Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/freebsd/freebsd-src.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 12:00:00 +0400
committersvn2git <svn2git@FreeBSD.org>1994-07-01 12:00:00 +0400
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
Release FreeBSD 1.1.5.1release/1.1.5.1_cvsreleng/1
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
-rw-r--r--CONTRIB.FreeBSD56
-rw-r--r--COPYRIGHT.FreeBSD8
-rw-r--r--COPYRIGHT.USL4
-rw-r--r--KNOWNBUGS23
-rw-r--r--MIRROR.SITES28
-rw-r--r--Makefile68
-rw-r--r--REGISTER.FreeBSD86
-rw-r--r--RELNOTES.FreeBSD87
-rw-r--r--ROSTER.FreeBSD127
-rw-r--r--SUPPORT.TXT91
-rw-r--r--TODO-1.1.538
-rw-r--r--bin/cp/cp.c4
-rw-r--r--bin/cp/path.c2
-rw-r--r--bin/csh/char.c4
-rw-r--r--bin/csh/char.h2
-rw-r--r--bin/csh/dol.c4
-rw-r--r--bin/csh/lex.c6
-rw-r--r--bin/df/df.c2
-rw-r--r--bin/ed/Makefile2
-rw-r--r--bin/ed/buf.c10
-rw-r--r--bin/ed/cbc.c2
-rw-r--r--bin/ed/ed.h17
-rw-r--r--bin/ed/glbl.c223
-rw-r--r--bin/ed/glob.c223
-rw-r--r--bin/ed/io.c2
-rw-r--r--bin/ed/main.c2
-rw-r--r--bin/ed/re.c2
-rw-r--r--bin/ed/sub.c2
-rw-r--r--bin/ed/undo.c2
-rw-r--r--bin/expr/expr.12
-rw-r--r--bin/ls/ls.12
-rw-r--r--bin/mkdir/mkdir.12
-rw-r--r--bin/mkdir/mkdir.c4
-rw-r--r--bin/mv/mv.c4
-rw-r--r--bin/rcp/Makefile10
-rw-r--r--bin/rm/rm.c2
-rw-r--r--bin/rmail/rmail.c1
-rw-r--r--bin/rmdir/rmdir.c4
-rw-r--r--bin/sh/builtins2
-rw-r--r--bin/sh/cd.c2
-rw-r--r--bin/sh/expand.c8
-rw-r--r--bin/sh/miscbltin.c4
-rw-r--r--bin/stty/cchar.c10
-rw-r--r--bin/stty/gfmt.c4
-rw-r--r--bin/stty/key.c2
-rw-r--r--bin/stty/print.c10
-rw-r--r--contrib/FAQ/FreeBSD.FAQ954
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.current.policy162
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.kdebug.FAQ33
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.mailing-list.FAQ77
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.ports.supfile18
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.slip.dialup.faq172
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.standard.supfile16
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSD.sup.faq98
-rw-r--r--contrib/FAQ/OTHER-FAQS/FreeBSDvsLinux70
-rw-r--r--contrib/FAQ/OTHER-FAQS/NFS77
-rw-r--r--contrib/FAQ/OTHER-FAQS/Systems.FAQ266
-rw-r--r--contrib/FAQ/code/printcap01/Makefile22
-rw-r--r--contrib/FAQ/code/printcap01/README14
-rw-r--r--contrib/FAQ/code/printcap01/hpf.c38
-rw-r--r--contrib/FAQ/code/printcap01/printcap.sample9
-rw-r--r--contrib/FAQ/code/printcap01/ps2lj34
-rw-r--r--contrib/Makefile4
-rwxr-xr-xcontrib/adduser/AddIt249
-rw-r--r--contrib/adduser/README40
-rw-r--r--contrib/adduser/dot.cshrc27
-rw-r--r--contrib/adduser/dot.login15
-rw-r--r--contrib/adduser/dot.profile2
-rw-r--r--contrib/adduser/userids1
-rwxr-xr-xcontrib/configit/ConfigIt761
-rw-r--r--contrib/configit/README32
-rw-r--r--contrib/configit/TODO9
-rw-r--r--contrib/crunch/COPYRIGHT25
-rw-r--r--contrib/crunch/Makefile4
-rw-r--r--contrib/crunch/Makefile.inc2
-rw-r--r--contrib/crunch/README88
-rw-r--r--contrib/crunch/crunchgen/Makefile9
-rw-r--r--contrib/crunch/crunchgen/crunched_main.c102
-rw-r--r--contrib/crunch/crunchgen/crunchgen.1266
-rw-r--r--contrib/crunch/crunchgen/crunchgen.c856
-rwxr-xr-xcontrib/crunch/crunchgen/mkskel.sh15
-rw-r--r--contrib/crunch/crunchide/Makefile4
-rw-r--r--contrib/crunch/crunchide/crunchide.168
-rw-r--r--contrib/crunch/crunchide/crunchide.c321
-rw-r--r--contrib/crunch/examples/Makefile32
-rw-r--r--contrib/crunch/examples/filesystem.conf26
-rw-r--r--contrib/crunch/examples/fixit.conf41
-rw-r--r--contrib/crunch/examples/kcopy.conf18
-rw-r--r--contrib/crunch/examples/really-big.conf146
-rw-r--r--contrib/manctl/Makefile11
-rw-r--r--contrib/manctl/manctl.sh376
-rw-r--r--contrib/tcpdump/tcpdump/tcpdump.12
-rw-r--r--contrib/tcpdump/tcpslice/tcpslice.12
-rw-r--r--contrib/xntpd/COPYRIGHT6
-rw-r--r--contrib/xntpd/Makefile.inc4
-rw-r--r--contrib/xntpd/README.FreeBSD76
-rw-r--r--contrib/xntpd/RELNOTES6
-rw-r--r--contrib/xntpd/VERSION2
-rw-r--r--contrib/xntpd/authstuff/authspeed.c2
-rw-r--r--contrib/xntpd/conf/Config.local4
-rw-r--r--contrib/xntpd/conf/Config.plain190
-rw-r--r--contrib/xntpd/doc/README.kern2015
-rw-r--r--contrib/xntpd/doc/notes.txt2
-rw-r--r--contrib/xntpd/gadget/.keep_me0
-rw-r--r--contrib/xntpd/hints/.keep_me0
-rw-r--r--contrib/xntpd/include/l_stdlib.h8
-rw-r--r--contrib/xntpd/include/ntp.h30
-rw-r--r--contrib/xntpd/include/ntp_control.h1
-rw-r--r--contrib/xntpd/include/ntp_if.h4
-rwxr-xr-xcontrib/xntpd/include/ntp_in.h259
-rw-r--r--contrib/xntpd/include/ntp_io.h1
-rw-r--r--contrib/xntpd/include/ntp_machine.h82
-rw-r--r--contrib/xntpd/include/ntp_request.h95
-rw-r--r--contrib/xntpd/include/ntp_stdlib.h1
-rw-r--r--contrib/xntpd/include/ntp_timex.h265
-rw-r--r--contrib/xntpd/include/ntpd.h13
-rw-r--r--contrib/xntpd/include/parse.h82
-rw-r--r--contrib/xntpd/kernel/.keep_me0
-rw-r--r--contrib/xntpd/lib/Makefile4
-rw-r--r--contrib/xntpd/lib/clocktypes.c2
-rw-r--r--contrib/xntpd/lib/netof.c25
-rw-r--r--contrib/xntpd/lib/numtohost.c5
-rw-r--r--contrib/xntpd/lib/systime.c3
-rw-r--r--contrib/xntpd/machines/.keep_me0
-rw-r--r--contrib/xntpd/ntpdate/ntpdate.h4
-rw-r--r--contrib/xntpd/ntpq/ntpq.c76
-rw-r--r--contrib/xntpd/parse/README.new_clocks212
-rw-r--r--contrib/xntpd/parse/README.parse_clocks263
-rw-r--r--contrib/xntpd/parse/clk_dcf7000.c7
-rw-r--r--contrib/xntpd/parse/clk_meinberg.c22
-rw-r--r--contrib/xntpd/parse/clk_rawdcf.c16
-rw-r--r--contrib/xntpd/parse/clk_schmid.c12
-rw-r--r--contrib/xntpd/parse/clk_trimble.c5
-rw-r--r--contrib/xntpd/parse/parse.c35
-rw-r--r--contrib/xntpd/parse/parse_conf.c7
-rw-r--r--contrib/xntpd/parse/parsesolaris.c35
-rw-r--r--contrib/xntpd/parse/parsestreams.c78
-rw-r--r--contrib/xntpd/parse/util/parsetest.c18
-rw-r--r--contrib/xntpd/parse/util/testdcf.c4
-rw-r--r--contrib/xntpd/ppsclock/ppstest/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/genassym/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/os/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4c/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sundev/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sys/.keep_me0
-rw-r--r--contrib/xntpd/refclocks/rclk.TRAK29
-rwxr-xr-xcontrib/xntpd/scripts/Guess.sh8
-rw-r--r--contrib/xntpd/scripts/README2
-rw-r--r--contrib/xntpd/scripts/stats/README35
-rw-r--r--contrib/xntpd/scripts/stats/dupe.awk3
-rw-r--r--contrib/xntpd/scripts/stats/ensemble.S5
-rw-r--r--contrib/xntpd/scripts/stats/etf.S15
-rw-r--r--contrib/xntpd/scripts/stats/itf.S5
-rw-r--r--contrib/xntpd/scripts/stats/loop.S7
-rw-r--r--contrib/xntpd/scripts/stats/loop.awk10
-rw-r--r--contrib/xntpd/scripts/stats/psummary.awk2
-rw-r--r--contrib/xntpd/scripts/stats/rms.awk41
-rwxr-xr-xcontrib/xntpd/scripts/stats/summary.sh95
-rw-r--r--contrib/xntpd/scripts/stats/tdata.S5
-rwxr-xr-xcontrib/xntpd/scripts/support/bin/monl3
-rw-r--r--contrib/xntpd/util/ntptime.c85
-rw-r--r--contrib/xntpd/util/tickadj.c71
-rw-r--r--contrib/xntpd/xntpd/Makefile4
-rw-r--r--contrib/xntpd/xntpd/minpoll (renamed from contrib/xntpd/adjtime/.keep_me)0
-rw-r--r--contrib/xntpd/xntpd/ntp_config.c201
-rw-r--r--contrib/xntpd/xntpd/ntp_control.c35
-rw-r--r--contrib/xntpd/xntpd/ntp_intres.c15
-rw-r--r--contrib/xntpd/xntpd/ntp_io.c95
-rw-r--r--contrib/xntpd/xntpd/ntp_loopfilter.c252
-rw-r--r--contrib/xntpd/xntpd/ntp_monitor.c51
-rw-r--r--contrib/xntpd/xntpd/ntp_peer.c26
-rw-r--r--contrib/xntpd/xntpd/ntp_proto.c225
-rw-r--r--contrib/xntpd/xntpd/ntp_refclock.c30
-rw-r--r--contrib/xntpd/xntpd/ntp_request.c175
-rw-r--r--contrib/xntpd/xntpd/ntp_restrict.c166
-rw-r--r--contrib/xntpd/xntpd/ntp_unixclock.c32
-rw-r--r--contrib/xntpd/xntpd/ntpd.c20
-rw-r--r--contrib/xntpd/xntpd/refclock_chu.c19
-rw-r--r--contrib/xntpd/xntpd/refclock_conf.c8
-rw-r--r--contrib/xntpd/xntpd/refclock_irig.c6
-rw-r--r--contrib/xntpd/xntpd/refclock_msfees.c2
-rw-r--r--contrib/xntpd/xntpd/refclock_parse.c103
-rw-r--r--contrib/xntpd/xntpd/refclock_trak.c1006
-rw-r--r--contrib/xntpd/xntpdc/ntpdc.c12
-rw-r--r--contrib/xntpd/xntpdc/ntpdc_ops.c297
-rw-r--r--contrib/xntpd/xntpres/xntpres.c18
-rw-r--r--etc/Makefile402
-rw-r--r--etc/crontab2
-rw-r--r--etc/csh.login4
-rw-r--r--etc/daily25
-rwxr-xr-xetc/etc.i386/EXTRACT_bin.sh18
-rwxr-xr-xetc/etc.i386/EXTRACT_secr.sh15
-rwxr-xr-xetc/etc.i386/EXTRACT_src.sh41
-rw-r--r--etc/etc.i386/MAKEDEV152
-rw-r--r--etc/etc.i386/README.1ST146
-rw-r--r--etc/etc.i386/README.INSTALL1011
-rw-r--r--etc/etc.i386/cdinst1.install15
-rw-r--r--etc/etc.i386/cpio.magic48
-rw-r--r--etc/etc.i386/cpio.rc13
-rw-r--r--etc/etc.i386/floppy.install_notes143
-rwxr-xr-xetc/etc.i386/inst1.install14
-rw-r--r--etc/etc.i386/inst2.rc4
-rw-r--r--etc/etc.i386/install_notes1043
-rw-r--r--etc/group1
-rw-r--r--etc/hosts16
-rw-r--r--etc/inetd.conf2
-rw-r--r--etc/kerberosIV/README35
-rw-r--r--etc/kerberosIV/krb.conf9
-rw-r--r--etc/kerberosIV/krb.realms3
-rw-r--r--etc/login.access44
-rw-r--r--etc/make.conf71
-rw-r--r--etc/master.passwd2
-rw-r--r--etc/minfree1
-rw-r--r--etc/mtree/BSD.local.dist20
-rw-r--r--etc/mtree/BSD.root.dist8
-rw-r--r--etc/mtree/BSD.usr.dist4
-rw-r--r--etc/mtree/BSD.var.dist7
-rw-r--r--etc/netstart5
-rw-r--r--etc/rc26
-rw-r--r--etc/rc.local2
-rw-r--r--etc/rc.serial91
-rw-r--r--etc/root/dot.login4
-rw-r--r--etc/root/dot.profile6
-rw-r--r--etc/services2
-rw-r--r--etc/skey.access8
-rw-r--r--etc/termcap.small154
-rw-r--r--etc/ttys14
-rw-r--r--games/Makefile2
-rw-r--r--games/fortune/fortune/fortune.c2
-rw-r--r--games/hack/COPYRIGHT6
-rw-r--r--games/hack/Makefile40
-rw-r--r--games/hack/Makequest196
-rw-r--r--games/hack/OWNER2
-rw-r--r--games/hack/Original_READ_ME61
-rw-r--r--games/hack/READ_ME92
-rw-r--r--games/hack/alloc.c47
-rw-r--r--games/hack/config.h139
-rw-r--r--games/hack/data232
-rw-r--r--games/hack/date.h2
-rw-r--r--games/hack/def.edog.h12
-rw-r--r--games/hack/def.eshk.h24
-rw-r--r--games/hack/def.flag.h42
-rw-r--r--games/hack/def.func_tab.h16
-rw-r--r--games/hack/def.gen.h15
-rw-r--r--games/hack/def.gold.h12
-rw-r--r--games/hack/def.mkroom.h26
-rw-r--r--games/hack/def.monst.h60
-rw-r--r--games/hack/def.obj.h48
-rw-r--r--games/hack/def.objclass.h60
-rw-r--r--games/hack/def.objects.h289
-rw-r--r--games/hack/def.permonst.h25
-rw-r--r--games/hack/def.rm.h52
-rw-r--r--games/hack/def.trap.h27
-rw-r--r--games/hack/def.wseg.h13
-rw-r--r--games/hack/hack.6155
-rw-r--r--games/hack/hack.Decl.c43
-rw-r--r--games/hack/hack.apply.c437
-rw-r--r--games/hack/hack.bones.c95
-rw-r--r--games/hack/hack.c798
-rw-r--r--games/hack/hack.cmd.c302
-rw-r--r--games/hack/hack.do.c488
-rw-r--r--games/hack/hack.do_name.c289
-rw-r--r--games/hack/hack.do_wear.c336
-rw-r--r--games/hack/hack.dog.c413
-rw-r--r--games/hack/hack.eat.c459
-rw-r--r--games/hack/hack.end.c642
-rw-r--r--games/hack/hack.engrave.c306
-rw-r--r--games/hack/hack.fight.c358
-rw-r--r--games/hack/hack.fix113
-rw-r--r--games/hack/hack.h160
-rw-r--r--games/hack/hack.invent.c863
-rw-r--r--games/hack/hack.ioctl.c53
-rw-r--r--games/hack/hack.lev.c285
-rw-r--r--games/hack/hack.main.c499
-rw-r--r--games/hack/hack.makemon.c198
-rw-r--r--games/hack/hack.mfndpos.h12
-rw-r--r--games/hack/hack.mhitu.c363
-rw-r--r--games/hack/hack.mklev.c741
-rw-r--r--games/hack/hack.mkmaze.c136
-rw-r--r--games/hack/hack.mkobj.c148
-rw-r--r--games/hack/hack.mkshop.c274
-rw-r--r--games/hack/hack.mon.c853
-rw-r--r--games/hack/hack.monst.c79
-rw-r--r--games/hack/hack.o_init.c160
-rw-r--r--games/hack/hack.objnam.c547
-rw-r--r--games/hack/hack.options.c203
-rw-r--r--games/hack/hack.pager.c406
-rw-r--r--games/hack/hack.potion.c386
-rw-r--r--games/hack/hack.pri.c660
-rw-r--r--games/hack/hack.read.c539
-rw-r--r--games/hack/hack.rip.c81
-rw-r--r--games/hack/hack.rumors.c63
-rw-r--r--games/hack/hack.save.c238
-rw-r--r--games/hack/hack.search.c133
-rw-r--r--games/hack/hack.sh14
-rw-r--r--games/hack/hack.shk.c987
-rw-r--r--games/hack/hack.shknam.c140
-rw-r--r--games/hack/hack.steal.c203
-rw-r--r--games/hack/hack.termcap.c276
-rw-r--r--games/hack/hack.timeout.c62
-rw-r--r--games/hack/hack.topl.c192
-rw-r--r--games/hack/hack.track.c38
-rw-r--r--games/hack/hack.trap.c447
-rw-r--r--games/hack/hack.tty.c338
-rw-r--r--games/hack/hack.u_init.c357
-rw-r--r--games/hack/hack.unix.c430
-rw-r--r--games/hack/hack.vault.c259
-rw-r--r--games/hack/hack.version.c16
-rw-r--r--games/hack/hack.wield.c99
-rw-r--r--games/hack/hack.wizard.c189
-rw-r--r--games/hack/hack.worm.c183
-rw-r--r--games/hack/hack.worn.c65
-rw-r--r--games/hack/hack.zap.c642
-rw-r--r--games/hack/help132
-rw-r--r--games/hack/hh55
-rw-r--r--games/hack/makedefs.c224
-rw-r--r--games/hack/pathnames.h39
-rw-r--r--games/hack/rnd.c30
-rw-r--r--games/hack/rumors505
-rw-r--r--games/monop/Makefile2
-rw-r--r--games/monop/misc.c2
-rw-r--r--games/sail/dr_main.c2
-rw-r--r--gnu/lib/Makefile4
-rw-r--r--gnu/lib/Makefile.inc8
-rw-r--r--gnu/lib/libg++/Makefile26
-rw-r--r--gnu/lib/libg++/Makefile.inc10
-rw-r--r--gnu/lib/libg++/g++-include/AVLMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/AVLMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/AVLMap.hP (renamed from gnu/lib/libg++/g++-include/gen/AVLMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/AVLSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/AVLSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/AVLSet.hP (renamed from gnu/lib/libg++/g++-include/gen/AVLSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/AVec.ccP (renamed from gnu/lib/libg++/g++-include/gen/AVec.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/AVec.hP (renamed from gnu/lib/libg++/g++-include/gen/AVec.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/BSTSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/BSTSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/BSTSet.hP (renamed from gnu/lib/libg++/g++-include/gen/BSTSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Bag.ccP (renamed from gnu/lib/libg++/g++-include/gen/Bag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Bag.hP (renamed from gnu/lib/libg++/g++-include/gen/Bag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/CHBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHBag.hP (renamed from gnu/lib/libg++/g++-include/gen/CHBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/CHMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHMap.hP (renamed from gnu/lib/libg++/g++-include/gen/CHMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHNode.ccP (renamed from gnu/lib/libg++/g++-include/gen/CHNode.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHNode.hP (renamed from gnu/lib/libg++/g++-include/gen/CHNode.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/CHSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/CHSet.hP (renamed from gnu/lib/libg++/g++-include/gen/CHSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/DLDeque.ccP (renamed from gnu/lib/libg++/g++-include/gen/DLDeque.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/DLDeque.hP (renamed from gnu/lib/libg++/g++-include/gen/DLDeque.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/DLList.ccP (renamed from gnu/lib/libg++/g++-include/gen/DLList.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/DLList.hP (renamed from gnu/lib/libg++/g++-include/gen/DLList.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Deque.ccP (renamed from gnu/lib/libg++/g++-include/gen/Deque.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Deque.hP (renamed from gnu/lib/libg++/g++-include/gen/Deque.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPQueue.ccP (renamed from gnu/lib/libg++/g++-include/gen/FPQueue.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPQueue.hP (renamed from gnu/lib/libg++/g++-include/gen/FPQueue.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPStack.ccP (renamed from gnu/lib/libg++/g++-include/gen/FPStack.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPStack.hP (renamed from gnu/lib/libg++/g++-include/gen/FPStack.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPlex.ccP (renamed from gnu/lib/libg++/g++-include/gen/FPlex.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/FPlex.hP (renamed from gnu/lib/libg++/g++-include/gen/FPlex.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/List.ccP (renamed from gnu/lib/libg++/g++-include/gen/List.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/List.hP (renamed from gnu/lib/libg++/g++-include/gen/List.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/MPlex.ccP (renamed from gnu/lib/libg++/g++-include/gen/MPlex.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/MPlex.hP (renamed from gnu/lib/libg++/g++-include/gen/MPlex.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Map.ccP (renamed from gnu/lib/libg++/g++-include/gen/Map.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Map.hP (renamed from gnu/lib/libg++/g++-include/gen/Map.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/OSLBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/OSLBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/OSLBag.hP (renamed from gnu/lib/libg++/g++-include/gen/OSLBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/OSLSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/OSLSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/OSLSet.hP (renamed from gnu/lib/libg++/g++-include/gen/OSLSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/OXPBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/OXPBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/OXPBag.hP (renamed from gnu/lib/libg++/g++-include/gen/OXPBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/OXPSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/OXPSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/OXPSet.hP (renamed from gnu/lib/libg++/g++-include/gen/OXPSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/PHPQ.ccP (renamed from gnu/lib/libg++/g++-include/gen/PHPQ.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/PHPQ.hP (renamed from gnu/lib/libg++/g++-include/gen/PHPQ.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/PQ.ccP (renamed from gnu/lib/libg++/g++-include/gen/PQ.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/PQ.hP (renamed from gnu/lib/libg++/g++-include/gen/PQ.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/PSList.hP (renamed from gnu/lib/libg++/g++-include/gen/PSList.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/PVec.hP (renamed from gnu/lib/libg++/g++-include/gen/PVec.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Plex.ccP (renamed from gnu/lib/libg++/g++-include/gen/Plex.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Plex.hP (renamed from gnu/lib/libg++/g++-include/gen/Plex.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Queue.ccP (renamed from gnu/lib/libg++/g++-include/gen/Queue.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Queue.hP (renamed from gnu/lib/libg++/g++-include/gen/Queue.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/RAVLMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/RAVLMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/RAVLMap.hP (renamed from gnu/lib/libg++/g++-include/gen/RAVLMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/RPlex.ccP (renamed from gnu/lib/libg++/g++-include/gen/RPlex.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/RPlex.hP (renamed from gnu/lib/libg++/g++-include/gen/RPlex.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/SLBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLBag.hP (renamed from gnu/lib/libg++/g++-include/gen/SLBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLList.ccP (renamed from gnu/lib/libg++/g++-include/gen/SLList.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLList.hP (renamed from gnu/lib/libg++/g++-include/gen/SLList.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLQueue.ccP (renamed from gnu/lib/libg++/g++-include/gen/SLQueue.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLQueue.hP (renamed from gnu/lib/libg++/g++-include/gen/SLQueue.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/SLSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLSet.hP (renamed from gnu/lib/libg++/g++-include/gen/SLSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLStack.ccP (renamed from gnu/lib/libg++/g++-include/gen/SLStack.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SLStack.hP (renamed from gnu/lib/libg++/g++-include/gen/SLStack.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Set.ccP (renamed from gnu/lib/libg++/g++-include/gen/Set.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Set.hP (renamed from gnu/lib/libg++/g++-include/gen/Set.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/SkipBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipBag.hP (renamed from gnu/lib/libg++/g++-include/gen/SkipBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/SkipMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipMap.hP (renamed from gnu/lib/libg++/g++-include/gen/SkipMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/SkipSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SkipSet.hP (renamed from gnu/lib/libg++/g++-include/gen/SkipSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/SplayBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayBag.hP (renamed from gnu/lib/libg++/g++-include/gen/SplayBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/SplayMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayMap.hP (renamed from gnu/lib/libg++/g++-include/gen/SplayMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayNode.ccP (renamed from gnu/lib/libg++/g++-include/gen/SplayNode.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayNode.hP (renamed from gnu/lib/libg++/g++-include/gen/SplayNode.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayPQ.ccP (renamed from gnu/lib/libg++/g++-include/gen/SplayPQ.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplayPQ.hP (renamed from gnu/lib/libg++/g++-include/gen/SplayPQ.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplaySet.ccP (renamed from gnu/lib/libg++/g++-include/gen/SplaySet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/SplaySet.hP (renamed from gnu/lib/libg++/g++-include/gen/SplaySet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Stack.ccP (renamed from gnu/lib/libg++/g++-include/gen/Stack.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Stack.hP (renamed from gnu/lib/libg++/g++-include/gen/Stack.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/VHBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHBag.hP (renamed from gnu/lib/libg++/g++-include/gen/VHBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHMap.ccP (renamed from gnu/lib/libg++/g++-include/gen/VHMap.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHMap.hP (renamed from gnu/lib/libg++/g++-include/gen/VHMap.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/VHSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VHSet.hP (renamed from gnu/lib/libg++/g++-include/gen/VHSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VOHSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/VOHSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VOHSet.hP (renamed from gnu/lib/libg++/g++-include/gen/VOHSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VQueue.ccP (renamed from gnu/lib/libg++/g++-include/gen/VQueue.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VQueue.hP (renamed from gnu/lib/libg++/g++-include/gen/VQueue.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/VStack.ccP (renamed from gnu/lib/libg++/g++-include/gen/VStack.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/VStack.hP (renamed from gnu/lib/libg++/g++-include/gen/VStack.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/Vec.ccP (renamed from gnu/lib/libg++/g++-include/gen/Vec.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/Vec.hP (renamed from gnu/lib/libg++/g++-include/gen/Vec.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPBag.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPBag.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPBag.hP (renamed from gnu/lib/libg++/g++-include/gen/XPBag.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPDeque.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPDeque.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPDeque.hP (renamed from gnu/lib/libg++/g++-include/gen/XPDeque.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPPQ.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPPQ.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPPQ.hP (renamed from gnu/lib/libg++/g++-include/gen/XPPQ.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPQueue.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPQueue.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPQueue.hP (renamed from gnu/lib/libg++/g++-include/gen/XPQueue.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPSet.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPSet.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPSet.hP (renamed from gnu/lib/libg++/g++-include/gen/XPSet.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPStack.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPStack.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPStack.hP (renamed from gnu/lib/libg++/g++-include/gen/XPStack.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPlex.ccP (renamed from gnu/lib/libg++/g++-include/gen/XPlex.ccP)0
-rw-r--r--gnu/lib/libg++/g++-include/XPlex.hP (renamed from gnu/lib/libg++/g++-include/gen/XPlex.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/assert.h14
-rw-r--r--gnu/lib/libg++/g++-include/bstring.h1
-rw-r--r--gnu/lib/libg++/g++-include/ctype.h10
-rw-r--r--gnu/lib/libg++/g++-include/curses.h82
-rw-r--r--gnu/lib/libg++/g++-include/defs.hP (renamed from gnu/lib/libg++/g++-include/gen/defs.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/dir.h1
-rw-r--r--gnu/lib/libg++/g++-include/dirent.h44
-rw-r--r--gnu/lib/libg++/g++-include/errno.h24
-rw-r--r--gnu/lib/libg++/g++-include/fcntl.h29
-rw-r--r--gnu/lib/libg++/g++-include/grp.h41
-rw-r--r--gnu/lib/libg++/g++-include/intSList.hP (renamed from gnu/lib/libg++/g++-include/gen/intSList.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/intVec.hP (renamed from gnu/lib/libg++/g++-include/gen/intVec.hP)0
-rw-r--r--gnu/lib/libg++/g++-include/math.h221
-rw-r--r--gnu/lib/libg++/g++-include/memory.h42
-rw-r--r--gnu/lib/libg++/g++-include/netdb.h4
-rw-r--r--gnu/lib/libg++/g++-include/pwd.h36
-rw-r--r--gnu/lib/libg++/g++-include/setjmp.h29
-rw-r--r--gnu/lib/libg++/g++-include/signal.h80
-rw-r--r--gnu/lib/libg++/g++-include/stdarg.h3
-rw-r--r--gnu/lib/libg++/g++-include/stddef.h12
-rw-r--r--gnu/lib/libg++/g++-include/stdio.h180
-rw-r--r--gnu/lib/libg++/g++-include/stdlib.h81
-rw-r--r--gnu/lib/libg++/g++-include/string.h45
-rw-r--r--gnu/lib/libg++/g++-include/strings.h1
-rw-r--r--gnu/lib/libg++/g++-include/sys/dir.h42
-rw-r--r--gnu/lib/libg++/g++-include/sys/fcntl.h15
-rw-r--r--gnu/lib/libg++/g++-include/sys/file.h28
-rw-r--r--gnu/lib/libg++/g++-include/sys/mman.h14
-rw-r--r--gnu/lib/libg++/g++-include/sys/param.h22
-rw-r--r--gnu/lib/libg++/g++-include/sys/resource.h29
-rw-r--r--gnu/lib/libg++/g++-include/sys/select.h8
-rw-r--r--gnu/lib/libg++/g++-include/sys/signal.h37
-rw-r--r--gnu/lib/libg++/g++-include/sys/socket.h63
-rw-r--r--gnu/lib/libg++/g++-include/sys/stat.h47
-rw-r--r--gnu/lib/libg++/g++-include/sys/time.h41
-rw-r--r--gnu/lib/libg++/g++-include/sys/times.h20
-rw-r--r--gnu/lib/libg++/g++-include/sys/types.h25
-rw-r--r--gnu/lib/libg++/g++-include/sys/wait.h42
-rw-r--r--gnu/lib/libg++/g++-include/time.h108
-rw-r--r--gnu/lib/libg++/g++-include/unistd.h187
-rw-r--r--gnu/lib/libg++/g++-include/values.h174
-rw-r--r--gnu/lib/libg++/include/values.h173
-rw-r--r--gnu/lib/libg++/libg++/CursesW.cc2
-rw-r--r--gnu/lib/libg++/libg++/Makefile10
-rw-r--r--gnu/lib/libmalloc/Makefile4
-rw-r--r--gnu/lib/libreadline/COPYING257
-rw-r--r--gnu/lib/libreadline/ChangeLog403
-rw-r--r--gnu/lib/libreadline/Makefile25
-rw-r--r--gnu/lib/libreadline/README6
-rw-r--r--gnu/lib/libreadline/README.FreeBSD21
-rw-r--r--gnu/lib/libreadline/STANDALONE32
-rw-r--r--gnu/lib/libreadline/VERSION1
-rw-r--r--gnu/lib/libreadline/ansi_stdlib.h41
-rw-r--r--gnu/lib/libreadline/bind.c1476
-rw-r--r--gnu/lib/libreadline/complete.c1381
-rw-r--r--gnu/lib/libreadline/display.c1017
-rw-r--r--gnu/lib/libreadline/doc/Makefile34
-rw-r--r--gnu/lib/libreadline/doc/hist.texinfo106
-rw-r--r--gnu/lib/libreadline/doc/hstech.texinfo308
-rw-r--r--gnu/lib/libreadline/doc/hsuser.texinfo197
-rw-r--r--gnu/lib/libreadline/doc/rlman.texinfo103
-rw-r--r--gnu/lib/libreadline/doc/rltech.texinfo1012
-rw-r--r--gnu/lib/libreadline/doc/rluser.texinfo865
-rw-r--r--gnu/lib/libreadline/doc/texindex.c1666
-rw-r--r--gnu/lib/libreadline/emacs_keymap.c885
-rw-r--r--gnu/lib/libreadline/examples/Inputrc58
-rw-r--r--gnu/lib/libreadline/examples/Makefile12
-rw-r--r--gnu/lib/libreadline/examples/fileman.c395
-rw-r--r--gnu/lib/libreadline/examples/manexamp.c96
-rw-r--r--gnu/lib/libreadline/funmap.c295
-rw-r--r--gnu/lib/libreadline/history.c2136
-rw-r--r--gnu/lib/libreadline/isearch.c372
-rw-r--r--gnu/lib/libreadline/keymaps.c195
-rw-r--r--gnu/lib/libreadline/memalloc.h56
-rw-r--r--gnu/lib/libreadline/parens.c118
-rw-r--r--gnu/lib/libreadline/posixstat.h149
-rw-r--r--gnu/lib/libreadline/readline.c3349
-rw-r--r--gnu/lib/libreadline/readline/chardefs.h89
-rw-r--r--gnu/lib/libreadline/readline/history.h149
-rw-r--r--gnu/lib/libreadline/readline/keymaps.h91
-rw-r--r--gnu/lib/libreadline/readline/readline.h267
-rw-r--r--gnu/lib/libreadline/readline/tilde.h38
-rw-r--r--gnu/lib/libreadline/rlconf.h57
-rw-r--r--gnu/lib/libreadline/rldefs.h190
-rw-r--r--gnu/lib/libreadline/rltty.c693
-rw-r--r--gnu/lib/libreadline/search.c360
-rw-r--r--gnu/lib/libreadline/signals.c303
-rw-r--r--gnu/lib/libreadline/tcsh_hack.readme27
-rw-r--r--gnu/lib/libreadline/tilde.c386
-rw-r--r--gnu/lib/libreadline/vi_keymap.c877
-rw-r--r--gnu/lib/libreadline/vi_mode.c1319
-rw-r--r--gnu/lib/libreadline/xmalloc.c78
-rw-r--r--gnu/lib/libregex/Makefile7
-rw-r--r--gnu/libexec/uucp/ChangeLog1669
-rw-r--r--gnu/libexec/uucp/Makefile.inc4
-rw-r--r--gnu/libexec/uucp/NEWS119
-rw-r--r--gnu/libexec/uucp/README107
-rw-r--r--gnu/libexec/uucp/TODO265
-rw-r--r--gnu/libexec/uucp/VERSION2
-rw-r--r--gnu/libexec/uucp/common_sources/chat.c61
-rw-r--r--gnu/libexec/uucp/common_sources/conf.h444
-rw-r--r--gnu/libexec/uucp/common_sources/config.h462
-rw-r--r--gnu/libexec/uucp/common_sources/conn.c251
-rw-r--r--gnu/libexec/uucp/common_sources/conn.h25
-rw-r--r--gnu/libexec/uucp/common_sources/copy.c4
-rw-r--r--gnu/libexec/uucp/common_sources/cu.h2
-rw-r--r--gnu/libexec/uucp/common_sources/log.c226
-rw-r--r--gnu/libexec/uucp/common_sources/policy.h205
-rw-r--r--gnu/libexec/uucp/common_sources/prot.c10
-rw-r--r--gnu/libexec/uucp/common_sources/prot.h7
-rw-r--r--gnu/libexec/uucp/common_sources/sysdep.h50
-rw-r--r--gnu/libexec/uucp/common_sources/system.h87
-rw-r--r--gnu/libexec/uucp/common_sources/tcp.c53
-rw-r--r--gnu/libexec/uucp/common_sources/tli.c116
-rw-r--r--gnu/libexec/uucp/common_sources/trans.h24
-rw-r--r--gnu/libexec/uucp/common_sources/util.c50
-rw-r--r--gnu/libexec/uucp/common_sources/uuconf.h60
-rw-r--r--gnu/libexec/uucp/common_sources/uucp.h37
-rw-r--r--gnu/libexec/uucp/common_sources/uudefs.h25
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.uurt36
-rw-r--r--gnu/libexec/uucp/contrib/README44
-rw-r--r--gnu/libexec/uucp/contrib/README-UURATE17
-rw-r--r--gnu/libexec/uucp/contrib/amiga.c43
-rw-r--r--gnu/libexec/uucp/contrib/dialHDB.c187
-rw-r--r--gnu/libexec/uucp/contrib/uucomp.shar552
-rw-r--r--gnu/libexec/uucp/contrib/uudemon.shar82
-rw-r--r--gnu/libexec/uucp/contrib/uupoll.shar2696
-rw-r--r--gnu/libexec/uucp/contrib/uurate.c2237
-rw-r--r--gnu/libexec/uucp/contrib/uurate.man257
-rwxr-xr-xgnu/libexec/uucp/contrib/uureroute.perl91
-rw-r--r--gnu/libexec/uucp/contrib/uusnap.c2
-rw-r--r--gnu/libexec/uucp/contrib/uutraf35
-rwxr-xr-xgnu/libexec/uucp/contrib/uuxconv50
-rw-r--r--gnu/libexec/uucp/contrib/xchat.c109
-rw-r--r--gnu/libexec/uucp/contrib/xchat.man14
-rw-r--r--gnu/libexec/uucp/cu/Makefile4
-rw-r--r--gnu/libexec/uucp/cu/cu.165
-rw-r--r--gnu/libexec/uucp/cu/cu.c157
-rw-r--r--gnu/libexec/uucp/doc/uucp.texi4036
-rw-r--r--gnu/libexec/uucp/libunix/MANIFEST5
-rw-r--r--gnu/libexec/uucp/libunix/Makefile21
-rw-r--r--gnu/libexec/uucp/libunix/app3.c5
-rw-r--r--gnu/libexec/uucp/libunix/app4.c5
-rw-r--r--gnu/libexec/uucp/libunix/cohtty.c21
-rw-r--r--gnu/libexec/uucp/libunix/corrup.c33
-rw-r--r--gnu/libexec/uucp/libunix/cusub.c64
-rw-r--r--gnu/libexec/uucp/libunix/cwd.c7
-rw-r--r--gnu/libexec/uucp/libunix/detach.c10
-rw-r--r--gnu/libexec/uucp/libunix/dirent.c2
-rw-r--r--gnu/libexec/uucp/libunix/dup2.c2
-rw-r--r--gnu/libexec/uucp/libunix/epopen.c4
-rw-r--r--gnu/libexec/uucp/libunix/filnam.c6
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.c128
-rw-r--r--gnu/libexec/uucp/libunix/ftw.c12
-rw-r--r--gnu/libexec/uucp/libunix/indir.c2
-rw-r--r--gnu/libexec/uucp/libunix/init.c28
-rw-r--r--gnu/libexec/uucp/libunix/iswait.c2
-rw-r--r--gnu/libexec/uucp/libunix/jobid.c2
-rw-r--r--gnu/libexec/uucp/libunix/lcksys.c39
-rw-r--r--gnu/libexec/uucp/libunix/locfil.c12
-rw-r--r--gnu/libexec/uucp/libunix/lock.c279
-rw-r--r--gnu/libexec/uucp/libunix/loctim.c4
-rw-r--r--gnu/libexec/uucp/libunix/mail.c52
-rw-r--r--gnu/libexec/uucp/libunix/mkdir.c2
-rw-r--r--gnu/libexec/uucp/libunix/mkdirs.c20
-rw-r--r--gnu/libexec/uucp/libunix/move.c24
-rw-r--r--gnu/libexec/uucp/libunix/opensr.c24
-rw-r--r--gnu/libexec/uucp/libunix/pause.c10
-rw-r--r--gnu/libexec/uucp/libunix/picksb.c14
-rw-r--r--gnu/libexec/uucp/libunix/pipe.c294
-rw-r--r--gnu/libexec/uucp/libunix/priv.c24
-rw-r--r--gnu/libexec/uucp/libunix/proctm.c6
-rw-r--r--gnu/libexec/uucp/libunix/recep.c12
-rw-r--r--gnu/libexec/uucp/libunix/run.c52
-rw-r--r--gnu/libexec/uucp/libunix/seq.c4
-rw-r--r--gnu/libexec/uucp/libunix/serial.c666
-rw-r--r--gnu/libexec/uucp/libunix/signal.c2
-rw-r--r--gnu/libexec/uucp/libunix/sindir.c5
-rw-r--r--gnu/libexec/uucp/libunix/sleep.c12
-rw-r--r--gnu/libexec/uucp/libunix/spawn.c55
-rw-r--r--gnu/libexec/uucp/libunix/splcmd.c44
-rw-r--r--gnu/libexec/uucp/libunix/spool.c43
-rw-r--r--gnu/libexec/uucp/libunix/srmdir.c6
-rw-r--r--gnu/libexec/uucp/libunix/statsb.c126
-rw-r--r--gnu/libexec/uucp/libunix/status.c6
-rw-r--r--gnu/libexec/uucp/libunix/strerr.c2
-rw-r--r--gnu/libexec/uucp/libunix/tmpfil.c5
-rw-r--r--gnu/libexec/uucp/libunix/uacces.c2
-rw-r--r--gnu/libexec/uucp/libunix/ufopen.c2
-rw-r--r--gnu/libexec/uucp/libunix/walk.c5
-rw-r--r--gnu/libexec/uucp/libunix/wldcrd.c7
-rw-r--r--gnu/libexec/uucp/libunix/work.c92
-rw-r--r--gnu/libexec/uucp/libunix/xqtfil.c11
-rw-r--r--gnu/libexec/uucp/libunix/xqtsub.c32
-rw-r--r--gnu/libexec/uucp/libuuconf/MANIFEST1
-rw-r--r--gnu/libexec/uucp/libuuconf/Makefile26
-rw-r--r--gnu/libexec/uucp/libuuconf/README4
-rw-r--r--gnu/libexec/uucp/libuuconf/addblk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/addstr.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/allblk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.h2
-rw-r--r--gnu/libexec/uucp/libuuconf/base.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/bool.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/callin.c118
-rw-r--r--gnu/libexec/uucp/libuuconf/calout.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/chatc.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdarg.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdfil.c9
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdlin.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/debfil.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/deblev.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/diacod.c6
-rw-r--r--gnu/libexec/uucp/libuuconf/dial.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/diasub.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/dnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/errno.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/errstr.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/filnam.c6
-rw-r--r--gnu/libexec/uucp/libuuconf/freblk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/fredia.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/free.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/freprt.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/fresys.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/grdcmp.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hdial.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hdnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hinit.c8
-rw-r--r--gnu/libexec/uucp/libuuconf/hlocnm.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hport.c46
-rw-r--r--gnu/libexec/uucp/libuuconf/hrmunk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hsinfo.c17
-rw-r--r--gnu/libexec/uucp/libuuconf/hsnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hsys.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/hunk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/iniglb.c7
-rw-r--r--gnu/libexec/uucp/libuuconf/init.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/int.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/lckdir.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/lineno.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/llocnm.c15
-rw-r--r--gnu/libexec/uucp/libuuconf/local.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/locnm.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/logfil.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/maxuxq.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/mrgblk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/paramc.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/port.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/prtsub.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/pubdir.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/rdlocs.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/rdperm.c36
-rw-r--r--gnu/libexec/uucp/libuuconf/reliab.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/remunk.c19
-rw-r--r--gnu/libexec/uucp/libuuconf/runuxq.c77
-rw-r--r--gnu/libexec/uucp/libuuconf/sinfo.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/snams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/split.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/spool.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/stafil.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/syshdr.h38
-rw-r--r--gnu/libexec/uucp/libuuconf/syssub.c71
-rw-r--r--gnu/libexec/uucp/libuuconf/tcalou.c16
-rw-r--r--gnu/libexec/uucp/libuuconf/tdial.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tdialc.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tdnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tgcmp.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/thread.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/time.c9
-rw-r--r--gnu/libexec/uucp/libuuconf/tinit.c123
-rw-r--r--gnu/libexec/uucp/libuuconf/tlocnm.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tport.c12
-rw-r--r--gnu/libexec/uucp/libuuconf/tportc.c78
-rw-r--r--gnu/libexec/uucp/libuuconf/tsinfo.c30
-rw-r--r--gnu/libexec/uucp/libuuconf/tsnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tsys.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/tval.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/ugtlin.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/unk.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/uucnfi.h12
-rw-r--r--gnu/libexec/uucp/libuuconf/val.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/vinit.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/vport.c9
-rw-r--r--gnu/libexec/uucp/libuuconf/vsinfo.c16
-rw-r--r--gnu/libexec/uucp/libuuconf/vsnams.c4
-rw-r--r--gnu/libexec/uucp/libuuconf/vsys.c4
-rw-r--r--gnu/libexec/uucp/libuucp/MANIFEST1
-rw-r--r--gnu/libexec/uucp/libuucp/Makefile7
-rw-r--r--gnu/libexec/uucp/libuucp/buffer.c24
-rw-r--r--gnu/libexec/uucp/libuucp/debug.c10
-rw-r--r--gnu/libexec/uucp/libuucp/getlin.c2
-rw-r--r--gnu/libexec/uucp/libuucp/parse.c20
-rw-r--r--gnu/libexec/uucp/libuucp/status.c18
-rw-r--r--gnu/libexec/uucp/libuucp/strtou.c21
-rw-r--r--gnu/libexec/uucp/sample/Makefile6
-rw-r--r--gnu/libexec/uucp/sample/call.sample (renamed from gnu/libexec/uucp/sample/call)0
-rw-r--r--gnu/libexec/uucp/sample/config.sample (renamed from gnu/libexec/uucp/sample/config)0
-rw-r--r--gnu/libexec/uucp/sample/dial35
-rw-r--r--gnu/libexec/uucp/sample/dial.sample39
-rw-r--r--gnu/libexec/uucp/sample/dialcode.sample (renamed from gnu/libexec/uucp/sample/dialcode)0
-rw-r--r--gnu/libexec/uucp/sample/passwd.sample (renamed from gnu/libexec/uucp/sample/passwd)0
-rw-r--r--gnu/libexec/uucp/sample/port.sample (renamed from gnu/libexec/uucp/sample/port)0
-rw-r--r--gnu/libexec/uucp/sample/sys1.sample (renamed from gnu/libexec/uucp/sample/sys1)0
-rw-r--r--gnu/libexec/uucp/sample/sys2.sample (renamed from gnu/libexec/uucp/sample/sys2)0
-rw-r--r--gnu/libexec/uucp/tstuu.c25
-rw-r--r--gnu/libexec/uucp/uuchk/Makefile4
-rw-r--r--gnu/libexec/uucp/uuchk/uuchk.c149
-rw-r--r--gnu/libexec/uucp/uucico/Makefile6
-rw-r--r--gnu/libexec/uucp/uucico/prote.c4
-rw-r--r--gnu/libexec/uucp/uucico/protf.c14
-rw-r--r--gnu/libexec/uucp/uucico/protg.c83
-rw-r--r--gnu/libexec/uucp/uucico/proti.c261
-rw-r--r--gnu/libexec/uucp/uucico/protj.c7
-rw-r--r--gnu/libexec/uucp/uucico/prott.c7
-rw-r--r--gnu/libexec/uucp/uucico/protz.c4
-rw-r--r--gnu/libexec/uucp/uucico/rec.c238
-rw-r--r--gnu/libexec/uucp/uucico/send.c271
-rw-r--r--gnu/libexec/uucp/uucico/time.c10
-rw-r--r--gnu/libexec/uucp/uucico/trans.c118
-rw-r--r--gnu/libexec/uucp/uucico/uucico.8176
-rw-r--r--gnu/libexec/uucp/uucico/uucico.c762
-rw-r--r--gnu/libexec/uucp/uucico/xcmd.c31
-rw-r--r--gnu/libexec/uucp/uuconv/Makefile4
-rw-r--r--gnu/libexec/uucp/uuconv/uuconv.c130
-rw-r--r--gnu/libexec/uucp/uucp/Makefile4
-rw-r--r--gnu/libexec/uucp/uucp/uucp.155
-rw-r--r--gnu/libexec/uucp/uucp/uucp.c186
-rw-r--r--gnu/libexec/uucp/uulog/uulog.c132
-rw-r--r--gnu/libexec/uucp/uuname/uuname.c88
-rw-r--r--gnu/libexec/uucp/uupick/uupick.c81
-rw-r--r--gnu/libexec/uucp/uusched/uusched.in6
-rw-r--r--gnu/libexec/uucp/uustat/uustat.1404
-rw-r--r--gnu/libexec/uucp/uustat/uustat.c395
-rw-r--r--gnu/libexec/uucp/uuto/uuto.in6
-rw-r--r--gnu/libexec/uucp/uux/Makefile4
-rw-r--r--gnu/libexec/uucp/uux/uux.197
-rw-r--r--gnu/libexec/uucp/uux/uux.c295
-rw-r--r--gnu/libexec/uucp/uuxqt/Makefile7
-rw-r--r--gnu/libexec/uucp/uuxqt/uuxqt.837
-rw-r--r--gnu/libexec/uucp/uuxqt/uuxqt.c292
-rw-r--r--gnu/usr.bin/Makefile6
-rw-r--r--gnu/usr.bin/awk/ACKNOWLEDGMENT8
-rw-r--r--gnu/usr.bin/awk/FUTURES69
-rw-r--r--gnu/usr.bin/awk/LIMITATIONS2
-rw-r--r--gnu/usr.bin/awk/Makefile20
-rw-r--r--gnu/usr.bin/awk/NEWS207
-rw-r--r--gnu/usr.bin/awk/PORTS9
-rw-r--r--gnu/usr.bin/awk/PROBLEMS6
-rw-r--r--gnu/usr.bin/awk/README25
-rw-r--r--gnu/usr.bin/awk/array.c300
-rw-r--r--gnu/usr.bin/awk/awk.1158
-rw-r--r--gnu/usr.bin/awk/awk.h115
-rw-r--r--gnu/usr.bin/awk/awk.y144
-rw-r--r--gnu/usr.bin/awk/builtin.c670
-rw-r--r--gnu/usr.bin/awk/config.h38
-rw-r--r--gnu/usr.bin/awk/dfa.c2837
-rw-r--r--gnu/usr.bin/awk/dfa.h425
-rw-r--r--gnu/usr.bin/awk/eval.c113
-rw-r--r--gnu/usr.bin/awk/field.c119
-rw-r--r--gnu/usr.bin/awk/getopt.c203
-rw-r--r--gnu/usr.bin/awk/getopt.h31
-rw-r--r--gnu/usr.bin/awk/getopt1.c81
-rw-r--r--gnu/usr.bin/awk/io.c221
-rw-r--r--gnu/usr.bin/awk/iop.c27
-rw-r--r--gnu/usr.bin/awk/main.c178
-rw-r--r--gnu/usr.bin/awk/msg.c11
-rw-r--r--gnu/usr.bin/awk/node.c68
-rw-r--r--gnu/usr.bin/awk/patchlevel.h2
-rw-r--r--gnu/usr.bin/awk/protos.h45
-rw-r--r--gnu/usr.bin/awk/re.c46
-rw-r--r--gnu/usr.bin/awk/regex.c6330
-rw-r--r--gnu/usr.bin/awk/regex.h675
-rw-r--r--gnu/usr.bin/awk/version.c3
-rw-r--r--gnu/usr.bin/cc/cc/gcc.c6
-rw-r--r--gnu/usr.bin/cc/cpp/cccp.c2
-rw-r--r--gnu/usr.bin/cc/lib/Makefile5
-rw-r--r--gnu/usr.bin/cc/libgcc/Makefile17
-rw-r--r--gnu/usr.bin/cc/libgcc/libgcc2.c5
-rw-r--r--gnu/usr.bin/cc25/Freebsd.gcc258.patch39
-rw-r--r--gnu/usr.bin/cc25/Makefile6
-rw-r--r--gnu/usr.bin/cc25/README209
-rw-r--r--gnu/usr.bin/cc25/gcc258-freebsd.patch1188
-rwxr-xr-xgnu/usr.bin/cc25/gnu2bsd.tcl470
-rw-r--r--gnu/usr.bin/cc25/usr.bin.cpp/Makefile10
-rw-r--r--gnu/usr.bin/cc25/usr.bin.cpp/cpp.script91
-rw-r--r--gnu/usr.bin/cc25/usr.bin.f77/Makefile7
-rw-r--r--gnu/usr.bin/cc25/usr.bin.f77/f77.script114
-rw-r--r--gnu/usr.bin/cvs/cvs/Makefile11
-rw-r--r--gnu/usr.bin/cvs/cvs/checkin.c7
-rw-r--r--gnu/usr.bin/cvs/cvs/checkout.c16
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.h6
-rw-r--r--gnu/usr.bin/cvs/cvs/diff.c26
-rw-r--r--gnu/usr.bin/cvs/cvs/ignore.c2
-rw-r--r--gnu/usr.bin/cvs/cvs/import.c6
-rw-r--r--gnu/usr.bin/cvs/cvs/main.c16
-rw-r--r--gnu/usr.bin/cvs/cvs/patch.c24
-rw-r--r--gnu/usr.bin/cvs/cvs/release.c4
-rw-r--r--gnu/usr.bin/cvs/cvs/update.c27
-rw-r--r--gnu/usr.bin/gdb/COPYING354
-rw-r--r--gnu/usr.bin/gdb/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/Makefile39
-rw-r--r--gnu/usr.bin/gdb/README.FreeBSD15
-rw-r--r--gnu/usr.bin/gdb/VERSION1
-rw-r--r--gnu/usr.bin/gdb/bfd/COPYING339
-rw-r--r--gnu/usr.bin/gdb/bfd/Makefile17
-rw-r--r--gnu/usr.bin/gdb/bfd/README.FreeBSD7
-rw-r--r--gnu/usr.bin/gdb/bfd/VERSION1
-rw-r--r--gnu/usr.bin/gdb/bfd/aout-target.h429
-rw-r--r--gnu/usr.bin/gdb/bfd/aout32.c23
-rw-r--r--gnu/usr.bin/gdb/bfd/aoutx.h2568
-rw-r--r--gnu/usr.bin/gdb/bfd/archive.c1770
-rw-r--r--gnu/usr.bin/gdb/bfd/archures.c731
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.c733
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.h1803
-rw-r--r--gnu/usr.bin/gdb/bfd/cache.c311
-rw-r--r--gnu/usr.bin/gdb/bfd/coffgen.c1519
-rw-r--r--gnu/usr.bin/gdb/bfd/core.c106
-rw-r--r--gnu/usr.bin/gdb/bfd/cpu-i386.c43
-rw-r--r--gnu/usr.bin/gdb/bfd/ctor.c148
-rw-r--r--gnu/usr.bin/gdb/bfd/ecoff.c3994
-rw-r--r--gnu/usr.bin/gdb/bfd/elf.c248
-rw-r--r--gnu/usr.bin/gdb/bfd/format.c258
-rw-r--r--gnu/usr.bin/gdb/bfd/freebsd386.c110
-rw-r--r--gnu/usr.bin/gdb/bfd/init.c78
-rw-r--r--gnu/usr.bin/gdb/bfd/libaout.h393
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.c850
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.h273
-rw-r--r--gnu/usr.bin/gdb/bfd/libcoff.h352
-rw-r--r--gnu/usr.bin/gdb/bfd/libecoff.h265
-rw-r--r--gnu/usr.bin/gdb/bfd/libelf.h249
-rw-r--r--gnu/usr.bin/gdb/bfd/opncls.c534
-rw-r--r--gnu/usr.bin/gdb/bfd/reloc.c1225
-rw-r--r--gnu/usr.bin/gdb/bfd/seclet.c185
-rw-r--r--gnu/usr.bin/gdb/bfd/seclet.h55
-rw-r--r--gnu/usr.bin/gdb/bfd/section.c899
-rw-r--r--gnu/usr.bin/gdb/bfd/srec.c1001
-rw-r--r--gnu/usr.bin/gdb/bfd/stab-syms.c59
-rw-r--r--gnu/usr.bin/gdb/bfd/syms.c527
-rw-r--r--gnu/usr.bin/gdb/bfd/sysdep.h47
-rw-r--r--gnu/usr.bin/gdb/bfd/targets.c635
-rw-r--r--gnu/usr.bin/gdb/bfd/trad-core.c384
-rw-r--r--gnu/usr.bin/gdb/config/i386bsd-dep.c1886
-rw-r--r--gnu/usr.bin/gdb/doc/ChangeLog783
-rw-r--r--gnu/usr.bin/gdb/doc/Makefile340
-rw-r--r--gnu/usr.bin/gdb/doc/Makefile.in327
-rw-r--r--gnu/usr.bin/gdb/doc/a4rc.sed11
-rw-r--r--gnu/usr.bin/gdb/doc/all-cfg.texi117
-rwxr-xr-xgnu/usr.bin/gdb/doc/config.status5
-rw-r--r--gnu/usr.bin/gdb/doc/configure.in7
-rw-r--r--gnu/usr.bin/gdb/doc/gdb-cfg.texi117
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info213
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-11304
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-21165
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-31264
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-41349
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-51215
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-61220
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-71233
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-8657
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.texinfo8591
-rw-r--r--gnu/usr.bin/gdb/doc/gdbint.texinfo2658
-rw-r--r--gnu/usr.bin/gdb/doc/h8-cfg.texi47
-rw-r--r--gnu/usr.bin/gdb/doc/libgdb.texinfo1471
-rw-r--r--gnu/usr.bin/gdb/doc/lpsrc.sed13
-rw-r--r--gnu/usr.bin/gdb/doc/psrc.sed13
-rw-r--r--gnu/usr.bin/gdb/doc/refcard.ps798
-rw-r--r--gnu/usr.bin/gdb/doc/refcard.tex646
-rw-r--r--gnu/usr.bin/gdb/doc/remote.texi1294
-rw-r--r--gnu/usr.bin/gdb/doc/stabs.texinfo3795
-rw-r--r--gnu/usr.bin/gdb/gdb.13
-rw-r--r--gnu/usr.bin/gdb/gdb/COPYING339
-rw-r--r--gnu/usr.bin/gdb/gdb/Makefile72
-rw-r--r--gnu/usr.bin/gdb/gdb/ansidecl.h139
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/aout64.h431
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ar.h32
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ranlib.h62
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/stab.def264
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/stab_gnu.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/blockframe.c821
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.c3301
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.h372
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.c950
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.h259
-rw-r--r--gnu/usr.bin/gdb/gdb/c-exp.y1601
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.c447
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/c-typeprint.c797
-rw-r--r--gnu/usr.bin/gdb/gdb/c-valprint.c416
-rw-r--r--gnu/usr.bin/gdb/gdb/call-cmds.h28
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-exp.y1997
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.c341
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-typeprint.c225
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-valprint.c332
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/ecoff.h262
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/internal.h538
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/sym.h477
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/symconst.h175
-rw-r--r--gnu/usr.bin/gdb/gdb/coffread.c2071
-rw-r--r--gnu/usr.bin/gdb/gdb/command.c1310
-rw-r--r--gnu/usr.bin/gdb/gdb/command.h241
-rw-r--r--gnu/usr.bin/gdb/gdb/complaints.c158
-rw-r--r--gnu/usr.bin/gdb/gdb/complaints.h46
-rw-r--r--gnu/usr.bin/gdb/gdb/copying.c327
-rw-r--r--gnu/usr.bin/gdb/gdb/core.c291
-rw-r--r--gnu/usr.bin/gdb/gdb/coredep.c118
-rw-r--r--gnu/usr.bin/gdb/gdb/corelow.c328
-rw-r--r--gnu/usr.bin/gdb/gdb/cp-valprint.c484
-rw-r--r--gnu/usr.bin/gdb/gdb/dbxread.c2234
-rw-r--r--gnu/usr.bin/gdb/gdb/dcache.c236
-rw-r--r--gnu/usr.bin/gdb/gdb/dcache.h83
-rw-r--r--gnu/usr.bin/gdb/gdb/defs.h901
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.c190
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.h77
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-asm.h176
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-buf.c69
-rw-r--r--gnu/usr.bin/gdb/gdb/dwarfread.c3866
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/common.h216
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/dwarf.h314
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/external.h190
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/internal.h195
-rw-r--r--gnu/usr.bin/gdb/gdb/elfread.c729
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.c198
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.h58
-rw-r--r--gnu/usr.bin/gdb/gdb/eval.c1213
-rw-r--r--gnu/usr.bin/gdb/gdb/exec.c489
-rw-r--r--gnu/usr.bin/gdb/gdb/expprint.c623
-rw-r--r--gnu/usr.bin/gdb/gdb/expression.h313
-rw-r--r--gnu/usr.bin/gdb/gdb/findvar.c971
-rw-r--r--gnu/usr.bin/gdb/gdb/fopen-same.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/fork-child.c310
-rw-r--r--gnu/usr.bin/gdb/gdb/frame.h238
-rw-r--r--gnu/usr.bin/gdb/gdb/freebsd-nat.c323
-rw-r--r--gnu/usr.bin/gdb/gdb/freebsd-solib.c1469
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb-stabs.h76
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb.1371
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcmd.h101
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcore.h129
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.c1440
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.h704
-rw-r--r--gnu/usr.bin/gdb/gdb/getopt.h129
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-dis.c1952
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-pinsn.c37
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-tdep.c595
-rw-r--r--gnu/usr.bin/gdb/gdb/infcmd.c1423
-rw-r--r--gnu/usr.bin/gdb/gdb/inferior.h401
-rw-r--r--gnu/usr.bin/gdb/gdb/inflow.c662
-rw-r--r--gnu/usr.bin/gdb/gdb/infptrace.c436
-rw-r--r--gnu/usr.bin/gdb/gdb/infrun.c1848
-rw-r--r--gnu/usr.bin/gdb/gdb/inftarg.c310
-rw-r--r--gnu/usr.bin/gdb/gdb/init.c47
-rw-r--r--gnu/usr.bin/gdb/gdb/language.c1332
-rw-r--r--gnu/usr.bin/gdb/gdb/language.h413
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-exp.y1169
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-lang.c457
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-typeprint.c49
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-valprint.c45
-rw-r--r--gnu/usr.bin/gdb/gdb/main.c2799
-rw-r--r--gnu/usr.bin/gdb/gdb/maint.c305
-rw-r--r--gnu/usr.bin/gdb/gdb/mem-break.c104
-rw-r--r--gnu/usr.bin/gdb/gdb/minsyms.c597
-rw-r--r--gnu/usr.bin/gdb/gdb/mipsread.c3653
-rw-r--r--gnu/usr.bin/gdb/gdb/nlmread.c300
-rw-r--r--gnu/usr.bin/gdb/gdb/nm.h44
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.c773
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.h437
-rw-r--r--gnu/usr.bin/gdb/gdb/obstack.h490
-rw-r--r--gnu/usr.bin/gdb/gdb/parse.c827
-rw-r--r--gnu/usr.bin/gdb/gdb/parser-defs.h188
-rw-r--r--gnu/usr.bin/gdb/gdb/partial-stab.h618
-rw-r--r--gnu/usr.bin/gdb/gdb/printcmd.c2078
-rw-r--r--gnu/usr.bin/gdb/gdb/putenv.c111
-rw-r--r--gnu/usr.bin/gdb/gdb/regex.c1725
-rw-r--r--gnu/usr.bin/gdb/gdb/regex.h179
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.c645
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.h149
-rw-r--r--gnu/usr.bin/gdb/gdb/remote.c1272
-rw-r--r--gnu/usr.bin/gdb/gdb/ser-unix.c633
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.c261
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.h153
-rw-r--r--gnu/usr.bin/gdb/gdb/signals.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/solib.h56
-rw-r--r--gnu/usr.bin/gdb/gdb/source.c1398
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.c3770
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.h194
-rw-r--r--gnu/usr.bin/gdb/gdb/stack.c1379
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.c1489
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.h228
-rw-r--r--gnu/usr.bin/gdb/gdb/symmisc.c857
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.c3035
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.h1124
-rw-r--r--gnu/usr.bin/gdb/gdb/target.c789
-rw-r--r--gnu/usr.bin/gdb/gdb/target.h465
-rw-r--r--gnu/usr.bin/gdb/gdb/terminal.h62
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.c248
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/tm-i386v.h309
-rw-r--r--gnu/usr.bin/gdb/gdb/tm.h76
-rw-r--r--gnu/usr.bin/gdb/gdb/typeprint.c297
-rw-r--r--gnu/usr.bin/gdb/gdb/typeprint.h21
-rw-r--r--gnu/usr.bin/gdb/gdb/utils.c1547
-rw-r--r--gnu/usr.bin/gdb/gdb/valarith.c969
-rw-r--r--gnu/usr.bin/gdb/gdb/valops.c1819
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.c1063
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.h40
-rw-r--r--gnu/usr.bin/gdb/gdb/value.h502
-rw-r--r--gnu/usr.bin/gdb/gdb/values.c1502
-rw-r--r--gnu/usr.bin/gdb/gdb/version.c3
-rw-r--r--gnu/usr.bin/gdb/gdb/wait.h38
-rw-r--r--gnu/usr.bin/gdb/gdb/xm.h31
-rw-r--r--gnu/usr.bin/gdb/kgdb_proto.h63
-rw-r--r--gnu/usr.bin/gdb/libiberty/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/libiberty/Makefile13
-rw-r--r--gnu/usr.bin/gdb/libiberty/README.FreeBSD7
-rw-r--r--gnu/usr.bin/gdb/libiberty/alloca-conf.h11
-rw-r--r--gnu/usr.bin/gdb/libiberty/argv.c332
-rw-r--r--gnu/usr.bin/gdb/libiberty/basename.c56
-rw-r--r--gnu/usr.bin/gdb/libiberty/concat.c118
-rw-r--r--gnu/usr.bin/gdb/libiberty/config.h1
-rw-r--r--gnu/usr.bin/gdb/libiberty/cplus-dem.c2669
-rw-r--r--gnu/usr.bin/gdb/libiberty/fdmatch.c71
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt.c750
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt1.c180
-rw-r--r--gnu/usr.bin/gdb/libiberty/ieee-float.c150
-rw-r--r--gnu/usr.bin/gdb/libiberty/ieee-float.h65
-rw-r--r--gnu/usr.bin/gdb/libiberty/obstack.c460
-rw-r--r--gnu/usr.bin/gdb/libiberty/sigsetmask.c44
-rw-r--r--gnu/usr.bin/gdb/libiberty/spaces.c67
-rw-r--r--gnu/usr.bin/gdb/libiberty/strerror.c811
-rw-r--r--gnu/usr.bin/gdb/libiberty/strsignal.c634
-rw-r--r--gnu/usr.bin/gdb/libiberty/xmalloc.c58
-rw-r--r--gnu/usr.bin/gdb/main.c2241
-rw-r--r--gnu/usr.bin/gdb/mmalloc/Makefile10
-rw-r--r--gnu/usr.bin/gdb/mmalloc/README.FreeBSD7
-rw-r--r--gnu/usr.bin/gdb/mmalloc/attach.c218
-rw-r--r--gnu/usr.bin/gdb/mmalloc/detach.c71
-rw-r--r--gnu/usr.bin/gdb/mmalloc/keys.c66
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mcalloc.c53
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mfree.c247
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.c334
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.h390
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.texi258
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmap-sup.c144
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmcheck.c196
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmemalign.c64
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmstats.c46
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmtrace.c166
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mrealloc.c160
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mvalloc.c40
-rw-r--r--gnu/usr.bin/gdb/mmalloc/sbrk-sup.c96
-rw-r--r--gnu/usr.bin/gdb/readline/ChangeLog98
-rw-r--r--gnu/usr.bin/gdb/readline/Makefile.gnu114
-rw-r--r--gnu/usr.bin/gdb/readline/chardefs.h50
-rw-r--r--gnu/usr.bin/gdb/readline/emacs_keymap.c472
-rw-r--r--gnu/usr.bin/gdb/readline/funmap.c217
-rw-r--r--gnu/usr.bin/gdb/readline/history.c1462
-rw-r--r--gnu/usr.bin/gdb/readline/history.h108
-rw-r--r--gnu/usr.bin/gdb/readline/keymaps.c172
-rw-r--r--gnu/usr.bin/gdb/readline/keymaps.h53
-rw-r--r--gnu/usr.bin/gdb/readline/readline.c5557
-rw-r--r--gnu/usr.bin/gdb/readline/readline.h161
-rw-r--r--gnu/usr.bin/gdb/readline/vi_keymap.c484
-rw-r--r--gnu/usr.bin/gdb/readline/vi_mode.c875
-rw-r--r--gnu/usr.bin/gdb/remote.c626
-rw-r--r--gnu/usr.bin/gdb/symtab.c2473
-rw-r--r--gnu/usr.bin/gdb/utils.c1096
-rw-r--r--gnu/usr.bin/gdb/xgdb/xgdb.c700
-rw-r--r--gnu/usr.bin/groff/Makefile.cfg5
-rw-r--r--gnu/usr.bin/groff/addftinfo/Makefile1
-rw-r--r--gnu/usr.bin/groff/devices/devascii/R.proto19
-rw-r--r--gnu/usr.bin/groff/eqn/Makefile1
-rw-r--r--gnu/usr.bin/groff/grodvi/Makefile1
-rw-r--r--gnu/usr.bin/groff/groff/Makefile1
-rw-r--r--gnu/usr.bin/groff/grops/Makefile1
-rw-r--r--gnu/usr.bin/groff/grops/psrm.cc3
-rw-r--r--gnu/usr.bin/groff/grotty/Makefile1
-rw-r--r--gnu/usr.bin/groff/indxbib/Makefile1
-rw-r--r--gnu/usr.bin/groff/libbib/Makefile1
-rw-r--r--gnu/usr.bin/groff/libdriver/Makefile1
-rw-r--r--gnu/usr.bin/groff/libgroff/Makefile1
-rw-r--r--gnu/usr.bin/groff/lkbib/Makefile1
-rw-r--r--gnu/usr.bin/groff/lookbib/Makefile1
-rw-r--r--gnu/usr.bin/groff/pic/Makefile1
-rw-r--r--gnu/usr.bin/groff/refer/Makefile1
-rw-r--r--gnu/usr.bin/groff/soelim/Makefile1
-rw-r--r--gnu/usr.bin/groff/tbl/Makefile1
-rw-r--r--gnu/usr.bin/groff/tfmtodit/Makefile1
-rw-r--r--gnu/usr.bin/groff/troff/Makefile1
-rw-r--r--gnu/usr.bin/groff/xditview/device.c6
-rw-r--r--gnu/usr.bin/gzip/Makefile1
-rw-r--r--gnu/usr.bin/kgdb/COPYING249
-rw-r--r--gnu/usr.bin/kgdb/ChangeLog (renamed from gnu/usr.bin/gdb/ChangeLog)0
-rw-r--r--gnu/usr.bin/kgdb/Gdbinit (renamed from gnu/usr.bin/gdb/Gdbinit)0
-rw-r--r--gnu/usr.bin/kgdb/Makefile36
-rw-r--r--gnu/usr.bin/kgdb/Makefile.dist (renamed from gnu/usr.bin/gdb/Makefile.dist)0
-rw-r--r--gnu/usr.bin/kgdb/Projects (renamed from gnu/usr.bin/gdb/Projects)0
-rw-r--r--gnu/usr.bin/kgdb/README.gnu (renamed from gnu/usr.bin/gdb/README.gnu)0
-rw-r--r--gnu/usr.bin/kgdb/XGdbinit.samp (renamed from gnu/usr.bin/gdb/XGdbinit.samp)0
-rw-r--r--gnu/usr.bin/kgdb/Xgdb.ad (renamed from gnu/usr.bin/gdb/Xgdb.ad)0
-rw-r--r--gnu/usr.bin/kgdb/blockframe.c (renamed from gnu/usr.bin/gdb/blockframe.c)0
-rw-r--r--gnu/usr.bin/kgdb/breakpoint.c (renamed from gnu/usr.bin/gdb/breakpoint.c)0
-rw-r--r--gnu/usr.bin/kgdb/command.c (renamed from gnu/usr.bin/gdb/command.c)0
-rw-r--r--gnu/usr.bin/kgdb/command.h (renamed from gnu/usr.bin/gdb/command.h)0
-rw-r--r--gnu/usr.bin/kgdb/config/Makefile.i386 (renamed from gnu/usr.bin/gdb/config/Makefile.i386)0
-rw-r--r--gnu/usr.bin/kgdb/config/default-dep.c (renamed from gnu/usr.bin/gdb/config/default-dep.c)0
-rw-r--r--gnu/usr.bin/kgdb/config/i386-dep.c (renamed from gnu/usr.bin/gdb/config/i386-dep.c)0
-rw-r--r--gnu/usr.bin/kgdb/config/i386-pinsn.c (renamed from gnu/usr.bin/gdb/config/i386-pinsn.c)0
-rw-r--r--gnu/usr.bin/kgdb/config/i386bsd-dep.c1889
-rw-r--r--gnu/usr.bin/kgdb/config/m-i386-sv32.h (renamed from gnu/usr.bin/gdb/config/m-i386-sv32.h)0
-rw-r--r--gnu/usr.bin/kgdb/config/m-i386.h (renamed from gnu/usr.bin/gdb/config/m-i386.h)0
-rw-r--r--gnu/usr.bin/kgdb/config/m-i386bsd.h (renamed from gnu/usr.bin/gdb/config/m-i386bsd.h)0
-rw-r--r--gnu/usr.bin/kgdb/config/m-i386g-sv32.h (renamed from gnu/usr.bin/gdb/config/m-i386g-sv32.h)0
-rw-r--r--gnu/usr.bin/kgdb/config/m-i386gas.h (renamed from gnu/usr.bin/gdb/config/m-i386gas.h)0
-rw-r--r--gnu/usr.bin/kgdb/copying.c (renamed from gnu/usr.bin/gdb/copying.c)0
-rw-r--r--gnu/usr.bin/kgdb/core.c (renamed from gnu/usr.bin/gdb/core.c)0
-rw-r--r--gnu/usr.bin/kgdb/cplus-dem.c (renamed from gnu/usr.bin/gdb/cplus-dem.c)0
-rw-r--r--gnu/usr.bin/kgdb/dbxread.c (renamed from gnu/usr.bin/gdb/dbxread.c)0
-rw-r--r--gnu/usr.bin/kgdb/defs.h (renamed from gnu/usr.bin/gdb/defs.h)0
-rw-r--r--gnu/usr.bin/kgdb/environ.c (renamed from gnu/usr.bin/gdb/environ.c)0
-rw-r--r--gnu/usr.bin/kgdb/environ.h (renamed from gnu/usr.bin/gdb/environ.h)0
-rw-r--r--gnu/usr.bin/kgdb/eval.c (renamed from gnu/usr.bin/gdb/eval.c)0
-rw-r--r--gnu/usr.bin/kgdb/expprint.c (renamed from gnu/usr.bin/gdb/expprint.c)0
-rw-r--r--gnu/usr.bin/kgdb/expread.y (renamed from gnu/usr.bin/gdb/expread.y)0
-rw-r--r--gnu/usr.bin/kgdb/expression.h (renamed from gnu/usr.bin/gdb/expression.h)0
-rw-r--r--gnu/usr.bin/kgdb/findvar.c (renamed from gnu/usr.bin/gdb/findvar.c)0
-rw-r--r--gnu/usr.bin/kgdb/frame.h (renamed from gnu/usr.bin/gdb/frame.h)0
-rw-r--r--gnu/usr.bin/kgdb/getpagesize.h (renamed from gnu/usr.bin/gdb/getpagesize.h)0
-rw-r--r--gnu/usr.bin/kgdb/infcmd.c (renamed from gnu/usr.bin/gdb/infcmd.c)0
-rw-r--r--gnu/usr.bin/kgdb/inferior.h (renamed from gnu/usr.bin/gdb/inferior.h)0
-rw-r--r--gnu/usr.bin/kgdb/inflow.c (renamed from gnu/usr.bin/gdb/inflow.c)0
-rw-r--r--gnu/usr.bin/kgdb/infrun.c (renamed from gnu/usr.bin/gdb/infrun.c)0
-rw-r--r--gnu/usr.bin/kgdb/kgdb.115
-rw-r--r--gnu/usr.bin/kgdb/kgdb_proto.h63
-rw-r--r--gnu/usr.bin/kgdb/main.c2236
-rw-r--r--gnu/usr.bin/kgdb/ngdb.i386/Makefile (renamed from gnu/usr.bin/gdb/ngdb.i386/Makefile)0
-rw-r--r--gnu/usr.bin/kgdb/obstack.c (renamed from gnu/usr.bin/gdb/obstack.c)0
-rw-r--r--gnu/usr.bin/kgdb/obstack.h (renamed from gnu/usr.bin/gdb/obstack.h)0
-rw-r--r--gnu/usr.bin/kgdb/printcmd.c (renamed from gnu/usr.bin/gdb/printcmd.c)0
-rw-r--r--gnu/usr.bin/kgdb/regex.c (renamed from gnu/usr.bin/gdb/regex.c)0
-rw-r--r--gnu/usr.bin/kgdb/regex.h (renamed from gnu/usr.bin/gdb/regex.h)0
-rw-r--r--gnu/usr.bin/kgdb/remote-sl.c (renamed from gnu/usr.bin/gdb/remote-sl.c)0
-rw-r--r--gnu/usr.bin/kgdb/remote.c626
-rw-r--r--gnu/usr.bin/kgdb/source.c (renamed from gnu/usr.bin/gdb/source.c)0
-rw-r--r--gnu/usr.bin/kgdb/stab.def (renamed from gnu/usr.bin/gdb/stab.def)0
-rw-r--r--gnu/usr.bin/kgdb/stack.c (renamed from gnu/usr.bin/gdb/stack.c)0
-rw-r--r--gnu/usr.bin/kgdb/symmisc.c (renamed from gnu/usr.bin/gdb/symmisc.c)0
-rw-r--r--gnu/usr.bin/kgdb/symseg.h (renamed from gnu/usr.bin/gdb/symseg.h)0
-rw-r--r--gnu/usr.bin/kgdb/symtab.c2473
-rw-r--r--gnu/usr.bin/kgdb/symtab.h (renamed from gnu/usr.bin/gdb/symtab.h)0
-rw-r--r--gnu/usr.bin/kgdb/utils.c1096
-rw-r--r--gnu/usr.bin/kgdb/valarith.c (renamed from gnu/usr.bin/gdb/valarith.c)0
-rw-r--r--gnu/usr.bin/kgdb/valops.c (renamed from gnu/usr.bin/gdb/valops.c)0
-rw-r--r--gnu/usr.bin/kgdb/valprint.c (renamed from gnu/usr.bin/gdb/valprint.c)0
-rw-r--r--gnu/usr.bin/kgdb/value.h (renamed from gnu/usr.bin/gdb/value.h)0
-rw-r--r--gnu/usr.bin/kgdb/values.c (renamed from gnu/usr.bin/gdb/values.c)0
-rw-r--r--gnu/usr.bin/kgdb/version.c (renamed from gnu/usr.bin/gdb/version.c)0
-rw-r--r--gnu/usr.bin/kgdb/wait.h (renamed from gnu/usr.bin/gdb/wait.h)0
-rw-r--r--gnu/usr.bin/kgdb/xgdb/Makefile (renamed from gnu/usr.bin/gdb/xgdb/Makefile)0
-rw-r--r--gnu/usr.bin/kgdb/xgdb/xgdb.c700
-rw-r--r--gnu/usr.bin/ld/etc.c153
-rw-r--r--gnu/usr.bin/ld/i386/md.c20
-rw-r--r--gnu/usr.bin/ld/i386/md.h4
-rw-r--r--gnu/usr.bin/ld/i386/mdprologue.S4
-rw-r--r--gnu/usr.bin/ld/ld.17
-rw-r--r--gnu/usr.bin/ld/ld.c766
-rw-r--r--gnu/usr.bin/ld/ld.h35
-rw-r--r--gnu/usr.bin/ld/ldconfig/Makefile4
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.82
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.c21
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.11
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.c56
-rw-r--r--gnu/usr.bin/ld/lib.c234
-rw-r--r--gnu/usr.bin/ld/rrs.c75
-rw-r--r--gnu/usr.bin/ld/rtld/Makefile4
-rw-r--r--gnu/usr.bin/ld/rtld/malloc.c5
-rw-r--r--gnu/usr.bin/ld/rtld/rtld.c124
-rw-r--r--gnu/usr.bin/ld/shlib.c39
-rw-r--r--gnu/usr.bin/ld/sparc/md.c12
-rw-r--r--gnu/usr.bin/ld/symbol.c44
-rw-r--r--gnu/usr.bin/ld/warnings.c217
-rw-r--r--gnu/usr.bin/man/Makefile.inc2
-rw-r--r--gnu/usr.bin/man/apropos/Makefile24
-rw-r--r--gnu/usr.bin/man/catman/Makefile17
-rw-r--r--gnu/usr.bin/man/catman/catman36
-rw-r--r--gnu/usr.bin/man/catman/catman.sh43
-rw-r--r--gnu/usr.bin/man/lib/Makefile5
-rw-r--r--gnu/usr.bin/man/lib/config.h_dist16
-rw-r--r--gnu/usr.bin/man/makewhatis/Makefile4
-rw-r--r--gnu/usr.bin/man/makewhatis/makewhatis.sh9
-rw-r--r--gnu/usr.bin/man/man/Makefile3
-rw-r--r--gnu/usr.bin/man/man/man.c75
-rw-r--r--gnu/usr.bin/man/man/man.man4
-rw-r--r--gnu/usr.bin/man/manpath/Makefile2
-rw-r--r--gnu/usr.bin/man/manpath/manpath.config4
-rw-r--r--gnu/usr.bin/man/whatis/Makefile23
-rw-r--r--gnu/usr.bin/patch/patch.16
-rw-r--r--gnu/usr.bin/patch/patch.c26
-rw-r--r--gnu/usr.bin/patch/pch.c6
-rw-r--r--gnu/usr.bin/ptx/.stamp-h.in (renamed from contrib/xntpd/compilers/.keep_me)0
-rw-r--r--gnu/usr.bin/ptx/COPYING339
-rw-r--r--gnu/usr.bin/ptx/ChangeLog546
-rw-r--r--gnu/usr.bin/ptx/Makefile10
-rw-r--r--gnu/usr.bin/ptx/NEWS53
-rw-r--r--gnu/usr.bin/ptx/README23
-rw-r--r--gnu/usr.bin/ptx/THANKS23
-rw-r--r--gnu/usr.bin/ptx/TODO94
-rw-r--r--gnu/usr.bin/ptx/alloca.c484
-rw-r--r--gnu/usr.bin/ptx/argmatch.c94
-rw-r--r--gnu/usr.bin/ptx/bumpalloc.h58
-rw-r--r--gnu/usr.bin/ptx/check-out65
-rw-r--r--gnu/usr.bin/ptx/config.h57
-rw-r--r--gnu/usr.bin/ptx/diacrit.c148
-rw-r--r--gnu/usr.bin/ptx/diacrit.h16
-rw-r--r--gnu/usr.bin/ptx/error.c117
-rw-r--r--gnu/usr.bin/ptx/examples/README21
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/Makefile28
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/README41
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/footer.tex1
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/header.tex21
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/tip.forgptx10
-rw-r--r--gnu/usr.bin/ptx/examples/ajay/x.pl22
-rw-r--r--gnu/usr.bin/ptx/examples/ignore/README65
-rw-r--r--gnu/usr.bin/ptx/examples/ignore/bix109
-rw-r--r--gnu/usr.bin/ptx/examples/ignore/eign163
-rwxr-xr-xgnu/usr.bin/ptx/examples/include.pl79
-rw-r--r--gnu/usr.bin/ptx/examples/latex/Makefile15
-rw-r--r--gnu/usr.bin/ptx/examples/latex/README10
-rw-r--r--gnu/usr.bin/ptx/examples/latex/latex.tex11
-rw-r--r--gnu/usr.bin/ptx/examples/latex/table.tex65
-rw-r--r--gnu/usr.bin/ptx/examples/luke/README2
-rw-r--r--gnu/usr.bin/ptx/examples/luke/xxroff.sh108
-rw-r--r--gnu/usr.bin/ptx/getopt.c757
-rw-r--r--gnu/usr.bin/ptx/getopt.h129
-rw-r--r--gnu/usr.bin/ptx/getopt1.c187
-rwxr-xr-xgnu/usr.bin/ptx/mkinstalldirs35
-rw-r--r--gnu/usr.bin/ptx/ptx.c2237
-rw-r--r--gnu/usr.bin/ptx/ptx.info496
-rw-r--r--gnu/usr.bin/ptx/ptx.texinfo554
-rw-r--r--gnu/usr.bin/ptx/regex.h490
-rw-r--r--gnu/usr.bin/ptx/texinfo.tex4053
-rw-r--r--gnu/usr.bin/ptx/xmalloc.c88
-rw-r--r--gnu/usr.bin/rcs/co/co.110
-rw-r--r--gnu/usr.bin/rcs/co/co.c13
-rw-r--r--gnu/usr.bin/rcs/lib/Makefile2
-rw-r--r--gnu/usr.bin/rcs/lib/rcsbase.h10
-rw-r--r--gnu/usr.bin/rcs/lib/rcsedit.c13
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeys.c61
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.16
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.c29
-rw-r--r--gnu/usr.bin/tar/Makefile1
-rw-r--r--gnu/usr.bin/tar/extract.c36
-rw-r--r--gnu/usr.bin/tar/tar.c3
-rw-r--r--gnu/usr.bin/tar/tar.h1
-rw-r--r--include/Makefile2
-rw-r--r--include/ar.h2
-rw-r--r--include/assert.h2
-rw-r--r--include/ctype.h144
-rw-r--r--include/grp.h2
-rw-r--r--include/kvm.h4
-rw-r--r--include/nlist.h2
-rw-r--r--include/octype.h82
-rw-r--r--include/protocols/dumprestore.h2
-rw-r--r--include/pwd.h2
-rw-r--r--include/rpcsvc/Makefile4
-rw-r--r--include/rune.h66
-rw-r--r--include/runetype.h101
-rw-r--r--include/setjmp.h2
-rw-r--r--include/skey.h36
-rw-r--r--include/stddef.h12
-rw-r--r--include/stdio.h8
-rw-r--r--include/stdlib.h48
-rw-r--r--include/time.h2
-rw-r--r--include/utmp.h2
-rw-r--r--include/varargs.h2
-rw-r--r--lib/Makefile10
-rw-r--r--lib/Makefile.inc2
-rw-r--r--lib/csu.i386/Makefile13
-rw-r--r--lib/csu.i386/c++rt0.c80
-rw-r--r--lib/csu.i386/crt0.c11
-rw-r--r--lib/csu.i386/crt1.c47
-rw-r--r--lib/libc/Makefile2
-rw-r--r--lib/libc/compat-43/Makefile.inc5
-rw-r--r--lib/libc/compat-43/setrgid.c61
-rw-r--r--lib/libc/compat-43/setruid.c61
-rw-r--r--lib/libc/db/hash/hash.c2
-rw-r--r--lib/libc/db/recno/rec_open.c2
-rw-r--r--lib/libc/gen/Makefile.inc13
-rw-r--r--lib/libc/gen/ctype_.c8
-rw-r--r--lib/libc/gen/getcap.32
-rw-r--r--lib/libc/gen/getcap.c29
-rw-r--r--lib/libc/gen/getfsent.32
-rw-r--r--lib/libc/gen/getmntinfo.32
-rw-r--r--lib/libc/gen/getpwent.314
-rw-r--r--lib/libc/gen/getpwent.c93
-rw-r--r--lib/libc/gen/isctype.c142
-rw-r--r--lib/libc/gen/semconfig.c2
-rw-r--r--lib/libc/gen/setmode.c11
-rw-r--r--lib/libc/gen/setrgid.c50
-rw-r--r--lib/libc/gen/setruid.c50
-rw-r--r--lib/libc/gen/setuid.399
-rw-r--r--lib/libc/i386/DEFS.h2
-rw-r--r--lib/libc/i386/string/bcmp.S11
-rw-r--r--lib/libc/i386/string/memcmp.S15
-rw-r--r--lib/libc/i386/string/memmove.S17
-rw-r--r--lib/libc/i386/string/memset.S16
-rw-r--r--lib/libc/i386/string/strcmp.S4
-rw-r--r--lib/libc/i386/string/strncmp.S69
-rw-r--r--lib/libc/locale/Makefile.inc18
-rw-r--r--lib/libc/locale/ansi.c148
-rw-r--r--lib/libc/locale/euc.4231
-rw-r--r--lib/libc/locale/euc.c220
-rw-r--r--lib/libc/locale/frune.c103
-rw-r--r--lib/libc/locale/isctype.c170
-rw-r--r--lib/libc/locale/mbrune.3157
-rw-r--r--lib/libc/locale/mbrune.c112
-rw-r--r--lib/libc/locale/multibyte.3241
-rw-r--r--lib/libc/locale/none.c93
-rw-r--r--lib/libc/locale/rune.3269
-rw-r--r--lib/libc/locale/rune.c334
-rw-r--r--lib/libc/locale/setlocale.3321
-rw-r--r--lib/libc/locale/setlocale.c198
-rw-r--r--lib/libc/locale/table.c160
-rw-r--r--lib/libc/locale/utf2.487
-rw-r--r--lib/libc/locale/utf2.c148
-rw-r--r--lib/libc/net/gethostnamadr.c1
-rw-r--r--lib/libc/net/ns_addr.c4
-rw-r--r--lib/libc/net/rcmd.c30
-rw-r--r--lib/libc/stdio/Makefile.inc7
-rw-r--r--lib/libc/stdio/fclose.c2
-rw-r--r--lib/libc/stdio/fgetline.3124
-rw-r--r--lib/libc/stdio/fgetline.c1
-rw-r--r--lib/libc/stdio/fgetln.3124
-rw-r--r--lib/libc/stdio/fgetln.c162
-rw-r--r--lib/libc/stdio/fseek.c2
-rw-r--r--lib/libc/stdio/gets.c13
-rw-r--r--lib/libc/stdio/local.h2
-rw-r--r--lib/libc/stdio/printf.32
-rw-r--r--lib/libc/stdlib/Makefile.inc2
-rw-r--r--lib/libc/stdlib/multibyte.c105
-rw-r--r--lib/libc/stdlib/rand.c2
-rw-r--r--lib/libc/string/index.32
-rw-r--r--lib/libc/string/strftime.c1
-rw-r--r--lib/libc/sys/Makefile.inc9
-rw-r--r--lib/libc/sys/execve.22
-rw-r--r--lib/libc/sys/setregid.22
-rw-r--r--lib/libc/sys/setreuid.22
-rw-r--r--lib/libc/sys/setuid.2121
-rw-r--r--lib/libc/sys/sigsuspend.24
-rw-r--r--lib/libcompat/Makefile18
-rw-r--r--lib/libcompat/cftime.c63
-rw-r--r--lib/libcompat/ftime.c69
-rw-r--r--lib/libcompat/libcompat.3205
-rw-r--r--lib/libcompat/regex.c93
-rw-r--r--lib/libcompat/regexp/COPYRIGHT22
-rw-r--r--lib/libcompat/regexp/Makefile.inc20
-rw-r--r--lib/libcompat/regexp/README84
-rw-r--r--lib/libcompat/regexp/regerror.c18
-rw-r--r--lib/libcompat/regexp/regexp.3321
-rw-r--r--lib/libcompat/regexp/regexp.c1320
-rw-r--r--lib/libcompat/regexp/regexp.h21
-rw-r--r--lib/libcompat/regexp/regmagic.h5
-rw-r--r--lib/libcompat/regexp/regsub.c81
-rw-r--r--lib/libcompat/setrgid.c49
-rw-r--r--lib/libcompat/setruid.c49
-rw-r--r--lib/libcompat/sgtty.c67
-rw-r--r--lib/libcurses/Makefile3
-rw-r--r--lib/libcurses/cr_put.c24
-rw-r--r--lib/libcurses/curses.h1
-rw-r--r--lib/libcurses/refresh.c42
-rw-r--r--lib/libcurses/setterm.c27
-rw-r--r--lib/libcurses/tstp.c8
-rw-r--r--lib/libcurses/tty.c41
-rw-r--r--lib/libmalloc/CHANGES58
-rw-r--r--lib/libmalloc/COPYRIGHT23
-rw-r--r--lib/libmalloc/Makefile17
-rw-r--r--lib/libmalloc/Makefile.moraes187
-rw-r--r--lib/libmalloc/NOTE151
-rw-r--r--lib/libmalloc/README68
-rw-r--r--lib/libmalloc/TODO62
-rw-r--r--lib/libmalloc/_emalloc.c55
-rw-r--r--lib/libmalloc/_malloc.c88
-rw-r--r--lib/libmalloc/_memalign.c37
-rw-r--r--lib/libmalloc/_strdup.c23
-rw-r--r--lib/libmalloc/_strsave.c23
-rw-r--r--lib/libmalloc/align.h94
-rw-r--r--lib/libmalloc/assert.h10
-rw-r--r--lib/libmalloc/botch.c45
-rw-r--r--lib/libmalloc/bsd.lib.mk269
-rw-r--r--lib/libmalloc/defs.h386
-rw-r--r--lib/libmalloc/dumpheap.c107
-rw-r--r--lib/libmalloc/emalloc.c69
-rw-r--r--lib/libmalloc/externs.h113
-rw-r--r--lib/libmalloc/getmem.c108
-rw-r--r--lib/libmalloc/globals.c87
-rw-r--r--lib/libmalloc/globals.h43
-rw-r--r--lib/libmalloc/globrename.h46
-rw-r--r--lib/libmalloc/leak.c160
-rw-r--r--lib/libmalloc/malloc.c622
-rw-r--r--lib/libmalloc/malloc.doc653
-rw-r--r--lib/libmalloc/malloc.h136
-rw-r--r--lib/libmalloc/memalign.c160
-rw-r--r--lib/libmalloc/setopts.c120
-rw-r--r--lib/libmalloc/sptree.c763
-rw-r--r--lib/libmalloc/sptree.h65
-rw-r--r--lib/libmalloc/stats.c38
-rw-r--r--lib/libmalloc/strdup.c26
-rw-r--r--lib/libmalloc/strsave.c21
-rwxr-xr-xlib/libmalloc/tests/munge.sh40
-rwxr-xr-xlib/libmalloc/tests/plot.sh81
-rwxr-xr-xlib/libmalloc/tests/regress11
-rw-r--r--lib/libmalloc/tests/simumalloc.c239
-rw-r--r--lib/libmalloc/tests/t1.c40
-rw-r--r--lib/libmalloc/tests/t2.c37
-rw-r--r--lib/libmalloc/tests/t3.c110
-rw-r--r--lib/libmalloc/tests/t4.c20
-rw-r--r--lib/libmalloc/tests/t5.c31
-rw-r--r--lib/libmalloc/tests/test.out415
-rw-r--r--lib/libmalloc/tests/testmalloc.c182
-rw-r--r--lib/libmalloc/tests/testmemalign.c16
-rwxr-xr-xlib/libmalloc/tests/testrun.sh28
-rw-r--r--lib/libmalloc/tests/testsbrk.c22
-rw-r--r--lib/libmalloc/tests/teststomp.c34
-rw-r--r--lib/libmalloc/trace.h19
-rw-r--r--lib/libmalloc/verify.c81
-rw-r--r--lib/libmalloc/version.c1
-rw-r--r--lib/libpthread/include/stdio.h4
-rw-r--r--lib/libpthread/stdio/fflush.c4
-rw-r--r--lib/libpthread/stdio/ftell.c4
-rw-r--r--lib/libpthread/stdio/vfprintf.c6
-rw-r--r--lib/libskey/Makefile7
-rw-r--r--lib/libskey/authfile.c177
-rw-r--r--lib/libskey/md4.c336
-rw-r--r--lib/libskey/md4.h47
-rw-r--r--lib/libskey/pathnames.h5
-rw-r--r--lib/libskey/put.c2289
-rw-r--r--lib/libskey/skey_crypt.c37
-rw-r--r--lib/libskey/skeylogin.c328
-rw-r--r--lib/libskey/skeysubr.c225
-rw-r--r--lib/libterm/Makefile4
-rw-r--r--lib/libterm/tputs.c14
-rw-r--r--lib/libutil/kvm.c33
-rw-r--r--lib/libutil/login.c37
-rw-r--r--lib/msun/Makefile111
-rw-r--r--lib/msun/i387/DEFS.h83
-rw-r--r--lib/msun/i387/e_acos.S49
-rw-r--r--lib/msun/i387/e_asin.S48
-rw-r--r--lib/msun/i387/e_atan2.S43
-rw-r--r--lib/msun/i387/e_exp.S52
-rw-r--r--lib/msun/i387/e_fmod.S47
-rw-r--r--lib/msun/i387/e_log.S43
-rw-r--r--lib/msun/i387/e_log10.S43
-rw-r--r--lib/msun/i387/e_remainder.S47
-rw-r--r--lib/msun/i387/e_scalb.S43
-rw-r--r--lib/msun/i387/e_sqrt.S42
-rw-r--r--lib/msun/i387/s_atan.S43
-rw-r--r--lib/msun/i387/s_ceil.S57
-rw-r--r--lib/msun/i387/s_copysign.S47
-rw-r--r--lib/msun/i387/s_cos.S55
-rw-r--r--lib/msun/i387/s_finite.S45
-rw-r--r--lib/msun/i387/s_floor.S57
-rw-r--r--lib/msun/i387/s_ilogb.S52
-rw-r--r--lib/msun/i387/s_log1p.S43
-rw-r--r--lib/msun/i387/s_logb.S43
-rw-r--r--lib/msun/i387/s_rint.S42
-rw-r--r--lib/msun/i387/s_scalbn.S43
-rw-r--r--lib/msun/i387/s_significand.S43
-rw-r--r--lib/msun/i387/s_sin.S55
-rw-r--r--lib/msun/i387/s_tan.S56
-rw-r--r--lib/msun/man/acos.389
-rw-r--r--lib/msun/man/acosh.382
-rw-r--r--lib/msun/man/asin.391
-rw-r--r--lib/msun/man/asinh.370
-rw-r--r--lib/msun/man/atan.375
-rw-r--r--lib/msun/man/atan2.3189
-rw-r--r--lib/msun/man/atanh.384
-rw-r--r--lib/msun/man/ceil.363
-rw-r--r--lib/msun/man/cos.374
-rw-r--r--lib/msun/man/cosh.375
-rw-r--r--lib/msun/man/erf.383
-rw-r--r--lib/msun/man/exp.3287
-rw-r--r--lib/msun/man/fabs.367
-rw-r--r--lib/msun/man/floor.363
-rw-r--r--lib/msun/man/fmod.376
-rw-r--r--lib/msun/man/hypot.3125
-rw-r--r--lib/msun/man/ieee.3152
-rw-r--r--lib/msun/man/ieee_test.390
-rw-r--r--lib/msun/man/j0.3128
-rw-r--r--lib/msun/man/lgamma.3124
-rw-r--r--lib/msun/man/math.3633
-rw-r--r--lib/msun/man/rint.363
-rw-r--r--lib/msun/man/sin.373
-rw-r--r--lib/msun/man/sinh.375
-rw-r--r--lib/msun/man/sqrt.3121
-rw-r--r--lib/msun/man/tan.374
-rw-r--r--lib/msun/man/tanh.371
-rw-r--r--lib/msun/src/Readme211
-rw-r--r--lib/msun/src/dependencies471
-rw-r--r--lib/msun/src/e_acos.c116
-rw-r--r--lib/msun/src/e_acosh.c75
-rw-r--r--lib/msun/src/e_asin.c125
-rw-r--r--lib/msun/src/e_atan2.c132
-rw-r--r--lib/msun/src/e_atanh.c78
-rw-r--r--lib/msun/src/e_cosh.c92
-rw-r--r--lib/msun/src/e_exp.c167
-rw-r--r--lib/msun/src/e_fmod.c153
-rw-r--r--lib/msun/src/e_gamma.c35
-rw-r--r--lib/msun/src/e_gamma_r.c34
-rw-r--r--lib/msun/src/e_hypot.c125
-rw-r--r--lib/msun/src/e_j0.c488
-rw-r--r--lib/msun/src/e_j1.c486
-rw-r--r--lib/msun/src/e_jn.c282
-rw-r--r--lib/msun/src/e_lgamma.c35
-rw-r--r--lib/msun/src/e_lgamma_r.c313
-rw-r--r--lib/msun/src/e_log.c149
-rw-r--r--lib/msun/src/e_log10.c101
-rw-r--r--lib/msun/src/e_pow.c308
-rw-r--r--lib/msun/src/e_rem_pio2.c153
-rw-r--r--lib/msun/src/e_remainder.c89
-rw-r--r--lib/msun/src/e_scalb.c54
-rw-r--r--lib/msun/src/e_sinh.c85
-rw-r--r--lib/msun/src/e_sqrt.c461
-rw-r--r--lib/msun/src/fdlibm.h196
-rw-r--r--lib/msun/src/k_cos.c102
-rw-r--r--lib/msun/src/k_rem_pio2.c319
-rw-r--r--lib/msun/src/k_sin.c84
-rw-r--r--lib/msun/src/k_standard.c737
-rw-r--r--lib/msun/src/k_tan.c137
-rw-r--r--lib/msun/src/math.h224
-rw-r--r--lib/msun/src/s_asinh.c71
-rw-r--r--lib/msun/src/s_atan.c143
-rw-r--r--lib/msun/src/s_cbrt.c95
-rw-r--r--lib/msun/src/s_ceil.c88
-rw-r--r--lib/msun/src/s_copysign.c42
-rw-r--r--lib/msun/src/s_cos.c87
-rw-r--r--lib/msun/src/s_erf.c320
-rw-r--r--lib/msun/src/s_expm1.c226
-rw-r--r--lib/msun/src/s_fabs.c38
-rw-r--r--lib/msun/src/s_finite.c41
-rw-r--r--lib/msun/src/s_floor.c89
-rw-r--r--lib/msun/src/s_frexp.c67
-rw-r--r--lib/msun/src/s_ilogb.c56
-rw-r--r--lib/msun/src/s_isnan.c50
-rw-r--r--lib/msun/src/s_ldexp.c31
-rw-r--r--lib/msun/src/s_lib_version.c38
-rw-r--r--lib/msun/src/s_log1p.c175
-rw-r--r--lib/msun/src/s_logb.c48
-rw-r--r--lib/msun/src/s_matherr.c29
-rw-r--r--lib/msun/src/s_modf.c92
-rw-r--r--lib/msun/src/s_nextafter.c90
-rw-r--r--lib/msun/src/s_rint.c94
-rw-r--r--lib/msun/src/s_scalbn.c73
-rw-r--r--lib/msun/src/s_signgam.c2
-rw-r--r--lib/msun/src/s_significand.c33
-rw-r--r--lib/msun/src/s_sin.c87
-rw-r--r--lib/msun/src/s_tan.c81
-rw-r--r--lib/msun/src/s_tanh.c85
-rw-r--r--lib/msun/src/w_acos.c42
-rw-r--r--lib/msun/src/w_acosh.c41
-rw-r--r--lib/msun/src/w_asin.c43
-rw-r--r--lib/msun/src/w_atan2.c42
-rw-r--r--lib/msun/src/w_atanh.c46
-rw-r--r--lib/msun/src/w_cabs.c27
-rw-r--r--lib/msun/src/w_cosh.c41
-rw-r--r--lib/msun/src/w_drem.c15
-rw-r--r--lib/msun/src/w_exp.c52
-rw-r--r--lib/msun/src/w_fmod.c42
-rw-r--r--lib/msun/src/w_gamma.c48
-rw-r--r--lib/msun/src/w_gamma_r.c45
-rw-r--r--lib/msun/src/w_hypot.c42
-rw-r--r--lib/msun/src/w_j0.c68
-rw-r--r--lib/msun/src/w_j1.c69
-rw-r--r--lib/msun/src/w_jn.c91
-rw-r--r--lib/msun/src/w_lgamma.c48
-rw-r--r--lib/msun/src/w_lgamma_r.c45
-rw-r--r--lib/msun/src/w_log.c42
-rw-r--r--lib/msun/src/w_log10.c45
-rw-r--r--lib/msun/src/w_pow.c62
-rw-r--r--lib/msun/src/w_remainder.c41
-rw-r--r--lib/msun/src/w_scalb.c59
-rw-r--r--lib/msun/src/w_sinh.c41
-rw-r--r--lib/msun/src/w_sqrt.c41
-rw-r--r--libexec/Makefile4
-rw-r--r--libexec/bootpd/bootpd.82
-rw-r--r--libexec/bootpd/bootptab.52
-rw-r--r--libexec/ftpd/Makefile9
-rw-r--r--libexec/ftpd/ftpd.c20
-rw-r--r--libexec/ftpd/skey-stuff.c23
-rw-r--r--libexec/getty/gettytab.h4
-rw-r--r--libexec/getty/main.c12
-rw-r--r--libexec/pppd/Makefile26
-rw-r--r--libexec/pppd/README284
-rw-r--r--libexec/pppd/args.h1
-rw-r--r--libexec/pppd/auth.c828
-rw-r--r--libexec/pppd/callout.h2
-rw-r--r--libexec/pppd/chap.c986
-rw-r--r--libexec/pppd/chap.h93
-rw-r--r--libexec/pppd/fsm.c1006
-rw-r--r--libexec/pppd/fsm.h76
-rw-r--r--libexec/pppd/ipcp.c1057
-rw-r--r--libexec/pppd/ipcp.h32
-rw-r--r--libexec/pppd/lcp.c1191
-rw-r--r--libexec/pppd/lcp.h37
-rw-r--r--libexec/pppd/magic.c4
-rw-r--r--libexec/pppd/magic.h2
-rw-r--r--libexec/pppd/main.c2701
-rw-r--r--libexec/pppd/md5.c134
-rw-r--r--libexec/pppd/options.c1195
-rw-r--r--libexec/pppd/patchlevel.h7
-rw-r--r--libexec/pppd/pathnames.h16
-rw-r--r--libexec/pppd/ppp.h41
-rw-r--r--libexec/pppd/pppd.82
-rw-r--r--libexec/pppd/pppd.h345
-rw-r--r--libexec/pppd/sys-bsd.c503
-rw-r--r--libexec/pppd/sys-str.c643
-rw-r--r--libexec/pppd/upap.c340
-rw-r--r--libexec/pppd/upap.h41
-rw-r--r--libexec/rexecd/Makefile6
-rw-r--r--libexec/rexecd/rexecd.c11
-rw-r--r--libexec/rlogind/Makefile15
-rw-r--r--libexec/rlogind/rlogind.c7
-rw-r--r--libexec/rpc.rusersd/rusers_proc.c2
-rw-r--r--libexec/rshd/Makefile16
-rw-r--r--libexec/telnetd/sys_term.c9
-rw-r--r--libexec/uucpd/Makefile1
-rw-r--r--libexec/uucpd/pathnames.h2
-rw-r--r--libexec/uucpd/uucpd.c214
-rw-r--r--libexec/xtend/Makefile11
-rw-r--r--libexec/xtend/packet.c317
-rw-r--r--libexec/xtend/paths.h11
-rw-r--r--libexec/xtend/status.c109
-rw-r--r--libexec/xtend/user.c162
-rw-r--r--libexec/xtend/xten.h58
-rw-r--r--libexec/xtend/xtend.8174
-rw-r--r--libexec/xtend/xtend.c319
-rw-r--r--libexec/xtend/xtend.h77
-rw-r--r--sbin/Makefile10
-rw-r--r--sbin/chkconfig/chkconfig.c30
-rw-r--r--sbin/comcontrol/comcontrol.879
-rw-r--r--sbin/comcontrol/comcontrol.c24
-rw-r--r--sbin/disklabel/disklabel.c113
-rw-r--r--sbin/dump/dump.82
-rw-r--r--sbin/dump/dumpoptr.c3
-rw-r--r--sbin/dump/dumptape.c17
-rw-r--r--sbin/dump/rdump.82
-rw-r--r--sbin/fsck/fsck.82
-rw-r--r--sbin/fsck/pass5.c15
-rw-r--r--sbin/fsck/setup.c4
-rw-r--r--sbin/fsck/utilities.c6
-rw-r--r--sbin/ft/Makefile3
-rw-r--r--sbin/ft/ft.86
-rw-r--r--sbin/ft/ft.c219
-rw-r--r--sbin/ft/ftecc.c448
-rw-r--r--sbin/ifconfig/ifconfig.c6
-rw-r--r--sbin/init.chmr/configure.c26
-rw-r--r--sbin/init/init.obin0 -> 5660 bytes
-rw-r--r--sbin/md5/Makefile34
-rw-r--r--sbin/md5/README34
-rw-r--r--sbin/md5/global.h30
-rw-r--r--sbin/md5/md5-announcement.txt37
-rw-r--r--sbin/md5/md5.143
-rw-r--r--sbin/md5/md5.h36
-rw-r--r--sbin/md5/md5c.c333
-rw-r--r--sbin/md5/mddriver.c231
-rw-r--r--sbin/mount/mount.84
-rw-r--r--sbin/mount/mount.c18
-rw-r--r--sbin/mountd/mountd.c2
-rw-r--r--sbin/ping/ping.c66
-rw-r--r--sbin/restore/Makefile2
-rw-r--r--sbin/restore/dirs.c2
-rw-r--r--sbin/restore/pathnames.h2
-rw-r--r--sbin/restore/restore.h2
-rw-r--r--sbin/restore/rrestore.82
-rw-r--r--sbin/restore/tape.c2
-rw-r--r--sbin/route/route.c4
-rw-r--r--sbin/routed/interface.h90
-rw-r--r--sbin/routed/startup.c486
-rw-r--r--sbin/slattach/slattach.c11
-rw-r--r--share/Makefile4
-rw-r--r--share/doc/ps1/06.sysman/a.t4
-rw-r--r--share/doc/smm/05.fsck/3.t2
-rw-r--r--share/doc/smm/05.fsck/Makefile2
-rw-r--r--share/doc/usd/04.csh/Makefile1
-rw-r--r--share/doc/usd/04.csh/csh.a2
-rw-r--r--share/doc/usd/34.trek/trek.me17
-rw-r--r--share/locale/Ja_JP.EUC158
-rw-r--r--share/locale/Makefile23
-rw-r--r--share/locale/POSIX33
-rw-r--r--share/locale/Russian.koi8-r39
-rw-r--r--share/locale/ldef.h53
-rw-r--r--share/locale/lex.l152
-rw-r--r--share/locale/mklocale.1257
-rw-r--r--share/locale/yacc.y821
-rw-r--r--share/man/man4/ddb.43
-rw-r--r--share/man/man4/man4.i386/Makefile4
-rw-r--r--share/man/man4/man4.i386/lpa.462
-rw-r--r--share/man/man4/man4.i386/lpt.46
-rw-r--r--share/man/man4/man4.i386/sio.4291
-rw-r--r--share/man/man4/man4.i386/tw.4111
-rw-r--r--share/man/man5/Makefile6
-rw-r--r--share/man/man5/pcfs.5294
-rw-r--r--share/man/man5/skey.access.534
-rw-r--r--share/man/man7/mdoc.7409
-rw-r--r--share/man/man8/adduser.816
-rw-r--r--share/me/footnote.me2
-rw-r--r--share/me/me.790
-rw-r--r--share/me/tmac.e4
-rw-r--r--share/mk/bsd.dep.mk2
-rw-r--r--share/mk/bsd.doc.mk5
-rw-r--r--share/mk/bsd.lib.mk26
-rw-r--r--share/mk/bsd.man.mk53
-rw-r--r--share/mk/bsd.own.mk2
-rw-r--r--share/mk/bsd.prog.mk52
-rw-r--r--share/mk/sys.mk8
-rwxr-xr-xshare/syscons/examples/setrus18
-rw-r--r--share/syscons/fonts/Makefile15
-rw-r--r--share/syscons/fonts/alt-8x14.fnt83
-rw-r--r--share/syscons/fonts/alt-8x16.fnt95
-rw-r--r--share/syscons/fonts/alt-8x8.fnt49
-rw-r--r--share/syscons/fonts/altb-8x16 (renamed from share/syscons/fonts/alt8x16.fnt)bin4096 -> 4096 bytes
-rw-r--r--share/syscons/fonts/altb-8x16.fnt95
-rw-r--r--share/syscons/fonts/altc-8x16.fnt95
-rw-r--r--share/syscons/fonts/cp850-8x14.fnt83
-rw-r--r--share/syscons/fonts/cp850-8x16.fnt95
-rw-r--r--share/syscons/fonts/cp850-8x8.fnt49
-rw-r--r--share/syscons/fonts/cp865-8x14.fnt83
-rw-r--r--share/syscons/fonts/cp865-8x16.fnt95
-rw-r--r--share/syscons/fonts/cp865-8x8.fnt49
-rw-r--r--share/syscons/fonts/iso-8x14.fnt83
-rw-r--r--share/syscons/fonts/iso-8x16.fnt95
-rw-r--r--share/syscons/fonts/iso-8x8.fnt49
-rw-r--r--share/syscons/fonts/koi8-8x14.fnt83
-rw-r--r--share/syscons/fonts/koi8-8x16.fnt95
-rw-r--r--share/syscons/fonts/koi8-8x8.fnt49
-rw-r--r--share/syscons/fonts/koi8b-8x16bin0 -> 4096 bytes
-rw-r--r--share/syscons/fonts/koi8b-8x16.fnt95
-rw-r--r--share/syscons/fonts/koi8c-8x16.fnt95
-rw-r--r--share/syscons/keymaps/Makefile24
-rw-r--r--share/syscons/keymaps/danish.cp865.kbd109
-rw-r--r--share/syscons/keymaps/danish.iso.kbd109
-rw-r--r--share/syscons/keymaps/german.cp850.kbd109
-rw-r--r--share/syscons/keymaps/german.iso.kbd109
-rw-r--r--share/syscons/keymaps/ru.koi8-r4
-rw-r--r--share/syscons/keymaps/ru.koi8-r.kbd237
-rw-r--r--share/syscons/keymaps/swedish.cp850.kbd109
-rw-r--r--share/syscons/keymaps/swedish.iso64
-rw-r--r--share/syscons/keymaps/swedish.iso.kbd109
-rw-r--r--share/syscons/keymaps/uk.cp850.kbd109
-rw-r--r--share/syscons/keymaps/uk.iso.kbd109
-rw-r--r--share/syscons/keymaps/us.iso.kbd109
-rw-r--r--share/syscons/scrnmaps/Makefile16
-rw-r--r--share/syscons/scrnmaps/koi8-r2alt.scm9
-rw-r--r--share/tmac/Makefile7
-rw-r--r--share/tmac/doc-syms14
-rw-r--r--share/zoneinfo/Makefile2
-rw-r--r--sys/conf/files5
-rw-r--r--sys/conf/newvers.sh12
-rw-r--r--sys/conf/param.c2
-rw-r--r--sys/doc/Changes277
-rw-r--r--sys/doc/Makefile19
-rw-r--r--sys/doc/ata/ata-1 (renamed from sys/i386/doc/ata/ata-1)0
-rw-r--r--sys/doc/ata/ata-10 (renamed from sys/i386/doc/ata/ata-10)0
-rw-r--r--sys/doc/ata/ata-11 (renamed from sys/i386/doc/ata/ata-11)0
-rw-r--r--sys/doc/ata/ata-2 (renamed from sys/i386/doc/ata/ata-2)0
-rw-r--r--sys/doc/ata/ata-3 (renamed from sys/i386/doc/ata/ata-3)0
-rw-r--r--sys/doc/ata/ata-4 (renamed from sys/i386/doc/ata/ata-4)0
-rw-r--r--sys/doc/ata/ata-5 (renamed from sys/i386/doc/ata/ata-5)0
-rw-r--r--sys/doc/ata/ata-6 (renamed from sys/i386/doc/ata/ata-6)0
-rw-r--r--sys/doc/ata/ata-7 (renamed from sys/i386/doc/ata/ata-7)0
-rw-r--r--sys/doc/ata/ata-8 (renamed from sys/i386/doc/ata/ata-8)0
-rw-r--r--sys/doc/ata/ata-9 (renamed from sys/i386/doc/ata/ata-9)0
-rw-r--r--sys/doc/ata/ata-apx (renamed from sys/i386/doc/ata/ata-apx)0
-rw-r--r--sys/doc/ata/ata-prt (renamed from sys/i386/doc/ata/ata-prt)0
-rw-r--r--sys/doc/ata/ata-toc (renamed from sys/i386/doc/ata/ata-toc)0
-rw-r--r--sys/doc/ed.relnotes174
-rw-r--r--sys/doc/memory-test.doc40
-rw-r--r--sys/doc/options.doc682
-rw-r--r--sys/doc/options.texi1074
-rw-r--r--sys/doc/seagate.doc125
-rw-r--r--sys/doc/sound.doc80
-rw-r--r--sys/doc/vm_layout.doc32
-rw-r--r--sys/doc/wt.doc (renamed from sys/i386/doc/wt.doc)0
-rw-r--r--sys/gnu/fpemul/Changelog36
-rw-r--r--sys/gnu/fpemul/README277
-rw-r--r--sys/gnu/fpemul/control_w.h95
-rw-r--r--sys/gnu/fpemul/div_small.s101
-rw-r--r--sys/gnu/fpemul/errors.c612
-rw-r--r--sys/gnu/fpemul/exception.h102
-rw-r--r--sys/gnu/fpemul/fpu_arith.c235
-rw-r--r--sys/gnu/fpemul/fpu_asm.h82
-rw-r--r--sys/gnu/fpemul/fpu_aux.c233
-rw-r--r--sys/gnu/fpemul/fpu_emu.h188
-rw-r--r--sys/gnu/fpemul/fpu_entry.c483
-rw-r--r--sys/gnu/fpemul/fpu_etc.c175
-rw-r--r--sys/gnu/fpemul/fpu_proto.h115
-rw-r--r--sys/gnu/fpemul/fpu_system.h97
-rw-r--r--sys/gnu/fpemul/fpu_trig.c1367
-rw-r--r--sys/gnu/fpemul/get_address.c203
-rw-r--r--sys/gnu/fpemul/load_store.c269
-rw-r--r--sys/gnu/fpemul/math_emu.h47
-rw-r--r--sys/gnu/fpemul/poly_2xm1.c141
-rw-r--r--sys/gnu/fpemul/poly_atan.c252
-rw-r--r--sys/gnu/fpemul/poly_div.s144
-rw-r--r--sys/gnu/fpemul/poly_l2.c318
-rw-r--r--sys/gnu/fpemul/poly_mul64.s124
-rw-r--r--sys/gnu/fpemul/poly_sin.c192
-rw-r--r--sys/gnu/fpemul/poly_tan.c229
-rw-r--r--sys/gnu/fpemul/polynomial.s192
-rw-r--r--sys/gnu/fpemul/reg_add_sub.c303
-rw-r--r--sys/gnu/fpemul/reg_compare.c384
-rw-r--r--sys/gnu/fpemul/reg_constant.c175
-rw-r--r--sys/gnu/fpemul/reg_constant.h82
-rw-r--r--sys/gnu/fpemul/reg_div.s295
-rw-r--r--sys/gnu/fpemul/reg_ld_str.c1387
-rw-r--r--sys/gnu/fpemul/reg_mul.c162
-rw-r--r--sys/gnu/fpemul/reg_norm.s182
-rw-r--r--sys/gnu/fpemul/reg_round.s653
-rw-r--r--sys/gnu/fpemul/reg_u_add.s244
-rw-r--r--sys/gnu/fpemul/reg_u_div.s506
-rw-r--r--sys/gnu/fpemul/reg_u_mul.s199
-rw-r--r--sys/gnu/fpemul/reg_u_sub.s361
-rw-r--r--sys/gnu/fpemul/status_w.h106
-rw-r--r--sys/gnu/fpemul/version.h61
-rw-r--r--sys/gnu/fpemul/wm_shrx.s261
-rw-r--r--sys/gnu/fpemul/wm_sqrt.s496
-rw-r--r--sys/i386/boot/Makefile45
-rw-r--r--sys/i386/boot/biosbootbin0 -> 512 bytes
-rw-r--r--sys/i386/boot/bootbin0 -> 7632 bytes
-rw-r--r--sys/i386/boot/boot.c12
-rwxr-xr-xsys/i386/boot/boot.symbin0 -> 10379 bytes
-rw-r--r--sys/i386/boot/boot2.S12
-rw-r--r--sys/i386/boot/bootbiosbin0 -> 7120 bytes
-rw-r--r--sys/i386/boot/disk.c45
-rw-r--r--sys/i386/boot/io.c20
-rw-r--r--sys/i386/boot/start.S3
-rw-r--r--sys/i386/conf/ECLIPSE66
-rw-r--r--sys/i386/conf/GENERICAH13
-rw-r--r--sys/i386/conf/GENERICBT12
-rw-r--r--sys/i386/conf/HAMSTER67
-rw-r--r--sys/i386/conf/LAPTOP68
-rw-r--r--sys/i386/conf/LINT79
-rw-r--r--sys/i386/conf/Makefile.i38618
-rw-r--r--sys/i386/conf/SYSCONS86
-rw-r--r--sys/i386/conf/TIME64
-rw-r--r--sys/i386/conf/WCARCH67
-rw-r--r--sys/i386/conf/WCARCHIVE73
-rw-r--r--sys/i386/conf/devices.i3863
-rw-r--r--sys/i386/conf/files.i38694
-rw-r--r--sys/i386/doc/Changes209
-rw-r--r--sys/i386/doc/Makefile19
-rw-r--r--sys/i386/doc/ed.relnotes174
-rw-r--r--sys/i386/doc/options.texi974
-rw-r--r--sys/i386/doc/sound.doc38
-rw-r--r--sys/i386/doc/vm_layout.doc32
-rw-r--r--sys/i386/i386/autoconf.c7
-rw-r--r--sys/i386/i386/conf.c65
-rw-r--r--sys/i386/i386/db_interface.c21
-rw-r--r--sys/i386/i386/exception.s138
-rw-r--r--sys/i386/i386/in_cksum.c94
-rw-r--r--sys/i386/i386/locore.s117
-rw-r--r--sys/i386/i386/machdep.c133
-rw-r--r--sys/i386/i386/math_emulate.c144
-rw-r--r--sys/i386/i386/microtime.s87
-rw-r--r--sys/i386/i386/pmap.c879
-rw-r--r--sys/i386/i386/random.s60
-rw-r--r--sys/i386/i386/support.s323
-rw-r--r--sys/i386/i386/swtch.s43
-rw-r--r--sys/i386/i386/trap.c814
-rw-r--r--sys/i386/i386/vm_machdep.c889
-rw-r--r--sys/i386/include/ansi.h21
-rw-r--r--sys/i386/include/asmacros.h6
-rw-r--r--sys/i386/include/console.h31
-rw-r--r--sys/i386/include/cpu.h13
-rw-r--r--sys/i386/include/cpufunc.h13
-rw-r--r--sys/i386/include/ioctl_fd.h31
-rw-r--r--sys/i386/include/limits.h6
-rw-r--r--sys/i386/include/lpt.h24
-rw-r--r--sys/i386/include/mouse.h44
-rw-r--r--sys/i386/include/npx.h10
-rw-r--r--sys/i386/include/param.h6
-rw-r--r--sys/i386/include/pcaudioio.h75
-rw-r--r--sys/i386/include/pmap.h55
-rw-r--r--sys/i386/include/psl.h6
-rw-r--r--sys/i386/include/pte.h4
-rw-r--r--sys/i386/include/soundcard.h50
-rw-r--r--sys/i386/include/spl.h104
-rw-r--r--sys/i386/include/ultrasound.h9
-rw-r--r--sys/i386/include/vmparam.h2
-rw-r--r--sys/i386/isa/aha1542.c13
-rw-r--r--sys/i386/isa/bt742a.c111
-rw-r--r--sys/i386/isa/bt742a_32.c1694
-rw-r--r--sys/i386/isa/clock.c279
-rw-r--r--sys/i386/isa/com.c101
-rw-r--r--sys/i386/isa/debug.h85
-rw-r--r--sys/i386/isa/elink.c77
-rw-r--r--sys/i386/isa/elink.h39
-rw-r--r--sys/i386/isa/fd.c778
-rw-r--r--sys/i386/isa/fdc.h12
-rw-r--r--sys/i386/isa/fdreg.h20
-rw-r--r--sys/i386/isa/ft.c1188
-rw-r--r--sys/i386/isa/ftreg.h11
-rw-r--r--sys/i386/isa/ic/i82365.h190
-rw-r--r--sys/i386/isa/ic/nec765.h73
-rw-r--r--sys/i386/isa/icu.h12
-rw-r--r--sys/i386/isa/icu.s492
-rw-r--r--sys/i386/isa/if_ed.c1451
-rw-r--r--sys/i386/isa/if_edreg.h2
-rw-r--r--sys/i386/isa/if_el.c800
-rw-r--r--sys/i386/isa/if_elreg.h76
-rw-r--r--sys/i386/isa/if_ep.c164
-rw-r--r--sys/i386/isa/if_ie507.h19
-rw-r--r--sys/i386/isa/if_is.c10
-rw-r--r--sys/i386/isa/if_ze.c1951
-rw-r--r--sys/i386/isa/if_zereg.h859
-rw-r--r--sys/i386/isa/ipl.h7
-rw-r--r--sys/i386/isa/isa.c227
-rw-r--r--sys/i386/isa/isa.h9
-rw-r--r--sys/i386/isa/isa_device.h4
-rw-r--r--sys/i386/isa/kbdtables.h40
-rw-r--r--sys/i386/isa/lpa.c14
-rw-r--r--sys/i386/isa/lpt.c150
-rw-r--r--sys/i386/isa/mcd.c5
-rw-r--r--sys/i386/isa/npx.c22
-rw-r--r--sys/i386/isa/pcaudio.c430
-rw-r--r--sys/i386/isa/pccons.c101
-rw-r--r--sys/i386/isa/psm.c464
-rw-r--r--sys/i386/isa/seagate.c2036
-rw-r--r--sys/i386/isa/sio.c1242
-rw-r--r--sys/i386/isa/sound/CHANGELOG75
-rw-r--r--sys/i386/isa/sound/RELNOTES.Linux256
-rw-r--r--sys/i386/isa/sound/adlib_card.c13
-rw-r--r--sys/i386/isa/sound/audio.c106
-rw-r--r--sys/i386/isa/sound/debug.h29
-rw-r--r--sys/i386/isa/sound/dev_table.c148
-rw-r--r--sys/i386/isa/sound/dev_table.h46
-rw-r--r--sys/i386/isa/sound/dmabuf.c360
-rw-r--r--sys/i386/isa/sound/dsp.c270
-rw-r--r--sys/i386/isa/sound/gus_card.c87
-rw-r--r--sys/i386/isa/sound/gus_hw.h15
-rw-r--r--sys/i386/isa/sound/gus_linearvol.h18
-rw-r--r--sys/i386/isa/sound/gus_midi.c14
-rw-r--r--sys/i386/isa/sound/gus_vol.c70
-rw-r--r--sys/i386/isa/sound/gus_wave.c1834
-rw-r--r--sys/i386/isa/sound/ics2101.c265
-rw-r--r--sys/i386/isa/sound/local.h13
-rw-r--r--sys/i386/isa/sound/midi.c220
-rw-r--r--sys/i386/isa/sound/midibuf.c14
-rw-r--r--sys/i386/isa/sound/mpu401.c129
-rw-r--r--sys/i386/isa/sound/opl3.c68
-rw-r--r--sys/i386/isa/sound/os.h94
-rw-r--r--sys/i386/isa/sound/pas.h12
-rw-r--r--sys/i386/isa/sound/pas2_card.c135
-rw-r--r--sys/i386/isa/sound/pas2_midi.c16
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c40
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c91
-rw-r--r--sys/i386/isa/sound/patmgr.c41
-rw-r--r--sys/i386/isa/sound/pro_midi.c140
-rw-r--r--sys/i386/isa/sound/sb.h28
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c627
-rw-r--r--sys/i386/isa/sound/sb16_midi.c287
-rw-r--r--sys/i386/isa/sound/sb_card.c13
-rw-r--r--sys/i386/isa/sound/sb_dsp.c1140
-rw-r--r--sys/i386/isa/sound/sb_midi.c224
-rw-r--r--sys/i386/isa/sound/sb_mixer.c422
-rw-r--r--sys/i386/isa/sound/sb_mixer.h212
-rw-r--r--sys/i386/isa/sound/sequencer.c311
-rw-r--r--sys/i386/isa/sound/sound_calls.h59
-rw-r--r--sys/i386/isa/sound/sound_config.h43
-rw-r--r--sys/i386/isa/sound/sound_switch.c445
-rw-r--r--sys/i386/isa/sound/soundcard.c307
-rw-r--r--sys/i386/isa/spkr.c23
-rw-r--r--sys/i386/isa/syscons.c623
-rw-r--r--sys/i386/isa/tw.c997
-rw-r--r--sys/i386/isa/ultra14f.c6
-rw-r--r--sys/i386/isa/vector.s196
-rw-r--r--sys/i386/isa/wd.c204
-rw-r--r--sys/i386/isa/wt.c3
-rw-r--r--sys/i386/isa/wt.c.orig902
-rw-r--r--sys/i386/netboot/Makefile9
-rw-r--r--sys/i386/netboot/bootmenu.c2
-rw-r--r--sys/i386/netboot/ether.c479
-rw-r--r--sys/i386/netboot/ether.h178
-rw-r--r--sys/i386/netboot/wd80x3.c240
-rw-r--r--sys/i386/pci/ncr.c5507
-rw-r--r--sys/i386/pci/ncr_reg.h489
-rw-r--r--sys/i386/pci/pci.c494
-rw-r--r--sys/i386/pci/pci.h58
-rw-r--r--sys/i386/pci/pci_config.c45
-rw-r--r--sys/i386/pci/pci_device.h88
-rw-r--r--sys/i386/pci/pcibios.c261
-rw-r--r--sys/i386/pci/pcibios.h53
-rw-r--r--sys/isofs/isofs_rrip.c7
-rw-r--r--sys/isofs/isofs_vfsops.c6
-rw-r--r--sys/isofs/isofs_vnops.c15
-rw-r--r--sys/kern/imgact_aout.c6
-rw-r--r--sys/kern/init_main.c34
-rw-r--r--sys/kern/init_sysent.c8
-rw-r--r--sys/kern/kern_acct.c2
-rw-r--r--sys/kern/kern_clock.c608
-rw-r--r--sys/kern/kern_descrip.c4
-rw-r--r--sys/kern/kern_execve.c45
-rw-r--r--sys/kern/kern_exit.c5
-rw-r--r--sys/kern/kern_fork.c10
-rw-r--r--sys/kern/kern_malloc.c74
-rw-r--r--sys/kern/kern_ntptime.c267
-rw-r--r--sys/kern/kern_physio.c105
-rw-r--r--sys/kern/kern_prot.c2
-rw-r--r--sys/kern/kern_resource.c2
-rw-r--r--sys/kern/kern_sig.c12
-rw-r--r--sys/kern/kern_subr.c2
-rw-r--r--sys/kern/kern_synch.c4
-rw-r--r--sys/kern/kern_time.c6
-rw-r--r--sys/kern/makesyscalls.sh4
-rw-r--r--sys/kern/spec_vnops.c4
-rw-r--r--sys/kern/subr_prf.c11
-rw-r--r--sys/kern/subr_rand.c100
-rw-r--r--sys/kern/sys_process.c2
-rw-r--r--sys/kern/syscalls.c6
-rw-r--r--sys/kern/syscalls.master6
-rw-r--r--sys/kern/sysv_msg.c6
-rw-r--r--sys/kern/sysv_sem.c12
-rw-r--r--sys/kern/sysv_shm.c14
-rw-r--r--sys/kern/tty.c545
-rw-r--r--sys/kern/tty_conf.c6
-rw-r--r--sys/kern/tty_pty.c155
-rw-r--r--sys/kern/uipc_mbuf.c17
-rw-r--r--sys/kern/vfs__bio.c95
-rw-r--r--sys/kern/vfs_lookup.c15
-rw-r--r--sys/kern/vfs_subr.c25
-rw-r--r--sys/kern/vfs_syscalls.c7
-rw-r--r--sys/kern/vfs_vnops.c3
-rw-r--r--sys/net/if.c7
-rw-r--r--sys/net/if.h12
-rw-r--r--sys/net/if_ethersubr.c226
-rw-r--r--sys/net/if_loop.c30
-rw-r--r--sys/net/if_ppp.c108
-rw-r--r--sys/net/if_sl.c54
-rw-r--r--sys/net/netisr.h15
-rw-r--r--sys/net/ppp.h41
-rw-r--r--sys/net/pppdefs.h41
-rw-r--r--sys/net/raw_cb.h3
-rw-r--r--sys/net/route.c2
-rw-r--r--sys/netinet/if_ether.c8
-rw-r--r--sys/netinet/if_ether.h100
-rw-r--r--sys/netinet/igmp.c321
-rw-r--r--sys/netinet/igmp.h60
-rw-r--r--sys/netinet/igmp_var.h80
-rw-r--r--sys/netinet/in.c132
-rw-r--r--sys/netinet/in.h37
-rw-r--r--sys/netinet/in_pcb.c93
-rw-r--r--sys/netinet/in_pcb.h7
-rw-r--r--sys/netinet/in_pcb.old.c503
-rw-r--r--sys/netinet/in_pcb.orig.c498
-rw-r--r--sys/netinet/in_proto.c12
-rw-r--r--sys/netinet/in_var.h117
-rw-r--r--sys/netinet/ip_icmp.c7
-rw-r--r--sys/netinet/ip_input.c53
-rw-r--r--sys/netinet/ip_mroute.c1056
-rw-r--r--sys/netinet/ip_mroute.h174
-rw-r--r--sys/netinet/ip_output.c494
-rw-r--r--sys/netinet/ip_var.h17
-rw-r--r--sys/netinet/raw_ip.c54
-rw-r--r--sys/netinet/tcp_usrreq.c7
-rw-r--r--sys/netinet/udp_usrreq.c104
-rw-r--r--sys/nfs/nfs_bio.c8
-rw-r--r--sys/nfs/nfs_serv.c16
-rw-r--r--sys/nfs/nfs_socket.c2
-rw-r--r--sys/nfs/nfs_subs.c60
-rw-r--r--sys/nfs/nfs_vnops.c16
-rw-r--r--sys/pcfs/pcfs_conv.c6
-rw-r--r--sys/pcfs/pcfs_fat.c18
-rw-r--r--sys/pcfs/pcfs_vfsops.c5
-rw-r--r--sys/pcfs/pcfs_vnops.c41
-rw-r--r--sys/procfs/procfs_subr.c174
-rw-r--r--sys/procfs/procfs_vnops.c10
-rw-r--r--sys/scsi/cd.c13
-rw-r--r--sys/scsi/scsi_base.c16
-rw-r--r--sys/scsi/scsi_ioctl.c2
-rw-r--r--sys/scsi/scsiconf.h3
-rw-r--r--sys/scsi/sd.c20
-rw-r--r--sys/scsi/st.c22
-rw-r--r--sys/sys/acct.h2
-rw-r--r--sys/sys/buf.h8
-rw-r--r--sys/sys/callout.h2
-rw-r--r--sys/sys/conf.h4
-rw-r--r--sys/sys/disklabel.h3
-rw-r--r--sys/sys/dkstat.h2
-rw-r--r--sys/sys/errno.h2
-rw-r--r--sys/sys/exec.h4
-rw-r--r--sys/sys/fcntl.h2
-rw-r--r--sys/sys/ftape.h5
-rw-r--r--sys/sys/ioctl.h9
-rw-r--r--sys/sys/ioctl_compat.h2
-rw-r--r--sys/sys/ipc.h2
-rw-r--r--sys/sys/kernel.h11
-rw-r--r--sys/sys/malloc.h17
-rw-r--r--sys/sys/map.h2
-rw-r--r--sys/sys/mbuf.h54
-rw-r--r--sys/sys/mount.h5
-rw-r--r--sys/sys/namei.h2
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/proc.h2
-rw-r--r--sys/sys/procfs.h24
-rw-r--r--sys/sys/signal.h2
-rw-r--r--sys/sys/specdev.h4
-rw-r--r--sys/sys/stat.h2
-rw-r--r--sys/sys/syscall.h6
-rw-r--r--sys/sys/systm.h42
-rw-r--r--sys/sys/termios.h8
-rw-r--r--sys/sys/timeb.h2
-rw-r--r--sys/sys/times.h2
-rw-r--r--sys/sys/timex.h290
-rw-r--r--sys/sys/tty.h55
-rw-r--r--sys/sys/ttydefaults.h8
-rw-r--r--sys/sys/types.h2
-rw-r--r--sys/sys/unistd.h12
-rw-r--r--sys/ufs/dir.h2
-rw-r--r--sys/ufs/ufs_disksubr.c7
-rw-r--r--sys/ufs/ufs_lookup.c2
-rw-r--r--sys/ufs/ufs_vfsops.c2
-rw-r--r--sys/ufs/ufs_vnops.c7
-rw-r--r--sys/vm/device_pager.c1
-rw-r--r--sys/vm/queue.h26
-rw-r--r--sys/vm/swap_pager.c1012
-rw-r--r--sys/vm/swap_pager.h9
-rw-r--r--sys/vm/vm_fault.c28
-rw-r--r--sys/vm/vm_glue.c52
-rw-r--r--sys/vm/vm_mmap.c101
-rw-r--r--sys/vm/vm_object.c24
-rw-r--r--sys/vm/vm_object.h5
-rw-r--r--sys/vm/vm_page.c93
-rw-r--r--sys/vm/vm_page.h40
-rw-r--r--sys/vm/vm_pageout.c763
-rw-r--r--sys/vm/vm_pageout.h3
-rw-r--r--sys/vm/vm_pager.c22
-rw-r--r--sys/vm/vm_pager.h4
-rw-r--r--sys/vm/vm_swap.c4
-rw-r--r--sys/vm/vm_unix.c9
-rw-r--r--sys/vm/vnode_pager.c1408
-rw-r--r--usr.bin/Makefile29
-rw-r--r--usr.bin/ar/replace.c4
-rw-r--r--usr.bin/basename/basename.12
-rw-r--r--usr.bin/cap_mkdb/Makefile5
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.1101
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.c250
-rw-r--r--usr.bin/chat/chat.c4
-rw-r--r--usr.bin/chpass/Makefile10
-rw-r--r--usr.bin/chpass/chpass.c37
-rw-r--r--usr.bin/chpass/pw_copy.c81
-rw-r--r--usr.bin/crontab/crontab.12
-rw-r--r--usr.bin/crontab/crontab.52
-rw-r--r--usr.bin/crontab/crontab.c2
-rw-r--r--usr.bin/elvis/input.c2
-rw-r--r--usr.bin/elvis/tmp.c1
-rw-r--r--usr.bin/env/env.12
-rw-r--r--usr.bin/finger/sprint.c5
-rw-r--r--usr.bin/finger/util.c4
-rw-r--r--usr.bin/ftp/glob.c7
-rw-r--r--usr.bin/groups/groups.c25
-rw-r--r--usr.bin/ipcs/Makefile2
-rw-r--r--usr.bin/join/join.c29
-rw-r--r--usr.bin/key/Makefile21
-rw-r--r--usr.bin/key/README.WZV100
-rw-r--r--usr.bin/key/key.149
-rw-r--r--usr.bin/key/skey.159
-rw-r--r--usr.bin/key/skey.c128
-rw-r--r--usr.bin/keyinfo/Makefile9
-rw-r--r--usr.bin/keyinfo/keyinfo.140
-rw-r--r--usr.bin/keyinfo/keyinfo.sh10
-rw-r--r--usr.bin/keyinit/Makefile20
-rw-r--r--usr.bin/keyinit/keyinit.164
-rw-r--r--usr.bin/keyinit/skeyinit.c194
-rw-r--r--usr.bin/last/last.c4
-rw-r--r--usr.bin/lex/lib/Makefile2
-rw-r--r--usr.bin/login/Makefile22
-rw-r--r--usr.bin/login/README10
-rw-r--r--usr.bin/login/klogin.c2
-rw-r--r--usr.bin/login/login.access.550
-rw-r--r--usr.bin/login/login.c49
-rw-r--r--usr.bin/login/login_access.c236
-rw-r--r--usr.bin/login/login_skey.c105
-rw-r--r--usr.bin/login/pathnames.h1
-rw-r--r--usr.bin/mail/Makefile3
-rw-r--r--usr.bin/mail/mail.13
-rw-r--r--usr.bin/make/str.c8
-rw-r--r--usr.bin/mesg/mesg.c2
-rw-r--r--usr.bin/more/output.c2
-rw-r--r--usr.bin/netstat/Makefile2
-rw-r--r--usr.bin/netstat/if.c92
-rw-r--r--usr.bin/netstat/inet.c44
-rw-r--r--usr.bin/netstat/main.c33
-rw-r--r--usr.bin/netstat/mroute.c211
-rw-r--r--usr.bin/netstat/netstat.16
-rw-r--r--usr.bin/nice/nice.12
-rw-r--r--usr.bin/passwd/Makefile18
-rw-r--r--usr.bin/passwd/kpasswd_proto.h54
-rw-r--r--usr.bin/passwd/krb_passwd.c316
-rw-r--r--usr.bin/passwd/local_passwd.c15
-rw-r--r--usr.bin/passwd/passwd.c4
-rw-r--r--usr.bin/passwd/pw_fastmkdb.c268
-rw-r--r--usr.bin/passwd/yp_passwd.c7
-rw-r--r--usr.bin/ranlib/build.c8
-rw-r--r--usr.bin/rdist/defs.h2
-rw-r--r--usr.bin/rev/rev.c7
-rw-r--r--usr.bin/rlogin/Makefile17
-rw-r--r--usr.bin/rlogin/kcmd.c309
-rw-r--r--usr.bin/rlogin/krcmd.c150
-rw-r--r--usr.bin/rsh/Makefile18
-rw-r--r--usr.bin/rup/rup.c6
-rw-r--r--usr.bin/sed/Makefile6
-rw-r--r--usr.bin/sed/POSIX11
-rw-r--r--usr.bin/sed/compile.c167
-rw-r--r--usr.bin/sed/defs.h11
-rw-r--r--usr.bin/sed/extern.h11
-rw-r--r--usr.bin/sed/main.c21
-rw-r--r--usr.bin/sed/misc.c7
-rw-r--r--usr.bin/sed/process.c154
-rw-r--r--usr.bin/split/split.c2
-rw-r--r--usr.bin/strings/strings.c2
-rw-r--r--usr.bin/su/Makefile21
-rw-r--r--usr.bin/su/su.14
-rw-r--r--usr.bin/su/su.c75
-rw-r--r--usr.bin/syscons/Makefile4
-rw-r--r--usr.bin/syscons/syscons.1103
-rw-r--r--usr.bin/syscons/syscons.c545
-rw-r--r--usr.bin/syscons/syscons.h6
-rw-r--r--usr.bin/telnet/Makefile6
-rw-r--r--usr.bin/telnet/commands.c2
-rw-r--r--usr.bin/telnet/telnet.137
-rw-r--r--usr.bin/telnet/telnet.c7
-rw-r--r--usr.bin/tn3270/tools/mkhits/dohits.c2
-rw-r--r--usr.bin/tput/tput.c6
-rw-r--r--usr.bin/tset/tset.c13
-rw-r--r--usr.bin/vi/Makefile80
-rw-r--r--usr.bin/vi/README152
-rw-r--r--usr.bin/vi/args.h4
-rw-r--r--usr.bin/vi/ascii.c93
-rw-r--r--usr.bin/vi/compat.h56
-rw-r--r--usr.bin/vi/cut.c323
-rw-r--r--usr.bin/vi/cut.h6
-rw-r--r--usr.bin/vi/delete.c30
-rw-r--r--usr.bin/vi/docs/README177
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/Makefile18
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/edit.vindex115
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/edittut.ms2322
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/Makefile14
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/ex.rm2230
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/ex.summary734
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/Makefile17
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms1079
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.chars644
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.in2064
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.summary468
-rw-r--r--usr.bin/vi/docs/bugs.current48
-rw-r--r--usr.bin/vi/docs/changelog138
-rw-r--r--usr.bin/vi/docs/features47
-rw-r--r--usr.bin/vi/docs/internals/autowrite88
-rw-r--r--usr.bin/vi/docs/internals/gdb.script68
-rw-r--r--usr.bin/vi/docs/internals/input314
-rw-r--r--usr.bin/vi/docs/internals/quoting219
-rw-r--r--usr.bin/vi/docs/internals/structures61
-rw-r--r--usr.bin/vi/docs/set.opt.roff1065
-rw-r--r--usr.bin/vi/docs/spell.ok163
-rw-r--r--usr.bin/vi/docs/tutorial/vi.advanced1458
-rw-r--r--usr.bin/vi/docs/tutorial/vi.beginner741
-rw-r--r--usr.bin/vi/docs/tutorial/vi.tut.csh24
-rw-r--r--usr.bin/vi/docs/vi.1452
-rw-r--r--usr.bin/vi/docs/vi.ref523
-rw-r--r--usr.bin/vi/docs/vi.ref.txt634
-rw-r--r--usr.bin/vi/ex/ex.c1608
-rw-r--r--usr.bin/vi/ex/ex_abbrev.c115
-rw-r--r--usr.bin/vi/ex/ex_append.c195
-rw-r--r--usr.bin/vi/ex/ex_args.c284
-rw-r--r--usr.bin/vi/ex/ex_argv.c585
-rw-r--r--usr.bin/vi/ex/ex_at.c109
-rw-r--r--usr.bin/vi/ex/ex_bang.c201
-rw-r--r--usr.bin/vi/ex/ex_cd.c205
-rw-r--r--usr.bin/vi/ex/ex_delete.c85
-rw-r--r--usr.bin/vi/ex/ex_digraph.c323
-rw-r--r--usr.bin/vi/ex/ex_display.c155
-rw-r--r--usr.bin/vi/ex/ex_edit.c124
-rw-r--r--usr.bin/vi/ex/ex_equal.c74
-rw-r--r--usr.bin/vi/ex/ex_exit.c93
-rw-r--r--usr.bin/vi/ex/ex_file.c102
-rw-r--r--usr.bin/vi/ex/ex_global.c387
-rw-r--r--usr.bin/vi/ex/ex_init.c203
-rw-r--r--usr.bin/vi/ex/ex_join.c199
-rw-r--r--usr.bin/vi/ex/ex_map.c168
-rw-r--r--usr.bin/vi/ex/ex_mark.c65
-rw-r--r--usr.bin/vi/ex/ex_mkexrc.c130
-rw-r--r--usr.bin/vi/ex/ex_move.c208
-rw-r--r--usr.bin/vi/ex/ex_open.c74
-rw-r--r--usr.bin/vi/ex/ex_preserve.c90
-rw-r--r--usr.bin/vi/ex/ex_print.c206
-rw-r--r--usr.bin/vi/ex/ex_put.c75
-rw-r--r--usr.bin/vi/ex/ex_read.c249
-rw-r--r--usr.bin/vi/ex/ex_screen.c154
-rw-r--r--usr.bin/vi/ex/ex_script.c580
-rw-r--r--usr.bin/vi/ex/ex_set.c69
-rw-r--r--usr.bin/vi/ex/ex_shell.c142
-rw-r--r--usr.bin/vi/ex/ex_shift.c203
-rw-r--r--usr.bin/vi/ex/ex_source.c65
-rw-r--r--usr.bin/vi/ex/ex_stop.c78
-rw-r--r--usr.bin/vi/ex/ex_subst.c972
-rw-r--r--usr.bin/vi/ex/ex_tag.c898
-rw-r--r--usr.bin/vi/ex/ex_undo.c110
-rw-r--r--usr.bin/vi/ex/ex_usage.c183
-rw-r--r--usr.bin/vi/ex/ex_util.c180
-rw-r--r--usr.bin/vi/ex/ex_version.c70
-rw-r--r--usr.bin/vi/ex/ex_visual.c132
-rw-r--r--usr.bin/vi/ex/ex_write.c306
-rw-r--r--usr.bin/vi/ex/ex_yank.c68
-rw-r--r--usr.bin/vi/ex/ex_z.c170
-rw-r--r--usr.bin/vi/ex/excmd.c447
-rw-r--r--usr.bin/vi/ex/excmd.h.stub320
-rw-r--r--usr.bin/vi/ex/filter.c400
-rw-r--r--usr.bin/vi/ex/script.h (renamed from usr.bin/vi/nex/script.h)0
-rw-r--r--usr.bin/vi/ex/tag.h (renamed from usr.bin/vi/nex/tag.h)0
-rw-r--r--usr.bin/vi/exf.c35
-rw-r--r--usr.bin/vi/exf.h7
-rw-r--r--usr.bin/vi/gs.h28
-rw-r--r--usr.bin/vi/include/bitstring.h143
-rw-r--r--usr.bin/vi/include/cdefs.h98
-rw-r--r--usr.bin/vi/include/compat.h241
-rw-r--r--usr.bin/vi/include/err.h16
-rw-r--r--usr.bin/vi/include/file.h15
-rw-r--r--usr.bin/vi/include/glob.h92
-rw-r--r--usr.bin/vi/include/mpool.h135
-rw-r--r--usr.bin/vi/include/ndbm.h77
-rw-r--r--usr.bin/vi/include/queue.h245
-rw-r--r--usr.bin/vi/interrupt.h96
-rw-r--r--usr.bin/vi/intr.c178
-rw-r--r--usr.bin/vi/line.c27
-rw-r--r--usr.bin/vi/log.c61
-rw-r--r--usr.bin/vi/log.h6
-rw-r--r--usr.bin/vi/main.c196
-rw-r--r--usr.bin/vi/mark.c130
-rw-r--r--usr.bin/vi/mark.h37
-rw-r--r--usr.bin/vi/mem.h11
-rw-r--r--usr.bin/vi/msg.h26
-rw-r--r--usr.bin/vi/nex/ex.c1523
-rw-r--r--usr.bin/vi/nex/ex_abbrev.c105
-rw-r--r--usr.bin/vi/nex/ex_append.c180
-rw-r--r--usr.bin/vi/nex/ex_args.c274
-rw-r--r--usr.bin/vi/nex/ex_argv.c575
-rw-r--r--usr.bin/vi/nex/ex_at.c99
-rw-r--r--usr.bin/vi/nex/ex_bang.c192
-rw-r--r--usr.bin/vi/nex/ex_cd.c82
-rw-r--r--usr.bin/vi/nex/ex_delete.c74
-rw-r--r--usr.bin/vi/nex/ex_digraph.c313
-rw-r--r--usr.bin/vi/nex/ex_display.c145
-rw-r--r--usr.bin/vi/nex/ex_edit.c114
-rw-r--r--usr.bin/vi/nex/ex_equal.c63
-rw-r--r--usr.bin/vi/nex/ex_exit.c82
-rw-r--r--usr.bin/vi/nex/ex_file.c92
-rw-r--r--usr.bin/vi/nex/ex_global.c403
-rw-r--r--usr.bin/vi/nex/ex_init.c189
-rw-r--r--usr.bin/vi/nex/ex_join.c189
-rw-r--r--usr.bin/vi/nex/ex_map.c158
-rw-r--r--usr.bin/vi/nex/ex_mark.c54
-rw-r--r--usr.bin/vi/nex/ex_mkexrc.c120
-rw-r--r--usr.bin/vi/nex/ex_move.c133
-rw-r--r--usr.bin/vi/nex/ex_open.c63
-rw-r--r--usr.bin/vi/nex/ex_preserve.c80
-rw-r--r--usr.bin/vi/nex/ex_print.c196
-rw-r--r--usr.bin/vi/nex/ex_put.c65
-rw-r--r--usr.bin/vi/nex/ex_read.c223
-rw-r--r--usr.bin/vi/nex/ex_screen.c134
-rw-r--r--usr.bin/vi/nex/ex_script.c570
-rw-r--r--usr.bin/vi/nex/ex_set.c58
-rw-r--r--usr.bin/vi/nex/ex_shell.c136
-rw-r--r--usr.bin/vi/nex/ex_shift.c193
-rw-r--r--usr.bin/vi/nex/ex_source.c54
-rw-r--r--usr.bin/vi/nex/ex_stop.c68
-rw-r--r--usr.bin/vi/nex/ex_subst.c984
-rw-r--r--usr.bin/vi/nex/ex_tag.c859
-rw-r--r--usr.bin/vi/nex/ex_undo.c99
-rw-r--r--usr.bin/vi/nex/ex_usage.c163
-rw-r--r--usr.bin/vi/nex/ex_util.c78
-rw-r--r--usr.bin/vi/nex/ex_version.c59
-rw-r--r--usr.bin/vi/nex/ex_visual.c122
-rw-r--r--usr.bin/vi/nex/ex_write.c277
-rw-r--r--usr.bin/vi/nex/ex_yank.c57
-rw-r--r--usr.bin/vi/nex/ex_z.c160
-rw-r--r--usr.bin/vi/nex/excmd.c431
-rw-r--r--usr.bin/vi/nex/excmd.h.stub340
-rw-r--r--usr.bin/vi/nex/filter.c393
-rw-r--r--usr.bin/vi/nvi/getc.c252
-rw-r--r--usr.bin/vi/nvi/v_again.c61
-rw-r--r--usr.bin/vi/nvi/v_at.c61
-rw-r--r--usr.bin/vi/nvi/v_ch.c273
-rw-r--r--usr.bin/vi/nvi/v_delete.c147
-rw-r--r--usr.bin/vi/nvi/v_ex.c55
-rw-r--r--usr.bin/vi/nvi/v_exit.c79
-rw-r--r--usr.bin/vi/nvi/v_exmode.c58
-rw-r--r--usr.bin/vi/nvi/v_filter.c92
-rw-r--r--usr.bin/vi/nvi/v_increment.c153
-rw-r--r--usr.bin/vi/nvi/v_init.c228
-rw-r--r--usr.bin/vi/nvi/v_join.c75
-rw-r--r--usr.bin/vi/nvi/v_left.c166
-rw-r--r--usr.bin/vi/nvi/v_mark.c87
-rw-r--r--usr.bin/vi/nvi/v_match.c152
-rw-r--r--usr.bin/vi/nvi/v_ntext.c1728
-rw-r--r--usr.bin/vi/nvi/v_paragraph.c273
-rw-r--r--usr.bin/vi/nvi/v_put.c130
-rw-r--r--usr.bin/vi/nvi/v_redraw.c56
-rw-r--r--usr.bin/vi/nvi/v_replace.c176
-rw-r--r--usr.bin/vi/nvi/v_right.c144
-rw-r--r--usr.bin/vi/nvi/v_screen.c79
-rw-r--r--usr.bin/vi/nvi/v_scroll.c354
-rw-r--r--usr.bin/vi/nvi/v_search.c364
-rw-r--r--usr.bin/vi/nvi/v_section.c146
-rw-r--r--usr.bin/vi/nvi/v_sentence.c328
-rw-r--r--usr.bin/vi/nvi/v_shift.c78
-rw-r--r--usr.bin/vi/nvi/v_status.c129
-rw-r--r--usr.bin/vi/nvi/v_stop.c61
-rw-r--r--usr.bin/vi/nvi/v_switch.c86
-rw-r--r--usr.bin/vi/nvi/v_tag.c79
-rw-r--r--usr.bin/vi/nvi/v_text.c827
-rw-r--r--usr.bin/vi/nvi/v_ulcase.c159
-rw-r--r--usr.bin/vi/nvi/v_undo.c136
-rw-r--r--usr.bin/vi/nvi/v_util.c127
-rw-r--r--usr.bin/vi/nvi/v_word.c560
-rw-r--r--usr.bin/vi/nvi/v_xchar.c135
-rw-r--r--usr.bin/vi/nvi/v_yank.c114
-rw-r--r--usr.bin/vi/nvi/v_z.c133
-rw-r--r--usr.bin/vi/nvi/vcmd.c522
-rw-r--r--usr.bin/vi/nvi/vcmd.h274
-rw-r--r--usr.bin/vi/nvi/vi.c780
-rw-r--r--usr.bin/vi/options.c142
-rw-r--r--usr.bin/vi/options.h.stub8
-rw-r--r--usr.bin/vi/options_f.c113
-rw-r--r--usr.bin/vi/pathnames.h4
-rw-r--r--usr.bin/vi/put.c248
-rw-r--r--usr.bin/vi/recover.c118
-rw-r--r--usr.bin/vi/screen.c25
-rw-r--r--usr.bin/vi/screen.h129
-rw-r--r--usr.bin/vi/search.c112
-rw-r--r--usr.bin/vi/search.h5
-rw-r--r--usr.bin/vi/seq.c144
-rw-r--r--usr.bin/vi/seq.h7
-rw-r--r--usr.bin/vi/sex/sex_confirm.c15
-rw-r--r--usr.bin/vi/sex/sex_get.c96
-rw-r--r--usr.bin/vi/sex/sex_refresh.c15
-rw-r--r--usr.bin/vi/sex/sex_screen.c33
-rw-r--r--usr.bin/vi/sex/sex_term.c22
-rw-r--r--usr.bin/vi/sex/sex_util.c28
-rw-r--r--usr.bin/vi/svi/svi_confirm.c14
-rw-r--r--usr.bin/vi/svi/svi_ex.c22
-rw-r--r--usr.bin/vi/svi/svi_get.c28
-rw-r--r--usr.bin/vi/svi/svi_line.c41
-rw-r--r--usr.bin/vi/svi/svi_refresh.c140
-rw-r--r--usr.bin/vi/svi/svi_relative.c312
-rw-r--r--usr.bin/vi/svi/svi_screen.c93
-rw-r--r--usr.bin/vi/svi/svi_screen.h37
-rw-r--r--usr.bin/vi/svi/svi_smap.c138
-rw-r--r--usr.bin/vi/svi/svi_split.c57
-rw-r--r--usr.bin/vi/svi/svi_util.c175
-rw-r--r--usr.bin/vi/term.c426
-rw-r--r--usr.bin/vi/term.h129
-rw-r--r--usr.bin/vi/timer.c240
-rw-r--r--usr.bin/vi/trace.c15
-rw-r--r--usr.bin/vi/util.c96
-rw-r--r--usr.bin/vi/vi.1451
-rw-r--r--usr.bin/vi/vi.h51
-rw-r--r--usr.bin/vi/vi/getc.c267
-rw-r--r--usr.bin/vi/vi/v_again.c70
-rw-r--r--usr.bin/vi/vi/v_at.c71
-rw-r--r--usr.bin/vi/vi/v_ch.c321
-rw-r--r--usr.bin/vi/vi/v_delete.c145
-rw-r--r--usr.bin/vi/vi/v_ex.c81
-rw-r--r--usr.bin/vi/vi/v_filter.c101
-rw-r--r--usr.bin/vi/vi/v_increment.c162
-rw-r--r--usr.bin/vi/vi/v_init.c241
-rw-r--r--usr.bin/vi/vi/v_join.c84
-rw-r--r--usr.bin/vi/vi/v_left.c286
-rw-r--r--usr.bin/vi/vi/v_mark.c156
-rw-r--r--usr.bin/vi/vi/v_match.c186
-rw-r--r--usr.bin/vi/vi/v_ntext.c1827
-rw-r--r--usr.bin/vi/vi/v_paragraph.c349
-rw-r--r--usr.bin/vi/vi/v_put.c141
-rw-r--r--usr.bin/vi/vi/v_redraw.c66
-rw-r--r--usr.bin/vi/vi/v_replace.c190
-rw-r--r--usr.bin/vi/vi/v_right.c163
-rw-r--r--usr.bin/vi/vi/v_screen.c89
-rw-r--r--usr.bin/vi/vi/v_scroll.c414
-rw-r--r--usr.bin/vi/vi/v_search.c365
-rw-r--r--usr.bin/vi/vi/v_section.c201
-rw-r--r--usr.bin/vi/vi/v_sentence.c386
-rw-r--r--usr.bin/vi/vi/v_shift.c86
-rw-r--r--usr.bin/vi/vi/v_status.c138
-rw-r--r--usr.bin/vi/vi/v_stop.c74
-rw-r--r--usr.bin/vi/vi/v_switch.c95
-rw-r--r--usr.bin/vi/vi/v_tag.c86
-rw-r--r--usr.bin/vi/vi/v_text.c848
-rw-r--r--usr.bin/vi/vi/v_ulcase.c172
-rw-r--r--usr.bin/vi/vi/v_undo.c143
-rw-r--r--usr.bin/vi/vi/v_util.c159
-rw-r--r--usr.bin/vi/vi/v_word.c569
-rw-r--r--usr.bin/vi/vi/v_xchar.c135
-rw-r--r--usr.bin/vi/vi/v_yank.c92
-rw-r--r--usr.bin/vi/vi/v_z.c143
-rw-r--r--usr.bin/vi/vi/v_zexit.c88
-rw-r--r--usr.bin/vi/vi/vcmd.c530
-rw-r--r--usr.bin/vi/vi/vcmd.h329
-rw-r--r--usr.bin/vi/vi/vi.c801
-rw-r--r--usr.bin/vi/xaw/xaw_screen.c18
-rw-r--r--usr.bin/w/w.c8
-rw-r--r--usr.bin/wall/wall.c3
-rw-r--r--usr.bin/wc/wc.c2
-rw-r--r--usr.bin/whereis/whereis.c2
-rw-r--r--usr.bin/yacc/yacc.18
-rw-r--r--usr.sbin/Makefile11
-rw-r--r--usr.sbin/XNSrouted/Makefile (renamed from sbin/XNSrouted/Makefile)0
-rw-r--r--usr.sbin/XNSrouted/XNSrouted.8 (renamed from sbin/XNSrouted/XNSrouted.8)0
-rw-r--r--usr.sbin/XNSrouted/af.c (renamed from sbin/XNSrouted/af.c)0
-rw-r--r--usr.sbin/XNSrouted/af.h (renamed from sbin/XNSrouted/af.h)0
-rw-r--r--usr.sbin/XNSrouted/defs.h (renamed from sbin/XNSrouted/defs.h)0
-rw-r--r--usr.sbin/XNSrouted/if.c (renamed from sbin/XNSrouted/if.c)0
-rw-r--r--usr.sbin/XNSrouted/input.c (renamed from sbin/XNSrouted/input.c)0
-rw-r--r--usr.sbin/XNSrouted/interface.h (renamed from sbin/XNSrouted/interface.h)0
-rw-r--r--usr.sbin/XNSrouted/main.c (renamed from sbin/XNSrouted/main.c)0
-rw-r--r--usr.sbin/XNSrouted/output.c (renamed from sbin/XNSrouted/output.c)0
-rw-r--r--usr.sbin/XNSrouted/protocol.h (renamed from sbin/XNSrouted/protocol.h)0
-rw-r--r--usr.sbin/XNSrouted/startup.c (renamed from sbin/XNSrouted/startup.c)0
-rw-r--r--usr.sbin/XNSrouted/table.h (renamed from sbin/XNSrouted/table.h)0
-rw-r--r--usr.sbin/XNSrouted/tables.c (renamed from sbin/XNSrouted/tables.c)0
-rw-r--r--usr.sbin/XNSrouted/timer.c (renamed from sbin/XNSrouted/timer.c)0
-rw-r--r--usr.sbin/XNSrouted/tools/query.c (renamed from sbin/XNSrouted/tools/query.c)0
-rw-r--r--usr.sbin/XNSrouted/trace.c (renamed from sbin/XNSrouted/trace.c)0
-rw-r--r--usr.sbin/XNSrouted/trace.h (renamed from sbin/XNSrouted/trace.h)0
-rw-r--r--usr.sbin/ac/Makefile18
-rw-r--r--usr.sbin/ac/ac.8165
-rw-r--r--usr.sbin/ac/ac.c557
-rw-r--r--usr.sbin/config/config.86
-rw-r--r--usr.sbin/config/main.c37
-rw-r--r--usr.sbin/config/mkglue.c6
-rw-r--r--usr.sbin/config/mkmakefile.c4
-rw-r--r--usr.sbin/cron/cron.82
-rw-r--r--usr.sbin/diskless_cfg/diskless.h2
-rw-r--r--usr.sbin/diskless_cfg/diskless_cfg.c86
-rw-r--r--usr.sbin/fdcontrol/Makefile4
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.877
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.c100
-rw-r--r--usr.sbin/fdformat/Makefile25
-rw-r--r--usr.sbin/fdformat/fdformat.126
-rw-r--r--usr.sbin/fdformat/fdformat.c66
-rw-r--r--usr.sbin/flcopy/Makefile7
-rw-r--r--usr.sbin/flcopy/flcopy.883
-rw-r--r--usr.sbin/flcopy/flcopy.c201
-rw-r--r--usr.sbin/flcopy/pathnames.h36
-rw-r--r--usr.sbin/kbdcontrol/Makefile4
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.177
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.c566
-rw-r--r--usr.sbin/kbdcontrol/lex.h55
-rw-r--r--usr.sbin/kbdcontrol/lex.l114
-rw-r--r--usr.sbin/kbdcontrol/path.h4
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c52
-rw-r--r--usr.sbin/lpr/common_source/common.c2
-rw-r--r--usr.sbin/lpr/lpr/lpr.c2
-rw-r--r--usr.sbin/lptcontrol/Makefile4
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.167
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.c93
-rw-r--r--usr.sbin/mrouted/LICENSE48
-rw-r--r--usr.sbin/mrouted/Makefile44
-rw-r--r--usr.sbin/mrouted/config.c528
-rw-r--r--usr.sbin/mrouted/defs.h129
-rw-r--r--usr.sbin/mrouted/dvmrp.h141
-rw-r--r--usr.sbin/mrouted/igmp.c217
-rw-r--r--usr.sbin/mrouted/inet.c187
-rw-r--r--usr.sbin/mrouted/kern.c213
-rw-r--r--usr.sbin/mrouted/main.c322
-rw-r--r--usr.sbin/mrouted/mapper.c932
-rw-r--r--usr.sbin/mrouted/mrinfo.c469
-rw-r--r--usr.sbin/mrouted/mrouted.8242
-rw-r--r--usr.sbin/mrouted/mrouted.conf15
-rw-r--r--usr.sbin/mrouted/route.c900
-rw-r--r--usr.sbin/mrouted/route.h50
-rw-r--r--usr.sbin/mrouted/vif.c782
-rw-r--r--usr.sbin/mrouted/vif.h47
-rw-r--r--usr.sbin/mtree/verify.c5
-rw-r--r--usr.sbin/named/named.restart2
-rw-r--r--usr.sbin/pwd_mkdb/Makefile3
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.814
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c126
-rw-r--r--usr.sbin/routed/Makefile (renamed from sbin/routed/Makefile)0
-rw-r--r--usr.sbin/routed/af.c (renamed from sbin/routed/af.c)0
-rw-r--r--usr.sbin/routed/af.h (renamed from sbin/routed/af.h)0
-rw-r--r--usr.sbin/routed/defs.h (renamed from sbin/routed/defs.h)0
-rw-r--r--usr.sbin/routed/if.c (renamed from sbin/routed/if.c)0
-rw-r--r--usr.sbin/routed/inet.c (renamed from sbin/routed/inet.c)0
-rw-r--r--usr.sbin/routed/input.c (renamed from sbin/routed/input.c)0
-rw-r--r--usr.sbin/routed/interface.h91
-rw-r--r--usr.sbin/routed/main.c (renamed from sbin/routed/main.c)0
-rw-r--r--usr.sbin/routed/output.c (renamed from sbin/routed/output.c)0
-rw-r--r--usr.sbin/routed/pathnames.h (renamed from sbin/routed/pathnames.h)0
-rw-r--r--usr.sbin/routed/query/Makefile (renamed from sbin/routed/query/Makefile)0
-rw-r--r--usr.sbin/routed/query/query.c (renamed from sbin/routed/query/query.c)0
-rw-r--r--usr.sbin/routed/routed.8 (renamed from sbin/routed/routed.8)0
-rw-r--r--usr.sbin/routed/startup.c486
-rw-r--r--usr.sbin/routed/table.h (renamed from sbin/routed/table.h)0
-rw-r--r--usr.sbin/routed/tables.c (renamed from sbin/routed/tables.c)0
-rw-r--r--usr.sbin/routed/timer.c (renamed from sbin/routed/timer.c)0
-rw-r--r--usr.sbin/routed/trace.c (renamed from sbin/routed/trace.c)0
-rw-r--r--usr.sbin/routed/trace.h (renamed from sbin/routed/trace.h)0
-rw-r--r--usr.sbin/routed/trace/Makefile (renamed from sbin/routed/trace/Makefile)0
-rw-r--r--usr.sbin/routed/trace/trace.c (renamed from sbin/routed/trace/trace.c)0
-rw-r--r--usr.sbin/sa/Makefile8
-rw-r--r--usr.sbin/sa/extern.h100
-rw-r--r--usr.sbin/sa/main.c542
-rw-r--r--usr.sbin/sa/pathnames.h35
-rw-r--r--usr.sbin/sa/pdb.c418
-rw-r--r--usr.sbin/sa/sa.8246
-rw-r--r--usr.sbin/sa/usrdb.c282
-rw-r--r--usr.sbin/sendmail/cf/README2
-rw-r--r--usr.sbin/sendmail/contrib/expn.pl2
-rw-r--r--usr.sbin/sendmail/src/conf.c2
-rw-r--r--usr.sbin/sliplogin/slip.hosts2
-rw-r--r--usr.sbin/sliplogin/sliplogin.c7
-rw-r--r--usr.sbin/slstat/Makefile11
-rw-r--r--usr.sbin/slstat/slstat.8141
-rw-r--r--usr.sbin/slstat/slstat.c287
-rw-r--r--usr.sbin/vidcontrol/Makefile4
-rw-r--r--usr.sbin/vidcontrol/decode.c74
-rw-r--r--usr.sbin/vidcontrol/path.h4
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.1112
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.c472
-rw-r--r--usr.sbin/xten/Install.notes222
-rw-r--r--usr.sbin/xten/Makefile10
-rw-r--r--usr.sbin/xten/xten.1110
-rw-r--r--usr.sbin/xten/xten.c164
2676 files changed, 403915 insertions, 99793 deletions
diff --git a/CONTRIB.FreeBSD b/CONTRIB.FreeBSD
index e06bc96faa63..482fbfdf5b1e 100644
--- a/CONTRIB.FreeBSD
+++ b/CONTRIB.FreeBSD
@@ -1,20 +1,24 @@
- FreeBSD 1.1
- Contributor List
+ FreeBSD 1.1.5
+ Contributor List
Derived Software Contributors:
-This software was derived from William F. Jolitz's 386BSD release 0.1.
+This software was originally derived from William F. Jolitz's 386BSD
+release 0.1, though very little of the original 386BSD specific code
+remains.
+
Please see the file CONTRIB.386BSD for the list of contributors from
386BSD.
-Included in this release are the patches from the patch kit version
-0.2.4. The names of contributors from the patch kit are listed below.
+Included in this release are some of the patches from the old 386BSD
+patch kit version 0.2.4, and therefore the names of contributors from the
+patch kit are also listed below.
-There are portions of NetBSD that has been intergraged into FreeBSD
-as well. We would like to thank all the contributors to NetBSD for
-their work.
+Finally, there are portions of NetBSD that have been integrated into
+FreeBSD as well, and we would therefore like to thank all the contributors
+to NetBSD for their work.
Hardware Contributors:
@@ -28,32 +32,35 @@ Dermot McDonnell for his donation of a Toshiba XM3401B CDROM
drive.
-FreeBSD core:
+The FreeBSD Core Team (in alphabetical order):
-Andrew Moore <alm@netcom.com>
-Andreas Schulz <ats@g386bsd.first.bmd.de>
+Andrew A. Chernov <ache@astral.msk.su>
John Dyson <dyson@implode.rain.com>
-Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
David Greenman <davidg@Root.COM>
-Jordan K. Hubbard <jkh@whisker.hubbard.ie>
-Nate Williams <nate@bsd.coe.montana.edu>
-Paul Richards <paul@isl.cf.ac.uk>
-Rich Murphey <rich@lamprey.utmb.edu>
Rodney W. Grimes <rgrimes@cdrom.com>
+Jordan K. Hubbard <jkh@freefall.cdrom.com>
Scott Mace <smace@neosoft.com>
+Andrew Moore <alm@netcom.com>
+Rich Murphey <rich@lamprey.utmb.edu>
+Geoff Rehmet <csgr@cs.ru.ac.za>
+Paul Richards <paul@isl.cf.ac.uk>
+Andreas Schulz <ats@g386bsd.first.bmd.de>
+Nate Williams <nate@bsd.coe.montana.edu>
Garrett A. Wollman <wollman@freefall.cdrom.com>
-Additional FreeBSD Contributors:
+Additional FreeBSD Contributors (no particular order):
+Atsushi Murai <amurai@spec.co.jp>
+Keith Moore <?>
Adam Glass <glass@postgres.berkeley.edu>
-Andrew A. Chernov <ache@astral.msk.su>
Andrew Herbert <andrew@werple.apana.org.au>
Bob Wilcox <bob@obiwan.uucp>
Bruce Evans <bde@kralizec.zeta.org.au>
Charles Hannum <mycroft@ai.mit.edu>
Chris G. Demetriou <cgd@postgres.berkeley.edu>
Chris Torek <torek@ee.lbl.gov>
+Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
Curt Mayer <curt@toad.com>
Dave Burgess <burgess@hrd769.brooks.af.mil>
Dave Rivers <rivers@ponds.uucp>
@@ -69,7 +76,7 @@ J.T. Conklin <jtc@winsey.com>
James Clark <jjc@jclark.com>
James da Silva <jds@cs.umd.edu> et al
Jim Wilson <wilson@moria.cygnus.com>
-John Dyson - <formerly dyson@ref.tfs.com>
+Joerg Wunsch <joerg_wunsch@uriah.sax.de>
Julian Elischer <julian@dialix.oz.au>
Julian Stacey <stacey@guug.de> <fallback: <julian@meepmeep.pcs.com>>
Keith Bostic <bostic@toe.CS.Berkeley.EDU>
@@ -79,7 +86,7 @@ Martin Birgmeier
Paul Kranenburg <pk@cs.few.eur.nl>
Paul Mackerras <paulus@cs.anu.edu.au>
Poul-Henning Kamp <phk@login.dkuug.dk>
-Rod Shady <rls@id.net>
+Rob Shady <rls@id.net>
Sascha Wildner <swildner@channelz.GUN.de>
Sean Eric Fagan <sef@kithrup.com>
Serge V. Vakulenko <vak@zebub.msk.su>
@@ -90,7 +97,7 @@ Theo Deraadt <deraadt@fsa.ca>
Yuval Yarom <yval@cs.huji.ac.il>
-Patch kit patch contributors:
+Patch kit patch contributors (no particular order):
Adam Glass <glass@postgres.berkeley.edu>
Adrian Hall <adrian@ibmpcug.co.uk>
@@ -138,7 +145,7 @@ Joerg Lohse <lohse@tech7.informatik.uni-hamburg.de>
Joerg Wunsch <joerg_wunsch@uriah.sax.de>
John Dyson - <formerly dyson@ref.tfs.com>
John Woods <jfw@eddie.mit.edu>
-Jordan K. Hubbard <jkh@whisker.lotus.ie>
+Jordan K. Hubbard <jkh@whisker.hubbard.ie>
Julian Elischer <julian@dialix.oz.au>
Julian Stacey <stacey@guug.de> <fallback: <julian@meepmeep.pcs.com>>
Karl Lehenbauer <karl@NeoSoft.com> <karl@one.neosoft.com>
@@ -165,11 +172,10 @@ Rich Murphey <rich@lamprey.utmb.edu>
Rick Macklem <root@snowhite.cis.uoguelph.ca>
Robert D. Thrush <rd@phoenix.aii.com>
Rodney W. Grimes <rgrimes@cdrom.com>
-Rog Egge
+Rog Egge <?>
Sascha Wildner <swildner@channelz.GUN.de>
Scott Burris <scott@pita.cns.ucla.edu>
Scott Reynolds <scott@clmqt.marquette.mi.us>
-Scotty ?
Sean Eric Fagan <sef@kithrup.com>
Simon J Gerraty <sjg@melb.bull.oz.au> <sjg@zen.void.oz.au>
Stephen McKay <robert@psych.psy.uq.oz.au>
@@ -182,4 +188,4 @@ Wolfgang Solfrank <ws@tools.de>
Wolfgang Stanglmeier <wolf@dentaro.GUN.de>
Yuval Yarom <yval@cs.huji.ac.il>
-$Id: CONTRIB.FreeBSD,v 1.32.2.1 1994/03/07 01:29:59 rgrimes Exp $
+$Id: CONTRIB.FreeBSD,v 1.36 1994/06/28 08:09:27 jkh Exp $
diff --git a/COPYRIGHT.FreeBSD b/COPYRIGHT.FreeBSD
index a4d88b1e0fcd..65d1707f4639 100644
--- a/COPYRIGHT.FreeBSD
+++ b/COPYRIGHT.FreeBSD
@@ -79,9 +79,10 @@ Copyright (C) 1992, 1993, Garrett A. Wollman
Copyright (C) 1992, 1993, HD Associates
Copyright (C) 1992, 1993, Holger Veit
Copyright (C) 1992, 1993, Jean-Loup Gailly
-Copyright (C) 1992, 1993, Joerg Wunsch
+Copyright (C) 1992, 1993, 1994 Joerg Wunsch
Copyright (C) 1992, 1993, John Brezak
Copyright (C) 1992, 1993, Motorola, Inc.
+Copyright (C) 1993, 1994, Jordan Hubbard
Copyright (C) 1992, 1993, Soeren Schmidt
Copyright (C) 1992, 1993, Theo de Raadt
Copyright (C) 1992, 1993, University of Vermont and State Agricultural College
@@ -114,5 +115,8 @@ Copyright (C) 1993, Thomas Koenig
Copyright (C) 1993, Winning Strategies, Inc.
Copyright (C) 1994, Christoph M. Robitschko
Copyright (C) 1994, University of Maryland
+Copyright (C) 1993, 1994, jc@irbs.UUCP (John Capo),
+ vak@zebub.msk.su (Serge Vakulenko),
+ ache@astral.msk.su (Andrew A. Chernov)
-$Id: COPYRIGHT.FreeBSD,v 1.2 1994/02/20 02:51:25 rgrimes Exp $
+$Id: COPYRIGHT.FreeBSD,v 1.4 1994/06/28 08:09:29 jkh Exp $
diff --git a/COPYRIGHT.USL b/COPYRIGHT.USL
index 851751885e59..8a7dd751090b 100644
--- a/COPYRIGHT.USL
+++ b/COPYRIGHT.USL
@@ -2,7 +2,7 @@ Copyright (c) UNIX System Laboratories, Inc.
All or some portions of this software are derived from
material licensed to the University of California by
American Telephone and Telegraph Co. or UNIX System Laboratories, Inc.
-and are reporduced herein with the permission of
+and are reproduced herein with the permission of
UNIX System Laboratories, Inc.
Additionally, the following files contained herein constitute
@@ -42,4 +42,4 @@ usr.bin/cpio/cpio.c [*]
copyright and/or trade secret.
-$Id: COPYRIGHT.USL,v 1.1.2.1 1994/05/04 06:32:01 rgrimes Exp $
+$Id: COPYRIGHT.USL,v 1.3 1994/05/18 22:53:56 rgrimes Exp $
diff --git a/KNOWNBUGS b/KNOWNBUGS
index 0c0740af5f8c..781357d4b5dc 100644
--- a/KNOWNBUGS
+++ b/KNOWNBUGS
@@ -11,9 +11,6 @@ installed on your hard-drive is to 'bounce' on a key like shift or
num-lock (which works well since you can see when the keyboard comes
back to life) until the boot sequence is finished. The keyboard will
work fine for installing FreeBSD onto the hard-drive.
- Generally the problems go away at this point, but if it doesn't
-you should install a SYSCONS kernel which doesn't experience these
-keyboard problems.
/usr/bin/gdb:
The gdb in the release will not work on shared objects nor will it
@@ -63,14 +60,14 @@ keyboard problems.
memory. If you find this to be the case, temporarily remove your
extra memory and contact Buslogic for an upgrade!
-/usr/bin/find
- find doesn't work on CDROM's. You need to call find with the
- "fstype isofs" argument to get it working. The bug seems to be
- in the "fts(3)" routines that find uses.
+fsck:
+ fsck can go into an endless loop in the repair/fsck cycle on
+ a corrupted filesystem. The message "VALUES IN SUPER BLOCK
+ DISAGREE WITH THOSE IN FIRST ALTERNATE" is very misleading.
+ fsck compares the superblock with the alternate in the last
+ cylinder group? So if this block is corrupt, you have no chance
+ to get the filesystem repaired. You can answer on the question
+ "UPDATE STANDARD SUPERBLOCK" with yes and get always the same
+ error message on the next fsck.
-/usr/bin/awk
- awk dumps core for the following command line "awk '' blubber".
- Problem is already known by the gawk maintainers and will be fixed
- in the next release of gawk.
-
-$Id: KNOWNBUGS,v 1.7.2.6 1994/05/01 20:58:17 rgrimes Exp $
+$Id: KNOWNBUGS,v 1.16 1994/06/04 10:39:55 jkh Exp $
diff --git a/MIRROR.SITES b/MIRROR.SITES
index 6005e7201810..d6690a92f3c2 100644
--- a/MIRROR.SITES
+++ b/MIRROR.SITES
@@ -4,6 +4,15 @@ The FreeBSD software is being mirrored at the following locations:
Country Site/Directory/Maintainer
======= =========================================================
+Australia minnie.cs.adfa.oz.au:/BSD/FreeBSD-1.1-RELEASE
+ <wkt@cs.adfa.oz.au>
+
+Australia ftp.physics.su.oz.au:/FreeBSD
+ David Dawes <dawes@physics.su.oz.au>
+
+Australia ftp.une.edu.au:/pub/FreeBSD
+ Gordon Smith <Gordon.Smith@une.edu.au>
+
Austria ftp.tu-graz.ac.at:/pub/FreeBSD
<ftp@ftp.tu-graz.ac.at>
@@ -14,7 +23,7 @@ France ftp.ibp.fr:/pub/FreeBSD
<ftp@ftp.ibp.fr>
Germany ftp.informatik.tu-muenchen.de:/pub/comp/os/bsd/FreeBSD
- <unknown>
+ <bsd@informatik.tu-muenchen.de>
Germany ftp.uni-duisburg.de:/pub/unix/FreeBSD
<ftp@ftp.uni-duisburg.de>
@@ -25,6 +34,9 @@ Germany gil.physik.rwth-aachen.de:/pub/FreeBSD
Hong Kong ftp.cs.cuhk.hk:/pub/FreeBSD
<unknown>
+Israel orgchem.weizmann.ac.il:/pub/FreeBSD
+ <serg@klara.weizmann.ac.il>
+
Netherlands ftp.nl.net:/pub/os/FreeBSD
<archive@nl.net>
@@ -32,10 +44,16 @@ Russia ftp.kiae.su:/FreeBSD
<arcman@kiae.su>
UK src.doc.ic.ac.uk:/packages/FreeBSD
- <unknown>
+ <wizards@doc.ic.ac.uk>
+
+USA gatekeeper.dec.com:/pub/BSD/FreeBSD
+ <hubbard@gatekeeper.dec.com>
+
+USA freebsd.uml.edu:/FreeBSD
+ <oneill@cs.uml.edu>
-USA ftp.dsu.edu:/pub/FreeBSD
- <ghelmer@alpha.dsu.edu>
+USA wuarchive.wustl.edu:/systems/unix/FreeBSD
+ <archives@wugate.wustl.edu>
-$Id: MIRROR.SITES,v 1.7.2.1 1994/04/18 04:41:53 rgrimes Exp $
+$Id: MIRROR.SITES,v 1.16 1994/06/08 13:33:51 sean Exp $
diff --git a/Makefile b/Makefile
index 4aa1c67ca56b..3b0826ab3215 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
# @(#)Makefile 5.1.1.2 (Berkeley) 5/9/91
#
-# $Id: Makefile,v 1.40 1994/02/18 02:03:17 rgrimes Exp $
+# $Id: Makefile,v 1.55 1994/06/15 21:30:28 adam Exp $
#
SUBDIR=
@@ -22,6 +22,13 @@ SUBDIR+= include
.if exists(lib)
SUBDIR+= lib
.endif
+
+# This contains both libraries and includes, which stuff below depends
+# upon.
+.if exists(kerberosIV) && !defined(NOCRYPT)
+SUBDIR+= kerberosIV
+.endif
+
.if exists(libexec)
SUBDIR+= libexec
.endif
@@ -60,6 +67,11 @@ CLEANDIR=
CLEANDIR= cleandir
.endif
+# Where is the c-compiler source. Change this, and gnu/usr.bin/Makefile if you
+# want to use another cc (gcc-2.5.8 for instance)
+CCDIR= ${.CURDIR}/gnu/usr.bin/cc
+#CCDIR= ${.CURDIR}/gnu/usr.bin/cc25
+
world: directories cleandist mk includes libraries tools mdec
@echo "--------------------------------------------------------------"
@echo " Rebuilding ${DESTDIR} The whole thing"
@@ -69,6 +81,9 @@ world: directories cleandist mk includes libraries tools mdec
cd ${.CURDIR}/share/man; make makedb
directories:
+ @echo "--------------------------------------------------------------"
+ @echo " Making directories"
+ @echo "--------------------------------------------------------------"
cd ${.CURDIR}/etc; make distrib-dirs
cleandist:
@@ -107,7 +122,7 @@ mk:
# DONT DO THIS!! chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/share/mk
# DONT DO THIS!! chmod 755 ${DESTDIR}/usr/share/mk
.endif
- cd ${.CURDIR}/share/mk; make install;
+ cd ${.CURDIR}/share/mk; make clean all install;
includes:
@echo "--------------------------------------------------------------"
@@ -120,11 +135,15 @@ includes:
chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/include
chmod 755 ${DESTDIR}/usr/include
.endif
- cd ${.CURDIR}/include; make install
- cd ${.CURDIR}/gnu/usr.bin/cc/libobjc; make beforeinstall
+ cd ${.CURDIR}/include; make clean all install
+ cd ${CCDIR}/libobjc; make beforeinstall
cd ${.CURDIR}/gnu/lib/libg++; make beforeinstall
+ cd ${.CURDIR}/gnu/lib/libreadline; make beforeinstall
cd ${.CURDIR}/lib/libcurses; make beforeinstall
cd ${.CURDIR}/lib/libc; make beforeinstall
+.if !defined(NOCRYPT) && exists(${.CURDIR}/kerberosIV)
+ cd ${.CURDIR}/kerberosIV/include; make clean all install
+.endif
# You MUST run this the first time you get the new sources to boot strap
# the shared library tools onto you system. This target should only
@@ -142,12 +161,39 @@ bootstrapld: directories cleandist mk includes
cd ${.CURDIR}/usr.bin/strip; make -DNOPIC depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/usr.bin/ld; make -DNOPIC depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/usr.bin/as; make depend all install ${CLEANDIR} obj
- cd ${.CURDIR}/gnu/usr.bin/cc; make -DNOPIC depend all install ${CLEANDIR} obj
- cd ${.CURDIR}/gnu/usr.bin/cc/libgcc; make all install ${CLEANDIR} obj
+ cd ${CCDIR}; make -DNOPIC depend all install ${CLEANDIR} obj
+ cd ${CCDIR}/libgcc; make all install ${CLEANDIR} obj
cd ${.CURDIR}/lib/csu.i386; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/lib/libc; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/usr.bin/ld/rtld; make depend all install ${CLEANDIR} obj
+# Standard database make routines are slow especially for big passwd files.
+# Moreover, *pwd.db bases are too big and waste root space. You can have
+# much faster routines with small *pwd.db, but loose binary compatibility
+# with previous versions and with other BSD-like systems. If you want to
+# setup much faster routines, define envirnoment variable (f.e. 'setenv
+# PW_COMPACT' in csh) and use target into /usr/src/Makefile. If you will
+# want to return this changes back, use the same target without defining
+# PW_COMPACT.
+
+bootstrappwd: #directories
+ -rm -f ${.CURDIR}/lib/libc/obj/getpwent.o ${.CURDIR}/lib/libc/getpwent.o
+ cd ${.CURDIR}/lib/libc; make all
+ -rm -f ${.CURDIR}/usr.sbin/pwd_mkdb/obj/pwd_mkdb.o ${.CURDIR}/usr.sbin/pwd_mkdb/pwd_mkdb.o
+ cd ${.CURDIR}/usr.sbin/pwd_mkdb; make all install ${CLEANDIR}
+ cp /etc/master.passwd /etc/mp.t; pwd_mkdb /etc/mp.t
+ SLIB=`basename ${.CURDIR}/lib/libc/obj/libc.so.*`; \
+ cp ${.CURDIR}/lib/libc/obj/$$SLIB /usr/lib/$$SLIB.tmp; \
+ mv /usr/lib/$$SLIB.tmp /usr/lib/$$SLIB
+ cd ${.CURDIR}/lib/libc; make install ${CLEANDIR}
+ cd ${.CURDIR}/usr.bin/passwd; make clean all install ${CLEANDIR}
+ cd ${.CURDIR}/usr.bin/chpass; make clean all install ${CLEANDIR}
+ cd ${.CURDIR}/bin; make clean all install ${CLEANDIR}
+ cd ${.CURDIR}/sbin; make clean all install ${CLEANDIR}
+ @echo "--------------------------------------------------------------"
+ @echo " Do a reboot now because all daemons need restarting"
+ @echo "--------------------------------------------------------------"
+
libraries:
# setenv NOPROFILE if you do not want profiled libraries
@echo "--------------------------------------------------------------"
@@ -158,18 +204,24 @@ libraries:
find ${DESTDIR}/usr/lib \! -name '*.s[ao].*' -a \! -type d | xargs -n30 rm -rf
.endif
cd ${.CURDIR}/lib; make depend all install ${CLEANDIR} obj
- cd ${.CURDIR}/gnu/usr.bin/cc/libgcc; make depend all install ${CLEANDIR} obj
+ cd ${CCDIR}/libgcc; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/lib/libg++; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/lib/libregex; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/gnu/lib/libmalloc; make depend all install ${CLEANDIR} obj
+ cd ${.CURDIR}/gnu/lib/libreadline; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/usr.bin/lex; make depend all install ${CLEANDIR} obj
+.if exists(${.CURDIR}/kerberosIV) && !defined(NOCRYPT)
+ cd ${.CURDIR}/kerberosIV/des; make depend all install ${CLEANDIR} obj
+ cd ${.CURDIR}/kerberosIV/krb; make depend all install ${CLEANDIR} obj
+ cd ${.CURDIR}/kerberosIV/kdb; make depend all install ${CLEANDIR} obj
+.endif
tools:
@echo "--------------------------------------------------------------"
@echo " Rebuilding ${DESTDIR} Compiler and Make"
@echo "--------------------------------------------------------------"
@echo
- cd ${.CURDIR}/gnu/usr.bin/cc; make depend all install ${CLEANDIR} obj
+ cd ${CCDIR}; make depend all install ${CLEANDIR} obj
cd ${.CURDIR}/usr.bin/make; make depend all install ${CLEANDIR} obj
mdec:
diff --git a/REGISTER.FreeBSD b/REGISTER.FreeBSD
new file mode 100644
index 000000000000..4b1432510b40
--- /dev/null
+++ b/REGISTER.FreeBSD
@@ -0,0 +1,86 @@
+In the absence of any other mechanism for counting the number of users
+of FreeBSD, we like to as kindly suggest that you take a few minutes
+to please register with the counter set up by
+<Harald.T.Alvestrand@uninett.no>.
+
+The justification for such "registration" is twofold: First, we sincerely do
+wish to know just what the size and demographics of our user-base are
+in order to better support its needs. Second, it's a sad fact that many
+people rely on counters and statistics (even when highly dubious) rather
+than actual experience when chosing an operating system, and the best we
+can hope to do in such circumstances is to at least try to provide some
+indication of how popular we are (or are not). This is not how we recommend
+that people go about chosing an operating system, but the necessity of
+"marketing" remains an undeniable fact of life.
+
+The FreeBSD team does not necessarily feel that Harald's counter represents
+the best approach to such statistics gathering, and its accuracy will only
+be as good as people's willingness to register with it (which may not reflect
+the actual OS population at any single point in time), but in the total absence
+of any other mechanism for providing such useful statistics, it's certainly a
+start and we thank Harald for his efforts in providing this service.
+It's a community service, and of potential benefit to everyone (all *BSD
+users), so let's see if we can't make it work!
+
+Included below is the standard blurb from the counter.
+
+Thanks in advance,
+
+ The FreeBSD team.
+
+
+How to get registered
+=====================
+
+In brief:
+
+ [To register a running installation of FreeBSD]
+ Send E-mail to bsd-counter@uninett.no with the SUBJECT line
+
+ "I use FreeBSD at <place>"
+
+Introduction
+============
+The intention of this counting project is to count all users of UNIXes
+that are:
+
+ - BSD-derived
+ - Freely available
+
+The variants NetBSD, 386BSD and FreeBSD are currently distinguished.
+
+(NOTE: Linux is NOT BSD-derived. If you use that, send mail to
+linux-counter@uninett.no instead!!!)
+
+The information is *not* used for any purpose but statistics, and unless
+you request it, information about single persons are *never* made public.
+(A list of users who have requested publication is available from the
+FTP file ftp://aun.uninett.no/pub/misc/386bsd/persons)
+
+How to register
+===============
+Send E-mail to bsd-counter@uninett.no
+
+The subject should be
+
+ I use FreeBSD|NetBSD|386BSD at <place>
+
+Where FreeBSD, NetBSD or 386BSD is the particular variant you're using
+and "place" can be school, work or home, or a combination of these.
+
+You will get back a letter with 3 things:
+
+ - An acknowledgement
+ - A form that you can fill out and send in with more information
+ about yourself, your machine, and your 386bsd-using friends
+ - A report giving the current status of the counter
+
+You can update your "vote" at any time, by sending an E-mail message
+from the same account. Duplicates will be weeded out.
+
+The current report, available by anonymous FTP to aun.uninett.no,
+directory pub/misc/386bsd-counter, file "short", is given below.
+
+For all questions, contact Harald.T.Alvestrand@uninett.no!
+
+$Id: REGISTER.FreeBSD,v 1.2 1994/06/04 10:39:57 jkh Exp $
diff --git a/RELNOTES.FreeBSD b/RELNOTES.FreeBSD
index 534d8056e850..729fff2f2d15 100644
--- a/RELNOTES.FreeBSD
+++ b/RELNOTES.FreeBSD
@@ -1,29 +1,35 @@
RELEASE NOTES
FreeBSD
- Release 1.1
+ Release 1.1.5
1. Technical overview
---------------------
FreeBSD is a freely available, full source 4.3 (+4.4 enhancements) BSD
release for Intel i386/i486 (or compatable) based PC's. It is based
-heavily on Bill Jolitz's 386BSD 0.1, with additions from "the patchkit",
+on Bill Jolitz's 386BSD 0.1, with additions from "the patchkit",
NetBSD, CSRG, and the Free Software Foundation.
-Many hundreds of bugs from the 386BSD 0.1 distribution were fixed,
-and many out-of-date pieces of software were upgraded to their current
-releases in the GAMMA distribution. This 1.0 distribution fixes
-many of the first-run problems our GAMMA and EPSILON users reported back
-to us.
+Since our first release of FreeBSD 1.0, many hundreds of bugs have been
+fixed, features added, and the overall quality of the system improved
+almost imeasurably. FreeBSD 1.1.5 represents the culmination of almost
+18 months of work and many thousands of man hours put in by our all-volunteer
+working group. We hope you enjoy it!
-Additionally, many packages such as XFree86 2.1, xview 3.2, elm, nntp,
-mh, InterViews and dozens of other miscellaneous utilities have been ported
-and are now available as add-ons. See then next section of this document
-for more details.
+Many packages have also been upgraded or added, such as XFree86 2.1,
+xview 3.2, elm, nntp, mh, InterViews and dozens of other miscellaneous
+utilities have been ported and are now available as add-ons. See the next
+section of this document for more details.
For a list of contributors, please see the files "CONTRIB.FreeBSD" and
"CONTRIB.386BSD", which should be bundled with your distribution.
+Also see the new "REGISTER.FreeBSD" file for information on registering
+with the "Free BSD user counter". We've also provided a list of who's
+responsible for what (so that you may query them directly) in the
+"ROSTER.FreeBSD" file; use of this file is encouraged to ensure faster
+resolution of an problems you may have!
+
The core of FreeBSD does not contain DES code which would inhibit its
being exported outside the United States. There is an add-on package
to the core distribution, for use only in the United States, that
@@ -36,8 +42,8 @@ and is described in the FreeBSD FAQ.
2. Supported Configurations
---------------------------
-FreeBSD currently runs on a wide variety of ISA and EISA bus based
-PC's, ranging from 386sx to 486 class machines (though the 386sx is
+FreeBSD currently runs on a wide variety of ISA, EISA and PCI bus based
+PC's, ranging from 386sx to Pentium class machines (though the 386sx is
not recommended). Support for generic IDE or ESDI drive configurations,
various SCSI controller, network and serial cards is also provided.
@@ -61,18 +67,24 @@ Adaptec 174x series EISA SCSI controller in standard and enhanced mode.
Buslogic 545S.
Buslogic 445S VLB SCSI controller
Buslogic 742A and 747.
+Buslogic 942A PCI
+
Please see special notes in /usr/src/KNOWNBUGS (filed under bt742a.c) for
details concerning possible buggy firmware and undocumented switch settings
-that may be necessary for proper operation of your controller.
+that may be necessary for proper operation of your Bt445S controller.
DTC 3290 EISA SCSI controller in 1542 emulation mode.
Ultra Store 14F and 34F.
+Seagate ST01/02 SCSI controllers.
+
+Future Domain 8xx/950 series SCSI controllers.
+
With all supported SCSI controllers, full support is provided for
SCSI-I & SCSI-II peripherals, including Disks, tape drives (including
DAT) and CD ROM drives. Note: This and the mcd driver (Mitsumi CDROM
-inteface card) is the only way a CD ROM drive may be currently
+interface card) is the only way a CD ROM drive may be currently
attached to a FreeBSD system; we do not support SoundBlaster CDROM
interface, or other "mini SCSI" adapters.
@@ -84,7 +96,9 @@ EISA controllers (which are normally 32 bit) when they're configured to
emulate an ISA card, which they then do in *all* respects. This problem
is avoided entirely by IDE controllers (which do not use DMA), true EISA
controllers (like the UltraStor or Adaptec 1742A) and most VLB (local bus)
-controllers.
+controllers. In the cases where it's necessary, the system will use
+"bounce buffers" to to talk to the controller so that you can still use
+more than 16Mb of memory without difficulty.
2.2. Ethernet cards
@@ -110,9 +124,9 @@ SMC Elite Ultra
2.3. Misc
-Various 2 and 4 port serial/parallel cards.
+AST 4 port serial card using shared IRQ.
-Simple (AST-like) multiport serial cards.
+ARNET 8 port serial card using shared IRQ.
BOCA ATIO66 6 port serial card using shared IRQ.
@@ -125,7 +139,7 @@ and Roland MPU-401 sound cards.
FreeBSD currently does NOT support IBM's microchannel (MCA) bus, but
support is apparently close to materializing. Details will be posted
-as they develop.
+as the situation develops.
3. Obtaining FreeBSD.
@@ -153,7 +167,7 @@ resort!
2. CDROM
-FreeBSD may be ordered on CDROM from:
+FreeBSD 1.1 may be ordered on CDROM from:
Walnut Creek CDROM
4041 Pike Lane, Suite D
@@ -245,21 +259,21 @@ The Computer Systems Research Group (CSRG), U.C. Berkeley.
Bill Jolitz, for his extensive work with 386BSD.
-The FreeBSD "core" group:
+The FreeBSD "core" team:
- Andrew A. Chernov
- John Dyson
- David Greenman
- Rodney W. Grimes
- Jordan K. Hubbard
- Scott Mace
- Andrew Moore
- Rich Murphey
- Paul Richards
- Christoph Robitschko
- Andreas Schulz
- Nate Williams
- Garrett A. Wollman
+ Andrew A. Chernov
+ John Dyson
+ David Greenman
+ Rodney W. Grimes
+ Jordan K. Hubbard
+ Scott Mace
+ Andrew Moore
+ Rich Murphey
+ Geoff Rehmet
+ Paul Richards
+ Andreas Schulz
+ Nate Williams
+ Garrett A. Wollman
Special mention to:
@@ -285,6 +299,7 @@ Special mention to:
Chris Provenzano Dave Rivers
Guido van Rooij Steven Wallace
Rick Weldon Terry Williams
+ Atsushi Murai
And everyone at Montana State University for their initial support.
@@ -293,6 +308,6 @@ Thanks to everyone, especially those not mentioned, and we sincerely
hope you enjoy this release of FreeBSD!
- The FreeBSD Core Group
+ The FreeBSD Core Team
-$Id: RELNOTES.FreeBSD,v 1.23.2.4 1994/05/02 02:23:48 rgrimes Exp $
+$Id: RELNOTES.FreeBSD,v 1.34 1994/06/28 08:09:31 jkh Exp $
diff --git a/ROSTER.FreeBSD b/ROSTER.FreeBSD
new file mode 100644
index 000000000000..9972cf4fee11
--- /dev/null
+++ b/ROSTER.FreeBSD
@@ -0,0 +1,127 @@
+This file attempts to document just who is `responsible' for what in
+the FreeBSD world. Since we're an all-volunteer group, the whole
+concept of `responsibility' must, of course, be taken with a grain of
+salt since the folks here may not always have time to deal with your
+problem right away. With that in mind, you are encouraged to contact
+these folks directly when your problem or suggestion clearly falls
+into their area of responsibility. If your queries don't net any
+positive results in, say, 48 hours, THEN you should try and contact
+the group at large. In most cases, however, using these folks as
+first-contacts will both cut down on our mail-overload and give you
+faster service.
+
+Thank you!
+
+ The FreeBSD Team
+ freebsd-hackers@freefall.cdrom.com
+
+---
+
+
+Legend:
+-------
+contrib = Contributed
+doc = Documentation
+lib = User-land library
+misc = Misc user-land utility (contrib, other)
+ports = Ported software in /usr/ports
+prog = User-land program
+share = Support data files
+sys = Kernel and system code
+tools = DOS support utilities
+
+Category Person Email address
+===============================================================================
+contrib/xntpd Garrett Wollman wollman@lcs.mit.edu
+doc/FAQ FAQ Team freebsd-faq@freefall.cdrom.com
+lib/libF77 L. Jonas Olsson ljo@po.cwru.edu
+lib/libc Garrett Wollman wollman@lcs.mit.edu
+lib/libcrypt (non-US) Geoff Rehmet csgr@cs.ru.ac.za
+lib/libcurses Andrew Chernov ache@astral.msk.su
+lib/libkrb Garrett Wollman wollman@lcs.mit.edu
+lib/libm Andrew Moore alm@netcom.com
+lib/libpthread Chris Provenzano proven@mit.edu
+lib/libskey Guido van Rooij guido@gvr.win.tue.nl
+lib/libtelnet Garrett Wollman wollman@lcs.mit.edu
+misc/addit Gary Clark II gclarkii@freefall.cdrom.com
+misc/configit Gary Clark II gclarkii@freefall.cdrom.com
+misc/gnats Andrew Moore alm@netcom.com
+misc/manctl Geoff Rehmet csgr@cs.ru.ac.za
+ports/{not below} Andrew Moore alm@freefall.cdrom.com
+ports/aXe Jordan Hubbard jkh@freefall.cdrom.com
+ports/archivers Scott Mace smace@freefall.cdrom.com
+ports/bash Jordan Hubbard jkh@freefall.cdrom.com
+ports/blt Jordan Hubbard jkh@freefall.cdrom.com
+ports/cpm Joerg Wunsch joerg_wunsch@uriah.sax.de
+ports/dgd Adam David adam@veda.is
+ports/elm Scott Mace smace@freefall.cdrom.com
+ports/emacs Jordan Hubbard jkh@freefall.cdrom.com
+ports/exmh Jordan Hubbard jkh@freefall.cdrom.com
+ports/ezd Jeffrey Hsu hsu@freefall.cdrom.com
+ports/franz Jordan Hubbard jkh@freefall.cdrom.com
+ports/fvwm Geoff Rehmet csgr@cs.ru.ac.za
+ports/golddig Jeffrey Hsu hsu@freefall.cdrom.com
+ports/ile Jordan Hubbard jkh@freefall.cdrom.com
+ports/ispell Piero Serini piero@strider.st.dsi.unimi.it
+ports/jpeg Scott Mace smace@freefall.cdrom.com
+ports/kermit Scott Mace smace@freefall.cdrom.com
+ports/ksh Sean Vickery seanv@cs.uq.edu.au
+ports/kterm Satoshi Asami asami@cs.berkeley.edu
+ports/lynx Serge V.Vakulenko vak@cronyx.msk.su
+ports/mprof Jeffrey Hsu hsu@freefall.cdrom.com
+ports/mtools Steven Wallace swallace@freefall.cdrom.com
+ports/netaudio Jeffrey Hsu hsu@freefall.cdrom.com
+ports/nethack Sean Vickery seanv@cs.uq.edu.au
+ports/pcvt J"org Wunsch joerg_wunsch@uriah.sax.de
+ports/piewm Satoshi Asami asami@cs.berkeley.edu
+ports/pkg_install Jordan Hubbard jkh@freefall.cdrom.com
+ports/popper Andreas Schulz ats@g386bsd.first.gmd.de
+ports/point Jordan Hubbard jkh@freefall.cdrom.com
+ports/sather Jeffrey Hsu hsu@freefall.cdrom.com
+ports/schemetoc Jeffrey Hsu hsu@freefall.cdrom.com
+ports/scm Jeffrey Hsu hsu@freefall.cdrom.com
+ports/seahaven Jeffrey Hsu hsu@freefall.cdrom.com
+ports/sml Jeffrey Hsu hsu@freefall.cdrom.com
+ports/sup Jordan Hubbard jkh@freefall.cdrom.com
+ports/tcl Jordan Hubbard jkh@freefall.cdrom.com
+ports/tcl-dp Jordan Hubbard jkh@freefall.cdrom.com
+ports/tclX Jordan Hubbard jkh@freefall.cdrom.com
+ports/tcsh Scott Mace smace@freefall.cdrom.com
+ports/tk Jordan Hubbard jkh@freefall.cdrom.com
+ports/vile Jordan Hubbard jkh@freefall.cdrom.com
+ports/vim Jordan Hubbard jkh@freefall.cdrom.com
+ports/wine Jeffrey Hsu hsu@freefall.cdrom.com
+ports/wu-ftpd Justin T. Gibbs gibbs@freefall.cdrom.com
+ports/xcdplayer Steven Wallace swallace@freefall.cdrom.com
+ports/xjewel Jeffrey Hsu hsu@freefall.cdrom.com
+ports/xlock Scott Mace smace@freefall.cdrom.com
+ports/xmine J"org Wunsch joerg_wunsch@uriah.sax.de
+ports/xphoon Satoshi Asami asami@cs.berkeley.edu
+ports/xv Scott Mace smace@freefall.cdrom.com
+ports/ytalk Geoff Rehmet csgr@cs.ru.ac.za
+ports/zircon Jordan Hubbard jkh@freefall.cdrom.com
+ports/zsh Scott Mace smace@freefall.cdrom.com
+prog/cc Poul-Henning Kamp phk@freefall.cdrom.com
+prog/cc25 Poul-Henning Kamp phk@freefall.cdrom.com
+prog/gdb Gary Jennejohn gj@pcs.dec.com
+prog/man Jordan Hubbard jkh@freefall.cdrom.com
+prog/telnet Garrett Wollman wollman@lcs.mit.edu
+sys/fd J"org Wunsch joerg_wunsch@uriah.sax.de
+sys/fd Serge V.Vakulenko vak@cronyx.msk.su
+sys/i386 David Greenman davidg@root.com
+sys/i386/isa/seagate Sean Vickery seanv@cs.uq.edu.au
+sys/i386/isa/sound Steven Wallace swallace@freefall.cdrom.com
+sys/i386/isa/bt742*.c Atsushi Murai amurai@spec.co.jp
+sys/kern David Greenman davidg@root.com
+sys/kern/ntp Garrett Wollman wollman@lcs.mit.edu
+sys/lpt Geoff Rehmet csgr@cs.ru.ac.za
+sys/net* David Greenman davidg@root.com
+sys/netboot Martin Renters martin@innovus.com
+sys/netinet Garrett Wollman wollman@lcs.mit.edu
+sys/pcmcia Poul-Henning Kamp phk@freefall.cdrom.com
+sys/scheduler John Dyson dyson@freefall.cdrom.com
+sys/syscons So/ren Schmidt sos@freefall.cdrom.com
+sys/vm David Greenman davidg@root.com
+sys/vm John Dyson dyson@freefall.cdrom.com
+sys/wt Serge V.Vakulenko vak@cronyx.msk.su
+tools/booteasy Serge V.Vakulenko vak@cronyx.msk.su
diff --git a/SUPPORT.TXT b/SUPPORT.TXT
index 1fac5fba7332..9397555e1c66 100644
--- a/SUPPORT.TXT
+++ b/SUPPORT.TXT
@@ -44,65 +44,46 @@ floppies and tape cartridges available. System software development
including drivers for non-standard equipment.
-Guy Helmer <ghelmer@alpha.dsu.edu>
-519 West Ave. South
-Madison, SD 57042
-Home: 605-256-2788
-Expires on 1995/06/30
-
-Interests: supporting FreeBSD & XFree86 installation, configuration,
-operation; Internet connection support; training. Prefer short-term
-part-time projects in the northern midwest United States. I reserve the
-right to refuse work. Rates negotiable.
-
-Degree: SDSM&T BS CS, 1989
-
-
Jordan Hubbard
Timberline Associates (est 1978)
-Dublin, Ireland
+Dublin, Ireland [And soon Boston / San Francisco]
Support hours: 1000 - 2300 GMT
Tel #: 00353-1-332796
Email: jkh@al.org
+Telephone (or Internet) and on-site consulting for FreeBSD in Ireland,
+the United States, United Kingdom and most parts of Europe. Services include
+installation, system configuration, networking and custom software
+projects, graphical user interfaces a specialty (actively involved with
+The X Window System since Version 9 and contributor to the X Consortium).
+Reasonable and flexible rates comensurate with location and duration of
+assignment. Internet assignments are welcomed, and generally billed at
+lower rates.
+
+
+Vector Systems Ltd, Julian H. Stacey.
+Post: Holz Strasse 27d, D 80469, Munich (Muenchen), Germany (Deutschland).
+Tel.: +49 89 268616 09:00-22:00 TZ=GMT+1
+Email: stacey@freefall.cdrom.com
+
+Custom designs & support using FreeBSD + X-Windows + FSF/GNU, + own Unix & DOS
+C tools. Systems engineering, hardware interfacing, multi lingual systems
+(European, Cyrillic, Chinese), communications, scientific, industrial real
+time programming. Source Tapes: QIC 525M, 150M, 60M.
+Deutsch: Man kann mir in Deutsch schreiben, (oder mich anrufen).
+Francais: Je comprend Francais, mais je n'ecris pas des responses en Francais.
+
+
+Sean Vickery
+2/449 Milton Road
+Auchenflower Qld 4066
+Australia
+Telephone: +61 (0)7 870 5241
+ Email: seanv@cs.uq.edu.au
+
+Sean offers support in most FreeBSD matters, including installation
+and configuration. His rates are reasonable. As well as on-site
+help, support is available over the phone and the net.
+
-Telephone and on-site consulting for FreeBSD for Ireland, the United
-Kingdom and most parts of Europe. Services include installation,
-system configuration and custom software projects, graphical user
-interfaces a specialty (actively involved with The X Window System
-since Version 9). Reasonable and flexible rates comeasurate with
-location and duration of assignment.
-
-
-
-Vector Systems Ltd,
-Julian H. Stacey, Holz Strasse 27d, 80469, Munich (Muenchen), Germany.
-Tel. +49 89 268616 09:00-19:00 Timezone=GMT+01:00
-email: <stacey@guug.de> (later changing to <stacey@vector.guug.de>)
-
-COMMERCIAL Independent Consultancy:
- Custom Project Designs, provision, & support, targeting all modern
- Unix like platforms. Prefered development & target platform: FreeBSD.
- Expertise in C, FSF/GNU tools, X Windows, multi lingual systems
- (inc. Cyrillic), systems engineering, hardware interfacing,
- communications & scientific & industrial programming.
- Generally avoiding: cobol, basic, payroll applications.
- Support & Provision available for combinations of
- FreeBSD, X-Windows, FSF/GNU & range of own C tools for
- all Unix + MSDOS.
- Rate: ~125 DM/hour, (~2.5DM=#1UK, ~1.5DM=$1USA @ Nov. 93).
-On Request:
- Personal Resume, Company Profile, Index of own purchasable tools,
- Index of public domain tools.
-Deutsch + Francais:
- Man kann mir in Deutsch schreiben, (oder mich anrufen).
- Je comprend Francais, mais je n'ecris pas des responses en Francais.
- (Contact me in English, German, or French.
-Public Domain Copies:
- Selections of FreeBSD, X-Windows, FSF/GNU Sources & Binaries available.
- 525, 150, & 60 Mbyte QIC Cartridge, TEAC 60M Cassette, 1.2&4M Floppies.
- From about 100DM per Cartridge for labour, media, postage.
-
-
-
-$Id: SUPPORT.TXT,v 1.1.2.1 1994/04/21 19:06:31 rgrimes Exp $
+$Id: SUPPORT.TXT,v 1.5 1994/06/09 03:46:15 jkh Exp $
diff --git a/TODO-1.1.5 b/TODO-1.1.5
new file mode 100644
index 000000000000..66d1777a13a2
--- /dev/null
+++ b/TODO-1.1.5
@@ -0,0 +1,38 @@
+This is my current TODO list for 1.1.5. Please feel free to add to
+it, assuming that you've actually got some confidence that you or
+someone else will be able to actually get to whatever it is (or it's
+so critical that you don't think 1.1.5 could/should be released
+without it).
+
+Also, please bear in mind the following milestones we have to hit:
+
+June 5th Feature Freeze (bug fixes and cleanup work only).
+June 16th Code Freeze
+June 20th Roll binaries - begin initial testing
+June 23rd Announce availability of 1.1.5.
+
+(*) = Task is completed
+(@) = Task is abandoned
+
+Task Urgency Who
+-------------------------------------------------------------------------------
+Floppy driver fixes Low * Joerg Wunsch
+Sound driver (GUS/Multicast/cleanup) Medium Steven W/Andrew C.
+Curses library problems Medium * Steven W.
+SIO driver - reported problems High * Andrew C/Bruce E/???
+Syscons integration / new features High * Soren Schmidt/Jordan
+Update FT driver Medium * Javier R/Steven G.
+Update gdb High * Paul
+Make pcfs less dangerous Low @ ???
+Bruce's disklabel and bad144 fixes Medium * Andrew C.
+Misc NetBSD drivers for weird devices Low @ Geoff
+Multicast Support Medium * Jordan
+Bounce Buffer fixes High * John/David
+VM panics and assorted lossage High * John/David
+Secure Key support Low * Guido
+Install script enhancements Medium * Andrew M/Jordan
+Fsck/umount cooperation with dirty bit Low @ Paul R.
+PCFS data corruption with cp Medium * Steven W./ATS
+PCFS extended DOS partition support Low @ ???
+ISOFS over NSF fix Medium/High * ???
+Libcompat Low * Joerg Wunsch
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index e21bba631e9d..97375b17d1a1 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -299,7 +299,7 @@ copy_file(fs, dne)
struct stat *fs;
int dne;
{
- static char buf[MAXBSIZE];
+ static char buf[MAXBSIZE * 4];
register int from_fd, to_fd, rcount, wcount;
struct stat to_stat;
char *p;
@@ -358,7 +358,7 @@ copy_file(fs, dne)
if (munmap((caddr_t) p, fs->st_size) < 0)
err("%s: %s", from.p_path, strerror(errno));
} else {
- while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ while ((rcount = read(from_fd, buf, sizeof(buf))) > 0) {
wcount = write(to_fd, buf, rcount);
if (rcount != wcount || wcount == -1) {
err("%s: %s", to.p_path, strerror(errno));
diff --git a/bin/cp/path.c b/bin/cp/path.c
index a84892193554..170460283522 100644
--- a/bin/cp/path.c
+++ b/bin/cp/path.c
@@ -50,7 +50,7 @@ static char sccsid[] = "@(#)path.c 5.2 (Berkeley) 10/27/91";
*/
#define STRIP_TRAILING_SLASH(p) { \
- while ((p)->p_end > (p)->p_path && (p)->p_end[-1] == '/') \
+ while ((p)->p_end > ((p)->p_path + 1) && (p)->p_end[-1] == '/') \
*--(p)->p_end = 0; \
}
diff --git a/bin/csh/char.c b/bin/csh/char.c
index f552a28684a5..eb2dab68bf10 100644
--- a/bin/csh/char.c
+++ b/bin/csh/char.c
@@ -63,10 +63,10 @@ unsigned short _cmap[256] = {
_CTR, _CTR, _CTR, _CTR,
/* sp ! " # */
- _SP|_META, 0, _Q, _META,
+ _SP|_META, 0, _Q2, _META,
/* $ % & ' */
- _DOL, 0, _META|_CMD, _Q,
+ _DOL, 0, _META|_CMD, _Q2,
/* ( ) * + */
_META|_CMD, _META, _GLOB, 0,
diff --git a/bin/csh/char.h b/bin/csh/char.h
index 297a6ee8e1e2..475436879180 100644
--- a/bin/csh/char.h
+++ b/bin/csh/char.h
@@ -42,7 +42,7 @@ extern unsigned char _cmap_lower[], _cmap_upper[];
#endif
-#define _Q 0x0001 /* '" */
+#define _Q2 0x0001 /* '" */
#define _Q1 0x0002 /* ` */
#define _SP 0x0004 /* space and tab */
#define _NL 0x0008 /* \n */
diff --git a/bin/csh/dol.c b/bin/csh/dol.c
index d2b28f5433b1..816b45840664 100644
--- a/bin/csh/dol.c
+++ b/bin/csh/dol.c
@@ -66,7 +66,7 @@ static Char *Dcp, **Dvp; /* Input vector for Dreadc */
#define unDgetC(c) Dpeekc = c
-#define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */
+#define QUOTES (_Q2|_Q1|_ESC) /* \ ' " ` */
/*
* The following variables give the information about the current
@@ -192,7 +192,7 @@ Dpack(wbuf, wp)
Gcat(STRNULL, wbuf);
return (NULL);
}
- if (cmap(c, _SP | _NL | _Q | _Q1)) { /* sp \t\n'"` */
+ if (cmap(c, _SP | _NL | _Q2 | _Q1)) { /* sp \t\n'"` */
unDgetC(c);
if (cmap(c, QUOTES))
return (wp);
diff --git a/bin/csh/lex.c b/bin/csh/lex.c
index 63af5da774a4..75fb7e3a7f70 100644
--- a/bin/csh/lex.c
+++ b/bin/csh/lex.c
@@ -315,7 +315,7 @@ loop:
break;
}
}
- else if (cmap(c, _META | _Q | _Q1 | _ESC)) {
+ else if (cmap(c, _META | _Q2 | _Q1 | _ESC)) {
if (c == '\\') {
c = getC(0);
if (c == '\n') {
@@ -327,7 +327,7 @@ loop:
*wp++ = '\\', --i;
c |= QUOTE;
}
- else if (cmap(c, _Q | _Q1)) { /* '"` */
+ else if (cmap(c, _Q2 | _Q1)) { /* '"` */
c1 = c;
dolflg = c == '"' ? DOALL : DOEXCL;
}
@@ -366,7 +366,7 @@ getC1(flag)
if ((c = *lap++) == 0)
lap = 0;
else {
- if (cmap(c, _META | _Q | _Q1))
+ if (cmap(c, _META | _Q2 | _Q1))
c |= QUOTE;
return (c);
}
diff --git a/bin/df/df.c b/bin/df/df.c
index a28a862cc09b..ecebfe85baac 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: df.c,v 1.3.2.2 1994/05/04 07:35:01 rgrimes Exp $
+ * $Id: df.c,v 1.5 1994/05/04 08:04:22 rgrimes Exp $
*/
/*
* Copyright (c) 1980, 1990 The Regents of the University of California.
diff --git a/bin/ed/Makefile b/bin/ed/Makefile
index a99763cc9202..7ecca79081d9 100644
--- a/bin/ed/Makefile
+++ b/bin/ed/Makefile
@@ -1,5 +1,5 @@
PROG= ed
-SRCS= buf.c cbc.c glob.c io.c main.c re.c sub.c undo.c
+SRCS= buf.c cbc.c glbl.c io.c main.c re.c sub.c undo.c
LINKS= ${BINDIR}/ed ${BINDIR}/red
MLINKS= ed.1 red.1
diff --git a/bin/ed/buf.c b/bin/ed/buf.c
index f5b8045ebb3b..70275990c9ae 100644
--- a/bin/ed/buf.c
+++ b/bin/ed/buf.c
@@ -26,10 +26,11 @@
* SUCH DAMAGE.
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: buf.c,v 1.4 1994/02/01 00:34:35 alm Exp $";
+static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
#endif /* not lint */
#include <sys/file.h>
+#include <sys/stat.h>
#include "ed.h"
@@ -131,7 +132,7 @@ add_line_node(lp)
line_t *cp;
cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
- insque(lp, cp);
+ INSQUE(lp, cp);
addr_last++;
current_addr++;
}
@@ -195,13 +196,18 @@ char sfn[15] = ""; /* scratch file name */
int
open_sbuf()
{
+ int u;
+
isbinary = newline_added = 0;
+ u = umask(077);
strcpy(sfn, "/tmp/ed.XXXXXX");
if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
sprintf(errmsg, "cannot open temp file");
+ umask(u);
return ERR;
}
+ umask(u);
return 0;
}
diff --git a/bin/ed/cbc.c b/bin/ed/cbc.c
index 9d1d9894583e..ee5285cdd0ec 100644
--- a/bin/ed/cbc.c
+++ b/bin/ed/cbc.c
@@ -38,7 +38,7 @@
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: cbc.c,v 1.2 1994/02/01 00:34:36 alm Exp $";
+static char *rcsid = "@(#)cbc.c,v 1.2 1994/02/01 00:34:36 alm Exp";
#endif /* not lint */
#include <sys/types.h>
diff --git a/bin/ed/ed.h b/bin/ed/ed.h
index 1f61428eb73a..dd638806c470 100644
--- a/bin/ed/ed.h
+++ b/bin/ed/ed.h
@@ -24,14 +24,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)$Id: ed.h,v 1.5 1994/02/01 00:34:39 alm Exp $
+ * @(#)ed.h,v 1.5 1994/02/01 00:34:39 alm Exp
*/
+#include <sys/types.h>
#if defined(BSD) && BSD >= 199103 || defined(__386BSD__)
# include <sys/param.h> /* for MAXPATHLEN */
#endif
#include <errno.h>
-#ifdef sun
+#if defined(sun) || defined(__NetBSD__)
# include <limits.h>
#endif
#include <regex.h>
@@ -166,17 +167,15 @@ if ((i) > (n)) { \
/* REQUE: link pred before succ */
#define REQUE(pred, succ) (pred)->q_forw = (succ), (succ)->q_back = (pred)
-#ifdef NEED_INSQUE
-/* insque: insert elem in circular queue after pred */
-#define insque(elem, pred) \
+/* INSQUE: insert elem in circular queue after pred */
+#define INSQUE(elem, pred) \
{ \
REQUE((elem), (pred)->q_forw); \
REQUE((pred), elem); \
}
-/* remque: remove_lines elem from circular queue */
-#define remque(elem) REQUE((elem)->q_back, (elem)->q_forw);
-#endif /* NEED_INSQUE */
+/* REMQUE: remove_lines elem from circular queue */
+#define REMQUE(elem) REQUE((elem)->q_back, (elem)->q_forw);
/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */
#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n')
@@ -184,7 +183,7 @@ if ((i) > (n)) { \
/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
-#ifndef strerror
+#ifdef sun
# define strerror(n) sys_errlist[n]
#endif
diff --git a/bin/ed/glbl.c b/bin/ed/glbl.c
new file mode 100644
index 000000000000..1e21d99d2876
--- /dev/null
+++ b/bin/ed/glbl.c
@@ -0,0 +1,223 @@
+/* glob.c: This file contains the global command routines for the ed line
+ editor */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef lint
+static char *rcsid = "@(#)glob.c,v 1.1 1994/02/01 00:34:40 alm Exp";
+#endif /* not lint */
+
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+
+#include "ed.h"
+
+
+/* build_active_list: add line matching a pattern to the global-active list */
+int
+build_active_list(isgcmd)
+ int isgcmd;
+{
+ pattern_t *pat;
+ line_t *lp;
+ long n;
+ char *s;
+ char delimiter;
+
+ if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
+ sprintf(errmsg, "invalid pattern delimiter");
+ return ERR;
+ } else if ((pat = get_compiled_pattern()) == NULL)
+ return ERR;
+ else if (*ibufp == delimiter)
+ ibufp++;
+ clear_active_list();
+ lp = get_addressed_line_node(first_addr);
+ for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
+ if ((s = get_sbuf_line(lp)) == NULL)
+ return ERR;
+ if (isbinary)
+ NUL_TO_NEWLINE(s, lp->len);
+ if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
+ set_active_node(lp) < 0)
+ return ERR;
+ }
+ return 0;
+}
+
+
+/* exec_global: apply command list in the command buffer to the active
+ lines in a range; return command status */
+long
+exec_global(interact, gflag)
+ int interact;
+ int gflag;
+{
+ static char *ocmd = NULL;
+ static int ocmdsz = 0;
+
+ line_t *lp = NULL;
+ int status;
+ int n;
+ char *cmd = NULL;
+
+#ifdef BACKWARDS
+ if (!interact)
+ if (!strcmp(ibufp, "\n"))
+ cmd = "p\n"; /* null cmd-list == `p' */
+ else if ((cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+#else
+ if (!interact && (cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+#endif
+ clear_undo_stack();
+ while ((lp = next_active_node()) != NULL) {
+ if ((current_addr = get_line_node_addr(lp)) < 0)
+ return ERR;
+ if (interact) {
+ /* print current_addr; get a command in global syntax */
+ if (display_lines(current_addr, current_addr, gflag) < 0)
+ return ERR;
+ while ((n = get_tty_line()) > 0 &&
+ ibuf[n - 1] != '\n')
+ clearerr(stdin);
+ if (n < 0)
+ return ERR;
+ else if (n == 0) {
+ sprintf(errmsg, "unexpected end-of-file");
+ return ERR;
+ } else if (n == 1 && !strcmp(ibuf, "\n"))
+ continue;
+ else if (n == 2 && !strcmp(ibuf, "&\n")) {
+ if (cmd == NULL) {
+ sprintf(errmsg, "no previous command");
+ return ERR;
+ } else cmd = ocmd;
+ } else if ((cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+ else {
+ REALLOC(ocmd, ocmdsz, n + 1, ERR);
+ memcpy(ocmd, cmd, n + 1);
+ cmd = ocmd;
+ }
+
+ }
+ ibufp = cmd;
+ for (; *ibufp;)
+ if ((status = extract_addr_range()) < 0 ||
+ (status = exec_command()) < 0 ||
+ status > 0 && (status = display_lines(
+ current_addr, current_addr, status)) < 0)
+ return status;
+ }
+ return 0;
+}
+
+
+line_t **active_list; /* list of lines active in a global command */
+long active_last; /* index of last active line in active_list */
+long active_size; /* size of active_list */
+long active_ptr; /* active_list index (non-decreasing) */
+long active_ndx; /* active_list index (modulo active_last) */
+
+/* set_active_node: add a line node to the global-active list */
+int
+set_active_node(lp)
+ line_t *lp;
+{
+ if (active_last + 1 > active_size) {
+ int ti = active_size;
+ line_t **ts;
+ SPL1();
+#if defined(sun) || defined(NO_REALLOC_NULL)
+ if (active_list != NULL) {
+#endif
+ if ((ts = (line_t **) realloc(active_list,
+ (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ sprintf(errmsg, "out of memory");
+ SPL0();
+ return ERR;
+ }
+#if defined(sun) || defined(NO_REALLOC_NULL)
+ } else {
+ if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
+ sizeof(line_t **))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ sprintf(errmsg, "out of memory");
+ SPL0();
+ return ERR;
+ }
+ }
+#endif
+ active_size = ti;
+ active_list = ts;
+ SPL0();
+ }
+ active_list[active_last++] = lp;
+ return 0;
+}
+
+
+/* unset_active_nodes: remove a range of lines from the global-active list */
+void
+unset_active_nodes(np, mp)
+ line_t *np, *mp;
+{
+ line_t *lp;
+ long i;
+
+ for (lp = np; lp != mp; lp = lp->q_forw)
+ for (i = 0; i < active_last; i++)
+ if (active_list[active_ndx] == lp) {
+ active_list[active_ndx] = NULL;
+ active_ndx = INC_MOD(active_ndx, active_last - 1);
+ break;
+ } else active_ndx = INC_MOD(active_ndx, active_last - 1);
+}
+
+
+/* next_active_node: return the next global-active line node */
+line_t *
+next_active_node()
+{
+ while (active_ptr < active_last && active_list[active_ptr] == NULL)
+ active_ptr++;
+ return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
+}
+
+
+/* clear_active_list: clear the global-active list */
+void
+clear_active_list()
+{
+ SPL1();
+ active_size = active_last = active_ptr = active_ndx = 0;
+ free(active_list);
+ active_list = NULL;
+ SPL0();
+}
diff --git a/bin/ed/glob.c b/bin/ed/glob.c
deleted file mode 100644
index 5c77d224cdff..000000000000
--- a/bin/ed/glob.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* glob.c: This file contains the global command routines for the ed line
- editor */
-/*-
- * Copyright (c) 1993 Andrew Moore, Talke Studio.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#ifndef lint
-static char *rcsid = "@(#)$Id: glob.c,v 1.1 1994/02/01 00:34:40 alm Exp $";
-#endif /* not lint */
-
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include "ed.h"
-
-
-/* build_active_list: add line matching a pattern to the global-active list */
-int
-build_active_list(isgcmd)
- int isgcmd;
-{
- pattern_t *pat;
- line_t *lp;
- long n;
- char *s;
- char delimiter;
-
- if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
- sprintf(errmsg, "invalid pattern delimiter");
- return ERR;
- } else if ((pat = get_compiled_pattern()) == NULL)
- return ERR;
- else if (*ibufp == delimiter)
- ibufp++;
- clear_active_list();
- lp = get_addressed_line_node(first_addr);
- for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
- if ((s = get_sbuf_line(lp)) == NULL)
- return ERR;
- if (isbinary)
- NUL_TO_NEWLINE(s, lp->len);
- if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
- set_active_node(lp) < 0)
- return ERR;
- }
- return 0;
-}
-
-
-/* exec_global: apply command list in the command buffer to the active
- lines in a range; return command status */
-long
-exec_global(interact, gflag)
- int interact;
- int gflag;
-{
- static char *ocmd = NULL;
- static int ocmdsz = 0;
-
- line_t *lp = NULL;
- int status;
- int n;
- char *cmd = NULL;
-
-#ifdef BACKWARDS
- if (!interact)
- if (!strcmp(ibufp, "\n"))
- cmd = "p\n"; /* null cmd-list == `p' */
- else if ((cmd = get_extended_line(&n, 0)) == NULL)
- return ERR;
-#else
- if (!interact && (cmd = get_extended_line(&n, 0)) == NULL)
- return ERR;
-#endif
- clear_undo_stack();
- while ((lp = next_active_node()) != NULL) {
- if ((current_addr = get_line_node_addr(lp)) < 0)
- return ERR;
- if (interact) {
- /* print current_addr; get a command in global syntax */
- if (display_lines(current_addr, current_addr, gflag) < 0)
- return ERR;
- while ((n = get_tty_line()) > 0 &&
- ibuf[n - 1] != '\n')
- clearerr(stdin);
- if (n < 0)
- return ERR;
- else if (n == 0) {
- sprintf(errmsg, "unexpected end-of-file");
- return ERR;
- } else if (n == 1 && !strcmp(ibuf, "\n"))
- continue;
- else if (n == 2 && !strcmp(ibuf, "&\n")) {
- if (cmd == NULL) {
- sprintf(errmsg, "no previous command");
- return ERR;
- } else cmd = ocmd;
- } else if ((cmd = get_extended_line(&n, 0)) == NULL)
- return ERR;
- else {
- REALLOC(ocmd, ocmdsz, n + 1, ERR);
- memcpy(ocmd, cmd, n + 1);
- cmd = ocmd;
- }
-
- }
- ibufp = cmd;
- for (; *ibufp;)
- if ((status = extract_addr_range()) < 0 ||
- (status = exec_command()) < 0 ||
- status > 0 && (status = display_lines(
- current_addr, current_addr, status)) < 0)
- return status;
- }
- return 0;
-}
-
-
-line_t **active_list; /* list of lines active in a global command */
-long active_last; /* index of last active line in active_list */
-long active_size; /* size of active_list */
-long active_ptr; /* active_list index (non-decreasing) */
-long active_ndx; /* active_list index (modulo active_last) */
-
-/* set_active_node: add a line node to the global-active list */
-int
-set_active_node(lp)
- line_t *lp;
-{
- if (active_last + 1 > active_size) {
- int ti = active_size;
- line_t **ts;
- SPL1();
-#if defined(sun) || defined(NO_REALLOC_NULL)
- if (active_list != NULL) {
-#endif
- if ((ts = (line_t **) realloc(active_list,
- (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
- fprintf(stderr, "%s\n", strerror(errno));
- sprintf(errmsg, "out of memory");
- SPL0();
- return ERR;
- }
-#if defined(sun) || defined(NO_REALLOC_NULL)
- } else {
- if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
- sizeof(line_t **))) == NULL) {
- fprintf(stderr, "%s\n", strerror(errno));
- sprintf(errmsg, "out of memory");
- SPL0();
- return ERR;
- }
- }
-#endif
- active_size = ti;
- active_list = ts;
- SPL0();
- }
- active_list[active_last++] = lp;
- return 0;
-}
-
-
-/* unset_active_nodes: remove a range of lines from the global-active list */
-void
-unset_active_nodes(np, mp)
- line_t *np, *mp;
-{
- line_t *lp;
- long i;
-
- for (lp = np; lp != mp; lp = lp->q_forw)
- for (i = 0; i < active_last; i++)
- if (active_list[active_ndx] == lp) {
- active_list[active_ndx] = NULL;
- active_ndx = INC_MOD(active_ndx, active_last - 1);
- break;
- } else active_ndx = INC_MOD(active_ndx, active_last - 1);
-}
-
-
-/* next_active_node: return the next global-active line node */
-line_t *
-next_active_node()
-{
- while (active_ptr < active_last && active_list[active_ptr] == NULL)
- active_ptr++;
- return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
-}
-
-
-/* clear_active_list: clear the global-active list */
-void
-clear_active_list()
-{
- SPL1();
- active_size = active_last = active_ptr = active_ndx = 0;
- free(active_list);
- active_list = NULL;
- SPL0();
-}
diff --git a/bin/ed/io.c b/bin/ed/io.c
index 0c63f3dc77fb..2187cb999415 100644
--- a/bin/ed/io.c
+++ b/bin/ed/io.c
@@ -26,7 +26,7 @@
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: io.c,v 1.1 1994/02/01 00:34:41 alm Exp $";
+static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
#endif /* not lint */
#include "ed.h"
diff --git a/bin/ed/main.c b/bin/ed/main.c
index ddaf513f4337..f177b86ecd9d 100644
--- a/bin/ed/main.c
+++ b/bin/ed/main.c
@@ -33,7 +33,7 @@ char *copyright =
#endif /* not lint */
#ifndef lint
-static char *rcsid = "@(#)$Id: main.c,v 1.1 1994/02/01 00:34:42 alm Exp $";
+static char *rcsid = "@(#)main.c,v 1.1 1994/02/01 00:34:42 alm Exp";
#endif /* not lint */
/*
diff --git a/bin/ed/re.c b/bin/ed/re.c
index f4b9f292944b..0e04dd83dd9f 100644
--- a/bin/ed/re.c
+++ b/bin/ed/re.c
@@ -27,7 +27,7 @@
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: re.c,v 1.6 1994/02/01 00:34:43 alm Exp $";
+static char *rcsid = "@(#)re.c,v 1.6 1994/02/01 00:34:43 alm Exp";
#endif /* not lint */
#include "ed.h"
diff --git a/bin/ed/sub.c b/bin/ed/sub.c
index c93d258c8cd2..9d46a7ca3d2e 100644
--- a/bin/ed/sub.c
+++ b/bin/ed/sub.c
@@ -27,7 +27,7 @@
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: sub.c,v 1.1 1994/02/01 00:34:44 alm Exp $";
+static char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
#endif /* not lint */
#include "ed.h"
diff --git a/bin/ed/undo.c b/bin/ed/undo.c
index a12e1c48e753..a686d14c1b36 100644
--- a/bin/ed/undo.c
+++ b/bin/ed/undo.c
@@ -26,7 +26,7 @@
*/
#ifndef lint
-static char *rcsid = "@(#)$Id: undo.c,v 1.1 1994/02/01 00:34:44 alm Exp $";
+static char *rcsid = "@(#)undo.c,v 1.1 1994/02/01 00:34:44 alm Exp";
#endif /* not lint */
#include "ed.h"
diff --git a/bin/expr/expr.1 b/bin/expr/expr.1
index 3cfa19b8f589..e6af35a40b17 100644
--- a/bin/expr/expr.1
+++ b/bin/expr/expr.1
@@ -28,7 +28,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $Id: expr.1,v 1.2.2.1 1994/05/01 15:59:55 jkh Exp $
+.\" $Id: expr.1,v 1.3 1994/04/24 01:18:46 jkh Exp $
.\"
.Dd July 3, 1993
.Dt EXPR 1
diff --git a/bin/ls/ls.1 b/bin/ls/ls.1
index 1363d00f80ae..cfcd293a6474 100644
--- a/bin/ls/ls.1
+++ b/bin/ls/ls.1
@@ -34,7 +34,7 @@
.\"
.\" @(#)ls.1 6.18 (Berkeley) 6/27/91
.\"
-.\" $Header: /home/cvs/386BSD/src/bin/ls/ls.1,v 1.2.2.1 1994/05/01 16:00:04 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/bin/ls/ls.1,v 1.3 1994/04/24 01:18:52 jkh Exp $
.\"
.Dd June 27, 1991
.Dt LS 1
diff --git a/bin/mkdir/mkdir.1 b/bin/mkdir/mkdir.1
index d8d598e4b4d2..85d2387fddcc 100644
--- a/bin/mkdir/mkdir.1
+++ b/bin/mkdir/mkdir.1
@@ -34,7 +34,7 @@
.\"
.\" @(#)mkdir.1 6.9 (Berkeley) 6/27/91
.\"
-.\" $Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.1,v 1.2.2.1 1994/05/01 16:00:13 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.1,v 1.2 1993/07/21 22:54:08 conklin Exp $
.\"
.Dd June 27, 1991
.Dt MKDIR 1
diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c
index b4ec95857c9e..4f59865a8e94 100644
--- a/bin/mkdir/mkdir.c
+++ b/bin/mkdir/mkdir.c
@@ -39,7 +39,7 @@ char copyright[] =
#ifndef lint
static char sccsid[] = "@(#)mkdir.c 5.7 (Berkeley) 5/31/90";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.c,v 1.2 1993/07/21 22:54:09 conklin Exp $";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.c,v 1.3 1994/05/23 01:15:19 ache Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -118,7 +118,7 @@ build(path, mode, dir_mode)
int ch;
for (p = path;; ++p) {
- if (!*p || *p == '/') {
+ if (!*p || *p == '/' && p != path) {
ch = *p;
*p = '\0';
if (stat(path, &sb)) {
diff --git a/bin/mv/mv.c b/bin/mv/mv.c
index aa37d0229f72..8fa66bb78f17 100644
--- a/bin/mv/mv.c
+++ b/bin/mv/mv.c
@@ -42,7 +42,7 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)mv.c 5.11 (Berkeley) 4/3/91";*/
-static char rcsid[] = "$Id: mv.c,v 1.2 1993/11/22 23:54:24 jtc Exp $";
+static char rcsid[] = "$Id: mv.c,v 1.3 1994/04/16 00:51:13 davidg Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -229,7 +229,7 @@ fastcopy(from, to, sbp)
(void)close(from_fd);
return(1);
}
- if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
+ if (!blen && !(bp = malloc(blen = sbp->st_blksize * 4))) {
error(NULL);
return(1);
}
diff --git a/bin/rcp/Makefile b/bin/rcp/Makefile
index e8cac815eb55..aea1fdd7ba92 100644
--- a/bin/rcp/Makefile
+++ b/bin/rcp/Makefile
@@ -1,15 +1,15 @@
# @(#)Makefile 5.4 (Berkeley) 10/21/90
PROG= rcp
-SRCS= rcp.c
+SRCS= rcp.c krcmd.c kcmd.c
BINOWN= root
BINMODE=4555
.PATH: ${.CURDIR}/../../usr.bin/rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-#DPADD+= ${LIBCRYPT} ${LIBKRB}
-#LDADD+= -lcrypt -lkrb
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+CFLAGS+=-DCRYPT -DKERBEROS
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
.endif
.include <bsd.prog.mk>
diff --git a/bin/rm/rm.c b/bin/rm/rm.c
index 45d74488b7fd..d0cf0d2b7bfd 100644
--- a/bin/rm/rm.c
+++ b/bin/rm/rm.c
@@ -39,7 +39,7 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)rm.c 4.26 (Berkeley) 3/10/91";*/
-static char rcsid[] = "$Id: rm.c,v 1.6.2.1 1994/03/07 02:25:28 rgrimes Exp $";
+static char rcsid[] = "$Id: rm.c,v 1.7 1994/03/05 16:12:06 ats Exp $";
#endif /* not lint */
#include <stdio.h>
diff --git a/bin/rmail/rmail.c b/bin/rmail/rmail.c
index 40e16887d7c9..7672cbfc44c1 100644
--- a/bin/rmail/rmail.c
+++ b/bin/rmail/rmail.c
@@ -163,7 +163,6 @@ main(argc, argv)
i = 0;
args[i++] = _PATH_SENDMAIL;
args[i++] = "-oee"; /* no errors, just status */
- args[i++] = "-odq"; /* queue it, don't try to deliver */
args[i++] = "-oi"; /* ignore '.' on a line by itself */
if (fsys[0] != '\0') { /* set sender's host name */
static char junk2[512];
diff --git a/bin/rmdir/rmdir.c b/bin/rmdir/rmdir.c
index b67393827094..b39e4e45e82d 100644
--- a/bin/rmdir/rmdir.c
+++ b/bin/rmdir/rmdir.c
@@ -39,7 +39,7 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)rmdir.c 5.3 (Berkeley) 5/31/90";*/
-static char rcsid[] = "$Id: rmdir.c,v 1.3 1993/11/23 00:13:55 jtc Exp $";
+static char rcsid[] = "$Id: rmdir.c,v 1.4 1994/05/23 01:41:06 ache Exp $";
#endif /* not lint */
/*
@@ -117,6 +117,8 @@ rmdirp (path)
/* skip trailing slash characters */
while (slash > path && *slash == '/')
slash--;
+ if (*slash == '/') /* don't attempt to remove root */
+ return 0;
*++slash = '\0';
if (rmdir (path)) {
diff --git a/bin/sh/builtins b/bin/sh/builtins
index b605bd890533..a08020a82430 100644
--- a/bin/sh/builtins
+++ b/bin/sh/builtins
@@ -50,7 +50,7 @@
# This file is part of ash, which is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
-bltincmd command
+bltincmd bltin
#alloccmd alloc
bgcmd -j bg
breakcmd break continue
diff --git a/bin/sh/cd.c b/bin/sh/cd.c
index e458c1f0ae20..615ac7a38fd2 100644
--- a/bin/sh/cd.c
+++ b/bin/sh/cd.c
@@ -217,7 +217,7 @@ top:
STPUTC('\0', p);
p = grabstackstr(p);
INTOFF;
- if (chdir(p) < 0) {
+ if (chdir(*p ? p : ".") < 0) {
INTON;
return -1;
}
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index 95d2e504cd70..c350eae3ee7f 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -403,7 +403,7 @@ again: /* jump here after setting a variable with ${var=text} */
if ((c = *p++) == CTLESC)
p++;
else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
- if (set)
+ if (set && argbackq)
argbackq = argbackq->next;
} else if (c == CTLVAR) {
if ((*p++ & VSTYPE) != VSNORMAL)
@@ -664,10 +664,10 @@ expandmeta(str)
savelastp = exparg.lastp;
INTOFF;
if (expdir == NULL)
- expdir = ckmalloc(8192); /* I hope this is big enough */
+ expdir = ckmalloc(16384); /* I hope this is big enough */
expmeta(expdir, str->text);
- if(strlen(expdir) >= 8192)
- error("malloc overflow in sh:expand.c in ckmalloc(8192)\n");
+ if(strlen(expdir) >= 16384)
+ error("malloc overflow in sh:expand.c in ckmalloc(16384)\n");
ckfree(expdir);
expdir = NULL;
INTON;
diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c
index b14da674a166..3384cd5c8341 100644
--- a/bin/sh/miscbltin.c
+++ b/bin/sh/miscbltin.c
@@ -89,8 +89,8 @@ readcmd(argc, argv) char **argv; {
out2str(prompt);
flushall();
}
- if ((ap = argptr) == NULL)
- error("arg count");
+ if (*(ap = argptr) == NULL)
+ error("bad argument/arg count");
if ((ifs = bltinlookup("IFS", 1)) == NULL)
ifs = nullstr;
status = 0;
diff --git a/bin/stty/cchar.c b/bin/stty/cchar.c
index b8e6206cfa59..c105f96c2081 100644
--- a/bin/stty/cchar.c
+++ b/bin/stty/cchar.c
@@ -60,12 +60,14 @@ struct cchar cchars1[] = {
"intr", VINTR, CINTR,
"kill", VKILL, CKILL,
"lnext", VLNEXT, CLNEXT,
+ "min", VMIN, CMIN,
"quit", VQUIT, CQUIT,
"reprint", VREPRINT, CREPRINT,
"start", VSTART, CSTART,
"status", VSTATUS, CSTATUS,
"stop", VSTOP, CSTOP,
"susp", VSUSP, CSUSP,
+ "time", VTIME, CTIME,
"werase", VWERASE, CWERASE,
NULL,
};
@@ -95,8 +97,8 @@ csearch(argvp, ip)
tmp.name = name;
if (!(cp = (struct cchar *)bsearch(&tmp, cchars1,
sizeof(cchars1)/sizeof(struct cchar) - 1, sizeof(struct cchar),
- c_cchar)) && !(cp = (struct cchar *)bsearch(&tmp, cchars1,
- sizeof(cchars1)/sizeof(struct cchar) - 1, sizeof(struct cchar),
+ c_cchar)) && !(cp = (struct cchar *)bsearch(&tmp, cchars2,
+ sizeof(cchars2)/sizeof(struct cchar) - 1, sizeof(struct cchar),
c_cchar)))
return(0);
@@ -109,10 +111,6 @@ csearch(argvp, ip)
ip->t.c_cc[cp->sub] = _POSIX_VDISABLE;
else if (cp->sub == VMIN || cp->sub == VTIME) {
val = strtol(arg, &ep, 10);
- if (val == _POSIX_VDISABLE) {
- warnx("value of %ld would disable the option -- %s",
- val, name);
- }
if (val > UCHAR_MAX) {
warnx("maximum option value is %d -- %s",
UCHAR_MAX, name);
diff --git a/bin/stty/gfmt.c b/bin/stty/gfmt.c
index d909131ee32c..97021bb31ba3 100644
--- a/bin/stty/gfmt.c
+++ b/bin/stty/gfmt.c
@@ -163,12 +163,12 @@ gread(tp, s)
tp->c_cc[VSUSP] = tmp;
continue;
}
- if (CHK("vmin")) {
+ if (CHK("min")) {
(void)sscanf(ep, "%ld", &tmp);
tp->c_cc[VMIN] = tmp;
continue;
}
- if (CHK("vtime")) {
+ if (CHK("time")) {
(void)sscanf(ep, "%ld", &tmp);
tp->c_cc[VTIME] = tmp;
continue;
diff --git a/bin/stty/key.c b/bin/stty/key.c
index 6a7aeca935e2..1f7114864058 100644
--- a/bin/stty/key.c
+++ b/bin/stty/key.c
@@ -276,6 +276,6 @@ f_tty(ip)
int tmp;
tmp = TTYDISC;
- if (ioctl(0, TIOCSETD, &tmp) < 0)
+ if (ioctl(ip->fd, TIOCSETD, &tmp) < 0)
err("TIOCSETD: %s", strerror(errno));
}
diff --git a/bin/stty/print.c b/bin/stty/print.c
index a3ef040efbec..fdd2f72c406d 100644
--- a/bin/stty/print.c
+++ b/bin/stty/print.c
@@ -74,6 +74,9 @@ print(tp, wp, ldisc, fmt)
case NTTYDISC:
cnt += printf("new tty disc; ");
break;
+ case PPPDISC:
+ cnt += printf("ppp disc; ");
+ break;
default:
cnt += printf("#%d disc; ", ldisc);
break;
@@ -250,13 +253,14 @@ ccval(p, c)
static char buf[5];
char *bp;
- if (c == _POSIX_VDISABLE)
- return("<undef>");
-
if (p->sub == VMIN || p->sub == VTIME) {
(void)snprintf(buf, sizeof(buf), "%d", c);
return (buf);
}
+
+ if (c == _POSIX_VDISABLE)
+ return("<undef>");
+
bp = buf;
if (c & 0200) {
*bp++ = 'M';
diff --git a/contrib/FAQ/FreeBSD.FAQ b/contrib/FAQ/FreeBSD.FAQ
new file mode 100644
index 000000000000..9ea99a15613f
--- /dev/null
+++ b/contrib/FAQ/FreeBSD.FAQ
@@ -0,0 +1,954 @@
+
+ FreeBSD
+ Frequently Asked Questions
+ For Versions 1.1 and above
+
+Please mail all suggestions and additions to <FreeBSD-FAQ@freefall.cdrom.com>
+
+
+Revision: $Id: FreeBSD.FAQ,v 1.36 1994/06/28 15:33:58 jkh Exp $
+
+All entries are assumed to be relevant to both FreeBSD 1.1 and FreeBSD 1.1.5,
+unless otherwise noted.
+
+
+Table of Contents
+-----------------
+
+0 Preface
+1 Installation
+2 Hardware Compatibility
+3 Commercial applications
+4 User Applications
+5 Miscellaneous Questions
+6 Kernel Configuration
+7 System Administration
+8 Networking
+9 Serial Communications
+
+
+
+0 Preface
+---------
+
+Welcome to the FreeBSD 1.1 FAQ! This document tries to answer some of
+the most frequently asked questions about FreeBSD 1.1 (or later,
+unless specifically indicated). If there's something you're having
+trouble with and you just don't see it here, then please send mail to:
+
+ <FreeBSD-questions@freefall.cdrom.com>
+
+
+Some of the instructions here will also refer to auxiliary utilities
+in the /usr/src/contrib/FAQ directory. CDROM purchasers and net folks
+who've grabbed the FreeBSD 1.1 `srcdist' will have these files. If
+you don't have the source distribution, then you can either grab the
+whole thing from:
+
+ FreeBSD.cdrom.com:pub/FreeBSD/FreeBSD-1.1
+
+Or you can grab only those files you're interested in straight out of
+the FreeBSD-current distribution in:
+
+ FreeBSD.cdrom.com:pub/FreeBSD/FreeBSD-current/src
+
+0.1: What is FreeBSD?
+
+FreeBSD is a UN*X type operating system based on William Jolitz's port
+of U.C. Berkeley's Networking Release 2 to the i386, 386BSD. It is no
+longer correct to say that FreeBSD is only 386BSD with the patchkit
+applied! There have been many additions and bug fixes made throughout
+the entire system, some of the highlights of which are:
+
+ More robust and extensive PC device support
+ System V-style IPC, messaging and semaphores
+ Shared Libraries
+ Much improved virtual memory code
+ Better console driver support
+ Network booting (diskless) support
+ /proc filesystem
+ Yellow Pages support
+ `LDT' support for WINE (primitive but developing Windows emulation)
+ Too many additional utilities and applications to mention
+
+
+0.2: My friends told me that FreeBSD was illegal and I shouldn't use it.
+ Is this really true?
+
+FreeBSD versions up to and including 1.1 have included code from
+Berkeley's Net/2 distribution. UNIX Systems Laboratories (now Novell)
+sued Berkeley claiming that Net/2 included some code that belonged to
+USL. In February of 1994, USL and Berkeley announced a settlement in
+which neither side admitted to doing anything wrong, but UCB agreed to
+stop distributing the disputed software.
+
+Since Berkeley will no longer defend this code, we have been requested
+to stop distributing it, and will be integrating all the improvements
+we have made in the VM system and i386-specific code into Berkeley's
+4.4-Lite distribution; the result will form the basis of FreeBSD 2.0.
+We expect the integration to take place over a period of three to six
+months, during which time we will have to stop work on 1.1 and
+concentrate all our efforts on the merge, and we expect to make more
+information available on the status of the merge effort as the situation
+progresses.
+
+However, to answer the question, "No. FreeBSD is not illegal." We
+have been allowed by USL to distribute 1.1 as the last Net/2 derived
+version, after which we have committed to move to 4.4 as previously
+stated.
+
+We expect to make more information available on the status of the
+merge effort as the situation progresses.
+
+0.3: What are the FreeBSD mailing lists, and how can I get on them?
+
+The following mailing lists are provided for FreeBSD users and
+developers. For more information, send to
+<majordomo@freefall.cdrom.com> and include a single line saying
+``help'' in the body of your message.
+
+FreeBSD-announce: For announcements about or on FreeBSD.
+FreeBSD-hackers: Useful for persons wishing to work on the internals.
+FreeBSD-questions: General questions on FreeBSD.
+FreeBSD-bugs: Where bugs should be sent.
+FreeBSD-commit: This list carries the commit messages for freefall. Useful
+ for tracking ongoing work.
+FreeBSD-SCSI: Mailing list for SCSI developers.
+FreeBSD-current: This list is for persons wishing to run FreeBSD-current
+ and carries announcements and discussions on current.
+
+Please see also the FreeBSD mailing list FAQ in:
+
+ /usr/src/contrib/FAQ/OTHER-FAQS/FreeBSD.mailing-list.FAQ
+
+0.4: What are the various FreeBSD news groups?
+
+While there are no groups currently dedicated to FreeBSD, you may find
+the following groups useful.
+
+comp.os.386bsd.announce: For announcements
+comp.os.386bsd.apps: For applications
+comp.os.386bsd.questions: For questions
+comp.os.386bsd.development: For working on the internals
+comp.os.386bsd.bugs: About bugs
+comp.os.386bsd.misc: For items that don't fit anywhere else
+
+NOTE: These groups cover all the *BSDs (FreeBSD, NetBSD, 386BSD).
+
+
+
+1 Installation
+--------------
+
+1.1: I just installed my system and rebooted. Now I can't find the
+ extract or configure programs, where did they go?
+
+These two commands are just shell functions defined in /.profile. To
+get these back, boot FreeBSD with a `-s' at the boot prompt.
+
+
+1.2: I want to install FreeBSD onto a SCSI disk that has more than
+ 1024 cylinders. How do I do it?
+
+This depends. If you don't have DOS (or another operating system) on
+the system, you can just keep the drive in native mode and simply make
+sure that your root partition is below 1024 so the BIOS can boot the
+kernel from it. It you also have DOS/some other OS on the drive then
+your best bet is to find out what parameters that it thinks you have
+before installing FreeBSD. When FreeBSD's installation procedure
+prompts you for these values, you should then enter them rather than
+simply going with the defaults.
+
+There is a freely available utility distributed with FreeBSD called
+`pfdisk' (located in the tools/ subdirectory) which can be used for
+this purpose.
+
+
+1.3: When I boot FreeBSD it says ``Missing Operating System''.
+
+See question 1.2. This is classically a case of FreeBSD and DOS or
+some other OS conflicting over their ideas of disk geometry. You will
+have to reinstall FreeBSD, but obeying the instructions given above
+will almost always get you going.
+
+
+1.4: I have an IDE drive with lots of bad blocks on it and FreeBSD doesn't
+ seem to install properly.
+
+FreeBSD's bad block (bad144) handling is still not 100% (to put it
+charitably) and it must unfortunately be said that if you've got an
+IDE or ESDI drive with lots of bad blocks, then FreeBSD is probably
+not for you! That said, it does work on thousands of IDE based
+systems, so you'd do well to try it first before simply giving up.
+
+IDE drives are *supposed* to come with built-in bad-block remapping;
+if you have documentation for your drive, you may want to see if this
+feature has been disabled on your drive. However, ESDI, RLL, and
+ST-506 drives normally do not do this.
+
+<1.1.5>
+FreeBSD-current has better bad block handling due to improvments made
+to the wd driver.
+
+1.5: I have 32MB of memory, should I expect any special problems?
+
+If you have an IDE controller, no. Likewise, if you have a full EISA
+system with EISA disk controller or a working local bus controller
+(read further) you'll have no problems. If you have an ISA system, or
+an EISA system with an ISA disk controller then you will most
+certainly have problems with the upper 16MB of memory due to the ISA
+24 bit DMA limitation (which ISA cards in EISA systems will also
+exhibit). If you have a local bus disk controller, then you should be
+OK, UNLESS it's a Buslogic Bt445S with a revision less than `D' (BIOS
+3.36 or earlier).
+
+<1.1.5>
+1.1.5 has bounce-buffer support that make all of the above scenarios work
+with a full 32MB of memory or more. You are therefore advised to simply pull
+16MB of memory out, install, and then see about upgrading to FreeBSD 1.1.5
+so that you can put it back.
+
+
+1.6: Do I need to install the complete sources?
+
+In general, no. However, we would strongly recommend that you
+install, at a minimum, the `base' source kit, which includes several
+of the files mentioned here, and the `sys' (kernel) source kit, which
+includes sources for the kernel. There is nothing in the system which
+requires the presence of the sources to operate, however, except for
+the kernel-configuration program config(8). With the exception of the
+kernel sources, our build structure is set up so that you can
+read-only mount the sources from elsewhere via NFS and still be able
+to make new binaries. (Because of the kernel-source restriction, we
+recommend that you not mount this on /usr/src directly, but rather in
+some other location with appropriate symbolic links to duplicate the
+top-level structure of the source tree.)
+
+Having the sources on-line and knowing how to build a system with them
+will make it much easier for you to upgrade to future releases of
+FreeBSD.
+
+1.7: DES encryption software can not be exported from the United
+ States. If I live outside the US, how can I encrypt passwords?
+
+Since the DES encryption algorithm, which is used by passwd(1) and
+friends to encrypt passwords cannot legally be exported from the US,
+non-US users should not download this software from US FTP sites.
+
+There is however a replacement libcrypt available, based on sources
+written in Australia by David Burren. This code is now available on
+some non-US FreeBSD mirror sites. Sources for the unencumbered
+libcrypt, and binaries of the programs which use it, can be obtained
+from the following FTP sites:
+
+ South Africa: braae.ru.ac.za:/pub/FreeBSD/securedist/
+ owl.und.ac.za (currently uncertain)
+ Iceland: ftp.veda.is:/pub/crypt/FreeBSD/
+
+The non-US securedist can be used as a direct replacement for the
+encumbered US securedist. This securedist package is installed the
+same way as the US package (see installation notes for details). If
+you are going to install DES encryption, you should do so as soon as
+possible, before installing other software.
+
+Non-US users should please not download any encryption software from
+the USA. This can get the maintainers of the sites from which the
+software is downloaded into severe legal difficulties.
+
+A non-US distribution of Kerberos is also being developed, and current
+versions can generally be obtained by anonymous FTP from
+braae.ru.ac.za.
+
+There is also a mailing list for the discussion of non-US encryption
+software. For more information, send an email message with a single
+line saying ``help'' in the body of your message to
+<majordomo@braae.ru.ac.za>.
+
+1.8 HELP! My keyboard locked up during the install!
+
+Some keyboard controllers are not a friend to FreeBSD. Among these are
+those on certain models of Gateway, IBM and AST machines. The most frequent
+symptom encountered in such cases is that the keyboard refuses to respond
+to input when at the `kcopy>' prompt in the second phase of bootstrapping
+FreeBSD. Fortunately, there is a work-around that may get you all the
+way home. Reset the machine and boot the kcopy floppy again, but this
+time, as the kernel is booting, tap periodically on the num-lock key
+until the kcopy prompt appears. Your keyboard should respond properly.
+
+Once your system is on the hard disk the problem generally goes away.
+Some folks for whom the problem persists even after this stage find
+relief in switching to the SYSCONS console driver (see /sys/i386/conf/SYSCONS),
+which is in any case far more featureful than pccons and a recommended
+upgrade.
+
+
+
+2 Hardware compatibility
+------------------------
+
+2.1: What kind of hard drives does FreeBSD run on?
+
+FreeBSD supports ST-506 (sometimes called ``MFM''), RLL, and ESDI
+drives, which are usually connected to WD-1002, WD-1003, or WD-1006
+controllers (although clones should also work). FreeBSD also supports
+IDE and SCSI hard drives.
+
+2.2: What SCSI controllers are supported?
+
+FreeBSD supports the following SCSI controllers:
+
+Adaptec AH-1542 Series <ISA>
+ AH-1742 Series <EISA>
+Buslogic BT-445 Series <VLB> (but see section 1.5)
+ BT-545 Series <ISA>
+ BT-742 Series <EISA>
+ BT-747 Series <EISA>
+Future Domain TMC-8XX/950 Series <ISA> (1.1.5 ONLY)
+Seagate ST-01/02 Series <ISA> (1.1.5 ONLY)
+UltraStor UH-14f Series <ISA>
+ UH-34f Series <EISA/VLB>
+
+There is supposed to be a UltraStor 24f driver floating around, but
+we're not sure where (could someone please point us at it?).
+
+2.3: What CD-ROM drives are supported by FreeBSD?
+
+Any SCSI drive connected to a supported controller. Mitsumi
+LU002(8bit), LU005(16bit) and FX001D(16bit 2x Speed).
+
+FreeBSD does NOT support drives connected to a Sound Blaster or
+non-SCSI SONY or Panasonic drives. A general rule of thumb when
+selecting a CDROM drive for FreeBSD use is to buy a very standard SCSI
+model; they cost more, but deliver very solid performance in return.
+Do not be fooled by very cheap drives that, in turn, deliver VERY LOW
+performance! As always, you get what you pay for.
+
+The Mitsumi driver is known to be extremely slow compared to SCSI
+drives.
+
+
+2.4: What multi-port serial cards are supported by FreeBSD?
+
+AST/4 and BOCA 4/8/16 port cards. Some unnamed clone cards have also
+been known to work, especially those that claim to be AST compatible.
+Check the sio(4) man page to get more information on configuring such
+cards.
+
+
+2.5: Does FreeBSD support the AHA-2742 SCSI adapter from Adaptec?
+
+No, FreeBSD does not. This is due to Adaptec's unwillingness to
+supply programming information under other than non-disclosure. This
+is unfortunate, but there's nothing we can do about it.
+
+
+2.6: I have a Mumbleco bus mouse. Is it supported and if so, how do I set
+ it up for XFree86?
+
+FreeBSD supports the Logitech and ATI Inport bus mice. You need to
+add the following line to the kernel config file and recompile for the
+Logitech and ATI mice:
+
+ device mse0 at isa? port 0x23c tty irq6 vector mseintr
+
+
+2.7: I have a PS/2 mouse (`keyboard' mouse) [Alternatively: I have a
+ laptop with a track-ball mouse]. How do I use it?
+
+<1.1>: For the PS/2 mouse you need to look in
+/usr/src/contrib/FAQ/programs/psm, which is John Solhed's port of the
+Linux PS/2 mouse driver.
+
+Follow the directions in the package. You will also need to change
+your Xconfig file to point to the mouse.
+
+<1.1.5>: The PS/2 mouse is part of the system. See the psm0 driver
+description in /sys/doc/options.doc.
+
+
+2.8: What types of tape drives are supported under FreeBSD?
+
+FreeBSD supports SCSI, QIC-02 and QIC-40/80 (Floppy based) tape
+drives. This includes 8-mm (aka Exabyte) and DAT drives.
+
+
+2.9: What sound cards are supported by FreeBSD?
+
+FreeBSD supports the SoundBlaster, SoundBlaster Pro, Pro Audio
+Spectrum 16, AdLib and Gravis UltraSound sound cards. There is also
+limited support for MPU-401 and compatible MIDI cards. The
+SoundBlaster 16 and SoundBlaster 16 ASP cards are not yet supported.
+NOTE: This is only for sound! This driver does not support CD-ROMs,
+SCSI or joysticks on these cards.
+
+
+2.10: What network cards does FreeBSD support?
+
+There is support for the following cards:
+
+`ed' driver:
+ NE2000 and 1000
+ WD/SMC 8003, 8013 and Elite Ultra (8216)
+ 3Com 3c503
+ And clones of the above
+
+`ie' driver:
+ AT&T EN100/StarLAN 10
+
+`is' driver:
+ Isolan AT 4141-0
+ Isolink 4110
+
+`ep' driver:
+ 3com 3c509 (*)
+
+
+(*)The `ep' driver is known to have some problems; see the
+/usr/src/KNOWNBUGS file for more details.
+
+
+2.11: I have a 386/486sx/486SLC machine without a math co-processor.
+ Will this cause me any problems?
+
+Generally no, but there are circumstances where you will take a hit,
+either in performance or accuracy of the math emulation code (see
+section 4.1). In particular, drawing arcs in X will be VERY slow. It
+is highly recommended that you lay out the $50 or so for a math
+co-processor; it's well worth it. NOTE: Some math co-processors are
+better than others. It pains us to say it, but nobody ever got fired
+for buying Intel. Unless you're sure it works with FreeBSD, beware of
+clones.
+
+2.12: I am about to buy a new machine to run FreeBSD on and
+ want an idea of what other people are running. Is there list
+ of other systems anywhere?
+
+Yes. Please look at the file FAQ/OTHER-FAQS/Systems.FAQ. This file
+is a listing of hardware that people are running in their machines.
+Please note, this is a raw listing of equipment that other users
+have sent in.
+
+
+
+3 Commercial Applications
+-------------------------
+
+Note: This section is still very sparse, though we're hoping, of
+course, that companies will add to it! :) The FreeBSD group has no
+financial interest in any of the companies listed here but simply
+lists them as a public service (and feels that commercial interest in
+FreeBSD can have very positive effects on FreeBSD's long-term
+viability). We encourage commercial software vendors to send their
+entries here for inclusion.
+
+
+3.1: Where can I get Motif for FreeBSD?
+
+Sequoia International provides commercial quality Motif 1.2.3
+development kits for FreeBSD 1.1 (with full shared library support)
+under the product name of `SWiM'. Due to licensing restrictions from
+the OSF, and the fact that Sequoia needs to make a living, these are
+NOT FREE, but nonetheless quite reasonably priced in comparison to
+many other commercial Motif distributions. Send electronic mail to
+<info@seq.com> for further information.
+
+3.2: What about other commercial quality development systems for FreeBSD?
+
+ParcPlace Systems, Inc., who currently provides their excellent
+`Object Interface & Object Builder' GUI development environment free
+of charge to Linux users, is considering the the FreeBSD platform and
+will make their intentions known fairly shortly.
+
+
+
+4 User Applications
+-------------------
+
+4.1: I want to run X, how do I go about it?
+
+First, get the XFree86 distribution of X11R5 from XFree86.cdrom.com.
+The version you want for FreeBSD 1.1 and later is XFree86 2.1. Follow
+the instructions for installation carefully. You may then wish to read
+the documentation for the ConfigXF86 tool, which assists you in
+configuring XFree86 for your particular graphics card/mouse/etc.
+
+
+4.1: I've been trying to run ghostscript on a 386 (or 486sx) with no
+ math co-processor and I keep getting errors. What's up?
+
+<1.1>: The problem here is due to the current FreeBSD math-emulator. You
+need to pick up the sources to an alternate emulation package, which
+you may find in:
+
+ /usr/src/contrib/FAQ/programs/fpu-emu
+
+Follow the instructions supplied.
+
+This is a port of an older Linux math-emulator. At some point,
+FreeBSD's default math emulator will be good enough that you can
+forget about having to do this.
+
+<1.1.5>: For 1.1.5 you may add the following to your kernel config file and
+it will be compiled in.
+options GPL_MATH_EMULATE
+
+NOTE: You will need to remove the MATH_EMULATE option when you do this.
+
+
+4.2: If I want something like seyon, term, Kermit, emacs or any one of
+ hundreds of popular freeware utilities, is there a good place to
+ search through first?
+
+Yes, the FreeBSD `ports collection' was put together for just that
+purpose. It contains some of the most often requested languages,
+editors, mail and news reading programs, network software and many
+many megabytes of other types of useful goodies. CDROM people will
+probably have the ports collection already in /usr/ports, other folks
+can get at the latest snapshot of the entire collection in:
+
+ FreeBSD.cdrom.com:pub/FreeBSD/FreeBSD-current/ports
+
+Note that this FTP server permits getting entire directories as one
+(optionally gzipped or compressed) tar file. Read the FTP welcome
+banner carefully for details.
+
+
+4.3: I want all this neat software, but I haven't got the space or
+ CPU power to compile it all myself. Is there any way of getting
+ binaries?
+
+Yes. We support the concept of a `package', which is essentially a
+gzipped binary distribution with a little extra intelligence embedded
+in it for doing any custom installation work required. Packages can
+also be installed or deinstalled again easily without having to know
+the gory details. CDROM people will have a packages/ directory on
+their CD, others can get the currently available packages from:
+
+ FreeBSD.cdrom.com:pub/FreeBSD/packages-1.1
+
+Note that all ports may not be available as packages, and that new
+packages are constantly being added. It is always a good idea to
+check periodically to see which packages are available. A README file
+in the packages directory provides more details on the care and
+feeding of the package software, so no explicit details will be given
+here.
+
+4.4: I'm trying to get Perl to work properly, but I keep getting
+ errors about dbm failures when I test it. How can I fix this?
+
+The problem here is that the tests are written for an older version of
+the dbm code. There is nothing wrong with perl and the errors can
+be ignored.
+
+
+
+5 Miscellaneous Questions
+----------------
+
+5.1: I've heard of something called FreeBSD-current. How do I run it, and
+ where can I get more information?
+
+Read the file /usr/src/contrib/FAQ/OTHER-FAQS/FreeBSD.current.policy,
+it will tell you all you need to know.
+
+
+5.2: What is this thing called `sup', and how do I use it?
+
+SUP stands for Software Update Protocol, and was developed by CMU for
+keeping their development trees in sync. We use it to keep remote
+sites in sync with our central development sources.
+
+To use it, you need to have direct internet connectivity (not just
+mail or news). First, pick up the sup_bin.tgz package from:
+
+ FreeBSD.cdrom.com:pub/FreeBSD/packages
+
+Second, read the file /usr/src/contrib/FAQ/OTHER-FAQS/FreeBSD.sup.faq.
+
+This file describes how to setup sup on your machine. You may also
+want to look at /usr/src/contrib/FAQ/OTHER-FAQS/FreeBSD.*.supfile,
+which are a set of supfiles for supping from freefall.cdrom.com
+
+
+5.3: How do I create customized installation disks that I can give
+ out to other people at my site?
+
+The entire process of creating installation disks and source and
+binary archives is automated by various targets in
+/usr/src/etc/Makefile. The information there should be enough to get
+you started.
+
+5.4: How do I re-build my system without clobbering the existing
+ installed binaries?
+
+If you define the environment variable DESTDIR while running `make
+world' or `make install', the newly-created binaries will be deposited
+in a directory tree identical to the installed one, rooted at
+${DESTDIR}. Some random combination of shared libraries modifications
+and program rebuilds can cause this to fail in `make world', however.
+
+
+5.5: When my system booted, it told me that ``(bus speed defaulted)''.
+ What does that mean?
+
+The Adaptec 1542 SCSI host adapters allow the user to configure their
+bus access speed in software. Previous versions of the 1542 driver tried
+to determine the fastest usable speed and set the adapter to that. We
+found that this breaks some users' systems, so you now have to define
+the ``TUNE_1542''' kernel configuration option in order to have this
+take place. Using it on those systems where it works may make your
+disks run faster, but on those systems where it doesn't, your data could
+be corrupted.
+
+5.6: I would like to track changes to current and do not have net access.
+ Is there any way besides downloading the whole tree?
+
+Yes, Poul-Henning has set up a source tracking list. Please email
+majordomo@ref.tfs.com with a body of "get ctm-src-cur README" for
+futher information.
+
+5.7: How do I split up large binary files into smaller 240k files
+ like the distribution does?
+
+Newer BSD based systems have a "-b" option to split that allows them to
+split files on arbitary byte bondaries.
+
+Here is an example from /usr/src/Makefile.
+bin-tarball:
+ (cd ${DISTDIR}; \
+ tar cf - . \
+ gzip --no-name -9 -c | \
+ split -b 240640 - \
+ ${RELEASEDIR}/tarballs/bindist/bin_tgz.)
+
+5.8: I'm running Syscons and every morning my console locks up. What
+ is going on here?
+
+This sounds like the "kill -1 syslogd" problem. Make sure that the
+following is correct on your system.
+1. The attributes of the following nodes are correct.
+/dev/console
+crw------- 1 root 0, 0 May 23 15:32 /dev/console
+/dev/ttyv0
+crw------- 1 root 12, 0 May 23 15:32 /dev/ttyv0
+The part you are concerned with are the major and minor device numbers.
+
+2. Make sure that getty is running on ttyv0 and NOT console.
+
+3. If /dev/vga exists that it is a symlink to /dev/ttyv0.
+
+5.9: I've had a couple of system panics and would like to be able
+ browse the system dumps. The normal kernel is stripped and
+ I don't want to run a bloated kernel. What can I do?
+
+Please retrieve the file FAQ/OTHER-FAQS/FreeBSD.kdebug.FAQ. This
+file covers the instructions for looking at system dumps.
+
+
+6 Kernel Configuration
+----------------------
+
+6.1: When I compile a kernel with multi-port serial code, it tells me
+ that only the first port is probed and the rest skipped due to
+ interrupt conflicts. How do I fix this?
+
+The problem here is that FreeBSD has code built-in to keep the kernel
+from getting trashed due to hardware or software conflicts. The way
+to fix this is to leave out the IRQ settings on other ports besides
+the first. Here is a example:
+
+#
+# Multiport high-speed serial line - 16550 UARTS
+#
+device sio2 at isa? port 0x2a0 tty irq 5 flags 0x501 vector siointr
+device sio3 at isa? port 0x2a8 tty flags 0x501 vector siointr
+device sio4 at isa? port 0x2b0 tty flags 0x501 vector siointr
+device sio5 at isa? port 0x2b8 tty flags 0x501 vector siointr
+
+
+6.2: FreeBSD is supposed to come with support for QIC-40/80 drives but
+ when I look, I can't find it.
+
+You need to uncomment the following line in the generic config file
+(or add it to your config file) and recompile.
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You will have a device called /dev/ft0, which you can write to through
+a special program to manage it called `ft' - see the man page on ft for
+further details. Versions previous to -current also had some trouble dealing
+wiht bad tape media; if you have trouble where ft seems to go back and forth
+over the same spot, try grabbing the latest version of ft from /usr/src/sbin/ft
+in current and try that.
+
+
+6.3: Does FreeBSD support IPC primitives like those in System V?
+
+Yes, FreeBSD supports System V-style IPC. This includes shared
+memory, messages and semaphores. You need to add the following lines
+to your kernel config to enable them.
+
+options SYSVSHM
+options "SHMMAXPGS=64" # 256Kb of sharable memory
+options SYSVSEM # enable for semaphores
+options SYSVMSG # enable for messaging
+
+Recompile and install.
+
+
+6.4: Are there any utilities that make configuring a kernel easier?
+
+Well, yes and no. Look in /sys/i386/doc/options.doc (/sys/doc on post
+1.1 systems) for a list of kernel options you can set, and what they
+do. For a friendlier front-end to the process, see
+/usr/src/contrib/configit
+
+
+6.5: Will FreeBSD ever support other architectures?
+
+Several different groups have expressed interest in working on
+multi-architecture support for FreeBSD. If you are interested in
+doing so, please contact the developers at
+<FreeBSD-hackers@freefall.cdrom.com> for more information on our
+strategy for porting.
+
+
+6.6: I just wrote a device driver for a Foobar Systems, Inc.
+ Integrated Adaptive Gronkulator card. How do I get the
+ appropriate major numbers assigned?
+
+This depends on whether or not you plan on making the driver publicly
+available. If you do, then please send us a copy of the driver source
+code, plus the appropriate modifications to files.i386, a sample
+configuration file entry, and the appropriate MAKEDEV code to create
+any special files your device uses. If you do not, or are unable to
+because of licensing restrictions, then character major number 32 and
+block major number 8 have been reserved specifically for this purpose;
+please use them. In any case, we'd appreciate hearing about your
+driver on <FreeBSD-hackers@freefall.cdrom.com>.
+
+6.7: I'm wanting to switch console drivers to Syscons. I changed my
+ kernel config file to run Syscons, but when I reboot the system
+ locks up! How do I fix it?
+
+There are four things that need to be done to properly install syscons
+on a system.
+1. Add the following line to your kernel config file while deleting the
+ line for pccons.
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+(Note the changed vector 'scintr'. It is a common error to change the
+device name but NOT the vector.
+
+2. Add the following option to your config file.
+options "NCONS=6" # Change to reflect the number of consoles
+
+3. Modify /etc/ttys to enable gettys on ttyv0 - ttyv??. Here is an
+example line.
+ttyv0 "/usr/libexec/getty Pc" Pc3 on secure
+Please make sure that you have disabled the getty on /dev/console.
+
+4. Create the device nodes in /dev. This is done useing the MAKEDEV
+script located in that directory. Here is a command line that will create
+6 virtual consoles.
+MAKEDEV vty6
+If /dev/vga exists, it should now be a symlink to /dev/ttyv0.
+
+NOTE: If you are going to be running X, you will need an unused vty that
+ has no getty running on it.
+
+
+
+7 System Administration
+-----------------------
+
+7.1: How do I add a user easily? I read the man page and am more confused
+ than ever! [Alternatively: I didn't read the man page, I never read
+ man pages! :-) ]
+
+Look at Gary Clark's Perl package ``AddIt'', which may be found in
+/usr/src/contrib/adduser. This is a first attempt at solving the
+problem and may be replaced with a more complex but capable solution
+later.
+
+
+7.2: I'm trying to use my printer and keep running into problems. I tried
+ looking at /etc/printcap, but it's close to useless. Any ideas?
+
+Yes, you can pick up Andreas Klemm's apsfilter package from:
+
+ftp.germany.eu.net:pub/comp/i386/Linux/Local.EUnet/People/akl/apsfilter-1.11.gz
+
+This is a complete package for printing text, PS and DVI files. It
+requires ghostscript and dvips.
+
+If you are looking for a simple printcap just for PS and text files,
+try picking up the printcap01 sources in:
+
+ /usr/src/contrib/FAQ/code/printcap01
+
+NOTE: We're looking for printcap entries for all printers. If you
+have one, or a filter for one, please send it or mail us a pointer to
+<FreeBSD-FAQ@freefall.cdrom.com>. Thanks!
+
+
+8 Networking
+------------
+
+8.1: Where can I get information booting FreeBSD `diskless', that is
+ booting and running a FreeBSD box from a server rather than having
+ a local disk?
+
+Please read /sys/i386/netboot/netboot.doc.
+
+
+8.2: I've heard that you can use a FreeBSD box as a dedicated network
+ router - is there any easy support for this?
+
+Internet standards and good engineering practice prohibit us from
+providing packet forwarding by default in FreeBSD. You can enable
+this support by adding `options GATEWAY' to your kernel configuration
+file and recompiling. In most cases, you will also need to run a
+routing process to tell other systems on your network about your
+router; FreeBSD comes with the standard BSD routing daemon routed(8),
+or for more complex situations you may want to try GateD (available by
+FTP from gated.Cornell.edu).
+
+It is our duty to warn you that, even when FreeBSD is configured in
+this way, it does not completely comply with the Internet standard
+requirements for routers; however, it comes close enough for ordinary
+usage.
+
+There is a standard `router floppy' that you can boot on a FreeBSD
+machine to configure it as a network router. Please look in:
+
+ freefall.cdrom.com:pub/incoming/freertr
+
+and follow the instructions.
+
+
+8.3: Does FreeBSD support SLIP and PPP?
+
+Yes. See the man pages for slattach(8) and/or pppd(8) if you're using
+FreeBSD to connect to another site. If you're using FreeBSD as a
+server for other machines, look at the man page for sliplogin(8).
+You may also want to take a look at the slip FAQ in:
+ FAQ/OTHER-FAQS/FreeBSD.slip.dialup.faq
+
+8.4: How do I set up NTP?
+
+NTP configuration is so complex and widely variable from site to site
+that it would be impossible to make a blanket statement here. Your
+best bet is to ask whoever's in charge of NTP at your site or network
+provider; chances are that they are running a similar version of NTP
+to the one that we provide, and they can probably provide you with the
+right configuration files to get things going.
+
+If you can't find anyone in charge, you should examine the files in
+/usr/src/contrib/xntpd/doc and see if they help any. If not, you
+could ask on the comp.protocols.time.ntp newsgroup, or the
+<ntp@ni.umd.edu> mailing-list.
+
+8.5: How do I get my network set up? I don't see how to make my
+ /dev/ed0 device!
+
+In the Berkeley networking framework, network interfaces are only
+directly accessible by kernel code. Please see the /etc/netstart file
+and the manual pages for the various network programs mentioned there
+for more information. If this leaves you totally confused, then you
+should pick up a book describing network administration on another
+BSD-related operating system; with few significant exceptions,
+administering networking on FreeBSD is basically the same as on SunOS
+4.0 or Ultrix.
+
+8.6: How do I get my 3C503 to use the other network port?
+
+Use `ifconfig ed0' to see whether the ALTPHYS flag is set, and then
+use either `ifconfig ed0 altphys' if it was off, or `ifconfig ed0
+-altphys' if it was on.
+
+8.7: I'm having problems with NFS to/from FreeBSD and my Wuffotronics
+ Workstation / generic NFS appliance, where should I look first?
+
+Certain PC network cards are better than others (to put it mildly) and
+can sometimes cause problems with network intensive applications like
+NFS. See /usr/src/contrib/FAQ/OTHER-FAQS/NFS for more information on this
+topic.
+
+8.8: I want to enable IP multicast support on my FreeBSD box, how do I do it?
+ [Alternatively: What the heck IS multicasting and what applications
+ make use of it?]
+
+First off, to you'll need to rebuild a kernel with multicast support in it.
+This requires that you have the sources to at least the kernel and the config
+utility. See /usr/src/sys/i386/conf/LINT for its comments on multicast; you'll
+need to set the MROUTING and MULTICAST options as shown there.
+
+Further reading/exploration for those interested in multicast:
+
+Product Description Where
+--------------- ----------------------- ---------------------------------------
+faq.txt Mbone FAQ ftp.isi.edu:/mbone/faq.txt
+imm/immserv IMage Multicast ftp.hawaii.edu:/paccom/imm.src.tar.Z
+ for jpg/gif images.
+nv Network Video. ftp.parc.xerox.com:
+ /pub/net-reseach/exp/nv3.3alpha.tar.Z
+vat LBL Visual Audio Tool. ftp.ee.lbl.gov:
+ /conferencing/vat/i386-vat.tar.Z
+wb LBL White Board. ftp.ee.lbl.gov:
+ /conferencing/wb/i386-wb.tar.Z
+mmcc MultiMedia Conference ftp.isi.edu:
+ Control program /confctrl/mmcc/mmcc-intel.tar.Z
+rtpqual Tools for testing the ftp.psc.edu:/pub/net_tools/rtpqual.c
+ quality of RTP packets.
+vat_nv_record Recording tools for vat ftp.sics.se:archive/vat_nv_record.tar.Z
+ and nv.
+
+[Many thanks to Jim Lowe for providing multicast support for FreeBSD, and this
+information]
+
+
+9 Serial Communications
+-----------------------
+
+9.1: When I do a set line in Kermit it locks up, what's the problem?
+
+The problem here is that FreeBSD thinks it's talking to a incoming
+modem connection, and is waiting for carrier to come up on it before
+completing the open. To disable modem control, do an:
+
+ stty -f /dev/ttyXX clocal
+
+(Where `ttyXX' is the tty port you're using). If you use a given port
+only for outgoing connections, you may wish to put this command in
+your /etc/rc.local to avoid having to do it every time you reboot your
+system.
+
+
+NOTE: Anyone wishing to submit a FAQ entry on how to get tip and cu working
+ would have it much appreciated! We all use Kermit over here! :-)
+
+-----------------------------------------------------------------------------
+If you see a problem with this FAQ, or wish to submit an entry, please
+mail us at <FreeBSD-FAQ@freefall.cdrom.com>. We appreciate your
+feedback, and cannot make this a better FAQ without your help!
+
+
+ FreeBSD Core Team
+
+-----------------------------------------------------------------------------
+
+ACKNOWLEDGMENTS:
+
+Gary Clark II - Our head FreeBSD FAQ maintenance man
+Jordan Hubbard - Janitorial services (I don't do windows)
+Garrett Wollman - Networking and formatting
+Robert Oliver, Jr. - Ideas and dumb questions (That made me think)
+Ollivier Robert - Invaluable feedback and contributions
+The FreeBSD Team - Kvetching, moaning, submitting data
+
+And to any others we've forgotten, apologies and heartfelt thanks!
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.current.policy b/contrib/FAQ/OTHER-FAQS/FreeBSD.current.policy
new file mode 100644
index 000000000000..cdebbc72bbbf
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.current.policy
@@ -0,0 +1,162 @@
+ THE FREEBSD CURRENT POLICY
+
+Last updated: $Date: 1994/05/07 11:39:26 $
+
+This document attempts to explain the rationale behind FreeBSD-current,
+what you should expect should you decide to run it, and states some
+prerequisites for making sure the process goes as smoothly as possible.
+
+
+1. What is FreeBSD-current?
+
+FreeBSD-current is, quite literally, nothing more than a daily snapshot of
+the working sources for FreeBSD. These include work in progress, experimental
+changes, and transitional mechanisms that may or may not be present in
+the next official release of the software. While many of us compile
+almost daily from FreeBSD-current sources, there are periods of time when
+the sources are literally uncompilable. These problems are generally resolved
+as expeditiously as possible, but whether or not FreeBSD-current sources bring
+disaster or greatly desired functionality can literally be a matter of which
+part of any given 24 hour period you grabbed them in! Please read on..
+
+Under certain circumstances we will sometimes make binaries for parts of
+FreeBSD-current available, but only because we're interested in getting
+something tested, not because we're in the business of providing binary
+releases of current. If we don't offer, please don't ask! It takes far
+too much time to do this as a general task.
+
+
+2. Who needs FreeBSD-current?
+
+FreeBSD-current is made generally available for 3 primary interest groups:
+
+ 1. Members of the FreeBSD group who are actively working on one
+ part or another of the source tree and for whom keeping `current'
+ is an absolute requirement.
+
+ 2. Members of the FreeBSD group who are active ALPHA/BETA testers
+ and willing to spend time working through problems in order to
+ ensure that FreeBSD-current remains as sane as possible. These
+ are also people who wish to make topical suggestions on changes
+ and the general direction of FreeBSD.
+
+ 3. Peripheral members of the FreeBSD (or some other) group who merely
+ wish to keep an eye on things and use the current sources for
+ reference purposes (e.g. for *reading*, not running). These
+ people also make the occasional comment or contribute code.
+
+
+3. What is FreeBSD-current _NOT_?
+
+ 1. A fast-track to getting pre-release bits because there's something
+ you heard was pretty cool in there and you want to be the first on
+ your block to have it.
+
+ 2. A quick way of getting bug fixes.
+
+ 3. In any way "officially supported" by us.
+
+ We do our best to help people genuinely in one of the 3
+ "legitimate" FreeBSD-current catagories, but we simply DO NOT
+ HAVE THE TIME to help every person who jumps into FreeBSD-current
+ with more enthusiasm than knowledge of how to deal with
+ experimental system software. This is not because we're mean and
+ nasty people who don't like helping people out (we wouldn't even be
+ doing FreeBSD if we were), it's literally because we can't answer
+ 400 messages a day AND actually work on FreeBSD! I'm sure if
+ given the choice between having us answer lots of questions or
+ continue to improve FreeBSD, most of you would vote for us
+ improving it (and so would we! :-).
+
+
+4. Ok. I still think I "qualify" for FreeBSD-current, so what do I do?
+
+ 1. Join the freebsd-hackers and freebsd-commit mailing lists.
+ This is not just a good idea, it's ESSENTIAL. If you aren't on
+ freebsd-hackers, you won't read the comments that people are
+ making about the current state of the system and thus will end
+ up stumbling over a lot of problems that others have already
+ found and solved. Even more importantly, you will miss out on
+ potentially critical information (e.g. "Yo, Everybody! Before you
+ rebuild /usr/src, you MUST rebuild the kernel or your system
+ will crash horribly!").
+
+ The freebsd-commit list will allow you to see the commit log
+ entry for each change as its made. This can also contain
+ important information, and will let you know what parts of the
+ system are being actively changed.
+
+ To join these lists, send mail to `majordomo@freefall.cdrom.com'
+ and say:
+
+ subscribe freebsd-hackers
+ subscribe freebsd-commit
+
+ In the body of your message. Optionally, you can also say `help'
+ and MajorDomo will send you full help on how to subscribe and
+ unsubscribe to the various other mailing lists we support.
+
+ 2. Grab the sources from freebsd.cdrom.com. You can do this in
+ two ways:
+
+ 1. Use the CMU `sup' program (Software Update Protocol).
+ This is the most recommended method, since it allows you
+ to grab the entire collection once and then only what's
+ changed from then on. Many people run sup from cron
+ and keep their sources up-to-date automatically.
+
+ To get a binary of the sup program for FreeBSD, as well
+ as the documentation and some sample configuration files,
+ look in:
+
+ freefall.cdrom.com:~ftp/pub/sup
+
+ 2. Use ftp. The source tree for FreeBSD-current is always
+ "exported" on:
+
+ freebsd.cdrom.com:~ftp/pub/FreeBSD/FreeBSD-current
+
+ We use `wu-ftpd' which allows compressed/tar'd grabbing
+ of whole trees. e.g. you see:
+
+ usr.bin/lex
+
+ You can do:
+
+ ftp> cd usr.bin
+ ftp> get lex.tar.Z
+
+ And it will get the whole directory for you as a compressed
+ tar file.
+
+ 3. If you're grabbing the sources to run, and not just look at,
+ then grab ALL of current, not just selected portions. The
+ reason for this is that various parts of the source depend on
+ updates elsewhere and trying to compile just a subset is almost
+ guaranteed to get you into trouble.
+
+ 4. Before compiling current, read the Makefile in /usr/src
+ carefully. You'll see one-time targets like `bootstrapld'
+ which *MUST* be run as part of the upgrading process. Reading
+ freebsd-hackers will keep you up-to-date on other bootstrapping
+ procedures that sometimes become necessary as we move towards
+ the next release.
+
+ 5. Be active! If you're running FreeBSD-current, we want to know
+ what you have to say about it, especially if you have suggestions
+ for enhancements or bug fixes. Suggestions with accompanying code
+ are received most enthusiastically! :-)
+
+
+Thank you for taking the time to read this all the way through. We're
+always very keen to remain "open" and share the fruits of our labor
+with the widest possible audience, but sharing development sources has
+always had certain pitfalls associated with it (which is why most
+commercial organizations won't even consider it) and I want to make
+sure that people at least come into this with their eyes open, and
+don't make the leap unless they're good at working without a net!
+
+ Jordan
+
+
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.kdebug.FAQ b/contrib/FAQ/OTHER-FAQS/FreeBSD.kdebug.FAQ
new file mode 100644
index 000000000000..150fb8aac735
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.kdebug.FAQ
@@ -0,0 +1,33 @@
+ Kernel debugging FAQ
+ FreeBSD
+
+Last modified: $Id: FreeBSD.kdebug.FAQ,v 1.1 1994/06/12 15:12:21 gclarkii Exp $
+
+Here are some instructions for getting kernel debugging working on
+a crash dump, it assumes that you have enough swap space for a crash
+dump.
+
+*** Start ***
+
+Config you're kernel using config -g
+
+Remove ${STRIP} -x $@; from the Makefile for the kernel so it doesn't
+get stripped.
+
+When the kernel's been built make a copy of it, say 386BSD.debug, and
+then run strip -x on the original. Install the original as normal.
+
+Now, after a crash dump, go to /sys/compile/WHATEVER and run kgdb. From kgdb
+do:
+
+symbol-file 386BSD.debug
+exec-file /var/crash/system.0
+core-file /var/crash/ram.0
+
+and viola, you can debug the crash dump using the kernel sources just like
+you can for any other program.
+
+
+
+ Paul Richards, FreeBSD core team member.
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.mailing-list.FAQ b/contrib/FAQ/OTHER-FAQS/FreeBSD.mailing-list.FAQ
new file mode 100644
index 000000000000..f522e79f782a
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.mailing-list.FAQ
@@ -0,0 +1,77 @@
+ THE FREEBSD MAILING LIST FAQ
+
+Last updated: $Date: 1994/05/07 11:42:03 $
+
+Though many of the FreeBSD development members read USENET, we cannot
+always guarantee that we'll get to your questions in a timely fashion
+(or at all) if you post them only to one of the comp.os.386bsd.*
+groups. By addressing your questions to the appropriate mailing list
+you will reach both us and a concentrated FreeBSD audience, invariably
+assuring a better (or at least faster) response.
+
+The following is a summary of the mailing lists:
+
+List Purpose
+-----------------------------------------------------------------------------
+freebsd-admim Administrative issues (limited)
+freebsd-arch Architecture and design discussions (limited)
+freebsd-scsi Discussions concerning the SCSI system
+freebsd-bugs Bug reports
+freebsd-tz Discussions of proper timezone handling
+freebsd-hackers Technical discussions and suggestions
+freebsd-questions User questions
+freebsd-announce Important events / milestones
+freebsd-current Discussions about the use of FreeBSD-current
+
+-----------------------------------------------------------------------------
+
+Of all the lists, freebsd-arch and freebsd-admin have closed memberships
+limited to a small subset of core team members and developers, though anyone
+is free to send suggestions and commentary to them. The other lists may
+be freely joined by anyone.
+
+All mailing lists live on `freefall.cdrom.com', so to post to a list you
+simply mail to `<listname>@freefall.cdrom.com'. It will then be redistributed
+to mailing list members throughout the world.
+
+To subscribe to a list, send mail to:
+
+ majordomo@freefall.cdrom.com
+
+And include the keyword
+
+ subscribe <listname> [<optional address>]
+
+In the body of your message. For example, to subscribe yourself to
+freebsd-hackers, you'd do:
+
+ % mail majordomo@freefall.cdrom.com
+ subscribe freebsd-hackers
+ ^D
+
+If you want to subscribe yourself under a different name, or submit a
+subscription request for a local mailing list (note: this is more efficient
+if you have several interested parties at one site, and highly appreciated by
+us!), you would do something like:
+
+ % mail majordomo@freefall.cdrom.com
+ subscribe freebsd-hackers local-hackers@somesite.com
+ ^D
+
+Finally, it is also possible to unsubscribe yourself from a list, get a
+list of other list members or see the list of mailing lists again by
+sending other types of control messages to majordomo. For a complete
+list of available commands, do this:
+
+ % mail majordomo@freefall.cdrom.com
+ help
+ ^D
+
+Finally, it is suggested that you only join the freebsd-hackers or
+freebsd-questions mailing lists if you're also willing to see upwards
+of 100 messages a day (peak)! If you're only interested in the "high points",
+then it's suggested that you join freebsd-announce, which will contain
+only infrequent traffic.
+
+ Thank you!
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.ports.supfile b/contrib/FAQ/OTHER-FAQS/FreeBSD.ports.supfile
new file mode 100644
index 000000000000..60d30bfedac5
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.ports.supfile
@@ -0,0 +1,18 @@
+
+ports-audio release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-base release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-comm release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-db release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-devel release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-editor release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-game release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-lang release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-mail release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-math release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-net release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-news release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-print release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-shell release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-util release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+ports-x11 release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/ports delete compress
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.slip.dialup.faq b/contrib/FAQ/OTHER-FAQS/FreeBSD.slip.dialup.faq
new file mode 100644
index 000000000000..23734d4c8ec4
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.slip.dialup.faq
@@ -0,0 +1,172 @@
+***********************************************************************
+*** How to Set Up SLIP on FreeBSD ***
+***********************************************************************
+
+Last updated: $Date: 1994/06/01 09:03:08 $
+ $Id: FreeBSD.slip.dialup.faq,v 1.1 1994/06/01 09:03:08 asami Exp $
+
+The following is I (asami) set up my FreeBSD machine for SLIP on a
+static host network. For dynamic hostname assignments (i.e., your
+address changes each time you dial up), you probably need to do
+something much fancier.
+
+This is just "what I did, and it worked for me". I'm sharing this
+just for your reference, I'm no expert in SLIP nor networking so your
+mileage may vary.
+
+First, make sure you have
+
+pseudo-device sl 2
+
+in your kernel's config file. It is included in the GENERICAH and
+GENERICBT kernels, so this won't be a problem unless you deleted it.
+
+Things you have to do only once:
+
+(1) Add your home machine, the gateway and nameservers to your
+ /etc/hosts file. Mine looks like this:
+
+127.0.0.1 localhost loghost
+136.152.64.181 silvia.HIP.Berkeley.EDU silvia.HIP silvia
+
+136.152.64.1 inr-3.Berkeley.EDU inr-3 slip-gateway
+128.32.136.9 ns1.Berkeley.edu ns1
+128.32.136.12 ns2.Berkeley.edu ns2
+
+ By the way, silvia is the name of the car that I had when I was
+ back in Japan (it's called 2?0SX here in U.S.).
+
+(2) Make sure you have "hosts" before "bind" in your /etc/host.conf.
+ Otherwise, funny things may happen.
+
+(3) Edit the /etc/netstart and add this to the end of the file:
+
+# set up slip
+gateway=slip-gateway
+ifconfig sl0 inet $hostname $gateway netmask 0xffffff00
+route add default $gateway
+
+ Note that because of the "slip-gateway" entry in /etc/hosts, there
+ is no local dependency in the netstart file. Also, you might want
+ to un-comment the "route add $hostname localhost" line.
+
+(3') Make a file /etc/resolv.conf which contains:
+
+domain HIP.Berkeley.EDU
+nameserver 128.32.136.9
+nameserver 128.32.136.12
+
+ As you can see, these set up the nameserver hosts. Of course, the
+ actual addresses depend on your environment.
+
+(4) Set the password for root and toor (and any other accounts that
+ doesn't have a password). Use passwd, don't edit the passwd or
+ passwd.master files!
+
+(5) Edit /etc/myname and reboot the machine.
+
+How to set up the connection:
+
+(6) Dial up, type "slip" at the prompt, enter your machine name and
+ password. The things you need to enter depends on your
+ environment. I use kermit, with a script like this:
+
+# kermit setup
+set modem hayes
+set line /dev/tty01
+set speed 57600
+set parity none
+set flow rts/cts
+set terminal bytesize 8
+set file type binary
+# The next macro will dial up and login
+define slip dial 643-9600, input 10 =>, if failure stop, -
+output slip\x0d, input 10 Username:, if failure stop, -
+output silvia\x0d, input 10 Password:, if failure stop, -
+output ***\x0d, echo \x0aCONNECTED\x0a
+
+ (of course, you have to change the hostname and password to fit
+ yours). Then you can just type "slip" from the kermit prompt to
+ get connected.
+
+ Note: leaving your password in plain text anywhere in the
+ filesystem is generally a BAD idea. Do it at your own risk. I'm
+ just too lazy.
+
+ If kermit doesn't give you a prompt, try "stty -f /dev/tty01
+ clocal". I put this in /etc/rc.local so that it works the first
+ time I boot the machine.
+
+(7) Leave the kermit there (you can suspend it by "z") and as root,
+ type
+
+slattach -h -c -s 57600 /dev/tty01
+
+ if you are able to "ping" hosts on campus, you are connected!
+
+ If it doesn't work, you might want to try "-a" instead of "-c".
+
+(8) Happy slipping!
+
+How to shutdown the connection:
+
+(9) Type "ps gx" (as root) to find out the PID of slattach, and use
+ "kill -INT" to kill it.
+
+ Then go back to kermit ("fg" if you suspended it) and exit from it
+ ("q").
+
+ The slattach man page says you have to use "ifconfig sl0 down" to
+ mark the interface down, but this doesn't seem to make any
+ difference for me. ("ifconfig sl0" reports the same thing.)
+
+ Some times, your modem might refuse to drop the carrier (mine
+ often does). In that case, simply start kermit and quit it again.
+ It usually goes out on the second try.
+
+ When you want to connect again, go back to (6). You may have to
+ watch out for clocal mode. If "stty -f /dev/tty01" doesn't tell
+ you it's clocal, you need to re-set it before kermitting.
+
+TROUBLESHOOTING:
+
+If it doesn't work, feel free to ask me. The things that people
+tripped over so far:
+
+* Not using "-c" or "-a" in slattach (I have no idea why this can be
+ fatal, but adding this flag solved the problem for at least one
+ person)
+
+* Using "s10" instead of "sl0" (might be hard to see the difference on
+ some fonts :)
+
+Try "ifconfig sl0" to see your interface status. I get:
+
+silvia# ifconfig sl0
+sl0: flags=10<POINTOPOINT>
+ inet 136.152.64.181 --> 136.152.64.1 netmask ffffff00
+
+Also, "netstat -r" will give the routing table, in case you get the
+"no route to host" messages from ping. Mine looks like:
+
+silvia# netstat -r
+Routing tables
+Destination Gateway Flags Refs Use IfaceMTU Rtt
+Netmasks:
+(root node)
+(root node)
+
+Route Tree for Protocol Family inet:
+(root node) =>
+default inr-3.Berkeley.EDU UG 8 224515 sl0 - -
+localhost.Berkel localhost.Berkeley UH 5 42127 lo0 - 0.438
+inr-3.Berkeley.E silvia.HIP.Berkele UH 1 0 sl0 - -
+silvia.HIP.Berke localhost.Berkeley UGH 34 47641234 lo0 - 0.438
+(root node)
+
+(this is after transferring a bunch of files, your numbers should be
+smaller).
+
+---
+Satoshi Asami
+asami@cs.berkeley.edu
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.standard.supfile b/contrib/FAQ/OTHER-FAQS/FreeBSD.standard.supfile
new file mode 100644
index 000000000000..531a98110b38
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.standard.supfile
@@ -0,0 +1,16 @@
+base release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+bin release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+contrib release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+crypt release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+etc release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+games release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+gnu release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+include release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+ksrc release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+lib release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+libexec release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+sbin release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+share release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+usrbin release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+usrsbin release=current host=freefall.cdrom.com hostbase=/home base=/usr prefix=/usr/src delete old compress
+
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSD.sup.faq b/contrib/FAQ/OTHER-FAQS/FreeBSD.sup.faq
new file mode 100644
index 000000000000..35c552168d6b
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSD.sup.faq
@@ -0,0 +1,98 @@
+
+ FreeBSD
+ Sup FAQ
+
+Last updated: $Date: 1994/05/11 22:40:48 $
+
+ SUP is a network based software update tool developed at CMU. The
+purpose of this document is get the beginner up and running with sup.
+
+ First off you will need to pick up the sup binaries. The easiest
+way of doing this is to grab the sup_bin.tgz package from:
+
+ freebsd.cdrom.com:~ftp/pub/FreeBSD/packages
+ (FreeBSD 1.1 or later)
+ freebsd.cdrom.com:~ftp/pub/FreeBSD/packages-1.0
+ (FreeBSD 1.0.2 or earlier)
+
+Install the sup package using pkg_add and add the following line to your
+/etc/services file:
+
+ sup 871/tcp #sup
+
+
+ SUP gets the information it needs to run from a configuration file
+called a supfile. This file tells sup what collections it will be updating
+and/or installing and where they go. There are already two files that
+have been created for supping FreeBSD, both of which may be gotten from:
+
+ freebsd.cdrom.com:~ftp/pub/FreeBSD/FAQ/OTHER-FAQS
+
+The file `FreeBSD.standard.supfile' is used for supping from the
+/usr/src tree, the file `FreeBSD.ports.supfile' for the /usr/ports tree.
+These two files can be installed whereever it is convient to do so.
+
+ Next you will have to comment out whichever distributions you do
+not wish to receive with a # at the begining of the distribution line.
+You will find a list of distributions and a description for each at the
+end of this file.
+
+ Once this is setup, you're ready to go.
+
+To start sup type:
+
+ sup supfile
+
+If you wish to see what sup is doing "verbosely", give it the -v option,
+like so:
+
+ sup -v supfile
+
+ Thats all there is to it! Remember that if you're running current,
+which is what you will have if you sup, please join the freebsd-current
+mailing list. For more information on current please see the file:
+
+freefall.cdrom.com:~ftp/pub/FreeBSD/FAQ/OTHER-FAQS/FreeBSD.current.policy
+
+Gary Clark II
+FreeBSD maintainance person
+
+----
+
+FreeBSD SUP distributions
+
+From FreeBSD.standard.supfile:
+
+base: Just those files at the top of /usr/src.
+bin: /bin
+contrib: Sources to programs located in /usr/src/contrib, including the FAQ.
+crypt: Sources to libcrypt. NOTE: This is for use by US and Canadians only!!
+etc: /etc
+games: /usr/games
+gnu: Software that is under the GPL, like gcc, groff and uucp.
+include: /usr/include
+ksrc: The kernel sources
+lib: /usr/lib
+libexec: /usr/libexec
+sbin: /sbin
+usrbin: /usr/bin
+usrsbin: /usr/sbin
+
+From FreeBSD.ports.supfile
+
+ports-audio: Audio applications
+ports-base: Just those files at the top of /usr/ports.
+ports-comm: Communications software
+ports-db: Database software
+ports-devel: Development software
+ports-editor: Editing software
+ports-game: Game software
+ports-lang: Programming Languages
+ports-mail: Mail software
+ports-math: Math software
+ports-net: Network software
+ports-news: USENET news software
+ports-print: Printing software
+ports-shell: User shell software
+ports-util: Utility software
+ports-x11: X11 software
diff --git a/contrib/FAQ/OTHER-FAQS/FreeBSDvsLinux b/contrib/FAQ/OTHER-FAQS/FreeBSDvsLinux
new file mode 100644
index 000000000000..c282475d60e5
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/FreeBSDvsLinux
@@ -0,0 +1,70 @@
+[ Note: You could very well simply substitute the word "NetBSD" for Linux
+ in the argument that follows ]
+
+From time to time, a thread in both the comp.os.386bsd.misc and
+comp.os.linux.misc groups flares up regarding which operating system is
+"better", FreeBSD or Linux. This generally provokes controversy from
+users on both sides, with one group claiming that their OS is "better"
+for some reason and the other group claiming that the first group
+doesn't know what the heck it's talking about.
+
+Both arguments are a waste of time.
+
+Rather than trying to win a rather questionable debate on relative
+(and constantly changing) technical merits, we should be asking ourselves
+what both groups are REALLY about and what they represent. This is
+naturally going to be a matter of personal opinion, but I believe even the
+most seriously at-odds members would agree that both operating systems
+represent a unique and long-awaited opportunity: The ability to run a
+fully featured operating system on popular, easily affordable hardware
+and for which all source code is freely available.
+
+Those who have been in computing for awhile will remember when the term
+`operating system' referred almost exclusively to something provided solely
+by the hardware vendor, with very little in the way of alternative options.
+It was never EVER given out with source code, and true "wizard" status could
+only be achieved by exerting mind-numbing amounts of effort and patience in
+digging through forbidden bits of binary data. By comparison, the situation
+today seems almost too good to be true! Certainly, the feeling of achievement
+that came from finally ferreting out some esoteric bit of information from
+a 4MB printed system dump was high, but I don't think that anyone would argue
+that it was hardly the most optimal way of truly getting to know your
+operating system! :-)
+
+So now, within a very short space of time, we're almost spoiled for choice in
+having machines several times more powerful than the first multi-user VAX
+machines and available for under $2000, and we've got not one but SEVERAL
+perfectly reasonable free operating systems to chose from. We are in a
+comparative paradise, and what are some of us doing? *Complaining* about it!
+I suppose too much is never enough, eh? :-)
+
+So, my essential point is simply this: For the first time ever we
+have what previous computing generations could only dream about;
+powerful computers at a reasonable prices and a wonderful selection of
+things to run on them. Be happy, read the source code you're so
+privileged to now have available (*believe* me! What I wouldn't have
+given, even 5 years ago!) and spend your energy in making constructive
+use of it, not in arguing with the guys on the other side of the
+fence!
+
+Additionally, it should be said that none of the FreeBSD team has
+anything but the highest degree of respect for Linus Torvalds and his
+"team" of dedicated volunteers (and we occasional exchange gripe mail
+about the huge volume of messages each of us gets as a direct result
+of being insane enough to volunteer to do something like this :-).
+Our common commitment to the Intel platform also gives us more common
+ground (and interests) than one might think and, if anything, it's a pity
+that we do not endevor to share more code and effort - ideologically,
+at least, I'd say we share pretty similar goals.
+
+As to which is "best", I have only one standard reply: Try them both,
+see for yourself, think for yourself. Both groups have given you
+something for free, at considerable personal effort, and the least you
+can do is give them the benefit of exerting enough effort to try what
+they're offering out before passing judgment (or worse, blindly
+accepting someone else's!).
+
+Whichever you run, you're getting a great deal - enjoy!
+
+
+ Jordan Hubbard
diff --git a/contrib/FAQ/OTHER-FAQS/NFS b/contrib/FAQ/OTHER-FAQS/NFS
new file mode 100644
index 000000000000..e6f7af8fc511
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/NFS
@@ -0,0 +1,77 @@
+FreeBSD and NFS [for a FAQ]
+
+Certain Ethernet adapters for ISA PC systems have limitations which
+can lead to serious network problems, particularly with NFS. This
+difficulty is not specific to FreeBSD, but FreeBSD systems are affected
+by it.
+
+The problem nearly always occurs when (FreeBSD) PC systems are networked
+with high-performance workstations, such as those made by Silicon Graphics,
+Inc., and Sun Microsystems, Inc. The NFS mount will work fine, and some
+operations may succeed, but suddenly the server will seem to become
+unresponsive to the client, even though requests to and from other systems
+continue to be processed. This happens to the client system, whether the
+client is the FreeBSD system or the workstation. On many systems, there is
+no way to shut down the client gracefully once this problem has manifested
+itself. The only solution is often to reset the client, because the NFS
+situation cannot be resolved.
+
+Though the "correct" solution is to get a higher performance and capacity
+Ethernet adapter for the FreeBSD system, there is a simple workaround that
+will allow satisfactory operation. If the FreeBSD system is the SERVER,
+include the option "wsize=1024" on the mount from the client. If the
+FreeBSD system is the CLIENT, then mount the NFS file system with the
+option "rsize=1024". These options may be specified using the fourth
+field of the fstab entry on the client for automatic mounts, or by using
+the "-o" parameter of the mount command for manual mounts.
+
+In the following examples, "fastws" is the host (interface) name of a
+high-performance workstation, and "freebox" is the host (interface) name of
+a FreeBSD system with a lower-performance Ethernet adapter. Also,
+"/sharedfs" will be the exported NFS filesystem (see "man exports"), and
+"/project" will be the mount point on the client for the exported file
+system. In all cases, note that additional options, such as "hard" or
+"soft" and "bg" may be desireable in your application.
+
+Examples for the FreeBSD system ("freebox") as the client:
+ in /etc/fstab on freebox:
+fastws:/sharedfs /project nfs rw,rsize=1024 0 0
+ as a manual mount command on freebox:
+mount -t nfs -o rsize=1024 fastws:/sharedfs /project
+
+Examples for the FreeBSD system as the server:
+ in /etc/fstab on fastws:
+freebox:/sharedfs /project nfs rw,wsize=1024 0 0
+ as a manual mount command on fastws:
+mount -t nfs -o wsize=1024 freebox:/sharedfs /project
+
+Nearly any 16-bit Ethernet adapter will allow operation without the above
+restrictions on the read or write size.
+
+For anyone who cares, here is what happens when the failure occurs, which
+also explains why it is unrecoverable. NFS typically works with a "block"
+size of 8k (though it may do fragments of smaller sizes). Since the maximum
+Ethernet packet is around 1500 bytes, the NFS "block" gets split into
+multiple Ethernet packets, even though it is still a single unit to the
+upper-level code, and must be received, assembled, and ACKNOWLEDGED as a
+unit. The high-performance workstations can pump out the packets which
+comprise the NFS unit one right after the other, just as close together as
+the standard allows. On the smaller, lower capacity cards, the later
+packets overrun the earlier packets of the same unit before they can be
+transferred to the host and the unit as a whole cannot be reconstructed or
+acknowledged. As a result, the workstation will time out and try again,
+but it will try again with the entire 8K unit, and the process will be
+repeated, ad infinitum.
+
+By keeping the unit size below the Ethernet packet size limitation, we
+ensure that any complete Ethernet packet received can be acknowledged
+individually, avoiding the deadlock situation.
+
+Overruns may still occur when a high-performance workstations is slamming
+data out to a PC system, but with the better cards, such overruns are
+not guarranteed on NFS "units". When an overrun occurs, the units affected
+will be retransmitted, and there will be a fair chance that they will be
+received, assembled, and acknowledged.
+--
+ John Lind, Starfire Consulting Services
+E-mail: john@starfire.MN.ORG USnail: PO Box 17247, Mpls MN 55417
diff --git a/contrib/FAQ/OTHER-FAQS/Systems.FAQ b/contrib/FAQ/OTHER-FAQS/Systems.FAQ
new file mode 100644
index 000000000000..c2e3e2ed5177
--- /dev/null
+++ b/contrib/FAQ/OTHER-FAQS/Systems.FAQ
@@ -0,0 +1,266 @@
+ Systems FAQ
+ For FreeBSD
+ Last Modified: $Id: Systems.FAQ,v 1.1 1994/06/11 17:59:19 gclarkii Exp $
+
+This FAQ is a list of systems that people have sent to the FAQ maintnance
+person for inclusion. If you have a system you would like to be included
+please send it to FreeBSD-FAQ@freefall.cdrom.com.
+
+Disclaimer: This document is composed of systems that people have sent to
+the FAQ maintnance person. It is the not to be taken as an endorsement
+for any system or manufacture.
+
+
+1.
+
+386DX/20 real AMI, ISA
+Oak SVGA (no X)
+8MB
+Adaptec 1542B, WD1007V ESDI
+Wren VI and Miniscribe 660MB 20Mbit/sec ESDI
+WD 8013EBT
+
+2.
+
+486DX/25 clone, AMI BIOS, ISA
+Orchid PCIII gas plasma (yes, VGA16)
+8MB
+Adaptec 1542B
+Micropolis 1684 SCSI
+SMC 8013EEWC
+
+3.
+
+ ??? OPTI chipset AMI BIOS 486/50 ISA
+ISA ET4000 w/ X11 (not so slow)
+16 Mb - 48 Mb swap
+ISA aha1542 B
+ISA no-name IDE w/ floppies
+FUJITSU M2623S-512 405MB set to SCSI2
+SEAGATE ST3283N 237MB SCSI2
+SANYO CRD-400I SCSI2 cdromcdrom
+
+4.
+
+Lipizzan LDO-1 486DX-33 motherboard
+Orchid ProIIs (1M) video
+8 MB memory
+Generic 2S/1P/2FD/IDE controller:
+Maxtor 7213 AT
+WDC AC2420H
+PAS-16 + Sony CDU31A CD drive (Fusion 16 package).
+ *** The CD drive does not currently work with FreeBSD.
+
+5.
+
+Asus VL/ISA-486SV2 (ISA-VLB as you can see)
+Orchid Fahrenheit 1280+ VLB (yes)
+20MB
+Some no-name IDE VLB controller
+Conner CP30504 (I think....the 540MB IDE one)
+Zoltrix 14.4/14.4 Fax/Modem on tty01
+Intel 486DX2/66 CPU + fan
+Conner CP30104 (120MB....for DOS)
+
+6.
+
+AIR 486El (running with AMD486/40)
+ATI Graphics Ultra Pro running XFree862.1
+16M
+Adaptec 1742
+Micropolis 2217
+Wangtec 6130FS DAT drive (Some problems)
+
+7.
+
+Compudyne 486 DX2/66
+ATI Local Bus GUP w/ 2megs
+16 Megs Memory
+504 IDE Hard Drive
+Colorado 250 meg QIC-80 tape drive
+
+8.
+
+American Megatrends Enterprise III, 486DX2-66
+ATI VLB Mach 32 (with X)
+16 meg
+Adaptec 1742 EISA SCSI with floppy
+Toshiba 5030 SCSI-II
+Toshiba 5157 SCSI-II
+SMC Elite16T ISA Ethernet (ISA)
+
+9.
+
+American Megatrends Enterprise III, 486DX
+ATI VLB Mach 32 (with X)
+32 meg
+Adaptec 1742 EISA SCSI with floppy
+Maxtor P0-12S SCSI
+Digital DSP5200S SCSI-II
+Pro Audio Spectrum 16
+Wonder Board, 4 serial (16550), 3 parallel, each on a different interrupt
+
+10.
+
+NoName 486DX/33, Intel Chipset, EISA-Bus
+ATI Graphics Ultra Pro EISA,
+17" Nanao (Eizo) F550-i Monitor
+Running the Mach32 X-Server XFree86-2.1.1 with fonts created from source.
+16 MB RAM (planning to add another 8 MB).
+AHA1742A
+Conner CP3100
+Fujitsu 520 MB
+Archive 525MB streamer tape.
+Gravis UltraSound - works for mod-files.
+
+11.
+
+ASUS SP3 PCI Board with i486 DX/2 66 MHz
+ISA ET4000 (I already tested a S3 805 PCI card successfully)
+Adaptec 1542B
+Toshiba XM3301TA CD-Rom
+CDC Harddisk, 572 MB (I don't know the exact specs)
+
+12.
+
+Mylex MAE486/33 EISA Motherboard
+16MB memory
+Actix GE32+ S3 801 gfx
+Adaptec 1742A controller
+Seagate ST3160 drive
+Seagate ST5120 drive
+Archive Viper 150MB tape
+Roland SCC-1 sound card
+Gravis Ultrasound card
+Longshine SMC/Novell compatable ethernet card
+
+13.
+
+Model: DECpc LPv 466d2
+Config: Local (Motherboard) S3 801 gfx, IDE controller, PS/2 mouse, 12MB memory
+
+14.
+
+
+??? 486/DX266 EISA/VLB Motherboard
+16MB memory
+#9 GXE L12 VLB 3MB graphics card
+Bt445S VLB disk controller
+DEC DSP3105S drive
+MAXSTOR P-17S drive
+Tandberg 525MB tape drive
+Toshiba XM3301 CDROM
+Soundblaster 2.0
+Longshine SMC/Novell compatable ethernet card
+
+15.
+
+M407 PC chips with 33Mhz 486.
+Had to disable external cache due to DMA problems. Board uses write-through
+cache unless a second chip is added to allow write-back.write-back.
+Orchid ProDesigner II (yes)
+16Mb
+IDE
+Maxtor 7213 AT and Maxtor 7120 AT
+2 BICC Isolans (Lance based cards)
+
+16.
+
+Gigabyte EISA/VLB motherboard with SIS chipset, AMI bios, 32 MB ram
+Adaptec 1742 SCSI 2 controller with floppy controller enabled
+Spea/V7 Mirage - S3/805 based localbus graphics card with 1 MB d-ram
+no name wd8013 compatible ethernet card
+Gravis Ultrasound card with 1 MB ram
+2 Fujitsu 400 MB and 1 Seagate 500 MB SCSI 2 harddisks
+5 1/4 + 3 1/2 inch floppy drives
+Tandberg TDC3600 60 MB + Tandberg TDC3800 525 MB Streamer (these don't work
+quite properly yet)
+
+17.
+
+i486DX33, 16 Mb RAM, 256 Kb external cache, VLB board
+no-name IDE/floppy controller
+Western Digital Caviar 2340 (325 Mb)
+Kalok KL-343 (40 Mb)
+Chips & Technologies 451 SuperVGA card (800x600, 16 colours, 256Kb)
+
+18.
+
+no name EISA i486DX/33 board, 16 MB RAM
+Adaptec AHA-1540*A* (not knowing if the current -current might cause
+ problems, my kernel is from end of march)
+Maxtor MXT-1240S, 1.2Gig very fast SCSI disk
+Seagate ST-1144A, just to boot off the beast (also has a messdos partition yet)
+Archive Viper 150 tape; has a firmware braindeadness when appending files,
+ works very well otherwise
+ELSA Winner 1000 ISA/EISA, 1MB VRAM, S3 86C928 (unfortunately, D-step chip)
+Nokia 447-B 17in monitor, running ~ 1100x800 resolution, very nice
+true `Mouse Systems' optical mouse, fine thing!
+sometimes a Toshiba XM-3301 CDROM, rather old, but solid & reliable
+
+19.
+
+older south-east Asia made notebook, i386SX/16, 5 MB RAM (where the 384 k hole
+ can be re-mapped, so all the 5 MB are useable)
+Seagate ST-9145AG, 120 MB 2.5in IDE disk, very low power consumption, but
+ rather slow transfer rate, only about 350 K/s, so paging is a mess
+640x480 LCD, ~ 16 gray tones distinguishable, Cirrus Logic CL-GD610/620
+ chipset; runs generic VGA-Mono and VGA-16 XFree86[tm] servers; needs
+ some hacks in rc.local to give full contrast when running with the
+ pcvt display driver (due to their different default attribute handling)
+
+
+20.
+
+Data General Dasher 386sx/16, 8 MB RAM
+Adaptec AHA-1542B
+Seagate ST-3655N, 525 MB SCSI disk
+Conner CP-3044, 40 MB IDE disk
+has been working with a Western Digital WD-1007V ESDI controller (on
+ secondary wdc address), and a Micropolis 1664-7 330 MB ESDI disk -
+ but this beast was terribly slow, loud (& unreliable) and therefore
+ had to go
+ET-3000 based 512 K VGA, slow (wrt. XFree86), but reliable
+3Com 3C503 Ethernet adaptor, suffers from the `do not nfs mount with
+ too large packets' problem, but works well otherwise
+`Mouse Systems' optical mouse
+Toshiba XM-3301 CDROM
+already ran with a Micropolis 1664-3 330 MB SCSI disk (same drive as
+ above, but different interface)
+already ran with an IBM 2Gig SCSI disk (don't remember the type)
+
+
+21.
+
+Mylex MNA 486/33 EISA Motherboard
+16Mb of Memory
+1.2 GB Toshiba 538 SCSI disk
+400Mb IBM SCSI disk
+150/250Mb Tandberg SCSI tape drive
+Toshiba 3401 SCSI CD-ROM
+Tseng 4000 Video Controller
+Logitech Bus Mouse
+Mediavision Pro Audio Stereo Sound Card
+Adaptech 1742A SCSI controller
+WD8013EBT Ethernet Card
+
+22.
+
+386DX-40 w/Cyrix math co-processor
+ET-4000 running X
+16MB
+IDE
+540MB Western Digital
+WD8003EP
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/FAQ/code/printcap01/Makefile b/contrib/FAQ/code/printcap01/Makefile
new file mode 100644
index 000000000000..fda6ebb83586
--- /dev/null
+++ b/contrib/FAQ/code/printcap01/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the FAQ/printcap
+#
+
+PROG = hpf
+SRCS = hpf.c
+
+
+install:
+ if test -d /usr/libexec/lpr; \
+ then \
+ true; \
+ else \
+ mkdir /usr/libexec/lpr;
+ fi;
+
+ install -c -o bin -g bin -m 555 hpf /usr/libexec/lpr
+ install -c -o bin -g bin -m 555 ps2lj3 /usr/libexec/lpr
+ install -c -o bin -g bin -m 555 printcap.sample /etc/printcap
+
+.include <bsd.prog.mk>
+
diff --git a/contrib/FAQ/code/printcap01/README b/contrib/FAQ/code/printcap01/README
new file mode 100644
index 000000000000..c13eb72ddb65
--- /dev/null
+++ b/contrib/FAQ/code/printcap01/README
@@ -0,0 +1,14 @@
+This print cap package was created by Curt Mayer. Please contact hime for more
+information.
+
+Curt Mayer
+curt@toad.com
+415-387-0217 home
+
+To install this package, type make then make install. This will copy the
+printcap.sample to /etc/printcap and create the directory /usr/libexec/lpr
+and copy the hpf filter to there.
+
+Thanks
+Gary Clark II
+FreeBSD FAQ Person
diff --git a/contrib/FAQ/code/printcap01/hpf.c b/contrib/FAQ/code/printcap01/hpf.c
new file mode 100644
index 000000000000..8d78c092f902
--- /dev/null
+++ b/contrib/FAQ/code/printcap01/hpf.c
@@ -0,0 +1,38 @@
+/*
+source to my hp filter, installed as /usr/libexec/lpr/hpf:
+*/
+#include "stdio.h"
+#include <signal.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+
+main(ac, av)
+int ac;
+char **av;
+{
+ int c;
+ struct sgttyb nbuf;
+ unsigned long lbits;
+
+ setbuf(stdout, NULL);
+ lbits = LDECCTQ | LPASS8 | LLITOUT;
+ ioctl(fileno(stdout), TIOCLSET, &lbits);
+ ioctl(fileno(stdout), TIOCGETP, &nbuf);
+ nbuf.sg_flags &= ~(ECHO | XTABS | CRMOD);
+ ioctl(fileno(stdout), TIOCSETP, &nbuf);
+
+ fputs("\033E\033&k2G", stdout);
+
+ while (1) {
+ if ((c = getchar()) != EOF) {
+ putchar(c);
+ } else {
+ break;
+ }
+ }
+
+ fputs("\033&l0H", stdout);
+
+ exit(0);
+}
diff --git a/contrib/FAQ/code/printcap01/printcap.sample b/contrib/FAQ/code/printcap01/printcap.sample
new file mode 100644
index 000000000000..10e87ba2d386
--- /dev/null
+++ b/contrib/FAQ/code/printcap01/printcap.sample
@@ -0,0 +1,9 @@
+
+ps|postscript emulation:\
+ :lp=/dev/lpa0:sd=/var/spool/lpd:lf=/var/log/lpd-errs:\
+ :if=/usr/libexec/lpr/ps2lj3:sh:mx#0:sf:
+
+lp|epson|lj|local line printer:\
+ :lp=/dev/lpa0:sd=/var/spool/lpd:lf=/var/log/lpd-errs:\
+ :if=/usr/libexec/lpr/hpf:\
+ :sh:mx#0:pw#80:
diff --git a/contrib/FAQ/code/printcap01/ps2lj3 b/contrib/FAQ/code/printcap01/ps2lj3
new file mode 100644
index 000000000000..8dc9ff384011
--- /dev/null
+++ b/contrib/FAQ/code/printcap01/ps2lj3
@@ -0,0 +1,4 @@
+
+#!/bin/sh
+/usr/gnu/bin/gs -dNOPAUSE -r300 -q -sDEVICE=ljet3 -sOutputFile=- -f -
+
diff --git a/contrib/Makefile b/contrib/Makefile
index c1625896c8f4..24d96987e809 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.3 1993/12/21 21:18:14 wollman Exp $
+# $Id: Makefile,v 1.5 1994/06/15 21:08:47 jkh Exp $
-SUBDIR= tcpdump xntpd
+SUBDIR= crunch manctl tcpdump xntpd
# Not ported: isode
diff --git a/contrib/adduser/AddIt b/contrib/adduser/AddIt
new file mode 100755
index 000000000000..64f6f945013b
--- /dev/null
+++ b/contrib/adduser/AddIt
@@ -0,0 +1,249 @@
+#!/usr/local/bin/perl
+
+# Copyright (c) 1994 GB Data Consulting
+# All rights reserved.
+# VERSION 0.8 BETA
+# 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. The name of the Author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+# 4. This license extends only to beta and network distributed versions.
+# All even number versions are non-network.
+# THIS SOFTWARE IS PROVIDED BY GB DATA 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 GB DATA 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.
+
+# You will need to define these if you wish to have defaults or use
+# that function.
+
+$defgroupid = 30; # Default ID
+$defusrdir = "\/usr\/u"; # Default User Dir
+$usequota = ""; # Use quotas
+$usemail = ""; # Use mailings
+$mailfile = ""; # File to use with mailings
+$userdefshell = "\/bin\/csh"; # Default user shell
+$useforward = ""; # Use a forward file
+$protouser= ""; # Prototypical user for quotas
+
+# Start getting information and print a banner
+
+print " AddIt\n";
+print " A system utility for adding users with defaults\n";
+print " Copyright 1994 GB Data Consulting\n";
+print "\n\n";
+
+#
+# User ID
+#
+
+print "Please enter the login name of the user: ";
+chop ($userlogin = <STDIN>);
+print "Please enter the user id or hit enter for the next id: ";
+chop ($userid = <STDIN>);
+
+if (!$userid) {
+ open (USERID, "+<userids");
+ chop ($xxuserid = <USERID>);
+ $userid = $xxuserid + 1;
+ close USERID;
+ open (USERID, "+>userids");
+ print (USERID "$userid\n");
+ close USERID;
+ }
+
+#
+# Group ID
+#
+
+print "Please enter the group id or hit enter for the default id: ";
+chop ($groupid = <STDIN>);
+
+if (!$groupid) {
+$groupid = "$defgroupid";
+}
+
+#
+# User name
+#
+
+print "Please enter the user's name: ";
+chop ($username = <STDIN>);
+
+#
+# Home directory
+#
+
+print "Please enter the users home directory or hit enter for default: ";
+chop ($userdir = <STDIN>);
+
+if (!$userdir) {
+ $userdir = "$defusrdir\/$userlogin";
+ print "$userdir\n";
+}
+
+#
+# Login Shell
+#
+
+print "Please enter the users login shell or hit enter for default: ";
+chop ($usershell = <STDIN>);
+
+if (!$usershell) {
+ $usershell = "$userdefshell";
+ print "$usershell\n";
+}
+
+#
+# Create password file entry
+#
+
+print "Opening and locking passwd file in blocking mode.\n";
+open (PASS, '>>/etc/master.passwd');
+flock (PASS, 2) || die "Can't lock passwd file, must be in use!!\n";
+print (PASS "$userlogin::$userid:$groupid::0:0:$username,,,:$userdir:$usershell\n");
+print "Unlocking and closing password file\n";
+flock (PASS,8);
+close PASS;
+print "Re-indexing password databases\n";
+system 'pwd_mkdb -p /etc/master.passwd';
+system "passwd $userlogin";
+
+#
+# Create user directory
+#
+print "Creating user directory\n";
+if (! -e $defusrdir)
+ {
+ print "$defusrdir does not exist, exiting!\n";
+ exit;
+ }
+system "mkdir $userdir";
+if (! -e $userdir)
+ {
+ print "$userdir does not exist!!\n";
+ print "This may be due to a parent dir not being there...\n";
+ exit;
+ }
+
+print "Copying user shell files\n";
+system "cp dot.login $userdir\/\.login";
+system "cp dot.profile $userdir\/\.profile";
+
+if ($usershell eq "\/bin\/csh" || $usershell eq "\/usr\/local\/bin\/tcsh")
+ {
+ system "cp dot.cshrc $userdir\/.cshrc";
+ }
+system "chmod -R 654 $userdir";
+system "chown -R $userid.$groupid $userdir";
+
+#
+# Mailings
+#
+if ($usemail)
+ {
+ print "Mailing new user notice\n";
+ system "elm \-s \"New User Mailing\" $userid $mailfile";
+ }
+
+#
+# Quotas
+#
+if ($usequota)
+ {
+ print "Editing quotas for user $userlogin\n";
+ if ($protouser) {
+ system "edquota -u -p $protouser $userlogin";
+ } else {
+ system "edquota -u $userlogin";
+ }
+}
+
+#
+# Forward files
+#
+if ($useforward)
+ {
+ print "Please enter the name of the account to forward to:";
+ chop ($account = <STDIN>);
+ if (!$account)
+ {
+ $acc = $defaccount;
+ }
+ else
+ {
+ $acc = $account;
+ }
+ print "Please enter the name of the system to forward to:";
+ chop ($system = <STDIN>);
+ if (!$system)
+ {
+ $sys = $defsystem;
+ }
+ else
+ {
+ $sys = $system;
+ }
+ print "Creating \.forward file for user $userlogin\n";
+ open (FORWARD, ">$userdir\/\.forward");
+ print (FORWARD "$acc@$sys\n");
+ close FORWARD;
+ system "chown $userid\.$groupid $userdir\/\.forward";
+}
+
+#
+# Print out information used in creation of this account
+#
+print "\n\n";
+print "Information used to create this account follows.\n";
+print "\n";
+print "Login Name: $userlogin\n";
+print "UserId: $userid\n";
+print "GroupId: $groupid\n";
+print "UserName: $username\n";
+print "HomeDir: $userdir\n";
+print "Shell: $usershell\n";
+if ($usemail)
+ {
+ $mailyn = "Using mailing";
+ }
+else
+ {
+ $mailyn = "Not using mailing";
+ }
+print "Mailing: $mailyn\n";
+if ($usequota)
+ {
+ $quotayn = "Using quotas";
+ }
+else
+ {
+ $quotayn = "Not using quotas";
+ }
+print "Quotas: $quotayn\n";
+if ($useforward)
+ {
+ $forwardyn = "forwarded to $acc@$sys";
+ }
+else
+ {
+ $forwardyn = "Not using forward file";
+ }
+print "ForwardFile: $forwardyn\n";
+print "\nDONE\n\n";
+
+
+
diff --git a/contrib/adduser/README b/contrib/adduser/README
new file mode 100644
index 000000000000..7ac1013e3f00
--- /dev/null
+++ b/contrib/adduser/README
@@ -0,0 +1,40 @@
+ AddIt
+ Version 0.8-Beta
+
+
+This is the README file for AddIt version 0.8Beta. AddIt is a
+perl script that is intended to make adding a user to the system simple
+and easy. Installation and use are very easy and directions follow.
+
+1. Un-tar the distribution on your system. It must have its own directory
+ due to other files it uses.
+2. Use vi to edit the userids file if your planning on using the auto id
+ option of the system. Make the userid one lower than what you want
+ to start at.
+3. Edit AddIt itself to configure the following options for use with the
+ system.
+
+ A. $defgroupid: This is the default group id the system will use.
+ B. $defusrdir: This is the default place for the system to create
+ user directories and copy needed files.
+ C. $usequota: Define this variable if you wish to use quotas on your
+ system. Make sure that you have a kernel that has this defined.
+ D. $usemail: Define this variable if you wish to have a flyer
+ mailed to the user after account creation.
+ E. $usedefshell: Define this to be the default shell on your system.
+ F. $useforward: Define this variable if you wish to have .forward
+ files created for use on the system.
+ G. $protouser: Define this variable to be the proto user for use with
+ quotas.
+ H. $mailfile: This is the file to mail to a new user when $usemail is
+ defined.
+
+5. Make sure that the default user directory ($defusrdir) exists.
+6. Run AddIt. The program will ask you questions about the user and
+ automaticly create their directory, copy startup files and then
+ do other things depending on how you have the system configured.
+
+
+As normal sugestions and bug reports to bugs@radon.gbdata.com.
+
+
diff --git a/contrib/adduser/dot.cshrc b/contrib/adduser/dot.cshrc
new file mode 100644
index 000000000000..d1e8a36ee1e4
--- /dev/null
+++ b/contrib/adduser/dot.cshrc
@@ -0,0 +1,27 @@
+# .cshrc initialization
+
+alias df df -k
+alias du du -k
+alias f finger
+alias h 'history -r | more'
+alias j jobs -l
+alias la ls -a
+alias lf ls -FA
+alias ll ls -lgsA
+alias su su -m
+alias tset 'set noglob histchars=""; eval `\tset -s \!*`; unset noglob histchars'
+alias x exit
+alias z suspend
+
+set path = (~/bin /bin /usr/{bin,new,games,local,old} .)
+
+if ($?prompt) then
+ # An interactive shell -- set some stuff up
+ set filec
+ set history = 1000
+ set ignoreeof
+ set mail = (/var/mail/$USER)
+ set mch = `hostname -s`
+ set prompt = "$mch:q:$cwd:t {\!} "
+ umask 2
+endif
diff --git a/contrib/adduser/dot.login b/contrib/adduser/dot.login
new file mode 100644
index 000000000000..bdbc7506830f
--- /dev/null
+++ b/contrib/adduser/dot.login
@@ -0,0 +1,15 @@
+#csh login file
+
+if ( ! $?TERMCAP ) then
+ tset -Q '-mdialup:?vt100' $TERM
+endif
+
+stty newcrt crterase
+
+set savehist=100
+set ignoreeof
+
+setenv EXINIT 'set ai sm noeb'
+setenv HOSTALIASES $HOME/.hostaliases
+
+/usr/games/fortune
diff --git a/contrib/adduser/dot.profile b/contrib/adduser/dot.profile
new file mode 100644
index 000000000000..95ed15cdc5ba
--- /dev/null
+++ b/contrib/adduser/dot.profile
@@ -0,0 +1,2 @@
+PATH=/bin:/usr/bin:/usr/new:/usr/local:/usr/games:/usr/old:.
+export PATH HOME TERM
diff --git a/contrib/adduser/userids b/contrib/adduser/userids
new file mode 100644
index 000000000000..2bc4cd64b870
--- /dev/null
+++ b/contrib/adduser/userids
@@ -0,0 +1 @@
+510
diff --git a/contrib/configit/ConfigIt b/contrib/configit/ConfigIt
new file mode 100755
index 000000000000..0899cba4faad
--- /dev/null
+++ b/contrib/configit/ConfigIt
@@ -0,0 +1,761 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1994 GB Data Consulting
+# 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. The name of the Author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+# 4. This license extends only to network distributed versions.
+# All even number versions are non-network.
+# THIS SOFTWARE IS PROVIDED BY GB DATA 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 GB DATA 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.
+#
+#
+#
+#
+# $Id: ConfigIt,v 1.2 1994/05/02 06:57:47 gclarkii Exp $
+#
+
+&config;
+&standard_devices;
+&menu;
+
+sub menu {
+system "clear";
+
+print " ConfigIt!\n";
+print " A auto-configuration system\n";
+print "\n\n\n";
+
+print " 1 Disk devices\n";
+print " 2 Serial devices\n";
+print " 3 Network devices\n";
+print " 4 Console devices\n";
+print " 5 Tape devices\n";
+print " 6 Misc devices and options\n";
+print " 7 Parallel devices\n";
+print "\n\n";
+print "Please enter you choice or q to quit: ";
+chop ($choice = <STDIN>);
+
+if ($choice eq ('q' || 'Q'))
+ {
+ print (CONFIG "\n\n\n");
+ close CONFIG;
+ exit; }
+ elsif ($choice == 1)
+ { &disk_devices; }
+ elsif ($choice == 2 && !$serdevsflag)
+ { &serial_devices; }
+ elsif ($choice == 3 && !$netdevsflag)
+ { &network_devices; }
+ elsif ($choice == 4)
+ { &console_devices; }
+ elsif ($choice == 5)
+ { &tape_devices; }
+ elsif ($choice == 6)
+ { &misc_dev_option; }
+ elsif ($choice == 7)
+ { &parallel_ports; }
+ else
+ { &menu; }
+&menu;
+
+}
+
+
+sub config {
+system "clear";
+print " ConfigIt!\n";
+print " A Auto-configuration System\n\n";
+print "Please enter the name of your system: ";
+chop ($systemname = <STDIN>);
+$systemname =~ tr/a-z/A-Z/;
+open (CONFIG, ">>$systemname");
+
+}
+
+
+sub config_serial_devices {
+print (CONFIG "\n#Multi-port Config\n");
+print "Multi-port Comm-Cards are not supported at this time....\n\n";
+sleep 3;
+
+}
+
+
+sub console_devices {
+system "clear";
+print " Console Devices\n\n";
+print " 1 Syscons\n";
+print " 2 Pccons\n";
+print "\n\n\n";
+print "Please enter your choice (q or Q to quit): ";
+chop ($cdevs = <STDIN>);
+
+if ($cdevs == 1 && !$condevsflag)
+ { &syscons; }
+elsif ($cdevs == 2 && !$condevsflag)
+ { &pccons; }
+elsif ($cdevs eq 'q')
+ { return; }
+elsif ($cdevs eq 'Q')
+ { return; }
+else {
+ &console_devices; }
+}
+
+
+
+sub disk_devices {
+
+ system "clear";
+ local ($choice);
+ print " Disk Device Sub-section\n\n";
+ print " 1 WD drives\n";
+ print " 2 SCSI drives\n";
+ print " 3 Floppy & QIC-40/80 Drives\n";
+ print " 4 Mitsumi CD-ROM Drive\n";
+ print "\n\n";
+ print "Please enter your choice: ";
+ chop ($choice = <STDIN>);
+
+ if ($choice eq ('q' || 'Q'))
+ { return; }
+ elsif ($choice == 1 && !$wdflag)
+ { &wd_drives; }
+ elsif ($choice == 2 && !$scsidevflag)
+ { &scsi_drives; }
+ elsif ($choice == 3 && !$floppyflag)
+ { &floppy_drives; }
+ elsif ($choice == 4 && !$mitsumiflag)
+ { &mitsumi_drive; }
+ else
+ { &disk_devices; }
+}
+
+
+sub doonecard {
+$cardnum = @_[0];
+
+system "clear";
+print " 1 AT&T EN100/STARLAN 10\n";
+print " 2 ISOLAN AT 4141-0\n or ISOLINK 4110\n";
+print " 3 WD/SMC 8003 & 8013\n";
+print " 4 SMC Ultra Elite 16\n";
+print " 5 3com 3c503\n";
+print " 6 NE1000/NE2000\n";
+print "\n\nPlease enter the type of network card number $cardnum : ";
+chop ($netcardchoice = <STDIN>);
+print "Please enter the port (in hex) address of the card: ";
+chop ($netcardadd = <STDIN>);
+print "Please enter the irq of the card: ";
+chop ($netcardirq = <STDIN>);
+
+if ($netcardchoice != 2)
+ { print "Please enter the I/O mem of the card: ";
+ chop ($netcardiomem = <STDIN>);
+ }
+
+if ($netcardchoice != (2 || 1))
+ {
+ if ($ednum < 1) {
+ $cardty = 'ed0';
+ $ednum++;
+ } else {
+ $cardty = "ed$ednum";
+ $ednum++;
+ }
+ $interp = 'edintr';
+ }
+
+if ($netcardchoice == 2)
+ {
+ if ($isnum < 1) {
+ $cardty = 'is0';
+ $isnum++;
+ } else {
+ $cardty = "is$isnum";
+ $isnum++;
+ }
+ $interp = 'isintr';
+ }
+
+if ($netcardchoice == 1)
+ {
+ if ($ienum < 1) {
+ $cardty = 'ie0';
+ $ienum++;
+ } else {
+ $cardty = "ie$ienum";
+ $ienum++
+ }
+ $interp = 'ieintr';
+ }
+
+print (CONFIG "device $cardty at isa? port $netcardadd net irq $netcardirq iomem $netcardiomem vector $interp\n");
+
+}
+
+
+sub floppy_drives
+{
+$floppyflag = 1;
+system "clear";
+print (CONFIG "\n#Disk devices\n\n");
+
+print "How many floppys do you have?: ";
+chop ($flch = <STDIN>);
+if ($flch > 0)
+ {
+ print (CONFIG "controller fdc0 at isa? port \"IO_FD1\" bio irq 6 drq 2 vector fdintr\n");
+ print (CONFIG "disk fd0 at fdc0 drive 0\n");
+ print (CONFIG "disk fd1 at fdc0 drive 1\n");
+ }
+if ($flch > 0)
+ {
+ print "Do you have a QIC-40/80 drive?: ";
+ chop ($qic40 = <STDIN>);
+ if ($qic40 eq 'y' || $qic40 eq 'Y')
+ {
+ print (CONFIG "tape ft0 at fdc0 drive 2\n");
+ }
+ }
+}
+
+
+sub misc_dev_option {
+system "clear";
+$miscdevflag = 1;
+print (CONFIG "\n# Misc Devices\n");
+print "Do you want kernel tracing?: ";
+chop ($ktrace = <STDIN>);
+if ($ktrace eq ('y' || 'Y'))
+ {
+ print (CONFIG "options KTRACE\n");
+ }
+print "Do you want kernel debugging?: ";
+chop ($kddb = <STDIN>);
+if ($kddb eq ('y' || 'Y'))
+ {
+ print (CONFIG "pseudo-device ddb\n");
+ }
+print "Do you want fast symlinks?: ";
+chop ($fastlinks = <STDIN>);
+if ($fastlinks eq ('y' || 'Y'))
+ {
+ print (CONFIG "options FASTLINKS\n");
+ }
+print "Do you want PC file system support?: ";
+chop ($pcfs = <STDIN>);
+if ($pcfs eq ('y' || 'Y'))
+ {
+ print (CONFIG "options PCFS\n");
+ }
+print "Do you want Memory File System support?: ";
+chop ($mfs = <STDIN>);
+if ($mfs eq ('y' || 'Y'))
+ {
+ print (CONFIG "options MFS\n");
+ }
+print "Do you want QUOTA support?: ";
+chop ($quota = <STDIN>);
+if ($quota eq ('y' || 'Y'))
+ {
+ print (CONFIG "options QUOTA\n");
+ }
+print "Do you want FIFO support?: ";
+chop ($fifo = <STDIN>);
+if ($fifo eq ('y' || 'Y'))
+ {
+ print (CONFIG "options FIFO\n");
+ }
+print "Do you want ISO File System support?: ";
+chop ($isofs = <STDIN>);
+if ($isofs eq ('y' || 'Y'))
+ {
+ print (CONFIG "options ISOFS\n");
+ }
+
+}
+
+
+sub mitsumi_drive {
+system "clear";
+$mitsumiflag = 1;
+print (CONFIG "\n#Disk devices\n\n");
+
+print "What address (hex) is the mitsumi controller at?: ";
+chop ($mitadd = <STDIN>);
+print "What interupt is the mitsumi controller at?: ";
+chop ($mitint = <STDIN>);
+print (CONFIG "device mcd at isa? port $mitadd bio irq $mitint vector mcdint\n");
+}
+
+#
+# Multi-port support for serial_devices.pl
+#
+# $Id: ConfigIt,v 1.2 1994/05/02 06:57:47 gclarkii Exp $
+#
+
+
+sub multiport {
+$numstandm = @_[0];
+system "clear";
+print "NOTE: Only 1 multiport card is supported by ConfigIt.\n";
+print "Please enter the number of ports on the card: ";
+ chop ($multinum = <STDIN>);
+print "Please enter the starting port of the card: ";
+ chop ($startm = <STDIN>);
+print "Please enter the port number of the master port or 0 if none: ";
+ chop ($multimaster = <STDIN>);
+print "Please enter the intrupt of the card: ";
+ chop ($multiint = <STDIN>);
+print (CONFIG "\n#Multi-port serial devices\n\n");
+print (CONFIG "options \"COM_MULTIPORT\"\n");
+
+$portm = $startm;
+$startm =~ tr/a-z/A-Z/;
+
+ for ($i = 1; $i < $multinum + 1; $i++) {
+ $siom = $i + $numstandm;
+ $siom = $siom - 1;
+ if ($siom < 10) { $sio = "sio0"; } else { $sio = "sio"; }
+
+ if ($multimaster != $i) {
+ print (CONFIG "device $sio$siom at isa? port $portm flags 0x501 vector siointr\n");
+ } else {
+ print (CONFIG "device $sio$siom at isa? port $portm tty irq $multiint flags 0x501 vector siointr\n");
+ }
+$portm =~ tr/A-Z/a-z/;
+$numorig = hex ("$portm");
+$numadd = hex ("0x08");
+$numend = $numadd + $numorig;
+$endm = sprintf ("%lx", $numend);
+$end1m = $endm;
+$portm = "0x$end1m";
+$portm =~ tr/a-z/A-Z/;
+
+ }
+if ($numstandm > 0) { &standard_serial; }
+}
+
+sub network_devices {
+system "clear";
+$netdevsflag = 1;
+print (CONFIG "\n# Network devices\n");
+print "How many networking cards do you have: ";
+chop ($numnet = <STDIN>);
+
+if ($numnet != 0) {
+for ($i = 1; $i <= $numnet ; $i++)
+{
+ &doonecard($i);
+ }
+}
+
+print "Do you need the SLIP device in the kernel?: ";
+chop ($slipch = <STDIN>);
+if ($slipch eq ('y' || 'Y'))
+ {
+ print "How many slip devices do you need: ";
+ chop ($slipno = <STDIN>);
+ print (CONFIG "pseudo-device slip $slipno\n");
+ }
+
+print "Do you need the PPP device in the kernel?: ";
+chop ($pppch = <STDIN>);
+if ($pppch eq ('y' || 'Y'))
+ {
+ print "How many PPP devices do you need: ";
+ chop ($pppno = <STDIN>);
+ print (CONFIG "pseudo-device ppp $pppno\n");
+ }
+
+print "Do you want Berkeley Packet Filter support?: ";
+chop ($bpf = <STDIN>);
+if ($bpf eq ('y' || 'Y'))
+ {
+ print (CONFIG "pseudo-device bpf\n");
+ }
+
+print "Do you want Internetwork Gateway support?: ";
+chop ($gateway = <STDIN>);
+if ($gateway eq ('y' || 'Y'))
+ {
+ print (CONFIG "option GATEWAY\n");
+ }
+
+print "Do you want NFS support?: ";
+chop ($nfs = <STDIN>);
+if ($nfs eq ('y' || 'Y'))
+ {
+ print (CONFIG "option NFS\n");
+ }
+
+print "How many pty's do you want?: ";
+chop ($ptyno = <STDIN>);
+if ($ptyno eq ('y' || 'Y'))
+ {
+ print (CONFIG "pseudo-device pty $ptyno\n");
+ }
+
+}
+
+
+#
+#
+#
+
+sub parallel_ports {
+
+print "How many parallel ports do you have: ";
+ chop ($paranum = <STDIN>);
+
+if ($paranum) {
+print (CONFIG "\n#Parallel devices\n\n");
+
+for ($i = 1; $i <= $paranum; $i++) {
+ $lpanum = $i - 1;
+ print "Please enter the address for parallel port number $i : ";
+ chop ($paraport = <STDIN>);
+ print "If you are running with out interupts on this port please\n";
+ print "anwser 0 to the following question.\n";
+ print "Please enter the interupt for parallel port number $i : ";
+ chop ($paraint = <STDIN>);
+ if ($paraint) {
+ print (CONFIG "device lpa$lpanum at isa? port $paraport tty irq $paraint vector lptintr\n");
+ } else {
+ print (CONFIG "device lpa$lpanum at isa? port $paraport tty vector lptintr\n");
+ }
+
+ }
+
+ }
+
+}
+
+sub pccons {
+$condevsflag = 1;
+print (CONFIG "\n# Console devices\n\n");
+print (CONFIG "device pc0 at isa? port \"IO_KBD\" tty irq 1 vector pcrint\n");
+
+}
+
+
+sub scsi_drives {
+$scsidevsflag = 1;
+system "clear";
+print (CONFIG "\n# SCSI Devices\n\n");
+print " 1 Adaptec 1542/Bustec 542\n";
+print " 2 Adaptec 1742\n";
+print " 3 Bustec 742\n";
+print " 4 Ultrastore 14F/34F\n";
+print "\n\n";
+print "Enter your choice or q to quit: ";
+chop ($scsicho = <STDIN>);
+
+if ($scsicho eq 'q' || $scsicho eq 'Q')
+ {
+ return;
+ }
+elsif ($scsicho == 1)
+ {
+ $scsicard = "aha0";
+ $scsiio = "\"IO_AHA0\"";
+ $scsiint = "ahaintr";
+ }
+elsif ($scsicho == 2)
+ {
+ $scsicard = "ahb0";
+ $scsiint = "ahbintr";
+ }
+elsif ($scsicho == 3)
+ {
+ $scsicard = "bt0";
+ $scsiio = "\"IO_BT0\"";
+ $scsiint = "btintr";
+ }
+elsif ($scsicho == 4)
+ {
+ $scsicard = "uha0";
+ $scsiio = "\"IO_UHA0\"";
+ $scsiio = "uhaintr";
+ }
+else { &scsi_drives; }
+
+if ($scsicho == 2)
+ {
+ print "Please enter the interupt the AHA-1742 is on: ";
+ chop ($scsiirq = <STDIN>);
+ print (CONFIG "contoller ahb0 at isa? bio irq $scsiirq vector $scsiint\n");
+ }
+elsif ($scsicho == 1 || $scsicho == 4)
+ {
+ print "Please enter the interupt the SCSI controller is on: ";
+ chop ($scsiirq = <STDIN>);
+ print "Please enter the dma channel the SCSI controller is on: ";
+ chop ($scsidrq = <STDIN>);
+ print (CONFIG "controller $scsicard at isa? port $scsiio bio irq $scsiirq drq $scsidrq vector $scsiint\n");
+ }
+else
+ {
+ print "Please enter the interupt the SCSI controller is on: ";
+ chop ($scsiirq = <STDIN>);
+ print (CONFIG "controller $scsicard at isa? port $scsiio bio irq $scsiirq vector $scsiint\n");
+ }
+
+print (CONFIG "device sd0\n");
+print (CONFIG "device sd1\n");
+print (CONFIG "device sd2\n");
+print (CONFIG "device sd3\n");
+print (CONFIG "device st1\n");
+print (CONFIG "device st2\n");
+print (CONFIG "device cd0\n");
+
+}
+
+#
+# Do serial ports, only standard ones are here
+#
+#
+
+sub serial_devices {
+system "clear";
+$serdevsflag = 1;
+
+print "Do you have a multi-port card (Non-standard serial card): ";
+ chop ($multicard = <STDIN>);
+print "Please enter the number of standard serial ports you have: ";
+ chop ($numstand = <STDIN>);
+
+ if ($multicard eq ( 'y' || 'Y')) {
+ print "Please enter the number of standard serial ports you also have: ";
+ &multiport($numstand);
+ } else {
+ &standard_serial($numstand);
+ }
+print "Do you wish to have bidirectionl serial ports: ";
+ chop ($bidir = <STDIN>);
+ if ($bidir eq ('y' || 'Y')) {
+ print (CONFIG "options \"COM_BIDIR\"\n");
+ }
+}
+
+
+sub standard_devices {
+system "clear";
+print "What timezone are you in? (cst = 6): ";
+chop ($time = <STDIN>);
+print "What type of cpu do you have? ( 386 or 486 ): ";
+chop ($cputype = <STDIN>);
+
+if ($cputype == 386)
+ {
+ print "Do you have a 387?: ";
+ chop ($mathco = <STDIN>);
+ }
+
+if ($cputype == 486)
+ {
+ print "Is it a DX or SX?: ";
+ chop ($dxsx = <STDIN>);
+ if ($dxsz eq 'SX' || $dxsx eq 'sx')
+ {
+ $mathco = 'n';
+ }
+ }
+
+chop ($date = `date`);
+chop ($whoami = `whoami`);
+
+print (CONFIG "\n#\n#Config file for $systemname\n");
+print (CONFIG "#Generated by ConfigIt!\n");
+print (CONFIG "#Generated at $date by $whoami\n#\n#\n\n");
+
+print (CONFIG "#Generic Items\n\n");
+print (CONFIG "machine \"i386\"\n");
+print (CONFIG "cpu \"I","$cputype","_CPU\"\n");
+
+if ($mathco eq 'n' || $mathco eq 'N')
+ {
+ print "Do you wish to use the new math emulator (its better): ";
+ chop ($choicesti = <STDIN>);
+ if ($choicesti eq ('y' || 'Y')) {
+ print (CONFIG "options GPL_MATH_EMULATE\n");
+ } else {
+ print (CONFIG "options MATH_EMULATE\n");
+ }
+}
+
+print "The following is used to set certain parameters.\n";
+print "Please enter the number of users you expect: ";
+ chop ($maxusers = <STDIN>);
+if ($maxusers <= 10) { $maxusers = 10; }
+print (CONFIG "ident $systemname\n");
+print (CONFIG "maxusers $maxusers\n");
+print (CONFIG "maxfdescs 2000\n");
+print (CONFIG "timezone $time dst\n");
+print (CONFIG "options \"COMPAT_43\"\n");
+print (CONFIG "options UCONSOLE\n");
+print (CONFIG "options XSERVER\n");
+print (CONFIG "options INET\n");
+print "What device is root on? (e.g. \"wd0\"): ";
+chop ($root = <STDIN>);
+if ($root) {
+$roots = "root on $root";
+} else { print "ABORTING you must have a root!\n"; exit; }
+
+print "What device is swap on? (e.g. \"wd0\" or \"wd0 and wd1\"): ";
+chop ($swap = <STDIN>);
+if ($swap) {
+$swaps = "swap on $swap";
+}
+print "What device is dump on? (e.g. \"wd0\"): ";
+chop ($dump = <STDIN>);
+if ($dumps) {
+$dumps = "dumps on $dump";
+}
+
+print (CONFIG "config \"386bsd\" $roots $swaps $dumps \n");
+print (CONFIG "pseudo-device vnodepager\n");
+print (CONFIG "pseudo-device swappager\n");
+print (CONFIG "pseudo-device devpager\n");
+print (CONFIG "pseudo-device ether\n");
+print (CONFIG "pseudo-device loop\n");
+print (CONFIG "pseudo-device log\n");
+print (CONFIG "pseudo-device speaker\n");
+print (CONFIG "device isa0\n");
+
+}
+
+
+#
+# Do standard serial ports
+#
+
+sub standard_serial {
+$sernumss = @_[0];
+
+ print "Are the $sernumss standard ports at the standard location and interup: ";
+ chop ($standss = <STDIN>);
+if ($standss eq ('y' || 'Y')) {
+
+ if ($sernumss == 0 || $sernumss > 4)
+ { print "invalid number of serial ports!!\n\n";
+ print "Please hit any key to continue.";
+ while (!($kbhit = <STDIN>)) {}
+ &serial_devices;}
+
+ if ($sernumss < 3) {
+ print (CONFIG "\n#Standard serial devices\n\n");
+ print (CONFIG "device sio00 at isa? port \"IO_COM1\" tty irq 4 vector siointr\n");
+ print (CONFIG "device sio01 at isa? port \"IO_COM2\" tty irq 3 vector siointr\n");
+ } else {
+ print (CONFIG "\n#Standard serial devices\n\n");
+ print (CONFIG "device sio00 at isa? port \"IO_COM1\" tty irq 4 vector siointr\n");
+ print (CONFIG "device sio01 at isa? port \"IO_COM2\" tty irq 3 vector siointr\n");
+ print (CONFIG "device sio02 at isa? port \"IO_COM3\" tty irq 5 vector siointr\n");
+ print (CONFIG "device sio03 at isa? port \"IO_COM4\" tty irq 9 vector siointr\n"); }
+
+} else {
+ print (CONFIG "\n#Standard serial devices\n\n");
+
+ for ($i = 1;$i <= $sernum;$i++) {
+ print "Please enter the intrupt for serial port number $i: ";
+ chop ($intt = <STDIN>);
+ print "Please enter the address for serial port number $i: ";
+ chop ($portk = <STDIN>);
+ $iik = $i - 1;
+ print (CONFIG "device sio0$iik at isa port $portk tty irq $intt vector siointr\n");
+
+ }
+ }
+}
+
+
+
+sub syscons {
+print (CONFIG "\n#Console device\n");
+
+$condevsflag = 1;
+system "clear";
+print (CONFIG "device sc0 at isa? port \"IO_KBD\" tty irq 1 vector scintr\n");
+print "How many virtual terminals do you want? (max 8): ";
+chop ($numvty = <STDIN>);
+if ($numvty == 0 || $numvty > 8)
+ { $numvty = 1; }
+print (CONFIG "options \"NCONS=$numvty\"\n");
+print (CONFIG "options \"STAR_SAVER\"\n");
+print (CONFIG "options \"FADE_SAVER\"\n");
+print (CONFIG "options \"SNAKE_SAVER\"\n");
+print (CONFIG "options \"BLANK_SAVER\"\n");
+
+}
+
+
+sub tape_devices
+{
+system "clear";
+print (CONFIG "\n# QIC-02 Tape devices\n\n");
+$tapdevsflag = 1;
+print "Do you have a QIC-02 tape drive?: ";
+chop ($qic02 = <STDIN>);
+if ($qic02 eq ('y' || 'Y'))
+ {
+print "What address is it at? (Hex): ";
+chop ($qic02add = <STDIN>);
+print "What interupt is it at?: ";
+chop ($qic02int = <STDIN>);
+print (CONFIG "device wt0 at isa? port $qic02add bio irq $qic02int drq 1 vector wtintr\n");
+ }
+}
+
+
+sub wd_drives {
+ $wdflag = 1;
+ local ($choice);
+ system "clear";
+ print (CONFIG "\n#Disk devices\n\n");
+
+ print " WD Drive Configuration\n\n";
+ print "How many WD drives do you have (Max of 4): ";
+ chop ($choice = <STDIN>);
+
+ if ($choice >= 3 ) {
+ print "\n";
+ print (CONFIG "controller wdc0 at isa? port \"IO_WD1\" bio irq 14 vector wdintr\n");
+ print "\n";
+ print (CONFIG "disk wd0 at wdc0 drive 0\n");
+ print (CONFIG "disk wd1 at wdc1 drive 1\n");
+ print (CONFIG "controller wdc1 at isa? port \"IO_WD2\" bio irq 15 vector wdintr\n");
+ print (CONFIG "disk wd2 at wdc1 drive 0\n");
+ print (CONFIG "disk wd3 at wdc1 drive 1\n");
+ print "\n";
+ } else {
+ print "\n";
+ print (CONFIG "controller wdc0 at isa? port \"IO_WD1\" bio irq 14 vector wdintr\n");
+ print "\n";
+ print (CONFIG "disk wd0 at wdc0 drive 0\n");
+ print (CONFIG "disk wd1 at wdc0 drive 1\n");
+ print "\n";
+ }
+}
+
diff --git a/contrib/configit/README b/contrib/configit/README
new file mode 100644
index 000000000000..cf3481d06846
--- /dev/null
+++ b/contrib/configit/README
@@ -0,0 +1,32 @@
+
+
+
+This is the README file for ConfigIt!, a kernel configuration file generator
+for FreeBSD 1.1Beta and above. ConfigIt! is a menu driven program that
+askes what options and devices you want in your kernel. For more information
+on what the various options and devices are please see the file options.texi
+in /sys/i386/doc.
+
+To run ConfigIt! you must have Perl 4.036 (It has not been tested with Perl 5).
+
+Steps needed to run ConfigIt!:
+1. Make sure that you have Perl installed on your system.
+2. Untar the archive in the directory where you wish to run it.
+3. Run the program.
+4. Copy the resulting config file to /sys/i386/conf.
+5. Run config SYSTEM_NAME.
+6. Change directory to /sys/compile/SYSTEM_NAME.
+7. Run make depend and then make in /sys/compile/SYSTEM_NAME.
+
+And thats it!
+
+If you have any questions, suggestions or whatever you can reach me
+at gclarkii@freefall.cdrom.com. Please DO NOT send questions about ConfigIt!
+to the mailing lists.
+
+Enjoy,
+
+Gary Clark II
+gclarkii@freefall.cdrom.com
+
+
diff --git a/contrib/configit/TODO b/contrib/configit/TODO
new file mode 100644
index 000000000000..9ab174419219
--- /dev/null
+++ b/contrib/configit/TODO
@@ -0,0 +1,9 @@
+TODO list for ConfigIt!
+Version 0.1 BETA
+
+1. Make the system more robust in taking anwsers to questions.
+2. Better SCSI support.
+3. Make it faster.
+4. Add more options that it will configure.
+5. Clean up code so that columns are lined up.
+
diff --git a/contrib/crunch/COPYRIGHT b/contrib/crunch/COPYRIGHT
new file mode 100644
index 000000000000..c7b4d2f9ae57
--- /dev/null
+++ b/contrib/crunch/COPYRIGHT
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
diff --git a/contrib/crunch/Makefile b/contrib/crunch/Makefile
new file mode 100644
index 000000000000..a38e0b9061df
--- /dev/null
+++ b/contrib/crunch/Makefile
@@ -0,0 +1,4 @@
+
+SUBDIR=crunchgen crunchide
+
+.include <bsd.subdir.mk>
diff --git a/contrib/crunch/Makefile.inc b/contrib/crunch/Makefile.inc
new file mode 100644
index 000000000000..da4210505219
--- /dev/null
+++ b/contrib/crunch/Makefile.inc
@@ -0,0 +1,2 @@
+# modify to taste
+BINDIR?= /usr/bin
diff --git a/contrib/crunch/README b/contrib/crunch/README
new file mode 100644
index 000000000000..27c2d0298afb
--- /dev/null
+++ b/contrib/crunch/README
@@ -0,0 +1,88 @@
+
+CRUNCH 0.2 README 6/14/94
+
+Crunch is available via anonymous ftp to ftp.cs.umd.edu in
+ pub/bsd/crunch-0.2.tar.gz
+
+
+WHAT'S NEW IN 0.2
+
+* The prototype awk script has been replaced by a more capable and
+ hopefully more robust C program.
+* No fragile template makefiles or dependencies on the details of the
+ bsd build environment.
+* You can build crunched binaries even with no sources on-line, you
+ just need the .o files. Crunchgen still will try to figure out as
+ much as possible on its own, but you can override its guessing by
+ specifying the list of .o files explicitly.
+* Crunch itself has been bmake'd and some man pages written, so it
+ should be ready to install.
+
+
+INTRODUCTION
+
+Crunch is a little package that helps create "crunched" binaries for use
+on boot, install, and fixit floppies. A crunched binary in this case is
+one where many programs have been linked together into one a.out file.
+The different programs are run depending on the value of argv[0], so
+hard links to the crunched binary suffice to simulate a perfectly normal
+system.
+
+As an example, I have created an 980K crunched "fixit" binary containing
+the following programs in their entirety:
+
+ cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+ mt mv pwd rcp rm rmdir sh sleep stty sync test [ badsect chown
+ clri disklabel dump rdump dmesg fdisk fsck halt ifconfig init
+ mknod mount newfs ping reboot restore rrestore swapon umount
+ ftp rsh sed telnet rlogin vi cpio gzip gunzip gzcat
+
+Note carefully: vi, cpio, gzip, ed, sed, dump/restore, some networking
+utilities, and the disk management utilities, all in a binary small
+enough to fit on a 1.2 MB root filesystem floppy (albeit with the kernel
+on its own boot floppy). A more reasonable subset can be made to fit
+easily with a kernel for a decent one-disk fixit filesystem.
+
+The linking together of different programs by hand is an old
+space-saving technique. Crunch automates the process by building the
+necessary stub files and makefile for you (via the crunchgen program),
+and by doctoring the symbol tables of the component .o files to allow
+them to link without "symbol multiply defined" conflicts (via the
+crunchide program).
+
+
+BUILDING CRUNCH
+
+Just type make, then make install.
+
+Crunch was written and tested under NetBSD/i386, but should work under
+other PC BSD systems that use GNU ld.
+
+The crunchgen(1) and crunchide(1) man pages have more details on using
+crunch, and the examples subdirectory contains some working .conf files
+and a sample Makefile.
+
+CREDITS
+
+Thanks to the NetBSD team for a consistently high quality effort in
+bringing together a solid, state of the art development environment.
+
+Thanks to the FreeBSD guys; Rod Grimes, Nate Williams and Jordan
+Hubbard; and to Bruce Evans, for immediate and detailed feedback on
+crunch 0.1, and for pressing me to make the prototype more useable.
+
+Crunch was written for the Maruti Hard Real-Time Operating System
+project at the University of Maryland, to help make for better install
+and recovery procedures for our NetBSD-based development environment. It
+is copyright (c) 1994 by the University of Maryland under a UCB-style
+freely- redistributable notice. See the file COPYRIGHT for details.
+
+Please let me know of any problems or of enhancements you make to this
+package. I'm particularly interested in the details of what you found
+was good to put on your fixit or install disks. Thanks!
+
+Share and Enjoy,
+Jaime
+............................................................................
+: Stand on my shoulders, : jds@cs.umd.edu : James da Silva
+: not on my toes. : uunet!mimsy!jds : http://www.cs.umd.edu/users/jds
diff --git a/contrib/crunch/crunchgen/Makefile b/contrib/crunch/crunchgen/Makefile
new file mode 100644
index 000000000000..71acb214dca0
--- /dev/null
+++ b/contrib/crunch/crunchgen/Makefile
@@ -0,0 +1,9 @@
+
+PROG=crunchgen
+SRCS=crunchgen.c crunched_skel.c
+CFLAGS+=-g -Wall
+
+crunched_skel.c: crunched_main.c
+ ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c >crunched_skel.c
+
+.include <bsd.prog.mk>
diff --git a/contrib/crunch/crunchgen/crunched_main.c b/contrib/crunch/crunchgen/crunched_main.c
new file mode 100644
index 000000000000..a07317aa5a6b
--- /dev/null
+++ b/contrib/crunch/crunchgen/crunched_main.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunched_main.c - main program for crunched binaries, it branches to a
+ * particular subprogram based on the value of argv[0]. Also included
+ * is a little program invoked when the crunched binary is called via
+ * its EXECNAME. This one prints out the list of compiled-in binaries,
+ * or calls one of them based on argv[1]. This allows the testing of
+ * the crunched binary without creating all the links.
+ */
+#include <stdio.h>
+#include <string.h>
+
+struct stub {
+ char *name;
+ int (*f)();
+};
+
+extern struct stub entry_points[];
+
+int main(int argc, char **argv)
+{
+ char *slash, *basename;
+ struct stub *ep;
+
+ if(argv[0] == NULL || *argv[0] == '\0')
+ crunched_usage();
+
+ slash = strrchr(argv[0], '/');
+ basename = slash? slash+1 : argv[0];
+
+ for(ep=entry_points; ep->name != NULL; ep++)
+ if(!strcmp(basename, ep->name)) break;
+
+ if(ep->name)
+ return ep->f(argc, argv);
+ else {
+ fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename);
+ crunched_usage();
+ }
+}
+
+
+int crunched_main(int argc, char **argv)
+{
+ struct stub *ep;
+ int columns, len;
+
+ if(argc <= 1)
+ crunched_usage();
+
+ return main(--argc, ++argv);
+}
+
+
+int crunched_usage()
+{
+ int columns, len;
+ struct stub *ep;
+
+ fprintf(stderr, "Usage: %s <prog> <args> ..., where <prog> is one of:\n",
+ EXECNAME);
+ columns = 0;
+ for(ep=entry_points; ep->name != NULL; ep++) {
+ len = strlen(ep->name) + 1;
+ if(columns+len < 80)
+ columns += len;
+ else {
+ fprintf(stderr, "\n");
+ columns = len;
+ }
+ fprintf(stderr, " %s", ep->name);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/* end of crunched_main.c */
+
diff --git a/contrib/crunch/crunchgen/crunchgen.1 b/contrib/crunch/crunchgen/crunchgen.1
new file mode 100644
index 000000000000..8c97d66cf1de
--- /dev/null
+++ b/contrib/crunch/crunchgen/crunchgen.1
@@ -0,0 +1,266 @@
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" 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, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd June 14, 1994
+.Dt CRUNCHGEN 1
+.Os BSD 4
+.Sh NAME
+.Nm \&crunchgen
+.Nd generates build environment for a crunched binary
+.Sh SYNOPSIS
+.Nm \&crunchgen
+.Op Fl fq
+.Op Fl m Ar makefile-name
+.Op Fl c Ar c-file-name
+.Op Fl e Ar exec-file-name
+.Op Ar conf-file
+.Sh DESCRIPTION
+
+A crunched binary is a program made up of many other programs linked
+together into a single executable. The crunched binary main()
+function determines which component program to run by the contents of
+argv[0]. The main reason to crunch programs together is for fitting
+as many programs as possible onto an installation or system recovery
+floppy.
+
+.Pp
+.Nm Crunchgen
+reads in the specifications in
+.Ar conf-file
+for a crunched binary, and generates a Makefile and accompanying
+top-level C source file that when built create the crunched executable
+file from the component programs. For each component program,
+.Nm crunchgen
+can optionally attempt to determine the object (.o) files that make up
+the program from its source directory Makefile. This information is
+cached between runs.
+.Nm Crunchgen
+uses the companion program
+.Nm crunchide
+to eliminate link-time conflicts between the component programs by
+hiding all unnecessary symbols.
+
+.Pp
+After
+.Nm crunchgen
+is run, the crunched binary can be built by running ``make -f
+<conf-name>.mk''. The component programs' object files must already
+be built. A ``objs'' target, included in the output makefile, will
+run make in each component program's source dir to build the object
+files for the user. This is not done automatically since in release
+engineering circumstances it is generally not desireable to be
+modifying objects in other directories.
+
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar c-file-name
+Set output C file name to
+.Ar c-file-name .
+The default name is ``<conf-name>.c''.
+.It Fl e Ar exec-file-name
+Set crunched binary executable file name to
+.Ar exec-file-name .
+The default name is ``<conf-name>''.
+.It Fl f
+Flush cache. Forces the recalculation of cached parameters.
+.It Fl m Ar makefile-name
+Set output Makefile name to
+.Ar makefile-name .
+The default name is ``<conf-name>.mk''.
+.It Fl q
+Quiet operation. Status messages are suppressed.
+.El
+.Sh CRUNCHGEN CONFIGURATION FILE COMMANDS
+
+.Nm Crunchgen
+reads specifications from the
+.Ar conf-file
+that describe the components of the crunched binary. In its simplest
+use, the component program names are merely listed along with the
+top-level source directories in which their sources can be found.
+.Nm Crunchgen
+then calculates (via the source makefiles) and caches the
+list of object files and their locations. For more specialized
+situations, the user can specify by hand all the parameters that
+.Nm crunchgen
+needs.
+.Pp
+The
+.Ar conf-file
+commands are as follows:
+.Bl -tag -width indent
+.It Nm srcdirs Ar dirname ...
+A list of source trees in which the source directories of the
+component programs can be found. These dirs are searched using the
+BSD ``<source-dir>/<progname>/'' convention. Multiple
+.Nm srcdirs
+lines can be specified. The directories are searched in the order
+they are given.
+.It Nm progs Ar progname ...
+A list of programs that make up the crunched binary. Multiple
+.Nm progs
+lines can be specified.
+.It Nm libs Ar libspec ...
+A list of library specifications to be included in the crunched binary link.
+Multiple
+.Nm libs
+lines can be specified.
+.It Nm ln Ar progname linkname
+Causes the crunched binary to invoke
+.Ar progname
+whenever
+.Ar linkname
+appears in argv[0]. This allows programs that change their behavior when
+run under different names to operate correctly.
+.El
+
+To handle specialized situations, such as when the source is not
+available or not built via a conventional Makefile, the following
+.Nm special
+commands can be used to set
+.Nm crunchgen
+parameters for a component program.
+.Bl -tag -width indent
+.It Nm special Ar progname Nm srcdir Ar pathname
+Set the source directory for
+.Ar progname .
+This is normally calculated by searching the specified
+.Nm srcdirs
+for a directory named
+.Ar progname .
+.It Nm special Ar progname Nm objdir Ar pathname
+Set the obj directory for
+.Ar progname .
+This is normally calculated by looking for a directory named
+.Dq Pa obj
+under the
+.Ar srcdir ,
+and if that is not found, the
+.Ar srcdir
+itself becomes the
+.Ar objdir .
+.It Nm special Ar progname Nm objs Ar object-file-name ...
+Set the list of object files for program
+.Ar progname .
+This is normally calculated by constructing a temporary makefile that includes
+.Dq Nm srcdir / Pa Makefile
+and outputs the value of $(OBJS).
+.It Nm special Ar progname Nm objpaths Ar full-pathname-to-object-file ...
+Sets the pathnames of the object files for program
+.Ar progname .
+This is normally calculated by prepending the
+.Nm objdir
+pathname to each file in the
+.Nm objs
+list.
+.El
+
+.Pp
+Only the
+.Nm objpaths
+parameter is actually needed by
+.Nm crunchgen ,
+but it is calculated from
+.Nm objdir
+and
+.Nm objs ,
+which are in turn calculated from
+.Nm srcdir ,
+so is sometimes convenient to specify the earlier parameters and let
+.Nm crunchgen
+calculate forward from there if it can.
+
+.Pp
+The makefile produced by
+.Nm crunchgen
+contains an optional
+.Ar objs
+target that will build the object files for each component program by
+running make inside that program's source directory. For this to work the
+.Nm srcdir
+and
+.Nm objs
+parameters must also be valid. If they are not valid for a particular program, that
+program is skipped in the
+.Ar objs
+target.
+.Sh EXAMPLE
+Here is an example
+.Nm crunchgen
+input conf file, named
+.Dq Pa kcopy.conf :
+.Pp
+.nf
+ srcdirs /usr/src/bin /usr/src/sbin
+
+ progs test cp echo sh fsck halt init mount umount myinstall
+ ln test [ # test can be invoked via [
+ ln sh -sh # init invokes the shell with "-sh" in argv[0]
+
+ special myprog objpaths /homes/leroy/src/myinstall.o # no sources
+
+ libs -lutil -lcrypt
+.fi
+.Pp
+This conf file specifies a small crunched binary consisting of some
+basic system utilities plus a homegrown install program ``myinstall'',
+for which no source directory is specified, but its object file is
+specified directly with the
+.Nm special
+line.
+.Pp
+The crunched binary ``kcopy'' can be built as follows:
+.Pp
+.nf
+ % crunchgen -m Makefile kcopy.conf # gen Makefile and kcopy.c
+ % make objs # build the component progams' .o files
+ % make # build the crunched binary kcopy
+ % kcopy sh # test that this invokes a sh shell
+ $ # it works!
+.fi
+.Pp
+At this point the binary ``kcopy'' can be copied onto an install floppy
+and hard-linked to the names of the component programs.
+.Sh SEE ALSO
+.Xr crunchide 1
+.Sh CAVEATS
+While
+.Nm crunch
+takes care to eliminate link conflicts between the component programs
+of a crunched binary, conflicts are still possible between the
+libraries that are linked in. Some shuffling in the order of
+libraries may be required, and in some rare cases two libraries may
+have an unresolveable conflict and thus cannot be crunched together.
+.Pp
+Some versions of the BSD build environment do not by default build the
+intermediate object file for single-source file programs. The ``make
+objs'' target must then be used to get those object files built, or
+some other arrangements made.
+.Sh AUTHOR
+.Nm Crunch
+was written by James da Silva <jds@cs.umd.edu>.
+.sp 0
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
diff --git a/contrib/crunch/crunchgen/crunchgen.c b/contrib/crunch/crunchgen/crunchgen.c
new file mode 100644
index 000000000000..6e9af1880dd9
--- /dev/null
+++ b/contrib/crunch/crunchgen/crunchgen.c
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * ========================================================================
+ * crunchgen.c
+ *
+ * Generates a Makefile and main C file for a crunched executable,
+ * from specs given in a .conf file.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#define CRUNCH_VERSION "0.2"
+
+#define MAXLINELEN 16384
+#define MAXFIELDS 2048
+
+
+/* internal representation of conf file: */
+
+/* simple lists of strings suffice for most parms */
+
+typedef struct strlst {
+ struct strlst *next;
+ char *str;
+} strlst_t;
+
+/* progs have structure, each field can be set with "special" or calculated */
+
+typedef struct prog {
+ struct prog *next;
+ char *name, *ident;
+ char *srcdir, *objdir;
+ strlst_t *objs, *objpaths;
+ strlst_t *links;
+ int goterror;
+} prog_t;
+
+
+/* global state */
+
+strlst_t *srcdirs = NULL;
+strlst_t *libs = NULL;
+prog_t *progs = NULL;
+
+char line[MAXLINELEN];
+
+char confname[MAXPATHLEN], infilename[MAXPATHLEN];
+char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN];
+char tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
+int linenum = -1;
+int goterror = 0;
+
+char *pname = "crunchgen";
+
+int verbose, readcache; /* options */
+int reading_cache;
+
+/* general library routines */
+
+void status(char *str);
+void out_of_memory(void);
+void add_string(strlst_t **listp, char *str);
+int is_dir(char *pathname);
+int is_nonempty_file(char *pathname);
+
+/* helper routines for main() */
+
+void usage(void);
+void parse_conf_file(void);
+void gen_outputs(void);
+
+
+int main(int argc, char **argv)
+{
+ char *p;
+ int optc;
+ extern int optind;
+ extern char *optarg;
+
+ verbose = 1;
+ readcache = 1;
+ *outmkname = *outcfname = *execfname = '\0';
+
+ if(argc > 0) pname = argv[0];
+
+ while((optc = getopt(argc, argv, "m:c:e:fq")) != -1) {
+ switch(optc) {
+ case 'f': readcache = 0; break;
+ case 'q': verbose = 0; break;
+
+ case 'm': strcpy(outmkname, optarg); break;
+ case 'c': strcpy(outcfname, optarg); break;
+ case 'e': strcpy(execfname, optarg); break;
+
+ case '?':
+ default: usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc != 1) usage();
+
+ /*
+ * generate filenames
+ */
+
+ strcpy(infilename, argv[0]);
+
+ /* confname = `basename infilename .conf` */
+
+ if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1);
+ else strcpy(confname, infilename);
+ if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0';
+
+ if(!*outmkname) sprintf(outmkname, "%s.mk", confname);
+ if(!*outcfname) sprintf(outcfname, "%s.c", confname);
+ if(!*execfname) sprintf(execfname, "%s", confname);
+
+ sprintf(cachename, "%s.cache", confname);
+ sprintf(tempfname, ".tmp_%sXXXXXX", confname);
+ if(mktemp(tempfname) == NULL) {
+ perror(tempfname);
+ exit(1);
+ }
+
+ parse_conf_file();
+ gen_outputs();
+
+ exit(goterror);
+}
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "%s [-fq] [-m <makefile>] [-c <c file>] [-e <exec file>] <conffile>\n",
+ pname);
+ exit(1);
+}
+
+
+/*
+ * ========================================================================
+ * parse_conf_file subsystem
+ *
+ */
+
+/* helper routines for parse_conf_file */
+
+void parse_one_file(char *filename);
+void parse_line(char *line, int *fc, char **fv, int nf);
+void add_srcdirs(int argc, char **argv);
+void add_progs(int argc, char **argv);
+void add_link(int argc, char **argv);
+void add_libs(int argc, char **argv);
+void add_special(int argc, char **argv);
+
+prog_t *find_prog(char *str);
+void add_prog(char *progname);
+
+
+void parse_conf_file(void)
+{
+ if(!is_nonempty_file(infilename)) {
+ fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
+ pname, infilename);
+ exit(1);
+ }
+ parse_one_file(infilename);
+ if(readcache && is_nonempty_file(cachename)) {
+ reading_cache = 1;
+ parse_one_file(cachename);
+ }
+}
+
+
+void parse_one_file(char *filename)
+{
+ char *fieldv[MAXFIELDS];
+ int fieldc;
+ void (*f)(int c, char **v);
+ FILE *cf;
+
+ sprintf(line, "reading %s", filename);
+ status(line);
+ strcpy(curfilename, filename);
+
+ if((cf = fopen(curfilename, "r")) == NULL) {
+ perror(curfilename);
+ goterror = 1;
+ return;
+ }
+
+ linenum = 0;
+ while(fgets(line, MAXLINELEN, cf) != NULL) {
+ linenum++;
+ parse_line(line, &fieldc, fieldv, MAXFIELDS);
+ if(fieldc < 1) continue;
+ if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs;
+ else if(!strcmp(fieldv[0], "progs")) f = add_progs;
+ else if(!strcmp(fieldv[0], "ln")) f = add_link;
+ else if(!strcmp(fieldv[0], "libs")) f = add_libs;
+ else if(!strcmp(fieldv[0], "special")) f = add_special;
+ else {
+ fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ if(fieldc < 2) {
+ fprintf(stderr,
+ "%s:%d: %s command needs at least 1 argument, skipping.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ f(fieldc, fieldv);
+ }
+
+ if(ferror(cf)) {
+ perror(curfilename);
+ goterror = 1;
+ }
+ fclose(cf);
+}
+
+
+void parse_line(char *line, int *fc, char **fv, int nf)
+{
+ char *p;
+
+ p = line;
+ *fc = 0;
+ while(1) {
+ while(isspace(*p)) p++;
+ if(*p == '\0' || *p == '#') break;
+
+ if(*fc < nf) fv[(*fc)++] = p;
+ while(*p && !isspace(*p) && *p != '#') p++;
+ if(*p == '\0' || *p == '#') break;
+ *p++ = '\0';
+ }
+ if(*p) *p = '\0'; /* needed for '#' case */
+}
+
+
+void add_srcdirs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++) {
+ if(is_dir(argv[i]))
+ add_string(&srcdirs, argv[i]);
+ else {
+ fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+ curfilename, linenum, argv[i]);
+ goterror = 1;
+ }
+ }
+}
+
+
+void add_progs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++)
+ add_prog(argv[i]);
+}
+
+
+void add_prog(char *progname)
+{
+ prog_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
+ if(!strcmp(p2->name, progname)) return;
+
+ p2 = malloc(sizeof(prog_t));
+ if(p2) p2->name = strdup(progname);
+ if(!p2 || !p2->name)
+ out_of_memory();
+
+ p2->next = NULL;
+ if(p1 == NULL) progs = p2;
+ else p1->next = p2;
+
+ p2->ident = p2->srcdir = p2->objdir = NULL;
+ p2->links = p2->objs = NULL;
+ p2->goterror = 0;
+}
+
+
+void add_link(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if(p == NULL) {
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping link.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+ for(i=2;i<argc;i++)
+ add_string(&p->links, argv[i]);
+}
+
+
+void add_libs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++)
+ add_string(&libs, argv[i]);
+}
+
+
+void add_special(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if(p == NULL) {
+ if(reading_cache) return;
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping special.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+
+ if(!strcmp(argv[2], "ident")) {
+ if(argc != 4) goto argcount;
+ if((p->ident = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "srcdir")) {
+ if(argc != 4) goto argcount;
+ if((p->srcdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "objdir")) {
+ if(argc != 4) goto argcount;
+ if((p->objdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "objs")) {
+ p->objs = NULL;
+ for(i=3;i<argc;i++)
+ add_string(&p->objs, argv[i]);
+ }
+ else if(!strcmp(argv[2], "objpaths")) {
+ p->objpaths = NULL;
+ for(i=3;i<argc;i++)
+ add_string(&p->objpaths, argv[i]);
+ }
+ else {
+ fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
+ curfilename, linenum, argv[2]);
+ goterror = 1;
+ }
+ return;
+
+
+ argcount:
+ fprintf(stderr,
+ "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
+ curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
+ goterror = 1;
+}
+
+
+prog_t *find_prog(char *str)
+{
+ prog_t *p;
+
+ for(p = progs; p != NULL; p = p->next)
+ if(!strcmp(p->name, str)) return p;
+
+ return NULL;
+}
+
+
+/*
+ * ========================================================================
+ * gen_outputs subsystem
+ *
+ */
+
+/* helper subroutines */
+
+void remove_error_progs(void);
+void fillin_program(prog_t *p);
+void gen_specials_cache(void);
+void gen_output_makefile(void);
+void gen_output_cfile(void);
+
+void fillin_program_objs(prog_t *p, char *path);
+void top_makefile_rules(FILE *outmk);
+void prog_makefile_rules(FILE *outmk, prog_t *p);
+void output_strlst(FILE *outf, strlst_t *lst);
+char *genident(char *str);
+char *dir_search(char *progname);
+
+
+void gen_outputs(void)
+{
+ prog_t *p;
+
+ for(p = progs; p != NULL; p = p->next)
+ fillin_program(p);
+
+ remove_error_progs();
+ gen_specials_cache();
+ gen_output_cfile();
+ gen_output_makefile();
+ status("");
+ fprintf(stderr,
+ "Run \"make -f %s objs exe\" to build crunched binary.\n",
+ outmkname);
+}
+
+
+void fillin_program(prog_t *p)
+{
+ char path[MAXPATHLEN];
+ char *srcparent;
+ strlst_t *s;
+
+ sprintf(line, "filling in parms for %s", p->name);
+ status(line);
+
+ if(!p->ident)
+ p->ident = genident(p->name);
+ if(!p->srcdir) {
+ srcparent = dir_search(p->name);
+ if(srcparent)
+ sprintf(path, "%s/%s", srcparent, p->name);
+ if(is_dir(path))
+ p->srcdir = strdup(path);
+ }
+ if(!p->objdir && p->srcdir) {
+ sprintf(path, "%s/obj", p->srcdir);
+ if(is_dir(path))
+ p->objdir = strdup(path);
+ else
+ p->objdir = p->srcdir;
+ }
+
+ if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir);
+ if(!p->objs && p->srcdir && is_nonempty_file(path))
+ fillin_program_objs(p, path);
+
+ if(!p->objpaths && p->objdir && p->objs)
+ for(s = p->objs; s != NULL; s = s->next) {
+ sprintf(line, "%s/%s", p->objdir, s->str);
+ add_string(&p->objpaths, line);
+ }
+
+ if(!p->srcdir && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
+ infilename, p->name);
+ if(!p->objs && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
+ infilename, p->name);
+
+ if(!p->objpaths) {
+ fprintf(stderr,
+ "%s: %s: error: no objpaths specified or calculated.\n",
+ infilename, p->name);
+ p->goterror = goterror = 1;
+ }
+}
+
+void fillin_program_objs(prog_t *p, char *path)
+{
+ char *obj, *cp;
+ int rc;
+ FILE *f;
+
+ /* discover the objs from the srcdir Makefile */
+
+ if((f = fopen(tempfname, "w")) == NULL) {
+ perror(tempfname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(f, ".include \"%s\"\n", path);
+ fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
+ fprintf(f, "OBJS=${PROG}.o\n");
+ fprintf(f, ".endif\n");
+ fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
+ fclose(f);
+
+ sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname);
+ if((f = popen(line, "r")) == NULL) {
+ perror("submake pipe");
+ goterror = 1;
+ return;
+ }
+
+ while(fgets(line, MAXLINELEN, f)) {
+ if(strncmp(line, "OBJS= ", 6)) {
+ fprintf(stderr, "make error: %s", line);
+ goterror = 1;
+ continue;
+ }
+ cp = line + 6;
+ while(isspace(*cp)) cp++;
+ while(*cp) {
+ obj = cp;
+ while(*cp && !isspace(*cp)) cp++;
+ if(*cp) *cp++ = '\0';
+ add_string(&p->objs, obj);
+ while(isspace(*cp)) cp++;
+ }
+ }
+ if((rc=pclose(f)) != 0) {
+ fprintf(stderr, "make error: make returned %d\n", rc);
+ goterror = 1;
+ }
+ unlink(tempfname);
+}
+
+void remove_error_progs(void)
+{
+ prog_t *p1, *p2;
+
+ p1 = NULL; p2 = progs;
+ while(p2 != NULL) {
+ if(!p2->goterror)
+ p1 = p2, p2 = p2->next;
+ else {
+ /* delete it from linked list */
+ fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
+ infilename, p2->name);
+ if(p1) p1->next = p2->next;
+ else progs = p2->next;
+ p2 = p2->next;
+ }
+ }
+}
+
+void gen_specials_cache(void)
+{
+ FILE *cachef;
+ prog_t *p;
+
+ sprintf(line, "generating %s", cachename);
+ status(line);
+
+ if((cachef = fopen(cachename, "w")) == NULL) {
+ perror(cachename);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
+ cachename, infilename, CRUNCH_VERSION);
+
+ for(p = progs; p != NULL; p = p->next) {
+ fprintf(cachef, "\n");
+ if(p->srcdir)
+ fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
+ if(p->objdir)
+ fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
+ if(p->objs) {
+ fprintf(cachef, "special %s objs", p->name);
+ output_strlst(cachef, p->objs);
+ }
+ fprintf(cachef, "special %s objpaths", p->name);
+ output_strlst(cachef, p->objpaths);
+ }
+ fclose(cachef);
+}
+
+
+void gen_output_makefile(void)
+{
+ prog_t *p;
+ FILE *outmk;
+
+ sprintf(line, "generating %s", outmkname);
+ status(line);
+
+ if((outmk = fopen(outmkname, "w")) == NULL) {
+ perror(outmkname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
+ outmkname, infilename, CRUNCH_VERSION);
+
+ top_makefile_rules(outmk);
+
+ for(p = progs; p != NULL; p = p->next)
+ prog_makefile_rules(outmk, p);
+
+ fprintf(outmk, "\n# ========\n");
+ fclose(outmk);
+}
+
+
+void gen_output_cfile(void)
+{
+ extern char *crunched_skel[];
+ char **cp;
+ FILE *outcf;
+ prog_t *p;
+ strlst_t *s;
+
+ sprintf(line, "generating %s", outcfname);
+ status(line);
+
+ if((outcf = fopen(outcfname, "w")) == NULL) {
+ perror(outcfname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(outcf,
+ "/* %s - generated from %s by crunchgen %s */\n",
+ outcfname, infilename, CRUNCH_VERSION);
+
+ fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
+ for(cp = crunched_skel; *cp != NULL; cp++)
+ fprintf(outcf, "%s\n", *cp);
+
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
+
+ fprintf(outcf, "\nstruct stub entry_points[] = {\n");
+ for(p = progs; p != NULL; p = p->next) {
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ p->name, p->ident);
+ for(s = p->links; s != NULL; s = s->next)
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ s->str, p->ident);
+ }
+
+ fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
+ fprintf(outcf, "\t{ NULL, NULL }\n};\n");
+ fclose(outcf);
+}
+
+
+char *genident(char *str)
+{
+ char *n,*s,*d;
+
+ /*
+ * generates a Makefile/C identifier from a program name, mapping '-' to
+ * '_' and ignoring all other non-identifier characters. This leads to
+ * programs named "foo.bar" and "foobar" to map to the same identifier.
+ */
+
+ if((n = strdup(str)) == NULL)
+ return NULL;
+ for(d = s = n; *s != '\0'; s++) {
+ if(*s == '-') *d++ = '_';
+ else if(*s == '_' || isalnum(*s)) *d++ = *s;
+ }
+ *d = '\0';
+ return n;
+}
+
+
+char *dir_search(char *progname)
+{
+ char path[MAXPATHLEN];
+ strlst_t *dir;
+
+ for(dir=srcdirs; dir != NULL; dir=dir->next) {
+ sprintf(path, "%s/%s", dir->str, progname);
+ if(is_dir(path)) return dir->str;
+ }
+ return NULL;
+}
+
+
+void top_makefile_rules(FILE *outmk)
+{
+ prog_t *p;
+
+ fprintf(outmk, "LIBS=");
+ output_strlst(outmk, libs);
+
+ fprintf(outmk, "CRUNCHED_OBJS=");
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s.lo", p->name);
+ fprintf(outmk, "\n");
+
+ fprintf(outmk, "SUBMAKE_TARGETS=");
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s_make", p->ident);
+ fprintf(outmk, "\n\n");
+
+ fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
+ execfname, execfname);
+ fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
+ execfname, execfname);
+ fprintf(outmk, "\tstrip %s\n", execfname);
+ fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
+ fprintf(outmk, "exe: %s\n", execfname);
+ fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
+ execfname);
+}
+
+
+void prog_makefile_rules(FILE *outmk, prog_t *p)
+{
+ fprintf(outmk, "\n# -------- %s\n\n", p->name);
+
+ if(p->srcdir && p->objs) {
+ fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
+ fprintf(outmk, "%s_OBJS=", p->ident);
+ output_strlst(outmk, p->objs);
+ fprintf(outmk, "%s_make:\n", p->ident);
+ fprintf(outmk, "\t(cd $(%s_SRCDIR); make $(%s_OBJS))\n\n",
+ p->ident, p->ident);
+ }
+ else
+ fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
+ p->ident, p->name);
+
+ fprintf(outmk, "%s_OBJPATHS=", p->ident);
+ output_strlst(outmk, p->objpaths);
+
+ fprintf(outmk, "%s_stub.c:\n", p->name);
+ fprintf(outmk, "\techo \""
+ "int _crunched_%s_stub(int argc, char **argv, char **envp)"
+ "{return main(argc,argv,envp);}\" >%s_stub.c\n",
+ p->ident, p->name);
+ fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->name, p->ident);
+ fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->name, p->ident);
+ fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n",
+ p->ident, p->name);
+}
+
+void output_strlst(FILE *outf, strlst_t *lst)
+{
+ for(; lst != NULL; lst = lst->next)
+ fprintf(outf, " %s", lst->str);
+ fprintf(outf, "\n");
+}
+
+
+/*
+ * ========================================================================
+ * general library routines
+ *
+ */
+
+void status(char *str)
+{
+ static int lastlen = 0;
+ int len, spaces;
+
+ if(!verbose) return;
+
+ len = strlen(str);
+ spaces = lastlen - len;
+ if(spaces < 1) spaces = 1;
+
+ fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
+ fflush(stderr);
+ lastlen = len;
+}
+
+
+void out_of_memory(void)
+{
+ fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
+ exit(1);
+}
+
+
+void add_string(strlst_t **listp, char *str)
+{
+ strlst_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
+ if(!strcmp(p2->str, str)) return;
+
+ p2 = malloc(sizeof(strlst_t));
+ if(p2) p2->str = strdup(str);
+ if(!p2 || !p2->str)
+ out_of_memory();
+
+ p2->next = NULL;
+ if(p1 == NULL) *listp = p2;
+ else p1->next = p2;
+}
+
+
+int is_dir(char *pathname)
+{
+ struct stat buf;
+
+ if(stat(pathname, &buf) == -1)
+ return 0;
+ return S_ISDIR(buf.st_mode);
+}
+
+int is_nonempty_file(char *pathname)
+{
+ struct stat buf;
+
+ if(stat(pathname, &buf) == -1)
+ return 0;
+
+ return S_ISREG(buf.st_mode) && buf.st_size > 0;
+}
diff --git a/contrib/crunch/crunchgen/mkskel.sh b/contrib/crunch/crunchgen/mkskel.sh
new file mode 100755
index 000000000000..fd53d78bbbac
--- /dev/null
+++ b/contrib/crunch/crunchgen/mkskel.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+# idea and sed lines taken straight from flex
+
+cat <<!EOF
+/* File created via mkskel.sh */
+
+char *crunched_skel[] = {
+!EOF
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
+
+cat <<!EOF
+ 0
+};
+!EOF
diff --git a/contrib/crunch/crunchide/Makefile b/contrib/crunch/crunchide/Makefile
new file mode 100644
index 000000000000..f6e1a8a45263
--- /dev/null
+++ b/contrib/crunch/crunchide/Makefile
@@ -0,0 +1,4 @@
+
+PROG= crunchide
+
+.include <bsd.prog.mk>
diff --git a/contrib/crunch/crunchide/crunchide.1 b/contrib/crunch/crunchide/crunchide.1
new file mode 100644
index 000000000000..38a04cf6b93f
--- /dev/null
+++ b/contrib/crunch/crunchide/crunchide.1
@@ -0,0 +1,68 @@
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" 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, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd June 14, 1994
+.Dt CRUNCHIDE 1
+.Os BSD 4
+.Sh NAME
+.Nm crunchide
+.Nd hides symbol names from ld, for crunching programs together
+.Sh SYNOPSIS
+.Nm crunchide
+.Op Fl f Ar keep-list-file
+.Op Fl k Ar keep-symbol
+.Op Ar object-file ...
+.Sh DESCRIPTION
+
+.Nm Crunchide
+hides the global symbols of
+.Ar object-file
+such that they are ignored by subsequent runs of the linker,
+.Xr ld 1 .
+Some symbols may be left visible via the
+.Fl k Ar keep-symbol
+and
+.Fl f Ar keep-list-file
+options. The
+.Ar keep-list-file
+must contain a list of symbols to keep visible, one symbol per line.
+Note that the C compiler prepends an underscore in front of
+symbols, so to keep the C function ``foo'' visible, the option
+\&``-k _foo'' must be used.
+
+.Pp
+.Nm Crunchide
+is designed as a companion program for
+.Xr crunchgen 1 ,
+which automates the process of creating crunched binaries from
+multiple component programs.
+.Sh SEE ALSO
+.Xr crunchgen 1 ,
+.Xr ld 1
+.Sh AUTHOR
+.Nm Crunch
+was written by James da Silva <jds@cs.umd.edu>.
+.sp 0
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
diff --git a/contrib/crunch/crunchide/crunchide.c b/contrib/crunch/crunchide/crunchide.c
new file mode 100644
index 000000000000..ae54da08cf58
--- /dev/null
+++ b/contrib/crunch/crunchide/crunchide.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
+ * global symbols. Allows the user to supply a "keep list" of symbols
+ * that are not to be hidden. This program relies on the use of the
+ * linker's -dc flag to actually put global bss data into the file's
+ * bss segment (rather than leaving it as undefined "common" data).
+ *
+ * The point of all this is to allow multiple programs to be linked
+ * together without getting multiple-defined errors.
+ *
+ * For example, consider a program "foo.c". It can be linked with a
+ * small stub routine, called "foostub.c", eg:
+ * int foo_main(int argc, char **argv){ return main(argc, argv); }
+ * like so:
+ * cc -c foo.c foostub.c
+ * ld -dc -r foo.o foostub.o -o foo.combined.o
+ * crunchide -k _foo_main foo.combined.o
+ * at this point, foo.combined.o can be linked with another program
+ * and invoked with "foo_main(argc, argv)". foo's main() and any
+ * other globals are hidden and will not conflict with other symbols.
+ *
+ * TODO:
+ * - resolve the theoretical hanging reloc problem (see check_reloc()
+ * below). I have yet to see this problem actually occur in any real
+ * program. In what cases will gcc/gas generate code that needs a
+ * relative reloc from a global symbol, other than PIC? The
+ * solution is to not hide the symbol from the linker in this case,
+ * but to generate some random name for it so that it doesn't link
+ * with anything but holds the place for the reloc.
+ * - arrange that all the BSS segments start at the same address, so
+ * that the final crunched binary BSS size is the max of all the
+ * component programs' BSS sizes, rather than their sum.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+char *pname = "crunchide";
+
+void usage(void);
+
+void add_to_keep_list(char *symbol);
+void add_file_to_keep_list(char *filename);
+
+void hide_syms(char *filename);
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ int ch;
+
+ if(argc > 0) pname = argv[0];
+
+ while ((ch = getopt(argc, argv, "k:f:")) != EOF)
+ switch(ch) {
+ case 'k':
+ add_to_keep_list(optarg);
+ break;
+ case 'f':
+ add_file_to_keep_list(optarg);
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc == 0) usage();
+
+ while(argc) {
+ hide_syms(*argv);
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",
+ pname);
+ exit(1);
+}
+
+/* ---------------------------- */
+
+struct keep {
+ struct keep *next;
+ char *sym;
+} *keep_list;
+
+void add_to_keep_list(char *symbol)
+{
+ struct keep *newp, *prevp, *curp;
+ int cmp;
+
+ for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
+ if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
+
+ if(curp && cmp == 0)
+ return; /* already in table */
+
+ newp = (struct keep *) malloc(sizeof(struct keep));
+ if(newp) newp->sym = strdup(symbol);
+ if(newp == NULL || newp->sym == NULL) {
+ fprintf(stderr, "%s: out of memory for keep list\n", pname);
+ exit(1);
+ }
+
+ newp->next = curp;
+ if(prevp) prevp->next = newp;
+ else keep_list = newp;
+}
+
+int in_keep_list(char *symbol)
+{
+ struct keep *curp;
+ int cmp;
+
+ for(curp = keep_list; curp; curp = curp->next)
+ if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
+
+ return curp && cmp == 0;
+}
+
+void add_file_to_keep_list(char *filename)
+{
+ FILE *keepf;
+ char symbol[1024];
+ int len;
+
+ if((keepf = fopen(filename, "r")) == NULL) {
+ perror(filename);
+ usage();
+ }
+
+ while(fgets(symbol, 1024, keepf)) {
+ len = strlen(symbol);
+ if(len && symbol[len-1] == '\n')
+ symbol[len-1] = '\0';
+
+ add_to_keep_list(symbol);
+ }
+ fclose(keepf);
+}
+
+/* ---------------------- */
+
+int nsyms, ntextrel, ndatarel;
+struct exec *hdrp;
+char *aoutdata, *strbase;
+struct relocation_info *textrel, *datarel;
+struct nlist *symbase;
+
+
+#define SYMSTR(sp) &strbase[(sp)->n_un.n_strx]
+
+/* is the symbol a global symbol defined in the current file? */
+#define IS_GLOBAL_DEFINED(sp) \
+ (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
+
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp) \
+ ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
+
+void check_reloc(char *filename, struct relocation_info *relp);
+
+void hide_syms(char *filename)
+{
+ int inf, outf, rc;
+ struct stat infstat;
+ struct relocation_info *relp;
+ struct nlist *symp;
+
+ /*
+ * Open the file and do some error checking.
+ */
+
+ if((inf = open(filename, O_RDWR)) == -1) {
+ perror(filename);
+ return;
+ }
+
+ if(fstat(inf, &infstat) == -1) {
+ perror(filename);
+ close(inf);
+ return;
+ }
+
+ if(infstat.st_size < sizeof(struct exec)) {
+ fprintf(stderr, "%s: short file\n", filename);
+ close(inf);
+ return;
+ }
+
+ /*
+ * Read the entire file into memory. XXX - Really, we only need to
+ * read the header and from TRELOFF to the end of the file.
+ */
+
+ if((aoutdata = (char *) malloc(infstat.st_size)) == NULL) {
+ fprintf(stderr, "%s: too big to read into memory\n", filename);
+ close(inf);
+ return;
+ }
+
+ if((rc = read(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
+ fprintf(stderr, "%s: read error: %s\n", filename,
+ rc == -1? strerror(errno) : "short read");
+ close(inf);
+ return;
+ }
+
+ /*
+ * Check the header and calculate offsets and sizes from it.
+ */
+
+ hdrp = (struct exec *) aoutdata;
+
+ if(N_BADMAG(*hdrp)) {
+ fprintf(stderr, "%s: bad magic: not an a.out file\n", filename);
+ close(inf);
+ return;
+ }
+
+#ifdef __FreeBSD__
+ textrel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp));
+ datarel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp) +
+ hdrp->a_trsize);
+#else
+ textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
+ datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
+#endif
+ symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
+ strbase = (char *) (aoutdata + N_STROFF(*hdrp));
+
+ ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
+ ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
+ nsyms = hdrp->a_syms / sizeof(struct nlist);
+
+ /*
+ * Zap the type field of all globally-defined symbols. The linker will
+ * subsequently ignore these entries. Don't zap any symbols in the
+ * keep list.
+ */
+
+ for(symp = symbase; symp < symbase + nsyms; symp++)
+ if(IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp)))
+ symp->n_type = 0;
+
+ /*
+ * Check whether the relocation entries reference any symbols that we
+ * just zapped. I don't know whether ld can handle this case, but I
+ * haven't encountered it yet. These checks are here so that the program
+ * doesn't fail silently should such symbols be encountered.
+ */
+
+ for(relp = textrel; relp < textrel + ntextrel; relp++)
+ check_reloc(filename, relp);
+ for(relp = datarel; relp < datarel + ndatarel; relp++)
+ check_reloc(filename, relp);
+
+ /*
+ * Write the .o file back out to disk. XXX - Really, we only need to
+ * write the symbol table entries back out.
+ */
+ lseek(inf, 0, SEEK_SET);
+ if((rc = write(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
+ fprintf(stderr, "%s: write error: %s\n", filename,
+ rc == -1? strerror(errno) : "short write");
+ }
+
+ close(inf);
+}
+
+
+void check_reloc(char *filename, struct relocation_info *relp)
+{
+ /* bail out if we zapped a symbol that is needed */
+ if(IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
+ fprintf(stderr,
+ "%s: oops, have hanging relocation for %s: bailing out!\n",
+ filename, SYMSTR(&symbase[relp->r_symbolnum]));
+ exit(1);
+ }
+}
diff --git a/contrib/crunch/examples/Makefile b/contrib/crunch/examples/Makefile
new file mode 100644
index 000000000000..861e3028cb87
--- /dev/null
+++ b/contrib/crunch/examples/Makefile
@@ -0,0 +1,32 @@
+
+CRUNCHED= fixit
+
+# below is boiler-plate to make $(CRUNCHED) from $(CRUNCHED).conf
+# I'd use PROG instead of CRUNCHED, but the system makefiles REALLY want
+# to build things in the normal way if you use PROG.
+
+CONF= $(CRUNCHED).conf
+
+OUTMK= $(CRUNCHED).mk
+OUTPUTS= $(OUTMK) $(CRUNCHED).c $(CRUNCHED).cache
+
+NOMAN=
+CLEANFILES+=$(CRUNCHED) *.o *.lo *.c *.mk *.cache
+CLEANDIRFILES+=$(OUTPUTS)
+
+all: $(CRUNCHED)
+exe: $(CRUNCHED)
+
+$(OUTPUTS): $(CONF)
+ crunchgen ${.CURDIR}/$(CONF)
+
+$(CRUNCHED): $(OUTPUTS) submake
+
+submake:
+ make -f $(OUTMK)
+objs:
+ make -f $(OUTMK) objs
+cleandir:
+ rm -f $(CLEANDIRFILES)
+
+.include <bsd.prog.mk>
diff --git a/contrib/crunch/examples/filesystem.conf b/contrib/crunch/examples/filesystem.conf
new file mode 100644
index 000000000000..c5bcb372dc81
--- /dev/null
+++ b/contrib/crunch/examples/filesystem.conf
@@ -0,0 +1,26 @@
+# $Id: filesystem.conf,v 1.2 1994/06/24 16:39:29 jkh Exp $
+
+srcdirs /usr/src/bin /usr/src/sbin /usr/src/gnu/usr.bin /usr/src/usr.sbin
+
+# /bin
+progs sh expr ls mkdir rm sync test
+ln test [
+
+# These are needed because of UN*X's idiotic way of indicating that something
+# is a login shell.
+ln sh -
+ln sh -sh
+
+# /sbin
+progs disklabel fdisk halt init mount mount_pcfs newfs umount
+
+# /usr/bin
+progs cpio gzip
+ln gzip gunzip
+ln gzip gzcat
+ln gzip zcat
+
+# /usr/sbin
+progs bad144
+
+libs -lutil
diff --git a/contrib/crunch/examples/fixit.conf b/contrib/crunch/examples/fixit.conf
new file mode 100644
index 000000000000..2298d41386be
--- /dev/null
+++ b/contrib/crunch/examples/fixit.conf
@@ -0,0 +1,41 @@
+# fixit.conf - put in anything we think we might want on a fixit floppy
+
+# first, we list the source dirs that our programs reside in. These are
+# searched in order listed to find the dir containing each program.
+
+srcdirs /usr/src/bin /usr/src/sbin /usr/src/usr.bin /usr/src/usr.sbin
+srcdirs /usr/src/gnu/usr.bin
+
+# second, we list all the programs we want to include in our crunched binary.
+# The order doesn't matter. Any program that needs hard links to it gets an
+# `ln' directive.
+
+# /bin stuff
+
+progs cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+progs mt mv pwd rcp rm rmdir sh sleep stty sync test
+
+ln test [
+ln sh -sh # init invokes the shell this way
+
+# /sbin stuff
+
+progs badsect chown clri disklabel dump dmesg fdisk fsck halt ifconfig init
+progs mknod mount newfs ping reboot restore swapon umount
+ln dump rdump
+ln restore rrestore
+
+# /usr/bin stuff
+
+progs ftp rsh sed telnet rlogin vi
+
+# gnu stuff
+
+progs cpio gzip
+ln gzip gunzip
+ln gzip gzcat
+
+# finally, we specify the libraries to link in with our binary
+
+libs -lcrypt -ltelnet -lutil -ll
+libs -lcurses -ltermcap
diff --git a/contrib/crunch/examples/kcopy.conf b/contrib/crunch/examples/kcopy.conf
new file mode 100644
index 000000000000..a50f6f28df52
--- /dev/null
+++ b/contrib/crunch/examples/kcopy.conf
@@ -0,0 +1,18 @@
+# $Id: kcopy.conf,v 1.3 1994/06/24 16:39:30 jkh Exp $
+
+srcdirs /usr/src/bin /usr/src/sbin
+
+# Programs from bin/
+progs sh cp echo test
+ln test [
+
+# These are needed because of UN*X's idiotic way of indicating that something
+# is a login shell.
+ln sh -
+ln sh -sh
+
+#
+# Programs from sbin/
+progs mount mount_isofs mount_pcfs fsck halt init umount
+
+libs -lutil
diff --git a/contrib/crunch/examples/really-big.conf b/contrib/crunch/examples/really-big.conf
new file mode 100644
index 000000000000..ce5083f7051c
--- /dev/null
+++ b/contrib/crunch/examples/really-big.conf
@@ -0,0 +1,146 @@
+# really-big.conf - just about everything, just for testing.
+# This ends up having some good examples of the use of specials for
+# those hard-to-reach programs. I stopped when I got tired, but we
+# could probably get even more stuff (like libexec stuff) in here.
+#
+# This produces a 4608000 byte binary. Pretty sick and twisted, eh?
+
+# =========================================================================
+
+srcdirs /usr/src/bin
+
+progs cat chmod cp csh date dd df domainname echo ed expr hostname kill
+progs ln ls mkdir mt mv ps pwd rcp rm rmail rmdir sh sleep stty sync test
+
+ln test [
+ln sh -sh
+
+
+# =========================================================================
+
+srcdirs /usr/src/sbin
+
+progs badsect bim clri disklabel dmesg dump dumpfs fdisk fsck halt
+progs ifconfig init mknod modload modunload mount mount_fdesc mount_isofs
+progs mount_kernfs mount_lofs mount_msdos mount_portal mount_procfs mountd
+progs newfs nfsd nfsiod ping quotacheck reboot restore route routed savecore
+progs shutdown slattach swapon ttyflags tunefs umount
+# shell scripts: fastboot
+
+ln dump rdump
+ln restore rrestore
+
+
+# =========================================================================
+
+srcdirs /usr/src/usr.bin
+
+progs apropos ar asa at basename biff cal calendar cap_mkdb checknr chpass
+progs cksum cmp col colcrt colrm column comm compress crontab ctags cut
+progs dirname du env error expand false file find finger fmt fold fpr from
+progs fsplit fstat ftp getconf getopt gprof head hexdump id indent ipcrm
+progs ipcs join kdump ktrace last lastcomm leave lex lock logger locate
+progs login logname look m4 machine mail make man mesg mkfifo
+progs mkstr modstat more msgs netstat newsyslog nfsstat nice nm nohup
+progs pagesize passwd paste patch pr printenv printf quota ranlib
+progs renice rev rlogin rpcgen rpcinfo rsh rup ruptime rusers rwall rwho
+progs script sed showmount size soelim split strings strip su tail talk
+progs tcopy tee telnet tftp time tip tn3270 touch tput tr true tset tsort
+progs tty ul uname unexpand unifdef uniq units unvis users uudecode uuencode
+progs vacation vgrind vi vis vmstat w wall wc what whatis whereis who
+progs whois window write xargs xinstall xstr yacc yes ypcat ypmatch ypwhich
+
+# shell scripts: lorder mkdep shar which
+# problems: rdist uses libcompat.a(regex.o), which conflicts with
+# libedit(readline.o) over regerror().
+
+# special requirements
+
+special locate srcdir /usr/src/usr.bin/locate/locate
+special tn3270 srcdir /usr/src/usr.bin/tn3270/tn3270
+
+
+# =========================================================================
+
+srcdirs /usr/src/usr.sbin
+
+progs ac accton amd arp bad144 catman chown chroot config config.new cron
+progs dev_mkdb diskpart edquota flcopy gettable grfinfo hilinfo htable inetd
+progs iostat iteconfig kvm_mkdb mrouted mtree named portmap pppd
+progs pstat pwd_mkdb quot quotaon rarpd rbootd repquota rmt rpc.bootparamd
+progs rwhod sa sliplogin slstats spray sysctl syslogd tcpdump
+progs traceroute trpt trsp update vipw vnconfig ypbind yppoll ypset
+
+special amd srcdir /usr/src/usr.sbin/amd/amd
+special amd objs vers.amd.o afs_ops.o am_ops.o clock.o util.o xutil.o efs_ops.o mapc.o info_file.o info_hes.o info_ndbm.o info_passwd.o info_nis.o info_union.o map.o srvr_afs.o srvr_nfs.o mntfs.o misc_rpc.o mount_fs.o mtab.o mtab_bsd.o nfs_ops.o nfs_prot_svc.o nfs_start.o nfs_subr.o opts.o pfs_ops.o rpc_fwd.o sched.o sfs_ops.o amq_svc.o amq_subr.o umount_fs.o host_ops.o nfsx_ops.o ufs_ops.o ifs_ops.o amd.o get_args.o restart.o wire.o
+
+
+srcdirs /usr/src/usr.sbin/lpr # lpr subsystem
+progs lpr lpc lpq lprm pac lptest
+special lpr srcdir /usr/src/usr.sbin/lpr/lpr
+
+srcdirs /usr/src/usr.sbin/sendmail # sendmail subsystem
+progs mailstats makemap praliases sendmail
+special sendmail srcdir /usr/src/usr.sbin/sendmail/src
+ln sendmail newaliases
+ln sendmail mailq
+
+srcdirs /usr/src/usr.sbin/timed # timed & timedc
+progs timed timedc
+special timed srcdir /usr/src/usr.sbin/timed/timed
+
+srcdirs /usr/src/usr.sbin/yp # yp subsystem
+progs ypbind ypwhich ypcat ypmatch ypset yppoll
+
+
+# =========================================================================
+
+srcdirs /usr/src/gnu/usr.bin
+
+progs bc cpio diff diff3 gas gawk grep gzip sdiff sort tar
+# shell scripts: send-pr
+
+srcdirs /usr/src/gnu/usr.bin/ld # ldd and ldconfig
+progs ld ldd ldconfig
+
+# rcs stuff loses because there are cross dependencies between librcs.a and
+# the individual programs. The solution would be to specify the objpaths
+# directly for each one, and include the full path to librcs.a each the
+# objpaths.
+
+# srcdirs /usr/src/gnu/usr.bin/rcs # rcs subsystem
+# progs ci co ident merge rcs rcsclean rcsdiff rcsmerge rlog
+# # shell script: rcsfreeze
+# special rcs srcdir /usr/src/gnu/usr.bin/rcs/rcs
+# libs /usr/src/gnu/usr.bin/rcs/lib/obj/librcs.a
+
+# gdb loses too
+# progs gdb
+# special gdb srcdir /usr/src/gnu/usr.bin/gdb/gdb
+# libs /usr/src/gnu/usr.bin/gdb/bfd/obj/libbfd.a
+# libs /usr/src/gnu/usr.bin/gdb/readline/obj/libreadline.a
+# libs /usr/src/gnu/usr.bin/gdb/libiberty/obj/libiberty.a
+
+# groff has the same problem as rcs
+# srcdirs /usr/src/gnu/usr.bin/groff # groff subsystem
+# progs groff troff tbl pic eqn grops grotty grodvi refer lookbib
+# progs indxbib lkbib tfmtodit addftinfo pfbtops psbb
+# shell script: nroff
+# special groff srcdir /usr/src/gnu/usr.bin/groff/groff
+# libs /usr/src/gnu/usr.bin/groff/libgroff/obj/libgroff.a
+# libs /usr/src/gnu/usr.bin/groff/libbib/obj/libbib.a
+# libs /usr/src/gnu/usr.bin/groff/libdriver/obj/libdriver.a
+
+srcdirs /usr/src/gnu/usr.bin/gcc2 # gcc & friends
+progs cc cpp cc1
+
+# cc1 has the same problem as rcs and groff, but since there's only one program
+# I'll go ahead and solve it as an example.
+
+special cc1 objpaths /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-parse.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-lang.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-lex.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-pragma.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-decl.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-typeck.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-convert.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-aux-info.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-iterate.o /usr/src/gnu/usr.bin/gcc2/common/obj/libcc1.a
+
+ln gzip gunzip
+ln gzip gzcat
+
+libs -ledit -lgnumalloc -lc -lcrypt -ltermcap -lcurses -ltelnet -lutil -lkvm
+libs -ll -ly -lm -lresolv -lrpcsvc -lcompat
diff --git a/contrib/manctl/Makefile b/contrib/manctl/Makefile
new file mode 100644
index 000000000000..7a2ae922f572
--- /dev/null
+++ b/contrib/manctl/Makefile
@@ -0,0 +1,11 @@
+# Makefile
+# $Id: Makefile,v 1.4 1994/05/26 20:16:49 csgr Exp $
+
+all:
+ @echo -n
+
+install: all
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/manctl.sh \
+ ${DESTDIR}/usr/sbin/manctl
+
+.include <bsd.prog.mk>
diff --git a/contrib/manctl/manctl.sh b/contrib/manctl/manctl.sh
new file mode 100644
index 000000000000..97116cfb31c4
--- /dev/null
+++ b/contrib/manctl/manctl.sh
@@ -0,0 +1,376 @@
+#!/bin/sh
+#
+# Copyright (c) 1994 Geoffrey M. Rehmet, Rhodes University
+# 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 Geoffrey M. Rehmet
+# 4. Neither the name of Geoffrey M. Rehmet nor that of Rhodes University
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED ``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 GEOFFREY M. REHMET OR RHODES UNIVERSITY 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.
+#
+# $Id: manctl.sh,v 1.4 1994/04/18 18:46:50 csgr Exp $
+#
+# manctl:
+# a utility for manipulating manual pages
+# functions:
+# compress uncompressed man pages (elliminating .so's)
+# this is now two-pass. If possible, .so's
+# are replaced with hard links
+# uncompress compressed man pages
+# purge old formatted man pages (not implemented yet)
+# Things to watch out for:
+# Hard links - careful with g(un)zipping!
+# .so's - throw everything through soelim before gzip!
+# symlinks - ignore these - eg: expn is its own man page:
+# don't want to compress this!
+#
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+
+#
+# purge cat? directories
+#
+do_purge()
+{
+ echo "purge $@" 2>&1
+ echo "not implemented yet\n" 2>&1
+}
+
+
+#
+# Uncompress one page
+#
+uncompress_page()
+{
+ local pname
+ local fname
+ local sect
+ local ext
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ # less than 3 fields - don't know what to do with this
+ if [ $# -lt 3 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 2 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+ ext=$2
+
+ IFS=" "
+ case "$ext" in
+ gz|Z) {
+ IFS=" " ; set `file $pname`
+ if [ $2 != "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $fname.$ext # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo gunzipping page $pname 1>&2
+ gunzip -c $pname > /tmp/manager.$$
+ chmod u+w $pname
+ cp /tmp/manager.$$ $pname
+ chmod 444 $pname
+ mv $pname $fname.$sect
+ rm /tmp/manager.$$
+ else
+ # skip symlinks - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+
+#
+# Uncompress manpages in paths
+#
+do_uncompress()
+{
+ local i
+ local dir
+ local workdir
+
+ workdir=`pwd`
+ while [ $# != 0 ] ; do
+ if [ -d $1 ] ; then
+ dir=$1
+ cd $dir
+ for i in * ; do
+ case $i in
+ *cat?) ;; # ignore cat directories
+ *) {
+ if [ -d $i ] ; then
+ do_uncompress $i
+ else
+ if [ -e $i ] ; then
+ uncompress_page $i
+ fi
+ fi } ;;
+ esac
+ done
+ cd $workdir
+ else
+ echo "directory $1 not found" 1>&2
+ fi
+ shift
+ done
+}
+
+#
+# Remove .so's from one file
+#
+so_purge_page()
+{
+ local so_entries
+ local lines
+ local fname
+
+ so_entries=`grep "^\.so" $1 | wc -l`
+ if [ $so_entries -eq 0 ] ; then ; return 0 ; fi
+
+ # we have a page with a .so in it
+ echo $1 contains a .so entry 2>&1
+
+ # now check how many lines in the file
+ lines=`wc -l < $1`
+
+ # if the file is only one line long, we can replace it
+ # with a hard link!
+ if [ $lines -eq 1 ] ; then
+ fname=$1;
+ echo replacing $fname with a hard link
+ set `cat $fname`;
+ rm -f $fname
+ ln ../$2 $fname
+ else
+ echo inlining page $fname 1>&2
+ cat $fname | \
+ (cd .. ; soelim ) > /tmp/manager.$$
+ chmod u+w $fname
+ cp /tmp/manager.$$ $fname
+ chmod 444 $fname
+ fi
+}
+
+#
+# Remove .so entries from man pages
+# If a page consists of just one line with a .so,
+# replace it with a hard link
+#
+remove_so()
+{
+ local pname
+ local fname
+ local sect
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ if [ $# -lt 2 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 1 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+
+ IFS=" "
+ case "$sect" in
+ gz) { echo file $pname already gzipped 1>&2 ; } ;;
+ Z) { echo file $pname already compressed 1>&2 ; } ;;
+ [12345678ln]*){
+ IFS=" " ; set `file $pname`
+ if [ $2 = "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $pname.gz # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo "removing .so's in page $pname" 1>&2
+ so_purge_page $pname
+ else
+ # skip symlink - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+
+#
+# compress one page
+# We need to watch out for hard links here.
+#
+compress_page()
+{
+ local pname
+ local fname
+ local sect
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ if [ $# -lt 2 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 1 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+
+ IFS=" "
+ case "$sect" in
+ gz) { echo file $pname already gzipped 1>&2 ; } ;;
+ Z) { echo file $pname already compressed 1>&2 ; } ;;
+ [12345678ln]*){
+ IFS=" " ; set `file $pname`
+ if [ $2 = "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $pname.gz # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo gzipping page $pname 1>&2
+ cat $pname | \
+ (cd .. ; soelim )| gzip -c -- > /tmp/manager.$$
+ chmod u+w $pname
+ cp /tmp/manager.$$ $pname
+ chmod 444 $pname
+ mv $pname $pname.gz
+ rm /tmp/manager.$$
+ else
+ # skip symlink - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+#
+# Compress man pages in paths
+#
+do_compress_so()
+{
+ local i
+ local dir
+ local workdir
+ local what
+
+ what=$1
+ shift
+ workdir=`pwd`
+ while [ $# != 0 ] ; do
+ if [ -d $1 ] ; then
+ dir=$1
+ cd $dir
+ for i in * ; do
+ case $i in
+ *cat?) ;; # ignore cat directories
+ *) {
+ if [ -d $i ] ; then
+ do_compress_so $what $i
+ else
+ if [ -e $i ] ; then
+ $what $i
+ fi
+ fi } ;;
+ esac
+ done
+ cd $workdir
+ else
+ echo "directory $1 not found" 1>&2
+ fi
+ shift
+ done
+}
+
+#
+# Display a usage message
+#
+ctl_usage()
+{
+ echo "usage : $1 -compress <path> ... " 1>&2
+ echo " $1 -uncompress <path> ... " 1>&2
+ echo " $1 -purge <days> <path> ... " 1>&2
+ echo " $1 -purge expire <path> ... " 1>&2
+ exit 1
+}
+
+#
+# remove .so's and do compress
+#
+do_compress()
+{
+ # First remove all so's from the pages to be compressed
+ do_compress_so remove_so "$@"
+ # now do ahead and compress the pages
+ do_compress_so compress_page "$@"
+}
+
+#
+# dispatch options
+#
+if [ $# = 0 ] ; then ; ctl_usage $0 ; fi ;
+
+case "$1" in
+ -compress) shift ; do_compress "$@" ;;
+ -uncompress) shift ; do_uncompress "$@" ;;
+ -purge) shift ; do_purge "$@" ;;
+ *) ctl_usage $0 ;;
+esac
diff --git a/contrib/tcpdump/tcpdump/tcpdump.1 b/contrib/tcpdump/tcpdump/tcpdump.1
index 61148f494014..da584b45b954 100644
--- a/contrib/tcpdump/tcpdump/tcpdump.1
+++ b/contrib/tcpdump/tcpdump/tcpdump.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.1,v 1.1.1.1.2.1 1994/05/01 16:00:56 jkh Exp $ (LBL)
+.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.1,v 1.2 1994/04/24 01:19:05 jkh Exp $ (LBL)
.\"
.\" Copyright (c) 1988, 1989, 1990, 1991, 1992
.\" The Regents of the University of California.
diff --git a/contrib/tcpdump/tcpslice/tcpslice.1 b/contrib/tcpdump/tcpslice/tcpslice.1
index 92af935f2897..1e0f7dca8b19 100644
--- a/contrib/tcpdump/tcpslice/tcpslice.1
+++ b/contrib/tcpdump/tcpslice/tcpslice.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.1,v 1.1.1.1.2.1 1994/05/01 16:01:05 jkh Exp $ (LBL)
+.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.1,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)
.\"
.\" Copyright (c) 1988-1990 The Regents of the University of California.
.\" All rights reserved.
diff --git a/contrib/xntpd/COPYRIGHT b/contrib/xntpd/COPYRIGHT
index 711a8f1efcb4..b9ce773f163a 100644
--- a/contrib/xntpd/COPYRIGHT
+++ b/contrib/xntpd/COPYRIGHT
@@ -1,6 +1,6 @@
/******************************************************************************
* *
- * Copyright (c) David L. Mills 1992, 1993, 1994 *
+ * Copyright (c) David L. Mills 1992, 1993, 1994 *
* *
* Permission to use, copy, modify, and distribute this software and its *
* documentation for any purpose and without fee is hereby granted, provided *
@@ -55,4 +55,6 @@
* Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> (Linux Port)
* Paul A Vixie <vixie@vix.com> (TrueTime GPS driver)
* Jim Jagielski <jim@jagubox.gsfc.nasa.gov> (A/UX port)
-*/
+ * Ray Schnitzler <schnitz@unipress.com> (First pass at a Unixware1 port.)
+ * Ajit Thyagarajan <ajit@ee.udel.edu> (IP multicast support)
+ */
diff --git a/contrib/xntpd/Makefile.inc b/contrib/xntpd/Makefile.inc
index 0983df967f72..f38f0a91a3dc 100644
--- a/contrib/xntpd/Makefile.inc
+++ b/contrib/xntpd/Makefile.inc
@@ -1,7 +1,7 @@
DEFS_LOCAL=-DREFCLOCK -DPARSE
-NTPDEFS= -DSYS_FREEBSD -DSYS_386BSD -DHAVE_TERMIOS
+NTPDEFS= -DSYS_FREEBSD -DSYS_386BSD
AUTHDEFS= -DMD5
CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DAS2201 -DGOES -DGPSTM -DOMEGA \
- -DLEITCH
+ -DLEITCH -DTRAK
CFLAGS+= ${NTPDEFS} ${DEFS_LOCAL} ${AUTHDEFS} ${CLOCKDEFS} ${COPTS}
BINDIR?= /usr/sbin
diff --git a/contrib/xntpd/README.FreeBSD b/contrib/xntpd/README.FreeBSD
index 437d4783d1ed..8fd237e1640c 100644
--- a/contrib/xntpd/README.FreeBSD
+++ b/contrib/xntpd/README.FreeBSD
@@ -1,6 +1,8 @@
+ $Id: README.FreeBSD,v 1.7 1994/04/21 21:10:20 wollman Exp $
+
This version of NTP was converted to the BSD-style Makefile system by
Garrett Wollman (wollman@freefall.cdrom.com); it is based on version
-3.3z (late beta) from the University of Delaware.
+3.3s (late beta) from the University of Delaware.
Besides the Makefile changes, the DES code has been completely removed
in order to make this code exportable. If you have a legal copy of
@@ -8,3 +10,75 @@ in order to make this code exportable. If you have a legal copy of
to the AUTHDEFS in Makefile.inc.
You can change CLOCKDEFS in the same file to add other reference clocks.
+
+This version of xntpd knows how to talk to the kernelized NTP PLL which is
+present in versions of FreeBSD-current after 21 April 1994. When this code
+is more widely released, I'll provide the patches to Mills.
+
+----------------------------------------------------
+Support for Conrad electronic's "DCF-77 Uhr, Mobil".
+----------------------------------------------------
+Conrad electronic in Germany,, Phone (+49) 962230111 (?), sells a gadget
+called "DCF77 Uhr, mobil", which is a DCF77 timecode receiver with a
+rs-232 interface. The price is around DM130.
+ 9-pin interface is Order# 97 94 57 66
+ 25-pin interface is Order# 97 94 81 66
+
+You must define
+ -DDCF77 -DPPS -DFREEBSD_CONRAD -DDEBUG
+when you compile xntpd. You can later remove -DDEBUG, if you feel like it.
+
+You must also have
+ options COM_BIDIR
+defined in your kernel, and finally the ttyport you intend to use must
+have special interrupt vector:
+ device sio1 at isa? port "IO_COM2" tty irq 3 vector siointrts
+ ^^^^^^^^^^^^
+connect the radio-clock to the tty port and link it to /dev/refclock-0:
+
+ cd /dev
+ sh MAKEDEV cua1
+ ln -s /dev/cua01 /dev/refclock-0
+
+make a directory to gather statistics in:
+ mkdir /var/tmp/ntp
+
+Create a /etc/ntp.conf along these lines:
+
+ # DCF77 without PPS
+ server 127.127.8.20
+ # DCF77 with PPS
+ #server 127.127.8.148 prefer
+
+ driftfile /var/tmp/ntp/ntp.drift
+ statsdir /var/tmp/ntp
+ statistics loopstats
+ statistics peerstats
+ statistics clockstats
+ filegen peerstats file peerstats type day enable
+ filegen loopstats file loopstats type day enable
+ filegen clockstats file clockstats type day enable
+
+Try to start it:
+ comcontrol ttyd1 bidir
+ tickadj -A
+ xntpd -d -d -d
+
+You should see the red LED flash on the receiver every second now. You
+may have to experiment a bit with the location, and possibly adjust the
+minute variable resistor inside to get a good signal. Be aware, that just
+because you see the light flash, is not the same as the signal being
+received by the computer. The chip doing the work in the reciver uses
+less than 1 micro-ampere, so even if RTS isn't pulled low, it will happily
+receive, but be unable to buffer the signal to the rs-232 levels needed.
+
+You can see what's going on in /var/log/messages, and query the
+daemon using xntpdc and ntpq, in particular the "clockvar" command
+of ntpq will tell about the clocks healt.
+
+I live in Slagelse, Denmark, which is ~1000 Km from Mainflingen, yet
+I have +/- 2 ms precision from this cheap gadget. If you have a very
+stable signal, you can use the 'pps' address instead to improve your
+timing.
+
+Have fun... Poul-Henning Kamp <phk@login.dkuug.dk>
diff --git a/contrib/xntpd/RELNOTES b/contrib/xntpd/RELNOTES
index 1b9d9c02c3b3..411ef452195b 100644
--- a/contrib/xntpd/RELNOTES
+++ b/contrib/xntpd/RELNOTES
@@ -31,6 +31,10 @@ this distribution. To make these programs:
For custom tailored configuration copying Config.local.dist to Config.local
and editing Config.local to suit the local needs is neccessary (at most
3 lines to change), or use one of the make's above and then tweak it.
+ Config.local can also be used to override common settings from the
+ machines/* files like the AUTHDEFS= to select very specific configurations.
+ Please use this feature with care and don't be disappointed if it doesn't
+ work the way you expect.
(2) Type "make" to compile everything of general interest. Expect few or
no warnings using cc and a moderate level of warnings using gcc.
@@ -140,6 +144,7 @@ the meal. The converse is not always true.
PC BSD/386 1.0 gcc LOCAL_CLOCK possibly see "build problems"
PC Linux (pl14) gcc LOCAL_CLOCK (dw 93/10/30)
PC Dell SVR4 v2.2 gcc ? (tl 93/12/30)
+ PC Unixware1/SVR4 cc no tickadj, ? (ras 93/04/11)
NCR3445 NCR SVR4 cc LOCAL_CLOCK (tm 93/11/29)
pb: Piete Brooks
@@ -149,6 +154,7 @@ the meal. The converse is not always true.
tl: Tony Lill <ajlill@tlill.hookup.net>
tm: Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
jmj: Jim Jagielski <jim@jagubox.gsfc.nasa.gov>
+ ras: Ray Schnitzler <schnitz@unipress.com>
Build Problems (and workaround):
diff --git a/contrib/xntpd/VERSION b/contrib/xntpd/VERSION
index 85051bd4db45..c145b870451f 100644
--- a/contrib/xntpd/VERSION
+++ b/contrib/xntpd/VERSION
@@ -1 +1 @@
-version=3.3c (beta)
+version=3.3s (beta multicast)
diff --git a/contrib/xntpd/authstuff/authspeed.c b/contrib/xntpd/authstuff/authspeed.c
index c83d5b24497e..ecddbcd96ba1 100644
--- a/contrib/xntpd/authstuff/authspeed.c
+++ b/contrib/xntpd/authstuff/authspeed.c
@@ -2,7 +2,7 @@
* authspeed - figure out how LONG it takes to do an NTP encryption
*/
-#if defined(SYS_HPUX) || defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SOLARIS) || defined(SYS_SVR4) || defined(SYS_PTX)
+#if defined(SYS_HPUX) || defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SOLARIS) || defined(SYS_SVR4) || defined(SYS_PTX) || defined(SYS_UNIXWARE1)
#define FAKE_RUSAGE
#endif
diff --git a/contrib/xntpd/conf/Config.local b/contrib/xntpd/conf/Config.local
index 12a6dfece755..22c12a36e90a 100644
--- a/contrib/xntpd/conf/Config.local
+++ b/contrib/xntpd/conf/Config.local
@@ -78,7 +78,7 @@ DEFS_OPT=-DDEBUG
# special distribution.
#
# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT)
-DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL
+DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DKERNEL_PLL -DMCAST
#
# Radio clock support definitions (these only make sense if -DREFCLOCK
@@ -182,7 +182,7 @@ DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL
# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC
# OSF/1 Alpha.
#
-CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHUPPS -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH
+CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHUPPS -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DLEITCH
#
# Directory into which binaries should be installed (default /usr/local)
diff --git a/contrib/xntpd/conf/Config.plain b/contrib/xntpd/conf/Config.plain
new file mode 100644
index 000000000000..67dd70ad50e6
--- /dev/null
+++ b/contrib/xntpd/conf/Config.plain
@@ -0,0 +1,190 @@
+# This is the local configure file (distribution version).
+# You must modify it to fit your particular configuration
+# and name it Config.local
+# The following configuratiions can be auto-generated:
+#
+# make Config.local.green
+# make a Config.local that supports a local clock
+# (i.e. allow fallback to use of the CPU's own clock)
+# make Config.local.NO.clock
+# make a Config.local that supports no clocks
+#
+#
+# NOTE TO GREENHORNS
+#
+# For plug-'n-play and no radios or other complicated gadgetry,
+# use "make Config.local.green" as above.
+#
+# Following defines can be set in the DEFS_OPT= define:
+#
+# The flag -DDEBUG includes some debugging code. To use this, include
+# the define and start the daemon with one or more -d flags, depending
+# on your calibration of pearannoya. The daemon will not detach your
+# terminal in this case. Judicious use of grep will reduce the speaker
+# volume to bearable levels.
+#
+# To change the location of the configuration file, use a
+# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar.
+#
+# The -DSYSLOG_FILE defines allows logging messages that are normally
+# reported via syslof() in a file. The file name can be configured using
+# the configuration line "logfile <filename>" in CONFIG_FILE.
+#
+# There are three serial port system software interfaces, each of
+# which is peculiar to one or more Unix versions. Define
+# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM
+# for POSIX compatibility including System V Streams, and
+# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three
+# should be defined. If none are defined, HAVE_BSD_TTYS is assumed.
+# Usually these defines are already set correctly.
+#
+DEFS_OPT=-DDEBUG
+
+#
+# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that)
+# and one of the following:
+#
+# The flag -DREFCLOCK causes the basic reference clock support to be
+# compiled into the daemon. If you set this you may also want to
+# configure the particular clock drivers you want in the CLOCKDEFS= line
+# below. This flag affects xntpd only. This define is included by
+# default when using the "make makeconfig" script.
+#
+# The next two sets of defines are meaningful only when radio clock
+# drivers or special 1-pps signals are to be used. For systems without
+# these features, these delicious complexities can be avoided. Ordinarily,
+# the "make makeconfig" script figures out which ones to use, but your
+# mileage may vary.
+#
+# There are three ways to utilize external 1-pps signals. Define
+# -DPPS to include just the pps routine, such as used by the DCF77(PARSE)
+# clock driver. Define -DPPSCLK to include a serial device driver
+# which avoids much of the jitter due to upper level port
+# processing. This requires a dedicated serial port and either the
+# tty_clock line discipline or tty_clk_streams module, both of
+# which are in the ./kernel directory. Define -DPPSCD to include a
+# special driver which intercepts carrier-detect transitions
+# generated by the pps signal. This requires a nondedicated serial
+# port and the ppsclock streams module in the ./kernel directory.
+# Only one of these three flags should be defined.
+#
+# The flag KERNEL_PLL causes code to be compiled for a special feature of
+# the kernel that (a) implements the phase-lock loop and (b) provides
+# a user interface to learn time, maximum error and estimated error.
+# See the file README.kern in the doc directory for further info.
+# This code is activated only if the relevant kernel features have
+# been configured; it does not affect operation of unmodified kernels.
+# To compile it, however, requires a few header files from the
+# special distribution.
+#
+# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT)
+DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DKERNEL_PLL -DMCAST
+
+#
+# Radio clock support definitions (these only make sense if -DREFCLOCK
+# used), which is normally the case. Note that a configuration can include
+# no clocks, more than one type of clock and even multiple clocks of the
+# same type.
+#
+# For most radio clocks operating with serial ports, accuracy can
+# be considerably improved through use of the tty_clk line
+# discipline or tty_clk_STREAMS streams module found in the
+# ./kernel directory. These gizmos capture a timestamp upon
+# occurrence of an intercept character and stuff it in the data
+# stream for the clock driver to munch. To select this mode,
+# postfix the driver name with the string CLK; that is, WWVB
+# becomes WWVBCLK. If more than one clock is in use, the CLK
+# postfix can be used with any or all of them.
+#
+# Alternatively, for the best accuracy, use the ppsclock streams
+# module in the ./ppsclock directory to steal the carrier-detect
+# transition and capture a precision timestamp. At present this
+# works only with SunOS 4.1.1 or later. To select this mode,
+# postfix the driver name with the string PPS; that is, AS2201
+# becomes AS2201PPS. If more than one clock is in use, the PPS
+# postfix should be used with only one of them. If any PPS
+# postfix is defined, the -DPPSPPS define should be used on the
+# DEFS above.
+#
+# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a
+# reference clock for those subnets without access to the real thing.
+# Works in all systems and requires no hardware support. This is defined
+# by default when using the "make makeconfig" script and greenhorn
+# configuraiton.
+#
+# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver
+# supports both the CLK and PPS modes. It should work in all systems
+# with a serial port.
+#
+# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It
+# should work in all systems with a serial port. The driver supports
+# both the CLK and PPS modes if the requisite kernel support is installed.
+#
+# Define -DCHU for a special CHU receiver using an ordinary shortwave
+# radio. This requires the chu_clk line discipline or chu_clk_STREAMS
+# module in the ./kernel directory. At present, this driver works only
+# on SunOS4.1.x; operation in other systems has not been confirmed.
+# Construction details for a suitable modem can be found in the ./gadget
+# directory. The driver supports # neither the CLK nor PPS modes.
+#
+# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance
+# this requires a special parsestreams STREAMS (SunOS 4.x) module in the
+# ./parse directory. Define -DPARSEPPS for PPS support via the
+# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above.
+# Define: -DCLOCK_MEINBERG for Meinberg clocks
+# -DCLOCK_SCHMID for Schmid receivers
+# -DCLOCK_DCF7000 for ELV DCF7000
+# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx)
+# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver
+#
+# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this
+# driver works only on SunOS4.1.x with CPU serial ports only. The PPS
+# mode is required.
+#
+# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should
+# work in all systems with a serial port. The driver does not support the
+# CLK mode, but does support the PPS mode. If the radio is connected to
+# more than one machine, the PPS mode is required.
+#
+# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This
+# driver is known to work with some other TrueTime products as well,
+# including the GPS-DC GPS receiver. It should work in all systems with
+# a serial port. The driver does not support the CLK mode, but does
+# support the PPS mode.
+#
+# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It
+# should work in all systems with a serial port. The driver does not
+# support the CLK mode, but does support the PPS mode.
+#
+# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This
+# requires the SunOS interface driver available from KSI. The driver
+# supports neither the CLK nor PPS modes.
+#
+# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for
+# the HP 5061B Cesium Clock. It should work in all systems with a serial
+# port. The driver does not support the CLK mode, but does support the
+# PPS mode.
+#
+# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works
+# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS
+# files on cl.cam.ac.uk still has support for CLK and CBREAK modes.
+#
+# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of
+# the Sun SPARCstations. This requires a modified BSD audio driver and
+# exclusive access to the audio port. A memo describing how it works and
+# how to install the driver is in the README.irig file in the ./doc
+# directory.
+#
+# Note: The following defines result in compilation of all the above radio
+# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and
+# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes
+# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile
+# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC
+# OSF/1 Alpha.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DCHU -DGOES -DOMEGA -DPST -DWWVB -DLEITCH
+
+#
+# Directory into which binaries should be installed (default /usr/local)
+#
+BINDIR= /usr/local/bin
diff --git a/contrib/xntpd/doc/README.kern b/contrib/xntpd/doc/README.kern
index 1b791c325ccf..aac26fa2e62b 100644
--- a/contrib/xntpd/doc/README.kern
+++ b/contrib/xntpd/doc/README.kern
@@ -1,567 +1,756 @@
- Unix Kernel Modifications for Precision Timekeeping
-
- Revised 3 December 1993
-
-Note: This information file is included in the distributions for the
-SunOS, Ultrix and OSF/1 kernels and in the NTP Version 3 distribution
-(xntp3.tar.Z) as the file README.kern. Availability of the kernel
-distributions, which involve licensed code, will be announced
-separately. The NTP Version 3 distribution can be obtained via anonymous
-ftp from louie.udel.edu in the directory pub/ntp. In order to utilize
-all features of this distribution, the NTP version number should be 3.3
+ A Kernel Model for Precision Timekeeping
+
+ Revised 3 April 1994
+
+Note: This memorandum is a substantial revision of RFC-1589, "A Kernel
+Model for Precision Timekeeping," March, 1994. It includes several
+changes to the daemon and user interfaces, as well as a new feature
+which disciplines the CPU clock oscillator in both time and frequency to
+a source of precision time signals. This memorandum is included in the
+distributions for the SunOS, Ultrix and OSF/1 kernels and in the NTP
+Version 3 distribution (xntp3.v.tar.Z) as the file README.kern, where v
+is the version identifier. Availability of the kernel distributions,
+which involve licensed code, will be announced separately. The NTP
+Version 3 distribution can be obtained via anonymous ftp from
+louie.udel.edu in the directory pub/ntp. In order to utilize all
+features of this distribution, the NTP version identifier should be 3q
or later.
+Overview
+
+This memorandum describes an engineering model which implements a
+precision time-of-day function for a generic operating system. The model
+is based on the principles of disciplined oscillators and phase-lock
+loops (PLL) and frequency-lock loops (FLL) often found in the
+engineering literature. It has been implemented in the Unix kernels for
+several workstations, including those made by Sun Microsystems and
+Digital Equipment. The model changes the way the system clock is
+adjusted in time and frequency, as well as provides mechanisms to
+discipline its frequency to an external precision timing source. The
+model incorporates a generic system-call interface for use with the
+Network Time Protocol (NTP) or similar time synchronization protocol.
+The NTP Version 3 daemon xntpd operates with this model to provide
+synchronization limited in principle only by the accuracy and stability
+of the external timing source.
+
+This memorandum does not obsolete or update any RFC. It does not propose
+a standard protocol, specification or algorithm. It is intended to
+provoke comment, refinement and implementations for kernels not
+considered herein. While a working knowledge of NTP is not required for
+an understanding of the design principles or implementation of the
+model, it may be helpful in understanding how the model behaves in a
+fully functional timekeeping system. The architecture and design of NTP
+is described in [MIL91], while the current NTP Version 3 protocol
+specification is given in RFC-1305 [MIL92a] and a subset of the
+protocol, the Simple Network Time Protocol (SNTP), is given in RFC-1361
+[MIL92c].
+
+The model has been implemented in the Unix kernels for three Sun
+Microsystems and Digital Equipment workstations. In addition, for the
+Digital machines the model provides improved precision to one
+microsecond (us). Since these specific implementations involve
+modifications to licensed code, they cannot be provided directly.
+Inquiries should be directed to the manufacturer's representatives.
+However, the engineering model for these implementations, including a
+simulator with code segments almost identical to the implementations,
+but not involving licensed code, is available via anonymous FTP from
+host louie.udel.edu in the directory pub/ntp and compressed tar archive
+kernel.tar.Z. The NTP Version 3 distribution can be obtained via
+anonymous ftp from the same host and directory in the compressed tar
+archive xntp3.3q.tar.Z, where the version number shown as 3.3q may be
+adjusted for new versions as they occur.
+
1. Introduction
-This memo describes modifications to certain SunOS, Ultrix and OSF/1
-kernel software that manage the system clock and timer functions. They
-provide improved accuracy and stability through the use of a disciplined
-clock interface for use with the Network Time Protocol (NTP) or similar
-time-synchronization protocol. In addition, for the DEC 3000 AXP (Alpha)
-and DECstation 5000/240 machines, the modifications provide improved
-precision within one microsecond (us) (SunOS 4.1.x already does provide
-precision to this order). The NTP Version 3 daemon xntpd operates with
-these kernel modifications to provide synchronization in principle to
-within this order, but in practice this is limited by the short-term
-stability of the timer oscillator to within the order of 100 usec.
-
-This memo describes the principles behind the design and operation of
-the new software. There are three versions: one that operates with the
-SunOS 4.1.x kernels, a second that operates with the Ultrix 4.x kernels
-and a third that operates with the OSF/1 V1.x kernels. A detailed
-description of the variables and algorithms is given in the hope that
-similar functionality can be incorporated in Unix kernels for other
-machines. The algorithms involve only minor changes to the system clock
-and interval timer routines and include interfaces for application
-programs to learn the system clock status and certain statistics of the
-time-synchronization process. Detailed installation instructions are
-given in a companion README.install file included in the kernel
-distributions. The kernel software itself is not provided for public
-distribution, since it involves licensed code. Detailed instructions on
-how to obtain it for either SunOS, Ultrix or OSF/1 will be given
-separately.
-
-The principal feature added to the Unix kernels is to change the way the
-system clock is controlled, in order to provide precision time and
-frequency adjustments. Another feature utilizes an undocumented bus-
-cycle counter in the DEC 3000 AXP and DECstation 5000/240 to provide
-precise time to the microsecond. This feature can in principle be used
-with any DEC machine that has this counter, although this has not been
-verified. The addition of these features does not affect the operation
-of existing Unix system calls such as gettimeofday(), settimeofday() and
-adjtime(); however, if the new features are in use, the operations of
-adjtime() are controlled instead by a new system call ntp_adjtime().
-
-Most Unix programs read the system clock using the gettimeofday() system
-call, which returns only the system time and timezone data. For some
-applications it is useful to know the maximum error of the reported time
-due to all causes, including clock reading errors, oscillator frequency
-errors and accumulated latencies on the path to a primary reference
-source. However, the new software can adjust the system clock to
-compensate for its intrinsic frequency error, so that the timing errors
-expected in normal operation will usually be much less than the maximum
-error. The user application interface includes a new system call
-ntp_gettime(), which returns the system time, as well as the maximum
-error and estimated error. This interface is intended to support
-applications that need such things, including distributed file systems,
-multimedia teleconferencing and other real-time applications. The
-protocol daemon application interface includes a new system call
-ntp_adjtime(), which can be used to read and write kernel variables used
-for precision timekeeping, including time and frequency adjustments,
-controlling time constant, leap-second warning and related data.
-
-In this memo, NTP Version 3 and the Unix implementation xntpd are used
-as an example application of the new system calls for use by a protocol
-daemon. In principle, the new system calls can be used by other
-protocols and daemon implementations as well. Even in cases where the
+This memorandum describes a model and programming interface for generic
+operating system software that manages the system clock and timer
+functions. The model provides improved accuracy and stability for most
+computers using the Network Time Protocol (NTP) or similar time
+synchronization protocol. This memorandum describes the design
+principles and implementations of the model, while related technical
+reports discuss the design approach, engineering analysis and
+performance evaluation of the model as implemented in Unix kernels for
+modern workstations. The NTP Version 3 daemon xntpd operates with these
+implementations to provide improved accuracy and stability, together
+with diminished overhead in the operating system and network. In
+addition, the model supports the use of external timing sources, such as
+precision pulse-per-second (PPS) signals and the industry standard IRIG
+timing signals. The NTP daemon automatically detects the presence of the
+new features and utilizes them when available.
+
+There are three prototype implementations of the model presented in this
+memorandum, one each for the Sun Microsystems SPARCstation with the
+SunOS 4.1.x kernel, Digital Equipment DECstation 5000 with the Ultrix
+4.x kernel and Digital Equipment 3000 AXP Alpha with the OSF/1 V1.x
+kernel. In addition, for the DECstation 5000/240 and 3000 AXP Alpha
+machines, a special feature provides improved precision to 1 us (stock
+Sun kernels already do provide this precision). Other than improving the
+system clock accuracy, stability and precision, these implementations do
+not change the operation of existing Unix system calls which manage the
+system clock, such as gettimeofday(), settimeofday() and adjtime();
+however, if the new features are in use, the operations of
+gettimeofday() and adjtime() can be controlled instead by new system
+calls ntp_gettime() and ntp_adjtime() as described below.
+
+A detailed description of the variables and algorithms that operate upon
+them is given in the hope that similar functionality can be incorporated
+in Unix kernels for other machines. The algorithms involve only minor
+changes to the system clock and interval timer routines and include
+interfaces for application programs to learn the system clock status and
+certain statistics of the time synchronization process. Detailed
+installation instructions are given in a specific README files included
+in the kernel distributions.
+
+In this memorandum, NTP Version 3 and the Unix implementation xntp3 are
+used as an example application of the new system calls for use by a
+synchronization daemon. In principle, these system calls can be used by
+other protocols and implementations as well. Even in cases where the
local time is maintained by periodic exchanges of messages at relatively
-long intervals, such as using the NIST Automated Computer Time Service,
-the ability to precisely adjust the local clock frequency simplifies the
-synchronization procedures and allows the call frequency to be
-considerably reduced.
-
-2. Design Principles
-
-In order to understand how the new software works, it is useful to
-consider how most Unix systems maintain the system time. In the original
-design a hardware timer interrupts the kernel at a fixed rate: 100 Hz in
-the SunOS kernel, 256 Hz in the Ultrix kernel and 1024 Hz in the OSF/1
-kernel. Since the Ultrix kernel rate does not evenly divide one second
-in microseconds, the kernel adds 64 microseconds once each second, so
-the timescale consists of 255 advances of 3906 usec plus one of 3970
-usec. Similarly, the OSF/1 kernel adds 576 usec once each second, so its
-timescale consists of 1023 advances of 976 usec plus one of 1552 usec.
-
-In all Unix kernels considered in this memo, it is possible to slew the
-system clock to a new offset using the standard Unix adjtime() system
-call. To do this the clock frequency is changed by adding or subtracting
-a fixed amount (tickadj) at each timer interrupt (tick) for a calculated
-number of ticks. Since this calculation involves dividing the requested
-offset by tickadj, it is possible to slew to a new offset with a
-precision only of tickadj, which is usually in the neighborhood of 5 us,
-but sometimes much higher. This results in an amortization error which
-can accumulate to unacceptable levels, so that special provisions must
-be made in the clock adjustment procedures of the protocol daemon.
-
-In order to maintain the system clock within specified bounds with this
-scheme, it is necessary to call adjtime() on a regular basis. For
-instance, let the bound be set at 100 usec, which is a reasonable value
-for NTP-synchronized hosts on a local network, and let the onboard
-oscillator tolerance be 100 parts-per-million (ppm), which is a
-reasonably conservative assumption. This requires that adjtime() be
-called at intervals not exceeding 1 second (s), which is in fact what
-the unmodified NTP software daemon does.
-
-In the new software this scheme is replaced by another that extends the
-low-order bits of the system clock to provide very precise clock
-adjustments. At each timer interrupt a precisely calibrated quantity is
-added to the composite time value and overflows handled as required. The
-quantity is computed from the measured clock offset and in addition a
-frequency adjustment, which is automatically calculated from previous
-time adjustments. This implementation operates as an adaptive-parameter
-first-order, type-II, phase-lock loop (PLL), which in principle provides
-precision control of the system clock phase to within +-1 us and
-frequency to within +-5 nanoseconds (ns) per day.
-
-This PLL model is identical to the one implemented in NTP, except that
-in NTP the software daemon has to simulate the PLL using only the
-original adjtime() system call. The daemon is considerably complicated
-by the need to parcel time adjustments at frequent intervals in order to
-maintain the accuracy to specified bounds. The modified kernel routines
-do this directly, allowing vast gobs of ugly daemon code to be avoided
-at the expense of only a small amount of new code in the kernel. In
-fact, the amount of code added to the kernel for the new scheme is about
-the amount needed to implement the old scheme. A new system call
-ntp_adjtime(), which operates in a way similar to the original
-adjtime(), is called only as each new time update is determined, which
-in NTP occurs at intervals of from 16 s to 1024 s. In addition, doing
-the frequency correction in the kernel means that the system time runs
-true even if the daemon were to cease operation or the network paths to
-the primary reference source fail. The addition of the new ntp_adjtime()
-system call does not affect the original adjtime() system call, which
-continues to operate in its traditional fashion. However, the two system
-calls canot be used at the same time; only one of the two should be used
-on any given system.
-
-It is the intent in the design that settimeofday() be used for changes
-in system time greater than +-128 ms. It has been the Internet
-experience that the need to change the system time in increments greater
-than +-128 milliseconds is extremely rare and is usually associated with
-a hardware or software malfunction or system reboot. Once the system
-clock has been set in this way, the ntp_adjtime() system call is used to
-provide periodic updates including the time offset, maximum error,
-estimated error and PLL time constant. With NTP the update interval
-depends on the measured error and time constant; however, the scheme is
-quite forgiving and neither moderate loss of updates nor variations in
-the length of the polling interval are serious.
-
-In addition, the kernel adjusts the maximum error to grow by an amount
-equal to the oscillator frequency tolerance times the elapsed time since
-the last update. The default engineering parameters have been optimized
-for intervals not greater than about 16 s. For longer intervals the PLL
-time constant can be adjusted to optimize the dynamic response up to
-intervals of 1024 s. Normally, this is automatically done by NTP. In any
-case, if updates are suspended, the PLL coasts at the frequency last
+long intervals, such as using the NIST Automated Computer Time Service
+[LEV89], the ability to precisely adjust the system clock frequency
+simplifies the synchronization procedures and allows the telephone call
+frequency to be considerably reduced.
+
+2. Design Approach
+
+While not strictly necessary for an understanding or implementation of
+the model, it may be helpful to briefly describe how NTP operates to
+control the system clock in a client computer. As described in [MIL91],
+the NTP protocol exchanges timestamps with one or more peers sharing a
+synchronization subnet to calculate the time offsets between peer clocks
+and the local clock. These offsets are processed by several algorithms
+which refine and combine the offsets to produce an ensemble average,
+which is then used to adjust the local clock time and frequency. The
+manner in which the local clock is adjusted represents the main topic of
+this memorandum. The goal in the enterprise is the most accurate and
+stable system clock possible with the available computer hardware and
+kernel software.
+
+In order to understand how the new model works, it is useful to review
+how most Unix kernels maintain the system clock. In the Unix design a
+hardware counter interrupts the kernel at a fixed rate: 100 Hz in the
+SunOS kernel, 256 Hz in the Ultrix kernel and 1024 Hz in the OSF/1
+kernel. Since the Ultrix timer interval (reciprocal of the rate) does
+not evenly divide one second in microseconds, the kernel adds 64 us once
+each second, so the timescale consists of 255 advances of 3906 us plus
+one of 3970 us. Similarly, the OSF/1 kernel adds 576 us once each
+second, so its timescale consists of 1023 advances of 976 us plus one of
+1552 us.
+
+2.1. Mechanisms to Adjust Time and Frequency
+
+In most Unix kernels it is possible to slew the system clock to a new
+offset relative to the current time by using the adjtime() system call.
+To do this the clock frequency is changed by adding or subtracting a
+fixed amount (tickadj) at each timer interrupt (tick) for a calculated
+number of timer interrupts. Since this calculation involves dividing the
+requested offset by tickadj, it is possible to slew to a new offset with
+a precision only of tickadj, which is usually in the neighborhood of 5
+us, but sometimes much larger. This results in a roundoff error which
+can accumulate to an unacceptable degree, so that special provisions
+must be made in the clock adjustment procedures of the synchronization
+daemon.
+
+In order to implement a frequency discipline function, it is necessary
+to provide time offset adjustments to the kernel at regular adjustment
+intervals using the adjtime() system call. In order to reduce the system
+clock jitter to the regime consistent with the model, it is necessary
+that the adjustment interval be relatively small, in the neighborhood of
+1 s. However, the Unix adjtime() implementation requires each offset
+adjustment to complete before another one can be begun, which means that
+large adjustments must be amortized over possibly many adjustment
+intervals. The requirement to implement the adjustment interval and
+compensate for roundoff error considerably complicates the synchronizing
+daemon implementation.
+
+In the new model this scheme is replaced by another that represents the
+system clock as a multiple-word, precision-time variable in order to
+provide very precise clock adjustments. At each timer interrupt a
+precisely calibrated quantity is added to the kernel time variable and
+overflows propagated as required. The quantity is computed as in the NTP
+local clock model described in [MIL92b], which operates as an adaptive-
+parameter, first-order, type-II phase-lock loop (PLL). In principle,
+this PLL design can provide precision control of the system clock
+oscillator within 1 us and frequency to within parts in 10^11. While
+precisions of this order are surely well beyond the capabilities of the
+CPU clock oscillator used in typical workstations, they are appropriate
+using precision external oscillators, as described below.
+
+The PLL design is identical to the one originally implemented in NTP and
+described in [MIL92b]. In the original design the software daemon
+simulates the PLL using the adjtime() system call; however, the daemon
+implementation is considerably complicated by the considerations
+described above. The modified kernel routines implement the PLL in the
+kernel using precision time and frequency representations, so that these
+complications are avoided. A new system call ntp_adjtime() is called
+only as each new time update is determined, which in NTP occurs at
+intervals of from 16 s to 1024 s. In addition, doing frequency
+compensation in the kernel means that the system clock runs true even if
+the daemon were to cease operation or the network paths to the primary
+synchronization source fail.
+
+In the new model the new ntp_adjtime() operates in a way similar to the
+original adjtime() system call, but does so independently of adjtime(),
+which continues to operate in its traditional fashion. When used with
+NTP, it is the design intent that settimeofday() or adjtime() be used
+only for system clock adjustments greater than +-128 ms, although the
+dynamic range of the new model is much larger at +-512 ms. It has been
+the Internet experience that the need to change the system clock in
+increments greater than +-128 ms is extremely rare and is usually
+associated with a hardware or software malfunction or system reboot.
+
+The easiest way to set the time is with the settimeofday() system call;
+however, this can under some conditions cause the clock to jump
+backwards. If this cannot be tolerated, adjtime() can be used to slew
+the clock to the new value without running backward or affecting the
+frequency discipline process. Once the system clock has been set within
++-128 ms, the ntp_adjtime() system call is used to provide periodic
+updates including the time offset, maximum error, estimated error and
+PLL time constant. With NTP the update interval and time constant depend
+on the measured delay and dispersion; however, the scheme is quite
+forgiving and neither moderate loss of updates nor variations in the
+update interval are serious.
+
+2.2 Daemon and Application Interface
+
+Unix application programs can read the system clock using the
+gettimeofday() system call, which returns only the system time and
+timezone data. For some applications it is useful to know the maximum
+error of the reported time due to all causes, including clock reading
+errors, oscillator frequency errors and accumulated latencies on the
+path to the primary synchronization source. However, in the new model
+the PLL adjusts the system clock to compensate for its intrinsic
+frequency error, so that the time error expected in normal operation
+will usually be much less than the maximum error. The programming
+interface includes a new system call ntp_gettime(), which returns the
+system time, as well as the maximum error and estimated error. This
+interface is intended to support applications that need such things,
+including distributed file systems, multimedia teleconferencing and
+other real-time applications. The programming interface also includes a
+new system call ntp_adjtime(), which can be used to read and write
+kernel variables for time and frequency adjustment, PLL time constant,
+leap-second warning and related data.
+
+In addition, the kernel adjusts the indicated maximum error to grow by
+an amount equal to the maximum oscillator frequency tolerance times the
+elapsed time since the last update. The default engineering parameters
+have been optimized for update intervals in the order of 64 s. As shown
+in [MIL93], this is near the optimum interval for NTP used with ordinary
+room-temperature quartz oscillators. For other intervals the PLL time
+constant can be adjusted to optimize the dynamic response over intervals
+of 16-1024 s. Normally, this is automatically done by NTP. In any case,
+if updates are suspended, the PLL coasts at the frequency last
determined, which usually results in errors increasing only to a few
-tens of milliseconds over a day.
-
-The new code needs to know the initial frequency offset and time
-constant for the PLL, and the daemon needs to know the current frequency
-offset computed by the kernel for monitoring purposes. These data are
-exchanged between the kernel and protocol daemon using ntp_adjtime() as
-documented later in this memo. Provisions are made to exchange related
-timing information, such as the maximum error and estimated error,
-between the kernel and daemon and between the kernel and application
-programs.
-
-In the DEC 3000 AXP, DECstation 5000/240 and possibly other DEC
-machines there is an undocumented hardware register that counts system
-bus cycles at a rate of 25 MHz. The new kernel microtime() routine tests
-for the CPU type and, in the case of these machines, use this register
-to interpolate system time between hardware timer interrupts. This
-results in a precision of +-1 us for all time values obtained via the
-gettimeofday() and ntp_gettime() system calls. These routines call the
-microtime() routine, which returns the actual interpolated value but
-does not change the kernel time variable. Therefore, other kernel
-routines that access the kernel time variable directly and do not call
-either gettimeofday(), ntp_gettime() or microtime() will continue their
-present behavior. The microtime() feature is independent of other
-features described here and is operative even if the kernel PLL or new
-system calls have not been implemented.
-
-While any protocol daemon can in principle be modified to use the new
-system calls, the most likely will be users of the NTP Version 3 daemon
-xntpd. The xntpd code determines whether the new system calls are
+tens of milliseconds over a day using typical modern workstations.
+
+While any synchronization daemon can in principle be modified to use the
+new system calls, the most likely will be users of the NTP Version 3
+daemon xntpd. The xntpd code determines whether the new system calls are
implemented and automatically reconfigures as required. When
-implemented, the daemon reads the frequency offset from a file and
-provides it and the initial time constant via ntp_adjtime(). In
-subsequent calls to ntp_adjtime(), only the time adjustment and time
+implemented, the daemon reads the frequency offset from a system file
+and provides it and the initial time constant via ntp_adjtime(). In
+subsequent calls to ntp_adjtime(), only the time offset and time
constant are affected. The daemon reads the frequency from the kernel
-using ntp_adjtime() at intervals of about one hour and writes it to the
-system log file. This information is recovered when the daemon is
-restarted after reboot, for example, so the sometimes extensive training
-period to learn the frequency separately for each system can be avoided.
-
-3. Kernel Interfaces
-
-This section describes the kernel interfaces to the protocol daemon and
-user applications. The ideas are based on suggestions from Jeff Mogul
-and Philip Gladstone and a similar interface designed by the latter. It
-is important to point out that the functionality of the original Unix
-adjtime() system call is preserved, so that the modified kernel will
-work as the unmodified one should the kernel PLL not be in use. In this
-case the ntp_adjtime() system call can still be used to read and write
-kernel variables that might be used by a protocol daemon other than NTP,
-for example.
-
-3.1. The ntp_gettime() System Call
-
-The syntax and semantics of the ntp_gettime() call are given in the
-following fragment of the timex.h header file. This file is identical in
-the SunOS, Ultrix and OSF/1 kernel distributions. Note that the timex.h
-file calls the syscall.h system header file, which must be modified to
-define the SYS_ntp_gettime system call specific to each system type. The
-kernel distributions include directions on how to do this.
-
-/*
- * This header file defines the Network Time Protocol (NTP) interfaces
- * for user and daemon application programs. These are implemented using
- * private system calls and data structures and require specific kernel
- * support.
- *
- * NAME
- * ntp_gettime - NTP user application interface
- *
- * SYNOPSIS
- * #include <sys/timex.h>
- *
- * int system call(SYS_ntp_gettime, tptr)
- *
- * int SYS_ntp_gettime defined in syscall.h header file
- * struct ntptimeval *tptr pointer to ntptimeval structure
- *
- * NTP user interface - used to read kernel clock values
- * Note: maximum error = NTP synch distance = dispersion + delay / 2;
- * estimated error = NTP dispersion.
- */
-struct ntptimeval {
- struct timeval time; /* current time */
- long maxerror; /* maximum error (usec) */
- long esterror; /* estimated error (usec) */
-};
-
-The ntp_gettime() system call returns three values in the ntptimeval
-structure: the current time in unix timeval format plus the maximum and
-estimated errors in microseconds. While the 32-bit long data type limits
-the error quantities to something more than an hour, in practice this is
-not significant, since the protocol itself will declare an
-unsynchronized condition well below that limit. If the protocol computes
-either of these values in excess of 16 seconds, they are clamped to that
-value and the local clock declared unsynchronized.
-
-Following is a detailed description of the ntptimeval structure members.
-
-struct timeval time;
-
- This member is set to the current system time, expressed as a Unix
- timeval structure. The timeval structure consists of two 32-bit
- words, one for the number of seconds past 1 January 1970 and the
- other the number of microseconds past the most recent second's
- epoch.
-
-long maxerror;
-
- This member is set to the value of the time_maxerror kernel
- variable, which establishes the maximum error of the indicated time
- relative to the primary reference source, in microseconds. This
- variable can also be set and read by the ntp_adjtime() system call.
- For NTP, the value is determined as the synchronization distance,
- which is equal to the root dispersion plus one-half the root delay.
- It is increased by a small amount (time_tolerance) each second to
- reflect the clock frequency tolerance. This variable is computed by
- the time-synchronization daemon and the kernel and returned in a
- ntp_gettime() system call, but is otherwise not used by the kernel.
-
-long esterror;
-
- This member is set to the value of the time_esterror kernel
- variable, which establishes the expected error of the indicated
- time relative to the primary reference source, in microseconds.
- This variable can also be set and read by the ntp_adjtime() system
- call. For NTP, the value is determined as the root dispersion,
- which represents the best estimate of the actual error of the
- system clock based on its past behavior, together with observations
- of multiple clocks within the peer group. This variable is computed
- by the time-synchronization daemon and returned in a ntp_gettime()
- system call, but is otherwise not used by the kernel.
-
-3.2. The ntp_adjtime() System Call
-
-The syntax and semantics of the ntp_adjtime() call is given in the
-following fragment of the timex.h header file. Note that, as in the
-ntp_gettime() system call, the the syscall.h system header file must be
-modified to define the SYS_ntp_adjtime system call specific to each
-system type.
-
-/*
- * NAME
- * ntp_adjtime - NTP daemon application interface
- *
- * SYNOPSIS
- * #include <sys/timex.h>
- *
- * int system call(SYS_ntp_adjtime, mode, tptr)
- *
- * int SYS_ntp_adjtime defined in syscall.h header file
- * struct timex *tptr pointer to timex structure
- *
- * NTP daemon interface - used to discipline kernel clock oscillator
- */
-struct timex {
- int mode; /* mode selector */
- long offset; /* time offset (usec) */
- long frequency; /* frequency offset (scaled ppm) */
- long maxerror; /* maximum error (usec) */
- long esterror; /* estimated error (usec) */
- int status; /* clock command/status */
- long time_constant; /* pll time constant */
- long precision; /* clock precision (usec) (read only) */
- long tolerance; /* clock frequency tolerance (ppm)
- * (read only)
- */
-};
-
-The ntp_adjtime() system call is used to read and write certain time-
-related kernel variables summarized in this and subsequent sections.
-Writing these variables can only be done in superuser mode. To write a
-variable, the mode structure member is set with one or more bits, one of
-which is assigned each of the following variables in turn. The current
-values for all variables are returned in any case; therefore, a mode
-argument of zero means to return these values without changing anything.
-
-Following is a description of the timex structure members.
-
-int mode;
-
- This is a bit-coded variable selecting one or more structure
- members, with one bit assigned each member. If a bit is set, the
- value of the associated member variable is copied to the
- corresponding kernel variable; if not, the member is ignored. The
- bits are assigned as given in the following fragment of the timex.h
- header file. Note that the precision and tolerance are intrinsic
- properties of the kernel configuration and cannot be changed.
-
- /*
- * Mode codes (timex.mode)
- */
- #define ADJ_OFFSET 0x0001 /* time offset */
- #define ADJ_FREQUENCY 0x0002 /* frequency offset */
- #define ADJ_MAXERROR 0x0004 /* maximum time error */
- #define ADJ_ESTERROR 0x0008 /* estimated time error */
- #define ADJ_STATUS 0x0010 /* clock status */
- #define ADJ_TIMECONST 0x0020 /* pll time constant */
-
-long offset;
-
- If selected, this member (scaled) replaces the value of the
- time_offset kernel variable, which defines the current time offset
- of the phase-lock loop. The value must be in the range +-512 ms in
- the present implementation. If so, the clock status is
- automatically set to TIME_OK.
-
-long time_constant;
-
- If selected, this member replaces the value of the time_constant
- kernel variable, which establishes the bandwidth of "stiffness" of
- the kernel PLL. The value is used as a shift, with the effective
- PLL time constant equal to a multiple of (1 << time_constant), in
- seconds. The optimum value for the time_constant variable is
- log2(update_interval) - 4, where update_interval is the nominal
- interval between clock updates, in seconds. With an ordinary crystal
- oscillator the optimum value for time_constant is about 2, giving
- an update_interval of 4 (64 s). Values of time_constant between zero
- and 2 can be used if quick convergence is necessary; values between
- 2 and 6 can be used to reduce network load, but at a modest cost in
- accuracy. Values above 6 are appropriate only if a precision
- oscillator is available.
-
-long frequency;
-
- If selected, this member (scaled) replaces the value of the
- time_frequency kernel variable, which establishes the intrinsic
- frequency of the local clock oscillator. This variable is scaled by
- (1 << SHIFT_USEC) in parts-per-million (ppm), giving it a maximum
- value of about +-31 ms/s and a minimum value (frequency resolution)
- of about 2e-11, which is appropriate for even the best quartz
- oscillator.
-
-long maxerror;
-
- If selected, this member replaces the value of the time_maxerror
- kernel variable, which establishes the maximum error of the
- indicated time relative to the primary reference source, in
- microseconds. This variable can also be read by the ntp_gettime()
- system call. For NTP, the value is determined as the
- synchronization distance, which is equal to the root dispersion
- plus one-half the root delay. It is increased by a small amount
- (time_tolerance) each second to reflect the clock frequency
- tolerance. This variable is computed by the time-synchronization
- daemon and the kernel and returned in a ntp_gettime() system call,
- but is otherwise not used by the kernel.
-
-long esterror;
-
- If selected, this member replaces the value of the time_esterror
- kernel variable, which establishes the expected error of the
- indicated time relative to the primary reference source, in
- microseconds. This variable can also be read by the ntp_gettime()
- system call. For NTP, the value is determined as the root
- dispersion, which represents the best estimate of the actual error
- of the system clock based on its past behavior, together with
- observations of multiple clocks within the peer group. This
- variable is computed by the time-synchronization daemon and
- returned in a ntp_gettime() system call, but is otherwise not used
- by the kernel.
-
-int status;
-
- If selected, this member replaces the value of the time_status
- kernel variable, which records whether the clock is synchronized,
- waiting for a leap second, etc. In order to set this variable
- explicitly, either (a) the current clock status is TIME_OK or (b)
- the member value is TIME_BAD; that is, the ntp_adjtime() call can
- always set the clock to the unsynchronized state or, if the clock
- is running correctly, can set it to any state. In any case, the
- ntp_adjtime() call always returns the current state in this member,
- so the caller can determine whether or not the request succeeded.
-
-long precision;
-
- This member is set equal to the time_precision kernel in
- microseconds variable upon return from the system call. The
- time_precision variable cannot be written. This variable represents
- the maximum error in reading the system clock, which is ordinarily
- equal to the kernel variable tick, 10000 usec in the SunOS kernel,
- 3906 usec in Ultrix kernel and 976 usec in the OSF/1 kernel.
- However, in cases where the time can be interpolated with
- microsecond resolution, such as in the SunOS kernel and modified
- Ultrix and OSF/1 kernels, the precision is specified as 1 usec.
- This variable is computed by the kernel for use by the time-
- synchronization daemon, but is otherwise not used by the kernel.
-
-long tolerance;
-
- This member is set equal to the time_tolerance kernel variable in
- parts-per-million (ppm) upon return from the system call. The
- time_tolerance variable cannot be written. This variable represents
- the maximum frequency error or tolerance of the particular platform
- and is a property of the architecture and manufacturing process.
-
-3.3. Command/Status Codes
-
-The kernel routines use the system clock status variable time_status,
-which records whether the clock is synchronized, waiting for a leap
-second, etc. The value of this variable is returned as the result code
-by both the ntp_gettime() and ntp_adjtime() system calls. In addition,
-it can be explicitly read and written using the ntp_adjtime() system
-call, but can be written only in superuser mode. Values presently
-defined in the timex.h header file are as follows:
-
-/*
- * Clock command/status codes (timex.status)
- */
-#define TIME_OK 0 /* clock synchronized */
-#define TIME_INS 1 /* insert leap second */
-#define TIME_DEL 2 /* delete leap second */
-#define TIME_OOP 3 /* leap second in progress */
-#define TIME_BAD 4 /* clock not synchronized */
-
-A detailed description of these codes as used by the leap-second state
-machine is given later in this memo. In case of a negative result code,
-the kernel has intercepted an invalid address or (in case of the
-ntp_adjtime() system call), a superuser violation.
-
-4. Technical Summary
-
-In order to more fully understand the workings of the PLL, a stand-alone
-simulator kern.c is included in the kernel distributions. This is an
-implementation of an adaptive-parameter, first-order, type-II phase-lock
-loop. The system clock is implemented using a set of variables and
-algorithms defined in the simulator and driven by explicit offsets
-generated by the simulator. The algorithms include code fragments
-identical to those in the modified kernel routines and operate in the
-same way, but the operations can be understood separately from any
-licensed source code into which these fragments may be integrated. The
-code segments themselves are not derived from any licensed code.
-
-4.1. PLL Simulation
-
-In the simulator the hardupdate() fragment is called by ntp_adjtime() as
-each update is computed to adjust the system clock phase and frequency.
-Note that the time constant is in units of powers of two, so that
-multiplies can be done by simple shifts. The phase variable is computed
-as the offset multiplied by the time constant. Then, the time since the
-last update is computed and clamped to a maximum (for robustness) and to
-zero if initializing. The offset is multiplied (sorry about the ugly
-multiply) by the result and by the square of the time constant and then
-added to the frequency variable. Finally, the frequency variable is
-clamped not to exceed the tolerance. Note that all shifts are assumed to
-be positive and that a shift of a signed quantity to the right requires
-a little dance.
-
-With the defines given, the maximum time offset is determined by the
-size in bits of the long type (32) less the SHIFT_UPDATE scale factor or
-18 bits (signed). The scale factor is chosen so that there is no loss of
-significance in later steps, which may involve a right shift up to 14
-bits. This results in a maximum offset of about +-130 ms. Since
+using ntp_adjtime() at intervals of about one hour and writes it to a
+system file. This information is recovered when the daemon is restarted
+after reboot, for example, so the sometimes extensive training period to
+learn the frequency separately for each oscillator can be avoided.
+
+2.3. Precision Clocks for DECstation 5000/240 and 3000 AXP Alpha
+
+The stock microtime() routine in the Ultrix kernel for Digital Equipment
+MIPS-based workstations returns system time to the precision of the
+timer interrupt interval, which is in the 1-4 ms range. However, in the
+DECstation 5000/240 and possibly other machines of that family, there is
+an undocumented IOASIC hardware register that counts system bus cycles
+at a rate of 25 MHz. The new microtime() routine for the Ultrix kernel
+uses this register to interpolate system time between timer interrupts.
+This results in a precision of 1 us for all time values obtained via the
+gettimeofday() and ntp_gettime() system calls. For the Digital Equipment
+3000 AXP Alpha, the architecture provides a hardware Process Cycle
+Counter and a machine instruction (rpcc) to read it. This counter
+operates at the fundamental frequency of the CPU clock or some
+submultiple of it, 133.333 MHz for the 3000/400 for example. The new
+microtime() routine for the OSF/1 kernel uses this counter in the same
+fashion as the Ultrix routine. Support for this feature is conditionally
+compiled in the kernel only if the MICRO option is used in the kernel
+configuration file.
+
+In both the Ultrix and OSF/1 kernels the gettimeofday() and
+ntp_gettime() system call use the new microtime() routine, which returns
+the interpolated value to 1-us resolution, but does not change the
+kernel time variable. Therefore, other routines that access the kernel
+time variable directly and do not call either gettimeofday(),
+ntp_gettime() or microtime() will continue their present behavior. The
+microtime() feature is independent of other features described here and
+is operative even if the kernel PLL or new system calls have not been
+implemented.
+
+The SunOS kernel already includes a system clock with 1-us resolution;
+so, in principle, no microtime() routine is necessary. An existing
+kernel routine uniqtime() implements this function, but it is coded in
+the C language and is rather slow at 42-85 us per call on a SPARCstation
+IPC. A replacement microtime() routine coded in assembler language is
+available in the NTP Version 3 distribution and is much faster at about
+3 us per call. Note that, as explained later, this routine should be
+called at an interrupt priority level not greater than that of the timer
+interrupt routine. Otherwise, it is possible to miss a tick increment,
+with result the time returned can be late by one tick. This is always
+true in the case of gettimeofday() and ntp_gettime(), but might not be
+true in other cases, such as when using the PPS signal described later
+in this memorandum.
+
+2.4. External Time and Frequency Discipline
+
+The overall accuracy of a time synchronization subnet with respect to
+Coordinated Universal Time (UTC) depends on the accuracy and stability
+of the primary synchronization source, usually a radio or satellite
+receiver, and the CPU clock oscillator of the primary server. As
+discussed in [MIL93], the traditional interface using a ASCII serial
+timecode and RS232 port precludes the full accuracy of most radio
+clocks. In addition, the poor frequency stability of typical CPU clock
+oscillators limits the accuracy, whether or not precision time sources
+are available. There are, however, several ways in which the system
+clock accuracy and stability can be improved to the degree limited only
+by the accuracy and stability of the synchronization source and the
+jitter of the interface and operating system.
+
+Many radio clocks produce special signals that can be used by external
+equipment to precisely synchronize time and frequency. Most produce a
+pulse-per-second (PPS) signal that can be read via a modem-control lead
+of a serial port and some produce a special IRIG signal that can be read
+directly by a bus peripheral, such as the KSI/Odetics TPRO IRIG SBus
+interface, or indirectly via the audio codec of some workstations, as
+described in [MIL93]. In the NTP Version 3 daemon xntpd, the PPS signal
+can be used to augment the less precise ASCII serial timecode to improve
+accuracy to the order of a few tens of microseconds. Support is also
+included in the NTP distribution for the TPRO interface, as well as the
+audio codec; however, the latter requires a modified kernel audio driver
+contained in the compressed tar archive bsd_audio.tar.Z in the same host
+and directory as the NTP Version 3 distribution mentioned previously.
+2.4.1. PPS Signal
+
+The most convenient way to interface a PPS signal to a computer is
+usually with a serial port and RS232-compatible signal; however, the PPS
+signal produced by most radio clocks and laboratory instruments is
+usually a TTL pulse signal. Therefore, some kind of level
+converter/pulse generator is necessary to adapt the PPS signal to a
+serial port. An example design, including schematic and printed-circuit
+board artwork, is in the compressed tar archive gadget.tar.Z in the same
+host and directory as the NTP Version 3 distribution mentioned
+previously. There are several ways the PPS signal can be used in
+conjunction with the NTP Version 3 daemon xntpd, as described in [MIL93]
+and in the documentation included in the distribution.
+
+The NTP Version 3 distribution includes a special ppsclock module for
+the SunOS 4.1.x kernel that captures the PPS signal presented via a
+modem-control lead of a serial port. Normally, the ppsclock module
+produces a timestamp at each transition of the PPS signal and provides
+it to the synchronization daemon for integration with the serial ASCII
+timecode, also produced by the radio clock. With the conventional PLL
+implementation in either the daemon or the kernel as described in
+[MIL93], the accuracy of this scheme is limited by the intrinsic
+stability of the CPU clock oscillator to a millisecond or two, depending
+on environmental temperature variations.
+
+The ppsclock module has been modified to in addition call a new kernel
+routine hardpps() once each second. In addition, the Ultrix 4.3 kernel
+has been modified to provide a similar functionality. The hardpps()
+routine compares the timestamp with a sample of the CPU clock oscillator
+in order to discipline the oscillator to the time and frequency of the
+PPS signal. Using this method, the time accuracy is improved to
+typically 20 us or less and frequency stability a few parts in 10^8,
+which is about two orders of magnitude better than the undisciplined
+oscillator. The new feature is conditionally compiled in the code
+described below only if the PPS_SYNC option is used in the kernel
+configuration file.
+
+When using the PPS signal to adjust the time, there is a problem with
+some kernels which is very difficult to fix. The serial port interrupt
+routine often operates at an interrupt priority level above the timer
+interrupt routine. Thus, as explained below, it is possible that a tick
+increment can be missed and the time returned late by one tick. It may
+happen that, if the CPU clock oscillator frequency is close to the PPS
+oscillator frequency (less than a few ppm), this condition can persist
+for two or more successive PPS interrupts. A useful workaround in the
+code is to use a glitch detector and median filter to process the PPS
+sample offsets. The glitch detector suppresses offset bursts greater
+than half the tick interval and which last less than 30 successive PPS
+interrupts. The median filter ranks the offsets in a moving window of
+three samples and uses the median as the output and the difference
+between the other two as a dispersion measure.
+
+2.4.2. External Clocks
+
+It is possible to replace the system clock function with an external bus
+peripheral. The TPRO device mentioned previously can be used to provide
+IRIG-synchronized time with a precision of 1 us. A driver for this
+device tprotime.c and header file tpro.h are included in the
+kernel.tar.Z distribution mentioned previously. Using this device, the
+system clock is read directly from the interface; however, the device
+does not record the year, so special provisions have been made to obtain
+the year from the kernel time variable and initialize the driver
+accordingly. Support for this feature is conditionally compiled in the
+kernel only if the EXT_CLOCK and TPRO options are used in the kernel
+configuration file.
+
+While the system clock function is provided directly by the microtime()
+routine in the driver, the kernel time variable must be disciplined as
+well, since not all system timing functions use the microtime() routine.
+This is done by measuring the time difference between the microtime()
+clock and kernel time variable and using it to adjust the kernel PLL as
+if the adjustment were provided by an external peer and NTP.
+
+A good deal of error checking is done in the TPRO driver, since the
+system clock is vulnerable to a misbehaving radio clock, IRIG signal
+source, interface cables and TPRO device itself. Unfortunately, there is
+no practical way to utilize the extensive diversity and redundancy
+capabilities available in the NTP synchronization daemon. In order to
+avoid disruptions that might occur if the TPRO time is far different
+from the kernel time variable, the latter is used instead of the former
+if the difference between the two exceeds 1000 s; presumably in that
+case operator intervention is required.
+
+2.4.2. External Oscillators
+
+Even if a source of PPS or IRIG signals is not available, it is still
+possible to improve the stability of the system clock through the use of
+a specialized bus peripheral. In order to explore the benefits of such
+an approach, a special SBus peripheral called HIGHBALL has been
+constructed. The device includes a pair of 32-bit hardware counters in
+Unix timeval format, together with a precision, oven-controlled quartz
+oscillator with a stability of a few parts in 10^9. A driver for this
+device hightime.c and header file high.h are included in the
+kernel.tar.Z distribution mentioned previously. Support for this feature
+is conditionally compiled in the kernel only if the EXT_CLOCK and
+HIGHBALL options are used in the kernel configuration file.
+
+Unlike the external clock case, where the system clock function is
+provided directly by the microtime() routine in the driver, the HIGHBALL
+counter offsets with respect to UTC must be provided first. This is done
+using the ordinary kernel PLL, but controlling the counter offsets
+directly, rather than the kernel time variable. At first, this might
+seem to defeat the purpose of the design, since the jitter and wander of
+the synchronization source will affect the counter offsets and thus the
+accuracy of the time. However, the jitter is much reduced by the PLL and
+the wander is small, especially if using a radio clock or another
+primary server disciplined in the same way. In practice, the scheme
+works to reduce the incidental wander to a few parts in 10^8, or about
+the same as using the PPS signal.
+
+As in the previous case, the kernel time variable must be disciplined as
+well, since not all system timing functions use the microtime() routine.
+However, the kernel PLL cannot be used for this, since it is already in
+use providing offsets for the HIGHBALL counters. Therefore, a special
+correction is calculated from the difference between the microtime()
+clock and the kernel time variable and used to adjust the kernel time
+variable at the next timer interrupt. This somewhat roundabout approach
+is necessary in order that the adjustment does not cause the kernel time
+variable to jump backwards and possibly lose or duplicate a timer event.
+
+2.5 Other Features
+
+It is a design feature of the NTP architecture that the system clocks in
+a synchronization subnet are to read the same or nearly the same values
+before during and after a leap-second event, as declared by national
+standards bodies. The new model is designed to implement the leap event
+upon command by an ntp_adjtime() argument. The intricate and sometimes
+arcane details of the model and implementation are discussed in [MIL92b]
+and [MIL93]. Further details are given in the technical summary later in
+this memorandum.
+3. Technical Summary
+
+In order to more fully understand the workings of the model, a stand-
+alone simulator kern.c and header file timex.h are included in the
+kernel.tar.Z distribution mentioned previously. In addition, an example
+kernel module kern_ntptime.c which implements the ntp_gettime() and
+ntp_adjtime() system calls is included. Neither of these programs
+incorporate licensed code. Since the distribution is somewhat large, due
+to copious comments and ornamentation, it is impractical to include a
+listing of these programs in this memorandum. In any case, implementors
+may choose to snip portions of the simulator for use in new kernel
+designs; but, due to formatting conventions, this would be difficult if
+included in this memorandum.
+
+The kern.c program is an implementation of an adaptive-parameter, first-
+order, type-II phase-lock loop. The system clock is implemented using a
+set of variables and algorithms defined in the simulator and driven by
+explicit offsets generated by the main() routine in the program. The
+algorithms include code fragments almost identical to those in the
+machine-specific kernel implementations and operate in the same way, but
+the operations can be understood separately from any licensed source
+code into which these fragments may be integrated. The code fragments
+themselves are not derived from any licensed code. The following
+discussion assumes that the simulator code is available for inspection.
+
+3.1. PLL Simulation
+
+The simulator operates in conformance with the analytical model
+described in [MIL92b]. The main() program operates as a driver for the
+fragments hardupdate(), hardclock(), second_overflow(), hardpps() and
+microtime(), although not all functions implemented in these fragments
+are simulated. The program simulates the PLL at each timer interrupt and
+prints a summary of critical program variables at each time update.
+
+There are three defined options in the kernel configuration file
+specific to each implementation. The PPS_SYNC option provides support
+for a pulse-per-second (PPS) signal, which is used to discipline the
+frequency of the CPU clock oscillator. The EXT_CLOCK option provides
+support for an external kernel-readable clock, such as the KSI/Odetics
+TPRO IRIG interface or HIGHBALL precision oscillator, both for the SBus.
+The TPRO option provides support for the former, while the HIGHBALL
+option provides support for the latter. External clocks are implemented
+as the microtime() clock driver, with the specific source code selected
+by the kernel configuration file.
+
+The PPS signal is carefully monitored for error conditions which can
+affect accuracy, stability and reliability. The time_status kernel
+variable contains bits that both control the use of the PPS signal and
+reveal its operational status. The function of each bit is described in
+a later section of this memo.
+
+3.1.1. The hardupdate() Fragment
+
+The hardupdate() fragment is called by ntp_adjtime() as each update is
+computed to adjust the system clock phase and frequency. Note that the
+time constant is in units of powers of two, so that multiplies can be
+done by simple shifts. The phase variable is computed as the offset
+divided by the time constant, but clamped to a maximum (for robustness).
+Then, the time since the last update is computed and clamped to a
+maximum and to zero if initializing. The offset is multiplied (sorry
+about the ugly multiply) by the result and divided by the square of the
+time constant and then added to the frequency variable. Note that all
+shifts are assumed to be positive and that a shift of a signed quantity
+to the right requires a little dance.
+
+The STA_PLL and STA_PPSTIME status bits, which are set by the
+ntp_adjtime() system call, serve to enable or inhibit the kernel PLL and
+PPS time-discipline functions. The STA_PPSSIGNAL status bit is set by
+the hardpps() code fragment when the PPS signal is present and operating
+within nominal bounds. Time discipline from the PPS signal operates only
+if both the STA_PPSTIME and STA_PPSSIGNAL bits are set; otherwise, the
+discipline operates from the offset given in the ntp_adjtime() system
+call. In the intended mode of operation, the synchronization daemon sets
+STA_PLL to enable the PLL when first initialized, then sets STA_PPSTIME
+when reliable synchronization to within +-128 ms has been achieved with
+either a radio clock or external peer. The daemon can detect and
+indicate this condition for monitoring purposes by noting that both
+STA_PPSTIME and STA_PPSSIGNAL are set.
+
+With the defines given in the program and header files, the maximum time
+offset is determined by the size in bits of the long type (32 or 64)
+less the SHIFT_UPDATE scale factor (12) or at least 20 bits (signed).
+The scale factor is chosen so that there is no loss of significance in
+later steps, which may involve a right shift up to SHIFT_UPDATE bits.
+This results in a time adjustment range over +-512 ms. Since
time_constant must be greater than or equal to zero, the maximum
-frequency offset is determined by the SHIFT_KF (20) scale factor, or
-about +-130 ppm. In the addition step, the value of offset * mtemp is
-represented in 18 + 10 = 28 bits, which will not overflow a long add.
-There could be a loss of precision due to the right shift of up to eight
-bits, since time_constant is bounded at 6. This results in a net worst-
-case frequency error of about 2^-16 us or well down into the oscillator
-phase noise. While the time_offset value is assumed checked before
-entry, the time_phase variable is an accumulator, so is clamped to the
-tolerance on every call. This helps to damp transients before the
-oscillator frequency has been determined, as well as to satisfy the
-correctness assertions if the time-synchronization protocol comes
-unstuck.
+frequency offset is determined by the SHIFT_USEC scale factor (16) or at
+least 16 bits (signed). This results in a frequency adjustment range
+over +-31,500 ppm.
+
+In the addition step, the value of offset * mtemp is not greater than
+MAXPHASE * MAXSEC = 31 bits (signed), which will not overflow a long add
+on a 32-bit machine. There could be a loss of precision due to the right
+shift of up to 12 bits, since time_constant is bounded at 6. This
+results in a net worst-case frequency resolution of about .063 ppm,
+which is not significant for most quartz oscillators. The worst case
+could be realized only if the NTP peer misbehaves according to the
+protocol specification.
+
+The time_offset value is clamped upon entry. The time_phase variable is
+an accumulator, so is clamped to the tolerance on every call. This helps
+to damp transients before the oscillator frequency has been stabilized,
+as well as to satisfy the correctness assertions if the time
+synchronization protocol or implementation misbehaves.
+
+3.1.2. The hardclock() Fragment
The hardclock() fragment is inserted in the hardware timer interrupt
-routine at the point the system clock is to be incremented. Previous to
-this fragment the time_update variable has been initialized to the value
-computed by the adjtime() system call in the stock Unix kernel, normally
-the value of tick plus/minus the tickadj value, which is usually in the
-order of 5 microseconds. When the kernel PLL is in use, adjtime() is
-not, so the time_update value at this point is the value of tick. This
-value, the phase adjustment (time_adj) and the clock phase (time_phase)
-are summed and the total tested for overflow of the microsecond. If an
-overflow occurs, the microsecond (tick) is incremented or decremented,
-depending on the sign of the overflow.
+routine at the point the system clock is to be incremented by the value
+of tick. Previous to this fragment the time_update variable has been
+initialized to the tick increment plus the value computed by the
+adjtime() system call in the stock Unix kernel, normally plus/minus the
+tickadj value, which is usually in the order of 5 us. The time_phase
+variable, which represents the instantaneous phase of the system clock,
+is advanced by time_adj, which is calculated in the second_overflow()
+fragment described below. If the value of time_phase exceeds 1 us in
+scaled units, time_update is increased by the (signed) excess and
+time_phase retains the residue.
+
+In those cases where a PPS signal is connected by a serial port
+operating at an interrupt priority level greater than the timer
+interrupt, special consideration should be given the location of the
+hardclock() fragment in the timer interrupt routine. The system clock
+should be advanced as early in the routine as possible, preferably
+before the hardware timer interrupt flag is cleared. This reduces or
+eliminates the possibility that the microtime() routine may latch the
+time after the flag is cleared, but before the system clock is advanced,
+which results in a returned time late by one tick.
+
+Except in the case of an external oscillator such as the HIGHBALL
+interface, the hardclock() fragment advances the system clock by the
+value of tick plus time_update. However, in the case of an external
+oscillator, the system clock is obtained directly from the interface and
+time_update used to discipline that interface instead. However, the
+system clock must still be disciplined as explained previously, so the
+value of clock_cpu computed by the second_overflow() fragment is used
+instead.
+
+3.1.3. The second_overflow() Fragment
The second_overflow() fragment is inserted at the point where the
microseconds field of the system time variable is being checked for
-overflow. On rollover of the second the maximum error is increased by
-the tolerance and the time offset is divided by the phase weight
-(SHIFT_KG) and time constant. The time offset is then reduced by the
-result and the result is scaled and becomes the value of the phase
-adjustment. The phase adjustment is then corrected for the calculated
-frequency offset and a fixed offset determined from the fixtick variable
-in some kernel implementations. On rollover of the day, the leap-warning
-indicator is checked and the apparent time adjusted +-1 s accordingly.
-The microtime() routine insures that the reported time is always
-monotonically increasing.
+overflow. Upon overflow the maximum error time_maxerror is increased by
+time_tolerance to reflect the maximum time offset due to oscillator
+frequency error. Then, the increment time_adj to advance the kernel time
+variable is calculated from the (scaled) time_offset and time_freq
+variables updated at the last call to the hardclock() fragment.
+
+The phase adjustment is calculated as a (signed) fraction of the
+time_offset remaining, where the fraction is added to time_adj, then
+subtracted from time_offset. This technique provides a rapid convergence
+when offsets are high, together with good resolution when offsets are
+low. The frequency adjustment is the sum of the (scaled) time_freq
+variable, an adjustment necessary when the tick interval does not evenly
+divide one second fixtick and PPS frequency adjustment pps_freq (if
+configured).
+
+The scheme of approximating exact multiply/divide operations with shifts
+produces good results, except when an exact calculation is required,
+such as when the PPS signal is being used to discipline the CPU clock
+oscillator frequency as described below. As long as the actual
+oscillator frequency is a power of two in Hz, no correction is required.
+However, in the SunOS kernel the clock frequency is 100 Hz, which
+results in an error factor of 0.78. In this case the code increases
+time_adj by a factor of 1.25, which results in an overall error less
+than three percent.
+
+On rollover of the day, the leap-second state machine described below
+determines whether a second is to be inserted or deleted in the
+timescale. The microtime() routine insures that the reported time is
+always monotonically increasing.
+
+3.1.4. The hardpps() Fragment
+
+The hardpps() fragment is operative only if the PPS_SYNC option is
+specified in the kernel configuration file. It is called from the serial
+port driver or equivalent interface at the on-time transition of the PPS
+signal. The code operates as a first-order, type-I, frequency-lock loop
+(FLL) controlled by the difference between the frequency represented by
+the pps_freq variable and the frequency of the hardware clock
+oscillator. It also provides offsets to the hardupdate() fragment in
+order to discipline the system clock time.
+
+In order to avoid calling the microtime() routine more than once for
+each PPS transition, the interface requires the calling program to
+capture the system time and hardware counter contents at the on-time
+transition of the PPS signal and provide a pointer to the timestamp
+(Unix timeval) and counter contents as arguments to the hardpps() call.
+The hardware counter contents are determined by saving the microseconds
+field of the system time, calling the microtime() routine, and
+subtracting the saved value. If a microseconds overflow has occurred
+during the process, the resulting microseconds value will be negative,
+in which case the caller adds 1000000 to normalize the microseconds
+field.
+
+In order to avoid large jitter when the PPS interrupt occurs during the
+timer interrupt routine before the system clock is advanced, a glitch
+detector is used. The detector latches when an offset exceeds a
+threshold tick/2 and stays latched until either a subsequent offset is
+less than the threshold or a specified interval MAXGLITCH (30 s) has
+elapsed. As long as the detector remains latched, it outputs the offset
+immediately preceding the latch, rather than the one received.
+
+A three-stage median filter is used to suppress jitter less than the
+glitch threshold. The median sample drives the PLL, while the difference
+between the other two samples represents the time dispersion. Time
+dispersion samples are averaged and used as a jitter estimate. If this
+estimate exceeds a threshold MAXTIME/2 (100 us), an error bit
+STA_PPSJITTER is raised in the status word.
+
+The frequency of the hardware oscillator is determined from the
+difference in hardware counter readings at the beginning and end of the
+calibration interval divided by the duration of the interval. However,
+the oscillator frequency tolerance, as much as 100 ppm, may cause the
+difference to exceed the tick value, creating an ambiguity. In order to
+avoid this ambiguity, the hardware counter value at the beginning of the
+interval is increased by the current pps_freq value once each second,
+but computed modulo the tick value. At the end of the interval, the
+difference between this value and the value computed from the hardware
+counter is the control signal for the FLL.
+
+Control signal samples which exceed the frequency tolerance MAXFREQ (100
+ppm) are discarded, as well as samples resulting from excessive interval
+duration jitter. In these cases an error bit STA_PPSERROR is raised in
+the status word. Surviving samples are then processed by a three-stage
+median filter. The median sample drives the FLL, while the difference
+between the other two samples represents the frequency dispersion.
+Frequency dispersion samples are averaged and used as a stabiity
+estimate. If this estimate is below a threshold MAXFREQ/4 (25 ppm), the
+median sample is used to correct the oscillator frequency pps_freq with
+a weight expressed as a shift PPS_AVG (2).
+
+Initially, an approximate value for the oscillator frequency is not
+known, so the duration of the calibration interval must be kept small to
+avoid overflowing the tick. The time difference at the end of the
+calibration interval is measured. If greater than tick/4, the interval
+is reduced by half. If less than this fraction for four successive
+calibration intervals, the interval is doubled. This design
+automatically adapts to nominal jitter in the PPS signal, as well as the
+value of tick. The duration of the calibration interval is set by the
+pps_shift variable as a shift in powers of two. The minimum value
+PPS_SHIFT (2) is chosen so that with the highest CPU oscillator
+frequency 1024 Hz and frequency tolerance 100 ppm the tick will not
+overflow. The maximum value PPS_SHIFTMAX (8) is chosen such that the
+maximum averaging time is about 1000 s as determined by measurements of
+Allan variance [MIL93].
+
+Should the PPS signal fail, the current frequency estimate pps_freq
+continues to be used, so the nominal frequency remains correct subject
+only to the instability of the undisciplined oscillator. The procedure
+to save and restore the frequency estimate works as follows. When
+setting the frequency from a file, the time_freq value is set as the
+file value minus the pps_freq value; when retrieving the frequency, the
+two values are added before saving in the file. This scheme provides a
+seamless interface should the PPS signal fail or the kernel
+configuration change. Note that the frequency discipline is active
+whether or not the synchronization daemon is active. Since all Unix
+systems take some time after reboot to build a running system, usually
+by that time the discipline process has already settled down and the
+initial transients due to frequency discipline have damped out.
+3.1.4. External Clock Interface
+
+The external clock driver interface is implemented with two routines,
+microtime(), which returns the current clock time, and clock_set(),
+which furnishes the apparent system time derived from the kernel time
+variable. The latter routine is called only when the clock is set using
+the settimeofday() system call, but can be called from within the
+driver, such as when the year rolls over, for example.
+
+In the stock SunOS kernel and modified Ultrix and OSF/1 kernels, the
+microtime() routine returns the kernel time variable plus an
+interpolation between timer interrupts based on the contents of a
+hardware counter. In the case of an external clock, such as described
+above, the system clock is read directly from the hardware clock
+registers. Examples of external clock drivers are in the tprotime.c and
+hightime.c routines included in the kernel.tar.Z distribution.
+
+The external clock routines return a status code which indicates whether
+the clock is operating correctly and the nature of the problem, if not.
+The return code is interpreted by the ntp_gettime() system call, which
+transitions the status state machine to the TIME_ERR state if an error
+code is returned. This is the only error checking implemented for the
+external clock in the present version of the code.
The simulator has been used to check the PLL operation over the design
-envelope of +-128 ms in time error and +-100 ppm in frequency error.
+envelope of +-512 ms in time error and +-100 ppm in frequency error.
This confirms that no overflows occur and that the loop initially
converges in about 15 minutes for timer interrupt rates from 50 Hz to
-1024 Hz. The loop has a normal overshoot of about seven percent and a
-final convergence time of several hours, depending on the initial time
-and frequency error.
+1024 Hz. The loop has a normal overshoot of a few percent and a final
+convergence time of several hours, depending on the initial time and
+frequency error.
-4.2. Leap Seconds
+3.2. Leap Seconds
It does not seem generally useful in the user application interface to
provide additional details private to the kernel and synchronization
@@ -571,205 +760,615 @@ independently evaluate the quality of time and project into the future
how long this time might be "valid." However, to do that properly would
duplicate the functionality of the synchronization protocol and require
knowledge of many mundane details of the platform architecture, such as
-the subnet configuration, reachability status and related variables.
-However, for the curious, the ntp_adjtime() system call can be used to
-reveal some of these mysteries.
+the subnet configuration, reachability status and related variables. For
+the curious, the ntp_adjtime() system call can be used to reveal some of
+these mysteries.
However, the user application may need to know whether a leap second is
scheduled, since this might affect interval calculations spanning the
event. A leap-warning condition is determined by the synchronization
protocol (if remotely synchronized), by the timecode receiver (if
available), or by the operator (if awake). This condition is set by the
-protocol daemon on the day the leap second is to occur (30 June or 31
-December, as announced) by specifying in a ntp_adjtime() system call a
-clock status of either TIME_DEL, if a second is to be deleted, or
-TIME_INS, if a second is to be inserted. Note that, on all occasions
+synchronization daemon on the day the leap second is to occur (30 June
+or 31 December, as announced) by specifying in a ntp_adjtime() system
+call a status bit of either STA_DEL, if a second is to be deleted, or
+STA_INS, if a second is to be inserted. Note that, on all occasions
since the inception of the leap-second scheme, there has never been a
-deletion occasion. If the value is TIME_DEL, the kernel adds one second
-to the system time immediately following second 23:59:58 and resets the
-clock status to TIME_OK. If the value is TIME_INS, the kernel subtracts
-one second from the system time immediately following second 23:59:59
-and resets the clock status to TIME_OOP, in effect causing system time
-to repeat second 59. Immediately following the repeated second, the
-kernel resets the clock status to TIME_OK.
+deletion, nor is there likely to be one in future. If the bit is
+STA_DEL, the kernel adds one second to the system time immediately
+following second 23:59:58 and resets the clock state to TIME_WAIT. If
+the bit is STA_INS, the kernel subtracts one second from the system time
+immediately following second 23:59:59 and resets the clock stateto
+TIME_OOP, in effect causing system time to repeat second 59. Immediately
+following the repeated second, the kernel resets the clock status to
+TIME_WAIT.
+
+Following the leap operations, the clock remains in the TIME_WAIT state
+until both the STA_DEL and STA_INS status bits are reset. This provides
+both an unambiguous indication that a leap recently occured, as well as
+time for the daemon or operator to clear the warning condition.
Depending upon the system call implementation, the reported time during
a leap second may repeat (with the TIME_OOP return code set to advertise
that fact) or be monotonically adjusted until system time "catches up"
to reported time. With the latter scheme the reported time will be
correct before and shortly after the leap second (depending on the
-number of microtime() calls during the leap second itself), but freeze
-or slowly advance during the leap second itself. However, Most programs
+number of microtime() calls during the leap second), but freeze or
+slowly advance during the leap second itself. However, Most programs
will probably use the ctime() library routine to convert from timeval
(seconds, microseconds) format to tm format (seconds, minutes,...). If
this routine is modified to use the ntp_gettime() system call and
inspect the return code, it could simply report the leap second as
second 60.
-To determine local midnight without fuss, the kernel simply finds the
-residue of the time.tv_sec value mod 86,400, but this requires a messy
-divide. Probably a better way to do this is to initialize an auxiliary
-counter in the settimeofday() routine using an ugly divide and increment
-the counter at the same time the time.tv_sec is incremented in the timer
-interrupt routine. For future embellishment.
+3.3. Clock Status State Machine
+
+The various options possible with the system clock model described in
+this memorandum require a careful examination of the state transitions,
+status indications and recovery procedures should a crucial signal or
+interface fail. In this section is presented a prototype state machine
+designed to support leap second insertion and deletion, as well as
+reveal various kinds of errors in the synchronization process. The
+states of this machine are decoded as follows:
+
+ TIME_OK If a PPS signal or external clock is present, it is
+ working properly and the system clock is derived
+ from it. If not, the synchronization daemon is
+ working properly and the system clock is
+ synchronized to a radio clock or one or more peers.
+
+ TIME_INS An insertion of one second in the system clock has
+ been declared following the last second of the
+ current day, but has not yet been executed.
+
+ TIME_DEL A deletion of the last second of the current day has
+ been declared, but not yet executed.
+
+ TIME_OOP An insertion of one second in the system clock has
+ been declared following the last second of the
+ current day. The second is in progress, but not yet
+ completed. Library conversion routines should
+ interpret this second as 23:59:60.
+
+ TIME_WAIT The scheduled leap event has occurred, but the
+ STA_DEL and STA_INS status bits have not yet been
+ cleared.
+
+ TIME_ERROR Either (a) the synchronization daemon has declared
+ the protocol is not working properly, (b) all
+ sources of outside synchronization have been lost or
+ (c) a PPS signal or external clock is present, but
+ not working properly.
+
+In all states the system clock is derived from either a PPS signal or
+external clock, if present, or the kernel time variable, if not. If a
+PPS error condition is recognized, the PPS signal is disabled and
+ntp_adjtime() updates are used instead. If an external clock error
+condition is recognized, the external clock is disabled and the kernel
+time variable is used instead.
+
+The state machine makes a transition once each second at an instant
+where the microseconds field of the kernel time variable overflows and
+one second is added to the seconds field. However, this condition is
+checked when the timer overflows, which may not coincide with the actual
+seconds increment. This may lead to some interesting anomalies, such as
+a status indication of a leap second in progress (TIME_OOP) when the
+leap second has already expired. This ambiguity is unavoidable, unless
+the timer interrupt is made synchronous with the system clock.
+
+The following state transitions are executed automatically by the kernel
+at rollover of the microseconds field:
+
+ any state -> TIME_ERROR This transition occurs when an error
+ condition is recognized and continues as long
+ as the condition persists. The error indication
+ overrides the normal state indication, but does
+ not affect the actual clock state. Therefore,
+ when the condition is cleared, the normal state
+ indication resumes.
+
+ TIME_OK->TIME_DEL This transition occurs if the STA_DEL bit is
+ set in the status word.
+
+ TIME_OK->TIME_INS This transition occurs if the STA_INS bit is
+ set in the status word.
+
+ TIME_INS->TIME_OOP This transition occurs immediately following
+ second 86,400 of the current day when an
+ insert-second event has been declared.
+
+ TIME_OOP->TIME_WAIT This transition occurs immediately following
+ second 86,401 of the current day; that is, one
+ second after entry to the TIME_OOP state.
+
+ TIME_DEL->TIME_WAIT This transition occurs immediately following
+ second 86,399 of the current day when a delete-
+ second event has been declared.
+
+ TIME_WAIT->TIME_OK This transition occurs when the STA_DEL and
+ STA_INS bits are cleared by an ntp_adjtime()
+ call.
+
+The following table summarizes the actions just before, during and just
+after a leap-second event. Each line in the table shows the UTC and NTP
+times at the beginning of the second. The left column shows the behavior
+when no leap event is to occur. In the middle column the state machine
+is in TIME_INS at the end of UTC second 23:59:59 and the NTP time has
+just reached 400. The NTP time is set back one second to 399 and the
+machine enters TIME_OOP. At the end of the repeated second the machine
+enters TIME_OK and the UTC and NTP times are again in correspondence. In
+the right column the state machine is in TIME_DEL at the end of UTC
+second 23:59:58 and the NTP time has just reached 399. The NTP time is
+incremented, the machine enters TIME_OK and both UTC and NTP times are
+again in correspondence.
+
+ No Leap Leap Insert Leap Delete
+ UTC NTP UTC NTP UTC NTP
+ ---------------------------------------------
+ 23:59:58|398 23:59:58|398 23:59:58|398
+ | | |
+ 23:59:59|399 23:59:59|399 00:00:00|400
+ | | |
+ 00:00:00|400 23:59:60|399 00:00:01|401
+ | | |
+ 00:00:01|401 00:00:00|400 00:00:02|402
+ | | |
+ 00:00:02|402 00:00:01|401 00:00:03|403
+ | | |
+To determine local midnight without fuss, the kernel code simply finds
+the residue of the time.tv_sec (or time.tv_sec + 1) value mod 86,400,
+but this requires a messy divide. Probably a better way to do this is to
+initialize an auxiliary counter in the settimeofday() routine using an
+ugly divide and increment the counter at the same time the time.tv_sec
+is incremented in the timer interrupt routine. For future embellishment.
+
+4. Programming Model and Interfaces
+
+This section describes the programming model for the synchronization
+daemon and user application programs. The ideas are based on suggestions
+from Jeff Mogul and Philip Gladstone and a similar interface designed by
+the latter. It is important to point out that the functionality of the
+original Unix adjtime() system call is preserved, so that the modified
+kernel will work as the unmodified one, should the new features not be
+in use. In this case the ntp_adjtime() system call can still be used to
+read and write kernel variables that might be used by a synchronization
+daemon other than NTP, for example.
+
+The kernel routines use the clock state variable time_state, which
+records whether the clock is synchronized, waiting for a leap second,
+etc. The value of this variable is returned as the result code by both
+the ntp_gettime() and ntp_adjtime() system calls. It is set implicitly
+by the STA_DEL and STA_INS status bits, as described previously. Values
+presently defined in the timex.h header file are as follows:
+
+ TIME_OK 0 no leap second warning
+ TIME_INS 1 insert leap second warning
+ TIME_DEL 2 delete leap second warning
+ TIME_OOP 3 leap second in progress
+ TIME_WAIT 4 leap second has occured
+ TIME_ERROR 5 clock not synchronized
+
+In case of a negative result code, the kernel has intercepted an invalid
+address or (in case of the ntp_adjtime() system call), a superuser
+violation.
+
+4.1. The ntp_gettime() System Call
+
+The syntax and semantics of the ntp_gettime() call are given in the
+following fragment of the timex.h header file. This file is identical,
+except for the SHIFT_HZ define, in the SunOS, Ultrix and OSF/1 kernel
+distributions. (The SHIFT_HZ define represents the logarithm to the base
+2 of the clock oscillator frequency specific to each system type.) Note
+that the timex.h file calls the syscall.h system header file, which must
+be modified to define the SYS_ntp_gettime system call specific to each
+system type. The kernel distributions include directions on how to do
+this.
+
+ /*
+ * This header file defines the Network Time Protocol (NTP)
+ * interfaces for user and daemon application programs. These are
+ * implemented using private system calls and data structures and
+ * require specific kernel support.
+ *
+ * NAME
+ * ntp_gettime - NTP user application interface
+ *
+ * SYNOPSIS
+ * #include <sys/timex.h>
+ *
+ * int system call(SYS_ntp_gettime, tptr)
+ *
+ * int SYS_ntp_gettime defined in syscall.h header file
+ * struct ntptimeval *tptr pointer to ntptimeval structure
+ *
+ * NTP user interface - used to read kernel clock values
+ * Note: maximum error = NTP synch distance = dispersion + delay /
+ * 2
+ * estimated error = NTP dispersion.
+ */
+ struct ntptimeval {
+ struct timeval time; /* current time (ro) */
+ long maxerror; /* maximum error (us) (ro) */
+ long esterror; /* estimated error (us) (ro) */
+ };
+
+The ntp_gettime() system call returns three read-only (ro) values in the
+ntptimeval structure: the current time in unix timeval format plus the
+maximum and estimated errors in microseconds. While the 32-bit long data
+type limits the error quantities to something more than an hour, in
+practice this is not significant, since the protocol itself will declare
+an unsynchronized condition well below that limit. In the NTP Version 3
+specification, if the protocol computes either of these values in excess
+of 16 seconds, they are clamped to that value and the system clock
+declared unsynchronized.
+
+Following is a detailed description of the ntptimeval structure members.
+
+struct timeval time (ro)
-4.2. Kernel Variables
+ This member is the current system time expressed as a Unix timeval
+ structure. The timeval structure consists of two 32-bit words; the
+ first is the number of seconds past 1 January 1970 assuming no
+ intervening leap-second insertions or deletions, while the second
+ is the number of microseconds within the second.
-The following kernel variables are defined by the new code:
+long maxerror (ro)
-long time_offset = 0; /* time adjustment (us) */
+ This member is the value of the time_maxerror kernel variable,
+ which represents the maximum error of the indicated time relative
+ to the primary synchronization source, in microseconds. For NTP,
+ the value is initialized by a ntp_adjtime() call to the
+ synchronization distance, which is equal to the root dispersion
+ plus one-half the root delay. It is increased by a small amount
+ (time_tolerance) each second to reflect the maximum clock frequency
+ error. This variable is provided bu a ntp-adjtime() system call and
+ modified by the kernel, but is otherwise not used by the kernel.
- This variable is used by the PLL to adjust the system time in small
- increments. It is scaled by (1 << SHIFT_UPDATE) in binary
- microseconds. The maximum value that can be represented is about +-
- 512 ms and the minimum value or precision is one microsecond.
+long esterror (ro)
-long time_constant = 0; /* pll time constant */
+ This member is the value of the time_esterror kernel variable,
+ which represents the expected error of the indicated time relative
+ to the primary synchronization source, in microseconds. For NTP,
+ the value is determined as the root dispersion, which represents
+ the best estimate of the actual error of the system clock based on
+ its past behavior, together with observations of multiple clocks
+ within the peer group. This variable is provided bu a ntp-adjtime()
+ system call, but is otherwise not used by the kernel.
+
+4.2. The ntp_adjtime() System Call
+
+The syntax and semantics of the ntp_adjtime() call are given in the
+following fragment of the timex.h header file. Note that, as in the
+ntp_gettime() system call, the syscall.h system header file must be
+modified to define the SYS_ntp_adjtime system call specific to each
+system type. In the fragment, rw = read/write, ro = read-only, wo =
+write-only.
+
+ /*
+ * NAME
+ * ntp_adjtime - NTP daemon application interface
+ *
+ * SYNOPSIS
+ * #include <sys/timex.h>
+ *
+ * int system call(SYS_ntp_adjtime, mode, tptr)
+ *
+ * int SYS_ntp_adjtime defined in syscall.h header file
+ * struct timex *tptr pointer to timex structure
+ *
+ * NTP daemon interface - used to discipline kernel clock
+ * oscillator
+ */
+ struct timex {
+ unsigned int mode; /* mode selector (wo) */
+ long offset; /* time offset (us) (rw) */
+ long frequency; /* frequency offset (scaled ppm) (rw)
+ */
+ long maxerror; /* maximum error (us) (rw) */
+ long esterror; /* estimated error (us) (rw) */
+ int status; /* clock status bits (rw) */
+ long constant; /* pll time constant (rw) */
+ long precision; /* clock precision (us) (ro) */
+ long tolerance; /* clock frequency tolerance (scaled
+ * ppm) (ro) */
+ /*
+ * The following read-only structure members are implemented
+ * only if the PPS signal discipline is configured in the
+ * kernel.
+ */
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro)
+ */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+ };
- This variable determines the bandwidth or "stiffness" of the PLL.
- It is used as a shift, with the effective value in positive powers
- of two. The default value (0) corresponds to a PLL time constant of
- about 4 minutes.
+The ntp_adjtime() system call is used to read and write certain time-
+related kernel variables summarized below. Writing these variables can
+only be done in superuser mode. To write a variable, the mode structure
+member is set with one or more bits, one of which is assigned each of
+the following variables in turn. The current values for all variables
+are returned in any case; therefore, a mode argument of zero means to
+return these values without changing anything.
-long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
+Following is a description of the timex structure members.
- This variable represents the maximum frequency error or tolerance
- of the particular platform and is a property of the architecture.
- It is expressed as a positive number greater than zero in parts-
- per-million (ppm). The default MAXFREQ (100) is appropriate for
- conventional workstations.
+mode (wo)
-long time_precision = 1000000 / HZ; /* clock precision (us) */
+ This is a bit-coded variable selecting one or more structure
+ members, with one bit assigned each member. If a bit is set, the
+ value of the associated member variable is copied to the
+ corresponding kernel variable; if not, the member is ignored. The
+ bits are assigned as given in the following, with the variable name
+ indicated in parens. Note that the precision, tolerance and PPS
+ variables are determined by the kernel and cannot be changed by
+ ntp_adjtime().
+
+ MOD_OFFSET 0x0001 time offset (offset)
+ MOD_FREQUENCY 0x0002 frequency offset (frequency)
+ MOD_MAXERROR 0x0004 maximum time error (maxerror)
+ MOD_ESTERROR 0x0008 estimated time error (esterror)
+ MOD_STATUS 0x0010 clock status (status)
+ MOD_TIMECONST 0x0020 pll time constant (constant)
+ MOD_CLKB 0x4000 set clock B
+ MOD_CLKA 0x8000 set clock A
+
+ Note that the MOD_CLK0 and MOD_CLK1 bits are intended for those
+ systems where more than one hardware clock is available for backup,
+ such as in Tandem Non-Stop computers. Presumably, in such cases
+ each clock would have its own oscillator and require a separate PLL
+ for each. Refinements to this model are for further study. The
+ interpretation of these bits is as follows:
+
+offset (rw)
+
+ If selected, this member specifies the time adjustment, in
+ microseconds. The absolute value must be less than MAXPHASE
+ (128000) microseconds defined in the timex.h header file. On
+ return, this member contains the residual offset remaining between
+ a previously specified offset and the current system time, in
+ microseconds.
+
+frequency (rw)
+
+ If selected, this member replaces the value of the time_frequency
+ kernel variable. The value is in ppm, with the integer part in the
+ high order 16 bits and fraction in the low order 16 bits. The
+ absolute value must be in the range less than MAXFREQ (100) ppm
+ defined in the timex.h header file.
+
+ The time_freq variable represents the frequency offset of the CPU
+ clock oscillator. It is recalculated as each update to the system
+ clock is determined by the offset member of the timex structure. It
+ is usually set from a value stored in a file when the
+ synchronization daemon is first started. The current value is
+ usually retrieved via this member and written to the file about
+ once per hour.
+
+maxerror (rw)
- This variable represents the maximum error in reading the system
- clock. It is expressed as a positive number greater than zero in
- microseconds and is usually based on the number of microseconds
- between timer interrupts, 3906 usec for the Ultrix kernel, 976 usec
- for the OSF/1 kernel. However, in cases where the time can be
- interpolated between timer interrupts with microsecond resolution,
- such as in the unmodified SunOS kernel and modified Ultrix and
- OSF/1 kernels, the precision is specified as 1 usec. This variable
- is computed by the kernel for use by the time-synchronization
- daemon, but is otherwise not used by the kernel.
+ If selected, this member replaces the value of the time_maxerror
+ kernel variable, in microseconds. This is the same variable as in
+ the ntp_getime() system call.
-long time_maxerror; /* maximum error */
+esterror (rw)
- This variable establishes the maximum error of the indicated time
- relative to the primary reference source, in microseconds. For NTP,
- the value is determined as the synchronization distance, which is
- equal to the root dispersion plus one-half the root delay. It is
- increased by a small amount (time_tolerance) each second to reflect
- the clock frequency tolerance. This variable is computed by the
- time-synchronization daemon and the kernel, but is otherwise not
- used by the kernel.
+ If selected, this member replaces the value of the time_esterror
+ kernel variable, in microseconds. This is the same variable as in
+ the ntp_getime() system call.
-long time_esterror; /* estimated error */
+int status (rw)
- This variable establishes the expected error of the indicated time
- relative to the primary reference source, in microseconds. For NTP,
- the value is determined as the root dispersion, which represents
- the best estimate of the actual error of the system clock based on
- its past behavior, together with observations of multiple clocks
- within the peer group. This variable is computed by the time-
- synchronization daemon and returned in system calls, but is
- otherwise not used by the kernel.
-
-long time_phase = 0; /* phase offset (scaled us) */
-long time_freq = 0; /* frequency offset (scaled ppm) */
-time_adj = 0; /* tick adjust (scaled 1 / HZ) */
-
- These variables control the phase increment and the frequency
- increment of the system clock at each tick. The time_phase variable
- is scaled by (1 << SHIFT_SCALE) (24) in microseconds, giving a
- maximum adjustment of about +-128 us/tick and a resolution of about
- 60 femtoseconds/tick. The time_freq variable is scaled by (1 <<
- SHIFT_KF) in parts-per-million (ppm), giving it a maximum value of
- over +-2000 ppm and a minimum value (frequency resolution) of about
- 1e-5 ppm. The time_adj variable is the actual phase increment in
- scaled microseconds to add to time_phase once each tick. It is
- computed from time_phase and time_freq once per second.
-
-long time_reftime = 0; /* time at last adjustment (s) */
-
- This variable is the second's portion of the system time on the
- last call to adjtime(). It is used to adjust the time_freq variable
- as the time since the last update increases.
-
-int fixtick = 1000000 % HZ; /* amortization factor */
-
- In some systems such as the Ultrix and OSF/1 kernels, the local
- clock runs at some frequency that does not divide the number of
- microseconds in the second. In order that the clock runs at a
- precise rate, it is necessary to introduce an amortization factor
- into the local timescale, in effect a leap-multimicrosecond. This
- is not a new kernel variable, but a new use of an existing kernel
- variable.
-
-4.3. Architecture Constants
-
-Following is a list of the important architecture constants that
-establish the response and stability of the PLL and provide maximum
-bounds on behavior in order to satisfy correctness assertions made in
-the protocol specification.
-
-#define HZ 256 /* timer interrupt frequency (Hz) */
-#define SHIFT_HZ 8 /* log2(HZ) */
-
- The HZ define (a variable in some kernels) establishes the timer
- interrupt frequency, 100 Hz for the SunOS kernel, 256 Hz for the
- Ultrix kernel and 1024 Hz for the OSF/1 kernel. The SHIFT_HZ define
- expresses the same value as the nearest power of two in order to
- avoid hardware multiply operations. These are the only parameters
- that need to be changed for different kernel timer interrupt
- frequencies.
-
-#define SHIFT_KG 6 /* shift for phase increment */
-#define SHIFT_KF 16 /* shift for frequency increment */
-#define MAXTC 6 /* maximum time constant (shift) */
-
- These defines establish the response and stability characteristics
- of the PLL model. The SHIFT_KG and SHIFT_KF defines establish the
- damping of the PLL and are chosen by analysis for a slightly
- underdamped convergence characteristic. The MAXTC define
- establishes the maximum time constant of the PLL.
-
-#define SHIFT_SCALE (SHIFT_KF + SHIFT_HZ) /* shift for scale factor */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale
- * factor */
-#define SHIFT_USEC 16 /* shift for 1 us in external units */
-#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in scaled units */
-
- The SHIFT_SCALE define establishes the decimal point on the
- time_phase variable which serves as a an extension to the low-order
- bits of the system clock variable. The SHIFT_UPDATE define
- establishes the decimal point of the phase portion of the
- ntp_adjtime() update. The SHIFT_USEC define represents 1 us in
- external units (shift), while the FINEUSEC define represents 1 us
- in internal units.
-
-#define MAXPHASE 128000 /* max phase error (usec) */
-#define MAXFREQ 100 /* max frequency error (ppm) */
-#define MINSEC 16 /* min interval between updates (s) */
-#define MAXSEC 1200 /* max interval between updates (s) */
-
- These defines establish the performance envelope of the PLL, one to
- bound the maximum phase error, another to bound the maximum
- frequency error and two others to bound the minimum and maximum
- time between updates. The intent of these bounds is to force the
- PLL to operate within predefined limits in order to conform to the
- correctness models assumed by time-synchronization protocols like
- NTP and DTSS. An excursion which exceeds these bounds is clamped to
- the bound and operation proceeds accordingly. In practice, this can
- occur only if something has failed or is operating out of
- tolerance, but otherwise the PLL continues to operate in a stable
- mode. Note that the MAXPHASE define conforms to the maximum offset
- allowed in NTP before the system time is reset (by settimeofday(),
- rather than incrementally adjusted (by ntp_adjtime().
+ If selected, this member replaces the value of the time_status
+ kernel variable. This variable controls the state machine used to
+ insert or delete leap seconds and shows the status of the
+ timekeeping system, PPS signal and external oscillator, if
+ configured.
+
+ STA_PLL 0x0001 enable PLL updates (r/w)
+ STA_PPSFREQ 0x0002 enable PPS freq discipline (r/w)
+ STA_PPSTIME 0x0004 enable PPS time discipline (r/w)
+ STA_INS 0x0010 insert leap (r/w)
+ STA_DEL 0x0020 delete leap (r/w)
+ STA_UNSYNC 0x0040 clock unsynchronized (r/w)
+ STA_PPSSIGNAL 0x0100 PPS signal present (r)
+ STA_PPSJITTER 0x0200 PPS signal jitter exceeded (r)
+ STA_PPSWANDER 0x0400 PPS signal wander exceeded (r)
+ STA_PPSERROR 0x0800 PPS signal calibration error (r)
+ STA_CLOCKERR 0x1000 clock hardware fault (r)
+
+ The interpretation of these bits is as follows:
+
+ STA_PLL set/cleared by the caller to enable PLL updates
+
+ STA_PPSFREQ set/cleared by the caller to enable PPS frequency
+ discipline
+
+ STA_PPSTIME set/cleared by the caller to enable PPS time
+ discipline
+
+ STA_INS set by the caller to insert a leap second at the end
+ of the current day; cleared by the caller after the
+ event
+
+ STA_DEL set by the caller to delete a leap second at the end
+ of the current day; cleared by the caller after the
+ event
+
+ STA_UNSYNC set/cleared by the caller to indicate clock
+ unsynchronized (e.g., when no peers are reachable)
+
+ STA_PPSSIGNAL set/cleared by the hardpps() fragment to indicate
+ PPS signal present
+
+ STA_PPSJITTER set/cleared by the hardpps() fragment to indicates
+ PPS signal jitter exceeded
+
+ STA_PPSWANDER set/cleared by the hardpps() fragment to indicates
+ PPS signal wander exceeded
+
+ STA_PPSERROR set/cleared by the hardpps() fragment to indicates
+ PPS signal calibration error
+
+ STA_CLOCKERR set/cleared by the external hardware clock driver to
+ indicate hardware fault
+
+ An error condition is raised when (a) either STA_UNSYNC or
+ STA_CLOCKERR is set (loss of synchronization), (b) STA_PPSFREQ or
+ STA_PPSTIME is set and STA_PPSSIGNAL is clear (loss of PPS signal),
+ (c) STA_PPSTIME and STA_PPSJITTER are both set (jitter exceeded),
+ (d) STA_PPSFREQ is set and either STA_PPSWANDER or STA_PPSERROR is
+ set (wander exceeded). An error condition results in a system call
+ return code of TIME_ERROR.
+
+constant (rw)
+
+ If selected, this member replaces the value of the time_constant
+ kernel variable. The value must be between zero and MAXTC (6)
+ defined in the timex.h header file.
+
+ The time_constant variable determines the bandwidth or "stiffness"
+ of the PLL. The value is used as a shift between zero and MAXTC
+ (6), with the effective PLL time constant equal to a multiple of (1
+ << time_constant), in seconds. For room-temperature quartz
+ oscillators, the recommended default value is 2, which corresponds
+ to a PLL time constant of about 900 s and a maximum update interval
+ of about 64 s. The maximum update interval scales directly with the
+ time constant, so that at the maximum time constant of 6, the
+ update interval can be as large as 1024 s.
+
+ Values of time_constant between zero and 2 can be used if quick
+ convergence is necessary; values between 2 and 6 can be used to
+ reduce network load, but at a modest cost in accuracy. Values above
+ 6 are appropriate only if an precision external oscillator is
+ present.
+
+precision (ro)
+
+ This is the current value of the time_precision kernel variable in
+ microseconds.
+
+ The time_precision variable represents the maximum error in reading
+ the system clock, in microseconds. It is usually based on the
+ number of microseconds between timer interrupts (tick), 10000 us
+ for the SunOS kernel, 3906 us for the Ultrix kernel, 976 us for the
+ OSF/1 kernel. However, in cases where the time can be interpolated
+ between timer interrupts with microsecond resolution, such as in
+ the stock SunOS kernel and modified Ultrix and OSF/1 kernels, the
+ precision is specified as 1 us. In cases where a PPS signal or
+ external oscillator is available, the precision can depend on the
+ operating condition of the signal or oscillator. This variable is
+ determined by the kernel for use by the synchronization daemon, but
+ is otherwise not used by the kernel.
+
+tolerance (ro)
+
+ This is the current value of the time_tolerance kernel variable.
+ The value is in ppm, with the integer part in the high order 16
+ bits and fraction in the low order 16 bits.
+
+ The time_tolerance variable represents the maximum frequency error
+ in ppm of the particular CPU clock oscillator and is a property of
+ the hardware; however, in principle it could change as result of
+ the presence of external discipline signals, for instance.
+
+ The recommended value for time_tolerance MAXFREQ (200) ppm is
+ appropriate for room-temperature quartz oscillators used in typical
+ workstations. However, it can change due to the operating condition
+ of the PPS signal and/or external oscillator. With either the PPS
+ signal or external oscillator, the recommended value for MAXFREQ is
+ 100 ppm.
+
+The following members are defined only if the PPS_SYNC option is
+specified in the kernel configuration file. These members are useful
+primarily as a monitoring and evalutation tool. These variables can be
+written only by the kernel.
+
+ppsfreq (ro)
+
+ This is the current value of the pps_freq kernel variable, which is
+ the CPU clock oscillator frequency offset relative to the PPS
+ discipline signal. The value is in ppm, with the integer part in
+ the high order 16 bits and fraction in the low order 16 bits.
+
+jitter (ro)
+
+ This is the current value of the pps_jitter kernel variable, which
+ is the average PPS time dispersion measured by the time-offset
+ median filter, in microseconds.
+
+shift (ro)
+
+ This is the current value of the pps_shift kernel variable, which
+ determines the duration of the calibration interval as the value of
+ 1 << pps_shift, in seconds.
+stabil (ro)
+
+ This is the current value of the pps_stabil kernel variable, which
+ is the average PPS frequency dispersion measured by the frequency-
+ offset median filter. The value is in ppm, with the integer part in
+ the high order 16 bits and fraction in the low order 16 bits.
+
+jitcnt (ro)
+
+ This is the current value of the pps_jitcnt kernel variable, counts
+ the number of PPS signals where the average jitter exceeds the
+ threshold MAXTIME (200 us).
+
+calcnt (ro)
+
+ This is the current value of the pps_calcnt kernel variable, which
+ counts the number of frequency calibration intervals. The duration
+ of these intervals can range from 4 to 256 seconds, as determined
+ by the pps_shift kernel variable.
+
+errcnt (ro)
+
+ This is the current value of the pps_errcnt kernel variable, which
+ counts the number of frequency calibration cycles where (a) the
+ apparent frequency offset is greater than MAXFREQ (100 ppm) or (b)
+ the interval jitter exceeds tick * 2.
+
+stbcnt (ro)
+
+ This is the current value of the pps_discnt kernel variable, which
+ counts the number of calibration intervals where the average
+ stability exceeds the threshold MAXFREQ / 4 (25 ppm).
+
+7. References
+
+[MIL91] Mills, D.L. Internet time synchronization: the Network Time
+Protocol, IEEE Trans. Communications COM-39, 10 (October 1991),
+1482-1493. Also in: Yang, Z., and T.A. Marsland (Eds.). Global
+States and Time in Distributed Systems, IEEE Press, Los Alamitos,
+CA, 91-102.
+
+[MIL92a] Mills, D.L. Network Time Protocol (Version 3) specification,
+implementation and analysis, RFC 1305, University of Delaware, March
+1992, 113 pp.
+
+[MIL92b] Mills, D.L. Modelling and analysis of computer network clocks,
+Electrical Engineering Department Report 92-5-2, University of Delaware,
+May 1992, 29 pp.
+
+[MIL92c] Mills, D.L. Simple Network Time Protocol (SNTP), RFC 1361,
+University of Delaware, August 1992, 10 pp.
+
+[MIL93] Mills, D.L. Precision synchronizatin of computer network clocks,
+Electrical Engineering Department Report 93-11-1, University of
+Delaware, November 1993, 66 pp.
+
+[LEV89] Levine, J., M. Weiss, D. Davis, D. Allan, and D. Sullivan. The
+NIST automated computer time service. J. Research National Institute of
+Standards and Technology 94, 5 (September-October 1989), 311-321.
David L. Mills <mills@udel.edu>
Electrical Engineering Department
University of Delaware
Newark, DE 19716
302 831 8247 fax 302 831 4316
-
-1 April 1992
+3 April 1994
diff --git a/contrib/xntpd/doc/notes.txt b/contrib/xntpd/doc/notes.txt
index 5ea2b3318bb3..1dd59f25b3ac 100644
--- a/contrib/xntpd/doc/notes.txt
+++ b/contrib/xntpd/doc/notes.txt
@@ -785,7 +785,7 @@ configuration functionality (though the only thing you can currently do
with mode-6 messages is set the leap-second warning bits) and the ntpq
program provides generic support for the latter. The leap bits that can be
set in the leap_warning variable (up to one month ahead) and in the
-leap_indication variable have a slighly different encoding than the
+leap_indication variable have a slightly different encoding than the
usual interpretation:
Value Action
diff --git a/contrib/xntpd/gadget/.keep_me b/contrib/xntpd/gadget/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/gadget/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/hints/.keep_me b/contrib/xntpd/hints/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/hints/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/include/l_stdlib.h b/contrib/xntpd/include/l_stdlib.h
index 89a8092853b5..e0b7c474095c 100644
--- a/contrib/xntpd/include/l_stdlib.h
+++ b/contrib/xntpd/include/l_stdlib.h
@@ -70,11 +70,11 @@ extern int getppid P((void));
extern int close P((int));
extern int ioctl P((int, int, char *));
-extern int read P((int, char *, unsigned));
+extern int read P((int, void *, unsigned));
extern int rename P((char *, char *));
-extern int write P((int, char *, int));
-extern int unlink P((char *));
-extern int link P((char *, char *));
+extern int write P((int, const void *, unsigned));
+extern int unlink P((const char *));
+extern int link P((const char *, const char *));
#ifdef FILE
extern int fclose P((FILE *));
diff --git a/contrib/xntpd/include/ntp.h b/contrib/xntpd/include/ntp.h
index 310353f1cda2..01bfa16a7ad8 100644
--- a/contrib/xntpd/include/ntp.h
+++ b/contrib/xntpd/include/ntp.h
@@ -173,6 +173,7 @@ struct interface {
#define INT_BROADCAST 1 /* can broadcast out this interface */
#define INT_BCASTOPEN 2 /* broadcast socket is open */
#define INT_LOOPBACK 4 /* the loopback interface */
+#define INT_MULTICAST 8 /* multicasting enabled */
/*
* Define flasher bits (tests 1 through 8 in packet procedure)
@@ -222,7 +223,7 @@ struct peer {
U_LONG keyid; /* encription key ID */
U_LONG pkeyid; /* keyid used to encrypt last message */
u_short associd; /* association ID, a unique integer */
- u_char unused;
+ u_char ttl; /* time to live (multicast) */
/* **Start of clear-to-zero area.*** */
/* Everything that is cleared to zero goes below here */
u_char valid; /* valid counter */
@@ -248,12 +249,6 @@ struct peer {
s_fp soffset; /* fp version of above */
s_fp synch; /* synch distance from above */
u_fp selectdisp; /* select dispersion */
-
- /*
- * Stuff related to the experimental broadcast delay
- * determination code. The registers will probably go away
- * later.
- */
U_LONG estbdelay; /* broadcast delay, as a ts fraction */
/*
@@ -346,7 +341,7 @@ struct peer {
*/
#define REFCLK_NONE 0 /* unknown or missing */
#define REFCLK_LOCALCLOCK 1 /* external (e.g., ACTS) */
-#define REFCLK_WWV_HEATH 2 /* Heath GC-1000 WWV/H */
+#define REFCLK_GPS_TRAK 2 /* TRAK 8810 GPS Receiver */
#define REFCLK_WWV_PST 3 /* PST/Traconex 1020 WWV/H */
#define REFCLK_WWVB_SPECTRACOM 4 /* Spectracom 8170/Netclock WWVB */
#define REFCLK_GOES_TRUETIME 5 /* TrueTime 468-DC GOES */
@@ -579,8 +574,8 @@ struct recvbuf {
#define PROTO_AUTHENTICATE 3
#define PROTO_BROADDELAY 4
#define PROTO_AUTHDELAY 5
-#define PROTO_MAXSKEW 6
-#define PROTO_SELECT 7
+#define PROTO_MULTICAST_ADD 6
+#define PROTO_MULTICAST_DEL 7
/*
* Configuration items for the loop filter
@@ -603,7 +598,7 @@ struct recvbuf {
*/
#define DEFPRECISION (-5) /* conservatively low */
#define DEFBROADDELAY (0x020c49ba) /* 8 ms. This is round trip delay */
-
+#define INADDR_NTP 0xe0000101 /* NTP multicast address 224.0.1.1 */
/*
* Structure used optionally for monitoring when this is turned on.
*/
@@ -612,6 +607,9 @@ struct mon_data {
struct mon_data *hash_prev; /* previous structure in hash list */
struct mon_data *mru_next; /* next structure in MRU list */
struct mon_data *mru_prev; /* previous structure in MRU list */
+ struct mon_data *fifo_next; /* next structure in FIFO list */
+ struct mon_data *fifo_prev; /* previous structure in FIFO list */
+ U_LONG lastdrop; /* last time dropped due to RES_LIMIT*/
U_LONG lasttime; /* last time data updated */
U_LONG firsttime; /* time structure initialized */
U_LONG count; /* count we have seen */
@@ -621,7 +619,12 @@ struct mon_data {
u_char version; /* version of incoming packet */
};
-
+/*
+ * Values used with mon_enabled to indicate reason for enabling monitoring
+ */
+#define MON_OFF 0x00 /* no monitoring */
+#define MON_ON 0x01 /* monitoring explicitly enabled */
+#define MON_RES 0x02 /* implicit monitoring for RES_LIMITED */
/*
* Structure used for restrictlist entries
*/
@@ -645,10 +648,11 @@ struct restrictlist {
#define RES_NOPEER 0x20 /* don't allocate memory resources */
#define RES_NOTRAP 0x40 /* don't allow him to set traps */
#define RES_LPTRAP 0x80 /* traps set by him are low priority */
+#define RES_LIMITED 0x100 /* limit per net number of clients */
#define RES_ALLFLAGS \
(RES_IGNORE|RES_DONTSERVE|RES_DONTTRUST|RES_NOQUERY\
- |RES_NOMODIFY|RES_NOPEER|RES_NOTRAP|RES_LPTRAP)
+ |RES_NOMODIFY|RES_NOPEER|RES_NOTRAP|RES_LPTRAP|RES_LIMITED)
/*
* Match flags
diff --git a/contrib/xntpd/include/ntp_control.h b/contrib/xntpd/include/ntp_control.h
index 74f75f17f51a..1e193835660d 100644
--- a/contrib/xntpd/include/ntp_control.h
+++ b/contrib/xntpd/include/ntp_control.h
@@ -68,6 +68,7 @@ struct ntp_control {
#define CTL_SST_TS_UDPTIME 7 /* time source UDP/TIME */
#define CTL_SST_TS_WRSTWTCH 8 /* time source is wristwatch */
#define CTL_SST_TS_TELEPHONE 9 /* time source is telephone modem */
+#define CTL_SST_TS_PPS 0x20 /* time source is PPS signal */
#define CTL_SYS_MAXEVENTS 15
diff --git a/contrib/xntpd/include/ntp_if.h b/contrib/xntpd/include/ntp_if.h
index 1a76ca02da4b..45a70c51bcd5 100644
--- a/contrib/xntpd/include/ntp_if.h
+++ b/contrib/xntpd/include/ntp_if.h
@@ -16,6 +16,10 @@
#include <sys/sockio.h>
#endif
+#if defined(SYS_UNIXWARE1)
+#include <sys/sockio.h>
+#endif
+
#if defined(SYS_PTX) || defined(SYS_SINIXM)
#include <sys/stream.h>
#include <sys/stropts.h>
diff --git a/contrib/xntpd/include/ntp_in.h b/contrib/xntpd/include/ntp_in.h
new file mode 100755
index 000000000000..80aa45151fc6
--- /dev/null
+++ b/contrib/xntpd/include/ntp_in.h
@@ -0,0 +1,259 @@
+/* @(#)in.h 1.19 90/07/27 SMI; from UCB 7.5 2/22/88 */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981.
+ */
+
+#ifndef _netinet_in_h
+#define _netinet_in_h
+#define _NETINET_IN_H_
+#define _SYS_IN_INCLUDED
+#define __IN_HEADER
+
+/*
+ * Protocols
+ */
+#define IPPROTO_IP 0 /* dummy for IP */
+#define IPPROTO_ICMP 1 /* control message protocol */
+#define IPPROTO_IGMP 2 /* group control protocol */
+#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
+#define IPPROTO_ST 5 /* st */
+#define IPPROTO_TCP 6 /* tcp */
+#define IPPROTO_EGP 8 /* exterior gateway protocol */
+#define IPPROTO_PUP 12 /* pup */
+#define IPPROTO_UDP 17 /* user datagram protocol */
+#define IPPROTO_IDP 22 /* xns idp */
+#define IPPROTO_HELLO 63 /* "hello" routing protocol */
+#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
+#define IPPROTO_OSPF 89 /* Open SPF IGP */
+
+#define IPPROTO_RAW 255 /* raw IP packet */
+#define IPPROTO_MAX 256
+
+/*
+ * Port/socket numbers: network standard functions
+ */
+#define IPPORT_ECHO 7
+#define IPPORT_DISCARD 9
+#define IPPORT_SYSTAT 11
+#define IPPORT_DAYTIME 13
+#define IPPORT_NETSTAT 15
+#define IPPORT_FTP 21
+#define IPPORT_TELNET 23
+#define IPPORT_SMTP 25
+#define IPPORT_TIMESERVER 37
+#define IPPORT_NAMESERVER 42
+#define IPPORT_WHOIS 43
+#define IPPORT_MTP 57
+
+/*
+ * Port/socket numbers: host specific functions
+ */
+#define IPPORT_TFTP 69
+#define IPPORT_RJE 77
+#define IPPORT_FINGER 79
+#define IPPORT_TTYLINK 87
+#define IPPORT_SUPDUP 95
+
+/*
+ * UNIX TCP sockets
+ */
+#define IPPORT_EXECSERVER 512
+#define IPPORT_LOGINSERVER 513
+#define IPPORT_CMDSERVER 514
+#define IPPORT_EFSSERVER 520
+
+/*
+ * UNIX UDP sockets
+ */
+#define IPPORT_BIFFUDP 512
+#define IPPORT_WHOSERVER 513
+#define IPPORT_ROUTESERVER 520 /* 520+1 also used */
+
+/*
+ * Ports < IPPORT_RESERVED are reserved for
+ * privileged processes (e.g. root).
+ * Ports > IPPORT_USERRESERVED are reserved
+ * for servers, not necessarily privileged.
+ */
+#define IPPORT_RESERVED 1024
+#define IPPORT_USERRESERVED 5000
+
+/*
+ * Link numbers
+ */
+#define IMPLINK_IP 155
+#define IMPLINK_LOWEXPER 156
+#define IMPLINK_HIGHEXPER 158
+
+/*
+ * Internet address
+ * This definition contains obsolete fields for compatibility
+ * with SunOS 3.x and 4.2bsd. The presence of subnets renders
+ * divisions into fixed fields misleading at best. New code
+ * should use only the s_addr field.
+ */
+struct in_addr {
+ union {
+ struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
+ struct { u_short s_w1,s_w2; } S_un_w;
+ u_long S_addr;
+ } S_un;
+#define s_addr S_un.S_addr /* should be used for all code */
+#define s_host S_un.S_un_b.s_b2 /* OBSOLETE: host on imp */
+#define s_net S_un.S_un_b.s_b1 /* OBSOLETE: network */
+#define s_imp S_un.S_un_w.s_w2 /* OBSOLETE: imp */
+#define s_impno S_un.S_un_b.s_b4 /* OBSOLETE: imp # */
+#define s_lh S_un.S_un_b.s_b3 /* OBSOLETE: logical host */
+};
+
+/*
+ * Definitions of bits in internet address integers.
+ * On subnets, the decomposition of addresses to host and net parts
+ * is done according to subnet mask, not the masks here.
+ */
+#define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST 0x00ffffff
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST 0x0000ffff
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST 0x000000ff
+
+#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
+#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
+#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
+#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
+#define IN_MULTICAST(i) IN_CLASSD(i)
+
+#define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000) == 0xe0000000)
+#define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000)
+
+#define INADDR_ANY (u_long)0x00000000
+#define INADDR_LOOPBACK (u_long)0x7F000001
+#define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */
+
+#define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */
+#define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */
+#define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */
+
+#define IN_LOOPBACKNET 127 /* official! */
+
+/*
+ * Define a macro to stuff the loopback address into an Internet address
+ */
+#define IN_SET_LOOPBACK_ADDR(a) {(a)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); \
+ (a)->sin_family = AF_INET;}
+
+/*
+ * Socket address, internet style.
+ */
+struct sockaddr_in {
+ short sin_family;
+ u_short sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+};
+
+/*
+ * Options for use with [gs]etsockopt at the IP level.
+ */
+#define IP_OPTIONS 1 /* set/get IP per-packet options */
+#define IP_MULTICAST_IF 2 /* set/get IP multicast interface */
+#define IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */
+#define IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */
+#define IP_ADD_MEMBERSHIP 5 /* add an IP group membership */
+#define IP_DROP_MEMBERSHIP 6 /* drop an IP group membership */
+
+#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */
+#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
+#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */
+
+/*
+ * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+ */
+struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+};
+
+#if !defined(vax) && !defined(ntohl) && !defined(i386)
+/*
+ * Macros for number representation conversion.
+ */
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+#endif
+
+#if !defined(ntohl) && (defined(vax) || defined(i386))
+u_short ntohs(), htons();
+u_long ntohl(), htonl();
+#endif
+
+#ifdef KERNEL
+extern struct domain inetdomain;
+extern struct protosw inetsw[];
+struct in_addr in_makeaddr();
+u_long in_netof(), in_lnaof();
+#endif
+
+#ifndef BYTE_ORDER
+/*
+ * Definitions for byte order,
+ * according to byte significance from low address to high.
+ */
+#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */
+#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */
+
+#if defined(vax) || defined(i386)
+#define BYTE_ORDER LITTLE_ENDIAN
+#else
+#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */
+#endif
+#endif BYTE_ORDER
+
+/*
+ * Macros for number representation conversion.
+ */
+#if BYTE_ORDER==LITTLE_ENDIAN
+#define NTOHL(d) ((d) = ntohl((d)))
+#define NTOHS(d) ((d) = ntohs((d)))
+#define HTONL(d) ((d) = htonl((d)))
+#define HTONS(d) ((d) = htons((d)))
+#else
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+#define NTOHL(d)
+#define NTOHS(d)
+#define HTONL(d)
+#define HTONS(d)
+#endif
+
+#endif /*!_netinet_in_h*/
diff --git a/contrib/xntpd/include/ntp_io.h b/contrib/xntpd/include/ntp_io.h
index c3b79be0616c..d60f08359b84 100644
--- a/contrib/xntpd/include/ntp_io.h
+++ b/contrib/xntpd/include/ntp_io.h
@@ -3,6 +3,7 @@
* SEEK_SET symbol form <untisd.h>.
*/
#if defined(NTP_POSIX_SOURCE)
+
/*
* POSIX way
*/
diff --git a/contrib/xntpd/include/ntp_machine.h b/contrib/xntpd/include/ntp_machine.h
index 1c3983e4a9ef..16c3fbf6da83 100644
--- a/contrib/xntpd/include/ntp_machine.h
+++ b/contrib/xntpd/include/ntp_machine.h
@@ -44,11 +44,16 @@ Signaled IO - Signled IO defines.
WHICH TERMINAL MODEL TO USE - I would assume HAVE_TERMIOS if
NTP_POSIX_SOURCE was set but can't. The
posix tty driver is too restrictive on most systems.
- It defined if you define STREAMS.
+ It is defined if you define STREAMS.
+ We do not put these defines in the ntp_machine.h as some systems
+ offer multiple interfaces and refclock configuration likes to
+ peek into the configuration defines for tty model restrictions.
+ Thus all tty definitions should be in the files in the machines directory.
+
+ HAVE_TERMIOS - Use POSIX termios.h
HAVE_SYSV_TTYS - Use SYSV termio.h
HAVE_BSD_TTYS - Use BSD stty.h
- HAVE_TERMIOS - Use POSIX termios.h
THIS MAKES PORTS TO NEW SYSTEMS EASY - You only have to wory about
kernel mucking.
@@ -79,6 +84,7 @@ INFO ON NEW KERNEL PLL SYS CALLS
NTP_SYSCALLS_STD - use the "normal" ones
NTP_SYSCALL_GET - SYS_ntp_gettime id
NTP_SYSCALL_ADJ - SYS_ntp_adjtime id
+ NTP_SYSCALLS_LIBC - ntp_adjtime() and ntp_gettime() are in libc.
HOW TO GET IP INTERFACE INFORMATION
@@ -274,7 +280,6 @@ in this file.
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/Ultrix"
#endif
-#define HAVE_TERMIOS
#endif
/*
@@ -297,9 +302,9 @@ in this file.
#define FORCE_NTPDATE_STEP
#define RETSIGTYPE void
#define HAVE_ATT_SETPGRP
-#define HAVE_BSD_TTYS
#define LOG_NTP LOG_LOCAL1
#define HAVE_SIGNALED_IO
+#define NTP_NEED_BOPS
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/AUX"
#endif
@@ -309,6 +314,7 @@ in this file.
* Next
*/
#if defined(SYS_NEXT)
+#define RETSIGTYPE void
#define DOSYNCTODR
#define HAVE_READKMEM
#define HAVE_BSD_NICE
@@ -329,8 +335,12 @@ in this file.
#define setlinebuf(f) setvbuf(f, NULL, _IOLBF, 0)
#define NO_SIGNED_CHAR_DECL
#define LOCK_PROCESS
-#define HAVE_NO_NICE /* HPUX uses rtprio instead */
#define RETSIGTYPE void
+#if (SYS_HPUX < 9)
+#define HAVE_NO_NICE /* HPUX uses rtprio instead */
+#else
+#define HAVE_BSD_NICE /* new at 9.X */
+#endif
#if (SYS_HPUX < 10)
#define NOKMEM
#else
@@ -352,8 +362,6 @@ in this file.
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/BSDI"
#endif
-#define HAVE_BSD_TTYS
-#define HAVE_TERMIOS
#endif
/*
@@ -387,6 +395,13 @@ in this file.
#define STR_SYSTEM "UNIX/*BSD"
#endif
#endif
+#ifdef SYS_FREEBSD
+#define HAVE_TERMIOS
+#define HAVE_UNAME
+#define HAVE_SYS_TIMEX_H
+#define NTP_SYSCALLS_LIBC
+#define KERNEL_PLL
+#endif
/*
* DEC AXP OSF/1
@@ -441,9 +456,6 @@ in this file.
*/
#if defined(SYS_PTX)
#define NO_SIGNED_CHAR_DECL
-#ifndef HAVE_SYSV_TTYS
-#define HAVE_SYSV_TTYS
-#endif
#define STREAMS_TLI
#define HAVE_ATT_SETPGRP
#define HAVE_SIGNALED_IO
@@ -458,6 +470,7 @@ in this file.
#define HAVE_READKMEM
#define UDP_WILDCARD_DELIVERY
#define NTP_POSIX_SOURCE
+#define memmove(x, y, z) memcpy(x, y, z)
struct timezone { int __0; }; /* unused placebo */
/*
* no comment !@!
@@ -521,13 +534,46 @@ typedef unsigned long u_long;
#endif
/*
+ * (Univel/Novell) Unixware1 SVR4 on intel x86 processor
+ */
+#if defined(SYS_UNIXWARE1)
+/* #define _POSIX_SOURCE */
+#undef HAVE_ATT_SETPGRP
+#define USE_PROTOTYPES
+#define NTP_POSIX_SOURCE
+#define HAVE_ATT_NICE
+#define HAVE_READKMEM
+#define USE_TTY_SIGPOLL
+#define USE_UDP_SIGPOLL
+#define UDP_WILDCARD_DELIVERY
+#undef HAVE_SIGNALED_IO
+#define STREAM
+#define STREAMS
+#ifndef STREAMS_TLI
+/*#define STREAMS_TLI*/
+#endif
+/* #define USE_STREAMS_DEVICE_FOR_IF_CONFIG */
+#undef STEP_SLEW /* TWO step */
+#define LOCK_PROCESS
+#define NO_SIGNED_CHAR_DECL
+#undef SYSV_TIMEOFDAY
+#define SIZE_RETURNED_IN_BUFFER
+#define RETSIGTYPE void
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Unixware1"
+#endif
+#endif
+
+/*
* DomainOS
*/
#if defined(SYS_DOMAINOS)
#define HAVE_BSD_NICE
#define NOKMEM
#define HAVE_SIGNALED_IO
-#define HAVE_BSD_TTYS
#define NTP_SYSCALLS_STD
#define USE_PROTOTYPES
#define UDP_WILDCARD_DELIVERY
@@ -565,6 +611,20 @@ typedef unsigned long u_long;
ERROR You_must_define_one_of_the_HAVE_xx_NICE_defines
#endif
+/*
+ * use only one tty model - no use in initialising
+ * a tty in three ways
+ * HAVE_TERMIOS is preferred over HAVE_SYSV_TTYS over HAVE_BSD_TTYS
+ */
+#ifdef HAVE_TERMIOS
+#undef HAVE_BSD_TTYS
+#undef HAVE_SYSV_TTYS
+#endif
+
+#ifdef HAVE_SYSV_TTYS
+#undef HAVE_BSD_TTYS
+#endif
+
#if !defined(HAVE_SYSV_TTYS) \
&& !defined(HAVE_BSD_TTYS) \
&& !defined(HAVE_TERMIOS)
diff --git a/contrib/xntpd/include/ntp_request.h b/contrib/xntpd/include/ntp_request.h
index e94cb452aac7..b1a947291316 100644
--- a/contrib/xntpd/include/ntp_request.h
+++ b/contrib/xntpd/include/ntp_request.h
@@ -254,9 +254,8 @@ struct resp_pkt {
#define REQ_GET_LEAPINFO 35 /* get leap information */
#define REQ_GET_CLOCKINFO 36 /* get clock information */
#define REQ_SET_CLKFUDGE 37 /* set clock fudge factors */
-#define REQ_SET_MAXSKEW 38 /* set the maximum skew factor */
+#define REQ_GET_KERNEL 38 /* get kernel pll/pps information */
#define REQ_GET_CLKBUGINFO 39 /* get clock debugging info */
-#define REQ_SET_SELECT_CODE 40 /* set selection algorithm */
#define REQ_SET_PRECISION 41 /* set clock precision */
@@ -267,8 +266,9 @@ struct resp_pkt {
#define INFO_FLAG_SYSPEER 0x2
#define INFO_FLAG_MINPOLL 0x4
#define INFO_FLAG_REFCLOCK 0x8
+#define INFO_FLAG_MCLIENT 0x8 /* danger */
#define INFO_FLAG_BCLIENT 0x10
-#define INFO_FLAG_PREFER 0x10 /* SHARES BCLIENT bit - ok since mutually exclusive - Oh why ist flags a u_char ? */
+#define INFO_FLAG_PREFER 0x10 /* danger */
#define INFO_FLAG_AUTHENABLE 0x20
#define INFO_FLAG_SEL_CANDIDATE 0x40
#define INFO_FLAG_SHORTLIST 0x80
@@ -323,10 +323,10 @@ struct info_peer {
u_char valid; /* peer.valid */
u_char reach; /* peer.reach */
u_char unreach; /* peer.unreach */
- u_char trust; /* peer.trust */
- u_char unused1;
- u_char unused2;
- u_char unused3;
+ u_char flash; /* peer.flash */
+ u_char ttl; /* peer.ttl */
+ u_char unused8; /* (obsolete) */
+ u_char unused9;
u_short associd; /* association ID */
U_LONG keyid; /* auth key in use */
U_LONG pkeyid; /* peer.pkeyid */
@@ -344,7 +344,14 @@ struct info_peer {
s_fp delay; /* peer.estdelay */
u_fp dispersion; /* peer.estdisp */
l_fp offset; /* peer.estoffset */
- U_LONG bdelay[NTP_SHIFT]; /* broadcast delay filters */
+ u_fp selectdisp; /* peer select dispersion */
+ LONG unused1; /* (obsolete) */
+ LONG unused2;
+ LONG unused3;
+ LONG unused4;
+ LONG unused5;
+ LONG unused6;
+ LONG unused7;
U_LONG estbdelay; /* broadcast delay */
};
@@ -406,12 +413,13 @@ struct info_sys {
U_LONG refid; /* reference ID of sync source */
l_fp reftime; /* system reference time */
U_LONG poll; /* system poll interval */
- u_short flags; /* system flags */
- u_char selection; /* selection algorithm code */
- u_char unused;
- l_fp bdelay; /* default broadcast delay, a ts fraction */
+ u_char flags; /* system flags */
+ u_char unused1; /* unused */
+ u_char unused2; /* unused */
+ u_char unused3; /* unused */
+ l_fp bdelay; /* default broadcast delay */
l_fp authdelay; /* default authentication delay */
- u_fp maxskew; /* maximum skew parameter (obsolete) */
+ u_fp maxskew; /* (obsolete) */
};
@@ -428,6 +436,24 @@ struct info_sys_stats {
U_LONG badlength; /* packets with bad length */
U_LONG processed; /* packets processed */
U_LONG badauth; /* packets dropped because of authorization */
+ U_LONG wanderhold; /* (obsolete) */
+ U_LONG limitrejected; /* rejected because of client limitation */
+};
+
+
+/*
+ * System stats - old version
+ */
+struct old_info_sys_stats {
+ U_LONG timeup; /* time we have been up and running */
+ U_LONG timereset; /* time since these were last cleared */
+ U_LONG badstratum; /* packets claiming an invalid stratum */
+ U_LONG oldversionpkt; /* old version packets received */
+ U_LONG newversionpkt; /* new version packets received */
+ U_LONG unknownversion; /* don't know version packets */
+ U_LONG badlength; /* packets with bad length */
+ U_LONG processed; /* packets processed */
+ U_LONG badauth; /* packets dropped because of authorization */
U_LONG wanderhold;
};
@@ -486,7 +512,8 @@ struct conf_peer {
u_char minpoll; /* min host poll interval */
u_char maxpoll; /* max host poll interval */
u_char flags; /* flags for this request */
- u_char unused;
+ u_char ttl; /* time to live (multicast) */
+ u_short unused; /* unused */
U_LONG keyid; /* key to use for this association */
};
@@ -516,6 +543,7 @@ struct conf_sys_flags {
*/
#define SYS_FLAG_BCLIENT 0x1
#define SYS_FLAG_AUTHENTICATE 0x2
+#define SYS_FLAG_MCLIENT 0x4
/*
* Structure used for returning restrict entries
@@ -546,6 +574,7 @@ struct conf_restrict {
struct info_monitor {
U_LONG lasttime; /* last packet from this host */
U_LONG firsttime; /* first time we received a packet */
+ U_LONG lastdrop; /* last time we rejected a packet due to client limitation policy */
U_LONG count; /* count of packets received */
U_LONG addr; /* host address */
u_short port; /* port number of last reception */
@@ -553,6 +582,18 @@ struct info_monitor {
u_char version; /* version number of last packet */
};
+/*
+ * Structure used for returning monitor data (old format
+ */
+struct old_info_monitor {
+ U_LONG lasttime; /* last packet from this host */
+ U_LONG firsttime; /* first time we received a packet */
+ U_LONG count; /* count of packets received */
+ U_LONG addr; /* host address */
+ u_short port; /* port number of last reception */
+ u_char mode; /* mode of last packet */
+ u_char version; /* version number of last packet */
+};
/*
* Structure used for passing indication of flags to clear
@@ -711,3 +752,29 @@ struct info_clkbug {
U_LONG values[NUMCBUGVALUES];
l_fp times[NUMCBUGTIMES];
};
+
+/*
+ * Structure used for returning kernel pll/PPS information
+ */
+struct info_kernel {
+ LONG offset;
+ LONG freq;
+ LONG maxerror;
+ LONG esterror;
+ u_short status;
+ u_short shift;
+ LONG constant;
+ LONG precision;
+ LONG tolerance;
+
+/*
+ * Variables used only if PPS signal discipline is implemented
+ */
+ LONG ppsfreq;
+ LONG jitter;
+ LONG stabil;
+ LONG jitcnt;
+ LONG calcnt;
+ LONG errcnt;
+ LONG stbcnt;
+};
diff --git a/contrib/xntpd/include/ntp_stdlib.h b/contrib/xntpd/include/ntp_stdlib.h
index 0ec062581616..f68c768d82d3 100644
--- a/contrib/xntpd/include/ntp_stdlib.h
+++ b/contrib/xntpd/include/ntp_stdlib.h
@@ -79,6 +79,7 @@ extern char * inttoa P((LONG));
extern char * mfptoa P((U_LONG, U_LONG, int));
extern char * mfptoms P((U_LONG, U_LONG, int));
extern char * modetoa P((int));
+extern U_LONG netof P((U_LONG));
extern char * numtoa P((U_LONG));
extern char * numtohost P((U_LONG));
extern int octtoint P((const char *, U_LONG *));
diff --git a/contrib/xntpd/include/ntp_timex.h b/contrib/xntpd/include/ntp_timex.h
index 1756e2e07f21..cb8396ac23fe 100644
--- a/contrib/xntpd/include/ntp_timex.h
+++ b/contrib/xntpd/include/ntp_timex.h
@@ -1,6 +1,6 @@
/******************************************************************************
* *
- * Copyright (c) David L. Mills 1993 *
+ * Copyright (c) David L. Mills 1993, 1994 *
* *
* Permission to use, copy, modify, and distribute this software and its *
* documentation for any purpose and without fee is hereby granted, provided *
@@ -17,12 +17,18 @@
/*
* Modification history timex.h
*
+ * 19 Mar 94 David L. Mills
+ * Moved defines from kernel routines to header file and added new
+ * defines for PPS phase-lock loop.
+ *
+ * 20 Feb 94 David L. Mills
+ * Revised status codes and structures for external clock and PPS
+ * signal discipline.
+ *
* 28 Nov 93 David L. Mills
- * Adjusted parameters to improve stability and increase poll interval
+ * Adjusted parameters to improve stability and increase poll
+ * interval.
*
- * 10 Oct 93 Torsten Duwe
- * Changed to ntp_timex.h (#ifdef'd HAVE_SYS_TIMEX_H)
- *
* 17 Sep 93 David L. Mills
* Created file
*/
@@ -41,7 +47,7 @@
* int syscall(SYS_ntp_gettime, tptr)
*
* int SYS_ntp_gettime defined in syscall.h header file
- * struct ntptimeval *tptr pointer to ntptimeval structure
+ * struct ntptimeval *tptr pointer to ntptimeval structure
*
* NAME
* ntp_adjtime - NTP daemon application interface
@@ -55,104 +61,213 @@
* struct timex *tptr pointer to timex structure
*
*/
-#ifndef _NTP_TIMEX_H
-#define _NTP_TIMEX_H
+#ifndef MSDOS /* Microsoft specific */
+#include <sys/syscall.h>
+#endif /* MSDOS */
/*
- * Include system timex.h (if appropriate)
+ * The following defines establish the engineering parameters of the
+ * phase-lock loop (PLL) model used in the kernel implementation. These
+ * parameters have been carefully chosen by analysis for good stability
+ * and wide dynamic range.
+ *
+ * The hz variable is defined in the kernel build environment. It
+ * establishes the timer interrupt frequency, 100 Hz for the SunOS
+ * kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the OSF/1
+ * kernel. SHIFT_HZ expresses the same value as the nearest power of two
+ * in order to avoid hardware multiply operations.
+ *
+ * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
+ * for a slightly underdamped convergence characteristic.
+ *
+ * MAXTC establishes the maximum time constant of the PLL. With the
+ * SHIFT_KG and SHIFT_KF values given and a time constant range from
+ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
+ * respectively.
*/
-#ifdef HAVE_SYS_TIMEX_H
-#include <sys/timex.h>
-#else /* provide definitions */
-#include <sys/syscall.h>
-
-extern int syscall P((int, void *, ...));
+#define SHIFT_HZ 7 /* log2(hz) */
+#define SHIFT_KG 6 /* phase factor (shift) */
+#define SHIFT_KF 16 /* frequency factor (shift) */
+#define MAXTC 6 /* maximum time constant (shift) */
-#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
-#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
+/*
+ * The following defines establish the scaling of the various variables
+ * used by the PLL. They are chosen to allow the greatest precision
+ * possible without overflow of a 32-bit word.
+ *
+ * SHIFT_SCALE defines the scaling (shift) of the time_phase variable,
+ * which serves as a an extension to the low-order bits of the system
+ * clock variable time.tv_usec.
+ *
+ * SHIFT_UPDATE defines the scaling (shift) of the time_offset variable,
+ * which represents the current time offset with respect to standard
+ * time.
+ *
+ * SHIFT_USEC defines the scaling (shift) of the time_freq and
+ * time_tolerance variables, which represent the current frequency
+ * offset and maximum frequency tolerance.
+ *
+ * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
+ */
+#define SHIFT_SCALE 23 /* phase scale (shift) */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
+#define SHIFT_USEC 16 /* frequency offset scale (shift) */
+#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
/*
- * The following defines establish the engineering parameters of the PLL
- * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
- * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the
- * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
- * nearest power of two in order to avoid hardware multiply operations.
+ * The following defines establish the performance envelope of the PLL.
+ * They insure it operates within predefined limits, in order to satisfy
+ * correctness assertions. An excursion which exceeds these bounds is
+ * clamped to the bound and operation proceeds accordingly. In practice,
+ * this can occur only if something has failed or is operating out of
+ * tolerance, but otherwise the PLL continues to operate in a stable
+ * mode.
+ *
+ * MAXPHASE must be set greater than or equal to CLOCK.MAX (128 ms), as
+ * defined in the NTP specification. CLOCK.MAX establishes the maximum
+ * time offset allowed before the system time is reset, rather than
+ * incrementally adjusted. Here, the maximum offset is clamped to
+ * MAXPHASE only in order to prevent overflow errors due to defective
+ * protocol implementations.
+ *
+ * MAXFREQ is the maximum frequency tolerance of the CPU clock
+ * oscillator plus the maximum slew rate allowed by the protocol. It
+ * should be set to at least the frequency tolerance of the oscillator
+ * plus 100 ppm for vernier frequency adjustments. If the kernel
+ * PPS discipline code is configured (PPS_SYNC), the oscillator time and
+ * frequency are disciplined to an external source, presumably with
+ * negligible time and frequency error relative to UTC, and MAXFREQ can
+ * be reduced.
+ *
+ * MAXTIME is the maximum jitter tolerance of the PPS signal if the
+ * kernel PPS discipline code is configured (PPS_SYNC).
+ *
+ * MINSEC and MAXSEC define the lower and upper bounds on the interval
+ * between protocol updates.
*/
-#define SHIFT_HZ 7 /* log2(HZ) */
+#define MAXPHASE 128000L /* max phase error (us) */
+#ifdef PPS_SYNC
+#define MAXFREQ (100L << SHIFT_USEC) /* max freq error (100 ppm) */
+#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
+#else
+#define MAXFREQ (200L << SHIFT_USEC) /* max freq error (200 ppm) */
+#endif /* PPS_SYNC */
+#define MINSEC 16L /* min interval between updates (s) */
+#define MAXSEC 1200L /* max interval between updates (s) */
+#ifdef PPS_SYNC
/*
- * The SHIFT_KG and SHIFT_KF defines establish the damping of the PLL
- * and are chosen by analysis for a slightly underdamped convergence
- * characteristic. The MAXTC define establishes the maximum time constant
- * of the PLL. With the parameters given and the default time constant of
- * zero, the PLL will converge in about 15 minutes.
+ * The following defines are used only if a pulse-per-second (PPS)
+ * signal is available and connected via a modem control lead, such as
+ * produced by the optional ppsclock feature incorporated in the Sun
+ * asynch driver. They establish the design parameters of the frequency-
+ * lock loop used to discipline the CPU clock oscillator to the PPS
+ * signal.
+ *
+ * PPS_AVG is the averaging factor for the frequency loop, as well as
+ * the time and frequency dispersion.
+ *
+ * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
+ * calibration intervals, respectively, in seconds as a power of two.
+ *
+ * PPS_VALID is the maximum interval before the PPS signal is considered
+ * invalid and protocol updates used directly instead.
+ *
+ * MAXGLITCH is the maximum interval before a time offset of more than
+ * MAXTIME is believed.
*/
-#define SHIFT_KG 6 /* shift for phase increment */
-#define SHIFT_KF 16 /* shift for frequency increment */
-#define MAXTC 6 /* maximum time constant (shift) */
+#define PPS_AVG 2 /* pps averaging constant (shift) */
+#define PPS_SHIFT 2 /* min interval duration (s) (shift) */
+#define PPS_SHIFTMAX 8 /* max interval duration (s) (shift) */
+#define PPS_VALID 120 /* pps signal watchdog max (s) */
+#define MAXGLITCH 30 /* pps signal glitch max (s) */
+#endif /* PPS_SYNC */
/*
- * The SHIFT_SCALE define establishes the decimal point of the time_phase
- * variable which serves as a an extension to the low-order bits of the
- * system clock variable. The SHIFT_UPDATE define establishes the decimal
- * point of the time_offset variable which represents the current offset
- * with respect to standard time. The SHIFT_USEC define represents 1 us in
- * external units (shift), while the FINEUSEC define represents 1 us in
- * internal units.
+ * The following defines and structures define the user interface for
+ * the ntp_gettime() and ntp_adjtime() system calls.
+ *
+ * Control mode codes (timex.modes)
*/
-#define SHIFT_SCALE 23 /* shift for phase scale factor */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */
-#define SHIFT_USEC 16 /* shift for 1 us in external units */
-#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in internal units */
+#define MOD_OFFSET 0x0001 /* set time offset */
+#define MOD_FREQUENCY 0x0002 /* set frequency offset */
+#define MOD_MAXERROR 0x0004 /* set maximum time error */
+#define MOD_ESTERROR 0x0008 /* set estimated time error */
+#define MOD_STATUS 0x0010 /* set clock status bits */
+#define MOD_TIMECONST 0x0020 /* set pll time constant */
+#define MOD_CLKB 0x4000 /* set clock B */
+#define MOD_CLKA 0x8000 /* set clock A */
/*
- * Mode codes (timex.mode)
+ * Status codes (timex.status)
*/
-#define ADJ_OFFSET 0x0001 /* time offset */
-#define ADJ_FREQUENCY 0x0002 /* frequency offset */
-#define ADJ_MAXERROR 0x0004 /* maximum time error */
-#define ADJ_ESTERROR 0x0008 /* estimated time error */
-#define ADJ_STATUS 0x0010 /* clock status */
-#define ADJ_TIMECONST 0x0020 /* pll time constant */
+#define STA_PLL 0x0001 /* enable PLL updates (rw) */
+#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
+#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
+
+#define STA_INS 0x0010 /* insert leap (rw) */
+#define STA_DEL 0x0020 /* delete leap (rw) */
+#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
+
+#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
+#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
+#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
+#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
+
+#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
+
+#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
+ STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
/*
- * Clock command/status codes (timex.status)
+ * Clock states (time_state)
*/
-#define TIME_OK 0 /* clock synchronized */
-#define TIME_INS 1 /* insert leap second */
-#define TIME_DEL 2 /* delete leap second */
+#define TIME_OK 0 /* no leap second warning */
+#define TIME_INS 1 /* insert leap second warning */
+#define TIME_DEL 2 /* delete leap second warning */
#define TIME_OOP 3 /* leap second in progress */
-#define TIME_BAD 4 /* clock not synchronized */
+#define TIME_WAIT 4 /* leap second has occured */
+#define TIME_ERROR 5 /* clock not synchronized */
/*
- * NTP user interface - used to read kernel clock values
+ * NTP user interface (ntp_gettime()) - used to read kernel clock values
+ *
* Note: maximum error = NTP synch distance = dispersion + delay / 2;
* estimated error = NTP dispersion.
*/
struct ntptimeval {
- struct timeval time; /* current time */
- long maxerror; /* maximum error (usec) */
- long esterror; /* estimated error (usec) */
+ struct timeval time; /* current time (ro) */
+ LONG maxerror; /* maximum error (us) (ro) */
+ LONG esterror; /* estimated error (us) (ro) */
};
/*
- * NTP daemon interface - used to discipline kernel clock oscillator
+ * NTP daemon interface - (ntp_adjtime()) used to discipline CPU clock
+ * oscillator
*/
struct timex {
- int mode; /* mode selector */
- long offset; /* time offset (usec) */
- long frequency; /* frequency offset (scaled ppm) */
- long maxerror; /* maximum error (usec) */
- long esterror; /* estimated error (usec) */
- int status; /* clock command/status */
- long time_constant; /* pll time constant */
- long precision; /* clock precision (usec) (read only) */
- long tolerance; /* clock frequency tolerance (ppm)
- * (read only)
- */
-};
-
-#endif /* HAVE_SYS_TIMEX_H */
-
-#endif /* _NTP_TIMEX_H */
+ unsigned int modes; /* clock mode bits (wo) */
+ LONG offset; /* time offset (us) (rw) */
+ LONG freq; /* frequency offset (scaled ppm) (rw) */
+ LONG maxerror; /* maximum error (us) (rw) */
+ LONG esterror; /* estimated error (us) (rw) */
+ int status; /* clock status bits (rw) */
+ LONG constant; /* pll time constant (rw) */
+ LONG precision; /* clock precision (us) (ro) */
+ LONG tolerance; /* clock frequency tolerance (scaled
+ * ppm) (ro) */
+ /*
+ * The following read-only structure members are implemented
+ * only if the PPS signal discipline is configured in the
+ * kernel.
+ */
+ LONG ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ LONG jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ LONG stabil; /* pps stability (scaled ppm) (ro) */
+ LONG jitcnt; /* jitter limit exceeded (ro) */
+ LONG calcnt; /* calibration intervals (ro) */
+ LONG errcnt; /* calibration errors (ro) */
+ LONG stbcnt; /* stability limit exceeded (ro) */
+};
diff --git a/contrib/xntpd/include/ntpd.h b/contrib/xntpd/include/ntpd.h
index f2c56af20b90..037e8cb366f4 100644
--- a/contrib/xntpd/include/ntpd.h
+++ b/contrib/xntpd/include/ntpd.h
@@ -63,6 +63,9 @@ extern void input_handler P((l_fp *));
extern void io_clr_stats P((void));
extern void io_setbclient P((void));
extern void io_unsetbclient P((void));
+extern void io_multicast_add P((U_LONG));
+extern void io_multicast_del P((U_LONG));
+
extern void sendpkt P((struct sockaddr_in *, struct interface *, struct pkt *, int));
#ifdef HAVE_SIGNALED_IO
extern void wait_for_signal P((void));
@@ -93,8 +96,8 @@ extern int pps_sample P((l_fp *));
/* ntp_monitor.c */
extern void init_mon P((void));
-extern void mon_start P((void));
-extern void mon_stop P((void));
+extern void mon_start P((int));
+extern void mon_stop P((int));
extern void monitor P((struct recvbuf *));
/* ntp_peer.c */
@@ -102,10 +105,10 @@ extern void init_peer P((void));
extern struct peer *findexistingpeer P((struct sockaddr_in *, struct peer *));
extern struct peer *findpeer P((struct sockaddr_in *, struct interface *));
extern struct peer *findpeerbyassoc P((int));
-extern struct peer *newpeer P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG));
+extern struct peer *newpeer P((struct sockaddr_in *, struct interface *, int, int, int, int, int, U_LONG));
extern void peer_all_reset P((void));
extern void peer_clr_stats P((void));
-extern struct peer *peer_config P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG, int));
+extern struct peer *peer_config P((struct sockaddr_in *, struct interface *, int, int, int, int, int, int, U_LONG));
extern void peer_reset P((struct peer *));
extern int peer_unconfig P((struct sockaddr_in *, struct interface *));
extern void unpeer P((struct peer *));
@@ -131,7 +134,7 @@ extern void clock_select P((void));
extern void clock_combine P((struct peer **, int));
extern void fast_xmit P((struct recvbuf *, int, int));
extern void init_proto P((void));
-extern void proto_config P((int, LONG));
+extern void proto_config P((int, U_LONG));
extern void proto_clr_stats P((void));
#ifdef REFCLOCK
diff --git a/contrib/xntpd/include/parse.h b/contrib/xntpd/include/parse.h
index 31041afe292f..6ce3f192754a 100644
--- a/contrib/xntpd/include/parse.h
+++ b/contrib/xntpd/include/parse.h
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/v3/include/parse.h,v 3.13 1994/01/25 19:04:21 kardel Exp
+ * /src/NTP/REPOSITORY/v3/include/parse.h,v 3.17 1994/03/03 09:27:20 kardel Exp
*
- * parse.h,v 3.13 1994/01/25 19:04:21 kardel Exp
+ * parse.h,v 3.17 1994/03/03 09:27:20 kardel Exp
*
* Copyright (c) 1989,1990,1991,1992,1993,1994
* Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
@@ -15,7 +15,7 @@
#ifndef __PARSE_H__
#define __PARSE_H__
#if !(defined(lint) || defined(__GNUC__))
- static char parsehrcsid[]="parse.h,v 3.13 1994/01/25 19:04:21 kardel Exp FAU";
+ static char parsehrcsid[]="parse.h,v 3.17 1994/03/03 09:27:20 kardel Exp";
#endif
#include "ntp_types.h"
@@ -81,35 +81,55 @@ extern int debug;
/*
* state flags
*/
-#define PARSEB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */
-#define PARSEB_POWERUP 0x0002 /* no synchronisation */
-#define PARSEB_NOSYNC 0x0004 /* timecode currently not confirmed */
-#define PARSEB_DST 0x0008 /* DST in effect */
-#define PARSEB_UTC 0x0010 /* UTC time */
-#define PARSEB_LEAP 0x0020 /* LEAP warning (1 hour prior to occurence) */
-#define PARSEB_ALTERNATE 0x0040 /* alternate antenna used */
-#define PARSEB_POSITION 0x0080 /* position available */
-#define PARSEB_LEAPSECOND 0x0100 /* actual leap second */
-
-#define PARSEB_S_LEAP 0x0200 /* supports LEAP */
-#define PARSEB_S_ANTENNA 0x0400 /* supports antenna information */
-#define PARSEB_S_PPS 0x0800 /* supports PPS time stamping */
-#define PARSEB_S_POSITION 0x1000 /* supports position information (GPS) */
-
-#define PARSEB_TIMECODE 0x2000 /* valid time code sample */
-#define PARSEB_PPS 0x4000 /* valid PPS sample */
+#define PARSEB_POWERUP 0x00000001 /* no synchronisation */
+#define PARSEB_NOSYNC 0x00000002 /* timecode currently not confirmed */
+
+/*
+ * time zone information
+ */
+#define PARSEB_ANNOUNCE 0x00000010 /* switch time zone warning (DST switch) */
+#define PARSEB_DST 0x00000020 /* DST in effect */
+#define PARSEB_UTC 0x00000040 /* UTC time */
+
+/*
+ * leap information
+ */
+#define PARSEB_LEAPDEL 0x00000100 /* LEAP deletion warning */
+#define PARSEB_LEAPADD 0x00000200 /* LEAP addition warning */
+#define PARSEB_LEAPS 0x00000300 /* LEAP warnings */
+#define PARSEB_LEAPSECOND 0x00000400 /* actual leap second */
+/*
+ * optional status information
+ */
+#define PARSEB_ALTERNATE 0x00001000 /* alternate antenna used */
+#define PARSEB_POSITION 0x00002000 /* position available */
+
+/*
+ * feature information
+ */
+#define PARSEB_S_LEAP 0x00010000 /* supports LEAP */
+#define PARSEB_S_ANTENNA 0x00020000 /* supports antenna information */
+#define PARSEB_S_PPS 0x00040000 /* supports PPS time stamping */
+#define PARSEB_S_POSITION 0x00080000 /* supports position information (GPS) */
+
+/*
+ * time stamp availality
+ */
+#define PARSEB_TIMECODE 0x10000000 /* valid time code sample */
+#define PARSEB_PPS 0x20000000 /* valid PPS sample */
#define PARSE_TCINFO (PARSEB_ANNOUNCE|PARSEB_POWERUP|PARSEB_NOSYNC|PARSEB_DST|\
- PARSEB_UTC|PARSEB_LEAP|PARSEB_ALTERNATE|PARSEB_S_LEAP|\
+ PARSEB_UTC|PARSEB_LEAPS|PARSEB_ALTERNATE|PARSEB_S_LEAP|\
PARSEB_S_LOCATION|PARSEB_TIMECODE)
-#define PARSE_POWERUP(x) ((x) & PARSEB_POWERUP)
-#define PARSE_NOSYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == PARSEB_NOSYNC)
-#define PARSE_SYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == 0)
-#define PARSE_ANNOUNCE(x) ((x) & PARSEB_ANNOUNCE)
-#define PARSE_DST(x) ((x) & PARSEB_DST)
+#define PARSE_POWERUP(x) ((x) & PARSEB_POWERUP)
+#define PARSE_NOSYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == PARSEB_NOSYNC)
+#define PARSE_SYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == 0)
+#define PARSE_ANNOUNCE(x) ((x) & PARSEB_ANNOUNCE)
+#define PARSE_DST(x) ((x) & PARSEB_DST)
#define PARSE_UTC(x) ((x) & PARSEB_UTC)
-#define PARSE_LEAP(x) (PARSE_SYNC(x) && ((x) & PARSEB_LEAP))
+#define PARSE_LEAPADD(x) (PARSE_SYNC(x) && (((x) & PARSEB_LEAPS) == PARSEB_LEAPADD))
+#define PARSE_LEAPDEL(x) (PARSE_SYNC(x) && (((x) & PARSEB_LEAPS) == PARSEB_LEAPDEL))
#define PARSE_ALTERNATE(x) ((x) & PARSEB_ALTERNATE)
#define PARSE_LEAPSECOND(x) (PARSE_SYNC(x) && ((x) & PARSEB_LEAP_SECOND))
@@ -118,9 +138,9 @@ extern int debug;
#define PARSE_S_PPS(x) ((x) & PARSEB_S_PPS)
#define PARSE_S_POSITION(x) ((x) & PARSEB_S_POSITION)
-#define PARSE_TIMECODE(x) ((x) & PARSEB_TIMECODE)
+#define PARSE_TIMECODE(x) ((x) & PARSEB_TIMECODE)
#define PARSE_PPS(x) ((x) & PARSEB_PPS)
-#define PARSE_POSITION(x) ((x) & PARSEB_POSITION)
+#define PARSE_POSITION(x) ((x) & PARSEB_POSITION)
/*
* operation flags - some are also fudge flags
@@ -281,6 +301,7 @@ struct clocktime /* clock time broken up from time code */
LONG second;
LONG usecond;
LONG utcoffset; /* in seconds */
+ time_t utctime; /* the actual time - alternative to date/time */
LONG flags; /* current clock status */
};
@@ -365,6 +386,9 @@ extern unsigned LONG pps_simple P((parse_t *, int status, timestamp_t *));
* History:
*
* parse.h,v
+ * Revision 3.17 1994/03/03 09:27:20 kardel
+ * rcs ids fixed
+ *
* Revision 3.13 1994/01/25 19:04:21 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/kernel/.keep_me b/contrib/xntpd/kernel/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/kernel/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/lib/Makefile b/contrib/xntpd/lib/Makefile
index dcb4f091f82c..b6c00416c159 100644
--- a/contrib/xntpd/lib/Makefile
+++ b/contrib/xntpd/lib/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.4 1993/12/22 11:32:23 rgrimes Exp $
+# $Id: Makefile,v 1.5 1994/04/03 20:37:05 wollman Exp $
#
CFLAGS+= -I${.CURDIR}/../include
@@ -10,7 +10,7 @@ SRCS= atoint.c atolfp.c atouint.c auth12crypt.c authdecrypt.c authdes.c \
clocktime.c dofptoa.c dolfptoa.c emalloc.c fptoa.c fptoms.c \
gettstamp.c hextoint.c hextolfp.c humandate.c inttoa.c \
lib_strbuf.c mfptoa.c mfptoms.c modetoa.c mstolfp.c \
- msutotsf.c numtoa.c refnumtoa.c numtohost.c octtoint.c \
+ msutotsf.c netof.c numtoa.c refnumtoa.c numtohost.c octtoint.c \
prettydate.c ranny.c tsftomsu.c tstotv.c tvtoa.c tvtots.c \
uglydate.c uinttoa.c utvtoa.c clocktypes.c \
md5.c a_md5encrypt.c a_md5decrypt.c \
diff --git a/contrib/xntpd/lib/clocktypes.c b/contrib/xntpd/lib/clocktypes.c
index 2701e3f1d0ef..816ef0708b3e 100644
--- a/contrib/xntpd/lib/clocktypes.c
+++ b/contrib/xntpd/lib/clocktypes.c
@@ -11,7 +11,7 @@
struct clktype clktypes[] = {
{ REFCLK_NONE, "unspecified type (0)", "UNKNOWN" },
{ REFCLK_LOCALCLOCK, "local clock synchronization (1)", "LOCAL" },
- { REFCLK_WWV_HEATH, "Heathkit WWV clock (2)", "WWV_HEATH" },
+ { REFCLK_GPS_TRAK, "TRAK 8810 GPS Receiver (2)", "GPS_TRAK" },
{ REFCLK_WWV_PST, "Precision Standard Time WWV clock (3)", "WWV_PST" },
{ REFCLK_WWVB_SPECTRACOM, "Spectracom WWVB clock (4)", "WWVB_SPEC" },
{ REFCLK_GOES_TRUETIME, "True Time GPS/GOES clock (5)", "GPS_GOES_TRUE" },
diff --git a/contrib/xntpd/lib/netof.c b/contrib/xntpd/lib/netof.c
new file mode 100644
index 000000000000..286a5846eb40
--- /dev/null
+++ b/contrib/xntpd/lib/netof.c
@@ -0,0 +1,25 @@
+/*
+ * netof - return the net address part of an ip address
+ * (zero out host part)
+ */
+#include <stdio.h>
+
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+
+U_LONG
+netof(num)
+ U_LONG num;
+{
+ register U_LONG netnum;
+
+ netnum = num;
+
+ if(IN_CLASSC(netnum))
+ netnum &= IN_CLASSC_NET;
+ else if (IN_CLASSB(netnum))
+ netnum &= IN_CLASSB_NET;
+ else /* treat als other like class A */
+ netnum &= IN_CLASSA_NET;
+ return netnum;
+}
diff --git a/contrib/xntpd/lib/numtohost.c b/contrib/xntpd/lib/numtohost.c
index e22b6231790a..2f07c2c4dac5 100644
--- a/contrib/xntpd/lib/numtohost.c
+++ b/contrib/xntpd/lib/numtohost.c
@@ -1,12 +1,11 @@
-/* numtohost.c,v 3.1 1993/07/06 01:08:40 jbj Exp
+/*
* numtohost - convert network number to host name.
*/
-#include "ntp_types.h"
#include <netdb.h>
#include "ntp_fp.h"
-#include "lib_strbuf.h"
#include "ntp_stdlib.h"
+#include "lib_strbuf.h"
#define LOOPBACKNET 0x7f000000
#define LOOPBACKHOST 0x7f000001
diff --git a/contrib/xntpd/lib/systime.c b/contrib/xntpd/lib/systime.c
index ea15734f1abb..1d6c59a5d969 100644
--- a/contrib/xntpd/lib/systime.c
+++ b/contrib/xntpd/lib/systime.c
@@ -47,12 +47,13 @@ extern int debug;
* We also remember the clock precision we computed from the kernel in
* case someone asks us.
*/
+ LONG sys_clock;
+
LONG adj_precision; /* adj precision in usec (tickadj) */
LONG tvu_maxslew; /* maximum adjust doable in 1<<CLOCK_ADJ sec (usec) */
U_LONG tsf_maxslew; /* same as above, as LONG format */
- LONG sys_clock;
l_fp sys_clock_offset; /* correction for current system time */
/*
diff --git a/contrib/xntpd/machines/.keep_me b/contrib/xntpd/machines/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/machines/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ntpdate/ntpdate.h b/contrib/xntpd/ntpdate/ntpdate.h
index 4a8ff746e772..f6d3ebf877f3 100644
--- a/contrib/xntpd/ntpdate/ntpdate.h
+++ b/contrib/xntpd/ntpdate/ntpdate.h
@@ -54,7 +54,11 @@ struct server {
* are close, or step the time if the times are farther apart. The
* following defines what is "close".
*/
+#ifdef linux
+#define NTPDATE_THRESHOLD (FP_SECOND / 8) /* 1/8 second */
+#else
#define NTPDATE_THRESHOLD (FP_SECOND >> 1) /* 1/2 second */
+#endif
/*
* When doing adjustments, ntpdate actually overadjusts (currently
diff --git a/contrib/xntpd/ntpq/ntpq.c b/contrib/xntpd/ntpq/ntpq.c
index 5cfc3daff820..73c2a351aa70 100644
--- a/contrib/xntpd/ntpq/ntpq.c
+++ b/contrib/xntpd/ntpq/ntpq.c
@@ -75,6 +75,7 @@ int jump = 0;
#define OC 12 /* integer, print in octal */
#define MD 13 /* mode */
#define AR 14 /* array of times */
+#define TST 15 /* test flags */
#define EOV 255 /* end of table */
@@ -145,7 +146,7 @@ struct ctl_var peer_var[] = {
{ CP_RECEIVED, UI, "received" }, /* 31 */
{ CP_SENT, UI, "sent" }, /* 32 */
{ CP_FILTERROR, AR, "filterror" }, /* 33 */
- { CP_FLASH, ST, "flash"}, /* 34 */
+ { CP_FLASH, TST, "flash"}, /* 34 */
{ CP_DISP, AR, "disp" }, /* 35 */
/*
* These are duplicate entires so that we can
@@ -189,6 +190,20 @@ struct codestring {
};
/*
+ * flasher bits
+ */
+static char *tstflagnames[] = {
+ "DUPLICATE PKT",
+ "BOGUS PKT",
+ "PROTO UNSYNC",
+ "PEER BOUNDS",
+ "BAD AUTH",
+ "PEER CLOCK UNSYNC",
+ "BAD STRATUM",
+ "ROOT BOUNDS"
+};
+
+/*
* Leap values
*/
struct codestring leap_codes[] = {
@@ -301,7 +316,7 @@ static int decodereach P((char *, U_LONG *));
static int decodearr P((char *, int *, l_fp *));
static char * getcode P((int, struct codestring *));
static void help P((struct parse *, FILE *));
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
static int helpsort P((const void *, const void *));
#else
static int helpsort P((char **, char **));
@@ -335,7 +350,7 @@ static void output P((FILE *, char *, char *));
static void endoutput P((FILE *));
static void outputarr P((FILE *, char *, int, l_fp *));
static void cookedprint P((int, int, char *, int, FILE *));
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
static int assoccmp P((const void *, const void *));
#else
static int assoccmp P((struct association *, struct association *));
@@ -1888,7 +1903,7 @@ help(pcmd, fp)
for (xcp = opcmds; xcp->keyword != 0; xcp++)
cmdsort[n++] = xcp->keyword;
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
qsort((void *)cmdsort, n, sizeof(char *), helpsort);
#else
qsort((char *)cmdsort, n, sizeof(char *), helpsort);
@@ -1934,7 +1949,7 @@ help(pcmd, fp)
* helpsort - do hostname qsort comparisons
*/
static int
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
helpsort(t1, t2)
const void *t1;
const void *t2;
@@ -2836,7 +2851,45 @@ outputarr(fp, name, narr, lfp)
output(fp, name, buf);
}
-
+static char *
+tstflags(val)
+ U_LONG val;
+{
+ register char *cb, *s;
+ register int i;
+ register char *sep;
+
+ sep = "";
+ i = 0;
+ s = cb = &circ_buf[nextcb][0];
+ if (++nextcb >= NUMCB)
+ nextcb = 0;
+
+ sprintf(cb, "0x%x", val);
+ cb += strlen(cb);
+ if (val <= ((1<<8)-1)) {
+ if (!val) {
+ strcat(cb, "<OK>");
+ cb += strlen(cb);
+ } else {
+ *cb++ = '<';
+ while (val) {
+ if (val & 0x1) {
+ sprintf(cb, "%s%s", sep, tstflagnames[i]);
+ sep = ";";
+ cb += strlen(cb);
+ }
+ i++;
+ val >>= 1;
+ }
+ *cb++ = '>';
+ }
+ } else {
+ *cb++ = '?';
+ }
+ *cb = '\0';
+ return s;
+}
/*
* cookedprint - output variables in cooked mode
@@ -2994,6 +3047,13 @@ cookedprint(datatype, length, data, status, fp)
outputarr(fp, name, narr, lfparr);
break;
+ case TST:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else
+ output(fp, name, tstflags(uval));
+ break;
+
default:
(void) fprintf(stderr,
"Internal error in cookedprint, %s=%s, fmt %d\n",
@@ -3028,7 +3088,7 @@ void
sortassoc()
{
if (numassoc > 1)
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
qsort((void *)assoc_cache, numassoc,
sizeof(struct association), assoccmp);
#else
@@ -3042,7 +3102,7 @@ sortassoc()
* assoccmp - compare two associations
*/
static int
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
assoccmp(t1, t2)
const void *t1;
const void *t2;
diff --git a/contrib/xntpd/parse/README.new_clocks b/contrib/xntpd/parse/README.new_clocks
new file mode 100644
index 000000000000..8fdd7cbd4250
--- /dev/null
+++ b/contrib/xntpd/parse/README.new_clocks
@@ -0,0 +1,212 @@
+Here is an attempt to sketch out what you need to do in order to
+add another clock to the parse driver:
+
+Prerequisites:
+- Does the system you want the clock connect to have
+ termio.h or termios.h ? (You need that for the parse driver)
+
+What to do:
+
+Make a conversion module (parse/clk_*.c)
+
+- What ist the time code format ?
+ - find year, month, day, hour, minute, second, status (synchronised or
+ not), possibly time zone information (you need to give the offset to UTC)
+ You will have to convert the data from a string into a struct clocktime:
+ struct clocktime /* clock time broken up from time code */
+ {
+ LONG day;
+ LONG month;
+ LONG year;
+ LONG hour;
+ LONG minute;
+ LONG second;
+ LONG usecond;
+ LONG utcoffset; /* in seconds */
+ time_t utcoffset; /* true utc time instead of date/time */
+ LONG flags; /* current clock status */
+ };
+
+ Conversion is usually simple and straight forward. For the flags following
+ values can be OR'ed together:
+
+ PARSEB_ANNOUNCE switch time zone warning (informational only)
+ PARSEB_POWERUP no synchronisation - clock confused (must set then)
+ PARSEB_NOSYNC timecode currently not confirmed (must set then)
+ usually on reception error when there is still a
+ chance the the generated time is still ok.
+
+ PARSEB_DST DST in effect (informational only)
+ PARSEB_UTC timecode contains UTC time (informational only)
+ PARSEB_LEAPADD LEAP addition warning (prior to leap happening - must set when imminent)
+ also used for time code that do not encode the
+ direction (as this is currently the default).
+ PARSEB_LEAPDEL LEAP deletion warning (prior to leap happening - must set when imminent)
+ PARSEB_ALTERNATE backup transmitter (informational only)
+ PARSEB_POSITION geographic position available (informational only)
+ PARSEB_LEAPSECOND actual leap second (this time code is the leap
+ second - informational only)
+
+ These are feature flags denoting items that are supported by the clock:
+ PARSEB_S_LEAP supports LEAP - might set PARSEB_LEAP
+ PARSEB_S_ANTENNA supports ANTENNA - might set PARSEB_ALTERNATE
+ PARSEB_S_PPS supports PPS time stamping
+ PARSEB_S_POSITION supports position information (GPS)
+
+ If the utctime field is non zero this value will be take as
+ time code value. This allows for conversion routines that
+ already have the utc time value. The utctime field gives the seconds
+ since Jan 1st 1970, 0:00:00. The useconds field gives the respective
+ usec value. The fields for date and time (down to second resolution)
+ will be ignored.
+
+ Conversion is done in the cvt_* routine in parse/clk_*.c files. look in
+ them for examples. The basic structure is:
+
+ struct clockformat <yourclock>_format = {
+ lots of fields for you to fill out (see below)
+ };
+
+ static cvt_<yourclock>()
+ ...
+ {
+ if (<I do not recognize my time code>) {
+ return CVT_NONE;
+ } else {
+ if (<conversion into clockformat is ok>) {
+ <set all necessary flags>;
+ return CVT_OK;
+ } else {
+ return CVT_FAIL|CVT_BADFMT;
+ }
+ }
+
+ The struct clockformat is the interface to the rest of the parse
+ driver - it holds all information necessary for finding the
+ clock message and doing the appropriate time stamping.
+
+struct clockformat
+{
+ unsigned LONG (*convert)();
+ /* conversion routine - your routine - cvt_<yourclock> */
+ void (*syncevt)();
+ /* routine for handling RS232 sync events (time stamps) - usually sync_simple */
+ unsigned LONG (*syncpps)();
+ /* PPS input routine - usually pps_simple */
+ unsigned LONG (*synth)();
+ /* time code synthesizer - usually not used - (LONG (*)())0 */
+ void *data;
+ /* local parameters - any parameters/data/configuration info your conversion
+ routine might need */
+ char *name;
+ /* clock format name - Name of the time code */
+ unsigned short length;
+ /* maximum length of data packet for your clock format */
+ unsigned LONG flags;
+ /* information for the parser what to look for */
+ struct timeval timeout;
+ /* buffer restart after timeout (us) - some clocks preceede new data by
+ a longer period of silence - unsually not used */
+ unsigned char startsym;
+ /* start symbol - character at the beginning of the clock data */
+ unsigned char endsym;
+ /* end symbol - character at the end of the clock data */
+ unsigned char syncsym;
+ /* sync symbol - character that is "on time" - where the time stamp should be taken */
+};
+
+ The flags:
+ F_START use startsym to find the beginning of the clock data
+ F_END use endsym to find the end of the clock data
+ SYNC_TIMEOUT packet restart after timeout in timeout field
+ SYNC_START packet start is sync event (time stamp at paket start)
+ SYNC_END packet end is sync event (time stamp at paket end)
+ SYNC_CHAR special character (syncsym) is sync event
+ SYNC_ONE PPS synchronize on 'ONE' transition
+ SYNC_ZERO PPS synchronize on 'ZERO' transition
+ SYNC_SYNTHESIZE generate intermediate time stamps (very special case!)
+ CVT_FIXEDONLY convert only in fixed configuration - (data format not
+ suitable for auto-configuration)
+
+
+ The above should have given you some hints on how to build a clk_*.c
+ file with the time code conversion. See the examples and pick a clock
+ closest to yours and tweak the code to match your clock.
+
+ In order to make your clk_*.c file usable a reference to the clockformat
+ structure must be put into parse_conf.c.
+
+TTY setup and initialisation/configuration will be done in
+xntpd/refclock_parse.c
+
+- Find out the exact tty settings for your clock (baud rate, parity,
+ stop bits, character size, ...) and note them in terms of
+ termio*.h c_cflag macros.
+
+- in xntpd/refclock_parse.c fill out a new the struct clockinfo element
+ (that allocates a new "IP" address - see comments)
+ (see all the other clocks for example)
+ struct clockinfo
+ {
+ U_LONG cl_flags; /* operation flags (io modes) */
+ PARSE_F_NOPOLLONLY always do async io - read whenever input comes
+ PARSE_F_POLLONLY never do async io - only read when expecting data
+ PARSE_F_PPSPPS use loopfilter PPS code (CIOGETEV)
+ PARSE_F_PPSONSECOND PPS pulses are on second
+ usually flags stay 0 as they are used only for special setups
+
+ void (*cl_poll)(); /* active poll routine */
+ The routine to call when the clock needs data sent to it in order to
+ get a time code from the clock (e.g. Trimble clock)
+ int (*cl_init)(); /* active poll init routine */
+ The routine to call for very special initializations.
+ void (*cl_end)(); /* active poll end routine */
+ The routine to call to undo any special initialisation (free memory/timers)
+ void *cl_data; /* local data area for "poll" mechanism */
+ local data for polling routines
+ u_fp cl_rootdelay; /* rootdelay */
+ NTP rottdelay estimate (usually 0)
+ U_LONG cl_basedelay; /* current offset - unsigned l_fp fractional par
+ time (fraction) by which the RS232 time code is delayed from the actual time.
+ t */
+ U_LONG cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional
+ time (fraction) by which the PPS time stamp is delayed (usually 0)
+ part */
+ char *cl_id; /* ID code (usually "DCF") */
+ Refclock id - (max 4 chars)
+ char *cl_description; /* device name */
+ Name of this device.
+ char *cl_format; /* fixed format */
+ If the data format cann not ne detected automatically this is the name
+ as in clk_*.c clockformat.
+ u_char cl_type; /* clock type (ntp control) */
+ Type if clock as in clock status word (ntp control messages) - usually 0
+ U_LONG cl_maxunsync; /* time to trust oscillator after loosing synch
+ */
+ seconds a clock can be trusted after loosing synchronisation.
+
+ U_LONG cl_cflag; /* terminal io flags */
+ U_LONG cl_iflag; /* terminal io flags */
+ U_LONG cl_oflag; /* terminal io flags */
+ U_LONG cl_lflag; /* terminal io flags */
+ termio*.h tty modes.
+ } clockinfo[] = {
+ ...,<other clocks>,...
+ { < your parameters> },
+ };
+
+
+Well, this is very sketchy, i know. But I hope it helps a little bit.
+The best way is to look which clock comes closest to your and tweak that
+code.
+Two sorts of clocks are used with parse. Clocks that automatically send
+their time code (once a second) do not need entries in the poll routines because
+they send the data all the time. The second sort are the clocks that need a
+command sent to them in order to reply with a time code (like the Trimble
+clock).
+
+For questions: kardel@informatik.uni-erlangen.de. Please include
+an exact description on how your clock works. (initialisation,
+TTY modes, strings to be sent to it, responses received from the clock).
+
+Frank Kardel
diff --git a/contrib/xntpd/parse/README.parse_clocks b/contrib/xntpd/parse/README.parse_clocks
new file mode 100644
index 000000000000..cf8d77eb76bb
--- /dev/null
+++ b/contrib/xntpd/parse/README.parse_clocks
@@ -0,0 +1,263 @@
+The parse driver currently supports several clocks with different
+query mechanisms. In order for you to find a sample that might be
+similar to a clock you might want to integrate into parse i'll sum
+up the major features of the clocks (this information is distributed
+in the parse/clk_*.c and xntpd/refclock_parse.c files).
+
+---
+ Meinberg: 127.127.8. 0- 3 (PZF535TCXO)
+ 127.127.8. 4- 7 (PZF535OCXO)
+ 127.127.8. 8-11 (DCFUA31)
+ 127.127.8.28-31 (GPS166)
+ Meinberg: start=<STX>, end=<ETX>, sync on start
+ pattern="\2D: . . ;T: ;U: . . ; \3"
+ pattern="\2 . . ; ; : : ; \3"
+ pattern="\2 . . ; ; : : ; : ; ; . . "
+
+ Meinberg is a german manufacturer of time code receivers. Those clocks
+ have a pretty common output format in the stock version. In order to
+ support NTP Meinberg was so kind to produce some special versions of
+ the firmware for the use with NTP. So, if you are going to use a
+ Meinberg clock please ask whether there is a special Uni Erlangen
+ version.
+
+ General characteristics:
+ Meinberg clocks primarily output pulse per second and a describing
+ ASCII string. This string can be produced in two modes. either upon
+ the reception of a question mark or every second. NTP uses the latter
+ mechanism. The DCF77 variants have a pretty good relationship between
+ RS232 time code and the PPS signal while the GPS receiver has no fixed
+ timeing between the datagram and the pulse (you need to use PPS with
+ GPS!) on DCF77 you might get away without the PPS signal.
+
+ The preferred tty setting for Meinberg is:
+ CFLAG (B9600|CS7|PARENB|CREAD|HUPCL)
+ IFLAG (IGNBRK|IGNPAR|ISTRIP)
+ OFLAG 0
+ LFLAG 0
+
+ The clock is run at datagram once per second.
+ Stock dataformat is:
+
+ <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
+ pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3
+ 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2
+
+ <STX> = '\002' ASCII start of text
+ <ETX> = '\003' ASCII end of text
+ <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ <w> = day of week (sunday= 0)
+ <hh>,<mm>,<ss> = hour, minute, second
+ <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ '#' if not PZF sychronisation available else ' ' for PZF 535
+ <F> = '*' if time comes from internal quartz else ' '
+ <D> = 'S' if daylight saving time is active else ' '
+ <A> = '!' during the hour preceeding an daylight saving time
+ start/end change
+
+ For the university of Erlangen a special format was implemented to support
+ LEAP announcement and anouncement of alternate antenna.
+
+ Version for UNI-ERLANGEN Software is: PZFUERL V4.6 (Meinberg)
+
+ The use of this software release (or higher) is *ABSOLUTELY*
+ recommended (ask for PZFUERL version as some minor HW fixes have
+ been introduced) due to the LEAP second support and UTC indication.
+ The standard timecode does not indicate when the timecode is in
+ UTC (by front panel configuration) thus we have no chance to find
+ the correct utc offset. For the standard format do not ever use
+ UTC display as this is not detectable in the time code !!!
+
+ <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
+ pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3
+ 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2
+ <STX> = '\002' ASCII start of text
+ <ETX> = '\003' ASCII end of text
+ <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ <w> = day of week (sunday= 0)
+ <hh>,<mm>,<ss> = hour, minute, second
+ <U> = 'U' UTC time display
+ <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ '#' if not PZF sychronisation available else ' ' for PZF 535
+ <F> = '*' if time comes from internal quartz else ' '
+ <D> = 'S' if daylight saving time is active else ' '
+ <A> = '!' during the hour preceeding an daylight saving time
+ start/end change
+ <L> = 'A' LEAP second announcement
+ <R> = 'R' alternate antenna
+
+ Meinberg GPS166 receiver
+
+ You must get the Uni-Erlangen firmware for the GPS receiver support
+ to work to full satisfaction !
+
+ <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
+ *
+ 000000000111111111122222222223333333333444444444455555555556666666
+ 123456789012345678901234567890123456789012345678901234567890123456
+ \x0209.07.93; 5; 08:48:26; +00:00; ; 49.5736N 11.0280E 373m\x03
+ *
+
+ <STX> = '\002' ASCII start of text
+ <ETX> = '\003' ASCII end of text
+ <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ <w> = day of week (sunday= 0)
+ <hh>,<mm>,<ss> = hour, minute, second
+ <+/->,<00:00> = offset to UTC
+ <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ '#' if not PZF sychronisation available else ' ' for PZF 535
+ <U> = 'U' UTC time display
+ <F> = '*' if time comes from internal quartz else ' '
+ <D> = 'S' if daylight saving time is active else ' '
+ <A> = '!' during the hour preceeding an daylight saving time
+ start/end change
+ <L> = 'A' LEAP second announcement
+ <R> = 'R' alternate antenna (reminiscent of PZF535) usually ' '
+ <L> = 'L' on 23:59:60
+
+
+ For the Meinberg parse look into clock_meinberg.c
+
+---
+ RAWDCF: 127.127.8.20-23 (Conrad receiver module - delay 210ms)
+ 127.127.8.24-27 (FAU receiver - delay 258ms)
+ RAWDCF: end=TIMEOUT>1.5s, sync each char (any char),generate psuedo time
+ codes, fixed format
+
+ direct DCF77 code input
+ In Europe it is relatively easy/cheap the receive the german time code
+ transmitter DCF77. The simplest version to process its signal is to
+ feed the 100/200ms pulse of the demodulated AM signal via a level
+ converter to an RS232 port at 50Baud. parse/clk_rawdcf.c holds all
+ necessary decoding logic for the time code which is transmitted each
+ minute for one minute. A bit of the time code is sent once a second.
+
+ The preferred tty setting is:
+ CFLAG (B50|CS8|CREAD|CLOCAL)
+ IFLAG 0
+ OFLAG 0
+ LFLAG 0
+
+ DCF77 raw time code
+
+ From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
+ und Berlin, Maerz 1989
+
+ Timecode transmission:
+ AM:
+ time marks are send every second except for the second before the
+ next minute mark
+ time marks consist of a reduction of transmitter power to 25%
+ of the nominal level
+ the falling edge is the time indication (on time)
+ time marks of a 100ms duration constitute a logical 0
+ time marks of a 200ms duration constitute a logical 1
+ FM:
+ see the spec. (basically a (non-)inverted psuedo random phase shift)
+
+ Encoding:
+ Second Contents
+ 0 - 10 AM: free, FM: 0
+ 11 - 14 free
+ 15 R - alternate antenna
+ 16 A1 - expect zone change (1 hour before)
+ 17 - 18 Z1,Z2 - time zone
+ 0 0 illegal
+ 0 1 MEZ (MET)
+ 1 0 MESZ (MED, MET DST)
+ 1 1 illegal
+ 19 A2 - expect leap insertion/deletion (1 hour before)
+ 20 S - start of time code (1)
+ 21 - 24 M1 - BCD (lsb first) Minutes
+ 25 - 27 M10 - BCD (lsb first) 10 Minutes
+ 28 P1 - Minute Parity (even)
+ 29 - 32 H1 - BCD (lsb first) Hours
+ 33 - 34 H10 - BCD (lsb first) 10 Hours
+ 35 P2 - Hour Parity (even)
+ 36 - 39 D1 - BCD (lsb first) Days
+ 40 - 41 D10 - BCD (lsb first) 10 Days
+ 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
+ 45 - 49 MO - BCD (lsb first) Month
+ 50 MO0 - 10 Months
+ 51 - 53 Y1 - BCD (lsb first) Years
+ 54 - 57 Y10 - BCD (lsb first) 10 Years
+ 58 P3 - Date Parity (even)
+ 59 - usually missing (minute indication), except for leap insertion
+
+---
+ Schmid clock: 127.127.8.16-19
+ Schmid clock: needs poll, binary input, end='\xFC', sync start
+
+ The Schmid clock is a DCF77 receiver that sends a binary
+ time code at the reception of a flag byte. The contents
+ if the flag byte determined the time code format. The
+ binary time code is delimited by the byte 0xFC.
+
+ TTY setup is:
+ CFLAG (B1200|CS8|CREAD|CLOCAL)
+ IFLAG 0
+ OFLAG 0
+ LFLAG 0
+
+ The command to Schmid's DCF77 clock is a single byte; each bit
+ allows the user to select some part of the time string, as follows (the
+ output for the lsb is sent first).
+
+ Bit 0: time in MEZ, 4 bytes *binary, not BCD*; hh.mm.ss.tenths
+ Bit 1: date 3 bytes *binary, not BCD: dd.mm.yy
+ Bit 2: week day, 1 byte (unused here)
+ Bit 3: time zone, 1 byte, 0=MET, 1=MEST. (unused here)
+ Bit 4: clock status, 1 byte, 0=time invalid,
+ 1=time from crystal backup,
+ 3=time from DCF77
+ Bit 5: transmitter status, 1 byte,
+ bit 0: backup antenna
+ bit 1: time zone change within 1h
+ bit 3,2: TZ 01=MEST, 10=MET
+ bit 4: leap second will be
+ added within one hour
+ bits 5-7: Zero
+ Bit 6: time in backup mode, units of 5 minutes (unused here)
+
+
+---
+ Trimble SV6: 127.127.8.32-35
+ Trimble SV6: needs poll, ascii timecode, start='>', end='<',
+ query='>QTM<', eol='<'
+
+ Trimble SV6 is a GPS receiver with PPS output. It needs to be polled.
+ It also need a special tty mode setup (EOL='<').
+
+ TTY setup is:
+ CFLAG (B4800|CS8|CREAD)
+ IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
+ OFLAG (OPOST|ONLCR)
+ LFLAG (ICANON|ECHOK)
+
+ Special flags are:
+ PARSE_F_PPSPPS - use CIOGETEV for PPS time stamping
+ PARSE_F_PPSONSECOND - the time code is not related to
+ the PPS pulse (so use the time code
+ only for the second epoch)
+
+ Timecode
+ 0000000000111111111122222222223333333 / char
+ 0123456789012345678901234567890123456 \ posn
+ >RTMhhmmssdddDDMMYYYYoodnnvrrrrr;*xx< Actual
+ ----33445566600112222BB7__-_____--99- Parse
+ >RTM 1 ;* <", Check
+
+---
+ ELV DCF7000: 127.127.8.12-15
+ ELV DCF7000: end='\r', pattern=" - - - - - - - \r"
+
+ The ELV DCF7000 is a cheap DCF77 receiver sending each second
+ a time code (though not very precise!) delimited by '`r'
+
+ Timecode
+ YY-MM-DD-HH-MM-SS-FF\r
+
+ FF&0x1 - DST
+ FF&0x2 - DST switch warning
+ FF&0x4 - unsynchronised
+
diff --git a/contrib/xntpd/parse/clk_dcf7000.c b/contrib/xntpd/parse/clk_dcf7000.c
index 5655d0a017f0..8b55e2f23280 100644
--- a/contrib/xntpd/parse/clk_dcf7000.c
+++ b/contrib/xntpd/parse/clk_dcf7000.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_DCF7000)
/*
- * /src/NTP/REPOSITORY/v3/parse/clk_dcf7000.c,v 3.10 1994/01/25 19:05:07 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/clk_dcf7000.c,v 3.11 1994/02/02 17:45:14 kardel Exp
*
- * clk_dcf7000.c,v 3.10 1994/01/25 19:05:07 kardel Exp
+ * clk_dcf7000.c,v 3.11 1994/02/02 17:45:14 kardel Exp
*
* ELV DCF7000 module
*
@@ -121,6 +121,9 @@ cvt_dcf7000(buffer, size, format, clock)
* History:
*
* clk_dcf7000.c,v
+ * Revision 3.11 1994/02/02 17:45:14 kardel
+ * rcs ids fixed
+ *
* Revision 3.6 1993/10/09 15:01:27 kardel
* file structure unified
*
diff --git a/contrib/xntpd/parse/clk_meinberg.c b/contrib/xntpd/parse/clk_meinberg.c
index b08dfec91152..69f88b90d30e 100644
--- a/contrib/xntpd/parse/clk_meinberg.c
+++ b/contrib/xntpd/parse/clk_meinberg.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_MEINBERG)
/*
- * /src/NTP/REPOSITORY/v3/parse/clk_meinberg.c,v 3.11 1994/01/25 19:05:10 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/clk_meinberg.c,v 3.14 1994/02/20 13:04:37 kardel Exp
*
- * clk_meinberg.c,v 3.11 1994/01/25 19:05:10 kardel Exp
+ * clk_meinberg.c,v 3.14 1994/02/20 13:04:37 kardel Exp
*
* Meinberg clock support
*
@@ -284,8 +284,13 @@ cvt_meinberg(buffer, size, format, clock)
clock->flags |= PARSEB_S_LEAP;
clock->flags |= PARSEB_S_ANTENNA;
+ /*
+ * DCF77 does not encode the direction -
+ * so we take the current default -
+ * earth slowing down
+ */
if (f[4] == 'A')
- clock->flags |= PARSEB_LEAP;
+ clock->flags |= PARSEB_LEAPADD;
if (f[5] == 'R')
clock->flags |= PARSEB_ALTERNATE;
@@ -394,9 +399,12 @@ cvt_mgps(buffer, size, format, clock)
/*
* oncoming leap second
+ * data format does not (yet) specify whether
+ * to add or to delete a second - thus we
+ * pick the current default
*/
if (f[5] == 'A')
- clock->flags |= PARSEB_LEAP;
+ clock->flags |= PARSEB_LEAPADD;
/*
* this is the leap second
@@ -414,6 +422,12 @@ cvt_mgps(buffer, size, format, clock)
* History:
*
* clk_meinberg.c,v
+ * Revision 3.14 1994/02/20 13:04:37 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.13 1994/02/02 17:45:21 kardel
+ * rcs ids fixed
+ *
* Revision 3.11 1994/01/25 19:05:10 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/clk_rawdcf.c b/contrib/xntpd/parse/clk_rawdcf.c
index 2fd3cae20b89..6b02031b6394 100644
--- a/contrib/xntpd/parse/clk_rawdcf.c
+++ b/contrib/xntpd/parse/clk_rawdcf.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_RAWDCF)
/*
- * /src/NTP/REPOSITORY/v3/parse/clk_rawdcf.c,v 3.9 1994/01/25 19:05:12 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/clk_rawdcf.c,v 3.13 1994/03/10 19:00:43 kardel Exp
*
- * clk_rawdcf.c,v 3.9 1994/01/25 19:05:12 kardel Exp
+ * clk_rawdcf.c,v 3.13 1994/03/10 19:00:43 kardel Exp
*
* Raw DCF77 pulse clock support
*
@@ -245,6 +245,7 @@ static unsigned LONG convert_rawdcf(buffer, size, dcfparam, clock)
parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n"));
clock->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP;
+ clock->utctime= 0;
clock->usecond= 0;
clock->second = 0;
clock->minute = ext_bf(buffer, DCF_M10, dcfparam->zerobits);
@@ -278,7 +279,7 @@ static unsigned LONG convert_rawdcf(buffer, size, dcfparam, clock)
clock->flags |= PARSEB_ANNOUNCE;
if (ext_bf(buffer, DCF_A2, dcfparam->zerobits))
- clock->flags |= PARSEB_LEAP;
+ clock->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */
if (ext_bf(buffer, DCF_R, dcfparam->zerobits))
clock->flags |= PARSEB_ALTERNATE;
@@ -529,6 +530,15 @@ static unsigned LONG snt_rawdcf(parseio, ptime)
* History:
*
* clk_rawdcf.c,v
+ * Revision 3.13 1994/03/10 19:00:43 kardel
+ * clear utctime field to avoid confusion on synthesize time stamps
+ *
+ * Revision 3.12 1994/02/20 13:04:39 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.11 1994/02/02 17:45:23 kardel
+ * rcs ids fixed
+ *
* Revision 3.9 1994/01/25 19:05:12 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/clk_schmid.c b/contrib/xntpd/parse/clk_schmid.c
index a8ec8a64b546..8129474782bb 100644
--- a/contrib/xntpd/parse/clk_schmid.c
+++ b/contrib/xntpd/parse/clk_schmid.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_SCHMID)
/*
- * /src/NTP/REPOSITORY/v3/parse/clk_schmid.c,v 3.10 1994/01/25 19:05:15 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/clk_schmid.c,v 3.13 1994/02/20 13:04:41 kardel Exp
*
- * clk_schmid.c,v 3.10 1994/01/25 19:05:15 kardel Exp
+ * clk_schmid.c,v 3.13 1994/02/20 13:04:41 kardel Exp
*
* Schmid clock support
*
@@ -152,7 +152,7 @@ cvt_schmid(buffer, size, format, clock)
if (buffer[8] & WS_LEAP)
{
- clock->flags |= PARSEB_LEAP;
+ clock->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */
}
}
@@ -168,6 +168,12 @@ cvt_schmid(buffer, size, format, clock)
* History:
*
* clk_schmid.c,v
+ * Revision 3.13 1994/02/20 13:04:41 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.12 1994/02/02 17:45:25 kardel
+ * rcs ids fixed
+ *
* Revision 3.10 1994/01/25 19:05:15 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/clk_trimble.c b/contrib/xntpd/parse/clk_trimble.c
index bfbf1e6bc796..187aed52a4d7 100644
--- a/contrib/xntpd/parse/clk_trimble.c
+++ b/contrib/xntpd/parse/clk_trimble.c
@@ -1,6 +1,6 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_TRIMSV6)
/*
- * /src/NTP/REPOSITORY/v3/parse/clk_trimble.c,v 3.7 1994/01/25 19:05:17 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/clk_trimble.c,v 3.9 1994/02/02 17:45:27 kardel Exp
*
* Trimble SV6 clock support
*/
@@ -106,6 +106,9 @@ cvt_trimsv6(buffer, size, format, clock)
* History:
*
* clk_trimble.c,v
+ * Revision 3.9 1994/02/02 17:45:27 kardel
+ * rcs ids fixed
+ *
* Revision 3.7 1994/01/25 19:05:17 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/parse.c b/contrib/xntpd/parse/parse.c
index ed5fd9a8fad7..84bfa39d1293 100644
--- a/contrib/xntpd/parse/parse.c
+++ b/contrib/xntpd/parse/parse.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
/*
- * /src/NTP/REPOSITORY/v3/parse/parse.c,v 3.19 1994/01/25 19:05:20 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/parse.c,v 3.23 1994/03/25 13:09:02 kardel Exp
*
- * parse.c,v 3.19 1994/01/25 19:05:20 kardel Exp
+ * parse.c,v 3.23 1994/03/25 13:09:02 kardel Exp
*
* Parser module for reference clock
*
@@ -29,6 +29,10 @@ static char rcsid[] = "parse.c,v 3.19 1994/01/25 19:05:20 kardel Exp";
#include "sys/time.h"
#include "sys/errno.h"
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+
#include "ntp_machine.h"
#if defined(PARSESTREAM) && (defined(SYS_SUNOS4) || defined(SYS_SOLARIS)) && defined(STREAM)
@@ -49,10 +53,6 @@ static char rcsid[] = "parse.c,v 3.19 1994/01/25 19:05:20 kardel Exp";
#endif
#endif
-#include "ntp_fp.h"
-#include "ntp_unixtime.h"
-#include "ntp_calendar.h"
-
#include "parse.h"
#include "ntp_stdlib.h"
@@ -178,6 +178,10 @@ setup_bitmaps(parseio, low, high)
{
fmt = clockformats[i];
+ if (!(parseio->parse_flags & PARSE_FIXED_FMT) &&
+ (fmt->flags & CVT_FIXEDONLY))
+ continue;
+
if (fmt->flags & F_START)
{
index = fmt->startsym / 8;
@@ -556,6 +560,9 @@ parse_to_unixtime(clock, cvtrtc)
register int i;
time_t t;
+ if (clock->utctime)
+ return clock->utctime; /* if the conversion routine gets it right away - why not */
+
if (clock->year < 100)
clock->year += 1900;
@@ -628,6 +635,9 @@ parse_to_unixtime(clock, cvtrtc)
t += clock->utcoffset; /* warp to UTC */
/* done */
+
+ clock->utctime = t; /* documentray only */
+
return t;
}
@@ -890,6 +900,8 @@ timepacket(parseio)
if (parseio->parse_flags & PARSE_FIXED_FMT)
{
+ clock.utctime = 0;
+
switch ((cvtrtc = clockformats[format]->convert ? clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock) : CVT_NONE) & CVT_MASK)
{
case CVT_FAIL:
@@ -941,6 +953,8 @@ timepacket(parseio)
{
do
{
+ clock.utctime = 0;
+
switch ((cvtrtc = (clockformats[format]->convert && !(clockformats[format]->flags & CVT_FIXEDONLY)) ?
clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock) :
CVT_NONE) & CVT_MASK)
@@ -1148,6 +1162,15 @@ parse_setcs(dct, parse)
* History:
*
* parse.c,v
+ * Revision 3.23 1994/03/25 13:09:02 kardel
+ * considering FIXEDONLY entries only in FIXEDONLY mode
+ *
+ * Revision 3.22 1994/02/25 12:34:49 kardel
+ * allow for converter generated utc times
+ *
+ * Revision 3.21 1994/02/02 17:45:30 kardel
+ * rcs ids fixed
+ *
* Revision 3.19 1994/01/25 19:05:20 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/parse_conf.c b/contrib/xntpd/parse/parse_conf.c
index 0281c9dd1071..238dd1234e66 100644
--- a/contrib/xntpd/parse/parse_conf.c
+++ b/contrib/xntpd/parse/parse_conf.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
/*
- * /src/NTP/REPOSITORY/v3/parse/parse_conf.c,v 3.13 1994/01/25 19:05:23 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/parse_conf.c,v 3.15 1994/02/02 17:45:32 kardel Exp
*
- * parse_conf.c,v 3.13 1994/01/25 19:05:23 kardel Exp
+ * parse_conf.c,v 3.15 1994/02/02 17:45:32 kardel Exp
*
* Parser configuration module for reference clocks
*
@@ -81,6 +81,9 @@ unsigned short nformats = sizeof(clockformats) / sizeof(clockformats[0]) - 1;
* History:
*
* parse_conf.c,v
+ * Revision 3.15 1994/02/02 17:45:32 kardel
+ * rcs ids fixed
+ *
* Revision 3.13 1994/01/25 19:05:23 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/parsesolaris.c b/contrib/xntpd/parse/parsesolaris.c
index 09fac2861f0c..23bc252e8fce 100644
--- a/contrib/xntpd/parse/parsesolaris.c
+++ b/contrib/xntpd/parse/parsesolaris.c
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/v3/parse/parsesolaris.c,v 3.9 1994/01/25 19:05:26 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/parsesolaris.c,v 3.15 1994/02/15 22:20:51 kardel Exp
*
- * parsesolaris.c,v 3.9 1994/01/25 19:05:26 kardel Exp
+ * parsesolaris.c,v 3.15 1994/02/15 22:20:51 kardel Exp
*
* STREAMS module for reference clocks
* (SunOS5.x - not fully tested - buyer beware ! - OS KILLERS may still be
@@ -19,7 +19,7 @@
*/
#ifndef lint
-static char rcsid[] = "parsesolaris.c,v 3.9 1994/01/25 19:05:26 kardel Exp";
+static char rcsid[] = "parsesolaris.c,v 3.15 1994/02/15 22:20:51 kardel Exp";
#endif
/*
@@ -65,7 +65,7 @@ static struct fmodsw fmod_templ =
{
"parse", /* module name */
&parseinfo, /* module information */
- 0, /* not clean yet */
+ D_NEW|D_MP|D_MTQPAIR, /* exclusive for q pair */
/* lock ptr */
};
@@ -139,7 +139,7 @@ int Strcmp(s, t)
/*ARGSUSED*/
int _init(void)
{
- static char revision[] = "3.9";
+ static char revision[] = "3.15";
char *s, *S, *t;
/*
@@ -413,6 +413,8 @@ static int parseopen(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *credp)
parse->parse_ppsclockev.tv.tv_usec = 0;
parse->parse_ppsclockev.serial = 0;
+ qprocson(q);
+
parseprintf(DD_OPEN,("parse: OPEN - initializing io subsystem q=%x\n", q));
if (!parse_ioinit(&parse->parse_io))
@@ -420,6 +422,8 @@ static int parseopen(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *credp)
/*
* ok guys - beat it
*/
+ qprocsoff(q);
+
kmem_free((caddr_t)parse, sizeof(parsestream_t));
parsebusy--;
@@ -441,7 +445,7 @@ static int parseopen(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *credp)
*/
if (!notice)
{
- printf("%s: Copyright (c) 1991-1993, Frank Kardel\n", modlstrmod.strmod_linkinfo);
+ printf("%s: Copyright (c) 1991-1994, Frank Kardel\n", modlstrmod.strmod_linkinfo);
notice = 1;
}
@@ -449,7 +453,12 @@ static int parseopen(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *credp)
}
else
{
+ qprocsoff(q);
+
+ kmem_free((caddr_t)parse, sizeof(parsestream_t));
+
parsebusy--;
+
return EIO;
}
}
@@ -462,6 +471,8 @@ static int parseclose(queue_t *q, int flags)
parseprintf(DD_CLOSE,("parse: CLOSE\n"));
+ qprocsoff(q);
+
s = splhigh();
if (parse->parse_dqueue)
@@ -1179,6 +1190,18 @@ static void zs_xsisr(struct zscom *zs)
* History:
*
* parsesolaris.c,v
+ * Revision 3.15 1994/02/15 22:20:51 kardel
+ * rcsid fixed
+ *
+ * Revision 3.14 1994/02/15 22:06:04 kardel
+ * added qprocsx & flags for MT capability
+ *
+ * Revision 3.13 1994/02/13 19:16:47 kardel
+ * updated verbose Copyright message
+ *
+ * Revision 3.12 1994/02/02 17:45:35 kardel
+ * rcs ids fixed
+ *
* Revision 3.9 1994/01/25 19:05:26 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/parsestreams.c b/contrib/xntpd/parse/parsestreams.c
index b371aedafcee..45d296337a69 100644
--- a/contrib/xntpd/parse/parsestreams.c
+++ b/contrib/xntpd/parse/parsestreams.c
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/v3/parse/parsestreams.c,v 3.12 1994/01/25 19:05:30 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/parsestreams.c,v 3.19 1994/02/24 16:33:54 kardel Exp
*
- * parsestreams.c,v 3.12 1994/01/25 19:05:30 kardel Exp
+ * parsestreams.c,v 3.19 1994/02/24 16:33:54 kardel Exp
*
* STREAMS module for reference clocks
* (SunOS4.x)
@@ -16,7 +16,7 @@
*/
#ifndef lint
-static char rcsid[] = "parsestreams.c,v 3.12 1994/01/25 19:05:30 kardel Exp";
+static char rcsid[] = "parsestreams.c,v 3.19 1994/02/24 16:33:54 kardel Exp";
#endif
#include "sys/types.h"
@@ -195,7 +195,7 @@ int xxxinit(fc, vdp, vdi, vds)
}
else
{
- static char revision[] = "3.12";
+ static char revision[] = "3.19";
char *s, *S, *t;
strncpy(ifm->f_name, mname, FMNAMESZ);
@@ -527,7 +527,7 @@ static int parseopen(q, dev, flag, sflag)
*/
if (!notice)
{
- printf("%s: Copyright (c) 1991-1993, Frank Kardel\n", parsesync_vd.Drv_name);
+ printf("%s: Copyright (c) 1991-1994, Frank Kardel\n", parsesync_vd.Drv_name);
notice = 1;
}
@@ -535,6 +535,8 @@ static int parseopen(q, dev, flag, sflag)
}
else
{
+ kmem_free((caddr_t)parse, sizeof(parsestream_t));
+
#ifdef VDDRV
parsebusy--;
#endif
@@ -1074,6 +1076,11 @@ static void close_zs_linemon(q, my_q)
#define MAXDEPTH 50 /* maximum allowed stream crawl */
+#ifdef PPS_SYNC
+extern hardpps();
+extern struct timeval time;
+#endif
+
/*
* take external status interrupt (only CD interests us)
*/
@@ -1085,15 +1092,18 @@ static void zs_xsisr(zs)
register queue_t *q;
register unsigned char zsstatus;
register int loopcheck;
- register unsigned char cdstate;
register char *dname;
+#ifdef PPS_SYNC
+ register int s;
+ register long usec;
+#endif
/*
* pick up current state
*/
zsstatus = zsaddr->zscc_control;
- if (za->za_rr0 ^ (cdstate = zsstatus & ZSRR0_CD))
+ if ((za->za_rr0 ^ zsstatus) & (ZSRR0_CD|ZSRR0_SYNC))
{
timestamp_t cdevent;
register int status;
@@ -1101,26 +1111,44 @@ static void zs_xsisr(zs)
/*
* CONDITIONAL external measurement support
*/
- SET_LED(cdstate); /*
+ SET_LED(zsstatus & (ZSRR0_CD|ZSRR0_SYNC)); /*
* inconsistent with upper SET_LED, but this
* is for oscilloscope business anyway and we
* are just interested in edge delays in the
* lower us range
*/
-
+#ifdef PPS_SYNC
+ s = splclock();
+ usec = time.tv_usec;
+#endif
/*
* time stamp
*/
uniqtime(&cdevent.tv);
-
- TIMEVAL_USADD(&cdevent.tv, xsdelay);
-
- q = za->za_ttycommon.t_readq;
+
+#ifdef PPS_SYNC
+ splx(s);
+#endif
/*
* logical state
*/
- status = cd_invert ? cdstate == 0 : cdstate != 0;
+ status = cd_invert ? (zsstatus & (ZSRR0_CD|ZSRR0_SYNC)) == 0 : (zsstatus & (ZSRR0_CD|ZSRR0_SYNC)) != 0;
+
+#ifdef PPS_SYNC
+ if (status)
+ {
+ usec = cdevent.tv.tv_usec - usec;
+ if (usec < 0)
+ usec += 1000000;
+
+ hardpps(&cdevent.tv, usec);
+ }
+#endif
+
+ TIMEVAL_USADD(&cdevent.tv, xsdelay);
+
+ q = za->za_ttycommon.t_readq;
/*
* ok - now the hard part - find ourself
@@ -1177,10 +1205,10 @@ static void zs_xsisr(zs)
/*
* only pretend that CD has been handled
*/
- za->za_rr0 = za->za_rr0 & ~ZSRR0_CD | zsstatus & ZSRR0_CD;
+ za->za_rr0 = za->za_rr0 & ~(ZSRR0_CD|ZSRR0_SYNC) | zsstatus & (ZSRR0_CD|ZSRR0_SYNC);
ZSDELAY(2);
- if (!((za->za_rr0 ^ zsstatus) & ~ZSRR0_CD))
+ if (!((za->za_rr0 ^ zsstatus) & ~(ZSRR0_CD|ZSRR0_SYNC)))
{
/*
* all done - kill status indication and return
@@ -1258,6 +1286,24 @@ static void zs_xsisr(zs)
* History:
*
* parsestreams.c,v
+ * Revision 3.19 1994/02/24 16:33:54 kardel
+ * CD events can also be posted on sync flag
+ *
+ * Revision 3.18 1994/02/24 14:12:58 kardel
+ * initial PPS_SYNC support version
+ *
+ * Revision 3.17 1994/02/20 15:18:02 kardel
+ * rcs id cleanup
+ *
+ * Revision 3.16 1994/02/15 22:39:50 kardel
+ * memory leak on open failure closed
+ *
+ * Revision 3.15 1994/02/13 19:16:50 kardel
+ * updated verbose Copyright message
+ *
+ * Revision 3.14 1994/02/02 17:45:38 kardel
+ * rcs ids fixed
+ *
* Revision 3.12 1994/01/25 19:05:30 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/parse/util/parsetest.c b/contrib/xntpd/parse/util/parsetest.c
index 9028b4cf4cf4..21e41289a1c6 100644
--- a/contrib/xntpd/parse/util/parsetest.c
+++ b/contrib/xntpd/parse/util/parsetest.c
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/v3/kernel/parsetest.c,v 3.4 1993/03/17 17:16:57 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/util/parsetest.c,v 3.13 1994/02/20 13:04:46 kardel Exp
*
- * parsetest.c,v 3.10 1994/01/23 17:22:18 kardel Exp
+ * parsetest.c,v 3.13 1994/02/20 13:04:46 kardel Exp
*
* Copyright (c) 1989,1990,1991,1992,1993,1994
* Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
@@ -11,15 +11,11 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* parsetest.c,v
- * Revision 3.4 1993/03/17 17:16:57 kardel
- * DEC OSF/1 ALPHA Integration - 930314
+ * Revision 3.13 1994/02/20 13:04:46 kardel
+ * parse add/delete second support
*
- * Revision 3.3 1993/01/18 09:24:33 kardel
- * updated copyright conditions in conjunction with
- * conditions set up in the COPYRIGHT file
- *
- * Revision 3.2 1993/01/17 13:43:00 kardel
- * 1993 initial update
+ * Revision 3.12 1994/02/02 17:45:51 kardel
+ * rcs ids fixed
*
*/
@@ -198,7 +194,7 @@ main(argc, argv)
parsetime_t parsetime;
struct strioctl strioc;
- printf("parsetest.c,v 3.10 1994/01/23 17:22:18 kardel Exp\n");
+ printf("parsetest.c,v 3.13 1994/02/20 13:04:46 kardel Exp\n");
while (ioctl(fd, I_POP, 0) == 0)
;
diff --git a/contrib/xntpd/parse/util/testdcf.c b/contrib/xntpd/parse/util/testdcf.c
index ebdfd2fded07..560ab27c4369 100644
--- a/contrib/xntpd/parse/util/testdcf.c
+++ b/contrib/xntpd/parse/util/testdcf.c
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/v3/parse/util/testdcf.c,v 3.9 1994/01/25 19:05:45 kardel Exp
+ * /src/NTP/REPOSITORY/v3/parse/util/testdcf.c,v 3.11 1994/02/02 17:45:55 kardel Exp
*
- * testdcf.c,v 3.9 1994/01/25 19:05:45 kardel Exp
+ * testdcf.c,v 3.11 1994/02/02 17:45:55 kardel Exp
*
* simple DCF77 100/200ms pulse test program (via 50Baud serial line)
*
diff --git a/contrib/xntpd/ppsclock/ppstest/.keep_me b/contrib/xntpd/ppsclock/ppstest/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/ppstest/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/genassym/.keep_me b/contrib/xntpd/ppsclock/sys/genassym/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/genassym/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/os/.keep_me b/contrib/xntpd/ppsclock/sys/os/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/os/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sun/.keep_me b/contrib/xntpd/ppsclock/sys/sun/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sun/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sun4c/.keep_me b/contrib/xntpd/ppsclock/sys/sun4c/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sun4c/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me b/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me b/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sundev/.keep_me b/contrib/xntpd/ppsclock/sys/sundev/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sundev/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/ppsclock/sys/sys/.keep_me b/contrib/xntpd/ppsclock/sys/sys/.keep_me
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/contrib/xntpd/ppsclock/sys/sys/.keep_me
+++ /dev/null
diff --git a/contrib/xntpd/refclocks/rclk.TRAK b/contrib/xntpd/refclocks/rclk.TRAK
new file mode 100644
index 000000000000..188ffd4445bc
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.TRAK
@@ -0,0 +1,29 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " TRAK - TRAK 8810 GPS station clock"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /TRAK/'; then
+ echo "TRAK - TRAK 8810 GPS station clock"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /TRAK/' ||
+ ( [ ! "$REFCONF" ] && query "Include TRAK 8810 GPS station clock (TRAK)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /TRAKPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use TRAK for PPS" n)); then
+ echo "-DTRAKPPS" >> $RCONFIG
+ else
+ echo "-DTRAK" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/scripts/Guess.sh b/contrib/xntpd/scripts/Guess.sh
index c2be5697eab7..88dcb1a5ef86 100755
--- a/contrib/xntpd/scripts/Guess.sh
+++ b/contrib/xntpd/scripts/Guess.sh
@@ -40,7 +40,11 @@ if [ -f /bin/uname -o -f /usr/bin/uname ]; then
guess="ultrix"
;;
hp-ux) case "$3" in
- *.10.*) guess="hpux10+" ;;
+ *.10.*) guess="hpux-adj" ;;
+ *.09.03) case "$5" in
+ 9000/3*) guess="hpux-adj" ;;
+ *) guess="hpux" ;;
+ esac ;;
*) guess="hpux" ;;
esac
;;
@@ -74,7 +78,7 @@ if [ -f /bin/uname -o -f /usr/bin/uname ]; then
3.2.*)
case "$4" in
v*)
- (i386) >/dev/null 2>&1 && guess=ptx;;
+ (i386) >/dev/null 2>&1 && [ -f /usr/lib/libseq.a ] && guess=ptx;;
esac
esac
fi
diff --git a/contrib/xntpd/scripts/README b/contrib/xntpd/scripts/README
index 79f1792a43d4..7439c6c6c498 100644
--- a/contrib/xntpd/scripts/README
+++ b/contrib/xntpd/scripts/README
@@ -11,7 +11,7 @@ Guess.sh script to figure out what machine and operating system
autoconf awesome script swiped from Jeff Johnson (who may have
swiped it from GNU) which delves deep into the system
files to reveal dark secrets necessary to port NTP to
- everything exceptt sewing machines. Unfinished work.
+ everything except sewing machines. Unfinished work.
makeconfig.sh shell script that calles Guess.sh and then figures out
what compiler is available, then builds the
diff --git a/contrib/xntpd/scripts/stats/README b/contrib/xntpd/scripts/stats/README
index 5aa64d4c1db9..680896342acb 100644
--- a/contrib/xntpd/scripts/stats/README
+++ b/contrib/xntpd/scripts/stats/README
@@ -3,20 +3,27 @@ Statistics processing scripts (README)
This directory contains a number of scripts for use with the filegen
facility. Those files ending in .awk are for the Unix awk utility, while
those ending in .sh are for the csh utility. Normally, the summary.sh
-script is called from a cron job once per day. This script calls the
-peer.sh script to process the peerstats file and append the summary
-statistics to the peer_summary file. Then, it callse the loop.sh script
-to process the loopstats file and append the summary statistics to the
-loop_summary file. Finally, it calls the clock.sh script to process the
-clockstats file and append the summary statistics to the clock_summary
-file.
+script is called from a cron job once per day. This script processes the
+daily loopstats, peerstats and clockstats files produced by the daemon,
+updates the loop_summary, peer_summary and clock_summary archive files,
+and deletes the daily files.
-Each of the three shell scripts peer.sh, loop.sh and clock.sh invoke
-one or more awk scripts to actually produce the data. This may result
-in multiple scans of the same input file. The input file is deleted after
-processing. In fact, the shell scripts will process all input files
-found of the correct type in chronological order, deleting each one as
-it is scanned, except the current day file.
+In the case of the Austron 2201A GPS receiver, the clockstats file
+contains a wealth of additional monitoring data. These data are summarized
+and writted to the clock_summary file, then a series of special files are
+constructed for later processing by the S utility.
+
+The summary.sh script invokes a number of awk scripts to actually produce
+the data. This may result in multiple scans of the same input file.
+The input file is deleted after processing. In fact, the shell scripts will
+process all input files found of the correct type in chronological order,
+deleting each one as it is scanned, except the current day file.
+
+The summary.sh script can produce input files for the S utility, if it
+is found on the search path. This utility makes PostScript graphs of the
+loopstats data for each day, as well as various statistics produced by
+the Austorn 220aA GPS receiver. The S utility is automatically run
+as a background job. Its control files have the .S extension.
The psummary.awk script can be used to scan the peer_summary file and
construct an historical reprise of the daily summaries.
@@ -29,4 +36,4 @@ David L. Mills
University of Delaware
mills@udel.edu
1 November 1993
-
+Revised 12 April 1994
diff --git a/contrib/xntpd/scripts/stats/dupe.awk b/contrib/xntpd/scripts/stats/dupe.awk
index 3ddc1b6f9754..317c2a4faf84 100644
--- a/contrib/xntpd/scripts/stats/dupe.awk
+++ b/contrib/xntpd/scripts/stats/dupe.awk
@@ -1,4 +1,5 @@
-# program to delete duplicate lines in a file
+#
+# delete duplicate lines
#
{
if (old != $0)
diff --git a/contrib/xntpd/scripts/stats/ensemble.S b/contrib/xntpd/scripts/stats/ensemble.S
new file mode 100644
index 000000000000..32a4dbabb820
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/ensemble.S
@@ -0,0 +1,5 @@
+ensemble <- scan(file1, list(day=0, sec=0, gps=0, gpsw=0, loran=0, loranw=0, ensemble=0, std=0))
+str <- paste("eps/", file1, ".eps", sep="")
+postscript(str, , , , 5, pointsize=18)
+par(mgp=c(1, 0, 0), tck = 0.03, mar = c(2, 2, 1, 1))
+plot(ensemble$sec, ensemble$ensemble, type="l", xlab=paste("MJD", ensemble$day, "Time (s)"), ylab="Ensemble Offset (ns)", ylim=c(-400, 400))
diff --git a/contrib/xntpd/scripts/stats/etf.S b/contrib/xntpd/scripts/stats/etf.S
new file mode 100644
index 000000000000..9b9c68b937b5
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/etf.S
@@ -0,0 +1,15 @@
+options(digits=4)
+file2 <- "etf_summary"
+etf <- scan(file1, list(day=0, sec=0, offset=0, stab=0))
+r <- lsfit(etf$sec, etf$offset)
+count<-length(etf$sec)
+mean<-r$coef[[1]]
+std<-sqrt(var(r$residuals))
+slope<-r$coef[[2]] * 1000
+cat("\n", file=file2 , append=TRUE, fill=FALSE, sep="")
+cat(file1, "\n", file=file2, append=TRUE, fill=FALSE, sep="")
+cat("etf1 ", count, ", T ", mean, " ns, R ", slope, " ps/s, std ", std, " us\n", file=file2, append=TRUE, fill=FALSE, sep="")
+str <- paste("eps/", file1, ".eps", sep="")
+postscript(str, , , , 5, pointsize=18)
+par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1))
+plot(etf$sec, etf$offset, type="l", xlab=paste("MJD", etf$day, "Time (s)"), ylab="External Offset (ns)", ylim=c(-400, 400))
diff --git a/contrib/xntpd/scripts/stats/itf.S b/contrib/xntpd/scripts/stats/itf.S
new file mode 100644
index 000000000000..56c8c8d0cc7a
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/itf.S
@@ -0,0 +1,5 @@
+itf <- scan(file1, list(day=0, sec=0, offset=0, stab=0))
+str <- paste("eps/", file1, ".eps", sep="")
+postscript(str, , , , 5, pointsize=18)
+par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1))
+plot(itf$sec, itf$offset, type="l", xlab=paste("MJD", itf$day, "Time (s)"), ylab="Internal Offset (ns)", ylim=c(-400, 400))
diff --git a/contrib/xntpd/scripts/stats/loop.S b/contrib/xntpd/scripts/stats/loop.S
new file mode 100644
index 000000000000..8e564b67eb67
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/loop.S
@@ -0,0 +1,7 @@
+options(digits=4)
+loop <- scan(file1, list(day=0, sec=0, offset=0, freq=0, tc=0))
+loop$offset <- loop$offset * 1e6
+str <- paste("eps/", file1, ".eps", sep="")
+postscript(str, , , , 5, pointsize=18)
+par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1))
+plot(loop$sec, loop$offset, type="l", xlab=paste("MJD", loop$day, "Time (s)"), ylab="PLL Offset (us)", ylim=c(-400, 400))
diff --git a/contrib/xntpd/scripts/stats/loop.awk b/contrib/xntpd/scripts/stats/loop.awk
index 25d0bdb97d53..470b27c8bef5 100644
--- a/contrib/xntpd/scripts/stats/loop.awk
+++ b/contrib/xntpd/scripts/stats/loop.awk
@@ -35,15 +35,7 @@ BEGIN {
loop_time_rms = sqrt(loop_time_rms / loop_count - loop_time * loop_time)
loop_freq /= loop_count
loop_freq_rms = sqrt(loop_freq_rms / loop_count - loop_freq * loop_freq)
- loop_tmax = loop_tmax - loop_time
- loop_tmin = loop_time - loop_tmin
- if (loop_tmin > loop_tmax)
- loop_tmax = loop_tmin
- loop_fmax = loop_fmax - loop_freq
- loop_fmin = loop_time - loop_fmin
- if (loop_fmin > loop_fmax)
- loop_fmax = loop_fmin
- printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, rms %.3f\n", loop_count, loop_time * 1e6, loop_tmax * 1e6, loop_time_rms * 1e6, loop_freq, loop_fmax, loop_freq_rms
+ printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", loop_count, (loop_tmax + loop_tmin) / 2 * 1e6, (loop_tmax - loop_tmin) / 2 * 1e6, loop_time_rms * 1e6, (loop_fmax + loop_fmin) / 2, (loop_fmax - loop_fmin) / 2, loop_freq_rms
}
}
diff --git a/contrib/xntpd/scripts/stats/psummary.awk b/contrib/xntpd/scripts/stats/psummary.awk
index b7f0e922a7d6..5ef8d8eb5280 100644
--- a/contrib/xntpd/scripts/stats/psummary.awk
+++ b/contrib/xntpd/scripts/stats/psummary.awk
@@ -1,5 +1,7 @@
# program to scan peer_summary file and produce summary of daily summaries
#
+# usage: awk -f psummary.awk peer_summary
+#
{
if (NF < 8 || $1 == "ident")
continue
diff --git a/contrib/xntpd/scripts/stats/rms.awk b/contrib/xntpd/scripts/stats/rms.awk
new file mode 100644
index 000000000000..34d612ab3582
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/rms.awk
@@ -0,0 +1,41 @@
+# program to scan peer_summary file
+#
+{
+ if (NF < 8 || $1 == "ident")
+ continue
+ i = n
+ for (j = 0; j < n; j++) {
+ if ($1 == peer_ident[j])
+ i = j
+ }
+ if (i == n) {
+ peer_ident[i] = $1
+ n++
+ }
+ peer_count[i]++
+ if (($7 - $6 / 2) < 400) {
+ peer_count[i]++
+ peer_mean[i] += $3
+ peer_var[i] += $4 * $4
+ if ($5 > peer_max[i])
+ peer_max[i] = $5
+ if ($5 > 1)
+ peer_1[i]++
+ if ($5 > 5)
+ peer_2[i]++
+ if ($5 > 10)
+ peer_3[i]++
+ if ($5 > 50)
+ peer_4[i]++
+ }
+} END {
+ printf " host cnt mean sd max >1 >5 >10 >50\n"
+ printf "=================================================================\n"
+ for (i = 0; i < n; i++) {
+ if (peer_count[i] <= 0)
+ continue
+ peer_mean[i] /= peer_count[i]
+ peer_var[i] = sqrt(peer_var[i] / peer_count[i])
+ printf "%15s%4d%10.3f%10.3f%10.3f%4d%4d%4d%4d\n", peer_ident[i], peer_count[i], peer_mean[i], peer_var[i], peer_max[i], peer_1[i], peer_2[i], peer_3[i], peer_4[i]
+ }
+}
diff --git a/contrib/xntpd/scripts/stats/summary.sh b/contrib/xntpd/scripts/stats/summary.sh
index ab99f4d8e8d5..caac2b0c3bec 100755
--- a/contrib/xntpd/scripts/stats/summary.sh
+++ b/contrib/xntpd/scripts/stats/summary.sh
@@ -1,17 +1,88 @@
-#!/bin/csh
+#!/bin/sh
#
# Script to summarize ipeerstats, loopstats and clockstats files
#
# This script can be run from a cron job once per day, week or month. It
# runs the file-specific summary script and appends the summary data to
-# designated files, which must be created first.
-#
-if ( -e peer_summary ) then
- peer.sh >>peer_summary
-endif
-if ( -e loop_summary ) then
- loop.sh >>loop_summary
-endif
-if ( -e clock_summary ) then
- clock.sh >>clock_summary
-endif
+# designated files.
+#
+DATE=`date +19%y%m%d`
+SIN=S.in
+SOUT=S.out
+LOOP=loop_summary
+PEER=peer_summary
+CLOCK=clock_summary
+
+rm -f $SIN $SOUT
+S=0
+if [ -f `which S | cut -f1 -d" "` ]; then
+ S=1
+fi
+#
+# Summarize loopstats files
+#
+for f in loopstats.????????; do
+ d=`echo $f | cut -f2 -d.`
+ if [ $DATE != $d ]; then
+ echo " " >>$LOOP
+ echo $f >>$LOOP
+ awk -f loop.awk $f >>$LOOP
+ if [ $S ]; then
+ echo "file1<-"\"${f}\" >>$SIN
+ echo "source("\""loop.S"\"")" >>$SIN
+ fi
+ rm -f $f
+ fi
+done
+
+#
+# Summarize peerstats files
+#
+for f in peerstats.????????; do
+ d=`echo $f | cut -f2 -d.`
+ if [ $DATE != $d ]; then
+ echo " " >>$PEER
+ echo $f >>$PEER
+ awk -f peer.awk $f >>$PEER
+ rm -f $f
+ fi
+done
+
+#
+# Summarize clockstats files
+#
+for f in clockstats.????????; do
+ d=`echo $f | cut -f2 -d.`
+ if [ $DATE != $d ]; then
+ echo " " >>$CLOCK
+ echo $f >>$CLOCK
+ awk -f clock.awk $f >>$CLOCK
+ if [ -f /dev/gps* ]; then
+ awk -f itf.awk $f >itf.$d
+ awk -f etf.awk $f >etf.$d
+ awk -f ensemble.awk $f >ensemble.$d
+ awk -f tdata.awk $f >tdata.$d
+ fi
+ rm -f $f
+ fi
+done
+
+#
+# Process clockstat files with S and generate PostScript plots
+#
+for f in itf etf ensemble tdata; do
+ for d in ${f}.????????; do
+ if [ -f $d ]; then
+ if [ $S ]; then
+ echo "file1<-"\"${d}\" >>$SIN
+ echo "source("\"${f}.S\"")" >>$SIN
+ echo "unix("\""rm ${d}"\"")" >>$SIN
+ else
+ rm -f $d
+ fi
+ fi
+ done
+done
+if [ -f $SIN ]; then
+ S BATCH $SIN $SOUT
+fi
diff --git a/contrib/xntpd/scripts/stats/tdata.S b/contrib/xntpd/scripts/stats/tdata.S
new file mode 100644
index 000000000000..f360a248c06a
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/tdata.S
@@ -0,0 +1,5 @@
+tdata <- scan(file1, list(day=0, sec=0, m=0, w=0, x=0, y=0, z=0))
+str <- paste("eps/", file1, ".eps", sep="")
+postscript(str, , , , 5, pointsize=18)
+par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1))
+plot(tdata$sec, tdata$m, type="l", xlab=paste("MJD", tdata$day, "Time (s)"), ylab="LORAN-M SNR (dB)")
diff --git a/contrib/xntpd/scripts/support/bin/monl b/contrib/xntpd/scripts/support/bin/monl
index 44201d0d0f99..f0c48dbf5f3f 100755
--- a/contrib/xntpd/scripts/support/bin/monl
+++ b/contrib/xntpd/scripts/support/bin/monl
@@ -143,7 +143,8 @@ foreach $hostname (@ARGV)
{
chop;
split;
- ($host, $count, $mode, $version, $lasttime, $firsttime) = (@_[$[, $[+2 .. $[+6]);
+ ($host, $count, $mode, $version, $lasttime, $firsttime) =
+ (@_[$[, $[+2 .. $[+4, $#_-1,$#_]);
$Seen{$host, $mode} = 1;
diff --git a/contrib/xntpd/util/ntptime.c b/contrib/xntpd/util/ntptime.c
index c0512df90a87..858fe7cba481 100644
--- a/contrib/xntpd/util/ntptime.c
+++ b/contrib/xntpd/util/ntptime.c
@@ -15,27 +15,29 @@
#include <signal.h>
#include <errno.h>
-#include <sys/syscall.h>
-
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#ifndef SYS_DECOSF1
#define BADCALL -1 /* this is supposed to be a bad syscall */
-#endif
-#include "ntp_timex.h"
+#endif /* SYS_DECOSF1 */
-#ifdef KERNEL_PLL
-#ifndef SYS_ntp_adjtime
+#ifdef KERNEL_PLL
+#include <sys/timex.h>
+#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
+#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
+#else /* KERNEL_PLL */
+#include "ntp_timex.h"
#define SYS_ntp_adjtime NTP_SYSCALL_ADJ
-#endif
-#ifndef SYS_ntp_gettime
#define SYS_ntp_gettime NTP_SYSCALL_GET
-#endif
-#endif /* KERNEL_PLL */
+#endif /* KERNEL_PLL */
+/*
+ * Function prototypes
+ */
extern int sigvec P((int, struct sigvec *, struct sigvec *));
+extern int syscall P((int, void *, ...));
void pll_trap P((void));
static struct sigvec newsigsys; /* new sigvec status */
@@ -56,50 +58,50 @@ main(argc, argv)
struct ntptimeval ntv;
struct timex ntx, _ntx;
int times[20];
- double ftemp;
+ double ftemp, gtemp;
l_fp ts;
int c;
int errflg = 0;
int cost = 0;
int rawtime = 0;
- ntx.mode = 0;
+ memset((char *)&ntx, 0, sizeof(ntx));
progname = argv[0];
while ((c = ntp_getopt(argc, argv, optargs)) != EOF) switch (c) {
case 'c':
cost++;
break;
case 'e':
- ntx.mode |= ADJ_ESTERROR;
+ ntx.modes |= MOD_ESTERROR;
ntx.esterror = atoi(ntp_optarg);
break;
case 'f':
- ntx.mode |= ADJ_FREQUENCY;
- ntx.frequency = (int) (atof(ntp_optarg)
- * (1 << SHIFT_USEC));
- if (ntx.frequency < (-100 << SHIFT_USEC)
- || ntx.frequency > ( 100 << SHIFT_USEC)) errflg++;
+ ntx.modes |= MOD_FREQUENCY;
+ ntx.freq = (int) (atof(ntp_optarg) *
+ (1 << SHIFT_USEC));
+ if (ntx.freq < (-100 << SHIFT_USEC)
+ || ntx.freq > ( 100 << SHIFT_USEC)) errflg++;
break;
case 'm':
- ntx.mode |= ADJ_MAXERROR;
+ ntx.modes |= MOD_MAXERROR;
ntx.maxerror = atoi(ntp_optarg);
break;
case 'o':
- ntx.mode |= ADJ_OFFSET;
+ ntx.modes |= MOD_OFFSET;
ntx.offset = atoi(ntp_optarg);
break;
case 'r':
rawtime++;
break;
case 's':
- ntx.mode |= ADJ_STATUS;
+ ntx.modes |= MOD_STATUS;
ntx.status = atoi(ntp_optarg);
if (ntx.status < 0 || ntx.status > 4) errflg++;
break;
case 't':
- ntx.mode |= ADJ_TIMECONST;
- ntx.time_constant = atoi(ntp_optarg);
- if (ntx.time_constant < 0 || ntx.time_constant > MAXTC)
+ ntx.modes |= MOD_TIMECONST;
+ ntx.constant = atoi(ntp_optarg);
+ if (ntx.constant < 0 || ntx.constant > MAXTC)
errflg++;
break;
default:
@@ -115,7 +117,7 @@ main(argc, argv)
-m maxerror max possible error (us)\n\
-o offset current offset (ms)\n\
-r print the unix and NTP time raw\n\
- -s status Set the status (0 .. 4)\n\
+ -l leap Set the leap bits\n\
-t timeconstant log2 of PLL time constant (0 .. %d)\n",
progname, optargs, MAXTC);
exit(2);
@@ -151,13 +153,13 @@ main(argc, argv)
times[c] = ntv.time.tv_usec;
}
if (pll_control >= 0) {
- printf("[ usec %06d:", times[0]);
+ printf("[ us %06d:", times[0]);
for (c=1; c< sizeof times / sizeof times[0]; c++) printf(" %d", times[c] - times[c-1]);
printf(" ]\n");
}
}
(void)ntp_gettime(&ntv);
- ntx.mode = 0; /* Ensure nothing is set */
+ _ntx.modes = 0; /* Ensure nothing is set */
(void)ntp_adjtime(&_ntx);
if (pll_control < 0) {
printf("NTP user interface routines are not configured in this kernel.\n");
@@ -175,9 +177,9 @@ main(argc, argv)
ts.l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */
ts.l_ui += JAN_1970;
ts.l_uf &= TS_MASK;
- printf(" time: %s, (.%06d)\n",
+ printf(" time %s, (.%06d),\n",
prettydate(&ts), ntv.time.tv_usec);
- printf(" confidence interval: %ld usec, estimated error: %ld usec\n",
+ printf(" maximum error %ld us, estimated error %ld us.\n",
ntv.maxerror, ntv.esterror);
if (rawtime) printf(" ntptime=%x.%x unixtime=%x.%06d %s",
ts.l_ui, ts.l_uf,
@@ -189,15 +191,26 @@ main(argc, argv)
">> ntp_adjtime() call fails");
else {
printf("ntp_adjtime() returns code %d\n", status);
- ftemp = ntx.frequency;
+ ftemp = ntx.freq;
ftemp /= (1 << SHIFT_USEC);
- printf(" mode: %02x, offset: %ld usec, frequency: %6.3f ppm,\n",
- ntx.mode, ntx.offset, ftemp);
- printf(" confidence interval: %ld usec, estimated error: %ld usec,\n",
+ printf(" modes %04x, offset %ld us, frequency %.3f ppm, interval %d s,\n",
+ ntx.modes, ntx.offset, ftemp, 1 << ntx.shift);
+ printf(" maximum error %ld us, estimated error %ld us,\n",
ntx.maxerror, ntx.esterror);
- printf(" status: %d, time constant: %ld, precision: %ld usec, tolerance: %ld usec\n",
- ntx.status, ntx.time_constant, ntx.precision,
- ntx.tolerance);
+ ftemp = ntx.tolerance;
+ ftemp /= (1 << SHIFT_USEC);
+ printf(" status %04x, time constant %ld, precision %ld us, tolerance %.0f ppm,\n",
+ ntx.status, ntx.constant, ntx.precision, ftemp);
+ if (ntx.shift == 0)
+ return;
+ ftemp = ntx.ppsfreq;
+ ftemp /= (1 << SHIFT_USEC);
+ gtemp = ntx.stabil;
+ gtemp /= (1 << SHIFT_USEC);
+ printf(" pps frequency %.3f ppm, stability %.3f ppm, jitter %ld us,\n",
+ ftemp, gtemp, ntx.jitter);
+ printf(" intervals %ld, jitter exceeded %ld, stability exceeded %ld, errors %ld.\n",
+ ntx.calcnt, ntx.jitcnt, ntx.stbcnt, ntx.errcnt);
}
/*
diff --git a/contrib/xntpd/util/tickadj.c b/contrib/xntpd/util/tickadj.c
index ab10b3728a0e..caec06871795 100644
--- a/contrib/xntpd/util/tickadj.c
+++ b/contrib/xntpd/util/tickadj.c
@@ -1,4 +1,4 @@
-/* tickadj.c,v 3.1 1993/07/06 01:11:05 jbj Exp
+/*
* tickadj - read, and possibly modify, the kernel `tick' and
* `tickadj' variables, as well as `dosynctodr'. Note that
* this operates on the running kernel only. I'd like to be
@@ -6,6 +6,41 @@
* mastered this yet.
*/
#include <stdio.h>
+
+#ifdef SYS_LINUX
+#include <sys/timex.h>
+
+struct timex txc;
+
+int
+main(int argc, char ** argv)
+{
+ if (argc > 2)
+ {
+ fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]);
+ exit(-1);
+ }
+ else if (argc == 2)
+ {
+ if ( (txc.tick = atoi(argv[1])) < 1 )
+ {
+ fprintf(stderr, "Silly value for tick: %s\n", argv[1]);
+ exit(-1);
+ }
+ txc.mode = ADJ_TICK;
+ }
+ else
+ txc.mode = 0;
+
+ if (__adjtimex(&txc) < 0)
+ perror("adjtimex");
+ else
+ printf("tick = %d\n", txc.tick);
+
+ return(0);
+}
+#else /* not Linux... kmem tweaking: */
+
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
@@ -298,10 +333,13 @@ getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off)
#if defined(SYS_AUX3) || defined(SYS_AUX2)
#define X_TICKADJ 0
-#define X_V 1
-#define X_TICK 2
+#define X_TICK 1
#define X_DEF
- static struct nlist nl[4];
+ static struct nlist nl[] =
+ { {"tickadj"},
+ {"tick"},
+ {""},
+ };
#endif
#ifdef NeXT
@@ -353,6 +391,22 @@ getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off)
#endif
#endif
+#if defined(SYS_HPUX)
+#define X_TICKADJ 0
+#define X_TICK 1
+#define X_DEF
+ static struct nlist nl[] =
+#ifdef hp9000s300
+ { {"_tickadj"},
+ {"_old_tick"},
+#else
+ { {"tickadj"},
+ {"old_tick"},
+#endif
+ {""},
+ };
+#endif
+
#if !defined(X_DEF)
#define X_TICKADJ 0
#define X_TICK 1
@@ -373,17 +427,11 @@ getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off)
"/kernel/unix",
"/386bsd",
"/netbsd",
+ "/hp-ux",
NULL
};
struct stat stbuf;
-#if defined(SYS_AUX3) || defined(SYS_AUX2)
- strcpy (nl[X_TICKADJ].n_name, "tickadj");
- strcpy (nl[X_V].n_name, "v");
- strcpy (nl[X_TICK].n_name, "tick");
- nl[3].n_name[0] = '\0';
-#endif
-
for (kname = kernels; *kname != NULL; kname++) {
if (stat(*kname, &stbuf) == -1)
continue;
@@ -513,3 +561,4 @@ readvar(fd, off, var)
exit(1);
}
}
+#endif /* not Linux */
diff --git a/contrib/xntpd/xntpd/Makefile b/contrib/xntpd/xntpd/Makefile
index 56f5dc2eb6eb..a4b083efde72 100644
--- a/contrib/xntpd/xntpd/Makefile
+++ b/contrib/xntpd/xntpd/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.4 1994/02/03 23:23:17 wollman Exp $
+# $Id: Makefile,v 1.5 1994/04/03 20:37:26 wollman Exp $
#
CFLAGS+= -I${.CURDIR}/../include
@@ -34,7 +34,7 @@ SRCS= ntp_config.c ntp_control.c ntp_io.c ntp_leap.c \
refclock_wwvb.c refclock_goes.c refclock_mx4200.c \
refclock_parse.c refclock_as2201.c refclock_omega.c \
refclock_tpro.c refclock_leitch.c refclock_irig.c \
- refclock_msfees.c refclock_gpstm.c ntp_intres.c \
+ refclock_msfees.c refclock_gpstm.c refclock_trak.c ntp_intres.c \
ntp_filegen.c version.c
beforedepend: version.c
diff --git a/contrib/xntpd/adjtime/.keep_me b/contrib/xntpd/xntpd/minpoll
index e69de29bb2d1..e69de29bb2d1 100644
--- a/contrib/xntpd/adjtime/.keep_me
+++ b/contrib/xntpd/xntpd/minpoll
diff --git a/contrib/xntpd/xntpd/ntp_config.c b/contrib/xntpd/xntpd/ntp_config.c
index 1b716f69fab5..8f356ac8c2e7 100644
--- a/contrib/xntpd/xntpd/ntp_config.c
+++ b/contrib/xntpd/xntpd/ntp_config.c
@@ -45,8 +45,9 @@
* peer 128.100.1.1 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
* server 128.100.2.2 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
* precision -7
- * broadcast 128.100.224.255 [ version 3 ] [ key 0 ]
- * broadcastclient yes|no
+ * broadcast 128.100.224.255 [ version 3 ] [ key 0 ] [ ttl 1 ]
+ * broadcastclient
+ * multicastclient [224.0.1.1]
* broadcastdelay 0.0102
* authenticate yes|no
* monitor yes|no
@@ -58,6 +59,16 @@
* statsdir /var/NTP/
* filegen peerstats [ file peerstats ] [ type day ] [ link ]
* resolver /path/progname
+ * clientlimit [ n ]
+ * clientperiod [ 3600 ]
+ * trustedkey [ key ]
+ * requestkey [ key]
+ * controlkey [ key ]
+ * trap [ address ]
+ * fudge [ ... ]
+ * pidfile [ ]
+ * logfile [ ]
+ * setvar [ ]
*
* And then some. See the manual page.
*/
@@ -84,22 +95,24 @@
#define CONFIG_CONTROLKEY 15
#define CONFIG_TRAP 16
#define CONFIG_FUDGE 17
-#define CONFIG_MAXSKEW 18
-#define CONFIG_RESOLVER 19
-#define CONFIG_SELECT 20
-#define CONFIG_STATSDIR 21
-#define CONFIG_FILEGEN 22
-#define CONFIG_STATISTICS 23
-#define CONFIG_PPS 24
-#define CONFIG_PIDFILE 25
-#define CONFIG_LOGFILE 26
-#define CONFIG_SETVAR 27
+#define CONFIG_RESOLVER 18
+#define CONFIG_STATSDIR 19
+#define CONFIG_FILEGEN 20
+#define CONFIG_STATISTICS 21
+#define CONFIG_PPS 22
+#define CONFIG_PIDFILE 23
+#define CONFIG_LOGFILE 24
+#define CONFIG_SETVAR 25
+#define CONFIG_CLIENTLIMIT 26
+#define CONFIG_CLIENTPERIOD 27
+#define CONFIG_MULTICASTCLIENT 28
#define CONF_MOD_VERSION 1
#define CONF_MOD_KEY 2
#define CONF_MOD_MINPOLL 3
#define CONF_MOD_MAXPOLL 4
#define CONF_MOD_PREFER 5
+#define CONF_MOD_TTL 6
#define CONF_PPS_DELAY 1
#define CONF_PPS_BAUD 2
@@ -114,6 +127,7 @@
#define CONF_RES_NOTRAP 8
#define CONF_RES_LPTRAP 9
#define CONF_RES_NTPPORT 10
+#define CONF_RES_LIMITED 11
#define CONF_TRAP_PORT 1
#define CONF_TRAP_INTERFACE 2
@@ -158,6 +172,7 @@ static struct keyword keywords[] = {
{ "driftfile", CONFIG_DRIFTFILE },
{ "broadcast", CONFIG_BROADCAST },
{ "broadcastclient", CONFIG_BROADCASTCLIENT },
+ { "multicastclient", CONFIG_MULTICASTCLIENT },
{ "authenticate", CONFIG_AUTHENTICATE },
{ "keys", CONFIG_KEYS },
{ "monitor", CONFIG_MONITOR },
@@ -170,15 +185,15 @@ static struct keyword keywords[] = {
{ "controlkey", CONFIG_CONTROLKEY },
{ "trap", CONFIG_TRAP },
{ "fudge", CONFIG_FUDGE },
- { "maxskew", CONFIG_MAXSKEW },
{ "resolver", CONFIG_RESOLVER },
- { "select", CONFIG_SELECT },
{ "statsdir", CONFIG_STATSDIR },
{ "filegen", CONFIG_FILEGEN },
{ "statistics", CONFIG_STATISTICS },
{ "pidfile", CONFIG_PIDFILE },
{ "logfile", CONFIG_LOGFILE },
{ "setvar", CONFIG_SETVAR },
+ { "clientlimit", CONFIG_CLIENTLIMIT },
+ { "clientperiod", CONFIG_CLIENTPERIOD },
{ "", CONFIG_UNKNOWN }
};
@@ -191,6 +206,7 @@ static struct keyword mod_keywords[] = {
{ "minpoll", CONF_MOD_MINPOLL },
{ "maxpoll", CONF_MOD_MAXPOLL },
{ "prefer", CONF_MOD_PREFER },
+ { "ttl", CONF_MOD_TTL },
{ "", CONFIG_UNKNOWN }
};
@@ -217,6 +233,7 @@ static struct keyword res_keywords[] = {
{ "notrap", CONF_RES_NOTRAP },
{ "lowpriotrap", CONF_RES_LPTRAP },
{ "ntpport", CONF_RES_NTPPORT },
+ { "limited", CONF_RES_LIMITED },
{ "", CONFIG_UNKNOWN }
};
@@ -318,12 +335,12 @@ extern int debug;
#endif
extern char *FindConfig();
char *progname;
-static char *xntp_options = "abc:de:f:k:l:p:r:s:t:v:V:";
+static char *xntp_options = "abc:de:f:k:l:mp:r:s:t:v:V:";
static int gettokens P((FILE *, char *, char **, int *));
static int matchkey P((char *, struct keyword *));
static int getnetnum P((char *, struct sockaddr_in *, int));
-static void save_resolve P((char *, int, int, int, int, int, U_LONG));
+static void save_resolve P((char *, int, int, int, int, int, int, U_LONG));
static void do_resolve P((char *, U_LONG, char *));
#ifdef RESOLVE_INTERNAL
static void do_resolve_internal P((void));
@@ -410,6 +427,7 @@ getconfig(argc, argv)
int peerversion;
int minpoll;
int maxpoll;
+ int ttl;
U_LONG peerkey;
int peerflags;
int hmode;
@@ -466,12 +484,15 @@ getconfig(argc, argv)
case 'a':
proto_config(PROTO_AUTHENTICATE, (LONG)1);
break;
+
case 'b':
proto_config(PROTO_BROADCLIENT, (LONG)1);
break;
+
case 'c':
config_file = ntp_optarg;
break;
+
case 'd':
#ifdef DEBUG
debug++;
@@ -516,6 +537,10 @@ getconfig(argc, argv)
}
break;
+ case 'm':
+ proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ break;
+
case 'p':
stats_config(STATS_PID_FILE, ntp_optarg);
break;
@@ -624,6 +649,7 @@ getconfig(argc, argv)
maxpoll = NTP_MAXPOLL;
peerkey = 0;
peerflags = 0;
+ ttl = 1;
for (i = 2; i < ntokens; i++)
switch (matchkey(tokens[i], mod_keywords)) {
case CONF_MOD_VERSION:
@@ -689,6 +715,16 @@ getconfig(argc, argv)
peerflags |= FLAG_PREFER;
break;
+ case CONF_MOD_TTL:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "ttl: argument required");
+ errflg = 1;
+ break;
+ }
+ ttl = atoi(tokens[++i]);
+ break;
+
case CONFIG_UNKNOWN:
errflg = 1;
break;
@@ -700,14 +736,15 @@ getconfig(argc, argv)
if (errflg == 0) {
if (peer_config(&peeraddr,
(struct interface *)0, hmode, peerversion,
- minpoll, maxpoll, peerkey, peerflags) == 0) {
+ minpoll, maxpoll, peerflags, ttl, peerkey)
+ == 0) {
syslog(LOG_ERR,
"configuration of %s failed",
ntoa(&peeraddr));
}
} else if (errflg == -1) {
save_resolve(tokens[1], hmode, peerversion,
- minpoll, maxpoll, peerflags, peerkey);
+ minpoll, maxpoll, peerflags, ttl, peerkey);
}
break;
@@ -764,23 +801,20 @@ getconfig(argc, argv)
} break;
case CONFIG_BROADCASTCLIENT:
- errflg = 0;
- if (ntokens >= 2) {
- if (STREQ(tokens[1], "yes"))
- proto_config(PROTO_BROADCLIENT, (LONG)1);
- else if (STREQ(tokens[1], "no"))
- proto_config(PROTO_BROADCLIENT, (LONG)0);
- else
- errflg++;
- } else {
- errflg++;
- }
-
- if (errflg)
- syslog(LOG_ERR,
- "should be `broadcastclient yes|no'");
+ proto_config(PROTO_BROADCLIENT, (U_LONG)1);
break;
+ case CONFIG_MULTICASTCLIENT:
+ if (ntokens > 1) {
+ for (i = 1; i < ntokens; i++) {
+ if (getnetnum(tokens[i], &peeraddr, 1));
+ proto_config(PROTO_MULTICAST_ADD,
+ peeraddr.sin_addr.s_addr);
+ }
+ } else
+ proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ break;
+
case CONFIG_AUTHENTICATE:
errflg = 0;
if (ntokens >= 2) {
@@ -817,9 +851,9 @@ getconfig(argc, argv)
errflg = 0;
if (ntokens >= 2) {
if (STREQ(tokens[1], "yes"))
- mon_start();
+ mon_start(MON_ON);
else if (STREQ(tokens[1], "no"))
- mon_stop();
+ mon_stop(MON_ON);
else
errflg++;
} else {
@@ -965,6 +999,10 @@ getconfig(argc, argv)
peerkey |= RESM_NTPONLY;
break;
+ case CONF_RES_LIMITED:
+ peerversion |= RES_LIMITED;
+ break;
+
case CONFIG_UNKNOWN:
errflg++;
break;
@@ -1252,26 +1290,6 @@ getconfig(argc, argv)
#endif
break;
- case CONFIG_MAXSKEW:
- if (ntokens >= 2) {
- l_fp tmp;
- u_fp utmp;
-
- if (!atolfp(tokens[1], &tmp)) {
- syslog(LOG_ERR,
- "maxskew value %s undecodable",
- tokens[1]);
- } else if (tmp.l_ui != 0) {
- syslog(LOG_ERR,
- "maxskew value %s is unlikely",
- tokens[1]);
- } else {
- utmp = LFPTOFP(&tmp);
- proto_config(PROTO_MAXSKEW, (LONG)utmp);
- }
- }
- break;
-
case CONFIG_RESOLVER:
if (ntokens >= 2) {
if (strlen(tokens[1]) >= (size_t)MAXFILENAME) {
@@ -1288,18 +1306,6 @@ getconfig(argc, argv)
}
break;
- case CONFIG_SELECT:
- if (ntokens >= 2) {
- i = atoi(tokens[1]);
- if (i < SELECT_1 || i > SELECT_5)
- syslog(LOG_ERR,
- "invalid selection algorithm %s, line ignored",
- tokens[1]);
- else
- proto_config(PROTO_SELECT, (LONG)i);
- }
- break;
-
case CONFIG_STATSDIR:
if (ntokens >= 2) {
stats_config(STATS_STATSDIR,tokens[1]);
@@ -1414,6 +1420,60 @@ getconfig(argc, argv)
((((ntokens > 2) && !strcmp(tokens[2], "default"))) ? DEF : 0));
}
break;
+
+ case CONFIG_CLIENTLIMIT:
+ if (ntokens < 2)
+ {
+ syslog(LOG_ERR,
+ "no value for clientlimit command - line ignored");
+ }
+ else
+ {
+ U_LONG i;
+ if (!atouint(tokens[1], &i) || !i)
+ {
+ syslog(LOG_ERR,
+ "illegal value for clientlimit command - line ignored");
+ }
+ else
+ {
+ extern U_LONG client_limit;
+ char bp[80];
+
+ sprintf(bp, "client_limit=%d", i);
+ set_sys_var(bp, strlen(bp)+1, RO);
+
+ client_limit = i;
+ }
+ }
+ break;
+
+ case CONFIG_CLIENTPERIOD:
+ if (ntokens < 2)
+ {
+ syslog(LOG_ERR,
+ "no value for clientperiod command - line ignored");
+ }
+ else
+ {
+ U_LONG i;
+ if (!atouint(tokens[1], &i) || i < 64)
+ {
+ syslog(LOG_ERR,
+ "illegal value for clientperiod command - line ignored");
+ }
+ else
+ {
+ extern U_LONG client_limit_period;
+ char bp[80];
+
+ sprintf(bp, "client_limit_period=%d", i);
+ set_sys_var(bp, strlen(bp)+1, RO);
+
+ client_limit_period = i;
+ }
+ }
+ break;
}
}
(void) fclose(fp);
@@ -1643,13 +1703,14 @@ int sig;
* save_resolve - save configuration info into a file for later name resolution
*/
static void
-save_resolve(name, mode, version, minpoll, maxpoll, flags, keyid)
+save_resolve(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
char *name;
int mode;
int version;
int minpoll;
int maxpoll;
int flags;
+ int ttl;
U_LONG keyid;
{
if (res_fp == NULL) {
@@ -1668,8 +1729,8 @@ save_resolve(name, mode, version, minpoll, maxpoll, flags, keyid)
}
#endif
- (void) fprintf(res_fp, "%s %d %d %d %d %d %lu\n", name, mode,
- version, minpoll, maxpoll, flags, keyid);
+ (void) fprintf(res_fp, "%s %d %d %d %d %d %d %lu\n", name, mode,
+ version, minpoll, maxpoll, flags, ttl, keyid);
}
diff --git a/contrib/xntpd/xntpd/ntp_control.c b/contrib/xntpd/xntpd/ntp_control.c
index 1c7849f48820..ef9c37a6751d 100644
--- a/contrib/xntpd/xntpd/ntp_control.c
+++ b/contrib/xntpd/xntpd/ntp_control.c
@@ -264,8 +264,20 @@ static u_char def_clock_var[] = {
/*
* System and processor definitions. These will change for the gizmo board.
*/
+#ifndef HAVE_UNAME
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX"
+#endif
+#ifndef STR_PROCESSOR
+#define STR_PROCESSOR "unknown"
+#endif
+
+static char str_system[] = STR_SYSTEM;
+static char str_processor[] = STR_PROCESSOR;
+#else
#include <sys/utsname.h>
static struct utsname utsname;
+#endif /* HAVE_UNAME */
/*
* Trap structures. We only allow a few of these, and send
@@ -294,7 +306,7 @@ static struct utsname utsname;
static u_char clocktypes[] = {
CTL_SST_TS_NTP, /* REFCLK_NONE */
CTL_SST_TS_UNSPEC, /* REFCLK_LOCALCLOCK */
- CTL_SST_TS_HF, /* REFCLK_WWV_HEATH */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK */
CTL_SST_TS_HF, /* REFCLK_WWV_PST */
CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM */
CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME */
@@ -379,6 +391,7 @@ extern struct peer *sys_peer;
extern l_fp last_offset;
extern s_fp drift_comp;
extern int time_constant;
+extern int pll_control;
/*
* Imported from the leap module
*/
@@ -426,7 +439,9 @@ init_control()
{
int i;
+#ifdef HAVE_UNAME
uname(&utsname);
+#endif /* HAVE_UNAME */
ctl_clr_stats();
@@ -716,10 +731,12 @@ ctlsysstatus()
if (sys_peer != 0)
if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC)
clock = sys_peer->sstclktype;
- else
+ else {
if (sys_peer->refclktype < sizeof(clocktypes))
clock = clocktypes[sys_peer->refclktype];
-
+ if (pps_control)
+ clock |= CTL_SST_TS_PPS;
+ }
return (u_short)CTL_SYS_STATUS(sys_leap, clock,
ctl_sys_num_events, ctl_sys_last_event);
}
@@ -1262,12 +1279,22 @@ ctl_putsys(varid)
ctl_putuint(sys_var[CS_LEAPWARNING].text, (U_LONG)leap_warning);
break;
case CS_PROCESSOR:
+#ifndef HAVE_UNAME
+ ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
+ sizeof(str_processor) - 1);
+#else
ctl_putstr(sys_var[CS_PROCESSOR].text, utsname.machine,
strlen(utsname.machine));
+#endif /* HAVE_UNAME */
break;
case CS_SYSTEM:
- ctl_putstr(sys_var[CS_SYSTEM].text, utsname.sysname,
+#ifndef HAVE_UNAME
+ ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
+ sizeof(str_system) - 1);
+#else
+ ctl_putstr(sys_var[CS_SYSTEM].text, utsname.sysname,
strlen(utsname.sysname));
+#endif /* HAVE_UNAME */
break;
case CS_KEYID:
ctl_putuint(sys_var[CS_KEYID].text, (U_LONG)0);
diff --git a/contrib/xntpd/xntpd/ntp_intres.c b/contrib/xntpd/xntpd/ntp_intres.c
index 20561e91b82d..5ff4af4d8242 100644
--- a/contrib/xntpd/xntpd/ntp_intres.c
+++ b/contrib/xntpd/xntpd/ntp_intres.c
@@ -48,6 +48,7 @@ struct conf_entry {
#define ce_minpoll ce_config.minpoll
#define ce_maxpoll ce_config.maxpoll
#define ce_flags ce_config.flags
+#define ce_ttl ce_config.ttl
#define ce_keyid ce_config.keyid
/*
@@ -102,8 +103,9 @@ static int resolve_value; /* next value of resolve timer */
#define TOK_MINPOLL 3
#define TOK_MAXPOLL 4
#define TOK_FLAGS 5
-#define TOK_KEYID 6
-#define NUMTOK 7
+#define TOK_TTL 6
+#define TOK_KEYID 7
+#define NUMTOK 8
#define MAXLINESIZE 512
@@ -128,7 +130,7 @@ extern int errno;
static RETSIGTYPE bong P((int));
static void checkparent P((void));
static void removeentry P((struct conf_entry *));
-static void addentry P((char *, int, int, int, int, int, U_LONG));
+static void addentry P((char *, int, int, int, int, int, int, U_LONG));
static int findhostaddr P((struct conf_entry *));
static void openntp P((void));
static int request P((struct conf_peer *));
@@ -279,13 +281,14 @@ removeentry(entry)
* addentry - add an entry to the configuration list
*/
static void
-addentry(name, mode, version, minpoll, maxpoll, flags, keyid)
+addentry(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
char *name;
int mode;
int version;
int minpoll;
int maxpoll;
int flags;
+ int ttl;
U_LONG keyid;
{
register char *cp;
@@ -304,6 +307,7 @@ addentry(name, mode, version, minpoll, maxpoll, flags, keyid)
ce->ce_minpoll = (u_char)minpoll;
ce->ce_maxpoll = (u_char)maxpoll;
ce->ce_flags = (u_char)flags;
+ ce->ce_ttl = (u_char)ttl;
ce->ce_keyid = htonl(keyid);
ce->ce_next = NULL;
@@ -751,7 +755,8 @@ readconf(fp, name)
*/
addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
(int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
- (int)intval[TOK_MAXPOLL], flags, intval[TOK_KEYID]);
+ (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
+ intval[TOK_KEYID]);
}
}
diff --git a/contrib/xntpd/xntpd/ntp_io.c b/contrib/xntpd/xntpd/ntp_io.c
index 614d5c52bde9..551df510dc37 100644
--- a/contrib/xntpd/xntpd/ntp_io.c
+++ b/contrib/xntpd/xntpd/ntp_io.c
@@ -10,6 +10,10 @@
#include <sys/ioctl.h>
#include <sys/time.h>
+#ifdef MCAST
+#include "ntp_in.h"
+#endif /* MCAST */
+
#include "ntpd.h"
#include "ntp_select.h"
#include "ntp_io.h"
@@ -53,7 +57,6 @@
/*
* Block the interrupt, for critical sections.
*/
-
#if defined(HAVE_SIGNALED_IO)
#define BLOCKIO() ((void) block_sigio())
#define UNBLOCKIO() ((void) unblock_sigio())
@@ -228,6 +231,9 @@ create_sockets(port)
inter_list[0].sent = 0;
inter_list[0].notsent = 0;
inter_list[0].flags = INT_BROADCAST;
+#ifdef MCAST
+ inter_list[0].flags |= INT_MULTICAST;
+#endif /* MCAST */
#ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
if ((vs = open("/dev/ip", O_RDONLY)) < 0) {
@@ -394,7 +400,7 @@ create_sockets(port)
maxactivefd = 0;
FD_ZERO(&activefds);
-
+
for (i = 0; i < ninterfaces; i++) {
inter_list[i].fd = open_socket(&inter_list[i].sin,
inter_list[i].flags & INT_BROADCAST);
@@ -458,23 +464,72 @@ io_setbclient()
}
+#ifdef MCAST
+/*
+ * io_multicast_add() - add multicast group address
+ */
+void
+io_multicast_add(addr)
+ U_LONG addr;
+{
+ int fd = inter_list[0].fd;
+ struct ip_mreq mreq;
+
+ if (!IN_CLASSD(addr))
+ return;
+ /*
+ * enable reception of multicast packets
+ */
+ mreq.imr_multiaddr.s_addr = addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) == -1)
+ syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP fails: %m");
+}
+#endif /* MCAST */
+
+
/*
* io_unsetbclient - close the broadcast client sockets
*/
void
io_unsetbclient()
{
- int i;
+ int i;
for (i = 1; i < ninterfaces; i++) {
if (!(inter_list[i].flags & INT_BCASTOPEN))
continue;
close_socket(inter_list[i].bfd);
inter_list[i].flags &= ~INT_BCASTOPEN;
- }
+ }
}
+#ifdef MCAST
+/*
+ * io_multicast_del() - delete multicast group address
+ */
+void
+io_multicast_del(addr)
+ U_LONG addr;
+{
+ int fd = inter_list[0].fd;
+ struct ip_mreq mreq;
+
+ if (!IN_CLASSD(addr))
+ return;
+ /*
+ * disable reception of multicast packets
+ */
+ mreq.imr_multiaddr.s_addr = addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) == -1)
+ syslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m");
+}
+#endif /* MCAST */
+
/*
* open_socket - open a socket, returning the file descriptor
@@ -510,7 +565,8 @@ open_socket(addr, bcast)
*/
if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
char buff[160];
- sprintf(buff, "bind() fd %d, family %d, port %d, addr %08x, bcast=%d fails: %%m",
+ sprintf(buff,
+ "bind() fd %d, family %d, port %d, addr %08x, bcast=%d fails: %%m",
fd,
addr->sin_family,
addr->sin_port,
@@ -557,6 +613,19 @@ Need non blocking I/O
syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m");
}
+#ifdef MCAST
+ /* for the moment we use the bcast option to set multicast ttl */
+
+ if (bcast) {
+ unsigned char mttl = 127;
+
+ /* set the multicast ttl for outgoing packets */
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &mttl, sizeof(mttl)) == -1) {
+ syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m");
+ }
+ }
+#endif /* MCAST */
#ifdef SO_BROADCAST
/* if this interface can support broadcast, set SO_BROADCAST */
@@ -566,7 +635,7 @@ Need non blocking I/O
syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
}
}
-#endif
+#endif /* SO_BROADCAST */
#ifdef DEBUG
if (debug > 1)
@@ -608,7 +677,7 @@ struct interface *
findbcastinter(addr)
struct sockaddr_in *addr;
{
-#ifdef SIOCGIFCONF
+#ifdef SIOCGIFCONF
register int i;
register U_LONG netnum;
@@ -622,7 +691,7 @@ findbcastinter(addr)
== (netnum & NSRCADR(&inter_list[i].mask)))
return &inter_list[i];
}
-#endif
+#endif /* SIOCGIFCONF */
return any_interface;
}
@@ -744,7 +813,7 @@ sendpkt(dest, inter, pkt, len)
#ifdef DEBUG
if (debug)
- printf("sendpkt(%s, %s, %d)\n", ntoa(dest),
+ printf("sendpkt(fd=%d %s, %s, %d)\n", inter->fd, ntoa(dest),
ntoa(&inter->sin), len);
#endif
@@ -902,11 +971,16 @@ again:
}
if (FD_ISSET(fd, &fds)) {
n--;
+
/*
* Get a buffer and read the frame. If we
* haven't got a buffer, or this is received
* on the wild card socket, just dump the packet.
*/
+
+ if (!(free_recvbufs && i == 0 &&
+ inter_list[i].flags & INT_MULTICAST)) {
+
#ifdef UDP_WILDCARD_DELIVERY
/*
* these guys manage to put properly addressed packets into the wildcard queue
@@ -932,6 +1006,7 @@ again:
packets_dropped++;
continue;
}
+ }
rb = freelist;
freelist = rb->next;
@@ -958,7 +1033,7 @@ again:
if (debug)
printf("input_handler: fd=%d length %d\n", fd, rb->recv_length);
#endif
-
+
/*
* Got one. Mark how and when it got here,
* put it on the full list and do bookkeeping.
diff --git a/contrib/xntpd/xntpd/ntp_loopfilter.c b/contrib/xntpd/xntpd/ntp_loopfilter.c
index 6d79c5d52ff4..13cbd61b6741 100644
--- a/contrib/xntpd/xntpd/ntp_loopfilter.c
+++ b/contrib/xntpd/xntpd/ntp_loopfilter.c
@@ -9,9 +9,6 @@
#include "ntpd.h"
#include "ntp_io.h"
-#if defined(KERNEL_PLL)
-#include "ntp_timex.h"
-#endif /* KERNEL_PLL */
#include "ntp_unixtime.h"
#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
@@ -46,11 +43,13 @@
#include "ntp_stdlib.h"
-#ifdef KERNEL_PLL
-#ifndef SYS_ntp_adjtime
-#define SYS_ntp_adjtime NTP_SYSCALL_ADJ
+#ifdef KERNEL_PLL
+#include <sys/timex.h>
+#ifndef NTP_SYSCALLS_LIBC
+#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
+#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
#endif
-#endif /* KERNEL_PLL */
+#endif /* KERNEL_PLL */
/*
* The loop filter is implemented in slavish adherence to the
@@ -95,17 +94,14 @@
#define RSH_DRIFT_TO_FRAC (CLOCK_DSCALE - 16)
#define RSH_DRIFT_TO_ADJ (RSH_DRIFT_TO_FRAC - CLOCK_ADJ)
#define RSH_FRAC_TO_FREQ (CLOCK_FREQ + CLOCK_ADJ - RSH_DRIFT_TO_FRAC)
+#define PPS_MAXAGE 120 /* pps signal timeout (s) */
+#define PPS_MAXUPDATE 600 /* pps update timeout (s) */
/*
- * Imported from the ntp_proto module
+ * Program variables
*/
-extern u_char sys_stratum;
-extern s_fp sys_rootdelay;
-extern u_fp sys_rootdispersion;
-extern s_char sys_precision;
-
l_fp last_offset; /* last adjustment done */
-static LONG clock_adjust; /* clock adjust register (fraction only) */
+static LONG clock_adjust; /* clock adjust (fraction only) */
s_fp drift_comp; /* drift compensation register */
static s_fp max_comp; /* drift limit imposed by max host clock slew */
@@ -114,11 +110,15 @@ static s_fp max_comp; /* drift limit imposed by max host clock slew */
static U_LONG tcadj_time; /* last time-constant adjust time */
U_LONG watchdog_timer; /* watchdog timer, in seconds */
-static int first_adjustment; /* set to 1 if waiting for first adjustment */
+static int first_adjustment; /* 1 if waiting for first adjustment */
static int tc_counter; /* time-constant hold counter */
- int pll_control; /* set nonzero if pll implemented in kernel */
- int pps_control; /* set nonzero if pps signal valid */
+static l_fp pps_offset; /* filtered pps offset */
+static u_fp pps_dispersion; /* pps dispersion */
+static U_LONG pps_time; /* last pps sample time */
+
+ int pps_control; /* true if working pps signal */
+ int pll_control; /* true if working kernel pll */
static l_fp pps_delay; /* pps tuning offset */
U_LONG pps_update; /* last pps update time */
int fdpps = -1; /* pps file descriptor */
@@ -154,29 +154,35 @@ static l_fp pps_delay; /* pps tuning offset */
( i == 300 ? B300 : 0 ))))))))
#define PPS_BAUD B38400 /* default serial port speed */
-#define PPS_MAXAGE 120 /* seconds after which we disbelieve pps */
-#define PPS_MAXUPDATE 600 /* seconds after which we disbelieve timecode */
+timecode */
#define PPS_DEV "/dev/pps" /* pps port */
#define PPS_FAC 3 /* pps shift (log2 trimmed samples) */
-#define NPPS 12 /* pps filter size (1<<PPS_FAC+2*PPS_TRIM) */
-#define PPS_TRIM 2 /* samples trimmed from median filter */
+#define PPS_TRIM 6 /* samples trimmed from median filter */
+#define NPPS ((1 << PPS_FAC) + 2 * PPS_TRIM) /* pps filter size */
#define PPS_XCPT "\377" /* intercept character */
#if defined(PPSCLK)
static struct refclockio io; /* given to the I/O handler */
static int pps_baud; /* baud rate of PPS line */
#endif /* PPSCLK */
-static l_fp pps_offset; /* filtered pps offset */
-static U_LONG pps_time; /* last pps sample time */
static U_LONG nsamples; /* number of pps samples collected */
static LONG samples[NPPS]; /* median filter for pps samples */
+
+#endif /* PPS || PPSCLK || PPSPPS */
+
+/*
+ * Imported from the ntp_proto module
+ */
+extern u_char sys_stratum;
+extern s_fp sys_rootdelay;
+extern u_fp sys_rootdispersion;
+extern s_char sys_precision;
+
/*
* Imported from ntp_io.c
*/
extern struct interface *loopback_interface;
-#endif /* PPS || PPSCLK || PPSPPS */
-
/*
* Imported from ntpd module
*/
@@ -191,10 +197,16 @@ extern U_LONG current_time; /* like it says, in seconds */
* sys_poll and sys_refskew are set here
*/
extern u_char sys_poll; /* log2 of system poll interval */
+extern u_char sys_leap; /* system leap bits */
extern l_fp sys_refskew; /* accumulated skew since last update */
extern u_fp sys_maxd; /* max dispersion of survivor list */
/*
+ * Imported from leap module
+ */
+extern u_char leapbits; /* sanitized leap bits */
+
+/*
* Function prototypes
*/
#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
@@ -205,9 +217,15 @@ static void pps_receive P((struct recvbuf *));
#endif /* PPS || PPSCLK || PPSPPS */
#if defined(KERNEL_PLL)
+#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
+ MOD_STATUS | MOD_TIMECONST)
extern int sigvec P((int, struct sigvec *, struct sigvec *));
+#ifndef NTP_SYSCALLS_LIBC
+extern int syscall P((int, void *, ...));
+#endif /* no NTP syscalls in libc */
void pll_trap P((void));
+static int pll_status; /* status bits for kernel pll */
static struct sigvec sigsys; /* current sigvec status */
static struct sigvec newsigsys; /* new sigvec status */
#endif /* KERNEL_PLL */
@@ -350,8 +368,8 @@ init_loopfilter()
}
}
#endif /* HAVE_BSD_TTYS */
- fdpps = fd232;
#endif /* HPUXGADGET */
+ fdpps = fd232;
/*
* Insert in device list.
@@ -399,7 +417,7 @@ local_clock(fp_offset, peer)
#ifdef DEBUG
if (debug > 1)
- printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 9),
+ printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 6),
ntoa(&peer->srcadr));
#endif
@@ -432,33 +450,26 @@ local_clock(fp_offset, peer)
last_offset = *fp_offset;
/*
- * If the magnitude of the offset is greater than CLOCK.MAX, step
- * the time and reset the registers.
+ * If the magnitude of the offset is greater than CLOCK.MAX,
+ * step the time and reset the registers.
*/
if (tmp_ui > CLOCK_MAX_I || (tmp_ui == CLOCK_MAX_I
&& (U_LONG)tmp_uf >= (U_LONG)CLOCK_MAX_F)) {
if (watchdog_timer < CLOCK_MINSTEP) {
/* Mustn't step yet, pretend we adjusted. */
-#ifdef SLEWALWAYS
syslog(LOG_INFO,
- "adjust: SLEW dropped (%s offset %s)\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
-#else
- syslog(LOG_INFO,
- "adjust: STEP dropped (%s offset %s)\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
-#endif
+ "clock correction %s too large (ignored)\n",
+ lfptoa(fp_offset, 6));
return (0);
}
+ syslog(LOG_NOTICE, "clock reset (%s) %s\n",
#ifdef SLEWALWAYS
- syslog(LOG_NOTICE, " ** adjust: SLEW %s offset %s **\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
+ "slew",
#else
- syslog(LOG_NOTICE, " ** adjust: STEP %s offset %s **\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
+ "step",
#endif
+ lfptoa(fp_offset, 6));
step_systime(fp_offset);
-
clock_adjust = 0;
watchdog_timer = 0;
first_adjustment = 1;
@@ -480,20 +491,24 @@ local_clock(fp_offset, peer)
* The time constant update goes after adjust and skew updates,
* as in appendix G.
*/
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
/*
* If pps samples are valid, update offset, root delay and
- * root dispersion. This may be a dramatic surprise to high-
- * stratum clients, since all of a sudden this server looks
- * like a stratum-1 clock.
+ * root dispersion. Also, set the system stratum to 1, even if
+ * the source of approximate time runs at a higher stratum. This
+ * may be a dramatic surprise to high-stratum clients, since all
+ * of a sudden this server looks like a stratum-1 clock.
*/
if (pps_control) {
last_offset = pps_offset;
+ sys_maxd = pps_dispersion;
sys_stratum = 1;
sys_rootdelay = 0;
- sys_rootdispersion = sys_maxd;
+ offset = LFPTOFP(&pps_offset);
+ if (offset < 0)
+ offset = -offset;
+ sys_rootdispersion = offset + pps_dispersion;
}
-#endif /* PPS || PPSCLK || PPSPPS */
+ offset = last_offset.l_f;
/*
* The pll_control is active when the phase-lock code is
@@ -504,26 +519,56 @@ local_clock(fp_offset, peer)
* know the scaling of the frequency variable (s_fp) is the
* same as the kernel variable (1 << SHIFT_USEC = 16).
*
+ * For kernels with the PPS discipline, the current offset and
+ * dispersion are set from kernel variables to maintain
+ * beauteous displays, but don't do much of anything.
+ *
* In the case of stock kernels the phase-lock loop is
* implemented the hard way and the clock_adjust and drift_comp
* computed as required.
*/
- offset = last_offset.l_f;
if (pll_control) {
#if defined(KERNEL_PLL)
- ntv.mode = ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR |
- ADJ_ESTERROR;
+ memset((char *)&ntv, 0, sizeof ntv);
+ ntv.modes = MOD_BITS;
if (offset >= 0) {
TSFTOTVU(offset, ntv.offset);
} else {
TSFTOTVU(-offset, ntv.offset);
ntv.offset = -ntv.offset;
}
- ntv.maxerror = sys_rootdispersion + sys_rootdelay / 2;
- ntv.esterror = sys_rootdispersion;
- ntv.time_constant = time_constant;
+ TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2, ntv.maxerror);
+ TSFTOTVU(sys_rootdispersion, ntv.esterror);
+ ntv.status = pll_status;
+ if (pps_update)
+ ntv.status |= STA_PPSTIME;
+ if (sys_leap & LEAP_ADDSECOND &&
+ sys_leap & LEAP_DELSECOND)
+ ntv.status |= STA_UNSYNC;
+ else if (sys_leap & LEAP_ADDSECOND)
+ ntv.status |= STA_INS;
+ else if (sys_leap & LEAP_DELSECOND)
+ ntv.status |= STA_DEL;
+ ntv.constant = time_constant;
(void)ntp_adjtime(&ntv);
- drift_comp = ntv.frequency;
+ drift_comp = ntv.freq;
+ if (ntv.status & STA_PPSTIME && ntv.status & STA_PPSSIGNAL
+ && ntv.shift) {
+ if (ntv.offset >= 0) {
+ TVUTOTSF(ntv.offset, offset);
+ } else {
+ TVUTOTSF(-ntv.offset, offset);
+ offset = -offset;
+ }
+ pps_offset.l_i = pps_offset.l_f = 0;
+ M_ADDF(pps_offset.l_i, pps_offset.l_f, offset);
+ TVUTOTSF(ntv.jitter, tmp);
+ pps_dispersion = (tmp >> 16) & 0xffff;
+ pps_time = current_time;
+ record_peer_stats(&loopback_interface->sin,
+ ctlsysstatus(), &pps_offset, 0, pps_dispersion);
+ } else
+ pps_time = 0;
#endif /* KERNEL_PLL */
} else {
if (offset < 0) {
@@ -533,21 +578,14 @@ local_clock(fp_offset, peer)
}
/*
- * Calculate the new frequency error. The factor given in the
- * spec gives the adjustment per 2**CLOCK_ADJ seconds, but we
- * want it as a (scaled) pure ratio, so we include that factor
- * now and remove it later.
+ * Calculate the new frequency error. The factor given
+ * in the spec gives the adjustment per 2**CLOCK_ADJ
+ * seconds, but we want it as a (scaled) pure ratio, so
+ * we include that factor now and remove it later.
*/
if (first_adjustment) {
first_adjustment = 0;
} else {
- /*
- * Clamp the integration interval to maxpoll.
- * The bitcounting in Section 5 gives (n+1)-6 for 2**n,
- * but has a factor 2**6 missing from CLOCK_FREQ.
- * We make 2**n give n instead. If watchdog_timer is
- * zero, pretend it's one.
- */
tmp = peer->maxpoll;
tmp_uf = watchdog_timer;
if (tmp_uf == 0)
@@ -558,10 +596,11 @@ local_clock(fp_offset, peer)
}
/*
- * We apply the frequency scaling at the same time as
- * the sample interval; this ensures a safe right-shift.
- * (as long as it keeps below 31 bits, which current
- * parameters should ensure.
+ * We apply the frequency scaling at the same
+ * time as the sample interval; this ensures a
+ * safe right-shift. (as long as it keeps below
+ * 31 bits, which current parameters should
+ * ensure.
*/
tmp = (RSH_FRAC_TO_FREQ - tmp) +
time_constant + time_constant;
@@ -581,7 +620,9 @@ local_clock(fp_offset, peer)
/*
* Determine when to adjust the time constant and poll interval.
*/
- if (current_time - tcadj_time >= (1 << sys_poll)) {
+ if (pps_control)
+ time_constant = 0;
+ else if (current_time - tcadj_time >= (1 << sys_poll) && !pps_control) {
tcadj_time = current_time;
tmp = offset;
if (tmp < 0)
@@ -607,8 +648,8 @@ local_clock(fp_offset, peer)
#ifdef DEBUG
if (debug > 1)
printf("adj %s, drft %s, tau %3i\n",
- mfptoa((clock_adjust<0?-1:0), clock_adjust, 9),
- fptoa(drift_comp, 9), time_constant);
+ mfptoa((clock_adjust<0?-1:0), clock_adjust, 6),
+ fptoa(drift_comp, 6), time_constant);
#endif /* DEBUG */
(void) record_loop_stats(&last_offset, &drift_comp, time_constant);
@@ -662,20 +703,20 @@ adj_host_clock()
}
}
#endif /* PPSPPS */
- if (pps_time != 0 && current_time - pps_time > PPS_MAXAGE)
- pps_time = 0;
- if (pps_update != 0 && current_time - pps_update > PPS_MAXUPDATE)
- pps_update = 0;
- if (pps_time != 0 && pps_update != 0) {
+#endif /* PPS || PPSCLK || PPSPPS */
+ if (pps_time && current_time - pps_time > PPS_MAXAGE)
+ pps_time = 0;
+ if (pps_update && current_time - pps_update > PPS_MAXUPDATE)
+ pps_update = 0;
+ if (pps_time && pps_update) {
if (!pps_control)
- syslog(LOG_INFO, "pps synch");
+ syslog(LOG_INFO, "PPS synch");
pps_control = 1;
} else {
if (pps_control)
- syslog(LOG_INFO, "pps synch lost");
+ syslog(LOG_INFO, "PPS synch lost");
pps_control = 0;
}
-#endif /* PPS || PPSCLK || PPSPPS */
/*
* Resist the following code if the phase-lock loop has been
@@ -722,22 +763,27 @@ loop_config(item, lfp_value, int_value)
tmp = LFPTOFP(lfp_value);
if (tmp >= max_comp || tmp <= -max_comp) {
syslog(LOG_ERR,
- "loop_config: skew compensation %s too large",
+ "loop_config: frequency offset %s in ntp.conf file is too large",
fptoa(tmp, 5));
} else {
drift_comp = tmp;
#if defined(KERNEL_PLL)
/*
- * If the phase-lock code is implemented in the kernel,
- * give the time_constant and saved frequency offset
- * to the kernel. If not, no harm is done.
+ * If the phase-lock code is implemented in the
+ * kernel, give the time_constant and saved
+ * frequency offset to the kernel. If not, no
+ * harm is done.
*/
pll_control = 1;
- ntv.mode = ADJ_FREQUENCY | ADJ_STATUS | ADJ_TIMECONST;
- ntv.status = TIME_BAD;
- ntv.time_constant = time_constant;
- ntv.frequency = drift_comp;
+ pll_status = STA_PLL | STA_PPSFREQ;
+ ntv.modes = MOD_BITS | MOD_FREQUENCY;
+ ntv.offset = 0;
+ ntv.freq = drift_comp;
+ ntv.maxerror = NTP_MAXDISPERSE;
+ ntv.esterror = NTP_MAXDISPERSE;
+ ntv.status = pll_status | STA_UNSYNC;
+ ntv.constant = time_constant;
newsigsys.sv_handler = pll_trap;
newsigsys.sv_mask = 0;
newsigsys.sv_flags = 0;
@@ -748,13 +794,13 @@ loop_config(item, lfp_value, int_value)
if ((sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)))
syslog(LOG_ERR,
"sigvec() fails to restore SIGSYS trap: %m\n");
- syslog(LOG_NOTICE,
- "%susing kernel phase-lock loop",
- (pll_control) ? "" : "Not ");
-#if DEBUG
- if (debug)
- printf("pll_control %d\n", pll_control);
-#endif
+ if (pll_control)
+ syslog(LOG_NOTICE,
+ "using kernel phase-lock loop %04x",
+ ntv.status);
+ else
+ syslog(LOG_NOTICE,
+ "using xntpd phase-lock loop");
#endif /* KERNEL_PLL */
}
@@ -812,7 +858,7 @@ loop_config(item, lfp_value, int_value)
* _trap - trap processor for undefined syscalls
*
* This nugget is called by the kernel when the SYS_ntp_adjtime()
- * syscall bombs because the silly thing has not been implemented int
+ * syscall bombs because the silly thing has not been implemented in
* the kernel. In this case the phase-lock loop is emulated by
* the stock adjtime() syscall and a lot of indelicate abuse.
*/
@@ -873,12 +919,14 @@ int pps_sample(tsr)
int i, j; /* temp ints */
LONG sort[NPPS]; /* temp array for sorting */
l_fp lftemp, ts; /* l_fp temps */
+ u_fp utemp; /* u_fp temp */
LONG ltemp; /* long temp */
/*
* Note the seconds offset is already in the low-order timestamp
- * doubleword, so all we have to do is sign-extend and invert it.
- * The resulting offset is believed only if within CLOCK_MAX.
+ * doubleword, so all we have to do is sign-extend and invert
+ * it. The resulting offset is believed only if within
+ * CLOCK_MAX.
*/
ts = *tsr;
lftemp.l_i = lftemp.l_f = 0;
@@ -934,14 +982,14 @@ int pps_sample(tsr)
}
lftemp.l_i = 0;
lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM];
- sys_maxd = LFPTOFP(&lftemp);
+ pps_dispersion = LFPTOFP(&lftemp);
#ifdef DEBUG
if (debug)
printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6),
lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5));
#endif /* DEBUG */
- record_peer_stats(&loopback_interface->sin, ctlsysstatus(), &pps_offset,
- sys_rootdelay, sys_rootdispersion);
+ record_peer_stats(&loopback_interface->sin, ctlsysstatus(),
+ &pps_offset, 0, pps_dispersion);
return (0);
}
#endif /* PPS || PPSCLK || PPSPPS */
diff --git a/contrib/xntpd/xntpd/ntp_monitor.c b/contrib/xntpd/xntpd/ntp_monitor.c
index 63af8d4d4d97..e2d2eb51adac 100644
--- a/contrib/xntpd/xntpd/ntp_monitor.c
+++ b/contrib/xntpd/xntpd/ntp_monitor.c
@@ -58,7 +58,7 @@
static struct mon_data *mon_hash; /* Pointer to array of hash buckets */
static int *mon_hash_count; /* Point to hash count stats keeper */
struct mon_data mon_mru_list;
-
+ struct mon_data mon_fifo_list;
/*
* List of free structures structures, and counters of free and total
* structures. The free structures are linked with the hash_next field.
@@ -93,7 +93,7 @@ init_mon()
* Don't do much of anything here. We don't allocate memory
* until someone explicitly starts us.
*/
- mon_enabled = 0;
+ mon_enabled = MON_OFF;
mon_have_memory = 0;
mon_free_mem = 0;
@@ -103,6 +103,7 @@ init_mon()
mon_hash = 0;
mon_hash_count = 0;
memset((char *)&mon_mru_list, 0, sizeof mon_mru_list);
+ memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list);
}
@@ -110,13 +111,18 @@ init_mon()
* mon_start - start up the monitoring software
*/
void
-mon_start()
+mon_start(mode)
+ int mode;
{
register struct mon_data *md;
register int i;
- if (mon_enabled)
+ if (mon_enabled != MON_OFF) {
+ mon_enabled |= mode;
return;
+ }
+ if (mode == MON_OFF)
+ return; /* Ooops.. */
if (!mon_have_memory) {
mon_hash = (struct mon_data *)
@@ -142,7 +148,10 @@ mon_start()
mon_mru_list.mru_next = &mon_mru_list;
mon_mru_list.mru_prev = &mon_mru_list;
- mon_enabled = 1;
+ mon_fifo_list.fifo_next = &mon_fifo_list;
+ mon_fifo_list.fifo_prev = &mon_fifo_list;
+
+ mon_enabled = mode;
}
@@ -150,12 +159,19 @@ mon_start()
* mon_stop - stop the monitoring software
*/
void
-mon_stop()
+mon_stop(mode)
+ int mode;
{
register struct mon_data *md;
register int i;
- if (!mon_enabled)
+ if (mon_enabled == MON_OFF)
+ return;
+ if ((mon_enabled & mode) == 0 || mode == MON_OFF)
+ return;
+
+ mon_enabled &= ~mode;
+ if (mon_enabled != MON_OFF)
return;
/*
@@ -176,7 +192,8 @@ mon_stop()
mon_mru_list.mru_next = &mon_mru_list;
mon_mru_list.mru_prev = &mon_mru_list;
- mon_enabled = 0;
+ mon_fifo_list.fifo_next = &mon_fifo_list;
+ mon_fifo_list.fifo_prev = &mon_fifo_list;
}
@@ -194,7 +211,7 @@ monitor(rbufp)
register int mode;
register struct mon_data *mdhash;
- if (!mon_enabled)
+ if (mon_enabled == MON_OFF)
return;
pkt = &rbufp->recv_pkt;
@@ -220,6 +237,7 @@ monitor(rbufp)
md->mru_prev = &mon_mru_list;
mon_mru_list.mru_next->mru_prev = md;
mon_mru_list.mru_next = md;
+
return;
}
md = md->hash_next;
@@ -240,6 +258,12 @@ monitor(rbufp)
md->hash_next->hash_prev = md->hash_prev;
md->hash_prev->hash_next = md->hash_next;
*(mon_hash_count + MON_HASH(md->rmtadr)) -= 1;
+ /*
+ * Get it from FIFO list
+ */
+ md->fifo_prev->fifo_next = md->fifo_next;
+ md->fifo_next->fifo_prev = md->fifo_prev;
+
} else {
if (mon_free_mem == 0)
mon_getmoremem();
@@ -252,6 +276,7 @@ monitor(rbufp)
* Got one, initialize it
*/
md->lasttime = md->firsttime = current_time;
+ md->lastdrop = 0;
md->count = 1;
md->rmtadr = netnum;
md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
@@ -260,7 +285,8 @@ monitor(rbufp)
/*
* Shuffle him into the hash table, inserting him at the
- * end. Also put him on top of the MRU list.
+ * end. Also put him on top of the MRU list
+ * and at bottom of FIFO list
*/
mdhash = mon_hash + MON_HASH(netnum);
md->hash_next = mdhash;
@@ -273,6 +299,11 @@ monitor(rbufp)
md->mru_prev = &mon_mru_list;
mon_mru_list.mru_next->mru_prev = md;
mon_mru_list.mru_next = md;
+
+ md->fifo_prev = mon_fifo_list.fifo_prev;
+ md->fifo_next = &mon_fifo_list;
+ mon_fifo_list.fifo_prev->fifo_next = md;
+ mon_fifo_list.fifo_prev = md;
}
diff --git a/contrib/xntpd/xntpd/ntp_peer.c b/contrib/xntpd/xntpd/ntp_peer.c
index cadd415346a9..9d8ec35dee78 100644
--- a/contrib/xntpd/xntpd/ntp_peer.c
+++ b/contrib/xntpd/xntpd/ntp_peer.c
@@ -340,22 +340,24 @@ unpeer(peer_to_remove)
* peer_config - configure a new peer
*/
struct peer *
-peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, key, flags)
+peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, flags, ttl, key)
struct sockaddr_in *srcadr;
struct interface *dstadr;
int hmode;
int version;
int minpoll;
int maxpoll;
- U_LONG key;
int flags;
+ int ttl;
+ U_LONG key;
{
register struct peer *peer;
#ifdef DEBUG
if (debug)
- printf("peer_config: addr %s mode %d version %d minpoll %d maxpoll %d key %u\n",
- ntoa(srcadr), hmode, version, minpoll, maxpoll, key);
+ printf("peer_config: addr %s mode %d version %d minpoll %d maxpoll %d flags %d ttl %d key %u\n",
+ ntoa(srcadr), hmode, version, minpoll, maxpoll, flags,
+ ttl, key);
#endif
/*
* See if we have this guy in the tables already. If
@@ -387,6 +389,7 @@ peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, key, flags)
peer->ppoll = peer->minpoll;
peer->flags = ((u_char)(flags|FLAG_CONFIG))
|(peer->flags & (FLAG_REFCLOCK|FLAG_DEFBDELAY));
+ peer->ttl = (u_char)ttl;
peer->keyid = key;
return peer;
}
@@ -395,7 +398,8 @@ peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, key, flags)
* If we're here this guy is unknown to us. Make a new peer
* structure for him.
*/
- peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, key);
+ peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
+ ttl, key);
if (peer != 0)
peer->flags |= (u_char)(flags|FLAG_CONFIG);
return peer;
@@ -406,13 +410,14 @@ peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, key, flags)
* newpeer - initialize a new peer association
*/
struct peer *
-newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, key)
+newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, ttl, key)
struct sockaddr_in *srcadr;
struct interface *dstadr;
int hmode;
int version;
int minpoll;
int maxpoll;
+ int ttl;
U_LONG key;
{
register struct peer *peer;
@@ -454,13 +459,10 @@ newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, key)
peer->maxpoll = (u_char)maxpoll;
peer->hpoll = peer->minpoll;
peer->ppoll = peer->minpoll;
+ peer->ttl = ttl;
peer->keyid = key;
-
- if (hmode == MODE_BCLIENT) {
- peer->estbdelay = sys_bdelay;
- peer->flags |= FLAG_DEFBDELAY;
- }
-
+ peer->estbdelay = sys_bdelay;
+ peer->flags |= FLAG_DEFBDELAY;
peer->leap = LEAP_NOTINSYNC;
peer->precision = DEFPRECISION;
peer->dispersion = NTP_MAXDISPERSE;
diff --git a/contrib/xntpd/xntpd/ntp_proto.c b/contrib/xntpd/xntpd/ntp_proto.c
index 88e95bbf8d13..a3f744eae881 100644
--- a/contrib/xntpd/xntpd/ntp_proto.c
+++ b/contrib/xntpd/xntpd/ntp_proto.c
@@ -25,7 +25,7 @@ l_fp sys_reftime; /* time we were last updated */
l_fp sys_refskew; /* accumulated skew since last update */
struct peer *sys_peer; /* our current peer */
u_char sys_poll; /* log2 of desired system poll interval */
-LONG sys_clock; /* second part of current time */
+extern LONG sys_clock; /* second part of current time - now in systime.c */
LONG sys_lastselect; /* sys_clock at last synch-dist update */
/*
@@ -48,7 +48,7 @@ U_LONG sys_unknownversion; /* don't know version packets */
U_LONG sys_badlength; /* packets with bad length */
U_LONG sys_processed; /* packets processed */
U_LONG sys_badauth; /* packets dropped because of authorization */
-U_LONG sys_wanderhold; /* sys_peer held to prevent wandering */
+U_LONG sys_limitrejected; /* pkts rejected due toclient count per net */
/*
* Imported from ntp_timer.c
@@ -90,7 +90,8 @@ transmit(peer)
struct pkt xpkt; /* packet to send */
U_LONG peer_timer;
- if (peer->hmode != MODE_BCLIENT) {
+ if ((peer->hmode != MODE_BROADCAST && peer->hmode != MODE_BCLIENT) ||
+ (peer->hmode == MODE_BROADCAST && sys_leap != LEAP_NOTINSYNC)) {
U_LONG xkeyid;
/*
@@ -239,17 +240,14 @@ transmit(peer)
/*
* Finally, adjust the hpoll variable for special conditions.
*/
- if (peer->flags & FLAG_SYSPEER && peer->hpoll > sys_poll) {
- /* clamp it */
+ if (peer->hmode == MODE_BCLIENT)
+ peer->hpoll = peer->ppoll;
+ else if (peer->flags & FLAG_SYSPEER &&
+ peer->hpoll > sys_poll)
peer->hpoll = max(peer->minpoll, sys_poll);
- }
- if (peer->hmode == MODE_BROADCAST || peer->hmode == MODE_BCLIENT) {
- /* clamp it */
- peer->hpoll = peer->minpoll;
- }
/*
- * Arrange for our next time out. hpoll will be less than
+ * Arrange for our next timeout. hpoll will be less than
* maxpoll for sure.
*/
if (peer->event_timer.next != 0)
@@ -262,37 +260,6 @@ transmit(peer)
TIMER_ENQUEUE(timerqueue, &peer->event_timer);
}
-#if 0
-static void
-ct_die(after)
-{
- syslog(LOG_ERR, "timers garbled (%s)", after?"after":"before");
- abort();
-}
-
-void
-check_timers(after)
-{
- register int i;
- register struct event *p, *q;
-
- for (i = 0; i < TIMER_NSLOTS; i++) {
- p = &timerqueue[i];
- if (p->event_time != 0)
- ct_die(after);
- do {
- q = p;
- if ((p = p->next) == 0)
- ct_die(after);
- if (p->prev != q)
- ct_die(after);
- } while (p->event_time != 0);
- if (p != &timerqueue[i])
- ct_die(after);
- }
-}
-#endif
-
/*
* receive - Receive Procedure. See section 3.4.2 in the specification.
*/
@@ -373,6 +340,21 @@ receive(rbufp)
return;
/*
+ * See if we only accept limited number of clients
+ * from the net this guy is from.
+ * Note: the flag is determined dynamically within restrictions()
+ */
+ if (restrict & RES_LIMITED) {
+ extern U_LONG client_limit;
+
+ sys_limitrejected++;
+ syslog(LOG_NOTICE,
+ "rejected mode %d request from %s - per net client limit (%d) exceeded",
+ PKT_MODE(pkt->li_vn_mode),
+ ntoa(&rbufp->recv_srcadr), client_limit);
+ return;
+ }
+ /*
* Dump anything with a putrid stratum. These will most likely
* come from someone trying to poll us with ntpdc.
*/
@@ -517,6 +499,9 @@ receive(rbufp)
break;
case MODE_PASSIVE:
+#ifdef MCAST
+ /* process the packet to determine the rt-delay */
+#endif /* MCAST */
case MODE_SERVER:
/*
* These are obvious errors. Ignore.
@@ -534,8 +519,10 @@ receive(rbufp)
/*
* Sort of a repeat of the above...
*/
+/*
if ((restrict & RES_NOPEER) || !sys_bclient)
return;
+*/
mymode = MODE_BCLIENT;
break;
}
@@ -546,7 +533,7 @@ receive(rbufp)
*/
peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, mymode,
PKT_VERSION(pkt->li_vn_mode), NTP_MINDPOLL,
- NTP_MAXPOLL, hiskeyid);
+ NTP_MAXPOLL, 0, hiskeyid);
if (peer == 0) {
/*
* The only way this can happen is if the
@@ -706,12 +693,11 @@ receive(rbufp)
* out to be bad.
*/
peer2 = newpeer(&rbufp->recv_srcadr,
- rbufp->dstadr, MODE_PASSIVE,
- PKT_VERSION(pkt->li_vn_mode),
- NTP_MINDPOLL, NTP_MAXPOLL,
- hiskeyid);
+ rbufp->dstadr, MODE_PASSIVE,
+ PKT_VERSION(pkt->li_vn_mode),
+ NTP_MINDPOLL, NTP_MAXPOLL, 0, hiskeyid);
if (process_packet(peer2, pkt, &rbufp->recv_time,
- has_mac, trustable) == 0) {
+ has_mac, trustable) == 0) {
/*
* Strange situation. We've been receiving
* broadcasts from him which we liked, but
@@ -769,20 +755,21 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
sys_processed++;
peer->processed++;
-
- peer->rec = *recv_ts;
p_dist = NTOHS_FP(pkt->rootdelay);
p_disp = NTOHS_FP(pkt->rootdispersion);
NTOHL_FP(&pkt->rec, &p_rec);
NTOHL_FP(&pkt->xmt, &p_xmt);
- NTOHL_FP(&pkt->org, &p_org);
+ if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST)
+ NTOHL_FP(&pkt->org, &p_org);
+ else
+ p_org = peer->rec;
+ peer->rec = *recv_ts;
peer->flash = 0;
randomize = POLL_RANDOMCHANGE;
/*
* Test for old or duplicate packets (tests 1 through 3).
*/
-
if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */
peer->oldpkt++;
if (L_ISEQU(&peer->org, &p_xmt)) /* test 1 */
@@ -796,6 +783,9 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
if ((p_rec.l_ui == 0 && p_rec.l_uf == 0) ||
(p_org.l_ui == 0 && p_org.l_uf == 0))
peer->flash |= TEST3; /* unsynchronized */
+ } else {
+ if (p_org.l_ui == 0 && p_org.l_uf == 0)
+ peer->flash |= TEST3; /* unsynchronized */
}
peer->org = p_xmt; /* reuse byte-swapped pkt->xmt */
peer->ppoll = pkt->ppoll;
@@ -901,39 +891,23 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
ci.l_ui = t10_ui;
ci.l_uf = t10_uf;
ei = (FP_SECOND >> (-(int)sys_precision));
- if (peer->hmode == MODE_BCLIENT) {
-#ifdef notdef
- if (PKT_MODE(pkt->li_vn_mode) == MODE_CLIENT) {
- /*
- * A client mode packet, used for delay computation.
- * Give the data to the filter.
- */
- bdelay_filter(peer, t23_ui, t23_uf, t10_ui, t10_uf);
- }
-#endif
- M_ADDUF(ci.l_ui, ci.l_uf, peer->estbdelay>>1);
+
+ /*
+ * If broadcast mode, time of last reception has been fiddled
+ * to p_org, rather than originate timestamp. We use this to
+ * augment dispersion and previously calcuated estbdelay as
+ * the delay. We know NTP_SKEWFACTOR == 16, which accounts for
+ * the simplified ei calculation.
+ */
+ if (PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST) {
+ M_ADDUF(ci.l_ui, ci.l_uf, peer->estbdelay >> 1);
di = MFPTOFP(0, peer->estbdelay);
+ ei += peer->rec.l_ui - p_org.l_ui;
} else {
M_ADD(ci.l_ui, ci.l_uf, t23_ui, t23_uf);
M_RSHIFT(ci.l_i, ci.l_uf);
-
- /*
- * Calculate di in t23 in full precision, then truncate
- * to an s_fp.
- */
M_SUB(t23_ui, t23_uf, t10_ui, t10_uf);
di = MFPTOFP(t23_ui, t23_uf);
- /*
- * Calculate (t3 - t0) in t23 in full precision, convert
- * to single, shift down by MAXSKEW and add to ei.
- * We know NTP_SKEWFACTOR == 16
- */
-#if 0
- t23_ui = peer->rec.l_ui; /* peer->rec == t0 */
- t23_uf = peer->rec.l_uf;
- M_SUB(t23_ui, t23_uf, p_org.l_ui, p_org.l_uf); /*pkt->org==t3*/
- ei += (MFPTOFP(t23_ui, t23_uf) >> NTP_SKEWFACTOR);
-#endif
ei += peer->rec.l_ui - p_org.l_ui;
}
#ifdef DEBUG
@@ -1057,9 +1031,7 @@ clock_update(peer)
if (d < 0)
d = -d;
sys_rootdelay = peer->rootdelay + d;
- sys_maxd = peer->dispersion;
- if (peer->flags & FLAG_PREFER)
- sys_maxd += peer->selectdisp;
+ sys_maxd = peer->dispersion + peer->selectdisp;
d = peer->soffset;
if (d < 0)
d = -d;
@@ -1155,7 +1127,7 @@ poll_update(peer, new_hpoll, randomize)
* Catch reference clocks here. The polling interval for a
* reference clock is fixed and needn't be maintained by us.
*/
- if (peer->flags & FLAG_REFCLOCK)
+ if (peer->flags & FLAG_REFCLOCK || peer->hmode == MODE_BROADCAST)
return;
/*
@@ -1177,7 +1149,9 @@ poll_update(peer, new_hpoll, randomize)
* less that peer.timer, update peer.timer.
*/
oldpoll = peer->hpoll;
- if ((peer->flags & FLAG_SYSPEER) && new_hpoll > sys_poll)
+ if (peer->hmode == MODE_BCLIENT)
+ peer->hpoll = peer->ppoll;
+ else if ((peer->flags & FLAG_SYSPEER) && new_hpoll > sys_poll)
peer->hpoll = max(peer->minpoll, sys_poll);
else {
if (new_hpoll > peer->maxpoll)
@@ -1192,10 +1166,10 @@ poll_update(peer, new_hpoll, randomize)
newpoll = max((u_char)min(peer->ppoll, peer->hpoll), peer->minpoll);
if (randomize == POLL_MAKERANDOM ||
(randomize == POLL_RANDOMCHANGE && newpoll != oldpoll))
- new_timer = (1<<(newpoll - 1))
+ new_timer = (1 << (newpoll - 1))
+ ranp2(newpoll - 1) + current_time;
else
- new_timer = (1<<newpoll) + current_time;
+ new_timer = (1 << newpoll) + current_time;
evp = &(peer->event_timer);
if (evp->next == 0 || evp->event_time > new_timer) {
TIMER_DEQUEUE(evp);
@@ -1342,26 +1316,10 @@ clock_filter(peer, sample_offset, sample_delay, sample_error)
/*
* Find where he goes in, then shift everyone else down
*/
- if (peer->hmode == MODE_BCLIENT) {
- register s_fp *soffsetp;
- /*
- * Sort by offset. The most positive offset
- * should correspond to the minimum delay.
- */
- soffsetp = peer->filter_soffset;
- for (i = 0; i < NTP_SHIFT-1; i++)
- if (errorp[ord[i]] >= NTP_MAXDISPERSE
- || sample_soffset >= soffsetp[ord[i]])
- break;
- } else {
- /*
- * Sort by distance.
- */
- for (i = 0; i < NTP_SHIFT-1; i++)
- if (errorp[ord[i]] >= NTP_MAXDISPERSE
- || sample_distance <= distance[ord[i]])
- break;
- }
+ for (i = 0; i < NTP_SHIFT-1; i++)
+ if (errorp[ord[i]] >= NTP_MAXDISPERSE
+ || sample_distance <= distance[ord[i]])
+ break;
for (j = NTP_SHIFT-1; j > i; j--)
ord[j] = ord[j-1];
@@ -1676,7 +1634,7 @@ clock_select()
if (d < 0)
d = -d;
sdisp += d;
- sdisp = ((sdisp>>1) + sdisp) >> 1;
+ sdisp = ((sdisp >> 1) + sdisp) >> 1;
}
peer_list[i]->selectdisp = sdisp;
if (sdisp > maxd) {
@@ -1729,9 +1687,7 @@ clock_select()
for (i = 1; i < nlist; i++)
if (peer_list[i] == sys_peer)
break;
- if (i < nlist)
- sys_wanderhold++;
- else
+ if (i >= nlist)
sys_peer = peer_list[0];
}
@@ -2064,7 +2020,6 @@ init_proto()
sys_unknownversion = 0;
sys_processed = 0;
sys_badauth = 0;
- sys_wanderhold = 0;
syslog(LOG_NOTICE, "default precision is initialized to 2**%d", sys_precision);
}
@@ -2076,7 +2031,7 @@ init_proto()
void
proto_config(item, value)
int item;
- LONG value;
+ U_LONG value;
{
/*
* Figure out what he wants to change, then do it
@@ -2087,11 +2042,33 @@ proto_config(item, value)
* Turn on/off facility to listen to broadcasts
*/
sys_bclient = (int)value;
- if (sys_bclient)
+ if (value)
io_setbclient();
else
io_unsetbclient();
break;
+
+ case PROTO_MULTICAST_ADD:
+ /*
+ * Add multicast group address
+ */
+ if (!sys_bclient) {
+ sys_bclient = 1;
+ io_setbclient();
+ }
+#ifdef MCAST
+ io_multicast_add(value);
+#endif /* MCAST */
+ break;
+
+ case PROTO_MULTICAST_DEL:
+ /*
+ * Delete multicast group address
+ */
+#ifdef MCAST
+ io_multicast_del(value);
+#endif /* MCAST */
+ break;
case PROTO_PRECISION:
/*
@@ -2104,7 +2081,7 @@ proto_config(item, value)
/*
* Set default broadcast delay
*/
- sys_bdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000;
+ sys_bdelay = ((value) + 0x00000800) & 0xfffff000;
break;
case PROTO_AUTHENTICATE:
@@ -2120,23 +2097,7 @@ proto_config(item, value)
* Provide an authentication delay value. Round it to
* the microsecond. This is crude.
*/
- sys_authdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000;
- break;
-
- case PROTO_MAXSKEW:
- /*
- * Set the maximum skew value
- */
- syslog(LOG_ERR,
- "proto_config: attempt to set maxskew (obsolete)");
- break;
-
- case PROTO_SELECT:
- /*
- * Set the selection algorithm.
- */
- syslog(LOG_ERR,
- "proto_config: attempt to set selection algorithm (obsolete)");
+ sys_authdelay = ((value) + 0x00000800) & 0xfffff000;
break;
default:
@@ -2163,6 +2124,6 @@ proto_clr_stats()
sys_badlength = 0;
sys_processed = 0;
sys_badauth = 0;
- sys_wanderhold = 0;
sys_stattime = current_time;
+ sys_limitrejected = 0;
}
diff --git a/contrib/xntpd/xntpd/ntp_refclock.c b/contrib/xntpd/xntpd/ntp_refclock.c
index 5199a1acbd26..2cb7cc29d9a4 100644
--- a/contrib/xntpd/xntpd/ntp_refclock.c
+++ b/contrib/xntpd/xntpd/ntp_refclock.c
@@ -93,17 +93,6 @@ refclock_newpeer(peer)
peer->stratum = STRATUM_REFCLOCK;
peer->ppoll = peer->minpoll;
peer->hpoll = peer->minpoll;
- peer->maxpoll = peer->minpoll;
-
- /*
- * Check the flags. If the peer is configured in client mode
- * but prefers the broadcast client filter algorithm, change
- * him over.
- */
- if (peer->hmode == MODE_CLIENT
- && refclock_conf[clktype]->clock_flags & REF_FLAG_BCLIENT)
- peer->hmode = MODE_BCLIENT;
-
peer->event_timer.peer = peer;
peer->event_timer.event_handler = refclock_transmit;
@@ -201,20 +190,14 @@ refclock_transmit(peer)
l_fp off;
- if (peer->valid > 0) peer->valid--;
- if (peer->hpoll > peer->minpoll) peer->hpoll--;
+ if (peer->valid > 0)
+ peer->valid--;
off.l_ui = off.l_uf = 0;
clock_filter(peer, &off, 0, NTP_MAXDISPERSE);
if (peer->flags & FLAG_SYSPEER)
- clock_select();
- } else {
- if (peer->valid < NTP_SHIFT) {
- peer->valid++;
- } else {
- if (peer->hpoll < peer->maxpoll)
- peer->hpoll++;
- }
- }
+ clock_select();
+ } else if (peer->valid < NTP_SHIFT)
+ peer->valid++;
/*
* If he wants to be polled, do it.
@@ -313,9 +296,6 @@ refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)
case MODE_CLIENT:
peer->pmode = MODE_SERVER;
break;
- case MODE_BCLIENT:
- peer->pmode = MODE_BROADCAST;
- break;
default:
syslog(LOG_ERR, "refclock_receive: internal error, mode = %d",
peer->hmode);
diff --git a/contrib/xntpd/xntpd/ntp_request.c b/contrib/xntpd/xntpd/ntp_request.c
index c19d1925a818..355b13b42b28 100644
--- a/contrib/xntpd/xntpd/ntp_request.c
+++ b/contrib/xntpd/xntpd/ntp_request.c
@@ -16,6 +16,14 @@
#include "ntp_if.h"
#include "ntp_stdlib.h"
+#ifdef KERNEL_PLL
+#include <sys/timex.h>
+#ifndef NTP_SYSCALLS_LIBC
+#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
+#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
+#endif
+#endif /* KERNEL_PLL */
+
/*
* Structure to hold request procedure information
*/
@@ -56,7 +64,7 @@ static void do_conf P((struct sockaddr_in *, struct interface *, struct req_pkt
static void do_unconf P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void set_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void clr_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
-static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, int));
+static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, U_LONG));
static void do_monitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_nomonitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void list_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *));
@@ -83,13 +91,14 @@ static void set_request_keyid P((struct sockaddr_in *, struct interface *, struc
static void set_control_keyid P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void get_ctl_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void get_leap_info P((struct sockaddr_in *, struct interface *, struct req_pkt *));
+#ifdef KERNEL_PLL
+static void get_kernel_info P((struct sockaddr_in *, struct interface *, struct req_pkt *));
+#endif /* KERNEL_PLL */
#ifdef REFCLOCK
static void get_clock_info P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void set_clock_fudge P((struct sockaddr_in *, struct interface *, struct req_pkt *));
#endif /* REFCLOCK */
-static void set_maxskew P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void set_precision P((struct sockaddr_in *, struct interface *, struct req_pkt *));
-static void set_select_code P((struct sockaddr_in *, struct interface *, struct req_pkt *));
#ifdef REFCLOCK
static void get_clkbug_info P((struct sockaddr_in *, struct interface *, struct req_pkt *));
#endif /* REFCLOCK */
@@ -134,9 +143,10 @@ static struct req_proc xntp_codes[] = {
{ REQ_CONTROL_KEY, AUTH, sizeof(U_LONG), set_control_keyid },
{ REQ_GET_CTLSTATS, NOAUTH, 0, get_ctl_stats },
{ REQ_GET_LEAPINFO, NOAUTH, 0, get_leap_info },
- { REQ_SET_MAXSKEW, AUTH, sizeof(u_fp), set_maxskew },
{ REQ_SET_PRECISION, AUTH, sizeof(LONG), set_precision },
- { REQ_SET_SELECT_CODE, AUTH, sizeof(U_LONG), set_select_code },
+#ifdef KERNEL_PLL
+ { REQ_GET_KERNEL, NOAUTH, 0, get_kernel_info },
+#endif /* KERNEL_PLL */
#ifdef REFCLOCK
{ REQ_GET_CLOCKINFO, NOAUTH, sizeof(U_LONG), get_clock_info },
{ REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), set_clock_fudge },
@@ -162,6 +172,10 @@ U_LONG numresppkts; /* number of resp packets sent with data */
U_LONG errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
/* by the error code */
+#if defined(KERNEL_PLL) && !defined(NTP_SYSCALLS_LIBC)
+extern int syscall P((int, void *, ...));
+#endif /* KERNEL_PLL */
+
/*
* Imported from the I/O module
*/
@@ -178,6 +192,11 @@ extern int debug;
extern U_LONG current_time;
/*
+ * Imported from ntp_loopfilter.c
+ */
+extern int pll_control;
+
+/*
* A hack. To keep the authentication module clear of xntp-ism's, we
* include a time reset variable for its stats here.
*/
@@ -657,6 +676,7 @@ peer_list_sum(srcadr, inter, inpkt)
ips->delay = HTONS_FP(pp->delay);
HTONL_FP(&pp->offset, &ips->offset);
ips->dispersion = HTONS_FP(pp->dispersion);
+
pp = pp->next;
ips = (struct info_peer_summary *)more_pkt();
}
@@ -724,7 +744,9 @@ peer_info (srcadr, inter, inpkt)
ip->valid = pp->valid;
ip->reach = pp->reach;
ip->unreach = pp->unreach;
- ip->trust = 0;
+ ip->flash = pp->flash;
+ ip->estbdelay = htonl(pp->estbdelay);
+ ip->ttl = pp->ttl;
ip->associd = htons(pp->associd);
ip->rootdelay = HTONS_FP(pp->rootdelay);
ip->rootdispersion = HTONS_FP(pp->rootdispersion);
@@ -745,12 +767,10 @@ peer_info (srcadr, inter, inpkt)
if (ip->order[i] >= NTP_SHIFT)
ip->order[i] -= NTP_SHIFT;
}
- ip->delay = HTONS_FP(pp->delay);
HTONL_FP(&pp->offset, &ip->offset);
+ ip->delay = HTONS_FP(pp->delay);
ip->dispersion = HTONS_FP(pp->dispersion);
- for (i = 0; i < NTP_SHIFT; i++)
- ip->bdelay[i] = 0;
- ip->estbdelay = htonl(pp->estbdelay);
+ ip->selectdisp = HTONS_FP(pp->selectdisp);
ip = (struct info_peer *)more_pkt();
}
flush_pkt();
@@ -882,12 +902,8 @@ sys_info(srcadr, inter, inpkt)
is->flags |= INFO_FLAG_BCLIENT;
if (sys_authenticate)
is->flags |= INFO_FLAG_AUTHENABLE;
- is->selection = 0; /* Obsolete */
-
HTONL_UF(sys_bdelay, &is->bdelay);
HTONL_UF(sys_authdelay, &is->authdelay);
- is->maxskew = 0;
-
(void) more_pkt();
flush_pkt();
}
@@ -915,7 +931,7 @@ sys_stats(srcadr, inter, inpkt)
extern U_LONG sys_badlength;
extern U_LONG sys_processed;
extern U_LONG sys_badauth;
- extern U_LONG sys_wanderhold;
+ extern U_LONG sys_limitrejected;
ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys_stats));
@@ -929,8 +945,7 @@ sys_stats(srcadr, inter, inpkt)
ss->badlength = htonl(sys_badlength);
ss->processed = htonl(sys_processed);
ss->badauth = htonl(sys_badauth);
- ss->wanderhold = htonl(sys_wanderhold);
-
+ ss->limitrejected = htonl(sys_limitrejected);
(void) more_pkt();
flush_pkt();
}
@@ -1167,7 +1182,7 @@ do_conf(srcadr, inter, inpkt)
/* XXX W2DO? minpoll/maxpoll arguments ??? */
if (peer_config(&peeraddr, (struct interface *)0,
cp->hmode, cp->version, cp->minpoll, cp->maxpoll,
- cp->keyid, fl) == 0) {
+ fl, cp->ttl, cp->keyid) == 0) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
@@ -1252,7 +1267,7 @@ set_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, 1);
+ setclr_flags(srcadr, inter, inpkt, (U_LONG)1);
}
@@ -1265,7 +1280,7 @@ clr_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, 0);
+ setclr_flags(srcadr, inter, inpkt, (U_LONG)0);
}
@@ -1277,7 +1292,7 @@ setclr_flags(srcadr, inter, inpkt, set)
struct sockaddr_in *srcadr;
struct interface *inter;
struct req_pkt *inpkt;
- int set;
+ U_LONG set;
{
register U_LONG flags;
@@ -1289,15 +1304,20 @@ setclr_flags(srcadr, inter, inpkt, set)
flags = ((struct conf_sys_flags *)inpkt->data)->flags;
if (flags
- & ~(SYS_FLAG_BCLIENT|SYS_FLAG_AUTHENTICATE)) {
+ & ~(SYS_FLAG_BCLIENT | SYS_FLAG_MCLIENT | SYS_FLAG_AUTHENTICATE)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if (flags & SYS_FLAG_BCLIENT)
- proto_config(PROTO_BROADCLIENT, (LONG)set);
+ proto_config(PROTO_BROADCLIENT, set);
+ if (flags & SYS_FLAG_MCLIENT)
+ if (set)
+ proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ else
+ proto_config(PROTO_MULTICAST_DEL, INADDR_NTP);
if (flags & SYS_FLAG_AUTHENTICATE)
- proto_config(PROTO_AUTHENTICATE, (LONG)set);
+ proto_config(PROTO_AUTHENTICATE, set);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1311,7 +1331,7 @@ do_monitor(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- mon_start();
+ mon_start(MON_ON);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1325,7 +1345,7 @@ do_nomonitor(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- mon_stop();
+ mon_stop(MON_ON);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1497,6 +1517,10 @@ mon_getlist(srcadr, inter, inpkt)
md = md->mru_next) {
im->lasttime = htonl(current_time - md->lasttime);
im->firsttime = htonl(current_time - md->firsttime);
+ if (md->lastdrop)
+ im->lastdrop = htonl(current_time - md->lastdrop);
+ else
+ im->lastdrop = 0;
im->count = htonl(md->count);
im->addr = md->rmtadr;
im->port = md->rmtport;
@@ -2079,6 +2103,57 @@ get_leap_info(srcadr, inter, inpkt)
}
+#ifdef KERNEL_PLL
+/*
+ * get_kernel_info - get kernel pll/pps information
+ */
+static void
+get_kernel_info(srcadr, inter, inpkt)
+ struct sockaddr_in *srcadr;
+ struct interface *inter;
+ struct req_pkt *inpkt;
+{
+ register struct info_kernel *ik;
+ struct timex ntx;
+
+ if (!pll_control)
+ return;
+ memset((char *)&ntx, 0, sizeof(ntx));
+ (void)ntp_adjtime(&ntx);
+
+ ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
+ sizeof(struct info_kernel));
+
+ /*
+ * pll variables
+ */
+ ik->offset = htonl(ntx.offset);
+ ik->freq = htonl(ntx.freq);
+ ik->maxerror = htonl(ntx.maxerror);
+ ik->esterror = htonl(ntx.esterror);
+ ik->status = htons(ntx.status);
+ ik->constant = htonl(ntx.constant);
+ ik->precision = htonl(ntx.precision);
+ ik->tolerance = htonl(ntx.tolerance);
+
+ /*
+ * pps variables
+ */
+ ik->ppsfreq = htonl(ntx.ppsfreq);
+ ik->jitter = htonl(ntx.jitter);
+ ik->shift = htons(ntx.shift);
+ ik->stabil = htonl(ntx.stabil);
+ ik->jitcnt = htonl(ntx.jitcnt);
+ ik->calcnt = htonl(ntx.calcnt);
+ ik->errcnt = htonl(ntx.errcnt);
+ ik->stbcnt = htonl(ntx.stbcnt);
+
+ (void) more_pkt();
+ flush_pkt();
+}
+#endif /* KERNEL_PLL */
+
+
#ifdef REFCLOCK
/*
* get_clock_info - get info about a clock
@@ -2204,29 +2279,6 @@ set_clock_fudge(srcadr, inter, inpkt)
#endif
/*
- * set_maxskew - set the system maxskew parameter
- */
-static void
-set_maxskew(srcadr, inter, inpkt)
- struct sockaddr_in *srcadr;
- struct interface *inter;
- struct req_pkt *inpkt;
-{
- register u_fp maxskew;
-
- if (INFO_NITEMS(inpkt->err_nitems) > 1) {
- req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
- return;
- }
-
- maxskew = NTOHS_FP(*(u_fp *)(inpkt->data));
-
- proto_config(PROTO_MAXSKEW, (LONG)maxskew);
- req_ack(srcadr, inter, inpkt, INFO_OKAY);
-}
-
-
-/*
* set_precision - set the system precision
*/
static void
@@ -2249,31 +2301,6 @@ set_precision(srcadr, inter, inpkt)
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
-
-/*
- * set_select_code - set a select code to use
- */
-static void
-set_select_code(srcadr, inter, inpkt)
- struct sockaddr_in *srcadr;
- struct interface *inter;
- struct req_pkt *inpkt;
-{
- register U_LONG select_code;
-
- select_code = ntohl(*(U_LONG *)(inpkt->data));
-
- if (INFO_NITEMS(inpkt->err_nitems) > 1 ||
- select_code < SELECT_1 || select_code > SELECT_5) {
- req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
- return;
- }
-
- proto_config(PROTO_SELECT, (LONG)select_code);
- req_ack(srcadr, inter, inpkt, INFO_OKAY);
-}
-
-
#ifdef REFCLOCK
/*
* get_clkbug_info - get debugging info about a clock
diff --git a/contrib/xntpd/xntpd/ntp_restrict.c b/contrib/xntpd/xntpd/ntp_restrict.c
index 51d896806207..43f01f296624 100644
--- a/contrib/xntpd/xntpd/ntp_restrict.c
+++ b/contrib/xntpd/xntpd/ntp_restrict.c
@@ -1,4 +1,4 @@
-/* ntp_restrict.c,v 3.1 1993/07/06 01:11:28 jbj Exp
+/*
* ntp_restrict.c - find out what restrictions this host is running under
*/
#include <stdio.h>
@@ -60,6 +60,21 @@ U_LONG res_not_found;
U_LONG res_timereset;
/*
+ * Parameters of the RES_LIMITED restriction option.
+ * client_limit is the number of hosts allowed per source net
+ * client_limit_period is the number of seconds after which an entry
+ * is no longer considered for client limit determination
+ */
+U_LONG client_limit;
+U_LONG client_limit_period;
+/*
+ * count number of restriction entries referring to RES_LIMITED
+ * controls activation/deactivation of monitoring
+ * (with respect ro RES_LIMITED control)
+ */
+U_LONG res_limited_refcnt;
+
+/*
* Our initial allocation of list entries.
*/
static struct restrictlist resinit[INITRESLIST];
@@ -70,12 +85,18 @@ static struct restrictlist resinit[INITRESLIST];
extern U_LONG current_time;
/*
+ * debug flag
+ */
+extern int debug;
+
+/*
* init_restrict - initialize the restriction data structures
*/
void
init_restrict()
{
register int i;
+ char bp[80];
/*
* Zero the list and put all but one on the free list
@@ -108,6 +129,18 @@ init_restrict()
res_found = 0;
res_not_found = 0;
res_timereset = 0;
+
+ /*
+ * set default values for RES_LIMIT functionality
+ */
+ client_limit = 3;
+ client_limit_period = 3600;
+ res_limited_refcnt = 0;
+
+ sprintf(bp, "client_limit=%d", client_limit);
+ set_sys_var(bp, strlen(bp)+1, RO);
+ sprintf(bp, "client_limit_period=%d", client_limit_period);
+ set_sys_var(bp, strlen(bp)+1, RO);
}
@@ -150,6 +183,120 @@ restrictions(srcadr)
else
res_found++;
+ /*
+ * The following implements limiting the number of clients
+ * accepted from a given network. The notion of "same network"
+ * is determined by the mask and addr fields of the restrict
+ * list entry. The monitor mechanism has to be enabled for
+ * collecting info on current clients.
+ *
+ * The policy is as follows:
+ * - take the list of clients recorded
+ * from the given "network" seen within the last
+ * client_limit_period seconds
+ * - if there are at most client_limit entries:
+ * --> access allowed
+ * - otherwise sort by time first seen
+ * - current client among the first client_limit seen
+ * hosts?
+ * if yes: access allowed
+ * else: eccess denied
+ */
+ if (match->flags & RES_LIMITED) {
+ int lcnt;
+ struct mon_data *md, *this_client;
+ extern int mon_enabled;
+ extern struct mon_data mon_fifo_list, mon_mru_list;
+
+#ifdef DEBUG
+ if (debug > 2)
+ printf("limited clients check: %d clients, period %d seconds, net is 0x%X\n",
+ client_limit, client_limit_period,
+ netof(hostaddr));
+#endif /*DEBUG*/
+ if (mon_enabled == MON_OFF) {
+#ifdef DEBUG
+ if (debug > 4)
+ printf("no limit - monitoring is off\n");
+#endif
+ return (int)(match->flags & ~RES_LIMITED);
+ }
+
+ /*
+ * How nice, MRU list provides our current client as the
+ * first entry in the list.
+ * Monitoring was verified to be active above, thus we
+ * know an entry for our client must exist, or some
+ * brain dead set the memory limit for mon entries to ZERO!!!
+ */
+ this_client = mon_mru_list.mru_next;
+
+ for (md = mon_fifo_list.fifo_next,lcnt = 0;
+ md != &mon_fifo_list;
+ md = md->fifo_next) {
+ if ((current_time - md->lasttime)
+ > client_limit_period) {
+#ifdef DEBUG
+ if (debug > 5)
+ printf("checking: %s: ignore: too old: %d\n",
+ numtoa(md->rmtadr),
+ current_time - md->lasttime);
+#endif
+ continue;
+ }
+ if (md->mode == MODE_BROADCAST ||
+ md->mode == MODE_CONTROL ||
+ md->mode == MODE_PRIVATE) {
+#ifdef DEBUG
+ if (debug > 5)
+ printf("checking: %s: ignore mode %d\n",
+ numtoa(md->rmtadr),
+ md->mode);
+#endif
+ continue;
+ }
+ if (netof(md->rmtadr) !=
+ netof(hostaddr)) {
+#ifdef DEBUG
+ if (debug > 5)
+ printf("checking: %s: different net 0x%X\n",
+ numtoa(md->rmtadr),
+ netof(md->rmtadr));
+#endif
+ continue;
+ }
+ lcnt++;
+ if (lcnt > client_limit ||
+ md->rmtadr == hostaddr) {
+#ifdef DEBUG
+ if (debug > 5)
+ printf("considering %s: found host\n",
+ numtoa(md->rmtadr));
+#endif
+ break;
+ }
+#ifdef DEBUG
+ else {
+ if (debug > 5)
+ printf("considering %s: same net\n",
+ numtoa(md->rmtadr));
+ }
+#endif
+
+ }
+#ifdef DEBUG
+ if (debug > 4)
+ printf("this one is rank %d in list, limit is %d: %s\n",
+ lcnt, client_limit,
+ (lcnt <= client_limit) ? "ALLOW" : "REJECT");
+#endif
+ if (lcnt <= client_limit) {
+ this_client->lastdrop = 0;
+ return (int)(match->flags & ~RES_LIMITED);
+ } else {
+ this_client->lastdrop = current_time;
+ }
+ }
return (int)match->flags;
}
@@ -257,6 +404,10 @@ restrict(op, resaddr, resmask, mflags, flags)
rlprev->next = rl;
restrictcount++;
}
+ if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
+ res_limited_refcnt++;
+ mon_start(MON_RES); /* ensure data gets collected */
+ }
rl->flags |= (u_short)flags;
break;
@@ -265,8 +416,14 @@ restrict(op, resaddr, resmask, mflags, flags)
* Remove some bits from the flags. If we didn't
* find this one, just return.
*/
- if (rl != 0)
+ if (rl != 0) {
+ if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
+ res_limited_refcnt--;
+ if (res_limited_refcnt == 0)
+ mon_stop(MON_RES);
+ }
rl->flags &= (u_short)~flags;
+ }
break;
case RESTRICT_REMOVE:
@@ -280,6 +437,11 @@ restrict(op, resaddr, resmask, mflags, flags)
&& !(rl->mflags & RESM_INTERFACE)) {
rlprev->next = rl->next;
restrictcount--;
+ if (rl->flags & RES_LIMITED) {
+ res_limited_refcnt--;
+ if (res_limited_refcnt == 0)
+ mon_stop(MON_RES);
+ }
memset((char *)rl, 0, sizeof(struct restrictlist));
rl->next = resfree;
diff --git a/contrib/xntpd/xntpd/ntp_unixclock.c b/contrib/xntpd/xntpd/ntp_unixclock.c
index 6b661835dbb7..1950d8c06fb3 100644
--- a/contrib/xntpd/xntpd/ntp_unixclock.c
+++ b/contrib/xntpd/xntpd/ntp_unixclock.c
@@ -251,10 +251,23 @@ clock_parms(tickadj, tick)
* Note that this version grovels about in /dev/kmem to determine
* these values. This probably should be elsewhere.
*/
-
-/* Define the following to be what the tick and tickadj variables are
- * called in your kernel.
+#if defined(SYS_UNIXWARE1)
+/*
+ * clock_parms - return the local clock tickadj and tick parameters
+ *
+ * The values set here were determined experimentally on a 486 system
+ * I'm not confident in them. - RAS
+ *
*/
+static void
+clock_parms(tickadj, tick)
+ U_LONG *tickadj;
+ U_LONG *tick;
+{
+ *tick = 10000; /* microseconds */
+ *tickadj = 80; /* microseconds */
+}
+#else /* SYS_UNIXWARE1 */
#if defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SYS_SVR4) || defined(SYS_PTX)
#define K_TICKADJ_NAME "tickadj"
@@ -373,6 +386,7 @@ clock_parms(tickadj, tick)
#undef K_TICK_NAME
#undef N_NAME
}
+#endif /* SYS_UNIXWARE1 */
#endif /* HAVE_READKMEM */
#if defined(SOLARIS)&&defined(ADJTIME_IS_ACCURATE)
@@ -421,7 +435,6 @@ clock_parms(tickadj, tick)
}
#endif /* sgi */
-
#ifdef NOKMEM
#ifndef HZ
@@ -556,13 +569,18 @@ clock_parms(tickadj, tick)
#endif /* SOLARIS */
#ifdef SYS_LINUX
-/* XXX should look this up somewhere ! */
+#include <sys/timex.h>
static void
clock_parms(tickadj, tick)
U_LONG *tickadj;
U_LONG *tick;
{
- *tickadj = (U_LONG)1;
- *tick = (U_LONG)10000;
+ struct timex txc;
+
+ txc.mode = 0;
+ __adjtimex(&txc);
+
+ *tickadj = (U_LONG)1; /* our adjtime is accurate */
+ *tick = (U_LONG)txc.tick;
}
#endif /* SYS_LINUX */
diff --git a/contrib/xntpd/xntpd/ntpd.c b/contrib/xntpd/xntpd/ntpd.c
index abe86d945151..9ed43c5c4a81 100644
--- a/contrib/xntpd/xntpd/ntpd.c
+++ b/contrib/xntpd/xntpd/ntpd.c
@@ -14,7 +14,7 @@
#include <sys/rtprio.h>
#endif
-#if defined(SYS_SVR4)
+#if defined(SYS_SVR4) || defined (SYS_UNIXWARE1)
#include <termios.h>
#endif
@@ -28,8 +28,12 @@
#include "ntp_stdlib.h"
#ifdef LOCK_PROCESS
+#ifdef SYS_SOLARIS
+#include <sys/mman.h>
+#else
#include <sys/lock.h>
#endif
+#endif
/*
* Signals we catch for debugging. If not debugging we ignore them.
@@ -139,7 +143,7 @@ main(argc, argv)
(void) dup2(0, 1);
(void) dup2(0, 2);
#ifdef NTP_POSIX_SOURCE
-#if defined(SOLARIS) || defined(SYS_PTX) || defined(SYS_AUX3) || defined(SYS_AIX)
+#if defined(SOLARIS) || defined(SYS_PTX) || defined(SYS_AUX3) || defined(SYS_AIX) || defined(SYS_ULTRIX)
(void) setsid();
#else
(void) setpgid(0, 0);
@@ -219,13 +223,23 @@ main(argc, argv)
if (rtprio(0, 120) < 0)
syslog(LOG_ERR, "rtprio() error: %m");
#else
-#if defined(PROCLOCK) && defined(LOCK_PROCESS)
+#if defined(LOCK_PROCESS)
+#if defined(MCL_CURRENT) && defined(MCL_FUTURE)
+ /*
+ * lock the process into memory
+ */
+ if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
+ syslog(LOG_ERR, "mlockall(): %m");
+#else
+#if defined(PROCLOCK)
/*
* lock the process into memory
*/
if (plock(PROCLOCK) < 0)
syslog(LOG_ERR, "plock(): %m");
#endif
+#endif
+#endif
#if defined(NTPD_PRIO) && NTPD_PRIO != 0
/*
* Set the priority.
diff --git a/contrib/xntpd/xntpd/refclock_chu.c b/contrib/xntpd/xntpd/refclock_chu.c
index 1c7c3bfa61c1..4596db22e2f5 100644
--- a/contrib/xntpd/xntpd/refclock_chu.c
+++ b/contrib/xntpd/xntpd/refclock_chu.c
@@ -599,6 +599,25 @@ chu_receive(rbufp)
chu->lastupdate = current_time;
/*
+ * Just for fun, we can debug the whole frame if
+ * we want.
+ */
+
+#ifdef CHU_DEBUG
+ syslog(LOG_DEBUG, "CHU %s packet:", (chuc->chutype == CHU_YEAR)?
+ "year":"time");
+ for (i=0; i < NCHUCHARS; i++) {
+ char c[64];
+
+ sprintf(c,"%c%c %s",hexstring[chuc->codechars[i]&0xf],
+ hexstring[chuc->codechars[i]>>4],
+ ctime(&(chuc->codetimes[i].tv_sec)));
+ c[strlen(c)-1]=0; /* ctime() adds a damn \n */
+ syslog(LOG_DEBUG, "%s .%06d", c, chuc->codetimes[i].tv_usec);
+ }
+#endif
+
+ /*
* At this point we're assured that both halves of the
* data match because of what the kernel has done.
* But there's more than one data format. We need to
diff --git a/contrib/xntpd/xntpd/refclock_conf.c b/contrib/xntpd/xntpd/refclock_conf.c
index 430c4a60f3fa..535ca27e9ebe 100644
--- a/contrib/xntpd/xntpd/refclock_conf.c
+++ b/contrib/xntpd/xntpd/refclock_conf.c
@@ -20,6 +20,12 @@ extern struct refclock refclock_local;
#define refclock_local refclock_none
#endif
+#if defined(TRAK) || defined(TRAKCLK) || defined(TRAKPPS)
+extern struct refclock refclock_trak;
+#else
+#define refclock_trak refclock_none
+#endif
+
#if defined(PST) || defined(PSTCLK) || defined(PSTPPS)
extern struct refclock refclock_pst;
#else
@@ -107,7 +113,7 @@ extern struct refclock refclock_gpstm;
struct refclock *refclock_conf[] = {
&refclock_none, /* 0 REFCLK_NONE */
&refclock_local, /* 1 REFCLK_LOCAL */
- &refclock_none, /* 2 REFCLK_WWV_HEATH */
+ &refclock_trak, /* 2 REFCLK_GPS_TRAK */
&refclock_pst, /* 3 REFCLK_WWV_PST */
&refclock_wwvb, /* 4 REFCLK_WWVB_SPECTRACOM */
&refclock_goes, /* 5 REFCLK_GOES_TRUETIME */
diff --git a/contrib/xntpd/xntpd/refclock_irig.c b/contrib/xntpd/xntpd/refclock_irig.c
index 40345bbefde7..6167af2784ee 100644
--- a/contrib/xntpd/xntpd/refclock_irig.c
+++ b/contrib/xntpd/xntpd/refclock_irig.c
@@ -19,7 +19,7 @@
* This driver supports the IRIG audio decoder. This clever gadget uses
* a modified BSD audio driver for the Sun SPARCstation which provides
* a timestamp, raw binary timecode, status byte and decoded ASCII
- # timecode. The data are represented in the structure:
+ * timecode. The data are represented in the structure:
*
* struct irig_time {
* struct timeval stamp; timestamp
@@ -418,7 +418,9 @@ struct peer *peer;
irig->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
irig->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
irig->second = MULBY10(cp[10] - '0') + cp[11] - '0';
- if (cp[12] != ' ')
+ if (cp[12] = ' ')
+ irig->leap = 0;
+ else
irig->leap = LEAP_NOTINSYNC;
if (irig->day < 1 || irig->day > 366) {
irig->baddata++;
diff --git a/contrib/xntpd/xntpd/refclock_msfees.c b/contrib/xntpd/xntpd/refclock_msfees.c
index b301bc2ebb23..c2a882abb919 100644
--- a/contrib/xntpd/xntpd/refclock_msfees.c
+++ b/contrib/xntpd/xntpd/refclock_msfees.c
@@ -139,7 +139,7 @@
#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
#ifndef STREAM_PP1
-#define STREAM_PP1 "ppsclockd\0<-- patch space for module name1 -->"
+#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
#endif
#ifndef STREAM_PP2
#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
diff --git a/contrib/xntpd/xntpd/refclock_parse.c b/contrib/xntpd/xntpd/refclock_parse.c
index 69e483764354..0d95d18908a5 100644
--- a/contrib/xntpd/xntpd/refclock_parse.c
+++ b/contrib/xntpd/xntpd/refclock_parse.c
@@ -1,8 +1,8 @@
#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
/*
- * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp
+ * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp
*
- * refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp
+ * refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp
*
* generic reference clock driver for receivers
*
@@ -30,6 +30,8 @@
* PPS - supply loopfilter with PPS samples (if configured)
* PPSPPS - notify loopfilter of PPS file descriptor
*
+ * FREEBSD_CONRAD - Make very cheap "Conrad DCF77 RS-232" gadget work
+ * with FreeBSD.
* TTY defines:
* HAVE_BSD_TTYS - currently unsupported
* HAVE_SYSV_TTYS - will use termio.h
@@ -82,6 +84,9 @@
#include <time.h>
#include <sys/errno.h>
+#ifdef FREEBSD_CONRAD
+#include <sys/ioctl.h>
+#endif
extern int errno;
#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
@@ -129,7 +134,7 @@ CURRENTLY NO BSD TTY SUPPORT
#include "parse.h"
#if !defined(NO_SCCSID) && !defined(lint) && !defined(__GNUC__)
-static char rcsid[]="refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp";
+static char rcsid[]="refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp";
#endif
/**===========================================================================
@@ -440,7 +445,12 @@ static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
#define RAWDCF_ROOTDELAY 0x00000364 /* 13 ms */
#define RAWDCF_FORMAT "RAW DCF77 Timecode"
#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
+
+#ifdef FREEBSD_CONRAD
+#define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
+#else
#define RAWDCF_CFLAG (B50|CS8|CREAD|CLOCAL)
+#endif
#define RAWDCF_IFLAG 0
#define RAWDCF_OFLAG 0
#define RAWDCF_LFLAG 0
@@ -1482,11 +1492,22 @@ local_receive(rbufp)
struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock;
register int count;
register char *s;
+#ifdef FREEBSD_CONRAD
+ struct timeval foo;
+#endif
+
/*
* eat all characters, parsing then and feeding complete samples
*/
count = rbufp->recv_length;
s = rbufp->recv_buffer;
+#ifdef FREEBSD_CONRAD
+ ioctl(parse->fd,TIOCTIMESTAMP,&foo);
+ TVTOTS(&foo, &rbufp->recv_time);
+ rbufp->recv_time.l_uf += TS_ROUNDBIT;
+ rbufp->recv_time.l_ui += JAN_1970;
+ rbufp->recv_time.l_uf &= TS_MASK;
+#endif
while (count--)
{
@@ -1653,7 +1674,8 @@ local_poll(parse)
* done if no more characters are available
*/
FD_SET(fd, &fdmask);
- if (select(fd + 1, &fdmask, 0, 0, &null_time) == 0)
+ if ((i == 0) &&
+ (select(fd + 1, &fdmask, 0, 0, &null_time) == 0))
return;
}
}
@@ -1706,7 +1728,8 @@ parsestate(state, buffer)
{ PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
{ PARSEB_DST, "DST" },
{ PARSEB_UTC, "UTC DISPLAY" },
- { PARSEB_LEAP, "LEAP WARNING" },
+ { PARSEB_LEAPADD, "LEAP ADD WARNING" },
+ { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
{ PARSEB_LEAPSECOND, "LEAP SECOND" },
{ PARSEB_ALTERNATE,"ALTERNATE ANTENNA" },
{ PARSEB_TIMECODE, "TIME CODE" },
@@ -2269,7 +2292,10 @@ parse_start(sysunit, peer)
tm.c_iflag = clockinfo[type].cl_iflag;
tm.c_oflag = clockinfo[type].cl_oflag;
tm.c_lflag = clockinfo[type].cl_lflag;
-
+#ifdef FREEBSD_CONRAD
+ tm.c_ispeed = 50;
+ tm.c_ospeed = 50;
+#endif
if (TTY_SETATTR(fd232, &tm) == -1)
{
syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tm): %m", unit, fd232);
@@ -2312,6 +2338,21 @@ parse_start(sysunit, peer)
return 0; /* well, ok - special initialisation broke */
}
+#ifdef FREEBSD_CONRAD
+ {
+ int i,j;
+ struct timeval tv;
+ ioctl(parse->fd,TIOCTIMESTAMP,&tv);
+ j = TIOCM_RTS;
+ i = ioctl(fd232, TIOCMBIC, &j);
+ if (i < 0) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: lowrts_poll: failed to lower RTS: %m",
+ CL_UNIT(parse->unit));
+ }
+ }
+#endif
+
strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
@@ -2539,9 +2580,10 @@ static void
parse_leap()
{
/*
- * PARSE does encode a leap warning... we are aware but not afraid of that
- * as long as we get a little help for the direction from the operator until
* PARSE encodes the LEAP correction direction.
+ * For timecodes that do not pass on the leap correction direction
+ * the default PARSEB_LEAPADD must be used. It may then be modified
+ * with a fudge flag (flag2).
*/
}
@@ -2821,7 +2863,7 @@ parse_control(unit, in, out)
sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
tt = add_var(&out->kv_list, 128, RO);
- sprintf(tt, "refclock_driver_version=\"refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp\"");
+ sprintf(tt, "refclock_driver_version=\"refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp\"");
out->lencode = strlen(outstatus);
out->lastcode = outstatus;
@@ -3100,7 +3142,11 @@ parse_process(parse, parsetime)
L_ADD(&off, &offset);
rectime = off; /* this makes org time and xmt time somewhat artificial */
- if (parse->flags & PARSE_STAT_FILTER)
+ L_SUB(&off, &parsetime->parse_stime.fp);
+
+ if ((parse->flags & PARSE_STAT_FILTER) &&
+ (off.l_i > -60) &&
+ (off.l_i < 60)) /* take usec error only if within +- 60 secs */
{
struct timeval usecerror;
/*
@@ -3112,10 +3158,6 @@ parse_process(parse, parsetime)
sTVTOTS(&usecerror, &off);
L_ADD(&off, &offset);
}
- else
- {
- L_SUB(&off, &parsetime->parse_stime.fp);
- }
}
if (PARSE_PPS(parsetime->parse_state) && CL_PPS(parse->unit))
@@ -3245,14 +3287,24 @@ parse_process(parse, parsetime)
}
else
{
- if (PARSE_LEAP(parsetime->parse_state))
+ if (PARSE_LEAPADD(parsetime->parse_state))
{
+ /*
+ * we pick this state also for time code that pass leap warnings
+ * without direction information (as earth is currently slowing
+ * down).
+ */
leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
}
else
- {
- leap = LEAP_NOWARNING;
- }
+ if (PARSE_LEAPDEL(parsetime->parse_state))
+ {
+ leap = LEAP_DELSECOND;
+ }
+ else
+ {
+ leap = LEAP_NOWARNING;
+ }
}
refclock_receive(parse->peer, &off, 0, LFPTOFP(&dispersion), &reftime, &rectime, leap);
@@ -3396,6 +3448,21 @@ trimble_init(parse)
* History:
*
* refclock_parse.c,v
+ * Revision 3.53 1994/03/25 13:07:39 kardel
+ * fixed offset calculation for large (>4 Min) offsets
+ *
+ * Revision 3.52 1994/03/03 09:58:00 kardel
+ * stick -kv in cvs is no fun
+ *
+ * Revision 3.49 1994/02/20 13:26:00 kardel
+ * rcs id cleanup
+ *
+ * Revision 3.48 1994/02/20 13:04:56 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.47 1994/02/02 17:44:30 kardel
+ * rcs ids fixed
+ *
* Revision 3.45 1994/01/25 19:06:27 kardel
* 94/01/23 reconcilation
*
diff --git a/contrib/xntpd/xntpd/refclock_trak.c b/contrib/xntpd/xntpd/refclock_trak.c
new file mode 100644
index 000000000000..f2b3eb11fc9d
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_trak.c
@@ -0,0 +1,1006 @@
+/*
+ * refclock_trak.c - clock driver for the TRAK 8810 GPS STATION CLOCK
+ * Tsuruoka Tomoaki Oct 30, 1993
+ * tsuruoka@nc.fukuoka-u.ac.jp
+ * Faculty of Engineering,
+ * Fukuoka University, Fukuoka, JAPAN
+ */
+#if defined(REFCLOCK) && (defined(TRAK) || defined(TRAKCLK) || defined(TRAKPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+static void gps_send();
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(TRAKCLK)
+#include <sys/clkdefs.h>
+#endif /* TRAKCLK */
+#endif /* STREAM */
+
+#if defined (TRAKPPS)
+#include <sys/ppsclock.h>
+#endif /* TRAKPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the TRAK 8810 GPS Receiver with
+ * Buffered RS-232-C Interface Module.
+ *
+ * Most of codes are copied from refclock_as2201.c, Thanks a lot.
+ *
+ * The program expects the radio responses once per seccond
+ * ( by "rqts,u" command or panel control )
+ * of the form "*RQTS U,ddd:hh:mm:ss.0,Q\r\n for UTC" where
+ * ddd= day of year
+ * hh= hours
+ * mm= minutes
+ * ss= seconds
+ * Q= Quality byte. Q=0 Phase error > 20 us
+ * Q=6 Pahse error < 20 us
+ * > 10 us
+ * Q=5 Pahse error < 10 us
+ * > 1 us
+ * Q=4 Pahse error < 1 us
+ * > 100 ns
+ * Q=3 Pahse error < 100 ns
+ * > 10 ns
+ * Q=2 Pahse error < 10 ns
+ * (note that my clock almost stable at 1 us per 10 hours)
+ *
+ * Request leap second status - if needed.
+ * send: rqls\n
+ * reply: RQLS yy,mm,dd
+ * where: yy is year
+ * mm is month
+ * dd is day of month.baud
+ * Note: Default data is all zeros
+ * i.e. RQLS 00,00,00
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* max number of GPS units */
+#define GPS232 "/dev/gps%d" /* name of radio device */
+#define SPEED232 B9600 /* uart speed (9600 bps) */
+
+/*
+ * Radio interface parameters
+ */
+#define GPSPRECISION (-20) /* precision assumed (about 1 us) */
+#define GPSREFID "GPS" /* reference id */
+#define GPSDESCRIPTION "TRAK 8810 GPS station clock" /* who we are */
+#define GPSHSREFID 0x7f7f020a /* 127.127.2.10 refid hi strata */
+#define GMT 0 /* hour offset from Greenwich */
+#define NCODES 3 /* stages of median filter */
+#define LENTOC 25 /* *RQTS U,ddd:hh:mm:ss.0,Q datecode length */
+#define BMAX 100 /* timecode buffer length */
+#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+
+/*
+ * Imported from ntp_timer module
+ */
+extern U_LONG current_time; /* current time (s) */
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * GPS unit control structure.
+ */
+struct gpsunit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last data receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NCODES]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short polled; /* when polled, means a last sample */
+ u_char lencode; /* length of last received ASCII string */
+ U_LONG lasttime; /* last time clock heard from */
+#ifdef TRAKPPS
+ U_LONG lastev; /* last ppsclock second */
+#endif /* TRAKPPS */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_short msec; /* milliseconds of second */
+ u_char leap; /* leap indicators */
+ U_LONG yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ U_LONG polls; /* polls sent */
+ U_LONG noreply; /* no replies to polls */
+ U_LONG coderecv; /* timecodes received */
+ U_LONG badformat; /* bad format */
+ U_LONG baddata; /* bad data */
+ U_LONG timestarted; /* time we started this */
+};
+
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct gpsunit *gpsunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void trak_init P(());
+static int trak_start P((u_int, struct peer *));
+static void trak_shutdown P((int));
+static void trak_report_event P((struct gpsunit *, int));
+static void trak_receive P((struct recvbuf *));
+static char trak_process P((struct gpsunit *, l_fp *, u_fp *));
+static void trak_poll P((int unit, struct peer *));
+static void trak_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void trak_buginfo P((int, struct refclockbug *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_trak = {
+ trak_start, trak_shutdown, trak_poll,
+ trak_control, trak_init, trak_buginfo, NOFLAGS
+};
+
+/*
+ * trak_init - initialize internal gps driver data
+ */
+static void
+trak_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)gpsunits, 0, sizeof gpsunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
+
+/*
+ * trak_start - open the GPS devices and initialize data for processing
+ */
+static int
+trak_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct gpsunit *gps;
+ register int i;
+ int fd232;
+ char trakdev[20];
+#ifdef TRAKPPS
+ struct ppsclockev ev;
+#endif /* TRAKPPS */
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_start: unit %d invalid", unit);
+ return (0);
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_start: unit %d in use", unit);
+ return (0);
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(trakdev, GPS232, unit);
+ fd232 = open(trakdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "trak_start: open of %s: %m", trakdev);
+ return (0);
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TCGETA): %m", trakdev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TCSETA): %m", trakdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(STREAM)
+ /*
+ * POSIX/STREAMS serial line parameters (termios interface)
+ *
+ * The TRAKCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The TRAKPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcgetattr(%s): %m", trakdev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcsetattr(%s): %m", trakdev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcflush(%s): %m", trakdev);
+ goto screwed;
+ }
+#if defined(TRAKCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, I_PUSH, clk): %m", trakdev);
+ if (ioctl(fd232, CLK_SETSTR, "*") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, CLK_SETSTR): %m", trakdev);
+#endif /* TRAKCLK */
+#if defined(TRAKPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, I_PUSH, ppsclock): %m", trakdev);
+ else
+ fdpps = fd232;
+#endif /* TRAKPPS */
+ }
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The TRAKCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(TRAKCLK)
+ int ldisc = CLKLDISC;
+#endif /* TRAKCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCGETP): %m", trakdev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(TRAKCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* TRAKCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCSETP): %m", trakdev);
+ goto screwed;
+ }
+#if defined(TRAKCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCSETD): %m",trakdev);
+ goto screwed;
+ }
+#endif /* TRAKCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (gpsunits[unit] != 0) {
+ gps = gpsunits[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && gpsunits[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ gps = gpsunits[i];
+ gpsunits[i] = 0;
+ } else {
+ gps = (struct gpsunit *)
+ emalloc(sizeof(struct gpsunit));
+ }
+ }
+ bzero((char *)gps, sizeof(struct gpsunit));
+ gpsunits[unit] = gps;
+
+ /*
+ * Set up the structures
+ */
+ gps->peer = peer;
+ gps->unit = (u_char)unit;
+ gps->timestarted = current_time;
+
+ gps->io.clock_recv = trak_receive;
+ gps->io.srcclock = (caddr_t)gps;
+ gps->io.datalen = 0;
+ gps->io.fd = fd232;
+#ifdef TRAKPPS
+ if (ioctl(fd232, CIOGETEV, (caddr_t)&ev) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, CIOGETEV): %m", trakdev);
+ goto screwed;
+ } else
+ gps->lastev = ev.tv.tv_sec;
+#endif /* TRAKPPS */
+ if (!io_addclock(&gps->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
+ */
+ peer->precision = GPSPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(GPSREFID, (char *)&peer->refid, 4);
+ else
+ peer->refid = htonl(GPSHSREFID);
+ unitinuse[unit] = 1;
+ /*
+ * request to give time code
+ */
+ {
+ void gps_send();
+ gps_send(gps,"\rRQTS,U\r");
+ gps_send(gps,"SEL 00\r");
+ }
+
+ return (1);
+
+ /*
+ * Something broke; abandon ship.
+ */
+screwed:
+ (void) close(fd232);
+ return (0);
+}
+
+/*
+ * trak_shutdown - shut down a GPS clock
+ */
+static void
+trak_shutdown(unit)
+ int unit;
+{
+ register struct gpsunit *gps;
+ void gps_send();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_shutdown: unit %d not in use", unit);
+ return;
+ }
+ gps = gpsunits[unit];
+ /*
+ * request not to give time code any more
+ */
+ gps_send(gps,"RQTX\r");
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ io_closeclock(&gps->io);
+
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * trak_report_event - note the occurance of an event
+ *
+ * This routine presently just remembers the report and logs it, but
+ * does nothing heroic for the trap handler.
+ */
+static void
+trak_report_event(gps, code)
+ struct gpsunit *gps;
+ int code;
+{
+ struct peer *peer;
+
+ peer = gps->peer;
+ if (gps->status != (u_char)code) {
+ gps->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ gps->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "clock %s event %x\n", ntoa(&peer->srcadr), code);
+ }
+}
+
+
+/*
+ * trak_receive - receive data from the serial interface
+ */
+static void
+trak_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i,cmdtype;
+ register struct gpsunit *gps;
+
+#if defined(TRAKPPS)
+ struct ppsclockev ev;
+ l_fp trtmp;
+#endif /* TRAKPPS */
+ register u_char *dpt;
+ register u_char *cp;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion;
+
+ /*
+ * Get the clock this applies to and pointers to the data.
+ * Edit the timecode to remove control chars and trashbits.
+ */
+ gps = (struct gpsunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = dpt + rbufp->recv_length;
+ cp = (u_char *)gps->lastcode;
+
+ while (dpt < dpend) {
+#ifdef TRAKCLK /* prior to TRAKPPS due to timestamp */
+ if ((*cp = 0x7f & *dpt++) != '*' ) cp++;
+ else if (*cp == '*' ) { /* caught magic character */
+ if ( dpend - dpt < 8) {
+ /* short timestamp */
+ if(debug) puts("gps: short timestamp.");
+ return;
+ }
+ if (!buftvtots(dpt,&gps->lastrec)) {
+ /* screwy timestamp */
+ if(debug) puts("gps: screwy timestamp.");
+ return;
+ }
+ dpt += 8;
+ }
+#else
+#ifdef TRAKPPS
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#else
+ /* both are not specified */
+#endif /* TRAKPPS */
+#endif /* TRAKCLK */
+ }
+ *cp = '\0';
+ gps->lencode = cp - (u_char *)gps->lastcode;
+ if (gps->lencode == 0) return;
+
+#ifdef DEBUG
+ if (debug)
+ printf("gps: timecode %d %s\n",
+ gps->lencode, gps->lastcode);
+#endif
+
+ /*
+ * We check the timecode format and decode its contents. The
+ * timecode has format *........RQTS U,ddd:hh:mm:ss.0,Q\r\n).
+ * 012345678901234567890123
+ */
+#define RQTS 0
+#define RQLS 1
+ cp = (u_char *)gps->lastcode;
+ gps->leap = 0;
+ cmdtype=0;
+ if(strncmp(cp,"*RQTS",5)==0) {
+ cmdtype=RQTS;
+ cp += 8;
+ }
+ else if(strncmp(cp,"RQTS",4)==0) {
+ cmdtype=RQTS;
+ cp += 7;
+ }
+ else if(strncmp(cp,"RQLS",4)==0) {
+ cmdtype=RQLS;
+ cp += 5;
+ }
+ else
+ return;
+
+ switch( cmdtype ) {
+ case RQTS:
+ /*
+ * Check time code format of TRAK 8810
+ */
+ if( !isdigit(cp[0]) ||
+ !isdigit(cp[1]) ||
+ !isdigit(cp[2]) ||
+ cp[3] != ':' ||
+ !isdigit(cp[4]) ||
+ !isdigit(cp[5]) ||
+ cp[6] != ':' ||
+ !isdigit(cp[7]) ||
+ !isdigit(cp[8]) ||
+ cp[9] != ':' ||
+ !isdigit(cp[10])||
+ !isdigit(cp[11])) {
+ gps->badformat++;
+ trak_report_event(gps, CEVNT_BADREPLY);
+ return;
+ }
+ break;
+ case RQLS:
+ /*
+ * reply for leap second request
+ */
+ if (cp[0] !='0' || cp[1] != '0' ) gps->leap = LEAP_ADDSECOND;
+ return;
+ default:
+ return;
+
+ }
+
+ /*
+ * Convert date and check values.
+ */
+ gps->day = cp[0] - '0';
+ gps->day = MULBY10(gps->day) + cp[1] - '0';
+ gps->day = MULBY10(gps->day) + cp[2] - '0';
+ if (gps->day < 1 || gps->day > 366) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADDATE);
+ return;
+ }
+ /*
+ * Convert time and check values.
+ */
+ gps->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ gps->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ gps->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ gps->msec = 0;
+ if (gps->hour > 23 || gps->minute > 59 || gps->second > 59) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
+ return;
+ }
+
+ if (!gps->polled) return;
+
+ /*
+ * Test for synchronization Check for quality byte.
+ */
+/*
+ switch( cp[15] ) {
+ case '0':
+ if(gps->peer->stratum == stratumtouse[gps->unit]) {
+ gps->peer->stratum = 10 ;
+ bzero(&gps->peer->refid,4);
+ }
+ break;
+ default:
+ if(gps->peer->stratum != stratumtouse[gps->unit]) {
+ gps->peer->stratum = stratumtouse[gps->unit] ;
+ bcopy(GPSREFID,&gps->peer->refid,4);
+ }
+ break;
+ }
+*/
+ if( cp[15] == '0') /* TRAK derailed from tracking satellites */
+ {
+ gps->leap = LEAP_NOTINSYNC;
+ gps->noreply++;
+ trak_report_event(gps, CEVNT_TIMEOUT);
+ }
+ else
+ {
+ gps->lasttime = current_time;
+ if( gps->lastevent == CEVNT_TIMEOUT ) {
+ gps->status = CEVNT_NOMINAL;
+ trak_report_event(gps, CEVNT_NOMINAL);
+ }
+ }
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the second, which presumably is the one which
+ * occured at the last pps pulse and which was captured by the
+ * loop_filter module. All we have to do here is present a
+ * reasonable facsimile of the time at that pulse so the clock-
+ * filter and selection machinery declares us truechimer. The
+ * precision offset within the second is really tuned by the
+ * loop_filter module. Note that this code does not yet know how
+ * to do the years and relies on the clock-calendar chip for
+ * sanity.
+ */
+
+#if defined(TRAKPPS)
+
+ /*
+ * timestamp must be greater than previous one.
+ */
+ if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
+ ev.tv.tv_sec += (U_LONG)JAN_1970;
+ TVTOTS(&ev.tv,&gps->lastrec);
+ if (gps->lastev < ev.tv.tv_sec) {
+ gps->lastev = ev.tv.tv_sec;
+ } else { /* in case of 1-pps missing */
+ gps->lastev = ev.tv.tv_sec;
+ return;
+ }
+ }
+ else
+ return; /* failed to get timestamp */
+#endif /* TRAKPPS */
+
+ if (!clocktime(gps->day, gps->hour, gps->minute,
+ gps->second, GMT, gps->lastrec.l_ui,
+ &gps->yearstart, &gps->lastref.l_ui)) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
+#ifdef DEBUG
+ if(debug) printf("gps: bad date \n");
+#endif
+ return;
+ }
+ MSUTOTSF(gps->msec, gps->lastref.l_uf);
+ tstmp = gps->lastref;
+
+ L_SUB(&tstmp, &gps->lastrec);
+ L_ADD(&tstmp, &(fudgefactor[gps->unit]));
+ i = ((int)(gps->coderecv)) % NCODES;
+ gps->offset[i] = tstmp;
+ gps->coderecv++;
+#if DEBUG
+ if (debug)
+ printf("gps: times %s %s %s\n",
+ ulfptoa(&gps->lastref, 6), ulfptoa(&gps->lastrec, 6),
+ lfptoa(&tstmp, 6));
+#endif
+/* if( tstmp.l_ui != 0 ) return; something wrong */
+
+ /*
+ * Process the samples in the median filter, add the fudge
+ * factor and pass the offset and dispersion along. We use
+ * lastref as both the reference time and receive time in order
+ * to avoid being cute, like setting the reference time later
+ * than the receive time, which may cause a paranoid protocol
+ * module to chuck out the data.
+ */
+ if (gps->coderecv < NCODES)
+ return;
+ if (!trak_process(gps, &tstmp, &dispersion)) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(gps->peer, &tstmp, GMT, dispersion,
+ &gps->lastrec, &gps->lastrec, gps->leap);
+ /*
+ * after all, clear polled flag
+ */
+ gps->polled = 0;
+}
+
+/*
+ * ==================================================================
+ * gps_send(gps,cmd) Sends a command to the GPS receiver.
+ * as gps_send(gps,"rqts,u\r");
+ * ==================================================================
+ */
+static void
+gps_send(gps,cmd)
+ struct gpsunit *gps;
+ char *cmd;
+{
+ if (write(gps->io.fd, cmd, strlen(cmd)) == -1) {
+ syslog(LOG_ERR, "gps_send: unit %d: %m", gps->unit);
+ trak_report_event(gps,CEVNT_FAULT);
+ } else {
+ gps->polls++;
+ }
+}
+
+/*
+ * trak_process - process a pile of samples from the clock
+ *
+ * This routine uses a three-stage median filter to calculate offset and
+ * dispersion and reduce jitter. The dispersion is calculated as the
+ * span of the filter (max - min).
+ */
+static char
+trak_process(gps, offset, dispersion)
+ struct gpsunit *gps;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, j;
+ register U_LONG tmp_ui, tmp_uf;
+ int not_median1 = -1; /* XXX correct? */
+ int not_median2 = -1; /* XXX correct? */
+ int median;
+ u_fp disp_tmp, disp_tmp2;
+
+ /*
+ * This code implements a three-stage median filter. First, we
+ * check if the samples are within 125 ms of each other. If not,
+ * dump the sample set. We take the median of the three offsets
+ * and use that as the sample offset. There probably is not much
+ * to be gained by a longer filter, since the clock filter in
+ * ntp_proto should do its thing.
+ */
+ disp_tmp2 = 0;
+ for (i = 0; i < NCODES-1; i++) {
+ for (j = i+1; j < NCODES; j++) {
+ tmp_ui = gps->offset[i].l_ui;
+ tmp_uf = gps->offset[i].l_uf;
+ M_SUB(tmp_ui, tmp_uf, gps->offset[j].l_ui,
+ gps->offset[j].l_uf);
+ if (M_ISNEG(tmp_ui, tmp_uf)) {
+ M_NEG(tmp_ui, tmp_uf);
+ }
+ if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
+ return (0);
+ }
+ disp_tmp = MFPTOFP(0, tmp_uf);
+ if (disp_tmp > disp_tmp2) {
+ disp_tmp2 = disp_tmp;
+ not_median1 = i;
+ not_median2 = j;
+ }
+ }
+ }
+ if (gps->lasttime == 0)
+ disp_tmp2 = NTP_MAXDISPERSE;
+ else
+ disp_tmp2 = current_time - gps->lasttime;
+ if (not_median1 == 0) {
+ if (not_median2 == 1)
+ median = 2;
+ else
+ median = 1;
+ } else {
+ median = 0;
+ }
+ *offset = gps->offset[median];
+ *dispersion = disp_tmp2;
+ return (1);
+}
+
+/*
+ * trak_poll - called by the transmit procedure
+ *
+ * We go to great pains to avoid changing state here, since there may be
+ * more than one eavesdropper receiving the same timecode.
+ */
+static void
+trak_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_poll: unit %d not in use", unit);
+ return;
+ }
+ gps = gpsunits[unit];
+ if ((current_time - gps->lasttime) > 150)
+ trak_report_event(gpsunits[unit], CEVNT_TIMEOUT);
+ /*
+ * usually trak_receive can get a timestamp every second
+ */
+#if !defined(TRAKPPS) && !defined(TRAKCLK)
+ gettstamp(&gps->lastrec);
+#endif
+ gps->polls++;
+ /*
+ * may be polled every 16 seconds (minpoll 4)
+ */
+ gps->polled = 1;
+}
+
+/*
+ * trak_control - set fudge factors, return statistics
+ */
+static void
+trak_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ /*
+ * Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ gps = gpsunits[unit];
+ peer = gps->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(GPSREFID, (char *)&peer->refid,
+ 4);
+ else
+ peer->refid = htonl(GPSHSREFID);
+ }
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_GPS_TRAK;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2;
+ out->clockdesc = GPSDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ gps = gpsunits[unit];
+ out->lencode = gps->lencode; /* LENTOC */;
+ out->lastcode = gps->lastcode;
+ out->timereset = current_time - gps->timestarted;
+ out->polls = gps->polls;
+ out->noresponse = gps->noreply;
+ out->badformat = gps->badformat;
+ out->baddata = gps->baddata;
+ out->lastevent = gps->lastevent;
+ out->currentstatus = gps->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * trak_buginfo - return clock dependent debugging info
+ */
+static void
+trak_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gps = gpsunits[unit];
+
+ bug->nvalues = 10;
+ bug->ntimes = 5;
+ if (gps->lasttime != 0)
+ bug->values[0] = current_time - gps->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)gps->reason;
+ bug->values[2] = (U_LONG)gps->year;
+ bug->values[3] = (U_LONG)gps->day;
+ bug->values[4] = (U_LONG)gps->hour;
+ bug->values[5] = (U_LONG)gps->minute;
+ bug->values[6] = (U_LONG)gps->second;
+ bug->values[7] = (U_LONG)gps->msec;
+ bug->values[8] = gps->noreply;
+ bug->values[9] = gps->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = gps->lastref;
+ bug->times[1] = gps->lastrec;
+ bug->times[2] = gps->offset[0];
+ bug->times[3] = gps->offset[1];
+ bug->times[4] = gps->offset[2];
+}
+#endif
diff --git a/contrib/xntpd/xntpdc/ntpdc.c b/contrib/xntpd/xntpdc/ntpdc.c
index 001bd77c1e55..3113c9ff7817 100644
--- a/contrib/xntpd/xntpdc/ntpdc.c
+++ b/contrib/xntpd/xntpdc/ntpdc.c
@@ -53,7 +53,7 @@ static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
static int getarg P((char *, int, arg_v *));
static int getnetnum P((char *, U_LONG *, char *));
static void help P((struct parse *, FILE *));
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
static int helpsort P((const void *, const void *));
#else
static int helpsort P((char **, char **));
@@ -598,8 +598,12 @@ again:
/*
* So far, so good. Copy this data into the output array.
*/
- if ((datap + datasize) > (pktdata + pktdatasize))
+ if ((datap + datasize) > (pktdata + pktdatasize)) {
+ int offset = datap - pktdata;
growpktdata();
+ *rdata = pktdata; /* might have been realloced ! */
+ datap = pktdata + offset;
+ }
memmove(datap, (char *)rpkt.data, datasize);
datap += datasize;
if (firstpkt) {
@@ -1149,7 +1153,7 @@ help(pcmd, fp)
for (xcp = opcmds; xcp->keyword != 0; xcp++)
cmdsort[n++] = xcp->keyword;
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
qsort((void *)cmdsort, n, sizeof(char *), helpsort);
#else
qsort((char *)cmdsort, n, sizeof(char *), helpsort);
@@ -1195,7 +1199,7 @@ help(pcmd, fp)
* helpsort - do hostname qsort comparisons
*/
static int
-#if defined(sgi) || defined(SYS_BSDI)
+#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
helpsort(t1, t2)
const void *t1;
const void *t2;
diff --git a/contrib/xntpd/xntpdc/ntpdc_ops.c b/contrib/xntpd/xntpdc/ntpdc_ops.c
index 55483faeba10..4fa9324784cc 100644
--- a/contrib/xntpd/xntpdc/ntpdc_ops.c
+++ b/contrib/xntpd/xntpdc/ntpdc_ops.c
@@ -66,10 +66,9 @@ static void ctlstats P((struct parse *, FILE *));
static void leapinfo P((struct parse *, FILE *));
static void clockstat P((struct parse *, FILE *));
static void fudge P((struct parse *, FILE *));
-static void maxskew P((struct parse *, FILE *));
static void clkbug P((struct parse *, FILE *));
static void setprecision P((struct parse *, FILE *));
-static void setselect P((struct parse *, FILE *));
+static void kerninfo P((struct parse *, FILE *));
/*
* Commands we understand. Ntpdc imports this.
@@ -77,37 +76,37 @@ static void setselect P((struct parse *, FILE *));
struct xcmd opcmds[] = {
{ "listpeers", peerlist, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print list of peers the server knows about" },
+ "display list of peers the server knows about" },
{ "peers", peers, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print peer summary information" },
+ "display peer summary information" },
{ "dmpeers", dmpeers, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print peer summary info the way Dave Mills likes it" },
+ "display peer summary info the way Dave Mills likes it" },
{ "showpeer", showpeer, { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
{ "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
- "print detailed information for one or more peers" },
+ "display detailed information for one or more peers" },
{ "pstats", peerstats, { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
{ "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
- "print statistical information for one or more peers" },
+ "display statistical information for one or more peers" },
{ "loopinfo", loopinfo, { OPT|STR, NO, NO, NO },
{ "oneline|multiline", "", "", "" },
- "print loop filter information" },
+ "display loop filter information" },
{ "sysinfo", sysinfo, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print local server information" },
+ "display local server information" },
{ "sysstats", sysstats, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print local server statistics" },
+ "display local server statistics" },
{ "memstats", memstats, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print peer memory usage statistics" },
+ "display peer memory usage statistics" },
{ "iostats", iostats, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print I/O subsystem statistics" },
+ "display I/O subsystem statistics" },
{ "timerstats", timerstats, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print event timer subsystem statistics" },
+ "display event timer subsystem statistics" },
{ "addpeer", addpeer, { ADD, OPT|UINT, OPT|UINT, OPT|STR },
{ "addr", "keyid", "version", "minpoll|prefer" },
"configure a new peer association" },
@@ -121,14 +120,14 @@ struct xcmd opcmds[] = {
{ "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
"unconfigure existing peer assocations" },
{ "set", set, { STR, OPT|STR, OPT|STR, OPT|STR },
- { "bclient|auth", "...", "...", "..." },
- "set a system flag (bclient, authenticate)" },
+ { "bclient|mclient|auth", "...", "...", "..." },
+ "set a system flag (bclient, mclient, auth)" },
{ "clear", sys_clear, { STR, OPT|STR, OPT|STR, OPT|STR },
- { "bclient|auth", "...", "...", "..." },
- "clear a system flag (bclient, authenticate)" },
+ { "bclient|mclient|auth", "...", "...", "..." },
+ "clear a system flag (bclient, mclient, auth)" },
{ "reslist", reslist, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print the server's restrict list" },
+ "display the server's restrict list" },
{ "restrict", restrict, { ADD, ADD, STR, OPT|STR },
{ "address", "mask",
"ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer",
@@ -144,7 +143,7 @@ struct xcmd opcmds[] = {
"delete a restrict entry" },
{ "monlist", monlist, { NO, NO, NO, NO },
{ "", "", "", "" },
- "print data the server's monitor routines have collected" },
+ "display data the server's monitor routines have collected" },
{ "monitor", monitor, { STR, NO, NO, NO },
{ "on|off", "", "", "" },
"turn the server's monitoring facility on or off" },
@@ -171,10 +170,10 @@ struct xcmd opcmds[] = {
"remove one or more key ID's from the trusted list" },
{ "authinfo", authinfo, { NO, NO, NO, NO },
{ "", "", "", "" },
- "obtain information concerning the state of the authentication code" },
+ "display the state of the authentication code" },
{ "traps", traps, { NO, NO, NO, NO },
{ "", "", "", "" },
- "obtain information about traps set in server" },
+ "display the traps set in the server" },
{ "addtrap", addtrap, { ADD, OPT|UINT, OPT|ADD, NO },
{ "address", "port", "interface", "" },
"configure a trap in the server" },
@@ -189,28 +188,26 @@ struct xcmd opcmds[] = {
"change the keyid the server uses to authenticate control messages" },
{ "ctlstats", ctlstats, { NO, NO, NO, NO },
{ "", "", "", "" },
- "obtain packet count statistics from the control module" },
+ "display packet count statistics from the control module" },
{ "leapinfo", leapinfo, { NO, NO, NO, NO },
{ "", "", "", "" },
- "obtain information about the current leap second state" },
+ "display the current leap second state" },
{ "clockstat", clockstat, { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
{ "address", "address", "address", "address" },
- "obtain status information about the specified clock" },
+ "display clock status information" },
{ "fudge", fudge, { ADD, STR, STR, NO },
{ "address", "time1|time2|val1|val2|flags", "value", "" },
"set/change one of a clock's fudge factors" },
- { "maxskew", maxskew, { STR, NO, NO, NO },
- { "maximum_skew", "", "", "" },
- "set the server's maximum skew parameter" },
{ "clkbug", clkbug, { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
{ "address", "address", "address", "address" },
- "obtain debugging information from the specified clock" },
+ "display clock debugging information" },
{ "setprecision", setprecision, { INT, NO, NO, NO },
{ "sys_precision", "", "", "" },
"set the server's advertised precision" },
- { "setselect", setselect, { UINT, NO, NO, NO },
- { "select_algorithm_number", "", "", "" },
- "change the selection weighting algorithm used by the server" },
+ { "kerninfo", kerninfo, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display the kernel pll/pps variables" },
+
{ 0, 0, { NO, NO, NO, NO },
{ "", "", "", "" }, "" }
};
@@ -374,9 +371,9 @@ dopeers(pcmd, fp, dmstyle)
return;
(void) fprintf(fp,
- " remote local st poll reach delay offset disp\n");
+ " remote local st poll reach delay offset disp\n");
(void) fprintf(fp,
- "======================================================================\n");
+ "=======================================================================\n");
while (items > 0) {
if (!dmstyle) {
if (plist->flags & INFO_FLAG_SYSPEER)
@@ -407,13 +404,14 @@ dopeers(pcmd, fp, dmstyle)
ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
NTP_MINPOLL);
(void) fprintf(fp,
- "%c%-15.15s %-15.15s %2d %4d %3o %7.7s %9.9s %6.6s\n",
+ "%c%-15.15s %-15.15s %2d %4d %3o %7.7s %9.9s %7.7s\n",
c, nntohost(plist->srcadr),
numtoa(plist->dstadr),
plist->stratum, ntp_poll, plist->reach,
- fptoa(NTOHS_FP(plist->delay), 4),
+ fptoa(NTOHS_FP(plist->delay), 5),
lfptoa(&tempts, 6),
- ufptoa(NTOHS_FP(plist->dispersion), 4));
+ ufptoa(NTOHS_FP(plist->dispersion), 5));
+
plist++;
items--;
}
@@ -451,16 +449,19 @@ printpeer(pp, fp)
"leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
pp->leap & 0x2 ? '1' : '0',
pp->leap & 0x1 ? '1' : '0',
- str, ufptoa(HTONS_FP(pp->rootdelay), 4),
- ufptoa(HTONS_FP(pp->rootdispersion), 4));
+ str, ufptoa(HTONS_FP(pp->rootdelay), 5),
+ ufptoa(HTONS_FP(pp->rootdispersion), 5));
(void) fprintf(fp,
"ppoll %d, hpoll %d, keyid %u, version %d, association %u\n",
pp->ppoll, pp->hpoll, pp->keyid, pp->version, ntohs(pp->associd));
(void) fprintf(fp,
- "valid %d, reach %03o, unreach %d, trust %03o\n",
- pp->valid, pp->reach, pp->unreach, pp->trust);
+ "valid %d, reach %03o, unreach %d, flash %03o, ",
+ pp->valid, pp->reach, pp->unreach, pp->flash);
+
+ (void) fprintf(fp, "estbdelay %s, ttl %d\n",
+ mfptoa(0, ntohl(pp->estbdelay), 5), pp->ttl);
(void) fprintf(fp, "timer %ds, flags", ntohl(pp->timer));
if (pp->flags == 0) {
@@ -508,7 +509,8 @@ printpeer(pp, fp)
(void) fprintf(fp, "filter delay: ");
for (i = 0; i < NTP_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s", fptoa(HTONS_FP(pp->filtdelay[i]),4));
+ (void) fprintf(fp, " %-8.8s",
+ fptoa(HTONS_FP(pp->filtdelay[i]), 5));
if (i == (NTP_SHIFT>>1)-1)
(void) fprintf(fp, "\n ");
}
@@ -517,7 +519,7 @@ printpeer(pp, fp)
(void) fprintf(fp, "filter offset:");
for (i = 0; i < NTP_SHIFT; i++) {
HTONL_FP(&pp->filtoffset[i], &tempts);
- (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 5));
+ (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
if (i == (NTP_SHIFT>>1)-1)
(void) fprintf(fp, "\n ");
}
@@ -531,23 +533,13 @@ printpeer(pp, fp)
}
(void) fprintf(fp, "\n");
- (void) fprintf(fp, "bdelay filter:");
- for (i = 0; i < NTP_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s",
- mfptoa(0, ntohl(pp->bdelay[i]), 5));
- if (i == (NTP_SHIFT>>1)-1)
- (void) fprintf(fp, "\n ");
- }
- (void) fprintf(fp, "\n");
-
- (void) fprintf(fp, "delay %s, estbdelay %s\n",
- fptoa(HTONS_FP(pp->delay), 4),
- mfptoa(0, ntohl(pp->estbdelay), 4));
HTONL_FP(&pp->offset, &tempts);
- (void) fprintf(fp, "offset %s, dispersion %s\n",
- lfptoa(&tempts, 6),
- ufptoa(HTONS_FP(pp->dispersion), 4));
+ (void) fprintf(fp,
+ "offset %s, delay %s, dispersion %s, selectdisp %s\n",
+ lfptoa(&tempts, 6), fptoa(HTONS_FP(pp->delay), 5),
+ ufptoa(HTONS_FP(pp->dispersion), 5),
+ ufptoa(HTONS_FP(pp->selectdisp), 5));
}
@@ -781,11 +773,10 @@ sysinfo(pcmd, fp)
is->leap & 0x1 ? '1' : '0');
(void) fprintf(fp, "stratum: %d\n", (int)is->stratum);
(void) fprintf(fp, "precision: %d\n", (int)is->precision);
- (void) fprintf(fp, "select algorithm: %d\n", (int)is->selection);
(void) fprintf(fp, "sync distance: %s\n",
- fptoa(NTOHS_FP(is->rootdelay), 4));
+ fptoa(NTOHS_FP(is->rootdelay), 5));
(void) fprintf(fp, "sync dispersion: %s\n",
- ufptoa(NTOHS_FP(is->rootdispersion), 4));
+ ufptoa(NTOHS_FP(is->rootdispersion), 5));
if (is->stratum <= 1) {
junk[4] = 0;
memmove(junk, (char *)&is->refid, 4);
@@ -799,7 +790,8 @@ sysinfo(pcmd, fp)
(void) fprintf(fp, "reference time: %s\n", prettydate(&tempts));
(void) fprintf(fp, "system flags: ");
- if ((is->flags & (INFO_FLAG_BCLIENT|INFO_FLAG_AUTHENABLE)) == 0) {
+ if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_MCLIENT |
+ INFO_FLAG_AUTHENABLE)) == 0) {
(void) fprintf(fp, "none\n");
} else {
res = 0;
@@ -807,6 +799,10 @@ sysinfo(pcmd, fp)
(void) fprintf(fp, "bclient");
res = 1;
}
+ if (is->flags & INFO_FLAG_MCLIENT) {
+ (void) fprintf(fp, "mclient");
+ res = 1;
+ }
if (is->flags & INFO_FLAG_AUTHENABLE)
(void) fprintf(fp, "%sauthenticate",
res ? ", " : "");
@@ -818,8 +814,6 @@ sysinfo(pcmd, fp)
HTONL_FP(&is->authdelay, &tempts);
(void) fprintf(fp, "encryption delay: %s\n", lfptoa(&tempts, 7));
- (void) fprintf(fp, "maximum skew: %s\n",
- ufptoa(NTOHS_FP(is->maxskew), 4));
}
@@ -846,8 +840,12 @@ sysstats(pcmd, fp)
if (!check1item(items, fp))
return;
- if (!checkitemsize(itemsize, sizeof(struct info_sys_stats)))
+ if (itemsize != sizeof(struct info_sys_stats) &&
+ itemsize != sizeof(struct old_info_sys_stats)) {
+ /* issue warning according to new structure size */
+ checkitemsize(itemsize, sizeof(struct info_sys_stats));
return;
+ }
(void) fprintf(fp, "system uptime: %d\n",
ntohl(ss->timeup));
@@ -867,8 +865,11 @@ sysstats(pcmd, fp)
ntohl(ss->processed));
(void) fprintf(fp, "bad authentication: %d\n",
ntohl(ss->badauth));
- (void) fprintf(fp, "wander hold downs: %d\n",
- ntohl(ss->wanderhold));
+ if (itemsize != sizeof(struct info_sys_stats))
+ return;
+
+ (void) fprintf(fp, "limitation rejects: %d\n",
+ ntohl(ss->limitrejected));
}
@@ -1205,6 +1206,8 @@ doset(pcmd, fp, req)
for (items = 0; items < pcmd->nargs; items++) {
if (STREQ(pcmd->argval[items].string, "bclient"))
sys.flags |= SYS_FLAG_BCLIENT;
+ else if (STREQ(pcmd->argval[items].string, "mclient"))
+ sys.flags |= SYS_FLAG_MCLIENT;
else if (STREQ(pcmd->argval[items].string, "auth"))
sys.flags |= SYS_FLAG_AUTHENTICATE;
else {
@@ -1243,6 +1246,7 @@ static struct resflags resflags[] = {
{ "nopeer", RES_NOPEER },
{ "notrap", RES_NOTRAP },
{ "lptrap", RES_LPTRAP },
+ { "limited", RES_LIMITED },
{ "", 0 }
};
@@ -1463,6 +1467,7 @@ monlist(pcmd, fp)
FILE *fp;
{
struct info_monitor *ml;
+ struct old_info_monitor *oml;
int items;
int itemsize;
int res;
@@ -1476,23 +1481,49 @@ monlist(pcmd, fp)
if (!checkitems(items, fp))
return;
- if (!checkitemsize(itemsize, sizeof(struct info_monitor)))
- return;
+ if (itemsize == sizeof(struct info_monitor)) {
- (void) fprintf(fp,
- " address port count mode version lasttime firsttime\n");
- (void) fprintf(fp,
- "=====================================================================\n");
- while (items > 0) {
- (void) fprintf(fp, "%-20.20s %5d %9d %4d %3d %9u %9u\n",
- nntohost(ml->addr),
- ntohs(ml->port),
- ntohl(ml->count),
- ml->mode, ml->version,
- ntohl(ml->lasttime),
- ntohl(ml->firsttime));
- ml++;
- items--;
+ (void) fprintf(fp,
+ " address port count mode version lastdrop lasttime firsttime\n");
+ (void) fprintf(fp,
+ "===============================================================================\n");
+ while (items > 0) {
+ (void) fprintf(fp, "%-20.20s %5d %9d %4d %3d %9u %9u %9u\n",
+ nntohost(ml->addr),
+ ntohs(ml->port),
+ ntohl(ml->count),
+ ml->mode,
+ ml->version,
+ ntohl(ml->lastdrop),
+ ntohl(ml->lasttime),
+ ntohl(ml->firsttime));
+ ml++;
+ items--;
+ }
+ } else {
+ if (itemsize != sizeof(struct old_info_monitor)) {
+ /* issue warning according to new info_monitor size */
+ checkitemsize(itemsize, sizeof(struct info_monitor));
+ return;
+ }
+
+ oml = (struct old_info_monitor *)ml;
+ (void) fprintf(fp,
+ " address port count mode version lasttime firsttime\n");
+ (void) fprintf(fp,
+ "======================================================================\n");
+ while (items > 0) {
+ (void) fprintf(fp, "%-20.20s %5d %9d %4d %3d %9u %9u\n",
+ nntohost(oml->addr),
+ ntohs(oml->port),
+ ntohl(oml->count),
+ oml->mode,
+ oml->version,
+ ntohl(oml->lasttime),
+ ntohl(oml->firsttime));
+ oml++;
+ items--;
+ }
}
}
@@ -2247,39 +2278,6 @@ fudge(pcmd, fp)
return;
}
-
-
-/*
- * maxskew - set the server's maximum skew parameter
- */
-static void
-maxskew(pcmd, fp)
- struct parse *pcmd;
- FILE *fp;
-{
- u_fp Xmaxskew;
- l_fp tmp;
- int items;
- int itemsize;
- char *dummy;
- int res;
-
- if (!atolfp(pcmd->argval[0].string, &tmp)) {
- (void) fprintf(stderr, "What the heck does %s mean?\n",
- pcmd->argval[0].string);
- return;
- }
- Xmaxskew = HTONS_FP(LFPTOFP(&tmp));
-
- res = doquery(IMPL_XNTPD, REQ_SET_MAXSKEW, 1, 1, sizeof(u_fp),
- (char *)&Xmaxskew, &items, &itemsize, &dummy);
-
- if (res == 0)
- (void) fprintf(fp, "done!\n");
-}
-
-
-
/*
* clkbug - get and print clock debugging information
*/
@@ -2395,27 +2393,72 @@ setprecision(pcmd, fp)
}
-
/*
- * setselect - change the server's selection algorithm
+ * kerninfo - display the kernel pll/pps variables
*/
static void
-setselect(pcmd, fp)
+kerninfo(pcmd, fp)
struct parse *pcmd;
FILE *fp;
{
- U_LONG select_code;
+ struct info_kernel *ik;
int items;
int itemsize;
- char *dummy;
int res;
- select_code = htonl(pcmd->argval[0].uval);
+ res = doquery(IMPL_XNTPD, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
+ &items, &itemsize, (char **)&ik);
+ if (res != 0 && items == 0)
+ return;
+ if (!check1item(items, fp))
+ return;
+ if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
+ return;
- res = doquery(IMPL_XNTPD, REQ_SET_SELECT_CODE, 1, 1, sizeof(U_LONG),
- (char *)&select_code, &items, &itemsize, &dummy);
-
- if (res == 0)
- (void) fprintf(fp, "done!\n");
- return;
+ /*
+ * pll variables
+ */
+ (void)fprintf(fp, "pll offset: %d us\n",
+ ntohl(ik->offset));
+ (void)fprintf(fp, "pll frequency: %s ppm\n",
+ fptoa((s_fp)ntohl(ik->freq), 3));
+ (void)fprintf(fp, "maximum error: %d us\n",
+ ntohl(ik->maxerror));
+ (void)fprintf(fp, "estimated error: %d us\n",
+ ntohl(ik->esterror));
+ (void)fprintf(fp, "status: %04x\n",
+ ntohs(ik->status & 0xffff));
+ (void)fprintf(fp, "pll time constant: %d\n",
+ ntohl(ik->constant));
+ (void)fprintf(fp, "precision: %d us\n",
+ ntohl(ik->precision));
+ (void)fprintf(fp, "frequency tolerance: %s ppm\n",
+ fptoa((s_fp)ntohl(ik->tolerance), 0));
+
+ /*
+ * For backwards compatibility (ugh), we find the pps variables
+ * only if the shift member is nonzero.
+ */
+ if (!ik->shift)
+ return;
+
+ /*
+ * pps variables
+ */
+ (void)fprintf(fp, "pps frequency: %s ppm\n",
+ fptoa((s_fp)ntohl(ik->ppsfreq), 3));
+ (void)fprintf(fp, "pps stability: %s ppm\n",
+ fptoa((s_fp)ntohl(ik->stabil), 3));
+ (void)fprintf(fp, "pps jitter: %d us\n",
+ ntohl(ik->jitter));
+ (void)fprintf(fp, "calibration interval: %d s\n",
+ 1 << ntohs(ik->shift));
+ (void)fprintf(fp, "calibration cycles: %d\n",
+ ntohl(ik->calcnt));
+ (void)fprintf(fp, "jitter exceeded: %d\n",
+ ntohl(ik->jitcnt));
+ (void)fprintf(fp, "stability exceeded: %d\n",
+ ntohl(ik->stbcnt));
+ (void)fprintf(fp, "calibration errors: %d\n",
+ ntohl(ik->errcnt));
}
diff --git a/contrib/xntpd/xntpres/xntpres.c b/contrib/xntpd/xntpres/xntpres.c
index ee88b1f3be98..47c6eda7dc12 100644
--- a/contrib/xntpd/xntpres/xntpres.c
+++ b/contrib/xntpd/xntpres/xntpres.c
@@ -46,6 +46,7 @@ struct conf_entry {
#define ce_minpoll ce_config.minpoll
#define ce_maxpoll ce_config.maxpoll
#define ce_flags ce_config.flags
+#define ce_ttl ce_config.ttl
#define ce_keyid ce_config.keyid
/*
@@ -100,8 +101,9 @@ int resolve_value; /* next value of resolve timer */
#define TOK_MINPOLL 3
#define TOK_MAXPOLL 4
#define TOK_FLAGS 5
-#define TOK_KEYID 6
-#define NUMTOK 7
+#define TOK_TTL 6
+#define TOK_KEYID 7
+#define NUMTOK 8
#define MAXLINESIZE 512
@@ -128,7 +130,7 @@ extern int errno;
static RETSIGTYPE bong P((int));
static void checkparent P((void));
static void removeentry P((struct conf_entry *));
-static void addentry P((char *, int, int, int, int, int, U_LONG));
+static void addentry P((char *, int, int, int, int, int, int, U_LONG));
static int findhostaddr P((struct conf_entry *));
static void openntp P((void));
static int request P((struct conf_peer *));
@@ -338,13 +340,14 @@ removeentry(entry)
* addentry - add an entry to the configuration list
*/
static void
-addentry(name, mode, version, minpoll, maxpoll, flags, keyid)
+addentry(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
char *name;
int mode;
int version;
int minpoll;
int maxpoll;
int flags;
+ int ttl;
U_LONG keyid;
{
register char *cp;
@@ -363,6 +366,7 @@ addentry(name, mode, version, minpoll, maxpoll, flags, keyid)
ce->ce_minpoll = (u_char)minpoll;
ce->ce_maxpoll = (u_char)maxpoll;
ce->ce_flags = (u_char)flags;
+ ce->ce_ttl = (u_char)ttl;
ce->ce_keyid = htonl(keyid);
ce->ce_next = NULL;
@@ -802,9 +806,9 @@ readconf(fp, name)
* This is as good as we can check it. Add it in.
*/
addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
- (int)intval[TOK_VERSION],
- (int)intval[TOK_MINPOLL], (int)intval[TOK_MAXPOLL],
- flags, intval[TOK_KEYID]);
+ (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
+ (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
+ intval[TOK_KEYID]);
}
}
diff --git a/etc/Makefile b/etc/Makefile
index 9b4b804c2471..f67591f79ddf 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -1,7 +1,5 @@
# from: @(#)Makefile 5.11 (Berkeley) 5/21/91
-# $Id: Makefile,v 1.53.2.5 1994/05/03 10:08:21 rgrimes Exp $
-
-NOOBJ= noobj
+# $Id: Makefile,v 1.76 1994/06/29 21:19:38 jkh Exp $
# disktab may be wrong -- hcx9 is a tahoe, but gets its own.
# -rw-r--r--
@@ -9,16 +7,23 @@ BINOWN= root
BINGRP= wheel
BIN1= aliases csh.cshrc csh.login csh.logout dm.conf \
ftpusers gettytab group hosts host.conf hosts.equiv hosts.lpd \
- inetd.conf motd myname netstart networks phones \
- printcap protocols rc rc.local remote security services shells \
- syslog.conf ttys etc.${MACHINE}/disktab rpc
+ inetd.conf login.access motd myname netstart \
+ networks phones printcap protocols rc rc.local remote \
+ security services shells skey.access \
+ syslog.conf ttys etc.${MACHINE}/disktab rpc make.conf \
+ ${.CURDIR}/../gnu/usr.bin/man/manpath/manpath.config \
+ ${.CURDIR}/../usr.bin/mail/misc/mail.rc
# -rw-rw-rw-
BIN2= motd
-# -rwxr-xr-x root.wheel, for the new f***ing cron root.wheel
+# -rwxr-xr-x root.wheel, for the new cron root.wheel
BIN3= daily weekly monthly
+CLEANFILES+= *.o *.lo *.c *.cache *.mk kcopy filesystem
+
+ZIPNSPLIT= gzip --no-name -9 -c | split -b 240640 -
+
MTREE= BSD.local.dist BSD.root.dist BSD.usr.dist BSD.var.dist
NAMEDB= localhost.rev named.boot root.cache
PCS= pcs750.bin
@@ -27,14 +32,14 @@ WCS2= fpevent fppwcs fppwcs_dual hdcwcs load_diags start_fpp wcs wcs_dual
# Special top level files for FreeBSD
COPYRIGHT= COPYRIGHT.386BSD COPYRIGHT.FreeBSD
-FREEBSD= CONTRIB.386BSD CONTRIB.FreeBSD
+FREEBSD= CONTRIB.386BSD CONTRIB.FreeBSD ROSTER.FreeBSD
FREEBSD+= MIRROR.SITES PERSONAL.ACKS RELNOTES.FreeBSD SUPPORT.TXT
FREEBSD+= ${COPYRIGHT}
#
# Floppy drive name and files for building FreeBSD Floppies
FLOPPY?= fd0
MOUNT?= /mnt
-FLOPPY_TYPE?= fd1200
+FLOPPY_TYPE?= fd1440
#
MDEC= usr/mdec/bootfd usr/mdec/fdboot
MDEC+= usr/mdec/bootsd usr/mdec/sdboot
@@ -42,10 +47,9 @@ MDEC+= usr/mdec/bootwd usr/mdec/wdboot
#
KC_DIRS= bin dev mnt sbin
KC_FILES= ${COPYRIGHT}
-KC_FILES+= bin/sh # XXX Crunch is broken!
-KC_FILES+= sbin/mount sbin/mount_isofs # XXX Crunch is broken!
-KC_LINKS= bin/[ bin/cp bin/echo bin/test
+KC_LINKS= bin/[ bin/cp bin/echo bin/sh bin/test
KC_LINKS+= sbin/fsck sbin/halt sbin/init
+KC_LINKS+= sbin/mount sbin/mount_isofs
KC_LINKS+= sbin/umount
#
CD_DIRS= etc usr
@@ -53,13 +57,12 @@ CD_DIRS= etc usr
FILESYSTEM_DIRS= bin dev etc mnt proc sbin usr usr/bin usr/mdec usr/sbin
FILESYSTEM_TREES= dev
FILESYSTEM_FILES= ${COPYRIGHT}
-FILESYSTEM_FILES+= bin/sh # XXX Crunch is broken!
FILESYSTEM_FILES+= dev/MAKEDEV
FILESYSTEM_FILES+= etc/group
FILESYSTEM_FILES+= etc/master.passwd etc/passwd etc/pwd.db
FILESYSTEM_FILES+= ${MDEC}
FILESYSTEM_LINKS= bin/[ bin/expr bin/ls bin/mkdir bin/rm
-FILESYSTEM_LINKS+= bin/sync bin/test
+FILESYSTEM_LINKS+= bin/sh bin/sync bin/test
FILESYSTEM_LINKS+= sbin/disklabel sbin/fdisk sbin/halt sbin/init
FILESYSTEM_LINKS+= sbin/mount sbin/mount_pcfs
FILESYSTEM_LINKS+= sbin/newfs
@@ -92,13 +95,13 @@ CPIO_CPIO+= usr/bin/awk usr/bin/chgrp usr/bin/cpio usr/bin/ex usr/bin/ftp
CPIO_CPIO+= usr/bin/gunzip usr/bin/gzcat usr/bin/gzip
CPIO_CPIO+= usr/bin/more usr/bin/tar usr/bin/tip
CPIO_CPIO+= usr/bin/vi usr/bin/view usr/bin/zcat
-CPIO_CPIO+= usr/lib/libc.so.1.0
-CPIO_CPIO+= usr/lib/libcurses.so.1.0
-CPIO_CPIO+= usr/lib/libgcc.so.1.0
-CPIO_CPIO+= usr/lib/libm.so.1.0
-CPIO_CPIO+= usr/lib/libtermlib.so.1.0
-CPIO_CPIO+= usr/lib/libtermcap.so.1.0
-CPIO_CPIO+= usr/lib/libutil.so.1.0
+CPIO_CPIO+= usr/lib/libc.so.1.1
+CPIO_CPIO+= usr/lib/libcurses.so.1.1
+CPIO_CPIO+= usr/lib/libgcc.so.1.1
+CPIO_CPIO+= usr/lib/libm.so.1.1
+CPIO_CPIO+= usr/lib/libtermlib.so.1.1
+CPIO_CPIO+= usr/lib/libtermcap.so.1.1
+CPIO_CPIO+= usr/lib/libutil.so.1.1
CPIO_CPIO+= usr/libexec/ld.so
CPIO_CPIO+= usr/sbin/bad144 usr/sbin/chown
CPIO_CPIO+= usr/share/misc/termcap
@@ -114,10 +117,10 @@ CRYPT_SRCS+= usr.bin/bdes usr.bin/lock usr.bin/login usr.bin/passwd
CRYPT_SRCS+= usr.bin/rlogin usr.bin/rsh usr.bin/su usr.bin/telnet
CRYPT_DIRS= bin sbin usr usr/bin usr/lib usr/libexec
-all clean cleandir depend etc install lint:
+all depend etc install lint:
crypt:
- rm -f ${LIBCRYPT};
+ rm -f /usr/lib/libcrypt*
(cd ${.CURDIR}/../${CRYPT_LIB}; \
${MAKE} cleandir obj depend all install)
for i in ${CRYPT_SRCS}; do \
@@ -126,41 +129,44 @@ crypt:
done
non-crypt:
- rm -f ${LIBCRYPT}
+ rm -f /usr/lib/libcrypt*
for i in ${CRYPT_SRCS}; do \
cd ${.CURDIR}/../$$i; \
${MAKE} cleandir obj depend all; \
done
distribution: distrib-dirs
- install -c -o ${BINOWN} -g ${BINGRP} -m 644 ${BIN1} ${DESTDIR}/etc
- install -c -o ${BINOWN} -g ${BINGRP} -m 666 ${BIN2} ${DESTDIR}/etc
- install -c -o root -g wheel -m 755 ${BIN3} ${DESTDIR}/etc
- install -c -o root -g wheel -m 644 crontab ${DESTDIR}/etc
- install -c -o root -g wheel -m 600 /dev/null ${DESTDIR}/var/cron/log
- install -c -o root -g wheel -m 600 master.passwd ${DESTDIR}/etc
- pwd_mkdb -p -d ${DESTDIR}/etc ${DESTDIR}/etc/master.passwd
+ (cd ${.CURDIR}; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 ${BIN1} ${DESTDIR}/etc; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 666 ${BIN2} ${DESTDIR}/etc; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 ${BIN3} ${DESTDIR}/etc; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 crontab ${DESTDIR}/etc; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 600 /dev/null \
+ ${DESTDIR}/var/cron/log; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 600 \
+ master.passwd ${DESTDIR}/etc; \
+ pwd_mkdb -p -d ${DESTDIR}/etc ${DESTDIR}/etc/master.passwd; \
install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
- MAKEDEV.local etc.${MACHINE}/MAKEDEV ${DESTDIR}/dev
+ MAKEDEV.local etc.${MACHINE}/MAKEDEV ${DESTDIR}/dev )
.if defined(CDROMDIST)
- (cd ${DESTDIR}/dev; sh MAKEDEV all)
+ (cd ${DESTDIR}/dev; sh MAKEDEV all) ;
.endif
- (cd root; \
- install -c -o root -g wheel -m 644 dot.cshrc \
+ (cd ${.CURDIR}/root; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 dot.cshrc \
${DESTDIR}/root/.cshrc; \
- install -c -o root -g wheel -m 644 dot.klogin \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 dot.klogin \
${DESTDIR}/root/.klogin; \
- install -c -o root -g wheel -m 644 dot.login \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 dot.login \
${DESTDIR}/root/.login; \
- install -c -o root -g wheel -m 644 dot.profile \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 dot.profile \
${DESTDIR}/root/.profile; \
rm -f ${DESTDIR}/.cshrc ${DESTDIR}/.profile; \
ln ${DESTDIR}/root/.cshrc ${DESTDIR}/.cshrc; \
ln ${DESTDIR}/root/.profile ${DESTDIR}/.profile)
- cd mtree; install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${MTREE} \
- ${DESTDIR}/etc/mtree
- cd namedb; install -c -o ${BINOWN} -g ${BINGRP} -m 644 ${NAMEDB} \
- ${DESTDIR}/etc/namedb
+ cd ${.CURDIR}/mtree; install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${MTREE} ${DESTDIR}/etc/mtree
+ cd ${.CURDIR}/namedb; install -c -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${NAMEDB} ${DESTDIR}/etc/namedb
install -c -o ${BINOWN} -g operator -m 664 /dev/null \
${DESTDIR}/etc/dumpdates
install -c -o nobody -g ${BINGRP} -m 664 /dev/null \
@@ -177,56 +183,75 @@ distribution: distrib-dirs
${DESTDIR}/var/log/wtmp
install -c -o ${BINOWN} -g ${BINGRP} -m 664 /dev/null \
${DESTDIR}/var/run/utmp
- (cd etc.${MACHINE}; install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
- fstab.* ${DESTDIR}/etc)
+ install -c -o ${BINOWN} -g ${BINGRP} -m 664 ${.CURDIR}/minfree \
+ ${DESTDIR}/var/crash
+ (cd ${.CURDIR}/etc.${MACHINE}; install -c -o ${BINOWN} -g ${BINGRP} \
+ -m 444 fstab.* ${DESTDIR}/etc)
.if defined(NOCRYPT)
- ${MAKE} non-crypt
- (cd ..; NOCRYPT=nocrypt; export NOCRYPT; ${MAKE} install)
+ (cd ${.CURDIR}; ${MAKE} non-crypt)
+ (cd ${.CURDIR}/..; NOCRYPT=nocrypt; export NOCRYPT; ${MAKE} install)
.else
- ${MAKE} crypt
- (cd ..; ${MAKE} install)
+ (cd ${.CURDIR}; ${MAKE} crypt)
+ (cd ${.CURDIR}/..; ${MAKE} install)
.endif
- (cd ../usr.sbin/sendmail/src; \
+ (cd ${.CURDIR}/../usr.sbin/sendmail/src; \
${MAKE} install; \
cd ../cf/cf; \
${MAKE} obj; \
${MAKE} freefall.cf; \
- install -o root -g wheel -m 644 obj/freefall.cf \
+ install -o ${BINOWN} -g ${BINGRP} -m 644 obj/freefall.cf \
${DESTDIR}/etc/sendmail.cf)
- (cd ../; \
- install -c -o root -g wheel -m 444 ${FREEBSD} ${DESTDIR}/)
- (cd ..; ${MAKE} mdec; )
- (cd ../share/man; ${MAKE} makedb; )
+ (cd ${.CURDIR}/..; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${FREEBSD} ${DESTDIR}/)
+ (cd ${.CURDIR}/..; ${MAKE} mdec; )
+ (cd ${.CURDIR}/../share/man; ${MAKE} makedb; )
.if ${MACHINE} == "tahoe"
- (cd etc.tahoe; install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${WCS1} \
- ${DESTDIR}/)
+ (cd ${.CURDIR}/etc.tahoe; install -c -o ${BINOWN} -g ${BINGRP} \
+ -m 444 ${WCS1} ${DESTDIR}/)
.endif
.if ${MACHINE} == "vax"
- (cd etc.vax; install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${PCS} \
- ${DESTDIR}/)
+ (cd ${.CURDIR}/etc.vax; install -c -o ${BINOWN} -g ${BINGRP} \
+ -m 444 ${PCS} ${DESTDIR}/)
.endif
+crunch:
+ crunchgen ${.CURDIR}/../contrib/crunch/examples/kcopy.conf
+ ${MAKE} -f kcopy.mk objs exe
+ crunchgen ${.CURDIR}/../contrib/crunch/examples/filesystem.conf
+ ${MAKE} -f filesystem.mk objs exe
+
+extract:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
+ ${.CURDIR}/etc.i386/EXTRACT_bin.sh \
+ ${RELEASEDIR}/tarballs/bindist/EXTRACT.sh
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
+ ${.CURDIR}/etc.i386/EXTRACT_src.sh \
+ ${RELEASEDIR}/tarballs/srcdist/EXTRACT.sh
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
+ ${.CURDIR}/etc.i386/EXTRACT_secr.sh \
+ ${RELEASEDIR}/tarballs/secrdist/EXTRACT.sh
+
hcx9-distribution:
- (cd etc.tahoe; install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${WCS2} \
- ${DESTDIR}/)
-
-kcopy-kernels: ../sys/i386/conf/GENERICAH ../sys/i386/conf/GENERICBT
- (cd ../sys/compile; rm -rf GENERICAH GENERICBT)
- (cd ../sys/i386/conf; config GENERICAH; config GENERICBT)
- (cd ../sys/compile/GENERICAH; ${MAKE} depend; ${MAKE} all; \
- install -c -o root -g wheel -m 755 386bsd \
+ (cd ${.CURDIR}/etc.tahoe; install -c -o ${BINOWN} -g ${BINGRP} \
+ -m 444 ${WCS2} ${DESTDIR}/)
+
+kcopy-kernels: ${.CURDIR}/../sys/i386/conf/GENERICAH ${.CURDIR}/../sys/i386/conf/GENERICBT
+ (cd ${.CURDIR}/../sys/compile; rm -rf GENERICAH GENERICBT)
+ (cd ${.CURDIR}/../sys/i386/conf; config GENERICAH; config GENERICBT)
+ (cd ${.CURDIR}/../sys/compile/GENERICAH; ${MAKE} depend; ${MAKE} all; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd \
${DESTDIR}/386bsd.GENERICAH)
- (cd ../sys/compile/GENERICBT; ${MAKE} depend; ${MAKE} all; \
- install -c -o root -g wheel -m 755 386bsd \
+ (cd ${.CURDIR}/../sys/compile/GENERICBT; ${MAKE} depend; ${MAKE} all; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd \
${DESTDIR}/386bsd.GENERICBT)
kcopy-floppy:
disklabel -w -r ${FLOPPY} ${FLOPPY_TYPE} \
- /usr/mdec/fdboot /usr/mdec/bootfd
- newfs -b 4096 -c 80 -f 512 -i 10240 -m 0 -o space \
+ ${DESTDIR}/usr/mdec/fdboot ${DESTDIR}/usr/mdec/bootfd
+ newfs -b 4096 -c 80 -f 512 -i 8192 -m 0 -o space \
r${FLOPPY} ${FLOPPY_TYPE}
mount /dev/${FLOPPY} ${MOUNT}
- chown root.wheel ${MOUNT}/.
+ chown ${BINOWN}.${BINGRP} ${MOUNT}/.
chmod 755 ${MOUNT}/.
(cd ${DESTDIR}/; \
ls -d ${KC_DIRS} | cpio -pdamuv ${MOUNT})
@@ -239,10 +264,10 @@ kcopy-floppy:
rm -rf rmcd*)
(cd ${DESTDIR}/; \
ls ${KC_FILES} | cpio -pdamuv ${MOUNT})
- install -c -o root -g wheel -m 755 etc.i386/kc.profile \
- ${MOUNT}/.profile
- install -c -o root -g wheel -m 755 ${RELEASEDIR}/distbin/kcopy \
- ${MOUNT}/bin/kcopy
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/kc.profile ${MOUNT}/.profile
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ kcopy ${MOUNT}/bin/kcopy
(cd ${MOUNT}/; \
for i in ${KC_LINKS}; do \
ln bin/kcopy $$i; \
@@ -250,27 +275,27 @@ kcopy-floppy:
kcopy_ah.flp:
${MAKE} kcopy-floppy
- (cd ../sys/compile/GENERICAH; \
- install -c -o root -g wheel -m 755 386bsd ${MOUNT}/)
+ (cd ${.CURDIR}/../sys/compile/GENERICAH; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd ${MOUNT}/)
df -ik ${MOUNT}
umount /dev/${FLOPPY}
fsck /dev/r${FLOPPY}
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/kcopy_ah.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/kcopy_ah.flp \
- >${RELEASEDIR}/floppies/kcopy_ah.flp.gz
+ >${RELEASEDIR}/floppies/kcopy_ah.flp.gz &
kcopy_bt.flp:
${MAKE} kcopy-floppy
- (cd ../sys/compile/GENERICBT; \
- install -c -o root -g wheel -m 755 386bsd ${MOUNT}/)
+ (cd ${.CURDIR}/../sys/compile/GENERICBT; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd ${MOUNT}/)
df -ik ${MOUNT}
umount /dev/${FLOPPY}
fsck /dev/r${FLOPPY}
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/kcopy_bt.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/kcopy_bt.flp \
- >${RELEASEDIR}/floppies/kcopy_bt.flp.gz
+ >${RELEASEDIR}/floppies/kcopy_bt.flp.gz &
cdins-floppy:
${MAKE} kcopy-floppy
@@ -280,44 +305,44 @@ cdins-floppy:
ln -s /cdrom/filesys/usr/libexec libexec; \
ln -s /cdrom/filesys/usr/lib lib)
mkdir ${MOUNT}/cdrom
- chown root.wheel ${MOUNT}/cdrom
+ chown ${BINOWN}.${BINGRP} ${MOUNT}/cdrom
chmod 755 ${MOUNT}/cdrom
- install -c -o root -g wheel -m 755 etc.i386/cdinst1.profile \
- ${MOUNT}/.profile
- install -c -o root -g wheel -m 755 etc.i386/cdinst1.install \
- ${MOUNT}/install
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/cdinst1.profile ${MOUNT}/.profile
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/cdinst1.install ${MOUNT}/install
cdins_ah.flp:
${MAKE} cdins-floppy
- (cd ../sys/compile/GENERICAH; \
- install -c -o root -g wheel -m 755 386bsd ${MOUNT}/)
+ (cd ${.CURDIR}/../sys/compile/GENERICAH; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd ${MOUNT}/)
df -ik ${MOUNT}
umount /dev/${FLOPPY}
fsck /dev/r${FLOPPY}
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/cdins_ah.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/cdins_ah.flp \
- >${RELEASEDIR}/floppies/cdins_ah.flp.gz
+ >${RELEASEDIR}/floppies/cdins_ah.flp.gz &
cdins_bt.flp:
${MAKE} cdins-floppy
- (cd ../sys/compile/GENERICBT; \
- install -c -o root -g wheel -m 755 386bsd ${MOUNT}/)
+ (cd ${.CURDIR}/../sys/compile/GENERICBT; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 386bsd ${MOUNT}/)
df -ik ${MOUNT}
umount /dev/${FLOPPY}
fsck /dev/r${FLOPPY}
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/cdins_bt.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/cdins_bt.flp \
- >${RELEASEDIR}/floppies/cdins_bt.flp.gz
+ >${RELEASEDIR}/floppies/cdins_bt.flp.gz &
filesyst.flp:
disklabel -w -r ${FLOPPY} ${FLOPPY_TYPE} \
- /usr/mdec/fdboot /usr/mdec/bootfd
+ ${DESTDIR}/usr/mdec/fdboot ${DESTDIR}/usr/mdec/bootfd
newfs -b 4096 -c 80 -f 512 -i 10240 -m 0 -o space \
r${FLOPPY} ${FLOPPY_TYPE}
mount /dev/${FLOPPY} ${MOUNT}
- chown root.wheel ${MOUNT}/.
+ chown ${BINOWN}.${BINGRP} ${MOUNT}/.
chmod 755 ${MOUNT}/.
(cd ${DESTDIR}/; \
ls -d ${FILESYSTEM_DIRS} | cpio -pdamuv ${MOUNT})
@@ -331,12 +356,12 @@ filesyst.flp:
(find ${FILESYSTEM_CPIO}; ls -d ${FILESYSTEM_CPIO_DIRS}) | \
cpio -H newc --block-size=16 -oav | \
gzip -9 >${MOUNT}/inst1.cpio.gz)
- install -c -o root -g wheel -m 755 etc.i386/inst1.profile \
- ${MOUNT}/.profile
- install -c -o root -g wheel -m 755 etc.i386/inst1.install \
- ${MOUNT}/install
- install -c -o root -g wheel -m 755 ${RELEASEDIR}/distbin/filesystem \
- ${MOUNT}/bin/filesystem
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/inst1.profile ${MOUNT}/.profile
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/inst1.install ${MOUNT}/install
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ filesystem ${MOUNT}/bin/filesystem
(cd ${MOUNT}/; \
for i in ${FILESYSTEM_LINKS}; do \
ln bin/filesystem $$i; \
@@ -354,153 +379,150 @@ filesyst.flp:
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/filesyst.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/filesyst.flp \
- >${RELEASEDIR}/floppies/filesyst.flp.gz
+ >${RELEASEDIR}/floppies/filesyst.flp.gz &
cpio.flp:
disklabel -w -r ${FLOPPY} ${FLOPPY_TYPE} \
- /usr/mdec/fdboot /usr/mdec/bootfd
+ ${DESTDIR}/usr/mdec/fdboot ${DESTDIR}/usr/mdec/bootfd
newfs -b 4096 -c 80 -f 512 -i 65536 -m 0 -o space \
r${FLOPPY} ${FLOPPY_TYPE}
mount /dev/${FLOPPY} ${MOUNT}
- chown root.wheel ${MOUNT}/.
+ chown ${BINOWN}.${BINGRP} ${MOUNT}/.
chmod 755 ${MOUNT}/.
(cd ${DESTDIR}/; \
ls ${CPIO_FILES} | cpio -pdamuv ${MOUNT})
+ # This ugliness is because the default termcap file is simply too
+ # big and we don't need such a hugh one for the initial installation,
+ # yet we want the symlink in /etc to point to the right place so we
+ # need to install the smaller one in the same location. Same goes
+ # for the elvis hackery; just trying to bum as many bytes as we can
+ # here, and that's rarely a very pretty process.
+ mv ${DESTDIR}/usr/share/misc/termcap ${DESTDIR}/usr/share/misc/otermcap
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/termcap.small ${DESTDIR}/usr/share/misc/termcap
+ # Use cp so we don't destroy the links.
+ cp ${DESTDIR}/usr/bin/ex ${DESTDIR}/usr/bin/ex.bak
+ cp ${DESTDIR}/usr/bin/elvis ${DESTDIR}/usr/bin/ex
(cd ${DESTDIR}/; \
(find ${CPIO_CPIO}; ls -d ${CPIO_CPIO_DIRS}) | \
cpio -H newc --block-size=16 -oav | \
gzip -9 >${MOUNT}/inst2.cpio.gz)
- install -c -o root -g wheel -m 755 etc.i386/cpio.rc \
- ${MOUNT}/rc
- install -c -o root -g wheel -m 755 etc.i386/cpio.install \
- ${MOUNT}/install
- install -c -o root -g wheel -m 755 etc.i386/cpio.magic \
- ${MOUNT}/magic
+ # cpio is done, put everything back in shape for the bindist.
+ mv ${DESTDIR}/usr/share/misc/otermcap ${DESTDIR}/usr/share/misc/termcap
+ cp ${DESTDIR}/usr/bin/ex.bak ${DESTDIR}/usr/bin/ex
+ rm ${DESTDIR}/usr/bin/ex.bak
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/cpio.rc ${MOUNT}/rc
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/cpio.install ${MOUNT}/install
+ install -c -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${.CURDIR}/etc.i386/cpio.magic ${MOUNT}/magic
df -ik ${MOUNT}
umount /dev/${FLOPPY}
fsck /dev/r${FLOPPY}
dd if=/dev/r${FLOPPY} of=${RELEASEDIR}/floppies/cpio.flp \
bs=15b count=160
gzip --no-name -9 -c ${RELEASEDIR}/floppies/cpio.flp \
- >${RELEASEDIR}/floppies/cpio.flp.gz
+ >${RELEASEDIR}/floppies/cpio.flp.gz &
bin-tarball:
(cd ${DESTDIR}; \
tar cf - . | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/bindist/bin_tgz.)
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/bindist/bin_tgz.)
+
+src-clean:
+ (cd ${DESTDIR}/usr/src; make cleandist)
+ find ${DESTDIR}/usr/src -name obj | xargs -n30 rm -rf
+ rm -rf ${DESTDIR}/usr/src/sys/compile/GENERIC*
+ chown -R bin:bin ${DESTDIR}/usr/src
+ chmod -R og-w ${DESTDIR}/usr/src
srcbase-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/[A-Z]* | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/base.)
+ tar --exclude CVS -cf - usr/src/[A-Z]* | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/base.)
srcbin-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/bin | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/bin.)
+ tar --exclude CVS -cf - usr/src/bin | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/srcbin.)
srccontrib-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/contrib | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/contrib.)
+ tar --exclude CVS -cf - usr/src/contrib | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/contrib.)
srcetc-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/etc | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/etc.)
+ tar --exclude CVS -cf - usr/src/etc | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/etc.)
srcgames-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/games | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/games.)
+ tar --exclude CVS -cf - usr/src/games | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/games.)
srcgnu-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/gnu | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/gnu.)
+ tar --exclude CVS -cf - usr/src/gnu | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/gnu.)
srcinclude-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/include | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/include.)
+ tar --exclude CVS -cf - usr/src/include | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/include.)
srclib-tarball:
(cd ${DESTDIR}; \
- tar --exclude usr/src/${CRYPT_LIB} -cf - usr/src/lib | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/lib.)
+ tar --exclude usr/src/${CRYPT_LIB} --exclude CVS -cf - \
+ usr/src/lib | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/lib.)
srclibcrypt-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/${CRYPT_LIB} | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/secrdist/libcrypt.)
+ tar --exclude CVS -cf - usr/src/${CRYPT_LIB} | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/secrdist/libcrypt.)
srclibexec-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/libexec | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/libexec.)
+ tar --exclude CVS -cf - usr/src/libexec | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/libexec.)
srcsbin-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/sbin | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/sbin.)
+ tar --exclude CVS -cf - usr/src/sbin | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/sbin.)
srcshare-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/share | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/share.)
+ tar --exclude CVS -cf - usr/src/share | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/share.)
srcsys-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/sys | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/sys.)
+ tar --exclude CVS -cf - usr/src/sys | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/sys.)
srcusrbin-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/usr.bin | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/usrbin.)
+ tar --exclude CVS -cf - usr/src/usr.bin | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/usrbin.)
srcusrsbin-tarball:
(cd ${DESTDIR}; \
- tar -cf - usr/src/usr.sbin | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/srcdist/usrsbin.)
+ tar --exclude CVS -cf - usr/src/usr.sbin | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/srcdist/usrsbin.)
-src-tarball: srcbase-tarball srcbin-tarball srccontrib-tarball srcetc-tarball \
- srcgames-tarball srcgnu-tarball srcinclude-tarball srclib-tarball \
- srclibcrypt-tarball srclibexec-tarball srcsbin-tarball \
- srcshare-tarball srcsys-tarball srcusrbin-tarball \
- srcusrsbin-tarball
+srckrb-tarball:
+ (cd ${DESTDIR}; \
+ tar --exclude CVS -cf - usr/src/kerberosIV | \
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/secrdist/kerberos.)
+
+src-tarball: src-clean srcbase-tarball srcbin-tarball srccontrib-tarball \
+ srcetc-tarball srcgames-tarball srcgnu-tarball srcinclude-tarball \
+ srclib-tarball srclibcrypt-tarball srclibexec-tarball srcsbin-tarball \
+ srcshare-tarball srcsys-tarball srcusrbin-tarball srcusrsbin-tarball \
+ srckrb-tarball
des-tarball:
rm -rf ${RELEASEDIR}/tmpdes
@@ -530,30 +552,28 @@ des-tarball:
done
(cd ${RELEASEDIR}/tmpdes; \
tar cf - . | \
- gzip --no-name -9 -c | \
- split -b 240640 - \
- ${RELEASEDIR}/tarballs/secrdist/des_tgz.)
+ ${ZIPNSPLIT} ${RELEASEDIR}/tarballs/secrdist/des_tgz.)
rm -rf ${RELEASEDIR}/tmpdes
distrib-dirs:
- mtree -u -f mtree/BSD.root.dist -p ${DESTDIR}/
- mtree -u -f mtree/BSD.var.dist -p ${DESTDIR}/var
- mtree -u -f mtree/BSD.usr.dist -p ${DESTDIR}/usr
+ mtree -u -f ${.CURDIR}/mtree/BSD.root.dist -p ${DESTDIR}/
+ mtree -u -f ${.CURDIR}/mtree/BSD.var.dist -p ${DESTDIR}/var
+ mtree -u -f ${.CURDIR}/mtree/BSD.usr.dist -p ${DESTDIR}/usr
.if defined(CDROMDIST)
- mtree -u -f mtree/BSD.local.dist -p ${DESTDIR}/usr/local
+ mtree -u -f ${.CURDIR}/mtree/BSD.local.dist -p ${DESTDIR}/usr/local
.endif
cd ${DESTDIR}/; rm -f ${DESTDIR}/sys; ln -s usr/src/sys sys
floppies: kcopy_ah.flp kcopy_bt.flp filesyst.flp cpio.flp \
cdins_ah.flp cdins_bt.flp
-release: release-dirs distribution kcopy-kernels floppies \
- bin-tarball des-tarball
-
+release: release-dirs distribution crunch extract kcopy-kernels \
+ floppies bin-tarball des-tarball clean
+
release-dirs:
rm -rf ${RELEASEDIR}/filesys
mkdir ${RELEASEDIR}/filesys
- chown root.wheel ${RELEASEDIR}/filesys
+ chown ${BINOWN}.${BINGRP} ${RELEASEDIR}/filesys
chmod 755 ${RELEASEDIR}/filesys
rm -rf ${RELEASEDIR}/tarballs
mkdir ${RELEASEDIR}/tarballs
@@ -561,11 +581,11 @@ release-dirs:
mkdir ${RELEASEDIR}/tarballs/objdist
mkdir ${RELEASEDIR}/tarballs/secrdist
mkdir ${RELEASEDIR}/tarballs/srcdist
- chown -R root.wheel ${RELEASEDIR}/tarballs
+ chown -R ${BINOWN}.${BINGRP} ${RELEASEDIR}/tarballs
chmod -R 755 ${RELEASEDIR}/tarballs
rm -rf ${RELEASEDIR}/floppies
mkdir ${RELEASEDIR}/floppies
- chown root.wheel ${RELEASEDIR}/floppies
+ chown ${BINOWN}.${BINGRP} ${RELEASEDIR}/floppies
chmod 755 ${RELEASEDIR}/floppies
.include <bsd.prog.mk>
diff --git a/etc/crontab b/etc/crontab
index a68a42083960..dcdd3cae9668 100644
--- a/etc/crontab
+++ b/etc/crontab
@@ -1,6 +1,6 @@
# /etc/crontab - root's crontab for FreeBSD
#
-# $Id: crontab,v 1.5.2.1 1994/04/15 17:46:56 sean Exp $
+# $Id: crontab,v 1.6 1994/04/15 16:57:38 sean Exp $
# From: Id: crontab,v 1.6 1993/05/31 02:03:57 cgd Exp
#
SHELL=/bin/sh
diff --git a/etc/csh.login b/etc/csh.login
index 040ba69f2d1e..4b827013c9d9 100644
--- a/etc/csh.login
+++ b/etc/csh.login
@@ -3,5 +3,5 @@
# information is shown in K-Blocks
# setenv BLOCKSIZE K
# Uncomment this, if you want to have 8-bit clean 'tcsh'
-# (temporary solution until proper locale will be available)
-# setenv LANG ru
+# (any LANG value cause this, here example for russian language)
+# setenv LANG Russian.koi8-r
diff --git a/etc/daily b/etc/daily
index c14b0eac9269..b30682500c91 100644
--- a/etc/daily
+++ b/etc/daily
@@ -25,8 +25,10 @@ fi
if [ -d /scratch ]; then
cd /scratch && {
- find . ! -name . -atime +1 -exec rm -f -- {} \;
- find . ! -name . -type d -mtime +1 -exec rmdir -- {} \; \
+ find . ! -name . ! -fstype local -a -prune -o \
+ -atime +1 -exec rm -f -- {} \;
+ find . ! -name . ! -fstype local -a -prune -o \
+ -type d -mtime +1 -exec rmdir -- {} \; \
>/dev/null 2>&1; }
fi
@@ -54,13 +56,18 @@ if [ -f /etc/news.expire ]; then
/etc/news.expire
fi
-#echo ""
-#echo "Purging accounting records:"
-#mv /var/account/acct.2 /var/account/acct.3
-#mv /var/account/acct.1 /var/account/acct.2
-#mv /var/account/acct.0 /var/account/acct.1
-#cp /var/account/acct /var/account/acct.0
-#sa -s > /dev/null
+if [ -d /var/account ] ; then
+ echo ""
+ echo "Purging accounting records:"
+ cd /var/account
+ if [ -f acct.2 ] ; then mv -f acct.2 acct.3 ; fi
+ if [ -f acct.1 ] ; then mv -f acct.1 acct.2 ; fi
+ if [ -f acct.0 ] ; then mv -f acct.0 acct.1 ; fi
+ if [ -f acct ] ; then
+ cp -pf acct acct.0
+ sa -s > /dev/null
+ fi
+fi
echo ""
echo "Backup passwd and group files:"
diff --git a/etc/etc.i386/EXTRACT_bin.sh b/etc/etc.i386/EXTRACT_bin.sh
new file mode 100755
index 000000000000..d6821747b195
--- /dev/null
+++ b/etc/etc.i386/EXTRACT_bin.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# This file will extract all of the FreeBSD binaries into ${EXTRACT_TARGET}
+# if it is set, or / otherwise.
+#
+# CAUTION DO NOT USE THIS TO INSTALL THE BINARIES ONTO A RUNNING
+# SYSTEM, it will NOT WORK!!! You should use the extract command from /magic
+# for installing the bindist onto your system.
+SOURCEDIR=.
+if [ X"${EXTRACT_TARGET}" = X"" ]; then
+ echo "YOU DO NOT WANT TO DO THAT!!!"
+ exit
+ EXTRACT_TARGET=/
+fi
+
+cd $SOURCEDIR
+cat bin_tgz.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+#NO_EXPORT#cat des_tgz.* | gunzip | tar --directory ${EXTRACT_TARGET} -xpf -
diff --git a/etc/etc.i386/EXTRACT_secr.sh b/etc/etc.i386/EXTRACT_secr.sh
new file mode 100755
index 000000000000..37b7b72aefe4
--- /dev/null
+++ b/etc/etc.i386/EXTRACT_secr.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# This file will extract all of the FreeBSD secure distribution into
+# ${EXTRACT_TARGET} if it is set, or / otherwise.
+#
+SOURCEDIR=.
+if [ X"${EXTRACT_TARGET}" = X"" ]; then
+ EXTRACT_TARGET=/
+fi
+
+cd $SOURCEDIR
+
+cat des_tgz.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat libcrypt.aa | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat kerberos.aa | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
diff --git a/etc/etc.i386/EXTRACT_src.sh b/etc/etc.i386/EXTRACT_src.sh
new file mode 100755
index 000000000000..fc1680c5b241
--- /dev/null
+++ b/etc/etc.i386/EXTRACT_src.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# This file will extract all of the FreeBSD sources into
+# ${EXTRACT_TARGET}/usr/src if it is set, or /usr/src otherwise.
+# If you do not want all the sources you can copy this file to your
+# disk and edit it to comment out the ones you do not want. You
+# will need to change the setting of SOURCEDIR to reflect where the srcdist
+# directory is (dependent on where your cdrom is mounted,
+# it might be /cdrom/tarballs/srcdist) .
+#
+if [ X"${SOURCEDIR}" = X"" ]; then
+ SOURCEDIR=.
+fi
+if [ X"${EXTRACT_TARGET}" = X"" ]; then
+ EXTRACT_TARGET=/
+fi
+
+cd $SOURCEDIR
+
+# Note that base.aa is REQUIRED to be able to use the source tree for
+# building in.
+#
+cat base.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+
+#
+# The following are optional
+#
+cat srcbin.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat contrib.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat etc.aa | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat games.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat gnu.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat include.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat lib.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+#NO_EXPORT#cat libcrypt.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat libexec.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat sbin.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat share.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat sys.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat usrbin.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
+cat usrsbin.* | gunzip | tar --unlink --directory ${EXTRACT_TARGET} -xpf -
diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV
index 9433a69698e5..7d7815d239a5 100644
--- a/etc/etc.i386/MAKEDEV
+++ b/etc/etc.i386/MAKEDEV
@@ -74,8 +74,9 @@
# speaker pc speaker
# tw* xten power controller
# snd* various sound cards
+# pcaudio PCM audio driver
#
-# $Id: MAKEDEV,v 1.28.2.1 1994/03/07 00:58:43 rgrimes Exp $
+# $Id: MAKEDEV,v 1.37 1994/06/17 21:50:07 jkh Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:
@@ -89,9 +90,8 @@ all)
sh MAKEDEV wd0 wd1 fd0 fd1 ft0 wt0 sd0 sd1 st0 cd0 mcd0 # bdev
sh MAKEDEV pty0 tty0 tty1 pc0 lpt0 lpt1 lpt2 # cdev
sh MAKEDEV ch0 tw0 bpf0 dcf0 lpa0 lpa1 lpa2 # cdev
- sh MAKEDEV speaker mse0 ttyd2 ttyd3 # cdev
- # NOTE: co0 and vty04 are not done by a "sh MAKEDEV all"
- # these are for codrv and interfere with other devices! - rgrimes
+ sh MAKEDEV speaker pcaudio psm0 mse0 ttyd2 ttyd3 # cdev
+ sh MAKEDEV vty4 # cdev
;;
std)
rm -f console drum mem kmem null zero io tty klog stdin stdout stderr
@@ -108,7 +108,7 @@ std)
mknod stdout c 22 1; chmod 666 stdout; chown root.wheel stdout
mknod stderr c 22 2; chmod 666 stderr; chown root.wheel stderr
rm -f fd/*
- mkdir fd > /dev/null 2>&1
+ mkdir fd > null 2>&1
(cd fd && eval `echo "" | awk ' BEGIN { \
for (i = 0; i < 64; i++) \
printf("mknod %d c 22 %d;", i, i)}'`)
@@ -120,7 +120,7 @@ std)
# Create device files for new Archive/Wangtek QIC-02 tape driver (vak)
wt*)
- umask 2 ; u=`expr $i : '..\(.*\)'`
+ umask 7 ; u=`expr $i : '..\(.*\)'`
if [ x$u = x ]; then u=0; fi
rm -f r[Ww]t$u nr[Ww]t$u r[Ww]t$u[a-f] nr[Ww]t$u[a-f]
mknod rwt${u} c 10 `expr 0 + $u` # default density, 512b blocks
@@ -264,6 +264,14 @@ sd*|wd*)
mknod ${name}${unit}f b $blk `expr $unit '*' 8 + 5`
mknod ${name}${unit}g b $blk `expr $unit '*' 8 + 6`
mknod ${name}${unit}h b $blk `expr $unit '*' 8 + 7`
+ case $i in
+ wd*)
+ mknod ${name}${unit}i b $blk `expr $unit '*' 8 + 64`
+ mknod ${name}${unit}j b $blk `expr $unit '*' 8 + 65`
+ mknod ${name}${unit}k b $blk `expr $unit '*' 8 + 66`
+ mknod ${name}${unit}l b $blk `expr $unit '*' 8 + 67`
+ mknod ${name}${unit}m b $blk `expr $unit '*' 8 + 68`
+ esac
mknod r${name}${unit}a c $chr `expr $unit '*' 8 + 0`
mknod r${name}${unit}b c $chr `expr $unit '*' 8 + 1`
mknod r${name}${unit}c c $chr `expr $unit '*' 8 + 2`
@@ -272,8 +280,16 @@ sd*|wd*)
mknod r${name}${unit}f c $chr `expr $unit '*' 8 + 5`
mknod r${name}${unit}g c $chr `expr $unit '*' 8 + 6`
mknod r${name}${unit}h c $chr `expr $unit '*' 8 + 7`
- chgrp operator ${name}${unit}[a-h] r${name}${unit}[a-h]
- chmod 640 ${name}${unit}[a-h] r${name}${unit}[a-h]
+ case $i in
+ wd*)
+ mknod r${name}${unit}i c $chr `expr $unit '*' 8 + 64`
+ mknod r${name}${unit}j c $chr `expr $unit '*' 8 + 65`
+ mknod r${name}${unit}k c $chr `expr $unit '*' 8 + 66`
+ mknod r${name}${unit}l c $chr `expr $unit '*' 8 + 67`
+ mknod r${name}${unit}m c $chr `expr $unit '*' 8 + 68`
+ esac
+ chgrp operator ${name}${unit}[a-m] r${name}${unit}[a-m]
+ chmod 640 ${name}${unit}[a-m] r${name}${unit}[a-m]
;;
*)
echo bad unit for disk in: $i
@@ -292,7 +308,6 @@ com*)
unit=`expr $i : '...\(.*\)'`
rm -f tty0$unit
mknod tty0$unit c 8 $unit
- chown uucp.wheel tty0$unit
;;
pty*)
@@ -342,7 +357,7 @@ st*)
nrst${unit}.${mode} \
erst${unit}.${mode} \
st${unit}ctl.${mode}
- chmod 644 rst${unit}.${mode}\
+ chmod 640 rst${unit}.${mode}\
nrst${unit}.${mode} \
erst${unit}.${mode}
chmod 660 st${unit}ctl.${mode}
@@ -416,7 +431,7 @@ tw*)
# hv 22-apr-93 use this to create the necessary video device for
# pccons driver
-pc*)
+pc?)
chr=12
minor=0
name=ttyv0
@@ -427,7 +442,7 @@ pc*)
;;
# Use this to create virtual consoles for syscons, pcvt or codrv
-# /dev/ttyv0-b
+# ttyv0-b
# use as MAKEDEV vtyNN to create NN entries
vty*)
chr=12
@@ -469,19 +484,42 @@ speaker)
chown root.wheel speaker
;;
-cua*|ttyd*)
- unit=`expr $i : '...d*\(.\)'`
- rm -f tty0$unit cua0$unit ttyd$unit
- mknod ttyd$unit c 28 $unit
- mknod cua0$unit c 28 `expr $unit + 128`
- chown uucp.wheel ttyd$unit cua0$unit
+cua0?|cua?|ttyd?)
+ unit=`expr $i : '...[d0]*\(.\)$'`
+ rm -f tty*0$unit cua*0$unit tty*d$unit
+ case $unit in
+ [0-9]) m=$unit;;
+ a) m=10;; b) m=11;; c) m=12;; d) m=13;; e) m=14;; f) m=15;; g) m=16;;
+ h) m=17;; i) m=18;; j) m=19;; k) m=20;; l) m=21;; m) m=22;; n) m=23;;
+ o) m=24;; p) m=25;; q) m=26;; r) m=27;; s) m=28;; t) m=29;; u) m=30;;
+ v) m=31;;
+ *) echo too many devices; exit 1;;
+ esac
+ mknod ttyd$unit c 28 $m
+ mknod ttyid$unit c 28 `expr $m + 32`
+ mknod ttyld$unit c 28 `expr $m + 64`
+ mknod cua0$unit c 28 `expr $m + 128`
+ mknod cuai0$unit c 28 `expr $m + 32 + 128`
+ mknod cual0$unit c 28 `expr $m + 64 + 128`
+ chown uucp.dialer cua*0$unit
+ chmod 660 cua*0$unit
;;
-tty*)
- unit=`expr $i : 'tty\(.\)'`
- rm -f tty0$unit cua0$unit ttyd$unit
+tty0?|tty?)
+ unit=`expr $i : 'tty0*\(.\)$'`
+ rm -f tty*0$unit cua*0$unit tty*d$unit
+ case $unit in
+ [0-9]) m=$unit;;
+ a) m=10;; b) m=11;; c) m=12;; d) m=13;; e) m=14;; f) m=15;; g) m=16;;
+ h) m=17;; i) m=18;; j) m=19;; k) m=20;; l) m=21;; m) m=22;; n) m=23;;
+ o) m=24;; p) m=25;; q) m=26;; r) m=27;; s) m=28;; t) m=29;; u) m=30;;
+ v) m=31;;
+ *) echo too many devices; exit 1;;
+ esac
umask 0
- mknod tty0$unit c 28 $unit
+ mknod tty0$unit c 28 $m
+ mknod ttyi0$unit c 28 `expr $m + 32`
+ mknod ttyl0$unit c 28 `expr $m + 64`
umask 77
;;
@@ -510,47 +548,55 @@ mouse*)
ln -s $name mouse
;;
+pcaudio)
+ rm -f pcaudio pcaudioctl
+ mknod pcaudio c 24 0
+ mknod pcaudioctl c 24 128
+ chown root.wheel pcaudio pcaudioctl
+ chmod 666 pcaudio pcaudioctl
+ ;;
+
snd*)
chr=30
- rm -f /dev/mixer # Mixer [ Control ]
- mknod /dev/mixer c $chr 0
- chmod 666 /dev/mixer
+ rm -f mixer # Mixer [ Control ]
+ mknod mixer c $chr 0
+ chmod 666 mixer
- rm -f /dev/sequencer # Sequencer [ FM Synth and MIDI output ]
- mknod /dev/sequencer c $chr 1
- chmod 666 /dev/sequencer
+ rm -f sequencer # Sequencer [ FM Synth and MIDI output ]
+ mknod sequencer c $chr 1
+ chmod 666 sequencer
- rm -f /dev/midi # Midi input [ Not implemented ]
- mknod /dev/midi c $chr 2
+ rm -f midi # Midi input [ Not implemented ]
+ mknod midi c $chr 2
- rm -f /dev/dsp # DSP [ Digitized voice ]
- mknod /dev/dsp c $chr 3
- chmod 666 /dev/dsp
+ rm -f dsp # DSP [ Digitized voice ]
+ mknod dsp c $chr 3
+ chmod 666 dsp
- rm -f /dev/audio # SPARC audio [ Not fully implemented ]
- mknod /dev/audio c $chr 4
- chmod 666 /dev/audio
+ rm -f audio # SPARC audio [ Not fully implemented ]
+ mknod audio c $chr 4
+ chmod 666 audio
- rm -f /dev/dsp16 # DSP16 [ Same as /dev/dsp, except 16 bits ]
- mknod /dev/dsp16 c $chr 5
- chmod 666 /dev/dsp16
+ rm -f dsp16 # DSP16 [ Same as dsp, except 16 bits ]
+ mknod dsp16 c $chr 5
+ chmod 666 dsp16
- rm -f /dev/sndstat # Status Device [ Debugging interface ]
- mknod /dev/sndstat c $chr 6
- chmod 666 /dev/sndstat
+ rm -f sndstat # Status Device [ Debugging interface ]
+ mknod sndstat c $chr 6
+ chmod 666 sndstat
- rm -f /dev/pro_midi # PRO_MIDI [PAS midi input and output]
- mknod /dev/pro_midi c $chr 15
- chmod 666 /dev/pro_midi
+ rm -f pro_midi # PRO_MIDI [PAS midi input and output]
+ mknod pro_midi c $chr 15
+ chmod 666 pro_midi
- rm -f /dev/dsp1 # DSP 1 [ SB emulation of PAS16 or 2nd audio ]
- mknod /dev/dsp1 c $chr 19
- chmod 666 /dev/dsp1
+ rm -f dsp1 # DSP 1 [ SB emulation of PAS16 or 2nd audio ]
+ mknod dsp1 c $chr 19
+ chmod 666 dsp1
- rm -f /dev/audio1 # Sparc Audio 1 [ SB emulation of PAS16 or 2nd audio ]
- mknod /dev/audio1 c $chr 20
- chmod 666 /dev/audio1
+ rm -f audio1 # Sparc Audio 1 [ SB emulation of PAS16 or 2nd audio ]
+ mknod audio1 c $chr 20
+ chmod 666 audio1
;;
local)
@@ -558,5 +604,9 @@ local)
sh MAKEDEV.local
;;
+*)
+ echo $i - no such device name
+ ;;
+
esac
done
diff --git a/etc/etc.i386/README.1ST b/etc/etc.i386/README.1ST
new file mode 100644
index 000000000000..eccb3aab208a
--- /dev/null
+++ b/etc/etc.i386/README.1ST
@@ -0,0 +1,146 @@
+ FLOPPY INSTALLATION NOTES
+ FreeBSD
+ Release 1.1.5
+
+Welcome to FreeBSD! This document has been put together in an effort
+to make initial installation of the system from floppy as easy as possible.
+It also provides a simple description for those eager to get started as soon as
+possible. Please see the file README.INSTALL for more detailed installation
+instructions.
+
+1. To install FreeBSD you will need 3 (or 4 if you choose to add the optional
+ DOS floppy) floppies, as well as the bulk of the distribution on some
+ other medium (floppy, tape, CD, etc). If you've retrieved this release
+ from the net, you'll first have to make the floppies yourself using
+ the supplied images.
+
+ Due to the differences in PC configurations, we've found it necessary
+ to provide multiple initial boot images that provide kernels for
+ different types of systems.
+
+ If your disk controller is one of:
+
+ MFM / RLL / IDE / ST506
+ Adaptec 154x series
+ Adaptec 174x series
+ Buslogic 545S
+
+ Then please use the disk image: kcopy_ah.flp
+ to construct your boot floppy.
+
+ If your disk controller is one of:
+
+ Bustek 742a
+ UltraStore 14F or 34F
+
+ Then please use the disk image: kcopy_bt.flp
+ to construct your boot floppy.
+
+ Next, make a second floppy from the disk image: filesyst.flp
+ You'll need this for the second stage of the boot process.
+
+ Finally, make a third floppy from the disk image: cpio.flp
+ You'll need this for the last stage of the boot process.
+
+ If you want to use any of the optional tools in the tools
+ subdirectory of the ftp distribution site, these should be
+ copied directly to a DOS formatted disk (using, either mcopy
+ or mount -t pcfs). This disk is referred to later as the
+ optional "dos" floppy.
+
+ If installing more than one operating system on a disk, then
+ it is recommended that the dos floppy at least include the
+ os-bs boot manager. If downloading files via a modem and SLIP
+ is not available, then the dos floppy should include kermit.
+ You'll have the option of loading the programs that are on
+ the dos floppy in the last stage of the boot process.
+
+2. Boot the first floppy. When it asks you to insert the file system floppy,
+ insert the second floppy ``filesyst.flp.'' Follow the instructions
+ that floppy gives you. If partitions already exist on the hard disk,
+ then by default FreeBSD attempts to install itself at the end of these.
+ Before rebooting, note the type of disk it says to copy the kernel
+ to: ``sd0a'' or ``wd0a'' (``sd0a'' is for SCSI systems, ``wd0a'' is
+ for all others.) When the system halts, go on to the next step.
+
+3. Boot the first floppy again, but this time when it asks
+ you to insert the file system floppy, just press the return key.
+ Follow the instructions that the floppy gives you. When you see
+ the ``kc>'' prompt, type ``copy'' (without quotes). At the next prompt,
+ ``copy kernel to>'', type either ``sd0a'' or ``wd0a'' as given in
+ the previous step. When the system halts, go on to the next step.
+
+4. Making sure that there's no floppy in the drive, press return to boot
+ from the hard disk. After it has booted and is asking what drive the
+ cpio floppy is in, insert the third floppy ``cpio.flp'' into a
+ floppy drive and answer the question about what drive it is in.
+ Note that 0 is the same as DOS drive A:, and 1 is the same as DOS
+ drive B:
+
+5. After the cpio floppy has been copied to the disk, remove it from the
+ drive. If there are programs on the dos-floppy that you would like
+ installed, then insert this disk in a floppy drive, again specifying
+ the drive to read from.
+
+6. After the cpio (or optional dos) floppy has been copied to the disk,
+ enter `halt' at the command prompt.
+
+7. When the system asks you to press the return key to reboot, first
+ remove the floppy and then press the return key to boot from the hard
+ disk.
+
+8. At this point you will get 4 errors from the fsck on boot, these
+ are normal and are caused by files that were open when the
+ /dev entries were built - just ignore them. The system will
+ correct these errors and then halt, after which you should press
+ the return key again to reboot with a clean system.
+
+9. Congratulations, you've got the mini FreeBSD system on your disk!
+
+10. Follow the instructions about set_tmp_dir and extract that
+ will come on your screen after you've pressed the return key.
+
+11. Run the configure command to set up some of the /etc files by
+ typing ``configure''. You will have to edit /etc/netstart after
+ this if you have a networking interface.
+
+12. Reboot so that the system comes up multiuser by typing ``reboot''.
+
+13. You are now running FreeBSD! Congratulations! You may now continue
+ with installing the source distribution, or stop here for now.
+
+14. The file /magic contains the special sh commands used during
+ installation. Should you need to use them you can do the following.
+
+ /bin/sh
+ . /magic
+
+15. If your disk has several operating systems, you may want to
+ install the Thomas Wolfram's os-bs boot manager for selecting
+ which system to boot. This works well with DOS, OS/2, FreeBSD
+ and other systems. To install it, boot the system with MS-DOS
+ and insert the dos-floppy of the FreeBSD install suite in
+ floppy drive A:. Then enter the DOS commands:
+ > A:
+ > os-bs135
+ > cd os-bs
+ > os-bs
+ A menu should now appear on the screen. Use the cursor keys
+ to highlight the install option and hit ENTER. Simply follow the
+ instructions from there.
+
+ For more information about the ob-bs program, including its
+ capabilities and limitations, see the file `readme.1st' in the
+ os-bs directory.
+
+ If you choose not to install os-bs, then fdisk can be used to
+ change the boot system. This is done by making the primary
+ partition for the boot system active. FreeBSD has an fdisk
+ command that can be used for this purpose as well.
+
+16. In addition to the FreeBSD source and binary distributions, many
+ additional packages, such as X11 and TeX, may be obtained from
+ freebsd.cdrom.com - please have a look around! You may also find
+ this a good time to read the release notes in RELNOTES.FreeBSD.
+
+End of $Id: README.1ST,v 1.1 1994/06/28 09:01:53 jkh Exp $
diff --git a/etc/etc.i386/README.INSTALL b/etc/etc.i386/README.INSTALL
new file mode 100644
index 000000000000..b8f69d23c5c5
--- /dev/null
+++ b/etc/etc.i386/README.INSTALL
@@ -0,0 +1,1011 @@
+ INSTALLATION NOTES
+ FreeBSD
+ Release 1.1.5
+
+These notes have been prepared from those written originally for NetBSD
+0.9. The conversion was done by someone who has had experience with
+installing and upgrading 386bsd, but who is not a unix guru, so there
+will be slant towards this experience. Corrections/updates are
+welcomed, it is difficult/impossible to test every last hardware
+combination.
+
+Be sure to read _ALL_ of this document before you try to install
+FreeBSD. FreeBSD probably looks a bit similar to things that you've
+seen before (perhaps 386BSD), but the installation procedures are quite
+different.
+
+
+FreeBSD Release Contents:
+------- --- ------- --------
+
+The FreeBSD Release consists of the following elements:
+
+Bootable Kernel-copy floppies
+
+ These disks are bootable and have enough utilities on
+ board to copy a new kernel to a prepared hard disk. While
+ they are primarily intended for installing FreeBSD, they
+ also make upgrading to a new kernel easy: boot from it,
+ and copy a new kernel to disk.
+
+ You must choose between one of two kernel-copy floppy
+ images, depending on your disk controller type. The
+ "kcopy-ah-floppy" image supports the Adaptec 154x and 1742
+ SCSI adapters, while "kcopy-bt-floppy" supports the Bustek
+ 742 and Ultrastore SCSI adapters. For systems with only
+ MFM, RLL, ESDI or IDE disk controllers, either image can
+ be used.
+
+Installation floppies
+
+ In addition to a bootable floppy, two additional floppies are
+ required to prepare your hard drive for FreeBSD and to install
+ the FreeBSD base distribution. Like the boot
+ floppies, these are distributed as binary images. They are
+ are referred to below as the "filesystem-floppy" and the
+ "cpio-floppy".
+
+ There is also an optional fourth installation disk referred
+ to as the "dos-floppy". Unlike the other install disks,
+ there is no binary image for the dos floppy. Instead this
+ is a regular MS-DOS-formatted floppy disk containing any
+ FreeBSD programs you choose to copy to it using mtools or
+ even the DOS copy command. The most commonly requested
+ programs have been put in a tools directory at FreeBSD
+ archives sites.
+
+
+FreeBSD distribution sets
+
+ These collections contain the complete FreeBSD system and
+ utilities in source and binary form. There are three
+ separate sets: the FreeBSD binaries, the FreeBSD sources,
+ and the DES sources+binaries. The DES set contains only
+ crypt(3) code and is subject to U.S.A. export restrictions.
+
+ The binary distribution set can be found in the "bindist"
+ subdirectory of the FreeBSD archive sites. It consists
+ of files named bin_tgz.aa to bin_tgz.cm (i.e., 65 files
+ all told). A CKSUMS file (* see note below) is included
+ for verifying the integrity of these.
+
+ The source distribution sets can be found in under
+ "srcdist" subdirectory of archive sites. It is consists
+ of files named for each logical group of src files (split into
+ "catagories"), plus the CKSUMS file.
+
+ Finally, the security distribution set contains
+ usr/src/libcrypt/*, the source files for the DES encryption
+ algorithm, and the binaries which depend on it. It can
+ be found in the "secrdist" subdirectory on sites which
+ choose to carry the complete FreeBSD distribution.
+
+ NOTE: Individuals who are not in the U.S.A. but who still want
+ to use encryption without violating U.S. export laws should read
+ the FreeBSD FAQ entry regarding foreign distribution of independently
+ developed encryption technology. Look in:
+
+ /usr/src/contrib/FAQ
+
+ Or, on the net, freebsd.cdrom.com:~ftp/pub/FreeBSD/FAQ
+
+
+ The individual files in each collection are no more than
+ 235 Kbytes in size. (The last file is just long enough
+ to contain the rest of the data for that distribution
+ set.)
+
+ Each collection is a split, gzip'ed tar archive. They
+ are reassembled and extracted by the install procedure.
+ However, to view them without installing FreeBSD, you can
+ use, e.g., the command line:
+
+ cat bin* | gunzip | tar tvf - | more
+
+ You should NOT extract the distribution directly, but rather
+ use the `extract' command available at installation time.
+ This command performs special-case handling to avoid possible
+ problems in extracting a release on a new system.
+
+ In each of the distribution directories, there is a file
+ named "CKSUMS" which contains the checksums of the files
+ in that directory, as generated by the cksum(1) command.
+ You can use cksum to verify the integrity of the archives,
+ if you suspect one of the files is corrupted.
+
+ N.B.: The CKSUMS files are produced using the 4.4BSD
+ version of cksum which is POSIX-compliant. The values in
+ these file do not match the cksums generated by the 386BSD 0.1
+ version of cksum (which is based on an earlier "standard").
+ A copy of the new cksum binary that will run on
+ 386bsd/Netbsd/FreeBSD can be found in the "tools" subdirectory
+ of the distribution.
+
+
+System Requirements and Supported Devices:
+------ ------------ --- --------- -------
+
+FreeBSD runs on ISA (AT-Bus), EISA and some PCI systems with 386, 486 and
+Pentium processors. A math coprocessor is recommended but not essential.
+It does NOT support Micro-channel systems, such as some IBM PS/2 systems.
+The minimal configuration should include 4Meg of RAM and an 80Meg hard disk,
+but to install the entire system (with sources) you'll need much more disk
+space, and to run X or compile programs on the system, more RAM is recommended.
+(4Meg will actually allow you to run X and/or compile, but it's extremely slow).
+
+For a complete list of supported cards and peripherals, please see the
+file RELNOTES.FreeBSD. It should be installed in the root directory
+of your newly installed system, or can be fetched off the net from:
+
+ freebsd.cdrom.com:~ftp/pub/FreeBSD/RELNOTES
+
+
+To be detected by the distributed kernels, certain devices must
+be configured as follows: (Note: IRQ 9 is the same as IRQ 2
+on ISA/EISA based machines)
+
+Device Name Port IRQ DRQ Misc
+------ ---- ---- --- --- ----
+Floppy Cntlr. fd0 0x3f0 6 2
+
+Std. Hard Disk Cntlr.
+ wd0 0x1f0 14
+
+AHA-154x SCSI Cntlr. 0x330 11 5 [kcopy-ah-floppy]
+
+AHA-174x SCSI Cntlr. automatically configured [kcopy-ah-floppy]
+
+BT742 SCSI Cntlr. 0x330 12 [kcopy-bt-floppy]
+
+UHA-14f SCSI Cntlr. or
+UHA-34f SCSI Cntlr. 0x330 14 5 [kcopy-bt-floppy]
+(In FreeBSD GAMMA and before, UHA was on IRQ 11)
+
+SCSI Disks sd[0-2] automatically configured
+
+SCSI Tapes st[01] automatically configured
+
+SCSI CD-ROMs cd0 automatically configured
+
+Serial Ports com0 0x3f8 4
+ com1 0x2f8 3
+ com2 0x3e8 5
+ com3 0x3f8 9
+
+Mitsumi CDROM 0x300 5 1 [kcopy-ah-floppy]
+
+SMC/WD Ethernet or
+3COM 3c503 ed0 0x280 5 iomem 0xd8000
+
+NOTE for 386bsd users: the we0 device for the WD80xxyy card has been
+replaced with an ed0 device. The default settings of 9/280/d000 have
+been changed to 5/280/d800 as this address accomdates all of the boards.
+
+Novell Ethernet ed0 0x280 5
+
+NOTE for 386bsd users: the ne0 device for the NEx000 card has been
+replaced with an ed0 device. The default settings of 9/300 have
+been changed to 5/280.
+
+ISOLAN ISOLink is0 0x280 10 7
+Novell NE2100 is0 0x280 10 7
+
+QIC-02 Tape wt0 0x300 5 1
+
+Parallel (Printer) Port
+ lpt0 0x3BC 7
+
+Interruptless Parallel (Printer) Port
+ lpa0 0x378
+ lpa1 0x278
+
+N.B.: Disable the lpt interrupt on the board or you will
+have problems using the lpa drivers.
+
+
+Hard-Disk Storage Requirements
+--------- ------- ------------
+
+The minimum base installation of FreeBSD requires a free hard disk
+partition with at least 16 MB free space. This is only enough for
+the three installation disks, which don't support a multi-user
+shell.
+
+The full binary distribution extracts to about 46 MB.
+The full source distribution extracts to about 72 MB.
+The kernel source only extracts to about 7 MB.
+To recompile the sources requires an additional 55 MB.
+To recompile the kernel requires an additional 2 MB.
+
+Since additional room is required for extracting the distributions,
+a full binary installation requires a minimum of about 80 MB (46
+MB extracted + 16 MB archived + 8 MB minimum swap + room for
+extracting).
+
+A complete source + binary distribution requires a minimum of
+about 210 MB (assuming a minimum 8 MB swap).
+
+
+Getting the System on to Useful Media:
+------- --- ------ -- -- ------ -----
+
+Installation is supported from several media types, including:
+
+ MS-DOS floppies
+ MS-DOS hard disk (Primary partition)
+ Tape
+ NFS partitions
+ FTP
+ Kermit
+
+No matter what you do, however, you'll need at least three disks (1.2M
+or 1.44M) handy, on which you will put the kernel-copy image and the
+install (or upgrade) floppy images.
+
+The images are available from the directory "floppies", under the root
+of the FreeBSD/FreeBSD-1.1.5 tree at your favorite archive site.
+They're available both as raw disk images, and gzipped, to save time
+downloading.
+
+If you are using an AHA-154x or AHA-1742 SCSI host adapter, you need
+the kcopy-ah-floppy image. If you're using a BT-742 SCSI host adapter
+or an Ultrastor adaptor, then you'll need the kcopy-bt-floppy image.
+If you're using MFM/RLL/IDE disk controllers, you can use either
+kernel-copy floppy image.
+
+If you are using UNIX to make the floppies, you should use the command
+dd(1) to write the raw floppy images (i.e., kcopy-ah-floppy or
+kcopy-bt-floppy, filesystem-floppy and cpio-floppy) to the floppies.
+For example, to write kcopy-ah-floppy to a 5.25" 1.2 Mb floppy
+disk under 386BSD, use:
+
+ $ dd if=kcopy-ah-floppy of=/dev/fd0a bs=30b count=80
+
+or for a 3.5" 1.44 Mb floppy:
+
+ $ dd if=kcopy-ah-floppy of=/dev/fd0a bs=36b count=80
+
+If you are using DOS to make the floppies, use the rawrite.exe
+utility. This can be found in the "tools" subdirectory of the
+archive site. Copy rawrite.exe and the binary images to a DOS
+disk, type "rawrite" under MS-DOS and follow the instructions.
+Rawrite can write binary images to either 1.2MB or 1.44MB
+MS-DOS-formatted floppies.
+
+Any other programs from the tools directory that might be needed
+for installing FreeBSD, such as kermit, should be copied to a DOS-
+formatted floppy (1.2MB or 1.44MB). Under 386BSD, they can be
+copied to floppy using the mcopy command. Under DOS, use the DOS
+copy command.
+
+The steps necessary to prepare the distribution sets for installation
+depend on which method of installation you choose. The various methods
+are explained below.
+
+To prepare for installing via MS-DOS hard disk:
+
+ To prepare FreeBSD for installaton from the MS-DOS C: drive
+ of the hard disk, you need to do the following:
+
+ If FreeBSD is installed on a hard disk containing
+ a Primary MS-DOS partition (as opposed to an
+ Extended DOS partition), then the FreeBSD distribution
+ files can be read directly from DOS. Preparation
+ is just a matter of copying the FreeBSD distribution
+ files onto DOS C: drive of the hard disk.
+
+ If FreeBSD is installed on a separate hard disk than
+ MS-DOS, it is not currently possible to read the FreeBSD
+ distribution files directly from DOS. In this case,
+ a different medium should be used.
+
+ Once you have the files on the C: drive, you can proceed to the
+ next step in the installation process, viz preparing your hard
+ disk.
+
+To prepare for installing via MS-DOS floppies:
+
+ To prepare FreeBSD for installaton from MS-DOS floppies, you
+ need to do the following:
+
+ Count the number of "<set>_tgz.xx" files
+ you have (these are split, gzip'ed, tar
+ archives). Call this number N. You will
+ need N/6 1.44M floppies, or N/5 1.2M
+ floppies to install the distribution
+ in this manner. For the set of bin files
+ (i.e., 80 files) and 1.2 Mb floppies you will
+ need 16 disks.
+
+ Format all of the floppies, with MS-DOS.
+ Don't make any of them MS-DOS bootable
+ floppies (i.e., don't use "format /s"!)
+ If you use "format /u" then the format
+ will run a tad faster.
+
+ Copy all of the "<set>_tgz.xx" files on
+ the DOS disks. Under DOS use the DOS copy
+ command. Under 386BSD, use, for instance,
+ the make_floppies script:
+
+ #!/bin/sh
+ N_PER_DISK=5
+
+ x=$N_PER_DISK
+ for dist in bin_tgz.*; do
+ if [ $x -ge $N_PER_DISK ]; then
+ x=0
+ echo -n "Insert next disk, "
+ echo -n "and press ENTER... "
+ read reply
+ mdel a:/\*
+ fi
+ mcopy $dist a:/
+ x=`expr $x + 1`
+ done
+
+ (Or you might use tar instead).
+
+ Once you have the files on DOS disks, you can proceed to the
+ next step in the installation process, viz preparing your hard
+ disk.
+
+To prepare for installing via a tape:
+
+ To install FreeBSD from a tape, you need to be somehow
+ to get the FreeBSD filesets you wish to install on
+ your system on to the appropriate kind of tape,
+ in tar format.
+
+ If you're making the tape on a UN*X system, the easiest
+ way to do so is:
+
+ tar cvf <tape_device> <files>
+
+ where "<tape_device>" is the name of the tape device
+ that describes the tape drive you're using (either
+ /dev/rst0 for SCSI tape, otherwise /dev/rwt0).
+ If you can't figure it out, ask your system administrator.
+ "<files>" are the names of the "<set>.tar.gz.xx" files
+ which you want to be placed on the tape.
+
+ If your tape drive is not a type recognzed by the
+ kernel, then it may be necessary to set the tape density
+ using either the st(1) command (for SCSI tape) or the
+ mt(1) command. Both these programs are available from
+ the tools directory of the FreeBSD archive site.
+
+To prepare for installing via an NFS partition:
+
+ NOTE: this method of installation is recommended
+ only for those already familiar with using
+ the BSD network-manipulation commands and
+ interfaces. If you aren't, this documentation
+ should help, but is not intended to be
+ all-encompassing.
+
+ Place the FreeBSD software you wish to install into
+ a directory on an NFS server, and make that directory
+ mountable by the machine which you will be installing
+ FreeBSD on. This will probably require modifying the
+ /etc/exports file of the NFS server and resetting
+ mountd, acts which will require superuser privileges.
+ Make a note of the numeric IP address of the NFS server
+ and make a note of the router closest to the the new
+ FreeBSD machine if the NFS server is not on a network
+ which is directly attached to the FreeBSD machine.
+
+ Once you have done this, you can proceed to the next
+ step in the installation process, preparing your hard disk.
+
+To prepare for installing via FTP:
+
+ NOTE: this method of installation is recommended
+ only for those already familiar with using
+ the BSD network-manipulation commands and
+ interfaces. If you aren't, this documentation
+ should help, but is not intended to be
+ all-encompassing.
+
+ The preparations for this method of installation
+ are easy: all you have to do is make sure that
+ there's some FTP site from which you can retrieve
+ the FreeBSD installation when it's time to do
+ the install. You should know the numeric IP
+ address of that site, and the numeric IP address of
+ your nearest router if the new FreeBSD computer is
+ not on the same net or subnet as the FTP site.
+
+ Once you have done this, you can proceed to the next
+ step in the installation process, preparing your hard disk.
+
+To prepare for installing via Kermit:
+
+ The preparations for this method of installation
+ require that the kermit program be put on the
+ dos-floppy installation disk. This will be
+ loaded as part of the minimum base installation.
+ Kermit is available from tools directory of the
+ FreeBSD FTP site. This is a FreeBSD binary and
+ only executes under the FreeBSD operating system.
+
+ Once you have done this, you can proceed to the next
+ step in the installation process, preparing your hard disk.
+
+To upgrade:
+
+ (The beta upgrade script is available on request from
+ FreeBSD-questions@freefall.cdrom.com)
+
+Preparing your Hard Disk for FreeBSD Installation:
+--------- ---- ---- ---- --- ------ ------------
+
+NOTE: If you wish to install FreeBSD on your whole drive, (i.e. you do
+not want DOS or any other operating system on your hard disk), you can
+skip this section, and go on to "Installing the FreeBSD System."
+
+Firstly, be sure you have a reliable backup of any data which you may
+want to keep; repartitioning your hard drive is an excellent way to
+destroy important data.
+
+WARNING: If you are using a disk controller which supports disk
+geometry translation, BE SURE TO USE THE SAME PARAMETERS FOR FreeBSD AS
+FOR DOS! If you do not, FreeBSD will not be able to properly coexist
+with DOS.
+
+Secondly, make sure your disk has at least 16 Mbytes free space (or
+80 Mbytes for the complete binary distribition).
+
+You are now set to install FreeBSD on your hard drive.
+
+Installing the FreeBSD System:
+---------- --- ------ ------
+
+If DOS or OS/2 is already installed on the hard disk, installation should
+be easy. By default FreeBSD is installed after the last DOS or OS/2
+partition. Otherwise, you may need to specify your hard disk's geometry
+(i.e., number of cylinders, heads and sectors per track).
+
+For computing partition sizes, it might help to have a calculator handy.
+
+And it's finally time to install the system!
+
+The following is a walk-through of the steps necessary to get FreeBSD
+installed on your hard disk. If you wish to stop the installation, you
+may hit Control-C at any prompt and then type `halt'.
+
+ Boot from the kcopy-ah or kcopy-bt floppy, depending on
+ your hard disk controller type.
+
+ When prompted to insert the filesystem floppy, remove the
+ kcopy floppy from the drive and insert filesystem floppy
+ and hit any key.
+ N.B.: The filesystem floppy must not be write protected.
+
+ [When booting, if no message prompt appears after a
+ reasonable period of time, reboot and try it again. If
+ this doesn't work, try disabling your CPU's internal and
+ external caches, and then try to boot again. If there is
+ still no message prompt, then you can't install FreeBSD
+ on your hardware. If you were able to install 386bsd,
+ this is definitely a bug in our software; please report
+ it! Please include your system configuration, and any
+ other relevant information in your bug report.]
+
+ The boot sequence continues after the filesystem floppy
+ has been inserted. A copyright notice is displayed along
+ with a list of the hardware that FreeBSD recognizes as
+ being in your machine. You might want to make a note of
+ the disk values for cylinders, heads, sectors etc for
+ later use.
+
+ After a short while (approximately 30 to 60 seconds), you
+ should see a welcome message and a prompt, asking if you
+ wish to proceed with the installation.
+
+ If you wish to proceed, enter "y" and then return.
+
+ You will then be asked what type of disk drive you have.
+ The valid options are listed on the screen (e.g., SCSI, ESDI).
+
+ You will then be asked for a label name for your disk.
+ This should be a short, one-word name for your disk,
+ e.g., "cp3100-mine" for a Conner Peripherals "3100" disk.
+ You needn't remember this name.
+
+ Next, you will be prompted for the geometry information.
+ The default values should be correct, in which case just
+ hit ENTER to accept them. Otherwise enter the values
+ that were displayed during the boot sequence as they are
+ requested.
+
+ The default size of the FreeBSD portion of the disk
+ is the maximum available at the end of the disk (which may
+ be the whole disk). Accept the default by hitting ENTER.
+ Otherwise, enter an appropriate value using the information
+ displayed.
+
+ If you are not installing on the whole disk, you will be
+ asked for the offset of the FreeBSD partition from the
+ beginning of the disk. Again, hit ENTER to accept the
+ default, or enter a cylinder offset from the beginning of
+ the disk.
+
+ You will then be asked for the size of your root partition,
+ in cylinders. The suggested maximum size is 15 Mbytes
+ which is used as a default. Accept this, or enter a
+ suitable value (after converting to cylinders using the
+ formula displayed).
+
+ Next, you will be asked for the size of your swap partition
+ - again, you must calculate this in cylinders. You should
+ probably allocate around twice as much swap space as you
+ have RAM memory. If you wish the system to save crash dumps
+ when it panics, you will need at least as much swap as you
+ have RAM.
+
+ The install program will then ask you for information about
+ the rest of the partitions you want on your disk. For the
+ purposes of this document, you only want one more: /usr.
+ Therefore, at the prompt, when in asks you to enter the size
+ of the next partition, enter the number of cylinders remaining
+ in the FreeBSD portion of the disk. When it asks you for the
+ mount point for this partition, say "/usr".
+
+ After the FreeBSD partition have been assigned, install checks
+ the disk for an MS-DOS partition. If one exists, you are prompted
+ whether to make this accessible from FreeBSD (i.e., for reading
+ and writing). And if you choose to make the DOS partition
+ accessible, you are prompted for what directory it should
+ be mounted on. "/dos" is used by default. With this
+ choice, you could copy the contents of the DOS root
+ directory (i.e., C:\), for instance, with the Unix command:
+
+ # cp /dos/* .
+
+ If have you a DOS partition and you don't want it visible
+ from FreeBSD, just respond with "n" when asked whether to
+ make it accessible.
+
+ YOU ARE NOW AT THE POINT OF NO RETURN.
+
+ If you confirm that you want to install FreeBSD, your hard
+ drive will be modified, and perhaps it contents scrambled at
+ the whim of the install program. This is especially likely
+ if you gave the install program incorrect information.
+ Enter "no" at the prompt to get the option of redoing the
+ configuration, using your previous choices as defaults.
+
+ If you are sure you want to proceed, enter "yes" at the prompt.
+
+ The install program now makes the filesystems you specified.
+ If all goes well, there should be no errors in this section
+ of the installation. If there are, restart from the the
+ beginning of the installation process.
+
+ After the installation program prompts you to see if you'd
+ like to be told about all of the files it's going to copy
+ to your hard drive, it will spend a few minutes copying these
+ files and then will print out an informative message and
+ place you at a "#" prompt.
+
+ Read the message and note which partition (e.g., sd0a or wd0a)
+ you need to copy a kernel to. Reboot the machine off the
+ kcopy-xx-floppy disk, but this time at the prompt asking
+ you to insert a file system floppy, do _not_ replace the
+ floppy, just press <enter>.
+
+ At the "kc>" prompt, enter "copy" to prepare to copy the
+ kernel on the floppy to your hard disk.
+
+ At the next "kc>" prompt, enter the disk partition to which
+ you want to copy the kernel. (e.g., sd0a or wd0a).
+
+ It will work for a minute or two, then present you with
+ another "#" prompt. Follow the instructions given, (i.e.,
+ halt the system) and reboot from the hard disk. You will
+ probably have to do a hardware reset or else your ethernet
+ card might not be recognised at reboot (e.g., if you have a
+ WD8003EP card).
+
+ When the machine boots, a three-line banner should appear at
+ the top of the screen. In a few seconds, a series of
+ messages will appear, describing the hardware in your machine.
+ Once again, this stage can take up to two minutes, so DO NOT
+ PANIC!
+
+ You will be asked to insert the cpio-floppy into a floppy
+ drive, and enter that drive's number. "0" corresponds to
+ DOS's "A:" drive, "1" corresponds to DOS's "B:" drive.
+
+ After you enter the number it will ask you if you'd like to
+ watch its progress, and after you answer this question it
+ will begin installing still more files on your hard disk.
+ This should take no more than 3 minutes.
+
+ You are given the option to load the dos-floppy disk.
+ In particular, if you want to use kermit for downloading
+ the distribution, the dos-floppy should have the kermit
+ binary. Or if you are using SCSI tape, the dos-floppy should
+ contain the st command.
+
+ To load the dos-floppy, remove the cpio-floppy from the
+ drive, insert the dos-floppy and enter a "yes" response
+ at the prompt. Otherwise, enter "no" at the prompt.
+
+ After the dos-floppy has been loaded, you are given (more)
+ instructions, (e.g., to halt the system) and you should
+ reboot the machine again, from the hard drive and probably
+ with a hardware reset to kick your ethernet card back into
+ life.
+
+ CONGRATULATIONS: You now have the minimum base of FreeBSD
+ files on your hard disk! Now you get to install the
+ distribution file sets. Remember that, at minimum, you must
+ install the bin.tar.gz.xx file set (see below for
+ instructions).
+
+ After the machine is done booting, you will be presented
+ with a screenful of information about what to do next.
+
+ What you do from this point on depends on which media you're
+ using to install FreeBSD. Follow the appropriate
+ instructions, given below.
+
+ To install from MS-DOS hard disk partition, floppy or tape:
+
+ The first thing you should do is to choose a temporary
+ directory where the distribution files can be stored.
+ To do this, use the command "set_tmp_dir" and enter
+ your choice. The default is /usr/distrib.
+
+ After you have chosen a temporary directory,
+ you should issue the appropriate load command:
+
+ load_dos - for loading from a MS-DOS hard disk
+ partition, or from floppies,
+
+ load_qic_tape - for loading from QIC-02 tape, or
+
+ load_scsi_tape - for you're loading from the first
+ SCSI tape drive in the system.
+
+ If loading from tape, it may be necessary to first
+ set the default density using the mt or st command.
+ The low-density device (/dev/rst0 or /dev/rmt0)
+ is used by the load_xx_tape command, so to prepare
+ a SCSI device for reading QIC-150 tape, you might use:
+
+ # st -f /dev/nrst0 rewind
+ # st -f /dev/nrst0 low_dnsty 16
+ # load_scsi_tape
+
+ If loading from floppy or hard disk, the load_dos
+ command prompts for information, such as to which
+ floppy drive or hard disk directory to load from.
+ Additional options are available, e.g., for listing
+ and, if loading from hard disk, changing source
+ directories.
+
+ Go to the directory which contains the first
+ distribution set you wish to install. This is
+ either the directory you specified above, if using
+ load_dos, or possibly a subdirectory of that
+ directory, if you loaded from tape.
+
+ When there, run "set_tmp_dir" again, and choose
+ the default temporary directory, by hitting
+ return at the prompt.
+
+ Run the "extract" command, giving it as its sole
+ argument the name of the distribution set you
+ wish to extract. For example, to extract the binary
+ distribution, use the command:
+
+ extract bin
+
+ and to extract the source distribution:
+
+ extract src
+
+ After the extraction is complete, go to the location
+ of the next set you want to extract, "set_tmp_dir"
+ again, and once again issue the appropriate
+ extract command. Continue this process until
+ you've finished installing all of the sets which you
+ desire to have on your hard disk.
+
+ After each set is finished, if you know that you
+ are running low on space you can remove the
+ distribution files for that set by saying:
+
+ rm <set>*
+
+ For example, if you wish to remove the distribution
+ files for the binarydist set, after the "extract bin"
+ command has completed, issue the command:
+
+ rm bin*
+
+ Once you have extracted all sets and are at the "#" prompt
+ again, proceed to the section "Configuring Your System,"
+ below.
+
+ To install via FTP or NFS:
+
+ First you must decide on a temporary directory to hold
+ the <set>.tar.gz.xx files. The directory /usr/distrib
+ is suggested. You should cd to it, if necessary do
+ a mkdir first. Use set_tmp_dir to identify this
+ directory to the install process.
+
+ Configure the appropriate ethernet interface (e.g. ed0,
+ ne0, etc.) up, with a command like:
+
+ ifconfig <ifname> <ipaddr> [netmask <netmask>]
+
+ where <ifname> is the interface name (e.g. ed0, etc.),
+ and <ipaddr> is the numeric IP address of the interface.
+ If the interface has a special netmask, supply
+ the word "netmask" and that netmask at the end of the
+ command line. For instance, without a special netmask:
+
+ ifconfig ed0 129.133.10.10
+
+ or with a special netmask
+
+ ifconfig ed0 128.32.240.167 netmask 0xffffff00
+
+ or the equivalent
+
+ ifconfig ed0 128.32.240.167 netmask 255.255.255.0
+
+ If you are using the AUI connector on a 3C503 card, you
+ must also set the LLC0 flag (the default is to use the BNC
+ connector):
+
+ ifconfig ed0 130.252.23.86 llc0
+
+ If the NFS server or FTP server is not on a directly-
+ connected network, you should set up a route to it
+ with the command:
+
+ route add default <gate_ipaddr>
+
+ where <gate_ipaddr> is your gateway's numeric IP address.
+
+ If you are NFS-mounting the distribution sets,
+ mount them on the temporary directory with the command:
+
+ mount -t nfs <serv_ipaddr>:<dist_dir> <tmp_dir>
+
+ where <serv_ipaddr> is the server's numeric IP address,
+ <dist_dir> is the path to the distribution files on
+ the server, and <tmp_dir> is the name of the local
+ temporary directory (e.g., /usr/distrib). Proceed as if
+ you had loaded the files from tape, "cd"ing to the
+ appropriate directories and running "set_tmp_dir" and
+ "extract" as appropriate.
+
+ If you are retrieving the distribution sets using ftp,
+ cd into the temp directory, and execute the command:
+
+ ftp <serv_ipaddr>
+
+ where <serv_ipaddr> is the server's numeric IP address.
+ Get the files with FTP, taking care to use binary mode
+ to transfer all files. A simple set of commands is
+
+ ftp <serv_ipaddr>
+ user ftp
+ passwd <user-id>@
+ hash
+ binary
+ prompt
+ cd <where/the/binarydist/files/are>
+ mget *
+ cd <where/the/sourcedist/files/are>
+ mget *
+ quit
+
+ Once you have all of the files for the distribution sets
+ that you wish to install, you can proceed using the
+ instructions above as if you had installed the files
+ from a floppy.
+
+ To install via Kermit:
+
+ First you must decide on a temporary directory to hold
+ the <set>.tar.gz.xx files. The directory /usr/distrib
+ is suggested. You should cd to it, if necessary do
+ a mkdir first. Use set_tmp_dir to identify this
+ directory to the install process.
+
+ Invoke kermit and dial the remote kermit server.
+ A typical session might be:
+ # stty -f /dev/sio01 clocal
+ # kermit
+ C-Kermit> set file type binary
+ C-Kermit> set line /dev/sio01
+ C-Kermit> set baud 9600
+ C-Kermit> set receive packet 740
+ C-Kermit> set window 4
+ C-Kermit> set block 2
+ C-Kermit> connect
+ Connecting to /dev/sio01, speed 9600.
+ The escape character is Ctrl-\ (ASCII 28, FS)
+ Type the escape character followed by C to get back,
+ or followed by ? to see other options.
+ atdt 1234567 <-- dial the remote
+ Connect 9600
+ login: mylogin <-- login to the remote
+ [...]
+ remote$ kermit -ix <-- remote kermit as binary server
+ [...]
+ ^\C <-- return to local kermit
+ C-Kermit> get bin_tgz* <-- request files from remote
+ [...] (wait long for transfer to complete)
+ C-Kermit> finish <-- terminate remote server
+ C-Kermit> connect
+ C-Kermit> exit <-- exit remote kermit
+ remote$ exit <-- exit remote host
+ ^\C <-- return to local kermit
+ C-Kermit> exit <-- exit local kermit
+
+ At this point the binary distribution should be
+ downloaded to the FreeBSD system. Run the "extract"
+ command, giving it as its sole argument the name
+ of the distribution set you wish to extract. For
+ example, to extract the binary distribution, use
+ the command:
+
+ extract bin
+
+ and to extract the source distribution:
+
+ extract src
+
+ After the extraction is complete, go to the location
+ of the next set you want to extract, "set_tmp_dir"
+ again, and once again issue the appropriate
+ extract command. Continue this process until
+ you've finished installing all of the sets which you
+ desire to have on your hard disk.
+
+ After each set is finished, if you know that you
+ are running low on space you can remove the
+ distribution files for that set by saying:
+
+ rm <set>*
+
+ For example, if you wish to remove the distribution
+ files for the binarydist set, after the "extract bin"
+ command has completed, issue the command:
+
+ rm bin*
+
+ Once you have extracted all sets and are at the "#" prompt
+ again, proceed to the section "Configuring Your System,"
+ below.
+
+
+Further Tips on Installing FreeBSD
+------- ---- -- ---------- -------
+
+ You might wish to install the binarydist first, get that
+ working, and then at a later point in time have a go at
+ installing the sourcedist. BEFORE YOU REBOOT AFTER INSTALLING
+ THE BINARYDIS, you must preserve the commands that do the
+ extracting. They are kept in the single-user-mode .profile
+ file called /.profile. Proceed like this:
+
+ mv /.profile /.profile.install
+ ln /root/.profile /.profile
+
+ When you are ready to install the sourcedist at some time
+ in the future, get into multi-user mode (i.e., the normal
+ means of running FreeBSD) and issue these commands:
+
+ cp /.profile.install /.profile
+ shutdown now
+
+ This will cause the system to go into single-user mode, and
+ the install profile will be active (i.e., you will find the
+ commands load_dos, extract etc available to you again).
+
+ If your disk has several operating systems, you may want
+ to install a boot manager such as Thomas Wolfram's os-bs
+ for selecting which system to boot. os-bs135.exe and other
+ boot managers are available from the tools directory of
+ the FreeBSD FTP site. os-bs works well with DOS, OS/2,
+ FreeBSD and other systems, however, it cannot currently
+ be used to boot FreeBSD from a second hard disk. Another
+ boot manager, such as boot-easy should be used.
+
+ To install, for instance, os-bs, boot the system with
+ MS-DOS and insert the dos-floppy containing os-bs135.exe
+ in floppy drive A:. Then enter the DOS commands:
+ > A:
+ > os-bs135
+ > cd os-bs
+ > os-bs
+ A menu should now appear on the screen. Use the cursor keys
+ to highlight the install option, hit ENTER, and follow the
+ instructions from there.
+
+ For more information about the ob-bs program, including its
+ capabilities and limitations, see the file `readme.1st' in the
+ os-bs directory.
+
+ If your disk has several operating systems and you choose
+ not to install os-bs, then fdisk can be used to change
+ the boot system. This is done by making the primary
+ partition for the boot system active. FreeBSD has an
+ fdisk command that can be used for this purpose as well.
+
+
+Configuring Your System:
+----------- ---- ------
+
+Once you have finished extracting all of the distribution sets that you
+want on your hard drive and are back at the "#" prompt, you are ready
+to configure your system.
+
+The configuration utility expects that you have installed the base
+system. If you have not, you will not be able to run it successfully
+(nor will you have a functional system regardless of configuration).
+
+To configure the newly installed operating system, run the command
+"configure".
+
+Configure will ask for the machine's hostname, domain name, and other
+network configuration information. You should check that configure has
+set up the following files correctly:
+
+ /etc/netstart
+ /etc/myname
+
+Once you have supplied configure all that it requests, your machine
+will be configured well enough that when you reboot it it will be a
+completely functional FreeBSD system. It is not completely configured,
+however; you should adjust the /etc/sendmail.cf file as necessary to
+suit your site and/or disable sendmail in /etc/rc and you should look
+in /etc/netstart to make sure the flags are defined correctly for your
+site. You might wish to set up several other tcp/ip files, such as
+
+ /etc/resolv.conf
+ /etc/networks
+
+Once you are done with configuration, reboot with the "reboot" command.
+
+When it boots off of the hard drive, you will have a complete FreeBSD
+system! CONGRATULATIONS! (You really deserve them!!!)
+
+
+Administrivia:
+-------------
+
+Registration? What's that?
+
+If you've got something to say, do so! We'd like your input.
+
+Please send random comments to:
+
+ FreeBSD-questions@freefall.cdrom.com
+
+Please send bug reports, and that sort of material to:
+
+ FreeBSD-bugs@freefall.cdrom.com
+
+If you'd like to help with this effort, and have an idea as to how
+you could be useful, send mail to:
+
+ FreeBSD-hackers@freefall.cdrom.com
+
+THANKS FOR USING THIS; that's what makes it all worthwhile.
+
+[a favor: Please avoid mailing huge documents or files to these mailing lists,
+ as they will end up in our personal mail spools. We will be
+ happy to make other arrangements]
+
+This is $Id: README.INSTALL,v 1.1 1994/06/28 09:01:55 jkh Exp $
diff --git a/etc/etc.i386/cdinst1.install b/etc/etc.i386/cdinst1.install
index f60f833f4e05..bb8380ed5063 100644
--- a/etc/etc.i386/cdinst1.install
+++ b/etc/etc.i386/cdinst1.install
@@ -1,7 +1,7 @@
#!/bin/sh
# cd install floppy disk /install script
#
-# $Id: cdinst1.install,v 1.1.2.3 1994/05/05 04:11:20 rgrimes Exp $
+# $Id: cdinst1.install,v 1.6 1994/06/29 06:46:01 rgrimes Exp $
# ${OPSYSTEM}, the mounting of the cdrom drive, and the path are all
# setup by .profile
@@ -432,7 +432,7 @@ sync
verified_install=""
while [ ! "$verified_install" ]; do # Begin of Big Loop
-rotdelay=""
+rotdelay="-d 0 -n 1"
drivename=wd0
drivetype=wd
sect_fwd=""
@@ -459,13 +459,11 @@ e*|E*|st*|ST*)
;;
i*|I*)
type=ST506
- rotdelay="-d 0"
;;
sc*|SC*)
drivename=sd0
drivetype=sd
type=SCSI
- rotdelay="-d 0"
DEFSECT=32
DEFHEAD=64
;;
@@ -474,6 +472,11 @@ sc*|SC*)
type=ST506
;;
esac
+echo -n "Install onto which drive [$drivename] "
+read resp junk
+drivename=${resp:-${drivename}}
+echo
+echo "Disk $drivename is of device type $drivetype."
if [ ! "$partition" ]; then
echo
echo "Please wait. Examining device /dev/r${drivename}d..."
@@ -859,7 +862,7 @@ if [ "$sect_fwd" = "sf:" ]; then
bad_read=$(expr "$data" : '[^(]*(read)[^0-9]*\([0-9]*\)')
[ "$bad_seek" -o "$bad_read" ] && echo -n "$bad_seek $bad_read "
done)
- [ "$badlist" ] && bad144 -a -c $drivename "$badlist"
+ [ "$badlist" ] && bad144 -a -c $drivename $badlist
echo " done."
fi
@@ -991,7 +994,7 @@ n*)
echo -n "What is the netmask? [0xffffff00] "
read resp
if [ "$resp" = "" ]; then
- ifnetmask="netmask 0xffffff00"
+ ifnetmask="netmask 0xffffff00
else
ifnetmask="netmask $resp"
fi
diff --git a/etc/etc.i386/cpio.magic b/etc/etc.i386/cpio.magic
index d3a8e028533b..a4353d943dbc 100644
--- a/etc/etc.i386/cpio.magic
+++ b/etc/etc.i386/cpio.magic
@@ -1,5 +1,5 @@
#!bin/sh
-# $Id: cpio.magic,v 1.2.2.4 1994/05/01 20:53:40 rgrimes Exp $
+# $Id: cpio.magic,v 1.13 1994/06/29 20:29:12 jkh Exp $
#
set_tmp_dir()
{
@@ -104,7 +104,7 @@ load_fd()
echo;
if [ "$drive" != "C" ]; then
echo "Insert floppy in drive $drive:, then press RETURN to copy files,"
- echo -n "or enter option (? for help): "
+ echo -n "or enter option (? for help): "
else
echo -n "Press RETURN to copy files, or enter option (? for help): "
fi
@@ -219,14 +219,14 @@ load_qic_tape()
tmp_dir
echo -n "Insert tape into QIC tape drive and hit return to continue: "
read foo
- tar xvf /dev/rwt0
+ tar --unlink -xvf /dev/rwt0
}
load_scsi_tape()
{
tmp_dir
echo -n "Insert tape into SCSI tape drive and hit return to continue: "
read foo
- tar xvf /dev/nrst0
+ tar --unlink -xvf /dev/nrst0
}
extract()
{
@@ -242,12 +242,7 @@ extract()
tarverbose=
;;
esac
- #XXX ugly hack to eliminate busy files, copy them to /tmp and use them
- #from there... even uglier.. we CAN NOT LOAD libc.so.1.0 from the tar
- #balls or it spams tar!!
- cp -p /bin/cat /usr/bin/gunzip /usr/bin/tar /tmp
-
- #XXX more ugly hacks to get around busy text files/symlink problems.
+ #XXX ugly hacks to get around busy text files/symlink problems.
if [ X"$1" = X"bin" ]; then
rm -f /bin/sh.$$ /sbin/init.$$ /etc/termcap.$$
mv /bin/sh /bin/sh.$$
@@ -259,11 +254,10 @@ extract()
mv /sbin/init /sbin/init.$$
fi
for i in $*; do
- /tmp/cat "$i"* |
- /tmp/gunzip |
- (cd / ; /tmp/tar --extract --file - --preserve-permissions --exclude libc.so.1.0 ${tarverbose} )
+ cat "$i"* |
+ gunzip |
+ (cd / ; tar --unlink --extract --file - --preserve-permissions ${tarverbose} )
done
- rm -f /tmp/cat /tmp/gunzip /tmp/tar
sync
[ X"$1" = X"bin" ] && echo "Run \`configure' to complete installation."
echo "(wd is now: `pwd`)"
@@ -359,6 +353,32 @@ configure()
;;
esac
+ echo
+ echo "Setting up access to a nameserver:"
+ echo -n "Do you want to configure /etc/resolv.conf? [n]: "
+ read resp
+ case "$resp" in
+ y*)
+ echo "OK: Configuring your /etc/resolv.conf"
+ echo "If you need more information about resolv.conf"
+ echo "type \"man 5 resolver\" once you have COMPLETED"
+ echo "installation of the binary distribution."
+ echo ""
+
+ nameserver=
+ while [ "$nameserver" = "" ]; do
+ echo -n "Enter the IP number of your nameserver: "
+ read nameserver
+ done
+
+ echo "nameserver $nameserver" > /etc/resolv.conf
+
+ echo " "
+ ;;
+ *)
+ ;;
+ esac
+
sync
echo
diff --git a/etc/etc.i386/cpio.rc b/etc/etc.i386/cpio.rc
index b7832ef7d339..5ef92dc31760 100644
--- a/etc/etc.i386/cpio.rc
+++ b/etc/etc.i386/cpio.rc
@@ -1,4 +1,4 @@
-# $Id: cpio.rc,v 1.1.2.1 1994/03/06 08:44:08 rgrimes Exp $
+# $Id: cpio.rc,v 1.4 1994/06/04 12:00:51 jkh Exp $
#
stty status '^T'
@@ -56,11 +56,20 @@ rm -f /fastboot
(cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; })
OPSYSTEM=FreeBSD
-RELEASE="1.1"
+RELEASE="1.1.5"
+NVTTYS="4"
echo "${OPSYSTEM} Base System Release ${RELEASE}"
echo ""
echo "Congratulations, you've got ${OPSYSTEM} on the hard disk!"
echo
+echo "Your system has been configured with ${NVTTYS} virtual terminals,"
+echo "though one has been reserved for X (should you need it) and has no"
+echo "login prompt on it. Once you've loaded the binary distribution and"
+echo "have rebooted the system, you can access these virtual terminals by"
+echo "pressing ALT-F<n>, where n is the function key number representing"
+echo "the virtual terminal you want to use. For more information, read"
+echo "the screen(4), kbdcontrol(1) and vidcontrol(1) man pages."
+echo
echo "Press the return key for more installation instructions"
read junkit
echo
diff --git a/etc/etc.i386/floppy.install_notes b/etc/etc.i386/floppy.install_notes
deleted file mode 100644
index 5b457018ee82..000000000000
--- a/etc/etc.i386/floppy.install_notes
+++ /dev/null
@@ -1,143 +0,0 @@
- FLOPPY INSTALLATION NOTES
- FreeBSD
- Release 1.1
-
-Welcome to FreeBSD! This document has been put together in an effort
-to make initial installation of the system from floppy as easy as possible.
-
-1. To install FreeBSD you will need 3 (or 4 if you choose to add the optional
- DOS floppy) floppies, as well as the bulk of the distribution on some
- other medium (floppy, tape, CD, etc). If you've retrieved this release
- from the net, you'll first have to make the floppies yourself using
- the supplied images.
-
- Due to the differences in PC configurations, we've found it necessary
- to provide multiple initial boot images that provide kernels for
- different types of systems.
-
- If your disk controller is one of:
-
- MFM / RLL / IDE / ST506
- Adaptec 154x series
- Adaptec 174x series
- Buslogic 545S
-
- Then please use the disk image: kcopy_ah.flp
- to construct your boot floppy.
-
- If your disk controller is one of:
-
- Bustek 742a
- UltraStore 14F or 34F
-
- Then please use the disk image: kcopy_bt.flp
- to construct your boot floppy.
-
- Next, make a second floppy from the disk image: filesyst.flp
- You'll need this for the second stage of the boot process.
-
- Finally, make a third floppy from the disk image: cpio.flp
- You'll need this for the last stage of the boot process.
-
- If you want to use any of the optional tools in the tools
- subdirectory of the ftp distribution site, these should be
- copied directly to a DOS formatted disk (using, either mcopy
- or mount -t pcfs). This disk is referred to later as the
- optional "dos" floppy.
-
- If installing more than one operating system on a disk, then
- it is recommended that the dos floppy at least include the
- os-bs boot manager. If downloading files via a modem and SLIP
- is not available, then the dos floppy should include kermit.
- You'll have the option of loading the programs that are on
- the dos floppy in the last stage of the boot process.
-
-2. Boot the first floppy. When it asks you to insert the file system floppy,
- insert the second floppy ``filesyst.flp.'' Follow the instructions
- that floppy gives you. If partitions already exist on the hard disk,
- then by default FreeBSD attempts to install itself at the end of these.
- Before rebooting, note the type of disk it says to copy the kernel
- to: ``sd0a'' or ``wd0a'' (``sd0a'' is for SCSI systems, ``wd0a'' is
- for all others.) When the system halts, go on to the next step.
-
-3. Boot the first floppy again, but this time when it asks
- you to insert the file system floppy, just press the return key.
- Follow the instructions that the floppy gives you. When you see
- the ``kc>'' prompt, type ``copy'' (without quotes). At the next prompt,
- ``copy kernel to>'', type either ``sd0a'' or ``wd0a'' as given in
- the previous step. When the system halts, go on to the next step.
-
-4. Making sure that there's no floppy in the drive, press return to boot
- from the hard disk. After it has booted and is asking what drive the
- cpio floppy is in, insert the third floppy ``cpio.flp'' into a
- floppy drive and answer the question about what drive it is in.
- Note that 0 is the same as DOS drive A:, and 1 is the same as DOS
- drive B:
-
-5. After the cpio floppy has been copied to the disk, remove it from the
- drive. If there are programs on the dos-floppy that you would like
- installed, then insert this disk in a floppy drive, again specifying
- the drive to read from.
-
-6. After the cpio (or optional dos) floppy has been copied to the disk,
- enter `halt' at the command prompt.
-
-7. When the system asks you to press the return key to reboot, first
- remove the floppy and then press the return key to boot from the hard
- disk.
-
-8. At this point you will get 4 errors from the fsck on boot, these
- are normal and are caused by files that were open when the
- /dev entries were built - just ignore them. The system will
- correct these errors and then halt, after which you should press
- the return key again to reboot with a clean system.
-
-9. Congratulations, you've got the mini FreeBSD system on your disk!
-
-10. Follow the instructions about set_tmp_dir and extract that
- will come on your screen after you've pressed the return key.
-
-11. Run the configure command to set up some of the /etc files by
- typing ``configure''. You will have to edit /etc/netstart after
- this if you have a networking interface.
-
-12. Reboot so that the system comes up multiuser by typing ``reboot''.
-
-13. You are now running FreeBSD! Congradulations! You may now continue
- with installing the source distribution, or stop here for now.
-
-14. The file /magic contains the special sh commands used during
- installation. Should you need to use them you can do the following.
-
- /bin/sh
- . /magic
-
-15. If your disk has several operating systems, you may want to
- install the Thomas Wolfram's os-bs boot manager for selecting
- which system to boot. This works well with DOS, OS/2, FreeBSD
- and other systems. To install it, boot the system with MS-DOS
- and insert the dos-floppy of the FreeBSD install suite in
- floppy drive A:. Then enter the DOS commands:
- > A:
- > os-bs135
- > cd os-bs
- > os-bs
- A menu should now appear on the screen. Use the cursor keys
- to highlight the install option and hit ENTER. Simply follow the
- instructions from there.
-
- For more information about the ob-bs program, including its
- capabilities and limitations, see the file `readme.1st' in the
- os-bs directory.
-
- If you choose not to install os-bs, then fdisk can be used to
- change the boot system. This is done by making the primary
- partition for the boot system active. FreeBSD has an fdisk
- command that can be used for this purpose as well.
-
-16. In addition to the FreeBSD source and binary distributions, many
- additional packages, such as X11 and TeX, may be obtained from
- freebsd.cdrom.com - please have a look around! You may also find
- this a good time to read the release notes in RELNOTES.FreeBSD.
-
-End of $Id: floppy.install_notes,v 1.13.2.1 1994/05/05 03:58:27 rgrimes Exp $
diff --git a/etc/etc.i386/inst1.install b/etc/etc.i386/inst1.install
index d6fce87bc433..e3941174fb9e 100755
--- a/etc/etc.i386/inst1.install
+++ b/etc/etc.i386/inst1.install
@@ -9,7 +9,7 @@ export PATH
OPSYSTEM=FreeBSD
OPSYSID=165
-ROOTMIN=7
+ROOTMIN=8
SWAPMIN=8
USRMIN=7
DISKMIN=`expr $ROOTMIN + $SWAPMIN + 1`
@@ -438,7 +438,7 @@ sync
verified_install=""
while [ ! "$verified_install" ]; do # Begin of Big Loop
-rotdelay=""
+rotdelay="-d 0 -n 1"
drivename=wd0
drivetype=wd
sect_fwd=""
@@ -465,13 +465,11 @@ e*|E*|st*|ST*)
;;
i*|I*)
type=ST506
- rotdelay="-d 0"
;;
sc*|SC*)
drivename=sd0
drivetype=sd
type=SCSI
- rotdelay="-d 0"
DEFSECT=32
DEFHEAD=64
;;
@@ -481,7 +479,11 @@ sc*|SC*)
;;
esac
echo
-echo "Disk is of device type $drivetype."
+echo -n "Install onto which drive [$drivename] "
+read resp junk
+drivename=${resp:-${drivename}}
+echo
+echo "Disk $drivename is of device type $drivetype."
if [ ! "$partition" ]; then
echo
echo "Examining device /dev/r${drivename}d..."
@@ -878,7 +880,7 @@ if [ "$sect_fwd" = "sf:" ]; then
bad_read=$(expr "$data" : '[^(]*(read)[^0-9]*\([0-9]*\)')
[ "$bad_seek" -o "$bad_read" ] && echo -n "$bad_seek $bad_read "
done)
- [ "$badlist" ] && bad144 -a -c $drivename "$badlist"
+ [ "$badlist" ] && bad144 -a -c $drivename $badlist
echo " done."
fi
diff --git a/etc/etc.i386/inst2.rc b/etc/etc.i386/inst2.rc
index c64ebfd30d27..acb3f1c6eee9 100644
--- a/etc/etc.i386/inst2.rc
+++ b/etc/etc.i386/inst2.rc
@@ -1,4 +1,4 @@
-# $Id: inst2.rc,v 1.1.2.2 1994/03/18 03:11:06 rgrimes Exp $
+# $Id: inst2.rc,v 1.4 1994/06/15 19:23:33 jkh Exp $
#
stty status '^T'
@@ -59,7 +59,7 @@ rm -f /fastboot
(cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; })
OPSYSTEM=FreeBSD
-RELEASE="1.1"
+RELEASE="1.1.5"
echo "${OPSYSTEM} Base System Release ${RELEASE}"
echo ""
echo "Congratulations, you've got ${OPSYSTEM} on the hard disk!"
diff --git a/etc/etc.i386/install_notes b/etc/etc.i386/install_notes
deleted file mode 100644
index fbf74c83aecc..000000000000
--- a/etc/etc.i386/install_notes
+++ /dev/null
@@ -1,1043 +0,0 @@
- INSTALLATION NOTES
- FreeBSD
- Release 1.1
-
-
-Be sure to read _ALL_ of this document before you try to install
-FreeBSD. FreeBSD probably looks a bit similar to things that you've
-seen before (perhaps 386BSD), but the installation procedures are quite
-different.
-
-
-FreeBSD Release Contents:
-------- --- ------- --------
-
-The FreeBSD Release consists of the following elements:
-
-Bootable Kernel copy floppies
-
- These disks are bootable and have enough utilities on
- board to copy a new kernel to a prepared hard disk. While
- they are primarily intended for installing FreeBSD, they
- also make upgrading to a new kernel easy: boot from it,
- and copy a new kernel to disk.
-
- You must choose between one of two kernel copy floppy
- images, depending on your disk controller type. The
- "kcopy_ah.flp" image supports the Adaptec 154x and 1742
- SCSI adapters, while "kcopy_bt.flp" supports the Bustek
- 742 and Ultrastore SCSI adapters. For systems with only
- MFM, RLL, ESDI or IDE disk controllers, either image can
- be used.
-
-Installation floppies
-
- In addition to a bootable floppy, currently two additional
- disks are required to prepare your hard drive for FreeBSD
- and to install the FreeBSD distribution. Like the boot
- floppies, these are distributed as binary images. They are
- are referred to below as the "filesyst.flp" and the
- "cpio.flp".
-
- There is also an optional fourth installation disk referred
- to as the "dos-floppy". Unlike the other install disks,
- there is no binary image for the dos floppy. Instead this
- is a regular MS-DOS-formatted floppy disk containing any
- FreeBSD programs you choose to copy to it using mtools or
- even the DOS copy command. The most commonly requested
- programs have been put in a tools directory at FreeBSD
- archives sites.
-
-Upgrade floppies
-
- These facilitate upgrading to FreeBSD from any previous
- patch-kit level of 386BSD 0.1. They are still in testing,
- but should be available by the time you read this from
- the tools/upgrade directory at FreeBSD archive sites.
- [the current version is:
- tools/upgrade/386BSD-to-FreeBSD-update-LATE-BETA.tar.gz]
-
-FreeBSD distribution sets
-
- These collections contain the complete FreeBSD system and
- utilities in source and binary form. There are three
- separate sets: the FreeBSD binaries, the FreeBSD sources,
- and the DES sources+binaries. The DES set contains only
- crypt(3) code and is subject to U.S.A. export restrictions.
-
- The binary distribution set can be found in the "bindist"
- subdirectory of the FreeBSD archive sites. It consists
- of files named bin_tgz.aa to bin_tgz.ce (i.e., 57 files
- all told). A CKSUMS file (* see note below) is included
- for verifying the integrity of these.
-
- The source distribution sets can be found in the
- "srcdist" subdirectory of archive sites. It is consists
- of files named base.aa to usrsbin.ae (i.e., 86 files
- all told), plus the file CKSUMS*.
-
- Finally, the security distribution set contains
- usr/src/libcrypt/*, the source files for the DES encryption
- algorithm, and the binaries which depend on it. It can
- be found in the "secrdist" subdirectory on sites which
- choose to carry the complete FreeBSD distribution.
-
- The individual files in each collection are no more than
- 235 Kbytes in size. (The last file is just long enough
- to contain the rest of the data for that distribution
- set.)
-
- Each collection is a split, gzip'ed tar archive. They
- are reassembled and extracted by the install procedure.
- However, to view them without installing FreeBSD, you can
- use, e.g., the command line:
-
- cat bin* | gunzip | tar tvf - | more
-
- or to extract the files themselves:
-
- cat bin* | gunzip | tar xvfp -
-
- Using this method, the files are extracted in the current
- directory. So to install the binary distribution, for
- instance, you have to run the "tar xvfp" from the root
- directory (/).
-
- In each of the distribution directories, there is a file
- named "CKSUMS" which contains the checksums of the files
- in that directory, as generated by the cksum(1) command.
- You can use cksum to verify the integrity of the archives,
- if you suspect one of the files is corrupted.
-
- N.B.: The CKSUMS files are produced using the 4.4BSD
- version of cksum which is POSIX-compliant. The values in
- these file do not match the cksums generated by the 386BSD 0.1
- version of cksum (which is based on an earlier "standard").
- A copy of the new cksum binary that will run on
- 386bsd/Netbsd/FreeBSD can be found in the "tools" subdirectory
- of the distribution.
-
-
-System Requirements and Supported Devices:
------- ------------ --- --------- -------
-
-FreeBSD runs on ISA (AT-Bus) and EISA systems, with 386 and 486
-processors, with or without math coprocessors. It does NOT support
-Micro-channel systems, such as some IBM PS/2 systems. The minimal
-configuration includes 4Meg of RAM, and an 80Meg hard disk, but to
-install the entire system you'll need much more disk space, and to run
-X or compile the system more RAM is recommended. (4Meg will actually
-allow you to run X and/or compile, but it's extremely slow.)
-
-Supported devices include:
-
- Standard floppy controllers
-
- Standard hard disk controllers:
- MFM
- ESDI
- IDE
- RLL
-
- SCSI hard disk controllers:
- Adaptec 154x series * [kcopy_ah.flp]
- Adaptec 174x series
- Buslogic 545S
- Bustek 742 (EISA) [kcopy_bt.flp]
- DTC 3290 in 1542 emulation mode *
- Ultrastor 14f and 34f
-
- * Your system can NOT have more than 16MB of memory with
- these controllers.
-
- Display Adaptors:
- MDA
- CGA
- VGA (and SVGA)
- HGC
-
- Serial communications ports
- 8250
- 16450
- 16550A
- [4-port multi-serial cards - require kernel built
- with MULTI_PORT option]
- [We do not support the Intel 82501 serial chip used
- in some PC's at this time]
-
- Ethernet controllers
- SMC/WD 8003, 8013, and equivalents
- (including the SMC "Elite" series)
- Novell NE1000, NE2000, NE2100
- 3COM 3c503
- ISOLAN ISOLink
-
- Tape drives:
- QIC-02 format tape drives
- most SCSI tape/DAT drives
- [an early QIC-40 or QIC-80 tape driver exists,
- but is not yet incorporated into FreeBSD]
-
- CD-ROM drives:
- Mitsumi CDROM drive with Mitsumi Controller
- Most SCSI CD-ROM drives on a supported SCSI controller
-
-To be detected by the distributed kernels, the devices must
-be configured as follows: (Note: IRQ 9 is the same as IRQ 2
-on ISA/EISA based machines)
-
-Device Name Port IRQ DRQ Misc
------- ---- ---- --- --- ----
-Floppy Cntlr. fd0 0x3f0 6 2
-
-Std. Hard Disk Cntlr.
- wd0 0x1f0 14
-
-AHA-154x SCSI Cntlr. 0x330 11 5 [kcopy_ah.flp]
-
-AHA-174x SCSI Cntlr. automatically configured [kcopy_ah.flp]
-
-BT742 SCSI Cntlr. 0x330 12 [kcopy_bt.flp]
-
-UHA-14f SCSI Cntlr. or
-UHA-34f SCSI Cntlr. 0x330 14 5 [kcopy_bt.flp]
-(In FreeBSD 1.0 GAMMA and before, UHA was on IRQ 11)
-
-SCSI Disks sd[0-2] automatically configured
-
-SCSI Tapes st[01] automatically configured
-
-SCSI CD-ROMs cd0 automatically configured
-
-Serial Ports com0 0x3f8 4
- com1 0x2f8 3
- com2 0x3e8 5
- com3 0x3f8 9
-
-SMC/WD Ethernet or
-3COM 3c503 ed0 0x280 5 iomem 0xd8000
-
-NOTE for 386bsd users: the we0 device for the WD80xxyy card has been
-replaced with an ed0 device. The default settings of 9/280/d000 have
-been changed to 5/280/d800 as this address accomdates all of the boards.
-
-Novell Ethernet ed0 0x280 5
-
-NOTE for 386bsd users: the ne0 device for the NEx000 card has been
-replaced with an ed0 device. The default settings of 9/300 have
-been changed to 5/280.
-
-ISOLAN ISOLink is0 0x280 10 7
-Novell NE2100 is0 0x280 10 7
-
-QIC-02 Tape wt0 0x300 5 1
-
-Parallel (Printer) Port
- lpt0 0x3BC 7
-
-Interruptless Parallel (Printer) Port
- lpa0 0x378
- lpa1 0x278
-
-N.B.: Disable the lpt interrupt on the board or you will
-have problems using the lpa drivers.
-
-Hard-Disk Storage Requirements
---------- ------- ------------
-
-The minimum base installation of FreeBSD requires a free hard disk
-partition with at least 16 MB free space. This is only enough for
-the three installation disks, which don't support a multi-user
-shell.
-
-The full binary distribution extracts to about 46 MB.
-The full source distribution extracts to about 86 MB.
-The kernel source only extracts to about 7 MB.
-To recompile the sources requires an additional 50 MB.
-To recompile the kernel requires an additional 2 MB.
-
-Since additional room is required for extracting the distributions,
-a full binary installation requires a minimum of about 80 MB (46
-MB extracted + 16 MB archived + 8 MB minimum swap + room for
-extracting).
-
-A complete source + binary distribution requires a minimum of
-about 210 MB (assuming a minimum 8 MB swap).
-
-
-Getting the System on to Useful Media:
-------- --- ------ -- -- ------ -----
-
-Installation is supported from several media types, including:
-
- MS-DOS floppies
- MS-DOS hard disk (Primary partition)
- Tape
- NFS partitions
- FTP
- Kermit
-
-No matter what you do, however, you'll need at least three disks (1.2M
-or 1.44M) handy, on which you will put the kernel copy image and the
-install (or upgrade) floppy images.
-
-The images are available from the directory "floppies", under the root
-of the FreeBSD/FreeBSD-1.1 tree at your favorite archive site.
-They're available both as raw disk images, and gzipped, to save time
-downloading.
-
-If you are using an AHA-154x or AHA-1742 SCSI host adapter, you need
-the kcopy_ah.flp image. If you're using a BT-742 SCSI host adapter
-or an Ultrastor adaptor, then you'll need the kcopy_bt.flp image.
-If you're using MFM/RLL/IDE disk controllers, you can use either
-kernel copy floppy image.
-
-If you are using UNIX to make the floppies, you should use the command
-dd(1) to write the raw floppy images (i.e., kcopy_ah.flp or
-kcopy_bt.flp, filesyst.flp and cpio.flp) to the floppies.
-For example, to write kcopy_ah.flp to a 5.25" 1.2 Mb floppy
-disk under 386BSD, use:
-
- $ dd if=kcopy_ah.flp of=/dev/fd0a bs=30b count=80
-
-or for a 3.5" 1.44 Mb floppy:
-
- $ dd if=kcopy_ah.flp of=/dev/fd0a bs=36b count=80
-
-If you are using DOS to make the floppies, use the rawrite.exe
-utility. This can be found in the "tools" subdirectory of the
-archive site. Copy rawrite.exe and the binary images to a DOS
-disk, type "rawrite" under MS-DOS and follow the instructions.
-Rawrite can write binary images to either 1.2MB or 1.44MB
-MS-DOS-formatted floppies.
-
-Any other programs from the tools directory that might be needed
-for installing FreeBSD, such as kermit, should be copied to a DOS-
-formatted floppy (1.2MB or 1.44MB). Under 386BSD, they can be
-copied to floppy using the mcopy command. Under DOS, use the DOS
-copy command.
-
-The steps necessary to prepare the distribution sets for installation
-depend on which method of installation you choose. The various methods
-are explained below.
-
-To prepare for installing via MS-DOS hard disk:
-
- To prepare FreeBSD for installaton from the MS-DOS C: drive
- of the hard disk, you need to do the following:
-
- If FreeBSD is installed on a hard disk containing
- a Primary MS-DOS partition (as opposed to an
- Extended DOS partition), then the FreeBSD distribution
- files can be read directly from DOS. Preparation
- is just a matter of copying the FreeBSD distribution
- files onto DOS C: drive of the hard disk.
-
- If FreeBSD is installed on a separate hard disk than
- MS-DOS, it is not currently possible to read the FreeBSD
- distribution files directly from DOS. In this case,
- a different medium should be used.
-
- Once you have the files on the C: drive, you can proceed to the
- next step in the installation process, viz preparing your hard
- disk.
-
-To prepare for installing via MS-DOS floppies:
-
- To prepare FreeBSD for installaton from MS-DOS floppies, you
- need to do the following:
-
- Count the number of "<set>_tgz.xx" files
- you have (these are split, gzip'ed, tar
- archives). Call this number N. You will
- need N/6 1.44M floppies, or N/5 1.2M
- floppies to install the distribution
- in this manner. For the set of bin files
- (i.e., 80 files) and 1.2 Mb floppies you will
- need 16 disks.
-
- Format all of the floppies, with MS-DOS.
- Don't make any of them MS-DOS bootable
- floppies (i.e., don't use "format /s"!)
- If you use "format /u" then the format
- will run a tad faster.
-
- Copy all of the "<set>_tgz.xx" files on
- the DOS disks. Under DOS use the DOS copy
- command. Under 386BSD, use, for instance,
- the make_floppies script:
-
- #!/bin/sh
- N_PER_DISK=5
-
- x=$N_PER_DISK
- for dist in bin_tgz.*; do
- if [ $x -ge $N_PER_DISK ]; then
- x=0
- echo -n "Insert next disk, "
- echo -n "and press ENTER... "
- read reply
- mdel a:/\*
- fi
- mcopy $dist a:/
- x=`expr $x + 1`
- done
-
- (Or you might use tar instead).
-
- Once you have the files on DOS disks, you can proceed to the
- next step in the installation process, viz preparing your hard
- disk.
-
-To prepare for installing via a tape:
-
- To install FreeBSD from a tape, you need to be somehow
- to get the FreeBSD filesets you wish to install on
- your system on to the appropriate kind of tape,
- in tar format.
-
- If you're making the tape on a UN*X system, the easiest
- way to do so is:
-
- tar cvf <tape_device> <files>
-
- where "<tape_device>" is the name of the tape device
- that describes the tape drive you're using (either
- /dev/rst0 for SCSI tape, otherwise /dev/rwt0).
- If you can't figure it out, ask your system administrator.
- "<files>" are the names of the "<set>.tar.gz.xx" files
- which you want to be placed on the tape.
-
- If your tape drive is not a type recognzed by the
- kernel, then it may be necessary to set the tape density
- using either the st(1) command (for SCSI tape) or the
- mt(1) command. Both these programs are available from
- the tools directory of the FreeBSD archive site.
-
-To prepare for installing via an NFS partition:
-
- NOTE: this method of installation is recommended
- only for those already familiar with using
- the BSD network-manipulation commands and
- interfaces. If you aren't, this documentation
- should help, but is not intended to be
- all-encompassing.
-
- Place the FreeBSD software you wish to install into
- a directory on an NFS server, and make that directory
- mountable by the machine which you will be installing
- FreeBSD on. This will probably require modifying the
- /etc/exports file of the NFS server and resetting
- mountd, acts which will require superuser privileges.
- Make a note of the numeric IP address of the NFS server
- and make a note of the router closest to the the new
- FreeBSD machine if the NFS server is not on a network
- which is directly attached to the FreeBSD machine.
-
- Once you have done this, you can proceed to the next
- step in the installation process, preparing your hard disk.
-
-To prepare for installing via FTP:
-
- NOTE: this method of installation is recommended
- only for those already familiar with using
- the BSD network-manipulation commands and
- interfaces. If you aren't, this documentation
- should help, but is not intended to be
- all-encompassing.
-
- The preparations for this method of installation
- are easy: all you have to do is make sure that
- there's some FTP site from which you can retrieve
- the FreeBSD installation when it's time to do
- the install. You should know the numeric IP
- address of that site, and the numeric IP address of
- your nearest router if the new FreeBSD computer is
- not on the same net or subnet as the FTP site.
-
- Once you have done this, you can proceed to the next
- step in the installation process, preparing your hard disk.
-
-To prepare for installing via Kermit:
-
- The preparations for this method of installation
- require that the kermit program be put on the
- dos-floppy installation disk. This will be
- loaded as part of the minimum base installation.
- Kermit is available from tools directory of the
- FreeBSD FTP site. This is a FreeBSD binary and
- only executes under the FreeBSD operating system.
-
- Once you have done this, you can proceed to the next
- step in the installation process, preparing your hard disk.
-
-To upgrade:
-
- (The beta upgrade script is available on request from
- FreeBSD-questions@freefall.cdrom.com)
-
-Preparing your Hard Disk for FreeBSD Installation:
---------- ---- ---- ---- --- ------ ------------
-
-NOTE: If you wish to install FreeBSD on your whole drive, (i.e. you do
-not want DOS or any other operating system on your hard disk), you can
-skip this section, and go on to "Installing the FreeBSD System."
-
-Firstly, be sure you have a reliable backup of any data which you may
-want to keep; repartitioning your hard drive is an excellent way to
-destroy important data.
-
-WARNING: If you are using a disk controller which supports disk
-geometry translation, BE SURE TO USE THE SAME PARAMETERS FOR FreeBSD AS
-FOR DOS! If you do not, FreeBSD will not be able to properly coexist
-with DOS.
-
-Secondly, make sure your disk has at least 16 Mbytes free space (or
-80 Mbytes for the complete binary distribition).
-
-You are now set to install FreeBSD on your hard drive.
-
-Installing the FreeBSD System:
----------- --- ------ ------
-
-If DOS or OS/2 is already installed on the hard disk, installation should
-be easy. By default FreeBSD is installed after the last DOS or OS/2
-partition. Otherwise, you may need to specify your hard disk's geometry
-(i.e., number of cylinders, heads and sectors per track).
-
-For computing partition sizes, it might help to have a calculator handy.
-
-And it's finally time to install the system!
-
-The following is a walk-through of the steps necessary to get FreeBSD
-installed on your hard disk. If you wish to stop the installation, you
-may hit Control-C at any prompt and then type `halt'.
-
- Boot from the kcopy_ah or kcopy_bt floppy, depending on
- your hard disk controller type.
-
- When prompted to insert the filesystem floppy, remove the
- kcopy floppy from the drive and insert filesystem floppy
- and hit any key.
- N.B.: The filesystem floppy must not be write protected.
-
- [When booting, if no message prompt appears after a
- reasonable period of time, reboot and try it again. If
- this doesn't work, try disabling your CPU's internal and
- external caches, and then try to boot again. If there is
- still no message prompt, then you can't install FreeBSD
- on your hardware. If you were able to install 386bsd,
- this is definitely a bug in our software; please report
- it! Please include your system configuration, and any
- other relevant information in your bug report.]
-
- The boot sequence continues after the filesystem floppy
- has been inserted. A copyright notice is displayed along
- with a list of the hardware that FreeBSD recognizes as
- being in your machine. You might want to make a note of
- the disk values for cylinders, heads, sectors etc for
- later use.
-
- After a short while (approximately 30 to 60 seconds), you
- should see a welcome message and a prompt, asking if you
- wish to proceed with the installation.
-
- If you wish to proceed, enter "y" and then return.
-
- You will then be asked what type of disk drive you have.
- The valid options are listed on the screen (e.g., SCSI, ESDI).
-
- You will then be asked for a label name for your disk.
- This should be a short, one-word name for your disk,
- e.g., "cp3100-mine" for a Conner Peripherals "3100" disk.
- You needn't remember this name.
-
- Next, you will be prompted for the geometry information.
- The default values should be correct, in which case just
- hit ENTER to accept them. Otherwise enter the values
- that were displayed during the boot sequence as they are
- requested.
-
- The default size of the FreeBSD portion of the disk
- is the maximum available at the end of the disk (which may
- be the whole disk). Accept the default by hitting ENTER.
- Otherwise, enter an appropriate value using the information
- displayed.
-
- If you are not installing on the whole disk, you will be
- asked for the offset of the FreeBSD partition from the
- beginning of the disk. Again, hit ENTER to accept the
- default, or enter a cylinder offset from the beginning of
- the disk.
-
- You will then be asked for the size of your root partition,
- in cylinders. The suggested maximum size is 15 Mbytes
- which is used as a default. Accept this, or enter a
- suitable value (after converting to cylinders using the
- formula displayed).
-
- Next, you will be asked for the size of your swap partition
- - again, you must calculate this in cylinders. You should
- probably allocate around twice as much swap space as you
- have RAM memory. If you wish the system to save crash dumps
- when it panics, you will need at least as much swap as you
- have RAM.
-
- The install program will then ask you for information about
- the rest of the partitions you want on your disk. For the
- purposes of this document, you only want one more: /usr.
- Therefore, at the prompt, when in asks you to enter the size
- of the next partition, enter the number of cylinders remaining
- in the FreeBSD portion of the disk. When it asks you for the
- mount point for this partition, say "/usr".
-
- After the FreeBSD partition have been assigned, install checks
- the disk for an MS-DOS partition. If one exists, you are prompted
- whether to make this accessible from FreeBSD (i.e., for reading
- and writing). And if you choose to make the DOS partition
- accessible, you are prompted for what directory it should
- be mounted on. "/dos" is used by default. With this
- choice, you could copy the contents of the DOS root
- directory (i.e., C:\), for instance, with the Unix command:
-
- # cp /dos/* .
-
- If have you a DOS partition and you don't want it visible
- from FreeBSD, just respond with "n" when asked whether to
- make it accessible.
-
- YOU ARE NOW AT THE POINT OF NO RETURN.
-
- If you confirm that you want to install FreeBSD, your hard
- drive will be modified, and perhaps it contents scrambled at
- the whim of the install program. This is especially likely
- if you gave the install program incorrect information.
- Enter "no" at the prompt to get the option of redoing the
- configuration, using your previous choices as defaults.
-
- If you are sure you want to proceed, enter "yes" at the prompt.
-
- The install program now makes the filesystems you specified.
- If all goes well, there should be no errors in this section
- of the installation. If there are, restart from the the
- beginning of the installation process.
-
- After the installation program prompts you to see if you'd
- like to be told about all of the files it's going to copy
- to your hard drive, it will spend a few minutes copying these
- files and then will print out an informative message and
- place you at a "#" prompt.
-
- Read the message and note which partition (e.g., sd0a or wd0a)
- you need to copy a kernel to. Reboot the machine off the
- kcopy_xx.flp disk, but this time at the prompt asking
- you to insert a file system floppy, do _not_ replace the
- floppy, just press <enter>.
-
- At the "kc>" prompt, enter "copy" to prepare to copy the
- kernel on the floppy to your hard disk.
-
- At the next "kc>" prompt, enter the disk partition to which
- you want to copy the kernel. (e.g., sd0a or wd0a).
-
- It will work for a minute or two, then present you with
- another "#" prompt. Follow the instructions given, (i.e.,
- halt the system) and reboot from the hard disk. You will
- probably have to do a hardware reset or else your ethernet
- card might not be recognised at reboot (e.g., if you have a
- WD8003EP card).
-
- When the machine boots, a three-line banner should appear at
- the top of the screen. In a few seconds, a series of
- messages will appear, describing the hardware in your machine.
- Once again, this stage can take up to two minutes, so DO NOT
- PANIC!
-
- You will be asked to insert the cpio.flp into a floppy
- drive, and enter that drive's number. "0" corresponds to
- DOS's "A:" drive, "1" corresponds to DOS's "B:" drive.
-
- After you enter the number it will ask you if you'd like to
- watch its progress, and after you answer this question it
- will begin installing still more files on your hard disk.
- This should take no more than 3 minutes.
-
- You are given the option to load the dos-floppy disk.
- In particular, if you want to use kermit for downloading
- the distribution, the dos-floppy should have the kermit
- binary. Or if you are using SCSI tape, the dos-floppy should
- contain the st command.
-
- To load the dos-floppy, remove the cpio.flp from the
- drive, insert the dos-floppy and enter a "yes" response
- at the prompt. Otherwise, enter "no" at the prompt.
-
- After the dos-floppy has been loaded, you are given (more)
- instructions, (e.g., to halt the system) and you should
- reboot the machine again, from the hard drive and probably
- with a hardware reset to kick your ethernet card back into
- life.
-
- CONGRATULATIONS: You now have the minimum base of FreeBSD
- files on your hard disk! Now you get to install the
- distribution file sets. Remember that, at minimum, you must
- install the bin_tgz.xx file set (see below for instructions).
-
- After the machine is done booting, you will be presented
- with a screenful of information about what to do next.
-
- What you do from this point on depends on which media you're
- using to install FreeBSD. Follow the appropriate
- instructions, given below.
-
- To install from MS-DOS hard disk partition, floppy or tape:
-
- The first thing you should do is to choose a temporary
- directory where the distribution files can be stored.
- To do this, use the command "set_tmp_dir" and enter
- your choice. The default is /usr/distrib.
-
- After you have chosen a temporary directory,
- you should issue the appropriate load command:
-
- load_dos - for loading from a MS-DOS hard disk
- partition, or from floppies,
-
- load_qic_tape - for loading from QIC-02 tape, or
-
- load_scsi_tape - for you're loading from the first
- SCSI tape drive in the system.
-
- If loading from tape, it may be necessary to first
- set the default density using the mt or st command.
- The low-density device (/dev/rst0 or /dev/rmt0)
- is used by the load_xx_tape command, so to prepare
- a SCSI device for reading QIC-150 tape, you might use:
-
- # st -f /dev/nrst0 rewind
- # st -f /dev/nrst0 low_dnsty 16
- # load_scsi_tape
-
- If loading from floppy or hard disk, the load_dos
- command prompts for information, such as to which
- floppy drive or hard disk directory to load from.
- Additional options are available, e.g., for listing
- and, if loading from hard disk, changing source
- directories.
-
- Go to the directory which contains the first
- distribution set you wish to install. This is
- either the directory you specified above, if using
- load_dos, or possibly a subdirectory of that
- directory, if you loaded from tape.
-
- When there, run "set_tmp_dir" again, and choose
- the default temporary directory, by hitting
- return at the prompt.
-
- Run the "extract" command, giving it as its sole
- argument the name of the distribution set you
- wish to extract. For example, to extract the binary
- distribution, use the command:
-
- extract bin
-
- and to extract the source distribution:
-
- extract src
-
- After the extraction is complete, go to the location
- of the next set you want to extract, "set_tmp_dir"
- again, and once again issue the appropriate
- extract command. Continue this process until
- you've finished installing all of the sets which you
- desire to have on your hard disk.
-
- After each set is finished, if you know that you
- are running low on space you can remove the
- distribution files for that set by saying:
-
- rm <set>*
-
- For example, if you wish to remove the distribution
- files for the binarydist set, after the "extract bin"
- command has completed, issue the command:
-
- rm bin*
-
- Once you have extracted all sets and are at the "#" prompt
- again, proceed to the section "Configuring Your System,"
- below.
-
- To install via FTP or NFS:
-
- First you must decide on a temporary directory to hold
- the <set>.xx files. The directory /usr/distrib
- is suggested. You should cd to it, if necessary do
- a mkdir first. Use set_tmp_dir to identify this
- directory to the install process.
-
- Configure the appropriate ethernet interface (e.g. ed0,
- ne0, etc.) up, with a command like:
-
- ifconfig <ifname> <ipaddr> [netmask <netmask>]
-
- where <ifname> is the interface name (e.g. ed0, etc.),
- and <ipaddr> is the numeric IP address of the interface.
- If the interface has a special netmask, supply
- the word "netmask" and that netmask at the end of the
- command line. For instance, without a special netmask:
-
- ifconfig ed0 129.133.10.10
-
- or with a special netmask
-
- ifconfig ed0 128.32.240.167 netmask 0xffffff00
-
- or the equivalent
-
- ifconfig ed0 128.32.240.167 netmask 255.255.255.0
-
- If you are using the AUI connector on a 3C503 card, you
- must also set the LLC0 flag (the default is to use the BNC
- connector):
-
- ifconfig ed0 130.252.23.86 llc0
-
- If the NFS server or FTP server is not on a directly-
- connected network, you should set up a route to it
- with the command:
-
- route add default <gate_ipaddr>
-
- where <gate_ipaddr> is your gateway's numeric IP address.
-
- If you are NFS-mounting the distribution sets,
- mount them on the temporary directory with the command:
-
- mount -t nfs <serv_ipaddr>:<dist_dir> <tmp_dir>
-
- where <serv_ipaddr> is the server's numeric IP address,
- <dist_dir> is the path to the distribution files on
- the server, and <tmp_dir> is the name of the local
- temporary directory (e.g., /usr/distrib). Proceed as if
- you had loaded the files from tape, "cd"ing to the
- appropriate directories and running "set_tmp_dir" and
- "extract" as appropriate.
-
- If you are retrieving the distribution sets using ftp,
- cd into the temp directory, and execute the command:
-
- ftp <serv_ipaddr>
-
- where <serv_ipaddr> is the server's numeric IP address.
- Get the files with FTP, taking care to use binary mode
- to transfer all files. A simple set of commands is
-
- ftp <serv_ipaddr>
- user ftp
- passwd <user-id>@
- hash
- binary
- prompt
- cd <where/the/binarydist/files/are>
- mget *
- cd <where/the/sourcedist/files/are>
- mget *
- quit
-
- Once you have all of the files for the distribution sets
- that you wish to install, you can proceed using the
- instructions above as if you had installed the files
- from a floppy.
-
- To install via Kermit:
-
- First you must decide on a temporary directory to hold
- the <set>.xx files. The directory /usr/distrib
- is suggested. You should cd to it, if necessary do
- a mkdir first. Use set_tmp_dir to identify this
- directory to the install process.
-
- Invoke kermit and dial the remote kermit server.
- A typical session might be:
- # stty -f /dev/sio01 clocal
- # kermit
- C-Kermit> set file type binary
- C-Kermit> set line /dev/sio01
- C-Kermit> set baud 9600
- C-Kermit> set receive packet 740
- C-Kermit> set window 4
- C-Kermit> set block 2
- C-Kermit> connect
- Connecting to /dev/sio01, speed 9600.
- The escape character is Ctrl-\ (ASCII 28, FS)
- Type the escape character followed by C to get back,
- or followed by ? to see other options.
- atdt 1234567 <-- dial the remote
- Connect 9600
- login: mylogin <-- login to the remote
- [...]
- remote$ kermit -ix <-- remote kermit as binary server
- [...]
- ^\C <-- return to local kermit
- C-Kermit> get bin_tgz* <-- request files from remote
- [...] (wait long for transfer to complete)
- C-Kermit> finish <-- terminate remote server
- C-Kermit> connect
- C-Kermit> exit <-- exit remote kermit
- remote$ exit <-- exit remote host
- ^\C <-- return to local kermit
- C-Kermit> exit <-- exit local kermit
-
- At this point the binary distribution should be
- downloaded to the FreeBSD system. Run the "extract"
- command, giving it as its sole argument the name
- of the distribution set you wish to extract. For
- example, to extract the binary distribution, use
- the command:
-
- extract bin
-
- and to extract the source distribution:
-
- extract src
-
- After the extraction is complete, go to the location
- of the next set you want to extract, "set_tmp_dir"
- again, and once again issue the appropriate
- extract command. Continue this process until
- you've finished installing all of the sets which you
- desire to have on your hard disk.
-
- After each set is finished, if you know that you
- are running low on space you can remove the
- distribution files for that set by saying:
-
- rm <set>*
-
- For example, if you wish to remove the distribution
- files for the binarydist set, after the "extract bin"
- command has completed, issue the command:
-
- rm bin*
-
- Once you have extracted all sets and are at the "#" prompt
- again, proceed to the section "Configuring Your System,"
- below.
-
-
-Further Tips on Installing FreeBSD
-------- ---- -- ---------- -------
-
- You might wish to install the bindist first, get that
- working, and then at a later point in time have a go at
- installing the sourcedist.
-
- When you are ready to install the sourcedist at some time
- in the future, get into multi-user mode (i.e., the normal
- means of running FreeBSD) and issue this command:
-
- shutdown now
-
- This will cause the system to go into single-user mode. To
- get the install commands active again issue this command:
-
- . /magic
-
- If your disk has several operating systems, you may want
- to install a boot manager such as Thomas Wolfram's os-bs
- for selecting which system to boot. os-bs135.exe and other
- boot managers are available from the tools directory of
- the FreeBSD FTP site. os-bs works well with DOS, OS/2,
- FreeBSD and other systems, however, it cannot currently
- be used to boot FreeBSD from a second hard disk. Another
- boot manager, such as boot-easy should be used.
-
- To install, for instance, os-bs, boot the system with
- MS-DOS and insert the dos-floppy containing os-bs135.exe
- in floppy drive A:. Then enter the DOS commands:
- > A:
- > os-bs135
- > cd os-bs
- > os-bs
- A menu should now appear on the screen. Use the cursor keys
- to highlight the install option, hit ENTER, and follow the
- instructions from there.
-
- For more information about the ob-bs program, including its
- capabilities and limitations, see the file `readme.1st' in the
- os-bs directory.
-
- If your disk has several operating systems and you choose
- not to install os-bs, then fdisk can be used to change
- the boot system. This is done by making the primary
- partition for the boot system active. FreeBSD has an
- fdisk command that can be used for this purpose as well.
-
-
-Configuring Your System:
------------ ---- ------
-
-Once you have finished extracting all of the distribution sets that you
-want on your hard drive and are back at the "#" prompt, you are ready
-to configure your system.
-
-The configuration utility expects that you have installed the base
-system. If you have not, you will not be able to run it successfully
-(nor will you have a functional system regardless of configuration).
-
-To configure the newly installed operating system, run the command
-"configure".
-
-Configure will ask for the machine's hostname, domain name, and other
-network configuration information. You should check that configure has
-set up the following files correctly:
-
- /etc/netstart
- /etc/myname
-
-Once you have supplied configure all that it requests, your machine
-will be configured well enough that when you reboot it it will be a
-completely functional FreeBSD system. It is not completely configured,
-however; you should adjust the /etc/sendmail.cf file as necessary to
-suit your site and/or disable sendmail in /etc/rc and you should look
-in /etc/netstart to make sure the flags are defined correctly for your
-site. You might wish to set up several other tcp/ip files, such as
-
- /etc/resolv.conf
- /etc/networks
-
-Once you are done with configuration, reboot with the "reboot" command.
-
-When it boots off of the hard drive, you will have a complete FreeBSD
-system! CONGRATULATIONS! (You really deserve them!!!)
-
-
-Administrivia:
--------------
-
-Registration? What's that?
-
-If you've got something to say, do so! We'd like your input.
-
-Please send random comments to:
-
- FreeBSD-questions@freefall.cdrom.com
-
-Please send bug reports, and that sort of material to:
-
- FreeBSD-bugs@freefall.cdrom.com
-
-If you'd like to help with this effort, and have an idea as to how
-you could be useful, send mail to:
-
- FreeBSD-hackers@freefall.cdrom.com
-
-THANKS FOR USING THIS; that's what makes it all worthwhile.
-
-[a favor: Please avoid mailing huge documents or files to these mailing lists,
- as they will end up in our personal mail spools. We will be
- happy to make other arrangements]
-
-This is $Id: install_notes,v 1.13.2.2 1994/05/05 09:08:55 rgrimes Exp $
diff --git a/etc/group b/etc/group
index 5c38d3667727..2bd4805a19fa 100644
--- a/etc/group
+++ b/etc/group
@@ -11,6 +11,7 @@ games:*:13:
staff:*:20:root
guest:*:31:root
nobody:*:39:
+uucp:*:66:
ingres:*:74:ingres
dialer:*:117:
nogroup:*:32766:
diff --git a/etc/hosts b/etc/hosts
index 08645ce9b767..6528805a96f4 100644
--- a/etc/hosts
+++ b/etc/hosts
@@ -1,4 +1,4 @@
-# $Id: hosts,v 1.2 1993/11/11 22:32:36 wollman Exp $
+# $Id: hosts,v 1.4 1994/06/24 23:50:16 wollman Exp $
#
# Host Database
# This file should contain the addresses and aliases
@@ -10,10 +10,18 @@
127.0.0.1 localhost localhost.my.domain
#
# Imaginary network.
-#0.2 myname.my.domain myname
-#0.3 myfriend.my.domain myfriend
+#10.0.0.2 myname.my.domain myname
+#10.0.0.3 myfriend.my.domain myfriend
#
-# NB: 0 is not a valid network number. PLEASE PLEASE PLEASE do not try
+# According to RFC 1597, you can use the following IP networks for
+# private nets which will never be connected to the Internet:
+#
+# 10.0.0.0 - 10.255.255.255
+# 172.16.0.0 - 172.31.255.255
+# 192.168.0.0 - 192.168.255.255
+#
+# In case you want to be able to connect to the Internet, you need
+# real official assigned numbers. PLEASE PLEASE PLEASE do not try
# to invent your own network numbers but instead get one from your
# network provider (if any) or from the Internet Registry (ftp to
# rs.internic.net, directory `/templates').
diff --git a/etc/inetd.conf b/etc/inetd.conf
index 12bad1601099..127fe26017c6 100644
--- a/etc/inetd.conf
+++ b/etc/inetd.conf
@@ -30,12 +30,12 @@ klogin stream tcp nowait root /usr/libexec/rlogind rlogind -k
eklogin stream tcp nowait root /usr/libexec/rlogind rlogind -k -x
kshell stream tcp nowait root /usr/libexec/rshd rshd -k
# Services run ONLY on the Kerberos server
+# Neither of these work in FreeBSD 1.x.
#krbupdate stream tcp nowait root /usr/libexec/registerd registerd
#kpasswd stream tcp nowait root /usr/libexec/kpasswdd kpasswdd
#
# RPC based services
# You MUST have portmapper running to use these!
-#mountd/1 dgram rpc/udp wait root /sbin/mountd mountd
#rstatd/1-3 dgram rpc/udp wait root /usr/libexec/rpc.rstatd rpc.rstatd
#rusersd/1-2 dgram rpc/udp wait root /usr/libexec/rpc.rusersd rpc.rusersd
#walld/1 dgram rpc/udp wait root /usr/libexec/rpc.rwalld rpc.rwalld
diff --git a/etc/kerberosIV/README b/etc/kerberosIV/README
new file mode 100644
index 000000000000..1482e99cd1df
--- /dev/null
+++ b/etc/kerberosIV/README
@@ -0,0 +1,35 @@
+# @(#)README 5.1 (Berkeley) 6/30/90
+
+Notes about the contents of the /etc/kerberosIV directory:
+
+The file master_key contains a copy of the master key under which the
+entire Kerberos database is encrypted. Disclosing this key would be bad
+news. The reason it is stored in the filesystem is because the following
+programs need to inspect or modify the kereros database, and so the key
+must be available for them, (or else it would have to be typed in by
+hand):
+ - kerberos (the server itself)
+ - registerd (for new user registration)
+ - kpasswdd (for changing passwords)
+
+The srvtab file contains the encryption keys for each service on the local
+host. Any host offering network services would have a key here, although
+many such files can be used.
+
+The principal.* files comprise the Kerberos database itself, and contain
+keys for all principles, and should not be world-readable.
+
+The kerberos.conf file contains the configuration for this machine:
+ - which realm I'm in
+ - which servers I should talk to for this realm
+
+The kerberos.realms file contains the name of Kerberos servers for
+various (sub)domains.
+
+Kerberos log information it placed in /var/log/kerberos.log
+(see rc.local to change it)
+
+The register_keys directory contains a set of files (all of which begin
+with "."), each of which contains a des key used for registering new users
+with the system. It is used only by the "registerd" program, and only on
+a Kerberos server host.
diff --git a/etc/kerberosIV/krb.conf b/etc/kerberosIV/krb.conf
new file mode 100644
index 000000000000..11ac1ac78b01
--- /dev/null
+++ b/etc/kerberosIV/krb.conf
@@ -0,0 +1,9 @@
+CS.BERKELEY.EDU
+CS.BERKELEY.EDU okeeffe.berkeley.edu
+ATHENA.MIT.EDU kerberos.mit.edu
+ATHENA.MIT.EDU kerberos-1.mit.edu
+ATHENA.MIT.EDU kerberos-2.mit.edu
+ATHENA.MIT.EDU kerberos-3.mit.edu
+LCS.MIT.EDU kerberos.lcs.mit.edu
+TELECOM.MIT.EDU bitsy.mit.edu
+ARC.NASA.GOV trident.arc.nasa.gov
diff --git a/etc/kerberosIV/krb.realms b/etc/kerberosIV/krb.realms
new file mode 100644
index 000000000000..1f1bec58ae95
--- /dev/null
+++ b/etc/kerberosIV/krb.realms
@@ -0,0 +1,3 @@
+.berkeley.edu CS.BERKELEY.EDU
+.MIT.EDU ATHENA.MIT.EDU
+.mit.edu ATHENA.MIT.EDU
diff --git a/etc/login.access b/etc/login.access
new file mode 100644
index 000000000000..5cf54541463d
--- /dev/null
+++ b/etc/login.access
@@ -0,0 +1,44 @@
+# Login access control table.
+#
+# When someone logs in, the table is scanned for the first entry that
+# matches the (user, host) combination, or, in case of non-networked
+# logins, the first entry that matches the (user, tty) combination. The
+# permissions field of that table entry determines whether the login will
+# be accepted or refused.
+#
+# Format of the login access control table is three fields separated by a
+# ":" character:
+#
+# permission : users : origins
+#
+# The first field should be a "+" (access granted) or "-" (access denied)
+# character. The second field should be a list of one or more login names,
+# group names, or ALL (always matches). The third field should be a list
+# of one or more tty names (for non-networked logins), host names, domain
+# names (begin with "."), host addresses, internet network numbers (end
+# with "."), ALL (always matches) or LOCAL (matches any string that does
+# not contain a "." character). If you run NIS you can use @netgroupname
+# in host or user patterns.
+#
+# The EXCEPT operator makes it possible to write very compact rules.
+#
+# The group file is searched only when a name does not match that of the
+# logged-in user. Only groups are matched in which users are explicitly
+# listed: the program does not look at a user's primary group id value.
+#
+##############################################################################
+#
+# Disallow console logins to all but a few accounts.
+#
+#-:ALL EXCEPT wheel shutdown sync:console
+#
+# Disallow non-local logins to privileged accounts (group wheel).
+#
+#-:wheel:ALL EXCEPT LOCAL .win.tue.nl
+#
+# Some accounts are not allowed to login from anywhere:
+#
+#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL
+#
+# All other accounts are allowed to login from anywhere.
+#
diff --git a/etc/make.conf b/etc/make.conf
new file mode 100644
index 000000000000..da2c51abf17d
--- /dev/null
+++ b/etc/make.conf
@@ -0,0 +1,71 @@
+# $Id: make.conf,v 1.8 1994/06/16 17:13:53 ache Exp $
+#
+# This file, if present, will be read by make (see /usr/share/mk/sys.mk)
+# It allows you to override macro definitions to make, without changing
+# in your source tree, or anything the source tree installs.
+#
+# You have to find the things you can put here in the Makefiles and
+# documentation of the source tree.
+#
+# This file must have a syntax as a Makefile.
+#
+# One, and probably the most common, use could be:
+#
+#CFLAGS= -O -m486 -pipe
+# A lot of people report that -O2 works fine, but there are known
+# bugs in gcc. -pipe will almost always speed up compilation.
+#
+#
+# Another useful entry could be:
+#
+#NOPROFILE= no_way
+# Avoid compiling profiled libraries
+#
+#
+# To compile and install the Sun libm instead of the default use:
+#
+#WANT_MSUN= yes
+#
+#
+# If you have a FPU (i387, i486DX, Pentium), you can make
+# the Sun libm use the FPU:
+#
+#HAVE_FPU= yes
+#
+#
+# If you do not want unformatted manual pages to be compressed
+# when they are installed:
+#
+#NOMANCOMPRESS= no_way
+#
+#
+# Default format for system documentation, depends on your printer.
+# Set this to "ascii" for simple printers or screen
+#
+#PRINTER= ps
+#
+#
+# How many times to check if a key has been pressed before giving up and
+# booting the default kernel. 0 actually means check once, but saves the
+# loop overhead.
+#
+#BOOTWAIT=0
+#BOOTWAIT=640000
+#
+#
+# Allow 'cc' to generate all FPU codes. Do not use this if you intend to
+# generate code to run on machines with broken FPU emulator. Beware, this
+# is a compile-time static option to 'cc'.
+#
+#CCFPU= yes
+#
+#
+# If you use national 8-bit charset and your charset description is
+# installed into /usr/share/locale (see setlocale(3)), you can
+# automatically setup all ctype-oriented application to understand
+# your charset properly by two things:
+# 1) uncomment following option
+# 2) set environment variable "LANG" to your charset name
+#
+#STARTUP_LOCALE= yes
+#
diff --git a/etc/master.passwd b/etc/master.passwd
index f4c94367502c..6ebb2fe02b3e 100644
--- a/etc/master.passwd
+++ b/etc/master.passwd
@@ -5,7 +5,7 @@ operator:*:2:20::0:0:System &:/usr/guest/operator:/bin/csh
bin:*:3:7::0:0:Binaries Commands and Source,,,:/:/nonexistent
games:*:7:13::0:0:Games pseudo-user:/usr/games:
man:*:9:9::0:0:Mister Man Pages:/usr/share/man:
-uucp:*:66:1::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
+uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
ingres:*:267:74::0:0:& Group:/usr/ingres:/bin/csh
falcon:*:32766:31::0:0:Prof. Steven &:/usr/games:/usr/games/wargames
nobody:*:32767:9999::0:0:Unprivileged user:/nonexistent:/nonexistent
diff --git a/etc/minfree b/etc/minfree
new file mode 100644
index 000000000000..c873496a2275
--- /dev/null
+++ b/etc/minfree
@@ -0,0 +1 @@
+2048
diff --git a/etc/mtree/BSD.local.dist b/etc/mtree/BSD.local.dist
index 9ff8a52c4b2d..cec50217217d 100644
--- a/etc/mtree/BSD.local.dist
+++ b/etc/mtree/BSD.local.dist
@@ -1,4 +1,4 @@
-# $Id: BSD.local.dist,v 1.4 1994/02/22 05:43:07 rgrimes Exp $
+# $Id: BSD.local.dist,v 1.5 1994/05/20 22:50:36 jkh Exp $
#
/set type=file uname=bin gname=bin mode=0755
@@ -15,23 +15,23 @@ lib type=dir uname=bin gname=bin mode=0755
..
man type=dir uname=bin gname=bin mode=0755
- cat1 type=dir uname=bin gname=bin mode=0755
+ cat1 type=dir uname=man gname=bin mode=0755
..
- cat2 type=dir uname=bin gname=bin mode=0755
+ cat2 type=dir uname=man gname=bin mode=0755
..
- cat3 type=dir uname=bin gname=bin mode=0755
+ cat3 type=dir uname=man gname=bin mode=0755
..
- cat4 type=dir uname=bin gname=bin mode=0755
+ cat4 type=dir uname=man gname=bin mode=0755
..
- cat5 type=dir uname=bin gname=bin mode=0755
+ cat5 type=dir uname=man gname=bin mode=0755
..
- cat6 type=dir uname=bin gname=bin mode=0755
+ cat6 type=dir uname=man gname=bin mode=0755
..
- cat7 type=dir uname=bin gname=bin mode=0755
+ cat7 type=dir uname=man gname=bin mode=0755
..
- cat8 type=dir uname=bin gname=bin mode=0755
+ cat8 type=dir uname=man gname=bin mode=0755
..
- catl type=dir uname=bin gname=bin mode=0755
+ catl type=dir uname=man gname=bin mode=0755
..
man1 type=dir uname=bin gname=bin mode=0755
..
diff --git a/etc/mtree/BSD.root.dist b/etc/mtree/BSD.root.dist
index 5d767c825b5a..250d39f56478 100644
--- a/etc/mtree/BSD.root.dist
+++ b/etc/mtree/BSD.root.dist
@@ -1,10 +1,10 @@
-# $Id: BSD.root.dist,v 1.10 1994/02/17 03:52:28 rgrimes Exp $
+# $Id: BSD.root.dist,v 1.13 1994/06/12 16:20:36 csgr Exp $
#
# top-level files are owned by root.wheel
# (else too easy to get root by compromising these)
-/set type=file uname=root gname=wheel mode=0775
+/set type=file uname=root gname=wheel mode=0755
sys type=link size=12 link=usr/src/sys
@@ -20,7 +20,9 @@ etc type=dir
..
namedb type=dir
..
- uucp type=dir uname=root gname=wheel mode=0755
+ uucp type=dir uname=uucp gname=uucp mode=0770
+ ..
+ kerberosIV type=dir
..
..
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index 98ec625552d7..85e39bb09064 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -1,4 +1,4 @@
-# $Id: BSD.usr.dist,v 1.9.2.1 1994/04/18 03:19:42 rgrimes Exp $
+# $Id: BSD.usr.dist,v 1.15 1994/06/01 02:39:37 ache Exp $
#
/set type=file uname=bin gname=bin mode=0755
@@ -37,7 +37,7 @@ lib type=dir uname=bin gname=bin mode=0755
libexec type=dir uname=bin gname=bin mode=0755
lpr type=dir uname=bin gname=bin mode=0755
..
- uucp type=dir uname=bin gname=bin mode=0755
+ uucp type=dir uname=bin gname=bin mode=0755
..
..
diff --git a/etc/mtree/BSD.var.dist b/etc/mtree/BSD.var.dist
index 1646c9da0716..72b1a69a078c 100644
--- a/etc/mtree/BSD.var.dist
+++ b/etc/mtree/BSD.var.dist
@@ -1,4 +1,4 @@
-# $Id: BSD.var.dist,v 1.9 1994/02/15 10:38:50 rgrimes Exp $
+# $Id: BSD.var.dist,v 1.15 1994/05/31 07:49:53 ache Exp $
#
/set type=dir uname=bin gname=bin mode=0755
@@ -36,7 +36,7 @@ rwho
..
spool
/set type=dir uname=bin gname=daemon mode=0755
- lock uname=uucp
+ lock uname=uucp gname=dialer mode=0775
..
lpd
..
@@ -44,7 +44,7 @@ spool
..
output
..
- /set type=dir uname=uucp gname=daemon mode=0755
+ /set type=dir uname=uucp gname=uucp mode=0775
uucp
.Preserve
..
@@ -57,6 +57,7 @@ spool
.Xqtdir
..
..
+ /set type=dir uname=uucp gname=uucp mode=0777
uucppublic
..
..
diff --git a/etc/netstart b/etc/netstart
index a078218a76ba..a32e3f5e1443 100644
--- a/etc/netstart
+++ b/etc/netstart
@@ -1,6 +1,6 @@
#!/bin/sh -
#
-# $Id: netstart,v 1.8.2.3 1994/05/04 08:57:11 rgrimes Exp $
+# $Id: netstart,v 1.12 1994/06/17 19:29:05 jkh Exp $
# From: @(#)netstart 5.9 (Berkeley) 3/30/91
routedflags=-q
@@ -32,6 +32,9 @@ fi
if [ -e /etc/hostname.is0 ]; then
ifconfig is0 `cat /etc/hostname.is0`
fi
+if [ -e /etc/hostname.ze0 ]; then
+ ifconfig ze0 `cat /etc/hostname.ze0`
+fi
# set the address for the loopback interface
ifconfig lo0 inet localhost
diff --git a/etc/rc b/etc/rc
index ee1b96427d73..84b3e41fc595 100644
--- a/etc/rc
+++ b/etc/rc
@@ -1,5 +1,5 @@
#!/bin/sh
-# $Id: rc,v 1.19.2.2 1994/04/18 04:14:19 rgrimes Exp $
+# $Id: rc,v 1.27 1994/06/06 17:45:37 phk Exp $
# From: @(#)rc 5.27 (Berkeley) 6/5/91
# System startup script run by init on autoboot
@@ -59,6 +59,12 @@ trap "echo 'Reboot interrupted'; exit 1" 3
swapon -a
+# Check for diskless boot, and remount the root RW.
+a=`mount`
+if [ 0 != `expr "$a" : '^[^/]*:/.* on /'` ] ; then
+ mount -u -o rw /
+fi
+
umount -a >/dev/null 2>&1
mount -a -t nonfs
rm -f /fastboot # XXX (root now writeable)
@@ -69,15 +75,21 @@ rm -f /fastboot # XXX (root now writeable)
# the machine runs UTC CMOS clock). See adjkerntz(8) for details.
adjkerntz -i
+# configure serial devices
+if [ -f /etc/rc.serial ]
+then
+ sh /etc/rc.serial
+fi
+
# set hostname, turn on network
echo 'starting network'
. /etc/netstart
# clean up left-over files
rm -f /etc/nologin
-rm -f /var/spool/uucp/LCK.*
-rm -f /var/spool/uucp/STST/*
-# don't add .[a-z]* to rm, because of .adjkerntz file
+rm -f /var/spool/lock/*
+rm -f /var/spool/uucp/.Temp/*
+# don't add .[a-z]* to rm, because of .adjkerntz file name
(cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; })
echo -n 'starting system logger'
@@ -156,7 +168,7 @@ fi
# If $routedflags == NO, routed isn't run.
if [ X${gated} = X"YES" -a -r /etc/gated.conf ]; then
echo -n ' gated'; gated $gatedflags
-elif [ X${routedflags} != X"NO" ]; then
+elif [ X"${routedflags}" != X"NO" ]; then
echo -n ' routed'; routed $routedflags
fi
@@ -207,6 +219,10 @@ echo '.'
mount -a -t nfs >/dev/null 2>&1 & # XXX shouldn't need background
+# if [ -x /usr/libexec/xtend ]; then
+# echo -n ' xtend'; /usr/libexec/xtend
+# fi
+
# Make shared lib searching a little faster. Leave /usr/lib first if you
# add your own entries or you may come to grief.
if [ -x /sbin/ldconfig ]; then
diff --git a/etc/rc.local b/etc/rc.local
index dbbd909a5b91..34e9ca28536c 100644
--- a/etc/rc.local
+++ b/etc/rc.local
@@ -10,7 +10,7 @@ uname -a > $T
echo "" >> $T
sed '1,/^$/d' < /etc/motd >> $T
cp $T /etc/motd
-chmod 666 /etc/motd
+chmod 644 /etc/motd
rm -f $T
echo -n 'starting local daemons:'
diff --git a/etc/rc.serial b/etc/rc.serial
new file mode 100644
index 000000000000..7f042e84e666
--- /dev/null
+++ b/etc/rc.serial
@@ -0,0 +1,91 @@
+# Change some defauls for serial devices.
+# Standard defaults are:
+# dtrwait 300
+# initial cflag from <sys/ttydefaults.h> = cread cs8 hupcl
+# initial iflag, lflag and oflag all 0
+# speed 9600
+# special chars from <sys/ttydefaults.h>
+# nothing locked
+# except for serial consoles the initial iflag, lflag and oflag are from
+# <sys/ttydefaults.h> and clocal is locked on.
+
+default() {
+ # Reset everything changed by the other functions to initial defaults.
+ for i in $*
+ do
+ comcontrol /dev/ttyd$i dtrwait 300
+ stty </dev/ttyid$i -clocal crtscts hupcl 9600 reprint ^R
+ stty </dev/ttyld$i -clocal -crtscts -hupcl 0
+ stty </dev/cuai0$i -clocal crtscts hupcl 9600 reprint ^R
+ stty </dev/cual0$i -clocal -crtscts -hupcl 0
+ done
+}
+
+maybe() {
+ # Special settings.
+ for i in $*
+ do
+ # Don't use ^R; it breaks bash's ^R when typed ahead.
+ stty </dev/ttyid$i reprint undef
+ stty </dev/cuai0$i reprint undef
+ # Lock clocal off on dialin device for security.
+ stty </dev/ttyld$i clocal
+ # Lock the speeds to use old binaries that don't support them.
+ # Any legal speed works to lock the initial speed.
+ stty </dev/ttyld$i 300
+ stty </dev/cual0$i 300
+ done
+}
+
+modem() {
+ # Modem that supports CTS and perhaps RTS handshaking.
+ for i in $*
+ do
+ comcontrol /dev/ttyd$i dtrwait 100 # may depend on modem
+ # Lock crtscts on.
+ # Speed reasonable for V42bis.
+ stty </dev/ttyid$i crtscts 57600
+ stty </dev/ttyld$i crtscts
+ stty </dev/cuai0$i crtscts 57600
+ stty </dev/cual0$i crtscts
+ done
+}
+
+mouse() {
+ # Mouse on either callin or callout port.
+ for i in $*
+ do
+ # Lock clocal on, hupcl off.
+ # Standard speed for Microsoft mouse.
+ stty </dev/ttyid$i clocal -hupcl 1200
+ stty </dev/ttyld$i clocal hupcl
+ stty </dev/cuai0$i clocal -hupcl 1200
+ stty </dev/cual0$i clocal hupcl
+ done
+}
+
+terminal() {
+ # Terminal that supports CTS and perhaps RTS handshaking
+ # with the cable or terminal arranged so that DCD is on
+ # at least while the terminal is on.
+ # Also works for bidirectional communications to another pc
+ # provided at most one side runs getty.
+ # Same as modem() except we want a faster speed and no dtrwait.
+ modem $*
+ for i in $*
+ do
+ comcontrol /dev/ttyd$i dtrwait 0
+ stty </dev/ttyid$i 115200
+ stty </dev/cuai0$i 115200
+ done
+}
+
+# Don't use anything from this file unless you have some buggy programs
+# that require it.
+#
+# Edit the functions and the examples to suit your system.
+#
+# maybe 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v
+# mouse 2
+# modem 1
+# terminal 0
diff --git a/etc/root/dot.login b/etc/root/dot.login
index def29c181a80..dee76bb3d30a 100644
--- a/etc/root/dot.login
+++ b/etc/root/dot.login
@@ -1,6 +1,6 @@
-# $Id: dot.login,v 1.4 1994/02/21 20:36:02 rgrimes Exp $
+# $Id: dot.login,v 1.5 1994/06/15 22:58:47 jkh Exp $
#
tset -Q \?$TERM
-stty crt erase ^\?
+stty crt erase ^h
umask 2
echo "Don't login as root, use su"
diff --git a/etc/root/dot.profile b/etc/root/dot.profile
index a817750a3df0..4e80d030dfda 100644
--- a/etc/root/dot.profile
+++ b/etc/root/dot.profile
@@ -1,8 +1,8 @@
-# $Id: dot.profile,v 1.4 1994/02/21 20:36:03 rgrimes Exp $
+# $Id: dot.profile,v 1.5 1994/06/15 22:58:49 jkh Exp $
#
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:.
-echo 'erase ^?, kill ^U, intr ^C'
-stty crt erase  kill  intr 
+echo 'erase ^h, kill ^U, intr ^C'
+stty crt erase  kill  intr 
export PATH
HOME=/root
export HOME
diff --git a/etc/services b/etc/services
index 040b814c7343..61440a190ede 100644
--- a/etc/services
+++ b/etc/services
@@ -7,7 +7,7 @@
# Updated from RFC 1340, ``Assigned Numbers'' (July 1992). Not all ports
# are included, only the more common ones.
#
-# $Id: services,v 1.5.2.1 1994/03/06 08:43:38 rgrimes Exp $
+# $Id: services,v 1.7 1994/03/02 17:58:29 wollman Exp $
# From: @(#)services 5.8 (Berkeley) 5/9/91
#
tcpmux 1/tcp # TCP port service multiplexer
diff --git a/etc/skey.access b/etc/skey.access
new file mode 100644
index 000000000000..22cdb69fe107
--- /dev/null
+++ b/etc/skey.access
@@ -0,0 +1,8 @@
+# First word says if UNIX passwords are to be permitted or denied.
+# remainder of the rule is a networknumber and mask. A rule matches a
+# host if any of its addresses satisfies:
+#
+# network = (address & mask)
+#
+#what network mask
+permit 0.0.0.0 0.0.0.0
diff --git a/etc/termcap.small b/etc/termcap.small
new file mode 100644
index 000000000000..9af048d553a3
--- /dev/null
+++ b/etc/termcap.small
@@ -0,0 +1,154 @@
+# Copyright (c) 1980, 1985, 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.
+#
+# @(#)termcap.src 5.88 (Berkeley) 4/30/91
+#
+#
+# for syscons
+cons25|ansi|ansi80x25:\
+ :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%d;%dH:co#80:\
+ :dc=\E[P:dl=\E[M:do=\E[B:bt=\E[Z:ei=:ho=\E[H:ic=\E[@:im=:li#25:\
+ :ms:nd=\E[C:pt:rs=\E[x\E[m\Ec:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:up=\E[A:\
+ :k1=\E[M:k2=\E[N:k3=\E[O:k4=\E[P:k5=\E[Q:k6=\E[R:\
+ :k7=\E[S:k8=\E[T:k9=\E[U:k0=\E[V:k10=\E[V:k11=\E[W:k12=\E[X:\
+ :kb=^h:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:le=^H:eo:sf=\E[S:sr=\E[T:\
+ :IC=\E[%d@:DC=\E[%dP:SF=\E[%dS:SR=\E[%dT:AL=\E[%dL:DL=\E[%dM:\
+ :DO=\E[%dB:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:\
+ :mb=\E[5m:md=\E[1m:me=\E[m:
+cons50|ansil|ansi80x50:\
+ :li#50:tc=cons25:
+dosansi|ANSI.SYS standard crt:\
+ :am:bs:ce=\E[K:cl=\E[2J:cm=\E[%i%d;%dH:co#80:\
+ :do=\E[B:li#25:mi:nd=\E[C:\
+ :se=\E[m:so=\E[7m:up=\E[A:us=\E[4m:ue=\E[m:\
+ :md=\E[1m:mh=\E[m:mb=\E[5m:me=\E[m:\
+ :kh=\EG:kb=^h:ku=\EH:kd=\EP:kl=\EK:kr=\EM:\
+ :k1=\E;:k2=\E<:k3=\E=:k4=\E>:k5=\E?:\
+ :k6=\E@:k7=\EA:k8=\EB:k9=\EC:k0=\ED:
+
+# The following is a version of the ibm-pc entry distributed with PC/IX,
+# (Interactive Systems' System 3 for the Big Blue), modified by Richard
+# McIntosh at UCB/CSM. The :pt: and :uc: have been removed from the original,
+# (the former is untrue, and the latter failed under UCB/man); standout and
+# underline modes have been added. Note: this entry describes the "native"
+# capabilities of the PC monochrome display, without ANY emulation; most
+# communications packages (but NOT PC/IX connect) do some kind of emulation.
+pc|ibmpc|ibm pc PC/IX:\
+ :li#24:co#80:am:bs:bw:eo:\
+ :cd=\E[J:ce=\E[K:cl=\Ec:cm=\E[%i%2;%2H:do=\E[B:ho=\E[;H:\
+ :nd=\E[C:up=\E[A:so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[0m:
+pc3mono|IBM PC 386BSD Console with monochrome monitor:\
+ :so=\E[0;1r\E[m:tc=pc3:
+pc3|ibmpc3|IBM PC 386BSD Console:\
+ :AL=\E[%dL:\
+ :DL=\E[%dM:\
+ :DO=\E[%dB:\
+ :K1=\E[H:\
+ :K2=\E[I:\
+ :K3=\E[E:\
+ :K4=\E[F:\
+ :K5=\E[G:\
+ :LE=\E[%dD:\
+ :RI=\E[%dC:\
+ :SF=\E[%dS:\
+ :SR=\E[%dT:\
+ :UP=\E[%dA:\
+ :al=\E[L:\
+ :am:\
+ :bl=^G:\
+ :bs:\
+ :cb=\E[1K:\
+ :cd=\E[J:\
+ :ce=\E[K:\
+ :cl=\E[H\E[J:\
+ :cm=\E[%i%d;%dH:\
+ :co#80:\
+ :cr=^M:\
+ :dl=\E[M:\
+ :do=^J:\
+ :ho=\E[H:\
+ :is=\E[m:\
+ :k0=\E[V:\
+ :k1=\E[M:\
+ :k2=\E[N:\
+ :k3=\E[O:\
+ :k4=\E[P:\
+ :k5=\E[Q:\
+ :k6=\E[R:\
+ :k7=\E[S:\
+ :k8=\E[T:\
+ :k9=\E[U:\
+ :kD=\177:\
+ :kH=\E[F:\
+ :kN=\E[G:\
+ :kP=\E[I:\
+ :kb=\177:\
+ :kd=\E[B:\
+ :kh=\E[H:\
+ :kl=\E[D:\
+ :kr=\E[C:\
+ :ku=\E[A:\
+ :le=^H:\
+ :li#25:\
+ :ms:\
+ :nd=\E[C:\
+ :pt:\
+ :rs=\E[m:\
+ :se=\E[m:\
+ :sf=\E[S:\
+ :so=\E[7;1r\E[7m:\
+ :sr=\E[T:\
+ :ta=^I:\
+ :te=\E[m:\
+ :ti=\E[m:\
+ :up=\E[A:
+# Syscons console with koi8-r russian code table.
+# Some non-standard termcap extentions added at the end (after 'ac')
+# for compatibility with current russian software.
+# You might need to add correct filename to Ct entry
+pc3r|ibmpc3r|FreeBSD console for syscons koi8-r code table:\
+ :li#25:co#80:am:bs:bw:eo:cu=\222:\
+ :UP=\E[%dA:DO=\E[%dB:RI=\E[%dC:LE=\E[%dD:AL=\E[%dL:DL=\E[%dM:\
+ :IC=\E[%d@:DC=\E[%dP:le=^H:ic=\E[@:dc=\E[P:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
+ :cm=\E[%i%d;%dH:do=^J:ho=\E[H:al=\E[L:dl=\E[M:nd=\E[C:up=\E[A:\
+ :so=\E[7m:se=\E[m:ms:rs=\E[x\E[m\Ec:pt:\
+ :mb=\E[5m:mr=\E[7m:md=\E[1m:mh=\E[30m\E[1m:me=\E[m:\
+ :kb=^H:kh=\E[H:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:\
+ :kN=\E[G:kP=\E[I:kH=\E[F:kI=\E[L:kD=\E[K:kB=\E[Z:\
+ :k1=\E[M:k2=\E[N:k3=\E[O:k4=\E[P:k5=\E[Q:k6=\E[R:k7=\E[S:k8=\E[T:\
+ :k9=\E[U:k0=\E[V:k.=\E[W:k-=\E[X:ko=k.,k-:kC=\E[E:\
+ :sr=\E[T:sf=\E[S:SR=\E[%dT:SF=\E[%dS:\
+ :ac=q\200x\201m\204v\211j\205t\206n\212u\207l\202w\210k\203y\230z\231f\234~\225a\221:\
+ :Nf#16:Nb#8:Cf=\E[=%dF:Cb=\E[=%dG:\
+ :gs=:ge=:g1=\200\201\204\211\205\206\212\207\202\210\203:\
+ :g2=\240\241\253\273\256\261\276\265\245\270\250:\
+ :f1=\E[M:f2=\E[N:f3=\E[O:f4=\E[P:f5=\E[Q:f6=\E[R:f7=\E[S:f8=\E[T:\
+ :f9=\E[U:f0=\E[V:f.=\E[W:f-=\E[X:CY:Cs=:Ce=:Ct=:
diff --git a/etc/ttys b/etc/ttys
index 20fda7f79126..93406544ad30 100644
--- a/etc/ttys
+++ b/etc/ttys
@@ -3,17 +3,21 @@
#
# name getty type status comments
#
-ttyv0 "/usr/libexec/getty Pc" pc3 on secure
+# This entry needed for asking password when init goes to single-user mode
+# If you want to be asked for password, change "secure" to "insecure" here
+console none unknown off secure
+#
+ttyv0 "/usr/libexec/getty Pc" cons25 on secure
# Virtual terminals
-ttyv1 "/usr/libexec/getty Pc" cons25 off secure
-ttyv2 "/usr/libexec/getty Pc" cons25 off secure
+ttyv1 "/usr/libexec/getty Pc" cons25 on secure
+ttyv2 "/usr/libexec/getty Pc" cons25 on secure
ttyv3 "/usr/libexec/getty Pc" cons25 off secure
# Hardwired terminals
tty00 "/usr/libexec/getty std.9600" unknown off secure
tty01 "/usr/libexec/getty std.9600" unknown off secure
# Dialin terminals
-ttyd2 "/usr/libexec/getty std.9600" unknown off secure
-ttyd3 "/usr/libexec/getty std.9600" unknown off secure
+ttyd2 "/usr/libexec/getty std.9600" unknown off secure
+ttyd3 "/usr/libexec/getty std.9600" unknown off secure
# Pseudo terminals
ttyp0 none network
ttyp1 none network
diff --git a/games/Makefile b/games/Makefile
index cc475918efb3..a57a1a15db07 100644
--- a/games/Makefile
+++ b/games/Makefile
@@ -11,7 +11,7 @@
#Missing: adventure boggle ching dungeon hunt phantasia quiz warp
SUBDIR= arithmetic atc backgammon banner battlestar bcd caesar canfield \
- cribbage dm factor fish fortune hack hangman larn \
+ cribbage dm factor fish fortune hangman larn \
mille monop morse number pom ppt primes rain robots rogue \
sail snake trek wargames worm worms wump
diff --git a/games/fortune/fortune/fortune.c b/games/fortune/fortune/fortune.c
index 79e9e1cde71e..fee1ebe8a4c3 100644
--- a/games/fortune/fortune/fortune.c
+++ b/games/fortune/fortune/fortune.c
@@ -148,7 +148,7 @@ char *do_malloc(), *copy(), *off_name();
FILEDESC *pick_child(), *new_fp();
-extern char *malloc(), *index(), *rindex(), *strcpy(), *strcat();
+extern char *index(), *rindex(), *strcpy(), *strcat();
extern time_t time();
diff --git a/games/hack/COPYRIGHT b/games/hack/COPYRIGHT
deleted file mode 100644
index 71a94494a8a0..000000000000
--- a/games/hack/COPYRIGHT
+++ /dev/null
@@ -1,6 +0,0 @@
-This entire subtree is copyright the Stichting Mathematisch Centrum.
-The following copyright notice applies to all files found here. None of
-these files contain AT&T proprietary source code.
-_____________________________________________________________________________
-
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
diff --git a/games/hack/Makefile b/games/hack/Makefile
deleted file mode 100644
index cc1af7a77784..000000000000
--- a/games/hack/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-# @(#)Makefile 5.10 (Berkeley) 12/8/90
-
-PROG= hack
-SRCS= alloc.c hack.Decl.c hack.apply.c hack.bones.c hack.c hack.cmd.c \
- hack.do.c hack.do_name.c hack.do_wear.c hack.dog.c hack.eat.c \
- hack.end.c hack.engrave.c hack.fight.c hack.invent.c hack.ioctl.c \
- hack.lev.c hack.main.c hack.makemon.c hack.mhitu.c hack.mklev.c \
- hack.mkmaze.c hack.mkobj.c hack.mkshop.c hack.mon.c hack.monst.c \
- hack.o_init.c hack.objnam.c hack.options.c hack.pager.c hack.potion.c \
- hack.pri.c hack.read.c hack.rip.c hack.rumors.c hack.save.c \
- hack.search.c hack.shk.c hack.shknam.c hack.steal.c hack.termcap.c \
- hack.timeout.c hack.topl.c hack.track.c hack.trap.c hack.tty.c \
- hack.u_init.c hack.unix.c hack.vault.c hack.version.c hack.wield.c \
- hack.wizard.c hack.worm.c hack.worn.c hack.zap.c rnd.c
-CFLAGS+= -I. -fwritable-strings
-MAN6= hack.6
-DPSRCS= hack.onames.h
-DPADD= ${LIBTERM}
-LDADD= -ltermcap
-HIDEGAME=hidegame
-CLEANFILES= hack.onames.h makedefs
-
-hack.onames.h: makedefs def.objects.h
- ./makedefs ${.CURDIR}/def.objects.h > hack.onames.h
-
-makedefs: makedefs.c
- ${CC} ${CFLAGS} -o ${.TARGET} ${.CURDIR}/${.PREFIX}.c
-
-beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m 666 /dev/null \
- ${DESTDIR}/var/games/hackdir/perm
- install -c -o ${BINOWN} -g ${BINGRP} -m 666 /dev/null \
- ${DESTDIR}/var/games/hackdir/record
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/help \
- ${.CURDIR}/hh ${.CURDIR}/data ${DESTDIR}/var/games/hackdir
- rm -f ${DESTDIR}/var/games/hackdir/bones*
-
-.depend alloc.o: hack.onames.h
-
-.include <bsd.prog.mk>
diff --git a/games/hack/Makequest b/games/hack/Makequest
deleted file mode 100644
index 9271c2841c92..000000000000
--- a/games/hack/Makequest
+++ /dev/null
@@ -1,196 +0,0 @@
-# Hack or Quest Makefile.
-
-# on some systems the termcap library is in -ltermcap
-TERMLIB = -ltermlib
-
-
-# make hack
-GAME = quest
-GAMEDIR = /usr/games/lib/questdir
-CFLAGS = -g -DQUEST
-HACKCSRC = hack.Decl.c\
- hack.apply.c hack.bones.c hack.c hack.cmd.c hack.do.c\
- hack.do_name.c hack.do_wear.c hack.dog.c hack.eat.c hack.end.c\
- hack.engrave.c hack.fight.c hack.invent.c hack.ioctl.c\
- hack.lev.c hack.main.c hack.makemon.c hack.mhitu.c\
- hack.mklev.c hack.mkmaze.c hack.mkobj.c hack.mkshop.c\
- hack.mon.c hack.monst.c hack.o_init.c hack.objnam.c\
- hack.options.c hack.pager.c hack.potion.c hack.pri.c\
- hack.read.c hack.rip.c hack.rumors.c hack.save.c\
- hack.search.c hack.shk.c hack.shknam.c hack.steal.c\
- hack.termcap.c hack.timeout.c hack.topl.c\
- hack.track.c hack.trap.c hack.tty.c hack.unix.c\
- hack.u_init.c hack.vault.c\
- hack.wield.c hack.wizard.c hack.worm.c hack.worn.c hack.zap.c\
- hack.version.c rnd.c alloc.c
-
-CSOURCES = $(HACKCSRC) makedefs.c
-
-HSOURCES = hack.h hack.mfndpos.h config.h\
- def.edog.h def.eshk.h def.flag.h def.func_tab.h def.gold.h\
- def.mkroom.h\
- def.monst.h def.obj.h def.objclass.h def.objects.h\
- def.permonst.h def.rm.h def.trap.h def.wseg.h
-
-SOURCES = $(CSOURCES) $(HSOURCES)
-
-AUX = data help hh rumors hack.6 hack.sh
-
-DISTR = $(SOURCES) $(AUX) READ_ME Makefile date.h hack.onames.h
-
-HOBJ = hack.Decl.o hack.apply.o hack.bones.o hack.o hack.cmd.o hack.do.o\
- hack.do_name.o hack.do_wear.o hack.dog.o hack.eat.o hack.end.o\
- hack.engrave.o hack.fight.o hack.invent.o hack.ioctl.o\
- hack.lev.o hack.main.o hack.makemon.o hack.mhitu.o hack.mklev.o\
- hack.mkmaze.o hack.mkobj.o hack.mkshop.o hack.mon.o\
- hack.monst.o hack.o_init.o hack.objnam.o hack.options.o\
- hack.pager.o hack.potion.o hack.pri.o\
- hack.read.o hack.rip.o hack.rumors.o hack.save.o\
- hack.search.o hack.shk.o hack.shknam.o hack.steal.o\
- hack.termcap.o hack.timeout.o hack.topl.o\
- hack.track.o hack.trap.o\
- hack.tty.o hack.unix.o hack.u_init.o hack.vault.o hack.wield.o\
- hack.wizard.o hack.worm.o hack.worn.o hack.zap.o\
- hack.version.o rnd.o alloc.o
-
-$(GAME): $(HOBJ) Makefile
- @echo "Loading ..."
- @ld -X -o $(GAME) /lib/crt0.o $(HOBJ) $(TERMLIB) -lc
-
-all: $(GAME) lint
- @echo "Done."
-
-makedefs: makedefs.c
- cc -o makedefs makedefs.c
-
-
-hack.onames.h: makedefs def.objects.h
- makedefs > hack.onames.h
-
-lint:
-# lint cannot have -p here because (i) capitals are meaningful:
-# [Ww]izard, (ii) identifiers may coincide in the first six places:
-# doweararm() versus dowearring().
-# _flsbuf comes from <stdio.h>, a bug in the system libraries.
- @echo lint -axbh -DLINT ...
- @lint -axbh -DLINT $(HACKCSRC) | sed '/_flsbuf/d'
-
-
-diff:
- @- for i in $(SOURCES) $(AUX) ; do \
- cmp -s $$i $D/$$i || \
- ( echo diff $D/$$i $$i ; diff $D/$$i $$i ; echo ) ; done
-
-distribution: Makefile
- @- for i in READ_ME $(SOURCES) $(AUX) Makefile date.h hack.onames.h\
- ; do \
- cmp -s $$i $D/$$i || \
- ( echo cp $$i $D ; cp $$i $D ) ; done
-# the distribution directory also contains the empty files perm and record.
-
-
-install:
- rm -f $(GAMEDIR)/$(GAME)
- cp $(GAME) $(GAMEDIR)/$(GAME)
- chmod 04511 $(GAMEDIR)/$(GAME)
- rm -f $(GAMEDIR)/bones*
-# cp hack.6 /usr/man/man6
-
-clean:
- rm -f *.o
-
-
-depend:
-# For the moment we are lazy and disregard /usr/include files because
-# the sources contain them conditionally. Perhaps we should use cpp.
-# ( /bin/grep '^#[ ]*include' $$i | sed -n \
-# -e 's,<\(.*\)>,"/usr/include/\1",' \
-#
- for i in ${CSOURCES}; do \
- ( /bin/grep '^#[ ]*include[ ]*"' $$i | sed -n \
- -e 's/[^"]*"\([^"]*\)".*/\1/' \
- -e H -e '$$g' -e '$$s/\n/ /g' \
- -e '$$s/.*/'$$i': &/' -e '$$s/\.c:/.o:/p' \
- >> makedep); done
- for i in ${HSOURCES}; do \
- ( /bin/grep '^#[ ]*include[ ]*"' $$i | sed -n \
- -e 's/[^"]*"\([^"]*\)".*/\1/' \
- -e H -e '$$g' -e '$$s/\n/ /g' \
- -e '$$s/.*/'$$i': &\
- touch '$$i/p \
- >> makedep); done
- @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
- @echo '$$r makedep' >>eddep
- @echo 'w' >>eddep
- @cp Makefile Makefile.bak
- ed - Makefile < eddep
- @rm -f eddep makedep
- @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
- @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
- @echo '# see make depend above' >> Makefile
- - diff Makefile Makefile.bak
- @rm -f Makefile.bak
-
-# DO NOT DELETE THIS LINE
-
-hack.Decl.o: hack.h def.mkroom.h
-hack.apply.o: hack.h def.edog.h def.mkroom.h
-hack.bones.o: hack.h
-hack.o: hack.h
-hack.cmd.o: hack.h def.func_tab.h
-hack.do.o: hack.h
-hack.do_name.o: hack.h
-hack.do_wear.o: hack.h
-hack.dog.o: hack.h hack.mfndpos.h def.edog.h def.mkroom.h
-hack.eat.o: hack.h
-hack.end.o: hack.h
-hack.engrave.o: hack.h
-hack.fight.o: hack.h
-hack.invent.o: hack.h def.wseg.h
-hack.ioctl.o: config.h
-hack.lev.o: hack.h def.mkroom.h def.wseg.h
-hack.main.o: hack.h
-hack.makemon.o: hack.h
-hack.mhitu.o: hack.h
-hack.mklev.o: hack.h def.mkroom.h
-hack.mkmaze.o: hack.h def.mkroom.h
-hack.mkobj.o: hack.h
-hack.mkshop.o: hack.h def.mkroom.h def.eshk.h
-hack.mon.o: hack.h hack.mfndpos.h
-hack.monst.o: hack.h def.eshk.h
-hack.o_init.o: config.h def.objects.h hack.onames.h
-hack.objnam.o: hack.h
-hack.options.o: config.h hack.h
-hack.pager.o: hack.h
-hack.potion.o: hack.h
-hack.pri.o: hack.h def.wseg.h
-hack.read.o: hack.h
-hack.rip.o: hack.h
-hack.rumors.o: hack.h
-hack.save.o: hack.h
-hack.search.o: hack.h
-hack.shk.o: hack.h hack.mfndpos.h def.mkroom.h def.eshk.h
-hack.shknam.o: hack.h
-hack.steal.o: hack.h
-hack.termcap.o: config.h def.flag.h
-hack.timeout.o: hack.h
-hack.topl.o: hack.h
-hack.track.o: hack.h
-hack.trap.o: hack.h def.mkroom.h
-hack.tty.o: hack.h
-hack.unix.o: hack.h def.mkroom.h
-hack.u_init.o: hack.h
-hack.vault.o: hack.h def.mkroom.h
-hack.wield.o: hack.h
-hack.wizard.o: hack.h
-hack.worm.o: hack.h def.wseg.h
-hack.worn.o: hack.h
-hack.zap.o: hack.h
-hack.version.o: date.h
-hack.h: config.h def.objclass.h def.monst.h def.gold.h def.trap.h def.obj.h def.flag.h def.rm.h def.permonst.h hack.onames.h
- touch hack.h
-def.objects.h: config.h def.objclass.h
- touch def.objects.h
-# DEPENDENCIES MUST END AT END OF FILE
-# IF YOU PUT STUFF HERE IT WILL GO AWAY
-# see make depend above
diff --git a/games/hack/OWNER b/games/hack/OWNER
deleted file mode 100644
index be2d1e530444..000000000000
--- a/games/hack/OWNER
+++ /dev/null
@@ -1,2 +0,0 @@
-Andries Brouwer
-mcvax!aeb
diff --git a/games/hack/Original_READ_ME b/games/hack/Original_READ_ME
deleted file mode 100644
index 9d2070be09e4..000000000000
--- a/games/hack/Original_READ_ME
+++ /dev/null
@@ -1,61 +0,0 @@
-This is export hack, my first semester programming project.
-
-To set it up for your system, you will have to do the following:
- 1: create a hack uid, to own the top ten list, etc.
- 2: create a hack directory "/usr/lib/game/hack" is the default.
- 2.5: make the directory 700 mode. /* sav files go in there...*/
- 3: modify hack.main.c to use the new directory.
- 4: modify hack.main.c so it uses the new hack gid. Gid accounts can
-go into magic mode without the password, can get cores with ^G, etc.
-(make sure gid isn't checked anywhere else...)
- 5: recompile hack.
- 6: put it in games after making it set-uid hack.
- 8: fix the bugs I undobtedly left in it.
- 9: tell me what you think of it.
-
- Hack uses the UCB file /etc/termcap to get your terminal escape codes.
-If you don't use it, you will have to make extensive changes to hack.pri.c
-
-If you find any bugs (That you think I don't know about), or have any
-awesome new changes (Like a better save (One that works!)), or have ANY
-questions, write me
- Jay Fenlason
- 29 East St.
- Sudbury Mass.
- 01776
-
-or call me at (617) 443-5036. Since I have both a modem and a teen-age
-sister, Good Luck.
-
-
-Hack is split (roughly) into several source files that do different things.
-I have tried to fit all the procedures having to do with a certain segment
-of the game into a single file, but the job is not the best in the world.
-The rough splits are:
-
-hack.c General random stuff and things I never got around to moving.
-hack.main.c main() and other random procedures, also the lock file stuff.
-hack.mon.c Monsters, moving, attacking, etc.
-hack.do.c drink, eat, read, wield, save, etc.
-hack.do1.c zap, wear, remove, etc...
-hack.pri.c stuff having to do with the screen, most of the terminal
- independant stuff is in here.
-hack.lev.c temp files and calling of mklev.
-
-Because of the peculiar restraints on our system, I make mklev (create
-a level) a separate procedure execd by hack when needed. The source for
-mklev is (Naturaly) mklev.c. You may want to put mklev back into hack.
-Good luck.
-
-Most of hack was written by me, with help from
- Kenny Woodland (KW) (general random things including
- the original BUZZ())
- Mike Thome (MT) (The original chamelian)
- and Jon Payne (JP) (The original lock file kludge and
- the massive CURS())
-
-This entire program would not have been possible without the SFSU Logo
-Workshop. I am eternally grateful to all of our students (Especially K.L.),
-without whom I would never have seen Rogue. I am especially grateful to
-Mike Clancy, without whose generous help I would never have gotten to play
-ROGUE.
diff --git a/games/hack/READ_ME b/games/hack/READ_ME
deleted file mode 100644
index cfe6ca2fe3eb..000000000000
--- a/games/hack/READ_ME
+++ /dev/null
@@ -1,92 +0,0 @@
-Hack is a display oriented dungeons & dragons - like game.
-Both display and command structure resemble rogue.
-(For a game with the same structure but entirely different display -
-a real cave instead of dull rectangles - try Quest)
-
-Hack was originally written by Jay Fenlason (at lincolnsudbury:
- 29 East St., Sudbury Mass., 01776) with help from
- Kenny Woodland, Mike Thome and Jon Payne.
-Basically it was an implementation of Rogue, however, with 52+ instead of 26
- monster types.
-The current version is more than thrice as large (with such new features as
- the dog, the long worms, the shops, etc.) and almost entirely rewritten
- (only the display routines are the original ones - I must rewrite these
- too one day; especially when you are blind strange things still happen).
-
-Files for hack:
- hack The actual game
- record Top 100 list (just start with an empty file)
- news Tells about recent changes in hack, or bugs found ...
- (Just start with no news file.)
- data Auxiliary file used by hack to give you the names
- and sometimes some more information on the
- objects and monsters.
- help Introductory information (no doubt outdated).
- hh Compactified version of help.
- perm An empty file used for locking purposes.
- rumors Texts for fortune cookies.
- (Some of these contain information on the game,
- others are just plain stupid. Additional rumors
- are appreciated.)
- hack.sh A shell script.
- (We have hack.sh in /usr/games/hack and
- hack in /usr/games/lib/hackdir/hack and all the other
- hack stuff in /usr/games/lib/hackdir - perhaps this
- will make the script clear.
- There is no need for you to use it.)
- READ_ME This file.
- Original_READ_ME Jay Fenlason's READ_ME
-
-System files used:
- /etc/termcap Used in conjunction with the environment variable
- $TERM.
- /bin/cat
- /usr/ucb/more
- /bin/sh Used when $SHELL is undefined.
-
-How to install hack:
-0. Compile the sources. Perhaps you should first look at the file config.h
- and define BSD if you are on a BSDtype system,
- define STUPID if your C-compiler chokes on complicated expressions.
- Make sure schar and uchar represent signed and unsigned types.
- If your C compiler doesnt allow initialization of bit fields
- change Bitfield. When config.h looks reasonable, say 'make'.
- (Perhaps you have to change TERMLIB in the makefile.)
-1. If it didnt exist already, introduce a loginname `play' .
-2. The program hack resides in a directory so that it is executable
- for everybody and is suid play:
- ---s--s--x 1 play 206848 Apr 3 00:17 hack
- Perhaps you wish to restrict playing to certain hours, or have games
- running under nice; in that case you might write a program play.c
- such that the program play is suid play and executable for everybody
- while all the games in /usr/games are readable or executable for
- play only; all the program play does is asking for the name of a game,
- checking that time-of-day and system load do not forbid playing,
- and then executing the game. Thus:
- -r-sr-sr-x 1 play 13312 May 24 12:52 play
- ---x------ 1 play 206848 Apr 3 00:17 hack
- If you are worried about security you might let play do
- chroot("/usr/games") so that no player can get access to the rest
- of the system via shell escapes and the likes.
- If you #define SECURE in config.h then hack will not setuid(getuid())
- before executing a chdir(). Hack will always do setuid(getuid()) with
- a fork. If you do not define UNIX then hack will not fork.
-3. The rest of the stuff belonging to hack sits in a subdirectory hackdir
- (on our system /usr/games/lib/hackdir) with modes
- drwx------ 3 play 1024 Aug 9 09:03 hackdir
- Here all the temporary files will be created (with names like xlock.17
- or user.5).
-4. If you are not really short on file space, creating a subdirectory
- hackdir/save (modes again drwx------) will enable users to save their
- unfinished games.
-
-The program hack is called
-$ hack [-d hackdir] [maxnrofplayers]
-(for playing) or
-$ hack [-d hackdir] -s [listofusers | limit | all]
-(for seeing part of the scorelist).
-The shell file hack (in this kit called hack.sh) takes care of
-calling hack with the right arguments.
-
-Send complaints, bug reports, suggestions for improvements to
-mcvax!aeb - in real life Andries Brouwer.
diff --git a/games/hack/alloc.c b/games/hack/alloc.c
deleted file mode 100644
index d94bf8b903b8..000000000000
--- a/games/hack/alloc.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* alloc.c - version 1.0.2 */
-#ifdef LINT
-
-/*
- a ridiculous definition, suppressing
- "possible pointer alignment problem" for (long *) malloc()
- "enlarg defined but never used"
- "ftell defined (in <stdio.h>) but never used"
- from lint
-*/
-#include <stdio.h>
-long *
-alloc(n) unsigned n; {
-long dummy = ftell(stderr);
- if(n) dummy = 0; /* make sure arg is used */
- return(&dummy);
-}
-
-#else
-
-extern char *malloc();
-extern char *realloc();
-
-long *
-alloc(lth)
-register unsigned lth;
-{
- register char *ptr;
-
- if(!(ptr = malloc(lth)))
- panic("Cannot get %d bytes", lth);
- return((long *) ptr);
-}
-
-long *
-enlarge(ptr,lth)
-register char *ptr;
-register unsigned lth;
-{
- register char *nptr;
-
- if(!(nptr = realloc(ptr,lth)))
- panic("Cannot reallocate %d bytes", lth);
- return((long *) nptr);
-}
-
-#endif LINT
diff --git a/games/hack/config.h b/games/hack/config.h
deleted file mode 100644
index f382937ba554..000000000000
--- a/games/hack/config.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* config.h - version 1.0.3 */
-
-#include "pathnames.h"
-
-#ifndef CONFIG /* make sure the compiler doesnt see the typedefs twice */
-
-#define CONFIG
-#define UNIX /* delete if no fork(), exec() available */
-#define CHDIR /* delete if no chdir() available */
-
-/*
- * Some include files are in a different place under SYSV
- * BSD SYSV
- * <sys/wait.h> <wait.h>
- * <sys/time.h> <time.h>
- * <sgtty.h> <termio.h>
- * Some routines are called differently
- * index strchr
- * rindex strrchr
- * Also, the code for suspend and various ioctls is only given for BSD4.2
- * (I do not have access to a SYSV system.)
- */
-#define BSD /* delete this line on System V */
-
-/* #define STUPID */ /* avoid some complicated expressions if
- your C compiler chokes on them */
-/* #define PYRAMID_BUG */ /* avoid a bug on the Pyramid */
-/* #define NOWAITINCLUDE */ /* neither <wait.h> nor <sys/wait.h> exists */
-
-#define WIZARD "bruno" /* the person allowed to use the -D option */
-#define RECORD "record"/* the file containing the list of topscorers */
-#define NEWS "news" /* the file containing the latest hack news */
-#define HELP "help" /* the file containing a description of the commands */
-#define SHELP "hh" /* abbreviated form of the same */
-#define RUMORFILE "rumors" /* a file with fortune cookies */
-#define DATAFILE "data" /* a file giving the meaning of symbols used */
-#define FMASK 0660 /* file creation mask */
-#define HLOCK "perm" /* an empty file used for locking purposes */
-#define LLOCK "safelock" /* link to previous */
-
-#ifdef UNIX
-/*
- * Define DEF_PAGER as your default pager, e.g. "/bin/cat" or "/usr/ucb/more"
- * If defined, it can be overridden by the environment variable PAGER.
- * Hack will use its internal pager if DEF_PAGER is not defined.
- * (This might be preferable for security reasons.)
- * #define DEF_PAGER ".../mydir/mypager"
- */
-
-/*
- * If you define MAIL, then the player will be notified of new mail
- * when it arrives. If you also define DEF_MAILREADER then this will
- * be the default mail reader, and can be overridden by the environment
- * variable MAILREADER; otherwise an internal pager will be used.
- * A stat system call is done on the mailbox every MAILCKFREQ moves.
- */
-/* #define MAIL */
-#define DEF_MAILREADER _PATH_MAIL /* or e.g. /bin/mail */
-#define MAILCKFREQ 100
-
-
-#define SHELL /* do not delete the '!' command */
-
-#ifdef BSD
-#define SUSPEND /* let ^Z suspend the game */
-#endif BSD
-#endif UNIX
-
-#ifdef CHDIR
-/*
- * If you define HACKDIR, then this will be the default playground;
- * otherwise it will be the current directory.
- */
-#ifdef QUEST
-#define HACKDIR _PATH_QUEST
-#else QUEST
-#define HACKDIR _PATH_HACK
-#endif QUEST
-
-/*
- * Some system administrators are stupid enough to make Hack suid root
- * or suid daemon, where daemon has other powers besides that of reading or
- * writing Hack files. In such cases one should be careful with chdir's
- * since the user might create files in a directory of his choice.
- * Of course SECURE is meaningful only if HACKDIR is defined.
- */
-#define SECURE /* do setuid(getuid()) after chdir() */
-
-/*
- * If it is desirable to limit the number of people that can play Hack
- * simultaneously, define HACKDIR, SECURE and MAX_NR_OF_PLAYERS.
- * #define MAX_NR_OF_PLAYERS 100
- */
-#endif CHDIR
-
-/* size of terminal screen is (at least) (ROWNO+2) by COLNO */
-#define COLNO 80
-#define ROWNO 22
-
-/*
- * small signed integers (8 bits suffice)
- * typedef char schar;
- * will do when you have signed characters; otherwise use
- * typedef short int schar;
- */
-typedef char schar;
-
-/*
- * small unsigned integers (8 bits suffice - but 7 bits do not)
- * - these are usually object types; be careful with inequalities! -
- * typedef unsigned char uchar;
- * will be satisfactory if you have an "unsigned char" type; otherwise use
- * typedef unsigned short int uchar;
- */
-typedef unsigned char uchar;
-
-/*
- * small integers in the range 0 - 127, usually coordinates
- * although they are nonnegative they must not be declared unsigned
- * since otherwise comparisons with signed quantities are done incorrectly
- */
-typedef schar xchar;
-typedef xchar boolean; /* 0 or 1 */
-#define TRUE 1
-#define FALSE 0
-
-/*
- * Declaration of bitfields in various structs; if your C compiler
- * doesnt handle bitfields well, e.g., if it is unable to initialize
- * structs containing bitfields, then you might use
- * #define Bitfield(x,n) uchar x
- * since the bitfields used never have more than 7 bits. (Most have 1 bit.)
- */
-#define Bitfield(x,n) unsigned x:n
-
-#define SIZE(x) (int)(sizeof(x) / sizeof(x[0]))
-
-#endif CONFIG
diff --git a/games/hack/data b/games/hack/data
deleted file mode 100644
index 5d8d509b0fd9..000000000000
--- a/games/hack/data
+++ /dev/null
@@ -1,232 +0,0 @@
- Hack & Quest data file - version 1.0.3
-@ human (or you)
-- a wall
-| a wall
-+ a door
-. the floor of a room
- a dark part of a room
-# a corridor
-} water filled area
-< the staircase to the previous level
-> the staircase to the next level
-^ a trap
-$ a pile, pot or chest of gold
-%% a piece of food
-! a potion
-* a gem
-? a scroll
-= a ring
-/ a wand
-[ a suit of armor
-) a weapon
-( a useful item (camera, key, rope etc.)
-0 an iron ball
-_ an iron chain
-` an enormous rock
-" an amulet
-, a trapper
-: a chameleon
-; a giant eel
-' a lurker above
-& a demon
-A a giant ant
-B a giant bat
-C a centaur;
- Of all the monsters put together by the Greek imagination
- the Centaurs (Kentauroi) constituted a class in themselves.
- Despite a strong streak of sensuality in their make-up,
- their normal behaviour was moral, and they took a kindly
- thought of man's welfare. The attempted outrage of Nessos on
- Deianeira, and that of the whole tribe of Centaurs on the
- Lapith women, are more than offset by the hospitality of
- Pholos and by the wisdom of Cheiron, physician, prophet,
- lyrist, and the instructor of Achilles. Further, the Cen-
- taurs were peculiar in that their nature, which united the
- body of a horse with the trunk and head of a man, involved
- an unthinkable duplication of vital organs and important
- members. So grotesque a combination seems almost un-Greek.
- These strange creatures were said to live in the caves and
- clefts of the mountains, myths associating them especially
- with the hills of Thessaly and the range of Erymanthos.
- [Mythology of all races, Vol. 1, pp. 270-271]
-D a dragon;
- In the West the dragon was the natural enemy of man. Although
- preferring to live in bleak and desolate regions, whenever it was
- seen among men it left in its wake a trail of destruction and
- disease. Yet any attempt to slay this beast was a perilous under-
- taking. For the dragon's assailant had to contend not only with
- clouds of sulphurous fumes pouring from its fire-breathing nos-
- trils, but also with the thrashings of its tail, the most deadly
- part of its serpent-like body.
- [From: Mythical Beasts by Deirdre Headon (The Leprechaun Library)]
-E a floating eye
-F a freezing sphere
-G a gnome;
- ... And then a gnome came by, carrying a bundle, an old fellow
- three times as large as an imp and wearing clothes of a sort,
- especially a hat. And he was clearly just as frightened as the
- imps though he could not go so fast. Ramon Alonzo saw that there
- must be some great trouble that was vexing magical things; and,
- since gnomes speak the language of men, and will answer if spoken
- to gently, he raised his hat, and asked of the gnome his name.
- The gnome did not stop his hasty shuffle a moment as he answered
- 'Alaraba' and grabbed the rim of his hat but forgot to doff it.
- 'What is the trouble, Alaraba?' said Ramon Alonzo.
- 'White magic. Run!' said the gnome ...
- [From: The Charwoman's Shadow, by Lord Dunsany.]
-H a hobgoblin;
- Hobgoblin. Used by the Puritans and in later times for
- wicked goblin spirits, as in Bunyan's 'Hobgoblin nor foul
- friend', but its more correct use is for the friendly spir-
- its of the brownie type. In 'A midsummer night's dream' a
- fairy says to Shakespeare's Puck:
- Those that Hobgoblin call you, and sweet Puck,
- You do their work, and they shall have good luck:
- Are you not he?
- and obviously Puck would not wish to be called a hobgoblin
- if that was an ill-omened word.
- Hobgoblins are on the whole, good-humoured and ready to be
- helpful, but fond of practical joking, and like most of the
- fairies rather nasty people to annoy. Boggarts hover on the
- verge of hobgoblindom. Bogles are just over the edge.
- One Hob mentioned by Henderson, was Hob Headless who haunted
- the road between Hurworth and Neasham, but could not cross
- the little river Kent, which flowed into the Tess. He was
- exorcised and laid under a large stone by the roadside for
- ninety-nine years and a day. If anyone was so unwary as to
- sit on that stone, he would be unable to quit it for ever.
- The ninety-nine years is nearly up, so trouble may soon be
- heard of on the road between Hurworth and Neasham.
- [Katharine Briggs, A dictionary of Fairies]
-I an invisible stalker
-J a jackal
-K a kobold
-L a leprechaun;
- The Irish Leprechaun is the Faeries' shoemaker and is known
- under various names in different parts of Ireland: Cluri-
- caune in Cork, Lurican in Kerry, Lurikeen in Kildare and Lu-
- rigadaun in Tipperary. Although he works for the Faeries,
- the Leprechaun is not of the same species. He is small, has
- dark skin and wears strange clothes. His nature has some-
- thing of the manic-depressive about it: first he is quite
- happy, whistling merrily as he nails a sole on to a shoe; a
- few minutes later, he is sullen and morose, drunk on his
- home-made heather ale. The Leprechaun's two great loves are
- tobacco and whiskey, and he is a first-rate con-man, impos-
- sible to out-fox. No one, no matter how clever, has ever
- managed to cheat him out of his hidden pot of gold or his
- magic shilling. At the last minute he always thinks of some
- way to divert his captor's attention and vanishes in the
- twinkling of an eye.
- [From: A Field Guide to the Little People
- by Nancy Arrowsmith & George Moorse. ]
-M a mimic
-N a nymph
-O an orc
-P a purple worm
-Q a quasit
-R a rust monster
-S a snake
-T a troll
-U an umber hulk
-V a vampire
-W a wraith
-X a xorn
-Y a yeti
-Z a zombie
-a an acid blob
-b a giant beetle
-c a cockatrice;
- Once in a great while, when the positions of the stars are
- just right, a seven-year-old rooster will lay an egg. Then,
- along will come a snake, to coil around the egg, or a toad,
- to squat upon the egg, keeping it warm and helping it to
- hatch. When it hatches, out comes a creature called basil-
- isk, or cockatrice, the most deadly of all creatures. A sin-
- gle glance from its yellow, piercing toad's eyes will kill
- both man and beast. Its power of destruction is said to be
- so great that sometimes simply to hear its hiss can prove
- fatal. Its breath is so venomenous that it causes all vege-
- tation to wither.
- There is, however, one creature which can withstand the
- basilisk's deadly gaze, and this is the weasel. No one knows
- why this is so, but although the fierce weasel can slay the
- basilisk, it will itself be killed in the struggle. Perhaps
- the weasel knows the basilisk's fatal weakness: if it ever
- sees its own reflection in a mirror it will perish instant-
- ly. But even a dead basilisk is dangerous, for it is said
- that merely touching its lifeless body can cause a person to
- sicken and die.
- [From: Mythical Beasts by Deirdre Headon (The Leprechaun
- Library) and other sources. ]
-d a dog
-e an ettin
-f a fog cloud
-g a gelatinous cube
-h a homunculus
-i an imp;
- ... imps ... little creatures of two feet high that could
- gambol and jump prodigiously; ...
- [From: The Charwoman's Shadow, by Lord Dunsany.]
-
- An 'imp' is an off-shoot or cutting. Thus an 'ymp tree' was
- a grafted tree, or one grown from a cutting, not from seed.
- 'Imp' properly means a small devil, an off-shoot of Satan,
- but the distinction between goblins or bogles and imps from
- hell is hard to make, and many in the Celtic countries as
- well as the English Puritans regarded all fairies as devils.
- The fairies of tradition often hover uneasily between the
- ghostly and the diabolic state.
- [Katharine Briggs, A dictionary of Fairies]
-j a jaguar
-k a killer bee
-l a leocrotta
-m a minotaur
-n a nurse
-o an owlbear
-p a piercer
-q a quivering blob
-r a giant rat
-s a scorpion
-t a tengu;
- The tengu was the most troublesome creature of Japanese
- legend. Part bird and part man, with red beak for a nose
- and flashing eyes, the tengu was notorious for stirring up
- feuds and prolonging enmity between families. Indeed, the
- belligerent tengus were supposed to have been man's first
- instructors in the use of arms.
- [From: Mythical Beasts by Deirdre Headon
- (The Leprechaun Library). ]
-u a unicorn;
- Men have always sought the elusive unicorn, for the single
- twisted horn which projected from its forehead was thought
- to be a powerful talisman. It was said that the unicorn had
- simply to dip the tip of its horn in a muddy pool for the
- water to become pure. Men also believed that to drink from
- this horn was a protection against all sickness, and that if
- the horn was ground to a powder it would act as an antidote
- to all poisons. Less than 200 years ago in France, the horn
- of a unicorn was used in a ceremony to test the royal food
- for poison.
- Although only the size of a small horse, the unicorn is a
- very fierce beast, capable of killing an elephant with a
- single thrust from its horn. Its fleetness of foot also
- makes this solitary creature difficult to capture. However,
- it can be tamed and captured by a maiden. Made gentle by the
- sight of a virgin, the unicorn can be lured to lay its head
- in her lap, and in this docile mood, the maiden may secure
- it with a golden rope.
- [From: Mythical Beasts by Deirdre Headon
- (The Leprechaun Library). ]
-v a violet fungi
-w a long worm;
- From its teeth the crysknife can be manufactured.
-~ the tail of a long worm
-x a xan;
- The xan were animals sent to prick the legs of the Lords of Xibalba.
-y a yellow light
-z a zruty;
- The zruty are wild and gigantic beings, living in the wildernesses
- of the Tatra mountains.
-1 The wizard of Yendor
-2 The mail daemon
diff --git a/games/hack/date.h b/games/hack/date.h
deleted file mode 100644
index 9a7ef7688854..000000000000
--- a/games/hack/date.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-char datestring[] = "Tue Jul 23 1985";
diff --git a/games/hack/def.edog.h b/games/hack/def.edog.h
deleted file mode 100644
index a5c2b4616e01..000000000000
--- a/games/hack/def.edog.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.edog.h - version 1.0.2 */
-
-struct edog {
- long hungrytime; /* at this time dog gets hungry */
- long eattime; /* dog is eating */
- long droptime; /* moment dog dropped object */
- unsigned dropdist; /* dist of drpped obj from @ */
- unsigned apport; /* amount of training */
- long whistletime; /* last time he whistled */
-};
-#define EDOG(mp) ((struct edog *)(&(mp->mextra[0])))
diff --git a/games/hack/def.eshk.h b/games/hack/def.eshk.h
deleted file mode 100644
index 2ebf2804d348..000000000000
--- a/games/hack/def.eshk.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.eshk.h - version 1.0.2 : added 'following' */
-
-#define BILLSZ 200
-struct bill_x {
- unsigned bo_id;
- unsigned useup:1;
- unsigned bquan:7;
- unsigned price; /* price per unit */
-};
-
-struct eshk {
- long int robbed; /* amount stolen by most recent customer */
- boolean following; /* following customer since he owes us sth */
- schar shoproom; /* index in rooms; set by inshop() */
- coord shk; /* usual position shopkeeper */
- coord shd; /* position shop door */
- int shoplevel; /* level of his shop */
- int billct;
- struct bill_x bill[BILLSZ];
- int visitct; /* nr of visits by most recent customer */
- char customer[PL_NSIZ]; /* most recent customer */
- char shknam[PL_NSIZ];
-};
diff --git a/games/hack/def.flag.h b/games/hack/def.flag.h
deleted file mode 100644
index 221f33dd9166..000000000000
--- a/games/hack/def.flag.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.flag.h - version 1.0.3 */
-
-struct flag {
- unsigned ident; /* social security number for each monster */
- unsigned debug:1; /* in debugging mode */
-#define wizard flags.debug
- unsigned toplin:2; /* a top line (message) has been printed */
- /* 0: top line empty; 2: no --More-- reqd. */
- unsigned cbreak:1; /* in cbreak mode, rogue format */
- unsigned standout:1; /* use standout for --More-- */
- unsigned nonull:1; /* avoid sending nulls to the terminal */
- unsigned time:1; /* display elapsed 'time' */
- unsigned nonews:1; /* suppress news printing */
- unsigned notombstone:1;
- unsigned end_top, end_around; /* describe desired score list */
- unsigned end_own:1; /* idem (list all own scores) */
- unsigned no_rest_on_space:1; /* spaces are ignored */
- unsigned beginner:1;
- unsigned female:1;
- unsigned invlet_constant:1; /* let objects keep their
- inventory symbol */
- unsigned move:1;
- unsigned mv:1;
- unsigned run:3; /* 0: h (etc), 1: H (etc), 2: fh (etc) */
- /* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */
- unsigned nopick:1; /* do not pickup objects */
- unsigned echo:1; /* 1 to echo characters */
- unsigned botl:1; /* partially redo status line */
- unsigned botlx:1; /* print an entirely new bottom line */
- unsigned nscrinh:1; /* inhibit nscr() in pline(); */
- unsigned made_amulet:1;
- unsigned no_of_wizards:2;/* 0, 1 or 2 (wizard and his shadow) */
- /* reset from 2 to 1, but never to 0 */
- unsigned moonphase:3;
-#define NEW_MOON 0
-#define FULL_MOON 4
-
-};
-
-extern struct flag flags;
-
diff --git a/games/hack/def.func_tab.h b/games/hack/def.func_tab.h
deleted file mode 100644
index 63f74d2ef618..000000000000
--- a/games/hack/def.func_tab.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.func_tab.h - version 1.0.2 */
-
-struct func_tab {
- char f_char;
- int (*f_funct)();
-};
-
-extern struct func_tab cmdlist[];
-
-struct ext_func_tab {
- char *ef_txt;
- int (*ef_funct)();
-};
-
-extern struct ext_func_tab extcmdlist[];
diff --git a/games/hack/def.gen.h b/games/hack/def.gen.h
deleted file mode 100644
index f1e44fc98977..000000000000
--- a/games/hack/def.gen.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.gen.h version 1.0.1: added ONCE flag */
-
-struct gen {
- struct gen *ngen;
- xchar gx,gy;
- unsigned gflag; /* 037: trap type; 040: SEEN flag */
- /* 0100: ONCE only */
-#define TRAPTYPE 037
-#define SEEN 040
-#define ONCE 0100
-};
-extern struct gen *fgold, *ftrap;
-struct gen *g_at();
-#define newgen() (struct gen *) alloc(sizeof(struct gen))
diff --git a/games/hack/def.gold.h b/games/hack/def.gold.h
deleted file mode 100644
index 808890883509..000000000000
--- a/games/hack/def.gold.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.gold.h - version 1.0.2 */
-
-struct gold {
- struct gold *ngold;
- xchar gx,gy;
- long amount;
-};
-
-extern struct gold *fgold;
-struct gold *g_at();
-#define newgold() (struct gold *) alloc(sizeof(struct gold))
diff --git a/games/hack/def.mkroom.h b/games/hack/def.mkroom.h
deleted file mode 100644
index ddbb62be1b02..000000000000
--- a/games/hack/def.mkroom.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.mkroom.h - version 1.0.3 */
-
-struct mkroom {
- schar lx,hx,ly,hy; /* usually xchar, but hx may be -1 */
- schar rtype,rlit,doorct,fdoor;
-};
-
-#define MAXNROFROOMS 15
-extern struct mkroom rooms[MAXNROFROOMS+1];
-
-#define DOORMAX 100
-extern coord doors[DOORMAX];
-
-/* various values of rtype */
-/* 0: ordinary room; 8-15: various shops */
-/* Note: some code assumes that >= 8 means shop, so be careful when adding
- new roomtypes */
-#define SWAMP 3
-#define VAULT 4
-#define BEEHIVE 5
-#define MORGUE 6
-#define ZOO 7
-#define SHOPBASE 8
-#define WANDSHOP 9
-#define GENERAL 15
diff --git a/games/hack/def.monst.h b/games/hack/def.monst.h
deleted file mode 100644
index 88836af7aee3..000000000000
--- a/games/hack/def.monst.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.monst.h - version 1.0.2 */
-
-struct monst {
- struct monst *nmon;
- struct permonst *data;
- unsigned m_id;
- xchar mx,my;
- xchar mdx,mdy; /* if mdispl then pos where last displayed */
-#define MTSZ 4
- coord mtrack[MTSZ]; /* monster track */
- schar mhp,mhpmax;
- char mappearance; /* nonzero for undetected 'M's and for '1's */
- Bitfield(mimic,1); /* undetected mimic */
- Bitfield(mdispl,1); /* mdx,mdy valid */
- Bitfield(minvis,1); /* invisible */
- Bitfield(cham,1); /* shape-changer */
- Bitfield(mhide,1); /* hides beneath objects */
- Bitfield(mundetected,1); /* not seen in present hiding place */
- Bitfield(mspeed,2);
- Bitfield(msleep,1);
- Bitfield(mfroz,1);
- Bitfield(mconf,1);
- Bitfield(mflee,1); /* fleeing */
- Bitfield(mfleetim,7); /* timeout for mflee */
- Bitfield(mcan,1); /* has been cancelled */
- Bitfield(mtame,1); /* implies peaceful */
- Bitfield(mpeaceful,1); /* does not attack unprovoked */
- Bitfield(isshk,1); /* is shopkeeper */
- Bitfield(isgd,1); /* is guard */
- Bitfield(mcansee,1); /* cansee 1, temp.blinded 0, blind 0 */
- Bitfield(mblinded,7); /* cansee 0, temp.blinded n, blind 0 */
- Bitfield(mtrapped,1); /* trapped in a pit or bear trap */
- Bitfield(mnamelth,6); /* length of name (following mxlth) */
-#ifndef NOWORM
- Bitfield(wormno,5); /* at most 31 worms on any level */
-#endif NOWORM
- unsigned mtrapseen; /* bitmap of traps we've been trapped in */
- long mlstmv; /* prevent two moves at once */
- struct obj *minvent;
- long mgold;
- unsigned mxlth; /* length of following data */
- /* in order to prevent alignment problems mextra should
- be (or follow) a long int */
- long mextra[1]; /* monster dependent info */
-};
-
-#define newmonst(xl) (struct monst *) alloc((unsigned)(xl) + sizeof(struct monst))
-
-extern struct monst *fmon;
-extern struct monst *fallen_down;
-struct monst *m_at();
-
-/* these are in mspeed */
-#define MSLOW 1 /* slow monster */
-#define MFAST 2 /* speeded monster */
-
-#define NAME(mtmp) (((char *) mtmp->mextra) + mtmp->mxlth)
-#define MREGEN "TVi1"
-#define UNDEAD "ZVW "
diff --git a/games/hack/def.obj.h b/games/hack/def.obj.h
deleted file mode 100644
index 50b21df1b8f0..000000000000
--- a/games/hack/def.obj.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.obj.h - version 1.0.3 */
-
-struct obj {
- struct obj *nobj;
- unsigned o_id;
- unsigned o_cnt_id; /* id of container object is in */
- xchar ox,oy;
- xchar odx,ody;
- uchar otyp;
- uchar owt;
- uchar quan; /* use oextra for tmp gold objects */
- schar spe; /* quality of weapon, armor or ring (+ or -)
- number of charges for wand ( >= -1 )
- special for uball and amulet %% BAH */
- char olet;
- char invlet;
- Bitfield(oinvis,1); /* not yet implemented */
- Bitfield(odispl,1);
- Bitfield(known,1); /* exact nature known */
- Bitfield(dknown,1); /* color or text known */
- Bitfield(cursed,1);
- Bitfield(unpaid,1); /* on some bill */
- Bitfield(rustfree,1);
- Bitfield(onamelth,6);
- long age; /* creation date */
- long owornmask;
-#define W_ARM 01L
-#define W_ARM2 02L
-#define W_ARMH 04L
-#define W_ARMS 010L
-#define W_ARMG 020L
-#define W_ARMOR (W_ARM | W_ARM2 | W_ARMH | W_ARMS | W_ARMG)
-#define W_RINGL 010000L /* make W_RINGL = RING_LEFT (see uprop) */
-#define W_RINGR 020000L
-#define W_RING (W_RINGL | W_RINGR)
-#define W_WEP 01000L
-#define W_BALL 02000L
-#define W_CHAIN 04000L
- long oextra[1]; /* used for name of ordinary objects - length
- is flexible; amount for tmp gold objects */
-};
-
-extern struct obj *fobj;
-
-#define newobj(xl) (struct obj *) alloc((unsigned)(xl) + sizeof(struct obj))
-#define ONAME(otmp) ((char *) otmp->oextra)
-#define OGOLD(otmp) (otmp->oextra[0])
diff --git a/games/hack/def.objclass.h b/games/hack/def.objclass.h
deleted file mode 100644
index 9e17de237ee7..000000000000
--- a/games/hack/def.objclass.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.objclass.h - version 1.0.3 */
-
-/* definition of a class of objects */
-
-struct objclass {
- char *oc_name; /* actual name */
- char *oc_descr; /* description when name unknown */
- char *oc_uname; /* called by user */
- Bitfield(oc_name_known,1);
- Bitfield(oc_merge,1); /* merge otherwise equal objects */
- char oc_olet;
- schar oc_prob; /* probability for mkobj() */
- schar oc_delay; /* delay when using such an object */
- uchar oc_weight;
- schar oc_oc1, oc_oc2;
- int oc_oi;
-#define nutrition oc_oi /* for foods */
-#define a_ac oc_oc1 /* for armors - only used in ARM_BONUS */
-#define ARM_BONUS(obj) ((10 - objects[obj->otyp].a_ac) + obj->spe)
-#define a_can oc_oc2 /* for armors */
-#define bits oc_oc1 /* for wands and rings */
- /* wands */
-#define NODIR 1
-#define IMMEDIATE 2
-#define RAY 4
- /* rings */
-#define SPEC 1 /* +n is meaningful */
-#define wldam oc_oc1 /* for weapons and PICK_AXE */
-#define wsdam oc_oc2 /* for weapons and PICK_AXE */
-#define g_val oc_oi /* for gems: value on exit */
-};
-
-extern struct objclass objects[];
-
-/* definitions of all object-symbols */
-
-#define ILLOBJ_SYM '\\'
-#define AMULET_SYM '"'
-#define FOOD_SYM '%'
-#define WEAPON_SYM ')'
-#define TOOL_SYM '('
-#define BALL_SYM '0'
-#define CHAIN_SYM '_'
-#define ROCK_SYM '`'
-#define ARMOR_SYM '['
-#define POTION_SYM '!'
-#define SCROLL_SYM '?'
-#define WAND_SYM '/'
-#define RING_SYM '='
-#define GEM_SYM '*'
-/* Other places with explicit knowledge of object symbols:
- * ....shk.c: char shtypes[] = "=/)%?![";
- * mklev.c: "=/)%?![<>"
- * hack.mkobj.c: char mkobjstr[] = "))[[!!!!????%%%%/=**";
- * hack.apply.c: otmp = getobj("0#%", "put in");
- * hack.eat.c: otmp = getobj("%", "eat");
- * hack.invent.c: if(index("!%?[)=*(0/\"", sym)){
- * hack.invent.c: || index("%?!*",otmp->olet))){
- */
diff --git a/games/hack/def.objects.h b/games/hack/def.objects.h
deleted file mode 100644
index b4400fc4a70b..000000000000
--- a/games/hack/def.objects.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.objects.h - version 1.0.3 */
-
-/* objects have letter " % ) ( 0 _ ` [ ! ? / = * */
-#include "config.h"
-#include "def.objclass.h"
-#define NULL (char *)0
-
-struct objclass objects[] = {
-
- { "strange object", NULL, NULL, 1, 0,
- ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 },
- { "amulet of Yendor", NULL, NULL, 1, 0,
- AMULET_SYM, 100, 0, 2, 0, 0, 0 },
-
-#define FOOD(name,prob,delay,weight,nutrition) { name, NULL, NULL, 1, 1,\
- FOOD_SYM, prob, delay, weight, 0, 0, nutrition }
-
-/* dog eats foods 0-4 but prefers 1 above 0,2,3,4 */
-/* food 4 can be read */
-/* food 5 improves your vision */
-/* food 6 makes you stronger (like Popeye) */
-/* foods CORPSE up to CORPSE+52 are cadavers */
-
- FOOD("food ration", 50, 5, 4, 800),
- FOOD("tripe ration", 20, 1, 2, 200),
- FOOD("pancake", 3, 1, 1, 200),
- FOOD("dead lizard", 3, 0, 1, 40),
- FOOD("fortune cookie", 7, 0, 1, 40),
- FOOD("carrot", 2, 0, 1, 50),
- FOOD("tin", 7, 0, 1, 0),
- FOOD("orange", 1, 0, 1, 80),
- FOOD("apple", 1, 0, 1, 50),
- FOOD("pear", 1, 0, 1, 50),
- FOOD("melon", 1, 0, 1, 100),
- FOOD("banana", 1, 0, 1, 80),
- FOOD("candy bar", 1, 0, 1, 100),
- FOOD("egg", 1, 0, 1, 80),
- FOOD("clove of garlic", 1, 0, 1, 40),
- FOOD("lump of royal jelly", 0, 0, 1, 200),
-
- FOOD("dead human", 0, 4, 40, 400),
- FOOD("dead giant ant", 0, 1, 3, 30),
- FOOD("dead giant bat", 0, 1, 3, 30),
- FOOD("dead centaur", 0, 5, 50, 500),
- FOOD("dead dragon", 0, 15, 150, 1500),
- FOOD("dead floating eye", 0, 1, 1, 10),
- FOOD("dead freezing sphere", 0, 1, 1, 10),
- FOOD("dead gnome", 0, 1, 10, 100),
- FOOD("dead hobgoblin", 0, 2, 20, 200),
- FOOD("dead stalker", 0, 4, 40, 400),
- FOOD("dead jackal", 0, 1, 10, 100),
- FOOD("dead kobold", 0, 1, 10, 100),
- FOOD("dead leprechaun", 0, 4, 40, 400),
- FOOD("dead mimic", 0, 4, 40, 400),
- FOOD("dead nymph", 0, 4, 40, 400),
- FOOD("dead orc", 0, 2, 20, 200),
- FOOD("dead purple worm", 0, 7, 70, 700),
- FOOD("dead quasit", 0, 2, 20, 200),
- FOOD("dead rust monster", 0, 5, 50, 500),
- FOOD("dead snake", 0, 1, 10, 100),
- FOOD("dead troll", 0, 4, 40, 400),
- FOOD("dead umber hulk", 0, 5, 50, 500),
- FOOD("dead vampire", 0, 4, 40, 400),
- FOOD("dead wraith", 0, 1, 1, 10),
- FOOD("dead xorn", 0, 7, 70, 700),
- FOOD("dead yeti", 0, 7, 70, 700),
- FOOD("dead zombie", 0, 1, 3, 30),
- FOOD("dead acid blob", 0, 1, 3, 30),
- FOOD("dead giant beetle", 0, 1, 1, 10),
- FOOD("dead cockatrice", 0, 1, 3, 30),
- FOOD("dead dog", 0, 2, 20, 200),
- FOOD("dead ettin", 0, 1, 3, 30),
- FOOD("dead fog cloud", 0, 1, 1, 10),
- FOOD("dead gelatinous cube", 0, 1, 10, 100),
- FOOD("dead homunculus", 0, 2, 20, 200),
- FOOD("dead imp", 0, 1, 1, 10),
- FOOD("dead jaguar", 0, 3, 30, 300),
- FOOD("dead killer bee", 0, 1, 1, 10),
- FOOD("dead leocrotta", 0, 5, 50, 500),
- FOOD("dead minotaur", 0, 7, 70, 700),
- FOOD("dead nurse", 0, 4, 40, 400),
- FOOD("dead owlbear", 0, 7, 70, 700),
- FOOD("dead piercer", 0, 2, 20, 200),
- FOOD("dead quivering blob", 0, 1, 10, 100),
- FOOD("dead giant rat", 0, 1, 3, 30),
- FOOD("dead giant scorpion", 0, 1, 10, 100),
- FOOD("dead tengu", 0, 3, 30, 300),
- FOOD("dead unicorn", 0, 3, 30, 300),
- FOOD("dead violet fungi", 0, 1, 10, 100),
- FOOD("dead long worm", 0, 5, 50, 500),
-/* %% wt of long worm should be proportional to its length */
- FOOD("dead xan", 0, 3, 30, 300),
- FOOD("dead yellow light", 0, 1, 1, 10),
- FOOD("dead zruty", 0, 6, 60, 600),
-
-/* weapons ... - ROCK come several at a time */
-/* weapons ... - (ROCK-1) are shot using idem+(BOW-ARROW) */
-/* weapons AXE, SWORD, THSWORD are good for worm-cutting */
-/* weapons (PICK-)AXE, DAGGER, CRYSKNIFE are good for tin-opening */
-#define WEAPON(name,prob,wt,ldam,sdam) { name, NULL, NULL, 1, 0 /*%%*/,\
- WEAPON_SYM, prob, 0, wt, ldam, sdam, 0 }
-
- WEAPON("arrow", 7, 0, 6, 6),
- WEAPON("sling bullet", 7, 0, 4, 6),
- WEAPON("crossbow bolt", 7, 0, 4, 6),
- WEAPON("dart", 7, 0, 3, 2),
- WEAPON("rock", 6, 1, 3, 3),
- WEAPON("boomerang", 2, 3, 9, 9),
- WEAPON("mace", 9, 3, 6, 7),
- WEAPON("axe", 6, 3, 6, 4),
- WEAPON("flail", 6, 3, 6, 5),
- WEAPON("long sword", 8, 3, 8, 12),
- WEAPON("two handed sword", 6, 4, 12, 6),
- WEAPON("dagger", 6, 3, 4, 3),
- WEAPON("worm tooth", 0, 4, 2, 2),
- WEAPON("crysknife", 0, 3, 10, 10),
- WEAPON("spear", 6, 3, 6, 8),
- WEAPON("bow", 6, 3, 4, 6),
- WEAPON("sling", 5, 3, 6, 6),
- WEAPON("crossbow", 6, 3, 4, 6),
-
- { "whistle", "whistle", NULL, 0, 0,
- TOOL_SYM, 90, 0, 2, 0, 0, 0 },
- { "magic whistle", "whistle", NULL, 0, 0,
- TOOL_SYM, 10, 0, 2, 0, 0, 0 },
- { "expensive camera", NULL, NULL, 1, 1,
- TOOL_SYM, 0, 0, 3, 0, 0, 0 },
- { "ice box", "large box", NULL, 0, 0,
- TOOL_SYM, 0, 0, 40, 0, 0, 0 },
- { "pick-axe", NULL, NULL, 1, 1,
- TOOL_SYM, 0, 0, 5, 6, 3, 0 },
- { "can opener", NULL, NULL, 1, 1,
- TOOL_SYM, 0, 0, 1, 0, 0, 0 },
- { "heavy iron ball", NULL, NULL, 1, 0,
- BALL_SYM, 100, 0, 20, 0, 0, 0 },
- { "iron chain", NULL, NULL, 1, 0,
- CHAIN_SYM, 100, 0, 20, 0, 0, 0 },
- { "enormous rock", NULL, NULL, 1, 0,
- ROCK_SYM, 100, 0, 200 /* > MAX_CARR_CAP */, 0, 0, 0 },
-
-#define ARMOR(name,prob,delay,ac,can) { name, NULL, NULL, 1, 0,\
- ARMOR_SYM, prob, delay, 8, ac, can, 0 }
- ARMOR("helmet", 3, 1, 9, 0),
- ARMOR("plate mail", 5, 5, 3, 2),
- ARMOR("splint mail", 8, 5, 4, 1),
- ARMOR("banded mail", 10, 5, 4, 0),
- ARMOR("chain mail", 10, 5, 5, 1),
- ARMOR("scale mail", 10, 5, 6, 0),
- ARMOR("ring mail", 15, 5, 7, 0),
- /* the armors below do not rust */
- ARMOR("studded leather armor", 13, 3, 7, 1),
- ARMOR("leather armor", 17, 3, 8, 0),
- ARMOR("elven cloak", 5, 0, 9, 3),
- ARMOR("shield", 3, 0, 9, 0),
- ARMOR("pair of gloves", 1, 1, 9, 0),
-
-#define POTION(name,color) { name, color, NULL, 0, 1,\
- POTION_SYM, 0, 0, 2, 0, 0, 0 }
-
- POTION("restore strength", "orange"),
- POTION("booze", "bubbly"),
- POTION("invisibility", "glowing"),
- POTION("fruit juice", "smoky"),
- POTION("healing", "pink"),
- POTION("paralysis", "puce"),
- POTION("monster detection", "purple"),
- POTION("object detection", "yellow"),
- POTION("sickness", "white"),
- POTION("confusion", "swirly"),
- POTION("gain strength", "purple-red"),
- POTION("speed", "ruby"),
- POTION("blindness", "dark green"),
- POTION("gain level", "emerald"),
- POTION("extra healing", "sky blue"),
- POTION("levitation", "brown"),
- POTION(NULL, "brilliant blue"),
- POTION(NULL, "clear"),
- POTION(NULL, "magenta"),
- POTION(NULL, "ebony"),
-
-#define SCROLL(name,text,prob) { name, text, NULL, 0, 1,\
- SCROLL_SYM, prob, 0, 3, 0, 0, 0 }
- SCROLL("mail", "KIRJE", 0),
- SCROLL("enchant armor", "ZELGO MER", 6),
- SCROLL("destroy armor", "JUYED AWK YACC", 5),
- SCROLL("confuse monster", "NR 9", 5),
- SCROLL("scare monster", "XIXAXA XOXAXA XUXAXA", 4),
- SCROLL("blank paper", "READ ME", 3),
- SCROLL("remove curse", "PRATYAVAYAH", 6),
- SCROLL("enchant weapon", "DAIYEN FOOELS", 6),
- SCROLL("damage weapon", "HACKEM MUCHE", 5),
- SCROLL("create monster", "LEP GEX VEN ZEA", 5),
- SCROLL("taming", "PRIRUTSENIE", 1),
- SCROLL("genocide", "ELBIB YLOH",2),
- SCROLL("light", "VERR YED HORRE", 10),
- SCROLL("teleportation", "VENZAR BORGAVVE", 5),
- SCROLL("gold detection", "THARR", 4),
- SCROLL("food detection", "YUM YUM", 1),
- SCROLL("identify", "KERNOD WEL", 18),
- SCROLL("magic mapping", "ELAM EBOW", 5),
- SCROLL("amnesia", "DUAM XNAHT", 3),
- SCROLL("fire", "ANDOVA BEGARIN", 5),
- SCROLL("punishment", "VE FORBRYDERNE", 1),
- SCROLL(NULL, "VELOX NEB", 0),
- SCROLL(NULL, "FOOBIE BLETCH", 0),
- SCROLL(NULL, "TEMOV", 0),
- SCROLL(NULL, "GARVEN DEH", 0),
-
-#define WAND(name,metal,prob,flags) { name, metal, NULL, 0, 0,\
- WAND_SYM, prob, 0, 3, flags, 0, 0 }
-
- WAND("light", "iridium", 10, NODIR),
- WAND("secret door detection", "tin", 5, NODIR),
- WAND("create monster", "platinum", 5, NODIR),
- WAND("wishing", "glass", 1, NODIR),
- WAND("striking", "zinc", 9, IMMEDIATE),
- WAND("slow monster", "balsa", 5, IMMEDIATE),
- WAND("speed monster", "copper", 5, IMMEDIATE),
- WAND("undead turning", "silver", 5, IMMEDIATE),
- WAND("polymorph", "brass", 5, IMMEDIATE),
- WAND("cancellation", "maple", 5, IMMEDIATE),
- WAND("teleportation", "pine", 5, IMMEDIATE),
- WAND("make invisible", "marble", 9, IMMEDIATE),
- WAND("digging", "iron", 5, RAY),
- WAND("magic missile", "aluminium", 10, RAY),
- WAND("fire", "steel", 5, RAY),
- WAND("sleep", "curved", 5, RAY),
- WAND("cold", "short", 5, RAY),
- WAND("death", "long", 1, RAY),
- WAND(NULL, "oak", 0, 0),
- WAND(NULL, "ebony", 0, 0),
- WAND(NULL, "runed", 0, 0),
-
-#define RING(name,stone,spec) { name, stone, NULL, 0, 0,\
- RING_SYM, 0, 0, 1, spec, 0, 0 }
-
- RING("adornment", "engagement", 0),
- RING("teleportation", "wooden", 0),
- RING("regeneration", "black onyx", 0),
- RING("searching", "topaz", 0),
- RING("see invisible", "pearl", 0),
- RING("stealth", "sapphire", 0),
- RING("levitation", "moonstone", 0),
- RING("poison resistance", "agate", 0),
- RING("aggravate monster", "tiger eye", 0),
- RING("hunger", "shining", 0),
- RING("fire resistance", "gold", 0),
- RING("cold resistance", "copper", 0),
- RING("protection from shape changers", "diamond", 0),
- RING("conflict", "jade", 0),
- RING("gain strength", "ruby", SPEC),
- RING("increase damage", "silver", SPEC),
- RING("protection", "granite", SPEC),
- RING("warning", "wire", 0),
- RING("teleport control", "iron", 0),
- RING(NULL, "ivory", 0),
- RING(NULL, "blackened", 0),
-
-/* gems ************************************************************/
-#define GEM(name,color,prob,gval) { name, color, NULL, 0, 1,\
- GEM_SYM, prob, 0, 1, 0, 0, gval }
- GEM("diamond", "blue", 1, 4000),
- GEM("ruby", "red", 1, 3500),
- GEM("sapphire", "blue", 1, 3000),
- GEM("emerald", "green", 1, 2500),
- GEM("turquoise", "green", 1, 2000),
- GEM("aquamarine", "blue", 1, 1500),
- GEM("tourmaline", "green", 1, 1000),
- GEM("topaz", "yellow", 1, 900),
- GEM("opal", "yellow", 1, 800),
- GEM("garnet", "dark", 1, 700),
- GEM("amethyst", "violet", 2, 650),
- GEM("agate", "green", 2, 600),
- GEM("onyx", "white", 2, 550),
- GEM("jasper", "yellowish brown", 2, 500),
- GEM("jade", "green", 2, 450),
- GEM("worthless piece of blue glass", "blue", 20, 0),
- GEM("worthless piece of red glass", "red", 20, 0),
- GEM("worthless piece of yellow glass", "yellow", 20, 0),
- GEM("worthless piece of green glass", "green", 20, 0),
- { NULL, NULL, NULL, 0, 0, ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 }
-};
-
-char obj_symbols[] = {
- ILLOBJ_SYM, AMULET_SYM, FOOD_SYM, WEAPON_SYM, TOOL_SYM,
- BALL_SYM, CHAIN_SYM, ROCK_SYM, ARMOR_SYM, POTION_SYM, SCROLL_SYM,
- WAND_SYM, RING_SYM, GEM_SYM, 0 };
-int bases[sizeof(obj_symbols)];
diff --git a/games/hack/def.permonst.h b/games/hack/def.permonst.h
deleted file mode 100644
index b19efc6ae4bc..000000000000
--- a/games/hack/def.permonst.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.permonst.h - version 1.0.2 */
-
-struct permonst {
- char *mname,mlet;
- schar mlevel,mmove,ac,damn,damd;
- unsigned pxlth;
-};
-
-extern struct permonst mons[];
-#define PM_ACID_BLOB &mons[7]
-#define PM_ZOMBIE &mons[13]
-#define PM_PIERCER &mons[17]
-#define PM_KILLER_BEE &mons[26]
-#define PM_WRAITH &mons[33]
-#define PM_MIMIC &mons[37]
-#define PM_VAMPIRE &mons[43]
-#define PM_CHAMELEON &mons[47]
-#define PM_DEMON &mons[54]
-#define PM_MINOTAUR &mons[55] /* last in mons array */
-#define PM_SHK &mons[56] /* very last */
-#define PM_GHOST &pm_ghost
-#define PM_EEL &pm_eel
-#define PM_WIZARD &pm_wizard
-#define CMNUM 55 /* number of common monsters */
diff --git a/games/hack/def.rm.h b/games/hack/def.rm.h
deleted file mode 100644
index f84921ca3365..000000000000
--- a/games/hack/def.rm.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.rm.h - version 1.0.2 */
-
-/* Level location types */
-#define HWALL 1
-#define VWALL 2
-#define SDOOR 3
-#define SCORR 4
-#define LDOOR 5
-#define POOL 6 /* not yet fully implemented */
- /* this should in fact be a bit like lit */
-#define DOOR 7
-#define CORR 8
-#define ROOM 9
-#define STAIRS 10
-
-/*
- * Avoid using the level types in inequalities:
- * these types are subject to change.
- * Instead, use one of the macros below.
- */
-#define IS_WALL(typ) ((typ) <= VWALL)
-#define IS_ROCK(typ) ((typ) < POOL) /* absolutely nonaccessible */
-#define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */
-#define IS_ROOM(typ) ((typ) >= ROOM) /* ROOM or STAIRS */
-#define ZAP_POS(typ) ((typ) > DOOR)
-
-/*
- * A few of the associated symbols are not hardwired.
- */
-#ifdef QUEST
-#define CORR_SYM ':'
-#else
-#define CORR_SYM '#'
-#endif QUEST
-#define POOL_SYM '}'
-
-#define ERRCHAR '{'
-
-/*
- * The structure describing a coordinate position.
- * Before adding fields, remember that this will significantly affect
- * the size of temporary files and save files.
- */
-struct rm {
- char scrsym;
- unsigned typ:5;
- unsigned new:1;
- unsigned seen:1;
- unsigned lit:1;
-};
-extern struct rm levl[COLNO][ROWNO];
diff --git a/games/hack/def.trap.h b/games/hack/def.trap.h
deleted file mode 100644
index 26946add76bb..000000000000
--- a/games/hack/def.trap.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.trap.h - version 1.0.2 */
-
-struct trap {
- struct trap *ntrap;
- xchar tx,ty;
- unsigned ttyp:5;
- unsigned tseen:1;
- unsigned once:1;
-};
-
-extern struct trap *ftrap;
-struct trap *t_at();
-#define newtrap() (struct trap *) alloc(sizeof(struct trap))
-
-/* various kinds of traps */
-#define BEAR_TRAP 0
-#define ARROW_TRAP 1
-#define DART_TRAP 2
-#define TRAPDOOR 3
-#define TELEP_TRAP 4
-#define PIT 5
-#define SLP_GAS_TRAP 6
-#define PIERC 7
-#define MIMIC 8 /* used only in mklev.c */
-#define TRAPNUM 9 /* if not less than 32, change sizeof(ttyp) */
- /* see also mtrapseen (bit map) */
diff --git a/games/hack/def.wseg.h b/games/hack/def.wseg.h
deleted file mode 100644
index 0a2af7791d03..000000000000
--- a/games/hack/def.wseg.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* def.wseg.h - version 1.0.2 */
-
-#ifndef NOWORM
-/* worm structure */
-struct wseg {
- struct wseg *nseg;
- xchar wx,wy;
- unsigned wdispl:1;
-};
-
-#define newseg() (struct wseg *) alloc(sizeof(struct wseg))
-#endif NOWORM
diff --git a/games/hack/hack.6 b/games/hack/hack.6
deleted file mode 100644
index 5210c2630bcd..000000000000
--- a/games/hack/hack.6
+++ /dev/null
@@ -1,155 +0,0 @@
-.TH HACK 6 "31 March 1985"
-.UC 4
-.SH NAME
-hack \- Exploring The Dungeons of Doom
-.SH SYNOPSIS
-.B /usr/games/hack
-[
-.B \-d
-.I directory
-]
-[
-.B \-n
-]
-[
-.B \-u
-.I playername
-]
-.br
-.B /usr/games/hack
-[
-.B \-d
-.I directory
-]
-.B \-s
-[
-.B \-X
-]
-[
-.I playernames
-]
-.SH DESCRIPTION
-.PP
-.I Hack
-is a display oriented dungeons & dragons - like game.
-Both display and command structure resemble rogue.
-(For a game with the same structure but entirely different display -
-a real cave instead of dull rectangles - try Quest.)
-.PP
-To get started you really only need to know two commands. The command
-.B ?
-will give you a list of the available commands and the command
-.B /
-will identify the things you see on the screen.
-.PP
-To win the game (as opposed to merely playing to beat other people high
-scores) you must locate the Amulet of Yendor which is somewhere below
-the 20th level of the dungeon and get it out. Nobody has achieved this
-yet and if somebody does, he will probably go down in history as a hero
-among heros.
-.PP
-When the game ends, either by your death, when you quit, or if you escape
-from the caves,
-.I hack
-will give you (a fragment of) the list of top scorers. The scoring
-is based on many aspects of your behavior but a rough estimate is
-obtained by taking the amount of gold you've found in the cave plus four
-times your (real) experience. Precious stones may be worth a lot of gold
-when brought to the exit.
-There is a 10% penalty for getting yourself killed.
-.PP
-The administration of the game is kept in the directory specified with the
-.B \-d
-option, or, if no such option is given, in the directory specified by
-the environment variable HACKDIR, or, if no such variable exists, in
-the current directory. This same directory contains several auxiliary
-files such as lockfiles and the list of topscorers and a subdirectory
-.I save
-where games are saved.
-The game administrator may however choose to install hack with a fixed
-playing ground, usually /usr/games/lib/hackdir.
-.PP
-The
-.B \-n
-option suppresses printing of the news.
-.PP
-The
-.B \-u
-.I playername
-option supplies the answer to the question "Who are you?".
-When
-.I playername
-has as suffix one of
-.B \-T \-S \-K \-F \-C \-W
-then this supplies the answer to the question "What kind of character ... ?".
-.PP
-The
-.B \-s
-option will print out the list of your scores. It may be followed by arguments
-.B \-X
-where X is one of the letters C, F, K, S, T, W to print the scores of
-Cavemen, Fighters, Knights, Speleologists, Tourists or Wizards.
-It may also be followed by one or more player names to print the scores of the
-players mentioned.
-.SH AUTHORS
-Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the
-original hack, very much like rogue (but full of bugs).
-.br
-Andries Brouwer continuously deformed their sources into the current
-version - in fact an entirely different game.
-.SH FILES
-.DT
-.ta \w'data, rumors\ \ \ 'u
-hack The hack program.
-.br
-data, rumors Data files used by hack.
-.br
-help, hh Help data files.
-.br
-record The list of topscorers.
-.br
-save A subdirectory containing the saved
-.br
- games.
-.br
-bones_dd Descriptions of the ghost and
-.br
- belongings of a deceased adventurer.
-.br
-xlock.dd Description of a dungeon level.
-.br
-safelock Lock file for xlock.
-.br
-record_lock Lock file for record.
-.SH ENVIRONMENT
-.DT
-.ta \w'HACKPAGER, PAGER\ \ \ 'u
-USER or LOGNAME Your login name.
-.br
-HOME Your home directory.
-.br
-SHELL Your shell.
-.br
-TERM The type of your terminal.
-.br
-HACKPAGER, PAGER Pager used instead of default pager.
-.br
-MAIL Mailbox file.
-.br
-MAILREADER Reader used instead of default
-.br
- (probably /bin/mail or /usr/ucb/mail).
-.br
-HACKDIR Playground.
-.br
-HACKOPTIONS String predefining several hack options
-.br
- (see help file).
-.br
-
-Several other environment variables are used in debugging (wizard) mode,
-like GENOCIDED, INVENT, MAGIC and SHOPTYPE.
-.SH BUGS
-.PP
-Probably infinite.
-Mail complaints to mcvax!aeb .
diff --git a/games/hack/hack.Decl.c b/games/hack/hack.Decl.c
deleted file mode 100644
index b2855ac93631..000000000000
--- a/games/hack/hack.Decl.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.Decl.c - version 1.0.3 */
-
-#include "hack.h"
-char nul[40]; /* contains zeros */
-char plname[PL_NSIZ]; /* player name */
-char lock[PL_NSIZ+4] = "1lock"; /* long enough for login name .99 */
-
-boolean in_mklev, restoring;
-
-struct rm levl[COLNO][ROWNO]; /* level map */
-#ifndef QUEST
-#include "def.mkroom.h"
-struct mkroom rooms[MAXNROFROOMS+1];
-coord doors[DOORMAX];
-#endif QUEST
-struct monst *fmon = 0;
-struct trap *ftrap = 0;
-struct gold *fgold = 0;
-struct obj *fobj = 0, *fcobj = 0, *invent = 0, *uwep = 0, *uarm = 0,
- *uarm2 = 0, *uarmh = 0, *uarms = 0, *uarmg = 0, *uright = 0,
- *uleft = 0, *uchain = 0, *uball = 0;
-struct flag flags;
-struct you u;
-struct monst youmonst; /* dummy; used as return value for boomhit */
-
-xchar dlevel = 1;
-xchar xupstair, yupstair, xdnstair, ydnstair;
-char *save_cm = 0, *killer, *nomovemsg;
-
-long moves = 1;
-long wailmsg = 0;
-
-int multi = 0;
-char genocided[60];
-char fut_geno[60];
-
-xchar curx,cury;
-xchar seelx, seehx, seely, seehy; /* corners of lit room */
-
-coord bhitpos;
-
-char quitchars[] = " \r\n\033";
diff --git a/games/hack/hack.apply.c b/games/hack/hack.apply.c
deleted file mode 100644
index 18da738dfe9c..000000000000
--- a/games/hack/hack.apply.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.apply.c - version 1.0.3 */
-
-#include "hack.h"
-#include "def.edog.h"
-#include "def.mkroom.h"
-static struct monst *bchit();
-extern struct obj *addinv();
-extern struct trap *maketrap();
-extern int (*occupation)();
-extern char *occtxt;
-extern char quitchars[];
-extern char pl_character[];
-
-static void use_camera(), use_ice_box(), use_whistle(), use_magic_whistle();
-static int use_pick_axe();
-
-doapply() {
- register struct obj *obj;
- register int res = 1;
-
- obj = getobj("(", "use or apply");
- if(!obj) return(0);
-
- switch(obj->otyp){
- case EXPENSIVE_CAMERA:
- use_camera(obj); break;
- case ICE_BOX:
- use_ice_box(obj); break;
- case PICK_AXE:
- res = use_pick_axe(obj);
- break;
-
- case MAGIC_WHISTLE:
- if(pl_character[0] == 'W' || u.ulevel > 9) {
- use_magic_whistle(obj);
- break;
- }
- /* fall into next case */
- case WHISTLE:
- use_whistle(obj);
- break;
-
- case CAN_OPENER:
- if(!carrying(TIN)) {
- pline("You have no can to open.");
- goto xit;
- }
- pline("You cannot open a tin without eating its contents.");
- pline("In order to eat, use the 'e' command.");
- if(obj != uwep)
- pline("Opening the tin will be much easier if you wield the can-opener.");
- goto xit;
-
- default:
- pline("Sorry, I don't know how to use that.");
- xit:
- nomul(0);
- return(0);
- }
- nomul(0);
- return(res);
-}
-
-/* ARGSUSED */
-static void
-use_camera(obj) /* register */ struct obj *obj; {
-register struct monst *mtmp;
- if(!getdir(1)){ /* ask: in what direction? */
- flags.move = multi = 0;
- return;
- }
- if(u.uswallow) {
- pline("You take a picture of %s's stomach.", monnam(u.ustuck));
- return;
- }
- if(u.dz) {
- pline("You take a picture of the %s.",
- (u.dz > 0) ? "floor" : "ceiling");
- return;
- }
- if(mtmp = bchit(u.dx, u.dy, COLNO, '!')) {
- if(mtmp->msleep){
- mtmp->msleep = 0;
- pline("The flash awakens %s.", monnam(mtmp)); /* a3 */
- } else
- if(mtmp->data->mlet != 'y')
- if(mtmp->mcansee || mtmp->mblinded){
- register int tmp = dist(mtmp->mx,mtmp->my);
- register int tmp2;
- if(cansee(mtmp->mx,mtmp->my))
- pline("%s is blinded by the flash!", Monnam(mtmp));
- setmangry(mtmp);
- if(tmp < 9 && !mtmp->isshk && rn2(4)) {
- mtmp->mflee = 1;
- if(rn2(4)) mtmp->mfleetim = rnd(100);
- }
- if(tmp < 3) mtmp->mcansee = mtmp->mblinded = 0;
- else {
- tmp2 = mtmp->mblinded;
- tmp2 += rnd(1 + 50/tmp);
- if(tmp2 > 127) tmp2 = 127;
- mtmp->mblinded = tmp2;
- mtmp->mcansee = 0;
- }
- }
- }
-}
-
-static
-struct obj *current_ice_box; /* a local variable of use_ice_box, to be
- used by its local procedures in/ck_ice_box */
-static
-in_ice_box(obj) register struct obj *obj; {
- if(obj == current_ice_box ||
- (Punished && (obj == uball || obj == uchain))){
- pline("You must be kidding.");
- return(0);
- }
- if(obj->owornmask & (W_ARMOR | W_RING)) {
- pline("You cannot refrigerate something you are wearing.");
- return(0);
- }
- if(obj->owt + current_ice_box->owt > 70) {
- pline("It won't fit.");
- return(1); /* be careful! */
- }
- if(obj == uwep) {
- if(uwep->cursed) {
- pline("Your weapon is welded to your hand!");
- return(0);
- }
- setuwep((struct obj *) 0);
- }
- current_ice_box->owt += obj->owt;
- freeinv(obj);
- obj->o_cnt_id = current_ice_box->o_id;
- obj->nobj = fcobj;
- fcobj = obj;
- obj->age = moves - obj->age; /* actual age */
- return(1);
-}
-
-static
-ck_ice_box(obj) register struct obj *obj; {
- return(obj->o_cnt_id == current_ice_box->o_id);
-}
-
-static
-out_ice_box(obj) register struct obj *obj; {
-register struct obj *otmp;
- if(obj == fcobj) fcobj = fcobj->nobj;
- else {
- for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
- if(!otmp->nobj) panic("out_ice_box");
- otmp->nobj = obj->nobj;
- }
- current_ice_box->owt -= obj->owt;
- obj->age = moves - obj->age; /* simulated point of time */
- (void) addinv(obj);
-}
-
-static void
-use_ice_box(obj) register struct obj *obj; {
-register int cnt = 0;
-register struct obj *otmp;
- current_ice_box = obj; /* for use by in/out_ice_box */
- for(otmp = fcobj; otmp; otmp = otmp->nobj)
- if(otmp->o_cnt_id == obj->o_id)
- cnt++;
- if(!cnt) pline("Your ice-box is empty.");
- else {
- pline("Do you want to take something out of the ice-box? [yn] ");
- if(readchar() == 'y')
- if(askchain(fcobj, (char *) 0, 0, out_ice_box, ck_ice_box, 0))
- return;
- pline("That was all. Do you wish to put something in? [yn] ");
- if(readchar() != 'y') return;
- }
- /* call getobj: 0: allow cnt; #: allow all types; %: expect food */
- otmp = getobj("0#%", "put in");
- if(!otmp || !in_ice_box(otmp))
- flags.move = multi = 0;
-}
-
-static
-struct monst *
-bchit(ddx,ddy,range,sym) register int ddx,ddy,range; char sym; {
- register struct monst *mtmp = (struct monst *) 0;
- register int bchx = u.ux, bchy = u.uy;
-
- if(sym) Tmp_at(-1, sym); /* open call */
- while(range--) {
- bchx += ddx;
- bchy += ddy;
- if(mtmp = m_at(bchx,bchy))
- break;
- if(!ZAP_POS(levl[bchx][bchy].typ)) {
- bchx -= ddx;
- bchy -= ddy;
- break;
- }
- if(sym) Tmp_at(bchx, bchy);
- }
- if(sym) Tmp_at(-1, -1);
- return(mtmp);
-}
-
-/* ARGSUSED */
-static void
-use_whistle(obj) struct obj *obj; {
-register struct monst *mtmp = fmon;
- pline("You produce a high whistling sound.");
- while(mtmp) {
- if(dist(mtmp->mx,mtmp->my) < u.ulevel*20) {
- if(mtmp->msleep)
- mtmp->msleep = 0;
- if(mtmp->mtame)
- EDOG(mtmp)->whistletime = moves;
- }
- mtmp = mtmp->nmon;
- }
-}
-
-/* ARGSUSED */
-static void
-use_magic_whistle(obj) struct obj *obj; {
-register struct monst *mtmp = fmon;
- pline("You produce a strange whistling sound.");
- while(mtmp) {
- if(mtmp->mtame) mnexto(mtmp);
- mtmp = mtmp->nmon;
- }
-}
-
-static int dig_effort; /* effort expended on current pos */
-static uchar dig_level;
-static coord dig_pos;
-static boolean dig_down;
-
-static
-dig() {
- register struct rm *lev;
- register dpx = dig_pos.x, dpy = dig_pos.y;
-
- /* perhaps a nymph stole his pick-axe while he was busy digging */
- /* or perhaps he teleported away */
- if(u.uswallow || !uwep || uwep->otyp != PICK_AXE ||
- dig_level != dlevel ||
- ((dig_down && (dpx != u.ux || dpy != u.uy)) ||
- (!dig_down && dist(dpx,dpy) > 2)))
- return(0);
-
- dig_effort += 10 + abon() + uwep->spe + rn2(5);
- if(dig_down) {
- if(!xdnstair) {
- pline("The floor here seems too hard to dig in.");
- return(0);
- }
- if(dig_effort > 250) {
- dighole();
- return(0); /* done with digging */
- }
- if(dig_effort > 50) {
- register struct trap *ttmp = t_at(dpx,dpy);
-
- if(!ttmp) {
- ttmp = maketrap(dpx,dpy,PIT);
- ttmp->tseen = 1;
- pline("You have dug a pit.");
- u.utrap = rn1(4,2);
- u.utraptype = TT_PIT;
- return(0);
- }
- }
- } else
- if(dig_effort > 100) {
- register char *digtxt;
- register struct obj *obj;
-
- lev = &levl[dpx][dpy];
- if(obj = sobj_at(ENORMOUS_ROCK, dpx, dpy)) {
- fracture_rock(obj);
- digtxt = "The rock falls apart.";
- } else if(!lev->typ || lev->typ == SCORR) {
- lev->typ = CORR;
- digtxt = "You succeeded in cutting away some rock.";
- } else if(lev->typ == HWALL || lev->typ == VWALL
- || lev->typ == SDOOR) {
- lev->typ = xdnstair ? DOOR : ROOM;
- digtxt = "You just made an opening in the wall.";
- } else
- digtxt = "Now what exactly was it that you were digging in?";
- mnewsym(dpx, dpy);
- prl(dpx, dpy);
- pline(digtxt); /* after mnewsym & prl */
- return(0);
- } else {
- if(IS_WALL(levl[dpx][dpy].typ)) {
- register int rno = inroom(dpx,dpy);
-
- if(rno >= 0 && rooms[rno].rtype >= 8) {
- pline("This wall seems too hard to dig into.");
- return(0);
- }
- }
- pline("You hit the rock with all your might.");
- }
- return(1);
-}
-
-/* When will hole be finished? Very rough indication used by shopkeeper. */
-holetime() {
- return( (occupation == dig) ? (250 - dig_effort)/20 : -1);
-}
-
-dighole()
-{
- register struct trap *ttmp = t_at(u.ux, u.uy);
-
- if(!xdnstair) {
- pline("The floor here seems too hard to dig in.");
- } else {
- if(ttmp)
- ttmp->ttyp = TRAPDOOR;
- else
- ttmp = maketrap(u.ux, u.uy, TRAPDOOR);
- ttmp->tseen = 1;
- pline("You've made a hole in the floor.");
- if(!u.ustuck) {
- if(inshop())
- shopdig(1);
- pline("You fall through ...");
- if(u.utraptype == TT_PIT) {
- u.utrap = 0;
- u.utraptype = 0;
- }
- goto_level(dlevel+1, FALSE);
- }
- }
-}
-
-static
-use_pick_axe(obj)
-struct obj *obj;
-{
- char dirsyms[12];
- extern char sdir[];
- register char *dsp = dirsyms, *sdp = sdir;
- register struct monst *mtmp;
- register struct rm *lev;
- register int rx, ry, res = 0;
-
- if(obj != uwep) {
- if(uwep && uwep->cursed) {
- /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */
- pline("Since your weapon is welded to your hand,");
- pline("you cannot use that pick-axe.");
- return(0);
- }
- pline("You now wield %s.", doname(obj));
- setuwep(obj);
- res = 1;
- }
- while(*sdp) {
- (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */
- rx = u.ux + u.dx;
- ry = u.uy + u.dy;
- if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) &&
- (IS_ROCK(levl[rx][ry].typ)
- || sobj_at(ENORMOUS_ROCK, rx, ry))))
- *dsp++ = *sdp;
- sdp++;
- }
- *dsp = 0;
- pline("In what direction do you want to dig? [%s] ", dirsyms);
- if(!getdir(0)) /* no txt */
- return(res);
- if(u.uswallow && attack(u.ustuck)) /* return(1) */;
- else
- if(u.dz < 0)
- pline("You cannot reach the ceiling.");
- else
- if(u.dz == 0) {
- if(Confusion)
- confdir();
- rx = u.ux + u.dx;
- ry = u.uy + u.dy;
- if((mtmp = m_at(rx, ry)) && attack(mtmp))
- return(1);
- if(!isok(rx, ry)) {
- pline("Clash!");
- return(1);
- }
- lev = &levl[rx][ry];
- if(lev->typ == DOOR)
- pline("Your %s against the door.",
- aobjnam(obj, "clang"));
- else if(!IS_ROCK(lev->typ)
- && !sobj_at(ENORMOUS_ROCK, rx, ry)) {
- /* ACCESSIBLE or POOL */
- pline("You swing your %s through thin air.",
- aobjnam(obj, (char *) 0));
- } else {
- if(dig_pos.x != rx || dig_pos.y != ry
- || dig_level != dlevel || dig_down) {
- dig_down = FALSE;
- dig_pos.x = rx;
- dig_pos.y = ry;
- dig_level = dlevel;
- dig_effort = 0;
- pline("You start digging.");
- } else
- pline("You continue digging.");
- occupation = dig;
- occtxt = "digging";
- }
- } else if(Levitation) {
- pline("You cannot reach the floor.");
- } else {
- if(dig_pos.x != u.ux || dig_pos.y != u.uy
- || dig_level != dlevel || !dig_down) {
- dig_down = TRUE;
- dig_pos.x = u.ux;
- dig_pos.y = u.uy;
- dig_level = dlevel;
- dig_effort = 0;
- pline("You start digging in the floor.");
- if(inshop())
- shopdig(0);
- } else
- pline("You continue digging in the floor.");
- occupation = dig;
- occtxt = "digging";
- }
- return(1);
-}
diff --git a/games/hack/hack.bones.c b/games/hack/hack.bones.c
deleted file mode 100644
index d4a05b822212..000000000000
--- a/games/hack/hack.bones.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.bones.c - version 1.0.3 */
-
-#include "hack.h"
-extern char plname[PL_NSIZ];
-extern long somegold();
-extern struct monst *makemon();
-extern struct permonst pm_ghost;
-
-char bones[] = "bones_xx";
-
-/* save bones and possessions of a deceased adventurer */
-savebones(){
-register fd;
-register struct obj *otmp;
-register struct trap *ttmp;
-register struct monst *mtmp;
- if(dlevel <= 0 || dlevel > MAXLEVEL) return;
- if(!rn2(1 + dlevel/2)) return; /* not so many ghosts on low levels */
- bones[6] = '0' + (dlevel/10);
- bones[7] = '0' + (dlevel%10);
- if((fd = open(bones,0)) >= 0){
- (void) close(fd);
- return;
- }
- /* drop everything; the corpse's possessions are usually cursed */
- otmp = invent;
- while(otmp){
- otmp->ox = u.ux;
- otmp->oy = u.uy;
- otmp->age = 0; /* very long ago */
- otmp->owornmask = 0;
- if(rn2(5)) otmp->cursed = 1;
- if(!otmp->nobj){
- otmp->nobj = fobj;
- fobj = invent;
- invent = 0; /* superfluous */
- break;
- }
- otmp = otmp->nobj;
- }
- if(!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) return;
- mtmp->mx = u.ux;
- mtmp->my = u.uy;
- mtmp->msleep = 1;
- (void) strcpy((char *) mtmp->mextra, plname);
- mkgold(somegold() + d(dlevel,30), u.ux, u.uy);
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
- mtmp->m_id = 0;
- if(mtmp->mtame) {
- mtmp->mtame = 0;
- mtmp->mpeaceful = 0;
- }
- mtmp->mlstmv = 0;
- if(mtmp->mdispl) unpmon(mtmp);
- }
- for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
- ttmp->tseen = 0;
- for(otmp = fobj; otmp; otmp = otmp->nobj) {
- otmp->o_id = 0;
- /* otmp->o_cnt_id = 0; - superfluous */
- otmp->onamelth = 0;
- otmp->known = 0;
- otmp->invlet = 0;
- if(otmp->olet == AMULET_SYM && !otmp->spe) {
- otmp->spe = -1; /* no longer the actual amulet */
- otmp->cursed = 1; /* flag as gotten from a ghost */
- }
- }
- if((fd = creat(bones, FMASK)) < 0) return;
- savelev(fd,dlevel);
- (void) close(fd);
-}
-
-getbones(){
-register fd,x,y,ok;
- if(rn2(3)) return(0); /* only once in three times do we find bones */
- bones[6] = '0' + dlevel/10;
- bones[7] = '0' + dlevel%10;
- if((fd = open(bones, 0)) < 0) return(0);
- if((ok = uptodate(fd)) != 0){
- getlev(fd, 0, dlevel);
- for(x = 0; x < COLNO; x++) for(y = 0; y < ROWNO; y++)
- levl[x][y].seen = levl[x][y].new = 0;
- }
- (void) close(fd);
-#ifdef WIZARD
- if(!wizard) /* duvel!frans: don't remove bones while debugging */
-#endif WiZARD
- if(unlink(bones) < 0){
- pline("Cannot unlink %s .", bones);
- return(0);
- }
- return(ok);
-}
diff --git a/games/hack/hack.c b/games/hack/hack.c
deleted file mode 100644
index 5c8288144ed8..000000000000
--- a/games/hack/hack.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-
-extern char news0();
-extern char *nomovemsg;
-extern char *exclam();
-extern struct obj *addinv();
-extern boolean hmon();
-
-/* called on movement:
- 1. when throwing ball+chain far away
- 2. when teleporting
- 3. when walking out of a lit room
- */
-unsee() {
- register x,y;
- register struct rm *lev;
-
-/*
- if(u.udispl){
- u.udispl = 0;
- newsym(u.udisx, u.udisy);
- }
-*/
-#ifndef QUEST
- if(seehx){
- seehx = 0;
- } else
-#endif QUEST
- for(x = u.ux-1; x < u.ux+2; x++)
- for(y = u.uy-1; y < u.uy+2; y++) {
- if(!isok(x, y)) continue;
- lev = &levl[x][y];
- if(!lev->lit && lev->scrsym == '.') {
- lev->scrsym =' ';
- lev->new = 1;
- on_scr(x,y);
- }
- }
-}
-
-/* called:
- in hack.eat.c: seeoff(0) - blind after eating rotten food
- in hack.mon.c: seeoff(0) - blinded by a yellow light
- in hack.mon.c: seeoff(1) - swallowed
- in hack.do.c: seeoff(0) - blind after drinking potion
- in hack.do.c: seeoff(1) - go up or down the stairs
- in hack.trap.c:seeoff(1) - fall through trapdoor
- */
-seeoff(mode) /* 1 to redo @, 0 to leave them */
-{ /* 1 means misc movement, 0 means blindness */
- register x,y;
- register struct rm *lev;
-
- if(u.udispl && mode){
- u.udispl = 0;
- levl[u.udisx][u.udisy].scrsym = news0(u.udisx,u.udisy);
- }
-#ifndef QUEST
- if(seehx) {
- seehx = 0;
- } else
-#endif QUEST
- if(!mode) {
- for(x = u.ux-1; x < u.ux+2; x++)
- for(y = u.uy-1; y < u.uy+2; y++) {
- if(!isok(x, y)) continue;
- lev = &levl[x][y];
- if(!lev->lit && lev->scrsym == '.')
- lev->seen = 0;
- }
- }
-}
-
-domove()
-{
- xchar oldx,oldy;
- register struct monst *mtmp;
- register struct rm *tmpr,*ust;
- struct trap *trap;
- register struct obj *otmp;
-
- u_wipe_engr(rnd(5));
-
- if(inv_weight() > 0){
- pline("You collapse under your load.");
- nomul(0);
- return;
- }
- if(u.uswallow) {
- u.dx = u.dy = 0;
- u.ux = u.ustuck->mx;
- u.uy = u.ustuck->my;
- } else {
- if(Confusion) {
- do {
- confdir();
- } while(!isok(u.ux+u.dx, u.uy+u.dy) ||
- IS_ROCK(levl[u.ux+u.dx][u.uy+u.dy].typ));
- }
- if(!isok(u.ux+u.dx, u.uy+u.dy)){
- nomul(0);
- return;
- }
- }
-
- ust = &levl[u.ux][u.uy];
- oldx = u.ux;
- oldy = u.uy;
- if(!u.uswallow && (trap = t_at(u.ux+u.dx, u.uy+u.dy)) && trap->tseen)
- nomul(0);
- if(u.ustuck && !u.uswallow && (u.ux+u.dx != u.ustuck->mx ||
- u.uy+u.dy != u.ustuck->my)) {
- if(dist(u.ustuck->mx, u.ustuck->my) > 2){
- /* perhaps it fled (or was teleported or ... ) */
- u.ustuck = 0;
- } else {
- if(Blind) pline("You cannot escape from it!");
- else pline("You cannot escape from %s!",
- monnam(u.ustuck));
- nomul(0);
- return;
- }
- }
- if(u.uswallow || (mtmp = m_at(u.ux+u.dx,u.uy+u.dy))) {
- /* attack monster */
-
- nomul(0);
- gethungry();
- if(multi < 0) return; /* we just fainted */
-
- /* try to attack; note that it might evade */
- if(attack(u.uswallow ? u.ustuck : mtmp))
- return;
- }
- /* not attacking an animal, so we try to move */
- if(u.utrap) {
- if(u.utraptype == TT_PIT) {
- pline("You are still in a pit.");
- u.utrap--;
- } else {
- pline("You are caught in a beartrap.");
- if((u.dx && u.dy) || !rn2(5)) u.utrap--;
- }
- return;
- }
- tmpr = &levl[u.ux+u.dx][u.uy+u.dy];
- if(IS_ROCK(tmpr->typ) ||
- (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))){
- flags.move = 0;
- nomul(0);
- return;
- }
- while(otmp = sobj_at(ENORMOUS_ROCK, u.ux+u.dx, u.uy+u.dy)) {
- register xchar rx = u.ux+2*u.dx, ry = u.uy+2*u.dy;
- register struct trap *ttmp;
- nomul(0);
- if(isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
- (levl[rx][ry].typ != DOOR || !(u.dx && u.dy)) &&
- !sobj_at(ENORMOUS_ROCK, rx, ry)) {
- if(m_at(rx,ry)) {
- pline("You hear a monster behind the rock.");
- pline("Perhaps that's why you cannot move it.");
- goto cannot_push;
- }
- if(ttmp = t_at(rx,ry))
- switch(ttmp->ttyp) {
- case PIT:
- pline("You push the rock into a pit!");
- deltrap(ttmp);
- delobj(otmp);
- pline("It completely fills the pit!");
- continue;
- case TELEP_TRAP:
- pline("You push the rock and suddenly it disappears!");
- delobj(otmp);
- continue;
- }
- if(levl[rx][ry].typ == POOL) {
- levl[rx][ry].typ = ROOM;
- mnewsym(rx,ry);
- prl(rx,ry);
- pline("You push the rock into the water.");
- pline("Now you can cross the water!");
- delobj(otmp);
- continue;
- }
- otmp->ox = rx;
- otmp->oy = ry;
- /* pobj(otmp); */
- if(cansee(rx,ry)) atl(rx,ry,otmp->olet);
- if(Invisible) newsym(u.ux+u.dx, u.uy+u.dy);
-
- { static long lastmovetime;
- /* note: this var contains garbage initially and
- after a restore */
- if(moves > lastmovetime+2 || moves < lastmovetime)
- pline("With great effort you move the enormous rock.");
- lastmovetime = moves;
- }
- } else {
- pline("You try to move the enormous rock, but in vain.");
- cannot_push:
- if((!invent || inv_weight()+90 <= 0) &&
- (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][u.uy+u.dy].typ)
- && IS_ROCK(levl[u.ux+u.dx][u.uy].typ)))){
- pline("However, you can squeeze yourself into a small opening.");
- break;
- } else
- return;
- }
- }
- if(u.dx && u.dy && IS_ROCK(levl[u.ux][u.uy+u.dy].typ) &&
- IS_ROCK(levl[u.ux+u.dx][u.uy].typ) &&
- invent && inv_weight()+40 > 0) {
- pline("You are carrying too much to get through.");
- nomul(0);
- return;
- }
- if(Punished &&
- DIST(u.ux+u.dx, u.uy+u.dy, uchain->ox, uchain->oy) > 2){
- if(carried(uball)) {
- movobj(uchain, u.ux, u.uy);
- goto nodrag;
- }
-
- if(DIST(u.ux+u.dx, u.uy+u.dy, uball->ox, uball->oy) < 3){
- /* leave ball, move chain under/over ball */
- movobj(uchain, uball->ox, uball->oy);
- goto nodrag;
- }
-
- if(inv_weight() + (int) uball->owt/2 > 0) {
- pline("You cannot %sdrag the heavy iron ball.",
- invent ? "carry all that and also " : "");
- nomul(0);
- return;
- }
-
- movobj(uball, uchain->ox, uchain->oy);
- unpobj(uball); /* BAH %% */
- uchain->ox = u.ux;
- uchain->oy = u.uy;
- nomul(-2);
- nomovemsg = "";
- nodrag: ;
- }
- u.ux += u.dx;
- u.uy += u.dy;
- if(flags.run) {
- if(tmpr->typ == DOOR ||
- (xupstair == u.ux && yupstair == u.uy) ||
- (xdnstair == u.ux && ydnstair == u.uy))
- nomul(0);
- }
-
- if(tmpr->typ == POOL && !Levitation)
- drown(); /* not necessarily fatal */
-
-/*
- if(u.udispl) {
- u.udispl = 0;
- newsym(oldx,oldy);
- }
-*/
- if(!Blind) {
-#ifdef QUEST
- setsee();
-#else
- if(ust->lit) {
- if(tmpr->lit) {
- if(tmpr->typ == DOOR)
- prl1(u.ux+u.dx,u.uy+u.dy);
- else if(ust->typ == DOOR)
- nose1(oldx-u.dx,oldy-u.dy);
- } else {
- unsee();
- prl1(u.ux+u.dx,u.uy+u.dy);
- }
- } else {
- if(tmpr->lit) setsee();
- else {
- prl1(u.ux+u.dx,u.uy+u.dy);
- if(tmpr->typ == DOOR) {
- if(u.dy) {
- prl(u.ux-1,u.uy);
- prl(u.ux+1,u.uy);
- } else {
- prl(u.ux,u.uy-1);
- prl(u.ux,u.uy+1);
- }
- }
- }
- nose1(oldx-u.dx,oldy-u.dy);
- }
-#endif QUEST
- } else {
- pru();
- }
- if(!flags.nopick) pickup(1);
- if(trap) dotrap(trap); /* fall into pit, arrow trap, etc. */
- (void) inshop();
- if(!Blind) read_engr_at(u.ux,u.uy);
-}
-
-movobj(obj, ox, oy)
-register struct obj *obj;
-register int ox, oy;
-{
- /* Some dirty programming to get display right */
- freeobj(obj);
- unpobj(obj);
- obj->nobj = fobj;
- fobj = obj;
- obj->ox = ox;
- obj->oy = oy;
-}
-
-dopickup(){
- if(!g_at(u.ux,u.uy) && !o_at(u.ux,u.uy)) {
- pline("There is nothing here to pick up.");
- return(0);
- }
- if(Levitation) {
- pline("You cannot reach the floor.");
- return(1);
- }
- pickup(0);
- return(1);
-}
-
-pickup(all)
-{
- register struct gold *gold;
- register struct obj *obj, *obj2;
- register int wt;
-
- if(Levitation) return;
- while(gold = g_at(u.ux,u.uy)) {
- pline("%ld gold piece%s.", gold->amount, plur(gold->amount));
- u.ugold += gold->amount;
- flags.botl = 1;
- freegold(gold);
- if(flags.run) nomul(0);
- if(Invisible) newsym(u.ux,u.uy);
- }
-
- /* check for more than one object */
- if(!all) {
- register int ct = 0;
-
- for(obj = fobj; obj; obj = obj->nobj)
- if(obj->ox == u.ux && obj->oy == u.uy)
- if(!Punished || obj != uchain)
- ct++;
- if(ct < 2)
- all++;
- else
- pline("There are several objects here.");
- }
-
- for(obj = fobj; obj; obj = obj2) {
- obj2 = obj->nobj; /* perhaps obj will be picked up */
- if(obj->ox == u.ux && obj->oy == u.uy) {
- if(flags.run) nomul(0);
-
- /* do not pick up uchain */
- if(Punished && obj == uchain)
- continue;
-
- if(!all) {
- char c;
-
- pline("Pick up %s ? [ynaq]", doname(obj));
- while(!index("ynaq ", (c = readchar())))
- bell();
- if(c == 'q') return;
- if(c == 'n') continue;
- if(c == 'a') all = 1;
- }
-
- if(obj->otyp == DEAD_COCKATRICE && !uarmg){
- pline("Touching the dead cockatrice is a fatal mistake.");
- pline("You turn to stone.");
- killer = "cockatrice cadaver";
- done("died");
- }
-
- if(obj->otyp == SCR_SCARE_MONSTER){
- if(!obj->spe) obj->spe = 1;
- else {
- /* Note: perhaps the 1st pickup failed: you cannot
- carry anymore, and so we never dropped it -
- let's assume that treading on it twice also
- destroys the scroll */
- pline("The scroll turns to dust as you pick it up.");
- delobj(obj);
- continue;
- }
- }
-
- wt = inv_weight() + obj->owt;
- if(wt > 0) {
- if(obj->quan > 1) {
- /* see how many we can lift */
- extern struct obj *splitobj();
- int savequan = obj->quan;
- int iw = inv_weight();
- int qq;
- for(qq = 1; qq < savequan; qq++){
- obj->quan = qq;
- if(iw + weight(obj) > 0)
- break;
- }
- obj->quan = savequan;
- qq--;
- /* we can carry qq of them */
- if(!qq) goto too_heavy;
- pline("You can only carry %s of the %s lying here.",
- (qq == 1) ? "one" : "some",
- doname(obj));
- (void) splitobj(obj, qq);
- /* note: obj2 is set already, so we'll never
- * encounter the other half; if it should be
- * otherwise then write
- * obj2 = splitobj(obj,qq);
- */
- goto lift_some;
- }
- too_heavy:
- pline("There %s %s here, but %s.",
- (obj->quan == 1) ? "is" : "are",
- doname(obj),
- !invent ? "it is too heavy for you to lift"
- : "you cannot carry anymore");
- break;
- }
- lift_some:
- if(inv_cnt() >= 52) {
- pline("Your knapsack cannot accomodate anymore items.");
- break;
- }
- if(wt > -5) pline("You have a little trouble lifting");
- freeobj(obj);
- if(Invisible) newsym(u.ux,u.uy);
- addtobill(obj); /* sets obj->unpaid if necessary */
- { int pickquan = obj->quan;
- int mergquan;
- if(!Blind) obj->dknown = 1; /* this is done by prinv(),
- but addinv() needs it already for merging */
- obj = addinv(obj); /* might merge it with other objects */
- mergquan = obj->quan;
- obj->quan = pickquan; /* to fool prinv() */
- prinv(obj);
- obj->quan = mergquan;
- }
- }
- }
-}
-
-/* stop running if we see something interesting */
-/* turn around a corner if that is the only way we can proceed */
-/* do not turn left or right twice */
-lookaround(){
-register x,y,i,x0,y0,m0,i0 = 9;
-register int corrct = 0, noturn = 0;
-register struct monst *mtmp;
-#ifdef lint
- /* suppress "used before set" message */
- x0 = y0 = 0;
-#endif lint
- if(Blind || flags.run == 0) return;
- if(flags.run == 1 && levl[u.ux][u.uy].typ == ROOM) return;
-#ifdef QUEST
- if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop;
-#endif QUEST
- for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
- if(x == u.ux && y == u.uy) continue;
- if(!levl[x][y].typ) continue;
- if((mtmp = m_at(x,y)) && !mtmp->mimic &&
- (!mtmp->minvis || See_invisible)){
- if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy))
- goto stop;
- } else mtmp = 0; /* invisible M cannot influence us */
- if(x == u.ux-u.dx && y == u.uy-u.dy) continue;
- switch(levl[x][y].scrsym){
- case '|':
- case '-':
- case '.':
- case ' ':
- break;
- case '+':
- if(x != u.ux && y != u.uy) break;
- if(flags.run != 1) goto stop;
- /* fall into next case */
- case CORR_SYM:
- corr:
- if(flags.run == 1 || flags.run == 3) {
- i = DIST(x,y,u.ux+u.dx,u.uy+u.dy);
- if(i > 2) break;
- if(corrct == 1 && DIST(x,y,x0,y0) != 1)
- noturn = 1;
- if(i < i0) {
- i0 = i;
- x0 = x;
- y0 = y;
- m0 = mtmp ? 1 : 0;
- }
- }
- corrct++;
- break;
- case '^':
- if(flags.run == 1) goto corr; /* if you must */
- if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
- break;
- default: /* e.g. objects or trap or stairs */
- if(flags.run == 1) goto corr;
- if(mtmp) break; /* d */
- stop:
- nomul(0);
- return;
- }
- }
-#ifdef QUEST
- if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop;
-#endif QUEST
- if(corrct > 1 && flags.run == 2) goto stop;
- if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
- (corrct == 1 || (corrct == 2 && i0 == 1))) {
- /* make sure that we do not turn too far */
- if(i0 == 2) {
- if(u.dx == y0-u.uy && u.dy == u.ux-x0)
- i = 2; /* straight turn right */
- else
- i = -2; /* straight turn left */
- } else if(u.dx && u.dy) {
- if((u.dx == u.dy && y0 == u.uy) ||
- (u.dx != u.dy && y0 != u.uy))
- i = -1; /* half turn left */
- else
- i = 1; /* half turn right */
- } else {
- if((x0-u.ux == y0-u.uy && !u.dy) ||
- (x0-u.ux != y0-u.uy && u.dy))
- i = 1; /* half turn right */
- else
- i = -1; /* half turn left */
- }
- i += u.last_str_turn;
- if(i <= 2 && i >= -2) {
- u.last_str_turn = i;
- u.dx = x0-u.ux, u.dy = y0-u.uy;
- }
- }
-}
-
-/* something like lookaround, but we are not running */
-/* react only to monsters that might hit us */
-monster_nearby() {
-register int x,y;
-register struct monst *mtmp;
- if(!Blind)
- for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
- if(x == u.ux && y == u.uy) continue;
- if((mtmp = m_at(x,y)) && !mtmp->mimic && !mtmp->mtame &&
- !mtmp->mpeaceful && !index("Ea", mtmp->data->mlet) &&
- !mtmp->mfroz && !mtmp->msleep && /* aplvax!jcn */
- (!mtmp->minvis || See_invisible))
- return(1);
- }
- return(0);
-}
-
-#ifdef QUEST
-cansee(x,y) xchar x,y; {
-register int dx,dy,adx,ady,sdx,sdy,dmax,d;
- if(Blind) return(0);
- if(!isok(x,y)) return(0);
- d = dist(x,y);
- if(d < 3) return(1);
- if(d > u.uhorizon*u.uhorizon) return(0);
- if(!levl[x][y].lit)
- return(0);
- dx = x - u.ux; adx = abs(dx); sdx = sgn(dx);
- dy = y - u.uy; ady = abs(dy); sdy = sgn(dy);
- if(dx == 0 || dy == 0 || adx == ady){
- dmax = (dx == 0) ? ady : adx;
- for(d = 1; d <= dmax; d++)
- if(!rroom(sdx*d,sdy*d))
- return(0);
- return(1);
- } else if(ady > adx){
- for(d = 1; d <= ady; d++){
- if(!rroom(sdx*( (d*adx)/ady ), sdy*d) ||
- !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d))
- return(0);
- }
- return(1);
- } else {
- for(d = 1; d <= adx; d++){
- if(!rroom(sdx*d, sdy*( (d*ady)/adx )) ||
- !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 )))
- return(0);
- }
- return(1);
- }
-}
-
-rroom(x,y) register int x,y; {
- return(IS_ROOM(levl[u.ux+x][u.uy+y].typ));
-}
-
-#else
-
-cansee(x,y) xchar x,y; {
- if(Blind || u.uswallow) return(0);
- if(dist(x,y) < 3) return(1);
- if(levl[x][y].lit && seelx <= x && x <= seehx && seely <= y &&
- y <= seehy) return(1);
- return(0);
-}
-#endif QUEST
-
-sgn(a) register int a; {
- return((a > 0) ? 1 : (a == 0) ? 0 : -1);
-}
-
-#ifdef QUEST
-setsee()
-{
- register x,y;
-
- if(Blind) {
- pru();
- return;
- }
- for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++)
- for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) {
- if(cansee(x,y))
- prl(x,y);
- }
-}
-
-#else
-
-setsee()
-{
- register x,y;
-
- if(Blind) {
- pru();
- return;
- }
- if(!levl[u.ux][u.uy].lit) {
- seelx = u.ux-1;
- seehx = u.ux+1;
- seely = u.uy-1;
- seehy = u.uy+1;
- } else {
- for(seelx = u.ux; levl[seelx-1][u.uy].lit; seelx--);
- for(seehx = u.ux; levl[seehx+1][u.uy].lit; seehx++);
- for(seely = u.uy; levl[u.ux][seely-1].lit; seely--);
- for(seehy = u.uy; levl[u.ux][seehy+1].lit; seehy++);
- }
- for(y = seely; y <= seehy; y++)
- for(x = seelx; x <= seehx; x++) {
- prl(x,y);
- }
- if(!levl[u.ux][u.uy].lit) seehx = 0; /* seems necessary elsewhere */
- else {
- if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1);
- if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1);
- if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y);
- if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y);
- }
-}
-#endif QUEST
-
-nomul(nval)
-register nval;
-{
- if(multi < 0) return;
- multi = nval;
- flags.mv = flags.run = 0;
-}
-
-abon()
-{
- if(u.ustr == 3) return(-3);
- else if(u.ustr < 6) return(-2);
- else if(u.ustr < 8) return(-1);
- else if(u.ustr < 17) return(0);
- else if(u.ustr < 69) return(1); /* up to 18/50 */
- else if(u.ustr < 118) return(2);
- else return(3);
-}
-
-dbon()
-{
- if(u.ustr < 6) return(-1);
- else if(u.ustr < 16) return(0);
- else if(u.ustr < 18) return(1);
- else if(u.ustr == 18) return(2); /* up to 18 */
- else if(u.ustr < 94) return(3); /* up to 18/75 */
- else if(u.ustr < 109) return(4); /* up to 18/90 */
- else if(u.ustr < 118) return(5); /* up to 18/99 */
- else return(6);
-}
-
-losestr(num) /* may kill you; cause may be poison or monster like 'A' */
-register num;
-{
- u.ustr -= num;
- while(u.ustr < 3) {
- u.ustr++;
- u.uhp -= 6;
- u.uhpmax -= 6;
- }
- flags.botl = 1;
-}
-
-losehp(n,knam)
-register n;
-register char *knam;
-{
- u.uhp -= n;
- if(u.uhp > u.uhpmax)
- u.uhpmax = u.uhp; /* perhaps n was negative */
- flags.botl = 1;
- if(u.uhp < 1) {
- killer = knam; /* the thing that killed you */
- done("died");
- }
-}
-
-losehp_m(n,mtmp)
-register n;
-register struct monst *mtmp;
-{
- u.uhp -= n;
- flags.botl = 1;
- if(u.uhp < 1)
- done_in_by(mtmp);
-}
-
-losexp() /* hit by V or W */
-{
- register num;
- extern long newuexp();
-
- if(u.ulevel > 1)
- pline("Goodbye level %u.", u.ulevel--);
- else
- u.uhp = -1;
- num = rnd(10);
- u.uhp -= num;
- u.uhpmax -= num;
- u.uexp = newuexp();
- flags.botl = 1;
-}
-
-inv_weight(){
-register struct obj *otmp = invent;
-register int wt = (u.ugold + 500)/1000;
-register int carrcap;
- if(Levitation) /* pugh@cornell */
- carrcap = MAX_CARR_CAP;
- else {
- carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel);
- if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
- if(Wounded_legs & LEFT_SIDE) carrcap -= 10;
- if(Wounded_legs & RIGHT_SIDE) carrcap -= 10;
- }
- while(otmp){
- wt += otmp->owt;
- otmp = otmp->nobj;
- }
- return(wt - carrcap);
-}
-
-inv_cnt(){
-register struct obj *otmp = invent;
-register int ct = 0;
- while(otmp){
- ct++;
- otmp = otmp->nobj;
- }
- return(ct);
-}
-
-long
-newuexp()
-{
- return(10*(1L << (u.ulevel-1)));
-}
diff --git a/games/hack/hack.cmd.c b/games/hack/hack.cmd.c
deleted file mode 100644
index e36cfcca9d66..000000000000
--- a/games/hack/hack.cmd.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.cmd.c - version 1.0.3 */
-
-#include "hack.h"
-#include "def.func_tab.h"
-
-int doredraw(),doredotopl(),dodrop(),dodrink(),doread(),dosearch(),dopickup(),
-doversion(),doweararm(),dowearring(),doremarm(),doremring(),dopay(),doapply(),
-dosave(),dowield(),ddoinv(),dozap(),ddocall(),dowhatis(),doengrave(),dotele(),
-dohelp(),doeat(),doddrop(),do_mname(),doidtrap(),doprwep(),doprarm(),
-doprring(),doprgold(),dodiscovered(),dotypeinv(),dolook(),doset(),
-doup(), dodown(), done1(), donull(), dothrow(), doextcmd(), dodip(), dopray();
-#ifdef SHELL
-int dosh();
-#endif SHELL
-#ifdef SUSPEND
-int dosuspend();
-#endif SUSPEND
-
-struct func_tab cmdlist[]={
- '\020', doredotopl,
- '\022', doredraw,
- '\024', dotele,
-#ifdef SUSPEND
- '\032', dosuspend,
-#endif SUSPEND
- 'a', doapply,
-/* 'A' : UNUSED */
-/* 'b', 'B' : go sw */
- 'c', ddocall,
- 'C', do_mname,
- 'd', dodrop,
- 'D', doddrop,
- 'e', doeat,
- 'E', doengrave,
-/* 'f', 'F' : multiple go (might become 'fight') */
-/* 'g', 'G' : UNUSED */
-/* 'h', 'H' : go west */
- 'I', dotypeinv, /* Robert Viduya */
- 'i', ddoinv,
-/* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
-/* 'o', doopen, */
- 'O', doset,
- 'p', dopay,
- 'P', dowearring,
- 'q', dodrink,
- 'Q', done1,
- 'r', doread,
- 'R', doremring,
- 's', dosearch,
- 'S', dosave,
- 't', dothrow,
- 'T', doremarm,
-/* 'u', 'U' : go ne */
- 'v', doversion,
-/* 'V' : UNUSED */
- 'w', dowield,
- 'W', doweararm,
-/* 'x', 'X' : UNUSED */
-/* 'y', 'Y' : go nw */
- 'z', dozap,
-/* 'Z' : UNUSED */
- '<', doup,
- '>', dodown,
- '/', dowhatis,
- '?', dohelp,
-#ifdef SHELL
- '!', dosh,
-#endif SHELL
- '.', donull,
- ' ', donull,
- ',', dopickup,
- ':', dolook,
- '^', doidtrap,
- '\\', dodiscovered, /* Robert Viduya */
- WEAPON_SYM, doprwep,
- ARMOR_SYM, doprarm,
- RING_SYM, doprring,
- '$', doprgold,
- '#', doextcmd,
- 0,0,0
-};
-
-struct ext_func_tab extcmdlist[] = {
- "dip", dodip,
- "pray", dopray,
- (char *) 0, donull
-};
-
-extern char *parse(), lowc(), unctrl(), quitchars[];
-
-rhack(cmd)
-register char *cmd;
-{
- register struct func_tab *tlist = cmdlist;
- boolean firsttime = FALSE;
- register res;
-
- if(!cmd) {
- firsttime = TRUE;
- flags.nopick = 0;
- cmd = parse();
- }
- if(!*cmd || (*cmd & 0377) == 0377 ||
- (flags.no_rest_on_space && *cmd == ' ')){
- bell();
- flags.move = 0;
- return; /* probably we just had an interrupt */
- }
- if(movecmd(*cmd)) {
- walk:
- if(multi) flags.mv = 1;
- domove();
- return;
- }
- if(movecmd(lowc(*cmd))) {
- flags.run = 1;
- rush:
- if(firsttime){
- if(!multi) multi = COLNO;
- u.last_str_turn = 0;
- }
- flags.mv = 1;
-#ifdef QUEST
- if(flags.run >= 4) finddir();
- if(firsttime){
- u.ux0 = u.ux + u.dx;
- u.uy0 = u.uy + u.dy;
- }
-#endif QUEST
- domove();
- return;
- }
- if((*cmd == 'f' && movecmd(cmd[1])) || movecmd(unctrl(*cmd))) {
- flags.run = 2;
- goto rush;
- }
- if(*cmd == 'F' && movecmd(lowc(cmd[1]))) {
- flags.run = 3;
- goto rush;
- }
- if(*cmd == 'm' && movecmd(cmd[1])) {
- flags.run = 0;
- flags.nopick = 1;
- goto walk;
- }
- if(*cmd == 'M' && movecmd(lowc(cmd[1]))) {
- flags.run = 1;
- flags.nopick = 1;
- goto rush;
- }
-#ifdef QUEST
- if(*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) {
- flags.run = 4;
- if(*cmd == 'F') flags.run += 2;
- if(cmd[2] == '-') flags.run += 1;
- goto rush;
- }
-#endif QUEST
- while(tlist->f_char) {
- if(*cmd == tlist->f_char){
- res = (*(tlist->f_funct))();
- if(!res) {
- flags.move = 0;
- multi = 0;
- }
- return;
- }
- tlist++;
- }
- { char expcmd[10];
- register char *cp = expcmd;
- while(*cmd && cp-expcmd < sizeof(expcmd)-2) {
- if(*cmd >= 040 && *cmd < 0177)
- *cp++ = *cmd++;
- else {
- *cp++ = '^';
- *cp++ = *cmd++ ^ 0100;
- }
- }
- *cp++ = 0;
- pline("Unknown command '%s'.", expcmd);
- }
- multi = flags.move = 0;
-}
-
-doextcmd() /* here after # - now read a full-word command */
-{
- char buf[BUFSZ];
- register struct ext_func_tab *efp = extcmdlist;
-
- pline("# ");
- getlin(buf);
- clrlin();
- if(buf[0] == '\033')
- return(0);
- while(efp->ef_txt) {
- if(!strcmp(efp->ef_txt, buf))
- return((*(efp->ef_funct))());
- efp++;
- }
- pline("%s: unknown command.", buf);
- return(0);
-}
-
-char
-lowc(sym)
-char sym;
-{
- return( (sym >= 'A' && sym <= 'Z') ? sym+'a'-'A' : sym );
-}
-
-char
-unctrl(sym)
-char sym;
-{
- return( (sym >= ('A' & 037) && sym <= ('Z' & 037)) ? sym + 0140 : sym );
-}
-
-/* 'rogue'-like direction commands */
-char sdir[] = "hykulnjb><";
-schar xdir[10] = { -1,-1, 0, 1, 1, 1, 0,-1, 0, 0 };
-schar ydir[10] = { 0,-1,-1,-1, 0, 1, 1, 1, 0, 0 };
-schar zdir[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1,-1 };
-
-movecmd(sym) /* also sets u.dz, but returns false for <> */
-char sym;
-{
- register char *dp;
-
- u.dz = 0;
- if(!(dp = index(sdir, sym))) return(0);
- u.dx = xdir[dp-sdir];
- u.dy = ydir[dp-sdir];
- u.dz = zdir[dp-sdir];
- return(!u.dz);
-}
-
-getdir(s)
-boolean s;
-{
- char dirsym;
-
- if(s) pline("In what direction?");
- dirsym = readchar();
- if(!movecmd(dirsym) && !u.dz) {
- if(!index(quitchars, dirsym))
- pline("What a strange direction!");
- return(0);
- }
- if(Confusion && !u.dz)
- confdir();
- return(1);
-}
-
-confdir()
-{
- register x = rn2(8);
- u.dx = xdir[x];
- u.dy = ydir[x];
-}
-
-#ifdef QUEST
-finddir(){
-register int i, ui = u.di;
- for(i = 0; i <= 8; i++){
- if(flags.run & 1) ui++; else ui += 7;
- ui %= 8;
- if(i == 8){
- pline("Not near a wall.");
- flags.move = multi = 0;
- return(0);
- }
- if(!isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
- break;
- }
- for(i = 0; i <= 8; i++){
- if(flags.run & 1) ui += 7; else ui++;
- ui %= 8;
- if(i == 8){
- pline("Not near a room.");
- flags.move = multi = 0;
- return(0);
- }
- if(isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
- break;
- }
- u.di = ui;
- u.dx = xdir[ui];
- u.dy = ydir[ui];
-}
-
-isroom(x,y) register x,y; { /* what about POOL? */
- return(isok(x,y) && (levl[x][y].typ == ROOM ||
- (levl[x][y].typ >= LDOOR && flags.run >= 6)));
-}
-#endif QUEST
-
-isok(x,y) register x,y; {
- /* x corresponds to curx, so x==1 is the first column. Ach. %% */
- return(x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1);
-}
diff --git a/games/hack/hack.do.c b/games/hack/hack.do.c
deleted file mode 100644
index 1227eb923dd8..000000000000
--- a/games/hack/hack.do.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.do.c - version 1.0.3 */
-
-/* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */
-
-#include "hack.h"
-
-extern struct obj *splitobj(), *addinv();
-extern boolean hmon();
-extern boolean level_exists[];
-extern struct monst youmonst;
-extern char *Doname();
-extern char *nomovemsg;
-
-static int drop();
-
-dodrop() {
- return(drop(getobj("0$#", "drop")));
-}
-
-static int
-drop(obj) register struct obj *obj; {
- if(!obj) return(0);
- if(obj->olet == '$') { /* pseudo object */
- register long amount = OGOLD(obj);
-
- if(amount == 0)
- pline("You didn't drop any gold pieces.");
- else {
- mkgold(amount, u.ux, u.uy);
- pline("You dropped %ld gold piece%s.",
- amount, plur(amount));
- if(Invisible) newsym(u.ux, u.uy);
- }
- free((char *) obj);
- return(1);
- }
- if(obj->owornmask & (W_ARMOR | W_RING)){
- pline("You cannot drop something you are wearing.");
- return(0);
- }
- if(obj == uwep) {
- if(uwep->cursed) {
- pline("Your weapon is welded to your hand!");
- return(0);
- }
- setuwep((struct obj *) 0);
- }
- pline("You dropped %s.", doname(obj));
- dropx(obj);
- return(1);
-}
-
-/* Called in several places - should not produce texts */
-dropx(obj)
-register struct obj *obj;
-{
- freeinv(obj);
- dropy(obj);
-}
-
-dropy(obj)
-register struct obj *obj;
-{
- if(obj->otyp == CRYSKNIFE)
- obj->otyp = WORM_TOOTH;
- obj->ox = u.ux;
- obj->oy = u.uy;
- obj->nobj = fobj;
- fobj = obj;
- if(Invisible) newsym(u.ux,u.uy);
- subfrombill(obj);
- stackobj(obj);
-}
-
-/* drop several things */
-doddrop() {
- return(ggetobj("drop", drop, 0));
-}
-
-dodown()
-{
- if(u.ux != xdnstair || u.uy != ydnstair) {
- pline("You can't go down here.");
- return(0);
- }
- if(u.ustuck) {
- pline("You are being held, and cannot go down.");
- return(1);
- }
- if(Levitation) {
- pline("You're floating high above the stairs.");
- return(0);
- }
-
- goto_level(dlevel+1, TRUE);
- return(1);
-}
-
-doup()
-{
- if(u.ux != xupstair || u.uy != yupstair) {
- pline("You can't go up here.");
- return(0);
- }
- if(u.ustuck) {
- pline("You are being held, and cannot go up.");
- return(1);
- }
- if(!Levitation && inv_weight() + 5 > 0) {
- pline("Your load is too heavy to climb the stairs.");
- return(1);
- }
-
- goto_level(dlevel-1, TRUE);
- return(1);
-}
-
-goto_level(newlevel, at_stairs)
-register int newlevel;
-register boolean at_stairs;
-{
- register fd;
- register boolean up = (newlevel < dlevel);
-
- if(newlevel <= 0) done("escaped"); /* in fact < 0 is impossible */
- if(newlevel > MAXLEVEL) newlevel = MAXLEVEL; /* strange ... */
- if(newlevel == dlevel) return; /* this can happen */
-
- glo(dlevel);
- fd = creat(lock, FMASK);
- if(fd < 0) {
- /*
- * This is not quite impossible: e.g., we may have
- * exceeded our quota. If that is the case then we
- * cannot leave this level, and cannot save either.
- * Another possibility is that the directory was not
- * writable.
- */
- pline("A mysterious force prevents you from going %s.",
- up ? "up" : "down");
- return;
- }
-
- if(Punished) unplacebc();
- u.utrap = 0; /* needed in level_tele */
- u.ustuck = 0; /* idem */
- keepdogs();
- seeoff(1);
- if(u.uswallow) /* idem */
- u.uswldtim = u.uswallow = 0;
- flags.nscrinh = 1;
- u.ux = FAR; /* hack */
- (void) inshop(); /* probably was a trapdoor */
-
- savelev(fd,dlevel);
- (void) close(fd);
-
- dlevel = newlevel;
- if(maxdlevel < dlevel)
- maxdlevel = dlevel;
- glo(dlevel);
-
- if(!level_exists[dlevel])
- mklev();
- else {
- extern int hackpid;
-
- if((fd = open(lock,0)) < 0) {
- pline("Cannot open %s .", lock);
- pline("Probably someone removed it.");
- done("tricked");
- }
- getlev(fd, hackpid, dlevel);
- (void) close(fd);
- }
-
- if(at_stairs) {
- if(up) {
- u.ux = xdnstair;
- u.uy = ydnstair;
- if(!u.ux) { /* entering a maze from below? */
- u.ux = xupstair; /* this will confuse the player! */
- u.uy = yupstair;
- }
- if(Punished && !Levitation){
- pline("With great effort you climb the stairs.");
- placebc(1);
- }
- } else {
- u.ux = xupstair;
- u.uy = yupstair;
- if(inv_weight() + 5 > 0 || Punished){
- pline("You fall down the stairs."); /* %% */
- losehp(rnd(3), "fall");
- if(Punished) {
- if(uwep != uball && rn2(3)){
- pline("... and are hit by the iron ball.");
- losehp(rnd(20), "iron ball");
- }
- placebc(1);
- }
- selftouch("Falling, you");
- }
- }
- { register struct monst *mtmp = m_at(u.ux, u.uy);
- if(mtmp)
- mnexto(mtmp);
- }
- } else { /* trapdoor or level_tele */
- do {
- u.ux = rnd(COLNO-1);
- u.uy = rn2(ROWNO);
- } while(levl[u.ux][u.uy].typ != ROOM ||
- m_at(u.ux,u.uy));
- if(Punished){
- if(uwep != uball && !up /* %% */ && rn2(5)){
- pline("The iron ball falls on your head.");
- losehp(rnd(25), "iron ball");
- }
- placebc(1);
- }
- selftouch("Falling, you");
- }
- (void) inshop();
- initrack();
-
- losedogs();
- { register struct monst *mtmp;
- if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp); /* riv05!a3 */
- }
- flags.nscrinh = 0;
- setsee();
- seeobjs(); /* make old cadavers disappear - riv05!a3 */
- docrt();
- pickup(1);
- read_engr_at(u.ux,u.uy);
-}
-
-donull() {
- return(1); /* Do nothing, but let other things happen */
-}
-
-dopray() {
- nomovemsg = "You finished your prayer.";
- nomul(-3);
- return(1);
-}
-
-struct monst *bhit(), *boomhit();
-dothrow()
-{
- register struct obj *obj;
- register struct monst *mon;
- register tmp;
-
- obj = getobj("#)", "throw"); /* it is also possible to throw food */
- /* (or jewels, or iron balls ... ) */
- if(!obj || !getdir(1)) /* ask "in what direction?" */
- return(0);
- if(obj->owornmask & (W_ARMOR | W_RING)){
- pline("You can't throw something you are wearing.");
- return(0);
- }
-
- u_wipe_engr(2);
-
- if(obj == uwep){
- if(obj->cursed){
- pline("Your weapon is welded to your hand.");
- return(1);
- }
- if(obj->quan > 1)
- setuwep(splitobj(obj, 1));
- else
- setuwep((struct obj *) 0);
- }
- else if(obj->quan > 1)
- (void) splitobj(obj, 1);
- freeinv(obj);
- if(u.uswallow) {
- mon = u.ustuck;
- bhitpos.x = mon->mx;
- bhitpos.y = mon->my;
- } else if(u.dz) {
- if(u.dz < 0) {
- pline("%s hits the ceiling, then falls back on top of your head.",
- Doname(obj)); /* note: obj->quan == 1 */
- if(obj->olet == POTION_SYM)
- potionhit(&youmonst, obj);
- else {
- if(uarmh) pline("Fortunately, you are wearing a helmet!");
- losehp(uarmh ? 1 : rnd((int)(obj->owt)), "falling object");
- dropy(obj);
- }
- } else {
- pline("%s hits the floor.", Doname(obj));
- if(obj->otyp == EXPENSIVE_CAMERA) {
- pline("It is shattered in a thousand pieces!");
- obfree(obj, Null(obj));
- } else if(obj->otyp == EGG) {
- pline("\"Splash!\"");
- obfree(obj, Null(obj));
- } else if(obj->olet == POTION_SYM) {
- pline("The flask breaks, and you smell a peculiar odor ...");
- potionbreathe(obj);
- obfree(obj, Null(obj));
- } else {
- dropy(obj);
- }
- }
- return(1);
- } else if(obj->otyp == BOOMERANG) {
- mon = boomhit(u.dx, u.dy);
- if(mon == &youmonst) { /* the thing was caught */
- (void) addinv(obj);
- return(1);
- }
- } else {
- if(obj->otyp == PICK_AXE && shkcatch(obj))
- return(1);
-
- mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 :
- (!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1,
- obj->olet,
- (int (*)()) 0, (int (*)()) 0, obj);
- }
- if(mon) {
- /* awake monster if sleeping */
- wakeup(mon);
-
- if(obj->olet == WEAPON_SYM) {
- tmp = -1+u.ulevel+mon->data->ac+abon();
- if(obj->otyp < ROCK) {
- if(!uwep ||
- uwep->otyp != obj->otyp+(BOW-ARROW))
- tmp -= 4;
- else {
- tmp += uwep->spe;
- }
- } else
- if(obj->otyp == BOOMERANG) tmp += 4;
- tmp += obj->spe;
- if(u.uswallow || tmp >= rnd(20)) {
- if(hmon(mon,obj,1) == TRUE){
- /* mon still alive */
-#ifndef NOWORM
- cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp);
-#endif NOWORM
- } else mon = 0;
- /* weapons thrown disappear sometimes */
- if(obj->otyp < BOOMERANG && rn2(3)) {
- /* check bill; free */
- obfree(obj, (struct obj *) 0);
- return(1);
- }
- } else miss(objects[obj->otyp].oc_name, mon);
- } else if(obj->otyp == HEAVY_IRON_BALL) {
- tmp = -1+u.ulevel+mon->data->ac+abon();
- if(!Punished || obj != uball) tmp += 2;
- if(u.utrap) tmp -= 2;
- if(u.uswallow || tmp >= rnd(20)) {
- if(hmon(mon,obj,1) == FALSE)
- mon = 0; /* he died */
- } else miss("iron ball", mon);
- } else if(obj->olet == POTION_SYM && u.ulevel > rn2(15)) {
- potionhit(mon, obj);
- return(1);
- } else {
- if(cansee(bhitpos.x,bhitpos.y))
- pline("You miss %s.",monnam(mon));
- else pline("You miss it.");
- if(obj->olet == FOOD_SYM && mon->data->mlet == 'd')
- if(tamedog(mon,obj)) return(1);
- if(obj->olet == GEM_SYM && mon->data->mlet == 'u' &&
- !mon->mtame){
- if(obj->dknown && objects[obj->otyp].oc_name_known){
- if(objects[obj->otyp].g_val > 0){
- u.uluck += 5;
- goto valuable;
- } else {
- pline("%s is not interested in your junk.",
- Monnam(mon));
- }
- } else { /* value unknown to @ */
- u.uluck++;
- valuable:
- if(u.uluck > LUCKMAX) /* dan@ut-ngp */
- u.uluck = LUCKMAX;
- pline("%s graciously accepts your gift.",
- Monnam(mon));
- mpickobj(mon, obj);
- rloc(mon);
- return(1);
- }
- }
- }
- }
- /* the code following might become part of dropy() */
- if(obj->otyp == CRYSKNIFE)
- obj->otyp = WORM_TOOTH;
- obj->ox = bhitpos.x;
- obj->oy = bhitpos.y;
- obj->nobj = fobj;
- fobj = obj;
- /* prevent him from throwing articles to the exit and escaping */
- /* subfrombill(obj); */
- stackobj(obj);
- if(Punished && obj == uball &&
- (bhitpos.x != u.ux || bhitpos.y != u.uy)){
- freeobj(uchain);
- unpobj(uchain);
- if(u.utrap){
- if(u.utraptype == TT_PIT)
- pline("The ball pulls you out of the pit!");
- else {
- register long side =
- rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
- pline("The ball pulls you out of the bear trap.");
- pline("Your %s leg is severely damaged.",
- (side == LEFT_SIDE) ? "left" : "right");
- set_wounded_legs(side, 500+rn2(1000));
- losehp(2, "thrown ball");
- }
- u.utrap = 0;
- }
- unsee();
- uchain->nobj = fobj;
- fobj = uchain;
- u.ux = uchain->ox = bhitpos.x - u.dx;
- u.uy = uchain->oy = bhitpos.y - u.dy;
- setsee();
- (void) inshop();
- }
- if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
- return(1);
-}
-
-/* split obj so that it gets size num */
-/* remainder is put in the object structure delivered by this call */
-struct obj *
-splitobj(obj, num) register struct obj *obj; register int num; {
-register struct obj *otmp;
- otmp = newobj(0);
- *otmp = *obj; /* copies whole structure */
- otmp->o_id = flags.ident++;
- otmp->onamelth = 0;
- obj->quan = num;
- obj->owt = weight(obj);
- otmp->quan -= num;
- otmp->owt = weight(otmp); /* -= obj->owt ? */
- obj->nobj = otmp;
- if(obj->unpaid) splitbill(obj,otmp);
- return(otmp);
-}
-
-more_experienced(exp,rexp)
-register int exp, rexp;
-{
- extern char pl_character[];
-
- u.uexp += exp;
- u.urexp += 4*exp + rexp;
- if(exp) flags.botl = 1;
- if(u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000))
- flags.beginner = 0;
-}
-
-set_wounded_legs(side, timex)
-register long side;
-register int timex;
-{
- if(!Wounded_legs || (Wounded_legs & TIMEOUT))
- Wounded_legs |= side + timex;
- else
- Wounded_legs |= side;
-}
-
-heal_legs()
-{
- if(Wounded_legs) {
- if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
- pline("Your legs feel somewhat better.");
- else
- pline("Your leg feels somewhat better.");
- Wounded_legs = 0;
- }
-}
diff --git a/games/hack/hack.do_name.c b/games/hack/hack.do_name.c
deleted file mode 100644
index 72ac62c86253..000000000000
--- a/games/hack/hack.do_name.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.do_name.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-extern char plname[];
-
-coord
-getpos(force,goal) int force; char *goal; {
-register cx,cy,i,c;
-extern char sdir[]; /* defined in hack.c */
-extern schar xdir[], ydir[]; /* idem */
-extern char *visctrl(); /* see below */
-coord cc;
- pline("(For instructions type a ?)");
- cx = u.ux;
- cy = u.uy;
- curs(cx,cy+2);
- while((c = readchar()) != '.'){
- for(i=0; i<8; i++) if(sdir[i] == c){
- if(1 <= cx + xdir[i] && cx + xdir[i] <= COLNO)
- cx += xdir[i];
- if(0 <= cy + ydir[i] && cy + ydir[i] <= ROWNO-1)
- cy += ydir[i];
- goto nxtc;
- }
- if(c == '?'){
- pline("Use [hjkl] to move the cursor to %s.", goal);
- pline("Type a . when you are at the right place.");
- } else {
- pline("Unknown direction: '%s' (%s).",
- visctrl(c),
- force ? "use hjkl or ." : "aborted");
- if(force) goto nxtc;
- cc.x = -1;
- cc.y = 0;
- return(cc);
- }
- nxtc: ;
- curs(cx,cy+2);
- }
- cc.x = cx;
- cc.y = cy;
- return(cc);
-}
-
-do_mname(){
-char buf[BUFSZ];
-coord cc;
-register int cx,cy,lth,i;
-register struct monst *mtmp, *mtmp2;
-extern char *lmonnam();
- cc = getpos(0, "the monster you want to name");
- cx = cc.x;
- cy = cc.y;
- if(cx < 0) return(0);
- mtmp = m_at(cx,cy);
- if(!mtmp){
- if(cx == u.ux && cy == u.uy)
- pline("This ugly monster is called %s and cannot be renamed.",
- plname);
- else
- pline("There is no monster there.");
- return(1);
- }
- if(mtmp->mimic){
- pline("I see no monster there.");
- return(1);
- }
- if(!cansee(cx,cy)) {
- pline("I cannot see a monster there.");
- return(1);
- }
- pline("What do you want to call %s? ", lmonnam(mtmp));
- getlin(buf);
- clrlin();
- if(!*buf || *buf == '\033')
- return(1);
- lth = strlen(buf)+1;
- if(lth > 63){
- buf[62] = 0;
- lth = 63;
- }
- mtmp2 = newmonst(mtmp->mxlth + lth);
- *mtmp2 = *mtmp;
- for(i=0; i<mtmp->mxlth; i++)
- ((char *) mtmp2->mextra)[i] = ((char *) mtmp->mextra)[i];
- mtmp2->mnamelth = lth;
- (void) strcpy(NAME(mtmp2), buf);
- replmon(mtmp,mtmp2);
- return(1);
-}
-
-/*
- * This routine changes the address of obj . Be careful not to call it
- * when there might be pointers around in unknown places. For now: only
- * when obj is in the inventory.
- */
-do_oname(obj) register struct obj *obj; {
-register struct obj *otmp, *otmp2;
-register lth;
-char buf[BUFSZ];
- pline("What do you want to name %s? ", doname(obj));
- getlin(buf);
- clrlin();
- if(!*buf || *buf == '\033')
- return;
- lth = strlen(buf)+1;
- if(lth > 63){
- buf[62] = 0;
- lth = 63;
- }
- otmp2 = newobj(lth);
- *otmp2 = *obj;
- otmp2->onamelth = lth;
- (void) strcpy(ONAME(otmp2), buf);
-
- setworn((struct obj *) 0, obj->owornmask);
- setworn(otmp2, otmp2->owornmask);
-
- /* do freeinv(obj); etc. by hand in order to preserve
- the position of this object in the inventory */
- if(obj == invent) invent = otmp2;
- else for(otmp = invent; ; otmp = otmp->nobj){
- if(!otmp)
- panic("Do_oname: cannot find obj.");
- if(otmp->nobj == obj){
- otmp->nobj = otmp2;
- break;
- }
- }
- /* obfree(obj, otmp2); /* now unnecessary: no pointers on bill */
- free((char *) obj); /* let us hope nobody else saved a pointer */
-}
-
-ddocall()
-{
- register struct obj *obj;
-
- pline("Do you want to name an individual object? [ny] ");
- switch(readchar()) {
- case '\033':
- break;
- case 'y':
- obj = getobj("#", "name");
- if(obj) do_oname(obj);
- break;
- default:
- obj = getobj("?!=/", "call");
- if(obj) docall(obj);
- }
- return(0);
-}
-
-docall(obj)
-register struct obj *obj;
-{
- char buf[BUFSZ];
- struct obj otemp;
- register char **str1;
- extern char *xname();
- register char *str;
-
- otemp = *obj;
- otemp.quan = 1;
- otemp.onamelth = 0;
- str = xname(&otemp);
- pline("Call %s %s: ", index(vowels,*str) ? "an" : "a", str);
- getlin(buf);
- clrlin();
- if(!*buf || *buf == '\033')
- return;
- str = newstring(strlen(buf)+1);
- (void) strcpy(str,buf);
- str1 = &(objects[obj->otyp].oc_uname);
- if(*str1) free(*str1);
- *str1 = str;
-}
-
-char *ghostnames[] = { /* these names should have length < PL_NSIZ */
- "adri", "andries", "andreas", "bert", "david", "dirk", "emile",
- "frans", "fred", "greg", "hether", "jay", "john", "jon", "kay",
- "kenny", "maud", "michiel", "mike", "peter", "robert", "ron",
- "tom", "wilmar"
-};
-
-char *
-xmonnam(mtmp, vb) register struct monst *mtmp; int vb; {
-static char buf[BUFSZ]; /* %% */
-extern char *shkname();
- if(mtmp->mnamelth && !vb) {
- (void) strcpy(buf, NAME(mtmp));
- return(buf);
- }
- switch(mtmp->data->mlet) {
- case ' ':
- { register char *gn = (char *) mtmp->mextra;
- if(!*gn) { /* might also look in scorefile */
- gn = ghostnames[rn2(SIZE(ghostnames))];
- if(!rn2(2)) (void)
- strcpy((char *) mtmp->mextra, !rn2(5) ? plname : gn);
- }
- (void) sprintf(buf, "%s's ghost", gn);
- }
- break;
- case '@':
- if(mtmp->isshk) {
- (void) strcpy(buf, shkname(mtmp));
- break;
- }
- /* fall into next case */
- default:
- (void) sprintf(buf, "the %s%s",
- mtmp->minvis ? "invisible " : "",
- mtmp->data->mname);
- }
- if(vb && mtmp->mnamelth) {
- (void) strcat(buf, " called ");
- (void) strcat(buf, NAME(mtmp));
- }
- return(buf);
-}
-
-char *
-lmonnam(mtmp) register struct monst *mtmp; {
- return(xmonnam(mtmp, 1));
-}
-
-char *
-monnam(mtmp) register struct monst *mtmp; {
- return(xmonnam(mtmp, 0));
-}
-
-char *
-Monnam(mtmp) register struct monst *mtmp; {
-register char *bp = monnam(mtmp);
- if('a' <= *bp && *bp <= 'z') *bp += ('A' - 'a');
- return(bp);
-}
-
-char *
-amonnam(mtmp,adj)
-register struct monst *mtmp;
-register char *adj;
-{
- register char *bp = monnam(mtmp);
- static char buf[BUFSZ]; /* %% */
-
- if(!strncmp(bp, "the ", 4)) bp += 4;
- (void) sprintf(buf, "the %s %s", adj, bp);
- return(buf);
-}
-
-char *
-Amonnam(mtmp, adj)
-register struct monst *mtmp;
-register char *adj;
-{
- register char *bp = amonnam(mtmp,adj);
-
- *bp = 'T';
- return(bp);
-}
-
-char *
-Xmonnam(mtmp) register struct monst *mtmp; {
-register char *bp = Monnam(mtmp);
- if(!strncmp(bp, "The ", 4)) {
- bp += 2;
- *bp = 'A';
- }
- return(bp);
-}
-
-char *
-visctrl(c)
-char c;
-{
-static char ccc[3];
- if(c < 040) {
- ccc[0] = '^';
- ccc[1] = c + 0100;
- ccc[2] = 0;
- } else {
- ccc[0] = c;
- ccc[1] = 0;
- }
- return(ccc);
-}
diff --git a/games/hack/hack.do_wear.c b/games/hack/hack.do_wear.c
deleted file mode 100644
index 423955d2940a..000000000000
--- a/games/hack/hack.do_wear.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.do_wear.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-extern char *nomovemsg;
-extern char quitchars[];
-extern char *Doname();
-
-off_msg(otmp) register struct obj *otmp; {
- pline("You were wearing %s.", doname(otmp));
-}
-
-doremarm() {
- register struct obj *otmp;
- if(!uarm && !uarmh && !uarms && !uarmg) {
- pline("Not wearing any armor.");
- return(0);
- }
- otmp = (!uarmh && !uarms && !uarmg) ? uarm :
- (!uarms && !uarm && !uarmg) ? uarmh :
- (!uarmh && !uarm && !uarmg) ? uarms :
- (!uarmh && !uarm && !uarms) ? uarmg :
- getobj("[", "take off");
- if(!otmp) return(0);
- if(!(otmp->owornmask & (W_ARMOR - W_ARM2))) {
- pline("You can't take that off.");
- return(0);
- }
- if( otmp == uarmg && uwep && uwep->cursed ) { /* myers@uwmacc */
- pline("You seem not able to take off the gloves while holding your weapon.");
- return(0);
- }
- (void) armoroff(otmp);
- return(1);
-}
-
-doremring() {
- if(!uleft && !uright){
- pline("Not wearing any ring.");
- return(0);
- }
- if(!uleft)
- return(dorr(uright));
- if(!uright)
- return(dorr(uleft));
- if(uleft && uright) while(1) {
- char answer;
-
- pline("What ring, Right or Left? [ rl?]");
- if(index(quitchars, (answer = readchar())))
- return(0);
- switch(answer) {
- case 'l':
- case 'L':
- return(dorr(uleft));
- case 'r':
- case 'R':
- return(dorr(uright));
- case '?':
- (void) doprring();
- /* might look at morc here %% */
- }
- }
- /* NOTREACHED */
-#ifdef lint
- return(0);
-#endif lint
-}
-
-dorr(otmp) register struct obj *otmp; {
- if(cursed(otmp)) return(0);
- ringoff(otmp);
- off_msg(otmp);
- return(1);
-}
-
-cursed(otmp) register struct obj *otmp; {
- if(otmp->cursed){
- pline("You can't. It appears to be cursed.");
- return(1);
- }
- return(0);
-}
-
-armoroff(otmp) register struct obj *otmp; {
-register int delay = -objects[otmp->otyp].oc_delay;
- if(cursed(otmp)) return(0);
- setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
- if(delay) {
- nomul(delay);
- switch(otmp->otyp) {
- case HELMET:
- nomovemsg = "You finished taking off your helmet.";
- break;
- case PAIR_OF_GLOVES:
- nomovemsg = "You finished taking off your gloves";
- break;
- default:
- nomovemsg = "You finished taking off your suit.";
- }
- } else {
- off_msg(otmp);
- }
- return(1);
-}
-
-doweararm() {
- register struct obj *otmp;
- register int delay;
- register int err = 0;
- long mask = 0;
-
- otmp = getobj("[", "wear");
- if(!otmp) return(0);
- if(otmp->owornmask & W_ARMOR) {
- pline("You are already wearing that!");
- return(0);
- }
- if(otmp->otyp == HELMET){
- if(uarmh) {
- pline("You are already wearing a helmet.");
- err++;
- } else
- mask = W_ARMH;
- } else if(otmp->otyp == SHIELD){
- if(uarms) pline("You are already wearing a shield."), err++;
- if(uwep && uwep->otyp == TWO_HANDED_SWORD)
- pline("You cannot wear a shield and wield a two-handed sword."), err++;
- if(!err) mask = W_ARMS;
- } else if(otmp->otyp == PAIR_OF_GLOVES) {
- if(uarmg) {
- pline("You are already wearing gloves.");
- err++;
- } else
- if(uwep && uwep->cursed) {
- pline("You cannot wear gloves over your weapon.");
- err++;
- } else
- mask = W_ARMG;
- } else {
- if(uarm) {
- if(otmp->otyp != ELVEN_CLOAK || uarm2) {
- pline("You are already wearing some armor.");
- err++;
- }
- }
- if(!err) mask = W_ARM;
- }
- if(otmp == uwep && uwep->cursed) {
- if(!err++)
- pline("%s is welded to your hand.", Doname(uwep));
- }
- if(err) return(0);
- setworn(otmp, mask);
- if(otmp == uwep)
- setuwep((struct obj *) 0);
- delay = -objects[otmp->otyp].oc_delay;
- if(delay){
- nomul(delay);
- nomovemsg = "You finished your dressing manoeuvre.";
- }
- otmp->known = 1;
- return(1);
-}
-
-dowearring() {
- register struct obj *otmp;
- long mask = 0;
- long oldprop;
-
- if(uleft && uright){
- pline("There are no more ring-fingers to fill.");
- return(0);
- }
- otmp = getobj("=", "wear");
- if(!otmp) return(0);
- if(otmp->owornmask & W_RING) {
- pline("You are already wearing that!");
- return(0);
- }
- if(otmp == uleft || otmp == uright) {
- pline("You are already wearing that.");
- return(0);
- }
- if(otmp == uwep && uwep->cursed) {
- pline("%s is welded to your hand.", Doname(uwep));
- return(0);
- }
- if(uleft) mask = RIGHT_RING;
- else if(uright) mask = LEFT_RING;
- else do {
- char answer;
-
- pline("What ring-finger, Right or Left? ");
- if(index(quitchars, (answer = readchar())))
- return(0);
- switch(answer){
- case 'l':
- case 'L':
- mask = LEFT_RING;
- break;
- case 'r':
- case 'R':
- mask = RIGHT_RING;
- break;
- }
- } while(!mask);
- setworn(otmp, mask);
- if(otmp == uwep)
- setuwep((struct obj *) 0);
- oldprop = u.uprops[PROP(otmp->otyp)].p_flgs;
- u.uprops[PROP(otmp->otyp)].p_flgs |= mask;
- switch(otmp->otyp){
- case RIN_LEVITATION:
- if(!oldprop) float_up();
- break;
- case RIN_PROTECTION_FROM_SHAPE_CHANGERS:
- rescham();
- break;
- case RIN_GAIN_STRENGTH:
- u.ustr += otmp->spe;
- u.ustrmax += otmp->spe;
- if(u.ustr > 118) u.ustr = 118;
- if(u.ustrmax > 118) u.ustrmax = 118;
- flags.botl = 1;
- break;
- case RIN_INCREASE_DAMAGE:
- u.udaminc += otmp->spe;
- break;
- }
- prinv(otmp);
- return(1);
-}
-
-ringoff(obj)
-register struct obj *obj;
-{
-register long mask;
- mask = obj->owornmask & W_RING;
- setworn((struct obj *) 0, obj->owornmask);
- if(!(u.uprops[PROP(obj->otyp)].p_flgs & mask))
- impossible("Strange... I didnt know you had that ring.");
- u.uprops[PROP(obj->otyp)].p_flgs &= ~mask;
- switch(obj->otyp) {
- case RIN_FIRE_RESISTANCE:
- /* Bad luck if the player is in hell... --jgm */
- if (!Fire_resistance && dlevel >= 30) {
- pline("The flames of Hell burn you to a crisp.");
- killer = "stupidity in hell";
- done("burned");
- }
- break;
- case RIN_LEVITATION:
- if(!Levitation) { /* no longer floating */
- float_down();
- }
- break;
- case RIN_GAIN_STRENGTH:
- u.ustr -= obj->spe;
- u.ustrmax -= obj->spe;
- if(u.ustr > 118) u.ustr = 118;
- if(u.ustrmax > 118) u.ustrmax = 118;
- flags.botl = 1;
- break;
- case RIN_INCREASE_DAMAGE:
- u.udaminc -= obj->spe;
- break;
- }
-}
-
-find_ac(){
-register int uac = 10;
- if(uarm) uac -= ARM_BONUS(uarm);
- if(uarm2) uac -= ARM_BONUS(uarm2);
- if(uarmh) uac -= ARM_BONUS(uarmh);
- if(uarms) uac -= ARM_BONUS(uarms);
- if(uarmg) uac -= ARM_BONUS(uarmg);
- if(uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe;
- if(uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe;
- if(uac != u.uac){
- u.uac = uac;
- flags.botl = 1;
- }
-}
-
-glibr(){
-register struct obj *otmp;
-int xfl = 0;
- if(!uarmg) if(uleft || uright) {
- /* Note: at present also cursed rings fall off */
- pline("Your %s off your fingers.",
- (uleft && uright) ? "rings slip" : "ring slips");
- xfl++;
- if((otmp = uleft) != Null(obj)){
- ringoff(uleft);
- dropx(otmp);
- }
- if((otmp = uright) != Null(obj)){
- ringoff(uright);
- dropx(otmp);
- }
- }
- if((otmp = uwep) != Null(obj)){
- /* Note: at present also cursed weapons fall */
- setuwep((struct obj *) 0);
- dropx(otmp);
- pline("Your weapon %sslips from your hands.",
- xfl ? "also " : "");
- }
-}
-
-struct obj *
-some_armor(){
-register struct obj *otmph = uarm;
- if(uarmh && (!otmph || !rn2(4))) otmph = uarmh;
- if(uarmg && (!otmph || !rn2(4))) otmph = uarmg;
- if(uarms && (!otmph || !rn2(4))) otmph = uarms;
- return(otmph);
-}
-
-corrode_armor(){
-register struct obj *otmph = some_armor();
- if(otmph){
- if(otmph->rustfree ||
- otmph->otyp == ELVEN_CLOAK ||
- otmph->otyp == LEATHER_ARMOR ||
- otmph->otyp == STUDDED_LEATHER_ARMOR) {
- pline("Your %s not affected!",
- aobjnam(otmph, "are"));
- return;
- }
- pline("Your %s!", aobjnam(otmph, "corrode"));
- otmph->spe--;
- }
-}
diff --git a/games/hack/hack.dog.c b/games/hack/hack.dog.c
deleted file mode 100644
index aa4387abbee9..000000000000
--- a/games/hack/hack.dog.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.dog.c - version 1.0.3 */
-
-#include "hack.h"
-#include "hack.mfndpos.h"
-extern struct monst *makemon();
-#include "def.edog.h"
-#include "def.mkroom.h"
-
-struct permonst li_dog =
- { "little dog", 'd',2,18,6,1,6,sizeof(struct edog) };
-struct permonst dog =
- { "dog", 'd',4,16,5,1,6,sizeof(struct edog) };
-struct permonst la_dog =
- { "large dog", 'd',6,15,4,2,4,sizeof(struct edog) };
-
-
-makedog(){
-register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy);
- if(!mtmp) return; /* dogs were genocided */
- initedog(mtmp);
-}
-
-initedog(mtmp) register struct monst *mtmp; {
- mtmp->mtame = mtmp->mpeaceful = 1;
- EDOG(mtmp)->hungrytime = 1000 + moves;
- EDOG(mtmp)->eattime = 0;
- EDOG(mtmp)->droptime = 0;
- EDOG(mtmp)->dropdist = 10000;
- EDOG(mtmp)->apport = 10;
- EDOG(mtmp)->whistletime = 0;
-}
-
-/* attach the monsters that went down (or up) together with @ */
-struct monst *mydogs = 0;
-struct monst *fallen_down = 0; /* monsters that fell through a trapdoor */
- /* they will appear on the next level @ goes to, even if he goes up! */
-
-losedogs(){
-register struct monst *mtmp;
- while(mtmp = mydogs){
- mydogs = mtmp->nmon;
- mtmp->nmon = fmon;
- fmon = mtmp;
- mnexto(mtmp);
- }
- while(mtmp = fallen_down){
- fallen_down = mtmp->nmon;
- mtmp->nmon = fmon;
- fmon = mtmp;
- rloc(mtmp);
- }
-}
-
-keepdogs(){
-register struct monst *mtmp;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(dist(mtmp->mx,mtmp->my) < 3 && follower(mtmp)
- && !mtmp->msleep && !mtmp->mfroz) {
- relmon(mtmp);
- mtmp->nmon = mydogs;
- mydogs = mtmp;
- unpmon(mtmp);
- keepdogs(); /* we destroyed the link, so use recursion */
- return; /* (admittedly somewhat primitive) */
- }
-}
-
-fall_down(mtmp) register struct monst *mtmp; {
- relmon(mtmp);
- mtmp->nmon = fallen_down;
- fallen_down = mtmp;
- unpmon(mtmp);
- mtmp->mtame = 0;
-}
-
-/* return quality of food; the lower the better */
-#define DOGFOOD 0
-#define CADAVER 1
-#define ACCFOOD 2
-#define MANFOOD 3
-#define APPORT 4
-#define POISON 5
-#define UNDEF 6
-dogfood(obj) register struct obj *obj; {
- switch(obj->olet) {
- case FOOD_SYM:
- return(
- (obj->otyp == TRIPE_RATION) ? DOGFOOD :
- (obj->otyp < CARROT) ? ACCFOOD :
- (obj->otyp < CORPSE) ? MANFOOD :
- (poisonous(obj) || obj->age + 50 <= moves ||
- obj->otyp == DEAD_COCKATRICE)
- ? POISON : CADAVER
- );
- default:
- if(!obj->cursed) return(APPORT);
- /* fall into next case */
- case BALL_SYM:
- case CHAIN_SYM:
- case ROCK_SYM:
- return(UNDEF);
- }
-}
-
-/* return 0 (no move), 1 (move) or 2 (dead) */
-dog_move(mtmp, after) register struct monst *mtmp; {
-register int nx,ny,omx,omy,appr,nearer,j;
-int udist,chi,i,whappr;
-register struct monst *mtmp2;
-register struct permonst *mdat = mtmp->data;
-register struct edog *edog = EDOG(mtmp);
-struct obj *obj;
-struct trap *trap;
-xchar cnt,chcnt,nix,niy;
-schar dogroom,uroom;
-xchar gx,gy,gtyp,otyp; /* current goal */
-coord poss[9];
-int info[9];
-#define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
-#define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
-
- if(moves <= edog->eattime) return(0); /* dog is still eating */
- omx = mtmp->mx;
- omy = mtmp->my;
- whappr = (moves - EDOG(mtmp)->whistletime < 5);
- if(moves > edog->hungrytime + 500 && !mtmp->mconf){
- mtmp->mconf = 1;
- mtmp->mhpmax /= 3;
- if(mtmp->mhp > mtmp->mhpmax)
- mtmp->mhp = mtmp->mhpmax;
- if(cansee(omx,omy))
- pline("%s is confused from hunger.", Monnam(mtmp));
- else pline("You feel worried about %s.", monnam(mtmp));
- } else
- if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){
- if(cansee(omx,omy))
- pline("%s dies from hunger.", Monnam(mtmp));
- else
- pline("You have a sad feeling for a moment, then it passes.");
- mondied(mtmp);
- return(2);
- }
- dogroom = inroom(omx,omy);
- uroom = inroom(u.ux,u.uy);
- udist = dist(omx,omy);
-
- /* maybe we tamed him while being swallowed --jgm */
- if(!udist) return(0);
-
- /* if we are carrying sth then we drop it (perhaps near @) */
- /* Note: if apport == 1 then our behaviour is independent of udist */
- if(mtmp->minvent){
- if(!rn2(udist) || !rn2((int) edog->apport))
- if(rn2(10) < edog->apport){
- relobj(mtmp, (int) mtmp->minvis);
- if(edog->apport > 1) edog->apport--;
- edog->dropdist = udist; /* hpscdi!jon */
- edog->droptime = moves;
- }
- } else {
- if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){
- if((otyp = dogfood(obj)) <= CADAVER){
- nix = omx;
- niy = omy;
- goto eatobj;
- }
- if(obj->owt < 10*mtmp->data->mlevel)
- if(rn2(20) < edog->apport+3)
- if(rn2(udist) || !rn2((int) edog->apport)){
- freeobj(obj);
- unpobj(obj);
- /* if(levl[omx][omy].scrsym == obj->olet)
- newsym(omx,omy); */
- mpickobj(mtmp,obj);
- }
- }
- }
-
- /* first we look for food */
- gtyp = UNDEF; /* no goal as yet */
-#ifdef LINT
- gx = gy = 0; /* suppress 'used before set' message */
-#endif LINT
- for(obj = fobj; obj; obj = obj->nobj) {
- otyp = dogfood(obj);
- if(otyp > gtyp || otyp == UNDEF) continue;
- if(inroom(obj->ox,obj->oy) != dogroom) continue;
- if(otyp < MANFOOD &&
- (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) {
- if(otyp < gtyp || (otyp == gtyp &&
- DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){
- gx = obj->ox;
- gy = obj->oy;
- gtyp = otyp;
- }
- } else
- if(gtyp == UNDEF && dogroom >= 0 &&
- uroom == dogroom &&
- !mtmp->minvent && edog->apport > rn2(8)){
- gx = obj->ox;
- gy = obj->oy;
- gtyp = APPORT;
- }
- }
- if(gtyp == UNDEF ||
- (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){
- if(dogroom < 0 || dogroom == uroom){
- gx = u.ux;
- gy = u.uy;
-#ifndef QUEST
- } else {
- int tmp = rooms[dogroom].fdoor;
- cnt = rooms[dogroom].doorct;
-
- gx = gy = FAR; /* random, far away */
- while(cnt--){
- if(dist(gx,gy) >
- dist(doors[tmp].x, doors[tmp].y)){
- gx = doors[tmp].x;
- gy = doors[tmp].y;
- }
- tmp++;
- }
- /* here gx == FAR e.g. when dog is in a vault */
- if(gx == FAR || (gx == omx && gy == omy)){
- gx = u.ux;
- gy = u.uy;
- }
-#endif QUEST
- }
- appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
- if(after && udist <= 4 && gx == u.ux && gy == u.uy)
- return(0);
- if(udist > 1){
- if(!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
- whappr ||
- (mtmp->minvent && rn2((int) edog->apport)))
- appr = 1;
- }
- /* if you have dog food he'll follow you more closely */
- if(appr == 0){
- obj = invent;
- while(obj){
- if(obj->otyp == TRIPE_RATION){
- appr = 1;
- break;
- }
- obj = obj->nobj;
- }
- }
- } else appr = 1; /* gtyp != UNDEF */
- if(mtmp->mconf) appr = 0;
-
- if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){
- extern coord *gettrack();
- register coord *cp;
- cp = gettrack(omx,omy);
- if(cp){
- gx = cp->x;
- gy = cp->y;
- }
- }
-
- nix = omx;
- niy = omy;
- cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS);
- chcnt = 0;
- chi = -1;
- for(i=0; i<cnt; i++){
- nx = poss[i].x;
- ny = poss[i].y;
- if(info[i] & ALLOW_M){
- mtmp2 = m_at(nx,ny);
- if(mtmp2->data->mlevel >= mdat->mlevel+2 ||
- mtmp2->data->mlet == 'c')
- continue;
- if(after) return(0); /* hit only once each move */
-
- if(hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
- mtmp2->mlstmv != moves &&
- hitmm(mtmp2,mtmp) == 2) return(2);
- return(0);
- }
-
- /* dog avoids traps */
- /* but perhaps we have to pass a trap in order to follow @ */
- if((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))){
- if(!trap->tseen && rn2(40)) continue;
- if(rn2(10)) continue;
- }
-
- /* dog eschewes cursed objects */
- /* but likes dog food */
- obj = fobj;
- while(obj){
- if(obj->ox != nx || obj->oy != ny)
- goto nextobj;
- if(obj->cursed) goto nxti;
- if(obj->olet == FOOD_SYM &&
- (otyp = dogfood(obj)) < MANFOOD &&
- (otyp < ACCFOOD || edog->hungrytime <= moves)){
- /* Note: our dog likes the food so much that he
- might eat it even when it conceals a cursed object */
- nix = nx;
- niy = ny;
- chi = i;
- eatobj:
- edog->eattime =
- moves + obj->quan * objects[obj->otyp].oc_delay;
- if(edog->hungrytime < moves)
- edog->hungrytime = moves;
- edog->hungrytime +=
- 5*obj->quan * objects[obj->otyp].nutrition;
- mtmp->mconf = 0;
- if(cansee(nix,niy))
- pline("%s ate %s.", Monnam(mtmp), doname(obj));
- /* perhaps this was a reward */
- if(otyp != CADAVER)
- edog->apport += 200/(edog->dropdist+moves-edog->droptime);
- delobj(obj);
- goto newdogpos;
- }
- nextobj:
- obj = obj->nobj;
- }
-
- for(j=0; j<MTSZ && j<cnt-1; j++)
- if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
- if(rn2(4*(cnt-j))) goto nxti;
-
-/* Some stupid C compilers cannot compute the whole expression at once. */
- nearer = GDIST(nx,ny);
- nearer -= GDIST(nix,niy);
- nearer *= appr;
- if((nearer == 0 && !rn2(++chcnt)) || nearer<0 ||
- (nearer > 0 && !whappr &&
- ((omx == nix && omy == niy && !rn2(3))
- || !rn2(12))
- )){
- nix = nx;
- niy = ny;
- if(nearer < 0) chcnt = 0;
- chi = i;
- }
- nxti: ;
- }
-newdogpos:
- if(nix != omx || niy != omy){
- if(info[chi] & ALLOW_U){
- (void) hitu(mtmp, d(mdat->damn, mdat->damd)+1);
- return(0);
- }
- mtmp->mx = nix;
- mtmp->my = niy;
- for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
- mtmp->mtrack[0].x = omx;
- mtmp->mtrack[0].y = omy;
- }
- if(mintrap(mtmp) == 2) /* he died */
- return(2);
- pmon(mtmp);
- return(1);
-}
-
-/* return roomnumber or -1 */
-inroom(x,y) xchar x,y; {
-#ifndef QUEST
- register struct mkroom *croom = &rooms[0];
- while(croom->hx >= 0){
- if(croom->hx >= x-1 && croom->lx <= x+1 &&
- croom->hy >= y-1 && croom->ly <= y+1)
- return(croom - rooms);
- croom++;
- }
-#endif QUEST
- return(-1); /* not in room or on door */
-}
-
-tamedog(mtmp, obj)
-register struct monst *mtmp;
-register struct obj *obj;
-{
- register struct monst *mtmp2;
-
- if(flags.moonphase == FULL_MOON && night() && rn2(6))
- return(0);
-
- /* If we cannot tame him, at least he's no longer afraid. */
- mtmp->mflee = 0;
- mtmp->mfleetim = 0;
- if(mtmp->mtame || mtmp->mfroz ||
-#ifndef NOWORM
- mtmp->wormno ||
-#endif NOWORM
- mtmp->isshk || mtmp->isgd || index(" &@12", mtmp->data->mlet))
- return(0); /* no tame long worms? */
- if(obj) {
- if(dogfood(obj) >= MANFOOD) return(0);
- if(cansee(mtmp->mx,mtmp->my)){
- pline("%s devours the %s.", Monnam(mtmp),
- objects[obj->otyp].oc_name);
- }
- obfree(obj, (struct obj *) 0);
- }
- mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
- *mtmp2 = *mtmp;
- mtmp2->mxlth = sizeof(struct edog);
- if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp));
- initedog(mtmp2);
- replmon(mtmp,mtmp2);
- return(1);
-}
diff --git a/games/hack/hack.eat.c b/games/hack/hack.eat.c
deleted file mode 100644
index f1a767779af1..000000000000
--- a/games/hack/hack.eat.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.eat.c - version 1.0.3 */
-
-#include "hack.h"
-char POISONOUS[] = "ADKSVabhks";
-extern char *nomovemsg;
-extern int (*afternmv)();
-extern int (*occupation)();
-extern char *occtxt;
-extern struct obj *splitobj(), *addinv();
-
-/* hunger texts used on bottom line (each 8 chars long) */
-#define SATIATED 0
-#define NOT_HUNGRY 1
-#define HUNGRY 2
-#define WEAK 3
-#define FAINTING 4
-#define FAINTED 5
-#define STARVED 6
-
-char *hu_stat[] = {
- "Satiated",
- " ",
- "Hungry ",
- "Weak ",
- "Fainting",
- "Fainted ",
- "Starved "
-};
-
-init_uhunger(){
- u.uhunger = 900;
- u.uhs = NOT_HUNGRY;
-}
-
-#define TTSZ SIZE(tintxts)
-struct { char *txt; int nut; } tintxts[] = {
- "It contains first quality peaches - what a surprise!", 40,
- "It contains salmon - not bad!", 60,
- "It contains apple juice - perhaps not what you hoped for.", 20,
- "It contains some nondescript substance, tasting awfully.", 500,
- "It contains rotten meat. You vomit.", -50,
- "It turns out to be empty.", 0
-};
-
-static struct {
- struct obj *tin;
- int usedtime, reqtime;
-} tin;
-
-opentin(){
- register int r;
-
- if(!carried(tin.tin)) /* perhaps it was stolen? */
- return(0); /* %% probably we should use tinoid */
- if(tin.usedtime++ >= 50) {
- pline("You give up your attempt to open the tin.");
- return(0);
- }
- if(tin.usedtime < tin.reqtime)
- return(1); /* still busy */
-
- pline("You succeed in opening the tin.");
- useup(tin.tin);
- r = rn2(2*TTSZ);
- if(r < TTSZ){
- pline(tintxts[r].txt);
- lesshungry(tintxts[r].nut);
- if(r == 1) /* SALMON */ {
- Glib = rnd(15);
- pline("Eating salmon made your fingers very slippery.");
- }
- } else {
- pline("It contains spinach - this makes you feel like Popeye!");
- lesshungry(600);
- if(u.ustr < 118)
- u.ustr += rnd( ((u.ustr < 17) ? 19 : 118) - u.ustr);
- if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
- flags.botl = 1;
- }
- return(0);
-}
-
-Meatdone(){
- u.usym = '@';
- prme();
-}
-
-doeat(){
- register struct obj *otmp;
- register struct objclass *ftmp;
- register tmp;
-
- /* Is there some food (probably a heavy corpse) here on the ground? */
- if(!Levitation)
- for(otmp = fobj; otmp; otmp = otmp->nobj) {
- if(otmp->ox == u.ux && otmp->oy == u.uy &&
- otmp->olet == FOOD_SYM) {
- pline("There %s %s here; eat %s? [ny] ",
- (otmp->quan == 1) ? "is" : "are",
- doname(otmp),
- (otmp->quan == 1) ? "it" : "one");
- if(readchar() == 'y') {
- if(otmp->quan != 1)
- (void) splitobj(otmp, 1);
- freeobj(otmp);
- otmp = addinv(otmp);
- addtobill(otmp);
- goto gotit;
- }
- }
- }
- otmp = getobj("%", "eat");
- if(!otmp) return(0);
-gotit:
- if(otmp->otyp == TIN){
- if(uwep) {
- switch(uwep->otyp) {
- case CAN_OPENER:
- tmp = 1;
- break;
- case DAGGER:
- case CRYSKNIFE:
- tmp = 3;
- break;
- case PICK_AXE:
- case AXE:
- tmp = 6;
- break;
- default:
- goto no_opener;
- }
- pline("Using your %s you try to open the tin.",
- aobjnam(uwep, (char *) 0));
- } else {
- no_opener:
- pline("It is not so easy to open this tin.");
- if(Glib) {
- pline("The tin slips out of your hands.");
- if(otmp->quan > 1) {
- register struct obj *obj;
- extern struct obj *splitobj();
-
- obj = splitobj(otmp, 1);
- if(otmp == uwep) setuwep(obj);
- }
- dropx(otmp);
- return(1);
- }
- tmp = 10 + rn2(1 + 500/((int)(u.ulevel + u.ustr)));
- }
- tin.reqtime = tmp;
- tin.usedtime = 0;
- tin.tin = otmp;
- occupation = opentin;
- occtxt = "opening the tin";
- return(1);
- }
- ftmp = &objects[otmp->otyp];
- multi = -ftmp->oc_delay;
- if(otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx;
- if(!rn2(7) && otmp->otyp != FORTUNE_COOKIE) {
- pline("Blecch! Rotten food!");
- if(!rn2(4)) {
- pline("You feel rather light headed.");
- Confusion += d(2,4);
- } else if(!rn2(4)&& !Blind) {
- pline("Everything suddenly goes dark.");
- Blind = d(2,10);
- seeoff(0);
- } else if(!rn2(3)) {
- if(Blind)
- pline("The world spins and you slap against the floor.");
- else
- pline("The world spins and goes dark.");
- nomul(-rnd(10));
- nomovemsg = "You are conscious again.";
- }
- lesshungry(ftmp->nutrition / 4);
- } else {
- if(u.uhunger >= 1500) {
- pline("You choke over your food.");
- pline("You die...");
- killer = ftmp->oc_name;
- done("choked");
- }
- switch(otmp->otyp){
- case FOOD_RATION:
- if(u.uhunger <= 200)
- pline("That food really hit the spot!");
- else if(u.uhunger <= 700)
- pline("That satiated your stomach!");
- else {
- pline("You're having a hard time getting all that food down.");
- multi -= 2;
- }
- lesshungry(ftmp->nutrition);
- if(multi < 0) nomovemsg = "You finished your meal.";
- break;
- case TRIPE_RATION:
- pline("Yak - dog food!");
- more_experienced(1,0);
- flags.botl = 1;
- if(rn2(2)){
- pline("You vomit.");
- morehungry(20);
- if(Sick) {
- Sick = 0; /* David Neves */
- pline("What a relief!");
- }
- } else lesshungry(ftmp->nutrition);
- break;
- default:
- if(otmp->otyp >= CORPSE)
- pline("That %s tasted terrible!",ftmp->oc_name);
- else
- pline("That %s was delicious!",ftmp->oc_name);
- lesshungry(ftmp->nutrition);
- if(otmp->otyp == DEAD_LIZARD && (Confusion > 2))
- Confusion = 2;
- else
-#ifdef QUEST
- if(otmp->otyp == CARROT && !Blind){
- u.uhorizon++;
- setsee();
- pline("Your vision improves.");
- } else
-#endif QUEST
- if(otmp->otyp == FORTUNE_COOKIE) {
- if(Blind) {
- pline("This cookie has a scrap of paper inside!");
- pline("What a pity, that you cannot read it!");
- } else
- outrumor();
- } else
- if(otmp->otyp == LUMP_OF_ROYAL_JELLY) {
- /* This stuff seems to be VERY healthy! */
- if(u.ustrmax < 118) u.ustrmax++;
- if(u.ustr < u.ustrmax) u.ustr++;
- u.uhp += rnd(20);
- if(u.uhp > u.uhpmax) {
- if(!rn2(17)) u.uhpmax++;
- u.uhp = u.uhpmax;
- }
- heal_legs();
- }
- break;
- }
- }
-eatx:
- if(multi<0 && !nomovemsg){
- static char msgbuf[BUFSZ];
- (void) sprintf(msgbuf, "You finished eating the %s.",
- ftmp->oc_name);
- nomovemsg = msgbuf;
- }
- useup(otmp);
- return(1);
-}
-
-/* called in hack.main.c */
-gethungry(){
- --u.uhunger;
- if(moves % 2) {
- if(Regeneration) u.uhunger--;
- if(Hunger) u.uhunger--;
- /* a3: if(Hunger & LEFT_RING) u.uhunger--;
- if(Hunger & RIGHT_RING) u.uhunger--;
- etc. */
- }
- if(moves % 20 == 0) { /* jimt@asgb */
- if(uleft) u.uhunger--;
- if(uright) u.uhunger--;
- }
- newuhs(TRUE);
-}
-
-/* called after vomiting and after performing feats of magic */
-morehungry(num) register num; {
- u.uhunger -= num;
- newuhs(TRUE);
-}
-
-/* called after eating something (and after drinking fruit juice) */
-lesshungry(num) register num; {
- u.uhunger += num;
- newuhs(FALSE);
-}
-
-unfaint(){
- u.uhs = FAINTING;
- flags.botl = 1;
-}
-
-newuhs(incr) boolean incr; {
- register int newhs, h = u.uhunger;
-
- newhs = (h > 1000) ? SATIATED :
- (h > 150) ? NOT_HUNGRY :
- (h > 50) ? HUNGRY :
- (h > 0) ? WEAK : FAINTING;
-
- if(newhs == FAINTING) {
- if(u.uhs == FAINTED)
- newhs = FAINTED;
- if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
- if(u.uhs != FAINTED && multi >= 0 /* %% */) {
- pline("You faint from lack of food.");
- nomul(-10+(u.uhunger/10));
- nomovemsg = "You regain consciousness.";
- afternmv = unfaint;
- newhs = FAINTED;
- }
- } else
- if(u.uhunger < -(int)(200 + 25*u.ulevel)) {
- u.uhs = STARVED;
- flags.botl = 1;
- bot();
- pline("You die from starvation.");
- done("starved");
- }
- }
-
- if(newhs != u.uhs) {
- if(newhs >= WEAK && u.uhs < WEAK)
- losestr(1); /* this may kill you -- see below */
- else
- if(newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax)
- losestr(-1);
- switch(newhs){
- case HUNGRY:
- pline((!incr) ? "You only feel hungry now." :
- (u.uhunger < 145) ? "You feel hungry." :
- "You are beginning to feel hungry.");
- break;
- case WEAK:
- pline((!incr) ? "You feel weak now." :
- (u.uhunger < 45) ? "You feel weak." :
- "You are beginning to feel weak.");
- break;
- }
- u.uhs = newhs;
- flags.botl = 1;
- if(u.uhp < 1) {
- pline("You die from hunger and exhaustion.");
- killer = "exhaustion";
- done("starved");
- }
- }
-}
-
-#define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
- ? 'a' + (otyp - DEAD_ACID_BLOB)\
- : '@' + (otyp - DEAD_HUMAN))
-poisonous(otmp)
-register struct obj *otmp;
-{
- return(index(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0);
-}
-
-/* returns 1 if some text was printed */
-eatcorpse(otmp) register struct obj *otmp; {
-register char let = CORPSE_I_TO_C(otmp->otyp);
-register tp = 0;
- if(let != 'a' && moves > otmp->age + 50 + rn2(100)) {
- tp++;
- pline("Ulch -- that meat was tainted!");
- pline("You get very sick.");
- Sick = 10 + rn2(10);
- u.usick_cause = objects[otmp->otyp].oc_name;
- } else if(index(POISONOUS, let) && rn2(5)){
- tp++;
- pline("Ecch -- that must have been poisonous!");
- if(!Poison_resistance){
- losestr(rnd(4));
- losehp(rnd(15), "poisonous corpse");
- } else
- pline("You don't seem affected by the poison.");
- } else if(index("ELNOPQRUuxz", let) && rn2(5)){
- tp++;
- pline("You feel sick.");
- losehp(rnd(8), "cadaver");
- }
- switch(let) {
- case 'L':
- case 'N':
- case 't':
- Teleportation |= INTRINSIC;
- break;
- case 'W':
- pluslvl();
- break;
- case 'n':
- u.uhp = u.uhpmax;
- flags.botl = 1;
- /* fall into next case */
- case '@':
- pline("You cannibal! You will be sorry for this!");
- /* not tp++; */
- /* fall into next case */
- case 'd':
- Aggravate_monster |= INTRINSIC;
- break;
- case 'I':
- if(!Invis) {
- Invis = 50+rn2(100);
- if(!See_invisible)
- newsym(u.ux, u.uy);
- } else {
- Invis |= INTRINSIC;
- See_invisible |= INTRINSIC;
- }
- /* fall into next case */
- case 'y':
-#ifdef QUEST
- u.uhorizon++;
-#endif QUEST
- /* fall into next case */
- case 'B':
- Confusion = 50;
- break;
- case 'D':
- Fire_resistance |= INTRINSIC;
- break;
- case 'E':
- Telepat |= INTRINSIC;
- break;
- case 'F':
- case 'Y':
- Cold_resistance |= INTRINSIC;
- break;
- case 'k':
- case 's':
- Poison_resistance |= INTRINSIC;
- break;
- case 'c':
- pline("You turn to stone.");
- killer = "dead cockatrice";
- done("died");
- /* NOTREACHED */
- case 'a':
- if(Stoned) {
- pline("What a pity - you just destroyed a future piece of art!");
- tp++;
- Stoned = 0;
- }
- break;
- case 'M':
- pline("You cannot resist the temptation to mimic a treasure chest.");
- tp++;
- nomul(-30);
- afternmv = Meatdone;
- nomovemsg = "You now again prefer mimicking a human.";
- u.usym = '$';
- prme();
- break;
- }
- return(tp);
-}
diff --git a/games/hack/hack.end.c b/games/hack/hack.end.c
deleted file mode 100644
index 0ddd2bd0edb7..000000000000
--- a/games/hack/hack.end.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.end.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-#include <signal.h>
-#define Sprintf (void) sprintf
-extern char plname[], pl_character[];
-extern char *itoa(), *ordin(), *eos();
-
-xchar maxdlevel = 1;
-
-void
-done1()
-{
- (void) signal(SIGINT,SIG_IGN);
- pline("Really quit?");
- if(readchar() != 'y') {
- (void) signal(SIGINT,done1);
- clrlin();
- (void) fflush(stdout);
- if(multi > 0) nomul(0);
- return;
- }
- done("quit");
- /* NOTREACHED */
-}
-
-int done_stopprint;
-int done_hup;
-
-void
-done_intr(){
- done_stopprint++;
- (void) signal(SIGINT, SIG_IGN);
- (void) signal(SIGQUIT, SIG_IGN);
-}
-
-void
-done_hangup(){
- done_hup++;
- (void) signal(SIGHUP, SIG_IGN);
- done_intr();
-}
-
-done_in_by(mtmp) register struct monst *mtmp; {
-static char buf[BUFSZ];
- pline("You die ...");
- if(mtmp->data->mlet == ' '){
- Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
- killer = buf;
- } else if(mtmp->mnamelth) {
- Sprintf(buf, "%s called %s",
- mtmp->data->mname, NAME(mtmp));
- killer = buf;
- } else if(mtmp->minvis) {
- Sprintf(buf, "invisible %s", mtmp->data->mname);
- killer = buf;
- } else killer = mtmp->data->mname;
- done("died");
-}
-
-/* called with arg "died", "drowned", "escaped", "quit", "choked", "panicked",
- "burned", "starved" or "tricked" */
-/* Be careful not to call panic from here! */
-done(st1)
-register char *st1;
-{
-
-#ifdef WIZARD
- if(wizard && *st1 == 'd'){
- u.uswldtim = 0;
- if(u.uhpmax < 0) u.uhpmax = 100; /* arbitrary */
- u.uhp = u.uhpmax;
- pline("For some reason you are still alive.");
- flags.move = 0;
- if(multi > 0) multi = 0; else multi = -1;
- flags.botl = 1;
- return;
- }
-#endif WIZARD
- (void) signal(SIGINT, done_intr);
- (void) signal(SIGQUIT, done_intr);
- (void) signal(SIGHUP, done_hangup);
- if(*st1 == 'q' && u.uhp < 1){
- st1 = "died";
- killer = "quit while already on Charon's boat";
- }
- if(*st1 == 's') killer = "starvation"; else
- if(*st1 == 'd' && st1[1] == 'r') killer = "drowning"; else
- if(*st1 == 'p') killer = "panic"; else
- if(*st1 == 't') killer = "trickery"; else
- if(!index("bcd", *st1)) killer = st1;
- paybill();
- clearlocks();
- if(flags.toplin == 1) more();
- if(index("bcds", *st1)){
-#ifdef WIZARD
- if(!wizard)
-#endif WIZARD
- savebones();
- if(!flags.notombstone)
- outrip();
- }
- if(*st1 == 'c') killer = st1; /* after outrip() */
- settty((char *) 0); /* does a clear_screen() */
- if(!done_stopprint)
- printf("Goodbye %s %s...\n\n", pl_character, plname);
- { long int tmp;
- tmp = u.ugold - u.ugold0;
- if(tmp < 0)
- tmp = 0;
- if(*st1 == 'd' || *st1 == 'b')
- tmp -= tmp/10;
- u.urexp += tmp;
- u.urexp += 50 * maxdlevel;
- if(maxdlevel > 20)
- u.urexp += 1000*((maxdlevel > 30) ? 10 : maxdlevel - 20);
- }
- if(*st1 == 'e') {
- extern struct monst *mydogs;
- register struct monst *mtmp;
- register struct obj *otmp;
- register int i;
- register unsigned worthlessct = 0;
- boolean has_amulet = FALSE;
-
- killer = st1;
- keepdogs();
- mtmp = mydogs;
- if(mtmp) {
- if(!done_stopprint) printf("You");
- while(mtmp) {
- if(!done_stopprint)
- printf(" and %s", monnam(mtmp));
- if(mtmp->mtame)
- u.urexp += mtmp->mhp;
- mtmp = mtmp->nmon;
- }
- if(!done_stopprint)
- printf("\nescaped from the dungeon with %ld points,\n",
- u.urexp);
- } else
- if(!done_stopprint)
- printf("You escaped from the dungeon with %ld points,\n",
- u.urexp);
- for(otmp = invent; otmp; otmp = otmp->nobj) {
- if(otmp->olet == GEM_SYM){
- objects[otmp->otyp].oc_name_known = 1;
- i = otmp->quan*objects[otmp->otyp].g_val;
- if(i == 0) {
- worthlessct += otmp->quan;
- continue;
- }
- u.urexp += i;
- if(!done_stopprint)
- printf("\t%s (worth %d Zorkmids),\n",
- doname(otmp), i);
- } else if(otmp->olet == AMULET_SYM) {
- otmp->known = 1;
- i = (otmp->spe < 0) ? 2 : 5000;
- u.urexp += i;
- if(!done_stopprint)
- printf("\t%s (worth %d Zorkmids),\n",
- doname(otmp), i);
- if(otmp->spe >= 0) {
- has_amulet = TRUE;
- killer = "escaped (with amulet)";
- }
- }
- }
- if(worthlessct) if(!done_stopprint)
- printf("\t%u worthless piece%s of coloured glass,\n",
- worthlessct, plur(worthlessct));
- if(has_amulet) u.urexp *= 2;
- } else
- if(!done_stopprint)
- printf("You %s on dungeon level %d with %ld points,\n",
- st1, dlevel, u.urexp);
- if(!done_stopprint)
- printf("and %ld piece%s of gold, after %ld move%s.\n",
- u.ugold, plur(u.ugold), moves, plur(moves));
- if(!done_stopprint)
- printf("You were level %u with a maximum of %d hit points when you %s.\n",
- u.ulevel, u.uhpmax, st1);
- if(*st1 == 'e' && !done_stopprint){
- getret(); /* all those pieces of coloured glass ... */
- cls();
- }
-#ifdef WIZARD
- if(!wizard)
-#endif WIZARD
- topten();
- if(done_stopprint) printf("\n\n");
- exit(0);
-}
-
-#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
-#define NAMSZ 8
-#define DTHSZ 40
-#define PERSMAX 1
-#define POINTSMIN 1 /* must be > 0 */
-#define ENTRYMAX 100 /* must be >= 10 */
-#define PERS_IS_UID /* delete for PERSMAX per name; now per uid */
-struct toptenentry {
- struct toptenentry *tt_next;
- long int points;
- int level,maxlvl,hp,maxhp;
- int uid;
- char plchar;
- char sex;
- char name[NAMSZ+1];
- char death[DTHSZ+1];
- char date[7]; /* yymmdd */
-} *tt_head;
-
-topten(){
- int uid = getuid();
- int rank, rank0 = -1, rank1 = 0;
- int occ_cnt = PERSMAX;
- register struct toptenentry *t0, *t1, *tprev;
- char *recfile = RECORD;
- char *reclock = "record_lock";
- int sleepct = 300;
- FILE *rfile;
- register flg = 0;
- extern char *getdate();
-#define HUP if(!done_hup)
- while(link(recfile, reclock) == -1) {
- HUP perror(reclock);
- if(!sleepct--) {
- HUP puts("I give up. Sorry.");
- HUP puts("Perhaps there is an old record_lock around?");
- return;
- }
- HUP printf("Waiting for access to record file. (%d)\n",
- sleepct);
- HUP (void) fflush(stdout);
- sleep(1);
- }
- if(!(rfile = fopen(recfile,"r"))){
- HUP puts("Cannot open record file!");
- goto unlock;
- }
- HUP (void) putchar('\n');
-
- /* create a new 'topten' entry */
- t0 = newttentry();
- t0->level = dlevel;
- t0->maxlvl = maxdlevel;
- t0->hp = u.uhp;
- t0->maxhp = u.uhpmax;
- t0->points = u.urexp;
- t0->plchar = pl_character[0];
- t0->sex = (flags.female ? 'F' : 'M');
- t0->uid = uid;
- (void) strncpy(t0->name, plname, NAMSZ);
- (t0->name)[NAMSZ] = 0;
- (void) strncpy(t0->death, killer, DTHSZ);
- (t0->death)[DTHSZ] = 0;
- (void) strcpy(t0->date, getdate());
-
- /* assure minimum number of points */
- if(t0->points < POINTSMIN)
- t0->points = 0;
-
- t1 = tt_head = newttentry();
- tprev = 0;
- /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
- for(rank = 1; ; ) {
- if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
- t1->date, &t1->uid,
- &t1->level, &t1->maxlvl,
- &t1->hp, &t1->maxhp, &t1->points,
- &t1->plchar, &t1->sex, t1->name, t1->death) != 11
- || t1->points < POINTSMIN)
- t1->points = 0;
- if(rank0 < 0 && t1->points < t0->points) {
- rank0 = rank++;
- if(tprev == 0)
- tt_head = t0;
- else
- tprev->tt_next = t0;
- t0->tt_next = t1;
- occ_cnt--;
- flg++; /* ask for a rewrite */
- } else
- tprev = t1;
- if(t1->points == 0) break;
- if(
-#ifdef PERS_IS_UID
- t1->uid == t0->uid &&
-#else
- strncmp(t1->name, t0->name, NAMSZ) == 0 &&
-#endif PERS_IS_UID
- t1->plchar == t0->plchar && --occ_cnt <= 0){
- if(rank0 < 0){
- rank0 = 0;
- rank1 = rank;
- HUP printf("You didn't beat your previous score of %ld points.\n\n",
- t1->points);
- }
- if(occ_cnt < 0){
- flg++;
- continue;
- }
- }
- if(rank <= ENTRYMAX){
- t1 = t1->tt_next = newttentry();
- rank++;
- }
- if(rank > ENTRYMAX){
- t1->points = 0;
- break;
- }
- }
- if(flg) { /* rewrite record file */
- (void) fclose(rfile);
- if(!(rfile = fopen(recfile,"w"))){
- HUP puts("Cannot write record file\n");
- goto unlock;
- }
-
- if(!done_stopprint) if(rank0 > 0){
- if(rank0 <= 10)
- puts("You made the top ten list!\n");
- else
- printf("You reached the %d%s place on the top %d list.\n\n",
- rank0, ordin(rank0), ENTRYMAX);
- }
- }
- if(rank0 == 0) rank0 = rank1;
- if(rank0 <= 0) rank0 = rank;
- if(!done_stopprint) outheader();
- t1 = tt_head;
- for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
- if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",
- t1->date, t1->uid,
- t1->level, t1->maxlvl,
- t1->hp, t1->maxhp, t1->points,
- t1->plchar, t1->sex, t1->name, t1->death);
- if(done_stopprint) continue;
- if(rank > flags.end_top &&
- (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
- && (!flags.end_own ||
-#ifdef PERS_IS_UID
- t1->uid != t0->uid ))
-#else
- strncmp(t1->name, t0->name, NAMSZ)))
-#endif PERS_IS_UID
- continue;
- if(rank == rank0-flags.end_around &&
- rank0 > flags.end_top+flags.end_around+1 &&
- !flags.end_own)
- (void) putchar('\n');
- if(rank != rank0)
- (void) outentry(rank, t1, 0);
- else if(!rank1)
- (void) outentry(rank, t1, 1);
- else {
- int t0lth = outentry(0, t0, -1);
- int t1lth = outentry(rank, t1, t0lth);
- if(t1lth > t0lth) t0lth = t1lth;
- (void) outentry(0, t0, t0lth);
- }
- }
- if(rank0 >= rank) if(!done_stopprint)
- (void) outentry(0, t0, 1);
- (void) fclose(rfile);
-unlock:
- (void) unlink(reclock);
-}
-
-outheader() {
-char linebuf[BUFSZ];
-register char *bp;
- (void) strcpy(linebuf, "Number Points Name");
- bp = eos(linebuf);
- while(bp < linebuf + COLNO - 9) *bp++ = ' ';
- (void) strcpy(bp, "Hp [max]");
- puts(linebuf);
-}
-
-/* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
-int
-outentry(rank,t1,so) register struct toptenentry *t1; {
-boolean quit = FALSE, killed = FALSE, starv = FALSE;
-char linebuf[BUFSZ];
- linebuf[0] = 0;
- if(rank) Sprintf(eos(linebuf), "%3d", rank);
- else Sprintf(eos(linebuf), " ");
- Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name);
- if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
- else Sprintf(eos(linebuf), "-%c ", t1->plchar);
- if(!strncmp("escaped", t1->death, 7)) {
- if(!strcmp(" (with amulet)", t1->death+7))
- Sprintf(eos(linebuf), "escaped the dungeon with amulet");
- else
- Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
- t1->maxlvl);
- } else {
- if(!strncmp(t1->death,"quit",4)) {
- quit = TRUE;
- if(t1->maxhp < 3*t1->hp && t1->maxlvl < 4)
- Sprintf(eos(linebuf), "cravenly gave up");
- else
- Sprintf(eos(linebuf), "quit");
- }
- else if(!strcmp(t1->death,"choked"))
- Sprintf(eos(linebuf), "choked on %s food",
- (t1->sex == 'F') ? "her" : "his");
- else if(!strncmp(t1->death,"starv",5))
- Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
- else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
- Sprintf(eos(linebuf), " on%s level %d",
- (killed || starv) ? "" : " dungeon", t1->level);
- if(t1->maxlvl != t1->level)
- Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
- if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
- }
- if(killed) Sprintf(eos(linebuf), " by %s%s",
- (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4))
- ? "" :
- index(vowels,*t1->death) ? "an " : "a ",
- t1->death);
- Sprintf(eos(linebuf), ".");
- if(t1->maxhp) {
- register char *bp = eos(linebuf);
- char hpbuf[10];
- int hppos;
- Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
- hppos = COLNO - 7 - strlen(hpbuf);
- if(bp <= linebuf + hppos) {
- while(bp < linebuf + hppos) *bp++ = ' ';
- (void) strcpy(bp, hpbuf);
- Sprintf(eos(bp), " [%d]", t1->maxhp);
- }
- }
- if(so == 0) puts(linebuf);
- else if(so > 0) {
- register char *bp = eos(linebuf);
- if(so >= COLNO) so = COLNO-1;
- while(bp < linebuf + so) *bp++ = ' ';
- *bp = 0;
- standoutbeg();
- fputs(linebuf,stdout);
- standoutend();
- (void) putchar('\n');
- }
- return(strlen(linebuf));
-}
-
-char *
-itoa(a) int a; {
-static char buf[12];
- Sprintf(buf,"%d",a);
- return(buf);
-}
-
-char *
-ordin(n) int n; {
-register int d = n%10;
- return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
- (d==2) ? "nd" : "rd");
-}
-
-clearlocks(){
-register x;
- (void) signal(SIGHUP,SIG_IGN);
- for(x = maxdlevel; x >= 0; x--) {
- glo(x);
- (void) unlink(lock); /* not all levels need be present */
- }
-}
-
-#ifdef NOSAVEONHANGUP
-hangup()
-{
- (void) signal(SIGINT, SIG_IGN);
- clearlocks();
- exit(1);
-}
-#endif NOSAVEONHANGUP
-
-char *
-eos(s)
-register char *s;
-{
- while(*s) s++;
- return(s);
-}
-
-/* it is the callers responsibility to check that there is room for c */
-charcat(s,c) register char *s, c; {
- while(*s) s++;
- *s++ = c;
- *s = 0;
-}
-
-/*
- * Called with args from main if argc >= 0. In this case, list scores as
- * requested. Otherwise, find scores for the current player (and list them
- * if argc == -1).
- */
-prscore(argc,argv) int argc; char **argv; {
- extern char *hname;
- char **players;
- int playerct;
- int rank;
- register struct toptenentry *t1, *t2;
- char *recfile = RECORD;
- FILE *rfile;
- register flg = 0;
- register int i;
-#ifdef nonsense
- long total_score = 0L;
- char totchars[10];
- int totcharct = 0;
-#endif nonsense
- int outflg = (argc >= -1);
-#ifdef PERS_IS_UID
- int uid = -1;
-#else
- char *player0;
-#endif PERS_IS_UID
-
- if(!(rfile = fopen(recfile,"r"))){
- puts("Cannot open record file!");
- return;
- }
-
- if(argc > 1 && !strncmp(argv[1], "-s", 2)){
- if(!argv[1][2]){
- argc--;
- argv++;
- } else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
- argv[1]++;
- argv[1][0] = '-';
- } else argv[1] += 2;
- }
- if(argc <= 1){
-#ifdef PERS_IS_UID
- uid = getuid();
- playerct = 0;
-#else
- player0 = plname;
- if(!*player0)
- player0 = "hackplayer";
- playerct = 1;
- players = &player0;
-#endif PERS_IS_UID
- } else {
- playerct = --argc;
- players = ++argv;
- }
- if(outflg) putchar('\n');
-
- t1 = tt_head = newttentry();
- for(rank = 1; ; rank++) {
- if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
- t1->date, &t1->uid,
- &t1->level, &t1->maxlvl,
- &t1->hp, &t1->maxhp, &t1->points,
- &t1->plchar, &t1->sex, t1->name, t1->death) != 11)
- t1->points = 0;
- if(t1->points == 0) break;
-#ifdef PERS_IS_UID
- if(!playerct && t1->uid == uid)
- flg++;
- else
-#endif PERS_IS_UID
- for(i = 0; i < playerct; i++){
- if(strcmp(players[i], "all") == 0 ||
- strncmp(t1->name, players[i], NAMSZ) == 0 ||
- (players[i][0] == '-' &&
- players[i][1] == t1->plchar &&
- players[i][2] == 0) ||
- (digit(players[i][0]) && rank <= atoi(players[i])))
- flg++;
- }
- t1 = t1->tt_next = newttentry();
- }
- (void) fclose(rfile);
- if(!flg) {
- if(outflg) {
- printf("Cannot find any entries for ");
- if(playerct < 1) printf("you.\n");
- else {
- if(playerct > 1) printf("any of ");
- for(i=0; i<playerct; i++)
- printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
- printf("Call is: %s -s [playernames]\n", hname);
- }
- }
- return;
- }
-
- if(outflg) outheader();
- t1 = tt_head;
- for(rank = 1; t1->points != 0; rank++, t1 = t2) {
- t2 = t1->tt_next;
-#ifdef PERS_IS_UID
- if(!playerct && t1->uid == uid)
- goto outwithit;
- else
-#endif PERS_IS_UID
- for(i = 0; i < playerct; i++){
- if(strcmp(players[i], "all") == 0 ||
- strncmp(t1->name, players[i], NAMSZ) == 0 ||
- (players[i][0] == '-' &&
- players[i][1] == t1->plchar &&
- players[i][2] == 0) ||
- (digit(players[i][0]) && rank <= atoi(players[i]))){
- outwithit:
- if(outflg)
- (void) outentry(rank, t1, 0);
-#ifdef nonsense
- total_score += t1->points;
- if(totcharct < sizeof(totchars)-1)
- totchars[totcharct++] = t1->plchar;
-#endif nonsense
- break;
- }
- }
- free((char *) t1);
- }
-#ifdef nonsense
- totchars[totcharct] = 0;
-
- /* We would like to determine whether he is experienced. However,
- the information collected here only tells about the scores/roles
- that got into the topten (top 100?). We should maintain a
- .hacklog or something in his home directory. */
- flags.beginner = (total_score < 6000);
- for(i=0; i<6; i++)
- if(!index(totchars, "CFKSTWX"[i])) {
- flags.beginner = 1;
- if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i];
- break;
- }
-#endif nonsense
-}
diff --git a/games/hack/hack.engrave.c b/games/hack/hack.engrave.c
deleted file mode 100644
index dc16c39f952c..000000000000
--- a/games/hack/hack.engrave.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.engrave.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern char *nomovemsg;
-extern char nul[];
-extern struct obj zeroobj;
-struct engr {
- struct engr *nxt_engr;
- char *engr_txt;
- xchar engr_x, engr_y;
- unsigned engr_lth; /* for save & restore; not length of text */
- long engr_time; /* moment engraving was (will be) finished */
- xchar engr_type;
-#define DUST 1
-#define ENGRAVE 2
-#define BURN 3
-} *head_engr;
-
-struct engr *
-engr_at(x,y) register xchar x,y; {
-register struct engr *ep = head_engr;
- while(ep) {
- if(x == ep->engr_x && y == ep->engr_y)
- return(ep);
- ep = ep->nxt_engr;
- }
- return((struct engr *) 0);
-}
-
-sengr_at(s,x,y) register char *s; register xchar x,y; {
-register struct engr *ep = engr_at(x,y);
-register char *t;
-register int n;
- if(ep && ep->engr_time <= moves) {
- t = ep->engr_txt;
-/*
- if(!strcmp(s,t)) return(1);
-*/
- n = strlen(s);
- while(*t) {
- if(!strncmp(s,t,n)) return(1);
- t++;
- }
- }
- return(0);
-}
-
-u_wipe_engr(cnt)
-register int cnt;
-{
- if(!u.uswallow && !Levitation)
- wipe_engr_at(u.ux, u.uy, cnt);
-}
-
-wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
-register struct engr *ep = engr_at(x,y);
-register int lth,pos;
-char ch;
- if(ep){
- if((ep->engr_type != DUST) || Levitation) {
- cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
- }
- lth = strlen(ep->engr_txt);
- if(lth && cnt > 0 ) {
- while(cnt--) {
- pos = rn2(lth);
- if((ch = ep->engr_txt[pos]) == ' ')
- continue;
- ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
- }
- }
- while(lth && ep->engr_txt[lth-1] == ' ')
- ep->engr_txt[--lth] = 0;
- while(ep->engr_txt[0] == ' ')
- ep->engr_txt++;
- if(!ep->engr_txt[0]) del_engr(ep);
- }
-}
-
-read_engr_at(x,y) register int x,y; {
-register struct engr *ep = engr_at(x,y);
- if(ep && ep->engr_txt[0]) {
- switch(ep->engr_type) {
- case DUST:
- pline("Something is written here in the dust.");
- break;
- case ENGRAVE:
- pline("Something is engraved here on the floor.");
- break;
- case BURN:
- pline("Some text has been burned here in the floor.");
- break;
- default:
- impossible("Something is written in a very strange way.");
- }
- pline("You read: \"%s\".", ep->engr_txt);
- }
-}
-
-make_engr_at(x,y,s)
-register int x,y;
-register char *s;
-{
- register struct engr *ep;
-
- if(ep = engr_at(x,y))
- del_engr(ep);
- ep = (struct engr *)
- alloc((unsigned)(sizeof(struct engr) + strlen(s) + 1));
- ep->nxt_engr = head_engr;
- head_engr = ep;
- ep->engr_x = x;
- ep->engr_y = y;
- ep->engr_txt = (char *)(ep + 1);
- (void) strcpy(ep->engr_txt, s);
- ep->engr_time = 0;
- ep->engr_type = DUST;
- ep->engr_lth = strlen(s) + 1;
-}
-
-doengrave(){
-register int len;
-register char *sp;
-register struct engr *ep, *oep = engr_at(u.ux,u.uy);
-char buf[BUFSZ];
-xchar type;
-int spct; /* number of leading spaces */
-register struct obj *otmp;
- multi = 0;
-
- if(u.uswallow) {
- pline("You're joking. Hahaha!"); /* riv05!a3 */
- return(0);
- }
-
- /* one may write with finger, weapon or wand */
- otmp = getobj("#-)/", "write with");
- if(!otmp) return(0);
-
- if(otmp == &zeroobj)
- otmp = 0;
- if(otmp && otmp->otyp == WAN_FIRE && otmp->spe) {
- type = BURN;
- otmp->spe--;
- } else {
- /* first wield otmp */
- if(otmp != uwep) {
- if(uwep && uwep->cursed) {
- /* Andreas Bormann */
- pline("Since your weapon is welded to your hand,");
- pline("you use the %s.", aobjnam(uwep, (char *) 0));
- otmp = uwep;
- } else {
- if(!otmp)
- pline("You are now empty-handed.");
- else if(otmp->cursed)
- pline("The %s %s to your hand!",
- aobjnam(otmp, "weld"),
- (otmp->quan == 1) ? "itself" : "themselves");
- else
- pline("You now wield %s.", doname(otmp));
- setuwep(otmp);
- }
- }
-
- if(!otmp)
- type = DUST;
- else
- if(otmp->otyp == DAGGER || otmp->otyp == TWO_HANDED_SWORD ||
- otmp->otyp == CRYSKNIFE ||
- otmp->otyp == LONG_SWORD || otmp->otyp == AXE) {
- type = ENGRAVE;
- if((int)otmp->spe <= -3) {
- type = DUST;
- pline("Your %s too dull for engraving.",
- aobjnam(otmp, "are"));
- if(oep && oep->engr_type != DUST) return(1);
- }
- } else type = DUST;
- }
- if(Levitation && type != BURN){ /* riv05!a3 */
- pline("You can't reach the floor!");
- return(1);
- }
- if(oep && oep->engr_type == DUST){
- pline("You wipe out the message that was written here.");
- del_engr(oep);
- oep = 0;
- }
- if(type == DUST && oep){
- pline("You cannot wipe out the message that is %s in the rock.",
- (oep->engr_type == BURN) ? "burned" : "engraved");
- return(1);
- }
-
- pline("What do you want to %s on the floor here? ",
- (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
- getlin(buf);
- clrlin();
- spct = 0;
- sp = buf;
- while(*sp == ' ') spct++, sp++;
- len = strlen(sp);
- if(!len || *buf == '\033') {
- if(type == BURN) otmp->spe++;
- return(0);
- }
-
- switch(type) {
- case DUST:
- case BURN:
- if(len > 15) {
- multi = -(len/10);
- nomovemsg = "You finished writing.";
- }
- break;
- case ENGRAVE: /* here otmp != 0 */
- { int len2 = (otmp->spe + 3) * 2 + 1;
-
- pline("Your %s dull.", aobjnam(otmp, "get"));
- if(len2 < len) {
- len = len2;
- sp[len] = 0;
- otmp->spe = -3;
- nomovemsg = "You cannot engrave more.";
- } else {
- otmp->spe -= len/2;
- nomovemsg = "You finished engraving.";
- }
- multi = -len;
- }
- break;
- }
- if(oep) len += strlen(oep->engr_txt) + spct;
- ep = (struct engr *) alloc((unsigned)(sizeof(struct engr) + len + 1));
- ep->nxt_engr = head_engr;
- head_engr = ep;
- ep->engr_x = u.ux;
- ep->engr_y = u.uy;
- sp = (char *)(ep + 1); /* (char *)ep + sizeof(struct engr) */
- ep->engr_txt = sp;
- if(oep) {
- (void) strcpy(sp, oep->engr_txt);
- (void) strcat(sp, buf);
- del_engr(oep);
- } else
- (void) strcpy(sp, buf);
- ep->engr_lth = len+1;
- ep->engr_type = type;
- ep->engr_time = moves-multi;
-
- /* kludge to protect pline against excessively long texts */
- if(len > BUFSZ-20) sp[BUFSZ-20] = 0;
-
- return(1);
-}
-
-save_engravings(fd) int fd; {
-register struct engr *ep = head_engr;
- while(ep) {
- if(!ep->engr_lth || !ep->engr_txt[0]){
- ep = ep->nxt_engr;
- continue;
- }
- bwrite(fd, (char *) & (ep->engr_lth), sizeof(ep->engr_lth));
- bwrite(fd, (char *) ep, sizeof(struct engr) + ep->engr_lth);
- ep = ep->nxt_engr;
- }
- bwrite(fd, (char *) nul, sizeof(unsigned));
- head_engr = 0;
-}
-
-rest_engravings(fd) int fd; {
-register struct engr *ep;
-unsigned lth;
- head_engr = 0;
- while(1) {
- mread(fd, (char *) &lth, sizeof(unsigned));
- if(lth == 0) return;
- ep = (struct engr *) alloc(sizeof(struct engr) + lth);
- mread(fd, (char *) ep, sizeof(struct engr) + lth);
- ep->nxt_engr = head_engr;
- ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */
- head_engr = ep;
- }
-}
-
-del_engr(ep) register struct engr *ep; {
-register struct engr *ept;
- if(ep == head_engr)
- head_engr = ep->nxt_engr;
- else {
- for(ept = head_engr; ept; ept = ept->nxt_engr) {
- if(ept->nxt_engr == ep) {
- ept->nxt_engr = ep->nxt_engr;
- goto fnd;
- }
- }
- impossible("Error in del_engr?");
- return;
- fnd: ;
- }
- free((char *) ep);
-}
diff --git a/games/hack/hack.fight.c b/games/hack/hack.fight.c
deleted file mode 100644
index ede886d16931..000000000000
--- a/games/hack/hack.fight.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.fight.c - version 1.0.3 */
-
-#include "hack.h"
-extern struct permonst li_dog, dog, la_dog;
-extern char *exclam(), *xname();
-extern struct obj *mkobj_at();
-
-static boolean far_noise;
-static long noisetime;
-
-/* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */
-hitmm(magr,mdef) register struct monst *magr,*mdef; {
-register struct permonst *pa = magr->data, *pd = mdef->data;
-int hit;
-schar tmp;
-boolean vis;
- if(index("Eauy", pa->mlet)) return(0);
- if(magr->mfroz) return(0); /* riv05!a3 */
- tmp = pd->ac + pa->mlevel;
- if(mdef->mconf || mdef->mfroz || mdef->msleep){
- tmp += 4;
- if(mdef->msleep) mdef->msleep = 0;
- }
- hit = (tmp > rnd(20));
- if(hit) mdef->msleep = 0;
- vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
- if(vis){
- char buf[BUFSZ];
- if(mdef->mimic) seemimic(mdef);
- if(magr->mimic) seemimic(magr);
- (void) sprintf(buf,"%s %s", Monnam(magr),
- hit ? "hits" : "misses");
- pline("%s %s.", buf, monnam(mdef));
- } else {
- boolean far = (dist(magr->mx, magr->my) > 15);
- if(far != far_noise || moves-noisetime > 10) {
- far_noise = far;
- noisetime = moves;
- pline("You hear some noises%s.",
- far ? " in the distance" : "");
- }
- }
- if(hit){
- if(magr->data->mlet == 'c' && !magr->cham) {
- magr->mhpmax += 3;
- if(vis) pline("%s is turned to stone!", Monnam(mdef));
- else if(mdef->mtame)
- pline("You have a peculiarly sad feeling for a moment, then it passes.");
- monstone(mdef);
- hit = 2;
- } else
- if((mdef->mhp -= d(pa->damn,pa->damd)) < 1) {
- magr->mhpmax += 1 + rn2(pd->mlevel+1);
- if(magr->mtame && magr->mhpmax > 8*pa->mlevel){
- if(pa == &li_dog) magr->data = pa = &dog;
- else if(pa == &dog) magr->data = pa = &la_dog;
- }
- if(vis) pline("%s is killed!", Monnam(mdef));
- else if(mdef->mtame)
- pline("You have a sad feeling for a moment, then it passes.");
- mondied(mdef);
- hit = 2;
- }
- }
- return(hit);
-}
-
-/* drop (perhaps) a cadaver and remove monster */
-mondied(mdef) register struct monst *mdef; {
-register struct permonst *pd = mdef->data;
- if(letter(pd->mlet) && rn2(3)){
- (void) mkobj_at(pd->mlet,mdef->mx,mdef->my);
- if(cansee(mdef->mx,mdef->my)){
- unpmon(mdef);
- atl(mdef->mx,mdef->my,fobj->olet);
- }
- stackobj(fobj);
- }
- mondead(mdef);
-}
-
-/* drop a rock and remove monster */
-monstone(mdef) register struct monst *mdef; {
- extern char mlarge[];
- if(index(mlarge, mdef->data->mlet))
- mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my);
- else
- mksobj_at(ROCK, mdef->mx, mdef->my);
- if(cansee(mdef->mx, mdef->my)){
- unpmon(mdef);
- atl(mdef->mx,mdef->my,fobj->olet);
- }
- mondead(mdef);
-}
-
-
-fightm(mtmp) register struct monst *mtmp; {
-register struct monst *mon;
- for(mon = fmon; mon; mon = mon->nmon) if(mon != mtmp) {
- if(DIST(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3)
- if(rn2(4))
- return(hitmm(mtmp,mon));
- }
- return(-1);
-}
-
-/* u is hit by sth, but not a monster */
-thitu(tlev,dam,name)
-register tlev,dam;
-register char *name;
-{
-char buf[BUFSZ];
- setan(name,buf);
- if(u.uac + tlev <= rnd(20)) {
- if(Blind) pline("It misses.");
- else pline("You are almost hit by %s!", buf);
- return(0);
- } else {
- if(Blind) pline("You are hit!");
- else pline("You are hit by %s!", buf);
- losehp(dam,name);
- return(1);
- }
-}
-
-char mlarge[] = "bCDdegIlmnoPSsTUwY',&";
-
-boolean
-hmon(mon,obj,thrown) /* return TRUE if mon still alive */
-register struct monst *mon;
-register struct obj *obj;
-register thrown;
-{
- register tmp;
- boolean hittxt = FALSE;
-
- if(!obj){
- tmp = rnd(2); /* attack with bare hands */
- if(mon->data->mlet == 'c' && !uarmg){
- pline("You hit the cockatrice with your bare hands.");
- pline("You turn to stone ...");
- done_in_by(mon);
- }
- } else if(obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) {
- if(obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG))
- tmp = rnd(2);
- else {
- if(index(mlarge, mon->data->mlet)) {
- tmp = rnd(objects[obj->otyp].wldam);
- if(obj->otyp == TWO_HANDED_SWORD) tmp += d(2,6);
- else if(obj->otyp == FLAIL) tmp += rnd(4);
- } else {
- tmp = rnd(objects[obj->otyp].wsdam);
- }
- tmp += obj->spe;
- if(!thrown && obj == uwep && obj->otyp == BOOMERANG
- && !rn2(3)){
- pline("As you hit %s, the boomerang breaks into splinters.",
- monnam(mon));
- freeinv(obj);
- setworn((struct obj *) 0, obj->owornmask);
- obfree(obj, (struct obj *) 0);
- tmp++;
- }
- }
- if(mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD &&
- !strcmp(ONAME(obj), "Orcrist"))
- tmp += rnd(10);
- } else switch(obj->otyp) {
- case HEAVY_IRON_BALL:
- tmp = rnd(25); break;
- case EXPENSIVE_CAMERA:
- pline("You succeed in destroying your camera. Congratulations!");
- freeinv(obj);
- if(obj->owornmask)
- setworn((struct obj *) 0, obj->owornmask);
- obfree(obj, (struct obj *) 0);
- return(TRUE);
- case DEAD_COCKATRICE:
- pline("You hit %s with the cockatrice corpse.",
- monnam(mon));
- if(mon->data->mlet == 'c') {
- tmp = 1;
- hittxt = TRUE;
- break;
- }
- pline("%s is turned to stone!", Monnam(mon));
- killed(mon);
- return(FALSE);
- case CLOVE_OF_GARLIC: /* no effect against demons */
- if(index(UNDEAD, mon->data->mlet))
- mon->mflee = 1;
- tmp = 1;
- break;
- default:
- /* non-weapons can damage because of their weight */
- /* (but not too much) */
- tmp = obj->owt/10;
- if(tmp < 1) tmp = 1;
- else tmp = rnd(tmp);
- if(tmp > 6) tmp = 6;
- }
-
- /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */
-
- tmp += u.udaminc + dbon();
- if(u.uswallow) {
- if((tmp -= u.uswldtim) <= 0) {
- pline("Your arms are no longer able to hit.");
- return(TRUE);
- }
- }
- if(tmp < 1) tmp = 1;
- mon->mhp -= tmp;
- if(mon->mhp < 1) {
- killed(mon);
- return(FALSE);
- }
- if(mon->mtame && (!mon->mflee || mon->mfleetim)) {
- mon->mflee = 1; /* Rick Richardson */
- mon->mfleetim += 10*rnd(tmp);
- }
-
- if(!hittxt) {
- if(thrown)
- /* this assumes that we cannot throw plural things */
- hit( xname(obj) /* or: objects[obj->otyp].oc_name */,
- mon, exclam(tmp) );
- else if(Blind)
- pline("You hit it.");
- else
- pline("You hit %s%s", monnam(mon), exclam(tmp));
- }
-
- if(u.umconf && !thrown) {
- if(!Blind) {
- pline("Your hands stop glowing blue.");
- if(!mon->mfroz && !mon->msleep)
- pline("%s appears confused.",Monnam(mon));
- }
- mon->mconf = 1;
- u.umconf = 0;
- }
- return(TRUE); /* mon still alive */
-}
-
-/* try to attack; return FALSE if monster evaded */
-/* u.dx and u.dy must be set */
-attack(mtmp)
-register struct monst *mtmp;
-{
- schar tmp;
- boolean malive = TRUE;
- register struct permonst *mdat;
- mdat = mtmp->data;
-
- u_wipe_engr(3); /* andrew@orca: prevent unlimited pick-axe attacks */
-
- if(mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
- !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
- (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */
- mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy))
- return(FALSE);
-
- if(mtmp->mimic){
- if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp;
- switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){
- case '+':
- pline("The door actually was a Mimic.");
- break;
- case '$':
- pline("The chest was a Mimic!");
- break;
- default:
- pline("Wait! That's a Mimic!");
- }
- wakeup(mtmp); /* clears mtmp->mimic */
- return(TRUE);
- }
-
- wakeup(mtmp);
-
- if(mtmp->mhide && mtmp->mundetected){
- register struct obj *obj;
-
- mtmp->mundetected = 0;
- if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind)
- pline("Wait! There's a %s hiding under %s!",
- mdat->mname, doname(obj));
- return(TRUE);
- }
-
- tmp = u.uluck + u.ulevel + mdat->ac + abon();
- if(uwep) {
- if(uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE)
- tmp += uwep->spe;
- if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1;
- else if(uwep->otyp == DAGGER) tmp += 2;
- else if(uwep->otyp == CRYSKNIFE) tmp += 3;
- else if(uwep->otyp == SPEAR &&
- index("XDne", mdat->mlet)) tmp += 2;
- }
- if(mtmp->msleep) {
- mtmp->msleep = 0;
- tmp += 2;
- }
- if(mtmp->mfroz) {
- tmp += 4;
- if(!rn2(10)) mtmp->mfroz = 0;
- }
- if(mtmp->mflee) tmp += 2;
- if(u.utrap) tmp -= 3;
-
- /* with a lot of luggage, your agility diminishes */
- tmp -= (inv_weight() + 40)/20;
-
- if(tmp <= rnd(20) && !u.uswallow){
- if(Blind) pline("You miss it.");
- else pline("You miss %s.",monnam(mtmp));
- } else {
- /* we hit the monster; be careful: it might die! */
-
- if((malive = hmon(mtmp,uwep,0)) == TRUE) {
- /* monster still alive */
- if(!rn2(25) && mtmp->mhp < mtmp->mhpmax/2) {
- mtmp->mflee = 1;
- if(!rn2(3)) mtmp->mfleetim = rnd(100);
- if(u.ustuck == mtmp && !u.uswallow)
- u.ustuck = 0;
- }
-#ifndef NOWORM
- if(mtmp->wormno)
- cutworm(mtmp, u.ux+u.dx, u.uy+u.dy,
- uwep ? uwep->otyp : 0);
-#endif NOWORM
- }
- if(mdat->mlet == 'a') {
- if(rn2(2)) {
- pline("You are splashed by the blob's acid!");
- losehp_m(rnd(6), mtmp);
- if(!rn2(30)) corrode_armor();
- }
- if(!rn2(6)) corrode_weapon();
- }
- }
- if(malive && mdat->mlet == 'E' && canseemon(mtmp)
- && !mtmp->mcan && rn2(3)) {
- if(mtmp->mcansee) {
- pline("You are frozen by the floating eye's gaze!");
- nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200);
- } else {
- pline("The blinded floating eye cannot defend itself.");
- if(!rn2(500)) if((int)u.uluck > LUCKMIN) u.uluck--;
- }
- }
- return(TRUE);
-}
diff --git a/games/hack/hack.fix b/games/hack/hack.fix
deleted file mode 100644
index 01e6460247d7..000000000000
--- a/games/hack/hack.fix
+++ /dev/null
@@ -1,113 +0,0 @@
-/***** unido:net.games.hack / ab / 7:23 pm Sep 13, 1985*/
-
-Recently hack (1.0.3) crashed with core dumps during some good games.
-The crashes occured in the onbill-routine. After investigating the core
-dump I found that the shopkeeper's bill was still to be paid. Normaly
-if you leave a shop the bill will be cleared and onbill() would not
-check it. But under certain conditions you can leave a shop without
-clearing the bill. The conditions are:
-
- 1. You have to rob a shop in order to make the shopkeeper
- follow you.
-
- 2. After leaving the shop being followed by the shopkeeper
- you must return to the shop...
-
- 3. ...and then leave the unguarded shop again.
- - The shopkeeper mustn't be present!
-
-If you climb the stairs to the previous level, chances are that your
-bill now contains much more items than allowed. If so the next call to
-onbill() will dump the core.
-
-Following is a context diff to fix the bug. Actually just the last hunk
-does the fix [it deletes two lines which have been inserted in 1.0.3],
-but I think the other fix was intended by the now deleted lines.
-
- Andreas
-
---
-Andreas Bormann ab@unido.UUCP
-University of Dortmund N 51 29' 05" E 07 24' 42"
-West Germany
-
------- the diff follows:
-
-*** hack.shk.c.orig Sun Aug 4 12:07:51 1985
---- hack.shk.c Fri Sep 13 14:29:52 1985
-***************
-*** 133,139
- /* Did we just leave a shop? */
- if(u.uinshop &&
- (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
-- u.uinshop = 0;
- if(shopkeeper) {
- if(ESHK(shopkeeper)->billct) {
- pline("Somehow you escaped the shop without paying!");
-
---- 133,138 -----
- /* Did we just leave a shop? */
- if(u.uinshop &&
- (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
- if(shopkeeper) {
- if(ESHK(shopkeeper)->billct) {
- if(inroom(shopkeeper->mx, shopkeeper->my)
-***************
-*** 136,142
- u.uinshop = 0;
- if(shopkeeper) {
- if(ESHK(shopkeeper)->billct) {
-! pline("Somehow you escaped the shop without paying!");
- addupbill();
- pline("You stole for a total worth of %ld zorkmids.",
- total);
-
---- 135,143 -----
- (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
- if(shopkeeper) {
- if(ESHK(shopkeeper)->billct) {
-! if(inroom(shopkeeper->mx, shopkeeper->my)
-! == u.uinshop - 1) /* ab@unido */
-! pline("Somehow you escaped the shop without paying!");
- addupbill();
- pline("You stole for a total worth of %ld zorkmids.",
- total);
-***************
-*** 149,154
- shopkeeper = 0;
- shlevel = 0;
- }
- }
-
- /* Did we just enter a zoo of some kind? */
-
---- 150,156 -----
- shopkeeper = 0;
- shlevel = 0;
- }
-+ u.uinshop = 0;
- }
-
- /* Did we just enter a zoo of some kind? */
-***************
-*** 183,190
- findshk(roomno);
- if(!shopkeeper) {
- rooms[roomno].rtype = 0;
-- u.uinshop = 0;
-- } else if(inroom(shopkeeper->mx, shopkeeper->my) != roomno) {
- u.uinshop = 0;
- } else if(!u.uinshop){
- if(!ESHK(shopkeeper)->visitct ||
-
---- 185,190 -----
- findshk(roomno);
- if(!shopkeeper) {
- rooms[roomno].rtype = 0;
- u.uinshop = 0;
- } else if(!u.uinshop){
- if(!ESHK(shopkeeper)->visitct ||
-/* ---------- */
-
-
-
diff --git a/games/hack/hack.h b/games/hack/hack.h
deleted file mode 100644
index 58c028379ee1..000000000000
--- a/games/hack/hack.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.h - version 1.0.3 */
-
-#include "config.h"
-#include <string.h>
-
-#ifndef BSD
-#define index strchr
-#define rindex strrchr
-#endif BSD
-
-#define Null(type) ((struct type *) 0)
-
-#include "def.objclass.h"
-
-typedef struct {
- xchar x,y;
-} coord;
-
-#include "def.monst.h" /* uses coord */
-#include "def.gold.h"
-#include "def.trap.h"
-#include "def.obj.h"
-#include "def.flag.h"
-
-#define plur(x) (((x) == 1) ? "" : "s")
-
-#define BUFSZ 256 /* for getlin buffers */
-#define PL_NSIZ 32 /* name of player, ghost, shopkeeper */
-
-#include "def.rm.h"
-#include "def.permonst.h"
-
-extern long *alloc();
-
-extern xchar xdnstair, ydnstair, xupstair, yupstair; /* stairs up and down. */
-
-extern xchar dlevel;
-#define newstring(x) (char *) alloc((unsigned)(x))
-#include "hack.onames.h"
-
-#define ON 1
-#define OFF 0
-
-extern struct obj *invent, *uwep, *uarm, *uarm2, *uarmh, *uarms, *uarmg,
- *uleft, *uright, *fcobj;
-extern struct obj *uchain; /* defined iff PUNISHED */
-extern struct obj *uball; /* defined if PUNISHED */
-struct obj *o_at(), *getobj(), *sobj_at();
-
-struct prop {
-#define TIMEOUT 007777 /* mask */
-#define LEFT_RING W_RINGL /* 010000L */
-#define RIGHT_RING W_RINGR /* 020000L */
-#define INTRINSIC 040000L
-#define LEFT_SIDE LEFT_RING
-#define RIGHT_SIDE RIGHT_RING
-#define BOTH_SIDES (LEFT_SIDE | RIGHT_SIDE)
- long p_flgs;
- int (*p_tofn)(); /* called after timeout */
-};
-
-struct you {
- xchar ux, uy;
- schar dx, dy, dz; /* direction of move (or zap or ... ) */
-#ifdef QUEST
- schar di; /* direction of FF */
- xchar ux0, uy0; /* initial position FF */
-#endif QUEST
- xchar udisx, udisy; /* last display pos */
- char usym; /* usually '@' */
- schar uluck;
-#define LUCKMAX 10 /* on moonlit nights 11 */
-#define LUCKMIN (-10)
- int last_str_turn:3; /* 0: none, 1: half turn, 2: full turn */
- /* +: turn right, -: turn left */
- unsigned udispl:1; /* @ on display */
- unsigned ulevel:4; /* 1 - 14 */
-#ifdef QUEST
- unsigned uhorizon:7;
-#endif QUEST
- unsigned utrap:3; /* trap timeout */
- unsigned utraptype:1; /* defined if utrap nonzero */
-#define TT_BEARTRAP 0
-#define TT_PIT 1
- unsigned uinshop:6; /* used only in shk.c - (roomno+1) of shop */
-
-
-/* perhaps these #define's should also be generated by makedefs */
-#define TELEPAT LAST_RING /* not a ring */
-#define Telepat u.uprops[TELEPAT].p_flgs
-#define FAST (LAST_RING+1) /* not a ring */
-#define Fast u.uprops[FAST].p_flgs
-#define CONFUSION (LAST_RING+2) /* not a ring */
-#define Confusion u.uprops[CONFUSION].p_flgs
-#define INVIS (LAST_RING+3) /* not a ring */
-#define Invis u.uprops[INVIS].p_flgs
-#define Invisible (Invis && !See_invisible)
-#define GLIB (LAST_RING+4) /* not a ring */
-#define Glib u.uprops[GLIB].p_flgs
-#define PUNISHED (LAST_RING+5) /* not a ring */
-#define Punished u.uprops[PUNISHED].p_flgs
-#define SICK (LAST_RING+6) /* not a ring */
-#define Sick u.uprops[SICK].p_flgs
-#define BLIND (LAST_RING+7) /* not a ring */
-#define Blind u.uprops[BLIND].p_flgs
-#define WOUNDED_LEGS (LAST_RING+8) /* not a ring */
-#define Wounded_legs u.uprops[WOUNDED_LEGS].p_flgs
-#define STONED (LAST_RING+9) /* not a ring */
-#define Stoned u.uprops[STONED].p_flgs
-#define PROP(x) (x-RIN_ADORNMENT) /* convert ring to index in uprops */
- unsigned umconf:1;
- char *usick_cause;
- struct prop uprops[LAST_RING+10];
-
- unsigned uswallow:1; /* set if swallowed by a monster */
- unsigned uswldtim:4; /* time you have been swallowed */
- unsigned uhs:3; /* hunger state - see hack.eat.c */
- schar ustr,ustrmax;
- schar udaminc;
- schar uac;
- int uhp,uhpmax;
- long int ugold,ugold0,uexp,urexp;
- int uhunger; /* refd only in eat.c and shk.c */
- int uinvault;
- struct monst *ustuck;
- int nr_killed[CMNUM+2]; /* used for experience bookkeeping */
-};
-
-extern struct you u;
-
-extern char *traps[];
-extern char *monnam(), *Monnam(), *amonnam(), *Amonnam(),
- *doname(), *aobjnam();
-extern char readchar();
-extern char vowels[];
-
-extern xchar curx,cury; /* cursor location on screen */
-
-extern coord bhitpos; /* place where thrown weapon falls to the ground */
-
-extern xchar seehx,seelx,seehy,seely; /* where to see*/
-extern char *save_cm,*killer;
-
-extern xchar dlevel, maxdlevel; /* dungeon level */
-
-extern long moves;
-
-extern int multi;
-
-
-extern char lock[];
-
-
-#define DIST(x1,y1,x2,y2) (((x1)-(x2))*((x1)-(x2)) + ((y1)-(y2))*((y1)-(y2)))
-
-#define PL_CSIZ 20 /* sizeof pl_character */
-#define MAX_CARR_CAP 120 /* so that boulders can be heavier */
-#define MAXLEVEL 40
-#define FAR (COLNO+2) /* position outside screen */
diff --git a/games/hack/hack.invent.c b/games/hack/hack.invent.c
deleted file mode 100644
index 66949b87afe1..000000000000
--- a/games/hack/hack.invent.c
+++ /dev/null
@@ -1,863 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.invent.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-extern struct obj *splitobj();
-extern struct obj zeroobj;
-extern char morc;
-extern char quitchars[];
-static char *xprname();
-
-#ifndef NOWORM
-#include "def.wseg.h"
-extern struct wseg *wsegs[32];
-#endif NOWORM
-
-#define NOINVSYM '#'
-
-static int lastinvnr = 51; /* 0 ... 51 */
-static
-assigninvlet(otmp)
-register struct obj *otmp;
-{
- boolean inuse[52];
- register int i;
- register struct obj *obj;
-
- for(i = 0; i < 52; i++) inuse[i] = FALSE;
- for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
- i = obj->invlet;
- if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
- if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
- if(i == otmp->invlet) otmp->invlet = 0;
- }
- if((i = otmp->invlet) &&
- (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
- return;
- for(i = lastinvnr+1; i != lastinvnr; i++) {
- if(i == 52) { i = -1; continue; }
- if(!inuse[i]) break;
- }
- otmp->invlet = (inuse[i] ? NOINVSYM :
- (i < 26) ? ('a'+i) : ('A'+i-26));
- lastinvnr = i;
-}
-
-struct obj *
-addinv(obj)
-register struct obj *obj;
-{
- register struct obj *otmp;
-
- /* merge or attach to end of chain */
- if(!invent) {
- invent = obj;
- otmp = 0;
- } else
- for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
- if(merged(otmp, obj, 0))
- return(otmp);
- if(!otmp->nobj) {
- otmp->nobj = obj;
- break;
- }
- }
- obj->nobj = 0;
-
- if(flags.invlet_constant) {
- assigninvlet(obj);
- /*
- * The ordering of the chain is nowhere significant
- * so in case you prefer some other order than the
- * historical one, change the code below.
- */
- if(otmp) { /* find proper place in chain */
- otmp->nobj = 0;
- if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
- obj->nobj = invent;
- invent = obj;
- } else
- for(otmp = invent; ; otmp = otmp->nobj) {
- if(!otmp->nobj ||
- (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
- obj->nobj = otmp->nobj;
- otmp->nobj = obj;
- break;
- }
- }
- }
- }
-
- return(obj);
-}
-
-useup(obj)
-register struct obj *obj;
-{
- if(obj->quan > 1){
- obj->quan--;
- obj->owt = weight(obj);
- } else {
- setnotworn(obj);
- freeinv(obj);
- obfree(obj, (struct obj *) 0);
- }
-}
-
-freeinv(obj)
-register struct obj *obj;
-{
- register struct obj *otmp;
-
- if(obj == invent)
- invent = invent->nobj;
- else {
- for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
- if(!otmp->nobj) panic("freeinv");
- otmp->nobj = obj->nobj;
- }
-}
-
-/* destroy object in fobj chain (if unpaid, it remains on the bill) */
-delobj(obj) register struct obj *obj; {
- freeobj(obj);
- unpobj(obj);
- obfree(obj, (struct obj *) 0);
-}
-
-/* unlink obj from chain starting with fobj */
-freeobj(obj) register struct obj *obj; {
- register struct obj *otmp;
-
- if(obj == fobj) fobj = fobj->nobj;
- else {
- for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
- if(!otmp) panic("error in freeobj");
- otmp->nobj = obj->nobj;
- }
-}
-
-/* Note: freegold throws away its argument! */
-freegold(gold) register struct gold *gold; {
- register struct gold *gtmp;
-
- if(gold == fgold) fgold = gold->ngold;
- else {
- for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
- if(!gtmp) panic("error in freegold");
- gtmp->ngold = gold->ngold;
- }
- free((char *) gold);
-}
-
-deltrap(trap)
-register struct trap *trap;
-{
- register struct trap *ttmp;
-
- if(trap == ftrap)
- ftrap = ftrap->ntrap;
- else {
- for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
- ttmp->ntrap = trap->ntrap;
- }
- free((char *) trap);
-}
-
-struct wseg *m_atseg;
-
-struct monst *
-m_at(x,y)
-register x,y;
-{
- register struct monst *mtmp;
-#ifndef NOWORM
- register struct wseg *wtmp;
-#endif NOWORM
-
- m_atseg = 0;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
- if(mtmp->mx == x && mtmp->my == y)
- return(mtmp);
-#ifndef NOWORM
- if(mtmp->wormno){
- for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
- if(wtmp->wx == x && wtmp->wy == y){
- m_atseg = wtmp;
- return(mtmp);
- }
- }
-#endif NOWORM
- }
- return(0);
-}
-
-struct obj *
-o_at(x,y)
-register x,y;
-{
- register struct obj *otmp;
-
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->ox == x && otmp->oy == y) return(otmp);
- return(0);
-}
-
-struct obj *
-sobj_at(n,x,y)
-register n,x,y;
-{
- register struct obj *otmp;
-
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
- return(otmp);
- return(0);
-}
-
-carried(obj) register struct obj *obj; {
-register struct obj *otmp;
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp == obj) return(1);
- return(0);
-}
-
-carrying(type)
-register int type;
-{
- register struct obj *otmp;
-
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp->otyp == type)
- return(TRUE);
- return(FALSE);
-}
-
-struct obj *
-o_on(id, objchn) unsigned int id; register struct obj *objchn; {
- while(objchn) {
- if(objchn->o_id == id) return(objchn);
- objchn = objchn->nobj;
- }
- return((struct obj *) 0);
-}
-
-struct trap *
-t_at(x,y)
-register x,y;
-{
- register struct trap *trap = ftrap;
- while(trap) {
- if(trap->tx == x && trap->ty == y) return(trap);
- trap = trap->ntrap;
- }
- return(0);
-}
-
-struct gold *
-g_at(x,y)
-register x,y;
-{
- register struct gold *gold = fgold;
- while(gold) {
- if(gold->gx == x && gold->gy == y) return(gold);
- gold = gold->ngold;
- }
- return(0);
-}
-
-/* make dummy object structure containing gold - for temporary use only */
-struct obj *
-mkgoldobj(q)
-register long q;
-{
- register struct obj *otmp;
-
- otmp = newobj(0);
- /* should set o_id etc. but otmp will be freed soon */
- otmp->olet = '$';
- u.ugold -= q;
- OGOLD(otmp) = q;
- flags.botl = 1;
- return(otmp);
-}
-
-/*
- * getobj returns:
- * struct obj *xxx: object to do something with.
- * (struct obj *) 0 error return: no object.
- * &zeroobj explicitly no object (as in w-).
- */
-struct obj *
-getobj(let,word)
-register char *let,*word;
-{
- register struct obj *otmp;
- register char ilet,ilet1,ilet2;
- char buf[BUFSZ];
- char lets[BUFSZ];
- register int foo = 0, foo2;
- register char *bp = buf;
- xchar allowcnt = 0; /* 0, 1 or 2 */
- boolean allowgold = FALSE;
- boolean allowall = FALSE;
- boolean allownone = FALSE;
- xchar foox = 0;
- long cnt;
-
- if(*let == '0') let++, allowcnt = 1;
- if(*let == '$') let++, allowgold = TRUE;
- if(*let == '#') let++, allowall = TRUE;
- if(*let == '-') let++, allownone = TRUE;
- if(allownone) *bp++ = '-';
- if(allowgold) *bp++ = '$';
- if(bp > buf && bp[-1] == '-') *bp++ = ' ';
-
- ilet = 'a';
- for(otmp = invent; otmp; otmp = otmp->nobj){
- if(!*let || index(let, otmp->olet)) {
- bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
-
- /* ugly check: remove inappropriate things */
- if((!strcmp(word, "take off") &&
- !(otmp->owornmask & (W_ARMOR - W_ARM2)))
- || (!strcmp(word, "wear") &&
- (otmp->owornmask & (W_ARMOR | W_RING)))
- || (!strcmp(word, "wield") &&
- (otmp->owornmask & W_WEP))) {
- foo--;
- foox++;
- }
- }
- if(ilet == 'z') ilet = 'A'; else ilet++;
- }
- bp[foo] = 0;
- if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
- (void) strcpy(lets, bp); /* necessary since we destroy buf */
- if(foo > 5) { /* compactify string */
- foo = foo2 = 1;
- ilet2 = bp[0];
- ilet1 = bp[1];
- while(ilet = bp[++foo2] = bp[++foo]){
- if(ilet == ilet1+1){
- if(ilet1 == ilet2+1)
- bp[foo2 - 1] = ilet1 = '-';
- else if(ilet2 == '-') {
- bp[--foo2] = ++ilet1;
- continue;
- }
- }
- ilet2 = ilet1;
- ilet1 = ilet;
- }
- }
- if(!foo && !allowall && !allowgold && !allownone) {
- pline("You don't have anything %sto %s.",
- foox ? "else " : "", word);
- return(0);
- }
- for(;;) {
- if(!buf[0])
- pline("What do you want to %s [*]? ", word);
- else
- pline("What do you want to %s [%s or ?*]? ",
- word, buf);
-
- cnt = 0;
- ilet = readchar();
- while(digit(ilet) && allowcnt) {
- if (cnt < 100000000)
- cnt = 10*cnt + (ilet - '0');
- else
- cnt = 999999999;
- allowcnt = 2; /* signal presence of cnt */
- ilet = readchar();
- }
- if(digit(ilet)) {
- pline("No count allowed with this command.");
- continue;
- }
- if(index(quitchars,ilet))
- return((struct obj *)0);
- if(ilet == '-') {
- return(allownone ? &zeroobj : (struct obj *) 0);
- }
- if(ilet == '$') {
- if(!allowgold){
- pline("You cannot %s gold.", word);
- continue;
- }
- if(!(allowcnt == 2 && cnt < u.ugold))
- cnt = u.ugold;
- return(mkgoldobj(cnt));
- }
- if(ilet == '?') {
- doinv(lets);
- if(!(ilet = morc)) continue;
- /* he typed a letter (not a space) to more() */
- } else if(ilet == '*') {
- doinv((char *) 0);
- if(!(ilet = morc)) continue;
- /* ... */
- }
- if(flags.invlet_constant) {
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp->invlet == ilet) break;
- } else {
- if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
- ilet -= 'a';
- for(otmp = invent; otmp && ilet;
- ilet--, otmp = otmp->nobj) ;
- }
- if(!otmp) {
- pline("You don't have that object.");
- continue;
- }
- if(cnt < 0 || otmp->quan < cnt) {
- pline("You don't have that many! [You have %u]"
- , otmp->quan);
- continue;
- }
- break;
- }
- if(!allowall && let && !index(let,otmp->olet)) {
- pline("That is a silly thing to %s.",word);
- return(0);
- }
- if(allowcnt == 2) { /* cnt given */
- if(cnt == 0) return(0);
- if(cnt != otmp->quan) {
- register struct obj *obj;
- obj = splitobj(otmp, (int) cnt);
- if(otmp == uwep) setuwep(obj);
- }
- }
- return(otmp);
-}
-
-ckunpaid(otmp) register struct obj *otmp; {
- return( otmp->unpaid );
-}
-
-/* interactive version of getobj - used for Drop and Identify */
-/* return the number of times fn was called successfully */
-ggetobj(word, fn, max)
-char *word;
-int (*fn)(), max;
-{
-char buf[BUFSZ];
-register char *ip;
-register char sym;
-register int oletct = 0, iletct = 0;
-register boolean allflag = FALSE;
-char olets[20], ilets[20];
-int (*ckfn)() = (int (*)()) 0;
-xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */
- if(!invent && !allowgold){
- pline("You have nothing to %s.", word);
- return(0);
- } else {
- register struct obj *otmp = invent;
- register int uflg = 0;
-
- if(allowgold) ilets[iletct++] = '$';
- ilets[iletct] = 0;
- while(otmp) {
- if(!index(ilets, otmp->olet)){
- ilets[iletct++] = otmp->olet;
- ilets[iletct] = 0;
- }
- if(otmp->unpaid) uflg = 1;
- otmp = otmp->nobj;
- }
- ilets[iletct++] = ' ';
- if(uflg) ilets[iletct++] = 'u';
- if(invent) ilets[iletct++] = 'a';
- ilets[iletct] = 0;
- }
- pline("What kinds of thing do you want to %s? [%s] ",
- word, ilets);
- getlin(buf);
- if(buf[0] == '\033') {
- clrlin();
- return(0);
- }
- ip = buf;
- olets[0] = 0;
- while(sym = *ip++){
- if(sym == ' ') continue;
- if(sym == '$') {
- if(allowgold == 1)
- (*fn)(mkgoldobj(u.ugold));
- else if(!u.ugold)
- pline("You have no gold.");
- allowgold = 2;
- } else
- if(sym == 'a' || sym == 'A') allflag = TRUE; else
- if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
- if(index("!%?[()=*/\"0", sym)){
- if(!index(olets, sym)){
- olets[oletct++] = sym;
- olets[oletct] = 0;
- }
- }
- else pline("You don't have any %c's.", sym);
- }
- if(allowgold == 2 && !oletct)
- return(1); /* he dropped gold (or at least tried to) */
- else
- return(askchain(invent, olets, allflag, fn, ckfn, max));
-}
-
-/*
- * Walk through the chain starting at objchn and ask for all objects
- * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
- * whether the action in question (i.e., fn) has to be performed.
- * If allflag then no questions are asked. Max gives the max nr of
- * objects to be treated. Return the number of objects treated.
- */
-askchain(objchn, olets, allflag, fn, ckfn, max)
-struct obj *objchn;
-register char *olets;
-int allflag;
-int (*fn)(), (*ckfn)();
-int max;
-{
-register struct obj *otmp, *otmp2;
-register char sym, ilet;
-register int cnt = 0;
- ilet = 'a'-1;
- for(otmp = objchn; otmp; otmp = otmp2){
- if(ilet == 'z') ilet = 'A'; else ilet++;
- otmp2 = otmp->nobj;
- if(olets && *olets && !index(olets, otmp->olet)) continue;
- if(ckfn && !(*ckfn)(otmp)) continue;
- if(!allflag) {
- pline(xprname(otmp, ilet));
- addtopl(" [nyaq]? ");
- sym = readchar();
- }
- else sym = 'y';
-
- switch(sym){
- case 'a':
- allflag = 1;
- case 'y':
- cnt += (*fn)(otmp);
- if(--max == 0) goto ret;
- case 'n':
- default:
- break;
- case 'q':
- goto ret;
- }
- }
- pline(cnt ? "That was all." : "No applicable objects.");
-ret:
- return(cnt);
-}
-
-obj_to_let(obj) /* should of course only be called for things in invent */
-register struct obj *obj;
-{
- register struct obj *otmp;
- register char ilet;
-
- if(flags.invlet_constant)
- return(obj->invlet);
- ilet = 'a';
- for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
- if(++ilet > 'z') ilet = 'A';
- return(otmp ? ilet : NOINVSYM);
-}
-
-prinv(obj)
-register struct obj *obj;
-{
- pline(xprname(obj, obj_to_let(obj)));
-}
-
-static char *
-xprname(obj,let)
-register struct obj *obj;
-register char let;
-{
- static char li[BUFSZ];
-
- (void) sprintf(li, "%c - %s.",
- flags.invlet_constant ? obj->invlet : let,
- doname(obj));
- return(li);
-}
-
-ddoinv()
-{
- doinv((char *) 0);
- return(0);
-}
-
-/* called with 0 or "": all objects in inventory */
-/* otherwise: all objects with (serial) letter in lets */
-doinv(lets)
-register char *lets;
-{
- register struct obj *otmp;
- register char ilet;
- int ct = 0;
- char any[BUFSZ];
-
- morc = 0; /* just to be sure */
-
- if(!invent){
- pline("Not carrying anything.");
- return;
- }
-
- cornline(0, (char *) 0);
- ilet = 'a';
- for(otmp = invent; otmp; otmp = otmp->nobj) {
- if(flags.invlet_constant) ilet = otmp->invlet;
- if(!lets || !*lets || index(lets, ilet)) {
- cornline(1, xprname(otmp, ilet));
- any[ct++] = ilet;
- }
- if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
- }
- any[ct] = 0;
- cornline(2, any);
-}
-
-dotypeinv () /* free after Robert Viduya */
-/* Changed to one type only, so he doesnt have to type cr */
-{
- char c, ilet;
- char stuff[BUFSZ];
- register int stct;
- register struct obj *otmp;
- boolean billx = inshop() && doinvbill(0);
- boolean unpd = FALSE;
-
- if (!invent && !u.ugold && !billx) {
- pline ("You aren't carrying anything.");
- return(0);
- }
-
- stct = 0;
- if(u.ugold) stuff[stct++] = '$';
- stuff[stct] = 0;
- for(otmp = invent; otmp; otmp = otmp->nobj) {
- if (!index (stuff, otmp->olet)) {
- stuff[stct++] = otmp->olet;
- stuff[stct] = 0;
- }
- if(otmp->unpaid)
- unpd = TRUE;
- }
- if(unpd) stuff[stct++] = 'u';
- if(billx) stuff[stct++] = 'x';
- stuff[stct] = 0;
-
- if(stct > 1) {
- pline ("What type of object [%s] do you want an inventory of? ",
- stuff);
- c = readchar();
- if(index(quitchars,c)) return(0);
- } else
- c = stuff[0];
-
- if(c == '$')
- return(doprgold());
-
- if(c == 'x' || c == 'X') {
- if(billx)
- (void) doinvbill(1);
- else
- pline("No used-up objects on the shopping bill.");
- return(0);
- }
-
- if((c == 'u' || c == 'U') && !unpd) {
- pline("You are not carrying any unpaid objects.");
- return(0);
- }
-
- stct = 0;
- ilet = 'a';
- for (otmp = invent; otmp; otmp = otmp -> nobj) {
- if(flags.invlet_constant) ilet = otmp->invlet;
- if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
- stuff[stct++] = ilet;
- if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
- }
- stuff[stct] = '\0';
- if(stct == 0)
- pline("You have no such objects.");
- else
- doinv (stuff);
-
- return(0);
-}
-
-/* look at what is here */
-dolook() {
- register struct obj *otmp, *otmp0;
- register struct gold *gold;
- char *verb = Blind ? "feel" : "see";
- int ct = 0;
-
- if(!u.uswallow) {
- if(Blind) {
- pline("You try to feel what is lying here on the floor.");
- if(Levitation) { /* ab@unido */
- pline("You cannot reach the floor!");
- return(1);
- }
- }
- otmp0 = o_at(u.ux, u.uy);
- gold = g_at(u.ux, u.uy);
- }
-
- if(u.uswallow || (!otmp0 && !gold)) {
- pline("You %s no objects here.", verb);
- return(!!Blind);
- }
-
- cornline(0, "Things that are here:");
- for(otmp = otmp0; otmp; otmp = otmp->nobj) {
- if(otmp->ox == u.ux && otmp->oy == u.uy) {
- ct++;
- cornline(1, doname(otmp));
- if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
- pline("Touching the dead cockatrice is a fatal mistake ...");
- pline("You die ...");
- killer = "dead cockatrice";
- done("died");
- }
- }
- }
-
- if(gold) {
- char gbuf[30];
-
- (void) sprintf(gbuf, "%ld gold piece%s",
- gold->amount, plur(gold->amount));
- if(!ct++)
- pline("You %s here %s.", verb, gbuf);
- else
- cornline(1, gbuf);
- }
-
- if(ct == 1 && !gold) {
- pline("You %s here %s.", verb, doname(otmp0));
- cornline(3, (char *) 0);
- }
- if(ct > 1)
- cornline(2, (char *) 0);
- return(!!Blind);
-}
-
-stackobj(obj) register struct obj *obj; {
-register struct obj *otmp = fobj;
- for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
- if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
- merged(obj,otmp,1))
- return;
-}
-
-/* merge obj with otmp and delete obj if types agree */
-merged(otmp,obj,lose) register struct obj *otmp, *obj; {
- if(obj->otyp == otmp->otyp &&
- obj->unpaid == otmp->unpaid &&
- obj->spe == otmp->spe &&
- obj->dknown == otmp->dknown &&
- obj->cursed == otmp->cursed &&
- (index("%*?!", obj->olet) ||
- (obj->known == otmp->known &&
- (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
- otmp->quan += obj->quan;
- otmp->owt += obj->owt;
- if(lose) freeobj(obj);
- obfree(obj,otmp); /* free(obj), bill->otmp */
- return(1);
- } else return(0);
-}
-
-/*
- * Gold is no longer displayed; in fact, when you have a lot of money,
- * it may take a while before you have counted it all.
- * [Bug: d$ and pickup still tell you how much it was.]
- */
-extern int (*occupation)();
-extern char *occtxt;
-static long goldcounted;
-
-countgold(){
- if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
- long eps = 0;
- if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
- pline("You probably have about %ld gold pieces.",
- u.ugold + eps);
- return(0); /* done */
- }
- return(1); /* continue */
-}
-
-doprgold(){
- if(!u.ugold)
- pline("You do not carry any gold.");
- else if(u.ugold <= 500)
- pline("You are carrying %ld gold pieces.", u.ugold);
- else {
- pline("You sit down in order to count your gold pieces.");
- goldcounted = 500;
- occupation = countgold;
- occtxt = "counting your gold";
- }
- return(1);
-}
-
-/* --- end of gold counting section --- */
-
-doprwep(){
- if(!uwep) pline("You are empty handed.");
- else prinv(uwep);
- return(0);
-}
-
-doprarm(){
- if(!uarm && !uarmg && !uarms && !uarmh)
- pline("You are not wearing any armor.");
- else {
- char lets[6];
- register int ct = 0;
-
- if(uarm) lets[ct++] = obj_to_let(uarm);
- if(uarm2) lets[ct++] = obj_to_let(uarm2);
- if(uarmh) lets[ct++] = obj_to_let(uarmh);
- if(uarms) lets[ct++] = obj_to_let(uarms);
- if(uarmg) lets[ct++] = obj_to_let(uarmg);
- lets[ct] = 0;
- doinv(lets);
- }
- return(0);
-}
-
-doprring(){
- if(!uleft && !uright)
- pline("You are not wearing any rings.");
- else {
- char lets[3];
- register int ct = 0;
-
- if(uleft) lets[ct++] = obj_to_let(uleft);
- if(uright) lets[ct++] = obj_to_let(uright);
- lets[ct] = 0;
- doinv(lets);
- }
- return(0);
-}
-
-digit(c) char c; {
- return(c >= '0' && c <= '9');
-}
diff --git a/games/hack/hack.ioctl.c b/games/hack/hack.ioctl.c
deleted file mode 100644
index 6669ceaba363..000000000000
--- a/games/hack/hack.ioctl.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.ioctl.c - version 1.0.2 */
-
-/* This cannot be part of hack.tty.c (as it was earlier) since on some
- systems (e.g. MUNIX) the include files <termio.h> and <sgtty.h>
- define the same constants, and the C preprocessor complains. */
-#include <stdio.h>
-#include "config.h"
-#ifdef BSD
-#include <sgtty.h>
-struct ltchars ltchars, ltchars0;
-#else
-#include <termio.h> /* also includes part of <sgtty.h> */
-struct termio termio;
-#endif BSD
-
-getioctls() {
-#ifdef BSD
- (void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) &ltchars);
- (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars0);
-#else
- (void) ioctl(fileno(stdin), (int) TCGETA, &termio);
-#endif BSD
-}
-
-setioctls() {
-#ifdef BSD
- (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars);
-#else
- (void) ioctl(fileno(stdin), (int) TCSETA, &termio);
-#endif BSD
-}
-
-#ifdef SUSPEND /* implies BSD */
-dosuspend() {
-#include <signal.h>
-#ifdef SIGTSTP
- if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
- settty((char *) 0);
- (void) signal(SIGTSTP, SIG_DFL);
- (void) kill(0, SIGTSTP);
- gettty();
- setftty();
- docrt();
- } else {
- pline("I don't think your shell has job control.");
- }
-#else SIGTSTP
- pline("Sorry, it seems we have no SIGTSTP here. Try ! or S.");
-#endif SIGTSTP
- return(0);
-}
-#endif SUSPEND
diff --git a/games/hack/hack.lev.c b/games/hack/hack.lev.c
deleted file mode 100644
index f011f675fb8a..000000000000
--- a/games/hack/hack.lev.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.lev.c - version 1.0.3 */
-
-#include "hack.h"
-#include "def.mkroom.h"
-#include <stdio.h>
-extern struct monst *restmonchn();
-extern struct obj *restobjchn();
-extern struct obj *billobjs;
-extern char *itoa();
-extern char SAVEF[];
-extern int hackpid;
-extern xchar dlevel;
-extern char nul[];
-
-#ifndef NOWORM
-#include "def.wseg.h"
-extern struct wseg *wsegs[32], *wheads[32];
-extern long wgrowtime[32];
-#endif NOWORM
-
-boolean level_exists[MAXLEVEL+1];
-
-savelev(fd,lev)
-int fd;
-xchar lev;
-{
-#ifndef NOWORM
- register struct wseg *wtmp, *wtmp2;
- register tmp;
-#endif NOWORM
-
- if(fd < 0) panic("Save on bad file!"); /* impossible */
- if(lev >= 0 && lev <= MAXLEVEL)
- level_exists[lev] = TRUE;
-
- bwrite(fd,(char *) &hackpid,sizeof(hackpid));
- bwrite(fd,(char *) &lev,sizeof(lev));
- bwrite(fd,(char *) levl,sizeof(levl));
- bwrite(fd,(char *) &moves,sizeof(long));
- bwrite(fd,(char *) &xupstair,sizeof(xupstair));
- bwrite(fd,(char *) &yupstair,sizeof(yupstair));
- bwrite(fd,(char *) &xdnstair,sizeof(xdnstair));
- bwrite(fd,(char *) &ydnstair,sizeof(ydnstair));
- savemonchn(fd, fmon);
- savegoldchn(fd, fgold);
- savetrapchn(fd, ftrap);
- saveobjchn(fd, fobj);
- saveobjchn(fd, billobjs);
- billobjs = 0;
- save_engravings(fd);
-#ifndef QUEST
- bwrite(fd,(char *) rooms,sizeof(rooms));
- bwrite(fd,(char *) doors,sizeof(doors));
-#endif QUEST
- fgold = 0;
- ftrap = 0;
- fmon = 0;
- fobj = 0;
-#ifndef NOWORM
- bwrite(fd,(char *) wsegs,sizeof(wsegs));
- for(tmp=1; tmp<32; tmp++){
- for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
- wtmp2 = wtmp->nseg;
- bwrite(fd,(char *) wtmp,sizeof(struct wseg));
- }
- wsegs[tmp] = 0;
- }
- bwrite(fd,(char *) wgrowtime,sizeof(wgrowtime));
-#endif NOWORM
-}
-
-bwrite(fd,loc,num)
-register fd;
-register char *loc;
-register unsigned num;
-{
-/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
- if(write(fd, loc, (int) num) != num)
- panic("cannot write %u bytes to file #%d", num, fd);
-}
-
-saveobjchn(fd,otmp)
-register fd;
-register struct obj *otmp;
-{
- register struct obj *otmp2;
- unsigned xl;
- int minusone = -1;
-
- while(otmp) {
- otmp2 = otmp->nobj;
- xl = otmp->onamelth;
- bwrite(fd, (char *) &xl, sizeof(int));
- bwrite(fd, (char *) otmp, xl + sizeof(struct obj));
- free((char *) otmp);
- otmp = otmp2;
- }
- bwrite(fd, (char *) &minusone, sizeof(int));
-}
-
-savemonchn(fd,mtmp)
-register fd;
-register struct monst *mtmp;
-{
- register struct monst *mtmp2;
- unsigned xl;
- int minusone = -1;
- struct permonst *monbegin = &mons[0];
-
- bwrite(fd, (char *) &monbegin, sizeof(monbegin));
-
- while(mtmp) {
- mtmp2 = mtmp->nmon;
- xl = mtmp->mxlth + mtmp->mnamelth;
- bwrite(fd, (char *) &xl, sizeof(int));
- bwrite(fd, (char *) mtmp, xl + sizeof(struct monst));
- if(mtmp->minvent) saveobjchn(fd,mtmp->minvent);
- free((char *) mtmp);
- mtmp = mtmp2;
- }
- bwrite(fd, (char *) &minusone, sizeof(int));
-}
-
-savegoldchn(fd,gold)
-register fd;
-register struct gold *gold;
-{
- register struct gold *gold2;
- while(gold) {
- gold2 = gold->ngold;
- bwrite(fd, (char *) gold, sizeof(struct gold));
- free((char *) gold);
- gold = gold2;
- }
- bwrite(fd, nul, sizeof(struct gold));
-}
-
-savetrapchn(fd,trap)
-register fd;
-register struct trap *trap;
-{
- register struct trap *trap2;
- while(trap) {
- trap2 = trap->ntrap;
- bwrite(fd, (char *) trap, sizeof(struct trap));
- free((char *) trap);
- trap = trap2;
- }
- bwrite(fd, nul, sizeof(struct trap));
-}
-
-getlev(fd,pid,lev)
-int fd,pid;
-xchar lev;
-{
- register struct gold *gold;
- register struct trap *trap;
-#ifndef NOWORM
- register struct wseg *wtmp;
-#endif NOWORM
- register tmp;
- long omoves;
- int hpid;
- xchar dlvl;
-
- /* First some sanity checks */
- mread(fd, (char *) &hpid, sizeof(hpid));
- mread(fd, (char *) &dlvl, sizeof(dlvl));
- if((pid && pid != hpid) || (lev && dlvl != lev)) {
- pline("Strange, this map is not as I remember it.");
- pline("Somebody is trying some trickery here ...");
- pline("This game is void ...");
- done("tricked");
- }
-
- fgold = 0;
- ftrap = 0;
- mread(fd, (char *) levl, sizeof(levl));
- mread(fd, (char *)&omoves, sizeof(omoves));
- mread(fd, (char *)&xupstair, sizeof(xupstair));
- mread(fd, (char *)&yupstair, sizeof(yupstair));
- mread(fd, (char *)&xdnstair, sizeof(xdnstair));
- mread(fd, (char *)&ydnstair, sizeof(ydnstair));
-
- fmon = restmonchn(fd);
-
- /* regenerate animals while on another level */
- { long tmoves = (moves > omoves) ? moves-omoves : 0;
- register struct monst *mtmp, *mtmp2;
- extern char genocided[];
-
- for(mtmp = fmon; mtmp; mtmp = mtmp2) {
- long newhp; /* tmoves may be very large */
-
- mtmp2 = mtmp->nmon;
- if(index(genocided, mtmp->data->mlet)) {
- mondead(mtmp);
- continue;
- }
-
- if(mtmp->mtame && tmoves > 250) {
- mtmp->mtame = 0;
- mtmp->mpeaceful = 0;
- }
-
- newhp = mtmp->mhp +
- (index(MREGEN, mtmp->data->mlet) ? tmoves : tmoves/20);
- if(newhp > mtmp->mhpmax)
- mtmp->mhp = mtmp->mhpmax;
- else
- mtmp->mhp = newhp;
- }
- }
-
- setgd();
- gold = newgold();
- mread(fd, (char *)gold, sizeof(struct gold));
- while(gold->gx) {
- gold->ngold = fgold;
- fgold = gold;
- gold = newgold();
- mread(fd, (char *)gold, sizeof(struct gold));
- }
- free((char *) gold);
- trap = newtrap();
- mread(fd, (char *)trap, sizeof(struct trap));
- while(trap->tx) {
- trap->ntrap = ftrap;
- ftrap = trap;
- trap = newtrap();
- mread(fd, (char *)trap, sizeof(struct trap));
- }
- free((char *) trap);
- fobj = restobjchn(fd);
- billobjs = restobjchn(fd);
- rest_engravings(fd);
-#ifndef QUEST
- mread(fd, (char *)rooms, sizeof(rooms));
- mread(fd, (char *)doors, sizeof(doors));
-#endif QUEST
-#ifndef NOWORM
- mread(fd, (char *)wsegs, sizeof(wsegs));
- for(tmp = 1; tmp < 32; tmp++) if(wsegs[tmp]){
- wheads[tmp] = wsegs[tmp] = wtmp = newseg();
- while(1) {
- mread(fd, (char *)wtmp, sizeof(struct wseg));
- if(!wtmp->nseg) break;
- wheads[tmp]->nseg = wtmp = newseg();
- wheads[tmp] = wtmp;
- }
- }
- mread(fd, (char *)wgrowtime, sizeof(wgrowtime));
-#endif NOWORM
-}
-
-mread(fd, buf, len)
-register fd;
-register char *buf;
-register unsigned len;
-{
- register int rlen;
- extern boolean restoring;
-
- rlen = read(fd, buf, (int) len);
- if(rlen != len){
- pline("Read %d instead of %u bytes.\n", rlen, len);
- if(restoring) {
- (void) unlink(SAVEF);
- error("Error restoring old game.");
- }
- panic("Error reading level file.");
- }
-}
-
-mklev()
-{
- extern boolean in_mklev;
-
- if(getbones()) return;
-
- in_mklev = TRUE;
- makelevel();
- in_mklev = FALSE;
-}
diff --git a/games/hack/hack.main.c b/games/hack/hack.main.c
deleted file mode 100644
index d2d59a2f3356..000000000000
--- a/games/hack/hack.main.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.main.c - version 1.0.3 */
-
-#include <stdio.h>
-#include <signal.h>
-#include "hack.h"
-
-#ifdef QUEST
-#define gamename "quest"
-#else
-#define gamename "hack"
-#endif
-
-extern char *getlogin(), *getenv();
-extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
-extern struct permonst mons[CMNUM+2];
-extern char genocided[], fut_geno[];
-
-int (*afternmv)();
-int (*occupation)();
-char *occtxt; /* defined when occupation != NULL */
-
-void done1();
-void hangup();
-
-int hackpid; /* current pid */
-int locknum; /* max num of players */
-#ifdef DEF_PAGER
-char *catmore; /* default pager */
-#endif
-char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
-char *hname; /* name of the game (argv[0] of call) */
-char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
-
-extern char *nomovemsg;
-extern long wailmsg;
-
-#ifdef CHDIR
-static void chdirx();
-#endif
-
-main(argc,argv)
-int argc;
-char *argv[];
-{
- register int fd;
-#ifdef CHDIR
- register char *dir;
-#endif
-
- hname = argv[0];
- hackpid = getpid();
-
-#ifdef CHDIR /* otherwise no chdir() */
- /*
- * See if we must change directory to the playground.
- * (Perhaps hack runs suid and playground is inaccessible
- * for the player.)
- * The environment variable HACKDIR is overridden by a
- * -d command line option (must be the first option given)
- */
-
- dir = getenv("HACKDIR");
- if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
- argc--;
- argv++;
- dir = argv[0]+2;
- if(*dir == '=' || *dir == ':') dir++;
- if(!*dir && argc > 1) {
- argc--;
- argv++;
- dir = argv[0];
- }
- if(!*dir)
- error("Flag -d must be followed by a directory name.");
- }
-#endif
-
- /*
- * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
- * 2. Use $USER or $LOGNAME (if 1. fails)
- * 3. Use getlogin() (if 2. fails)
- * The resulting name is overridden by command line options.
- * If everything fails, or if the resulting name is some generic
- * account like "games", "play", "player", "hack" then eventually
- * we'll ask him.
- * Note that we trust him here; it is possible to play under
- * somebody else's name.
- */
- { register char *s;
-
- initoptions();
- if(!*plname && (s = getenv("USER")))
- (void) strncpy(plname, s, sizeof(plname)-1);
- if(!*plname && (s = getenv("LOGNAME")))
- (void) strncpy(plname, s, sizeof(plname)-1);
- if(!*plname && (s = getlogin()))
- (void) strncpy(plname, s, sizeof(plname)-1);
- }
-
- /*
- * Now we know the directory containing 'record' and
- * may do a prscore().
- */
- if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
-#ifdef CHDIR
- chdirx(dir,0);
-#endif
- prscore(argc, argv);
- exit(0);
- }
-
- /*
- * It seems he really wants to play.
- * Remember tty modes, to be restored on exit.
- */
- gettty();
- setbuf(stdout,obuf);
- setrandom();
- startup();
- cls();
- u.uhp = 1; /* prevent RIP on early quits */
- u.ux = FAR; /* prevent nscr() */
- (void) signal(SIGHUP, hangup);
-
- /*
- * Find the creation date of this game,
- * so as to avoid restoring outdated savefiles.
- */
- gethdate(hname);
-
- /*
- * We cannot do chdir earlier, otherwise gethdate will fail.
- */
-#ifdef CHDIR
- chdirx(dir,1);
-#endif
-
- /*
- * Process options.
- */
- while(argc > 1 && argv[1][0] == '-'){
- argv++;
- argc--;
- switch(argv[0][1]){
-#ifdef WIZARD
- case 'D':
-/* if(!strcmp(getlogin(), WIZARD)) */
- wizard = TRUE;
-/* else
- printf("Sorry.\n"); */
- break;
-#endif
-#ifdef NEWS
- case 'n':
- flags.nonews = TRUE;
- break;
-#endif
- case 'u':
- if(argv[0][2])
- (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
- else if(argc > 1) {
- argc--;
- argv++;
- (void) strncpy(plname, argv[0], sizeof(plname)-1);
- } else
- printf("Player name expected after -u\n");
- break;
- default:
- /* allow -T for Tourist, etc. */
- (void) strncpy(pl_character, argv[0]+1,
- sizeof(pl_character)-1);
-
- /* printf("Unknown option: %s\n", *argv); */
- }
- }
-
- if(argc > 1)
- locknum = atoi(argv[1]);
-#ifdef MAX_NR_OF_PLAYERS
- if(!locknum || locknum > MAX_NR_OF_PLAYERS)
- locknum = MAX_NR_OF_PLAYERS;
-#endif
-#ifdef DEF_PAGER
- if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
- catmore = DEF_PAGER;
-#endif
-#ifdef MAIL
- getmailstatus();
-#endif
-#ifdef WIZARD
- if(wizard) (void) strcpy(plname, "wizard"); else
-#endif
- if(!*plname || !strncmp(plname, "player", 4)
- || !strncmp(plname, "games", 4))
- askname();
- plnamesuffix(); /* strip suffix from name; calls askname() */
- /* again if suffix was whole name */
- /* accepts any suffix */
-#ifdef WIZARD
- if(!wizard) {
-#endif
- /*
- * check for multiple games under the same name
- * (if !locknum) or check max nr of players (otherwise)
- */
- (void) signal(SIGQUIT,SIG_IGN);
- (void) signal(SIGINT,SIG_IGN);
- if(!locknum)
- (void) strcpy(lock,plname);
- getlock(); /* sets lock if locknum != 0 */
-#ifdef WIZARD
- } else {
- register char *sfoo;
- (void) strcpy(lock,plname);
- if(sfoo = getenv("MAGIC"))
- while(*sfoo) {
- switch(*sfoo++) {
- case 'n': (void) srandom(*sfoo++);
- break;
- }
- }
- if(sfoo = getenv("GENOCIDED")){
- if(*sfoo == '!'){
- register struct permonst *pm = mons;
- register char *gp = genocided;
-
- while(pm < mons+CMNUM+2){
- if(!index(sfoo, pm->mlet))
- *gp++ = pm->mlet;
- pm++;
- }
- *gp = 0;
- } else
- (void) strcpy(genocided, sfoo);
- (void) strcpy(fut_geno, genocided);
- }
- }
-#endif
- setftty();
- (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
- regularize(SAVEF+5); /* avoid . or / in name */
- if((fd = open(SAVEF,0)) >= 0 &&
- (uptodate(fd) || unlink(SAVEF) == 666)) {
- (void) signal(SIGINT,done1);
- pline("Restoring old save file...");
- (void) fflush(stdout);
- if(!dorecover(fd))
- goto not_recovered;
- pline("Hello %s, welcome to %s!", plname, gamename);
- flags.move = 0;
- } else {
-not_recovered:
- fobj = fcobj = invent = 0;
- fmon = fallen_down = 0;
- ftrap = 0;
- fgold = 0;
- flags.ident = 1;
- init_objects();
- u_init();
-
- (void) signal(SIGINT,done1);
- mklev();
- u.ux = xupstair;
- u.uy = yupstair;
- (void) inshop();
- setsee();
- flags.botlx = 1;
- makedog();
- { register struct monst *mtmp;
- if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp); /* riv05!a3 */
- }
- seemons();
-#ifdef NEWS
- if(flags.nonews || !readnews())
- /* after reading news we did docrt() already */
-#endif
- docrt();
-
- /* give welcome message before pickup messages */
- pline("Hello %s, welcome to %s!", plname, gamename);
-
- pickup(1);
- read_engr_at(u.ux,u.uy);
- flags.move = 1;
- }
-
- flags.moonphase = phase_of_the_moon();
- if(flags.moonphase == FULL_MOON) {
- pline("You are lucky! Full moon tonight.");
- u.uluck++;
- } else if(flags.moonphase == NEW_MOON) {
- pline("Be careful! New moon tonight.");
- }
-
- initrack();
-
- for(;;) {
- if(flags.move) { /* actual time passed */
-
- settrack();
-
- if(moves%2 == 0 ||
- (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
- extern struct monst *makemon();
- movemon();
- if(!rn2(70))
- (void) makemon((struct permonst *)0, 0, 0);
- }
- if(Glib) glibr();
- timeout();
- ++moves;
- if(flags.time) flags.botl = 1;
- if(u.uhp < 1) {
- pline("You die...");
- done("died");
- }
- if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
- wailmsg = moves;
- if(u.uhp == 1)
- pline("You hear the wailing of the Banshee...");
- else
- pline("You hear the howling of the CwnAnnwn...");
- }
- if(u.uhp < u.uhpmax) {
- if(u.ulevel > 9) {
- if(Regeneration || !(moves%3)) {
- flags.botl = 1;
- u.uhp += rnd((int) u.ulevel-9);
- if(u.uhp > u.uhpmax)
- u.uhp = u.uhpmax;
- }
- } else if(Regeneration ||
- (!(moves%(22-u.ulevel*2)))) {
- flags.botl = 1;
- u.uhp++;
- }
- }
- if(Teleportation && !rn2(85)) tele();
- if(Searching && multi >= 0) (void) dosearch();
- gethungry();
- invault();
- amulet();
- }
- if(multi < 0) {
- if(!++multi){
- pline(nomovemsg ? nomovemsg :
- "You can move again.");
- nomovemsg = 0;
- if(afternmv) (*afternmv)();
- afternmv = 0;
- }
- }
-
- find_ac();
-#ifndef QUEST
- if(!flags.mv || Blind)
-#endif
- {
- seeobjs();
- seemons();
- nscr();
- }
- if(flags.botl || flags.botlx) bot();
-
- flags.move = 1;
-
- if(multi >= 0 && occupation) {
- if(monster_nearby())
- stop_occupation();
- else if ((*occupation)() == 0)
- occupation = 0;
- continue;
- }
-
- if(multi > 0) {
-#ifdef QUEST
- if(flags.run >= 4) finddir();
-#endif
- lookaround();
- if(!multi) { /* lookaround may clear multi */
- flags.move = 0;
- continue;
- }
- if(flags.mv) {
- if(multi < COLNO && !--multi)
- flags.mv = flags.run = 0;
- domove();
- } else {
- --multi;
- rhack(save_cm);
- }
- } else if(multi == 0) {
-#ifdef MAIL
- ckmailstatus();
-#endif
- rhack((char *) 0);
- }
- if(multi && multi%7 == 0)
- (void) fflush(stdout);
- }
-}
-
-glo(foo)
-register foo;
-{
- /* construct the string xlock.n */
- register char *tf;
-
- tf = lock;
- while(*tf && *tf != '.') tf++;
- (void) sprintf(tf, ".%d", foo);
-}
-
-/*
- * plname is filled either by an option (-u Player or -uPlayer) or
- * explicitly (-w implies wizard) or by askname.
- * It may still contain a suffix denoting pl_character.
- */
-askname(){
-register int c,ct;
- printf("\nWho are you? ");
- (void) fflush(stdout);
- ct = 0;
- while((c = getchar()) != '\n'){
- if(c == EOF) error("End of input\n");
- /* some people get confused when their erase char is not ^H */
- if(c == '\010') {
- if(ct) ct--;
- continue;
- }
- if(c != '-')
- if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
- if(ct < sizeof(plname)-1) plname[ct++] = c;
- }
- plname[ct] = 0;
- if(ct == 0) askname();
-}
-
-/*VARARGS1*/
-impossible(s,x1,x2)
-register char *s;
-{
- pline(s,x1,x2);
- pline("Program in disorder - perhaps you'd better Quit.");
-}
-
-#ifdef CHDIR
-static void
-chdirx(dir, wr)
-char *dir;
-boolean wr;
-{
-
-#ifdef SECURE
- if(dir /* User specified directory? */
-#ifdef HACKDIR
- && strcmp(dir, HACKDIR) /* and not the default? */
-#endif
- ) {
- (void) setuid(getuid()); /* Ron Wessels */
- (void) setgid(getgid());
- }
-#endif
-
-#ifdef HACKDIR
- if(dir == NULL)
- dir = HACKDIR;
-#endif
-
- if(dir && chdir(dir) < 0) {
- perror(dir);
- error("Cannot chdir to %s.", dir);
- }
-
- /* warn the player if he cannot write the record file */
- /* perhaps we should also test whether . is writable */
- /* unfortunately the access systemcall is worthless */
- if(wr) {
- register fd;
-
- if(dir == NULL)
- dir = ".";
- if((fd = open(RECORD, 2)) < 0) {
- printf("Warning: cannot write %s/%s", dir, RECORD);
- getret();
- } else
- (void) close(fd);
- }
-}
-#endif
-
-stop_occupation()
-{
- if(occupation) {
- pline("You stop %s.", occtxt);
- occupation = 0;
- }
-}
diff --git a/games/hack/hack.makemon.c b/games/hack/hack.makemon.c
deleted file mode 100644
index bcf23b621d74..000000000000
--- a/games/hack/hack.makemon.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.makemon.c - version 1.0.2 */
-
-#include "hack.h"
-extern char fut_geno[];
-extern char *index();
-extern struct obj *mkobj_at();
-struct monst zeromonst;
-
-/*
- * called with [x,y] = coordinates;
- * [0,0] means anyplace
- * [u.ux,u.uy] means: call mnexto (if !in_mklev)
- *
- * In case we make an Orc or killer bee, we make an entire horde (swarm);
- * note that in this case we return only one of them (the one at [x,y]).
- */
-struct monst *
-makemon(ptr,x,y)
-register struct permonst *ptr;
-{
- register struct monst *mtmp;
- register tmp, ct;
- boolean anything = (!ptr);
- extern boolean in_mklev;
-
- if(x != 0 || y != 0) if(m_at(x,y)) return((struct monst *) 0);
- if(ptr){
- if(index(fut_geno, ptr->mlet)) return((struct monst *) 0);
- } else {
- ct = CMNUM - strlen(fut_geno);
- if(index(fut_geno, 'm')) ct++; /* make only 1 minotaur */
- if(index(fut_geno, '@')) ct++;
- if(ct <= 0) return(0); /* no more monsters! */
- tmp = rn2(ct*dlevel/24 + 7);
- if(tmp < dlevel - 4) tmp = rn2(ct*dlevel/24 + 12);
- if(tmp >= ct) tmp = rn1(ct - ct/2, ct/2);
- for(ct = 0; ct < CMNUM; ct++){
- ptr = &mons[ct];
- if(index(fut_geno, ptr->mlet))
- continue;
- if(!tmp--) goto gotmon;
- }
- panic("makemon?");
- }
-gotmon:
- mtmp = newmonst(ptr->pxlth);
- *mtmp = zeromonst; /* clear all entries in structure */
- for(ct = 0; ct < ptr->pxlth; ct++)
- ((char *) &(mtmp->mextra[0]))[ct] = 0;
- mtmp->nmon = fmon;
- fmon = mtmp;
- mtmp->m_id = flags.ident++;
- mtmp->data = ptr;
- mtmp->mxlth = ptr->pxlth;
- if(ptr->mlet == 'D') mtmp->mhpmax = mtmp->mhp = 80;
- else if(!ptr->mlevel) mtmp->mhpmax = mtmp->mhp = rnd(4);
- else mtmp->mhpmax = mtmp->mhp = d(ptr->mlevel, 8);
- mtmp->mx = x;
- mtmp->my = y;
- mtmp->mcansee = 1;
- if(ptr->mlet == 'M'){
- mtmp->mimic = 1;
- mtmp->mappearance = ']';
- }
- if(!in_mklev) {
- if(x == u.ux && y == u.uy && ptr->mlet != ' ')
- mnexto(mtmp);
- if(x == 0 && y == 0)
- rloc(mtmp);
- }
- if(ptr->mlet == 's' || ptr->mlet == 'S') {
- mtmp->mhide = mtmp->mundetected = 1;
- if(in_mklev)
- if(mtmp->mx && mtmp->my)
- (void) mkobj_at(0, mtmp->mx, mtmp->my);
- }
- if(ptr->mlet == ':') {
- mtmp->cham = 1;
- (void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
- }
- if(ptr->mlet == 'I' || ptr->mlet == ';')
- mtmp->minvis = 1;
- if(ptr->mlet == 'L' || ptr->mlet == 'N'
- || (in_mklev && index("&w;", ptr->mlet) && rn2(5))
- ) mtmp->msleep = 1;
-
-#ifndef NOWORM
- if(ptr->mlet == 'w' && getwn(mtmp))
- initworm(mtmp);
-#endif NOWORM
-
- if(anything) if(ptr->mlet == 'O' || ptr->mlet == 'k') {
- coord enexto();
- coord mm;
- register int cnt = rnd(10);
- mm.x = x;
- mm.y = y;
- while(cnt--) {
- mm = enexto(mm.x, mm.y);
- (void) makemon(ptr, mm.x, mm.y);
- }
- }
-
- return(mtmp);
-}
-
-coord
-enexto(xx,yy)
-register xchar xx,yy;
-{
- register xchar x,y;
- coord foo[15], *tfoo;
- int range;
-
- tfoo = foo;
- range = 1;
- do { /* full kludge action. */
- for(x = xx-range; x <= xx+range; x++)
- if(goodpos(x, yy-range)) {
- tfoo->x = x;
- tfoo++->y = yy-range;
- if(tfoo == &foo[15]) goto foofull;
- }
- for(x = xx-range; x <= xx+range; x++)
- if(goodpos(x,yy+range)) {
- tfoo->x = x;
- tfoo++->y = yy+range;
- if(tfoo == &foo[15]) goto foofull;
- }
- for(y = yy+1-range; y < yy+range; y++)
- if(goodpos(xx-range,y)) {
- tfoo->x = xx-range;
- tfoo++->y = y;
- if(tfoo == &foo[15]) goto foofull;
- }
- for(y = yy+1-range; y < yy+range; y++)
- if(goodpos(xx+range,y)) {
- tfoo->x = xx+range;
- tfoo++->y = y;
- if(tfoo == &foo[15]) goto foofull;
- }
- range++;
- } while(tfoo == foo);
-foofull:
- return( foo[rn2(tfoo-foo)] );
-}
-
-goodpos(x,y) /* used only in mnexto and rloc */
-{
- return(
- ! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 ||
- m_at(x,y) || !ACCESSIBLE(levl[x][y].typ)
- || (x == u.ux && y == u.uy)
- || sobj_at(ENORMOUS_ROCK, x, y)
- ));
-}
-
-rloc(mtmp)
-struct monst *mtmp;
-{
- register tx,ty;
- register char ch = mtmp->data->mlet;
-
-#ifndef NOWORM
- if(ch == 'w' && mtmp->mx) return; /* do not relocate worms */
-#endif NOWORM
- do {
- tx = rn1(COLNO-3,2);
- ty = rn2(ROWNO);
- } while(!goodpos(tx,ty));
- mtmp->mx = tx;
- mtmp->my = ty;
- if(u.ustuck == mtmp){
- if(u.uswallow) {
- u.ux = tx;
- u.uy = ty;
- docrt();
- } else u.ustuck = 0;
- }
- pmon(mtmp);
-}
-
-struct monst *
-mkmon_at(let,x,y)
-char let;
-register int x,y;
-{
- register int ct;
- register struct permonst *ptr;
-
- for(ct = 0; ct < CMNUM; ct++) {
- ptr = &mons[ct];
- if(ptr->mlet == let)
- return(makemon(ptr,x,y));
- }
- return(0);
-}
diff --git a/games/hack/hack.mfndpos.h b/games/hack/hack.mfndpos.h
deleted file mode 100644
index f4da529fc7fc..000000000000
--- a/games/hack/hack.mfndpos.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mfndpos.h - version 1.0.2 */
-
-#define ALLOW_TRAPS 0777
-#define ALLOW_U 01000
-#define ALLOW_M 02000
-#define ALLOW_TM 04000
-#define ALLOW_ALL (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS)
-#define ALLOW_SSM 010000
-#define ALLOW_ROCK 020000
-#define NOTONL 040000
-#define NOGARLIC 0100000
diff --git a/games/hack/hack.mhitu.c b/games/hack/hack.mhitu.c
deleted file mode 100644
index ae7d204b17e7..000000000000
--- a/games/hack/hack.mhitu.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mhitu.c - version 1.0.3 */
-
-#include "hack.h"
-extern struct monst *makemon();
-
-/*
- * mhitu: monster hits you
- * returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise
- */
-mhitu(mtmp)
-register struct monst *mtmp;
-{
- register struct permonst *mdat = mtmp->data;
- register int tmp, ctmp;
-
- nomul(0);
-
- /* If swallowed, can only be affected by hissers and by u.ustuck */
- if(u.uswallow) {
- if(mtmp != u.ustuck) {
- if(mdat->mlet == 'c' && !rn2(13)) {
- pline("Outside, you hear %s's hissing!",
- monnam(mtmp));
- pline("%s gets turned to stone!",
- Monnam(u.ustuck));
- pline("And the same fate befalls you.");
- done_in_by(mtmp);
- /* "notreached": not return(1); */
- }
- return(0);
- }
- switch(mdat->mlet) { /* now mtmp == u.ustuck */
- case ',':
- youswld(mtmp, (u.uac > 0) ? u.uac+4 : 4,
- 5, "The trapper");
- break;
- case '\'':
- youswld(mtmp,rnd(6),7,"The lurker above");
- break;
- case 'P':
- youswld(mtmp,d(2,4),12,"The purple worm");
- break;
- default:
- /* This is not impossible! */
- pline("The mysterious monster totally digests you.");
- u.uhp = 0;
- }
- if(u.uhp < 1) done_in_by(mtmp);
- return(0);
- }
-
- if(mdat->mlet == 'c' && Stoned)
- return(0);
-
- /* make eels visible the moment they hit/miss us */
- if(mdat->mlet == ';' && mtmp->minvis && cansee(mtmp->mx,mtmp->my)){
- mtmp->minvis = 0;
- pmon(mtmp);
- }
- if(!index("1&DuxynNF",mdat->mlet))
- tmp = hitu(mtmp,d(mdat->damn,mdat->damd));
- else
- tmp = 0;
- if(index(UNDEAD, mdat->mlet) && midnight())
- tmp += hitu(mtmp,d(mdat->damn,mdat->damd));
-
- ctmp = tmp && !mtmp->mcan &&
- (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50));
- switch(mdat->mlet) {
- case '1':
- if(wiz_hit(mtmp)) return(1); /* he disappeared */
- break;
- case '&':
- if(!mtmp->cham && !mtmp->mcan && !rn2(13)) {
- (void) makemon(PM_DEMON,u.ux,u.uy);
- } else {
- (void) hitu(mtmp,d(2,6));
- (void) hitu(mtmp,d(2,6));
- (void) hitu(mtmp,rnd(3));
- (void) hitu(mtmp,rnd(3));
- (void) hitu(mtmp,rn1(4,2));
- }
- break;
- case ',':
- if(tmp) justswld(mtmp,"The trapper");
- break;
- case '\'':
- if(tmp) justswld(mtmp, "The lurker above");
- break;
- case ';':
- if(ctmp) {
- if(!u.ustuck && !rn2(10)) {
- pline("%s swings itself around you!",
- Monnam(mtmp));
- u.ustuck = mtmp;
- } else if(u.ustuck == mtmp &&
- levl[mtmp->mx][mtmp->my].typ == POOL) {
- pline("%s drowns you ...", Monnam(mtmp));
- done("drowned");
- }
- }
- break;
- case 'A':
- if(ctmp && rn2(2)) {
- if(Poison_resistance)
- pline("The sting doesn't seem to affect you.");
- else {
- pline("You feel weaker!");
- losestr(1);
- }
- }
- break;
- case 'C':
- (void) hitu(mtmp,rnd(6));
- break;
- case 'c':
- if(!rn2(5)) {
- pline("You hear %s's hissing!", monnam(mtmp));
- if(ctmp || !rn2(20) || (flags.moonphase == NEW_MOON
- && !carrying(DEAD_LIZARD))) {
- Stoned = 5;
- /* pline("You get turned to stone!"); */
- /* done_in_by(mtmp); */
- }
- }
- break;
- case 'D':
- if(rn2(6) || mtmp->mcan) {
- (void) hitu(mtmp,d(3,10));
- (void) hitu(mtmp,rnd(8));
- (void) hitu(mtmp,rnd(8));
- break;
- }
- kludge("%s breathes fire!","The dragon");
- buzz(-1,mtmp->mx,mtmp->my,u.ux-mtmp->mx,u.uy-mtmp->my);
- break;
- case 'd':
- (void) hitu(mtmp,d(2, (flags.moonphase == FULL_MOON) ? 3 : 4));
- break;
- case 'e':
- (void) hitu(mtmp,d(3,6));
- break;
- case 'F':
- if(mtmp->mcan) break;
- kludge("%s explodes!","The freezing sphere");
- if(Cold_resistance) pline("You don't seem affected by it.");
- else {
- xchar dn;
- if(17-(u.ulevel/2) > rnd(20)) {
- pline("You get blasted!");
- dn = 6;
- } else {
- pline("You duck the blast...");
- dn = 3;
- }
- losehp_m(d(dn,6), mtmp);
- }
- mondead(mtmp);
- return(1);
- case 'g':
- if(ctmp && multi >= 0 && !rn2(3)) {
- kludge("You are frozen by %ss juices","the cube'");
- nomul(-rnd(10));
- }
- break;
- case 'h':
- if(ctmp && multi >= 0 && !rn2(5)) {
- nomul(-rnd(10));
- kludge("You are put to sleep by %ss bite!",
- "the homunculus'");
- }
- break;
- case 'j':
- tmp = hitu(mtmp,rnd(3));
- tmp &= hitu(mtmp,rnd(3));
- if(tmp){
- (void) hitu(mtmp,rnd(4));
- (void) hitu(mtmp,rnd(4));
- }
- break;
- case 'k':
- if((hitu(mtmp,rnd(4)) || !rn2(3)) && ctmp){
- poisoned("bee's sting",mdat->mname);
- }
- break;
- case 'L':
- if(tmp) stealgold(mtmp);
- break;
- case 'N':
- if(mtmp->mcan && !Blind) {
- pline("%s tries to seduce you, but you seem not interested.",
- Amonnam(mtmp, "plain"));
- if(rn2(3)) rloc(mtmp);
- } else if(steal(mtmp)) {
- rloc(mtmp);
- mtmp->mflee = 1;
- }
- break;
- case 'n':
- if(!uwep && !uarm && !uarmh && !uarms && !uarmg) {
- pline("%s hits! (I hope you don't mind)",
- Monnam(mtmp));
- u.uhp += rnd(7);
- if(!rn2(7)) u.uhpmax++;
- if(u.uhp > u.uhpmax) u.uhp = u.uhpmax;
- flags.botl = 1;
- if(!rn2(50)) rloc(mtmp);
- } else {
- (void) hitu(mtmp,d(2,6));
- (void) hitu(mtmp,d(2,6));
- }
- break;
- case 'o':
- tmp = hitu(mtmp,rnd(6));
- if(hitu(mtmp,rnd(6)) && tmp && /* hits with both paws */
- !u.ustuck && rn2(2)) {
- u.ustuck = mtmp;
- kludge("%s has grabbed you!","The owlbear");
- u.uhp -= d(2,8);
- } else if(u.ustuck == mtmp) {
- u.uhp -= d(2,8);
- pline("You are being crushed.");
- }
- break;
- case 'P':
- if(ctmp && !rn2(4))
- justswld(mtmp,"The purple worm");
- else
- (void) hitu(mtmp,d(2,4));
- break;
- case 'Q':
- (void) hitu(mtmp,rnd(2));
- (void) hitu(mtmp,rnd(2));
- break;
- case 'R':
- if(tmp && uarmh && !uarmh->rustfree &&
- (int) uarmh->spe >= -1) {
- pline("Your helmet rusts!");
- uarmh->spe--;
- } else
- if(ctmp && uarm && !uarm->rustfree && /* Mike Newton */
- uarm->otyp < STUDDED_LEATHER_ARMOR &&
- (int) uarm->spe >= -1) {
- pline("Your armor rusts!");
- uarm->spe--;
- }
- break;
- case 'S':
- if(ctmp && !rn2(8)) {
- poisoned("snake's bite",mdat->mname);
- }
- break;
- case 's':
- if(tmp && !rn2(8)) {
- poisoned("scorpion's sting",mdat->mname);
- }
- (void) hitu(mtmp,rnd(8));
- (void) hitu(mtmp,rnd(8));
- break;
- case 'T':
- (void) hitu(mtmp,rnd(6));
- (void) hitu(mtmp,rnd(6));
- break;
- case 't':
- if(!rn2(5)) rloc(mtmp);
- break;
- case 'u':
- mtmp->mflee = 1;
- break;
- case 'U':
- (void) hitu(mtmp,d(3,4));
- (void) hitu(mtmp,d(3,4));
- break;
- case 'v':
- if(ctmp && !u.ustuck) u.ustuck = mtmp;
- break;
- case 'V':
- if(tmp) u.uhp -= 4;
- if(ctmp) losexp();
- break;
- case 'W':
- if(ctmp) losexp();
- break;
-#ifndef NOWORM
- case 'w':
- if(tmp) wormhit(mtmp);
-#endif NOWORM
- break;
- case 'X':
- (void) hitu(mtmp,rnd(5));
- (void) hitu(mtmp,rnd(5));
- (void) hitu(mtmp,rnd(5));
- break;
- case 'x':
- { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
- pline("%s pricks in your %s leg!",
- Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left");
- set_wounded_legs(side, rnd(50));
- losehp_m(2, mtmp);
- break;
- }
- case 'y':
- if(mtmp->mcan) break;
- mondead(mtmp);
- if(!Blind) {
- pline("You are blinded by a blast of light!");
- Blind = d(4,12);
- seeoff(0);
- }
- return(1);
- case 'Y':
- (void) hitu(mtmp,rnd(6));
- break;
- }
- if(u.uhp < 1) done_in_by(mtmp);
- return(0);
-}
-
-hitu(mtmp,dam)
-register struct monst *mtmp;
-register dam;
-{
- register tmp, res;
-
- nomul(0);
- if(u.uswallow) return(0);
-
- if(mtmp->mhide && mtmp->mundetected) {
- mtmp->mundetected = 0;
- if(!Blind) {
- register struct obj *obj;
- extern char * Xmonnam();
- if(obj = o_at(mtmp->mx,mtmp->my))
- pline("%s was hidden under %s!",
- Xmonnam(mtmp), doname(obj));
- }
- }
-
- tmp = u.uac;
- /* give people with Ac = -10 at least some vulnerability */
- if(tmp < 0) {
- dam += tmp; /* decrease damage */
- if(dam <= 0) dam = 1;
- tmp = -rn2(-tmp);
- }
- tmp += mtmp->data->mlevel;
- if(multi < 0) tmp += 4;
- if((Invis && mtmp->data->mlet != 'I') || !mtmp->mcansee) tmp -= 2;
- if(mtmp->mtrapped) tmp -= 2;
- if(tmp <= rnd(20)) {
- if(Blind) pline("It misses.");
- else pline("%s misses.",Monnam(mtmp));
- res = 0;
- } else {
- if(Blind) pline("It hits!");
- else pline("%s hits!",Monnam(mtmp));
- losehp_m(dam, mtmp);
- res = 1;
- }
- stop_occupation();
- return(res);
-}
diff --git a/games/hack/hack.mklev.c b/games/hack/hack.mklev.c
deleted file mode 100644
index 89040213744d..000000000000
--- a/games/hack/hack.mklev.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mklev.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern char *getlogin(), *getenv();
-extern struct monst *makemon();
-extern struct obj *mkobj_at();
-extern struct trap *maketrap();
-
-#define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx)
-#define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly)
-
-#include "def.mkroom.h"
-#define XLIM 4 /* define minimum required space around a room */
-#define YLIM 3
-boolean secret; /* TRUE while making a vault: increase [XY]LIM */
-struct mkroom rooms[MAXNROFROOMS+1];
-int smeq[MAXNROFROOMS+1];
-coord doors[DOORMAX];
-int doorindex;
-struct rm zerorm;
-int comp();
-schar nxcor;
-boolean goldseen;
-int nroom;
-xchar xdnstair,xupstair,ydnstair,yupstair;
-
-/* Definitions used by makerooms() and addrs() */
-#define MAXRS 50 /* max lth of temp rectangle table - arbitrary */
-struct rectangle {
- xchar rlx,rly,rhx,rhy;
-} rs[MAXRS+1];
-int rscnt,rsmax; /* 0..rscnt-1: currently under consideration */
- /* rscnt..rsmax: discarded */
-
-makelevel()
-{
- register struct mkroom *croom, *troom;
- register unsigned tryct;
- register x,y;
-
- nroom = 0;
- doorindex = 0;
- rooms[0].hx = -1; /* in case we are in a maze */
-
- for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
- levl[x][y] = zerorm;
-
- oinit(); /* assign level dependent obj probabilities */
-
- if(dlevel >= rn1(3, 26)) { /* there might be several mazes */
- makemaz();
- return;
- }
-
- /* construct the rooms */
- nroom = 0;
- secret = FALSE;
- (void) makerooms();
-
- /* construct stairs (up and down in different rooms if possible) */
- croom = &rooms[rn2(nroom)];
- xdnstair = somex();
- ydnstair = somey();
- levl[xdnstair][ydnstair].scrsym ='>';
- levl[xdnstair][ydnstair].typ = STAIRS;
- if(nroom > 1) {
- troom = croom;
- croom = &rooms[rn2(nroom-1)];
- if(croom >= troom) croom++;
- }
- xupstair = somex(); /* %% < and > might be in the same place */
- yupstair = somey();
- levl[xupstair][yupstair].scrsym ='<';
- levl[xupstair][yupstair].typ = STAIRS;
-
- /* for each room: put things inside */
- for(croom = rooms; croom->hx > 0; croom++) {
-
- /* put a sleeping monster inside */
- /* Note: monster may be on the stairs. This cannot be
- avoided: maybe the player fell through a trapdoor
- while a monster was on the stairs. Conclusion:
- we have to check for monsters on the stairs anyway. */
- if(!rn2(3)) (void)
- makemon((struct permonst *) 0, somex(), somey());
-
- /* put traps and mimics inside */
- goldseen = FALSE;
- while(!rn2(8-(dlevel/6))) mktrap(0,0,croom);
- if(!goldseen && !rn2(3)) mkgold(0L,somex(),somey());
- if(!rn2(3)) {
- (void) mkobj_at(0, somex(), somey());
- tryct = 0;
- while(!rn2(5)) {
- if(++tryct > 100){
- printf("tryct overflow4\n");
- break;
- }
- (void) mkobj_at(0, somex(), somey());
- }
- }
- }
-
- qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
- makecorridors();
- make_niches();
-
- /* make a secret treasure vault, not connected to the rest */
- if(nroom <= (2*MAXNROFROOMS/3)) if(rn2(3)) {
- troom = &rooms[nroom];
- secret = TRUE;
- if(makerooms()) {
- troom->rtype = VAULT; /* treasure vault */
- for(x = troom->lx; x <= troom->hx; x++)
- for(y = troom->ly; y <= troom->hy; y++)
- mkgold((long)(rnd(dlevel*100) + 50), x, y);
- if(!rn2(3))
- makevtele();
- }
- }
-
-#ifndef QUEST
-#ifdef WIZARD
- if(wizard && getenv("SHOPTYPE")) mkshop(); else
-#endif WIZARD
- if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3) mkshop();
- else
- if(dlevel > 6 && !rn2(7)) mkzoo(ZOO);
- else
- if(dlevel > 9 && !rn2(5)) mkzoo(BEEHIVE);
- else
- if(dlevel > 11 && !rn2(6)) mkzoo(MORGUE);
- else
- if(dlevel > 18 && !rn2(6)) mkswamp();
-#endif QUEST
-}
-
-makerooms() {
-register struct rectangle *rsp;
-register int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy;
-int tryct = 0, xlim, ylim;
-
- /* init */
- xlim = XLIM + secret;
- ylim = YLIM + secret;
- if(nroom == 0) {
- rsp = rs;
- rsp->rlx = rsp->rly = 0;
- rsp->rhx = COLNO-1;
- rsp->rhy = ROWNO-1;
- rsmax = 1;
- }
- rscnt = rsmax;
-
- /* make rooms until satisfied */
- while(rscnt > 0 && nroom < MAXNROFROOMS-1) {
- if(!secret && nroom > (MAXNROFROOMS/3) &&
- !rn2((MAXNROFROOMS-nroom)*(MAXNROFROOMS-nroom)))
- return(0);
-
- /* pick a rectangle */
- rsp = &rs[rn2(rscnt)];
- hx = rsp->rhx;
- hy = rsp->rhy;
- lx = rsp->rlx;
- ly = rsp->rly;
-
- /* find size of room */
- if(secret)
- dx = dy = 1;
- else {
- dx = 2 + rn2((hx-lx-8 > 20) ? 12 : 8);
- dy = 2 + rn2(4);
- if(dx*dy > 50)
- dy = 50/dx;
- }
-
- /* look whether our room will fit */
- if(hx-lx < dx + dx/2 + 2*xlim || hy-ly < dy + dy/3 + 2*ylim) {
- /* no, too small */
- /* maybe we throw this area out */
- if(secret || !rn2(MAXNROFROOMS+1-nroom-tryct)) {
- rscnt--;
- rs[rsmax] = *rsp;
- *rsp = rs[rscnt];
- rs[rscnt] = rs[rsmax];
- tryct = 0;
- } else
- tryct++;
- continue;
- }
-
- lowx = lx + xlim + rn2(hx - lx - dx - 2*xlim + 1);
- lowy = ly + ylim + rn2(hy - ly - dy - 2*ylim + 1);
- hix = lowx + dx;
- hiy = lowy + dy;
-
- if(maker(lowx, dx, lowy, dy)) {
- if(secret)
- return(1);
- addrs(lowx-1, lowy-1, hix+1, hiy+1);
- tryct = 0;
- } else
- if(tryct++ > 100)
- break;
- }
- return(0); /* failed to make vault - very strange */
-}
-
-addrs(lowx,lowy,hix,hiy)
-register int lowx,lowy,hix,hiy;
-{
- register struct rectangle *rsp;
- register int lx,ly,hx,hy,xlim,ylim;
- boolean discarded;
-
- xlim = XLIM + secret;
- ylim = YLIM + secret;
-
- /* walk down since rscnt and rsmax change */
- for(rsp = &rs[rsmax-1]; rsp >= rs; rsp--) {
-
- if((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy ||
- (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy)
- continue;
- if((discarded = (rsp >= &rs[rscnt]))) {
- *rsp = rs[--rsmax];
- } else {
- rsmax--;
- rscnt--;
- *rsp = rs[rscnt];
- if(rscnt != rsmax)
- rs[rscnt] = rs[rsmax];
- }
- if(lowy - ly > 2*ylim + 4)
- addrsx(lx,ly,hx,lowy-2,discarded);
- if(lowx - lx > 2*xlim + 4)
- addrsx(lx,ly,lowx-2,hy,discarded);
- if(hy - hiy > 2*ylim + 4)
- addrsx(lx,hiy+2,hx,hy,discarded);
- if(hx - hix > 2*xlim + 4)
- addrsx(hix+2,ly,hx,hy,discarded);
- }
-}
-
-addrsx(lx,ly,hx,hy,discarded)
-register int lx,ly,hx,hy;
-boolean discarded; /* piece of a discarded area */
-{
- register struct rectangle *rsp;
-
- /* check inclusions */
- for(rsp = rs; rsp < &rs[rsmax]; rsp++) {
- if(lx >= rsp->rlx && hx <= rsp->rhx &&
- ly >= rsp->rly && hy <= rsp->rhy)
- return;
- }
-
- /* make a new entry */
- if(rsmax >= MAXRS) {
-#ifdef WIZARD
- if(wizard) pline("MAXRS may be too small.");
-#endif WIZARD
- return;
- }
- rsmax++;
- if(!discarded) {
- *rsp = rs[rscnt];
- rsp = &rs[rscnt];
- rscnt++;
- }
- rsp->rlx = lx;
- rsp->rly = ly;
- rsp->rhx = hx;
- rsp->rhy = hy;
-}
-
-comp(x,y)
-register struct mkroom *x,*y;
-{
- if(x->lx < y->lx) return(-1);
- return(x->lx > y->lx);
-}
-
-coord
-finddpos(xl,yl,xh,yh) {
- coord ff;
- register x,y;
-
- x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
- y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
- if(okdoor(x, y))
- goto gotit;
-
- for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
- if(okdoor(x, y))
- goto gotit;
-
- for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
- if(levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR)
- goto gotit;
- /* cannot find something reasonable -- strange */
- x = xl;
- y = yh;
-gotit:
- ff.x = x;
- ff.y = y;
- return(ff);
-}
-
-/* see whether it is allowable to create a door at [x,y] */
-okdoor(x,y)
-register x,y;
-{
- if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
- levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
- levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
- levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
- (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
- doorindex >= DOORMAX)
- return(0);
- return(1);
-}
-
-dodoor(x,y,aroom)
-register x,y;
-register struct mkroom *aroom;
-{
- if(doorindex >= DOORMAX) {
- impossible("DOORMAX exceeded?");
- return;
- }
- if(!okdoor(x,y) && nxcor)
- return;
- dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
-}
-
-dosdoor(x,y,aroom,type)
-register x,y;
-register struct mkroom *aroom;
-register type;
-{
- register struct mkroom *broom;
- register tmp;
-
- if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs with '+' as scrsym */
- type = DOOR;
- levl[x][y].typ = type;
- if(type == DOOR)
- levl[x][y].scrsym = '+';
- aroom->doorct++;
- broom = aroom+1;
- if(broom->hx < 0) tmp = doorindex; else
- for(tmp = doorindex; tmp > broom->fdoor; tmp--)
- doors[tmp] = doors[tmp-1];
- doorindex++;
- doors[tmp].x = x;
- doors[tmp].y = y;
- for( ; broom->hx >= 0; broom++) broom->fdoor++;
-}
-
-/* Only called from makerooms() */
-maker(lowx,ddx,lowy,ddy)
-schar lowx,ddx,lowy,ddy;
-{
- register struct mkroom *croom;
- register x, y, hix = lowx+ddx, hiy = lowy+ddy;
- register xlim = XLIM + secret, ylim = YLIM + secret;
-
- if(nroom >= MAXNROFROOMS) return(0);
- if(lowx < XLIM) lowx = XLIM;
- if(lowy < YLIM) lowy = YLIM;
- if(hix > COLNO-XLIM-1) hix = COLNO-XLIM-1;
- if(hiy > ROWNO-YLIM-1) hiy = ROWNO-YLIM-1;
-chk:
- if(hix <= lowx || hiy <= lowy) return(0);
-
- /* check area around room (and make room smaller if necessary) */
- for(x = lowx - xlim; x <= hix + xlim; x++) {
- for(y = lowy - ylim; y <= hiy + ylim; y++) {
- if(levl[x][y].typ) {
-#ifdef WIZARD
- if(wizard && !secret)
- pline("Strange area [%d,%d] in maker().",x,y);
-#endif WIZARD
- if(!rn2(3)) return(0);
- if(x < lowx)
- lowx = x+xlim+1;
- else
- hix = x-xlim-1;
- if(y < lowy)
- lowy = y+ylim+1;
- else
- hiy = y-ylim-1;
- goto chk;
- }
- }
- }
-
- croom = &rooms[nroom];
-
- /* on low levels the room is lit (usually) */
- /* secret vaults are always lit */
- if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) {
- for(x = lowx-1; x <= hix+1; x++)
- for(y = lowy-1; y <= hiy+1; y++)
- levl[x][y].lit = 1;
- croom->rlit = 1;
- } else
- croom->rlit = 0;
- croom->lx = lowx;
- croom->hx = hix;
- croom->ly = lowy;
- croom->hy = hiy;
- croom->rtype = croom->doorct = croom->fdoor = 0;
-
- for(x = lowx-1; x <= hix+1; x++)
- for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
- levl[x][y].scrsym = '-';
- levl[x][y].typ = HWALL;
- }
- for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
- for(y = lowy; y <= hiy; y++) {
- levl[x][y].scrsym = '|';
- levl[x][y].typ = VWALL;
- }
- for(x = lowx; x <= hix; x++)
- for(y = lowy; y <= hiy; y++) {
- levl[x][y].scrsym = '.';
- levl[x][y].typ = ROOM;
- }
-
- smeq[nroom] = nroom;
- croom++;
- croom->hx = -1;
- nroom++;
- return(1);
-}
-
-makecorridors() {
- register a,b;
-
- nxcor = 0;
- for(a = 0; a < nroom-1; a++)
- join(a, a+1);
- for(a = 0; a < nroom-2; a++)
- if(smeq[a] != smeq[a+2])
- join(a, a+2);
- for(a = 0; a < nroom; a++)
- for(b = 0; b < nroom; b++)
- if(smeq[a] != smeq[b])
- join(a, b);
- if(nroom > 2)
- for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
- a = rn2(nroom);
- b = rn2(nroom-2);
- if(b >= a) b += 2;
- join(a, b);
- }
-}
-
-join(a,b)
-register a,b;
-{
- coord cc,tt;
- register tx, ty, xx, yy;
- register struct rm *crm;
- register struct mkroom *croom, *troom;
- register dx, dy, dix, diy, cct;
-
- croom = &rooms[a];
- troom = &rooms[b];
-
- /* find positions cc and tt for doors in croom and troom
- and direction for a corridor between them */
-
- if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
- if(troom->lx > croom->hx) {
- dx = 1;
- dy = 0;
- xx = croom->hx+1;
- tx = troom->lx-1;
- cc = finddpos(xx,croom->ly,xx,croom->hy);
- tt = finddpos(tx,troom->ly,tx,troom->hy);
- } else if(troom->hy < croom->ly) {
- dy = -1;
- dx = 0;
- yy = croom->ly-1;
- cc = finddpos(croom->lx,yy,croom->hx,yy);
- ty = troom->hy+1;
- tt = finddpos(troom->lx,ty,troom->hx,ty);
- } else if(troom->hx < croom->lx) {
- dx = -1;
- dy = 0;
- xx = croom->lx-1;
- tx = troom->hx+1;
- cc = finddpos(xx,croom->ly,xx,croom->hy);
- tt = finddpos(tx,troom->ly,tx,troom->hy);
- } else {
- dy = 1;
- dx = 0;
- yy = croom->hy+1;
- ty = troom->ly-1;
- cc = finddpos(croom->lx,yy,croom->hx,yy);
- tt = finddpos(troom->lx,ty,troom->hx,ty);
- }
- xx = cc.x;
- yy = cc.y;
- tx = tt.x - dx;
- ty = tt.y - dy;
- if(nxcor && levl[xx+dx][yy+dy].typ)
- return;
- dodoor(xx,yy,croom);
-
- cct = 0;
- while(xx != tx || yy != ty) {
- xx += dx;
- yy += dy;
-
- /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
- if(cct++ > 500 || (nxcor && !rn2(35)))
- return;
-
- if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1)
- return; /* impossible */
-
- crm = &levl[xx][yy];
- if(!(crm->typ)) {
- if(rn2(100)) {
- crm->typ = CORR;
- crm->scrsym = CORR_SYM;
- if(nxcor && !rn2(50))
- (void) mkobj_at(ROCK_SYM, xx, yy);
- } else {
- crm->typ = SCORR;
- crm->scrsym = ' ';
- }
- } else
- if(crm->typ != CORR && crm->typ != SCORR) {
- /* strange ... */
- return;
- }
-
- /* find next corridor position */
- dix = abs(xx-tx);
- diy = abs(yy-ty);
-
- /* do we have to change direction ? */
- if(dy && dix > diy) {
- register ddx = (xx > tx) ? -1 : 1;
-
- crm = &levl[xx+ddx][yy];
- if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
- dx = ddx;
- dy = 0;
- continue;
- }
- } else if(dx && diy > dix) {
- register ddy = (yy > ty) ? -1 : 1;
-
- crm = &levl[xx][yy+ddy];
- if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
- dy = ddy;
- dx = 0;
- continue;
- }
- }
-
- /* continue straight on? */
- crm = &levl[xx+dx][yy+dy];
- if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
- continue;
-
- /* no, what must we do now?? */
- if(dx) {
- dx = 0;
- dy = (ty < yy) ? -1 : 1;
- crm = &levl[xx+dx][yy+dy];
- if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
- continue;
- dy = -dy;
- continue;
- } else {
- dy = 0;
- dx = (tx < xx) ? -1 : 1;
- crm = &levl[xx+dx][yy+dy];
- if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
- continue;
- dx = -dx;
- continue;
- }
- }
-
- /* we succeeded in digging the corridor */
- dodoor(tt.x, tt.y, troom);
-
- if(smeq[a] < smeq[b])
- smeq[b] = smeq[a];
- else
- smeq[a] = smeq[b];
-}
-
-make_niches()
-{
- register int ct = rnd(nroom/2 + 1);
- while(ct--) makeniche(FALSE);
-}
-
-makevtele()
-{
- makeniche(TRUE);
-}
-
-makeniche(with_trap)
-boolean with_trap;
-{
- register struct mkroom *aroom;
- register struct rm *rm;
- register int vct = 8;
- coord dd;
- register dy,xx,yy;
- register struct trap *ttmp;
-
- if(doorindex < DOORMAX)
- while(vct--) {
- aroom = &rooms[rn2(nroom-1)];
- if(aroom->rtype != 0) continue; /* not an ordinary room */
- if(aroom->doorct == 1 && rn2(5)) continue;
- if(rn2(2)) {
- dy = 1;
- dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1);
- } else {
- dy = -1;
- dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1);
- }
- xx = dd.x;
- yy = dd.y;
- if((rm = &levl[xx][yy+dy])->typ) continue;
- if(with_trap || !rn2(4)) {
- rm->typ = SCORR;
- rm->scrsym = ' ';
- if(with_trap) {
- ttmp = maketrap(xx, yy+dy, TELEP_TRAP);
- ttmp->once = 1;
- make_engr_at(xx, yy-dy, "ad ae?ar um");
- }
- dosdoor(xx, yy, aroom, SDOOR);
- } else {
- rm->typ = CORR;
- rm->scrsym = CORR_SYM;
- if(rn2(7))
- dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
- else {
- mksobj_at(SCR_TELEPORTATION, xx, yy+dy);
- if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy);
- }
- }
- return;
- }
-}
-
-/* make a trap somewhere (in croom if mazeflag = 0) */
-mktrap(num,mazeflag,croom)
-register num,mazeflag;
-register struct mkroom *croom;
-{
- register struct trap *ttmp;
- register int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0;
- register xchar mx,my;
- extern char fut_geno[];
-
- if(!num || num >= TRAPNUM) {
- nopierc = (dlevel < 4) ? 1 : 0;
- nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
- if(index(fut_geno, 'M')) nomimic = 1;
- kind = rn2(TRAPNUM - nopierc - nomimic);
- /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
- } else kind = num;
-
- if(kind == MIMIC) {
- register struct monst *mtmp;
-
- fakedoor = (!rn2(3) && !mazeflag);
- fakegold = (!fakedoor && !rn2(2));
- if(fakegold) goldseen = TRUE;
- do {
- if(++tryct > 200) return;
- if(fakedoor) {
- /* note: fakedoor maybe on actual door */
- if(rn2(2)){
- if(rn2(2))
- mx = croom->hx+1;
- else mx = croom->lx-1;
- my = somey();
- } else {
- if(rn2(2))
- my = croom->hy+1;
- else my = croom->ly-1;
- mx = somex();
- }
- } else if(mazeflag) {
- extern coord mazexy();
- coord mm;
- mm = mazexy();
- mx = mm.x;
- my = mm.y;
- } else {
- mx = somex();
- my = somey();
- }
- } while(m_at(mx,my) || levl[mx][my].typ == STAIRS);
- if(mtmp = makemon(PM_MIMIC,mx,my)) {
- mtmp->mimic = 1;
- mtmp->mappearance =
- fakegold ? '$' : fakedoor ? '+' :
- (mazeflag && rn2(2)) ? AMULET_SYM :
- "=/)%?![<>" [ rn2(9) ];
- }
- return;
- }
-
- do {
- if(++tryct > 200)
- return;
- if(mazeflag){
- extern coord mazexy();
- coord mm;
- mm = mazexy();
- mx = mm.x;
- my = mm.y;
- } else {
- mx = somex();
- my = somey();
- }
- } while(t_at(mx, my) || levl[mx][my].typ == STAIRS);
- ttmp = maketrap(mx, my, kind);
- if(mazeflag && !rn2(10) && ttmp->ttyp < PIERC)
- ttmp->tseen = 1;
-}
diff --git a/games/hack/hack.mkmaze.c b/games/hack/hack.mkmaze.c
deleted file mode 100644
index bee24f954c30..000000000000
--- a/games/hack/hack.mkmaze.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mkmaze.c - version 1.0.2 */
-
-#include "hack.h"
-#include "def.mkroom.h" /* not really used */
-extern struct monst *makemon();
-extern struct permonst pm_wizard;
-extern struct obj *mkobj_at();
-extern coord mazexy();
-struct permonst hell_hound =
- { "hell hound", 'd', 12, 14, 2, 3, 6, 0 };
-
-makemaz()
-{
- int x,y;
- register zx,zy;
- coord mm;
- boolean al = (dlevel >= 30 && !flags.made_amulet);
-
- for(x = 2; x < COLNO-1; x++)
- for(y = 2; y < ROWNO-1; y++)
- levl[x][y].typ = (x%2 && y%2) ? 0 : HWALL;
- if(al) {
- register struct monst *mtmp;
-
- zx = 2*(COLNO/4) - 1;
- zy = 2*(ROWNO/4) - 1;
- for(x = zx-2; x < zx+4; x++) for(y = zy-2; y <= zy+2; y++) {
- levl[x][y].typ =
- (y == zy-2 || y == zy+2 || x == zx-2 || x == zx+3) ? POOL :
- (y == zy-1 || y == zy+1 || x == zx-1 || x == zx+2) ? HWALL:
- ROOM;
- }
- (void) mkobj_at(AMULET_SYM, zx, zy);
- flags.made_amulet = 1;
- walkfrom(zx+4, zy);
- if(mtmp = makemon(&hell_hound, zx, zy))
- mtmp->msleep = 1;
- if(mtmp = makemon(PM_WIZARD, zx+1, zy)) {
- mtmp->msleep = 1;
- flags.no_of_wizards = 1;
- }
- } else {
- mm = mazexy();
- zx = mm.x;
- zy = mm.y;
- walkfrom(zx,zy);
- (void) mksobj_at(WAN_WISHING, zx, zy);
- (void) mkobj_at(ROCK_SYM, zx, zy); /* put a rock on top of it */
- }
-
- for(x = 2; x < COLNO-1; x++)
- for(y = 2; y < ROWNO-1; y++) {
- switch(levl[x][y].typ) {
- case HWALL:
- levl[x][y].scrsym = '-';
- break;
- case ROOM:
- levl[x][y].scrsym = '.';
- break;
- }
- }
- for(x = rn1(8,11); x; x--) {
- mm = mazexy();
- (void) mkobj_at(rn2(2) ? GEM_SYM : 0, mm.x, mm.y);
- }
- for(x = rn1(10,2); x; x--) {
- mm = mazexy();
- (void) mkobj_at(ROCK_SYM, mm.x, mm.y);
- }
- mm = mazexy();
- (void) makemon(PM_MINOTAUR, mm.x, mm.y);
- for(x = rn1(5,7); x; x--) {
- mm = mazexy();
- (void) makemon((struct permonst *) 0, mm.x, mm.y);
- }
- for(x = rn1(6,7); x; x--) {
- mm = mazexy();
- mkgold(0L,mm.x,mm.y);
- }
- for(x = rn1(6,7); x; x--)
- mktrap(0,1,(struct mkroom *) 0);
- mm = mazexy();
- levl[(xupstair = mm.x)][(yupstair = mm.y)].scrsym = '<';
- levl[xupstair][yupstair].typ = STAIRS;
- xdnstair = ydnstair = 0;
-}
-
-walkfrom(x,y) int x,y; {
-register int q,a,dir;
-int dirs[4];
- levl[x][y].typ = ROOM;
- while(1) {
- q = 0;
- for(a = 0; a < 4; a++)
- if(okay(x,y,a)) dirs[q++]= a;
- if(!q) return;
- dir = dirs[rn2(q)];
- move(&x,&y,dir);
- levl[x][y].typ = ROOM;
- move(&x,&y,dir);
- walkfrom(x,y);
- }
-}
-
-move(x,y,dir)
-register int *x, *y;
-register int dir;
-{
- switch(dir){
- case 0: --(*y); break;
- case 1: (*x)++; break;
- case 2: (*y)++; break;
- case 3: --(*x); break;
- }
-}
-
-okay(x,y,dir)
-int x,y;
-register int dir;
-{
- move(&x,&y,dir);
- move(&x,&y,dir);
- if(x<3 || y<3 || x>COLNO-3 || y>ROWNO-3 || levl[x][y].typ != 0)
- return(0);
- else
- return(1);
-}
-
-coord
-mazexy(){
- coord mm;
- mm.x = 3 + 2*rn2(COLNO/2 - 2);
- mm.y = 3 + 2*rn2(ROWNO/2 - 2);
- return mm;
-}
diff --git a/games/hack/hack.mkobj.c b/games/hack/hack.mkobj.c
deleted file mode 100644
index 18a69146d045..000000000000
--- a/games/hack/hack.mkobj.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mkobj.c - version 1.0.3 */
-
-#include "hack.h"
-
-char mkobjstr[] = "))[[!!!!????%%%%/=**))[[!!!!????%%%%/=**(%";
-struct obj *mkobj(), *mksobj();
-
-struct obj *
-mkobj_at(let,x,y)
-register let,x,y;
-{
- register struct obj *otmp = mkobj(let);
- otmp->ox = x;
- otmp->oy = y;
- otmp->nobj = fobj;
- fobj = otmp;
- return(otmp);
-}
-
-mksobj_at(otyp,x,y)
-register otyp,x,y;
-{
- register struct obj *otmp = mksobj(otyp);
- otmp->ox = x;
- otmp->oy = y;
- otmp->nobj = fobj;
- fobj = otmp;
-}
-
-struct obj *
-mkobj(let) {
- if(!let)
- let = mkobjstr[rn2(sizeof(mkobjstr) - 1)];
- return(
- mksobj(
- letter(let) ?
- CORPSE + ((let > 'Z') ? (let-'a'+'Z'-'@'+1) : (let-'@'))
- : probtype(let)
- )
- );
-}
-
-
-struct obj zeroobj;
-
-struct obj *
-mksobj(otyp)
-register otyp;
-{
- register struct obj *otmp;
- char let = objects[otyp].oc_olet;
-
- otmp = newobj(0);
- *otmp = zeroobj;
- otmp->age = moves;
- otmp->o_id = flags.ident++;
- otmp->quan = 1;
- otmp->olet = let;
- otmp->otyp = otyp;
- otmp->dknown = index("/=!?*", let) ? 0 : 1;
- switch(let) {
- case WEAPON_SYM:
- otmp->quan = (otmp->otyp <= ROCK) ? rn1(6,6) : 1;
- if(!rn2(11)) otmp->spe = rnd(3);
- else if(!rn2(10)) {
- otmp->cursed = 1;
- otmp->spe = -rnd(3);
- }
- break;
- case FOOD_SYM:
- if(otmp->otyp >= CORPSE) break;
-#ifdef NOT_YET_IMPLEMENTED
- /* if tins are to be identified, need to adapt doname() etc */
- if(otmp->otyp == TIN)
- otmp->spe = rnd(...);
-#endif NOT_YET_IMPLEMENTED
- /* fall into next case */
- case GEM_SYM:
- otmp->quan = rn2(6) ? 1 : 2;
- case TOOL_SYM:
- case CHAIN_SYM:
- case BALL_SYM:
- case ROCK_SYM:
- case POTION_SYM:
- case SCROLL_SYM:
- case AMULET_SYM:
- break;
- case ARMOR_SYM:
- if(!rn2(8)) otmp->cursed = 1;
- if(!rn2(10)) otmp->spe = rnd(3);
- else if(!rn2(9)) {
- otmp->spe = -rnd(3);
- otmp->cursed = 1;
- }
- break;
- case WAND_SYM:
- if(otmp->otyp == WAN_WISHING) otmp->spe = 3; else
- otmp->spe = rn1(5,
- (objects[otmp->otyp].bits & NODIR) ? 11 : 4);
- break;
- case RING_SYM:
- if(objects[otmp->otyp].bits & SPEC) {
- if(!rn2(3)) {
- otmp->cursed = 1;
- otmp->spe = -rnd(2);
- } else otmp->spe = rnd(2);
- } else if(otmp->otyp == RIN_TELEPORTATION ||
- otmp->otyp == RIN_AGGRAVATE_MONSTER ||
- otmp->otyp == RIN_HUNGER || !rn2(9))
- otmp->cursed = 1;
- break;
- default:
- panic("impossible mkobj");
- }
- otmp->owt = weight(otmp);
- return(otmp);
-}
-
-letter(c) {
- return(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'));
-}
-
-weight(obj)
-register struct obj *obj;
-{
-register int wt = objects[obj->otyp].oc_weight;
- return(wt ? wt*obj->quan : (obj->quan + 1)/2);
-}
-
-mkgold(num,x,y)
-register long num;
-{
- register struct gold *gold;
- register long amount = (num ? num : 1 + (rnd(dlevel+2) * rnd(30)));
-
- if(gold = g_at(x,y))
- gold->amount += amount;
- else {
- gold = newgold();
- gold->ngold = fgold;
- gold->gx = x;
- gold->gy = y;
- gold->amount = amount;
- fgold = gold;
- /* do sth with display? */
- }
-}
diff --git a/games/hack/hack.mkshop.c b/games/hack/hack.mkshop.c
deleted file mode 100644
index 7a8fdfbfaaa6..000000000000
--- a/games/hack/hack.mkshop.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mkshop.c - version 1.0.3 */
-
-#ifndef QUEST
-#include "hack.h"
-#include "def.mkroom.h"
-#include "def.eshk.h"
-#define ESHK ((struct eshk *)(&(shk->mextra[0])))
-extern struct monst *makemon();
-extern struct obj *mkobj_at();
-extern int nroom;
-extern char shtypes[]; /* = "=/)%?!["; 8 types: 7 specialized, 1 mixed */
-schar shprobs[] = { 3,3,5,5,10,10,14,50 }; /* their probabilities */
-
-mkshop(){
-register struct mkroom *sroom;
-register int sh,sx,sy,i = -1;
-register char let;
-int roomno;
-register struct monst *shk;
-#ifdef WIZARD
-extern char *getenv();
-register char *ep = getenv("SHOPTYPE");
- /* first determine shoptype */
- if(wizard){
- if(ep){
- if(*ep == 'z' || *ep == 'Z'){
- mkzoo(ZOO);
- return;
- }
- if(*ep == 'm' || *ep == 'M'){
- mkzoo(MORGUE);
- return;
- }
- if(*ep == 'b' || *ep == 'B'){
- mkzoo(BEEHIVE);
- return;
- }
- if(*ep == 's' || *ep == 'S'){
- mkswamp();
- return;
- }
- for(i=0; shtypes[i]; i++)
- if(*ep == shtypes[i]) break;
- goto gottype;
- }
- }
-gottype:
-#endif WIZARD
- for(sroom = &rooms[0], roomno = 0; ; sroom++, roomno++){
- if(sroom->hx < 0) return;
- if(sroom - rooms >= nroom) {
- pline("rooms not closed by -1?");
- return;
- }
- if(sroom->rtype) continue;
- if(!sroom->rlit || has_dnstairs(sroom) || has_upstairs(sroom))
- continue;
- if(
-#ifdef WIZARD
- (wizard && ep != NULL && sroom->doorct != 0) ||
-#endif WIZARD
- sroom->doorct <= 2 && sroom->doorct > 0) break;
- }
-
- if(i < 0) { /* shoptype not yet determined */
- register int j;
-
- for(j = rn2(100), i = 0; (j -= shprobs[i])>= 0; i++)
- if(!shtypes[i]) break; /* superfluous */
- if(isbig(sroom) && i + SHOPBASE == WANDSHOP)
- i = GENERAL-SHOPBASE;
- }
- sroom->rtype = i + SHOPBASE;
- let = shtypes[i];
- sh = sroom->fdoor;
- sx = doors[sh].x;
- sy = doors[sh].y;
- if(sx == sroom->lx-1) sx++; else
- if(sx == sroom->hx+1) sx--; else
- if(sy == sroom->ly-1) sy++; else
- if(sy == sroom->hy+1) sy--; else {
-#ifdef WIZARD
- /* This is said to happen sometimes, but I've never seen it. */
- if(wizard) {
- register int j = sroom->doorct;
- extern int doorindex;
-
- pline("Where is shopdoor?");
- pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly,
- sroom->hx, sroom->hy);
- pline("doormax=%d doorct=%d fdoor=%d",
- doorindex, sroom->doorct, sh);
- while(j--) {
- pline("door [%d,%d]", doors[sh].x, doors[sh].y);
- sh++;
- }
- more();
- }
-#endif WIZARD
- return;
- }
- if(!(shk = makemon(PM_SHK,sx,sy))) return;
- shk->isshk = shk->mpeaceful = 1;
- shk->msleep = 0;
- shk->mtrapseen = ~0; /* we know all the traps already */
- ESHK->shoproom = roomno;
- ESHK->shoplevel = dlevel;
- ESHK->shd = doors[sh];
- ESHK->shk.x = sx;
- ESHK->shk.y = sy;
- ESHK->robbed = 0;
- ESHK->visitct = 0;
- ESHK->following = 0;
- shk->mgold = 1000 + 30*rnd(100); /* initial capital */
- ESHK->billct = 0;
- findname(ESHK->shknam, let);
- for(sx = sroom->lx; sx <= sroom->hx; sx++)
- for(sy = sroom->ly; sy <= sroom->hy; sy++){
- register struct monst *mtmp;
- if((sx == sroom->lx && doors[sh].x == sx-1) ||
- (sx == sroom->hx && doors[sh].x == sx+1) ||
- (sy == sroom->ly && doors[sh].y == sy-1) ||
- (sy == sroom->hy && doors[sh].y == sy+1)) continue;
- if(rn2(100) < dlevel && !m_at(sx,sy) &&
- (mtmp = makemon(PM_MIMIC, sx, sy))){
- mtmp->mimic = 1;
- mtmp->mappearance =
- (let && rn2(10) < dlevel) ? let : ']';
- continue;
- }
- (void) mkobj_at(let, sx, sy);
- }
-}
-
-mkzoo(type)
-int type;
-{
- register struct mkroom *sroom;
- register struct monst *mon;
- register int sh,sx,sy,i;
- int goldlim = 500 * dlevel;
- int moct = 0;
- struct permonst *morguemon();
-
- i = nroom;
- for(sroom = &rooms[rn2(nroom)]; ; sroom++) {
- if(sroom == &rooms[nroom])
- sroom = &rooms[0];
- if(!i-- || sroom->hx < 0)
- return;
- if(sroom->rtype)
- continue;
- if(type == MORGUE && sroom->rlit)
- continue;
- if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
- continue;
- if(sroom->doorct == 1 || !rn2(5))
- break;
- }
- sroom->rtype = type;
- sh = sroom->fdoor;
- for(sx = sroom->lx; sx <= sroom->hx; sx++)
- for(sy = sroom->ly; sy <= sroom->hy; sy++){
- if((sx == sroom->lx && doors[sh].x == sx-1) ||
- (sx == sroom->hx && doors[sh].x == sx+1) ||
- (sy == sroom->ly && doors[sh].y == sy-1) ||
- (sy == sroom->hy && doors[sh].y == sy+1)) continue;
- mon = makemon(
- (type == MORGUE) ? morguemon() :
- (type == BEEHIVE) ? PM_KILLER_BEE : (struct permonst *) 0,
- sx, sy);
- if(mon) mon->msleep = 1;
- switch(type) {
- case ZOO:
- i = sq(dist2(sx,sy,doors[sh].x,doors[sh].y));
- if(i >= goldlim) i = 5*dlevel;
- goldlim -= i;
- mkgold((long)(10 + rn2(i)), sx, sy);
- break;
- case MORGUE:
- /* Usually there is one dead body in the morgue */
- if(!moct && rn2(3)) {
- mksobj_at(CORPSE, sx, sy);
- moct++;
- }
- break;
- case BEEHIVE:
- if(!rn2(3)) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy);
- break;
- }
- }
-}
-
-struct permonst *
-morguemon()
-{
- extern struct permonst pm_ghost;
- register int i = rn2(100), hd = rn2(dlevel);
-
- if(hd > 10 && i < 10) return(PM_DEMON);
- if(hd > 8 && i > 85) return(PM_VAMPIRE);
- return((i < 40) ? PM_GHOST : (i < 60) ? PM_WRAITH : PM_ZOMBIE);
-}
-
-mkswamp() /* Michiel Huisjes & Fred de Wilde */
-{
- register struct mkroom *sroom;
- register int sx,sy,i,eelct = 0;
- extern struct permonst pm_eel;
-
- for(i=0; i<5; i++) { /* 5 tries */
- sroom = &rooms[rn2(nroom)];
- if(sroom->hx < 0 || sroom->rtype ||
- has_upstairs(sroom) || has_dnstairs(sroom))
- continue;
-
- /* satisfied; make a swamp */
- sroom->rtype = SWAMP;
- for(sx = sroom->lx; sx <= sroom->hx; sx++)
- for(sy = sroom->ly; sy <= sroom->hy; sy++)
- if((sx+sy)%2 && !o_at(sx,sy) && !t_at(sx,sy)
- && !m_at(sx,sy) && !nexttodoor(sx,sy)){
- levl[sx][sy].typ = POOL;
- levl[sx][sy].scrsym = POOL_SYM;
- if(!eelct || !rn2(4)) {
- (void) makemon(PM_EEL, sx, sy);
- eelct++;
- }
- }
- }
-}
-
-nexttodoor(sx,sy)
-register sx,sy;
-{
- register dx,dy;
- register struct rm *lev;
- for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
- if((lev = &levl[sx+dx][sy+dy])->typ == DOOR ||
- lev->typ == SDOOR || lev->typ == LDOOR)
- return(1);
- return(0);
-}
-
-has_dnstairs(sroom)
-register struct mkroom *sroom;
-{
- return(sroom->lx <= xdnstair && xdnstair <= sroom->hx &&
- sroom->ly <= ydnstair && ydnstair <= sroom->hy);
-}
-
-has_upstairs(sroom)
-register struct mkroom *sroom;
-{
- return(sroom->lx <= xupstair && xupstair <= sroom->hx &&
- sroom->ly <= yupstair && yupstair <= sroom->hy);
-}
-
-isbig(sroom)
-register struct mkroom *sroom;
-{
- register int area = (sroom->hx - sroom->lx) * (sroom->hy - sroom->ly);
- return( area > 20 );
-}
-
-dist2(x0,y0,x1,y1){
- return((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1));
-}
-
-sq(a) int a; {
- return(a*a);
-}
-#endif QUEST
diff --git a/games/hack/hack.mon.c b/games/hack/hack.mon.c
deleted file mode 100644
index b31c15922c9a..000000000000
--- a/games/hack/hack.mon.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.mon.c - version 1.0.3 */
-
-#include "hack.h"
-#include "hack.mfndpos.h"
-
-#ifndef NULL
-#define NULL (char *) 0
-#endif
-
-extern struct monst *makemon();
-extern struct obj *mkobj_at();
-
-int warnlevel; /* used by movemon and dochugw */
-long lastwarntime;
-int lastwarnlev;
-char *warnings[] = {
- "white", "pink", "red", "ruby", "purple", "black"
-};
-
-movemon()
-{
- register struct monst *mtmp;
- register int fr;
-
- warnlevel = 0;
-
- while(1) {
- /* find a monster that we haven't treated yet */
- /* note that mtmp or mtmp->nmon might get killed
- while mtmp moves, so we cannot just walk down the
- chain (even new monsters might get created!) */
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->mlstmv < moves) goto next_mon;
- /* treated all monsters */
- break;
-
- next_mon:
- mtmp->mlstmv = moves;
-
- /* most monsters drown in pools */
- { boolean inpool, iseel;
-
- inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
- iseel = (mtmp->data->mlet == ';');
- if(inpool && !iseel) {
- if(cansee(mtmp->mx,mtmp->my))
- pline("%s drowns.", Monnam(mtmp));
- mondead(mtmp);
- continue;
- }
- /* but eels have a difficult time outside */
- if(iseel && !inpool) {
- if(mtmp->mhp > 1) mtmp->mhp--;
- mtmp->mflee = 1;
- mtmp->mfleetim += 2;
- }
- }
- if(mtmp->mblinded && !--mtmp->mblinded)
- mtmp->mcansee = 1;
- if(mtmp->mfleetim && !--mtmp->mfleetim)
- mtmp->mflee = 0;
- if(mtmp->mimic) continue;
- if(mtmp->mspeed != MSLOW || !(moves%2)){
- /* continue if the monster died fighting */
- fr = -1;
- if(Conflict && cansee(mtmp->mx,mtmp->my)
- && (fr = fightm(mtmp)) == 2)
- continue;
- if(fr<0 && dochugw(mtmp))
- continue;
- }
- if(mtmp->mspeed == MFAST && dochugw(mtmp))
- continue;
- }
-
- warnlevel -= u.ulevel;
- if(warnlevel >= SIZE(warnings))
- warnlevel = SIZE(warnings)-1;
- if(warnlevel >= 0)
- if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
- register char *rr;
- switch(Warning & (LEFT_RING | RIGHT_RING)){
- case LEFT_RING:
- rr = "Your left ring glows";
- break;
- case RIGHT_RING:
- rr = "Your right ring glows";
- break;
- case LEFT_RING | RIGHT_RING:
- rr = "Both your rings glow";
- break;
- default:
- rr = "Your fingertips glow";
- break;
- }
- pline("%s %s!", rr, warnings[warnlevel]);
- lastwarntime = moves;
- lastwarnlev = warnlevel;
- }
-
- dmonsfree(); /* remove all dead monsters */
-}
-
-justswld(mtmp,name)
-register struct monst *mtmp;
-char *name;
-{
-
- mtmp->mx = u.ux;
- mtmp->my = u.uy;
- u.ustuck = mtmp;
- pmon(mtmp);
- kludge("%s swallows you!",name);
- more();
- seeoff(1);
- u.uswallow = 1;
- u.uswldtim = 0;
- swallowed();
-}
-
-youswld(mtmp,dam,die,name)
-register struct monst *mtmp;
-register dam,die;
-char *name;
-{
- if(mtmp != u.ustuck) return;
- kludge("%s digests you!",name);
- u.uhp -= dam;
- if(u.uswldtim++ >= die){ /* a3 */
- pline("It totally digests you!");
- u.uhp = -1;
- }
- if(u.uhp < 1) done_in_by(mtmp);
- /* flags.botlx = 1; /* should we show status line ? */
-}
-
-dochugw(mtmp) register struct monst *mtmp; {
-register x = mtmp->mx;
-register y = mtmp->my;
-register d = dochug(mtmp);
-register dd;
- if(!d) /* monster still alive */
- if(Warning)
- if(!mtmp->mpeaceful)
- if(mtmp->data->mlevel > warnlevel)
- if((dd = dist(mtmp->mx,mtmp->my)) < dist(x,y))
- if(dd < 100)
- if(!canseemon(mtmp))
- warnlevel = mtmp->data->mlevel;
- return(d);
-}
-
-/* returns 1 if monster died moving, 0 otherwise */
-dochug(mtmp)
-register struct monst *mtmp;
-{
- register struct permonst *mdat;
- register tmp, nearby, scared;
-
- if(mtmp->cham && !rn2(6))
- (void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
- mdat = mtmp->data;
- if(mdat->mlevel < 0)
- panic("bad monster %c (%d)",mdat->mlet,mdat->mlevel);
-
- /* regenerate monsters */
- if((!(moves%20) || index(MREGEN, mdat->mlet)) &&
- mtmp->mhp < mtmp->mhpmax)
- mtmp->mhp++;
-
- if(mtmp->mfroz) return(0); /* frozen monsters don't do anything */
-
- if(mtmp->msleep) {
- /* wake up, or get out of here. */
- /* ettins are hard to surprise */
- /* Nymphs and Leprechauns do not easily wake up */
- if(cansee(mtmp->mx,mtmp->my) &&
- (!Stealth || (mdat->mlet == 'e' && rn2(10))) &&
- (!index("NL",mdat->mlet) || !rn2(50)) &&
- (Aggravate_monster || index("d1", mdat->mlet)
- || (!rn2(7) && !mtmp->mimic)))
- mtmp->msleep = 0;
- else return(0);
- }
-
- /* not frozen or sleeping: wipe out texts written in the dust */
- wipe_engr_at(mtmp->mx, mtmp->my, 1);
-
- /* confused monsters get unconfused with small probability */
- if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
-
- /* some monsters teleport */
- if(mtmp->mflee && index("tNL", mdat->mlet) && !rn2(40)){
- rloc(mtmp);
- return(0);
- }
- if(mdat->mmove < rnd(6)) return(0);
-
- /* fleeing monsters might regain courage */
- if(mtmp->mflee && !mtmp->mfleetim
- && mtmp->mhp == mtmp->mhpmax && !rn2(25))
- mtmp->mflee = 0;
-
- nearby = (dist(mtmp->mx, mtmp->my) < 3);
- scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) ||
- sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)));
- if(scared && !mtmp->mflee) {
- mtmp->mflee = 1;
- mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
- }
-
- if(!nearby ||
- mtmp->mflee ||
- mtmp->mconf ||
- (mtmp->minvis && !rn2(3)) ||
- (index("BIuy", mdat->mlet) && !rn2(4)) ||
- (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
- (!mtmp->mcansee && !rn2(4)) ||
- mtmp->mpeaceful
- ) {
- tmp = m_move(mtmp,0); /* 2: monster died moving */
- if(tmp == 2 || (tmp && mdat->mmove <= 12))
- return(tmp == 2);
- }
-
- if(!index("Ea", mdat->mlet) && nearby &&
- !mtmp->mpeaceful && u.uhp > 0 && !scared) {
- if(mhitu(mtmp))
- return(1); /* monster died (e.g. 'y' or 'F') */
- }
- /* extra movement for fast monsters */
- if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp,1);
- return(tmp == 2);
-}
-
-m_move(mtmp,after)
-register struct monst *mtmp;
-{
- register struct monst *mtmp2;
- register nx,ny,omx,omy,appr,nearer,cnt,i,j;
- xchar gx,gy,nix,niy,chcnt;
- schar chi;
- boolean likegold, likegems, likeobjs;
- char msym = mtmp->data->mlet;
- schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */
- coord poss[9];
- int info[9];
-
- if(mtmp->mfroz || mtmp->msleep)
- return(0);
- if(mtmp->mtrapped) {
- i = mintrap(mtmp);
- if(i == 2) return(2); /* he died */
- if(i == 1) return(0); /* still in trap, so didnt move */
- }
- if(mtmp->mhide && o_at(mtmp->mx,mtmp->my) && rn2(10))
- return(0); /* do not leave hiding place */
-
-#ifndef NOWORM
- if(mtmp->wormno)
- goto not_special;
-#endif NOWORM
-
- /* my dog gets a special treatment */
- if(mtmp->mtame) {
- return( dog_move(mtmp, after) );
- }
-
- /* likewise for shopkeeper */
- if(mtmp->isshk) {
- mmoved = shk_move(mtmp);
- if(mmoved >= 0)
- goto postmov;
- mmoved = 0; /* follow player outside shop */
- }
-
- /* and for the guard */
- if(mtmp->isgd) {
- mmoved = gd_move();
- goto postmov;
- }
-
-/* teleport if that lies in our nature ('t') or when badly wounded ('1') */
- if((msym == 't' && !rn2(5))
- || (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5))
- || levl[u.ux][u.uy].typ == STAIRS))) {
- if(mtmp->mhp < 7 || (msym == 't' && rn2(2)))
- rloc(mtmp);
- else
- mnexto(mtmp);
- mmoved = 1;
- goto postmov;
- }
-
- /* spit fire ('D') or use a wand ('1') when appropriate */
- if(index("D1", msym))
- inrange(mtmp);
-
- if(msym == 'U' && !mtmp->mcan && canseemon(mtmp) &&
- mtmp->mcansee && rn2(5)) {
- if(!Confusion)
- pline("%s's gaze has confused you!", Monnam(mtmp));
- else
- pline("You are getting more and more confused.");
- if(rn2(3)) mtmp->mcan = 1;
- Confusion += d(3,4); /* timeout */
- }
-not_special:
- if(!mtmp->mflee && u.uswallow && u.ustuck != mtmp) return(1);
- appr = 1;
- if(mtmp->mflee) appr = -1;
- if(mtmp->mconf || Invis || !mtmp->mcansee ||
- (index("BIy", msym) && !rn2(3)))
- appr = 0;
- omx = mtmp->mx;
- omy = mtmp->my;
- gx = u.ux;
- gy = u.uy;
- if(msym == 'L' && appr == 1 && mtmp->mgold > u.ugold)
- appr = -1;
-
- /* random criterion for 'smell' or track finding ability
- should use mtmp->msmell or sth
- */
- if(msym == '@' ||
- ('a' <= msym && msym <= 'z')) {
- extern coord *gettrack();
- register coord *cp;
- schar mroom;
- mroom = inroom(omx,omy);
- if(mroom < 0 || mroom != inroom(u.ux,u.uy)){
- cp = gettrack(omx,omy);
- if(cp){
- gx = cp->x;
- gy = cp->y;
- }
- }
- }
-
- /* look for gold or jewels nearby */
- likegold = (index("LOD", msym) != NULL);
- likegems = (index("ODu", msym) != NULL);
- likeobjs = mtmp->mhide;
-#define SRCHRADIUS 25
- { xchar mind = SRCHRADIUS; /* not too far away */
- register int dd;
- if(likegold){
- register struct gold *gold;
- for(gold = fgold; gold; gold = gold->ngold)
- if((dd = DIST(omx,omy,gold->gx,gold->gy)) < mind){
- mind = dd;
- gx = gold->gx;
- gy = gold->gy;
- }
- }
- if(likegems || likeobjs){
- register struct obj *otmp;
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(likeobjs || otmp->olet == GEM_SYM)
- if(msym != 'u' ||
- objects[otmp->otyp].g_val != 0)
- if((dd = DIST(omx,omy,otmp->ox,otmp->oy)) < mind){
- mind = dd;
- gx = otmp->ox;
- gy = otmp->oy;
- }
- }
- if(mind < SRCHRADIUS && appr == -1) {
- if(dist(omx,omy) < 10) {
- gx = u.ux;
- gy = u.uy;
- } else
- appr = 1;
- }
- }
- nix = omx;
- niy = omy;
- cnt = mfndpos(mtmp,poss,info,
- msym == 'u' ? NOTONL :
- (msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) :
- index(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS);
- /* ALLOW_ROCK for some monsters ? */
- chcnt = 0;
- chi = -1;
- for(i=0; i<cnt; i++) {
- nx = poss[i].x;
- ny = poss[i].y;
- for(j=0; j<MTSZ && j<cnt-1; j++)
- if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
- if(rn2(4*(cnt-j))) goto nxti;
-#ifdef STUPID
- /* some stupid compilers think that this is too complicated */
- { int d1 = DIST(nx,ny,gx,gy);
- int d2 = DIST(nix,niy,gx,gy);
- nearer = (d1 < d2);
- }
-#else
- nearer = (DIST(nx,ny,gx,gy) < DIST(nix,niy,gx,gy));
-#endif STUPID
- if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
- !mmoved ||
- (!appr && !rn2(++chcnt))){
- nix = nx;
- niy = ny;
- chi = i;
- mmoved = 1;
- }
- nxti: ;
- }
- if(mmoved){
- if(info[chi] & ALLOW_M){
- mtmp2 = m_at(nix,niy);
- if(hitmm(mtmp,mtmp2) == 1 && rn2(4) &&
- hitmm(mtmp2,mtmp) == 2) return(2);
- return(0);
- }
- if(info[chi] & ALLOW_U){
- (void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd)+1);
- return(0);
- }
- mtmp->mx = nix;
- mtmp->my = niy;
- for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
- mtmp->mtrack[0].x = omx;
- mtmp->mtrack[0].y = omy;
-#ifndef NOWORM
- if(mtmp->wormno) worm_move(mtmp);
-#endif NOWORM
- } else {
- if(msym == 'u' && rn2(2)){
- rloc(mtmp);
- return(0);
- }
-#ifndef NOWORM
- if(mtmp->wormno) worm_nomove(mtmp);
-#endif NOWORM
- }
-postmov:
- if(mmoved == 1) {
- if(mintrap(mtmp) == 2) /* he died */
- return(2);
- if(likegold) mpickgold(mtmp);
- if(likegems) mpickgems(mtmp);
- if(mtmp->mhide) mtmp->mundetected = 1;
- }
- pmon(mtmp);
- return(mmoved);
-}
-
-mpickgold(mtmp) register struct monst *mtmp; {
-register struct gold *gold;
- while(gold = g_at(mtmp->mx, mtmp->my)){
- mtmp->mgold += gold->amount;
- freegold(gold);
- if(levl[mtmp->mx][mtmp->my].scrsym == '$')
- newsym(mtmp->mx, mtmp->my);
- }
-}
-
-mpickgems(mtmp) register struct monst *mtmp; {
-register struct obj *otmp;
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->olet == GEM_SYM)
- if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
- if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0){
- freeobj(otmp);
- mpickobj(mtmp, otmp);
- if(levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
- newsym(mtmp->mx, mtmp->my); /* %% */
- return; /* pick only one object */
- }
-}
-
-/* return number of acceptable neighbour positions */
-mfndpos(mon,poss,info,flag)
-register struct monst *mon;
-coord poss[9];
-int info[9], flag;
-{
- register int x,y,nx,ny,cnt = 0,ntyp;
- register struct monst *mtmp;
- int nowtyp;
- boolean pool;
-
- x = mon->mx;
- y = mon->my;
- nowtyp = levl[x][y].typ;
-
- pool = (mon->data->mlet == ';');
-nexttry: /* eels prefer the water, but if there is no water nearby,
- they will crawl over land */
- if(mon->mconf) {
- flag |= ALLOW_ALL;
- flag &= ~NOTONL;
- }
- for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
- if(nx != x || ny != y) if(isok(nx,ny))
- if(!IS_ROCK(ntyp = levl[nx][ny].typ))
- if(!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR)))
- if((ntyp == POOL) == pool) {
- info[cnt] = 0;
- if(nx == u.ux && ny == u.uy){
- if(!(flag & ALLOW_U)) continue;
- info[cnt] = ALLOW_U;
- } else if(mtmp = m_at(nx,ny)){
- if(!(flag & ALLOW_M)) continue;
- info[cnt] = ALLOW_M;
- if(mtmp->mtame){
- if(!(flag & ALLOW_TM)) continue;
- info[cnt] |= ALLOW_TM;
- }
- }
- if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
- if(flag & NOGARLIC) continue;
- info[cnt] |= NOGARLIC;
- }
- if(sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
- (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
- if(!(flag & ALLOW_SSM)) continue;
- info[cnt] |= ALLOW_SSM;
- }
- if(sobj_at(ENORMOUS_ROCK, nx, ny)) {
- if(!(flag & ALLOW_ROCK)) continue;
- info[cnt] |= ALLOW_ROCK;
- }
- if(!Invis && online(nx,ny)){
- if(flag & NOTONL) continue;
- info[cnt] |= NOTONL;
- }
- /* we cannot avoid traps of an unknown kind */
- { register struct trap *ttmp = t_at(nx, ny);
- register int tt;
- if(ttmp) {
- tt = 1 << ttmp->ttyp;
- if(mon->mtrapseen & tt){
- if(!(flag & tt)) continue;
- info[cnt] |= tt;
- }
- }
- }
- poss[cnt].x = nx;
- poss[cnt].y = ny;
- cnt++;
- }
- if(!cnt && pool && nowtyp != POOL) {
- pool = FALSE;
- goto nexttry;
- }
- return(cnt);
-}
-
-dist(x,y) int x,y; {
- return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy));
-}
-
-poisoned(string, pname)
-register char *string, *pname;
-{
- register int i;
-
- if(Blind) pline("It was poisoned.");
- else pline("The %s was poisoned!",string);
- if(Poison_resistance) {
- pline("The poison doesn't seem to affect you.");
- return;
- }
- i = rn2(10);
- if(i == 0) {
- u.uhp = -1;
- pline("I am afraid the poison was deadly ...");
- } else if(i <= 5) {
- losestr(rn1(3,3));
- } else {
- losehp(rn1(10,6), pname);
- }
- if(u.uhp < 1) {
- killer = pname;
- done("died");
- }
-}
-
-mondead(mtmp)
-register struct monst *mtmp;
-{
- relobj(mtmp,1);
- unpmon(mtmp);
- relmon(mtmp);
- unstuck(mtmp);
- if(mtmp->isshk) shkdead(mtmp);
- if(mtmp->isgd) gddead();
-#ifndef NOWORM
- if(mtmp->wormno) wormdead(mtmp);
-#endif NOWORM
- monfree(mtmp);
-}
-
-/* called when monster is moved to larger structure */
-replmon(mtmp,mtmp2)
-register struct monst *mtmp, *mtmp2;
-{
- relmon(mtmp);
- monfree(mtmp);
- mtmp2->nmon = fmon;
- fmon = mtmp2;
- if(u.ustuck == mtmp) u.ustuck = mtmp2;
- if(mtmp2->isshk) replshk(mtmp,mtmp2);
- if(mtmp2->isgd) replgd(mtmp,mtmp2);
-}
-
-relmon(mon)
-register struct monst *mon;
-{
- register struct monst *mtmp;
-
- if(mon == fmon) fmon = fmon->nmon;
- else {
- for(mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon) ;
- mtmp->nmon = mon->nmon;
- }
-}
-
-/* we do not free monsters immediately, in order to have their name
- available shortly after their demise */
-struct monst *fdmon; /* chain of dead monsters, need not to be saved */
-
-monfree(mtmp) register struct monst *mtmp; {
- mtmp->nmon = fdmon;
- fdmon = mtmp;
-}
-
-dmonsfree(){
-register struct monst *mtmp;
- while(mtmp = fdmon){
- fdmon = mtmp->nmon;
- free((char *) mtmp);
- }
-}
-
-unstuck(mtmp)
-register struct monst *mtmp;
-{
- if(u.ustuck == mtmp) {
- if(u.uswallow){
- u.ux = mtmp->mx;
- u.uy = mtmp->my;
- u.uswallow = 0;
- setsee();
- docrt();
- }
- u.ustuck = 0;
- }
-}
-
-killed(mtmp)
-register struct monst *mtmp;
-{
-#ifdef lint
-#define NEW_SCORING
-#endif lint
- register int tmp,tmp2,nk,x,y;
- register struct permonst *mdat;
- extern long newuexp();
-
- if(mtmp->cham) mtmp->data = PM_CHAMELEON;
- mdat = mtmp->data;
- if(Blind) pline("You destroy it!");
- else {
- pline("You destroy %s!",
- mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
- }
- if(u.umconf) {
- if(!Blind) pline("Your hands stop glowing blue.");
- u.umconf = 0;
- }
-
- /* count killed monsters */
-#define MAXMONNO 100
- nk = 1; /* in case we cannot find it in mons */
- tmp = mdat - mons; /* index in mons array (if not 'd', '@', ...) */
- if(tmp >= 0 && tmp < CMNUM+2) {
- extern char fut_geno[];
- u.nr_killed[tmp]++;
- if((nk = u.nr_killed[tmp]) > MAXMONNO &&
- !index(fut_geno, mdat->mlet))
- charcat(fut_geno, mdat->mlet);
- }
-
- /* punish bad behaviour */
- if(mdat->mlet == '@') Telepat = 0, u.uluck -= 2;
- if(mtmp->mpeaceful || mtmp->mtame) u.uluck--;
- if(mdat->mlet == 'u') u.uluck -= 5;
- if((int)u.uluck < LUCKMIN) u.uluck = LUCKMIN;
-
- /* give experience points */
- tmp = 1 + mdat->mlevel * mdat->mlevel;
- if(mdat->ac < 3) tmp += 2*(7 - mdat->ac);
- if(index("AcsSDXaeRTVWU&In:P", mdat->mlet))
- tmp += 2*mdat->mlevel;
- if(index("DeV&P",mdat->mlet)) tmp += (7*mdat->mlevel);
- if(mdat->mlevel > 6) tmp += 50;
- if(mdat->mlet == ';') tmp += 1000;
-
-#ifdef NEW_SCORING
- /* ------- recent addition: make nr of points decrease
- when this is not the first of this kind */
- { int ul = u.ulevel;
- int ml = mdat->mlevel;
-
- if(ul < 14) /* points are given based on present and future level */
- for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
- if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk
- >= 10*pow((unsigned)(ul-1)))
- if(++ul == 14) break;
-
- tmp2 = ml - ul -1;
- tmp = (tmp + ((tmp2 < 0) ? 0 : 4<<tmp2))/nk;
- if(!tmp) tmp = 1;
- }
- /* note: ul is not necessarily the future value of u.ulevel */
- /* ------- end of recent valuation change ------- */
-#endif NEW_SCORING
-
- more_experienced(tmp,0);
- flags.botl = 1;
- while(u.ulevel < 14 && u.uexp >= newuexp()){
- pline("Welcome to experience level %u.", ++u.ulevel);
- tmp = rnd(10);
- if(tmp < 3) tmp = rnd(10);
- u.uhpmax += tmp;
- u.uhp += tmp;
- flags.botl = 1;
- }
-
- /* dispose of monster and make cadaver */
- x = mtmp->mx; y = mtmp->my;
- mondead(mtmp);
- tmp = mdat->mlet;
- if(tmp == 'm') { /* he killed a minotaur, give him a wand of digging */
- /* note: the dead minotaur will be on top of it! */
- mksobj_at(WAN_DIGGING, x, y);
- /* if(cansee(x,y)) atl(x,y,fobj->olet); */
- stackobj(fobj);
- } else
-#ifndef NOWORM
- if(tmp == 'w') {
- mksobj_at(WORM_TOOTH, x, y);
- stackobj(fobj);
- } else
-#endif NOWORM
- if(!letter(tmp) || (!index("mw", tmp) && !rn2(3))) tmp = 0;
-
- if(ACCESSIBLE(levl[x][y].typ)) /* might be mimic in wall or dead eel*/
- if(x != u.ux || y != u.uy) /* might be here after swallowed */
- if(index("NTVm&",mdat->mlet) || rn2(5)) {
- register struct obj *obj2 = mkobj_at(tmp,x,y);
- if(cansee(x,y))
- atl(x,y,obj2->olet);
- stackobj(obj2);
- }
-}
-
-kludge(str,arg)
-register char *str,*arg;
-{
- if(Blind) {
- if(*str == '%') pline(str,"It");
- else pline(str,"it");
- } else pline(str,arg);
-}
-
-rescham() /* force all chameleons to become normal */
-{
- register struct monst *mtmp;
-
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->cham) {
- mtmp->cham = 0;
- (void) newcham(mtmp, PM_CHAMELEON);
- }
-}
-
-newcham(mtmp,mdat) /* make a chameleon look like a new monster */
- /* returns 1 if the monster actually changed */
-register struct monst *mtmp;
-register struct permonst *mdat;
-{
- register mhp, hpn, hpd;
-
- if(mdat == mtmp->data) return(0); /* still the same monster */
-#ifndef NOWORM
- if(mtmp->wormno) wormdead(mtmp); /* throw tail away */
-#endif NOWORM
- if (u.ustuck == mtmp) {
- if (u.uswallow) {
- u.uswallow = 0;
- u.uswldtim = 0;
- mnexto (mtmp);
- docrt ();
- prme ();
- }
- u.ustuck = 0;
- }
- hpn = mtmp->mhp;
- hpd = (mtmp->data->mlevel)*8;
- if(!hpd) hpd = 4;
- mtmp->data = mdat;
- mhp = (mdat->mlevel)*8;
- /* new hp: same fraction of max as before */
- mtmp->mhp = 2 + (hpn*mhp)/hpd;
- hpn = mtmp->mhpmax;
- mtmp->mhpmax = 2 + (hpn*mhp)/hpd;
- mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
-#ifndef NOWORM
- if(mdat->mlet == 'w' && getwn(mtmp)) initworm(mtmp);
- /* perhaps we should clear mtmp->mtame here? */
-#endif NOWORM
- unpmon(mtmp); /* necessary for 'I' and to force pmon */
- pmon(mtmp);
- return(1);
-}
-
-mnexto(mtmp) /* Make monster mtmp next to you (if possible) */
-struct monst *mtmp;
-{
- extern coord enexto();
- coord mm;
- mm = enexto(u.ux, u.uy);
- mtmp->mx = mm.x;
- mtmp->my = mm.y;
- pmon(mtmp);
-}
-
-ishuman(mtmp) register struct monst *mtmp; {
- return(mtmp->data->mlet == '@');
-}
-
-setmangry(mtmp) register struct monst *mtmp; {
- if(!mtmp->mpeaceful) return;
- if(mtmp->mtame) return;
- mtmp->mpeaceful = 0;
- if(ishuman(mtmp)) pline("%s gets angry!", Monnam(mtmp));
-}
-
-/* not one hundred procent correct: now a snake may hide under an
- invisible object */
-canseemon(mtmp)
-register struct monst *mtmp;
-{
- return((!mtmp->minvis || See_invisible)
- && (!mtmp->mhide || !o_at(mtmp->mx,mtmp->my))
- && cansee(mtmp->mx, mtmp->my));
-}
diff --git a/games/hack/hack.monst.c b/games/hack/hack.monst.c
deleted file mode 100644
index b682b59de230..000000000000
--- a/games/hack/hack.monst.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.monst.c - version 1.0.2 */
-
-#include "hack.h"
-#include "def.eshk.h"
-extern char plname[PL_NSIZ];
-
-struct permonst mons[CMNUM+2] = {
- { "bat", 'B',1,22,8,1,4,0 },
- { "gnome", 'G',1,6,5,1,6,0 },
- { "hobgoblin", 'H',1,9,5,1,8,0 },
- { "jackal", 'J',0,12,7,1,2,0 },
- { "kobold", 'K',1,6,7,1,4,0 },
- { "leprechaun", 'L',5,15,8,1,2,0 },
- { "giant rat", 'r',0,12,7,1,3,0 },
- { "acid blob", 'a',2,3,8,0,0,0 },
- { "floating eye", 'E',2,1,9,0,0,0 },
- { "homunculus", 'h',2,6,6,1,3,0 },
- { "imp", 'i',2,6,2,1,4,0 },
- { "orc", 'O',2,9,6,1,8,0 },
- { "yellow light", 'y',3,15,0,0,0,0 },
- { "zombie", 'Z',2,6,8,1,8,0 },
- { "giant ant", 'A',3,18,3,1,6,0 },
- { "fog cloud", 'f',3,1,0,1,6,0 },
- { "nymph", 'N',6,12,9,1,2,0 },
- { "piercer", 'p',3,1,3,2,6,0 },
- { "quasit", 'Q',3,15,3,1,4,0 },
- { "quivering blob", 'q',3,1,8,1,8,0 },
- { "violet fungi", 'v',3,1,7,1,4,0 },
- { "giant beetle", 'b',4,6,4,3,4,0 },
- { "centaur", 'C',4,18,4,1,6,0 },
- { "cockatrice", 'c',4,6,6,1,3,0 },
- { "gelatinous cube", 'g',4,6,8,2,4,0 },
- { "jaguar", 'j',4,15,6,1,8,0 },
- { "killer bee", 'k',4,14,4,2,4,0 },
- { "snake", 'S',4,15,3,1,6,0 },
- { "freezing sphere", 'F',2,13,4,0,0,0 },
- { "owlbear", 'o',5,12,5,2,6,0 },
- { "rust monster", 'R',10,18,3,0,0,0 },
- { "scorpion", 's',5,15,3,1,4,0 },
- { "tengu", 't',5,13,5,1,7,0 },
- { "wraith", 'W',5,12,5,1,6,0 },
-#ifdef NOWORM
- { "wumpus", 'w',8,3,2,3,6,0 },
-#else
- { "long worm", 'w',8,3,5,1,4,0 },
-#endif NOWORM
- { "large dog", 'd',6,15,4,2,4,0 },
- { "leocrotta", 'l',6,18,4,3,6,0 },
- { "mimic", 'M',7,3,7,3,4,0 },
- { "troll", 'T',7,12,4,2,7,0 },
- { "unicorn", 'u',8,24,5,1,10,0 },
- { "yeti", 'Y',5,15,6,1,6,0 },
- { "stalker", 'I',8,12,3,4,4,0 },
- { "umber hulk", 'U',9,6,2,2,10,0 },
- { "vampire", 'V',8,12,1,1,6,0 },
- { "xorn", 'X',8,9,-2,4,6,0 },
- { "xan", 'x',7,18,-2,2,4,0 },
- { "zruty", 'z',9,8,3,3,6,0 },
- { "chameleon", ':',6,5,6,4,2,0 },
- { "dragon", 'D',10,9,-1,3,8,0 },
- { "ettin", 'e',10,12,3,2,8,0 },
- { "lurker above", '\'',10,3,3,0,0,0 },
- { "nurse", 'n',11,6,0,1,3,0 },
- { "trapper", ',',12,3,3,0,0,0 },
- { "purple worm", 'P',15,9,6,2,8,0 },
- { "demon", '&',10,12,-4,1,4,0 },
- { "minotaur", 'm',15,15,6,4,10,0 },
- { "shopkeeper", '@', 12, 18, 0, 4, 8, sizeof(struct eshk) }
-};
-
-struct permonst pm_ghost = { "ghost", ' ', 10, 3, -5, 1, 1, sizeof(plname) };
-struct permonst pm_wizard = {
- "wizard of Yendor", '1', 15, 12, -2, 1, 12, 0
-};
-#ifdef MAIL
-struct permonst pm_mail_daemon = { "mail daemon", '2', 100, 1, 10, 0, 0, 0 };
-#endif MAIL
-struct permonst pm_eel = { "giant eel", ';', 15, 6, -3, 3, 6, 0 };
diff --git a/games/hack/hack.o_init.c b/games/hack/hack.o_init.c
deleted file mode 100644
index 37b33aefb081..000000000000
--- a/games/hack/hack.o_init.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.o_init.c - version 1.0.3 */
-
-#include "config.h" /* for typedefs */
-#include "def.objects.h"
-#include "hack.onames.h" /* for LAST_GEM */
-extern char *index();
-
-int
-letindex(let) register char let; {
-register int i = 0;
-register char ch;
- while((ch = obj_symbols[i++]) != 0)
- if(ch == let) return(i);
- return(0);
-}
-
-init_objects(){
-register int i, j, first, last, sum, end;
-register char let, *tmp;
- /* init base; if probs given check that they add up to 100,
- otherwise compute probs; shuffle descriptions */
- end = SIZE(objects);
- first = 0;
- while( first < end ) {
- let = objects[first].oc_olet;
- last = first+1;
- while(last < end && objects[last].oc_olet == let
- && objects[last].oc_name != NULL)
- last++;
- i = letindex(let);
- if((!i && let != ILLOBJ_SYM) || bases[i] != 0)
- error("initialization error");
- bases[i] = first;
-
- if(let == GEM_SYM)
- setgemprobs();
- check:
- sum = 0;
- for(j = first; j < last; j++) sum += objects[j].oc_prob;
- if(sum == 0) {
- for(j = first; j < last; j++)
- objects[j].oc_prob = (100+j-first)/(last-first);
- goto check;
- }
- if(sum != 100)
- error("init-prob error for %c", let);
-
- if(objects[first].oc_descr != NULL && let != TOOL_SYM){
- /* shuffle, also some additional descriptions */
- while(last < end && objects[last].oc_olet == let)
- last++;
- j = last;
- while(--j > first) {
- i = first + rn2(j+1-first);
- tmp = objects[j].oc_descr;
- objects[j].oc_descr = objects[i].oc_descr;
- objects[i].oc_descr = tmp;
- }
- }
- first = last;
- }
-}
-
-probtype(let) register char let; {
-register int i = bases[letindex(let)];
-register int prob = rn2(100);
- while((prob -= objects[i].oc_prob) >= 0) i++;
- if(objects[i].oc_olet != let || !objects[i].oc_name)
- panic("probtype(%c) error, i=%d", let, i);
- return(i);
-}
-
-setgemprobs()
-{
- register int j,first;
- extern xchar dlevel;
-
- first = bases[letindex(GEM_SYM)];
-
- for(j = 0; j < 9-dlevel/3; j++)
- objects[first+j].oc_prob = 0;
- first += j;
- if(first >= LAST_GEM || first >= SIZE(objects) ||
- objects[first].oc_olet != GEM_SYM ||
- objects[first].oc_name == NULL)
- printf("Not enough gems? - first=%d j=%d LAST_GEM=%d\n",
- first, j, LAST_GEM);
- for(j = first; j < LAST_GEM; j++)
- objects[j].oc_prob = (20+j-first)/(LAST_GEM-first);
-}
-
-oinit() /* level dependent initialization */
-{
- setgemprobs();
-}
-
-extern long *alloc();
-
-savenames(fd) register fd; {
-register int i;
-unsigned len;
- bwrite(fd, (char *) bases, sizeof bases);
- bwrite(fd, (char *) objects, sizeof objects);
- /* as long as we use only one version of Hack/Quest we
- need not save oc_name and oc_descr, but we must save
- oc_uname for all objects */
- for(i=0; i < SIZE(objects); i++) {
- if(objects[i].oc_uname) {
- len = strlen(objects[i].oc_uname)+1;
- bwrite(fd, (char *) &len, sizeof len);
- bwrite(fd, objects[i].oc_uname, len);
- }
- }
-}
-
-restnames(fd) register fd; {
-register int i;
-unsigned len;
- mread(fd, (char *) bases, sizeof bases);
- mread(fd, (char *) objects, sizeof objects);
- for(i=0; i < SIZE(objects); i++) if(objects[i].oc_uname) {
- mread(fd, (char *) &len, sizeof len);
- objects[i].oc_uname = (char *) alloc(len);
- mread(fd, objects[i].oc_uname, len);
- }
-}
-
-dodiscovered() /* free after Robert Viduya */
-{
- extern char *typename();
- register int i, end;
- int ct = 0;
-
- cornline(0, "Discoveries");
-
- end = SIZE(objects);
- for (i = 0; i < end; i++) {
- if (interesting_to_discover (i)) {
- ct++;
- cornline(1, typename(i));
- }
- }
- if (ct == 0) {
- pline ("You haven't discovered anything yet...");
- cornline(3, (char *) 0);
- } else
- cornline(2, (char *) 0);
-
- return(0);
-}
-
-interesting_to_discover(i)
-register int i;
-{
- return(
- objects[i].oc_uname != NULL ||
- (objects[i].oc_name_known && objects[i].oc_descr != NULL)
- );
-}
diff --git a/games/hack/hack.objnam.c b/games/hack/hack.objnam.c
deleted file mode 100644
index a1c966cd912e..000000000000
--- a/games/hack/hack.objnam.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.objnam.c - version 1.0.2 */
-
-#include "hack.h"
-#define Sprintf (void) sprintf
-#define Strcat (void) strcat
-#define Strcpy (void) strcpy
-#define PREFIX 15
-extern char *eos();
-extern int bases[];
-
-char *
-strprepend(s,pref) register char *s, *pref; {
-register int i = strlen(pref);
- if(i > PREFIX) {
- pline("WARNING: prefix too short.");
- return(s);
- }
- s -= i;
- (void) strncpy(s, pref, i); /* do not copy trailing 0 */
- return(s);
-}
-
-char *
-sitoa(a) int a; {
-static char buf[13];
- Sprintf(buf, (a < 0) ? "%d" : "+%d", a);
- return(buf);
-}
-
-char *
-typename(otyp)
-register int otyp;
-{
-static char buf[BUFSZ];
-register struct objclass *ocl = &objects[otyp];
-register char *an = ocl->oc_name;
-register char *dn = ocl->oc_descr;
-register char *un = ocl->oc_uname;
-register int nn = ocl->oc_name_known;
- switch(ocl->oc_olet) {
- case POTION_SYM:
- Strcpy(buf, "potion");
- break;
- case SCROLL_SYM:
- Strcpy(buf, "scroll");
- break;
- case WAND_SYM:
- Strcpy(buf, "wand");
- break;
- case RING_SYM:
- Strcpy(buf, "ring");
- break;
- default:
- if(nn) {
- Strcpy(buf, an);
- if(otyp >= TURQUOISE && otyp <= JADE)
- Strcat(buf, " stone");
- if(un)
- Sprintf(eos(buf), " called %s", un);
- if(dn)
- Sprintf(eos(buf), " (%s)", dn);
- } else {
- Strcpy(buf, dn ? dn : an);
- if(ocl->oc_olet == GEM_SYM)
- Strcat(buf, " gem");
- if(un)
- Sprintf(eos(buf), " called %s", un);
- }
- return(buf);
- }
- /* here for ring/scroll/potion/wand */
- if(nn)
- Sprintf(eos(buf), " of %s", an);
- if(un)
- Sprintf(eos(buf), " called %s", un);
- if(dn)
- Sprintf(eos(buf), " (%s)", dn);
- return(buf);
-}
-
-char *
-xname(obj)
-register struct obj *obj;
-{
-static char bufr[BUFSZ];
-register char *buf = &(bufr[PREFIX]); /* leave room for "17 -3 " */
-register int nn = objects[obj->otyp].oc_name_known;
-register char *an = objects[obj->otyp].oc_name;
-register char *dn = objects[obj->otyp].oc_descr;
-register char *un = objects[obj->otyp].oc_uname;
-register int pl = (obj->quan != 1);
- if(!obj->dknown && !Blind) obj->dknown = 1; /* %% doesnt belong here */
- switch(obj->olet) {
- case AMULET_SYM:
- Strcpy(buf, (obj->spe < 0 && obj->known)
- ? "cheap plastic imitation of the " : "");
- Strcat(buf,"Amulet of Yendor");
- break;
- case TOOL_SYM:
- if(!nn) {
- Strcpy(buf, dn);
- break;
- }
- Strcpy(buf,an);
- break;
- case FOOD_SYM:
- if(obj->otyp == DEAD_HOMUNCULUS && pl) {
- pl = 0;
- Strcpy(buf, "dead homunculi");
- break;
- }
- /* fungis ? */
- /* fall into next case */
- case WEAPON_SYM:
- if(obj->otyp == WORM_TOOTH && pl) {
- pl = 0;
- Strcpy(buf, "worm teeth");
- break;
- }
- if(obj->otyp == CRYSKNIFE && pl) {
- pl = 0;
- Strcpy(buf, "crysknives");
- break;
- }
- /* fall into next case */
- case ARMOR_SYM:
- case CHAIN_SYM:
- case ROCK_SYM:
- Strcpy(buf,an);
- break;
- case BALL_SYM:
- Sprintf(buf, "%sheavy iron ball",
- (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
- break;
- case POTION_SYM:
- if(nn || un || !obj->dknown) {
- Strcpy(buf, "potion");
- if(pl) {
- pl = 0;
- Strcat(buf, "s");
- }
- if(!obj->dknown) break;
- if(un) {
- Strcat(buf, " called ");
- Strcat(buf, un);
- } else {
- Strcat(buf, " of ");
- Strcat(buf, an);
- }
- } else {
- Strcpy(buf, dn);
- Strcat(buf, " potion");
- }
- break;
- case SCROLL_SYM:
- Strcpy(buf, "scroll");
- if(pl) {
- pl = 0;
- Strcat(buf, "s");
- }
- if(!obj->dknown) break;
- if(nn) {
- Strcat(buf, " of ");
- Strcat(buf, an);
- } else if(un) {
- Strcat(buf, " called ");
- Strcat(buf, un);
- } else {
- Strcat(buf, " labeled ");
- Strcat(buf, dn);
- }
- break;
- case WAND_SYM:
- if(!obj->dknown)
- Sprintf(buf, "wand");
- else if(nn)
- Sprintf(buf, "wand of %s", an);
- else if(un)
- Sprintf(buf, "wand called %s", un);
- else
- Sprintf(buf, "%s wand", dn);
- break;
- case RING_SYM:
- if(!obj->dknown)
- Sprintf(buf, "ring");
- else if(nn)
- Sprintf(buf, "ring of %s", an);
- else if(un)
- Sprintf(buf, "ring called %s", un);
- else
- Sprintf(buf, "%s ring", dn);
- break;
- case GEM_SYM:
- if(!obj->dknown) {
- Strcpy(buf, "gem");
- break;
- }
- if(!nn) {
- Sprintf(buf, "%s gem", dn);
- break;
- }
- Strcpy(buf, an);
- if(obj->otyp >= TURQUOISE && obj->otyp <= JADE)
- Strcat(buf, " stone");
- break;
- default:
- Sprintf(buf,"glorkum %c (0%o) %u %d",
- obj->olet,obj->olet,obj->otyp,obj->spe);
- }
- if(pl) {
- register char *p;
-
- for(p = buf; *p; p++) {
- if(!strncmp(" of ", p, 4)) {
- /* pieces of, cloves of, lumps of */
- register int c1, c2 = 's';
-
- do {
- c1 = c2; c2 = *p; *p++ = c1;
- } while(c1);
- goto nopl;
- }
- }
- p = eos(buf)-1;
- if(*p == 's' || *p == 'z' || *p == 'x' ||
- (*p == 'h' && p[-1] == 's'))
- Strcat(buf, "es"); /* boxes */
- else if(*p == 'y' && !index(vowels, p[-1]))
- Strcpy(p, "ies"); /* rubies, zruties */
- else
- Strcat(buf, "s");
- }
-nopl:
- if(obj->onamelth) {
- Strcat(buf, " named ");
- Strcat(buf, ONAME(obj));
- }
- return(buf);
-}
-
-char *
-doname(obj)
-register struct obj *obj;
-{
-char prefix[PREFIX];
-register char *bp = xname(obj);
- if(obj->quan != 1)
- Sprintf(prefix, "%u ", obj->quan);
- else
- Strcpy(prefix, "a ");
- switch(obj->olet) {
- case AMULET_SYM:
- if(strncmp(bp, "cheap ", 6))
- Strcpy(prefix, "the ");
- break;
- case ARMOR_SYM:
- if(obj->owornmask & W_ARMOR)
- Strcat(bp, " (being worn)");
- /* fall into next case */
- case WEAPON_SYM:
- if(obj->known) {
- Strcat(prefix, sitoa(obj->spe));
- Strcat(prefix, " ");
- }
- break;
- case WAND_SYM:
- if(obj->known)
- Sprintf(eos(bp), " (%d)", obj->spe);
- break;
- case RING_SYM:
- if(obj->owornmask & W_RINGR) Strcat(bp, " (on right hand)");
- if(obj->owornmask & W_RINGL) Strcat(bp, " (on left hand)");
- if(obj->known && (objects[obj->otyp].bits & SPEC)) {
- Strcat(prefix, sitoa(obj->spe));
- Strcat(prefix, " ");
- }
- break;
- }
- if(obj->owornmask & W_WEP)
- Strcat(bp, " (weapon in hand)");
- if(obj->unpaid)
- Strcat(bp, " (unpaid)");
- if(!strcmp(prefix, "a ") && index(vowels, *bp))
- Strcpy(prefix, "an ");
- bp = strprepend(bp, prefix);
- return(bp);
-}
-
-/* used only in hack.fight.c (thitu) */
-setan(str,buf)
-register char *str,*buf;
-{
- if(index(vowels,*str))
- Sprintf(buf, "an %s", str);
- else
- Sprintf(buf, "a %s", str);
-}
-
-char *
-aobjnam(otmp,verb) register struct obj *otmp; register char *verb; {
-register char *bp = xname(otmp);
-char prefix[PREFIX];
- if(otmp->quan != 1) {
- Sprintf(prefix, "%u ", otmp->quan);
- bp = strprepend(bp, prefix);
- }
-
- if(verb) {
- /* verb is given in plural (i.e., without trailing s) */
- Strcat(bp, " ");
- if(otmp->quan != 1)
- Strcat(bp, verb);
- else if(!strcmp(verb, "are"))
- Strcat(bp, "is");
- else {
- Strcat(bp, verb);
- Strcat(bp, "s");
- }
- }
- return(bp);
-}
-
-char *
-Doname(obj)
-register struct obj *obj;
-{
- register char *s = doname(obj);
-
- if('a' <= *s && *s <= 'z') *s -= ('a' - 'A');
- return(s);
-}
-
-char *wrp[] = { "wand", "ring", "potion", "scroll", "gem" };
-char wrpsym[] = { WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM };
-
-struct obj *
-readobjnam(bp) register char *bp; {
-register char *p;
-register int i;
-int cnt, spe, spesgn, typ, heavy;
-char let;
-char *un, *dn, *an;
-/* int the = 0; char *oname = 0; */
- cnt = spe = spesgn = typ = heavy = 0;
- let = 0;
- an = dn = un = 0;
- for(p = bp; *p; p++)
- if('A' <= *p && *p <= 'Z') *p += 'a'-'A';
- if(!strncmp(bp, "the ", 4)){
-/* the = 1; */
- bp += 4;
- } else if(!strncmp(bp, "an ", 3)){
- cnt = 1;
- bp += 3;
- } else if(!strncmp(bp, "a ", 2)){
- cnt = 1;
- bp += 2;
- }
- if(!cnt && digit(*bp)){
- cnt = atoi(bp);
- while(digit(*bp)) bp++;
- while(*bp == ' ') bp++;
- }
- if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */
-
- if(*bp == '+' || *bp == '-'){
- spesgn = (*bp++ == '+') ? 1 : -1;
- spe = atoi(bp);
- while(digit(*bp)) bp++;
- while(*bp == ' ') bp++;
- } else {
- p = rindex(bp, '(');
- if(p) {
- if(p > bp && p[-1] == ' ') p[-1] = 0;
- else *p = 0;
- p++;
- spe = atoi(p);
- while(digit(*p)) p++;
- if(strcmp(p, ")")) spe = 0;
- else spesgn = 1;
- }
- }
- /* now we have the actual name, as delivered by xname, say
- green potions called whisky
- scrolls labeled "QWERTY"
- egg
- dead zruties
- fortune cookies
- very heavy iron ball named hoei
- wand of wishing
- elven cloak
- */
- for(p = bp; *p; p++) if(!strncmp(p, " named ", 7)) {
- *p = 0;
-/* oname = p+7; */
- }
- for(p = bp; *p; p++) if(!strncmp(p, " called ", 8)) {
- *p = 0;
- un = p+8;
- }
- for(p = bp; *p; p++) if(!strncmp(p, " labeled ", 9)) {
- *p = 0;
- dn = p+9;
- }
-
- /* first change to singular if necessary */
- if(cnt != 1) {
- /* find "cloves of garlic", "worthless pieces of blue glass" */
- for(p = bp; *p; p++) if(!strncmp(p, "s of ", 5)){
- while(*p = p[1]) p++;
- goto sing;
- }
- /* remove -s or -es (boxes) or -ies (rubies, zruties) */
- p = eos(bp);
- if(p[-1] == 's') {
- if(p[-2] == 'e') {
- if(p[-3] == 'i') {
- if(!strcmp(p-7, "cookies"))
- goto mins;
- Strcpy(p-3, "y");
- goto sing;
- }
-
- /* note: cloves / knives from clove / knife */
- if(!strcmp(p-6, "knives")) {
- Strcpy(p-3, "fe");
- goto sing;
- }
-
- /* note: nurses, axes but boxes */
- if(!strcmp(p-5, "boxes")) {
- p[-2] = 0;
- goto sing;
- }
- }
- mins:
- p[-1] = 0;
- } else {
- if(!strcmp(p-9, "homunculi")) {
- Strcpy(p-1, "us"); /* !! makes string longer */
- goto sing;
- }
- if(!strcmp(p-5, "teeth")) {
- Strcpy(p-5, "tooth");
- goto sing;
- }
- /* here we cannot find the plural suffix */
- }
- }
-sing:
- if(!strcmp(bp, "amulet of yendor")) {
- typ = AMULET_OF_YENDOR;
- goto typfnd;
- }
- p = eos(bp);
- if(!strcmp(p-5, " mail")){ /* Note: ring mail is not a ring ! */
- let = ARMOR_SYM;
- an = bp;
- goto srch;
- }
- for(i = 0; i < sizeof(wrpsym); i++) {
- register int j = strlen(wrp[i]);
- if(!strncmp(bp, wrp[i], j)){
- let = wrpsym[i];
- bp += j;
- if(!strncmp(bp, " of ", 4)) an = bp+4;
- /* else if(*bp) ?? */
- goto srch;
- }
- if(!strcmp(p-j, wrp[i])){
- let = wrpsym[i];
- p -= j;
- *p = 0;
- if(p[-1] == ' ') p[-1] = 0;
- dn = bp;
- goto srch;
- }
- }
- if(!strcmp(p-6, " stone")){
- p[-6] = 0;
- let = GEM_SYM;
- an = bp;
- goto srch;
- }
- if(!strcmp(bp, "very heavy iron ball")){
- heavy = 1;
- typ = HEAVY_IRON_BALL;
- goto typfnd;
- }
- an = bp;
-srch:
- if(!an && !dn && !un)
- goto any;
- i = 1;
- if(let) i = bases[letindex(let)];
- while(i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)){
- register char *zn = objects[i].oc_name;
-
- if(!zn) goto nxti;
- if(an && strcmp(an, zn))
- goto nxti;
- if(dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
- goto nxti;
- if(un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
- goto nxti;
- typ = i;
- goto typfnd;
- nxti:
- i++;
- }
-any:
- if(!let) let = wrpsym[rn2(sizeof(wrpsym))];
- typ = probtype(let);
-typfnd:
- { register struct obj *otmp;
- extern struct obj *mksobj();
- let = objects[typ].oc_olet;
- otmp = mksobj(typ);
- if(heavy)
- otmp->owt += 15;
- if(cnt > 0 && index("%?!*)", let) &&
- (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
- otmp->quan = cnt;
-
- if(spe > 3 && spe > otmp->spe)
- spe = 0;
- else if(let == WAND_SYM)
- spe = otmp->spe;
- if(spe == 3 && u.uluck < 0)
- spesgn = -1;
- if(let != WAND_SYM && spesgn == -1)
- spe = -spe;
- if(let == BALL_SYM)
- spe = 0;
- else if(let == AMULET_SYM)
- spe = -1;
- else if(typ == WAN_WISHING && rn2(10))
- spe = (rn2(10) ? -1 : 0);
- otmp->spe = spe;
-
- if(spesgn == -1)
- otmp->cursed = 1;
-
- return(otmp);
- }
-}
diff --git a/games/hack/hack.options.c b/games/hack/hack.options.c
deleted file mode 100644
index ed95de310ead..000000000000
--- a/games/hack/hack.options.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.options.c - version 1.0.3 */
-
-#include "config.h"
-#include "hack.h"
-extern char *eos();
-
-initoptions()
-{
- register char *opts;
- extern char *getenv();
-
- flags.time = flags.nonews = flags.notombstone = flags.end_own =
- flags.standout = flags.nonull = FALSE;
- flags.no_rest_on_space = TRUE;
- flags.invlet_constant = TRUE;
- flags.end_top = 5;
- flags.end_around = 4;
- flags.female = FALSE; /* players are usually male */
-
- if(opts = getenv("HACKOPTIONS"))
- parseoptions(opts,TRUE);
-}
-
-parseoptions(opts, from_env)
-register char *opts;
-boolean from_env;
-{
- register char *op,*op2;
- unsigned num;
- boolean negated;
-
- if(op = index(opts, ',')) {
- *op++ = 0;
- parseoptions(op, from_env);
- }
- if(op = index(opts, ' ')) {
- op2 = op;
- while(*op++)
- if(*op != ' ') *op2++ = *op;
- }
- if(!*opts) return;
- negated = FALSE;
- while((*opts == '!') || !strncmp(opts, "no", 2)) {
- if(*opts == '!') opts++; else opts += 2;
- negated = !negated;
- }
-
- if(!strncmp(opts,"standout",8)) {
- flags.standout = !negated;
- return;
- }
-
- if(!strncmp(opts,"null",3)) {
- flags.nonull = negated;
- return;
- }
-
- if(!strncmp(opts,"tombstone",4)) {
- flags.notombstone = negated;
- return;
- }
-
- if(!strncmp(opts,"news",4)) {
- flags.nonews = negated;
- return;
- }
-
- if(!strncmp(opts,"time",4)) {
- flags.time = !negated;
- flags.botl = 1;
- return;
- }
-
- if(!strncmp(opts,"restonspace",4)) {
- flags.no_rest_on_space = negated;
- return;
- }
-
- if(!strncmp(opts,"fixinv",4)) {
- if(from_env)
- flags.invlet_constant = !negated;
- else
- pline("The fixinvlet option must be in HACKOPTIONS.");
- return;
- }
-
- if(!strncmp(opts,"male",4)) {
- flags.female = negated;
- return;
- }
- if(!strncmp(opts,"female",6)) {
- flags.female = !negated;
- return;
- }
-
- /* name:string */
- if(!strncmp(opts,"name",4)) {
- extern char plname[PL_NSIZ];
- if(!from_env) {
- pline("The playername can be set only from HACKOPTIONS.");
- return;
- }
- op = index(opts,':');
- if(!op) goto bad;
- (void) strncpy(plname, op+1, sizeof(plname)-1);
- return;
- }
-
- /* endgame:5t[op] 5a[round] o[wn] */
- if(!strncmp(opts,"endgame",3)) {
- op = index(opts,':');
- if(!op) goto bad;
- op++;
- while(*op) {
- num = 1;
- if(digit(*op)) {
- num = atoi(op);
- while(digit(*op)) op++;
- } else
- if(*op == '!') {
- negated = !negated;
- op++;
- }
- switch(*op) {
- case 't':
- flags.end_top = num;
- break;
- case 'a':
- flags.end_around = num;
- break;
- case 'o':
- flags.end_own = !negated;
- break;
- default:
- goto bad;
- }
- while(letter(*++op)) ;
- if(*op == '/') op++;
- }
- return;
- }
-bad:
- if(!from_env) {
- if(!strncmp(opts, "help", 4)) {
- pline("%s%s%s",
-"To set options use `HACKOPTIONS=\"<options>\"' in your environment, or ",
-"give the command 'o' followed by the line `<options>' while playing. ",
-"Here <options> is a list of <option>s separated by commas." );
- pline("%s%s%s",
-"Simple (boolean) options are rest_on_space, news, time, ",
-"null, tombstone, (fe)male. ",
-"These can be negated by prefixing them with '!' or \"no\"." );
- pline("%s",
-"A string option is name, as in HACKOPTIONS=\"name:Merlin-W\"." );
- pline("%s%s%s",
-"A compound option is endgame; it is followed by a description of what ",
-"parts of the scorelist you want to see. You might for example say: ",
-"`endgame:own scores/5 top scores/4 around my score'." );
- return;
- }
- pline("Bad option: %s.", opts);
- pline("Type `o help<cr>' for help.");
- return;
- }
- puts("Bad syntax in HACKOPTIONS.");
- puts("Use for example:");
- puts(
-"HACKOPTIONS=\"!restonspace,notombstone,endgame:own/5 topscorers/4 around me\""
- );
- getret();
-}
-
-doset()
-{
- char buf[BUFSZ];
-
- pline("What options do you want to set? ");
- getlin(buf);
- if(!buf[0] || buf[0] == '\033') {
- (void) strcpy(buf,"HACKOPTIONS=");
- (void) strcat(buf, flags.female ? "female," : "male,");
- if(flags.standout) (void) strcat(buf,"standout,");
- if(flags.nonull) (void) strcat(buf,"nonull,");
- if(flags.nonews) (void) strcat(buf,"nonews,");
- if(flags.time) (void) strcat(buf,"time,");
- if(flags.notombstone) (void) strcat(buf,"notombstone,");
- if(flags.no_rest_on_space)
- (void) strcat(buf,"!rest_on_space,");
- if(flags.end_top != 5 || flags.end_around != 4 || flags.end_own){
- (void) sprintf(eos(buf), "endgame: %u topscores/%u around me",
- flags.end_top, flags.end_around);
- if(flags.end_own) (void) strcat(buf, "/own scores");
- } else {
- register char *eop = eos(buf);
- if(*--eop == ',') *eop = 0;
- }
- pline(buf);
- } else
- parseoptions(buf, FALSE);
-
- return(0);
-}
diff --git a/games/hack/hack.pager.c b/games/hack/hack.pager.c
deleted file mode 100644
index b1edb9164e8c..000000000000
--- a/games/hack/hack.pager.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.pager.c - version 1.0.3 */
-
-/* This file contains the command routine dowhatis() and a pager. */
-/* Also readmail() and doshell(), and generally the things that
- contact the outside world. */
-
-#include <sys/types.h>
-#include <sys/signal.h>
-#include <stdio.h>
-#include "hack.h"
-extern int CO, LI; /* usually COLNO and ROWNO+2 */
-extern char *CD;
-extern char quitchars[];
-extern char *getenv(), *getlogin();
-void done1();
-
-dowhatis()
-{
- FILE *fp;
- char bufr[BUFSZ+6];
- register char *buf = &bufr[6], *ep, q;
- extern char readchar();
-
- if(!(fp = fopen(DATAFILE, "r")))
- pline("Cannot open data file!");
- else {
- pline("Specify what? ");
- q = readchar();
- if(q != '\t')
- while(fgets(buf,BUFSZ,fp))
- if(*buf == q) {
- ep = index(buf, '\n');
- if(ep) *ep = 0;
- /* else: bad data file */
- /* Expand tab 'by hand' */
- if(buf[1] == '\t'){
- buf = bufr;
- buf[0] = q;
- (void) strncpy(buf+1, " ", 7);
- }
- pline(buf);
- if(ep[-1] == ';') {
- pline("More info? ");
- if(readchar() == 'y') {
- page_more(fp,1); /* does fclose() */
- return(0);
- }
- }
- (void) fclose(fp); /* kopper@psuvax1 */
- return(0);
- }
- pline("I've never heard of such things.");
- (void) fclose(fp);
- }
- return(0);
-}
-
-/* make the paging of a file interruptible */
-static int got_intrup;
-
-void
-intruph(){
- got_intrup++;
-}
-
-/* simple pager, also used from dohelp() */
-page_more(fp,strip)
-FILE *fp;
-int strip; /* nr of chars to be stripped from each line (0 or 1) */
-{
- register char *bufr, *ep;
- sig_t prevsig = signal(SIGINT, intruph);
-
- set_pager(0);
- bufr = (char *) alloc((unsigned) CO);
- bufr[CO-1] = 0;
- while(fgets(bufr,CO-1,fp) && (!strip || *bufr == '\t') && !got_intrup){
- ep = index(bufr, '\n');
- if(ep)
- *ep = 0;
- if(page_line(bufr+strip)) {
- set_pager(2);
- goto ret;
- }
- }
- set_pager(1);
-ret:
- free(bufr);
- (void) fclose(fp);
- (void) signal(SIGINT, prevsig);
- got_intrup = 0;
-}
-
-static boolean whole_screen = TRUE;
-#define PAGMIN 12 /* minimum # of lines for page below level map */
-
-set_whole_screen() { /* called in termcap as soon as LI is known */
- whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD);
-}
-
-#ifdef NEWS
-readnews() {
- register int ret;
-
- whole_screen = TRUE; /* force a docrt(), our first */
- ret = page_file(NEWS, TRUE);
- set_whole_screen();
- return(ret); /* report whether we did docrt() */
-}
-#endif NEWS
-
-set_pager(mode)
-register int mode; /* 0: open 1: wait+close 2: close */
-{
- static boolean so;
- if(mode == 0) {
- if(!whole_screen) {
- /* clear topline */
- clrlin();
- /* use part of screen below level map */
- curs(1, ROWNO+4);
- } else {
- cls();
- }
- so = flags.standout;
- flags.standout = 1;
- } else {
- if(mode == 1) {
- curs(1, LI);
- more();
- }
- flags.standout = so;
- if(whole_screen)
- docrt();
- else {
- curs(1, ROWNO+4);
- cl_eos();
- }
- }
-}
-
-page_line(s) /* returns 1 if we should quit */
-register char *s;
-{
- extern char morc;
-
- if(cury == LI-1) {
- if(!*s)
- return(0); /* suppress blank lines at top */
- putchar('\n');
- cury++;
- cmore("q\033");
- if(morc) {
- morc = 0;
- return(1);
- }
- if(whole_screen)
- cls();
- else {
- curs(1, ROWNO+4);
- cl_eos();
- }
- }
- puts(s);
- cury++;
- return(0);
-}
-
-/*
- * Flexible pager: feed it with a number of lines and it will decide
- * whether these should be fed to the pager above, or displayed in a
- * corner.
- * Call:
- * cornline(0, title or 0) : initialize
- * cornline(1, text) : add text to the chain of texts
- * cornline(2, morcs) : output everything and cleanup
- * cornline(3, 0) : cleanup
- */
-
-cornline(mode, text)
-int mode;
-char *text;
-{
- static struct line {
- struct line *next_line;
- char *line_text;
- } *texthead, *texttail;
- static int maxlen;
- static int linect;
- register struct line *tl;
-
- if(mode == 0) {
- texthead = 0;
- maxlen = 0;
- linect = 0;
- if(text) {
- cornline(1, text); /* title */
- cornline(1, ""); /* blank line */
- }
- return;
- }
-
- if(mode == 1) {
- register int len;
-
- if(!text) return; /* superfluous, just to be sure */
- linect++;
- len = strlen(text);
- if(len > maxlen)
- maxlen = len;
- tl = (struct line *)
- alloc((unsigned)(len + sizeof(struct line) + 1));
- tl->next_line = 0;
- tl->line_text = (char *)(tl + 1);
- (void) strcpy(tl->line_text, text);
- if(!texthead)
- texthead = tl;
- else
- texttail->next_line = tl;
- texttail = tl;
- return;
- }
-
- /* --- now we really do it --- */
- if(mode == 2 && linect == 1) /* topline only */
- pline(texthead->line_text);
- else
- if(mode == 2) {
- register int curline, lth;
-
- if(flags.toplin == 1) more(); /* ab@unido */
- remember_topl();
-
- lth = CO - maxlen - 2; /* Use full screen width */
- if (linect < LI && lth >= 10) { /* in a corner */
- home ();
- cl_end ();
- flags.toplin = 0;
- curline = 1;
- for (tl = texthead; tl; tl = tl->next_line) {
- curs (lth, curline);
- if(curline > 1)
- cl_end ();
- putsym(' ');
- putstr (tl->line_text);
- curline++;
- }
- curs (lth, curline);
- cl_end ();
- cmore (text);
- home ();
- cl_end ();
- docorner (lth, curline-1);
- } else { /* feed to pager */
- set_pager(0);
- for (tl = texthead; tl; tl = tl->next_line) {
- if (page_line (tl->line_text)) {
- set_pager(2);
- goto cleanup;
- }
- }
- if(text) {
- cgetret(text);
- set_pager(2);
- } else
- set_pager(1);
- }
- }
-
-cleanup:
- while(tl = texthead) {
- texthead = tl->next_line;
- free((char *) tl);
- }
-}
-
-dohelp()
-{
- char c;
-
- pline ("Long or short help? ");
- while (((c = readchar ()) != 'l') && (c != 's') && !index(quitchars,c))
- bell ();
- if (!index(quitchars, c))
- (void) page_file((c == 'l') ? HELP : SHELP, FALSE);
- return(0);
-}
-
-page_file(fnam, silent) /* return: 0 - cannot open fnam; 1 - otherwise */
-register char *fnam;
-boolean silent;
-{
-#ifdef DEF_PAGER /* this implies that UNIX is defined */
- {
- /* use external pager; this may give security problems */
-
- register int fd = open(fnam, 0);
-
- if(fd < 0) {
- if(!silent) pline("Cannot open %s.", fnam);
- return(0);
- }
- if(child(1)){
- extern char *catmore;
-
- /* Now that child() does a setuid(getuid()) and a chdir(),
- we may not be able to open file fnam anymore, so make
- it stdin. */
- (void) close(0);
- if(dup(fd)) {
- if(!silent) printf("Cannot open %s as stdin.\n", fnam);
- } else {
- execl(catmore, "page", (char *) 0);
- if(!silent) printf("Cannot exec %s.\n", catmore);
- }
- exit(1);
- }
- (void) close(fd);
- }
-#else DEF_PAGER
- {
- FILE *f; /* free after Robert Viduya */
-
- if ((f = fopen (fnam, "r")) == (FILE *) 0) {
- if(!silent) {
- home(); perror (fnam); flags.toplin = 1;
- pline ("Cannot open %s.", fnam);
- }
- return(0);
- }
- page_more(f, 0);
- }
-#endif DEF_PAGER
-
- return(1);
-}
-
-#ifdef UNIX
-#ifdef SHELL
-dosh(){
-register char *str;
- if(child(0)) {
- if(str = getenv("SHELL"))
- execl(str, str, (char *) 0);
- else
- execl("/bin/sh", "sh", (char *) 0);
- pline("sh: cannot execute.");
- exit(1);
- }
- return(0);
-}
-#endif SHELL
-
-#ifdef NOWAITINCLUDE
-union wait { /* used only for the cast (union wait *) 0 */
- int w_status;
- struct {
- unsigned short w_Termsig:7;
- unsigned short w_Coredump:1;
- unsigned short w_Retcode:8;
- } w_T;
-};
-
-#else
-
-#ifdef BSD
-#include <sys/wait.h>
-#else
-#include <wait.h>
-#endif BSD
-#endif NOWAITINCLUDE
-
-child(wt) {
- int status;
- register int f;
-
- f = fork();
- if(f == 0){ /* child */
- settty((char *) 0); /* also calls end_screen() */
- (void) setuid(getuid());
- (void) setgid(getgid());
-#ifdef CHDIR
- (void) chdir(getenv("HOME"));
-#endif CHDIR
- return(1);
- }
- if(f == -1) { /* cannot fork */
- pline("Fork failed. Try again.");
- return(0);
- }
- /* fork succeeded; wait for child to exit */
- (void) signal(SIGINT,SIG_IGN);
- (void) signal(SIGQUIT,SIG_IGN);
- (void) wait(&status);
- gettty();
- setftty();
- (void) signal(SIGINT,done1);
-#ifdef WIZARD
- if(wizard) (void) signal(SIGQUIT,SIG_DFL);
-#endif WIZARD
- if(wt) getret();
- docrt();
- return(0);
-}
-#endif UNIX
diff --git a/games/hack/hack.potion.c b/games/hack/hack.potion.c
deleted file mode 100644
index c860299eb5bb..000000000000
--- a/games/hack/hack.potion.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.potion.c - version 1.0.3 */
-
-#include "hack.h"
-extern int float_down();
-extern char *nomovemsg;
-extern struct monst youmonst;
-extern struct monst *makemon();
-
-dodrink() {
- register struct obj *otmp,*objs;
- register struct monst *mtmp;
- register int unkn = 0, nothing = 0;
-
- otmp = getobj("!", "drink");
- if(!otmp) return(0);
- if(!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
- ghost_from_bottle();
- goto use_it;
- }
- switch(otmp->otyp){
- case POT_RESTORE_STRENGTH:
- unkn++;
- pline("Wow! This makes you feel great!");
- if(u.ustr < u.ustrmax) {
- u.ustr = u.ustrmax;
- flags.botl = 1;
- }
- break;
- case POT_BOOZE:
- unkn++;
- pline("Ooph! This tastes like liquid fire!");
- Confusion += d(3,8);
- /* the whiskey makes us feel better */
- if(u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey");
- if(!rn2(4)) {
- pline("You pass out.");
- multi = -rnd(15);
- nomovemsg = "You awake with a headache.";
- }
- break;
- case POT_INVISIBILITY:
- if(Invis || See_invisible)
- nothing++;
- else {
- if(!Blind)
- pline("Gee! All of a sudden, you can't see yourself.");
- else
- pline("You feel rather airy."), unkn++;
- newsym(u.ux,u.uy);
- }
- Invis += rn1(15,31);
- break;
- case POT_FRUIT_JUICE:
- pline("This tastes like fruit juice.");
- lesshungry(20);
- break;
- case POT_HEALING:
- pline("You begin to feel better.");
- flags.botl = 1;
- u.uhp += rnd(10);
- if(u.uhp > u.uhpmax)
- u.uhp = ++u.uhpmax;
- if(Blind) Blind = 1; /* see on next move */
- if(Sick) Sick = 0;
- break;
- case POT_PARALYSIS:
- if(Levitation)
- pline("You are motionlessly suspended.");
- else
- pline("Your feet are frozen to the floor!");
- nomul(-(rn1(10,25)));
- break;
- case POT_MONSTER_DETECTION:
- if(!fmon) {
- strange_feeling(otmp, "You feel threatened.");
- return(1);
- } else {
- cls();
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->mx > 0)
- at(mtmp->mx,mtmp->my,mtmp->data->mlet);
- prme();
- pline("You sense the presence of monsters.");
- more();
- docrt();
- }
- break;
- case POT_OBJECT_DETECTION:
- if(!fobj) {
- strange_feeling(otmp, "You feel a pull downward.");
- return(1);
- } else {
- for(objs = fobj; objs; objs = objs->nobj)
- if(objs->ox != u.ux || objs->oy != u.uy)
- goto outobjmap;
- pline("You sense the presence of objects close nearby.");
- break;
- outobjmap:
- cls();
- for(objs = fobj; objs; objs = objs->nobj)
- at(objs->ox,objs->oy,objs->olet);
- prme();
- pline("You sense the presence of objects.");
- more();
- docrt();
- }
- break;
- case POT_SICKNESS:
- pline("Yech! This stuff tastes like poison.");
- if(Poison_resistance)
- pline("(But in fact it was biologically contaminated orange juice.)");
- losestr(rn1(4,3));
- losehp(rnd(10), "contaminated potion");
- break;
- case POT_CONFUSION:
- if(!Confusion)
- pline("Huh, What? Where am I?");
- else
- nothing++;
- Confusion += rn1(7,16);
- break;
- case POT_GAIN_STRENGTH:
- pline("Wow do you feel strong!");
- if(u.ustr >= 118) break; /* > 118 is impossible */
- if(u.ustr > 17) u.ustr += rnd(118-u.ustr);
- else u.ustr++;
- if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
- flags.botl = 1;
- break;
- case POT_SPEED:
- if(Wounded_legs) {
- heal_legs();
- unkn++;
- break;
- }
- if(!(Fast & ~INTRINSIC))
- pline("You are suddenly moving much faster.");
- else
- pline("Your legs get new energy."), unkn++;
- Fast += rn1(10,100);
- break;
- case POT_BLINDNESS:
- if(!Blind)
- pline("A cloud of darkness falls upon you.");
- else
- nothing++;
- Blind += rn1(100,250);
- seeoff(0);
- break;
- case POT_GAIN_LEVEL:
- pluslvl();
- break;
- case POT_EXTRA_HEALING:
- pline("You feel much better.");
- flags.botl = 1;
- u.uhp += d(2,20)+1;
- if(u.uhp > u.uhpmax)
- u.uhp = (u.uhpmax += 2);
- if(Blind) Blind = 1;
- if(Sick) Sick = 0;
- break;
- case POT_LEVITATION:
- if(!Levitation)
- float_up();
- else
- nothing++;
- Levitation += rnd(100);
- u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
- break;
- default:
- impossible("What a funny potion! (%u)", otmp->otyp);
- return(0);
- }
- if(nothing) {
- unkn++;
- pline("You have a peculiar feeling for a moment, then it passes.");
- }
- if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
- if(!unkn) {
- objects[otmp->otyp].oc_name_known = 1;
- more_experienced(0,10);
- } else if(!objects[otmp->otyp].oc_uname)
- docall(otmp);
- }
-use_it:
- useup(otmp);
- return(1);
-}
-
-pluslvl()
-{
- register num;
-
- pline("You feel more experienced.");
- num = rnd(10);
- u.uhpmax += num;
- u.uhp += num;
- if(u.ulevel < 14) {
- extern long newuexp();
-
- u.uexp = newuexp()+1;
- pline("Welcome to experience level %u.", ++u.ulevel);
- }
- flags.botl = 1;
-}
-
-strange_feeling(obj,txt)
-register struct obj *obj;
-register char *txt;
-{
- if(flags.beginner)
- pline("You have a strange feeling for a moment, then it passes.");
- else
- pline(txt);
- if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
- docall(obj);
- useup(obj);
-}
-
-char *bottlenames[] = {
- "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
-};
-
-potionhit(mon, obj)
-register struct monst *mon;
-register struct obj *obj;
-{
- extern char *xname();
- register char *botlnam = bottlenames[rn2(SIZE(bottlenames))];
- boolean uclose, isyou = (mon == &youmonst);
-
- if(isyou) {
- uclose = TRUE;
- pline("The %s crashes on your head and breaks into shivers.",
- botlnam);
- losehp(rnd(2), "thrown potion");
- } else {
- uclose = (dist(mon->mx,mon->my) < 3);
- /* perhaps 'E' and 'a' have no head? */
- pline("The %s crashes on %s's head and breaks into shivers.",
- botlnam, monnam(mon));
- if(rn2(5) && mon->mhp > 1)
- mon->mhp--;
- }
- pline("The %s evaporates.", xname(obj));
-
- if(!isyou && !rn2(3)) switch(obj->otyp) {
-
- case POT_RESTORE_STRENGTH:
- case POT_GAIN_STRENGTH:
- case POT_HEALING:
- case POT_EXTRA_HEALING:
- if(mon->mhp < mon->mhpmax) {
- mon->mhp = mon->mhpmax;
- pline("%s looks sound and hale again!", Monnam(mon));
- }
- break;
- case POT_SICKNESS:
- if(mon->mhpmax > 3)
- mon->mhpmax /= 2;
- if(mon->mhp > 2)
- mon->mhp /= 2;
- break;
- case POT_CONFUSION:
- case POT_BOOZE:
- mon->mconf = 1;
- break;
- case POT_INVISIBILITY:
- unpmon(mon);
- mon->minvis = 1;
- pmon(mon);
- break;
- case POT_PARALYSIS:
- mon->mfroz = 1;
- break;
- case POT_SPEED:
- mon->mspeed = MFAST;
- break;
- case POT_BLINDNESS:
- mon->mblinded |= 64 + rn2(64);
- break;
-/*
- case POT_GAIN_LEVEL:
- case POT_LEVITATION:
- case POT_FRUIT_JUICE:
- case POT_MONSTER_DETECTION:
- case POT_OBJECT_DETECTION:
- break;
-*/
- }
- if(uclose && rn2(5))
- potionbreathe(obj);
- obfree(obj, Null(obj));
-}
-
-potionbreathe(obj)
-register struct obj *obj;
-{
- switch(obj->otyp) {
- case POT_RESTORE_STRENGTH:
- case POT_GAIN_STRENGTH:
- if(u.ustr < u.ustrmax) u.ustr++, flags.botl = 1;
- break;
- case POT_HEALING:
- case POT_EXTRA_HEALING:
- if(u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
- break;
- case POT_SICKNESS:
- if(u.uhp <= 5) u.uhp = 1; else u.uhp -= 5;
- flags.botl = 1;
- break;
- case POT_CONFUSION:
- case POT_BOOZE:
- if(!Confusion)
- pline("You feel somewhat dizzy.");
- Confusion += rnd(5);
- break;
- case POT_INVISIBILITY:
- pline("For an instant you couldn't see your right hand.");
- break;
- case POT_PARALYSIS:
- pline("Something seems to be holding you.");
- nomul(-rnd(5));
- break;
- case POT_SPEED:
- Fast += rnd(5);
- pline("Your knees seem more flexible now.");
- break;
- case POT_BLINDNESS:
- if(!Blind) pline("It suddenly gets dark.");
- Blind += rnd(5);
- seeoff(0);
- break;
-/*
- case POT_GAIN_LEVEL:
- case POT_LEVITATION:
- case POT_FRUIT_JUICE:
- case POT_MONSTER_DETECTION:
- case POT_OBJECT_DETECTION:
- break;
-*/
- }
- /* note: no obfree() */
-}
-
-/*
- * -- rudimentary -- to do this correctly requires much more work
- * -- all sharp weapons get one or more qualities derived from the potions
- * -- texts on scrolls may be (partially) wiped out; do they become blank?
- * -- or does their effect change, like under Confusion?
- * -- all objects may be made invisible by POT_INVISIBILITY
- * -- If the flask is small, can one dip a large object? Does it magically
- * -- become a jug? Etc.
- */
-dodip(){
- register struct obj *potion, *obj;
-
- if(!(obj = getobj("#", "dip")))
- return(0);
- if(!(potion = getobj("!", "dip into")))
- return(0);
- pline("Interesting...");
- if(obj->otyp == ARROW || obj->otyp == DART ||
- obj->otyp == CROSSBOW_BOLT) {
- if(potion->otyp == POT_SICKNESS) {
- useup(potion);
- if(obj->spe < 7) obj->spe++; /* %% */
- }
- }
- return(1);
-}
-
-ghost_from_bottle(){
- extern struct permonst pm_ghost;
- register struct monst *mtmp;
-
- if(!(mtmp = makemon(PM_GHOST,u.ux,u.uy))){
- pline("This bottle turns out to be empty.");
- return;
- }
- mnexto(mtmp);
- pline("As you open the bottle, an enormous ghost emerges!");
- pline("You are frightened to death, and unable to move.");
- nomul(-3);
-}
diff --git a/games/hack/hack.pri.c b/games/hack/hack.pri.c
deleted file mode 100644
index 13ee6b7d0b15..000000000000
--- a/games/hack/hack.pri.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.pri.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-xchar scrlx, scrhx, scrly, scrhy; /* corners of new area on screen */
-
-extern char *hu_stat[]; /* in eat.c */
-extern char *CD;
-
-swallowed()
-{
- char *ulook = "|@|";
- ulook[1] = u.usym;
-
- cls();
- curs(u.ux-1, u.uy+1);
- fputs("/-\\", stdout);
- curx = u.ux+2;
- curs(u.ux-1, u.uy+2);
- fputs(ulook, stdout);
- curx = u.ux+2;
- curs(u.ux-1, u.uy+3);
- fputs("\\-/", stdout);
- curx = u.ux+2;
- u.udispl = 1;
- u.udisx = u.ux;
- u.udisy = u.uy;
-}
-
-
-/*VARARGS1*/
-boolean panicking;
-
-panic(str,a1,a2,a3,a4,a5,a6)
-char *str;
-{
- if(panicking++) exit(1); /* avoid loops - this should never happen*/
- home();
- puts(" Suddenly, the dungeon collapses.");
- fputs(" ERROR: ", stdout);
- printf(str,a1,a2,a3,a4,a5,a6);
-#ifdef DEBUG
-#ifdef UNIX
- if(!fork())
- abort(); /* generate core dump */
-#endif UNIX
-#endif DEBUG
- more(); /* contains a fflush() */
- done("panicked");
-}
-
-atl(x,y,ch)
-register x,y;
-{
- register struct rm *crm = &levl[x][y];
-
- if(x<0 || x>COLNO-1 || y<0 || y>ROWNO-1){
- impossible("atl(%d,%d,%c)",x,y,ch);
- return;
- }
- if(crm->seen && crm->scrsym == ch) return;
- crm->scrsym = ch;
- crm->new = 1;
- on_scr(x,y);
-}
-
-on_scr(x,y)
-register x,y;
-{
- if(x < scrlx) scrlx = x;
- if(x > scrhx) scrhx = x;
- if(y < scrly) scrly = y;
- if(y > scrhy) scrhy = y;
-}
-
-/* call: (x,y) - display
- (-1,0) - close (leave last symbol)
- (-1,-1)- close (undo last symbol)
- (-1,let)-open: initialize symbol
- (-2,let)-change let
-*/
-
-tmp_at(x,y) schar x,y; {
-static schar prevx, prevy;
-static char let;
- if((int)x == -2){ /* change let call */
- let = y;
- return;
- }
- if((int)x == -1 && (int)y >= 0){ /* open or close call */
- let = y;
- prevx = -1;
- return;
- }
- if(prevx >= 0 && cansee(prevx,prevy)) {
- delay_output();
- prl(prevx, prevy); /* in case there was a monster */
- at(prevx, prevy, levl[prevx][prevy].scrsym);
- }
- if(x >= 0){ /* normal call */
- if(cansee(x,y)) at(x,y,let);
- prevx = x;
- prevy = y;
- } else { /* close call */
- let = 0;
- prevx = -1;
- }
-}
-
-/* like the previous, but the symbols are first erased on completion */
-Tmp_at(x,y) schar x,y; {
-static char let;
-static xchar cnt;
-static coord tc[COLNO]; /* but watch reflecting beams! */
-register xx,yy;
- if((int)x == -1) {
- if(y > 0) { /* open call */
- let = y;
- cnt = 0;
- return;
- }
- /* close call (do not distinguish y==0 and y==-1) */
- while(cnt--) {
- xx = tc[cnt].x;
- yy = tc[cnt].y;
- prl(xx, yy);
- at(xx, yy, levl[xx][yy].scrsym);
- }
- cnt = let = 0; /* superfluous */
- return;
- }
- if((int)x == -2) { /* change let call */
- let = y;
- return;
- }
- /* normal call */
- if(cansee(x,y)) {
- if(cnt) delay_output();
- at(x,y,let);
- tc[cnt].x = x;
- tc[cnt].y = y;
- if(++cnt >= COLNO) panic("Tmp_at overflow?");
- levl[x][y].new = 0; /* prevent pline-nscr erasing --- */
- }
-}
-
-setclipped(){
- error("Hack needs a screen of size at least %d by %d.\n",
- ROWNO+2, COLNO);
-}
-
-at(x,y,ch)
-register xchar x,y;
-char ch;
-{
-#ifndef lint
- /* if xchar is unsigned, lint will complain about if(x < 0) */
- if(x < 0 || x > COLNO-1 || y < 0 || y > ROWNO-1) {
- impossible("At gets 0%o at %d %d.", ch, x, y);
- return;
- }
-#endif lint
- if(!ch) {
- impossible("At gets null at %d %d.", x, y);
- return;
- }
- y += 2;
- curs(x,y);
- (void) putchar(ch);
- curx++;
-}
-
-prme(){
- if(!Invisible) at(u.ux,u.uy,u.usym);
-}
-
-doredraw()
-{
- docrt();
- return(0);
-}
-
-docrt()
-{
- register x,y;
- register struct rm *room;
- register struct monst *mtmp;
-
- if(u.uswallow) {
- swallowed();
- return;
- }
- cls();
-
-/* Some ridiculous code to get display of @ and monsters (almost) right */
- if(!Invisible) {
- levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym;
- levl[u.udisx][u.udisy].seen = 1;
- u.udispl = 1;
- } else u.udispl = 0;
-
- seemons(); /* reset old positions */
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- mtmp->mdispl = 0;
- seemons(); /* force new positions to be shown */
-/* This nonsense should disappear soon --------------------------------- */
-
- for(y = 0; y < ROWNO; y++)
- for(x = 0; x < COLNO; x++)
- if((room = &levl[x][y])->new) {
- room->new = 0;
- at(x,y,room->scrsym);
- } else if(room->seen)
- at(x,y,room->scrsym);
- scrlx = COLNO;
- scrly = ROWNO;
- scrhx = scrhy = 0;
- flags.botlx = 1;
- bot();
-}
-
-docorner(xmin,ymax) register xmin,ymax; {
- register x,y;
- register struct rm *room;
- register struct monst *mtmp;
-
- if(u.uswallow) { /* Can be done more efficiently */
- swallowed();
- return;
- }
-
- seemons(); /* reset old positions */
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->mx >= xmin && mtmp->my < ymax)
- mtmp->mdispl = 0;
- seemons(); /* force new positions to be shown */
-
- for(y = 0; y < ymax; y++) {
- if(y > ROWNO && CD) break;
- curs(xmin,y+2);
- cl_end();
- if(y < ROWNO) {
- for(x = xmin; x < COLNO; x++) {
- if((room = &levl[x][y])->new) {
- room->new = 0;
- at(x,y,room->scrsym);
- } else
- if(room->seen)
- at(x,y,room->scrsym);
- }
- }
- }
- if(ymax > ROWNO) {
- cornbot(xmin-1);
- if(ymax > ROWNO+1 && CD) {
- curs(1,ROWNO+3);
- cl_eos();
- }
- }
-}
-
-curs_on_u(){
- curs(u.ux, u.uy+2);
-}
-
-pru()
-{
- if(u.udispl && (Invisible || u.udisx != u.ux || u.udisy != u.uy))
- /* if(! levl[u.udisx][u.udisy].new) */
- if(!vism_at(u.udisx, u.udisy))
- newsym(u.udisx, u.udisy);
- if(Invisible) {
- u.udispl = 0;
- prl(u.ux,u.uy);
- } else
- if(!u.udispl || u.udisx != u.ux || u.udisy != u.uy) {
- atl(u.ux, u.uy, u.usym);
- u.udispl = 1;
- u.udisx = u.ux;
- u.udisy = u.uy;
- }
- levl[u.ux][u.uy].seen = 1;
-}
-
-#ifndef NOWORM
-#include "def.wseg.h"
-extern struct wseg *m_atseg;
-#endif NOWORM
-
-/* print a position that is visible for @ */
-prl(x,y)
-{
- register struct rm *room;
- register struct monst *mtmp;
- register struct obj *otmp;
-
- if(x == u.ux && y == u.uy && (!Invisible)) {
- pru();
- return;
- }
- if(!isok(x,y)) return;
- room = &levl[x][y];
- if((!room->typ) ||
- (IS_ROCK(room->typ) && levl[u.ux][u.uy].typ == CORR))
- return;
- if((mtmp = m_at(x,y)) && !mtmp->mhide &&
- (!mtmp->minvis || See_invisible)) {
-#ifndef NOWORM
- if(m_atseg)
- pwseg(m_atseg);
- else
-#endif NOWORM
- pmon(mtmp);
- }
- else if((otmp = o_at(x,y)) && room->typ != POOL)
- atl(x,y,otmp->olet);
- else if(mtmp && (!mtmp->minvis || See_invisible)) {
- /* must be a hiding monster, but not hiding right now */
- /* assume for the moment that long worms do not hide */
- pmon(mtmp);
- }
- else if(g_at(x,y) && room->typ != POOL)
- atl(x,y,'$');
- else if(!room->seen || room->scrsym == ' ') {
- room->new = room->seen = 1;
- newsym(x,y);
- on_scr(x,y);
- }
- room->seen = 1;
-}
-
-char
-news0(x,y)
-register xchar x,y;
-{
- register struct obj *otmp;
- register struct trap *ttmp;
- struct rm *room;
- register char tmp;
-
- room = &levl[x][y];
- if(!room->seen) tmp = ' ';
- else if(room->typ == POOL) tmp = POOL_SYM;
- else if(!Blind && (otmp = o_at(x,y))) tmp = otmp->olet;
- else if(!Blind && g_at(x,y)) tmp = '$';
- else if(x == xupstair && y == yupstair) tmp = '<';
- else if(x == xdnstair && y == ydnstair) tmp = '>';
- else if((ttmp = t_at(x,y)) && ttmp->tseen) tmp = '^';
- else switch(room->typ) {
- case SCORR:
- case SDOOR:
- tmp = room->scrsym; /* %% wrong after killing mimic ! */
- break;
- case HWALL:
- tmp = '-';
- break;
- case VWALL:
- tmp = '|';
- break;
- case LDOOR:
- case DOOR:
- tmp = '+';
- break;
- case CORR:
- tmp = CORR_SYM;
- break;
- case ROOM:
- if(room->lit || cansee(x,y) || Blind) tmp = '.';
- else tmp = ' ';
- break;
-/*
- case POOL:
- tmp = POOL_SYM;
- break;
-*/
- default:
- tmp = ERRCHAR;
- }
- return(tmp);
-}
-
-newsym(x,y)
-register x,y;
-{
- atl(x,y,news0(x,y));
-}
-
-/* used with wand of digging (or pick-axe): fill scrsym and force display */
-/* also when a POOL evaporates */
-mnewsym(x,y)
-register x,y;
-{
- register struct rm *room;
- char newscrsym;
-
- if(!vism_at(x,y)) {
- room = &levl[x][y];
- newscrsym = news0(x,y);
- if(room->scrsym != newscrsym) {
- room->scrsym = newscrsym;
- room->seen = 0;
- }
- }
-}
-
-nosee(x,y)
-register x,y;
-{
- register struct rm *room;
-
- if(!isok(x,y)) return;
- room = &levl[x][y];
- if(room->scrsym == '.' && !room->lit && !Blind) {
- room->scrsym = ' ';
- room->new = 1;
- on_scr(x,y);
- }
-}
-
-#ifndef QUEST
-prl1(x,y)
-register x,y;
-{
- if(u.dx) {
- if(u.dy) {
- prl(x-(2*u.dx),y);
- prl(x-u.dx,y);
- prl(x,y);
- prl(x,y-u.dy);
- prl(x,y-(2*u.dy));
- } else {
- prl(x,y-1);
- prl(x,y);
- prl(x,y+1);
- }
- } else {
- prl(x-1,y);
- prl(x,y);
- prl(x+1,y);
- }
-}
-
-nose1(x,y)
-register x,y;
-{
- if(u.dx) {
- if(u.dy) {
- nosee(x,u.uy);
- nosee(x,u.uy-u.dy);
- nosee(x,y);
- nosee(u.ux-u.dx,y);
- nosee(u.ux,y);
- } else {
- nosee(x,y-1);
- nosee(x,y);
- nosee(x,y+1);
- }
- } else {
- nosee(x-1,y);
- nosee(x,y);
- nosee(x+1,y);
- }
-}
-#endif QUEST
-
-vism_at(x,y)
-register x,y;
-{
- register struct monst *mtmp;
-
- return((x == u.ux && y == u.uy && !Invisible)
- ? 1 :
- (mtmp = m_at(x,y))
- ? ((Blind && Telepat) || canseemon(mtmp)) :
- 0);
-}
-
-#ifdef NEWSCR
-pobj(obj) register struct obj *obj; {
-register int show = (!obj->oinvis || See_invisible) &&
- cansee(obj->ox,obj->oy);
- if(obj->odispl){
- if(obj->odx != obj->ox || obj->ody != obj->oy || !show)
- if(!vism_at(obj->odx,obj->ody)){
- newsym(obj->odx, obj->ody);
- obj->odispl = 0;
- }
- }
- if(show && !vism_at(obj->ox,obj->oy)){
- atl(obj->ox,obj->oy,obj->olet);
- obj->odispl = 1;
- obj->odx = obj->ox;
- obj->ody = obj->oy;
- }
-}
-#endif NEWSCR
-
-unpobj(obj) register struct obj *obj; {
-/* if(obj->odispl){
- if(!vism_at(obj->odx, obj->ody))
- newsym(obj->odx, obj->ody);
- obj->odispl = 0;
- }
-*/
- if(!vism_at(obj->ox,obj->oy))
- newsym(obj->ox,obj->oy);
-}
-
-seeobjs(){
-register struct obj *obj, *obj2;
- for(obj = fobj; obj; obj = obj2) {
- obj2 = obj->nobj;
- if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
- && obj->age + 250 < moves)
- delobj(obj);
- }
- for(obj = invent; obj; obj = obj2) {
- obj2 = obj->nobj;
- if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
- && obj->age + 250 < moves)
- useup(obj);
- }
-}
-
-seemons(){
-register struct monst *mtmp;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
- if(mtmp->data->mlet == ';')
- mtmp->minvis = (u.ustuck != mtmp &&
- levl[mtmp->mx][mtmp->my].typ == POOL);
- pmon(mtmp);
-#ifndef NOWORM
- if(mtmp->wormno) wormsee(mtmp->wormno);
-#endif NOWORM
- }
-}
-
-pmon(mon) register struct monst *mon; {
-register int show = (Blind && Telepat) || canseemon(mon);
- if(mon->mdispl){
- if(mon->mdx != mon->mx || mon->mdy != mon->my || !show)
- unpmon(mon);
- }
- if(show && !mon->mdispl){
- atl(mon->mx,mon->my,
- (!mon->mappearance
- || u.uprops[PROP(RIN_PROTECTION_FROM_SHAPE_CHANGERS)].p_flgs
- ) ? mon->data->mlet : mon->mappearance);
- mon->mdispl = 1;
- mon->mdx = mon->mx;
- mon->mdy = mon->my;
- }
-}
-
-unpmon(mon) register struct monst *mon; {
- if(mon->mdispl){
- newsym(mon->mdx, mon->mdy);
- mon->mdispl = 0;
- }
-}
-
-nscr()
-{
- register x,y;
- register struct rm *room;
-
- if(u.uswallow || u.ux == FAR || flags.nscrinh) return;
- pru();
- for(y = scrly; y <= scrhy; y++)
- for(x = scrlx; x <= scrhx; x++)
- if((room = &levl[x][y])->new) {
- room->new = 0;
- at(x,y,room->scrsym);
- }
- scrhx = scrhy = 0;
- scrlx = COLNO;
- scrly = ROWNO;
-}
-
-/* 100 suffices for bot(); no relation with COLNO */
-char oldbot[100], newbot[100];
-cornbot(lth)
-register int lth;
-{
- if(lth < sizeof(oldbot)) {
- oldbot[lth] = 0;
- flags.botl = 1;
- }
-}
-
-bot()
-{
-register char *ob = oldbot, *nb = newbot;
-register int i;
-extern char *eos();
- if(flags.botlx) *ob = 0;
- flags.botl = flags.botlx = 0;
-#ifdef GOLD_ON_BOTL
- (void) sprintf(newbot,
- "Level %-2d Gold %-5lu Hp %3d(%d) Ac %-2d Str ",
- dlevel, u.ugold, u.uhp, u.uhpmax, u.uac);
-#else
- (void) sprintf(newbot,
- "Level %-2d Hp %3d(%d) Ac %-2d Str ",
- dlevel, u.uhp, u.uhpmax, u.uac);
-#endif GOLD_ON_BOTL
- if(u.ustr>18) {
- if(u.ustr>117)
- (void) strcat(newbot,"18/**");
- else
- (void) sprintf(eos(newbot), "18/%02d",u.ustr-18);
- } else
- (void) sprintf(eos(newbot), "%-2d ",u.ustr);
-#ifdef EXP_ON_BOTL
- (void) sprintf(eos(newbot), " Exp %2d/%-5lu ", u.ulevel,u.uexp);
-#else
- (void) sprintf(eos(newbot), " Exp %2u ", u.ulevel);
-#endif EXP_ON_BOTL
- (void) strcat(newbot, hu_stat[u.uhs]);
- if(flags.time)
- (void) sprintf(eos(newbot), " %ld", moves);
- if(strlen(newbot) >= COLNO) {
- register char *bp0, *bp1;
- bp0 = bp1 = newbot;
- do {
- if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
- *bp1++ = *bp0;
- } while(*bp0++);
- }
- for(i = 1; i<COLNO; i++) {
- if(*ob != *nb){
- curs(i,ROWNO+2);
- (void) putchar(*nb ? *nb : ' ');
- curx++;
- }
- if(*ob) ob++;
- if(*nb) nb++;
- }
- (void) strcpy(oldbot, newbot);
-}
-
-#ifdef WAN_PROBING
-mstatusline(mtmp) register struct monst *mtmp; {
- pline("Status of %s: ", monnam(mtmp));
- pline("Level %-2d Gold %-5lu Hp %3d(%d) Ac %-2d Dam %d",
- mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->mhpmax,
- mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1));
-}
-#endif WAN_PROBING
-
-cls(){
- if(flags.toplin == 1)
- more();
- flags.toplin = 0;
-
- clear_screen();
-
- flags.botlx = 1;
-}
diff --git a/games/hack/hack.read.c b/games/hack/hack.read.c
deleted file mode 100644
index 5c0de3a7a0c1..000000000000
--- a/games/hack/hack.read.c
+++ /dev/null
@@ -1,539 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.read.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern struct monst *makemon();
-extern struct obj *mkobj_at();
-int identify();
-
-doread() {
- register struct obj *scroll;
- register boolean confused = (Confusion != 0);
- register boolean known = FALSE;
- extern struct obj *some_armor();
-
- scroll = getobj("?", "read");
- if(!scroll) return(0);
- if(!scroll->dknown && Blind) {
- pline("Being blind, you cannot read the formula on the scroll.");
- return(0);
- }
- if(Blind)
- pline("As you pronounce the formula on it, the scroll disappears.");
- else
- pline("As you read the scroll, it disappears.");
- if(confused)
- pline("Being confused, you mispronounce the magic words ... ");
-
- switch(scroll->otyp) {
-#ifdef MAIL
- case SCR_MAIL:
- readmail(/* scroll */);
- break;
-#endif MAIL
- case SCR_ENCHANT_ARMOR:
- { register struct obj *otmp = some_armor();
- if(!otmp) {
- strange_feeling(scroll,"Your skin glows then fades.");
- return(1);
- }
- if(confused) {
- pline("Your %s glows silver for a moment.",
- objects[otmp->otyp].oc_name);
- otmp->rustfree = 1;
- break;
- }
- if(otmp->spe > 3 && rn2(otmp->spe)) {
- pline("Your %s glows violently green for a while, then evaporates.",
- objects[otmp->otyp].oc_name);
- useup(otmp);
- break;
- }
- pline("Your %s glows green for a moment.",
- objects[otmp->otyp].oc_name);
- otmp->cursed = 0;
- otmp->spe++;
- break;
- }
- case SCR_DESTROY_ARMOR:
- if(confused) {
- register struct obj *otmp = some_armor();
- if(!otmp) {
- strange_feeling(scroll,"Your bones itch.");
- return(1);
- }
- pline("Your %s glows purple for a moment.",
- objects[otmp->otyp].oc_name);
- otmp->rustfree = 0;
- break;
- }
- if(uarm) {
- pline("Your armor turns to dust and falls to the floor!");
- useup(uarm);
- } else if(uarmh) {
- pline("Your helmet turns to dust and is blown away!");
- useup(uarmh);
- } else if(uarmg) {
- pline("Your gloves vanish!");
- useup(uarmg);
- selftouch("You");
- } else {
- strange_feeling(scroll,"Your skin itches.");
- return(1);
- }
- break;
- case SCR_CONFUSE_MONSTER:
- if(confused) {
- pline("Your hands begin to glow purple.");
- Confusion += rnd(100);
- } else {
- pline("Your hands begin to glow blue.");
- u.umconf = 1;
- }
- break;
- case SCR_SCARE_MONSTER:
- { register int ct = 0;
- register struct monst *mtmp;
-
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(cansee(mtmp->mx,mtmp->my)) {
- if(confused)
- mtmp->mflee = mtmp->mfroz =
- mtmp->msleep = 0;
- else
- mtmp->mflee = 1;
- ct++;
- }
- if(!ct) {
- if(confused)
- pline("You hear sad wailing in the distance.");
- else
- pline("You hear maniacal laughter in the distance.");
- }
- break;
- }
- case SCR_BLANK_PAPER:
- if(confused)
- pline("You see strange patterns on this scroll.");
- else
- pline("This scroll seems to be blank.");
- break;
- case SCR_REMOVE_CURSE:
- { register struct obj *obj;
- if(confused)
- pline("You feel like you need some help.");
- else
- pline("You feel like someone is helping you.");
- for(obj = invent; obj ; obj = obj->nobj)
- if(obj->owornmask)
- obj->cursed = confused;
- if(Punished && !confused) {
- Punished = 0;
- freeobj(uchain);
- unpobj(uchain);
- free((char *) uchain);
- uball->spe = 0;
- uball->owornmask &= ~W_BALL;
- uchain = uball = (struct obj *) 0;
- }
- break;
- }
- case SCR_CREATE_MONSTER:
- { register int cnt = 1;
-
- if(!rn2(73)) cnt += rnd(4);
- if(confused) cnt += 12;
- while(cnt--)
- (void) makemon(confused ? PM_ACID_BLOB :
- (struct permonst *) 0, u.ux, u.uy);
- break;
- }
- case SCR_ENCHANT_WEAPON:
- if(uwep && confused) {
- pline("Your %s glows silver for a moment.",
- objects[uwep->otyp].oc_name);
- uwep->rustfree = 1;
- } else
- if(!chwepon(scroll, 1)) /* tests for !uwep */
- return(1);
- break;
- case SCR_DAMAGE_WEAPON:
- if(uwep && confused) {
- pline("Your %s glows purple for a moment.",
- objects[uwep->otyp].oc_name);
- uwep->rustfree = 0;
- } else
- if(!chwepon(scroll, -1)) /* tests for !uwep */
- return(1);
- break;
- case SCR_TAMING:
- { register int i,j;
- register int bd = confused ? 5 : 1;
- register struct monst *mtmp;
-
- for(i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++)
- if(mtmp = m_at(u.ux+i, u.uy+j))
- (void) tamedog(mtmp, (struct obj *) 0);
- break;
- }
- case SCR_GENOCIDE:
- { extern char genocided[], fut_geno[];
- char buf[BUFSZ];
- register struct monst *mtmp, *mtmp2;
-
- pline("You have found a scroll of genocide!");
- known = TRUE;
- if(confused)
- *buf = u.usym;
- else do {
- pline("What monster do you want to genocide (Type the letter)? ");
- getlin(buf);
- } while(strlen(buf) != 1 || !monstersym(*buf));
- if(!index(fut_geno, *buf))
- charcat(fut_geno, *buf);
- if(!index(genocided, *buf))
- charcat(genocided, *buf);
- else {
- pline("Such monsters do not exist in this world.");
- break;
- }
- for(mtmp = fmon; mtmp; mtmp = mtmp2){
- mtmp2 = mtmp->nmon;
- if(mtmp->data->mlet == *buf)
- mondead(mtmp);
- }
- pline("Wiped out all %c's.", *buf);
- if(*buf == u.usym) {
- killer = "scroll of genocide";
- u.uhp = -1;
- }
- break;
- }
- case SCR_LIGHT:
- if(!Blind) known = TRUE;
- litroom(!confused);
- break;
- case SCR_TELEPORTATION:
- if(confused)
- level_tele();
- else {
-#ifdef QUEST
- register int oux = u.ux, ouy = u.uy;
- tele();
- if(dist(oux, ouy) > 100) known = TRUE;
-#else QUEST
- register int uroom = inroom(u.ux, u.uy);
- tele();
- if(uroom != inroom(u.ux, u.uy)) known = TRUE;
-#endif QUEST
- }
- break;
- case SCR_GOLD_DETECTION:
- /* Unfortunately this code has become slightly less elegant,
- now that gold and traps no longer are of the same type. */
- if(confused) {
- register struct trap *ttmp;
-
- if(!ftrap) {
- strange_feeling(scroll, "Your toes stop itching.");
- return(1);
- } else {
- for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
- if(ttmp->tx != u.ux || ttmp->ty != u.uy)
- goto outtrapmap;
- /* only under me - no separate display required */
- pline("Your toes itch!");
- break;
- outtrapmap:
- cls();
- for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
- at(ttmp->tx, ttmp->ty, '$');
- prme();
- pline("You feel very greedy!");
- }
- } else {
- register struct gold *gtmp;
-
- if(!fgold) {
- strange_feeling(scroll, "You feel materially poor.");
- return(1);
- } else {
- known = TRUE;
- for(gtmp = fgold; gtmp; gtmp = gtmp->ngold)
- if(gtmp->gx != u.ux || gtmp->gy != u.uy)
- goto outgoldmap;
- /* only under me - no separate display required */
- pline("You notice some gold between your feet.");
- break;
- outgoldmap:
- cls();
- for(gtmp = fgold; gtmp; gtmp = gtmp->ngold)
- at(gtmp->gx, gtmp->gy, '$');
- prme();
- pline("You feel very greedy, and sense gold!");
- }
- }
- /* common sequel */
- more();
- docrt();
- break;
- case SCR_FOOD_DETECTION:
- { register ct = 0, ctu = 0;
- register struct obj *obj;
- register char foodsym = confused ? POTION_SYM : FOOD_SYM;
-
- for(obj = fobj; obj; obj = obj->nobj)
- if(obj->olet == FOOD_SYM) {
- if(obj->ox == u.ux && obj->oy == u.uy) ctu++;
- else ct++;
- }
- if(!ct && !ctu) {
- strange_feeling(scroll,"Your nose twitches.");
- return(1);
- } else if(!ct) {
- known = TRUE;
- pline("You smell %s close nearby.",
- confused ? "something" : "food");
-
- } else {
- known = TRUE;
- cls();
- for(obj = fobj; obj; obj = obj->nobj)
- if(obj->olet == foodsym)
- at(obj->ox, obj->oy, FOOD_SYM);
- prme();
- pline("Your nose tingles and you smell %s!",
- confused ? "something" : "food");
- more();
- docrt();
- }
- break;
- }
- case SCR_IDENTIFY:
- /* known = TRUE; */
- if(confused)
- pline("You identify this as an identify scroll.");
- else
- pline("This is an identify scroll.");
- useup(scroll);
- objects[SCR_IDENTIFY].oc_name_known = 1;
- if(!confused)
- while(
- !ggetobj("identify", identify, rn2(5) ? 1 : rn2(5))
- && invent
- );
- return(1);
- case SCR_MAGIC_MAPPING:
- { register struct rm *lev;
- register int num, zx, zy;
-
- known = TRUE;
- pline("On this scroll %s a map!",
- confused ? "was" : "is");
- for(zy = 0; zy < ROWNO; zy++)
- for(zx = 0; zx < COLNO; zx++) {
- if(confused && rn2(7)) continue;
- lev = &(levl[zx][zy]);
- if((num = lev->typ) == 0)
- continue;
- if(num == SCORR) {
- lev->typ = CORR;
- lev->scrsym = CORR_SYM;
- } else
- if(num == SDOOR) {
- lev->typ = DOOR;
- lev->scrsym = '+';
- /* do sth in doors ? */
- } else if(lev->seen) continue;
-#ifndef QUEST
- if(num != ROOM)
-#endif QUEST
- {
- lev->seen = lev->new = 1;
- if(lev->scrsym == ' ' || !lev->scrsym)
- newsym(zx,zy);
- else
- on_scr(zx,zy);
- }
- }
- break;
- }
- case SCR_AMNESIA:
- { register int zx, zy;
-
- known = TRUE;
- for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
- if(!confused || rn2(7))
- if(!cansee(zx,zy))
- levl[zx][zy].seen = 0;
- docrt();
- pline("Thinking of Maud you forget everything else.");
- break;
- }
- case SCR_FIRE:
- { register int num;
- register struct monst *mtmp;
-
- known = TRUE;
- if(confused) {
- pline("The scroll catches fire and you burn your hands.");
- losehp(1, "scroll of fire");
- } else {
- pline("The scroll erupts in a tower of flame!");
- if(Fire_resistance)
- pline("You are uninjured.");
- else {
- num = rnd(6);
- u.uhpmax -= num;
- losehp(num, "scroll of fire");
- }
- }
- num = (2*num + 1)/3;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
- if(dist(mtmp->mx,mtmp->my) < 3) {
- mtmp->mhp -= num;
- if(index("FY", mtmp->data->mlet))
- mtmp->mhp -= 3*num; /* this might well kill 'F's */
- if(mtmp->mhp < 1) {
- killed(mtmp);
- break; /* primitive */
- }
- }
- }
- break;
- }
- case SCR_PUNISHMENT:
- known = TRUE;
- if(confused) {
- pline("You feel guilty.");
- break;
- }
- pline("You are being punished for your misbehaviour!");
- if(Punished){
- pline("Your iron ball gets heavier.");
- uball->owt += 15;
- break;
- }
- Punished = INTRINSIC;
- setworn(mkobj_at(CHAIN_SYM, u.ux, u.uy), W_CHAIN);
- setworn(mkobj_at(BALL_SYM, u.ux, u.uy), W_BALL);
- uball->spe = 1; /* special ball (see save) */
- break;
- default:
- impossible("What weird language is this written in? (%u)",
- scroll->otyp);
- }
- if(!objects[scroll->otyp].oc_name_known) {
- if(known && !confused) {
- objects[scroll->otyp].oc_name_known = 1;
- more_experienced(0,10);
- } else if(!objects[scroll->otyp].oc_uname)
- docall(scroll);
- }
- useup(scroll);
- return(1);
-}
-
-identify(otmp) /* also called by newmail() */
-register struct obj *otmp;
-{
- objects[otmp->otyp].oc_name_known = 1;
- otmp->known = otmp->dknown = 1;
- prinv(otmp);
- return(1);
-}
-
-litroom(on)
-register boolean on;
-{
- register num,zx,zy;
-
- /* first produce the text (provided he is not blind) */
- if(Blind) goto do_it;
- if(!on) {
- if(u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR ||
- !levl[u.ux][u.uy].lit) {
- pline("It seems even darker in here than before.");
- return;
- } else
- pline("It suddenly becomes dark in here.");
- } else {
- if(u.uswallow){
- pline("%s's stomach is lit.", Monnam(u.ustuck));
- return;
- }
- if(!xdnstair){
- pline("Nothing Happens.");
- return;
- }
-#ifdef QUEST
- pline("The cave lights up around you, then fades.");
- return;
-#else QUEST
- if(levl[u.ux][u.uy].typ == CORR) {
- pline("The corridor lights up around you, then fades.");
- return;
- } else if(levl[u.ux][u.uy].lit) {
- pline("The light here seems better now.");
- return;
- } else
- pline("The room is lit.");
-#endif QUEST
- }
-
-do_it:
-#ifdef QUEST
- return;
-#else QUEST
- if(levl[u.ux][u.uy].lit == on)
- return;
- if(levl[u.ux][u.uy].typ == DOOR) {
- if(IS_ROOM(levl[u.ux][u.uy+1].typ)) zy = u.uy+1;
- else if(IS_ROOM(levl[u.ux][u.uy-1].typ)) zy = u.uy-1;
- else zy = u.uy;
- if(IS_ROOM(levl[u.ux+1][u.uy].typ)) zx = u.ux+1;
- else if(IS_ROOM(levl[u.ux-1][u.uy].typ)) zx = u.ux-1;
- else zx = u.ux;
- } else {
- zx = u.ux;
- zy = u.uy;
- }
- for(seelx = u.ux; (num = levl[seelx-1][zy].typ) != CORR && num != 0;
- seelx--);
- for(seehx = u.ux; (num = levl[seehx+1][zy].typ) != CORR && num != 0;
- seehx++);
- for(seely = u.uy; (num = levl[zx][seely-1].typ) != CORR && num != 0;
- seely--);
- for(seehy = u.uy; (num = levl[zx][seehy+1].typ) != CORR && num != 0;
- seehy++);
- for(zy = seely; zy <= seehy; zy++)
- for(zx = seelx; zx <= seehx; zx++) {
- levl[zx][zy].lit = on;
- if(!Blind && dist(zx,zy) > 2)
- if(on) prl(zx,zy); else nosee(zx,zy);
- }
- if(!on) seehx = 0;
-#endif QUEST
-}
-
-/* Test whether we may genocide all monsters with symbol ch */
-monstersym(ch) /* arnold@ucsfcgl */
-register char ch;
-{
- register struct permonst *mp;
- extern struct permonst pm_eel;
-
- /*
- * can't genocide certain monsters
- */
- if (index("12 &:", ch))
- return FALSE;
-
- if (ch == pm_eel.mlet)
- return TRUE;
- for (mp = mons; mp < &mons[CMNUM+2]; mp++)
- if (mp->mlet == ch)
- return TRUE;
- return FALSE;
-}
diff --git a/games/hack/hack.rip.c b/games/hack/hack.rip.c
deleted file mode 100644
index bdc282308c7e..000000000000
--- a/games/hack/hack.rip.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.rip.c - version 1.0.2 */
-
-#include <stdio.h>
-#include "hack.h"
-
-extern char plname[];
-
-static char *rip[] = {
-" ----------",
-" / \\",
-" / REST \\",
-" / IN \\",
-" / PEACE \\",
-" / \\",
-" | |",
-" | |",
-" | |",
-" | |",
-" | |",
-" | 1001 |",
-" *| * * * | *",
-" _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n",
-0
-};
-
-outrip(){
- register char **dp = rip;
- register char *dpx;
- char buf[BUFSZ];
- register x,y;
-
- cls();
- (void) strcpy(buf, plname);
- buf[16] = 0;
- center(6, buf);
- (void) sprintf(buf, "%ld AU", u.ugold);
- center(7, buf);
- (void) sprintf(buf, "killed by%s",
- !strncmp(killer, "the ", 4) ? "" :
- !strcmp(killer, "starvation") ? "" :
- index(vowels, *killer) ? " an" : " a");
- center(8, buf);
- (void) strcpy(buf, killer);
- if(strlen(buf) > 16) {
- register int i,i0,i1;
- i0 = i1 = 0;
- for(i = 0; i <= 16; i++)
- if(buf[i] == ' ') i0 = i, i1 = i+1;
- if(!i0) i0 = i1 = 16;
- buf[i1 + 16] = 0;
- center(10, buf+i1);
- buf[i0] = 0;
- }
- center(9, buf);
- (void) sprintf(buf, "%4d", getyear());
- center(11, buf);
- for(y=8; *dp; y++,dp++){
- x = 0;
- dpx = *dp;
- while(dpx[x]) {
- while(dpx[x] == ' ') x++;
- curs(x,y);
- while(dpx[x] && dpx[x] != ' '){
- extern int done_stopprint;
- if(done_stopprint)
- return;
- curx++;
- (void) putchar(dpx[x++]);
- }
- }
- }
- getret();
-}
-
-center(line, text) int line; char *text; {
-register char *ip,*op;
- ip = text;
- op = &rip[line][28 - ((strlen(text)+1)/2)];
- while(*ip) *op++ = *ip++;
-}
diff --git a/games/hack/hack.rumors.c b/games/hack/hack.rumors.c
deleted file mode 100644
index ee5f139993ce..000000000000
--- a/games/hack/hack.rumors.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.rumors.c - version 1.0.3 */
-
-#include <stdio.h>
-#include "hack.h" /* for RUMORFILE and BSD (index) */
-#define CHARSZ 8 /* number of bits in a char */
-extern long *alloc();
-extern char *index();
-int n_rumors = 0;
-int n_used_rumors = -1;
-char *usedbits;
-
-init_rumors(rumf) register FILE *rumf; {
-register int i;
- n_used_rumors = 0;
- while(skipline(rumf)) n_rumors++;
- rewind(rumf);
- i = n_rumors/CHARSZ;
- usedbits = (char *) alloc((unsigned)(i+1));
- for( ; i>=0; i--) usedbits[i] = 0;
-}
-
-skipline(rumf) register FILE *rumf; {
-char line[COLNO];
- while(1) {
- if(!fgets(line, sizeof(line), rumf)) return(0);
- if(index(line, '\n')) return(1);
- }
-}
-
-outline(rumf) register FILE *rumf; {
-char line[COLNO];
-register char *ep;
- if(!fgets(line, sizeof(line), rumf)) return;
- if((ep = index(line, '\n')) != 0) *ep = 0;
- pline("This cookie has a scrap of paper inside! It reads: ");
- pline(line);
-}
-
-outrumor(){
-register int rn,i;
-register FILE *rumf;
- if(n_rumors <= n_used_rumors ||
- (rumf = fopen(RUMORFILE, "r")) == (FILE *) 0) return;
- if(n_used_rumors < 0) init_rumors(rumf);
- if(!n_rumors) goto none;
- rn = rn2(n_rumors - n_used_rumors);
- i = 0;
- while(rn || used(i)) {
- (void) skipline(rumf);
- if(!used(i)) rn--;
- i++;
- }
- usedbits[i/CHARSZ] |= (1 << (i % CHARSZ));
- n_used_rumors++;
- outline(rumf);
-none:
- (void) fclose(rumf);
-}
-
-used(i) register int i; {
- return(usedbits[i/CHARSZ] & (1 << (i % CHARSZ)));
-}
diff --git a/games/hack/hack.save.c b/games/hack/hack.save.c
deleted file mode 100644
index fe09e1e72e1e..000000000000
--- a/games/hack/hack.save.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.save.c - version 1.0.3 */
-
-#include "hack.h"
-extern char genocided[60]; /* defined in Decl.c */
-extern char fut_geno[60]; /* idem */
-#include <signal.h>
-
-extern char SAVEF[], nul[];
-extern char pl_character[PL_CSIZ];
-extern long lseek();
-extern struct obj *restobjchn();
-extern struct monst *restmonchn();
-
-dosave(){
- if(dosave0(0)) {
- settty("Be seeing you ...\n");
- exit(0);
- }
-#ifdef lint
- return(0);
-#endif lint
-}
-
-#ifndef NOSAVEONHANGUP
-hangup(){
- (void) dosave0(1);
- exit(1);
-}
-#endif NOSAVEONHANGUP
-
-/* returns 1 if save successful */
-dosave0(hu) int hu; {
- register fd, ofd;
- int tmp; /* not register ! */
-
- (void) signal(SIGHUP, SIG_IGN);
- (void) signal(SIGINT, SIG_IGN);
- if((fd = creat(SAVEF, FMASK)) < 0) {
- if(!hu) pline("Cannot open save file. (Continue or Quit)");
- (void) unlink(SAVEF); /* ab@unido */
- return(0);
- }
- if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
- u.uluck--; /* and unido!ab */
- savelev(fd,dlevel);
- saveobjchn(fd, invent);
- saveobjchn(fd, fcobj);
- savemonchn(fd, fallen_down);
- tmp = getuid();
- bwrite(fd, (char *) &tmp, sizeof tmp);
- bwrite(fd, (char *) &flags, sizeof(struct flag));
- bwrite(fd, (char *) &dlevel, sizeof dlevel);
- bwrite(fd, (char *) &maxdlevel, sizeof maxdlevel);
- bwrite(fd, (char *) &moves, sizeof moves);
- bwrite(fd, (char *) &u, sizeof(struct you));
- if(u.ustuck)
- bwrite(fd, (char *) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
- bwrite(fd, (char *) pl_character, sizeof pl_character);
- bwrite(fd, (char *) genocided, sizeof genocided);
- bwrite(fd, (char *) fut_geno, sizeof fut_geno);
- savenames(fd);
- for(tmp = 1; tmp <= maxdlevel; tmp++) {
- extern int hackpid;
- extern boolean level_exists[];
-
- if(tmp == dlevel || !level_exists[tmp]) continue;
- glo(tmp);
- if((ofd = open(lock, 0)) < 0) {
- if(!hu) pline("Error while saving: cannot read %s.", lock);
- (void) close(fd);
- (void) unlink(SAVEF);
- if(!hu) done("tricked");
- return(0);
- }
- getlev(ofd, hackpid, tmp);
- (void) close(ofd);
- bwrite(fd, (char *) &tmp, sizeof tmp); /* level number */
- savelev(fd,tmp); /* actual level */
- (void) unlink(lock);
- }
- (void) close(fd);
- glo(dlevel);
- (void) unlink(lock); /* get rid of current level --jgm */
- glo(0);
- (void) unlink(lock);
- return(1);
-}
-
-dorecover(fd)
-register fd;
-{
- register nfd;
- int tmp; /* not a register ! */
- unsigned mid; /* idem */
- struct obj *otmp;
- extern boolean restoring;
-
- restoring = TRUE;
- getlev(fd, 0, 0);
- invent = restobjchn(fd);
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp->owornmask)
- setworn(otmp, otmp->owornmask);
- fcobj = restobjchn(fd);
- fallen_down = restmonchn(fd);
- mread(fd, (char *) &tmp, sizeof tmp);
- if(tmp != getuid()) { /* strange ... */
- (void) close(fd);
- (void) unlink(SAVEF);
- puts("Saved game was not yours.");
- restoring = FALSE;
- return(0);
- }
- mread(fd, (char *) &flags, sizeof(struct flag));
- mread(fd, (char *) &dlevel, sizeof dlevel);
- mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
- mread(fd, (char *) &moves, sizeof moves);
- mread(fd, (char *) &u, sizeof(struct you));
- if(u.ustuck)
- mread(fd, (char *) &mid, sizeof mid);
- mread(fd, (char *) pl_character, sizeof pl_character);
- mread(fd, (char *) genocided, sizeof genocided);
- mread(fd, (char *) fut_geno, sizeof fut_geno);
- restnames(fd);
- while(1) {
- if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
- break;
- getlev(fd, 0, tmp);
- glo(tmp);
- if((nfd = creat(lock, FMASK)) < 0)
- panic("Cannot open temp file %s!\n", lock);
- savelev(nfd,tmp);
- (void) close(nfd);
- }
- (void) lseek(fd, 0L, 0);
- getlev(fd, 0, 0);
- (void) close(fd);
- (void) unlink(SAVEF);
- if(Punished) {
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->olet == CHAIN_SYM) goto chainfnd;
- panic("Cannot find the iron chain?");
- chainfnd:
- uchain = otmp;
- if(!uball){
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->olet == BALL_SYM && otmp->spe)
- goto ballfnd;
- panic("Cannot find the iron ball?");
- ballfnd:
- uball = otmp;
- }
- }
- if(u.ustuck) {
- register struct monst *mtmp;
-
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->m_id == mid) goto monfnd;
- panic("Cannot find the monster ustuck.");
- monfnd:
- u.ustuck = mtmp;
- }
-#ifndef QUEST
- setsee(); /* only to recompute seelx etc. - these weren't saved */
-#endif QUEST
- docrt();
- restoring = FALSE;
- return(1);
-}
-
-struct obj *
-restobjchn(fd)
-register fd;
-{
- register struct obj *otmp, *otmp2;
- register struct obj *first = 0;
- int xl;
-#ifdef lint
- /* suppress "used before set" warning from lint */
- otmp2 = 0;
-#endif lint
- while(1) {
- mread(fd, (char *) &xl, sizeof(xl));
- if(xl == -1) break;
- otmp = newobj(xl);
- if(!first) first = otmp;
- else otmp2->nobj = otmp;
- mread(fd, (char *) otmp, (unsigned) xl + sizeof(struct obj));
- if(!otmp->o_id) otmp->o_id = flags.ident++;
- otmp2 = otmp;
- }
- if(first && otmp2->nobj){
- impossible("Restobjchn: error reading objchn.");
- otmp2->nobj = 0;
- }
- return(first);
-}
-
-struct monst *
-restmonchn(fd)
-register fd;
-{
- register struct monst *mtmp, *mtmp2;
- register struct monst *first = 0;
- int xl;
-
- struct permonst *monbegin;
- long differ;
-
- mread(fd, (char *)&monbegin, sizeof(monbegin));
- differ = (char *)(&mons[0]) - (char *)(monbegin);
-
-#ifdef lint
- /* suppress "used before set" warning from lint */
- mtmp2 = 0;
-#endif lint
- while(1) {
- mread(fd, (char *) &xl, sizeof(xl));
- if(xl == -1) break;
- mtmp = newmonst(xl);
- if(!first) first = mtmp;
- else mtmp2->nmon = mtmp;
- mread(fd, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
- if(!mtmp->m_id)
- mtmp->m_id = flags.ident++;
- mtmp->data = (struct permonst *)
- ((char *) mtmp->data + differ);
- if(mtmp->minvent)
- mtmp->minvent = restobjchn(fd);
- mtmp2 = mtmp;
- }
- if(first && mtmp2->nmon){
- impossible("Restmonchn: error reading monchn.");
- mtmp2->nmon = 0;
- }
- return(first);
-}
diff --git a/games/hack/hack.search.c b/games/hack/hack.search.c
deleted file mode 100644
index c0ef9932ee91..000000000000
--- a/games/hack/hack.search.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.search.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern struct monst *makemon();
-
-findit() /* returns number of things found */
-{
- int num;
- register xchar zx,zy;
- register struct trap *ttmp;
- register struct monst *mtmp;
- xchar lx,hx,ly,hy;
-
- if(u.uswallow) return(0);
- for(lx = u.ux; (num = levl[lx-1][u.uy].typ) && num != CORR; lx--) ;
- for(hx = u.ux; (num = levl[hx+1][u.uy].typ) && num != CORR; hx++) ;
- for(ly = u.uy; (num = levl[u.ux][ly-1].typ) && num != CORR; ly--) ;
- for(hy = u.uy; (num = levl[u.ux][hy+1].typ) && num != CORR; hy++) ;
- num = 0;
- for(zy = ly; zy <= hy; zy++)
- for(zx = lx; zx <= hx; zx++) {
- if(levl[zx][zy].typ == SDOOR) {
- levl[zx][zy].typ = DOOR;
- atl(zx, zy, '+');
- num++;
- } else if(levl[zx][zy].typ == SCORR) {
- levl[zx][zy].typ = CORR;
- atl(zx, zy, CORR_SYM);
- num++;
- } else if(ttmp = t_at(zx, zy)) {
- if(ttmp->ttyp == PIERC){
- (void) makemon(PM_PIERCER, zx, zy);
- num++;
- deltrap(ttmp);
- } else if(!ttmp->tseen) {
- ttmp->tseen = 1;
- if(!vism_at(zx, zy))
- atl(zx,zy,'^');
- num++;
- }
- } else if(mtmp = m_at(zx,zy)) if(mtmp->mimic){
- seemimic(mtmp);
- num++;
- }
- }
- return(num);
-}
-
-dosearch()
-{
- register xchar x,y;
- register struct trap *trap;
- register struct monst *mtmp;
-
- if(u.uswallow)
- pline("What are you looking for? The exit?");
- else
- for(x = u.ux-1; x < u.ux+2; x++)
- for(y = u.uy-1; y < u.uy+2; y++) if(x != u.ux || y != u.uy) {
- if(levl[x][y].typ == SDOOR) {
- if(rn2(7)) continue;
- levl[x][y].typ = DOOR;
- levl[x][y].seen = 0; /* force prl */
- prl(x,y);
- nomul(0);
- } else if(levl[x][y].typ == SCORR) {
- if(rn2(7)) continue;
- levl[x][y].typ = CORR;
- levl[x][y].seen = 0; /* force prl */
- prl(x,y);
- nomul(0);
- } else {
- /* Be careful not to find anything in an SCORR or SDOOR */
- if(mtmp = m_at(x,y)) if(mtmp->mimic){
- seemimic(mtmp);
- pline("You find a mimic.");
- return(1);
- }
- for(trap = ftrap; trap; trap = trap->ntrap)
- if(trap->tx == x && trap->ty == y &&
- !trap->tseen && !rn2(8)) {
- nomul(0);
- pline("You find a%s.", traps[trap->ttyp]);
- if(trap->ttyp == PIERC) {
- deltrap(trap);
- (void) makemon(PM_PIERCER,x,y);
- return(1);
- }
- trap->tseen = 1;
- if(!vism_at(x,y)) atl(x,y,'^');
- }
- }
- }
- return(1);
-}
-
-doidtrap() {
-register struct trap *trap;
-register int x,y;
- if(!getdir(1)) return(0);
- x = u.ux + u.dx;
- y = u.uy + u.dy;
- for(trap = ftrap; trap; trap = trap->ntrap)
- if(trap->tx == x && trap->ty == y && trap->tseen) {
- if(u.dz)
- if((u.dz < 0) != (!xdnstair && trap->ttyp == TRAPDOOR))
- continue;
- pline("That is a%s.", traps[trap->ttyp]);
- return(0);
- }
- pline("I can't see a trap there.");
- return(0);
-}
-
-wakeup(mtmp)
-register struct monst *mtmp;
-{
- mtmp->msleep = 0;
- setmangry(mtmp);
- if(mtmp->mimic) seemimic(mtmp);
-}
-
-/* NOTE: we must check if(mtmp->mimic) before calling this routine */
-seemimic(mtmp)
-register struct monst *mtmp;
-{
- mtmp->mimic = 0;
- mtmp->mappearance = 0;
- unpmon(mtmp);
- pmon(mtmp);
-}
diff --git a/games/hack/hack.sh b/games/hack/hack.sh
deleted file mode 100644
index 8136ec42055d..000000000000
--- a/games/hack/hack.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-HACKDIR=/usr/games/lib/hackdir
-HACK=$HACKDIR/hack
-MAXNROFPLAYERS=4
-
-cd $HACKDIR
-case $1 in
- -s*)
- exec $HACK $@
- ;;
- *)
- exec $HACK $@ $MAXNROFPLAYERS
- ;;
-esac
diff --git a/games/hack/hack.shk.c b/games/hack/hack.shk.c
deleted file mode 100644
index 1478b1d8d576..000000000000
--- a/games/hack/hack.shk.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.shk.c - version 1.0.3 */
-
-#include "hack.h"
-#ifdef QUEST
-int shlevel = 0;
-struct monst *shopkeeper = 0;
-struct obj *billobjs = 0;
-obfree(obj,merge) register struct obj *obj, *merge; {
- free((char *) obj);
-}
-inshop(){ return(0); }
-shopdig(){}
-addtobill(){}
-subfrombill(){}
-splitbill(){}
-dopay(){ return(0); }
-paybill(){}
-doinvbill(){ return(0); }
-shkdead(){}
-shkcatch(){ return(0); }
-shk_move(){ return(0); }
-replshk(mtmp,mtmp2) struct monst *mtmp, *mtmp2; {}
-char *shkname(){ return(""); }
-
-#else QUEST
-#include "hack.mfndpos.h"
-#include "def.mkroom.h"
-#include "def.eshk.h"
-
-#define ESHK(mon) ((struct eshk *)(&(mon->mextra[0])))
-#define NOTANGRY(mon) mon->mpeaceful
-#define ANGRY(mon) !NOTANGRY(mon)
-
-extern char plname[], *xname();
-extern struct obj *o_on(), *bp_to_obj();
-
-/* Descriptor of current shopkeeper. Note that the bill need not be
- per-shopkeeper, since it is valid only when in a shop. */
-static struct monst *shopkeeper = 0;
-static struct bill_x *bill;
-static int shlevel = 0; /* level of this shopkeeper */
- struct obj *billobjs; /* objects on bill with bp->useup */
- /* only accessed here and by save & restore */
-static long int total; /* filled by addupbill() */
-static long int followmsg; /* last time of follow message */
-
-/*
- invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
- obj->quan <= bp->bquan
- */
-
-
-char shtypes[] = { /* 8 shoptypes: 7 specialized, 1 mixed */
- RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, SCROLL_SYM,
- POTION_SYM, ARMOR_SYM, 0
-};
-
-static char *shopnam[] = {
- "engagement ring", "walking cane", "antique weapon",
- "delicatessen", "second hand book", "liquor",
- "used armor", "assorted antiques"
-};
-
-char *
-shkname(mtmp) /* called in do_name.c */
-register struct monst *mtmp;
-{
- return(ESHK(mtmp)->shknam);
-}
-
-static void setpaid();
-
-shkdead(mtmp) /* called in mon.c */
-register struct monst *mtmp;
-{
- register struct eshk *eshk = ESHK(mtmp);
-
- if(eshk->shoplevel == dlevel)
- rooms[eshk->shoproom].rtype = 0;
- if(mtmp == shopkeeper) {
- setpaid();
- shopkeeper = 0;
- bill = (struct bill_x *) -1000; /* dump core when referenced */
- }
-}
-
-replshk(mtmp,mtmp2)
-register struct monst *mtmp, *mtmp2;
-{
- if(mtmp == shopkeeper) {
- shopkeeper = mtmp2;
- bill = &(ESHK(shopkeeper)->bill[0]);
- }
-}
-
-static void
-setpaid(){ /* caller has checked that shopkeeper exists */
- /* either we paid or left the shop or he just died */
-register struct obj *obj;
-register struct monst *mtmp;
- for(obj = invent; obj; obj = obj->nobj)
- obj->unpaid = 0;
- for(obj = fobj; obj; obj = obj->nobj)
- obj->unpaid = 0;
- for(obj = fcobj; obj; obj = obj->nobj)
- obj->unpaid = 0;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- for(obj = mtmp->minvent; obj; obj = obj->nobj)
- obj->unpaid = 0;
- for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
- for(obj = mtmp->minvent; obj; obj = obj->nobj)
- obj->unpaid = 0;
- while(obj = billobjs){
- billobjs = obj->nobj;
- free((char *) obj);
- }
- ESHK(shopkeeper)->billct = 0;
-}
-
-static
-addupbill(){ /* delivers result in total */
- /* caller has checked that shopkeeper exists */
-register ct = ESHK(shopkeeper)->billct;
-register struct bill_x *bp = bill;
- total = 0;
- while(ct--){
- total += bp->price * bp->bquan;
- bp++;
- }
-}
-
-inshop(){
-register roomno = inroom(u.ux,u.uy);
-
- static void findshk();
-
- /* Did we just leave a shop? */
- if(u.uinshop &&
- (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
- if(shopkeeper) {
- if(ESHK(shopkeeper)->billct) {
- if(inroom(shopkeeper->mx, shopkeeper->my)
- == u.uinshop - 1) /* ab@unido */
- pline("Somehow you escaped the shop without paying!");
- addupbill();
- pline("You stole for a total worth of %ld zorkmids.",
- total);
- ESHK(shopkeeper)->robbed += total;
- setpaid();
- if((rooms[ESHK(shopkeeper)->shoproom].rtype == GENERAL)
- == (rn2(3) == 0))
- ESHK(shopkeeper)->following = 1;
- }
- shopkeeper = 0;
- shlevel = 0;
- }
- u.uinshop = 0;
- }
-
- /* Did we just enter a zoo of some kind? */
- if(roomno >= 0) {
- register int rt = rooms[roomno].rtype;
- register struct monst *mtmp;
- if(rt == ZOO) {
- pline("Welcome to David's treasure zoo!");
- } else
- if(rt == SWAMP) {
- pline("It looks rather muddy down here.");
- } else
- if(rt == MORGUE) {
- if(midnight())
- pline("Go away! Go away!");
- else
- pline("You get an uncanny feeling ...");
- } else
- rt = 0;
- if(rt != 0) {
- rooms[roomno].rtype = 0;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(rt != ZOO || !rn2(3))
- mtmp->msleep = 0;
- }
- }
-
- /* Did we just enter a shop? */
- if(roomno >= 0 && rooms[roomno].rtype >= 8) {
- if(shlevel != dlevel || !shopkeeper
- || ESHK(shopkeeper)->shoproom != roomno)
- findshk(roomno);
- if(!shopkeeper) {
- rooms[roomno].rtype = 0;
- u.uinshop = 0;
- } else if(!u.uinshop){
- if(!ESHK(shopkeeper)->visitct ||
- strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){
-
- /* He seems to be new here */
- ESHK(shopkeeper)->visitct = 0;
- ESHK(shopkeeper)->following = 0;
- (void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
- NOTANGRY(shopkeeper) = 1;
- }
- if(!ESHK(shopkeeper)->following) {
- boolean box, pick;
-
- pline("Hello %s! Welcome%s to %s's %s shop!",
- plname,
- ESHK(shopkeeper)->visitct++ ? " again" : "",
- shkname(shopkeeper),
- shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8] );
- box = carrying(ICE_BOX);
- pick = carrying(PICK_AXE);
- if(box || pick) {
- if(dochug(shopkeeper)) {
- u.uinshop = 0; /* he died moving */
- return(0);
- }
- pline("Will you please leave your %s outside?",
- (box && pick) ? "box and pick-axe" :
- box ? "box" : "pick-axe");
- }
- }
- u.uinshop = roomno + 1;
- }
- }
- return(u.uinshop);
-}
-
-static void
-findshk(roomno)
-register roomno;
-{
-register struct monst *mtmp;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
- && ESHK(mtmp)->shoplevel == dlevel) {
- shopkeeper = mtmp;
- bill = &(ESHK(shopkeeper)->bill[0]);
- shlevel = dlevel;
- if(ANGRY(shopkeeper) &&
- strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
- NOTANGRY(shopkeeper) = 1;
- /* billobjs = 0; -- this is wrong if we save in a shop */
- /* (and it is harmless to have too many things in billobjs) */
- return;
- }
- shopkeeper = 0;
- shlevel = 0;
- bill = (struct bill_x *) -1000; /* dump core when referenced */
-}
-
-static struct bill_x *
-onbill(obj) register struct obj *obj; {
-register struct bill_x *bp;
- if(!shopkeeper) return(0);
- for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
- if(bp->bo_id == obj->o_id) {
- if(!obj->unpaid) pline("onbill: paid obj on bill?");
- return(bp);
- }
- if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
- return(0);
-}
-
-/* called with two args on merge */
-obfree(obj,merge) register struct obj *obj, *merge; {
-register struct bill_x *bp = onbill(obj);
-register struct bill_x *bpm;
- if(bp) {
- if(!merge){
- bp->useup = 1;
- obj->unpaid = 0; /* only for doinvbill */
- obj->nobj = billobjs;
- billobjs = obj;
- return;
- }
- bpm = onbill(merge);
- if(!bpm){
- /* this used to be a rename */
- impossible("obfree: not on bill??");
- return;
- } else {
- /* this was a merger */
- bpm->bquan += bp->bquan;
- ESHK(shopkeeper)->billct--;
- *bp = bill[ESHK(shopkeeper)->billct];
- }
- }
- free((char *) obj);
-}
-
-static
-pay(tmp,shkp)
-long tmp;
-register struct monst *shkp;
-{
- long robbed = ESHK(shkp)->robbed;
-
- u.ugold -= tmp;
- shkp->mgold += tmp;
- flags.botl = 1;
- if(robbed) {
- robbed -= tmp;
- if(robbed < 0) robbed = 0;
- ESHK(shkp)->robbed = robbed;
- }
-}
-
-dopay(){
-long ltmp;
-register struct bill_x *bp;
-register struct monst *shkp;
-int pass, tmp;
-
- static int dopayobj();
-
- multi = 0;
- (void) inshop();
- for(shkp = fmon; shkp; shkp = shkp->nmon)
- if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
- break;
- if(!shkp && u.uinshop &&
- inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom)
- shkp = shopkeeper;
-
- if(!shkp) {
- pline("There is nobody here to receive your payment.");
- return(0);
- }
- ltmp = ESHK(shkp)->robbed;
- if(shkp != shopkeeper && NOTANGRY(shkp)) {
- if(!ltmp) {
- pline("You do not owe %s anything.", monnam(shkp));
- } else
- if(!u.ugold) {
- pline("You have no money.");
- } else {
- long ugold = u.ugold;
-
- if(u.ugold > ltmp) {
- pline("You give %s the %ld gold pieces he asked for.",
- monnam(shkp), ltmp);
- pay(ltmp, shkp);
- } else {
- pline("You give %s all your gold.", monnam(shkp));
- pay(u.ugold, shkp);
- }
- if(ugold < ltmp/2) {
- pline("Unfortunately, he doesn't look satisfied.");
- } else {
- ESHK(shkp)->robbed = 0;
- ESHK(shkp)->following = 0;
- if(ESHK(shkp)->shoplevel != dlevel) {
- /* For convenience's sake, let him disappear */
- shkp->minvent = 0; /* %% */
- shkp->mgold = 0;
- mondead(shkp);
- }
- }
- }
- return(1);
- }
-
- if(!ESHK(shkp)->billct){
- pline("You do not owe %s anything.", monnam(shkp));
- if(!u.ugold){
- pline("Moreover, you have no money.");
- return(1);
- }
- if(ESHK(shkp)->robbed){
-#define min(a,b) ((a<b)?a:b)
- pline("But since his shop has been robbed recently,");
- pline("you %srepay %s's expenses.",
- (u.ugold < ESHK(shkp)->robbed) ? "partially " : "",
- monnam(shkp));
- pay(min(u.ugold, ESHK(shkp)->robbed), shkp);
- ESHK(shkp)->robbed = 0;
- return(1);
- }
- if(ANGRY(shkp)){
- pline("But in order to appease %s,",
- amonnam(shkp, "angry"));
- if(u.ugold >= 1000){
- ltmp = 1000;
- pline(" you give him 1000 gold pieces.");
- } else {
- ltmp = u.ugold;
- pline(" you give him all your money.");
- }
- pay(ltmp, shkp);
- if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
- || rn2(3)){
- pline("%s calms down.", Monnam(shkp));
- NOTANGRY(shkp) = 1;
- } else pline("%s is as angry as ever.",
- Monnam(shkp));
- }
- return(1);
- }
- if(shkp != shopkeeper) {
- impossible("dopay: not to shopkeeper?");
- if(shopkeeper) setpaid();
- return(0);
- }
- for(pass = 0; pass <= 1; pass++) {
- tmp = 0;
- while(tmp < ESHK(shopkeeper)->billct) {
- bp = &bill[tmp];
- if(!pass && !bp->useup) {
- tmp++;
- continue;
- }
- if(!dopayobj(bp)) return(1);
- bill[tmp] = bill[--ESHK(shopkeeper)->billct];
- }
- }
- pline("Thank you for shopping in %s's %s store!",
- shkname(shopkeeper),
- shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]);
- NOTANGRY(shopkeeper) = 1;
- return(1);
-}
-
-/* return 1 if paid successfully */
-/* 0 if not enough money */
-/* -1 if object could not be found (but was paid) */
-static
-dopayobj(bp) register struct bill_x *bp; {
-register struct obj *obj;
-long ltmp;
-
- /* find the object on one of the lists */
- obj = bp_to_obj(bp);
-
- if(!obj) {
- impossible("Shopkeeper administration out of order.");
- setpaid(); /* be nice to the player */
- return(0);
- }
-
- if(!obj->unpaid && !bp->useup){
- impossible("Paid object on bill??");
- return(1);
- }
- obj->unpaid = 0;
- ltmp = bp->price * bp->bquan;
- if(ANGRY(shopkeeper)) ltmp += ltmp/3;
- if(u.ugold < ltmp){
- pline("You don't have gold enough to pay %s.",
- doname(obj));
- obj->unpaid = 1;
- return(0);
- }
- pay(ltmp, shopkeeper);
- pline("You bought %s for %ld gold piece%s.",
- doname(obj), ltmp, plur(ltmp));
- if(bp->useup) {
- register struct obj *otmp = billobjs;
- if(obj == billobjs)
- billobjs = obj->nobj;
- else {
- while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
- if(otmp) otmp->nobj = obj->nobj;
- else pline("Error in shopkeeper administration.");
- }
- free((char *) obj);
- }
- return(1);
-}
-
-/* routine called after dying (or quitting) with nonempty bill */
-paybill(){
- if(shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct){
- addupbill();
- if(total > u.ugold){
- shopkeeper->mgold += u.ugold;
- u.ugold = 0;
- pline("%s comes and takes all your possessions.",
- Monnam(shopkeeper));
- } else {
- u.ugold -= total;
- shopkeeper->mgold += total;
- pline("%s comes and takes the %ld zorkmids you owed him.",
- Monnam(shopkeeper), total);
- }
- setpaid(); /* in case we create bones */
- }
-}
-
-/* find obj on one of the lists */
-struct obj *
-bp_to_obj(bp)
-register struct bill_x *bp;
-{
- register struct obj *obj;
- register struct monst *mtmp;
- register unsigned id = bp->bo_id;
-
- if(bp->useup)
- obj = o_on(id, billobjs);
- else if(!(obj = o_on(id, invent)) &&
- !(obj = o_on(id, fobj)) &&
- !(obj = o_on(id, fcobj))) {
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(obj = o_on(id, mtmp->minvent))
- break;
- for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
- if(obj = o_on(id, mtmp->minvent))
- break;
- }
- return(obj);
-}
-
-static int getprice();
-
-/* called in hack.c when we pickup an object */
-addtobill(obj) register struct obj *obj; {
-register struct bill_x *bp;
- if(!inshop() ||
- (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
- (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) ||
- onbill(obj) /* perhaps we threw it away earlier */
- ) return;
- if(ESHK(shopkeeper)->billct == BILLSZ){
- pline("You got that for free!");
- return;
- }
- bp = &bill[ESHK(shopkeeper)->billct];
- bp->bo_id = obj->o_id;
- bp->bquan = obj->quan;
- bp->useup = 0;
- bp->price = getprice(obj);
- ESHK(shopkeeper)->billct++;
- obj->unpaid = 1;
-}
-
-splitbill(obj,otmp) register struct obj *obj, *otmp; {
- /* otmp has been split off from obj */
-register struct bill_x *bp;
-register int tmp;
- bp = onbill(obj);
- if(!bp) {
- impossible("splitbill: not on bill?");
- return;
- }
- if(bp->bquan < otmp->quan) {
- impossible("Negative quantity on bill??");
- }
- if(bp->bquan == otmp->quan) {
- impossible("Zero quantity on bill??");
- }
- bp->bquan -= otmp->quan;
-
- /* addtobill(otmp); */
- if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0;
- else {
- tmp = bp->price;
- bp = &bill[ESHK(shopkeeper)->billct];
- bp->bo_id = otmp->o_id;
- bp->bquan = otmp->quan;
- bp->useup = 0;
- bp->price = tmp;
- ESHK(shopkeeper)->billct++;
- }
-}
-
-subfrombill(obj) register struct obj *obj; {
-long ltmp;
-register int tmp;
-register struct obj *otmp;
-register struct bill_x *bp;
- if(!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
- (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y))
- return;
- if((bp = onbill(obj)) != 0){
- obj->unpaid = 0;
- if(bp->bquan > obj->quan){
- otmp = newobj(0);
- *otmp = *obj;
- bp->bo_id = otmp->o_id = flags.ident++;
- otmp->quan = (bp->bquan -= obj->quan);
- otmp->owt = 0; /* superfluous */
- otmp->onamelth = 0;
- bp->useup = 1;
- otmp->nobj = billobjs;
- billobjs = otmp;
- return;
- }
- ESHK(shopkeeper)->billct--;
- *bp = bill[ESHK(shopkeeper)->billct];
- return;
- }
- if(obj->unpaid){
- pline("%s didn't notice.", Monnam(shopkeeper));
- obj->unpaid = 0;
- return; /* %% */
- }
- /* he dropped something of his own - probably wants to sell it */
- if(shopkeeper->msleep || shopkeeper->mfroz ||
- inroom(shopkeeper->mx,shopkeeper->my) != ESHK(shopkeeper)->shoproom)
- return;
- if(ESHK(shopkeeper)->billct == BILLSZ ||
- ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype-8]) && tmp != obj->olet)
- || index("_0", obj->olet)) {
- pline("%s seems not interested.", Monnam(shopkeeper));
- return;
- }
- ltmp = getprice(obj) * obj->quan;
- if(ANGRY(shopkeeper)) {
- ltmp /= 3;
- NOTANGRY(shopkeeper) = 1;
- } else ltmp /= 2;
- if(ESHK(shopkeeper)->robbed){
- if((ESHK(shopkeeper)->robbed -= ltmp) < 0)
- ESHK(shopkeeper)->robbed = 0;
-pline("Thank you for your contribution to restock this recently plundered shop.");
- return;
- }
- if(ltmp > shopkeeper->mgold)
- ltmp = shopkeeper->mgold;
- pay(-ltmp, shopkeeper);
- if(!ltmp)
- pline("%s gladly accepts %s but cannot pay you at present.",
- Monnam(shopkeeper), doname(obj));
- else
- pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
- plur(ltmp));
-}
-
-doinvbill(mode)
-int mode; /* 0: deliver count 1: paged */
-{
- register struct bill_x *bp;
- register struct obj *obj;
- long totused, thisused;
- char buf[BUFSZ];
-
- if(mode == 0) {
- register int cnt = 0;
-
- if(shopkeeper)
- for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
- if(bp->useup ||
- ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
- cnt++;
- return(cnt);
- }
-
- if(!shopkeeper) {
- impossible("doinvbill: no shopkeeper?");
- return(0);
- }
-
- set_pager(0);
- if(page_line("Unpaid articles already used up:") || page_line(""))
- goto quit;
-
- totused = 0;
- for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
- obj = bp_to_obj(bp);
- if(!obj) {
- impossible("Bad shopkeeper administration.");
- goto quit;
- }
- if(bp->useup || bp->bquan > obj->quan) {
- register int cnt, oquan, uquan;
-
- oquan = obj->quan;
- uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
- thisused = bp->price * uquan;
- totused += thisused;
- obj->quan = uquan; /* cheat doname */
- (void) sprintf(buf, "x - %s", doname(obj));
- obj->quan = oquan; /* restore value */
- for(cnt = 0; buf[cnt]; cnt++);
- while(cnt < 50)
- buf[cnt++] = ' ';
- (void) sprintf(&buf[cnt], " %5ld zorkmids", thisused);
- if(page_line(buf))
- goto quit;
- }
- }
- (void) sprintf(buf, "Total:%50ld zorkmids", totused);
- if(page_line("") || page_line(buf))
- goto quit;
- set_pager(1);
- return(0);
-quit:
- set_pager(2);
- return(0);
-}
-
-static
-getprice(obj) register struct obj *obj; {
-register int tmp, ac;
- static int realhunger();
-
- switch(obj->olet){
- case AMULET_SYM:
- tmp = 10*rnd(500);
- break;
- case TOOL_SYM:
- tmp = 10*rnd((obj->otyp == EXPENSIVE_CAMERA) ? 150 : 30);
- break;
- case RING_SYM:
- tmp = 10*rnd(100);
- break;
- case WAND_SYM:
- tmp = 10*rnd(100);
- break;
- case SCROLL_SYM:
- tmp = 10*rnd(50);
-#ifdef MAIL
- if(obj->otyp == SCR_MAIL)
- tmp = rnd(5);
-#endif MAIL
- break;
- case POTION_SYM:
- tmp = 10*rnd(50);
- break;
- case FOOD_SYM:
- tmp = 10*rnd(5 + (2000/realhunger()));
- break;
- case GEM_SYM:
- tmp = 10*rnd(20);
- break;
- case ARMOR_SYM:
- ac = ARM_BONUS(obj);
- if(ac <= -10) /* probably impossible */
- ac = -9;
- tmp = 100 + ac*ac*rnd(10+ac);
- break;
- case WEAPON_SYM:
- if(obj->otyp < BOOMERANG)
- tmp = 5*rnd(10);
- else if(obj->otyp == LONG_SWORD ||
- obj->otyp == TWO_HANDED_SWORD)
- tmp = 10*rnd(150);
- else tmp = 10*rnd(75);
- break;
- case CHAIN_SYM:
- pline("Strange ..., carrying a chain?");
- case BALL_SYM:
- tmp = 10;
- break;
- default:
- tmp = 10000;
- }
- return(tmp);
-}
-
-static
-realhunger(){ /* not completely foolproof */
-register tmp = u.uhunger;
-register struct obj *otmp = invent;
- while(otmp){
- if(otmp->olet == FOOD_SYM && !otmp->unpaid)
- tmp += objects[otmp->otyp].nutrition;
- otmp = otmp->nobj;
- }
- return((tmp <= 0) ? 1 : tmp);
-}
-
-shkcatch(obj)
-register struct obj *obj;
-{
- register struct monst *shkp = shopkeeper;
-
- if(u.uinshop && shkp && !shkp->mfroz && !shkp->msleep &&
- u.dx && u.dy &&
- inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop &&
- shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y &&
- u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) {
- pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj));
- obj->nobj = shkp->minvent;
- shkp->minvent = obj;
- return(1);
- }
- return(0);
-}
-
-/*
- * shk_move: return 1: he moved 0: he didnt -1: let m_move do it
- */
-shk_move(shkp)
-register struct monst *shkp;
-{
- register struct monst *mtmp;
- register struct permonst *mdat = shkp->data;
- register xchar gx,gy,omx,omy,nx,ny,nix,niy;
- register schar appr,i;
- register int udist;
- int z;
- schar shkroom,chi,chcnt,cnt;
- boolean uondoor, satdoor, avoid, badinv;
- coord poss[9];
- int info[9];
- struct obj *ib = 0;
-
- omx = shkp->mx;
- omy = shkp->my;
-
- if((udist = dist(omx,omy)) < 3) {
- if(ANGRY(shkp)) {
- (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
- return(0);
- }
- if(ESHK(shkp)->following) {
- if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)){
- pline("Hello %s! I was looking for %s.",
- plname, ESHK(shkp)->customer);
- ESHK(shkp)->following = 0;
- return(0);
- }
- if(!ESHK(shkp)->robbed) { /* impossible? */
- ESHK(shkp)->following = 0;
- return(0);
- }
- if(moves > followmsg+4) {
- pline("Hello %s! Didn't you forget to pay?",
- plname);
- followmsg = moves;
- }
- if(udist < 2)
- return(0);
- }
- }
-
- shkroom = inroom(omx,omy);
- appr = 1;
- gx = ESHK(shkp)->shk.x;
- gy = ESHK(shkp)->shk.y;
- satdoor = (gx == omx && gy == omy);
- if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
- gx = u.ux;
- gy = u.uy;
- if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
- if(udist > 4)
- return(-1); /* leave it to m_move */
- } else if(ANGRY(shkp)) {
- long saveBlind = Blind;
- Blind = 0;
- if(shkp->mcansee && !Invis && cansee(omx,omy)) {
- gx = u.ux;
- gy = u.uy;
- }
- Blind = saveBlind;
- avoid = FALSE;
- } else {
-#define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy))
- if(Invis)
- avoid = FALSE;
- else {
- uondoor = (u.ux == ESHK(shkp)->shd.x &&
- u.uy == ESHK(shkp)->shd.y);
- if(uondoor) {
- if(ESHK(shkp)->billct)
- pline("Hello %s! Will you please pay before leaving?",
- plname);
- badinv = (carrying(PICK_AXE) || carrying(ICE_BOX));
- if(satdoor && badinv)
- return(0);
- avoid = !badinv;
- } else {
- avoid = (u.uinshop && dist(gx,gy) > 8);
- badinv = FALSE;
- }
-
- if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid)
- && GDIST(omx,omy) < 3){
- if(!badinv && !online(omx,omy))
- return(0);
- if(satdoor)
- appr = gx = gy = 0;
- }
- }
- }
- if(omx == gx && omy == gy)
- return(0);
- if(shkp->mconf) {
- avoid = FALSE;
- appr = 0;
- }
- nix = omx;
- niy = omy;
- cnt = mfndpos(shkp,poss,info,ALLOW_SSM);
- if(avoid && uondoor) { /* perhaps we cannot avoid him */
- for(i=0; i<cnt; i++)
- if(!(info[i] & NOTONL)) goto notonl_ok;
- avoid = FALSE;
- notonl_ok:
- ;
- }
- chi = -1;
- chcnt = 0;
- for(i=0; i<cnt; i++){
- nx = poss[i].x;
- ny = poss[i].y;
- if(levl[nx][ny].typ == ROOM
- || shkroom != ESHK(shkp)->shoproom
- || ESHK(shkp)->following) {
-#ifdef STUPID
- /* cater for stupid compilers */
- register int zz;
-#endif STUPID
- if(uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) {
- nix = nx; niy = ny; chi = i; break;
- }
- if(avoid && (info[i] & NOTONL))
- continue;
- if((!appr && !rn2(++chcnt)) ||
-#ifdef STUPID
- (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))
-#else
- (appr && GDIST(nx,ny) < GDIST(nix,niy))
-#endif STUPID
- ) {
- nix = nx;
- niy = ny;
- chi = i;
- }
- }
- }
- if(nix != omx || niy != omy){
- if(info[chi] & ALLOW_M){
- mtmp = m_at(nix,niy);
- if(hitmm(shkp,mtmp) == 1 && rn2(3) &&
- hitmm(mtmp,shkp) == 2) return(2);
- return(0);
- } else if(info[chi] & ALLOW_U){
- (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
- return(0);
- }
- shkp->mx = nix;
- shkp->my = niy;
- pmon(shkp);
- if(ib) {
- freeobj(ib);
- mpickobj(shkp, ib);
- }
- return(1);
- }
- return(0);
-}
-
-/* He is digging in the shop. */
-shopdig(fall)
-register int fall;
-{
- if(!fall) {
- if(u.utraptype == TT_PIT)
- pline("\"Be careful, sir, or you might fall through the floor.\"");
- else
- pline("\"Please, do not damage the floor here.\"");
- } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) {
- register struct obj *obj, *obj2;
-
- pline("%s grabs your backpack!", shkname(shopkeeper));
- for(obj = invent; obj; obj = obj2) {
- obj2 = obj->nobj;
- if(obj->owornmask) continue;
- freeinv(obj);
- obj->nobj = shopkeeper->minvent;
- shopkeeper->minvent = obj;
- if(obj->unpaid)
- subfrombill(obj);
- }
- }
-}
-#endif QUEST
-
-online(x,y) {
- return(x==u.ux || y==u.uy ||
- (x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
-}
-
-/* Does this monster follow me downstairs? */
-follower(mtmp)
-register struct monst *mtmp;
-{
- return( mtmp->mtame || index("1TVWZi&, ", mtmp->data->mlet)
-#ifndef QUEST
- || (mtmp->isshk && ESHK(mtmp)->following)
-#endif QUEST
- );
-}
diff --git a/games/hack/hack.shknam.c b/games/hack/hack.shknam.c
deleted file mode 100644
index 9d4b860ff6b6..000000000000
--- a/games/hack/hack.shknam.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.shknam.c - version 1.0.2 */
-
-#include "hack.h"
-
-char *shkliquors[] = {
- /* Ukraine */
- "Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka",
- /* N. Russia */
- "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
- "Narodnaja", "Kyzyl",
- /* Silezie */
- "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
- "Brzeg", "Krnov", "Hradec Kralove",
- /* Schweiz */
- "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
- "Flims", "Vals", "Schuls", "Zum Loch",
- 0
-};
-
-char *shkbooks[] = {
- /* Eire */
- "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
- "Loughrea", "Croagh", "Maumakeogh", "Ballyjamesduff",
- "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
- "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
- "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
- "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
- "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
- 0
-};
-
-char *shkarmors[] = {
- /* Turquie */
- "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
- "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
- "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
- "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
- "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
- "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
- 0
-};
-
-char *shkwands[] = {
- /* Wales */
- "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
- "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
- "Y-Fenni", "Measteg", "Rhydaman", "Beddgelert",
- "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
- /* Scotland */
- "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
- "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
- "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
- "Kyleakin", "Dunvegan",
- 0
-};
-
-char *shkrings[] = {
- /* Hollandse familienamen */
- "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
- "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
- "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
- "Ypey",
- /* Skandinaviske navne */
- "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
- "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
- "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
- 0
-};
-
-char *shkfoods[] = {
- /* Indonesia */
- "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
- "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
- "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
- "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",
- "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
- "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
- "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
- 0
-};
-
-char *shkweapons[] = {
- /* Perigord */
- "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
- "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
- "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
- "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
- "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
- "Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
- 0
-};
-
-char *shkgeneral[] = {
- /* Suriname */
- "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
- "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
- "Akalapi", "Sipaliwini",
- /* Greenland */
- "Annootok", "Upernavik", "Angmagssalik",
- /* N. Canada */
- "Aklavik", "Inuvik", "Tuktoyaktuk",
- "Chicoutimi", "Ouiatchouane", "Chibougamau",
- "Matagami", "Kipawa", "Kinojevis",
- "Abitibi", "Maganasipi",
- /* Iceland */
- "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
- "Holmavik",
- 0
-};
-
-struct shk_nx {
- char x;
- char **xn;
-} shk_nx[] = {
- { POTION_SYM, shkliquors },
- { SCROLL_SYM, shkbooks },
- { ARMOR_SYM, shkarmors },
- { WAND_SYM, shkwands },
- { RING_SYM, shkrings },
- { FOOD_SYM, shkfoods },
- { WEAPON_SYM, shkweapons },
- { 0, shkgeneral }
-};
-
-findname(nampt, let) char *nampt; char let; {
-register struct shk_nx *p = shk_nx;
-register char **q;
-register int i;
- while(p->x && p->x != let) p++;
- q = p->xn;
- for(i=0; i<dlevel; i++) if(!q[i]){
- /* Not enough names, try general name */
- if(let) findname(nampt, 0);
- else (void) strcpy(nampt, "Dirk");
- return;
- }
- (void) strncpy(nampt, q[i], PL_NSIZ);
- nampt[PL_NSIZ-1] = 0;
-}
diff --git a/games/hack/hack.steal.c b/games/hack/hack.steal.c
deleted file mode 100644
index f123d37f790b..000000000000
--- a/games/hack/hack.steal.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.steal.c - version 1.0.3 */
-
-#include "hack.h"
-
-long /* actually returns something that fits in an int */
-somegold(){
- return( (u.ugold < 100) ? u.ugold :
- (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
-}
-
-stealgold(mtmp) register struct monst *mtmp; {
-register struct gold *gold = g_at(u.ux, u.uy);
-register long tmp;
- if(gold && ( !u.ugold || gold->amount > u.ugold || !rn2(5))) {
- mtmp->mgold += gold->amount;
- freegold(gold);
- if(Invisible) newsym(u.ux, u.uy);
- pline("%s quickly snatches some gold from between your feet!",
- Monnam(mtmp));
- if(!u.ugold || !rn2(5)) {
- rloc(mtmp);
- mtmp->mflee = 1;
- }
- } else if(u.ugold) {
- u.ugold -= (tmp = somegold());
- pline("Your purse feels lighter.");
- mtmp->mgold += tmp;
- rloc(mtmp);
- mtmp->mflee = 1;
- flags.botl = 1;
- }
-}
-
-/* steal armor after he finishes taking it off */
-unsigned stealoid; /* object to be stolen */
-unsigned stealmid; /* monster doing the stealing */
-stealarm(){
- register struct monst *mtmp;
- register struct obj *otmp;
-
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp->o_id == stealoid) {
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->m_id == stealmid) {
- if(dist(mtmp->mx,mtmp->my) < 3) {
- freeinv(otmp);
- pline("%s steals %s!", Monnam(mtmp), doname(otmp));
- mpickobj(mtmp,otmp);
- mtmp->mflee = 1;
- rloc(mtmp);
- }
- break;
- }
- break;
- }
- stealoid = 0;
-}
-
-/* returns 1 when something was stolen */
-/* (or at least, when N should flee now) */
-/* avoid stealing the object stealoid */
-steal(mtmp)
-struct monst *mtmp;
-{
- register struct obj *otmp;
- register tmp;
- register named = 0;
-
- if(!invent){
- if(Blind)
- pline("Somebody tries to rob you, but finds nothing to steal.");
- else
- pline("%s tries to rob you, but she finds nothing to steal!",
- Monnam(mtmp));
- return(1); /* let her flee */
- }
- tmp = 0;
- for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp != uarm2)
- tmp += ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1);
- tmp = rn2(tmp);
- for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp != uarm2)
- if((tmp -= ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1))
- < 0) break;
- if(!otmp) {
- impossible("Steal fails!");
- return(0);
- }
- if(otmp->o_id == stealoid)
- return(0);
- if((otmp->owornmask & (W_ARMOR | W_RING))){
- switch(otmp->olet) {
- case RING_SYM:
- ringoff(otmp);
- break;
- case ARMOR_SYM:
- if(multi < 0 || otmp == uarms){
- setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
- break;
- }
- { int curssv = otmp->cursed;
- otmp->cursed = 0;
- stop_occupation();
- pline("%s seduces you and %s off your %s.",
- Amonnam(mtmp, Blind ? "gentle" : "beautiful"),
- otmp->cursed ? "helps you to take"
- : "you start taking",
- (otmp == uarmg) ? "gloves" :
- (otmp == uarmh) ? "helmet" : "armor");
- named++;
- (void) armoroff(otmp);
- otmp->cursed = curssv;
- if(multi < 0){
- extern char *nomovemsg;
- extern int (*afternmv)();
- /*
- multi = 0;
- nomovemsg = 0;
- afternmv = 0;
- */
- stealoid = otmp->o_id;
- stealmid = mtmp->m_id;
- afternmv = stealarm;
- return(0);
- }
- break;
- }
- default:
- impossible("Tried to steal a strange worn thing.");
- }
- }
- else if(otmp == uwep)
- setuwep((struct obj *) 0);
- if(otmp->olet == CHAIN_SYM) {
- impossible("How come you are carrying that chain?");
- }
- if(Punished && otmp == uball){
- Punished = 0;
- freeobj(uchain);
- free((char *) uchain);
- uchain = (struct obj *) 0;
- uball->spe = 0;
- uball = (struct obj *) 0; /* superfluous */
- }
- freeinv(otmp);
- pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
- mpickobj(mtmp,otmp);
- return((multi < 0) ? 0 : 1);
-}
-
-mpickobj(mtmp,otmp)
-register struct monst *mtmp;
-register struct obj *otmp;
-{
- otmp->nobj = mtmp->minvent;
- mtmp->minvent = otmp;
-}
-
-stealamulet(mtmp)
-register struct monst *mtmp;
-{
- register struct obj *otmp;
-
- for(otmp = invent; otmp; otmp = otmp->nobj) {
- if(otmp->olet == AMULET_SYM) {
- /* might be an imitation one */
- if(otmp == uwep) setuwep((struct obj *) 0);
- freeinv(otmp);
- mpickobj(mtmp,otmp);
- pline("%s stole %s!", Monnam(mtmp), doname(otmp));
- return(1);
- }
- }
- return(0);
-}
-
-/* release the objects the killed animal has stolen */
-relobj(mtmp,show)
-register struct monst *mtmp;
-register show;
-{
- register struct obj *otmp, *otmp2;
-
- for(otmp = mtmp->minvent; otmp; otmp = otmp2){
- otmp->ox = mtmp->mx;
- otmp->oy = mtmp->my;
- otmp2 = otmp->nobj;
- otmp->nobj = fobj;
- fobj = otmp;
- stackobj(fobj);
- if(show & cansee(mtmp->mx,mtmp->my))
- atl(otmp->ox,otmp->oy,otmp->olet);
- }
- mtmp->minvent = (struct obj *) 0;
- if(mtmp->mgold || mtmp->data->mlet == 'L') {
- register long tmp;
-
- tmp = (mtmp->mgold > 10000) ? 10000 : mtmp->mgold;
- mkgold((long)(tmp + d(dlevel,30)), mtmp->mx, mtmp->my);
- if(show & cansee(mtmp->mx,mtmp->my))
- atl(mtmp->mx,mtmp->my,'$');
- }
-}
diff --git a/games/hack/hack.termcap.c b/games/hack/hack.termcap.c
deleted file mode 100644
index e94d6729c17b..000000000000
--- a/games/hack/hack.termcap.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.termcap.c - version 1.0.3 */
-
-#include <stdio.h>
-#include "config.h" /* for ROWNO and COLNO */
-#include "def.flag.h" /* for flags.nonull */
-extern char *tgetstr(), *tgoto(), *getenv();
-extern long *alloc();
-
-#ifndef lint
-extern /* it is defined in libtermlib (libtermcap) */
-#endif lint
- short ospeed; /* terminal baudrate; used by tputs */
-static char tbuf[512];
-static char *HO, *CL, *CE, *UP, *CM, *ND, *XD, *BC, *SO, *SE, *TI, *TE;
-static char *VS, *VE;
-static int SG;
-static char PC = '\0';
-char *CD; /* tested in pri.c: docorner() */
-int CO, LI; /* used in pri.c and whatis.c */
-
-startup()
-{
- register char *term;
- register char *tptr;
- char *tbufptr, *pc;
-
- tptr = (char *) alloc(1024);
-
- tbufptr = tbuf;
- if(!(term = getenv("TERM")))
- error("Can't get TERM.");
- if(!strncmp(term, "5620", 4))
- flags.nonull = 1; /* this should be a termcap flag */
- if(tgetent(tptr, term) < 1)
- error("Unknown terminal type: %s.", term);
- if(pc = tgetstr("pc", &tbufptr))
- PC = *pc;
- if(!(BC = tgetstr("bc", &tbufptr))) {
- if(!tgetflag("bs"))
- error("Terminal must backspace.");
- BC = tbufptr;
- tbufptr += 2;
- *BC = '\b';
- }
- HO = tgetstr("ho", &tbufptr);
- CO = tgetnum("co");
- LI = tgetnum("li");
- if(CO < COLNO || LI < ROWNO+2)
- setclipped();
- if(!(CL = tgetstr("cl", &tbufptr)))
- error("Hack needs CL.");
- ND = tgetstr("nd", &tbufptr);
- if(tgetflag("os"))
- error("Hack can't have OS.");
- CE = tgetstr("ce", &tbufptr);
- UP = tgetstr("up", &tbufptr);
- /* It seems that xd is no longer supported, and we should use
- a linefeed instead; unfortunately this requires resetting
- CRMOD, and many output routines will have to be modified
- slightly. Let's leave that till the next release. */
- XD = tgetstr("xd", &tbufptr);
-/* not: XD = tgetstr("do", &tbufptr); */
- if(!(CM = tgetstr("cm", &tbufptr))) {
- if(!UP && !HO)
- error("Hack needs CM or UP or HO.");
- printf("Playing hack on terminals without cm is suspect...\n");
- getret();
- }
- SO = tgetstr("so", &tbufptr);
- SE = tgetstr("se", &tbufptr);
- SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */
- if(!SO || !SE || (SG > 0)) SO = SE = 0;
- CD = tgetstr("cd", &tbufptr);
- set_whole_screen(); /* uses LI and CD */
- if(tbufptr-tbuf > sizeof(tbuf)) error("TERMCAP entry too big...\n");
- free(tptr);
-}
-
-start_screen()
-{
- xputs(TI);
- xputs(VS);
-}
-
-end_screen()
-{
- xputs(VE);
- xputs(TE);
-}
-
-/* Cursor movements */
-extern xchar curx, cury;
-
-curs(x, y)
-register int x, y; /* not xchar: perhaps xchar is unsigned and
- curx-x would be unsigned as well */
-{
-
- if (y == cury && x == curx)
- return;
- if(!ND && (curx != x || x <= 3)) { /* Extremely primitive */
- cmov(x, y); /* bunker!wtm */
- return;
- }
- if(abs(cury-y) <= 3 && abs(curx-x) <= 3)
- nocmov(x, y);
- else if((x <= 3 && abs(cury-y)<= 3) || (!CM && x<abs(curx-x))) {
- (void) putchar('\r');
- curx = 1;
- nocmov(x, y);
- } else if(!CM) {
- nocmov(x, y);
- } else
- cmov(x, y);
-}
-
-nocmov(x, y)
-{
- if (cury > y) {
- if(UP) {
- while (cury > y) { /* Go up. */
- xputs(UP);
- cury--;
- }
- } else if(CM) {
- cmov(x, y);
- } else if(HO) {
- home();
- curs(x, y);
- } /* else impossible("..."); */
- } else if (cury < y) {
- if(XD) {
- while(cury < y) {
- xputs(XD);
- cury++;
- }
- } else if(CM) {
- cmov(x, y);
- } else {
- while(cury < y) {
- xputc('\n');
- curx = 1;
- cury++;
- }
- }
- }
- if (curx < x) { /* Go to the right. */
- if(!ND) cmov(x, y); else /* bah */
- /* should instead print what is there already */
- while (curx < x) {
- xputs(ND);
- curx++;
- }
- } else if (curx > x) {
- while (curx > x) { /* Go to the left. */
- xputs(BC);
- curx--;
- }
- }
-}
-
-cmov(x, y)
-register x, y;
-{
- xputs(tgoto(CM, x-1, y-1));
- cury = y;
- curx = x;
-}
-
-xputc(c) char c; {
- (void) fputc(c, stdout);
-}
-
-xputs(s) char *s; {
- tputs(s, 1, xputc);
-}
-
-cl_end() {
- if(CE)
- xputs(CE);
- else { /* no-CE fix - free after Harold Rynes */
- /* this looks terrible, especially on a slow terminal
- but is better than nothing */
- register cx = curx, cy = cury;
-
- while(curx < COLNO) {
- xputc(' ');
- curx++;
- }
- curs(cx, cy);
- }
-}
-
-clear_screen() {
- xputs(CL);
- curx = cury = 1;
-}
-
-home()
-{
- if(HO)
- xputs(HO);
- else if(CM)
- xputs(tgoto(CM, 0, 0));
- else
- curs(1, 1); /* using UP ... */
- curx = cury = 1;
-}
-
-standoutbeg()
-{
- if(SO) xputs(SO);
-}
-
-standoutend()
-{
- if(SE) xputs(SE);
-}
-
-backsp()
-{
- xputs(BC);
- curx--;
-}
-
-bell()
-{
- (void) putchar('\007'); /* curx does not change */
- (void) fflush(stdout);
-}
-
-static short tmspc10[] = { /* from termcap */
- 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5
-};
-
-delay_output() {
- /* delay 50 ms - could also use a 'nap'-system call */
- /* BUG: if the padding character is visible, as it is on the 5620
- then this looks terrible. */
- if(!flags.nonull)
- tputs("50", 1, xputc);
-
- /* cbosgd!cbcephus!pds for SYS V R2 */
- /* is this terminfo, or what? */
- /* tputs("$<50>", 1, xputc); */
-
- else if(ospeed > 0 || ospeed < SIZE(tmspc10)) if(CM) {
- /* delay by sending cm(here) an appropriate number of times */
- register int cmlen = strlen(tgoto(CM, curx-1, cury-1));
- register int i = 500 + tmspc10[ospeed]/2;
-
- while(i > 0) {
- cmov(curx, cury);
- i -= cmlen*tmspc10[ospeed];
- }
- }
-}
-
-cl_eos() /* free after Robert Viduya */
-{ /* must only be called with curx = 1 */
-
- if(CD)
- xputs(CD);
- else {
- register int cx = curx, cy = cury;
- while(cury <= LI-2) {
- cl_end();
- xputc('\n');
- curx = 1;
- cury++;
- }
- cl_end();
- curs(cx, cy);
- }
-}
diff --git a/games/hack/hack.timeout.c b/games/hack/hack.timeout.c
deleted file mode 100644
index d828297684ff..000000000000
--- a/games/hack/hack.timeout.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.timeout.c - version 1.0.3 */
-
-#include "hack.h"
-
-timeout(){
-register struct prop *upp;
- if(Stoned) stoned_dialogue();
- for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
- if((upp->p_flgs & TIMEOUT) && !--upp->p_flgs) {
- if(upp->p_tofn) (*upp->p_tofn)();
- else switch(upp - u.uprops){
- case STONED:
- killer = "cockatrice";
- done("died");
- break;
- case SICK:
- pline("You die because of food poisoning.");
- killer = u.usick_cause;
- done("died");
- break;
- case FAST:
- pline("You feel yourself slowing down.");
- break;
- case CONFUSION:
- pline("You feel less confused now.");
- break;
- case BLIND:
- pline("You can see again.");
- setsee();
- break;
- case INVIS:
- on_scr(u.ux,u.uy);
- pline("You are no longer invisible.");
- break;
- case WOUNDED_LEGS:
- heal_legs();
- break;
- }
- }
-}
-
-/* He is being petrified - dialogue by inmet!tower */
-char *stoned_texts[] = {
- "You are slowing down.", /* 5 */
- "Your limbs are stiffening.", /* 4 */
- "Your limbs have turned to stone.", /* 3 */
- "You have turned to stone.", /* 2 */
- "You are a statue." /* 1 */
-};
-
-stoned_dialogue()
-{
- register long i = (Stoned & TIMEOUT);
-
- if(i > 0 && i <= SIZE(stoned_texts))
- pline(stoned_texts[SIZE(stoned_texts) - i]);
- if(i == 5)
- Fast = 0;
- if(i == 3)
- nomul(-3);
-}
diff --git a/games/hack/hack.topl.c b/games/hack/hack.topl.c
deleted file mode 100644
index 13a033d19c5e..000000000000
--- a/games/hack/hack.topl.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.topl.c - version 1.0.2 */
-
-#include "hack.h"
-#include <stdio.h>
-extern char *eos();
-extern int CO;
-
-char toplines[BUFSZ];
-xchar tlx, tly; /* set by pline; used by addtopl */
-
-struct topl {
- struct topl *next_topl;
- char *topl_text;
-} *old_toplines, *last_redone_topl;
-#define OTLMAX 20 /* max nr of old toplines remembered */
-
-doredotopl(){
- if(last_redone_topl)
- last_redone_topl = last_redone_topl->next_topl;
- if(!last_redone_topl)
- last_redone_topl = old_toplines;
- if(last_redone_topl){
- (void) strcpy(toplines, last_redone_topl->topl_text);
- }
- redotoplin();
- return(0);
-}
-
-redotoplin() {
- home();
- if(index(toplines, '\n')) cl_end();
- putstr(toplines);
- cl_end();
- tlx = curx;
- tly = cury;
- flags.toplin = 1;
- if(tly > 1)
- more();
-}
-
-remember_topl() {
-register struct topl *tl;
-register int cnt = OTLMAX;
- if(last_redone_topl &&
- !strcmp(toplines, last_redone_topl->topl_text)) return;
- if(old_toplines &&
- !strcmp(toplines, old_toplines->topl_text)) return;
- last_redone_topl = 0;
- tl = (struct topl *)
- alloc((unsigned)(strlen(toplines) + sizeof(struct topl) + 1));
- tl->next_topl = old_toplines;
- tl->topl_text = (char *)(tl + 1);
- (void) strcpy(tl->topl_text, toplines);
- old_toplines = tl;
- while(cnt && tl){
- cnt--;
- tl = tl->next_topl;
- }
- if(tl && tl->next_topl){
- free((char *) tl->next_topl);
- tl->next_topl = 0;
- }
-}
-
-addtopl(s) char *s; {
- curs(tlx,tly);
- if(tlx + strlen(s) > CO) putsym('\n');
- putstr(s);
- tlx = curx;
- tly = cury;
- flags.toplin = 1;
-}
-
-xmore(s)
-char *s; /* allowed chars besides space/return */
-{
- if(flags.toplin) {
- curs(tlx, tly);
- if(tlx + 8 > CO) putsym('\n'), tly++;
- }
-
- if(flags.standout)
- standoutbeg();
- putstr("--More--");
- if(flags.standout)
- standoutend();
-
- xwaitforspace(s);
- if(flags.toplin && tly > 1) {
- home();
- cl_end();
- docorner(1, tly-1);
- }
- flags.toplin = 0;
-}
-
-more(){
- xmore("");
-}
-
-cmore(s)
-register char *s;
-{
- xmore(s);
-}
-
-clrlin(){
- if(flags.toplin) {
- home();
- cl_end();
- if(tly > 1) docorner(1, tly-1);
- remember_topl();
- }
- flags.toplin = 0;
-}
-
-/*VARARGS1*/
-pline(line,arg1,arg2,arg3,arg4,arg5,arg6)
-register char *line,*arg1,*arg2,*arg3,*arg4,*arg5,*arg6;
-{
- char pbuf[BUFSZ];
- register char *bp = pbuf, *tl;
- register int n,n0;
-
- if(!line || !*line) return;
- if(!index(line, '%')) (void) strcpy(pbuf,line); else
- (void) sprintf(pbuf,line,arg1,arg2,arg3,arg4,arg5,arg6);
- if(flags.toplin == 1 && !strcmp(pbuf, toplines)) return;
- nscr(); /* %% */
-
- /* If there is room on the line, print message on same line */
- /* But messages like "You die..." deserve their own line */
- n0 = strlen(bp);
- if(flags.toplin == 1 && tly == 1 &&
- n0 + strlen(toplines) + 3 < CO-8 && /* leave room for --More-- */
- strncmp(bp, "You ", 4)) {
- (void) strcat(toplines, " ");
- (void) strcat(toplines, bp);
- tlx += 2;
- addtopl(bp);
- return;
- }
- if(flags.toplin == 1) more();
- remember_topl();
- toplines[0] = 0;
- while(n0){
- if(n0 >= CO){
- /* look for appropriate cut point */
- n0 = 0;
- for(n = 0; n < CO; n++) if(bp[n] == ' ')
- n0 = n;
- if(!n0) for(n = 0; n < CO-1; n++)
- if(!letter(bp[n])) n0 = n;
- if(!n0) n0 = CO-2;
- }
- (void) strncpy((tl = eos(toplines)), bp, n0);
- tl[n0] = 0;
- bp += n0;
-
- /* remove trailing spaces, but leave one */
- while(n0 > 1 && tl[n0-1] == ' ' && tl[n0-2] == ' ')
- tl[--n0] = 0;
-
- n0 = strlen(bp);
- if(n0 && tl[0]) (void) strcat(tl, "\n");
- }
- redotoplin();
-}
-
-putsym(c) char c; {
- switch(c) {
- case '\b':
- backsp();
- return;
- case '\n':
- curx = 1;
- cury++;
- if(cury > tly) tly = cury;
- break;
- default:
- if(curx == CO)
- putsym('\n'); /* 1 <= curx <= CO; avoid CO */
- else
- curx++;
- }
- (void) putchar(c);
-}
-
-putstr(s) register char *s; {
- while(*s) putsym(*s++);
-}
diff --git a/games/hack/hack.track.c b/games/hack/hack.track.c
deleted file mode 100644
index 6b41c2cdb118..000000000000
--- a/games/hack/hack.track.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.track.c - version 1.0.2 */
-
-#include "hack.h"
-
-#define UTSZ 50
-
-coord utrack[UTSZ];
-int utcnt = 0;
-int utpnt = 0;
-
-initrack(){
- utcnt = utpnt = 0;
-}
-
-/* add to track */
-settrack(){
- if(utcnt < UTSZ) utcnt++;
- if(utpnt == UTSZ) utpnt = 0;
- utrack[utpnt].x = u.ux;
- utrack[utpnt].y = u.uy;
- utpnt++;
-}
-
-coord *
-gettrack(x,y) register x,y; {
-register int i,cnt,dist;
-coord tc;
- cnt = utcnt;
- for(i = utpnt-1; cnt--; i--){
- if(i == -1) i = UTSZ-1;
- tc = utrack[i];
- dist = (x-tc.x)*(x-tc.x) + (y-tc.y)*(y-tc.y);
- if(dist < 3)
- return(dist ? &(utrack[i]) : 0);
- }
- return(0);
-}
diff --git a/games/hack/hack.trap.c b/games/hack/hack.trap.c
deleted file mode 100644
index e426dd1ccb98..000000000000
--- a/games/hack/hack.trap.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.trap.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern struct monst *makemon();
-
-char vowels[] = "aeiou";
-
-char *traps[] = {
- " bear trap",
- "n arrow trap",
- " dart trap",
- " trapdoor",
- " teleportation trap",
- " pit",
- " sleeping gas trap",
- " piercer",
- " mimic"
-};
-
-struct trap *
-maketrap(x,y,typ)
-register x,y,typ;
-{
- register struct trap *ttmp;
-
- ttmp = newtrap();
- ttmp->ttyp = typ;
- ttmp->tseen = 0;
- ttmp->once = 0;
- ttmp->tx = x;
- ttmp->ty = y;
- ttmp->ntrap = ftrap;
- ftrap = ttmp;
- return(ttmp);
-}
-
-dotrap(trap) register struct trap *trap; {
- register int ttype = trap->ttyp;
-
- nomul(0);
- if(trap->tseen && !rn2(5) && ttype != PIT)
- pline("You escape a%s.", traps[ttype]);
- else {
- trap->tseen = 1;
- switch(ttype) {
- case SLP_GAS_TRAP:
- pline("A cloud of gas puts you to sleep!");
- nomul(-rnd(25));
- break;
- case BEAR_TRAP:
- if(Levitation) {
- pline("You float over a bear trap.");
- break;
- }
- u.utrap = 4 + rn2(4);
- u.utraptype = TT_BEARTRAP;
- pline("A bear trap closes on your foot!");
- break;
- case PIERC:
- deltrap(trap);
- if(makemon(PM_PIERCER,u.ux,u.uy)) {
- pline("A piercer suddenly drops from the ceiling!");
- if(uarmh)
- pline("Its blow glances off your helmet.");
- else
- (void) thitu(3,d(4,6),"falling piercer");
- }
- break;
- case ARROW_TRAP:
- pline("An arrow shoots out at you!");
- if(!thitu(8,rnd(6),"arrow")){
- mksobj_at(ARROW, u.ux, u.uy);
- fobj->quan = 1;
- }
- break;
- case TRAPDOOR:
- if(!xdnstair) {
-pline("A trap door in the ceiling opens and a rock falls on your head!");
-if(uarmh) pline("Fortunately, you are wearing a helmet!");
- losehp(uarmh ? 2 : d(2,10),"falling rock");
- mksobj_at(ROCK, u.ux, u.uy);
- fobj->quan = 1;
- stackobj(fobj);
- if(Invisible) newsym(u.ux, u.uy);
- } else {
- register int newlevel = dlevel + 1;
- while(!rn2(4) && newlevel < 29)
- newlevel++;
- pline("A trap door opens up under you!");
- if(Levitation || u.ustuck) {
- pline("For some reason you don't fall in.");
- break;
- }
-
- goto_level(newlevel, FALSE);
- }
- break;
- case DART_TRAP:
- pline("A little dart shoots out at you!");
- if(thitu(7,rnd(3),"little dart")) {
- if(!rn2(6))
- poisoned("dart","poison dart");
- } else {
- mksobj_at(DART, u.ux, u.uy);
- fobj->quan = 1;
- }
- break;
- case TELEP_TRAP:
- if(trap->once) {
- deltrap(trap);
- newsym(u.ux,u.uy);
- vtele();
- } else {
- newsym(u.ux,u.uy);
- tele();
- }
- break;
- case PIT:
- if(Levitation) {
- pline("A pit opens up under you!");
- pline("You don't fall in!");
- break;
- }
- pline("You fall into a pit!");
- u.utrap = rn1(6,2);
- u.utraptype = TT_PIT;
- losehp(rnd(6),"fall into a pit");
- selftouch("Falling, you");
- break;
- default:
- impossible("You hit a trap of type %u", trap->ttyp);
- }
- }
-}
-
-mintrap(mtmp) register struct monst *mtmp; {
- register struct trap *trap = t_at(mtmp->mx, mtmp->my);
- register int wasintrap = mtmp->mtrapped;
-
- if(!trap) {
- mtmp->mtrapped = 0; /* perhaps teleported? */
- } else if(wasintrap) {
- if(!rn2(40)) mtmp->mtrapped = 0;
- } else {
- register int tt = trap->ttyp;
- int in_sight = cansee(mtmp->mx,mtmp->my);
- extern char mlarge[];
-
- if(mtmp->mtrapseen & (1 << tt)) {
- /* he has been in such a trap - perhaps he escapes */
- if(rn2(4)) return(0);
- }
- mtmp->mtrapseen |= (1 << tt);
- switch (tt) {
- case BEAR_TRAP:
- if(index(mlarge, mtmp->data->mlet)) {
- if(in_sight)
- pline("%s is caught in a bear trap!",
- Monnam(mtmp));
- else
- if(mtmp->data->mlet == 'o')
- pline("You hear the roaring of an angry bear!");
- mtmp->mtrapped = 1;
- }
- break;
- case PIT:
- /* there should be a mtmp/data -> floating */
- if(!index("EywBfk'& ", mtmp->data->mlet)) { /* ab */
- mtmp->mtrapped = 1;
- if(in_sight)
- pline("%s falls in a pit!", Monnam(mtmp));
- }
- break;
- case SLP_GAS_TRAP:
- if(!mtmp->msleep && !mtmp->mfroz) {
- mtmp->msleep = 1;
- if(in_sight)
- pline("%s suddenly falls asleep!",
- Monnam(mtmp));
- }
- break;
- case TELEP_TRAP:
- rloc(mtmp);
- if(in_sight && !cansee(mtmp->mx,mtmp->my))
- pline("%s suddenly disappears!",
- Monnam(mtmp));
- break;
- case ARROW_TRAP:
- if(in_sight) {
- pline("%s is hit by an arrow!",
- Monnam(mtmp));
- }
- mtmp->mhp -= 3;
- break;
- case DART_TRAP:
- if(in_sight) {
- pline("%s is hit by a dart!",
- Monnam(mtmp));
- }
- mtmp->mhp -= 2;
- /* not mondied here !! */
- break;
- case TRAPDOOR:
- if(!xdnstair) {
- mtmp->mhp -= 10;
- if(in_sight)
-pline("A trap door in the ceiling opens and a rock hits %s!", monnam(mtmp));
- break;
- }
- if(mtmp->data->mlet != 'w'){
- fall_down(mtmp);
- if(in_sight)
- pline("Suddenly, %s disappears out of sight.", monnam(mtmp));
- return(2); /* no longer on this level */
- }
- break;
- case PIERC:
- break;
- default:
- impossible("Some monster encountered a strange trap.");
- }
- }
- return(mtmp->mtrapped);
-}
-
-selftouch(arg) char *arg; {
- if(uwep && uwep->otyp == DEAD_COCKATRICE){
- pline("%s touch the dead cockatrice.", arg);
- pline("You turn to stone.");
- killer = objects[uwep->otyp].oc_name;
- done("died");
- }
-}
-
-float_up(){
- if(u.utrap) {
- if(u.utraptype == TT_PIT) {
- u.utrap = 0;
- pline("You float up, out of the pit!");
- } else {
- pline("You float up, only your leg is still stuck.");
- }
- } else
- pline("You start to float in the air!");
-}
-
-float_down(){
- register struct trap *trap;
- pline("You float gently to the ground.");
- if(trap = t_at(u.ux,u.uy))
- switch(trap->ttyp) {
- case PIERC:
- break;
- case TRAPDOOR:
- if(!xdnstair || u.ustuck) break;
- /* fall into next case */
- default:
- dotrap(trap);
- }
- pickup(1);
-}
-
-vtele() {
-#include "def.mkroom.h"
- register struct mkroom *croom;
- for(croom = &rooms[0]; croom->hx >= 0; croom++)
- if(croom->rtype == VAULT) {
- register x,y;
-
- x = rn2(2) ? croom->lx : croom->hx;
- y = rn2(2) ? croom->ly : croom->hy;
- if(teleok(x,y)) {
- teleds(x,y);
- return;
- }
- }
- tele();
-}
-
-tele() {
- extern coord getpos();
- coord cc;
- register int nux,nuy;
-
- if(Teleport_control) {
- pline("To what position do you want to be teleported?");
- cc = getpos(1, "the desired position"); /* 1: force valid */
- /* possible extensions: introduce a small error if
- magic power is low; allow transfer to solid rock */
- if(teleok(cc.x, cc.y)){
- teleds(cc.x, cc.y);
- return;
- }
- pline("Sorry ...");
- }
- do {
- nux = rnd(COLNO-1);
- nuy = rn2(ROWNO);
- } while(!teleok(nux, nuy));
- teleds(nux, nuy);
-}
-
-teleds(nux, nuy)
-register int nux,nuy;
-{
- if(Punished) unplacebc();
- unsee();
- u.utrap = 0;
- u.ustuck = 0;
- u.ux = nux;
- u.uy = nuy;
- setsee();
- if(Punished) placebc(1);
- if(u.uswallow){
- u.uswldtim = u.uswallow = 0;
- docrt();
- }
- nomul(0);
- if(levl[nux][nuy].typ == POOL && !Levitation)
- drown();
- (void) inshop();
- pickup(1);
- if(!Blind) read_engr_at(u.ux,u.uy);
-}
-
-teleok(x,y) register int x,y; { /* might throw him into a POOL */
- return( isok(x,y) && !IS_ROCK(levl[x][y].typ) && !m_at(x,y) &&
- !sobj_at(ENORMOUS_ROCK,x,y) && !t_at(x,y)
- );
- /* Note: gold is permitted (because of vaults) */
-}
-
-dotele() {
- extern char pl_character[];
-
- if(
-#ifdef WIZARD
- !wizard &&
-#endif WIZARD
- (!Teleportation || u.ulevel < 6 ||
- (pl_character[0] != 'W' && u.ulevel < 10))) {
- pline("You are not able to teleport at will.");
- return(0);
- }
- if(u.uhunger <= 100 || u.ustr < 6) {
- pline("You miss the strength for a teleport spell.");
- return(1);
- }
- tele();
- morehungry(100);
- return(1);
-}
-
-placebc(attach) int attach; {
- if(!uchain || !uball){
- impossible("Where are your chain and ball??");
- return;
- }
- uball->ox = uchain->ox = u.ux;
- uball->oy = uchain->oy = u.uy;
- if(attach){
- uchain->nobj = fobj;
- fobj = uchain;
- if(!carried(uball)){
- uball->nobj = fobj;
- fobj = uball;
- }
- }
-}
-
-unplacebc(){
- if(!carried(uball)){
- freeobj(uball);
- unpobj(uball);
- }
- freeobj(uchain);
- unpobj(uchain);
-}
-
-level_tele() {
-register int newlevel;
- if(Teleport_control) {
- char buf[BUFSZ];
-
- do {
- pline("To what level do you want to teleport? [type a number] ");
- getlin(buf);
- } while(!digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])));
- newlevel = atoi(buf);
- } else {
- newlevel = 5 + rn2(20); /* 5 - 24 */
- if(dlevel == newlevel)
- if(!xdnstair) newlevel--; else newlevel++;
- }
- if(newlevel >= 30) {
- if(newlevel > MAXLEVEL) newlevel = MAXLEVEL;
- pline("You arrive at the center of the earth ...");
- pline("Unfortunately it is here that hell is located.");
- if(Fire_resistance) {
- pline("But the fire doesn't seem to harm you.");
- } else {
- pline("You burn to a crisp.");
- dlevel = maxdlevel = newlevel;
- killer = "visit to the hell";
- done("burned");
- }
- }
- if(newlevel < 0) {
- newlevel = 0;
- pline("You are now high above the clouds ...");
- if(Levitation) {
- pline("You float gently down to earth.");
- done("escaped");
- }
- pline("Unfortunately, you don't know how to fly.");
- pline("You fall down a few thousand feet and break your neck.");
- dlevel = 0;
- killer = "fall";
- done("died");
- }
-
- goto_level(newlevel, FALSE); /* calls done("escaped") if newlevel==0 */
-}
-
-drown()
-{
- pline("You fall into a pool!");
- pline("You can't swim!");
- if(rn2(3) < u.uluck+2) {
- /* most scrolls become unreadable */
- register struct obj *obj;
-
- for(obj = invent; obj; obj = obj->nobj)
- if(obj->olet == SCROLL_SYM && rn2(12) > u.uluck)
- obj->otyp = SCR_BLANK_PAPER;
- /* we should perhaps merge these scrolls ? */
-
- pline("You attempt a teleport spell."); /* utcsri!carroll */
- (void) dotele();
- if(levl[u.ux][u.uy].typ != POOL) return;
- }
- pline("You drown ...");
- killer = "pool of water";
- done("drowned");
-}
diff --git a/games/hack/hack.tty.c b/games/hack/hack.tty.c
deleted file mode 100644
index 68fefc4e3958..000000000000
--- a/games/hack/hack.tty.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*-
- * Copyright (c) 1988 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)hack.tty.c 5.3 (Berkeley) 5/13/91";
-#endif /* not lint */
-
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.tty.c - version 1.0.3 */
-/* With thanks to the people who sent code for SYSV - hpscdi!jon,
- arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */
-
-#include "hack.h"
-#include <stdio.h>
-
-/*
- * The distinctions here are not BSD - rest but rather USG - rest, as
- * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
- */
-#ifdef BSD
-#define V7
-#else
-#define USG
-#endif BSD
-
-/*
- * Some systems may have getchar() return EOF for various reasons, and
- * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
- */
-#ifndef BSD
-#define NR_OF_EOFS 20
-#endif BSD
-
-
-#ifdef USG
-
-#include <termio.h>
-#define termstruct termio
-#define kill_sym c_cc[VKILL]
-#define erase_sym c_cc[VERASE]
-#define EXTABS TAB3
-#define tabflgs c_oflag
-#define echoflgs c_lflag
-#define cbrkflgs c_lflag
-#define CBRKMASK ICANON
-#define CBRKON ! /* reverse condition */
-#define OSPEED(x) ((x).c_cflag & CBAUD)
-#define GTTY(x) (ioctl(0, TCGETA, x))
-#define STTY(x) (ioctl(0, TCSETA, x)) /* TCSETAF? TCSETAW? */
-
-#else /* V7 */
-
-#include <sgtty.h>
-#define termstruct sgttyb
-#define kill_sym sg_kill
-#define erase_sym sg_erase
-#define EXTABS XTABS
-#define tabflgs sg_flags
-#define echoflgs sg_flags
-#define cbrkflgs sg_flags
-#define CBRKMASK CBREAK
-#define CBRKON /* empty */
-#define OSPEED(x) (x).sg_ospeed
-#define GTTY(x) (gtty(0, x))
-#define STTY(x) (stty(0, x))
-
-#endif USG
-
-extern short ospeed;
-static char erase_char, kill_char;
-static boolean settty_needed = FALSE;
-struct termstruct inittyb, curttyb;
-
-/*
- * Get initial state of terminal, set ospeed (for termcap routines)
- * and switch off tab expansion if necessary.
- * Called by startup() in termcap.c and after returning from ! or ^Z
- */
-gettty(){
- if(GTTY(&inittyb) < 0)
- perror("Hack (gettty)");
- curttyb = inittyb;
- ospeed = OSPEED(inittyb);
- erase_char = inittyb.erase_sym;
- kill_char = inittyb.kill_sym;
- getioctls();
-
- /* do not expand tabs - they might be needed inside a cm sequence */
- if(curttyb.tabflgs & EXTABS) {
- curttyb.tabflgs &= ~EXTABS;
- setctty();
- }
- settty_needed = TRUE;
-}
-
-/* reset terminal to original state */
-settty(s) char *s; {
- clear_screen();
- end_screen();
- if(s) printf(s);
- (void) fflush(stdout);
- if(STTY(&inittyb) < 0)
- perror("Hack (settty)");
- flags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
- flags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
- setioctls();
-}
-
-setctty(){
- if(STTY(&curttyb) < 0)
- perror("Hack (setctty)");
-}
-
-
-setftty(){
-register int ef = 0; /* desired value of flags & ECHO */
-register int cf = CBRKON(CBRKMASK); /* desired value of flags & CBREAK */
-register int change = 0;
- flags.cbreak = ON;
- flags.echo = OFF;
- /* Should use (ECHO|CRMOD) here instead of ECHO */
- if((curttyb.echoflgs & ECHO) != ef){
- curttyb.echoflgs &= ~ECHO;
-/* curttyb.echoflgs |= ef; */
- change++;
- }
- if((curttyb.cbrkflgs & CBRKMASK) != cf){
- curttyb.cbrkflgs &= ~CBRKMASK;
- curttyb.cbrkflgs |= cf;
-#ifdef USG
- /* be satisfied with one character; no timeout */
- curttyb.c_cc[VMIN] = 1; /* was VEOF */
- curttyb.c_cc[VTIME] = 0; /* was VEOL */
-#endif USG
- change++;
- }
- if(change){
- setctty();
- }
- start_screen();
-}
-
-
-/* fatal error */
-/*VARARGS1*/
-error(s,x,y) char *s; {
- if(settty_needed)
- settty((char *) 0);
- printf(s,x,y);
- putchar('\n');
- exit(1);
-}
-
-/*
- * Read a line closed with '\n' into the array char bufp[BUFSZ].
- * (The '\n' is not stored. The string is closed with a '\0'.)
- * Reading can be interrupted by an escape ('\033') - now the
- * resulting string is "\033".
- */
-getlin(bufp)
-register char *bufp;
-{
- register char *obufp = bufp;
- register int c;
-
- flags.toplin = 2; /* nonempty, no --More-- required */
- for(;;) {
- (void) fflush(stdout);
- if((c = getchar()) == EOF) {
- *bufp = 0;
- return;
- }
- if(c == '\033') {
- *obufp = c;
- obufp[1] = 0;
- return;
- }
- if(c == erase_char || c == '\b') {
- if(bufp != obufp) {
- bufp--;
- putstr("\b \b"); /* putsym converts \b */
- } else bell();
- } else if(c == '\n') {
- *bufp = 0;
- return;
- } else if(' ' <= c && c < '\177') {
- /* avoid isprint() - some people don't have it
- ' ' is not always a printing char */
- *bufp = c;
- bufp[1] = 0;
- putstr(bufp);
- if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
- bufp++;
- } else if(c == kill_char || c == '\177') { /* Robert Viduya */
- /* this test last - @ might be the kill_char */
- while(bufp != obufp) {
- bufp--;
- putstr("\b \b");
- }
- } else
- bell();
- }
-}
-
-getret() {
- cgetret("");
-}
-
-cgetret(s)
-register char *s;
-{
- putsym('\n');
- if(flags.standout)
- standoutbeg();
- putstr("Hit ");
- putstr(flags.cbreak ? "space" : "return");
- putstr(" to continue: ");
- if(flags.standout)
- standoutend();
- xwaitforspace(s);
-}
-
-char morc; /* tell the outside world what char he used */
-
-xwaitforspace(s)
-register char *s; /* chars allowed besides space or return */
-{
-register int c;
-
- morc = 0;
-
- while((c = readchar()) != '\n') {
- if(flags.cbreak) {
- if(c == ' ') break;
- if(s && index(s,c)) {
- morc = c;
- break;
- }
- bell();
- }
- }
-}
-
-char *
-parse()
-{
- static char inputline[COLNO];
- register foo;
-
- flags.move = 1;
- if(!Invisible) curs_on_u(); else home();
- while((foo = readchar()) >= '0' && foo <= '9')
- multi = 10*multi+foo-'0';
- if(multi) {
- multi--;
- save_cm = inputline;
- }
- inputline[0] = foo;
- inputline[1] = 0;
- if(foo == 'f' || foo == 'F'){
- inputline[1] = getchar();
-#ifdef QUEST
- if(inputline[1] == foo) inputline[2] = getchar(); else
-#endif QUEST
- inputline[2] = 0;
- }
- if(foo == 'm' || foo == 'M'){
- inputline[1] = getchar();
- inputline[2] = 0;
- }
- clrlin();
- return(inputline);
-}
-
-char
-readchar() {
- register int sym;
-
- (void) fflush(stdout);
- if((sym = getchar()) == EOF)
-#ifdef NR_OF_EOFS
- { /*
- * Some SYSV systems seem to return EOFs for various reasons
- * (?like when one hits break or for interrupted systemcalls?),
- * and we must see several before we quit.
- */
- register int cnt = NR_OF_EOFS;
- while (cnt--) {
- clearerr(stdin); /* omit if clearerr is undefined */
- if((sym = getchar()) != EOF) goto noteof;
- }
- end_of_input();
- noteof: ;
- }
-#else
- end_of_input();
-#endif NR_OF_EOFS
- if(flags.toplin == 1)
- flags.toplin = 2;
- return((char) sym);
-}
-
-end_of_input()
-{
- settty("End of input?\n");
- clearlocks();
- exit(0);
-}
diff --git a/games/hack/hack.u_init.c b/games/hack/hack.u_init.c
deleted file mode 100644
index bc06fa5ecfd5..000000000000
--- a/games/hack/hack.u_init.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.u_init.c - version 1.0.3 */
-
-#include "hack.h"
-#include <stdio.h>
-#include <signal.h>
-#define Strcpy (void) strcpy
-#define Strcat (void) strcat
-#define UNDEF_TYP 0
-#define UNDEF_SPE '\177'
-extern struct obj *addinv();
-extern char *eos();
-extern char plname[];
-
-struct you zerou;
-char pl_character[PL_CSIZ];
-char *(roles[]) = { /* must all have distinct first letter */
- /* roles[4] may be changed to -man */
- "Tourist", "Speleologist", "Fighter", "Knight",
- "Cave-man", "Wizard"
-};
-#define NR_OF_ROLES SIZE(roles)
-char rolesyms[NR_OF_ROLES + 1]; /* filled by u_init() */
-
-struct trobj {
- uchar trotyp;
- schar trspe;
- char trolet;
- Bitfield(trquan,6);
- Bitfield(trknown,1);
-};
-
-#ifdef WIZARD
-struct trobj Extra_objs[] = {
- { 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0 }
-};
-#endif WIZARD
-
-struct trobj Cave_man[] = {
- { MACE, 1, WEAPON_SYM, 1, 1 },
- { BOW, 1, WEAPON_SYM, 1, 1 },
- { ARROW, 0, WEAPON_SYM, 25, 1 }, /* quan is variable */
- { LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1 },
- { 0, 0, 0, 0, 0}
-};
-
-struct trobj Fighter[] = {
- { TWO_HANDED_SWORD, 0, WEAPON_SYM, 1, 1 },
- { RING_MAIL, 0, ARMOR_SYM, 1, 1 },
- { 0, 0, 0, 0, 0 }
-};
-
-struct trobj Knight[] = {
- { LONG_SWORD, 0, WEAPON_SYM, 1, 1 },
- { SPEAR, 2, WEAPON_SYM, 1, 1 },
- { RING_MAIL, 1, ARMOR_SYM, 1, 1 },
- { HELMET, 0, ARMOR_SYM, 1, 1 },
- { SHIELD, 0, ARMOR_SYM, 1, 1 },
- { PAIR_OF_GLOVES, 0, ARMOR_SYM, 1, 1 },
- { 0, 0, 0, 0, 0 }
-};
-
-struct trobj Speleologist[] = {
- { STUDDED_LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1 },
- { UNDEF_TYP, 0, POTION_SYM, 2, 0 },
- { FOOD_RATION, 0, FOOD_SYM, 3, 1 },
- { PICK_AXE, UNDEF_SPE, TOOL_SYM, 1, 0 },
- { ICE_BOX, 0, TOOL_SYM, 1, 0 },
- { 0, 0, 0, 0, 0}
-};
-
-struct trobj Tinopener[] = {
- { CAN_OPENER, 0, TOOL_SYM, 1, 1 },
- { 0, 0, 0, 0, 0 }
-};
-
-struct trobj Tourist[] = {
- { UNDEF_TYP, 0, FOOD_SYM, 10, 1 },
- { POT_EXTRA_HEALING, 0, POTION_SYM, 2, 0 },
- { EXPENSIVE_CAMERA, 0, TOOL_SYM, 1, 1 },
- { DART, 2, WEAPON_SYM, 25, 1 }, /* quan is variable */
- { 0, 0, 0, 0, 0 }
-};
-
-struct trobj Wizard[] = {
- { ELVEN_CLOAK, 0, ARMOR_SYM, 1, 1 },
- { UNDEF_TYP, UNDEF_SPE, WAND_SYM, 2, 0 },
- { UNDEF_TYP, UNDEF_SPE, RING_SYM, 2, 0 },
- { UNDEF_TYP, UNDEF_SPE, POTION_SYM, 2, 0 },
- { UNDEF_TYP, UNDEF_SPE, SCROLL_SYM, 3, 0 },
- { 0, 0, 0, 0, 0 }
-};
-
-u_init(){
-register int i;
-char exper = 'y', pc;
-extern char readchar();
- if(flags.female) /* should have been set in HACKOPTIONS */
- roles[4] = "Cave-woman";
- for(i = 0; i < NR_OF_ROLES; i++)
- rolesyms[i] = roles[i][0];
- rolesyms[i] = 0;
-
- if(pc = pl_character[0]) {
- if('a' <= pc && pc <= 'z') pc += 'A'-'a';
- if((i = role_index(pc)) >= 0)
- goto got_suffix; /* implies experienced */
- printf("\nUnknown role: %c\n", pc);
- pl_character[0] = pc = 0;
- }
-
- printf("\nAre you an experienced player? [ny] ");
-
- while(!index("ynYN \n\004", (exper = readchar())))
- bell();
- if(exper == '\004') /* Give him an opportunity to get out */
- end_of_input();
- printf("%c\n", exper); /* echo */
- if(index("Nn \n", exper)) {
- exper = 0;
- goto beginner;
- }
-
- printf("\nTell me what kind of character you are:\n");
- printf("Are you");
- for(i = 0; i < NR_OF_ROLES; i++) {
- printf(" a %s", roles[i]);
- if(i == 2) /* %% */
- printf(",\n\t");
- else if(i < NR_OF_ROLES - 2)
- printf(",");
- else if(i == NR_OF_ROLES - 2)
- printf(" or");
- }
- printf("? [%s] ", rolesyms);
-
- while(pc = readchar()) {
- if('a' <= pc && pc <= 'z') pc += 'A'-'a';
- if((i = role_index(pc)) >= 0) {
- printf("%c\n", pc); /* echo */
- (void) fflush(stdout); /* should be seen */
- break;
- }
- if(pc == '\n')
- break;
- if(pc == '\004') /* Give him the opportunity to get out */
- end_of_input();
- bell();
- }
- if(pc == '\n')
- pc = 0;
-
-beginner:
- if(!pc) {
- printf("\nI'll choose a character for you.\n");
- i = rn2(NR_OF_ROLES);
- pc = rolesyms[i];
- printf("This game you will be a%s %s.\n",
- exper ? "n experienced" : "",
- roles[i]);
- getret();
- /* give him some feedback in case mklev takes much time */
- (void) putchar('\n');
- (void) fflush(stdout);
- }
- if(exper) {
- roles[i][0] = pc;
- }
-
-got_suffix:
-
- (void) strncpy(pl_character, roles[i], PL_CSIZ-1);
- pl_character[PL_CSIZ-1] = 0;
- flags.beginner = 1;
- u = zerou;
- u.usym = '@';
- u.ulevel = 1;
- init_uhunger();
-#ifdef QUEST
- u.uhorizon = 6;
-#endif QUEST
- uarm = uarm2 = uarmh = uarms = uarmg = uwep = uball = uchain =
- uleft = uright = 0;
-
- switch(pc) {
- case 'c':
- case 'C':
- Cave_man[2].trquan = 12 + rnd(9)*rnd(9);
- u.uhp = u.uhpmax = 16;
- u.ustr = u.ustrmax = 18;
- ini_inv(Cave_man);
- break;
- case 't':
- case 'T':
- Tourist[3].trquan = 20 + rnd(20);
- u.ugold = u.ugold0 = rnd(1000);
- u.uhp = u.uhpmax = 10;
- u.ustr = u.ustrmax = 8;
- ini_inv(Tourist);
- if(!rn2(25)) ini_inv(Tinopener);
- break;
- case 'w':
- case 'W':
- for(i=1; i<=4; i++) if(!rn2(5))
- Wizard[i].trquan += rn2(3) - 1;
- u.uhp = u.uhpmax = 15;
- u.ustr = u.ustrmax = 16;
- ini_inv(Wizard);
- break;
- case 's':
- case 'S':
- Fast = INTRINSIC;
- Stealth = INTRINSIC;
- u.uhp = u.uhpmax = 12;
- u.ustr = u.ustrmax = 10;
- ini_inv(Speleologist);
- if(!rn2(10)) ini_inv(Tinopener);
- break;
- case 'k':
- case 'K':
- u.uhp = u.uhpmax = 12;
- u.ustr = u.ustrmax = 10;
- ini_inv(Knight);
- break;
- case 'f':
- case 'F':
- u.uhp = u.uhpmax = 14;
- u.ustr = u.ustrmax = 17;
- ini_inv(Fighter);
- break;
- default: /* impossible */
- u.uhp = u.uhpmax = 12;
- u.ustr = u.ustrmax = 16;
- }
- find_ac();
- if(!rn2(20)) {
- register int d = rn2(7) - 2; /* biased variation */
- u.ustr += d;
- u.ustrmax += d;
- }
-
-#ifdef WIZARD
- if(wizard) wiz_inv();
-#endif WIZARD
-
- /* make sure he can carry all he has - especially for T's */
- while(inv_weight() > 0 && u.ustr < 118)
- u.ustr++, u.ustrmax++;
-}
-
-ini_inv(trop) register struct trobj *trop; {
-register struct obj *obj;
-extern struct obj *mkobj();
- while(trop->trolet) {
- obj = mkobj(trop->trolet);
- obj->known = trop->trknown;
- /* not obj->dknown = 1; - let him look at it at least once */
- obj->cursed = 0;
- if(obj->olet == WEAPON_SYM){
- obj->quan = trop->trquan;
- trop->trquan = 1;
- }
- if(trop->trspe != UNDEF_SPE)
- obj->spe = trop->trspe;
- if(trop->trotyp != UNDEF_TYP)
- obj->otyp = trop->trotyp;
- else
- if(obj->otyp == WAN_WISHING) /* gitpyr!robert */
- obj->otyp = WAN_DEATH;
- obj->owt = weight(obj); /* defined after setting otyp+quan */
- obj = addinv(obj);
- if(obj->olet == ARMOR_SYM){
- switch(obj->otyp){
- case SHIELD:
- if(!uarms) setworn(obj, W_ARMS);
- break;
- case HELMET:
- if(!uarmh) setworn(obj, W_ARMH);
- break;
- case PAIR_OF_GLOVES:
- if(!uarmg) setworn(obj, W_ARMG);
- break;
- case ELVEN_CLOAK:
- if(!uarm2)
- setworn(obj, W_ARM);
- break;
- default:
- if(!uarm) setworn(obj, W_ARM);
- }
- }
- if(obj->olet == WEAPON_SYM)
- if(!uwep) setuwep(obj);
-#ifndef PYRAMID_BUG
- if(--trop->trquan) continue; /* make a similar object */
-#else
- if(trop->trquan) { /* check if zero first */
- --trop->trquan;
- if(trop->trquan)
- continue; /* make a similar object */
- }
-#endif PYRAMID_BUG
- trop++;
- }
-}
-
-#ifdef WIZARD
-wiz_inv(){
-register struct trobj *trop = &Extra_objs[0];
-extern char *getenv();
-register char *ep = getenv("INVENT");
-register int type;
- while(ep && *ep) {
- type = atoi(ep);
- ep = index(ep, ',');
- if(ep) while(*ep == ',' || *ep == ' ') ep++;
- if(type <= 0 || type > NROFOBJECTS) continue;
- trop->trotyp = type;
- trop->trolet = objects[type].oc_olet;
- trop->trspe = 4;
- trop->trknown = 1;
- trop->trquan = 1;
- ini_inv(trop);
- }
- /* give him a wand of wishing by default */
- trop->trotyp = WAN_WISHING;
- trop->trolet = WAND_SYM;
- trop->trspe = 20;
- trop->trknown = 1;
- trop->trquan = 1;
- ini_inv(trop);
-}
-#endif WIZARD
-
-plnamesuffix() {
-register char *p;
- if(p = rindex(plname, '-')) {
- *p = 0;
- pl_character[0] = p[1];
- pl_character[1] = 0;
- if(!plname[0]) {
- askname();
- plnamesuffix();
- }
- }
-}
-
-role_index(pc)
-char pc;
-{ /* must be called only from u_init() */
- /* so that rolesyms[] is defined */
- register char *cp;
-
- if(cp = index(rolesyms, pc))
- return(cp - rolesyms);
- return(-1);
-}
diff --git a/games/hack/hack.unix.c b/games/hack/hack.unix.c
deleted file mode 100644
index 03b294db8b10..000000000000
--- a/games/hack/hack.unix.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.unix.c - version 1.0.3 */
-
-/* This file collects some Unix dependencies; hack.pager.c contains some more */
-
-/*
- * The time is used for:
- * - seed for random()
- * - year on tombstone and yymmdd in record file
- * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
- * - night and midnight (the undead are dangerous at midnight)
- * - determination of what files are "very old"
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include "hack.h" /* mainly for index() which depends on BSD */
-
-#include <sys/types.h> /* for time_t and stat */
-#include <sys/stat.h>
-#ifdef BSD
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif BSD
-
-extern char *getenv();
-extern time_t time();
-
-setrandom()
-{
- (void) srandom((int) time ((time_t *) 0));
-}
-
-struct tm *
-getlt()
-{
- time_t date;
- struct tm *localtime();
-
- (void) time(&date);
- return(localtime(&date));
-}
-
-getyear()
-{
- return(1900 + getlt()->tm_year);
-}
-
-char *
-getdate()
-{
- static char datestr[7];
- register struct tm *lt = getlt();
-
- (void) sprintf(datestr, "%2d%2d%2d",
- lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
- if(datestr[2] == ' ') datestr[2] = '0';
- if(datestr[4] == ' ') datestr[4] = '0';
- return(datestr);
-}
-
-phase_of_the_moon() /* 0-7, with 0: new, 4: full */
-{ /* moon period: 29.5306 days */
- /* year: 365.2422 days */
- register struct tm *lt = getlt();
- register int epact, diy, golden;
-
- diy = lt->tm_yday;
- golden = (lt->tm_year % 19) + 1;
- epact = (11 * golden + 18) % 30;
- if ((epact == 25 && golden > 11) || epact == 24)
- epact++;
-
- return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
-}
-
-night()
-{
- register int hour = getlt()->tm_hour;
-
- return(hour < 6 || hour > 21);
-}
-
-midnight()
-{
- return(getlt()->tm_hour == 0);
-}
-
-struct stat buf, hbuf;
-
-gethdate(name) char *name; {
-/* old version - for people short of space */
-/*
-/* register char *np;
-/* if(stat(name, &hbuf))
-/* error("Cannot get status of %s.",
-/* (np = rindex(name, '/')) ? np+1 : name);
-/*
-/* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
-
-
-/*
- * The problem with #include <sys/param.h> is that this include file
- * does not exist on all systems, and moreover, that it sometimes includes
- * <sys/types.h> again, so that the compiler sees these typedefs twice.
- */
-#define MAXPATHLEN 1024
-
-register char *np, *path;
-char filename[MAXPATHLEN+1];
- if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL)
- path = "";
-
- for (;;) {
- if ((np = index(path, ':')) == NULL)
- np = path + strlen(path); /* point to end str */
- if (np - path <= 1) /* %% */
- (void) strcpy(filename, name);
- else {
- (void) strncpy(filename, path, np - path);
- filename[np - path] = '/';
- (void) strcpy(filename + (np - path) + 1, name);
- }
- if (stat(filename, &hbuf) == 0)
- return;
- if (*np == '\0')
- break;
- path = np + 1;
- }
- error("Cannot get status of %s.",
- (np = rindex(name, '/')) ? np+1 : name);
-}
-
-uptodate(fd) {
- if(fstat(fd, &buf)) {
- pline("Cannot get status of saved level? ");
- return(0);
- }
- if(buf.st_mtime < hbuf.st_mtime) {
- pline("Saved level is out of date. ");
- return(0);
- }
- return(1);
-}
-
-/* see whether we should throw away this xlock file */
-veryold(fd) {
- register int i;
- time_t date;
-
- if(fstat(fd, &buf)) return(0); /* cannot get status */
- if(buf.st_size != sizeof(int)) return(0); /* not an xlock file */
- (void) time(&date);
- if(date - buf.st_mtime < 3L*24L*60L*60L) { /* recent */
- extern int errno;
- int lockedpid; /* should be the same size as hackpid */
-
- if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) !=
- sizeof(lockedpid))
- /* strange ... */
- return(0);
-
- /* From: Rick Adams <seismo!rick>
- /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5.
- /* It will do nothing on V7 or 4.1bsd. */
- if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
- return(0);
- }
- (void) close(fd);
- for(i = 1; i <= MAXLEVEL; i++) { /* try to remove all */
- glo(i);
- (void) unlink(lock);
- }
- glo(0);
- if(unlink(lock)) return(0); /* cannot remove it */
- return(1); /* success! */
-}
-
-getlock()
-{
- extern int errno, hackpid, locknum;
- register int i = 0, fd;
-
- (void) fflush(stdout);
-
- /* we ignore QUIT and INT at this point */
- if (link(HLOCK, LLOCK) == -1) {
- register int errnosv = errno;
-
- perror(HLOCK);
- printf("Cannot link %s to %s\n", LLOCK, HLOCK);
- switch(errnosv) {
- case ENOENT:
- printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
- break;
- case EACCES:
- printf("It seems you don't have write permission here.\n");
- break;
- case EEXIST:
- printf("(Try again or rm %s.)\n", LLOCK);
- break;
- default:
- printf("I don't know what is wrong.");
- }
- getret();
- error("");
- /*NOTREACHED*/
- }
-
- regularize(lock);
- glo(0);
- if(locknum > 25) locknum = 25;
-
- do {
- if(locknum) lock[0] = 'a' + i++;
-
- if((fd = open(lock, 0)) == -1) {
- if(errno == ENOENT) goto gotlock; /* no such file */
- perror(lock);
- (void) unlink(LLOCK);
- error("Cannot open %s", lock);
- }
-
- if(veryold(fd)) /* if true, this closes fd and unlinks lock */
- goto gotlock;
- (void) close(fd);
- } while(i < locknum);
-
- (void) unlink(LLOCK);
- error(locknum ? "Too many hacks running now."
- : "There is a game in progress under your name.");
-gotlock:
- fd = creat(lock, FMASK);
- if(unlink(LLOCK) == -1)
- error("Cannot unlink %s.", LLOCK);
- if(fd == -1) {
- error("cannot creat lock file.");
- } else {
- if(write(fd, (char *) &hackpid, sizeof(hackpid))
- != sizeof(hackpid)){
- error("cannot write lock");
- }
- if(close(fd) == -1) {
- error("cannot close lock");
- }
- }
-}
-
-#ifdef MAIL
-
-/*
- * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
- * I don't know the details of his implementation.]
- * { Later note: he disliked my calling a general mailreader and felt that
- * hack should do the paging itself. But when I get mail, I want to put it
- * in some folder, reply, etc. - it would be unreasonable to put all these
- * functions in hack. }
- * The mail daemon '2' is at present not a real monster, but only a visual
- * effect. Thus, makemon() is superfluous. This might become otherwise,
- * however. The motion of '2' is less restrained than usual: diagonal moves
- * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
- * in a ROOM, even when you are Blind.
- * Its path should be longer when you are Telepat-hic and Blind.
- *
- * Interesting side effects:
- * - You can get rich by sending yourself a lot of mail and selling
- * it to the shopkeeper. Unfortunately mail isn't very valuable.
- * - You might die in case '2' comes along at a critical moment during
- * a fight and delivers a scroll the weight of which causes you to
- * collapse.
- *
- * Possible extensions:
- * - Open the file MAIL and do fstat instead of stat for efficiency.
- * (But sh uses stat, so this cannot be too bad.)
- * - Examine the mail and produce a scroll of mail called "From somebody".
- * - Invoke MAILREADER in such a way that only this single letter is read.
- *
- * - Make him lose his mail when a Nymph steals the letter.
- * - Do something to the text when the scroll is enchanted or cancelled.
- */
-#include "def.mkroom.h"
-static struct stat omstat,nmstat;
-static char *mailbox;
-static long laststattime;
-
-getmailstatus() {
- if(!(mailbox = getenv("MAIL")))
- return;
- if(stat(mailbox, &omstat)){
-#ifdef PERMANENT_MAILBOX
- pline("Cannot get status of MAIL=%s .", mailbox);
- mailbox = 0;
-#else
- omstat.st_mtime = 0;
-#endif PERMANENT_MAILBOX
- }
-}
-
-ckmailstatus() {
- if(!mailbox
-#ifdef MAILCKFREQ
- || moves < laststattime + MAILCKFREQ
-#endif MAILCKFREQ
- )
- return;
- laststattime = moves;
- if(stat(mailbox, &nmstat)){
-#ifdef PERMANENT_MAILBOX
- pline("Cannot get status of MAIL=%s anymore.", mailbox);
- mailbox = 0;
-#else
- nmstat.st_mtime = 0;
-#endif PERMANENT_MAILBOX
- } else if(nmstat.st_mtime > omstat.st_mtime) {
- if(nmstat.st_size)
- newmail();
- getmailstatus(); /* might be too late ... */
- }
-}
-
-newmail() {
- /* produce a scroll of mail */
- register struct obj *obj;
- register struct monst *md;
- extern char plname[];
- extern struct obj *mksobj(), *addinv();
- extern struct monst *makemon();
- extern struct permonst pm_mail_daemon;
-
- obj = mksobj(SCR_MAIL);
- if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
- mdrush(md,0);
-
- pline("\"Hello, %s! I have some mail for you.\"", plname);
- if(md) {
- if(dist(md->mx,md->my) > 2)
- pline("\"Catch!\"");
- more();
-
- /* let him disappear again */
- mdrush(md,1);
- mondead(md);
- }
-
- obj = addinv(obj);
- (void) identify(obj); /* set known and do prinv() */
-}
-
-/* make md run through the cave */
-mdrush(md,away)
-register struct monst *md;
-boolean away;
-{
- register int uroom = inroom(u.ux, u.uy);
- if(uroom >= 0) {
- register int tmp = rooms[uroom].fdoor;
- register int cnt = rooms[uroom].doorct;
- register int fx = u.ux, fy = u.uy;
- while(cnt--) {
- if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){
- fx = doors[tmp].x;
- fy = doors[tmp].y;
- }
- tmp++;
- }
- tmp_at(-1, md->data->mlet); /* open call */
- if(away) { /* interchange origin and destination */
- unpmon(md);
- tmp = fx; fx = md->mx; md->mx = tmp;
- tmp = fy; fy = md->my; md->my = tmp;
- }
- while(fx != md->mx || fy != md->my) {
- register int dx,dy,nfx = fx,nfy = fy,d1,d2;
-
- tmp_at(fx,fy);
- d1 = DIST(fx,fy,md->mx,md->my);
- for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
- if(dx || dy) {
- d2 = DIST(fx+dx,fy+dy,md->mx,md->my);
- if(d2 < d1) {
- d1 = d2;
- nfx = fx+dx;
- nfy = fy+dy;
- }
- }
- if(nfx != fx || nfy != fy) {
- fx = nfx;
- fy = nfy;
- } else {
- if(!away) {
- md->mx = fx;
- md->my = fy;
- }
- break;
- }
- }
- tmp_at(-1,-1); /* close call */
- }
- if(!away)
- pmon(md);
-}
-
-readmail() {
-#ifdef DEF_MAILREADER /* This implies that UNIX is defined */
- register char *mr = 0;
- more();
- if(!(mr = getenv("MAILREADER")))
- mr = DEF_MAILREADER;
- if(child(1)){
- execl(mr, mr, (char *) 0);
- exit(1);
- }
-#else DEF_MAILREADER
- (void) page_file(mailbox, FALSE);
-#endif DEF_MAILREADER
- /* get new stat; not entirely correct: there is a small time
- window where we do not see new mail */
- getmailstatus();
-}
-#endif MAIL
-
-regularize(s) /* normalize file name - we don't like ..'s or /'s */
-register char *s;
-{
- register char *lp;
-
- while((lp = index(s, '.')) || (lp = index(s, '/')))
- *lp = '_';
-}
diff --git a/games/hack/hack.vault.c b/games/hack/hack.vault.c
deleted file mode 100644
index a82c9f9a509b..000000000000
--- a/games/hack/hack.vault.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.vault.c - version 1.0.2 */
-
-#include "hack.h"
-#ifdef QUEST
-setgd(/* mtmp */) /* struct monst *mtmp; */ {}
-gd_move() { return(2); }
-gddead(mtmp) struct monst *mtmp; {}
-replgd(mtmp,mtmp2) struct monst *mtmp, *mtmp2; {}
-invault(){}
-
-#else
-
-
-#include "def.mkroom.h"
-extern struct monst *makemon();
-#define FCSIZ (ROWNO+COLNO)
-struct fakecorridor {
- xchar fx,fy,ftyp;
-};
-
-struct egd {
- int fcbeg, fcend; /* fcend: first unused pos */
- xchar gdx, gdy; /* goal of guard's walk */
- unsigned gddone:1;
- struct fakecorridor fakecorr[FCSIZ];
-};
-
-static struct permonst pm_guard =
- { "guard", '@', 12, 12, -1, 4, 10, sizeof(struct egd) };
-
-static struct monst *guard;
-static int gdlevel;
-#define EGD ((struct egd *)(&(guard->mextra[0])))
-
-static
-restfakecorr()
-{
- register fcx,fcy,fcbeg;
- register struct rm *crm;
-
- while((fcbeg = EGD->fcbeg) < EGD->fcend) {
- fcx = EGD->fakecorr[fcbeg].fx;
- fcy = EGD->fakecorr[fcbeg].fy;
- if((u.ux == fcx && u.uy == fcy) || cansee(fcx,fcy) ||
- m_at(fcx,fcy))
- return;
- crm = &levl[fcx][fcy];
- crm->typ = EGD->fakecorr[fcbeg].ftyp;
- if(!crm->typ) crm->seen = 0;
- newsym(fcx,fcy);
- EGD->fcbeg++;
- }
- /* it seems he left the corridor - let the guard disappear */
- mondead(guard);
- guard = 0;
-}
-
-static
-goldincorridor()
-{
- register int fci;
-
- for(fci = EGD->fcbeg; fci < EGD->fcend; fci++)
- if(g_at(EGD->fakecorr[fci].fx, EGD->fakecorr[fci].fy))
- return(1);
- return(0);
-}
-
-setgd(){
-register struct monst *mtmp;
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd){
- guard = mtmp;
- gdlevel = dlevel;
- return;
- }
- guard = 0;
-}
-
-invault(){
-register tmp = inroom(u.ux, u.uy);
- if(tmp < 0 || rooms[tmp].rtype != VAULT) {
- u.uinvault = 0;
- return;
- }
- if(++u.uinvault % 50 == 0 && (!guard || gdlevel != dlevel)) {
- char buf[BUFSZ];
- register x,y,dd,gx,gy;
-
- /* first find the goal for the guard */
- for(dd = 1; (dd < ROWNO || dd < COLNO); dd++) {
- for(y = u.uy-dd; y <= u.uy+dd; y++) {
- if(y < 0 || y > ROWNO-1) continue;
- for(x = u.ux-dd; x <= u.ux+dd; x++) {
- if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd)
- x = u.ux+dd;
- if(x < 0 || x > COLNO-1) continue;
- if(levl[x][y].typ == CORR) goto fnd;
- }
- }
- }
- impossible("Not a single corridor on this level??");
- tele();
- return;
-fnd:
- gx = x; gy = y;
-
- /* next find a good place for a door in the wall */
- x = u.ux; y = u.uy;
- while(levl[x][y].typ == ROOM) {
- register int dx,dy;
-
- dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
- dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
- if(abs(gx-x) >= abs(gy-y))
- x += dx;
- else
- y += dy;
- }
-
- /* make something interesting happen */
- if(!(guard = makemon(&pm_guard,x,y))) return;
- guard->isgd = guard->mpeaceful = 1;
- EGD->gddone = 0;
- gdlevel = dlevel;
- if(!cansee(guard->mx, guard->my)) {
- mondead(guard);
- guard = 0;
- return;
- }
-
- pline("Suddenly one of the Vault's guards enters!");
- pmon(guard);
- do {
- pline("\"Hello stranger, who are you?\" - ");
- getlin(buf);
- } while (!letter(buf[0]));
-
- if(!strcmp(buf, "Croesus") || !strcmp(buf, "Kroisos")) {
- pline("\"Oh, yes - of course. Sorry to have disturbed you.\"");
- mondead(guard);
- guard = 0;
- return;
- }
- clrlin();
- pline("\"I don't know you.\"");
- if(!u.ugold)
- pline("\"Please follow me.\"");
- else {
- pline("\"Most likely all that gold was stolen from this vault.\"");
- pline("\"Please drop your gold (say d$ ) and follow me.\"");
- }
- EGD->gdx = gx;
- EGD->gdy = gy;
- EGD->fcbeg = 0;
- EGD->fakecorr[0].fx = x;
- EGD->fakecorr[0].fy = y;
- EGD->fakecorr[0].ftyp = levl[x][y].typ;
- levl[x][y].typ = DOOR;
- EGD->fcend = 1;
- }
-}
-
-gd_move(){
-register int x,y,dx,dy,gx,gy,nx,ny,typ;
-register struct fakecorridor *fcp;
-register struct rm *crm;
- if(!guard || gdlevel != dlevel){
- impossible("Where is the guard?");
- return(2); /* died */
- }
- if(u.ugold || goldincorridor())
- return(0); /* didnt move */
- if(dist(guard->mx,guard->my) > 1 || EGD->gddone) {
- restfakecorr();
- return(0); /* didnt move */
- }
- x = guard->mx;
- y = guard->my;
- /* look around (hor & vert only) for accessible places */
- for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
- if(nx == x || ny == y) if(nx != x || ny != y)
- if(isok(nx,ny))
- if(!IS_WALL(typ = (crm = &levl[nx][ny])->typ) && typ != POOL) {
- register int i;
- for(i = EGD->fcbeg; i < EGD->fcend; i++)
- if(EGD->fakecorr[i].fx == nx &&
- EGD->fakecorr[i].fy == ny)
- goto nextnxy;
- if((i = inroom(nx,ny)) >= 0 && rooms[i].rtype == VAULT)
- goto nextnxy;
- /* seems we found a good place to leave him alone */
- EGD->gddone = 1;
- if(ACCESSIBLE(typ)) goto newpos;
- crm->typ = (typ == SCORR) ? CORR : DOOR;
- goto proceed;
- }
- nextnxy: ;
- }
- nx = x;
- ny = y;
- gx = EGD->gdx;
- gy = EGD->gdy;
- dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
- dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
- if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;
-
- while((typ = (crm = &levl[nx][ny])->typ) != 0) {
- /* in view of the above we must have IS_WALL(typ) or typ == POOL */
- /* must be a wall here */
- if(isok(nx+nx-x,ny+ny-y) && typ != POOL &&
- ZAP_POS(levl[nx+nx-x][ny+ny-y].typ)){
- crm->typ = DOOR;
- goto proceed;
- }
- if(dy && nx != x) {
- nx = x; ny = y+dy;
- continue;
- }
- if(dx && ny != y) {
- ny = y; nx = x+dx; dy = 0;
- continue;
- }
- /* I don't like this, but ... */
- crm->typ = DOOR;
- goto proceed;
- }
- crm->typ = CORR;
-proceed:
- if(cansee(nx,ny)) {
- mnewsym(nx,ny);
- prl(nx,ny);
- }
- fcp = &(EGD->fakecorr[EGD->fcend]);
- if(EGD->fcend++ == FCSIZ) panic("fakecorr overflow");
- fcp->fx = nx;
- fcp->fy = ny;
- fcp->ftyp = typ;
-newpos:
- if(EGD->gddone) nx = ny = 0;
- guard->mx = nx;
- guard->my = ny;
- pmon(guard);
- restfakecorr();
- return(1);
-}
-
-gddead(){
- guard = 0;
-}
-
-replgd(mtmp,mtmp2)
-register struct monst *mtmp, *mtmp2;
-{
- if(mtmp == guard)
- guard = mtmp2;
-}
-
-#endif QUEST
diff --git a/games/hack/hack.version.c b/games/hack/hack.version.c
deleted file mode 100644
index ae0a12d3535e..000000000000
--- a/games/hack/hack.version.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.version.c - version 1.0.3 */
-/* $Header: /home/cvs/386BSD/src/games/hack/hack.version.c,v 1.1.1.1 1993/06/12 14:40:26 rgrimes Exp $ */
-
-#include "date.h"
-
-doversion(){
- pline("%s 1.0.3 - last edit %s.", (
-#ifdef QUEST
- "Quest"
-#else
- "Hack"
-#endif QUEST
- ), datestring);
- return(0);
-}
diff --git a/games/hack/hack.wield.c b/games/hack/hack.wield.c
deleted file mode 100644
index d0609a1cb6d4..000000000000
--- a/games/hack/hack.wield.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.wield.c - version 1.0.3 */
-
-#include "hack.h"
-extern struct obj zeroobj;
-
-setuwep(obj) register struct obj *obj; {
- setworn(obj, W_WEP);
-}
-
-dowield()
-{
- register struct obj *wep;
- register int res = 0;
-
- multi = 0;
- if(!(wep = getobj("#-)", "wield"))) /* nothing */;
- else if(uwep == wep)
- pline("You are already wielding that!");
- else if(uwep && uwep->cursed)
- pline("The %s welded to your hand!",
- aobjnam(uwep, "are"));
- else if(wep == &zeroobj) {
- if(uwep == 0){
- pline("You are already empty handed.");
- } else {
- setuwep((struct obj *) 0);
- res++;
- pline("You are empty handed.");
- }
- } else if(uarms && wep->otyp == TWO_HANDED_SWORD)
- pline("You cannot wield a two-handed sword and wear a shield.");
- else if(wep->owornmask & (W_ARMOR | W_RING))
- pline("You cannot wield that!");
- else {
- setuwep(wep);
- res++;
- if(uwep->cursed)
- pline("The %s %s to your hand!",
- aobjnam(uwep, "weld"),
- (uwep->quan == 1) ? "itself" : "themselves"); /* a3 */
- else prinv(uwep);
- }
- return(res);
-}
-
-corrode_weapon(){
- if(!uwep || uwep->olet != WEAPON_SYM) return; /* %% */
- if(uwep->rustfree)
- pline("Your %s not affected.", aobjnam(uwep, "are"));
- else {
- pline("Your %s!", aobjnam(uwep, "corrode"));
- uwep->spe--;
- }
-}
-
-chwepon(otmp,amount)
-register struct obj *otmp;
-register amount;
-{
-register char *color = (amount < 0) ? "black" : "green";
-register char *time;
- if(!uwep || uwep->olet != WEAPON_SYM) {
- strange_feeling(otmp,
- (amount > 0) ? "Your hands twitch."
- : "Your hands itch.");
- return(0);
- }
-
- if(uwep->otyp == WORM_TOOTH && amount > 0) {
- uwep->otyp = CRYSKNIFE;
- pline("Your weapon seems sharper now.");
- uwep->cursed = 0;
- return(1);
- }
-
- if(uwep->otyp == CRYSKNIFE && amount < 0) {
- uwep->otyp = WORM_TOOTH;
- pline("Your weapon looks duller now.");
- return(1);
- }
-
- /* there is a (soft) upper limit to uwep->spe */
- if(amount > 0 && uwep->spe > 5 && rn2(3)) {
- pline("Your %s violently green for a while and then evaporate%s.",
- aobjnam(uwep, "glow"), plur(uwep->quan));
- while(uwep) /* let all of them disappear */
- /* note: uwep->quan = 1 is nogood if unpaid */
- useup(uwep);
- return(1);
- }
- if(!rn2(6)) amount *= 2;
- time = (amount*amount == 1) ? "moment" : "while";
- pline("Your %s %s for a %s.",
- aobjnam(uwep, "glow"), color, time);
- uwep->spe += amount;
- if(amount > 0) uwep->cursed = 0;
- return(1);
-}
diff --git a/games/hack/hack.wizard.c b/games/hack/hack.wizard.c
deleted file mode 100644
index 835ecc3dfbd9..000000000000
--- a/games/hack/hack.wizard.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.wizard.c - version 1.0.3 */
-
-/* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */
-
-#include "hack.h"
-extern struct permonst pm_wizard;
-extern struct monst *makemon();
-
-#define WIZSHOT 6 /* one chance in WIZSHOT that wizard will try magic */
-#define BOLT_LIM 8 /* from this distance D and 1 will try to hit you */
-
-char wizapp[] = "@DNPTUVXcemntx";
-
-/* If he has found the Amulet, make the wizard appear after some time */
-amulet(){
- register struct obj *otmp;
- register struct monst *mtmp;
-
- if(!flags.made_amulet || !flags.no_of_wizards)
- return;
- /* find wizard, and wake him if necessary */
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->data->mlet == '1' && mtmp->msleep && !rn2(40))
- for(otmp = invent; otmp; otmp = otmp->nobj)
- if(otmp->olet == AMULET_SYM && !otmp->spe) {
- mtmp->msleep = 0;
- if(dist(mtmp->mx,mtmp->my) > 2)
- pline(
- "You get the creepy feeling that somebody noticed your taking the Amulet."
- );
- return;
- }
-}
-
-wiz_hit(mtmp)
-register struct monst *mtmp;
-{
- /* if we have stolen or found the amulet, we disappear */
- if(mtmp->minvent && mtmp->minvent->olet == AMULET_SYM &&
- mtmp->minvent->spe == 0) {
- /* vanish -- very primitive */
- fall_down(mtmp);
- return(1);
- }
-
- /* if it is lying around someplace, we teleport to it */
- if(!carrying(AMULET_OF_YENDOR)) {
- register struct obj *otmp;
-
- for(otmp = fobj; otmp; otmp = otmp->nobj)
- if(otmp->olet == AMULET_SYM && !otmp->spe) {
- if((u.ux != otmp->ox || u.uy != otmp->oy) &&
- !m_at(otmp->ox, otmp->oy)) {
-
- /* teleport to it and pick it up */
- mtmp->mx = otmp->ox;
- mtmp->my = otmp->oy;
- freeobj(otmp);
- mpickobj(mtmp, otmp);
- pmon(mtmp);
- return(0);
- }
- goto hithim;
- }
- return(0); /* we don't know where it is */
- }
-hithim:
- if(rn2(2)) { /* hit - perhaps steal */
-
- /* if hit 1/20 chance of stealing amulet & vanish
- - amulet is on level 26 again. */
- if(hitu(mtmp, d(mtmp->data->damn,mtmp->data->damd))
- && !rn2(20) && stealamulet(mtmp))
- ;
- }
- else
- inrange(mtmp); /* try magic */
- return(0);
-}
-
-inrange(mtmp)
-register struct monst *mtmp;
-{
- register schar tx,ty;
-
- /* do nothing if cancelled (but make '1' say something) */
- if(mtmp->data->mlet != '1' && mtmp->mcan)
- return;
-
- /* spit fire only when both in a room or both in a corridor */
- if(inroom(u.ux,u.uy) != inroom(mtmp->mx,mtmp->my)) return;
- tx = u.ux - mtmp->mx;
- ty = u.uy - mtmp->my;
- if((!tx && abs(ty) < BOLT_LIM) || (!ty && abs(tx) < BOLT_LIM)
- || (abs(tx) == abs(ty) && abs(tx) < BOLT_LIM)){
- switch(mtmp->data->mlet) {
- case 'D':
- /* spit fire in the direction of @ (not nec. hitting) */
- buzz(-1,mtmp->mx,mtmp->my,sgn(tx),sgn(ty));
- break;
- case '1':
- if(rn2(WIZSHOT)) break;
- /* if you zapped wizard with wand of cancellation,
- he has to shake off the effects before he can throw
- spells successfully. 1/2 the time they fail anyway */
- if(mtmp->mcan || rn2(2)) {
- if(canseemon(mtmp))
- pline("%s makes a gesture, then curses.",
- Monnam(mtmp));
- else
- pline("You hear mumbled cursing.");
- if(!rn2(3)) {
- mtmp->mspeed = 0;
- mtmp->minvis = 0;
- }
- if(!rn2(3))
- mtmp->mcan = 0;
- } else {
- if(canseemon(mtmp)){
- if(!rn2(6) && !Invis) {
- pline("%s hypnotizes you.", Monnam(mtmp));
- nomul(rn2(3) + 3);
- break;
- } else
- pline("%s chants an incantation.",
- Monnam(mtmp));
- } else
- pline("You hear a mumbled incantation.");
- switch(rn2(Invis ? 5 : 6)) {
- case 0:
- /* create a nasty monster from a deep level */
- /* (for the moment, 'nasty' is not implemented) */
- (void) makemon((struct permonst *)0, u.ux, u.uy);
- break;
- case 1:
- pline("\"Destroy the thief, my pets!\"");
- aggravate(); /* aggravate all the monsters */
- /* fall into next case */
- case 2:
- if (flags.no_of_wizards == 1 && rnd(5) == 0)
- /* if only 1 wizard, clone himself */
- clonewiz(mtmp);
- break;
- case 3:
- if(mtmp->mspeed == MSLOW)
- mtmp->mspeed = 0;
- else
- mtmp->mspeed = MFAST;
- break;
- case 4:
- mtmp->minvis = 1;
- break;
- case 5:
- /* Only if not Invisible */
- pline("You hear a clap of thunder!");
- /* shoot a bolt of fire or cold, or a sleep ray */
- buzz(-rnd(3),mtmp->mx,mtmp->my,sgn(tx),sgn(ty));
- break;
- }
- }
- }
- if(u.uhp < 1) done_in_by(mtmp);
- }
-}
-
-aggravate()
-{
- register struct monst *mtmp;
-
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
- mtmp->msleep = 0;
- if(mtmp->mfroz && !rn2(5))
- mtmp->mfroz = 0;
- }
-}
-
-clonewiz(mtmp)
-register struct monst *mtmp;
-{
- register struct monst *mtmp2;
-
- if(mtmp2 = makemon(PM_WIZARD, mtmp->mx, mtmp->my)) {
- flags.no_of_wizards = 2;
- unpmon(mtmp2);
- mtmp2->mappearance = wizapp[rn2(sizeof(wizapp)-1)];
- pmon(mtmp);
- }
-}
diff --git a/games/hack/hack.worm.c b/games/hack/hack.worm.c
deleted file mode 100644
index ba3505d19b4f..000000000000
--- a/games/hack/hack.worm.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.worm.c - version 1.0.2 */
-
-#include "hack.h"
-#ifndef NOWORM
-#include "def.wseg.h"
-
-struct wseg *wsegs[32]; /* linked list, tail first */
-struct wseg *wheads[32];
-long wgrowtime[32];
-
-getwn(mtmp) struct monst *mtmp; {
-register tmp;
- for(tmp=1; tmp<32; tmp++) if(!wsegs[tmp]) {
- mtmp->wormno = tmp;
- return(1);
- }
- return(0); /* level infested with worms */
-}
-
-/* called to initialize a worm unless cut in half */
-initworm(mtmp) struct monst *mtmp; {
-register struct wseg *wtmp;
-register tmp = mtmp->wormno;
- if(!tmp) return;
- wheads[tmp] = wsegs[tmp] = wtmp = newseg();
- wgrowtime[tmp] = 0;
- wtmp->wx = mtmp->mx;
- wtmp->wy = mtmp->my;
-/* wtmp->wdispl = 0; */
- wtmp->nseg = 0;
-}
-
-worm_move(mtmp) struct monst *mtmp; {
-register struct wseg *wtmp, *whd;
-register tmp = mtmp->wormno;
- wtmp = newseg();
- wtmp->wx = mtmp->mx;
- wtmp->wy = mtmp->my;
- wtmp->nseg = 0;
-/* wtmp->wdispl = 0; */
- (whd = wheads[tmp])->nseg = wtmp;
- wheads[tmp] = wtmp;
- if(cansee(whd->wx,whd->wy)){
- unpmon(mtmp);
- atl(whd->wx, whd->wy, '~');
- whd->wdispl = 1;
- } else whd->wdispl = 0;
- if(wgrowtime[tmp] <= moves) {
- if(!wgrowtime[tmp]) wgrowtime[tmp] = moves + rnd(5);
- else wgrowtime[tmp] += 2+rnd(15);
- mtmp->mhpmax += 3;
- mtmp->mhp += 3;
- return;
- }
- whd = wsegs[tmp];
- wsegs[tmp] = whd->nseg;
- remseg(whd);
-}
-
-worm_nomove(mtmp) register struct monst *mtmp; {
-register tmp;
-register struct wseg *wtmp;
- tmp = mtmp->wormno;
- wtmp = wsegs[tmp];
- if(wtmp == wheads[tmp]) return;
- if(wtmp == 0 || wtmp->nseg == 0) panic("worm_nomove?");
- wsegs[tmp] = wtmp->nseg;
- remseg(wtmp);
- mtmp->mhp -= 3; /* mhpmax not changed ! */
-}
-
-wormdead(mtmp) register struct monst *mtmp; {
-register tmp = mtmp->wormno;
-register struct wseg *wtmp, *wtmp2;
- if(!tmp) return;
- mtmp->wormno = 0;
- for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
- wtmp2 = wtmp->nseg;
- remseg(wtmp);
- }
- wsegs[tmp] = 0;
-}
-
-wormhit(mtmp) register struct monst *mtmp; {
-register tmp = mtmp->wormno;
-register struct wseg *wtmp;
- if(!tmp) return; /* worm without tail */
- for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp->nseg)
- (void) hitu(mtmp,1);
-}
-
-wormsee(tmp) register unsigned tmp; {
-register struct wseg *wtmp = wsegs[tmp];
- if(!wtmp) panic("wormsee: wtmp==0");
- for(; wtmp->nseg; wtmp = wtmp->nseg)
- if(!cansee(wtmp->wx,wtmp->wy) && wtmp->wdispl){
- newsym(wtmp->wx, wtmp->wy);
- wtmp->wdispl = 0;
- }
-}
-
-pwseg(wtmp) register struct wseg *wtmp; {
- if(!wtmp->wdispl){
- atl(wtmp->wx, wtmp->wy, '~');
- wtmp->wdispl = 1;
- }
-}
-
-cutworm(mtmp,x,y,weptyp)
-register struct monst *mtmp;
-register xchar x,y;
-register uchar weptyp; /* uwep->otyp or 0 */
-{
- register struct wseg *wtmp, *wtmp2;
- register struct monst *mtmp2;
- register tmp,tmp2;
- if(mtmp->mx == x && mtmp->my == y) return; /* hit headon */
-
- /* cutting goes best with axe or sword */
- tmp = rnd(20);
- if(weptyp == LONG_SWORD || weptyp == TWO_HANDED_SWORD ||
- weptyp == AXE) tmp += 5;
- if(tmp < 12) return;
-
- /* if tail then worm just loses a tail segment */
- tmp = mtmp->wormno;
- wtmp = wsegs[tmp];
- if(wtmp->wx == x && wtmp->wy == y){
- wsegs[tmp] = wtmp->nseg;
- remseg(wtmp);
- return;
- }
-
- /* cut the worm in two halves */
- mtmp2 = newmonst(0);
- *mtmp2 = *mtmp;
- mtmp2->mxlth = mtmp2->mnamelth = 0;
-
- /* sometimes the tail end dies */
- if(rn2(3) || !getwn(mtmp2)){
- monfree(mtmp2);
- tmp2 = 0;
- } else {
- tmp2 = mtmp2->wormno;
- wsegs[tmp2] = wsegs[tmp];
- wgrowtime[tmp2] = 0;
- }
- do {
- if(wtmp->nseg->wx == x && wtmp->nseg->wy == y){
- if(tmp2) wheads[tmp2] = wtmp;
- wsegs[tmp] = wtmp->nseg->nseg;
- remseg(wtmp->nseg);
- wtmp->nseg = 0;
- if(tmp2){
- pline("You cut the worm in half.");
- mtmp2->mhpmax = mtmp2->mhp =
- d(mtmp2->data->mlevel, 8);
- mtmp2->mx = wtmp->wx;
- mtmp2->my = wtmp->wy;
- mtmp2->nmon = fmon;
- fmon = mtmp2;
- pmon(mtmp2);
- } else {
- pline("You cut off part of the worm's tail.");
- remseg(wtmp);
- }
- mtmp->mhp /= 2;
- return;
- }
- wtmp2 = wtmp->nseg;
- if(!tmp2) remseg(wtmp);
- wtmp = wtmp2;
- } while(wtmp->nseg);
- panic("Cannot find worm segment");
-}
-
-remseg(wtmp) register struct wseg *wtmp; {
- if(wtmp->wdispl)
- newsym(wtmp->wx, wtmp->wy);
- free((char *) wtmp);
-}
-#endif NOWORM
diff --git a/games/hack/hack.worn.c b/games/hack/hack.worn.c
deleted file mode 100644
index bfec47f21996..000000000000
--- a/games/hack/hack.worn.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.worn.c - version 1.0.2 */
-
-#include "hack.h"
-
-struct worn {
- long w_mask;
- struct obj **w_obj;
-} worn[] = {
- { W_ARM, &uarm },
- { W_ARM2, &uarm2 },
- { W_ARMH, &uarmh },
- { W_ARMS, &uarms },
- { W_ARMG, &uarmg },
- { W_RINGL, &uleft },
- { W_RINGR, &uright },
- { W_WEP, &uwep },
- { W_BALL, &uball },
- { W_CHAIN, &uchain },
- { 0, 0 }
-};
-
-setworn(obj, mask)
-register struct obj *obj;
-long mask;
-{
- register struct worn *wp;
- register struct obj *oobj;
-
- for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
- oobj = *(wp->w_obj);
- if(oobj && !(oobj->owornmask & wp->w_mask))
- impossible("Setworn: mask = %ld.", wp->w_mask);
- if(oobj) oobj->owornmask &= ~wp->w_mask;
- if(obj && oobj && wp->w_mask == W_ARM){
- if(uarm2) {
- impossible("Setworn: uarm2 set?");
- } else
- setworn(uarm, W_ARM2);
- }
- *(wp->w_obj) = obj;
- if(obj) obj->owornmask |= wp->w_mask;
- }
- if(uarm2 && !uarm) {
- uarm = uarm2;
- uarm2 = 0;
- uarm->owornmask ^= (W_ARM | W_ARM2);
- }
-}
-
-/* called e.g. when obj is destroyed */
-setnotworn(obj) register struct obj *obj; {
- register struct worn *wp;
-
- for(wp = worn; wp->w_mask; wp++)
- if(obj == *(wp->w_obj)) {
- *(wp->w_obj) = 0;
- obj->owornmask &= ~wp->w_mask;
- }
- if(uarm2 && !uarm) {
- uarm = uarm2;
- uarm2 = 0;
- uarm->owornmask ^= (W_ARM | W_ARM2);
- }
-}
diff --git a/games/hack/hack.zap.c b/games/hack/hack.zap.c
deleted file mode 100644
index e1472b56906f..000000000000
--- a/games/hack/hack.zap.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* hack.zap.c - version 1.0.3 */
-
-#include "hack.h"
-
-extern struct obj *mkobj_at();
-extern struct monst *makemon(), *mkmon_at(), youmonst;
-struct monst *bhit();
-char *exclam();
-
-char *fl[]= {
- "magic missile",
- "bolt of fire",
- "sleep ray",
- "bolt of cold",
- "death ray"
-};
-
-/* Routines for IMMEDIATE wands. */
-/* bhitm: monster mtmp was hit by the effect of wand otmp */
-bhitm(mtmp, otmp)
-register struct monst *mtmp;
-register struct obj *otmp;
-{
- wakeup(mtmp);
- switch(otmp->otyp) {
- case WAN_STRIKING:
- if(u.uswallow || rnd(20) < 10+mtmp->data->ac) {
- register int tmp = d(2,12);
- hit("wand", mtmp, exclam(tmp));
- mtmp->mhp -= tmp;
- if(mtmp->mhp < 1) killed(mtmp);
- } else miss("wand", mtmp);
- break;
- case WAN_SLOW_MONSTER:
- mtmp->mspeed = MSLOW;
- break;
- case WAN_SPEED_MONSTER:
- mtmp->mspeed = MFAST;
- break;
- case WAN_UNDEAD_TURNING:
- if(index(UNDEAD,mtmp->data->mlet)) {
- mtmp->mhp -= rnd(8);
- if(mtmp->mhp < 1) killed(mtmp);
- else mtmp->mflee = 1;
- }
- break;
- case WAN_POLYMORPH:
- if( newcham(mtmp,&mons[rn2(CMNUM)]) )
- objects[otmp->otyp].oc_name_known = 1;
- break;
- case WAN_CANCELLATION:
- mtmp->mcan = 1;
- break;
- case WAN_TELEPORTATION:
- rloc(mtmp);
- break;
- case WAN_MAKE_INVISIBLE:
- mtmp->minvis = 1;
- break;
-#ifdef WAN_PROBING
- case WAN_PROBING:
- mstatusline(mtmp);
- break;
-#endif WAN_PROBING
- default:
- impossible("What an interesting wand (%u)", otmp->otyp);
- }
-}
-
-bhito(obj, otmp) /* object obj was hit by the effect of wand otmp */
-register struct obj *obj, *otmp; /* returns TRUE if sth was done */
-{
- register int res = TRUE;
-
- if(obj == uball || obj == uchain)
- res = FALSE;
- else
- switch(otmp->otyp) {
- case WAN_POLYMORPH:
- /* preserve symbol and quantity, but turn rocks into gems */
- mkobj_at((obj->otyp == ROCK || obj->otyp == ENORMOUS_ROCK)
- ? GEM_SYM : obj->olet,
- obj->ox, obj->oy) -> quan = obj->quan;
- delobj(obj);
- break;
- case WAN_STRIKING:
- if(obj->otyp == ENORMOUS_ROCK)
- fracture_rock(obj);
- else
- res = FALSE;
- break;
- case WAN_CANCELLATION:
- if(obj->spe && obj->olet != AMULET_SYM) {
- obj->known = 0;
- obj->spe = 0;
- }
- break;
- case WAN_TELEPORTATION:
- rloco(obj);
- break;
- case WAN_MAKE_INVISIBLE:
- obj->oinvis = 1;
- break;
- case WAN_UNDEAD_TURNING:
- res = revive(obj);
- break;
- case WAN_SLOW_MONSTER: /* no effect on objects */
- case WAN_SPEED_MONSTER:
-#ifdef WAN_PROBING
- case WAN_PROBING:
-#endif WAN_PROBING
- res = FALSE;
- break;
- default:
- impossible("What an interesting wand (%u)", otmp->otyp);
- }
- return(res);
-}
-
-dozap()
-{
- register struct obj *obj;
- xchar zx,zy;
-
- obj = getobj("/", "zap");
- if(!obj) return(0);
- if(obj->spe < 0 || (obj->spe == 0 && rn2(121))) {
- pline("Nothing Happens.");
- return(1);
- }
- if(obj->spe == 0)
- pline("You wrest one more spell from the worn-out wand.");
- if(!(objects[obj->otyp].bits & NODIR) && !getdir(1))
- return(1); /* make him pay for knowing !NODIR */
- obj->spe--;
- if(objects[obj->otyp].bits & IMMEDIATE) {
- if(u.uswallow)
- bhitm(u.ustuck, obj);
- else if(u.dz) {
- if(u.dz > 0) {
- register struct obj *otmp = o_at(u.ux, u.uy);
- if(otmp)
- (void) bhito(otmp, obj);
- }
- } else
- (void) bhit(u.dx,u.dy,rn1(8,6),0,bhitm,bhito,obj);
- } else {
- switch(obj->otyp){
- case WAN_LIGHT:
- litroom(TRUE);
- break;
- case WAN_SECRET_DOOR_DETECTION:
- if(!findit()) return(1);
- break;
- case WAN_CREATE_MONSTER:
- { register int cnt = 1;
- if(!rn2(23)) cnt += rn2(7) + 1;
- while(cnt--)
- (void) makemon((struct permonst *) 0, u.ux, u.uy);
- }
- break;
- case WAN_WISHING:
- { char buf[BUFSZ];
- register struct obj *otmp;
- extern struct obj *readobjnam(), *addinv();
- if(u.uluck + rn2(5) < 0) {
- pline("Unfortunately, nothing happens.");
- break;
- }
- pline("You may wish for an object. What do you want? ");
- getlin(buf);
- if(buf[0] == '\033') buf[0] = 0;
- otmp = readobjnam(buf);
- otmp = addinv(otmp);
- prinv(otmp);
- break;
- }
- case WAN_DIGGING:
- /* Original effect (approximately):
- * from CORR: dig until we pierce a wall
- * from ROOM: piece wall and dig until we reach
- * an ACCESSIBLE place.
- * Currently: dig for digdepth positions;
- * also down on request of Lennart Augustsson.
- */
- { register struct rm *room;
- register int digdepth;
- if(u.uswallow) {
- register struct monst *mtmp = u.ustuck;
-
- pline("You pierce %s's stomach wall!",
- monnam(mtmp));
- mtmp->mhp = 1; /* almost dead */
- unstuck(mtmp);
- mnexto(mtmp);
- break;
- }
- if(u.dz) {
- if(u.dz < 0) {
- pline("You loosen a rock from the ceiling.");
- pline("It falls on your head!");
- losehp(1, "falling rock");
- mksobj_at(ROCK, u.ux, u.uy);
- fobj->quan = 1;
- stackobj(fobj);
- if(Invisible) newsym(u.ux, u.uy);
- } else {
- dighole();
- }
- break;
- }
- zx = u.ux+u.dx;
- zy = u.uy+u.dy;
- digdepth = 8 + rn2(18);
- Tmp_at(-1, '*'); /* open call */
- while(--digdepth >= 0) {
- if(!isok(zx,zy)) break;
- room = &levl[zx][zy];
- Tmp_at(zx,zy);
- if(!xdnstair){
- if(zx < 3 || zx > COLNO-3 ||
- zy < 3 || zy > ROWNO-3)
- break;
- if(room->typ == HWALL ||
- room->typ == VWALL){
- room->typ = ROOM;
- break;
- }
- } else
- if(room->typ == HWALL || room->typ == VWALL ||
- room->typ == SDOOR || room->typ == LDOOR){
- room->typ = DOOR;
- digdepth -= 2;
- } else
- if(room->typ == SCORR || !room->typ) {
- room->typ = CORR;
- digdepth--;
- }
- mnewsym(zx,zy);
- zx += u.dx;
- zy += u.dy;
- }
- mnewsym(zx,zy); /* not always necessary */
- Tmp_at(-1,-1); /* closing call */
- break;
- }
- default:
- buzz((int) obj->otyp - WAN_MAGIC_MISSILE,
- u.ux, u.uy, u.dx, u.dy);
- break;
- }
- if(!objects[obj->otyp].oc_name_known) {
- objects[obj->otyp].oc_name_known = 1;
- more_experienced(0,10);
- }
- }
- return(1);
-}
-
-char *
-exclam(force)
-register int force;
-{
- /* force == 0 occurs e.g. with sleep ray */
- /* note that large force is usual with wands so that !! would
- require information about hand/weapon/wand */
- return( (force < 0) ? "?" : (force <= 4) ? "." : "!" );
-}
-
-hit(str,mtmp,force)
-register char *str;
-register struct monst *mtmp;
-register char *force; /* usually either "." or "!" */
-{
- if(!cansee(mtmp->mx,mtmp->my)) pline("The %s hits it.", str);
- else pline("The %s hits %s%s", str, monnam(mtmp), force);
-}
-
-miss(str,mtmp)
-register char *str;
-register struct monst *mtmp;
-{
- if(!cansee(mtmp->mx,mtmp->my)) pline("The %s misses it.",str);
- else pline("The %s misses %s.",str,monnam(mtmp));
-}
-
-/* bhit: called when a weapon is thrown (sym = obj->olet) or when an
- IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of
- range or when a monster is hit; the monster is returned, and bhitpos
- is set to the final position of the weapon thrown; the ray of a wand
- may affect several objects and monsters on its path - for each of
- these an argument function is called. */
-/* check !u.uswallow before calling bhit() */
-
-struct monst *
-bhit(ddx,ddy,range,sym,fhitm,fhito,obj)
-register int ddx,ddy,range; /* direction and range */
-char sym; /* symbol displayed on path */
-int (*fhitm)(), (*fhito)(); /* fns called when mon/obj hit */
-struct obj *obj; /* 2nd arg to fhitm/fhito */
-{
- register struct monst *mtmp;
- register struct obj *otmp;
- register int typ;
-
- bhitpos.x = u.ux;
- bhitpos.y = u.uy;
-
- if(sym) tmp_at(-1, sym); /* open call */
- while(range-- > 0) {
- bhitpos.x += ddx;
- bhitpos.y += ddy;
- typ = levl[bhitpos.x][bhitpos.y].typ;
- if(mtmp = m_at(bhitpos.x,bhitpos.y)){
- if(sym) {
- tmp_at(-1, -1); /* close call */
- return(mtmp);
- }
- (*fhitm)(mtmp, obj);
- range -= 3;
- }
- if(fhito && (otmp = o_at(bhitpos.x,bhitpos.y))){
- if((*fhito)(otmp, obj))
- range--;
- }
- if(!ZAP_POS(typ)) {
- bhitpos.x -= ddx;
- bhitpos.y -= ddy;
- break;
- }
- if(sym) tmp_at(bhitpos.x, bhitpos.y);
- }
-
- /* leave last symbol unless in a pool */
- if(sym)
- tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0);
- return(0);
-}
-
-struct monst *
-boomhit(dx,dy) {
- register int i, ct;
- register struct monst *mtmp;
- char sym = ')';
- extern schar xdir[], ydir[];
-
- bhitpos.x = u.ux;
- bhitpos.y = u.uy;
-
- for(i=0; i<8; i++) if(xdir[i] == dx && ydir[i] == dy) break;
- tmp_at(-1, sym); /* open call */
- for(ct=0; ct<10; ct++) {
- if(i == 8) i = 0;
- sym = ')' + '(' - sym;
- tmp_at(-2, sym); /* change let call */
- dx = xdir[i];
- dy = ydir[i];
- bhitpos.x += dx;
- bhitpos.y += dy;
- if(mtmp = m_at(bhitpos.x, bhitpos.y)){
- tmp_at(-1,-1);
- return(mtmp);
- }
- if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) {
- bhitpos.x -= dx;
- bhitpos.y -= dy;
- break;
- }
- if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
- if(rn2(20) >= 10+u.ulevel){ /* we hit ourselves */
- (void) thitu(10, rnd(10), "boomerang");
- break;
- } else { /* we catch it */
- tmp_at(-1,-1);
- pline("Skillfully, you catch the boomerang.");
- return(&youmonst);
- }
- }
- tmp_at(bhitpos.x, bhitpos.y);
- if(ct % 5 != 0) i++;
- }
- tmp_at(-1, -1); /* do not leave last symbol */
- return(0);
-}
-
-char
-dirlet(dx,dy) register dx,dy; {
- return
- (dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
-}
-
-/* type == -1: monster spitting fire at you */
-/* type == -1,-2,-3: bolts sent out by wizard */
-/* called with dx = dy = 0 with vertical bolts */
-buzz(type,sx,sy,dx,dy)
-register int type;
-register xchar sx,sy;
-register int dx,dy;
-{
- int abstype = abs(type);
- register char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype];
- struct rm *lev;
- xchar range;
- struct monst *mon;
-
- if(u.uswallow) {
- register int tmp;
-
- if(type < 0) return;
- tmp = zhit(u.ustuck, type);
- pline("The %s rips into %s%s",
- fltxt, monnam(u.ustuck), exclam(tmp));
- return;
- }
- if(type < 0) pru();
- range = rn1(7,7);
- Tmp_at(-1, dirlet(dx,dy)); /* open call */
- while(range-- > 0) {
- sx += dx;
- sy += dy;
- if((lev = &levl[sx][sy])->typ) Tmp_at(sx,sy);
- else {
- int bounce = 0;
- if(cansee(sx-dx,sy-dy))
- pline("The %s bounces!", fltxt);
- if(ZAP_POS(levl[sx][sy-dy].typ))
- bounce = 1;
- if(ZAP_POS(levl[sx-dx][sy].typ)) {
- if(!bounce || rn2(2)) bounce = 2;
- }
- switch(bounce){
- case 0:
- dx = -dx;
- dy = -dy;
- continue;
- case 1:
- dy = -dy;
- sx -= dx;
- break;
- case 2:
- dx = -dx;
- sy -= dy;
- break;
- }
- Tmp_at(-2,dirlet(dx,dy));
- continue;
- }
- if(lev->typ == POOL && abstype == 1 /* fire */) {
- range -= 3;
- lev->typ = ROOM;
- if(cansee(sx,sy)) {
- mnewsym(sx,sy);
- pline("The water evaporates.");
- } else
- pline("You hear a hissing sound.");
- }
- if((mon = m_at(sx,sy)) &&
- (type != -1 || mon->data->mlet != 'D')) {
- wakeup(mon);
- if(rnd(20) < 18 + mon->data->ac) {
- register int tmp = zhit(mon,abstype);
- if(mon->mhp < 1) {
- if(type < 0) {
- if(cansee(mon->mx,mon->my))
- pline("%s is killed by the %s!",
- Monnam(mon), fltxt);
- mondied(mon);
- } else
- killed(mon);
- } else
- hit(fltxt, mon, exclam(tmp));
- range -= 2;
- } else
- miss(fltxt,mon);
- } else if(sx == u.ux && sy == u.uy) {
- nomul(0);
- if(rnd(20) < 18+u.uac) {
- register int dam = 0;
- range -= 2;
- pline("The %s hits you!",fltxt);
- switch(abstype) {
- case 0:
- dam = d(2,6);
- break;
- case 1:
- if(Fire_resistance)
- pline("You don't feel hot!");
- else dam = d(6,6);
- if(!rn2(3))
- burn_scrolls();
- break;
- case 2:
- nomul(-rnd(25)); /* sleep ray */
- break;
- case 3:
- if(Cold_resistance)
- pline("You don't feel cold!");
- else dam = d(6,6);
- break;
- case 4:
- u.uhp = -1;
- }
- losehp(dam,fltxt);
- } else pline("The %s whizzes by you!",fltxt);
- stop_occupation();
- }
- if(!ZAP_POS(lev->typ)) {
- int bounce = 0, rmn;
- if(cansee(sx,sy)) pline("The %s bounces!",fltxt);
- range--;
- if(!dx || !dy || !rn2(20)){
- dx = -dx;
- dy = -dy;
- } else {
- if(ZAP_POS(rmn = levl[sx][sy-dy].typ) &&
- (IS_ROOM(rmn) || ZAP_POS(levl[sx+dx][sy-dy].typ)))
- bounce = 1;
- if(ZAP_POS(rmn = levl[sx-dx][sy].typ) &&
- (IS_ROOM(rmn) || ZAP_POS(levl[sx-dx][sy+dy].typ)))
- if(!bounce || rn2(2))
- bounce = 2;
-
- switch(bounce){
- case 0:
- dy = -dy;
- dx = -dx;
- break;
- case 1:
- dy = -dy;
- break;
- case 2:
- dx = -dx;
- break;
- }
- Tmp_at(-2, dirlet(dx,dy));
- }
- }
- }
- Tmp_at(-1,-1);
-}
-
-zhit(mon,type) /* returns damage to mon */
-register struct monst *mon;
-register type;
-{
- register int tmp = 0;
-
- switch(type) {
- case 0: /* magic missile */
- tmp = d(2,6);
- break;
- case -1: /* Dragon blazing fire */
- case 1: /* fire */
- if(index("Dg", mon->data->mlet)) break;
- tmp = d(6,6);
- if(index("YF", mon->data->mlet)) tmp += 7;
- break;
- case 2: /* sleep*/
- mon->mfroz = 1;
- break;
- case 3: /* cold */
- if(index("YFgf", mon->data->mlet)) break;
- tmp = d(6,6);
- if(mon->data->mlet == 'D') tmp += 7;
- break;
- case 4: /* death*/
- if(index(UNDEAD, mon->data->mlet)) break;
- tmp = mon->mhp+1;
- break;
- }
- mon->mhp -= tmp;
- return(tmp);
-}
-
-#define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
- ? 'a' + (otyp - DEAD_ACID_BLOB)\
- : '@' + (otyp - DEAD_HUMAN))
-revive(obj)
-register struct obj *obj;
-{
- register struct monst *mtmp;
-
- if(obj->olet == FOOD_SYM && obj->otyp > CORPSE) {
- /* do not (yet) revive shopkeepers */
- /* Note: this might conceivably produce two monsters
- at the same position - strange, but harmless */
- mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp),obj->ox,obj->oy);
- delobj(obj);
- }
- return(!!mtmp); /* TRUE if some monster created */
-}
-
-rloco(obj)
-register struct obj *obj;
-{
- register tx,ty,otx,oty;
-
- otx = obj->ox;
- oty = obj->oy;
- do {
- tx = rn1(COLNO-3,2);
- ty = rn2(ROWNO);
- } while(!goodpos(tx,ty));
- obj->ox = tx;
- obj->oy = ty;
- if(cansee(otx,oty))
- newsym(otx,oty);
-}
-
-fracture_rock(obj) /* fractured by pick-axe or wand of striking */
-register struct obj *obj; /* no texts here! */
-{
- /* unpobj(obj); */
- obj->otyp = ROCK;
- obj->quan = 7 + rn2(60);
- obj->owt = weight(obj);
- obj->olet = WEAPON_SYM;
- if(cansee(obj->ox,obj->oy))
- prl(obj->ox,obj->oy);
-}
-
-burn_scrolls()
-{
- register struct obj *obj, *obj2;
- register int cnt = 0;
-
- for(obj = invent; obj; obj = obj2) {
- obj2 = obj->nobj;
- if(obj->olet == SCROLL_SYM) {
- cnt++;
- useup(obj);
- }
- }
- if(cnt > 1) {
- pline("Your scrolls catch fire!");
- losehp(cnt, "burning scrolls");
- } else if(cnt) {
- pline("Your scroll catches fire!");
- losehp(1, "burning scroll");
- }
-}
diff --git a/games/hack/help b/games/hack/help
deleted file mode 100644
index 24b22a5d410f..000000000000
--- a/games/hack/help
+++ /dev/null
@@ -1,132 +0,0 @@
- Welcome to HACK! ( description of version 1.0.3 )
-
- Hack is a Dungeons and Dragons like game where you (the adventurer)
-descend into the depths of the dungeon in search of the Amulet of Yendor
-(reputed to be hidden on the twentieth level). You are accompanied by a
-little dog that can help you in many ways and can be trained to do all
-sorts of things. On the way you will find useful (or useless) items, (quite
-possibly with magic properties) and assorted monsters. You attack a monster
-by trying to move into the space a monster is in (but often it is much
-wiser to leave it alone).
-
- Unlike most adventure games, which give you a verbal description of
-your location, hack gives you a visual image of the dungeon level you are on.
-
- Hack uses the following symbols:
- A to Z and a to z: monsters. You can find out what a letter
-represents by saying "/ (letter)", as in "/A", which will tell you that 'A'
-is a giant ant.
- - and | These form the walls of a room (or maze).
- . this is the floor of a room.
- # this is a corridor.
- > this is the staircase to the next level.
- < the staircase to the previous level.
- ` A large boulder.
- @ You (usually).
- ^ A trap.
- ) A weapon of some sort.
- ( Some other useful object (key, rope, dynamite, camera, ...)
- [ A suit of armor.
- % A piece of food (not necessarily healthy ...).
- / A wand.
- = A ring.
- ? A scroll.
- ! A magic potion.
- $ A pile or pot of gold.
-
-Commands:
- Hack knows the following commands:
- ? help: print this list.
- Q Quit the game.
- S Save the game.
- ! Escape to a shell.
- ^Z Suspend the game.
- < up: go up the staircase (if you are standing on it).
- > down: go down (just like up).
- kjhlyubn - go one step in the direction indicated.
- k: north (i.e., to the top of the screen),
- j: south, h: west, l: east, y: ne, u: nw, b: se, n: sw.
- KJHLYUBN - Go in that direction until you hit a wall or run
- into something.
- m (followed by one of kjhlyubn): move without picking up
- any objects.
- M (followed by one of KJHLYUBN): Move far, no pickup.
- f (followed by one of kjhlyubn): move until something
- interesting is found.
- F (followed by one of KJHLYUBN): as previous, but forking
- of corridors is not considered interesting.
- i print your inventory.
- I print selected parts of your inventory, like in
- I* - print all gems in inventory;
- IU - print all unpaid items;
- IX - print all used up items that are on your shopping bill;
- I$ - count your money.
- s search for secret doors and traps around you.
- ^ ask for the type of a trap you found earlier.
- ) ask for current wielded weapon.
- [ ask for current armor.
- = ask for current rings.
- $ count how many gold pieces you are carrying.
- . rest, do nothing.
- , pick up some things.
- : look at what is here.
- ^T teleport.
- ^R redraw the screen.
- ^P repeat last message
- (subsequent ^P's repeat earlier messages).
- / (followed by any symbol): tell what this symbol represents.
- \ tell what has been discovered.
- e eat food.
- w wield weapon. w- means: wield nothing, use bare hands.
- q drink (quaff) a potion.
- r read a scroll.
- T Takeoff armor.
- R Remove Ring.
- W Wear armor.
- P Put on a ring.
- z zap a wand.
- t throw an object or shoot an arrow.
- p pay your shopping bill.
- d drop something. d7a: drop seven items of object a.
- D Drop several things.
- In answer to the question "What kinds of things do you
- want to drop? [!%= au]" you should give zero or more
- object symbols possibly followed by 'a' and/or 'u'.
- 'a' means: drop all such objects, without asking for
- confirmation.
- 'u' means: drop only unpaid objects (when in a shop).
- a use, apply - Generic command for using a key to lock
- or unlock a door, using a camera, using a rope, etc.
- c call: name a certain object or class of objects.
- C Call: Name an individual monster.
- E Engrave: Write a message in the dust on the floor.
- E- means: use fingers for writing.
- O Set options. You will be asked to enter an option line.
- If this is empty, the current options are reported.
- Otherwise it should be a list of options separated by commas.
- Possible boolean options are: oneline, time, news, tombstone,
- rest_on_space, fixinvlet, beginner, male, female.
- They can be negated by prefixing them with '!' or "no".
- A string option is name; it supplies the answer to the question
- "Who are you?"; it may have a suffix.
- A compound option is endgame; it is followed by a description
- of what parts of the list of topscorers should be printed
- when the game is finished.
- Usually one will not want to use the 'O' command, but instead
- put a HACKOPTIONS="...." line in one's environment.
- v print version number.
-
- You can put a number before a command to repeat it that many times,
- as in "20s" or "40.".
-
- At present, some information is displayed on the bottom line.
- (It is expected that this information will go away in future versions.)
- You see on what dungeon level you are, how many hit points you have
- now (and will have when fully recovered), what your armor class is
- (the lower the better), your strength, experience level and the
- state of your stomach.
-
- Have Fun, and Good Hacking!
-
-
-
diff --git a/games/hack/hh b/games/hack/hh
deleted file mode 100644
index d777102dae64..000000000000
--- a/games/hack/hh
+++ /dev/null
@@ -1,55 +0,0 @@
-y k u Move commands:
- \|/ hykulnjb: single move in specified direction
-h-+-l HYKULNJB: repeated move in specified direction
- /|\ (until stopped by e.g. a wall)
-b j n f<dir>: fast movement in direction <dir>
- (until something interesting is seen)
- m<dir>: move without picking up objects
-
-Meta commands:
-Q quit leave the game
-S save save the game (to be continued later)
-! sh escape to some SHELL
-^Z suspend suspend the game (independent of your current suspend char)
-O set set options
-? help print information
-/ whatis give name (and sometimes more info) of specified monster
-\ known print list of what's been discovered
-v version print version number
-^R redraw redraw the screen (^R denotes the symbol CTRL/R)
-^P print repeat last message (subsequent ^P's repeat earlier messages)
-# introduces a long command; not really implemented
-
-Game commands:
-^T teleport teleport
-a apply, use use something (a key, camera, etc.)
-c call give a name to a class of objects
-d drop drop an object. d7a: drop seven items of object a.
-e eat eat something
-i invent list the inventory (all objects you are carrying)
-I invent list selected parts of the inventory
- IU: list unpaid objects
- IX: list unpaid but used up items
- I$: count your money
-p pay pay your bill
-q drink quaff a potion
-r read read a scroll
-s search search for secret doors, hidden traps and monsters
-t throw throw or shoot a weapon
-w wield wield a weapon (w- wield nothing)
-z zap zap a wand
-C name name an individual monster (e.g., baptize your dog)
-D Drop drop several things
-E Engrave write a message in the dust on the floor (E- use fingers)
-P wear put on a ring
-R remove remove a ring
-T remove take off some armor
-W wear put on some armor
-< up go up the stairs
-> down go down the stairs
-^ trap_id identify a previously found trap
-),[,= ask for current weapon, armor, rings, respectively
-$ gold count your gold
-. rest wait a moment
-, pickup pick up all you can carry
-: look look at what is here
diff --git a/games/hack/makedefs.c b/games/hack/makedefs.c
deleted file mode 100644
index aa113b9fed8d..000000000000
--- a/games/hack/makedefs.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
-/* makedefs.c - version 1.0.2 */
-
-#include <stdio.h>
-
-/* construct definitions of object constants */
-#define LINSZ 1000
-#define STRSZ 40
-
-int fd;
-char string[STRSZ];
-
-main(argc, argv)
- int argc;
- char **argv;
-{
-register int index = 0;
-register int propct = 0;
-register char *sp;
- if (argc != 2) {
- (void)fprintf(stderr, "usage: makedefs file\n");
- exit(1);
- }
- if ((fd = open(argv[1], 0)) < 0) {
- perror(argv[1]);
- exit(1);
- }
- skipuntil("objects[] = {");
- while(getentry()) {
- if(!*string){
- index++;
- continue;
- }
- for(sp = string; *sp; sp++)
- if(*sp == ' ' || *sp == '\t' || *sp == '-')
- *sp = '_';
- if(!strncmp(string, "RIN_", 4)){
- capitalize(string+4);
- printf("#define %s u.uprops[%d].p_flgs\n",
- string+4, propct++);
- }
- for(sp = string; *sp; sp++) capitalize(sp);
- /* avoid trouble with stupid C preprocessors */
- if(!strncmp(string, "WORTHLESS_PIECE_OF_", 19))
- printf("/* #define %s %d */\n", string, index);
- else
- printf("#define %s %d\n", string, index);
- index++;
- }
- printf("\n#define CORPSE DEAD_HUMAN\n");
- printf("#define LAST_GEM (JADE+1)\n");
- printf("#define LAST_RING %d\n", propct);
- printf("#define NROFOBJECTS %d\n", index-1);
- exit(0);
-}
-
-char line[LINSZ], *lp = line, *lp0 = line, *lpe = line;
-int eof;
-
-readline(){
-register int n = read(fd, lp0, (line+LINSZ)-lp0);
- if(n < 0){
- printf("Input error.\n");
- exit(1);
- }
- if(n == 0) eof++;
- lpe = lp0+n;
-}
-
-char
-nextchar(){
- if(lp == lpe){
- readline();
- lp = lp0;
- }
- return((lp == lpe) ? 0 : *lp++);
-}
-
-skipuntil(s) char *s; {
-register char *sp0, *sp1;
-loop:
- while(*s != nextchar())
- if(eof) {
- printf("Cannot skipuntil %s\n", s);
- exit(1);
- }
- if(strlen(s) > lpe-lp+1){
- register char *lp1, *lp2;
- lp2 = lp;
- lp1 = lp = lp0;
- while(lp2 != lpe) *lp1++ = *lp2++;
- lp2 = lp0; /* save value */
- lp0 = lp1;
- readline();
- lp0 = lp2;
- if(strlen(s) > lpe-lp+1) {
- printf("error in skipuntil");
- exit(1);
- }
- }
- sp0 = s+1;
- sp1 = lp;
- while(*sp0 && *sp0 == *sp1) sp0++, sp1++;
- if(!*sp0){
- lp = sp1;
- return(1);
- }
- goto loop;
-}
-
-getentry(){
-int inbraces = 0, inparens = 0, stringseen = 0, commaseen = 0;
-int prefix = 0;
-char ch;
-#define NSZ 10
-char identif[NSZ], *ip;
- string[0] = string[4] = 0;
- /* read until {...} or XXX(...) followed by ,
- skip comment and #define lines
- deliver 0 on failure
- */
- while(1) {
- ch = nextchar();
- swi:
- if(letter(ch)){
- ip = identif;
- do {
- if(ip < identif+NSZ-1) *ip++ = ch;
- ch = nextchar();
- } while(letter(ch) || digit(ch));
- *ip = 0;
- while(ch == ' ' || ch == '\t') ch = nextchar();
- if(ch == '(' && !inparens && !stringseen)
- if(!strcmp(identif, "WAND") ||
- !strcmp(identif, "RING") ||
- !strcmp(identif, "POTION") ||
- !strcmp(identif, "SCROLL"))
- (void) strncpy(string, identif, 3),
- string[3] = '_',
- prefix = 4;
- }
- switch(ch) {
- case '/':
- /* watch for comment */
- if((ch = nextchar()) == '*')
- skipuntil("*/");
- goto swi;
- case '{':
- inbraces++;
- continue;
- case '(':
- inparens++;
- continue;
- case '}':
- inbraces--;
- if(inbraces < 0) return(0);
- continue;
- case ')':
- inparens--;
- if(inparens < 0) {
- printf("too many ) ?");
- exit(1);
- }
- continue;
- case '\n':
- /* watch for #define at begin of line */
- if((ch = nextchar()) == '#'){
- register char pch;
- /* skip until '\n' not preceded by '\\' */
- do {
- pch = ch;
- ch = nextchar();
- } while(ch != '\n' || pch == '\\');
- continue;
- }
- goto swi;
- case ',':
- if(!inparens && !inbraces){
- if(prefix && !string[prefix])
- string[0] = 0;
- if(stringseen) return(1);
- printf("unexpected ,\n");
- exit(1);
- }
- commaseen++;
- continue;
- case '\'':
- if((ch = nextchar()) == '\\') ch = nextchar();
- if(nextchar() != '\''){
- printf("strange character denotation?\n");
- exit(1);
- }
- continue;
- case '"':
- {
- register char *sp = string + prefix;
- register char pch;
- register int store = (inbraces || inparens)
- && !stringseen++ && !commaseen;
- do {
- pch = ch;
- ch = nextchar();
- if(store && sp < string+STRSZ)
- *sp++ = ch;
- } while(ch != '"' || pch == '\\');
- if(store) *--sp = 0;
- continue;
- }
- }
- }
-}
-
-capitalize(sp) register char *sp; {
- if('a' <= *sp && *sp <= 'z') *sp += 'A'-'a';
-}
-
-letter(ch) register char ch; {
- return( ('a' <= ch && ch <= 'z') ||
- ('A' <= ch && ch <= 'Z') );
-}
-
-digit(ch) register char ch; {
- return( '0' <= ch && ch <= '9' );
-}
diff --git a/games/hack/pathnames.h b/games/hack/pathnames.h
deleted file mode 100644
index 1df8f008a6f9..000000000000
--- a/games/hack/pathnames.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-
- * Copyright (c) 1990 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.
- *
- * @(#)pathnames.h 5.1 (Berkeley) 5/2/90
- */
-
-#define _PATH_MAIL "/usr/bin/mail"
-#define _PATH_QUEST "/var/games/questdir"
-#define _PATH_HACK "/var/games/hackdir"
-
diff --git a/games/hack/rnd.c b/games/hack/rnd.c
deleted file mode 100644
index 8547cef210a2..000000000000
--- a/games/hack/rnd.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* rnd.c - version 1.0.2 */
-
-#define RND(x) ((random()>>3) % x)
-
-rn1(x,y)
-register x,y;
-{
- return(RND(x)+y);
-}
-
-rn2(x)
-register x;
-{
- return(RND(x));
-}
-
-rnd(x)
-register x;
-{
- return(RND(x)+1);
-}
-
-d(n,x)
-register n,x;
-{
- register tmp = n;
-
- while(n--) tmp += RND(x);
- return(tmp);
-}
diff --git a/games/hack/rumors b/games/hack/rumors
deleted file mode 100644
index 9435a5fecc74..000000000000
--- a/games/hack/rumors
+++ /dev/null
@@ -1,505 +0,0 @@
-"Quit" is a four letter word.
-"So when I die, the first thing I will see in Heaven is a score list?"
--- more --
-...and rings may protect your fingers.
-...and sometimes a piercer drops by.
-A Quasit is even faster than a jaguar!
-A chameleon imitating a postman often delivers scrolls of fire.
-A chameleon imitating a postman sometimes delivers scrolls of punishment.
-A clove of garlic a day keeps your best friends away.
-A cockatrice's corpse is guaranteed to be untainted!
-A confused acid blob may attack.
-A dead lizard is a good thing to turn undead.
-A dragon is just a Snake that ate a scroll of fire.
-A fading corridor enlightens your insight.
-A glowing potion is too hot to drink.
-A good amulet may protect you against guards.
-A homunculus wouldnt want to hurt a wizard.
-A jaguar shouldn't frighten you.
-A long worm can be defined recursively. So how should you attack it?
-A long worm hits with all of its length.
-A magic vomit pump is a necessity for gourmands.
-A monstrous mind is a toy for ever.
-A nurse a day keeps the doctor away.
-A potion of blindness makes you see invisible things.
-A ring is just a wound wand.
-A ring of adornment protects against Nymphs.
-A ring of conflict is a bad thing if there is a nurse in the room.
-A ring of extra ringfinger is useless if not enchanted.
-A ring of stealth can be recognised by that it does not teleport you.
-A rope may form a trail in a maze.
-A rumour has it that rumours are just rumours.
-A scroll of enchant amulet is only useful on your way back.
-A smoky potion surely affects your vision.
-A spear might hit a nurse.
-A spear will hit an ettin.
-A staff may recharge if you drop it for awhile.
-A tin of smoked eel is a wonderful find.
-A truly wise man never plays leapfrog with a unicorn.
-A two-handed sword usually misses.
-A unicorn can be tamed only by a fair maiden.
-A visit to the Zoo is very educational; you meet interesting animals.
-A wand of deaf is a more dangerous weapon than a wand of sheep.
-A wand of vibration might bring the whole cave crashing about your ears.
-A winner never quits. A quitter never wins.
-A xan is a small animal. It doesn't reach higher than your leg.
-Acid blobs should be attacked bare-handed.
-Affairs with Nymphs are often very expensive.
-Afraid of Mimics? Try to wear a ring of true seeing.
-Afraid of falling piercers? Wear a helmet!
-After being attacked by a Harpy you have a lot of arrows.
-All monsters are created evil, but some are more evil than others.
-Always attack a floating Eye from behind!
-Always be aware of the phase of the moon!
-Always read the info about a monster before dealing with it.
-Always sweep the floor before engraving important messages.
-Amulets are hard to make. Even for a wand of wishing.
-An Umber hulk can be a confusing sight.
-An elven cloak is always the height of fashion.
-An elven cloak protects against magic.
-An ettin is hard to kill; an imp is hard to hit. See the difference?
-Any small object that is accidentally dropped will hide under a larger object.
-Are you blind? Catch a floating Eye!
-Asking about monsters may be very useful.
-Attack long worms from the rear - that is so much safer!
-Attacking an eel when there is none usually is a fatal mistake!
-Balrogs only appear on the deeper levels.
-Be careful when eating bananas. Monsters might slip on the peels.
-Be careful when eating salmon - your fingers might become greasy.
-Be careful when the moon is in its last quarter.
-Be careful when throwing a boomerang - you might hit the back of your head.
-Be nice to a nurse: put away your weapon and take off your clothes.
-Being digested is a painfully slow process.
-Better go home and hit your kids. They are just little monsters!
-Better go home and play with your kids. They are just little monsters!
-Better leave the dungeon, otherwise you might get hurt badly.
-Beware of dark rooms - they may be the Morgue.
-Beware of death rays!
-Beware of falling rocks, wear a helmet!
-Beware of hungry dogs!
-Beware of the minotaur. He's very horny!
-Beware of the potion of Nitroglycerine - it's not for the weak of heart.
-Beware of wands of instant disaster.
-Beware: there's always a chance that your wand explodes as you try to zap it!
-Beyond the 23-rd level lies a happy retirement in a room of your own.
-Blank scrolls make more interesting reading.
-Blind? Eat a carrot!
-Booksellers never read scrolls; it might carry them too far away.
-Booksellers never read scrolls; it might leave their shop unguarded.
-Changing your suit without dropping your sword? You must be kidding!
-Cockatrices might turn themselves to stone faced with a mirror.
-Consumption of home-made food is strictly forbidden in this dungeon.
-Dark gems are just coloured glass.
-Dark room? Just flash often with your camera.
-Dark room? Your chance to develop your photographs!
-Dark rooms are not *completely* dark: just wait and let your eyes adjust...
-Dead lizards protect against a cockatrice.
-Death is just around the next door.
-Death is life's way of telling you you've been fired.
-Descend in order to meet more decent monsters.
-Did you know worms had teeth?
-Didn't you forget to pay?
-Didn't you forget to pay?
-Direct a direct hit on your direct opponent, directing in the right direction.
-Do something big today: lift a boulder.
-Do you want to visit hell? Dig a *very* deep hole.
-Dogs are attracted by the smell of tripe.
-Dogs do not eat when the moon is full.
-Dogs never step on cursed items.
-Dogs of ghosts aren't angry, just hungry.
-Don't bother about money: only Leprechauns and shopkeepers are interested.
-Don't create fireballs: they might turn against you.
-Don't eat too much: you might start hiccoughing!
-Don't forget! Large dogs are MUCH harder to kill than little dogs.
-Don't play hack at your work, your boss might hit you!
-Don't swim with weapons or armour: they might rust!
-Don't tell a soul you found a secret door, otherwise it isn't secret anymore.
-Don't throw gems. They are so precious! Besides, you might hit a roommate.
-Drinking might affect your health.
-Drop your vanity and get rid of your jewels! Pickpockets about!
-Dungeon expects every monster to do his duty.
-Dust is an armor of poor quality.
-Eat 10 cloves of garlic and keep all humans at a two-square distance.
-Eat a homunculus if you want to avoid sickness.
-Eating a Wraith is a rewarding experience!
-Eating a freezing sphere is like eating a yeti.
-Eating a killer bee is like eating a scorpion.
-Eating a tengu is like eating a Nymph.
-Eating unpaid Leprechauns may be advantageous.
-Eels hide under mud. Use a unicorn to clear the water and make them visible.
-Elven cloaks cannot rust.
-Engrave your wishes with a wand of wishing.
-Eventually all wands of striking do strike.
-Eventually you will come to admire the swift elegance of a retreating nymph.
-Ever fought with an enchanted tooth?
-Ever heard hissing outside? I *knew* you hadn't!
-Ever seen a leocrotta dancing the tengu?
-Ever slept in the arms of a homunculus?
-Ever tamed a shopkeeper?
-Ever tried digging through a Vault Guard?
-Ever tried enchanting a rope?
-Ever tried to catch a flying boomerang?
-Ever tried to put a Troll into a large box?
-Ever wondered why one would want to dip something in a potion?
-Every dog should be a domesticated one.
-Every hand has only one finger to put a ring on. You've got only two hands. So?
-Every level contains a shop; only the entrance is often hidden.
-Everybody should have tasted a scorpion at least once in his life.
-Expensive cameras have penetrating flashlights.
-Feeding the animals is strictly prohibited. The Management.
-Feeling lousy? Why don't you drink a potion of tea?
-Fiery letters might deter monsters.
-First Law of Hacking: leaving is much more difficult than entering.
-For any remedy there is a misery.
-Fourth Law of Hacking: you will find the exit at the entrance.
-Gems are the droppings of other inmates.
-Gems do get a burden.
-Genocide on shopkeepers is punishable.
-Getting Hungry? Stop wearing rings!
-Getting Hungry? Wear an amulet!
-Ghosts always empty the fridge.
-Ghosts are visible because they don't leave a trace.
-Giant beetles make giant holes in giant trees!
-Giving head to a long worm is like a long lasting reception.
-Gold is a heavy metal.
-Good day for overcoming obstacles. Try a steeplechase.
-Gossip is the opiate of the depressed.
-Hackers do it with bugs.
-Half Moon tonight. (At least it's better than no Moon at all.)
-Handle your flasks carefully - there might be a ghost inside!
-Have a good meal today: eat a minotaur.
-Hey guys, you *WIELD* a dead lizard against a cocatrice! [David London]
-Hissing is a sound I hate.
-Hitting is the lingua franca in these regions.
-Humans use walking canes when they grow old.
-Hunger is a confusing experience for a dog!
-Hungry dogs are unreliable.
-Hungry? There is an abundance of food on the next level.
-Hungry? Wear an amulet!
-I doubt whether nurses are virgins.
-I guess you have never hit a postman with an Amulet of Yendor yet...
-I once knew a hacker who ate too fast and choked to death.....
-I smell a maze of twisty little passages.
-I wished, I never wished a wand of wishing. (Wishful thinking)
-If "nothing happens", something *has* happened anyway!!
-If a chameleon mimics a mace, it really mimics a Mimic mimicking a mace.
-If a shopkeeper kicks you out of his shop, he'll kick you out of the dungeon.
-If you are being punished, it's done with a deadly weapon.
-If you are the shopkeeper you can take things for free.
-If you are too cute some monsters might be tempted to embrace you.
-If you can't learn to do it well, learn to enjoy doing it badly.
-If you need a wand of digging, kindly ask the minotaur.
-If you see nurses you better start looking somewhere for a doctor.
-If you turn blind: don't expect your dog to be turned into a seeing-eye dog.
-If you want to feal great, you must eat something real big.
-If you want to float you'd better eat a floating eye.
-If you want to genocide nurses, genocide @'s.
-If you want to hit, use a dagger.
-If you want to rob a shop, train your dog.
-If you're afraid of trapdoors, just cover the floor with all you've got.
-If you're lost, try buying a map next time you're in a shop.
-If your ghost kills a player, it increases your score.
-Important mail? Be careful that it isn't stolen!
-Improve your environment, using a wand of rearrangement.
-In a hurry? Try a ride on a fast moving quasit!
-In a way, a scorpion is like a snake.
-In need of a rest? Quaff a potion of sickness!
-In total, there are eight sorts of shops.
-Increase mindpower: Tame your own ghost!
-Inside a shop you better take a look at the price tags before buying anything.
-It furthers one to see the great man.
-It is bad manners to use a wand in a shop.
-It is not always a good idea to whistle for your dog.
-It is said that Giant Rabbits can be tamed with carrots only.
-It is said that purple worms and trappers fill the same niche.
-It might be a good idea to offer the unicorn a ruby.
-It seems you keep overlooking a sign reading "No trespassing"!
-It would be peculiarly sad were your dog turned to stone.
-It's all a matter of life and death, so beware of the undead.
-It's bad luck to drown a postman.
-It's bad luck, being punished.
-It's easy to overlook a monster in a wood.
-It's not safe to Save.
-Jackals are intrinsically rotten.
-Just below any trapdoor there may be another one. Just keep falling!
-Keep a clear mind: quaff clear potions.
-Keep your armours away from rust.
-Keep your weaponry away from acids.
-Kicking the terminal doesn't hurt the monsters.
-Kill a unicorn and you kill your luck.
-Killer bees keep appearing till you kill their queen.
-Large dogs make larger turds than little ones.
-Latest news? Put 'net.games.hack' in your .newsrc !
-Latest news? Put newsgroup 'netUNX.indoor.hackers-scroll' in your .newsrc!
-Learn how to spell. Play Hack!
-Leather armour cannot rust.
-Leprechauns are the most skilled cutpurses in this dungeon.
-Leprechauns hide their gold in a secret room.
-Let your fingers do the walking on the yulkjhnb keys.
-Let's face it: this time you're not going to win.
-Let's have a party, drink a lot of booze.
-Liquor sellers do not drink; they hate to see you twice.
-Looking for a monster -- use a staff of monster summoning.
-Looking pale? Quaff a red potion!
-M.M.Vault cashiers teleport any amount of gold to the next local branch.
-Many monsters make a murdering mob.
-Meet yourself! Commit suicide and type "hack"
-Meeting your own ghost decreases your luck considerably!
-Memory flaw - core dumped.
-Money is the root of all evil.
-Money to invest? Take it to the local branch of the Magic Memory Vault!
-Monsters come from nowhere to hit you everywhere.
-Monsters sleep because you are boring, not because they ever get tired.
-Most monsters can't swim.
-Most monsters prefer minced meat. That's why they are hitting you!
-Most rumors are just as misleading as this one.
-Much ado Nothing Happens.
-Murder complaint? Mail to 'netnix!devil!gamble!freak!trap!lastwill!rip'.
-Need money? Sell your corpses to a tin factory.
-Never ask a shopkeeper for a price list.
-Never attack a guard.
-Never drop a crysknife! No, never even unwield it, until...
-Never eat with glowing hands!
-Never fight a monster: you might get killed.
-Never go into the dungeon at midnight.
-Never kick a sleeping dog.
-Never kiss an animal. It may cause kissing disease.
-Never map the labyrinth.
-Never mind the monsters hitting you: they just replace the charwomen.
-Never ride a long worm.
-Never step on a cursed engraving.
-Never swim with a camera: there's nothing to take pictures of.
-Never trust a random generator in magic fields.
-Never use a wand of death.
-Never use your best weapon to engrave a curse.
-Never vomit on a door mat.
-No easy fighting with a heavy load!
-No level contains two shops. The maze is no level. So...
-No part of this fortune may be reproduced, stored in a retrieval system, ...
-No weapon is better than a crysknife.
-Not all rumors are as misleading as this one.
-Not even a spear will hit a Xorn.
-Now what is it that cures digestion?
-Nurses are accustomed to touch naked persons: they don't harm them.
-Nurses prefer undressed hackers.
-Nymphs and nurses like beautiful rings.
-Nymphs are blondes. Are you a gentleman?
-Nymphs are very pleased when you call them by their real name: Lorelei.
-Offering a unicorn a worthless piece of glass might prove to be fatal!
-Old hackers never die: young ones do.
-Old trees sometimes fall without a warning!
-Once your little dog will be a big dog, and you will be proud of it.
-One can even choke in a fortune cookie!
-One has to leave shops before closing time.
-One homunculus a day keeps the doctor away.
-One level further down somebody is getting killed, right now.
-One wand of concentration equals eight scrolls of create monster.
-Only Today! A dramatic price-cut on slightly used wands.
-Only a Nymph knows how to unlock chains.
-Only a dragon will never get a cold from a wand of cold.
-Only a real dummy would ever call his sword 'Elbereth'.
-Only a wizard can use a magic whistle.
-Only adventurers of evil alignment think of killing their dog.
-Only cave-women can catch a unicorn. And then only with a golden rope.
-Only chaotic evils kill sleeping monsters.
-Only david can find the zoo!
-Only real trappers escape traps.
-Only real wizards can write scrolls.
-Only wizards are able to zap a wand.
-Opening a tin is difficult, especially when you are not so strong!
-Opening a tin is difficult, especially when you attempt this bare handed!
-Operation coded OVERKILL has started now.
-Orcs and killer bees share their lifestyle.
-Orcs do not procreate in dark rooms.
-PLEASE ignore previous rumour.
-Plain nymphs are harmless.
-Playing billiards pays when you are in a shop.
-Polymorphing your dog probably makes you safer.
-Praying will frighten Demons.
-Punishment is a thing you call over yourself. So why complain?
-Pursue the monsters and you will be had indeed.
-Put on a ring of teleportation: it will take you away from onslaught.
-Rays aren't boomerangs, of course, but still...
-Read the manual before entering the cave - You might get killed otherwise.
-Reading Herbert will disgust you, but in one case it might be enlightening.
-Reading Tolkien might help you.
-Reading might change your vision.
-Reading might improve your scope.
-Relying on a dog might turn you in a dog addict.
-Reward your doggie with a giant Bat.
-Ropes are made from the long, blond hairs of dead Nymphs.
-Row (3x) that boat gently down the stream, Charon (4x), death is but a dream.
-Running is good for your legs.
-Rust monsters love water. There are potions they hate, however.
-Savings do include amnesia.
-Scorpions often hide under tripe rations.
-Screw up your courage! You've screwed up everything else.
-Scrolls of fire are useful against fog clouds.
-Second Law of Hacking: first in, first out.
-Selling and rebuying a wand will recharge it.
-Shopkeepers accept creditcards, as long as you pay cash.
-Shopkeepers are vegetarians: they only eat Swedes.
-Shopkeepers can't read, so what use is engraving in a shop?
-Shopkeepers can't swim.
-Shopkeepers have incredible patience.
-Shopkeepers often have strange names.
-Shopkeepers sometimes die from old age.
-Sleeping may increase your strength.
-Snakes are often found under worthless objects.
-Some Balrogs don't attack if you offer them a ring.
-Some mazes (especially small ones) have no solutions, says man 6 maze.
-Some monsters can be tamed. I once saw a hacker with a tame Dragon!
-Some potions are quite mind-expanding.
-Some questions Sphynxes ask just *don't* have any answers.
-Sometimes "mu" is the answer.
-Sometimes monsters are more likely to fight each other than attack you.
-Sorry, no fortune this time. Better luck next cookie!
-Spare your scrolls of make-edible until it's really necessary!
-Speed Kills (The Doors)
-Spinach, carrot, and a melon - a meal fit for a nurse!
-Stay clear of the level of no return.
-Suddenly the dungeon will collapse ...
-Surprise your dog with an acid blob!
-Tainted meat is even more sickening than poison!
-Take a long worm from the rear, according to its mate it's a lot more fun.
-Tame a troll and it will learn you fighting.
-Taming a postman may cause a system security violation.
-Taming is a gradual process of excercising and rewarding.
-Telepathy is just a trick: once you know how to do it, it's easy.
-Teleportation lessens your orientation.
-The "pray" command is not yet implemented.
-The Jackal only eats bad food.
-The Leprechaun Gold Tru$t is no division of the Magic Memory Vault.
-The Leprechauns hide their treasure in a small hidden room.
-The air is positively magic in here. Better wear a negative armor.
-The best equipment for your work is, of course, the most expensive.
-The emptiness of a ghost is too heavy to bear.
-The key to this game is that there are no keys.
-The longer the wand the better.
-The moon is not the only heavenly body to influence this game.
-The postman always rings twice.
-The proof of the quivering blob is in the eating thereof.
-The secret of wands of Nothing Happens: try again!
-The use of dynamite is dangerous.
-There are better information sources than fortune cookies.
-There are monsters of softening penetration.
-There are monsters of striking charity.
-There have been people like you in here; their ghosts seek revenge on you.
-There is a VIP-lounge on this level. Only first-class travellers admitted.
-There is a big treasure hidden in the zoo!
-There is a message concealed in each fortune cookie.
-There is a trap on this level!
-There is more magic in this cave than meets the eye.
-There is no business like throw business.
-There is no harm in praising a large dog.
-There is nothing like eating a Mimic.
-There seem to be monsters of touching benevolence.
-They say a gelatinous cube can paralyse you...
-They say that Elven cloaks absorb enchantments.
-They say that a dagger hits.
-They say that a dog avoids traps.
-They say that a dog can be trained to fetch objects.
-They say that a dog never steps on a cursed object.
-They say that a spear will hit a Dragon.
-They say that a spear will hit a Xorn.
-They say that a spear will hit a neo-otyugh. (Do YOU know what that is?)
-They say that a spear will hit an ettin.
-They say that a two-handed sword misses.
-They say that a unicorn might bring you luck.
-They say that an elven cloak may be worn over your armor.
-They say that an elven cloak protects against magic.
-They say that cavemen seldom find tins in the dungeon.
-They say that dead lizards protect against a cockatrice.
-They say that killing a shopkeeper brings bad luck.
-They say that monsters never step on a scare monster scroll.
-They say that only david can find the zoo!
-They say that shopkeepers often have a large amount of money in their purse.
-They say that the owner of the dungeon might change it slightly.
-They say that the use of dynamite is dangerous.
-They say that the walls in shops are made of extra hard material.
-They say that there is a big treasure hidden in the zoo!
-They say that there is a message concealed in each fortune cookie.
-They say that there is a trap on this level!
-They say that throwing food at a wild dog might tame him.
-They say that you can meet old friends in the caves.
-They say that you can't take your pick-axe into a shop.
-They say that you cannot trust scrolls of rumour.
-They say that you need a key in order to open locked doors.
-Third Law of Hacking: the last blow counts most.
-This dungeon is restroom equipped (for your convenience).
-This fortune cookie is property of Fortune Cookies, Inc.
-This is not a fortune.
-This is the Leprechaun Law: every purse has a price.
-Throwing food at a wild dog might tame him.
-Tin openers are rare indeed.
-Tired of irritating bats? Try a scroll of silence.
-To hit or not to hit, that is the question.
-To reach heaven, escape the dungeon while wearing a ring of levitation.
-Tranquillizers might get you killed.
-Travel fast, use some magic speed!
-Tripe on its own is revolting, but with onions it's delicious!
-Try hacking in the wee hours: you will have more room.
-Try the fall back end run play against ghosts.
-Ulch, that meat was painted.
-Unwanted mail? Sell it to the bookshop!
-Vampires hate garlic.
-Vault guards always make sure you aren't a shopkeeper.
-Vault guards never disturb their Lords.
-Visitors are requested not to apply genocide to shopkeepers.
-WARNING from H.M. Govt: Quaffing may be dangerous to your health.
-Wanna fly? Eat a bat.
-Want a hint? Zap a wand of make invisible on your weapon!
-Want fun? Throw a potion in a pool and go swimming!
-Want to conserve your dead corpses? Go to the tin factory!
-Wanted: shopkeepers. Send a scroll of mail to: Mage of Yendor/Level 35/Dungeon.
-Warning: end of file 'fortunes' reached.
-Warning: people who eat dragons can go to hell!!
-Watch your steps on staircases.
-Wear armor, going naked seems to offend public decency in here.
-What a pity, you cannot read it!
-What do you think is the use of dead lizards?
-What do you think would be the use of a two handed sword called "Orcrist" ?
-When a piercer drops in on you, you will be tempted to hit the ceiling!
-When in a maze follow the right wall and you will never get lost.
-When in a shop, do as shopkeepers do.
-When punished, watch your steps on the stairs!
-When you have a key, you don't have to wait for the guard.
-When you have seen one killer bee, you have seen them all.
-When your dog follows you through a trap door, don't hit it!
-Where do you think all those demons come from? From Hell, of course.
-Where do you think the hell is located? It must be deep, deep down.
-Who should ever have thought one could live from eating fog clouds?
-Why a "2" for the postman? Well, how many times does he ring?
-Why should one ever throw an egg to a cockatrice?
-Why would anybody in his sane mind engrave "Elbereth" ?
-Wish for a master key and open the Magic Memory Vault!
-Wish for a pass-key and pass all obstacles!
-Wish for a skeleton-key and open all doors!
-Wishing too much may bring you too little.
-Wizards do not sleep.
-You are heading for head-stone for sure.
-You are just the kind of bad food some monsters like to digest.
-You can always wear an elven cloak.
-You can eat what your dog can eat.
-You can get a genuine Amulet of Yendor by doing the following: -- more --
-You can't get rid of a cursed plate mail with a can-opener.
-You can't leave a shop through the back door: there ain't one!
-You cannot ride a long worm.
-You cannot trust scrolls of rumour.
-You die...
-You feel greedy and want more gold? Why don't you try digging?
-You feel like someone is pulling your leg.
-You have to outwit a Sphynx or pay her.
-You may get rich selling letters, but beware of being blackmailed!
-You may have a kick from kicking a little dog.
-You might choke on your food by eating fortune cookies.
-You might cut yourself on a long sword.
-You might trick a shopkeeper if you're invisible.
-You need a key in order to open locked doors.
-You offend Shai-Hulud by sheathing your crysknife without having drawn blood.
-You want to regain strength? Two levels ahead is a guesthouse!
-You'll need a spear if you want to attack a Dragon.
-You've got to know how to put out a yellow light.
-Your dog can buy cheaper than you do.
-Zapping a wand of Nothing Happens doesn't harm you a bit.
-Zapping a wand of undead turning might bring your dog back to life.
diff --git a/games/monop/Makefile b/games/monop/Makefile
index 1b682754a02e..38a673592b2e 100644
--- a/games/monop/Makefile
+++ b/games/monop/Makefile
@@ -13,7 +13,7 @@ cards.pck: initdeck
./initdeck ${.CURDIR}/cards.inp
initdeck: initdeck.c
- ${CC} ${CFLAGS} -o ${.TARGET} ${.CURDIR}/initdeck.c
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} ${.CURDIR}/initdeck.c
beforeinstall:
install ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 cards.pck \
diff --git a/games/monop/misc.c b/games/monop/misc.c
index 836437a48f26..aec843a8869a 100644
--- a/games/monop/misc.c
+++ b/games/monop/misc.c
@@ -303,6 +303,8 @@ shell_out() {
shell = shell_in();
fflush(stdout);
if (!fork()) {
+ setuid(getuid());
+ setgid(getgid());
signal(SIGINT, SIG_DFL);
execsh(shell);
}
diff --git a/games/sail/dr_main.c b/games/sail/dr_main.c
index c6e49681a9a9..7fe24f110f9a 100644
--- a/games/sail/dr_main.c
+++ b/games/sail/dr_main.c
@@ -48,7 +48,7 @@ dr_main()
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGTSTP, SIG_IGN);
if (issetuid)
- (void) setruid(geteuid());
+ (void) setuid(geteuid());
if (game < 0 || game >= NSCENE) {
fprintf(stderr, "DRIVER: Bad game number %d\n", game);
exit(1);
diff --git a/gnu/lib/Makefile b/gnu/lib/Makefile
index d51120c8632a..1eea41d398aa 100644
--- a/gnu/lib/Makefile
+++ b/gnu/lib/Makefile
@@ -1,5 +1,5 @@
-# $Id: Makefile,v 1.1 1994/01/30 01:03:08 rgrimes Exp $
+# $Id: Makefile,v 1.2 1994/05/09 16:11:10 ache Exp $
-SUBDIR= libg++ libmalloc libregex
+SUBDIR= libg++ libmalloc libregex libreadline
.include <bsd.subdir.mk>
diff --git a/gnu/lib/Makefile.inc b/gnu/lib/Makefile.inc
index b0e5d4bdbc8d..fca604a41eac 100644
--- a/gnu/lib/Makefile.inc
+++ b/gnu/lib/Makefile.inc
@@ -1,4 +1,8 @@
-# $Id: Makefile.inc,v 1.1 1994/01/30 01:03:16 rgrimes Exp $
+# $Id: Makefile.inc,v 1.3 1994/05/28 09:56:30 csgr Exp $
SHLIB_MAJOR?= 1
-SHLIB_MINOR?= 0
+SHLIB_MINOR?= 1
+
+
+# NB: SHLIB major and minor nos. must also be specified in libg++/Makefile.inc
+# (This is due to the deeper tree structure of libg++)
diff --git a/gnu/lib/libg++/Makefile b/gnu/lib/libg++/Makefile
index 6d6b02d6c82e..158c7bd3254a 100644
--- a/gnu/lib/libg++/Makefile
+++ b/gnu/lib/libg++/Makefile
@@ -1,6 +1,6 @@
SUBDIR= libg++ genclass
-INCLUDEDIRS= iostream libg++ g++-include
+INCLUDEDIRS= iostream libg++
beforeinstall:
@-if [ ! -d ${DESTDIR}/usr/include/g++ ]; then \
@@ -8,16 +8,6 @@ beforeinstall:
chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/include/g++; \
chmod 755 ${DESTDIR}/usr/include/g++; \
fi
- @-if [ ! -d ${DESTDIR}/usr/include/g++/gen ]; then \
- mkdir ${DESTDIR}/usr/include/g++/gen; \
- chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/include/g++/gen; \
- chmod 755 ${DESTDIR}/usr/include/g++/gen; \
- fi
- @-if [ ! -d ${DESTDIR}/usr/include/g++/sys ]; then \
- mkdir ${DESTDIR}/usr/include/g++/sys; \
- chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/include/g++/sys; \
- chmod 755 ${DESTDIR}/usr/include/g++/sys; \
- fi
@-for i in ${INCLUDEDIRS}; do \
echo installing includes from $$i ; \
(cd $$i; for j in *.[ih]; do \
@@ -26,17 +16,15 @@ beforeinstall:
${DESTDIR}/usr/include/g++/$$j; \
done); \
done
- @echo installing includes from g++-include/sys
- @(cd g++-include/sys ; for j in *.[ih]; do \
- cmp -s $$j ${DESTDIR}/usr/include/g++/sys/$$j || \
+ @(cd g++-include ; for j in *.*P; do \
+ cmp -s $$j ${DESTDIR}/usr/include/g++/$$j || \
install -c -o ${BINOWN} -g ${BINGRP} -m 444 $$j \
- ${DESTDIR}/usr/include/g++/sys/$$j; \
+ ${DESTDIR}/usr/include/g++/$$j; \
done)
- @echo installing includes from g++-include/gen
- @(cd g++-include/gen ; for j in *.*P; do \
- cmp -s $$j ${DESTDIR}/usr/include/g++/gen/$$j || \
+ @(cd include ; for j in *.h; do \
+ cmp -s $$j ${DESTDIR}/usr/include/$$j || \
install -c -o ${BINOWN} -g ${BINGRP} -m 444 $$j \
- ${DESTDIR}/usr/include/g++/gen/$$j; \
+ ${DESTDIR}/usr/include/$$j; \
done)
.include <bsd.subdir.mk>
diff --git a/gnu/lib/libg++/Makefile.inc b/gnu/lib/libg++/Makefile.inc
index e528d08dc10c..ff12eac227d5 100644
--- a/gnu/lib/libg++/Makefile.inc
+++ b/gnu/lib/libg++/Makefile.inc
@@ -1 +1,9 @@
-NOPIC?= nopic
+# $Id: Makefile.inc,v 1.10 1994/06/13 21:50:02 ache Exp $
+
+CPLUSPLUSLIB= yes
+
+# SHLIB major and minor nos. MUST be specified here.
+# Do not remove the following 2 lines.
+SHLIB_MAJOR=1
+SHLIB_MINOR=1
+
diff --git a/gnu/lib/libg++/g++-include/gen/AVLMap.ccP b/gnu/lib/libg++/g++-include/AVLMap.ccP
index a9be60f06612..a9be60f06612 100644
--- a/gnu/lib/libg++/g++-include/gen/AVLMap.ccP
+++ b/gnu/lib/libg++/g++-include/AVLMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/AVLMap.hP b/gnu/lib/libg++/g++-include/AVLMap.hP
index 119ee82caa33..119ee82caa33 100644
--- a/gnu/lib/libg++/g++-include/gen/AVLMap.hP
+++ b/gnu/lib/libg++/g++-include/AVLMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/AVLSet.ccP b/gnu/lib/libg++/g++-include/AVLSet.ccP
index b170734e547f..b170734e547f 100644
--- a/gnu/lib/libg++/g++-include/gen/AVLSet.ccP
+++ b/gnu/lib/libg++/g++-include/AVLSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/AVLSet.hP b/gnu/lib/libg++/g++-include/AVLSet.hP
index 16ad1d194686..16ad1d194686 100644
--- a/gnu/lib/libg++/g++-include/gen/AVLSet.hP
+++ b/gnu/lib/libg++/g++-include/AVLSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/AVec.ccP b/gnu/lib/libg++/g++-include/AVec.ccP
index bc671bf8e1d7..bc671bf8e1d7 100644
--- a/gnu/lib/libg++/g++-include/gen/AVec.ccP
+++ b/gnu/lib/libg++/g++-include/AVec.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/AVec.hP b/gnu/lib/libg++/g++-include/AVec.hP
index cd9a9c3fe5d6..cd9a9c3fe5d6 100644
--- a/gnu/lib/libg++/g++-include/gen/AVec.hP
+++ b/gnu/lib/libg++/g++-include/AVec.hP
diff --git a/gnu/lib/libg++/g++-include/gen/BSTSet.ccP b/gnu/lib/libg++/g++-include/BSTSet.ccP
index 6a69d8f45b28..6a69d8f45b28 100644
--- a/gnu/lib/libg++/g++-include/gen/BSTSet.ccP
+++ b/gnu/lib/libg++/g++-include/BSTSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/BSTSet.hP b/gnu/lib/libg++/g++-include/BSTSet.hP
index 82f2069c0fa5..82f2069c0fa5 100644
--- a/gnu/lib/libg++/g++-include/gen/BSTSet.hP
+++ b/gnu/lib/libg++/g++-include/BSTSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Bag.ccP b/gnu/lib/libg++/g++-include/Bag.ccP
index 836d0d6656d2..836d0d6656d2 100644
--- a/gnu/lib/libg++/g++-include/gen/Bag.ccP
+++ b/gnu/lib/libg++/g++-include/Bag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Bag.hP b/gnu/lib/libg++/g++-include/Bag.hP
index 4b9a87a9099c..4b9a87a9099c 100644
--- a/gnu/lib/libg++/g++-include/gen/Bag.hP
+++ b/gnu/lib/libg++/g++-include/Bag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/CHBag.ccP b/gnu/lib/libg++/g++-include/CHBag.ccP
index 16649ac22f2f..16649ac22f2f 100644
--- a/gnu/lib/libg++/g++-include/gen/CHBag.ccP
+++ b/gnu/lib/libg++/g++-include/CHBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/CHBag.hP b/gnu/lib/libg++/g++-include/CHBag.hP
index f6ca10b3b93e..f6ca10b3b93e 100644
--- a/gnu/lib/libg++/g++-include/gen/CHBag.hP
+++ b/gnu/lib/libg++/g++-include/CHBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/CHMap.ccP b/gnu/lib/libg++/g++-include/CHMap.ccP
index 1bd76db5fc97..1bd76db5fc97 100644
--- a/gnu/lib/libg++/g++-include/gen/CHMap.ccP
+++ b/gnu/lib/libg++/g++-include/CHMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/CHMap.hP b/gnu/lib/libg++/g++-include/CHMap.hP
index 95441a3544fd..95441a3544fd 100644
--- a/gnu/lib/libg++/g++-include/gen/CHMap.hP
+++ b/gnu/lib/libg++/g++-include/CHMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/CHNode.ccP b/gnu/lib/libg++/g++-include/CHNode.ccP
index e16725fd746c..e16725fd746c 100644
--- a/gnu/lib/libg++/g++-include/gen/CHNode.ccP
+++ b/gnu/lib/libg++/g++-include/CHNode.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/CHNode.hP b/gnu/lib/libg++/g++-include/CHNode.hP
index 84e67d069bee..84e67d069bee 100644
--- a/gnu/lib/libg++/g++-include/gen/CHNode.hP
+++ b/gnu/lib/libg++/g++-include/CHNode.hP
diff --git a/gnu/lib/libg++/g++-include/gen/CHSet.ccP b/gnu/lib/libg++/g++-include/CHSet.ccP
index 330506cb1932..330506cb1932 100644
--- a/gnu/lib/libg++/g++-include/gen/CHSet.ccP
+++ b/gnu/lib/libg++/g++-include/CHSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/CHSet.hP b/gnu/lib/libg++/g++-include/CHSet.hP
index f0a08de4ce6b..f0a08de4ce6b 100644
--- a/gnu/lib/libg++/g++-include/gen/CHSet.hP
+++ b/gnu/lib/libg++/g++-include/CHSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/DLDeque.ccP b/gnu/lib/libg++/g++-include/DLDeque.ccP
index d5a0db7f910a..d5a0db7f910a 100644
--- a/gnu/lib/libg++/g++-include/gen/DLDeque.ccP
+++ b/gnu/lib/libg++/g++-include/DLDeque.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/DLDeque.hP b/gnu/lib/libg++/g++-include/DLDeque.hP
index d91cdd41cbc7..d91cdd41cbc7 100644
--- a/gnu/lib/libg++/g++-include/gen/DLDeque.hP
+++ b/gnu/lib/libg++/g++-include/DLDeque.hP
diff --git a/gnu/lib/libg++/g++-include/gen/DLList.ccP b/gnu/lib/libg++/g++-include/DLList.ccP
index cb1e22a33773..cb1e22a33773 100644
--- a/gnu/lib/libg++/g++-include/gen/DLList.ccP
+++ b/gnu/lib/libg++/g++-include/DLList.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/DLList.hP b/gnu/lib/libg++/g++-include/DLList.hP
index b115ab9f6fbb..b115ab9f6fbb 100644
--- a/gnu/lib/libg++/g++-include/gen/DLList.hP
+++ b/gnu/lib/libg++/g++-include/DLList.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Deque.ccP b/gnu/lib/libg++/g++-include/Deque.ccP
index 79a9b72c875c..79a9b72c875c 100644
--- a/gnu/lib/libg++/g++-include/gen/Deque.ccP
+++ b/gnu/lib/libg++/g++-include/Deque.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Deque.hP b/gnu/lib/libg++/g++-include/Deque.hP
index 7ec52d4a0c0f..7ec52d4a0c0f 100644
--- a/gnu/lib/libg++/g++-include/gen/Deque.hP
+++ b/gnu/lib/libg++/g++-include/Deque.hP
diff --git a/gnu/lib/libg++/g++-include/gen/FPQueue.ccP b/gnu/lib/libg++/g++-include/FPQueue.ccP
index a358cacb60ee..a358cacb60ee 100644
--- a/gnu/lib/libg++/g++-include/gen/FPQueue.ccP
+++ b/gnu/lib/libg++/g++-include/FPQueue.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/FPQueue.hP b/gnu/lib/libg++/g++-include/FPQueue.hP
index f647ae9dfd01..f647ae9dfd01 100644
--- a/gnu/lib/libg++/g++-include/gen/FPQueue.hP
+++ b/gnu/lib/libg++/g++-include/FPQueue.hP
diff --git a/gnu/lib/libg++/g++-include/gen/FPStack.ccP b/gnu/lib/libg++/g++-include/FPStack.ccP
index 954991193b7a..954991193b7a 100644
--- a/gnu/lib/libg++/g++-include/gen/FPStack.ccP
+++ b/gnu/lib/libg++/g++-include/FPStack.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/FPStack.hP b/gnu/lib/libg++/g++-include/FPStack.hP
index 091f25536002..091f25536002 100644
--- a/gnu/lib/libg++/g++-include/gen/FPStack.hP
+++ b/gnu/lib/libg++/g++-include/FPStack.hP
diff --git a/gnu/lib/libg++/g++-include/gen/FPlex.ccP b/gnu/lib/libg++/g++-include/FPlex.ccP
index 70d6c475571e..70d6c475571e 100644
--- a/gnu/lib/libg++/g++-include/gen/FPlex.ccP
+++ b/gnu/lib/libg++/g++-include/FPlex.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/FPlex.hP b/gnu/lib/libg++/g++-include/FPlex.hP
index eb93a0c37281..eb93a0c37281 100644
--- a/gnu/lib/libg++/g++-include/gen/FPlex.hP
+++ b/gnu/lib/libg++/g++-include/FPlex.hP
diff --git a/gnu/lib/libg++/g++-include/gen/List.ccP b/gnu/lib/libg++/g++-include/List.ccP
index 2afbdaf97215..2afbdaf97215 100644
--- a/gnu/lib/libg++/g++-include/gen/List.ccP
+++ b/gnu/lib/libg++/g++-include/List.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/List.hP b/gnu/lib/libg++/g++-include/List.hP
index 7ccdbc3bc41f..7ccdbc3bc41f 100644
--- a/gnu/lib/libg++/g++-include/gen/List.hP
+++ b/gnu/lib/libg++/g++-include/List.hP
diff --git a/gnu/lib/libg++/g++-include/gen/MPlex.ccP b/gnu/lib/libg++/g++-include/MPlex.ccP
index 89a1bcf9e600..89a1bcf9e600 100644
--- a/gnu/lib/libg++/g++-include/gen/MPlex.ccP
+++ b/gnu/lib/libg++/g++-include/MPlex.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/MPlex.hP b/gnu/lib/libg++/g++-include/MPlex.hP
index 8bf78d13a135..8bf78d13a135 100644
--- a/gnu/lib/libg++/g++-include/gen/MPlex.hP
+++ b/gnu/lib/libg++/g++-include/MPlex.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Map.ccP b/gnu/lib/libg++/g++-include/Map.ccP
index 03bb4b84f0fd..03bb4b84f0fd 100644
--- a/gnu/lib/libg++/g++-include/gen/Map.ccP
+++ b/gnu/lib/libg++/g++-include/Map.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Map.hP b/gnu/lib/libg++/g++-include/Map.hP
index 716a17fdd9ee..716a17fdd9ee 100644
--- a/gnu/lib/libg++/g++-include/gen/Map.hP
+++ b/gnu/lib/libg++/g++-include/Map.hP
diff --git a/gnu/lib/libg++/g++-include/gen/OSLBag.ccP b/gnu/lib/libg++/g++-include/OSLBag.ccP
index 78398192bcef..78398192bcef 100644
--- a/gnu/lib/libg++/g++-include/gen/OSLBag.ccP
+++ b/gnu/lib/libg++/g++-include/OSLBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/OSLBag.hP b/gnu/lib/libg++/g++-include/OSLBag.hP
index de4d67cf9a5d..de4d67cf9a5d 100644
--- a/gnu/lib/libg++/g++-include/gen/OSLBag.hP
+++ b/gnu/lib/libg++/g++-include/OSLBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/OSLSet.ccP b/gnu/lib/libg++/g++-include/OSLSet.ccP
index bfd32ae954ce..bfd32ae954ce 100644
--- a/gnu/lib/libg++/g++-include/gen/OSLSet.ccP
+++ b/gnu/lib/libg++/g++-include/OSLSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/OSLSet.hP b/gnu/lib/libg++/g++-include/OSLSet.hP
index bf3707f6c7b0..bf3707f6c7b0 100644
--- a/gnu/lib/libg++/g++-include/gen/OSLSet.hP
+++ b/gnu/lib/libg++/g++-include/OSLSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/OXPBag.ccP b/gnu/lib/libg++/g++-include/OXPBag.ccP
index 6619e25ea191..6619e25ea191 100644
--- a/gnu/lib/libg++/g++-include/gen/OXPBag.ccP
+++ b/gnu/lib/libg++/g++-include/OXPBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/OXPBag.hP b/gnu/lib/libg++/g++-include/OXPBag.hP
index 128d4a20e401..128d4a20e401 100644
--- a/gnu/lib/libg++/g++-include/gen/OXPBag.hP
+++ b/gnu/lib/libg++/g++-include/OXPBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/OXPSet.ccP b/gnu/lib/libg++/g++-include/OXPSet.ccP
index 14611954511e..14611954511e 100644
--- a/gnu/lib/libg++/g++-include/gen/OXPSet.ccP
+++ b/gnu/lib/libg++/g++-include/OXPSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/OXPSet.hP b/gnu/lib/libg++/g++-include/OXPSet.hP
index 4e0c97712d2a..4e0c97712d2a 100644
--- a/gnu/lib/libg++/g++-include/gen/OXPSet.hP
+++ b/gnu/lib/libg++/g++-include/OXPSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/PHPQ.ccP b/gnu/lib/libg++/g++-include/PHPQ.ccP
index 764b11c5cf99..764b11c5cf99 100644
--- a/gnu/lib/libg++/g++-include/gen/PHPQ.ccP
+++ b/gnu/lib/libg++/g++-include/PHPQ.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/PHPQ.hP b/gnu/lib/libg++/g++-include/PHPQ.hP
index 359c527c602c..359c527c602c 100644
--- a/gnu/lib/libg++/g++-include/gen/PHPQ.hP
+++ b/gnu/lib/libg++/g++-include/PHPQ.hP
diff --git a/gnu/lib/libg++/g++-include/gen/PQ.ccP b/gnu/lib/libg++/g++-include/PQ.ccP
index 810240759cbf..810240759cbf 100644
--- a/gnu/lib/libg++/g++-include/gen/PQ.ccP
+++ b/gnu/lib/libg++/g++-include/PQ.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/PQ.hP b/gnu/lib/libg++/g++-include/PQ.hP
index 981592ae856b..981592ae856b 100644
--- a/gnu/lib/libg++/g++-include/gen/PQ.hP
+++ b/gnu/lib/libg++/g++-include/PQ.hP
diff --git a/gnu/lib/libg++/g++-include/gen/PSList.hP b/gnu/lib/libg++/g++-include/PSList.hP
index eacb34dbe354..eacb34dbe354 100644
--- a/gnu/lib/libg++/g++-include/gen/PSList.hP
+++ b/gnu/lib/libg++/g++-include/PSList.hP
diff --git a/gnu/lib/libg++/g++-include/gen/PVec.hP b/gnu/lib/libg++/g++-include/PVec.hP
index de32482610b4..de32482610b4 100644
--- a/gnu/lib/libg++/g++-include/gen/PVec.hP
+++ b/gnu/lib/libg++/g++-include/PVec.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Plex.ccP b/gnu/lib/libg++/g++-include/Plex.ccP
index 5eb13c85f488..5eb13c85f488 100644
--- a/gnu/lib/libg++/g++-include/gen/Plex.ccP
+++ b/gnu/lib/libg++/g++-include/Plex.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Plex.hP b/gnu/lib/libg++/g++-include/Plex.hP
index f8af1b6ba7ca..f8af1b6ba7ca 100644
--- a/gnu/lib/libg++/g++-include/gen/Plex.hP
+++ b/gnu/lib/libg++/g++-include/Plex.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Queue.ccP b/gnu/lib/libg++/g++-include/Queue.ccP
index fb48d952ff71..fb48d952ff71 100644
--- a/gnu/lib/libg++/g++-include/gen/Queue.ccP
+++ b/gnu/lib/libg++/g++-include/Queue.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Queue.hP b/gnu/lib/libg++/g++-include/Queue.hP
index 73db6e034eb2..73db6e034eb2 100644
--- a/gnu/lib/libg++/g++-include/gen/Queue.hP
+++ b/gnu/lib/libg++/g++-include/Queue.hP
diff --git a/gnu/lib/libg++/g++-include/gen/RAVLMap.ccP b/gnu/lib/libg++/g++-include/RAVLMap.ccP
index 7537dd07884d..7537dd07884d 100644
--- a/gnu/lib/libg++/g++-include/gen/RAVLMap.ccP
+++ b/gnu/lib/libg++/g++-include/RAVLMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/RAVLMap.hP b/gnu/lib/libg++/g++-include/RAVLMap.hP
index d3c523ee2978..d3c523ee2978 100644
--- a/gnu/lib/libg++/g++-include/gen/RAVLMap.hP
+++ b/gnu/lib/libg++/g++-include/RAVLMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/RPlex.ccP b/gnu/lib/libg++/g++-include/RPlex.ccP
index 0dbd2cee7e49..0dbd2cee7e49 100644
--- a/gnu/lib/libg++/g++-include/gen/RPlex.ccP
+++ b/gnu/lib/libg++/g++-include/RPlex.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/RPlex.hP b/gnu/lib/libg++/g++-include/RPlex.hP
index ed28c357e4d1..ed28c357e4d1 100644
--- a/gnu/lib/libg++/g++-include/gen/RPlex.hP
+++ b/gnu/lib/libg++/g++-include/RPlex.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SLBag.ccP b/gnu/lib/libg++/g++-include/SLBag.ccP
index 50d2447c7d29..50d2447c7d29 100644
--- a/gnu/lib/libg++/g++-include/gen/SLBag.ccP
+++ b/gnu/lib/libg++/g++-include/SLBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SLBag.hP b/gnu/lib/libg++/g++-include/SLBag.hP
index edb648e9d3a2..edb648e9d3a2 100644
--- a/gnu/lib/libg++/g++-include/gen/SLBag.hP
+++ b/gnu/lib/libg++/g++-include/SLBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SLList.ccP b/gnu/lib/libg++/g++-include/SLList.ccP
index 3ebd8d5bc98d..3ebd8d5bc98d 100644
--- a/gnu/lib/libg++/g++-include/gen/SLList.ccP
+++ b/gnu/lib/libg++/g++-include/SLList.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SLList.hP b/gnu/lib/libg++/g++-include/SLList.hP
index e5570bdf8fec..e5570bdf8fec 100644
--- a/gnu/lib/libg++/g++-include/gen/SLList.hP
+++ b/gnu/lib/libg++/g++-include/SLList.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SLQueue.ccP b/gnu/lib/libg++/g++-include/SLQueue.ccP
index 8a5935b77570..8a5935b77570 100644
--- a/gnu/lib/libg++/g++-include/gen/SLQueue.ccP
+++ b/gnu/lib/libg++/g++-include/SLQueue.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SLQueue.hP b/gnu/lib/libg++/g++-include/SLQueue.hP
index 20fd74c9c57e..20fd74c9c57e 100644
--- a/gnu/lib/libg++/g++-include/gen/SLQueue.hP
+++ b/gnu/lib/libg++/g++-include/SLQueue.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SLSet.ccP b/gnu/lib/libg++/g++-include/SLSet.ccP
index 5f580849ff34..5f580849ff34 100644
--- a/gnu/lib/libg++/g++-include/gen/SLSet.ccP
+++ b/gnu/lib/libg++/g++-include/SLSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SLSet.hP b/gnu/lib/libg++/g++-include/SLSet.hP
index fcf153633f80..fcf153633f80 100644
--- a/gnu/lib/libg++/g++-include/gen/SLSet.hP
+++ b/gnu/lib/libg++/g++-include/SLSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SLStack.ccP b/gnu/lib/libg++/g++-include/SLStack.ccP
index 3996b41fac55..3996b41fac55 100644
--- a/gnu/lib/libg++/g++-include/gen/SLStack.ccP
+++ b/gnu/lib/libg++/g++-include/SLStack.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SLStack.hP b/gnu/lib/libg++/g++-include/SLStack.hP
index e20d9b9c2a47..e20d9b9c2a47 100644
--- a/gnu/lib/libg++/g++-include/gen/SLStack.hP
+++ b/gnu/lib/libg++/g++-include/SLStack.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Set.ccP b/gnu/lib/libg++/g++-include/Set.ccP
index f312aa15cc75..f312aa15cc75 100644
--- a/gnu/lib/libg++/g++-include/gen/Set.ccP
+++ b/gnu/lib/libg++/g++-include/Set.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Set.hP b/gnu/lib/libg++/g++-include/Set.hP
index 6c2192262711..6c2192262711 100644
--- a/gnu/lib/libg++/g++-include/gen/Set.hP
+++ b/gnu/lib/libg++/g++-include/Set.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipBag.ccP b/gnu/lib/libg++/g++-include/SkipBag.ccP
index cc347e981338..cc347e981338 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipBag.ccP
+++ b/gnu/lib/libg++/g++-include/SkipBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipBag.hP b/gnu/lib/libg++/g++-include/SkipBag.hP
index 1bfe9da44627..1bfe9da44627 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipBag.hP
+++ b/gnu/lib/libg++/g++-include/SkipBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipMap.ccP b/gnu/lib/libg++/g++-include/SkipMap.ccP
index 8b6afe2eddf3..8b6afe2eddf3 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipMap.ccP
+++ b/gnu/lib/libg++/g++-include/SkipMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipMap.hP b/gnu/lib/libg++/g++-include/SkipMap.hP
index 65766d64c7a7..65766d64c7a7 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipMap.hP
+++ b/gnu/lib/libg++/g++-include/SkipMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipSet.ccP b/gnu/lib/libg++/g++-include/SkipSet.ccP
index a1bf33d0fa01..a1bf33d0fa01 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipSet.ccP
+++ b/gnu/lib/libg++/g++-include/SkipSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SkipSet.hP b/gnu/lib/libg++/g++-include/SkipSet.hP
index cd953052394d..cd953052394d 100644
--- a/gnu/lib/libg++/g++-include/gen/SkipSet.hP
+++ b/gnu/lib/libg++/g++-include/SkipSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayBag.ccP b/gnu/lib/libg++/g++-include/SplayBag.ccP
index ff02a992a656..ff02a992a656 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayBag.ccP
+++ b/gnu/lib/libg++/g++-include/SplayBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayBag.hP b/gnu/lib/libg++/g++-include/SplayBag.hP
index 9d7fcad1ddc3..9d7fcad1ddc3 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayBag.hP
+++ b/gnu/lib/libg++/g++-include/SplayBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayMap.ccP b/gnu/lib/libg++/g++-include/SplayMap.ccP
index 4be340db0f6d..4be340db0f6d 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayMap.ccP
+++ b/gnu/lib/libg++/g++-include/SplayMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayMap.hP b/gnu/lib/libg++/g++-include/SplayMap.hP
index ced95378ab72..ced95378ab72 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayMap.hP
+++ b/gnu/lib/libg++/g++-include/SplayMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayNode.ccP b/gnu/lib/libg++/g++-include/SplayNode.ccP
index 9dfb1d8c0658..9dfb1d8c0658 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayNode.ccP
+++ b/gnu/lib/libg++/g++-include/SplayNode.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayNode.hP b/gnu/lib/libg++/g++-include/SplayNode.hP
index a196861fc9cc..a196861fc9cc 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayNode.hP
+++ b/gnu/lib/libg++/g++-include/SplayNode.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayPQ.ccP b/gnu/lib/libg++/g++-include/SplayPQ.ccP
index 0740cd9a930d..0740cd9a930d 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayPQ.ccP
+++ b/gnu/lib/libg++/g++-include/SplayPQ.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SplayPQ.hP b/gnu/lib/libg++/g++-include/SplayPQ.hP
index c75c4a05299d..c75c4a05299d 100644
--- a/gnu/lib/libg++/g++-include/gen/SplayPQ.hP
+++ b/gnu/lib/libg++/g++-include/SplayPQ.hP
diff --git a/gnu/lib/libg++/g++-include/gen/SplaySet.ccP b/gnu/lib/libg++/g++-include/SplaySet.ccP
index bba5601c7eb6..bba5601c7eb6 100644
--- a/gnu/lib/libg++/g++-include/gen/SplaySet.ccP
+++ b/gnu/lib/libg++/g++-include/SplaySet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/SplaySet.hP b/gnu/lib/libg++/g++-include/SplaySet.hP
index cf50b975548a..cf50b975548a 100644
--- a/gnu/lib/libg++/g++-include/gen/SplaySet.hP
+++ b/gnu/lib/libg++/g++-include/SplaySet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Stack.ccP b/gnu/lib/libg++/g++-include/Stack.ccP
index efb6b8edbde5..efb6b8edbde5 100644
--- a/gnu/lib/libg++/g++-include/gen/Stack.ccP
+++ b/gnu/lib/libg++/g++-include/Stack.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Stack.hP b/gnu/lib/libg++/g++-include/Stack.hP
index 37acb2fac5b7..37acb2fac5b7 100644
--- a/gnu/lib/libg++/g++-include/gen/Stack.hP
+++ b/gnu/lib/libg++/g++-include/Stack.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VHBag.ccP b/gnu/lib/libg++/g++-include/VHBag.ccP
index 81a20eb140db..81a20eb140db 100644
--- a/gnu/lib/libg++/g++-include/gen/VHBag.ccP
+++ b/gnu/lib/libg++/g++-include/VHBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VHBag.hP b/gnu/lib/libg++/g++-include/VHBag.hP
index 72c774a5591d..72c774a5591d 100644
--- a/gnu/lib/libg++/g++-include/gen/VHBag.hP
+++ b/gnu/lib/libg++/g++-include/VHBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VHMap.ccP b/gnu/lib/libg++/g++-include/VHMap.ccP
index d6b60e997a9c..d6b60e997a9c 100644
--- a/gnu/lib/libg++/g++-include/gen/VHMap.ccP
+++ b/gnu/lib/libg++/g++-include/VHMap.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VHMap.hP b/gnu/lib/libg++/g++-include/VHMap.hP
index ac8fe4d219a8..ac8fe4d219a8 100644
--- a/gnu/lib/libg++/g++-include/gen/VHMap.hP
+++ b/gnu/lib/libg++/g++-include/VHMap.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VHSet.ccP b/gnu/lib/libg++/g++-include/VHSet.ccP
index a78b319834c1..a78b319834c1 100644
--- a/gnu/lib/libg++/g++-include/gen/VHSet.ccP
+++ b/gnu/lib/libg++/g++-include/VHSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VHSet.hP b/gnu/lib/libg++/g++-include/VHSet.hP
index b7b3a3578c5a..b7b3a3578c5a 100644
--- a/gnu/lib/libg++/g++-include/gen/VHSet.hP
+++ b/gnu/lib/libg++/g++-include/VHSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VOHSet.ccP b/gnu/lib/libg++/g++-include/VOHSet.ccP
index c5d4557a4cb4..c5d4557a4cb4 100644
--- a/gnu/lib/libg++/g++-include/gen/VOHSet.ccP
+++ b/gnu/lib/libg++/g++-include/VOHSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VOHSet.hP b/gnu/lib/libg++/g++-include/VOHSet.hP
index 94decaad123b..94decaad123b 100644
--- a/gnu/lib/libg++/g++-include/gen/VOHSet.hP
+++ b/gnu/lib/libg++/g++-include/VOHSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VQueue.ccP b/gnu/lib/libg++/g++-include/VQueue.ccP
index 1181b3f50d6a..1181b3f50d6a 100644
--- a/gnu/lib/libg++/g++-include/gen/VQueue.ccP
+++ b/gnu/lib/libg++/g++-include/VQueue.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VQueue.hP b/gnu/lib/libg++/g++-include/VQueue.hP
index cce2c85d24af..cce2c85d24af 100644
--- a/gnu/lib/libg++/g++-include/gen/VQueue.hP
+++ b/gnu/lib/libg++/g++-include/VQueue.hP
diff --git a/gnu/lib/libg++/g++-include/gen/VStack.ccP b/gnu/lib/libg++/g++-include/VStack.ccP
index 5203d51341d4..5203d51341d4 100644
--- a/gnu/lib/libg++/g++-include/gen/VStack.ccP
+++ b/gnu/lib/libg++/g++-include/VStack.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/VStack.hP b/gnu/lib/libg++/g++-include/VStack.hP
index c8190bf06407..c8190bf06407 100644
--- a/gnu/lib/libg++/g++-include/gen/VStack.hP
+++ b/gnu/lib/libg++/g++-include/VStack.hP
diff --git a/gnu/lib/libg++/g++-include/gen/Vec.ccP b/gnu/lib/libg++/g++-include/Vec.ccP
index c9cbfb2109e6..c9cbfb2109e6 100644
--- a/gnu/lib/libg++/g++-include/gen/Vec.ccP
+++ b/gnu/lib/libg++/g++-include/Vec.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/Vec.hP b/gnu/lib/libg++/g++-include/Vec.hP
index 97ff3f5fef09..97ff3f5fef09 100644
--- a/gnu/lib/libg++/g++-include/gen/Vec.hP
+++ b/gnu/lib/libg++/g++-include/Vec.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPBag.ccP b/gnu/lib/libg++/g++-include/XPBag.ccP
index 76dc35cf3932..76dc35cf3932 100644
--- a/gnu/lib/libg++/g++-include/gen/XPBag.ccP
+++ b/gnu/lib/libg++/g++-include/XPBag.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPBag.hP b/gnu/lib/libg++/g++-include/XPBag.hP
index 296a59082d0b..296a59082d0b 100644
--- a/gnu/lib/libg++/g++-include/gen/XPBag.hP
+++ b/gnu/lib/libg++/g++-include/XPBag.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPDeque.ccP b/gnu/lib/libg++/g++-include/XPDeque.ccP
index 6b363d9bdc4e..6b363d9bdc4e 100644
--- a/gnu/lib/libg++/g++-include/gen/XPDeque.ccP
+++ b/gnu/lib/libg++/g++-include/XPDeque.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPDeque.hP b/gnu/lib/libg++/g++-include/XPDeque.hP
index b8e7c8268f08..b8e7c8268f08 100644
--- a/gnu/lib/libg++/g++-include/gen/XPDeque.hP
+++ b/gnu/lib/libg++/g++-include/XPDeque.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPPQ.ccP b/gnu/lib/libg++/g++-include/XPPQ.ccP
index 41515a39bbbf..41515a39bbbf 100644
--- a/gnu/lib/libg++/g++-include/gen/XPPQ.ccP
+++ b/gnu/lib/libg++/g++-include/XPPQ.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPPQ.hP b/gnu/lib/libg++/g++-include/XPPQ.hP
index af813a2b90d5..af813a2b90d5 100644
--- a/gnu/lib/libg++/g++-include/gen/XPPQ.hP
+++ b/gnu/lib/libg++/g++-include/XPPQ.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPQueue.ccP b/gnu/lib/libg++/g++-include/XPQueue.ccP
index 77bfd1c7a957..77bfd1c7a957 100644
--- a/gnu/lib/libg++/g++-include/gen/XPQueue.ccP
+++ b/gnu/lib/libg++/g++-include/XPQueue.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPQueue.hP b/gnu/lib/libg++/g++-include/XPQueue.hP
index ebae20f3f616..ebae20f3f616 100644
--- a/gnu/lib/libg++/g++-include/gen/XPQueue.hP
+++ b/gnu/lib/libg++/g++-include/XPQueue.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPSet.ccP b/gnu/lib/libg++/g++-include/XPSet.ccP
index 1102790700b9..1102790700b9 100644
--- a/gnu/lib/libg++/g++-include/gen/XPSet.ccP
+++ b/gnu/lib/libg++/g++-include/XPSet.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPSet.hP b/gnu/lib/libg++/g++-include/XPSet.hP
index 9269ec12c8fe..9269ec12c8fe 100644
--- a/gnu/lib/libg++/g++-include/gen/XPSet.hP
+++ b/gnu/lib/libg++/g++-include/XPSet.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPStack.ccP b/gnu/lib/libg++/g++-include/XPStack.ccP
index fe24f0f044a1..fe24f0f044a1 100644
--- a/gnu/lib/libg++/g++-include/gen/XPStack.ccP
+++ b/gnu/lib/libg++/g++-include/XPStack.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPStack.hP b/gnu/lib/libg++/g++-include/XPStack.hP
index 9d103e530dda..9d103e530dda 100644
--- a/gnu/lib/libg++/g++-include/gen/XPStack.hP
+++ b/gnu/lib/libg++/g++-include/XPStack.hP
diff --git a/gnu/lib/libg++/g++-include/gen/XPlex.ccP b/gnu/lib/libg++/g++-include/XPlex.ccP
index c91e5035a4ff..c91e5035a4ff 100644
--- a/gnu/lib/libg++/g++-include/gen/XPlex.ccP
+++ b/gnu/lib/libg++/g++-include/XPlex.ccP
diff --git a/gnu/lib/libg++/g++-include/gen/XPlex.hP b/gnu/lib/libg++/g++-include/XPlex.hP
index 41f100091bd9..41f100091bd9 100644
--- a/gnu/lib/libg++/g++-include/gen/XPlex.hP
+++ b/gnu/lib/libg++/g++-include/XPlex.hP
diff --git a/gnu/lib/libg++/g++-include/assert.h b/gnu/lib/libg++/g++-include/assert.h
deleted file mode 100644
index 44a65704cfae..000000000000
--- a/gnu/lib/libg++/g++-include/assert.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __libgxx_assert_h
-
-extern "C" {
-#ifdef __assert_h_recursive
-#include_next <assert.h>
-#else
-/* assert.h on some systems needs stdio.h, in violation of ANSI. */
-#include <stdio.h>
-#include_next <assert.h>
-
-#define __libgxx_assert_h 1
-#endif
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/bstring.h b/gnu/lib/libg++/g++-include/bstring.h
deleted file mode 100644
index 3b2f5900276f..000000000000
--- a/gnu/lib/libg++/g++-include/bstring.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <string.h>
diff --git a/gnu/lib/libg++/g++-include/ctype.h b/gnu/lib/libg++/g++-include/ctype.h
deleted file mode 100644
index b573e1995df9..000000000000
--- a/gnu/lib/libg++/g++-include/ctype.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <_G_config.h>
-extern "C" {
-#include_next <ctype.h>
-#ifndef toupper
-extern int toupper _G_ARGS((int));
-#endif
-#ifndef tolower
-extern int tolower _G_ARGS((int));
-#endif
-}
diff --git a/gnu/lib/libg++/g++-include/curses.h b/gnu/lib/libg++/g++-include/curses.h
deleted file mode 100644
index b7b32be78c77..000000000000
--- a/gnu/lib/libg++/g++-include/curses.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef _G_curses_h
-
-#include <_G_config.h>
-
-#if _G_HAVE_CURSES
-
-#ifdef __curses_h_recursive
-#include_next <curses.h>
-#else
-#define __curses_h_recursive
-
-extern "C" {
-#include_next <curses.h>
-
-/* Some systems (SVR4 for example) allow the definition of CHTYPE to set the
- type of some arguments to the curses functions. It can be set to "char"
- to save space, or it can be set to something longer to store both a
- character and some attributes. By default they do not define CHTYPE,
- and when CHTYPE is not defined, the default type is "unsigned long" instead
- of the traditional "char". However, SVR4 <curses.h> does define
- _VR3_COMPAT_CODE, so we can use that to detect when we should use the SVR4
- default if CHTYPE is not defined. For other systems, just default to the
- traditional default "char". */
-
-#ifdef CHTYPE
- typedef CHTYPE _G_chtype; /* Use specified type. */
-#else
-#ifdef _VR3_COMPAT_CODE
- typedef unsigned long _G_chtype; /* SVR4 default is "unsigned long" */
-#elif defined(hpux)
- typedef unsigned int _G_chtype;
-#else
- typedef char _G_chtype; /* Traditional default is "char" */
-#endif
-#endif
-
-/* Some args are conceptually const, but SVR4 (and others?) get it wrong. */
-#define _C_const /* const */
-
-WINDOW * (newwin)(int, int, int, int);
-WINDOW * (subwin)(WINDOW *, int, int, int, int);
-WINDOW * (initscr)();
-int (box) (WINDOW*, _G_chtype, _G_chtype);
-int (delwin)(WINDOW*);
-int (getcurx)(WINDOW*);
-int (getcury)(WINDOW*);
-int (mvcur)(int, int, int, int);
-int (overlay)(WINDOW*, WINDOW*);
-int (overwrite)(WINDOW*, WINDOW*);
-int (scroll)(WINDOW*);
-int (touchwin)(WINDOW*);
-int (waddch)(WINDOW*, _G_chtype);
-int (waddstr) _G_ARGS((WINDOW*, const char*));
-int (wclear)(WINDOW*);
-int (wclrtobot)(WINDOW*);
-int (wclrtoeol)(WINDOW*);
-int (wdelch)(WINDOW*);
-int (wdeleteln)(WINDOW*);
-int (werase)(WINDOW*);
-int (wgetch)(WINDOW*);
-int (wgetstr)(WINDOW*, char*);
-int (winsch)(WINDOW*, _G_chtype);
-int (winsertln)(WINDOW*);
-int (wmove)(WINDOW*, int, int);
-int (wrefresh)(WINDOW*);
-int (wstandend)(WINDOW*);
-int (wstandout)(WINDOW*);
-
-// SVR4 rather inanely bundles the format-string parameter with the '...'.
-// This breaks VMS, and I don't want to penalize VMS for being right for once!
-
-int (wprintw)(WINDOW*, _G_CURSES_FORMAT_ARG ...);
-int (mvwprintw)(WINDOW*, int y, int x, _G_CURSES_FORMAT_ARG ...);
-int (wscanw)(WINDOW*, _G_CURSES_FORMAT_ARG ...);
-int (mvwscanw)(WINDOW*, int, int, _G_CURSES_FORMAT_ARG ...);
-int (endwin)();
-
-}
-#define _G_curses_h
-#endif
-#endif /* _G_HAVE_CURSES */
-#endif /* _G_curses_h */
diff --git a/gnu/lib/libg++/g++-include/gen/defs.hP b/gnu/lib/libg++/g++-include/defs.hP
index 054f6a65c3d8..054f6a65c3d8 100644
--- a/gnu/lib/libg++/g++-include/gen/defs.hP
+++ b/gnu/lib/libg++/g++-include/defs.hP
diff --git a/gnu/lib/libg++/g++-include/dir.h b/gnu/lib/libg++/g++-include/dir.h
deleted file mode 100644
index 78c540242c57..000000000000
--- a/gnu/lib/libg++/g++-include/dir.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <sys/dir.h>
diff --git a/gnu/lib/libg++/g++-include/dirent.h b/gnu/lib/libg++/g++-include/dirent.h
deleted file mode 100644
index 4c06ea837a8f..000000000000
--- a/gnu/lib/libg++/g++-include/dirent.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __libgxx_dirent_h
-
-#include <_G_config.h>
-
-#if !_G_HAVE_DIRENT
-#define __libgxx_dirent_h
-#define direct dirent
-#include <sys/dir.h>
-#else
-
-extern "C" {
-
-#ifdef __dirent_h_recursive
-#include_next <dirent.h>
-#else
-// Note: sys/dir.h checks __dirent_h_recursive
-#define __dirent_h_recursive
-#define opendir __hide_opendir
-#define closedir __hide_closedir
-#define readdir __hide_readdir
-#define telldir __hide_telldir
-#define seekdir __hide_seekdir
-
-#include_next <dirent.h>
-
-#define __libgxx_dirent_h
-#undef opendir
-#undef closedir
-#undef readdir
-#undef telldir
-#undef seekdir
-
-DIR *opendir(const char *);
-int closedir(DIR *);
-struct dirent *readdir(DIR *);
-long telldir(DIR *);
-void seekdir(DIR *, long);
-// We don't bother with rewinddir (many systems define it as a macro).
-// void rewinddir(DIR *);
-#endif
-}
-
-#endif
-#endif
diff --git a/gnu/lib/libg++/g++-include/errno.h b/gnu/lib/libg++/g++-include/errno.h
deleted file mode 100644
index f9f86c85d142..000000000000
--- a/gnu/lib/libg++/g++-include/errno.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef errno_h
-
-extern "C" {
-
-#ifdef __errno_h_recursive
-#include_next <errno.h>
-#else
-#define __errno_h_recursive
-#include_next <errno.h>
-
-#define errno_h 1
-
-extern char* sys_errlist[];
-extern int sys_nerr;
-#ifndef errno
-extern int errno;
-#endif
-void perror(const char*);
-char* strerr(int);
-
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/fcntl.h b/gnu/lib/libg++/g++-include/fcntl.h
deleted file mode 100644
index 48637ef0167f..000000000000
--- a/gnu/lib/libg++/g++-include/fcntl.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef fcntl_h
-
-extern "C" {
-
-#ifdef __fcntl_h_recursive
-#include_next <fcntl.h>
-#else
-#define fcntl __hide_fcntl
-#define open __hide_open
-#define creat __hide_creat
-
-#define __fcntl_h_recursive
-#include <_G_config.h>
-#include_next <fcntl.h>
-
-#undef fcntl
-#undef open
-#undef creat
-
-#define fcntl_h 1
-
-int fcntl(int, int, ...);
-int creat _G_ARGS((const char*, unsigned short int));
-
-int open _G_ARGS((const char*, int, ...));
-
-#endif
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/grp.h b/gnu/lib/libg++/g++-include/grp.h
deleted file mode 100644
index ed937deb7da8..000000000000
--- a/gnu/lib/libg++/g++-include/grp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef grp_h
-
-extern "C" {
-
-#ifdef __grp_h_recursive
-#include_next <grp.h>
-#else
-#define __grp_h_recursive
-
-#include <stdio.h>
-
-#define getgrent c_proto_getgrent
-#define getgrgid c_proto_getgrgid
-#define getgrnam c_proto_getgrnam
-#define setgrent c_proto_setgrent
-#define endgrent c_proto_endgrent
-#define fgetgrent c_proto_fgetgrent
-
-#include_next <grp.h>
-
-#define grp_h 1
-
-#undef getgrent
-#undef getgrgid
-#undef getgrnam
-
-extern struct group* getgrent();
-extern struct group* fgetgrent(FILE*);
-extern struct group* getgrgid(int);
-extern struct group* getgrnam(const char*);
-#if defined(__OSF1__) || defined (__386BSD__)
-extern int setgrent();
-#else
-extern void setgrent();
-#endif
-extern void endgrent();
-
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/gen/intSList.hP b/gnu/lib/libg++/g++-include/intSList.hP
index 24aa3b6a685b..24aa3b6a685b 100644
--- a/gnu/lib/libg++/g++-include/gen/intSList.hP
+++ b/gnu/lib/libg++/g++-include/intSList.hP
diff --git a/gnu/lib/libg++/g++-include/gen/intVec.hP b/gnu/lib/libg++/g++-include/intVec.hP
index e3838700251d..e3838700251d 100644
--- a/gnu/lib/libg++/g++-include/gen/intVec.hP
+++ b/gnu/lib/libg++/g++-include/intVec.hP
diff --git a/gnu/lib/libg++/g++-include/math.h b/gnu/lib/libg++/g++-include/math.h
deleted file mode 100644
index 2bf43305197e..000000000000
--- a/gnu/lib/libg++/g++-include/math.h
+++ /dev/null
@@ -1,221 +0,0 @@
-// This may look like C code, but it is really -*- C++ -*-
-/*
-Copyright (C) 1988 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
-This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-
-#ifndef _math_h
-#ifdef __GNUG__
-#pragma interface
-#endif
-#define _math_h 1
-
-#if defined(hp300) && defined(__HAVE_FPU__)
-#define __HAVE_68881__ 1
-#endif
-
-#if defined(masscomp)
-#define __HAVE_68881__ 1
-#endif
-
-#ifdef __HAVE_68881__ /* MC68881/2 Floating-Point Coprocessor */
-extern "C" { /* fill in what we've left out */
-#include <math-68881.h>
-
-double acosh(double);
-double asinh(double);
-double cbrt(double);
-double copysign(double,double);
-double erf(double);
-double erfc(double);
-double finite(double);
-double gamma(double);
-double hypot(double,double);
-double infnan(int);
-int isinf(double);
-int isnan(double);
-double j0(double);
-double j1(double);
-double jn(int, double);
-double lgamma(double);
-double y0(double);
-double y1(double);
-double yn(int, double);
-
-double aint(double);
-double anint(double);
-int irint(double);
-int nint(double);
-}
-/* Please add inline asm code for other machines here! */
-#else
-extern "C" {
-
-#include <_G_config.h>
-
-double acos(double);
-double acosh(double);
-double asin(double);
-double asinh(double);
-double atan(double);
-double atan2(double, double);
-double atanh(double);
-double cbrt(double);
-double ceil(double);
-double copysign(double,double);
-double cos(double);
-double cosh(double);
-double drem(double,double);
-double erf(double);
-double erfc(double);
-double exp(double);
-double expm1(double);
-double fabs(double);
-int finite(double);
-double floor(double);
-double fmod(double, double);
-double frexp(double, int*);
-double gamma(double);
-double hypot(double,double);
-double infnan(int);
-#if !defined(sequent) && !defined(DGUX) &&!defined(sony) && !defined(masscomp) && !defined(hpux)
-/* see below */
-int isinf(double);
-int isnan(double);
-#endif
-double j0(double);
-double j1(double);
-double jn(int, double);
-double ldexp(double, int);
-double lgamma(double);
-double log(double);
-double log10(double);
-double log1p(double);
-double logb(double);
-double modf(double, double*);
-double pow(double, double);
-double rint(double);
-double scalb _G_ARGS((double, int));
-double sin(double);
-double sinh(double);
-double sqrt(double);
-double tan(double);
-double tanh(double);
-double y0(double);
-double y1(double);
-double yn(int, double);
-
-double aint(double);
-double anint(double);
-int irint(double);
-int nint(double);
-}
-
-#endif
-
-/* libg++ doesn't use this since it is not available on some systems */
-
-/* the following ifdef is just for compiling OOPS */
-
-#ifndef DONT_DECLARE_EXCEPTION
-struct libm_exception
-{
- int type;
- char* name;
- double arg1, arg2, retval;
-};
-
-#define DOMAIN 1
-#define SING 2
-#define OVERFLOW 3
-#define UNDERFLOW 4
-#define TLOSS 5
-#define PLOSS 6
-
-extern "C" int matherr(libm_exception*);
-
-#endif
-
-#include <float.h>
-
-/* On some systems, HUGE ought to be MAXFLOAT or IEEE infinity */
-
-#ifndef HUGE
-#define HUGE DBL_MAX
-#endif
-#ifndef HUGE_VAL
-#define HUGE_VAL DBL_MAX
-#endif
-
-
-/* sequents don't supply these. The following should suffice */
-#if defined(sequent) || defined(DGUX) || defined(sony) || defined(masscomp) \
-|| defined(hpux)
-#include <float.h>
-static inline int isnan(double x) { return x != x; }
-static inline int isinf(double x) { return x > DBL_MAX || x < -DBL_MAX; }
-#endif
-
-/* These seem to be sun & sysV names of these constants */
-
-#ifndef M_E
-#define M_E 2.7182818284590452354
-#endif
-#ifndef M_LOG2E
-#define M_LOG2E 1.4426950408889634074
-#endif
-#ifndef M_LOG10E
-#define M_LOG10E 0.43429448190325182765
-#endif
-#ifndef M_LN2
-#define M_LN2 0.69314718055994530942
-#endif
-#ifndef M_LN10
-#define M_LN10 2.30258509299404568402
-#endif
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-#ifndef M_PI_2
-#define M_PI_2 1.57079632679489661923
-#endif
-#ifndef M_1_PI
-#define M_1_PI 0.31830988618379067154
-#endif
-#ifndef M_PI_4
-#define M_PI_4 0.78539816339744830962
-#endif
-#ifndef M_2_PI
-#define M_2_PI 0.63661977236758134308
-#endif
-#ifndef M_2_SQRTPI
-#define M_2_SQRTPI 1.12837916709551257390
-#endif
-#ifndef M_SQRT2
-#define M_SQRT2 1.41421356237309504880
-#endif
-#ifndef M_SQRT1_2
-#define M_SQRT1_2 0.70710678118654752440
-#endif
-
-#ifndef PI // as in stroustrup
-#define PI M_PI
-#endif
-#ifndef PI2
-#define PI2 M_PI_2
-#endif
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/memory.h b/gnu/lib/libg++/g++-include/memory.h
deleted file mode 100644
index dc3b3d52824d..000000000000
--- a/gnu/lib/libg++/g++-include/memory.h
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#ifndef _memory_h
-#define _memory_h 1
-
-#include "_G_config.h"
-#include <stddef.h>
-
-extern "C" {
-
-void* memalign _G_ARGS((_G_size_t, _G_size_t));
-void* memccpy _G_ARGS((void*, const void*, int, _G_size_t));
-void* memchr _G_ARGS((const void*, int, _G_size_t));
-int memcmp _G_ARGS((const void*, const void*, _G_size_t));
-void* memcpy _G_ARGS((void*, const void*, _G_size_t));
-void* memmove _G_ARGS((void*, const void*, _G_size_t));
-void* memset _G_ARGS((void*, int, _G_size_t));
-int ffs _G_ARGS((int));
-#if defined(__OSF1__) || defined(__386BSD__)
-int getpagesize _G_ARGS((void));
-#else
-_G_size_t getpagesize _G_ARGS((void));
-#endif
-void* valloc _G_ARGS((_G_size_t));
-
-void bcopy _G_ARGS((const void*, void*, _G_size_t));
-int bcmp _G_ARGS((const void*, const void*, int));
-void bzero _G_ARGS((void*, int));
-}
-
-#ifdef __GNUG__
-#ifndef alloca
-#define alloca(x) __builtin_alloca(x)
-#endif
-#else
-#ifndef IV
-extern "C" void* alloca(_G_size_t);
-#else
-extern "C" void* alloca(unsigned long);
-#endif /* IV */
-#endif
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/netdb.h b/gnu/lib/libg++/g++-include/netdb.h
deleted file mode 100644
index c718a8e5b718..000000000000
--- a/gnu/lib/libg++/g++-include/netdb.h
+++ /dev/null
@@ -1,4 +0,0 @@
-extern "C"
-{
-#include_next <netdb.h>
-}
diff --git a/gnu/lib/libg++/g++-include/pwd.h b/gnu/lib/libg++/g++-include/pwd.h
deleted file mode 100644
index f33d7ee4141e..000000000000
--- a/gnu/lib/libg++/g++-include/pwd.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _pwd_h
-
-// the Interviews-based standard kludge again
-
-extern "C" {
-
-#ifdef __pwd_h_recursive
-#include_next <pwd.h>
-#else
-#define getpwent c_proto_getpwent
-#define getpwuid c_proto_getpwuid
-#define getpwnam c_proto_getpwnam
-#define setpwent c_proto_setpwent
-#define endpwent c_proto_endpwent
-
-#define __pwd_h_recursive
-#include_next <pwd.h>
-
-#define _pwd_h 1
-
-#undef getpwent
-#undef getpwuid
-#undef getpwnam
-#undef setpwent
-#undef endpwent
-
-extern struct passwd* getpwent();
-extern struct passwd* getpwuid(int);
-extern struct passwd* getpwnam(const char*);
-extern int setpwent();
-extern int endpwent();
-
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/setjmp.h b/gnu/lib/libg++/g++-include/setjmp.h
deleted file mode 100644
index dc35dea4e728..000000000000
--- a/gnu/lib/libg++/g++-include/setjmp.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _setjmp_h
-
-extern "C" {
-
-#ifdef __setjmp_h_recursive
-#include_next <setjmp.h>
-#else
-#define __setjmp_h_recursive
-#define setjmp C_header_setjmp
-#define longjmp C_header_longjmp
-
-#ifdef VMS
-#include "gnu_cc_include:[000000]setjmp.h"
-#else
-#include_next <setjmp.h>
-#endif
-
-#undef setjmp
-#undef longjmp
-
-#define _setjmp_h 1
-
-extern int setjmp(jmp_buf);
-extern void longjmp(jmp_buf, int);
-
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/signal.h b/gnu/lib/libg++/g++-include/signal.h
deleted file mode 100644
index 1fe0f1611e3a..000000000000
--- a/gnu/lib/libg++/g++-include/signal.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// This may look like C code, but it is really -*- C++ -*-
-/*
-Copyright (C) 1989 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
-This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _signal_h
-
-#include <_G_config.h>
-
-extern "C" {
-
-#ifdef __signal_h_recursive
-#include_next <signal.h>
-#else
-
-#define __signal_h_recursive
-
-#define signal __hide_signal
-#define psignal __hide_psignal
-#include_next <signal.h>
-#undef signal
-#undef psignal
-
-#define _signal_h 1
-
-// The Interviews folks call this SignalHandler. Might as well conform.
-typedef _G_signal_return_type (*SignalHandler) (...);
-typedef int (*SSignalHandler) (...);
-
-extern SignalHandler signal _G_ARGS((int sig, SignalHandler action));
-//extern SignalHandler sigset _G_ARGS((int sig, SignalHandler action));
-extern SSignalHandler ssignal _G_ARGS((int sig, SSignalHandler action));
-extern int gsignal _G_ARGS((int sig));
-extern int kill _G_ARGS((_G_pid_t pid, int sig));
-#ifndef __386BSD__
-extern int killpg _G_ARGS((short int, int));
-#else
-extern int killpg _G_ARGS((_G_pid_t, int));
-#endif
-extern int siginterrupt _G_ARGS((int, int));
-extern void psignal _G_ARGS((unsigned, const char*));
-
-#ifndef hpux // Interviews folks claim that hpux doesn't like these
-extern int sigsetmask _G_ARGS((int mask));
-extern int sigblock _G_ARGS((int mask));
-extern int sigpause _G_ARGS((int mask));
-extern int sigvec _G_ARGS((int, struct sigvec*, struct sigvec*));
-#endif
-
-// The Interviews version also has these ...
-
-#define SignalBad ((SignalHandler)-1)
-#define SignalDefault ((SignalHandler)0)
-#define SignalIgnore ((SignalHandler)1)
-
-#undef BADSIG
-#undef SIG_DFL
-#undef SIG_IGN
-#define BAD_SIG SignalBad
-#define SIG_DFL SignalDefault
-#define SIG_IGN SignalIgnore
-
-#endif
-}
-
-#endif
-
diff --git a/gnu/lib/libg++/g++-include/stdarg.h b/gnu/lib/libg++/g++-include/stdarg.h
deleted file mode 100644
index 67dc22e1ab93..000000000000
--- a/gnu/lib/libg++/g++-include/stdarg.h
+++ /dev/null
@@ -1,3 +0,0 @@
-extern "C" {
-#include_next <stdarg.h>
-}
diff --git a/gnu/lib/libg++/g++-include/stddef.h b/gnu/lib/libg++/g++-include/stddef.h
deleted file mode 100644
index 66e78bab2036..000000000000
--- a/gnu/lib/libg++/g++-include/stddef.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __libgxx_stddef_h
-
-extern "C" {
-#ifdef __stddef_h_recursive
-#include_next <stddef.h>
-#else
-#include_next <stddef.h>
-
-#define __libgxx_stddef_h 1
-#endif
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/stdio.h b/gnu/lib/libg++/g++-include/stdio.h
deleted file mode 100644
index 7ee1cf2ffa2b..000000000000
--- a/gnu/lib/libg++/g++-include/stdio.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// This may look like C code, but it is really -*- C++ -*-
-/*
-Copyright (C) 1988 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
-This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _stdio_h
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-#ifdef __stdio_h_recursive
-#include_next <stdio.h>
-#else
-#define __stdio_h_recursive
-
-// Note: The #define _stdio_h is at the end of this file,
-// in case #include_next <stdio.h> finds an installed version of this
-// same file -- we want it to continue until it finds the C version.
-
-#include <_G_config.h>
-
-extern "C" {
-
-#undef NULL
-
-#define fdopen __hide_fdopen
-#define fopen __hide_fopen
-#define fprintf __hide_fprintf
-#define fputs __hide_fputs
-#define fread __hide_fread
-#define freopen __hide_freopen
-#define fscanf __hide_fscanf
-#define ftell __hide_ftell
-#define fwrite __hide_fwrite
-#define new __hide_new /* In case 'new' is used as a parameter name. */
-#define perror __hide_perror
-#define popen __hide_popen
-#define printf __hide_printf
-#define puts __hide_puts
-#define putw __hide_putw
-#define rewind __hide_rewind
-#define tempnam __hide_tempnam
-#define scanf __hide_scanf
-#define setbuf __hide_setbuf
-#define setbuffer __hide_setbuffer
-#define setlinebuf __hide_setlinebuf
-#define setvbuf __hide_setvbuf
-#define sprintf __hide_sprintf
-#define sscanf __hide_sscanf
-#define tempnam __hide_tempnam
-#define vfprintf __hide_vfprintf
-#define vprintf __hide_vprintf
-#define vsprintf __hide_vsprintf
-#define _flsbuf __hide__flsbuf
-
-#include_next <stdio.h>
-
-#undef fdopen
-#undef fopen
-#undef fprintf
-#undef fputs
-#undef fread
-#undef freopen
-#undef fscanf
-#undef ftell
-#undef fwrite
-#undef new
-#undef perror
-#undef popen
-#undef printf
-#undef puts
-#undef putw
-/* SCO defines remove to call unlink; that's very dangerous for us. */
-#undef remove
-#undef rewind
-#undef tempnam
-#undef scanf
-#undef setbuf
-#undef setbuffer
-#undef setlinebuf
-#undef setvbuf
-#undef sprintf
-#undef sscanf
-#undef tempnam
-#undef vprintf
-#undef vfprintf
-#undef vsprintf
-#undef _flsbuf
-
-#ifndef NULL
-#define NULL _G_NULL
-#endif
-
-#ifndef size_t
-#define size_t _G_size_t
-#endif
-}
-
-extern "C" {
-
-int fclose(FILE*);
-FILE* fdopen(int, const char*);
-int fflush(FILE*);
-int fgetc(FILE*);
-#ifndef __386BSD__
-char* fgets _G_ARGS((char*, int, FILE *));
-#else
-char* fgets _G_ARGS((char*, _G_size_t, FILE *));
-#endif
-FILE* fopen(const char*, const char*);
-int fprintf(FILE*, const char* ...);
-int fputc(int, FILE*);
-int fputs(const char*, FILE*);
-size_t fread(void*, size_t, size_t, FILE*);
-#ifdef VMS
-FILE* freopen(const char*, const char*, FILE* ...);
-#else
-FILE* freopen(const char*, const char*, FILE*);
-#endif
-int fscanf(FILE*, const char* ...);
-int fseek(FILE*, long, int);
-long ftell(FILE *);
-size_t fwrite(const void*, size_t, size_t, FILE*);
-char* gets(char*);
-int getw(FILE*);
-int pclose(FILE*);
-void perror(const char*);
-FILE* popen(const char*, const char*);
-int printf(const char* ...);
-int puts(const char*);
-int putw(int, FILE*);
-int rewind(FILE*);
-int scanf(const char* ...);
-void setbuf(FILE*, char*);
-void setbuffer(FILE*, char*, int);
-int setlinebuf(FILE*);
-int setvbuf(FILE*, char*, int, size_t);
-int sscanf(char*, const char* ...);
-FILE* tmpfile();
-int ungetc(int, FILE*);
-int vfprintf _G_ARGS((FILE*, const char*, _G_va_list));
-int vprintf _G_ARGS((const char*, _G_va_list));
-_G_sprintf_return_type sprintf _G_ARGS((char*, const char* ...));
-_G_sprintf_return_type vsprintf _G_ARGS((char*, const char*, _G_va_list));
-
-extern int _filbuf _G_ARGS((FILE*));
-extern int _flsbuf _G_ARGS((unsigned, FILE*));
-
-}
-
-#ifndef L_ctermid
-#define L_ctermid 9
-#endif
-#ifndef L_cuserid
-#define L_cuserid 9
-#endif
-#ifndef P_tmpdir
-#define P_tmpdir "/tmp/"
-#endif
-#ifndef L_tmpnam
-#define L_tmpnam (sizeof(P_tmpdir) + 15)
-#endif
-
-#define _stdio_h 1
-
-#endif
-#endif // _stdio_h
diff --git a/gnu/lib/libg++/g++-include/stdlib.h b/gnu/lib/libg++/g++-include/stdlib.h
deleted file mode 100644
index b0682435da73..000000000000
--- a/gnu/lib/libg++/g++-include/stdlib.h
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-#ifndef _stdlib_h
-#define _stdlib_h 1
-
-#include <_G_config.h>
-#include <stddef.h>
-
-extern "C" {
-
-int abs(int);
-
-#ifdef __GNUG__
-void volatile abort(void);
-#else
-void abort(void);
-#endif
-
-double atof(const char*);
-int atoi(const char*);
-long atol(const char*);
-
-int atexit(auto void (*p) (void));
-void* bsearch (const void *, const void *, size_t,
- size_t, auto int (*ptf)(const void*, const void*));
-void* calloc(size_t, size_t);
-void cfree(void*);
-
-#ifdef __GNUG__
-void volatile exit(int);
-#else
-void exit(int);
-#endif
-
-char* fcvt(double, int, int*, int*);
-void free(void*);
-char* getenv(const char*);
-int getopt _G_ARGS((int, char * const *, const char*));
-int getpw(int, char*);
-char* gcvt(double, int, char*);
-char* ecvt(double, int, int*, int*);
-extern char** environ;
-
-long labs(long);
-void* malloc(size_t);
-size_t malloc_usable_size(void*);
-int putenv(const char*);
-extern char* optarg;
-extern int opterr;
-extern int optind;
-void qsort(void*, size_t, size_t, auto int (*ptf)(void*,void*));
-int rand(void);
-void* realloc(void*, size_t);
-int setkey(const char*);
-int srand(unsigned int);
-double strtod(const char*, char**);
-long strtol(const char*, char**, int);
-unsigned long strtoul(const char*, char **, int);
-int system(const char*);
-
-long random(void);
-void srandom(int);
-char* setstate(char*);
-char* initstate(unsigned, char*, int);
-
-double drand48(void);
-void lcong48(short*);
-long jrand48(short*);
-long lrand48(void);
-long mrand48(void);
-long nrand48(short*);
-short* seed48(short*);
-void srand48(long);
-
-char* ctermid(char*);
-char* cuserid(char*);
-char* tempnam(const char*, const char*);
-char* tmpnam(char*);
-
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/string.h b/gnu/lib/libg++/g++-include/string.h
deleted file mode 100644
index b11ca0acfffc..000000000000
--- a/gnu/lib/libg++/g++-include/string.h
+++ /dev/null
@@ -1,45 +0,0 @@
-
-#ifndef _string_h
-#define _string_h 1
-
-#include <_G_config.h>
-
-#ifndef size_t
-#define size_t _G_size_t
-#endif
-
-#ifndef NULL
-#define NULL _G_NULL
-#endif
-
-extern "C" {
-
-char* strcat(char*, const char*);
-char* strchr(const char*, int);
-int strcmp(const char*, const char*);
-int strcoll(const char*, const char*);
-char* strcpy(char*, const char*);
-size_t strcspn(const char*, const char*);
-char* strdup(const char*);
-// NOTE: If you get a error message from g++ that this declaration
-// conflicts with a <built-in> declaration of strlen(), that usually
-// indicates that __SIZE_TYPE__ is incorrectly defined by gcc.
-// Fix or add SIZE_TYPE in the appropriate file in gcc/config/*.h.
-size_t strlen(const char*);
-char* strncat(char*, const char*, size_t);
-int strncmp(const char*, const char*, size_t);
-char* strncpy(char*, const char*, size_t);
-char* strpbrk(const char*, const char*);
-char* strrchr(const char*, int);
-size_t strspn(const char*, const char*);
-char* strstr(const char*, const char *);
-char* strtok(char*, const char*);
-size_t strxfrm(char*, const char*, size_t);
-
-char* index(const char*, int);
-char* rindex(const char*, int);
-}
-
-#include <memory.h>
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/strings.h b/gnu/lib/libg++/g++-include/strings.h
deleted file mode 100644
index 3b2f5900276f..000000000000
--- a/gnu/lib/libg++/g++-include/strings.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <string.h>
diff --git a/gnu/lib/libg++/g++-include/sys/dir.h b/gnu/lib/libg++/g++-include/sys/dir.h
deleted file mode 100644
index 586867252a6c..000000000000
--- a/gnu/lib/libg++/g++-include/sys/dir.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __libgxx_sys_dir_h
-
-extern "C" {
-
-#ifdef __sys_dir_h_recursive
-#include_next <sys/dir.h>
-#else
-#define __sys_dir_h_recursive
-#define opendir __hide_opendir
-#define closedir __hide_closedir
-#define readdir __hide_readdir
-#define telldir __hide_telldir
-#define seekdir __hide_seekdir
-
-#include_next <sys/dir.h>
-
-#define __libgxx_sys_dir_h
-#undef opendir
-#undef closedir
-#undef readdir
-#undef telldir
-#undef seekdir
-
-DIR *opendir(const char *);
-int closedir(DIR *);
-#ifdef __dirent_h_recursive
-// Some operating systems we won't mention (such as the imitation
-// of Unix marketed by IBM) implement dirent.h by including sys/dir.h,
-// in which case sys/dir.h defines struct dirent, rather than
-// the struct direct originally used by BSD.
-struct dirent *readdir(DIR *);
-#else
-struct direct *readdir(DIR *);
-#endif
-long telldir(DIR *);
-void seekdir(DIR *, long);
-// We don't bother with rewinddir (many systems define it as a macro).
-// void rewinddir(DIR *);
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/fcntl.h b/gnu/lib/libg++/g++-include/sys/fcntl.h
deleted file mode 100644
index d4fdcfeddaaa..000000000000
--- a/gnu/lib/libg++/g++-include/sys/fcntl.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __libgxx_sys_fcntl_h
-
-extern "C"
-{
-#ifdef __sys_fcntl_h_recursive
-#include_next <sys/fcntl.h>
-#else
-#define __sys_fcntl_h_recursive
-#include_next <sys/fcntl.h>
-#define __libgxx_sys_fcntl_h 1
-#endif
-}
-
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/file.h b/gnu/lib/libg++/g++-include/sys/file.h
deleted file mode 100644
index 70b49c244a80..000000000000
--- a/gnu/lib/libg++/g++-include/sys/file.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __libgxx_sys_file_h
-
-extern "C"
-{
-#ifdef __sys_file_h_recursive
-#include_next <sys/file.h>
-#else
-#define fcntl __hide_fcntl
-#define open __hide_open
-#define creat __hide_creat
-
-#define __sys_file_h_recursive
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]file.h"
-#else
-#include_next <sys/file.h>
-#endif
-
-#undef fcntl
-#undef open
-#undef creat
-
-#define __libgxx_sys_file_h 1
-
-#endif
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/mman.h b/gnu/lib/libg++/g++-include/sys/mman.h
deleted file mode 100644
index c4b2e15793dc..000000000000
--- a/gnu/lib/libg++/g++-include/sys/mman.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __libgxx_sys_mman_h
-
-extern "C" {
-#ifdef __sys_mman_h_recursive
-#include_next <sys/mman.h>
-#else
-#define __sys_mman_h_recursive
-#include_next <sys/mman.h>
-
-#define __libgxx_sys_mman_h 1
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/param.h b/gnu/lib/libg++/g++-include/sys/param.h
deleted file mode 100644
index 610a19b8f424..000000000000
--- a/gnu/lib/libg++/g++-include/sys/param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __libgxx_sys_param_h
-
-extern "C"
-{
-#ifdef __sys_param_h_recursive
-#include_next <sys/param.h>
-#else
-#define __sys_param_h_recursive
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]param.h"
-#else
-#include_next <sys/param.h>
-#endif
-
-#undef setbit /* Conflicts with Integer::setbit(). */
-
-#define __libgxx_sys_param_h 1
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/resource.h b/gnu/lib/libg++/g++-include/sys/resource.h
deleted file mode 100644
index 3596c1b3145c..000000000000
--- a/gnu/lib/libg++/g++-include/sys/resource.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __libgxx_sys_resource_h
-
-extern "C"
-{
-#ifdef __sys_resource_h_recursive
-#include_next <sys/resource.h>
-#else
-#include <_G_config.h>
-#define __sys_resource_h_recursive
-#include <sys/time.h>
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]resource.h"
-#else
-#include_next <sys/resource.h>
-#endif
-
-#define __libgxx_sys_resource_h 1
-
-int getrusage(int, struct rusage*);
-int getrlimit (int resource, struct rlimit *rlp);
-int setrlimit _G_ARGS((int resource, const struct rlimit *rlp));
-long ulimit(int, long);
-int getpriority(int, int);
-int setpriority(int, int, int);
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/select.h b/gnu/lib/libg++/g++-include/sys/select.h
deleted file mode 100644
index 1c80ffef05e3..000000000000
--- a/gnu/lib/libg++/g++-include/sys/select.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Needed by Interviews for AIX. */
-#ifndef __libgxx_sys_select_h
-extern "C"
-{
-#include_next <sys/select.h>
-#define __libgxx_sys_select_h 1
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/signal.h b/gnu/lib/libg++/g++-include/sys/signal.h
deleted file mode 100644
index 68212052ceac..000000000000
--- a/gnu/lib/libg++/g++-include/sys/signal.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// This may look like C code, but it is really -*- C++ -*-
-/*
-Copyright (C) 1989 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
-This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Partly for systems that think signal.h is is sys/ */
-/* But note that some systems that use sys/signal.h to define signal.h. */
-
-#ifndef __libgxx_sys_signal_h
-#if defined(__sys_signal_h_recursive) || defined(__signal_h_recursive)
-#include_next <sys/signal.h>
-#else
-#define __sys_signal_h_recursive
-
-extern "C" {
-#define signal __hide_signal
-#include_next <sys/signal.h>
-#undef signal
-}
-
-#define __libgxx_sys_signal_h 1
-#endif
-#endif
-
diff --git a/gnu/lib/libg++/g++-include/sys/socket.h b/gnu/lib/libg++/g++-include/sys/socket.h
deleted file mode 100644
index 5ff6018ccbf4..000000000000
--- a/gnu/lib/libg++/g++-include/sys/socket.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef __libgxx_sys_socket_h
-
-#include <_G_config.h>
-
-extern "C"
-{
-#ifdef __sys_socket_h_recursive
-#include_next <sys/socket.h>
-#else
-#define __sys_socket_h_recursive
-#include <time.h>
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]socket.h"
-#else
-#include_next <sys/socket.h>
-#endif
-
-#define __libgxx_sys_socket_h 1
-
-// void* in select, since different systems use int* or fd_set*
-int accept _G_ARGS((int, struct sockaddr*, int*));
-#ifndef __386BSD__
-int select _G_ARGS((int, void*, void*, void*, struct timeval*));
-
-int bind _G_ARGS((int, const void*, int));
-int connect _G_ARGS((int, struct sockaddr*, int));
-#else
-int select _G_ARGS((int, struct fd_set*, struct fd_set*, struct fd_set*, struct timeval*));
-
-int bind _G_ARGS((int, const struct sockaddr *, int));
-int connect _G_ARGS((int, const struct sockaddr*, int));
-#endif
-int getsockname _G_ARGS((int, struct sockaddr*, int*));
-int getpeername _G_ARGS((int, struct sockaddr*, int*));
-int getsockopt(int, int, int, void*, int*);
-int listen(int, int);
-#ifndef hpux
-int rcmd _G_ARGS((char**, int, const char*, const char*, const char*, int*));
-#endif
-int recv(int, void*, int, int);
-int recvmsg(int, struct msghdr*, int);
-int rexec(char**, int, const char*, const char*, const char*, int*);
-int rresvport(int*);
-int send _G_ARGS((int, const void*, int, int));
-int sendmsg _G_ARGS((int, const struct msghdr*, int));
-int shutdown(int, int);
-int socket(int, int, int);
-int socketpair(int, int, int, int sv[2]);
-
-#ifndef __386BSD__
-int recvfrom _G_ARGS((int, void*, int, int, void*, int *));
-int sendto _G_ARGS((int, const void*, int, int, void*, int));
-int setsockopt _G_ARGS((int, int, int, const char*, int));
-#else
-int recvfrom _G_ARGS((int, void*, int, int, struct sockaddr*, int *));
-int sendto _G_ARGS((int, const void*, int, int, const struct sockaddr*, int));
-int setsockopt _G_ARGS((int, int, int, const void*, int));
-#endif
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/stat.h b/gnu/lib/libg++/g++-include/sys/stat.h
deleted file mode 100644
index cffe2a5e1d31..000000000000
--- a/gnu/lib/libg++/g++-include/sys/stat.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __libgxx_sys_stat_h
-
-extern "C"
-{
-#ifdef __sys_stat_h_recursive
-#include_next <sys/stat.h>
-#else
-#define __sys_stat_h_recursive
-#include <_G_config.h>
-#define chmod __hide_chmod
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]stat.h"
-#else
-#include_next <sys/stat.h>
-#endif
-#undef chmod
-
-#define __libgxx_sys_stat_h 1
-
-extern int chmod _G_ARGS((const char*, _G_mode_t));
-extern int stat _G_ARGS((const char *path, struct stat *buf));
-extern int lstat _G_ARGS((const char *path, struct stat *buf));
-extern int fstat _G_ARGS((int fd, struct stat *buf));
-
-#ifndef S_ISDIR
-#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
-#endif
-#ifndef S_ISBLK
-#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
-#endif
-#ifndef S_ISCHR
-#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
-#endif
-#ifndef S_ISFIFO
-#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
-#endif
-#ifndef S_ISREG
-#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
-#endif
-
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/time.h b/gnu/lib/libg++/g++-include/sys/time.h
deleted file mode 100644
index 81419b8c4814..000000000000
--- a/gnu/lib/libg++/g++-include/sys/time.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __libgxx_sys_time_h
-
-extern "C"
-{
-#ifdef __sys_time_h_recursive
-#include_next <sys/time.h>
-#else
-#define __sys_time_h_recursive
-
-// Some system (e.g Ultrix) define these in sys/time.h.
-
-#ifndef __time_h_recursive
-#define time __hide_time
-#define clock __hide_clock
-#define gmtime __hide_gmtime
-#define localtime __hide_localtime
-#define ctime __hide_ctime
-#define asctime __hide_asctime
-#define strftime __hide_strftime
-#endif
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]resourcetime.h"
-#else
-#include_next <sys/time.h>
-#endif
-#undef __sys_time_h_recursive
-
-#define __libgxx_sys_time_h 1
-
-#undef clock
-#undef ctime
-#undef gmtime
-#undef localtime
-#undef time
-#undef asctime
-#undef strftime
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/times.h b/gnu/lib/libg++/g++-include/sys/times.h
deleted file mode 100644
index d026ca5258f0..000000000000
--- a/gnu/lib/libg++/g++-include/sys/times.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __libgxx_sys_times_h
-
-extern "C"
-{
-#ifdef __sys_times_h_recursive
-#include_next <sys/times.h>
-#else
-#define __sys_times_h_recursive
-#include_next <sys/times.h>
-#define __libgxx_sys_times_h 1
-
-#include <_G_config.h>
-
-extern _G_clock_t times _G_ARGS((struct tms*));
-
-#endif
-}
-
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/sys/types.h b/gnu/lib/libg++/g++-include/sys/types.h
deleted file mode 100644
index 67f4d316b5ea..000000000000
--- a/gnu/lib/libg++/g++-include/sys/types.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __libgxx_sys_types_h
-
-extern "C"
-{
-#ifdef __sys_types_h_recursive
-#include_next <sys/types.h>
-#else
-
-#define __sys_types_h_recursive
-#include <stddef.h>
-
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]types.h"
-#else
-#include_next <sys/types.h>
-#endif
-
-#define __libgxx_sys_types_h 1
-
-#endif
-}
-
-
-#endif
-
diff --git a/gnu/lib/libg++/g++-include/sys/wait.h b/gnu/lib/libg++/g++-include/sys/wait.h
deleted file mode 100644
index e6e4e31924e9..000000000000
--- a/gnu/lib/libg++/g++-include/sys/wait.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __libgxx_sys_wait_h
-
-#include <_G_config.h>
-
-extern "C" {
-#ifdef __sys_wait_h_recursive
-#include_next <sys/wait.h>
-#else
-#define __sys_wait_h_recursive
-
-
-#if _G_HAVE_SYS_WAIT
-#ifdef VMS
-#include "GNU_CC_INCLUDE:[sys]wait.h"
-#else
-#include_next <sys/wait.h>
-#endif
-#else /* !_G_HAVE_SYS_WAIT */
-/* Traditional definitions. */
-#define WEXITSTATUS(status) (((x) >> 8) & 0xFF)
-#define WIFSTOPPED(x) (((x) & 0xFF) == 0177)
-#define WIFEXITED(x) (! WIFSTOPPED(x) && WTERMSIG(x) == 0)
-#define WIFSIGNALED(x) (! WIFSTOPPED(x) && WTERMSIG(x) != 0)
-#define WTERMSIG(status) ((x) & 0x7F)
-#define WSTOPSIG(status) (((x) >> 8) & 0xFF)
-#endif /* !_G_HAVE_SYS_WAIT */
-
-#define __libgxx_sys_wait_h 1
-
-struct rusage;
-extern _G_pid_t wait _G_ARGS((int*));
-extern _G_pid_t waitpid _G_ARGS((_G_pid_t, int*, int));
-extern _G_pid_t wait3 _G_ARGS((int*, int options, struct rusage*));
-#ifndef __386BSD__
-extern _G_pid_t wait4 _G_ARGS((int, int*, int, struct rusage*));
-#else
-extern _G_pid_t wait4 _G_ARGS((_G_pid_t, int*, int, struct rusage*));
-#endif
-#endif
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/time.h b/gnu/lib/libg++/g++-include/time.h
deleted file mode 100644
index ea9c00f4a45c..000000000000
--- a/gnu/lib/libg++/g++-include/time.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef _G_time_h
-#define _G_time_h
-
-extern "C" {
-
-#ifdef __time_h_recursive
-#include_next <time.h>
-#else
-#define __time_h_recursive
-
-#include <_G_config.h>
-
-// A clean way to use and/or define time_t might allow removal of this crud.
-#ifndef __sys_time_h_recursive
-#define time __hide_time
-#define clock __hide_clock
-#define difftime __hide_difftime
-#define gmtime __hide_gmtime
-#define localtime __hide_localtime
-#define ctime __hide_ctime
-#define asctime __hide_asctime
-#define strftime __hide_strftime
-#endif
-#define mktime __hide_mktime
-#define tzset __hide_tzset
-#define tzsetwall __hide_tzsetwall
-#define getitimer __hide_getitimer
-#define setitimer __hide_setitimer
-#define gettimeofday __hide_gettimeofday
-#define settimeofday __hide_settimeofday
-
-#ifdef VMS
- struct unix_time
- {
- long int tv_sec;
- long int tv_usec;
- };
-
- struct rusage
- {
- struct unix_time ru_utime;
- };
-
-#define RUSAGE_SELF 0 //define it, it will be unused
-#else
-#ifdef hpux
-#define _INCLUDE_POSIX_SOURCE
-#endif
-
-#include_next <time.h>
-#endif
-#undef __time_h_recursive
-
-#define time_h 1
-
-#undef time
-#undef clock
-#undef difftime
-#undef gmtime
-#undef localtime
-#undef asctime
-#undef ctime
-#undef mktime
-#undef strftime
-#undef tzset
-#undef tzsetwall
-#undef getitimer
-#undef setitimer
-#undef gettimeofday
-#undef settimeofday
-
-extern char* asctime _G_ARGS((const struct tm*));
-extern char* ctime _G_ARGS((const _G_time_t*));
-double difftime _G_ARGS((_G_time_t, _G_time_t));
-extern struct tm* gmtime _G_ARGS((const _G_time_t*));
-extern struct tm* localtime _G_ARGS((const _G_time_t*));
-extern _G_time_t mktime(struct tm*);
-extern _G_size_t strftime _G_ARGS((char*,_G_size_t,const char*,const struct tm*));
-extern void tzset();
-extern void tzsetwall();
-
-extern int getitimer(int, struct itimerval*);
-extern int setitimer _G_ARGS((int, const struct itimerval*,struct itimerval*));
-extern int gettimeofday(struct timeval*, struct timezone*);
-extern int settimeofday _G_ARGS((const struct timeval*,const struct timezone*));
-extern int stime _G_ARGS((const _G_time_t*));
-extern int dysize(int);
-
-#if defined(___AIX__)
-int clock (void);
-#elif defined(hpux)
-unsigned long clock(void);
-#else
-long clock(void);
-#endif
-_G_time_t time(_G_time_t*);
-unsigned ualarm(unsigned, unsigned);
-#ifndef __386BSD__
-unsigned usleep(unsigned);
-void profil _G_ARGS((unsigned short*, _G_size_t, unsigned int, unsigned));
-#else
-void usleep(unsigned);
-int profil _G_ARGS((char*, int, int, int));
-#endif
-
-#endif
-}
-#endif
diff --git a/gnu/lib/libg++/g++-include/unistd.h b/gnu/lib/libg++/g++-include/unistd.h
deleted file mode 100644
index bd7a93529aed..000000000000
--- a/gnu/lib/libg++/g++-include/unistd.h
+++ /dev/null
@@ -1,187 +0,0 @@
-#ifndef _G_unistd_h
-#define _G_unistd_h 1
-
-#include <_G_config.h>
-
-extern "C" {
-
-#if _G_HAVE_UNISTD
-#ifndef _G_USE_PROTOS
-#define chmod __hide_chmod
-#define chown __hide_chown
-#define execl __hide_execl
-#define execlp __hide_execlp
-#define execle __hide_execle
-#define fchown __hide_fchown
-#define ioctl __hide_ioctl
-#define setgid __hide_setgid
-#define setuid __hide_setuid
-#endif
-#ifdef _AIX
-// AIX's unistd.h defines int rename (const char *old, const char *new).
-// This is not legal ANSI. It causes a C++ syntax error (because of 'new').
-#define new __new
-#endif
-#include_next <unistd.h>
-#ifdef _AIX
-#undef new
-#endif
-#ifndef _G_USE_PROTOS
-#undef chmod
-#undef chown
-#undef execl
-#undef execle
-#undef execlp
-#undef fchown
-#undef ioctl
-#undef setgid
-#undef setuid
-#endif
-#else
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-#endif
-
-#ifndef F_OK
-#define F_OK 0
-#endif
-#ifndef X_OK
-#define X_OK 1
-#endif
-#ifndef W_OK
-#define W_OK 2
-#endif
-#ifndef R_OK
-#define R_OK 4
-#endif
-#endif
-
-#ifdef __GNUG__
-extern void volatile _exit(int);
-#else
-void _exit(int);
-#endif
-
-extern unsigned alarm _G_ARGS((unsigned));
-#ifndef __386BSD__
-extern int brk _G_ARGS((void*));
-#else
-extern char* brk _G_ARGS((const char*));
-#endif
-extern int chdir _G_ARGS((const char*));
-extern int chmod _G_ARGS((const char*, _G_mode_t));
-extern int chown (const char*, _G_uid_t, _G_gid_t);
-extern int close _G_ARGS((int));
-extern char* crypt _G_ARGS((const char*, const char*));
-extern int dup _G_ARGS((int));
-extern int dup2 _G_ARGS((int, int));
-#ifndef __386BSD__
-extern void encrypt _G_ARGS((char*, int));
-#else
-extern int encrypt _G_ARGS((char*, int));
-#endif
-extern int execl (const char*, const char *, ...);
-extern int execle (const char*, const char *, ...);
-extern int execlp (const char*, const char*, ...);
-#ifndef __386BSD__
-extern int exect _G_ARGS((const char*, const char**, char**));
-extern int execv _G_ARGS((const char*, const char * const *));
-extern int execve _G_ARGS((const char*, const char * const *, const char * const *));
-extern int execvp _G_ARGS((const char*, const char * const *));
-extern int fchown (int, _G_uid_t, _G_gid_t);
-#else
-extern int exect _G_ARGS((const char*, char * const*, char * const *));
-extern int execv _G_ARGS((const char*, char * const *));
-extern int execve _G_ARGS((const char*, char * const *, char * const *));
-extern int execvp _G_ARGS((const char*, char * const *));
-extern int fchown (int, int, int);
-#endif
-extern _G_pid_t fork _G_ARGS((void));
-extern int fsync _G_ARGS((int));
-extern int ftruncate _G_ARGS((int, _G_off_t));
-extern char* getcwd _G_ARGS((char*, _G_size_t));
-extern int getdomainname _G_ARGS((char*, int));
-extern int getdtablesize _G_ARGS((void));
-#ifndef __386BSD__
-extern int getgroups _G_ARGS((int, _G_gid_t*));
-#else
-extern int getgroups _G_ARGS((int, int*));
-#endif
-extern _G_uid_t geteuid _G_ARGS((void));
-extern _G_gid_t getegid _G_ARGS((void));
-extern _G_gid_t getgid _G_ARGS((void));
-extern long gethostid _G_ARGS((void));
-extern int gethostname _G_ARGS((char*, int));
-extern _G_pid_t getpgrp _G_ARGS((...));
-extern _G_pid_t getpid _G_ARGS((void));
-extern _G_pid_t getppid _G_ARGS((void));
-extern char* getlogin _G_ARGS((void));
-extern char* getpass _G_ARGS((const char*));
-extern _G_uid_t getuid _G_ARGS((void));
-#ifndef __386BSD__
-extern int ioctl (int, int, ... );
-#else
-extern int ioctl (int, unsigned long, ... );
-#endif
-extern int isatty _G_ARGS((int));
-extern int link _G_ARGS((const char*, const char*));
-extern int lockf _G_ARGS((int, int, long));
-extern int mkstemp _G_ARGS((char*));
-extern char* mktemp _G_ARGS((char*));
-extern int nice _G_ARGS((int));
-extern int pause _G_ARGS((void));
-extern int pipe _G_ARGS((int*));
-extern int readlink _G_ARGS((const char*, char*, int));
-extern int rename _G_ARGS((const char*, const char*));
-extern int rmdir _G_ARGS((const char*));
-#if defined( __OSF1__ ) || defined (__386BSD__)
-extern char* sbrk _G_ARGS((int));
-#else
-extern void* sbrk _G_ARGS((int));
-#endif
-extern int syscall _G_ARGS((int, ...));
-extern int setgid (_G_gid_t);
-extern int sethostname _G_ARGS((const char*, int));
-#ifdef _G_SYSV
-extern _G_pid_t setpgrp _G_ARGS((void));
-extern _G_pid_t setsid _G_ARGS((void));
-#else
-#ifndef __386BSD__
-extern _G_pid_t setpgrp _G_ARGS((_G_pid_t, _G_pid_t));
-#else
-extern _G_pid_t setsid _G_ARGS((void));
-extern int setpgrp _G_ARGS((_G_pid_t, _G_pid_t));
-#endif
-#endif
-extern int setregid _G_ARGS((int, int));
-extern int setreuid _G_ARGS((int, int));
-extern int setuid (_G_uid_t);
-extern unsigned sleep _G_ARGS((unsigned));
-extern void swab _G_ARGS((void*, void*, int));
-extern int symlink _G_ARGS((const char*, const char*));
-extern long sysconf _G_ARGS((int));
-extern int truncate _G_ARGS((const char*, _G_off_t));
-extern char* ttyname _G_ARGS((int));
-extern int ttyslot _G_ARGS((void));
-//extern int umask _G_ARGS((int)); /* commented out for now; wrong for SunOs4.1 */
-extern int unlink _G_ARGS((const char*));
-#ifndef __386BSD__
-extern _G_pid_t vfork _G_ARGS((void));
-#else
-extern int vfork _G_ARGS((void));
-#endif
-extern int vadvise _G_ARGS((int));
-extern int vhangup _G_ARGS((void));
-extern _G_off_t lseek _G_ARGS((int, long, int));
-extern _G_ssize_t read _G_ARGS((int, void*, _G_size_t));
-extern _G_ssize_t write _G_ARGS((int, const void*, _G_size_t));
-extern int access _G_ARGS((const char*, int));
-#ifndef hpux
-extern int flock _G_ARGS((int, int));
-#endif
-
-}
-
-#endif
diff --git a/gnu/lib/libg++/g++-include/values.h b/gnu/lib/libg++/g++-include/values.h
deleted file mode 100644
index 56f8a9415551..000000000000
--- a/gnu/lib/libg++/g++-include/values.h
+++ /dev/null
@@ -1,174 +0,0 @@
-// This may look like C code, but it is really -*- C++ -*-
-/*
-Copyright (C) 1988 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
-This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-
-#ifndef _values_h
-#define _values_h 1
-
-#define BITSPERBYTE 8
-#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
-
-#define CHARBITS BITS(char)
-#define SHORTBITS BITS(short)
-#define INTBITS BITS(int)
-#define LONGBITS BITS(long)
-#define PTRBITS BITS(char*)
-#define DOUBLEBITS BITS(double)
-#define FLOATBITS BITS(float)
-
-#define MINSHORT ((short)(1 << (SHORTBITS - 1)))
-#define MININT (1 << (INTBITS - 1))
-#define MINLONG (1L << (LONGBITS - 1))
-
-#define MAXSHORT ((short)~MINSHORT)
-#define MAXINT (~MININT)
-#define MAXLONG (~MINLONG)
-
-#define HIBITS MINSHORT
-#define HIBITL MINLONG
-
-#if defined(sun) || defined(hp300) || defined(hpux) || defined(masscomp) || defined(sgi)
-#ifdef masscomp
-#define MAXDOUBLE \
-({ \
- double maxdouble_val; \
- \
- __asm ("fmove%.d #0x7fefffffffffffff,%0" /* Max double */ \
- : "=f" (maxdouble_val) \
- : /* no inputs */); \
- maxdouble_val; \
-})
-#define MAXFLOAT ((float) 3.40e+38)
-#else
-#define MAXDOUBLE 1.79769313486231470e+308
-#define MAXFLOAT ((float)3.40282346638528860e+38)
-#endif
-#define MINDOUBLE 4.94065645841246544e-324
-#define MINFLOAT ((float)1.40129846432481707e-45)
-#define _IEEE 1
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
-#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-#elif defined(sony)
-#define MAXDOUBLE 1.79769313486231470e+308
-#define MAXFLOAT ((float)3.40282346638528860e+38)
-#define MINDOUBLE 2.2250738585072010e-308
-#define MINFLOAT ((float)1.17549435e-38)
-#define _IEEE 1
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
-#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-#elif defined(sequent)
-extern double _maxdouble, _mindouble;
-extern float _maxfloat, _minfloat;
-#define MAXDOUBLE _maxdouble
-#define MAXFLOAT _maxfloat
-#define MINDOUBLE _mindouble
-#define MINFLOAT _minfloat
-#define _IEEE 1
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-(DMAXEXP - 3))
-#define FMINEXP (-(FMAXEXP - 3))
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-#elif defined(i386)
-#define MAXDOUBLE 1.79769313486231570e+308
-#define MAXFLOAT ((float)3.40282346638528860e+38)
-#define MINDOUBLE 2.22507385850720140e-308
-#define MINFLOAT ((float)1.17549435082228750e-38)
-#define _IEEE 0
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-DMAXEXP)
-#define FMINEXP (-FMAXEXP)
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-/* from Andrew Klossner <andrew%frip.wv.tek.com@relay.cs.net> */
-#elif defined(m88k)
- /* These are "good" guesses ...
- I'll figure out the true mins and maxes later, at the time I find
- out the mins and maxes that the compiler can tokenize. */
-#define MAXDOUBLE 1.79769313486231e+308
-#define MAXFLOAT ((float)3.40282346638528e+38)
-#define MINDOUBLE 2.22507385850720e-308
-#define MINFLOAT ((float)1.17549435082228e-38)
-#define _IEEE 1
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (1-DMAXEXP)
-#define FMINEXP (1-FMAXEXP)
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-#elif defined(convex)
-#define MAXDOUBLE 8.9884656743115785e+306
-#define MAXFLOAT ((float) 1.70141173e+38)
-#define MINDOUBLE 5.5626846462680035e-308
-#define MINFLOAT ((float) 2.93873588e-39)
-#define _IEEE 0
-#define _DEXPLEN 11
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-DMAXEXP)
-#define FMINEXP (-FMAXEXP)
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-
-// #elif defined(vax)
-// use vax versions by default -- they seem to be the most conservative
-#else
-
-#define MAXDOUBLE 1.701411834604692293e+38
-#define MINDOUBLE (2.938735877055718770e-39)
-
-#define MAXFLOAT 1.7014117331926443e+38
-#define MINFLOAT 2.9387358770557188e-39
-
-#define _IEEE 0
-#define _DEXPLEN 8
-#define _FEXPLEN 8
-#define _HIDDENBIT 1
-#define DMINEXP (-DMAXEXP)
-#define FMINEXP (-FMAXEXP)
-#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
-#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
-#endif
-
-#define DSIGNIF (DOUBLEBITS - _DEXPLEN + _HIDDENBIT - 1)
-#define FSIGNIF (FLOATBITS - _FEXPLEN + _HIDDENBIT - 1)
-#define DMAXPOWTWO ((double)(1L << LONGBITS -2)*(1L << DSIGNIF - LONGBITS +1))
-#define FMAXPOWTWO ((float)(1L << FSIGNIF - 1))
-
-#endif
-
diff --git a/gnu/lib/libg++/include/values.h b/gnu/lib/libg++/include/values.h
new file mode 100644
index 000000000000..529c5e7ae96a
--- /dev/null
+++ b/gnu/lib/libg++/include/values.h
@@ -0,0 +1,173 @@
+/*
+Copyright (C) 1988 Free Software Foundation
+ written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _VALUES_H_
+#define _VALUES_H_
+
+#define BITSPERBYTE 8
+#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
+
+#define CHARBITS BITS(char)
+#define SHORTBITS BITS(short)
+#define INTBITS BITS(int)
+#define LONGBITS BITS(long)
+#define PTRBITS BITS(char*)
+#define DOUBLEBITS BITS(double)
+#define FLOATBITS BITS(float)
+
+#define MINSHORT ((short)(1 << (SHORTBITS - 1)))
+#define MININT (1 << (INTBITS - 1))
+#define MINLONG (1L << (LONGBITS - 1))
+
+#define MAXSHORT ((short)~MINSHORT)
+#define MAXINT (~MININT)
+#define MAXLONG (~MINLONG)
+
+#define HIBITS MINSHORT
+#define HIBITL MINLONG
+
+#if defined(sun) || defined(hp300) || defined(hpux) || defined(masscomp) || defined(sgi)
+#ifdef masscomp
+#define MAXDOUBLE \
+({ \
+ double maxdouble_val; \
+ \
+ __asm ("fmove%.d #0x7fefffffffffffff,%0" /* Max double */ \
+ : "=f" (maxdouble_val) \
+ : /* no inputs */); \
+ maxdouble_val; \
+})
+#define MAXFLOAT ((float) 3.40e+38)
+#else
+#define MAXDOUBLE 1.79769313486231470e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#endif
+#define MINDOUBLE 4.94065645841246544e-324
+#define MINFLOAT ((float)1.40129846432481707e-45)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+#elif defined(sony)
+#define MAXDOUBLE 1.79769313486231470e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 2.2250738585072010e-308
+#define MINFLOAT ((float)1.17549435e-38)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+#elif defined(sequent)
+extern double _maxdouble, _mindouble;
+extern float _maxfloat, _minfloat;
+#define MAXDOUBLE _maxdouble
+#define MAXFLOAT _maxfloat
+#define MINDOUBLE _mindouble
+#define MINFLOAT _minfloat
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-(DMAXEXP - 3))
+#define FMINEXP (-(FMAXEXP - 3))
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+#elif defined(i386)
+#define MAXDOUBLE 1.79769313486231570e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 2.22507385850720140e-308
+#define MINFLOAT ((float)1.17549435082228750e-38)
+#define _IEEE 0
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-DMAXEXP)
+#define FMINEXP (-FMAXEXP)
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+/* from Andrew Klossner <andrew%frip.wv.tek.com@relay.cs.net> */
+#elif defined(m88k)
+ /* These are "good" guesses ...
+ I'll figure out the true mins and maxes later, at the time I find
+ out the mins and maxes that the compiler can tokenize. */
+#define MAXDOUBLE 1.79769313486231e+308
+#define MAXFLOAT ((float)3.40282346638528e+38)
+#define MINDOUBLE 2.22507385850720e-308
+#define MINFLOAT ((float)1.17549435082228e-38)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (1-DMAXEXP)
+#define FMINEXP (1-FMAXEXP)
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+#elif defined(convex)
+#define MAXDOUBLE 8.9884656743115785e+306
+#define MAXFLOAT ((float) 1.70141173e+38)
+#define MINDOUBLE 5.5626846462680035e-308
+#define MINFLOAT ((float) 2.93873588e-39)
+#define _IEEE 0
+#define _DEXPLEN 11
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-DMAXEXP)
+#define FMINEXP (-FMAXEXP)
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+
+/* #elif defined(vax) */
+/* use vax versions by default -- they seem to be the most conservative */
+#else
+
+#define MAXDOUBLE 1.701411834604692293e+38
+#define MINDOUBLE (2.938735877055718770e-39)
+
+#define MAXFLOAT 1.7014117331926443e+38
+#define MINFLOAT 2.9387358770557188e-39
+
+#define _IEEE 0
+#define _DEXPLEN 8
+#define _FEXPLEN 8
+#define _HIDDENBIT 1
+#define DMINEXP (-DMAXEXP)
+#define FMINEXP (-FMAXEXP)
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+#endif
+
+#define DSIGNIF (DOUBLEBITS - _DEXPLEN + _HIDDENBIT - 1)
+#define FSIGNIF (FLOATBITS - _FEXPLEN + _HIDDENBIT - 1)
+#define DMAXPOWTWO ((double)(1L << LONGBITS -2)*(1L << DSIGNIF - LONGBITS +1))
+#define FMAXPOWTWO ((float)(1L << FSIGNIF - 1))
+
+#endif /* !_VALUES_H_ */
+
diff --git a/gnu/lib/libg++/libg++/CursesW.cc b/gnu/lib/libg++/libg++/CursesW.cc
index 9533f6915566..2aa2260ec0ce 100644
--- a/gnu/lib/libg++/libg++/CursesW.cc
+++ b/gnu/lib/libg++/libg++/CursesW.cc
@@ -41,7 +41,7 @@ int CursesWindow::count = 0;
#if !defined(_IO_MAGIC) && !defined(HAVE_VSCANF) &&!defined vsscanf
extern "C" int _doscan(FILE *, const char*, va_list args);
-static int vsscanf(char *buf, const char * fmt, va_list args)
+static int vsscanf(const char *buf, const char * fmt, va_list args)
{
FILE b;
#ifdef _IOSTRG
diff --git a/gnu/lib/libg++/libg++/Makefile b/gnu/lib/libg++/libg++/Makefile
index 4f59cdbe0c8e..8c6a3ccfdb71 100644
--- a/gnu/lib/libg++/libg++/Makefile
+++ b/gnu/lib/libg++/libg++/Makefile
@@ -1,5 +1,11 @@
LIB= g++
+
+# This cruft is necessary due to the way shared library globals are
+# dereferenced. The libg++ encapsulation of curses makes this necessary.
+SHARED_LDADD+= -lcurses
+
CC= gcc
+
SRCS= AllocRing.cc Obstack.cc builtin.cc \
regex.cc Regex.cc String.cc Integer.cc Rational.cc Complex.cc Random.cc \
BitSet.cc BitString.cc LogNorm.cc SmplHist.cc SmplStat.cc \
@@ -17,9 +23,7 @@ SRCS= AllocRing.cc Obstack.cc builtin.cc \
sbufvscan.C stdiostream.C floatconv.C outfloat.C iomanip.C \
insque.c strerror.c
-CFLAGS+= -I$(.CURDIR) -I$(.CURDIR)/../libiberty
-CXXFLAGS= -nostdinc++ -I$(.CURDIR) -I$(.CURDIR)/../g++-include \
- -I$(.CURDIR)/../iostream
+CFLAGS+= -I$(.CURDIR)/../libiberty
NOMAN= noman
.PATH: $(.CURDIR)/../iostream $(.CURDIR)/../libiberty
diff --git a/gnu/lib/libmalloc/Makefile b/gnu/lib/libmalloc/Makefile
index 56724dfc095a..d69a7dbe5a44 100644
--- a/gnu/lib/libmalloc/Makefile
+++ b/gnu/lib/libmalloc/Makefile
@@ -1,7 +1,5 @@
-# $Id: Makefile,v 1.4 1993/12/28 07:54:51 smace Exp $
+# $Id: Makefile,v 1.5 1994/05/27 10:48:19 csgr Exp $
-SHLIB_MAJOR=1
-SHLIB_MINOR=0
CFLAGS+= -I${.CURDIR}
diff --git a/gnu/lib/libreadline/COPYING b/gnu/lib/libreadline/COPYING
new file mode 100644
index 000000000000..1bb82d1b26d8
--- /dev/null
+++ b/gnu/lib/libreadline/COPYING
@@ -0,0 +1,257 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+The Free Software Foundation has exempted Bash from the requirement of
+Paragraph 2c of the General Public License. This is to say, there is
+no requirement for Bash to print a notice when it is started
+interactively in the usual way. We made this exception because users
+and standards expect shells not to print such messages. This
+exception applies to any program that serves as a shell and that is
+based primarily on Bash as opposed to other GNU software.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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/gnu/lib/libreadline/ChangeLog b/gnu/lib/libreadline/ChangeLog
new file mode 100644
index 000000000000..1cf0c004af56
--- /dev/null
+++ b/gnu/lib/libreadline/ChangeLog
@@ -0,0 +1,403 @@
+Tue Mar 23 14:36:51 1993 Brian Fox (bfox@eos.crseo.ucsb.edu)
+
+ * readline.c (rl_copy): Changed name to rl_copy_text.
+
+Mon Mar 22 19:16:05 1993 Brian Fox (bfox@eos.crseo.ucsb.edu)
+
+ * dispose_cmd.c, several other files. Declare dispose_xxx () as
+ "void".
+
+ * builtins/hashcom.h: Make declarations of hashed_filenames be
+ "extern" to keep the SGI compiler happy.
+
+ * readline.c (rl_initialize_everything): Assign values to
+ out_stream and in_stream immediately, since
+ output_character_function () can be called before
+ readline_internal () is called.
+
+Tue Dec 8 09:30:56 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (rl_init_terminal) Set PC from BC, not from *buffer.
+
+Mon Nov 30 09:35:47 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (invoking_keyseqs_in_map, rl_parse_and_bind) Allow
+ backslash to quote characters, such as backslash, double quote,
+ and space. Backslash quotes all character indiscriminately.
+
+ * funmap.c (vi_keymap) Fix type in "vi-replace" declaration.
+
+Fri Nov 20 10:55:05 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (init_terminal_io, rl_prep_terminal): FINALLY!
+ Declare and use termcap variable `ospeed' when setting up terminal
+ parameters.
+
+Thu Oct 8 08:53:07 1992 Brian J. Fox (bfox@helios)
+
+ * Makefile, this directory: Include (as links to the canonical
+ sources), tilde.c, tilde.h, posixstat.h and xmalloc.c.
+
+Tue Sep 29 13:07:21 1992 Brian J. Fox (bfox@helios)
+
+ * readline.c (init_terminal_io) Don't set arrow keys if the key
+ sequences that represent them are already set.
+
+ * readline.c (rl_function_of_keyseq) New function returns the first
+ function (or macro) found while searching a key sequence.
+
+Mon Sep 28 00:34:04 1992 Brian J. Fox (bfox@helios)
+
+ * readline.c (LibraryVersion) New static char * contains current
+ version number. Version is at 2.0.
+
+ * readline.c (rl_complete_internal): Incorporated clean changes
+ from gilmore (gnu@cygnus.com) to support quoted substrings within
+ completion functions.
+
+ * readline.c (many locations) Added support for the _GO32_,
+ whatever that is. Patches supplied by Cygnus, typed in by hand,
+ with cleanups.
+
+Sun Aug 16 12:46:24 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (init_terminal_io): Find out the values of the keypad
+ arrows and bind them to appropriate RL functions if present.
+
+Mon Aug 10 18:13:24 1992 Brian Fox (bfox@cubit)
+
+ * history.c (stifle_history): A negative argument to stifle
+ becomes zero.
+
+Tue Jul 28 09:28:41 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (rl_variable_bind): New local structure describes
+ booleans by name and address; code in rl_variable_bind () looks at
+ structure to set simple variables.
+
+ * parens.c (rl_insert_close): New variable rl_blink_matching_paren
+ is non-zero if we want to blink the matching open when a close is
+ inserted. If FD_SET is defined, rl_blink_matching_paren defaults
+ to 1, else 0. If FD_SET is not defined, and
+ rl_blink_matching_paren is non-zero, the close character(s) are/is
+ simply inserted.
+
+Wed Jul 22 20:03:59 1992 Brian Fox (bfox@cubit)
+
+ * history.c, readline.c, vi_mode.c: Cause the functions strchr ()
+ and strrchr () to be used instead of index () and rindex ()
+ throughout the source.
+
+Mon Jul 13 11:34:07 1992 Brian Fox (bfox@cubit)
+
+ * readline.c: (rl_variable_bind) New variable "meta-flag" if "on"
+ means force the use of the 8th bit as Meta bit. Internal variable
+ is called meta_flag.
+
+Thu Jul 9 10:37:56 1992 Brian Fox (bfox@cubit)
+
+ * history.c (get_history_event) Change INDEX to LOCAL_INDEX. If
+ compiling for the shell, allow shell metacharacters to separate
+ history tokens as they would for shell tokens.
+
+Sat Jul 4 19:29:12 1992 Brian Fox (bfox@cubit)
+
+ * vi_keymap.c: According to Posix, TAB self-inserts instead of
+ doing completion.
+
+ * vi_mode.c: (rl_vi_yank_arg) Enter VI insert mode after yanking
+ an arg from the previous line.
+
+ * search.c: New file takes over vi style searching and implements
+ non-incremental searching the history.
+
+ Makefile: Add search.c and search.o.
+
+ funmap.c: Add names for non-incremental-forward-search-history and
+ non-incremental-reverse-search-history.
+
+ readline.h: Add extern definitions for non-incremental searching.
+
+ vi_mode.c: Remove old search code; add calls to code in search.c.
+
+Fri Jul 3 10:36:33 1992 Brian Fox (bfox@cubit)
+
+ * readline.c (rl_delete_horizontal_space); New function deletes
+ all whitespace surrounding point.
+
+ funmap.c: Add "delete-horizontal-space".
+ emacs_keymap.c: Put rl_delete_horizontal_space () on M-\.
+
+ * readline.c (rl_set_signals, rl_clear_signals); New function
+ rl_set_sighandler () is either defined in a Posix way (if
+ HAVE_POSIX_SIGNALS is defined) or in a BSD way. Function is
+ called from rl_set_signals () and rl_clear_signals ().
+
+Fri May 8 12:50:15 1992 Brian Fox (bfox@cubit)
+
+ * readline.c: (readline_default_bindings) Do comparisons with
+ _POSIX_VDISABLE casted to `unsigned char'. Change tty characters
+ to be unsigned char.
+
+Thu Apr 30 12:36:35 1992 Brian Fox (bfox@cubit)
+
+ * readline.c: (rl_getc) Handle "read would block" error on
+ non-blocking IO streams.
+
+ * readline.c: (rl_signal_handler): Unblock only the signal that we
+ have caught, not all signals.
+
+Sun Feb 23 03:33:09 1992 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: Many functions. Use only the macros META_CHAR and
+ UNMETA to deal with meta characters. Prior to this, we used
+ numeric values and tests.
+
+ * readline.c (rl_complete_internal) Report exactly the number of
+ possible completions, not the number + 1.
+
+ * vi_mode.c (rl_do_move) Do not change the cursor position when
+ using `cw' or `cW'.
+
+ * vi_mode.c (rl_vi_complete) Enter insert mode after completing
+ with `*' or `\'.
+
+Fri Feb 21 05:58:18 1992 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (rl_dispatch) Increment rl_key_sequence_length for
+ meta characters that map onto ESC map.
+
+Mon Feb 10 01:41:35 1992 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * history.c (history_do_write) Build a buffer of all of the lines
+ to write and write them in one fell swoop (lower overhead than
+ calling write () for each line). Suggested by Peter Ho.
+
+ * readline.c: Include hbullx20 as well as hpux for determining
+ USGr3ness.
+
+ * readline.c (rl_unix_word_rubout) As per the "Now REMEMBER"
+ comment, pass arguments to rl_kill_text () in the correct order to
+ preserve prepending and appending of killed text.
+
+ * readline.c (rl_search_history) malloc (), realloc (), and free
+ () SEARCH_STRING so that there are no static limits on searching.
+
+ * vi_mode.c (rl_vi_subst) Don't forget to end the undo group.
+
+Fri Jan 31 14:51:02 1992 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (rl_signal_handler): Zero the current history entry's
+ pointer after freeing the undo_list when SIGINT received.
+ Reformat a couple of functions.
+
+Sat Jan 25 13:47:35 1992 Brian Fox (bfox at bears)
+
+ * readline.c (parser_if): free () TNAME after use.
+
+Tue Jan 21 01:01:35 1992 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (rl_redisplay) and (rl_character_len): Display
+ Control characters as "^c" and Meta characters as "\234", instead
+ of "C-C" and "M-C".
+
+Sun Dec 29 10:59:00 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (init_terminal_io) Default to environment variables
+ LINES and COLUMNS before termcap entry values. If all else fails,
+ then assume 80x24 terminal.
+
+Sat Dec 28 16:33:11 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: If this machine is USG and it is hpux, then define
+ USGr3.
+
+ * history.c: Cosmetic fixes.
+
+Thu Nov 21 00:10:12 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * vi_mode.c: (rl_do_move) Place cursor at end of line, never at
+ next to last character.
+
+Thu Nov 14 05:08:01 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * history.c (get_history_event) Non-anchored searches can have a
+ return index of greater than zero from get_history_event ().
+
+Fri Nov 1 07:02:13 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (rl_translate_keyseq) Make C-? translate to RUBOUT
+ unconditionally.
+
+Mon Oct 28 11:34:52 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c; Use Posix directory routines and macros.
+
+ * funmap.c; Add entry for call-last-kbd-macro.
+
+ * readline.c (rl_prep_term); Use system EOF character on POSIX
+ systems also.
+
+Thu Oct 3 16:19:53 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c; Make a distinction between having a TERMIOS tty
+ driver, and having POSIX signal handling. You might one without
+ the other. New defines used HAVE_POSIX_SIGNALS, and
+ TERMIOS_TTY_DRIVER.
+
+Tue Jul 30 22:37:26 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: rl_getc () If a call to read () returns without an
+ error, but with zero characters, the file is empty, so return EOF.
+
+Thu Jul 11 20:58:38 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: (rl_get_next_history, rl_get_previous_history)
+ Reallocate the buffer space if the line being moved to is longer
+ the the current space allocated. Amazing that no one has found
+ this bug until now.
+
+Sun Jul 7 02:37:05 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c:(rl_parse_and_bind) Allow leading whitespace.
+ Make sure TERMIO and TERMIOS systems treat CR and NL
+ disctinctly.
+
+Tue Jun 25 04:09:27 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: Rework parsing conditionals to pay attention to the
+ prior states of the conditional stack. This makes $if statements
+ work correctly.
+
+Mon Jun 24 20:45:59 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: support for displaying key binding information
+ includes the functions rl_list_funmap_names (),
+ invoking_keyseqs_in_map (), rl_invoking_keyseqs (),
+ rl_dump_functions (), and rl_function_dumper ().
+
+ funmap.c: support for same includes rl_funmap_names ().
+
+ readline.c, funmap.c: no longer define STATIC_MALLOC. However,
+ update both version of xrealloc () to handle a null pointer.
+
+Thu Apr 25 12:03:49 1991 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * vi_mode.c (rl_vi_fword, fWord, etc. All functions use
+ the macro `isident()'. Fixed movement bug which prevents
+ continious movement through the text.
+
+Fri Jul 27 16:47:01 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (parser_if) Allow "$if term=foo" construct.
+
+Wed May 23 16:10:33 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c (rl_dispatch) Correctly remember the last command
+ executed. Fixed typo in username_completion_function ().
+
+Mon Apr 9 19:55:48 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: username_completion_function (); For text passed in
+ with a leading `~', remember that this could be a filename (after
+ it is completed).
+
+Thu Apr 5 13:44:24 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: rl_search_history (): Correctly handle case of an
+ unfound search string, but a graceful exit (as with ESC).
+
+ * readline.c: rl_restart_output (); The Apollo passes the address
+ of the file descriptor to TIOCSTART, not the descriptor itself.
+
+Tue Mar 20 05:38:55 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * readline.c: rl_complete (); second call in a row causes possible
+ completions to be listed.
+
+ * readline.c: rl_redisplay (), added prompt_this_line variable
+ which is the first character character following \n in prompt.
+
+Sun Mar 11 04:32:03 1990 Brian Fox (bfox at gnuwest.fsf.org)
+
+ * Signals are now supposedly handled inside of SYSV compilation.
+
+Wed Jan 17 19:24:09 1990 Brian Fox (bfox at sbphy.ucsb.edu)
+
+ * history.c: history_expand (); fixed overwriting memory error,
+ added needed argument to call to get_history_event ().
+
+Thu Jan 11 10:54:04 1990 Brian Fox (bfox at sbphy.ucsb.edu)
+
+ * readline.c: added mark_modified_lines to control the
+ display of an asterisk on modified history lines. Also
+ added a user variable called mark-modified-lines to the
+ `set' command.
+
+Thu Jan 4 10:38:05 1990 Brian Fox (bfox at sbphy.ucsb.edu)
+
+ * readline.c: start_insert (). Only use IC if we don't have an im
+ capability.
+
+Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: rl_prep_terminal (). Only turn on 8th bit
+ as meta-bit iff the terminal is not using parity.
+
+Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: start_insert (). Uses multiple
+ insertion call in cases where that makes sense.
+
+ rl_insert (). Read type-ahead buffer for additional
+ keys that are bound to rl_insert, and insert them
+ all at once. Make insertion of single keys given
+ with an argument much more efficient.
+
+Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: Changed handling of EOF. readline () returns
+ (char *)EOF or consed string. The EOF character is read from the
+ tty, or if the tty doesn't have one, defaults to C-d.
+
+ * readline.c: Added support for event driven programs.
+ rl_event_hook is the address of a function you want called
+ while Readline is waiting for input.
+
+ * readline.c: Cleanup time. Functions without type declarations
+ do not use return with a value.
+
+ * history.c: history_expand () has new variable which is the
+ characters to ignore immediately following history_expansion_char.
+
+Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel)
+
+ * rl_prep_terminal ()
+ BSD version turns off C-s, C-q, C-y, C-v.
+
+ * readline.c -- rl_prep_terminal ()
+ SYSV version hacks readline_echoing_p.
+ BSD version turns on passing of the 8th bit for the duration
+ of reading the line.
+
+Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: new variable rl_tilde_expander.
+ If non-null, this contains the address of a function to call if
+ the standard meaning for expanding a tilde fails. The function is
+ called with the text sans tilde (as in "foo"), and returns a
+ malloc()'ed string which is the expansion, or a NULL pointer if
+ there is no expansion.
+
+ * readline.h - new file chardefs.h
+ Separates things that only readline.c needs from the standard
+ header file publishing interesting things about readline.
+
+ * readline.c:
+ readline_default_bindings () now looks at terminal chararacters
+ and binds those as well.
+
+Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel)
+
+ * Made readline and history into independent libraries.
+
diff --git a/gnu/lib/libreadline/Makefile b/gnu/lib/libreadline/Makefile
new file mode 100644
index 000000000000..bfe8661dc075
--- /dev/null
+++ b/gnu/lib/libreadline/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.13 1994/06/12 08:50:39 ache Exp $
+
+
+CFLAGS+= -I${.CURDIR} -DVOID_SIGHANDLER \
+ -DHAVE_UNISTD_H -DHAVE_STRING_H -DHAVE_STDLIB_H -DHAVE_VARARGS_H \
+ -DFreeBSD
+
+LIB= readline
+SRCS+= readline.c funmap.c keymaps.c vi_mode.c parens.c \
+ rltty.c complete.c bind.c isearch.c display.c signals.c \
+ history.c search.c tilde.c xmalloc.c
+HEADERS= history.h readline.h keymaps.h chardefs.h tilde.h
+NOMAN= noman
+
+beforeinstall:
+ @-if [ ! -d ${DESTDIR}/usr/include/readline ]; then \
+ mkdir ${DESTDIR}/usr/include/readline; \
+ chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/include/readline; \
+ chmod 755 ${DESTDIR}/usr/include/readline; \
+ fi
+ cd ${.CURDIR}/readline; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${HEADERS} ${DESTDIR}/usr/include/readline
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libreadline/README b/gnu/lib/libreadline/README
new file mode 100644
index 000000000000..131471ca8354
--- /dev/null
+++ b/gnu/lib/libreadline/README
@@ -0,0 +1,6 @@
+This is the distribution of the Gnu Readline library. See the file
+STANDALONE for a description of the #defines that can be passed via
+the makefile to build readline on different systems.
+
+The file rlconf.h contains defines that enable and disable certain
+readline features.
diff --git a/gnu/lib/libreadline/README.FreeBSD b/gnu/lib/libreadline/README.FreeBSD
new file mode 100644
index 000000000000..6af2775c2eb0
--- /dev/null
+++ b/gnu/lib/libreadline/README.FreeBSD
@@ -0,0 +1,21 @@
+The GNU Readline library is a programming tool that provides a
+consistent user interface for recalling lines of previously typed
+input and performing editing tasks on input lines.
+
+paul@freefall.cdrom.com
+
+There was a bug with tcsh: when readline attempt to get tty
+modes from background, it got no-echo editing tcsh mode.
+
+Workaround for this implemented via TIOCGWINSZ/TIOCSWINSZ
+with same winsize structure: it does nothing expect polling
+process from background. Look tcsh_hack.readme for details.
+
+This version is more ctype-oriented than original bash version.
+
+If you want 8-bit clean version, put
+ set convert-meta off
+ set output-meta on
+in your ~/.inputrc file
+
+ache@astral.msk.su
diff --git a/gnu/lib/libreadline/STANDALONE b/gnu/lib/libreadline/STANDALONE
new file mode 100644
index 000000000000..17d5fb7fc80c
--- /dev/null
+++ b/gnu/lib/libreadline/STANDALONE
@@ -0,0 +1,32 @@
+This is a description of C preprocessor defines that readline accepts.
+Most are passed in from the parent `make'; e.g. from the bash source
+directory.
+
+NO_SYS_FILE <sys/file.h> is not present
+HAVE_UNISTD_H <unistd.h> exists
+HAVE_STDLIB_H <stdlib.h> exists
+HAVE_GETPW_DECLS declarations for the getpw functions are in <pwd.h>
+HAVE_VARARGS_H <varargs.h> exists and is usable
+HAVE_STRING_H <string.h> exists
+HAVE_ALLOCA_H <alloca.h> exists and is needed for alloca()
+HAVE_ALLOCA alloca(3) or a define for it exists
+PRAGMA_ALLOCA use of alloca() requires a #pragma, as in AIX 3.x
+VOID_SIGHANDLER signal handlers are void functions
+HAVE_DIRENT_H <dirent.h> exists and is usable
+HAVE_SYS_PTEM_H <sys/ptem.h> exists
+HAVE_SYS_PTE_H <sys/pte.h> exists
+HAVE_SYS_STREAM_H <sys/stream.h> exists
+
+System-specific options:
+
+OSF1 A machine running OSF/1
+BSD386 BSDI's BSD/386 version 1.0 or 1.1
+NetBSD NetBSD
+FreeBSD FreeBSD version 1.1
+_386BSD Old FreeBSD or NetBSD or ancient Jolitz 386bsd
+AIX AIX 3.x
+USG Running a variant of System V
+USGr3 Running System V.3
+XENIX_22 Xenix 2.2
+Linux Linux
+CRAY running a recent version of Cray UNICOS
diff --git a/gnu/lib/libreadline/VERSION b/gnu/lib/libreadline/VERSION
new file mode 100644
index 000000000000..97c5aef14b50
--- /dev/null
+++ b/gnu/lib/libreadline/VERSION
@@ -0,0 +1 @@
+readline 2.0 from bash1.14.1
diff --git a/gnu/lib/libreadline/ansi_stdlib.h b/gnu/lib/libreadline/ansi_stdlib.h
new file mode 100644
index 000000000000..52339da5d333
--- /dev/null
+++ b/gnu/lib/libreadline/ansi_stdlib.h
@@ -0,0 +1,41 @@
+/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */
+/* A minimal stdlib.h containing extern declarations for those functions
+ that bash uses. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_STDLIB_H_)
+#define _STDLIB_H_ 1
+
+/* String conversion functions. */
+extern int atoi ();
+extern long int atol ();
+
+/* Memory allocation functions. */
+extern char *malloc ();
+extern char *realloc ();
+extern void free ();
+
+/* Other miscellaneous functions. */
+extern void abort ();
+extern void exit ();
+extern char *getenv ();
+extern void qsort ();
+
+#endif /* _STDLIB_H */
diff --git a/gnu/lib/libreadline/bind.c b/gnu/lib/libreadline/bind.c
new file mode 100644
index 000000000000..b77a8a7c1ba7
--- /dev/null
+++ b/gnu/lib/libreadline/bind.c
@@ -0,0 +1,1476 @@
+/* bind.c -- key binding and startup file support for the readline library. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+# include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_bell_preference;
+extern int _rl_meta_flag;
+extern int rl_blink_matching_paren;
+extern int _rl_convert_meta_chars_to_ascii;
+extern int _rl_output_meta_chars;
+extern int _rl_complete_show_all;
+#if defined (VISIBLE_STATS)
+extern int rl_visible_stats;
+#endif /* VISIBLE_STATS */
+extern int rl_complete_with_tilde_expansion;
+extern int rl_completion_query_items;
+#if defined (VI_MODE)
+extern char *rl_vi_comment_begin;
+#endif
+
+extern int rl_explicit_arg;
+extern int rl_editing_mode;
+extern unsigned short _rl_parsing_conditionalized_out;
+extern Keymap _rl_keymap;
+
+extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+
+extern char **rl_funmap_names ();
+
+/* Forward declarations */
+void rl_set_keymap_from_edit_mode ();
+
+static int glean_key_from_name ();
+#if !defined (BSD386) && !defined (NetBSD) && \
+ !defined (FreeBSD) && !defined (_386BSD)
+static int stricmp (), strnicmp ();
+#else
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+/* **************************************************************** */
+/* */
+/* Binding keys */
+/* */
+/* **************************************************************** */
+
+/* rl_add_defun (char *name, Function *function, int key)
+ Add NAME to the list of named functions. Make FUNCTION be the function
+ that gets called. If KEY is not -1, then bind it. */
+rl_add_defun (name, function, key)
+ char *name;
+ Function *function;
+ int key;
+{
+ if (key != -1)
+ rl_bind_key (key, function);
+ rl_add_funmap_entry (name, function);
+ return 0;
+}
+
+/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
+int
+rl_bind_key (key, function)
+ int key;
+ Function *function;
+{
+ if (key < 0)
+ return (key);
+
+ if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (_rl_keymap[ESC].type == ISKMAP)
+ {
+ Keymap escmap;
+
+ escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC);
+ key = UNMETA (key);
+ escmap[key].type = ISFUNC;
+ escmap[key].function = function;
+ return (0);
+ }
+ return (key);
+ }
+
+ _rl_keymap[key].type = ISFUNC;
+ _rl_keymap[key].function = function;
+ return (0);
+}
+
+/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid
+ KEY. */
+int
+rl_bind_key_in_map (key, function, map)
+ int key;
+ Function *function;
+ Keymap map;
+{
+ int result;
+ Keymap oldmap = _rl_keymap;
+
+ _rl_keymap = map;
+ result = rl_bind_key (key, function);
+ _rl_keymap = oldmap;
+ return (result);
+}
+
+/* Make KEY do nothing in the currently selected keymap.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key (key)
+ int key;
+{
+ return (rl_bind_key (key, (Function *)NULL));
+}
+
+/* Make KEY do nothing in MAP.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key_in_map (key, map)
+ int key;
+ Keymap map;
+{
+ return (rl_bind_key_in_map (key, (Function *)NULL, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ FUNCTION. This makes new keymaps as necessary. The initial
+ place to do bindings is in MAP. */
+rl_set_key (keyseq, function, map)
+ char *keyseq;
+ Function *function;
+ Keymap map;
+{
+ return (rl_generic_bind (ISFUNC, keyseq, function, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the string of characters MACRO. This makes new keymaps as
+ necessary. The initial place to do bindings is in MAP. */
+rl_macro_bind (keyseq, macro, map)
+ char *keyseq, *macro;
+ Keymap map;
+{
+ char *macro_keys;
+ int macro_keys_len;
+
+ macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1);
+
+ if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
+ {
+ free (macro_keys);
+ return -1;
+ }
+ rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+ return 0;
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the arbitrary pointer DATA. TYPE says what kind of data is
+ pointed to by DATA, right now this can be a function (ISFUNC),
+ a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps
+ as necessary. The initial place to do bindings is in MAP. */
+rl_generic_bind (type, keyseq, data, map)
+ int type;
+ char *keyseq, *data;
+ Keymap map;
+{
+ char *keys;
+ int keys_len;
+ register int i;
+
+ /* If no keys to bind to, exit right away. */
+ if (!keyseq || !*keyseq)
+ {
+ if (type == ISMACR)
+ free (data);
+ return -1;
+ }
+
+ keys = xmalloc (1 + (2 * strlen (keyseq)));
+
+ /* Translate the ASCII representation of KEYSEQ into an array of
+ characters. Stuff the characters into KEYS, and the length of
+ KEYS into KEYS_LEN. */
+ if (rl_translate_keyseq (keyseq, keys, &keys_len))
+ {
+ free (keys);
+ return -1;
+ }
+
+ /* Bind keys, making new keymaps as necessary. */
+ for (i = 0; i < keys_len; i++)
+ {
+ int ic = (int) ((unsigned char)keys[i]);
+
+ if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic))
+ {
+ ic = UNMETA (ic);
+ if (map[ESC].type == ISKMAP)
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ }
+
+ if ((i + 1) < keys_len)
+ {
+ if (map[ic].type != ISKMAP)
+ {
+ if (map[ic].type == ISMACR)
+ free ((char *)map[ic].function);
+
+ map[ic].type = ISKMAP;
+ map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap());
+ }
+ map = FUNCTION_TO_KEYMAP (map, ic);
+ }
+ else
+ {
+ if (map[ic].type == ISMACR)
+ free ((char *)map[ic].function);
+
+ map[ic].function = KEYMAP_TO_FUNCTION (data);
+ map[ic].type = type;
+ }
+ }
+ free (keys);
+ return 0;
+}
+
+/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY,
+ an array of characters. LEN gets the final length of ARRAY. Return
+ non-zero if there was an error parsing SEQ. */
+rl_translate_keyseq (seq, array, len)
+ char *seq, *array;
+ int *len;
+{
+ register int i, c, l = 0;
+
+ for (i = 0; c = seq[i]; i++)
+ {
+ if (c == '\\')
+ {
+ c = seq[++i];
+
+ if (!c)
+ break;
+
+ if (((c == 'C' || c == 'M') && seq[i + 1] == '-') ||
+ (c == 'e'))
+ {
+ /* Handle special case of backwards define. */
+ if (strncmp (&seq[i], "C-\\M-", 5) == 0)
+ {
+ array[l++] = ESC;
+ i += 5;
+ array[l++] = CTRL (to_upper (seq[i]));
+ if (!seq[i])
+ i--;
+ continue;
+ }
+
+ switch (c)
+ {
+ case 'M':
+ i++;
+ array[l++] = ESC;
+ break;
+
+ case 'C':
+ i += 2;
+ /* Special hack for C-?... */
+ if (seq[i] == '?')
+ array[l++] = RUBOUT;
+ else
+ array[l++] = CTRL (to_upper (seq[i]));
+ break;
+
+ case 'e':
+ array[l++] = ESC;
+ }
+
+ continue;
+ }
+ }
+ array[l++] = c;
+ }
+
+ *len = l;
+ array[l] = '\0';
+ return (0);
+}
+
+/* Return a pointer to the function that STRING represents.
+ If STRING doesn't have a matching function, then a NULL pointer
+ is returned. */
+Function *
+rl_named_function (string)
+ char *string;
+{
+ register int i;
+
+ rl_initialize_funmap ();
+
+ for (i = 0; funmap[i]; i++)
+ if (stricmp (funmap[i]->name, string) == 0)
+ return (funmap[i]->function);
+ return ((Function *)NULL);
+}
+
+/* Return the function (or macro) definition which would be invoked via
+ KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is
+ used. TYPE, if non-NULL, is a pointer to an int which will receive the
+ type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap),
+ or ISMACR (macro). */
+Function *
+rl_function_of_keyseq (keyseq, map, type)
+ char *keyseq;
+ Keymap map;
+ int *type;
+{
+ register int i;
+
+ if (!map)
+ map = _rl_keymap;
+
+ for (i = 0; keyseq && keyseq[i]; i++)
+ {
+ int ic = keyseq[i];
+
+ if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (map[ESC].type != ISKMAP)
+ {
+ if (type)
+ *type = map[ESC].type;
+
+ return (map[ESC].function);
+ }
+ else
+ {
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ ic = UNMETA (ic);
+ }
+ }
+
+ if (map[ic].type == ISKMAP)
+ {
+ /* If this is the last key in the key sequence, return the
+ map. */
+ if (!keyseq[i + 1])
+ {
+ if (type)
+ *type = ISKMAP;
+
+ return (map[ic].function);
+ }
+ else
+ map = FUNCTION_TO_KEYMAP (map, ic);
+ }
+ else
+ {
+ if (type)
+ *type = map[ic].type;
+
+ return (map[ic].function);
+ }
+ }
+ return ((Function *) NULL);
+}
+
+/* The last key bindings file read. */
+static char *last_readline_init_file = (char *)NULL;
+
+/* Re-read the current keybindings file. */
+rl_re_read_init_file (count, ignore)
+ int count, ignore;
+{
+ int r;
+ r = rl_read_init_file ((char *)NULL);
+ rl_set_keymap_from_edit_mode ();
+ return r;
+}
+
+/* Do key bindings from a file. If FILENAME is NULL it defaults
+ to the first non-null filename from this list:
+ 1. the filename used for the previous call
+ 2. the value of the shell variable `INPUTRC'
+ 3. ~/.inputrc
+ If the file existed and could be opened and read, 0 is returned,
+ otherwise errno is returned. */
+int
+rl_read_init_file (filename)
+ char *filename;
+{
+ register int i;
+ char *buffer, *openname, *line, *end;
+ struct stat finfo;
+ int file;
+
+ /* Default the filename. */
+ if (!filename)
+ {
+ filename = last_readline_init_file;
+ if (!filename)
+ filename = getenv ("INPUTRC");
+ if (!filename)
+ filename = DEFAULT_INPUTRC;
+ }
+
+ openname = tilde_expand (filename);
+
+ if ((stat (openname, &finfo) < 0) ||
+ (file = open (openname, O_RDONLY, 0666)) < 0)
+ {
+ free (openname);
+ return (errno);
+ }
+ else
+ free (openname);
+
+ if (filename != last_readline_init_file)
+ {
+ if (last_readline_init_file)
+ free (last_readline_init_file);
+
+ last_readline_init_file = savestring (filename);
+ }
+
+ /* Read the file into BUFFER. */
+ buffer = (char *)xmalloc ((int)finfo.st_size + 1);
+ i = read (file, buffer, finfo.st_size);
+ close (file);
+
+ if (i != finfo.st_size)
+ return (errno);
+
+ /* Loop over the lines in the file. Lines that start with `#' are
+ comments; all other lines are commands for readline initialization. */
+ line = buffer;
+ end = buffer + finfo.st_size;
+ while (line < end)
+ {
+ /* Find the end of this line. */
+ for (i = 0; line + i != end && line[i] != '\n'; i++);
+
+ /* Mark end of line. */
+ line[i] = '\0';
+
+ /* Skip leading whitespace. */
+ while (*line && whitespace (*line))
+ line++;
+
+ /* If the line is not a comment, then parse it. */
+ if (*line && *line != '#')
+ rl_parse_and_bind (line);
+
+ /* Move to the next line. */
+ line += i + 1;
+ }
+ free (buffer);
+ return (0);
+}
+
+/* **************************************************************** */
+/* */
+/* Parser Directives */
+/* */
+/* **************************************************************** */
+
+/* Conditionals. */
+
+/* Calling programs set this to have their argv[0]. */
+char *rl_readline_name = "other";
+
+/* Stack of previous values of parsing_conditionalized_out. */
+static unsigned char *if_stack = (unsigned char *)NULL;
+static int if_stack_depth = 0;
+static int if_stack_size = 0;
+
+/* Push _rl_parsing_conditionalized_out, and set parser state based
+ on ARGS. */
+static int
+parser_if (args)
+ char *args;
+{
+ register int i;
+
+ /* Push parser state. */
+ if (if_stack_depth + 1 >= if_stack_size)
+ {
+ if (!if_stack)
+ if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
+ else
+ if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
+ }
+ if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out;
+
+ /* If parsing is turned off, then nothing can turn it back on except
+ for finding the matching endif. In that case, return right now. */
+ if (_rl_parsing_conditionalized_out)
+ return 0;
+
+ /* Isolate first argument. */
+ for (i = 0; args[i] && !whitespace (args[i]); i++);
+
+ if (args[i])
+ args[i++] = '\0';
+
+ /* Handle "if term=foo" and "if mode=emacs" constructs. If this
+ isn't term=foo, or mode=emacs, then check to see if the first
+ word in ARGS is the same as the value stored in rl_readline_name. */
+ if (rl_terminal_name && strnicmp (args, "term=", 5) == 0)
+ {
+ char *tem, *tname;
+
+ /* Terminals like "aaa-60" are equivalent to "aaa". */
+ tname = savestring (rl_terminal_name);
+ tem = strchr (tname, '-');
+ if (tem)
+ *tem = '\0';
+
+ /* Test the `long' and `short' forms of the terminal name so that
+ if someone has a `sun-cmd' and does not want to have bindings
+ that will be executed if the terminal is a `sun', they can put
+ `$if term=sun-cmd' into their .inputrc. */
+ if ((stricmp (args + 5, tname) == 0) ||
+ (stricmp (args + 5, rl_terminal_name) == 0))
+ _rl_parsing_conditionalized_out = 0;
+ else
+ _rl_parsing_conditionalized_out = 1;
+
+ free (tname);
+ }
+#if defined (VI_MODE)
+ else if (strnicmp (args, "mode=", 5) == 0)
+ {
+ int mode;
+
+ if (stricmp (args + 5, "emacs") == 0)
+ mode = emacs_mode;
+ else if (stricmp (args + 5, "vi") == 0)
+ mode = vi_mode;
+ else
+ mode = no_mode;
+
+ if (mode == rl_editing_mode)
+ _rl_parsing_conditionalized_out = 0;
+ else
+ _rl_parsing_conditionalized_out = 1;
+ }
+#endif /* VI_MODE */
+ /* Check to see if the first word in ARGS is the same as the
+ value stored in rl_readline_name. */
+ else if (stricmp (args, rl_readline_name) == 0)
+ _rl_parsing_conditionalized_out = 0;
+ else
+ _rl_parsing_conditionalized_out = 1;
+ return 0;
+}
+
+/* Invert the current parser state if there is anything on the stack. */
+static int
+parser_else (args)
+ char *args;
+{
+ register int i;
+
+ if (!if_stack_depth)
+ {
+ /* Error message? */
+ return 0;
+ }
+
+ /* Check the previous (n - 1) levels of the stack to make sure that
+ we haven't previously turned off parsing. */
+ for (i = 0; i < if_stack_depth - 1; i++)
+ if (if_stack[i] == 1)
+ return 0;
+
+ /* Invert the state of parsing if at top level. */
+ _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out;
+ return 0;
+}
+
+/* Terminate a conditional, popping the value of
+ _rl_parsing_conditionalized_out from the stack. */
+static int
+parser_endif (args)
+ char *args;
+{
+ if (if_stack_depth)
+ _rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
+ else
+ {
+ /* *** What, no error message? *** */
+ }
+ return 0;
+}
+
+/* Associate textual names with actual functions. */
+static struct {
+ char *name;
+ Function *function;
+} parser_directives [] = {
+ { "if", parser_if },
+ { "endif", parser_endif },
+ { "else", parser_else },
+ { (char *)0x0, (Function *)0x0 }
+};
+
+/* Handle a parser directive. STATEMENT is the line of the directive
+ without any leading `$'. */
+static int
+handle_parser_directive (statement)
+ char *statement;
+{
+ register int i;
+ char *directive, *args;
+
+ /* Isolate the actual directive. */
+
+ /* Skip whitespace. */
+ for (i = 0; whitespace (statement[i]); i++);
+
+ directive = &statement[i];
+
+ for (; statement[i] && !whitespace (statement[i]); i++);
+
+ if (statement[i])
+ statement[i++] = '\0';
+
+ for (; statement[i] && whitespace (statement[i]); i++);
+
+ args = &statement[i];
+
+ /* Lookup the command, and act on it. */
+ for (i = 0; parser_directives[i].name; i++)
+ if (stricmp (directive, parser_directives[i].name) == 0)
+ {
+ (*parser_directives[i].function) (args);
+ return (0);
+ }
+
+ /* *** Should an error message be output? */
+ return (1);
+}
+
+static int substring_member_of_array ();
+
+/* Read the binding command from STRING and perform it.
+ A key binding command looks like: Keyname: function-name\0,
+ a variable binding command looks like: set variable value.
+ A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
+rl_parse_and_bind (string)
+ char *string;
+{
+ char *funname, *kname;
+ register int c, i;
+ int key, equivalency;
+
+ while (string && whitespace (*string))
+ string++;
+
+ if (!string || !*string || *string == '#')
+ return 0;
+
+ /* If this is a parser directive, act on it. */
+ if (*string == '$')
+ {
+ handle_parser_directive (&string[1]);
+ return 0;
+ }
+
+ /* If we aren't supposed to be parsing right now, then we're done. */
+ if (_rl_parsing_conditionalized_out)
+ return 0;
+
+ i = 0;
+ /* If this keyname is a complex key expression surrounded by quotes,
+ advance to after the matching close quote. This code allows the
+ backslash to quote characters in the key expression. */
+ if (*string == '"')
+ {
+ int passc = 0;
+
+ for (i = 1; c = string[i]; i++)
+ {
+ if (passc)
+ {
+ passc = 0;
+ continue;
+ }
+
+ if (c == '\\')
+ {
+ passc++;
+ continue;
+ }
+
+ if (c == '"')
+ break;
+ }
+ }
+
+ /* Advance to the colon (:) or whitespace which separates the two objects. */
+ for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
+
+ equivalency = (c == ':' && string[i + 1] == '=');
+
+ /* Mark the end of the command (or keyname). */
+ if (string[i])
+ string[i++] = '\0';
+
+ /* If doing assignment, skip the '=' sign as well. */
+ if (equivalency)
+ string[i++] = '\0';
+
+ /* If this is a command to set a variable, then do that. */
+ if (stricmp (string, "set") == 0)
+ {
+ char *var = string + i;
+ char *value;
+
+ /* Make VAR point to start of variable name. */
+ while (*var && whitespace (*var)) var++;
+
+ /* Make value point to start of value string. */
+ value = var;
+ while (*value && !whitespace (*value)) value++;
+ if (*value)
+ *value++ = '\0';
+ while (*value && whitespace (*value)) value++;
+
+ rl_variable_bind (var, value);
+ return 0;
+ }
+
+ /* Skip any whitespace between keyname and funname. */
+ for (; string[i] && whitespace (string[i]); i++);
+ funname = &string[i];
+
+ /* Now isolate funname.
+ For straight function names just look for whitespace, since
+ that will signify the end of the string. But this could be a
+ macro definition. In that case, the string is quoted, so skip
+ to the matching delimiter. We allow the backslash to quote the
+ delimiter characters in the macro body. */
+ /* This code exists to allow whitespace in macro expansions, which
+ would otherwise be gobbled up by the next `for' loop.*/
+ /* XXX - it may be desirable to allow backslash quoting only if " is
+ the quoted string delimiter, like the shell. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ int delimiter = string[i++];
+ int passc = 0;
+
+ for (; c = string[i]; i++)
+ {
+ if (passc)
+ {
+ passc = 0;
+ continue;
+ }
+
+ if (c == '\\')
+ {
+ passc = 1;
+ continue;
+ }
+
+ if (c == delimiter)
+ break;
+ }
+ if (c)
+ i++;
+ }
+
+ /* Advance to the end of the string. */
+ for (; string[i] && !whitespace (string[i]); i++);
+
+ /* No extra whitespace at the end of the string. */
+ string[i] = '\0';
+
+ /* Handle equivalency bindings here. Make the left-hand side be exactly
+ whatever the right-hand evaluates to, including keymaps. */
+ if (equivalency)
+ {
+ return 0;
+ }
+
+ /* If this is a new-style key-binding, then do the binding with
+ rl_set_key (). Otherwise, let the older code deal with it. */
+ if (*string == '"')
+ {
+ char *seq = xmalloc (1 + strlen (string));
+ register int j, k = 0;
+ int passc = 0;
+
+ for (j = 1; string[j]; j++)
+ {
+ /* Allow backslash to quote characters, but leave them in place.
+ This allows a string to end with a backslash quoting another
+ backslash, or with a backslash quoting a double quote. The
+ backslashes are left in place for rl_translate_keyseq (). */
+ if (passc || (string[j] == '\\'))
+ {
+ seq[k++] = string[j];
+ passc = !passc;
+ continue;
+ }
+
+ if (string[j] == '"')
+ break;
+
+ seq[k++] = string[j];
+ }
+ seq[k] = '\0';
+
+ /* Binding macro? */
+ if (*funname == '\'' || *funname == '"')
+ {
+ j = strlen (funname);
+
+ /* Remove the delimiting quotes from each end of FUNNAME. */
+ if (j && funname[j - 1] == *funname)
+ funname[j - 1] = '\0';
+
+ rl_macro_bind (seq, &funname[1], _rl_keymap);
+ }
+ else
+ rl_set_key (seq, rl_named_function (funname), _rl_keymap);
+
+ free (seq);
+ return 0;
+ }
+
+ /* Get the actual character we want to deal with. */
+ kname = strrchr (string, '-');
+ if (!kname)
+ kname = string;
+ else
+ kname++;
+
+ key = glean_key_from_name (kname);
+
+ /* Add in control and meta bits. */
+ if (substring_member_of_array (string, possible_control_prefixes))
+ key = CTRL (to_upper (key));
+
+ if (substring_member_of_array (string, possible_meta_prefixes))
+ key = META (key);
+
+ /* Temporary. Handle old-style keyname with macro-binding. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ char seq[2];
+ int fl = strlen (funname);
+
+ seq[0] = key; seq[1] = '\0';
+ if (fl && funname[fl - 1] == *funname)
+ funname[fl - 1] = '\0';
+
+ rl_macro_bind (seq, &funname[1], _rl_keymap);
+ }
+#if defined (PREFIX_META_HACK)
+ /* Ugly, but working hack to keep prefix-meta around. */
+ else if (stricmp (funname, "prefix-meta") == 0)
+ {
+ char seq[2];
+
+ seq[0] = key;
+ seq[1] = '\0';
+ rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap);
+ }
+#endif /* PREFIX_META_HACK */
+ else
+ rl_bind_key (key, rl_named_function (funname));
+ return 0;
+}
+
+/* Simple structure for boolean readline variables (i.e., those that can
+ have one of two values; either "On" or 1 for truth, or "Off" or 0 for
+ false. */
+
+static struct {
+ char *name;
+ int *value;
+} boolean_varlist [] = {
+ { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode },
+ { "mark-modified-lines", &_rl_mark_modified_lines },
+ { "meta-flag", &_rl_meta_flag },
+ { "blink-matching-paren", &rl_blink_matching_paren },
+ { "convert-meta", &_rl_convert_meta_chars_to_ascii },
+ { "show-all-if-ambiguous", &_rl_complete_show_all },
+ { "output-meta", &_rl_output_meta_chars },
+#if defined (VISIBLE_STATS)
+ { "visible-stats", &rl_visible_stats },
+#endif /* VISIBLE_STATS */
+ { "expand-tilde", &rl_complete_with_tilde_expansion },
+ { (char *)NULL, (int *)NULL }
+};
+
+rl_variable_bind (name, value)
+ char *name, *value;
+{
+ register int i;
+
+ /* Check for simple variables first. */
+ for (i = 0; boolean_varlist[i].name; i++)
+ {
+ if (stricmp (name, boolean_varlist[i].name) == 0)
+ {
+ /* A variable is TRUE if the "value" is "on", "1" or "". */
+ if ((!*value) ||
+ (stricmp (value, "On") == 0) ||
+ (value[0] == '1' && value[1] == '\0'))
+ *boolean_varlist[i].value = 1;
+ else
+ *boolean_varlist[i].value = 0;
+ return 0;
+ }
+ }
+
+ /* Not a boolean variable, so check for specials. */
+
+ /* Editing mode change? */
+ if (stricmp (name, "editing-mode") == 0)
+ {
+ if (strnicmp (value, "vi", 2) == 0)
+ {
+#if defined (VI_MODE)
+ _rl_keymap = vi_insertion_keymap;
+ rl_editing_mode = vi_mode;
+#endif /* VI_MODE */
+ }
+ else if (strnicmp (value, "emacs", 5) == 0)
+ {
+ _rl_keymap = emacs_standard_keymap;
+ rl_editing_mode = emacs_mode;
+ }
+ }
+
+ /* Comment string change? */
+ else if (stricmp (name, "comment-begin") == 0)
+ {
+#if defined (VI_MODE)
+ if (*value)
+ {
+ if (rl_vi_comment_begin)
+ free (rl_vi_comment_begin);
+
+ rl_vi_comment_begin = savestring (value);
+ }
+#endif /* VI_MODE */
+ }
+ else if (stricmp (name, "completion-query-items") == 0)
+ {
+ int nval = 100;
+ if (*value)
+ {
+ nval = atoi (value);
+ if (nval < 0)
+ nval = 0;
+ }
+ rl_completion_query_items = nval;
+ }
+ else if (stricmp (name, "keymap") == 0)
+ {
+ Keymap kmap;
+ kmap = rl_get_keymap_by_name (value);
+ if (kmap)
+ rl_set_keymap (kmap);
+ }
+ else if (stricmp (name, "bell-style") == 0)
+ {
+ if (!*value)
+ _rl_bell_preference = AUDIBLE_BELL;
+ else
+ {
+ if (stricmp (value, "none") == 0 || stricmp (value, "off") == 0)
+ _rl_bell_preference = NO_BELL;
+ else if (stricmp (value, "audible") == 0 || stricmp (value, "on") == 0)
+ _rl_bell_preference = AUDIBLE_BELL;
+ else if (stricmp (value, "visible") == 0)
+ _rl_bell_preference = VISIBLE_BELL;
+ }
+ }
+ else if (stricmp (name, "prefer-visible-bell") == 0)
+ {
+ /* Backwards compatibility. */
+ if (*value && (stricmp (value, "on") == 0 ||
+ (*value == '1' && !value[1])))
+ _rl_bell_preference = VISIBLE_BELL;
+ else
+ _rl_bell_preference = AUDIBLE_BELL;
+ }
+
+ return 0;
+}
+
+/* Return the character which matches NAME.
+ For example, `Space' returns ' '. */
+
+typedef struct {
+ char *name;
+ int value;
+} assoc_list;
+
+static assoc_list name_key_alist[] = {
+ { "DEL", 0x7f },
+ { "ESC", '\033' },
+ { "Escape", '\033' },
+ { "LFD", '\n' },
+ { "Newline", '\n' },
+ { "RET", '\r' },
+ { "Return", '\r' },
+ { "Rubout", 0x7f },
+ { "SPC", ' ' },
+ { "Space", ' ' },
+ { "Tab", 0x09 },
+ { (char *)0x0, 0 }
+};
+
+static int
+glean_key_from_name (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; name_key_alist[i].name; i++)
+ if (stricmp (name, name_key_alist[i].name) == 0)
+ return (name_key_alist[i].value);
+
+ return (*(unsigned char *)name); /* XXX was return (*name) */
+}
+
+/* Auxiliary functions to manage keymaps. */
+static struct {
+ char *name;
+ Keymap map;
+} keymap_names[] = {
+ { "emacs", emacs_standard_keymap },
+ { "emacs-standard", emacs_standard_keymap },
+ { "emacs-meta", emacs_meta_keymap },
+ { "emacs-ctlx", emacs_ctlx_keymap },
+#if defined (VI_MODE)
+ { "vi", vi_movement_keymap },
+ { "vi-move", vi_movement_keymap },
+ { "vi-command", vi_movement_keymap },
+ { "vi-insert", vi_insertion_keymap },
+#endif /* VI_MODE */
+ { (char *)0x0, (Keymap)0x0 }
+};
+
+Keymap
+rl_get_keymap_by_name (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; keymap_names[i].name; i++)
+ if (strcmp (name, keymap_names[i].name) == 0)
+ return (keymap_names[i].map);
+ return ((Keymap) NULL);
+}
+
+void
+rl_set_keymap (map)
+ Keymap map;
+{
+ if (map)
+ _rl_keymap = map;
+}
+
+Keymap
+rl_get_keymap ()
+{
+ return (_rl_keymap);
+}
+
+void
+rl_set_keymap_from_edit_mode ()
+{
+ if (rl_editing_mode == emacs_mode)
+ _rl_keymap = emacs_standard_keymap;
+#if defined (VI_MODE)
+ else if (rl_editing_mode == vi_mode)
+ _rl_keymap = vi_insertion_keymap;
+#endif /* VI_MODE */
+}
+
+/* **************************************************************** */
+/* */
+/* Key Binding and Function Information */
+/* */
+/* **************************************************************** */
+
+/* Each of the following functions produces information about the
+ state of keybindings and functions known to Readline. The info
+ is always printed to rl_outstream, and in such a way that it can
+ be read back in (i.e., passed to rl_parse_and_bind (). */
+
+/* Print the names of functions known to Readline. */
+void
+rl_list_funmap_names (ignore)
+ int ignore;
+{
+ register int i;
+ char **funmap_names;
+
+ funmap_names = rl_funmap_names ();
+
+ if (!funmap_names)
+ return;
+
+ for (i = 0; funmap_names[i]; i++)
+ fprintf (rl_outstream, "%s\n", funmap_names[i]);
+
+ free (funmap_names);
+}
+
+/* Return a NULL terminated array of strings which represent the key
+ sequences that are used to invoke FUNCTION in MAP. */
+char **
+rl_invoking_keyseqs_in_map (function, map)
+ Function *function;
+ Keymap map;
+{
+ register int key;
+ char **result;
+ int result_index, result_size;
+
+ result = (char **)NULL;
+ result_index = result_size = 0;
+
+ for (key = 0; key < 128; key++)
+ {
+ switch (map[key].type)
+ {
+ case ISMACR:
+ /* Macros match, if, and only if, the pointers are identical.
+ Thus, they are treated exactly like functions in here. */
+ case ISFUNC:
+ /* If the function in the keymap is the one we are looking for,
+ then add the current KEY to the list of invoking keys. */
+ if (map[key].function == function)
+ {
+ char *keyname = (char *)xmalloc (5);
+
+ if (CTRL_P (key))
+ sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
+ else if (key == RUBOUT)
+ sprintf (keyname, "\\C-?");
+ else if (key == '\\' || key == '"')
+ {
+ keyname[0] = '\\';
+ keyname[1] = (char) key;
+ keyname[2] = '\0';
+ }
+ else
+ {
+ keyname[0] = (char) key;
+ keyname[1] = '\0';
+ }
+
+ if (result_index + 2 > result_size)
+ result = (char **) xrealloc
+ (result, (result_size += 10) * sizeof (char *));
+
+ result[result_index++] = keyname;
+ result[result_index] = (char *)NULL;
+ }
+ break;
+
+ case ISKMAP:
+ {
+ char **seqs = (char **)NULL;
+
+ /* Find the list of keyseqs in this map which have FUNCTION as
+ their target. Add the key sequences found to RESULT. */
+ if (map[key].function)
+ seqs =
+ rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key));
+
+ if (seqs)
+ {
+ register int i;
+
+ for (i = 0; seqs[i]; i++)
+ {
+ char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
+
+ if (key == ESC)
+ sprintf (keyname, "\\e");
+ else if (CTRL_P (key))
+ sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
+ else if (key == RUBOUT)
+ sprintf (keyname, "\\C-?");
+ else if (key == '\\' || key == '"')
+ {
+ keyname[0] = '\\';
+ keyname[1] = (char) key;
+ keyname[2] = '\0';
+ }
+ else
+ {
+ keyname[0] = (char) key;
+ keyname[1] = '\0';
+ }
+
+ strcat (keyname, seqs[i]);
+ free (seqs[i]);
+
+ if (result_index + 2 > result_size)
+ result = (char **) xrealloc
+ (result, (result_size += 10) * sizeof (char *));
+
+ result[result_index++] = keyname;
+ result[result_index] = (char *)NULL;
+ }
+
+ free (seqs);
+ }
+ }
+ break;
+ }
+ }
+ return (result);
+}
+
+/* Return a NULL terminated array of strings which represent the key
+ sequences that can be used to invoke FUNCTION using the current keymap. */
+char **
+rl_invoking_keyseqs (function)
+ Function *function;
+{
+ return (rl_invoking_keyseqs_in_map (function, _rl_keymap));
+}
+
+/* Print all of the current functions and their bindings to
+ rl_outstream. If an explicit argument is given, then print
+ the output in such a way that it can be read back in. */
+int
+rl_dump_functions (count, key)
+ int count, key;
+{
+ rl_function_dumper (rl_explicit_arg);
+ rl_on_new_line ();
+ return (0);
+}
+
+/* Print all of the functions and their bindings to rl_outstream. If
+ PRINT_READABLY is non-zero, then print the output in such a way
+ that it can be read back in. */
+void
+rl_function_dumper (print_readably)
+ int print_readably;
+{
+ register int i;
+ char **names;
+ char *name;
+
+ names = rl_funmap_names ();
+
+ fprintf (rl_outstream, "\n");
+
+ for (i = 0; name = names[i]; i++)
+ {
+ Function *function;
+ char **invokers;
+
+ function = rl_named_function (name);
+ invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap);
+
+ if (print_readably)
+ {
+ if (!invokers)
+ fprintf (rl_outstream, "# %s (not bound)\n", name);
+ else
+ {
+ register int j;
+
+ for (j = 0; invokers[j]; j++)
+ {
+ fprintf (rl_outstream, "\"%s\": %s\n",
+ invokers[j], name);
+ free (invokers[j]);
+ }
+
+ free (invokers);
+ }
+ }
+ else
+ {
+ if (!invokers)
+ fprintf (rl_outstream, "%s is not bound to any keys\n",
+ name);
+ else
+ {
+ register int j;
+
+ fprintf (rl_outstream, "%s can be found on ", name);
+
+ for (j = 0; invokers[j] && j < 5; j++)
+ {
+ fprintf (rl_outstream, "\"%s\"%s", invokers[j],
+ invokers[j + 1] ? ", " : ".\n");
+ }
+
+ if (j == 5 && invokers[j])
+ fprintf (rl_outstream, "...\n");
+
+ for (j = 0; invokers[j]; j++)
+ free (invokers[j]);
+
+ free (invokers);
+ }
+ }
+ }
+}
+
+/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */
+void
+_rl_bind_if_unbound (keyseq, default_func)
+ char *keyseq;
+ Function *default_func;
+{
+ Function *func;
+
+ if (keyseq)
+ {
+ func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL);
+ if (!func || func == rl_do_lowercase_version)
+ rl_set_key (keyseq, default_func, _rl_keymap);
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* String Utility Functions */
+/* */
+/* **************************************************************** */
+
+static char *strindex ();
+
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+ char *string, **array;
+{
+ while (*array)
+ {
+ if (strindex (string, *array))
+ return (1);
+ array++;
+ }
+ return (0);
+}
+
+#if !defined (BSD386) && !defined (NetBSD) && \
+ !defined (FreeBSD) && !defined (_386BSD)
+/* Whoops, Unix doesn't have strnicmp. */
+
+/* Compare at most COUNT characters from string1 to string2. Case
+ doesn't matter. */
+static int
+strnicmp (string1, string2, count)
+ char *string1, *string2;
+ int count;
+{
+ register char ch1, ch2;
+
+ while (count)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (to_upper(ch1) == to_upper(ch2))
+ count--;
+ else break;
+ }
+ return (count);
+}
+
+/* strcmp (), but caseless. */
+static int
+stricmp (string1, string2)
+ char *string1, *string2;
+{
+ register char ch1, ch2;
+
+ while (*string1 && *string2)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (to_upper(ch1) != to_upper(ch2))
+ return (1);
+ }
+ return (*string1 | *string2);
+}
+#endif
+
+/* Determine if s2 occurs in s1. If so, return a pointer to the
+ match in s1. The compare is case insensitive. */
+static char *
+strindex (s1, s2)
+ register char *s1, *s2;
+{
+ register int i, l = strlen (s2);
+ register int len = strlen (s1);
+
+ for (i = 0; (len - i) >= l; i++)
+ if (strnicmp (&s1[i], s2, l) == 0)
+ return (s1 + i);
+ return ((char *)NULL);
+}
diff --git a/gnu/lib/libreadline/complete.c b/gnu/lib/libreadline/complete.c
new file mode 100644
index 000000000000..037222db64b1
--- /dev/null
+++ b/gnu/lib/libreadline/complete.c
@@ -0,0 +1,1381 @@
+/* complete.c -- filename completion for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+# include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include <pwd.h>
+#if defined (USG) && !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwent ();
+#endif /* USG && !HAVE_GETPW_DECLS */
+
+/* ISC systems don't define getpwent() if _POSIX_SOURCE is defined. */
+#if defined (isc386) && defined (_POSIX_SOURCE)
+# if defined (__STDC__)
+extern struct passwd *getpwent (void);
+# else
+extern struct passwd *getpwent ();
+# endif /* !__STDC__ */
+#endif /* isc386 && _POSIX_SOURCE */
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include <readline/readline.h>
+
+/* Possible values for do_replace in rl_complete_internal. */
+#define NO_MATCH 0
+#define SINGLE_MATCH 1
+#define MULT_MATCH 2
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+extern char *tilde_expand ();
+extern char *rl_copy_text ();
+
+extern Function *rl_last_func;
+extern int rl_editing_mode;
+extern int screenwidth;
+
+/* Forward declarations for functions defined and used in this file. */
+char *filename_completion_function ();
+char **completion_matches ();
+
+static int compare_strings ();
+static char *rl_strpbrk ();
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+/* If non-zero, then this is the address of a function to call when
+ completing on a directory name. The function is called with
+ the address of a string (the current directory name) as an arg. */
+Function *rl_directory_completion_hook = (Function *)NULL;
+
+/* Non-zero means readline completion functions perform tilde expansion. */
+int rl_complete_with_tilde_expansion = 0;
+
+/* If non-zero, non-unique completions always show the list of matches. */
+int _rl_complete_show_all = 0;
+
+#if defined (VISIBLE_STATS)
+# if !defined (X_OK)
+# define X_OK 1
+# endif
+
+static int stat_char ();
+
+/* Non-zero means add an additional character to each filename displayed
+ during listing completion iff rl_filename_completion_desired which helps
+ to indicate the type of file being listed. */
+int rl_visible_stats = 0;
+#endif /* VISIBLE_STATS */
+
+/* **************************************************************** */
+/* */
+/* Completion matching, from readline's point of view. */
+/* */
+/* **************************************************************** */
+
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_entry_function (), the default filename
+ completer. */
+Function *rl_completion_entry_function = (Function *)NULL;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+CPPFunction *rl_attempted_completion_function = (CPPFunction *)NULL;
+
+/* Non-zero means to suppress normal filename completion after the
+ user-specified completion function has been called. */
+int rl_attempted_completion_over = 0;
+
+/* Local variable states what happened during the last completion attempt. */
+static int completion_changed_buffer = 0;
+
+/* Complete the word at or before point. You have supplied the function
+ that does the initial simple matching selection algorithm (see
+ completion_matches ()). The default is to do filename completion. */
+
+rl_complete (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ if (rl_last_func == rl_complete && !completion_changed_buffer)
+ return (rl_complete_internal ('?'));
+ else if (_rl_complete_show_all)
+ return (rl_complete_internal ('!'));
+ else
+ return (rl_complete_internal (TAB));
+}
+
+/* List the possible completions. See description of rl_complete (). */
+rl_possible_completions (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ return (rl_complete_internal ('?'));
+}
+
+rl_insert_completions (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ return (rl_complete_internal ('*'));
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed. */
+get_y_or_n ()
+{
+ int c;
+
+ for (;;)
+ {
+ c = rl_read_key ();
+ if (c == 'y' || c == 'Y' || c == ' ')
+ return (1);
+ if (c == 'n' || c == 'N' || c == RUBOUT)
+ return (0);
+ if (c == ABORT_CHAR)
+ rl_abort ();
+ ding ();
+ }
+}
+
+/* Up to this many items will be displayed in response to a
+ possible-completions call. After that, we ask the user if
+ she is sure she wants to see them all. */
+int rl_completion_query_items = 100;
+
+/* The basic list of characters that signal a break between words for the
+ completer routine. The contents of this variable is what breaks words
+ in the shell, i.e. " \t\n\"\\'`@$><=" */
+char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
+
+/* The list of characters that signal a break between words for
+ rl_complete_internal. The default list is the contents of
+ rl_basic_word_break_characters. */
+char *rl_completer_word_break_characters = (char *)NULL;
+
+/* List of characters which can be used to quote a substring of the line.
+ Completion occurs on the entire substring, and within the substring
+ rl_completer_word_break_characters are treated as any other character,
+ unless they also appear within this list. */
+char *rl_completer_quote_characters = (char *)NULL;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+char *rl_special_prefixes = (char *)NULL;
+
+/* If non-zero, then disallow duplicates in the matches. */
+int rl_ignore_completion_duplicates = 1;
+
+/* Non-zero means that the results of the matches are to be treated
+ as filenames. This is ALWAYS zero on entry, and can only be changed
+ within a completion entry finder function. */
+int rl_filename_completion_desired = 0;
+
+/* This function, if defined, is called by the completer when real
+ filename completion is done, after all the matching names have been
+ generated. It is passed a (char**) known as matches in the code below.
+ It consists of a NULL-terminated array of pointers to potential
+ matching strings. The 1st element (matches[0]) is the maximal
+ substring that is common to all matches. This function can re-arrange
+ the list of matches as required, but all elements of the array must be
+ free()'d if they are deleted. The main intent of this function is
+ to implement FIGNORE a la SunOS csh. */
+Function *rl_ignore_some_completions_function = (Function *)NULL;
+
+#if defined (SHELL)
+/* A function to strip quotes that are not protected by backquotes. It
+ allows single quotes to appear within double quotes, and vice versa.
+ It should be smarter. It's fairly shell-specific, hence the SHELL
+ definition wrapper. */
+static char *
+_delete_quotes (text)
+ char *text;
+{
+ char *ret, *p, *r;
+ int l, quoted;
+
+ l = strlen (text);
+ ret = xmalloc (l + 1);
+ for (quoted = 0, p = text, r = ret; p && *p; p++)
+ {
+ /* Allow backslash-quoted characters to pass through unscathed. */
+ if (*p == '\\')
+ continue;
+ /* Close quote. */
+ if (quoted && *p == quoted)
+ {
+ quoted = 0;
+ continue;
+ }
+ /* Open quote. */
+ if (quoted == 0 && (*p == '\'' || *p == '"'))
+ {
+ quoted = *p;
+ continue;
+ }
+ *r++ = *p;
+ }
+ *r = '\0';
+ return ret;
+}
+#endif /* SHELL */
+
+/* Return the portion of PATHNAME that should be output when listing
+ possible completions. If we are hacking filename completion, we
+ are only interested in the basename, the portion following the
+ final slash. Otherwise, we return what we were passed. */
+static char *
+printable_part (pathname)
+ char *pathname;
+{
+ char *temp = (char *)NULL;
+
+ if (rl_filename_completion_desired)
+ temp = strrchr (pathname, '/');
+
+ if (!temp)
+ return (pathname);
+ else
+ return (++temp);
+}
+
+/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we
+ are using it, check for and output a single character for `special'
+ filenames. Return 1 if we printed an extension character, 0 if not. */
+static int
+print_filename (to_print, full_pathname)
+ char *to_print, *full_pathname;
+{
+#if !defined (VISIBLE_STATS)
+ fputs (to_print, rl_outstream);
+ return 0;
+#else
+ char *s, c, *new_full_pathname;
+ int extension_char = 0, slen, tlen;
+
+ fputs (to_print, rl_outstream);
+ if (rl_filename_completion_desired && rl_visible_stats)
+ {
+ /* If to_print != full_pathname, to_print is the basename of the
+ path passed. In this case, we try to expand the directory
+ name before checking for the stat character. */
+ if (to_print != full_pathname)
+ {
+ /* Terminate the directory name. */
+ c = to_print[-1];
+ to_print[-1] = '\0';
+
+ s = tilde_expand (full_pathname);
+ if (rl_directory_completion_hook)
+ (*rl_directory_completion_hook) (&s);
+
+ slen = strlen (s);
+ tlen = strlen (to_print);
+ new_full_pathname = xmalloc (slen + tlen + 2);
+ strcpy (new_full_pathname, s);
+ new_full_pathname[slen] = '/';
+ strcpy (new_full_pathname + slen + 1, to_print);
+
+ extension_char = stat_char (new_full_pathname);
+
+ free (new_full_pathname);
+ to_print[-1] = c;
+ }
+ else
+ {
+ s = tilde_expand (full_pathname);
+ extension_char = stat_char (s);
+ }
+
+ free (s);
+ if (extension_char)
+ putc (extension_char, rl_outstream);
+ return (extension_char != 0);
+ }
+ else
+ return 0;
+#endif /* VISIBLE_STATS */
+}
+
+/* Complete the word at or before point.
+ WHAT_TO_DO says what to do with the completion.
+ `?' means list the possible completions.
+ TAB means do standard completion.
+ `*' means insert all of the possible completions.
+ `!' means to do standard completion, and list all possible completions if
+ there is more than one. */
+rl_complete_internal (what_to_do)
+ int what_to_do;
+{
+ char **matches;
+ Function *our_func;
+ int start, scan, end, delimiter = 0, pass_next;
+ char *text, *saved_line_buffer;
+ char *replacement;
+ char quote_char = '\0';
+#if defined (SHELL)
+ int found_quote = 0;
+#endif
+
+ if (rl_line_buffer)
+ saved_line_buffer = savestring (rl_line_buffer);
+ else
+ saved_line_buffer = (char *)NULL;
+
+ if (rl_completion_entry_function)
+ our_func = rl_completion_entry_function;
+ else
+ our_func = (Function *)filename_completion_function;
+
+ /* Only the completion entry function can change this. */
+ rl_filename_completion_desired = 0;
+
+ /* We now look backwards for the start of a filename/variable word. */
+ end = rl_point;
+
+ if (rl_point)
+ {
+ if (rl_completer_quote_characters)
+ {
+ /* We have a list of characters which can be used in pairs to
+ quote substrings for the completer. Try to find the start
+ of an unclosed quoted substring. */
+ /* FOUND_QUOTE is set so we know what kind of quotes we found. */
+ for (scan = pass_next = 0; scan < end; scan++)
+ {
+ if (pass_next)
+ {
+ pass_next = 0;
+ continue;
+ }
+
+ if (rl_line_buffer[scan] == '\\')
+ {
+ pass_next = 1;
+ continue;
+ }
+
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char. */
+ if (rl_line_buffer[scan] == quote_char)
+ {
+ /* Found matching close. Abandon this substring. */
+ quote_char = '\0';
+ rl_point = end;
+ }
+ }
+ else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan]))
+ {
+ /* Found start of a quoted substring. */
+ quote_char = rl_line_buffer[scan];
+ rl_point = scan + 1;
+#if defined (SHELL)
+ if (quote_char == '\'')
+ found_quote |= 1;
+ else if (quote_char == '"')
+ found_quote |= 2;
+#endif
+ }
+ }
+ }
+
+ if (rl_point == end)
+ {
+ int quoted = 0;
+ /* We didn't find an unclosed quoted substring up which to do
+ completion, so use the word break characters to find the
+ substring on which to complete. */
+ while (--rl_point)
+ {
+ scan = rl_line_buffer[rl_point];
+#if defined (SHELL)
+ /* Don't let word break characters in quoted substrings break
+ words for the completer. */
+ if (found_quote)
+ {
+ if (strchr (rl_completer_quote_characters, scan))
+ {
+ quoted = !quoted;
+ continue;
+ }
+ if (quoted)
+ continue;
+ }
+#endif /* SHELL */
+ if (strchr (rl_completer_word_break_characters, scan))
+ break;
+ }
+ }
+
+ /* If we are at a word break, then advance past it. */
+ scan = rl_line_buffer[rl_point];
+ if (strchr (rl_completer_word_break_characters, scan))
+ {
+ /* If the character that caused the word break was a quoting
+ character, then remember it as the delimiter. */
+ if (strchr ("\"'", scan) && (end - rl_point) > 1)
+ delimiter = scan;
+
+ /* If the character isn't needed to determine something special
+ about what kind of completion to perform, then advance past it. */
+ if (!rl_special_prefixes || strchr (rl_special_prefixes, scan) == 0)
+ rl_point++;
+ }
+ }
+
+ /* At this point, we know we have an open quote if quote_char != '\0'. */
+ start = rl_point;
+ rl_point = end;
+ text = rl_copy_text (start, end);
+
+ /* If the user wants to TRY to complete, but then wants to give
+ up and use the default completion function, they set the
+ variable rl_attempted_completion_function. */
+ if (rl_attempted_completion_function)
+ {
+ matches = (*rl_attempted_completion_function) (text, start, end);
+
+ if (matches || rl_attempted_completion_over)
+ {
+ rl_attempted_completion_over = 0;
+ our_func = (Function *)NULL;
+ goto after_usual_completion;
+ }
+ }
+
+#if defined (SHELL)
+ /* Beware -- we're stripping the quotes here. Do this only if we know
+ we are doing filename completion. */
+ if (found_quote && our_func == (Function *)filename_completion_function)
+ {
+ /* delete single and double quotes */
+ replacement = _delete_quotes (text);
+ free (text);
+ text = replacement;
+ replacement = (char *)0;
+ }
+#endif /* SHELL */
+
+ matches = completion_matches (text, our_func);
+
+ after_usual_completion:
+ free (text);
+
+ if (!matches)
+ ding ();
+ else
+ {
+ register int i;
+
+ /* It seems to me that in all the cases we handle we would like
+ to ignore duplicate possiblilities. Scan for the text to
+ insert being identical to the other completions. */
+ if (rl_ignore_completion_duplicates)
+ {
+ char *lowest_common;
+ int j, newlen = 0;
+ char dead_slot;
+ char **temp_array;
+
+ /* Sort the items. */
+ /* It is safe to sort this array, because the lowest common
+ denominator found in matches[0] will remain in place. */
+ for (i = 0; matches[i]; i++);
+ qsort (matches, i, sizeof (char *), compare_strings);
+
+ /* Remember the lowest common denominator for it may be unique. */
+ lowest_common = savestring (matches[0]);
+
+ for (i = 0; matches[i + 1]; i++)
+ {
+ if (strcmp (matches[i], matches[i + 1]) == 0)
+ {
+ free (matches[i]);
+ matches[i] = (char *)&dead_slot;
+ }
+ else
+ newlen++;
+ }
+
+ /* We have marked all the dead slots with (char *)&dead_slot.
+ Copy all the non-dead entries into a new array. */
+ temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *));
+ for (i = j = 1; matches[i]; i++)
+ {
+ if (matches[i] != (char *)&dead_slot)
+ temp_array[j++] = matches[i];
+ }
+ temp_array[j] = (char *)NULL;
+
+ if (matches[0] != (char *)&dead_slot)
+ free (matches[0]);
+ free (matches);
+
+ matches = temp_array;
+
+ /* Place the lowest common denominator back in [0]. */
+ matches[0] = lowest_common;
+
+ /* If there is one string left, and it is identical to the
+ lowest common denominator, then the LCD is the string to
+ insert. */
+ if (j == 2 && strcmp (matches[0], matches[1]) == 0)
+ {
+ free (matches[1]);
+ matches[1] = (char *)NULL;
+ }
+ }
+
+ switch (what_to_do)
+ {
+ case TAB:
+ case '!':
+ /* If we are matching filenames, then here is our chance to
+ do clever processing by re-examining the list. Call the
+ ignore function with the array as a parameter. It can
+ munge the array, deleting matches as it desires. */
+ if (rl_ignore_some_completions_function &&
+ our_func == (Function *)filename_completion_function)
+ (void)(*rl_ignore_some_completions_function)(matches);
+
+ /* If we are doing completion on quoted substrings, and any matches
+ contain any of the completer_word_break_characters, then auto-
+ matically prepend the substring with a quote character (just pick
+ the first one from the list of such) if it does not already begin
+ with a quote string. FIXME: Need to remove any such automatically
+ inserted quote character when it no longer is necessary, such as
+ if we change the string we are completing on and the new set of
+ matches don't require a quoted substring. */
+ replacement = matches[0];
+
+ if (matches[0] && rl_completer_quote_characters && !quote_char &&
+ rl_filename_completion_desired)
+ {
+ int do_replace;
+
+ do_replace = NO_MATCH;
+
+ /* If there is a single match, see if we need to quote it.
+ This also checks whether the common prefix of several
+ matches needs to be quoted. If the common prefix should
+ not be checked, add !matches[1] to the if clause. */
+ if (rl_strpbrk (matches[0], rl_completer_word_break_characters)
+#if defined (SHELL)
+ || rl_strpbrk (matches[0], "$`")
+#endif
+ )
+ do_replace = matches[1] ? MULT_MATCH : SINGLE_MATCH;
+
+ if (do_replace != NO_MATCH)
+ {
+#if defined (SHELL)
+ /* XXX - experimental */
+ /* Quote the replacement, since we found an
+ embedded word break character in a potential
+ match. */
+ char *rtext, *mtext;
+ int rlen;
+ extern char *double_quote (); /* in builtins/common.c */
+
+ /* If DO_REPLACE == MULT_MATCH, it means that there is
+ more than one match. In this case, we do not add
+ the closing quote or attempt to perform tilde
+ expansion. If DO_REPLACE == SINGLE_MATCH, we try
+ to perform tilde expansion, because double quotes
+ inhibit tilde expansion by the shell. */
+
+ mtext = matches[0];
+ if (mtext[0] == '~' && do_replace == SINGLE_MATCH)
+ mtext = tilde_expand (matches[0]);
+ rtext = double_quote (mtext);
+ if (mtext != matches[0])
+ free (mtext);
+
+ rlen = strlen (rtext);
+ replacement = xmalloc (rlen + 1);
+ strcpy (replacement, rtext);
+ if (do_replace == MULT_MATCH)
+ replacement[rlen - 1] = '\0';
+ free (rtext);
+#else /* !SHELL */
+ /* Found an embedded word break character in a potential
+ match, so we need to prepend a quote character if we
+ are replacing the completion string. */
+ replacement = xmalloc (strlen (matches[0]) + 2);
+ quote_char = *rl_completer_quote_characters;
+ *replacement = quote_char;
+ strcpy (replacement + 1, matches[0]);
+#endif /* SHELL */
+ }
+ }
+
+ if (replacement)
+ {
+ rl_begin_undo_group ();
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ rl_insert_text (replacement);
+ rl_end_undo_group ();
+ if (replacement != matches[0])
+ free (replacement);
+ }
+
+ /* If there are more matches, ring the bell to indicate.
+ If this was the only match, and we are hacking files,
+ check the file to see if it was a directory. If so,
+ add a '/' to the name. If not, and we are at the end
+ of the line, then add a space. */
+ if (matches[1])
+ {
+ if (what_to_do == '!')
+ goto display_matches; /* XXX */
+ else if (rl_editing_mode != vi_mode)
+ ding (); /* There are other matches remaining. */
+ }
+ else
+ {
+ char temp_string[4];
+ int temp_string_index = 0;
+
+ if (quote_char)
+ temp_string[temp_string_index++] = quote_char;
+
+ temp_string[temp_string_index++] = delimiter ? delimiter : ' ';
+ temp_string[temp_string_index++] = '\0';
+
+ if (rl_filename_completion_desired)
+ {
+ struct stat finfo;
+ char *filename = tilde_expand (matches[0]);
+
+ if ((stat (filename, &finfo) == 0) && S_ISDIR (finfo.st_mode))
+ {
+ if (rl_line_buffer[rl_point] != '/')
+ rl_insert_text ("/");
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+ free (filename);
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+ }
+ break;
+
+ case '*':
+ {
+ int i = 1;
+
+ rl_begin_undo_group ();
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ if (matches[1])
+ {
+ while (matches[i])
+ {
+ rl_insert_text (matches[i++]);
+ rl_insert_text (" ");
+ }
+ }
+ else
+ {
+ rl_insert_text (matches[0]);
+ rl_insert_text (" ");
+ }
+ rl_end_undo_group ();
+ }
+ break;
+
+ case '?':
+ {
+ int len, count, limit, max;
+ int j, k, l;
+
+ /* Handle simple case first. What if there is only one answer? */
+ if (!matches[1])
+ {
+ char *temp;
+
+ temp = printable_part (matches[0]);
+ crlf ();
+ print_filename (temp, matches[0]);
+ crlf ();
+ goto restart;
+ }
+
+ /* There is more than one answer. Find out how many there are,
+ and find out what the maximum printed length of a single entry
+ is. */
+ display_matches:
+ for (max = 0, i = 1; matches[i]; i++)
+ {
+ char *temp;
+ int name_length;
+
+ temp = printable_part (matches[i]);
+ name_length = strlen (temp);
+
+ if (name_length > max)
+ max = name_length;
+ }
+
+ len = i - 1;
+
+ /* If there are many items, then ask the user if she
+ really wants to see them all. */
+ if (len >= rl_completion_query_items)
+ {
+ crlf ();
+ fprintf (rl_outstream,
+ "There are %d possibilities. Do you really", len);
+ crlf ();
+ fprintf (rl_outstream, "wish to see them all? (y or n)");
+ fflush (rl_outstream);
+ if (!get_y_or_n ())
+ {
+ crlf ();
+ goto restart;
+ }
+ }
+
+ /* How many items of MAX length can we fit in the screen window? */
+ max += 2;
+ limit = screenwidth / max;
+ if (limit != 1 && (limit * max == screenwidth))
+ limit--;
+
+ /* Avoid a possible floating exception. If max > screenwidth,
+ limit will be 0 and a divide-by-zero fault will result. */
+ if (limit == 0)
+ limit = 1;
+
+ /* How many iterations of the printing loop? */
+ count = (len + (limit - 1)) / limit;
+
+ /* Watch out for special case. If LEN is less than LIMIT, then
+ just do the inner printing loop. */
+ if (len < limit)
+ count = 1;
+
+ /* Sort the items if they are not already sorted. */
+ if (!rl_ignore_completion_duplicates)
+ qsort (matches, len, sizeof (char *), compare_strings);
+
+ /* Print the sorted items, up-and-down alphabetically, like
+ ls might. */
+ crlf ();
+
+ for (i = 1; i < count + 1; i++)
+ {
+ for (j = 0, l = i; j < limit; j++)
+ {
+ if (l > len || !matches[l])
+ break;
+ else
+ {
+ char *temp;
+ int printed_length;
+
+ temp = printable_part (matches[l]);
+ printed_length = strlen (temp);
+ printed_length += print_filename (temp, matches[l]);
+
+ if (j + 1 < limit)
+ {
+ for (k = 0; k < max - printed_length; k++)
+ putc (' ', rl_outstream);
+ }
+ }
+ l += count;
+ }
+ crlf ();
+ }
+ restart:
+
+ rl_on_new_line ();
+ }
+ break;
+
+ default:
+ fprintf (stderr, "\r\nreadline: bad value for what_to_do in rl_complete\n");
+ abort ();
+ }
+
+ for (i = 0; matches[i]; i++)
+ free (matches[i]);
+ free (matches);
+ }
+
+ /* Check to see if the line has changed through all of this manipulation. */
+ if (saved_line_buffer)
+ {
+ if (strcmp (rl_line_buffer, saved_line_buffer) != 0)
+ completion_changed_buffer = 1;
+ else
+ completion_changed_buffer = 0;
+
+ free (saved_line_buffer);
+ }
+ return 0;
+}
+
+#if defined (VISIBLE_STATS)
+/* Return the character which best describes FILENAME.
+ `@' for symbolic links
+ `/' for directories
+ `*' for executables
+ `=' for sockets */
+static int
+stat_char (filename)
+ char *filename;
+{
+ struct stat finfo;
+ int character, r;
+
+#if defined (S_ISLNK)
+ r = lstat (filename, &finfo);
+#else
+ r = stat (filename, &finfo);
+#endif
+
+ if (r == -1)
+ return (0);
+
+ character = 0;
+ if (S_ISDIR (finfo.st_mode))
+ character = '/';
+#if defined (S_ISLNK)
+ else if (S_ISLNK (finfo.st_mode))
+ character = '@';
+#endif /* S_ISLNK */
+#if defined (S_ISSOCK)
+ else if (S_ISSOCK (finfo.st_mode))
+ character = '=';
+#endif /* S_ISSOCK */
+ else if (S_ISREG (finfo.st_mode))
+ {
+ if (access (filename, X_OK) == 0)
+ character = '*';
+ }
+ return (character);
+}
+#endif /* VISIBLE_STATS */
+
+/* Stupid comparison routine for qsort () ing strings. */
+static int
+compare_strings (s1, s2)
+ char **s1, **s2;
+{
+ return (strcmp (*s1, *s2));
+}
+
+/* A completion function for usernames.
+ TEXT contains a partial username preceded by a random
+ character (usually `~'). */
+char *
+username_completion_function (text, state)
+ int state;
+ char *text;
+{
+#if defined (__GO32__)
+ return (char *)NULL;
+#else /* !__GO32__ */
+ static char *username = (char *)NULL;
+ static struct passwd *entry;
+ static int namelen, first_char, first_char_loc;
+
+ if (!state)
+ {
+ if (username)
+ free (username);
+
+ first_char = *text;
+
+ if (first_char == '~')
+ first_char_loc = 1;
+ else
+ first_char_loc = 0;
+
+ username = savestring (&text[first_char_loc]);
+ namelen = strlen (username);
+ setpwent ();
+ }
+
+ while (entry = getpwent ())
+ {
+ if ((username[0] == entry->pw_name[0]) &&
+ (strncmp (username, entry->pw_name, namelen) == 0))
+ break;
+ }
+
+ if (!entry)
+ {
+ endpwent ();
+ return ((char *)NULL);
+ }
+ else
+ {
+ char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
+
+ *value = *text;
+
+ strcpy (value + first_char_loc, entry->pw_name);
+
+ if (first_char == '~')
+ rl_filename_completion_desired = 1;
+
+ return (value);
+ }
+#endif /* !__GO32__ */
+}
+
+/* **************************************************************** */
+/* */
+/* Completion */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means that case is not significant in completion. */
+int completion_case_fold = 0;
+
+/* Return an array of (char *) which is a list of completions for TEXT.
+ If there are no completions, return a NULL pointer.
+ The first entry in the returned array is the substitution for TEXT.
+ The remaining entries are the possible completions.
+ The array is terminated with a NULL pointer.
+
+ ENTRY_FUNCTION is a function of two args, and returns a (char *).
+ The first argument is TEXT.
+ The second is a state argument; it should be zero on the first call, and
+ non-zero on subsequent calls. It returns a NULL pointer to the caller
+ when there are no more matches.
+ */
+char **
+completion_matches (text, entry_function)
+ char *text;
+ CPFunction *entry_function;
+{
+ /* Number of slots in match_list. */
+ int match_list_size;
+
+ /* The list of matches. */
+ char **match_list =
+ (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
+
+ /* Number of matches actually found. */
+ int matches = 0;
+
+ /* Temporary string binder. */
+ char *string;
+
+ match_list[1] = (char *)NULL;
+
+ while (string = (*entry_function) (text, matches))
+ {
+ if (matches + 1 == match_list_size)
+ match_list = (char **)xrealloc
+ (match_list, ((match_list_size += 10) + 1) * sizeof (char *));
+
+ match_list[++matches] = string;
+ match_list[matches + 1] = (char *)NULL;
+ }
+
+ /* If there were any matches, then look through them finding out the
+ lowest common denominator. That then becomes match_list[0]. */
+ if (matches)
+ {
+ register int i = 1;
+ int low = 100000; /* Count of max-matched characters. */
+
+ /* If only one match, just use that. */
+ if (matches == 1)
+ {
+ match_list[0] = match_list[1];
+ match_list[1] = (char *)NULL;
+ }
+ else
+ {
+ /* Otherwise, compare each member of the list with
+ the next, finding out where they stop matching. */
+
+ while (i < matches)
+ {
+ register int c1, c2, si;
+
+ if (completion_case_fold)
+ {
+ for (si = 0;
+ (c1 = to_lower(match_list[i][si])) &&
+ (c2 = to_lower(match_list[i + 1][si]));
+ si++)
+ if (c1 != c2) break;
+ }
+ else
+ {
+ for (si = 0;
+ (c1 = match_list[i][si]) &&
+ (c2 = match_list[i + 1][si]);
+ si++)
+ if (c1 != c2) break;
+ }
+
+ if (low > si) low = si;
+ i++;
+ }
+ match_list[0] = (char *)xmalloc (low + 1);
+ strncpy (match_list[0], match_list[1], low);
+ match_list[0][low] = '\0';
+ }
+ }
+ else /* There were no matches. */
+ {
+ free (match_list);
+ match_list = (char **)NULL;
+ }
+ return (match_list);
+}
+
+/* Okay, now we write the entry_function for filename completion. In the
+ general case. Note that completion in the shell is a little different
+ because of all the pathnames that must be followed when looking up the
+ completion for a command. */
+char *
+filename_completion_function (text, state)
+ int state;
+ char *text;
+{
+ static DIR *directory;
+ static char *filename = (char *)NULL;
+ static char *dirname = (char *)NULL;
+ static char *users_dirname = (char *)NULL;
+ static int filename_len;
+
+ struct direct *entry = (struct direct *)NULL;
+
+ /* If we don't have any state, then do some initialization. */
+ if (!state)
+ {
+ char *temp;
+
+ if (dirname) free (dirname);
+ if (filename) free (filename);
+ if (users_dirname) free (users_dirname);
+
+ filename = savestring (text);
+ if (!*text) text = ".";
+ dirname = savestring (text);
+
+ temp = strrchr (dirname, '/');
+
+ if (temp)
+ {
+ strcpy (filename, ++temp);
+ *temp = '\0';
+ }
+ else
+ strcpy (dirname, ".");
+
+ /* We aren't done yet. We also support the "~user" syntax. */
+
+ /* Save the version of the directory that the user typed. */
+ users_dirname = savestring (dirname);
+ {
+ char *temp_dirname;
+ int replace_dirname;
+
+ temp_dirname = tilde_expand (dirname);
+ free (dirname);
+ dirname = temp_dirname;
+
+ replace_dirname = 0;
+ if (rl_directory_completion_hook)
+ replace_dirname = (*rl_directory_completion_hook) (&dirname);
+ if (replace_dirname)
+ {
+ free (users_dirname);
+ users_dirname = savestring (dirname);
+ }
+ }
+ directory = opendir (dirname);
+ filename_len = strlen (filename);
+
+ rl_filename_completion_desired = 1;
+ }
+
+ /* At this point we should entertain the possibility of hacking wildcarded
+ filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name
+ contains globbing characters, then build an array of directories, and
+ then map over that list while completing. */
+ /* *** UNIMPLEMENTED *** */
+
+ /* Now that we have some state, we can read the directory. */
+
+ while (directory && (entry = readdir (directory)))
+ {
+ /* Special case for no filename.
+ All entries except "." and ".." match. */
+ if (!filename_len)
+ {
+ if ((strcmp (entry->d_name, ".") != 0) &&
+ (strcmp (entry->d_name, "..") != 0))
+ break;
+ }
+ else
+ {
+ /* Otherwise, if these match up to the length of filename, then
+ it is a match. */
+ if (((int)D_NAMLEN (entry)) >= filename_len &&
+ (entry->d_name[0] == filename[0]) &&
+ (strncmp (filename, entry->d_name, filename_len) == 0))
+ break;
+ }
+ }
+
+ if (!entry)
+ {
+ if (directory)
+ {
+ closedir (directory);
+ directory = (DIR *)NULL;
+ }
+
+ if (dirname)
+ {
+ free (dirname);
+ dirname = (char *)NULL;
+ }
+ if (filename)
+ {
+ free (filename);
+ filename = (char *)NULL;
+ }
+ if (users_dirname)
+ {
+ free (users_dirname);
+ users_dirname = (char *)NULL;
+ }
+
+ return (char *)NULL;
+ }
+ else
+ {
+ char *temp;
+
+ /* dirname && (strcmp (dirname, ".") != 0) */
+ if (dirname && (dirname[0] != '.' || dirname[1]))
+ {
+ if (rl_complete_with_tilde_expansion && *users_dirname == '~')
+ {
+ int dirlen = strlen (dirname);
+ temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry));
+ strcpy (temp, dirname);
+ /* Canonicalization cuts off any final slash present. We need
+ to add it back. */
+ if (dirname[dirlen - 1] != '/')
+ {
+ temp[dirlen] = '/';
+ temp[dirlen + 1] = '\0';
+ }
+ }
+ else
+ {
+ temp = (char *)
+ xmalloc (1 + strlen (users_dirname) + D_NAMLEN (entry));
+ strcpy (temp, users_dirname);
+ }
+
+ strcat (temp, entry->d_name);
+ }
+ else
+ temp = (savestring (entry->d_name));
+
+ return (temp);
+ }
+}
+
+/* A function for simple tilde expansion. */
+int
+rl_tilde_expand (ignore, key)
+ int ignore, key;
+{
+ register int start, end;
+ char *homedir;
+
+ end = rl_point;
+ start = end - 1;
+
+ if (rl_point == rl_end && rl_line_buffer[rl_point] == '~')
+ {
+ homedir = tilde_expand ("~");
+ goto insert;
+ }
+ else if (rl_line_buffer[start] != '~')
+ {
+ for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--);
+ start++;
+ }
+
+ end = start;
+ do
+ {
+ end++;
+ }
+ while (!whitespace (rl_line_buffer[end]) && end < rl_end);
+
+ if (whitespace (rl_line_buffer[end]) || end >= rl_end)
+ end--;
+
+ /* If the first character of the current word is a tilde, perform
+ tilde expansion and insert the result. If not a tilde, do
+ nothing. */
+ if (rl_line_buffer[start] == '~')
+ {
+ char *temp;
+ int len;
+
+ len = end - start + 1;
+ temp = xmalloc (len + 1);
+ strncpy (temp, rl_line_buffer + start, len);
+ temp[len] = '\0';
+ homedir = tilde_expand (temp);
+ free (temp);
+
+ insert:
+ rl_begin_undo_group ();
+ rl_delete_text (start, end + 1);
+ rl_point = start;
+ rl_insert_text (homedir);
+ rl_end_undo_group ();
+ }
+
+ return (0);
+}
+
+/* Find the first occurrence in STRING1 of any character from STRING2.
+ Return a pointer to the character in STRING1. */
+static char *
+rl_strpbrk (string1, string2)
+ char *string1, *string2;
+{
+ register char *scan;
+
+ for (; *string1; string1++)
+ {
+ for (scan = string2; *scan; scan++)
+ {
+ if (*string1 == *scan)
+ {
+ return (string1);
+ }
+ }
+ }
+ return ((char *)NULL);
+}
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/gnu/lib/libreadline/display.c b/gnu/lib/libreadline/display.c
new file mode 100644
index 000000000000..95c61d80b5a8
--- /dev/null
+++ b/gnu/lib/libreadline/display.c
@@ -0,0 +1,1017 @@
+/* display.c -- readline redisplay facility. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+/* Global and pseudo-global variables and functions
+ imported from readline.c. */
+extern char *rl_prompt;
+extern int readline_echoing_p;
+extern char *term_clreol, *term_im, *term_ic, *term_ei, *term_DC;
+/* Termcap variables. */
+extern char *term_up, *term_dc, *term_cr, *term_IC;
+extern int screenheight, screenwidth, screenchars;
+extern int terminal_can_insert;
+
+extern void _rl_output_some_chars ();
+extern int _rl_output_character_function ();
+
+extern int _rl_output_meta_chars;
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_prefer_visible_bell;
+
+/* Pseudo-global functions (local to the readline library) exported
+ by this file. */
+void _rl_move_cursor_relative (), _rl_output_some_chars ();
+void _rl_move_vert ();
+
+static void update_line (), clear_to_eol ();
+static void delete_chars (), insert_some_chars ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Display stuff */
+/* */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me. I never seem to write good
+ display routines in C. Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+ the problems of input lines longer than the screen width.
+
+ update_line and the code that calls it makes a multiple line,
+ automatically wrapping line update. Carefull attention needs
+ to be paid to the vertical position variables.
+
+ handling of terminals with autowrap on (incl. DEC braindamage)
+ could be improved a bit. Right now I just cheat and decrement
+ screenwidth by one. */
+
+/* Keep two buffers; one which reflects the current contents of the
+ screen, and the other to draw what we think the new contents should
+ be. Then compare the buffers, and make whatever changes to the
+ screen itself that we should. Finally, make the buffer that we
+ just drew into be the one which reflects the current contents of the
+ screen, and place the cursor where it belongs.
+
+ Commands that want to can fix the display themselves, and then let
+ this function know that the display has been fixed by setting the
+ RL_DISPLAY_FIXED variable. This is good for efficiency. */
+
+/* Global variables declared here. */
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+/* The stuff that gets printed out before the actual text of the line.
+ This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *)NULL;
+
+/* Pseudo-global variables declared here. */
+/* The visible cursor position. If you print some text, adjust this. */
+int _rl_last_c_pos = 0;
+int _rl_last_v_pos = 0;
+
+/* Number of lines currently on screen minus 1. */
+int _rl_vis_botlin = 0;
+
+/* Variables used only in this file. */
+/* The last left edge of text that was displayed. This is used when
+ doing horizontal scrolling. It shifts in thirds of a screenwidth. */
+static int last_lmargin = 0;
+
+/* The line display buffers. One is the line currently displayed on
+ the screen. The other is the line about to be displayed. */
+static char *visible_line = (char *)NULL;
+static char *invisible_line = (char *)NULL;
+
+/* A buffer for `modeline' messages. */
+static char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+static int forced_display = 0;
+
+/* Default and initial buffer size. Can grow. */
+static int line_size = 1024;
+
+static char *last_prompt_string = (char *)NULL;
+static char *local_prompt, *local_prompt_prefix;
+static int visible_length, prefix_length;
+
+/* The number of invisible characters in the line currently being
+ displayed on the screen. */
+static int visible_wrap_offset = 0;
+
+/* The length (buffer offset) of the first line of the last (possibly
+ multi-line) buffer displayed on the screen. */
+static int visible_first_line_len = 0;
+
+/* Expand the prompt string S and return the number of visible
+ characters in *LP, if LP is not null. This is currently more-or-less
+ a placeholder for expansion. */
+
+/* Current implementation:
+ \001 (^A) start non-visible characters
+ \002 (^B) end non-visible characters
+ all characters except \001 and \002 (following a \001) are copied to
+ the returned string; all characters except those between \001 and
+ \002 are assumed to be `visible'. */
+
+static char *
+expand_prompt (pmt, lp)
+ char *pmt;
+ int *lp;
+{
+ char *r, *ret, *p;
+ int l, rl, ignoring;
+
+ /* Short-circuit if we can. */
+ if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
+ {
+ r = savestring (pmt);
+ if (lp)
+ *lp = strlen (r);
+ return r;
+ }
+
+ l = strlen (pmt);
+ r = ret = xmalloc (l + 1);
+
+ for (rl = ignoring = 0, p = pmt; p && *p; p++)
+ {
+ /* This code strips the invisible character string markers
+ RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
+ if (*p == RL_PROMPT_START_IGNORE)
+ {
+ ignoring++;
+ continue;
+ }
+ else if (ignoring && *p == RL_PROMPT_END_IGNORE)
+ {
+ ignoring = 0;
+ continue;
+ }
+ else
+ {
+ *r++ = *p;
+ if (!ignoring)
+ rl++;
+ }
+ }
+
+ *r = '\0';
+ if (lp)
+ *lp = rl;
+ return ret;
+}
+
+/*
+ * Expand the prompt string into the various display components, if
+ * necessary.
+ *
+ * local_prompt = expanded last line of string in rl_display_prompt
+ * (portion after the final newline)
+ * local_prompt_prefix = portion before last newline of rl_display_prompt,
+ * expanded via expand_prompt
+ * visible_length = number of visible characters in local_prompt
+ * prefix_length = number of visible characters in local_prompt_prefix
+ *
+ * This function is called once per call to readline(). It may also be
+ * called arbitrarily to expand the primary prompt.
+ *
+ * The return value is the number of visible characters on the last line
+ * of the (possibly multi-line) prompt.
+ */
+int
+rl_expand_prompt (prompt)
+ char *prompt;
+{
+ char *p, *t;
+ int c;
+
+ /* Clear out any saved values. */
+ if (local_prompt)
+ free (local_prompt);
+ if (local_prompt_prefix)
+ free (local_prompt_prefix);
+ local_prompt = local_prompt_prefix = (char *)0;
+
+ p = strrchr (prompt, '\n');
+ if (!p)
+ {
+ /* The prompt is only one line. */
+ local_prompt = expand_prompt (prompt, &visible_length);
+ local_prompt_prefix = (char *)0;
+ return (visible_length);
+ }
+ else
+ {
+ /* The prompt spans multiple lines. */
+ t = ++p;
+ local_prompt = expand_prompt (p, &visible_length);
+ c = *t; *t = '\0';
+ /* The portion of the prompt string up to and including the
+ final newline is now null-terminated. */
+ local_prompt_prefix = expand_prompt (prompt, &prefix_length);
+ *t = c;
+ return (prefix_length);
+ }
+}
+
+/* Basic redisplay algorithm. */
+void
+rl_redisplay ()
+{
+ register int in, out, c, linenum;
+ register char *line = invisible_line;
+ int c_pos = 0, inv_botlin = 0, wrap_offset, wrap_column;
+ char *prompt_this_line;
+
+ if (!readline_echoing_p)
+ return;
+
+ if (!rl_display_prompt)
+ rl_display_prompt = "";
+
+ if (!invisible_line)
+ {
+ visible_line = (char *)xmalloc (line_size);
+ invisible_line = (char *)xmalloc (line_size);
+ line = invisible_line;
+ for (in = 0; in < line_size; in++)
+ {
+ visible_line[in] = 0;
+ invisible_line[in] = 1;
+ }
+ rl_on_new_line ();
+ }
+
+ /* Draw the line into the buffer. */
+ c_pos = -1;
+
+ /* Mark the line as modified or not. We only do this for history
+ lines. */
+ out = 0;
+ if (_rl_mark_modified_lines && current_history () && rl_undo_list)
+ {
+ line[out++] = '*';
+ line[out] = '\0';
+ }
+
+ /* If someone thought that the redisplay was handled, but the currently
+ visible line has a different modification state than the one about
+ to become visible, then correct the caller's misconception. */
+ if (visible_line[0] != invisible_line[0])
+ rl_display_fixed = 0;
+
+ /* If the prompt to be displayed is the `primary' readline prompt (the
+ one passed to readline()), use the values we have already expanded.
+ If not, use what's already in rl_display_prompt. WRAP_OFFSET is the
+ number of non-visible characters in the prompt string. */
+ if (rl_display_prompt == rl_prompt)
+ {
+ int local_len = strlen (local_prompt);
+ if (local_prompt_prefix && forced_display)
+ _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
+
+ if (local_prompt)
+ strncpy (line + out, local_prompt, local_len);
+ out += local_len;
+ line[out] = '\0';
+ wrap_offset = local_len - visible_length;
+ }
+ else
+ {
+ int pmtlen;
+ prompt_this_line = strrchr (rl_display_prompt, '\n');
+ if (!prompt_this_line)
+ prompt_this_line = rl_display_prompt;
+ else
+ {
+ prompt_this_line++;
+ if (forced_display)
+ _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt);
+ }
+
+ pmtlen = strlen (prompt_this_line);
+ strncpy (line + out, prompt_this_line, pmtlen);
+ out += pmtlen;
+ line[out] = '\0';
+ wrap_offset = 0;
+ }
+
+ for (in = 0; in < rl_end; in++)
+ {
+ c = (unsigned char)rl_line_buffer[in];
+
+ if (out + 8 >= line_size) /* XXX - 8 for \t */
+ {
+ line_size *= 2;
+ visible_line = (char *)xrealloc (visible_line, line_size);
+ invisible_line = (char *)xrealloc (invisible_line, line_size);
+ line = invisible_line;
+ }
+
+ if (in == rl_point)
+ c_pos = out;
+
+ if (META_CHAR (c))
+ {
+ if (_rl_output_meta_chars == 0)
+ {
+ sprintf (line + out, "\\%o", c);
+ out += 4;
+ }
+ else
+ line[out++] = c;
+ }
+#if defined (DISPLAY_TABS)
+ else if (c == '\t')
+ {
+ register int newout = (out | (int)7) + 1;
+ while (out < newout)
+ line[out++] = ' ';
+ }
+#endif
+ else if (c < ' ')
+ {
+ line[out++] = '^';
+ line[out++] = UNCTRL (c); /* XXX was c ^ 0x40 */
+ }
+ else if (c == 127)
+ {
+ line[out++] = '^';
+ line[out++] = '?';
+ }
+ else
+ line[out++] = c;
+ }
+ line[out] = '\0';
+ if (c_pos < 0)
+ c_pos = out;
+
+ /* C_POS == position in buffer where cursor should be placed. */
+
+ /* PWP: now is when things get a bit hairy. The visible and invisible
+ line buffers are really multiple lines, which would wrap every
+ (screenwidth - 1) characters. Go through each in turn, finding
+ the changed region and updating it. The line order is top to bottom. */
+
+ /* If we can move the cursor up and down, then use multiple lines,
+ otherwise, let long lines display in a single terminal line, and
+ horizontally scroll it. */
+
+ if (!_rl_horizontal_scroll_mode && term_up && *term_up)
+ {
+ int total_screen_chars = screenchars;
+ int nleft, cursor_linenum, pos;
+
+ if (!rl_display_fixed || forced_display)
+ {
+ forced_display = 0;
+
+ /* If we have more than a screenful of material to display, then
+ only display a screenful. We should display the last screen,
+ not the first. I'll fix this in a minute. */
+ if (out >= total_screen_chars)
+ out = total_screen_chars - 1;
+
+ /* Number of screen lines to display. The first line wraps at
+ (screenwidth + wrap_offset) chars, the rest of the lines have
+ screenwidth chars. */
+ nleft = out - screenwidth - wrap_offset;
+ if (nleft > 0)
+ inv_botlin = 1 + nleft / screenwidth;
+ else
+ inv_botlin = 0;
+
+ /* The first line is at character position 0 in the buffer. The
+ second and subsequent lines start at N * screenwidth, offset by
+ OFFSET. OFFSET is wrap_offset for the invisible line and
+ visible_wrap_offset for the line currently displayed. */
+
+#define L_OFFSET(n, offset) ((n) > 0 ? ((n) * screenwidth) + (offset) : 0)
+#define VIS_CHARS(line) &visible_line[L_OFFSET((line), visible_wrap_offset)]
+#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
+#define INV_LINE(line) &invisible_line[L_OFFSET((line), wrap_offset)]
+
+ /* For each line in the buffer, do the updating display. */
+ for (linenum = 0; linenum <= inv_botlin; linenum++)
+ {
+ update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum);
+
+ /* If this is the line with the prompt, we might need to
+ compensate for invisible characters in the new line. Do
+ this only if there is not more than one new line (which
+ implies that we completely overwrite the old visible line)
+ and the new line is shorter than the old. */
+ if (linenum == 0 &&
+ inv_botlin == 0 &&
+ (wrap_offset > visible_wrap_offset) &&
+ (_rl_last_c_pos < visible_first_line_len))
+ {
+ nleft = screenwidth + wrap_offset - _rl_last_c_pos;
+ clear_to_eol (nleft);
+ }
+
+ /* Since the new first line is now visible, save its length. */
+ if (linenum == 0)
+ visible_first_line_len = _rl_last_c_pos;
+ }
+
+ /* We may have deleted some lines. If so, clear the left over
+ blank ones at the bottom out. */
+ if (_rl_vis_botlin > inv_botlin)
+ {
+ char *tt;
+ for (; linenum <= _rl_vis_botlin; linenum++)
+ {
+ tt = VIS_CHARS (linenum);
+ _rl_move_vert (linenum);
+ _rl_move_cursor_relative (0, tt);
+ clear_to_eol
+ ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth);
+ }
+ }
+ _rl_vis_botlin = inv_botlin;
+
+ /* Move the cursor where it should be. */
+ /* Which line? */
+ nleft = c_pos - screenwidth - wrap_offset;
+ if (nleft > 0)
+ cursor_linenum = 1 + nleft / screenwidth;
+ else
+ cursor_linenum = 0;
+ _rl_move_vert (cursor_linenum);
+
+ /* Where on that line? And where does that line start
+ in the buffer? */
+ pos = L_OFFSET(cursor_linenum, wrap_offset);
+ nleft = c_pos - pos;
+ _rl_move_cursor_relative (nleft, &invisible_line[pos]);
+ }
+ }
+ else /* Do horizontal scrolling. */
+ {
+ int lmargin;
+
+ /* Always at top line. */
+ _rl_last_v_pos = 0;
+
+ /* If the display position of the cursor would be off the edge
+ of the screen, start the display of this line at an offset that
+ leaves the cursor on the screen. */
+ if (c_pos - last_lmargin > screenwidth - 2)
+ lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
+ else if (c_pos - last_lmargin < 1)
+ lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
+ else
+ lmargin = last_lmargin;
+
+ /* If the first character on the screen isn't the first character
+ in the display line, indicate this with a special character. */
+ if (lmargin > 0)
+ line[lmargin] = '<';
+
+ if (lmargin + screenwidth < out)
+ line[lmargin + screenwidth - 1] = '>';
+
+ if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+ {
+ forced_display = 0;
+ update_line (&visible_line[last_lmargin],
+ &invisible_line[lmargin], 0);
+
+ _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+ last_lmargin = lmargin;
+ }
+ }
+ fflush (rl_outstream);
+
+ /* Swap visible and non-visible lines. */
+ {
+ char *temp = visible_line;
+ visible_line = invisible_line;
+ invisible_line = temp;
+ rl_display_fixed = 0;
+ visible_wrap_offset = wrap_offset;
+ }
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+ line on the screen; vis:
+
+ /old first difference
+ /beginning of line | /old last same /old EOL
+ v v v v
+old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new: eddie> Oh, my little buggy says to me, as lurgid as
+ ^ ^ ^ ^
+ \beginning of line | \new last same \new end of line
+ \new first difference
+
+ All are character pointers for the sake of speed. Special cases for
+ no differences, as well as for end of line additions must be handeled.
+
+ Could be made even smarter, but this works well enough */
+static void
+update_line (old, new, current_line)
+ register char *old, *new;
+ int current_line;
+{
+ register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+ int lendiff, wsatend;
+
+ /* Find first difference. */
+ for (ofd = old, nfd = new;
+ (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
+ ofd++, nfd++)
+ ;
+
+ /* Move to the end of the screen line. */
+ for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
+ for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
+
+ /* If no difference, continue to next line. */
+ if (ofd == oe && nfd == ne)
+ return;
+
+ wsatend = 1; /* flag for trailing whitespace */
+ ols = oe - 1; /* find last same */
+ nls = ne - 1;
+ while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
+ {
+ if (*ols != ' ')
+ wsatend = 0;
+ ols--;
+ nls--;
+ }
+
+ if (wsatend)
+ {
+ ols = oe;
+ nls = ne;
+ }
+ else if (*ols != *nls)
+ {
+ if (*ols) /* don't step past the NUL */
+ ols++;
+ if (*nls)
+ nls++;
+ }
+
+ _rl_move_vert (current_line);
+ _rl_move_cursor_relative (ofd - old, old);
+
+ /* if (len (new) > len (old)) */
+ lendiff = (nls - nfd) - (ols - ofd);
+
+ /* Insert (diff (len (old), len (new)) ch. */
+ if (lendiff > 0)
+ {
+ if (terminal_can_insert)
+ {
+ /* Sometimes it is cheaper to print the characters rather than
+ use the terminal's capabilities. */
+ if ((2 * (ne - nfd)) < lendiff && !term_IC)
+ {
+ _rl_output_some_chars (nfd, (ne - nfd));
+ _rl_last_c_pos += (ne - nfd);
+ }
+ else
+ {
+ if (*ols)
+ {
+ insert_some_chars (nfd, lendiff);
+ _rl_last_c_pos += lendiff;
+ }
+ else
+ {
+ /* At the end of a line the characters do not have to
+ be "inserted". They can just be placed on the screen. */
+ _rl_output_some_chars (nfd, lendiff);
+ _rl_last_c_pos += lendiff;
+ }
+ /* Copy (new) chars to screen from first diff to last match. */
+ if (((nls - nfd) - lendiff) > 0)
+ {
+ _rl_output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
+ _rl_last_c_pos += ((nls - nfd) - lendiff);
+ }
+ }
+ }
+ else
+ { /* cannot insert chars, write to EOL */
+ _rl_output_some_chars (nfd, (ne - nfd));
+ _rl_last_c_pos += (ne - nfd);
+ }
+ }
+ else /* Delete characters from line. */
+ {
+ /* If possible and inexpensive to use terminal deletion, then do so. */
+ if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
+ {
+ if (lendiff)
+ delete_chars (-lendiff); /* delete (diff) characters */
+
+ /* Copy (new) chars to screen from first diff to last match */
+ if ((nls - nfd) > 0)
+ {
+ _rl_output_some_chars (nfd, (nls - nfd));
+ _rl_last_c_pos += (nls - nfd);
+ }
+ }
+ /* Otherwise, print over the existing material. */
+ else
+ {
+ _rl_output_some_chars (nfd, (ne - nfd));
+ _rl_last_c_pos += (ne - nfd);
+ clear_to_eol ((oe - old) - (ne - new));
+ }
+ }
+}
+
+/* Tell the update routines that we have moved onto a new (empty) line. */
+rl_on_new_line ()
+{
+ if (visible_line)
+ visible_line[0] = '\0';
+
+ _rl_last_c_pos = _rl_last_v_pos = 0;
+ _rl_vis_botlin = last_lmargin = 0;
+ return 0;
+}
+
+/* Actually update the display, period. */
+rl_forced_update_display ()
+{
+ if (visible_line)
+ {
+ register char *temp = visible_line;
+
+ while (*temp) *temp++ = '\0';
+ }
+ rl_on_new_line ();
+ forced_display++;
+ rl_redisplay ();
+ return 0;
+}
+
+/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
+ DATA is the contents of the screen line of interest; i.e., where
+ the movement is being done. */
+void
+_rl_move_cursor_relative (new, data)
+ int new;
+ char *data;
+{
+ register int i;
+
+ /* It may be faster to output a CR, and then move forwards instead
+ of moving backwards. */
+ if (new + 1 < _rl_last_c_pos - new)
+ {
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_last_c_pos = 0;
+ }
+
+ if (_rl_last_c_pos == new) return;
+
+ if (_rl_last_c_pos < new)
+ {
+ /* Move the cursor forward. We do it by printing the command
+ to move the cursor forward if there is one, else print that
+ portion of the output buffer again. Which is cheaper? */
+
+ /* The above comment is left here for posterity. It is faster
+ to print one character (non-control) than to print a control
+ sequence telling the terminal to move forward one character.
+ That kind of control is for people who don't know what the
+ data is underneath the cursor. */
+#if defined (HACK_TERMCAP_MOTION)
+ extern char *term_forward_char;
+
+ if (term_forward_char)
+ for (i = _rl_last_c_pos; i < new; i++)
+ tputs (term_forward_char, 1, _rl_output_character_function);
+ else
+ for (i = _rl_last_c_pos; i < new; i++)
+ putc (data[i], rl_outstream);
+#else
+ for (i = _rl_last_c_pos; i < new; i++)
+ putc (data[i], rl_outstream);
+#endif /* HACK_TERMCAP_MOTION */
+ }
+ else
+ backspace (_rl_last_c_pos - new);
+ _rl_last_c_pos = new;
+}
+
+/* PWP: move the cursor up or down. */
+void
+_rl_move_vert (to)
+ int to;
+{
+ register int delta, i;
+
+ if (_rl_last_v_pos == to || to > screenheight)
+ return;
+
+#if defined (__GO32__)
+ {
+ int row, col;
+
+ ScreenGetCursor (&row, &col);
+ ScreenSetCursor ((row + to - _rl_last_v_pos), col);
+ }
+#else /* !__GO32__ */
+
+ if ((delta = to - _rl_last_v_pos) > 0)
+ {
+ for (i = 0; i < delta; i++)
+ putc ('\n', rl_outstream);
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_last_c_pos = 0;
+ }
+ else
+ { /* delta < 0 */
+ if (term_up && *term_up)
+ for (i = 0; i < -delta; i++)
+ tputs (term_up, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+ _rl_last_v_pos = to; /* Now TO is here */
+}
+
+/* Physically print C on rl_outstream. This is for functions which know
+ how to optimize the display. Return the number of characters output. */
+rl_show_char (c)
+ int c;
+{
+ int n = 1;
+ if (META_CHAR (c) && (_rl_output_meta_chars == 0))
+ {
+ fprintf (rl_outstream, "M-");
+ n += 2;
+ c = UNMETA (c);
+ }
+
+#if defined (DISPLAY_TABS)
+ if (c < 32 && c != '\t')
+#else
+ if (c < 32)
+#endif /* !DISPLAY_TABS */
+ {
+ fprintf (rl_outstream, "C-");
+ n += 2;
+ c += 64;
+ }
+
+ putc (c, rl_outstream);
+ fflush (rl_outstream);
+ return n;
+}
+
+int
+rl_character_len (c, pos)
+ register int c, pos;
+{
+ if (META_CHAR (c))
+ return ((_rl_output_meta_chars == 0) ? 4 : 1);
+
+ if (c == '\t')
+ {
+#if defined (DISPLAY_TABS)
+ return (((pos | (int)7) + 1) - pos);
+#else
+ return (2);
+#endif /* !DISPLAY_TABS */
+ }
+
+ return ((isprint (c)) ? 1 : 2);
+}
+
+/* How to print things in the "echo-area". The prompt is treated as a
+ mini-modeline. */
+
+#if defined (HAVE_VARARGS_H)
+rl_message (va_alist)
+ va_dcl
+{
+ char *format;
+ va_list args;
+
+ va_start (args);
+ format = va_arg (args, char *);
+ vsprintf (msg_buf, format, args);
+ va_end (args);
+
+ rl_display_prompt = msg_buf;
+ rl_redisplay ();
+ return 0;
+}
+#else /* !HAVE_VARARGS_H */
+rl_message (format, arg1, arg2)
+ char *format;
+{
+ sprintf (msg_buf, format, arg1, arg2);
+ rl_display_prompt = msg_buf;
+ rl_redisplay ();
+ return 0;
+}
+#endif /* !HAVE_VARARGS_H */
+
+/* How to clear things from the "echo-area". */
+rl_clear_message ()
+{
+ rl_display_prompt = rl_prompt;
+ rl_redisplay ();
+ return 0;
+}
+
+rl_reset_line_state ()
+{
+ rl_on_new_line ();
+
+ rl_display_prompt = rl_prompt ? rl_prompt : "";
+ forced_display = 1;
+ return 0;
+}
+
+/* Quick redisplay hack when erasing characters at the end of the line. */
+void
+_rl_erase_at_end_of_line (l)
+ int l;
+{
+ register int i;
+
+ backspace (l);
+ for (i = 0; i < l; i++)
+ putc (' ', rl_outstream);
+ backspace (l);
+ for (i = 0; i < l; i++)
+ visible_line[--_rl_last_c_pos] = '\0';
+ rl_display_fixed++;
+}
+
+/* Clear to the end of the line. COUNT is the minimum
+ number of character spaces to clear, */
+static void
+clear_to_eol (count)
+ int count;
+{
+#if !defined (__GO32__)
+ if (term_clreol)
+ {
+ tputs (term_clreol, 1, _rl_output_character_function);
+ }
+ else
+#endif /* !__GO32__ */
+ {
+ register int i;
+
+ /* Do one more character space. */
+ count++;
+
+ for (i = 0; i < count; i++)
+ putc (' ', rl_outstream);
+
+ backspace (count);
+ }
+}
+
+/* Insert COUNT characters from STRING to the output stream. */
+static void
+insert_some_chars (string, count)
+ char *string;
+ int count;
+{
+#if defined (__GO32__)
+ int row, col, width;
+ char *row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+
+ memcpy (row_start + col + count, row_start + col, width - col - count);
+
+ /* Place the text on the screen. */
+ _rl_output_some_chars (string, count);
+#else /* !_GO32 */
+
+ /* If IC is defined, then we do not have to "enter" insert mode. */
+ if (term_IC)
+ {
+ char *tgoto (), *buffer;
+ buffer = tgoto (term_IC, 0, count);
+ tputs (buffer, 1, _rl_output_character_function);
+ _rl_output_some_chars (string, count);
+ }
+ else
+ {
+ register int i;
+
+ /* If we have to turn on insert-mode, then do so. */
+ if (term_im && *term_im)
+ tputs (term_im, 1, _rl_output_character_function);
+
+ /* If there is a special command for inserting characters, then
+ use that first to open up the space. */
+ if (term_ic && *term_ic)
+ {
+ for (i = count; i--; )
+ tputs (term_ic, 1, _rl_output_character_function);
+ }
+
+ /* Print the text. */
+ _rl_output_some_chars (string, count);
+
+ /* If there is a string to turn off insert mode, we had best use
+ it now. */
+ if (term_ei && *term_ei)
+ tputs (term_ei, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+}
+
+/* Delete COUNT characters from the display line. */
+static void
+delete_chars (count)
+ int count;
+{
+#if defined (__GO32__)
+ int row, col, width;
+ char *row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+
+ memcpy (row_start + col, row_start + col + count, width - col - count);
+ memset (row_start + width - count, 0, count * 2);
+#else /* !_GO32 */
+
+ if (count > screenwidth)
+ return;
+
+ if (term_DC && *term_DC)
+ {
+ char *tgoto (), *buffer;
+ buffer = tgoto (term_DC, count, count);
+ tputs (buffer, count, _rl_output_character_function);
+ }
+ else
+ {
+ if (term_dc && *term_dc)
+ while (count--)
+ tputs (term_dc, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+}
diff --git a/gnu/lib/libreadline/doc/Makefile b/gnu/lib/libreadline/doc/Makefile
new file mode 100644
index 000000000000..c79ad92b3fe4
--- /dev/null
+++ b/gnu/lib/libreadline/doc/Makefile
@@ -0,0 +1,34 @@
+# This makefile for History library documentation is in -*- text -*- mode.
+# Emacs likes it that way.
+
+DOC_SUPPORT = ../../doc-support/
+TEXINDEX = $(DOC_SUPPORT)/texindex
+
+TEX = tex
+DVIOBJ = history.dvi
+INFOBJ = history.info
+
+all: $(DVIOBJ) $(INFOBJ)
+
+history.dvi: hist.texinfo hsuser.texinfo hstech.texinfo
+ $(TEX) hist.texinfo
+ $(TEXINDEX) hist.??
+ $(TEX) hist.texinfo
+ mv hist.dvi history.dvi
+
+history.info: hist.texinfo hsuser.texinfo hstech.texinfo
+ makeinfo hist.texinfo
+
+./texinfo.tex: $(DOC_SUPPORT)texinfo.tex
+ ln -s $(DOC_SUPPORT)texinfo.tex .
+
+$(TEXINDEX):
+ (cd $(DOC_SUPPORT); $(MAKE) $(MFLAGS) CFLAGS='$(CFLAGS)' texindex)
+
+clean:
+ rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
+ *.fns *.kys *.tps *.vrs *.o core texinfo.tex
+
+squeaky-clean:
+ rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
+ *.dvi *.info *.info-* *.fns *.kys *.tps *.vrs *.o core
diff --git a/gnu/lib/libreadline/doc/hist.texinfo b/gnu/lib/libreadline/doc/hist.texinfo
new file mode 100644
index 000000000000..629273810445
--- /dev/null
+++ b/gnu/lib/libreadline/doc/hist.texinfo
@@ -0,0 +1,106 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename history.info
+@settitle GNU Readline Library
+@comment %**end of header (This is for running Texinfo on a region.)
+@synindex vr fn
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@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 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.
+
+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 Foundation.
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{GNU History Library}
+@center Brian Fox
+@center Free Software Foundation
+@center Version 1.1
+@center April 1991
+
+@c Include the Distribution inside the titlepage environment so
+@c that headings are turned off.
+
+@page
+
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+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 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 Foundation.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+@end titlepage
+
+@ifinfo
+@node Top
+@top GNU History Library
+
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+@menu
+* Using History Interactively:: GNU History User's Manual.
+* Programming with GNU History:: GNU History Programmer's Manual.
+* Concept Index:: Index of concepts described in this manual.
+* Function and Variable Index:: Index of externally visible functions
+ and variables.
+@end menu
+@end ifinfo
+
+@include hsuser.texinfo
+@include hstech.texinfo
+
+@node Concept Index
+@appendix Concept Index
+@printindex cp
+
+@node Function and Variable Index
+@appendix Function and Variable Index
+@printindex vr
+@contents
+
+@bye
diff --git a/gnu/lib/libreadline/doc/hstech.texinfo b/gnu/lib/libreadline/doc/hstech.texinfo
new file mode 100644
index 000000000000..b5cbc2a92f25
--- /dev/null
+++ b/gnu/lib/libreadline/doc/hstech.texinfo
@@ -0,0 +1,308 @@
+@ignore
+This file documents the user interface to the GNU History library.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+Authored by Brian Fox.
+
+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 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).
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided 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.
+@end ignore
+
+@node Programming with GNU History
+@chapter Programming with GNU History
+
+This chapter describes how to interface the GNU History Library with
+programs that you write. It should be considered a technical guide.
+For information on the interactive use of GNU History, @pxref{Using
+History Interactively}.
+
+@menu
+* Introduction to History:: What is the GNU History library for?
+* History Storage:: How information is stored.
+* History Functions:: Functions that you can use.
+* History Variables:: Variables that control behaviour.
+* History Programming Example:: Example of using the GNU History Library.
+@end menu
+
+@node Introduction to History
+@section Introduction to History
+
+Many programs read input from the user a line at a time. The GNU history
+library is able to keep track of those lines, associate arbitrary data with
+each line, and utilize information from previous lines in making up new
+ones.
+
+The programmer using the History library has available to him functions
+for remembering lines on a history stack, associating arbitrary data
+with a line, removing lines from the stack, searching through the stack
+for a line containing an arbitrary text string, and referencing any line
+on the stack directly. In addition, a history @dfn{expansion} function
+is available which provides for a consistent user interface across many
+different programs.
+
+The end-user using programs written with the History library has the
+benifit of a consistent user interface, with a set of well-known
+commands for manipulating the text of previous lines and using that text
+in new commands. The basic history manipulation commands are similar to
+the history substitution used by @code{Csh}.
+
+If the programmer desires, he can use the Readline library, which
+includes some history manipulation by default, and has the added
+advantage of Emacs style command line editing.
+
+@node History Storage
+@section History Storage
+
+@example
+typedef struct _hist_entry @{
+ char *line;
+ char *data;
+@} HIST_ENTRY;
+@end example
+
+@node History Functions
+@section History Functions
+
+This section describes the calling sequence for the various functions
+present in GNU History.
+
+@defun {void using_history} ()
+Begin a session in which the history functions might be used. This
+just initializes the interactive variables.
+@end defun
+
+@defun {void add_history} (char *string)
+Place @var{string} at the end of the history list. The associated data
+field (if any) is set to @code{NULL}.
+@end defun
+
+@defun {int where_history} ()
+Returns the number which says what history element we are now looking
+at.
+@end defun
+
+@defun {int history_set_pos} (int pos)
+Set the position in the history list to @var{pos}.
+@end defun
+
+@defun {int history_search_pos} (char *string, int direction, int pos)
+Search for @var{string} in the history list, starting at @var{pos}, an
+absolute index into the list. @var{direction}, if negative, says to search
+backwards from @var{pos}, else forwards. Returns the absolute index of
+the history element where @var{string} was found, or -1 otherwise.
+@end defun
+
+@defun {HIST_ENTRY *remove_history} ();
+Remove history element @var{which} from the history. The removed
+element is returned to you so you can free the line, data,
+and containing structure.
+@end defun
+
+@defun {void stifle_history} (int max)
+Stifle the history list, remembering only @var{max} number of entries.
+@end defun
+
+@defun {int unstifle_history} ();
+Stop stifling the history. This returns the previous amount the
+history was stifled by. The value is positive if the history was
+stifled, negative if it wasn't.
+@end defun
+
+@defun {int read_history} (char *filename)
+Add the contents of @var{filename} to the history list, a line at a
+time. If @var{filename} is @code{NULL}, then read from
+@file{~/.history}. Returns 0 if successful, or errno if not.
+@end defun
+
+@defun {int read_history_range} (char *filename, int from, int to)
+Read a range of lines from @var{filename}, adding them to the history list.
+Start reading at the @var{from}'th line and end at the @var{to}'th. If
+@var{from} is zero, start at the beginning. If @var{to} is less than
+@var{from}, then read until the end of the file. If @var{filename} is
+@code{NULL}, then read from @file{~/.history}. Returns 0 if successful,
+or @code{errno} if not.
+@end defun
+
+@defun {int write_history} (char *filename)
+Append the current history to @var{filename}. If @var{filename} is
+@code{NULL}, then append the history list to @file{~/.history}. Values
+returned are as in @code{read_history ()}.
+@end defun
+
+@defun {int append_history} (int nelements, char *filename)
+Append @var{nelement} entries to @var{filename}. The entries appended
+are from the end of the list minus @var{nelements} up to the end of the
+list.
+@end defun
+
+@defun {HIST_ENTRY *replace_history_entry} ()
+Make the history entry at @var{which} have @var{line} and @var{data}.
+This returns the old entry so you can dispose of the data. In the case
+of an invalid @var{which}, a @code{NULL} pointer is returned.
+@end defun
+
+@defun {HIST_ENTRY *current_history} ()
+Return the history entry at the current position, as determined by
+@code{history_offset}. If there is no entry there, return a @code{NULL}
+pointer.
+@end defun
+
+@defun {HIST_ENTRY *previous_history} ()
+Back up @var{history_offset} to the previous history entry, and return a
+pointer to that entry. If there is no previous entry, return a
+@code{NULL} pointer.
+@end defun
+
+@defun {HIST_ENTRY *next_history} ()
+Move @code{history_offset} forward to the next history entry, and return
+the a pointer to that entry. If there is no next entry, return a
+@code{NULL} pointer.
+@end defun
+
+@defun {HIST_ENTRY **history_list} ()
+Return a @code{NULL} terminated array of @code{HIST_ENTRY} which is the
+current input history. Element 0 of this list is the beginning of time.
+If there is no history, return @code{NULL}.
+@end defun
+
+@defun {int history_search} (char *string, int direction)
+Search the history for @var{string}, starting at @code{history_offset}.
+If @var{direction} < 0, then the search is through previous entries,
+else through subsequent. If @var{string} is found, then
+@code{current_history ()} is the history entry, and the value of this
+function is the offset in the line of that history entry that the
+@var{string} was found in. Otherwise, nothing is changed, and a -1 is
+returned.
+@end defun
+
+@defun {int history_expand} (char *string, char **output)
+Expand @var{string}, placing the result into @var{output}, a pointer
+to a string. Returns:
+@table @code
+@item 0
+If no expansions took place (or, if the only change in
+the text was the de-slashifying of the history expansion
+character),
+@item 1
+if expansions did take place, or
+@item -1
+if there was an error in expansion.
+@end table
+
+If an error ocurred in expansion, then @var{output} contains a descriptive
+error message.
+@end defun
+
+@defun {char *history_arg_extract} (int first, int last, char *string)
+Extract a string segment consisting of the @var{first} through @var{last}
+arguments present in @var{string}. Arguments are broken up as in
+the GNU Bash shell.
+@end defun
+
+@defun {int history_total_bytes} ();
+Return the number of bytes that the primary history entries are using.
+This just adds up the lengths of @code{the_history->lines}.
+@end defun
+
+@node History Variables
+@section History Variables
+
+This section describes the variables in GNU History that are externally
+visible.
+
+@defvar {int history_base}
+For convenience only. You set this when interpreting history commands.
+It is the logical offset of the first history element.
+@end defvar
+
+@node History Programming Example
+@section History Programming Example
+
+The following snippet of code demonstrates simple use of the GNU History
+Library.
+
+@smallexample
+main ()
+@{
+ char line[1024], *t;
+ int done = 0;
+
+ line[0] = 0;
+
+ while (!done)
+ @{
+ fprintf (stdout, "history%% ");
+ t = gets (line);
+
+ if (!t)
+ strcpy (line, "quit");
+
+ if (line[0])
+ @{
+ char *expansion;
+ int result;
+
+ using_history ();
+
+ result = history_expand (line, &expansion);
+ strcpy (line, expansion);
+ free (expansion);
+ if (result)
+ fprintf (stderr, "%s\n", line);
+
+ if (result < 0)
+ continue;
+
+ add_history (line);
+ @}
+
+ if (strcmp (line, "quit") == 0) done = 1;
+ if (strcmp (line, "save") == 0) write_history (0);
+ if (strcmp (line, "read") == 0) read_history (0);
+ if (strcmp (line, "list") == 0)
+ @{
+ register HIST_ENTRY **the_list = history_list ();
+ register int i;
+
+ if (the_list)
+ for (i = 0; the_list[i]; i++)
+ fprintf (stdout, "%d: %s\n",
+ i + history_base, the_list[i]->line);
+ @}
+ if (strncmp (line, "delete", strlen ("delete")) == 0)
+ @{
+ int which;
+ if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+ @{
+ HIST_ENTRY *entry = remove_history (which);
+ if (!entry)
+ fprintf (stderr, "No such entry %d\n", which);
+ else
+ @{
+ free (entry->line);
+ free (entry);
+ @}
+ @}
+ else
+ @{
+ fprintf (stderr, "non-numeric arg given to `delete'\n");
+ @}
+ @}
+ @}
+@}
+@end smallexample
diff --git a/gnu/lib/libreadline/doc/hsuser.texinfo b/gnu/lib/libreadline/doc/hsuser.texinfo
new file mode 100644
index 000000000000..44f7fa093203
--- /dev/null
+++ b/gnu/lib/libreadline/doc/hsuser.texinfo
@@ -0,0 +1,197 @@
+@ignore
+This file documents the user interface to the GNU History library.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+Authored by Brian Fox and Chet Ramey.
+
+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 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).
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided 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.
+@end ignore
+
+@node Using History Interactively
+@chapter Using History Interactively
+
+@ifset BashFeatures
+This chapter describes how to use the GNU History Library interactively,
+from a user's standpoint. It should be considered a user's guide. For
+information on using the GNU History Library in your own programs,
+see the GNU Readline Library Manual.
+@end ifset
+@ifclear BashFeatures
+This chapter describes how to use the GNU History Library interactively,
+from a user's standpoint. It should be considered a user's guide. For
+information on using the GNU History Library in your own programs,
+@pxref{Programming with GNU History}.
+@end ifclear
+
+@menu
+* History Interaction:: What it feels like using History as a user.
+@end menu
+
+@node History Interaction
+@section History Interaction
+@cindex expansion
+
+The History library provides a history expansion feature that is similar
+to the history expansion in @code{csh}. The following text describes
+the syntax used to manipulate the history information.
+
+History expansion takes place in two parts. The first is to determine
+which line from the previous history should be used during substitution.
+The second is to select portions of that line for inclusion into the
+current one. The line selected from the previous history is called the
+@dfn{event}, and the portions of that line that are acted upon are
+called @dfn{words}. The line is broken into words in the same fashion
+that Bash does, so that several English (or Unix) words
+surrounded by quotes are considered as one word.
+
+@menu
+* Event Designators:: How to specify which history line to use.
+* Word Designators:: Specifying which words are of interest.
+* Modifiers:: Modifying the results of substitution.
+@end menu
+
+@node Event Designators
+@subsection Event Designators
+@cindex event designators
+
+An event designator is a reference to a command line entry in the
+history list.
+
+@table @asis
+
+@item @code{!}
+Start a history substitution, except when followed by a space, tab,
+the end of the line, @key{=} or @key{(}.
+
+@item @code{!!}
+Refer to the previous command. This is a synonym for @code{!-1}.
+
+@item @code{!n}
+Refer to command line @var{n}.
+
+@item @code{!-n}
+Refer to the command line @var{n} lines back.
+
+@item @code{!string}
+Refer to the most recent command starting with @var{string}.
+
+@item @code{!?string}[@code{?}]
+Refer to the most recent command containing @var{string}.
+
+@item @code{!#}
+The entire command line typed so far.
+
+@item @code{^string1^string2^}
+Quick Substitution. Repeat the last command, replacing @var{string1}
+with @var{string2}. Equivalent to
+@code{!!:s/string1/string2/}.
+
+@end table
+
+@node Word Designators
+@subsection Word Designators
+
+A @key{:} separates the event specification from the word designator. It
+can be omitted if the word designator begins with a @key{^}, @key{$},
+@key{*} or @key{%}. Words are numbered from the beginning of the line,
+with the first word being denoted by a 0 (zero).
+
+@table @code
+
+@item 0 (zero)
+The @code{0}th word. For many applications, this is the command word.
+
+@item n
+The @var{n}th word.
+
+@item ^
+The first argument; that is, word 1.
+
+@item $
+The last argument.
+
+@item %
+The word matched by the most recent @code{?string?} search.
+
+@item x-y
+A range of words; @code{-@var{y}} abbreviates @code{0-@var{y}}.
+
+@item *
+All of the words, except the @code{0}th. This is a synonym for @code{1-$}.
+It is not an error to use @key{*} if there is just one word in the event;
+the empty string is returned in that case.
+
+@item x*
+Abbreviates @code{x-$}
+
+@item x-
+Abbreviates @code{x-$} like @code{x*}, but omits the last word.
+
+@end table
+
+@node Modifiers
+@subsection Modifiers
+
+After the optional word designator, you can add a sequence of one or more
+of the following modifiers, each preceded by a @key{:}.
+
+@table @code
+
+@item h
+Remove a trailing pathname component, leaving only the head.
+
+@item r
+Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename.
+
+@item e
+Remove all but the trailing suffix.
+
+@item t
+Remove all leading pathname components, leaving the tail.
+
+@item p
+Print the new command but do not execute it.
+
+@ifset BashFeatures
+@item q
+Quote the substituted words, escaping further substitutions.
+
+@item x
+Quote the substituted words as with @code{q},
+but break into words at spaces, tabs, and newlines.
+@end ifset
+
+@item s/old/new/
+Substitute @var{new} for the first occurrence of @var{old} in the
+event line. Any delimiter may be used in place of @key{/}.
+The delimiter may be quoted in @var{old} and @var{new}
+with a single backslash. If @key{&} appears in @var{new},
+it is replaced by @var{old}. A single backslash will quote
+the @key{&}. The final delimiter is optional if it is the last
+character on the input line.
+
+@item &
+Repeat the previous substitution.
+
+@item g
+Cause changes to be applied over the entire event line. Used in
+conjunction with @code{s}, as in @code{gs/old/new/}, or with
+@code{&}.
+
+@end table
diff --git a/gnu/lib/libreadline/doc/rlman.texinfo b/gnu/lib/libreadline/doc/rlman.texinfo
new file mode 100644
index 000000000000..f2e7fb6db919
--- /dev/null
+++ b/gnu/lib/libreadline/doc/rlman.texinfo
@@ -0,0 +1,103 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename readline.info
+@settitle GNU Readline Library
+@comment %**end of header (This is for running Texinfo on a region.)
+@synindex vr fn
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@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 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.
+
+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 Foundation.
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{GNU Readline Library}
+@center Brian Fox
+@center Free Software Foundation
+@center Version 1.1
+@center April 1991
+
+@page
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+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 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 Foundation.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+@end titlepage
+
+@ifinfo
+@node Top
+@top GNU Readline Library
+
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+@menu
+* Command Line Editing:: GNU Readline User's Manual.
+* Programming with GNU Readline:: GNU Readline Programmer's Manual.
+* Concept Index:: Index of concepts described in this manual.
+* Function and Variable Index:: Index of externally visible functions
+ and variables.
+@end menu
+@end ifinfo
+
+@include rluser.texinfo
+@include rltech.texinfo
+
+@node Concept Index
+@unnumbered Concept Index
+@printindex cp
+
+@node Function and Variable Index
+@unnumbered Function and Variable Index
+@printindex fn
+
+@contents
+@bye
+
diff --git a/gnu/lib/libreadline/doc/rltech.texinfo b/gnu/lib/libreadline/doc/rltech.texinfo
new file mode 100644
index 000000000000..2048b7c29dfb
--- /dev/null
+++ b/gnu/lib/libreadline/doc/rltech.texinfo
@@ -0,0 +1,1012 @@
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename rltech.info
+@comment %**end of header (This is for running Texinfo on a region.)
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU Readline Library, a utility for aiding
+in the consitency of user interface across discrete programs that need
+to provide a command line interface.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@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 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.
+
+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 Foundation.
+@end ifinfo
+
+@node Programming with GNU Readline
+@chapter Programming with GNU Readline
+
+This manual describes the interface between the GNU Readline Library and
+user programs. If you are a programmer, and you wish to include the
+features found in GNU Readline in your own programs, such as completion,
+line editing, and interactive history manipulation, this documentation
+is for you.
+
+@menu
+* Default Behaviour:: Using the default behaviour of Readline.
+* Custom Functions:: Adding your own functions to Readline.
+* Custom Completers:: Supplanting or supplementing Readline's
+ completion functions.
+@end menu
+
+@node Default Behaviour
+@section Default Behaviour
+
+Many programs provide a command line interface, such as @code{mail},
+@code{ftp}, and @code{sh}. For such programs, the default behaviour of
+Readline is sufficient. This section describes how to use Readline in
+the simplest way possible, perhaps to replace calls in your code to
+@code{gets ()}.
+
+@findex readline ()
+@cindex readline, function
+The function @code{readline} prints a prompt and then reads and returns
+a single line of text from the user. The line which @code{readline ()}
+returns is allocated with @code{malloc ()}; you should @code{free ()}
+the line when you are done with it. The declaration for @code{readline}
+in ANSI C is
+
+@example
+@code{char *readline (char *@var{prompt});}
+@end example
+
+So, one might say
+@example
+@code{char *line = readline ("Enter a line: ");}
+@end example
+in order to read a line of text from the user.
+
+The line which is returned has the final newline removed, so only the
+text of the line remains.
+
+If readline encounters an @code{EOF} while reading the line, and the
+line is empty at that point, then @code{(char *)NULL} is returned.
+Otherwise, the line is ended just as if a newline was typed.
+
+If you want the user to be able to get at the line later, (with
+@key{C-p} for example), you must call @code{add_history ()} to save the
+line away in a @dfn{history} list of such lines.
+
+@example
+@code{add_history (line)};
+@end example
+
+For full details on the GNU History Library, see the associated manual.
+
+It is polite to avoid saving empty lines on the history list, since it
+is rare than someone has a burning need to reuse a blank line. Here is
+a function which usefully replaces the standard @code{gets ()} library
+function:
+
+@example
+/* A static variable for holding the line. */
+static char *line_read = (char *)NULL;
+
+/* Read a string, and return a pointer to it. Returns NULL on EOF. */
+char *
+do_gets ()
+@{
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+ if (line_read != (char *)NULL)
+ @{
+ free (line_read);
+ line_read = (char *)NULL;
+ @}
+
+ /* Get a line from the user. */
+ line_read = readline ("");
+
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+
+ return (line_read);
+@}
+@end example
+
+The above code gives the user the default behaviour of @key{TAB}
+completion: completion on file names. If you do not want readline to
+complete on filenames, you can change the binding of the @key{TAB} key
+with @code{rl_bind_key ()}.
+
+@findex rl_bind_key ()
+@example
+@code{int rl_bind_key (int @var{key}, int (*@var{function})());}
+@end example
+
+@code{rl_bind_key ()} takes 2 arguments; @var{key} is the character that
+you want to bind, and @var{function} is the address of the function to
+run when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert ()}
+makes @key{TAB} just insert itself.
+
+@code{rl_bind_key ()} returns non-zero if @var{key} is not a valid
+ASCII character code (between 0 and 255).
+
+@example
+@code{rl_bind_key ('\t', rl_insert);}
+@end example
+
+This code should be executed once at the start of your program; you
+might write a function called @code{initialize_readline ()} which
+performs this and other desired initializations, such as installing
+custom completers, etc.
+
+@node Custom Functions
+@section Custom Functions
+
+Readline provides a great many functions for manipulating the text of
+the line. But it isn't possible to anticipate the needs of all
+programs. This section describes the various functions and variables
+defined in within the Readline library which allow a user program to add
+customized functionality to Readline.
+
+@menu
+* The Function Type:: C declarations to make code readable.
+* Function Naming:: How to give a function you write a name.
+* Keymaps:: Making keymaps.
+* Binding Keys:: Changing Keymaps.
+* Function Writing:: Variables and calling conventions.
+* Allowing Undoing:: How to make your functions undoable.
+@end menu
+
+@node The Function Type
+@subsection The Function Type
+
+For the sake of readabilty, we declare a new type of object, called
+@dfn{Function}. A @code{Function} is a C language function which
+returns an @code{int}. The type declaration for @code{Function} is:
+
+@noindent
+@code{typedef int Function ();}
+
+The reason for declaring this new type is to make it easier to write
+code describing pointers to C functions. Let us say we had a variable
+called @var{func} which was a pointer to a function. Instead of the
+classic C declaration
+
+@code{int (*)()func;}
+
+we have
+
+@code{Function *func;}
+
+@node Function Naming
+@subsection Naming a Function
+
+The user can dynamically change the bindings of keys while using
+Readline. This is done by representing the function with a descriptive
+name. The user is able to type the descriptive name when referring to
+the function. Thus, in an init file, one might find
+
+@example
+Meta-Rubout: backward-kill-word
+@end example
+
+This binds the keystroke @key{Meta-Rubout} to the function
+@emph{descriptively} named @code{backward-kill-word}. You, as the
+programmer, should bind the functions you write to descriptive names as
+well. Readline provides a function for doing that:
+
+@defun rl_add_defun (char *name, Function *function, int key)
+Add @var{name} to the list of named functions. Make @var{function} be
+the function that gets called. If @var{key} is not -1, then bind it to
+@var{function} using @code{rl_bind_key ()}.
+@end defun
+
+Using this function alone is sufficient for most applications. It is
+the recommended way to add a few functions to the default functions that
+Readline has built in already. If you need to do more or different
+things than adding a function to Readline, you may need to use the
+underlying functions described below.
+
+@node Keymaps
+@subsection Selecting a Keymap
+
+Key bindings take place on a @dfn{keymap}. The keymap is the
+association between the keys that the user types and the functions that
+get run. You can make your own keymaps, copy existing keymaps, and tell
+Readline which keymap to use.
+
+@defun {Keymap rl_make_bare_keymap} ()
+Returns a new, empty keymap. The space for the keymap is allocated with
+@code{malloc ()}; you should @code{free ()} it when you are done.
+@end defun
+
+@defun {Keymap rl_copy_keymap} (Keymap map)
+Return a new keymap which is a copy of @var{map}.
+@end defun
+
+@defun {Keymap rl_make_keymap} ()
+Return a new keymap with the printing characters bound to rl_insert,
+the lowercase Meta characters bound to run their equivalents, and
+the Meta digits bound to produce numeric arguments.
+@end defun
+
+@node Binding Keys
+@subsection Binding Keys
+
+You associate keys with functions through the keymap. Here are
+functions for doing that.
+
+@defun {int rl_bind_key} (int key, Function *function)
+Binds @var{key} to @var{function} in the currently selected keymap.
+Returns non-zero in the case of an invalid @var{key}.
+@end defun
+
+@defun {int rl_bind_key_in_map} (int key, Function *function, Keymap map)
+Bind @var{key} to @var{function} in @var{map}. Returns non-zero in the case
+of an invalid @var{key}.
+@end defun
+
+@defun {int rl_unbind_key} (int key)
+Make @var{key} do nothing in the currently selected keymap.
+Returns non-zero in case of error.
+@end defun
+
+@defun {int rl_unbind_key_in_map} (int key, Keymap map)
+Make @var{key} be bound to the null function in @var{map}.
+Returns non-zero in case of error.
+@end defun
+
+@defun rl_generic_bind (int type, char *keyseq, char *data, Keymap map)
+Bind the key sequence represented by the string @var{keyseq} to the arbitrary
+pointer @var{data}. @var{type} says what kind of data is pointed to by
+@var{data}; right now this can be a function (@code{ISFUNC}), a macro
+(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as
+necessary. The initial place to do bindings is in @var{map}.
+@end defun
+
+@node Function Writing
+@subsection Writing a New Function
+
+In order to write new functions for Readline, you need to know the
+calling conventions for keyboard invoked functions, and the names of the
+variables that describe the current state of the line gathered so far.
+
+@defvar {char *rl_line_buffer}
+This is the line gathered so far. You are welcome to modify the
+contents of this, but see Undoing, below.
+@end defvar
+
+@defvar {int rl_point}
+The offset of the current cursor position in @var{rl_line_buffer}.
+@end defvar
+
+@defvar {int rl_end}
+The number of characters present in @code{rl_line_buffer}. When
+@code{rl_point} is at the end of the line, then @code{rl_point} and
+@code{rl_end} are equal.
+@end defvar
+
+The calling sequence for a command @code{foo} looks like
+
+@example
+@code{foo (int count, int key)}
+@end example
+
+where @var{count} is the numeric argument (or 1 if defaulted) and
+@var{key} is the key that invoked this function.
+
+It is completely up to the function as to what should be done with the
+numeric argument; some functions use it as a repeat count, other
+functions as a flag, and some choose to ignore it. In general, if a
+function uses the numeric argument as a repeat count, it should be able
+to do something useful with a negative argument as well as a positive
+argument. At the very least, it should be aware that it can be passed a
+negative argument.
+
+@node Allowing Undoing
+@subsection Allowing Undoing
+
+Supporting the undo command is a painless thing to do, and makes your
+functions much more useful to the end user. It is certainly easy to try
+something if you know you can undo it. I could use an undo function for
+the stock market.
+
+If your function simply inserts text once, or deletes text once, and it
+calls @code{rl_insert_text ()} or @code{rl_delete_text ()} to do it, then
+undoing is already done for you automatically, and you can safely skip
+this section.
+
+If you do multiple insertions or multiple deletions, or any combination
+of these operations, you should group them together into one operation.
+This can be done with @code{rl_begin_undo_group ()} and
+@code{rl_end_undo_group ()}.
+
+@defun rl_begin_undo_group ()
+Begins saving undo information in a group construct. The undo
+information usually comes from calls to @code{rl_insert_text ()} and
+@code{rl_delete_text ()}, but they could be direct calls to
+@code{rl_add_undo ()}.
+@end defun
+
+@defun rl_end_undo_group ()
+Closes the current undo group started with @code{rl_begin_undo_group
+()}. There should be exactly one call to @code{rl_end_undo_group ()}
+for every call to @code{rl_begin_undo_group ()}.
+@end defun
+
+Finally, if you neither insert nor delete text, but directly modify the
+existing text (e.g. change its case), you call @code{rl_modifying ()}
+once, just before you modify the text. You must supply the indices of
+the text range that you are going to modify.
+
+@defun rl_modifying (int start, int end)
+Tell Readline to save the text between @var{start} and @var{end} as a
+single undo unit. It is assumed that subsequent to this call you will
+modify that range of text in some way.
+@end defun
+
+@subsection An Example
+
+Here is a function which changes lowercase characters to the uppercase
+equivalents, and uppercase characters to the lowercase equivalents. If
+this function was bound to @samp{M-c}, then typing @samp{M-c} would
+change the case of the character under point. Typing @samp{10 M-c}
+would change the case of the following 10 characters, leaving the cursor on
+the last character changed.
+
+@example
+/* Invert the case of the COUNT following characters. */
+invert_case_line (count, key)
+ int count, key;
+@{
+ register int start, end;
+
+ start = rl_point;
+
+ if (count < 0)
+ @{
+ direction = -1;
+ count = -count;
+ @}
+ else
+ direction = 1;
+
+ /* Find the end of the range to modify. */
+ end = start + (count * direction);
+
+ /* Force it to be within range. */
+ if (end > rl_end)
+ end = rl_end;
+ else if (end < 0)
+ end = -1;
+
+ if (start > end)
+ @{
+ int temp = start;
+ start = end;
+ end = temp;
+ @}
+
+ if (start == end)
+ return;
+
+ /* Tell readline that we are modifying the line, so save the undo
+ information. */
+ rl_modifying (start, end);
+
+ for (; start != end; start += direction)
+ @{
+ if (uppercase_p (rl_line_buffer[start]))
+ rl_line_buffer[start] = to_lower (rl_line_buffer[start]);
+ else if (lowercase_p (rl_line_buffer[start]))
+ rl_line_buffer[start] = to_upper (rl_line_buffer[start]);
+ @}
+ /* Move point to on top of the last character changed. */
+ rl_point = end - direction;
+@}
+@end example
+
+@node Custom Completers
+@section Custom Completers
+
+Typically, a program that reads commands from the user has a way of
+disambiguating commands and data. If your program is one of these, then
+it can provide completion for either commands, or data, or both commands
+and data. The following sections describe how your program and Readline
+cooperate to provide this service to end users.
+
+@menu
+* How Completing Works:: The logic used to do completion.
+* Completion Functions:: Functions provided by Readline.
+* Completion Variables:: Variables which control completion.
+* A Short Completion Example:: An example of writing completer subroutines.
+@end menu
+
+@node How Completing Works
+@subsection How Completing Works
+
+In order to complete some text, the full list of possible completions
+must be available. That is to say, it is not possible to accurately
+expand a partial word without knowing what all of the possible words
+that make sense in that context are. The GNU Readline library provides
+the user interface to completion, and additionally, two of the most common
+completion functions; filename and username. For completing other types
+of text, you must write your own completion function. This section
+describes exactly what those functions must do, and provides an example
+function.
+
+There are three major functions used to perform completion:
+
+@enumerate
+@item
+The user-interface function @code{rl_complete ()}. This function is
+called interactively with the same calling conventions as other
+functions in readline intended for interactive use; i.e. @var{count},
+and @var{invoking-key}. It isolates the word to be completed and calls
+@code{completion_matches ()} to generate a list of possible completions.
+It then either lists the possible completions or actually performs the
+completion, depending on which behaviour is desired.
+
+@item
+The internal function @code{completion_matches ()} uses your
+@dfn{generator} function to generate the list of possible matches, and
+then returns the array of these matches. You should place the address
+of your generator function in @code{rl_completion_entry_function}.
+
+@item
+The generator function is called repeatedly from
+@code{completion_matches ()}, returning a string each time. The
+arguments to the generator function are @var{text} and @var{state}.
+@var{text} is the partial word to be completed. @var{state} is zero the
+first time the function is called, and a positive non-zero integer for
+each subsequent call. When the generator function returns @code{(char
+*)NULL} this signals @code{completion_matches ()} that there are no more
+possibilities left.
+
+@end enumerate
+
+@defun rl_complete (int ignore, int invoking_key)
+Complete the word at or before point. You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{completion_matches ()}). The default is to do filename completion.
+@end defun
+
+Note that @code{rl_complete ()} has the identical calling conventions as
+any other key-invokable function; this is because by default it is bound
+to the @samp{TAB} key.
+
+@defvar {Function *rl_completion_entry_function}
+This is a pointer to the generator function for @code{completion_matches
+()}. If the value of @code{rl_completion_entry_function} is
+@code{(Function *)NULL} then the default filename generator function is
+used, namely @code{filename_entry_function ()}.
+@end defvar
+
+@node Completion Functions
+@subsection Completion Functions
+
+Here is the complete list of callable completion functions present in
+Readline.
+
+@defun rl_complete_internal (int what_to_do)
+Complete the word at or before point. @var{what_to_do} says what to do
+with the completion. A value of @samp{?} means list the possible
+completions. @samp{TAB} means do standard completion. @samp{*} means
+insert all of the possible completions.
+@end defun
+
+@defun rl_complete (int ignore, int invoking_key)
+Complete the word at or before point. You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{completion_matches ()}). The default is to do filename
+completion. This just calls @code{rl_complete_internal ()} with an
+argument of @samp{TAB}.
+@end defun
+
+@defun rl_possible_completions ()
+List the possible completions. See description of @code{rl_complete
+()}. This just calls @code{rl_complete_internal ()} with an argument of
+@samp{?}.
+@end defun
+
+@defun {char **completion_matches} (char *text, char *(*entry_function) ())
+Returns an array of @code{(char *)} which is a list of completions for
+@var{text}. If there are no completions, returns @code{(char **)NULL}.
+The first entry in the returned array is the substitution for @var{text}.
+The remaining entries are the possible completions. The array is
+terminated with a @code{NULL} pointer.
+
+@var{entry_function} is a function of two args, and returns a
+@code{(char *)}. The first argument is @var{text}. The second is a
+state argument; it is zero on the first call, and non-zero on subsequent
+calls. It returns a @code{NULL} pointer to the caller when there are
+no more matches.
+@end defun
+
+@defun {char *filename_completion_function} (char *text, int state)
+A generator function for filename completion in the general case. Note
+that completion in the Bash shell is a little different because of all
+the pathnames that must be followed when looking up the completion for a
+command.
+@end defun
+
+@defun {char *username_completion_function} (char *text, int state)
+A completion generator for usernames. @var{text} contains a partial
+username preceded by a random character (usually @samp{~}).
+@end defun
+
+@node Completion Variables
+@subsection Completion Variables
+
+@defvar {Function *rl_completion_entry_function}
+A pointer to the generator function for @code{completion_matches ()}.
+@code{NULL} means to use @code{filename_entry_function ()}, the default
+filename completer.
+@end defvar
+
+@defvar {Function *rl_attempted_completion_function}
+A pointer to an alternative function to create matches.
+The function is called with @var{text}, @var{start}, and @var{end}.
+@var{start} and @var{end} are indices in @code{rl_line_buffer} saying
+what the boundaries of @var{text} are. If this function exists and
+returns @code{NULL} then @code{rl_complete ()} will call the value of
+@code{rl_completion_entry_function} to generate matches, otherwise the
+array of strings returned will be used.
+@end defvar
+
+@defvar {int rl_completion_query_items}
+Up to this many items will be displayed in response to a
+possible-completions call. After that, we ask the user if she is sure
+she wants to see them all. The default value is 100.
+@end defvar
+
+@defvar {char *rl_basic_word_break_characters}
+The basic list of characters that signal a break between words for the
+completer routine. The contents of this variable is what breaks words
+in the Bash shell, i.e. " \t\n\"\\'`@@$><=;|&@{(".
+@end defvar
+
+@defvar {char *rl_completer_word_break_characters}
+The list of characters that signal a break between words for
+@code{rl_complete_internal ()}. The default list is the contents of
+@code{rl_basic_word_break_characters}.
+@end defvar
+
+@defvar {char *rl_special_prefixes}
+The list of characters that are word break characters, but should be
+left in @var{text} when it is passed to the completion function.
+Programs can use this to help determine what kind of completing to do.
+@end defvar
+
+@defvar {int rl_ignore_completion_duplicates}
+If non-zero, then disallow duplicates in the matches. Default is 1.
+@end defvar
+
+@defvar {int rl_filename_completion_desired}
+Non-zero means that the results of the matches are to be treated as
+filenames. This is @emph{always} zero on entry, and can only be changed
+within a completion entry generator function.
+@end defvar
+
+@defvar {Function *rl_ignore_some_completions_function}
+This function, if defined, is called by the completer when real filename
+completion is done, after all the matching names have been generated.
+It is passed a @code{NULL} terminated array of @code{(char *)} known as
+@var{matches} in the code. The 1st element (@code{matches[0]}) is the
+maximal substring that is common to all matches. This function can
+re-arrange the list of matches as required, but each deleted element of
+the array must be @code{free()}'d.
+@end defvar
+
+@node A Short Completion Example
+@subsection A Short Completion Example
+
+Here is a small application demonstrating the use of the GNU Readline
+library. It is called @code{fileman}, and the source code resides in
+@file{readline/examples/fileman.c}. This sample application provides
+completion of command names, line editing features, and access to the
+history list.
+
+@page
+@smallexample
+/* fileman.c -- A tiny application which demonstrates how to use the
+ GNU Readline library. This application interactively allows users
+ to manipulate files and their modes. */
+
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+/* The names of functions that actually do the manipulation. */
+int com_list (), com_view (), com_rename (), com_stat (), com_pwd ();
+int com_delete (), com_help (), com_cd (), com_quit ();
+
+/* A structure which contains information on the commands this program
+ can understand. */
+
+typedef struct @{
+ char *name; /* User printable name of the function. */
+ Function *func; /* Function to call to do the job. */
+ char *doc; /* Documentation for this function. */
+@} COMMAND;
+
+COMMAND commands[] = @{
+ @{ "cd", com_cd, "Change to directory DIR" @},
+ @{ "delete", com_delete, "Delete FILE" @},
+ @{ "help", com_help, "Display this text" @},
+ @{ "?", com_help, "Synonym for `help'" @},
+ @{ "list", com_list, "List files in DIR" @},
+ @{ "ls", com_list, "Synonym for `list'" @},
+ @{ "pwd", com_pwd, "Print the current working directory" @},
+ @{ "quit", com_quit, "Quit using Fileman" @},
+ @{ "rename", com_rename, "Rename FILE to NEWNAME" @},
+ @{ "stat", com_stat, "Print out statistics on FILE" @},
+ @{ "view", com_view, "View the contents of FILE" @},
+ @{ (char *)NULL, (Function *)NULL, (char *)NULL @}
+@};
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this global means the user is done using this program. */
+int done = 0;
+@page
+main (argc, argv)
+ int argc;
+ char **argv;
+@{
+ progname = argv[0];
+
+ initialize_readline (); /* Bind our completer. */
+
+ /* Loop reading and executing lines until the user quits. */
+ while (!done)
+ @{
+ char *line;
+
+ line = readline ("FileMan: ");
+
+ if (!line)
+ @{
+ done = 1; /* Encountered EOF at top level. */
+ @}
+ else
+ @{
+ /* Remove leading and trailing whitespace from the line.
+ Then, if there is anything left, add it to the history list
+ and execute it. */
+ stripwhite (line);
+
+ if (*line)
+ @{
+ add_history (line);
+ execute_line (line);
+ @}
+ @}
+
+ if (line)
+ free (line);
+ @}
+ exit (0);
+@}
+
+/* Execute a command line. */
+execute_line (line)
+ char *line;
+@{
+ register int i;
+ COMMAND *find_command (), *command;
+ char *word;
+
+ /* Isolate the command word. */
+ i = 0;
+ while (line[i] && !whitespace (line[i]))
+ i++;
+
+ word = line;
+
+ if (line[i])
+ line[i++] = '\0';
+
+ command = find_command (word);
+
+ if (!command)
+ @{
+ fprintf (stderr, "%s: No such command for FileMan.\n", word);
+ return;
+ @}
+
+ /* Get argument to command, if any. */
+ while (whitespace (line[i]))
+ i++;
+
+ word = line + i;
+
+ /* Call the function. */
+ (*(command->func)) (word);
+@}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+ command. Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+ char *name;
+@{
+ register int i;
+
+ for (i = 0; commands[i].name; i++)
+ if (strcmp (name, commands[i].name) == 0)
+ return (&commands[i]);
+
+ return ((COMMAND *)NULL);
+@}
+
+/* Strip whitespace from the start and end of STRING. */
+stripwhite (string)
+ char *string;
+@{
+ register int i = 0;
+
+ while (whitespace (string[i]))
+ i++;
+
+ if (i)
+ strcpy (string, string + i);
+
+ i = strlen (string) - 1;
+
+ while (i > 0 && whitespace (string[i]))
+ i--;
+
+ string[++i] = '\0';
+@}
+@page
+/* **************************************************************** */
+/* */
+/* Interface to Readline Completion */
+/* */
+/* **************************************************************** */
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+initialize_readline ()
+@{
+ char **fileman_completion ();
+
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = "FileMan";
+
+ /* Tell the completer that we want a crack first. */
+ rl_attempted_completion_function = (Function *)fileman_completion;
+@}
+
+/* Attempt to complete on the contents of TEXT. START and END show the
+ region of TEXT that contains the word to complete. We can use the
+ entire line in case we want to do some simple parsing. Return the
+ array of matches, or NULL if there aren't any. */
+char **
+fileman_completion (text, start, end)
+ char *text;
+ int start, end;
+@{
+ char **matches;
+ char *command_generator ();
+
+ matches = (char **)NULL;
+
+ /* If this word is at the start of the line, then it is a command
+ to complete. Otherwise it is the name of a file in the current
+ directory. */
+ if (start == 0)
+ matches = completion_matches (text, command_generator);
+
+ return (matches);
+@}
+
+/* Generator function for command completion. STATE lets us know whether
+ to start from scratch; without any state (i.e. STATE == 0), then we
+ start at the top of the list. */
+char *
+command_generator (text, state)
+ char *text;
+ int state;
+@{
+ static int list_index, len;
+ char *name;
+
+ /* If this is a new word to complete, initialize now. This includes
+ saving the length of TEXT for efficiency, and initializing the index
+ variable to 0. */
+ if (!state)
+ @{
+ list_index = 0;
+ len = strlen (text);
+ @}
+
+ /* Return the next name which partially matches from the command list. */
+ while (name = commands[list_index].name)
+ @{
+ list_index++;
+
+ if (strncmp (name, text, len) == 0)
+ return (name);
+ @}
+
+ /* If no names matched, then return NULL. */
+ return ((char *)NULL);
+@}
+@page
+/* **************************************************************** */
+/* */
+/* FileMan Commands */
+/* */
+/* **************************************************************** */
+
+/* String to pass to system (). This is for the LIST, VIEW and RENAME
+ commands. */
+static char syscom[1024];
+
+/* List the file(s) named in arg. */
+com_list (arg)
+ char *arg;
+@{
+ if (!arg)
+ arg = "*";
+
+ sprintf (syscom, "ls -FClg %s", arg);
+ system (syscom);
+@}
+
+com_view (arg)
+ char *arg;
+@{
+ if (!valid_argument ("view", arg))
+ return;
+
+ sprintf (syscom, "cat %s | more", arg);
+ system (syscom);
+@}
+
+com_rename (arg)
+ char *arg;
+@{
+ too_dangerous ("rename");
+@}
+
+com_stat (arg)
+ char *arg;
+@{
+ struct stat finfo;
+
+ if (!valid_argument ("stat", arg))
+ return;
+
+ if (stat (arg, &finfo) == -1)
+ @{
+ perror (arg);
+ return;
+ @}
+
+ printf ("Statistics for `%s':\n", arg);
+
+ printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
+ finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s", finfo.st_size);
+ printf (" Created on: %s", ctime (&finfo.st_ctime));
+ printf (" Last access at: %s", ctime (&finfo.st_atime));
+ printf ("Last modified at: %s", ctime (&finfo.st_mtime));
+@}
+
+com_delete (arg)
+ char *arg;
+@{
+ too_dangerous ("delete");
+@}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+ not present. */
+com_help (arg)
+ char *arg;
+@{
+ register int i;
+ int printed = 0;
+
+ for (i = 0; commands[i].name; i++)
+ @{
+ if (!*arg || (strcmp (arg, commands[i].name) == 0))
+ @{
+ printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+ printed++;
+ @}
+ @}
+
+ if (!printed)
+ @{
+ printf ("No commands match `%s'. Possibilties are:\n", arg);
+
+ for (i = 0; commands[i].name; i++)
+ @{
+ /* Print in six columns. */
+ if (printed == 6)
+ @{
+ printed = 0;
+ printf ("\n");
+ @}
+
+ printf ("%s\t", commands[i].name);
+ printed++;
+ @}
+
+ if (printed)
+ printf ("\n");
+ @}
+@}
+
+/* Change to the directory ARG. */
+com_cd (arg)
+ char *arg;
+@{
+ if (chdir (arg) == -1)
+ perror (arg);
+
+ com_pwd ("");
+@}
+
+/* Print out the current working directory. */
+com_pwd (ignore)
+ char *ignore;
+@{
+ char dir[1024];
+
+ (void) getwd (dir);
+
+ printf ("Current directory is %s\n", dir);
+@}
+
+/* The user wishes to quit using this program. Just set DONE non-zero. */
+com_quit (arg)
+ char *arg;
+@{
+ done = 1;
+@}
+
+/* Function which tells you that you can't do this. */
+too_dangerous (caller)
+ char *caller;
+@{
+ fprintf (stderr,
+ "%s: Too dangerous for me to distribute. Write it yourself.\n",
+ caller);
+@}
+
+/* Return non-zero if ARG is a valid argument for CALLER, else print
+ an error message and return zero. */
+int
+valid_argument (caller, arg)
+ char *caller, *arg;
+@{
+ if (!arg || !*arg)
+ @{
+ fprintf (stderr, "%s: Argument required.\n", caller);
+ return (0);
+ @}
+
+ return (1);
+@}
+@end smallexample
diff --git a/gnu/lib/libreadline/doc/rluser.texinfo b/gnu/lib/libreadline/doc/rluser.texinfo
new file mode 100644
index 000000000000..36a65b8fc94d
--- /dev/null
+++ b/gnu/lib/libreadline/doc/rluser.texinfo
@@ -0,0 +1,865 @@
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename rluser.info
+@comment %**end of header (This is for running Texinfo on a region.)
+@setchapternewpage odd
+
+@ignore
+This file documents the end user interface to the GNU command line
+editing features. It is to be an appendix to manuals for programs which
+use these features. There is a document entitled "readline.texinfo"
+which contains both end-user and programmer documentation for the GNU
+Readline Library.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Authored by Brian Fox and Chet Ramey.
+
+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).
+
+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
+GNU Copyright statement is available to the distributee, and provided 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.
+@end ignore
+
+@comment If you are including this manual as an appendix, then set the
+@comment variable readline-appendix.
+
+@node Command Line Editing
+@chapter Command Line Editing
+
+This chapter describes the basic features of the GNU
+command line editing interface.
+
+@menu
+* Introduction and Notation:: Notation used in this text.
+* Readline Interaction:: The minimum set of commands for editing a line.
+* Readline Init File:: Customizing Readline from a user's view.
+* Bindable Readline Commands:: A description of most of the Readline commands
+ available for binding
+* Readline vi Mode:: A short description of how to make Readline
+ behave line the vi editor.
+@end menu
+
+@node Introduction and Notation
+@section Introduction to Line Editing
+
+The following paragraphs describe the notation used to represent
+keystrokes.
+
+The text @key{C-k} is read as `Control-K' and describes the character
+produced when the Control key is depressed and the @key{k} key is struck.
+
+The text @key{M-k} is read as `Meta-K' and describes the character
+produced when the meta key (if you have one) is depressed, and the @key{k}
+key is struck. If you do not have a meta key, the identical keystroke
+can be generated by typing @key{ESC} @i{first}, and then typing @key{k}.
+Either process is known as @dfn{metafying} the @key{k} key.
+
+The text @key{M-C-k} is read as `Meta-Control-k' and describes the
+character produced by @dfn{metafying} @key{C-k}.
+
+In addition, several keys have their own names. Specifically,
+@key{DEL}, @key{ESC}, @key{LFD}, @key{SPC}, @key{RET}, and @key{TAB} all
+stand for themselves when seen in this text, or in an init file
+(@pxref{Readline Init File}, for more info).
+
+@node Readline Interaction
+@section Readline Interaction
+@cindex interaction, readline
+
+Often during an interactive session you type in a long line of text,
+only to notice that the first word on the line is misspelled. The
+Readline library gives you a set of commands for manipulating the text
+as you type it in, allowing you to just fix your typo, and not forcing
+you to retype the majority of the line. Using these editing commands,
+you move the cursor to the place that needs correction, and delete or
+insert the text of the corrections. Then, when you are satisfied with
+the line, you simply press @key{RETURN}. You do not have to be at the
+end of the line to press @key{RETURN}; the entire line is accepted
+regardless of the location of the cursor within the line.
+
+@menu
+* Readline Bare Essentials:: The least you need to know about Readline.
+* Readline Movement Commands:: Moving about the input line.
+* Readline Killing Commands:: How to delete text, and how to get it back!
+* Readline Arguments:: Giving numeric arguments to commands.
+@end menu
+
+@node Readline Bare Essentials
+@subsection Readline Bare Essentials
+
+In order to enter characters into the line, simply type them. The typed
+character appears where the cursor was, and then the cursor moves one
+space to the right. If you mistype a character, you can use your
+erase character to back up and delete the mistyped character.
+
+Sometimes you may miss typing a character that you wanted to type, and
+not notice your error until you have typed several other characters. In
+that case, you can type @key{C-b} to move the cursor to the left, and then
+correct your mistake. Afterwards, you can move the cursor to the right
+with @key{C-f}.
+
+When you add text in the middle of a line, you will notice that characters
+to the right of the cursor are `pushed over' to make room for the text
+that you have inserted. Likewise, when you delete text behind the cursor,
+characters to the right of the cursor are `pulled back' to fill in the
+blank space created by the removal of the text. A list of the basic bare
+essentials for editing the text of an input line follows.
+
+@table @asis
+@item @key{C-b}
+Move back one character.
+@item @key{C-f}
+Move forward one character.
+@item @key{DEL}
+Delete the character to the left of the cursor.
+@item @key{C-d}
+Delete the character underneath the cursor.
+@item @w{Printing characters}
+Insert the character into the line at the cursor.
+@item @key{C-_}
+Undo the last thing that you did. You can undo all the way back to an
+empty line.
+@end table
+
+@node Readline Movement Commands
+@subsection Readline Movement Commands
+
+
+The above table describes the most basic possible keystrokes that you need
+in order to do editing of the input line. For your convenience, many
+other commands have been added in addition to @key{C-b}, @key{C-f},
+@key{C-d}, and @key{DEL}. Here are some commands for moving more rapidly
+about the line.
+
+@table @key
+@item C-a
+Move to the start of the line.
+@item C-e
+Move to the end of the line.
+@item M-f
+Move forward a word.
+@item M-b
+Move backward a word.
+@item C-l
+Clear the screen, reprinting the current line at the top.
+@end table
+
+Notice how @key{C-f} moves forward a character, while @key{M-f} moves
+forward a word. It is a loose convention that control keystrokes
+operate on characters while meta keystrokes operate on words.
+
+@node Readline Killing Commands
+@subsection Readline Killing Commands
+
+@dfn{Killing} text means to delete the text from the line, but to save
+it away for later use, usually by @dfn{yanking} (re-inserting)
+it back into the line.
+If the description for a command says that it `kills' text, then you can
+be sure that you can get the text back in a different (or the same)
+place later.
+
+When you use a kill command, the text is saved in a @dfn{kill-ring}.
+Any number of consecutive kills save all of the killed text together, so
+that when you yank it back, you get it all. The kill
+ring is not line specific; the text that you killed on a previously
+typed line is available to be yanked back later, when you are typing
+another line.
+
+Here is the list of commands for killing text.
+
+@table @key
+@item C-k
+Kill the text from the current cursor position to the end of the line.
+
+@item M-d
+Kill from the cursor to the end of the current word, or if between
+words, to the end of the next word.
+
+@item M-DEL
+Kill from the cursor the start of the previous word, or if between
+words, to the start of the previous word.
+
+@item C-w
+Kill from the cursor to the previous whitespace. This is different than
+@key{M-DEL} because the word boundaries differ.
+
+@end table
+
+And, here is how to @dfn{yank} the text back into the line. Yanking
+means to copy the most-recently-killed text from the kill buffer.
+
+@table @key
+@item C-y
+Yank the most recently killed text back into the buffer at the cursor.
+
+@item M-y
+Rotate the kill-ring, and yank the new top. You can only do this if
+the prior command is @key{C-y} or @key{M-y}.
+@end table
+
+@node Readline Arguments
+@subsection Readline Arguments
+
+You can pass numeric arguments to Readline commands. Sometimes the
+argument acts as a repeat count, other times it is the @i{sign} of the
+argument that is significant. If you pass a negative argument to a
+command which normally acts in a forward direction, that command will
+act in a backward direction. For example, to kill text back to the
+start of the line, you might type @key{M--} @key{C-k}.
+
+The general way to pass numeric arguments to a command is to type meta
+digits before the command. If the first `digit' you type is a minus
+sign (@key{-}), then the sign of the argument will be negative. Once
+you have typed one meta digit to get the argument started, you can type
+the remainder of the digits, and then the command. For example, to give
+the @key{C-d} command an argument of 10, you could type @key{M-1 0 C-d}.
+
+
+@node Readline Init File
+@section Readline Init File
+
+Although the Readline library comes with a set of Emacs-like
+keybindings installed by default,
+it is possible that you would like to use a different set
+of keybindings. You can customize programs that use Readline by putting
+commands in an @dfn{init} file in your home directory. The name of this
+file is taken from the value of the shell variable @code{INPUTRC}. If
+that variable is unset, the default is @file{~/.inputrc}.
+
+When a program which uses the Readline library starts up, the
+init file is read, and the key bindings are set.
+
+In addition, the @code{C-x C-r} command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+@menu
+* Readline Init Syntax:: Syntax for the commands in the inputrc file.
+* Conditional Init Constructs:: Conditional key bindings in the inputrc file.
+@end menu
+
+@node Readline Init Syntax
+@subsection Readline Init Syntax
+
+There are only a few basic constructs allowed in the
+Readline init file. Blank lines are ignored.
+Lines beginning with a @key{#} are comments.
+Lines beginning with a @key{$} indicate conditional
+constructs (@pxref{Conditional Init Constructs}). Other lines
+denote variable settings and key bindings.
+
+@table @asis
+@item Variable Settings
+You can change the state of a few variables in Readline by
+using the @code{set} command within the init file. Here is how you
+would specify that you wish to use @code{vi} line editing commands:
+
+@example
+set editing-mode vi
+@end example
+
+Right now, there are only a few variables which can be set;
+so few, in fact, that we just list them here:
+
+@table @code
+
+@item editing-mode
+@vindex editing-mode
+The @code{editing-mode} variable controls which editing mode you are
+using. By default, Readline starts up in Emacs editing mode, where
+the keystrokes are most similar to Emacs. This variable can be
+set to either @code{emacs} or @code{vi}.
+
+@item horizontal-scroll-mode
+@vindex horizontal-scroll-mode
+This variable can be set to either @code{On} or @code{Off}. Setting it
+to @code{On} means that the text of the lines that you edit will scroll
+horizontally on a single screen line when they are longer than the width
+of the screen, instead of wrapping onto a new screen line. By default,
+this variable is set to @code{Off}.
+
+@item mark-modified-lines
+@vindex mark-modified-lines
+This variable, when set to @code{On}, says to display an asterisk
+(@samp{*}) at the start of history lines which have been modified.
+This variable is @code{off} by default.
+
+@item bell-style
+@vindex bell-style
+Controls what happens when Readline wants to ring the terminal bell.
+If set to @code{none}, Readline never rings the bell. If set to
+@code{visible}, Readline uses a visible bell if one is available.
+If set to @code{audible} (the default), Readline attempts to ring
+the terminal's bell.
+
+@item comment-begin
+@vindex comment-begin
+The string to insert at the beginning of the line when the
+@code{vi-comment} command is executed. The default value
+is @code{"#"}.
+
+@item meta-flag
+@vindex meta-flag
+If set to @code{on}, Readline will enable eight-bit input (it
+will not strip the eighth bit from the characters it reads),
+regardless of what the terminal claims it can support. The
+default value is @code{off}.
+
+@item convert-meta
+@vindex convert-meta
+If set to @code{on}, Readline will convert characters with the
+eigth bit set to an ASCII key sequence by stripping the eigth
+bit and prepending an @key{ESC} character, converting them to a
+meta-prefixed key sequence. The default value is @code{on}.
+
+@item output-meta
+@vindex output-meta
+If set to @code{on}, Readline will display characters with the
+eighth bit set directly rather than as a meta-prefixed escape
+sequence. The default is @code{off}.
+
+@item completion-query-items
+@vindex completion-query-items
+The number of possible completions that determines when the user is
+asked whether he wants to see the list of possibilities. If the
+number of possible completions is greater than this value,
+Readline will ask the user whether or not he wishes to view
+them; otherwise, they are simply listed. The default limit is
+@code{100}.
+
+@item keymap
+@vindex keymap
+Sets Readline's idea of the current keymap for key binding commands.
+Acceptable @code{keymap} names are
+@code{emacs},
+@code{emacs-standard},
+@code{emacs-meta},
+@code{emacs-ctlx},
+@code{vi},
+@code{vi-move},
+@code{vi-command}, and
+@code{vi-insert}.
+@code{vi} is equivalent to @code{vi-command}; @code{emacs} is
+equivalent to @code{emacs-standard}. The default value is @code{emacs}.
+The value of the @code{editing-mode} variable also affects the
+default keymap.
+
+@item show-all-if-ambiguous
+@vindex show-all-if-ambiguous
+This alters the default behavior of the completion functions. If
+set to @code{on},
+words which have more than one possible completion cause the
+matches to be listed immediately instead of ringing the bell.
+The default value is @code{off}.
+
+@item expand-tilde
+@vindex expand-tilde
+If set to @code{on}, tilde expansion is performed when Readline
+attempts word completion. The default is @code{off}.
+
+@end table
+
+@item Key Bindings
+The syntax for controlling key bindings in the init file is
+simple. First you have to know the name of the command that you
+want to change. The following pages contain tables of the command name,
+the default keybinding, and a short description of what the command
+does.
+
+Once you know the name of the command, simply place the name of the key
+you wish to bind the command to, a colon, and then the name of the
+command on a line in the init file. The name of the key
+can be expressed in different ways, depending on which is most
+comfortable for you.
+
+@table @asis
+@item @w{@var{keyname}: @var{function-name} or @var{macro}}
+@var{keyname} is the name of a key spelled out in English. For example:
+@example
+Control-u: universal-argument
+Meta-Rubout: backward-kill-word
+Control-o: ">&output"
+@end example
+
+In the above example, @samp{C-u} is bound to the function
+@code{universal-argument}, and @samp{C-o} is bound to run the macro
+expressed on the right hand side (that is, to insert the text
+@samp{>&output} into the line).
+
+@item @w{"@var{keyseq}": @var{function-name} or @var{macro}}
+@var{keyseq} differs from @var{keyname} above in that strings
+denoting an entire key sequence can be specified, by placing
+the key sequence in double quotes. Some GNU Emacs style key
+escapes can be used, as in the following example, but the
+special character names are not recognized.
+
+@example
+"\C-u": universal-argument
+"\C-x\C-r": re-read-init-file
+"\e[11~": "Function Key 1"
+@end example
+
+In the above example, @samp{C-u} is bound to the function
+@code{universal-argument} (just as it was in the first example),
+@samp{C-x C-r} is bound to the function @code{re-read-init-file}, and
+@samp{ESC [ 1 1 ~} is bound to insert the text @samp{Function Key 1}.
+The following escape sequences are available when specifying key
+sequences:
+
+@table @code
+@item @kbd{\C-}
+control prefix
+@item @kbd{\M-}
+meta prefix
+@item @kbd{\e}
+an escape character
+@item @kbd{\\}
+backslash
+@item @kbd{\"}
+@key{"}
+@item @kbd{\'}
+@key{'}
+@end table
+
+When entering the text of a macro, single or double quotes should
+be used to indicate a macro definition. Unquoted text
+is assumed to be a function name. Backslash
+will quote any character in the macro text, including @key{"}
+and @key{'}.
+For example, the following binding will make @kbd{C-x \}
+insert a single @key{\} into the line:
+@example
+"\C-x\\": "\\"
+@end example
+
+@end table
+@end table
+
+@node Conditional Init Constructs
+@subsection Conditional Init Constructs
+
+Readline implements a facility similar in spirit to the conditional
+compilation features of the C preprocessor which allows key
+bindings and variable settings to be performed as the result
+of tests. There are three parser directives used.
+
+@ftable @code
+@item $if
+The @code{$if} construct allows bindings to be made based on the
+editing mode, the terminal being used, or the application using
+Readline. The text of the test extends to the end of the line;
+no characters are required to isolate it.
+
+@table @code
+@item mode
+The @code{mode=} form of the @code{$if} directive is used to test
+whether Readline is in @code{emacs} or @code{vi} mode.
+This may be used in conjunction
+with the @samp{set keymap} command, for instance, to set bindings in
+the @code{emacs-standard} and @code{emacs-ctlx} keymaps only if
+Readline is starting out in @code{emacs} mode.
+
+@item term
+The @code{term=} form may be used to include terminal-specific
+key bindings, perhaps to bind the key sequences output by the
+terminal's function keys. The word on the right side of the
+@samp{=} is tested against the full name of the terminal and the
+portion of the terminal name before the first @samp{-}. This
+allows @var{sun} to match both @var{sun} and @var{sun-cmd},
+for instance.
+
+@item application
+The @var{application} construct is used to include
+application-specific settings. Each program using the Readline
+library sets the @var{application name}, and you can test for it.
+This could be used to bind key sequences to functions useful for
+a specific program. For instance, the following command adds a
+key sequence that quotes the current or previous word in Bash:
+@example
+$if bash
+# Quote the current or previous word
+"\C-xq": "\eb\"\ef\""
+$endif
+@end example
+@end table
+
+@item $endif
+This command, as you saw in the previous example, terminates an
+@code{$if} command.
+
+@item $else
+Commands in this branch of the @code{$if} directive are executed if
+the test fails.
+@end ftable
+
+@node Bindable Readline Commands
+@section Bindable Readline Commands
+
+@menu
+* Commands For Moving:: Moving about the line.
+* Commands For History:: Getting at previous lines.
+* Commands For Text:: Commands for changing text.
+* Commands For Killing:: Commands for killing and yanking.
+* Numeric Arguments:: Specifying numeric arguments, repeat counts.
+* Commands For Completion:: Getting Readline to do the typing for you.
+* Keyboard Macros:: Saving and re-executing typed characters
+* Miscellaneous Commands:: Other miscellaneous commands.
+@end menu
+
+@node Commands For Moving
+@subsection Commands For Moving
+@ftable @code
+@item beginning-of-line (C-a)
+Move to the start of the current line.
+
+@item end-of-line (C-e)
+Move to the end of the line.
+
+@item forward-char (C-f)
+Move forward a character.
+
+@item backward-char (C-b)
+Move back a character.
+
+@item forward-word (M-f)
+Move forward to the end of the next word. Words are composed of
+letters and digits.
+
+@item backward-word (M-b)
+Move back to the start of this, or the previous, word. Words are
+composed of letters and digits.
+
+@item clear-screen (C-l)
+Clear the screen and redraw the current line,
+leaving the current line at the top of the screen.
+
+@item redraw-current-line ()
+Refresh the current line. By default, this is unbound.
+
+@end ftable
+
+@node Commands For History
+@subsection Commands For Manipulating The History
+
+@ftable @code
+@item accept-line (Newline, Return)
+@ifset BashFeatures
+Accept the line regardless of where the cursor is. If this line is
+non-empty, add it to the history list according to the setting of
+the @code{HISTCONTROL} variable. If this line was a history
+line, then restore the history line to its original state.
+@end ifset
+@ifclear BashFeatures
+Accept the line regardless of where the cursor is. If this line is
+non-empty, add it to the history list. If this line was a history
+line, then restore the history line to its original state.
+@end ifclear
+
+@item previous-history (C-p)
+Move `up' through the history list.
+
+@item next-history (C-n)
+Move `down' through the history list.
+
+@item beginning-of-history (M-<)
+Move to the first line in the history.
+
+@item end-of-history (M->)
+Move to the end of the input history, i.e., the line you are entering.
+
+@item reverse-search-history (C-r)
+Search backward starting at the current line and moving `up' through
+the history as necessary. This is an incremental search.
+
+@item forward-search-history (C-s)
+Search forward starting at the current line and moving `down' through
+the the history as necessary. This is an incremental search.
+
+@item non-incremental-reverse-search-history (M-p)
+Search backward starting at the current line and moving `up'
+through the history as necessary using a non-incremental search
+for a string supplied by the user.
+
+@item non-incremental-forward-search-history (M-n)
+Search forward starting at the current line and moving `down'
+through the the history as necessary using a non-incremental search
+for a string supplied by the user.
+
+@item history-search-forward ()
+Search forward through the history for the string of characters
+between the start of the current line and the current point. This
+is a non-incremental search. By default, this command is unbound.
+
+@item history-search-backward ()
+Search backward through the history for the string of characters
+between the start of the current line and the current point. This
+is a non-incremental search. By default, this command is unbound.
+
+@item yank-nth-arg (M-C-y)
+Insert the first argument to the previous command (usually
+the second word on the previous line). With an argument @var{n},
+insert the @var{n}th word from the previous command (the words
+in the previous command begin with word 0). A negative argument
+inserts the @var{n}th word from the end of the previous command.
+
+@end ftable
+
+@node Commands For Text
+@subsection Commands For Changing Text
+
+@ftable @code
+@item delete-char (C-d)
+Delete the character under the cursor. If the cursor is at the
+beginning of the line, there are no characters in the line, and
+the last character typed was not C-d, then return EOF.
+
+@item backward-delete-char (Rubout)
+Delete the character behind the cursor. A numeric arg says to kill
+the characters instead of deleting them.
+
+@item quoted-insert (C-q, C-v)
+Add the next character that you type to the line verbatim. This is
+how to insert key sequences like @key{C-q}, for example.
+
+@item tab-insert (M-TAB)
+Insert a tab character.
+
+@item self-insert (a, b, A, 1, !, ...)
+Insert yourself.
+
+@item transpose-chars (C-t)
+Drag the character before the cursor forward over
+the character at the cursor, moving the
+cursor forward as well. If the insertion point
+is at the end of the line, then this
+transposes the last two characters of the line.
+Negative argumentss don't work.
+
+@item transpose-words (M-t)
+Drag the word behind the cursor past the word in front of the cursor
+moving the cursor over that word as well.
+
+@item upcase-word (M-u)
+Uppercase the current (or following) word. With a negative argument,
+do the previous word, but do not move the cursor.
+
+@item downcase-word (M-l)
+Lowercase the current (or following) word. With a negative argument,
+do the previous word, but do not move the cursor.
+
+@item capitalize-word (M-c)
+Capitalize the current (or following) word. With a negative argument,
+do the previous word, but do not move the cursor.
+
+@end ftable
+
+@node Commands For Killing
+@subsection Killing And Yanking
+
+@ftable @code
+
+@item kill-line (C-k)
+Kill the text from the current cursor position to the end of the line.
+
+@item backward-kill-line (C-x Rubout)
+Kill backward to the beginning of the line.
+
+@item unix-line-discard (C-u)
+Kill backward from the cursor to the beginning of the current line.
+Save the killed text on the kill-ring.
+
+@item kill-whole-line ()
+Kill all characters on the current line, no matter where the
+cursor is. By default, this is unbound.
+
+@item kill-word (M-d)
+Kill from the cursor to the end of the current word, or if between
+words, to the end of the next word. Word boundaries are the same
+as @code{forward-word}.
+
+@item backward-kill-word (M-DEL)
+Kill the word behind the cursor. Word boundaries are the same
+as @code{backward-word}.
+
+@item unix-word-rubout (C-w)
+Kill the word behind the cursor, using white space as a word
+boundary. The killed text is saved on the kill-ring.
+
+@item delete-horizontal-space ()
+Delete all spaces and tabs around point. By default, this is unbound.
+
+@item yank (C-y)
+Yank the top of the kill ring into the buffer at the current
+cursor position.
+
+@item yank-pop (M-y)
+Rotate the kill-ring, and yank the new top. You can only do this if
+the prior command is yank or yank-pop.
+@end ftable
+
+@node Numeric Arguments
+@subsection Specifying Numeric Arguments
+@ftable @code
+
+@item digit-argument (M-0, M-1, ... M--)
+Add this digit to the argument already accumulating, or start a new
+argument. M-- starts a negative argument.
+
+@item universal-argument ()
+Each time this is executed, the argument count is multiplied by four.
+The argument count is initially one, so executing this function the
+first time makes the argument count four. By default, this is not
+bound to a key.
+@end ftable
+
+@node Commands For Completion
+@subsection Letting Readline Type For You
+
+@ftable @code
+@item complete (TAB)
+Attempt to do completion on the text before the cursor. This is
+implementation defined. Generally, if you are typing a filename
+argument, you can do filename completion; if you are typing a command,
+you can do command completion, if you are typing in a symbol to GDB, you
+can do symbol name completion, if you are typing in a variable to Bash,
+you can do variable name completion, and so on.
+@ifset BashFeatures
+See the Bash manual page for a complete list of available completion
+functions.
+@end ifset
+
+@item possible-completions (M-?)
+List the possible completions of the text before the cursor.
+
+@item insert-completions ()
+Insert all completions of the text before point that would have
+been generated by @code{possible-completions}. By default, this
+is not bound to a key.
+
+@end ftable
+
+@node Keyboard Macros
+@subsection Keyboard Macros
+@ftable @code
+
+@item start-kbd-macro (C-x ()
+Begin saving the characters typed into the current keyboard macro.
+
+@item end-kbd-macro (C-x ))
+Stop saving the characters typed into the current keyboard macro
+and save the definition.
+
+@item call-last-kbd-macro (C-x e)
+Re-execute the last keyboard macro defined, by making the characters
+in the macro appear as if typed at the keyboard.
+
+@end ftable
+
+@node Miscellaneous Commands
+@subsection Some Miscellaneous Commands
+@ftable @code
+
+@item re-read-init-file (C-x C-r)
+Read in the contents of your init file, and incorporate
+any bindings or variable assignments found there.
+
+@item abort (C-g)
+Abort the current editing command and
+ring the terminal's bell (subject to the setting of
+@code{bell-style}).
+
+@item do-uppercase-version (M-a, M-b, ...)
+Run the command that is bound to the corresoponding uppercase
+character.
+
+@item prefix-meta (ESC)
+Make the next character that you type be metafied. This is for people
+without a meta key. Typing @samp{ESC f} is equivalent to typing
+@samp{M-f}.
+
+@item undo (C-_, C-x C-u)
+Incremental undo, separately remembered for each line.
+
+@item revert-line (M-r)
+Undo all changes made to this line. This is like typing the @code{undo}
+command enough times to get back to the beginning.
+
+@item tilde-expand (M-~)
+Perform tilde expansion on the current word.
+
+@item dump-functions ()
+Print all of the functions and their key bindings to the
+readline output stream. If a numeric argument is supplied,
+the output is formatted in such a way that it can be made part
+of an @var{inputrc} file.
+
+@ifset BashFeatures
+@item display-shell-version (C-x C-v)
+Display version information about the current instance of Bash.
+
+@item shell-expand-line (M-C-e)
+Expand the line the way the shell does when it reads it. This
+performs alias and history expansion as well as all of the shell
+word expansions.
+
+@item history-expand-line (M-^)
+Perform history expansion on the current line.
+
+@item insert-last-argument (M-., M-_)
+Insert the last argument to the previous command (the last word on
+the previous line). With an argument @var{n},
+insert the @var{n}th word from the previous command (the words
+in the previous command begin with word 0). A negative argument
+inserts the @var{n}th word from the end of the previous command.
+
+@item operate-and-get-next (C-o)
+Accept the current line for execution and fetch the next line
+relative to the current line from the history for editing. Any
+argument is ignored.
+
+@item emacs-editing-mode (C-e)
+When in @code{vi} editing mode, this causes a switch back to
+emacs editing mode, as if the command @code{set -o emacs} had
+been executed.
+
+@end ifset
+
+@end ftable
+
+@node Readline vi Mode
+@section Readline vi Mode
+
+While the Readline library does not have a full set of @code{vi}
+editing functions, it does contain enough to allow simple editing
+of the line. The Readline @code{vi} mode behaves as specified in
+the Posix 1003.2 standard.
+
+@ifset BashFeatures
+In order to switch interactively between @code{Emacs} and @code{Vi}
+editing modes, use the @code{set -o emacs} and @code{set -o vi}
+commands (@pxref{The Set Builtin}).
+@end ifset
+@ifclear BashFeatures
+In order to switch interactively between @code{Emacs} and @code{Vi}
+editing modes, use the command M-C-j (toggle-editing-mode).
+@end ifclear
+The Readline default is @code{emacs} mode.
+
+When you enter a line in @code{vi} mode, you are already placed in
+`insertion' mode, as if you had typed an @samp{i}. Pressing @key{ESC}
+switches you into `command' mode, where you can edit the text of the
+line with the standard @code{vi} movement keys, move to previous
+history lines with @samp{k}, and following lines with @samp{j}, and
+so forth.
diff --git a/gnu/lib/libreadline/doc/texindex.c b/gnu/lib/libreadline/doc/texindex.c
new file mode 100644
index 000000000000..9233bab12690
--- /dev/null
+++ b/gnu/lib/libreadline/doc/texindex.c
@@ -0,0 +1,1666 @@
+/* Prepare TeX index dribble output into an actual index.
+
+ Version 1.45
+
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "getopt.h"
+#include "bashansi.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#else /* !HAVE_UNISTD_H */
+extern long lseek ();
+#endif /* !HAVE_UNISTD_H */
+
+extern char *mktemp ();
+
+#if !defined (HAVE_STRERROR)
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif
+
+#include <sys/types.h>
+
+#if defined (_AIX) || !defined (_POSIX_VERSION)
+# include <sys/file.h>
+#endif
+
+#include <fcntl.h>
+
+#define TI_NO_ERROR 0
+#define TI_FATAL_ERROR 1
+
+#if !defined (SEEK_SET)
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif /* !SEEK_SET */
+
+/* When sorting in core, this structure describes one line
+ and the position and length of its first keyfield. */
+struct lineinfo
+{
+ char *text; /* The actual text of the line. */
+ union {
+ char *text; /* The start of the key (for textual comparison). */
+ long number; /* The numeric value (for numeric comparison). */
+ } key;
+ long keylen; /* Length of KEY field. */
+};
+
+/* This structure describes a field to use as a sort key. */
+struct keyfield
+{
+ int startwords; /* Number of words to skip. */
+ int startchars; /* Number of additional chars to skip. */
+ int endwords; /* Number of words to ignore at end. */
+ int endchars; /* Ditto for characters of last word. */
+ char ignore_blanks; /* Non-zero means ignore spaces and tabs. */
+ char fold_case; /* Non-zero means case doesn't matter. */
+ char reverse; /* Non-zero means compare in reverse order. */
+ char numeric; /* Non-zeros means field is ASCII numeric. */
+ char positional; /* Sort according to file position. */
+ char braced; /* Count balanced-braced groupings as fields. */
+};
+
+/* Vector of keyfields to use. */
+struct keyfield keyfields[3];
+
+/* Number of keyfields stored in that vector. */
+int num_keyfields = 3;
+
+/* Vector of input file names, terminated with a null pointer. */
+char **infiles;
+
+/* Vector of corresponding output file names, or NULL, meaning default it
+ (add an `s' to the end). */
+char **outfiles;
+
+/* Length of `infiles'. */
+int num_infiles;
+
+/* Pointer to the array of pointers to lines being sorted. */
+char **linearray;
+
+/* The allocated length of `linearray'. */
+long nlines;
+
+/* Directory to use for temporary files. On Unix, it ends with a slash. */
+char *tempdir;
+
+/* Start of filename to use for temporary files. */
+char *tempbase;
+
+/* Number of last temporary file. */
+int tempcount;
+
+/* Number of last temporary file already deleted.
+ Temporary files are deleted by `flush_tempfiles' in order of creation. */
+int last_deleted_tempcount;
+
+/* During in-core sort, this points to the base of the data block
+ which contains all the lines of data. */
+char *text_base;
+
+/* Additional command switches .*/
+
+/* Nonzero means do not delete tempfiles -- for debugging. */
+int keep_tempfiles;
+
+/* The name this program was run with. */
+char *program_name;
+
+/* Forward declarations of functions in this file. */
+
+void decode_command ();
+void sort_in_core ();
+void sort_offline ();
+char **parsefile ();
+char *find_field ();
+char *find_pos ();
+long find_value ();
+char *find_braced_pos ();
+char *find_braced_end ();
+void writelines ();
+int compare_field ();
+int compare_full ();
+long readline ();
+int merge_files ();
+int merge_direct ();
+void pfatal_with_name ();
+void fatal ();
+void error ();
+void *xmalloc (), *xrealloc ();
+char *concat ();
+char *maketempname ();
+void flush_tempfiles ();
+char *tempcopy ();
+
+#define MAX_IN_CORE_SORT 500000
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ tempcount = 0;
+ last_deleted_tempcount = 0;
+ program_name = argv[0];
+
+ /* Describe the kind of sorting to do. */
+ /* The first keyfield uses the first braced field and folds case. */
+ keyfields[0].braced = 1;
+ keyfields[0].fold_case = 1;
+ keyfields[0].endwords = -1;
+ keyfields[0].endchars = -1;
+
+ /* The second keyfield uses the second braced field, numerically. */
+ keyfields[1].braced = 1;
+ keyfields[1].numeric = 1;
+ keyfields[1].startwords = 1;
+ keyfields[1].endwords = -1;
+ keyfields[1].endchars = -1;
+
+ /* The third keyfield (which is ignored while discarding duplicates)
+ compares the whole line. */
+ keyfields[2].endwords = -1;
+ keyfields[2].endchars = -1;
+
+ decode_command (argc, argv);
+
+ tempbase = mktemp (concat ("txiXXXXXX", "", ""));
+
+ /* Process input files completely, one by one. */
+
+ for (i = 0; i < num_infiles; i++)
+ {
+ int desc;
+ long ptr;
+ char *outfile;
+
+ desc = open (infiles[i], O_RDONLY, 0);
+ if (desc < 0)
+ pfatal_with_name (infiles[i]);
+ lseek (desc, 0L, SEEK_END);
+ ptr = lseek (desc, 0L, SEEK_CUR);
+
+ close (desc);
+
+ outfile = outfiles[i];
+ if (!outfile)
+ {
+ outfile = concat (infiles[i], "s", "");
+ }
+
+ if (ptr < MAX_IN_CORE_SORT)
+ /* Sort a small amount of data. */
+ sort_in_core (infiles[i], ptr, outfile);
+ else
+ sort_offline (infiles[i], ptr, outfile);
+ }
+
+ flush_tempfiles (tempcount);
+ exit (TI_NO_ERROR);
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [-k] infile [-o outfile] ...\n", program_name);
+ exit (1);
+}
+
+/* Decode the command line arguments to set the parameter variables
+ and set up the vector of keyfields and the vector of input files. */
+
+void
+decode_command (argc, argv)
+ int argc;
+ char **argv;
+{
+ int optc;
+ char **ip;
+ char **op;
+
+ /* Store default values into parameter variables. */
+
+ tempdir = getenv ("TMPDIR");
+ if (tempdir == NULL)
+ tempdir = "/tmp/";
+ else
+ tempdir = concat (tempdir, "/", "");
+
+ keep_tempfiles = 0;
+
+ /* Allocate ARGC input files, which must be enough. */
+
+ infiles = (char **) xmalloc (argc * sizeof (char *));
+ outfiles = (char **) xmalloc (argc * sizeof (char *));
+ ip = infiles;
+ op = outfiles;
+
+ while ((optc = getopt (argc, argv, "-ko:")) != EOF)
+ {
+ switch (optc)
+ {
+ case 1: /* Non-option filename. */
+ *ip++ = optarg;
+ *op++ = NULL;
+ break;
+
+ case 'k':
+ keep_tempfiles = 1;
+ break;
+
+ case 'o':
+ if (op > outfiles)
+ *(op - 1) = optarg;
+ break;
+
+ default:
+ usage ();
+ }
+ }
+
+ /* Record number of keyfields and terminate list of filenames. */
+ num_infiles = ip - infiles;
+ *ip = 0;
+ if (num_infiles == 0)
+ usage ();
+}
+
+/* Return a name for a temporary file. */
+
+char *
+maketempname (count)
+ int count;
+{
+ char tempsuffix[10];
+ sprintf (tempsuffix, "%d", count);
+ return concat (tempdir, tempbase, tempsuffix);
+}
+
+/* Delete all temporary files up to TO_COUNT. */
+
+void
+flush_tempfiles (to_count)
+ int to_count;
+{
+ if (keep_tempfiles)
+ return;
+ while (last_deleted_tempcount < to_count)
+ unlink (maketempname (++last_deleted_tempcount));
+}
+
+/* Copy the input file open on IDESC into a temporary file
+ and return the temporary file name. */
+
+#define BUFSIZE 1024
+
+char *
+tempcopy (idesc)
+ int idesc;
+{
+ char *outfile = maketempname (++tempcount);
+ int odesc;
+ char buffer[BUFSIZE];
+
+ odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
+
+ if (odesc < 0)
+ pfatal_with_name (outfile);
+
+ while (1)
+ {
+ int nread = read (idesc, buffer, BUFSIZE);
+ write (odesc, buffer, nread);
+ if (!nread)
+ break;
+ }
+
+ close (odesc);
+
+ return outfile;
+}
+
+/* Compare LINE1 and LINE2 according to the specified set of keyfields. */
+
+int
+compare_full (line1, line2)
+ char **line1, **line2;
+{
+ int i;
+
+ /* Compare using the first keyfield;
+ if that does not distinguish the lines, try the second keyfield;
+ and so on. */
+
+ for (i = 0; i < num_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], *line1, &length1);
+ char *start2 = find_field (&keyfields[i], *line2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
+ start2, length2, *line2 - text_base);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Compare LINE1 and LINE2, described by structures
+ in which the first keyfield is identified in advance.
+ For positional sorting, assumes that the order of the lines in core
+ reflects their nominal order. */
+
+int
+compare_prepared (line1, line2)
+ struct lineinfo *line1, *line2;
+{
+ int i;
+ int tem;
+ char *text1, *text2;
+
+ /* Compare using the first keyfield, which has been found for us already. */
+ if (keyfields->positional)
+ {
+ if (line1->text - text_base > line2->text - text_base)
+ tem = 1;
+ else
+ tem = -1;
+ }
+ else if (keyfields->numeric)
+ tem = line1->key.number - line2->key.number;
+ else
+ tem = compare_field (keyfields, line1->key.text, line1->keylen, 0,
+ line2->key.text, line2->keylen, 0);
+ if (tem)
+ {
+ if (keyfields->reverse)
+ return -tem;
+ return tem;
+ }
+
+ text1 = line1->text;
+ text2 = line2->text;
+
+ /* Compare using the second keyfield;
+ if that does not distinguish the lines, try the third keyfield;
+ and so on. */
+
+ for (i = 1; i < num_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], text1, &length1);
+ char *start2 = find_field (&keyfields[i], text2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
+ start2, length2, text2 - text_base);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Like compare_full but more general.
+ You can pass any strings, and you can say how many keyfields to use.
+ POS1 and POS2 should indicate the nominal positional ordering of
+ the two lines in the input. */
+
+int
+compare_general (str1, str2, pos1, pos2, use_keyfields)
+ char *str1, *str2;
+ long pos1, pos2;
+ int use_keyfields;
+{
+ int i;
+
+ /* Compare using the first keyfield;
+ if that does not distinguish the lines, try the second keyfield;
+ and so on. */
+
+ for (i = 0; i < use_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], str1, &length1);
+ char *start2 = find_field (&keyfields[i], str2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, pos1,
+ start2, length2, pos2);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Find the start and length of a field in STR according to KEYFIELD.
+ A pointer to the starting character is returned, and the length
+ is stored into the int that LENGTHPTR points to. */
+
+char *
+find_field (keyfield, str, lengthptr)
+ struct keyfield *keyfield;
+ char *str;
+ long *lengthptr;
+{
+ char *start;
+ char *end;
+ char *(*fun) ();
+
+ if (keyfield->braced)
+ fun = find_braced_pos;
+ else
+ fun = find_pos;
+
+ start = (*fun) (str, keyfield->startwords, keyfield->startchars,
+ keyfield->ignore_blanks);
+ if (keyfield->endwords < 0)
+ {
+ if (keyfield->braced)
+ end = find_braced_end (start);
+ else
+ {
+ end = start;
+ while (*end && *end != '\n')
+ end++;
+ }
+ }
+ else
+ {
+ end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0);
+ if (end - str < start - str)
+ end = start;
+ }
+ *lengthptr = end - start;
+ return start;
+}
+
+/* Return a pointer to a specified place within STR,
+ skipping (from the beginning) WORDS words and then CHARS chars.
+ If IGNORE_BLANKS is nonzero, we skip all blanks
+ after finding the specified word. */
+
+char *
+find_pos (str, words, chars, ignore_blanks)
+ char *str;
+ int words, chars;
+ int ignore_blanks;
+{
+ int i;
+ char *p = str;
+
+ for (i = 0; i < words; i++)
+ {
+ char c;
+ /* Find next bunch of nonblanks and skip them. */
+ while ((c = *p) == ' ' || c == '\t')
+ p++;
+ while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t'))
+ p++;
+ if (!*p || *p == '\n')
+ return p;
+ }
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ for (i = 0; i < chars; i++)
+ {
+ if (!*p || *p == '\n')
+ break;
+ p++;
+ }
+ return p;
+}
+
+/* Like find_pos but assumes that each field is surrounded by braces
+ and that braces within fields are balanced. */
+
+char *
+find_braced_pos (str, words, chars, ignore_blanks)
+ char *str;
+ int words, chars;
+ int ignore_blanks;
+{
+ int i;
+ int bracelevel;
+ char *p = str;
+ char c;
+
+ for (i = 0; i < words; i++)
+ {
+ bracelevel = 1;
+ while ((c = *p++) != '{' && c != '\n' && c)
+ /* Do nothing. */ ;
+ if (c != '{')
+ return p - 1;
+ while (bracelevel)
+ {
+ c = *p++;
+ if (c == '{')
+ bracelevel++;
+ if (c == '}')
+ bracelevel--;
+ if (c == 0 || c == '\n')
+ return p - 1;
+ }
+ }
+
+ while ((c = *p++) != '{' && c != '\n' && c)
+ /* Do nothing. */ ;
+
+ if (c != '{')
+ return p - 1;
+
+ if (ignore_blanks)
+ while ((c = *p) == ' ' || c == '\t')
+ p++;
+
+ for (i = 0; i < chars; i++)
+ {
+ if (!*p || *p == '\n')
+ break;
+ p++;
+ }
+ return p;
+}
+
+/* Find the end of the balanced-brace field which starts at STR.
+ The position returned is just before the closing brace. */
+
+char *
+find_braced_end (str)
+ char *str;
+{
+ int bracelevel;
+ char *p = str;
+ char c;
+
+ bracelevel = 1;
+ while (bracelevel)
+ {
+ c = *p++;
+ if (c == '{')
+ bracelevel++;
+ if (c == '}')
+ bracelevel--;
+ if (c == 0 || c == '\n')
+ return p - 1;
+ }
+ return p - 1;
+}
+
+long
+find_value (start, length)
+ char *start;
+ long length;
+{
+ while (length != 0L)
+ {
+ if (isdigit (*start))
+ return atol (start);
+ length--;
+ start++;
+ }
+ return 0l;
+}
+
+/* Vector used to translate characters for comparison.
+ This is how we make all alphanumerics follow all else,
+ and ignore case in the first sorting. */
+int char_order[256];
+
+void
+init_char_order ()
+{
+ int i;
+ for (i = 1; i < 256; i++)
+ char_order[i] = i;
+
+ for (i = '0'; i <= '9'; i++)
+ char_order[i] += 512;
+
+ for (i = 'a'; i <= 'z'; i++)
+ {
+ char_order[i] = 512 + i;
+ char_order[i + 'A' - 'a'] = 512 + i;
+ }
+}
+
+/* Compare two fields (each specified as a start pointer and a character count)
+ according to KEYFIELD.
+ The sign of the value reports the relation between the fields. */
+
+int
+compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
+ struct keyfield *keyfield;
+ char *start1;
+ long length1;
+ long pos1;
+ char *start2;
+ long length2;
+ long pos2;
+{
+ if (keyfields->positional)
+ {
+ if (pos1 > pos2)
+ return 1;
+ else
+ return -1;
+ }
+ if (keyfield->numeric)
+ {
+ long value = find_value (start1, length1) - find_value (start2, length2);
+ if (value > 0)
+ return 1;
+ if (value < 0)
+ return -1;
+ return 0;
+ }
+ else
+ {
+ char *p1 = start1;
+ char *p2 = start2;
+ char *e1 = start1 + length1;
+ char *e2 = start2 + length2;
+
+ while (1)
+ {
+ int c1, c2;
+
+ if (p1 == e1)
+ c1 = 0;
+ else
+ c1 = *p1++;
+ if (p2 == e2)
+ c2 = 0;
+ else
+ c2 = *p2++;
+
+ if (char_order[c1] != char_order[c2])
+ return char_order[c1] - char_order[c2];
+ if (!c1)
+ break;
+ }
+
+ /* Strings are equal except possibly for case. */
+ p1 = start1;
+ p2 = start2;
+ while (1)
+ {
+ int c1, c2;
+
+ if (p1 == e1)
+ c1 = 0;
+ else
+ c1 = *p1++;
+ if (p2 == e2)
+ c2 = 0;
+ else
+ c2 = *p2++;
+
+ if (c1 != c2)
+ /* Reverse sign here so upper case comes out last. */
+ return c2 - c1;
+ if (!c1)
+ break;
+ }
+
+ return 0;
+ }
+}
+
+/* A `struct linebuffer' is a structure which holds a line of text.
+ `readline' reads a line from a stream into a linebuffer
+ and works regardless of the length of the line. */
+
+struct linebuffer
+{
+ long size;
+ char *buffer;
+};
+
+/* Initialize LINEBUFFER for use. */
+
+void
+initbuffer (linebuffer)
+ struct linebuffer *linebuffer;
+{
+ linebuffer->size = 200;
+ linebuffer->buffer = (char *) xmalloc (200);
+}
+
+/* Read a line of text from STREAM into LINEBUFFER.
+ Return the length of the line. */
+
+long
+readline (linebuffer, stream)
+ struct linebuffer *linebuffer;
+ FILE *stream;
+{
+ char *buffer = linebuffer->buffer;
+ char *p = linebuffer->buffer;
+ char *end = p + linebuffer->size;
+
+ while (1)
+ {
+ int c = getc (stream);
+ if (p == end)
+ {
+ buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
+ p += buffer - linebuffer->buffer;
+ end += buffer - linebuffer->buffer;
+ linebuffer->buffer = buffer;
+ }
+ if (c < 0 || c == '\n')
+ {
+ *p = 0;
+ break;
+ }
+ *p++ = c;
+ }
+
+ return p - buffer;
+}
+
+/* Sort an input file too big to sort in core. */
+
+void
+sort_offline (infile, nfiles, total, outfile)
+ char *infile;
+ int nfiles;
+ long total;
+ char *outfile;
+{
+ /* More than enough. */
+ int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;
+ char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+ FILE *istream = fopen (infile, "r");
+ int i;
+ struct linebuffer lb;
+ long linelength;
+ int failure = 0;
+
+ initbuffer (&lb);
+
+ /* Read in one line of input data. */
+
+ linelength = readline (&lb, istream);
+
+ if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ /* Split up the input into `ntemps' temporary files, or maybe fewer,
+ and put the new files' names into `tempfiles' */
+
+ for (i = 0; i < ntemps; i++)
+ {
+ char *outname = maketempname (++tempcount);
+ FILE *ostream = fopen (outname, "w");
+ long tempsize = 0;
+
+ if (!ostream)
+ pfatal_with_name (outname);
+ tempfiles[i] = outname;
+
+ /* Copy lines into this temp file as long as it does not make file
+ "too big" or until there are no more lines. */
+
+ while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
+ {
+ tempsize += linelength + 1;
+ fputs (lb.buffer, ostream);
+ putc ('\n', ostream);
+
+ /* Read another line of input data. */
+
+ linelength = readline (&lb, istream);
+ if (!linelength && feof (istream))
+ break;
+
+ if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ failure = 1;
+ goto fail;
+ }
+ }
+ fclose (ostream);
+ if (feof (istream))
+ break;
+ }
+
+ free (lb.buffer);
+
+fail:
+ /* Record number of temp files we actually needed. */
+
+ ntemps = i;
+
+ /* Sort each tempfile into another tempfile.
+ Delete the first set of tempfiles and put the names of the second
+ into `tempfiles'. */
+
+ for (i = 0; i < ntemps; i++)
+ {
+ char *newtemp = maketempname (++tempcount);
+ sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
+ if (!keep_tempfiles)
+ unlink (tempfiles[i]);
+ tempfiles[i] = newtemp;
+ }
+
+ if (failure)
+ return;
+
+ /* Merge the tempfiles together and indexify. */
+
+ merge_files (tempfiles, ntemps, outfile);
+}
+
+/* Sort INFILE, whose size is TOTAL,
+ assuming that is small enough to be done in-core,
+ then indexify it and send the output to OUTFILE (or to stdout). */
+
+void
+sort_in_core (infile, total, outfile)
+ char *infile;
+ long total;
+ char *outfile;
+{
+ char **nextline;
+ char *data = (char *) xmalloc (total + 1);
+ char *file_data;
+ long file_size;
+ int i;
+ FILE *ostream = stdout;
+ struct lineinfo *lineinfo;
+
+ /* Read the contents of the file into the moby array `data'. */
+
+ int desc = open (infile, O_RDONLY, 0);
+
+ if (desc < 0)
+ fatal ("failure reopening %s", infile);
+ for (file_size = 0;;)
+ {
+ i = read (desc, data + file_size, total - file_size);
+ if (i <= 0)
+ break;
+ file_size += i;
+ }
+ file_data = data;
+ data[file_size] = 0;
+
+ close (desc);
+
+ if (file_size > 0 && data[0] != '\\' && data[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ init_char_order ();
+
+ /* Sort routines want to know this address. */
+
+ text_base = data;
+
+ /* Create the array of pointers to lines, with a default size
+ frequently enough. */
+
+ nlines = total / 50;
+ if (!nlines)
+ nlines = 2;
+ linearray = (char **) xmalloc (nlines * sizeof (char *));
+
+ /* `nextline' points to the next free slot in this array.
+ `nlines' is the allocated size. */
+
+ nextline = linearray;
+
+ /* Parse the input file's data, and make entries for the lines. */
+
+ nextline = parsefile (infile, nextline, file_data, file_size);
+ if (nextline == 0)
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ /* Sort the lines. */
+
+ /* If we have enough space, find the first keyfield of each line in advance.
+ Make a `struct lineinfo' for each line, which records the keyfield
+ as well as the line, and sort them. */
+
+ lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
+
+ if (lineinfo)
+ {
+ struct lineinfo *lp;
+ char **p;
+
+ for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+ {
+ lp->text = *p;
+ lp->key.text = find_field (keyfields, *p, &lp->keylen);
+ if (keyfields->numeric)
+ lp->key.number = find_value (lp->key.text, lp->keylen);
+ }
+
+ qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared);
+
+ for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+ *p = lp->text;
+
+ free (lineinfo);
+ }
+ else
+ qsort (linearray, nextline - linearray, sizeof (char *), compare_full);
+
+ /* Open the output file. */
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ if (!ostream)
+ pfatal_with_name (outfile);
+ }
+
+ writelines (linearray, nextline - linearray, ostream);
+ if (outfile)
+ fclose (ostream);
+
+ free (linearray);
+ free (data);
+}
+
+/* Parse an input string in core into lines.
+ DATA is the input string, and SIZE is its length.
+ Data goes in LINEARRAY starting at NEXTLINE.
+ The value returned is the first entry in LINEARRAY still unused.
+ Value 0 means input file contents are invalid. */
+
+char **
+parsefile (filename, nextline, data, size)
+ char *filename;
+ char **nextline;
+ char *data;
+ long size;
+{
+ char *p, *end;
+ char **line = nextline;
+
+ p = data;
+ end = p + size;
+ *end = 0;
+
+ while (p != end)
+ {
+ if (p[0] != '\\' && p[0] != '@')
+ return 0;
+
+ *line = p;
+ while (*p && *p != '\n')
+ p++;
+ if (p != end)
+ p++;
+
+ line++;
+ if (line == linearray + nlines)
+ {
+ char **old = linearray;
+ linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4));
+ line += linearray - old;
+ }
+ }
+
+ return line;
+}
+
+/* Indexification is a filter applied to the sorted lines
+ as they are being written to the output file.
+ Multiple entries for the same name, with different page numbers,
+ get combined into a single entry with multiple page numbers.
+ The first braced field, which is used for sorting, is discarded.
+ However, its first character is examined, folded to lower case,
+ and if it is different from that in the previous line fed to us
+ a \initial line is written with one argument, the new initial.
+
+ If an entry has four braced fields, then the second and third
+ constitute primary and secondary names.
+ In this case, each change of primary name
+ generates a \primary line which contains only the primary name,
+ and in between these are \secondary lines which contain
+ just a secondary name and page numbers. */
+
+/* The last primary name we wrote a \primary entry for.
+ If only one level of indexing is being done, this is the last name seen. */
+char *lastprimary;
+/* Length of storage allocated for lastprimary. */
+int lastprimarylength;
+
+/* Similar, for the secondary name. */
+char *lastsecondary;
+int lastsecondarylength;
+
+/* Zero if we are not in the middle of writing an entry.
+ One if we have written the beginning of an entry but have not
+ yet written any page numbers into it.
+ Greater than one if we have written the beginning of an entry
+ plus at least one page number. */
+int pending;
+
+/* The initial (for sorting purposes) of the last primary entry written.
+ When this changes, a \initial {c} line is written */
+
+char *lastinitial;
+
+int lastinitiallength;
+
+/* When we need a string of length 1 for the value of lastinitial,
+ store it here. */
+
+char lastinitial1[2];
+
+/* Initialize static storage for writing an index. */
+
+static void
+xbzero(s, n)
+ char *s;
+ int n;
+{
+ register char *p;
+ for (p = s; n--; )
+ *p++ = '\0';
+}
+
+void
+init_index ()
+{
+ pending = 0;
+ lastinitial = lastinitial1;
+ lastinitial1[0] = 0;
+ lastinitial1[1] = 0;
+ lastinitiallength = 0;
+ lastprimarylength = 100;
+ lastprimary = (char *) xmalloc (lastprimarylength + 1);
+ xbzero (lastprimary, lastprimarylength + 1);
+ lastsecondarylength = 100;
+ lastsecondary = (char *) xmalloc (lastsecondarylength + 1);
+ xbzero (lastsecondary, lastsecondarylength + 1);
+}
+
+/* Indexify. Merge entries for the same name,
+ insert headers for each initial character, etc. */
+
+void
+indexify (line, ostream)
+ char *line;
+ FILE *ostream;
+{
+ char *primary, *secondary, *pagenumber;
+ int primarylength, secondarylength = 0, pagelength;
+ int nosecondary;
+ int initiallength;
+ char *initial;
+ char initial1[2];
+ register char *p;
+
+ /* First, analyze the parts of the entry fed to us this time. */
+
+ p = find_braced_pos (line, 0, 0, 0);
+ if (*p == '{')
+ {
+ initial = p;
+ /* Get length of inner pair of braces starting at `p',
+ including that inner pair of braces. */
+ initiallength = find_braced_end (p + 1) + 1 - p;
+ }
+ else
+ {
+ initial = initial1;
+ initial1[0] = *p;
+ initial1[1] = 0;
+ initiallength = 1;
+
+ if (initial1[0] >= 'a' && initial1[0] <= 'z')
+ initial1[0] -= 040;
+ }
+
+ pagenumber = find_braced_pos (line, 1, 0, 0);
+ pagelength = find_braced_end (pagenumber) - pagenumber;
+ if (pagelength == 0)
+ abort ();
+
+ primary = find_braced_pos (line, 2, 0, 0);
+ primarylength = find_braced_end (primary) - primary;
+
+ secondary = find_braced_pos (line, 3, 0, 0);
+ nosecondary = !*secondary;
+ if (!nosecondary)
+ secondarylength = find_braced_end (secondary) - secondary;
+
+ /* If the primary is different from before, make a new primary entry. */
+ if (strncmp (primary, lastprimary, primarylength))
+ {
+ /* Close off current secondary entry first, if one is open. */
+ if (pending)
+ {
+ fputs ("}\n", ostream);
+ pending = 0;
+ }
+
+ /* If this primary has a different initial, include an entry for
+ the initial. */
+ if (initiallength != lastinitiallength ||
+ strncmp (initial, lastinitial, initiallength))
+ {
+ fprintf (ostream, "\\initial {");
+ fwrite (initial, 1, initiallength, ostream);
+ fprintf (ostream, "}\n", initial);
+ if (initial == initial1)
+ {
+ lastinitial = lastinitial1;
+ *lastinitial1 = *initial1;
+ }
+ else
+ {
+ lastinitial = initial;
+ }
+ lastinitiallength = initiallength;
+ }
+
+ /* Make the entry for the primary. */
+ if (nosecondary)
+ fputs ("\\entry {", ostream);
+ else
+ fputs ("\\primary {", ostream);
+ fwrite (primary, primarylength, 1, ostream);
+ if (nosecondary)
+ {
+ fputs ("}{", ostream);
+ pending = 1;
+ }
+ else
+ fputs ("}\n", ostream);
+
+ /* Record name of most recent primary. */
+ if (lastprimarylength < primarylength)
+ {
+ lastprimarylength = primarylength + 100;
+ lastprimary = (char *) xrealloc (lastprimary,
+ 1 + lastprimarylength);
+ }
+ strncpy (lastprimary, primary, primarylength);
+ lastprimary[primarylength] = 0;
+
+ /* There is no current secondary within this primary, now. */
+ lastsecondary[0] = 0;
+ }
+
+ /* Should not have an entry with no subtopic following one with a subtopic. */
+
+ if (nosecondary && *lastsecondary)
+ error ("entry %s follows an entry with a secondary name", line);
+
+ /* Start a new secondary entry if necessary. */
+ if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
+ {
+ if (pending)
+ {
+ fputs ("}\n", ostream);
+ pending = 0;
+ }
+
+ /* Write the entry for the secondary. */
+ fputs ("\\secondary {", ostream);
+ fwrite (secondary, secondarylength, 1, ostream);
+ fputs ("}{", ostream);
+ pending = 1;
+
+ /* Record name of most recent secondary. */
+ if (lastsecondarylength < secondarylength)
+ {
+ lastsecondarylength = secondarylength + 100;
+ lastsecondary = (char *) xrealloc (lastsecondary,
+ 1 + lastsecondarylength);
+ }
+ strncpy (lastsecondary, secondary, secondarylength);
+ lastsecondary[secondarylength] = 0;
+ }
+
+ /* Here to add one more page number to the current entry. */
+ if (pending++ != 1)
+ fputs (", ", ostream); /* Punctuate first, if this is not the first. */
+ fwrite (pagenumber, pagelength, 1, ostream);
+}
+
+/* Close out any unfinished output entry. */
+
+void
+finish_index (ostream)
+ FILE *ostream;
+{
+ if (pending)
+ fputs ("}\n", ostream);
+ free (lastprimary);
+ free (lastsecondary);
+}
+
+/* Copy the lines in the sorted order.
+ Each line is copied out of the input file it was found in. */
+
+void
+writelines (linearray, nlines, ostream)
+ char **linearray;
+ int nlines;
+ FILE *ostream;
+{
+ char **stop_line = linearray + nlines;
+ char **next_line;
+
+ init_index ();
+
+ /* Output the text of the lines, and free the buffer space. */
+
+ for (next_line = linearray; next_line != stop_line; next_line++)
+ {
+ /* If -u was specified, output the line only if distinct from previous one. */
+ if (next_line == linearray
+ /* Compare previous line with this one, using only the
+ explicitly specd keyfields. */
+ || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
+ {
+ char *p = *next_line;
+ char c;
+
+ while ((c = *p++) && c != '\n')
+ /* Do nothing. */ ;
+ *(p - 1) = 0;
+ indexify (*next_line, ostream);
+ }
+ }
+
+ finish_index (ostream);
+}
+
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This is the high-level interface that can handle an unlimited
+ number of files. */
+
+#define MAX_DIRECT_MERGE 10
+
+int
+merge_files (infiles, nfiles, outfile)
+ char **infiles;
+ int nfiles;
+ char *outfile;
+{
+ char **tempfiles;
+ int ntemps;
+ int i;
+ int value = 0;
+ int start_tempcount = tempcount;
+
+ if (nfiles <= MAX_DIRECT_MERGE)
+ return merge_direct (infiles, nfiles, outfile);
+
+ /* Merge groups of MAX_DIRECT_MERGE input files at a time,
+ making a temporary file to hold each group's result. */
+
+ ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
+ tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+ for (i = 0; i < ntemps; i++)
+ {
+ int nf = MAX_DIRECT_MERGE;
+ if (i + 1 == ntemps)
+ nf = nfiles - i * MAX_DIRECT_MERGE;
+ tempfiles[i] = maketempname (++tempcount);
+ value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
+ }
+
+ /* All temporary files that existed before are no longer needed
+ since their contents have been merged into our new tempfiles.
+ So delete them. */
+ flush_tempfiles (start_tempcount);
+
+ /* Now merge the temporary files we created. */
+
+ merge_files (tempfiles, ntemps, outfile);
+
+ free (tempfiles);
+
+ return value;
+}
+
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This version of merging will not work if the number of
+ input files gets too high. Higher level functions
+ use it only with a bounded number of input files. */
+
+int
+merge_direct (infiles, nfiles, outfile)
+ char **infiles;
+ int nfiles;
+ char *outfile;
+{
+ struct linebuffer *lb1, *lb2;
+ struct linebuffer **thisline, **prevline;
+ FILE **streams;
+ int i;
+ int nleft;
+ int lossage = 0;
+ int *file_lossage;
+ struct linebuffer *prev_out = 0;
+ FILE *ostream = stdout;
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ }
+ if (!ostream)
+ pfatal_with_name (outfile);
+
+ init_index ();
+
+ if (nfiles == 0)
+ {
+ if (outfile)
+ fclose (ostream);
+ return 0;
+ }
+
+ /* For each file, make two line buffers.
+ Also, for each file, there is an element of `thisline'
+ which points at any time to one of the file's two buffers,
+ and an element of `prevline' which points to the other buffer.
+ `thisline' is supposed to point to the next available line from the file,
+ while `prevline' holds the last file line used,
+ which is remembered so that we can verify that the file is properly sorted. */
+
+ /* lb1 and lb2 contain one buffer each per file. */
+ lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+ lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+
+ /* thisline[i] points to the linebuffer holding the next available line in file i,
+ or is zero if there are no lines left in that file. */
+ thisline = (struct linebuffer **)
+ xmalloc (nfiles * sizeof (struct linebuffer *));
+ /* prevline[i] points to the linebuffer holding the last used line
+ from file i. This is just for verifying that file i is properly
+ sorted. */
+ prevline = (struct linebuffer **)
+ xmalloc (nfiles * sizeof (struct linebuffer *));
+ /* streams[i] holds the input stream for file i. */
+ streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
+ /* file_lossage[i] is nonzero if we already know file i is not
+ properly sorted. */
+ file_lossage = (int *) xmalloc (nfiles * sizeof (int));
+
+ /* Allocate and initialize all that storage. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ initbuffer (&lb1[i]);
+ initbuffer (&lb2[i]);
+ thisline[i] = &lb1[i];
+ prevline[i] = &lb2[i];
+ file_lossage[i] = 0;
+ streams[i] = fopen (infiles[i], "r");
+ if (!streams[i])
+ pfatal_with_name (infiles[i]);
+
+ readline (thisline[i], streams[i]);
+ }
+
+ /* Keep count of number of files not at eof. */
+ nleft = nfiles;
+
+ while (nleft)
+ {
+ struct linebuffer *best = 0;
+ struct linebuffer *exch;
+ int bestfile = -1;
+ int i;
+
+ /* Look at the next avail line of each file; choose the least one. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ if (thisline[i] &&
+ (!best ||
+ 0 < compare_general (best->buffer, thisline[i]->buffer,
+ (long) bestfile, (long) i, num_keyfields)))
+ {
+ best = thisline[i];
+ bestfile = i;
+ }
+ }
+
+ /* Output that line, unless it matches the previous one and we
+ don't want duplicates. */
+
+ if (!(prev_out &&
+ !compare_general (prev_out->buffer,
+ best->buffer, 0L, 1L, num_keyfields - 1)))
+ indexify (best->buffer, ostream);
+ prev_out = best;
+
+ /* Now make the line the previous of its file, and fetch a new
+ line from that file. */
+
+ exch = prevline[bestfile];
+ prevline[bestfile] = thisline[bestfile];
+ thisline[bestfile] = exch;
+
+ while (1)
+ {
+ /* If the file has no more, mark it empty. */
+
+ if (feof (streams[bestfile]))
+ {
+ thisline[bestfile] = 0;
+ /* Update the number of files still not empty. */
+ nleft--;
+ break;
+ }
+ readline (thisline[bestfile], streams[bestfile]);
+ if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
+ break;
+ }
+ }
+
+ finish_index (ostream);
+
+ /* Free all storage and close all input streams. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ fclose (streams[i]);
+ free (lb1[i].buffer);
+ free (lb2[i].buffer);
+ }
+ free (file_lossage);
+ free (lb1);
+ free (lb2);
+ free (thisline);
+ free (prevline);
+ free (streams);
+
+ if (outfile)
+ fclose (ostream);
+
+ return lossage;
+}
+
+/* Print error message and exit. */
+
+void
+fatal (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+ exit (TI_FATAL_ERROR);
+}
+
+/* Print error message. S1 is printf control string, S2 is arg for it. */
+
+void
+error (s1, s2)
+ char *s1, *s2;
+{
+ printf ("%s: ", program_name);
+ printf (s1, s2);
+ printf ("\n");
+}
+
+#if !defined (HAVE_STRERROR)
+static char *
+strerror (n)
+ int n;
+{
+ static char ebuf[40];
+
+ if (n < sys_nerr)
+ return sys_errlist[n];
+ else
+ {
+ sprintf (ebuf, "Unknown error %d", n);
+ return ebuf;
+ }
+}
+#endif
+
+void
+perror_with_name (name)
+ char *name;
+{
+ char *s;
+
+ s = concat ("", strerror (errno), " for %s");
+ error (s, name);
+}
+
+void
+pfatal_with_name (name)
+ char *name;
+{
+ char *s;
+
+ s = concat ("", strerror (errno), " for %s");
+ fatal (s, name);
+}
+
+/* Return a newly-allocated string whose contents concatenate those of
+ S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+/* Just like malloc, but kills the program in case of fatal error. */
+void *
+xmalloc (nbytes)
+ int nbytes;
+{
+ void *temp = (void *) malloc (nbytes);
+
+ if (nbytes && temp == (void *)NULL)
+ memory_error ("xmalloc", nbytes);
+
+ return (temp);
+}
+
+/* Like realloc (), but barfs if there isn't enough memory. */
+void *
+xrealloc (pointer, nbytes)
+ void *pointer;
+ int nbytes;
+{
+ void *temp;
+
+ if (!pointer)
+ temp = (void *)xmalloc (nbytes);
+ else
+ temp = (void *)realloc (pointer, nbytes);
+
+ if (nbytes && !temp)
+ memory_error ("xrealloc", nbytes);
+
+ return (temp);
+}
+
+memory_error (callers_name, bytes_wanted)
+ char *callers_name;
+ int bytes_wanted;
+{
+ char printable_string[80];
+
+ sprintf (printable_string,
+ "Virtual memory exhausted in %s ()! Needed %d bytes.",
+ callers_name, bytes_wanted);
+
+ error (printable_string, "");
+ abort ();
+}
diff --git a/gnu/lib/libreadline/emacs_keymap.c b/gnu/lib/libreadline/emacs_keymap.c
new file mode 100644
index 000000000000..ab058fc0f7eb
--- /dev/null
+++ b/gnu/lib/libreadline/emacs_keymap.c
@@ -0,0 +1,885 @@
+/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* !BUFSIZ */
+
+#include <readline/readline.h>
+
+/* An array of function pointers, one for each possible key.
+ If the type byte is ISKMAP, then the pointer is the address of
+ a keymap. */
+
+KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, rl_beg_of_line }, /* Control-a */
+ { ISFUNC, rl_backward }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_delete }, /* Control-d */
+ { ISFUNC, rl_end_of_line }, /* Control-e */
+ { ISFUNC, rl_forward }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_rubout }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* ) */
+#else
+ { ISFUNC, rl_insert }, /* ) */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* ] */
+#else
+ { ISFUNC, rl_insert }, /* ] */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* } */
+#else
+ { ISFUNC, rl_insert }, /* } */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Pure 8-bit characters (128 - 159).
+ These might be used in some
+ character sets. */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+
+ /* ISO Latin-1 characters (160 - 255) */
+ { ISFUNC, rl_insert }, /* No-break space */
+ { ISFUNC, rl_insert }, /* Inverted exclamation mark */
+ { ISFUNC, rl_insert }, /* Cent sign */
+ { ISFUNC, rl_insert }, /* Pound sign */
+ { ISFUNC, rl_insert }, /* Currency sign */
+ { ISFUNC, rl_insert }, /* Yen sign */
+ { ISFUNC, rl_insert }, /* Broken bar */
+ { ISFUNC, rl_insert }, /* Section sign */
+ { ISFUNC, rl_insert }, /* Diaeresis */
+ { ISFUNC, rl_insert }, /* Copyright sign */
+ { ISFUNC, rl_insert }, /* Feminine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Not sign */
+ { ISFUNC, rl_insert }, /* Soft hyphen */
+ { ISFUNC, rl_insert }, /* Registered sign */
+ { ISFUNC, rl_insert }, /* Macron */
+ { ISFUNC, rl_insert }, /* Degree sign */
+ { ISFUNC, rl_insert }, /* Plus-minus sign */
+ { ISFUNC, rl_insert }, /* Superscript two */
+ { ISFUNC, rl_insert }, /* Superscript three */
+ { ISFUNC, rl_insert }, /* Acute accent */
+ { ISFUNC, rl_insert }, /* Micro sign */
+ { ISFUNC, rl_insert }, /* Pilcrow sign */
+ { ISFUNC, rl_insert }, /* Middle dot */
+ { ISFUNC, rl_insert }, /* Cedilla */
+ { ISFUNC, rl_insert }, /* Superscript one */
+ { ISFUNC, rl_insert }, /* Masculine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one half */
+ { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */
+ { ISFUNC, rl_insert }, /* Inverted questionk mark */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin capital letter ae */
+ { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Multiplication sign */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */
+ { ISFUNC, rl_insert }, /* Latin small letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin small letter ae */
+ { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin small letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Division sign */
+ { ISFUNC, rl_insert }, /* Latin small letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin small letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter y with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */
+ { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
+
+ /* Meta keys. Just like above, but the high bit is set. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
+ { ISFUNC, rl_abort }, /* Meta-Control-g */
+ { ISFUNC, rl_backward_kill_word }, /* Meta-Control-h */
+ { ISFUNC, rl_tab_insert }, /* Meta-Control-i */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
+ { ISFUNC, rl_revert_line }, /* Meta-Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
+ { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
+
+ { ISFUNC, rl_complete }, /* Meta-Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */
+ { ISFUNC, (Function *)0x0 }, /* Meta-! */
+ { ISFUNC, (Function *)0x0 }, /* Meta-" */
+ { ISFUNC, (Function *)0x0 }, /* Meta-# */
+ { ISFUNC, (Function *)0x0 }, /* Meta-$ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-% */
+ { ISFUNC, rl_tilde_expand }, /* Meta-& */
+ { ISFUNC, (Function *)0x0 }, /* Meta-' */
+ { ISFUNC, (Function *)0x0 }, /* Meta-( */
+ { ISFUNC, (Function *)0x0 }, /* Meta-) */
+ { ISFUNC, (Function *)0x0 }, /* Meta-* */
+ { ISFUNC, (Function *)0x0 }, /* Meta-+ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-, */
+ { ISFUNC, rl_digit_argument }, /* Meta-- */
+ { ISFUNC, (Function *)0x0 }, /* Meta-. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-/ */
+
+ /* Regular digits. */
+ { ISFUNC, rl_digit_argument }, /* Meta-0 */
+ { ISFUNC, rl_digit_argument }, /* Meta-1 */
+ { ISFUNC, rl_digit_argument }, /* Meta-2 */
+ { ISFUNC, rl_digit_argument }, /* Meta-3 */
+ { ISFUNC, rl_digit_argument }, /* Meta-4 */
+ { ISFUNC, rl_digit_argument }, /* Meta-5 */
+ { ISFUNC, rl_digit_argument }, /* Meta-6 */
+ { ISFUNC, rl_digit_argument }, /* Meta-7 */
+ { ISFUNC, rl_digit_argument }, /* Meta-8 */
+ { ISFUNC, rl_digit_argument }, /* Meta-9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-: */
+ { ISFUNC, (Function *)0x0 }, /* Meta-; */
+ { ISFUNC, rl_beginning_of_history }, /* Meta-< */
+ { ISFUNC, (Function *)0x0 }, /* Meta-= */
+ { ISFUNC, rl_end_of_history }, /* Meta-> */
+ { ISFUNC, rl_possible_completions }, /* Meta-? */
+ { ISFUNC, (Function *)0x0 }, /* Meta-@ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-A */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-B */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-C */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-D */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-E */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-F */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-G */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-H */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-I */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-J */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-K */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-L */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-M */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-N */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-O */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-P */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-R */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-S */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-T */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-U */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-V */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-W */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-X */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_arrow_keys }, /* Meta-[ */
+ { ISFUNC, rl_delete_horizontal_space }, /* Meta-\ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-^ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-_ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-a */
+ { ISFUNC, rl_backward_word }, /* Meta-b */
+ { ISFUNC, rl_capitalize_word }, /* Meta-c */
+ { ISFUNC, rl_kill_word }, /* Meta-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-e */
+ { ISFUNC, rl_forward_word }, /* Meta-f */
+ { ISFUNC, (Function *)0x0 }, /* Meta-g */
+ { ISFUNC, (Function *)0x0 }, /* Meta-h */
+ { ISFUNC, (Function *)0x0 }, /* Meta-i */
+ { ISFUNC, (Function *)0x0 }, /* Meta-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-k */
+ { ISFUNC, rl_downcase_word }, /* Meta-l */
+ { ISFUNC, (Function *)0x0 }, /* Meta-m */
+ { ISFUNC, rl_noninc_forward_search }, /* Meta-n */
+ { ISFUNC, rl_arrow_keys }, /* Meta-o */
+ { ISFUNC, rl_noninc_reverse_search }, /* Meta-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-q */
+ { ISFUNC, rl_revert_line }, /* Meta-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-s */
+ { ISFUNC, rl_transpose_words }, /* Meta-t */
+ { ISFUNC, rl_upcase_word }, /* Meta-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-x */
+ { ISFUNC, rl_yank_pop }, /* Meta-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-{ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-| */
+ { ISFUNC, (Function *)0x0 }, /* Meta-} */
+ { ISFUNC, rl_tilde_expand }, /* Meta-~ */
+ { ISFUNC, rl_backward_kill_word }, /* Meta-rubout */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, (Function *)0x0 }, /* Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, (Function *)0x0 }, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, rl_re_read_init_file }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, rl_undo_command }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISFUNC, (Function *)0x0 }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, rl_start_kbd_macro }, /* ( */
+ { ISFUNC, rl_end_kbd_macro }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, (Function *)0x0 }, /* 0 */
+ { ISFUNC, (Function *)0x0 }, /* 1 */
+ { ISFUNC, (Function *)0x0 }, /* 2 */
+ { ISFUNC, (Function *)0x0 }, /* 3 */
+ { ISFUNC, (Function *)0x0 }, /* 4 */
+ { ISFUNC, (Function *)0x0 }, /* 5 */
+ { ISFUNC, (Function *)0x0 }, /* 6 */
+ { ISFUNC, (Function *)0x0 }, /* 7 */
+ { ISFUNC, (Function *)0x0 }, /* 8 */
+ { ISFUNC, (Function *)0x0 }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, rl_call_last_kbd_macro }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, (Function *)0x0 }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_line }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
diff --git a/gnu/lib/libreadline/examples/Inputrc b/gnu/lib/libreadline/examples/Inputrc
new file mode 100644
index 000000000000..db9510dd7b64
--- /dev/null
+++ b/gnu/lib/libreadline/examples/Inputrc
@@ -0,0 +1,58 @@
+# My ~/.inputrc file is in -*- text -*- for easy editing with Emacs.
+#
+# Notice the various bindings which are conditionalized depending
+# on which program is running, or what terminal is active.
+#
+
+# In all programs, all terminals, make sure this is bound.
+"\C-x\C-r": re-read-init-file
+
+# Hp terminals (and some others) have ugly default behaviour for C-h.
+"\C-h": backward-delete-char
+"\e\C-h": backward-kill-word
+"\C-xd": dump-functions
+
+# In xterm windows, make the arrow keys do the right thing.
+$if TERM=xterm
+"\e[A": previous-history
+"\e[B": next-history
+"\e[C": forward-char
+"\e[D": backward-char
+
+# Under Xterm in Bash, we bind local Function keys to do something useful.
+$if Bash
+"\e[11~": "Function Key 1"
+"\e[12~": "Function Key 2"
+"\e[13~": "Function Key 3"
+"\e[14~": "Function Key 4"
+"\e[15~": "Function Key 5"
+
+# I know the following escape sequence numbers are 1 greater than
+# the function key. Don't ask me why, I didn't design the xterm terminal.
+"\e[17~": "Function Key 6"
+"\e[18~": "Function Key 7"
+"\e[19~": "Function Key 8"
+"\e[20~": "Function Key 9"
+"\e[21~": "Function Key 10"
+$endif
+$endif
+
+# For Bash, all terminals, add some Bash specific hacks.
+$if Bash
+"\C-xv": show-bash-version
+"\C-x\C-e": shell-expand-line
+
+# Here is one for editing my path.
+"\C-xp": "$PATH\C-x\C-e\C-e\"\C-aPATH=\":\C-b"
+
+# Make C-x r read my mail in emacs.
+# "\C-xr": "emacs -f rmail\C-j"
+$endif
+
+# For FTP, different hacks:
+$if Ftp
+"\C-xg": "get \M-?"
+"\C-xt": "put \M-?"
+$endif
+
+" ": self-insert
diff --git a/gnu/lib/libreadline/examples/Makefile b/gnu/lib/libreadline/examples/Makefile
new file mode 100644
index 000000000000..3d1fc527a628
--- /dev/null
+++ b/gnu/lib/libreadline/examples/Makefile
@@ -0,0 +1,12 @@
+# This is the Makefile for the examples subdirectory of readline. -*- text -*-
+#
+
+EXECUTABLES = fileman
+CFLAGS = -g -I../..
+LDFLAGS = -g -L..
+
+fileman: fileman.o
+ $(CC) $(LDFLAGS) -o fileman fileman.o -lreadline -ltermcap
+
+fileman.o: fileman.c
+
diff --git a/gnu/lib/libreadline/examples/fileman.c b/gnu/lib/libreadline/examples/fileman.c
new file mode 100644
index 000000000000..d1e72c5d5311
--- /dev/null
+++ b/gnu/lib/libreadline/examples/fileman.c
@@ -0,0 +1,395 @@
+/* fileman.c -- A tiny application which demonstrates how to use the
+ GNU Readline library. This application interactively allows users
+ to manipulate files and their modes. */
+
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+/* The names of functions that actually do the manipulation. */
+int com_list (), com_view (), com_rename (), com_stat (), com_pwd ();
+int com_delete (), com_help (), com_cd (), com_quit ();
+
+/* A structure which contains information on the commands this program
+ can understand. */
+
+typedef struct {
+ char *name; /* User printable name of the function. */
+ Function *func; /* Function to call to do the job. */
+ char *doc; /* Documentation for this function. */
+} COMMAND;
+
+COMMAND commands[] = {
+ { "cd", com_cd, "Change to directory DIR" },
+ { "delete", com_delete, "Delete FILE" },
+ { "help", com_help, "Display this text" },
+ { "?", com_help, "Synonym for `help'" },
+ { "list", com_list, "List files in DIR" },
+ { "ls", com_list, "Synonym for `list'" },
+ { "pwd", com_pwd, "Print the current working directory" },
+ { "quit", com_quit, "Quit using Fileman" },
+ { "rename", com_rename, "Rename FILE to NEWNAME" },
+ { "stat", com_stat, "Print out statistics on FILE" },
+ { "view", com_view, "View the contents of FILE" },
+ { (char *)NULL, (Function *)NULL, (char *)NULL }
+};
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this global means the user is done using this program. */
+int done = 0;
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ progname = argv[0];
+
+ initialize_readline (); /* Bind our completer. */
+
+ /* Loop reading and executing lines until the user quits. */
+ while (!done)
+ {
+ char *line;
+
+ line = readline ("FileMan: ");
+
+ if (!line)
+ {
+ done = 1; /* Encountered EOF at top level. */
+ }
+ else
+ {
+ /* Remove leading and trailing whitespace from the line.
+ Then, if there is anything left, add it to the history list
+ and execute it. */
+ stripwhite (line);
+
+ if (*line)
+ {
+ add_history (line);
+ execute_line (line);
+ }
+ }
+
+ if (line)
+ free (line);
+ }
+ exit (0);
+}
+
+/* Execute a command line. */
+execute_line (line)
+ char *line;
+{
+ register int i;
+ COMMAND *find_command (), *command;
+ char *word;
+
+ /* Isolate the command word. */
+ i = 0;
+ while (line[i] && !whitespace (line[i]))
+ i++;
+
+ word = line;
+
+ if (line[i])
+ line[i++] = '\0';
+
+ command = find_command (word);
+
+ if (!command)
+ {
+ fprintf (stderr, "%s: No such command for FileMan.\n", word);
+ return;
+ }
+
+ /* Get argument to command, if any. */
+ while (whitespace (line[i]))
+ i++;
+
+ word = line + i;
+
+ /* Call the function. */
+ (*(command->func)) (word);
+}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+ command. Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; commands[i].name; i++)
+ if (strcmp (name, commands[i].name) == 0)
+ return (&commands[i]);
+
+ return ((COMMAND *)NULL);
+}
+
+/* Strip whitespace from the start and end of STRING. */
+stripwhite (string)
+ char *string;
+{
+ register int i = 0;
+
+ while (whitespace (string[i]))
+ i++;
+
+ if (i)
+ strcpy (string, string + i);
+
+ i = strlen (string) - 1;
+
+ while (i > 0 && whitespace (string[i]))
+ i--;
+
+ string[++i] = '\0';
+}
+
+/* **************************************************************** */
+/* */
+/* Interface to Readline Completion */
+/* */
+/* **************************************************************** */
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+initialize_readline ()
+{
+ char **fileman_completion ();
+
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = "FileMan";
+
+ /* Tell the completer that we want a crack first. */
+ rl_attempted_completion_function = (Function *)fileman_completion;
+}
+
+/* Attempt to complete on the contents of TEXT. START and END show the
+ region of TEXT that contains the word to complete. We can use the
+ entire line in case we want to do some simple parsing. Return the
+ array of matches, or NULL if there aren't any. */
+char **
+fileman_completion (text, start, end)
+ char *text;
+ int start, end;
+{
+ char **matches;
+ char *command_generator ();
+
+ matches = (char **)NULL;
+
+ /* If this word is at the start of the line, then it is a command
+ to complete. Otherwise it is the name of a file in the current
+ directory. */
+ if (start == 0)
+ matches = completion_matches (text, command_generator);
+
+ return (matches);
+}
+
+/* Generator function for command completion. STATE lets us know whether
+ to start from scratch; without any state (i.e. STATE == 0), then we
+ start at the top of the list. */
+char *
+command_generator (text, state)
+ char *text;
+ int state;
+{
+ static int list_index, len;
+ char *name;
+
+ /* If this is a new word to complete, initialize now. This includes
+ saving the length of TEXT for efficiency, and initializing the index
+ variable to 0. */
+ if (!state)
+ {
+ list_index = 0;
+ len = strlen (text);
+ }
+
+ /* Return the next name which partially matches from the command list. */
+ while (name = commands[list_index].name)
+ {
+ list_index++;
+
+ if (strncmp (name, text, len) == 0)
+ return (name);
+ }
+
+ /* If no names matched, then return NULL. */
+ return ((char *)NULL);
+}
+
+/* **************************************************************** */
+/* */
+/* FileMan Commands */
+/* */
+/* **************************************************************** */
+
+/* String to pass to system (). This is for the LIST, VIEW and RENAME
+ commands. */
+static char syscom[1024];
+
+/* List the file(s) named in arg. */
+com_list (arg)
+ char *arg;
+{
+ if (!arg)
+ arg = "*";
+
+ sprintf (syscom, "ls -FClg %s", arg);
+ system (syscom);
+}
+
+com_view (arg)
+ char *arg;
+{
+ if (!valid_argument ("view", arg))
+ return;
+
+ sprintf (syscom, "cat %s | more", arg);
+ system (syscom);
+}
+
+com_rename (arg)
+ char *arg;
+{
+ too_dangerous ("rename");
+}
+
+com_stat (arg)
+ char *arg;
+{
+ struct stat finfo;
+
+ if (!valid_argument ("stat", arg))
+ return;
+
+ if (stat (arg, &finfo) == -1)
+ {
+ perror (arg);
+ return;
+ }
+
+ printf ("Statistics for `%s':\n", arg);
+
+ printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
+ finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s", finfo.st_size);
+ printf (" Created on: %s", ctime (&finfo.st_ctime));
+ printf (" Last access at: %s", ctime (&finfo.st_atime));
+ printf ("Last modified at: %s", ctime (&finfo.st_mtime));
+}
+
+com_delete (arg)
+ char *arg;
+{
+ too_dangerous ("delete");
+}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+ not present. */
+com_help (arg)
+ char *arg;
+{
+ register int i;
+ int printed = 0;
+
+ for (i = 0; commands[i].name; i++)
+ {
+ if (!*arg || (strcmp (arg, commands[i].name) == 0))
+ {
+ printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+ printed++;
+ }
+ }
+
+ if (!printed)
+ {
+ printf ("No commands match `%s'. Possibilties are:\n", arg);
+
+ for (i = 0; commands[i].name; i++)
+ {
+ /* Print in six columns. */
+ if (printed == 6)
+ {
+ printed = 0;
+ printf ("\n");
+ }
+
+ printf ("%s\t", commands[i].name);
+ printed++;
+ }
+
+ if (printed)
+ printf ("\n");
+ }
+}
+
+/* Change to the directory ARG. */
+com_cd (arg)
+ char *arg;
+{
+ if (chdir (arg) == -1)
+ perror (arg);
+
+ com_pwd ("");
+}
+
+/* Print out the current working directory. */
+com_pwd (ignore)
+ char *ignore;
+{
+ char dir[1024];
+
+ (void) getwd (dir);
+
+ printf ("Current directory is %s\n", dir);
+}
+
+/* The user wishes to quit using this program. Just set DONE non-zero. */
+com_quit (arg)
+ char *arg;
+{
+ done = 1;
+}
+
+/* Function which tells you that you can't do this. */
+too_dangerous (caller)
+ char *caller;
+{
+ fprintf (stderr,
+ "%s: Too dangerous for me to distribute. Write it yourself.\n",
+ caller);
+}
+
+/* Return non-zero if ARG is a valid argument for CALLER, else print
+ an error message and return zero. */
+int
+valid_argument (caller, arg)
+ char *caller, *arg;
+{
+ if (!arg || !*arg)
+ {
+ fprintf (stderr, "%s: Argument required.\n", caller);
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "cc -g -I../.. -L.. -o fileman fileman.c -lreadline -ltermcap"
+ * end:
+ */
diff --git a/gnu/lib/libreadline/examples/manexamp.c b/gnu/lib/libreadline/examples/manexamp.c
new file mode 100644
index 000000000000..b7ec96a755b2
--- /dev/null
+++ b/gnu/lib/libreadline/examples/manexamp.c
@@ -0,0 +1,96 @@
+/* manexamp.c -- The examples which appear in the documentation are here. */
+
+#include <stdio.h>
+#include <readline/readline.h>
+
+
+/* **************************************************************** */
+/* */
+* How to Emulate gets () */
+/* */
+/* **************************************************************** */
+
+/* A static variable for holding the line. */
+static char *line_read = (char *)NULL;
+
+/* Read a string, and return a pointer to it. Returns NULL on EOF. */
+char *
+do_gets ()
+{
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+ if (line_read != (char *)NULL)
+ {
+ free (line_read);
+ line_read = (char *)NULL;
+ }
+
+ /* Get a line from the user. */
+ line_read = readline ("");
+
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+
+ return (line_read);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Writing a Function to be Called by Readline. */
+/* */
+/* **************************************************************** */
+
+/* Invert the case of the COUNT following characters. */
+invert_case_line (count, key)
+ int count, key;
+{
+ register int start, end;
+
+ start = rl_point;
+
+ if (count < 0)
+ {
+ direction = -1;
+ count = -count;
+ }
+ else
+ direction = 1;
+
+ /* Find the end of the range to modify. */
+ end = start + (count * direction);
+
+ /* Force it to be within range. */
+ if (end > rl_end)
+ end = rl_end;
+ else if (end < 0)
+ end = -1;
+
+ if (start > end)
+ {
+ int temp = start;
+ start = end;
+ end = temp;
+ }
+
+ if (start == end)
+ return;
+
+ /* Tell readline that we are modifying the line, so save the undo
+ information. */
+ rl_modifying (start, end);
+
+ for (; start != end; start += direction)
+ {
+ if (uppercase_p (rl_line_buffer[start]))
+ rl_line_buffer[start] = to_lower (rl_line_buffer[start]);
+ else if (lowercase_p (rl_line_buffer[start]))
+ rl_line_buffer[start] = to_upper (rl_line_buffer[start]);
+ }
+
+ /* Move point to on top of the last character changed. */
+ rl_point = end - direction;
+}
+
+
diff --git a/gnu/lib/libreadline/funmap.c b/gnu/lib/libreadline/funmap.c
new file mode 100644
index 000000000000..6e26b984ae29
--- /dev/null
+++ b/gnu/lib/libreadline/funmap.c
@@ -0,0 +1,295 @@
+/* funmap.c -- attach names to functions. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* BUFSIZ */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include "rlconf.h"
+#include <readline/readline.h>
+
+FUNMAP **funmap = (FUNMAP **)NULL;
+static int funmap_size = 0;
+static int funmap_entry = 0;
+
+/* After initializing the function map, this is the index of the first
+ program specific function. */
+int funmap_program_specific_entry_start;
+
+static FUNMAP default_funmap[] = {
+
+ { "abort", rl_abort },
+ { "accept-line", rl_newline },
+ { "arrow-key-prefix", rl_arrow_keys },
+ { "backward-char", rl_backward },
+ { "backward-delete-char", rl_rubout },
+ { "backward-kill-line", rl_backward_kill_line },
+ { "backward-kill-word", rl_backward_kill_word },
+ { "backward-word", rl_backward_word },
+ { "beginning-of-history", rl_beginning_of_history },
+ { "beginning-of-line", rl_beg_of_line },
+ { "call-last-kbd-macro", rl_call_last_kbd_macro },
+ { "capitalize-word", rl_capitalize_word },
+ { "clear-screen", rl_clear_screen },
+ { "complete", rl_complete },
+ { "delete-char", rl_delete },
+ { "delete-horizontal-space", rl_delete_horizontal_space },
+ { "digit-argument", rl_digit_argument },
+ { "do-lowercase-version", rl_do_lowercase_version },
+ { "downcase-word", rl_downcase_word },
+ { "dump-functions", rl_dump_functions },
+ { "emacs-editing-mode", rl_emacs_editing_mode },
+ { "end-kbd-macro", rl_end_kbd_macro },
+ { "end-of-history", rl_end_of_history },
+ { "end-of-line", rl_end_of_line },
+ { "forward-char", rl_forward },
+ { "forward-search-history", rl_forward_search_history },
+ { "forward-word", rl_forward_word },
+ { "history-search-backward", rl_history_search_backward },
+ { "history-search-forward", rl_history_search_forward },
+ { "insert-completions", rl_insert_completions },
+ { "kill-whole-line", rl_kill_full_line },
+ { "kill-line", rl_kill_line },
+ { "kill-word", rl_kill_word },
+ { "next-history", rl_get_next_history },
+ { "non-incremental-forward-search-history", rl_noninc_forward_search },
+ { "non-incremental-reverse-search-history", rl_noninc_reverse_search },
+ { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again },
+ { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again },
+ { "possible-completions", rl_possible_completions },
+ { "previous-history", rl_get_previous_history },
+ { "quoted-insert", rl_quoted_insert },
+ { "re-read-init-file", rl_re_read_init_file },
+ { "redraw-current-line", rl_refresh_line},
+ { "reverse-search-history", rl_reverse_search_history },
+ { "revert-line", rl_revert_line },
+ { "self-insert", rl_insert },
+ { "start-kbd-macro", rl_start_kbd_macro },
+ { "tab-insert", rl_tab_insert },
+ { "tilde-expand", rl_tilde_expand },
+ { "transpose-chars", rl_transpose_chars },
+ { "transpose-words", rl_transpose_words },
+ { "undo", rl_undo_command },
+ { "universal-argument", rl_universal_argument },
+ { "unix-line-discard", rl_unix_line_discard },
+ { "unix-word-rubout", rl_unix_word_rubout },
+ { "upcase-word", rl_upcase_word },
+ { "yank", rl_yank },
+ { "yank-nth-arg", rl_yank_nth_arg },
+ { "yank-pop", rl_yank_pop },
+
+#if defined (VI_MODE)
+ { "vi-append-eol", rl_vi_append_eol },
+ { "vi-append-mode", rl_vi_append_mode },
+ { "vi-arg-digit", rl_vi_arg_digit },
+ { "vi-bWord", rl_vi_bWord },
+ { "vi-bracktype", rl_vi_bracktype },
+ { "vi-bword", rl_vi_bword },
+ { "vi-change-case", rl_vi_change_case },
+ { "vi-change-char", rl_vi_change_char },
+ { "vi-change-to", rl_vi_change_to },
+ { "vi-char-search", rl_vi_char_search },
+ { "vi-column", rl_vi_column },
+ { "vi-comment", rl_vi_comment },
+ { "vi-complete", rl_vi_complete },
+ { "vi-delete", rl_vi_delete },
+ { "vi-delete-to", rl_vi_delete_to },
+ { "vi-eWord", rl_vi_eWord },
+ { "vi-editing-mode", rl_vi_editing_mode },
+ { "vi-end-word", rl_vi_end_word },
+ { "vi-eof-maybe", rl_vi_eof_maybe },
+ { "vi-eword", rl_vi_eword },
+ { "vi-fWord", rl_vi_fWord },
+ { "vi-first-print", rl_vi_first_print },
+ { "vi-fword", rl_vi_fword },
+ { "vi-insert-beg", rl_vi_insert_beg },
+ { "vi-insertion-mode", rl_vi_insertion_mode },
+ { "vi-match", rl_vi_match },
+ { "vi-movement-mode", rl_vi_movement_mode },
+ { "vi-next-word", rl_vi_next_word },
+ { "vi-overstrike", rl_vi_overstrike },
+ { "vi-overstrike-delete", rl_vi_overstrike_delete },
+ { "vi-prev-word", rl_vi_prev_word },
+ { "vi-put", rl_vi_put },
+ { "vi-redo", rl_vi_redo },
+ { "vi-replace", rl_vi_replace },
+ { "vi-search", rl_vi_search },
+ { "vi-search-again", rl_vi_search_again },
+ { "vi-subst", rl_vi_subst },
+ { "vi-tilde-expand", rl_vi_tilde_expand },
+ { "vi-yank-arg", rl_vi_yank_arg },
+ { "vi-yank-to", rl_vi_yank_to },
+
+#endif /* VI_MODE */
+
+ {(char *)NULL, (Function *)NULL }
+};
+
+rl_add_funmap_entry (name, function)
+ char *name;
+ Function *function;
+{
+ if (funmap_entry + 2 >= funmap_size)
+ if (!funmap)
+ funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *));
+ else
+ funmap =
+ (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *));
+
+ funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
+ funmap[funmap_entry]->name = name;
+ funmap[funmap_entry]->function = function;
+
+ funmap[++funmap_entry] = (FUNMAP *)NULL;
+ return funmap_entry;
+}
+
+static int funmap_initialized = 0;
+
+/* Make the funmap contain all of the default entries. */
+void
+rl_initialize_funmap ()
+{
+ register int i;
+
+ if (funmap_initialized)
+ return;
+
+ for (i = 0; default_funmap[i].name; i++)
+ rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
+
+ funmap_initialized = 1;
+ funmap_program_specific_entry_start = i;
+}
+
+/* Stupid comparison routine for qsort () ing strings. */
+static int
+qsort_string_compare (s1, s2)
+ register char **s1, **s2;
+{
+ int r;
+
+ r = **s1 - **s2;
+ if (r == 0)
+ r = strcmp (*s1, *s2);
+ return r;
+}
+
+/* Produce a NULL terminated array of known function names. The array
+ is sorted. The array itself is allocated, but not the strings inside.
+ You should free () the array when you done, but not the pointrs. */
+char **
+rl_funmap_names ()
+{
+ char **result = (char **)NULL;
+ int result_size, result_index;
+
+ result_size = result_index = 0;
+
+ /* Make sure that the function map has been initialized. */
+ rl_initialize_funmap ();
+
+ for (result_index = 0; funmap[result_index]; result_index++)
+ {
+ if (result_index + 2 > result_size)
+ {
+ if (!result)
+ result = (char **)xmalloc ((result_size = 20) * sizeof (char *));
+ else
+ result = (char **)
+ xrealloc (result, (result_size += 20) * sizeof (char *));
+ }
+
+ result[result_index] = funmap[result_index]->name;
+ result[result_index + 1] = (char *)NULL;
+ }
+
+ qsort (result, result_index, sizeof (char *), qsort_string_compare);
+ return (result);
+}
+
+/* Things that mean `Control'. */
+char *possible_control_prefixes[] = {
+ "Control-", "C-", "CTRL-", (char *)NULL
+};
+
+char *possible_meta_prefixes[] = {
+ "Meta", "M-", (char *)NULL
+};
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "history: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/gnu/lib/libreadline/history.c b/gnu/lib/libreadline/history.c
new file mode 100644
index 000000000000..b5262d3369ae
--- /dev/null
+++ b/gnu/lib/libreadline/history.c
@@ -0,0 +1,2136 @@
+/* History.c -- standalone history library */
+
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The 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 1, or (at your option)
+ any later version.
+
+ The 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The goal is to make the implementation transparent, so that you
+ don't have to know what data types are used, just what functions
+ you can call. I think I have done that. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+#include <errno.h>
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "memalloc.h"
+#include <readline/history.h>
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+
+#ifndef savestring
+# ifndef strcpy
+extern char *strcpy ();
+# endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifndef digit
+#define digit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef digit_value
+#define digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+# ifndef strchr
+extern char *strchr ();
+# endif
+#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
+#endif
+
+/* Possible history errors passed to hist_error. */
+#define EVENT_NOT_FOUND 0
+#define BAD_WORD_SPEC 1
+#define SUBST_FAILED 2
+#define BAD_MODIFIER 3
+
+static char error_pointer;
+
+static char *subst_lhs;
+static char *subst_rhs;
+static int subst_lhs_len = 0;
+static int subst_rhs_len = 0;
+
+static char *get_history_word_specifier ();
+
+#if defined (SHELL)
+extern char *single_quote ();
+#endif
+
+/* **************************************************************** */
+/* */
+/* History Functions */
+/* */
+/* **************************************************************** */
+
+/* An array of HIST_ENTRY. This is where we store the history. */
+static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
+
+/* Non-zero means that we have enforced a limit on the amount of
+ history that we save. */
+int history_stifled = 0;
+
+/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
+ entries to remember. */
+int max_input_history;
+
+/* The current location of the interactive history pointer. Just makes
+ life easier for outside callers. */
+static int history_offset = 0;
+
+/* The number of strings currently stored in the input_history list. */
+int history_length = 0;
+
+/* The current number of slots allocated to the input_history. */
+static int history_size = 0;
+
+/* The number of slots to increase the_history by. */
+#define DEFAULT_HISTORY_GROW_SIZE 50
+
+/* The character that represents the start of a history expansion
+ request. This is usually `!'. */
+char history_expansion_char = '!';
+
+/* The character that invokes word substitution if found at the start of
+ a line. This is usually `^'. */
+char history_subst_char = '^';
+
+/* During tokenization, if this character is seen as the first character
+ of a word, then it, and all subsequent characters upto a newline are
+ ignored. For a Bourne shell, this should be '#'. Bash special cases
+ the interactive comment character to not be a comment delimiter. */
+char history_comment_char = '\0';
+
+/* The list of characters which inhibit the expansion of text if found
+ immediately following history_expansion_char. */
+char *history_no_expand_chars = " \t\n\r=";
+
+/* The logical `base' of the history array. It defaults to 1. */
+int history_base = 1;
+
+/* Return the current HISTORY_STATE of the history. */
+HISTORY_STATE *
+history_get_history_state ()
+{
+ HISTORY_STATE *state;
+
+ state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
+ state->entries = the_history;
+ state->offset = history_offset;
+ state->length = history_length;
+ state->size = history_size;
+
+ return (state);
+}
+
+/* Set the state of the current history array to STATE. */
+void
+history_set_history_state (state)
+ HISTORY_STATE *state;
+{
+ the_history = state->entries;
+ history_offset = state->offset;
+ history_length = state->length;
+ history_size = state->size;
+}
+
+/* Begin a session in which the history functions might be used. This
+ initializes interactive variables. */
+void
+using_history ()
+{
+ history_offset = history_length;
+}
+
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines. */
+int
+history_total_bytes ()
+{
+ register int i, result;
+
+ result = 0;
+
+ for (i = 0; the_history && the_history[i]; i++)
+ result += strlen (the_history[i]->line);
+
+ return (result);
+}
+
+/* Place STRING at the end of the history list. The data field
+ is set to NULL. */
+void
+add_history (string)
+ char *string;
+{
+ HIST_ENTRY *temp;
+
+ if (history_stifled && (history_length == max_input_history))
+ {
+ register int i;
+
+ /* If the history is stifled, and history_length is zero,
+ and it equals max_input_history, we don't save items. */
+ if (history_length == 0)
+ return;
+
+ /* If there is something in the slot, then remove it. */
+ if (the_history[0])
+ {
+ free (the_history[0]->line);
+ free (the_history[0]);
+ }
+
+ /* Copy the rest of the entries, moving down one slot. */
+ for (i = 0; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_base++;
+
+ }
+ else
+ {
+ if (!history_size)
+ {
+ history_size = DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
+ history_length = 1;
+
+ }
+ else
+ {
+ if (history_length == (history_size - 1))
+ {
+ history_size += DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)
+ xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
+ }
+ history_length++;
+ }
+ }
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ temp->line = savestring (string);
+ temp->data = (char *)NULL;
+
+ the_history[history_length] = (HIST_ENTRY *)NULL;
+ the_history[history_length - 1] = temp;
+}
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+HIST_ENTRY *
+replace_history_entry (which, line, data)
+ int which;
+ char *line;
+ char *data;
+{
+ HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ HIST_ENTRY *old_value;
+
+ if (which >= history_length)
+ return ((HIST_ENTRY *)NULL);
+
+ old_value = the_history[which];
+
+ temp->line = savestring (line);
+ temp->data = data;
+ the_history[which] = temp;
+
+ return (old_value);
+}
+
+/* Returns the magic number which says what history element we are
+ looking at now. In this implementation, it returns history_offset. */
+int
+where_history ()
+{
+ return (history_offset);
+}
+
+/* Search the history for STRING, starting at history_offset.
+ If DIRECTION < 0, then the search is through previous entries, else
+ through subsequent. If ANCHORED is non-zero, the string must
+ appear at the beginning of a history line, otherwise, the string
+ may appear anywhere in the line. If the string is found, then
+ current_history () is the history entry, and the value of this
+ function is the offset in the line of that history entry that the
+ string was found in. Otherwise, nothing is changed, and a -1 is
+ returned. */
+
+#define ANCHORED_SEARCH 1
+#define NON_ANCHORED_SEARCH 0
+
+static int
+history_search_internal (string, direction, anchored)
+ char *string;
+ int direction, anchored;
+{
+ register int i, reverse;
+ register char *line;
+ register int line_index;
+ int string_len;
+
+ i = history_offset;
+ reverse = (direction < 0);
+
+ /* Take care of trivial cases first. */
+
+ if (!history_length || ((i == history_length) && !reverse))
+ return (-1);
+
+ if (reverse && (i == history_length))
+ i--;
+
+#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
+
+ string_len = strlen (string);
+ while (1)
+ {
+ /* Search each line in the history list for STRING. */
+
+ /* At limit for direction? */
+ if ((reverse && i < 0) || (!reverse && i == history_length))
+ return (-1);
+
+ line = the_history[i]->line;
+ line_index = strlen (line);
+
+ /* If STRING is longer than line, no match. */
+ if (string_len > line_index)
+ {
+ NEXT_LINE ();
+ continue;
+ }
+
+ /* Handle anchored searches first. */
+ if (anchored == ANCHORED_SEARCH)
+ {
+ if (STREQN (string, line, string_len))
+ {
+ history_offset = i;
+ return (0);
+ }
+
+ NEXT_LINE ();
+ continue;
+ }
+
+ /* Do substring search. */
+ if (reverse)
+ {
+ line_index -= string_len;
+
+ while (line_index >= 0)
+ {
+ if (STREQN (string, line + line_index, string_len))
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ line_index--;
+ }
+ }
+ else
+ {
+ register int limit = line_index - string_len + 1;
+ line_index = 0;
+
+ while (line_index < limit)
+ {
+ if (STREQN (string, line + line_index, string_len))
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ line_index++;
+ }
+ }
+ NEXT_LINE ();
+ }
+}
+
+/* Do a non-anchored search for STRING through the history in DIRECTION. */
+int
+history_search (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
+}
+
+/* Do an anchored search for string through the history in DIRECTION. */
+int
+history_search_prefix (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, ANCHORED_SEARCH));
+}
+
+/* Remove history element WHICH from the history. The removed
+ element is returned to you so you can free the line, data,
+ and containing structure. */
+HIST_ENTRY *
+remove_history (which)
+ int which;
+{
+ HIST_ENTRY *return_value;
+
+ if (which >= history_length || !history_length)
+ return_value = (HIST_ENTRY *)NULL;
+ else
+ {
+ register int i;
+ return_value = the_history[which];
+
+ for (i = which; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_length--;
+ }
+
+ return (return_value);
+}
+
+/* Stifle the history list, remembering only MAX number of lines. */
+void
+stifle_history (max)
+ int max;
+{
+ if (max < 0)
+ max = 0;
+
+ if (history_length > max)
+ {
+ register int i, j;
+
+ /* This loses because we cannot free the data. */
+ for (i = 0; i < (history_length - max); i++)
+ {
+ free (the_history[i]->line);
+ free (the_history[i]);
+ }
+
+ history_base = i;
+ for (j = 0, i = history_length - max; j < max; i++, j++)
+ the_history[j] = the_history[i];
+ the_history[j] = (HIST_ENTRY *)NULL;
+ history_length = j;
+ }
+
+ history_stifled = 1;
+ max_input_history = max;
+}
+
+/* Stop stifling the history. This returns the previous amount the history
+ was stifled by. The value is positive if the history was stifled, negative
+ if it wasn't. */
+int
+unstifle_history ()
+{
+ int result = max_input_history;
+
+ if (history_stifled)
+ {
+ result = -result;
+ history_stifled = 0;
+ }
+
+ return (result);
+}
+
+/* Return the string that should be used in the place of this
+ filename. This only matters when you don't specify the
+ filename to read_history (), or write_history (). */
+static char *
+history_filename (filename)
+ char *filename;
+{
+ char *return_val = filename ? savestring (filename) : (char *)NULL;
+
+ if (!return_val)
+ {
+ char *home;
+ int home_len;
+
+ home = getenv ("HOME");
+
+ if (!home)
+ home = ".";
+
+ home_len = strlen (home);
+ /* strlen(".history") == 8 */
+ return_val = xmalloc (2 + home_len + 8);
+
+ strcpy (return_val, home);
+ return_val[home_len] = '/';
+ strcpy (return_val + home_len + 1, ".history");
+ }
+
+ return (return_val);
+}
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+int
+read_history (filename)
+ char *filename;
+{
+ return (read_history_range (filename, 0, -1));
+}
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+ Start reading at the FROM'th line and end at the TO'th. If FROM
+ is zero, start at the beginning. If TO is less than FROM, read
+ until the end of the file. If FILENAME is NULL, then read from
+ ~/.history. Returns 0 if successful, or errno if not. */
+int
+read_history_range (filename, from, to)
+ char *filename;
+ int from, to;
+{
+ register int line_start, line_end;
+ char *input, *buffer = (char *)NULL;
+ int file, current_line;
+ struct stat finfo;
+
+ input = history_filename (filename);
+ file = open (input, O_RDONLY, 0666);
+
+ if ((file < 0) || (fstat (file, &finfo) == -1))
+ goto error_and_exit;
+
+ buffer = xmalloc ((int)finfo.st_size + 1);
+
+ if (read (file, buffer, finfo.st_size) != finfo.st_size)
+ {
+ error_and_exit:
+ if (file >= 0)
+ close (file);
+
+ if (input)
+ free (input);
+
+ if (buffer)
+ free (buffer);
+
+ return (errno);
+ }
+
+ close (file);
+
+ /* Set TO to larger than end of file if negative. */
+ if (to < 0)
+ to = finfo.st_size;
+
+ /* Start at beginning of file, work to end. */
+ line_start = line_end = current_line = 0;
+
+ /* Skip lines until we are at FROM. */
+ while (line_start < finfo.st_size && current_line < from)
+ {
+ for (line_end = line_start; line_end < finfo.st_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ current_line++;
+ line_start = line_end + 1;
+ if (current_line == from)
+ break;
+ }
+ }
+
+ /* If there are lines left to gobble, then gobble them now. */
+ for (line_end = line_start; line_end < finfo.st_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ buffer[line_end] = '\0';
+
+ if (buffer[line_start])
+ add_history (buffer + line_start);
+
+ current_line++;
+
+ if (current_line >= to)
+ break;
+
+ line_start = line_end + 1;
+ }
+
+ if (input)
+ free (input);
+
+ if (buffer)
+ free (buffer);
+
+ return (0);
+}
+
+/* Truncate the history file FNAME, leaving only LINES trailing lines.
+ If FNAME is NULL, then use ~/.history. */
+int
+history_truncate_file (fname, lines)
+ char *fname;
+ register int lines;
+{
+ register int i;
+ int file, chars_read;
+ char *buffer = (char *)NULL, *filename;
+ struct stat finfo;
+
+ filename = history_filename (fname);
+ file = open (filename, O_RDONLY, 0666);
+
+ if (file == -1 || fstat (file, &finfo) == -1)
+ goto truncate_exit;
+
+ buffer = xmalloc ((int)finfo.st_size + 1);
+ chars_read = read (file, buffer, finfo.st_size);
+ close (file);
+
+ if (chars_read <= 0)
+ goto truncate_exit;
+
+ /* Count backwards from the end of buffer until we have passed
+ LINES lines. */
+ for (i = chars_read - 1; lines && i; i--)
+ {
+ if (buffer[i] == '\n')
+ lines--;
+ }
+
+ /* If this is the first line, then the file contains exactly the
+ number of lines we want to truncate to, so we don't need to do
+ anything. It's the first line if we don't find a newline between
+ the current value of i and 0. Otherwise, write from the start of
+ this line until the end of the buffer. */
+ for ( ; i; i--)
+ if (buffer[i] == '\n')
+ {
+ i++;
+ break;
+ }
+
+ /* Write only if there are more lines in the file than we want to
+ truncate to. */
+ if (i && ((file = open (filename, O_WRONLY, 0666)) != -1))
+ {
+ write (file, buffer + i, finfo.st_size - i);
+ close (file);
+ }
+
+ truncate_exit:
+ if (buffer)
+ free (buffer);
+
+ free (filename);
+ return 0;
+}
+
+#define HISTORY_APPEND 0
+#define HISTORY_OVERWRITE 1
+
+/* Workhorse function for writing history. Writes NELEMENT entries
+ from the history list to FILENAME. OVERWRITE is non-zero if you
+ wish to replace FILENAME with the entries. */
+static int
+history_do_write (filename, nelements, overwrite)
+ char *filename;
+ int nelements, overwrite;
+{
+ register int i;
+ char *output = history_filename (filename);
+ int file, mode;
+
+ mode = overwrite ? O_WRONLY | O_CREAT | O_TRUNC : O_WRONLY | O_APPEND;
+
+ if ((file = open (output, mode, 0666)) == -1)
+ {
+ if (output)
+ free (output);
+
+ return (errno);
+ }
+
+ if (nelements > history_length)
+ nelements = history_length;
+
+ /* Build a buffer of all the lines to write, and write them in one syscall.
+ Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
+ {
+ register int j = 0;
+ int buffer_size = 0;
+ char *buffer;
+
+ /* Calculate the total number of bytes to write. */
+ for (i = history_length - nelements; i < history_length; i++)
+ buffer_size += 1 + strlen (the_history[i]->line);
+
+ /* Allocate the buffer, and fill it. */
+ buffer = xmalloc (buffer_size);
+
+ for (i = history_length - nelements; i < history_length; i++)
+ {
+ strcpy (buffer + j, the_history[i]->line);
+ j += strlen (the_history[i]->line);
+ buffer[j++] = '\n';
+ }
+
+ write (file, buffer, buffer_size);
+ free (buffer);
+ }
+
+ close (file);
+
+ if (output)
+ free (output);
+
+ return (0);
+}
+
+/* Append NELEMENT entries to FILENAME. The entries appended are from
+ the end of the list minus NELEMENTs up to the end of the list. */
+int
+append_history (nelements, filename)
+ int nelements;
+ char *filename;
+{
+ return (history_do_write (filename, nelements, HISTORY_APPEND));
+}
+
+/* Overwrite FILENAME with the current history. If FILENAME is NULL,
+ then write the history list to ~/.history. Values returned
+ are as in read_history ().*/
+int
+write_history (filename)
+ char *filename;
+{
+ return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
+}
+
+/* Return the history entry at the current position, as determined by
+ history_offset. If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *
+current_history ()
+{
+ if ((history_offset == history_length) || !the_history)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[history_offset]);
+}
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry then return
+ a NULL pointer. */
+HIST_ENTRY *
+previous_history ()
+{
+ if (!history_offset)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[--history_offset]);
+}
+
+/* Move history_offset forward to the next history entry, and return
+ a pointer to that entry. If there is no next entry then return a
+ NULL pointer. */
+HIST_ENTRY *
+next_history ()
+{
+ if (history_offset == history_length)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[++history_offset]);
+}
+
+/* Return the current history array. The caller has to be carefull, since this
+ is the actual array of data, and could be bashed or made corrupt easily.
+ The array is terminated with a NULL pointer. */
+HIST_ENTRY **
+history_list ()
+{
+ return (the_history);
+}
+
+/* Return the history entry which is logically at OFFSET in the history array.
+ OFFSET is relative to history_base. */
+HIST_ENTRY *
+history_get (offset)
+ int offset;
+{
+ int local_index = offset - history_base;
+
+ if (local_index >= history_length ||
+ local_index < 0 ||
+ !the_history)
+ return ((HIST_ENTRY *)NULL);
+ return (the_history[local_index]);
+}
+
+/* Search for STRING in the history list. DIR is < 0 for searching
+ backwards. POS is an absolute index into the history list at
+ which point to begin searching. */
+int
+history_search_pos (string, dir, pos)
+ char *string;
+ int dir, pos;
+{
+ int ret, old = where_history ();
+ history_set_pos (pos);
+ if (history_search (string, dir) == -1)
+ {
+ history_set_pos (old);
+ return (-1);
+ }
+ ret = where_history ();
+ history_set_pos (old);
+ return ret;
+}
+
+/* Make the current history item be the one at POS, an absolute index.
+ Returns zero if POS is out of range, else non-zero. */
+int
+history_set_pos (pos)
+ int pos;
+{
+ if (pos > history_length || pos < 0 || !the_history)
+ return (0);
+ history_offset = pos;
+ return (1);
+}
+
+
+/* **************************************************************** */
+/* */
+/* History Expansion */
+/* */
+/* **************************************************************** */
+
+/* Hairy history expansion on text, not tokens. This is of general
+ use, and thus belongs in this library. */
+
+/* The last string searched for in a !?string? search. */
+static char *search_string = (char *)NULL;
+
+/* Return the event specified at TEXT + OFFSET modifying OFFSET to
+ point to after the event specifier. Just a pointer to the history
+ line is returned; NULL is returned in the event of a bad specifier.
+ You pass STRING with *INDEX equal to the history_expansion_char that
+ begins this specification.
+ DELIMITING_QUOTE is a character that is allowed to end the string
+ specification for what to search for in addition to the normal
+ characters `:', ` ', `\t', `\n', and sometimes `?'.
+ So you might call this function like:
+ line = get_history_event ("!echo:p", &index, 0); */
+char *
+get_history_event (string, caller_index, delimiting_quote)
+ char *string;
+ int *caller_index;
+ int delimiting_quote;
+{
+ register int i = *caller_index;
+ register char c;
+ HIST_ENTRY *entry;
+ int which, sign = 1;
+ int local_index, search_mode, substring_okay = 0;
+ char *temp;
+
+ /* The event can be specified in a number of ways.
+
+ !! the previous command
+ !n command line N
+ !-n current command-line minus N
+ !str the most recent command starting with STR
+ !?str[?]
+ the most recent command containing STR
+
+ All values N are determined via HISTORY_BASE. */
+
+ if (string[i] != history_expansion_char)
+ return ((char *)NULL);
+
+ /* Move on to the specification. */
+ i++;
+
+#define RETURN_ENTRY(e, w) \
+ return ((e = history_get (w)) ? e->line : (char *)NULL)
+
+ /* Handle !! case. */
+ if (string[i] == history_expansion_char)
+ {
+ i++;
+ which = history_base + (history_length - 1);
+ *caller_index = i;
+ RETURN_ENTRY (entry, which);
+ }
+
+ /* Hack case of numeric line specification. */
+ if (string[i] == '-')
+ {
+ sign = -1;
+ i++;
+ }
+
+ if (digit (string[i]))
+ {
+ /* Get the extent of the digits and compute the value. */
+ for (which = 0; digit (string[i]); i++)
+ which = (which * 10) + digit_value (string[i]);
+
+ *caller_index = i;
+
+ if (sign < 0)
+ which = (history_length + history_base) - which;
+
+ RETURN_ENTRY (entry, which);
+ }
+
+ /* This must be something to search for. If the spec begins with
+ a '?', then the string may be anywhere on the line. Otherwise,
+ the string must be found at the start of a line. */
+ if (string[i] == '?')
+ {
+ substring_okay++;
+ i++;
+ }
+
+ /* Only a closing `?' or a newline delimit a substring search string. */
+ for (local_index = i; c = string[i]; i++)
+ if ((!substring_okay && (whitespace (c) || c == ':' ||
+#if defined (SHELL)
+ member (c, ";&()|<>") ||
+#endif /* SHELL */
+ string[i] == delimiting_quote)) ||
+ string[i] == '\n' ||
+ (substring_okay && string[i] == '?'))
+ break;
+
+ temp = xmalloc (1 + (i - local_index));
+ strncpy (temp, &string[local_index], (i - local_index));
+ temp[i - local_index] = '\0';
+
+ if (substring_okay && string[i] == '?')
+ i++;
+
+ *caller_index = i;
+
+#define FAIL_SEARCH() \
+ do { history_offset = history_length; free (temp) ; return (char *)NULL; } while (0)
+
+ search_mode = substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH;
+ while (1)
+ {
+ local_index = history_search_internal (temp, -1, search_mode);
+
+ if (local_index < 0)
+ FAIL_SEARCH ();
+
+ if (local_index == 0 || substring_okay)
+ {
+ entry = current_history ();
+ history_offset = history_length;
+
+ /* If this was a substring search, then remember the
+ string that we matched for word substitution. */
+ if (substring_okay)
+ {
+ if (search_string)
+ free (search_string);
+ search_string = temp;
+ }
+ else
+ free (temp);
+ return (entry->line);
+ }
+
+ if (history_offset)
+ history_offset--;
+ else
+ FAIL_SEARCH ();
+ }
+#undef FAIL_SEARCH
+#undef RETURN_ENTRY
+}
+#if defined (SHELL)
+/* Function for extracting single-quoted strings. Used for inhibiting
+ history expansion within single quotes. */
+
+/* Extract the contents of STRING as if it is enclosed in single quotes.
+ SINDEX, when passed in, is the offset of the character immediately
+ following the opening single quote; on exit, SINDEX is left pointing
+ to the closing single quote. */
+static void
+rl_string_extract_single_quoted (string, sindex)
+ char *string;
+ int *sindex;
+{
+ register int i = *sindex;
+
+ while (string[i] && string[i] != '\'')
+ i++;
+
+ *sindex = i;
+}
+
+static char *
+quote_breaks (s)
+ char *s;
+{
+ register char *p, *r;
+ char *ret;
+ int len = 3;
+
+ for (p = s; p && *p; p++, len++)
+ {
+ if (*p == '\'')
+ len += 3;
+ else if (whitespace (*p) || *p == '\n')
+ len += 2;
+ }
+
+ r = ret = xmalloc (len);
+ *r++ = '\'';
+ for (p = s; p && *p; )
+ {
+ if (*p == '\'')
+ {
+ *r++ = '\'';
+ *r++ = '\\';
+ *r++ = '\'';
+ *r++ = '\'';
+ p++;
+ }
+ else if (whitespace (*p) || *p == '\n')
+ {
+ *r++ = '\'';
+ *r++ = *p++;
+ *r++ = '\'';
+ }
+ else
+ *r++ = *p++;
+ }
+ *r++ = '\'';
+ *r = '\0';
+ return ret;
+}
+#endif /* SHELL */
+
+static char *
+hist_error (ret, s, start, current, errtype)
+ char *ret, *s;
+ int start, current, errtype;
+{
+ char *temp, *emsg;
+ int ll;
+
+ ll = 1 + (current - start);
+ temp = xmalloc (1 + ll);
+ strncpy (temp, s + start, ll);
+ temp[ll] = 0;
+
+ switch (errtype)
+ {
+ case EVENT_NOT_FOUND:
+ emsg = "event not found";
+ break;
+ case BAD_WORD_SPEC:
+ emsg = "bad word specifier";
+ break;
+ case SUBST_FAILED:
+ emsg = "substitution failed";
+ break;
+ case BAD_MODIFIER:
+ emsg = "unrecognized history modifier";
+ break;
+ default:
+ emsg = "unknown expansion error";
+ break;
+ }
+
+ sprintf (ret, "%s: %s", temp, emsg);
+ free (temp);
+ return ret;
+}
+
+/* Get a history substitution string from STR starting at *IPTR
+ and return it. The length is returned in LENPTR.
+
+ A backslash can quote the delimiter. If the string is the
+ empty string, the previous pattern is used. If there is
+ no previous pattern for the lhs, the last history search
+ string is used.
+
+ If IS_RHS is 1, we ignore empty strings and set the pattern
+ to "" anyway. subst_lhs is not changed if the lhs is empty;
+ subst_rhs is allowed to be set to the empty string. */
+
+static char *
+get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
+ char *str;
+ int *iptr, delimiter, is_rhs, *lenptr;
+{
+ register int si, i, j, k;
+ char *s = (char *) NULL;
+
+ i = *iptr;
+
+ for (si = i; str[si] && str[si] != delimiter; si++)
+ if (str[si] == '\\' && str[si + 1] == delimiter)
+ si++;
+
+ if (si > i || is_rhs)
+ {
+ s = xmalloc (si - i + 1);
+ for (j = 0, k = i; k < si; j++, k++)
+ {
+ /* Remove a backslash quoting the search string delimiter. */
+ if (str[k] == '\\' && str[k + 1] == delimiter)
+ k++;
+ s[j] = str[k];
+ }
+ s[j] = '\0';
+ if (lenptr)
+ *lenptr = j;
+ }
+
+ i = si;
+ if (str[i])
+ i++;
+ *iptr = i;
+
+ return s;
+}
+
+static void
+postproc_subst_rhs ()
+{
+ char *new;
+ int i, j, new_size;
+
+ new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
+ for (i = j = 0; i < subst_rhs_len; i++)
+ {
+ if (subst_rhs[i] == '&')
+ {
+ if (j + subst_lhs_len >= new_size)
+ new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
+ strcpy (new + j, subst_lhs);
+ j += subst_lhs_len;
+ }
+ else
+ {
+ /* a single backslash protects the `&' from lhs interpolation */
+ if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
+ i++;
+ if (j >= new_size)
+ new = xrealloc (new, new_size *= 2);
+ new[j++] = subst_rhs[i];
+ }
+ }
+ new[j] = '\0';
+ free (subst_rhs);
+ subst_rhs = new;
+ subst_rhs_len = j;
+}
+
+/* Expand the bulk of a history specifier starting at STRING[START].
+ Returns 0 if everything is OK, -1 if an error occurred, and 1
+ if the `p' modifier was supplied and the caller should just print
+ the returned string. Returns the new index into string in
+ *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
+static int
+history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
+ char *string;
+ int start, *end_index_ptr;
+ char **ret_string;
+ char *current_line; /* for !# */
+{
+ int i, n, starting_index;
+ int substitute_globally, want_quotes, print_only;
+ char *event, *temp, *result, *tstr, *t, c, *word_spec;
+ int result_len;
+
+ result = xmalloc (result_len = 128);
+
+ i = start;
+
+ /* If it is followed by something that starts a word specifier,
+ then !! is implied as the event specifier. */
+
+ if (member (string[i + 1], ":$*%^"))
+ {
+ char fake_s[3];
+ int fake_i = 0;
+ i++;
+ fake_s[0] = fake_s[1] = history_expansion_char;
+ fake_s[2] = '\0';
+ event = get_history_event (fake_s, &fake_i, 0);
+ }
+ else if (string[i + 1] == '#')
+ {
+ i += 2;
+ event = current_line;
+ }
+ else
+ {
+ int quoted_search_delimiter = 0;
+
+ /* If the character before this `!' is a double or single
+ quote, then this expansion takes place inside of the
+ quoted string. If we have to search for some text ("!foo"),
+ allow the delimiter to end the search string. */
+ if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+ quoted_search_delimiter = string[i - 1];
+ event = get_history_event (string, &i, quoted_search_delimiter);
+ }
+
+ if (!event)
+ {
+ hist_error (result, string, start, i, EVENT_NOT_FOUND);
+ *ret_string = result;
+ return (-1);
+ }
+
+ /* If a word specifier is found, then do what that requires. */
+ starting_index = i;
+ word_spec = get_history_word_specifier (string, event, &i);
+
+ /* There is no such thing as a `malformed word specifier'. However,
+ it is possible for a specifier that has no match. In that case,
+ we complain. */
+ if (word_spec == (char *)&error_pointer)
+ {
+ hist_error (result, string, starting_index, i, BAD_WORD_SPEC);
+ *ret_string = result;
+ return (-1);
+ }
+
+ /* If no word specifier, than the thing of interest was the event. */
+ if (!word_spec)
+ temp = savestring (event);
+ else
+ {
+ temp = savestring (word_spec);
+ free (word_spec);
+ }
+
+ /* Perhaps there are other modifiers involved. Do what they say. */
+ want_quotes = substitute_globally = print_only = 0;
+ starting_index = i;
+
+ while (string[i] == ':')
+ {
+ c = string[i + 1];
+
+ if (c == 'g')
+ {
+ substitute_globally = 1;
+ i++;
+ c = string[i + 1];
+ }
+
+ switch (c)
+ {
+ default:
+ hist_error (result, string, i+1, i+2, BAD_MODIFIER);
+ *ret_string = result;
+ free (temp);
+ return -1;
+
+#if defined (SHELL)
+ case 'q':
+ want_quotes = 'q';
+ break;
+
+ case 'x':
+ want_quotes = 'x';
+ break;
+#endif /* SHELL */
+
+ /* :p means make this the last executed line. So we
+ return an error state after adding this line to the
+ history. */
+ case 'p':
+ print_only++;
+ break;
+
+ /* :t discards all but the last part of the pathname. */
+ case 't':
+ tstr = strrchr (temp, '/');
+ if (tstr)
+ {
+ tstr++;
+ t = savestring (tstr);
+ free (temp);
+ temp = t;
+ }
+ break;
+
+ /* :h discards the last part of a pathname. */
+ case 'h':
+ tstr = strrchr (temp, '/');
+ if (tstr)
+ *tstr = '\0';
+ break;
+
+ /* :r discards the suffix. */
+ case 'r':
+ tstr = strrchr (temp, '.');
+ if (tstr)
+ *tstr = '\0';
+ break;
+
+ /* :e discards everything but the suffix. */
+ case 'e':
+ tstr = strrchr (temp, '.');
+ if (tstr)
+ {
+ t = savestring (tstr);
+ free (temp);
+ temp = t;
+ }
+ break;
+
+ /* :s/this/that substitutes `that' for the first
+ occurrence of `this'. :gs/this/that substitutes `that'
+ for each occurrence of `this'. :& repeats the last
+ substitution. :g& repeats the last substitution
+ globally. */
+
+ case '&':
+ case 's':
+ {
+ char *new_event, *t;
+ int delimiter, failed, si, l_temp;
+
+ if (c == 's')
+ {
+ if (i + 2 < (int)strlen (string))
+ delimiter = string[i + 2];
+ else
+ break; /* no search delimiter */
+
+ i += 3;
+
+ t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
+ /* An empty substitution lhs with no previous substitution
+ uses the last search string as the lhs. */
+ if (t)
+ {
+ if (subst_lhs)
+ free (subst_lhs);
+ subst_lhs = t;
+ }
+ else if (!subst_lhs)
+ {
+ if (search_string && *search_string)
+ {
+ subst_lhs = savestring (search_string);
+ subst_lhs_len = strlen (subst_lhs);
+ }
+ else
+ {
+ subst_lhs = (char *) NULL;
+ subst_lhs_len = 0;
+ }
+ }
+
+ /* If there is no lhs, the substitution can't succeed. */
+ if (subst_lhs_len == 0)
+ {
+ hist_error (result, string, starting_index, i, SUBST_FAILED);
+ *ret_string = result;
+ free (temp);
+ return -1;
+ }
+
+ if (subst_rhs)
+ free (subst_rhs);
+ subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
+
+ /* If `&' appears in the rhs, it's supposed to be replaced
+ with the lhs. */
+ if (member ('&', subst_rhs))
+ postproc_subst_rhs ();
+ }
+ else
+ i += 2;
+
+ l_temp = strlen (temp);
+ /* Ignore impossible cases. */
+ if (subst_lhs_len > l_temp)
+ {
+ hist_error (result, string, starting_index, i, SUBST_FAILED);
+ *ret_string = result;
+ free (temp);
+ return (-1);
+ }
+
+ /* Find the first occurrence of THIS in TEMP. */
+ si = 0;
+ for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
+ if (STREQN (temp+si, subst_lhs, subst_lhs_len))
+ {
+ int len = subst_rhs_len - subst_lhs_len + l_temp;
+ new_event = xmalloc (1 + len);
+ strncpy (new_event, temp, si);
+ strncpy (new_event + si, subst_rhs, subst_rhs_len);
+ strncpy (new_event + si + subst_rhs_len,
+ temp + si + subst_lhs_len,
+ l_temp - (si + subst_lhs_len));
+ new_event[len] = '\0';
+ free (temp);
+ temp = new_event;
+
+ failed = 0;
+
+ if (substitute_globally)
+ {
+ si += subst_rhs_len;
+ l_temp = strlen (temp);
+ substitute_globally++;
+ continue;
+ }
+ else
+ break;
+ }
+
+ if (substitute_globally > 1)
+ {
+ substitute_globally = 0;
+ continue; /* don't want to increment i */
+ }
+
+ if (failed == 0)
+ continue; /* don't want to increment i */
+
+ hist_error (result, string, starting_index, i, SUBST_FAILED);
+ *ret_string = result;
+ free (temp);
+ return (-1);
+ }
+ }
+ i += 2;
+ }
+ /* Done with modfiers. */
+ /* Believe it or not, we have to back the pointer up by one. */
+ --i;
+
+#if defined (SHELL)
+ if (want_quotes)
+ {
+ char *x;
+
+ if (want_quotes == 'q')
+ x = single_quote (temp);
+ else if (want_quotes == 'x')
+ x = quote_breaks (temp);
+ else
+ x = savestring (temp);
+
+ free (temp);
+ temp = x;
+ }
+#endif /* SHELL */
+
+ n = strlen (temp);
+ if (n > result_len)
+ result = xrealloc (result, n + 1);
+ strcpy (result, temp);
+ free (temp);
+
+ *end_index_ptr = i;
+ *ret_string = result;
+ return (print_only);
+}
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ -1) If there was an error in expansion.
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ 2) If the `p' modifier was given and the caller should print the result
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+
+#define ADD_STRING(s) \
+ do \
+ { \
+ int sl = strlen (s); \
+ j += sl; \
+ while (j >= result_len) \
+ result = xrealloc (result, result_len += 128); \
+ strcpy (result + j - sl, s); \
+ } \
+ while (0)
+
+#define ADD_CHAR(c) \
+ do \
+ { \
+ if (j >= result_len) \
+ result = xrealloc (result, result_len += 64); \
+ result[j++] = c; \
+ result[j] = '\0'; \
+ } \
+ while (0)
+
+int
+history_expand (hstring, output)
+ char *hstring;
+ char **output;
+{
+ register int j;
+ int i, r, l, passc, cc, modified, eindex, only_printing;
+ char *string;
+
+ /* The output string, and its length. */
+ int result_len;
+ char *result;
+
+ /* Used when adding the string. */
+ char *temp;
+
+ /* Prepare the buffer for printing error messages. */
+ result = xmalloc (result_len = 256);
+ result[0] = '\0';
+
+ only_printing = modified = 0;
+ l = strlen (hstring);
+
+ /* Grovel the string. Only backslash can quote the history escape
+ character. We also handle arg specifiers. */
+
+ /* Before we grovel forever, see if the history_expansion_char appears
+ anywhere within the text. */
+
+ /* The quick substitution character is a history expansion all right. That
+ is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
+ that is the substitution that we do. */
+ if (hstring[0] == history_subst_char)
+ {
+ string = xmalloc (l + 5);
+
+ string[0] = string[1] = history_expansion_char;
+ string[2] = ':';
+ string[3] = 's';
+ strcpy (string + 4, hstring);
+ l += 4;
+ }
+ else
+ {
+ string = hstring;
+ /* If not quick substitution, still maybe have to do expansion. */
+
+ /* `!' followed by one of the characters in history_no_expand_chars
+ is NOT an expansion. */
+ for (i = 0; string[i]; i++)
+ {
+ cc = string[i + 1];
+ if (string[i] == history_expansion_char)
+ {
+ if (!cc || member (cc, history_no_expand_chars))
+ continue;
+#if defined (SHELL)
+ /* The shell uses ! as a pattern negation character
+ in globbing [...] expressions, so let those pass
+ without expansion. */
+ else if (i > 0 && (string[i - 1] == '[') &&
+ member (']', string + i + 1))
+ continue;
+#endif /* SHELL */
+ else
+ break;
+ }
+#if defined (SHELL)
+ else if (string[i] == '\'')
+ {
+ /* If this is bash, single quotes inhibit history expansion. */
+ i++;
+ rl_string_extract_single_quoted (string, &i);
+ }
+ else if (string[i] == '\\')
+ {
+ /* If this is bash, allow backslashes to quote single
+ quotes and
+ the history expansion character. */
+ if (cc == '\'' || cc == history_expansion_char)
+ i++;
+ }
+#endif /* SHELL */
+ }
+
+ if (string[i] != history_expansion_char)
+ {
+ free (result);
+ *output = savestring (string);
+ return (0);
+ }
+ }
+
+ /* Extract and perform the substitution. */
+ for (passc = i = j = 0; i < l; i++)
+ {
+ int tchar = string[i];
+
+ if (passc)
+ {
+ passc = 0;
+ ADD_CHAR (tchar);
+ continue;
+ }
+
+ if (tchar == history_expansion_char)
+ tchar = -3;
+
+ switch (tchar)
+ {
+ default:
+ ADD_CHAR (string[i]);
+ break;
+
+ case '\\':
+ passc++;
+ ADD_CHAR (tchar);
+ break;
+
+#if defined (SHELL)
+ case '\'':
+ {
+ /* If this is bash, single quotes inhibit history expansion. */
+ int quote, slen;
+
+ quote = i++;
+ rl_string_extract_single_quoted (string, &i);
+
+ slen = i - quote + 2;
+ temp = xmalloc (slen);
+ strncpy (temp, string + quote, slen);
+ temp[slen - 1] = '\0';
+ ADD_STRING (temp);
+ free (temp);
+ break;
+ }
+#endif /* SHELL */
+
+ case -3: /* history_expansion_char */
+ cc = string[i + 1];
+
+ /* If the history_expansion_char is followed by one of the
+ characters in history_no_expand_chars, then it is not a
+ candidate for expansion of any kind. */
+ if (member (cc, history_no_expand_chars))
+ {
+ ADD_CHAR (string[i]);
+ break;
+ }
+
+#ifdef NO_BANG_HASH_MODIFIERS
+ /* There is something that is listed as a `word specifier' in csh
+ documentation which means `the expanded text to this point'.
+ That is not a word specifier, it is an event specifier. If we
+ don't want to allow modifiers with `!#', just stick the current
+ output line in again. */
+ if (cc == '#')
+ {
+ if (result)
+ {
+ temp = xmalloc (1 + strlen (result));
+ strcpy (temp, result);
+ ADD_STRING (temp);
+ free (temp);
+ }
+ i++;
+ break;
+ }
+#endif
+
+ r = history_expand_internal (string, i, &eindex, &temp, result);
+ if (r < 0)
+ {
+ *output = temp;
+ free (result);
+ if (string != hstring)
+ free (string);
+ return -1;
+ }
+ else
+ {
+ if (temp)
+ {
+ modified++;
+ if (*temp)
+ ADD_STRING (temp);
+ free (temp);
+ }
+ only_printing = r == 1;
+ i = eindex;
+ }
+ break;
+ }
+ }
+
+ *output = result;
+ if (string != hstring)
+ free (string);
+
+ if (only_printing)
+ {
+ add_history (result);
+ return (2);
+ }
+
+ return (modified != 0);
+}
+
+/* Return a consed string which is the word specified in SPEC, and found
+ in FROM. NULL is returned if there is no spec. The address of
+ ERROR_POINTER is returned if the word specified cannot be found.
+ CALLER_INDEX is the offset in SPEC to start looking; it is updated
+ to point to just after the last character parsed. */
+static char *
+get_history_word_specifier (spec, from, caller_index)
+ char *spec, *from;
+ int *caller_index;
+{
+ register int i = *caller_index;
+ int first, last;
+ int expecting_word_spec = 0;
+ char *result;
+
+ /* The range of words to return doesn't exist yet. */
+ first = last = 0;
+ result = (char *)NULL;
+
+ /* If we found a colon, then this *must* be a word specification. If
+ it isn't, then it is an error. */
+ if (spec[i] == ':')
+ {
+ i++;
+ expecting_word_spec++;
+ }
+
+ /* Handle special cases first. */
+
+ /* `%' is the word last searched for. */
+ if (spec[i] == '%')
+ {
+ *caller_index = i + 1;
+ return (search_string ? savestring (search_string) : savestring (""));
+ }
+
+ /* `*' matches all of the arguments, but not the command. */
+ if (spec[i] == '*')
+ {
+ *caller_index = i + 1;
+ result = history_arg_extract (1, '$', from);
+ return (result ? result : savestring (""));
+ }
+
+ /* `$' is last arg. */
+ if (spec[i] == '$')
+ {
+ *caller_index = i + 1;
+ return (history_arg_extract ('$', '$', from));
+ }
+
+ /* Try to get FIRST and LAST figured out. */
+
+ if (spec[i] == '-' || spec[i] == '^')
+ first = 1;
+ else if (digit (spec[i]) && expecting_word_spec)
+ {
+ for (first = 0; digit (spec[i]); i++)
+ first = (first * 10) + digit_value (spec[i]);
+ }
+ else
+ return ((char *)NULL); /* no valid `first' for word specifier */
+
+ if (spec[i] == '^' || spec[i] == '*')
+ {
+ last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
+ i++;
+ }
+ else if (spec[i] != '-')
+ last = first;
+ else
+ {
+ i++;
+
+ if (digit (spec[i]))
+ {
+ for (last = 0; digit (spec[i]); i++)
+ last = (last * 10) + digit_value (spec[i]);
+ }
+ else if (spec[i] == '$')
+ {
+ i++;
+ last = '$';
+ }
+ else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
+ last = -1; /* x- abbreviates x-$ omitting word `$' */
+ }
+
+ *caller_index = i;
+
+ if (last >= first || last == '$' || last < 0)
+ result = history_arg_extract (first, last, from);
+
+ return (result ? result : (char *)&error_pointer);
+}
+
+/* Extract the args specified, starting at FIRST, and ending at LAST.
+ The args are taken from STRING. If either FIRST or LAST is < 0,
+ then make that arg count from the right (subtract from the number of
+ tokens, so that FIRST = -1 means the next to last token on the line).
+ If LAST is `$' the last arg from STRING is used. */
+char *
+history_arg_extract (first, last, string)
+ int first, last;
+ char *string;
+{
+ register int i, len;
+ char *result = (char *)NULL;
+ int size = 0, offset = 0;
+ char **list;
+
+ /* XXX - think about making history_tokenize return a struct array,
+ each struct in array being a string and a length to avoid the
+ calls to strlen below. */
+ if ((list = history_tokenize (string)) == NULL)
+ return ((char *)NULL);
+
+ for (len = 0; list[len]; len++)
+ ;
+
+ if (last < 0)
+ last = len + last - 1;
+
+ if (first < 0)
+ first = len + first - 1;
+
+ if (last == '$')
+ last = len - 1;
+
+ if (first == '$')
+ first = len - 1;
+
+ last++;
+
+ if (first > len || last > len || first < 0 || last < 0)
+ result = ((char *)NULL);
+ else
+ {
+ for (size = 0, i = first; i < last; i++)
+ size += strlen (list[i]) + 1;
+ result = xmalloc (size + 1);
+
+ for (i = first; i < last; i++)
+ {
+ strcpy (result + offset, list[i]);
+ offset += strlen (list[i]);
+ if (i + 1 < last)
+ {
+ result[offset++] = ' ';
+ result[offset] = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < len; i++)
+ free (list[i]);
+ free (list);
+
+ return (result);
+}
+
+#define slashify_in_quotes "\\`\"$"
+
+/* Return an array of tokens, much as the shell might. The tokens are
+ parsed out of STRING. */
+char **
+history_tokenize (string)
+ char *string;
+{
+ char **result = (char **)NULL;
+ register int i, start, result_index, size;
+ int len;
+
+ i = result_index = size = 0;
+
+ /* Get a token, and stuff it into RESULT. The tokens are split
+ exactly where the shell would split them. */
+ while (string[i])
+ {
+ int delimiter = 0;
+
+ /* Skip leading whitespace. */
+ for (; string[i] && whitespace (string[i]); i++)
+ ;
+ if (!string[i] || string[i] == history_comment_char)
+ return (result);
+
+ start = i;
+
+ if (member (string[i], "()\n"))
+ {
+ i++;
+ goto got_token;
+ }
+
+ if (member (string[i], "<>;&|$"))
+ {
+ int peek = string[i + 1];
+
+ if (peek == string[i] && peek != '$')
+ {
+ if (peek == '<' && string[i + 2] == '-')
+ i++;
+ i += 2;
+ goto got_token;
+ }
+ else
+ {
+ if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
+ ((peek == '>') && (string[i] == '&')) ||
+ ((peek == '(') && (string[i] == '$')))
+ {
+ i += 2;
+ goto got_token;
+ }
+ }
+ if (string[i] != '$')
+ {
+ i++;
+ goto got_token;
+ }
+ }
+
+ /* Get word from string + i; */
+
+ if (member (string[i], "\"'`"))
+ delimiter = string[i++];
+
+ for (; string[i]; i++)
+ {
+ if (string[i] == '\\' && string[i + 1] == '\n')
+ {
+ i++;
+ continue;
+ }
+
+ if (string[i] == '\\' && delimiter != '\'' &&
+ (delimiter != '"' || member (string[i], slashify_in_quotes)))
+ {
+ i++;
+ continue;
+ }
+
+ if (delimiter && string[i] == delimiter)
+ {
+ delimiter = 0;
+ continue;
+ }
+
+ if (!delimiter && (member (string[i], " \t\n;&()|<>")))
+ break;
+
+ if (!delimiter && member (string[i], "\"'`"))
+ delimiter = string[i];
+ }
+ got_token:
+
+ len = i - start;
+ if (result_index + 2 >= size)
+ result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
+ result[result_index] = xmalloc (1 + len);
+ strncpy (result[result_index], string + start, len);
+ result[result_index][len] = '\0';
+ result[++result_index] = (char *)NULL;
+ }
+
+ return (result);
+}
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)xmalloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "history: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
+
+/* **************************************************************** */
+/* */
+/* Test Code */
+/* */
+/* **************************************************************** */
+#ifdef TEST
+main ()
+{
+ char line[1024], *t;
+ int done = 0;
+
+ line[0] = 0;
+
+ while (!done)
+ {
+ fprintf (stdout, "history%% ");
+ t = gets (line);
+
+ if (!t)
+ strcpy (line, "quit");
+
+ if (line[0])
+ {
+ char *expansion;
+ int result;
+
+ using_history ();
+
+ result = history_expand (line, &expansion);
+ strcpy (line, expansion);
+ free (expansion);
+ if (result)
+ fprintf (stderr, "%s\n", line);
+
+ if (result < 0)
+ continue;
+
+ add_history (line);
+ }
+
+ if (strcmp (line, "quit") == 0) done = 1;
+ if (strcmp (line, "save") == 0) write_history (0);
+ if (strcmp (line, "read") == 0) read_history (0);
+ if (strcmp (line, "list") == 0)
+ {
+ register HIST_ENTRY **the_list = history_list ();
+ register int i;
+
+ if (the_list)
+ for (i = 0; the_list[i]; i++)
+ fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
+ }
+ if (strncmp (line, "delete", strlen ("delete")) == 0)
+ {
+ int which;
+ if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+ {
+ HIST_ENTRY *entry = remove_history (which);
+ if (!entry)
+ fprintf (stderr, "No such entry %d\n", which);
+ else
+ {
+ free (entry->line);
+ free (entry);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "non-numeric arg given to `delete'\n");
+ }
+ }
+ }
+}
+
+#endif /* TEST */
+
+/*
+* Local variables:
+* compile-command: "gcc -g -DTEST -o history history.c"
+* end:
+*/
diff --git a/gnu/lib/libreadline/isearch.c b/gnu/lib/libreadline/isearch.c
new file mode 100644
index 000000000000..591cc99ac3e2
--- /dev/null
+++ b/gnu/lib/libreadline/isearch.c
@@ -0,0 +1,372 @@
+/* **************************************************************** */
+/* */
+/* I-Search and Searching */
+/* */
+/* **************************************************************** */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The 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 1, or (at your option)
+ any later version.
+
+ The 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#include "memalloc.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+
+/* Variables imported from other files in the readline library. */
+extern Keymap _rl_keymap;
+extern HIST_ENTRY *saved_line_for_history;
+extern int rl_line_buffer_len;
+extern int rl_point, rl_end;
+extern char *rl_line_buffer;
+
+extern char *xmalloc (), *xrealloc ();
+
+static int rl_search_history ();
+
+/* Last line found by the current incremental search, so we don't `find'
+ identical lines many times in a row. */
+static char *prev_line_found;
+
+/* Search backwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+rl_reverse_search_history (sign, key)
+ int sign;
+ int key;
+{
+ return (rl_search_history (-sign, key));
+}
+
+/* Search forwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+rl_forward_search_history (sign, key)
+ int sign;
+ int key;
+{
+ return (rl_search_history (sign, key));
+}
+
+/* Display the current state of the search in the echo-area.
+ SEARCH_STRING contains the string that is being searched for,
+ DIRECTION is zero for forward, or 1 for reverse,
+ WHERE is the history list number of the current line. If it is
+ -1, then this line is the starting one. */
+static void
+rl_display_search (search_string, reverse_p, where)
+ char *search_string;
+ int reverse_p, where;
+{
+ char *message;
+
+ message = xmalloc (1 + (search_string ? strlen (search_string) : 0) + 30);
+ *message = '\0';
+
+#if defined (NOTDEF)
+ if (where != -1)
+ sprintf (message, "[%d]", where + history_base);
+#endif /* NOTDEF */
+
+ strcat (message, "(");
+
+ if (reverse_p)
+ strcat (message, "reverse-");
+
+ strcat (message, "i-search)`");
+
+ if (search_string)
+ strcat (message, search_string);
+
+ strcat (message, "': ");
+ rl_message ("%s", message, 0);
+ free (message);
+ rl_redisplay ();
+}
+
+/* Search through the history looking for an interactively typed string.
+ This is analogous to i-search. We start the search in the current line.
+ DIRECTION is which direction to search; >= 0 means forward, < 0 means
+ backwards. */
+static int
+rl_search_history (direction, invoking_key)
+ int direction;
+ int invoking_key;
+{
+ /* The string that the user types in to search for. */
+ char *search_string;
+
+ /* The current length of SEARCH_STRING. */
+ int search_string_index;
+
+ /* The amount of space that SEARCH_STRING has allocated to it. */
+ int search_string_size;
+
+ /* The list of lines to search through. */
+ char **lines, *allocated_line = (char *)NULL;
+
+ /* The length of LINES. */
+ int hlen;
+
+ /* Where we get LINES from. */
+ HIST_ENTRY **hlist = history_list ();
+
+ register int i = 0;
+ int orig_point = rl_point;
+ int orig_line = where_history ();
+ int last_found_line = orig_line;
+ int c, done = 0, found, failed, sline_len;
+
+ /* The line currently being searched. */
+ char *sline;
+
+ /* Offset in that line. */
+ int line_index;
+
+ /* Non-zero if we are doing a reverse search. */
+ int reverse = (direction < 0);
+
+ /* Create an arrary of pointers to the lines that we want to search. */
+ maybe_replace_line ();
+ if (hlist)
+ for (i = 0; hlist[i]; i++);
+
+ /* Allocate space for this many lines, +1 for the current input line,
+ and remember those lines. */
+ lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *));
+ for (i = 0; i < hlen; i++)
+ lines[i] = hlist[i]->line;
+
+ if (saved_line_for_history)
+ lines[i] = saved_line_for_history->line;
+ else
+ {
+ /* Keep track of this so we can free it. */
+ allocated_line = xmalloc (1 + strlen (rl_line_buffer));
+ strcpy (allocated_line, &rl_line_buffer[0]);
+ lines[i] = allocated_line;
+ }
+
+ hlen++;
+
+ /* The line where we start the search. */
+ i = orig_line;
+
+ /* Initialize search parameters. */
+ search_string = xmalloc (search_string_size = 128);
+ *search_string = '\0';
+ search_string_index = 0;
+
+ /* Normalize DIRECTION into 1 or -1. */
+ direction = (direction >= 0) ? 1 : -1;
+
+ rl_display_search (search_string, reverse, -1);
+
+ sline = rl_line_buffer;
+ sline_len = strlen (sline);
+ line_index = rl_point;
+
+ found = failed = 0;
+ while (!done)
+ {
+ Function *f = (Function *)NULL;
+
+ /* Read a key and decide how to proceed. */
+ c = rl_read_key ();
+
+ /* Hack C to Do What I Mean. */
+ if (_rl_keymap[c].type == ISFUNC)
+ {
+ f = _rl_keymap[c].function;
+
+ if (f == rl_reverse_search_history)
+ c = reverse ? -1 : -2;
+ else if (f == rl_forward_search_history)
+ c = !reverse ? -1 : -2;
+ }
+
+ switch (c)
+ {
+ case ESC:
+ done = 1;
+ continue;
+
+ case -1:
+ if (!search_string_index)
+ continue;
+ else
+ {
+ if (reverse)
+ --line_index;
+ else
+ {
+ if (line_index != sline_len)
+ ++line_index;
+ else
+ ding ();
+ }
+ }
+ break;
+
+ /* switch directions */
+ case -2:
+ direction = -direction;
+ reverse = (direction < 0);
+ break;
+
+ case CTRL ('G'):
+ strcpy (rl_line_buffer, lines[orig_line]);
+ rl_point = orig_point;
+ rl_end = strlen (rl_line_buffer);
+ rl_clear_message ();
+ free (allocated_line);
+ free (lines);
+ return;
+
+ default:
+ if (c < 32 || c > 126)
+ {
+ rl_execute_next (c);
+ done = 1;
+ continue;
+ }
+ else
+ {
+ /* Add character to search string and continue search. */
+ if (search_string_index + 2 >= search_string_size)
+ {
+ search_string_size += 128;
+ search_string = xrealloc (search_string, search_string_size);
+ }
+ search_string[search_string_index++] = c;
+ search_string[search_string_index] = '\0';
+ break;
+ }
+ }
+
+ found = failed = 0;
+ while (1)
+ {
+ int limit = sline_len - search_string_index + 1;
+
+ /* Search the current line. */
+ while (reverse ? (line_index >= 0) : (line_index < limit))
+ {
+ if (STREQN(search_string, sline + line_index, search_string_index))
+ {
+ found++;
+ break;
+ }
+ else
+ line_index += reverse ? -1 : 1;
+ }
+ if (found)
+ break;
+
+ /* Move to the next line, but skip new copies of the line
+ we just found and lines shorter than the string we're
+ searching for. */
+ do
+ {
+ /* Move to the next line. */
+ i += direction;
+
+ /* At limit for direction? */
+ if ((reverse && i < 0) || (!reverse && i == hlen))
+ {
+ failed++;
+ break;
+ }
+
+ /* We will need these later. */
+ sline = lines[i];
+ sline_len = strlen (sline);
+ }
+ while ((prev_line_found && STREQ (prev_line_found, lines[i])) ||
+ (search_string_index > sline_len));
+
+ if (failed)
+ break;
+
+ /* Now set up the line for searching... */
+ if (reverse)
+ line_index = sline_len - search_string_index;
+ else
+ line_index = 0;
+ }
+
+ if (failed)
+ {
+ /* We cannot find the search string. Ding the bell. */
+ ding ();
+ i = last_found_line;
+ break;
+ }
+
+ /* We have found the search string. Just display it. But don't
+ actually move there in the history list until the user accepts
+ the location. */
+ if (found)
+ {
+ int line_len;
+
+ prev_line_found = lines[i];
+ line_len = strlen (lines[i]);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (rl_line_buffer, lines[i]);
+ rl_point = line_index;
+ rl_end = line_len;
+ last_found_line = i;
+ rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
+ }
+ }
+
+ /* The searching is over. The user may have found the string that she
+ was looking for, or else she may have exited a failing search. If
+ LINE_INDEX is -1, then that shows that the string searched for was
+ not found. We use this to determine where to place rl_point. */
+
+ /* First put back the original state. */
+ strcpy (rl_line_buffer, lines[orig_line]);
+
+ /* Free the search string. */
+ free (search_string);
+
+ if (last_found_line < orig_line)
+ rl_get_previous_history (orig_line - last_found_line);
+ else
+ rl_get_next_history (last_found_line - orig_line);
+
+ /* If the string was not found, put point at the end of the line. */
+ if (line_index < 0)
+ line_index = strlen (rl_line_buffer);
+ rl_point = line_index;
+ rl_clear_message ();
+
+ free (allocated_line);
+ free (lines);
+
+ return 0;
+}
diff --git a/gnu/lib/libreadline/keymaps.c b/gnu/lib/libreadline/keymaps.c
new file mode 100644
index 000000000000..e7974c99602b
--- /dev/null
+++ b/gnu/lib/libreadline/keymaps.c
@@ -0,0 +1,195 @@
+/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include "rlconf.h"
+#include <readline/keymaps.h>
+#include "emacs_keymap.c"
+
+#ifdef VI_MODE
+#include "vi_keymap.c"
+#endif
+
+extern int rl_do_lowercase_version ();
+extern int rl_rubout (), rl_insert ();
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+/* **************************************************************** */
+/* */
+/* Functions for manipulating Keymaps. */
+/* */
+/* **************************************************************** */
+
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+Keymap
+rl_make_bare_keymap ()
+{
+ register int i;
+ Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY));
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = (Function *)NULL;
+ }
+
+ for (i = 'A'; i < ('Z' + 1); i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = rl_do_lowercase_version;
+ }
+
+ return (keymap);
+}
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+rl_copy_keymap (map)
+ Keymap map;
+{
+ register int i;
+ Keymap temp = rl_make_bare_keymap ();
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ temp[i].type = map[i].type;
+ temp[i].function = map[i].function;
+ }
+ return (temp);
+}
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the uppercase Meta characters bound to run their lowercase equivalents,
+ and the Meta digits bound to produce numeric arguments. */
+Keymap
+rl_make_keymap ()
+{
+ register int i;
+ Keymap newmap;
+
+ newmap = rl_make_bare_keymap ();
+
+ /* All ASCII printing characters are self-inserting. */
+ for (i = ' '; i < 126; i++)
+ newmap[i].function = rl_insert;
+
+ newmap[TAB].function = rl_insert;
+ newmap[RUBOUT].function = rl_rubout;
+ newmap[CTRL('H')].function = rl_rubout;
+
+#if KEYMAP_SIZE > 128
+ /* Printing characters in some 8-bit character sets. */
+ for (i = 128; i < 160; i++)
+ newmap[i].function = rl_insert;
+
+ /* ISO Latin-1 printing characters should self-insert. */
+ for (i = 160; i < 256; i++)
+ newmap[i].function = rl_insert;
+#endif /* KEYMAP_SIZE > 128 */
+
+ return (newmap);
+}
+
+/* Free the storage associated with MAP. */
+void
+rl_discard_keymap (map)
+ Keymap (map);
+{
+ int i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ switch (map[i].type)
+ {
+ case ISFUNC:
+ break;
+
+ case ISKMAP:
+ rl_discard_keymap ((Keymap)map[i].function);
+ break;
+
+ case ISMACR:
+ free ((char *)map[i].function);
+ break;
+ }
+ }
+}
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/gnu/lib/libreadline/memalloc.h b/gnu/lib/libreadline/memalloc.h
new file mode 100644
index 000000000000..750d53df9c7e
--- /dev/null
+++ b/gnu/lib/libreadline/memalloc.h
@@ -0,0 +1,56 @@
+/* memalloc.h -- consolidate code for including alloca.h or malloc.h and
+ defining alloca. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (__MEMALLOC_H__)
+# define __MEMALLOC_H__
+
+#if defined (sparc) && defined (sun) && !defined (HAVE_ALLOCA_H)
+# define HAVE_ALLOCA_H
+#endif
+
+#if defined (__GNUC__) && !defined (HAVE_ALLOCA)
+# define HAVE_ALLOCA
+#endif
+
+#if defined (HAVE_ALLOCA_H) && !defined (HAVE_ALLOCA)
+# define HAVE_ALLOCA
+#endif /* HAVE_ALLOCA_H && !HAVE_ALLOCA */
+
+#if !defined (BUILDING_MAKEFILE)
+
+#if defined (__GNUC__)
+# undef alloca
+# define alloca __builtin_alloca
+#else /* !__GNUC__ */
+# if defined (HAVE_ALLOCA_H)
+# if defined (IBMESA)
+# include <malloc.h>
+# else /* !IBMESA */
+# include <alloca.h>
+# endif /* !IBMESA */
+# else
+extern char *alloca ();
+# endif /* !HAVE_ALLOCA_H */
+#endif /* !__GNUC__ */
+
+#endif /* !BUILDING_MAKEFILE */
+
+#endif /* __MEMALLOC_H__ */
diff --git a/gnu/lib/libreadline/parens.c b/gnu/lib/libreadline/parens.c
new file mode 100644
index 000000000000..e1727d56968e
--- /dev/null
+++ b/gnu/lib/libreadline/parens.c
@@ -0,0 +1,118 @@
+/* parens.c -- Implemenation of matching parenthesis feature. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#if defined (FD_SET)
+#include <sys/time.h>
+#endif
+#include <readline/readline.h>
+
+extern int rl_explicit_arg;
+
+/* Non-zero means try to blink the matching open parenthesis when the
+ close parenthesis is inserted. */
+#if defined (FD_SET)
+int rl_blink_matching_paren = 1;
+#else /* !FD_SET */
+int rl_blink_matching_paren = 0;
+#endif /* !FD_SET */
+
+static int find_matching_open ();
+
+rl_insert_close (count, invoking_key)
+ int count, invoking_key;
+{
+ if (rl_explicit_arg || !rl_blink_matching_paren)
+ rl_insert (count, invoking_key);
+ else
+ {
+#if defined (FD_SET)
+ int orig_point, match_point, ready;
+ struct timeval timer;
+ fd_set readfds;
+
+ rl_insert (1, invoking_key);
+ rl_redisplay ();
+ match_point =
+ find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
+
+ /* Emacs might message or ring the bell here, but I don't. */
+ if (match_point < 0)
+ return -1;
+
+ FD_ZERO (&readfds);
+ FD_SET (fileno (rl_instream), &readfds);
+ timer.tv_sec = 1;
+ timer.tv_usec = 500;
+
+ orig_point = rl_point;
+ rl_point = match_point;
+ rl_redisplay ();
+ ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
+ rl_point = orig_point;
+#else /* !FD_SET */
+ rl_insert (count, invoking_key);
+#endif /* !FD_SET */
+ }
+ return 0;
+}
+
+static int
+find_matching_open (string, from, closer)
+ char *string;
+ int from, closer;
+{
+ register int i;
+ int opener, level, delimiter;
+
+ switch (closer)
+ {
+ case ']': opener = '['; break;
+ case '}': opener = '{'; break;
+ case ')': opener = '('; break;
+ default:
+ return (-1);
+ }
+
+ level = 1; /* The closer passed in counts as 1. */
+ delimiter = 0; /* Delimited state unknown. */
+
+ for (i = from; i > -1; i--)
+ {
+ if (delimiter && (string[i] == delimiter))
+ delimiter = 0;
+ else if ((string[i] == '\'') || (string[i] == '"'))
+ delimiter = rl_line_buffer[i];
+ else if (!delimiter && (string[i] == closer))
+ level++;
+ else if (!delimiter && (string[i] == opener))
+ level--;
+
+ if (!level)
+ break;
+ }
+ return (i);
+}
+
+
+
diff --git a/gnu/lib/libreadline/posixstat.h b/gnu/lib/libreadline/posixstat.h
new file mode 100644
index 000000000000..7d1cece35257
--- /dev/null
+++ b/gnu/lib/libreadline/posixstat.h
@@ -0,0 +1,149 @@
+/* posixstat.h -- Posix stat(2) definitions for systems that
+ don't have them. */
+
+/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can 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.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file should be included instead of <sys/stat.h>.
+ It relies on the local sys/stat.h to work though. */
+#if !defined (_POSIXSTAT_H)
+#define _POSIXSTAT_H
+
+#include <sys/stat.h>
+
+#if defined (isc386)
+# if !defined (S_IFDIR)
+# define S_IFDIR 0040000
+# endif /* !S_IFDIR */
+# if !defined (S_IFMT)
+# define S_IFMT 0170000
+# endif /* !S_IFMT */
+#endif /* isc386 */
+
+/* This text is taken directly from the Cadmus I was trying to
+ compile on:
+ the following MACROs are defined for X/OPEN compatibility
+ however, is the param correct ??
+ #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK)
+
+ Well, the answer is no. Thus... */
+#if defined (BrainDeath)
+# undef S_ISBLK
+# undef S_ISCHR
+# undef S_ISDIR
+# undef S_ISFIFO
+# undef S_ISREG
+#endif /* BrainDeath */
+
+/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */
+
+/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but
+ do not provide the S_IS* macros that Posix requires. */
+
+#if defined (_S_IFMT) && !defined (S_IFMT)
+#define S_IFMT _S_IFMT
+#endif
+#if defined (_S_IFIFO) && !defined (S_IFIFO)
+#define S_IFIFO _S_IFIFO
+#endif
+#if defined (_S_IFCHR) && !defined (S_IFCHR)
+#define S_IFCHR _S_IFCHR
+#endif
+#if defined (_S_IFDIR) && !defined (S_IFDIR)
+#define S_IFDIR _S_IFDIR
+#endif
+#if defined (_S_IFBLK) && !defined (S_IFBLK)
+#define S_IFBLK _S_IFBLK
+#endif
+#if defined (_S_IFREG) && !defined (S_IFREG)
+#define S_IFREG _S_IFREG
+#endif
+#if defined (_S_IFLNK) && !defined (S_IFLNK)
+#define S_IFLNK _S_IFLNK
+#endif
+#if defined (_S_IFSOCK) && !defined (S_IFSOCK)
+#define S_IFSOCK _S_IFSOCK
+#endif
+
+/* Test for each symbol individually and define the ones necessary (some
+ systems claiming Posix compatibility define some but not all). */
+
+#if defined (S_IFBLK) && !defined (S_ISBLK)
+#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */
+#endif
+
+#if defined (S_IFCHR) && !defined (S_ISCHR)
+#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */
+#endif
+
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */
+#endif
+
+#if defined (S_IFREG) && !defined (S_ISREG)
+#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */
+#endif
+
+#if defined (S_IFIFO) && !defined (S_ISFIFO)
+#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */
+#endif
+
+#if defined (S_IFLNK) && !defined (S_ISLNK)
+#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */
+#endif
+
+#if defined (S_IFSOCK) && !defined (S_ISSOCK)
+#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */
+#endif
+
+/*
+ * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes
+ */
+
+#if !defined (S_IRWXU)
+# if !defined (S_IREAD)
+# define S_IREAD 00400
+# define S_IWRITE 00200
+# define S_IEXEC 00100
+# endif /* S_IREAD */
+
+# if !defined (S_IRUSR)
+# define S_IRUSR S_IREAD /* read, owner */
+# define S_IWUSR S_IWRITE /* write, owner */
+# define S_IXUSR S_IEXEC /* execute, owner */
+
+# define S_IRGRP (S_IREAD >> 3) /* read, group */
+# define S_IWGRP (S_IWRITE >> 3) /* write, group */
+# define S_IXGRP (S_IEXEC >> 3) /* execute, group */
+
+# define S_IROTH (S_IREAD >> 6) /* read, other */
+# define S_IWOTH (S_IWRITE >> 6) /* write, other */
+# define S_IXOTH (S_IEXEC >> 6) /* execute, other */
+# endif /* !S_IRUSR */
+
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif /* !S_IRWXU */
+
+/* These are non-standard, but are used in builtins.c$symbolic_umask() */
+#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
+#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
+#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+
+#endif /* _POSIXSTAT_H */
diff --git a/gnu/lib/libreadline/readline.c b/gnu/lib/libreadline/readline.c
new file mode 100644
index 000000000000..ee624c1e7670
--- /dev/null
+++ b/gnu/lib/libreadline/readline.c
@@ -0,0 +1,3349 @@
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+# include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+#include <signal.h>
+
+/* This is needed to include support for TIOCGWINSZ and window resizing. */
+#if defined (OSF1) || defined (BSD386) || defined (NetBSD) || \
+ defined (FreeBSD) || defined (_386BSD) || defined (AIX)
+# include <sys/ioctl.h>
+#endif /* OSF1 || BSD386 */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include <setjmp.h>
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+/* NOTE: Functions and variables prefixed with `_rl_' are
+ pseudo-global: they are global so they can be shared
+ between files in the readline library, but are not intended
+ to be visible to readline callers. */
+
+/* Functions imported from other files in the library. */
+extern char *tgetstr ();
+extern void rl_prep_terminal (), rl_deprep_terminal ();
+
+extern void _rl_bind_if_unbound ();
+
+/* External redisplay functions and variables from display.c */
+extern void _rl_move_vert ();
+
+extern void _rl_erase_at_end_of_line ();
+extern void _rl_move_cursor_relative ();
+
+extern int _rl_vis_botlin;
+extern int _rl_last_c_pos;
+extern int rl_display_fixed;
+extern char *rl_display_prompt;
+
+/* Variables imported from complete.c. */
+extern char *rl_completer_word_break_characters;
+extern char *rl_basic_word_break_characters;
+extern int rl_completion_query_items;
+extern int rl_complete_with_tilde_expansion;
+
+#if defined (VI_MODE)
+extern void _rl_vi_set_last ();
+extern void _rl_vi_reset_last ();
+extern void _rl_vi_done_inserting ();
+#endif /* VI_MODE */
+
+/* Forward declarations used in this file. */
+void _rl_free_history_entry ();
+
+int _rl_dispatch ();
+void _rl_set_screen_size ();
+int _rl_output_character_function ();
+
+static char *readline_internal ();
+static void readline_initialize_everything ();
+static int init_terminal_io ();
+static void start_using_history ();
+
+#if !defined (__GO32__)
+static void readline_default_bindings ();
+#endif /* !__GO32__ */
+
+#if defined (__GO32__)
+# include <sys/pc.h>
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+
+/* **************************************************************** */
+/* */
+/* Line editing input utility */
+/* */
+/* **************************************************************** */
+
+static char *LibraryVersion = "2.0";
+
+/* A pointer to the keymap that is currently in use.
+ By default, it is the standard emacs keymap. */
+Keymap _rl_keymap = emacs_standard_keymap;
+
+/* The current style of editing. */
+int rl_editing_mode = emacs_mode;
+
+/* Non-zero if the previous command was a kill command. */
+static int last_command_was_kill = 0;
+
+/* The current value of the numeric argument specified by the user. */
+int rl_numeric_arg = 1;
+
+/* Non-zero if an argument was typed. */
+int rl_explicit_arg = 0;
+
+/* Temporary value used while generating the argument. */
+int rl_arg_sign = 1;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized = 0;
+
+/* If non-zero, this program is running in an EMACS buffer. */
+static char *running_in_emacs = (char *)NULL;
+
+/* The current offset in the current input line. */
+int rl_point;
+
+/* Mark in the current input line. */
+int rl_mark;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+
+/* The last function executed by readline. */
+Function *rl_last_func = (Function *)NULL;
+
+/* Top level environment for readline_internal (). */
+static jmp_buf readline_top_level;
+
+/* The streams we interact with. */
+static FILE *in_stream, *out_stream;
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = (FILE *)NULL;
+FILE *rl_outstream = (FILE *)NULL;
+
+/* Non-zero means echo characters as they are read. */
+int readline_echoing_p = 1;
+
+/* Current prompt. */
+char *rl_prompt;
+int rl_visible_prompt_length = 0;
+
+/* The number of characters read in order to type this complete command. */
+int rl_key_sequence_length = 0;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal () prints the first prompt. */
+Function *rl_startup_hook = (Function *)NULL;
+
+/* What we use internally. You should always refer to RL_LINE_BUFFER. */
+static char *the_line;
+
+/* The character that can generate an EOF. Really read from
+ the terminal driver... just defaulted here. */
+int _rl_eof_char = CTRL ('D');
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Pointer to a useful terminal name. */
+char *rl_terminal_name = (char *)NULL;
+
+/* Non-zero means to always use horizontal scrolling in line display. */
+int _rl_horizontal_scroll_mode = 0;
+
+/* Non-zero means to display an asterisk at the starts of history lines
+ which have been modified. */
+int _rl_mark_modified_lines = 0;
+
+/* The style of `bell' notification preferred. This can be set to NO_BELL,
+ AUDIBLE_BELL, or VISIBLE_BELL. */
+int _rl_bell_preference = AUDIBLE_BELL;
+
+/* Line buffer and maintenence. */
+char *rl_line_buffer = (char *)NULL;
+int rl_line_buffer_len = 0;
+#define DEFAULT_BUFFER_SIZE 256
+
+
+/* **************************************************************** */
+/* */
+/* `Forward' declarations */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means do not parse any lines other than comments and
+ parser directives. */
+unsigned char _rl_parsing_conditionalized_out = 0;
+
+/* Non-zero means to save keys that we dispatch on in a kbd macro. */
+static int defining_kbd_macro = 0;
+
+/* Non-zero means to convert characters with the meta bit set to
+ escape-prefixed characters so we can indirect through
+ emacs_meta_keymap or vi_escape_keymap. */
+int _rl_convert_meta_chars_to_ascii = 1;
+
+/* Non-zero means to output characters with the meta bit set directly
+ rather than as a meta-prefixed escape sequence. */
+int _rl_output_meta_chars = 0;
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+ the undo list. */
+static int doing_an_undo = 0;
+
+/* **************************************************************** */
+/* */
+/* Top Level Functions */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means treat 0200 bit in terminal input as Meta bit. */
+int _rl_meta_flag = 0; /* Forward declaration */
+
+/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means
+ none. A return value of NULL means that EOF was encountered. */
+char *
+readline (prompt)
+ char *prompt;
+{
+ char *value;
+
+ rl_prompt = prompt;
+
+ /* If we are at EOF return a NULL string. */
+ if (rl_pending_input == EOF)
+ {
+ rl_pending_input = 0;
+ return ((char *)NULL);
+ }
+
+ rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
+
+ rl_initialize ();
+ rl_prep_terminal (_rl_meta_flag);
+
+#if defined (HANDLE_SIGNALS)
+ rl_set_signals ();
+#endif
+
+ value = readline_internal ();
+ rl_deprep_terminal ();
+
+#if defined (HANDLE_SIGNALS)
+ rl_clear_signals ();
+#endif
+
+ return (value);
+}
+
+/* Read a line of input from the global rl_instream, doing output on
+ the global rl_outstream.
+ If rl_prompt is non-null, then that is our prompt. */
+static char *
+readline_internal ()
+{
+ int lastc, c, eof_found;
+
+ in_stream = rl_instream;
+ out_stream = rl_outstream;
+
+ lastc = -1;
+ eof_found = 0;
+
+ if (rl_startup_hook)
+ (*rl_startup_hook) ();
+
+ if (!readline_echoing_p)
+ {
+ if (rl_prompt)
+ {
+ fprintf (out_stream, "%s", rl_prompt);
+ fflush (out_stream);
+ }
+ }
+ else
+ {
+ rl_on_new_line ();
+ rl_redisplay ();
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_vi_insertion_mode ();
+#endif /* VI_MODE */
+ }
+
+ while (!rl_done)
+ {
+ int lk = last_command_was_kill;
+ int code;
+
+ code = setjmp (readline_top_level);
+
+ if (code)
+ rl_redisplay ();
+
+ if (!rl_pending_input)
+ {
+ /* Then initialize the argument and number of keys read. */
+ rl_init_argument ();
+ rl_key_sequence_length = 0;
+ }
+
+ c = rl_read_key ();
+
+ /* EOF typed to a non-blank line is a <NL>. */
+ if (c == EOF && rl_end)
+ c = NEWLINE;
+
+ /* The character _rl_eof_char typed to blank line, and not as the
+ previous character is interpreted as EOF. */
+ if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
+ {
+ eof_found = 1;
+ break;
+ }
+
+ lastc = c;
+ _rl_dispatch (c, _rl_keymap);
+
+ /* If there was no change in last_command_was_kill, then no kill
+ has taken place. Note that if input is pending we are reading
+ a prefix command, so nothing has changed yet. */
+ if (!rl_pending_input)
+ {
+ if (lk == last_command_was_kill)
+ last_command_was_kill = 0;
+ }
+
+#if defined (VI_MODE)
+ /* In vi mode, when you exit insert mode, the cursor moves back
+ over the previous character. We explicitly check for that here. */
+ if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
+ rl_vi_check ();
+#endif /* VI_MODE */
+
+ if (!rl_done)
+ rl_redisplay ();
+ }
+
+ /* Restore the original of this history line, iff the line that we
+ are editing was originally in the history, AND the line has changed. */
+ {
+ HIST_ENTRY *entry = current_history ();
+
+ if (entry && rl_undo_list)
+ {
+ char *temp = savestring (the_line);
+ rl_revert_line ();
+ entry = replace_history_entry (where_history (), the_line,
+ (HIST_ENTRY *)NULL);
+ _rl_free_history_entry (entry);
+
+ strcpy (the_line, temp);
+ free (temp);
+ }
+ }
+
+ /* At any rate, it is highly likely that this line has an undo list. Get
+ rid of it now. */
+ if (rl_undo_list)
+ free_undo_list ();
+
+ if (eof_found)
+ return (char *)NULL;
+ else
+ return (savestring (the_line));
+}
+
+/* **************************************************************** */
+/* */
+/* Character Input Buffering */
+/* */
+/* **************************************************************** */
+
+static int pop_index = 0, push_index = 0, ibuffer_len = 511;
+static unsigned char ibuffer[512];
+
+/* Non-null means it is a pointer to a function to run while waiting for
+ character input. */
+Function *rl_event_hook = (Function *)NULL;
+
+#define any_typein (push_index != pop_index)
+
+/* Add KEY to the buffer of characters to be read. */
+rl_stuff_char (key)
+ int key;
+{
+ if (key == EOF)
+ {
+ key = NEWLINE;
+ rl_pending_input = EOF;
+ }
+ ibuffer[push_index++] = key;
+ if (push_index >= ibuffer_len)
+ push_index = 0;
+ return push_index;
+}
+
+/* Return the amount of space available in the
+ buffer for stuffing characters. */
+int
+ibuffer_space ()
+{
+ if (pop_index > push_index)
+ return (pop_index - push_index);
+ else
+ return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+ Return the key in KEY.
+ Result is KEY if there was a key, or 0 if there wasn't. */
+int
+rl_get_char (key)
+ int *key;
+{
+ if (push_index == pop_index)
+ return (0);
+
+ *key = ibuffer[pop_index++];
+
+ if (pop_index >= ibuffer_len)
+ pop_index = 0;
+
+ return (1);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+ Returns non-zero if successful, zero if there is
+ no space left in the buffer. */
+int
+rl_unget_char (key)
+ int key;
+{
+ if (ibuffer_space ())
+ {
+ pop_index--;
+ if (pop_index < 0)
+ pop_index = ibuffer_len - 1;
+ ibuffer[pop_index] = key;
+ return (1);
+ }
+ return (0);
+}
+
+/* If a character is available to be read, then read it
+ and stuff it into IBUFFER. Otherwise, just return. */
+void
+rl_gather_tyi ()
+{
+#if defined (__GO32__)
+ char input;
+
+ if (isatty (0))
+ {
+ int i = rl_getc ();
+
+ if (i != EOF)
+ rl_stuff_char (i);
+ }
+ else if (kbhit () && ibuffer_space ())
+ rl_stuff_char (getkey ());
+#else /* !__GO32__ */
+
+ int tty = fileno (in_stream);
+ register int tem, result = -1;
+ int chars_avail;
+ char input;
+
+#if defined (FIONREAD)
+ result = ioctl (tty, FIONREAD, &chars_avail);
+#endif
+
+#if defined (O_NDELAY)
+ if (result == -1)
+ {
+ int flags;
+
+ flags = fcntl (tty, F_GETFL, 0);
+
+ fcntl (tty, F_SETFL, (flags | O_NDELAY));
+ chars_avail = read (tty, &input, 1);
+
+ fcntl (tty, F_SETFL, flags);
+ if (chars_avail == -1 && errno == EAGAIN)
+ return;
+ }
+#endif /* O_NDELAY */
+
+ /* If there's nothing available, don't waste time trying to read
+ something. */
+ if (chars_avail == 0)
+ return;
+
+ tem = ibuffer_space ();
+
+ if (chars_avail > tem)
+ chars_avail = tem;
+
+ /* One cannot read all of the available input. I can only read a single
+ character at a time, or else programs which require input can be
+ thwarted. If the buffer is larger than one character, I lose.
+ Damn! */
+ if (tem < ibuffer_len)
+ chars_avail = 0;
+
+ if (result != -1)
+ {
+ while (chars_avail--)
+ rl_stuff_char (rl_getc (in_stream));
+ }
+ else
+ {
+ if (chars_avail)
+ rl_stuff_char (input);
+ }
+#endif /* !__GO32__ */
+}
+
+static int next_macro_key ();
+/* Read a key, including pending input. */
+int
+rl_read_key ()
+{
+ int c;
+
+ rl_key_sequence_length++;
+
+ if (rl_pending_input)
+ {
+ c = rl_pending_input;
+ rl_pending_input = 0;
+ }
+ else
+ {
+ /* If input is coming from a macro, then use that. */
+ if (c = next_macro_key ())
+ return (c);
+
+ /* If the user has an event function, then call it periodically. */
+ if (rl_event_hook)
+ {
+ while (rl_event_hook && !rl_get_char (&c))
+ {
+ (*rl_event_hook) ();
+ rl_gather_tyi ();
+ }
+ }
+ else
+ {
+ if (!rl_get_char (&c))
+ c = rl_getc (in_stream);
+ }
+ }
+
+ return (c);
+}
+
+/* Found later in this file. */
+static void add_macro_char (), with_macro_input ();
+
+/* Do the command associated with KEY in MAP.
+ If the associated command is really a keymap, then read
+ another key, and dispatch into that map. */
+int
+_rl_dispatch (key, map)
+ register int key;
+ Keymap map;
+{
+ int r = 0;
+
+ if (defining_kbd_macro)
+ add_macro_char (key);
+
+ if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (map[ESC].type == ISKMAP)
+ {
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ key = UNMETA (key);
+ rl_key_sequence_length += 2;
+ return (_rl_dispatch (key, map));
+ }
+ else
+ ding ();
+ return 0;
+ }
+
+ switch (map[key].type)
+ {
+ case ISFUNC:
+ {
+ Function *func = map[key].function;
+
+ if (func != (Function *)NULL)
+ {
+ /* Special case rl_do_lowercase_version (). */
+ if (func == rl_do_lowercase_version)
+ return (_rl_dispatch (to_lower (key), map));
+
+ r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key);
+
+ /* If we have input pending, then the last command was a prefix
+ command. Don't change the state of rl_last_func. Otherwise,
+ remember the last command executed in this variable. */
+ if (!rl_pending_input)
+ rl_last_func = map[key].function;
+ }
+ else
+ {
+ rl_abort ();
+ return -1;
+ }
+ }
+ break;
+
+ case ISKMAP:
+ if (map[key].function != (Function *)NULL)
+ {
+ int newkey;
+
+ rl_key_sequence_length++;
+ newkey = rl_read_key ();
+ r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key));
+ }
+ else
+ {
+ rl_abort ();
+ return -1;
+ }
+ break;
+
+ case ISMACR:
+ if (map[key].function != (Function *)NULL)
+ {
+ char *macro;
+
+ macro = savestring ((char *)map[key].function);
+ with_macro_input (macro);
+ return 0;
+ }
+ break;
+ }
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
+ rl_vi_textmod_command (key))
+ _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
+#endif
+ return (r);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Hacking Keyboard Macros */
+/* */
+/* **************************************************************** */
+
+/* The currently executing macro string. If this is non-zero,
+ then it is a malloc ()'ed string where input is coming from. */
+static char *executing_macro = (char *)NULL;
+
+/* The offset in the above string to the next character to be read. */
+static int executing_macro_index = 0;
+
+/* The current macro string being built. Characters get stuffed
+ in here by add_macro_char (). */
+static char *current_macro = (char *)NULL;
+
+/* The size of the buffer allocated to current_macro. */
+static int current_macro_size = 0;
+
+/* The index at which characters are being added to current_macro. */
+static int current_macro_index = 0;
+
+/* A structure used to save nested macro strings.
+ It is a linked list of string/index for each saved macro. */
+struct saved_macro {
+ struct saved_macro *next;
+ char *string;
+ int sindex;
+};
+
+/* The list of saved macros. */
+struct saved_macro *macro_list = (struct saved_macro *)NULL;
+
+/* Forward declarations of static functions. Thank you C. */
+static void push_executing_macro (), pop_executing_macro ();
+
+/* This one has to be declared earlier in the file. */
+/* static void add_macro_char (); */
+
+/* Set up to read subsequent input from STRING.
+ STRING is free ()'ed when we are done with it. */
+static void
+with_macro_input (string)
+ char *string;
+{
+ push_executing_macro ();
+ executing_macro = string;
+ executing_macro_index = 0;
+}
+
+/* Return the next character available from a macro, or 0 if
+ there are no macro characters. */
+static int
+next_macro_key ()
+{
+ if (!executing_macro)
+ return (0);
+
+ if (!executing_macro[executing_macro_index])
+ {
+ pop_executing_macro ();
+ return (next_macro_key ());
+ }
+
+ return (executing_macro[executing_macro_index++]);
+}
+
+/* Save the currently executing macro on a stack of saved macros. */
+static void
+push_executing_macro ()
+{
+ struct saved_macro *saver;
+
+ saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
+ saver->next = macro_list;
+ saver->sindex = executing_macro_index;
+ saver->string = executing_macro;
+
+ macro_list = saver;
+}
+
+/* Discard the current macro, replacing it with the one
+ on the top of the stack of saved macros. */
+static void
+pop_executing_macro ()
+{
+ if (executing_macro)
+ free (executing_macro);
+
+ executing_macro = (char *)NULL;
+ executing_macro_index = 0;
+
+ if (macro_list)
+ {
+ struct saved_macro *disposer = macro_list;
+ executing_macro = macro_list->string;
+ executing_macro_index = macro_list->sindex;
+ macro_list = macro_list->next;
+ free (disposer);
+ }
+}
+
+/* Add a character to the macro being built. */
+static void
+add_macro_char (c)
+ int c;
+{
+ if (current_macro_index + 1 >= current_macro_size)
+ {
+ if (!current_macro)
+ current_macro = (char *)xmalloc (current_macro_size = 25);
+ else
+ current_macro =
+ (char *)xrealloc (current_macro, current_macro_size += 25);
+ }
+
+ current_macro[current_macro_index++] = c;
+ current_macro[current_macro_index] = '\0';
+}
+
+/* Begin defining a keyboard macro.
+ Keystrokes are recorded as they are executed.
+ End the definition with rl_end_kbd_macro ().
+ If a numeric argument was explicitly typed, then append this
+ definition to the end of the existing macro, and start by
+ re-executing the existing macro. */
+rl_start_kbd_macro (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ if (defining_kbd_macro)
+ {
+ rl_abort ();
+ return -1;
+ }
+
+ if (rl_explicit_arg)
+ {
+ if (current_macro)
+ with_macro_input (savestring (current_macro));
+ }
+ else
+ current_macro_index = 0;
+
+ defining_kbd_macro = 1;
+ return 0;
+}
+
+/* Stop defining a keyboard macro.
+ A numeric argument says to execute the macro right now,
+ that many times, counting the definition as the first time. */
+rl_end_kbd_macro (count, ignore)
+ int count, ignore;
+{
+ if (!defining_kbd_macro)
+ {
+ rl_abort ();
+ return -1;
+ }
+
+ current_macro_index -= (rl_key_sequence_length - 1);
+ current_macro[current_macro_index] = '\0';
+
+ defining_kbd_macro = 0;
+
+ return (rl_call_last_kbd_macro (--count, 0));
+}
+
+/* Execute the most recently defined keyboard macro.
+ COUNT says how many times to execute it. */
+rl_call_last_kbd_macro (count, ignore)
+ int count, ignore;
+{
+ if (!current_macro)
+ rl_abort ();
+
+ if (defining_kbd_macro)
+ {
+ ding (); /* no recursive macros */
+ current_macro[--current_macro_index] = '\0'; /* erase this char */
+ return 0;
+ }
+
+ while (count--)
+ with_macro_input (savestring (current_macro));
+ return 0;
+}
+
+void
+_rl_kill_kbd_macro ()
+{
+ if (current_macro)
+ {
+ free (current_macro);
+ current_macro = (char *) NULL;
+ }
+ current_macro_size = current_macro_index = 0;
+
+ if (executing_macro)
+ {
+ free (executing_macro);
+ executing_macro = (char *) NULL;
+ }
+ executing_macro_index = 0;
+
+ defining_kbd_macro = 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Initializations */
+/* */
+/* **************************************************************** */
+
+/* Initliaze readline (and terminal if not already). */
+rl_initialize ()
+{
+ /* If we have never been called before, initialize the
+ terminal and data structures. */
+ if (!rl_initialized)
+ {
+ readline_initialize_everything ();
+ rl_initialized++;
+ }
+
+ /* Initalize the current line information. */
+ rl_point = rl_end = 0;
+ the_line = rl_line_buffer;
+ the_line[0] = 0;
+
+ /* We aren't done yet. We haven't even gotten started yet! */
+ rl_done = 0;
+
+ /* Tell the history routines what is going on. */
+ start_using_history ();
+
+ /* Make the display buffer match the state of the line. */
+ rl_reset_line_state ();
+
+ /* No such function typed yet. */
+ rl_last_func = (Function *)NULL;
+
+ /* Parsing of key-bindings begins in an enabled state. */
+ _rl_parsing_conditionalized_out = 0;
+
+ return 0;
+}
+
+/* Initialize the entire state of the world. */
+static void
+readline_initialize_everything ()
+{
+ /* Find out if we are running in Emacs. */
+ running_in_emacs = getenv ("EMACS");
+
+ /* Set up input and output if they are not already set up. */
+ if (!rl_instream)
+ rl_instream = stdin;
+
+ if (!rl_outstream)
+ rl_outstream = stdout;
+
+ /* Bind in_stream and out_stream immediately. These values may change,
+ but they may also be used before readline_internal () is called. */
+ in_stream = rl_instream;
+ out_stream = rl_outstream;
+
+ /* Allocate data structures. */
+ if (!rl_line_buffer)
+ rl_line_buffer =
+ (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
+
+ /* Initialize the terminal interface. */
+ init_terminal_io ((char *)NULL);
+
+#if !defined (__GO32__)
+ /* Bind tty characters to readline functions. */
+ readline_default_bindings ();
+#endif /* !__GO32__ */
+
+ /* Initialize the function names. */
+ rl_initialize_funmap ();
+
+ /* Read in the init file. */
+ rl_read_init_file ((char *)NULL);
+
+ /* Override the effect of any `set keymap' assignments in the
+ inputrc file. */
+ rl_set_keymap_from_edit_mode ();
+
+ /* If the completion parser's default word break characters haven't
+ been set yet, then do so now. */
+ if (rl_completer_word_break_characters == (char *)NULL)
+ rl_completer_word_break_characters = rl_basic_word_break_characters;
+}
+
+/* If this system allows us to look at the values of the regular
+ input editing characters, then bind them to their readline
+ equivalents, iff the characters are not bound to keymaps. */
+static void
+readline_default_bindings ()
+{
+ rltty_set_default_bindings (_rl_keymap);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Numeric Arguments */
+/* */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+static int
+rl_digit_loop ()
+{
+ int key, c;
+
+ while (1)
+ {
+ rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
+ key = c = rl_read_key ();
+
+ if (_rl_keymap[c].type == ISFUNC &&
+ _rl_keymap[c].function == rl_universal_argument)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+ c = UNMETA (c);
+ if (numeric (c))
+ {
+ if (rl_explicit_arg)
+ rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
+ else
+ rl_numeric_arg = (c - '0');
+ rl_explicit_arg = 1;
+ }
+ else
+ {
+ if (c == '-' && !rl_explicit_arg)
+ {
+ rl_numeric_arg = 1;
+ rl_arg_sign = -1;
+ }
+ else
+ {
+ rl_clear_message ();
+ return (_rl_dispatch (key, _rl_keymap));
+ }
+ }
+ }
+ return 0;
+}
+
+/* Add the current digit to the argument in progress. */
+rl_digit_argument (ignore, key)
+ int ignore, key;
+{
+ rl_pending_input = key;
+ return (rl_digit_loop ());
+}
+
+/* What to do when you abort reading an argument. */
+rl_discard_argument ()
+{
+ ding ();
+ rl_clear_message ();
+ rl_init_argument ();
+ return 0;
+}
+
+/* Create a default argument. */
+rl_init_argument ()
+{
+ rl_numeric_arg = rl_arg_sign = 1;
+ rl_explicit_arg = 0;
+ return 0;
+}
+
+/* C-u, universal argument. Multiply the current argument by 4.
+ Read a key. If the key has nothing to do with arguments, then
+ dispatch on it. If the key is the abort character then abort. */
+rl_universal_argument ()
+{
+ rl_numeric_arg *= 4;
+ return (rl_digit_loop ());
+}
+
+/* **************************************************************** */
+/* */
+/* Terminal and Termcap */
+/* */
+/* **************************************************************** */
+
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
+
+static int tcap_initialized = 0;
+
+/* Non-zero means this terminal can't really do anything. */
+int dumb_term = 0;
+/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
+ Unfortunately, PC is a global variable used by the termcap library. */
+#undef PC
+
+#if !defined (__linux__)
+char PC;
+char *BC, *UP;
+#endif /* __linux__ */
+
+/* Some strings to control terminal actions. These are output by tputs (). */
+char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
+char *term_pc;
+
+int screenwidth, screenheight, screenchars;
+
+/* Non-zero if we determine that the terminal can do character insertion. */
+int terminal_can_insert = 0;
+
+/* How to insert characters. */
+char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
+
+/* How to delete characters. */
+char *term_dc, *term_DC;
+
+#if defined (HACK_TERMCAP_MOTION)
+char *term_forward_char;
+#endif /* HACK_TERMCAP_MOTION */
+
+/* How to go up a line. */
+char *term_up;
+
+/* A visible bell, if the terminal can be made to flash the screen. */
+char *visible_bell;
+
+/* Non-zero means that this terminal has a meta key. */
+int term_has_meta;
+
+/* The string to write to turn on the meta key, if this term has one. */
+char *term_mm;
+
+/* The string to write to turn off the meta key, if this term has one. */
+char *term_mo;
+
+/* The key sequences output by the arrow keys, if this terminal has any. */
+char *term_ku, *term_kd, *term_kr, *term_kl;
+
+/* How to initialize and reset the arrow keys, if this terminal has any. */
+char *term_ks, *term_ke;
+
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+ has changed. */
+rl_reset_terminal (terminal_name)
+ char *terminal_name;
+{
+ init_terminal_io (terminal_name);
+ return 0;
+}
+
+/* Set readline's idea of the screen size. TTY is a file descriptor open
+ to the terminal. If IGNORE_ENV is true, we do not pay attention to the
+ values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
+ non-null serve to check whether or not we have initialized termcap. */
+void
+_rl_set_screen_size (tty, ignore_env)
+ int tty, ignore_env;
+{
+#if defined (TIOCGWINSZ)
+ struct winsize window_size;
+#endif /* TIOCGWINSZ */
+
+#if defined (TIOCGWINSZ)
+ if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
+ {
+ screenwidth = (int) window_size.ws_col;
+ screenheight = (int) window_size.ws_row;
+ }
+#endif /* TIOCGWINSZ */
+
+ /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
+ is unset. */
+ if (screenwidth <= 0)
+ {
+ char *sw;
+
+ if (!ignore_env && (sw = getenv ("COLUMNS")))
+ screenwidth = atoi (sw);
+
+ if (screenwidth <= 0 && term_string_buffer)
+ screenwidth = tgetnum ("co");
+ }
+
+ /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
+ is unset. */
+ if (screenheight <= 0)
+ {
+ char *sh;
+
+ if (!ignore_env && (sh = getenv ("LINES")))
+ screenheight = atoi (sh);
+
+ if (screenheight <= 0 && term_string_buffer)
+ screenheight = tgetnum ("li");
+ }
+
+ /* If all else fails, default to 80x24 terminal. */
+ if (screenwidth <= 1)
+ screenwidth = 80;
+
+ if (screenheight <= 0)
+ screenheight = 24;
+
+#if defined (SHELL)
+ /* If we're being compiled as part of bash, set the environment
+ variables $LINES and $COLUMNS to new values. */
+ set_lines_and_columns (screenheight, screenwidth);
+#endif
+
+ screenwidth--;
+
+ screenchars = screenwidth * screenheight;
+}
+
+struct _tc_string {
+ char *tc_var;
+ char **tc_value;
+};
+
+/* This should be kept sorted, just in case we decide to change the
+ search algorithm to something smarter. */
+static struct _tc_string tc_strings[] =
+{
+ "DC", &term_DC,
+ "IC", &term_IC,
+ "ce", &term_clreol,
+ "cl", &term_clrpag,
+ "cr", &term_cr,
+ "dc", &term_dc,
+ "ei", &term_ei,
+ "ic", &term_ic,
+ "im", &term_im,
+ "kd", &term_kd,
+ "kl", &term_kl,
+ "kr", &term_kr,
+ "ku", &term_ku,
+ "ks", &term_ks,
+ "ke", &term_ke,
+ "le", &term_backspace,
+ "mm", &term_mm,
+ "mo", &term_mo,
+#if defined (HACK_TERMCAP_MOTION)
+ "nd", &term_forward_char,
+#endif
+ "pc", &term_pc,
+ "up", &term_up,
+ "vb", &visible_bell,
+};
+
+#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
+
+/* Read the desired terminal capability strings into BP. The capabilities
+ are described in the TC_STRINGS table. */
+static void
+get_term_capabilities (bp)
+ char **bp;
+{
+ register int i;
+
+ for (i = 0; i < NUM_TC_STRINGS; i++)
+ *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
+ tcap_initialized = 1;
+}
+
+static int
+init_terminal_io (terminal_name)
+ char *terminal_name;
+{
+#if defined (__GO32__)
+ screenwidth = ScreenCols ();
+ screenheight = ScreenRows ();
+ screenchars = screenwidth * screenheight;
+ term_cr = "\r";
+ term_im = term_ei = term_ic = term_IC = (char *)NULL;
+ term_up = term_dc = term_DC = visible_bell = (char *)NULL;
+
+ /* Does the __GO32__ have a meta key? I don't know. */
+ term_has_meta = 0;
+ term_mm = term_mo = (char *)NULL;
+
+ /* It probably has arrow keys, but I don't know what they are. */
+ term_ku = term_kd = term_kr = term_kl = (char *)NULL;
+
+#if defined (HACK_TERMCAP_MOTION)
+ term_forward_char = (char *)NULL;
+#endif /* HACK_TERMCAP_MOTION */
+ terminal_can_insert = 0;
+ return;
+#else /* !__GO32__ */
+
+ char *term, *buffer;
+ int tty;
+
+ term = terminal_name ? terminal_name : getenv ("TERM");
+
+ if (!term_string_buffer)
+ term_string_buffer = (char *)xmalloc (2048);
+
+ if (!term_buffer)
+ term_buffer = (char *)xmalloc (2048);
+
+ buffer = term_string_buffer;
+
+ term_clrpag = term_cr = term_clreol = (char *)NULL;
+
+ if (!term)
+ term = "dumb";
+
+ if (tgetent (term_buffer, term) <= 0)
+ {
+ dumb_term = 1;
+ screenwidth = 79;
+ screenheight = 24;
+ screenchars = 79 * 24;
+ term_cr = "\r";
+ term_im = term_ei = term_ic = term_IC = (char *)NULL;
+ term_up = term_dc = term_DC = visible_bell = (char *)NULL;
+ term_ku = term_kd = term_kl = term_kr = (char *)NULL;
+#if defined (HACK_TERMCAP_MOTION)
+ term_forward_char = (char *)NULL;
+#endif
+ terminal_can_insert = 0;
+ return 0;
+ }
+
+ get_term_capabilities (&buffer);
+
+ /* Set up the variables that the termcap library expects the application
+ to provide. */
+ PC = term_pc ? *term_pc : 0;
+ BC = term_backspace;
+ UP = term_up;
+
+ if (!term_cr)
+ term_cr = "\r";
+
+ if (rl_instream)
+ tty = fileno (rl_instream);
+ else
+ tty = 0;
+
+ screenwidth = screenheight = 0;
+
+ _rl_set_screen_size (tty, 0);
+
+ /* "An application program can assume that the terminal can do
+ character insertion if *any one of* the capabilities `IC',
+ `im', `ic' or `ip' is provided." But we can't do anything if
+ only `ip' is provided, so... */
+ terminal_can_insert = (term_IC || term_im || term_ic);
+
+ /* Check to see if this terminal has a meta key and clear the capability
+ variables if there is none. */
+ term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
+ if (!term_has_meta)
+ {
+ term_mm = (char *)NULL;
+ term_mo = (char *)NULL;
+ }
+
+ /* Attempt to find and bind the arrow keys. Do not override already
+ bound keys in an overzealous attempt, however. */
+ _rl_bind_if_unbound (term_ku, rl_get_previous_history);
+ _rl_bind_if_unbound (term_kd, rl_get_next_history);
+ _rl_bind_if_unbound (term_kr, rl_forward);
+ _rl_bind_if_unbound (term_kl, rl_backward);
+
+#endif /* !__GO32__ */
+ return 0;
+}
+
+char *
+rl_get_termcap (cap)
+ char *cap;
+{
+ register int i;
+
+ if (tcap_initialized == 0)
+ return ((char *)NULL);
+ for (i = 0; i < NUM_TC_STRINGS; i++)
+ {
+ if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
+ return *(tc_strings[i].tc_value);
+ }
+ return ((char *)NULL);
+}
+
+/* A function for the use of tputs () */
+int
+_rl_output_character_function (c)
+ int c;
+{
+ return putc (c, out_stream);
+}
+
+/* Write COUNT characters from STRING to the output stream. */
+void
+_rl_output_some_chars (string, count)
+ char *string;
+ int count;
+{
+ fwrite (string, 1, count, out_stream);
+}
+
+/* Move the cursor back. */
+backspace (count)
+ int count;
+{
+ register int i;
+
+#if !defined (__GO32__)
+ if (term_backspace)
+ for (i = 0; i < count; i++)
+ tputs (term_backspace, 1, _rl_output_character_function);
+ else
+#endif /* !__GO32__ */
+ for (i = 0; i < count; i++)
+ putc ('\b', out_stream);
+ return 0;
+}
+
+/* Move to the start of the next line. */
+crlf ()
+{
+#if defined (NEW_TTY_DRIVER)
+ tputs (term_cr, 1, _rl_output_character_function);
+#endif /* NEW_TTY_DRIVER */
+ putc ('\n', out_stream);
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Utility Functions */
+/* */
+/* **************************************************************** */
+
+/* Return 0 if C is not a member of the class of characters that belong
+ in words, or 1 if it is. */
+
+int allow_pathname_alphabetic_chars = 0;
+char *pathname_alphabetic_chars = "/-_=~.#$";
+
+int
+alphabetic (c)
+ int c;
+{
+ if (pure_alphabetic (c) || (numeric (c)))
+ return (1);
+
+ if (allow_pathname_alphabetic_chars)
+ return (strchr (pathname_alphabetic_chars, c) != NULL);
+ else
+ return (0);
+}
+
+/* Return non-zero if C is a numeric character. */
+int
+numeric (c)
+ int c;
+{
+ return (c >= '0' && c <= '9');
+}
+
+/* Ring the terminal bell. */
+int
+ding ()
+{
+ if (readline_echoing_p)
+ {
+#if !defined (__GO32__)
+ switch (_rl_bell_preference)
+ {
+ case NO_BELL:
+ default:
+ break;
+ case VISIBLE_BELL:
+ if (visible_bell)
+ {
+ tputs (visible_bell, 1, _rl_output_character_function);
+ break;
+ }
+ /* FALLTHROUGH */
+ case AUDIBLE_BELL:
+ fprintf (stderr, "\007");
+ fflush (stderr);
+ break;
+ }
+#else /* __GO32__ */
+ fprintf (stderr, "\007");
+ fflush (stderr);
+#endif /* __GO32__ */
+ return (0);
+ }
+ return (-1);
+}
+
+/* How to abort things. */
+rl_abort ()
+{
+ ding ();
+ rl_clear_message ();
+ rl_init_argument ();
+ rl_pending_input = 0;
+
+ defining_kbd_macro = 0;
+ while (executing_macro)
+ pop_executing_macro ();
+
+ rl_last_func = (Function *)NULL;
+ longjmp (readline_top_level, 1);
+}
+
+/* Return a copy of the string between FROM and TO.
+ FROM is inclusive, TO is not. */
+char *
+rl_copy_text (from, to)
+ int from, to;
+{
+ register int length;
+ char *copy;
+
+ /* Fix it if the caller is confused. */
+ if (from > to)
+ {
+ int t = from;
+ from = to;
+ to = t;
+ }
+
+ length = to - from;
+ copy = (char *)xmalloc (1 + length);
+ strncpy (copy, the_line + from, length);
+ copy[length] = '\0';
+ return (copy);
+}
+
+/* Increase the size of RL_LINE_BUFFER until it has enough space to hold
+ LEN characters. */
+void
+rl_extend_line_buffer (len)
+ int len;
+{
+ while (len >= rl_line_buffer_len)
+ rl_line_buffer =
+ (char *)xrealloc
+ (rl_line_buffer, rl_line_buffer_len += DEFAULT_BUFFER_SIZE);
+
+ the_line = rl_line_buffer;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Insert and Delete */
+/* */
+/* **************************************************************** */
+
+/* Insert a string of text into the line at point. This is the only
+ way that you should do insertion. rl_insert () calls this
+ function. */
+rl_insert_text (string)
+ char *string;
+{
+ register int i, l = strlen (string);
+
+ if (rl_end + l >= rl_line_buffer_len)
+ rl_extend_line_buffer (rl_end + l);
+
+ for (i = rl_end; i >= rl_point; i--)
+ the_line[i + l] = the_line[i];
+ strncpy (the_line + rl_point, string, l);
+
+ /* Remember how to undo this if we aren't undoing something. */
+ if (!doing_an_undo)
+ {
+ /* If possible and desirable, concatenate the undos. */
+ if ((l == 1) &&
+ rl_undo_list &&
+ (rl_undo_list->what == UNDO_INSERT) &&
+ (rl_undo_list->end == rl_point) &&
+ (rl_undo_list->end - rl_undo_list->start < 20))
+ rl_undo_list->end++;
+ else
+ rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
+ }
+ rl_point += l;
+ rl_end += l;
+ the_line[rl_end] = '\0';
+ return l;
+}
+
+/* Delete the string between FROM and TO. FROM is
+ inclusive, TO is not. */
+rl_delete_text (from, to)
+ int from, to;
+{
+ register char *text;
+ register int diff, i;
+
+ /* Fix it if the caller is confused. */
+ if (from > to)
+ {
+ int t = from;
+ from = to;
+ to = t;
+ }
+ text = rl_copy_text (from, to);
+
+ /* Some versions of strncpy() can't handle overlapping arguments. */
+ diff = to - from;
+ for (i = from; i < rl_end - diff; i++)
+ the_line[i] = the_line[i + diff];
+
+ /* Remember how to undo this delete. */
+ if (!doing_an_undo)
+ rl_add_undo (UNDO_DELETE, from, to, text);
+ else
+ free (text);
+
+ rl_end -= diff;
+ the_line[rl_end] = '\0';
+ return (diff);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Readline character functions */
+/* */
+/* **************************************************************** */
+
+/* This is not a gap editor, just a stupid line input routine. No hair
+ is involved in writing any of the functions, and none should be. */
+
+/* Note that:
+
+ rl_end is the place in the string that we would place '\0';
+ i.e., it is always safe to place '\0' there.
+
+ rl_point is the place in the string where the cursor is. Sometimes
+ this is the same as rl_end.
+
+ Any command that is called interactively receives two arguments.
+ The first is a count: the numeric arg pased to this command.
+ The second is the key which invoked this command.
+*/
+
+
+/* **************************************************************** */
+/* */
+/* Movement Commands */
+/* */
+/* **************************************************************** */
+
+/* Note that if you `optimize' the display for these functions, you cannot
+ use said functions in other functions which do not do optimizing display.
+ I.e., you will have to update the data base for rl_redisplay, and you
+ might as well let rl_redisplay do that job. */
+
+/* Move forward COUNT characters. */
+rl_forward (count)
+ int count;
+{
+ if (count < 0)
+ rl_backward (-count);
+ else if (count > 0)
+ {
+ int end = rl_point + count;
+#if defined (VI_MODE)
+ int lend = rl_end - (rl_editing_mode == vi_mode);
+#else
+ int lend = rl_end;
+#endif
+
+ if (end > lend)
+ {
+ rl_point = lend;
+ ding ();
+ }
+ else
+ rl_point = end;
+ }
+ return 0;
+}
+
+/* Move backward COUNT characters. */
+rl_backward (count)
+ int count;
+{
+ if (count < 0)
+ rl_forward (-count);
+ else if (count > 0)
+ {
+ if (rl_point < count)
+ {
+ rl_point = 0;
+ ding ();
+ }
+ else
+ rl_point -= count;
+ }
+ return 0;
+}
+
+/* Move to the beginning of the line. */
+rl_beg_of_line ()
+{
+ rl_point = 0;
+ return 0;
+}
+
+/* Move to the end of the line. */
+rl_end_of_line ()
+{
+ rl_point = rl_end;
+ return 0;
+}
+
+/* Move forward a word. We do what Emacs does. */
+rl_forward_word (count)
+ int count;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_backward_word (-count);
+ return 0;
+ }
+
+ while (count)
+ {
+ if (rl_point == rl_end)
+ return 0;
+
+ /* If we are not in a word, move forward until we are in one.
+ Then, move forward until we hit a non-alphabetic character. */
+ c = the_line[rl_point];
+ if (!alphabetic (c))
+ {
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (alphabetic (c))
+ break;
+ }
+ }
+ if (rl_point == rl_end)
+ return 0;
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (!alphabetic (c))
+ break;
+ }
+ --count;
+ }
+ return 0;
+}
+
+/* Move backward a word. We do what Emacs does. */
+rl_backward_word (count)
+ int count;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_forward_word (-count);
+ return 0;
+ }
+
+ while (count)
+ {
+ if (!rl_point)
+ return 0;
+
+ /* Like rl_forward_word (), except that we look at the characters
+ just before point. */
+
+ c = the_line[rl_point - 1];
+ if (!alphabetic (c))
+ {
+ while (--rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ while (rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (!alphabetic (c))
+ break;
+ else
+ --rl_point;
+ }
+ --count;
+ }
+ return 0;
+}
+
+/* Clear the current line. Numeric argument to C-l does this. */
+rl_refresh_line ()
+{
+ int curr_line, nleft;
+
+ /* Find out whether or not there might be invisible characters in the
+ editing buffer. */
+ if (rl_display_prompt == rl_prompt)
+ nleft = _rl_last_c_pos - screenwidth - rl_visible_prompt_length;
+ else
+ nleft = _rl_last_c_pos - screenwidth;
+
+ if (nleft > 0)
+ curr_line = 1 + nleft / screenwidth;
+ else
+ curr_line = 0;
+
+ _rl_move_vert (curr_line);
+ _rl_move_cursor_relative (0, the_line); /* XXX is this right */
+
+#if defined (__GO32__)
+ {
+ int row, col, width, row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+ memset (row_start + col, 0, (width - col) * 2);
+ }
+#else /* !__GO32__ */
+ if (term_clreol)
+ tputs (term_clreol, 1, _rl_output_character_function);
+#endif /* !__GO32__ */
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return 0;
+}
+
+/* C-l typed to a line without quoting clears the screen, and then reprints
+ the prompt and the current input line. Given a numeric arg, redraw only
+ the current line. */
+rl_clear_screen ()
+{
+ if (rl_explicit_arg)
+ {
+ rl_refresh_line ();
+ return 0;
+ }
+
+#if !defined (__GO32__)
+ if (term_clrpag)
+ tputs (term_clrpag, 1, _rl_output_character_function);
+ else
+#endif /* !__GO32__ */
+ crlf ();
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return 0;
+}
+
+rl_arrow_keys (count, c)
+ int count, c;
+{
+ int ch;
+
+ ch = rl_read_key ();
+
+ switch (to_upper (ch))
+ {
+ case 'A':
+ rl_get_previous_history (count);
+ break;
+
+ case 'B':
+ rl_get_next_history (count);
+ break;
+
+ case 'C':
+ rl_forward (count);
+ break;
+
+ case 'D':
+ rl_backward (count);
+ break;
+
+ default:
+ ding ();
+ }
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Text commands */
+/* */
+/* **************************************************************** */
+
+/* Insert the character C at the current location, moving point forward. */
+rl_insert (count, c)
+ int count, c;
+{
+ register int i;
+ char *string;
+
+ if (count <= 0)
+ return 0;
+
+ /* If we can optimize, then do it. But don't let people crash
+ readline because of extra large arguments. */
+ if (count > 1 && count < 1024)
+ {
+ string = xmalloc (1 + count);
+
+ for (i = 0; i < count; i++)
+ string[i] = c;
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ free (string);
+
+ return 0;
+ }
+
+ if (count > 1024)
+ {
+ int decreaser;
+ char str[1024+1];
+
+ for (i = 0; i < 1024; i++)
+ str[i] = c;
+
+ while (count)
+ {
+ decreaser = (count > 1024 ? 1024 : count);
+ str[decreaser] = '\0';
+ rl_insert_text (str);
+ count -= decreaser;
+ }
+
+ return 0;
+ }
+
+ /* We are inserting a single character.
+ If there is pending input, then make a string of all of the
+ pending characters that are bound to rl_insert, and insert
+ them all. */
+ if (any_typein)
+ {
+ int key = 0, t;
+
+ i = 0;
+ string = xmalloc (ibuffer_len + 1);
+ string[i++] = c;
+
+ while ((t = rl_get_char (&key)) &&
+ (_rl_keymap[key].type == ISFUNC &&
+ _rl_keymap[key].function == rl_insert))
+ string[i++] = key;
+
+ if (t)
+ rl_unget_char (key);
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ free (string);
+ }
+ else
+ {
+ /* Inserting a single character. */
+ char str[2];
+
+ str[1] = '\0';
+ str[0] = c;
+ rl_insert_text (str);
+ }
+ return 0;
+}
+
+/* Insert the next typed character verbatim. */
+rl_quoted_insert (count)
+ int count;
+{
+ int c;
+
+ c = rl_read_key ();
+ return (rl_insert (count, c));
+
+}
+
+/* Insert a tab character. */
+rl_tab_insert (count)
+ int count;
+{
+ return (rl_insert (count, '\t'));
+}
+
+/* What to do when a NEWLINE is pressed. We accept the whole line.
+ KEY is the key that invoked this command. I guess it could have
+ meaning in the future. */
+rl_newline (count, key)
+ int count, key;
+{
+ rl_done = 1;
+
+#if defined (VI_MODE)
+ _rl_vi_done_inserting ();
+ _rl_vi_reset_last ();
+
+#endif /* VI_MODE */
+
+ if (readline_echoing_p)
+ {
+ _rl_move_vert (_rl_vis_botlin);
+ _rl_vis_botlin = 0;
+ crlf ();
+ fflush (out_stream);
+ rl_display_fixed++;
+ }
+ return 0;
+}
+
+rl_clean_up_for_exit ()
+{
+ if (readline_echoing_p)
+ {
+ _rl_move_vert (_rl_vis_botlin);
+ _rl_vis_botlin = 0;
+ fflush (out_stream);
+ rl_restart_output ();
+ }
+ return 0;
+}
+
+/* What to do for some uppercase characters, like meta characters,
+ and some characters appearing in emacs_ctlx_keymap. This function
+ is just a stub, you bind keys to it and the code in _rl_dispatch ()
+ is special cased. */
+rl_do_lowercase_version (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ return 0;
+}
+
+/* Rubout the character behind point. */
+rl_rubout (count)
+ int count;
+{
+ if (count < 0)
+ {
+ rl_delete (-count);
+ return 0;
+ }
+
+ if (!rl_point)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (count > 1 || rl_explicit_arg)
+ {
+ int orig_point = rl_point;
+ rl_backward (count);
+ rl_kill_text (orig_point, rl_point);
+ }
+ else
+ {
+ int c = the_line[--rl_point];
+ rl_delete_text (rl_point, rl_point + 1);
+
+ if (rl_point == rl_end && isprint (c) && _rl_last_c_pos)
+ {
+ int l;
+ l = rl_character_len (c, rl_point);
+ _rl_erase_at_end_of_line (l);
+ }
+ }
+ return 0;
+}
+
+/* Delete the character under the cursor. Given a numeric argument,
+ kill that many characters instead. */
+rl_delete (count, invoking_key)
+ int count, invoking_key;
+{
+ if (count < 0)
+ {
+ return (rl_rubout (-count));
+ }
+
+ if (rl_point == rl_end)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (count > 1 || rl_explicit_arg)
+ {
+ int orig_point = rl_point;
+ rl_forward (count);
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ return 0;
+ }
+ else
+ return (rl_delete_text (rl_point, rl_point + 1));
+
+}
+
+/* Delete all spaces and tabs around point. */
+rl_delete_horizontal_space (count, ignore)
+ int count, ignore;
+{
+ int start = rl_point;
+
+ while (rl_point && whitespace (the_line[rl_point - 1]))
+ rl_point--;
+
+ start = rl_point;
+
+ while (rl_point < rl_end && whitespace (the_line[rl_point]))
+ rl_point++;
+
+ if (start != rl_point)
+ {
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ }
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Kill commands */
+/* */
+/* **************************************************************** */
+
+/* The next two functions mimic unix line editing behaviour, except they
+ save the deleted text on the kill ring. This is safer than not saving
+ it, and since we have a ring, nobody should get screwed. */
+
+/* This does what C-w does in Unix. We can't prevent people from
+ using behaviour that they expect. */
+rl_unix_word_rubout ()
+{
+ if (!rl_point)
+ ding ();
+ else
+ {
+ int orig_point = rl_point;
+
+ while (rl_point && whitespace (the_line[rl_point - 1]))
+ rl_point--;
+
+ while (rl_point && !whitespace (the_line[rl_point - 1]))
+ rl_point--;
+
+ rl_kill_text (orig_point, rl_point);
+ }
+ return 0;
+}
+
+/* Here is C-u doing what Unix does. You don't *have* to use these
+ key-bindings. We have a choice of killing the entire line, or
+ killing from where we are to the start of the line. We choose the
+ latter, because if you are a Unix weenie, then you haven't backspaced
+ into the line at all, and if you aren't, then you know what you are
+ doing. */
+rl_unix_line_discard ()
+{
+ if (!rl_point)
+ ding ();
+ else
+ {
+ rl_kill_text (rl_point, 0);
+ rl_point = 0;
+ }
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Commands For Typos */
+/* */
+/* **************************************************************** */
+
+/* Random and interesting things in here. */
+
+/* **************************************************************** */
+/* */
+/* Changing Case */
+/* */
+/* **************************************************************** */
+
+/* The three kinds of things that we know how to do. */
+#define UpCase 1
+#define DownCase 2
+#define CapCase 3
+
+static int rl_change_case ();
+
+/* Uppercase the word at point. */
+rl_upcase_word (count)
+ int count;
+{
+ return (rl_change_case (count, UpCase));
+}
+
+/* Lowercase the word at point. */
+rl_downcase_word (count)
+ int count;
+{
+ return (rl_change_case (count, DownCase));
+}
+
+/* Upcase the first letter, downcase the rest. */
+rl_capitalize_word (count)
+ int count;
+{
+ return (rl_change_case (count, CapCase));
+}
+
+/* The meaty function.
+ Change the case of COUNT words, performing OP on them.
+ OP is one of UpCase, DownCase, or CapCase.
+ If a negative argument is given, leave point where it started,
+ otherwise, leave it where it moves to. */
+static int
+rl_change_case (count, op)
+ int count, op;
+{
+ register int start = rl_point, end;
+ int state = 0;
+
+ rl_forward_word (count);
+ end = rl_point;
+
+ if (count < 0)
+ {
+ int temp = start;
+ start = end;
+ end = temp;
+ }
+
+ /* We are going to modify some text, so let's prepare to undo it. */
+ rl_modifying (start, end);
+
+ for (; start < end; start++)
+ {
+ switch (op)
+ {
+ case UpCase:
+ the_line[start] = to_upper (the_line[start]);
+ break;
+
+ case DownCase:
+ the_line[start] = to_lower (the_line[start]);
+ break;
+
+ case CapCase:
+ if (state == 0)
+ {
+ the_line[start] = to_upper (the_line[start]);
+ state = 1;
+ }
+ else
+ {
+ the_line[start] = to_lower (the_line[start]);
+ }
+ if (!pure_alphabetic (the_line[start]))
+ state = 0;
+ break;
+
+ default:
+ abort ();
+ return -1;
+ }
+ }
+ rl_point = end;
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Transposition */
+/* */
+/* **************************************************************** */
+
+/* Transpose the words at point. */
+rl_transpose_words (count)
+ int count;
+{
+ char *word1, *word2;
+ int w1_beg, w1_end, w2_beg, w2_end;
+ int orig_point = rl_point;
+
+ if (!count)
+ return 0;
+
+ /* Find the two words. */
+ rl_forward_word (count);
+ w2_end = rl_point;
+ rl_backward_word (1);
+ w2_beg = rl_point;
+ rl_backward_word (count);
+ w1_beg = rl_point;
+ rl_forward_word (1);
+ w1_end = rl_point;
+
+ /* Do some check to make sure that there really are two words. */
+ if ((w1_beg == w2_beg) || (w2_beg < w1_end))
+ {
+ ding ();
+ rl_point = orig_point;
+ return -1;
+ }
+
+ /* Get the text of the words. */
+ word1 = rl_copy_text (w1_beg, w1_end);
+ word2 = rl_copy_text (w2_beg, w2_end);
+
+ /* We are about to do many insertions and deletions. Remember them
+ as one operation. */
+ rl_begin_undo_group ();
+
+ /* Do the stuff at word2 first, so that we don't have to worry
+ about word1 moving. */
+ rl_point = w2_beg;
+ rl_delete_text (w2_beg, w2_end);
+ rl_insert_text (word1);
+
+ rl_point = w1_beg;
+ rl_delete_text (w1_beg, w1_end);
+ rl_insert_text (word2);
+
+ /* This is exactly correct since the text before this point has not
+ changed in length. */
+ rl_point = w2_end;
+
+ /* I think that does it. */
+ rl_end_undo_group ();
+ free (word1);
+ free (word2);
+
+ return 0;
+}
+
+/* Transpose the characters at point. If point is at the end of the line,
+ then transpose the characters before point. */
+rl_transpose_chars (count)
+ int count;
+{
+ char dummy[2];
+
+ if (!count)
+ return 0;
+
+ if (!rl_point || rl_end < 2)
+ {
+ ding ();
+ return -1;
+ }
+
+ rl_begin_undo_group ();
+
+ if (rl_point == rl_end)
+ {
+ --rl_point;
+ count = 1;
+ }
+ rl_point--;
+
+ dummy[0] = the_line[rl_point];
+ dummy[1] = '\0';
+
+ rl_delete_text (rl_point, rl_point + 1);
+
+ rl_point += count;
+ if (rl_point > rl_end)
+ rl_point = rl_end;
+ else if (rl_point < 0)
+ rl_point = 0;
+ rl_insert_text (dummy);
+
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Undo, and Undoing */
+/* */
+/* **************************************************************** */
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+void
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ temp->what = what;
+ temp->start = start;
+ temp->end = end;
+ temp->text = text;
+ temp->next = rl_undo_list;
+ rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+void
+free_undo_list ()
+{
+ while (rl_undo_list)
+ {
+ UNDO_LIST *release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+
+ if (release->what == UNDO_DELETE)
+ free (release->text);
+
+ free (release);
+ }
+ rl_undo_list = (UNDO_LIST *)NULL;
+}
+
+/* Undo the next thing in the list. Return 0 if there
+ is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+ UNDO_LIST *release;
+ int waiting_for_begin = 0;
+
+undo_thing:
+ if (!rl_undo_list)
+ return (0);
+
+ doing_an_undo = 1;
+
+ switch (rl_undo_list->what) {
+
+ /* Undoing deletes means inserting some text. */
+ case UNDO_DELETE:
+ rl_point = rl_undo_list->start;
+ rl_insert_text (rl_undo_list->text);
+ free (rl_undo_list->text);
+ break;
+
+ /* Undoing inserts means deleting some text. */
+ case UNDO_INSERT:
+ rl_delete_text (rl_undo_list->start, rl_undo_list->end);
+ rl_point = rl_undo_list->start;
+ break;
+
+ /* Undoing an END means undoing everything 'til we get to
+ a BEGIN. */
+ case UNDO_END:
+ waiting_for_begin++;
+ break;
+
+ /* Undoing a BEGIN means that we are done with this group. */
+ case UNDO_BEGIN:
+ if (waiting_for_begin)
+ waiting_for_begin--;
+ else
+ ding ();
+ break;
+ }
+
+ doing_an_undo = 0;
+
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+ free (release);
+
+ if (waiting_for_begin)
+ goto undo_thing;
+
+ return (1);
+}
+
+/* Begin a group. Subsequent undos are undone as an atomic operation. */
+rl_begin_undo_group ()
+{
+ rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+ return 0;
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+rl_end_undo_group ()
+{
+ rl_add_undo (UNDO_END, 0, 0, 0);
+ return 0;
+}
+
+/* Save an undo entry for the text from START to END. */
+rl_modifying (start, end)
+ int start, end;
+{
+ if (start > end)
+ {
+ int t = start;
+ start = end;
+ end = t;
+ }
+
+ if (start != end)
+ {
+ char *temp = rl_copy_text (start, end);
+ rl_begin_undo_group ();
+ rl_add_undo (UNDO_DELETE, start, end, temp);
+ rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+ rl_end_undo_group ();
+ }
+ return 0;
+}
+
+/* Revert the current line to its previous state. */
+rl_revert_line ()
+{
+ if (!rl_undo_list)
+ ding ();
+ else
+ {
+ while (rl_undo_list)
+ rl_do_undo ();
+ }
+ return 0;
+}
+
+/* Do some undoing of things that were done. */
+rl_undo_command (count)
+ int count;
+{
+ if (count < 0)
+ return 0; /* Nothing to do. */
+
+ while (count)
+ {
+ if (rl_do_undo ())
+ count--;
+ else
+ {
+ ding ();
+ break;
+ }
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* History Utilities */
+/* */
+/* **************************************************************** */
+
+/* We already have a history library, and that is what we use to control
+ the history features of readline. However, this is our local interface
+ to the history mechanism. */
+
+/* While we are editing the history, this is the saved
+ version of the original line. */
+HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL;
+
+/* Set the history pointer back to the last entry in the history. */
+static void
+start_using_history ()
+{
+ using_history ();
+ if (saved_line_for_history)
+ _rl_free_history_entry (saved_line_for_history);
+
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Free the contents (and containing structure) of a HIST_ENTRY. */
+void
+_rl_free_history_entry (entry)
+ HIST_ENTRY *entry;
+{
+ if (!entry)
+ return;
+ if (entry->line)
+ free (entry->line);
+ free (entry);
+}
+
+/* Perhaps put back the current line if it has changed. */
+maybe_replace_line ()
+{
+ HIST_ENTRY *temp = current_history ();
+
+ /* If the current line has changed, save the changes. */
+ if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
+ {
+ temp = replace_history_entry (where_history (), the_line, rl_undo_list);
+ free (temp->line);
+ free (temp);
+ }
+ return 0;
+}
+
+/* Put back the saved_line_for_history if there is one. */
+maybe_unsave_line ()
+{
+ if (saved_line_for_history)
+ {
+ int line_len;
+
+ line_len = strlen (saved_line_for_history->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, saved_line_for_history->line);
+ rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
+ _rl_free_history_entry (saved_line_for_history);
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+ rl_end = rl_point = strlen (the_line);
+ }
+ else
+ ding ();
+ return 0;
+}
+
+/* Save the current line in saved_line_for_history. */
+maybe_save_line ()
+{
+ if (!saved_line_for_history)
+ {
+ saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ saved_line_for_history->line = savestring (the_line);
+ saved_line_for_history->data = (char *)rl_undo_list;
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* History Commands */
+/* */
+/* **************************************************************** */
+
+/* Meta-< goes to the start of the history. */
+rl_beginning_of_history ()
+{
+ return (rl_get_previous_history (1 + where_history ()));
+}
+
+/* Meta-> goes to the end of the history. (The current line). */
+rl_end_of_history ()
+{
+ maybe_replace_line ();
+ using_history ();
+ maybe_unsave_line ();
+ return 0;
+}
+
+/* Move down to the next history line. */
+rl_get_next_history (count)
+ int count;
+{
+ HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+ if (count < 0)
+ return (rl_get_previous_history (-count));
+
+ if (!count)
+ return 0;
+
+ maybe_replace_line ();
+
+ while (count)
+ {
+ temp = next_history ();
+ if (!temp)
+ break;
+ --count;
+ }
+
+ if (!temp)
+ maybe_unsave_line ();
+ else
+ {
+ int line_len;
+
+ line_len = strlen (temp->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = strlen (the_line);
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = 0;
+#endif /* VI_MODE */
+ }
+ return 0;
+}
+
+/* Get the previous item out of our interactive history, making it the current
+ line. If there is no previous history, just ding. */
+rl_get_previous_history (count)
+ int count;
+{
+ HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL;
+ HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+ if (count < 0)
+ return (rl_get_next_history (-count));
+
+ if (!count)
+ return 0;
+
+ /* If we don't have a line saved, then save this one. */
+ maybe_save_line ();
+
+ /* If the current line has changed, save the changes. */
+ maybe_replace_line ();
+
+ while (count)
+ {
+ temp = previous_history ();
+ if (!temp)
+ break;
+ else
+ old_temp = temp;
+ --count;
+ }
+
+ /* If there was a large argument, and we moved back to the start of the
+ history, that is not an error. So use the last value found. */
+ if (!temp && old_temp)
+ temp = old_temp;
+
+ if (!temp)
+ ding ();
+ else
+ {
+ int line_len;
+
+ line_len = strlen (temp->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = line_len;
+
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = 0;
+#endif /* VI_MODE */
+ }
+ return 0;
+}
+
+/* Make C be the next command to be executed. */
+rl_execute_next (c)
+ int c;
+{
+ rl_pending_input = c;
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* The Mark and the Region. */
+/* */
+/* **************************************************************** */
+
+/* Set the mark at POSITION. */
+rl_set_mark (position)
+ int position;
+{
+ if (position > rl_end)
+ return -1;
+
+ rl_mark = position;
+ return 0;
+}
+
+/* Exchange the position of mark and point. */
+rl_exchange_mark_and_point ()
+{
+ if (rl_mark > rl_end)
+ rl_mark = -1;
+
+ if (rl_mark == -1)
+ {
+ ding ();
+ return -1;
+ }
+ else
+ {
+ int temp = rl_point;
+
+ rl_point = rl_mark;
+ rl_mark = temp;
+ }
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Killing Mechanism */
+/* */
+/* **************************************************************** */
+
+/* What we assume for a max number of kills. */
+#define DEFAULT_MAX_KILLS 10
+
+/* The real variable to look at to find out when to flush kills. */
+int rl_max_kills = DEFAULT_MAX_KILLS;
+
+/* Where to store killed text. */
+char **rl_kill_ring = (char **)NULL;
+
+/* Where we are in the kill ring. */
+int rl_kill_index = 0;
+
+/* How many slots we have in the kill ring. */
+int rl_kill_ring_length = 0;
+
+/* How to say that you only want to save a certain amount
+ of kill material. */
+rl_set_retained_kills (num)
+ int num;
+{
+ return 0;
+}
+
+/* The way to kill something. This appends or prepends to the last
+ kill, if the last command was a kill command. if FROM is less
+ than TO, then the text is appended, otherwise prepended. If the
+ last command was not a kill command, then a new slot is made for
+ this kill. */
+rl_kill_text (from, to)
+ int from, to;
+{
+ int slot;
+ char *text = rl_copy_text (from, to);
+
+ /* Is there anything to kill? */
+ if (from == to)
+ {
+ free (text);
+ last_command_was_kill++;
+ return 0;
+ }
+
+ /* Delete the copied text from the line. */
+ rl_delete_text (from, to);
+
+ /* First, find the slot to work with. */
+ if (!last_command_was_kill)
+ {
+ /* Get a new slot. */
+ if (!rl_kill_ring)
+ {
+ /* If we don't have any defined, then make one. */
+ rl_kill_ring = (char **)
+ xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *));
+ slot = 1;
+ }
+ else
+ {
+ /* We have to add a new slot on the end, unless we have
+ exceeded the max limit for remembering kills. */
+ slot = rl_kill_ring_length;
+ if (slot == rl_max_kills)
+ {
+ register int i;
+ free (rl_kill_ring[0]);
+ for (i = 0; i < slot; i++)
+ rl_kill_ring[i] = rl_kill_ring[i + 1];
+ }
+ else
+ {
+ rl_kill_ring =
+ (char **)
+ xrealloc (rl_kill_ring,
+ ((slot = (rl_kill_ring_length += 1)) + 1)
+ * sizeof (char *));
+ }
+ }
+ slot--;
+ }
+ else
+ {
+ slot = rl_kill_ring_length - 1;
+ }
+
+ /* If the last command was a kill, prepend or append. */
+ if (last_command_was_kill && rl_editing_mode != vi_mode)
+ {
+ char *old = rl_kill_ring[slot];
+ char *new = (char *)xmalloc (1 + strlen (old) + strlen (text));
+
+ if (from < to)
+ {
+ strcpy (new, old);
+ strcat (new, text);
+ }
+ else
+ {
+ strcpy (new, text);
+ strcat (new, old);
+ }
+ free (old);
+ free (text);
+ rl_kill_ring[slot] = new;
+ }
+ else
+ {
+ rl_kill_ring[slot] = text;
+ }
+ rl_kill_index = slot;
+ last_command_was_kill++;
+ return 0;
+}
+
+/* Now REMEMBER! In order to do prepending or appending correctly, kill
+ commands always make rl_point's original position be the FROM argument,
+ and rl_point's extent be the TO argument. */
+
+/* **************************************************************** */
+/* */
+/* Killing Commands */
+/* */
+/* **************************************************************** */
+
+/* Delete the word at point, saving the text in the kill ring. */
+rl_kill_word (count)
+ int count;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ return (rl_backward_kill_word (-count));
+ else
+ {
+ rl_forward_word (count);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+
+ rl_point = orig_point;
+ }
+ return 0;
+}
+
+/* Rubout the word before point, placing it on the kill ring. */
+rl_backward_kill_word (count, ignore)
+ int count, ignore;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ return (rl_kill_word (-count));
+ else
+ {
+ rl_backward_word (count);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+ }
+ return 0;
+}
+
+/* Kill from here to the end of the line. If DIRECTION is negative, kill
+ back to the line start instead. */
+rl_kill_line (direction)
+ int direction;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ return (rl_backward_kill_line (1));
+ else
+ {
+ rl_end_of_line ();
+ if (orig_point != rl_point)
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ }
+ return 0;
+}
+
+/* Kill backwards to the start of the line. If DIRECTION is negative, kill
+ forwards to the line end instead. */
+rl_backward_kill_line (direction)
+ int direction;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ return (rl_kill_line (1));
+ else
+ {
+ if (!rl_point)
+ ding ();
+ else
+ {
+ rl_beg_of_line ();
+ rl_kill_text (orig_point, rl_point);
+ }
+ }
+ return 0;
+}
+
+/* Kill the whole line, no matter where point is. */
+rl_kill_full_line (count, ignore)
+ int count, ignore;
+{
+ rl_begin_undo_group ();
+ rl_point = 0;
+ rl_kill_text (rl_point, rl_end);
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* Yank back the last killed text. This ignores arguments. */
+rl_yank (count, ignore)
+ int count, ignore;
+{
+ if (!rl_kill_ring)
+ {
+ rl_abort ();
+ return -1;
+ }
+
+ rl_set_mark (rl_point);
+ rl_insert_text (rl_kill_ring[rl_kill_index]);
+ return 0;
+}
+
+/* If the last command was yank, or yank_pop, and the text just
+ before point is identical to the current kill item, then
+ delete that text from the line, rotate the index down, and
+ yank back some other text. */
+rl_yank_pop (count, key)
+ int count, key;
+{
+ int l;
+
+ if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) ||
+ !rl_kill_ring)
+ {
+ rl_abort ();
+ return -1;
+ }
+
+ l = strlen (rl_kill_ring[rl_kill_index]);
+ if (((rl_point - l) >= 0) &&
+ (strncmp (the_line + (rl_point - l),
+ rl_kill_ring[rl_kill_index], l) == 0))
+ {
+ rl_delete_text ((rl_point - l), rl_point);
+ rl_point -= l;
+ rl_kill_index--;
+ if (rl_kill_index < 0)
+ rl_kill_index = rl_kill_ring_length - 1;
+ rl_yank (1, 0);
+ return 0;
+ }
+ else
+ {
+ rl_abort ();
+ return -1;
+ }
+}
+
+/* Yank the COUNTth argument from the previous history line. */
+rl_yank_nth_arg (count, ignore)
+ int count, ignore;
+{
+ register HIST_ENTRY *entry = previous_history ();
+ char *arg;
+
+ if (entry)
+ next_history ();
+ else
+ {
+ ding ();
+ return -1;
+ }
+
+ arg = history_arg_extract (count, count, entry->line);
+ if (!arg || !*arg)
+ {
+ ding ();
+ return -1;
+ }
+
+ rl_begin_undo_group ();
+
+#if defined (VI_MODE)
+ /* Vi mode always inserts a space before yanking the argument, and it
+ inserts it right *after* rl_point. */
+ if (rl_editing_mode == vi_mode)
+ {
+ rl_vi_append_mode ();
+ rl_insert_text (" ");
+ }
+#endif /* VI_MODE */
+
+ rl_insert_text (arg);
+ free (arg);
+
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* How to toggle back and forth between editing modes. */
+rl_vi_editing_mode (count, key)
+ int count, key;
+{
+#if defined (VI_MODE)
+ rl_editing_mode = vi_mode;
+ rl_vi_insertion_mode ();
+ return 0;
+#endif /* VI_MODE */
+}
+
+rl_emacs_editing_mode (count, key)
+ int count, key;
+{
+ rl_editing_mode = emacs_mode;
+ _rl_keymap = emacs_standard_keymap;
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* USG (System V) Support */
+/* */
+/* **************************************************************** */
+
+int
+rl_getc (stream)
+ FILE *stream;
+{
+ int result;
+ unsigned char c;
+
+#if defined (__GO32__)
+ if (isatty (0))
+ return (getkey ());
+#endif /* __GO32__ */
+
+ while (1)
+ {
+ result = read (fileno (stream), &c, sizeof (unsigned char));
+
+ if (result == sizeof (unsigned char))
+ return (c);
+
+ /* If zero characters are returned, then the file that we are
+ reading from is empty! Return EOF in that case. */
+ if (result == 0)
+ return (EOF);
+
+#if defined (EWOULDBLOCK)
+ if (errno == EWOULDBLOCK)
+ {
+ int flags;
+
+ if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+ return (EOF);
+ if (flags & O_NDELAY)
+ {
+ flags &= ~O_NDELAY;
+ fcntl (fileno (stream), F_SETFL, flags);
+ continue;
+ }
+ continue;
+ }
+#endif /* EWOULDBLOCK */
+
+#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK)
+ if (errno == EAGAIN)
+ {
+ int flags;
+
+ if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+ return (EOF);
+ if (flags & O_NONBLOCK)
+ {
+ flags &= ~O_NONBLOCK;
+ fcntl (fileno (stream), F_SETFL, flags);
+ continue;
+ }
+ }
+#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */
+
+#if !defined (__GO32__)
+ /* If the error that we received was SIGINT, then try again,
+ this is simply an interrupted system call to read ().
+ Otherwise, some error ocurred, also signifying EOF. */
+ if (errno != EINTR)
+ return (EOF);
+#endif /* !__GO32__ */
+ }
+}
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
+
+
+/* **************************************************************** */
+/* */
+/* Testing Readline */
+/* */
+/* **************************************************************** */
+
+#if defined (TEST)
+
+main ()
+{
+ HIST_ENTRY **history_list ();
+ char *temp = (char *)NULL;
+ char *prompt = "readline% ";
+ int done = 0;
+
+ while (!done)
+ {
+ temp = readline (prompt);
+
+ /* Test for EOF. */
+ if (!temp)
+ exit (1);
+
+ /* If there is anything on the line, print it and remember it. */
+ if (*temp)
+ {
+ fprintf (stderr, "%s\r\n", temp);
+ add_history (temp);
+ }
+
+ /* Check for `command' that we handle. */
+ if (strcmp (temp, "quit") == 0)
+ done = 1;
+
+ if (strcmp (temp, "list") == 0)
+ {
+ HIST_ENTRY **list = history_list ();
+ register int i;
+ if (list)
+ {
+ for (i = 0; list[i]; i++)
+ {
+ fprintf (stderr, "%d: %s\r\n", i, list[i]->line);
+ free (list[i]->line);
+ }
+ free (list);
+ }
+ }
+ free (temp);
+ }
+}
+
+#endif /* TEST */
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap"
+ * end:
+ */
diff --git a/gnu/lib/libreadline/readline/chardefs.h b/gnu/lib/libreadline/readline/chardefs.h
new file mode 100644
index 000000000000..aa63da61da5c
--- /dev/null
+++ b/gnu/lib/libreadline/readline/chardefs.h
@@ -0,0 +1,89 @@
+/* chardefs.h -- Character definitions for readline. */
+#ifndef _CHARDEFS_
+#define _CHARDEFS_
+
+#include <ctype.h>
+#include <string.h>
+
+#ifndef savestring
+extern char *xmalloc ();
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifdef CTRL
+#undef CTRL
+#endif
+
+/* Some character stuff. */
+#define control_character_threshold 0x020 /* Smaller than this is control. */
+#define meta_character_threshold 0x07f /* Larger than this is Meta. */
+#define control_character_bit 0x40 /* 0x000000, must be off. */
+#define meta_character_bit 0x080 /* x0000000, must be on. */
+#define largest_char 255 /* Largest character value. */
+
+#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
+#define CTRL(c) ((c) & (~control_character_bit))
+#define META(c) ((c) | meta_character_bit)
+
+#define UNMETA(c) ((c) & (~meta_character_bit))
+#define UNCTRL(c) to_upper(((c)|control_character_bit))
+
+#define lowercase_p(c) islower(c)
+#define uppercase_p(c) isupper(c)
+
+#define pure_alphabetic(c) isalpha(c)
+
+#ifndef to_upper
+#define to_upper(c) toupper(c)
+#define to_lower(c) tolower(c)
+#endif
+
+#define CTRL_P(c) ((c) < control_character_threshold)
+#define META_P(c) ((c) > meta_character_threshold)
+
+#ifndef digit_value
+#define digit_value(x) ((x) - '0')
+#endif
+
+#ifndef NEWLINE
+#define NEWLINE '\n'
+#endif
+
+#ifndef RETURN
+#define RETURN CTRL('M')
+#endif
+
+#ifndef RUBOUT
+#define RUBOUT 0x7f
+#endif
+
+#ifndef TAB
+#define TAB '\t'
+#endif
+
+#ifdef ABORT_CHAR
+#undef ABORT_CHAR
+#endif
+#define ABORT_CHAR CTRL('G')
+
+#ifdef PAGE
+#undef PAGE
+#endif
+#define PAGE CTRL('L')
+
+#ifdef SPACE
+#undef SPACE
+#endif
+#define SPACE 0x20
+
+#ifdef ESC
+#undef ESC
+#endif
+
+#define ESC CTRL('[')
+
+#endif /* _CHARDEFS_ */
diff --git a/gnu/lib/libreadline/readline/history.h b/gnu/lib/libreadline/readline/history.h
new file mode 100644
index 000000000000..2ef5424cb184
--- /dev/null
+++ b/gnu/lib/libreadline/readline/history.h
@@ -0,0 +1,149 @@
+/* History.h -- the names of functions that you can call in history. */
+
+/* The structure used to store a history entry. */
+typedef struct _hist_entry {
+ char *line;
+ char *data;
+} HIST_ENTRY;
+
+/* A structure used to pass the current state of the history stuff around. */
+typedef struct _hist_state {
+ HIST_ENTRY **entries; /* Pointer to the entries themselves. */
+ int offset; /* The location pointer within this array. */
+ int length; /* Number of elements within this array. */
+ int size; /* Number of slots allocated to this array. */
+} HISTORY_STATE;
+
+/* For convenience only. You set this when interpreting history commands.
+ It is the logical offset of the first history element. */
+extern int history_base;
+
+/* Begin a session in which the history functions might be used. This
+ just initializes the interactive variables. */
+extern void using_history ();
+
+/* Return the current HISTORY_STATE of the history. */
+extern HISTORY_STATE *history_get_history_state ();
+
+/* Set the state of the current history array to STATE. */
+extern void history_set_history_state ();
+
+/* Place STRING at the end of the history list.
+ The associated data field (if any) is set to NULL. */
+extern void add_history ();
+
+/* Returns the number which says what history element we are now
+ looking at. */
+extern int where_history ();
+
+/* Set the position in the history list to POS. */
+int history_set_pos ();
+
+/* Search for STRING in the history list, starting at POS, an
+ absolute index into the list. DIR, if negative, says to search
+ backwards from POS, else forwards.
+ Returns the absolute index of the history element where STRING
+ was found, or -1 otherwise. */
+extern int history_search_pos ();
+
+/* A reasonably useless function, only here for completeness. WHICH
+ is the magic number that tells us which element to delete. The
+ elements are numbered from 0. */
+extern HIST_ENTRY *remove_history ();
+
+/* Stifle the history list, remembering only MAX number of entries. */
+extern void stifle_history ();
+
+/* Stop stifling the history. This returns the previous amount the
+ history was stifled by. The value is positive if the history was
+ stifled, negative if it wasn't. */
+extern int unstifle_history ();
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+extern int read_history ();
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+ Start reading at the FROM'th line and end at the TO'th. If FROM
+ is zero, start at the beginning. If TO is less than FROM, read
+ until the end of the file. If FILENAME is NULL, then read from
+ ~/.history. Returns 0 if successful, or errno if not. */
+extern int read_history_range ();
+
+/* Append the current history to FILENAME. If FILENAME is NULL,
+ then append the history list to ~/.history. Values returned
+ are as in read_history (). */
+extern int write_history ();
+
+/* Append NELEMENT entries to FILENAME. The entries appended are from
+ the end of the list minus NELEMENTs up to the end of the list. */
+int append_history ();
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+extern HIST_ENTRY *replace_history_entry ();
+
+/* Return the history entry at the current position, as determined by
+ history_offset. If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *current_history ();
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry, return
+ a NULL pointer. */
+extern HIST_ENTRY *previous_history ();
+
+/* Move history_offset forward to the next item in the input_history,
+ and return the a pointer to that entry. If there is no next entry,
+ return a NULL pointer. */
+extern HIST_ENTRY *next_history ();
+
+/* Return a NULL terminated array of HIST_ENTRY which is the current input
+ history. Element 0 of this list is the beginning of time. If there
+ is no history, return NULL. */
+extern HIST_ENTRY **history_list ();
+
+/* Search the history for STRING, starting at history_offset.
+ If DIRECTION < 0, then the search is through previous entries,
+ else through subsequent. If the string is found, then
+ current_history () is the history entry, and the value of this function
+ is the offset in the line of that history entry that the string was
+ found in. Otherwise, nothing is changed, and a -1 is returned. */
+extern int history_search ();
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ -1) If there was an error in expansion.
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+extern int history_expand ();
+
+/* Return an array of tokens, much as the shell might. The tokens are
+ parsed out of STRING. */
+extern char **history_tokenize ();
+
+/* Extract a string segment consisting of the FIRST through LAST
+ arguments present in STRING. Arguments are broken up as in
+ the shell. */
+extern char *history_arg_extract ();
+
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines. */
+extern int history_total_bytes ();
+
+/* Exported history variables. */
+extern int history_stifled;
+extern int history_length;
+extern int max_input_history;
+extern char history_expansion_char;
+extern char history_subst_char;
+extern char history_comment_char;
+extern char *history_no_expand_chars;
+extern int history_base;
diff --git a/gnu/lib/libreadline/readline/keymaps.h b/gnu/lib/libreadline/readline/keymaps.h
new file mode 100644
index 000000000000..f7e9f6f9689b
--- /dev/null
+++ b/gnu/lib/libreadline/readline/keymaps.h
@@ -0,0 +1,91 @@
+/* keymaps.h -- Manipulation of readline keymaps. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _KEYMAPS_H_
+#define _KEYMAPS_H_
+
+#include <readline/chardefs.h>
+
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif
+
+/* A keymap contains one entry for each key in the ASCII set.
+ Each entry consists of a type and a pointer.
+ POINTER is the address of a function to run, or the
+ address of a keymap to indirect through.
+ TYPE says which kind of thing POINTER is. */
+typedef struct _keymap_entry {
+ char type;
+ Function *function;
+} KEYMAP_ENTRY;
+
+/* This must be large enough to hold bindings for all of the characters
+ in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x,
+ and so on). */
+#define KEYMAP_SIZE 256
+
+/* I wanted to make the above structure contain a union of:
+ union { Function *function; struct _keymap_entry *keymap; } value;
+ but this made it impossible for me to create a static array.
+ Maybe I need C lessons. */
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
+extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+extern Keymap rl_make_bare_keymap ();
+
+/* Return a new keymap which is a copy of MAP. */
+extern Keymap rl_copy_keymap ();
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the lowercase Meta characters bound to run their equivalents, and
+ the Meta digits bound to produce numeric arguments. */
+extern Keymap rl_make_keymap ();
+
+extern void rl_discard_keymap ();
+
+/* Return the keymap corresponding to a given name. Names look like
+ `emacs' or `emacs-meta' or `vi-insert'. */
+extern Keymap rl_get_keymap_by_name ();
+
+/* Return the current keymap. */
+extern Keymap rl_get_keymap ();
+
+/* Set the current keymap to MAP. */
+extern void rl_set_keymap ();
+
+#endif /* _KEYMAPS_H_ */
diff --git a/gnu/lib/libreadline/readline/readline.h b/gnu/lib/libreadline/readline/readline.h
new file mode 100644
index 000000000000..bbc8a0f02ac7
--- /dev/null
+++ b/gnu/lib/libreadline/readline/readline.h
@@ -0,0 +1,267 @@
+/* Readline.h -- the names of functions callable from within readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_READLINE_H_)
+#define _READLINE_H_
+
+#include <readline/keymaps.h>
+#include <readline/tilde.h>
+
+/* The functions for manipulating the text of the line within readline.
+Most of these functions are bound to keys by default. */
+extern int
+ rl_tilde_expand (),
+ rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (),
+ rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (),
+ rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (),
+ rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars (),
+ rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout (),
+ rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (),
+ rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (),
+ rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words (),
+ rl_complete (), rl_possible_completions (), rl_insert_completions (),
+ rl_do_lowercase_version (), rl_kill_full_line (),
+ rl_digit_argument (), rl_universal_argument (), rl_abort (),
+ rl_undo_command (), rl_revert_line (), rl_beginning_of_history (),
+ rl_end_of_history (), rl_forward_search_history (), rl_insert (),
+ rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (),
+ rl_restart_output (), rl_re_read_init_file (), rl_dump_functions (),
+ rl_delete_horizontal_space (), rl_history_search_forward (),
+ rl_history_search_backward ();
+
+/* `Public' utility functions. */
+extern int rl_insert_text (), rl_delete_text (), rl_kill_text ();
+extern int rl_complete_internal ();
+extern int rl_expand_prompt ();
+extern int rl_initialize ();
+extern int rl_set_signals (), rl_clear_signals ();
+extern int rl_init_argument (), rl_digit_argument ();
+extern int rl_read_key (), rl_getc (), rl_stuff_char ();
+extern int maybe_save_line (), maybe_unsave_line (), maybe_replace_line ();
+extern int rl_modifying ();
+
+extern int rl_begin_undo_group (), rl_end_undo_group ();
+extern void rl_add_undo (), free_undo_list ();
+extern int rl_do_undo ();
+
+extern int rl_insert_close ();
+
+/* These are *both* defined even when VI_MODE is not. */
+extern int rl_vi_editing_mode (), rl_emacs_editing_mode ();
+
+/* Non incremental history searching. */
+extern int
+ rl_noninc_forward_search (), rl_noninc_reverse_search (),
+ rl_noninc_forward_search_again (), rl_noninc_reverse_search_again ();
+
+/* Things for vi mode. */
+extern int rl_vi_check (), rl_vi_textmod_command ();
+extern int
+ rl_vi_redo (), rl_vi_tilde_expand (),
+ rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (),
+ rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (),
+ rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (),
+ rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (),
+ rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (),
+ rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (),
+ rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (),
+ rl_vi_change_char (), rl_vi_yank_arg (), rl_vi_search (),
+ rl_vi_search_again (), rl_vi_subst (), rl_vi_overstrike (),
+ rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (),
+ rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (),
+ rl_vi_complete (), rl_vi_fetch_history ();
+
+/* Keyboard macro commands. */
+extern int rl_start_kbd_macro (), rl_end_kbd_macro ();
+extern int rl_call_last_kbd_macro ();
+
+extern int rl_arrow_keys(), rl_refresh_line ();
+
+/* Maintaining the state of undo. We remember individual deletes and inserts
+ on a chain of things to do. */
+
+/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
+ to insert some text, and UNDO_INSERT means to delete some text. I.e.,
+ the code tells undo what to undo, not how to undo it. */
+enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
+
+/* What an element of THE_UNDO_LIST looks like. */
+typedef struct undo_list {
+ struct undo_list *next;
+ int start, end; /* Where the change took place. */
+ char *text; /* The text to insert, if undoing a delete. */
+ enum undo_code what; /* Delete, Insert, Begin, End. */
+} UNDO_LIST;
+
+/* The current undo list for RL_LINE_BUFFER. */
+extern UNDO_LIST *rl_undo_list;
+
+/* The data structure for mapping textual names to code addresses. */
+typedef struct {
+ char *name;
+ Function *function;
+} FUNMAP;
+
+extern FUNMAP **funmap;
+
+/* **************************************************************** */
+/* */
+/* Well Published Variables */
+/* */
+/* **************************************************************** */
+
+/* The name of the calling program. You should initialize this to
+ whatever was in argv[0]. It is used when parsing conditionals. */
+extern char *rl_readline_name;
+
+/* The line buffer that is in use. */
+extern char *rl_line_buffer;
+
+/* The location of point, and end. */
+extern int rl_point, rl_end;
+
+/* The name of the terminal to use. */
+extern char *rl_terminal_name;
+
+/* The input and output streams. */
+extern FILE *rl_instream, *rl_outstream;
+
+/* The basic list of characters that signal a break between words for the
+ completer routine. The initial contents of this variable is what
+ breaks words in the shell, i.e. "n\"\\'`@$>". */
+extern char *rl_basic_word_break_characters;
+
+/* The list of characters that signal a break between words for
+ rl_complete_internal. The default list is the contents of
+ rl_basic_word_break_characters. */
+extern char *rl_completer_word_break_characters;
+
+/* List of characters which can be used to quote a substring of the line.
+ Completion occurs on the entire substring, and within the substring
+ rl_completer_word_break_characters are treated as any other character,
+ unless they also appear within this list. */
+extern char *rl_completer_quote_characters;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+extern char *rl_special_prefixes;
+
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_entry_function (), the default filename
+ completer. */
+extern Function *rl_completion_entry_function;
+
+/* If rl_ignore_some_completions_function is non-NULL it is the address
+ of a function to call after all of the possible matches have been
+ generated, but before the actual completion is done to the input line.
+ The function is called with one argument; a NULL terminated array
+ of (char *). If your function removes any of the elements, they
+ must be free()'ed. */
+extern Function *rl_ignore_some_completions_function;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+extern CPPFunction *rl_attempted_completion_function;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal () prints the first prompt. */
+extern Function *rl_startup_hook;
+
+/* If non-zero, then this is the address of a function to call when
+ completing on a directory name. The function is called with
+ the address of a string (the current directory name) as an arg. */
+extern Function *rl_directory_completion_hook;
+
+/* Backwards compatibility with previous versions of readline. */
+#define rl_symbolic_link_hook rl_directory_completion_hook
+
+/* The address of a function to call periodically while Readline is
+ awaiting character input, or NULL, for no event handling. */
+extern Function *rl_event_hook;
+
+/* Non-zero means that modified history lines are preceded
+ with an asterisk. */
+extern int rl_show_star;
+
+/* Non-zero means to suppress normal filename completion after the
+ user-specified completion function has been called. */
+extern int rl_attempted_completion_over;
+
+/* **************************************************************** */
+/* */
+/* Well Published Functions */
+/* */
+/* **************************************************************** */
+
+/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
+extern char *readline ();
+
+/* These functions are from complete.c. */
+/* Return an array of strings which are the result of repeatadly calling
+ FUNC with TEXT. */
+extern char **completion_matches ();
+extern char *username_completion_function ();
+extern char *filename_completion_function ();
+
+/* These functions are from bind.c. */
+/* rl_add_defun (char *name, Function *function, int key)
+ Add NAME to the list of named functions. Make FUNCTION
+ be the function that gets called.
+ If KEY is not -1, then bind it. */
+extern int rl_add_defun ();
+extern int rl_bind_key (), rl_bind_key_in_map ();
+extern int rl_unbind_key (), rl_unbind_key_in_map ();
+extern int rl_set_key ();
+extern int rl_macro_bind (), rl_generic_bind (), rl_variable_bind ();
+extern int rl_translate_keyseq ();
+extern Function *rl_named_function (), *rl_function_of_keyseq ();
+extern int rl_parse_and_bind ();
+extern Keymap rl_get_keymap (), rl_get_keymap_by_name ();
+extern void rl_set_keymap ();
+extern char **rl_invoking_keyseqs (), **rl_invoking_keyseqs_in_map ();
+extern void rl_function_dumper ();
+extern int rl_read_init_file ();
+
+/* Functions in funmap.c */
+extern void rl_list_funmap_names ();
+extern void rl_initialize_funmap ();
+
+/* Functions in display.c */
+extern void rl_redisplay ();
+extern int rl_message (), rl_clear_message ();
+extern int rl_reset_line_state ();
+extern int rl_character_len ();
+extern int rl_show_char ();
+extern int crlf (), rl_on_new_line ();
+extern int rl_forced_update_display ();
+
+/* Definitions available for use by readline clients. */
+#define RL_PROMPT_START_IGNORE '\001'
+#define RL_PROMPT_END_IGNORE '\002'
+
+#endif /* _READLINE_H_ */
diff --git a/gnu/lib/libreadline/readline/tilde.h b/gnu/lib/libreadline/readline/tilde.h
new file mode 100644
index 000000000000..726d081ba9cb
--- /dev/null
+++ b/gnu/lib/libreadline/readline/tilde.h
@@ -0,0 +1,38 @@
+/* tilde.h: Externally available variables and function in libtilde.a. */
+
+#if !defined (__TILDE_H__)
+# define __TILDE_H__
+
+/* Function pointers can be declared as (Function *)foo. */
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+extern CPFunction *tilde_expansion_failure_hook;
+
+/* When non-null, this is a NULL terminated array of strings which
+ are duplicates for a tilde prefix. Bash uses this to expand
+ `=~' and `:~'. */
+extern char **tilde_additional_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+ the end of a username, instead of just "/". Bash sets this to
+ `:' and `=~'. */
+extern char **tilde_additional_suffixes;
+
+/* Return a new string which is the result of tilde expanding STRING. */
+extern char *tilde_expand ();
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook. */
+extern char *tilde_expand_word ();
+
+#endif /* __TILDE_H__ */
diff --git a/gnu/lib/libreadline/rlconf.h b/gnu/lib/libreadline/rlconf.h
new file mode 100644
index 000000000000..a9b100fd10c3
--- /dev/null
+++ b/gnu/lib/libreadline/rlconf.h
@@ -0,0 +1,57 @@
+/* rlconf.h -- readline configuration definitions */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The 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 1, or (at your option)
+ any later version.
+
+ The 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLCONF_H_)
+#define _RLCONF_H_
+
+/* Define this if you want the vi-mode editing available. */
+#define VI_MODE
+
+/* Define this to get an indication of file type when listing completions. */
+#define VISIBLE_STATS
+
+/* If defined, readline shows opening parens and braces when closing
+ paren or brace entered. */
+#define PAREN_MATCHING
+
+/* This definition is needed by readline.c, rltty.c, and signals.c. */
+/* If on, then readline handles signals in a way that doesn't screw. */
+#define HANDLE_SIGNALS
+
+/* Ugly but working hack for binding prefix meta. */
+#define PREFIX_META_HACK
+
+/* The final, last-ditch effort file name for an init file. */
+#define DEFAULT_INPUTRC "~/.inputrc"
+
+/* If defined, expand tabs to spaces. */
+#define DISPLAY_TABS
+
+/* If defined, use the terminal escape sequence to move the cursor forward
+ over a character when updating the line rather than rewriting it. */
+/* #define HACK_TERMCAP_MOTION */
+
+/* The string inserted by the vi-mode `insert comment' command. */
+#define VI_COMMENT_BEGIN_DEFAULT "#"
+
+#endif /* _RLCONF_H_ */
diff --git a/gnu/lib/libreadline/rldefs.h b/gnu/lib/libreadline/rldefs.h
new file mode 100644
index 000000000000..8f8a176c873f
--- /dev/null
+++ b/gnu/lib/libreadline/rldefs.h
@@ -0,0 +1,190 @@
+/* rldefs.h -- an attempt to isolate some of the system-specific defines
+ for readline. This should be included after any files that define
+ system-specific constants like _POSIX_VERSION or USG. */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The 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 1, or (at your option)
+ any later version.
+
+ The 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLDEFS_H)
+#define _RLDEFS_H
+
+#if !defined (PRAGMA_ALLOCA)
+# include "memalloc.h"
+#endif
+
+#define NEW_TTY_DRIVER
+#define HAVE_BSD_SIGNALS
+/* #define USE_XON_XOFF */
+
+#if defined (__linux__)
+# include <termcap.h>
+#endif /* __linux__ */
+
+/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
+#if defined (USG) && !defined (hpux)
+# undef HAVE_BSD_SIGNALS
+#endif
+
+/* System V machines use termio. */
+#if !defined (_POSIX_VERSION)
+# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX)
+# undef NEW_TTY_DRIVER
+# define TERMIO_TTY_DRIVER
+# include <termio.h>
+# if !defined (TCOON)
+# define TCOON 1
+# endif
+# endif /* USG || hpux || Xenix || sgi || DUGX */
+#endif /* !_POSIX_VERSION */
+
+/* Posix systems use termios and the Posix signal functions. */
+#if defined (_POSIX_VERSION)
+# if !defined (TERMIOS_MISSING)
+# undef NEW_TTY_DRIVER
+# define TERMIOS_TTY_DRIVER
+# include <termios.h>
+# endif /* !TERMIOS_MISSING */
+# define HAVE_POSIX_SIGNALS
+# if !defined (O_NDELAY)
+# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */
+# endif /* O_NDELAY */
+#endif /* _POSIX_VERSION */
+
+/* System V.3 machines have the old 4.1 BSD `reliable' signal interface. */
+#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
+# if defined (USGr3) && !defined (XENIX_22)
+# if !defined (HAVE_USG_SIGHOLD)
+# define HAVE_USG_SIGHOLD
+# endif /* !HAVE_USG_SIGHOLD */
+# endif /* USGr3 && !XENIX_22 */
+#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
+
+/* Other (BSD) machines use sgtty. */
+#if defined (NEW_TTY_DRIVER)
+# include <sgtty.h>
+#endif
+
+/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
+ it is not already defined. It is used both to determine if a
+ special character is disabled and to disable certain special
+ characters. Posix systems should set to 0, USG systems to -1. */
+#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
+# if defined (_POSIX_VERSION)
+# define _POSIX_VDISABLE 0
+# else /* !_POSIX_VERSION */
+# define _POSIX_VDISABLE -1
+# endif /* !_POSIX_VERSION */
+#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
+
+#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3))
+# if !defined (HAVE_DIRENT_H)
+# define HAVE_DIRENT_H
+# endif /* !HAVE_DIRENT_H */
+#endif /* !SHELL && (_POSIX_VERSION || USGr3) */
+
+#if defined (HAVE_DIRENT_H)
+# include <dirent.h>
+# if !defined (direct)
+# define direct dirent
+# endif /* !direct */
+# define D_NAMLEN(d) strlen ((d)->d_name)
+#else /* !HAVE_DIRENT_H */
+# define D_NAMLEN(d) ((d)->d_namlen)
+# if defined (USG)
+# if defined (Xenix)
+# include <sys/ndir.h>
+# else /* !Xenix (but USG...) */
+# include "ndir.h"
+# endif /* !Xenix */
+# else /* !USG */
+# include <sys/dir.h>
+# endif /* !USG */
+#endif /* !HAVE_DIRENT_H */
+
+#if defined (USG) && defined (TIOCGWINSZ) && !defined (Linux)
+# if defined (HAVE_SYS_STREAM_H)
+# include <sys/stream.h>
+# endif /* HAVE_SYS_STREAM_H */
+# if defined (HAVE_SYS_PTEM_H)
+# include <sys/ptem.h>
+# endif /* HAVE_SYS_PTEM_H */
+# if defined (HAVE_SYS_PTE_H)
+# include <sys/pte.h>
+# endif /* HAVE_SYS_PTE_H */
+#endif /* USG && TIOCGWINSZ && !Linux */
+
+/* Posix macro to check file in statbuf for directory-ness.
+ This requires that <sys/stat.h> be included before this test. */
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif
+
+/* Decide which flavor of the header file describing the C library
+ string functions to include and include it. */
+
+#if defined (USG) || defined (NeXT)
+# if !defined (HAVE_STRING_H)
+# define HAVE_STRING_H
+# endif /* !HAVE_STRING_H */
+#endif /* USG || NeXT */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+#if defined (HAVE_VARARGS_H)
+# include <varargs.h>
+#endif /* HAVE_VARARGS_H */
+
+#if !defined (emacs_mode)
+# define no_mode -1
+# define vi_mode 0
+# define emacs_mode 1
+#endif
+
+/* If you cast map[key].function to type (Keymap) on a Cray,
+ the compiler takes the value of map[key].function and
+ divides it by 4 to convert between pointer types (pointers
+ to functions and pointers to structs are different sizes).
+ This is not what is wanted. */
+#if defined (CRAY)
+# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function)
+# define KEYMAP_TO_FUNCTION(data) (Function *)((int)(data))
+#else
+# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function)
+# define KEYMAP_TO_FUNCTION(data) (Function *)(data)
+#endif
+
+/* Possible values for _rl_bell_preference. */
+#define NO_BELL 0
+#define AUDIBLE_BELL 1
+#define VISIBLE_BELL 2
+
+/* CONFIGURATION SECTION */
+#include "rlconf.h"
+
+#endif /* !_RLDEFS_H */
diff --git a/gnu/lib/libreadline/rltty.c b/gnu/lib/libreadline/rltty.c
new file mode 100644
index 000000000000..3864863a0cf1
--- /dev/null
+++ b/gnu/lib/libreadline/rltty.c
@@ -0,0 +1,693 @@
+/* rltty.c -- functions to prepare and restore the terminal for readline's
+ use. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+/* This is needed to include support for TIOCGWINSZ and window resizing. */
+#if defined (OSF1) || defined (BSD386) || defined (NetBSD) || \
+ defined (FreeBSD) || defined (_386BSD) || defined (AIX)
+# include <sys/ioctl.h>
+#endif /* OSF1 || BSD386 */
+
+#include "rldefs.h"
+#include <readline/readline.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int readline_echoing_p;
+extern int _rl_eof_char;
+
+#if defined (__GO32__)
+# include <sys/pc.h>
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+/* **************************************************************** */
+/* */
+/* Signal Management */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_POSIX_SIGNALS)
+static sigset_t sigint_set, sigint_oset;
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+static int sigint_oldmask;
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+static int sigint_blocked = 0;
+
+/* Cause SIGINT to not be delivered until the corresponding call to
+ release_sigint(). */
+static void
+block_sigint ()
+{
+ if (sigint_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&sigint_set);
+ sigemptyset (&sigint_oset);
+ sigaddset (&sigint_set, SIGINT);
+ sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigint_oldmask = sigblock (sigmask (SIGINT));
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sighold (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+ sigint_blocked = 1;
+}
+
+/* Allow SIGINT to be delivered. */
+static void
+release_sigint ()
+{
+ if (!sigint_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
+#else
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (sigint_oldmask);
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sigrelse (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigint_blocked = 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Controlling the Meta Key and Keypad */
+/* */
+/* **************************************************************** */
+
+extern int term_has_meta;
+extern char *term_mm;
+extern char *term_mo;
+
+extern char *term_ks;
+extern char *term_ke;
+static int
+outchar (c)
+ int c;
+{
+ return putc (c, rl_outstream);
+}
+
+/* Turn on/off the meta key depending on ON. */
+static void
+control_meta_key (on)
+ int on;
+{
+ if (term_has_meta)
+ {
+ if (on && term_mm)
+ tputs (term_mm, 1, outchar);
+ else if (!on && term_mo)
+ tputs (term_mo, 1, outchar);
+ }
+}
+
+static void
+control_keypad (on)
+ int on;
+{
+ if (on && term_ks)
+ tputs (term_ks, 1, outchar);
+ else if (!on && term_ke)
+ tputs (term_ke, 1, outchar);
+}
+
+/* **************************************************************** */
+/* */
+/* Saving and Restoring the TTY */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means that the terminal is in a prepped state. */
+static int terminal_prepped = 0;
+
+/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
+ and output is suspended. */
+#if defined (__ksr1__)
+static int ksrflow = 0;
+#endif
+#if defined (NEW_TTY_DRIVER)
+
+/* Values for the `flags' field of a struct bsdtty. This tells which
+ elements of the struct bsdtty have been fetched from the system and
+ are valid. */
+#define SGTTY_SET 0x01
+#define LFLAG_SET 0x02
+#define TCHARS_SET 0x04
+#define LTCHARS_SET 0x08
+
+struct bsdtty {
+ struct sgttyb sgttyb; /* Basic BSD tty driver information. */
+ int lflag; /* Local mode flags, like LPASS8. */
+#if defined (TIOCGETC)
+ struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */
+#endif
+#if defined (TIOCGLTC)
+ struct ltchars ltchars; /* 4.2 BSD editing characters */
+#endif
+ int flags; /* Bitmap saying which parts of the struct are valid. */
+};
+
+#define TIOTYPE struct bsdtty
+
+static TIOTYPE otio;
+
+static int
+get_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ tiop->flags = tiop->lflag = 0;
+
+ ioctl (tty, TIOCGETP, &(tiop->sgttyb));
+ tiop->flags |= SGTTY_SET;
+
+#if defined (TIOCLGET)
+ ioctl (tty, TIOCLGET, &(tiop->lflag));
+ tiop->flags |= LFLAG_SET;
+#endif
+
+#if defined (TIOCGETC)
+ ioctl (tty, TIOCGETC, &(tiop->tchars));
+ tiop->flags |= TCHARS_SET;
+#endif
+
+#if defined (TIOCGLTC)
+ ioctl (tty, TIOCGLTC, &(tiop->ltchars));
+ tiop->flags |= LTCHARS_SET;
+#endif
+
+ return 0;
+}
+
+set_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ if (tiop->flags & SGTTY_SET)
+ {
+ ioctl (tty, TIOCSETN, &(tiop->sgttyb));
+ tiop->flags &= ~SGTTY_SET;
+ }
+ readline_echoing_p = 1;
+
+#if defined (TIOCLSET)
+ if (tiop->flags & LFLAG_SET)
+ {
+ ioctl (tty, TIOCLSET, &(tiop->lflag));
+ tiop->flags &= ~LFLAG_SET;
+ }
+#endif
+
+#if defined (TIOCSETC)
+ if (tiop->flags & TCHARS_SET)
+ {
+ ioctl (tty, TIOCSETC, &(tiop->tchars));
+ tiop->flags &= ~TCHARS_SET;
+ }
+#endif
+
+#if defined (TIOCSLTC)
+ if (tiop->flags & LTCHARS_SET)
+ {
+ ioctl (tty, TIOCSLTC, &(tiop->ltchars));
+ tiop->flags &= ~LTCHARS_SET;
+ }
+#endif
+
+ return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, otio, tiop)
+ int meta_flag;
+ TIOTYPE otio, *tiop;
+{
+#if !defined (__GO32__)
+ readline_echoing_p = (otio.sgttyb.sg_flags & ECHO);
+
+ /* Copy the original settings to the structure we're going to use for
+ our settings. */
+ tiop->sgttyb = otio.sgttyb;
+ tiop->lflag = otio.lflag;
+#if defined (TIOCGETC)
+ tiop->tchars = otio.tchars;
+#endif
+#if defined (TIOCGLTC)
+ tiop->ltchars = otio.ltchars;
+#endif
+ tiop->flags = otio.flags;
+
+ /* First, the basic settings to put us into character-at-a-time, no-echo
+ input mode. */
+ tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
+ tiop->sgttyb.sg_flags |= CBREAK;
+
+ /* If this terminal doesn't care how the 8th bit is used, then we can
+ use it for the meta-key. If only one of even or odd parity is
+ specified, then the terminal is using parity, and we cannot. */
+#if !defined (ANYP)
+# define ANYP (EVENP | ODDP)
+#endif
+ if (((otio.sgttyb.sg_flags & ANYP) == ANYP) ||
+ ((otio.sgttyb.sg_flags & ANYP) == 0))
+ {
+ tiop->sgttyb.sg_flags |= ANYP;
+
+ /* Hack on local mode flags if we can. */
+#if defined (TIOCLGET)
+# if defined (LPASS8)
+ tiop->lflag |= LPASS8;
+# endif /* LPASS8 */
+#endif /* TIOCLGET */
+ }
+
+#if defined (TIOCGETC)
+# if defined (USE_XON_XOFF)
+ /* Get rid of terminal output start and stop characters. */
+ tiop->tchars.t_stopc = -1; /* C-s */
+ tiop->tchars.t_startc = -1; /* C-q */
+
+ /* If there is an XON character, bind it to restart the output. */
+ if (otio.tchars.t_startc != -1)
+ rl_bind_key (otio.tchars.t_startc, rl_restart_output);
+# endif /* USE_XON_XOFF */
+
+ /* If there is an EOF char, bind _rl_eof_char to it. */
+ if (otio.tchars.t_eofc != -1)
+ _rl_eof_char = otio.tchars.t_eofc;
+
+# if defined (NO_KILL_INTR)
+ /* Get rid of terminal-generated SIGQUIT and SIGINT. */
+ tiop->tchars.t_quitc = -1; /* C-\ */
+ tiop->tchars.t_intrc = -1; /* C-c */
+# endif /* NO_KILL_INTR */
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+ /* Make the interrupt keys go away. Just enough to make people happy. */
+ tiop->ltchars.t_dsuspc = -1; /* C-y */
+ tiop->ltchars.t_lnextc = -1; /* C-v */
+#endif /* TIOCGLTC */
+#endif /* !__GO32__ */
+}
+
+#else /* !defined (NEW_TTY_DRIVER) */
+
+#if !defined (VMIN)
+# define VMIN VEOF
+#endif
+
+#if !defined (VTIME)
+# define VTIME VEOL
+#endif
+
+#if defined (TERMIOS_TTY_DRIVER)
+# define TIOTYPE struct termios
+# define DRAIN_OUTPUT(fd) tcdrain (fd)
+# define GETATTR(tty, tiop) (tcgetattr (tty, tiop))
+# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop))
+#else
+# define TIOTYPE struct termio
+# define DRAIN_OUTPUT(fd)
+# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop))
+# define SETATTR(tty, tiop) (ioctl (tty, TCSETA, tiop))
+#endif /* !TERMIOS_TTY_DRIVER */
+
+static TIOTYPE otio;
+
+static int
+get_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+#ifdef TIOCGWINSZ
+/* XXX this prevents to got editing mode from tcsh. Ache */
+ struct winsize w;
+
+ if (ioctl (tty, TIOCGWINSZ, &w) == 0)
+ (void) ioctl (tty, TIOCSWINSZ, &w);
+#endif
+
+ while (GETATTR (tty, tiop) < 0)
+ {
+ if (errno != EINTR)
+ return -1;
+ errno = 0;
+ }
+ return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ while (SETATTR (tty, tiop) < 0)
+ {
+ if (errno != EINTR)
+ return -1;
+ errno = 0;
+ }
+
+#if 0
+
+#if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ if (ksrflow)
+ {
+ ksrflow = 0;
+ tcflow (tty, TCOON);
+ }
+# else /* !ksr1 */
+ tcflow (tty, TCOON); /* Simulate a ^Q. */
+# endif /* !ksr1 */
+#else
+ ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
+#endif /* !TERMIOS_TTY_DRIVER */
+
+#endif
+
+ return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, otio, tiop)
+ int meta_flag;
+ TIOTYPE otio, *tiop;
+{
+ readline_echoing_p = (otio.c_lflag & ECHO);
+
+ tiop->c_lflag &= ~(ICANON | ECHO);
+
+ if ((unsigned char) otio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
+ _rl_eof_char = otio.c_cc[VEOF];
+
+#if defined (USE_XON_XOFF)
+#if defined (IXANY)
+ tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
+#else
+ /* `strict' Posix systems do not define IXANY. */
+ tiop->c_iflag &= ~(IXON | IXOFF);
+#endif /* IXANY */
+#endif /* USE_XON_XOFF */
+
+ /* Only turn this off if we are using all 8 bits. */
+ if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
+ tiop->c_iflag &= ~(ISTRIP | INPCK);
+
+ /* Make sure we differentiate between CR and NL on input. */
+ tiop->c_iflag &= ~(ICRNL | INLCR);
+
+#if !defined (HANDLE_SIGNALS)
+ tiop->c_lflag &= ~ISIG;
+#else
+ tiop->c_lflag |= ISIG;
+#endif
+
+ tiop->c_cc[VMIN] = 1;
+ tiop->c_cc[VTIME] = 0;
+
+ /* Turn off characters that we need on Posix systems with job control,
+ just to be sure. This includes ^Y and ^V. This should not really
+ be necessary. */
+#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
+
+#if defined (VLNEXT)
+ tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
+#endif
+
+#if defined (VDSUSP)
+ tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
+#endif
+
+#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
+}
+#endif /* NEW_TTY_DRIVER */
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+void
+rl_prep_terminal (meta_flag)
+ int meta_flag;
+{
+#if !defined (__GO32__)
+ int tty = fileno (rl_instream);
+ TIOTYPE tio;
+
+ if (terminal_prepped)
+ return;
+
+ /* Try to keep this function from being INTerrupted. */
+ block_sigint ();
+
+ if (get_tty_settings (tty, &tio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ otio = tio;
+
+ prepare_terminal_settings (meta_flag, otio, &tio);
+
+ if (set_tty_settings (tty, &tio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ control_meta_key (1);
+ control_keypad (1);
+ terminal_prepped = 1;
+
+ release_sigint ();
+#endif /* !__GO32__ */
+}
+
+/* Restore the terminal's normal settings and modes. */
+void
+rl_deprep_terminal ()
+{
+#if !defined (__GO32__)
+ int tty = fileno (rl_instream);
+
+ if (!terminal_prepped)
+ return;
+
+ /* Try to keep this function from being INTerrupted. */
+ block_sigint ();
+
+ if (set_tty_settings (tty, &otio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ control_meta_key (0);
+ control_keypad (0);
+ terminal_prepped = 0;
+
+ release_sigint ();
+#endif /* !__GO32__ */
+}
+
+/* **************************************************************** */
+/* */
+/* Bogus Flow Control */
+/* */
+/* **************************************************************** */
+
+rl_restart_output (count, key)
+ int count, key;
+{
+ int fildes = fileno (rl_outstream);
+#if defined (TIOCSTART)
+#if defined (apollo)
+ ioctl (&fildes, TIOCSTART, 0);
+#else
+ ioctl (fildes, TIOCSTART, 0);
+#endif /* apollo */
+
+#else /* !TIOCSTART */
+# if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ if (ksrflow)
+ {
+ ksrflow = 0;
+ tcflow (fildes, TCOON);
+ }
+# else /* !ksr1 */
+ tcflow (fildes, TCOON); /* Simulate a ^Q. */
+# endif /* !ksr1 */
+# else /* !TERMIOS_TTY_DRIVER */
+# if defined (TCXONC)
+ ioctl (fildes, TCXONC, TCOON);
+# endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTART */
+
+ return 0;
+}
+
+rl_stop_output (count, key)
+ int count, key;
+{
+ int fildes = fileno (rl_instream);
+
+#if defined (TIOCSTOP)
+# if defined (apollo)
+ ioctl (&fildes, TIOCSTOP, 0);
+# else
+ ioctl (fildes, TIOCSTOP, 0);
+# endif /* apollo */
+#else /* !TIOCSTOP */
+# if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ ksrflow = 1;
+# endif /* ksr1 */
+ tcflow (fildes, TCOOFF);
+# else
+# if defined (TCXONC)
+ ioctl (fildes, TCXONC, TCOON);
+# endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTOP */
+
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Default Key Bindings */
+/* */
+/* **************************************************************** */
+void
+rltty_set_default_bindings (kmap)
+ Keymap kmap;
+{
+ TIOTYPE ttybuff;
+ int tty = fileno (rl_instream);
+
+#if defined (NEW_TTY_DRIVER)
+
+ if (get_tty_settings (tty, &ttybuff) == 0)
+ {
+ if (ttybuff.flags & SGTTY_SET)
+ {
+ int erase, kill;
+
+ erase = ttybuff.sgttyb.sg_erase;
+ kill = ttybuff.sgttyb.sg_kill;
+
+ if (erase != -1 && kmap[erase].type == ISFUNC)
+ kmap[erase].function = rl_rubout;
+
+ if (kill != -1 && kmap[kill].type == ISFUNC)
+ kmap[kill].function = rl_unix_line_discard;
+ }
+
+# if defined (TIOCGLTC)
+
+ if (ttybuff.flags & LTCHARS_SET)
+ {
+ int werase, nextc;
+
+ werase = ttybuff.ltchars.t_werasc;
+ nextc = ttybuff.ltchars.t_lnextc;
+
+ if (werase != -1 && kmap[werase].type == ISFUNC)
+ kmap[werase].function = rl_unix_word_rubout;
+
+ if (nextc != -1 && kmap[nextc].type == ISFUNC)
+ kmap[nextc].function = rl_quoted_insert;
+ }
+ }
+# endif /* TIOCGLTC */
+
+#else /* !NEW_TTY_DRIVER */
+
+ if (get_tty_settings (tty, &ttybuff) == 0)
+ {
+ unsigned char erase, kill;
+
+ erase = ttybuff.c_cc[VERASE];
+ kill = ttybuff.c_cc[VKILL];
+
+ if (erase != (unsigned char)_POSIX_VDISABLE &&
+ kmap[erase].type == ISFUNC)
+ kmap[erase].function = rl_rubout;
+
+ if (kill != (unsigned char)_POSIX_VDISABLE &&
+ kmap[kill].type == ISFUNC)
+ kmap[kill].function = rl_unix_line_discard;
+
+# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+ {
+ unsigned char nextc;
+
+ nextc = ttybuff.c_cc[VLNEXT];
+
+ if (nextc != (unsigned char)_POSIX_VDISABLE &&
+ kmap[nextc].type == ISFUNC)
+ kmap[nextc].function = rl_quoted_insert;
+ }
+# endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+ {
+ unsigned char werase;
+
+ werase = ttybuff.c_cc[VWERASE];
+
+ if (werase != (unsigned char)_POSIX_VDISABLE &&
+ kmap[werase].type == ISFUNC)
+ kmap[werase].function = rl_unix_word_rubout;
+ }
+# endif /* VWERASE && TERMIOS_TTY_DRIVER */
+ }
+#endif /* !NEW_TTY_DRIVER */
+}
diff --git a/gnu/lib/libreadline/search.c b/gnu/lib/libreadline/search.c
new file mode 100644
index 000000000000..e3b8bb9f76e4
--- /dev/null
+++ b/gnu/lib/libreadline/search.c
@@ -0,0 +1,360 @@
+/* search.c - code for non-incremental searching in emacs and vi modes. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file is part of the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The 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 1, or (at your option)
+ any later version.
+
+ The 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#include "memalloc.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+
+#define abs(x) (((x) > 0) ? (x) : -(x))
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables imported from readline.c */
+extern int rl_point, rl_end, rl_line_buffer_len;
+extern Keymap _rl_keymap;
+extern char *rl_prompt;
+extern char *rl_line_buffer;
+extern HIST_ENTRY *saved_line_for_history;
+extern Function *rl_last_func;
+
+/* Functions imported from the rest of the library. */
+extern int _rl_free_history_entry ();
+
+static char *noninc_search_string = (char *) NULL;
+static int noninc_history_pos = 0;
+static char *prev_line_found = (char *) NULL;
+
+/* Search the history list for STRING starting at absolute history position
+ POS. If STRING begins with `^', the search must match STRING at the
+ beginning of a history line, otherwise a full substring match is performed
+ for STRING. DIR < 0 means to search backwards through the history list,
+ DIR >= 0 means to search forward. */
+static int
+noninc_search_from_pos (string, pos, dir)
+ char *string;
+ int pos, dir;
+{
+ int ret, old;
+
+ old = where_history ();
+ history_set_pos (pos);
+
+ if (*string == '^')
+ ret = history_search_prefix (string + 1, dir);
+ else
+ ret = history_search (string, dir);
+
+ if (ret != -1)
+ ret = where_history ();
+
+ history_set_pos (old);
+ return (ret);
+}
+
+/* Search for a line in the history containing STRING. If DIR is < 0, the
+ search is backwards through previous entries, else through subsequent
+ entries. */
+static void
+noninc_dosearch (string, dir)
+ char *string;
+ int dir;
+{
+ int oldpos, pos;
+ HIST_ENTRY *entry;
+
+ if (string == 0 || *string == 0 || noninc_history_pos < 0)
+ {
+ ding ();
+ return;
+ }
+
+ pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
+ if (pos == -1)
+ {
+ /* Search failed, current history position unchanged. */
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = 0;
+ ding ();
+ return;
+ }
+
+ noninc_history_pos = pos;
+
+ oldpos = where_history ();
+ history_set_pos (noninc_history_pos);
+ entry = current_history ();
+ history_set_pos (oldpos);
+
+ {
+ int line_len;
+
+ line_len = strlen (entry->line);
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+ strcpy (rl_line_buffer, entry->line);
+ }
+
+ rl_undo_list = (UNDO_LIST *)entry->data;
+ rl_end = strlen (rl_line_buffer);
+ rl_point = 0;
+ rl_clear_message ();
+
+ if (saved_line_for_history)
+ _rl_free_history_entry (saved_line_for_history);
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Search non-interactively through the history list. DIR < 0 means to
+ search backwards through the history of previous commands; otherwise
+ the search is for commands subsequent to the current position in the
+ history list. PCHAR is the character to use for prompting when reading
+ the search string; if not specified (0), it defaults to `:'. */
+static void
+noninc_search (dir, pchar)
+ int dir;
+ int pchar;
+{
+ int saved_point, c, pmtlen;
+ char *p;
+
+ maybe_save_line ();
+ saved_point = rl_point;
+
+ /* Use the line buffer to read the search string. */
+ rl_line_buffer[0] = 0;
+ rl_end = rl_point = 0;
+
+ /* XXX - this needs fixing to work with the prompt expansion stuff - XXX */
+ pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
+ p = xmalloc (2 + pmtlen);
+ if (pmtlen)
+ strcpy (p, rl_prompt);
+ p[pmtlen] = pchar ? pchar : ':';
+ p[pmtlen + 1] = '\0';
+
+ rl_message (p, 0, 0);
+ free (p);
+
+ /* Read the search string. */
+ while (c = rl_read_key ())
+ {
+ switch (c)
+ {
+ case CTRL('H'):
+ case RUBOUT:
+ if (rl_point == 0)
+ {
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = saved_point;
+ return;
+ }
+ rl_rubout (1);
+ break;
+
+ case CTRL('W'):
+ rl_unix_word_rubout ();
+ break;
+
+ case CTRL('U'):
+ rl_unix_line_discard ();
+ break;
+
+ case RETURN:
+ case NEWLINE:
+ goto dosearch;
+ /* NOTREACHED */
+ break;
+
+ case CTRL('C'):
+ case CTRL('G'):
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = saved_point;
+ ding ();
+ return;
+
+ default:
+ rl_insert (1, c);
+ break;
+ }
+ rl_redisplay ();
+ }
+
+ dosearch:
+ /* If rl_point == 0, we want to re-use the previous search string and
+ start from the saved history position. If there's no previous search
+ string, punt. */
+ if (rl_point == 0)
+ {
+ if (!noninc_search_string)
+ {
+ ding ();
+ return;
+ }
+ }
+ else
+ {
+ /* We want to start the search from the current history position. */
+ noninc_history_pos = where_history ();
+ if (noninc_search_string)
+ free (noninc_search_string);
+ noninc_search_string = savestring (rl_line_buffer);
+ }
+
+ noninc_dosearch (noninc_search_string, dir);
+}
+
+/* Search forward through the history list for a string. If the vi-mode
+ code calls this, KEY will be `?'. */
+rl_noninc_forward_search (count, key)
+ int count, key;
+{
+ if (key == '?')
+ noninc_search (1, '?');
+ else
+ noninc_search (1, 0);
+ return 0;
+}
+
+/* Reverse search the history list for a string. If the vi-mode code
+ calls this, KEY will be `/'. */
+rl_noninc_reverse_search (count, key)
+ int count, key;
+{
+ if (key == '/')
+ noninc_search (-1, '/');
+ else
+ noninc_search (-1, 0);
+ return 0;
+}
+
+/* Search forward through the history list for the last string searched
+ for. If there is no saved search string, abort. */
+rl_noninc_forward_search_again (count, key)
+ int count, key;
+{
+ if (!noninc_search_string)
+ {
+ ding ();
+ return (-1);
+ }
+ noninc_dosearch (noninc_search_string, 1);
+ return 0;
+}
+
+/* Reverse search in the history list for the last string searched
+ for. If there is no saved search string, abort. */
+rl_noninc_reverse_search_again (count, key)
+ int count, key;
+{
+ if (!noninc_search_string)
+ {
+ ding ();
+ return (-1);
+ }
+ noninc_dosearch (noninc_search_string, -1);
+ return 0;
+}
+
+static int
+rl_history_search_internal (count, direction)
+ int count, direction;
+{
+ HIST_ENTRY *temp, *old_temp;
+ int line_len;
+
+ maybe_save_line ();
+
+ temp = old_temp = (HIST_ENTRY *)NULL;
+ while (count)
+ {
+ temp = (direction < 0) ? previous_history () : next_history ();
+ if (!temp)
+ break;
+ if (STREQN (rl_line_buffer, temp->line, rl_point))
+ {
+ /* Don't find multiple instances of the same line. */
+ if (prev_line_found && STREQ (prev_line_found, temp->line))
+ continue;
+ if (direction < 0)
+ old_temp = temp;
+ prev_line_found = temp->line;
+ count--;
+ }
+ }
+
+ if (!temp)
+ {
+ if (direction < 0 && old_temp)
+ temp = old_temp;
+ else
+ {
+ maybe_unsave_line ();
+ ding ();
+ return 1;
+ }
+ }
+
+ line_len = strlen (temp->line);
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+ strcpy (rl_line_buffer, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = line_len;
+ return 0;
+}
+
+/* Search forward in the history for the string of characters
+ from the start of the line to rl_point. This is a non-incremental
+ search. */
+int
+rl_history_search_forward (count, ignore)
+ int count, ignore;
+{
+ if (count == 0)
+ return (0);
+ if (rl_last_func != rl_history_search_forward)
+ prev_line_found = (char *)NULL;
+ return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
+}
+
+/* Search backward through the history for the string of characters
+ from the start of the line to rl_point. This is a non-incremental
+ search. */
+int
+rl_history_search_backward (count, ignore)
+ int count, ignore;
+{
+ if (count == 0)
+ return (0);
+ if (rl_last_func != rl_history_search_backward)
+ prev_line_found = (char *)NULL;
+ return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
+}
diff --git a/gnu/lib/libreadline/signals.c b/gnu/lib/libreadline/signals.c
new file mode 100644
index 000000000000..f57c07ca1243
--- /dev/null
+++ b/gnu/lib/libreadline/signals.c
@@ -0,0 +1,303 @@
+/* signals.c -- signal handling support for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+# include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+#include <signal.h>
+
+/* This is needed to include support for TIOCGWINSZ and window resizing. */
+#if defined (OSF1) || defined (BSD386) || defined (_386BSD) || defined (__BSD_4_4__) || defined (AIX)
+# include <sys/ioctl.h>
+#endif /* OSF1 || BSD386 || _386BSD || __BSD_4_4__ || AIX */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static void cr ();
+
+extern int readline_echoing_p;
+extern int rl_pending_input;
+extern char *term_cr;
+
+extern int _rl_meta_flag;
+
+extern int _rl_output_character_function ();
+
+extern void free_undo_list ();
+
+#if defined (VOID_SIGHANDLER)
+# define sighandler void
+#else
+# define sighandler int
+#endif /* VOID_SIGHANDLER */
+
+/* This typedef is equivalant to the one for Function; it allows us
+ to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef sighandler SigHandler ();
+
+#if defined (__GO32__)
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+
+/* **************************************************************** */
+/* */
+/* Signal Handling */
+/* */
+/* **************************************************************** */
+
+#if defined (SIGWINCH)
+static SigHandler *old_sigwinch = (SigHandler *)NULL;
+
+static sighandler
+rl_handle_sigwinch (sig)
+ int sig;
+{
+ if (readline_echoing_p)
+ {
+ _rl_set_screen_size (fileno (rl_instream), 1);
+
+ cr (); /* was crlf () */
+ rl_forced_update_display ();
+ }
+
+ if (old_sigwinch &&
+ old_sigwinch != (SigHandler *)SIG_IGN &&
+ old_sigwinch != (SigHandler *)SIG_DFL)
+ (*old_sigwinch) (sig);
+#if !defined (VOID_SIGHANDLER)
+ return (0);
+#endif /* VOID_SIGHANDLER */
+}
+#endif /* SIGWINCH */
+
+#if defined (HANDLE_SIGNALS)
+/* Interrupt handling. */
+static SigHandler
+ *old_int = (SigHandler *)NULL,
+ *old_alrm = (SigHandler *)NULL;
+#if !defined (SHELL)
+static SigHandler
+ *old_tstp = (SigHandler *)NULL,
+ *old_ttou = (SigHandler *)NULL,
+ *old_ttin = (SigHandler *)NULL,
+ *old_cont = (SigHandler *)NULL;
+#endif /* !SHELL */
+
+/* Handle an interrupt character. */
+static sighandler
+rl_signal_handler (sig)
+ int sig;
+{
+#if defined (HAVE_POSIX_SIGNALS)
+ sigset_t set;
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ long omask;
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
+ /* Since the signal will not be blocked while we are in the signal
+ handler, ignore it until rl_clear_signals resets the catcher. */
+ if (sig == SIGINT)
+ signal (sig, SIG_IGN);
+#endif /* !HAVE_BSD_SIGNALS */
+
+ switch (sig)
+ {
+ case SIGINT:
+ {
+ register HIST_ENTRY *entry;
+
+ free_undo_list ();
+
+ entry = current_history ();
+ if (entry)
+ entry->data = (char *)NULL;
+ }
+ _rl_kill_kbd_macro ();
+ rl_clear_message ();
+ rl_init_argument ();
+
+#if defined (SIGTSTP)
+ case SIGTSTP:
+ case SIGTTOU:
+ case SIGTTIN:
+#endif /* SIGTSTP */
+ case SIGALRM:
+ rl_clean_up_for_exit ();
+ rl_deprep_terminal ();
+ rl_clear_signals ();
+ rl_pending_input = 0;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
+ sigdelset (&set, sig);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ omask = sigblock (0);
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ kill (getpid (), sig);
+
+ /* Let the signal that we just sent through. */
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (omask & ~(sigmask (sig)));
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ rl_prep_terminal (_rl_meta_flag);
+ rl_set_signals ();
+ }
+
+#if !defined (VOID_SIGHANDLER)
+ return (0);
+#endif /* !VOID_SIGHANDLER */
+}
+
+#if defined (HAVE_POSIX_SIGNALS)
+static SigHandler *
+rl_set_sighandler (sig, handler)
+ int sig;
+ SigHandler *handler;
+{
+ struct sigaction act, oact;
+
+ act.sa_handler = handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigemptyset (&oact.sa_mask);
+ sigaction (sig, &act, &oact);
+ return (oact.sa_handler);
+}
+
+#else /* !HAVE_POSIX_SIGNALS */
+# define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler)
+#endif /* !HAVE_POSIX_SIGNALS */
+
+rl_set_signals ()
+{
+ old_int = (SigHandler *)rl_set_sighandler (SIGINT, rl_signal_handler);
+ if (old_int == (SigHandler *)SIG_IGN)
+ signal (SIGINT, SIG_IGN);
+
+ old_alrm = (SigHandler *)rl_set_sighandler (SIGALRM, rl_signal_handler);
+ if (old_alrm == (SigHandler *)SIG_IGN)
+ signal (SIGALRM, SIG_IGN);
+
+#if !defined (SHELL)
+
+#if defined (SIGTSTP)
+ old_tstp = (SigHandler *)rl_set_sighandler (SIGTSTP, rl_signal_handler);
+ if (old_tstp == (SigHandler *)SIG_IGN)
+ signal (SIGTSTP, SIG_IGN);
+#endif /* SIGTSTP */
+#if defined (SIGTTOU)
+ old_ttou = (SigHandler *)rl_set_sighandler (SIGTTOU, rl_signal_handler);
+ old_ttin = (SigHandler *)rl_set_sighandler (SIGTTIN, rl_signal_handler);
+
+ if (old_tstp == (SigHandler *)SIG_IGN)
+ {
+ signal (SIGTTOU, SIG_IGN);
+ signal (SIGTTIN, SIG_IGN);
+ }
+#endif /* SIGTTOU */
+
+#endif /* !SHELL */
+
+#if defined (SIGWINCH)
+ old_sigwinch =
+ (SigHandler *) rl_set_sighandler (SIGWINCH, rl_handle_sigwinch);
+#endif /* SIGWINCH */
+ return 0;
+}
+
+rl_clear_signals ()
+{
+ rl_set_sighandler (SIGINT, old_int);
+ rl_set_sighandler (SIGALRM, old_alrm);
+
+#if !defined (SHELL)
+
+#if defined (SIGTSTP)
+ signal (SIGTSTP, old_tstp);
+#endif
+
+#if defined (SIGTTOU)
+ signal (SIGTTOU, old_ttou);
+ signal (SIGTTIN, old_ttin);
+#endif /* SIGTTOU */
+
+#endif /* !SHELL */
+
+#if defined (SIGWINCH)
+ signal (SIGWINCH, old_sigwinch);
+#endif
+
+ return 0;
+}
+
+/* Move to the start of the current line. */
+static void
+cr ()
+{
+ if (term_cr)
+ tputs (term_cr, 1, _rl_output_character_function);
+}
+#endif /* HANDLE_SIGNALS */
diff --git a/gnu/lib/libreadline/tcsh_hack.readme b/gnu/lib/libreadline/tcsh_hack.readme
new file mode 100644
index 000000000000..6fd5da173688
--- /dev/null
+++ b/gnu/lib/libreadline/tcsh_hack.readme
@@ -0,0 +1,27 @@
+*** rltty.c.orig Thu May 12 19:02:50 1994
+--- rltty.c Thu May 12 19:03:06 1994
+***************
+*** 21,26 ****
+--- 21,27 ----
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+ #include <sys/types.h>
++ #include <sys/ioctl.h>
+ #include <signal.h>
+ #include <errno.h>
+ #include <stdio.h>
+***************
+*** 359,364 ****
+--- 360,371 ----
+ int tty;
+ TIOTYPE *tiop;
+ {
++ /* XXX this prevents to got editing mode from tcsh. Ache */
++ struct winsize w;
++
++ if (ioctl (tty, TIOCGWINSZ, &w) == 0)
++ (void) ioctl (tty, TIOCSWINSZ, &w);
++
+ while (GETATTR (tty, tiop) < 0)
+ {
+ if (errno != EINTR)
diff --git a/gnu/lib/libreadline/tilde.c b/gnu/lib/libreadline/tilde.c
new file mode 100644
index 000000000000..8cb4246761e0
--- /dev/null
+++ b/gnu/lib/libreadline/tilde.c
@@ -0,0 +1,386 @@
+/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "memalloc.h"
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <readline/tilde.h>
+#include <pwd.h>
+
+#if defined (USG) && !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwuid (), *getpwnam ();
+#endif /* USG && !defined (HAVE_GETPW_DECLS) */
+
+#if !defined (savestring)
+extern char *xmalloc ();
+# ifndef strcpy
+extern char *strcpy ();
+# endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif /* !savestring */
+
+#if !defined (NULL)
+# if defined (__STDC__)
+# define NULL ((void *) 0)
+# else
+# define NULL 0x0
+# endif /* !__STDC__ */
+#endif /* !NULL */
+
+#if defined (TEST) || defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* TEST || STATIC_MALLOC */
+
+/* The default value of tilde_additional_prefixes. This is set to
+ whitespace preceding a tilde so that simple programs which do not
+ perform any word separation get desired behaviour. */
+static char *default_prefixes[] =
+ { " ~", "\t~", (char *)NULL };
+
+/* The default value of tilde_additional_suffixes. This is set to
+ whitespace or newline so that simple programs which do not
+ perform any word separation get desired behaviour. */
+static char *default_suffixes[] =
+ { " ", "\n", (char *)NULL };
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL;
+
+/* When non-null, this is a NULL terminated array of strings which
+ are duplicates for a tilde prefix. Bash uses this to expand
+ `=~' and `:~'. */
+char **tilde_additional_prefixes = default_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+ the end of a username, instead of just "/". Bash sets this to
+ `:' and `=~'. */
+char **tilde_additional_suffixes = default_suffixes;
+
+/* Find the start of a tilde expansion in STRING, and return the index of
+ the tilde which starts the expansion. Place the length of the text
+ which identified this tilde starter in LEN, excluding the tilde itself. */
+static int
+tilde_find_prefix (string, len)
+ char *string;
+ int *len;
+{
+ register int i, j, string_len;
+ register char **prefixes = tilde_additional_prefixes;
+
+ string_len = strlen (string);
+ *len = 0;
+
+ if (!*string || *string == '~')
+ return (0);
+
+ if (prefixes)
+ {
+ for (i = 0; i < string_len; i++)
+ {
+ for (j = 0; prefixes[j]; j++)
+ {
+ if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
+ {
+ *len = strlen (prefixes[j]) - 1;
+ return (i + *len);
+ }
+ }
+ }
+ }
+ return (string_len);
+}
+
+/* Find the end of a tilde expansion in STRING, and return the index of
+ the character which ends the tilde definition. */
+static int
+tilde_find_suffix (string)
+ char *string;
+{
+ register int i, j, string_len;
+ register char **suffixes = tilde_additional_suffixes;
+
+ string_len = strlen (string);
+
+ for (i = 0; i < string_len; i++)
+ {
+ if (string[i] == '/' || !string[i])
+ break;
+
+ for (j = 0; suffixes && suffixes[j]; j++)
+ {
+ if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
+ return (i);
+ }
+ }
+ return (i);
+}
+
+/* Return a new string which is the result of tilde expanding STRING. */
+char *
+tilde_expand (string)
+ char *string;
+{
+ char *result, *tilde_expand_word ();
+ int result_size, result_index;
+
+ result_size = result_index = 0;
+ result = (char *)NULL;
+
+ /* Scan through STRING expanding tildes as we come to them. */
+ while (1)
+ {
+ register int start, end;
+ char *tilde_word, *expansion;
+ int len;
+
+ /* Make START point to the tilde which starts the expansion. */
+ start = tilde_find_prefix (string, &len);
+
+ /* Copy the skipped text into the result. */
+ if ((result_index + start + 1) > result_size)
+ result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
+
+ strncpy (result + result_index, string, start);
+ result_index += start;
+
+ /* Advance STRING to the starting tilde. */
+ string += start;
+
+ /* Make END be the index of one after the last character of the
+ username. */
+ end = tilde_find_suffix (string);
+
+ /* If both START and END are zero, we are all done. */
+ if (!start && !end)
+ break;
+
+ /* Expand the entire tilde word, and copy it into RESULT. */
+ tilde_word = (char *)xmalloc (1 + end);
+ strncpy (tilde_word, string, end);
+ tilde_word[end] = '\0';
+ string += end;
+
+ expansion = tilde_expand_word (tilde_word);
+ free (tilde_word);
+
+ len = strlen (expansion);
+ if ((result_index + len + 1) > result_size)
+ result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
+
+ strcpy (result + result_index, expansion);
+ result_index += len;
+ free (expansion);
+ }
+
+ result[result_index] = '\0';
+
+ return (result);
+}
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook. */
+char *
+tilde_expand_word (filename)
+ char *filename;
+{
+ char *dirname;
+
+ dirname = filename ? savestring (filename) : (char *)NULL;
+
+ if (dirname && *dirname == '~')
+ {
+ char *temp_name;
+ if (!dirname[1] || dirname[1] == '/')
+ {
+ /* Prepend $HOME to the rest of the string. */
+ char *temp_home = (char *)getenv ("HOME");
+
+ /* If there is no HOME variable, look up the directory in
+ the password database. */
+ if (!temp_home)
+ {
+ struct passwd *entry;
+
+ entry = getpwuid (getuid ());
+ if (entry)
+ temp_home = entry->pw_dir;
+ }
+
+ temp_name = xmalloc (1 + strlen (&dirname[1])
+ + (temp_home ? strlen (temp_home) : 0));
+ temp_name[0] = '\0';
+ if (temp_home)
+ strcpy (temp_name, temp_home);
+ strcat (temp_name, dirname + 1);
+ free (dirname);
+ dirname = temp_name;
+ }
+ else
+ {
+ char u_name[257];
+ struct passwd *user_entry;
+ char *username;
+ int i, c;
+
+ username = u_name;
+ for (i = 1; c = dirname[i]; i++)
+ {
+ if (c == '/')
+ break;
+ else
+ username[i - 1] = c;
+ }
+ username[i - 1] = '\0';
+
+ if (!(user_entry = getpwnam (username)))
+ {
+ /* If the calling program has a special syntax for
+ expanding tildes, and we couldn't find a standard
+ expansion, then let them try. */
+ if (tilde_expansion_failure_hook)
+ {
+ char *expansion;
+
+ expansion = (*tilde_expansion_failure_hook) (username);
+
+ if (expansion)
+ {
+ temp_name = xmalloc (1 + strlen (expansion)
+ + strlen (&dirname[i]));
+ strcpy (temp_name, expansion);
+ strcat (temp_name, &dirname[i]);
+ free (expansion);
+ free (dirname);
+ dirname = temp_name;
+ }
+ }
+ /* We shouldn't report errors. */
+ }
+ else
+ {
+ temp_name = xmalloc (1 + strlen (user_entry->pw_dir)
+ + strlen (&dirname[i]));
+ strcpy (temp_name, user_entry->pw_dir);
+ strcat (temp_name, &dirname[i]);
+ free (dirname);
+ dirname = temp_name;
+ }
+ endpwent ();
+ }
+ }
+ return (dirname);
+}
+
+
+#if defined (TEST)
+#undef NULL
+#include <stdio.h>
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *result, line[512];
+ int done = 0;
+
+ while (!done)
+ {
+ printf ("~expand: ");
+ fflush (stdout);
+
+ if (!gets (line))
+ strcpy (line, "done");
+
+ if ((strcmp (line, "done") == 0) ||
+ (strcmp (line, "quit") == 0) ||
+ (strcmp (line, "exit") == 0))
+ {
+ done = 1;
+ break;
+ }
+
+ result = tilde_expand (line);
+ printf (" --> %s\n", result);
+ free (result);
+ }
+ exit (0);
+}
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -DTEST -o tilde tilde.c"
+ * end:
+ */
+#endif /* TEST */
diff --git a/gnu/lib/libreadline/vi_keymap.c b/gnu/lib/libreadline/vi_keymap.c
new file mode 100644
index 000000000000..c360489fb769
--- /dev/null
+++ b/gnu/lib/libreadline/vi_keymap.c
@@ -0,0 +1,877 @@
+/* vi_keymap.c -- the keymap for vi_mode in readline (). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* !BUFSIZ */
+
+#include <readline/readline.h>
+
+#if 0
+extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
+#endif
+
+/* The keymap arrays for handling vi mode. */
+KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_emacs_editing_mode }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_backward }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISFUNC, rl_abort }, /* Control-[ */ /* vi_escape_keymap */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_forward }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, rl_vi_comment }, /* # */
+ { ISFUNC, rl_end_of_line }, /* $ */
+ { ISFUNC, rl_vi_match }, /* % */
+ { ISFUNC, rl_vi_tilde_expand }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, rl_vi_complete }, /* * */
+ { ISFUNC, rl_get_next_history}, /* + */
+ { ISFUNC, rl_vi_char_search }, /* , */
+ { ISFUNC, rl_get_previous_history }, /* - */
+ { ISFUNC, rl_vi_redo }, /* . */
+ { ISFUNC, rl_vi_search }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_beg_of_line }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, rl_vi_char_search }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, rl_vi_complete }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, rl_vi_search }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_vi_append_eol }, /* A */
+ { ISFUNC, rl_vi_prev_word}, /* B */
+ { ISFUNC, rl_vi_change_to }, /* C */
+ { ISFUNC, rl_vi_delete_to }, /* D */
+ { ISFUNC, rl_vi_end_word }, /* E */
+ { ISFUNC, rl_vi_char_search }, /* F */
+ { ISFUNC, rl_vi_fetch_history }, /* G */
+ { ISFUNC, (Function *)0x0 }, /* H */
+ { ISFUNC, rl_vi_insert_beg }, /* I */
+ { ISFUNC, (Function *)0x0 }, /* J */
+ { ISFUNC, (Function *)0x0 }, /* K */
+ { ISFUNC, (Function *)0x0 }, /* L */
+ { ISFUNC, (Function *)0x0 }, /* M */
+ { ISFUNC, rl_vi_search_again }, /* N */
+ { ISFUNC, (Function *)0x0 }, /* O */
+ { ISFUNC, rl_vi_put }, /* P */
+ { ISFUNC, (Function *)0x0 }, /* Q */
+ { ISFUNC, rl_vi_replace }, /* R */
+ { ISFUNC, rl_vi_subst }, /* S */
+ { ISFUNC, rl_vi_char_search }, /* T */
+ { ISFUNC, rl_revert_line }, /* U */
+ { ISFUNC, (Function *)0x0 }, /* V */
+ { ISFUNC, rl_vi_next_word }, /* W */
+ { ISFUNC, rl_rubout }, /* X */
+ { ISFUNC, rl_vi_yank_to }, /* Y */
+ { ISFUNC, (Function *)0x0 }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, rl_vi_complete }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, rl_vi_first_print }, /* ^ */
+ { ISFUNC, rl_vi_yank_arg }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_vi_append_mode }, /* a */
+ { ISFUNC, rl_vi_prev_word }, /* b */
+ { ISFUNC, rl_vi_change_to }, /* c */
+ { ISFUNC, rl_vi_delete_to }, /* d */
+ { ISFUNC, rl_vi_end_word }, /* e */
+ { ISFUNC, rl_vi_char_search }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, rl_backward }, /* h */
+ { ISFUNC, rl_vi_insertion_mode }, /* i */
+ { ISFUNC, rl_get_next_history }, /* j */
+ { ISFUNC, rl_get_previous_history }, /* k */
+ { ISFUNC, rl_forward }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, rl_vi_search_again }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, rl_vi_put }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, rl_vi_change_char }, /* r */
+ { ISFUNC, rl_vi_subst }, /* s */
+ { ISFUNC, rl_vi_char_search }, /* t */
+ { ISFUNC, rl_undo_command }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, rl_vi_next_word }, /* w */
+ { ISFUNC, rl_vi_delete }, /* x */
+ { ISFUNC, rl_vi_yank_to }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, rl_vi_column }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, rl_vi_change_case }, /* ~ */
+ { ISFUNC, (Function *)0x0 }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+
+KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, rl_insert }, /* Control-a */
+ { ISFUNC, rl_insert }, /* Control-b */
+ { ISFUNC, rl_insert }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_insert }, /* Control-e */
+ { ISFUNC, rl_insert }, /* Control-f */
+ { ISFUNC, rl_insert }, /* Control-g */
+ { ISFUNC, rl_rubout }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_insert }, /* Control-k */
+ { ISFUNC, rl_insert }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_insert }, /* Control-n */
+ { ISFUNC, rl_insert }, /* Control-o */
+ { ISFUNC, rl_insert }, /* Control-p */
+ { ISFUNC, rl_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, rl_insert }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, rl_insert }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, rl_insert }, /* Control-\ */
+ { ISFUNC, rl_insert }, /* Control-] */
+ { ISFUNC, rl_insert }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+ { ISFUNC, rl_insert }, /* ) */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+ { ISFUNC, rl_insert }, /* ] */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+ { ISFUNC, rl_insert }, /* } */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Pure 8-bit characters (128 - 159).
+ These might be used in some
+ character sets. */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+
+ /* ISO Latin-1 characters (160 - 255) */
+ { ISFUNC, rl_insert }, /* No-break space */
+ { ISFUNC, rl_insert }, /* Inverted exclamation mark */
+ { ISFUNC, rl_insert }, /* Cent sign */
+ { ISFUNC, rl_insert }, /* Pound sign */
+ { ISFUNC, rl_insert }, /* Currency sign */
+ { ISFUNC, rl_insert }, /* Yen sign */
+ { ISFUNC, rl_insert }, /* Broken bar */
+ { ISFUNC, rl_insert }, /* Section sign */
+ { ISFUNC, rl_insert }, /* Diaeresis */
+ { ISFUNC, rl_insert }, /* Copyright sign */
+ { ISFUNC, rl_insert }, /* Feminine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Not sign */
+ { ISFUNC, rl_insert }, /* Soft hyphen */
+ { ISFUNC, rl_insert }, /* Registered sign */
+ { ISFUNC, rl_insert }, /* Macron */
+ { ISFUNC, rl_insert }, /* Degree sign */
+ { ISFUNC, rl_insert }, /* Plus-minus sign */
+ { ISFUNC, rl_insert }, /* Superscript two */
+ { ISFUNC, rl_insert }, /* Superscript three */
+ { ISFUNC, rl_insert }, /* Acute accent */
+ { ISFUNC, rl_insert }, /* Micro sign */
+ { ISFUNC, rl_insert }, /* Pilcrow sign */
+ { ISFUNC, rl_insert }, /* Middle dot */
+ { ISFUNC, rl_insert }, /* Cedilla */
+ { ISFUNC, rl_insert }, /* Superscript one */
+ { ISFUNC, rl_insert }, /* Masculine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one half */
+ { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */
+ { ISFUNC, rl_insert }, /* Inverted questionk mark */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin capital letter ae */
+ { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Multiplication sign */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */
+ { ISFUNC, rl_insert }, /* Latin small letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin small letter ae */
+ { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin small letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Division sign */
+ { ISFUNC, rl_insert }, /* Latin small letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin small letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter y with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */
+ { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+/* Unused for the time being. */
+#if 0
+KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, (Function *)0x0 }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, rl_tab_insert}, /* Control-i */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, (Function *)0x0 }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_vi_arg_digit }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_arrow_keys }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, (Function *)0x0 }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, rl_arrow_keys }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, (Function *)0x0 }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_word }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+#endif
diff --git a/gnu/lib/libreadline/vi_mode.c b/gnu/lib/libreadline/vi_mode.c
new file mode 100644
index 000000000000..165c287493c0
--- /dev/null
+++ b/gnu/lib/libreadline/vi_mode.c
@@ -0,0 +1,1319 @@
+/* vi_mode.c -- A vi emulation mode for Bash.
+ Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* **************************************************************** */
+/* */
+/* VI Emulation Mode */
+/* */
+/* **************************************************************** */
+#include "rlconf.h"
+
+#if defined (VI_MODE)
+
+#include <sys/types.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* Some standard library routines. */
+#include "rldefs.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#ifndef digit
+#define digit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef isletter
+#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#endif
+
+#ifndef digit_value
+#define digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+#define member(c, s) ((c) ? (char *)strchr ((s), (c)) : 0)
+#endif
+
+#ifndef isident
+#define isident(c) ((isletter(c) || digit(c) || c == '_'))
+#endif
+
+#ifndef exchange
+#define exchange(x, y) {int temp = x; x = y; y = temp;}
+#endif
+
+#ifndef VI_COMMENT_BEGIN_DEFAULT
+#define VI_COMMENT_BEGIN_DEFAULT "#"
+#endif
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+/* Variables imported from readline.c */
+extern int rl_point, rl_end, rl_mark, rl_done;
+extern FILE *rl_instream;
+extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
+extern Keymap _rl_keymap;
+extern char *rl_prompt;
+extern char *rl_line_buffer;
+extern int rl_arg_sign;
+
+extern void _rl_dispatch ();
+
+extern void rl_extend_line_buffer ();
+extern int rl_vi_check ();
+
+/* Non-zero means enter insertion mode. */
+static int _rl_vi_doing_insert = 0;
+
+/* String inserted into the line by rl_vi_comment (). */
+char *rl_vi_comment_begin = (char *)NULL;
+
+/* *** UNCLEAN *** */
+/* Command keys which do movement for xxx_to commands. */
+static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
+
+/* Keymap used for vi replace characters. Created dynamically since
+ rarely used. */
+static Keymap vi_replace_map = (Keymap)NULL;
+
+/* The number of characters inserted in the last replace operation. */
+static int vi_replace_count = 0;
+
+/* If non-zero, we have text inserted after a c[motion] command that put
+ us implicitly into insert mode. Some people want this text to be
+ attached to the command so that it is `redoable' with `.'. */
+static int vi_continued_command = 0;
+
+static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
+static int _rl_vi_last_repeat = 1;
+static int _rl_vi_last_arg_sign = 1;
+static int _rl_vi_last_motion = 0;
+static int _rl_vi_last_search_char = 0;
+static int _rl_vi_last_replacement = 0;
+
+static int vi_redoing = 0;
+
+/* Text modification commands. These are the `redoable' commands. */
+static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
+
+static int rl_digit_loop1 ();
+
+void
+_rl_vi_reset_last ()
+{
+ _rl_vi_last_command = 'i';
+ _rl_vi_last_repeat = 1;
+ _rl_vi_last_arg_sign = 1;
+ _rl_vi_last_motion = 0;
+}
+
+void
+_rl_vi_set_last (key, repeat, sign)
+ int key, repeat, sign;
+{
+ _rl_vi_last_command = key;
+ _rl_vi_last_repeat = repeat;
+ _rl_vi_last_arg_sign = sign;
+}
+
+/* Is the command C a VI mode text modification command? */
+int
+rl_vi_textmod_command (c)
+ int c;
+{
+ return (member (c, vi_textmod) != (char *)NULL);
+}
+
+/* Bound to `.'. Called from command mode, so we know that we have to
+ redo a text modification command. The default for _rl_vi_last_command
+ puts you back into insert mode. */
+rl_vi_redo (count, c)
+ int count, c;
+{
+ if (!rl_explicit_arg)
+ {
+ rl_numeric_arg = _rl_vi_last_repeat;
+ rl_arg_sign = _rl_vi_last_arg_sign;
+ }
+
+ vi_redoing = 1;
+ _rl_dispatch (_rl_vi_last_command, _rl_keymap);
+ vi_redoing = 0;
+
+ return (0);
+}
+
+/* Yank the nth arg from the previous line into this line at point. */
+rl_vi_yank_arg (count)
+ int count;
+{
+ /* Readline thinks that the first word on a line is the 0th, while vi
+ thinks the first word on a line is the 1st. Compensate. */
+ if (rl_explicit_arg)
+ rl_yank_nth_arg (count - 1, 0);
+ else
+ rl_yank_nth_arg ('$', 0);
+
+ return (0);
+}
+
+/* With an argument, move back that many history lines, else move to the
+ beginning of history. */
+rl_vi_fetch_history (count, c)
+ int count, c;
+{
+ int current = where_history ();
+
+ /* Giving an argument of n means we want the nth command in the history
+ file. The command number is interpreted the same way that the bash
+ `history' command does it -- that is, giving an argument count of 450
+ to this command would get the command listed as number 450 in the
+ output of `history'. */
+ if (rl_explicit_arg)
+ {
+ int wanted = history_base + current - count;
+ if (wanted <= 0)
+ rl_beginning_of_history (0, 0);
+ else
+ rl_get_previous_history (wanted);
+ }
+ else
+ rl_beginning_of_history (count, 0);
+ return (0);
+}
+
+/* Search again for the last thing searched for. */
+rl_vi_search_again (count, key)
+ int count, key;
+{
+ switch (key)
+ {
+ case 'n':
+ rl_noninc_reverse_search_again (count, key);
+ break;
+
+ case 'N':
+ rl_noninc_forward_search_again (count, key);
+ break;
+ }
+ return (0);
+}
+
+/* Do a vi style search. */
+rl_vi_search (count, key)
+ int count, key;
+{
+ switch (key)
+ {
+ case '?':
+ rl_noninc_forward_search (count, key);
+ break;
+
+ case '/':
+ rl_noninc_reverse_search (count, key);
+ break;
+
+ default:
+ ding ();
+ break;
+ }
+ return (0);
+}
+
+/* Completion, from vi's point of view. */
+rl_vi_complete (ignore, key)
+ int ignore, key;
+{
+ if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
+ {
+ if (!whitespace (rl_line_buffer[rl_point + 1]))
+ rl_vi_end_word (1, 'E');
+ rl_point++;
+ }
+
+ if (key == '*')
+ rl_complete_internal ('*'); /* Expansion and replacement. */
+ else if (key == '=')
+ rl_complete_internal ('?'); /* List possible completions. */
+ else if (key == '\\')
+ rl_complete_internal (TAB); /* Standard Readline completion. */
+ else
+ rl_complete (0, key);
+
+ if (key == '*' || key == '\\')
+ {
+ _rl_vi_set_last (key, 1, rl_arg_sign);
+ rl_vi_insertion_mode ();
+ }
+ return (0);
+}
+
+/* Tilde expansion for vi mode. */
+rl_vi_tilde_expand (ignore, key)
+ int ignore, key;
+{
+ rl_tilde_expand (0, key);
+ _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */
+ rl_vi_insertion_mode ();
+ return (0);
+}
+
+/* Previous word in vi mode. */
+rl_vi_prev_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_vi_next_word (-count, key));
+
+ if (rl_point == 0)
+ {
+ ding ();
+ return (0);
+ }
+
+ if (uppercase_p (key))
+ rl_vi_bWord (count);
+ else
+ rl_vi_bword (count);
+
+ return (0);
+}
+
+/* Next word in vi mode. */
+rl_vi_next_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_vi_prev_word (-count, key));
+
+ if (rl_point >= (rl_end - 1))
+ {
+ ding ();
+ return (0);
+ }
+
+ if (uppercase_p (key))
+ rl_vi_fWord (count);
+ else
+ rl_vi_fword (count);
+ return (0);
+}
+
+/* Move to the end of the ?next? word. */
+rl_vi_end_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (uppercase_p (key))
+ rl_vi_eWord (count);
+ else
+ rl_vi_eword (count);
+ return (0);
+}
+
+/* Move forward a word the way that 'W' does. */
+rl_vi_fWord (count)
+ int count;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ /* Skip until whitespace. */
+ while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+
+ /* Now skip whitespace. */
+ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ return (0);
+}
+
+rl_vi_bWord (count)
+ int count;
+{
+ while (count-- && rl_point > 0)
+ {
+ /* If we are at the start of a word, move back to whitespace so
+ we will go back to the start of the previous word. */
+ if (!whitespace (rl_line_buffer[rl_point]) &&
+ whitespace (rl_line_buffer[rl_point - 1]))
+ rl_point--;
+
+ while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ if (rl_point > 0)
+ {
+ while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
+ rl_point++;
+ }
+ }
+ return (0);
+}
+
+rl_vi_eWord (count)
+ int count;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ if (!whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Move to the next non-whitespace character (to the start of the
+ next word). */
+ while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
+
+ if (rl_point && rl_point < rl_end)
+ {
+ /* Skip whitespace. */
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Skip until whitespace. */
+ while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Move back to the last character of the word. */
+ rl_point--;
+ }
+ }
+ return (0);
+}
+
+rl_vi_fword (count)
+ int count;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ /* Move to white space (really non-identifer). */
+ if (isident (rl_line_buffer[rl_point]))
+ {
+ while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ else /* if (!whitespace (rl_line_buffer[rl_point])) */
+ {
+ while (!isident (rl_line_buffer[rl_point]) &&
+ !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+
+ /* Move past whitespace. */
+ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ return (0);
+}
+
+rl_vi_bword (count)
+ int count;
+{
+ while (count-- && rl_point > 0)
+ {
+ int last_is_ident;
+
+ /* If we are at the start of a word, move back to whitespace
+ so we will go back to the start of the previous word. */
+ if (!whitespace (rl_line_buffer[rl_point]) &&
+ whitespace (rl_line_buffer[rl_point - 1]))
+ rl_point--;
+
+ /* If this character and the previous character are `opposite', move
+ back so we don't get messed up by the rl_point++ down there in
+ the while loop. Without this code, words like `l;' screw up the
+ function. */
+ last_is_ident = isident (rl_line_buffer[rl_point - 1]);
+ if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
+ (!isident (rl_line_buffer[rl_point]) && last_is_ident))
+ rl_point--;
+
+ while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ if (rl_point > 0)
+ {
+ if (isident (rl_line_buffer[rl_point]))
+ while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
+ else
+ while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
+ !whitespace (rl_line_buffer[rl_point]));
+ rl_point++;
+ }
+ }
+ return (0);
+}
+
+rl_vi_eword (count)
+ int count;
+{
+ while (count-- && rl_point < rl_end - 1)
+ {
+ if (!whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ if (rl_point < rl_end)
+ {
+ if (isident (rl_line_buffer[rl_point]))
+ while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
+ else
+ while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
+ && !whitespace (rl_line_buffer[rl_point]));
+ }
+ rl_point--;
+ }
+ return (0);
+}
+
+rl_vi_insert_beg ()
+{
+ rl_beg_of_line ();
+ rl_vi_insertion_mode ();
+ return (0);
+}
+
+rl_vi_append_mode ()
+{
+ if (rl_point < rl_end)
+ rl_point++;
+ rl_vi_insertion_mode ();
+ return (0);
+}
+
+rl_vi_append_eol ()
+{
+ rl_end_of_line ();
+ rl_vi_append_mode ();
+ return (0);
+}
+
+/* What to do in the case of C-d. */
+rl_vi_eof_maybe (count, c)
+ int count, c;
+{
+ return (rl_newline (1, '\n'));
+}
+
+/* Insertion mode stuff. */
+
+/* Switching from one mode to the other really just involves
+ switching keymaps. */
+rl_vi_insertion_mode ()
+{
+ _rl_keymap = vi_insertion_keymap;
+ return (0);
+}
+
+void
+_rl_vi_done_inserting ()
+{
+ if (_rl_vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ /* Now, the text between rl_undo_list->next->start and
+ rl_undo_list->next->end is what was inserted while in insert
+ mode. */
+ _rl_vi_doing_insert = 0;
+ vi_continued_command = 1;
+ }
+ else
+ vi_continued_command = 0;
+}
+
+rl_vi_movement_mode ()
+{
+ if (rl_point > 0)
+ rl_backward (1);
+
+#if 0
+ _rl_vi_reset_last ();
+#endif
+
+ _rl_keymap = vi_movement_keymap;
+ _rl_vi_done_inserting ();
+ return (0);
+}
+
+rl_vi_arg_digit (count, c)
+ int count, c;
+{
+ if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
+ return (rl_beg_of_line ());
+ else
+ return (rl_digit_argument (count, c));
+}
+
+rl_vi_change_case (count, ignore)
+ int count, ignore;
+{
+ char c = 0;
+
+ /* Don't try this on an empty line. */
+ if (rl_point >= rl_end)
+ return (0);
+
+ while (count-- && rl_point < rl_end)
+ {
+ if (uppercase_p (rl_line_buffer[rl_point]))
+ c = to_lower (rl_line_buffer[rl_point]);
+ else if (lowercase_p (rl_line_buffer[rl_point]))
+ c = to_upper (rl_line_buffer[rl_point]);
+ else
+ {
+ /* Just skip over characters neither upper nor lower case. */
+ rl_forward (1);
+ continue;
+ }
+
+ /* Vi is kind of strange here. */
+ if (c)
+ {
+ rl_begin_undo_group ();
+ rl_delete (1, c);
+ rl_insert (1, c);
+ rl_end_undo_group ();
+ rl_vi_check ();
+ }
+ else
+ rl_forward (1);
+ }
+ return (0);
+}
+
+rl_vi_put (count, key)
+ int count, key;
+{
+ if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
+ rl_point++;
+
+ rl_yank ();
+ rl_backward (1);
+ return (0);
+}
+
+rl_vi_check ()
+{
+ if (rl_point && rl_point == rl_end)
+ rl_point--;
+ return (0);
+}
+
+rl_vi_column (count)
+{
+ if (count > rl_end)
+ rl_end_of_line ();
+ else
+ rl_point = count - 1;
+ return (0);
+}
+
+int
+rl_vi_domove (key, nextkey)
+ int key, *nextkey;
+{
+ int c, save;
+ int old_end;
+
+ rl_mark = rl_point;
+ c = rl_read_key ();
+ *nextkey = c;
+
+ if (!member (c, vi_motion))
+ {
+ if (digit (c))
+ {
+ save = rl_numeric_arg;
+ rl_numeric_arg = digit_value (c);
+ rl_digit_loop1 ();
+ rl_numeric_arg *= save;
+ c = rl_read_key (); /* real command */
+ *nextkey = c;
+ }
+ else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
+ {
+ rl_mark = rl_end;
+ rl_beg_of_line ();
+ _rl_vi_last_motion = c;
+ return (0);
+ }
+ else
+ return (-1);
+ }
+
+ _rl_vi_last_motion = c;
+
+ /* Append a blank character temporarily so that the motion routines
+ work right at the end of the line. */
+ old_end = rl_end;
+ rl_line_buffer[rl_end++] = ' ';
+ rl_line_buffer[rl_end] = '\0';
+
+ _rl_dispatch (c, _rl_keymap);
+
+ /* Remove the blank that we added. */
+ rl_end = old_end;
+ rl_line_buffer[rl_end] = '\0';
+ if (rl_point > rl_end)
+ rl_point = rl_end;
+
+ /* No change in position means the command failed. */
+ if (rl_mark == rl_point)
+ return (-1);
+
+ /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
+ word. If we are not at the end of the line, and we are on a
+ non-whitespace character, move back one (presumably to whitespace). */
+ if ((to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
+ !whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ /* If cw or cW, back up to the end of a word, so the behaviour of ce
+ or cE is the actual result. Brute-force, no subtlety. */
+ if (key == 'c' && rl_point >= rl_mark && (to_upper (c) == 'W'))
+ {
+ /* Don't move farther back than where we started. */
+ while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ /* Posix.2 says that if cw or cW moves the cursor towards the end of
+ the line, the character under the cursor should be deleted. */
+ if (rl_point == rl_mark)
+ rl_point++;
+ else
+ {
+ /* Move past the end of the word so that the kill doesn't
+ remove the last letter of the previous word. Only do this
+ if we are not at the end of the line. */
+ if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+ }
+ }
+
+ if (rl_mark < rl_point)
+ exchange (rl_point, rl_mark);
+
+ return (0);
+}
+
+/* A simplified loop for vi. Don't dispatch key at end.
+ Don't recognize minus sign? */
+static int
+rl_digit_loop1 ()
+{
+ int key, c;
+
+ while (1)
+ {
+ rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
+ key = c = rl_read_key ();
+
+ if (_rl_keymap[c].type == ISFUNC &&
+ _rl_keymap[c].function == rl_universal_argument)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+
+ c = UNMETA (c);
+ if (numeric (c))
+ {
+ if (rl_explicit_arg)
+ rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
+ else
+ rl_numeric_arg = digit_value (c);
+ rl_explicit_arg = 1;
+ }
+ else
+ {
+ rl_clear_message ();
+ rl_stuff_char (key);
+ break;
+ }
+ }
+ return (0);
+}
+
+rl_vi_delete_to (count, key)
+ int count, key;
+{
+ int c;
+
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+ else if (vi_redoing)
+ rl_stuff_char (_rl_vi_last_motion);
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. */
+ if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ rl_kill_text (rl_point, rl_mark);
+ return (0);
+}
+
+rl_vi_change_to (count, key)
+ int count, key;
+{
+ int c, start_pos;
+
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+ else if (vi_redoing)
+ rl_stuff_char (_rl_vi_last_motion);
+
+ start_pos = rl_point;
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. c[wW] are handled by special-case code in rl_vi_domove(),
+ and already leave the mark at the correct location. */
+ if ((strchr (" l|hwW^0%bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ /* The cursor never moves with c[wW]. */
+ if ((to_upper (c) == 'W') && rl_point < start_pos)
+ rl_point = start_pos;
+
+ rl_kill_text (rl_point, rl_mark);
+
+ rl_begin_undo_group ();
+ _rl_vi_doing_insert = 1;
+ _rl_vi_set_last (key, count, rl_arg_sign);
+ rl_vi_insertion_mode ();
+
+ return (0);
+}
+
+rl_vi_yank_to (count, key)
+ int count, key;
+{
+ int c, save = rl_point;
+
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. */
+ if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ rl_begin_undo_group ();
+ rl_kill_text (rl_point, rl_mark);
+ rl_end_undo_group ();
+ rl_do_undo ();
+ rl_point = save;
+
+ return (0);
+}
+
+rl_vi_delete (count)
+ int count;
+{
+ int end;
+
+ if (rl_end == 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ end = rl_point + count;
+
+ if (end >= rl_end)
+ end = rl_end;
+
+ rl_kill_text (rl_point, end);
+
+ if (rl_point > 0 && rl_point == rl_end)
+ rl_backward (1);
+ return (0);
+}
+
+/* Turn the current line into a comment in shell history.
+ A K*rn shell style function. */
+rl_vi_comment ()
+{
+ rl_beg_of_line ();
+
+ if (rl_vi_comment_begin != (char *)NULL)
+ rl_insert_text (rl_vi_comment_begin);
+ else
+ rl_insert_text (VI_COMMENT_BEGIN_DEFAULT); /* Default. */
+
+ rl_redisplay ();
+ rl_newline (1, '\010');
+ return (0);
+}
+
+rl_vi_first_print ()
+{
+ return (rl_back_to_indent ());
+}
+
+rl_back_to_indent (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ rl_beg_of_line ();
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+ return (0);
+}
+
+/* NOTE: it is necessary that opposite directions are inverses */
+#define FTO 1 /* forward to */
+#define BTO -1 /* backward to */
+#define FFIND 2 /* forward find */
+#define BFIND -2 /* backward find */
+
+rl_vi_char_search (count, key)
+ int count, key;
+{
+ static char target;
+ static int orig_dir, dir;
+ int pos;
+
+ if (key == ';' || key == ',')
+ dir = (key == ';' ? orig_dir : -orig_dir);
+ else
+ {
+ if (vi_redoing)
+ target = _rl_vi_last_search_char;
+ else
+ _rl_vi_last_search_char = target = rl_getc (rl_instream);
+
+ switch (key)
+ {
+ case 't':
+ orig_dir = dir = FTO;
+ break;
+
+ case 'T':
+ orig_dir = dir = BTO;
+ break;
+
+ case 'f':
+ orig_dir = dir = FFIND;
+ break;
+
+ case 'F':
+ orig_dir = dir = BFIND;
+ break;
+ }
+ }
+
+ pos = rl_point;
+
+ while (count--)
+ {
+ if (dir < 0)
+ {
+ if (pos == 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ pos--;
+ do
+ {
+ if (rl_line_buffer[pos] == target)
+ {
+ if (dir == BTO)
+ rl_point = pos + 1;
+ else
+ rl_point = pos;
+ break;
+ }
+ }
+ while (pos--);
+
+ if (pos < 0)
+ {
+ ding ();
+ return -1;
+ }
+ }
+ else
+ { /* dir > 0 */
+ if (pos >= rl_end)
+ {
+ ding ();
+ return -1;
+ }
+
+ pos++;
+ do
+ {
+ if (rl_line_buffer[pos] == target)
+ {
+ if (dir == FTO)
+ rl_point = pos - 1;
+ else
+ rl_point = pos;
+ break;
+ }
+ }
+ while (++pos < rl_end);
+
+ if (pos >= (rl_end - 1))
+ {
+ ding ();
+ return -1;
+ }
+ }
+ }
+ return (0);
+}
+
+/* Match brackets */
+rl_vi_match ()
+{
+ int count = 1, brack, pos;
+
+ pos = rl_point;
+ if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
+ {
+ while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
+ rl_point < rl_end - 1)
+ rl_forward (1);
+
+ if (brack <= 0)
+ {
+ rl_point = pos;
+ ding ();
+ return -1;
+ }
+ }
+
+ pos = rl_point;
+
+ if (brack < 0)
+ {
+ while (count)
+ {
+ if (--pos >= 0)
+ {
+ int b = rl_vi_bracktype (rl_line_buffer[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return -1;
+ }
+ }
+ }
+ else
+ { /* brack > 0 */
+ while (count)
+ {
+ if (++pos < rl_end)
+ {
+ int b = rl_vi_bracktype (rl_line_buffer[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return -1;
+ }
+ }
+ }
+ rl_point = pos;
+ return (0);
+}
+
+int
+rl_vi_bracktype (c)
+ int c;
+{
+ switch (c)
+ {
+ case '(': return 1;
+ case ')': return -1;
+ case '[': return 2;
+ case ']': return -2;
+ case '{': return 3;
+ case '}': return -3;
+ default: return 0;
+ }
+}
+
+rl_vi_change_char (count, key)
+ int count, key;
+{
+ int c;
+
+ if (vi_redoing)
+ c = _rl_vi_last_replacement;
+ else
+ _rl_vi_last_replacement = c = rl_getc (rl_instream);
+
+ if (c == '\033' || c == CTRL ('C'))
+ return -1;
+
+ while (count-- && rl_point < rl_end)
+ {
+ rl_begin_undo_group ();
+
+ rl_delete (1, c);
+ rl_insert (1, c);
+ if (count == 0)
+ rl_backward (1);
+
+ rl_end_undo_group ();
+ }
+ return (0);
+}
+
+rl_vi_subst (count, key)
+ int count, key;
+{
+ rl_begin_undo_group ();
+
+ if (uppercase_p (key))
+ {
+ rl_beg_of_line ();
+ rl_kill_line (1);
+ }
+ else
+ rl_delete (count, key);
+
+ rl_end_undo_group ();
+
+ _rl_vi_set_last (key, count, rl_arg_sign);
+
+ rl_begin_undo_group ();
+ _rl_vi_doing_insert = 1;
+ rl_vi_insertion_mode ();
+
+ return (0);
+}
+
+rl_vi_overstrike (count, key)
+ int count, key;
+{
+ int i;
+
+ if (_rl_vi_doing_insert == 0)
+ {
+ _rl_vi_doing_insert = 1;
+ rl_begin_undo_group ();
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ vi_replace_count++;
+ rl_begin_undo_group ();
+
+ if (rl_point < rl_end)
+ {
+ rl_delete (1, key);
+ rl_insert (1, key);
+ }
+ else
+ rl_insert (1, key);
+
+ rl_end_undo_group ();
+ }
+ return (0);
+}
+
+rl_vi_overstrike_delete (count)
+ int count;
+{
+ int i, s;
+
+ for (i = 0; i < count; i++)
+ {
+ if (vi_replace_count == 0)
+ {
+ ding ();
+ break;
+ }
+ s = rl_point;
+
+ if (rl_do_undo ())
+ vi_replace_count--;
+
+ if (rl_point == s)
+ rl_backward (1);
+ }
+
+ if (vi_replace_count == 0 && _rl_vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ rl_do_undo ();
+ _rl_vi_doing_insert = 0;
+ }
+ return (0);
+}
+
+rl_vi_replace (count, key)
+ int count, key;
+{
+ int i;
+
+ vi_replace_count = 0;
+
+ if (!vi_replace_map)
+ {
+ vi_replace_map = rl_make_bare_keymap ();
+
+ for (i = ' '; i < 127; i++)
+ vi_replace_map[i].function = rl_vi_overstrike;
+
+ vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
+ vi_replace_map[ESC].function = rl_vi_movement_mode;
+ vi_replace_map[RETURN].function = rl_newline;
+ vi_replace_map[NEWLINE].function = rl_newline;
+
+ /* If the normal vi insertion keymap has ^H bound to erase, do the
+ same here. Probably should remove the assignment to RUBOUT up
+ there, but I don't think it will make a difference in real life. */
+ if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
+ vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
+ vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
+
+ }
+ _rl_keymap = vi_replace_map;
+ return (0);
+}
+
+#if 0
+/* Try to complete the word we are standing on or the word that ends with
+ the previous character. A space matches everything. Word delimiters are
+ space and ;. */
+rl_vi_possible_completions()
+{
+ int save_pos = rl_point;
+
+ if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
+ {
+ while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
+ rl_line_buffer[rl_point] != ';')
+ rl_point++;
+ }
+ else if (rl_line_buffer[rl_point - 1] == ';')
+ {
+ ding ();
+ return (0);
+ }
+
+ rl_possible_completions ();
+ rl_point = save_pos;
+
+ return (0);
+}
+#endif
+
+#if defined (STATIC_MALLOC)
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)xmalloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
+
+#endif /* VI_MODE */
diff --git a/gnu/lib/libreadline/xmalloc.c b/gnu/lib/libreadline/xmalloc.c
new file mode 100644
index 000000000000..4f6dc762e227
--- /dev/null
+++ b/gnu/lib/libreadline/xmalloc.c
@@ -0,0 +1,78 @@
+/* xmalloc.c -- safe versions of malloc and realloc */
+
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (ALREADY_HAVE_XMALLOC)
+#else
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+static void memory_error_and_abort ();
+
+/* **************************************************************** */
+/* */
+/* Memory Allocation and Deallocation. */
+/* */
+/* **************************************************************** */
+
+/* Return a pointer to free()able block of memory large enough
+ to hold BYTES number of bytes. If the memory cannot be allocated,
+ print an error message and abort. */
+char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xmalloc");
+ return (temp);
+}
+
+char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xrealloc");
+ return (temp);
+}
+
+static void
+memory_error_and_abort (fname)
+ char *fname;
+{
+ fprintf (stderr, "%s: Out of virtual memory!\n", fname);
+ abort ();
+}
+#endif /* !ALREADY_HAVE_XMALLOC */
diff --git a/gnu/lib/libregex/Makefile b/gnu/lib/libregex/Makefile
index 0fab747c7ed0..cacc8b738860 100644
--- a/gnu/lib/libregex/Makefile
+++ b/gnu/lib/libregex/Makefile
@@ -1,11 +1,12 @@
-# $Header: /home/cvs/386BSD/src/gnu/lib/libregex/Makefile,v 1.6 1994/01/29 20:20:51 nate Exp $
+# $Header: /home/cvs/386BSD/src/gnu/lib/libregex/Makefile,v 1.8 1994/05/27 10:53:33 csgr Exp $
-SHLIB_MAJOR=1
-SHLIB_MINOR=0
LIB= gnuregex
CFLAGS+=-DHAVE_STRING_H=1
SRCS= regex.c
NOMAN= noman
+afterinstall:
+ install -c ${.CURDIR}/regex.h ${DESTDIR}/usr/include/gnuregex.h
+
.include <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/ChangeLog b/gnu/libexec/uucp/ChangeLog
index 48a52b75a285..82353fff56a3 100644
--- a/gnu/libexec/uucp/ChangeLog
+++ b/gnu/libexec/uucp/ChangeLog
@@ -1,25 +1,1260 @@
-Sat Feb 13 15:57:30 1993 Ian Lance Taylor (ian@comton.airs.com)
+Thu May 5 23:15:11 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Released version 1.05.
+
+ * Makefile.in (doc-dist): Put uucp.ps in uucp-doc-$(VERSION).
+
+Sun May 1 23:41:49 1994 Ian Lance Taylor (ian@airs.com)
+
+ * uuchk.c (ikshow_port): Show reliability information.
+ (ukshow_dialer): Likewise.
+ (ukshow_reliable): New function.
+
+Sat Apr 16 22:28:10 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Andrew A. Chernov: uucico.c (main): Pass 'z' to getopt.
+ (uhelp): Mention -z aka --try-next.
+
+ * log.c (ustats): Report failed transfers when HAVE_HDB_LOGGING.
+
+Wed Apr 13 23:07:20 1994 Ian Lance Taylor (ian@airs.com)
+
+ * prot.c (fsend_data): If no room in receive buffer, just write
+ the data out, don't call fconn_io.
+
+Tue Apr 12 21:55:32 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Spider Boardman: unix/serial.c (fsysdep_modem_end_dial): Set
+ terminal characteristics of reopened port.
+
+Sun Apr 10 18:05:34 1994 Ian Lance Taylor (ian@airs.com)
+
+ * send.c (flocal_send_fail): Always call fsysdep_did_work.
+ (flocal_send_await_reply): Don't call flocal_send_fail if we are
+ going to call fsend_exec_file_init. Only call
+ fsend_exec_file_init if fnever is TRUE. Pass fnever to
+ flocal_send_cancelled using the qinfo->fsent flag.
+ (flocal_send_cancelled): Only call fsend_exec_file_init if
+ qinfo->fsent is TRUE.
+
+ * unix/statsb.c (fsysdep_lock_status): If HAVE_QNX_LOCKFILES,
+ initialize painid to NULL.
+
+Tue Apr 5 23:09:00 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Released version gamma 1.05.
+
+ * Makefile.in (VERSION): Changed to gamma1.05.
+
+ * uucico.c (fcall): Return TRUE if -C was used and no call was
+ made because there was no work.
+
+Mon Apr 4 20:29:30 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Chris Lewis: unix/serial.c: Include <sys/ioctl.h> if
+ HAVE_TXADDCD. Check for HAVE_TXADDCD rather than ifdef TXADDCD or
+ TXDELCD.
+
+ * configure.in: Check for TXADDCD in <sys/ioctl.h>.
+ * config.h.in (HAVE_TXADDCD): New configuration macro.
+
+Sun Apr 3 14:05:30 1994 Ian Lance Taylor (ian@airs.com)
+
+ * send.c (flocal_send_request): Queue stransfer structure up
+ before sending any command or data, because sending data may cause
+ data to be received for this stransfer, and we must be prepared to
+ handle it correctly.
+ (fremote_rec_reply): Likewise.
+ * rec.c (flocal_rec_send_request, fremote_send_reply): Likewise.
+ (fremote_send_fail_send): Likewise.
+ * xcmd.c (flocal_xcmd_request): Likewise.
+
+ * Chris Lewis: unix/serial.c (fsserial_hardflow): Add support for
+ AIX TXADDCD and 3b1 CTSCD.
+
+Sat Apr 2 00:04:30 1994 Ian Lance Taylor (ian@airs.com)
+
+ * policy.h (USE_TRADITIONAL_STATUS): Permit this to be defined.
+ * lib/status.c: Control initialization of azStatus based on
+ USE_TRADITIONAL_STATUS rather than SPOOLDIR_HDB || SPOOLDIR_SVR4.
+
+Fri Apr 1 23:52:09 1994 Ian Lance Taylor (ian@airs.com)
+
+ * log.c (ulog): When using HAVE_HDB_LOGGING, force the program
+ name to lower case when using it as a file name.
+
+ * send.c (flocal_send_await_reply): Correct code to really not
+ decrement number of channels to one.
+ * rec.c (flocal_rec_await_reply): Likewise.
+
+Wed Mar 30 22:57:30 1994 Ian Lance Taylor (ian@airs.com)
+
+ * lib/buffer.c (ubuffree): Change ioff from size_t to int to avoid
+ HP/UX compiler bug.
+
+ * configure.in: Make sure that <utime.h> defines struct utimbuf
+ before assuming that it is present.
+
+Tue Mar 29 23:00:15 1994 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/filnam.c: Use UUCONF_CONST, not const, to match
+ declaration in uuconf.h.
+
+Mon Mar 28 20:06:00 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Andrew A. Chernov: policy.h: For several macros, add commented
+ out values appropriate for some free BSD distributions.
+ * Makefile.in: Likewise.
+
+ * uucico.c (icallin_cmp): Use pointer, not void *.
+ * uuconf/callin.c (struct sinfo, uuconf_callin): Likewise.
+
+ * Chris Lewis: uuconv.c (fvperm_string_cmp, fvperm_array_cmp): AIX
+ 3.2.5 cc can't handle conditional expressions in if conditions.
+
+Sun Mar 27 15:04:27 1994 Ian Lance Taylor (ian@airs.com)
+
+ * send.c (flocal_send_fail): Don't assume that qtrans is not NULL.
+
+ * Jeff Ross, Stephen J. Walick: Makefile.in (uusched): Substitute
+ for @SBINDIR@, not @BINDIR@.
+
+ * configure.in: Make sure that <dirent.h> defines struct dirent
+ before assuming that it is present.
+
+ * Benoit Grange: unix/detach.c (usysdep_detach): Correct type of
+ HAVE_BSD_SETPGRP for HAVE_BSD_PGRP.
+
+Sat Mar 26 12:59:36 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Andrew A. Chernov: uucico.c (asLongopts): Add --try-next as
+ synonym for -z.
+ (main): If -z, call fcall with ftrynext as TRUE.
+ (fcall): Add ftrynext argument. If ftrynext is TRUE, try the next
+ alternate if a call fails.
+
+Fri Mar 25 22:37:51 1994 Ian Lance Taylor (ian@airs.com)
+
+ * lib/parse.c (fparse_cmd): If we get a decimal 666 or 777 for the
+ mode, turn it into an octal 0666 or 0777.
+
+ * send.c (flocal_send_fail): Accept qdaemon argument rather than
+ qsys. Changed all callers. If we are going to send an execution
+ file, don't call fsysdep_did_work.
+
+ * protg.c (fgstart): Say ``sending'' and ``receiving'' instead of
+ ``remote'' and ``local'' in log message.
+ * proti.c (fijstart): Likewise.
+
+Thu Mar 24 22:40:49 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Gert Doering: uuchk.c (ikshow_port): Don't use qtli for a TCP
+ port.
+
+ * Makefile.in (uusched, uuto): Fix typo in sed command.
+
+ * unix/mail.c (fsysdep_mail): Add casts to avoid warnings.
+ * uuconf/runuxq.c (uuconf_runuuxqt): Likewise.
+
+ * Emmanuel Mogenet: unix/pipe.c (fspipe_dial): Make consistently
+ static.
+
+ * unix/serial.c (fsserial_open): Only strip /dev/ from the start
+ of a device name, rather than dropping everything before the last
+ slash.
+
+ * sysh.unx (ftw): Change stat argument to not be const pointer.
+ * unix/ftw.c (ftw_dir, ftw): Change stat argument to func argument
+ to not be const pointer.
+ * unix/srmdir.c (isremove_dir): Change stat argument to not be
+ const pointer.
+ * unix/walk.c (iswalk_dir): Likewise.
+
+Wed Mar 23 20:02:26 1994 Ian Lance Taylor (ian@airs.com)
+
+ * conn.c (fconn_break): Remove incorrect indirection of function
+ pointer.
+
+ * unix/mkdirs.c (fsysdep_make_dirs): Some systems can return
+ EACCES, not EEXIST, when a directory exists.
+
+ * configure.in: Fix STAT_STATFS2_FSIZE test.
+ * configure: Regenerated.
+
+Tue Mar 22 01:32:21 1994 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c (main): Skip a leading dash in argv[0] which is
+ probably the result of being invoked by the Unix login program.
+
+ * configure.in: Check for sys/time.h.
+ * config.h.in (HAVE_SYS_TIME_H): Define.
+
+ * unix/serial.c (fsysdep_modem_begin_dial): Correct type of q for
+ qsysdep.
+
+ * uux.c (main): Check for zXnames being NULL.
+
+Sat Mar 19 14:07:31 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Released version beta 1.05.
+
+ * Makefile.in (uucp.info): Use -o argument to force info files to
+ be created in objdir.
+ (doc-dist): Get README-DOC from $(srcdir).
+
+ * lib/debug.c (iDebug, azDebug_names, idebug_parse): Only compile
+ if DEBUG > 1.
+
+Mon Feb 14 22:46:49 1994 Ian Lance Taylor (ian@airs.com)
+
+ * lib/strtou.c: New file, for strtoul.
+ * lib/MANIFEST: List strtou.c.
+ * configure.in: Check for strtoul, add strtou.o to LIBOBJS if not
+ there.
+ * config.h.in (HAVE_STRTOUL): Define.
+ * uucp.h (strtoul): Declare.
+
+Mon Jan 31 20:17:30 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Makefile.in, lib/Makefile.in, unix/Makefile.in,
+ uuconf/Makefile.in: Use $(CFLAGS) after all other flags.
+
+Sun Jan 30 14:34:51 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Makefile.in (clean, distclean, dist, doc-dist): Remove .tar.gz
+ file, not .tar.Z one.
+ (dist, doc-dist): Use gzip --best, not compress.
+
+ * Makefile.in (VERSION): Set to beta1.05.
+
+ * cu.c, uuchk.c, uucico.c, uuconv.c, uucp.c, uulog.c, uuname.c,
+ uupick.c, uustat.c, uux.c, uuxqt.c: Updated copyright date.
+
+ * conn.c (fconn_init): Added third argument: type of standard
+ input port.
+ * conn.h (fconn_init): Updated declaration.
+ * uucico.c (asLongopts): Added --stdin, synonym for -i.
+ (main): Accept -i TLI to set standard input to be of type TLI.
+ Pass appropriate additional argument to fconn_init.
+ (uhelp): Updated.
+ (fconn_call, iuport_lock): Changed all calls to fconn_init.
+ * cu.c: Changed all calls to fconn_init.
+ * prot.c, protj.c: Include uuconf.h before conn.h.
+ * Makefile.in (prot.o, protj.o): Updated.
+
+ * unix/serial.c (fsysdep_conn_read): Permit up to two EWOULDBLOCK
+ error returns from read before quitting.
+
+Sat Jan 22 16:48:41 1994 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/hinit.c: Don't treat lines with leading whitespace as
+ comments in Sysfiles.
+
+ * log.c: Don't require ANSI C to use vfprintf, just require
+ stdarg.h and prototypes. Required for Alpha cc support.
+
+ * configure.in: Check for prototype support. Check for stdarg.h.
+ When looking for socket and t_open check for "-lsocket -lnsl"
+ after plain "-lnsl".
+ * config.h.in (HAVE_PROTOTYPES, HAVE_STDARG_H): New macros.
+ * uucp.h: Demand that an ANSI C compiler support prototypes. If
+ HAVE_PROTOTYPES is 1 for Classic C, defined P(x) to be x.
+
+ * configure: Upgraded to autoconf 1.7.
+
+ * protg.c (fgstart): Ensure that window size is reasonable.
+
+ * protg.c (fvstart): Change default packet size from 512 to 1024.
+
+ * trans.h (struct sdaemon): Added zconfig, irunuuxqt, and
+ cxfiles_received fields.
+ (fspawn_uuxqt): Declare.
+ * uucico.c (fcall, flogin_prompt, faccept_call): Added zconfig and
+ fuuxqt arguments; changed all callers.
+ (main): Use fspawn_uuxqt to invoke uuxqt, and only do it if
+ uuconf_runuuxqt returns UUCONF_RUNUUXQT_ONCE.
+ (fcall, faccept_call): Initialize new struct sdaemon fields.
+ Spawn uuxqt if uuconf_runuuxqt returned UUCONF_RUNUUXQT_PERCALL or
+ if it returned a positive number and execution files have arrived
+ since the last time uuxqt was spawned.
+ (fspawn_uuxqt): New function.
+ * rec.c (frec_file_end): Spawn uuxqt if enough execution files
+ have been received.
+
+ * uuconf.h (UUCONF_RUNUUXQT_NEVER, UUCONF_RUNUUXQT_ONCE,
+ UUCONF_RUNUUXQT_PERCALL): New #define constants.
+ (uuconf_runuuxqt): Declare.
+ * uuconf/runuxq.c: New file.
+ * uuconf/uucnfi.h (struct sprocess); Added zrunuuxqt field.
+ * uuconf/tinit.c (asCmds): Added "run-uuxqt".
+ * uuconf/iniglb.c (_uuconf_iinit_global): Initialize zrunuuxqt
+ field.
+ * uuconf/MANIFEST, uuconf/Makefile.in: Handle runuxq.c.
+
+ * system.h (fsysdep_run): Added ffork argument.
+ * unix/run.c (fsysdep_run): Added ffork argument.
+ * uucico.c (main), uux.c (main), uucp.c (main): Changed calls to
+ fsysdep_run to pass ffork argument as FALSE.
+
+Fri Jan 14 19:40:20 1994 Ian Lance Taylor (ian@airs.com)
+
+ * Chip Salzenberg: unix/splcmd.c (zsysdep_spool_commands): More
+ fitting value for size of abtempfile.
+
+Mon Jan 10 22:46:52 1994 Ian Lance Taylor (ian@airs.com)
+
+ * unix/recep.c (fsysdep_remember_reception): Create directory with
+ mode of 0755, not 0777.
+
+Mon Jan 3 20:34:35 1994 Ian Lance Taylor (ian@airs.com)
+
+ * protg.c (fgprocess_data): Don't believe the ACK of an out of
+ order packet.
+
+ * uucico.c (asProtocols): Added 'v'.
+ * prot.h (fvstart): Declare.
+ * protg.c (fvstart): New function.
+
+Sun Jan 2 15:34:12 1994 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c (main), uucp.c (main), uux.c (main): Pass -I argument
+ to invoked program.
+
+ * uustat.c (JOB_REJUVENATE): Define.
+ (asLongopts): Add "rejuvenate-all".
+ (main, ususage): Handle -R.
+ (fsworkfile_show, fsexecutions): Handle JOB_REJUVENATE.
+ * system.h (fsysdep_touch_file): Declare.
+ * unix/statsb.c (issettime): Rename from ussettime.
+ (fsysdep_touch_file): Create.
+
+ * Jim Avera: system.h: (INIT_NOCLOSE): Define.
+ * unix/init.c (usysdep_initialize): If INIT_NOCLOSE is set, don't
+ close all open descriptors.
+
+ * Allen Delaney: tli.c: Don't declare t_alloc if we have
+ <tiuser.h>, since it can cause conflicts.
+
+ * configure.in: Call AC_CONST.
+ * config.h.in: Added #undef const for configure to comment out.
+ * uucp.h: Don't undefine const here.
+
+ * Spider Boardman: uucico.c (main): Correct error message.
+ uux.c (main), uucp.c (main): Call uucico with -C option.
+
+ * tstuu.c (uprepare_test): Don't put the obsolete pty command into
+ the port file.
+
+ * spawn.c (ixsspawn): Set close-on-exec flag for both ends of
+ new pipe.
+
+ * Andrew A. Chernov: unix/serial.c (ICLEAR_IFLAG): Clear IMAXBEL
+ if it is defined.
+ (ICLEAR_LFLAG): Clear PENDIN if it is defined.
+
+ * send.c (flocal_send_file_init): If stat fails, discard the
+ command and save the temporary file.
+ (flocal_send_fail): Cleaned up zsysdep_save_temp_file call.
+
+Thu Dec 23 00:55:22 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Martin Tomes: spawn.c (ixsspawn): On ISC, call __setostype
+ before execve.
+
+Wed Dec 22 00:06:25 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/tport.c (ipunknown): Set UUCONF_CMDTABRET_EXIT if an
+ error is found.
+
+ * uucico.c (asLongopts): Add --login as a synonym for -u.
+ (main): Permit a privileged user to use -u to set the login name
+ rather than always using zsysdep_login_name ().
+ (flogin_prompt): Accept login name as an argument. If non-null,
+ use it rather than prompting for one.
+ (uhelp): Document new --login option.
+ * uucico.8: Document new --login option.
+ * unix/priv.c: New file, containing fsysdep_privileged.
+ * unix/statsb.c (fsysdep_privileged): Moved to priv.c.
+ * unix/MANIFEST, unix/Makefile.in: Support new priv.c file.
+
+ * uuchk.c (ikshow_port): Print a note when using the port name as
+ a device name.
+
+Tue Dec 21 00:01:40 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c (fcall): Ignore status file times in the future when
+ deciding whether a retry is permitted.
+
+ * detach.c (usysdep_detach): If it forks, output a debugging
+ message with the old and new process IDs.
+
+ * Scott Ballantyne: unix/spawn.c (ixsspawn): If fkeepuid is TRUE,
+ try to set the real user and group ID to the effective user and
+ group ID. This will not work on System V derived systems, but
+ should do no harm.
+ * unix/xqtsub.c (fsysdep_execute): Pass fkeepuid as TRUE to
+ ixsspawn.
+ * unix/epopen.c (espopen): Likewise.
+
+ * uucico.c (faccept_call): Use correct default for
+ max-remote-debug.
+
+ * uuconf/tportc.c (ipdialer): Don't core dump if the port name is
+ NULL, as it is for the default port.
+
+ * unix/xqtsub.c (fsysdep_xqt_check_file): Do not permit the name
+ ``..'', or strings starting with ``../''.
+
+ * proti.c (fijstart): Send a fourth byte in the SYNC packet with
+ the number of channels.
+ (fiprocess_packet): If a SYNC packet has a fourth byte, use it to
+ set the number of channels.
+
+ * rec.c (flocal_rec_await_reply): Handle RN9 (no channels
+ available on remote).
+ * send.c (flocal_send_await_reply): Handle SN9 (no channels
+ available on remote).
+
+ * trans.h (struct sdaemon): Added cchans field.
+ * uucico.c (fcall, fdo_call, faccept_call): Initialize cchans.
+ * trans.c (utchanalc, fcheck_queue, floop): Use qdaemon->cchans,
+ not qdaemon->qproto->cchans.
+ * send.c (flocal_send_request, flocal_send_await_reply): Likewise.
+ * rec.c (fremote_send_fail): Likewise.
+
+Sun Dec 19 19:44:31 1993 Ian Lance Taylor (ian@airs.com)
+
+ * proti.c (cIack_frequency): New static variable.
+ (asIproto_params): New protocol parameter ack-frequency.
+ (fijstart): If cIack_frequency is not set, set it to half the
+ window size.
+ (fishutdown): Clear cIack_frequency.
+ (fiprocess_data): Use cIack_frequency to determine when to send an
+ acknowledgement, rather than always sending one at half the window
+ size.
+
+ * uuconf/cmdfil.c (uuconf_cmd_file): Free zline.
+
+ * uuconf/callin.c (uuconf_callin): Treat colon as a field
+ delimiter, for Unix /etc/passwd support.
+
+ * unix/xqtsub.c (zsysdep_find_command): If file named with
+ absolute path does not exist, give a reasonable error message.
+
+ * uuconf/rdperm.c (ihadd_norw): Ignore use of empty string with
+ NOREAD or NOWRITE, rather than denying everything.
+
+ * Chip Salzenberg: uulog.c (main): Set zluser correctly under
+ HAVE_HDB_LOGGING.
+
+ * Chip Salzenberg: protz.c (izrecv_hdr): Use %lx, not %x.
+
+Sun Dec 12 19:24:35 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uucp.c (uccopy): Null terminate name of forwarding system.
+
+Mon Nov 22 21:12:41 1993 Ian Lance Taylor (ian@airs.com)
+
+ * unix/tmpfil.c: Include "uudefs.h".
+ * unix/Makefile.in: Changed accordingly.
+
+ * log.c (zstpcpy): New function.
+ (ulog): Output to log file with a single call to fprintf.
+
+ * uucp.c (uccopy): Clarified "not permitted to send" error.
+
+ * log.c (ulog): If debugging is on, output all log messages to
+ debugging file.
+
+ * uucico.c (fdo_call): Changed "Bad initialization string" error
+ message.
+
+ * unix/lock.c (fsdo_lock): Print date a stale lock was last
+ modified.
+
+ * uucico.c (uaccept_call_cleanup): Call ulog_system (NULL).
+
+Sun Nov 21 17:04:27 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Joe Wells: policy.h: Added new parameter LOG_DEVICE_PREFIX.
+ * unix/serial.c (fsserial_open): Use it.
+
+ * Makefile.in: Always use CFLAGS as well as LDFLAGS when linking.
+
+ * Joe Wells: policy.h: Added new parameter QNX_LOG_NODE_ID.
+ * log.c (ulog): Log the QNX node ID if QNX_LOG_NODE_ID is set.
+
+ * Joe Wells: unix/serial.c: Support QNX dev_info function for
+ serial port locking.
+
+ * Joe Wells: unix/fsusg.c: Support QNX disk_space function.
+ * unix/Makefile.in: fsusg.o now depends upon uudefs.h.
+
+ * Joe Wells: policy.h: Changed PS_PROGRAM default for __QNX__.
+ Added HAVE_QNX_LOCKFILES. Rearranged LOCKFILE defines to permit
+ some default selections.
+ * sysh.unx: Removed LOCKFILES sanity check.
+ * unix/lock.c (fsdo_lock, fsqnx_stale), unix/serial.c
+ (fsserial_lockfile), unix/statsb.c (fsysdep_lock_status): Added
+ support for HAVE_QNX_LOCKFILES.
+
+ * configure.in, config.h.in, policy.h: Moved MAIL_PROGRAM to
+ policy.h. Added MAIL_PROGRAM_TO_BODY and
+ MAIL_PROGRAM_SUBJECT_BODY.
+ * unix/mail.c: Updated accordingly.
+
+ * uucico.c (main): Don't make -p imply -e.
+ (uhelp): Modified accordingly.
+ * uucico.8: Modified accordingly.
+
+Mon Nov 1 21:34:36 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c (main): Call fconn_close and fconn_open rather than
+ calling fconn_reset.
+ * conn.h (struct sconncmds): Removed pfreset field.
+ (fconn_reset): Removed declaration.
+ * conn.c (fconn_reset): Removed.
+ * tcp.c (ftcp_reset): Removed.
+ (ftcp_open): Save pid in ssysdep_conn information.
+ (ftcp_close): If pid has changed, return FALSE.
+ * tli.c (ftli_reset): Removed.
+ (ftli_open): Save pid in ssysdep_conn information.
+ (ftli_close): If pid has changed, return FALSE.
+ * unix/pipe.c (fspipe_close): Replaced with fspipe_reset body.
+ (fspipe_reset): Removed.
+ (fspipe_dial): Call fspipe_close, not fspipe_reset.
+ * unix/serial.c (fsserial_reset, fsstdin_reset): Removed.
+ (fsysdep_modem_begin_dial): Hangup terminal here, rather than
+ calling fconn_reset.
+
+ * send.c (fremote_rec_reply): If we want to request hangup, send
+ an M after the mode.
+ * rec.c (flocal_rec_await_reply): If there an M after the mode,
+ the remote is requesting a hangup.
+
+Sun Oct 31 23:43:40 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uux.c (zXnames): New static variable to hold list of file names
+ being sent.
+ (uxadd_name): Function to add a new name.
+ (main, uxadd_send_file): Call uxadd_name.
+ (main): Include zXnames in log message.
+
+Mon Oct 18 00:23:27 1993 Ian Lance Taylor (ian@airs.com)
+
+ * proti.c (fijstart): Ensure that packet size and window size are
+ reasonable; restrict window size to 16.
+
+ * proti.c (iIforced_remote_winsize): Removed, along with all
+ references.
+ (asIproto_params): Removed "remote-window".
+
+Sun Oct 17 22:15:14 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Mark Delany: protg.c (cGremote_duprrs): New static variable.
+ (fgstart): Initialize it.
+ (fgshutdown): Count rejects as cGremote_duprrs + cGremote_rejects.
+ (fgprocess_data): If cGremote_rejects is non-zero, don't treat
+ duplicate RR as reject. Count duplicate RR's in cGremote_duprrs,
+ not cGremote_rejects.
+
+ * Mark Delany: unix/serial.c (fsdouble_chat, fsysdep_conn_chat):
+ After running a chat program, reread the terminal characteristics.
+
+Wed Oct 13 20:46:46 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c (fdo_call): Fix typo.
+
+Thu Oct 7 22:28:45 1993 Ian Lance Taylor (ian@airs.com)
+
+ * unix/app3.c (zsappend3), unix/app4.c (zsappend4), unix/ftw.c
+ (ftw), unix/sindir.c (zsysdep_in_dir): Don't duplicate '/'
+ character for root directory.
+
+ * send.c (flocal_send_await_reply): If an SN comes in while the
+ file is being sent, seek to the end rather than setting fsendfile
+ to FALSE.
+ (flocal_send_cancelled): Don't send an empty packet.
+ * trans.c (utransfree): Set e field to EFILECLOSED when debugging.
+ (floop): Check for file send cancelled at top of loop, not middle.
+
+ * uucp.h (ffileseekend): Define.
+
+Wed Oct 6 00:51:08 1993 Ian Lance Taylor (ian@airs.com)
+
+ * proti.c (fisenddata, fiprocess_packet): Report channel numbers
+ in debugging messages.
+
+Tue Oct 5 00:00:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * unix/statsb.c (fsysdep_lock_status): Only report the status of a
+ particular job once, no matter how many lock files it has.
+
+ * uustat.c (fsnotify): Added itime argument. Changed all callers.
+ Report time job was queued in mail message.
+
+ * unix/cusub.c (fsysdep_terminal_raw): For TERMIO and TERMIOS,
+ clear IXON, IXOFF and IXANY (TERMIO only) in c_iflag.
+
+ * Lele Gaifax: log.c (ustats): Report device name.
+
+ * log.c (ulog): Use zsysdep_base_name of zProgram.
+
+ * uuxqt.c (main): Accept local system name and unknown system
+ names for -s argument. zsysdep_get_xqt may return an alias.
+
+Wed Sep 29 00:13:39 1993 Ian Lance Taylor (ian@airs.com)
+
+ * proti.c (fiprocess_packet): If sending an ACK for a NAK, don't
+ also send a packet.
+
+ * unix/serial.c (fsysdep_modem_end_dial): If TIOCWONLINE is not
+ defined, reopen the port to wait for carrier.
+
+ * policy.h: Use __ultrix__ as well as ultrix in check for
+ HAVE_STRIP_BUG.
+
+Tue Sep 28 22:25:05 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Marcel Waldvogel: uuchk.c (ukshow): Don't die if the call out
+ file can not be opened.
+
+Sun Sep 19 00:16:01 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Jason Molenda: policy.h (HAVE_SEQUENT_LOCKFILES): New
+ configuration parameter.
+ * sysh.unx, unix/serial.c: Implement it.
+
+ * uulog.c (main): Ignore any errors when trying to canonicalize
+ the system name.
+
+ * Marcel Waldvogel: uucico.c (faccept_call): If the calling system
+ is already locked, and we are using sequence numbers for it,
+ increment the local sequence number to keep in synch.
+
+ * unix/sleep.c (usysdep_sleep): If usysdep_pause is accurate, use
+ it. Otherwise call sleep, but always for at least two seconds.
+ * chat.c (fcsend): Call usysdep_sleep with 1, not 2.
+
+ * unix/pause.c: Correct USE_SELECT_TIMER to HAVE_SELECT.
+
+ * unix/serial.c (fsmodem_open): Only turn on hardware flow control
+ for an incoming connection.
+ (fsmodem_carrier): Turn on hardware flow control after turning on
+ carrier. Turn off hardware flow control before turning off
+ carrier.
+
+ * uuxqt.c (uqdo_xqt_file): Use known system name, not system name
+ from execution file, unless the former is a prefix of the latter.
+
+Sat Sep 18 16:53:41 1993 Ian Lance Taylor (ian@airs.com)
+
+ * policy.h: Add HAVE_ENCRYPTED_PASSWORDS configuration parameter.
+ * callin.c: Change interface to use a passed in comparison
+ function.
+ * uuconf.h: Change declaration of uuconf_callin.
+ * uucico.c (flogin_prompt): Change call to uuconf_callin.
+ (icallin_cmp): New function. Handle HAVE_ENCRYPTED_PASSWORDS.
+
+ * Hans-Dieter Doll: chat.c (fchat): Permit \W at the end of an
+ expect string to specify a timeout.
+
+ * util.c (zremove_local_sys): New function.
+ * uudefs.h: Declare zremove_local_sys.
+ * uucp.c (main): Read local system information. Ignore local
+ system name in front of arguments.
+ * uux.c (main): Ignore local system name in front of arguments.
+
+ * configure.in: Call AC_HAVE_POUNDBANG, AC_STAT_MACROS_BROKEN,
+ AC_TIME_WITH_SYS_TIME, AC_STRUCT_TM. Call AC_SUBST(POUNDBANG).
+ Remove HAVE_SYS_TIME_AND_TIME_H check. Rework disk space
+ configuration to actually check for the functions. Check for
+ function dev_info. Don't confuse HAVE_FTW_H and HAVE_FTW (from
+ Joe Wells).
+ * config.h.in (STAT_MACROS_BROKEN, TM_IN_SYS_TIME, STAT_DUSTAT,
+ STAT_DISK_SPACE, HAVE_DEV_INFO): New macros set by configure.
+ (TIME_WITH_SYS_TIME): Renamed from HAVE_SYS_TIME_AND_TIME_H.
+ * Makefile.in (POUNDBANG): Set to @POUNDBANG@.
+ (uusched, uuto): If POUNDBANG = no, turn #!/bin/sh into :.
+ (config.status): Use config.status --recheck.
+ (configure): Chdir to $(srcdir) before running autoconf.
+ * sysh.unx: If STAT_MACROS_BROKEN, undefine S_ISDIR.
+ * log.c, time.c, uustat.c, unix/loctim.c: If TM_IN_SYS_TIME,
+ include <sys/time.h>, not <time.h>.
+ * tstuu.c, unix/pause.c, unix/proctm.c, unix/serial.c: Rename
+ HAVE_SYS_TIME_AND_TIME_H to TIME_WITH_SYS_TIME.
+ * fsusg.c: Check STAT_DUSTAT, not _AIX and _I386.
+
+ * config.h.in: Renamed from conf.h.in.
+ * MANIFEST, configure.in, Makefile.in, lib/Makefile.in,
+ unix/Makefile.in, uuconf/Makefile.in, uucp.h: conf.h renamed to
+ config.h.
+
+Fri Sep 17 00:36:16 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Joe Wells: policy.h: If __QNX__, default to HAVE_POSIX_TERMIOS.
+
+ * Joe Wells: Makefile.in (FORCE): Add dummy command to work around
+ QNX make bug.
+
+ * Makefile.in, lib/Makefile.in, unix/Makefile.in,
+ uuconf/Makefile.in: Add .PHONY declaration for appropriate
+ commands.
+
+ * Joe Wells: Makefile.in (install): Create $(man1dir) and
+ $(man8dir) if necessary.
+ (install-info): Create $(infodir) if necessary.
+
+ * Joe Wells: sysh.unx (bsgrade): Declare as returning int rather
+ than char, since it can return a negative number.
+ * unix/work.c (bsgrade): Define as returning int.
+
+ * Joe Wells: unix/lock.c (fsdo_lock), unix/statsb.c
+ (fsysdep_lock_status): Use pid_t rather than int for variables
+ that hold pid's. Cast to long when using printf.
+
+ * Joe Wells: uucico.c (fcall): Fix test for 24 hour check when too
+ many retries.
+
+ * Joe Wells: uucico.c (fcall), unix/opensr.c
+ (esysdep_open_receive), unix/recep.c (fsysdep_already received):
+ Cast values in multiplication to determine seconds per day or per
+ week to long, because result is larger than 16 bits.
+
+ * Joe Wells: uuconv.c: Add return 0 after exit to avoid warnings.
+
+Thu Sep 16 23:53:58 1993 Ian Lance Taylor (ian@airs.com)
+
+ * Joe Wells: configure.in: Set AR from environment, defaulting to
+ ar, and substitute it in Makefiles.
+ * Makefile.in: Set AR to @AR@. Pass it down in MDEFINES.
+ * lib/Makefile.in, unix/Makefile.in, uuconf/Makefile.in: Set AR to
+ @AR@. Use $(AR) instead of ar. Use rc instead of qc (POSIX.2
+ does not define q).
+
+Wed Sep 15 00:47:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/callin.c (uuconf_callin): Take an additional argument: a
+ function to call to transform the login name and password. This
+ is a hack to avoid requiring escape sequence handling in uuconf.
+ * uucico.c (flogin_prompt): Pass cescape to uuconf_callin. This
+ is an incompatible change.
+ * uuconf.h (uuconf_callin): Update declaration.
+ * tstuu.c (uprepare_test): Use \s in password in Call1 and Pass2.
+
+ * chat.c (fcsend, fcprogram): Expand escape sequences in callout
+ login names and passwords. This is an incompatible change.
+
+ * Joe Wells: uustat.c (fsnotify): Add missing break statement.
+
+ * Mark Eichin: tstuu.c (main): Add some sleeps in the children to
+ make the tests more robust on Linux.
+
+ * uulog.c (ulhelp): Clean up general usage message: don't show -F
+ for HDB_LOGGING, don't show -x for non HDB_LOGGING. Remove
+ mention of numeric debugging levels.
+ * uustat.c (ushelp): Remove mention of numeric debugging levels.
+
+ * unix/serial.c (ICLEAR_CFLAG): Removed CLOCAL.
+ (enum tclocal_setting): New enum.
+ (fsserial_lock): Don't call TIOCSCTTY.
+ (fsserial_open): Changed flocal argument to tlocal. Use it to
+ determine initial CLOCAL setting for TERMIO and TERMIOS. Don't
+ call TIOCSCTTY until after setting the terminal state.
+ (fsstdin_open): Call fsserial_open with IGNORE_CLOCAL.
+ (fsmodem_open): Call fsserial_open with SET_CLOCAL if calling out,
+ CLEAR_CLOCAL if waiting for an incoming call.
+ (fsdirect_open): Call with SET_CLOCAL or CLEAR_CLOCAL depending
+ upon fcarrier setting.
+ * uuconf.h (struct uuconf_direct_port): Added fcarrier field.
+ * uuconf/tportc.c (asPdirect_cmds): Added ``carrier'' command.
+ (_uuconf_iport_cmd): Initialize direct fcarrier field to FALSE.
+ * uuconf/hport.c (uuconf_hdb_find_port), uuconf/vport.c
+ (uuconf_v2_find_port): Set direct fcarrier field to FALSE.
+ * uuchk.c (ikshow_port): Print direct port carrier field.
+ * uuconv.c (uvwrite_taylor_port): Likewise.
+
+ * uustat.c (main, fsquery, fsquery_systems, fsquery_show): Support
+ -o, -y, -s and -S in conjunction with -q.
+
+Tue Sep 14 00:51:50 1993 Ian Lance Taylor (ian@airs.com)
+
+ * log.c (ulog): If we can't open the log file, print an error on
+ stderr.
+
+ * configure.in, conf.h.in: Adjusted for autoconf 1.5.
+
+Sun Sep 12 15:52:29 1993 Ian Lance Taylor (ian@airs.com)
+
+ * unix/serial.c (fsserial_open): Add flocal argument. Changed all
+ callers. Pass it as TRUE when dialing out on a modem. This is
+ supposedly required on 386bsd.
+
+ * conn.c (fconn_dial_sequence): New function.
+ (fmodem_dial): Use fconn_dial_sequence. Call fsysdep_modem_begin
+ only once, before entire sequence, and fsysdep_modem_end only
+ once, after entire sequence. Don't call fcdo_dial.
+ (fcdo_dial): Removed.
+ * conn.h: Declare fconn_dial_sequence.
+ * uucico.c (fconn_call): Don't free dialer if fconn_dial fails.
+ * uuconf.h (struct uuconf_tcp_port): Add pzdialer field.
+ * tcp.c (ftcp_dial): Pass new pzdialer field to
+ fconn_dial_sequence.
+ * tli.c (ftli_dial): Pass pzdialer to fconn_dial_sequence.
+ * uuconf/hport.c (uuconf_hdb_find_port): Add trailing dialer
+ sequence to pzdialer field for TCP port.
+ * uuconf/tportc.c (asPtcp): Add ``dialer-sequence'' command.
+ (_uuconf_iport_cmd): Initialize pzdialer for TCP port.
+ * uuconf/vsinfo.c (_uuconf_iv2_system_internal): Initialize
+ pzdialer for TCP port.
+ * uuchk.c (ikshow_port): Print TCP pzdialer field.
+ * uuconv.c (uvwrite_taylor_port, ivwrite_hdb_port): Output TCP
+ pzdialer field.
+
+Sat Sep 11 16:30:17 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uulog.c, uuname.c (main): Pass INIT_NOCHDIR to
+ usysdep_initialize.
+
+ * uucp.1, uustat.1, uux.1, uuxqt.8: Remove uses of nonportable .EX
+ and .EE macros.
+
+ * uuxqt.c (asQcmds, iqout, iqfile, iqrequestor, iquser): Remove
+ restrictions on number of arguments to commands in execution file,
+ since is there is such a range of buggy UUCP implementations out
+ there.
+
+ * sysh.unx (CORRUPTDIR): Define.
+ * unix/corrup.c: New file for new zsysdep_save_corrupt_file
+ function to save a file in CORRUPTDIR.
+ * unix/Makefile.in, unix/MANIFEST: Add corrup.
+ * system.h: Add declaration of zsysdep_save_corrupt_file.
+ * uuxqt.c (uqdo_xqt_file): If execution file has a syntax error,
+ save it using zsysdep_save_corrupt_file and notify OWNER.
+
+ * uuconf/hsinfo.c (_uuconf_ihdb_system_internal), vsinfo.c
+ (_uuconf_iv2_system_internal): Treat a specified time/grade as
+ both a timegrade and a call-timegrade.
+
+ * rec.c (frec_file_end): If the received file can not be moved to
+ the final location, and there is enough disk space, keep the file,
+ mentioned the saved name in the error message, and send mail to
+ OWNER about it. If the hand created execution file can not be
+ moved, delete it.
+ * unix/move.c (fsysdep_move_file): Don't delete the original file
+ if the move fails.
+ * unix/splcmd.c (zsysdep_spool_commands): Remove the temporary
+ file if the move fails.
+
+Wed Sep 1 23:29:30 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/tinit.c (itdebug, _uuconf_idebug_cmd): New functions.
+ (asCmds): Call itdebug for "debug", to accept spaces between
+ options as well as commas.
+ * uuconf/tsinfo.c (iidebug): New function.
+ (asIcmds): Call iidebug for "debug".
+ * uuconf/uucnfi.h: Added prototype for _uuconf_idebug_cmd.
+
+Tue Aug 31 00:09:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * send.c (flocal_send_file_init): Don't set flocal if job was
+ requested by a remote user.
+ (flocal_send_fail, flocal_send_open_file): Don't save temporary
+ file in .Preserve if job was requested by a remote user.
+
+ * unix/wldcrd.c (fsysdep_wildcard_start): Don't free zcmd until
+ after calling espopen.
+
+ * lib/buffer.c (ubuffree): Added debugging code controlled by
+ DEBUG_BUFFER macro.
+
+Sun Aug 29 13:33:21 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uuconf/tcalou.c: Permit empty password in call file.
+
+ * unix/work.c (COMMANDS_PER_SCAN): New macro.
+ (fsysdep_get_work_init): Get at most COMMANDS_PER_SCAN new command
+ files, to avoid timeouts while reading a large directory.
+
+ * rec.c (fremote_send_file_init): Initialize crestart.
+
+ * uux.c (main): Changed special handling of single "-" argument to
+ call getopt multiple times.
+
+ * D.J. James: protg.c (fgsendcmd, fgsenddata), prott.c
+ (ftsendcmd): Avoid passing 0 to bzero to avoid SunOS bug.
+
+ * protf.c (ffprocess_data): Some systems seem to send characters
+ with parity, so strip the parity bit from incoming bytes.
+
+ * Kenji Rikitake: uucp.h: Changed order of header files to avoid
+ gcc stddef.h vs. sys/stdtypes.h problem on SunOS 4.1.
+
+ * Alexander Lehmann: configure.in: Correct misspelling of
+ HAVE_GETWD.
+
+ * John Hood: unix/filnam.c (ZCHARS): Get the alphabet right.
+
+ * Gabor Kiss: tcp.c (ftcp_dial): Use all gethostbyname info before
+ calling getservbyname.
+
+Thu Aug 26 23:15:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uux.c, uuxqt.c: Added long options.
+
+ * uucp.c: Added v to getopt_long argument, print help and version
+ info to stderr.
+
+ * unix/splcmd.c (zsysdep_spool_commands): Create command file via
+ temporary file, so that the command file is created atomically.
+ * unix/spool.c (zscmd_file): Accept files starting with "TMP".
+
+Sun Jul 25 14:50:41 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uupick.c, uustat.c: Added long options.
+
+Mon Jul 19 22:06:19 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uucico.c, uuconv.c, uucp.c, uulog.c, uuname.c: Added long
+ options.
+ * uucico.c (main, fcall): Made -c option not print the ``No work''
+ log message.
+ * uuname.c (main): Call ulog_uuconf rather than unuuconf_error.
+
+Sun Jul 11 14:29:39 1993 Ian Lance Taylor (ian@airs.com)
+
+ * cu.c, uuchk.c: Added long options.
+
+ * uudefs.h, log.c (zProgram): Renamed from abProgram.
+ * cu.c, uucico.c, uucp.c, uulog.c, uuname.c, uupick.c, uustat.c,
+ uux.c, uuxqt.c (main): Initialize zProgram from argv[0].
+
+ * Bob Hemedinger: unix/cohtty.c (fscoherent_disable_tty): Almost
+ always return TRUE.
+ * unix/serial.c (fsserial_lockfile): Skip "LCK.." in string passed
+ to lockttyexist and fscoherent_disable_tty.
+ * uucico.c (main): If __COHERENT__ is defined, change the meaning
+ of -c for backward compatibility with old Coherent UUCP.
+
+ * David Nugent: uucico.c (main): Added -C option to only call
+ system named by -s or -S if there is work.
+
+ * uuconf/syssub.c (_uuconf_isystem_default): Merge in default
+ protocol parameters so that setting parameters for one protocol
+ does not lose the default settings for other protocols.
+
+ * unix/lcksys.c (zssys_lock_name): New function.
+ (fsysdep_lock_system, fsysdep_unlock_system): Use it.
+
+ * John Plate: uuchk.c (ukshow): Call ukshow_size with the right
+ arguments in the called remote case.
+
+ * uuconf/remunk.c (uuconf_remote_unknown): use the remote.unknown
+ shell script if HDB_CONFIG and no ``unknown'' commands appeared in
+ the config file.
+
+ * Jim Brownfield: uuconf/vsinfo.c (_uuconf_iv2_system_internal):
+ Accept continuation lines in L.sys.
+
+ * Marc Evans: unix/serial.c (fsysdep_conn_write, fsysdep_conn_io):
+ Add casts to t_snd calls to avoid warnings.
+
+ * Julian Stacey: uuchk.c (main): If no information found, say so.
+
+ * Ju"rgen Fluk: uulog.c (main): Better error messages for HDB.
+
+ * uucico.c (zget_typed_line): If last string ended in \r, ignore
+ leading \n.
+
+ * Mark E. Mallett: uuconf/time.c (asTdays): Add "none".
+
+ * uuconf/hsinfo.c (_uuconf_ihdb_system_internal): Report line
+ numbers for syntax errors.
+
+Sat Jul 10 10:28:03 1993 Ian Lance Taylor (ian@airs.com)
+
+ Initial hardware flow control support from Peter Wemm:
+ * uuconf.h (struct uuconf_modem_port, struct uuconf_direct_port):
+ New field uuconf_fhardflow in each structure.
+ * unix/serial.c (fsserial_hardflow): New routine. Initially
+ supports SunOS and SCO Unix.
+ (fsmodem_open, fsdirect_open): Turn on hardware flow control if
+ supported by the port.
+ (fsserial_set): If CRTFSL is set, don't send XON/XOFF characters.
+ * uuconf/hport.c (uuconf_hdb_find_port), uuconf/tportc.c
+ (_uuconf_iport_cmd), uuconf/vport.c (uuconf_v2_find_port):
+ Initialize uuconf_fhardflow field to TRUE.
+ * uuconf/tportc.c (struct asPmodem_cmds, struct asPdirect_cmds):
+ Added "hardflow" command.
+ * uuchk.c (ikshow_port): Report whether hardware flow control is
+ available.
+ * uuconv.c (uvwrite_taylor_port): Write out hardware flow control
+ information.
+
+ * Peter Wemm: protg.c (fgstart), proti.c (fijstart): Report local
+ packet and window size as well as remote.
+ * rec.c (fremote_send_file_init), send.c (flocal_send_open_file,
+ fremote_rec_reply): Report number of bytes being sent or received,
+ and restart point if any.
+
+ * Peter Wemm: trans.h (struct sdaemon): New fields csent and
+ creceived.
+ * uucico.c (fcall, faccept_call): Initialize csent and creceived.
+ (fdo_call, faccept_call): Report on number of file bytes
+ transferred and bytes per second.
+ * rec.c (frec_file_end): Record number of bytes received.
+ * send.c (fsend_wait_confirm): Record numbers of bytes sent.
+ * trans.c (ufailed): Record number of bytes sent or received.
+
+ * Peter Wemm: uusched.in, uuto.in: Use #!/bin/sh rather than :.
+ Use exec when invoking program.
+
+ * uulog.c (main): Don't die if we can't canonicalize the -s
+ argument.
+
+ * unix/cusub.c (uscu_child): Force the descriptor into blocking
+ mode.
+
+ Port type pipe support contributed by Marc Boucher:
+ * unix/pipe.c: New file. Support routines for pipes.
+ * unix/MANIFEST, unix/Makefile.in: Adjusted for new file pipe.c.
+ * uuconf.h (enum uuconf_porttype): Added UUCONF_PORTTYPE_PIPE.
+ (struct uuconf_pipe_port): New structure.
+ (struct uuconf_port): Added uuconf_pipe_port to union.
+ * sysh.unx (struct ssysdep_conn): Add fields ord, owr and ipid,
+ rename istdout_flags to iwr_flags.
+ (fsdouble_{read, write, chat}): New prototypes.
+ * conn.h: Prototype for fsysdep_pipe_init.
+ * unix/serial.c: Renamed fsstdin_{read, write, chat} to
+ fsdouble_{read, write, chat}. Made them non-static. Changed them
+ to use ord and owr fields rather than 0 and 1.
+ (fsserial_init, fsstdin_open): Initialize ord and owr fields.
+ (fsstdin_close, fsblock, fsstdin_reset, fsysdep_conn_io,
+ fsstdin_break, fsstdin_set): Use ord and owr fields rather than 0
+ and 1.
+ * uuconf/tportc.c (asPtype_names): Added "pipe".
+ (asPpipe_cmds, CPIPE_CMDS): New array of pipe commands.
+ (CCMDS, _uuconf_iport_cmd): Adjusted accordingly.
+ * tcp.c (fsysdep_tcp_init), tli.c (fsysdep_tli_init): Initialize
+ new ord and owr fields.
+ * conn.c (fconn_init): Call fsysdep_pipe_init for
+ UUCONF_PORTTYPE_PIPE.
+ * unix/cusub.c (zsport_line, uscu_child, fsysdep_shell): Handle
+ UUCONF_PORTTYPE_PIPE.
+ * uuchk.c (ikshow_port): Report on port type pipe.
+ * uuconv.c (uvwrite_taylor_port): Write out port type pipe.
+
+ * Marc Boucher: cu.c: (main, ucuabort): Use new variable
+ fCuconnprinted to avoid printing ZDISMSG if ZCONNMSG has not been
+ printed.
+ (main): Call fsysdep_port_access only after we have locked the
+ port, to get a better error message on systems with shared lines.
+
+ * Marc Boucher: policy.h (HAVE_FULLDUPLEX_PIPES): New macro.
+ * unix/spawn.c (ixspawn): Use it.
+
+ * Marc Boucher: uucico.c (uusage): Added lines for -c and -D.
+
+ * uuconf/time.c (_uuconf_itime_parse): Add casts to avoid a
+ compiler warning.
+
+ * uustat.c (fsworkfile_show): Don't report non-existent send
+ files.
+
+ * lib/parse.c (fparse_cmd): Accept any base for the mode argument,
+ rather than always using 8. Depend upon the leading zero to
+ indicate base 8. Accomodates UFGATE 1.03.
+
+Wed Jun 30 00:27:27 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uudefs.h (struct scmd): Changed bdummy field to bgrade.
+ * trans.c (fqueue_send): Sort sends by whether they are a command
+ and then by grade.
+ * unix/work.c (asSwork_files): Renamed from azSwork_files, made
+ array of struct ssfilename rather than char *.
+ (struct ssfile): Added bgrade field.
+ (iswork_cmp, fsysdep_get_work_init, usysdep_get_work_freed):
+ Changed accordingly.
+ (fsysdep_get_work): Set qcmd->bgrade.
+ * uucp.c (uccopy), uux.c (main, uxadd_send_file), uuxqt.c
+ (uqdo_xqt_file), xcmd.c (fremote_xcmd_init), lib/parse.c
+ (fparse_cmd): Initialize bgrade field of scmd structure.
+
+Sun Jun 27 23:21:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * send.c (flocal_send_await_reply, flocal_send_cancelled): If the
+ first D. file being sent for a faked E command fails, send the
+ second one anyhow.
+
+Sun Jun 6 23:07:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * proti.c (fiprocess_data): If we get a packet we sent a NAK for,
+ forget that sent NAKs for all preceding packets.
+ (fiprocess_packet): If we get a NAK for the packet we are about to
+ send, and all our packets have been acknowledged, send an ACK.
+
+Thu Jun 3 20:54:55 1993 Ian Lance Taylor (ian@airs.com)
+
+ * prot.h (struct sprotocol): Added frestart field.
+ * uucico.c (asProtocols): Initialize frestart field.
+ * system.h, unix/opensr.c (zsysdep_receive_temp): Added frestart
+ argument to zsysdep_receive_temp.
+ * rec.c (flocal_rec_send_request, fremote_send_file_init,
+ frec_file_end): Pass frestart argument to zsysdep_receive_temp.
+ * unix/opensr.c (esysdep_open_receive): Permit pcrestart argument
+ to be NULL.
+ * rec.c (flocal_rec_await_reply, fremote_send_file_init): Pass
+ pcrestart argument to esysdep_open_receive as NULL if file
+ tranfers can not be restarted.
+
+ * lib/status.c (azStatus): Uwe Doering: If SPOOLDIR_HDB or
+ SPOOLDIR_SVR4, use the same strings they use.
+ * unix/status.c (aiMapstatus): Uwe Doering: Swap 4 and 20.
+
+ * unix/serial.c (fsserial_open): Uwe Doering: Set VTIME to 1.
+
+ * uucico.c (faccept_call, uaccept_call_cleanup): Uwe Doering: Free
+ and unlock evertyhing after any return from faccept_call.
+ (main): Don't need to unlock after faccept_call here any more.
+
+ * proti.c (fiprocess_data): Added additional debugging
+ information.
+
+Sat May 15 13:55:21 1993 Ian Lance Taylor (ian@airs.com)
+
+ * protg.c (fgprocess_data): Don't treat a duplicate RR as an RJ if
+ we are retransmitting packets. If we are treating a duplicate RR
+ as an RJ, don't also treat it as an acknowledgement.
+
+ * unix/serial.c (fsysdep_conn_io): Typo in debugging message.
+
+Tue May 4 00:03:32 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uux.c (main): Andreas Raab: Move aboptions out of local block
+ since a pointer to it escapes the scope.
+
+ * unix/mkdirs.c: W Christopher Martin: Just try to make the
+ directories, and ignore EEXIST errors, rather than first checking
+ whether the directory exists.
+
+ * send.c (flocal_send_request): Chip Salzenberg: Double check that
+ the file still exists before sending the S command.
+
+ * uucico.c (zget_uucp_cmd, zget_typed_line), trans.c (fgot_data):
+ Matthew Geier: Avoid doing memcpy (z, NULL, 0).
+
+Mon May 3 22:52:46 1993 Ian Lance Taylor (ian@airs.com)
+
+ * system.h, unix/locfil.c, unix/cwd.c, unix/picksb.c: Johan
+ Vromans: Added pfbadname argument to zsysdep_local_file,
+ zsysdep_local_file_cwd, zsysdep_uupick_local_file.
+ * Changed all callers.
+ * send.c (fremote_rec_file_init), rec.c (fremote_send_file_init):
+ If remote system gives bad name, return an error rather than
+ aborting the connection.
+ * uuxqt.c (uqdo_xqt_file): If bad file name, abort execution
+ rather than try again later.
+ * uupick.c (main): If bad file name, permit new command rather
+ than exiting.
+
+ * lib/debug.c: Stephan Niemz: Accept whitespace separated
+ debugging types.
+
+ * unix/detach.c: Always use setsid if it is available.
+
+Sun May 2 13:23:33 1993 Ian Lance Taylor (ian@airs.com)
+
+ * unix/spool.c (zsfind_file): Fix handling of execution file
+ names for systems to work with any possible execution file name.
+
+ * send.c (flocal_send_open_file): Subtract starting position from
+ number of bytes passed to pffile.
+
+ * uuconf/rdperm.c: Syd Weinstein: Don't skip lines in Permissions
+ with leading whitespace.
+
+ * uuconf/vsinfo.c: Gero Kuhlmann: Set default retry time
+ correctly.
+
+ * unix/lock.c (fsdo_lock): Andrew Vignaux: Handle readonly lock
+ files correctly.
+
+ * send.c (flocal_send_fail, flocal_send_await_reply): James Van
+ Artsdalen: Clarify error messages relating to execution files.
+
+ * log.c (ustats): Avoid overflow in bytes/sec calculation.
+
+Sat May 1 17:40:14 1993 Ian Lance Taylor (ian@airs.com)
+
+ * trans.c (ftadd_cmd): Don't treat junk at end of command as a
+ size if the remote system doesn't support sizes.
+
+ * uucico.c (faccept_call): Turn on the protocol before reading the
+ queue, in case there are lots of command files.
+
+ * unix/cusub.c: Julian Stacey: If SIGUSR2 is not defined, use
+ SIGURG instead.
+
+ * uuconf/syshdr.unx (MAKE_ABSOLUTE): New macro.
+ * uuconf/tinit.c (itaddfile): Renamed from itadd. Use
+ MAKE_ABSOLUTE to force absolute pathnames to configuration files.
+
+ * conn.c (fconn_close): Steve M. Robbins: Ignore any SIGHUP
+ received after closing the connection.
+
+ * cu.c (main): Frank Conrad: When an alternate fails, move on to
+ the next one.
+
+ * uucico.c (faccept_call): Alexei K. Yushin: Supposedly some
+ UUCP's send UgG rather than just Ug.
+
+ * unix/serial.c (fsserial_lockfile): Bob Hemedinger: Fix error
+ message in HAVE_COHERENT_LOCKFILES case.
+
+ * unix/mkdir.c: Andy Fyfe: Pass fkeepuid as TRUE to ixsspawn.
+
+ * unix/strerr.c: Undefine strerror in case there is a macro
+ definition which configure did not pick up.
+
+ * configure.in: Andy Fyfe: AT&T 3b1 has sys/mount.h but not
+ statfs.
+
+ * uudir.c: Andy Fyfe: Include uucp.h.
+
+ * unix/fsusg.c: Andy Fyfe: Typos in (untested) STAT_USTAT case.
+
+ * unix/filnam.c: Eric Lee Green: Avoid generating filenames that
+ only differ in case, to make life easier for bad filesystems.
+
+ * uuconf/llocnm.c: Brian J. Murrell: Don't read HDB files if
+ ``hdb-files no'' given.
+
+Sat Mar 20 16:10:20 1993 Ian Lance Taylor (ian@airs.com)
+
+ * uudefs.h (eSendfile, eRecfile): Deleted obsolete declarations.
+
+Sat Feb 13 15:57:30 1993 Ian Lance Taylor (ian@airs.com)
* Released version 1.04.
* unix/detach.c: Andrew A. Chernov: Don't check return of setsid.
-Sun Jan 31 01:45:56 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sun Jan 31 01:45:56 1993 Ian Lance Taylor (ian@airs.com)
* cu.c (main): Pass "cu" to uuconf_init.
* protz.c (fzprocess): Restore ZPAD char before calling getinsync.
-Sat Jan 30 22:19:26 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jan 30 22:19:26 1993 Ian Lance Taylor (ian@airs.com)
* Makefile.in (doc-dist): New target.
-Wed Jan 27 22:55:26 1993 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jan 27 22:55:26 1993 Ian Lance Taylor (ian@airs.com)
* protg.c (fgstart): Set iGremote_segsize when using
remote-packet-size.
-Tue Jan 26 01:01:34 1993 Ian Lance Taylor (ian@comton.airs.com)
+Tue Jan 26 01:01:34 1993 Ian Lance Taylor (ian@airs.com)
* proti.c (fiprocess_data): always send an ACK after receiving
half a window, rather than sometimes resending a packet. Half a
@@ -28,7 +1263,7 @@ Tue Jan 26 01:01:34 1993 Ian Lance Taylor (ian@comton.airs.com)
* tstuu.c (main, cread, fsend): rewrote communication routines to
avoid deadlock.
-Sun Jan 24 01:02:47 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sun Jan 24 01:02:47 1993 Ian Lance Taylor (ian@airs.com)
* trans.c (ufailed): don't report statistics if no bytes
transferred.
@@ -36,27 +1271,27 @@ Sun Jan 24 01:02:47 1993 Ian Lance Taylor (ian@comton.airs.com)
* Makefile.in (install): simplified somewhat.
(dist): distribute the sample directory.
-Sat Jan 23 19:47:12 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jan 23 19:47:12 1993 Ian Lance Taylor (ian@airs.com)
* configure.in, conf.h.in, tli.c: Karl Swarz: check for and use
<sys/tli.h>.
-Fri Jan 22 00:09:37 1993 Ian Lance Taylor (ian@comton.airs.com)
+Fri Jan 22 00:09:37 1993 Ian Lance Taylor (ian@airs.com)
* send.c (flocal_send_request): Alan Judge: don't send C in option
string when faking an E command as an S command.
-Thu Jan 21 00:09:31 1993 Ian Lance Taylor (ian@comton.airs.com)
+Thu Jan 21 00:09:31 1993 Ian Lance Taylor (ian@airs.com)
* uux.c (main): don't use E command if forwarding.
-Wed Jan 20 00:22:38 1993 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jan 20 00:22:38 1993 Ian Lance Taylor (ian@airs.com)
* send.c (fsend_exec_file_init), rec.c (frec_file_end), uux.c
(main): Chip Salzenberg: always put the C line last in an
execution file, to support Fredmail.
-Tue Jan 19 00:09:43 1993 Ian Lance Taylor (ian@comton.airs.com)
+Tue Jan 19 00:09:43 1993 Ian Lance Taylor (ian@airs.com)
* trans.h, trans.c (ftcharge, floop, fgot_data): rewrote timing
code.
@@ -65,7 +1300,7 @@ Tue Jan 19 00:09:43 1993 Ian Lance Taylor (ian@comton.airs.com)
(fqueue_local, fqueue_remote, fqueue_send, fqueue_receive): added
boolean return value and qdaemon argument.
-Mon Jan 18 00:01:46 1993 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jan 18 00:01:46 1993 Ian Lance Taylor (ian@airs.com)
* uucico.c (fdo_call, faccept_call): Ted Lindgreen, Chip
Salzenberg: wait for remote hangup string before hanging up.
@@ -73,7 +1308,7 @@ Mon Jan 18 00:01:46 1993 Ian Lance Taylor (ian@comton.airs.com)
* proti.c (fiprocess_data, fiprocess_packet): stop scanning input
buffer after a CLOSE packet.
-Sat Jan 16 22:44:28 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jan 16 22:44:28 1993 Ian Lance Taylor (ian@airs.com)
* system.h, uucico.c (main), uuxqt.c (main), unix/init.c: Ted
Lindgreen: eliminated INIT_DAEMON.
@@ -88,7 +1323,7 @@ Sat Jan 16 22:44:28 1993 Ian Lance Taylor (ian@comton.airs.com)
* policy.h, unix/pause.c: Gregory Gulik: added HAVE_HUNDREDTHS_NAP
configuration parameter.
-Wed Jan 6 21:06:45 1993 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jan 6 21:06:45 1993 Ian Lance Taylor (ian@airs.com)
* unix/serial.c (fsserial_lockfile): create HDB lock files when
using HAVE_COHERENT_LOCKING.
@@ -98,11 +1333,11 @@ Wed Jan 6 21:06:45 1993 Ian Lance Taylor (ian@comton.airs.com)
* unix/cusub.c (fsysdep_terminal_raw): Andrew A. Chernov: if
POSIX_TERMIOS, turn of IEXTEN flag.
-Sat Jan 2 23:19:27 1993 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jan 2 23:19:27 1993 Ian Lance Taylor (ian@airs.com)
* protg.c (fgprocess_data): treat a duplicate RR as an RJ.
-Fri Jan 1 11:17:30 1993 Ian Lance Taylor (ian@comton.airs.com)
+Fri Jan 1 11:17:30 1993 Ian Lance Taylor (ian@airs.com)
* policy.h, unix/proctm.c: Steven S. Dick: use sysconf
(_SC_CLK_TCK) for TIMES_TICK if possible.
@@ -113,7 +1348,7 @@ Fri Jan 1 11:17:30 1993 Ian Lance Taylor (ian@comton.airs.com)
unix/run.c: Karsten Thygesen: removed ffork argument from
fsysdep_run.
-Wed Dec 30 00:21:55 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Dec 30 00:21:55 1992 Ian Lance Taylor (ian@airs.com)
* unix/link.c: Andrey G Blochintsev: don't fail just because
destination directories do not exist.
@@ -123,12 +1358,12 @@ Wed Dec 30 00:21:55 1992 Ian Lance Taylor (ian@comton.airs.com)
* protz.c: Chip Salzenberg: reformatted to 80 columns.
-Tue Dec 29 23:50:52 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Dec 29 23:50:52 1992 Ian Lance Taylor (ian@airs.com)
* uuconv.c (uvwrite_time): scott@geom.umn.edu: handle midnight
more correctly.
-Fri Dec 18 00:49:16 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Dec 18 00:49:16 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uucp.c (uccopy), uux.c (main), cu.c (icuput, icutake),
unix/ufopen.c (esysdep_user_fopen): Doug Evans: open files used
@@ -136,7 +1371,7 @@ Fri Dec 18 00:49:16 1992 Ian Lance Taylor (ian@comton.airs.com)
privileges of uucp. Added frd and fbinary arguments to
esysdep_user_fopen.
-Thu Dec 17 00:04:53 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Dec 17 00:04:53 1992 Ian Lance Taylor (ian@airs.com)
* unix/picksb.c (zsysdep_uupick): Peter Wemm: allocation error.
@@ -150,14 +1385,14 @@ Thu Dec 17 00:04:53 1992 Ian Lance Taylor (ian@comton.airs.com)
(fsend_await_confirm), rec.c (frec_file_end): Peter Wemm: added
fmaster argument to ustats, used only in HDB_LOGGING.
-Wed Dec 16 23:35:51 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Dec 16 23:35:51 1992 Ian Lance Taylor (ian@airs.com)
* uustat.c (main): Marc Unangst: forgot to call strtol for -y.
* policy.h, sysh.unx: Brian J. Murrell: yet another configuration
parameter: HAVE_BROKEN_SETREUID.
-Tue Dec 15 00:13:04 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Dec 15 00:13:04 1992 Ian Lance Taylor (ian@airs.com)
* uuconv.c (uvwrite_taylor_system): mnichols@pacesetter.com: use
command-path rather than path.
@@ -181,18 +1416,18 @@ Tue Dec 15 00:13:04 1992 Ian Lance Taylor (ian@comton.airs.com)
FREE_SPACE_DELTA bytes, and abort the file transfer if disk space
gets too low.
-Wed Dec 2 00:24:12 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Dec 2 00:24:12 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, unix/serial.c (fsserial_set): Frank Conrad: added
HAVE_PARITY_BUG parameter for the Sony NEWS.
-Mon Nov 30 00:06:59 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Nov 30 00:06:59 1992 Ian Lance Taylor (ian@airs.com)
* lib/spool.c (fspool_file): Andrew Chernov: accept any
alphanumeric character in the name, because it could be a grade
from another system.
-Sun Nov 29 22:36:47 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Nov 29 22:36:47 1992 Ian Lance Taylor (ian@airs.com)
* lib/buffer.c (ubuffree): scott@geom.umn.edu, Richard Gumpertz:
use a temporary variable to hold the offsetof result.
@@ -212,14 +1447,14 @@ Sun Nov 29 22:36:47 1992 Ian Lance Taylor (ian@comton.airs.com)
* rec.c (fremote_send_reply): do file restart correctly for E
commands.
-Sun Nov 22 15:09:43 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Nov 22 15:09:43 1992 Ian Lance Taylor (ian@airs.com)
* protz.c: Chip Salzenberg: always do bitwise operations on
unsigned values.
* getopt.h: Chip Salzenberg: don't rely on __STDC__.
-Thu Nov 19 00:13:46 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Nov 19 00:13:46 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/freblk.c: Niels Baggesen: loop over the right list.
@@ -227,7 +1462,7 @@ Thu Nov 19 00:13:46 1992 Ian Lance Taylor (ian@comton.airs.com)
take an argument and default to showing 10 current lines.
(ulusage): added new options and missing old ones.
-Wed Nov 18 22:26:36 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Nov 18 22:26:36 1992 Ian Lance Taylor (ian@airs.com)
* rec.c (frec_file_end): Andrey G Blochintsev: call
fsysdep_remember_reception as soon as the file has been moved to
@@ -239,7 +1474,7 @@ Wed Nov 18 22:26:36 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/tmpfil.c (ZDIGS): don't use '.', since we use it to
separate parts of the file name.
-Sun Nov 15 15:31:49 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Nov 15 15:31:49 1992 Ian Lance Taylor (ian@airs.com)
* uustat.c (fsquery_show, csunits_show): Marc Unangst, Chip
Salzenberg: line up uustat -q output.
@@ -282,7 +1517,7 @@ Sun Nov 15 15:31:49 1992 Ian Lance Taylor (ian@comton.airs.com)
* configure.in: Brian Campbell: check for /usr/bin/mailx.
-Sat Nov 14 11:11:04 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Nov 14 11:11:04 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/hlocnm.c (uuconf_hdb_login_localname): Christian Seyb:
check for _uuconf_unset as well as NULL.
@@ -294,7 +1529,7 @@ Sat Nov 14 11:11:04 1992 Ian Lance Taylor (ian@comton.airs.com)
and made _uuconf_unset char * to avoid possible alignment
problems.
-Tue Nov 10 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Nov 10 00:16:35 1992 Ian Lance Taylor (ian@airs.com)
* trans.h, uucico.c (fcall, faccept_call), trans.c (uclear_queue,
floop): Stephen J. Walick: move clean up from end of floop into
@@ -305,13 +1540,13 @@ Tue Nov 10 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com)
location for HAVE_SVR4_LOCKFILES.
(fsserial_init): Doug Evans: null terminate the device name.
-Sun Nov 8 10:58:59 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Nov 8 10:58:59 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (fcall, faccept_call): Stephen J. Walick: call
usysdep_get_work_free here.
trans.c (floop): don't call usysdep_get_work free here.
-Sun Nov 1 17:05:07 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Nov 1 17:05:07 1992 Ian Lance Taylor (ian@airs.com)
* Released gamma version 1.04.
@@ -326,7 +1561,7 @@ Sun Nov 1 17:05:07 1992 Ian Lance Taylor (ian@comton.airs.com)
* policy.h, unix/cohtty.c: Bob Hemedinger: finish Coherent style
locking.
-Wed Oct 28 00:20:15 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Oct 28 00:20:15 1992 Ian Lance Taylor (ian@airs.com)
* tstuu.c: Ralf Stephan: check HAVE_POLL_H and HAVE_STROPTS_H.
@@ -338,7 +1573,7 @@ Wed Oct 28 00:20:15 1992 Ian Lance Taylor (ian@comton.airs.com)
requested position.
uucp.c, uux.c, uuxqt.c, xcmd.c: initialize ipos field.
-Sun Oct 25 10:39:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Oct 25 10:39:23 1992 Ian Lance Taylor (ian@airs.com)
* unix/serial.c (fsysdep_conn_write, fsysdep_conn_io): T. William
Wells: take special care to ensure we don't write after SIGHUP.
@@ -350,7 +1585,7 @@ Sun Oct 25 10:39:23 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/cusub.c (uscu_child): Igor V. Semenyuk: accept a 0 return
from read until we have read some data at some point.
-Thu Oct 22 10:38:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Oct 22 10:38:32 1992 Ian Lance Taylor (ian@airs.com)
* proti.c: various tweaks for bad connections.
@@ -363,7 +1598,7 @@ Thu Oct 22 10:38:32 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuxqt.c (uqdo_xqt_file): Bob Hemedinger: don't take address of
array.
-Wed Oct 21 00:05:31 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Oct 21 00:05:31 1992 Ian Lance Taylor (ian@airs.com)
* uustat.c (fsnotify): Gert Doering: if the file appears to be
binary, don't include it in any mail message.
@@ -391,7 +1626,7 @@ Wed Oct 21 00:05:31 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucico.c (fdo_call, faccept_call): Hans-Dieter Doll: avoid
overflow when turning ulimit value into bytes.
-Tue Oct 20 23:12:26 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Oct 20 23:12:26 1992 Ian Lance Taylor (ian@airs.com)
* serial.c (fsmodem_carrier): Hans-Dieter Doll: use IS68K LNOMDM
bit if available.
@@ -403,7 +1638,7 @@ Tue Oct 20 23:12:26 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/run.c: Peter Wemm: pass fsetuid as TRUE to ixsspawn.
-Sun Oct 18 13:58:17 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Oct 18 13:58:17 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, unix/serial.c (fsmodem_close): Stephen J. Walick:
added HAVE_RESET_BUG for SCO Xenix.
@@ -413,18 +1648,18 @@ Sun Oct 18 13:58:17 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/ufopen.c: Igor V. Semenyuk: handle unsigned uid_t.
-Sat Oct 17 11:00:30 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Oct 17 11:00:30 1992 Ian Lance Taylor (ian@airs.com)
* conf.h.in, configure.in, uucp.h, unix/serial.c
(fsserial_lockfile), lib/MANIFEST: eliminated strlwr.
-Fri Oct 16 01:10:56 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Oct 16 01:10:56 1992 Ian Lance Taylor (ian@airs.com)
* Igor V. Semenyuk: uuchk.c (ukshow): print max-remote-debug
correctly.
lib/debug.c (idebug_parse): accept DEBUG_NONE.
-Thu Oct 15 00:49:58 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Oct 15 00:49:58 1992 Ian Lance Taylor (ian@airs.com)
* unix/cusub.c (fsysdep_terminal_puts): don't modify zalc before
freeing it up.
@@ -432,7 +1667,7 @@ Thu Oct 15 00:49:58 1992 Ian Lance Taylor (ian@comton.airs.com)
* protg.c (fgcheck_errors, fggot_ack, fgprocess_data): Mark E.
Mallett: better handling of error decay.
-Wed Oct 14 22:09:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Oct 14 22:09:20 1992 Ian Lance Taylor (ian@airs.com)
* unix/lock.c: Tomi Vainio: make sure SEEK_SET is defined.
@@ -445,12 +1680,12 @@ Wed Oct 14 22:09:20 1992 Ian Lance Taylor (ian@comton.airs.com)
lib/debug.c, unix/portnm.c, uuconf/int.c, uuconf/llocnm.c,
uuconf/time.c: cast more arguments to eliminate more warnings.
-Tue Oct 13 00:25:03 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Oct 13 00:25:03 1992 Ian Lance Taylor (ian@airs.com)
* prot.h, proti.c (fistart, fijstart), protj.c, uucico.c, tstuu.c
(uprepare_test), Makefile.in, MANIFEST: added 'j' protocol.
-Sun Oct 11 23:45:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Oct 11 23:45:20 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, unix/serial.c (fsserial_set): added HAVE_STRIP_BUG to
policy.h to get around stupid Ultrix bug.
@@ -459,16 +1694,16 @@ Sun Oct 11 23:45:20 1992 Ian Lance Taylor (ian@comton.airs.com)
HAVE_BSD_TTY, keep tchars and ltchars in the sterminal structure,
and in fsserial_open disable all interrupt characters.
-Sat Oct 10 01:18:31 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Oct 10 01:18:31 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/tinit.c (itunknown): Gert Doering: don't save "unknown"
with the other arguments.
-Fri Oct 9 00:56:43 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Oct 9 00:56:43 1992 Ian Lance Taylor (ian@airs.com)
* unix/lock.c: check for running process before doing kill.
-Thu Oct 8 00:20:12 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Oct 8 00:20:12 1992 Ian Lance Taylor (ian@airs.com)
* chat.c, protf.c, send.c, rec.c, unix/locfil.c: Stephen J.
Walick: cast arguments to strtol and strcspn to avoid warnings.
@@ -485,7 +1720,7 @@ Thu Oct 8 00:20:12 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/spool.c (zsfind_file): Matthias Zepf: fixed typos for
SPOOLDIR_BSD*.
-Wed Oct 7 00:03:08 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Oct 7 00:03:08 1992 Ian Lance Taylor (ian@airs.com)
* uuname.c (main): Marc Boucher: reverse sense of -a, and do not
display aliases by default.
@@ -495,7 +1730,7 @@ Wed Oct 7 00:03:08 1992 Ian Lance Taylor (ian@comton.airs.com)
* tstuu.c (main): Marc Boucher: add support for STREAMS ptys.
-Tue Oct 6 23:16:15 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Oct 6 23:16:15 1992 Ian Lance Taylor (ian@airs.com)
* policy.h: Marc Boucher: improve comments to describe SVR4.
@@ -506,7 +1741,7 @@ Tue Oct 6 23:16:15 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuname.c (main): Andreas Vogel: usysdep_exit (TRUE) rather than
usysdep_exit (EXIT_SUCCESS).
-Mon Oct 5 22:59:51 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Oct 5 22:59:51 1992 Ian Lance Taylor (ian@airs.com)
* sysh.unx, unix/serial.c (fsserial_init): Marc Boucher: avoid
freeing unallocated string.
@@ -518,7 +1753,7 @@ Mon Oct 5 22:59:51 1992 Ian Lance Taylor (ian@comton.airs.com)
(fcudo_cmd, fcudo_subcmd, uculist_fns, icuunrecogfn): T. William
Wells: give reasonable error messages.
-Sun Oct 4 00:03:10 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Oct 4 00:03:10 1992 Ian Lance Taylor (ian@airs.com)
* */Makefile.in: T. William Wells: use ar qc rather than ar rc.
@@ -566,7 +1801,7 @@ Sun Oct 4 00:03:10 1992 Ian Lance Taylor (ian@comton.airs.com)
argument to zsfile_to_jobid, and pbgrade argument to
zsjobid_to_file.
-Sat Oct 3 11:03:13 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Oct 3 11:03:13 1992 Ian Lance Taylor (ian@airs.com)
* MANIFEST, Makefile.in, lib/MANIFEST, lib/Makefile.in,
lib/parse.c: moved parse.c from main directory to lib.
@@ -590,7 +1825,7 @@ Sat Oct 3 11:03:13 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuconf/cmdarg.c: check first character to avoid calls to
strcmp or strcasecmp.
-Thu Oct 1 23:44:24 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Oct 1 23:44:24 1992 Ian Lance Taylor (ian@airs.com)
* trans.h, uucico.c (fdo_call, faccept_call), parse.c
(fparse_cmd), send.c (flocal_send_request): Gert Doering: SVR4
@@ -600,7 +1835,7 @@ Thu Oct 1 23:44:24 1992 Ian Lance Taylor (ian@comton.airs.com)
* tstuu.c (main, uprepare_test): added -n switch to not destroy
existing configuration files.
-Fri Sep 25 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Sep 25 00:16:35 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgsenddata): T. William Wells: clear bytes correctly so
that resending a packet doesn't get a completely incorrect size.
@@ -608,14 +1843,14 @@ Fri Sep 25 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com)
* send.c (usadd_exec_line): Stephen J. Walick: don't send trailing
spaces on the created execute file, because it confuses Waffle.
-Thu Sep 24 00:25:18 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Sep 24 00:25:18 1992 Ian Lance Taylor (ian@airs.com)
* unix/jobid.c (zsjobid_to_file): Franc,ois Pinard: if the job ID
is too short, return NULL rather than dumping core.
unix/statsb.c (fskill_or_rejuv, isysdep_work_time): handle a NULL
return from zsjobid_to_file.
-Mon Sep 21 09:01:02 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Sep 21 09:01:02 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/init.c, uuconf/syssub.c: Lele Gaifax: moved
declaration of _uuconf_unset from syssub.c to addstr.c because
@@ -627,11 +1862,11 @@ Mon Sep 21 09:01:02 1992 Ian Lance Taylor (ian@comton.airs.com)
* lib/Makefile.in, unix/Makefile.in: Lele Gaifax: bug in clean
target.
-Thu Sep 17 01:01:13 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Sep 17 01:01:13 1992 Ian Lance Taylor (ian@airs.com)
* Released beta version 1.04.
-Wed Sep 16 01:02:55 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Sep 16 01:02:55 1992 Ian Lance Taylor (ian@airs.com)
* uux.c (main): null terminate the options list for an 'E'
command.
@@ -655,14 +1890,14 @@ Wed Sep 16 01:02:55 1992 Ian Lance Taylor (ian@comton.airs.com)
lib/Makefile.in: use -I flags to permit compilation in a separate
directory. Set up clean targets per GNU standards.
-Tue Sep 15 00:07:09 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Sep 15 00:07:09 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (zget_uucp_cmd): can't set size_t variable to -1.
* Makefile.in (install): don't install info files. Added new
targets info and install-info.
-Mon Sep 14 13:19:42 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Sep 14 13:19:42 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (main): Gregory Bond: canonicalize the system name given
by the -s argument.
@@ -685,7 +1920,7 @@ Mon Sep 14 13:19:42 1992 Ian Lance Taylor (ian@comton.airs.com)
fsysdep_unlock_uuxqt_dir, fsysdep_move_uuxqt_files): use .Xqtdir
for first uuxqt execution, not .Xqtdir0000.
-Sun Sep 13 11:51:22 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Sep 13 11:51:22 1992 Ian Lance Taylor (ian@airs.com)
* trans.h, uucico.c (fdo_call, faccept_call), send.c
(flocal_send_request), rec.c (flocal_rec_send_request) parse.c
@@ -716,7 +1951,7 @@ Sun Sep 13 11:51:22 1992 Ian Lance Taylor (ian@comton.airs.com)
minutes. Honor CYM from the remote system. Send CYM if we have
something to do.
-Sat Sep 12 15:47:52 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Sep 12 15:47:52 1992 Ian Lance Taylor (ian@airs.com)
* Makefile.in: use $(MAKE) instead of make for recursive calls.
@@ -724,7 +1959,7 @@ Sat Sep 12 15:47:52 1992 Ian Lance Taylor (ian@comton.airs.com)
unix/MANIFEST, unix/Makefile.in: added esysdep_user_open to open a
file with user permissions.
-Fri Sep 11 00:27:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Sep 11 00:27:32 1992 Ian Lance Taylor (ian@airs.com)
* uudefs.h, copy.c: added fcopy_open_file.
@@ -732,7 +1967,7 @@ Fri Sep 11 00:27:32 1992 Ian Lance Taylor (ian@comton.airs.com)
* configure.in, conf.h.in: check for setreuid.
-Tue Sep 8 00:11:10 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Sep 8 00:11:10 1992 Ian Lance Taylor (ian@airs.com)
* protf.c (ffsendcmd), prott.c (ftsendcmd): eliminate calls to
alloca.
@@ -743,7 +1978,7 @@ Tue Sep 8 00:11:10 1992 Ian Lance Taylor (ian@comton.airs.com)
lib/Makefile.in, lib/MANIFEST: added getopt_long, and changed all
calls to getopt to call getopt_long instead.
-Mon Sep 7 22:26:51 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Sep 7 22:26:51 1992 Ian Lance Taylor (ian@airs.com)
* getopt.h, lib/getopt.c, lib/Makefile.in: bring getopt up to
glibc 1.04; call malloc instead of alloca in exchange.
@@ -755,7 +1990,7 @@ Mon Sep 7 22:26:51 1992 Ian Lance Taylor (ian@comton.airs.com)
* cu.c, unix/cusub.c: various minor improvements.
-Sun Sep 6 20:25:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Sep 6 20:25:20 1992 Ian Lance Taylor (ian@airs.com)
* uux.c (uxcopy_stdin): use getchar rather than fread to avoid
SVR4 bug.
@@ -766,12 +2001,12 @@ Sun Sep 6 20:25:20 1992 Ian Lance Taylor (ian@comton.airs.com)
* protg.c (fgsend_control): Niels Baggesen: report sending an RJ
when DEBUG_ABNORMAL.
-Tue Aug 25 00:07:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Aug 25 00:07:20 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/time.c: Zacharias Beckman: let user defined time tables
override the defaults.
-Mon Aug 24 00:25:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Aug 24 00:25:23 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uuxqt.c (uqdo_xqt_file), unix/xqtsub.c
(zsysdep_xqt_local_file): Jarmo Raiha: expand ~name in uuxqt.c.
@@ -803,7 +2038,7 @@ Mon Aug 24 00:25:23 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/serial.c: Brian Campbell: check for B57600, B76800 and
B115200 in baud rate table.
-Sun Aug 23 13:05:28 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Aug 23 13:05:28 1992 Ian Lance Taylor (ian@airs.com)
* chat.c (fcsend), tstuu.c (uchild): Chip Salzenberg: call sleep
(2) instead of sleep (1). Hopefully this won't break any chat
@@ -844,7 +2079,7 @@ Sun Aug 23 13:05:28 1992 Ian Lance Taylor (ian@comton.airs.com)
when closing a modem connection. Also, retry if we time out when
setting MIN.
-Sat Aug 22 22:31:34 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Aug 22 22:31:34 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/time.c: Stephen Walick: don't require a comma between
time strings, since HDB doesn't seem to.
@@ -871,14 +2106,14 @@ Sat Aug 22 22:31:34 1992 Ian Lance Taylor (ian@comton.airs.com)
unix/xqtfil.c: Brian J. Murrell and Don Phillips: added
SPOOLDIR_SVR4.
-Thu Aug 20 00:06:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Aug 20 00:06:32 1992 Ian Lance Taylor (ian@airs.com)
* sysh.unx: Chiaki Ishikawa: some systems define some but not all
of the S_ file mode bits.
* uuchk.c (ikshow_port): Chiaki Ishikawa: display lockname.
-Wed Aug 19 22:41:39 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Aug 19 22:41:39 1992 Ian Lance Taylor (ian@airs.com)
* log.c (ustats): Scott Blachowicz: avoid overflow when reporting
bytes per second.
@@ -896,29 +2131,29 @@ Wed Aug 19 22:41:39 1992 Ian Lance Taylor (ian@comton.airs.com)
ack. Added new SN8 rejection, meaning that the file has already
been received.
-Sat Aug 15 11:50:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Aug 15 11:50:32 1992 Ian Lance Taylor (ian@airs.com)
* uuconf/time.c (itadd_span): Don Lewis: fixed bug if later span
overlapped two or more earlier spans.
-Thu Aug 13 00:19:50 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Aug 13 00:19:50 1992 Ian Lance Taylor (ian@airs.com)
* system.h, rec.c (fremote_send_file_init, fremote_send_reply),
uucico.c (fdo_call, faccept_call), uucp.c (main), uux.c (main),
unix/opensr.c (zsysdep_receive_temp, esysdep_open_receive):
implemented file restart.
-Wed Aug 12 23:32:05 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Aug 12 23:32:05 1992 Ian Lance Taylor (ian@airs.com)
* proti.c (fiprocess_data): ensure that the first argument to
fgot_data is always > 0 if the second argument is > 0.
-Mon Aug 10 22:43:40 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Aug 10 22:43:40 1992 Ian Lance Taylor (ian@airs.com)
* trans.c (floop, ustats_failed): handle half-duplex connections
and failed calls correctly.
-Sun Aug 9 17:56:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Aug 9 17:56:32 1992 Ian Lance Taylor (ian@airs.com)
* proti.c (firesend, fisenddata, ficheck_errors): made several
changes to improve performance on a lossy line: can now shrink
@@ -934,7 +2169,7 @@ Sun Aug 9 17:56:32 1992 Ian Lance Taylor (ian@comton.airs.com)
* MANIFEST, Makefile.in, prot.h, uucico.c, protz.c, trans.c: Doug
Evans: added Doug Evans's zmodem implementation as protocol 'a'.
-Wed Aug 5 22:28:14 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Aug 5 22:28:14 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, uuconf.h, uucico.c (fcall), uuconf/tsinfo.c,
uuconf/hsinfo.c, uuconf/syssub.c: added "max-retries" command for
@@ -947,7 +2182,7 @@ Wed Aug 5 22:28:14 1992 Ian Lance Taylor (ian@comton.airs.com)
protocol entry point, changed handshake successful message to
display it.
-Tue Aug 4 00:04:31 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Aug 4 00:04:31 1992 Ian Lance Taylor (ian@airs.com)
* prot.h, uucico.c, protg.c (fbiggstart, cGshort_packets): Chip
Salzenberg: added support for 'G' protocol. Added "short-packets"
@@ -960,7 +2195,7 @@ Tue Aug 4 00:04:31 1992 Ian Lance Taylor (ian@comton.airs.com)
* unix/spawn.c: don't close the file descriptor after dupping it.
-Sun Aug 2 23:04:18 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Aug 2 23:04:18 1992 Ian Lance Taylor (ian@airs.com)
* trans.c (fremote_hangup_reply): don't hangup if a file transfer
is in progress.
@@ -968,7 +2203,7 @@ Sun Aug 2 23:04:18 1992 Ian Lance Taylor (ian@comton.airs.com)
* send.c (flocal_send_cancelled): don't pass a NULL buffer to
pfsenddata.
-Sun Jul 26 13:28:27 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Jul 26 13:28:27 1992 Ian Lance Taylor (ian@airs.com)
* unix/work.c (fsysdep_get_work_init): return TRUE if there is no
work directory.
@@ -991,7 +2226,7 @@ Sun Jul 26 13:28:27 1992 Ian Lance Taylor (ian@comton.airs.com)
memmove, avoiding the SCO bug and making the 'g' protocol slightly
more efficient.
-Sat Jul 25 14:20:30 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jul 25 14:20:30 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h, uudefs.h, many other files: broke part of uucp.h out
into uudefs.h, stopped including uuconf.h in uucp.h, fixed up .c
@@ -1016,7 +2251,7 @@ Sat Jul 25 14:20:30 1992 Ian Lance Taylor (ian@comton.airs.com)
lib/escape.c. Made all connections on Unix use the same
system dependent structure.
-Tue Jul 21 22:08:10 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Jul 21 22:08:10 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h, trans.h, uucico.c (fdo_call, faccept_call), uuxqt.c
(uqdo_xqt_file), uucp.c (main), uux.c (main), uustat.c
@@ -1028,7 +2263,7 @@ Tue Jul 21 22:08:10 1992 Ian Lance Taylor (ian@comton.airs.com)
added E request to send file executions which only require reading
from standard input.
-Sat Jul 18 20:22:50 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jul 18 20:22:50 1992 Ian Lance Taylor (ian@airs.com)
* proti.c, Makefile.in, MANIFEST, prot.h, system.h, trans.h,
uucico.c, prote.c, protf.c, protg.c, prott.c, trans.c, send.c,
@@ -1037,31 +2272,31 @@ Sat Jul 18 20:22:50 1992 Ian Lance Taylor (ian@comton.airs.com)
points. Cleaned up send and receive state machines. Removed
pfgone argument from esysdep_open_send.
-Fri Jul 17 09:41:05 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Jul 17 09:41:05 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (uqdo_xqt_file): only report base name of execution
file, not full name.
-Thu Jul 16 00:45:06 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Jul 16 00:45:06 1992 Ian Lance Taylor (ian@airs.com)
* lib/crc.c: unroll the loop a bit.
* configure.in, conf.h.in, unix/init.c: updated to autoconf 0.120.
-Wed Jul 15 14:45:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jul 15 14:45:32 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconv.c, uuconf/uucnfi.h, uuconf/reliab.c,
uuconf/tportc.c, uuconf/tdialc.c, uuconf/diasub.c, uuconf/hport.c,
uuconf/prtsub.c, uuconf/vsinfo.c: added UUCONF_RELIABLE_FULLDUPLEX
and "half-duplex" command for ports and dialers.
-Mon Jul 13 16:53:04 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jul 13 16:53:04 1992 Ian Lance Taylor (ian@airs.com)
* prot.h, lib/crc.c, lib/Makefile.in, lib/MANIFEST: added icrc
function to compute 32 bit CRC (from Gary S. Brown, via Doug
Evans).
-Sun Jul 12 21:40:15 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Jul 12 21:40:15 1992 Ian Lance Taylor (ian@airs.com)
* uuconv.c (uvwrite_time): Chris Lewis: don't output two commas in
a row.
@@ -1069,7 +2304,7 @@ Sun Jul 12 21:40:15 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuconv.c (uvwrite_taylor_system, uvwrite_taylor_port): Chris
Lewis: generate command "protocol", not "protocols".
-Sat Jul 11 17:09:09 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jul 11 17:09:09 1992 Ian Lance Taylor (ian@airs.com)
* xcmd.c (fremote_xcmd_init): Chris Lewis: use qdaemon->puuconf,
since puuconf is not defined.
@@ -1083,7 +2318,7 @@ Sat Jul 11 17:09:09 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuconf/freblk.c, uuconf/free.c: Chris Lewis: don't define as
void when ! UUCONF_ANSI_C.
-Thu Jul 9 09:17:55 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Jul 9 09:17:55 1992 Ian Lance Taylor (ian@airs.com)
* prot.h, uucico.c (fdo_call, faccept_call), prote.c (festart),
protf.c (ffstart), protg.c (fgstart), prott.c (ftstart): no need
@@ -1092,7 +2327,7 @@ Thu Jul 9 09:17:55 1992 Ian Lance Taylor (ian@comton.airs.com)
* protf.c (ffawait_ack, ffawait_cksum): don't try to resend if we
don't have a file.
-Wed Jul 8 14:28:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jul 8 14:28:23 1992 Ian Lance Taylor (ian@airs.com)
* unix/srmdir.c (fsysdep_rmdir), unix/walk.c (usysdep_walk_tree):
cast to char * to avoid warning.
@@ -1119,7 +2354,7 @@ Wed Jul 8 14:28:23 1992 Ian Lance Taylor (ian@comton.airs.com)
of jobs to do, and support connections. Added new files trans.h,
trans.c, send.c, rec.c, xcmd.c, and removed old file file.c.
-Mon Jun 29 15:14:15 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jun 29 15:14:15 1992 Ian Lance Taylor (ian@airs.com)
* Makefile.in: Stephen J. Walick: copy uustat.1 to
uustat.$(manext), not uucp.($manext). Also try to create
@@ -1128,11 +2363,11 @@ Mon Jun 29 15:14:15 1992 Ian Lance Taylor (ian@comton.airs.com)
* chat.c (fcsend, fcprogram): check for NULL return from
uuconf_callout.
-Thu Jun 18 22:37:28 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Jun 18 22:37:28 1992 Ian Lance Taylor (ian@airs.com)
* configure.in, Makefile.in: updated to autoconf 0.118.
-Wed Jun 17 14:22:11 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jun 17 14:22:11 1992 Ian Lance Taylor (ian@airs.com)
* unix/serial.c (fsserial_init): add /dev if necessary to device
as well as to port name.
@@ -1142,12 +2377,12 @@ Wed Jun 17 14:22:11 1992 Ian Lance Taylor (ian@comton.airs.com)
* cu.c (main), uucp.c (main), uux.c (main), uuxqt.c (main): don't
call zsysdep_localname until we've called usysdep_initialize.
-Tue Jun 16 17:42:50 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Jun 16 17:42:50 1992 Ian Lance Taylor (ian@airs.com)
* unix/signal.c (usset_signal): set SA_INTERRUPT to force system
calls to be interrupted on SunOS.
-Mon Jun 15 15:10:24 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jun 15 15:10:24 1992 Ian Lance Taylor (ian@airs.com)
* everything: integrated uuconf library. Split out lib and unix
libraries. Made many changes, including defaults for port and
@@ -1155,19 +2390,19 @@ Mon Jun 15 15:10:24 1992 Ian Lance Taylor (ian@comton.airs.com)
handling of HDB Permissions, new zbufalc routines to manage
strings on the heap. Incorporated uuconv.
-Wed Jun 10 23:51:03 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jun 10 23:51:03 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/Makefile.in, uuconf/locnm.c, uuconf/llocnm.c,
uuconf/hlocnm.c, uuconf/tlocnm.c: renamed uuconf_localname to
uuconf_login_localname and added new uuconf_localname which
doesn't need to read system information.
-Tue Jun 9 14:19:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Jun 9 14:19:20 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/Makefile.in, uuconf/local.c: wrote
uuconf_system_local.
-Mon Jun 8 14:14:30 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jun 8 14:14:30 1992 Ian Lance Taylor (ian@airs.com)
* policy.h: changed description of LOCKDIR, which now need not
always be defined.
@@ -1176,7 +2411,7 @@ Mon Jun 8 14:14:30 1992 Ian Lance Taylor (ian@comton.airs.com)
uuconf/tinit.c, uuconf/Makefile.in: added uuconf_lockdir, and
``lockdir'' command to config.
-Sat Jun 6 22:07:58 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Jun 6 22:07:58 1992 Ian Lance Taylor (ian@airs.com)
* configure.in: updated to autoconf 0.115, added code to set
LIBOBJS.
@@ -1185,13 +2420,13 @@ Sat Jun 6 22:07:58 1992 Ian Lance Taylor (ian@comton.airs.com)
routines now in lib/, changed to include regular UUCP header
files.
-Fri Jun 5 15:31:29 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Jun 5 15:31:29 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/uucnfi.h, uuconf/syssub.c, uuconf/uuconv.c:
always set zpubdir for every system, changed uuconf_zpubdir to
const char *.
-Wed Jun 3 15:15:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Jun 3 15:15:32 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/Makefile.in, uuconf/deblev.c, uuconf/maxuxq.c,
uuconf/pubdir.c, uuconf/spool.c: wrote uuconf_debuglevel,
@@ -1201,12 +2436,12 @@ Wed Jun 3 15:15:32 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuconf/tportc.c: default TCP ports to being fully reliable.
-Mon Jun 1 17:03:22 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Jun 1 17:03:22 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/prtsub.c: removed uuconf_psysdep from
uuconf_port.
-Sun May 31 00:07:40 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun May 31 00:07:40 1992 Ian Lance Taylor (ian@airs.com)
* uuconf.h, uuconf/Makefile.in, uuconf/diacod.c: wrote
uuconf_dialcode.
@@ -1224,7 +2459,7 @@ Sun May 31 00:07:40 1992 Ian Lance Taylor (ian@comton.airs.com)
* uuconf.h, uuconf/Makefile.in, uuconf/val.c, uuconf/tval.c: wrote
uuconf_validate, uuconf_taylor_validate.
-Sat May 30 12:37:02 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat May 30 12:37:02 1992 Ian Lance Taylor (ian@airs.com)
* system.h, sys1.unx: changed zsysdep_local_name to
zsysdep_localname, and made it fatal out rather than return NULL.
@@ -1246,12 +2481,12 @@ Sat May 30 12:37:02 1992 Ian Lance Taylor (ian@comton.airs.com)
* configure.in, conf.h.in: check for <stddef.h>.
-Fri May 29 00:03:05 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri May 29 00:03:05 1992 Ian Lance Taylor (ian@airs.com)
* sysinf.c (ztranslate_system): Jac Kersing: must xstrdup the
argument, since it points to a buffer that will be reused.
-Thu May 28 12:42:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu May 28 12:42:20 1992 Ian Lance Taylor (ian@airs.com)
* sys3.unx (zsysdep_real_file_name): Ted Lindgreen: check return
value of zstilde_expand.
@@ -1303,13 +2538,13 @@ Thu May 28 12:42:20 1992 Ian Lance Taylor (ian@comton.airs.com)
* configure.in, conf.h.in, sysh.unx, sys1.unx: John Theus: use
sv_onstack instead of sv_flags in the sigvec structure on 4.2BSD.
-Wed May 27 23:23:39 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed May 27 23:23:39 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, sys2.unx (fsysdep_modem_no_carrier): Scott Reynolds:
added HAVE_CLOCAL_BUG compilation parameter to work around
problems on some serial ports.
-Tue May 26 15:50:17 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue May 26 15:50:17 1992 Ian Lance Taylor (ian@airs.com)
* uustat.c, uustat.1: added a bunch of options to support uuclean:
-e, -i, -K, -M, -N, -W, -Q.
@@ -1317,13 +2552,13 @@ Tue May 26 15:50:17 1992 Ian Lance Taylor (ian@comton.airs.com)
* system.h, sys7.unx (fsysdep_privileged, fskill_or_rejuv): added
fsysdep_privileged function.
-Thu May 21 13:30:21 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu May 21 13:30:21 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (uqdo_xqt_file): processing of execution file has to be
case significant; this will change handling of "n" flag, which was
not correctly handled before.
-Wed May 20 14:22:12 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed May 20 14:22:12 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx (usysdep_detach): close the statistics file when
detaching.
@@ -1361,7 +2596,7 @@ Wed May 20 14:22:12 1992 Ian Lance Taylor (ian@comton.airs.com)
(usysdep_walk_tree, isdir, ftw, do_ftw): added -R option to uucp
to recursively copy directories.
-Tue May 19 18:29:32 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue May 19 18:29:32 1992 Ian Lance Taylor (ian@airs.com)
* sys3.unx: changed zsysdep_in_dir to always append the filename
to the directory, even if the directory did not already exist.
@@ -1369,25 +2604,25 @@ Tue May 19 18:29:32 1992 Ian Lance Taylor (ian@comton.airs.com)
* sysh.unx, sys1.unx, sys3.unx, sys4.unx, sys5.unx: renamed
fsdirectory_exists to fsysdep_directory.
-Mon May 18 14:49:35 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon May 18 14:49:35 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uucp.c (main), sys6.unx (zsysdep_uuto): added -t
option to uucp to emulate uuto, wrote zsysdep_uuto to do Unix
dependent destination translation for uuto, added -p option to
uucp as synonym for -C for uuto compatibility.
-Sun May 17 22:04:09 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun May 17 22:04:09 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgexchange_init): permit a second INITB to override the
segment size given in the first INITB.
-Tue May 5 16:03:22 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue May 5 16:03:22 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (main, fdo_call), uucico.8: Chip Salzenberg: added -c
option to uucico to not warn if invoked when the system may not be
called.
-Tue Apr 28 15:05:01 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Apr 28 15:05:01 1992 Ian Lance Taylor (ian@airs.com)
* sysh.unx, sys2.unx (fsserial_open, fsblock): preserve file
status flags.
@@ -1395,7 +2630,7 @@ Tue Apr 28 15:05:01 1992 Ian Lance Taylor (ian@comton.airs.com)
* protg.c (fgwait_for_packet): Heiko Rupp: only send RJ packet if
there are no unacknowledged packets.
-Mon Apr 27 18:56:42 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Apr 27 18:56:42 1992 Ian Lance Taylor (ian@airs.com)
* system.h: added several routines for cu.
@@ -1404,7 +2639,7 @@ Mon Apr 27 18:56:42 1992 Ian Lance Taylor (ian@comton.airs.com)
* uux.c (main): Jose Manas: dumb bug when checking against
calloc_args.
-Fri Apr 24 20:32:06 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Apr 24 20:32:06 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx: changed HAVE_LONG_NAMES to HAVE_LONG_FILENAMES for new
version of autoconf.
@@ -1423,7 +2658,7 @@ Fri Apr 24 20:32:06 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys2.unx: get the right versions of major and minor.
-Wed Apr 22 11:19:11 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Apr 22 11:19:11 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgsenddata, fggot_ack): Michael Haberler: the slow
start after error code was essentially shrinking the window size.
@@ -1440,7 +2675,7 @@ Wed Apr 22 11:19:11 1992 Ian Lance Taylor (ian@comton.airs.com)
(uv2_read_systems): Michael Richardson: don't core dump if no chat
script.
-Tue Apr 21 00:19:47 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Apr 21 00:19:47 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (faccept_call): Chris Lewis: a successful call in
should clear the number of retries.
@@ -1454,24 +2689,24 @@ Tue Apr 21 00:19:47 1992 Ian Lance Taylor (ian@comton.airs.com)
parity generation, input parity checking, and XON/XOFF
handshaking, all to support cu.
-Mon Apr 20 11:47:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Apr 20 11:47:23 1992 Ian Lance Taylor (ian@airs.com)
* port.h, uucico.c (fdo_call), port.c (fport_dial, fmodem_dial),
tcp.c (ftcp_dial): added separate zphone argument to fport_dial to
support cu.
-Thu Apr 16 01:15:42 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Apr 16 01:15:42 1992 Ian Lance Taylor (ian@airs.com)
* bnu.c (ubadd_perm, ubadd_perm_alternate): Chris Lewis: handle a
combination of Permissions entries which specify just LOGNAME with
entries that specify both MACHINE and LOGNAME.
-Wed Apr 15 16:11:48 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Apr 15 16:11:48 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx (usysdep_initialize, zsysdep_login_name): John Theus:
don't die if can't get login name, unless it's really needed.
-Tue Apr 14 12:39:18 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Apr 14 12:39:18 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (main, fcall): Petri Helenius: must relock system after
detaching from terminal when trying different alternates.
@@ -1505,18 +2740,18 @@ Tue Apr 14 12:39:18 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucp.texi: Harlan Stenn: correct case of references.
-Tue Apr 7 01:02:17 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Apr 7 01:02:17 1992 Ian Lance Taylor (ian@airs.com)
* Released version 1.03.
-Mon Apr 6 15:49:08 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Apr 6 15:49:08 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (faccept_call): Marc Boucher: set *pqsys to NULL.
* bnu.c (ubnu_read_systems, fbnu_find_port): Erik Forsberg:
support multiple character modem classes.
-Fri Apr 3 00:37:25 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Apr 3 00:37:25 1992 Ian Lance Taylor (ian@airs.com)
* sys2.unx: Petri Helenius: only clear known bits in termio or
termios structure; didn't change HAVE_BSD_TTY handling--maybe next
@@ -1529,14 +2764,14 @@ Fri Apr 3 00:37:25 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys1.unx, chat.c: minor cleanups for gcc 2.1.
-Thu Apr 2 17:51:36 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Apr 2 17:51:36 1992 Ian Lance Taylor (ian@airs.com)
* tstuu.c: conditionally declare times.
* uucp.h, prot.c, sysinf.c, prtinf.c: added gcc 2.0 format
checking to ulog, and fixed a few problems it discovered.
-Wed Apr 1 16:21:08 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Apr 1 16:21:08 1992 Ian Lance Taylor (ian@airs.com)
* sys3.unx (esysdep_open_receive): David J. MacKenzie: some
USG_STATFS systems use 512 as the block size of f_bfree, despite
@@ -1564,7 +2799,7 @@ Wed Apr 1 16:21:08 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucico.8, uuxqt.8, uucp.1, uux.1: updated -x switch, cleaned up
a bit.
-Tue Mar 31 14:40:06 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Mar 31 14:40:06 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx (usysdep_initialize): use $PWD to get the current
working directory if it's defined and correct.
@@ -1579,7 +2814,7 @@ Tue Mar 31 14:40:06 1992 Ian Lance Taylor (ian@comton.airs.com)
* protg.c (fgsenddata): Niels Baggesen: packet to retransmit did
not get reset correctly.
-Mon Mar 30 10:03:28 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Mar 30 10:03:28 1992 Ian Lance Taylor (ian@airs.com)
* tcp.c (ftcp_reset): Petri Helenius: TCP server never started
uuxqt, because it exited in ftcp_reset.
@@ -1590,7 +2825,7 @@ Mon Mar 30 10:03:28 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys3.unx (esysdep_open_receive): Niels Baggesen: USG statfs has
an f_bsize field.
-Sun Mar 29 23:04:20 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Mar 29 23:04:20 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h, sysinf.c, prot.c, prote.c, protf.c, protg.c, prott.c:
Niels Baggesen: added new debugging types abnormal and uucp-proto.
@@ -1604,7 +2839,7 @@ Sun Mar 29 23:04:20 1992 Ian Lance Taylor (ian@comton.airs.com)
fsserial_io): always block and unblock the read and write
descriptors together.
-Sat Mar 28 14:40:50 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Mar 28 14:40:50 1992 Ian Lance Taylor (ian@airs.com)
* uustat.c: allow multiple systems and users to be specified at
once; likewise for kills and rejuvenates. Allow old and young to
@@ -1640,7 +2875,7 @@ Sat Mar 28 14:40:50 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucico.c (fuucp), log.c (ulog, ustats, ustats_close): close log
and statistics file every time master and slave switch roles.
-Fri Mar 27 00:31:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Mar 27 00:31:23 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (fdo_call): Mark Mallett: minor cleanup.
@@ -1674,29 +2909,29 @@ Fri Mar 27 00:31:23 1992 Ian Lance Taylor (ian@comton.airs.com)
* Makefile.in, configure.in: David J. MacKenzie: various cleanups.
Changed default newconfigdir definition. Supported compilation in
a different directory. Used symbolic links if available. Changed
- default infordir definition per Franc,ois Pinard.
+ default infodir definition per Franc,ois Pinard.
* policy.h: David J. MacKenzie: various cleanups.
-Thu Mar 26 12:17:41 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Mar 26 12:17:41 1992 Ian Lance Taylor (ian@airs.com)
* sys3.unx: reduced race condition in fsdo_lock.
* sys1.unx: Gerben Wierda: various cleanups. Also don't set
sa_flags to SV_INTERRUPT per Chip Salzenberg.
-Wed Mar 25 22:20:24 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Mar 25 22:20:24 1992 Ian Lance Taylor (ian@airs.com)
* configure.in: Overhauled for readability and functionality as
suggested by T. William Wells and others. Added bug checks,
including for SCO memmove and ftime.
-Tue Mar 24 12:18:56 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Mar 24 12:18:56 1992 Ian Lance Taylor (ian@airs.com)
* sysinf.c (uiread_systems): fixed handling of alternates in
file-wide defaults.
-Wed Mar 18 01:01:25 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Mar 18 01:01:25 1992 Ian Lance Taylor (ian@airs.com)
* config.c (tprocess_one_cmd): handle CMDTABTYPE_FULLSTRING
correctly if there are no arguments.
@@ -1706,7 +2941,7 @@ Wed Mar 18 01:01:25 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys1.unx (usysdep_detach): open the controlling terminal in non
delay mode since it might be a modem.
-Tue Mar 17 00:01:53 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Mar 17 00:01:53 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (fdo_call, faccept_call): T. William Wells: set current
time in status file when call completes.
@@ -1718,7 +2953,7 @@ Tue Mar 17 00:01:53 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys2.unx (fsserial_lock, fsserial_open): don't block when
opening the write descriptor.
-Mon Mar 16 00:14:43 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Mar 16 00:14:43 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uuxqt.c (uqdo_xqt_file), sys5.unx (fsysdep_execute):
pass command to fsysdep_execute as first element of argument
@@ -1771,7 +3006,7 @@ Mon Mar 16 00:14:43 1992 Ian Lance Taylor (ian@comton.airs.com)
maximum file transfer size; accept and ignore SVR4 -R flag meaning
that the system supports file restart.
-Sun Mar 15 00:21:56 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Mar 15 00:21:56 1992 Ian Lance Taylor (ian@airs.com)
* sysinf.c (titime, titimegrade): permit a retry time to be
specified as an optional additional argument.
@@ -1798,7 +3033,7 @@ Sun Mar 15 00:21:56 1992 Ian Lance Taylor (ian@comton.airs.com)
* bnu.c (fbnu_find_port): Scott Ballantyne: accept "Any" as a
Device speed.
-Sat Mar 14 20:52:11 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Mar 14 20:52:11 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h, system.h, sysh.unx, uucico.c (main, zget_typed_line),
uuxqt.c (main), uucp.c (main), uux.c (main, uxcopy_stdin), tcp.c
@@ -1817,7 +3052,7 @@ Sat Mar 14 20:52:11 1992 Ian Lance Taylor (ian@comton.airs.com)
tstuu.c (uchild): added function isspawn, espopen and iswait and
channeled all execs of new processes and waits through them.
-Fri Mar 13 18:00:04 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Mar 13 18:00:04 1992 Ian Lance Taylor (ian@airs.com)
* sysinf.c (uset_system_defaults): Chip Salzenberg: changed
default login script timeout to 10 seconds.
@@ -1828,7 +3063,7 @@ Fri Mar 13 18:00:04 1992 Ian Lance Taylor (ian@comton.airs.com)
freport argument to freceive_data, and change all old calls to
pass it in as FALSE.
-Thu Mar 12 14:49:59 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Mar 12 14:49:59 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h: added a padding byte to scmd structure, since at least
one compiler needs it.
@@ -1850,7 +3085,7 @@ Thu Mar 12 14:49:59 1992 Ian Lance Taylor (ian@comton.airs.com)
The debugging types are additive. Many source files changed.
Inspired by Michael Richardson, Johan Vromans and Peter da Silva.
-Wed Mar 11 12:01:03 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Mar 11 12:01:03 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, uuxqt.c (uqdo_xqt_file): Chip Salzenberg: support
Internet mail addresses in uuxqt replies (added configuration
@@ -1872,7 +3107,7 @@ Wed Mar 11 12:01:03 1992 Ian Lance Taylor (ian@comton.airs.com)
Jon Zeef: if a temporary failure occurs, retry the execution
later.
-Tue Mar 10 12:40:30 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Mar 10 12:40:30 1992 Ian Lance Taylor (ian@airs.com)
* sysh.unx, sys1.unx (isfork), sys2.unx, sys5.unx, tcp.c:
Franc,ois Pinard: retry fork several times before giving up.
@@ -1908,7 +3143,7 @@ Tue Mar 10 12:40:30 1992 Ian Lance Taylor (ian@comton.airs.com)
parameter HAVE_TERMIOS_AND_SYS_IOCTL_H accordingly; handle it in
sysh.unx.
-Mon Mar 9 00:06:12 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Mar 9 00:06:12 1992 Ian Lance Taylor (ian@airs.com)
* sys2.unx (fsserial_close): Franc,ois Pinard: sleep for a second
after closing the serial port to give it a chance to settle.
@@ -1940,7 +3175,7 @@ Mon Mar 9 00:06:12 1992 Ian Lance Taylor (ian@comton.airs.com)
this status type is not used (if an attempt is made to call the
system, the status is left unchanged).
-Sun Mar 8 11:41:45 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Mar 8 11:41:45 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (main, flogin_prompt, faccept_call): Ted Lindgreen: if
we were asked to call a single system, or if a single system
@@ -1959,7 +3194,7 @@ Sun Mar 8 11:41:45 1992 Ian Lance Taylor (ian@comton.airs.com)
report the port name and (for incoming calls) the login name in
the log file.
-Sat Mar 7 10:00:47 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Mar 7 10:00:47 1992 Ian Lance Taylor (ian@airs.com)
* port.h, prtinf.c, sys2.unx (fsserial_lockfile, fsserial_lock):
Peter da Silva: added ``lockname'' command to ports to permit
@@ -1981,7 +3216,7 @@ Sat Mar 7 10:00:47 1992 Ian Lance Taylor (ian@comton.airs.com)
* prot.h: never included more than once.
-Fri Mar 6 21:53:28 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Mar 6 21:53:28 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h: Eric Ziegast: some systems don't define EXIT_SUCCESS or
EXIT_FAILURE in stdlib.h.
@@ -1993,7 +3228,7 @@ Fri Mar 6 21:53:28 1992 Ian Lance Taylor (ian@comton.airs.com)
incorrect maximum possible transfer size. Added new file
uutime.h.
-Wed Mar 4 10:06:13 1992 Ian Lance Taylor (ian@comton.airs.com)
+Wed Mar 4 10:06:13 1992 Ian Lance Taylor (ian@airs.com)
* sys2.unx (fsserial_lockfile, fsserial_lock, fsysdep_modem_open,
fsysdep_direct_open, fsysdep_modem_close, fsysdep_direct_close):
@@ -2014,7 +3249,7 @@ Wed Mar 4 10:06:13 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucico.c (zget_uucp_cmd): Michael Haberler: some systems send \n
after Shere, rather than a null byte.
-Tue Mar 3 01:03:22 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Mar 3 01:03:22 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (main, uqdo_xqt_file): permit local executions, don't
get grade out of system dependent file name.
@@ -2060,7 +3295,7 @@ Tue Mar 3 01:03:22 1992 Ian Lance Taylor (ian@comton.airs.com)
with V2 or BNU configuration files, don't complain if the
HAVE_TAYLOR_CONFIG files are missing.
-Mon Mar 2 10:21:36 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Mar 2 10:21:36 1992 Ian Lance Taylor (ian@airs.com)
* sys2.unx (fsserial_read): T. William Wells: don't arbitrarily
extend read timeout.
@@ -2068,14 +3303,14 @@ Mon Mar 2 10:21:36 1992 Ian Lance Taylor (ian@comton.airs.com)
* uux.c (main): check iSignal before entering fread, since the
user may have hit ^C earlier in the program.
-Sun Mar 1 23:39:33 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Mar 1 23:39:33 1992 Ian Lance Taylor (ian@airs.com)
* policy.h, uucp.h, sysh.unx, sys2.unx (fsserial_lock,
fsysdep_modem_close, fsysdep_direct_close), util.c (strlwr),
configure.in: Marc Unangst: added HAVE_SCO_LOCKFILES configuration
parameter to force lock file names to lower case.
-Fri Feb 28 00:07:12 1992 Ian Lance Taylor (ian@comton.airs.com)
+Fri Feb 28 00:07:12 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uucico.c (faccept_call, fdo_xcmd), uuxqt.c
(uqdo_xqt_file), uux.c (main), uucp.c (main, ucspool_cmds),
@@ -2107,7 +3342,7 @@ Fri Feb 28 00:07:12 1992 Ian Lance Taylor (ian@comton.airs.com)
setjmp. Also TIOCNOTTY sets the process group to 0, so we don't
have to fork before calling it.
-Thu Feb 27 00:08:09 1992 Ian Lance Taylor (ian@comton.airs.com)
+Thu Feb 27 00:08:09 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx, sys6.unx, sys7.unx: added some extern definitions.
@@ -2132,7 +3367,7 @@ Thu Feb 27 00:08:09 1992 Ian Lance Taylor (ian@comton.airs.com)
checked at various points, notably in the port routines and in the
main loops in uucico and uuxqt.
-Tue Feb 25 10:59:23 1992 Ian Lance Taylor (ian@comton.airs.com)
+Tue Feb 25 10:59:23 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgwait_for_packet): Bob Denny: reset the count of
timeouts only when data is recognized, so that we aren't fooled by
@@ -2141,7 +3376,7 @@ Tue Feb 25 10:59:23 1992 Ian Lance Taylor (ian@comton.airs.com)
* sys5.unx (zsysdep_get_xqt): Bob Denny: don't warn if opendir
gets ENOENT. I think POSIX requires ENOTDIR, but what can you do?
-Mon Feb 24 14:37:10 1992 Ian Lance Taylor (ian@comton.airs.com)
+Mon Feb 24 14:37:10 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (main, uusage): don't treat an extra argument as a port
name.
@@ -2169,7 +3404,7 @@ Mon Feb 24 14:37:10 1992 Ian Lance Taylor (ian@comton.airs.com)
* uucp.h: John Theus: if we don't have vprintf, ulog is defined
without an ellipsis, so don't declare it with one.
-Sun Feb 23 14:45:53 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sun Feb 23 14:45:53 1992 Ian Lance Taylor (ian@airs.com)
* uucp.h, system.h, bnu.c (ubnu_read_systems), config.c
(fin_directory_list), sys1.unx (fsysdep_in_directory), sys5.unx
@@ -2192,7 +3427,7 @@ Sun Feb 23 14:45:53 1992 Ian Lance Taylor (ian@comton.airs.com)
zcalled_remote_receive fields to ssysteminfo structure for this,
and handled them in all the appropriate places.
-Sat Feb 22 22:30:59 1992 Ian Lance Taylor (ian@comton.airs.com)
+Sat Feb 22 22:30:59 1992 Ian Lance Taylor (ian@airs.com)
* Complete overhaul of configuration to use automatic shell
script. Eliminated conf.h, now generated by configure. Renamed
@@ -2200,12 +3435,12 @@ Sat Feb 22 22:30:59 1992 Ian Lance Taylor (ian@comton.airs.com)
decisions and other choices which can not be made automatically.
Many changes to many source files, none having to do with code.
-Thu Feb 20 17:57:55 1992 Ian Lance Taylor (ian at comton.airs.com)
+Thu Feb 20 17:57:55 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (fdo_call): Chip Salzenberg: some systems truncate the
Shere= machine name to 7 characters.
-Wed Feb 19 14:36:31 1992 Ian Lance Taylor (ian at comton.airs.com)
+Wed Feb 19 14:36:31 1992 Ian Lance Taylor (ian@airs.com)
* sys7.unx (fskill_or_rejuv): make sure that only the submitter or
the superuser is permitted to cancel (or rejuvenate) a request.
@@ -2223,12 +3458,12 @@ Wed Feb 19 14:36:31 1992 Ian Lance Taylor (ian at comton.airs.com)
to take a time returned by isysdep_time rather than always use the
current time. Changed the calls as appropriate.
-Tue Feb 18 14:03:19 1992 Ian Lance Taylor (ian at comton.airs.com)
+Tue Feb 18 14:03:19 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (main): pass fdaemon argument correctly to
usysdep_initialize.
-Mon Feb 17 17:09:16 1992 Ian Lance Taylor (ian at comton.airs.com)
+Mon Feb 17 17:09:16 1992 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (uqdo_xqt_file): T. William Wells: make sure sh uses
absolute path of command, rather than relying on PATH.
@@ -2242,7 +3477,7 @@ Mon Feb 17 17:09:16 1992 Ian Lance Taylor (ian at comton.airs.com)
* sys2.unx (fsrun_chat): Bob Denny: log chat program messages as
LOG_NORMAL, not LOG_ERROR.
-Fri Feb 14 00:17:57 1992 Ian Lance Taylor (ian at comton.airs.com)
+Fri Feb 14 00:17:57 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (ucatch), uuxqt.c (uqcatch): Neils Baggesen: under
HAVE_BNU_LOGGING, don't lose the system name when dieing.
@@ -2260,7 +3495,7 @@ Fri Feb 14 00:17:57 1992 Ian Lance Taylor (ian at comton.airs.com)
* uucp.c (main): Niels Baggesen: abtname must be copied into
memory, or it will be overwritten by the next file to be copied.
-Sun Feb 9 00:12:58 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sun Feb 9 00:12:58 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (fuucp), prot.c (fsend_file, freceive_file): Bob Denny:
call fmail_transfer before calling fsysdep_did_work, because the
@@ -2272,7 +3507,7 @@ Sun Feb 9 00:12:58 1992 Ian Lance Taylor (ian at comton.airs.com)
suid program uudir which sets its uid to uucp and invokes
/bin/mkdir. Added rules to create uudir to Makefile.
-Sat Feb 8 14:25:50 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sat Feb 8 14:25:50 1992 Ian Lance Taylor (ian@airs.com)
* sysh.unx, sys1.unx (opendir, readdir, closedir), sys4.unx,
sys5.unx: added HAVE_OLD_DIRECTORIES configuration parameter to
@@ -2321,7 +3556,7 @@ Sat Feb 8 14:25:50 1992 Ian Lance Taylor (ian at comton.airs.com)
related variables by macro defining them to gnu_*. This avoids
conflicts with system header files and system libraries.
-Fri Feb 7 12:08:42 1992 Ian Lance Taylor (ian at comton.airs.com)
+Fri Feb 7 12:08:42 1992 Ian Lance Taylor (ian@airs.com)
* everything: added HAVE_STRING_H and HAVE_STRINGS_H. Removed
include of <string.h> in every source file and put it in uucp.h.
@@ -2331,7 +3566,7 @@ Fri Feb 7 12:08:42 1992 Ian Lance Taylor (ian at comton.airs.com)
* uucico.c (fcall): Bob Denny: retry time not reached is not
really an error, so just make a normal log entry for it.
-Sun Feb 2 01:38:47 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sun Feb 2 01:38:47 1992 Ian Lance Taylor (ian@airs.com)
* uucp.c (main): Get the file name for the destination of a local
copy using zsysdep_real_file_name rather than zsysdep_in_dir,
@@ -2350,7 +3585,7 @@ Sun Feb 2 01:38:47 1992 Ian Lance Taylor (ian at comton.airs.com)
be separated by more than just a single space if they are read
from a V2 or BNU configuration file.
-Fri Jan 31 19:51:57 1992 Ian Lance Taylor (ian at comton.airs.com)
+Fri Jan 31 19:51:57 1992 Ian Lance Taylor (ian@airs.com)
* protg.c: Chip Salzenberg: change default window size to 7.
@@ -2360,12 +3595,12 @@ Fri Jan 31 19:51:57 1992 Ian Lance Taylor (ian at comton.airs.com)
* log.c (ulog): Michael Nolan: if SIGABRT is not defined, just
call abort.
-Thu Jan 30 18:19:33 1992 Ian Lance Taylor (ian at comton.airs.com)
+Thu Jan 30 18:19:33 1992 Ian Lance Taylor (ian@airs.com)
* bnu.c (ubadd_perm): Michael Nolan: debugging check was done
wrong for entry with LOGNAME but no MACHINE.
-Wed Jan 29 13:28:59 1992 Ian Lance Taylor (ian at comton.airs.com)
+Wed Jan 29 13:28:59 1992 Ian Lance Taylor (ian@airs.com)
* uucico.c (zget_uucp_cmd): Patrick Smith: only wait a short time
for the hangup string.
@@ -2373,7 +3608,7 @@ Wed Jan 29 13:28:59 1992 Ian Lance Taylor (ian at comton.airs.com)
* sys4.unx (iswork_cmp): Patrick Smith: fixed casts to not cast
away const.
-Tue Jan 28 11:06:34 1992 Ian Lance Taylor (ian at comton.airs.com)
+Tue Jan 28 11:06:34 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx, sys3.unx, tstuu.c: Jay Vassos-Libove: removed some
declarations of system functions that conflict with system header
@@ -2384,7 +3619,7 @@ Tue Jan 28 11:06:34 1992 Ian Lance Taylor (ian at comton.airs.com)
* protg.c (fgsendcmd): the previous patch wasn't really correct.
-Mon Jan 27 22:30:47 1992 Ian Lance Taylor (ian at comton.airs.com)
+Mon Jan 27 22:30:47 1992 Ian Lance Taylor (ian@airs.com)
* log.c (ustats): Marty Shannon: don't report a failed transfer
under USE_BNU_LOGGING.
@@ -2403,7 +3638,7 @@ Mon Jan 27 22:30:47 1992 Ian Lance Taylor (ian at comton.airs.com)
end of command which was exactly a power of two in length
correctly.
-Tue Jan 21 14:37:10 1992 Ian Lance Taylor (ian at comton.airs.com)
+Tue Jan 21 14:37:10 1992 Ian Lance Taylor (ian@airs.com)
* Released version 1.02.
@@ -2411,7 +3646,7 @@ Tue Jan 21 14:37:10 1992 Ian Lance Taylor (ian at comton.airs.com)
zcone_system), sys1.unx (fsysdep_run): Chip Salzenberg: have uucp
and uux start up uucico -s system rather than uucico -r1.
-Mon Jan 20 11:45:38 1992 Ian Lance Taylor (ian at comton.airs.com)
+Mon Jan 20 11:45:38 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx (fsysdep_make_dirs): don't try to create a directory
with no name.
@@ -2427,7 +3662,7 @@ Mon Jan 20 11:45:38 1992 Ian Lance Taylor (ian at comton.airs.com)
the .Status file if it's the wrong time to call, and upon
receiving a call.
-Sun Jan 19 13:29:23 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sun Jan 19 13:29:23 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgsendcmd, fgsenddata): Dave Platt: if the remote UUCP
accepts packets larger than 64 bytes, assume it can handle
@@ -2443,7 +3678,7 @@ Sun Jan 19 13:29:23 1992 Ian Lance Taylor (ian at comton.airs.com)
* conf.h, uucp.h, util.c (bsearch): added HAVE_BSEARCH
configuration parameter.
-Sat Jan 18 17:45:28 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sat Jan 18 17:45:28 1992 Ian Lance Taylor (ian@airs.com)
* tstuu.c (utransfer): Mike Park: don't sleep when the input
buffer is full; it's too slow.
@@ -2463,7 +3698,7 @@ Sat Jan 18 17:45:28 1992 Ian Lance Taylor (ian at comton.airs.com)
permanently and does not remove file if request fails only
temporarily.
-Thu Jan 16 11:33:08 1992 Ian Lance Taylor (ian at comton.airs.com)
+Thu Jan 16 11:33:08 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgsendcmd, fgsenddata): zero out unused bytes in short
packets.
@@ -2484,7 +3719,7 @@ Thu Jan 16 11:33:08 1992 Ian Lance Taylor (ian at comton.airs.com)
* sys2.unx, tstuu.c: Mike Park: ioctl is sometimes declared
varadic, so we can't declare it.
-Wed Jan 15 02:03:43 1992 Ian Lance Taylor (ian at comton.airs.com)
+Wed Jan 15 02:03:43 1992 Ian Lance Taylor (ian@airs.com)
* sys1.unx: put \n at end of fsysdep_run error message.
@@ -2520,7 +3755,7 @@ Wed Jan 15 02:03:43 1992 Ian Lance Taylor (ian at comton.airs.com)
configuration files are looked up using NEWCONFIGLIB. Old style
configuration files are looked up using OLDCONFIGLIB.
-Mon Jan 13 00:35:43 1992 Ian Lance Taylor (ian at comton.airs.com)
+Mon Jan 13 00:35:43 1992 Ian Lance Taylor (ian@airs.com)
* sys3.unx: David Nugent: don't declare chmod, since it may be
prototyped to take an argument that is smaller than an int.
@@ -2566,7 +3801,7 @@ Mon Jan 13 00:35:43 1992 Ian Lance Taylor (ian at comton.airs.com)
* sysinf.c (tisystem): Mike Park: ulog was being passed the wrong
number of arguments.
-Sun Jan 12 14:32:47 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sun Jan 12 14:32:47 1992 Ian Lance Taylor (ian@airs.com)
* Eliminated CONFIG, INSTALL and THANKS. They are now included in
uucp.texi. Changed README and MANIFEST accordingly. Added
@@ -2580,7 +3815,7 @@ Sun Jan 12 14:32:47 1992 Ian Lance Taylor (ian at comton.airs.com)
* log.c (ulog): allocate enough bytes to name file if
HAVE_BNU_LOGGING is in use but zLogfile has no %s.
-Sat Jan 11 12:11:56 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sat Jan 11 12:11:56 1992 Ian Lance Taylor (ian@airs.com)
* Makefile: changed to correspond to GNU standards, according to
standards.text of 24 Nov 91.
@@ -2597,7 +3832,7 @@ Sat Jan 11 12:11:56 1992 Ian Lance Taylor (ian at comton.airs.com)
structure to avoid bug in AIX compiler which causes it to fail to
recognize an address constant containing the -> operator.
-Tue Jan 7 10:22:43 1992 Ian Lance Taylor (ian at comton.airs.com)
+Tue Jan 7 10:22:43 1992 Ian Lance Taylor (ian@airs.com)
* Released beta 1.02.
@@ -2608,7 +3843,7 @@ Tue Jan 7 10:22:43 1992 Ian Lance Taylor (ian at comton.airs.com)
* sysinf.c (tadd_proto_param): Niels Baggesen: allocate number of
protocol parameters based on *pc, not sIhold.cproto_params.
-Sat Jan 4 16:42:21 1992 Ian Lance Taylor (ian at comton.airs.com)
+Sat Jan 4 16:42:21 1992 Ian Lance Taylor (ian@airs.com)
* log.c (ulog): tweaked HAVE_V2_LOGGING slightly.
@@ -2639,7 +3874,7 @@ Sat Jan 4 16:42:21 1992 Ian Lance Taylor (ian at comton.airs.com)
option ALLOW_FILENAME_ARGUMENTS to permit arguments that look like
filenames, to allow undoing the patch I just made.
-Fri Jan 3 00:44:59 1992 Ian Lance Taylor (ian at comton.airs.com)
+Fri Jan 3 00:44:59 1992 Ian Lance Taylor (ian@airs.com)
* system.h, uuxqt.c (uqdo_xqt_file), sys5.unx
(fsysdep_xqt_check_file): David J. Fiander: make sure that if an
@@ -2648,12 +3883,12 @@ Fri Jan 3 00:44:59 1992 Ian Lance Taylor (ian at comton.airs.com)
* sys3.unx (fsdo_lock): remove temporary file if link fails in
fsdo_lock.
-Thu Jan 2 00:01:53 1992 Ian Lance Taylor (ian at comton.airs.com)
+Thu Jan 2 00:01:53 1992 Ian Lance Taylor (ian@airs.com)
* protg.c (fgstart, fgshutdown, fgprocess_data): count remote
rejections separately from resent packets when counting errors.
-Tue Dec 31 14:31:38 1991 Ian Lance Taylor (ian at comton.airs.com)
+Tue Dec 31 14:31:38 1991 Ian Lance Taylor (ian@airs.com)
* protg.c (fgstart): Franc,ois Pinard: forgot to initialize
cGdelayed_packets.
@@ -2666,13 +3901,13 @@ Tue Dec 31 14:31:38 1991 Ian Lance Taylor (ian at comton.airs.com)
sent; fixed bug in freceive_data which caused to ask for the wrong
number of bytes when the buffer was empty.
-Mon Dec 30 23:16:48 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Dec 30 23:16:48 1991 Ian Lance Taylor (ian@airs.com)
* sys2.unx (fsserial_open): Chip Salzenberg: don't turn on IXON
and IXOFF initially; after all, the initialization packets might
contain an XOFF character.
-Sun Dec 29 00:00:42 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sun Dec 29 00:00:42 1991 Ian Lance Taylor (ian@airs.com)
* uucp.h, prot.c (fploop): John Theus: check for EOF before
reading from file to work around bug in Tektronix library.
@@ -2686,7 +3921,7 @@ Sun Dec 29 00:00:42 1991 Ian Lance Taylor (ian at comton.airs.com)
* log.c (zldate_and_time): wasn't allocating enough buffer space.
-Sat Dec 28 01:09:58 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Dec 28 01:09:58 1991 Ian Lance Taylor (ian@airs.com)
* uuxqt.c (uqdo_xqt_file): forgot to initialize zmail.
@@ -2719,7 +3954,7 @@ Sat Dec 28 01:09:58 1991 Ian Lance Taylor (ian at comton.airs.com)
* conf.h, uucp.h, util.c, getopt.c, tstuu.c: added HAVE_STRCHR and
HAVE_INDEX to conf.h.
-Fri Dec 27 01:00:41 1991 Ian Lance Taylor (ian at comton.airs.com)
+Fri Dec 27 01:00:41 1991 Ian Lance Taylor (ian@airs.com)
* uucico.c (fuucp): set fmasterdone correctly when running as a
slave.
@@ -2740,18 +3975,18 @@ Fri Dec 27 01:00:41 1991 Ian Lance Taylor (ian at comton.airs.com)
parameter ``errors'' to set maximum number of errors permitted.
Also made fgprocess_data only reply once per batch of data.
-Thu Dec 26 17:54:54 1991 Ian Lance Taylor (ian at comton.airs.com)
+Thu Dec 26 17:54:54 1991 Ian Lance Taylor (ian@airs.com)
* tcp.c (ftcp_dial, itcp_port_number): Monty Solomon: cast
arguments to avoid prototype errors on NeXT.
-Mon Dec 23 00:16:19 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Dec 23 00:16:19 1991 Ian Lance Taylor (ian@airs.com)
* uucp.h, sysinf.c, uucico.c (main, flogin_prompt, faccept_call),
uuchk.c (main): David Nugent: allow debugging level to be set for
a specific system.
-Sun Dec 22 15:51:10 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sun Dec 22 15:51:10 1991 Ian Lance Taylor (ian@airs.com)
* conf.h, uucp.c, sysh.unx, tcp.c, sys1.unx, sys2.unx, sys3.unx,
sys5.unx, sys6.unx, tstuu.c: Monty Solomon: added HAVE_UNISTD_H to
@@ -2769,7 +4004,7 @@ Sun Dec 22 15:51:10 1991 Ian Lance Taylor (ian at comton.airs.com)
* uucp.h: Monty Solomon: removed prototypes for strcasecmp and
strncasecmp from uucp.h, since they may be in string.h.
-Sat Dec 21 16:04:58 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Dec 21 16:04:58 1991 Ian Lance Taylor (ian@airs.com)
* uucp.h, uucico.c (ucatch), prot.c (fpsendfile_confirm,
fprecfile_confirm, ustats_failed), file.c (fsent_file,
@@ -2795,7 +4030,7 @@ Sat Dec 21 16:04:58 1991 Ian Lance Taylor (ian at comton.airs.com)
* sys1.unx (fsysdep_run): use the real program name from abProgram
in the error messages in fsysdep_run.
-Thu Dec 19 19:02:28 1991 Ian Lance Taylor (ian at comton.airs.com)
+Thu Dec 19 19:02:28 1991 Ian Lance Taylor (ian@airs.com)
* uucico.c (fdo_call, faccept_call): Terry Gardner: put the length
of the conversation in the ``Call complete'' log file message.
@@ -2829,7 +4064,7 @@ Thu Dec 19 19:02:28 1991 Ian Lance Taylor (ian at comton.airs.com)
optimized the protocol to wait for up to seven characters at a
time rather than just one.
-Wed Dec 18 00:12:42 1991 Ian Lance Taylor (ian at comton.airs.com)
+Wed Dec 18 00:12:42 1991 Ian Lance Taylor (ian@airs.com)
* sysh.unx, sys2.unx, tstuu.c: Terry Gardner: added
USE_FOR_UNBLOCKED configuration parameter to support systems that
@@ -2852,7 +4087,7 @@ Wed Dec 18 00:12:42 1991 Ian Lance Taylor (ian at comton.airs.com)
-l option to uucico to prompt for the login name and password once
and then exit.
-Tue Dec 17 00:24:41 1991 Ian Lance Taylor (ian at comton.airs.com)
+Tue Dec 17 00:24:41 1991 Ian Lance Taylor (ian@airs.com)
* uucp.h, uucico.c, uuxqt.c, uux.c, uucp.c, config.c
(uread_config), log.c (ulog): eliminated ulog_program and added
@@ -2894,7 +4129,7 @@ Tue Dec 17 00:24:41 1991 Ian Lance Taylor (ian at comton.airs.com)
when a serial port is opened. This will clear out a
NO\sCARRIER string left by a previous dropped connection.
-Mon Dec 16 11:26:17 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Dec 16 11:26:17 1991 Ian Lance Taylor (ian@airs.com)
* uucico.c (main), uuxqt.c (main), tstuu.c (main, uchild): David
Nugent: ignore SIGHUP in uucico and uuxqt, so that they are
@@ -2905,7 +4140,7 @@ Mon Dec 16 11:26:17 1991 Ian Lance Taylor (ian at comton.airs.com)
fbnu_read_dialer_info): Mike Bernson: ignore lines that begin with
whitespace, fix compilation error.
-Sat Dec 14 20:59:10 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Dec 14 20:59:10 1991 Ian Lance Taylor (ian@airs.com)
* sys2.unx (fsserial_open): don't turn on ISTRIP initially.
@@ -2932,12 +4167,12 @@ Sat Dec 14 20:59:10 1991 Ian Lance Taylor (ian at comton.airs.com)
processing files just because opendir failed on one; it could just
be because we don't have read permission.
-Fri Dec 13 17:43:52 1991 Ian Lance Taylor (ian at comton.airs.com)
+Fri Dec 13 17:43:52 1991 Ian Lance Taylor (ian@airs.com)
* config.c (uprocesscmds): don't continually allocate and free the
array of arguments.
-Thu Dec 12 12:46:01 1991 Ian Lance Taylor (ian at comton.airs.com)
+Thu Dec 12 12:46:01 1991 Ian Lance Taylor (ian@airs.com)
* prot.c (fgetcmd): Franc,ois Pinard: don't bother to give an
error if the final HY doesn't come in; apparently the MtXinu UUCP
@@ -2962,7 +4197,7 @@ Thu Dec 12 12:46:01 1991 Ian Lance Taylor (ian at comton.airs.com)
GID as well as the UID, in case anybody wants to run this as a
setgid package.
-Wed Dec 11 10:03:22 1991 Ian Lance Taylor (ian at comton.airs.com)
+Wed Dec 11 10:03:22 1991 Ian Lance Taylor (ian@airs.com)
* conf.h, uucp.h, util.c (strtol): Mark Powell: added my own
version of strtol to util.c, for systems which lack it.
@@ -2972,7 +4207,7 @@ Wed Dec 11 10:03:22 1991 Ian Lance Taylor (ian at comton.airs.com)
already seen; otherwise the other side may assume we've already
seen them while we're looking for them.
-Tue Dec 10 15:42:41 1991 Ian Lance Taylor (ian at comton.airs.com)
+Tue Dec 10 15:42:41 1991 Ian Lance Taylor (ian@airs.com)
* conf.h, sysh.unx, log.c (ulog, ustats), tstuu.c (uprepare_test):
Arne Ludwig: merged in Arne Ludwig's patches to support V2 and BNU
@@ -2994,7 +4229,7 @@ Tue Dec 10 15:42:41 1991 Ian Lance Taylor (ian at comton.airs.com)
file.c to log.c in preparation for supporting BNU log file
routines.
-Mon Dec 9 12:00:52 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Dec 9 12:00:52 1991 Ian Lance Taylor (ian@airs.com)
* bnu.c (ubnu_read_systems): Arne Ludwig: the device entry for a
system can be followed by a comma and a list of protocols.
@@ -3017,7 +4252,7 @@ Mon Dec 9 12:00:52 1991 Ian Lance Taylor (ian at comton.airs.com)
* config.c (uprocesscmds): Richard Todd: don't warn if the special
"#" command is unrecognized.
-Sat Dec 7 13:05:40 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Dec 7 13:05:40 1991 Ian Lance Taylor (ian@airs.com)
* config.c (uprocesscmds): Franc,ois Pinard: don't limit the
number of arguments to a command!
@@ -3025,7 +4260,7 @@ Sat Dec 7 13:05:40 1991 Ian Lance Taylor (ian at comton.airs.com)
* chat.c (fchat): handle a chat script which consists only of a
single string.
-Fri Dec 6 16:11:29 1991 Ian Lance Taylor (ian at comton.airs.com)
+Fri Dec 6 16:11:29 1991 Ian Lance Taylor (ian@airs.com)
* sys5.unx (fsysdep_execute): David J. Fiander: if execve fails
with ENOEXEC, try using /bin/sh with a quoted argument.
@@ -3050,7 +4285,7 @@ Fri Dec 6 16:11:29 1991 Ian Lance Taylor (ian at comton.airs.com)
return a negative number, since the callers don't know how to deal
with that.
-Mon Dec 2 16:26:16 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Dec 2 16:26:16 1991 Ian Lance Taylor (ian@airs.com)
* bnu.c (ubnu_read_systems): Dave Buck: time strings with grades
were parsed in an endless loop!
@@ -3065,7 +4300,7 @@ Mon Dec 2 16:26:16 1991 Ian Lance Taylor (ian at comton.airs.com)
the ``protocol-parameter'' command didn't work for ports or
dialers.
-Sun Dec 1 09:46:12 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sun Dec 1 09:46:12 1991 Ian Lance Taylor (ian@airs.com)
* tstuu.c: don't use the fd_set typedef at all.
@@ -3079,7 +4314,7 @@ Sun Dec 1 09:46:12 1991 Ian Lance Taylor (ian at comton.airs.com)
* uuchk.c (fkshow_port): Bob Izenberg: report dialer/token pairs
correctly.
-Sat Nov 30 17:40:00 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Nov 30 17:40:00 1991 Ian Lance Taylor (ian@airs.com)
* tstuu.c: Bob Izenberg: copied over conditional definitions of
EAGAIN and EWOULDBLOCK from sys2.unx.
@@ -3123,7 +4358,7 @@ Sat Nov 30 17:40:00 1991 Ian Lance Taylor (ian at comton.airs.com)
auto array abpubdir, since old cc didn't permit initialization of
auto aggregates.
-Mon Nov 25 20:56:39 1991 Ian Lance Taylor (ian at comton.airs.com)
+Mon Nov 25 20:56:39 1991 Ian Lance Taylor (ian@airs.com)
* tstuu.c: Bob Denny: add definitions for FD_SET, FD_ZERO and
FD_ISSET.
@@ -3141,12 +4376,12 @@ Mon Nov 25 20:56:39 1991 Ian Lance Taylor (ian at comton.airs.com)
(fv2_find_port): Marty Shannon: the ireliable field of ports
and dialers was not getting initialized.
-Sun Nov 24 15:06:37 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sun Nov 24 15:06:37 1991 Ian Lance Taylor (ian@airs.com)
* tcp.c (itcp_port_number): Michael Haberler: wasn't calling
htons if passed a numeric string.
-Sat Nov 23 13:43:52 1991 Ian Lance Taylor (ian at comton.airs.com)
+Sat Nov 23 13:43:52 1991 Ian Lance Taylor (ian@airs.com)
* Released version 1.01 to alt.sources and uunet
diff --git a/gnu/libexec/uucp/Makefile.inc b/gnu/libexec/uucp/Makefile.inc
index b9bac708a1ab..a40e0a35300b 100644
--- a/gnu/libexec/uucp/Makefile.inc
+++ b/gnu/libexec/uucp/Makefile.inc
@@ -16,9 +16,9 @@ LIBUUCP= $(.CURDIR)/../libuucp/obj/libuucp.a
LIBUUCP= $(.CURDIR)/../libuucp/libuucp.a
.endif
-VERSION= 1.04
+VERSION= 1.05
owner= uucp
-group= wheel
+group= uucp
bindir= /usr/bin
sbindir= /usr/libexec/uucp
diff --git a/gnu/libexec/uucp/NEWS b/gnu/libexec/uucp/NEWS
new file mode 100644
index 000000000000..65360d57fa8e
--- /dev/null
+++ b/gnu/libexec/uucp/NEWS
@@ -0,0 +1,119 @@
+Changes in version 1.05:
+
+ As usual, many bugs were fixed.
+
+ Support was added for the UUPC/extended 'v' protocol.
+
+ Initial hardware flow control support was added, contributed by
+ Peter Wemm.
+
+ A new port type, ``pipe'', was added; this sends data to a program
+ such as rlogin, and was contributed by Marc Boucher.
+
+ The programs all now accept long option names with a leading --.
+ They all support --help and --version.
+
+ uuxqt now saves execution files it can not parse in
+ $(SPOOLDIR)/.Corrupt.
+
+ If a received file can not be moved to the final location, and
+ there is enough disk space, it is kept in the spool directory.
+
+ A run-uuxqt command was added to config, to permit specifying when
+ uuxqt should be run.
+
+ The 'i' protocol has a new ack-frequency protocol parameter. The
+ remote-window protocol parameter was removed, as it did not work
+ correctly.
+
+ Chat scripts now permit /W in an expect string to set the timeout.
+
+ TCP ports now support the ``dialer-sequence'' command.
+
+ Direct ports now support the ``carrier'' command.
+
+ Some support was added to read UUCP passwords from /etc/passwd,
+ and to use encrypted passwords.
+
+ uucico now accepts a -C argument to only call a system named by -S
+ or -s if there is work for it.
+
+ uucico accepts a -i TLI argument to use TLI I/O calls on standard
+ input.
+
+ uucico accepts a -u argument to set the user name.
+
+ uucico accepts a -z argument to try the next alternate if a call
+ fails.
+
+ uustat accepts a -R argument to rejuvenate each listed job.
+
+ Mailer configuration was moved from configure checking to
+ policy.h.
+
+ Support was added for QNX, contributed by Joe Wells.
+
+Changes in version 1.04:
+
+IMPORTANT: the default when talking to another version of 1.04 is to
+use the new bidirectional 'i' protocol. If you are using a
+half-duplex modem, such as a Telebit T2500, you will want to either
+mark the port as half-duplex with the ``half-duplex'' command, or
+force use of the 'g' protocol by using the ``protocol'' command in the
+sys or port file or by adding ``,g'' after the port name in the
+Systems or L.sys or Devices file.
+
+ As usual, many bugs were fixed.
+
+ Bidirectional transfers are supported with the new 'i' protocol;
+ it requires an eight-bit clear datapath.
+
+ New programs: uusched, cu, uuto and uupick.
+
+ The 'G' protocol and a new Zmodem protocol were added.
+
+ A number of uustat options were added to support uuclean, and a
+ sample uuclean shell script was added to the contrib directory.
+ The uustat output formats were changed slightly.
+
+ A protocol extension eliminates transfer of the command file for
+ simple commands, such as rmail or rnews, when talking to another
+ version of 1.04.
+
+ Some TLI support was added.
+
+ UUCP forwarding was added, along with the ``forward-to'',
+ ``forward-from'' and ``forward'' commands.
+
+ If a file transfer fails in the middle, the retry will now start
+ from where it left off. The implementation is compatible with
+ SVR4.
+
+ The work queue is checked every 10 minutes during a conversation;
+ if there is new work and a bidirectional protocol is not in use,
+ the receiving uucico requests the sender to transfer control.
+
+ The amount of free disk space is checked periodically as a file is
+ received, and if it drops too low the call is aborted.
+
+ The UUCP configuration file reading routines were moved into a
+ standalone library, uuconf. All known bugs in V2 and HDB
+ configuration file reading were fixed.
+
+ The ``half-duplex'' command was added for the port and dialer
+ files.
+
+ The ``max-retries'', ``success-wait'', ``send-request'' and
+ ``receive-request'' commands were added for the sys file. The
+ ``call-request'' and ``called-request'' commands were eliminated
+ (they did not work correctly anyhow).
+
+ \d in chat scripts now calls sleep (2) rather than sleep (1), so
+ it will sleep longer (on some systems sleep(1) may delay much less
+ than one second).
+
+ SPOOLDIR_SVR4 was added for SVR4 style spool directories.
+
+ Defaults are now permitted in the port and dialer files.
+
+ The ALIAS field is supported in the HDB Permissions file.
diff --git a/gnu/libexec/uucp/README b/gnu/libexec/uucp/README
index bfcd46c3f2ae..8d69444fd62f 100644
--- a/gnu/libexec/uucp/README
+++ b/gnu/libexec/uucp/README
@@ -1,8 +1,8 @@
-This is the README file for version 1.04 of the Taylor UUCP package.
+This is the README file for version 1.05 of the Taylor UUCP package.
It was written by Ian Lance Taylor. I can be reached at ian@airs.com,
-or, equivalently, uunet!cygint!airs!ian, or c/o Cygnus Support, 4th
-Floor, Building 200, 1 Kendall Square, Cambridge MA, 02139, USA.
+or, equivalently, uunet!cygint!airs!ian, or c/o Cygnus Support,
+Building 200, 1 Kendall Square, Cambridge MA, 02139, USA.
There is a mailing list for discussion of the package. To join (or
get off) the list, send mail to taylor-uucp-request@gnu.ai.mit.edu.
@@ -11,6 +11,10 @@ joining the list, make sure you include the address at which you want
to receive mail in the body of your message. To send a message to the
list, send it to taylor-uucp@gnu.ai.mit.edu.
+Jeff Ross has volunteered to maintain patches for UUCP releases. They
+may be obtained via anonymous FTP from ftp.fdu.edu, in the directory
+pub/taylor-uucp.
+
This package is covered by the Gnu Public License. See the file
COPYING for details. If you would like to do something with this
package that you feel is reasonable but you feel is prohibited by the
@@ -25,8 +29,7 @@ uupick, and cu, as well as uuchk (a program to check configuration
files), uuconv (a program to convert from one type of configuration
file to another) and tstuu (a test harness for the package).
-The Free Software Foundation plans to make this their standard UUCP
-package.
+This is the standard UUCP package of the Free Software Foundation.
The package currently supports the 'f', 'g' (in all window and packet
sizes), 'G', 't' and 'e' protocols, as well a Zmodem protocol and two
@@ -77,80 +80,13 @@ If you start using this package, I suggest that you join the mailing
list (see above) to keep up to date on patches and new versions. I am
also open to suggestions for improvements and modifications.
-CHANGES SINCE 1.03
-
-For a complete list, see ChangeLog.
-
-IMPORTANT: the default when talking to another version of 1.04 is to
-use the new bidirectional 'i' protocol. If you are using a
-half-duplex modem, such as a Telebit T2500, you will want to either
-mark the port as half-duplex with the ``half-duplex'' command, or
-force use of the 'g' protocol by using the ``protocol'' command in the
-sys or port file or by adding ``,g'' after the port name in the
-Systems or L.sys or Devices file.
-
- As usual, many bugs were fixed.
-
- Bidirectional transfers are supported with the new 'i' protocol;
- it requires an eight-bit clear datapath.
-
- New programs: uusched, cu, uuto and uupick.
-
- The 'G' protocol and a new Zmodem protocol were added.
-
- A number of uustat options were added to support uuclean, and a
- sample uuclean shell script was added to the contrib directory.
- The uustat output formats were changed slightly.
-
- A protocol extension eliminates transfer of the command file for
- simple commands, such as rmail or rnews, when talking to another
- version of 1.04.
-
- Some TLI support was added.
-
- UUCP forwarding was added, along with the ``forward-to'',
- ``forward-from'' and ``forward'' commands.
-
- If a file transfer fails in the middle, the retry will now start
- from where it left off. The implementation is compatible with
- SVR4.
-
- The work queue is checked every 10 minutes during a conversation;
- if there is new work and a bidirectional protocol is not in use,
- the receiving uucico requests the sender to transfer control.
-
- The amount of free disk space is checked periodically as a file is
- received, and if it drops too low the call is aborted.
-
- The UUCP configuration file reading routines were moved into a
- standalone library, uuconf. All known bugs in V2 and HDB
- configuration file reading were fixed.
-
- The ``half-duplex'' command was added for the port and dialer
- files.
-
- The ``max-retries'', ``success-wait'', ``send-request'' and
- ``receive-request'' commands were added for the sys file. The
- ``call-request'' and ``called-request'' commands were eliminated
- (they did not work correctly anyhow).
-
- \d in chat scripts now calls sleep (2) rather than sleep (1), so
- it will sleep longer (on some systems sleep(1) may delay much less
- than one second).
-
- SPOOLDIR_SVR4 was added for SVR4 style spool directories.
-
- Defaults are now permitted in the port and dialer files.
-
- The ALIAS field is supported in the HDB Permissions file.
-
DOCUMENTATION
The documentation is in the file uucp.texi, which is a Texinfo file.
Texinfo is a format used by the Free Software Foundation. You can
print the documentation using TeX in combination with the file
texinfo.tex. DVI, PostScript and info versions of the documentation
-are available in a separate package, uucp-doc-1.04.tar.Z.
+are available in a separate package, uucp-doc-1.05.tar.gz.
See the TODO file for things which should be done. Please feel free
to do them, although you may want to check with me first. Send me
@@ -174,7 +110,7 @@ The compilation instructions are in uucp.texi. Here is a summary.
what is available on your system, so if your system is at all
unusual you will need to pass in $CC and $LIBS correctly.
- The configure script will create conf.h from conf.h.in and
+ The configure script will create config.h from config.h.in and
Makefile from Makefile.in. It will also create config.status,
which is a shell script which actually creates the files. Please
report any configuration problems, so that they can be fixed in
@@ -195,7 +131,23 @@ The compilation instructions are in uucp.texi. Here is a summary.
use -posix, instead I run gcc with -D_POSIX_SOURCE, and add
-lcposix to LIBS.
- Examine conf.h and Makefile to make sure they're right.
+ On some versions of BSDI there is a bug in the shell which causes
+ the default value for CFLAGS to be set incorrectly. If ``echo
+ ${CFLAGS--g}'' echoes ``g'' rather than ``-g'', then you must set
+ CFLAGS in the environment before running configure. There is a
+ patch available from BSDI for this bug. (From David Vrona).
+
+ On AIX 3.2.5, and possibly other versions, cc -E does not work,
+ reporting ``Option NOROCONST is not valid.'' Test this before
+ running configure by doing something like
+ touch /tmp/foo.c
+ cc -E /tmp/foo.c
+ This may give a warning about the file being empty, but it should
+ not give the ``Option NOROCONST'' warning. The workaround is to
+ remove the ",noroconst" entry from the "options" clause in the
+ "cc" stanza in /etc/xlc.cfg. (From Chris Lewis).
+
+ Examine config.h and Makefile to make sure they're right.
Edit policy.h for your local system.
@@ -204,4 +156,7 @@ The compilation instructions are in uucp.texi. Here is a summary.
Use ``uuchk'' to check configuration files. You can use
``uuconv'' to convert between configuration file formats.
- Type ``make install'' to install.
+ Type ``make install'' to install. Note that by default the
+ programs are compiled with debugging information, and they are not
+ stripped when they are installed. Read the man page for strip for
+ more information.
diff --git a/gnu/libexec/uucp/TODO b/gnu/libexec/uucp/TODO
index a1cc643ab52f..a0e96bfdc8cc 100644
--- a/gnu/libexec/uucp/TODO
+++ b/gnu/libexec/uucp/TODO
@@ -92,11 +92,6 @@ UUCP protocols to do file transfers. This would allow ftp work to be
done late at night, and allow neighbors of cooperative Internet sites
to use UUCP forwarding for anonymous FTP.
-31.
-
-David Nugent: add a -C option to uucico to only call the system if
-there is work to do.
-
32.
It would be nice if uucico could sleep until a line was available.
@@ -194,11 +189,6 @@ expect strings.
Use POSIX fcntl locks when possible instead of creating a lock file.
-130.
-
-Chip Salzenberg: BSD lets you override the timeout for a particular
-expect string by using a trailing ~.
-
138.
T. William Wells: BNU apparently uses a file named A.whatever to hold
@@ -323,20 +313,6 @@ system and command locks, and do any other type of file.
Scott Blachowicz: provide some sort of include mechanism for the
configuration files.
-162.
-
-Chris Lewis: add uuxqtpolicy command, probably in config, supporting
-the following values which determine when uuxqt should be run:
- - never (let cron or something else worry about it)
- - perinvocation (when uucico exits for good - current behaviour)
- - persite (when uucico terminates a conversation - HDBish)
- - periodic (per 5 or 10 incoming X. files - BSDish)
- - perturnaround?
-
-163.
-
-Sort jobs in the send queue by size. Pretty easy.
-
164.
Ed Carp: preserve files if uuxqt execution fails.
@@ -349,11 +325,6 @@ Marc Sheldon: use exit codes from <sysexits.h> in uux and uucp.
Chip Salzenberg: allow chat failure strings to specify a retry time.
-167.
-
-Gregory Bond: allow a dialer sequence for a TCP port, so you can make
-a TCP connection to a modem and then dial out.
-
168.
Jose A. Manas: allow a maximum connect time, after which we try to
@@ -421,14 +392,6 @@ number''.
Don Phillips: should there be some way to restrict of grade of
transfers even when the other system places the call?
-179.
-
-Nickolay Saukh: add something to chat scripts to specify the timeout
-for an expect string, e.g. AT\c OK\W3 to wait for 3 seconds. Except
-that perhaps the unit should not be seconds. Berkeley apparently uses
-~number, not \W number, but I don't see any reason to prevent use of
-the ~ character in an expect string.
-
180.
Nickolay Saukh: if we have received a partial file, request the remote
@@ -451,12 +414,6 @@ statement.
Optionally check for interrupts in fcopy_file, since it can take a
long time to copy a file named in a uucp request.
-184.
-
-Ian Moran: if an attempt is made to a copy a file to a directory which
-denies write permission, perhaps the file should be saved somewhere.
-It must be saved in a private location, though.
-
185.
A syntax error in a command received from the remote system should not
@@ -536,11 +493,6 @@ to do, and then try again later. This would require a protocol
extension. I don't know if it's worth it. The code should be checked
to see how well it handles a disk full situation.
-196.
-
-For real adjustability, provide some mechanism for picking the lead
-characters to use for the shell scripts, between : and #!.
-
197.
Try alternate IP addresses if there are any.
@@ -571,3 +523,220 @@ Bill Foote: have uuchk check whether a system is defined more than
once.
203.
+
+Eric Ziegast: allow specification of the minimum grade to receive, as
+well as the maximum grade. Probably sending a second character after
+the -pM argument would work fine.
+
+204.
+
+Tom Rushworth: perhaps there should be some program which can be used
+to retrieve the current spool directory. Perhaps on option on uustat.
+
+207.
+
+James B. O'Connor: use additional messages in the status file when
+placing a call, such as Dialing, Chatting, and the like. Slightly
+less efficient.
+
+208.
+
+When checking whether a file may be received into a directory, perhaps
+uucico should check using the real user ID rather than insisting that
+the directory be world writable. This should be a policy.h parameter.
+This would enable sites which use different uids for each incoming
+UUCP login to have better control over security.
+
+209.
+
+Jon Vos: add an alias command for ports.
+
+210.
+
+Joe Wells: I'd like to have a way so that if the dial chat fails due
+to "NO CARRIER", in addition to this log message:
+
+ ERROR: Chat script failed: Got "NO\sCARRIER"
+
+I would get another log message right next to it that would look like
+this:
+
+ ERROR: Chat script failed: 5 "RRING" strings seen
+
+Ian: I doubt this is worth implementing in uucico, but it might make
+sense for an external, or otherwise more independent and controllable,
+chat program.
+
+211.
+
+Joe Wells: In some cases it would be nice to be able to change the set
+of chat-fail strings in the middle of the chat script. Personally, I
+think this is too complex for the simple chat scripts currently
+implemented.
+
+212.
+
+Joe Wells: There should be an option to all programs directing them to
+send all debugging output to the log file. This would just involve
+calling ulog_to_file at some point just after reporting any usage
+messages.
+
+213.
+
+Joe Wells: There should be a way to specify the execution directory
+used by uuxqt. This would avoid certain sorts of permissions
+problems. Some mechanism would still be needed for using multiple
+directories.
+
+214.
+
+Joe Wells: uuto should be documented.
+
+215.
+
+Joe Wells: Perhaps it should be possible to use multiple spool
+directories. It would be a lot of work, though.
+
+216.
+
+Joe Wells: It should be possible to specify only one of complete or
+abort.
+
+217.
+
+Dan Everhart: It would be nice if the chat-fail string could affect
+the error message reported by uustat, so that uustat could say
+something ``Line was busy''.
+
+218.
+
+Andrew A. Chernov: Add a chat-char-delay xx configuration parameter,
+which has the effect of adding \p after each character, with delay xx.
+This is to accommodate modems which can't accept command characters at
+a given baud rate.
+
+219.
+
+Gert Doering: Provide some mechanism for specifying the maximum length
+of a call. Convenient for anonymous UUCP sites.
+
+220.
+
+Joe Wells: There should be some way for "cu" to obey user commands
+during the dial chat. Right now, the only thing the user can do is
+send signals (e.g. type Control-C). This leads to user complaints
+that "cu" is not obeying its documentation.
+
+221.
+
+Joe Wells: Right now, if there is any failure in the dial or login
+chat scripts, the remote system alternate is skipped even though the
+cause of the failure may have been the local serial port or modem.
+"uucico" will not try another modem with the same remote system
+alternate. If the remote system only has one alternate, then it is
+skipped entirely.
+
+Thus, there should be a way to specify that when certain expect
+strings are not seen or certain chat-fail strings are seen that the
+port is skipped instead of the remote system alternate.
+
+222.
+
+Richard H. Gumpertz: Support pipelines in uuxqt. Right now they are
+only supported if uux puts in an 'e' line (which it does) and shell
+executions are permitted (which they normally are not). It would be
+possible to permit restricted pipelines by handling the pipe character
+specially and making sure all commands in the pipeline were permitted.
+
+223.
+
+Bill Sommerfeld: When dialing out, set the status to DIALING rather
+than CONNECTION CLOSED. Setting the status takes a bit of time; it's
+hard to tell where the right break-even point is.
+
+224.
+
+Joe Wells: Keep track of the last successful incoming call separately
+from the last successful outgoing call. Currently the two times are
+both put together in the status file.
+
+225.
+
+Joe Wells: It would be nice if uustat would provide a way to avoid
+bouncing mail that it sent itself, to avoid sending notification
+e-mail for notification e-mail. I can't think of a mechanism, though
+(using a special grade for uustat does not work because most mail
+programs do not provide a mechanism for passing a grade through to
+uux).
+
+226.
+
+Joe Wells: It would be nice if uustat could know whether it had sent
+mail for a particular job, to avoid generating multiple messages for
+the job.
+
+227.
+
+Joe Wells: It would be nice if dialcode suffixes were supported, as
+well as prefixes.
+
+228.
+
+Joe Wells: It would be nice to support another spool directory scheme
+which split stuff up more to avoid very large directories. This would
+be most useful for the files which are named in C. and X. files,
+rather than for the C. and X. files themselves (since C. and X. files
+are rarely looked up by name). Basically, some sort of partition of
+the D. directory is called for.
+
+229.
+
+Joe Wells: ``It would be nice if the exit sequence of "cu", where it
+runs the complete chat script and then disconnects could be aborted
+without disconnecting. (Yes, I know, this is a strange desire.) It
+would be nice to be able to reinvoke the dial chat by user command in
+"cu". It would be nice to be able to invoke an arbitrary named chat
+script in "cu".''
+
+230.
+
+Kevin Johnson: Provide some mechanism such that all requests to a
+particular system were automatically forwarded through some other
+system. This would be useful to hide details of a non-strongly-
+connected network, particularly if the details were subject to change.
+
+231.
+
+Gert Doering: Perhaps it should be possible to -r the default for uucp
+and uux. This would require adding a new option to force the
+invocation of uucico.
+
+232.
+
+Mark Davies: spaces are not handled correctly in the -a argument of
+uux. If an E command is generated, the requestor address is not
+quoted correctly, nor is it parsed correctly. If an execution file is
+generated, the R line is not parsed correctly.
+
+233.
+
+Emmanuel Mogenet: provide some mechanism for a maximum number of
+garbage bytes during a chat script before giving up.
+
+234.
+
+Scott Ballantyne: The address for a TCP port should be separate from
+the phone number, so that a TCP dialer can use \D.
+
+235.
+
+Peter Wemm: The 'i' protocol default parameters do not work at 2400
+baud, because the time it takes to transfer half the packets is less
+than the timeout time. Of course people can always change the
+parameters, but it would be nice if this were dealt with somehow.
+
+236.
+
+Andrew A. Chernov: Perhaps uuxqt should log when it terminates.
+
+237.
diff --git a/gnu/libexec/uucp/VERSION b/gnu/libexec/uucp/VERSION
index 99fd8f0eef77..f940c9bc0bc7 100644
--- a/gnu/libexec/uucp/VERSION
+++ b/gnu/libexec/uucp/VERSION
@@ -1,4 +1,4 @@
-Version 1.04
+Version 1.05
a complete, unmodified version of this program is available from
prep.ai.mit.edu.
diff --git a/gnu/libexec/uucp/common_sources/chat.c b/gnu/libexec/uucp/common_sources/chat.c
index 8544ed2e2027..96c2942652e5 100644
--- a/gnu/libexec/uucp/common_sources/chat.c
+++ b/gnu/libexec/uucp/common_sources/chat.c
@@ -1,7 +1,7 @@
/* chat.c
Chat routine for the UUCP package.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char chat_rcsid[] = "$Id: chat.c,v 1.1 1993/08/05 18:22:30 conklin Exp $";
+const char chat_rcsid[] = "$Id: chat.c,v 1.2 1994/05/07 18:08:33 ache Exp $";
#endif
#include <ctype.h>
@@ -153,6 +153,9 @@ fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
/* Loop over subexpects and subsends. */
while (TRUE)
{
+ char *ztimeout;
+ int ctimeout;
+
/* Copy the expect string into the buffer so that we can
modify it in cescape. */
clen = strlen (*pzchat);
@@ -167,6 +170,23 @@ fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
azstrings[0] = zbuf;
if (azstrings[0][0] == '-')
++azstrings[0];
+
+ /* \Wnum at the end of the string is a timeout. */
+ ctimeout = qchat->uuconf_ctimeout;
+ ztimeout = strrchr (azstrings[0], '\\');
+ if (ztimeout != NULL && ztimeout[1] == 'W')
+ {
+ char *zend;
+ int cval;
+
+ cval = (int) strtol (ztimeout + 2, &zend, 10);
+ if (zend != ztimeout + 2 && *zend == '\0')
+ {
+ ctimeout = cval;
+ *ztimeout = '\0';
+ }
+ }
+
aclens[0] = cescape (azstrings[0]);
if (aclens[0] == 0
@@ -185,8 +205,7 @@ fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
int istr;
istr = icexpect (qconn, cstrings, azstrings, aclens,
- qchat->uuconf_ctimeout,
- qchat->uuconf_fstrip);
+ ctimeout, qchat->uuconf_fstrip);
/* If we found the string, break out of the
subexpect/subsend loop. */
@@ -640,7 +659,7 @@ fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
break;
case 'd':
fquote = fcsend_debug (fquote, (size_t) 0, "sleep");
- usysdep_sleep (2);
+ usysdep_sleep (1);
break;
case 'e':
fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off");
@@ -717,6 +736,8 @@ fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
case 'L':
{
const char *zlog;
+ char *zcopy;
+ size_t clen;
if (qsys == NULL)
{
@@ -756,18 +777,24 @@ fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
}
zlog = zcallout_login;
}
+ zcopy = zbufcpy (zlog);
+ clen = cescape (zcopy);
fquote = fcsend_debug (fquote, (size_t) 0, "login");
- fquote = fcsend_debug (fquote, strlen (zlog), zlog);
- if (! (*pfwrite) (qconn, zlog, strlen (zlog)))
+ fquote = fcsend_debug (fquote, clen, zcopy);
+ if (! (*pfwrite) (qconn, zcopy, clen))
{
+ ubuffree (zcopy);
ucsend_debug_end (fquote, TRUE);
return FALSE;
}
+ ubuffree (zcopy);
}
break;
case 'P':
{
const char *zpass;
+ char *zcopy;
+ size_t clen;
if (qsys == NULL)
{
@@ -807,13 +834,17 @@ fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
}
zpass = zcallout_pass;
}
+ zcopy = zbufcpy (zpass);
+ clen = cescape (zcopy);
fquote = fcsend_debug (fquote, (size_t) 0, "password");
- fquote = fcsend_debug (fquote, strlen (zpass), zpass);
- if (! (*pfwrite) (qconn, zpass, strlen (zpass)))
+ fquote = fcsend_debug (fquote, clen, zcopy);
+ if (! (*pfwrite) (qconn, zcopy, clen))
{
+ ubuffree (zcopy);
ucsend_debug_end (fquote, TRUE);
return FALSE;
}
+ ubuffree (zcopy);
}
break;
case 'D':
@@ -1168,6 +1199,7 @@ fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
for (zfrom = *pz; *zfrom != '\0'; zfrom++)
{
const char *zadd = NULL;
+ char *zfree = NULL;
size_t cadd;
char abadd[15];
@@ -1241,7 +1273,9 @@ fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
}
zlog = zcallout_login;
}
- zadd = zlog;
+ zfree = zbufcpy (zlog);
+ (void) cescape (zfree);
+ zadd = zfree;
}
break;
case 'P':
@@ -1287,7 +1321,9 @@ fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
}
zpass = zcallout_pass;
}
- zadd = zpass;
+ zfree = zbufcpy (zpass);
+ (void) cescape (zfree);
+ zadd = zfree;
}
break;
case 'D':
@@ -1405,6 +1441,7 @@ fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
memcpy (zto, zadd, cadd + 1);
zto += cadd;
clen += cadd;
+ ubuffree (zfree);
}
if (! fret)
diff --git a/gnu/libexec/uucp/common_sources/conf.h b/gnu/libexec/uucp/common_sources/conf.h
deleted file mode 100644
index 9053c4423e0a..000000000000
--- a/gnu/libexec/uucp/common_sources/conf.h
+++ /dev/null
@@ -1,444 +0,0 @@
-/* conf.h. Generated automatically by configure. */
-/* Configuration header file for Taylor UUCP. -*- C -*- */
-
-/* Set MAIL_PROGRAM to a program which takes a mail address as an
- argument and accepts a mail message to send to that address on
- stdin (e.g. "/bin/mail"). */
-#define MAIL_PROGRAM "/usr/bin/mail"
-
-/* Set ECHO_PROGRAM to a program which echoes its arguments; if echo
- is a shell builtin you can just use "echo". */
-#define ECHO_PROGRAM "echo"
-
-/* The following macros indicate what header files you have. Set the
- macro to 1 if you have the corresponding header file, or 0 if you
- do not. */
-#define HAVE_STDDEF_H 1 /* <stddef.h> */
-#define HAVE_STRING_H 1 /* <string.h> */
-#define HAVE_STRINGS_H 1 /* <strings.h> */
-#define HAVE_UNISTD_H 1 /* <unistd.h> */
-#define HAVE_STDLIB_H 1 /* <stdlib.h> */
-#define HAVE_LIMITS_H 1 /* <limits.h> */
-#define HAVE_TIME_H 1 /* <time.h> */
-#define HAVE_SYS_WAIT_H 1 /* <sys/wait.h> */
-#define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */
-#define HAVE_DIRENT_H 1 /* <dirent.h> */
-#define HAVE_MEMORY_H 1 /* <memory.h> */
-#define HAVE_SYS_PARAM_H 1 /* <sys/param.h> */
-#define HAVE_UTIME_H 1 /* <utime.h> */
-#define HAVE_FCNTL_H 1 /* <fcntl.h> */
-#define HAVE_SYS_FILE_H 1 /* <sys/file.h> */
-#define HAVE_SYS_TIMES_H 1 /* <sys/times.h> */
-#define HAVE_LIBC_H 0 /* <libc.h> */
-#define HAVE_SYSEXITS_H 1 /* <sysexits.h> */
-#define HAVE_POLL_H 0 /* <poll.h> */
-#define HAVE_TIUSER_H 0 /* <tiuser.h> */
-#define HAVE_XTI_H 0 /* <xti.h> */
-#define HAVE_SYS_TLI_H 0 /* <sys/tli.h> */
-#define HAVE_STROPTS_H 0 /* <stropts.h> */
-#define HAVE_FTW_H 0 /* <ftw.h> */
-#define HAVE_GLOB_H 1 /* <glob.h> */
-#define HAVE_SYS_SELECT_H 0 /* <sys/select.h> */
-#define HAVE_SYS_TYPES_TCP_H 0 /* <sys/types.tcp.h> */
-
-/* If major and minor are not defined in <sys/types.h>, but are in
- <sys/mkdev.h>, set MAJOR_IN_MKDEV to 1. If they are in
- <sys/sysmacros.h>, set MAJOR_IN_SYSMACROS to 1. */
-#define MAJOR_IN_MKDEV 0
-#define MAJOR_IN_SYSMACROS 0
-
-/* If the macro offsetof is not defined in <stddef.h>, you may give it
- a definition here. If you do not, the code will use a definition
- (in uucp.h) that should be fairly portable. */
-/* #define offsetof */
-
-/* Set RETSIGTYPE to the return type of a signal handler. On newer
- systems this will be void; some older systems use int. */
-#define RETSIGTYPE void
-
-/* Set HAVE_SYS_TIME_AND_TIME_H to 1 if <time.h> and <sys/time.h> can both
- be included in a single source file; if you don't have either or both of
- them, it doesn't matter what you set this to. */
-#define HAVE_SYS_TIME_AND_TIME_H 1
-
-/* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if <termios.h> and <sys/ioctl.h>
- can both be included in a single source file; if you don't have either
- or both of them, it doesn't matter what you set this to. */
-#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1
-
-/* If you are configuring by hand, you should set one of the terminal
- driver options in policy.h. If you are autoconfiguring, the script
- will check whether your system defines CBREAK, which is a terminal
- setting; if your system supports CBREAK, and you don't set a terminal
- driver in policy.h, the code will assume that you have a BSD style
- terminal driver. */
-#define HAVE_CBREAK 1
-
-/* The package needs several standard types. If you are using the
- configure script, it will look in standard places for these types,
- and give default definitions for them here if it doesn't find them.
- The default definitions should work on most systems, but you may
- want to check them. If you are configuring by hand, you will have
- to figure out whether the types are defined on your system, and
- what they should be defined to.
-
- Any type that is not defined on your system should get a macro
- definition. The definition should be of the name of the type in
- all capital letters. For example, #define PID_T int. If the type
- is defined in a standard header file, the macro name should not be
- defined. */
-
-/* The type pid_t is used to hold a process ID number. It is normally
- defined in <sys/types.h>. This is the type returned by the
- functions fork or getpid. Usually int will work fine. */
-#undef PID_T
-
-/* The type uid_t is used to hold a user ID number. It is normally
- defined in <sys/types.h>. This is the type returned by the getuid
- function. Usually int will work fine. */
-#undef UID_T
-
-/* The type gid_t is used to hold a group ID number. It is sometimes
- defined in <sys/types.h>. This is the type returned by the getgid
- function. Usually int will work fine. */
-#undef GID_T
-
-/* The type off_t is used to hold an offset in a file. It is sometimes
- defined in <sys/types.h>. This is the type of the second argument to
- the lseek function. Usually long will work fine. */
-#undef OFF_T
-
-/* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined
- in <signal.h> as required by ANSI C. */
-#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 0
-
-/* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined
- in <sys/types.h>. This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is
- set to 1. */
-#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0
-
-/* The type sig_atomic_t is used to hold a value which may be
- referenced in a single atomic operation. If it is not defined in
- either <signal.h> or <sys/types.h>, you may want to give it a
- definition here. If you don't, the code will use char. If your
- compiler does not support sig_atomic_t, there is no type which is
- really correct; fortunately, for this package it does not really
- matter very much. */
-#undef SIG_ATOMIC_T
-
-/* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in
- <stddef.h> as required by ANSI C. */
-#define HAVE_SIZE_T_IN_STDDEF_H 1
-
-/* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in
- <sys/types.h>. This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set
- to 1. */
-#define HAVE_SIZE_T_IN_TYPES_H 1
-
-/* The type size_t is used to hold the size of an object. In
- particular, an argument of this type is passed as the size argument
- to the malloc and realloc functions. If size_t is not defined in
- either <stddef.h> or <sys/types.h>, you may want to give it a
- definition here. If you don't, the code will use unsigned. */
-#undef SIZE_T
-
-/* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in
- <time.h>, as required by the ANSI C standard. */
-#define HAVE_TIME_T_IN_TIME_H 1
-
-/* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in
- <sys/types.h>. This is ignored if HAVE_TIME_T_IN_TIME_H is set to
- 1. */
-#define HAVE_TIME_T_IN_TYPES_H 1
-
-/* When Taylor UUCP is talking to another instance of itself, it will
- tell the other side the size of a file before it is transferred.
- If the package can determine how much disk space is available, it
- will use this information to avoid filling up the disk. Define one
- of the following macros to tell the code how to determine the
- amount of available disk space. It is possible that none of these
- are appropriate; it will do no harm to use none of them, but, of
- course, nothing will then prevent the package from filling up the
- disk. Note that this space check is only useful when talking to
- another instance of Taylor UUCP.
-
- STAT_STATVFS statvfs function
- STAT_STATFS2_BSIZE two argument statfs function with f_bsize field
- STAT_STATFS2_FSIZE two argument statfs function with f_fsize field
- STAT_STATFS2_FS_DATA two argument statfs function with fd_req field
- STAT_STATFS4 four argument statfs function
- STAT_USTAT the ustat function with 512 byte blocks. */
-#define STAT_STATVFS 0
-#define STAT_STATFS2_BSIZE 0
-#define STAT_STATFS2_FSIZE 1
-#define STAT_STATFS2_FS_DATA 0
-#define STAT_STATFS4 0
-#define STAT_USTAT 0
-
-/* Set HAVE_VOID to 1 if the compiler supports declaring functions with
- a return type of void and casting values to void. */
-#define HAVE_VOID 1
-
-/* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned
- char. */
-#define HAVE_UNSIGNED_CHAR 1
-
-/* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in <errno.h>. */
-#define HAVE_ERRNO_DECLARATION 1
-
-/* There are now a number of functions to check for. For each of
- these, the macro HAVE_FUNC should be set to 1 if your system has
- FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system
- has vfprintf, 0 otherwise. */
-
-/* Taylor UUCP will take advantage of the following functions if they
- are available, but knows how to deal with their absence. */
-#define HAVE_VFPRINTF 1
-#define HAVE_FTRUNCATE 1
-#define HAVE_LTRUNC 0
-#define HAVE_WAITPID 1
-#define HAVE_WAIT4 1
-#define HAVE_GLOB 1
-#define HAVE_SETREUID 1
-
-/* There are several functions which are replaced in the subdirectory
- lib. If they are missing, the configure script will automatically
- add them to lib/Makefile to force them to be recompiled. If you
- are configuring by hand, you will have to do this yourself. The
- string @LIBOBJS@ in lib/Makefile.in should be replaced by a list of
- object files in lib/Makefile. The following comments tell you
- which object file names to add (they are generally fairly obvious,
- given that the file names have no more than six characters before
- the period). */
-
-/* For each of these functions, if it does not exist, the indicated
- object file should be added to lib/Makefile. */
-#define HAVE_BSEARCH 1 /* bsrch.o */
-#define HAVE_GETLINE 0 /* getlin.o */
-#define HAVE_MEMCHR 1 /* memchr.o */
-#define HAVE_STRDUP 1 /* strdup.o */
-#define HAVE_STRSTR 1 /* strstr.o */
-#define HAVE_STRTOL 1 /* strtol.o */
-
-/* If neither of these functions exists, you should add bzero.o to
- lib/Makefile. */
-#define HAVE_BZERO 1
-#define HAVE_MEMSET 1
-
-/* If neither of these functions exists, you should add memcmp.o to
- lib/Makefile. */
-#define HAVE_MEMCMP 1
-#define HAVE_BCMP 1
-
-/* If neither of these functions exists, you should add memcpy.o to
- lib/Makefile. */
-#define HAVE_MEMCPY 1
-#define HAVE_BCOPY 1
-
-/* If neither of these functions exists, you should add strcas.o to
- lib/Makefile. */
-#define HAVE_STRCASECMP 1
-#define HAVE_STRICMP 0
-
-/* If neither of these functions exists, you should add strncs.o to
- lib/Makefile. */
-#define HAVE_STRNCASECMP 1
-#define HAVE_STRNICMP 0
-
-/* If neither of these functions exists, you should add strchr.o to
- lib/Makefile. */
-#define HAVE_STRCHR 1
-#define HAVE_INDEX 1
-
-/* If neither of these functions exists, you should add strrch.o to
- lib/Makefile. */
-#define HAVE_STRRCHR 1
-#define HAVE_RINDEX 1
-
-/* There are also Unix specific functions which are replaced in the
- subdirectory unix. If they are missing, the configure script will
- automatically add them to unix/Makefile to force them to be
- recompiled. If you are configuring by hand, you will have to do
- this yourself. The string @UNIXOBJS@ in unix/Makefile.in should be
- replaced by a list of object files in unix/Makefile. The following
- comments tell you which object file names to add. */
-
-/* For each of these functions, if it does not exist, the indicated
- object file should be added to unix/Makefile. */
-#define HAVE_OPENDIR 1 /* dirent.o */
-#define HAVE_DUP2 1 /* dup2.o */
-#define HAVE_FTW 0 /* ftw.o */
-#define HAVE_REMOVE 1 /* remove.o */
-#define HAVE_RENAME 1 /* rename.o */
-#define HAVE_STRERROR 1 /* strerr.o */
-
-/* The code needs to know how to create directories. If you have the
- mkdir function, set HAVE_MKDIR to 1 and replace @UUDIR@ in
- Makefile.in with '# ' (the configure script will set @UUDIR@
- according to the variable UUDIR). Otherwise, set HAVE_MKDIR to 0,
- remove @UUDIR@ from Makefile.in, set MKDIR_PROGRAM to the name of
- the program which will create a directory named on the command line
- (e.g., "/bin/mkdir"), and add mkdir.o to the @UNIXOBJS@ string in
- unix/Makefile.in. */
-#define HAVE_MKDIR 1
-#define MKDIR_PROGRAM unused
-
-/* The code also needs to know how to remove directories. If you have
- the rmdir function, set HAVE_RMDIR to 1. Otherwise, set
- RMDIR_PROGRAM to the name of the program which will remove a
- directory named on the command line (e.g., "/bin/rmdir") and add
- rmdir.o to the @UNIXOBJS@ string in unix/Makefile.in. */
-#define HAVE_RMDIR 1
-#define RMDIR_PROGRAM unused
-
-/* The code needs to know to how to get the name of the current
- directory. If getcwd is available it will be used, otherwise if
- getwd is available it will be used. Otherwise, set PWD_PROGRAM to
- the name of the program which will print the name of the current
- working directory (e.g., "/bin/pwd") and add getcwd.o to the
- @UNIXOBJS@ string in unix/Makefile.in. */
-#define HAVE_GETCWD 1
-#define HAVE_GETWD 1
-#define PWD_PROGRAM unused
-
-/* If you have either sigsetjmp or setret, it will be used instead of
- setjmp. These functions will only be used if your system restarts
- system calls after interrupts (see HAVE_RESTARTABLE_SYSCALLS,
- below). */
-#define HAVE_SIGSETJMP 0
-#define HAVE_SETRET 0
-
-/* The code needs to know what function to use to set a signal
- handler. If will try to use each of the following functions in
- turn. If none are available, it will use signal, which is assumed
- to always exist. */
-#define HAVE_SIGACTION 1
-#define HAVE_SIGVEC 1
-#define HAVE_SIGSET 0
-
-/* If the code is going to use sigvec (HAVE_SIGACTION is 0 and
- HAVE_SIGVEC is 1), then HAVE_SIGVEC_SV_FLAGS must be set to 1 if
- the sigvec structure contains the sv_flags field, or 0 if the
- sigvec structure contains the sv_onstack field. If the code is not
- going to use sigvec, it doesn't matter what this is set to. */
-#define HAVE_SIGVEC_SV_FLAGS 1
-
-/* The code will try to use each of the following functions in turn
- when blocking signals from delivery. If none are available, a
- relatively unimportant race condition will exist. */
-#define HAVE_SIGPROCMASK 1
-#define HAVE_SIGBLOCK 1
-#define HAVE_SIGHOLD 0
-
-/* If you have either of the following functions, it will be used to
- determine the number of file descriptors which may be open.
- Otherwise, the code will use OPEN_MAX if defined, then NOFILE if
- defined, then 20. */
-#define HAVE_GETDTABLESIZE 1
-#define HAVE_SYSCONF 0
-
-/* The code will use one of the following functions when detaching
- from a terminal. One of these must exist. */
-#define HAVE_SETPGRP 0
-#define HAVE_SETSID 1
-
-/* If you do not specify the local node name in the main configuration
- file, Taylor UUCP will try to use each of the following functions
- in turn. If neither is available, you must specify the local node
- name in the configuration file. */
-#define HAVE_GETHOSTNAME 1
-#define HAVE_UNAME 0
-
-/* The code will try to use each of the following functions in turn to
- determine the current time. If none are available, it will use
- time, which is assumed to always exist. */
-#define HAVE_GETTIMEOFDAY 1
-#define HAVE_FTIME 0
-
-/* If neither gettimeofday nor ftime is available, the code will use
- times (if available) to measure a span of time. See also the
- discussion of TIMES_TICK in policy.h. */
-#define HAVE_TIMES 1
-
-/* When a chat script requests a pause of less than a second with \p,
- Taylor UUCP will try to use each of the following functions in
- turn. If none are available, it will sleep for a full second.
- Also, the (non-portable) tstuu program requires either select or
- poll. */
-#define HAVE_NAPMS 0
-#define HAVE_NAP 0
-#define HAVE_USLEEP 1
-#define HAVE_POLL 0
-#define HAVE_SELECT 1
-
-/* If the getgrent function is available, it will be used to determine
- all the groups a user belongs to when checking file access
- permissions. */
-#define HAVE_GETGRENT 1
-
-/* If the socket function is available, TCP support code will be
- compiled in. */
-#define HAVE_SOCKET 1
-
-/* If the t_open function is available, TLI support code will be
- compiled in. This may require adding a library, such as -lnsl or
- -lxti, to the Makefile variables LIBS. */
-#define HAVE_T_OPEN 0
-
-/* That's the end of the list of the functions. Now there are a few
- last miscellaneous items. */
-
-/* On some systems the following functions are declared in such a way
- that the code cannot make a simple extern. On other systems, these
- functions are not declared at all, and the extern is required. If
- a declaration of the function, as shown, compiles on your system,
- set the value to 1. Not all functions declared externally are
- listed here, only the ones with which I have had trouble. */
-/* extern long times (); */
-#define TIMES_DECLARATION_OK 0
-/* extern struct passwd *getpwnam (); */
-#define GETPWNAM_DECLARATION_OK 1
-/* extern struct passwd *getpwuid (); */
-#define GETPWUID_DECLARATION_OK 0
-/* extern struct group *getgrent (); */
-#define GETGRENT_DECLARATION_OK 1
-
-/* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and
- your setpgrp calls takes 2 arguments (on System V they generally
- take no arguments). You can safely set this to 1 on System V,
- provided the call will compile without any errors. */
-#define HAVE_BSD_PGRP 0
-
-/* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header
- file <sys/wait.h>. */
-#define HAVE_UNION_WAIT 1
-
-/* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names
- longer than 14 characters. */
-#define HAVE_LONG_FILE_NAMES 1
-
-/* If slow system calls are restarted after interrupts, set
- HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION
- is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and
- SV_INTERRUPT is defined in <signal.h>. In both of these cases
- system calls can be prevented from restarting. */
-#define HAVE_RESTARTABLE_SYSCALLS 1
-
-/* Some systems supposedly need the following macros to be defined.
- These are handled by the configure script (it will turn #undef into
- #define when appropriate, which is why the peculiar #ifndef #undef
- construction is used). If you are configuring by hand, you may add
- appropriate definitions here, or just add them to CFLAGS when
- running make. */
-#ifndef _ALL_SOURCE
-#undef _ALL_SOURCE
-#endif
-#ifndef _POSIX_SOURCE
-#undef _POSIX_SOURCE
-#endif
-#ifndef _MINIX
-#undef _MINIX
-#endif
-#ifndef _POSIX_1_SOURCE
-#undef _POSIX_1_SOURCE
-#endif
diff --git a/gnu/libexec/uucp/common_sources/config.h b/gnu/libexec/uucp/common_sources/config.h
new file mode 100644
index 000000000000..c02a754eae9d
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/config.h
@@ -0,0 +1,462 @@
+/* config.h. Generated automatically by configure. */
+/* Configuration header file for Taylor UUCP. -*- C -*- */
+
+/* If your compiler does not use const correctly, then undefine it
+ here. This #undef is commented out by the configure script if it
+ determines that const is supported. */
+/* #undef const */
+
+/* If your compiler supports prototypes, set HAVE_PROTOTYPES to 1. */
+#define HAVE_PROTOTYPES 1
+
+/* Set ECHO_PROGRAM to a program which echoes its arguments; if echo
+ is a shell builtin you can just use "echo". */
+#define ECHO_PROGRAM "echo"
+
+/* The following macros indicate what header files you have. Set the
+ macro to 1 if you have the corresponding header file, or 0 if you
+ do not. */
+#define HAVE_STDDEF_H 1 /* <stddef.h> */
+#define HAVE_STDARG_H 1 /* <stdarg.h> */
+#define HAVE_STRING_H 1 /* <string.h> */
+#define HAVE_STRINGS_H 1 /* <strings.h> */
+#define HAVE_UNISTD_H 1 /* <unistd.h> */
+#define HAVE_STDLIB_H 1 /* <stdlib.h> */
+#define HAVE_LIMITS_H 1 /* <limits.h> */
+#define HAVE_TIME_H 1 /* <time.h> */
+#define HAVE_SYS_WAIT_H 1 /* <sys/wait.h> */
+#define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */
+#define HAVE_DIRENT_H 0 /* <dirent.h> */
+#define HAVE_MEMORY_H 1 /* <memory.h> */
+#define HAVE_SYS_PARAM_H 1 /* <sys/param.h> */
+#define HAVE_UTIME_H 1 /* <utime.h> */
+#define HAVE_FCNTL_H 1 /* <fcntl.h> */
+#define HAVE_SYS_FILE_H 1 /* <sys/file.h> */
+#define HAVE_SYS_TIME_H 1 /* <sys/time.h> */
+#define HAVE_SYS_TIMES_H 1 /* <sys/times.h> */
+#define HAVE_LIBC_H 0 /* <libc.h> */
+#define HAVE_SYSEXITS_H 1 /* <sysexits.h> */
+#define HAVE_POLL_H 0 /* <poll.h> */
+#define HAVE_TIUSER_H 0 /* <tiuser.h> */
+#define HAVE_XTI_H 0 /* <xti.h> */
+#define HAVE_SYS_TLI_H 0 /* <sys/tli.h> */
+#define HAVE_STROPTS_H 0 /* <stropts.h> */
+#define HAVE_FTW_H 0 /* <ftw.h> */
+#define HAVE_GLOB_H 1 /* <glob.h> */
+#define HAVE_SYS_SELECT_H 0 /* <sys/select.h> */
+#define HAVE_SYS_TYPES_TCP_H 0 /* <sys/types.tcp.h> */
+
+/* If major and minor are not defined in <sys/types.h>, but are in
+ <sys/mkdev.h>, set MAJOR_IN_MKDEV to 1. If they are in
+ <sys/sysmacros.h>, set MAJOR_IN_SYSMACROS to 1. */
+#define MAJOR_IN_MKDEV 0
+#define MAJOR_IN_SYSMACROS 0
+
+/* If the macro offsetof is not defined in <stddef.h>, you may give it
+ a definition here. If you do not, the code will use a definition
+ (in uucp.h) that should be fairly portable. */
+/* #define offsetof */
+
+/* Set RETSIGTYPE to the return type of a signal handler. On newer
+ systems this will be void; some older systems use int. */
+#define RETSIGTYPE void
+
+/* If the macro S_ISDIR is defined in <sys/stat.h>, but is incorrect,
+ define STAT_MACROS_BROKEN to be 1. This is said to be the case on
+ Tektronix UTekV, Amdahl UTS and Motorola System V/88. */
+#define STAT_MACROS_BROKEN 0
+
+/* Set TIME_WITH_SYS_TIME to 1 if <time.h> and <sys/time.h> can both
+ be included in a single source file; if you don't have either or
+ both of them, it doesn't matter what you set this to. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Set TM_IN_SYS_TIME to 1 if struct tm is defined in <sys/time.h>
+ rather than in <time.h>. */
+#define TM_IN_SYS_TIME 0
+
+/* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if <termios.h> and <sys/ioctl.h>
+ can both be included in a single source file; if you don't have either
+ or both of them, it doesn't matter what you set this to. */
+#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1
+
+/* If you are configuring by hand, you should set one of the terminal
+ driver options in policy.h. If you are autoconfiguring, the script
+ will check whether your system defines CBREAK, which is a terminal
+ setting; if your system supports CBREAK, and you don't set a terminal
+ driver in policy.h, the code will assume that you have a BSD style
+ terminal driver. */
+#define HAVE_CBREAK 1
+
+/* The package needs several standard types. If you are using the
+ configure script, it will look in standard places for these types,
+ and give default definitions for them here if it doesn't find them.
+ The default definitions should work on most systems, but you may
+ want to check them. If you are configuring by hand, you will have
+ to figure out whether the types are defined on your system, and
+ what they should be defined to.
+
+ Any type that is not defined on your system should get a macro
+ definition. The definition should be of the name of the type in
+ all capital letters. For example, #define PID_T int. If the type
+ is defined in a standard header file, the macro name should not be
+ defined. */
+
+/* The type pid_t is used to hold a process ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the
+ functions fork or getpid. Usually int will work fine. */
+/* #undef PID_T */
+
+/* The type uid_t is used to hold a user ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the getuid
+ function. Usually int will work fine. */
+/* #undef UID_T */
+
+/* The type gid_t is used to hold a group ID number. It is sometimes
+ defined in <sys/types.h>. This is the type returned by the getgid
+ function. Usually int will work fine. */
+/* #undef GID_T */
+
+/* The type off_t is used to hold an offset in a file. It is sometimes
+ defined in <sys/types.h>. This is the type of the second argument to
+ the lseek function. Usually long will work fine. */
+/* #undef OFF_T */
+
+/* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined
+ in <signal.h> as required by ANSI C. */
+#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 0
+
+/* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined
+ in <sys/types.h>. This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is
+ set to 1. */
+#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0
+
+/* The type sig_atomic_t is used to hold a value which may be
+ referenced in a single atomic operation. If it is not defined in
+ either <signal.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use char. If your
+ compiler does not support sig_atomic_t, there is no type which is
+ really correct; fortunately, for this package it does not really
+ matter very much. */
+/* #undef SIG_ATOMIC_T */
+
+/* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in
+ <stddef.h> as required by ANSI C. */
+#define HAVE_SIZE_T_IN_STDDEF_H 1
+
+/* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in
+ <sys/types.h>. This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set
+ to 1. */
+#define HAVE_SIZE_T_IN_TYPES_H 1
+
+/* The type size_t is used to hold the size of an object. In
+ particular, an argument of this type is passed as the size argument
+ to the malloc and realloc functions. If size_t is not defined in
+ either <stddef.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use unsigned. */
+/* #undef SIZE_T */
+
+/* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in
+ <time.h>, as required by the ANSI C standard. */
+#define HAVE_TIME_T_IN_TIME_H 1
+
+/* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in
+ <sys/types.h>. This is ignored if HAVE_TIME_T_IN_TIME_H is set to
+ 1. */
+#define HAVE_TIME_T_IN_TYPES_H 1
+
+/* When Taylor UUCP is talking to another instance of itself, it will
+ tell the other side the size of a file before it is transferred.
+ If the package can determine how much disk space is available, it
+ will use this information to avoid filling up the disk. Define one
+ of the following macros to tell the code how to determine the
+ amount of available disk space. It is possible that none of these
+ are appropriate; it will do no harm to use none of them, but, of
+ course, nothing will then prevent the package from filling up the
+ disk. Note that this space check is only useful when talking to
+ another instance of Taylor UUCP.
+
+ STAT_STATVFS statvfs function
+ STAT_STATFS2_BSIZE two argument statfs function with f_bsize field
+ STAT_STATFS2_FSIZE two argument statfs function with f_fsize field
+ STAT_STATFS2_FS_DATA two argument statfs function with fd_req field
+ STAT_STATFS4 four argument statfs function
+ STAT_DUSTAT dustat function (AIX PS/2)
+ STAT_DISK_SPACE disk_space function (QNX)
+ STAT_USTAT the ustat function with 512 byte blocks. */
+#define STAT_STATVFS 0
+#define STAT_STATFS2_BSIZE 0
+#define STAT_STATFS2_FSIZE 1
+#define STAT_STATFS2_FS_DATA 0
+#define STAT_STATFS4 0
+#define STAT_DUSTAT 0
+#define STAT_DISK_SPACE 0
+#define STAT_USTAT 0
+
+/* Set HAVE_VOID to 1 if the compiler supports declaring functions with
+ a return type of void and casting values to void. */
+#define HAVE_VOID 1
+
+/* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned
+ char. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in <errno.h>. */
+#define HAVE_ERRNO_DECLARATION 1
+
+/* Set HAVE_TXADDCD to 1 if TXADDCD is defined in <sys/ioctl.h>, as it
+ is on AIX. */
+#define HAVE_TXADDCD 0
+
+/* There are now a number of functions to check for. For each of
+ these, the macro HAVE_FUNC should be set to 1 if your system has
+ FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system
+ has vfprintf, 0 otherwise. */
+
+/* Taylor UUCP will take advantage of the following functions if they
+ are available, but knows how to deal with their absence. */
+#define HAVE_VFPRINTF 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_LTRUNC 0
+#define HAVE_WAITPID 1
+#define HAVE_WAIT4 1
+#define HAVE_GLOB 1
+#define HAVE_SETREUID 1
+
+/* There are several functions which are replaced in the subdirectory
+ lib. If they are missing, the configure script will automatically
+ add them to lib/Makefile to force them to be recompiled. If you
+ are configuring by hand, you will have to do this yourself. The
+ string @LIBOBJS@ in lib/Makefile.in should be replaced by a list of
+ object files in lib/Makefile. The following comments tell you
+ which object file names to add (they are generally fairly obvious,
+ given that the file names have no more than six characters before
+ the period). */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to lib/Makefile. */
+#define HAVE_BSEARCH 1 /* bsrch.o */
+#define HAVE_GETLINE 0 /* getlin.o */
+#define HAVE_MEMCHR 1 /* memchr.o */
+#define HAVE_STRDUP 1 /* strdup.o */
+#define HAVE_STRSTR 1 /* strstr.o */
+#define HAVE_STRTOL 1 /* strtol.o */
+#define HAVE_STRTOUL 1 /* strtou.o */
+
+/* If neither of these functions exists, you should add bzero.o to
+ lib/Makefile. */
+#define HAVE_BZERO 1
+#define HAVE_MEMSET 1
+
+/* If neither of these functions exists, you should add memcmp.o to
+ lib/Makefile. */
+#define HAVE_MEMCMP 1
+#define HAVE_BCMP 1
+
+/* If neither of these functions exists, you should add memcpy.o to
+ lib/Makefile. */
+#define HAVE_MEMCPY 1
+#define HAVE_BCOPY 1
+
+/* If neither of these functions exists, you should add strcas.o to
+ lib/Makefile. */
+#define HAVE_STRCASECMP 1
+#define HAVE_STRICMP 0
+
+/* If neither of these functions exists, you should add strncs.o to
+ lib/Makefile. */
+#define HAVE_STRNCASECMP 1
+#define HAVE_STRNICMP 0
+
+/* If neither of these functions exists, you should add strchr.o to
+ lib/Makefile. */
+#define HAVE_STRCHR 1
+#define HAVE_INDEX 1
+
+/* If neither of these functions exists, you should add strrch.o to
+ lib/Makefile. */
+#define HAVE_STRRCHR 1
+#define HAVE_RINDEX 1
+
+/* There are also Unix specific functions which are replaced in the
+ subdirectory unix. If they are missing, the configure script will
+ automatically add them to unix/Makefile to force them to be
+ recompiled. If you are configuring by hand, you will have to do
+ this yourself. The string @UNIXOBJS@ in unix/Makefile.in should be
+ replaced by a list of object files in unix/Makefile. The following
+ comments tell you which object file names to add. */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to unix/Makefile. */
+#define HAVE_OPENDIR 1 /* dirent.o */
+#define HAVE_DUP2 1 /* dup2.o */
+#define HAVE_FTW 0 /* ftw.o */
+#define HAVE_REMOVE 1 /* remove.o */
+#define HAVE_RENAME 1 /* rename.o */
+#define HAVE_STRERROR 1 /* strerr.o */
+
+/* The code needs to know how to create directories. If you have the
+ mkdir function, set HAVE_MKDIR to 1 and replace @UUDIR@ in
+ Makefile.in with '# ' (the configure script will set @UUDIR@
+ according to the variable UUDIR). Otherwise, set HAVE_MKDIR to 0,
+ remove @UUDIR@ from Makefile.in, set MKDIR_PROGRAM to the name of
+ the program which will create a directory named on the command line
+ (e.g., "/bin/mkdir"), and add mkdir.o to the @UNIXOBJS@ string in
+ unix/Makefile.in. */
+#define HAVE_MKDIR 1
+#define MKDIR_PROGRAM unused
+
+/* The code also needs to know how to remove directories. If you have
+ the rmdir function, set HAVE_RMDIR to 1. Otherwise, set
+ RMDIR_PROGRAM to the name of the program which will remove a
+ directory named on the command line (e.g., "/bin/rmdir") and add
+ rmdir.o to the @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_RMDIR 1
+#define RMDIR_PROGRAM unused
+
+/* The code needs to know to how to get the name of the current
+ directory. If getcwd is available it will be used, otherwise if
+ getwd is available it will be used. Otherwise, set PWD_PROGRAM to
+ the name of the program which will print the name of the current
+ working directory (e.g., "/bin/pwd") and add getcwd.o to the
+ @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_GETCWD 1
+#define HAVE_GETWD 1
+#define PWD_PROGRAM unused
+
+/* If you have either sigsetjmp or setret, it will be used instead of
+ setjmp. These functions will only be used if your system restarts
+ system calls after interrupts (see HAVE_RESTARTABLE_SYSCALLS,
+ below). */
+#define HAVE_SIGSETJMP 1
+#define HAVE_SETRET 0
+
+/* The code needs to know what function to use to set a signal
+ handler. If will try to use each of the following functions in
+ turn. If none are available, it will use signal, which is assumed
+ to always exist. */
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIGSET 0
+
+/* If the code is going to use sigvec (HAVE_SIGACTION is 0 and
+ HAVE_SIGVEC is 1), then HAVE_SIGVEC_SV_FLAGS must be set to 1 if
+ the sigvec structure contains the sv_flags field, or 0 if the
+ sigvec structure contains the sv_onstack field. If the code is not
+ going to use sigvec, it doesn't matter what this is set to. */
+#define HAVE_SIGVEC_SV_FLAGS 1
+
+/* The code will try to use each of the following functions in turn
+ when blocking signals from delivery. If none are available, a
+ relatively unimportant race condition will exist. */
+#define HAVE_SIGPROCMASK 1
+#define HAVE_SIGBLOCK 1
+#define HAVE_SIGHOLD 0
+
+/* If you have either of the following functions, it will be used to
+ determine the number of file descriptors which may be open.
+ Otherwise, the code will use OPEN_MAX if defined, then NOFILE if
+ defined, then 20. */
+#define HAVE_GETDTABLESIZE 1
+#define HAVE_SYSCONF 0
+
+/* The code will use one of the following functions when detaching
+ from a terminal. One of these must exist. */
+#define HAVE_SETPGRP 1
+#define HAVE_SETSID 1
+
+/* If you do not specify the local node name in the main configuration
+ file, Taylor UUCP will try to use each of the following functions
+ in turn. If neither is available, you must specify the local node
+ name in the configuration file. */
+#define HAVE_GETHOSTNAME 1
+#define HAVE_UNAME 1
+
+/* The code will try to use each of the following functions in turn to
+ determine the current time. If none are available, it will use
+ time, which is assumed to always exist. */
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_FTIME 0
+
+/* If neither gettimeofday nor ftime is available, the code will use
+ times (if available) to measure a span of time. See also the
+ discussion of TIMES_TICK in policy.h. */
+#define HAVE_TIMES 1
+
+/* When a chat script requests a pause of less than a second with \p,
+ Taylor UUCP will try to use each of the following functions in
+ turn. If none are available, it will sleep for a full second.
+ Also, the (non-portable) tstuu program requires either select or
+ poll. */
+#define HAVE_NAPMS 0
+#define HAVE_NAP 0
+#define HAVE_USLEEP 1
+#define HAVE_POLL 0
+#define HAVE_SELECT 1
+
+/* If the getgrent function is available, it will be used to determine
+ all the groups a user belongs to when checking file access
+ permissions. */
+#define HAVE_GETGRENT 1
+
+/* If the socket function is available, TCP support code will be
+ compiled in. */
+#define HAVE_SOCKET 1
+
+/* If the t_open function is available, TLI support code will be
+ compiled in. This may require adding a library, such as -lnsl or
+ -lxti, to the Makefile variables LIBS. */
+#define HAVE_T_OPEN 0
+
+/* If the dev_info function is available (QNX only), it will be used
+ to determine if any other process has the serial port open, and
+ that will cause uucico and cu to presume the port is locked. */
+#define HAVE_DEV_INFO 0
+
+/* That's the end of the list of the functions. Now there are a few
+ last miscellaneous items. */
+
+/* On some systems the following functions are declared in such a way
+ that the code cannot make a simple extern. On other systems, these
+ functions are not declared at all, and the extern is required. If
+ a declaration of the function, as shown, compiles on your system,
+ set the value to 1. Not all functions declared externally are
+ listed here, only the ones with which I have had trouble. */
+/* extern long times (); */
+#define TIMES_DECLARATION_OK 0
+/* extern struct passwd *getpwnam (); */
+#define GETPWNAM_DECLARATION_OK 1
+/* extern struct passwd *getpwuid (); */
+#define GETPWUID_DECLARATION_OK 1
+/* extern struct group *getgrent (); */
+#define GETGRENT_DECLARATION_OK 1
+
+/* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and
+ your setpgrp calls takes 2 arguments (on System V they generally
+ take no arguments). You can safely set this to 1 on System V,
+ provided the call will compile without any errors. */
+#define HAVE_BSD_PGRP 0
+
+/* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header
+ file <sys/wait.h>. */
+#define HAVE_UNION_WAIT 1
+
+/* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names
+ longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* If slow system calls are restarted after interrupts, set
+ HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION
+ is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and
+ SV_INTERRUPT is defined in <signal.h>. In both of these cases
+ system calls can be prevented from restarting. */
+#define HAVE_RESTARTABLE_SYSCALLS 1
+
+/* Some systems supposedly need the following macros to be defined.
+ These are handled by the configure script. If you are configuring
+ by hand, you may add appropriate definitions here, or just add them
+ to CFLAGS when running make. */
+/* #undef _ALL_SOURCE */
+/* #undef _POSIX_SOURCE */
+/* #undef _MINIX */
+/* #undef _POSIX_1_SOURCE */
diff --git a/gnu/libexec/uucp/common_sources/conn.c b/gnu/libexec/uucp/common_sources/conn.c
index 8db53516a685..5085ee5b63c9 100644
--- a/gnu/libexec/uucp/common_sources/conn.c
+++ b/gnu/libexec/uucp/common_sources/conn.c
@@ -1,7 +1,7 @@
/* conn.c
Connection routines for the Taylor UUCP package.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/05 18:22:35 conklin Exp $";
+const char conn_rcsid[] = "$Id: conn.c,v 1.2 1994/05/07 18:08:38 ache Exp $";
#endif
#include <ctype.h>
@@ -35,21 +35,19 @@ const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/05 18:22:35 conklin Exp $";
#include "uuconf.h"
#include "conn.h"
-static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf,
- struct uuconf_dialer *qdialer,
- const char *zphone, boolean ftranslate));
-
/* Create a new connection. This relies on system dependent functions
to set the qcmds and psysdep fields. If qport is NULL, it opens a
- standard input port. */
+ standard input port, in which case ttype is the type of port to
+ use. */
boolean
-fconn_init (qport, qconn)
+fconn_init (qport, qconn, ttype)
struct uuconf_port *qport;
struct sconnection *qconn;
+ enum uuconf_porttype ttype;
{
qconn->qport = qport;
- switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype)
+ switch (qport == NULL ? ttype : qport->uuconf_ttype)
{
case UUCONF_PORTTYPE_STDIN:
return fsysdep_stdin_init (qconn);
@@ -65,8 +63,10 @@ fconn_init (qport, qconn)
case UUCONF_PORTTYPE_TLI:
return fsysdep_tli_init (qconn);
#endif
+ case UUCONF_PORTTYPE_PIPE:
+ return fsysdep_pipe_init (qconn);
default:
- ulog (LOG_ERROR, "Unknown port type");
+ ulog (LOG_ERROR, "Unknown or unsupported port type");
return FALSE;
}
}
@@ -202,8 +202,9 @@ fconn_close (qconn, puuconf, qdialer, fsuccess)
fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess);
- /* Make sure any signal reporting has been done before we set
- fLog_sighup back to TRUE. */
+ /* Ignore any SIGHUP we may have gotten, and make sure any signal
+ reporting has been done before we reset fLog_sighup. */
+ afSignal[INDEXSIG_SIGHUP] = FALSE;
ulog (LOG_ERROR, (const char *) NULL);
fLog_sighup = TRUE;
@@ -211,17 +212,6 @@ fconn_close (qconn, puuconf, qdialer, fsuccess)
return fret;
}
-
-/* Reset the connection. */
-
-boolean
-fconn_reset (qconn)
- struct sconnection *qconn;
-{
- DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection");
-
- return (*qconn->qcmds->pfreset) (qconn);
-}
/* Dial out on the connection. */
@@ -347,7 +337,7 @@ fconn_break (qconn)
{
boolean (*pfbreak) P((struct sconnection *));
- pfbreak = *qconn->qcmds->pfbreak;
+ pfbreak = qconn->qcmds->pfbreak;
if (pfbreak == NULL)
return TRUE;
@@ -419,74 +409,65 @@ iconn_baud (qconn)
return (*pibaud) (qconn);
}
-/* Modem dialing routines. */
+/* Run through a dialer sequence. The pzdialer argument is a list of
+ strings, which are considered in dialer/token pairs. The dialer
+ string names a dialer to use. The token string is what \D and \T
+ in the chat script expand to. If there is no token for the last
+ dialer, the zphone argument is used. The qdialer argument is
+ filled in with information for the first dialer, and *ptdialerfound
+ is set to whether the information should be freed or not. However,
+ if *ptdialerfound is not DIALERFOUND_FALSE when this function is
+ called, then the information for the first dialer is already in
+ qdialer. */
-/*ARGSUSED*/
boolean
-fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, qdialer,
+ ptdialerfound)
struct sconnection *qconn;
pointer puuconf;
+ char **pzdialer;
const struct uuconf_system *qsys;
const char *zphone;
struct uuconf_dialer *qdialer;
enum tdialerfound *ptdialerfound;
{
- *ptdialerfound = DIALERFOUND_FALSE;
+ const char *zname;
+ boolean ffirst, ffreefirst;
- if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ if (qconn->qport == NULL)
+ zname = NULL;
+ else
+ zname = qconn->qport->uuconf_zname;
+ ffirst = TRUE;
+ ffreefirst = FALSE;
+ while (*pzdialer != NULL)
{
- char **pz;
- boolean ffirst;
-
- /* The pzdialer field is a sequence of dialer/token pairs. The
- dialer portion names a dialer to use. The token portion is
- what \D and \T in the chat script expand to. If there is no
- token for the last dialer, the phone number for the system is
- used. */
- ffirst = TRUE;
- pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
- while (*pz != NULL)
+ struct uuconf_dialer *q;
+ struct uuconf_dialer s;
+ const char *ztoken;
+ boolean ftranslate;
+
+ if (! ffirst)
+ q = &s;
+ else
+ q = qdialer;
+
+ if (! ffirst || *ptdialerfound == DIALERFOUND_FALSE)
{
int iuuconf;
- struct uuconf_dialer *q;
- struct uuconf_dialer s;
- const char *ztoken;
- boolean ftranslate;
- if (! ffirst)
- q = &s;
- else
- q = qdialer;
-
- iuuconf = uuconf_dialer_info (puuconf, *pz, q);
+ iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
if (iuuconf == UUCONF_NOT_FOUND)
{
- ulog (LOG_ERROR, "%s: Dialer not found", *pz);
+ ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
+ if (ffreefirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
return FALSE;
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
- return FALSE;
- }
-
- ++pz;
- ztoken = *pz;
-
- ftranslate = FALSE;
- if (ztoken == NULL
- || strcmp (ztoken, "\\D") == 0)
- ztoken = zphone;
- else if (strcmp (ztoken, "\\T") == 0)
- {
- ztoken = zphone;
- ftranslate = TRUE;
- }
-
- if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate))
- {
- (void) uuconf_dialer_free (puuconf, q);
- if (! ffirst)
+ if (ffreefirst)
(void) uuconf_dialer_free (puuconf, qdialer);
return FALSE;
}
@@ -494,25 +475,109 @@ fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
if (ffirst)
{
*ptdialerfound = DIALERFOUND_FREE;
- ffirst = FALSE;
+ ffreefirst = TRUE;
}
- else
+ }
+
+ ++pzdialer;
+ ztoken = *pzdialer;
+
+ ftranslate = FALSE;
+ if (ztoken == NULL
+ || strcmp (ztoken, "\\D") == 0)
+ ztoken = zphone;
+ else if (strcmp (ztoken, "\\T") == 0)
+ {
+ ztoken = zphone;
+ ftranslate = TRUE;
+ }
+
+ if (! fchat (qconn, puuconf, &q->uuconf_schat, qsys, q, ztoken,
+ ftranslate, zname, iconn_baud (qconn)))
+ {
+ if (q == &s)
(void) uuconf_dialer_free (puuconf, q);
+ if (ffreefirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+ return FALSE;
+ }
+
+ if (ffirst)
+ ffirst = FALSE;
+ else
+ (void) uuconf_dialer_free (puuconf, q);
+
+ if (*pzdialer != NULL)
+ ++pzdialer;
+ }
+
+ return TRUE;
+}
+
+/* Modem dialing routine. */
+
+/*ARGSUSED*/
+boolean
+fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ char **pzdialer;
+
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ pzdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
+ if (pzdialer != NULL && *pzdialer != NULL)
+ {
+ int iuuconf;
+ boolean fret;
- if (*pz != NULL)
- ++pz;
+ iuuconf = uuconf_dialer_info (puuconf, *pzdialer, qdialer);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
}
- return TRUE;
+ *ptdialerfound = DIALERFOUND_FREE;
+
+ fret = (fsysdep_modem_begin_dial (qconn, qdialer)
+ && fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone,
+ qdialer, ptdialerfound)
+ && fsysdep_modem_end_dial (qconn, qdialer));
+
+ if (! fret)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+
+ return fret;
}
else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL)
{
struct uuconf_dialer *q;
+ const char *zname;
q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
*qdialer = *q;
*ptdialerfound = DIALERFOUND_TRUE;
- return fcdo_dial (qconn, puuconf, q, zphone, FALSE);
+
+ if (qconn->qport == NULL)
+ zname = NULL;
+ else
+ zname = qconn->qport->uuconf_zname;
+
+ return (fsysdep_modem_begin_dial (qconn, q)
+ && fchat (qconn, puuconf, &q->uuconf_schat, qsys, q,
+ zphone, FALSE, zname, iconn_baud (qconn))
+ && fsysdep_modem_end_dial (qconn, q));
}
else
{
@@ -520,33 +585,3 @@ fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
return FALSE;
}
}
-
-/* Actually use a dialer. We set up the modem (which may include
- opening the dialer device), run the chat script, and finish dealing
- with the modem. */
-
-static boolean
-fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate)
- struct sconnection *qconn;
- pointer puuconf;
- struct uuconf_dialer *qdial;
- const char *zphone;
- boolean ftranslate;
-{
- const char *zname;
-
- if (! fsysdep_modem_begin_dial (qconn, qdial))
- return FALSE;
-
- if (qconn->qport == NULL)
- zname = NULL;
- else
- zname = qconn->qport->uuconf_zname;
-
- if (! fchat (qconn, puuconf, &qdial->uuconf_schat,
- (const struct uuconf_system *) NULL, qdial,
- zphone, ftranslate, zname, iconn_baud (qconn)))
- return FALSE;
-
- return fsysdep_modem_end_dial (qconn, qdial);
-}
diff --git a/gnu/libexec/uucp/common_sources/conn.h b/gnu/libexec/uucp/common_sources/conn.h
index 59d4881b07ff..368f7e658949 100644
--- a/gnu/libexec/uucp/common_sources/conn.h
+++ b/gnu/libexec/uucp/common_sources/conn.h
@@ -1,7 +1,7 @@
/* conn.h
Header file for routines which manipulate connections.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#ifndef CONN_H
@@ -121,8 +121,6 @@ struct sconncmds
pointer puuconf,
struct uuconf_dialer *qdialer,
boolean fsuccess));
- /* Reset the connection so that another call may be accepted. */
- boolean (*pfreset) P((struct sconnection *qconn));
/* Dial a number on a connection. This set *qdialer to the dialer
used, if any, and sets *ptdialerfound appropriately. The qsys
and zphone arguments are for the chat script. This field may be
@@ -170,9 +168,11 @@ struct sconncmds
/* Initialize a connection. This must be called before any of the
other connection functions are called. It initializes the fields
- of qconn. It returns FALSE on error. */
+ of qconn. If qport is NULL, this opens standard input as a port
+ using type ttype. This function returns FALSE on error. */
extern boolean fconn_init P((struct uuconf_port *qport,
- struct sconnection *qconn));
+ struct sconnection *qconn,
+ enum uuconf_porttype ttype));
/* Free up connection data. */
extern void uconn_free P((struct sconnection *qconn));
@@ -199,9 +199,6 @@ extern boolean fconn_close P((struct sconnection *qconn,
struct uuconf_dialer *qdialer,
boolean fsuccess));
-/* Reset a connection such that another call may be accepted. */
-extern boolean fconn_reset P((struct sconnection *q));
-
/* Dial out on a connection. The qsys and zphone arguments are for
the chat scripts; zphone is the phone number to dial. If qdialer
is not NULL, *qdialer will be set to the dialer information used if
@@ -275,6 +272,15 @@ extern boolean fconn_carrier P((struct sconnection *qconn,
extern boolean fconn_run_chat P((struct sconnection *qconn,
char **pzprog));
+/* Run through a dialer sequence. This is a support routine for the
+ port type specific dialing routines. */
+extern boolean fconn_dial_sequence P((struct sconnection *qconn,
+ pointer puuconf, char **pzdialer,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialerfound));
+
/* Dialing out on a modem is partially system independent. This is
the modem dialing routine. */
extern boolean fmodem_dial P((struct sconnection *qconn, pointer puuconf,
@@ -308,5 +314,6 @@ extern boolean fsysdep_tcp_init P((struct sconnection *qconn));
#if HAVE_TLI
extern boolean fsysdep_tli_init P((struct sconnection *qconn));
#endif
+extern boolean fsysdep_pipe_init P((struct sconnection *qconn));
#endif /* ! defined (CONN_H) */
diff --git a/gnu/libexec/uucp/common_sources/copy.c b/gnu/libexec/uucp/common_sources/copy.c
index 0d1a5bb2c270..176b53641c99 100644
--- a/gnu/libexec/uucp/common_sources/copy.c
+++ b/gnu/libexec/uucp/common_sources/copy.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char copy_rcsid[] = "$Id: copy.c,v 1.1 1993/08/05 18:22:37 conklin Exp $";
+const char copy_rcsid[] = "$Id: copy.c,v 1.2 1994/05/07 18:08:42 ache Exp $";
#endif
#include "uudefs.h"
diff --git a/gnu/libexec/uucp/common_sources/cu.h b/gnu/libexec/uucp/common_sources/cu.h
index 5a514ee3bfe7..748e2d32c199 100644
--- a/gnu/libexec/uucp/common_sources/cu.h
+++ b/gnu/libexec/uucp/common_sources/cu.h
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* The user settable variables supported by cu. */
diff --git a/gnu/libexec/uucp/common_sources/log.c b/gnu/libexec/uucp/common_sources/log.c
index 9528baf5ca39..761efeff64af 100644
--- a/gnu/libexec/uucp/common_sources/log.c
+++ b/gnu/libexec/uucp/common_sources/log.c
@@ -1,7 +1,7 @@
/* log.c
Routines to add entries to the log files.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,22 +20,25 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char log_rcsid[] = "$Id: log.c,v 1.1 1993/08/05 18:22:39 conklin Exp $";
+const char log_rcsid[] = "$Id: log.c,v 1.2 1994/05/07 18:08:47 ache Exp $";
#endif
+#include <ctype.h>
#include <errno.h>
-#if ANSI_C
+#if HAVE_STDARG_H
#include <stdarg.h>
#endif
-#if HAVE_TIME_H
+#if TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
#include <time.h>
#endif
@@ -45,8 +48,12 @@ const char log_rcsid[] = "$Id: log.c,v 1.1 1993/08/05 18:22:39 conklin Exp $";
/* Local functions. */
+__inline__ static char *zstpcpy P((char *zto, const char *zfrom));
static const char *zldate_and_time P((void));
+/* Program name. Set by main function. */
+const char *zProgram;
+
/* Log file name. */
static const char *zLogfile;
@@ -86,9 +93,6 @@ static FILE *eLdebug;
/* Whether we've tried to open the debugging file. */
static boolean fLdebug_tried;
-
-/* Whether we've written out any debugging information. */
-static boolean fLdebugging;
#endif
/* Statistics file name. */
@@ -212,11 +216,24 @@ ulog_device (zdevice)
zLdevice = zbufcpy (zdevice);
}
+/* A helper function for ulog. */
+
+__inline__ static char *
+zstpcpy (zto, zfrom)
+ char *zto;
+ const char *zfrom;
+{
+ while ((*zto++ = *zfrom++) != '\0')
+ ;
+ return zto - 1;
+}
+
/* Make a log entry. We make a token concession to non ANSI_C systems,
but it clearly won't always work. */
-#if ! ANSI_C
+#if ! HAVE_PROTOTYPES || ! HAVE_STDARG_H
#undef HAVE_VFPRINTF
+#define HAVE_VFPRINTF 0
#endif
/*VARARGS2*/
@@ -235,7 +252,11 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
#endif
FILE *e, *edebug;
boolean fstart, fend;
- const char *zhdr, *zstr;
+ const char *zhdr;
+ char *zprefix;
+ register char *zset;
+ char *zformat;
+ char *zfrom;
/* Log any received signal. We do it this way to avoid calling ulog
from the signal handler. A few routines call ulog to get this
@@ -276,11 +297,10 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
if (fLfile
&& eLdebug == NULL
&& ! fLdebug_tried
- && (fLdebugging || (int) ttype >= (int) LOG_DEBUG))
+ && iDebug != 0)
{
fLdebug_tried = TRUE;
eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE);
- fLdebugging = TRUE;
}
#endif /* DEBUG > 1 */
@@ -307,6 +327,8 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
#else /* HAVE_HDB_LOGGING */
{
const char *zsys;
+ char *zbase;
+ char *zlower;
char *zfile;
/* We want to write to .Log/program/system, e.g.
@@ -316,11 +338,23 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
else
zsys = zLsystem;
+ zbase = zsysdep_base_name (zProgram);
+ if (zbase == NULL)
+ zbase = zbufcpy (zProgram);
+
+ /* On some systems the native uusched will invoke uucico
+ with an upper case argv[0]. We work around that by
+ forcing the filename to lower case here. */
+ for (zlower = zbase; *zlower != '\0'; zlower++)
+ if (isupper (*zlower))
+ *zlower = tolower (*zlower);
+
zfile = zbufalc (strlen (zLogfile)
- + strlen (abProgram)
+ + strlen (zbase)
+ strlen (zsys)
+ 1);
- sprintf (zfile, zLogfile, abProgram, zsys);
+ sprintf (zfile, zLogfile, zbase, zsys);
+ ubuffree (zbase);
eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE);
ubuffree (zfile);
}
@@ -328,10 +362,13 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
if (eLlog == NULL)
{
- /* We can't open the log file. We don't even have a
- safe way to report this problem, since we may not be
- able to write to stderr (it may, for example, be
- attached to the incoming call). */
+ /* We can't open the log file. We report the problem to
+ stderr. This is not ideal, since if this is uucico
+ running on an inbound call stderr is actually
+ connected to a remote system, but is better than
+ doing nothing. */
+ fprintf (stderr, "%s: %s: can not open log file\n",
+ zProgram, zLogfile);
if (pfLfatal != NULL)
(*pfLfatal) ();
usysdep_exit (FALSE);
@@ -392,99 +429,122 @@ ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
break;
}
- if (fstart)
+ if (! fstart)
+ zprefix = zbufcpy ("");
+ else
{
if (! fLfile)
{
- fprintf (e, "%s: ", abProgram);
- if (edebug != NULL)
- fprintf (edebug, "%s: ", abProgram);
+ zprefix = zbufalc (strlen (zProgram) + 3);
+ sprintf (zprefix, "%s: ", zProgram);
}
else
{
+ zprefix = zbufalc (strlen (zProgram)
+ + (zLsystem == NULL ? 1 : strlen (zLsystem))
+ + (zLuser == NULL ? 4 : strlen (zLuser))
+ + sizeof "1991-12-31 12:00:00.00"
+ + strlen (zhdr)
+ + 100);
+ zset = zprefix;
#if HAVE_TAYLOR_LOGGING
- fprintf (e, "%s ", abProgram);
- if (edebug != NULL)
- fprintf (edebug, "%s ", abProgram);
+ {
+ char *zbase;
+
+ zbase = zsysdep_base_name (zProgram);
+ if (zbase == NULL)
+ zbase = zbufcpy (zProgram);
+ zset = zstpcpy (zset, zbase);
+ *zset++ = ' ';
+ ubuffree (zbase);
+ }
#else /* ! HAVE_TAYLOR_LOGGING */
- fprintf (e, "%s ", zLuser == NULL ? "uucp" : zLuser);
- if (edebug != NULL)
- fprintf (edebug, "%s ", zLuser == NULL ? "uucp" : zLuser);
+ zset = zstpcpy (zset, zLuser == NULL ? "uucp" : zLuser);
+ *zset++ = ' ';
#endif /* HAVE_TAYLOR_LOGGING */
- fprintf (e, "%s ", zLsystem == NULL ? "-" : zLsystem);
- if (edebug != NULL)
- fprintf (edebug, "%s ", zLsystem == NULL ? "-" : zLsystem);
+ zset = zstpcpy (zset, zLsystem == NULL ? "-" : zLsystem);
+ *zset++ = ' ';
#if HAVE_TAYLOR_LOGGING
- fprintf (e, "%s ", zLuser == NULL ? "-" : zLuser);
- if (edebug != NULL)
- fprintf (edebug, "%s ", zLuser == NULL ? "-" : zLuser);
+ zset = zstpcpy (zset, zLuser == NULL ? "-" : zLuser);
+ *zset++ = ' ';
#endif /* HAVE_TAYLOR_LOGGING */
- zstr = zldate_and_time ();
- fprintf (e, "(%s", zstr);
- if (edebug != NULL)
- fprintf (edebug, "(%s", zstr);
+ *zset++ = '(';
+ zset = zstpcpy (zset, zldate_and_time ());
if (iLid != 0)
{
#if ! HAVE_HDB_LOGGING
#if HAVE_TAYLOR_LOGGING
- fprintf (e, " %d", iLid);
- if (edebug != NULL)
- fprintf (edebug, " %d", iLid);
+ sprintf (zset, " %d", iLid);
#else /* ! HAVE_TAYLOR_LOGGING */
- fprintf (e, "-%d", iLid);
- if (edebug != NULL)
- fprintf (edebug, "-%d", iLid);
+ sprintf (zset, "-%d", iLid);
#endif /* ! HAVE_TAYLOR_LOGGING */
#else /* HAVE_HDB_LOGGING */
-
/* I assume that the second number here is meant to be
some sort of file sequence number, and that it should
correspond to the sequence number in the statistics
file. I don't have any really convenient way to do
this, so I won't unless somebody thinks it's very
important. */
- fprintf (e, ",%d,%d", iLid, 0);
- if (edebug != NULL)
- fprintf (edebug, ",%d,%d", iLid, 0);
+ sprintf (zset, ",%d,%d", iLid, 0);
#endif /* HAVE_HDB_LOGGING */
+
+ zset += strlen (zset);
}
- fprintf (e, ") ");
- if (edebug != NULL)
- fprintf (edebug, ") ");
+#if QNX_LOG_NODE_ID
+ sprintf (zset, " %ld", (long) getnid ());
+ zset += strlen (zset);
+#endif
+
+ *zset++ = ')';
+ *zset++ = ' ';
- fprintf (e, "%s", zhdr);
- if (edebug != NULL)
- fprintf (edebug, "%s", zhdr);
+ strcpy (zset, zhdr);
}
}
+ zformat = zbufalc (2 * strlen (zprefix) + strlen (zmsg) + 2);
+
+ zset = zformat;
+ zfrom = zprefix;
+ while (*zfrom != '\0')
+ {
+ if (*zfrom == '%')
+ *zset++ = '%';
+ *zset++ = *zfrom++;
+ }
+
+ ubuffree (zprefix);
+
+ zset = zstpcpy (zset, zmsg);
+
+ if (fend)
+ {
+ *zset++ = '\n';
+ *zset = '\0';
+ }
+
#if HAVE_VFPRINTF
va_start (parg, zmsg);
- vfprintf (e, zmsg, parg);
+ vfprintf (e, zformat, parg);
va_end (parg);
if (edebug != NULL)
{
va_start (parg, zmsg);
- vfprintf (edebug, zmsg, parg);
+ vfprintf (edebug, zformat, parg);
va_end (parg);
}
#else /* ! HAVE_VFPRINTF */
- fprintf (e, zmsg, a, b, c, d, f, g, h, i, j);
+ fprintf (e, zformat, a, b, c, d, f, g, h, i, j);
if (edebug != NULL)
- fprintf (edebug, zmsg, a, b, c, d, f, g, h, i, j);
+ fprintf (edebug, zformat, a, b, c, d, f, g, h, i, j);
#endif /* ! HAVE_VFPRINTF */
- if (fend)
- {
- fprintf (e, "\n");
- if (edebug != NULL)
- fprintf (edebug, "\n");
- }
+ ubuffree (zformat);
(void) fflush (e);
if (edebug != NULL)
@@ -581,13 +641,24 @@ ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster)
cbps = 0;
else
{
- long cmillis;
-
- /* This computation will not overflow provided csecs < 2147483
- and cbytes and cbps both fit in a long. */
+ long cmillis, cdiv, crem;
+
+ /* Compute ((csecs * 1000) / cmillis) using integer division.
+ Where DIV is integer division, we know
+ a = (a DIV b) * b + a % b
+ so
+ a / b = (a DIV b) + (a % b) / b
+ We compute the latter with a as csecs and b as cmillis,
+ mixing the multiplication by 1000. */
cmillis = csecs * 1000 + cmicros / 1000;
- cbps = ((cbytes / cmillis) * 1000
- + ((cbytes % cmillis) * 1000) / cmillis);
+ cdiv = (cbytes / cmillis) * 1000;
+ crem = (cbytes % cmillis) * 1000;
+ cbps = cdiv + (crem / cmillis);
+ if (cmillis < 0 || cdiv < 0 || crem < 0 || cbps < 0)
+ {
+ /* We overflowed using milliseconds, so use seconds. */
+ cbps = cbytes / (csecs + ((cmicros > 500000L) ? 1 : 0));
+ }
}
if (eLstats == NULL)
@@ -602,11 +673,12 @@ ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster)
#if HAVE_TAYLOR_LOGGING
fprintf (eLstats,
- "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec)\n",
+ "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec) on port %s\n",
zuser, zsystem, zldate_and_time (),
fsucceeded ? "" : "failed after ",
fsent ? "sent" : "received",
- cbytes, csecs, cmicros / 1000, cbps);
+ cbytes, csecs, cmicros / 1000, cbps,
+ zLdevice == NULL ? "unknown" : zLdevice);
#endif /* HAVE_TAYLOR_LOGGING */
#if HAVE_V2_LOGGING
fprintf (eLstats,
@@ -625,18 +697,16 @@ ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster)
probably correspond to the sequence number in the log file, but
that is currently always 0; using this fake sequence number
will still at least reveal which transfers are from different
- calls. We don't report a failed data transfer with this
- format. */
- if (! fsucceeded)
- return;
+ calls. */
++iseq;
fprintf (eLstats,
- "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld %s\n",
+ "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld%s%s\n",
zsystem, zuser, fmaster ? 'M' : 'S', zldate_and_time (),
iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
fsent ? "->" : "<-",
cbytes, csecs, cmicros / 1000, cbps,
- "bytes/sec");
+ " bytes/sec",
+ fsucceeded ? "" : " [PARTIAL FILE]");
}
#endif /* HAVE_HDB_LOGGING */
diff --git a/gnu/libexec/uucp/common_sources/policy.h b/gnu/libexec/uucp/common_sources/policy.h
index 4c829bf42d8e..7fd03a24fa2e 100644
--- a/gnu/libexec/uucp/common_sources/policy.h
+++ b/gnu/libexec/uucp/common_sources/policy.h
@@ -1,7 +1,7 @@
/* policy.h
Configuration file for policy decisions. To be edited on site.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* This header file contains macro definitions which must be set by
@@ -72,14 +72,19 @@
figure out what's happening if something goes wrong. */
#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS == 0
+#ifdef __QNX__
+#undef HAVE_POSIX_TERMIOS
+#define HAVE_POSIX_TERMIOS 1
+#else /* ! defined (__QNX__) */
#if HAVE_CBREAK
#undef HAVE_BSD_TTY
#define HAVE_BSD_TTY 1
-#else
+#else /* ! HAVE_CBREAK */
#undef HAVE_SYSV_TERMIO
#define HAVE_SYSV_TERMIO 1
-#endif
-#endif
+#endif /* ! HAVE_CBREAK */
+#endif /* ! defined (__QNX__) */
+#endif /* HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS == 0 */
/* On some systems a write to a serial port will block even if the
file descriptor has been set to not block. File transfer can be
@@ -155,12 +160,23 @@
#define HAVE_STRIP_BUG 0
#if HAVE_BSD_TTY
+#ifdef __ultrix__
+#ifndef ultrix
+#define ultrix
+#endif
+#endif
#ifdef ultrix
#undef HAVE_STRIP_BUG
#define HAVE_STRIP_BUG 1
#endif
#endif
+/* If your system implements full duplex pipes, set
+ HAVE_FULLDUPLEX_PIPES to 1. Everything should work fine if you
+ leave it set to 0, but setting it to 1 can be slightly more
+ efficient. */
+#define HAVE_FULLDUPLEX_PIPES 0
+
/* TIMES_TICK is the fraction of a second which times(2) returns (for
example, if times returns 100ths of a second TIMES_TICK should be
set to 100). On a true POSIX system (one which has the sysconf
@@ -187,7 +203,7 @@
HAVE_SAVED_SETUID to 1, but your system does not have saved set
user ID, uucp will fail with an error message whenever anybody
other than the uucp user uses it. */
-#define HAVE_SAVED_SETUID 1
+#define HAVE_SAVED_SETUID 0
/* On some systems, such as the DG Aviion and, possibly, the RS/6000,
the setreuid function is broken. It should be possible to use
@@ -197,7 +213,7 @@
set HAVE_BROKEN_SETREUID to 1; if you do not, you will get error
messages from setreuid. Systems on which setreuid exists but is
broken pretty much always have saved setuid. */
-#define HAVE_BROKEN_SETREUID 0
+#define HAVE_BROKEN_SETREUID 1
/* On the 3B2, and possibly other systems, nap takes an argument in
hundredths of a second rather than milliseconds. I don't know of
@@ -206,6 +222,34 @@
have the nap function. */
#define HAVE_HUNDREDTHS_NAP 0
+/* Set MAIL_PROGRAM to a program which can be used to send mail. It
+ will be used for mail to both local and remote users. Set
+ MAIL_PROGRAM_TO_BODY to 1 if the recipient should be specified as a
+ To: line in the body of the message; otherwise, the recipient will
+ be provided as an argument to MAIL_PROGRAM. Set
+ MAIL_PROGRAM_SUBJECT_BODY if the subject should be specified as a
+ Subject: line in the body of the message; otherwise, the subject
+ will be provided using the -s option to MAIL_PROGRAM (if your mail
+ program does not support the -s option, you must set
+ MAIL_PROGRAM_SUBJECT_BODY to 1). If your system uses sendmail, use
+ the sendmail choice below. Otherwise, select one of the other
+ choices as appropriate. */
+#if 1
+#define MAIL_PROGRAM "/usr/sbin/sendmail -t"
+#define MAIL_PROGRAM_TO_BODY 1
+#define MAIL_PROGRAM_SUBJECT_BODY 1
+#endif
+#if 0
+#define MAIL_PROGRAM "/usr/ucb/mail"
+#define MAIL_PROGRAM_TO_BODY 0
+#define MAIL_PROGRAM_SUBJECT_BODY 0
+#endif
+#if 0
+#define MAIL_PROGRAM "/bin/mail"
+#define MAIL_PROGRAM_TO_BODY 0
+#define MAIL_PROGRAM_SUBJECT_BODY 1
+#endif
+
/* Set PS_PROGRAM to the program to run to get a process status,
including the arguments to pass it. This is used by ``uustat -p''.
Set HAVE_PS_MULTIPLE to 1 if a comma separated list of process
@@ -229,6 +273,13 @@
#define PS_PROGRAM "/bin/ps -flp"
#define HAVE_PS_MULTIPLE 1
#endif
+#ifdef __QNX__
+/* Use this for QNX, along with HAVE_QNX_LOCKFILES. */
+#undef PS_PROGRAM
+#undef HAVE_PS_MULTIPLE
+#define PS_PROGRAM "/bin/ps -l -n -p"
+#define HAVE_PS_MULTIPLE 0
+#endif
/* If you use other programs that also lock devices, such as cu or
uugetty, the other programs and UUCP must agree on whether a device
@@ -269,20 +320,91 @@
device itself, and zzz is the minor device number of the port
device.
+ Sequent DYNIX/ptx (but perhaps not Dynix 3.x) uses yet another
+ naming convention. The lock file for /dev/ttyXA/XAAP is named
+ LCK..ttyXAAP.
+
Coherent use a completely different method of terminal locking.
See unix/cohtty for details. For locks other than for terminals,
- HDB type lock files are used. */
+ HDB type lock files are used.
+
+ QNX lock files are similar to HDB lock files except that the node
+ ID must be stored in addition to the process ID and for serial
+ devices the node ID must be included in the lock file name. QNX
+ boxes are generally used in bunches, and all of them behave like
+ one big machine to some extent. Thus, processes on different
+ machines will be sharing the files in the spool directory. To
+ detect if a process has died and a lock is thus stale, you need the
+ node ID of the process as well as the process ID. The process ID
+ is stored as a number written using ASCII digits padded to 10
+ characters, followed by a space, followed by the node ID written
+ using ASCII digits padded to 10 characters, followed by a newline.
+ The format for QNX lock files was made up just for Taylor UUCP.
+ QNX doesn't come with a version of UUCP. */
#define HAVE_V2_LOCKFILES 0
#define HAVE_HDB_LOCKFILES 1
#define HAVE_SCO_LOCKFILES 0
#define HAVE_SVR4_LOCKFILES 0
+#define HAVE_SEQUENT_LOCKFILES 0
#define HAVE_COHERENT_LOCKFILES 0
+#define HAVE_QNX_LOCKFILES 0
+
+/* This tries to pick a default based on preprocessor definitions.
+ Ignore it if you have explicitly set one of the above values. */
+#if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_SEQUENT_LOCKFILES + HAVE_COHERENT_LOCKFILES + HAVE_QNX_LOCKFILES == 0
+#ifdef __QNX__
+#undef HAVE_QNX_LOCKFILES
+#define HAVE_QNX_LOCKFILES 1
+#else /* ! defined (__QNX__) */
+#ifdef __COHERENT__
+#undef HAVE_COHERENT_LOCKFILES
+#define HAVE_COHERENT_LOCKFILES 1
+#else /* ! defined (__COHERENT__) */
+#ifdef _SEQUENT_
+#undef HAVE_SEQUENT_LOCKFILES
+#define HAVE_SEQUENT_LOCKFILES 1
+#else /* ! defined (_SEQUENT) */
+#ifdef sco
+#undef HAVE_SCO_LOCKFILES
+#define HAVE_SCO_LOCKFILES 1
+#else /* ! defined (sco) */
+#ifdef __svr4__
+#undef HAVE_SVR4_LOCKFILES
+#define HAVE_SVR4_LOCKFILES 1
+#else /* ! defined (__svr4__) */
+/* Final default is HDB. There's no way to tell V2 from HDB. */
+#undef HAVE_HDB_LOCKFILES
+#define HAVE_HDB_LOCKFILES 1
+#endif /* ! defined (__svr4__) */
+#endif /* ! defined (sco) */
+#endif /* ! defined (_SEQUENT) */
+#endif /* ! defined (__COHERENT__) */
+#endif /* ! defined (__QNX__) */
+#endif /* no LOCKFILES define */
/* If your system supports Internet mail addresses (which look like
user@host.domain rather than system!user), HAVE_INTERNET_MAIL
- should be set to 1. This is checked by uuxqt when sending error
- (or success, if requested) notifications to the person who
- submitted the job. */
+ should be set to 1. This is checked by uuxqt and uustat when
+ sending notifications to the person who submitted the job.
+
+ If your system does not understand addresses of the form user@host,
+ you must set HAVE_INTERNET_MAIL to 0.
+
+ If your system does not understand addresses of the form host!user,
+ which is unlikely, you must set HAVE_INTERNET_MAIL to 1.
+
+ If your system sends mail addressed to "A!B@C" to host C (i.e., it
+ parses the address as "(A!B)@C"), you must set HAVE_INTERNET_MAIL
+ to 1.
+
+ If your system sends mail addressed to "A!B@C" to host A (i.e., it
+ parses the address as "A!(B@C)"), you must set HAVE_INTERNET_MAIL
+ to 0.
+
+ Note that in general it is best to avoid addresses of the form
+ "A!B@C" because of this ambiguity of precedence. UUCP will not
+ intentionally generate addresses of this form, but it can occur in
+ certain rather complex cases. */
#define HAVE_INTERNET_MAIL 1
/* Adminstrative decisions. */
@@ -303,6 +425,16 @@
file size will be very helpful. */
#define DEBUG 2
+/* Set HAVE_ENCRYPTED_PASSWORDS to 1 if you want login passwords to be
+ encrypted before comparing them against the values in the file.
+ This only applies when uucico is run with the -l or -e switches and
+ is doing its own login prompting. Note that the passwords used are
+ from the UUCP password file, not the system /etc/passwd file. See
+ the documentation for further details. If you set this, you are
+ responsible for encrypting the passwords in the UUCP password file.
+ The function crypt will be used to do comparisons. */
+#define HAVE_ENCRYPTED_PASSWORDS 0
+
/* Set the default grade to use for a uucp command if the -g option is
not used. The grades, from highest to lowest, are 0 to 9, A to Z,
a to z. */
@@ -327,8 +459,8 @@
When looking something up (a system, a port, etc.) the new style
configuration files will be read first, followed by the V2
configuration files, followed by the HDB configuration files. */
-#define HAVE_V2_CONFIG 1
-#define HAVE_HDB_CONFIG 1
+#define HAVE_V2_CONFIG 0
+#define HAVE_HDB_CONFIG 0
/* Exactly one of the following macros must be set to 1. The exact
format of the spool directories is explained in unix/spool.c.
@@ -351,6 +483,15 @@
#define SPOOLDIR_SVR4 0
#define SPOOLDIR_TAYLOR 1
+/* The status file generated by UUCP can use either the traditional
+ HDB upper case comments or new easier to read lower case comments.
+ This affects the display of uustat -m or uustat -q. Some
+ third-party programs read these status files and expect them to be
+ in a certain format. The default is to use the traditional
+ comments when using an HDB or SVR4 spool directory, and to use
+ lower case comments otherwise. */
+#define USE_TRADITIONAL_STATUS (SPOOLDIR_HDB || SPOOLDIR_SVR4)
+
/* You must select which type of logging you want by setting exactly
one of the following to 1. These control output to the log file
and to the statistics file.
@@ -392,6 +533,27 @@
#define HAVE_V2_LOGGING 0
#define HAVE_HDB_LOGGING 0
+/* If QNX_LOG_NODE_ID is set to 1, log messages will include the QNX
+ node ID just after the process ID. This is a policy decision
+ because it changes the log file entry format, which can break other
+ programs (e.g., some of the ones in the contrib directory) which
+ expect to read the standard log file format. */
+#ifdef __QNX__
+#define QNX_LOG_NODE_ID 1
+#else
+#define QNX_LOG_NODE_ID 0
+#endif
+
+/* If LOG_DEVICE_PREFIX is 1, log messages will give the full
+ pathname of a device rather than just the final component. This is
+ important because on QNX //2/dev/ser2 refers to a different device
+ than //4/dev/ser2. */
+#ifdef __QNX__
+#define LOG_DEVICE_PREFIX 1
+#else
+#define LOG_DEVICE_PREFIX 0
+#endif
+
/* If you would like the log, debugging and statistics files to be
closed after each message, set CLOSE_LOGFILES to 1. This will
permit the log files to be easily moved. If a log file does not
@@ -403,6 +565,7 @@
/* The name of the default spool directory. If HAVE_TAYLOR_CONFIG is
set to 1, this may be overridden by the ``spool'' command in the
configuration file. */
+/* #define SPOOLDIR "/usr/spool/uucp" */
#define SPOOLDIR "/var/spool/uucp"
/* The name of the default public directory. If HAVE_TAYLOR_CONFIG is
@@ -410,6 +573,7 @@
configuration file. Also, a particular system may be given a
specific public directory by using the ``pubdir'' command in the
system file. */
+/* #define PUBDIR "/usr/spool/uucppublic" */
#define PUBDIR "/var/spool/uucppublic"
/* The default command path. This is a space separated list of
@@ -464,16 +628,19 @@
/* The default log file when using HAVE_TAYLOR_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile''
command in the configuration file. */
+/* #define LOGFILE "/usr/spool/uucp/Log" */
#define LOGFILE "/var/spool/uucp/Log"
/* The default statistics file when using HAVE_TAYLOR_LOGGING. When
using HAVE_TAYLOR_CONFIG, this may be overridden by the
``statfile'' command in the configuration file. */
+/* #define STATFILE "/usr/spool/uucp/Stats" */
#define STATFILE "/var/spool/uucp/Stats"
/* The default debugging file when using HAVE_TAYLOR_LOGGING. When
using HAVE_TAYLOR_CONFIG, this may be overridden by the
``debugfile'' command in the configuration file. */
+/* #define DEBUGFILE "/usr/spool/uucp/Debug" */
#define DEBUGFILE "/var/spool/uucp/Debug"
#endif /* HAVE_TAYLOR_LOGGING */
@@ -483,17 +650,17 @@
/* The default log file when using HAVE_V2_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile''
command in the configuration file. */
-#define LOGFILE "/var/spool/uucp/LOGFILE"
+#define LOGFILE "/usr/spool/uucp/LOGFILE"
/* The default statistics file when using HAVE_V2_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile''
command in the configuration file. */
-#define STATFILE "/var/spool/uucp/SYSLOG"
+#define STATFILE "/usr/spool/uucp/SYSLOG"
/* The default debugging file when using HAVE_V2_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile''
command in the configuration file. */
-#define DEBUGFILE "/var/spool/uucp/DEBUG"
+#define DEBUGFILE "/usr/spool/uucp/DEBUG"
#endif /* HAVE_V2_LOGGING */
@@ -506,16 +673,16 @@
be replaced by the system name (if there is no appropriate system,
"ANY" will be used). No other '%' character may appear in the
string. */
-#define LOGFILE "/var/spool/uucp/.Log/%s/%s"
+#define LOGFILE "/usr/spool/uucp/.Log/%s/%s"
/* The default statistics file when using HAVE_HDB_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile''
command in the configuration file. */
-#define STATFILE "/var/spool/uucp/.Admin/xferstats"
+#define STATFILE "/usr/spool/uucp/.Admin/xferstats"
/* The default debugging file when using HAVE_HDB_LOGGING. When using
HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile''
command in the configuration file. */
-#define DEBUGFILE "/var/spool/uucp/.Admin/audit.local"
+#define DEBUGFILE "/usr/spool/uucp/.Admin/audit.local"
#endif /* HAVE_HDB_LOGGING */
diff --git a/gnu/libexec/uucp/common_sources/prot.c b/gnu/libexec/uucp/common_sources/prot.c
index 433bf2766829..067ac1f52ff1 100644
--- a/gnu/libexec/uucp/common_sources/prot.c
+++ b/gnu/libexec/uucp/common_sources/prot.c
@@ -1,7 +1,7 @@
/* prot.c
Protocol support routines to move commands and data around.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,18 +20,19 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char prot_rcsid[] = "$Id: prot.c,v 1.1 1993/08/05 18:22:41 conklin Exp $";
+const char prot_rcsid[] = "$Id: prot.c,v 1.2 1994/05/07 18:08:51 ache Exp $";
#endif
#include <errno.h>
#include "uudefs.h"
+#include "uuconf.h"
#include "system.h"
#include "conn.h"
#include "prot.h"
@@ -76,6 +77,9 @@ fsend_data (qconn, zsend, csend, fdoread)
--crec;
}
+ if (crec == 0)
+ return fconn_write (qconn, zsend, csend);
+
csent = csend;
if (! fconn_io (qconn, zsend, &csent, abPrecbuf + iPrecend, &crec))
diff --git a/gnu/libexec/uucp/common_sources/prot.h b/gnu/libexec/uucp/common_sources/prot.h
index 4e2bb584d842..07dc6203f426 100644
--- a/gnu/libexec/uucp/common_sources/prot.h
+++ b/gnu/libexec/uucp/common_sources/prot.h
@@ -1,7 +1,7 @@
/* prot.h
Protocol header file.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* We need the definition of uuconf_cmdtab to declare the protocol
@@ -49,6 +49,8 @@ struct sprotocol
int ireliable;
/* The maximum number of channels this protocol can support. */
int cchans;
+ /* Whether files may be reliably restarted using this protocol. */
+ boolean frestart;
/* Protocol parameter commands. */
struct uuconf_cmdtab *qcmds;
/* A routine to start the protocol. If *pzlog is set to be
@@ -163,6 +165,7 @@ extern boolean fijstart P((struct sdaemon *qdaemon, char **pzlog,
extern struct uuconf_cmdtab asGproto_params[];
extern boolean fgstart P((struct sdaemon *qdaemon, char **pzlog));
extern boolean fbiggstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fvstart P((struct sdaemon *qdaemon, char **pzlog));
extern boolean fgshutdown P((struct sdaemon *qdaemon));
extern boolean fgsendcmd P((struct sdaemon *qdaemon, const char *z,
int ilocal, int iremote));
diff --git a/gnu/libexec/uucp/common_sources/sysdep.h b/gnu/libexec/uucp/common_sources/sysdep.h
index 47675ac2385d..41dcecdf9277 100644
--- a/gnu/libexec/uucp/common_sources/sysdep.h
+++ b/gnu/libexec/uucp/common_sources/sysdep.h
@@ -1,7 +1,7 @@
/* sysh.unx -*- C -*-
The header file for the UNIX system dependent routines.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#ifndef SYSH_UNX_H
@@ -34,14 +34,9 @@ struct uuconf_system;
struct sconnection;
#endif
-/* Make sure the defines do not conflict. These are in this file
- because they are Unix dependent. */
-#if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_COHERENT_LOCKFILES != 1
- #error LOCKFILES define not set or duplicated
-#endif
-
-/* SCO and SVR4 lockfiles are basically just like HDB lockfiles. */
-#if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES
+/* SCO, SVR4 and Sequent lockfiles are basically just like HDB
+ lockfiles. */
+#if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES || HAVE_SEQUENT_LOCKFILES
#undef HAVE_HDB_LOCKFILES
#define HAVE_HDB_LOCKFILES 1
#endif
@@ -230,6 +225,9 @@ typedef struct termios sterminal;
failed. */
#define PRESERVEDIR ".Preserve"
+/* The name of the directory to which we move corrupt files. */
+#define CORRUPTDIR ".Corrupt"
+
/* The length of the sequence number used in a file name. */
#define CSEQLEN (4)
@@ -284,6 +282,10 @@ typedef struct termios sterminal;
#define S_IXOTH 0001
#endif
+#if STAT_MACROS_BROKEN
+#undef S_ISDIR
+#endif
+
#ifndef S_ISDIR
#ifdef S_IFDIR
#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
@@ -351,12 +353,16 @@ struct ssysdep_conn
{
/* File descriptor. */
int o;
+ /* File descriptor to read from (used by stdin and pipe port types). */
+ int ord;
+ /* File descriptor to write to (used by stdin and pipe port types). */
+ int owr;
/* Device name. */
char *zdevice;
/* File status flags. */
int iflags;
- /* File status flags for descriptor 1 (-1 if not standard input). */
- int istdout_flags;
+ /* File status flags for write descriptor (-1 if not used). */
+ int iwr_flags;
/* Hold the real descriptor when using a dialer device. */
int ohold;
/* TRUE if this is a terminal and the remaining fields are valid. */
@@ -369,6 +375,9 @@ struct ssysdep_conn
sterminal sorig;
/* Current terminal settings. */
sterminal snew;
+ /* Process ID of currently executing pipe command, or parent process
+ of forked TCP or TLI server, or -1. */
+ pid_t ipid;
#if HAVE_COHERENT_LOCKFILES
/* On Coherent we need to hold on to the real port name which will
be used to enable the port. Ick. */
@@ -428,6 +437,19 @@ extern FILE *espopen P((const char **pazargs, boolean frd,
prototype. */
extern int ixswait P((unsigned long ipid, const char *zreport));
+/* Read from a connection using two file descriptors. */
+extern boolean fsdouble_read P((struct sconnection *qconn, char *zbuf,
+ size_t *pclen, size_t cmin, int ctimeout,
+ boolean freport));
+
+/* Write to a connection using two file descriptors. */
+extern boolean fsdouble_write P((struct sconnection *qconn,
+ const char *zbuf, size_t clen));
+
+/* Run a chat program on a connection using two file descriptors. */
+extern boolean fsdouble_chat P((struct sconnection *qconn,
+ char **pzprog));
+
/* Find a spool file in the spool directory. For a local file, the
bgrade argument is the grade of the file. This is needed for
SPOOLDIR_SVR4. */
@@ -435,7 +457,7 @@ extern char *zsfind_file P((const char *zsimple, const char *zsystem,
int bgrade));
/* Return the grade given a sequence number. */
-extern char bsgrade P((pointer pseq));
+extern int bsgrade P((pointer pseq));
/* Lock a string. */
extern boolean fsdo_lock P((const char *, boolean fspooldir,
@@ -493,7 +515,7 @@ extern int dup2 P((int oold, int onew));
#if ! HAVE_FTW
extern int ftw P((const char *zdir,
int (*pfn) P((const char *zfile,
- const struct stat *qstat,
+ struct stat *qstat,
int iflag)),
int cdescriptors));
#endif
diff --git a/gnu/libexec/uucp/common_sources/system.h b/gnu/libexec/uucp/common_sources/system.h
index aa9d2a41a45a..9765edf17a49 100644
--- a/gnu/libexec/uucp/common_sources/system.h
+++ b/gnu/libexec/uucp/common_sources/system.h
@@ -2,7 +2,7 @@
Header file for system dependent stuff in the Taylor UUCP package.
This file is not itself system dependent.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -21,7 +21,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#ifndef SYSTEM_H
@@ -73,6 +73,11 @@ extern size_t cSysdep_max_name_len;
means, on Unix, this program is normally installed setuid. */
#define INIT_SUID (04)
+/* Do not close all open descriptors. This is not used by the UUCP
+ code, but it is used by other programs which share some of the
+ system dependent libraries. */
+#define INIT_NOCLOSE (010)
+
extern void usysdep_initialize P((pointer puuconf, int iflags));
/* Exit the program. The fsuccess argument indicates whether to
@@ -172,9 +177,13 @@ extern const char *zsysdep_port_name P((boolean *pftcp_port));
desirable on other systems. This should always return an absolute
path name, probably in the public directory. It should return NULL
on error; otherwise the return value should be allocated using
- zbufcpy or zbufalc. */
+ zbufcpy or zbufalc. If pfbadname is not NULL, then if the function
+ returns NULL *pfbadname should be set to TRUE if the error is just
+ that the file name is badly specified; *pfbadname should be set to
+ FALSE for some sort of internal error. */
extern char *zsysdep_local_file P((const char *zname,
- const char *zpubdir));
+ const char *zpubdir,
+ boolean *pfbadname));
/* Return whether a file name is in a directory, and check for read or
write access. This should check whether zfile is within zdir (or
@@ -201,17 +210,16 @@ extern boolean fsysdep_in_directory P((const char *zfile,
return error. */
extern boolean fsysdep_file_exists P((const char *zfile));
-/* Start up a program. The code expects fsysdep_run to return after
- doing a fork, but at least for now everything will work fine if it
- does not (on a system which does not support forking). The three
- string arguments may be catenated together to form the program to
- execute; I did it this way to make it easy to call execl(2), and
- because I never needed more than two arguments. The program will
- always be "uucico" or "uuxqt". The return value will be passed
- directly to usysdep_exit, and should be TRUE on success, FALSE on
+/* Start up a program. If the ffork argument is true, this should
+ spawn a new process and return. If the ffork argument is false,
+ this may either return or not. The three string arguments may be
+ catenated together to form the program to execute; I did it this
+ way to make it easy to call execl(2), and because I never needed
+ more than two arguments. The program will always be "uucico" or
+ "uuxqt". The return value should be TRUE on success, FALSE on
error. */
-extern boolean fsysdep_run P((const char *zprogram, const char *zarg1,
- const char *zarg2));
+extern boolean fsysdep_run P((boolean ffork, const char *zprogram,
+ const char *zarg1, const char *zarg2));
/* Send a mail message. This function will be passed an array of
strings. All necessary newlines are already included; the strings
@@ -329,6 +337,12 @@ extern boolean fsysdep_did_work P((pointer pseq));
the file. */
extern const char *zsysdep_save_temp_file P((pointer pseq));
+/* Save a file in a location used to hold corrupt files. This is
+ called if a bad execution file is found by uuxqt. This should
+ return the new name of the file (allocated by zbufalc), or NULL if
+ the move failed (in which the original file should remain). */
+extern char *zsysdep_save_corrupt_file P((const char *zfile));
+
/* Cleanup anything left over by fsysdep_get_work_init and
fsysdep_get_work. This may be called even though
fsysdep_get_work_init has not been. */
@@ -397,23 +411,27 @@ extern openfile_t esysdep_open_send P((const struct uuconf_system *qsys,
/* Return a temporary file name to receive into. This file will be
opened by esysdep_open_receive. The qsys argument is the system
the file is coming from, the zto argument is the name the file will
- have after it has been fully received, and the ztemp argument, if
- it is not NULL, is from the command sent by the remote system. The
- return value must be freed using ubuffree. The function should
- return NULL on error. */
+ have after it has been fully received, the ztemp argument, if it is
+ not NULL, is from the command sent by the remote system, and the
+ frestart argument is TRUE if the protocol and remote system permit
+ file transfers to be restarted. The return value must be freed
+ using ubuffree. The function should return NULL on error. */
extern char *zsysdep_receive_temp P((const struct uuconf_system *qsys,
const char *zfile,
- const char *ztemp));
+ const char *ztemp,
+ boolean frestart));
/* Open a file to receive from another system. The zreceive argument
is the return value of zsysdep_receive_temp with the same qsys,
zfile and ztemp arguments. If the function can determine that this
file has already been partially received, it should set *pcrestart
to the number of bytes that have been received. If the file has
- not been partially received, *pcrestart should be set to -1. The
- function should return EFILECLOSED on error. After the file is
- written, fsysdep_move_file will be called to move the file to its
- final destination, and to set the correct file mode. */
+ not been partially received, *pcrestart should be set to -1.
+ pcrestart will be passed in as NULL if file restart is not
+ supported by the protocol or the remote system. The function
+ should return EFILECLOSED on error. After the file is written,
+ fsysdep_move_file will be called to move the file to its final
+ destination, and to set the correct file mode. */
extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys,
const char *zto,
const char *ztemp,
@@ -428,8 +446,8 @@ extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys,
this should make sure the directory is writeable by the user zuser
(if zuser is NULL, then it must be writeable by any user); this is
to avoid a window of vulnerability between fsysdep_in_directory and
- fsysdep_move_file. This function should return FALSE on error; the
- zorig file should be removed even if an error occurs. */
+ fsysdep_move_file. This function should return FALSE on error, in
+ which case the zorig file should still exist. */
extern boolean fsysdep_move_file P((const char *zorig, const char *zto,
boolean fmkdirs, boolean fpublic,
boolean fcheck, const char *zuser));
@@ -675,7 +693,8 @@ extern boolean fsysdep_move_uuxqt_files P((int cfiles,
started in rather than in the public directory. This should return
NULL on error. */
extern char *zsysdep_local_file_cwd P((const char *zname,
- const char *zpubdir));
+ const char *zpubdir,
+ boolean *pfbadname));
/* Add the working directory to a file name. The named file is
actually on a remote system. If the file already has a directory,
@@ -748,9 +767,11 @@ extern boolean usysdep_walk_tree P((const char *zdir,
extern char *zsysdep_jobid P((const struct uuconf_system *qsys,
pointer pseq));
-/* See whether the current user is permitted to kill jobs submitted by
- another user. This should return TRUE if permission is granted,
- FALSE otherwise. */
+/* See whether the current user is privileged. Privileged users are
+ permitted to kill jobs submitted by another user, and they are
+ permitted to use the -u argument to uucico; other uses of this call
+ may be added later. This should return TRUE if permission is
+ granted, FALSE otherwise. */
extern boolean fsysdep_privileged P((void));
/* Kill a job, given the jobid. This should remove all associated
@@ -778,6 +799,11 @@ extern long ixsysdep_work_time P((const struct uuconf_system *qsys,
value must use the same epoch as ixsysdep_time. */
extern long ixsysdep_file_time P((const char *zfile));
+/* Touch a file to make it appear as though it was created at the
+ current time. This is called by uustat on execution files. On
+ error this should log an error message and return FALSE. */
+extern boolean fsysdep_touch_file P((const char *zfile));
+
/* Get the size in bytes of a file. If this file does not exist, this
should not give an error message, but should return -1. If some
other error occurs, this should return -2. */
@@ -942,7 +968,8 @@ extern boolean fsysdep_uupick_free P((const char *zsystem,
zsysdep_local_file_cwd except that a file beginning with ~/ is
placed in the user's home directory rather than in the public
directory. */
-extern char *zsysdep_uupick_local_file P((const char *zfile));
+extern char *zsysdep_uupick_local_file P((const char *zfile,
+ boolean *pfbadname));
/* Remove a directory and all the files in it. */
extern boolean fsysdep_rmdir P((const char *zdir));
diff --git a/gnu/libexec/uucp/common_sources/tcp.c b/gnu/libexec/uucp/common_sources/tcp.c
index 543e9f0d8205..6c06eb639ab4 100644
--- a/gnu/libexec/uucp/common_sources/tcp.c
+++ b/gnu/libexec/uucp/common_sources/tcp.c
@@ -1,7 +1,7 @@
/* tcp.c
Code to handle TCP connections.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char tcp_rcsid[] = "$Id: tcp.c,v 1.1 1993/08/05 18:22:46 conklin Exp $";
+const char tcp_rcsid[] = "$Id: tcp.c,v 1.2 1994/05/07 18:09:01 ache Exp $";
#endif
#if HAVE_TCP
@@ -72,7 +72,6 @@ static boolean ftcp_close P((struct sconnection *qconn,
pointer puuconf,
struct uuconf_dialer *qdialer,
boolean fsuccess));
-static boolean ftcp_reset P((struct sconnection *qconn));
static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf,
const struct uuconf_system *qsys,
const char *zphone,
@@ -88,7 +87,6 @@ static const struct sconncmds stcpcmds =
NULL, /* pfunlock */
ftcp_open,
ftcp_close,
- ftcp_reset,
ftcp_dial,
fsysdep_conn_read,
fsysdep_conn_write,
@@ -110,9 +108,11 @@ fsysdep_tcp_init (qconn)
q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
q->o = -1;
+ q->ord = -1;
+ q->owr = -1;
q->zdevice = NULL;
q->iflags = -1;
- q->istdout_flags = -1;
+ q->iwr_flags = -1;
q->fterminal = FALSE;
q->ftli = FALSE;
q->ibaud = 0;
@@ -175,6 +175,10 @@ ftcp_open (qconn, ibaud, fwait)
return FALSE;
}
+ /* We save our process ID in the qconn structure. This is checked
+ in ftcp_close. */
+ qsysdep->ipid = getpid ();
+
/* If we aren't waiting for a connection, we're done. */
if (! fwait)
return TRUE;
@@ -347,23 +351,16 @@ ftcp_close (qconn, puuconf, qdialer, fsuccess)
fret = FALSE;
}
qsysdep->o = -1;
- return fret;
-}
-
-/* Reset the port. This will be called by a child which was forked
- off in ftcp_open, above. We don't want uucico to continue looping
- and giving login prompts, so we pretend that we received a SIGINT
- signal. This should probably be handled more cleanly. The signal
- will not be recorded in the log file because we don't set
- afLog_signal[INDEXSIG_SIGINT]. */
-/*ARGSUSED*/
-static boolean
-ftcp_reset (qconn)
- struct sconnection *qconn;
-{
- afSignal[INDEXSIG_SIGINT] = TRUE;
- return TRUE;
+ /* If the current pid is not the one we used to open the port, then
+ we must have forked up above and we are now the child. In this
+ case, we are being called from within the fendless loop in
+ uucico.c. We return FALSE to force the loop to end and the child
+ to exit. This should be handled in a cleaner fashion. */
+ if (qsysdep->ipid != getpid ())
+ fret = FALSE;
+
+ return fret;
}
/* Dial out on a TCP port, so to speak: connect to a remote computer. */
@@ -383,6 +380,7 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
struct hostent *q;
struct sockaddr_in s;
const char *zport;
+ char **pzdialer;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
@@ -411,9 +409,9 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
}
s.sin_family = q->h_addrtype;
+ memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length);
zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
s.sin_port = itcp_port_number (zport);
- memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length);
if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
{
@@ -421,6 +419,15 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
return FALSE;
}
+ /* Handle the dialer sequence, if any. */
+ pzdialer = qconn->qport->uuconf_u.uuconf_stcp.uuconf_pzdialer;
+ if (pzdialer != NULL && *pzdialer != NULL)
+ {
+ if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone,
+ qdialer, ptdialer))
+ return FALSE;
+ }
+
return TRUE;
}
diff --git a/gnu/libexec/uucp/common_sources/tli.c b/gnu/libexec/uucp/common_sources/tli.c
index 9fffdcdfebd1..0b2ab5489fb1 100644
--- a/gnu/libexec/uucp/common_sources/tli.c
+++ b/gnu/libexec/uucp/common_sources/tli.c
@@ -1,7 +1,7 @@
/* tli.c
Code to handle TLI connections.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char tli_rcsid[] = "$Id: tli.c,v 1.1 1993/08/05 18:22:46 conklin Exp $";
+const char tli_rcsid[] = "$Id: tli.c,v 1.2 1994/05/07 18:09:03 ache Exp $";
#endif
#if HAVE_TLI
@@ -92,9 +92,11 @@ extern int t_errno;
extern char *t_errlist[];
extern int t_nerr;
+#ifndef HAVE_TIUSER_H
#ifndef t_alloc
extern pointer t_alloc ();
#endif
+#endif
/* This code handles TLI connections. It's Unix specific. It's
largely based on code from Unix Network Programming, by W. Richard
@@ -110,7 +112,6 @@ static boolean ftli_close P((struct sconnection *qconn,
pointer puuconf,
struct uuconf_dialer *qdialer,
boolean fsuccess));
-static boolean ftli_reset P((struct sconnection *qconn));
static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf,
const struct uuconf_system *qsys,
const char *zphone,
@@ -125,7 +126,6 @@ static const struct sconncmds stlicmds =
NULL, /* pfunlock */
ftli_open,
ftli_close,
- ftli_reset,
ftli_dial,
fsysdep_conn_read,
fsysdep_conn_write,
@@ -149,7 +149,8 @@ ztlierror ()
return t_errlist[t_errno];
}
-/* Initialize a TLI connection. */
+/* Initialize a TLI connection. This may be called with qconn->qport
+ NULL, when opening standard input as a TLI connection. */
boolean
fsysdep_tli_init (qconn)
@@ -159,9 +160,11 @@ fsysdep_tli_init (qconn)
q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
q->o = -1;
+ q->ord = -1;
+ q->owr = -1;
q->zdevice = NULL;
q->iflags = -1;
- q->istdout_flags = -1;
+ q->iwr_flags = -1;
q->fterminal = FALSE;
q->ftli = TRUE;
q->ibaud = 0;
@@ -295,6 +298,10 @@ ftli_open (qconn, ibaud, fwait)
return FALSE;
}
+ /* We save our process ID in the qconn structure. This is checked
+ in ftli_close. */
+ qsysdep->ipid = getpid ();
+
/* If we aren't waiting for a connection, we can bind to any local
address, and then we're finished. */
if (! fwait)
@@ -463,23 +470,15 @@ ftli_close (qconn, puuconf, qdialer, fsuccess)
qsysdep->o = -1;
}
- return fret;
-}
-
-/* Reset the port. This will be called by a child which was forked
- off in ftli_open, above. We don't want uucico to continue looping
- and giving login prompts, so we pretend that we received a SIGINT
- signal. This should probably be handled more cleanly. The signal
- will not be recorded in the log file because we don't set
- afLog_signal[INDEXSIG_SIGINT]. */
+ /* If the current pid is not the one we used to open the port, then
+ we must have forked up above and we are now the child. In this
+ case, we are being called from within the fendless loop in
+ uucico.c. We return FALSE to force the loop to end and the child
+ to exit. This should be handled in a cleaner fashion. */
+ if (qsysdep->ipid != getpid ())
+ fret = FALSE;
-/*ARGSUSED*/
-static boolean
-ftli_reset (qconn)
- struct sconnection *qconn;
-{
- afSignal[INDEXSIG_SIGINT] = TRUE;
- return TRUE;
+ return fret;
}
/* Dial out on a TLI port, so to speak: connect to a remote computer. */
@@ -569,73 +568,12 @@ ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
if (! ftli_push (qconn))
return FALSE;
- /* Handle the rest of the dialer sequence. This is similar to
- fmodem_dial, and they should, perhaps, be combined somehow. */
- if (pzdialer != NULL)
+ /* Handle the rest of the dialer sequence. */
+ if (pzdialer != NULL && *pzdialer != NULL)
{
- boolean ffirst;
-
- ffirst = TRUE;
- while (*pzdialer != NULL)
- {
- int iuuconf;
- struct uuconf_dialer *q;
- struct uuconf_dialer s;
- const char *ztoken;
- boolean ftranslate;
-
- if (! ffirst)
- q = &s;
- else
- q = qdialer;
-
- iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
- if (iuuconf == UUCONF_NOT_FOUND)
- {
- ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
- return FALSE;
- }
- else if (iuuconf != UUCONF_SUCCESS)
- {
- ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
- return FALSE;
- }
-
- ++pzdialer;
- ztoken = *pzdialer;
-
- ftranslate = FALSE;
- if (ztoken == NULL
- || strcmp (ztoken, "\\D") == 0)
- ztoken = zphone;
- else if (strcmp (ztoken, "\\T") == 0)
- {
- ztoken = zphone;
- ftranslate = TRUE;
- }
-
- if (! fchat (qconn, puuconf, &q->uuconf_schat,
- (const struct uuconf_system *) NULL, q,
- zphone, ftranslate, qconn->qport->uuconf_zname,
- (long) 0))
- {
- (void) uuconf_dialer_free (puuconf, q);
- if (! ffirst)
- (void) uuconf_dialer_free (puuconf, qdialer);
- return FALSE;
- }
-
- if (ffirst)
- {
- *ptdialerfound = DIALERFOUND_FREE;
- ffirst = FALSE;
- }
- else
- (void) uuconf_dialer_free (puuconf, q);
-
- if (*pzdialer != NULL)
- ++pzdialer;
- }
+ if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone,
+ qdialer, ptdialerfound))
+ return FALSE;
}
return TRUE;
diff --git a/gnu/libexec/uucp/common_sources/trans.h b/gnu/libexec/uucp/common_sources/trans.h
index 79c380ea48d8..93aee2e9ac8f 100644
--- a/gnu/libexec/uucp/common_sources/trans.h
+++ b/gnu/libexec/uucp/common_sources/trans.h
@@ -1,7 +1,7 @@
/* trans.h
Header file for file and command transfer routines.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* The maximum possible number of channels. */
@@ -56,6 +56,10 @@ struct sdaemon
{
/* Global uuconf pointer. */
pointer puuconf;
+ /* Configuration file name argument (from -I option). */
+ const char *zconfig;
+ /* How often to spawn uuxqt (from uuconf_runuuxqt). */
+ int irunuuxqt;
/* Remote system information. */
const struct uuconf_system *qsys;
/* Local name being used. */
@@ -64,6 +68,8 @@ struct sdaemon
struct sconnection *qconn;
/* Protocol being used. */
const struct sprotocol *qproto;
+ /* Number of channels being used. */
+ int cchans;
/* The largest file size permitted for a local request. */
long clocal_size;
/* The largest file size permitted for a remote request. */
@@ -72,6 +78,13 @@ struct sdaemon
long cmax_ever;
/* The remote system ulimit. */
long cmax_receive;
+ /* Number of bytes sent. */
+ long csent;
+ /* Number of bytes received. */
+ long creceived;
+ /* Number of execution files received since the last time we spawned
+ uuxqt. */
+ long cxfiles_received;
/* Features supported by the remote side. */
int ifeatures;
/* TRUE if we should request the remote side to hang up. */
@@ -266,3 +279,10 @@ extern void usent_receive_ack P((struct sdaemon *qdaemon,
lost. */
extern void uwindow_acked P((struct sdaemon *qdaemon,
boolean fallacked));
+
+/* Spawn a uuxqt process. The ffork argument is passed to
+ fsysdep_run. If the zsys argument is not NULL, then -s zsys is
+ passed to uuxqt. The zconfig argument is the name of the
+ configuration file, from the -I option. */
+extern boolean fspawn_uuxqt P((boolean ffork, const char *zsys,
+ const char *zconfig));
diff --git a/gnu/libexec/uucp/common_sources/util.c b/gnu/libexec/uucp/common_sources/util.c
index 89b3caf1d446..2534665a4d1e 100644
--- a/gnu/libexec/uucp/common_sources/util.c
+++ b/gnu/libexec/uucp/common_sources/util.c
@@ -1,7 +1,7 @@
/* util.c
A couple of UUCP utility functions.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char util_rcsid[] = "$Id: util.c,v 1.1 1993/08/05 18:22:48 conklin Exp $";
+const char util_rcsid[] = "$Id: util.c,v 1.2 1994/05/07 18:09:07 ache Exp $";
#endif
#include <ctype.h>
@@ -95,6 +95,46 @@ funknown_system (puuconf, zsystem, qsys)
return TRUE;
}
+/* Remove all occurrences of the local system name followed by an
+ exclamation point from the front of a string, returning the new
+ string. This is used by uucp and uux. */
+
+char *
+zremove_local_sys (qlocalsys, z)
+ struct uuconf_system *qlocalsys;
+ char *z;
+{
+ size_t clen;
+ char *zexclam;
+
+ clen = strlen (qlocalsys->uuconf_zname);
+ zexclam = strchr (z, '!');
+ while (zexclam != NULL)
+ {
+ if (z == zexclam
+ || (zexclam - z == clen
+ && strncmp (z, qlocalsys->uuconf_zname, clen) == 0))
+ ;
+ else if (qlocalsys->uuconf_pzalias == NULL)
+ break;
+ else
+ {
+ char **pzal;
+
+ for (pzal = qlocalsys->uuconf_pzalias; *pzal != NULL; pzal++)
+ if (strlen (*pzal) == zexclam - z
+ && strncmp (z, *pzal, (size_t) (zexclam - z)) == 0)
+ break;
+ if (*pzal == NULL)
+ break;
+ }
+ z = zexclam + 1;
+ zexclam = strchr (z, '!');
+ }
+
+ return z;
+}
+
/* See whether a file is in a directory list, and make sure the user
has appropriate access. */
@@ -118,7 +158,7 @@ fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser)
if (pz[0][0] == '!')
{
- zuse = zsysdep_local_file (*pz + 1, zpubdir);
+ zuse = zsysdep_local_file (*pz + 1, zpubdir, (boolean *) NULL);
if (zuse == NULL)
return FALSE;
@@ -128,7 +168,7 @@ fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser)
}
else
{
- zuse = zsysdep_local_file (*pz, zpubdir);
+ zuse = zsysdep_local_file (*pz, zpubdir, (boolean *) NULL);
if (zuse == NULL)
return FALSE;
diff --git a/gnu/libexec/uucp/common_sources/uuconf.h b/gnu/libexec/uucp/common_sources/uuconf.h
index 4bf6bccbf3f2..1710568d499a 100644
--- a/gnu/libexec/uucp/common_sources/uuconf.h
+++ b/gnu/libexec/uucp/common_sources/uuconf.h
@@ -1,7 +1,7 @@
/* uuconf.h
Header file for UUCP configuration routines.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -26,7 +26,7 @@
informative, and does not modify the License in any way).
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#ifndef UUCONF_H
@@ -348,7 +348,9 @@ enum uuconf_porttype
/* A TCP port. Not supported on all systems. */
UUCONF_PORTTYPE_TCP,
/* A TLI port. Not supported on all systems. */
- UUCONF_PORTTYPE_TLI
+ UUCONF_PORTTYPE_TLI,
+ /* A pipe port. Not supported on all systems. */
+ UUCONF_PORTTYPE_PIPE
};
/* Additional information for a stdin port (there is none). */
@@ -377,6 +379,8 @@ struct uuconf_modem_port
long uuconf_ihighbaud;
/* Non-zero if the port supports carrier detect. */
int uuconf_fcarrier;
+ /* Non-zero if the port supports hardware flow control. */
+ int uuconf_fhardflow;
/* A NULL terminated sequence of dialer/token pairs (element 0 is a
dialer name, element 1 is a token, etc.) May be NULL, in which
case qdialer should not be NULL. */
@@ -394,6 +398,10 @@ struct uuconf_direct_port
char *uuconf_zdevice;
/* The baud rate (speed). */
long uuconf_ibaud;
+ /* Non-zero if the port uses carrier detect. */
+ int uuconf_fcarrier;
+ /* Non-zero if the port supports hardware flow control. */
+ int uuconf_fhardflow;
};
/* Additional information for a TCP port. */
@@ -403,6 +411,9 @@ struct uuconf_tcp_port
/* The TCP port number to use. May be a name or a number. May be
NULL, in which case "uucp" is looked up using getservbyname. */
char *uuconf_zport;
+ /* A NULL terminated sequence of dialer/token pairs (element 0 is a
+ dialer name, element 1 is a token, etc.) May be NULL. */
+ char **uuconf_pzdialer;
};
/* Additional information for a TLI port. */
@@ -431,6 +442,14 @@ struct uuconf_tli_port
char *uuconf_zservaddr;
};
+/* Additional information for a pipe port. */
+
+struct uuconf_pipe_port
+{
+ /* The command and its arguments. */
+ char **uuconf_pzcmd;
+};
+
/* Information kept for a port. */
struct uuconf_port
@@ -460,6 +479,7 @@ struct uuconf_port
struct uuconf_direct_port uuconf_sdirect;
struct uuconf_tcp_port uuconf_stcp;
struct uuconf_tli_port uuconf_stli;
+ struct uuconf_pipe_port uuconf_spipe;
} uuconf_u;
};
@@ -545,6 +565,13 @@ struct uuconf_dialer
be b1 - b2. */
#define UUCONF_GRADE_CMP(b1, b2) (uuconf_grade_cmp ((b1), (b2)))
+/* uuconf_runuuxqt returns either a positive number (the number of
+ execution files to receive between uuxqt invocations) or one of
+ these constant values. */
+#define UUCONF_RUNUUXQT_NEVER (0)
+#define UUCONF_RUNUUXQT_ONCE (-1)
+#define UUCONF_RUNUUXQT_PERCALL (-2)
+
/* Most of the uuconf functions returns an error code. A value of
zero (UUCONF_SUCCESS) indicates success. */
@@ -849,15 +876,29 @@ extern int uuconf_debuglevel (void *uuconf_pglobal,
extern int uuconf_maxuuxqts (void *uuconf_pglobal,
int *uuconf_pcmaxuuxqt);
+/* Get the frequency with which to spawn a uuxqt process. This
+ returns an integer. A positive number is the number of execution
+ files that should be received between spawns. Other values are one
+ of the UUCONF_RUNUUXQT constants listed above. */
+extern int uuconf_runuuxqt (void *uuconf_pglobal,
+ int *uuconf_pirunuuxqt);
+
/* Check a login name and password. This checks the Taylor UUCP
password file (not /etc/passwd). It will work even if
- uuconf_taylor_init was not called. If the login name exists and
- the password is correct, this returns UUCONF_SUCCESS. If the login
- does not exist, or the password is wrong, this returns
- UUCONF_NOT_FOUND. Other errors are also possible. */
+ uuconf_taylor_init was not called. All comparisons are done via a
+ callback function. The first argument to the function will be zero
+ when comparing login names, non-zero when comparing passwords. The
+ second argument to the function will be the pinfo argument passed
+ to uuconf_callin. The third argument will be the login name or
+ password from the UUCP password file. The comparison function
+ should return non-zero for a match, or zero for a non-match. If
+ the login name is found and the password compares correctly,
+ uuconf_callin will return UUCONF_SUCCESS. If the login is not
+ found, or the password does not compare correctly, uuconf_callin
+ will return UUCONF_NOT_FOUND. Other errors are also possible. */
extern int uuconf_callin (void *uuconf_pglobal,
- const char *uuconf_zlogin,
- const char *uuconf_zpassword);
+ int (*uuconf_cmp) (int, void *, const char *),
+ void *uuconf_pinfo);
/* Get the callout login name and password for a system. This will
set both *pzlog and *pzpass to a string allocated by malloc, or to
@@ -922,6 +963,7 @@ extern int uuconf_statsfile ();
extern int uuconf_debugfile ();
extern int uuconf_debuglevel ();
extern int uuconf_maxuuxqts ();
+extern int uuconf_runuuxqt ();
extern int uuconf_callin ();
extern int uuconf_callout ();
extern int uuconf_remote_unknown ();
diff --git a/gnu/libexec/uucp/common_sources/uucp.h b/gnu/libexec/uucp/common_sources/uucp.h
index 8df3ec4c3e79..5faa63c120b6 100644
--- a/gnu/libexec/uucp/common_sources/uucp.h
+++ b/gnu/libexec/uucp/common_sources/uucp.h
@@ -1,7 +1,7 @@
/* uucp.h
Header file for the UUCP package.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,11 +20,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* Get the system configuration parameters. */
-#include "conf.h"
+#include "config.h"
#include "policy.h"
/* Get a definition for ANSI_C if we weren't given one. */
@@ -41,11 +41,11 @@
/* We always include some standard header files. We need <signal.h>
to define sig_atomic_t. */
+#include <stdio.h>
+#include <signal.h>
#if HAVE_STDDEF_H
#include <stddef.h>
#endif
-#include <stdio.h>
-#include <signal.h>
/* On some systems we need <sys/types.h> to get sig_atomic_t or
size_t or time_t. */
@@ -103,21 +103,24 @@ typedef long time_t;
constpointer -- for a generic pointer to constant data.
BUCHAR -- to convert a character to unsigned. */
#if ANSI_C
-#if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR
- #error ANSI C compiler without void or unsigned char
+#if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR || ! HAVE_PROTOTYPES
+ #error ANSI C compiler without void or unsigned char or prototypes
#endif
#define P(x) x
typedef void *pointer;
typedef const void *constpointer;
#define BUCHAR(b) ((unsigned char) (b))
#else /* ! ANSI_C */
-/* Handle uses of const, volatile and void in Classic C. */
-#define const
+/* Handle uses of volatile and void in Classic C. */
#define volatile
#if ! HAVE_VOID
#define void int
#endif
+#if HAVE_PROTOTYPES
+#define P(x) x
+#else
#define P(x) ()
+#endif
typedef char *pointer;
typedef const char *constpointer;
#if HAVE_UNSIGNED_CHAR
@@ -169,6 +172,7 @@ extern pointer memcpy (), memchr ();
#else /* ! HAVE_STDLIB_H */
extern pointer malloc (), realloc (), bsearch ();
extern long strtol ();
+extern unsigned long strtoul ();
extern char *getenv ();
#endif /* ! HAVE_STDLIB_H */
@@ -225,6 +229,11 @@ typedef FILE *openfile_t;
#define ffileseek(e, i) (fseek ((e), (long) (i), 0) == 0)
#define ffilerewind(e) (fseek ((e), (long) 0, 0) == 0)
#endif
+#ifdef SEEK_END
+#define ffileseekend(e) (fseek ((e), (long) 0, SEEK_END) == 0)
+#else
+#define ffileseekend(e) (fseek ((e), (long) 0, 2) == 0)
+#endif
#define ffileclose(e) (fclose (e) == 0)
#else /* ! USE_STDIO */
@@ -247,6 +256,11 @@ typedef int openfile_t;
#define ffileseek(e, i) (lseek ((e), (long) i, 0) >= 0)
#define ffilerewind(e) (lseek ((e), (long) 0, 0) >= 0)
#endif
+#ifdef SEEK_END
+#define ffileseekend(e) (lseek ((e), (long) 0, SEEK_END) >= 0)
+#else
+#define ffileseekend(e) (lseek ((e), (long) 0, 2) >= 0)
+#endif
#define ffileclose(e) (close (e) >= 0)
#endif /* ! USE_STDIO */
@@ -359,6 +373,11 @@ extern char *strrchr P((const char *z, int b));
extern long strtol P((const char *, char **, int));
#endif
+/* Turn a string into a long unsigned integer. */
+#if ! HAVE_STRTOUL
+extern unsigned long strtoul P((const char *, char **, int));
+#endif
+
/* Lookup a key in a sorted array. */
#if ! HAVE_BSEARCH
extern pointer bsearch P((constpointer pkey, constpointer parray,
diff --git a/gnu/libexec/uucp/common_sources/uudefs.h b/gnu/libexec/uucp/common_sources/uudefs.h
index 47d2c89896ef..f957ee636c16 100644
--- a/gnu/libexec/uucp/common_sources/uudefs.h
+++ b/gnu/libexec/uucp/common_sources/uudefs.h
@@ -1,7 +1,7 @@
/* uudefs.h
Miscellaneous definitions for the UUCP package.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#if ANSI_C
@@ -106,8 +106,8 @@ struct scmd
simple execution, 'H' for hangup, 'Y' for hangup confirm, 'N' for
hangup deny). */
char bcmd;
- /* At least one compiler needs an explicit padding byte here. */
- char bdummy;
+ /* Grade of the command ('\0' if from remote system). */
+ char bgrade;
/* Sequence handle for fsysdep_did_work. */
pointer pseq;
/* File name to transfer from. */
@@ -237,6 +237,12 @@ extern boolean fspool_file P((const char *zfile));
extern boolean ftimespan_match P((const struct uuconf_timespan *qspan,
long *pival, int *pcretry));
+/* Remove all occurrences of the local system name followed by an
+ exclamation point from the start of the argument. Return the
+ possibly shortened argument. */
+extern char *zremove_local_sys P((struct uuconf_system *qlocalsys,
+ char *z));
+
/* Determine the maximum size that may ever be transferred, given a
timesize span. If there are any time gaps larger than 1 hour not
described by the timesize span, this returns -1. Otherwise it
@@ -375,9 +381,8 @@ extern void xfree P((pointer));
/* Global variables. */
-/* The name of the program being run. This is statically initialized,
- although it should perhaps be set from argv[0]. */
-extern char abProgram[];
+/* The name of the program being run. Set from argv[0]. */
+extern const char *zProgram;
/* When a signal occurs, the signal handlers sets the appropriate
element of the arrays afSignal and afLog_signal to TRUE. The
@@ -427,12 +432,6 @@ extern boolean fLog_sighup;
(afSignal[INDEXSIG_SIGHUP] || afSignal[INDEXSIG_SIGQUIT] \
|| afSignal[INDEXSIG_SIGTERM] || afSignal[INDEXSIG_SIGPIPE])
-/* File being sent. */
-extern openfile_t eSendfile;
-
-/* File being received. */
-extern openfile_t eRecfile;
-
/* Device name to log. This is set by fconn_open. It may be NULL. */
extern char *zLdevice;
diff --git a/gnu/libexec/uucp/contrib/Makefile.uurt b/gnu/libexec/uucp/contrib/Makefile.uurt
index 235fcca889f8..39922d5cb319 100644
--- a/gnu/libexec/uucp/contrib/Makefile.uurt
+++ b/gnu/libexec/uucp/contrib/Makefile.uurt
@@ -1,30 +1,40 @@
+# $Id: Makefile.uurt,v 1.2 1994/05/07 18:09:19 ache Exp $
+# Makefile for uurate 1.10
#
-# Makefile for uurate 1.0
-#
+
+# Prefix directory for installation directories.
+prefix = /usr/local
+
+# Directory where the needed .h files are installed (uucp.h ...).
+uucpsrcs = ../
# Where uurate is installed
-BIN=/usr/local/bin
+BIN=$(prefix)/bin
+# Where uurate's man is installed
+MAN=$(prefix)/man/man1
+
+# The directory to look in for Taylor style configuration files
+newconfigdir = $(prefix)/conf/uucp
# Flags to use when compiling uurate
-CFLAGS=-I..
+CC=gcc -O2
+CFLAGS=-I.. -Wall
+LDFLAGS=-s
-CC=cc
SHELL=/bin/sh
PROGS=uurate
#-----------
+MORECFLAGS= -I. -I$(uucpsrcs) -DNEWCONFIGLIB=\"$(newconfigdir)\"
all: $(PROGS)
+uurate: uurate.c
+ $(CC) $(CFLAGS) $(MORECFLAGS) $@.c -o $@ $(LDFLAGS)
+
install: $(PROGS)
- @for i in $(PROGS) ; do \
- echo "Install $$i into $(BIN)..." ; \
- cp $$i $(BIN) ; \
- echo "Set ownership and protection..." ; \
- /bin/chmod 0555 $(BIN)/$$i ; \
- /bin/chown bin $(BIN)/$$i ; \
- /bin/chgrp bin $(BIN)/$$i ; \
- done
+ cp $(PROGS) $(BIN)
+ cp uurate.man $(MAN)/uurate.1
clean:
rm -f $(PROGS) core
diff --git a/gnu/libexec/uucp/contrib/README b/gnu/libexec/uucp/contrib/README
index c4105ed03868..8e4651a9bbd2 100644
--- a/gnu/libexec/uucp/contrib/README
+++ b/gnu/libexec/uucp/contrib/README
@@ -3,6 +3,11 @@ This is the README file for the Taylor UUCP contrib directory.
This directory contains contributed shell scripts and programs that
you may find useful.
+Not actually included here, but nonetheless useful, is the TUA program
+distributed by Lele Gaifax <lele@nautilus.sublink.org>. It can do
+various sorts of analysis of any type of UUCP log file. It should be
+available from most FTP sites.
+
xchat.c, xchat.man, README-XCHAT, xc-conf.h-dist, Makefile.xchat:
A program by Bob Denny that may be invoked by the ``chat-program''
command for any of the various types of chat scripts. It is
@@ -13,9 +18,16 @@ xchat.c, xchat.man, README-XCHAT, xc-conf.h-dist, Makefile.xchat:
Dial.Hayes, Hangup.Hayes, Login.LAT, Login.PortSel, Login.VMS:
Sample scripts for xchat.
+uucomp.shar
+ A set of programs which automatically compresses outgoing data in
+ the spool directory. The remote system must cooperate when using
+ this. It can cut down on phone usage when applicable.
+ Contributed by Ed Carp.
+
uurate.c, uurate.man, README-UURATE, Makefile.uurt:
A nifty little program by Bob Denny which analyzes the Log and
- Stats file and prints various sorts of reports.
+ Stats file and prints various sorts of reports. This version was
+ tweaked by Stephan Niemz and Klaus Dahlenburg.
uutraf:
Another program to produce neat reports from your log files, this
@@ -28,9 +40,10 @@ savelog.sh, savelog.man:
is originally from smail. It was written by Ronald S. Karr and
Landon Curt Noll, and was given to me by Bob Denny.
-uureroute:
- A perl script reroute all mail queued up for one host to another.
- Written by Bill Campbell and contributed by Francois Pinard.
+uureroute.perl:
+ A perl script to reroute all mail queued up for one host to
+ another. Written by Bill Campbell and contributed by Francois
+ Pinard.
stats.sh:
A gawk script by Zacharias Beckman which reads the Stats file and
@@ -39,6 +52,29 @@ stats.sh:
uuq.sh:
A uuq workalike shell script by Zacharias Beckman.
+uupoll.shar:
+ uupoll and autopoll programs contributed by Klaus Dahlenburg.
+ uupoll can be used to automatically poll all systems, or a list of
+ systems; autopoll will poll and then retry failed calls.
+
+uudemon.shar:
+ An implementation of the HDB uudemon.poll script by Donald Burr.
+
+uuxconv:
+ A program by Richard E. Nickle to help convert SPOOLDIR_HDB spool
+ directories to SPOOLDIR_TAYLOR spool directories (note that it is
+ not necessary to convert your spool directories at all; the
+ SPOOLDIR_TAYLOR approach may be slightly more efficient).
+
+dialHDB.c:
+ A program by Daniel Hagerty which permits using HDB dialer
+ programs as chat programs.
+
+amiga.c:
+ A wrapper program to run uucico from a cron table under Amiga
+ SVR4 (apparently a wrapper is required). This was contributed by
+ Lawrence E. Rosenman.
+
tstout.c:
A program to remove a user from utmp and wtmp, essentially logging
them out. I put this together from BSD code. I need it to use
diff --git a/gnu/libexec/uucp/contrib/README-UURATE b/gnu/libexec/uucp/contrib/README-UURATE
index 2cc361ce26fb..0ef637514a5b 100644
--- a/gnu/libexec/uucp/contrib/README-UURATE
+++ b/gnu/libexec/uucp/contrib/README-UURATE
@@ -1,20 +1,21 @@
-uurate V1.2 - Gather and display Taylor UUCP traffic statistics
+uurate V1.10 - Gather and display Taylor UUCP traffic statistics
-Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992
+Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992 (V1.2.1)
+Klaus Dahlenburg (kdburg@incoahe.hanse.de) - Tue Sep 28 18:11:34 CET 1993
See the man page for documentation.
Installation:
------------
-(1) Copy Makefile.uurt to Makefile.
+(1) Copy or sym-link Makefile.uurt to Makefile.
-(2) Edit Makefile: set BIN where you want uurate to be installed, and
- set CFLAGS to point to the directory containing the UUCP sources
- (this is .. by default).
+(2) Edit Makefile: set BIN where you want uurate to be installed,
+ MAN where the man page should go to, and set CFLAGS to point
+ to the directory containing the UUCP sources (this is .. by
+ default). Don't forget to set newconfigdir= to point to the
+ directory where the (Taylor-uucp)config is stored.
(3) Type ``make'' to compile the program.
(4) Type ``make install'' to install the program.
-
-(5) Install the man page if you want. I didn't put that into the Makefile.
diff --git a/gnu/libexec/uucp/contrib/amiga.c b/gnu/libexec/uucp/contrib/amiga.c
new file mode 100644
index 000000000000..d982364cfd57
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/amiga.c
@@ -0,0 +1,43 @@
+/* Wrapper code for Taylor UUCP on Amiga Unix (SVR4) for cron invoked UUCP */
+/* processes. */
+
+/* The problem: Cron is not a "licensed" process. any process that grabs a
+ controlling terminal needs to be licensed. Taylor UUCP needs controlling
+ terminals. Taylor UUCP does relinquish the controlling terminal before
+ fork(), so the "UUCP" license is appropriate.
+ This simple program does the "right" thing, but *MUST* be SETUID ROOT */
+
+/* Written by: Lawrence E. Rosenman <ler@lerami.lerctr.org> */
+
+#include <sys/sysm68k.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pwd.h>
+
+int main(int argc,char *argv[],char *envp)
+{
+ struct passwd *pw;
+ char name[256];
+
+ strcpy(name,"/usr/local/lib/uucp/uucico");
+ if (sysm68k(_m68k_LIMUSER,EUA_GET_LIC) == 0 ) { /* are we unlicensed? */
+ if (sysm68k(_m68k_LIMUSER,EUA_UUCP) == -1) { /* yes, get a "uucp" license */
+ fprintf(stderr,"sysm68k failed, errno=%d\n",errno); /* we didn't? crab it */
+ exit(errno);
+ }
+ }
+
+ pw = getpwnam("uucp"); /* get the Password Entry for uucp */
+ if (pw == NULL)
+ {
+ fprintf(stderr,"User ID \"uucp\" doesn't exist.\n");
+ exit(1);
+ }
+ setgid(pw->pw_gid); /* set gid to uucp */
+ setuid(pw->pw_uid); /* set uid to uucp */
+ argv[0]=name; /* have PS not lie... */
+ execv("/usr/local/lib/uucp/uucico",argv); /* go to the real program */
+ exit(errno);
+}
diff --git a/gnu/libexec/uucp/contrib/dialHDB.c b/gnu/libexec/uucp/contrib/dialHDB.c
new file mode 100644
index 000000000000..cb2662134af6
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/dialHDB.c
@@ -0,0 +1,187 @@
+/*
+# File: dialHDB.c
+# Author: Daniel Hagerty , hag@eddie.mit.edu
+# Copyright (C) 1993
+# Date: Fri Nov 26 19:22:31 1993
+# Description: Program for using HDB dialers for dialing modems, exiting
+ with 0 on success, else failure.
+# Version: 1.0
+# Revision History:
+######
+### 11/26/93 Hag - File creation
+######
+### 1/5/94 Hag - Finally got around to finishing this damn thing.
+######
+*/
+/* Basic theory behind this program-
+ dialHDB forks into two processes, a monitor parent, and a child
+ that does the exec of the dialer. Child pretty much just execs the
+ dialer program, unless there's an exec problem, in which case the
+ child sends the parent a SIGUSR1 to indicate failed execution.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define kUsage "Usage:\n\t%s dialerPath device number speed\n\
+%s dialer -h device speed\n"
+
+#define kExitErrFlag 0x80 /* & in with exit code to determine error */
+#define kErrorMask 0x0f /* Mask to determine error code */
+
+/* Error code defines as lifted from an HDB dialer */
+#define RCE_NULL 0 /* general purpose or unknown error code */
+#define RCE_INUSE 1 /* line in use */
+#define RCE_SIG 2 /* signal aborted dialer */
+#define RCE_ARGS 3 /* invalid arguments */
+#define RCE_PHNO 4 /* invalid phone number */
+#define RCE_SPEED 5 /* invalid baud rate -or- bad connect baud */
+#define RCE_OPEN 6 /* can't open line */
+#define RCE_IOCTL 7 /* ioctl error */
+#define RCE_TIMOUT 8 /* timeout */
+#define RCE_NOTONE 9 /* no dial tone */
+#define RCE_BUSY 13 /* phone is busy */
+#define RCE_NOCARR 14 /* no carrier */
+#define RCE_ANSWER 15 /* no answer */
+
+/* Structure definition to map error codes to strings */
+typedef struct
+{
+ int errNum;
+ char *errString;
+} errTable;
+
+const errTable errors[]=
+{
+ { RCE_NULL, "Unknown Error" },
+ { RCE_INUSE, "Line is being used" },
+ { RCE_SIG, "Recieved fatal signal" },
+ { RCE_ARGS, "Bad arguments" },
+ { RCE_PHNO, "Invalid phone number" },
+ { RCE_SPEED, "Invalid baud rate or bad connection" },
+ { RCE_OPEN, "Unable to open line" },
+ { RCE_IOCTL, "ioctl error" },
+ { RCE_TIMOUT, "Timed out" },
+ { RCE_NOTONE, "No dialtone" },
+ { RCE_BUSY, "Phone number is busy" },
+ { RCE_NOCARR, "No carrier" },
+ { RCE_ANSWER, "No answer" },
+ { 0,NULL}
+};
+
+/* Function Prototypes */
+int figureStat(int stat);
+char *findInTable(int error);
+void badExec(void);
+
+char *dialerName; /* basename of our dialer program */
+char *dialerPath; /* full path of dialer program */
+
+main(int argc,char *argv[])
+{
+ int parent; /* pid of parent process */
+ int child; /* pid of child process */
+ int stat; /* exit status of child process */
+ char *temp; /* used to get basename of dialer */
+
+ if(argc!=5)
+ {
+ fprintf(stderr,kUsage,argv[0],argv[0]);
+ exit(1);
+ }
+
+ dialerPath=argv[1];
+ dialerName= (temp=strrchr(argv[1],'/'))!=NULL ? temp+1 : argv[1];
+
+ parent=getpid();
+
+ signal(SIGUSR1,badExec); /* set up for possible failed exec */
+
+ if((child=fork())<0)
+ {
+ perror("fork");
+ exit(2);
+ }
+ if(child>0) /* We're parent, wait for child to exit */
+ {
+ /* Set up to ignore signals so we can report them on stderror */
+ signal(SIGHUP,SIG_IGN);
+ signal(SIGINT,SIG_IGN);
+ signal(SIGTERM,SIG_IGN);
+
+ wait(&stat); /* wait for child to exit */
+ exit(figureStat(stat)); /* figure out our exit code and die */
+ }
+ else /* child process */
+ {
+ close(0); /* close of modem file desc, since HDB */
+ close(1); /* doesn't use them */
+ dup2(2,1); /* and remap stdout to stderr, just in case */
+ if(execvp(argv[1],argv+1)<0) /* exec program with argv shifted by 1 */
+ { /* if exec fails, send SIGUSR1 to parent */
+ kill(parent,SIGUSR1);
+ exit(0);
+ }
+ }
+ exit(0);
+}
+
+/* Figure out whether or not dialer ran succesfully, and return
+with 0 if it worked, otherwise error */
+int figureStat(int stat)
+{
+ int exit;
+ int errFlag;
+ int error;
+
+ if(WIFSIGNALED(stat)) /* determine if exit was from signal or what */
+ {
+ fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
+ WTERMSIG(stat));
+ return(1);
+ }
+ if(WIFSTOPPED(stat))
+ {
+ fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
+ WSTOPSIG(stat));
+ return(1);
+ }
+ exit=WEXITSTATUS(stat);
+
+ errFlag=exit&kExitErrFlag; /* Is the error flag set? */
+ if(errFlag)
+ {
+ char *errString;
+
+ error=exit&kErrorMask;
+ errString=findInTable(error); /* find it's string, print it on stderr */
+ fprintf(stderr,"Error: %s - %s.\n",dialerName,errString); /* and return */
+ return(1);
+ }
+ return(0);
+}
+
+/* Support routine, look up exit code in error table, and return pointer
+to proper string */
+char *findInTable(int error)
+{
+ int i=0;
+
+ for(i=0;errors[i].errString!=NULL;i++)
+ {
+ if(errors[i].errNum==error)
+ return(errors[i].errString);
+ }
+ /* Still here, return the top entry, for unknown error */
+ return(errors[0].errString);
+}
+
+/* Called by signal if we recieve SIGUSR 1 */
+void badExec(void)
+{
+ fprintf(stderr,"Error: %s - Execution problem.\n",dialerPath);
+ exit(1);
+}
diff --git a/gnu/libexec/uucp/contrib/uucomp.shar b/gnu/libexec/uucp/contrib/uucomp.shar
new file mode 100644
index 000000000000..da131d048c5e
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uucomp.shar
@@ -0,0 +1,552 @@
+#! /bin/sh
+#
+# Created by shar, version 0.5 - 04/10/91
+#
+# This is a shell archive, meaning:
+# 1. Remove everything about the #! /bin/sh line.
+# 2. Save the resulting text in a file.
+# 3. Execute the file with /bin/sh to create:
+#
+# length name
+# ------ -------------------------------------
+# 128 uucomp-1.1/Compress
+# 264 uucomp-1.1/Copyright
+# 410 uucomp-1.1/INTERNALS
+# 1069 uucomp-1.1/Makefile
+# 3528 uucomp-1.1/README
+# 632 uucomp-1.1/crmail.c
+# 632 uucomp-1.1/crnews.c
+# 108 uucomp-1.1/tags
+# 3506 uucomp-1.1/uucomp.c
+# 383 uucomp-1.1/uucomp.h
+#
+
+if test ! -d uucomp-1.1 ; then
+ mkdir uucomp-1.1
+fi
+#
+# Archive number 1
+# This archive created Tue Sep 28 20:21:14 1993
+#
+
+echo "shar: extracting uucomp-1.1/Compress - (128 characters)"
+if test -f 'uucomp-1.1/Compress' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Compress
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Compress'
+Xfor i in $*
+Xdo
+X if [ -d /usr/spool/uucp/$i ]
+X then
+X# echo Looking at $i
+X cd /usr/spool/uucp/$i
+X /usr/bin/uucomp C.*
+X fi
+Xdone
+SHAR_EOF
+if test 128 -ne "`wc -c < 'uucomp-1.1/Compress'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Compress (should have been 128 characters, but was "`wc -c < 'uucomp-1.1/Compress'`" characters) *****"
+fi
+fi
+
+touch 0715110393 uucomp-1.1/Compress
+chmod 0700 uucomp-1.1/Compress
+
+echo "shar: extracting uucomp-1.1/Copyright - (264 characters)"
+if test -f 'uucomp-1.1/Copyright' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Copyright
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Copyright'
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+SHAR_EOF
+if test 264 -ne "`wc -c < 'uucomp-1.1/Copyright'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Copyright (should have been 264 characters, but was "`wc -c < 'uucomp-1.1/Copyright'`" characters) *****"
+fi
+fi
+
+touch 0715174993 uucomp-1.1/Copyright
+chmod 0600 uucomp-1.1/Copyright
+
+echo "shar: extracting uucomp-1.1/INTERNALS - (410 characters)"
+if test -f 'uucomp-1.1/INTERNALS' ; then
+ echo shar: will not over-write existing file uucomp-1.1/INTERNALS
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/INTERNALS'
+XThis is the basic workflow for uucomp:
+X
+Xfor (every argv)
+Xdo
+X if not "C." file skip
+X if open fail, skip
+X read 1 line from C. file
+X grab second and 10th field (second is data file name,
+X 10th is command name)
+X if open fail on second field, skip
+X if 10th field isn't "rmail" or "rnews", skip
+X execute "gzip -9" on second field
+X change "rmail" and "rnews" to "crmail" and "crnews", respectively
+X in C. file
+Xdone
+SHAR_EOF
+if test 410 -ne "`wc -c < 'uucomp-1.1/INTERNALS'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/INTERNALS (should have been 410 characters, but was "`wc -c < 'uucomp-1.1/INTERNALS'`" characters) *****"
+fi
+fi
+
+touch 0715174693 uucomp-1.1/INTERNALS
+chmod 0600 uucomp-1.1/INTERNALS
+
+echo "shar: extracting uucomp-1.1/Makefile - (1069 characters)"
+if test -f 'uucomp-1.1/Makefile' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Makefile
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Makefile'
+X#
+X# Makefile generated with genmake - version 1.1 08/22/92
+X#
+X# genmake is Copyright 1991 by Edwin R. Carp
+X#
+X# GENMAKE -B/usr/bin -tsp [files]
+X#
+X
+XCC = gcc -O6
+XCFLAGS = $(INCLUDE)
+XSOURCES = crmail.c crnews.c uucomp.c
+XOBJECTS = crmail.o crnews.o uucomp.o
+XPROGRAMS = /usr/bin/crmail /usr/bin/crnews /usr/bin/uucomp
+X
+Xall: $(PROGRAMS) tags
+X
+X/usr/bin/crmail: crmail.o
+X $(CC) $(CFLAGS) -o crmail crmail.o $(LDFLAGS) -O
+X strip crmail
+X chmod 755 crmail
+X mv crmail /usr/bin
+X
+X/usr/bin/crnews: crnews.o
+X $(CC) $(CFLAGS) -o crnews crnews.o $(LDFLAGS) -O
+X strip crnews
+X chmod 755 crnews
+X mv crnews /usr/bin
+X
+X/usr/bin/uucomp: uucomp.o
+X $(CC) $(CFLAGS) -o uucomp uucomp.o $(LDFLAGS) -O
+X strip uucomp
+X chmod 755 uucomp
+X mv uucomp /usr/bin
+X
+Xclean:
+X /bin/rm -f $(OBJECTS) MAKELOG eddep makedep
+X
+Xclobber:
+X /bin/rm -f $(OBJECTS) $(PROGRAMS) MAKELOG eddep makedep *~ *.bak *.BAK
+X /bin/rm -f tags
+X
+Xhidden:
+X echo "make all > MAKELOG 2>&1 &"|/bin/sh
+X
+Xmakefile:
+X genmake -B/usr/bin -tsp $(SOURCES) &
+X
+Xmakeall:
+X genmake -B/usr/bin -tsp *.c &
+X
+Xtags: $(SOURCES)
+X ctags $(SOURCES) > tags
+X
+SHAR_EOF
+if test 1069 -ne "`wc -c < 'uucomp-1.1/Makefile'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Makefile (should have been 1069 characters, but was "`wc -c < 'uucomp-1.1/Makefile'`" characters) *****"
+fi
+fi
+
+touch 0714235093 uucomp-1.1/Makefile
+chmod 0600 uucomp-1.1/Makefile
+
+echo "shar: extracting uucomp-1.1/README - (3528 characters)"
+if test -f 'uucomp-1.1/README' ; then
+ echo shar: will not over-write existing file uucomp-1.1/README
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/README'
+XLike most people these days, I'm looking for ways to make my computing
+Xenvironment more efficient. This environment consists of a 486, a 386,
+Xand a 386SL laptop, all of which run Taylor uucp under Linux. The 386
+Xlaptop gets used a lot, since it goes wherever I go and I answer a lot
+Xof news and email every day. Often, I must use other people's facilities
+X(phone lines and such) to send out replies and post news if I'm not at home.
+XSince it's not fair to the client for them to pay for my zone calls back
+Xto my home in Fremont, I place the calls on my phone card. Unfortunately,
+XPacBell is very proud of the services they offer, especially in regards
+Xto this convenience of automatically charging calls to my house wherever I
+Xmay be. Considering that this can be very expensive to do, I searched for
+Xa way to cut my phone bill down to something I could afford to pay each
+Xmonth without fainting every time I saw the bill.
+X
+XThe first thing I did was to go out and plunk $195 for a 14.4KB modem.
+XThat helped, but C-News is very slow on my laptop, and batching articles
+Xis even slower, and email (of course) isn't batched at all. Even with
+XMNP5 compression turned on, this doesn't make for a very efficient setup,
+Xeven at high speeds.
+X
+XPlaying around with uucp told me that the line turnaround wasn't that much
+Xoverhead, nor was sending the C./X. files (the execute files) - the real
+Xoverhead was sending out uncompressed news and especially email, since
+XI subscribe to several mailing lists and digests can run quite large.
+X
+XI looked at uubatch, but the most current version I could find (1.05) was
+Xnot compatible with Taylor uucp (and I had no other alternative), so I
+Xdecided to write my own. Experiments with "gzip -9" convinced me that
+Xthat was the way to go, since gzip gives email and news 60 to 75 percent
+Xcompression, which would tend to cut one's phone bill significantly.
+X
+XYou hold in your mailbox (or news reader) the end result of that effort.
+XBear in mind that (1) this is a "first cut" and while it is unlikely that
+Xthere are very many bugs, there are certainly places where the programs could
+Xbe improved and tuned. Suggestions and comments are welcome!
+X
+XTo install:
+X
+X 1. Feed this to shar.
+X 2. Look at the Makefile. Make sure that the paths for
+X things are set up correctly.
+X 3. Look at uucomp.h and make sure that the path and
+X options for COMPRESS/UNCOMPRESS are set up properly.
+X 3. Type "make". This will make uucomp, crmail, and crnews
+X and will place them in /usr/bin. Move Compress into
+X /usr/lib/uucp.
+X 4. Make an entry in crontab to do
+X /usr/lib/uucp/Compress site1 site2 site3...
+X occasionally. It is suggested that this be done fairly
+X frequently. Alternately, you could set up a login shell
+X for selected sites to run uucomp every time that site
+X logged in.
+X 5. Don't forget to add /usr/bin/crmail and /usr/bin/crnews
+X to the list of programs allowed to be executed in your
+X Permissions file (if running HDB UUCP), or whatever is
+X appropriate for your version of uucp.
+X
+XEnjoy! Any questions or comments can be sent to erc@apple.com.
+X
+XNote: This is tuned for Taylor uucp, but would not be particularly
+Xdifficult to adapt to other version of uucp. See the file INTERNALS for
+Xdetails of how this works.
+X
+XJuly 15, 1993
+XEd Carp
+Xerc@apple.com
+X------------------------------------------------------------------------------
+XChanges since 1.0:
+X
+X Version Date Description
+X
+X 1.1 08/04/93 Added sanity check in C. file (check that
+X 'E' is first char in file, otherwise skip)
+SHAR_EOF
+if test 3528 -ne "`wc -c < 'uucomp-1.1/README'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/README (should have been 3528 characters, but was "`wc -c < 'uucomp-1.1/README'`" characters) *****"
+fi
+fi
+
+touch 0804224993 uucomp-1.1/README
+chmod 0600 uucomp-1.1/README
+
+echo "shar: extracting uucomp-1.1/crmail.c - (632 characters)"
+if test -f 'uucomp-1.1/crmail.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/crmail.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/crmail.c'
+X/*
+X * crmail - get compressed mail from host, uncompress
+X * WARNING: This may be insecure!
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X char cmd[1024];
+X int i;
+X
+X sprintf (cmd, "%s|%s ", UNCOMPRESS, RMAIL);
+X for (i = 1; i < argc; i++)
+X {
+X strcat (cmd, argv[i]);
+X strcat (cmd, " ");
+X }
+X system (cmd);
+X exit (0);
+X}
+SHAR_EOF
+if test 632 -ne "`wc -c < 'uucomp-1.1/crmail.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/crmail.c (should have been 632 characters, but was "`wc -c < 'uucomp-1.1/crmail.c'`" characters) *****"
+fi
+fi
+
+touch 0715195493 uucomp-1.1/crmail.c
+chmod 0600 uucomp-1.1/crmail.c
+
+echo "shar: extracting uucomp-1.1/crnews.c - (632 characters)"
+if test -f 'uucomp-1.1/crnews.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/crnews.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/crnews.c'
+X/*
+X * crnews - get compressed news from host, uncompress
+X * WARNING: This may be insecure!
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X char cmd[1024];
+X int i;
+X
+X sprintf (cmd, "%s|%s ", UNCOMPRESS, RNEWS);
+X for (i = 1; i < argc; i++)
+X {
+X strcat (cmd, argv[i]);
+X strcat (cmd, " ");
+X }
+X system (cmd);
+X exit (0);
+X}
+SHAR_EOF
+if test 632 -ne "`wc -c < 'uucomp-1.1/crnews.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/crnews.c (should have been 632 characters, but was "`wc -c < 'uucomp-1.1/crnews.c'`" characters) *****"
+fi
+fi
+
+touch 0715195593 uucomp-1.1/crnews.c
+chmod 0600 uucomp-1.1/crnews.c
+
+echo "shar: extracting uucomp-1.1/tags - (108 characters)"
+if test -f 'uucomp-1.1/tags' ; then
+ echo shar: will not over-write existing file uucomp-1.1/tags
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/tags'
+Xmain crmail.c /^main (argc, argv)$/
+Xmain crnews.c /^main (argc, argv)$/
+Xmain uucomp.c /^main (argc, argv)$/
+SHAR_EOF
+if test 108 -ne "`wc -c < 'uucomp-1.1/tags'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/tags (should have been 108 characters, but was "`wc -c < 'uucomp-1.1/tags'`" characters) *****"
+fi
+fi
+
+touch 0804224993 uucomp-1.1/tags
+chmod 0600 uucomp-1.1/tags
+
+echo "shar: extracting uucomp-1.1/uucomp.c - (3506 characters)"
+if test -f 'uucomp-1.1/uucomp.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/uucomp.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/uucomp.c'
+X/*
+X * uucomp - compress outgoing news/mail
+X *
+X * usage: uucomp C.*
+X *
+X * This works for Taylor uucp (available from prep.ai.mit.edu:/pub/gnu/uucp*),
+X * but I don't promise it works for anyone else's uucp package. Basically, this
+X * is a quick-n-dirty hack to get compressed mail and news to a uucp site. This
+X * becomes important when you're on the other end of a 1200 baud packet radio
+X * link, where the throughput can be 60 CPS (or lower). It also tends to hide
+X * any nasties that people might want to say to you, since the packets *are*
+X * public readable. Yes, I looked at uubatch, but it was too complicated for
+X * me to figure out <grin>, and it didn't work with Taylor-uucp. This is almost
+X * too simple to work...
+X *
+X * To use this little guy, do something like this in the .bashrc or .profile
+X * or .cshrc of the uucp's login shell:
+X *
+X * cd /usr/spool/uucp/<wherever the C. and D. files are kept>
+X * /usr/bin/uucomp C.*
+X * exec /usr/lib/uucp/uucico
+X *
+X * This program was written by Ed Carp (erc@apple.com). It can be used for any
+X * non-commercial purpose. This software is freely redistributable.
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+X#undef NULL
+X#define NULL (0)
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X int i, j, sw, ctr = 0, errflag = 0, mctr = 0, nctr = 0, skipctr = 0;
+X char scr[64], rcmd[10], line[1024], lineout[1024];
+X char *strtok (), *ptr, *lineptr, compfile[32];
+X FILE *in;
+X
+X printf ("uucomp 1.1 08/04/93 ... by erc@apple.com\nscanning %d files.", argc - 1);
+X for (i = 1; i < argc; i++)
+X {
+X if (strncmp (argv[i], "C.", 2) != 0)
+X {
+X skipctr++;
+X continue;
+X }
+X if ((in = fopen (argv[i], "r+")) == (FILE *) NULL)
+X {
+X skipctr++;
+X continue;
+X }
+X fgets (line, 1022, in);
+X if(*line != 'E')
+X {
+X skipctr++;
+X continue;
+X }
+X line[strlen (line) - 1] = NULL;
+X rewind (in);
+X *lineout = NULL;
+X lineptr = line;
+X sw = errflag = 0;
+X printf (".");
+X fflush (stdout);
+X for (j = 0;; j++)
+X {
+X ptr = strtok (lineptr, " ");
+X if (ptr == NULL)
+X break;
+X lineptr = NULL;
+X if (j == 1)
+X {
+X if (access (ptr, 4) == EOF)
+X {
+X#ifdef DEBUG
+X printf ("skip: file '%s' doesn't exist\n", ptr);
+X#endif
+X errflag = 1;
+X break; /*
+X * skip it if the data file isn't
+X * there yet
+X */
+X }
+X strcpy (compfile, ptr);
+X }
+X if (j == 9)
+X {
+X if (strcmp (ptr, "rmail") != 0 && strcmp (ptr, "rnews") != 0)
+X {
+X#ifdef DEBUG
+X printf ("skip: '%s' wrong command\n", ptr);
+X#endif
+X errflag = 1;
+X break;
+X }
+X if (strcmp (ptr, "rmail") == 0)
+X mctr++;
+X if (strcmp (ptr, "rnews") == 0)
+X nctr++;
+X sw = 1;
+X strcat (lineout, "c");
+X }
+X strcat (lineout, ptr);
+X strcat (lineout, " ");
+X }
+X if (errflag == 1)
+X {
+X skipctr++;
+X fclose (in);
+X continue;
+X }
+X fprintf (in, "%s\n", lineout);
+X fclose (in);
+X sprintf (line,
+X "%s -fc > /tmp/uucomp.%d < %s;cp /tmp/uucomp.%d %s",
+X COMPRESS, getpid (), compfile, getpid (), compfile);
+X system (line);
+X ctr++;
+X }
+X sprintf (line, "/tmp/uucomp.%d", getpid ());
+X unlink (line);
+X printf ("\n%d skipped, %d compressed (%d mail, %d news).\n",
+X skipctr, ctr, mctr, nctr);
+X exit (0);
+X}
+SHAR_EOF
+if test 3506 -ne "`wc -c < 'uucomp-1.1/uucomp.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/uucomp.c (should have been 3506 characters, but was "`wc -c < 'uucomp-1.1/uucomp.c'`" characters) *****"
+fi
+fi
+
+touch 0804224693 uucomp-1.1/uucomp.c
+chmod 0600 uucomp-1.1/uucomp.c
+
+echo "shar: extracting uucomp-1.1/uucomp.h - (383 characters)"
+if test -f 'uucomp-1.1/uucomp.h' ; then
+ echo shar: will not over-write existing file uucomp-1.1/uucomp.h
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/uucomp.h'
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#define COMPRESS "/usr/bin/gzip -9c"
+X#define UNCOMPRESS "/usr/bin/gzip -dc"
+X#define RMAIL "rmail"
+X#define RNEWS "rnews"
+SHAR_EOF
+if test 383 -ne "`wc -c < 'uucomp-1.1/uucomp.h'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/uucomp.h (should have been 383 characters, but was "`wc -c < 'uucomp-1.1/uucomp.h'`" characters) *****"
+fi
+fi
+
+touch 0715190293 uucomp-1.1/uucomp.h
+chmod 0600 uucomp-1.1/uucomp.h
+echo End of all shell archives
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uudemon.shar b/gnu/libexec/uucp/contrib/uudemon.shar
new file mode 100644
index 000000000000..31a8fa60707c
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uudemon.shar
@@ -0,0 +1,82 @@
+#! /bin/sh
+# This is a shell archive. Remove anything before this line, then unpack
+# it by saving it into a file and typing "sh file". To overwrite existing
+# files, type "sh file -c". You can also feed this as standard input via
+# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
+# will see the following message at the end:
+# "End of shell archive."
+# Contents: Poll uudemon.poll
+# Wrapped by dburr@sbanet on Fri Jul 23 20:15:18 1993
+PATH=/bin:/usr/bin:/usr/ucb ; export PATH
+if test -f 'Poll' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'Poll'\"
+else
+echo shar: Extracting \"'Poll'\" \(244 characters\)
+sed "s/^X//" >'Poll' <<'END_OF_FILE'
+X# HDB-ish poll file
+X#
+X# Format: <site><tab><hour1> <hour2> ...
+X# ONLY ONE TAB BETWEEN FIELDS... more may work, but I have absolutely no
+X# idea if it will work at all.
+X#
+X# comment lines (begin with `#') are ignored.
+X
+Xdschub 20 21 22
+Xgd 20 21 22
+END_OF_FILE
+if test 244 -ne `wc -c <'Poll'`; then
+ echo shar: \"'Poll'\" unpacked with wrong size!
+fi
+# end of 'Poll'
+fi
+if test -f 'uudemon.poll' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'uudemon.poll'\"
+else
+echo shar: Extracting \"'uudemon.poll'\" \(941 characters\)
+sed "s/^X//" >'uudemon.poll' <<'END_OF_FILE'
+X#!/bin/sh
+X#
+X# This is my impersonation of the HDB uudemon.poll script.
+X# Yes, I know, this is very clumsy and clunky... ahh well, I've always
+X# been better at C/pascal/etc than Shell programming... :(
+X
+X# change LIBDIR to where UUCP library/conf. files are
+X# change SPOOLDIR to the UUCP spool directory. It must be HDB-ish.
+XLIBDIR=/usr/lib/uucp; export LIBDIR
+XSPOOLDIR=/usr/spool/uucp; export SPOOLDIR
+X
+X### no changes needed past here ###
+X
+XHOUR=`date +%H`; export HOUR
+X
+Xif [ -f ${LIBDIR}/Poll ]; then
+X for SYS in `uuname`
+X do
+X CHOICES="`grep "^$SYS[ ]" ${LIBDIR}/Poll | awk -F' ' \
+X '{ print $2 }'`"
+X DOIT="no"
+X for H in $CHOICES
+X do
+X if [ "$HOUR" = "$H" ]; then
+X DOIT="yes"
+X fi
+X done
+X if [ "$DOIT" = "yes" ]; then
+X if [ ! -d ${SPOOLDIR}/${SYS} ]; then
+X mkdir ${SPOOLDIR}/${SYS}
+X fi
+X chmod 755 ${SPOOLDIR}/${SYS}
+X touch ${SPOOLDIR}/${SYS}/C.${SYS}n0000
+X chmod 644 ${SPOOLDIR}/${SYS}/C.${SYS}n0000
+X fi
+X done
+Xfi
+END_OF_FILE
+if test 941 -ne `wc -c <'uudemon.poll'`; then
+ echo shar: \"'uudemon.poll'\" unpacked with wrong size!
+fi
+chmod +x 'uudemon.poll'
+# end of 'uudemon.poll'
+fi
+echo shar: End of shell archive.
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uupoll.shar b/gnu/libexec/uucp/contrib/uupoll.shar
new file mode 100644
index 000000000000..49cdb1b33318
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uupoll.shar
@@ -0,0 +1,2696 @@
+#!/bin/sh
+# This is a shell archive (produced by shar 3.49)
+# To extract the files from this archive, save it to a file, remove
+# everything above the "!/bin/sh" line above, and type "sh file_name".
+#
+# made 04/17/1994 02:21 UTC by ian@comton.airs.com
+# Source directory /disk4/ian
+#
+# existing files will NOT be overwritten unless -c is specified
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 2602 -r--r--r-- uupoll/Makefile
+# 3636 -r--r--r-- uupoll/README
+# 4718 -r--r--r-- uupoll/autopoll.8c
+# 44031 -r--r--r-- uupoll/autopoll.c
+# 3884 -r--r--r-- uupoll/conf.h
+# 4787 -r--r--r-- uupoll/uupoll.8c
+# 27587 -r--r--r-- uupoll/uupoll.c
+#
+# ============= uupoll/Makefile ==============
+if test ! -d 'uupoll'; then
+ echo 'x - creating directory uupoll'
+ mkdir 'uupoll'
+fi
+if test -f 'uupoll/Makefile' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/Makefile (File already exists)'
+else
+echo 'x - extracting uupoll/Makefile (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/Makefile' &&
+# This is the Makefile for uupoll and autopoll
+# borrowed and hacked from Taylor UUCP 1.04
+X
+# Prefix directory for installation directories.
+prefix = /usr/local
+X
+# The user name/group that should own the resulting executables.
+# Both should run suid.
+owner = uucp.daemon
+X
+# Which mode should the resulting executables have.
+emode = 4111
+X
+# Where to install autopoll. This definition requires $(prefix)/lib to exist.
+lbindir = $(prefix)/lib/uucp
+X
+# Where are the sources from uucp-Taylor uucp.h, uuconf.h, policy.h.
+# the following assumes that our sources are in uucp-1.05/contrib/uupoll
+# and the required .h files are in main directory for uucp-1.05
+uucpsrcs = ../../
+X
+# Where to install uupoll
+bbindir = $(prefix)/bin
+X
+# Where to install man pages. Section 8 for daemons.
+man8dir = $(prefix)/man/man8
+man8ext = .8c
+X
+# Define programs and flags
+CC = gcc
+CFLAGS = -O2
+LDFLAGS = -s
+LIBS =
+X
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL) -m 644
+X
+#
+# Nothing else to configure
+#
+X
+SHELL = /bin/sh
+X
+VERSION = 1.00
+X
+MORECFLAGS = -I. -I$(uucpsrcs) -Wall
+X
+PROGRAMS = uupoll autopoll
+X
+UUPOLLOBJS = uupoll.o
+AUTOOBJS = autopoll.o
+X
+ALLOBJS = uupoll.o autopoll.o
+X
+all: $(PROGRAMS)
+X
+install: $(PROGRAMS)
+X if test -d $(lbindir); then true; else mkdir $(lbindir); fi
+X if test -d $(bbindir); then true; else mkdir $(bbindir); fi
+X -if test -f $(lbindir)/autopoll.old; then rm -f $(lbindir)/autopoll; else mv $(lbindir)/autopoll $(lbindir)/autopoll.old; fi
+X -if test -f $(bbindir)/uupoll.old; then rm -f $(bbindir)/uupoll; else mv $(bbindir)/uupoll $(bbindir)/uupoll.old; fi
+X $(INSTALL_PROGRAM) autopoll $(lbindir)/autopoll
+X $(INSTALL_PROGRAM) uupoll $(bbindir)/uupoll
+X chown $(owner) $(lbindir)/autopoll $(bbindir)/uupoll
+X chmod $(emode) $(lbindir)/autopoll $(bbindir)/uupoll
+X $(INSTALL_DATA) uupoll.8c $(man8dir)/uupoll$(man8ext)
+X $(INSTALL_DATA) autopoll.8c $(man8dir)/autopoll$(man8ext)
+X
+uninstall:
+X rm -f $(lbindir)/autopoll $(bbindir)/uupoll
+X rm -f $(man8dir)/autopoll$(man8ext) $(man8dir)/uupoll$(man8ext)
+X -cp $(lbindir)/autopoll.old $(lbindir)/autopoll
+X -cp $(bbindir)/uupoll.old $(bbindir)/uupoll
+X -chown $(owner) $(lbindir)/autopoll $(bbindir)/uupoll
+X -chmod $(emode) $(lbindir)/autopoll $(bbindir)/uupoll
+X
+uupoll: $(UUPOLLOBJS)
+X $(CC) $(LDFLAGS) -o uupoll $(UUPOLLOBJS) $(LIBS)
+X
+autopoll: $(AUTOOBJS)
+X $(CC) $(LDFLAGS) -o autopoll $(AUTOOBJS) $(LIBS)
+X
+.c.o:
+X $(CC) -c $(CFLAGS) $(MORECFLAGS) $<
+X
+X
+clean:
+X rm -f $(ALLOBJS) $(PROGRAMS)
+X
+mostlyclean: clean
+X
+TAGS:
+X etags *.h *.c
+X
+# Header file dependencies. These are maintained by hand.
+X
+$(ALLOBJS): conf.h
+X
+.NOEXPORT:
+SHAR_EOF
+chmod 0444 uupoll/Makefile ||
+echo 'restore of uupoll/Makefile failed'
+Wc_c="`wc -c < 'uupoll/Makefile'`"
+test 2602 -eq "$Wc_c" ||
+ echo 'uupoll/Makefile: original size 2602, current size' "$Wc_c"
+fi
+# ============= uupoll/README ==============
+if test -f 'uupoll/README' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/README (File already exists)'
+else
+echo 'x - extracting uupoll/README (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/README' &&
+X
+The package consists of the following files:
+X
+X - autopoll.c
+X - autopoll.8c
+X - conf.h
+X - Makefile
+X - README
+X - uupoll.c
+X - uupoll.8c
+X
+CAVEAT:
+uupoll as well as autopoll are created, tested and run on
+a NeXT running NeXTstep 2.1+ only! Autopoll will take the same arguments
+as uucico and may well work with them the same way uucico works but it
+has only been tested to call uucico with the options:
+X
+X -s<site> -S<site> -f -r1 -C -D (as well as the long form of these options)
+X
+so far. All options given to autopoll will be passed verbatim to uucico.
+X
+DESCRIPTION:
+The program uupoll was created to be a full replacement for the vendor
+supplied one on a NeXT computer. That uupoll checked any site name against
+the "hardwired" L.sys and did end with a "Bus error" if the site could not
+be found. There was no source available to modify so it had to be created
+from scratch.
+The program autopoll has no equivalent an the NeXT. The intentions behind
+it was to automate the task of rescheduling any failed call. It may be
+started by an entry in the crontab tables in just the same way uucico is
+started (it will start uucico):
+X
+05 5 * * * uucp /usr/local/lib/uucp/autopoll -r1 >>/tmp/poll.log 2>&1
+X
+Any messages go to stderr or a file (if compiled with that option); in case
+the file could not be opened it will use stdout to tell you just that and quit.
+To catch any output one may place the string
+X
+X >>/tmp/poll.log 2>&1
+X
+into the command line as well. Uupoll as well as autopoll will place only
+a start message into the logfiles in case they are invoked manually from
+the shell.
+If the call fails autopoll will reschedule uucico for a later time by means
+of an AT job.
+The messages given by uupoll and autopoll carry an indicator to inform about
+the nature of an error; they are:
+X
+- (I) informal message; such as ".. started" ".. ended".
+- (W) there might be an error but the program decided to go ahead.
+X The exit code will be at least 4.
+- (E) a severe error was encountered that either aborts the whole run or
+X only the task for one site will be aborted.
+X The exit code will be at least 8.
+- (C) a catastrophic error has been found such as unable to fork. The run
+X is aborted.
+X The exit code will be at least 16.
+The final message will show the exit code the programm has terminated with.
+X
+For more information see the man pages or look into the source.
+X
+INSTALLATION:
+all files should be placed in one folder. Then examine and change the files
+Makefile and conf.h to meet your needs. To compile uupoll some files of
+uucp must be available (see Makefile: uucpsrcs)
+If not already there change to the directory which contain the files and type:
+X
+make
+X
+this should compile UUPOLL and AUTOPOLL. There should only be a warning
+that rcsid is defined but not used.
+Before actually installing you should test the programs to be working as
+desired.
+Then check the Makefile for the final placement of the modules and the man
+pages. Make sure the ownership and setuid is what you need on your machine
+to run the program(s).
+Then su to root and type:
+X
+make install
+X
+which should install the above programs and the man pages in the appropriate
+directories.
+Some word on the coding: have mercy! This is my second project in 'C'; any
+suggestions that may improve the style/coding are welcome however.
+X
+In case of any problems that can't be solved feel free to contact the
+author at:
+X
+Klaus Dahlenburg Timezone : GMT + 2
+P.O.Box 1267 email : kdburg@incoahe.hanse.de
+D-21249 Tostedt Fax : +49 4287 676
+X Germany Voice : +49 4287 681
+X
+Have fun!
+SHAR_EOF
+chmod 0444 uupoll/README ||
+echo 'restore of uupoll/README failed'
+Wc_c="`wc -c < 'uupoll/README'`"
+test 3636 -eq "$Wc_c" ||
+ echo 'uupoll/README: original size 3636, current size' "$Wc_c"
+fi
+# ============= uupoll/autopoll.8c ==============
+if test -f 'uupoll/autopoll.8c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/autopoll.8c (File already exists)'
+else
+echo 'x - extracting uupoll/autopoll.8c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/autopoll.8c' &&
+.\"
+.\" @(#)autopoll.8c 1.4 (incoahe) 5/09/1993
+.\"
+.TH AUTOPOLL 8C "May 09, 1993"
+.UC 6
+.SH NAME
+autopoll \- automatic \s-1UUCP\s+1 file transfer supervisor
+.SH SYNOPSIS
+.B autopoll
+[
+.BI options
+]
+.SH DESCRIPTION
+file transfer requests placed by
+.IR uucp (1)
+or
+.IR uux (1)
+are handled by
+.IR uucico (8C).
+.IR uucico
+will be invoked immediately by the above programs unless the \-r
+option is given which queues the request for later processing. This
+is typically done by entries in the
+.IR crontab
+table(s) which will invoke
+.IR uucico.
+.IR uucico
+can also be invoked by
+.IR uupoll (8C).
+All methods have in common that there is no automatic retry by
+.IR uucico
+itself in case the call failed for some reason.
+Either manual
+intervention or some sort of scripts must be used to overcome this
+limitation.
+.PP
+.IR Autopoll
+can be used to automate up to a certain degree the task of rescheduling
+a call. None of the standard programs already mentioned need to be
+modified to get this working. Also not recommended (see BUGS section)
+.IR uucico
+may be an alias to
+.IR autopoll
+as all arguments passed to
+.IR autopoll
+will be copied verbatim to
+.IR uucico.
+In case this is done by link or other means the original
+.I uucio
+must still be available in a directory outside of the normal search path
+otherwise
+.I autopoll
+can't do what it's intended to do and will form a loop.
+.PP
+When
+.IR autopoll
+is called thre will be a check on the \-s, \-S and \-f option to
+see whether this
+is a specific call or not. Also the \-S and the \-f option must be checked
+to determine the type of call: honor any imposed wait for a site or not.
+Any call to ourself or to an unknown site will be refused. The known sites
+will be obtained by a call to
+.IR uuname(1).
+All other options will not be checked in any way. Next to this
+.IR uucico
+is called and the exit code is checked for a `1' which indicates that the call
+failed for some reason whatsoever. A `0' exit code will be interpreted as
+a success and
+.IR autopoll
+ends immediate. If the call seems to be unsuccessful a new call is scheduled
+for any site whose .Status files have a retry period greater than 0. The
+retry will be scheduled by means of placing an
+.IR at
+job at the time of the failing call plus any wait time given. For those
+sites that have been called with either the \-f or \-S option the retry
+time will be the time of the failing call plus 120 seconds.
+.PP
+In case the time calculated from the values found in a \.Status file is
+lower than the current time, the current time plus 60 seconds will be taken
+as the retry time.
+.PP
+A site will
+.IR not
+be automatically called again if one of the following
+conditions is met:
+.PP
+\-
+.IR uucico
+is terminated by a signal
+.PP
+\- either fork() or exec() failed
+.PP
+\- the
+.IR at
+command failed for any reasons.
+.PP
+\- if no wait should be honored and the retry time is found to be zero.
+(this may indicate a `Wrong time to call' condition.
+.PP
+There are other circumstances that may lead to not reschedule a call or
+not to call
+.IR uucico
+at all, all of which should be accompanied by (a) self explanatory message(s).
+.SH BUGS
+\- invalid options will make
+.IR uucico
+fail. The exit code for this type is the same as for any other failure; this
+can reschedule the call over and over again or never.
+.PP
+\-
+.IR autopoll
+may not work as expected when called with options other than \-r1, \-s,
+\-S or \-f.
+.PP
+\- a rescheduled call may fail with `wrong time to call' the second time
+but will be rescheduled again. The times to call won't be checked by
+.IR autopoll
+and the .Status file may not indicate this in case the \-c option is given.
+.PP
+\- in case the ..._DIR points to an invalid file a `Bus error' my pop up
+during the `exec' call.
+.PP
+\- the `chat-timeout' value may have to be increased when using
+.IR autopoll.
+An indication to do that is that the call fails short after `CONNECT'
+has been received with `Time out in chat script'.
+.PP
+\- the site names given will be checked aginst the output of
+.I uuname
+without any alias expansion done.
+.PP
+\- the text strings whithin the \.Status files will not be used to detect
+a failing call.
+.SH FILES
+.nf
+/usr/local/lib/uucp UUCP internal utilities
+/usr/lib/uucp
+/usr/local/bin UUCP internal utilities
+/usr/bin
+/usr/spool/uucp/.Status/ Status files for each site
+/usr/spool/uucp/ UUCP spool area. one of its sub-
+X directories will hold the null jobs.
+/tmp/poll.log This file is present only if autopoll
+X has been compiled to place the messages
+X into a file. Otherwise all messages will
+X go to stderr. The directory as well as
+X the name may be different.
+.fi
+.SH SEE ALSO
+uucp(1C), uux(1C), uucico(8C), uupoll(8C), uuname(1C), sort(1), uniq(1),
+at(1)
+SHAR_EOF
+chmod 0444 uupoll/autopoll.8c ||
+echo 'restore of uupoll/autopoll.8c failed'
+Wc_c="`wc -c < 'uupoll/autopoll.8c'`"
+test 4718 -eq "$Wc_c" ||
+ echo 'uupoll/autopoll.8c: original size 4718, current size' "$Wc_c"
+fi
+# ============= uupoll/autopoll.c ==============
+if test -f 'uupoll/autopoll.c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/autopoll.c (File already exists)'
+else
+echo 'x - extracting uupoll/autopoll.c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/autopoll.c' &&
+/* ---------------------------------------------------------------------------*
+X
+X Name: autopoll
+X
+X Author: Klaus Dahlenburg <kdburg@incoahe.hanse.de>
+X
+X Status: Public domain
+X
+X Copyright: none; claiming it to be your work will adversly affect
+X your image to be a good programmer.
+X
+X Function: Autopoll may be called just as uucico is called. The difference
+X is that autopoll will call uucico and if the return code is
+X not zero a check is made on the status files to see which site's
+X call failed. Those sites will be called again at that time found
+X in the status file plus any imposed wait. The next call will be
+X scheduled via an at job which in turn is handled by cron.
+X Atrun depends on the scheduling granularity of cron so the
+X actual times may be later than planned.
+X Autopoll will check the options -f and -s (-S) as well as the name
+X of the site passed. All other options will be passed unchecked.
+X The -f and -S options will indicate to autopoll that any wait
+X to call a site should be ignored; if the call fails the next
+X call to those sites will be at the current time plus 120 secs.
+X When the time found plus any wait evaluates to a time that
+X passed already the next call will be the current time plus 60
+X secs. The name of the site if given must be a valid one and not
+X the host itself otherwise it will be ignored.
+X
+X Call: autopoll [ options ]
+X
+X all option that apply to uucico may be given and
+X will be passed verbatim. See man uucico(8).
+X
+X Environment: NeXT 2.1+, Taylor UUCP-1.04+
+X
+X I/O: stdin: unused.
+X stdout: used only when ALOG_DIR is defined and the file
+X can't be opened. It will be a single message to tell
+X just that and the run is aborted.
+X stderr: all messages go here.
+X If ALOG_DIR is defined (see conf.h) all messages will
+X be appended to a file autopoll.msglog in that
+X directory; the file will be created automatically if
+X necessary; a redirection is then no longer possible.
+X Needs access to .Status files (see Comments later on).
+X
+X Called Programs: sort, uniq, uucico, uuname, at
+X
+X Compile: no special options are needed. Compiled with gcc 2.3.3 -O2.
+X Compile with the supplied cc might produce erroneous code
+X for the check options switch case 's' code: the break inside
+X the first if (..) {... break} is ignored.
+X
+X Comments: - should run setuid UUCP or whatever userid is necessary to
+X access (RDONLY) the .Status files and to run the programs
+X named under "Called Programs" above.
+X - No alias expansion is done on the given names for the
+X check against uuname's output..
+X - Invalid arguments will yield in an exit code > 0 as do
+X "normal" failures. It may therefore happen that a site
+X is called at the intervals with the same invalid arguments.
+X - "Wrong time to call" is not handled properly and may
+X call the site at the intervals until the time ban is lifted.
+X - human action is necessary as we can't distinguish between
+X "normal" failures and "errors" such as wrong password,
+X number to dial etc. The logs should be checked periodically.
+X - if CICO_DIR points to a non existent program the run may
+X end with signal 10: Bus Error.
+X - is has been observed that uucico will time out with "Dial
+X failed" when called via autopoll; setting chat-timeout to
+X value of 40 cured that problem.
+X - no rescheduling is done in case uucico fails and this
+X is not reported in the .Status file, one should check
+X the uucico log; this is to the fact that autopoll will
+X not scan the uucico log.
+*/
+X
+X
+#if !defined(lint)
+static char rcsid[] = "$Id: uupoll.shar,v 1.1 1994/05/07 18:09:32 ache Exp $";
+#endif /* not lint */
+X
+/* $Log: uupoll.shar,v $
+# Revision 1.1 1994/05/07 18:09:32 ache
+# Upgrade to version 1.05
+#
+X * Revision 2.8 1994/04/14 17:22:54 kdburg
+X * corrected misspelled AT_OPTION
+X *
+X * Revision 2.7 1994/04/11 20:15:48 kdburg
+X * major rework done; honor now some of the new option taht came with
+X * uucp-1.05
+X *
+X * Revision 2.6 1994/03/26 17:40:30 kdburg
+X * added support for UNAME_DIR; cleanup of some code; adjusted code after
+X * obtaining sitenames via popen()
+X *
+X * Revision 2.5 1993/07/07 16:49:02 kdburg
+X * when used interactivly only the start msg is put into the msg-log
+X * so far defined (UULOG)
+X *
+X * Revision 2.4 1993/06/26 16:17:51 kdburg
+X * the -S option wasn't propagated to the command passed to the at pgm
+X *
+X * Revision 2.3 1993/05/25 12:05:01 kdburg
+X * added error check on gettimeofday; added comment in the note section;
+X * minor changes not affection code
+X *
+X * Revision 2.2 1993/05/17 20:47:05 kdburg
+X * execution of at cmd also ok always said failed...
+X *
+X * Revision 2.1 1993/05/16 21:49:13 kdburg
+X * changed exit() to _exit() in case the exec fails within child
+X *
+X * Revision 2.0 1993/05/16 14:12:05 kdburg
+X * initial revision
+X * */
+X
+#define CAT 16
+#define SEVERE 8
+#define WARNING 4
+#define OK 0
+/* Boolean types */
+typedef int bool;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+X
+#include "conf.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+X
+#ifdef ALOG_FILE
+X static char Msg_Log[] = ALOG_FILE; /* name of msglog filename */
+#endif
+X
+#ifdef UNAME_DIR
+X static char subcmd[] = " | sort | uniq"; /* pipe that follows uuname */
+#else /* ! UNAME_DIR */
+X static char Sort[] = "uuname | sort | uniq"; /* default to obtain site names */
+#endif /*UNAME_DIR */
+X
+#ifdef AT_OPTION
+X static char at_opt[] = AT_OPTION;
+#else
+X static char at_opt[] = "-mc";
+#endif /* AT_OPTION */
+X
+static char at_cmd[] = "at";
+static char cGrade[] = DEF_GRADE; /* grade as defined in conf.h */
+static char dGrade[] = "A"; /* use this if DEF_GRADE is invalid */
+static char Auto_Dir[] = AUTO_DIR; /* we live here */
+static char Cico_Dir[] = CICO_DIR; /* here lives cico */
+X
+struct Sites {
+X char name[MAXHOSTNAMELEN+1]; /* name of site as supplied by uuname */
+X char grade[1]; /* as passed or defaulted */
+X bool flag; /* TRUE: call this site only */
+X bool force; /* TRUE: -S or -f option given */
+X int stat_code;
+X int stat_retries;
+X long stat_lastcall;
+X long stat_delay;
+X char *stat_errtext;
+};
+X struct Common_Stor {
+X int maxtab; /* high-water-mark for site tab */
+X int Single_Site_Tab; /* entry into site tab for a site */
+X /* passed via -s or -S option */
+X bool force_any; /* TRUE: -f option without site */
+X bool one_site; /* TRUE: call for a specific site */
+X bool nodetach; /* TRUE: -D or --nodetach found */
+X bool ifwork; /* TRUE: -C or --ifwork found */
+X char *Grade; /* use this as grade for calls */
+X char *Poll_Pgm; /* our name without path */
+X char *called_as; /* but called by this name */
+X int our_pid; /* our process-id */
+X char *Uucico; /* cico's name without path */
+X char This_Site[MAXHOSTNAMELEN+1]; /* our site name */
+X char Single_Site[MAXHOSTNAMELEN+1]; /* name of site found as arg */
+X union wait *W_Stat;
+X char *Usort; /* will hold uuname + subcmd */
+X struct passwd *pwd;
+X struct timeval tp;
+X struct timezone tzp;
+X struct Sites Sitetab[SITE_MAX];
+X char mon[3];
+X int day, hh, mm, ss;
+X char oname[24];
+X char jname[20];
+X char tstr[20];
+X char ctag[2];
+X char workf[300];
+X char call_args[300];
+X };
+X
+/* copied from taylor uucp "uudefs.h"
+X *
+X **/
+X
+/* The tstatus_type enumeration holds the kinds of status information
+X we put in the status file. The order of entries here corresponds
+X to the order of entries in the azStatus array. */
+enum tstatus_type
+{
+X /* Conversation complete. */
+X STATUS_COMPLETE,
+X /* Port unavailable. */
+X STATUS_PORT_FAILED,
+X /* Dial failed. */
+X STATUS_DIAL_FAILED,
+X /* Login failed. */
+X STATUS_LOGIN_FAILED,
+X /* Handshake failed. */
+X STATUS_HANDSHAKE_FAILED,
+X /* Failed after logging in. */
+X STATUS_FAILED,
+X /* Talking to remote system. */
+X STATUS_TALKING,
+X /* Wrong time to call. */
+X STATUS_WRONG_TIME,
+X /* Number of status values. */
+X STATUS_VALUES
+};
+X
+/* ----end-- copied from taylor uucp "uudefs.h" */
+X
+X
+/* define the prototypes
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *);
+int get_sites(struct Common_Stor *);
+int Call_Cico(int argc, char *argv[], struct Common_Stor *);
+int get_args(int argc, char *argv[], struct Common_Stor *);
+int Housekeeping(int argc, char *argv[], struct Common_Stor *);
+int Chk_Status(int argc, char *argv[],
+X struct timeval tcc,
+X struct timezone tzcc,
+X struct Common_Stor *);
+int Check_Site(struct Common_Stor *);
+int start_at(char *name, struct Common_Stor *);
+void *storage(unsigned count, char *errloc, int *Rc, struct Common_Stor *);
+X
+extern int gethostname(char *name, int namelen);
+extern int system(char *cmd);
+extern int fork();
+extern int unlink(char *path);
+extern void *malloc(size_t byteSize);
+extern int execve(char *name, char *argv[], char *envp[]);
+extern int execlp(char *name, char *arg0, ...);
+extern int chmod(char *path, int mode);
+extern int getuid();
+extern int getpid();
+extern int isatty(int);
+extern char *ttyname(int);
+extern void free(void *ptr);
+#ifdef __STRICT_ANSI__
+extern FILE *popen(char *command, char *type);
+extern int pclose(FILE *stream);
+extern void _exit(int status);
+#endif /* __STRICT_ANSI__ */
+#ifdef __STRICT_BSD__
+extern int fprintf(FILE *stream, const char *format, ...);
+extern int fclose(FILE *stream);
+extern char *strerror(int errnum);
+extern int fflush(FILE *stream);
+extern void exit(int status);
+extern int fscanf(FILE *stream, const char *format, ...);
+extern int sscanf(char *s, const char *format, ...);
+#endif /* __STRICT_BSD__ */
+X
+/* --------------------------------------------------------------------------*/
+/* Main */
+/* --------------------------------------------------------------------------*/
+X
+int main(int argc, char *argv[])
+{
+X
+X struct Common_Stor *sCom_Sto;
+X int Maxrc = OK; /* Max err-code encountered so far */
+X int k = 0;
+X
+X if ( NULL == (sCom_Sto = malloc(sizeof(struct Common_Stor))) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X AUTO_DIR,"Common_Stor",errno,strerror(errno));
+X exit (CAT);
+X }
+X
+X Maxrc = Housekeeping(argc, argv, sCom_Sto);
+X
+/* If any errors popped up so far they are of such a nature that it is very
+X * questionable to continue; so we better bail out in this case.
+X */
+X if (Maxrc <= WARNING) {
+X if ((sCom_Sto->W_Stat = (union wait *)storage (sizeof(union wait),
+X "W_Stat",&Maxrc,sCom_Sto)) != NULL) {
+X k = Call_Cico(argc, argv, sCom_Sto);
+X Maxrc = Maxrc >= k ? Maxrc:k;
+X free(sCom_Sto->W_Stat);
+X sCom_Sto->W_Stat = NULL;
+X }
+X }
+X k = gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp);
+X fprintf(stderr,"%s: (I) ended with rc = %i on %s\n",
+X sCom_Sto->called_as,
+X Maxrc,k!=0 ? "time unavailable":ctime(&sCom_Sto->tp.tv_sec));
+X fclose(stderr);
+X free(sCom_Sto);
+X sCom_Sto = NULL;
+X exit (Maxrc);
+}
+X
+/* --------------------------------------------------------------------------*/
+/* Functions */
+/* --------------------------------------------------------------------------*/
+X
+/* --------------------------------------------------------------------
+X * housekeeping
+X */
+X
+int Housekeeping(argc, argv, sCom_Sto)
+X int argc;
+X char *argv[];
+X struct Common_Stor *sCom_Sto; {
+X
+X FILE *seclog = NULL;
+X int Rc = OK;
+X int Rci = OK; /* intermediate rc as returnd by functions */
+X
+X sCom_Sto->our_pid = getpid();
+X
+/*
+X * get our name sans path
+X * */
+X
+X sCom_Sto->called_as = argv[0] + strlen(*argv);
+X for(;sCom_Sto->called_as >= argv[0] && *--sCom_Sto->called_as != '/';)
+X ;
+X sCom_Sto->called_as++;
+X
+/* if defined set up the name of the message log file otherwise
+X * stderr will be used. Setup the cmd string to obtain all known sitenames
+X * which will be sorted in ascending order with duplicates removed
+X * */
+X
+X Rc = set_mlog(&seclog, sCom_Sto);
+X if (Rc > WARNING)
+X return (Rc);
+X
+/* put out the started message including the time and the userid.
+X * */
+X
+X sCom_Sto->pwd = getpwuid(getuid());
+X
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X
+X if (seclog != NULL) {
+X fprintf(seclog,"\n%s: (I) started by `%s' (%s) on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ttyname(0),
+X ctime(&sCom_Sto->tp.tv_sec));
+X fclose(seclog);
+X }
+X fprintf(stderr,"\n%s: (I) started by `%s' on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ctime(&sCom_Sto->tp.tv_sec));
+X
+/* set up the default grade
+X * */
+X
+X sCom_Sto->Grade = dGrade; /* set default for now */
+X if (strlen(cGrade) != 1) {
+X fprintf(stderr,"%s: (W) grade %s invalid; default `%s' used\n",
+X sCom_Sto->called_as,cGrade,sCom_Sto->Grade);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X sCom_Sto->Grade = cGrade; /* Ok, take the one from conf.h */
+X
+/* get the program to actually call the site. This is normally UUCICO.
+X * */
+X
+X sCom_Sto->Uucico = Cico_Dir + strlen(Cico_Dir);
+X for(;sCom_Sto->Uucico >= Cico_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+X
+/* get the path to ourself.
+X * */
+X
+X sCom_Sto->Poll_Pgm = Auto_Dir + strlen(Auto_Dir);
+X for(;sCom_Sto->Poll_Pgm >= Auto_Dir && *--(sCom_Sto->Poll_Pgm) != '/';)
+X ;
+X sCom_Sto->Poll_Pgm++;
+X
+/* obtain our sitename
+X * */
+X
+X if ((gethostname(sCom_Sto->This_Site,MAXHOSTNAMELEN+1)) != 0) {
+X fprintf(stderr,"%s: (W) hostname could not be obtained\n",
+X sCom_Sto->called_as);
+X Rc = (Rc >= WARNING) ? Rc:WARNING;
+X }
+X
+/* obtain all known sitenames
+X * */
+X
+X Rci = get_sites(sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+/* check the arguments that we are called with
+X * */
+X
+X Rci = get_args(argc, argv, sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * check all relevant arguments that have been passed to us. Those args
+X * that may be needed for a recall will be copied to a workfield.
+X * */
+X
+int get_args(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X
+X int j = 0;
+X int Rc = OK;
+X int Rci = OK;
+X
+X strcpy(sCom_Sto->Single_Site,"");
+X sCom_Sto->force_any = FALSE;
+X sCom_Sto->one_site = FALSE;
+X sCom_Sto->nodetach = FALSE;
+X
+X strcpy(sCom_Sto->call_args,AUTO_DIR); /* specify complete path to us */
+X strcat(sCom_Sto->call_args," "); /* and separate by one space */
+X for (j=1;j<argc;j++) {
+X if (strcmp(argv[j],"--nodetach") == 0 ||
+X strcmp(argv[j],"-D") == 0) {
+X sCom_Sto->nodetach = TRUE;
+X strcat(sCom_Sto->call_args,"-D ");
+X continue;
+X }
+X if (strcmp(argv[j],"--force") == 0 ||
+X strcmp(argv[j],"-f") == 0) {
+X strcat(sCom_Sto->call_args,"-f ");
+X sCom_Sto->force_any = TRUE;
+X continue;
+X }
+X if (strcmp(argv[j],"--ifwork") == 0 ||
+X strcmp(argv[j],"-C") == 0) {
+X sCom_Sto->ifwork = TRUE;
+X continue;
+X }
+X if ( strncmp(argv[j],"-s",2) == 0 ||
+X strncmp(argv[j],"-S",2) == 0 ||
+X strcmp(argv[j],"--system") == 0) {
+X if (strncmp(argv[j],"-S",2) == 0)
+X sCom_Sto->force_any = TRUE;
+X
+X if (strlen(argv[j]) == 2 || strcmp(argv[j],"--system") == 0) {
+X j++;
+X if (j>=argc) {
+X fprintf(stderr,"%s: (E) System to call is missing\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X else {
+X strcpy(sCom_Sto->Single_Site,argv[j]);
+X Rci = Check_Site(sCom_Sto);
+X if (! Rci) {
+X sCom_Sto->one_site = TRUE; /* specific call */
+X strcat(sCom_Sto->call_args,argv[j-1]);
+X strcat(sCom_Sto->call_args," ");
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X }
+X }
+X Rc = Rci <= Rc ? Rc:Rci;
+X }
+X else {
+X strcpy(sCom_Sto->Single_Site,argv[j]+2);
+X Rci = Check_Site(sCom_Sto);
+X if (! Rci) {
+X sCom_Sto->one_site = TRUE; /* specific call */
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X }
+X Rc = Rci <= Rc ? Rc:Rci;
+X }
+X continue;
+X }
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X } /* end copy all arguments */
+X
+X if (sCom_Sto->ifwork) {
+X if (sCom_Sto->one_site) {
+X strcat(sCom_Sto->call_args,"-C ");
+X }
+X else {
+X fprintf(stderr,"%s: (W) no site given, '-C' option is ignored\n",
+X sCom_Sto->called_as);
+X sCom_Sto->ifwork = FALSE;
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X }
+X
+X if (! sCom_Sto->nodetach) {
+X strcat(sCom_Sto->call_args,"-D ");
+X }
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * call uucico or whatever programm is necessary to get connected
+X */
+X
+/* Start uucico and wait for completion. In case the return code is '0'
+X * we're finished; otherwise we'll have to check the status files for any
+X * non successful calls (retry time > 0).
+X * Any such site will be called again at the current time plus any wait
+X * Note:
+X * If the '-D' or '--nodetach' option is missing, uucico will
+X * detach immediate. The return-code is 0 in this case and therefore
+X * we can't check whether the call is successful or not. No recall
+X * is scheduled for such an invocation. If we however get control
+X * to schedule a recall we silently add the '-D' option. To add
+X * the '-D' option in any case may be undesirable for a specific
+X * type of run.
+X */
+X
+int Call_Cico(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X
+X int W_Ret = 0;
+X int pid = 0;
+X int Rc = OK;
+X struct timeval tcc;
+X struct timezone tzcc;
+X
+X if ((gettimeofday(&tcc, &tzcc)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= CAT ? Rc:CAT;
+X }
+X
+X if (Rc > WARNING) {
+X return (Rc);
+X }
+X
+X fflush(stderr);
+X switch(pid = fork()) {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork(). Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (CAT);
+X case 0:
+X if ((argv[0] = (char *)storage(strlen(sCom_Sto->Uucico)+1,"argv[0]",
+X &Rc,sCom_Sto)) == NULL) {
+X _exit (CAT);
+X }
+X strcpy(argv[0],sCom_Sto->Uucico); /* change name to be uucico */
+X execve(Cico_Dir, argv, NULL);
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fprintf(stderr,"%s: (I) starting %s [%d]\n\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico,pid);
+X fflush(stderr); /* maybe we come behind uucico's output */
+X /* if any; it's a race condition */
+X W_Ret = wait(sCom_Sto->W_Stat);
+X if (sCom_Sto->W_Stat->w_termsig == 0) {
+X if (sCom_Sto->W_Stat->w_retcode == 0) {
+X fprintf(stderr,"%s: (I) %s [%d] ended normally\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico,pid);
+X return (OK);
+X }
+X if (sCom_Sto->W_Stat->w_retcode != CAT) {
+X fprintf(stderr,"%s: (I) %s's log may contain further information !\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico);
+X fprintf(stderr,"\n%s: (W) %s [%d] ended with rc = %i\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,pid,
+X sCom_Sto->W_Stat->w_retcode);
+X return (Chk_Status(argc, argv,
+X tcc, tzcc, sCom_Sto));
+X }
+X else
+X return (CAT); /* we where unable to exec */
+X }
+X else {
+X fprintf(stderr,"\n%s: (E) %s [%d] terminated by signal %i\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X pid,
+X sCom_Sto->W_Stat->w_termsig);
+X return (SEVERE);
+X }
+X } /* switch (pid = fork()) */
+X return (OK); /* Never reached: silence the compiler */
+}
+X
+X
+/* --------------------------------------------------------------------
+X * check the status after the call has completed and the return code
+X * is > zero. The status is checked for all sites found via uuname or
+X * for one site only (option -s, -S or --system given on call)
+X */
+X
+int Chk_Status(int argc, char *argv[],
+X struct timeval tcc,
+X struct timezone tzcc,
+X struct Common_Stor *sCom_Sto) {
+X
+/*
+X * For all sites found in Site_Tab their status files will be checked.
+X * The table scan will be bypassed for a call to a specific site.
+X * If the call failed the wait period is > 0. We will schedule an at-job
+X * to be run at the time found + the delta. In case we find an old entry
+X * where the time + delta is lower than the current time we'll advance
+X * the current time by 60 secs. and use that value instead.
+X * In case we are invoked to call a specific site and either the -f option or
+X * the site was given as -S... indicating to disregard any wait, we'll
+X * use the time found in the status file increased by 120 secs.
+*/
+X
+X FILE *infile;
+X long secs, retries = 0;
+X long add = 0;
+X int errind = 0;
+X int i = 0;
+X int ecnt = 0;
+X int recall_cnt = 0;
+X char curr_site[MAXHOSTNAMELEN+11] = ""; /* keyword + sitename */
+X bool schedule = TRUE; /* FALSE: no more rescheduling: unspec. + force */
+X int Rc = WARNING; /* uucico got rc = 1 otherwise we were not here */
+X int Rs = 0; /* uucico' reason code from .Status file */
+X
+/*
+X * Note
+X * We have to increase the sum of time and wait by at least one minute.
+X * That is because this time denotes the earliest point *after* which
+X * we may call again.
+X * When a site is called at the wrong time the follwing actions are
+X * taken: wait = 0 && ! force --> no further action (indicator: see log)
+X * wait = 0 && force --> (W) message generated; no further action
+X * wait > 0 && ! force --> normal scheduling at time + wait
+X * wait > 0 && force --> normal scheduling at time+120 secs
+X * We can't depend on the string "Wrong time to call" because the .Status
+X * file may not be updated due to the -c switch. This may lead to a
+X * situation where the site will be called over and over again while it's
+X * still the wrong time. (No we don't want to go fishing for a message in
+X * the uucp LOG!)
+X * In case the -s, -S or --system option was given we will only
+X * check that site and schedule a recall for it so far the
+X * conditions are met.
+X * In case the -C or --ifwork switch is given without naming a site a
+X * the option is dropped and only an unspecific call is scheduled.
+X * */
+X
+X if (sCom_Sto->one_site) {
+X i = sCom_Sto->Single_Site_Tab;
+X if (strncmp(sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Single_Site,
+X sizeof(sCom_Sto->Single_Site)) != 0) {
+X fprintf(stderr,"%s: (C) internal index-error (%d): %s found: %s\n",
+X sCom_Sto->called_as,
+X i,
+X sCom_Sto->Single_Site,
+X sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= CAT ? Rc:CAT;
+X return (Rc); /* break unconditionally */
+X }
+X }
+X
+X for (i = sCom_Sto->Single_Site_Tab; i <= sCom_Sto->maxtab; i++) {
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X if ((infile=fopen(sCom_Sto->workf,"r")) == NULL) {
+X ecnt++;
+X fprintf(stderr,"%s: (W) no access to status file for: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X if (sCom_Sto->one_site) {
+X break;
+X }
+X else {
+X continue;
+X }
+X }
+X
+X fscanf(infile,"%d %d %ld %ld",&errind,&retries,&secs,&add);
+X fclose(infile);
+X
+X /*
+X * in case the .Status file is not updated and we have a call to
+X * a specific site we try to give some clues of what went wrong
+X * (we won't succeed in any case!)
+X */
+X
+X if (sCom_Sto->Sitetab[i].stat_lastcall == secs && sCom_Sto->one_site) {
+X
+X if (errind == 0 && retries == 0 && add == 0)
+X break;
+X
+X if (errind > 0) {
+X if (tcc.tv_sec <= (secs+add) && ! sCom_Sto->Sitetab[i].force) {
+X fprintf(stderr,"%s: (W) retry time not reached for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X fprintf(stderr,"%s: (E) maybe port/site unavailable site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X }
+X else {
+X if (sCom_Sto->one_site) {
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X }
+X fprintf(stderr,"%s: (W) no recall scheduled for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break; /* bail out completely */
+X }
+X
+X if (sCom_Sto->Sitetab[i].stat_lastcall == secs) {
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X
+X Rs = OK; /* if Rs is > WARNING we won't schedule a recall */
+X switch(errind) {
+X case STATUS_COMPLETE:
+X if (add != 0 || retries != 0) {
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X }
+X break;
+X case STATUS_PORT_FAILED:
+X fprintf(stderr,"%s: (E) port was unavailable site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_DIAL_FAILED:
+X fprintf(stderr,"%s: (E) dail failed for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_LOGIN_FAILED:
+X fprintf(stderr,"%s: (E) login for site: %s failed\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X case STATUS_HANDSHAKE_FAILED:
+X fprintf(stderr,"%s: (E) handshake failed site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_FAILED:
+X fprintf(stderr,"%s: (E) invalid status after login site: %s \n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_TALKING:
+X break;
+X case STATUS_WRONG_TIME:
+X fprintf(stderr,"%s: (W) it's the wrong time to call site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X default:
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X }
+X Rc = Rs > Rc ? Rs:Rc;
+X if (Rs > WARNING) { /* schedule a recall ? */
+X fprintf(stderr,"%s: (W) no recall scheduled for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X
+X if (add == 0) {
+X fprintf(stderr,"%s: (W) no delay found for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X
+X
+X if (! schedule) {
+X recall_cnt += 1;
+X continue; /* scheduling already done: unspec. + force */
+X }
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) {
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X fclose(infile);
+X Rc = Rc >= CAT ? Rc:CAT;
+X break; /* break unconditionally */
+X }
+X
+X if (sCom_Sto->force_any || sCom_Sto->Sitetab[i].force) {
+X add = secs + 120; /* shorten the wait */
+X }
+X else { /* ! force */
+X
+/*
+X * check for an already scheduled recall. For we don't keep
+X * a file of already scheduled recalls the only way to recognize
+X * this, is to check the current time against that of the .Stats file.
+X * In case the current time is >= the .Stats-time + n-secs fuzz value
+X * we assume (99.99% correctness) that we have already scheduled a recall
+X * for this site. If this assumption is incorrect a call will be
+X * scheduled on the next unspecific failing call. This check can't
+X * be done for forced call because the .Stats will be updated.
+X */
+X if (sCom_Sto->tp.tv_sec >= secs+2) {
+X fprintf(stderr,"%s: (W) Retry time not reached for site: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X add += secs + 60; /* if not force then take the full wait */
+X } /* force */
+X
+X if (sCom_Sto->tp.tv_sec >= add) {
+X add = sCom_Sto->tp.tv_sec + 60; /* time < current time */
+X }
+X
+X sscanf(ctime(&add),"%*s %s %d %d:%d:%d",sCom_Sto->mon,
+X &sCom_Sto->day,
+X &sCom_Sto->hh,
+X &sCom_Sto->mm,
+X &sCom_Sto->ss);
+X
+X sprintf(sCom_Sto->oname,"/tmp/at.%d.%02d%02d%02d",sCom_Sto->our_pid,
+X sCom_Sto->hh,
+X sCom_Sto->mm,
+X sCom_Sto->ss);
+X if (! sCom_Sto->one_site) {
+X strcpy(curr_site,"-s");
+X strcat(curr_site,sCom_Sto->Sitetab[i].name);
+X }
+X
+X /*
+X * If 'onesite' is FALSE and 'force' is TRUE
+X * we will reschedule one unspecific call an let UUCICO decide
+X * which site should be called (is there any work?)
+X */
+X
+X if ( ! sCom_Sto->one_site && sCom_Sto->force_any) {
+X recall_cnt += 1;
+X schedule = FALSE;
+X continue;
+X }
+X strcat(sCom_Sto->call_args,curr_site);
+X Rs = start_at(sCom_Sto->Sitetab[i].name, sCom_Sto);
+X Rc = Rs >= Rc ? Rs:Rc;
+X unlink(sCom_Sto->oname);
+X if (Rc > SEVERE || sCom_Sto->one_site)
+X break;
+X } /* for (i = Single_Site_Tab; ...) */
+X
+X if (ecnt > sCom_Sto->maxtab) {
+X fprintf(stderr,"%s: (E) no access to status files; no scheduling done\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X if (! schedule) {
+X if (recall_cnt == 1) {
+X strcat(sCom_Sto->call_args,curr_site);
+X }
+X Rs = start_at("any site", sCom_Sto);
+X Rc = Rs >= Rc ? Rs:Rc;
+X unlink(sCom_Sto->oname);
+X }
+X }
+X return (Rc);
+}
+X
+X /*
+X *
+X */
+X
+int start_at(char *site, struct Common_Stor *sCom_Sto) {
+X
+FILE *outfile;
+int W_Ret = 0;
+int Rc = OK;
+int pid = 0;
+X
+/*
+X * if we can't open the workfile to be passed to AT we'll abandon
+X * this site and set the rc accordingly
+X * */
+X
+X if ((outfile=fopen(sCom_Sto->oname,"w")) == NULL) {
+X fprintf(stderr,"%s: (E) could not open workfile %s. No scheduling for: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->oname,
+X site);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X fclose(outfile);
+X unlink(sCom_Sto->oname);
+X return (Rc); /* bail out here */
+X }
+X sprintf(sCom_Sto->jname,"at.%d.%02d%02d%02d",sCom_Sto->our_pid,
+X sCom_Sto->hh,
+X sCom_Sto->mm,
+X sCom_Sto->ss);
+X fprintf(outfile,"%s \n",sCom_Sto->call_args);
+X sprintf(sCom_Sto->tstr,"%02d%02d",sCom_Sto->hh,
+X sCom_Sto->mm);
+X sprintf(sCom_Sto->ctag,"%d",sCom_Sto->day);
+X fclose(outfile);
+X if ((chmod(sCom_Sto->oname,00644)) != 0) {
+X fprintf(stderr,"%s: (W) chmod to %s failed. Reason_code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->oname,
+X errno,
+X strerror(errno));
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X
+X switch (pid = fork()) {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork(). Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X case 0:
+X if (*at_opt == '\0')
+X execlp(at_cmd, at_cmd, sCom_Sto->tstr,
+X sCom_Sto->mon, sCom_Sto->ctag,
+X sCom_Sto->oname, 0);
+X else
+X execlp(at_cmd, at_cmd, at_opt, sCom_Sto->tstr,
+X sCom_Sto->mon, sCom_Sto->ctag,
+X sCom_Sto->oname, 0);
+X
+X fprintf(stderr,"%s: (C) could not start AT-cmd. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fprintf(stderr,"%s: (I) at [%d] started. Job name: %s\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->jname);
+X W_Ret = wait(sCom_Sto->W_Stat);
+X if (sCom_Sto->W_Stat->w_termsig == 0) {
+X if (sCom_Sto->W_Stat->w_retcode != 0) {
+X if (sCom_Sto->W_Stat->w_retcode != CAT) {
+X fprintf(stderr,"%s: (E) at-cmd failed for some reason\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X Rc = Rc >= CAT ? Rc:CAT;
+X }
+X
+X fprintf(stderr,"%s: (I) at [%d] ended with rc = %i\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->W_Stat->w_retcode);
+X /* bail out in case wait returned > SEVERE */
+X if (Rc > SEVERE) {
+X return (Rc);
+X }
+X }
+X else {
+X fprintf(stderr,"%s: (I) at-cmd [%d] ended normally\n",
+X sCom_Sto->called_as,
+X pid);
+X }
+X }
+X else {
+X fprintf(stderr,"%s: (E) at [%d] terminated by signal %i\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->W_Stat->w_termsig);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* switch (pid = fork()) */
+X return (Rc);
+}
+/* -----------------------------------------------------------------
+X * check the site passed via -s or -S option to be a valid one and
+X * not to be our hostname.
+X * */
+X
+int Check_Site(struct Common_Stor *sCom_Sto) {
+X
+X int i,j = 0;
+X sCom_Sto->Single_Site_Tab = 0;
+X if (strcmp(sCom_Sto->Single_Site,sCom_Sto->This_Site) == 0) {
+X fprintf(stderr,"%s: (E) won't call *ourself* %s\n",
+X sCom_Sto->called_as,sCom_Sto->Single_Site);
+X return(SEVERE);
+X }
+X for(i=0;i<=sCom_Sto->maxtab;i++) {
+X if ((j=strcmp(sCom_Sto->Sitetab[i].name,sCom_Sto->Single_Site)) >= 0) {
+X break;
+X }
+X }
+X if (j != 0) {
+X fprintf(stderr,"%s: (E) unknown site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Single_Site);
+X return(SEVERE);
+X }
+X sCom_Sto->Single_Site_Tab = i;
+X sCom_Sto->Sitetab[i].flag = TRUE;
+X if (sCom_Sto->force_any) {
+X sCom_Sto->Sitetab[i].force = TRUE;
+X sCom_Sto->force_any = FALSE;
+X }
+X return(OK);
+}
+X
+X /* ------------------------------------------------------------------
+X * storage - get some memory
+X */
+X
+void *storage(unsigned count,
+X char *location,
+X int *Rc,
+X struct Common_Stor *sCom_Sto)
+{
+X void *p;
+X
+X if( NULL == (p= malloc(count)) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X sCom_Sto->called_as,location,errno,strerror(errno));
+X *Rc = *Rc >= CAT ? *Rc:CAT;
+X }
+X return p;
+}
+X
+/* ------------------------------------------------------------------
+X * if defined open the message log file otherwise all mesages will go
+X * to stderr. If UNAME_DIR is defined construct the command to be
+X * passed to popen(); if undefined the deafult will be used
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *sCom_Sto) {
+X
+X int Rc = 0;
+X
+#ifdef ALOG_FILE
+X if (!isatty(0)) {
+X if ((freopen(Msg_Log,"a",stderr)) == NULL) {
+X fprintf(stdout,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+X else {
+X if ((*seclog = fopen(Msg_Log,"a")) == NULL) {
+X fprintf(stderr,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+#endif /* ALOG_FILE */
+X
+/* set up the pipe together with the complete path to uuname */
+X
+#ifdef UNAME_DIR
+X if ((sCom_Sto->Usort = (char *)storage (sizeof(UNAME_DIR)+sizeof(subcmd),
+X "Sort",&Rc, sCom_Sto)) != NULL) {
+X strncpy(sCom_Sto->Usort,UNAME_DIR,strlen(UNAME_DIR)); /* paste in the path */
+X strcat(sCom_Sto->Usort,subcmd); /* chain the pipe to it */
+X }
+#else /* ! UNAME_DIR */
+X sCom_Sto->Usort = &Sort; /* set pointer to uuname + sort */
+#endif /* UNAME_DIR */
+X
+X return (Rc);
+}
+X
+/* ------------------------------------------------------------------
+X * obtain all active sitenames
+X * */
+X
+int get_sites(struct Common_Stor *sCom_Sto) {
+X
+X int i = 0;
+X int n;
+X int Rc = 0;
+X FILE *infile, *statsfile;
+X
+X if ((infile=popen(sCom_Sto->Usort,"r")) != NULL) {
+X while(fgets(sCom_Sto->Sitetab[i].name,MAXHOSTNAMELEN+1,infile)) {
+X if (i > SITE_MAX) { /* let'm run so that we can give */
+X i++; /* the user some guidance */
+X continue; /* we'll tell the user later on */
+X }
+X n = strlen(sCom_Sto->Sitetab[i].name)-1; /* offset: next to last char */
+X sCom_Sto->Sitetab[i].name[n] = '\0'; /* strip trailing newline */
+X sCom_Sto->Sitetab[i].flag = FALSE; /* TRUE: poll this site only*/
+X sCom_Sto->Sitetab[i].force = FALSE; /* TRUE: force call */
+X strcpy(sCom_Sto->Sitetab[i].grade,sCom_Sto->Grade);
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X if ((statsfile=fopen(sCom_Sto->workf,"r")) == NULL) {
+X fprintf(stderr,"%s: (W) no access to status file for: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X fscanf(statsfile,"%d %d %ld %ld %s",
+X &sCom_Sto->Sitetab[i].stat_code,
+X &sCom_Sto->Sitetab[i].stat_retries,
+X &sCom_Sto->Sitetab[i].stat_lastcall,
+X &sCom_Sto->Sitetab[i].stat_delay,
+X sCom_Sto->workf);
+X
+X fclose(statsfile);
+X if ((sCom_Sto->Sitetab[i].stat_errtext =
+X (char *)storage (sizeof(sCom_Sto->workf),
+X "stat_errtext",&Rc, sCom_Sto)) == NULL) {
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X strcpy(sCom_Sto->Sitetab[i].stat_errtext,sCom_Sto->workf);
+X }
+X sCom_Sto->maxtab = i++; /* set high-water-mark */
+X }
+X if (ferror(infile) != 0) {
+X fprintf(stderr,"%s: (E) fgets() for sitenames failed reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X pclose(infile);
+X
+X /*
+X * check for an empty table (strange but possible)
+X */
+X
+X if (sCom_Sto->maxtab == 0) {
+X fprintf(stderr,"%s: (E) could not obtain sitenames.\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X
+X /* in case the internal table overflows we'll now give notice and tell
+X * the user by which amount the table has to be increased to hold all
+X * site-names
+X */
+X
+X if (i > SITE_MAX) {
+X fprintf(stderr,"%s: (E) number of sites > internal tab\n",
+X sCom_Sto->called_as);
+X fprintf(stderr,"%s: (E) increase SITE_MAX to >= %d and recompile\n",
+X sCom_Sto->called_as,i);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* sCom_Sto->maxtab == 0 */
+X
+X }
+X else /* infile == NULL */
+X {
+X fprintf(stderr,"%s: (E) could not sort sitenames. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X
+X } /* if ((infile=popen(sCom_Sto->Usort,"r")) ... */
+X
+X return (Rc);
+}
+SHAR_EOF
+chmod 0444 uupoll/autopoll.c ||
+echo 'restore of uupoll/autopoll.c failed'
+Wc_c="`wc -c < 'uupoll/autopoll.c'`"
+test 44031 -eq "$Wc_c" ||
+ echo 'uupoll/autopoll.c: original size 44031, current size' "$Wc_c"
+fi
+# ============= uupoll/conf.h ==============
+if test -f 'uupoll/conf.h' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/conf.h (File already exists)'
+else
+echo 'x - extracting uupoll/conf.h (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/conf.h' &&
+#ifndef CONF
+X #define CONF
+X
+/* $Id: uupoll.shar,v 1.1 1994/05/07 18:09:32 ache Exp $ */
+/* $Log: uupoll.shar,v $
+# Revision 1.1 1994/05/07 18:09:32 ache
+# Upgrade to version 1.05
+#
+X * Revision 1.9 1994/04/14 17:24:58 kdburg
+X * added comment to the AT_OPTION
+X *
+X * Revision 1.8 1994/03/26 17:41:06 kdburg
+X * the location of uuname can now be specified. This was added due to
+X * the fact that cron (NeXT 3.2 and +) now obeys the path that was active
+X * during boot (either /.path or set within /etc/rc) so autopoll/uupoll
+X * always got the wrong uuname when called direct fron cron. This is
+X * not true when called via a script that does a 'su - user -c ...'
+X *
+X * Revision 1.7 1993/06/26 16:21:47 kdburg
+X * default location for logfiles changed
+X *
+X * Revision 1.6 1993/05/14 22:32:05 kdburg
+X * change to HAVE_SPOOLDIR_TAYLOR
+X *
+X * Revision 1.5 1993/05/09 13:16:53 kdburg
+X * make have-autopoll the default
+X *
+X * Revision 1.4 1993/05/08 23:17:34 kdburg
+X * cleanup and to reflect changes made to autopoll/uupoll
+X *
+X * Revision 1.3 1993/04/29 10:46:34 kdburg
+X * added def for STATUS_DIR
+X *
+X * Revision 1.2 1993/04/27 15:31:47 kdburg
+X * rearranged the defs; changed LOG_DIR to ALOG_DIR in case uupoll
+X * will have one too; we need then eventually 2 different dirs.
+X *
+X * Revision 1.1 1993/04/26 21:20:12 kdburg
+X * Initial revision
+X * */
+X
+/* --------- combined config file for uupoll and autopoll */
+/* --------- change the following defines to meet your needs */
+X
+/* define the default grade to be inserted into the pollfile name */
+#define DEF_GRADE "A"
+X
+/* Define the complete path to the uuname program.
+X * If undefined we'll use just the name 'uuname' to call it
+X * */
+#define UNAME_DIR "/usr/local/bin/uuname"
+X
+/* define the path to the directory which does contain uucico */
+#define CICO_DIR "/usr/local/lib/uucp/uucico"
+X
+/* define the path to the directory which holds all the uucp files.
+X * We'll place the poll file in one of it's subdirectories
+X * */
+#define SPOOL_DIR "/usr/spool/uucp"
+X
+/* at least one of the follwing must be defined To use the second or
+X * third set of definitions, change the ``#if 1'' to ``#if 0''
+X * and change the appropriate ``#if 0'' to ``#if 1''.
+X * */
+#if 0
+#define HAVE_SPOOLDIR_BSD
+#endif
+#if 0
+#define HAVE_SPOOLDIR_HDB
+#endif
+#if 1
+#define HAVE_SPOOLDIR_TAYLOR
+#endif
+X
+/* define the maximum number of sites in your config or L.sys */
+#define SITE_MAX 100
+X
+/* define the path to the directory which is to contain the
+X * message log created by uupoll and the file name itself.
+X * change the ``#if 1'' to ``#if 0'' to have the messages on stderr
+X * */
+#if 1
+#define ULOG_FILE "/Logfiles/poll.log"
+#endif
+X
+/* change if to 0 if you don't have autopoll installed. */
+#if 1
+#define AUTO_POLL
+#endif
+X
+/* The following defs are irrelevant if you don't have autopoll */
+X
+/* define the options to be given to the at cmd (-s -c -m). The default
+X * is shown (use csh and send mail after execution) if AT_OPTION is
+X * undefined
+X * */
+#define AT_OPTION "-mc"
+X
+/* Define the complete path to the autopoll program.
+X * This will assure that we get the one we want
+X * The path must be the same as given in Makefile (lbindir)
+X * */
+#define AUTO_DIR "/usr/local/lib/uucp/autopoll"
+X
+/* define the path to the directory which is to contain the
+X * message log created by autopoll and the file name itself.
+X * change the ``#if 1'' to ``#if 0'' to have the messages on stderr
+X * */
+#if 1
+#define ALOG_FILE "/Logfiles/poll.log"
+#endif
+X
+/* define the full path to the directory which holds the status files
+X * The name should be given *except* the sitename. A trailing `/' if any
+X * must be given.
+X * Example: /usr/spool/uucp/.Status/sys.sitename
+X * then specify STATUS_DIR as
+X * "/usr/spool/uucp/.Status/sys."
+X * */
+#define STATUS_DIR "/usr/spool/uucp/.Status/"
+#endif
+SHAR_EOF
+chmod 0444 uupoll/conf.h ||
+echo 'restore of uupoll/conf.h failed'
+Wc_c="`wc -c < 'uupoll/conf.h'`"
+test 3884 -eq "$Wc_c" ||
+ echo 'uupoll/conf.h: original size 3884, current size' "$Wc_c"
+fi
+# ============= uupoll/uupoll.8c ==============
+if test -f 'uupoll/uupoll.8c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/uupoll.8c (File already exists)'
+else
+echo 'x - extracting uupoll/uupoll.8c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/uupoll.8c' &&
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved. The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\" @(#)uupoll.8c 6.1 (Berkeley) 4/24/86
+.\" @(#)uupoll.8c 1.11 (incoahe) 5/09/1993
+.\"
+.TH UUPOLL 8C "Mai 09, 1993"
+.UC 6
+.SH NAME
+uupoll \- poll a remote \s-1UUCP\s+1 site
+.SH SYNOPSIS
+.B uupoll
+[
+.BI \-g grade
+] [
+.B \-n
+] [
+.B \-x
+]
+.I system ... ...
+.SH SUMMARY
+This version of
+.IR uupoll
+can be used to fully replace the vendor supplied
+.IR uupoll
+that comes with the NeXTStep OS. The original version (up to 3.1) had a
+X bug in that
+X an unknown site given as argument would yield in a `Bus error' condition.
+Using any other type of UUCP like Taylor-UUCP with the option of having
+a different file structure as well as a different L.sys will therefore
+make it necessary to do maintenance to the (unused) L.sys as well to keep
+.IR uupoll
+going. This one has been programmed from scratch due to the fact that no
+source code was available. Some enhancements have been incorporated into
+this version:
+.PP
+\- the default grade may now be compiled different from `A'.
+.PP
+\- the options may now be given in any order and the \-g option may be given
+more than once. Any option will be used immediately when encountered and
+will stay in effect unless reset; this does not apply to the \-x and \-n
+option which can't be reset. The processing of options is guaranteed to be
+from left to right so that some grouping may be achieved (see below).
+.PP
+\-
+.IR uupoll
+may be used to call any program instead of
+.IR uucico
+namely
+.IR autopoll
+to ease the task of rescheduling a failed call.
+.SH DESCRIPTION
+.I Uupoll
+is used to force a poll of a remote system. It queues a null job for the
+remote system, unless the \-x option has been given, and then invokes
+either
+.IR uucico (8C)
+or
+.IR autopoll (8C)
+or any other program depending on how
+.IR uupoll
+is customized. If used in conjunction with
+.IR autopoll
+the latter will then invoke
+.IR uucico.
+.SH OPTIONS
+The following options are available:
+.TP 8
+.BI \-g grade
+Only send jobs of grade
+.I grade
+or higher on this call. The
+.I grade
+stays in effect until it is changed by a different \-g option.
+.TP 8
+.B \-n
+Queue the null job, but do not invoke the program that actually calls
+the named site(s).
+The \-n option once given will apply to all sites following to the
+.IR right
+of it.
+.TP 8
+.B \-x
+Do not place a null job for all following sites. This option must be given
+before the \-n option. The \-n option will nullify this. Any grade in effect
+will not be honored because
+.I uucico (Taylor)
+does not carry the \-g option at the moment.
+.PP
+.I Uupoll
+is usually run by
+.IR cron (5)
+or by a user who wants to hurry a job along. A typical entry in
+.I crontab
+could be:
+.PP
+.nf
+X 0 0,8,16 * * * uucp /usr/bin/uupoll ihnp4
+X 0 4,12,20 * * * uucp /usr/bin/uupoll ucbvax
+.fi
+This will poll
+.B ihnp4
+at midnight, 0800, and 1600, and
+.B ucbvax
+at 0400, noon, and 2000.
+.PP
+If the local machine is already running
+.I uucico
+every
+hour and has a limited number of outgoing modems, a better approach
+might be:
+.PP
+.nf
+X 0 0,8,16 * * * uucp /usr/bin/uupoll -n ihnp4
+X 0 4,12,20 * * * uucp /usr/bin/uupoll -n ucbvax
+X 5 * * * * uucp /usr/lib/uucp/uucico -r1 -D -C
+.fi
+This will queue null jobs for the remote sites at the top of the hour; they
+will be processed by
+.I uucico
+when it runs five minutes later (the -C option apply to Taylor
+uucp-1.05 only, the -D option applies to Talor uucp-1.04 and up)
+.SH EXTENDED options
+An example of the options and how they interact is given below. The working
+order while processing the options is left to right:
+.nf
+X uupoll -gC site1 -gB site2 -x site3 -n -gA site4 site5
+.fi
+.PP
+this poll will:
+.PP
+- call immediate site1 with grade C or higher and will place a null job
+.PP
+- call immediate site2 with grade B or higher and will place a null job
+.PP
+- call immediate site3 with grade B or higher without placing a null job
+.PP
+- just placing a null job for site4 and site5 with grade A or higher. These
+sites will be called at the next regular schedule.
+.SH BUGS
+When more than one site is given on the command line and no \-n option is
+given there will be an immediate invocation of
+.IR uucico
+or
+.IR autopoll
+for
+.IR all
+sites given. That may lead to a `No port available' condition.
+.SH FILES
+.ta \w'/usr/spool/uucp/ 'u
+.nf
+/etc/uucp/ UUCP internal files/utilities
+/usr/spool/uucp/ Spool directory
+/tmp/poll.log This file is present only if uupoll has been
+X compiled to place the messages into a file.
+X Otherwise all messages will go to stderr.
+X The directory as well as the name may be
+X different. The name may be defined at compile time.
+.fi
+.SH SEE ALSO
+uucp(1C), uux(1C), uucico(8C), autopoll(8C)
+SHAR_EOF
+chmod 0444 uupoll/uupoll.8c ||
+echo 'restore of uupoll/uupoll.8c failed'
+Wc_c="`wc -c < 'uupoll/uupoll.8c'`"
+test 4787 -eq "$Wc_c" ||
+ echo 'uupoll/uupoll.8c: original size 4787, current size' "$Wc_c"
+fi
+# ============= uupoll/uupoll.c ==============
+if test -f 'uupoll/uupoll.c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/uupoll.c (File already exists)'
+else
+echo 'x - extracting uupoll/uupoll.c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/uupoll.c' &&
+/* ---------------------------------------------------------------------------*
+X
+X Name: uupoll
+X
+X Author: Klaus Dahlenburg <kdburg@incoahe.hanse.de>
+X
+X Status: Public domain
+X
+X Copyright: none
+X
+X Funktion: The main intention behind this program was to get a full
+X replacement of the uupoll supplied by NeXT when using an
+X UUCP or a file structure that is different from that hardwired
+X config in NeXT's uupoll. The lack of source made it impossible
+X to modify the supplied uupoll.
+X
+X Call: uupoll [-n] [-x] [-g[A | 0-9,A-Z,a-z]] site ...
+X
+X -n just place a poll file but do not call uucico;
+X This option can be given only once.
+X -x meaningful only for sites not affected by the -n
+X option. It prevents the creation of a poll file;
+X the default is to place one. In case the poll fails
+X there will be no attempt to poll those sites on
+X the next general (unspecific) poll. If using
+X autopoll the site will be called at the next + 1
+X run of autopoll.
+X -g any grade may be given to meet the criteria for
+X a successful poll. The default being specified
+X in conf.h (A).
+X This option may be given individually for each
+X site to call.
+X site the name of the site to be called. As many sites
+X as necessary may be specified separated by at least
+X one blank.
+X Note: any site will be called with the options currently in
+X effect. The working order is left to right. Example:
+X uupoll -gQ site1 site2 -gZ site3 -n site4
+X site1 and site2 will be called immediate with grade Q
+X site3 will be called immediate with grade Z. Site4 will
+X have a poll file created with grade Z.
+X
+X Environment: NeXT 2.1
+X
+X Called Programs: sort, uniq, uucico (or autopoll), uuname
+X
+X Compile: no special options are needed
+X
+X Comments: - should run setuid UUCP or whatever userid is necessary to
+X write to the spool directory with the proper ownership of
+X the files and to run uucico.
+X - No alias expansion is done on the given names.
+*/
+X
+#if !defined(lint)
+static char rcsid[] = "$Id: uupoll.shar,v 1.1 1994/05/07 18:09:32 ache Exp $";
+#endif /* not lint */
+X
+/* $Log: uupoll.shar,v $
+# Revision 1.1 1994/05/07 18:09:32 ache
+# Upgrade to version 1.05
+#
+X * Revision 2.7 1994/04/14 17:22:04 kdburg
+X * major rework done
+X *
+X * Revision 2.6 1994/03/26 17:38:41 kdburg
+X * added support for UNAME_DIR; cleanup of some code; adjusted code after
+X * obtaining sitenames via popen()
+X *
+X * Revision 2.5 1994/03/24 19:01:24 kdburg
+X * some minor changes; some calls had their rc not checked
+X *
+X * Revision 2.4 1993/07/08 07:56:26 kdburg
+X * befor invoking autopoll stdin is now closed to avoid blocking of
+X * terminal
+X *
+X * Revision 2.3 1993/07/05 19:43:00 kdburg
+X * when used interactivly only the start msg is put into the msg-log
+X * so far defined (UULOG)
+X *
+X * Revision 2.2 1993/05/20 18:50:52 kdburg
+X * no execute permission to the poll-pgm (uucico/autopoll) was not
+X * reflected in the log; when to start message was not given when -x
+X * option was present
+X *
+X * Revision 2.1 1993/05/16 21:48:15 kdburg
+X * changed exit() to _exit() in case the exec fails within child
+X *
+X * Revision 2.0 1993/05/16 14:11:04 kdburg
+X * initial revision
+X * */
+X
+#define CAT 16
+#define SEVERE 8
+#define WARNING 4
+#define OK 0
+#define P_MODE 00647 /* file-mode for poll-file */
+/* Boolean types */
+typedef int bool;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+X
+#include "conf.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <sys/time.h>
+X
+#define X_OK 1 /* access: executable ? */
+X
+#ifdef ALOG_FILE
+X static char Msg_Log[] = ALOG_FILE; /* name of msglog filename */
+#endif
+X
+#ifdef UNAME_DIR
+X static char subcmd[] = " | sort | uniq"; /* pipe that follows uuname */
+#else /* ! UNAME_DIR */
+X static char Sort[] = "uuname | sort | uniq"; /* default to obtain site names */
+#endif /*UNAME_DIR */
+X
+static char cGrade[] = DEF_GRADE; /* grade as defined in conf.h */
+static char dGrade[] = "A"; /* use this if DEF_GRADE is invalid */
+#ifdef AUTO_POLL
+X static char Auto_Dir[] = AUTO_DIR; /* autopoll lives here */
+#else
+X static char Cico_Dir[] = CICO_DIR; /* and here lives cico */
+#endif /* AUTO_POLL */
+X
+struct Sites {
+X char name[MAXHOSTNAMELEN+1]; /* name of site as supplied by uuname */
+X char grade[1]; /* as passed or defaulted */
+X bool flag; /* TRUE this site should be polled */
+X int asap; /* 1 without -n; 2 with -x option */
+};
+X struct Common_Stor {
+X int maxtab; /* high-water-mark for site tab */
+X char *Grade; /* use this as grade for calls */
+X char *Poll_Pgm; /* our name without path */
+X char *called_as; /* but called by this name */
+X int our_pid; /* our process-id */
+X char *Uucico; /* cico's name without path */
+X char This_Site[MAXHOSTNAMELEN+1]; /* our site name */
+X char System[MAXHOSTNAMELEN+1]; /* intermediate to hold sitename */
+X char *Usort; /* will hold uuname + subcmd */
+X struct passwd *pwd;
+X struct timeval tp;
+X struct timezone tzp;
+X struct Sites Sitetab[SITE_MAX];
+X char workf[300];
+X };
+X
+/* define the prototypes
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *);
+int get_sites(struct Common_Stor *);
+int Check_Args(int argc, char *argv[], struct Common_Stor *);
+int Housekeeping(int argc, char *argv[], struct Common_Stor *);
+int Call_Site(struct Common_Stor *);
+void *storage(unsigned count, char *errloc, int *Rc, struct Common_Stor *);
+X
+extern int getpid();
+extern void free(void *ptr);
+extern int access(char *path, int mode);
+extern int gethostname(char *name, int namelen);
+extern int system(char *cmd);
+extern int fork();
+extern int execlp(char *name, char *arg0, ...);
+extern void *malloc(size_t byteSize);
+extern int getuid();
+extern int isatty(int);
+extern char *ttyname(int);
+extern int open(char *path, int flags, int mode);
+extern int close(int fd);
+#ifdef __STRICT_ANSI__
+extern FILE *popen(char *command, char *type);
+extern int pclose(FILE *stream);
+extern void _exit(int status);
+#endif /* __STRICT_ANSI__ */
+#ifdef __STRICT_BSD__
+extern int fprintf(FILE *stream, const char *format, ...);
+extern int fclose(FILE *stream);
+extern char *strerror(int errnum);
+extern int fflush(FILE *stream);
+extern void exit(int status);
+#endif /* __STRICT_BSD__ */
+X
+/* --------------------------------------------------------------------------*/
+/* Main */
+/* --------------------------------------------------------------------------*/
+X
+int main(int argc, char *argv[])
+{
+X
+X struct Common_Stor *sCom_Sto;
+X int Maxrc = OK; /* Max err-code encountered so far */
+X int k = 0;
+X
+X if ( NULL == (sCom_Sto = malloc(sizeof(struct Common_Stor))) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X argv[0],"Common_Stor",errno,strerror(errno));
+X exit (CAT);
+X }
+X
+X Maxrc = Housekeeping(argc, argv, sCom_Sto);
+X
+/* If any errors popped up so far they are of such a nature that it is very
+X * questionable to continue; so we better bail out in this case.
+X */
+X if (Maxrc <= WARNING) {
+X k = Call_Site(sCom_Sto);
+X Maxrc = Maxrc >= k ? Maxrc:k;
+X }
+X k = gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp);
+X fprintf(stderr,"%s: (I) ended with rc = %i on %s\n",
+X sCom_Sto->called_as,
+X Maxrc,k!=0 ? "time unavailable":ctime(&sCom_Sto->tp.tv_sec));
+X fclose(stderr);
+X free(sCom_Sto);
+X sCom_Sto = NULL;
+X exit (Maxrc);
+}
+X
+/* --------------------------------------------------------------------------*/
+/* Functions */
+/* --------------------------------------------------------------------------*/
+X
+/* --------------------------------------------------------------------
+X * housekeeping
+X */
+X
+int Housekeeping(argc, argv, sCom_Sto)
+X int argc;
+X char *argv[];
+X struct Common_Stor *sCom_Sto; {
+X
+X FILE *seclog = NULL;
+X int Rc = OK;
+X int Rci = OK; /* intermediate rc as returnd by functions */
+X
+X sCom_Sto->our_pid = getpid();
+X
+/*
+X * get our name sans path
+X * */
+X
+X sCom_Sto->called_as = argv[0] + strlen(*argv);
+X for(;sCom_Sto->called_as >= argv[0] && *--sCom_Sto->called_as != '/';)
+X ;
+X sCom_Sto->called_as++;
+X
+/* if defined set up the name of the message log file otherwise
+X * stderr will be used. Setup the cmd string to obtain all known sitenames
+X * which will be sorted in ascending order with duplicates removed
+X * */
+X
+X Rc = set_mlog(&seclog, sCom_Sto);
+X if (Rc > WARNING)
+X return (Rc);
+X
+/* put out the started message including the time and the userid.
+X * */
+X
+X sCom_Sto->pwd = getpwuid(getuid());
+X
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X
+X if (seclog != NULL) {
+X fprintf(seclog,"\n%s: (I) started by `%s' (%s) on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ttyname(0),
+X ctime(&sCom_Sto->tp.tv_sec));
+X fclose(seclog);
+X }
+X fprintf(stderr,"\n%s: (I) started by `%s' on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ctime(&sCom_Sto->tp.tv_sec));
+X
+/* set up the default grade
+X * */
+X
+X sCom_Sto->Grade = dGrade; /* set default for now */
+X if (strlen(cGrade) != 1) {
+X fprintf(stderr,"%s: (W) grade %s invalid; default `%s' used\n",
+X sCom_Sto->called_as,cGrade,sCom_Sto->Grade);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X sCom_Sto->Grade = cGrade; /* Ok, take the one from conf.h */
+X
+/* get the program to actually call the site. This is either UUCICO
+X * or AUTOPOLL or something completely different.
+X * */
+X
+#ifdef AUTO_POLL
+X sCom_Sto->Uucico = Auto_Dir + strlen(Auto_Dir);
+X for(;sCom_Sto->Uucico >= Auto_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+#else /* ! AUTO_POLL */
+X sCom_Sto->Uucico = Cico_Dir + strlen(Cico_Dir);
+X for(;sCom_Sto->Uucico >= Cico_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+#endif /* AUTO_POLL */
+X
+/* get the path to ourself.
+X * */
+X
+X sCom_Sto->Poll_Pgm = argv[0] + strlen(argv[0]);
+X for(;sCom_Sto->Poll_Pgm >= argv[0] && *--(sCom_Sto->Poll_Pgm) != '/';)
+X ;
+X sCom_Sto->Poll_Pgm++;
+X
+/* obtain our sitename
+X * */
+X
+X if ((gethostname(sCom_Sto->This_Site,MAXHOSTNAMELEN+1)) != 0) {
+X fprintf(stderr,"%s: (W) hostname could not be obtained\n",
+X sCom_Sto->called_as);
+X Rc = (Rc >= WARNING) ? Rc:WARNING;
+X }
+X
+/* obtain all known sitenames
+X * */
+X
+X Rci = get_sites(sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+/* check the arguments that we are called with
+X * */
+X
+X Rci = Check_Args(argc, argv, sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * check all relevant arguments that have been passed to us. Those args
+X * that may be needed for a recall will be copied to a workfield.
+X * */
+X
+int Check_Args(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X int i,s,k,n = 0;
+X int Rc = OK;
+X int One_Site = 0; /* TRUE: found at least one valid site to call */
+X int poll_file = 1; /* FALSE: after -x option given */
+X int def_flag = 0; /* TRUE: when option -n was encountered */
+X
+X /* --------------------------------------------------------------*/
+X /* check the arguments passed to us */
+X /* */
+X /* These are: -n -> place a POLL file but do not start uucico */
+X /* -x -> do not place a poll file (immed. poll only) */
+X /* -g? -> specify a grade with the POLL file. The ? */
+X /* may be: 0-9, A-Z, a-z */
+X /* (validity not checked!) */
+X /* site name of the site to call. There many be as */
+X /* many as necessary separated by at least one */
+X /* blank */
+X /* Note: all options will stay in effect as long as they are'nt */
+X /* changed by a new setting. The options -n and -x can't */
+X /* be negated once given; that means place all sites */
+X /* that should be immediately polled to the left of the */
+X /* -n option; the same applies to the -x option which must */
+X /* be left of the -n option to come into effect! */
+X /* The working order is left to right! */
+X /* --------------------------------------------------------------*/
+X
+X for (i = 1, s = 0; i < argc; i++) {
+X k = strlen(argv[i]);
+X switch (*argv[i]) {
+X
+X /* ----> handle the options */
+X
+X case '-':
+X n = 1;
+X switch (*(argv[i]+n)) {
+X case 'n':
+X if (k > 2) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X def_flag = 1;
+X break;
+X case 'x':
+X if (k > 2) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (def_flag) {
+X fprintf(stderr,"%s: (W) -x after -n has no effect\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X poll_file = 0;
+X }
+X break;
+X case 'g':
+X if (k > 3) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (*(argv[i]+n+1) == '\0') {
+X fprintf(stderr,"%s: (E) missing grade\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (isalnum(*(argv[i]+n+1)) == 0) {
+X fprintf(stderr,"%s: (E) invalid grade %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X strcpy(sCom_Sto->Grade,(argv[i]+n+1));
+X break;
+X default:
+X fprintf(stderr,"%s: (W) missing/unknown option `-%s' ignored\n",
+X sCom_Sto->called_as,argv[i]+n);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X } /* end of switch (*(argv[i]+n)) */
+X break;
+X
+X /* ----> handle the sitenames */
+X
+X default:
+X if (strcmp(argv[i],sCom_Sto->This_Site) == 0) {
+X fprintf(stderr,"%s: (W) ignoring to call *ourself* %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X }
+X strcpy(sCom_Sto->System,argv[i]);
+X for(s=0;s<=sCom_Sto->maxtab;s++) {
+X if ((n=strcmp(sCom_Sto->Sitetab[s].name,sCom_Sto->System)) >= 0) {
+X break;
+X }
+X }
+X if (n != 0) {
+X fprintf(stderr,"%s: (W) unknown site (ignored): %s\n",
+X sCom_Sto->called_as,sCom_Sto->System);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X }
+X
+X /* ----> if there was no error we arrive here to save the data */
+X
+X strcpy(sCom_Sto->Sitetab[s].grade,sCom_Sto->Grade);
+X One_Site = sCom_Sto->Sitetab[s].flag = 1; /* poll this site */
+X if (def_flag)
+X sCom_Sto->Sitetab[s].asap = 0; /* poll on next schedule */
+X else {
+X sCom_Sto->Sitetab[s].asap = 1; /* poll immediately */
+X if (! poll_file)
+X sCom_Sto->Sitetab[s].asap++; /* and do not place a poll file */
+X }
+X s++;
+X break;
+X } /* end of switch (*argv[i]) */
+X } /* end of for(...) */
+X
+/* now let's check what we've gotten so far. If no valid data has been */
+/* entered we will indicate that to prevent further processing */
+X
+X if (! One_Site) {
+X fprintf(stderr,"%s: (E) found no site to call\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X
+return (Rc);
+}
+X
+int Call_Site(struct Common_Stor *sCom_Sto) {
+X
+/* For all sites that carry the -n flag we will place */
+/* a poll file into the appropriate directory. For all others there will */
+/* be an immediate call to uucico (or autopoll) */
+/* Those sites that have been named on the command have the corresponding */
+/* flag byte set to one. */
+X
+X int fdpoll; /* fildes for the poll file */
+X int mode = P_MODE; /* mode for poll file */
+X int i = 0;
+X int Rc = OK;
+X int pid = 0; /* process-id after fork() */
+X
+X for(i=0;(i<=sCom_Sto->maxtab);i++) {
+X if (sCom_Sto->Sitetab[i].flag == 0) /* should we trigger this one ? */
+X continue; /* nope */
+X
+/* processing done for delayed polls only */
+X
+X if (sCom_Sto->Sitetab[i].asap <= 1) { /* do not place a poll file */
+X /* for sites that will be polled */
+X /* immediate and carry the -x option */
+#ifdef HAVE_SPOOLDIR_TAYLOR
+X sprintf(sCom_Sto->workf,"%s/%s/C./C.%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+#ifdef HAVE_SPOOLDIR_HDB
+X sprintf(sCom_Sto->workf,"%s/%s/C.%s%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+#ifdef HAVE_SPOOLDIR_BSD
+X sprintf(sCom_Sto->workf,"%s/C./C.%s%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+X
+X fflush(stderr);
+X if ((fdpoll=open(sCom_Sto->workf,O_CREAT,mode)) <= 0) {
+X fprintf(stderr,"%s: (E) couldn't place poll file for system: %s. Reason: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X if (close(fdpoll) != 0) {
+X fprintf(stderr,"%s: (W) close failed for poll file; system: %s. Reason: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X strerror(errno));
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X }
+X }
+X
+/* the following processing is done for immediate polls only
+X * there is no wait for the completion of the called program that actually
+X * calls the site
+X * */
+X
+X fflush(stderr);
+X if (Rc <= WARNING) {
+X fprintf(stderr,"%s: (I) site %s will be called %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].asap == 0 ?
+X "upon next poll":"immediately");
+X if (sCom_Sto->Sitetab[i].asap >= 1)
+X {
+#ifdef AUTO_DIR
+X if ( access(Auto_Dir,X_OK) != 0) /* do we have xecute permission ? */
+#else /* ! AUTO_DIR */
+X if ( access(Cico_Dir,X_OK) != 0) /* do we have xecute permission ? */
+#endif /* AUTO_DIR */
+X {
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT); /* abandon the run */
+X }
+X switch (pid = fork())
+X {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork() Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X case 0:
+X if (isatty(0))
+X close(0); /* don't block the terminal by autopoll */
+#ifdef AUTO_DIR
+X execlp(Auto_Dir,
+#else /* ! AUTO_DIR */
+X execlp(Cico_Dir,
+#endif /*AUTO_DIR */
+X sCom_Sto->Uucico,
+X "-D", "-r1", "-s",
+X sCom_Sto->Sitetab[i].name,0);
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fflush(stderr);
+X fprintf(stderr,"%s: (I) %s [%d] started; site: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X pid,
+X sCom_Sto->Sitetab[i].name);
+X } /* switch (pid = fork()) */
+X } /* if (Sitetab ...) */
+X } /* if (Rc ...) */
+X } /* for(i=0;(i<= ...)) */
+X return (Rc);
+}
+X
+X /* ------------------------------------------------------------------
+X * storage - get some memory
+X */
+X
+void *storage(unsigned count,
+X char *location,
+X int *Rc,
+X struct Common_Stor *sCom_Sto)
+{
+X void *p;
+X
+X if( NULL == (p= malloc(count)) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X sCom_Sto->called_as,location,errno,strerror(errno));
+X *Rc = *Rc >= CAT ? *Rc:CAT;
+X }
+X return p;
+}
+X
+/* ------------------------------------------------------------------
+X * if defined open the message log file otherwise all mesages will go
+X * to stderr. If UNAME_DIR is defined construct the command to be
+X * passed to popen(); if undefined the default will be used
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *sCom_Sto) {
+X
+X int Rc = 0;
+X
+#ifdef ALOG_FILE
+X if (!isatty(0)) {
+X if ((freopen(Msg_Log,"a",stderr)) == NULL) {
+X fprintf(stdout,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+X else {
+X if ((*seclog = fopen(Msg_Log,"a")) == NULL) {
+X fprintf(stderr,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+#endif /* ALOG_FILE */
+X
+/* set up the pipe together with the complete path to uuname */
+X
+#ifdef UNAME_DIR
+X if ((sCom_Sto->Usort = (char *)storage (sizeof(UNAME_DIR)+sizeof(subcmd),
+X "Sort",&Rc, sCom_Sto)) != NULL) {
+X strncpy(sCom_Sto->Usort,UNAME_DIR,strlen(UNAME_DIR)); /* paste in the path */
+X strcat(sCom_Sto->Usort,subcmd); /* chain the pipe to it */
+X }
+#else /* ! UNAME_DIR */
+X sCom_Sto->Usort = &Sort; /* set pointer to uuname + sort */
+#endif /* UNAME_DIR */
+X
+X return (Rc);
+}
+X
+/* ------------------------------------------------------------------
+X * obtain all active sitenames
+X * */
+X
+int get_sites(struct Common_Stor *sCom_Sto) {
+X
+X int i = 0;
+X int n;
+X int Rc = 0;
+X FILE *infile;
+X
+X if ((infile=popen(sCom_Sto->Usort,"r")) != NULL) {
+X while(fgets(sCom_Sto->Sitetab[i].name,MAXHOSTNAMELEN+1,infile)) {
+X if (i > SITE_MAX) { /* let'm run so that we can give */
+X i++; /* the user some guidance */
+X continue; /* we'll tell the user later on */
+X }
+X n = strlen(sCom_Sto->Sitetab[i].name)-1; /* offset: next to last char */
+X sCom_Sto->Sitetab[i].name[n] = '\0'; /* strip trailing newline */
+X sCom_Sto->Sitetab[i].flag = FALSE; /* TRUE: poll this site */
+X sCom_Sto->Sitetab[i].asap = FALSE; /* TRUE: immediate poll */
+X strcpy(sCom_Sto->Sitetab[i].grade,sCom_Sto->Grade);
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X sCom_Sto->maxtab = i++; /* set high-water-mark */
+X }
+X if (ferror(infile) != 0) {
+X fprintf(stderr,"%s: (E) fgets() for sitenames failed reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X pclose(infile);
+X
+X /*
+X * check for an empty table (strange but possible)
+X */
+X
+X if (sCom_Sto->maxtab == 0) {
+X fprintf(stderr,"%s: (E) could not obtain sitenames.\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X
+X /* in case the internal table overflows we'll now give notice and tell
+X * the user by which amount the table has to be increased to hold all
+X * site-names
+X */
+X
+X if (i > SITE_MAX) {
+X fprintf(stderr,"%s: (E) number of sites > internal tab\n",
+X sCom_Sto->called_as);
+X fprintf(stderr,"%s: (E) increase SITE_MAX to >= %d and recompile\n",
+X sCom_Sto->called_as,i);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* sCom_Sto->maxtab == 0 */
+X
+X }
+X else /* infile == NULL */
+X {
+X fprintf(stderr,"%s: (E) could not sort sitenames. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X
+X } /* if ((infile=popen(sCom_Sto->Usort,"r")) ... */
+X
+X return (Rc);
+}
+SHAR_EOF
+chmod 0444 uupoll/uupoll.c ||
+echo 'restore of uupoll/uupoll.c failed'
+Wc_c="`wc -c < 'uupoll/uupoll.c'`"
+test 27587 -eq "$Wc_c" ||
+ echo 'uupoll/uupoll.c: original size 27587, current size' "$Wc_c"
+fi
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uurate.c b/gnu/libexec/uucp/contrib/uurate.c
index ceab41c53bfd..80972f611baf 100644
--- a/gnu/libexec/uucp/contrib/uurate.c
+++ b/gnu/libexec/uucp/contrib/uurate.c
@@ -5,16 +5,16 @@
* and outputs various statistical data to standard out.
*
* Author:
- * Bob Denny (denny@alisa.com)
- * Fri Feb 7 13:38:36 1992
+ * Bob Denny (denny@alisa.com)
+ * Fri Feb 7 13:38:36 1992
*
* Original author:
- * Mark Pizzolato mark@infopiz.UUCP
+ * Mark Pizzolato mark@infopiz.UUCP
*
* Edits:
- * Bob Denny - Fri Feb 7 15:04:54 1992
- * Heavy rework for Taylor UUCP. This was the (very old) uurate from
- * DECUS UUCP, which had a single logfile for activity and stats.
+ * Bob Denny - Fri Feb 7 15:04:54 1992
+ * Heavy rework for Taylor UUCP. This was the (very old) uurate from
+ * DECUS UUCP, which had a single logfile for activity and stats.
* Personally, I would have done things differently, with tables
* and case statements, but in the interest of time, I preserved
* Mark Pizzolato's techniques and style.
@@ -23,41 +23,165 @@
* Changes to report format suggested by Francois Pinard and others.
* Add summary report, format from uutraf.pl (perl script), again
* thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
+ *
+ * Stephan Niemz <stephan@sunlab.ka.sub.org> - Fri Apr 9 1993
+ * - Print totals in summary report,
+ * - show all commands in execution report,
+ * - count incoming calls correctly,
+ * - suppress empty tables,
+ * - don't divide by zero in efficiency report,
+ * - limit the efficiency to 100% (could be more with the i-protocol),
+ * - suppress some zeros to improve readability,
+ * - check for failure of calloc,
+ * - -h option changed to -s for consistency with all other uucp commands
+ * (but -h was left in for comptibility).
+ *
+ * Scott Boyd <scott@futures.com> - Thu Aug 26 13:21:34 PDT 1993
+ * - Changed hosts linked-list insertion routine so that hosts
+ * are always listed in alphabetical order on reports.
+ *
+ * Klaus Dahlenburg <kdburg@incoahe.hanse.de> - Fri Jun 18 1993 (1.2.2)
+ * - redesigned the printed layout (sticked to those 80 column tubes).
+ * - 'Retry time not ...' and ' ERROR: All matching ports ...' will now be
+ * counted as calls and will raise the failed-call counter.
+ * - times now shown as hh:mm:ss; the fields may hold up to 999 hrs
+ * (a month equals 744 hrs at max). Printing will be as follows:
+ *
+ * hrs > 0 hh:mm:ss
+ * min > 0 mm:ss
+ * sec > 0 ss
+ * leading zeroes are suppressed.
+ *
+ * - the bytes xfered will be given in thousands only (we're counting
+ * so 1K is 1000 bytes!). Sums up to 9,999,999.9 thousand can be shown.
+ * - dropped the fractions of a byte in columns: bytes/second (avg cps).
+ * - File statistic changed to display in/out in one row instead of 2
+ * separate reports.
+ * - eliminated the goto in command report and tightened the code; also
+ * the 'goto usage' has been replaced by a call to void usage() with no
+ * return (exit 1).
+ * - a totaling is done for all reports now; the total values are held
+ * within the structure; after finishing read there will be an alloc
+ * for a site named 'Total' so that the totals line will be printed
+ * more or less automatically.
+ * - option -t implemented: that is every possible report will be given.
+ * - the start and end date/time of the input files are printed; can be
+ * dropped by the -q option at run time.
+ * - it is now possible to use Log/Stats files from V2_LOGGING configs.
+ * They must however not be mixed together (with each other).
+ * - the Log/Stats files are taken from config which is passed via
+ * Makefile at compile time. Variable to set is: newconfigdir. If the
+ * default config can't be read the default values are used
+ * (the config is optional!).
+ * Note: keyword/filename must be on the same line (no continuation).
+ * - -I option implemented to run with a different config file. In case
+ * the file can't be opened the run is aborted!
+ * - -q option implemented to run without environment report (default is
+ * FALSE: print the report).
+ * - -p option added to print protocol statistics: one for the packets
+ * and one for the errors encountered
+ * - reapplied patch by Scott Boyd <scott@futures.com> that I did not
+ * get knowledge of
*/
+/* $Log: uurate.c,v $
+ * Revision 1.2 1994/05/07 18:09:35 ache
+ * Upgrade to version 1.05
+ *
+ * Revision 1.15 1994/04/07 21:47:11 kdburg
+ * printed 'no data avail' while there was data; layout chnaged
+ * (cosmetic only)
+ *
+ * Revision 1.14 1994/04/07 21:16:32 kdburg
+ * the layout of the protocol-used line within the LOGFILE changed
+ * from 1.04 to 1.05; both formats may be used together; output
+ * changed for packet report (columns adjusted)
+ *
+ * Revision 1.13 1994/04/04 10:04:35 kdburg
+ * cosmetic change to the packet-report (separator lines)
+ *
+ * Revision 1.12 1994/03/30 19:52:04 kdburg
+ * incorporated patch by Scott Boyd which was missing from this version
+ * of uurate.c. Left the comment in cronological order.
+ *
+ * Revision 1.11 1994/03/28 18:53:22 kdburg
+ * config not checked properly for 'logfile/statsfile' overwrites, bail-out
+ * possible; wrong file name written to log for statsfile when found
+ *
+ * Revision 1.10 1993/09/28 16:46:51 kdburg
+ * transmission failures denoted by: failed after ... in stats file
+ * have not been counted at all.
+ *
+ * Revision 1.9 1993/08/17 23:38:36 kdburg
+ * sometimes a line(site) was missing from the protocol stats due
+ * to a missing +; added option -d and -v reassing option -h to print
+ * the help; a zero was returned instead of a null-pointer by
+ * prot_sum
+ *
+ * Revision 1.8 1993/07/03 06:58:55 kdburg
+ * empty input not handled properly; assigned some buffer to input; msg
+ * not displayed when no protocol data was available
+ *
+ * Revision 1.7 1993/06/27 10:31:53 kdburg
+ * rindex was replaced by strchr must be strrchr
+ *
+ * Revision 1.6 1993/06/26 06:59:18 kdburg
+ * switch hdr_done not reset at beginning of protocol report
+ *
+ * Revision 1.5 1993/06/25 22:22:30 kdburg
+ * changed rindex to strchr; if there is no NEWCONFIG defined take
+ * appropriate action
+ *
+ * Revision 1.4 1993/06/25 20:04:07 kdburg
+ * added comment about -p option; inserted proto for rindex
+ *
+ * Revision 1.3 1993/06/25 19:31:14 kdburg
+ * major rework done; added protocol reports (normal/errors)
+ *
+ * Revision 1.2 1993/06/21 19:53:54 kdburg
+ * init
+ * */
-char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2";
-
-#include <ctype.h> /* Character Classification */
-#include <string.h>
+char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2.2";
+static char rcsid[] = "$Id: uurate.c,v 1.2 1994/05/07 18:09:35 ache Exp $";
+#include <ctype.h> /* Character Classification */
#include <math.h>
-
#include "uucp.h"
+/* uucp.h includes string.h or strings.h, no include here. */
#define _DEBUG_ 0
-
+
/*
* Direction of Calling and Data Transmission
*/
-#define IN 0 /* Inbound */
-#define OUT 1 /* Outbound */
+
+#define IN 0 /* Inbound */
+#define OUT 1 /* Outbound */
+
+/*
+ * define some limits
+ */
+#define MAXCOLS 8 /* report has this # of columns incl. 'name' */
+#define MAXREP 6 /* number of reports available */
+#define MAXFNAME 64 /* max input file name length incl. path*/
+#define MAXDNAME 8 /* max display (Hostname) name length */
/*
* Data structures used to collect information
*/
struct File_Stats
{
- int files; /* Files Transferred */
- unsigned long bytes; /* Data Size Transferred*/
- double time; /* Transmission Time */
+ int files; /* Files Transferred */
+ unsigned long bytes; /* Data Size Transferred*/
+ double time; /* Transmission Time */
};
struct Phone_Call
{
- int calls; /* Call Count */
- int succs; /* Successful calls */
- double connect_time; /* Connect Time Spent */
- struct File_Stats flow[2]; /* Rcvd & Sent Data */
+ int calls; /* Call Count */
+ int succs; /* Successful calls */
+ double connect_time; /* Connect Time Spent */
+ struct File_Stats flow[2]; /* Rcvd & Sent Data */
};
struct Execution_Command
@@ -67,591 +191,1664 @@ struct Execution_Command
int count;
};
+struct Protocol_Summary
+ {
+ struct Protocol_Summary *next;
+ char type[3];
+ long int pr_cnt;
+ long int pr_psent;
+ long int pr_present;
+ long int pr_preceived;
+ long int pr_eheader;
+ long int pr_echksum;
+ long int pr_eorder;
+ long int pr_ereject;
+ long int pr_pwinmin;
+ long int pr_pwinmax;
+ long int pr_psizemin;
+ long int pr_psizemax;
+ };
+
struct Host_entry
{
struct Host_entry *next;
char Hostname[32];
- struct Execution_Command *cmds; /* Local Activities */
- struct Phone_Call call[2]; /* In & Out Activities */
+ struct Execution_Command *cmds; /* Local Activities */
+ struct Phone_Call call[2]; /* In & Out Activities */
+ struct Protocol_Summary *proto;
};
+ struct Host_entry *hosts = NULL;
+ struct Host_entry *tot = NULL;
+ struct Host_entry *cur = NULL;
+ struct Execution_Command *cmd, *t_cmds = NULL;
+ struct Protocol_Summary *prot, *t_prot, *s_prot, *ss_prot = NULL;
/*
* Stuff for getopt()
*/
-extern int optind; /* GETOPT : Option Index */
-extern char *optarg; /* GETOPT : Option Value */
-extern void *calloc();
-
-static void fmtime();
-static void fmbytes();
+extern int optind; /* GETOPT : Option Index */
+extern char *optarg; /* GETOPT : Option Value */
+#if ! HAVE_STDLIB_H
+ extern pointer *calloc();
+#endif /* HAVE_STDLIB_H */
/*
* Default files to read. Taken from Taylor compile-time configuration.
- * Must look like an argvec, hence the dummy argv[0].
+ * def_logs must look like an argvec, hence the dummy argv[0].
+ * Maybe later modified by scanning the config
*/
-static char *(def_logs[3]) = { "", LOGFILE, STATFILE };
+
+static char *def_logs[3] = { NULL, NULL, NULL};
+char *I_conf = NULL; /* points to config lib given by -I option */
+char *D_conf = NULL; /* points to config lib from makefile */
+char *Tlog = NULL; /* points to Log-file */
+char *Tstat = NULL; /* points to Stats-file */
+char Pgm_name[64]; /* our pgm-name */
+char logline[BUFSIZ+1]; /* input area */
+char noConf[] = "- not defined -";
+char buff[16*BUFSIZ];
+char sbuff[2*BUFSIZ];
/*
- * Misc. strings for reports
+ * Boolean switches for various decisions
*/
-static char *(file_hdr[2]) = { "\nReceived file statistics:\n",
- "\nSent file statistics\n" };
-
+
+ int p_done = FALSE; /* TRUE: start date/time of file printed */
+ int hdr_done = FALSE; /* TRUE: report header printed */
+ int show_files = FALSE; /* TRUE: -f option given */
+ int show_calls = FALSE; /* TRUE: -c option given */
+ int show_commands = FALSE; /* TRUE: -x option given */
+ int show_efficiency = FALSE; /* TRUE: -e option given */
+ int show_all = FALSE; /* TRUE: -t option given */
+ int show_proto = FALSE; /* TRUE: -p option given */
+ int use_stdin = FALSE; /* TRUE: -i option given */
+ int be_quiet = FALSE; /* TRUE: -q option given */
+ int have_files[2]; /* TRUE: [IN] or [OUT] files found */
+ int have_calls = FALSE; /* TRUE: in/out calls found */
+ int have_commands = FALSE; /* TRUE: found uuxqt records */
+ int have_proto = FALSE; /* TRUE: protocol data found */
+ int no_records = TRUE; /* FALSE: got one record from file */
+
+/*
+ * protos
+ */
+
+static pointer *getmem(unsigned n);
+static void inc_cmd(struct Execution_Command **, char *name);
+static void fmtime(double sec, char *buf);
+static void fmbytes(unsigned long n, char *buf);
+static void usage();
+static int chk_config(char *conf, int n, int type);
+static void hdrprt(char c, int bot);
+struct Protocol_Summary *prot_sum(struct Protocol_Summary **, char *, int);
+
/*
* BEGIN EXECUTION
*/
-main(argc, argv)
-int argc;
-char *argv[];
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
{
- char c;
- char *p, *s;
- struct Host_entry *hosts = NULL;
- struct Host_entry *cur = NULL;
- struct Host_entry *e;
- struct Execution_Command *cmd;
- struct Execution_Command *ec;
- char Hostname[64];
FILE *Log = NULL;
- char logline[1024];
+ int c;
+ char *p, *s, *stt, *flq = NULL;
+ char Hostname[MAXHOSTNAMELEN]; /* def taken from <sys/param.h> */
+ char Filename[15]; /* filename to be printed */
+ char in_date[14]; /* holds the date info of record read*/
+ char in_time[14]; /* holds the time info of record read */
+ char dt_info[31]; /* holds the date info from the last record read */
char *logmsg;
- int sent;
- int called;
- int show_files = 0; /* I prefer boolean, but... */
- int show_calls = 0;
- int show_commands = 0;
- int show_efficiency = 0;
- int show_summary = 0;
- int have_files = 0;
- int have_calls = 0;
- int have_commands = 0;
- int use_stdin = 0;
- Hostname[0] = '\0';
+ int sent, called = IN;
+ int report = 0; /* if <= 0 give msg that no report was avail. */
+ int junk;
+
+ /* --------------------------------------------------------------------
+ * P r o l o g
+ * --------------------------------------------------------------------
+ */
+
+ Hostname[0] = '\0';
+ have_files[IN]= have_files[OUT]= FALSE;
+ setvbuf(stdout,sbuff,_IOFBF,sizeof(sbuff));
+
+ /*
+ * get how we've been called isolate the name from the path
+ */
+ if ((stt = strrchr(argv[0],'/')) != NULL)
+ strcpy(Pgm_name,++stt);
+ else
+ strcpy(Pgm_name,argv[0]);
+ def_logs[0] = Pgm_name;
+
/*
* I wish the compiler had the #error directive!
*/
-#if !HAVE_TAYLOR_LOGGING
- fprintf(stderr, "uurate cannot be used with your configuration of\n");
- fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n");
- fprintf(stderr, "TAYLOR_LOGGING configuration.\n");
+
+#if !HAVE_TAYLOR_LOGGING && !HAVE_V2_LOGGING
+ fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,"Your config of Taylor UUCP is not yet supported.");
+ fprintf(stderr,"%s: (E) %s\n",Pgm_name,"Current support is for V2 or TAYLOR logging only.");
+ puts(" Run aborted due to errors\n")
exit(1);
#endif
/*
- * Process the command line arguments
+ * get some mem to store the default config name (def's are in
+ * policy.h )
*/
- while((c = getopt(argc, argv, "h:cfexai")) != EOF)
- {
- switch(c)
- {
- case 'h':
- strcpy(Hostname, optarg);
- break;
- case 'c':
- show_calls = 1;
- break;
- case 'f':
- show_files = 1;
- break;
- case 'x':
- show_commands = 1;
- break;
- case 'e':
- show_efficiency = 1;
- break;
- case 'a':
- show_calls = show_files = show_commands = show_efficiency = 1;
- break;
- case 'i':
- use_stdin = 1;
- break;
- default :
- goto usage;
- }
- }
+ if (sizeof(NEWCONFIGLIB) > 1) /* defined at compile time */
+ {
+ D_conf = (char *)getmem((sizeof(NEWCONFIGLIB) + sizeof("/config")));
+ strcpy(D_conf,NEWCONFIGLIB); /* passed by makefile */
+ strcat(D_conf,"/config");
+ }
+ Tlog = (char *)getmem(sizeof(LOGFILE));
+ Tstat = (char *)getmem(sizeof(STATFILE));
+ Tlog = LOGFILE;
+ Tstat = STATFILE;
+
/*
- * If no report switches given, show summary report.
+ * Process the command line arguments
*/
- if (show_calls == 0 && show_files == 0
- && show_efficiency == 0 && show_commands == 0)
- show_summary = 1;
-
+
+ while((c = getopt(argc, argv, "I:s:cfdexaitphv")) != EOF)
+ {
+ switch(c)
+ {
+ case 'h':
+ (void) usage();
+ case 's':
+ strcpy(Hostname, optarg);
+ break;
+ case 'c':
+ show_calls = TRUE;
+ ++report;
+ break;
+ case 'd':
+ printf("%s: (I) config-file default: %s\n",Pgm_name,D_conf);
+ exit (0);
+ break;
+ case 'f':
+ show_files = TRUE;
+ ++report;
+ break;
+ case 'x':
+ show_commands = TRUE;
+ ++report;
+ break;
+ case 'e':
+ show_efficiency = TRUE;
+ ++report;
+ break;
+ case 'a':
+ show_calls = show_files = show_commands = show_efficiency = TRUE;
+ report = 4;
+ break;
+ case 'i':
+ use_stdin = TRUE;
+ break;
+ case 't':
+ show_all = TRUE;
+ report = MAXREP;
+ break;
+ case 'p':
+ show_proto = TRUE;
+ ++report;
+ break;
+ case 'I':
+ I_conf = (char *)getmem(sizeof(optarg));
+ I_conf = optarg;
+ break;
+ case 'q':
+ be_quiet = TRUE;
+ break;
+ case 'v':
+ printf("%s\n",rcsid);
+ exit (0);
+ default :
+ (void) usage();
+ }
+ }
+ if (report == 0) /* no options given */
+ ++report; /* at least summary can be printed */
+ if (! be_quiet)
+ hdrprt('i',0); /* print header for environment info */
+
/*
* Adjust argv and argc to account for the args processed above.
*/
+
argc -= (optind - 1);
argv += (optind - 1);
/*
- * If further args present, Assume rest are logfiles for us to process,
- * otherwise, take input from Log and Stat files provided in the
- * compilation environment of Taylor UUCP. If -i was given, Log already
- * points to stdin and no file args are accepted.
+ * If further args present, Assume rest are logfiles for us to process
+ * which should be given in pairs (log plus stat) otherwise the results may
+ * not come out as expected! If no further args are present take input from
+ * Log and Stat files provided in the compilation environment of Taylor UUCP.
+ * If -i was given, Log already points to stdin and no file args are accepted.
+ */
+
+ if (use_stdin) /* If -i, read from stdin */
+ {
+ if (argc != 1) /* No file arguments allowed */
+ {
+ fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,
+ "it's not posssible to give file args with '-i'");
+ (void) usage();
+ }
+ else
+ {
+ argc = 2;
+ Log = stdin;
+ if (! be_quiet)
+ puts(" Input from stdin; no other files will be used\n");
+ }
+ }
+ else
+ {
+ if (argc != 1) /* file arguments are present */
+ {
+ if (! be_quiet)
+ puts(" No defaults used; will use passed file arguments\n");
+ }
+ else /* Read from current logs */
+ {
+ def_logs[1] = Tlog; /* prime the */
+ def_logs[2] = Tstat; /* file names */
+ if (! be_quiet)
+ printf(" Config for this run: ");
+
+ if (I_conf != NULL)
+ {
+ junk = 0;
+ if (! be_quiet)
+ printf("%s\n",I_conf);
+ if (0 != (chk_config(I_conf,be_quiet,junk)))
+ return (8);
+ }
+ else
+ {
+ if (D_conf != NULL)
+ {
+ junk = 1; /* indicate default (compiled) config */
+ if (! be_quiet)
+ printf("%s\n",D_conf);
+ chk_config(D_conf,be_quiet,junk);
+ }
+ else
+ if (! be_quiet)
+ printf("%s\n",noConf);
+ }
+ def_logs[1] = Tlog; /* final setting of */
+ def_logs[2] = Tstat; /* file names */
+ argv = def_logs; /* Bash argvec to log/stat files */
+ argc = sizeof(def_logs) / sizeof(def_logs[0]);
+ }
+ }
+
+ /* --------------------------------------------------------------------
+ * MAIN LOGFILE PROCESSING LOOP
+ * --------------------------------------------------------------------
*/
- if(argc == 1) /* No file arguments */
+
+ if (!use_stdin)
+ {
+ if (argc < 3 && ! be_quiet)
+ {
+ puts(" (W) there is only one input file!");
+ puts(" (W) some reports may not be printed");
+ }
+ if (! be_quiet)
+ hdrprt('d',0); /* give subheaderline */
+ }
+
+ while (argc > 1)
+ {
+ if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
{
- if (use_stdin) /* If -i, read from stdin */
- {
- argc = 2;
- Log = stdin;
- }
- else /* Read from current logs */
- {
- argc = 3; /* Bash argvec to default log/stat files */
- argv = &def_logs[0];
- }
+ perror(argv[1]);
+ exit (8);
}
- else if (use_stdin) /* File args with -i is an error */
+ setvbuf(Log,buff,_IOFBF,sizeof(buff));
+ if ((flq = strrchr(argv[1], '/')) == NULL)
+ strncpy(Filename,argv[1],sizeof(Filename)-1);
+ else
+ strncpy(Filename,++flq,sizeof(Filename)-1);
+
+ strcpy(in_date," n/a");
+ strcpy(in_time," n/a");
+ p_done = FALSE; /* no info printed yet */
+ no_records = TRUE; /* not read any record yet */
+
+ /*
+ * Read each line of the logfile and collect information
+ */
+
+ while (fgets(logline, sizeof(logline), Log))
{
- fprintf(stderr, "uurate (error): file args given with '-i'\n");
- goto usage;
+ /*
+ * The host name of the other end of the connection is
+ * always the second field of the log line, whether we
+ * are reading a Log file or a Stats file. Set 'p' to
+ * point to the second field, null-terminated. Skip
+ * the line if something is funny. V2 and Taylor ar identical
+ * up to this part. Put out the start/end date of the files read;
+ */
+
+ if (NULL == (p = strchr(logline, ' ')))
+ continue;
+ no_records = FALSE; /* got one (usable) record at least */
+ ++p;
+
+ if (NULL != (stt = strchr(p, '(')))
+ {
+ if (! p_done && ! use_stdin && ! be_quiet)
+ {
+
+#if HAVE_TAYLOR_LOGGING
+ sscanf(++stt,"%s%*c%[^.]",in_date,in_time);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+#if HAVE_V2_LOGGING
+ sscanf(++stt,"%[^-]%*c%[1234567890:]",in_date,in_time);
+#endif /* HAVE_V2_LOGGING */
+
+ printf(" %-14s %10s %8s",Filename, in_date, in_time);
+ strcpy(in_date," n/a"); /* reset to default */
+ strcpy(in_time," n/a");
+ p_done = TRUE;
+ }
+ else
+ {
+ if (! use_stdin && ! be_quiet) /* save for last time stamp prt. */
+ strncpy(dt_info,++stt,sizeof(dt_info)-1);
+ }
+ }
+
+ if (NULL != (s = strchr(p, ' ')))
+ *s = '\0';
+ for (s = p; *s; ++s)
+ if (isupper(*s))
+ *s = tolower(*s);
+
+ /*
+ * Skip this line if we got -s <host> and
+ * this line does not contain that host name.
+ * Don't skip the `incoming call' line with the system name `-'.
+ */
+
+ if (Hostname[0] != '\0')
+ if ( (p[0] != '-' || p[1] != '\0') && 0 != strcmp(p, Hostname) )
+ continue;
+
+ /*
+ * We are within a call block now. If this line is a file
+ * transfer record, determine the direction. If not then
+ * skip the line if it is not interesting.
+ */
+
+ if ((s = strchr(++s, ')')) == NULL)
+ continue;
+
+#if ! HAVE_TAYLOR_LOGGING
+#if HAVE_V2_LOGGING
+ if ((strncmp(s,") (",3)) == 0) /* are we in stats file ?) */
+ if ((s = strchr(++s, ')')) == NULL)
+ continue; /* yes but strange layout */
+#endif /* HAVE_V2_LOGGING */
+#endif /* ! HAVE_TAYLOR_LOGGING */
+
+ logmsg = s + 2; /* Message is 2 characters after ')' */
+ if ((0 != strncmp(logmsg, "Call complete", 13)) &&
+ (0 != strncmp(logmsg, "Calling system", 14)) &&
+ (0 != strncmp(logmsg, "Incoming call", 13)) &&
+ (0 != strncmp(logmsg, "Handshake successful", 20)) &&
+ (0 != strncmp(logmsg, "Retry time not", 14)) &&
+ (0 != strncmp(logmsg, "ERROR: All matching ports", 25)) &&
+ (0 != strncmp(logmsg, "Executing", 9)) &&
+ (0 != strncmp(logmsg, "Protocol ", 9)) &&
+ (0 != strncmp(logmsg, "sent ", 5)) &&
+ (0 != strncmp(logmsg, "received ", 9)) &&
+ (0 != strncmp(logmsg, "failed after ", 13)) &&
+ (0 != strncmp(logmsg, "Errors: ", 8)))
+ continue;
+
+ /*
+ * Find the Host_entry for this host, or create a new
+ * one and link it on to the list.
+ */
+
+ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
+ {
+ struct Host_entry *e, *last;
+
+ for (e= cur= hosts; cur != NULL ; e= cur, cur= cur->next)
+ if (0 == strcmp(cur->Hostname, p))
+ break;
+ if (cur == NULL)
+ {
+ cur= (struct Host_entry *)getmem(sizeof(*hosts));
+ strcpy(cur->Hostname, p);
+ if (hosts == NULL)
+ e= hosts= cur;
+ else {
+ e = hosts;
+ last = NULL;
+ while (e != NULL) {
+ if (strcmp(e->Hostname, cur->Hostname) <= 0) {
+ if (e->next == NULL) {
+ e->next = cur;
+ break;
+ }
+ last = e;
+ e = e->next;
+ }
+ else {
+ cur->next = e;
+ if (last == NULL)
+ hosts = cur;
+ else
+ last->next = cur;
+ break;
+ }
+ } /* while (e != NULL) */
+ } /* hosts == NULL */
+ } /* cur == NULL */
+ }
+
+ /*
+ * OK, if this is a uuxqt record, find the Execution_Command
+ * structure for the command being executed, or create a new
+ * one. Then count an execution of this command.
+ * (Log file only)
+ */
+
+ if (0 == strncmp(logmsg, "Executing", 9))
+ {
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if ((s = strpbrk(++p, " )")) == NULL)
+ continue;
+ *s = '\0';
+ inc_cmd(&cur->cmds, p);
+ inc_cmd(&t_cmds, p);
+ have_commands = TRUE;
+ continue;
+ }
+
+ /*
+ * Count start of outgoing call.
+ */
+
+ if ((0 == strncmp(logmsg, "Calling system", 14)) ||
+ (0 == strncmp(logmsg, "Retry time not", 14)) ||
+ (0 == strncmp(logmsg, "ERROR: All matching ports", 25)))
+ {
+ called = OUT;
+ cur->call[OUT].calls++;
+ have_calls = TRUE;
+ s_prot = NULL; /* destroy pointer to protocol */
+ continue;
+ }
+
+ /*
+ * Count start of incoming call.
+ */
+
+ if (0 == strncmp(logmsg, "Incoming call", 13))
+ {
+ called = IN;
+ s_prot = NULL; /* destroy pointer to protocol */
+ continue;
+ }
+
+ /*
+ * On an incoming call, get system name from the second line.
+ * Get protocol type and size/window too
+ */
+
+ if (0 == strncmp(logmsg, "Handshake successful", 20))
+ {
+ if ( called==IN )
+ cur->call[IN].calls++;
+ have_calls = TRUE;
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if (0 == strncmp(p, "(protocol ", 10))
+ {
+ if (NULL == (p = strchr(p, '\'')))
+ continue;
+ ss_prot = prot_sum(&cur->proto, ++p, 1);
+ s_prot = prot_sum(&t_prot, p, 1);
+ continue;
+ }
+ }
+
+ /*
+ * check protocol type and get stats
+ *
+ */
+
+ if (0 == strncmp(logmsg, "Protocol ", 9))
+ {
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (p = strchr(logmsg, '\'')))
+ continue;
+ ss_prot = prot_sum(&cur->proto, ++p, 2);
+ s_prot = prot_sum(&t_prot, p, 2);
+ continue;
+ }
+
+ /*
+ * check protocol errors. Unfortunately the line does not contain
+ * the used protocol, so if any previous line did contain that
+ * information and we did process that line we will save the pointer
+ * to that particular segment into s_prot. If this pointer is not set
+ * the error info is lost for we don't know where to store.
+ *
+ */
+
+ if ((0 == strncmp(logmsg, "Errors: header", 14)) && s_prot != NULL)
+ {
+ int i1,i2,i3,i4 = 0;
+ sscanf(logmsg,"%*s %*s %d%*c%*s %d%*c%*s %d%*c%*s %*s%*c %d",&i1,&i2,&i3,&i4);
+ ss_prot->pr_eheader += i1;
+ ss_prot->pr_echksum += i2;
+ ss_prot->pr_eorder += i3;
+ ss_prot->pr_ereject += i4;
+ s_prot->pr_eheader += i1;
+ s_prot->pr_echksum += i2;
+ s_prot->pr_eorder += i3;
+ s_prot->pr_ereject += i4;
+ s_prot = NULL;
+ continue;
+ }
+
+ /*
+ * Handle end of call. Pick up the connect time.
+ * position is on the closing paren of date/time info
+ * i.e: ) text....
+ */
+
+ if (0 == strncmp(logmsg, "Call complete", 13))
+ {
+ cur->call[called].succs++;
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (s = strchr(logmsg, '(')))
+ continue;
+ cur->call[called].connect_time += atof(s+1);
+ continue;
+ }
+
+ /*
+ * We are definitely in a Stats file now.
+ * If we reached here, this must have been a file transfer
+ * record. Count it in the field corresponding to the
+ * direction of the transfer. Count bytes transferred and
+ * the time to transfer as well.
+ * Position within the record is at the word 'received' or 'sent'
+ * depending on the direction.
+ */
+
+ sent = IN; /* give it an initial value */
+ if (0 == strncmp(logmsg, "failed after ",13))
+ logmsg += 13; /* the transmission failed for any reason */
+ /* so advance pointer */
+ if (0 == strncmp(logmsg, "sent", 4))
+ sent = OUT;
+ else if (0 == strncmp(logmsg, "received", 8))
+ sent = IN;
+ have_files[sent] = TRUE;
+ cur->call[called].flow[sent].files++;
+ if (NULL == (s = strchr(logmsg, ' '))) /* point past keyword */
+ continue; /* nothing follows */
+ /* we should be at the bytes column now*/
+#if HAVE_TAYLOR_LOGGING
+ cur->call[called].flow[sent].bytes += atol(++s);
+#endif /* HAVE_TAYLOR_LOGGING */
+#if HAVE_V2_LOGGING
+ if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # bytes */
+ continue;
+ cur->call[called].flow[sent].bytes += atol(s);
+#endif /* HAVE_V2_LOGGING */
+ if (NULL == (s = strchr(s, ' '))) /* point past # of bytes */
+ continue;
+ if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # of seconds */
+ continue;
+ cur->call[called].flow[sent].time += atof(s);
+
+ } /* end of while (fgets(logline...)) */
+
+ if (stt != NULL && ! use_stdin && ! be_quiet && ! no_records)
+ {
+
+#if HAVE_TAYLOR_LOGGING
+ sscanf(dt_info,"%s%*c%[^.]",in_date,in_time);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+#if HAVE_V2_LOGGING
+ sscanf(dt_info,"%[^-]%*c%[1234567890:]",in_date,in_time);
+#endif /* HAVE_V2_LOGGING */
+
+ printf(" %10s %8s\n",in_date, in_time);
+ p_done = FALSE;
}
+ if (Log != stdin)
+ {
+ if (0 != ferror(Log))
+ {
+ if (! be_quiet)
+ printf(" %-14s data is incomplete; read error"," ");
+ else
+ fprintf(stderr,"%s (W) data is incomplete; read error on %s\n",
+ Pgm_name,argv[1]);
+ }
+ else
+ {
+ if (! be_quiet && no_records)
+ printf(" %-14s %10s\n",Filename, " is empty ");
+ }
+ }
+ fclose(Log);
-#if _DEBUG_
- printf("\n");
-#endif
+ argc--;
+ argv++;
+ } /* end of while (for (argv ....) */
/*
- * MAIN LOGFILE PROCESSING LOOP
+ * do we have *any* data ?
*/
- while (argc > 1)
- {
- if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
- {
- perror(argv[1]);
- return;
- }
+ if (cur == NULL)
+ {
+ puts("\n(I) Sorry! No data is available for any requested report\n");
+ exit(0);
+ }
-#if _DEBUG_
- printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1]));
-#endif
-
- /*
- * Read each line of the logfile and collect information
- */
- while (fgets(logline, sizeof(logline), Log))
- {
- /*
- * The host name of the other end of the connection is
- * always the second field of the log line, whether we
- * are reading a Log file or a Stats file. Set 'p' to
- * point to the second field, null-terminated. Skip
- * the line if something is funny.
- */
- if (NULL == (p = strchr(logline, ' ')))
- continue;
- ++p;
- if (NULL != (s = strchr(p, ' ')))
- *s = '\0';
- for (s = p; *s; ++s)
- if (isupper(*s))
- *s = tolower(*s);
- /*
- * Skip this line if we got -h <host> and
- * this line does not contain that host name.
- */
- if (Hostname[0] != '\0')
- if (0 != strcmp(p, Hostname))
- continue;
- /*
- * We are within a call block now. If this line is a file
- * transfer record, determine the direction. If not then
- * skip the line if it is not interesting.
- */
- if ((s = strchr(++s, ')')) == NULL)
- continue;
- logmsg = s + 2; /* Message is 2 characters after ')' */
- if (0 == strncmp(logmsg, "sent", 4))
- sent = OUT;
- else
- if (0 == strncmp(logmsg, "received", 8))
- sent = IN;
- else
- if ((0 != strncmp(logmsg, "Call complete", 13)) &&
- (0 != strncmp(logmsg, "Calling system", 14)) &&
- (0 != strncmp(logmsg, "Incoming call", 13)) &&
- (0 != strncmp(logmsg, "Executing", 9)))
- continue;
- /*
- * Find the Host_entry for this host, or create a new
- * one and link it on to the list.
- */
- if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
- {
- for (cur = hosts; cur != NULL ; cur = cur->next)
- if (0 == strcmp(cur->Hostname, p))
- break;
- if (cur == NULL)
- {
- cur = (struct Host_entry *)calloc(1, sizeof(*hosts));
- strcpy(cur->Hostname, p);
- if (hosts == NULL)
- hosts = cur;
- else
- {
- for (e = hosts; e->next != NULL; e = e->next);
- e->next = cur;
- }
- }
- }
- /*
- * OK, if this is a uuxqt record, find the Execution_Command
- * structure for the command being executed, or create a new
- * one. Then count an execution of this command.
- */
- if (0 == strncmp(logmsg, "Executing", 9))
- {
- if (NULL == (p = strchr(logmsg, '(')))
- continue;
- if ((s = strpbrk(++p, " )")) == NULL)
- continue;
- *s = '\0';
- for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
- if (0 == strcmp(cmd->Commandname, p))
- break;
- if (cmd == NULL)
- {
- cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd));
- strcpy(cmd->Commandname, p);
- if (cur->cmds == NULL)
- cur->cmds = cmd;
- else
- {
- for (ec = cur->cmds; ec->next != NULL; ec = ec->next);
- ec->next = cmd;
- }
- }
- ++cmd->count;
- have_commands = 1;
- continue;
- }
- /*
- * Count start of outgoing call.
- */
- if (0 == strncmp(logmsg, "Calling system", 14))
- {
- called = OUT;
- cur->call[called].calls += 1;
- have_calls = 1;
- continue;
- }
- /*
- * Count start of incoming call.
- */
- if (0 == strncmp(logmsg, "Incoming call", 13))
- {
- called = IN;
- cur->call[called].calls += 1;
- have_calls = 1;
- continue;
- }
- /*
- * Handle end of call. Pick up the connect time.
- */
- if (0 == strncmp(logmsg, "Call complete", 13))
- {
- cur->call[called].succs += 1;
- if (NULL == (s = strchr(logmsg, '(')))
- continue;
- cur->call[called].connect_time += atof(s+1);
- continue;
- }
- /*
- * If we reached here, this must have been a file transfer
- * record. Count it in the field corresponding to the
- * direction of the transfer. Count bytes transferred and
- * the time to transfer as well.
- */
- have_files = 1;
- cur->call[called].flow[sent].files += 1;
- if (NULL == (s = strchr(logmsg, ' ')))
- continue;
- cur->call[called].flow[sent].bytes += atol(++s);
- if (NULL == (s = strchr(s, ' ')))
- continue;
- if (NULL == (s = strpbrk(s, "0123456789")))
- continue;
- cur->call[called].flow[sent].time += atof(s);
- }
- argc -= 1;
- argv += 1;
- if(Log != stdin)
- fclose(Log);
- }
-
/*
- * ***********
- * * REPORTS *
- * ***********
+ * truncate hostname, alloc the structure holding the totals and
+ * collect the totals data
*/
+ for (cur = hosts; cur != NULL;cur = cur->next)
+ {
+ cur->Hostname[MAXDNAME] = '\0';
+ if (cur->next == NULL) /* last so will have to alloc totals */
+ {
+ cur->next = (struct Host_entry *)getmem(sizeof(*hosts));
+ strcpy(cur->next->Hostname,"Totals");
+ tot = cur->next;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ if (cur->next != NULL) /* don't count totals to totals */
+ {
+ tot->call[IN].flow[IN].bytes += cur->call[IN].flow[IN].bytes;
+ tot->call[OUT].flow[IN].bytes += cur->call[OUT].flow[IN].bytes;
+ tot->call[IN].flow[OUT].bytes += cur->call[IN].flow[OUT].bytes;
+ tot->call[OUT].flow[OUT].bytes += cur->call[OUT].flow[OUT].bytes;
+ tot->call[IN].flow[IN].time += cur->call[IN].flow[IN].time;
+ tot->call[OUT].flow[IN].time += cur->call[OUT].flow[IN].time;
+ tot->call[IN].flow[OUT].time += cur->call[IN].flow[OUT].time;
+ tot->call[OUT].flow[OUT].time += cur->call[OUT].flow[OUT].time;
+ tot->call[IN].flow[IN].files += cur->call[IN].flow[IN].files;
+ tot->call[OUT].flow[IN].files += cur->call[OUT].flow[IN].files;
+ tot->call[IN].flow[OUT].files += cur->call[IN].flow[OUT].files;
+ tot->call[OUT].flow[OUT].files += cur->call[OUT].flow[OUT].files;
+ tot->call[OUT].succs += cur->call[OUT].succs;
+ tot->call[OUT].calls += cur->call[OUT].calls;
+ tot->call[OUT].connect_time += cur->call[OUT].connect_time;
+ tot->call[IN].succs += cur->call[IN].succs;
+ tot->call[IN].calls += cur->call[IN].calls;
+ tot->call[IN].connect_time += cur->call[IN].connect_time;
+ }
+ }
+ break; /* totals is last in Host_Entry */
+ }
+ }
+
/*
- * Truncate the Hostnames to 8 characters at most.
+ * ***********
+ * * REPORTS *
+ * ***********
*/
- for (cur = hosts; cur != NULL; cur = cur->next)
- cur->Hostname[8] = '\0';
#if _DEBUG_
- printf("\n");
+ putchar('\n');
#endif
- /*
- * Summary report
+ /* ------------------------------------------------------------------
+ *
+ * Summary report only when no other report except option -t is given
*
* I know, this code could be tightened (rbd)...
+ * ------------------------------------------------------------------
*/
- if(show_summary)
- {
- char t1[32], t2[32], t3[32], t4[32], t5[32];
- long ib, ob, b, rf, sf;
- long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0;
- double it, ot, ir, or;
- double t_it=0.0, t_ot=0.0;
- int nhosts = 0;
-
- printf("\n\
- Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n");
- printf("\
- Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n");
- printf("\
--------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
- for (cur = hosts; cur != NULL; cur = cur->next)
- {
- ib = (cur->call[IN].flow[IN].bytes +
- cur->call[OUT].flow[IN].bytes);
- fmbytes(ib, t1);
- t_ib += ib;
-
- ob = (cur->call[IN].flow[OUT].bytes +
- cur->call[OUT].flow[OUT].bytes);
- fmbytes(ob, t2);
- t_ob += ob;
-
- b = ib + ob;
- fmbytes(b, t3);
- t_b += b;
-
- it = cur->call[IN].flow[IN].time +
- cur->call[OUT].flow[IN].time;
- fmtime(it, t4);
- t_it += it;
-
- ot = cur->call[IN].flow[OUT].time +
- cur->call[OUT].flow[OUT].time;
- fmtime(ot, t5);
- t_ot += ot;
-
- rf = cur->call[IN].flow[IN].files +
- cur->call[OUT].flow[IN].files;
- t_rf += rf;
-
- sf = cur->call[IN].flow[OUT].files +
- cur->call[OUT].flow[OUT].files;
- t_sf += sf;
-
- ir = (it == 0.0) ? 0.0 : (ib / it);
- or = (ot == 0.0) ? 0.0 : (ob / ot);
-
- printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
- cur->Hostname,
- t1, t2, t3, t4, t5,
- ir, or, rf, sf);
- }
-
- if(nhosts > 1)
- {
- fmbytes(t_ib, t1);
- fmbytes(t_ob, t2);
- fmbytes(t_b, t3);
- fmtime(t_it, t4);
- fmtime(t_ot, t5);
- ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it);
- or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot);
-
- printf("\
--------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
- printf("\
-Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
- t1, t2, t3, t4, t5,
- ir, or, t_rf, t_sf);
- }
- }
-
- /*
- * Call statistics report
+ if ( !(show_calls || show_files ||
+ show_efficiency || show_commands || show_proto) || show_all)
+ {
+ if (have_calls || have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32], t3[32], t4[32], t5[32];
+ long ib, ob, b, rf, sf;
+ double it, ot, ir, or;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ ib = (cur->call[IN].flow[IN].bytes +
+ cur->call[OUT].flow[IN].bytes);
+ fmbytes(ib, t1);
+
+ ob = (cur->call[IN].flow[OUT].bytes +
+ cur->call[OUT].flow[OUT].bytes);
+ fmbytes(ob, t2);
+
+ /* Don't print null-lines. */
+ if (( b= ib+ob ) == 0 )
+ continue;
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('s',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+
+ fmbytes(b, t3);
+
+ it = cur->call[IN].flow[IN].time +
+ cur->call[OUT].flow[IN].time;
+ fmtime(it, t4);
+
+ ot = cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(ot, t5);
+
+ rf = cur->call[IN].flow[IN].files +
+ cur->call[OUT].flow[IN].files;
+
+ sf = cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[OUT].files;
+
+ ir = (it == 0.0) ? 0.0 : (ib / it);
+ or = (ot == 0.0) ? 0.0 : (ob / ot);
+
+ if (cur->next == NULL) /* totals line reached ? */
+ hdrprt('s',1); /* print the separator line */
+
+ printf("%-8s %4d %4d %9s %9s %9s %9s %9s %5.0f %5.0f\n",
+ cur->Hostname, rf, sf,
+ t1, t2, t3, t4, t5,
+ ir, or);
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Compact summary report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Compact summary report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Protocol statistics report
+ * ------------------------------------------------------------------
*/
- if(show_calls && have_calls)
- {
- char t1[32], t2[32];
-
- printf("\nCall statistics:\n");
- printf("\
- sysname callto failto totime callfm failfm fmtime\n");
- printf("\
- -------- ------ ------ -------- ------ ------ --------\n");
- for (cur = hosts; cur != NULL; cur = cur->next)
- {
- fmtime(cur->call[OUT].connect_time, t1);
- fmtime(cur->call[IN].connect_time, t2),
- printf(" %-8s %6d %6d %8s %6d %6d %8s\n",
- cur->Hostname,
- cur->call[OUT].calls,
- cur->call[OUT].calls - cur->call[OUT].succs,
- t1,
- cur->call[IN].calls,
- cur->call[IN].calls - cur->call[IN].succs,
- t2);
- }
- }
- /*
- * File statistics report
+ if (show_proto || show_all)
+ {
+ if (have_proto)
+ {
+ /* --------------------- */
+ /* protocol packet report */
+ /* --------------------- */
+
+ char *type = NULL;
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ type = cur->Hostname;
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ puts("-------------------------------------------------------------------");
+ cur->proto = t_prot;
+ }
+ for (prot = cur->proto; prot != NULL; prot = prot->next)
+ {
+ if (! hdr_done)
+ {
+ hdrprt('p',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ printf("%-8s %3s %4d %4d %5d %4d %10d %7d %10d\n",
+ type == NULL ? " ":cur->Hostname,
+ prot->type,
+ prot->pr_psizemin,
+ prot->pr_psizemax,
+ prot->pr_pwinmin,
+ prot->pr_pwinmax,
+ prot->pr_psent,
+ prot->pr_present,
+ prot->pr_preceived);
+ type = NULL;
+ }
+ }
+ if (! hdr_done)
+ puts("\n(I) No data found to print Protocol packet report");
+
+ /* --------------------- */
+ /* protocol error report */
+ /* --------------------- */
+
+ type = NULL;
+ hdr_done = FALSE;
+ if (t_prot != NULL)
+ {
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ type = cur->Hostname;
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ puts("--------------------------------------------------------------");
+ cur->proto = t_prot;
+ }
+
+ for (prot = cur->proto; prot != NULL; prot = prot->next)
+ {
+ if ((prot->pr_eheader + prot->pr_echksum +
+ prot->pr_eorder + prot->pr_ereject) != 0)
+ {
+ if (! hdr_done)
+ {
+ hdrprt('p',1); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ printf("%-8s %3s %11d %11d %11d %11d\n",
+ type == NULL ? " ":cur->Hostname,
+ prot->type,
+ prot->pr_eheader,
+ prot->pr_echksum,
+ prot->pr_eorder,
+ prot->pr_ereject);
+ type = NULL;
+ }
+ }
+ }
+ }
+ if (! hdr_done)
+ puts("\n(I) No data found to print Protocol error report");
+ }
+ else
+ {
+ puts("\n(I) No data available for Protocol reports");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Call statistics report
+ * ------------------------------------------------------------------
*/
- if(show_files && have_files)
- {
- char t1[32], t2[32];
-
- for (sent = IN; sent <= OUT; ++sent)
- {
- printf(file_hdr[sent]);
- printf(" sysname files bytes xfr time byte/s\n");
- printf(" -------- ------ -------- -------- ------\n");
- for (cur = hosts; cur != NULL; cur = cur->next)
- {
- double rate;
- double time;
-
- time = cur->call[IN].flow[sent].time +
- cur->call[OUT].flow[sent].time;
- if (time == 0.0)
- continue;
- rate = (cur->call[IN].flow[sent].bytes +
- cur->call[OUT].flow[sent].bytes) / time;
- fmbytes((cur->call[IN].flow[sent].bytes +
- cur->call[OUT].flow[sent].bytes), t1);
- fmtime((cur->call[IN].flow[sent].time +
- cur->call[OUT].flow[sent].time), t2);
- printf(" %-8s %6d %8s %8s %6.1f\n",
- cur->Hostname,
- cur->call[IN].flow[sent].files +
- cur->call[OUT].flow[sent].files,
- t1, t2, rate);
- }
- }
- }
- /*
- * Efficiency report
+ if (show_calls || show_all)
+ {
+ if (have_calls)
+ {
+ char t1[32], t2[32];
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ hdrprt('c',1); /* print the separator line */
+ }
+ else
+ {
+ /* Don't print null-lines on deatail lines */
+ if ( cur->call[OUT].calls + cur->call[IN].calls == 0 )
+ continue;
+
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('c',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ }
+ if ( cur->call[OUT].calls > 0 || cur->next == NULL)
+ {
+ fmtime(cur->call[OUT].connect_time, t1);
+ printf( " %-8s %7d %7d %7d %9s",
+ cur->Hostname,
+ cur->call[OUT].succs,
+ cur->call[OUT].calls - cur->call[OUT].succs,
+ cur->call[OUT].calls,
+ t1 );
+ }
+ else
+ {
+ printf( " %-42s", cur->Hostname );
+ }
+ if ( cur->call[IN].calls > 0 || cur->next == NULL )
+ {
+ fmtime(cur->call[IN].connect_time, t2);
+ printf( " %7d %7d %7d %9s",
+ cur->call[IN].succs,
+ cur->call[IN].calls - cur->call[IN].succs,
+ cur->call[IN].calls,
+ t2 );
+ }
+ putchar('\n');
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Call statistics report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Call statistics report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * File statistics report
+ * ------------------------------------------------------------------
*/
- if (show_efficiency && have_files)
+
+ if (show_files || show_all)
+ {
+ if (have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32];
+ double rate = 0, time = 0;
+ int b = 0;
+ int lineOut = 0;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ lineOut = 0;
+ for (sent= IN; sent <= OUT; ++sent)
+ {
+ b = cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes;
+ time = cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time;
+
+ /* Don't print null-lines on detail lines. */
+ if ( (b != 0 && time != 0.0) || cur->next == NULL)
+ {
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('f',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ fmbytes(b, t1);
+ rate = (cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes) / time;
+ fmtime((cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time), t2);
+
+ if (lineOut == 0) /* first half not printed yet ? */
+ {
+ if (cur->next == NULL) /* totals line ? */
+ hdrprt('f',1); /* print the separator line */
+ printf(" %-8s", cur->Hostname);
+ if (sent == OUT) /* can't happen whith totals line */
+ printf("%34s", " ");
+ }
+
+ printf(" %5d %11s %9s %5.0f",
+ cur->call[IN].flow[sent].files +
+ cur->call[OUT].flow[sent].files,
+ t1, t2, rate);
+ lineOut = 1;
+ }
+ } /* end: for (sent ... ) */
+ if (lineOut)
+ printf("\n");
+ } /* end: for (cur= ... ) */
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print File statistics report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for File statistics report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Efficiency report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_efficiency || show_all)
+ {
+ if (have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32], t3[32];
+ double total, flow;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ /* Don't print null-lines. */
+ if ( 0 == cur->call[IN].flow[IN].files +
+ cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[IN].files +
+ cur->call[OUT].flow[OUT].files ||
+ 0.0 == (total= cur->call[IN].connect_time +
+ cur->call[OUT].connect_time))
+ {
+ continue;
+ }
+
+ if (! hdr_done)
+ {
+ hdrprt('e',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+
+ flow = cur->call[IN].flow[IN].time +
+ cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[IN].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(total, t1);
+ fmtime(flow, t2);
+ fmtime(total-flow, t3);
+
+ if (cur->next == NULL)
+ hdrprt('e',1); /* print the separator line */
+
+ printf(" %-8s %10s %10s %10s %7.2f\n",
+ cur->Hostname, t1, t2, t3,
+ flow >= total ? 100.0: flow*100.0/total);
+ } /* end: for (cur= .. */
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Efficiency report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Efficiency report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Command execution report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_commands || show_all)
+ {
+ if (have_commands)
+ {
+ int ncmds, i, match;
+
+ /*
+ * layout the header line. The column's header is the command name
+ */
+
+ hdr_done = FALSE;
+ for (ncmds= 0, cmd= t_cmds;
+ cmd != NULL && ncmds <= MAXCOLS-1;
+ ncmds++, cmd= cmd->next)
+ {
+ if (! hdr_done)
+ {
+ puts("\nCommand executions:");
+ puts("-------------------");
+ puts(" Name of ");
+ fputs(" site ", stdout);
+ hdr_done = TRUE;
+ }
+ printf(" %7s", cmd->Commandname);
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Command execution report");
+ }
+ else
+ {
+ fputs("\n --------", stdout);
+ for (i= 0; i<ncmds; i++)
+ fputs(" ------", stdout);
+ putchar('\n');
+
+ /*
+ * print out the number of executions for each host/command
+ */
+
+ for (cur= hosts; cur != NULL; cur= cur->next)
+ {
+ if (cur->next == NULL)
+ break;
+
+ /* Don't print null-lines. */
+
+ if (cur->cmds == NULL)
+ continue;
+
+ printf(" %-8s", cur->Hostname);
+ for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
+ {
+ struct Execution_Command *ec;
+ match = FALSE;
+ for(ec= cur->cmds; ec != NULL; ec= ec->next)
+ {
+ if ( 0 == strcmp(cmd->Commandname, ec->Commandname) )
+ {
+ printf(" %7d", ec->count);
+ match = TRUE;
+ break;
+ }
+ }
+ if (! match)
+ printf("%8s"," "); /* blank out column */
+ }
+ putchar('\n');
+ }
+
+ /*
+ * print the totals line
+ */
+
+ fputs(" --------", stdout);
+ for (i= 0; i<ncmds; i++)
+ fputs("--------", stdout);
+ printf("\n %-8s", cur->Hostname);
+ for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
+ {
+ printf(" %7d", cmd->count);
+ }
+ putchar('\n');
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Command execution report");
+ --report;
+ }
+ }
+ if (report <= 0 ) /* any reports ? */
+ {
+ puts("\n(I) Sorry! No data is available for any requested report\n");
+ exit(1);
+ }
+
+ puts("\n(I) End of reports\n");
+ exit (0);
+} /* end of main */
+
+ /* ------------------------------------------------------------------
+ * * Functions *
+ * ------------------------------------------------------------------
+ */
+
+ /* ------------------------------------------------------------------
+ * display the help
+ * ------------------------------------------------------------------
+ */
+
+void usage()
+{
+ fprintf(stderr,"Usage uurate [-acdefhiptvx] [-s hostname] [-I config file] [logfile(s) ... logfile(s)]\n");
+ fprintf(stderr,"where:\t-a\tPrint reports c,e,f,x\n");
+ fprintf(stderr,"\t-c\tReport call statistics\n");
+ fprintf(stderr,"\t-d\tPrint the name of the default config file\n");
+ fprintf(stderr,"\t-e\tReport efficiency statistics\n");
+ fprintf(stderr,"\t-f\tReport file transfer statistics\n");
+ fprintf(stderr,"\t-h\tPrint this help\n");
+ fprintf(stderr,"\t-i\tRead log info from standard input\n");
+ fprintf(stderr,"\t-p\tReport protocol statistics\n");
+ fprintf(stderr,"\t-t\tAll available reports plus compact summary report\n");
+ fprintf(stderr,"\t-v\tPrint version number\n");
+ fprintf(stderr,"\t-x\tReport command execution statistics\n");
+ fprintf(stderr,"\t-s host\tReport activities involving HOST only\n");
+ fprintf(stderr,"\t-I config Use config instead of standard config file\n");
+ fprintf(stderr,"If no report options given, a compact summary report is printed.\n");
+ fprintf(stderr,"log files should be given as pairs that is Log/Stats ... .\n");
+ fprintf(stderr,"If neither -i nor logfiles given, those names found in config will be used\n");
+
+ exit (1);
+}
+
+ /* ------------------------------------------------------------------
+ * getmem - get some memory
+ * ------------------------------------------------------------------
+ */
+
+static pointer *getmem(n)
+ unsigned n;
+{
+ pointer *p;
+
+ if( NULL== (p= calloc(1, n)) )
{
- char t1[32], t2[32], t3[32];
- double total, flow;
-
- printf("\nEfficiency:\n");
- printf(" sysname conntime flowtime ovhdtime eff. %%\n");
- printf(" -------- -------- -------- -------- ------\n");
- for (cur = hosts; cur != NULL; cur = cur->next)
- {
- total = cur->call[IN].connect_time + cur->call[OUT].connect_time;
- flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time +
- cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time;
- fmtime(total, t1);
- fmtime(flow, t2);
- fmtime((total-flow), t3);
- printf(" %-8s %8s %8s %8s %5.1f%%\n",
- cur->Hostname, t1, t2, t3, ((flow / total) * 100.0));
- }
+ fprintf(stderr,"\a%s (C) %s\n",Pgm_name, "out of memory\n");
+ exit (8);
}
+ return p;
+}
+
+ /* ------------------------------------------------------------------
+ * inc_cmd - increment command count
+ * ------------------------------------------------------------------
+ */
+
+static void inc_cmd(cmds, name)
+ struct Execution_Command **cmds;
+ char *name;
+{
+ int cnt = 0;
+ struct Execution_Command *cmd, *ec;
+
+ for (ec = cmd = *cmds; cmd != NULL; ec= cmd, cmd= cmd->next, cnt++)
+ if ( (0 == strcmp(cmd->Commandname, name)) ||
+ (0 == strcmp(cmd->Commandname, "Misc.")) )
+ break;
+ if (cmd == NULL)
+ {
+ cmd= (struct Execution_Command *)getmem(sizeof(*cmd));
+ if (cnt <= MAXCOLS-1) /* first col prints site name therefore < max-1 */
+ {
+ strcpy(cmd->Commandname, name);
+ if (*cmds == NULL)
+ ec = *cmds = cmd;
+ else
+ ec->next= cmd;
+ }
+ else
+ {
+ strcpy(ec->Commandname, "Misc."); /* reached high-water-mark */
+ cmd = ec; /* backtrack */
+ }
+ }
+ cmd->count++;
+}
+
+
+ /* ------------------------------------------------------------------
+ * prot_sum - collect protocol data
+ * ------------------------------------------------------------------
+ */
+
+ struct Protocol_Summary *
+ prot_sum(proto, ptype, ind)
+ struct Protocol_Summary **proto;
+ char *ptype;
+ int ind;
+{
+ int cnt = 0;
+ int i1, i2, i3 = 0;
+ struct Protocol_Summary *cur, *first;
+ for (first = cur = *proto; cur != NULL; first= cur, cur= cur->next, cnt++)
+ {
+ if ( (0 == strncmp(cur->type, ptype,strlen(cur->type))))
+ break;
+ }
+ if (cur == NULL)
+ {
+ cur= (struct Protocol_Summary *)getmem(sizeof(*cur));
+ sscanf(ptype,"%[^\' ]3",cur->type);
+ if (*proto == NULL)
+ first = *proto = cur;
+ else
+ first->next= cur;
+ }
+ if (NULL == (ptype = strchr(ptype, ' ')))
+ return (NULL);
+ cur->pr_cnt++;
+ have_proto = TRUE;
+ ++ptype;
+ switch(ind)
+ {
+ case 1: /* used protocol line */
/*
- * Command execution report
- */
- if (show_commands & have_commands)
- {
- printf("\nCommand executions:\n");
- printf(" sysname rmail rnews other\n");
- printf(" -------- ------ ------ ------\n");
- for (cur = hosts; cur != NULL; cur = cur->next)
- {
- int rmail, rnews, other;
-
- if (cur->cmds == NULL)
- continue;
- rmail = rnews = other = 0;
- for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
- {
- if (strcmp(cmd->Commandname, "rmail") == 0)
- rmail += cmd->count;
- else if (strcmp(cmd->Commandname, "rnews") == 0)
- rnews += cmd->count;
- else
- other += cmd->count;
- }
- printf(" %-8s %6d %6d %6d\n", cur->Hostname,
- rmail, rnews, other);
- }
- }
- return;
-
- usage:
- fprintf(stderr,
- "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n");
- fprintf(stderr,"where:\t-c\tReport call statistics\n");
- fprintf(stderr, "\t-f\tReport file transfer statistics\n");
- fprintf(stderr, "\t-e\tReport efficiency statistics\n");
- fprintf(stderr, "\t-x\tReport command execution statistics\n");
- fprintf(stderr, "\t-a\tAll of the above reports\n");
- fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n");
- fprintf(stderr, "\t-i\tRead log info from standard input\n");
- fprintf(stderr,
- "If no report options given, a compact summary report is given.\n");
- fprintf(stderr,
- "If neither -i nor logfiles given, defaults to reading from\n");
- fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE);
+ * uucp-1.04 format: .... packet size ssss window ww)
+ * uucp-1.05 format: .... remote packet/window ssss/ww local ssss/ww)
+ * (the remote packet/window will be used!)
+ */
+
+ i1 = i2 = 0; /* reset */
+
+ if (NULL == (strchr(ptype, '/')))
+ sscanf(ptype,"%*s %*s %d %*s %d",&i1,&i2);
+ else
+ sscanf(ptype,"%*s %*s %d/%d",&i1,&i2);
+
+ if (i1 > cur->pr_psizemax)
+ cur->pr_psizemax = i1;
+ if (i1 < cur->pr_psizemin || cur->pr_psizemin == 0)
+ cur->pr_psizemin = i1;
+
+ if (i2 > cur->pr_pwinmax)
+ cur->pr_pwinmax = i2;
+ if (i2 < cur->pr_pwinmin || cur->pr_pwinmin == 0)
+ cur->pr_pwinmin = i2;
+ break;
+ case 2: /* protocol statistics line */
+ i1 = i2 = i3 = 0; /* reset */
+ sscanf(ptype,"%*s %*s %d%*c %*s %d%*c %*s %d",&i1,&i2,&i3);
+ cur->pr_psent += i1;
+ cur->pr_present += i2;
+ cur->pr_preceived += i3;
+ break;
+ default:
+ break;
+ }
+ return (cur);
}
+ /* ------------------------------------------------------------------
+ * fmtime() - Format time in hours & minutes & seconds;
+ * ------------------------------------------------------------------
+ */
-/*
- * fmtime() - Format time in hours & minutes;
- */
static void fmtime(dsec, buf)
- double dsec;
- char *buf;
+ double dsec;
+ char *buf;
{
long hrs, min, lsec;
- lsec = dsec;
- hrs = lsec / 3600L;
- min = (lsec - (hrs * 3600L)) / 60L;
+ if( dsec <= 0 )
+ {
+ strcpy(buf, "0" );
+ return;
+ }
+ lsec = fmod(dsec+0.5, 60L); /* round to the next full second */
+ hrs = dsec / 3600L;
+ min = ((long)dsec / 60L) % 60L;
+ if (hrs == 0)
+ if (min == 0)
+ sprintf(buf,"%6s%2ld"," ",lsec);
+ else
+ sprintf(buf,"%3s%2ld:%02ld"," ",min,lsec);
+ else
+ sprintf(buf,"%2ld:%02ld:%02ld",hrs,min,lsec);
- sprintf(buf, "%02ld:%02ld", hrs, min);
}
-/*
- * fmbytes - Format size in bytes
- */
+ /* ------------------------------------------------------------------
+ * fmbytes - Format size in bytes
+ * ------------------------------------------------------------------
+ */
+
static void fmbytes(n, buf)
- unsigned long n;
- char *buf;
+ unsigned long n;
+ char *buf;
{
- char t;
- double s = n;
+ if ( n == 0 )
+ {
+ strcpy( buf, "0.0" );
+ return;
+ }
+ sprintf(buf, "%.1f", (double)n / 1000.0); /* Display in Kilobytes */
+}
- if(s >= 10239897.6) /* More than 9999.9K ? */
- {
- s = (double)n / 1048576.0; /* Yes, display in Megabytes */
- t = 'M';
- }
- else
- {
- s = (double)n / 1024.0; /* Display in Kilobytes */
- t = 'K';
- }
- sprintf(buf, "%.1f%c", s, t);
+ /* ------------------------------------------------------------------
+ * chk_config - Read the config file
+ * check on keywords: logfile and statfile. When found override
+ * the corresponding default
+ * ------------------------------------------------------------------
+ */
+
+int chk_config(char *T_conf,int be_quiet, int type)
+{
+ FILE *Conf;
+ char keywrd[9];
+ char name[MAXPATHLEN+1];
+ char *pos1, *pos2;
+ int i = 0;
+ int logf = FALSE;
+ int statf = FALSE;
+
+ if ((Conf = fopen(T_conf, "r")) == NULL)
+ {
+ if (! be_quiet)
+ {
+ puts(" Could not open config");
+ if (type == 0)
+ {
+ puts(" The run will be aborted\n");
+ return (8);
+ }
+ }
+ else
+ {
+ fprintf(stderr,"%s (E) %s %s \n",Pgm_name,
+ "could not open config:",
+ T_conf);
+ if (type != 0)
+ fprintf(stderr,"%s (W) defaults used for all files\n",
+ Pgm_name);
+ else
+ {
+ fprintf(stderr,"%s (C) ended due to errors\n",
+ Pgm_name);
+ return (8);
+ }
+ }
+ }
+ else
+ {
+ while (fgets(logline, sizeof(logline), Conf))
+ {
+ if (logline[0] == '#')
+ continue;
+ sscanf(logline,"%8s %s",keywrd,name);
+ if (0 == strncmp(keywrd,"logfile",7))
+ {
+ pos1 = pos2 = name;
+ for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
+ {
+ if (*pos1 == '#') /* name immed followed by comment */
+ break;
+ if (*pos1 == '\\') /* quoted comment (filename has #) */
+ {
+ ++pos1; /* skip escape char */
+ if (*pos1 != '#') /* continuation ? */
+ {
+ puts(" Config error:");
+ puts(" Found filename continuation; bailing out\n");
+ exit (8);
+ }
+ }
+ *pos2 = *pos1; /* move char */
+ }
+ *pos2 = '\0'; /* terminate string */
+ Tlog = (char *)getmem(strlen(name)+1);
+ strcpy(Tlog,name);
+ if (! be_quiet)
+ printf(" logfile used: %s\n",Tlog);
+ logf = TRUE;
+ if (statf) /* statsfile still to come ? */
+ break; /* no finished */
+ continue;
+ }
+
+ if (0 == strncmp(keywrd,"statfile",8))
+ {
+ pos1 = pos2 = name;
+ for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
+ {
+ if (*pos1 == '#') /* name immed followed by comment */
+ break;
+ if (*pos1 == '\\') /* quoted comment (filename has #) */
+ {
+ ++pos1; /* skip escape char */
+ if (*pos1 != '#') /* continuation ? */
+ {
+ puts(" Config error:");
+ puts(" Found filename continuation; bailing out\n");
+ exit (8);
+ }
+ }
+ *pos2 = *pos1; /* move char */
+ }
+ *pos2 = '\0'; /* terminate string */
+ Tstat = (char *)getmem(strlen(name)+1);
+ strcpy(Tstat,name);
+ if (! be_quiet)
+ printf(" statfile used: %s\n",Tstat);
+ statf = TRUE;
+ if (logf) /* logfile still to come ? */
+ break; /* no finished */
+ continue;
+ }
+ }
+ fclose(Conf);
+ }
+
+ if (! be_quiet)
+ {
+ if (! logf)
+ puts(" logfile used: - default -");
+ if (! statf)
+ puts(" statfile used: - default -");
+ }
+
+return 0;
}
+
+ /* ------------------------------------------------------------------
+ * hdrprt - Print Header/Trailer lines (constant data)
+ * ------------------------------------------------------------------
+ */
+
+static void hdrprt(char head, int bot)
+{
+ switch(head)
+ {
+ case('s'): /* standard summary report */
+ if (bot == 0)
+ {
+ puts("\nCompact summary:");
+ puts("----------------");
+ puts("\
+Name of + Files + +------- Bytes/1000 --------+ +------ Time -----+ + Avg CPS +\n\
+site in out inbound outbound total inbound outbound in out\n\
+-------- ---- ---- --------- --------- --------- --------- --------- ----- -----");
+ }
+ else
+ puts("\
+--------------------------------------------------------------------------------");
+ break;
+
+
+ case('f'): /* file statistic report */
+ if (bot == 0)
+ {
+ puts("\nFile statistics:");
+ puts("----------------");
+ puts(" Name of +----------- Inbound -----------+ +---------- Outbound -----------+");
+ puts(" site files Bytes/1000 xfr time B/sec files Bytes/1000 xfr time B/sec");
+ puts(" -------- ----- ----------- --------- ----- ----- ----------- --------- -----");
+ }
+ else
+ puts("\
+ ----------------------------------------------------------------------------");
+ break;
+
+
+ case('c'): /* calls statistic report */
+ if (bot == 0)
+ {
+ puts("\nCall statistics:");
+ puts("----------------");
+ puts(" Name of +------- Outbound Calls -------+ +-------- Inbound Calls ------+");
+ puts(" site succ. failed total time succ. failed total time");
+ puts(" -------- ------ ------ ------ --------- ------ ------ ------ ---------");
+ }
+ else
+ puts("\
+ ----------------------------------------------------------------------------");
+ break;
+
+
+ case('e'): /* efficiency statistic report */
+ if (bot == 0)
+ {
+ puts("\nEfficiency:");
+ puts("-----------");
+ puts(" Name of +------ Times inbound/outbound -------+");
+ puts(" site connected xfr time overhead eff. %");
+ puts(" -------- --------- --------- --------- ------");
+ }
+ else
+ puts(" -------------------------------------------------");
+ break;
+
+ case('i'): /* Environment information */
+ if (bot == 0)
+ {
+ puts("\nEnvironment Information:");
+ puts("------------------------");
+ printf(" Default config: %s\n",D_conf == NULL ?
+ noConf:D_conf);
+ printf(" Default logfile: %s\n",Tlog);
+ printf(" Default statfile: %s\n\n",Tstat);
+ }
+ break;
+
+ case('d'): /* Date/time coverage */
+ if (bot == 0)
+ {
+ puts("\n Date coverage of input files:");
+ puts(" Name of +----- Start -----+ +------ End ------+");
+ puts(" file date time date time");
+ puts(" -------- ---------- -------- ---------- --------");
+ }
+ break;
+
+ case('p'): /* Protocol stats */
+ if (bot == 0)
+ {
+ puts("\nProtocol packet report:");
+ puts("-----------------------");
+ puts(" +------- protocol -----+ +--------- Packets ----------+");
+ puts("Name of packet window ");
+ puts("site typ min max min max sent resent received");
+ puts("-------- --- ---- ---- ---- ---- ----------- ------- ----------");
+ }
+ else
+ {
+ puts("\nProtocol error report:");
+ puts("----------------------");
+ puts("Name of +----------------- Error Types --------------------+");
+ puts("site typ header checksum order rem-reject");
+ puts("-------- --- ----------- ---------- ----------- ----------");
+ }
+ break;
+
+ default:
+ if (bot == 0)
+ {
+ puts("\nNo header for this report defined:");
+ }
+ else
+ puts(" ");
+ break;
+ }
+}
diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man
index 9f33ef303862..b7b69a46f2dd 100644
--- a/gnu/libexec/uucp/contrib/uurate.man
+++ b/gnu/libexec/uucp/contrib/uurate.man
@@ -1,10 +1,13 @@
+''' $Id: uurate.man,v 1.2 1994/05/07 18:09:37 ache Exp $
.TH uurate 1
.SH NAME
uurate \- Report Taylor UUCP statistics
.SH SYNOPSIS
-.BR uurate " [ " "\-cfexai" " ] [ " "\-h "
+.BR uurate " [ " "\-acdefhipqtvx" " ] [ " "\-s "
.I host
-.RI " ] [ " "logfile..." " ] "
+.RI " ] [ " "\-I "
+.I config
+.RI " ][ " "logfile..." " ] "
.PP
or simply,
.PP
@@ -12,20 +15,20 @@ or simply,
.PP
for a traffic summary report.
.SH DESCRIPTION
-The
+The
.I uurate
-command provides tabular summary reports on the operation of the
+command provides tabular summary reports on the operation of the
Taylor UUCP system. Data is taken from the currently active log
-files, standard input, or from a list of log files given on the
-command line. Output is in the form of tabular reports summarizing
+files, standard input, or from a list of log files given on the
+command line. Output is in the form of tabular reports summarizing
call, file transfer, and command execution
.RI "(" "uuxqt" ")"
activity.
.PP
-The log files given to
+The log and stats files given to
.I uurate
-must be in the ``Taylor'' format. Also, note that call and file
-transfer activities are logged in separate files, nominally called
+must be in the ``Taylor'' or ``V2'' format. Also, note that call and file
+transfer activities are logged in separate files, nominally called
.I Log
and
.I Stats,
@@ -33,43 +36,49 @@ respectively. For reports to be meaningful, the
.I Log
and
.I Stats
-files should be given to
+files should be given to
.I uurate
together, and cover the same time period.
.PP
If neither the
.B \-i
-option nor any
+or
+.B \-I
+option nor any
.I logfile
-options are given,
+options are given,
.I uurate
defaults to taking its input from the current Taylor
.I Log
and
.I Stats
-files, as defined at compilation time.
+files. The names are either as defined at compilation time, in case
+there is no config file, or taken from the arguments of the keywords
+.I logfile
+and
+.I statfile
+when encountered in the config file.
This is the normal mode of operation.
.PP
The reporting options described below can be used to select
-the set of reports desired. If no options are given, the
-.B call
-and
-.B file
-reports are displayed. If there is no relevant data for a particular
-report or host, that report or host will be supressed.
+the set of reports desired. If no options are given, a summary
+report is displayed. If there is no relevant data for a particular
+report or host, that report or host will be suppressed.
.SH OPTIONS
-The following options may be given to
+The following options may be given to
.I uurate:
.TP 5
+.B \-a
+All reports. Identical to
+.B \-cfexp.
+.TP 5
.B \-c
Report on call statistics. Requires data from a
.I Log
file.
.TP 5
-.B \-f
-Report on file transfer statistics. Requires data from a
-.I Stats
-file.
+.B \-d
+will print the default config file to be used.
.TP 5
.B \-e
Report on efficiency (total connect time versus time spent transferring
@@ -79,6 +88,32 @@ and a
.I Stats
file, and they must span the same time period.
.TP 5
+.B \-f
+Report on file transfer statistics. Requires data from a
+.I Stats
+file.
+.TP 5
+.B \-h
+will print a short help information.
+.TP 5
+.B \-i
+tells uurate to read any logfile information from standard input.
+.TP 5
+.B \-p
+report on protocol errors and packets sent/received
+.TP 5
+.B \-q
+do not print the Environment information,
+.TP 5
+.B \-t
+All reports. Identical to
+.B \-cfexp.
+plus the
+.B Compact summary.
+.TP 5
+.B \-v
+will print the version id string
+.TP 5
.B \-x
Report on remote execution requests (e.g.,
.IR rmail ")."
@@ -86,19 +121,20 @@ Requires data from a
.I Log
file.
.TP 5
-.B \-a
-All reports. Identical to
-.B \-cfex.
-.TP 5
-.BI "\-h " "host"
+.BI "\-s " "host"
Restrict report output to
.I host.
+.TP 5
+.BI "\-I " "config file"
+an alternate config file may be passed by this option.
.SH "DESCRIPTION OF REPORTS"
There are four reports available: the call, file transfer, efficiency,
and remote execution reports. Each may be selected by a command line
-option. All reports may be selected via the option
-.B \-a.
-If no report selection options are given,
+option. All reports may be selected via the options
+.B \-a
+or
+.B \-t.
+If no report selection options are given,
.I uurate
displays a compact traffic summary report (see below).
.SS "Summary report"
@@ -109,109 +145,136 @@ displays a traffic summary report. This is particularly useful in daily
jobs which report on errors and the like. Traffic statistics for each
active system is reported on a single line. If more than one system was
active, a 'totals' line is included at the end of the report.
+.SS "Protocol packet report"
+The protocol report gives statistics on min/max packet and window sizes
+used during transmission. Further on data is collected for packets
+transferred. The data is collected for each host/protocol type.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "typ " "Type of protocol used"
+.BR "Min " "minimum packet/window size"
+.BR "Max " "maximum packet/window size"
+.BR "sent " "packets sent"
+.BR "resent " "packets resent"
+.BR "received " "packets received"
+.in -.3
+.SS "Protocol error report"
+The protocol report gives statistics on packet errors
+during transmission. The data is collected for each host/protocol type.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.5i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "typ " "Type of protocol used"
+.BR "header " "number of errors in header"
+.BR "checksum " "number of checksum errors"
+.BR "order " "number of order errors"
+.BR "resent " "number packets resent"
+.BR "rem-reject " "packets that the remote site rejected"
+.in -.3
.SS "Call report"
-The call report gives statistics on inbound and outbound calls for
+The call report gives statistics on inbound and outbound calls for
each active host system. The fields are described below:
+.PP
.br
.nf
-.in +.5i
+.in +.3i
.ta 1.0i
-.BR "sysname " "UUCP node name of neighbor host system"
-.BR "callto " "Outbound calls attempted to that system"
-.BR "failto " "Failed outbound calls to that system"
-.BR "totime " "Connect time (sec.) on outbound calls"
-.BR "callfm " "Inbound calls attempted by that system"
-.BR "failfm " "Failed inbound calls from that system"
-.BR "fmtime " "Connect time (sec.) on inbound calls"
-.in -.5
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "succ. " "Successful calls attempted to/by that system,"
+.BR "failed " "Failed calls to/by that system,"
+.BR "total " "Total calls to/by that system,"
+.BR "time " "Collected connect time (hh:mm:ss) for all calls,"
+.in -.3
.SS "File transfer reports"
-The file transfer reports give statistics on inbound and
+The file transfer reports give statistics on inbound and
outbound file transfers (regardless of which end initiated the transfer)
for each active host system. There are two reports, one for files
sent to the remote system and one for files received from the remote
system. The fields in each report are described below:
+.PP
.br
.nf
-.in +.5i
+.in +.3i
.ta 1.0i
-.BR "sysname " "UUCP node name of neighbor host system"
-.BR "files " "Number of files transferred"
-.BR "bytes " "Total size (bytes) of files transferred"
-.BR "seconds " "Total time (sec.) to transfer files"
-.BR "byte/sec " "Average transfer rate (bytes/sec)"
-.in -.5
+.BR "site " "UUCP node name of neighbor host system"
+.BR "files " "Number of files transferred"
+.BR "Bytes/1000 " "Total size of files transferred given in thousands"
+.BR "xfr time " "Total time (hh:mm:ss) spent on transfer the files,"
+.BR "B/sec " "Average transfer rate (bytes/sec)."
+.in -.3
.SS "Efficiency report"
The efficiency report describes the utilization of the links
to each active remote system, giving the ratio of total connect time
-to the time spent actually transferring files.
+to the time spent actually transferring files.
The fields are described below:
+.PP
.br
.nf
-.in +.5i
+.in +.3i
.ta 1.0i
-.BR "sysname " "UUCP node name of neighbor host system"
-.BR "conntime " "Total connect time for that system"
-.BR "flowtime " "Total file transfer time for that system"
-.BR "ovhdtime " "Connect time not used to transfer files"
-.BR "effcy (%) " "Ratio of connect time to transfer time"
-.in -.5
-.SS "Remote execution report"
+.BR "site " "UUCP node name of neighbor host system"
+.BR "connected " "Total connect time for that system (turn-around)"
+.BR "xfr time " "Total file transfer time for that system"
+.BR "overhead " "Connect time not used to transfer files,"
+.BR "eff. % " "Ratio of connect time to transfer time (xfer*100/conn)"
+.in -.3
+.SS "Command executions report"
The remote execution report describes remotely
-requested command executions from each active host system.
-Executions of
+requested command executions from each active host system, like
.I rmail
and
-.I rnews
-are the most common, and are detailed separately. The fields
-are described below:
+.IR rnews "."
+Up to eight command names are displayed. If there are more, the
+rest will be put together in an `Misc.' column.
+The fields are described below:
+.PP
.br
.nf
-.in +.5i
+.in +.3i
.ta 1.0i
-.BR "sysname " "UUCP node name of neighbor host system"
-.BR "rmail " "Number of rmail requests from that system"
-.BR "rnews " "Number of rnews requests from that system"
-.BR "other " "Number of other requests from that system"
-.in -.5i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "(command) " "Number of requests of this command,"
+.BR "Misc. " "Number of other requests, if more than eight."
+.in -.3i
.SS FILES
The file names below may be changed at compilation time or by the
configuration file, so these are only approximations.
.br
.nf
-.in +.5in
-.ta 2.0i
-.IR "/usr/spool/uucp/Log " "Taylor format call/execution log"
-.IR "/usr/spool/uucp/Stats " "Taylor format file transfer log"
+.in +.3in
+.ta 2.2i
+.IR "/usr/spool/uucp/Log " "V2/Taylor format call/execution log,"
+.IR "/usr/spool/uucp/Stats " "V2/Taylor format file transfer log."
.SS "SEE ALSO"
.IR uucico "(8)"
.SS BUGS
-Does not understand older (V2, BNU) logging formats. Anyone care to
-volunteer to add this? I don't use the stuff myself.
+Does not understand other than V2/TAYLOR logging formats. Anyone care to
+volunteer to add the not mentioned?
.PP
-The entries that Taylor UUCP makes in the log file for incoming calls
-don't have a host name. This confuses
-.I uurate
-into thinking that the calls came in for system "-". This may require
-a change to Taylor logging.
+Scanning the arguments of logfile and statfile keywords
+in config should handle lines continued with the backslash as well.
.PP
-Should check the configuration file to locate the currently active
-.I Log
-and
-.I Stats
-files when using them for default inputs. Instead, it uses the
-compile-time settings only.
-.PP
-Should report packet protocol error statistics by host and
-protocol type.
+The
+.B failfm
+field in the call statistics table is always zero, unless
+something really serious happens, e.g. uucico got SIGQUIT or
+the whole system crashed.
.SS AUTHOR
-Robert B. Denny (denny@alisa.com)
+Robert B. Denny (denny@alisa.com).
.br
Loosely based on the DECUS UUCP program
.I uurate
by Mark Pizzolato.
-
-
-
-
-
-
+.br
+Modified by Stephan Niemz (stephan@sunlab.ka.sub.org).
+.br
+Modified by Klaus Dahlenburg (kdburg@incoahe.hanse.de).
diff --git a/gnu/libexec/uucp/contrib/uureroute.perl b/gnu/libexec/uucp/contrib/uureroute.perl
new file mode 100755
index 000000000000..3eeb654e1e27
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uureroute.perl
@@ -0,0 +1,91 @@
+#!/usr/local/bin/perl
+eval ' exec /usr/local/bin/perl $0 "$@" '
+ if $running_under_some_shell;
+
+# From a script by <Bill.Campbell@celestial.com>
+# Newsgroups: comp.sources.misc
+# Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01
+# Date: 26 Feb 92 02:28:37 GMT
+#
+# This is a Honey DanBer specific routine written in perl to reroute all
+# mail queued up for a specific host. It needs to be run as "root" since
+# uucp will not allow itself to remove others requests.
+#
+# Revision *** 92/21/09: Francois Pinard <pinard@iro.umontreal.ca>
+# 1. adapted for Taylor UUCP
+#
+# Revision 1.3 91/10/08 09:01:21 src
+# 1. Rewritten in perl
+# 2. Add -v option for debugging.
+#
+# Revision 1.2 91/10/07 23:57:42 root
+# 1. Fix mail program path.
+# 2. Truncate directory name to 7 characters
+
+($progname = $0) =~ s!.*/!!; # save this very early
+
+$USAGE = "
+# Reroute uucp mail
+#
+# Usage: $progname [-v] host [host...]
+#
+# Options Argument Description
+# -v Verbose (doesn't execute /bin/sh)
+#
+";
+
+$UUSTAT = "/usr/local/bin/uustat";
+$SHELL = "/bin/sh";
+$SMAIL = "/bin/smail";
+
+sub usage
+{
+ die join ("\n", @_) . "\n$USAGE\n";
+}
+
+do "getopts.pl";
+
+&usage ("Invalid Option") unless do Getopts ("vV");
+
+$verbose = ($opt_v ? '-v' : ());
+$suffix = ($verbose ? '' : $$);
+
+&usage ("No system specified") if $#ARGV < 0;
+
+if (!$verbose)
+{
+ open (SHELL, "| $SHELL");
+ select SHELL;
+}
+
+while ($system = shift)
+{
+ $sysprefix = substr ($system, 0, 7);
+ $directory = "/usr/spool/uucp/$sysprefix";
+ open (UUSTAT, "$UUSTAT -s $system -c rmail |");
+ print "set -ex\n";
+ while (<UUSTAT>)
+ {
+ ($jobid, ) = split;
+ ($cfile) = substr ($jobid, length ($jobid) - 5);
+ $cfilename = "$directory/C./C.$cfile";
+ open (CFILE, $cfilename) || die "Cannot open $cfilename\n";
+ $_ = <CFILE>;
+ close CFILE;
+ if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/)
+ {
+ $datafile = "$directory/D./D.$1";
+ $address = $2;
+ }
+ else
+ {
+ print STDERR;
+ die "Cannot parse previous line from $cfilename\n";
+ }
+ print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n";
+ }
+ close UUSTAT;
+}
+close SHELL unless $verbose;
+
+exit 0;
diff --git a/gnu/libexec/uucp/contrib/uusnap.c b/gnu/libexec/uucp/contrib/uusnap.c
index d657a620ec8a..a3d9fb433249 100644
--- a/gnu/libexec/uucp/contrib/uusnap.c
+++ b/gnu/libexec/uucp/contrib/uusnap.c
@@ -25,7 +25,7 @@
#include "uucp.h"
#if USE_RCS_ID
-char uusnap_rcsid[] = "$Id: uusnap.c,v 1.1 1993/08/05 18:23:18 conklin Exp $";
+char uusnap_rcsid[] = "$Id: uusnap.c,v 1.2 1994/05/07 18:09:40 ache Exp $";
#endif
#include <ctype.h>
diff --git a/gnu/libexec/uucp/contrib/uutraf b/gnu/libexec/uucp/contrib/uutraf
index 8b56d0f6b4f5..9625ea5206ca 100644
--- a/gnu/libexec/uucp/contrib/uutraf
+++ b/gnu/libexec/uucp/contrib/uutraf
@@ -1,11 +1,11 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# uutraf.pl -- UUCP Traffic Analyzer
-# SCCS Status : @(#)@ uutraf 1.7
+# SCCS Status : @(#)@ uutraf 1.8
# Author : Johan Vromans
# Created On : ***
# Last Modified By: Johan Vromans
-# Last Modified On: Wed Feb 26 08:52:56 1992
-# Update Count : 4
+# Last Modified On: Mon Aug 30 15:02:22 1993
+# Update Count : 6
# Status : OK
# Requires: : Perl V4 or later
@@ -52,7 +52,7 @@ if ( $ARGV[0] =~ /^-/ ) {
}
if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) {
- @ARGV = ("/usr/spool/uucp/Stats") unless $#ARGV >= 0;
+ @ARGV = ("/usr/local/spool/uucp/Stats") unless $#ARGV >= 0;
$pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " .
"(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds";
$uucp_type = 0;
@@ -73,16 +73,17 @@ elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) {
$recv = "received";
}
else {
- die ("Unknown UUCP type: $uucp_type\n");
+ die ("FATAL: Unknown UUCP type: $uucp_type\n");
}
$garbage = 0;
while ( <> ) {
unless ( /$pat/o ) {
- print STDERR "Possible garbage: $_";
+ print STDERR "$_";
+ next if /failed/;
if ( $garbage++ > 10 ) {
- die ("Too much garbage; wrong UUCP type?\n");
+ die ("FATAL: Too much garbage; wrong UUCP type?\n");
}
next;
}
@@ -90,10 +91,10 @@ while ( <> ) {
# gather timestamps
$last_date = $2;
$first_date = $last_date unless defined $first_date;
-
+
# initialize new hosts
unless ( defined $hosts{$1} ) {
- $hosts{$1} = $files_in{$1} = $files_out{$1} =
+ $hosts{$1} = $files_in{$1} = $files_out{$1} =
$bytes_in{$1} = $bytes_out{$1} =
$secs_in{$1} = $secs_out{$1} = 0;
}
@@ -162,9 +163,9 @@ foreach $host (@hosts) {
sub print_line {
reset "Z"; # reset print fields
- local ($Zhost,
- $Zi_bytes, $Zo_bytes,
- $Zi_secs, $Zo_secs,
+ local ($Zhost,
+ $Zi_bytes, $Zo_bytes,
+ $Zi_secs, $Zo_secs,
$Zi_count, $Zo_count) = @_;
$Ti_bytes += $Zi_bytes;
$To_bytes += $Zo_bytes;
@@ -186,7 +187,7 @@ sub print_line {
sub print_dashes {
$Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes =
- $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
+ $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
"------------";
write;
# easy, isn't it?
@@ -196,6 +197,12 @@ sub print_dashes {
sub gethostname {
$ENV{"SHELL"} = "/bin/sh";
+ $try = `hostname 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ $try = `uname -n 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
$try = `uuname -l 2>/dev/null`;
chop $try;
return $+ if $try =~ /^[-.\w]+$/;
diff --git a/gnu/libexec/uucp/contrib/uuxconv b/gnu/libexec/uucp/contrib/uuxconv
new file mode 100755
index 000000000000..843f9e000fab
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuxconv
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# uuxconv
+#
+# After converting to Taylor from SVR4.03 UUCP, I still had a lot of
+# jobs queued up to go out.
+#
+# This script is a one-shot to mass-requeue a site's spool.
+#
+# It doesn't go and do your whole spool, nor even all grades.
+# you need to go into each grade directory for each site and
+# execute this.
+#
+# i.e.: You have a site named 'foo'
+# cd /var/spool/uucp/foo/Z
+# uuxconv foo
+#
+# it does delete the 'D' & 'X' after requeing them, but doesn't remove
+# the 'C' files.
+#
+# I foolishly went and ran this script on all my queued jobs, without
+# adding the improvements to recursively go through the entire UUCP spool,
+# so now I'm out of files to test with. I don't want to add the code
+# to do that since I can't test it, and this worked.
+#
+# I hereby give this (trivial :-)) program to the GNU Project/FSF
+# and Ian Taylor in it's entirety, so that it can be placed in
+# the contrib directory of taylor-uucp, and save others the pain
+# of rewriting it.
+#
+# Richard Nickle (rick@trystro.uucp, rnickle@gnu.ai.mit.edu)
+# May 27, 1993
+#
+if [ $# -eq 0 ]
+then
+ echo "Usage: $0 sitename"
+ exit 1
+fi
+exit 0
+site=$1
+tsite=`echo $site | cut -c1-5`
+find . -name "D.$tsite*" -print |
+while read file
+do
+ control=`egrep "^C" $file | cut -c3-`
+ input=`egrep "^I" $file | cut -c3-`
+ (uux - -r -z $site!$control < $input) && (rm $file $input)
+ echo "$site!$control < $input"
+done
+exit 0
diff --git a/gnu/libexec/uucp/contrib/xchat.c b/gnu/libexec/uucp/contrib/xchat.c
index 0fd763d9f3fc..b44549e53ed4 100644
--- a/gnu/libexec/uucp/contrib/xchat.c
+++ b/gnu/libexec/uucp/contrib/xchat.c
@@ -9,6 +9,9 @@
* Bob Denny (denny@alisa.com)
* Based on code in DECUS UUCP (for VAX/VMS)
*
+ * Small modification by:
+ * Daniel Hagerty (hag@eddie.mit.edu)
+ *
* History:
* Version 1.0 shipped with Taylor 1.03. No configuration info inside.
*
@@ -18,21 +21,25 @@
* for timed reads. Use Taylor UUCP "conf.h" file to set
* configuration for this program. Add defaulting of script
* and log file paths.
+ *
+ * Daniel Hagerty - Mon Nov 22 18:17:38 1993
+ * V1.2 - Added a new opcode to xchat. "expectstr" is a cross between
+ * sendstr and expect, looking for a parameter supplied string.
+ * Useful where a prompt could change for different dial in
+ * lines and such.
*
* Bugs:
* Does not support BSD terminal I/O. Anyone care to add it?
*/
-#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <time.h>
-#include <sys/time.h>
#include <sys/ioctl.h>
-#include <sys/termios.h>
+#include <sys/termio.h>
#include "xc-conf.h"
@@ -132,7 +139,8 @@ struct script_opdef {
#define SC_PEVN 39 /* Set port for 7-bit, even parity */
#define SC_PODD 40 /* Set port for 7-bit, odd parity */
#define SC_HUPS 41 /* Change state on HUP signal */
-#define SC_END 42 /* end of array */
+#define SC_XPST 42 /* Expect a param string */
+#define SC_END 43 /* end of array */
/* values for prmtype, prm2type */
@@ -188,6 +196,7 @@ static struct script_opdef sc_opdef[] =
{"sendstr", SC_SNDP, SC_INT, SC_NONE},
{"ifstr", SC_IF1P, SC_INT, SC_NWST},
{"ifnstr", SC_IF0P, SC_INT, SC_NWST},
+ {"expectstr", SC_XPST, SC_INT, SC_NWST},
{"table end", SC_END, SC_NONE, SC_NONE}
};
@@ -224,16 +233,16 @@ static char telno[64]; /* Telephone number w/meta-chars */
static int Debug;
static int fShangup = FALSE; /* TRUE if HUP signal received */
static FILE *dbf = NULL;
-static struct termios old, new;
+static struct termio old, new;
-static void usignal();
-static void uhup();
+extern int usignal();
+extern int uhup();
static struct siglist
{
int signal;
- void (*o_catcher) ();
- void (*n_catcher) ();
+ int (*o_catcher) ();
+ int (*n_catcher) ();
} sigtbl[] = {
{ SIGHUP, NULL, uhup },
{ SIGINT, NULL, usignal },
@@ -246,17 +255,17 @@ static struct siglist
extern struct script *read_script();
extern void msleep();
-static char xgetc();
-static void charlog();
-static void setup_tty();
-static void restore_tty();
-static void ttoslow();
-static void ttflui();
-static void tthang();
-static void ttbreak();
-static void tt7bit();
-static void ttpar();
-static void DEBUG();
+extern char xgetc();
+extern void charlog();
+extern void setup_tty();
+extern void restore_tty();
+extern void ttoslow();
+extern void ttflui();
+extern void tthang();
+extern void ttbreak();
+extern void tt7bit();
+extern void ttpar();
+extern void DEBUG();
extern void *malloc();
@@ -337,7 +346,7 @@ char *argv[];
sigs = &sigtbl[0];
while(sigs->signal)
{
- sigs->o_catcher = signal(sigs->signal, sigs->n_catcher);
+ sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher);
sigs += 1;
}
@@ -1031,6 +1040,7 @@ int do_script(begin)
case SC_TIMO: /* these are "expects", don't bother */
case SC_XPCT: /* with them yet, other than noting that */
case SC_CARR: /* they exist */
+ case SC_XPST:
expcnt++;
break;
}
@@ -1134,7 +1144,24 @@ int do_script(begin)
}
}
}
-
+ /* New opcode added by hag@eddie.mit.edu for expecting a
+ parameter supplied string */
+ case SC_XPST:
+ if(curscr->intprm >paramc-1)
+ {
+ sprintf(tempstr,"expectstr - param#%d",curscr->intprm);
+ logit(tempstr, " not present");
+ return(FAIL);
+ }
+ prmlen=xlat_str(tempstr,paramv[curscr->intprm]);
+ if((expin >= prmlen) &&
+ (strncmp(tempstr,&expbuf[expin-prmlen],
+ prmlen) == SAME))
+ {
+ charlog(tempstr,prmlen,DB_LGI, "Matched");
+ goto _chgstate;
+ }
+ break;
/*
* SIGNAL HANDLERS
*/
@@ -1142,7 +1169,7 @@ int do_script(begin)
/*
* usignal - generic signal catcher
*/
-static void usignal(isig)
+static int usignal(isig)
int isig;
{
DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig);
@@ -1153,7 +1180,7 @@ static void usignal(isig)
/*
* uhup - HUP catcher
*/
-static void uhup(isig)
+static int uhup(isig)
int isig;
{
DEBUG(DB_LOG, "Data set hangup.\n");
@@ -1175,15 +1202,14 @@ int tmo; /* Timeout, seconds */
{
char c;
struct timeval s;
- fd_set f;
+ int f = 1; /* Select on stdin */
int result;
- FD_SET(0,&f); /* Select on stdin */
if(read(0, &c, 1) <= 0) /* If no data available */
{
s.tv_sec = (long)tmo;
s.tv_usec = 0L;
- if(select (1, &f, (fd_set *) NULL, &f, &s) == 1)
+ if(select (1, &f, (int *) NULL, &f, &s) == 1)
read(0, &c, 1);
else
c = '\377';
@@ -1294,7 +1320,7 @@ static void setup_tty()
{
register int i;
- tcgetattr(0,&old);
+ ioctl(0, TCGETA, &old);
new = old;
@@ -1305,7 +1331,7 @@ static void setup_tty()
new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */
new.c_lflag = 0; /* No special line discipline */
- tcsetattr(0,TCSANOW,&new);
+ ioctl(0, TCSETA, &new);
}
/*
@@ -1314,7 +1340,7 @@ static void setup_tty()
static void restore_tty(sig)
int sig;
{
- tcsetattr(0,TCSANOW,&old);
+ ioctl(0, TCSETA, &old);
return;
}
@@ -1346,7 +1372,7 @@ static void ttoslow(s, len, delay)
static void ttflui()
{
if(isatty(0))
- tcflush(0,TCIFLUSH);
+ (void) ioctl ( 0, TCFLSH, 0);
}
/*
@@ -1364,13 +1390,13 @@ static int ttcd()
*/
static void tthang()
{
- if(!isatty(1))
+ if(!isatty())
return;
-#ifdef TIOCCDTR
- (void) ioctl (1, TIOCCDTR, 0);
+#ifdef TCCLRDTR
+ (void) ioctl (1, TCCLRDTR, 0);
sleep (2);
- (void) ioctl (1, TIOCSDTR, 0);
+ (void) ioctl (1, TCSETDTR, 0);
#endif
return;
@@ -1381,7 +1407,7 @@ static void tthang()
*/
static void ttbreak()
{
- tcsendbreak(1,5);
+ (void) ioctl (1, TCSBRK, 0);
}
/*
@@ -1405,7 +1431,7 @@ static void tt7bit(enable)
else
new.c_iflag &= ~ISTRIP;
- tcsetattr(0,TCSANOW,&new);
+ ioctl(0, TCSETA, &new);
}
/*
@@ -1436,5 +1462,12 @@ static void ttpar(mode)
break;
}
- tcsetattr(0,TCSANOW,&new);
+ ioctl(0, TCSETA, &new);
}
+
+
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/xchat.man b/gnu/libexec/uucp/contrib/xchat.man
index c980e202fcb4..55537be90726 100644
--- a/gnu/libexec/uucp/contrib/xchat.man
+++ b/gnu/libexec/uucp/contrib/xchat.man
@@ -380,6 +380,18 @@ is received from standard input (usually the serial port).
Case is significant, but high-order bits are not
checked.
.TP 2.0i
+.BI "expectstr " "ns int"
+Change to state
+.I ns
+if the string specified in parameter
+.I int
+is received from standard input (usually the serial port).
+.I int
+must be in the range 0 to 7.
+Case is significant, but high-order bits are not
+checked.
+Useful where a prompt can change in different dial-in lines.
+.TP 2.0i
.BI "ifcarr " ns
Change to state
.I ns
@@ -604,6 +616,8 @@ seconds).
uucico(8) for Taylor UUCP, and documentation for Taylor UUCP.
.SH AUTHOR
Robert B. Denny (denny@alisa.com)
+.SH CONTRIBUTORS
+Daniel Hagerty (hag@eddie.mit.edu)
.SH HISTORY
This program is an adaptation of the dial/login script processing
code that is a part of DECUS UUCP for VAX/VMS, written by Jamie
diff --git a/gnu/libexec/uucp/cu/Makefile b/gnu/libexec/uucp/cu/Makefile
index c2171a690a83..ada7ab2b64a7 100644
--- a/gnu/libexec/uucp/cu/Makefile
+++ b/gnu/libexec/uucp/cu/Makefile
@@ -1,9 +1,9 @@
# Makefile for cu
-# $Id: Makefile,v 1.1 1993/08/05 18:23:27 conklin Exp $
+# $Id: Makefile,v 1.3 1994/05/31 07:47:39 ache Exp $
BINDIR= $(bindir)
BINOWN= $(owner)
-BINMODE= 4555
+BINMODE= 4555
PROG= cu
SRCS= cu.c prot.c log.c chat.c conn.c tcp.c tli.c copy.c
diff --git a/gnu/libexec/uucp/cu/cu.1 b/gnu/libexec/uucp/cu/cu.1
index c08fe8020f25..630e11ca6e96 100644
--- a/gnu/libexec/uucp/cu/cu.1
+++ b/gnu/libexec/uucp/cu/cu.1
@@ -1,5 +1,5 @@
-''' $Id: cu.1,v 1.1 1993/08/05 18:23:28 conklin Exp $
-.TH cu 1 "Taylor UUCP 1.04"
+''' $Id: cu.1,v 1.2 1994/05/07 18:09:51 ache Exp $
+.TH cu 1 "Taylor UUCP 1.05"
.SH NAME
cu \- Call up another system
.SH SYNOPSIS
@@ -22,8 +22,12 @@ Otherwise, if the argument begins with a digit, it is taken to be a
phone number to call. Otherwise, it is taken to be the name of a
system to call. The
.B \-z
+or
+.B \-\-system
option may be used to name a system beginning with a digit, and the
.B \-c
+or
+.B \-\-phone
option may be used to name a phone number that does not begin with a
digit.
@@ -31,9 +35,9 @@ digit.
locates a port to use in the UUCP configuration files. If a simple
system name is given, it will select a port appropriate for that
system. The
-.B \-p, \-l
+.B \-p, \-\-port, \-l, \-\-line, \-s
and
-.B \-s
+.B \-\-speed
options may be used to control the port selection.
When a connection is made to the remote system,
@@ -208,53 +212,55 @@ default is true.
The following options may be given to
.I cu.
.TP 5
-.B \-e
+.B \-e, \-\-parity=even
Use even parity.
.TP 5
-.B \-o
-Use odd parity. If both
+.B \-o, \-\-parity=odd
+Use odd parity.
+.TP 5
+.B \-\-parity=none
+Use no parity. No parity is also used if both
.B \-e
and
.B \-o
-are used, no parity is used. Otherwise the default parity of the line
-is used.
+are given.
.TP 5
-.B \-h
+.B \-h, \-\-halfduplex
Echo characters locally (half-duplex mode).
.TP 5
-.B \-z system
+.B \-z system, \-\-system system
The system to call.
.TP 5
-.B \-c phone-number
+.B \-c phone-number, \-\-phone phone-number
The phone number to call.
.TP 5
-.B \-p port
+.B \-p port, \-\-port port
Name the port to use.
.TP 5
.B \-a port
Equivalent to
-.B \-p port.
+.B \-\-port port.
.TP 5
-.B \-l line
+.B \-l line, \-\-line line
Name the line to use by giving a device name. This may be used to
dial out on ports that are not listed in the UUCP configuration files.
Write access to the device is required.
.TP 5
-.B \-s speed
+.B \-s speed, \-\-speed speed
The speed (baud rate) to use.
.TP 5
.B \-#
Where # is a number, equivalent to
-.B \-s #.
+.B \-\-speed #.
.TP 5
-.B \-n
+.B \-n, \-\-prompt
Prompt for the phone number to use.
.TP 5
.B \-d
Enter debugging mode. Equivalent to
-.B \-x all.
+.B \-debug all.
.TP 5
-.B \-x type
+.B \-x type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing. Only abnormal, chat,
@@ -262,20 +268,26 @@ handshake, port, config, incoming and outgoing are meaningful for
.I cu.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
-.B \-x all
+.B \-\-debug abnormal,chat.
+.B \-\-debug all
may be used to turn on all debugging options.
.TP 5
-.B \-I file
+.B \-I file, \-\-config file
Set configuration file to use. This option may not be available,
depending upon how
.I cu
was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
.SH BUGS
This program does not work very well.
.SH FILES
@@ -284,3 +296,6 @@ approximation.
.br
/usr/lib/uucp/config - Configuration file.
+.SH AUTHOR
+Ian Lance Taylor
+<ian@airs.com>
diff --git a/gnu/libexec/uucp/cu/cu.c b/gnu/libexec/uucp/cu/cu.c
index 5e34601de3b9..3939f6a02ece 100644
--- a/gnu/libexec/uucp/cu/cu.c
+++ b/gnu/libexec/uucp/cu/cu.c
@@ -1,7 +1,7 @@
/* cu.c
Call up a remote system.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char cu_rcsid[] = "$Id: cu.c,v 1.1 1993/08/05 18:23:29 conklin Exp $";
+const char cu_rcsid[] = "$Id: cu.c,v 1.2 1994/05/07 18:09:54 ache Exp $";
#endif
#include "cu.h"
@@ -66,7 +66,7 @@ boolean fCuvar_binary = FALSE;
/* A prefix string to use before sending a binary character from a
file; this is only used if fCuvar_binary is TRUE. The default is
- ^Z. */
+ ^V. */
const char *zCuvar_binary_prefix = "\026";
/* Whether to check for echoes of characters sent when sending a file.
@@ -126,9 +126,6 @@ static const struct uuconf_cmdtab asCuvars[] =
{ NULL, 0, NULL, NULL}
};
-/* The program name. */
-char abProgram[] = "cu";
-
/* The string printed at the initial connect. */
#if ANSI_C
#define ZCONNMSG "\aConnected."
@@ -175,6 +172,9 @@ static boolean fCulocalecho;
/* Whether we need to call fsysdep_cu_finish. */
static boolean fCustarted;
+/* Whether ZCONNMSG has been printed yet. */
+static boolean fCuconnprinted = FALSE;
+
/* A structure used to pass information to icuport_lock. */
struct sconninfo
{
@@ -187,6 +187,7 @@ struct sconninfo
/* Local functions. */
static void ucuusage P((void));
+static void ucuhelp P((void));
static void ucuabort P((void));
static void uculog_start P((void));
static void uculog_end P((void));
@@ -209,7 +210,24 @@ static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
/* Long getopt options. */
-static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asCulongopts[] =
+{
+ { "phone", required_argument, NULL, 'c' },
+ { "parity", required_argument, NULL, 2 },
+ { "halfduplex", no_argument, NULL, 'h' },
+ { "prompt", no_argument, NULL, 'n' },
+ { "line", required_argument, NULL, 'l' },
+ { "port", required_argument, NULL, 'p' },
+ { "speed", required_argument, NULL, 's' },
+ { "baud", required_argument, NULL, 's' },
+ { "mapcr", no_argument, NULL, 't' },
+ { "system", required_argument, NULL, 'z' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -252,6 +270,8 @@ main (argc, argv)
struct uuconf_dialer *qdialer;
char bcmd;
+ zProgram = argv[0];
+
/* We want to accept -# as a speed. It's easiest to look through
the arguments, replace -# with -s#, and let getopt handle it. */
for (i = 1; i < argc; i++)
@@ -271,7 +291,7 @@ main (argc, argv)
}
}
- while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:",
+ while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tvx:z:",
asCulongopts, (int *) NULL)) != EOF)
{
switch (iopt)
@@ -347,13 +367,47 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ fprintf
+ (stderr,
+ "%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 2:
+ /* --parity. */
+ if (strncmp (optarg, "even", strlen (optarg)) == 0)
+ feven = TRUE;
+ else if (strncmp (optarg, "odd", strlen (optarg)) == 0)
+ fodd = TRUE;
+ else if (strncmp (optarg, "none", strlen (optarg)) == 0)
+ {
+ feven = TRUE;
+ fodd = TRUE;
+ }
+ else
+ {
+ fprintf (stderr, "%s: --parity requires even, odd or none\n",
+ zProgram);
+ ucuusage ();
+ }
+ break;
+
+ case 1:
+ /* --help. */
+ ucuhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
ucuusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -366,7 +420,10 @@ main (argc, argv)
if (optind != argc - 1
|| zsystem != NULL
|| zphone != NULL)
- ucuusage ();
+ {
+ fprintf (stderr, "%s: too many arguments\n", zProgram);
+ ucuusage ();
+ }
if (strcmp (argv[optind], "dir") != 0)
{
if (isdigit (BUCHAR (argv[optind][0])))
@@ -382,7 +439,11 @@ main (argc, argv)
&& zport == NULL
&& zline == NULL
&& ibaud == 0L)
- ucuusage ();
+ {
+ fprintf (stderr, "%s: must specify system, line, port or speed\n",
+ zProgram);
+ ucuusage ();
+ }
if (fprompt)
{
@@ -395,7 +456,7 @@ main (argc, argv)
if (getline (&zphone, &cphone, stdin) <= 0
|| *zphone == '\0')
{
- fprintf (stderr, "%s: No phone number entered\n", abProgram);
+ fprintf (stderr, "%s: no phone number entered\n", zProgram);
exit (EXIT_FAILURE);
}
}
@@ -523,16 +584,20 @@ main (argc, argv)
sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
- if (! fsysdep_port_access (&sport))
- ulog (LOG_FATAL, "%s: Permission denied", zline);
-
- if (! fconn_init (&sport, &sconn))
+ if (! fconn_init (&sport, &sconn, UUCONF_PORTTYPE_UNKNOWN))
ucuabort ();
if (! fconn_lock (&sconn, FALSE))
ulog (LOG_FATAL, "%s: Line in use", zline);
qCuconn = &sconn;
+
+ /* Check user access after locking the port, because on
+ some systems shared lines affect the ownership and
+ permissions. In such a case ``Line in use'' is more
+ clear than ``Permission denied.'' */
+ if (! fsysdep_port_access (&sport))
+ ulog (LOG_FATAL, "%s: Permission denied", zline);
}
ihighbaud = 0L;
}
@@ -544,7 +609,8 @@ main (argc, argv)
continue;
if (qsys->uuconf_qport != NULL)
{
- if (fconn_init (qsys->uuconf_qport, &sconn))
+ if (fconn_init (qsys->uuconf_qport, &sconn,
+ UUCONF_PORTTYPE_UNKNOWN))
{
if (fconn_lock (&sconn, FALSE))
{
@@ -648,7 +714,8 @@ main (argc, argv)
|| qsys == NULL)
ucuabort ();
- if (qsys->uuconf_qalternate == NULL)
+ qsys = qsys->uuconf_qalternate;
+ if (qsys == NULL)
ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
fCuclose_conn = FALSE;
@@ -693,6 +760,7 @@ main (argc, argv)
only comes out when a special command is received from the
terminal. */
printf ("%s\n", ZCONNMSG);
+ fCuconnprinted = TRUE;
if (! fsysdep_terminal_raw (fCulocalecho))
ucuabort ();
@@ -719,7 +787,8 @@ main (argc, argv)
(void) fconn_unlock (&sconn);
uconn_free (&sconn);
- printf ("\n%s\n", ZDISMSG);
+ if (fCuconnprinted)
+ printf ("\n%s\n", ZDISMSG);
ulog_close ();
@@ -734,41 +803,56 @@ main (argc, argv)
static void
ucuusage ()
{
+ fprintf (stderr, "Usage: %s [options] [system or phone-number]\n",
+ zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+ucuhelp ()
+{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ "Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
fprintf (stderr,
- "Usage: cu [options] [system or phone-number]\n");
+ "Usage: %s [options] [system or phone-number]\n", zProgram);
fprintf (stderr,
- " -a port, -p port: Use named port\n");
+ " -a,-p,--port port: Use named port\n");
fprintf (stderr,
- " -l line: Use named device (e.g. tty0)\n");
+ " -l,--line line: Use named device (e.g. tty0)\n");
fprintf (stderr,
- " -s speed, -#: Use given speed\n");
+ " -s,--speed,--baud speed, -#: Use given speed\n");
fprintf (stderr,
- " -c phone: Phone number to call\n");
+ " -c,--phone phone: Phone number to call\n");
fprintf (stderr,
- " -z system: System to call\n");
+ " -z,--system system: System to call\n");
fprintf (stderr,
" -e: Set even parity\n");
fprintf (stderr,
" -o: Set odd parity\n");
fprintf (stderr,
- " -h: Echo locally\n");
+ " --parity={odd,even}: Set parity\n");
+ fprintf (stderr,
+ " -h,--halfduplex: Echo locally\n");
fprintf (stderr,
- " -t: Map carriage return to carriage return/linefeed\n");
+ " -t,--mapcr: Map carriage return to carriage return/linefeed\n");
fprintf (stderr,
- " -n: Prompt for phone number\n");
+ " -n,--prompt: Prompt for phone number\n");
fprintf (stderr,
" -d: Set maximum debugging level\n");
fprintf (stderr,
- " -x debug: Set debugging type\n");
+ " -x,--debug debug: Set debugging type\n");
#if HAVE_TAYLOR_CONFIG
fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ " -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
-
- exit (EXIT_FAILURE);
+ fprintf (stderr,
+ " -v,--version: Print version and exit\n");
+ fprintf (stderr,
+ " --help: Print help and exit\n");
}
/* This function is called when a fatal error occurs. */
@@ -805,7 +889,8 @@ ucuabort ()
ulog_close ();
- printf ("\n%s\n", ZDISMSG);
+ if (fCuconnprinted)
+ printf ("\n%s\n", ZDISMSG);
usysdep_exit (FALSE);
}
@@ -866,7 +951,7 @@ icuport_lock (qport, pinfo)
q->fmatched = TRUE;
- if (! fconn_init (qport, q->qconn))
+ if (! fconn_init (qport, q->qconn, UUCONF_PORTTYPE_UNKNOWN))
return UUCONF_NOT_FOUND;
else if (! fconn_lock (q->qconn, FALSE))
{
diff --git a/gnu/libexec/uucp/doc/uucp.texi b/gnu/libexec/uucp/doc/uucp.texi
new file mode 100644
index 000000000000..5ab74118d6e9
--- /dev/null
+++ b/gnu/libexec/uucp/doc/uucp.texi
@@ -0,0 +1,4036 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename uucp.info
+@settitle Taylor UUCP
+@setchapternewpage odd
+@c %**end of header
+
+@iftex
+@finalout
+@end iftex
+
+@ignore
+---------------------------------------------------------------------->
+Franc,ois Pinard says:
+
+Hi, Ian! This is the promised merging of the current documents from
+Taylor UUCP 1.01, plus the patches to documentation you sent to me, into
+a taylor.texi file. Many things remain to do, among which:
+
+- merging in the Taylor UUCP program man pages.
+----------------------------------------------------------------------<
+@end ignore
+
+@ifinfo
+This file documents Taylor UUCP, version 1.05.
+
+Copyright @copyright{} 1992, 1993, 1994 Ian Lance Taylor
+
+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.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a 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 copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``Copying'' are included exactly as in the original, and
+provided 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 the section entitled ``Copying'' may be included in a
+translation approved by the author instead of in the original English.
+@end ifinfo
+
+@titlepage
+@title Taylor UUCP
+@subtitle Version 1.05
+@author Ian Lance Taylor @code{<ian@@airs.com>}
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993, 1994 Ian Lance Taylor
+
+Published by Ian Lance Taylor @code{<ian@@airs.com>}.
+
+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
+section entitled ``Copying'' are included exactly as in the original, and
+provided 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 the section entitled ``Copying'' may be included in a
+translation approved by the author instead of in the original English.
+@end titlepage
+
+@node Top, Copying, (dir), (dir)
+@top Taylor UUCP 1.05
+
+This is the documentation for the Taylor UUCP package, version 1.05.
+The programs were written by Ian Lance Taylor. The author can be
+reached at @code{<ian@@airs.com>}, or @samp{c/o Cygnus Support, Building
+200, 1 Kendall Square, Cambridge, MA, 02139, USA}.
+
+There is a mailing list for discussion of the package. To join (or get
+off) the list, send mail to
+@code{<taylor-uucp-request@@gnu.ai.mit.edu>}. Mail to this address is
+answered by a person, not a program. When joining the list, please give
+the address at which you wish to receive mail; do not rely on the
+message headers. To send a message to the list, send it to
+@code{<taylor-uucp@@gnu.ai.mit.edu>}.
+
+Jeff Ross has volunteered to maintain patches for UUCP releases. They
+may be obtained via anonymous FTP from ftp.fdu.edu, in the directory
+pub/taylor-uucp.
+
+@menu
+* Copying:: Taylor UUCP copying conditions
+* Introduction:: Introduction to Taylor UUCP
+* Overall Installation:: Taylor UUCP installation
+* Configuration Files:: Taylor UUCP configuration files
+* Protocols:: UUCP protocol internals
+* Hacking:: Hacking Taylor UUCP
+* Acknowledgements:: Acknowledgements
+
+* Index (concepts):: Concept index
+* Index (configuration file):: Index to new configuration files
+
+ --- The Detailed Node Listing ---
+
+Taylor UUCP Overall Installation
+
+* Configuration:: Configuring Taylor UUCP
+* Compilation:: Compiling Taylor UUCP
+* Testing:: Testing Taylor UUCP
+* Installation:: Installing Taylor UUCP
+* TCP:: TCP together with Taylor UUCP
+
+Installing Taylor UUCP
+
+* Running uucico:: Running uucico
+* Using UUCP for mail and news:: Using UUCP for mail and news.
+* Trimming UUCP Log Files:: Trimming UUCP Log Files
+
+Using UUCP for mail and news.
+
+* Sending mail or news:: Sending mail or news via UUCP
+* Receiving mail or news:: Receiving mail or news via UUCP
+
+Taylor UUCP Configuration Files
+
+* Configuration File Format:: Configuration file format
+* Configuration File Overview:: Configuration File Overview
+* Configuration Examples:: Examples of configuration files
+* Time Strings:: How to write time strings
+* Chat Scripts:: How to write chat scripts
+* config File:: The main configuration file
+* sys File:: The system configuration file
+* port File:: The port configuration files
+* dial File:: The dialer configuration files
+* Security:: Security issues
+
+Examples of Configuration Files
+
+* config File Examples:: Examples of the main configuration file
+* Leaf Example:: Call a single remote site
+* Gateway Example:: The gateway for several local systems
+
+The Main Configuration File
+
+* Miscellaneous (config):: Miscellaneous config file commands
+* Configuration File Names:: Using different configuration files
+* Log File Names:: Using different log files
+* Debugging Levels:: Debugging levels
+
+The System Configuration File
+
+* Defaults and Alternates:: Using defaults and alternates
+* Naming the System:: Naming the system
+* Calling Out:: Calling out
+* Accepting a Call:: Accepting a call
+* Protocol Selection:: Protocol selection
+* File Transfer Control:: File transfer control
+* Miscellaneous (sys):: Miscellaneous sys file commands
+* Default sys File Values:: Default values
+
+Calling Out
+
+* When to Call:: When to call
+* Placing the Call:: Placing the call
+* Logging In:: Logging in
+
+Hacking Taylor UUCP
+
+* System Dependence:: System Dependence
+* Naming Conventions:: Naming Conventions
+* Patches:: Patches
+@end menu
+
+@node Copying, Introduction, Top, Top
+@unnumbered Taylor UUCP Copying Conditions
+
+This package is covered by the GNU Public License. See the file
+@file{COPYING} for details. If you would like to do something with this
+package that you feel is reasonable, but you feel is prohibited by the
+license, contact me to see if we can work it out.
+
+Here is some propaganda from the Free Software Foundation. If you find
+this stuff offensive or annoying, remember that you probably did not
+spend any money to get this code. I did not write this code to make
+life easier for developers of UUCP packages, I wrote it to help end
+users, and I believe that these are the most appropriate conditions for
+distribution.
+
+All the programs, scripts and documents relating to Taylor UUCP are
+@dfn{free}; this means that everyone is free to use them and free to
+redistribute them on a free basis. The Taylor UUCP-related programs are
+not in the public domain; they are copyrighted and there are
+restrictions on their distribution, but these restrictions are designed
+to permit everything that a good cooperating citizen would want to do.
+What is not allowed is to try to prevent others from further sharing any
+version of these programs that they might get from you.
+
+Specifically, we want to make sure that you have the right to give away
+copies of the programs that relate to Taylor UUCP, that you receive
+source code or else can get it if you want it, that you can change these
+programs or use pieces of them in new free programs, and that you know
+you can do these things.
+
+To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute
+copies of the Taylor UUCP related programs, 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.
+
+Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for the programs that relate to Taylor
+UUCP. If these programs are modified by someone else and passed on, we
+want their recipients to know that what they have is not what we
+distributed, so that any problems introduced by others will not reflect
+on our reputation.
+
+The precise conditions of the licenses for the programs currently being
+distributed that relate to Taylor UUCP are found in the General Public
+Licenses that accompany them.
+
+@node Introduction, Overall Installation, Copying, Top
+@chapter Introduction to Taylor UUCP
+
+General introductions to UUCP are available, and perhaps one day I will
+write one. In the meantime, here is a very brief one that concentrates
+on the programs provided by Taylor UUCP.
+
+Taylor UUCP is a complete UUCP package. It is covered by the GNU Public
+License, which means that the source code is always available. It is
+composed of several programs; most of the names of these programs are
+based on earlier UUCP packages.
+
+@table @code
+
+@item uucp
+
+The @code{uucp} program is used to copy file between systems. It is
+similar to the standard Unix @code{cp} program, except that you can
+refer to a file on a remote system by using @samp{system!} before the
+file name. For example, to copy the file @file{notes.txt} to the system
+@samp{airs}, you would say @samp{uucp notes.txt airs!~/notes.txt}. In
+this example @samp{~} is used to name the UUCP public directory on
+@samp{airs}.
+
+@item uux
+
+The @code{uux} program is used to request the execution of a program on
+a remote system. This is how mail and news are transferred over UUCP.
+As with @code{uucp}, programs and files on remote systems may be named
+by using @samp{system!}. For example, to run the @code{rnews} program
+on @samp{airs} passing it standard input, you would say @samp{uux -
+airs!rnews}. The @samp{-} means to read standard input and set things
+up such that when @code{rnews} runs on @samp{airs} it will receive the
+same standard input.
+
+@end table
+
+Neither @code{uucp} nor @code{uux} actually do any work immediately.
+Instead, they queue up requests for later processing. They then start a
+daemon process which processes the requests and calls up the appropriate
+systems. Normally the system will also start the daemon periodically to
+check if there is any work to be done. The advantage of this approach
+is that it all happens automatically. You don't have to sit around
+waiting for the files to be transferred. The disadvantage is that if
+anything goes wrong it might be a while before anybody notices.
+
+@table @code
+
+@item uustat
+
+The @code{uustat} program does many things. By default it will simply
+list all the jobs you have queued with @code{uucp} or @code{uux} that
+have not yet been processed. You can use @code{uustat} to remove any of
+your jobs from the queue. You can also it use it to show the status of
+the UUCP system in various ways, such as showing the connection status
+of all the remote systems your system knows about. The system
+administrator can use @code{uustat} to automatically discard old jobs
+while sending mail to the user who requested them.
+
+@item uuname
+
+The @code{uuname} program by default lists all the remote systems your
+system knows about. You can also use it to get the name of your local
+system. It is mostly useful for shell scripts.
+
+@item uulog
+
+The @code{uulog} program can be used to display entries in the UUCP log
+file. It can select the entries for a particular system or a particular
+user. You can use it to see what has happened to your queued jobs in
+the past.
+
+@item uuto
+@item uupick
+
+@code{uuto} is a simple shell script interface to @code{uucp}. It will
+transfer a file, or the contents of a directory, to a remote system, and
+notify a particular user on the remote system when it arrives. The
+remote user can then retrieve the file(s) with @code{uupick}.
+
+@item cu
+
+The @code{cu} program can be used to call up another system and
+communicate with it as though you were directly connected. It can also
+do simple file transfers, though it does not provide any error checking.
+
+@end table
+
+These eight programs just described, @code{uucp}, @code{uux},
+@code{uuto}, @code{uupick}, @code{uustat}, @code{uuname}, @code{uulog},
+and @code{cu} are the user programs provided by Taylor UUCP@.
+@code{uucp}, @code{uux}, and @code{uuto} add requests to the work queue,
+@code{uupick} extracts files from the UUCP public directory,
+@code{uustat} examines the work queue, @code{uuname} examines the
+configuration files, @code{uulog} examines the log files, and @code{cu}
+just uses the UUCP configuration files.
+
+The real work is actually done by two daemon processes, which are
+normally run automatically rather than by a user.
+
+@table @code
+
+@item uucico
+
+The @code{uucico} daemon is the program which actually calls the remote
+system and transfers files and requests. @code{uucico} is normally
+started automatically by @code{uucp} and @code{uux}. Most systems will
+also start it periodically to make sure that all work requests are
+handled. @code{uucico} checks the queue to see what work needs to be
+done, and then calls the appropriate systems. If the call fails,
+perhaps because the phone line is busy, @code{uucico} leaves the
+requests in the queue and goes on to the next system to call. It is
+also possible to force @code{uucico} to call a remote system even if
+there is no work to be done for it, so that it can pick up any work that
+may be queued up remotely.
+
+@need 1000
+@item uuxqt
+
+The @code{uuxqt} daemon processes execution requests made by the
+@code{uux} program on remote systems. It also processes requests made
+on the local system which require files from a remote system. It is
+normally started by @code{uucico}.
+
+@end table
+
+Suppose you, on the system @samp{bantam}, want to copy a file to the
+system @samp{airs}. You would run the @code{uucp} command locally, with
+a command like @samp{uucp notes.txt airs!~/notes.txt}. This would queue
+up a request on @samp{bantam} for @samp{airs}, and would then start the
+@code{uucico} daemon. @code{uucico} would see that there was a request
+for @samp{airs} and attempt to call it. When the call succeeded,
+another copy of @code{uucico} would be started on @samp{airs}. The two
+copies of @code{uucico} would tell each other what they had to do and
+transfer the file from @samp{bantam} to @samp{airs}. When the file
+transfer was complete the @code{uucico} on @samp{airs} would move it
+into the UUCP public directory.
+
+UUCP is often used to transfer mail. This is normally done
+automatically by mailer programs. When @samp{bantam} has a mail message
+to send to @samp{ian} at @samp{airs}, it executes @samp{uux - airs!rmail
+ian} and writes the mail message to the @code{uux} process as standard
+input. The @code{uux} program, running on @samp{bantam}, will read the
+standard input and store it, as well as the @code{rmail} request itself,
+on the work queue for @samp{airs}. @code{uux} will then start the
+@code{uucico} daemon. The @code{uucico} daemon will call up
+@samp{airs}, just as in the @code{uucp} example, and transfer the work
+request and the mail message. The @code{uucico} daemon on @samp{airs}
+will put the files on a local work queue. When the communication
+session is over, the @code{uucico} daemon on @samp{airs} will start the
+@code{uuxqt} daemon. @code{uuxqt} will see the request to run, and will
+run @samp{rmail ian} with the mail message as standard input. The
+@code{rmail} program, which is not part of the UUCP package, is then
+responsible for either putting the message in the right mailbox on
+@samp{airs} or forwarding the message on to another system.
+
+Taylor UUCP comes with a few other programs that are useful when
+installing and configuring UUCP.
+
+@table @code
+
+@item uuchk
+
+The @code{uuchk} program reads the UUCP configuration files and displays
+a rather lengthy description of what it finds. This is useful when
+configuring UUCP to make certain that the UUCP package will do what you
+expect it to do.
+
+@item uuconv
+
+The @code{uuconv} program can be used to convert UUCP configuration
+files from one format to another. This can be useful for administrators
+converting from an older UUCP. Taylor UUCP is able to read and use old
+configuration file formats, but some new features can not be selected
+using the old formats.
+
+@item uusched
+
+The @code{uusched} script is just provided for compatibility with older
+UUCP releases. It starts @code{uucico} to call, one at a time, all the
+systems for which work has been queued.
+
+@item tstuu
+
+The @code{tstuu} program is a test harness for the UUCP package; it can
+help check that the package has been configured and compiled correctly.
+However, it uses pseudo-terminals, which means that it is less portable
+than the rest of the package. If it works, it can be useful when
+initially installing Taylor UUCP.
+
+@end table
+
+@node Overall Installation, Configuration Files, Introduction, Top
+@chapter Taylor UUCP Overall Installation
+
+These are the installation instructions for the Taylor UUCP package.
+
+@menu
+* Configuration:: Configuring Taylor UUCP
+* Compilation:: Compiling Taylor UUCP
+* Testing:: Testing Taylor UUCP
+* Installation:: Installing Taylor UUCP
+* TCP:: TCP together with Taylor UUCP
+@end menu
+
+@node Configuration, Compilation, Overall Installation, Overall Installation
+@section Configuring Taylor UUCP
+
+You will have to decide what types of configuration files you want to
+use. This package supports a new sort of configuration file; see
+@ref{Configuration Files}. It also supports V2 configuration files
+(@file{L.sys}, @file{L-devices}, etc.) and HDB configuration files
+(@file{Systems}, @file{Devices}, etc.). No documentation is provided
+for V2 or HDB configuration files. All types of configuration files can
+be used at once, if you are so inclined. Currently using just V2
+configuration files is not really possible, because there is no way to
+specify a dialer (there are no built in dialers, and the program does
+not know how to read @file{acucap} or @file{modemcap}); however, V2
+configuration files can be used with a new style dial file (@pxref{dial
+File}), or with a HDB @file{Dialers} file.
+
+Use of HDB configuration files has two known bugs. A blank line in the
+middle of an entry in the @file{Permissions} file will not be ignored as
+it should be. Dialer programs, as found in some versions of HDB, are
+not recognized directly. If you must use a dialer program, rather than
+an entry in @file{Devices}, you must use the @code{chat-program} command
+in a new style dial file; see @ref{dial File}. You will have to invoke
+the dialer program via a shell script or another program, since an exit
+code of 0 is required to recognize success; the @code{dialHDB} program
+in the @file{contrib} directory may be used for this purpose.
+
+The @code{uuconv} program can be used to convert from V2 or HDB
+configuration files to the new style (it can also do the reverse
+translation, if you are so inclined). It will not do all of the work,
+and the results should be carefully checked, but it can be quite useful.
+
+If you are installing a new system, you will, of course, have to write
+the configuration files; see @ref{Configuration Files}.
+
+You must also decide what sort of spool directory you want to use. If
+you will be using only these programs for UUCP, I recommend
+@samp{SPOOLDIR_TAYLOR}; otherwise select the spool directory
+corresponding to your existing UUCP package. The details of the spool
+directory choices are described at somewhat tedious length in
+@file{unix/spool.c}.
+
+@node Compilation, Testing, Configuration, Overall Installation
+@section Compiling Taylor UUCP
+
+@enumerate
+
+@item
+Take a look at the top of @file{Makefile.in} and set the appropriate
+values for your system. These control where the programs are installed
+and which user on the system owns them (normally they will be owned by a
+special user @code{uucp} rather than a real person; they should probably
+not be owned by @code{root}).
+
+@item
+Run the shell script @code{configure}. This script was generated using
+the @code{autoconf} program written by David MacKenzie of the Free
+Software Foundation. It takes a while to run. It will generate the
+file @file{config.h} based on @file{config.h.in}, and, for each source
+code directory, will generate @file{Makefile} based on
+@file{Makefile.in}.
+
+You can pass certain arguments to @code{configure} in the environment.
+Because @code{configure} will compile little test programs to see what
+is available on your system, you must tell it how to run your compiler.
+It recognizes the following environment variables:
+
+@table @samp
+@item CC
+The C compiler. If this is not set, then if @code{configure} can find
+@samp{gcc} it will use it, otherwise it will use @samp{cc}.
+@item CFLAGS
+Flags to pass to the C compiler when compiling the actual code. If this
+is not set, @code{configure} will use @samp{-g}.
+@item LDFLAGS
+Flags to pass to the C compiler when only linking, not compiling. If
+this is not set, @code{configure} will use the empty string.
+@item LIBS
+Libraries to pass to the C compiler. If this is not set,
+@code{configure} will use the empty string.
+@item INSTALL
+The program to run to install UUCP in the binary directory. If this is
+not set, then if @code{configure} finds the BSD @code{install} program,
+it will set this to @samp{install -c}; otherwise, it will use @samp{cp}.
+@item INSTALLDATA
+The program to run to install UUCP data files, such as the man pages and
+the info pages. If this is not set, then if @code{configure} finds the
+BSD @code{install} program, it will set this to @samp{install -c -m
+644}; otherwise, it will use @samp{cp}.
+@end table
+
+Suppose you want to set the environment variable @samp{CC} to
+@samp{rcc}. If you are using @code{sh} or @code{bash}, invoke
+@code{configure} as @samp{CC=rcc configure}. If you are using
+@code{csh}, do @samp{setenv CC rcc; sh configure}.
+
+On some systems you will want to use @samp{LIBS=-lmalloc}. On Xenix
+derived versions of Unix do not use @samp{LIBS=-lx} because this will
+bring in the wrong versions of certain routines; if you want to use
+@samp{-lx} you must specify @samp{LIBS=-lc -lx}.
+
+If @code{configure} fails for some reason, or if you have a very weird
+system, you may have to configure the package by hand. To do this, copy
+the file @file{config.h.in} to @file{config.h} and edit it for your
+system. Then for each source directory (the top directory, and the
+subdirectories @file{lib}, @file{unix}, and @file{uuconf}) copy
+@file{Makefile.in} to @file{Makefile}, find the words within @kbd{@@}
+characters, and set them correctly for your system.
+
+@item
+Igor V. Semenyuk provided this (lightly edited) note about ISC Unix 3.0.
+The @code{configure} script will default to passing @samp{-posix} to
+@code{gcc}. However, using @samp{-posix} changes the environment to
+POSIX, and on ISC 3.0, at least, the default for POSIX_NO_TRUNC is 1.
+This means nothing for uucp, but can lead to a problem when uuxqt
+executes rmail. IDA sendmail has dbm configuration files named
+@file{mailertable.@{dir,pag@}}. Notice these names are 15 characters
+long. When uuxqt compiled with @samp{-posix} executes rmail, which in
+turn executes sendmail, the later is run under POSIX environment too!
+This leads to sendmail bombing out with @samp{'error opening 'M'
+database: name too long' (mailertable.dir)}. It's rather obscure
+behaviour, and it took me a day to find out the cause. I don't use
+@samp{-posix}, instead I run @code{gcc} with @samp{-D_POSIX_SOURCE}, and
+add @samp{-lcposix} to @samp{LIBS}.
+
+@item
+On some versions of BSDI there is a bug in the shell which causes the
+default value for @samp{CFLAGS} to be set incorrectly. If @samp{echo
+$@{CFLAGS--g@}} echoes @samp{g} rather than @samp{-g}, then you must set
+@samp{CFLAGS} in the environment before running configure. There is a
+patch available from BSDI for this bug. (From David Vrona).
+
+@item
+On AIX 3.2.5, and possibly other versions, @samp{cc -E} does not work,
+reporting @samp{Option NOROCONST is not valid}. Test this before
+running configure by doing something like @samp{touch /tmp/foo.c; cc -E
+/tmp/foo.c}. This may give a warning about the file being empty, but it
+should not give the @samp{Option NOROCONST} warning. The workaround is
+to remove the @samp{,noroconst} entry from the @samp{options} clause in
+the @samp{cc} stanza in @file{/etc/xlc.cfg}. (From Chris Lewis).
+
+@item
+You should verify that @code{configure} worked correctly by checking
+@file{config.h} and the instances of @file{Makefile}.
+
+@item
+Edit @file{policy.h} for your local system. The comments should explain
+the various choices. The default values are intended to be reasonable,
+so you may not have to make any changes.
+
+@item
+Type @samp{make} to compile everything. The @file{tstuu.c} file is not
+particularly portable; if you can't figure out how to compile it you can
+safely ignore it, as it is only used for testing (to use STREAMS
+pseudo-terminals, tstuu.c must be compiled with
+@samp{-DHAVE_STREAMS_PTYS}; this is not automatically determined at the
+moment). If you have any other problems there is probably a bug in the
+@code{configure} script.
+
+@item
+Please report any problems you have. That is the only way they will get
+fixed for other people. Supply a patch if you can (@pxref{Patches}), or
+just ask for help.
+
+@end enumerate
+
+@node Testing, Installation, Compilation, Overall Installation
+@section Testing Taylor UUCP
+
+This package is in use at hundreds, perhaps thousands, of sites, and has
+been running at @file{airs.com} for several years. However, it will
+doubtless fail in some situations. Do not rely on this code until you
+have proven to yourself that it will work.
+
+You can use the @code{uuchk} program to test your configuration files.
+It will read them and print out a verbose description. This program
+should not be made setuid, because it will display passwords if it can
+read them.
+
+If your system supports pseudo-terminals, and you compiled the code to
+support the new style of configuration files, you should be able to use
+the @code{tstuu} program to test the @code{uucico} daemon (if your
+system supports STREAMS based pseudo-terminals, you must compile tstuu.c
+with @samp{-DHAVE_STREAMS_PTYS}, at least at the moment; the STREAMS
+based code was contributed by Marc Boucher).
+
+To run @code{tstuu}, just type @samp{tstuu} with no arguments while
+logged in to the compilation directory (since it runs @file{./uucp},
+@file{./uux} and @file{./uucico}). It will run a lengthy series of
+tests (it takes over ten minutes on a slow VAX). You will need a fair
+amount of space available in @file{/usr/tmp}. You will probably want to
+put it in the background. Do not use @kbd{^Z}, because the program
+traps on @code{SIGCHLD} and winds up dying. It will create a directory
+@file{/usr/tmp/tstuu} and fill it with configuration files, and create
+spool directories @file{/usr/tmp/tstuu/spool1} and
+@file{/usr/tmp/tstuu/spool2}.
+
+If your system does not support the @code{FIONREAD} call, the
+@samp{tstuu} program will run very slowly. This may or may not get
+fixed in a later version.
+
+The program will finish with an execute file named
+@file{X.@var{something}} and a data file named @file{D.@var{something}}
+in the directory @file{/usr/tmp/tstuu/spool1} (or, more likely, in
+subdirectories, depending on the choice of @code{SPOOLDIR} in
+@file{policy.h}). Two log files will be created in the directory
+@file{/usr/tmp/tstuu}. They will be named @file{Log1} and @file{Log2},
+or, if you have selected @code{HAVE_HDB_LOGGING} in @file{policy.h},
+@file{Log1/uucico/test2} and @file{Log2/uucico/test1}. You can test
+@code{uuxqt} by running the command @samp{./uuxqt -I
+/usr/tmp/tstuu/Config1}. This should leave a command file
+@file{C.@var{something}} and a data file @file{D.@var{something}} in
+@file{/usr/tmp/tstuu/spool1} or in subdirectories. Again, there should
+be no errors in the log file.
+
+Assuming you compiled the code with debugging enabled, the @samp{-x}
+switch can be used to set debugging modes; see the @code{debug} command
+for details (@pxref{Debugging Levels}). Use @samp{-x all} to turn on
+all debugging and generate far more output than you will ever want to
+see. The @code{uucico} daemons will put debugging output in the files
+@file{Debug1} and @file{Debug2} in the directory @file{/usr/tmp/tstuu}.
+After that, you're pretty much on your own.
+
+On some systems you can also use @code{tstuu} to test @code{uucico}
+against the system @code{uucico}, by using the @samp{-u} switch. For
+this to work, change the definitions of @code{ZUUCICO_CMD} and
+@code{UUCICO_EXECL} at the top of @file{tstuu.c} to something
+appropriate for your system. The definitions in @file{tstuu.c} are what
+I used for Ultrix 4.0, on which @file{/usr/lib/uucp/uucico} is
+particularly obstinate about being run as a child; I was only able to
+run it by creating a login name with no password whose shell was
+@file{/usr/lib/uucp/uucico}. Calling login in this way will leave fake
+entries in @file{wtmp} and @file{utmp}; if you compile @file{tstout.c}
+(in the @file{contrib} directory) as a setuid @code{root} program,
+@code{tstuu} will run it to clear those entries out. On most systems,
+such hackery should not be necessary, although on SCO I had to su to
+@code{root} (@code{uucp} might also have worked) before I could run
+@file{/usr/lib/uucp/uucico}.
+
+You can test @code{uucp} and @code{uux} (give them the @samp{-r} switch
+to keep them from starting @code{uucico}) to make sure they create the
+right sorts of files. Unfortunately, if you don't know what the right
+sorts of files are, I'm not going to tell you here.
+
+If @code{tstuu} passes, or you can't run it for some reason or other,
+move on to testing with some other system. Set up the configuration
+files (@pxref{Configuration Files}), or use an existing configuration.
+Tell @code{uucico} to dial out to the system by using the @samp{-s}
+system switch (e.g. @samp{uucico -s uunet}). The log file should tell
+you what happens.
+
+If you compiled the code with debugging enabled, you can use debugging
+mode to get a great deal of information about what sort of data is
+flowing back and forth; the various possibilities are described under
+the @code{debug} command (@pxref{Debugging Levels}). When initially
+setting up a connection @samp{-x chat} is probably the most useful (e.g.
+@samp{uucico -s uunet -x chat}); you may also want to use @samp{-x
+handshake,incoming,outgoing}. You can use @samp{-x} multiple times on
+one command line, or you can give it comma separated arguments as in the
+last example. Use @samp{-x all} to turn on all possible debugging
+information. The debugging information is written to a file, normally
+@file{/usr/spool/uucp/Debug}, although the default can be changed in
+@file{policy.h} and the @file{config} file can override the name with
+the @code{debugfile} command. The debugging file may contain passwords
+and some file contents as they are transmitted over the line, so the
+debugging file is only readable by the @code{uucp} user.
+
+You can use the @samp{-f} switch to force @code{uucico} to call out even
+if the last call failed recently; using @samp{-S} when naming a system
+has the same effect. Otherwise the status file (in the @file{.Status}
+subdirectory of the main spool directory, normally
+@file{/usr/spool/uucp}) will prevent too many attempts from occurring in
+rapid succession.
+
+Again, please let me know about any problems you have and how you got
+around them. If you do report a problem, please include the version
+number of the package you are using, and a sample of the debugging file
+showing the problem (debugging information is usually what is needed,
+not just the log file). General questions such as ``why doesn't uucico
+dial out'' are impossible to answer without much more information.
+
+@node Installation, TCP, Testing, Overall Installation
+@section Installing Taylor UUCP
+
+You can install the executable files by becoming @code{root} and typing
+@samp{make install}. Or you can look at what @samp{make install} does
+and do it by hand. It tries to preserve your old programs, if any, but
+it only does this the first time Taylor UUCP is installed (so that if
+you install several versions of Taylor UUCP, you can still go back to
+your original UUCP programs). You can retrieve the original programs by
+typing @samp{make uninstall}.
+
+Note that by default the programs are compiled with debugging
+information, and they are not stripped when they are installed. You may
+want to strip the installed programs to save disk space. See your
+system documentation for strip for more information.
+
+However, simply installing the executable files is not enough. You must
+also arrange for them to be used correctly.
+
+@menu
+* Running uucico:: Running uucico
+* Using UUCP for mail and news:: Using UUCP for mail and news.
+* Trimming UUCP Log Files:: Trimming UUCP Log Files
+@end menu
+
+@node Running uucico, Using UUCP for mail and news, Installation, Installation
+@subsection Running uucico
+
+By default @code{uucp} and @code{uux} will automatically start up
+@code{uucico} to call another system whenever work is queued up.
+However, the call may fail, or you may have put in time restrictions
+which prevent the call at that time (perhaps because telephone rates are
+high) (@pxref{When to Call}). Also, a remote system may have work
+queued up for your system, but may not be calling you for some reason
+(perhaps you have agreed that your system should always place the call).
+To make sure that works get transferred between the systems withing a
+reasonable time period, you should arrange to periodically invoke
+@code{uucico}.
+
+These periodic invocations are normally caused by entries in the
+@file{crontab} file. The exact format of @file{crontab} files, and how
+new entries are added, varies from system to system; check your local
+documentation (try @samp{man cron}).
+
+To attempt to call all systems with outstanding work, use the command
+@samp{uucico -r1}. To attempt to call a particular system, use the
+command @samp{uucico -s @var{system}}. To attempt to call a particular
+system, but only if there is work for it, use the command @samp{uucico
+-C -s @var{system}}.
+
+A common case is to want to try to call a system at a certain time, with
+periodic retries if the call fails. A simple way to do this is to
+create an empty UUCP command file, known as a @dfn{poll file}. If a
+poll file exists for a system, then @samp{uucico -r1} will place a call
+to it. If the call succeeds, the poll file will be deleted.
+
+The file can be easily created using the @samp{touch} command. The name
+of a poll file currently depends on the type of spool directory you are
+using, as set in @file{policy.h}. If you are using
+@code{SPOOLDIR_TAYLOR} (the default), put something like this in your
+@file{crontab} file:
+@example
+touch /usr/spool/uucp/@var{sys}/C./C.A0000
+@end example
+In this example @var{sys} is the system you wish to call, and
+@samp{/usr/spool/uucp} is your UUCP spool directory.
+If you are using @code{SPOOLDIR_HDB}, use
+@example
+touch /usr/spool/uucp/@var{sys}/C.@var{sys}A0000
+@end example
+
+For example, I use the following crontab entries locally:
+
+@example
+45 * * * * /bin/echo /usr/lib/uucp/uucico -r1 | /bin/su uucpa
+40 4,10,15 * * * touch /usr/spool/uucp/uunet/C./C.A0000
+@end example
+
+Every hour, at 45 minutes past, this will check if there is any work to
+be done, and, if there is, will call the appropriate system. Also, at
+4:40am, 10:40am and 3:40pm this will create a poll file file for
+@samp{uunet}, forcing the next check to call @samp{uunet}.
+
+@node Using UUCP for mail and news, Trimming UUCP Log Files, Running uucico, Installation
+@subsection Using UUCP for mail and news.
+
+Taylor UUCP does not include a mail package. All Unix systems come with
+some sort of mail delivery agent, typically @code{sendmail} or
+@code{MMDF}. Source code is available for some alternative mail
+delivery agents, such as @code{IDA sendmail} and @code{smail}.
+
+Taylor UUCP also does not include a news package. The two major Unix
+news packages are @code{C-news} and @code{INN}. Both are available in
+source code form.
+
+Configuring and using mail delivery agents is a notoriously complex
+topic, and I will not be discussing it here. Configuring news systems
+is usually simpler, but I will not be discussing that either. I will
+merely describe the interactions between the mail and news systems and
+UUCP.
+
+A mail or news system interacts with UUCP in two ways: sending and
+receiving.
+
+@menu
+* Sending mail or news:: Sending mail or news via UUCP
+* Receiving mail or news:: Receiving mail or news via UUCP
+@end menu
+
+@node Sending mail or news, Receiving mail or news, Using UUCP for mail and news, Using UUCP for mail and news
+@unnumberedsubsubsec Sending mail or news via UUCP
+
+When mail is to be sent from your machine to another machine via UUCP,
+the mail delivery agent will invoke @code{uux}. It will generally run a
+command such as @samp{uux - @var{system}!rmail}, where @var{system} is
+the remote system to which the mail is being sent. It may pass other
+options to @code{uux}, such as @samp{-r} or @samp{-g}.
+
+News also invokes @code{uux} in order to transfer articles to another
+system. The only difference is that news will use @code{uux} to invoke
+@code{rnews} on the remote system, rather than @code{rmail}.
+
+You should arrange for your mail and news systems to invoke the Taylor
+UUCP version of @code{uux} when sending mail via UUCP. If you simply
+replace any existing version of @code{uux} with the Taylor UUCP version,
+this will probably happen automatically. However, if both versions
+exist on your system, you will probably have to modify the mail and news
+configuration files in some way.
+
+Actually, if both the system UUCP and Taylor UUCP are using the same
+spool directory format, the system @code{uux} will probably work fine
+with the Taylor @code{uucico} (the reverse is not the case: the Taylor
+@code{uux} requires the Taylor @code{uucico}). However, data transfer
+will be somewhat more efficient if the Taylor @code{uux} is used.
+
+@node Receiving mail or news, , Sending mail or news, Using UUCP for mail and news
+@unnumberedsubsubsec Receiving mail or news via UUCP
+
+As noted in @ref{Sending mail or news}, mail is sent by requesting a
+remote execution of @code{rmail}. To receive mail, then, all that is
+necessary is for UUCP to invoke @code{rmail} itself.
+
+Any mail delivery agent will provide an appropriate version of
+@code{rmail}; you must simply make sure that it is in the command path
+used by UUCP (it almost certainly already is). The default command path
+is set in @file{policy.h}, and it may be overridden for a particular
+system by the @code{command-path} command (@pxref{Miscellaneous (sys)}).
+
+Similarly, for news UUCP must be able to invoke @code{rnews}. Any news
+system will provide a version of @code{rnews}, and you must ensure that
+is in a directory on the path that UUCP will search.
+
+@node Trimming UUCP Log Files, , Using UUCP for mail and news, Installation
+@subsection Trimming UUCP Log Files
+
+You should also periodically trim the log files, as they will otherwise
+continue to grow without limit. The names of the log files are set in
+@file{policy.h}, and may be overridden in the configuration file
+(@pxref{config File}). By default they are are
+@file{/usr/spool/uucp/Log} and @file{/usr/spool/uucp/Stats}.
+
+You may find the @code{savelog} program in the @file{contrib} directory
+to be of use. There is a manual page for it in @file{contrib} as well.
+
+@node TCP, , Installation, Overall Installation
+@section TCP together with Taylor UUCP
+
+If your system has a Berkeley style socket library, or a System V style
+TLI interface library, you can compile the code to permit making
+connections over TCP. Specifying that a system should be reached via
+TCP is easy, but nonobvious.
+
+If you are using the new style configuration files, see
+@ref{Configuration Files}. Basically, you can just add the line
+@samp{port type tcp} to the entry in the system configuration file. By
+default UUCP will get the port number by looking up @samp{uucp} in
+@file{/etc/services}; if @samp{uucp} is not found, port 540 will be
+used. You can set the port number to use with the command @samp{port
+service @var{xxx}}, where @var{xxx} can be either a number or a name to
+look up in @file{/etc/services}. You can specify the address of the
+remote host with @samp{address @var{a.b.c}}; if you don't give an
+address, the remote system name will be used. You should give an
+explicit chat script for the system when you use TCP; the default chat
+script begins with a carriage return, which will not work with some UUCP
+TCP servers.
+
+If you are using V2 configuration files, add a line like this to
+@file{L.sys}:
+
+@example
+@var{sys} Any TCP uucp @var{host}.@var{domain} chat-script
+@end example
+
+This will make an entry for system @var{sys}, to be called at any time,
+over TCP, using port number @samp{uucp} (as found in
+@file{/etc/services}; this may be specified as a number), using remote
+host @file{@var{host}.@var{domain}}, with some chat script.
+
+@need 1000
+If you are using HDB configuration files, add a line like this to
+Systems:
+
+@example
+@var{sys} Any TCP - @var{host}.@var{domain} chat-script
+@end example
+
+and a line like this to Devices:
+
+@example
+TCP uucp - -
+@end example
+
+You only need one line in Devices regardless of how many systems you
+contact over TCP. This will make an entry for system @var{sys}, to be
+called at any time, over TCP, using port number @samp{uucp} (as found in
+@file{/etc/services}; this may be specified as a number), using remote
+host @file{@var{host}.@var{domain}}, with some chat script.
+
+The @code{uucico} daemon can also be run as a TCP server. To use the
+default port number, which is a reserved port, @code{uucico} must be
+invoked by root (or it must be set user ID to root, but I don't
+recommend doing that).
+
+Basically, you must define a port, either using the port file
+(@pxref{port File}) if you are using the new configuration method or
+with an entry in Devices if you are using HDB; there is no way to define
+a port using V2. If you are using HDB the port must be named
+@samp{TCP}; a line as shown above will suffice. You can then start
+@code{uucico} as @samp{uucico -p TCP} (after the @samp{-p}, name the
+port; in HDB it must be @samp{TCP}). This will wait for incoming
+connections, and fork off a child for each one. Each connection will be
+prompted with @samp{login:} and @samp{Password:}; the results will be
+checked against the UUCP (not the system) password file
+(@pxref{Configuration File Names}).
+
+Of course, you can get a similar effect by using the BSD @code{uucpd}
+program.
+
+You can also have @code{inetd} start up @code{uucico} with the @samp{-l}
+switch, which will cause it to prompt with @samp{login:} and
+@samp{Password:} and check the results against the UUCP (not the system)
+password file (you may want to also use the @samp{-D} switch to avoid a
+fork, which in this case is unnecessary). This may be used in place of
+@code{uucpd}.
+
+@node Configuration Files, Protocols, Overall Installation, Top
+@chapter Taylor UUCP Configuration Files
+
+This chapter describes the configuration files accepted by the Taylor
+UUCP package if compiled with @code{HAVE_TAYLOR_CONFIG} defined in
+@file{policy.h}.
+
+The configuration files are normally found in the directory
+@var{newconfigdir}, which is defined by the @file{Makefile} variable
+@file{newconfigdir}; by default @var{newconfigdir} is
+@file{/usr/local/conf/uucp}. However, the main configuration file,
+@file{config}, is the only one which must be in that directory, since it
+may specify a different location for any or all of the other files. You
+may run any of the UUCP programs with a different main configuration
+file by using the @samp{-I} option; this can be useful when testing a
+new configuration. When you use the @samp{-I} option the programs will
+revoke any setuid privileges.
+
+@menu
+* Configuration File Format:: Configuration file format
+* Configuration File Overview:: Configuration File Overview
+* Configuration Examples:: Examples of configuration files
+* Time Strings:: How to write time strings
+* Chat Scripts:: How to write chat scripts
+* config File:: The main configuration file
+* sys File:: The system configuration file
+* port File:: The port configuration files
+* dial File:: The dialer configuration files
+* Security:: Security issues
+@end menu
+
+@node Configuration File Format, Configuration File Overview, Configuration Files, Configuration Files
+@section Configuration File Format
+
+All the configuration files follow a simple line-oriented
+@samp{@var{keyword} @var{value}} format. Empty lines are ignored, as
+are leading spaces; unlike HDB, lines with leading spaces are read. The
+first word on each line is a keyword. The rest of the line is
+interpreted according to the keyword. Most keywords are followed by
+numbers, boolean values or simple strings with no embedded spaces.
+
+The @kbd{#} character is used for comments. Everything from a @kbd{#}
+to the end of the line is ignored unless the @kbd{#} is preceded by a
+@kbd{\} (backslash); if the @kbd{#} is preceeded by a @kbd{\}, the
+@kbd{\} is removed but the @kbd{#} remains in the line. This can be
+useful for a phone number containing a @kbd{#}. To enter the sequence
+@samp{\#}, use @samp{\\#}.
+
+The backslash character may be used to continue lines. If the last
+character in a line is a backslash, the backslash is removed and the
+line is continued by the next line. The second line is attached to the
+first with no intervening characters; if you want any whitespace between
+the end of the first line and the start of the second line, you must
+insert it yourself.
+
+However, the backslash is not a general quoting character. For example,
+you cannot use it to get an embedded space in a string argument.
+
+Everything after the keyword must be on the same line. A @var{boolean}
+may be specified as @kbd{y}, @kbd{Y}, @kbd{t}, or @kbd{T} for true and
+@kbd{n}, @kbd{N}, @kbd{f}, or @kbd{F} for false; any trailing characters
+are ignored, so @code{true}, @code{false}, etc., are also acceptable.
+
+@node Configuration File Overview, Configuration Examples, Configuration File Format, Configuration Files
+@section Configuration File Overview
+
+UUCP uses several different types of configuration files, each
+describing a different kind of information. The commands permitted in
+each file are described in detail below. This section is a brief
+description of some of the different types of files.
+
+The @file{config} file is the main configuration file. It describes
+general information not associated with a particular remote system, such
+as the location of various log files. There are reasonable defaults for
+everything that may be specified in the @file{config} file, so you may
+not actually need one on your system.
+
+There may be only one @file{config} file, but there may be one or more
+of each other type of file. The default is one file for each type, but
+more may be listed in the @file{config} file.
+
+The @file{sys} files are used to describe remote systems. Each remote
+system to which you connect must be listed in a @file{sys} file. A
+@file{sys} file will include information for a system, such as the speed
+(baud rate) to use, or when to place calls.
+
+For each system you wish to call, you must describe one or more ports;
+these ports may be defined directly in the @file{sys} file, or they may
+be defined in a @file{port} file.
+
+The @file{port} files are used to describe ports. A port is a
+particular hardware connection on your computer. You would normally
+define as many ports as there are modems attached to your computer. A
+TCP connection is also described using a port.
+
+The @file{dial} files are used to describe dialers. Dialer is
+essentially another word for modem. The @file{dial} file describes the
+commands UUCP should use to dial out on a particular type of modem. You
+would normally define as many dialers as there are types of modems
+attached to your computer. For example, if you have three Telebit
+modems used for UUCP, you would probably define three ports and one
+dialer.
+
+There are other types of configuration files, but these are the
+important ones. The other types are described below.
+
+@node Configuration Examples, Time Strings, Configuration File Overview, Configuration Files
+@section Examples of Configuration Files
+
+This section provides few typical examples of configuration files.
+There are also sample configuration files in the @file{sample}
+subdirectory of the distribution.
+
+@menu
+* config File Examples:: Examples of the main configuration file
+* Leaf Example:: Call a single remote site
+* Gateway Example:: The gateway for several local systems
+@end menu
+
+@node config File Examples, Leaf Example, Configuration Examples, Configuration Examples
+@subsection config File Examples
+@cindex config file examples
+
+To start with, here are some examples of uses of the main configuration
+file, @file{config}. For a complete description of the commands that
+are permitted in @file{config}, see @ref{config File}.
+
+In many cases you will not need to create a @file{config} file at all.
+The most common reason to create one is to give your machine a special
+UUCP name. Other reasons might be to change the UUCP spool directory or
+to permit any remote system to call in.
+
+If you have an internal network of machines, then it is likely that the
+internal name of your UUCP machine is not the name you want to use when
+calling other systems. For example, here at @file{airs.com} our
+mail/news gateway machine is named @file{elmer.airs.com} (it is one of
+several machines all named @file{@var{localname}.airs.com}). If we did
+not provide a @file{config} file, then our UUCP name would be
+@file{elmer}; however, we actually want it to be @file{airs}.
+Therefore, we use the following line in @file{config}:
+
+@example
+nodename airs
+@end example
+
+@cindex changing spool directory
+@cindex spool directory (changing)
+The UUCP spool directory name is set in @file{policy.h} when the code is
+compiled. You might at some point decide that it is appropriate to move
+the spool directory, perhaps to put it on a different disk partition.
+You would use the following commands in @file{config} to change to
+directories on the partition @file{/uucp}:
+
+@example
+spool /uucp/spool
+pubdir /uucp/uucppublic
+logfile /uucp/spool/Log
+debugfile /uucp/spool/Debug
+@end example
+
+You would then move the contents of the current spool directory to
+@file{/uucp/spool}. If you do this, make sure that no UUCP processes
+are running while you change @file{config} and move the spool directory.
+
+@cindex anonymous UUCP
+Suppose you wanted to permit any system to call in to your system and
+request files. This is generally known as @dfn{anonymous UUCP}, since
+the systems which call in are effectively anonymous. By default,
+unknown systems are not permitted to call in. To permit this you must
+use the @code{unknown} command in @file{config}. The @code{unknown}
+command is followed by any command that may appear in the system file;
+for full details, see @ref{sys File}.
+
+I will show two possible anonymous UUCP configurations. The first will
+let any system call in and download files, but will not permit them to
+upload files to your system.
+
+@example
+# No files may be transferred to this system
+unknown receive-request no
+# The public directory is /usr/spool/anonymous
+unknown pubdir /usr/spool/anonymous
+# Only files in the public directory may be sent (the default anyhow)
+unknown remote-send ~
+@end example
+
+@noindent
+Setting the public directory is convenient for the systems which call
+in. It permits to request a file by prefixing it with @file{~/}. For
+example, assuming your system is known as @samp{server}, then to
+retrieve the file @file{/usr/spool/anonymous/INDEX} a user on a remote
+site could just enter @samp{uucp server!~/INDEX ~}; this would transfer
+@file{INDEX} from @samp{server}'s public directory to the user's local
+public directory. Note that when using @samp{csh} or @samp{bash} the
+@kbd{!} and the second @kbd{~} must be quoted.
+
+The next example will permit remote systems to upload files to a special
+directory named @file{/usr/spool/anonymous/upload}. Permitting a remote
+system to upload files permits it to send work requests as well; this
+example is careful to prohibit commands from unknown systems.
+
+@example
+# No commands may be executed (the list of permitted commands is empty)
+unknown commands
+# The public directory is /usr/spool/anonymous
+unknown pubdir /usr/spool/anonymous
+# Only files in the public directory may be sent; users may not download
+# files from the upload directory
+unknown remote-send ~ !~/upload
+# May only upload files into /usr/spool/anonymous/upload
+unknown remote-receive ~/upload
+@end example
+
+@node Leaf Example, Gateway Example, config File Examples, Configuration Examples
+@subsection Leaf Example
+
+@cindex leaf site
+@cindex sys file example (leaf)
+A relatively common simple case is a @dfn{leaf site}, a system which
+only calls or is called by a single remote site. Here is a typical
+@file{sys} file that might be used in such a case. For full details on
+what commands can appear in the @file{sys} file, see @ref{sys File}.
+
+This is the @file{sys} file that is used at @file{airs.com}. We use a
+single modem to dial out to @file{uunet}. This example shows how you
+can specify the port and dialer information directly in the @file{sys}
+file for simple cases. It also shows the use of the following:
+
+@table @code
+
+@item call-login
+Using @code{call-login} and @code{call-password} allows the default
+login chat script to be used. In this case, the login name is specified
+in the call-out login file (@pxref{Configuration File Names}).
+
+@item call-timegrade
+@file{uunet} is requested to not send us news during the daytime.
+
+@item chat-fail
+If the modem returns @samp{BUSY} or @samp{NO CARRIER} the call is
+immediately aborted.
+
+@item protocol-parameter
+Since @file{uunet} tends to be slow, the default timeout has been
+increased.
+
+@end table
+
+This @file{sys} file relies on certain defaults. It will allow
+@file{uunet} to queue up @samp{rmail} and @samp{rnews} commands. It
+will allow users to request files from @file{uunet} into the UUCP public
+directory. It will also allow @file{uunet} to request files from the
+UUCP public directory; in fact @file{uunet} never requests files, but
+for additional security we could add the line @samp{request false}.
+
+@example
+# The following information is for uunet
+system uunet
+
+# The login name and password are kept in the callout password file
+call-login *
+call-password *
+
+# We can send anything at any time.
+time any
+
+# During the day we only accept grade `Z' or above; at other times
+# (not mentioned here) we accept all grades. uunet queues up news
+# at grade `d', which is lower than `Z'.
+call-timegrade Z Wk0755-2305,Su1655-2305
+
+# The phone number.
+phone 7389449
+
+# uunet tends to be slow, so we increase the timeout
+chat-timeout 120
+
+# We are using a preconfigured Telebit 2500.
+port type modem
+port device /dev/ttyd0
+port speed 19200
+port carrier true
+port dialer chat "" ATZ\r\d\c OK ATDT\D CONNECT
+port dialer chat-fail BUSY
+port dialer chat-fail NO\sCARRIER
+port dialer complete \d\d+++\d\dATH\r\c
+port dialer abort \d\d+++\d\dATH\r\c
+
+# Increase the timeout and the number of retries.
+protocol-parameter g timeout 20
+protocol-parameter g retries 10
+@end example
+
+@node Gateway Example, , Leaf Example, Configuration Examples
+@subsection Gateway Example
+
+@cindex gateway
+@cindex sys file example (gateway)
+Many organizations have several local machines which are connected by
+UUCP, and a single machine which connects to the outside world. This
+single machine is often referred to as a @dfn{gateway} machine.
+
+For this example I will assume a fairly simple case. It should still
+provide a good general example. There are three machines, @file{elmer},
+@file{comton} and @file{bugs}. @file{elmer} is the gateway machine for
+which I will show the configuration file. @file{elmer} calls out to
+@file{uupsi}. As an additional complication, @file{uupsi} knows
+@file{elmer} as @file{airs}; this will show how a machine can have one
+name on an internal network but a different name to the external world.
+@file{elmer} has two modems. It also has an TCP/IP connection to
+@file{uupsi}, but since that is supposed to be reserved for interactive
+work (it is, perhaps, only a 9600 baud SLIP line) it will only use it if
+the modems are not available.
+
+A network this small would normally use a single @file{sys} file.
+However, for pedagogical purposes I will show two separate @file{sys}
+files, one for the local systems and one for @file{uupsi}. This is done
+with the @code{sysfile} command in the @file{config} file. Here is the
+@file{config} file.
+
+@example
+# This is config
+# The local sys file
+sysfile /usr/local/lib/uucp/sys.local
+# The remote sys file
+sysfile /usr/local/lib/uucp/sys.remote
+@end example
+
+Using the defaults feature of the @file{sys} file can greatly simplify
+the listing of local systems. Here is @file{sys.local}. Note that this
+assumes that the local systems are trusted; they are permited to request
+any world readable file and to write files into any world writable
+directory.
+
+@example
+# This is sys.local
+# Get the login name and password to use from the call-out file
+call-login *
+call-password *
+
+# The systems must use a particular login
+called-login Ulocal
+
+# Permit sending any world readable file
+local-send /
+remote-send /
+
+# Permit requesting into any world writable directory
+local-receive /
+remote-receive /
+
+# Call at any time
+time any
+
+# Use port1, then port2
+port port1
+
+alternate
+
+port port2
+
+# Now define the systems themselves. Because of all the defaults we
+# used, there is very little to specify for the systems themselves.
+
+system comton
+phone 5551212
+
+system bugs
+phone 5552424
+@end example
+
+The @file{sys.remote} file describes the @file{uupsi} connection. The
+@code{myname} command is used to change the UUCP name to @file{airs}
+when talking to @file{uupsi}.
+
+@example
+# This is sys.remote
+# Define uupsi
+system uupsi
+
+# The login name and password are in the call-out file
+call-login *
+call-password *
+
+# We can call out at any time
+time any
+
+# uupsi uses a special login name
+called-login Uuupsi
+
+# uuspi thinks of us as `airs'
+myname airs
+
+# The phone number
+phone 5554848
+
+# We use port2 first, then port1, then TCP
+
+port port2
+
+alternate
+
+port port1
+
+alternate
+
+# We don't bother to make a special entry in the port file for TCP, we
+# just describe the entire port right here. We use a special chat
+# script over TCP because the usual one confuses some TCP servers.
+port type TCP
+address uu.psi.com
+chat ogin: \L word: \P
+@end example
+
+The ports are defined in the file @file{port} (@pxref{port File}). For
+this example they are both connected to the same type of 2400 baud
+Hayes-compatible modem.
+
+@example
+# This is port
+
+port port1
+type modem
+device /dev/ttyd0
+dialer hayes
+speed 2400
+
+port port2
+type modem
+device /dev/ttyd1
+dialer hayes
+speed 2400
+@end example
+
+Dialers are described in the @file{dial} file (@pxref{dial File}).
+
+@example
+# This is dial
+
+dialer hayes
+
+# The chat script used to dial the phone. \D is the phone number.
+chat "" ATZ\r\d\c OK ATDT\D CONNECT
+
+# If we get BUSY or NO CARRIER we abort the dial immediately
+chat-fail BUSY
+chat-fail NO\sCARRIER
+
+# When the call is over we make sure we hangup the modem.
+complete \d\d+++\d\dATH\r\c
+abort \d\d+++\d\dATH\r\c
+@end example
+
+@node Time Strings, Chat Scripts, Configuration Examples, Configuration Files
+@section Time Strings
+@cindex time strings
+
+Several commands use time strings to specify a range of times. This
+section describes how to write time strings.
+
+A time string may be a list of simple time strings separated with a
+vertical bar @kbd{|} or a comma @kbd{,}.
+
+Each simple time string must begin with @samp{Su}, @samp{Mo}, @samp{Tu},
+@samp{We}, @samp{Th}, @samp{Fr}, or @samp{Sa}, or @samp{Wk} for any
+weekday, or @samp{Any} for any day.
+
+Following the day may be a range of hours separated with a hyphen using
+24 hour time. The range of hours may cross 0; for example
+@samp{2300-0700} means any time except 7 AM to 11 PM. If no time is
+given, calls may be made at any time on the specified day(s).
+
+The time string may also consist of the single word @samp{Never}, which
+does not match any time, or a single word with a name defined in a
+previous @code{timetable} command (@pxref{Miscellaneous (config)}).
+
+Here are a few sample time strings with an explanation of what they
+mean.
+
+@table @samp
+
+@item Wk2305-0855,Sa,Su2305-1655
+
+This means weekdays before 8:55 AM or after 11:05 PM, any time Saturday,
+or Sunday before 4:55 PM or after 11:05 PM. These are approximately the
+times during which night rates apply to phone calls in the U.S.A. Note
+that this time string uses, for example, @samp{2305} rather than
+@samp{2300}; this will ensure a cheap rate phone call even if the
+computer clock is running up to five minutes ahead of the real time.
+
+@item Wk0905-2255,Su1705-2255
+
+This means weekdays from 9:05 AM to 10:55 PM, or Sunday from 5:05 PM to
+10:55 PM. This is approximately the opposite of the previous example.
+
+@item Any
+
+This means any day. Since no time is specified, it means any time on
+any day.
+
+@end table
+
+@node Chat Scripts, config File, Time Strings, Configuration Files
+@section Chat Scripts
+@cindex chat scripts
+
+Chat scripts are used in several different places, such as dialing out
+on modems or logging in to remote systems. Chat scripts are made up of
+pairs of strings. The program waits until it sees the first string,
+known as the @dfn{expect} string, and then sends out the second string,
+the @dfn{send} string.
+
+Each chat script is defined using a set of commands. These commands
+always end in a string beginning with @code{chat}, but may start with
+different strings. For example, in the @file{sys} file there is one set
+of commands beginning with @code{chat} and another set beginning with
+@code{called-chat}. The prefixes are only used to disambiguate
+different types of chat scripts, and this section ignores the prefixes
+when describing the commands.
+
+@table @code
+
+@item chat @var{strings}
+@findex chat
+
+Specify a chat script. The arguments to the @code{chat} command are
+pairs of strings separated by whitespace. The first string of each pair
+is an expect string, the second is a send string. The program will wait
+for the expect string to appear; when it does, the program will send the
+send string. If the expect string does not appear within a certain
+number of seconds (as set by the @code{chat-timeout} command) the chat
+script fails and, typically, the call is aborted. If the final expect
+string is seen (and the optional final send string has been sent), the
+chat script is successful.
+
+An expect string may contain additional subsend and subexpect strings,
+separated by hyphens. If the expect string is not seen, the subsend
+string is sent and the chat script continues by waiting for the
+subexpect string. This means that a hyphen may not appear in an expect
+string; on an ASCII system, use @samp{\055} instead.
+
+An expect string may simply be @samp{""}, meaning to skip the expect
+phase. Otherwise, the following escape characters may appear in expect
+strings:
+
+@table @samp
+@item \b
+a backspace character
+@item \n
+a newline or line feed character
+@item \N
+a null character (for HDB compatibility)
+@item \r
+a carriage return character
+@item \s
+a space character
+@item \t
+a tab character
+@item \\
+a backslash character
+@item \@var{ddd}
+character @var{ddd}, where @var{ddd} are up to three octal digits
+@item \x@var{ddd}
+character @var{ddd}, where @var{ddd} are hexadecimal digits.
+@end table
+
+As in C, there may be up to three octal digits following a backslash,
+but the hexadecimal escape sequence continues as far as possible. To
+follow a hexadecimal escape sequence with a hex digit, interpose a send
+string of @samp{""}.
+
+A chat script expect string may also specify a timeout. This is done by
+using the escape sequence @samp{\W@var{seconds}}. This escape sequence
+may only appear at the very end of the expect string. It temporarily
+overrides the timeout set by @code{chat-timeout} (described below) only
+for the expect string to which it is attached.
+
+A send string may simply be @samp{""} to skip the send phase.
+Otherwise, all of the escape characters legal for expect strings may be
+used, and the following escape characters are also permitted:
+
+@table @samp
+@item EOT
+send an end of transmission character (@kbd{^D})
+@item BREAK
+send a break character (may not work on all systems)
+@item \c
+suppress trailing carriage return at end of send string
+@item \d
+delay sending for 1 or 2 seconds
+@item \e
+disable echo checking
+@item \E
+enable echo checking
+@item \K
+same as @samp{BREAK} (for HDB compatibility)
+@item \p
+pause sending for a fraction of a second
+@end table
+
+Some specific types of chat scripts also define additional escape
+sequences that may appear in the send string. For example, the login
+chat script defines @samp{\L} and @samp{\P} to send the login name and
+password, respectively.
+
+A carriage return will be sent at the end of each send string, unless
+the @kbd{\c} escape sequence appears in the string. Note that some UUCP
+packages use @kbd{\b} for break, but here it means backspace.
+
+Echo checking means that after writing each character the program will
+wait until the character is echoed. Echo checking must be turned on
+separately for each send string for which it is desired; it will be
+turned on for characters following @kbd{\E} and turned off for characters
+following @kbd{\e}.
+
+@item chat-timeout @var{number}
+@findex chat-timeout
+
+The number of seconds to wait for an expect string in the chat script
+before timing out and sending the next subsend or failing the chat
+script entirely. The default value is 10 for a login chat or 60 for
+any other type of chat.
+
+@item chat-fail @var{string}
+@findex chat-fail
+
+If the @var{string} is seen at any time during a chat script, the chat
+script is aborted. The string may not contain any whitespace
+characters; escape sequences must be used for them. Multiple
+@code{chat-fail} commands may appear in a single chat script. The
+default is to have none.
+
+This permits a chat script to be quickly aborted if an error string is
+seen. For example, a script used to dial out on a modem might use the
+command @samp{chat-fail BUSY} to stop the chat script immediately if the
+string @samp{BUSY} was seen.
+
+The @code{chat-fail} strings are considered in the order they are
+listed, so if one string is a suffix of another the longer one should be
+listed first. Of course, if one string is contained within another, the
+smaller string will always be found before the larger string could
+match.
+
+@item chat-seven-bit @var{boolean}
+@findex chat-seven-bit
+
+If the argument is true, all incoming characters are stripped to seven
+bits when being compared to the expect string. Otherwise all eight bits
+are used in the comparison. The default is true, because some Unix
+systems generate parity bits during the login prompt which must be
+ignored while running a chat script. This has no effect on any
+@code{chat-program}, which must ignore parity by itself if necessary.
+
+@item chat-program @var{strings}
+@findex chat-program
+
+Specify a program to run before executing the chat script. This program
+could run its own version of a chat script, or it could do whatever it
+wants. If both @code{chat-program} and @code{chat} are specified, the
+program is executed first followed by the chat script.
+
+The first argument to the @code{chat-program} command is the program
+name to run. The remaining arguments are passed to the program. The
+following escape sequences are recognized in the arguments:
+
+@table @kbd
+@item \Y
+port device name
+@item \S
+port speed
+@item \\
+backslash
+@end table
+
+Some specific uses of @code{chat-program} define additional escape
+sequences.
+
+Arguments other than escape sequences are passed exactly as they appear
+in the configuration file, except that sequences of whitespace are
+compressed to a single space character (this exception may be removed in
+the future).
+
+If the @code{chat-program} command is not used, no program is run.
+
+On Unix, the standard input and standard output of the program will be
+attached to the port in use. Anything the program writes to standard
+error will be written to the UUCP log file. No other file descriptors
+will be open. If the program does not exit with a status of 0, it will
+be assumed to have failed. This means that the dialing programs used by
+some versions of HDB may not be used directly, but you may be able to
+run them via the @code{dialHDB} program in the @file{contrib} directory.
+
+The program will be run as the @code{uucp} user, and the environment
+will be that of the process that started @code{uucico}, so care must be
+taken to maintain security.
+
+No search path is used to find the program; a full path name must be
+given. If the program is an executable shell script, it will be passed
+to @file{/bin/sh} even on systems which are unable to execute shell
+scripts.
+
+@end table
+
+Here is a simple example of a chat script that might be used to reset a
+Hayes compatible modem.
+
+@example
+chat "" ATZ OK-ATZ-OK
+@end example
+
+The first expect string is @samp{""}, so it is ignored. The chat script
+then sends @samp{ATZ}. If the modem responds with @samp{OK}, the chat
+script finishes. If 60 seconds (the default timeout) pass before seeing
+@samp{OK}, the chat script sends another @samp{ATZ}. If it then sees
+@samp{OK}, the chat script succeeds. Otherwise, the chat script fails.
+
+For a more complex chat script example, see @ref{Logging In}.
+
+@node config File, sys File, Chat Scripts, Configuration Files
+@section The Main Configuration File
+@cindex config file
+@cindex main configuration file
+@cindex configuration file (config)
+
+The main configuration file is named @file{config}.
+
+Since all the values that may be specified in the main configuration
+file also have defaults, there need not be a main configuration file at
+all.
+
+Each command in @file{config} may have a program prefix, which is a
+separate word appearing at the beginning of the line. The currently
+supported prefixes are @samp{uucp} and @samp{cu}. Any command prefixed
+by @samp{uucp} will not be read by the @code{cu} program. Any command
+prefixed by @samp{cu} will only be read by the @code{cu} program. For
+example, to use a list of systems known only to @code{cu}, list them in
+a separate file @file{@var{file}} and put @samp{cu sysfile
+@file{@var{file}}} in @file{config}.
+
+@menu
+* Miscellaneous (config):: Miscellaneous config file commands
+* Configuration File Names:: Using different configuration files
+* Log File Names:: Using different log files
+* Debugging Levels:: Debugging levels
+@end menu
+
+@node Miscellaneous (config), Configuration File Names, config File, config File
+@subsection Miscellaneous config File Commands
+
+@table @code
+
+@item nodename @var{string}
+@findex nodename
+@itemx hostname @var{string}
+@findex hostname
+@itemx uuname @var{string}
+@findex uuname
+@cindex UUCP system name
+@cindex system name
+
+These keywords are equivalent. They specify the UUCP name of the local
+host. If there is no configuration file, an appropriate system function
+will be used to get the host name, if possible.
+
+@item spool @var{string}
+@findex spool
+@cindex spool directory
+@cindex /usr/spool/uucp
+
+Specify the spool directory. The default is from @file{policy.h}. This
+is where UUCP files are queued. Status files and various sorts of
+temporary files are also stored in this directory and subdirectories of
+it.
+
+@item pubdir @var{string}
+@findex pubdir in config file
+@cindex public directory
+@cindex uucppublic
+@cindex /usr/spool/uucppublic
+
+Specify the public directory. The default is from @file{policy.h}.
+When a file is named using a leading @kbd{~/}, it is taken from or to
+the public directory. Each system may use a separate public directory
+by using the @code{pubdir} command in the system configuration file; see
+@ref{Miscellaneous (sys)}.
+
+@item lockdir @var{string}
+@findex lockdir
+@cindex lock directory
+
+Specify the directory to place lock files in. The default is from
+@file{policy.h}; see the information in that file. Normally the lock
+directory should be set correctly in @file{policy.h}, and not changed
+here. However, changing the lock directory is sometimes useful for
+testing purposes.
+
+@item unknown @var{string} @dots{}
+@findex unknown
+@cindex unknown systems
+
+The @var{string} and subsequent arguments are treated as though they
+appeared in the system file (@pxref{sys File}). They are used to apply
+to any unknown systems that may call in, probably to set file transfer
+permissions and the like. If the @code{unknown} command is not used,
+unknown systems are not permitted to call in.
+
+@item max-uuxqts @var{number}
+@findex max-uuxqts
+
+Specify the maximum number of @code{uuxqt} processes which may run at
+the same time. Having several @code{uuxqt} processes running at once
+can significantly slow down a system, but since @code{uuxqt} is
+automatically started by @code{uucico}, it can happen quite easily. The
+default for @code{max-uuxqts} is 0, which means that there is no limit.
+If HDB configuration files are being read and the code was compiled
+without @code{HAVE_TAYLOR_CONFIG}, then if the file @file{Maxuuxqts} in
+the configuration directory contains a readable number it will be used as
+the value for @code{max-uuxqts}.
+
+@item run-uuxqt @var{string} or @var{number}
+@findex run-uuxqt
+
+Specify when @code{uuxqt} should be run by @code{uucico}. This may be a
+positive number, in which case @code{uucico} will start a @code{uuxqt}
+process whenever it receives the given number of execution files from
+the remote system, and, if necessary, at the end of the call. The
+argument may also be one of the strings @samp{once}, @samp{percall}, or
+@samp{never}. The string @samp{once} means that @code{uucico} will
+start @code{uuxqt} once at the end of execution. The string
+@samp{percall} means that @code{uucico} will start @code{uuxqt} once per
+call that it makes (this is only different from @code{once} when
+@code{uucico} is invoked in a way that causes it to make multiple calls,
+such as when the @samp{-r1} argument is used without the @samp{-s}
+argument). The string @samp{never} means that @code{uucico} will never
+start @code{uuxqt}, in which case @code{uuxqt} should be periodically
+run via some other mechanism. The default depends upon which type of
+configuration files are being used; if @code{HAVE_TAYLOR_CONFIG} is used
+the default is @samp{once}, otherwise if @code{HAVE_HDB_CONFIG} is used
+the default is @samp{percall}, and otherwise, for @code{HAVE_V2_CONFIG},
+the default is @samp{10}.
+
+@item timetable @var{string} @var{string}
+@findex timetable
+
+The @code{timetable} defines a timetable that may be used in
+subsequently appearing time strings; @ref{Time Strings}. The first
+string names the timetable entry; the second is a time string.
+
+The following @code{timetable} commands are predefined. The NonPeak
+timetable is included for compatibility. It originally described the
+offpeak hours of Tymnet and Telenet, but both have since changed their
+schedules.
+
+@example
+timetable Evening Wk1705-0755,Sa,Su
+timetable Night Wk2305-0755,Sa,Su2305-1655
+timetable NonPeak Wk1805-0655,Sa,Su
+@end example
+
+If this command does not appear, then obviously no additional timetables
+will be defined.
+
+@item v2-files @var{boolean}
+@findex v2-files
+
+If the code was compiled to be able to read V2 configuration files, a
+false argument to this command will prevent them from being read.
+This can be useful while testing. The default is true.
+
+@item hdb-files @var{boolean}
+@findex hdb-files
+
+If the code was compiled to be able to read HDB configuration files, a
+false argument to this command will prevent them from being read.
+This can be useful while testing. The default is true.
+
+@end table
+
+@node Configuration File Names, Log File Names, Miscellaneous (config), config File
+@subsection Configuration File Names
+
+@table @code
+
+@item sysfile @var{strings}
+@findex sysfile
+
+Specify the system file(s). The default is the file @file{sys} in the
+directory @var{newconfigdir}. These files hold information about other
+systems with which this system communicates; see @ref{sys File}.
+Multiple system files may be given on the line, and the @code{sysfile}
+command may be repeated; each system file has its own set of defaults.
+
+@item portfile @var{strings}
+@findex portfile
+
+Specify the port file(s). The default is the file @file{port} in the
+directory @var{newconfigdir}. These files describe ports which are used
+to call other systems and accept calls from other systems; see @ref{port
+File}. No port files need be named at all. Multiple port files may be
+given on the line, and the @code{portfile} command may be repeated.
+
+@item dialfile @var{strings}
+@findex dialfile
+
+Specify the dial file(s). The default is the file @file{dial} in the
+directory @var{newconfigdir}. These files describe dialing devices
+(modems); @xref{dial File}. No dial files need be named at all.
+Multiple dial files may be given on the line, and the @code{dialfile}
+command may be repeated.
+
+@item dialcodefile @var{strings}
+@findex dialcodefile
+@cindex configuration file (dialcode)
+@cindex dialcode file
+@cindex dialcode configuration file
+
+Specify the dialcode file(s). The default is the file @file{dialcode}
+in the directory @var{newconfigdir}. These files specify dialcodes that
+may be used when sending phone numbers to a modem. This permits using
+the same set of phone numbers in different area-codes or with different
+phone systems, by using dialcodes to specify the calling sequence. When
+a phone number goes through dialcode translation, the leading alphabetic
+characters are stripped off. The dialcode files are read line by line,
+just like any other configuration file, and when a line is found whose
+first word is the same as the leading characters from the phone number,
+the second word on the line (which would normally consist of numbers)
+replaces the dialcode in the phone number. No dialcode file need be
+used. Multiple dialcode files may be specified on the line, and the
+@code{dialcodefile} command may be repeated; all the dialcode files will
+be read in turn until a dialcode is located.
+
+@item callfile @var{strings}
+@findex callfile
+@cindex call out file
+@cindex call configuration file
+@cindex call out login name
+@cindex call out password
+@cindex configuration file (call)
+
+Specify the call out login name and password file(s). The default is
+the file @file{call} in the directory @var{newconfigdir}. If the call
+out login name or password for a system are given as @kbd{*}
+(@pxref{Logging In}), these files are read to get the real login name or
+password. Each line in the file(s) has three words: the system name,
+the login name, and the password. The login name and password may
+contain escape sequences like those in a chat script expect string
+(@pxref{Chat Scripts}). This file is only used when placing calls to
+remote systems; the password file described under @code{passwdfile}
+below is used for incoming calls. The intention of the call out file is
+to permit the system file to be publically readable; the call out files
+must obviously be kept secure. These files need not be used. Multiple
+call out files may be specified on the line, and the @code{callfile}
+command may be repeated; all the files will be read in turn until the
+system is found.
+
+@item passwdfile @var{strings}
+@findex passwdfile
+@cindex passwd file
+@cindex passwd configuration file
+@cindex configuration file (passwd)
+@cindex call in login name
+@cindex call in password
+
+Specify the password file(s) to use for login names when @code{uucico}
+is doing its own login prompting, which it does when given the
+@samp{-e}, @samp{-l} or @samp{-w} switches. The default is the file
+@file{passwd} in the directory @var{newconfigdir}. Each line in the
+file(s) has two words: the login name and the password (e.g. @code{Ufoo
+foopas}). They may contain escape sequences like those in a chat script
+expect string (@pxref{Chat Scripts}). The login name is accepted before
+the system name is known, so these are independent of which system is
+calling in; a particular login may be required for a system by using the
+@code{called-login} command in the system file (@pxref{Accepting a
+Call}). These password files are optional, although one must exist if
+@code{uucico} is to present its own login prompts.
+
+As a special exception, a colon may be used to separate the login name
+from the password, and a colon may be used to terminate the password.
+This means that the login name and password may not contain a colon.
+This feature, in conjunction with the @code{HAVE_ENCRYPTED_PASSWORDS}
+macro in @file{policy.h}, permits using a standard Unix
+@file{/etc/passwd} as a UUCP password file, providing the same set of
+login names and passwords for both @code{getty} and @code{uucico}.
+
+Multiple password files may be specified on the line, and the
+@code{passwdfile} command may be repeated; all the files will be read in
+turn until the login name is found.
+
+@end table
+
+@node Log File Names, Debugging Levels, Configuration File Names, config File
+@subsection Log File Names
+
+@table @code
+
+@item logfile @var{string}
+@findex logfile
+@cindex log file
+
+Name the log file. The default is from @file{policy.h}. Logging
+information is written to this file. If @code{HAVE_HDB_LOGGING} is
+defined in @file{policy.h}, then by default a separate log file is used
+for each system. Using this command to name a log file will cause all
+the systems to use it.
+
+@item statfile @var{string}
+@findex statfile
+@cindex statistics file
+
+Name the statistics file. The default is from @file{policy.h}.
+Statistical information about file transfers is written to this file.
+
+@item debugfile @var{string}
+@findex debugfile
+@cindex debugging file
+
+Name the file to which all debugging information is written. The
+default is from @file{policy.h}. This command is only effective if the
+code has been compiled to include debugging (this is controlled by the
+@code{DEBUG} macro in @file{policy.h}). If debugging is on, messages
+written to the log file are also written to the debugging file to make
+it easier to keep the order of actions straight. The debugging file is
+different from the log file because information such as passwords can
+appear in it, so it must be not be publically readable.
+
+@end table
+
+@node Debugging Levels, , Log File Names, config File
+@subsection Debugging Levels
+
+@table @code
+
+@item debug @var{string} @dots{}
+@findex debug in config file
+
+Set the debugging level. This command is only effective if the code has
+been compiled to include debugging. The default is to have no
+debugging. The arguments are strings which name the types of debugging
+to be turned on. The following types of debugging are defined:
+
+@table @samp
+@item abnormal
+Output debugging messages for abnormal situations, such as recoverable errors.
+@item chat
+Output debugging messages for chat scripts.
+@item handshake
+Output debugging messages for the initial handshake.
+@item uucp-proto
+Output debugging messages for the UUCP session protocol.
+@item proto
+Output debugging messages for the individual link protocols.
+@item port
+Output debugging messages for actions on the communication port.
+@item config
+Output debugging messages while reading the configuration files.
+@item spooldir
+Output debugging messages for actions in the spool directory.
+@item execute
+Output debugging messages whenever another program is executed.
+@item incoming
+List all incoming data in the debugging file.
+@item outgoing
+List all outgoing data in the debugging file.
+@item all
+All of the above.
+@end table
+
+The debugging level may also be specified as a number. A 1 will set
+@samp{chat} debugging, a 2 will set both @samp{chat} and
+@samp{handshake} debugging, and so on down the possibilities. Currently
+an 11 will turn on all possible debugging, since there are 11 types of
+debugging messages listed above; more debugging types may be added in
+the future. The @code{debug} command may be used several times in the
+configuration file; every debugging type named will be turned on. When
+running any of the programs, the @samp{-x} switch (actually, for
+@code{uulog} it's the @samp{-X} switch) may be used to turn on
+debugging. The argument to the @samp{-x} switch is one of the strings
+listed above, or a number as described above, or a comma separated list
+of strings (e.g. @samp{-x chat,handshake}). The @samp{-x} switch may
+also appear several times on the command line, in which case all named
+debugging types will be turned on. The @samp{-x} debugging is in
+addition to any debugging specified by the @code{debug} command; there
+is no way to cancel debugging information. The debugging level may also
+be set specifically for calls to or from a specific system with the
+@code{debug} command in the system file (@pxref{Miscellaneous (sys)}).
+
+The debugging messages are somewhat idiosyncratic; it may be necessary
+to refer to the source code for additional information in some cases.
+
+@end table
+
+@node sys File, port File, config File, Configuration Files
+@section The System Configuration File
+@cindex sys file
+@cindex system configuration file
+@cindex configuration file (sys)
+
+By default there is a single system configuration, named @file{sys} in
+the directory @var{newconfigdir}. This may be overridden by the
+@code{sysfile} command in the main configuration file; see
+@ref{Configuration File Names}.
+
+These files describe all remote systems known to the UUCP package.
+
+@menu
+* Defaults and Alternates:: Using defaults and alternates
+* Naming the System:: Naming the system
+* Calling Out:: Calling out
+* Accepting a Call:: Accepting a call
+* Protocol Selection:: Protocol selection
+* File Transfer Control:: File transfer control
+* Miscellaneous (sys):: Miscellaneous sys file commands
+* Default sys File Values:: Default values
+@end menu
+
+@node Defaults and Alternates, Naming the System, sys File, sys File
+@subsection Defaults and Alternates
+
+The first set of commands in the file, up to the first @code{system}
+command, specify defaults to be used for all systems in that file. Each
+@file{sys} file uses a different set of defaults.
+
+Subsequently, each set of commands from @code{system} up to the next
+@code{system} command describe a particular system. Default values may
+be overridden for specific systems.
+
+Each system may then have a series of alternate choices to use when
+calling out or calling in. The first set of commands for a particular
+system, up to the first @code{alternate} command, provide the first
+choice. Subsequently, each set of commands from @code{alternate} up to
+the next @code{alternate} command describe an alternate choice for
+calling out or calling in.
+
+When a system is called, the commands before the first @code{alternate}
+are used to select a phone number, port, and so forth; if the call fails
+for some reason, the commands between the first @code{alternate} and the
+second are used, and so forth. Well, not quite. Actually, each
+succeeding alternate will only be used if it is different in some
+relevant way (different phone number, different chat script, etc.). If
+you want to force the same alternate to be used again (to retry a phone
+call more than once, for example), enter the phone number (or any other
+relevant field) again to make it appear different.
+
+The alternates can also be used to give different permissions to an
+incoming call based on the login name. This will only be done if the
+first set of commands, before the first @code{alternate} command, uses
+the @code{called-login} command. The list of alternates will be
+searched, and the first alternate with a matching @code{called-login}
+command will be used. If no alternates match, the call will be
+rejected.
+
+The @code{alternate} command may also be used in the file-wide defaults
+(the set of commands before the first @code{system} command). This
+might be used to specify a list of ports which are available for all
+systems (for an example of this, see @ref{Gateway Example}) or to
+specify permissions based on the login name used by the remote system
+when it calls in. The first alternate for each system will default to
+the first alternate for the file-wide defaults (as modified by the
+commands used before the first @code{alternate} command for this
+system), the second alternate for each system to the second alternate
+for the file-wide defaults (as modified the same way), and so forth. If
+a system specifies more alternates than the file-wide defaults, the
+trailing ones will default to the last file-wide default alternate. If
+a system specifies fewer alternates than the file-wide defaults, the
+trailing file-wide default alternates will be used unmodified. The
+@code{default-alternates} command may be used to modify this behaviour.
+
+This can all get rather confusing, although it's easier to use than to
+describe concisely; the @code{uuchk} program may be used to ensure that
+you are getting what you want.
+
+@node Naming the System, Calling Out, Defaults and Alternates, sys File
+@subsection Naming the System
+
+@table @code
+
+@item system @var{string}
+@findex system
+
+Specify the remote system name. Subsequent commands up to the next
+@code{system} command refer to this system.
+
+@item alternate [@var{string}]
+@findex alternate
+
+Start an alternate set of commands (@pxref{Defaults and Alternates}).
+An optional argument may be used to name the alternate. This name will
+be put in the log file if the alternate is used to call the system.
+There is no way to name the first alternate (the commands before the
+first @code{alternate} command).
+
+@item default-alternates @var{boolean}
+@findex default-alternates
+
+If the argument is false, any remaining default alternates (from the
+defaults specified at the top of the current system file) will not be
+used. The default is true.
+
+@item alias @var{string}
+@findex alias
+
+Specify an alias for the current system. The alias may be used by local
+@code{uucp} and @code{uux} commands, as well as by the remote system
+(which can be convenient if a remote system changes its name). The
+default is to have no aliases.
+
+@item myname @var{string}
+@findex myname
+
+Specifies a different system name to use when calling the remote system.
+Also, if @code{called-login} is used and is not @samp{ANY}, then, when a
+system logs in with that login name, @var{string} is used as the local
+system name. Because the local system name must be determined before
+the remote system has identified itself, using @code{myname} and
+@code{called-login} together for any system will set the local name for
+that login; this means that each locally used system name must have a
+unique login name associated with it. This allows a system to have
+different names for an external and an internal network. The default is
+to not use a special local name.
+
+@end table
+
+@node Calling Out, Accepting a Call, Naming the System, sys File
+@subsection Calling Out
+
+This section describes commands used when placing a call to another
+system.
+
+@menu
+* When to Call:: When to call
+* Placing the Call:: Placing the call
+* Logging In:: Logging in
+@end menu
+
+@node When to Call, Placing the Call, Calling Out, Calling Out
+@subsubsection When to Call
+
+@table @code
+
+@item time @var{string} [@var{number}]
+@findex time
+
+Specify when the system may be called. The first argument is a time
+string; see @ref{Time Strings}. The optional second argument specifies
+a retry time in minutes. If a call made during a time that matches the
+time string fails, no more calls are permitted until the retry time has
+passed. By default an exponentially increasing retry time is used:
+after each failure the next retry period is longer. A retry time
+specified in the @code{time} command is always a fixed amount of time.
+
+The @code{time} command may appear multiple times in a single alternate,
+in which case if any time string matches the system may be called. When
+the @code{time} command is used for a particular system, any @code{time}
+or @code{timegrade} commands that appeared in the system defaults are
+ignored.
+
+The default time string is @samp{Never}.
+
+@item timegrade @var{character} @var{string} [@var{number}]
+@findex timegrade
+
+The @var{character} specifies a grade. It must be a single letter or
+digit. The @var{string} is a time string (@pxref{Time Strings}). All
+jobs of grade @var{character} or higher (where @kbd{0} > @kbd{9} >
+@kbd{A} > @kbd{Z} > @kbd{a} > @kbd{z}) may be run at the specified time.
+An ordinary @code{time} command is equivalent to using @code{timegrade}
+with a grade of @kbd{z}, permitting all jobs. If there are no jobs of a
+sufficiently high grade according to the time string, the system will
+not be called. Giving the @samp{-s} switch to @code{uucico} to force it
+to call a system causes it to assume there is a job of grade @kbd{0}
+waiting to be run.
+
+The optional third argument specifies a retry time in minutes. See the
+@code{time} command, above, for more details.
+
+Note that the @code{timegrade} command serves two purposes: 1) if there
+is no job of sufficiently high grade the system will not be called, and
+2) if the system is called anyway (because the @samp{-s} switch was
+given to @code{uucico}) only jobs of sufficiently high grade will be
+transferred. However, if the other system calls in, the
+@code{timegrade} commands are ignored, and jobs of any grade may be
+transferred (but see @code{call-timegrade} below). Also, the
+@code{timegrade} command will not prevent the other system from
+transferring any job it chooses, regardless of who placed the call.
+
+The @code{timegrade} command may appear multiple times without using
+@code{alternate}. When the @code{timegrade} command is used for a
+particular system, any @code{time} or @code{timegrade} commands that
+appeared in the system defaults are ignored.
+
+If this command does not appear, there are no restrictions on what grade
+of work may be done at what time.
+
+@item max-retries @var{number}
+@findex max-retries
+
+Gives the maximum number of times this system may be retried. If this
+many calls to the system fail, it will be called at most once a day
+whatever the retry time is. The default is 26.
+
+@item success-wait @var{number}
+
+A retry time, in seconds, which applies after a successful call. This
+can be used to put a limit on how frequently the system is called. For
+example, an argument of 1800 means that the system will not be called
+more than once every half hour. The default is 0, which means that
+there is no limit.
+
+@item call-timegrade @var{character} @var{string}
+@findex call-timegrade
+
+The @var{character} is a single character @kbd{A} to @kbd{Z}, @kbd{a} to
+@kbd{z}, or @kbd{0} to @kbd{9} and specifies a grade. The @var{string}
+is a time string as described under the @code{time} command. If a call
+is placed to the other system during a time which matches the time
+string, the remote system will be requested to only run jobs of grade
+@var{character} or higher. Unfortunately, there is no way to guarantee
+that the other system will obey the request (this UUCP package will, but
+there are others which will not); moreover job grades are historically
+somewhat arbitrary, so specifying a grade will only be meaningful if the
+other system cooperates in assigning grades. This grade restriction
+only applies when the other system is called, not when the other system
+calls in.
+
+The @code{call-timegrade} command may appear multiple times without
+using @code{alternate}. If this command does not appear, or if none of
+the time strings match, the remote system will be allowed to send
+whatever grades of work it chooses.
+
+@end table
+
+@node Placing the Call, Logging In, When to Call, Calling Out
+@subsubsection Placing the Call
+
+@table @code
+
+@itemx speed @var{number}
+@findex speed in sys file
+@item baud @var{number}
+@findex baud in sys file
+
+Specify the speed (the term @dfn{baud} is technically incorrect, but
+widely understood) at which to call the system. This will try all
+available ports with that speed until an unlocked port is found. The
+ports are defined in the port file. If both @code{speed} and
+@code{port} commands appear, both are used when selecting a port. To
+allow calls at more than one speed, the @code{alternate} command must be
+used (@pxref{Defaults and Alternates}). If this command does not
+appear, there is no default; the speed may be specified in the port
+file, but if it is not then the natural speed of the port will be used
+(whatever that means on the system). Specifying an explicit speed of 0
+will request the natural speed of the port (whatever the system sets it
+to), overriding any default speed from the defaults at the top of the
+file.
+
+@item port @var{string}
+@findex port in sys file
+
+Name a particular port or type of port to use when calling the system.
+The information for this port is obtained from the port file. If this
+command does not appear, there is no default; a port must somehow be
+specified in order to call out (it may be specified implicitly using the
+@code{speed} command or explicitly using the next version of
+@code{port}). There may be many ports with the same name; each will be
+tried in turn until an unlocked one is found which matches the desired
+speed.
+
+@item port @var{string} @dots{}
+
+If more than one string follows the @code{port} command, the strings are
+treated as a command that might appear in the port file (@pxref{port
+File}). If a port is named (by using a single string following
+@code{port}) these commands are ignored; their purpose is to permit
+defining the port completely in the system file rather than always
+requiring entries in two different files. In order to call out, a port
+must be specified using some version of the @code{port} command, or by
+using the @code{speed} command to select ports from the port file.
+
+@item phone @var{string}
+@findex phone
+@itemx address @var{string}
+@findex address
+
+Give a phone number to call (when using a modem port) or a remote host
+to contact (when using a TCP or TLI port). The commands @code{phone}
+and @code{address} are equivalent; the duplication is intended to
+provide a mnemonic choice depending on the type of port in use.
+
+When used with a modem port, an @kbd{=} character in the phone number
+means to wait for a secondary dial tone (although only some modems
+support this); a @kbd{-} character means to pause while dialing for 1
+second (again, only some modems support this). If the system has more
+than one phone number, each one must appear in a different alternate.
+The @code{phone} command must appear in order to call out on a modem;
+there is no default.
+
+When used with a TCP port, the string names the host to contact. It may
+be a domain name or a numeric Internet address. If no address is
+specified, the system name is used.
+
+When used with a TLI port, the string is treated as though it were an
+expect string in a chat script, allowing the use of escape characters
+(@pxref{Chat Scripts}). The @code{dialer-sequence} command in the port
+file may override this address (@pxref{port File}).
+
+When used with a port that not a modem or TCP or TLI, this command is
+ignored.
+
+@end table
+
+@node Logging In, , Placing the Call, Calling Out
+@subsubsection Logging In
+@table @code
+
+@item chat @var{strings}
+@findex chat in sys file
+@item chat-timeout @var{number}
+@findex chat-timeout in sys file
+@item chat-fail @var{string}
+@findex chat-fail in sys file
+@item chat-seven-bit @var{boolean}
+@findex chat-seven-bit in sys file
+@item chat-program @var{strings}
+@findex chat-program in sys file
+
+These commands describe a chat script to use when logging on to a remote
+system. Chat scripts are explained in @ref{Chat Scripts}.
+
+Two additional escape sequences may be used in send strings.
+
+@table @samp
+@item \L
+Send the login name, as set by the @code{call-login} command.
+@item \P
+Send the password, as set by the @code{call-password} command.
+@end table
+
+Three additional escape sequences may be used with the
+@code{chat-program} command. These are @samp{\L} and @samp{\P}, which
+become the login name and password, respectively, and @samp{\Z}, which
+becomes the name of the system of being called.
+
+The default chat script is:
+
+@example
+chat "" \r\c ogin:-BREAK-ogin:-BREAK-ogin: \L word: \P
+@end example
+
+This will send a carriage return (the @kbd{\c} suppresses the additional
+trailing carriage return that would otherwise be sent) and waits for the
+string @samp{ogin:} (which would be the last part of the @samp{login:}
+prompt supplied by a Unix system). If it doesn't see @samp{ogin:}, it
+sends a break and waits for @samp{ogin:} again. If it still doesn't see
+@samp{ogin:}, it sends another break and waits for @samp{ogin:} again.
+If it still doesn't see @samp{ogin:}, the chat script aborts and hangs
+up the phone. If it does see @samp{ogin:} at some point, it sends the
+login name (as specified by the @code{call-login} command) followed by a
+carriage return (since all send strings are followed by a carriage
+return unless @kbd{\c} is used) and waits for the string @samp{word:}
+(which would be the last part of the @samp{Password:} prompt supplied by
+a Unix system). If it sees @samp{word:}, it sends the password and a
+carriage return, completing the chat script. The program will then
+enter the handshake phase of the UUCP protocol.
+
+This chat script will work for most systems, so you will only be
+required to use the @code{call-login} and @code{call-password} commands.
+In fact, in the file-wide defaults you could set defaults of
+@samp{call-login *} and @samp{call-password *}; you would then just have
+to make an entry for each system in the call-out login file.
+
+Some systems seem to flush input after the @samp{login:} prompt, so they
+may need a version of this chat script with a @kbd{\d} before the
+@kbd{\L}. When using UUCP over TCP, some servers will not be handle the
+initial carriage return sent by this chat script; in this case you may
+have to specify the simple chat script @samp{ogin: \L word: \P}.
+
+@item call-login @var{string}
+@findex call-login
+
+Specify the login name to send with @kbd{\L} in the chat script. If the
+string is @samp{*} (e.g. @samp{call-login *}) the login name will be
+fetched from the call out login name and password file
+(@pxref{Configuration File Names}). The string may contain escape
+sequences as though it were an expect string in a chat script
+(@pxref{Chat Scripts}). There is no default.
+
+@item call-password @var{string}
+@findex call-password
+
+Specify the password to send with @kbd{\P} in the chat script. If the
+string is @samp{*} (e.g. @samp{call-password *}) the password will be
+fetched from the call-out login name and password file
+(@pxref{Configuration File Names}). The string may contain escape
+sequences as though it were an expect string in a chat script
+(@pxref{Chat Scripts}). There is no default.
+
+@end table
+
+@node Accepting a Call, Protocol Selection, Calling Out, sys File
+@subsection Accepting a Call
+
+@table @code
+
+@item called-login @var{strings}
+@findex called-login
+
+The first @var{string} specifies the login name that the system must use
+when calling in. If it is @samp{ANY} (e.g. @samp{called-login ANY}) any
+login name may be used; this is useful to override a file-wide default
+and to indicate that future alternates may have different login names.
+Case is significant. The default value is @samp{ANY}.
+
+Different alternates (@pxref{Defaults and Alternates}) may use different
+@code{called-login} commands, in which case the login name will be used
+to select which alternate is in effect; this will only work if the first
+alternate (before the first @code{alternate} command) uses the
+@code{called-login} command.
+
+Additional strings may be specified after the login name; they are a
+list of which systems are permitted to use this login name. If this
+feature is used, then normally the login name will only be given in a
+single @code{called-login} command. Only systems which appear on the
+list, or which use an explicit @code{called-login} command, will be
+permitted to use that login name. If the same login name is used more
+than once with a list of systems, all the lists are concatenated
+together. This feature permits you to restrict a login name to a
+particular set of systems without requiring you to use the
+@code{called-login} command for every single system; you can achieve a
+similar effect by using a different system file for each permitted login
+name with an appropriate @code{called-login} command in the file-wide
+defaults.
+
+@item callback @var{boolean}
+@findex callback
+
+If @var{boolean} is true, then when the remote system calls
+@code{uucico} will hang up the connection and prepare to call it back.
+The default is false.
+
+@item called-chat @var{strings}
+@findex called-chat
+@item called-chat-timeout @var{number}
+@findex called-chat-timeout
+@item called-chat-fail @var{string}
+@findex called-chat-fail
+@item called-chat-seven-bit @var{boolean}
+@findex called-chat-seven-bit
+@item called-chat-program @var{strings}
+@findex called-chat-program
+
+These commands may be used to define a chat script (@pxref{Chat
+Scripts}) that is run whenever the local system is called by the system
+being defined. The chat script defined by the @code{chat} command
+(@pxref{Logging In}), on the other hand, is used when the remote system
+is called. This called chat script might be used to set special modem
+parameters that are appropriate to a particular system. It is run after
+protocol negotiation is complete, but before the protocol has been
+started. See @ref{Logging In} for additional escape sequence which may
+be used besides those defined for all chat scripts. There is no default
+called chat script. If the called chat script fails, the incoming call
+will be aborted.
+
+@end table
+
+@node Protocol Selection, File Transfer Control, Accepting a Call, sys File
+@subsection Protocol Selection
+
+@table @code
+
+@item protocol @var{string}
+@findex protocol in sys file
+
+Specifies which protocols to use for the other system, and in which
+order to use them. This would not normally be used. For example,
+@samp{protocol tfg}.
+
+The default depends on the characteristics of the port and the dialer,
+as specified by the @code{seven-bit} and @code{reliable} commands. If
+neither the port nor the dialer use either of these commands, the
+default is to assume an eight-bit reliable connection. The commands
+@samp{seven-bit true} or @samp{reliable false} might be used in either
+the port or the dialer to change this. Each protocol has particular
+requirements that must be met before it will be considered during
+negotiation with the remote side.
+
+The @samp{t} and @samp{e} protocols are intended for use over TCP or
+some other communication path with end to end reliability, as they do no
+checking of the data at all. They will only be considered on a TCP port
+which is both reliable and eight bit.
+
+The @samp{i} protocol is a bidirectional protocol. It requires an
+eight-bit connection. It will run over a half-duplex link, such as
+Telebit modems in PEP mode, but for efficient use of such a connection
+you must use the @code{half-duplex} command (@pxref{port File}).
+
+The @samp{g} protocol is robust, but requires an eight-bit connection.
+
+The @samp{G} protocol is the System V Release 4 version of the @samp{g}
+protocol.
+
+The @samp{a} protocol is a Zmodem like protocol, contributed by Doug
+Evans. It requires an eight-bit connection, but unlike the @samp{g} or
+@samp{i} protocol it will work if certain control characters may not be
+transmitted.
+
+The @samp{j} protocol is a variant of the @samp{i} protocol which can
+avoid certain control characters. The set of characters it avoids can
+be set by a parameter. While it technically does not require an eight
+bit connection (it could be configured to avoid all characters with the
+high bit set) it would be very inefficient to use it over one. It is
+useful over a eight-bit connection that will not transmit certain
+control characters.
+
+The @samp{f} protocol is intended for use with X.25 connections; it
+checksums each file as a whole, so any error causes the entire file to
+be retransmitted. It requires a reliable connection, but only uses
+seven-bit transmissions. It is a streaming protocol, so, while it can
+be used on a serial port, the port must be completely reliable and flow
+controlled; many aren't.
+
+The @samp{v} protocol is the @samp{g} protocol as used by the DOS
+program UUPC/Extended. It is provided only so that UUPC/Extended users
+can use it; there is no particular reason to select it.
+
+The protocols will be considered in the order shown above. This means
+that if neither the @code{seven-bit} nor the @code{reliable} command are
+used, the @samp{t} protocol will be used over a TCP connection and the
+@samp{i} protocol will be used over any other type of connection
+(subject, of course, to what is supported by the remote system; it may
+be assumed that all systems support the @samp{g} protocol).
+
+Note that currently specifying both @samp{seven-bit true} and
+@samp{reliable false} will not match any protocol. If this occurs
+through a combination of port and dialer specifications, you will have
+to use the @code{protocol} command for the system or no protocol will be
+selected at all (the only reasonable choice would be @samp{protocol f}).
+
+A protocol list may also be specified for a port (@pxref{port File}),
+but if there is a list for the system the list for the port is ignored.
+
+@item protocol-parameter @var{character} @var{string} @dots{}
+@findex protocol-parameter in sys file
+
+@var{character} is a single character specifying a protocol. The
+remaining strings are a command specific to that protocol which will be
+executed if that protocol is used. A typical command is something like
+@samp{window 7}. The particular commands are protocol specific.
+
+The @samp{i} protocol supports the following commands, all of which take
+numeric arguments:
+
+@table @code
+@item window
+The window size to request the remote system to use. This must be
+between 1 and 16 inclusive. The default is 16.
+@item packet-size
+The packet size to request the remote system to use. This must be
+between 1 and 4095 inclusive. The default is 1024.
+@item remote-packet-size
+If this is between 1 and 4095 inclusive, the packet size requested by
+the remote system is ignored and this is used instead. The default is
+0, which means that the remote system's request is honored.
+@item sync-timeout
+The length of time, in seconds, to wait for a SYNC packet from the remote
+system. SYNC packets are exchanged when the protocol is started. The
+default is 10.
+@item sync-retries
+The number of times to retry sending a SYNC packet before giving up.
+The default is 6.
+@item timeout
+The length of time, in seconds, to wait for an incoming packet before
+sending a negative acknowledgement. The default is 10.
+@item retries
+The number of times to retry sending a packet or a negative
+acknowledgement before giving up and closing the connection. The
+default is 6.
+@item errors
+The maximum number of errors to permit before closing the connection.
+The default is 100.
+@item error-decay
+The rate at which to ignore errors. Each time this many packets are
+received, the error count is decreased by one, so that a long connection
+with an occasional error will not exceed the limit set by @code{errors}.
+The default is 10.
+@item ack-frequency
+The number of packets to receive before sending an acknowledgement. The
+default is half the requested window size, which should provide good
+performance in most cases.
+@end table
+
+The @samp{g}, @samp{G} and @samp{v} protocols support the following
+commands, all of which take numeric arguments, except
+@code{short-packets} which takes a boolean argument:
+
+@table @code
+@item window
+The window size to request the remote system to use. This must be
+between 1 and 7 inclusive. The default is 7.
+@item packet-size
+The packet size to request the remote system to use. This must be a
+power of 2 between 32 and 4096 inclusive. The default is 64 for the
+@samp{g} and @samp{G} protocols and 512 for the @samp{v} protocol. Many
+older UUCP packages do not support packet sizes larger than 64, and many
+others do not support packet sizes larger than 128. Some UUCP packages
+will even dump core if a larger packet size is requested. The packet
+size is not a negotiation, and it may be different in each direction.
+If you request a packet size larger than the remote system supports, you
+will not be able to send any files.
+@item startup-retries
+The number of times to retry the initialization sequence. The default
+is 8.
+@item init-retries
+The number of times to retry one phase of the initialization sequence
+(there are three phases). The default is 4.
+@item init-timeout
+The timeout in seconds for one phase of the initialization sequence. The
+default is 10.
+@item retries
+The number of times to retry sending either a data packet or a request
+for the next packet. The default is 6.
+@item timeout
+The timeout in seconds when waiting for either a data packet or an
+acknowledgement. The default is 10.
+@item garbage
+The number of unrecognized bytes to permit before dropping the
+connection. This must be larger than the packet size. The default is
+10000.
+@item errors
+The number of errors (malformed packets, out of order packets, bad
+checksums, or packets rejected by the remote system) to permit before
+dropping the connection. The default is 100.
+@item error-decay
+The rate at which to ignore errors. Each time this many packets are
+received, the error count is decreased by one, so that a long connection
+with an occasional error will not exceed the limit set by @code{errors}.
+The default is 10.
+@item remote-window
+If this is between 1 and 7 inclusive, the window size requested by the
+remote system is ignored and this is used instead. This can be useful
+when dealing with some poor UUCP packages. The default is 0, which
+means that the remote system's request is honored.
+@item remote-packet-size
+If this is between 32 and 4096 inclusive the packet size requested by
+the remote system is ignored and this is used instead. There is
+probably no good reason to use this. The default is 0, which means that
+the remote system's request is honored.
+@item short-packets
+If this is true, then the code will optimize by sending shorter packets
+when there is less data to send. This confuses some UUCP packages, such
+as System V Release 4 (when using the @samp{G} protocol) and Waffle;
+when connecting to such a package, this parameter must be set to false.
+The default is true for the @samp{g} and @samp{v} protocols and false
+for the @samp{G} protocol.
+@end table
+
+The @samp{a} protocol is a Zmodem like protocol contributed by Doug
+Evans. It supports the following commands, all of which take numeric
+arguments except for @code{escape-control}, which takes a boolean
+argument:
+
+@table @code
+@item timeout
+Number of seconds to wait for a packet to arrive. The default is 10.
+@item retries
+The number of times to retry sending a packet. The default is 10.
+@item startup-retries
+The number of times to retry sending the initialization packet. The
+default is 4.
+@item garbage
+The number of garbage characters to accept before closing the
+connection. The default is 2400.
+@item send-window
+The number of characters that may be sent before waiting for an
+acknowledgement. The default is 1024.
+@item escape-control
+Whether to escape control characters. If this is true, the protocol may
+be used over a connection which does not transmit certain control
+characters, such as @code{XON} or @code{XOFF}. The connection must
+still transmit eight bit characters other than control characters. The
+default is false.
+@end table
+
+The @samp{j} protocol can be used over an eight bit connection that will
+not transmit certain control characters. It accepts the same protocol
+parameters that the @samp{i} protocol accepts, as well as one more:
+
+@table @code
+@item avoid
+A list of characters to avoid. This is a string which is interpreted as
+an escape sequence (@pxref{Chat Scripts}). The protocol does not have a
+way to avoid printable ASCII characters (byte values from 32 to 126,
+inclusive); only ASCII control characters and eight-bit characters may
+be avoided. The default value is @samp{\021\023}; these are the
+characters @code{XON} and @code{XOFF} which many connections use for
+flow control. If the package is configured to use @code{HAVE_BSD_TTY},
+then on some versions of Unix you may have to avoid @samp{\377} as well,
+due to the way some implementations of the BSD terminal driver handle
+signals.
+@end table
+
+The @samp{f} protocol is intended for use with error-correcting modems
+only; it checksums each file as a whole, so any error causes the entire
+file to be retransmitted. It supports the following commands, both of
+which take numeric arguments:
+
+@table @code
+@item timeout
+The timeout in seconds before giving up. The default is 120.
+@item retries
+How many times to retry sending a file. The default is 2.
+@end table
+
+The @samp{t} and @samp{e} protocols are intended for use over TCP or
+some other communication path with end to end reliability, as they do no
+checking of the data at all. They both support a single command, which
+takes a numeric argument:
+
+@table @code
+@item timeout
+The timeout in seconds before giving up. The default is 120.
+@end table
+
+The protocol parameters are reset to their default values after each
+call.
+
+@end table
+
+@node File Transfer Control, Miscellaneous (sys), Protocol Selection, sys File
+@subsection File Transfer Control
+
+@table @code
+
+@item send-request @var{boolean}
+@findex send-request
+
+The @var{boolean} determines whether the remote system is permitted to
+request files from the local system. The default is yes.
+
+@item receive-request @var{boolean}
+@findex receive-request
+
+The @var{boolean} determines whether the remote system is permitted to
+send files to the local system. The default is yes.
+
+@item request @var{boolean}
+@findex request
+
+A shorthand command, equivalent to specifying both @samp{send-request
+@var{boolean}} and @samp{receive-request @var{boolean}}.
+
+@item call-transfer @var{boolean}
+@findex call-transfer
+
+The @var{boolean} is checked when the local system places the call. It
+determines whether the local system may do file transfers queued up for
+the remote system. The default is yes.
+
+@item called-transfer @var{boolean}
+@findex called-transfer
+
+The @var{boolean} is checked when the remote system calls in. It
+determines whether the local system may do file transfers queued up for
+the remote system. The default is yes.
+
+@item transfer @var{boolean}
+@findex transfer
+
+Equivalent to specifying both @samp{call-transfer @var{boolean}}
+@samp{called-transfer @var{boolean}}.
+
+@item call-local-size @var{number} @var{string}
+@findex call-local-size
+
+The @var{string} is a time string (@pxref{Time Strings}). The
+@var{number} is the size in bytes of the largest file that should be
+transferred at a time matching the time string if the local system
+placed the call and the request was made by the local system. This
+command may appear multiple times in a single alternate. If this
+command does not appear, or if none of the time strings match, there are
+no size restrictions.
+
+With all the size control commands, the size of a file from the remote
+system (as opposed to a file from the local system) will only be checked
+if the other system is running this package; other UUCP packages will
+not understand a maximum size request, nor will they provide the size of
+remote files.
+
+@item call-remote-size @var{number} @var{string}
+@findex call-remote-size
+
+Specify the size in bytes of the largest file that should be
+transferred at a given time by remote request when the local system
+placed the call. This command may appear multiple times in a single
+alternate. If this command does not appear, there are no size
+restrictions.
+
+@item called-local-size @var{number} @var{string}
+@findex called-local-size
+
+Specify the size in bytes of the largest file that should be transferred
+at a given time by local request when the remote system placed the call.
+This command may appear multiple times in a single alternate. If this
+command does not appear, there are no size restrictions.
+
+@item called-remote-size @var{number} @var{string}
+@findex called-remote-size
+
+Specify the size in bytes of the largest file that should be transferred
+at a given time by remote request when the remote system placed the
+call. This command may appear multiple times in a single alternate. If
+this command does not appear, there are no size restrictions.
+
+@item local-send @var{strings}
+@findex local-send
+
+Specifies that files in the directories named by the @var{strings} may
+be sent to the remote system when requested locally (using @code{uucp}
+or @code{uux}). The directories in the list should be separated by
+whitespace. A @kbd{~} may be used for the public directory. On a Unix
+system, this is typically @file{/usr/spool/uucppublic}; the public
+directory may be set with the @code{pubdir} command. Here is an example
+of @code{local-send}:
+
+@example
+local-send ~ /usr/spool/ftp/pub
+@end example
+
+Listing a directory allows all files within the directory and all
+subdirectories to be sent. Directories may be excluded by preceding
+them with an exclamation point. For example:
+
+@example
+local-send /usr/ftp !/usr/ftp/private ~
+@end example
+
+@noindent
+means that all files in @file{/usr/ftp} or the public directory may be
+sent, except those files in @file{/usr/ftp/private}. The list of
+directories is read from left to right, and the last directory to apply
+takes effect; this means that directories should be listed from top
+down. The default is the root directory (i.e., any file at all may be
+sent by local request).
+
+@item remote-send @var{strings}
+@findex remote-send
+
+Specifies that files in the named directories may be sent to the remote
+system when requested by the remote system. The default is @kbd{~}.
+
+@item local-receive @var{strings}
+@findex local-receive
+
+Specifies that files may be received into the named directories when
+requested by a local user. The default is @kbd{~}.
+
+@item remote-receive @var{strings}
+@findex remote-receive
+
+Specifies that files may be received into the named directories when
+requested by the remote system. The default is @kbd{~}. On Unix, the
+remote system may only request that files be received into directories
+that are writeable by the world, regardless of how this is set.
+
+@item forward-to @var{strings}
+@findex forward-to
+
+Specifies a list of systems to which files may be forwarded. The remote
+system may forward files through the local system on to any of the
+systems in this list. The string @samp{ANY} may be used to permit
+forwarding to any system. The default is to not permit forwarding to
+other systems. Note that if the remote system is permitted to execute
+the @code{uucp} command, it effectively has the ability to forward to
+any system.
+
+@item forward-from @var{strings}
+@findex forward-from
+
+Specifies a list of systems from which files may be forwarded. The
+remote system may request files via the local system from any of the
+systems in this list. The string @samp{ANY} may be used to permit
+forwarding to any system. The default is to not permit forwarding from
+other systems. Note that if a remote system is permitted to execute the
+@code{uucp} command, it effectively has the ability to request files
+from any system.
+
+@item forward @var{strings}
+@findex forward
+
+Equivalent to specifying both @samp{forward-to @var{strings}} and
+@samp{forward-from @var{strings}}. This would normally be used rather
+than either of the more specific commands.
+
+@end table
+
+@node Miscellaneous (sys), Default sys File Values, File Transfer Control, sys File
+@subsection Miscellaneous sys File Commands
+
+@table @code
+
+@item sequence @var{boolean}
+@findex sequence
+
+If @var{boolean} is true, then conversation sequencing is automatically
+used for the remote system, so that if somebody manages to spoof as the
+remote system, it will be detected the next time the remote system
+actually calls. This is false by default.
+
+@item command-path @var{string}
+@findex command-path
+
+Specifies the path (a list of whitespace separated directories) to be
+searched to locate commands to execute. This is only used for commands
+requested by @code{uux}, not for chat programs. The default is from
+@file{policy.h}.
+
+@item commands @var{strings}
+@findex commands
+
+The list of commands which the remote system is permitted to execute
+locally. For example: @samp{commands rnews rmail}. If the value is
+@samp{ALL} (case significant), all commands may be executed. The
+default is @samp{rnews rmail}.
+
+@item free-space @var{number}
+@findex free-space
+
+Specify the minimum amount of file system space (in bytes) to leave free
+after receiving a file. If the incoming file will not fit, it will be
+rejected. This initial rejection will only work when talking to another
+instance of this package, since older UUCP packages do not provide the
+file size of incoming files. Also, while a file is being received,
+@code{uucico} will periodically check the amount of free space. If it
+drops below the amount given by the @code{free-space} command, the file
+transfer will be aborted. The default amount of space to leave free is
+from @file{policy.h}. This file space checking may not work on all
+systems.
+
+@item pubdir @var{string}
+@findex pubdir in sys file
+
+Specifies the public directory that is used when @kbd{~} is specifed in
+a file transfer or a list of directories. This essentially overrides
+the public directory specified in the main configuration file for this
+system only. The default is the public directory specified in the main
+configuration file (which defaults to a value from @file{policy.h}).
+
+@item debug @var{string} @dots{}
+@findex debug in sys file
+
+Set additional debugging for calls to or from the system. This may be
+used to debug a connection with a specific system. It is particularly
+useful when debugging incoming calls, since debugging information will
+be generated whenever the call comes in. See the @code{debug} command
+in the main configuration file (@pxref{Debugging Levels}) for more
+details. The debugging information specified here is in addition to
+that specified in the main configuration file or on the command line.
+
+@item max-remote-debug @var{string} @dots{}
+@findex max-remote-debug
+
+When the system calls in, it may request that the debugging level be set
+to a certain value. This command may be used to put a limit on the
+debugging level which the system may request, to avoid filling up the
+disk with debugging information. Only the debugging types named in the
+@code{max-remote-debug} command may be turned on by the remote system.
+To prohibit any debugging, use @samp{max-remote-debug none}.
+
+@end table
+
+@node Default sys File Values, , Miscellaneous (sys), sys File
+@subsection Default sys File Values
+
+The following are used as default values for all systems; they can be
+considered as appearing before the start of the file.
+
+@example
+time Never
+chat "" \r\c ogin:-BREAK-ogin:-BREAK-ogin: \L word: \P
+chat-timeout 10
+callback n
+sequence n
+request y
+transfer y
+local-send /
+remote-send ~
+local-receive ~
+remove-receive ~
+command-path [ from @file{policy.h} ]
+commands rnews rmail
+max-remote-debug abnormal,chat,handshake
+@end example
+
+@node port File, dial File, sys File, Configuration Files
+@section The Port Configuration File
+@cindex port file
+@cindex port configuration file
+@cindex configuration file (port)
+
+The port files may be used to name and describe ports. By default there
+is a single port file, named @file{port} in the directory
+@var{newconfigdir}. This may be overridden by the @code{portfile}
+command in the main configuration file; see @ref{Configuration File
+Names}.
+
+Any commands in a port file before the first @code{port} command specify
+defaults for all ports in the file; however, since the @code{type}
+command must appear before all other commands for a port, the defaults
+are only useful if all ports in the file are of the same type (this
+restriction may be lifted in a later version). All commands after a
+@code{port} command up to the next @code{port} command then describe
+that port. There are different types of ports; each type supports its
+own set of commands. Each command indicates which types of ports
+support it. There may be many ports with the same name; if a system
+requests a port by name then each port with that name will be tried
+until an unlocked one is found.
+
+@table @code
+
+@item port @var{string}
+@findex port in port file
+
+Introduces and names a port.
+
+@item type @var{string}
+@findex type
+
+Define the type of port. The default is @samp{modem}. If this command
+appears, it must immediately follow the @code{port} command. The type defines
+what commands are subsequently allowed. Currently the types are:
+
+@table @samp
+@item modem
+For a modem hookup.
+@item stdin
+For a connection through standard input and standard output, as when
+@code{uucico} is run as a login shell.
+@item direct
+For a direct connection to another system.
+@item tcp
+For a connection using TCP.
+@item tli
+For a connection using TLI.
+@item pipe
+For a connection through a pipe running another program.
+@end table
+
+@item protocol @var{string}
+@findex protocol in port file
+
+Specify a list of protocols to use for this port. This is just like the
+corresponding command for a system (@pxref{Protocol Selection}). A
+protocol list for a system takes precedence over a list for a port.
+
+@item protocol-parameter @var{character} @var{strings} [ any type ]
+@findex protocol-parameter in port file
+
+The same command as the @code{protocol-parameter} command used for
+systems (@pxref{Protocol Selection}). This one takes precedence.
+
+@item seven-bit @var{boolean} [ any type ]
+@findex seven-bit in port file
+
+This is only used during protocol negotiation; if the argument is true,
+it forces the selection of a protocol which works across a seven-bit
+link. It does not prevent eight bit characters from being transmitted.
+The default is false.
+
+@item reliable @var{boolean} [ any type ]
+@findex reliable in port file
+
+This is only used during protocol negotiation; if the argument is
+false, it forces the selection of a protocol which works across
+an unreliable communication link. The default is true. It would
+be more common to specify this for a dialer rather than a port.
+
+@item half-duplex @var{boolean} [ any type ]
+@findex half-duplex in port file
+
+If the argument is true, it means that the port only supports
+half-duplex connections. This only affects bidirectional protocols, and
+causes them to not do bidirectional transfers.
+
+@item device @var{string} [ modem, direct and tli only ]
+@findex device
+
+Names the device associated with this port. If the device is not named,
+the port name is taken as the device. Device names are system
+dependent. On Unix, a modem or direct connection might be something
+like @file{/dev/ttyd0}; a TLI port might be @file{/dev/inet/tcp}.
+
+@itemx speed @var{number} [modem and direct only ]
+@findex speed in port file
+@item baud @var{number} [ modem and direct only ]
+@findex baud in port file
+
+The speed this port runs at. If a system specifies a speed but no port
+name, then all ports which match the speed will be tried in order. If
+the speed is not specified here and is not specified by the system, the
+natural speed of the port will be used by default.
+
+@itemx speed-range @var{number} @var{number} [ modem only ]
+@findex speed-range
+@item baud-range @var{number} @var{number} [ modem only ]
+@findex baud-range
+
+Specify a range of speeds this port can run at. The first number is the
+minimum speed, the second number is the maximum speed. These numbers
+will be used when matching a system which specifies a desired speed.
+The simple @code{speed} (or @code{baud}) command is still used to
+determine the speed to run at if the system does not specify a speed.
+For example, the command @samp{speed-range 300 19200} means that the
+port will match any system which uses a speed from 300 to 19200 baud
+(and will use the speed specified by the system); this could be combined
+with @samp{speed 2400}, which means that when this port is used with a
+system that does not specify a speed, the port will be used at 2400
+baud.
+
+@item carrier @var{boolean} [ modem and direct only ]
+@findex carrier in port file
+
+The argument indicates whether the port supports carrier.
+
+If a modem port does not support carrier, the carrier detect signal will
+never be required on this port, regardless of what the modem chat script
+indicates. The default for a modem port is true.
+
+If a direct port supports carrier, the port will be set to expect
+carrier whenever it is used. The default for a direct port is false.
+
+@item hardflow @var{boolean} [ modem and direct only ]
+@findex hardflow
+
+The argument indicates whether the port supports hardware flow control.
+If it does not, hardware flow control will not be turned on for this
+port. The default is true. Hardware flow control is only supported on
+some systems.
+
+@item dial-device @var{string} [ modem only ]
+@findex dial-device
+
+Dialing instructions should be output to the named device, rather than
+to the normal port device. The default is to output to the normal port
+device.
+
+@item dialer @var{string} [ modem only ]
+@findex dialer in port file
+
+Name a dialer to use. The information is looked up in the dial file.
+There is no default. Some sort of dialer information must be specified
+to call out on a modem.
+
+@item dialer @var{string} @dots{} [ modem only ]
+
+Execute a dialer command. If a dialer is named (by using the first form
+of this command, described just above), these commands are ignored.
+They may be used to specify dialer information directly in simple
+situations without needing to go to a separate file. There is no
+default. Some sort of dialer information must be specified to call out
+on a modem.
+
+@item dialer-sequence @var{strings} [ modem or tcp or tli only ]
+@findex dialer-sequence
+
+Name a sequence of dialers and tokens (phone numbers) to use. The first
+argument names a dialer, and the second argument names a token. The
+third argument names another dialer, and so on. If there are an odd
+number of arguments, the phone number specified with a @code{phone}
+command in the system file is used as the final token. The token is
+what is used for @kbd{\D} or @kbd{\T} in the dialer chat script. If the
+token in this string is @kbd{\D}, the system phone number will be used;
+if it is @kbd{\T}, the system phone number will be used after undergoing
+dialcodes translation. A missing final token is taken as @kbd{\D}.
+
+This command currently does not work if @code{dial-device} is specified;
+to handle this correctly will require a more systematic notion of chat
+scripts. Moreover, the @code{complete} and @code{abort} chat scripts,
+the protocol parameters, and the @code{carrier} and @code{dtr-toggle}
+commands are ignored for all but the first dialer.
+
+This command basically lets you specify a sequence of chat scripts to
+use. For example, the first dialer might get you to a local network and
+the second dialer might describe how to select a machine from the local
+network. This lets you break your dialing sequence into simple modules,
+and may make it easier to share dialer entries between machines.
+
+This command is to only way to use a chat script with a TCP port. This
+can be useful when using a modem which is accessed via TCP.
+
+When this command is used with a TLI port, then if the first dialer is
+@samp{TLI} or @samp{TLIS} the first token is used as the address to
+connect to. If the first dialer is something else, or if there is no
+token, the address given by the @code{address} command is used
+(@pxref{Placing the Call}). Escape sequences in the address are
+expanded as they are for chat script expect strings (@pxref{Chat
+Scripts}). The different between @samp{TLI} and @samp{TLIS} is that the
+latter implies the command @samp{stream true}. These contortions are
+all for HDB compatibility. Any subsequent dialers are treated as they
+are for a TCP port.
+
+@item lockname @var{string} [ modem and direct only ]
+@findex lockname
+
+Give the name to use when locking this port. On Unix, this is the name
+of the file that will be created in the lock directory. It is used as
+is, so on Unix it should generally start with @samp{LCK..}. For
+example, if a single port were named both @file{/dev/ttycu0} and
+@file{/dev/tty0} (perhaps with different characteristics keyed on the
+minor device number), then the command @code{lockname LCK..ttycu0} could
+be used to force the latter to use the same lock file name as the
+former.
+
+@item service @var{string} [ tcp only ]
+@findex service
+
+Name the TCP port number to use. This may be a number. If not, it will
+be looked up in @file{/etc/services}. If this is not specified, the
+string @samp{uucp} is looked up in @file{/etc/services}. If it is not
+found, port number 540 (the standard UUCP-over-TCP port number) will be
+used.
+
+@item push @var{strings} [ tli only ]
+@findex push
+
+Give a list of modules to push on to the TLI stream.
+
+@item stream @var{boolean} [ tli only ]
+@findex stream
+
+If this is true, and the @code{push} command was not used, the
+@samp{tirdwr} module is pushed on to the TLI stream.
+
+@item server-address @var{string} [ tli only ]
+@findex server-address
+
+Give the address to use when running as a TLI server. Escape sequences
+in the address are expanded as they are for chat script expect strings
+(@pxref{Chat Scripts}).
+
+@item command @var{strings} [ pipe only ]
+@findex command
+
+Give the command, with arguments, to run when using a pipe port type.
+When a port of this type is used, the command is executed and uucico
+communicates with it over a pipe. This permits uucico or cu to
+communicate with another system which can only be reached through some
+unusual means. A sample use might be @samp{command /bin/rlogin -E -8 -l
+@var{login} @var{system}}. The command is run with the full privileges
+of UUCP; it is responsible for maintaining security.
+
+@end table
+
+@node dial File, Security, port File, Configuration Files
+@section The Dialer Configuration File
+@cindex dial file
+@cindex dialer configuration file
+@cindex configuration file (dial)
+
+The dialer configuration files define dialers. By default there is a
+single dialer file, named @file{dial} in the directory
+@var{newconfigdir}. This may be overridden by the @code{dialfile}
+command in the main configuration file; see @ref{Configuration File
+Names}.
+
+Any commands in the file before the first @code{dialer} command specify
+defaults for all the dialers in the file. All commands after a
+@code{dialer} command up to the next @code{dialer} command are
+associated with the named dialer.
+
+@table @code
+
+@item dialer @var{string}
+@findex dialer in dial file
+
+Introduces and names a dialer.
+
+@item chat @var{strings}
+@findex chat in dial file
+@item chat-timeout @var{number}
+@findex chat-timeout in dial file
+@item chat-fail @var{string}
+@findex chat-fail in dial file
+@item chat-seven-bit @var{boolean}
+@findex chat-seven-bit in dial file
+@item chat-program @var{strings}
+@findex chat-program in dial file
+
+Specify a chat script to be used to dial the phone. See @ref{Chat
+Scripts} for full details on chat scripts.
+
+Taylor UUCP will sleep for one second between attempts to dial out on a
+modem. If your modem requires a longer wait period, you must start your
+chat script with delays (@samp{\d} in a send string).
+
+The chat script will be read from and sent to the port specified by the
+@code{dial-device} command for the port, if there is one.
+
+The following escape addition escape sequences may appear in send
+strings:
+
+@table @kbd
+@item \D
+send phone number without dialcode translation
+@item \T
+send phone number with dialcode translation
+@item \M
+do not require carrier
+@item \m
+require carrier (fail if not present)
+@end table
+
+See the description of the dialcodes file (@pxref{Configuration File
+Names}) for a description of dialcode translation. If the port does not
+support carrier (as set by the @code{carrier} command in the port file)
+@kbd{\M} and @kbd{\m} are ignored. If both the port and the dialer
+support carrier (as set by the @code{carrier} command in the port file
+and the @code{carrier} command in the dialer file), then every chat
+script implicitly begins with @kbd{\M} and ends with @kbd{\m}. There is
+no default chat script for dialers.
+
+The following additional escape sequences may be used in
+@code{chat-program}:
+
+@table @kbd
+@item \D
+phone number without dialcode translation
+@item \T
+phone number with dialcode translation
+@end table
+
+If the program changes the port in any way (e.g., sets parity) the
+changes will be preserved during protocol negotiation, but once the
+protocol is selected it will change the port settings.
+
+@item dialtone @var{string}
+@findex dialtone
+
+A string to output when dialing the phone number which causes the modem
+to wait for a secondary dial tone. This is used to translate the
+@kbd{=} character in a phone number. The default is a comma.
+
+@item pause @var{string}
+@findex pause
+
+A string to output when dialing the phone number which causes the modem
+to wait for 1 second. This is used to translate the @kbd{-} character
+in a phone number. The default is a comma.
+
+@item carrier @var{boolean}
+@findex carrier in dial file
+
+If the argument is true, the dialer supports the modem carrier signal.
+After the phone number is dialed, @code{uucico} will require that
+carrier be on. One some systems, it will be able to wait for it. If
+the argument is false, carrier will not be required. The default is
+true.
+
+@item carrier-wait @var{number}
+@findex carrier-wait
+
+If the port is supposed to wait for carrier, this may be used to
+indicate how many seconds to wait. The default is 60 seconds. Only
+some systems support waiting for carrier.
+
+@item dtr-toggle @var{boolean} @var{boolean}
+@findex dtr-toggle
+
+If the first argument is true, then DTR is toggled before using
+the modem. This is only supported on some systems and some ports. The
+second @var{boolean} need not be present; if it is, and it is
+true, the program will sleep for 1 second after toggling DTR.
+The default is not to toggle DTR.
+
+@item complete-chat @var{strings}
+@findex complete-chat
+@item complete-chat-timeout @var{number}
+@findex complete-chat-timeout
+@item complete-chat-fail @var{string}
+@findex complete-chat-fail
+@item complete-chat-seven-bit @var{boolean}
+@findex complete-chat-seven-bit
+@item complete-chat-program @var{strings}
+@findex complete-chat-program
+
+These commands define a chat script (@pxref{Chat Scripts}) which is run
+when a call is finished normally. This allows the modem to be reset.
+There is no default. No additional escape sequences may be used.
+
+@item complete @var{string}
+@findex complete
+
+This is a simple use of @code{complete-chat}. It is equivalent to
+@code{complete-chat "" @var{string}}; this has the effect of sending
+@var{string} to the modem when a call finishes normally.
+
+@item abort-chat @var{strings}
+@findex abort-chat
+@item abort-chat-timeout @var{number}
+@findex abort-chat-timeout
+@item abort-chat-fail @var{string}
+@findex abort-chat-fail
+@item abort-chat-seven-bit @var{boolean}
+@findex abort-chat-seven-bit
+@item abort-chat-program @var{strings}
+@findex abort-chat-program
+
+These commands define a chat script (@pxref{Chat Scripts}) to be run
+when a call is aborted. They may be used to interrupt and reset the
+modem. There is no default. No additional escape sequences may be
+used.
+
+@item abort @var{string}
+@findex abort
+
+This is a simple use of @code{abort-chat}. It is equivalent to
+@code{abort-chat "" @var{string}}; this has the effect of sending
+@var{string} to the modem when a call is aborted.
+
+@item protocol-parameter @var{character} @var{strings}
+@findex protocol-parameter in dial file
+
+Set protocol parameters, just like the @code{protocol-parameter} command
+in the system configuration file or the port configuration file; see
+@ref{Protocol Selection}. These parameters take precedence, then those
+for the port, then those for the system.
+
+@item seven-bit @var{boolean}
+@findex seven-bit in dial file
+
+This is only used during protocol negotiation; if it is true, it
+forces selection of a protocol which works across a seven-bit link. It
+does not prevent eight bit characters from being transmitted. The
+default is false. It would be more common to specify this for a
+port than for a dialer.
+
+@item reliable @var{boolean}
+@findex reliable in dial file
+
+This is only used during protocol negotiation; if it is false, it
+forces selection of a protocol which works across an unreliable
+communication link. The default is true.
+
+@item half-duplex @var{boolean} [ any type ]
+@findex half-duplex in dial file
+
+If the argument is true, it means that the dialer only supports
+half-duplex connections. This only affects bidirectional protocols, and
+causes them to not do bidirectional transfers.
+
+@end table
+
+@node Security, , dial File, Configuration Files
+@section Security
+
+This discussion of UUCP security applies only to Unix. It is a bit
+cursory; suggestions for improvement are solicited.
+
+UUCP is traditionally not very secure. Taylor UUCP addresses some
+security issues, but is still far from being a secure system.
+
+If security is very important to you, then you should not permit any
+external access to your computer, including UUCP. Any opening to the
+outside world is a potential security risk.
+
+By default Taylor UUCP provides few mechanisms to secure local users of
+the system from each other. You can allow increased security by putting
+the owner of the UUCP programs (normally @code{uucp}) into a separate
+group; the use of this is explained in the following paragraphs, which
+refer to this separate group as @code{uucp-group}.
+
+When the @code{uucp} program is invoked to copy a file to a remote
+system, it will by default copy the file into the UUCP spool directory.
+When the @code{uux} program is used, the @samp{-C} switch must be used
+to copy the file into the UUCP spool directory. In any case, once the
+file has been copied into the spool directory, other local users will
+not be able to access it.
+
+When a file is requested from a remote system, UUCP will only permit it
+to be placed in a directory which is writable by the requesting user.
+The directory must also be writable by UUCP. A local user can create a
+directory with a group of @code{uucp-group} and set the mode to permit
+group write access. This will allow the file be requested without
+permitting it to be viewed by any other user.
+
+There is no provision for security for @code{uucp} requests (as opposed
+to @code{uux} requests) made by a user on a remote system. A file sent
+over by a remote request may only be placed in a directory which is
+world writable, and the file will be world readable and writable. This
+will permit any local user to destroy or replace the contents of the
+file. A file requested by a remote system must be world readable, and
+the directory it is in must be world readable. Any local user will be
+able to examine, although not necessarily modify, the file before it is
+sent.
+
+There are some security holes and race conditions that apply to the
+above discussion which I will not elaborate on. They are not hidden
+from anybody who reads the source code, but they are somewhat technical
+and difficult (though scarcely impossible) to exploit. Suffice it to
+say that even under the best of conditions UUCP is not completely
+secure.
+
+For many sites, security from remote sites is a more important
+consideration. Fortunately, Taylor UUCP does provide some support in
+this area.
+
+The greatest security is provided by always dialing out to the other
+site. This prevents anybody from pretending to be the other site. Of
+course, only one side of the connection can do this.
+
+If remote dialins must be permitted, then it is best if the dialin line
+is used only for UUCP. If this is the case, then you should create a
+call-in password file (@pxref{Configuration File Names}) and let
+@code{uucico} do its own login prompting. For example, to let remote
+sites log in on a port named @samp{entry} in the port file (@pxref{port
+File}) you might invoke @samp{uucico -p entry}. This would cause
+@code{uucico} to enter an endless loop of login prompts and daemon
+executions. The advantage of this approach is that even if remote users
+break into the system by guessing or learning the password, they will
+only be able to do whatever @code{uucico} permits them to do. They will
+not be able to start a shell on your system.
+
+If remote users can dial in and log on to your system, then you have a
+security hazard more serious than that posed by UUCP. But then, you
+probably knew that already.
+
+Once your system has connected with the remote UUCP, there is a fair
+amount of control you can exercise. You can use the @code{remote-send}
+and @code{remote-receive} commands to control the directories the remote
+UUCP can access. You can use the @code{request} command to prevent the
+remote UUCP from making any requests of your system at all; however, if
+you do this it will not even be able to send you mail or news. If you
+do permit remote requests, you should be careful to restrict what
+commands may be executed at the remote system's request. The default is
+@code{rmail} and @code{rnews}, which will suffice for most systems.
+
+If different remote systems call in and they must be granted different
+privileges (perhaps some systems are within the same organization and
+some are not) then the @code{called-login} command should be used for
+each system to require that they different login names. Otherwise it
+would be simple for a remote system to use the @code{myname} command and
+pretend to be a different system. The @code{sequence} command can be
+used to detect when one system pretended to be another, but since the
+sequence numbers must be reset manually after a failed handshake this
+can sometimes be more trouble than it's worth.
+
+@node Protocols, Hacking, Configuration Files, Top
+@chapter UUCP protocol internals
+
+A detailed description of how the various UUCP protocols work is posted
+monthly to the newsgroups @samp{comp.mail.uucp}, @samp{news.answers} and
+@samp{comp.answers}. There is no need to read this information in order
+to use Taylor UUCP. It is intended for people who are interested in how
+the UUCP code works.
+
+@node Hacking, Acknowledgements, Protocols, Top
+@chapter Hacking Taylor UUCP
+
+This chapter provides the briefest of guides to the Taylor UUCP source
+code itself.
+
+@menu
+* System Dependence:: System Dependence
+* Naming Conventions:: Naming Conventions
+* Patches:: Patches
+@end menu
+
+@node System Dependence, Naming Conventions, Hacking, Hacking
+@section System Dependence
+
+The code is carefully segregated into a system independent portion and a
+system dependent portion. The system dependent code is in the
+@file{unix} subdirectory, and also in the files @file{tcp.c},
+@file{tli.c} and @file{sysh.unx} (also known as @file{sysdep.h}).
+
+With the right configuration parameters, the system independent code
+calls only ANSI C functions. Some of the less common ANSI C functions
+are also provided in the @file{lib} directory. The replacement function
+@code{strtol} in @file{lib/strtol.c} assumes that the characters @kbd{A}
+to @kbd{F} and @kbd{a} to @kbd{f} appear in strictly sequential order.
+The function @code{igradecmp} in @file{uuconf/grdcmp.c} assumes that the
+upper and lower case letters appear in order. Both assumptions are true
+for ASCII and EBCDIC, but neither is guaranteed by ANSI C. Disregarding
+these caveats, I believe that the system independent portion of the code
+is strictly conforming.
+
+That's not too exciting, since all the work is done in the system
+dependent code. I think that this code can conform to POSIX 1003.1,
+given the right compilation parameters. I'm a bit less certain about
+this, though.
+
+The code is in use on a 16 bit segmented system with no function
+prototypes, so I'm certain that all casts to long and pointers are done
+when necessary.
+
+@node Naming Conventions, Patches, System Dependence, Hacking
+@section Naming Conventions
+
+I use a modified Hungarian naming convention for my variables and
+functions. As with all naming conventions, the code is rather opaque if
+you are not familiar with it, but becomes clear and easy to use with
+time.
+
+The first character indicates the type of the variable (or function
+return value). Sometimes additional characters are used. I use the
+following type prefixes:
+
+@table @samp
+@item a
+array; the next character is the type of an element
+@item b
+byte or character
+@item c
+count of something
+@item e
+stdio FILE *
+@item f
+boolean
+@item i
+generic integer
+@item l
+double
+@item o
+file descriptor (as returned by open, creat, etc.)
+@item p
+generic pointer
+@item q
+pointer to structure
+@item s
+structure
+@item u
+void (function return values only)
+@item z
+character string
+@end table
+
+A generic pointer (@code{p}) is sometimes a @code{void *}, sometimes a
+function pointer in which case the prefix is pf, and sometimes a pointer
+to another type, in which case the next character is the type to which
+it points (pf is overloaded).
+
+An array of strings (@code{char *[]}) would be named @code{az} (array of
+string). If this array were passed to a function, the function
+parameter would be named @code{paz} (pointer to array of string).
+
+Note that the variable name prefixes do not necessarily indicate the
+type of the variable. For example, a variable prefixed with i may be
+int, long or short. Similarly, a variable prefixed with b may be a char
+or an int; for example, the return value of getchar would be caught in
+an int variable prefixed with b.
+
+For a non-local variable (extern or file static), the first character
+after the type prefix is capitalized.
+
+Most static variables and functions use another letter after the type
+prefix to indicate which module they come from. This is to help
+distinguish different names in the debugger. For example, all static
+functions in @file{protg.c}, the @samp{g} protocol source code, use a
+module prefix of @samp{g}. This isn't too useful, as a number of
+modules use a module prefix of @samp{s}.
+
+@node Patches, , Naming Conventions, Hacking
+@section Patches
+
+I am always grateful for any patches sent in. Much of the flexibility
+and portability of the code is due to other people. Please do not
+hesitate to send me any changes you have found necessary or useful.
+
+When sending a patch, please send the output of the Unix @code{diff}
+program invoked with the @samp{-c} option (if you have the GNU version
+of @code{diff}, use the @samp{-p} option). Always invoke @code{diff}
+with the original file first and the modified file second.
+
+If your @code{diff} does not support @samp{-c} (or you don't have
+@code{diff}), send a complete copy of the modified file (if you have
+just changed a single function, you can just send the new version of the
+function). In particular, please do not send @code{diff} output without
+the @samp{-c} option, as it is useless.
+
+If you have made a number of changes, it is very convenient for me if
+you send each change as a separate mail message. Sometimes I will think
+that one change is useful but another one is not. If they are in
+different messages it is much easier for me to apply one but not the
+other.
+
+I rarely apply the patches directly. Instead I work my way through the
+hunks and apply each one separately. This ensures that the naming
+remains consistent, and that I understand all the code.
+
+If you can not follow all these rules, then don't. But if you do, it
+makes it more likely that I will incorporate your changes. I am not
+paid for my UUCP work, and my available time is unfortunately very
+restricted. The package is important to me, and I do what I can, but I
+can not do all that I would like, much less all that everybody else
+would like.
+
+Finally, please do not be offended if I do not reply to messages for
+some time, even a few weeks. I am often behind on my mail, and if I
+think your message deserves a considered reply I will often put it aside
+until I have time to deal with it.
+
+@node Acknowledgements, Index (concepts), Hacking, Top
+@chapter Acknowledgements
+
+This is a list of people who gave help or suggestions while I was
+working on the Taylor UUCP project. Appearance on this list does not
+constitute endorsement of the program, particularly since some of the
+comments were criticisms. I've probably left some people off, and I
+apologize for any oversight; it does not mean your contribution was
+unappreciated.
+
+@ifinfo
+First of all, I would like to thank the people at Infinity Development
+Systems (formerly AIRS, which lives on in the domain name, at least for
+now) for permitting me to use their computers and @file{uunet} access.
+I would also like to thank Richard Stallman @code{<rms@@gnu.ai.mit.edu>}
+for founding the Free Software Foundation and John Gilmore
+@code{<gnu@@cygnus.com>} for writing the initial version of gnuucp which
+was a direct inspiration for this somewhat larger project. Chip
+Salzenberg @code{<chip@@tct.com>} has contributed many patches.
+Franc,ois Pinard @code{<pinard@@iro.umontreal.ca>} tirelessly tested the
+code and suggested many improvements. He also put together the initial
+version of this document. Doug Evans contributed the zmodem protocol.
+Marc Boucher @code{<marc@@CAM.ORG>} contributed the code supporting the
+pipe port type. Finally, Verbus M. Counts @code{<verbus@@westmark.com>}
+and Centel Federal Systems, Inc. deserve special thanks, since they
+actually paid me money to port this code to System III.
+@end ifinfo
+@iftex
+First of all, I would like to thank the people at Infinity Development
+Systems (formerly AIRS, which lives on in the domain name, at least for
+now) for permitting me to use their computers and @file{uunet} access.
+I would also like to thank Richard Stallman @code{<rms@@gnu.ai.mit.edu>}
+for founding the Free Software Foundation and John Gilmore
+@code{<gnu@@cygnus.com>} for writing the initial version of gnuucp which
+was a direct inspiration for this somewhat larger project. Chip
+Salzenberg @code{<chip@@tct.com>} has contributed many patches.
+@tex
+Fran\c cois Pinard
+@end tex
+@code{<pinard@@iro.umontreal.ca>} tirelessly tested the code and
+suggested many improvements. He also put together the initial version
+of this document. Doug Evans contributed the zmodem protocol. Marc
+Boucher @code{<marc@@CAM.ORG>} contributed the code supporting the pipe
+port type. Finally, Verbus M. Counts @code{<verbus@@westmark.com>} and
+Centel Federal Systems, Inc. deserve special thanks, since they actually
+paid me money to port this code to System III.
+@end iftex
+
+In alphabetical order:
+
+@example
+"Earle F. Ake - SAIC" @code{<ake@@Dayton.SAIC.COM>}
+@code{mra@@searchtech.com} (Michael Almond)
+@code{cambler@@zeus.calpoly.edu} (Christopher J. Ambler)
+Brian W. Antoine @code{<briana@@tau-ceti.isc-br.com>}
+@code{jantypas@@soft21.s21.com} (John Antypas)
+@code{james@@bigtex.cactus.org} (James Van Artsdalen)
+@code{nba@@sysware.DK} (Niels Baggesen)
+@code{uunet!hotmomma!sdb} (Scott Ballantyne)
+Zacharias Beckman @code{<zac@@dolphin.com>}
+@code{mike@@mbsun.ann-arbor.mi.us} (Mike Bernson)
+@code{bob@@usixth.sublink.org} (Roberto Biancardi)
+@code{statsci!scott@@coco.ms.washington.edu} (Scott Blachowicz)
+@code{bag%wood2.cs.kiev.ua@@relay.ussr.eu.net} (Andrey G Blochintsev)
+@code{spider@@Orb.Nashua.NH.US} (Spider Boardman)
+Gregory Bond @code{<gnb@@bby.com.au>}
+Marc Boucher @code{<marc@@CAM.ORG>}
+@code{dean@@coplex.com} (Dean Brooks)
+@code{jbrow@@radical.com} (Jim Brownfield)
+@code{dave@@dlb.com} (Dave Buck)
+@code{gordon@@sneaky.lonestar.org} (Gordon Burditt)
+@code{dburr@@sbphy.physics.ucsb.edu} (Donald Burr)
+@code{mib@@gnu.ai.mit.edu} (Michael I Bushnell)
+Brian Campbell @code{<brianc@@quantum.on.ca>}
+Andrew A. Chernov @code{<ache@@astral.msk.su>}
+@code{mafc!frank@@bach.helios.de} (Frank Conrad)
+Ed Carp @code{<erc@@apple.com>}
+@code{mpc@@mbs.linet.org} (Mark Clements)
+@code{verbus@@westmark.westmark.com} (Verbus M. Counts)
+@code{cbmvax!snark.thyrsus.com!cowan} (John Cowan)
+Bob Cunningham @code{<bob@@soest.hawaii.edu>}
+@code{kdburg@@incoahe.hanse.de} (Klaus Dahlenburg)
+Damon @code{<d@@exnet.co.uk>}
+@code{hubert@@arakis.fdn.org} (Hubert Delahaye)
+@code{markd@@bushwire.apana.org.au} (Mark Delany)
+Allen Delaney @code{<allen@@brc.ubc.ca>}
+@code{denny@@dakota.alisa.com} (Bob Denny)
+@code{ssd@@nevets.oau.org} (Steven S. Dick)
+@code{gert@@greenie.gold.sub.org} (Gert Doering)
+@code{gemini@@geminix.in-berlin.de} (Uwe Doering)
+Hans-Dieter Doll @code{<hd2@@Insel.DE>}
+Mark W. Eichin @code{<eichin@@cygnus.com>}
+Andrew Evans @code{<andrew@@airs.com>}
+@code{dje@@cygnus.com} (Doug Evans)
+Marc Evans @code{<marc@@synergytics.com>}
+Dan Everhart @code{<dan@@dyndata.com>}
+@code{kksys!kegworks!lfahnoe@@cs.umn.edu} (Larry Fahnoe)
+@code{fenner@@jazz.psu.edu} (Bill Fenner)
+@code{jaf@@inference.com} (Jose A. Fernandez)
+"David J. Fiander" @code{<golem!david@@news.lsuc.on.ca>}
+Thomas Fischer @code{<batman@@olorin.dark.sub.org>}
+@code{louis@@marco.de} (Ju"rgen Fluk)
+@code{erik@@eab.retix.com} (Erik Forsberg)
+@code{andy@@scp.caltech.edu} (Andy Fyfe)
+Lele Gaifax @code{<piggy@@idea.sublink.org>}
+@code{Peter.Galbavy@@micromuse.co.uk}
+@code{hunter@@phoenix.pub.uu.oz.au} (James Gardiner [hunter])
+Terry Gardner @code{<cphpcom!tjg01>}
+@code{ol@@infopro.spb.su} (Oleg Girko)
+@code{jimmy@@tokyo07.info.com} (Jim Gottlieb)
+Benoit Grange @code{<ben@@fizz.fdn.org>}
+@code{elg@@elgamy.jpunix.com} (Eric Lee Green)
+@code{ryan@@cs.umb.edu} (Daniel R. Guilderson)
+@code{greg@@gagme.chi.il.us} (Gregory Gulik)
+Richard H. Gumpertz @code{<rhg@@cps.com>}
+Michael Haberler @code{<mah@@parrot.prv.univie.ac.at>}
+Daniel Hagerty @code{<hag@@eddie.mit.edu>}
+@code{jh@@moon.nbn.com} (John Harkin)
+@code{guy@@auspex.auspex.com} (Guy Harris)
+Petri Helenius @code{<pete@@fidata.fi>}
+@code{gabe@@edi.com} (B. Gabriel Helou)
+Bob Hemedinger @code{<bob@@dalek.mwc.com>}
+Andrew Herbert @code{<andrew@@werple.pub.uu.oz.au>}
+Peter Honeyman @code{<honey@@citi.umich.edu>}
+@code{jhood@@smoke.marlboro.vt.us} (John Hood)
+Bill Irwin @code{<bill@@twg.bc.ca>}
+@code{pmcgw!personal-media.co.jp!ishikawa} (Chiaki Ishikawa)
+@code{bei@@dogface.austin.tx.us} (Bob Izenberg)
+@code{djamiga!djjames@@fsd.com} (D.J.James)
+Rob Janssen @code{<cmgit!rob@@relay.nluug.nl>}
+@code{harvee!esj} (Eric S Johansson)
+Kevin Johnson @code{<kjj@@pondscum.phx.mcd.mot.com>}
+Alan Judge @code{<aj@@dec4ie.IEunet.ie>}
+@code{chris@@cj_net.in-berlin.de} (Christof Junge)
+@code{tron@@Veritas.COM} (Ronald S. Karr)
+Brendan Kehoe @code{<brendan@@cs.widener.edu>}
+@code{warlock@@csuchico.edu} (John Kennedy)
+@code{kersing@@nlmug.nl.mugnet.org} (Jac Kersing)
+Gabor Kiss @code{<kissg@@sztaki.hu>}
+@code{gero@@gkminix.han.de} (Gero Kuhlmann)
+@code{rob@@pact.nl} (Rob Kurver)
+@code{kent@@sparky.IMD.Sterling.COM} (Kent Landfield)
+@code{lebaron@@inrs-telecom.uquebec.ca} (Gregory LeBaron)
+@code{karl@@sugar.NeoSoft.Com} (Karl Lehenbauer)
+@code{alex@@hal.rhein-main.de} (Alexander Lehmann)
+@code{merlyn@@digibd.com} (Merlyn LeRoy)
+@code{clewis@@ferret.ocunix.on.ca} (Chris Lewis)
+@code{gdonl@@ssi1.com} (Don Lewis)
+@code{libove@@libove.det.dec.com} (Jay Vassos-Libove)
+@code{bruce%blilly@@Broadcast.Sony.COM} (Bruce Lilly)
+Ted Lindgreen @code{<tlindgreen@@encore.nl>}
+@code{andrew@@cubetech.com} (Andrew Loewenstern)
+"Arne Ludwig" @code{<arne@@rrzbu.hanse.de>}
+Matthew Lyle @code{<matt@@mips.mitek.com>}
+@code{djm@@eng.umd.edu} (David J. MacKenzie)
+John R MacMillan @code{<chance!john@@sq.sq.com>}
+Giles D Malet @code{<shrdlu!gdm@@provar.kwnet.on.ca>}
+@code{mem@@mv.MV.COM} (Mark E. Mallett)
+@code{pepe@@dit.upm.es} (Jose A. Manas)
+@code{peter@@xpoint.ruessel.sub.org} (Peter Mandrella)
+@code{martelli@@cadlab.sublink.org} (Alex Martelli)
+W Christopher Martin @code{<wcm@@geek.ca.geac.com>}
+Yanek Martinson @code{<yanek@@mthvax.cs.miami.edu>}
+@code{jm@@aristote.univ-paris8.fr} (Jean Mehat)
+@code{me@@halfab.freiburg.sub.org} (Udo Meyer)
+@code{les@@chinet.chi.il.us} (Leslie Mikesell)
+@code{mmitchel@@digi.lonestar.org} (Mitch Mitchell)
+Emmanuel Mogenet @code{<mgix@@krainte.jpn.thomson-di.fr>}
+@code{rmohr@@infoac.rmi.de} (Rupert Mohr)
+Jason Molenda @code{<molenda@@sequent.com>}
+@code{ianm@@icsbelf.co.uk} (Ian Moran)
+@code{brian@@ilinx.wimsey.bc.ca} (Brian J. Murrell)
+@code{service@@infohh.rmi.de} (Dirk Musstopf)
+@code{lyndon@@cs.athabascau.ca} (Lyndon Nerenberg)
+@code{rolf@@saans.north.de} (Rolf Nerstheimer)
+@code{tom@@smart.bo.open.de} (Thomas Neumann)
+@code{mnichols@@pacesetter.com}
+Richard E. Nickle @code{<trystro!rick@@Think.COM>}
+@code{stephan@@sunlab.ka.sub.org} (Stephan Niemz)
+@code{nolan@@helios.unl.edu} (Michael Nolan)
+david nugent @code{<david@@csource.oz.au>}
+Jim O'Connor @code{<jim@@bahamut.fsc.com>}
+Petri Ojala @code{<ojala@@funet.fi>}
+@code{oneill@@cs.ulowell.edu} (Brian 'Doc' O'Neill)
+@code{abekas!dragoman!mikep@@decwrl.dec.com} (Mike Park)
+Tim Peiffer @code{peiffer@@cs.umn.edu}
+@code{don@@blkhole.resun.com} (Don Phillips)
+"Mark Pizzolato 415-369-9366" @code{<mark@@infocomm.com>}
+John Plate @code{<plate@@infotek.dk>}
+@code{dplatt@@ntg.com} (Dave Platt)
+@code{eldorado@@tharr.UUCP} (Mark Powell)
+Mark Powell @code{<mark@@inet-uk.co.uk>}
+@code{pozar@@kumr.lns.com} (Tim Pozar)
+@code{putsch@@uicc.com} (Jeff Putsch)
+@code{ar@@nvmr.robin.de} (Andreas Raab)
+Jarmo Raiha @code{<jarmo@@ksvltd.FI>}
+Scott Reynolds @code{<scott@@clmqt.marquette.Mi.US>}
+@code{mcr@@Sandelman.OCUnix.On.Ca} (Michael Richardson)
+Kenji Rikitake @code{<kenji@@rcac.astem.or.jp>}
+@code{arnold@@cc.gatech.edu} (Arnold Robbins)
+@code{steve@@Nyongwa.cam.org} (Steve M. Robbins)
+Serge Robyns @code{<sr@@denkart.be>}
+Lawrence E. Rosenman @code{<ler@@lerami.lerctr.org>}
+Jeff Ross @code{<jeff@@wisdom.bubble.org>}
+Aleksey P. Rudnev @code{<alex@@kiae.su>}
+"Heiko W.Rupp" @code{<hwr@@pilhuhn.ka.sub.org>}
+@code{wolfgang@@wsrcc.com} (Wolfgang S. Rupprecht)
+@code{tbr@@tfic.bc.ca} (Tom Rushworth)
+@code{jsacco@@ssl.com} (Joseph E. Sacco)
+@code{rsalz@@bbn.com} (Rich Salz)
+@code{sojurn!mike@@hobbes.cert.sei.cmu.edu} (Mike Sangrey)
+Nickolay Saukh @code{<nms@@ussr.EU.net>}
+@code{heiko@@lotte.sax.de} (Heiko Schlittermann)
+Eric Schnoebelen @code{<eric@@cirr.com>}
+@code{russell@@alpha3.ersys.edmonton.ab.ca} (Russell Schulz)
+@code{scott@@geom.umn.edu}
+Igor V. Semenyuk @code{<iga@@argrd0.argonaut.su>}
+Christopher Sawtell @code{<chris@@gerty.equinox.gen.nz>}
+@code{schuler@@bds.sub.org} (Bernd Schuler)
+@code{uunet!gold.sub.org!root} (Christian Seyb)
+@code{s4mjs!mjs@@nirvo.nirvonics.com} (M. J. Shannon Jr.)
+@code{peter@@ficc.ferranti.com} (Peter da Silva)
+@code{vince@@victrola.sea.wa.us} (Vince Skahan)
+@code{frumious!pat} (Patrick Smith)
+@code{roscom!monty@@bu.edu} (Monty Solomon)
+@code{sommerfeld@@orchard.medford.ma.us} (Bill Sommerfeld)
+Julian Stacey @code{<stacey@@guug.de>}
+Harlan Stenn @code{<harlan@@mumps.pfcs.com>}
+Ralf Stephan @code{<ralf@@ark.abg.sub.org>}
+@code{johannes@@titan.westfalen.de} (Johannes Stille)
+@code{chs@@antic.apu.fi} (Hannu Strang)
+@code{ralf@@reswi.ruhr.de} (Ralf E. Stranzenbach)
+@code{sullivan@@Mathcom.com} (S. Sullivan)
+Shigeya Suzuki @code{<shigeya@@dink.foretune.co.jp>}
+@code{swiers@@plains.NoDak.edu}
+Oleg Tabarovsky @code{<olg@@olghome.pccentre.msk.su>}
+John Theus @code{<john@@theus.rain.com>}
+@code{rd@@aii.com} (Bob Thrush)
+ppKarsten Thygesen @code{<karthy@@dannug.dk>}
+Graham Toal @code{<gtoal@@pizzabox.demon.co.uk>}
+@code{rmtodd@@servalan.servalan.com} (Richard Todd)
+Martin Tomes @code{<mt00@@controls.eurotherm.co.uk>}
+Len Tower @code{<tower-prep@@ai.mit.edu>}
+Mark Towfiq @code{<justice!towfiq@@Eingedi.Newton.MA.US>}
+@code{mju@@mudos.ann-arbor.mi.us} (Marc Unangst)
+Tomi Vainio @code{<tomppa@@fidata.fi>}
+Andrew Vignaux @code{<ajv@@ferrari.datamark.co.nz>}
+@code{vogel@@omega.ssw.de} (Andreas Vogel)
+@code{jos@@bull.nl} (Jos Vos)
+@code{jv@@nl.net} (Johan Vromans)
+David Vrona @code{<dave@@sashimi.wwa.com>}
+@code{Marcel.Waldvogel@@nice.usergroup.ethz.ch} (Marcel Waldvogel)
+@code{steve@@nshore.org} (Stephen J. Walick)
+@code{syd@@dsinc.dsi.com} (Syd Weinstein)
+@code{gerben@@rna.indiv.nluug.nl} (Gerben Wierda)
+@code{jbw@@cs.bu.edu} (Joe Wells)
+@code{frnkmth!twwells.com!bill} (T. William Wells)
+Peter Wemm @code{<Peter_Wemm@@zeus.dialix.oz.au>}
+@code{mauxci!eci386!woods@@apple.com} (Greg A. Woods)
+Michael Yu.Yaroslavtsev @code{<mike@@yaranga.ipmce.su>}
+Alexei K. Yushin @code{<root@@july.elis.crimea.ua>}
+@code{jon@@console.ais.org} (Jon Zeeff)
+Matthias Zepf @code{<agnus@@amylnd.stgt.sub.org>}
+Eric Ziegast @code{<uunet!ziegast>}
+@end example
+
+@node Index (concepts), Index (configuration file), Acknowledgements, Top
+@unnumbered Concept Index
+
+@printindex cp
+
+@node Index (configuration file), , Index (concepts), Top
+@unnumbered Configuration File Index
+
+@printindex fn
+
+@contents
+@bye
diff --git a/gnu/libexec/uucp/libunix/MANIFEST b/gnu/libexec/uucp/libunix/MANIFEST
index d64e79922046..c57f466fc988 100644
--- a/gnu/libexec/uucp/libunix/MANIFEST
+++ b/gnu/libexec/uucp/libunix/MANIFEST
@@ -8,8 +8,9 @@ basnam.c
bytfre.c
chmod.c
cohtty.c
-cwd.c
+corrup.c
cusub.c
+cwd.c
detach.c
dirent.c
dup2.c
@@ -40,7 +41,9 @@ move.c
opensr.c
pause.c
picksb.c
+pipe.c
portnm.c
+priv.c
proctm.c
recep.c
remove.c
diff --git a/gnu/libexec/uucp/libunix/Makefile b/gnu/libexec/uucp/libunix/Makefile
index 3a6750b17164..103c99d62e8b 100644
--- a/gnu/libexec/uucp/libunix/Makefile
+++ b/gnu/libexec/uucp/libunix/Makefile
@@ -1,16 +1,17 @@
# This subdirectory contains Unix specific support functions.
-# $Id: Makefile,v 1.1 1993/08/05 18:23:34 conklin Exp $
+# $Id: Makefile,v 1.2 1994/05/07 18:10:03 ache Exp $
LIB= unix
-SRCS= access.c addbas.c app3.c app4.c basnam.c bytfre.c cwd.c \
- chmod.c cohtty.c cusub.c detach.c efopen.c epopen.c exists.c \
- filnam.c fsusg.c indir.c init.c isdir.c isfork.c iswait.c \
- jobid.c lcksys.c link.c locfil.c lock.c loctim.c mail.c \
- mkdirs.c mode.c move.c opensr.c pause.c picksb.c portnm.c \
- proctm.c recep.c run.c seq.c serial.c signal.c sindir.c size.c \
- sleep.c spawn.c splcmd.c splnam.c spool.c srmdir.c statsb.c \
- status.c time.c tmpfil.c trunc.c uacces.c ufopen.c ultspl.c \
- unknwn.c uuto.c walk.c wldcrd.c work.c xqtfil.c xqtsub.c ftw.c
+SRCS = access.c addbas.c app3.c app4.c basnam.c bytfre.c corrup.c \
+ chmod.c cohtty.c cusub.c cwd.c detach.c efopen.c epopen.c \
+ exists.c filnam.c fsusg.c indir.c init.c isdir.c isfork.c \
+ iswait.c jobid.c lcksys.c link.c locfil.c lock.c loctim.c \
+ mail.c mkdirs.c mode.c move.c opensr.c pause.c picksb.c pipe.c \
+ portnm.c priv.c proctm.c recep.c run.c seq.c serial.c signal.c \
+ sindir.c size.c sleep.c spawn.c splcmd.c splnam.c spool.c \
+ srmdir.c statsb.c status.c time.c tmpfil.c trunc.c uacces.c \
+ ufopen.c ultspl.c unknwn.c uuto.c walk.c wldcrd.c work.c \
+ xqtfil.c xqtsub.c ftw.c
CFLAGS+= -I$(.CURDIR)/../common_sources \
-DOWNER=\"$(owner)\" -DSBINDIR=\"$(sbindir)\"
diff --git a/gnu/libexec/uucp/libunix/app3.c b/gnu/libexec/uucp/libunix/app3.c
index 5c0b58938515..f3c3555a363d 100644
--- a/gnu/libexec/uucp/libunix/app3.c
+++ b/gnu/libexec/uucp/libunix/app3.c
@@ -19,7 +19,10 @@ zsappend3 (zdir1, zdir2, zfile)
cdir2 = strlen (zdir2);
cfile = strlen (zfile);
zret = zbufalc (cdir1 + cdir2 + cfile + 3);
- memcpy (zret, zdir1, cdir1);
+ if (cdir1 == 1 && *zdir1 == '/')
+ cdir1 = 0;
+ else
+ memcpy (zret, zdir1, cdir1);
memcpy (zret + cdir1 + 1, zdir2, cdir2);
memcpy (zret + cdir1 + cdir2 + 2, zfile, cfile);
zret[cdir1] = '/';
diff --git a/gnu/libexec/uucp/libunix/app4.c b/gnu/libexec/uucp/libunix/app4.c
index a3b3787f68fd..d3a243fd7285 100644
--- a/gnu/libexec/uucp/libunix/app4.c
+++ b/gnu/libexec/uucp/libunix/app4.c
@@ -21,7 +21,10 @@ zsappend4 (zdir1, zdir2, zdir3, zfile)
cdir3 = strlen (zdir3);
cfile = strlen (zfile);
zret = zbufalc (cdir1 + cdir2 + cdir3 + cfile + 4);
- memcpy (zret, zdir1, cdir1);
+ if (cdir1 == 1 && *zdir1 == '/')
+ cdir1 = 0;
+ else
+ memcpy (zret, zdir1, cdir1);
memcpy (zret + cdir1 + 1, zdir2, cdir2);
memcpy (zret + cdir1 + cdir2 + 2, zdir3, cdir3);
memcpy (zret + cdir1 + cdir2 + cdir3 + 3, zfile, cfile);
diff --git a/gnu/libexec/uucp/libunix/cohtty.c b/gnu/libexec/uucp/libunix/cohtty.c
index a7aec1cae338..5a52df91e57c 100644
--- a/gnu/libexec/uucp/libunix/cohtty.c
+++ b/gnu/libexec/uucp/libunix/cohtty.c
@@ -37,6 +37,19 @@
* reset the serial device to see if the device needs to be re-enabled.
*/
+/* May 10, 1993: This function will always return true for the following
+ * reasons:
+ * 1) lock files have already been dealt with
+ * 2) if someone else already has the port open, uucico should fail anyways
+ * 3) Coherent's disable command return can return '0' or '1', but will
+ * succeed in any event.
+ * 4) It doesn't matter if there is a ttys entry for the port in question.
+ * /etc/ttys generally only lists devices that MAY be enabled for logins.
+ * If a device will never be used for logins, then there may not be a
+ * ttys entry, in which case, disable won't be called anyways.
+ * ---bob@mwc.com
+ */
+
boolean
fscoherent_disable_tty (zdevice, pzenable)
const char *zdevice;
@@ -130,14 +143,14 @@ char enable_device[16]; /* this will hold our device name
+ strlen (enable_device));
sprintf(*pzenable,"/dev/%s", enable_device);
/* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */
- return(x==0? TRUE : FALSE); /* disable either failed
- or succeded */
+ return TRUE;
}else{
- return FALSE; /* device in tty entry not enabled */
+ /* device not enabled */
+ return TRUE;
}
}
}
- return FALSE; /* no ttys entry found */
+ return TRUE; /* no ttys entry found */
}
/* The following is COHERENT 4.0 specific. It is used to test for any
diff --git a/gnu/libexec/uucp/libunix/corrup.c b/gnu/libexec/uucp/libunix/corrup.c
new file mode 100644
index 000000000000..87f19e668894
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/corrup.c
@@ -0,0 +1,33 @@
+/* corrup.c
+ Save a file in the .Corrupt directory. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "uudefs.h"
+#include "system.h"
+
+char *
+zsysdep_save_corrupt_file (zfile)
+ const char *zfile;
+{
+ const char *zslash;
+ char *zto;
+
+ zslash = strrchr (zfile, '/');
+ if (zslash == NULL)
+ zslash = zfile;
+ else
+ ++zslash;
+
+ zto = zsappend3 (zSspooldir, CORRUPTDIR, zslash);
+
+ if (! fsysdep_move_file (zfile, zto, TRUE, FALSE, FALSE,
+ (const char *) NULL))
+ {
+ ubuffree (zto);
+ return NULL;
+ }
+
+ return zto;
+}
diff --git a/gnu/libexec/uucp/libunix/cusub.c b/gnu/libexec/uucp/libunix/cusub.c
index d1110fd5c7b4..6505a07ac639 100644
--- a/gnu/libexec/uucp/libunix/cusub.c
+++ b/gnu/libexec/uucp/libunix/cusub.c
@@ -1,7 +1,7 @@
/* cusub.c
System dependent routines for cu.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/05 18:23:44 conklin Exp $";
+const char cusub_rcsid[] = "$Id: cusub.c,v 1.2 1994/05/07 18:10:14 ache Exp $";
#endif
#include "uudefs.h"
@@ -37,8 +37,40 @@ const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/05 18:23:44 conklin Exp $
#include "conn.h"
#include "prot.h"
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* Get definitions for both O_NONBLOCK and O_NDELAY. */
+#ifndef O_NDELAY
+#ifdef FNDELAY
+#define O_NDELAY FNDELAY
+#else /* ! defined (FNDELAY) */
+#define O_NDELAY 0
+#endif /* ! defined (FNDELAY) */
+#endif /* ! defined (O_NDELAY) */
+
+#ifndef O_NONBLOCK
+#ifdef FNBLOCK
+#define O_NONBLOCK FNBLOCK
+#else /* ! defined (FNBLOCK) */
+#define O_NONBLOCK 0
+#endif /* ! defined (FNBLOCK) */
+#endif /* ! defined (O_NONBLOCK) */
+
#include <errno.h>
+/* 4.2 systems don't define SIGUSR2. This should work for them. On
+ systems which are missing SIGUSR1, or SIGURG, you must find two
+ signals which you can safely use. */
+#ifndef SIGUSR2
+#define SIGUSR2 SIGURG
+#endif
+
/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
#ifndef EAGAIN
#ifndef EWOULDBLOCK
@@ -69,6 +101,7 @@ static char bStstp;
static const char *zsport_line P((const struct uuconf_port *qport));
static void uscu_child P((struct sconnection *qconn, int opipe));
+static RETSIGTYPE uscu_child_handler P((int isig));
static RETSIGTYPE uscu_alarm P((int isig));
static int cscu_escape P((char *pbcmd, const char *zlocalname));
static RETSIGTYPE uscu_alarm_kill P((int isig));
@@ -97,6 +130,7 @@ zsport_line (qport)
break;
case UUCONF_PORTTYPE_TCP:
case UUCONF_PORTTYPE_TLI:
+ case UUCONF_PORTTYPE_PIPE:
return NULL;
}
@@ -556,7 +590,9 @@ uscu_child (qconn, opipe)
CATCH_PROTECT int cwrite;
CATCH_PROTECT char abbuf[1024];
- /* It would be nice if we could just use fsserial_read, but that
+ fgot = FALSE;
+
+ /* It would be nice if we could just use fsysdep_conn_read, but that
will log signals that we don't want logged. There should be a
generic way to extract the file descriptor from the port. */
if (qconn->qport == NULL)
@@ -571,8 +607,12 @@ uscu_child (qconn, opipe)
oport = -1;
break;
#endif
+ case UUCONF_PORTTYPE_PIPE:
+ /* A read of 0 on a pipe always means EOF (see below). */
+ fgot = TRUE;
+ /* Fall through. */
case UUCONF_PORTTYPE_STDIN:
- oport = 0;
+ oport = ((struct ssysdep_conn *) qconn->psysdep)->ord;
break;
case UUCONF_PORTTYPE_MODEM:
case UUCONF_PORTTYPE_DIRECT:
@@ -583,6 +623,10 @@ uscu_child (qconn, opipe)
}
}
+ /* Force the descriptor into blocking mode. */
+ (void) fcntl (oport, F_SETFL,
+ fcntl (oport, F_GETFL, 0) &~ (O_NDELAY | O_NONBLOCK));
+
usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL);
usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL);
usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL);
@@ -591,7 +635,6 @@ uscu_child (qconn, opipe)
usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL);
fstopped = FALSE;
- fgot = FALSE;
iSchild_sig = 0;
cwrite = 0;
@@ -792,7 +835,7 @@ fsysdep_terminal_raw (flocalecho)
sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
else
sSterm_new.c_lflag &=~ (ICANON | ISIG);
- sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
sSterm_new.c_oflag &=~ (OPOST);
sSterm_new.c_cc[VMIN] = 1;
sSterm_new.c_cc[VTIME] = 0;
@@ -808,7 +851,7 @@ fsysdep_terminal_raw (flocalecho)
(ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
else
sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG);
- sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL | IXON | IXOFF);
sSterm_new.c_oflag &=~ (OPOST);
sSterm_new.c_cc[VMIN] = 1;
sSterm_new.c_cc[VTIME] = 0;
@@ -1094,8 +1137,9 @@ fsysdep_shell (qconn, zcmd, tcmd)
oread = owrite = -1;
break;
case UUCONF_PORTTYPE_STDIN:
- oread = 0;
- owrite = 1;
+ case UUCONF_PORTTYPE_PIPE:
+ oread = ((struct ssysdep_conn *) qconn->psysdep)->ord;
+ owrite = ((struct ssysdep_conn *) qconn->psysdep)->owr;
break;
case UUCONF_PORTTYPE_MODEM:
case UUCONF_PORTTYPE_DIRECT:
diff --git a/gnu/libexec/uucp/libunix/cwd.c b/gnu/libexec/uucp/libunix/cwd.c
index 433025db6c3a..71d05d11f545 100644
--- a/gnu/libexec/uucp/libunix/cwd.c
+++ b/gnu/libexec/uucp/libunix/cwd.c
@@ -24,14 +24,17 @@ fsysdep_needs_cwd (zfile)
consistent with other UUCP packages. */
char *
-zsysdep_local_file_cwd (zfile, zpubdir)
+zsysdep_local_file_cwd (zfile, zpubdir, pfbadname)
const char *zfile;
const char *zpubdir;
+ boolean *pfbadname;
{
+ if (pfbadname != NULL)
+ *pfbadname = FALSE;
if (*zfile == '/')
return zbufcpy (zfile);
else if (*zfile == '~')
- return zsysdep_local_file (zfile, zpubdir);
+ return zsysdep_local_file (zfile, zpubdir, pfbadname);
else
return zsysdep_add_cwd (zfile);
}
diff --git a/gnu/libexec/uucp/libunix/detach.c b/gnu/libexec/uucp/libunix/detach.c
index 73144da001d4..9b505af499cc 100644
--- a/gnu/libexec/uucp/libunix/detach.c
+++ b/gnu/libexec/uucp/libunix/detach.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -100,11 +100,15 @@ usysdep_detach ()
while (getppid () != 1)
sleep (1);
- ulog_id (getpid ());
+ ipid = getpid ();
+ ulog_id (ipid);
/* Restore SIGHUP catcher if it wasn't being ignored. */
if (! fignored)
usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+
+ DEBUG_MESSAGE2 (DEBUG_PORT, "Forked; old PID %ld, new pid %ld",
+ (long) igrp, (long) ipid);
}
#if ! HAVE_SETSID && HAVE_TIOCNOTTY
@@ -146,7 +150,7 @@ usysdep_detach ()
setpgrp (0, 0) will set our process group to 0 so that we can
acquire a new controlling terminal (TIOCNOTTY may or may not have
already done that anyhow). */
-#if HAVE_BSD_SETPGRP
+#if HAVE_BSD_PGRP
if (setpgrp (0, 0) < 0)
#else
if (setpgrp () < 0)
diff --git a/gnu/libexec/uucp/libunix/dirent.c b/gnu/libexec/uucp/libunix/dirent.c
index 83db496cabbd..c7e467ec1b1a 100644
--- a/gnu/libexec/uucp/libunix/dirent.c
+++ b/gnu/libexec/uucp/libunix/dirent.c
@@ -21,7 +21,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/dup2.c b/gnu/libexec/uucp/libunix/dup2.c
index 6a7359fe92e8..d1454205125b 100644
--- a/gnu/libexec/uucp/libunix/dup2.c
+++ b/gnu/libexec/uucp/libunix/dup2.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/epopen.c b/gnu/libexec/uucp/libunix/epopen.c
index dec1b3999d64..8c1f5cd0d854 100644
--- a/gnu/libexec/uucp/libunix/epopen.c
+++ b/gnu/libexec/uucp/libunix/epopen.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -56,7 +56,7 @@ espopen (pazargs, frd, pipid)
}
aidescs[2] = SPAWN_NULL;
- ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE,
+ ipid = ixsspawn (pazargs, aidescs, TRUE, FALSE,
(const char *) NULL, FALSE, TRUE,
(const char *) NULL, (const char *) NULL,
(const char *) NULL);
diff --git a/gnu/libexec/uucp/libunix/filnam.c b/gnu/libexec/uucp/libunix/filnam.c
index 62054767b89a..0b234c06dcca 100644
--- a/gnu/libexec/uucp/libunix/filnam.c
+++ b/gnu/libexec/uucp/libunix/filnam.c
@@ -1,7 +1,7 @@
/* filnam.c
Get names to use for UUCP files.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -62,7 +62,7 @@ extern off_t lseek ();
#endif
#define ZCHARS \
- "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
/* Local functions. */
diff --git a/gnu/libexec/uucp/libunix/fsusg.c b/gnu/libexec/uucp/libunix/fsusg.c
index e2b40a8ad5a5..116ab88fc187 100644
--- a/gnu/libexec/uucp/libunix/fsusg.c
+++ b/gnu/libexec/uucp/libunix/fsusg.c
@@ -1,5 +1,5 @@
/* fsusage.c -- return space usage of mounted filesystems
- Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1992, 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
@@ -19,11 +19,10 @@
for use with Taylor UUCP. */
#include "uucp.h"
+#include "uudefs.h"
#include "sysdep.h"
#include "fsusg.h"
-int statfs ();
-
#if STAT_STATFS2_BSIZE
#ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */
#include <sys/vfs.h>
@@ -52,16 +51,19 @@ int statfs ();
#endif
#endif
-#ifdef _AIX
-#ifdef _I386 /* AIX PS/2. */
+#if STAT_DUSTAT /* AIX PS/2. */
#include <sys/stat.h>
#include <sys/dustat.h>
#endif
-#endif
#if STAT_STATVFS /* SVR4. */
#include <sys/statvfs.h>
-int statvfs ();
+#endif
+
+#if STAT_DISK_SPACE /* QNX. */
+#include <sys/disk.h>
+#include <fcntl.h>
+#include <errno.h>
#endif
#define STAT_NONE 0
@@ -71,7 +73,9 @@ int statvfs ();
#if ! STAT_STATFS2_FSIZE
#if ! STAT_STATFS2_FS_DATA
#if ! STAT_STATFS4
+#if ! STAT_DUSTAT
#if ! STAT_USTAT
+#if ! STAT_DISK_SPACE
#undef STAT_NONE
#define STAT_NONE 1
#endif
@@ -80,9 +84,13 @@ int statvfs ();
#endif
#endif
#endif
+#endif
+#endif
#if ! STAT_NONE
+static long adjust_blocks P((long blocks, int fromsize, int tosize));
+
/* Return the number of TOSIZE-byte blocks used by
BLOCKS FROMSIZE-byte blocks, rounding up. */
@@ -121,7 +129,7 @@ get_fs_usage (path, disk, fsp)
if (statfs (path, &fsd) != 1)
return -1;
-#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
+#define convert_blocks(b) adjust_blocks ((long) (b), 1024, 512)
fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
@@ -129,7 +137,7 @@ get_fs_usage (path, disk, fsp)
fsp->fsu_ffree = fsd.fd_req.gfree;
#endif
-#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
+#if STAT_STATFS2_BSIZE || STAT_DUSTAT /* 4.3BSD, SunOS 4, HP-UX, AIX. */
struct statfs fsd;
if (statfs (path, &fsd) < 0)
@@ -169,23 +177,94 @@ get_fs_usage (path, disk, fsp)
adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
#endif
+#if STAT_DISK_SPACE /* QNX. */
+ int o;
+ int iret;
+ long cfree_blocks, ctotal_blocks;
+ char *zpath;
+ char *zslash;
+
+ zpath = zbufcpy (path);
+ while ((o = open (zpath, O_RDONLY, 0)) == -1
+ && errno == ENOENT)
+ {
+ /* The named file doesn't exist, so we can't open it. Try the
+ directory containing it. */
+ if ((strcmp ("/", zpath) == 0)
+ || (strcmp (zpath, ".") == 0)
+ || (strcmp (zpath, "") == 0)
+ /* QNX peculiarity: "//2" means root on node 2 */
+ || ((strncmp (zpath, "//", 2) == 0)
+ && (strchr (zpath + 2, '/') == NULL)))
+ {
+ /* We can't shorten this! */
+ break;
+ }
+
+ /* Shorten the pathname by one component and try again. */
+ zslash = strrchr (zpath, '/');
+ if (zslash == NULL)
+ {
+ /* Try the current directory. We can open directories. */
+ zpath[0] = '.';
+ zpath[1] = '\0';
+ }
+ else if (zslash == zpath)
+ {
+ /* Try the root directory. */
+ zpath[0] = '/';
+ zpath[1] = '\0';
+ }
+ else
+ {
+ /* Chop off last path component. */
+ zslash[0] = '\0';
+ }
+ }
+ if (o == -1)
+ {
+ ulog (LOG_ERROR, "get_fs_usage: open (%s) failed: %s", zpath,
+ strerror (errno));
+ ubuffree (zpath);
+ return -1;
+ }
+ ubuffree (zpath);
+
+ iret = disk_space (o, &cfree_blocks, &ctotal_blocks);
+ (void) close (o);
+ if (iret == -1)
+ {
+ ulog (LOG_ERROR, "get_fs_usage: disk_space failed: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ fsp->fsu_blocks = ctotal_blocks;
+ fsp->fsu_bfree = cfree_blocks;
+ fsp->fsu_bavail = cfree_blocks;
+
+ /* QNX has no limit on the number of inodes. Most inodes are stored
+ directly in the directory entry. */
+ fsp->fsu_files = -1;
+ fsp->fsu_ffree = -1;
+#endif /* STAT_DISK_SPACE */
+
#if STAT_USTAT
- {
- struct stat sstat;
- struct ustat s;
+ struct stat sstat;
+ struct ustat s;
- if (stat (path, &sstat) < 0
- || ustat (sstat.st_dev, &s) < 0)
- return -1;
- fsp->fsu_blocks = -1;
- fsp->fsu_bfree = f_tfree;
- fsp->fsu_bavail = f_tfree;
- fsp->fsu_files = -1;
- fsp->fsu_ffree = -1;
- }
+ if (stat (path, &sstat) < 0
+ || ustat (sstat.st_dev, &s) < 0)
+ return -1;
+ fsp->fsu_blocks = -1;
+ fsp->fsu_bfree = s.f_tfree;
+ fsp->fsu_bavail = s.f_tfree;
+ fsp->fsu_files = -1;
+ fsp->fsu_ffree = -1;
#endif
#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */
+#if ! STAT_DISK_SPACE
#if ! STAT_USTAT
#if ! STAT_NONE
fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
@@ -196,12 +275,12 @@ get_fs_usage (path, disk, fsp)
#endif
#endif
#endif
+#endif
return 0;
}
-#ifdef _AIX
-#ifdef _I386
+#if STAT_DUSTAT
/* AIX PS/2 does not supply statfs. */
int
@@ -227,5 +306,4 @@ statfs (path, fsb)
fsb->f_fsid.val[1] = fsd.du_pckno;
return 0;
}
-#endif
-#endif /* _AIX && _I386 */
+#endif /* STAT_DUSTAT */
diff --git a/gnu/libexec/uucp/libunix/ftw.c b/gnu/libexec/uucp/libunix/ftw.c
index c3372b53ca48..c7af06e04f02 100644
--- a/gnu/libexec/uucp/libunix/ftw.c
+++ b/gnu/libexec/uucp/libunix/ftw.c
@@ -17,7 +17,7 @@ License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.
-Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */
+Modified by Ian Lance Taylor for Taylor UUCP, June 1992, and October 1993. */
#include "uucp.h"
@@ -63,7 +63,7 @@ ftw_dir (dirs, level, descriptors, dir, len, func)
int descriptors;
char *dir;
size_t len;
- int (*func) P((const char *file, const struct stat *status, int flag));
+ int (*func) P((const char *file, struct stat *status, int flag));
{
int got;
struct dirent *entry;
@@ -177,7 +177,7 @@ ftw_dir (dirs, level, descriptors, dir, len, func)
int
ftw (dir, func, descriptors)
const char *dir;
- int (*func) P((const char *file, const struct stat *status, int flag));
+ int (*func) P((const char *file, struct stat *status, int flag));
int descriptors;
{
DIR **dirs;
@@ -234,7 +234,11 @@ ftw (dir, func, descriptors)
if (flag == FTW_D)
{
if (ret == 0)
- ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
+ {
+ if (len == 1 && *buf == '/')
+ len = 0;
+ ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
+ }
if (dirs[0] != NULL)
{
int save;
diff --git a/gnu/libexec/uucp/libunix/indir.c b/gnu/libexec/uucp/libunix/indir.c
index 2484ec23f85d..de1df702cc53 100644
--- a/gnu/libexec/uucp/libunix/indir.c
+++ b/gnu/libexec/uucp/libunix/indir.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/init.c b/gnu/libexec/uucp/libunix/init.c
index d4a137762813..95822db11684 100644
--- a/gnu/libexec/uucp/libunix/init.c
+++ b/gnu/libexec/uucp/libunix/init.c
@@ -1,7 +1,7 @@
/* init.c
Initialize the system dependent routines.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -153,35 +153,39 @@ usysdep_initialize (puuconf,iflags)
pointer puuconf;
int iflags;
{
- int cdescs;
- int o;
int iuuconf;
char *z;
struct passwd *q;
ulog_id (getpid ());
- /* Close everything but stdin, stdout and stderr. */
+ if ((iflags & INIT_NOCLOSE) == 0)
+ {
+ int cdescs;
+ int o;
+
+ /* Close everything but stdin, stdout and stderr. */
#if HAVE_GETDTABLESIZE
- cdescs = getdtablesize ();
+ cdescs = getdtablesize ();
#else
#if HAVE_SYSCONF
- cdescs = sysconf (_SC_OPEN_MAX);
+ cdescs = sysconf (_SC_OPEN_MAX);
#else
#ifdef OPEN_MAX
- cdescs = OPEN_MAX;
+ cdescs = OPEN_MAX;
#else
#ifdef NOFILE
- cdescs = NOFILE;
+ cdescs = NOFILE;
#else
- cdescs = 20;
+ cdescs = 20;
#endif /* ! defined (NOFILE) */
#endif /* ! defined (OPEN_MAX) */
#endif /* ! HAVE_SYSCONF */
#endif /* ! HAVE_GETDTABLESIZE */
- for (o = 3; o < cdescs; o++)
- (void) close (o);
+ for (o = 3; o < cdescs; o++)
+ (void) close (o);
+ }
/* Make sure stdin, stdout and stderr are open. */
if (fcntl (0, F_GETFD, 0) < 0
diff --git a/gnu/libexec/uucp/libunix/iswait.c b/gnu/libexec/uucp/libunix/iswait.c
index d2610aa1f8bd..aa855151c926 100644
--- a/gnu/libexec/uucp/libunix/iswait.c
+++ b/gnu/libexec/uucp/libunix/iswait.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/jobid.c b/gnu/libexec/uucp/libunix/jobid.c
index 7f22f1d37d75..c8b21cbcf21f 100644
--- a/gnu/libexec/uucp/libunix/jobid.c
+++ b/gnu/libexec/uucp/libunix/jobid.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/lcksys.c b/gnu/libexec/uucp/libunix/lcksys.c
index 4ece16afe7b5..c1b0efaa3b9e 100644
--- a/gnu/libexec/uucp/libunix/lcksys.c
+++ b/gnu/libexec/uucp/libunix/lcksys.c
@@ -8,20 +8,32 @@
#include "sysdep.h"
#include "system.h"
+/* Get the name of a system lock file. */
+
+static char *zssys_lock_name P((const struct uuconf_system *qsys, char *z));
+
+#define LOCKNAMELEN (sizeof "LCK..12345678")
+
+static char *
+zssys_lock_name (qsys, z)
+ const struct uuconf_system *qsys;
+ char *z;
+{
+ strcpy (z, "LCK..");
+ strncpy (z + sizeof "LCK.." - 1, qsys->uuconf_zname, 8);
+ z[sizeof "LCK.." - 1 + 8] = '\0';
+ return z;
+}
+
/* Lock a remote system. */
boolean
fsysdep_lock_system (qsys)
const struct uuconf_system *qsys;
{
- char *z;
- boolean fret;
-
- z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
- sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
- fret = fsdo_lock (z, FALSE, (boolean *) NULL);
- ubuffree (z);
- return fret;
+ char ab[LOCKNAMELEN];
+
+ return fsdo_lock (zssys_lock_name (qsys, ab), FALSE, (boolean *) NULL);
}
/* Unlock a remote system. */
@@ -30,12 +42,7 @@ boolean
fsysdep_unlock_system (qsys)
const struct uuconf_system *qsys;
{
- char *z;
- boolean fret;
-
- z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
- sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
- fret = fsdo_unlock (z, FALSE);
- ubuffree (z);
- return fret;
+ char ab[LOCKNAMELEN];
+
+ return fsdo_unlock (zssys_lock_name (qsys, ab), FALSE);
}
diff --git a/gnu/libexec/uucp/libunix/locfil.c b/gnu/libexec/uucp/libunix/locfil.c
index 0e05af9bcee9..1c4db66520a6 100644
--- a/gnu/libexec/uucp/libunix/locfil.c
+++ b/gnu/libexec/uucp/libunix/locfil.c
@@ -1,7 +1,7 @@
/* locfil.c
Expand a file name on the local system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -41,12 +41,16 @@ extern struct passwd *getpwnam ();
and moving any other type of file into the public directory. */
char *
-zsysdep_local_file (zfile, zpubdir)
+zsysdep_local_file (zfile, zpubdir, pfbadname)
const char *zfile;
const char *zpubdir;
+ boolean *pfbadname;
{
const char *zdir;
+ if (pfbadname != NULL)
+ *pfbadname = FALSE;
+
if (*zfile == '/')
return zbufcpy (zfile);
@@ -79,6 +83,8 @@ zsysdep_local_file (zfile, zpubdir)
{
ulog (LOG_ERROR, "User %s not found", zcopy);
ubuffree (zcopy);
+ if (pfbadname != NULL)
+ *pfbadname = TRUE;
return NULL;
}
ubuffree (zcopy);
diff --git a/gnu/libexec/uucp/libunix/lock.c b/gnu/libexec/uucp/libunix/lock.c
index d823213017b6..4011534291d7 100644
--- a/gnu/libexec/uucp/libunix/lock.c
+++ b/gnu/libexec/uucp/libunix/lock.c
@@ -1,7 +1,7 @@
/* lock.c
Lock and unlock a file name.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/05 18:24:06 conklin Exp $";
+const char lock_rcsid[] = "$Id: lock.c,v 1.2 1994/05/07 18:10:40 ache Exp $";
#endif
#include "uudefs.h"
@@ -43,6 +43,19 @@ const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/05 18:24:06 conklin Exp $";
#endif
#endif
+#if TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#if HAVE_QNX_LOCKFILES
+#include <sys/kernel.h>
+#include <sys/psinfo.h>
+#include <sys/seginfo.h>
+#include <sys/vc.h>
+#endif
+
#ifndef O_RDONLY
#define O_RDONLY 0
#define O_WRONLY 1
@@ -56,6 +69,15 @@ const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/05 18:24:06 conklin Exp $";
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
+
+#ifndef localtime
+extern struct tm *localtime ();
+#endif
+
+#if HAVE_QNX_LOCKFILES
+static boolean fsqnx_stale P((unsigned long ipid, unsigned long inme,
+ unsigned long inid, boolean *pferr));
+#endif
/* Lock something. If the fspooldir argument is TRUE, the argument is
a file name relative to the spool directory; otherwise the argument
@@ -73,13 +95,19 @@ fsdo_lock (zlock, fspooldir, pferr)
size_t cslash;
pid_t ime;
char *ztempfile;
- char abtempfile[sizeof "TMP1234567890"];
+ char abtempfile[sizeof "TMP12345678901234567890"];
int o;
+#if HAVE_QNX_LOCKFILES
+ nid_t inme;
+ char ab[23];
+ char *zend;
+#else
#if HAVE_V2_LOCKFILES
int i;
#else
char ab[12];
#endif
+#endif
int cwrote;
const char *zerr;
boolean fret;
@@ -99,6 +127,9 @@ fsdo_lock (zlock, fspooldir, pferr)
}
ime = getpid ();
+#if HAVE_QNX_LOCKFILES
+ inme = getnid ();
+#endif
/* We do the actual lock by creating a file and then linking it to
the final file name we want. This avoids race conditions due to
@@ -114,7 +145,12 @@ fsdo_lock (zlock, fspooldir, pferr)
else
cslash = zslash - zpath + 1;
+#if HAVE_QNX_LOCKFILES
+ sprintf (abtempfile, "TMP%010lx%010lx", (unsigned long) ime,
+ (unsigned long) inme);
+#else
sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
+#endif
ztempfile = zbufalc (cslash + sizeof abtempfile);
memcpy (ztempfile, zpath, cslash);
memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
@@ -141,13 +177,18 @@ fsdo_lock (zlock, fspooldir, pferr)
}
}
+#if HAVE_QNX_LOCKFILES
+ sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inid);
+ cwrote = write (o, ab, strlen (ab));
+#else
#if HAVE_V2_LOCKFILES
- i = ime;
+ i = (int) ime;
cwrote = write (o, &i, sizeof i);
#else
- sprintf (ab, "%10d\n", (int) ime);
+ sprintf (ab, "%10ld\n", (long) ime);
cwrote = write (o, ab, strlen (ab));
#endif
+#endif
zerr = NULL;
if (cwrote < 0)
@@ -177,8 +218,13 @@ fsdo_lock (zlock, fspooldir, pferr)
while (link (ztempfile, zpath) != 0)
{
int cgot;
- int ipid;
+ pid_t ipid;
boolean freadonly;
+ struct stat st;
+ char abtime[sizeof "1991-12-31 12:00:00"];
+#if HAVE_QNX_LOCKFILES
+ nid_t inid;
+#endif
fret = FALSE;
@@ -228,11 +274,17 @@ fsdo_lock (zlock, fspooldir, pferr)
break;
}
+#if HAVE_QNX_LOCKFILES
+ ab[cgot] = '\0';
+ ipid = (pid_t) strtol (ab, &zend, 10);
+ inid = (nid_t) strtol (zend, (char **) NULL, 10);
+#else
#if HAVE_V2_LOCKFILES
- ipid = i;
+ ipid = (pid_t) i;
#else
ab[cgot] = '\0';
- ipid = strtol (ab, (char **) NULL, 10);
+ ipid = (pid_t) strtol (ab, (char **) NULL, 10);
+#endif
#endif
/* On NFS, the link might have actually succeeded even though we
@@ -247,18 +299,49 @@ fsdo_lock (zlock, fspooldir, pferr)
going to worry about this possibility. */
if (ipid == ime)
{
- fret = TRUE;
- break;
+#if HAVE_QNX_LOCKFILES
+ if (inid == inme)
+#endif
+ {
+ fret = TRUE;
+ break;
+ }
}
+#if HAVE_QNX_LOCKFILES
+ if (! fsqnx_stale ((unsigned long) ipid, (unsigned long) inme,
+ (unsigned long) inid, pferr))
+ break;
+#else
/* If the process still exists, we will get EPERM rather than
ESRCH. We then return FALSE to indicate that we cannot make
the lock. */
if (kill (ipid, 0) == 0 || errno == EPERM)
break;
+#endif
- ulog (LOG_ERROR, "Found stale lock %s held by process %d",
- zpath, ipid);
+ if (fstat (o, &st) < 0)
+ strcpy (abtime, "unknown");
+ else
+ {
+ time_t itm;
+ struct tm *q;
+
+ itm = (time_t) st.st_mtime;
+ q = localtime (&itm);
+ sprintf (abtime, "%04d-%02d-%02d %02d:%02d:%02d",
+ q->tm_year + 1900, q->tm_mon + 1, q->tm_mday, q->tm_hour,
+ q->tm_min, q->tm_sec);
+ }
+
+#if HAVE_QNX_LOCKFILES
+ ulog (LOG_ERROR,
+ "Stale lock %s held by process %ld on node %ld created %s",
+ zpath, (long) ipid, (long) inid, abtime);
+#else
+ ulog (LOG_ERROR, "Stale lock %s held by process %ld created %s",
+ zpath, (long) ipid, abtime);
+#endif
/* This is a stale lock, created by a process that no longer
exists.
@@ -317,6 +400,7 @@ fsdo_lock (zlock, fspooldir, pferr)
(void) close (o);
o = -1;
(void) remove (zpath);
+ fret = TRUE;
continue;
}
@@ -326,13 +410,18 @@ fsdo_lock (zlock, fspooldir, pferr)
break;
}
+#if HAVE_QNX_LOCKFILES
+ sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inid);
+ cwrote = write (o, ab, strlen (ab));
+#else
#if HAVE_V2_LOCKFILES
- i = ime;
+ i = (int) ime;
cwrote = write (o, &i, sizeof i);
#else
- sprintf (ab, "%10d\n", (int) ime);
+ sprintf (ab, "%10ld\n", (long) ime);
cwrote = write (o, ab, strlen (ab));
#endif
+#endif
if (cwrote < 0)
{
@@ -360,52 +449,63 @@ fsdo_lock (zlock, fspooldir, pferr)
break;
}
+#if HAVE_QNX_LOCKFILES
+ ab[cgot] = '\0';
+ ipid = (pid_t) strtol (ab, &zend, 10);
+ inid = (nid_t) strtol (zend, (char **) NULL, 10);
+#else
#if HAVE_V2_LOCKFILES
- ipid = i;
+ ipid = (pid_t) i;
#else
ab[cgot] = '\0';
- ipid = strtol (ab, (char **) NULL, 10);
+ ipid = (pid_t) strtol (ab, (char **) NULL, 10);
+#endif
#endif
if (ipid == ime)
{
- struct stat sfile, sdescriptor;
-
- /* It looks like we have the lock. Do the final stat
- check. */
- if (stat ((char *) zpath, &sfile) < 0)
- {
- if (errno != ENOENT)
- {
- zerr = "stat";
- break;
- }
- /* Loop around and try again. */
- }
- else
+#if HAVE_QNX_LOCKFILES
+ if (inid == inme)
+#endif
{
- if (fstat (o, &sdescriptor) < 0)
+ struct stat sfile, sdescriptor;
+
+ /* It looks like we have the lock. Do the final stat
+ check. */
+ if (stat ((char *) zpath, &sfile) < 0)
{
- zerr = "fstat";
- break;
+ if (errno != ENOENT)
+ {
+ zerr = "stat";
+ break;
+ }
+ /* Loop around and try again. */
}
-
- if (sfile.st_ino == sdescriptor.st_ino
- && sfile.st_dev == sdescriptor.st_dev)
+ else
{
- /* Close the file before assuming we've succeeded to
- pick up any trailing errors. */
- if (close (o) < 0)
+ if (fstat (o, &sdescriptor) < 0)
{
- zerr = "close";
+ zerr = "fstat";
break;
}
- o = -1;
-
- /* We have the lock. */
- fret = TRUE;
- break;
+ if (sfile.st_ino == sdescriptor.st_ino
+ && sfile.st_dev == sdescriptor.st_dev)
+ {
+ /* Close the file before assuming we've
+ succeeded to pick up any trailing errors. */
+ if (close (o) < 0)
+ {
+ zerr = "close";
+ break;
+ }
+
+ o = -1;
+
+ /* We have the lock. */
+ fret = TRUE;
+ break;
+ }
}
}
}
@@ -475,3 +575,90 @@ fsdo_unlock (zlock, fspooldir)
return FALSE;
}
}
+
+#if HAVE_QNX_LOCKFILES
+
+/* Return TRUE if the lock is stale. */
+
+static boolean
+fsqnx_stale (ipid, inme, inid, pferr)
+ unsigned long ipid;
+ unsigned long inme;
+ unsigned long inid;
+ boolean *pferr;
+{
+ /* A virtual process ID. This virtual process ID, which will exist
+ on the local node, will represent the process ID of the process
+ manager process (Proc) on the remote node. */
+ pid_t ivid;
+ /* The return value of the qnx_psinfo function. This is either a
+ process ID which might or might not be the same as the process
+ being looked for, or -1 to indicate no process found. */
+ pid_t ifound_pid;
+ /* This holds the actual result of qnx_psinfo. We will ignore
+ almost all the fields since we're just checking for existence. */
+ struct _psinfo spsdata;
+
+ /* Establish connection with a remote process manager if necessary. */
+ if (inid != inme)
+ {
+ ivid = qnx_vc_attach (inid /* remote node ID */,
+ PROC_PID /* pid of process manager */,
+ 1000 /* initial buffer size */,
+ 0 /* flags */);
+ if (ivid < 0)
+ {
+ ulog (LOG_ERROR, "qnx_vc_attach (%lu, PROC_PID): %s",
+ inid, strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Use the local pid of the local process manager. */
+ ivid = PROC_PID;
+ }
+
+ /* Request the process information. */
+ ifound_pid = qnx_psinfo (ivid /* process manager handling request */,
+ ipid /* get info on this process */,
+ &spsdata /* put info in this struct */,
+ 0 /* unused */,
+ (struct _seginfo *) NULL /* unused */);
+
+ /* Deallocate the virtual connection before continuing. */
+ {
+ int isaved_errno = errno;
+ if (qnx_vc_detach (ivid) < 0)
+ ulog (LOG_ERROR, "qnx_vd_detach (%ld): %s", (long) ivid,
+ strerror (errno));
+ errno = isaved_errno;
+ }
+
+ /* If the returned pid matches then the process still holds the lock. */
+ if ((ifound_pid == ipid) && (spsdata.pid == ipid))
+ return FALSE;
+
+ /* If the returned pid is positive and doesn't match, then the
+ process doesn't exist and the lock is stale. Continue. */
+
+ /* If the returned pid is negative (-1) and errno is EINVAL (or ESRCH
+ in older versions of QNX), then the process doesn't exist and the
+ lock is stale. Continue. */
+
+ /* Check for impossible errors. */
+ if ((ifound_pid < 0) && (errno != ESRCH) && (errno != EINVAL))
+ {
+ ulog (LOG_ERROR, "qnx_psinfo (%ld, %ld): %s", (long) ivid,
+ (long) ipid, strerror (errno));
+ /* Since we don't know what the hell this means, and we don't
+ want our system to freeze, we treat this case as a stale
+ lock. Continue on. */
+ }
+
+ return TRUE;
+}
+
+#endif /* HAVE_QNX_LOCKFILES */
diff --git a/gnu/libexec/uucp/libunix/loctim.c b/gnu/libexec/uucp/libunix/loctim.c
index da5f32e2d273..7f1f87aa671c 100644
--- a/gnu/libexec/uucp/libunix/loctim.c
+++ b/gnu/libexec/uucp/libunix/loctim.c
@@ -3,7 +3,9 @@
#include "uucp.h"
-#if HAVE_TIME_H
+#if TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
#include <time.h>
#endif
diff --git a/gnu/libexec/uucp/libunix/mail.c b/gnu/libexec/uucp/libunix/mail.c
index 74c1aa95adc6..e1fbaa92afee 100644
--- a/gnu/libexec/uucp/libunix/mail.c
+++ b/gnu/libexec/uucp/libunix/mail.c
@@ -1,7 +1,7 @@
/* mail.c
Send mail to a user.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -48,17 +48,47 @@ fsysdep_mail (zto, zsubject, cstrs, paz)
int cstrs;
const char **paz;
{
- const char *az[3];
+ char **pazargs;
+ char *zcopy, *ztok;
+ size_t cargs, iarg;
FILE *e;
pid_t ipid;
time_t itime;
int i;
- az[0] = MAIL_PROGRAM;
- az[1] = zto;
- az[2] = NULL;
+ /* Parse MAIL_PROGRAM into an array of arguments. */
+ zcopy = zbufcpy (MAIL_PROGRAM);
+
+ cargs = 0;
+ for (ztok = strtok (zcopy, " \t");
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"))
+ ++cargs;
+
+ pazargs = (char **) xmalloc ((cargs + 4) * sizeof (char *));
+
+ memcpy (zcopy, MAIL_PROGRAM, sizeof MAIL_PROGRAM);
+ for (ztok = strtok (zcopy, " \t"), iarg = 0;
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"), ++iarg)
+ pazargs[iarg] = ztok;
+
+#if ! MAIL_PROGRAM_SUBJECT_BODY
+ pazargs[iarg++] = (char *) "-s";
+ pazargs[iarg++] = (char *) zsubject;
+#endif
+
+#if ! MAIL_PROGRAM_TO_BODY
+ pazargs[iarg++] = (char *) zto;
+#endif
+
+ pazargs[iarg] = NULL;
+
+ e = espopen ((const char **) pazargs, FALSE, &ipid);
+
+ ubuffree (zcopy);
+ xfree ((pointer) pazargs);
- e = espopen (az, FALSE, &ipid);
if (e == NULL)
{
ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM,
@@ -66,10 +96,16 @@ fsysdep_mail (zto, zsubject, cstrs, paz)
return FALSE;
}
- fprintf (e, "Subject: %s\n", zsubject);
+#if MAIL_PROGRAM_TO_BODY
fprintf (e, "To: %s\n", zto);
+#endif
+#if MAIL_PROGRAM_SUBJECT_BODY
+ fprintf (e, "Subject: %s\n", zsubject);
+#endif
+#if MAIL_PROGRAM_TO_BODY || MAIL_PROGRAM_SUBJECT_BODY
fprintf (e, "\n");
+#endif
(void) time (&itime);
/* Remember that ctime includes a \n, so this skips a line. */
diff --git a/gnu/libexec/uucp/libunix/mkdir.c b/gnu/libexec/uucp/libunix/mkdir.c
index f59ad5dfd6e6..2546cbff1e46 100644
--- a/gnu/libexec/uucp/libunix/mkdir.c
+++ b/gnu/libexec/uucp/libunix/mkdir.c
@@ -38,7 +38,7 @@ mkdir (zdir, imode)
aidescs[1] = SPAWN_NULL;
aidescs[2] = SPAWN_NULL;
- ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
TRUE, FALSE, (const char *) NULL,
(const char *) NULL, (const char *) NULL);
diff --git a/gnu/libexec/uucp/libunix/mkdirs.c b/gnu/libexec/uucp/libunix/mkdirs.c
index a4e0b67bb8c3..9b5b23ffd7b1 100644
--- a/gnu/libexec/uucp/libunix/mkdirs.c
+++ b/gnu/libexec/uucp/libunix/mkdirs.c
@@ -29,17 +29,19 @@ fsysdep_make_dirs (zfile, fpublic)
if (*z == '/' && z != zcopy)
{
*z = '\0';
- if (! fsysdep_directory (zcopy))
+ if (mkdir (zcopy, imode) != 0
+ && errno != EEXIST
+ && (errno != EACCES || ! fsysdep_directory (zcopy)))
{
- if (mkdir (zcopy, imode) != 0)
- {
- ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
- strerror (errno));
- ubuffree (zcopy);
- return FALSE;
- }
+ ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
+ strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
}
- *z = '/';
+ *z = '/'; /* replace '/' in its place */
+ /* now skips over multiple '/' in name */
+ while ( (*(z + 1)) && (*(z + 1)) == '/')
+ z++;
}
}
diff --git a/gnu/libexec/uucp/libunix/move.c b/gnu/libexec/uucp/libunix/move.c
index ccfe6d4d728d..3345bbfa04dc 100644
--- a/gnu/libexec/uucp/libunix/move.c
+++ b/gnu/libexec/uucp/libunix/move.c
@@ -1,7 +1,7 @@
/* move.c
Move a file.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -77,14 +77,12 @@ fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
if (stat (zcopy, &s) != 0)
{
ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
- (void) remove (zorig);
ubuffree (zcopy);
return FALSE;
}
if (! fsuser_access (&s, W_OK, zuser))
{
ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
- (void) remove (zorig);
ubuffree (zcopy);
return FALSE;
}
@@ -107,10 +105,7 @@ fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
if (fmkdirs && errno == ENOENT)
{
if (! fsysdep_make_dirs (zto, fpublic))
- {
- (void) remove (zorig);
- return FALSE;
- }
+ return FALSE;
if (rename (zorig, zto) == 0)
return TRUE;
}
@@ -127,7 +122,6 @@ fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
{
ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto,
strerror (errno));
- (void) remove (zorig);
return FALSE;
}
@@ -135,7 +129,6 @@ fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
if (stat ((char *) zorig, &s) < 0)
{
ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno));
- (void) remove (zorig);
return FALSE;
}
@@ -148,26 +141,19 @@ fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
if (fmkdirs && errno == ENOENT)
{
if (! fsysdep_make_dirs (zto, fpublic))
- {
- (void) remove (zorig);
- return FALSE;
- }
+ return FALSE;
o = creat ((char *) zto, s.st_mode);
}
if (o < 0)
{
ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno));
- (void) remove (zorig);
return FALSE;
}
}
(void) close (o);
if (! fcopy_file (zorig, zto, fpublic, fmkdirs))
- {
- (void) remove (zorig);
- return FALSE;
- }
+ return FALSE;
if (remove (zorig) != 0)
ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno));
diff --git a/gnu/libexec/uucp/libunix/opensr.c b/gnu/libexec/uucp/libunix/opensr.c
index 3a8ca7a8b8ac..15cd5cd13601 100644
--- a/gnu/libexec/uucp/libunix/opensr.c
+++ b/gnu/libexec/uucp/libunix/opensr.c
@@ -1,7 +1,7 @@
/* opensr.c
Open files for sending and receiving.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -131,16 +131,18 @@ esysdep_open_send (qsys, zfile, fcheck, zuser)
}
/* Get a temporary file name to receive into. We use the ztemp
- argument to pick the file name, so that we relocate the file if the
+ argument to pick the file name, so that we restart the file if the
transmission is aborted. */
char *
-zsysdep_receive_temp (qsys, zto, ztemp)
+zsysdep_receive_temp (qsys, zto, ztemp, frestart)
const struct uuconf_system *qsys;
const char *zto;
const char *ztemp;
+ boolean frestart;
{
- if (ztemp != NULL
+ if (frestart
+ && ztemp != NULL
&& *ztemp == 'D'
&& strcmp (ztemp, "D.0") != 0)
return zsappend3 (".Temp", qsys->uuconf_zname, ztemp);
@@ -148,6 +150,10 @@ zsysdep_receive_temp (qsys, zto, ztemp)
return zstemp_file (qsys);
}
+/* The number of seconds in one week. We must cast to long for this
+ to be calculated correctly on a machine with 16 bit ints. */
+#define SECS_PER_WEEK ((long) 7 * (long) 24 * (long) 60 * (long) 60)
+
/* Open a temporary file to receive into. This should, perhaps, check
that we have write permission on the receiving directory, but it
doesn't. */
@@ -168,8 +174,10 @@ esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
that case, we may have already received some portion of this
file. */
o = -1;
- *pcrestart = -1;
- if (ztemp != NULL
+ if (pcrestart != NULL)
+ *pcrestart = -1;
+ if (pcrestart != NULL
+ && ztemp != NULL
&& *ztemp == 'D'
&& strcmp (ztemp, "D.0") != 0)
{
@@ -185,7 +193,7 @@ esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
restarted, and they know about this issue, they can touch
it to bring it up to date. */
if (fstat (o, &s) < 0
- || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL))
+ || s.st_mtime + SECS_PER_WEEK < time ((time_t *) NULL))
{
(void) close (o);
o = -1;
diff --git a/gnu/libexec/uucp/libunix/pause.c b/gnu/libexec/uucp/libunix/pause.c
index e774e0897bf2..8155db327260 100644
--- a/gnu/libexec/uucp/libunix/pause.c
+++ b/gnu/libexec/uucp/libunix/pause.c
@@ -29,7 +29,9 @@
#endif
#if HAVE_SELECT
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -53,7 +55,7 @@ struct pollfd
#endif /* HAVE_POLL */
#if HAVE_TIME_H
-#if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER
+#if ! HAVE_SYS_TIME_H || ! HAVE_SELECT || TIME_WITH_SYS_TIME
#include <time.h>
#endif
#endif
@@ -87,10 +89,10 @@ usysdep_pause ()
s.tv_sec = 0;
s.tv_usec = 500 * (long) 1000;
select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s);
-#endif /* USE_SELECT_TIMER */
+#endif /* HAVE_SELECT */
#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
-#if ! USE_SELECT_TIMER && ! HAVE_POLL
+#if ! HAVE_SELECT && ! HAVE_POLL
sleep (1);
-#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
+#endif /* ! HAVE_SELECT && ! HAVE_POLL */
#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
}
diff --git a/gnu/libexec/uucp/libunix/picksb.c b/gnu/libexec/uucp/libunix/picksb.c
index 4d8cc4b2f3b6..a1afd1b8ae59 100644
--- a/gnu/libexec/uucp/libunix/picksb.c
+++ b/gnu/libexec/uucp/libunix/picksb.c
@@ -1,7 +1,7 @@
/* picksb.c
System dependent routines for uupick.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char picksb_rcsid[] = "$Id: picksb.c,v 1.1 1993/08/05 18:24:15 conklin Exp $";
+const char picksb_rcsid[] = "$Id: picksb.c,v 1.2 1994/05/07 18:10:54 ache Exp $";
#endif
#include "uudefs.h"
@@ -203,18 +203,22 @@ fsysdep_uupick_free (zsystem, zpubdir)
/* Expand a local file name for uupick. */
char *
-zsysdep_uupick_local_file (zfile)
+zsysdep_uupick_local_file (zfile, pfbadname)
const char *zfile;
+ boolean *pfbadname;
{
struct passwd *q;
+ if (pfbadname != NULL)
+ *pfbadname = FALSE;
+
/* If this does not start with a simple ~, pass it to
zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd
only uses the zpubdir argument if the file starts with a simple
~, so it doesn't really matter what we pass for zpubdir. */
if (zfile[0] != '~'
|| (zfile[1] != '/' && zfile[1] != '\0'))
- return zsysdep_local_file_cwd (zfile, (const char *) NULL);
+ return zsysdep_local_file_cwd (zfile, (const char *) NULL, pfbadname);
q = getpwuid (getuid ());
if (q == NULL)
diff --git a/gnu/libexec/uucp/libunix/pipe.c b/gnu/libexec/uucp/libunix/pipe.c
new file mode 100644
index 000000000000..80e9e7f61bd4
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/pipe.c
@@ -0,0 +1,294 @@
+/* pipe.c
+ The pipe port communication routines for Unix.
+ Contributed by Marc Boucher <marc@CAM.ORG>.
+
+ Copyright (C) 1993 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char pipe_rcsid[] = "$Id: pipe.c,v 1.1 1994/05/07 18:10:56 ache Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "conn.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* Local functions. */
+
+static void uspipe_free P((struct sconnection *qconn));
+static boolean fspipe_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fspipe_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fspipe_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialer));
+
+/* The command table for standard input ports. */
+
+static const struct sconncmds spipecmds =
+{
+ uspipe_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ fspipe_open,
+ fspipe_close,
+ fspipe_dial,
+ fsdouble_read,
+ fsdouble_write,
+ fsysdep_conn_io,
+ NULL, /* pfbreak */
+ NULL, /* pfset */
+ NULL, /* pfcarrier */
+ fsdouble_chat,
+ NULL /* pibaud */
+};
+
+/* Initialize a pipe connection. */
+
+boolean
+fsysdep_pipe_init (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ q->o = -1;
+ q->ord = -1;
+ q->owr = -1;
+ q->zdevice = NULL;
+ q->iflags = -1;
+ q->iwr_flags = -1;
+ q->fterminal = FALSE;
+ q->ftli = FALSE;
+ q->ibaud = 0;
+ q->ipid = -1;
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = &spipecmds;
+ return TRUE;
+}
+
+static void
+uspipe_free (qconn)
+ struct sconnection *qconn;
+{
+ xfree (qconn->psysdep);
+}
+
+/* Open a pipe port. */
+
+/*ARGSUSED*/
+static boolean
+fspipe_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ /* We don't do incoming waits on pipes. */
+ if (fwait)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Close a pipe port. */
+
+/*ARGSUSED*/
+static boolean
+fspipe_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ fret = TRUE;
+
+ /* Close our sides of the pipe. */
+ if (qsysdep->ord >= 0 && close (qsysdep->ord) < 0)
+ {
+ ulog (LOG_ERROR, "fspipe_close: close read fd: %s", strerror (errno));
+ fret = FALSE;
+ }
+ if (qsysdep->owr != qsysdep->ord
+ && qsysdep->owr >= 0
+ && close (qsysdep->owr) < 0)
+ {
+ ulog (LOG_ERROR, "fspipe_close: close write fd: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->ord = -1;
+ qsysdep->owr = -1;
+
+ /* Kill dangling child process. */
+ if (qsysdep->ipid >= 0)
+ {
+ if (kill (qsysdep->ipid, SIGHUP) == 0)
+ usysdep_sleep (2);
+#ifdef SIGPIPE
+ if (kill (qsysdep->ipid, SIGPIPE) == 0)
+ usysdep_sleep (2);
+#endif
+ if (kill (qsysdep->ipid, SIGKILL) < 0 && errno == EPERM)
+ {
+ ulog (LOG_ERROR, "fspipe_close: Cannot kill child pid %lu: %s",
+ (unsigned long) qsysdep->ipid, strerror (errno));
+ fret = FALSE;
+ }
+ else
+ (void) ixswait ((unsigned long) qsysdep->ipid, (const char *) NULL);
+ }
+ qsysdep->ipid = -1;
+ return fret;
+}
+
+/* Dial out on a pipe port, so to speak: launch connection program
+ under us. The code alternates q->o between q->ord and q->owr as
+ appropriate. It is always q->ord before any call to fsblock. */
+
+/*ARGSUSED*/
+static boolean
+fspipe_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialer;
+{
+ struct ssysdep_conn *q;
+ int aidescs[3];
+ const char **pzprog;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ *ptdialer = DIALERFOUND_FALSE;
+
+ pzprog = (const char **) qconn->qport->uuconf_u.uuconf_spipe.uuconf_pzcmd;
+
+ if (pzprog == NULL)
+ {
+ ulog (LOG_ERROR, "No command for pipe connection");
+ return FALSE;
+ }
+
+ aidescs[0] = SPAWN_WRITE_PIPE;
+ aidescs[1] = SPAWN_READ_PIPE;
+ aidescs[2] = SPAWN_NULL;
+
+ /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the
+ responsibility of security on the connection program. */
+ q->ipid = ixsspawn (pzprog, aidescs, TRUE, TRUE, (const char *) NULL,
+ FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (q->ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
+ return FALSE;
+ }
+
+ q->owr = aidescs[0];
+ q->ord = aidescs[1];
+ q->o = q->ord;
+
+ q->iflags = fcntl (q->ord, F_GETFL, 0);
+ q->iwr_flags = fcntl (q->owr, F_GETFL, 0);
+ if (q->iflags < 0 || q->iwr_flags < 0)
+ {
+ ulog (LOG_ERROR, "fspipe_dial: fcntl: %s", strerror (errno));
+ (void) fspipe_close (qconn, puuconf, qdialer, FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#if 0
+
+/* Marc Boucher's contributed code used an alarm to avoid waiting too
+ long when closing the pipe. However, I believe that it is not
+ possible for the kernel to sleep when closing a pipe; it is only
+ possible when closing a device. Therefore, I have removed the
+ code, but am preserving it in case I am wrong. To reenable it, the
+ two calls to close in fspipe_close should be changed to call
+ fspipe_alarmclose. */
+
+static RETSIGTYPE
+usalarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, usalarm);
+#endif
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ longjmp (sSjmp_buf, 1);
+#endif
+}
+
+static int
+fspipe_alarmclose (fd)
+ int fd;
+{
+ int iret = -1;
+ int ierrno = 0;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ iret = close (fd);
+ ierrno = errno;
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ errno = ierrno;
+ return iret;
+}
+
+#endif /* 0 */
diff --git a/gnu/libexec/uucp/libunix/priv.c b/gnu/libexec/uucp/libunix/priv.c
new file mode 100644
index 000000000000..207bd3dbbb9d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/priv.c
@@ -0,0 +1,24 @@
+/* priv.c
+ See if a user is privileged. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+/* See whether the user is privileged (for example, only privileged
+ users are permitted to kill arbitrary jobs with uustat). This is
+ true only for root and uucp. We check for uucp by seeing if the
+ real user ID and the effective user ID are the same; this works
+ because we should be suid to uucp, so our effective user ID will
+ always be uucp while our real user ID will be whoever ran the
+ program. */
+
+boolean
+fsysdep_privileged ()
+{
+ uid_t iuid;
+
+ iuid = getuid ();
+ return iuid == 0 || iuid == geteuid ();
+}
diff --git a/gnu/libexec/uucp/libunix/proctm.c b/gnu/libexec/uucp/libunix/proctm.c
index 55cf96f0c972..b9b6eb9e4afc 100644
--- a/gnu/libexec/uucp/libunix/proctm.c
+++ b/gnu/libexec/uucp/libunix/proctm.c
@@ -1,7 +1,7 @@
/* proctm.c
Get the time spent in the process.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -48,7 +48,7 @@
#define HAVE_FTIME 0
#endif
-#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY)
+#if HAVE_TIME_H && (TIME_WITH_SYS_TIME || ! HAVE_GETTIMEOFDAY)
#include <time.h>
#endif
diff --git a/gnu/libexec/uucp/libunix/recep.c b/gnu/libexec/uucp/libunix/recep.c
index 84a211a7a946..152fd0d0ba1f 100644
--- a/gnu/libexec/uucp/libunix/recep.c
+++ b/gnu/libexec/uucp/libunix/recep.c
@@ -1,7 +1,7 @@
/* recep.c
See whether a file has already been received.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -103,7 +103,7 @@ fsysdep_remember_reception (qsys, zto, ztemp)
{
if (errno == ENOENT)
{
- if (fsysdep_make_dirs (zfile, TRUE))
+ if (fsysdep_make_dirs (zfile, FALSE))
{
ubuffree (zfile);
return FALSE;
@@ -133,6 +133,10 @@ fsysdep_remember_reception (qsys, zto, ztemp)
return TRUE;
}
+/* The number of seconds in one week. We must cast to long for this
+ to be calculated correctly on a machine with 16 bit ints. */
+#define SECS_PER_WEEK ((long) 7 * (long) 24 * (long) 60 * (long) 60)
+
/* See if we have already received a file. Note that don't delete the
marker file here, because we need to know that the sending system
has received our denial first. This function returns TRUE if the
@@ -161,7 +165,7 @@ fsysdep_already_received (qsys, zto, ztemp)
}
/* Ignore the file (return FALSE) if it is over one week old. */
- fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL);
+ fret = s.st_mtime + SECS_PER_WEEK >= time ((time_t *) NULL);
if (fret)
DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s",
diff --git a/gnu/libexec/uucp/libunix/run.c b/gnu/libexec/uucp/libunix/run.c
index e21919628372..af9b078d3bd9 100644
--- a/gnu/libexec/uucp/libunix/run.c
+++ b/gnu/libexec/uucp/libunix/run.c
@@ -1,7 +1,7 @@
/* run.c
Run a program.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -31,13 +31,11 @@
#include <errno.h>
-/* Start up a new program and end the current one. We don't have to
- worry about SIGHUP because the current process is either not a
- process group leader (uucp, uux) or it does not have a controlling
- terminal (uucico). */
+/* Start up a new program. */
boolean
-fsysdep_run (zprogram, zarg1, zarg2)
+fsysdep_run (ffork, zprogram, zarg1, zarg2)
+ boolean ffork;
const char *zprogram;
const char *zarg1;
const char *zarg2;
@@ -47,6 +45,40 @@ fsysdep_run (zprogram, zarg1, zarg2)
int aidescs[3];
pid_t ipid;
+ /* If we are supposed to fork, fork and then spawn so that we don't
+ have to worry about zombie processes. */
+ if (ffork)
+ {
+ ipid = ixsfork ();
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (ipid != 0)
+ {
+ /* This is the parent. Wait for the child we just forked to
+ exit (below) and return. */
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+
+ /* Force the log files to be reopened in case the child just
+ output any error messages and stdio doesn't handle
+ appending correctly. */
+ ulog_close ();
+
+ return TRUE;
+ }
+
+ /* This is the child. Detach from the terminal to avoid any
+ unexpected SIGHUP signals. At this point we are definitely
+ not a process group leader, so usysdep_detach will not fork
+ again. */
+ usysdep_detach ();
+
+ /* Now spawn the program and then exit. */
+ }
+
zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram));
sprintf (zlib, "%s/%s", SBINDIR, zprogram);
@@ -65,11 +97,17 @@ fsysdep_run (zprogram, zarg1, zarg2)
FALSE, TRUE, (const char *) NULL,
(const char *) NULL, (const char *) NULL);
ubuffree (zlib);
+
if (ipid < 0)
{
ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ if (ffork)
+ _exit (EXIT_FAILURE);
return FALSE;
}
+ if (ffork)
+ _exit (EXIT_SUCCESS);
+
return TRUE;
}
diff --git a/gnu/libexec/uucp/libunix/seq.c b/gnu/libexec/uucp/libunix/seq.c
index 2e01233022a9..5188510b6128 100644
--- a/gnu/libexec/uucp/libunix/seq.c
+++ b/gnu/libexec/uucp/libunix/seq.c
@@ -1,7 +1,7 @@
/* seq.c
Get and increment the conversation sequence number for a system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/serial.c b/gnu/libexec/uucp/libunix/serial.c
index cee90fcc7bb3..cfa28d075a07 100644
--- a/gnu/libexec/uucp/libunix/serial.c
+++ b/gnu/libexec/uucp/libunix/serial.c
@@ -1,7 +1,7 @@
/* serial.c
The serial port communication routines for Unix.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char serial_rcsid[] = "$Id: serial.c,v 1.3 1994/02/07 23:47:51 ache Exp $";
+const char serial_rcsid[] = "$Id: serial.c,v 1.4 1994/05/07 18:11:09 ache Exp $";
#endif
#include "uudefs.h"
@@ -78,19 +78,21 @@ const char serial_rcsid[] = "$Id: serial.c,v 1.3 1994/02/07 23:47:51 ache Exp $"
#define FD_CLOEXEC 1
#endif
-#if HAVE_SYS_IOCTL_H
+#if HAVE_SYS_IOCTL_H || HAVE_TXADDCD
#include <sys/ioctl.h>
#endif
#if HAVE_BSD_TTY
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#endif
#if HAVE_TIME_H
-#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY
+#if ! HAVE_SYS_TIME_H || ! HAVE_BSD_TTY || TIME_WITH_SYS_TIME
#include <time.h>
#endif
#endif
@@ -117,6 +119,10 @@ const char serial_rcsid[] = "$Id: serial.c,v 1.3 1994/02/07 23:47:51 ache Exp $"
#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
#endif /* HAVE_SVR4_LOCKFILES */
+#if HAVE_DEV_INFO
+#include <sys/dev.h>
+#endif
+
/* Get definitions for both O_NONBLOCK and O_NDELAY. */
#ifndef O_NDELAY
#ifdef FNDELAY
@@ -180,38 +186,46 @@ extern int t_nerr;
/* Determine bits to clear for the various terminal control fields for
HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */
+
+/* These fields are defined on some systems, and I am told that it
+ does not hurt to clear them, and it sometimes helps. */
+#ifndef IMAXBEL
+#define IMAXBEL 0
+#endif
+
+#ifndef PENDIN
+#define PENDIN 0
+#endif
+
#if HAVE_SYSV_TERMIO
#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
| ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
- | IXON | IXANY | IXOFF)
+ | IXON | IXANY | IXOFF | IMAXBEL)
#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
| OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
| VTDLY | FFDLY)
-#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
+#define ICLEAR_CFLAG (CBAUD | CSIZE | PARENB | PARODD)
#define ISET_CFLAG (CS8 | CREAD | HUPCL)
#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
- | ECHONL | NOFLSH)
+ | ECHONL | NOFLSH | PENDIN)
#endif
#if HAVE_POSIX_TERMIOS
-#ifdef IMAXBEL
-#define CI_ADD1 IMAXBEL
-#else
-#define CI_ADD1 0
-#endif
#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
| INLCR | INPCK | ISTRIP | IXOFF | IXON \
- | PARMRK | CI_ADD1)
+ | PARMRK | IMAXBEL)
#define ICLEAR_OFLAG (OPOST)
-#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
+#define ICLEAR_CFLAG (CSIZE | PARENB | PARODD)
#define ISET_CFLAG (CS8 | CREAD | HUPCL)
-#ifdef PENDIN
-#define CL_ADD1 PENDIN
-#else
-#define CL_ADD1 0
-#endif
#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
- | ISIG | NOFLSH | TOSTOP | CL_ADD1)
+ | ISIG | NOFLSH | TOSTOP | PENDIN)
#endif
+
+enum tclocal_setting
+{
+ SET_CLOCAL,
+ CLEAR_CLOCAL,
+ IGNORE_CLOCAL
+};
/* Local functions. */
@@ -226,7 +240,7 @@ static boolean fsserial_lock P((struct sconnection *qconn,
boolean fin));
static boolean fsserial_unlock P((struct sconnection *qconn));
static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
- boolean fwait));
+ boolean fwait, enum tclocal_setting tlocal));
static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
boolean fwait));
static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
@@ -247,13 +261,6 @@ static boolean fsdirect_close P((struct sconnection *qconn,
pointer puuconf,
struct uuconf_dialer *qdialer,
boolean fsuccess));
-static boolean fsserial_reset P((struct sconnection *qconn));
-static boolean fsstdin_reset P((struct sconnection *qconn));
-static boolean fsstdin_read P((struct sconnection *qconn,
- char *zbuf, size_t *pclen, size_t cmin,
- int ctimeout, boolean freport));
-static boolean fsstdin_write P((struct sconnection *qconn,
- const char *zwrite, size_t cwrite));
static boolean fsserial_break P((struct sconnection *qconn));
static boolean fsstdin_break P((struct sconnection *qconn));
static boolean fsserial_set P((struct sconnection *qconn,
@@ -266,9 +273,9 @@ static boolean fsstdin_set P((struct sconnection *qconn,
enum txonxoffsetting txonxoff));
static boolean fsmodem_carrier P((struct sconnection *qconn,
boolean fcarrier));
+static boolean fsserial_hardflow P((struct sconnection *qconn,
+ boolean fhardflow));
static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
-static boolean fsstdin_chat P((struct sconnection *qconn,
- char **pzprog));
static long isserial_baud P((struct sconnection *qconn));
/* The command table for standard input ports. */
@@ -280,15 +287,14 @@ static const struct sconncmds sstdincmds =
NULL, /* pfunlock */
fsstdin_open,
fsstdin_close,
- fsstdin_reset,
NULL, /* pfdial */
- fsstdin_read,
- fsstdin_write,
+ fsdouble_read,
+ fsdouble_write,
fsysdep_conn_io,
fsstdin_break,
fsstdin_set,
NULL, /* pfcarrier */
- fsstdin_chat,
+ fsdouble_chat,
isserial_baud
};
@@ -301,7 +307,6 @@ static const struct sconncmds smodemcmds =
fsserial_unlock,
fsmodem_open,
fsmodem_close,
- fsserial_reset,
fmodem_dial,
fsysdep_conn_read,
fsysdep_conn_write,
@@ -322,7 +327,6 @@ static const struct sconncmds sdirectcmds =
fsserial_unlock,
fsdirect_open,
fsdirect_close,
- fsserial_reset,
NULL, /* pfdial */
fsysdep_conn_read,
fsysdep_conn_write,
@@ -499,6 +503,8 @@ fsserial_init (qconn, qcmds, zdevice)
q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
}
q->o = -1;
+ q->ord = -1;
+ q->owr = -1;
q->ftli = FALSE;
qconn->psysdep = (pointer) q;
qconn->qcmds = qcmds;
@@ -548,6 +554,12 @@ usserial_free (qconn)
qconn->psysdep = NULL;
}
+#if HAVE_SEQUENT_LOCKFILES
+#define LCK_TEMPLATE "LCK..tty"
+#else
+#define LCK_TEMPLATE "LCK.."
+#endif
+
/* This routine is used for both locking and unlocking. It is the
only routine which knows how to translate a device name into the
name of a lock file. If it can't figure out a name, it does
@@ -571,6 +583,39 @@ fsserial_lockfile (flok, qconn)
zalc = NULL;
if (z == NULL)
{
+#if HAVE_QNX_LOCKFILES
+ {
+ nid_t idevice_nid;
+ char abdevice_nid[13]; /* length of long, a period, and a NUL */
+ size_t cdevice_nid;
+ const char *zbase;
+ size_t clen;
+
+ /* If the node ID is explicitly specified as part of the
+ pathname to the device, use that. Otherwise, presume the
+ device is local to the current node. */
+ if (qsysdep->zdevice[0] == '/' && qsysdep->zdevice[1] == '/')
+ idevice_nid = (nid_t) strtol (qsysdep->zdevice + 2,
+ (char **) NULL, 10);
+ else
+ idevice_nid = getnid ();
+
+ sprintf (abdevice_nid, "%ld.", (long) idevice_nid);
+ cdevice_nid = strlen (abdevice_nid);
+
+ zbase = strrchr (qsysdep->zdevice, '/') + 1;
+ clen = strlen (zbase);
+
+ zalc = zbufalc (sizeof LCK_TEMPLATE + cdevice_nid + clen);
+
+ memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
+ memcpy (zalc + sizeof LCK_TEMPLATE - 1, abdevice_nid, cdevice_nid);
+ memcpy (zalc + sizeof LCK_TEMPLATE - 1 + cdevice_nid,
+ zbase, clen + 1);
+
+ z = zalc;
+ }
+#else /* ! HAVE_QNX_LOCKFILES */
#if ! HAVE_SVR4_LOCKFILES
{
const char *zbase;
@@ -578,22 +623,21 @@ fsserial_lockfile (flok, qconn)
zbase = strrchr (qsysdep->zdevice, '/') + 1;
clen = strlen (zbase);
- zalc = zbufalc (sizeof "LCK.." + clen);
- memcpy (zalc, "LCK..", sizeof "LCK.." - 1);
- memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1);
+ zalc = zbufalc (sizeof LCK_TEMPLATE + clen);
+ memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
+ memcpy (zalc + sizeof LCK_TEMPLATE - 1, zbase, clen + 1);
#if HAVE_SCO_LOCKFILES
{
char *zl;
- for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++)
+ for (zl = zalc + sizeof LCK_TEMPLATE - 1; *zl != '\0'; zl++)
if (isupper (*zl))
*zl = tolower (*zl);
}
#endif
z = zalc;
}
-#else /* ! HAVE_SVR4_LOCKFILES */
-#if HAVE_SVR4_LOCKFILES
+#else /* HAVE_SVR4_LOCKFILES */
{
struct stat s;
@@ -608,10 +652,8 @@ fsserial_lockfile (flok, qconn)
major (s.st_rdev), minor (s.st_rdev));
z = zalc;
}
-#else /* ! HAVE_SVR4_LOCKFILES */
- z = strrchr (qsysdep->zdevice, '/') + 1;
-#endif /* ! HAVE_SVR4_LOCKFILES */
-#endif /* ! HAVE_SVR4_LOCKFILES */
+#endif /* HAVE_SVR4_LOCKFILES */
+#endif /* ! HAVE_QNX_LOCKFILES */
}
if (flok)
@@ -624,13 +666,15 @@ fsserial_lockfile (flok, qconn)
{
if (flok)
{
- if (lockttyexist (z))
+ if (lockttyexist (z + sizeof LCK_TEMPLATE - 1))
{
- ulog (LOG_NORMAL, "%s: port already locked", z+5);
+ ulog (LOG_NORMAL, "%s: port already locked",
+ z + sizeof LCK_TEMPLATE - 1);
fret = FALSE;
}
else
- fret = !(fscoherent_disable_tty (z, &qsysdep->zenable));
+ fret = fscoherent_disable_tty (z + sizeof LCK_TEMPLATE - 1,
+ &qsysdep->zenable);
}
else
{
@@ -689,7 +733,7 @@ fsserial_lock (qconn, fin)
if (! fsserial_lockfile (TRUE, qconn))
return FALSE;
-#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
+#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL || HAVE_DEV_INFO
/* Open the line and try to mark it in use. */
{
struct ssysdep_conn *qsysdep;
@@ -740,6 +784,38 @@ fsserial_lock (qconn, fin)
}
#endif
+#if HAVE_DEV_INFO
+ /* QNX programs "lock" a serial port by simply opening it and
+ checking if some other program also has the port open. If the
+ count of openers is greater than one, the program presumes the
+ port is "locked" and backs off. This isn't really "locking" of
+ course, but it pretty much seems to work. This can result in
+ dropping incoming connections if an outgoing connection is
+ started at exactly the same time. It would probably be better
+ to stop using the lock files at all for this case, but that
+ would involve more complex changes to the code, and I'm afraid
+ I would break something. -- Joe Wells <jbw@cs.bu.edu> */
+ {
+ struct _dev_info_entry sdevinfo;
+
+ if (dev_info (qsysdep->o, &sdevinfo) == -1)
+ {
+ ulog (LOG_ERROR, "dev_info: %s", strerror (errno));
+ sdevinfo.open_count = 2; /* force presumption of "locked" */
+ }
+ if (sdevinfo.open_count != 1)
+ {
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif /* TIOCNOTTY */
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+ }
+#endif /* HAVE_DEV_INFO */
+
if (fcntl (qsysdep->o, F_SETFD,
fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
{
@@ -752,11 +828,6 @@ fsserial_lock (qconn, fin)
(void) fsserial_lockfile (FALSE, qconn);
return FALSE;
}
-
-#ifdef TIOCSCTTY
- /* On BSD 4.4, make it our controlling terminal. */
- (void) ioctl (qsysdep->o, TIOCSCTTY, 0);
-#endif
}
#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
@@ -796,8 +867,7 @@ fsserial_unlock (qconn)
return fret;
}
-/* Open a serial line. This sets the terminal settings. We begin in
- seven bit mode and let the protocol change if necessary. */
+/* A table to map baud rates into index numbers. */
#if HAVE_POSIX_TERMIOS
typedef speed_t baud_code;
@@ -858,11 +928,18 @@ static struct sbaud_table
static int cSmin;
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+/* Open a serial line. This sets the terminal settings. We begin in
+ seven bit mode and let the protocol change if necessary. If fwait
+ is FALSE we open the terminal in non-blocking mode. If flocal is
+ TRUE we set CLOCAL on the terminal when using termio[s]; this is
+ supposedly required on some versions of BSD/386. */
+
static boolean
-fsserial_open (qconn, ibaud, fwait)
+fsserial_open (qconn, ibaud, fwait, tlocal)
struct sconnection *qconn;
long ibaud;
boolean fwait;
+ enum tclocal_setting tlocal;
{
struct ssysdep_conn *q;
baud_code ib;
@@ -870,7 +947,19 @@ fsserial_open (qconn, ibaud, fwait)
q = (struct ssysdep_conn *) qconn->psysdep;
if (q->zdevice != NULL)
- ulog_device (strrchr (q->zdevice, '/') + 1);
+ {
+#if LOG_DEVICE_PREFIX
+ ulog_device (q->zdevice);
+#else
+ const char *z;
+
+ if (strncmp (q->zdevice, "/dev/", sizeof "/dev/" - 1) == 0)
+ z = q->zdevice + sizeof "/dev/" - 1;
+ else
+ z = q->zdevice;
+ ulog_device (z);
+#endif
+ }
else
{
const char *zport;
@@ -945,7 +1034,7 @@ fsserial_open (qconn, ibaud, fwait)
ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
return FALSE;
}
- q->istdout_flags = -1;
+ q->iwr_flags = -1;
if (! fgetterminfo (q->o, &q->sorig))
{
@@ -1025,13 +1114,11 @@ fsserial_open (qconn, ibaud, fwait)
q->snew.c_iflag &=~ ICLEAR_IFLAG;
q->snew.c_oflag &=~ ICLEAR_OFLAG;
q->snew.c_cflag &=~ ICLEAR_CFLAG;
- if (!fwait)
- q->snew.c_cflag |= CLOCAL;
- q->snew.c_cflag |= (ib | ISET_CFLAG);
+ q->snew.c_cflag |= ib | ISET_CFLAG;
q->snew.c_lflag &=~ ICLEAR_LFLAG;
cSmin = 1;
q->snew.c_cc[VMIN] = cSmin;
- q->snew.c_cc[VTIME] = 0;
+ q->snew.c_cc[VTIME] = 1;
#ifdef TCFLSH
/* Flush pending input. */
@@ -1048,13 +1135,11 @@ fsserial_open (qconn, ibaud, fwait)
q->snew.c_iflag &=~ ICLEAR_IFLAG;
q->snew.c_oflag &=~ ICLEAR_OFLAG;
q->snew.c_cflag &=~ ICLEAR_CFLAG;
- if (!fwait)
- q->snew.c_cflag |= CLOCAL;
q->snew.c_cflag |= ISET_CFLAG;
q->snew.c_lflag &=~ ICLEAR_LFLAG;
cSmin = 1;
q->snew.c_cc[VMIN] = cSmin;
- q->snew.c_cc[VTIME] = 0;
+ q->snew.c_cc[VTIME] = 1;
(void) cfsetospeed (&q->snew, ib);
(void) cfsetispeed (&q->snew, ib);
@@ -1064,6 +1149,20 @@ fsserial_open (qconn, ibaud, fwait)
#endif /* HAVE_POSIX_TERMIOS */
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ switch (tlocal)
+ {
+ case SET_CLOCAL:
+ q->snew.c_cflag |= CLOCAL;
+ break;
+ case CLEAR_CLOCAL:
+ q->snew.c_cflag &=~ CLOCAL;
+ break;
+ case IGNORE_CLOCAL:
+ break;
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
if (! fsetterminfo (q->o, &q->snew))
{
ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
@@ -1098,8 +1197,9 @@ fsserial_open (qconn, ibaud, fwait)
return TRUE;
}
-/* Open a standard input port. The code alternates q->o between 0 and
- 1 as appropriate. It is always 0 before any call to fsblock. */
+/* Open a standard input port. The code alternates q->o between
+ q->ord and q->owr as appropriate. It is always q->ord before any
+ call to fsblock. */
static boolean
fsstdin_open (qconn, ibaud, fwait)
@@ -1110,11 +1210,14 @@ fsstdin_open (qconn, ibaud, fwait)
struct ssysdep_conn *q;
q = (struct ssysdep_conn *) qconn->psysdep;
- q->o = 0;
- if (! fsserial_open (qconn, ibaud, fwait))
+ q->ord = 0;
+ q->owr = 1;
+
+ q->o = q->ord;
+ if (! fsserial_open (qconn, ibaud, fwait, IGNORE_CLOCAL))
return FALSE;
- q->istdout_flags = fcntl (1, F_GETFL, 0);
- if (q->istdout_flags < 0)
+ q->iwr_flags = fcntl (q->owr, F_GETFL, 0);
+ if (q->iwr_flags < 0)
{
ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
return FALSE;
@@ -1130,9 +1233,26 @@ fsmodem_open (qconn, ibaud, fwait)
long ibaud;
boolean fwait;
{
+ struct uuconf_modem_port *qm;
+
+ qm = &qconn->qport->uuconf_u.uuconf_smodem;
if (ibaud == (long) 0)
- ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
- return fsserial_open (qconn, ibaud, fwait);
+ ibaud = qm->uuconf_ibaud;
+
+ if (! fsserial_open (qconn, ibaud, fwait,
+ fwait ? CLEAR_CLOCAL : SET_CLOCAL))
+ return FALSE;
+
+ /* If we are waiting for carrier, then turn on hardware flow
+ control. We don't turn on hardware flow control when dialing
+ out, because some modems don't assert the necessary signals until
+ they see carrier. Instead, we turn on hardware flow control in
+ fsmodem_carrier. */
+ if (fwait
+ && ! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
+ return FALSE;
+
+ return TRUE;
}
/* Open a direct port. */
@@ -1143,9 +1263,18 @@ fsdirect_open (qconn, ibaud, fwait)
long ibaud;
boolean fwait;
{
+ struct uuconf_direct_port *qd;
+
+ qd = &qconn->qport->uuconf_u.uuconf_sdirect;
if (ibaud == (long) 0)
- ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
- return fsserial_open (qconn, ibaud, fwait);
+ ibaud = qd->uuconf_ibaud;
+ if (! fsserial_open (qconn, ibaud, fwait,
+ qd->uuconf_fcarrier ? CLEAR_CLOCAL : SET_CLOCAL))
+ return FALSE;
+
+ /* Always turn on hardware flow control for a direct port when it is
+ opened. There is no other sensible time to turn it on. */
+ return fsserial_hardflow (qconn, qd->uuconf_fhardflow);
}
/* Change the blocking status of the port. We keep track of the
@@ -1188,14 +1317,14 @@ fsblock (qs, fblock)
qs->iflags = iwant;
- if (qs->istdout_flags >= 0)
+ if (qs->iwr_flags >= 0 && qs->ord != qs->owr)
{
if (fblock)
- iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK);
+ iwant = qs->iwr_flags &~ (O_NDELAY | O_NONBLOCK);
else
- iwant = qs->istdout_flags | iSunblock;
+ iwant = qs->iwr_flags | iSunblock;
- if (fcntl (1, F_SETFL, iwant) < 0)
+ if (fcntl (qs->owr, F_SETFL, iwant) < 0)
{
/* We don't bother to fix up iSunblock here, since we
succeeded above. */
@@ -1203,7 +1332,7 @@ fsblock (qs, fblock)
return FALSE;
}
- qs->istdout_flags = iwant;
+ qs->iwr_flags = iwant;
}
return TRUE;
@@ -1274,9 +1403,9 @@ fsstdin_close (qconn, puuconf, qdialer, fsuccess)
struct ssysdep_conn *qsysdep;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- (void) close (1);
+ (void) close (qsysdep->owr);
(void) close (2);
- qsysdep->o = 0;
+ qsysdep->o = qsysdep->ord;
return fsserial_close (qsysdep);
}
@@ -1442,68 +1571,6 @@ fsdirect_close (qconn, puuconf, qdialer, fsuccess)
return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
}
-/* Reset a serial port by hanging up. */
-
-static boolean
-fsserial_reset (qconn)
- struct sconnection *qconn;
-{
- struct ssysdep_conn *q;
- sterminal sbaud;
-
- q = (struct ssysdep_conn *) qconn->psysdep;
-
- if (! q->fterminal)
- return TRUE;
-
- sbaud = q->snew;
-
-#if HAVE_BSD_TTY
- sbaud.stty.sg_ispeed = B0;
- sbaud.stty.sg_ospeed = B0;
-#endif
-#if HAVE_SYSV_TERMIO
- sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
-#endif
-#if HAVE_POSIX_TERMIOS
- if (cfsetospeed (&sbaud, B0) < 0)
- {
- ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno));
- return FALSE;
- }
-#endif
-
- if (! fsetterminfodrain (q->o, &sbaud))
- {
- ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno));
- return FALSE;
- }
-
- /* Give the terminal a chance to settle. */
- sleep (2);
-
- if (! fsetterminfo (q->o, &q->snew))
- {
- ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Reset a standard input port. */
-
-static boolean
-fsstdin_reset (qconn)
- struct sconnection *qconn;
-{
- struct ssysdep_conn *qsysdep;
-
- qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- qsysdep->o = 0;
- return fsserial_reset (qconn);
-}
-
/* Begin dialing out on a modem port. This opens the dialer device if
there is one. */
@@ -1536,7 +1603,27 @@ fsysdep_modem_begin_dial (qconn, qdial)
sleep (2);
(void) ioctl (qsysdep->o, TIOCSDTR, 0);
#else /* ! defined (TIOCCDTR) */
- (void) fconn_reset (qconn);
+ if (qsysdep->fterminal)
+ {
+ sterminal sbaud;
+
+ sbaud = qsysdep->snew;
+
+#if HAVE_BSD_TTY
+ sbaud.stty.sg_ispeed = B0;
+ sbaud.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ (void) cfsetospeed (&sbaud, B0);
+#endif
+
+ (void) fsetterminfodrain (qsysdep->o, &sbaud);
+ sleep (2);
+ (void) fsetterminfo (qsysdep->o, &qsysdep->snew);
+ }
#endif /* ! defined (TIOCCDTR) */
if (qdial->uuconf_fdtr_toggle_wait)
@@ -1598,15 +1685,17 @@ fsmodem_carrier (qconn, fcarrier)
boolean fcarrier;
{
register struct ssysdep_conn *q;
+ struct uuconf_modem_port *qm;
q = (struct ssysdep_conn *) qconn->psysdep;
if (! q->fterminal)
return TRUE;
+ qm = &qconn->qport->uuconf_u.uuconf_smodem;
if (fcarrier)
{
- if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier)
+ if (qm->uuconf_fcarrier)
{
#ifdef TIOCCAR
/* Tell the modem to pay attention to carrier. */
@@ -1619,18 +1708,18 @@ fsmodem_carrier (qconn, fcarrier)
#if HAVE_BSD_TTY
#ifdef LNOMDM
- /* IS68K Unix uses a local LNOMDM bit. */
- {
- int iparam;
-
- iparam = LNOMDM;
- if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
+ /* IS68K Unix uses a local LNOMDM bit. */
{
- ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
- strerror (errno));
- return FALSE;
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
}
- }
#endif /* LNOMDM */
#endif /* HAVE_BSD_TTY */
@@ -1644,9 +1733,20 @@ fsmodem_carrier (qconn, fcarrier)
}
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
}
+
+ /* Turn on hardware flow control after turning on carrier. We
+ don't do it until now because some modems don't assert the
+ right signals until they see carrier. */
+ if (! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
+ return FALSE;
}
else
{
+ /* Turn off any hardware flow control before turning off
+ carrier. */
+ if (! fsserial_hardflow (qconn, FALSE))
+ return FALSE;
+
#ifdef TIOCNCAR
/* Tell the modem to ignore carrier. */
if (ioctl (q->o, TIOCNCAR, 0) < 0)
@@ -1714,6 +1814,104 @@ fsmodem_carrier (qconn, fcarrier)
return TRUE;
}
+/* Tell the port to use hardware flow control. There is no standard
+ mechanism for controlling this. This implementation supports
+ CRTSCTS on SunOS, RTS/CTSFLOW on 386(ish) unix, CTSCD on the 3b1,
+ and TXADDCD/TXDELCD on AIX. If you know how to do it on other
+ systems, please implement it and send me the patches. */
+
+static boolean
+fsserial_hardflow (qconn, fhardflow)
+ struct sconnection *qconn;
+ boolean fhardflow;
+{
+ register struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ /* Don't do anything if we don't know what to do. */
+#if HAVE_BSD_TTY
+#define HAVE_HARDFLOW 0
+#endif
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+#if ! HAVE_TXADDCD
+#ifndef CRTSFL
+#ifndef CRTSCTS
+#ifndef CTSCD
+#define HAVE_HARDFLOW 0
+#endif
+#endif
+#endif
+#endif
+#endif
+
+#ifndef HAVE_HARDFLOW
+#define HAVE_HARDFLOW 1
+#endif
+
+#if HAVE_HARDFLOW
+ if (fhardflow)
+ {
+#if HAVE_TXADDCD
+ /* The return value does not reliably indicate whether this
+ actually succeeded. */
+ (void) ioctl (q->o, TXADDCD, "rts");
+#else /* ! HAVE_TXADDCD */
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+#ifdef CRTSFL
+ q->snew.c_cflag |= CRTSFL;
+ q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
+#endif /* defined (CRTSFL) */
+#ifdef CRTSCTS
+ q->snew.c_cflag |= CRTSCTS;
+#endif /* defined (CRTSCTS) */
+#ifdef CTSCD
+ q->snew.c_cflag |= CTSCD;
+#endif /* defined (CTSCD) */
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't enable hardware flow control: %s",
+ strerror (errno));
+ return FALSE;
+ }
+#endif /* ! HAVE_TXADDCD */
+ }
+ else
+ {
+#if HAVE_TXADDCD
+ /* The return value does not reliably indicate whether this
+ actually succeeded. */
+ (void) ioctl (q->o, TXDELCD, "rts");
+#else /* ! HAVE_TXADDCD */
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+#ifdef CRTSFL
+ q->snew.c_cflag &=~ CRTSFL;
+ q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
+#endif /* defined (CRTSFL) */
+#ifdef CRTSCTS
+ q->snew.c_cflag &=~ CRTSCTS;
+#endif /* defined (CRTSCTS) */
+#ifdef CTSCD
+ q->snew.c_cflag &=~ CTSCD;
+#endif /* defined (CTSCD) */
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't disable hardware flow control: %s",
+ strerror (errno));
+ return FALSE;
+ }
+#endif /* ! HAVE_TXADDCD */
+ }
+#endif /* HAVE_HARDFLOW */
+
+ return TRUE;
+}
+
/* Finish dialing out on a modem by closing any dialer device and waiting
for carrier. */
@@ -1795,7 +1993,50 @@ fsysdep_modem_end_dial (qconn, qdial)
return FALSE;
}
-#endif /* TIOCWONLINE */
+#else /* ! defined (TIOCWONLINE) */
+
+ /* Try to open the port again without using O_NDELAY. In
+ principle, the open should delay until carrier is available.
+ This may not work on some systems, so we just ignore any
+ errors. */
+ {
+ int onew;
+
+ onew = open (q->zdevice, O_RDWR);
+ if (onew >= 0)
+ {
+ boolean fbad;
+ int iflags;
+
+ fbad = FALSE;
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ fbad = TRUE;
+
+ if (! fbad)
+ {
+ iflags = fcntl (onew, F_GETFL, 0);
+ if (iflags < 0
+ || ! fsetterminfo (onew, &q->snew))
+ fbad = TRUE;
+ }
+
+ if (fbad)
+ (void) close (onew);
+ else
+ {
+ (void) close (q->o);
+ q->o = onew;
+ q->iflags = iflags;
+#if HAVE_TIOCSINUSE
+ (void) ioctl (onew, TIOCSINUSE, 0);
+#endif
+ }
+ }
+ }
+
+#endif /* ! defined (TIOCWONLINE) */
}
return TRUE;
@@ -1855,6 +2096,7 @@ fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
boolean fret;
register struct ssysdep_conn * const q
= (struct ssysdep_conn *) qconn->psysdep;
+ int cwouldblock;
cwant = *pclen;
*pclen = 0;
@@ -1893,6 +2135,7 @@ fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
fret = FALSE;
+ cwouldblock = 0;
while (TRUE)
{
int cgot;
@@ -2009,10 +2252,26 @@ fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
(normally we would have received SIGHUP, but we can't count
on that). We turn off the signals before calling ulog to
reduce problems with interrupted system calls. */
- if (cgot <= 0)
+ if (cgot > 0)
+ cwouldblock = 0;
+ else
{
if (cgot < 0 && errno == EINTR)
cgot = 0;
+ else if (cgot < 0
+ && (errno == EAGAIN || errno == EWOULDBLOCK)
+ && cwouldblock < 2)
+ {
+ /* Incomprehensibly, on some systems the read will
+ return EWOULDBLOCK even though the descriptor has
+ been set to blocking mode. We permit the read call
+ to do this twice in a row, and then error out. We
+ don't want to permit an arbitrary number of
+ EWOULDBLOCK errors, since that could hang us up
+ indefinitely. */
+ ++cwouldblock;
+ cgot = 0;
+ }
else
{
int ierr;
@@ -2128,10 +2387,10 @@ fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
return fret;
}
-/* Read from a stdin port. */
+/* Read from a port with separate read/write file descriptors. */
-static boolean
-fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+boolean
+fsdouble_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
struct sconnection *qconn;
char *zbuf;
size_t *pclen;
@@ -2142,7 +2401,7 @@ fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
struct ssysdep_conn *qsysdep;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- qsysdep->o = 0;
+ qsysdep->o = qsysdep->ord;
return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
}
@@ -2180,7 +2439,7 @@ fsysdep_conn_write (qconn, zwrite, cwrite)
#if HAVE_TLI
if (q->ftli)
{
- cdid = t_snd (q->o, zwrite, cwrite, 0);
+ cdid = t_snd (q->o, (char *) zwrite, cwrite, 0);
if (cdid < 0 && t_errno != TSYSERR)
{
ulog (LOG_ERROR, "t_snd: %s",
@@ -2239,10 +2498,10 @@ fsysdep_conn_write (qconn, zwrite, cwrite)
return TRUE;
}
-/* Write to a stdin port. */
+/* Write to a port with separate read/write file descriptors. */
-static boolean
-fsstdin_write (qconn, zwrite, cwrite)
+boolean
+fsdouble_write (qconn, zwrite, cwrite)
struct sconnection *qconn;
const char *zwrite;
size_t cwrite;
@@ -2250,10 +2509,10 @@ fsstdin_write (qconn, zwrite, cwrite)
struct ssysdep_conn *qsysdep;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- qsysdep->o = 0;
+ qsysdep->o = qsysdep->ord;
if (! fsblock (qsysdep, TRUE))
return FALSE;
- qsysdep->o = 1;
+ qsysdep->o = qsysdep->owr;
return fsysdep_conn_write (qconn, zwrite, cwrite);
}
@@ -2317,8 +2576,8 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
/* If we are running on standard input, we switch the file
descriptors by hand. */
- if (q->istdout_flags >= 0)
- q->o = 0;
+ if (q->ord >= 0)
+ q->o = q->ord;
/* Do an unblocked read. */
if (! fsblock (q, FALSE))
@@ -2392,8 +2651,8 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
cdo = SINGLE_WRITE;
#endif
- if (q->istdout_flags >= 0)
- q->o = 1;
+ if (q->owr >= 0)
+ q->o = q->owr;
/* Loop until we get something besides EINTR. */
while (TRUE)
@@ -2405,7 +2664,7 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
#if HAVE_TLI
if (q->ftli)
{
- cdid = t_snd (q->o, zwrite, cdo, 0);
+ cdid = t_snd (q->o, (char *) zwrite, cdo, 0);
if (cdid < 0)
{
if (t_errno == TFLOW)
@@ -2460,8 +2719,8 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
{
/* We didn't write any data. Do a blocking write. */
- if (q->istdout_flags >= 0)
- q->o = 0;
+ if (q->ord >= 0)
+ q->o = q->ord;
if (! fsblock (q, TRUE))
return FALSE;
@@ -2471,11 +2730,11 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
cdo = SINGLE_WRITE;
DEBUG_MESSAGE1 (DEBUG_PORT,
- "fsysdep_conn_io: Blocking write of %lud",
+ "fsysdep_conn_io: Blocking write of %lu",
(unsigned long) cdo);
- if (q->istdout_flags >= 0)
- q->o = 1;
+ if (q->owr >= 0)
+ q->o = q->owr;
/* Loop until we get something besides EINTR. */
while (TRUE)
@@ -2487,7 +2746,7 @@ fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
#if HAVE_TLI
if (q->ftli)
{
- cdid = t_snd (q->o, zwrite, cdo, 0);
+ cdid = t_snd (q->o, (char *) zwrite, cdo, 0);
if (cdid < 0 && t_errno != TSYSERR)
{
ulog (LOG_ERROR, "t_snd: %s",
@@ -2576,7 +2835,7 @@ fsstdin_break (qconn)
struct ssysdep_conn *qsysdep;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- qsysdep->o = 1;
+ qsysdep->o = qsysdep->owr;
return fsserial_break (qconn);
}
@@ -2805,6 +3064,22 @@ fsserial_set (qconn, tparity, tstrip, txonxoff)
}
#endif /* HAVE_POSIX_TERMIOS */
#endif /* defined (CRTSCTS) */
+#ifdef CRTSFL
+ if ((q->snew.c_cflag & CRTSFL) != 0)
+ {
+ iset = IXON;
+ iclear = IXOFF;
+ /* SCO says we cant have CRTSFL **and** RTSFLOW/CTSFLOW */
+#ifdef RTSFLOW
+ iclear |= RTSFLOW;
+#endif
+#ifdef CTSFLOW
+ iclear |= CTSFLOW;
+#endif
+ fdo = TRUE;
+ break;
+ }
+#endif /* defined(CRTSFL) */
iset = IXON | IXOFF;
iclear = 0;
fdo = TRUE;
@@ -2890,7 +3165,7 @@ fsstdin_set (qconn, tparity, tstrip, txonxoff)
struct ssysdep_conn *qsysdep;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- qsysdep->o = 0;
+ qsysdep->o = qsysdep->ord;
return fsserial_set (qconn, tparity, tstrip, txonxoff);
}
@@ -2954,15 +3229,22 @@ fsrun_chat (oread, owrite, pzprog)
return ixswait ((unsigned long) ipid, "Chat program") == 0;
}
-/* Run a chat program on a stdin port. */
+/* Run a chat program on a port using separate read/write file
+ descriptors. */
-/*ARGSUSED*/
-static boolean
-fsstdin_chat (qconn, pzprog)
+boolean
+fsdouble_chat (qconn, pzprog)
struct sconnection *qconn;
char **pzprog;
{
- return fsrun_chat (0, 1, pzprog);
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ fret = fsrun_chat (qsysdep->ord, qsysdep->owr, pzprog);
+ if (qsysdep->fterminal)
+ (void) fgetterminfo (qsysdep->ord, &qsysdep->snew);
+ return fret;
}
/* Run a chat program on any general type of connection. */
@@ -2973,9 +3255,13 @@ fsysdep_conn_chat (qconn, pzprog)
char **pzprog;
{
struct ssysdep_conn *qsysdep;
+ boolean fret;
qsysdep = (struct ssysdep_conn *) qconn->psysdep;
- return fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
+ fret = fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
+ if (qsysdep->fterminal)
+ (void) fgetterminfo (qsysdep->o, &qsysdep->snew);
+ return fret;
}
/* Return baud rate of a serial port. */
diff --git a/gnu/libexec/uucp/libunix/signal.c b/gnu/libexec/uucp/libunix/signal.c
index 33e24a724574..75016c30e116 100644
--- a/gnu/libexec/uucp/libunix/signal.c
+++ b/gnu/libexec/uucp/libunix/signal.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/sindir.c b/gnu/libexec/uucp/libunix/sindir.c
index d98750818915..7c9da50045ff 100644
--- a/gnu/libexec/uucp/libunix/sindir.c
+++ b/gnu/libexec/uucp/libunix/sindir.c
@@ -18,7 +18,10 @@ zsysdep_in_dir (zdir, zfile)
cdir = strlen (zdir);
cfile = strlen (zfile);
zret = zbufalc (cdir + cfile + 2);
- memcpy (zret, zdir, cdir);
+ if (cdir == 1 && *zdir == '/')
+ cdir = 0;
+ else
+ memcpy (zret, zdir, cdir);
memcpy (zret + cdir + 1, zfile, cfile);
zret[cdir] = '/';
zret[cdir + cfile + 1] = '\0';
diff --git a/gnu/libexec/uucp/libunix/sleep.c b/gnu/libexec/uucp/libunix/sleep.c
index b232f9674ff0..910c9292e198 100644
--- a/gnu/libexec/uucp/libunix/sleep.c
+++ b/gnu/libexec/uucp/libunix/sleep.c
@@ -10,5 +10,17 @@ void
usysdep_sleep (c)
int c;
{
+#if HAVE_NAPMS || HAVE_NAP || HAVE_USLEEP || HAVE_SELECT || HAVE_POLL
+ int i;
+
+ /* In this case, usysdep_pause is accurate. */
+ for (i = 2 * c; i > 0; i--)
+ usysdep_pause ();
+#else
+ /* On some system sleep (1) may not sleep at all. Avoid this sort
+ of problem by always doing at least sleep (2). */
+ if (c < 2)
+ c = 2;
(void) sleep (c);
+#endif
}
diff --git a/gnu/libexec/uucp/libunix/spawn.c b/gnu/libexec/uucp/libunix/spawn.c
index 7ab080d1a9ca..67b915fc66a1 100644
--- a/gnu/libexec/uucp/libunix/spawn.c
+++ b/gnu/libexec/uucp/libunix/spawn.c
@@ -1,7 +1,7 @@
/* spawn.c
Spawn a program securely.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -102,6 +102,9 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
char *azenv[9];
char **pazenv;
boolean ferr;
+#if HAVE_FULLDUPLEX_PIPES
+ boolean ffullduplex;
+#endif
int ierr = 0;
int onull;
int aichild_descs[3];
@@ -196,6 +199,11 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
cpar_close = 0;
cchild_close = 0;
+#if HAVE_FULLDUPLEX_PIPES
+ ffullduplex = (aidescs[0] == SPAWN_WRITE_PIPE
+ && aidescs[1] == SPAWN_READ_PIPE);
+#endif
+
for (i = 0; i < 3; i++)
{
if (aidescs[i] == SPAWN_NULL)
@@ -224,6 +232,16 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
{
int aipipe[2];
+#if HAVE_FULLDUPLEX_PIPES
+ if (ffullduplex && i == 1)
+ {
+ /* Just use the fullduplex pipe. */
+ aidescs[i] = aidescs[0];
+ aichild_descs[i] = aichild_descs[0];
+ continue;
+ }
+#endif
+
if (pipe (aipipe) < 0)
{
ierr = errno;
@@ -249,8 +267,10 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
++cpar_close;
++cchild_close;
- if (fcntl (aidescs[i], F_SETFD,
- fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ if (fcntl (aipipe[0], F_SETFD,
+ fcntl (aipipe[0], F_GETFD, 0) | FD_CLOEXEC) < 0
+ || fcntl (aipipe[1], F_SETFD,
+ fcntl (aipipe[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
{
ierr = errno;
ferr = TRUE;
@@ -332,9 +352,21 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
if (! fkeepuid)
{
+ /* Return to the uid of the invoking user. */
(void) setuid (getuid ());
(void) setgid (getgid ());
}
+ else
+ {
+ /* Try to force the UUCP uid to be both real and effective user
+ ID, in order to present a consistent environment regardless
+ of the invoking user. This won't work on System V based
+ systems, but it will do no harm. It would be possible to use
+ a setuid root program to force the UID setting, but I don't
+ think the efficiency loss is worth it. */
+ (void) setuid (geteuid ());
+ (void) setgid (getegid ());
+ }
if (zchdir != NULL)
(void) chdir (zchdir);
@@ -352,11 +384,24 @@ ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
#endif
}
+#ifdef isc386
+#ifdef _POSIX_SOURCE
+ /* ISC has a remarkably stupid notion of environments. If a program
+ is compiled in the POSIX environment, it sets a process state.
+ If you then exec a program which expects the USG environment, the
+ process state is not reset, so the execed program fails. The
+ __setostype call is required to change back to the USG
+ environment. This ought to be a switch in policy.h, but it seems
+ too trivial, so I will leave this code here and wait for it to
+ break in some fashion in the next version of ISC. */
+ __setostype (0);
+#endif
+#endif
+
(void) execve ((char *) zcmd, (char **) pazargs, pazenv);
/* The exec failed. If permitted, try using /bin/sh to execute a
shell script. */
-
if (errno == ENOEXEC && fshell)
{
char *zto;
diff --git a/gnu/libexec/uucp/libunix/splcmd.c b/gnu/libexec/uucp/libunix/splcmd.c
index 9f6616a36dd0..774066119967 100644
--- a/gnu/libexec/uucp/libunix/splcmd.c
+++ b/gnu/libexec/uucp/libunix/splcmd.c
@@ -1,7 +1,7 @@
/* splcmd.c
Spool a command.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -44,10 +44,12 @@ zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
int ccmds;
const struct scmd *pascmds;
{
- char *z;
+ char abtempfile[sizeof "TMP1234567890"];
+ char *ztemp;
FILE *e;
int i;
const struct scmd *q;
+ char *z;
char *zjobid;
#if DEBUG > 0
@@ -55,14 +57,17 @@ zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
ulog (LOG_FATAL, "Bad grade %d", bgrade);
#endif
- z = zscmd_file (qsys, bgrade);
- if (z == NULL)
+ /* Write the commands into a temporary file and then rename it to
+ avoid a race with uucico reading the file. */
+ sprintf (abtempfile, "TMP%010lx", (unsigned long) getpid ());
+ ztemp = zsfind_file (abtempfile, qsys->uuconf_zname, bgrade);
+ if (ztemp == NULL)
return NULL;
- e = esysdep_fopen (z, FALSE, FALSE, TRUE);
+ e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE);
if (e == NULL)
{
- ubuffree (z);
+ ubuffree (ztemp);
return NULL;
}
@@ -93,8 +98,8 @@ zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
"zsysdep_spool_commands: Unrecognized type %d",
q->bcmd);
(void) fclose (e);
- (void) remove (z);
- ubuffree (z);
+ (void) remove (ztemp);
+ ubuffree (ztemp);
return NULL;
}
}
@@ -102,11 +107,30 @@ zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
if (fclose (e) != 0)
{
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
- (void) remove (z);
+ (void) remove (ztemp);
+ ubuffree (ztemp);
+ return NULL;
+ }
+
+ z = zscmd_file (qsys, bgrade);
+ if (z == NULL)
+ {
+ (void) remove (ztemp);
+ ubuffree (ztemp);
+ return NULL;
+ }
+
+ if (! fsysdep_move_file (ztemp, z, FALSE, FALSE, FALSE,
+ (const char *) NULL))
+ {
+ (void) remove (ztemp);
+ ubuffree (ztemp);
ubuffree (z);
return NULL;
}
+ ubuffree (ztemp);
+
zjobid = zsfile_to_jobid (qsys, z, bgrade);
if (zjobid == NULL)
(void) remove (z);
diff --git a/gnu/libexec/uucp/libunix/spool.c b/gnu/libexec/uucp/libunix/spool.c
index a3e50f7747f1..fa1d8e6b34c2 100644
--- a/gnu/libexec/uucp/libunix/spool.c
+++ b/gnu/libexec/uucp/libunix/spool.c
@@ -1,7 +1,7 @@
/* spool.c
Find a file in the spool directory.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/05 18:24:31 conklin Exp $";
+const char spool_rcsid[] = "$Id: spool.c,v 1.2 1994/05/07 18:11:24 ache Exp $";
#endif
#include "uudefs.h"
@@ -194,7 +194,12 @@ zsfind_file (zsimple, zsystem, bgrade)
const char *zsystem;
int bgrade;
{
- if (! fspool_file (zsimple))
+ /* zsysdep_spool_commands calls this with TMPXXX which we must treat
+ as a C. file. */
+ if ((zsimple[0] != 'T'
+ || zsimple[1] != 'M'
+ || zsimple[2] != 'P')
+ && ! fspool_file (zsimple))
{
ulog (LOG_ERROR, "Unrecognized file name %s", zsimple);
return NULL;
@@ -203,7 +208,9 @@ zsfind_file (zsimple, zsystem, bgrade)
#if ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR
if (*zsimple == 'X')
{
- size_t clen;
+ static char *zbuf;
+ static size_t cbuf;
+ size_t clen, cwant;
/* Files beginning with X. are execute files. It is important
for security reasons that we know the system which created
@@ -216,22 +223,19 @@ zsfind_file (zsimple, zsystem, bgrade)
too short, but hopefully no problem will occur since any
System V systems will be using HDB or SVR4 or TAYLOR. */
clen = strlen (zsimple);
- if (clen <= 7 || strncmp (zsimple + 2, zsystem, clen - 7) != 0)
+ if (clen < 5)
{
- static char *zbuf;
- static size_t cbuf;
- size_t cwant;
-
- cwant = strlen (zsystem) + 8;
- if (cwant > cbuf)
- {
- zbuf = (char *) xrealloc ((pointer) zbuf, cwant);
- cbuf = cwant;
- }
- sprintf (zbuf, "X.%s%s", zsystem,
- clen < 5 ? zsimple : zsimple + clen - 5);
- zsimple = zbuf;
+ ulog (LOG_ERROR, "Bad file name (too short) %s", zsimple);
+ return NULL;
}
+ cwant = strlen (zsystem) + 8;
+ if (cwant > cbuf)
+ {
+ zbuf = (char *) xrealloc ((pointer) zbuf, cwant);
+ cbuf = cwant;
+ }
+ sprintf (zbuf, "X.%s%s", zsystem, zsimple + clen - 5);
+ zsimple = zbuf;
}
#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR */
@@ -264,6 +268,7 @@ zsfind_file (zsimple, zsystem, bgrade)
switch (*zsimple)
{
case 'C':
+ case 'T':
#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
return zsysdep_in_dir ("C.", zsimple);
#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
diff --git a/gnu/libexec/uucp/libunix/srmdir.c b/gnu/libexec/uucp/libunix/srmdir.c
index 28487ef30970..6110b003fc25 100644
--- a/gnu/libexec/uucp/libunix/srmdir.c
+++ b/gnu/libexec/uucp/libunix/srmdir.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -35,7 +35,7 @@
#include <ftw.h>
#endif
-static int isremove_dir P((const char *, const struct stat *, int));
+static int isremove_dir P((const char *, struct stat *, int));
/* Keep a list of directories to be removed. */
@@ -90,7 +90,7 @@ fsysdep_rmdir (zdir)
static int
isremove_dir (zfile, qstat, iflag)
const char *zfile;
- const struct stat *qstat;
+ struct stat *qstat;
int iflag;
{
if (iflag == FTW_D || iflag == FTW_DNR)
diff --git a/gnu/libexec/uucp/libunix/statsb.c b/gnu/libexec/uucp/libunix/statsb.c
index aa17f9e9df07..733cad260fa3 100644
--- a/gnu/libexec/uucp/libunix/statsb.c
+++ b/gnu/libexec/uucp/libunix/statsb.c
@@ -1,7 +1,7 @@
/* statsb.c
System dependent routines for uustat.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/05 18:24:34 conklin Exp $";
+const char statsb_rcsid[] = "$Id: statsb.c,v 1.2 1994/05/07 18:11:29 ache Exp $";
#endif
#include "uudefs.h"
@@ -73,32 +73,16 @@ const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/05 18:24:34 conklin Exp
/* Local functions. */
-static int ussettime P((const char *z, time_t inow));
+static int issettime P((const char *z, time_t inow));
static boolean fskill_or_rejuv P((pointer puuconf, const char *zid,
boolean fkill));
-/* See whether the user is permitted to kill arbitrary jobs. This is
- true only for root and uucp. We check for uucp by seeing if the
- real user ID and the effective user ID are the same; this works
- because we should be suid to uucp, so our effective user ID will
- always be uucp while our real user ID will be whoever ran the
- program. */
-
-boolean
-fsysdep_privileged ()
-{
- uid_t iuid;
-
- iuid = getuid ();
- return iuid == 0 || iuid == geteuid ();
-}
-
/* Set file access time to the present. On many systems this could be
done by passing NULL to utime, but on some that doesn't work. This
routine is not time critical, so we never rely on NULL. */
static int
-ussettime(z, inow)
+issettime(z, inow)
const char *z;
time_t inow;
{
@@ -238,7 +222,7 @@ fskill_or_rejuv (puuconf, zid, fkill)
if (fkill)
isys = remove (ztemp);
else
- isys = ussettime (ztemp, inow);
+ isys = issettime (ztemp, inow);
if (isys != 0 && errno != ENOENT)
{
@@ -261,7 +245,7 @@ fskill_or_rejuv (puuconf, zid, fkill)
if (fkill)
isys = remove (zfile);
else
- isys = ussettime (zfile, inow);
+ isys = issettime (zfile, inow);
if (isys != 0 && errno != ENOENT)
{
@@ -313,6 +297,21 @@ ixsysdep_file_time (zfile)
return (long) s.st_mtime;
}
+
+/* Set the time of a file to the current time. */
+
+boolean
+fsysdep_touch_file (zfile)
+ const char *zfile;
+{
+ if (issettime (zfile, time ((time_t *) NULL)) != 0)
+ {
+ ulog (LOG_ERROR, "utime (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
/* Start getting the status files. */
@@ -399,7 +398,10 @@ fsysdep_lock_status ()
DIR *qdir;
struct dirent *qentry;
int calc;
- int *pai;
+ pid_t *pai;
+#if HAVE_QNX_LOCKFILES
+ nid_t *painid;
+#endif
int cgot;
int aidescs[3];
char *zcopy, *ztok;
@@ -420,18 +422,28 @@ fsysdep_lock_status ()
calc = 0;
pai = NULL;
cgot = 0;
+#if HAVE_QNX_LOCKFILES
+ painid = NULL;
+#endif
while ((qentry = readdir (qdir)) != NULL)
{
char *zname;
int o;
+#if HAVE_QNX_LOCKFILES
+ nid_t inid;
+ char ab[23];
+ char *zend;
+#else
#if HAVE_V2_LOCKFILES
int i;
#else
char ab[12];
#endif
+#endif
int cread;
int ierr;
- int ipid;
+ pid_t ipid;
+ int icheck;
if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
continue;
@@ -464,22 +476,45 @@ fsysdep_lock_status ()
ubuffree (zname);
+#if HAVE_QNX_LOCKFILES
+ ab[cread] = '\0';
+ ipid = (pid_t) strtol (ab, &zend, 10);
+ inid = (nid_t) strtol (zend, (char **) NULL, 10);
+#else
#if HAVE_V2_LOCKFILES
- ipid = i;
+ ipid = (pid_t) i;
#else
ab[cread] = '\0';
- ipid = strtol (ab, (char **) NULL, 10);
+ ipid = (pid_t) strtol (ab, (char **) NULL, 10);
+#endif
#endif
- printf ("%s: %d\n", qentry->d_name, ipid);
+#if HAVE_QNX_LOCKFILES
+ printf ("%s: %ld %ld\n", qentry->d_name, (long) inid, (long) ipid);
+#else
+ printf ("%s: %ld\n", qentry->d_name, (long) ipid);
+#endif
+
+ for (icheck = 0; icheck < cgot; icheck++)
+ if (pai[icheck] == ipid)
+ break;
+ if (icheck < cgot)
+ continue;
if (cgot >= calc)
{
calc += 10;
- pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int));
+ pai = (pid_t *) xrealloc ((pointer) pai, calc * sizeof (pid_t));
+#if HAVE_QNX_LOCKFILES
+ painid = (nid_t *) xrealloc ((pointer) painid,
+ calc * sizeof (nid_t));
+#endif
}
pai[cgot] = ipid;
+#if HAVE_QNX_LOCKFILES
+ painid[cgot] = inid;
+#endif
++cgot;
}
@@ -513,16 +548,40 @@ fsysdep_lock_status ()
{
int i;
char *zlast, *zset;
+#if HAVE_QNX_LOCKFILES
+ char *zpenultimate, *zsetnid;
+#endif /* HAVE_QNX_LOCKFILES */
zlast = pazargs[cargs - 1];
zset = zbufalc (strlen (zlast) + 20);
+
+#if HAVE_QNX_LOCKFILES
+ /* We assume in this case that PS_PROGRAM ends with " -n -p".
+ Thus, the last argument is "-p" and the second-to-last
+ (penultimate) argument is "-n". We modify them to read "-n###"
+ and "-p###" where "###" is the node ID and the process ID,
+ respectively. This seems like quite a roundabout way of doing
+ things. Why don't we just leave the " -n -p" part out of
+ PS_PROGRAM and construct the "-n###" and "-p###" arguments here
+ from scratch? Because that would not fit as well with how the
+ code works for the other systems and would require larger
+ changes. */
+ zpenultimate = pazargs[cargs - 2];
+ zsetnid = zbufalc (strlen (zpenultimate) + 20);
+#endif
+
for (i = 0; i < cgot; i++)
{
pid_t ipid;
- sprintf (zset, "%s%d", zlast, pai[i]);
+ sprintf (zset, "%s%ld", zlast, (long) pai[i]);
pazargs[cargs - 1] = zset;
+#if HAVE_QNX_LOCKFILES
+ sprintf (zsetnid, "%s%ld", zpenultimate, (long) painid[i]);
+ pazargs[cargs - 2] = zsetnid;
+#endif
+
ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
(const char *) NULL, FALSE, TRUE,
(const char *) NULL, (const char *) NULL,
@@ -533,6 +592,9 @@ fsysdep_lock_status ()
(void) ixswait ((unsigned long) ipid, PS_PROGRAM);
}
ubuffree (zset);
+#if HAVE_QNX_LOCKFILES
+ ubuffree (zsetnid);
+#endif
}
#else
{
@@ -546,7 +608,7 @@ fsysdep_lock_status ()
{
char ab[20];
- sprintf (ab, "%d", pai[i]);
+ sprintf (ab, "%ld", (long) pai[i]);
strcat (zlast, ab);
if (i + 1 < cgot)
strcat (zlast, ",");
@@ -563,7 +625,7 @@ fsysdep_lock_status ()
(void) ixswait ((unsigned long) ipid, PS_PROGRAM);
ubuffree (zlast);
}
-#endif
+#endif
ubuffree (zcopy);
xfree ((pointer) pazargs);
diff --git a/gnu/libexec/uucp/libunix/status.c b/gnu/libexec/uucp/libunix/status.c
index f403068a7094..a967085e08ff 100644
--- a/gnu/libexec/uucp/libunix/status.c
+++ b/gnu/libexec/uucp/libunix/status.c
@@ -1,7 +1,7 @@
/* status.c
Routines to get and set the status for a system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -41,7 +41,7 @@
static const int aiMapstatus[] =
{
- 0, 13, 7, 6, 4, 20, 3, 2
+ 0, 13, 7, 6, 20, 4, 3, 2
};
#define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0]))
diff --git a/gnu/libexec/uucp/libunix/strerr.c b/gnu/libexec/uucp/libunix/strerr.c
index d2a6c2128d04..8e7480f1ec5c 100644
--- a/gnu/libexec/uucp/libunix/strerr.c
+++ b/gnu/libexec/uucp/libunix/strerr.c
@@ -12,6 +12,8 @@ extern int sys_nerr;
extern char *sys_errlist[];
#endif
+#undef strerror
+
char *
strerror (ierr)
int ierr;
diff --git a/gnu/libexec/uucp/libunix/tmpfil.c b/gnu/libexec/uucp/libunix/tmpfil.c
index 2dac0024388a..b10e8096df4e 100644
--- a/gnu/libexec/uucp/libunix/tmpfil.c
+++ b/gnu/libexec/uucp/libunix/tmpfil.c
@@ -1,7 +1,7 @@
/* tmpfil.c
Get a temporary file name.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,11 +20,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
+#include "uudefs.h"
#include "uuconf.h"
#include "system.h"
#include "sysdep.h"
diff --git a/gnu/libexec/uucp/libunix/uacces.c b/gnu/libexec/uucp/libunix/uacces.c
index c92c78eae354..d99ead36674b 100644
--- a/gnu/libexec/uucp/libunix/uacces.c
+++ b/gnu/libexec/uucp/libunix/uacces.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/ufopen.c b/gnu/libexec/uucp/libunix/ufopen.c
index 5a7b6f22b0d0..76ee1d1394d5 100644
--- a/gnu/libexec/uucp/libunix/ufopen.c
+++ b/gnu/libexec/uucp/libunix/ufopen.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libunix/walk.c b/gnu/libexec/uucp/libunix/walk.c
index ab96123127dd..85b94dae8a98 100644
--- a/gnu/libexec/uucp/libunix/walk.c
+++ b/gnu/libexec/uucp/libunix/walk.c
@@ -11,8 +11,7 @@
#include <ftw.h>
#endif
-static int iswalk_dir P((const char *zname, const struct stat *qstat,
- int iflag));
+static int iswalk_dir P((const char *zname, struct stat *qstat, int iflag));
/* Walk a directory tree. */
@@ -41,7 +40,7 @@ usysdep_walk_tree (zdir, pufn, pinfo)
static int
iswalk_dir (zname, qstat, iflag)
const char *zname;
- const struct stat *qstat;
+ struct stat *qstat;
int iflag;
{
char *zcopy;
diff --git a/gnu/libexec/uucp/libunix/wldcrd.c b/gnu/libexec/uucp/libunix/wldcrd.c
index cfbd15eb848a..13faa29b9c43 100644
--- a/gnu/libexec/uucp/libunix/wldcrd.c
+++ b/gnu/libexec/uucp/libunix/wldcrd.c
@@ -1,7 +1,7 @@
/* wldcrd.c
Expand wildcards.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -113,9 +113,10 @@ fsysdep_wildcard_start (zfile)
azargs[2] = zcmd;
azargs[3] = NULL;
+ e = espopen (azargs, TRUE, &ipid);
+
ubuffree (zcmd);
- e = espopen (azargs, TRUE, &ipid);
if (e == NULL)
{
ulog (LOG_ERROR, "espopen: %s", strerror (errno));
diff --git a/gnu/libexec/uucp/libunix/work.c b/gnu/libexec/uucp/libunix/work.c
index 8744347aeb44..f5cdb7969e17 100644
--- a/gnu/libexec/uucp/libunix/work.c
+++ b/gnu/libexec/uucp/libunix/work.c
@@ -1,7 +1,7 @@
/* work.c
Routines to read command files.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char work_rcsid[] = "$Id: work.c,v 1.1 1993/08/05 18:24:45 conklin Exp $";
+const char work_rcsid[] = "$Id: work.c,v 1.2 1994/05/07 18:11:41 ache Exp $";
#endif
#include "uudefs.h"
@@ -55,10 +55,25 @@ static int iswork_cmp P((constpointer pkey, constpointer pdatum));
/* These functions can support multiple actions going on at once.
This allows the UUCP package to send and receive multiple files at
- the same time. This is a very flexible feature, but I'm not sure
- it will actually be used all that much.
+ the same time. */
- The ssfile structure holds a command file name and all the lines
+/* To avoid wasting a lot of time scanning the spool directory, which
+ might cause the remote system to time out, we limit each scan to
+ pick up at most a certain number of files. */
+#define COMMANDS_PER_SCAN (200)
+
+/* The ssfilename structure holds the name of a work file, as well as
+ its grade. */
+
+struct ssfilename
+{
+ char *zfile;
+ char bgrade;
+ /* Some compiler may need this, and it won't normally hurt. */
+ char bdummy;
+};
+
+/* The ssfile structure holds a command file name and all the lines
read in from that command file. The union within the ssline
structure initially holds a line from the file and then holds a
pointer back to the ssfile structure; a pointer to this union is
@@ -77,6 +92,9 @@ struct ssline
struct ssfile
{
char *zfile;
+ char bgrade;
+ /* bdummy is needed for some buggy compilers. */
+ char bdummy;
int clines;
int cdid;
struct ssline aslines[CFILELINES];
@@ -84,7 +102,7 @@ struct ssfile
/* Static variables for the work scan. */
-static char **azSwork_files;
+static struct ssfilename *asSwork_files;
static size_t cSwork_files;
static size_t iSwork_file;
static struct ssfile *qSwork_file;
@@ -182,10 +200,10 @@ iswork_cmp (pkey, pdatum)
constpointer pkey;
constpointer pdatum;
{
- const char * const *pzkey = (const char * const *) pkey;
- const char * const *pzdatum = (const char * const *) pdatum;
+ const struct ssfilename *qkey = (const struct ssfilename *) pkey;
+ const struct ssfilename *qdatum = (const struct ssfilename *) pdatum;
- return strcmp (*pzkey, *pzdatum);
+ return strcmp (qkey->zfile, qdatum->zfile);
}
/* See whether there is any work to do for a particular system. */
@@ -309,7 +327,8 @@ fsysdep_get_work_init (qsys, bgrade)
(bad) qsort implementations are very slow when given a sorted
array, which causes particularly bad effects here. */
if (chad > 0)
- qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp);
+ qsort ((pointer) asSwork_files, chad, sizeof (struct ssfilename),
+ iswork_cmp);
#if SPOOLDIR_SVR4
qgdir = qdir;
@@ -342,6 +361,7 @@ fsysdep_get_work_init (qsys, bgrade)
{
char bfilegrade;
char *zname;
+ struct ssfilename slook;
#if ! SPOOLDIR_SVR4
zname = zbufcpy (qentry->d_name);
@@ -350,13 +370,14 @@ fsysdep_get_work_init (qsys, bgrade)
bfilegrade = qgentry->d_name[0];
#endif
+ slook.zfile = zname;
if (! fswork_file (qsys->uuconf_zname, qentry->d_name,
&bfilegrade)
|| UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0
- || (azSwork_files != NULL
- && bsearch ((pointer) &zname,
- (pointer) azSwork_files,
- chad, sizeof (char *),
+ || (asSwork_files != NULL
+ && bsearch ((pointer) &slook,
+ (pointer) asSwork_files,
+ chad, sizeof (struct ssfilename),
iswork_cmp) != NULL))
ubuffree (zname);
else
@@ -368,18 +389,24 @@ fsysdep_get_work_init (qsys, bgrade)
if (cSwork_files >= callocated)
{
callocated += CWORKFILES;
- azSwork_files =
- (char **) xrealloc ((pointer) azSwork_files,
- callocated * sizeof (char *));
+ asSwork_files =
+ ((struct ssfilename *)
+ xrealloc ((pointer) asSwork_files,
+ (callocated * sizeof (struct ssfilename))));
}
- azSwork_files[cSwork_files] = zname;
+ asSwork_files[cSwork_files].zfile = zname;
+ asSwork_files[cSwork_files].bgrade = bfilegrade;
++cSwork_files;
+ if (cSwork_files - chad > COMMANDS_PER_SCAN)
+ break;
}
}
#if SPOOLDIR_SVR4
closedir (qdir);
+ if (cSwork_files - chad > COMMANDS_PER_SCAN)
+ break;
}
qdir = qgdir;
#endif
@@ -389,10 +416,10 @@ fsysdep_get_work_init (qsys, bgrade)
/* Sorting the files alphabetically will get the grades in the
right order, since all the file prefixes are the same. */
-
- if (cSwork_files > chad)
- qsort ((pointer) (azSwork_files + chad), cSwork_files - chad,
- sizeof (char *), iswork_cmp);
+ if (cSwork_files > iSwork_file)
+ qsort ((pointer) (asSwork_files + iSwork_file),
+ cSwork_files - iSwork_file,
+ sizeof (struct ssfilename), iswork_cmp);
return TRUE;
}
@@ -417,7 +444,7 @@ fsysdep_get_work (qsys, bgrade, qcmd)
if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines)
qSwork_file = NULL;
- if (azSwork_files == NULL)
+ if (asSwork_files == NULL)
{
qcmd->bcmd = 'H';
return TRUE;
@@ -437,6 +464,7 @@ fsysdep_get_work (qsys, bgrade, qcmd)
char *zline;
size_t cline;
char *zname;
+ char bfilegrade;
/* Read all the lines of a command file into memory. */
do
@@ -464,7 +492,8 @@ fsysdep_get_work (qsys, bgrade, qcmd)
return FALSE;
}
- zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]);
+ zname = zsysdep_in_dir (zdir, asSwork_files[iSwork_file].zfile);
+ bfilegrade = asSwork_files[iSwork_file].bgrade;
++iSwork_file;
@@ -521,6 +550,7 @@ fsysdep_get_work (qsys, bgrade, qcmd)
}
qfile->zfile = zname;
+ qfile->bgrade = bfilegrade;
qfile->clines = iline;
qfile->cdid = 0;
qSwork_file = qfile;
@@ -554,6 +584,7 @@ fsysdep_get_work (qsys, bgrade, qcmd)
qSwork_file->aslines[iline].zline = NULL;
continue;
}
+ qcmd->bgrade = qSwork_file->bgrade;
qSwork_file->aslines[iline].qfile = qSwork_file;
qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]);
@@ -652,14 +683,14 @@ void
usysdep_get_work_free (qsys)
const struct uuconf_system *qsys;
{
- if (azSwork_files != NULL)
+ if (asSwork_files != NULL)
{
size_t i;
for (i = 0; i < cSwork_files; i++)
- ubuffree ((pointer) azSwork_files[i]);
- xfree ((pointer) azSwork_files);
- azSwork_files = NULL;
+ ubuffree ((pointer) asSwork_files[i].zfile);
+ xfree ((pointer) asSwork_files);
+ asSwork_files = NULL;
cSwork_files = 0;
iSwork_file = 0;
}
@@ -710,6 +741,7 @@ zsysdep_save_temp_file (pseq)
if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE,
(const char *) NULL))
{
+ /* Leave the file where it was, not that is much help. */
ubuffree (zto);
return "Could not move file to preservation directory";
}
@@ -743,7 +775,7 @@ zsysdep_jobid (qsys, pseq)
this is a remote file; returning -1 will cause zsfind_file to do
the right thing. */
-char
+int
bsgrade (pseq)
pointer pseq;
{
diff --git a/gnu/libexec/uucp/libunix/xqtfil.c b/gnu/libexec/uucp/libunix/xqtfil.c
index 9edb40f23fef..75cbc5393472 100644
--- a/gnu/libexec/uucp/libunix/xqtfil.c
+++ b/gnu/libexec/uucp/libunix/xqtfil.c
@@ -1,7 +1,7 @@
/* xqtfil.c
Routines to read execute files.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.1 1993/08/05 18:24:46 conklin Exp $";
+const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.2 1994/05/07 18:11:42 ache Exp $";
#endif
#include "uudefs.h"
@@ -144,9 +144,8 @@ zsysdep_get_xqt (pzsystem, pferr)
return NULL;
}
- /* No system name may start with a dot (this is enforced by
- tisystem in sysinf.c). This allows us to quickly skip
- impossible directories. */
+ /* No system name may start with a dot This allows us to
+ quickly skip impossible directories. */
if (qtop->d_name[0] == '.')
continue;
diff --git a/gnu/libexec/uucp/libunix/xqtsub.c b/gnu/libexec/uucp/libunix/xqtsub.c
index 87b558b83086..a7aca2a60efb 100644
--- a/gnu/libexec/uucp/libunix/xqtsub.c
+++ b/gnu/libexec/uucp/libunix/xqtsub.c
@@ -1,7 +1,7 @@
/* xqtsub.c
System dependent functions used only by uuxqt.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 1993/08/05 18:24:47 conklin Exp $";
+const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.2 1994/05/07 18:11:43 ache Exp $";
#endif
#include "uudefs.h"
@@ -89,6 +89,7 @@ zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
boolean *pferr;
{
char **pz;
+ struct stat s;
*pferr = FALSE;
@@ -110,7 +111,16 @@ zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
/* If we already have an absolute path, we can get out
immediately. */
if (**pz == '/')
- return zbufcpy (*pz);
+ {
+ /* Quick error check. */
+ if (stat (*pz, &s) != 0)
+ {
+ ulog (LOG_ERROR, "%s: %s", *pz, strerror (errno));
+ *pferr = TRUE;
+ return NULL;
+ }
+ return zbufcpy (*pz);
+ }
break;
}
}
@@ -124,14 +134,12 @@ zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
for (pz = pzpath; *pz != NULL; pz++)
{
char *zname;
- struct stat s;
zname = zsysdep_in_dir (*pz, zcmd);
if (stat (zname, &s) == 0)
return zname;
}
- *pferr = FALSE;
return NULL;
}
@@ -159,7 +167,8 @@ zsysdep_xqt_local_file (qsys, zfile)
memcpy (zret, zfile + 1, clen);
return zret;
}
- return zsysdep_local_file (zfile, qsys->uuconf_zpubdir);
+ return zsysdep_local_file (zfile, qsys->uuconf_zpubdir,
+ (boolean *) NULL);
}
#if ! ALLOW_FILENAME_ARGUMENTS
@@ -177,9 +186,12 @@ fsysdep_xqt_check_file (qsys, zfile)
{
size_t clen;
+ /* Disallow exact "..", prefix "../", suffix "/..", internal "/../",
+ and restricted absolute paths. */
clen = strlen (zfile);
- if ((clen == sizeof "../" - 1
- && strcmp (zfile, "../") == 0)
+ if ((clen == sizeof ".." - 1
+ && strcmp (zfile, "..") == 0)
+ || strncmp (zfile, "../", sizeof "../" - 1) == 0
|| (clen >= sizeof "/.." - 1
&& strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
|| strstr (zfile, "/../") != NULL
@@ -358,7 +370,7 @@ fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
/* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
aren't already using the shell. */
- ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE,
+ ipid = ixsspawn (pazargs, aidescs, TRUE, FALSE, zxqtdir, TRUE,
! fshell, zpath, qsys->uuconf_zname, zuser);
ierr = errno;
diff --git a/gnu/libexec/uucp/libuuconf/MANIFEST b/gnu/libexec/uucp/libuuconf/MANIFEST
index 8d1eb3646632..98787b59489a 100644
--- a/gnu/libexec/uucp/libuuconf/MANIFEST
+++ b/gnu/libexec/uucp/libuuconf/MANIFEST
@@ -61,6 +61,7 @@ rdlocs.c
rdperm.c
reliab.c
remunk.c
+runuxq.c
sinfo.c
snams.c
split.c
diff --git a/gnu/libexec/uucp/libuuconf/Makefile b/gnu/libexec/uucp/libuuconf/Makefile
index f990bef51581..52a5be2142b9 100644
--- a/gnu/libexec/uucp/libuuconf/Makefile
+++ b/gnu/libexec/uucp/libuuconf/Makefile
@@ -1,19 +1,19 @@
# This is the Makefile for the Taylor UUCP uuconf library
-# $Id: Makefile,v 1.1 1993/08/05 18:24:52 conklin Exp $
+# $Id: Makefile,v 1.2 1994/05/07 18:11:49 ache Exp $
LIB= uuconf
-SRCS= addblk.c addstr.c allblk.c alloc.c base.c bool.c callin.c \
- calout.c chatc.c cmdarg.c cmdfil.c cmdlin.c debfil.c deblev.c \
- diacod.c dial.c diasub.c dnams.c errno.c errstr.c filnam.c \
- freblk.c fredia.c free.c freprt.c fresys.c grdcmp.c hdial.c \
- hdnams.c hinit.c hlocnm.c hport.c hrmunk.c hsinfo.c hsnams.c \
- hsys.c hunk.c iniglb.c init.c int.c lckdir.c lineno.c llocnm.c \
- local.c locnm.c logfil.c maxuxq.c mrgblk.c paramc.c port.c \
- prtsub.c pubdir.c rdlocs.c rdperm.c reliab.c remunk.c sinfo.c \
- snams.c split.c spool.c stafil.c syssub.c tcalou.c tdial.c \
- tdialc.c tdnams.c tgcmp.c thread.c time.c tinit.c tlocnm.c \
- tport.c tportc.c tsinfo.c tsnams.c tsys.c tval.c ugtlin.c \
- unk.c val.c vinit.c vport.c vsinfo.c vsnams.c vsys.c
+SRCS = addblk.c addstr.c allblk.c alloc.c base.c bool.c callin.c \
+ calout.c chatc.c cmdarg.c cmdfil.c cmdlin.c debfil.c deblev.c \
+ diacod.c dial.c diasub.c dnams.c errno.c errstr.c filnam.c \
+ freblk.c fredia.c free.c freprt.c fresys.c grdcmp.c hdial.c \
+ hdnams.c hinit.c hlocnm.c hport.c hrmunk.c hsinfo.c hsnams.c \
+ hsys.c hunk.c iniglb.c init.c int.c lckdir.c lineno.c llocnm.c \
+ local.c locnm.c logfil.c maxuxq.c mrgblk.c paramc.c port.c \
+ prtsub.c pubdir.c rdlocs.c rdperm.c reliab.c remunk.c runuxq.c \
+ sinfo.c snams.c split.c spool.c stafil.c syssub.c tcalou.c \
+ tdial.c tdialc.c tdnams.c tgcmp.c thread.c time.c tinit.c \
+ tlocnm.c tport.c tportc.c tsinfo.c tsnams.c tsys.c tval.c \
+ ugtlin.c unk.c val.c vinit.c vport.c vsinfo.c vsnams.c vsys.c
CFLAGS+= -I$(.CURDIR)/../common_sources \
-DNEWCONFIGLIB=\"$(newconfigdir)\"\
-DOLDCONFIGLIB=\"$(oldconfigdir)\"
diff --git a/gnu/libexec/uucp/libuuconf/README b/gnu/libexec/uucp/libuuconf/README
index 64a5eecf03a5..b9a2156c86dc 100644
--- a/gnu/libexec/uucp/libuuconf/README
+++ b/gnu/libexec/uucp/libuuconf/README
@@ -1,8 +1,8 @@
This is the README file for the beta release of the uuconf library.
It was written by Ian Lance Taylor. I can be reached at ian@airs.com,
-or, equivalently, uunet!airs!ian, or c/o Infinity Development Systems,
-P.O. Box 520, Waltham MA, 02254.
+or, equivalently, uunet!cygint!airs!ian, or c/o Cygnus Support, 4th
+Floor, Building 200, 1 Kendall Square, Cambridge MA, 02139, USA.
This package is covered by the Gnu Library General Public License.
See the file COPYING.LIB for details. If you would like to do
diff --git a/gnu/libexec/uucp/libuuconf/addblk.c b/gnu/libexec/uucp/libuuconf/addblk.c
index 49517273c924..4a3ecdd3f024 100644
--- a/gnu/libexec/uucp/libuuconf/addblk.c
+++ b/gnu/libexec/uucp/libuuconf/addblk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_addblk_rcsid[] = "$Id: addblk.c,v 1.1 1993/08/05 18:24:56 conklin Exp $";
+const char _uuconf_addblk_rcsid[] = "$Id: addblk.c,v 1.2 1994/05/07 18:11:51 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/addstr.c b/gnu/libexec/uucp/libuuconf/addstr.c
index 635b63ebd67d..17f62af06976 100644
--- a/gnu/libexec/uucp/libuuconf/addstr.c
+++ b/gnu/libexec/uucp/libuuconf/addstr.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_addstr_rcsid[] = "$Id: addstr.c,v 1.1 1993/08/05 18:24:57 conklin Exp $";
+const char _uuconf_addstr_rcsid[] = "$Id: addstr.c,v 1.2 1994/05/07 18:11:52 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/allblk.c b/gnu/libexec/uucp/libuuconf/allblk.c
index 1c61331e6c80..4fe467cb0a88 100644
--- a/gnu/libexec/uucp/libuuconf/allblk.c
+++ b/gnu/libexec/uucp/libuuconf/allblk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_allblk_rcsid[] = "$Id: allblk.c,v 1.1 1993/08/05 18:24:58 conklin Exp $";
+const char _uuconf_allblk_rcsid[] = "$Id: allblk.c,v 1.2 1994/05/07 18:11:53 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/alloc.c b/gnu/libexec/uucp/libuuconf/alloc.c
index 9b9c90649646..ed789403a3ed 100644
--- a/gnu/libexec/uucp/libuuconf/alloc.c
+++ b/gnu/libexec/uucp/libuuconf/alloc.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_alloc_rcsid[] = "$Id: alloc.c,v 1.1 1993/08/05 18:24:59 conklin Exp $";
+const char _uuconf_alloc_rcsid[] = "$Id: alloc.c,v 1.2 1994/05/07 18:11:54 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/alloc.h b/gnu/libexec/uucp/libuuconf/alloc.h
index c5c9cad8e32b..d6949ab5005a 100644
--- a/gnu/libexec/uucp/libuuconf/alloc.h
+++ b/gnu/libexec/uucp/libuuconf/alloc.h
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* This header file is private to the uuconf memory allocation
diff --git a/gnu/libexec/uucp/libuuconf/base.c b/gnu/libexec/uucp/libuuconf/base.c
index 9ab35826539d..0cd9e2c36177 100644
--- a/gnu/libexec/uucp/libuuconf/base.c
+++ b/gnu/libexec/uucp/libuuconf/base.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_base_rcsid[] = "$Id: base.c,v 1.1 1993/08/05 18:25:01 conklin Exp $";
+const char _uuconf_base_rcsid[] = "$Id: base.c,v 1.2 1994/05/07 18:11:57 ache Exp $";
#endif
/* This turns a cmdtab_offset table into a uuconf_cmdtab table. Each
diff --git a/gnu/libexec/uucp/libuuconf/bool.c b/gnu/libexec/uucp/libuuconf/bool.c
index fa6e5f666b99..66958c30d169 100644
--- a/gnu/libexec/uucp/libuuconf/bool.c
+++ b/gnu/libexec/uucp/libuuconf/bool.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_bool_rcsid[] = "$Id: bool.c,v 1.1 1993/08/05 18:25:03 conklin Exp $";
+const char _uuconf_bool_rcsid[] = "$Id: bool.c,v 1.2 1994/05/07 18:11:58 ache Exp $";
#endif
/* Parse a boolean string into a variable. This is called by
diff --git a/gnu/libexec/uucp/libuuconf/callin.c b/gnu/libexec/uucp/libuuconf/callin.c
index 94c6130d4972..e8699b1af507 100644
--- a/gnu/libexec/uucp/libuuconf/callin.c
+++ b/gnu/libexec/uucp/libuuconf/callin.c
@@ -1,7 +1,7 @@
/* callin.c
Check a login name and password against the UUCP password file.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,35 +20,46 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_callin_rcsid[] = "$Id: callin.c,v 1.1 1993/08/05 18:25:04 conklin Exp $";
+const char _uuconf_callin_rcsid[] = "$Id: callin.c,v 1.2 1994/05/07 18:11:58 ache Exp $";
#endif
#include <errno.h>
-static int iplogin P((pointer pglobal, int argc, char **argv,
+static int ipcheck P((pointer pglobal, int argc, char **argv,
pointer pvar, pointer pinfo));
+
+struct sinfo
+{
+ int (*pcmpfn) P((int, pointer, const char *));
+ pointer pinfo;
+ boolean ffound;
+ boolean fmatched;
+};
/* Check a login name and password against the UUCP password file.
This looks at the Taylor UUCP password file, but will work even if
- uuconf_taylor_init was not called. */
+ uuconf_taylor_init was not called. It accepts either spaces or
+ colons as field delimiters. */
int
-uuconf_callin (pglobal, zlogin, zpassword)
+uuconf_callin (pglobal, pcmpfn, pinfo)
pointer pglobal;
- const char *zlogin;
- const char *zpassword;
+ int (*pcmpfn) P((int, pointer, const char *));
+ pointer pinfo;
{
struct sglobal *qglobal = (struct sglobal *) pglobal;
int iret;
char **pz;
- struct uuconf_cmdtab as[2];
- char *zfilepass;
+ struct uuconf_cmdtab as[1];
+ struct sinfo s;
+ char *zline;
+ size_t cline;
/* If we have no password file names, fill in the default name. */
if (qglobal->qprocess->pzpwdfiles == NULL)
@@ -66,14 +77,15 @@ uuconf_callin (pglobal, zlogin, zpassword)
return iret;
}
- as[0].uuconf_zcmd = zlogin;
- as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2;
- as[0].uuconf_pvar = (pointer) &zfilepass;
- as[0].uuconf_pifn = iplogin;
+ as[0].uuconf_zcmd = NULL;
- as[1].uuconf_zcmd = NULL;
+ s.pcmpfn = pcmpfn;
+ s.pinfo = pinfo;
+ s.ffound = FALSE;
+ s.fmatched = FALSE;
- zfilepass = NULL;
+ zline = NULL;
+ cline = 0;
iret = UUCONF_SUCCESS;
@@ -91,52 +103,82 @@ uuconf_callin (pglobal, zlogin, zpassword)
break;
}
- iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL,
- (uuconf_cmdtabfn) NULL,
- UUCONF_CMDTABFLAG_CASE, (pointer) NULL);
+ qglobal->ilineno = 0;
+
+ iret = UUCONF_SUCCESS;
+
+ while (getline (&zline, &cline, e) > 0)
+ {
+ char *zcolon;
+
+ ++qglobal->ilineno;
+
+ /* Turn the first two colon characters into spaces. This is
+ a hack to make Unix style passwd files work. */
+ zcolon = strchr (zline, ':');
+ if (zcolon != NULL)
+ {
+ *zcolon = ' ';
+ zcolon = strchr (zcolon, ':');
+ if (zcolon != NULL)
+ *zcolon = ' ';
+ }
+ iret = uuconf_cmd_line (pglobal, zline, as, (pointer) &s,
+ ipcheck, 0, (pointer) NULL);
+ if ((iret & UUCONF_CMDTABRET_EXIT) != 0)
+ {
+ iret &=~ UUCONF_CMDTABRET_EXIT;
+ if (iret != UUCONF_SUCCESS)
+ iret |= UUCONF_ERROR_LINENO;
+ break;
+ }
+
+ iret = UUCONF_SUCCESS;
+ }
+
(void) fclose (e);
- if (iret != UUCONF_SUCCESS || zfilepass != NULL)
+ if (iret != UUCONF_SUCCESS || s.ffound)
break;
}
+ if (zline != NULL)
+ free ((pointer) zline);
+
if (iret != UUCONF_SUCCESS)
{
qglobal->zfilename = *pz;
iret |= UUCONF_ERROR_FILENAME;
}
- else if (zfilepass == NULL
- || strcmp (zfilepass, zpassword) != 0)
+ else if (! s.ffound || ! s.fmatched)
iret = UUCONF_NOT_FOUND;
- if (zfilepass != NULL)
- free ((pointer) zfilepass);
-
return iret;
}
-/* This is called if it is the name we are looking for. The pvar
- argument points to zfilepass, and we set it to the password. */
+/* This is called on each line of the file. It checks to see if the
+ login name from the file is the one we are looking for. If it is,
+ it sets ffound, and then sets fmatched according to whether the
+ password matches or not. */
static int
-iplogin (pglobal, argc, argv, pvar, pinfo)
+ipcheck (pglobal, argc, argv, pvar, pinfo)
pointer pglobal;
int argc;
char **argv;
pointer pvar;
pointer pinfo;
{
- struct sglobal *qglobal = (struct sglobal *) pglobal;
- char **pzpass = (char **) pvar;
+ struct sinfo *q = (struct sinfo *) pinfo;
- *pzpass = strdup (argv[1]);
- if (*pzpass == NULL)
- {
- qglobal->ierrno = errno;
- return (UUCONF_MALLOC_FAILED
- | UUCONF_ERROR_ERRNO
- | UUCONF_CMDTABRET_EXIT);
- }
+ if (argc != 2)
+ return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
+
+ if (! (*q->pcmpfn) (0, q->pinfo, argv[0]))
+ return UUCONF_CMDTABRET_CONTINUE;
+
+ q->ffound = TRUE;
+ q->fmatched = (*q->pcmpfn) (1, q->pinfo, argv[1]) != 0;
return UUCONF_CMDTABRET_EXIT;
}
diff --git a/gnu/libexec/uucp/libuuconf/calout.c b/gnu/libexec/uucp/libuuconf/calout.c
index d73382aedb19..9e847551b911 100644
--- a/gnu/libexec/uucp/libuuconf/calout.c
+++ b/gnu/libexec/uucp/libuuconf/calout.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_calout_rcsid[] = "$Id: calout.c,v 1.1 1993/08/05 18:25:05 conklin Exp $";
+const char _uuconf_calout_rcsid[] = "$Id: calout.c,v 1.2 1994/05/07 18:12:00 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/chatc.c b/gnu/libexec/uucp/libuuconf/chatc.c
index f19f589d2254..409c9b7652d7 100644
--- a/gnu/libexec/uucp/libuuconf/chatc.c
+++ b/gnu/libexec/uucp/libuuconf/chatc.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_chatc_rcsid[] = "$Id: chatc.c,v 1.1 1993/08/05 18:25:06 conklin Exp $";
+const char _uuconf_chatc_rcsid[] = "$Id: chatc.c,v 1.2 1994/05/07 18:12:01 ache Exp $";
#endif
#include <ctype.h>
diff --git a/gnu/libexec/uucp/libuuconf/cmdarg.c b/gnu/libexec/uucp/libuuconf/cmdarg.c
index 39c8d30b4dd3..fbe687063095 100644
--- a/gnu/libexec/uucp/libuuconf/cmdarg.c
+++ b/gnu/libexec/uucp/libuuconf/cmdarg.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_cmdarg_rcsid[] = "$Id: cmdarg.c,v 1.1 1993/08/05 18:25:07 conklin Exp $";
+const char _uuconf_cmdarg_rcsid[] = "$Id: cmdarg.c,v 1.2 1994/05/07 18:12:02 ache Exp $";
#endif
#include <ctype.h>
diff --git a/gnu/libexec/uucp/libuuconf/cmdfil.c b/gnu/libexec/uucp/libuuconf/cmdfil.c
index 074359dbcf41..a116b82652b1 100644
--- a/gnu/libexec/uucp/libuuconf/cmdfil.c
+++ b/gnu/libexec/uucp/libuuconf/cmdfil.c
@@ -1,7 +1,7 @@
/* cmdfil.c
Read and parse commands from a file.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_cmdfil_rcsid[] = "$Id: cmdfil.c,v 1.1 1993/08/05 18:25:08 conklin Exp $";
+const char _uuconf_cmdfil_rcsid[] = "$Id: cmdfil.c,v 1.2 1994/05/07 18:12:03 ache Exp $";
#endif
#include <errno.h>
@@ -99,5 +99,8 @@ uuconf_cmd_file (pglobal, e, qtab, pinfo, pfiunknown, iflags, pblock)
iret = UUCONF_SUCCESS;
}
+ if (zline != NULL)
+ free ((pointer) zline);
+
return iret;
}
diff --git a/gnu/libexec/uucp/libuuconf/cmdlin.c b/gnu/libexec/uucp/libuuconf/cmdlin.c
index cb7f81c92ded..069ed37b64c3 100644
--- a/gnu/libexec/uucp/libuuconf/cmdlin.c
+++ b/gnu/libexec/uucp/libuuconf/cmdlin.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_cmdlin_rcsid[] = "$Id: cmdlin.c,v 1.1 1993/08/05 18:25:09 conklin Exp $";
+const char _uuconf_cmdlin_rcsid[] = "$Id: cmdlin.c,v 1.2 1994/05/07 18:12:04 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/debfil.c b/gnu/libexec/uucp/libuuconf/debfil.c
index c03df4413a58..42ea999ec280 100644
--- a/gnu/libexec/uucp/libuuconf/debfil.c
+++ b/gnu/libexec/uucp/libuuconf/debfil.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_debfil_rcsid[] = "$Id: debfil.c,v 1.1 1993/08/05 18:25:10 conklin Exp $";
+const char _uuconf_debfil_rcsid[] = "$Id: debfil.c,v 1.2 1994/05/07 18:12:05 ache Exp $";
#endif
/* Get the name of the UUCP debugging file. */
diff --git a/gnu/libexec/uucp/libuuconf/deblev.c b/gnu/libexec/uucp/libuuconf/deblev.c
index 8d00f67a5ffd..38956820404f 100644
--- a/gnu/libexec/uucp/libuuconf/deblev.c
+++ b/gnu/libexec/uucp/libuuconf/deblev.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_deblev_rcsid[] = "$Id: deblev.c,v 1.1 1993/08/05 18:25:10 conklin Exp $";
+const char _uuconf_deblev_rcsid[] = "$Id: deblev.c,v 1.2 1994/05/07 18:12:06 ache Exp $";
#endif
/* Get the UUCP debugging level. */
diff --git a/gnu/libexec/uucp/libuuconf/diacod.c b/gnu/libexec/uucp/libuuconf/diacod.c
index 5a5015062129..f5076ea353eb 100644
--- a/gnu/libexec/uucp/libuuconf/diacod.c
+++ b/gnu/libexec/uucp/libuuconf/diacod.c
@@ -1,7 +1,7 @@
/* diacod.c
Translate a dialcode.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_diacod_rcsid[] = "$Id: diacod.c,v 1.1 1993/08/05 18:25:11 conklin Exp $";
+const char _uuconf_diacod_rcsid[] = "$Id: diacod.c,v 1.2 1994/05/07 18:12:07 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/dial.c b/gnu/libexec/uucp/libuuconf/dial.c
index fa2c449885c5..f7f641366487 100644
--- a/gnu/libexec/uucp/libuuconf/dial.c
+++ b/gnu/libexec/uucp/libuuconf/dial.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_dial_rcsid[] = "$Id: dial.c,v 1.1 1993/08/05 18:25:12 conklin Exp $";
+const char _uuconf_dial_rcsid[] = "$Id: dial.c,v 1.2 1994/05/07 18:12:08 ache Exp $";
#endif
/* Find a dialer by name. */
diff --git a/gnu/libexec/uucp/libuuconf/diasub.c b/gnu/libexec/uucp/libuuconf/diasub.c
index 5b99c4aa3d0a..9e49bfb4c711 100644
--- a/gnu/libexec/uucp/libuuconf/diasub.c
+++ b/gnu/libexec/uucp/libuuconf/diasub.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_diasub_rcsid[] = "$Id: diasub.c,v 1.1 1993/08/05 18:25:13 conklin Exp $";
+const char _uuconf_diasub_rcsid[] = "$Id: diasub.c,v 1.2 1994/05/07 18:12:09 ache Exp $";
#endif
/* Clear the information in a dialer. */
diff --git a/gnu/libexec/uucp/libuuconf/dnams.c b/gnu/libexec/uucp/libuuconf/dnams.c
index 35b56ec4f605..3eac1159eae5 100644
--- a/gnu/libexec/uucp/libuuconf/dnams.c
+++ b/gnu/libexec/uucp/libuuconf/dnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_dnams_rcsid[] = "$Id: dnams.c,v 1.1 1993/08/05 18:25:14 conklin Exp $";
+const char _uuconf_dnams_rcsid[] = "$Id: dnams.c,v 1.2 1994/05/07 18:12:10 ache Exp $";
#endif
/* Get all known dialer names. */
diff --git a/gnu/libexec/uucp/libuuconf/errno.c b/gnu/libexec/uucp/libuuconf/errno.c
index 911052894da1..350a26b7e742 100644
--- a/gnu/libexec/uucp/libuuconf/errno.c
+++ b/gnu/libexec/uucp/libuuconf/errno.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_errno_rcsid[] = "$Id: errno.c,v 1.1 1993/08/05 18:25:15 conklin Exp $";
+const char _uuconf_errno_rcsid[] = "$Id: errno.c,v 1.2 1994/05/07 18:12:11 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/errstr.c b/gnu/libexec/uucp/libuuconf/errstr.c
index e04db886fea2..4bca654a2f15 100644
--- a/gnu/libexec/uucp/libuuconf/errstr.c
+++ b/gnu/libexec/uucp/libuuconf/errstr.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_errstr_rcsid[] = "$Id: errstr.c,v 1.1 1993/08/05 18:25:16 conklin Exp $";
+const char _uuconf_errstr_rcsid[] = "$Id: errstr.c,v 1.2 1994/05/07 18:12:12 ache Exp $";
#endif
static char *zeprint_num P((char *zbuf, size_t cbuf, int ival));
diff --git a/gnu/libexec/uucp/libuuconf/filnam.c b/gnu/libexec/uucp/libuuconf/filnam.c
index 7f02f3e2c569..003fb5257ed5 100644
--- a/gnu/libexec/uucp/libuuconf/filnam.c
+++ b/gnu/libexec/uucp/libuuconf/filnam.c
@@ -20,18 +20,18 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_filnam_rcsid[] = "$Id: filnam.c,v 1.1 1993/08/05 18:25:17 conklin Exp $";
+const char _uuconf_filnam_rcsid[] = "$Id: filnam.c,v 1.2 1994/05/07 18:12:13 ache Exp $";
#endif
/* Return the saved file name. */
-const char *
+UUCONF_CONST char *
uuconf_error_filename (pglobal)
pointer pglobal;
{
diff --git a/gnu/libexec/uucp/libuuconf/freblk.c b/gnu/libexec/uucp/libuuconf/freblk.c
index ab16cb78377b..215d0949ae36 100644
--- a/gnu/libexec/uucp/libuuconf/freblk.c
+++ b/gnu/libexec/uucp/libuuconf/freblk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_freblk_rcsid[] = "$Id: freblk.c,v 1.1 1993/08/05 18:25:18 conklin Exp $";
+const char _uuconf_freblk_rcsid[] = "$Id: freblk.c,v 1.2 1994/05/07 18:12:14 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/fredia.c b/gnu/libexec/uucp/libuuconf/fredia.c
index 26d376b916e3..4f6532ec105f 100644
--- a/gnu/libexec/uucp/libuuconf/fredia.c
+++ b/gnu/libexec/uucp/libuuconf/fredia.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_fredia_rcsid[] = "$Id: fredia.c,v 1.1 1993/08/05 18:25:19 conklin Exp $";
+const char _uuconf_fredia_rcsid[] = "$Id: fredia.c,v 1.2 1994/05/07 18:12:15 ache Exp $";
#endif
/* Free the memory allocated for a dialer. */
diff --git a/gnu/libexec/uucp/libuuconf/free.c b/gnu/libexec/uucp/libuuconf/free.c
index 77985645ba6f..b1ac98fb2b3c 100644
--- a/gnu/libexec/uucp/libuuconf/free.c
+++ b/gnu/libexec/uucp/libuuconf/free.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_free_rcsid[] = "$Id: free.c,v 1.1 1993/08/05 18:25:20 conklin Exp $";
+const char _uuconf_free_rcsid[] = "$Id: free.c,v 1.2 1994/05/07 18:12:17 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/freprt.c b/gnu/libexec/uucp/libuuconf/freprt.c
index 30764f64339d..6fdda5aaf0df 100644
--- a/gnu/libexec/uucp/libuuconf/freprt.c
+++ b/gnu/libexec/uucp/libuuconf/freprt.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_freprt_rcsid[] = "$Id: freprt.c,v 1.1 1993/08/05 18:25:21 conklin Exp $";
+const char _uuconf_freprt_rcsid[] = "$Id: freprt.c,v 1.2 1994/05/07 18:12:18 ache Exp $";
#endif
/* Free the memory allocated for a port. */
diff --git a/gnu/libexec/uucp/libuuconf/fresys.c b/gnu/libexec/uucp/libuuconf/fresys.c
index 1bd8635f2d79..a880ec9e9bab 100644
--- a/gnu/libexec/uucp/libuuconf/fresys.c
+++ b/gnu/libexec/uucp/libuuconf/fresys.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_fresys_rcsid[] = "$Id: fresys.c,v 1.1 1993/08/05 18:25:21 conklin Exp $";
+const char _uuconf_fresys_rcsid[] = "$Id: fresys.c,v 1.2 1994/05/07 18:12:19 ache Exp $";
#endif
/* Free the memory allocated for a system. */
diff --git a/gnu/libexec/uucp/libuuconf/grdcmp.c b/gnu/libexec/uucp/libuuconf/grdcmp.c
index 9d80242266f1..ce29d98ba5ab 100644
--- a/gnu/libexec/uucp/libuuconf/grdcmp.c
+++ b/gnu/libexec/uucp/libuuconf/grdcmp.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_grdcmp_rcsid[] = "$Id: grdcmp.c,v 1.1 1993/08/05 18:25:22 conklin Exp $";
+const char _uuconf_grdcmp_rcsid[] = "$Id: grdcmp.c,v 1.2 1994/05/07 18:12:20 ache Exp $";
#endif
#include <ctype.h>
diff --git a/gnu/libexec/uucp/libuuconf/hdial.c b/gnu/libexec/uucp/libuuconf/hdial.c
index 6d070401cba1..dc242e0084a9 100644
--- a/gnu/libexec/uucp/libuuconf/hdial.c
+++ b/gnu/libexec/uucp/libuuconf/hdial.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hdial_rcsid[] = "$Id: hdial.c,v 1.1 1993/08/05 18:25:23 conklin Exp $";
+const char _uuconf_hdial_rcsid[] = "$Id: hdial.c,v 1.2 1994/05/07 18:12:20 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/hdnams.c b/gnu/libexec/uucp/libuuconf/hdnams.c
index 8b87944351da..eec16e96d7f6 100644
--- a/gnu/libexec/uucp/libuuconf/hdnams.c
+++ b/gnu/libexec/uucp/libuuconf/hdnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hdnams_rcsid[] = "$Id: hdnams.c,v 1.1 1993/08/05 18:25:24 conklin Exp $";
+const char _uuconf_hdnams_rcsid[] = "$Id: hdnams.c,v 1.2 1994/05/07 18:12:21 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/hinit.c b/gnu/libexec/uucp/libuuconf/hinit.c
index 785434d03508..3dcf36a5ca89 100644
--- a/gnu/libexec/uucp/libuuconf/hinit.c
+++ b/gnu/libexec/uucp/libuuconf/hinit.c
@@ -1,7 +1,7 @@
/* hinit.c
Initialize for reading HDB configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hinit_rcsid[] = "$Id: hinit.c,v 1.1 1993/08/05 18:25:25 conklin Exp $";
+const char _uuconf_hinit_rcsid[] = "$Id: hinit.c,v 1.2 1994/05/07 18:12:23 ache Exp $";
#endif
#include <errno.h>
@@ -125,7 +125,7 @@ uuconf_hdb_init (ppglobal, zprogram)
--cchars;
if (zline[cchars] == '\n')
zline[cchars] = '\0';
- if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
+ if (zline[0] == '#')
continue;
ctypes = _uuconf_istrsplit (zline, '\0', &pzargs, &cargs);
diff --git a/gnu/libexec/uucp/libuuconf/hlocnm.c b/gnu/libexec/uucp/libuuconf/hlocnm.c
index 810f42a0f60c..a2b02ab083e0 100644
--- a/gnu/libexec/uucp/libuuconf/hlocnm.c
+++ b/gnu/libexec/uucp/libuuconf/hlocnm.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hlocnm_rcsid[] = "$Id: hlocnm.c,v 1.1 1993/08/05 18:25:26 conklin Exp $";
+const char _uuconf_hlocnm_rcsid[] = "$Id: hlocnm.c,v 1.2 1994/05/07 18:12:23 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/hport.c b/gnu/libexec/uucp/libuuconf/hport.c
index 77563214a4d1..c2f9593d31f1 100644
--- a/gnu/libexec/uucp/libuuconf/hport.c
+++ b/gnu/libexec/uucp/libuuconf/hport.c
@@ -1,7 +1,7 @@
/* hport.c
Find a port in the HDB configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hport_rcsid[] = "$Id: hport.c,v 1.1 1993/08/05 18:25:27 conklin Exp $";
+const char _uuconf_hport_rcsid[] = "$Id: hport.c,v 1.2 1994/05/07 18:12:25 ache Exp $";
#endif
#include <errno.h>
@@ -85,6 +85,7 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
char *z, *zprotos, *zport;
long ilow, ihigh;
pointer pblock;
+ char ***ppzdialer;
++qglobal->ilineno;
@@ -202,6 +203,9 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1];
qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
+ ppzdialer = NULL;
}
else if (strcmp (pzsplit[0], "TCP") == 0)
{
@@ -213,43 +217,23 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
| UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX
| UUCONF_RELIABLE_SPECIFIED);
qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[1];
+ ppzdialer = &qport->uuconf_u.uuconf_stcp.uuconf_pzdialer;
}
else if (ctoks >= 5
&& (strcmp (pzsplit[4], "TLI") == 0
|| strcmp (pzsplit[4], "TLIS") == 0))
{
- size_t c;
- char **pzd;
-
qport->uuconf_ttype = UUCONF_PORTTYPE_TLI;
qport->uuconf_u.uuconf_stli.uuconf_zdevice = pzsplit[1];
qport->uuconf_u.uuconf_stli.uuconf_fstream
= strcmp (pzsplit[4], "TLIS") == 0;
qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL;
- pblock = uuconf_malloc_block ();
- if (pblock == NULL)
- {
- qglobal->ierrno = errno;
- iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
- break;
- }
- c = (ctoks - 4) * sizeof (char *);
- pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *));
- if (pzd == NULL)
- {
- qglobal->ierrno = errno;
- uuconf_free_block (pblock);
- iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
- break;
- }
- memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c);
- pzd[ctoks - 4] = NULL;
- qport->uuconf_u.uuconf_stli.uuconf_pzdialer = pzd;
qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL;
qport->uuconf_ireliable
= (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE
| UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX
| UUCONF_RELIABLE_SPECIFIED);
+ ppzdialer = &qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
}
else
{
@@ -273,8 +257,15 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh;
}
qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
+ qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
+ qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
+ ppzdialer = &qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
+ }
+
+ if (ppzdialer != NULL)
+ {
if (ctoks < 5)
- qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
+ *ppzdialer = NULL;
else
{
size_t c;
@@ -299,9 +290,8 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c);
pzd[ctoks - 4] = NULL;
- qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd;
+ *ppzdialer = pzd;
}
- qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
}
if (pifn != NULL)
diff --git a/gnu/libexec/uucp/libuuconf/hrmunk.c b/gnu/libexec/uucp/libuuconf/hrmunk.c
index c028049c1b77..9c88e8af3b0f 100644
--- a/gnu/libexec/uucp/libuuconf/hrmunk.c
+++ b/gnu/libexec/uucp/libuuconf/hrmunk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hrmunk_rcsid[] = "$Id: hrmunk.c,v 1.1 1993/08/05 18:25:28 conklin Exp $";
+const char _uuconf_hrmunk_rcsid[] = "$Id: hrmunk.c,v 1.2 1994/05/07 18:12:26 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/hsinfo.c b/gnu/libexec/uucp/libuuconf/hsinfo.c
index 9e50cbec6a77..d20c00ff9067 100644
--- a/gnu/libexec/uucp/libuuconf/hsinfo.c
+++ b/gnu/libexec/uucp/libuuconf/hsinfo.c
@@ -1,7 +1,7 @@
/* hsinfo.c
Get information about a system from the HDB configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hsinfo_rcsid[] = "$Id: hsinfo.c,v 1.1 1993/08/05 18:25:29 conklin Exp $";
+const char _uuconf_hsinfo_rcsid[] = "$Id: hsinfo.c,v 1.2 1994/05/07 18:12:27 ache Exp $";
#endif
#include <errno.h>
@@ -112,6 +112,8 @@ _uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
FILE *e;
int cchars;
+ qglobal->ilineno = 0;
+
e = fopen (*pz, "r");
if (e == NULL)
{
@@ -122,8 +124,6 @@ _uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
break;
}
- qglobal->ilineno = 0;
-
while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0)
{
int ctoks, ctimes, i;
@@ -258,6 +258,11 @@ _uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
pblock);
if (iret != UUCONF_SUCCESS)
break;
+
+ /* Treat any time/grade setting as both a timegrade and
+ a call-timegrade. */
+ if (bgrade != UUCONF_GRADE_LOW)
+ qset->uuconf_qcalltimegrade = qset->uuconf_qtimegrade;
}
if (iret != UUCONF_SUCCESS)
@@ -355,7 +360,7 @@ _uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
if (iret != UUCONF_SUCCESS)
{
qglobal->zfilename = *pz;
- return iret | UUCONF_ERROR_FILENAME;
+ return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
}
if (pblock == NULL)
diff --git a/gnu/libexec/uucp/libuuconf/hsnams.c b/gnu/libexec/uucp/libuuconf/hsnams.c
index dae09d993c73..a86909fe8725 100644
--- a/gnu/libexec/uucp/libuuconf/hsnams.c
+++ b/gnu/libexec/uucp/libuuconf/hsnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hsnams_rcsid[] = "$Id: hsnams.c,v 1.1 1993/08/05 18:25:30 conklin Exp $";
+const char _uuconf_hsnams_rcsid[] = "$Id: hsnams.c,v 1.2 1994/05/07 18:12:28 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/hsys.c b/gnu/libexec/uucp/libuuconf/hsys.c
index 683978d281fb..dc8d637a436f 100644
--- a/gnu/libexec/uucp/libuuconf/hsys.c
+++ b/gnu/libexec/uucp/libuuconf/hsys.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hsys_rcsid[] = "$Id: hsys.c,v 1.1 1993/08/05 18:25:31 conklin Exp $";
+const char _uuconf_hsys_rcsid[] = "$Id: hsys.c,v 1.2 1994/05/07 18:12:29 ache Exp $";
#endif
/* Get system information from the HDB configuration files. This is a
diff --git a/gnu/libexec/uucp/libuuconf/hunk.c b/gnu/libexec/uucp/libuuconf/hunk.c
index df5fd4fcbbb9..2b471ba238b3 100644
--- a/gnu/libexec/uucp/libuuconf/hunk.c
+++ b/gnu/libexec/uucp/libuuconf/hunk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_hunk_rcsid[] = "$Id: hunk.c,v 1.1 1993/08/05 18:25:33 conklin Exp $";
+const char _uuconf_hunk_rcsid[] = "$Id: hunk.c,v 1.2 1994/05/07 18:12:30 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/iniglb.c b/gnu/libexec/uucp/libuuconf/iniglb.c
index 7642d779de32..6fea99988cae 100644
--- a/gnu/libexec/uucp/libuuconf/iniglb.c
+++ b/gnu/libexec/uucp/libuuconf/iniglb.c
@@ -1,7 +1,7 @@
/* iniglb.c
Initialize the global information structure.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_iniglb_rcsid[] = "$Id: iniglb.c,v 1.1 1993/08/05 18:25:35 conklin Exp $";
+const char _uuconf_iniglb_rcsid[] = "$Id: iniglb.c,v 1.2 1994/05/07 18:12:31 ache Exp $";
#endif
#include <errno.h>
@@ -84,6 +84,7 @@ _uuconf_iinit_global (pqglobal)
qprocess->zdebugfile = DEBUGFILE;
qprocess->zdebug = "";
qprocess->cmaxuuxqts = 0;
+ qprocess->zrunuuxqt = NULL;
qprocess->fv2 = TRUE;
qprocess->fhdb = TRUE;
qprocess->pzdialcodefiles = NULL;
diff --git a/gnu/libexec/uucp/libuuconf/init.c b/gnu/libexec/uucp/libuuconf/init.c
index ccd2ad1d4e6f..65a84406ceda 100644
--- a/gnu/libexec/uucp/libuuconf/init.c
+++ b/gnu/libexec/uucp/libuuconf/init.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_init_rcsid[] = "$Id: init.c,v 1.1 1993/08/05 18:25:36 conklin Exp $";
+const char _uuconf_init_rcsid[] = "$Id: init.c,v 1.2 1994/05/07 18:12:32 ache Exp $";
#endif
/* Initialize the UUCP configuration file reading routines. This is
diff --git a/gnu/libexec/uucp/libuuconf/int.c b/gnu/libexec/uucp/libuuconf/int.c
index 93a274cb546a..dacd75517bff 100644
--- a/gnu/libexec/uucp/libuuconf/int.c
+++ b/gnu/libexec/uucp/libuuconf/int.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_int_rcsid[] = "$Id: int.c,v 1.1 1993/08/05 18:25:37 conklin Exp $";
+const char _uuconf_int_rcsid[] = "$Id: int.c,v 1.2 1994/05/07 18:12:33 ache Exp $";
#endif
/* Parse a string into a variable. This is called by uuconf_cmd_args,
diff --git a/gnu/libexec/uucp/libuuconf/lckdir.c b/gnu/libexec/uucp/libuuconf/lckdir.c
index 286f38a2b5d6..ffba44c221ab 100644
--- a/gnu/libexec/uucp/libuuconf/lckdir.c
+++ b/gnu/libexec/uucp/libuuconf/lckdir.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_lckdir_rcsid[] = "$Id: lckdir.c,v 1.1 1993/08/05 18:25:38 conklin Exp $";
+const char _uuconf_lckdir_rcsid[] = "$Id: lckdir.c,v 1.2 1994/05/07 18:12:34 ache Exp $";
#endif
/* Get the name of the UUCP lock directory. */
diff --git a/gnu/libexec/uucp/libuuconf/lineno.c b/gnu/libexec/uucp/libuuconf/lineno.c
index fdba3b51dace..4c5646bda013 100644
--- a/gnu/libexec/uucp/libuuconf/lineno.c
+++ b/gnu/libexec/uucp/libuuconf/lineno.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_lineno_rcsid[] = "$Id: lineno.c,v 1.1 1993/08/05 18:25:39 conklin Exp $";
+const char _uuconf_lineno_rcsid[] = "$Id: lineno.c,v 1.2 1994/05/07 18:12:35 ache Exp $";
#endif
/* Return the saved line number. */
diff --git a/gnu/libexec/uucp/libuuconf/llocnm.c b/gnu/libexec/uucp/libuuconf/llocnm.c
index bb0d70df6c77..d7b7c0cc1ff7 100644
--- a/gnu/libexec/uucp/libuuconf/llocnm.c
+++ b/gnu/libexec/uucp/libuuconf/llocnm.c
@@ -1,7 +1,7 @@
/* llocnm.c
Get the local name to use, given a login name.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_llocnm_rcsid[] = "$Id: llocnm.c,v 1.1 1993/08/05 18:25:40 conklin Exp $";
+const char _uuconf_llocnm_rcsid[] = "$Id: llocnm.c,v 1.2 1994/05/07 18:12:36 ache Exp $";
#endif
#include <errno.h>
@@ -49,9 +49,12 @@ uuconf_login_localname (pglobal, zlogin, pzname)
#endif
#if HAVE_HDB_CONFIG
- iret = uuconf_hdb_login_localname (pglobal, zlogin, pzname);
- if (iret != UUCONF_NOT_FOUND)
- return iret;
+ if (qglobal->qprocess->fhdb)
+ {
+ iret = uuconf_hdb_login_localname (pglobal, zlogin, pzname);
+ if (iret != UUCONF_NOT_FOUND)
+ return iret;
+ }
#endif
if (qglobal->qprocess->zlocalname != NULL)
diff --git a/gnu/libexec/uucp/libuuconf/local.c b/gnu/libexec/uucp/libuuconf/local.c
index 2e2c843585e9..0cd93b83ac89 100644
--- a/gnu/libexec/uucp/libuuconf/local.c
+++ b/gnu/libexec/uucp/libuuconf/local.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_local_rcsid[] = "$Id: local.c,v 1.1 1993/08/05 18:25:40 conklin Exp $";
+const char _uuconf_local_rcsid[] = "$Id: local.c,v 1.2 1994/05/07 18:12:37 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/locnm.c b/gnu/libexec/uucp/libuuconf/locnm.c
index 14cf4dd5fb8b..76b2e8702b87 100644
--- a/gnu/libexec/uucp/libuuconf/locnm.c
+++ b/gnu/libexec/uucp/libuuconf/locnm.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_locnm_rcsid[] = "$Id: locnm.c,v 1.1 1993/08/05 18:25:41 conklin Exp $";
+const char _uuconf_locnm_rcsid[] = "$Id: locnm.c,v 1.2 1994/05/07 18:12:38 ache Exp $";
#endif
/* Get the local node name. */
diff --git a/gnu/libexec/uucp/libuuconf/logfil.c b/gnu/libexec/uucp/libuuconf/logfil.c
index bcfb4fa1b104..677d8d4a428f 100644
--- a/gnu/libexec/uucp/libuuconf/logfil.c
+++ b/gnu/libexec/uucp/libuuconf/logfil.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_logfil_rcsid[] = "$Id: logfil.c,v 1.1 1993/08/05 18:25:42 conklin Exp $";
+const char _uuconf_logfil_rcsid[] = "$Id: logfil.c,v 1.2 1994/05/07 18:12:39 ache Exp $";
#endif
/* Get the name of the UUCP log file. */
diff --git a/gnu/libexec/uucp/libuuconf/maxuxq.c b/gnu/libexec/uucp/libuuconf/maxuxq.c
index d581e4536ad9..66b0db004c61 100644
--- a/gnu/libexec/uucp/libuuconf/maxuxq.c
+++ b/gnu/libexec/uucp/libuuconf/maxuxq.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_maxuxq_rcsid[] = "$Id: maxuxq.c,v 1.1 1993/08/05 18:25:43 conklin Exp $";
+const char _uuconf_maxuxq_rcsid[] = "$Id: maxuxq.c,v 1.2 1994/05/07 18:12:40 ache Exp $";
#endif
/* Get the maximum number of simultaneous uuxqt executions. When
diff --git a/gnu/libexec/uucp/libuuconf/mrgblk.c b/gnu/libexec/uucp/libuuconf/mrgblk.c
index 297969724b82..f34ab58c8b22 100644
--- a/gnu/libexec/uucp/libuuconf/mrgblk.c
+++ b/gnu/libexec/uucp/libuuconf/mrgblk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_mrgblk_rcsid[] = "$Id: mrgblk.c,v 1.1 1993/08/05 18:25:44 conklin Exp $";
+const char _uuconf_mrgblk_rcsid[] = "$Id: mrgblk.c,v 1.2 1994/05/07 18:12:41 ache Exp $";
#endif
#include "alloc.h"
diff --git a/gnu/libexec/uucp/libuuconf/paramc.c b/gnu/libexec/uucp/libuuconf/paramc.c
index a9c4a3d97382..772f802d8486 100644
--- a/gnu/libexec/uucp/libuuconf/paramc.c
+++ b/gnu/libexec/uucp/libuuconf/paramc.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_paramc_rcsid[] = "$Id: paramc.c,v 1.1 1993/08/05 18:25:45 conklin Exp $";
+const char _uuconf_paramc_rcsid[] = "$Id: paramc.c,v 1.2 1994/05/07 18:12:42 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/port.c b/gnu/libexec/uucp/libuuconf/port.c
index 8a704b7628cd..047fe4547b0d 100644
--- a/gnu/libexec/uucp/libuuconf/port.c
+++ b/gnu/libexec/uucp/libuuconf/port.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_port_rcsid[] = "$Id: port.c,v 1.1 1993/08/05 18:25:46 conklin Exp $";
+const char _uuconf_port_rcsid[] = "$Id: port.c,v 1.2 1994/05/07 18:12:43 ache Exp $";
#endif
/* Find a port by name, baud rate, and special purpose function. */
diff --git a/gnu/libexec/uucp/libuuconf/prtsub.c b/gnu/libexec/uucp/libuuconf/prtsub.c
index ee8ca916a30f..d961f736ad33 100644
--- a/gnu/libexec/uucp/libuuconf/prtsub.c
+++ b/gnu/libexec/uucp/libuuconf/prtsub.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_prtsub_rcsid[] = "$Id: prtsub.c,v 1.1 1993/08/05 18:25:47 conklin Exp $";
+const char _uuconf_prtsub_rcsid[] = "$Id: prtsub.c,v 1.2 1994/05/07 18:12:44 ache Exp $";
#endif
/* Clear the information in a port. This can only clear the type
diff --git a/gnu/libexec/uucp/libuuconf/pubdir.c b/gnu/libexec/uucp/libuuconf/pubdir.c
index fcf5207d02ea..4eca22a3eab2 100644
--- a/gnu/libexec/uucp/libuuconf/pubdir.c
+++ b/gnu/libexec/uucp/libuuconf/pubdir.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_pubdir_rcsid[] = "$Id: pubdir.c,v 1.1 1993/08/05 18:25:48 conklin Exp $";
+const char _uuconf_pubdir_rcsid[] = "$Id: pubdir.c,v 1.2 1994/05/07 18:12:45 ache Exp $";
#endif
/* Get the name of the UUCP public directory. */
diff --git a/gnu/libexec/uucp/libuuconf/rdlocs.c b/gnu/libexec/uucp/libuuconf/rdlocs.c
index 488673f4dad6..0f5f0a03871a 100644
--- a/gnu/libexec/uucp/libuuconf/rdlocs.c
+++ b/gnu/libexec/uucp/libuuconf/rdlocs.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_rdlocs_rcsid[] = "$Id: rdlocs.c,v 1.1 1993/08/05 18:25:49 conklin Exp $";
+const char _uuconf_rdlocs_rcsid[] = "$Id: rdlocs.c,v 1.2 1994/05/07 18:12:46 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/rdperm.c b/gnu/libexec/uucp/libuuconf/rdperm.c
index 950ba3bf943b..712dc6fef47e 100644
--- a/gnu/libexec/uucp/libuuconf/rdperm.c
+++ b/gnu/libexec/uucp/libuuconf/rdperm.c
@@ -1,7 +1,7 @@
/* rdperm.c
Read the HDB Permissions file.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_rdperm_rcsid[] = "$Id: rdperm.c,v 1.1 1993/08/05 18:25:50 conklin Exp $";
+const char _uuconf_rdperm_rcsid[] = "$Id: rdperm.c,v 1.2 1994/05/07 18:12:48 ache Exp $";
#endif
#include <errno.h>
@@ -165,7 +165,7 @@ _uuconf_ihread_permissions (qglobal)
--cchars;
if (zline[cchars] == '\n')
zline[cchars] = '\0';
- if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
+ if (zline[0] == '#')
continue;
centries = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
@@ -427,19 +427,25 @@ ihadd_norw (qglobal, ppz, pzno)
char *znew;
int iret;
- csize = strlen (*pz) + 1;
- znew = (char *) uuconf_malloc (qglobal->pblock, csize + 1);
- if (znew == NULL)
+ /* Ignore an attempt to say NOREAD or NOWRITE with an empty
+ string, since it will be interpreted as an attempt to deny
+ everything. */
+ if (**pz != '\0')
{
- qglobal->ierrno = errno;
- return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ csize = strlen (*pz) + 1;
+ znew = (char *) uuconf_malloc (qglobal->pblock, csize + 1);
+ if (znew == NULL)
+ {
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ znew[0] = '!';
+ memcpy ((pointer) (znew + 1), (pointer) *pz, csize);
+ iret = _uuconf_iadd_string (qglobal, znew, FALSE, FALSE, ppz,
+ qglobal->pblock);
+ if (iret != UUCONF_SUCCESS)
+ return iret;
}
- znew[0] = '!';
- memcpy ((pointer) (znew + 1), (pointer) *pz, csize);
- iret = _uuconf_iadd_string (qglobal, znew, FALSE, FALSE, ppz,
- qglobal->pblock);
- if (iret != UUCONF_SUCCESS)
- return iret;
}
return UUCONF_SUCCESS;
diff --git a/gnu/libexec/uucp/libuuconf/reliab.c b/gnu/libexec/uucp/libuuconf/reliab.c
index 048c13d4e66b..faf4d74001c5 100644
--- a/gnu/libexec/uucp/libuuconf/reliab.c
+++ b/gnu/libexec/uucp/libuuconf/reliab.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_reliab_rcsid[] = "$Id: reliab.c,v 1.1 1993/08/05 18:25:51 conklin Exp $";
+const char _uuconf_reliab_rcsid[] = "$Id: reliab.c,v 1.2 1994/05/07 18:12:49 ache Exp $";
#endif
/* Handle the "seven-bit" command for a port or a dialer. The pvar
diff --git a/gnu/libexec/uucp/libuuconf/remunk.c b/gnu/libexec/uucp/libuuconf/remunk.c
index 1e5b714aa265..c88d49b24cb9 100644
--- a/gnu/libexec/uucp/libuuconf/remunk.c
+++ b/gnu/libexec/uucp/libuuconf/remunk.c
@@ -1,7 +1,7 @@
/* remunk.c
Get the name of the remote.unknown shell script.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_remunk_rcsid[] = "$Id: remunk.c,v 1.1 1993/08/05 18:25:52 conklin Exp $";
+const char _uuconf_remunk_rcsid[] = "$Id: remunk.c,v 1.2 1994/05/07 18:12:50 ache Exp $";
#endif
/* Get the name of the remote.unknown shell script. */
@@ -37,9 +37,18 @@ uuconf_remote_unknown (pglobal, pzname)
pointer pglobal;
char **pzname;
{
-#if HAVE_TAYLOR_CONFIG || ! HAVE_HDB_CONFIG
+#if ! HAVE_HDB_CONFIG
return UUCONF_NOT_FOUND;
#else
+#if HAVE_TAYLOR_CONFIG
+ struct sglobal *qglobal = (struct sglobal *) pglobal;
+
+ /* If ``unknown'' commands were used in the config file, then ignore
+ any remote.unknown script. */
+ if (qglobal->qprocess->qunknown != NULL)
+ return UUCONF_NOT_FOUND;
+#endif /* HAVE_TAYLOR_CONFIG */
+
return uuconf_hdb_remote_unknown (pglobal, pzname);
-#endif
+#endif /* HAVE_HDB_CONFIG */
}
diff --git a/gnu/libexec/uucp/libuuconf/runuxq.c b/gnu/libexec/uucp/libuuconf/runuxq.c
new file mode 100644
index 000000000000..01c368b98d33
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/runuxq.c
@@ -0,0 +1,77 @@
+/* maxuxq.c
+ Return how often to spawn a uuxqt process.
+
+ Copyright (C) 1994 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_runuxq_rcsid[] = "$Id: runuxq.c,v 1.1 1994/05/07 18:12:51 ache Exp $";
+#endif
+
+/* Return how often to spawn a uuxqt process. This is either a
+ positive number representing the number of execution files to be
+ received between spawns, or a special code. When using
+ TAYLOR_CONFIG, this is from the ``run-uuxqt'' command in config
+ (the default is UUCONF_RUNUUXQT_ONCE, for compatibility).
+ Otherwise, we return UUCONF_RUNUUXQT_PERCALL for HDB_CONFIG and 10
+ for V2_CONFIG, to emulate traditional HDB and V2 emulations. */
+
+int
+uuconf_runuuxqt (pglobal, pirunuuxqt)
+ pointer pglobal;
+ int *pirunuuxqt;
+{
+#if HAVE_TAYLOR_CONFIG
+ {
+ struct sglobal *qglobal = (struct sglobal *) pglobal;
+ const char *zrun;
+
+ zrun = qglobal->qprocess->zrunuuxqt;
+ if (zrun == NULL
+ || strcasecmp (zrun, "once") == 0)
+ *pirunuuxqt = UUCONF_RUNUUXQT_ONCE;
+ else if (strcasecmp (zrun, "never") == 0)
+ *pirunuuxqt = UUCONF_RUNUUXQT_NEVER;
+ else if (strcasecmp (zrun, "percall") == 0)
+ *pirunuuxqt = UUCONF_RUNUUXQT_PERCALL;
+ else
+ {
+ char *zend;
+
+ *pirunuuxqt = strtol ((char *) qglobal->qprocess->zrunuuxqt,
+ &zend, 10);
+ if (*zend != '\0' || *pirunuuxqt <= 0)
+ *pirunuuxqt = UUCONF_RUNUUXQT_ONCE;
+ }
+ }
+#else /* ! HAVE_TAYLOR_CONFIG */
+#if HAVE_HDB_CONFIG
+ *pirunuuxqt = UUCONF_RUNUUXQT_PERCALL;
+#else /* ! HAVE_HDB_CONFIG */
+ *pirunuuxqt = 10;
+#endif /* ! HAVE_HDB_CONFIG */
+#endif /* ! HAVE_TAYLOR_CONFIG */
+
+ return UUCONF_SUCCESS;
+}
diff --git a/gnu/libexec/uucp/libuuconf/sinfo.c b/gnu/libexec/uucp/libuuconf/sinfo.c
index 6eef6f811199..bb503820894e 100644
--- a/gnu/libexec/uucp/libuuconf/sinfo.c
+++ b/gnu/libexec/uucp/libuuconf/sinfo.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_sinfo_rcsid[] = "$Id: sinfo.c,v 1.1 1993/08/05 18:25:52 conklin Exp $";
+const char _uuconf_sinfo_rcsid[] = "$Id: sinfo.c,v 1.2 1994/05/07 18:12:52 ache Exp $";
#endif
/* Get information about a particular system. We combine the
diff --git a/gnu/libexec/uucp/libuuconf/snams.c b/gnu/libexec/uucp/libuuconf/snams.c
index 190e5cd7f4f7..9e130691a3fc 100644
--- a/gnu/libexec/uucp/libuuconf/snams.c
+++ b/gnu/libexec/uucp/libuuconf/snams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_snams_rcsid[] = "$Id: snams.c,v 1.1 1993/08/05 18:25:53 conklin Exp $";
+const char _uuconf_snams_rcsid[] = "$Id: snams.c,v 1.2 1994/05/07 18:12:53 ache Exp $";
#endif
/* Get all known system names. */
diff --git a/gnu/libexec/uucp/libuuconf/split.c b/gnu/libexec/uucp/libuuconf/split.c
index 2a14753c382e..f9b825a154ca 100644
--- a/gnu/libexec/uucp/libuuconf/split.c
+++ b/gnu/libexec/uucp/libuuconf/split.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_split_rcsid[] = "$Id: split.c,v 1.1 1993/08/05 18:25:54 conklin Exp $";
+const char _uuconf_split_rcsid[] = "$Id: split.c,v 1.2 1994/05/07 18:12:54 ache Exp $";
#endif
#include <ctype.h>
diff --git a/gnu/libexec/uucp/libuuconf/spool.c b/gnu/libexec/uucp/libuuconf/spool.c
index 933f3c102ca5..176e77107243 100644
--- a/gnu/libexec/uucp/libuuconf/spool.c
+++ b/gnu/libexec/uucp/libuuconf/spool.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/05 18:25:55 conklin Exp $";
+const char _uuconf_spool_rcsid[] = "$Id: spool.c,v 1.2 1994/05/07 18:12:55 ache Exp $";
#endif
/* Get the name of the UUCP spool directory. */
diff --git a/gnu/libexec/uucp/libuuconf/stafil.c b/gnu/libexec/uucp/libuuconf/stafil.c
index db95f05aff90..5757c0f885cd 100644
--- a/gnu/libexec/uucp/libuuconf/stafil.c
+++ b/gnu/libexec/uucp/libuuconf/stafil.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_stafil_rcsid[] = "$Id: stafil.c,v 1.1 1993/08/05 18:25:56 conklin Exp $";
+const char _uuconf_stafil_rcsid[] = "$Id: stafil.c,v 1.2 1994/05/07 18:12:56 ache Exp $";
#endif
/* Get the name of the UUCP statistics file. */
diff --git a/gnu/libexec/uucp/libuuconf/syshdr.h b/gnu/libexec/uucp/libuuconf/syshdr.h
index 8ff18a6ca49e..b5a759fd1a6c 100644
--- a/gnu/libexec/uucp/libuuconf/syshdr.h
+++ b/gnu/libexec/uucp/libuuconf/syshdr.h
@@ -1,7 +1,7 @@
/* syshdr.unx -*- C -*-
Unix system header for the uuconf library.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* The root directory (used when setting local-send and local-receive
@@ -82,6 +82,40 @@ extern char *sys_errlist[];
#endif /* ! HAVE_STRERROR */
+/* This macro is used to make a filename found in a configuration file
+ into an absolute path. The zdir argument is the directory to put it
+ in. The zset argument is set to the new string. The fallocated
+ argument is set to TRUE if the new string was allocated. */
+#define MAKE_ABSOLUTE(zset, fallocated, zfile, zdir, pblock) \
+ do \
+ { \
+ if (*(zfile) == '/') \
+ { \
+ (zset) = (zfile); \
+ (fallocated) = FALSE; \
+ } \
+ else \
+ { \
+ size_t abs_cdir, abs_cfile; \
+ char *abs_zret; \
+\
+ abs_cdir = strlen (zdir); \
+ abs_cfile = strlen (zfile); \
+ abs_zret = (char *) uuconf_malloc ((pblock), \
+ abs_cdir + abs_cfile + 2); \
+ (zset) = abs_zret; \
+ (fallocated) = TRUE; \
+ if (abs_zret != NULL) \
+ { \
+ memcpy ((pointer) abs_zret, (pointer) (zdir), abs_cdir); \
+ abs_zret[abs_cdir] = '/'; \
+ memcpy ((pointer) (abs_zret + abs_cdir + 1), \
+ (pointer) (zfile), abs_cfile + 1); \
+ } \
+ } \
+ } \
+ while (0)
+
/* We want to be able to mark the Taylor UUCP system files as close on
exec. */
#if HAVE_FCNTL_H
diff --git a/gnu/libexec/uucp/libuuconf/syssub.c b/gnu/libexec/uucp/libuuconf/syssub.c
index 2a0894950e5f..b27c0eb9747c 100644
--- a/gnu/libexec/uucp/libuuconf/syssub.c
+++ b/gnu/libexec/uucp/libuuconf/syssub.c
@@ -1,7 +1,7 @@
/* syssub.c
System information subroutines.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_syssub_rcsid[] = "$Id: syssub.c,v 1.1 1993/08/05 18:25:59 conklin Exp $";
+const char _uuconf_syssub_rcsid[] = "$Id: syssub.c,v 1.2 1994/05/07 18:12:59 ache Exp $";
#endif
#include <errno.h>
@@ -231,6 +231,71 @@ _uuconf_isystem_default (qglobal, qset, qdefault, faddalternates)
if (qalt->uuconf_qproto_params
== (struct uuconf_proto_param *) &_uuconf_unset)
qalt->uuconf_qproto_params = qdefault->uuconf_qproto_params;
+ else if (qdefault->uuconf_qproto_params != NULL)
+ {
+ int cnew, ca;
+ struct uuconf_proto_param *qd, *qa;
+
+ /* Merge in the default protocol parameters, so that a
+ system with 'g' protocol parameters won't lose the
+ default 'i' protocol parameters. */
+ ca = 0;
+ cnew = 0;
+ for (qd = qdefault->uuconf_qproto_params;
+ qd->uuconf_bproto != '\0';
+ qd++)
+ {
+ int c;
+
+ c = 0;
+ for (qa = qalt->uuconf_qproto_params;
+ (qa->uuconf_bproto != '\0'
+ && qa->uuconf_bproto != qd->uuconf_bproto);
+ qa++)
+ ++c;
+ if (qa->uuconf_bproto == '\0')
+ {
+ ++cnew;
+ ca = c;
+ }
+ }
+
+ if (cnew > 0)
+ {
+ struct uuconf_proto_param *qnew;
+
+ qnew = ((struct uuconf_proto_param *)
+ uuconf_malloc (qset->uuconf_palloc,
+ ((ca + cnew + 1)
+ * sizeof (struct uuconf_proto_param))));
+ if (qnew == NULL)
+ {
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ memcpy ((pointer) qnew, (pointer) qalt->uuconf_qproto_params,
+ ca * sizeof (struct uuconf_proto_param));
+ cnew = 0;
+ for (qd = qdefault->uuconf_qproto_params;
+ qd->uuconf_bproto != '\0';
+ qd++)
+ {
+ for (qa = qalt->uuconf_qproto_params;
+ (qa->uuconf_bproto != '\0'
+ && qa->uuconf_bproto != qd->uuconf_bproto);
+ qa++)
+ ;
+ if (qa->uuconf_bproto == '\0')
+ {
+ qnew[ca + cnew] = *qd;
+ ++cnew;
+ }
+ }
+ qnew[ca + cnew].uuconf_bproto = '\0';
+ uuconf_free (qset->uuconf_palloc, qalt->uuconf_qproto_params);
+ qalt->uuconf_qproto_params = qnew;
+ }
+ }
if (qdefault->uuconf_qalternate != NULL)
qdefault = qdefault->uuconf_qalternate;
diff --git a/gnu/libexec/uucp/libuuconf/tcalou.c b/gnu/libexec/uucp/libuuconf/tcalou.c
index 85f58a9fe89d..9caec19a1257 100644
--- a/gnu/libexec/uucp/libuuconf/tcalou.c
+++ b/gnu/libexec/uucp/libuuconf/tcalou.c
@@ -1,7 +1,7 @@
/* tcalou.c
Find callout login name and password from Taylor UUCP configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tcalou_rcsid[] = "$Id: tcalou.c,v 1.1 1993/08/05 18:26:00 conklin Exp $";
+const char _uuconf_tcalou_rcsid[] = "$Id: tcalou.c,v 1.2 1994/05/07 18:13:00 ache Exp $";
#endif
#include <errno.h>
@@ -99,7 +99,7 @@ uuconf_taylor_callout (pglobal, qsys, pzlog, pzpass)
}
as[0].uuconf_zcmd = qsys->uuconf_zname;
- as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 3;
+ as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 0;
if (*pzlog == NULL)
as[0].uuconf_pvar = (pointer) pzlog;
else
@@ -168,6 +168,9 @@ icsys (pglobal, argc, argv, pvar, pinfo)
char **pzlog = (char **) pvar;
char **pzpass = (char **) pinfo;
+ if (argc < 2 || argc > 3)
+ return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
+
if (pzlog != NULL)
{
*pzlog = strdup (argv[1]);
@@ -182,7 +185,10 @@ icsys (pglobal, argc, argv, pvar, pinfo)
if (pzpass != NULL)
{
- *pzpass = strdup (argv[2]);
+ if (argc < 3)
+ *pzpass = strdup ("");
+ else
+ *pzpass = strdup (argv[2]);
if (*pzpass == NULL)
{
qglobal->ierrno = errno;
diff --git a/gnu/libexec/uucp/libuuconf/tdial.c b/gnu/libexec/uucp/libuuconf/tdial.c
index dbc3f831100b..0ac9117bb5b9 100644
--- a/gnu/libexec/uucp/libuuconf/tdial.c
+++ b/gnu/libexec/uucp/libuuconf/tdial.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tdial_rcsid[] = "$Id: tdial.c,v 1.1 1993/08/05 18:26:01 conklin Exp $";
+const char _uuconf_tdial_rcsid[] = "$Id: tdial.c,v 1.2 1994/05/07 18:13:01 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/tdialc.c b/gnu/libexec/uucp/libuuconf/tdialc.c
index 208cbe11fc48..7ae94800a35f 100644
--- a/gnu/libexec/uucp/libuuconf/tdialc.c
+++ b/gnu/libexec/uucp/libuuconf/tdialc.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tdialc_rcsid[] = "$Id: tdialc.c,v 1.1 1993/08/05 18:26:03 conklin Exp $";
+const char _uuconf_tdialc_rcsid[] = "$Id: tdialc.c,v 1.2 1994/05/07 18:13:02 ache Exp $";
#endif
static int idchat P((pointer pglobal, int argc, char **argv, pointer pvar,
diff --git a/gnu/libexec/uucp/libuuconf/tdnams.c b/gnu/libexec/uucp/libuuconf/tdnams.c
index 85328f586d61..bc8efa272644 100644
--- a/gnu/libexec/uucp/libuuconf/tdnams.c
+++ b/gnu/libexec/uucp/libuuconf/tdnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tdnams_rcsid[] = "$Id: tdnams.c,v 1.1 1993/08/05 18:26:04 conklin Exp $";
+const char _uuconf_tdnams_rcsid[] = "$Id: tdnams.c,v 1.2 1994/05/07 18:13:03 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/tgcmp.c b/gnu/libexec/uucp/libuuconf/tgcmp.c
index 896b71d89c6d..0d6383a26681 100644
--- a/gnu/libexec/uucp/libuuconf/tgcmp.c
+++ b/gnu/libexec/uucp/libuuconf/tgcmp.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tgcmp_rcsid[] = "$Id: tgcmp.c,v 1.1 1993/08/05 18:26:05 conklin Exp $";
+const char _uuconf_tgcmp_rcsid[] = "$Id: tgcmp.c,v 1.2 1994/05/07 18:13:04 ache Exp $";
#endif
/* A comparison function to pass to _uuconf_itime_parse. This
diff --git a/gnu/libexec/uucp/libuuconf/thread.c b/gnu/libexec/uucp/libuuconf/thread.c
index 24f1caee8c1a..bf5dce7f8897 100644
--- a/gnu/libexec/uucp/libuuconf/thread.c
+++ b/gnu/libexec/uucp/libuuconf/thread.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_thread_rcsid[] = "$Id: thread.c,v 1.1 1993/08/05 18:26:06 conklin Exp $";
+const char _uuconf_thread_rcsid[] = "$Id: thread.c,v 1.2 1994/05/07 18:13:05 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/time.c b/gnu/libexec/uucp/libuuconf/time.c
index 33ce3f442c3c..e61bbf2ecee4 100644
--- a/gnu/libexec/uucp/libuuconf/time.c
+++ b/gnu/libexec/uucp/libuuconf/time.c
@@ -1,7 +1,7 @@
/* time.c
Parse a time string into a uuconf_timespan structure.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_time_rcsid[] = "$Id: time.c,v 1.1 1993/08/05 18:26:07 conklin Exp $";
+const char _uuconf_time_rcsid[] = "$Id: time.c,v 1.2 1994/05/07 18:13:06 ache Exp $";
#endif
#include <ctype.h>
@@ -61,6 +61,7 @@ static const struct
{ "fr", 5, 5 },
{ "sa", 6, 6 },
{ "never", -1, -2 },
+ { "none", -1, -2 },
{ NULL, 0, 0 }
};
@@ -106,7 +107,7 @@ _uuconf_itime_parse (qglobal, ztime, ival, cretry, picmp, pqspan, pblock)
{
if ((bfirst == (*pz)[0]
|| (isupper (BUCHAR ((*pz)[0]))
- && bfirst == tolower (BUCHAR ((*pz)[0]))))
+ && (int) bfirst == (int) tolower (BUCHAR ((*pz)[0]))))
&& strcasecmp (ztime, *pz) == 0)
zfound = pz[1];
pz += 2;
diff --git a/gnu/libexec/uucp/libuuconf/tinit.c b/gnu/libexec/uucp/libuuconf/tinit.c
index d8331c810c9a..28b2b5fdd143 100644
--- a/gnu/libexec/uucp/libuuconf/tinit.c
+++ b/gnu/libexec/uucp/libuuconf/tinit.c
@@ -1,7 +1,7 @@
/* tinit.c
Initialize for reading Taylor UUCP configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tinit_rcsid[] = "$Id: tinit.c,v 1.1 1993/08/05 18:26:08 conklin Exp $";
+const char _uuconf_tinit_rcsid[] = "$Id: tinit.c,v 1.2 1994/05/07 18:13:07 ache Exp $";
#endif
#include <errno.h>
@@ -35,8 +35,10 @@ const char _uuconf_tinit_rcsid[] = "$Id: tinit.c,v 1.1 1993/08/05 18:26:08 conkl
static int itset_default P((struct sglobal *qglobal, char ***ppzvar,
const char *zfile));
-static int itadd P((pointer pglobal, int argc, char **argv, pointer pvar,
- pointer pinfo));
+static int itdebug P((pointer pglobal, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int itaddfile P((pointer pglobal, int argc, char **argv, pointer pvar,
+ pointer pinfo));
static int itunknown P((pointer pglobal, int argc, char **argv, pointer pvar,
pointer pinfo));
static int itprogram P((pointer pglobal, int argc, char **argv, pointer pvar,
@@ -62,22 +64,24 @@ static const struct cmdtab_offset asCmds[] =
offsetof (struct sprocess, zstatsfile), NULL },
{ "debugfile", UUCONF_CMDTABTYPE_STRING,
offsetof (struct sprocess, zdebugfile), NULL },
- { "debug", UUCONF_CMDTABTYPE_STRING,
- offsetof (struct sprocess, zdebug), NULL },
+ { "debug", UUCONF_CMDTABTYPE_FN | 0,
+ offsetof (struct sprocess, zdebug), itdebug },
{ "max-uuxqts", UUCONF_CMDTABTYPE_INT,
offsetof (struct sprocess, cmaxuuxqts), NULL },
+ { "run-uuxqt", UUCONF_CMDTABTYPE_STRING,
+ offsetof (struct sprocess, zrunuuxqt), NULL },
{ "sysfile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzsysfiles), itadd },
+ offsetof (struct sprocess, pzsysfiles), itaddfile },
{ "portfile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzportfiles), itadd },
+ offsetof (struct sprocess, pzportfiles), itaddfile },
{ "dialfile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzdialfiles), itadd },
+ offsetof (struct sprocess, pzdialfiles), itaddfile },
{ "dialcodefile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzdialcodefiles), itadd },
+ offsetof (struct sprocess, pzdialcodefiles), itaddfile },
{ "callfile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzcallfiles), itadd },
+ offsetof (struct sprocess, pzcallfiles), itaddfile },
{ "passwdfile", UUCONF_CMDTABTYPE_FN | 0,
- offsetof (struct sprocess, pzpwdfiles), itadd },
+ offsetof (struct sprocess, pzpwdfiles), itaddfile },
{ "unknown", UUCONF_CMDTABTYPE_FN, offsetof (struct sprocess, qunknown),
itunknown },
{ "v2-files", UUCONF_CMDTABTYPE_BOOLEAN,
@@ -227,11 +231,29 @@ uuconf_taylor_init (ppglobal, zprogram, zname)
return UUCONF_SUCCESS;
}
-/* Add new strings to a variable. */
+/* Local interface to the _uuconf_idebug_cmd function, which handles
+ the "debug" command. */
+
+static int
+itdebug (pglobal, argc, argv, pvar, pinfo)
+ pointer pglobal;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sglobal *qglobal = (struct sglobal *) pglobal;
+ char **pzdebug = (char **) pvar;
+
+ return _uuconf_idebug_cmd (qglobal, pzdebug, argc, argv,
+ qglobal->pblock);
+}
+
+/* Add new filenames to a list of files. */
/*ARGSUSED*/
static int
-itadd (pglobal, argc, argv, pvar, pinfo)
+itaddfile (pglobal, argc, argv, pvar, pinfo)
pointer pglobal;
int argc;
char **argv;
@@ -254,7 +276,19 @@ itadd (pglobal, argc, argv, pvar, pinfo)
{
for (i = 1; i < argc; i++)
{
- iret = _uuconf_iadd_string (qglobal, argv[i], TRUE, FALSE, ppz,
+ char *z;
+ boolean fallocated;
+
+ MAKE_ABSOLUTE (z, fallocated, argv[i], NEWCONFIGLIB,
+ qglobal->pblock);
+ if (z == NULL)
+ {
+ qglobal->ierrno = errno;
+ return (UUCONF_MALLOC_FAILED
+ | UUCONF_ERROR_ERRNO
+ | UUCONF_CMDTABRET_EXIT);
+ }
+ iret = _uuconf_iadd_string (qglobal, z, ! fallocated, FALSE, ppz,
qglobal->pblock);
if (iret != UUCONF_SUCCESS)
return iret;
@@ -368,3 +402,60 @@ itset_default (qglobal, ppzvar, zfile)
return _uuconf_iadd_string (qglobal, zadd, FALSE, FALSE, ppzvar,
qglobal->pblock);
}
+
+/* Handle the "debug" command which is documented to take multiple
+ arguments. This is also called by the ``debug'' command in a sys
+ file. It returns a CMDTABRET code. This should probably be in its
+ own file, but the only other place it is called is from tsinfo.c,
+ and any user of tsinfo.c it sure to link in this file as well. */
+
+int
+_uuconf_idebug_cmd (qglobal, pzdebug, argc, argv, pblock)
+ struct sglobal *qglobal;
+ char **pzdebug;
+ int argc;
+ char **argv;
+ pointer pblock;
+{
+ if (argc == 1)
+ {
+ *pzdebug = NULL;
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ else if (argc == 2)
+ {
+ *pzdebug = argv[1];
+ return UUCONF_CMDTABRET_KEEP;
+ }
+ else
+ {
+ size_t cdebug;
+ int i;
+ char *zdebug;
+
+ cdebug = 0;
+ for (i = 1; i < argc; i++)
+ cdebug += strlen (argv[i]) + 1;
+ zdebug = (char *) uuconf_malloc (pblock, cdebug);
+ if (zdebug == NULL)
+ {
+ qglobal->ierrno = errno;
+ return (UUCONF_MALLOC_FAILED
+ | UUCONF_ERROR_ERRNO
+ | UUCONF_CMDTABRET_EXIT);
+ }
+ cdebug = 0;
+ for (i = 1; i < argc; i++)
+ {
+ size_t clen;
+
+ clen = strlen (argv[i]);
+ memcpy (zdebug + cdebug, argv[i], clen);
+ zdebug[cdebug + clen] = ' ';
+ cdebug += clen + 1;
+ }
+ zdebug[cdebug - 1] = '\0';
+ *pzdebug = zdebug;
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+}
diff --git a/gnu/libexec/uucp/libuuconf/tlocnm.c b/gnu/libexec/uucp/libuuconf/tlocnm.c
index be237ea2af6c..aa5cc2c9d466 100644
--- a/gnu/libexec/uucp/libuuconf/tlocnm.c
+++ b/gnu/libexec/uucp/libuuconf/tlocnm.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tlocnm_rcsid[] = "$Id: tlocnm.c,v 1.1 1993/08/05 18:26:09 conklin Exp $";
+const char _uuconf_tlocnm_rcsid[] = "$Id: tlocnm.c,v 1.2 1994/05/07 18:13:08 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/tport.c b/gnu/libexec/uucp/libuuconf/tport.c
index 45f1cb7c07f7..71ac0b3d188a 100644
--- a/gnu/libexec/uucp/libuuconf/tport.c
+++ b/gnu/libexec/uucp/libuuconf/tport.c
@@ -1,7 +1,7 @@
/* tport.c
Find a port in the Taylor UUCP configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tport_rcsid[] = "$Id: tport.c,v 1.1 1993/08/05 18:26:11 conklin Exp $";
+const char _uuconf_tport_rcsid[] = "$Id: tport.c,v 1.2 1994/05/07 18:13:09 ache Exp $";
#endif
#include <errno.h>
@@ -290,6 +290,10 @@ ipunknown (pglobal, argc, argv, pvar, pinfo)
{
struct sglobal *qglobal = (struct sglobal *) pglobal;
struct uuconf_port *qport = (struct uuconf_port *) pinfo;
+ int iret;
- return _uuconf_iport_cmd (qglobal, argc, argv, qport);
+ iret = _uuconf_iport_cmd (qglobal, argc, argv, qport);
+ if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS)
+ iret |= UUCONF_CMDTABRET_EXIT;
+ return iret;
}
diff --git a/gnu/libexec/uucp/libuuconf/tportc.c b/gnu/libexec/uucp/libuuconf/tportc.c
index 6a97870af7c0..394f027878e1 100644
--- a/gnu/libexec/uucp/libuuconf/tportc.c
+++ b/gnu/libexec/uucp/libuuconf/tportc.c
@@ -1,7 +1,7 @@
/* tportc.c
Handle a Taylor UUCP port command.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tportc_rcsid[] = "$Id: tportc.c,v 1.1 1993/08/05 18:26:12 conklin Exp $";
+const char _uuconf_tportc_rcsid[] = "$Id: tportc.c,v 1.2 1994/05/07 18:13:11 ache Exp $";
#endif
#include <errno.h>
@@ -50,7 +50,8 @@ static const char * const azPtype_names[] =
"modem",
"direct",
"tcp",
- "tli"
+ "tli",
+ "pipe"
};
#define CPORT_TYPES (sizeof azPtype_names / sizeof azPtype_names[0])
@@ -104,6 +105,9 @@ static const struct cmdtab_offset asPmodem_cmds[] =
{ "carrier", UUCONF_CMDTABTYPE_BOOLEAN,
offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fcarrier),
NULL },
+ { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN,
+ offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fhardflow),
+ NULL },
{ "dial-device", UUCONF_CMDTABTYPE_STRING,
offsetof (struct uuconf_port,
uuconf_u.uuconf_smodem.uuconf_zdial_device),
@@ -130,6 +134,12 @@ static const struct cmdtab_offset asPdirect_cmds[] =
{ "speed", UUCONF_CMDTABTYPE_LONG,
offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud),
NULL },
+ { "carrier", UUCONF_CMDTABTYPE_BOOLEAN,
+ offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fcarrier),
+ NULL },
+ { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN,
+ offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fhardflow),
+ NULL },
{ NULL, 0, 0, NULL }
};
@@ -141,6 +151,9 @@ static const struct cmdtab_offset asPtcp_cmds[] =
{ "service", UUCONF_CMDTABTYPE_STRING,
offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport),
NULL },
+ { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING,
+ offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_pzdialer),
+ NULL },
{ NULL, 0, 0, NULL }
};
@@ -169,11 +182,22 @@ static const struct cmdtab_offset asPtli_cmds[] =
#define CTLI_CMDS (sizeof asPtli_cmds / sizeof asPtli_cmds[0])
+/* The pipe port command table. */
+static const struct cmdtab_offset asPpipe_cmds[] =
+{
+ { "command", UUCONF_CMDTABTYPE_FULLSTRING,
+ offsetof (struct uuconf_port, uuconf_u.uuconf_spipe.uuconf_pzcmd),
+ NULL },
+ { NULL, 0, 0, NULL}
+};
+
+#define CPIPE_CMDS (sizeof asPpipe_cmds / sizeof asPpipe_cmds[0])
+
#undef max
#define max(i1, i2) ((i1) > (i2) ? (i1) : (i2))
#define CCMDS \
max (max (max (CPORT_CMDS, CSTDIN_CMDS), CMODEM_CMDS), \
- max (max (CDIRECT_CMDS, CTCP_CMDS), CTLI_CMDS))
+ max (max (CDIRECT_CMDS, CTCP_CMDS), max (CTLI_CMDS, CPIPE_CMDS)))
/* Handle a command passed to a port from a Taylor UUCP configuration
file. This can be called when reading either the port file or the
@@ -243,15 +267,19 @@ _uuconf_iport_cmd (qglobal, argc, argv, qport)
qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L;
qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L;
qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
+ qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
break;
case UUCONF_PORTTYPE_DIRECT:
qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = -1;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
break;
case UUCONF_PORTTYPE_TCP:
qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp";
+ qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL;
qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED
| UUCONF_RELIABLE_ENDTOEND
| UUCONF_RELIABLE_RELIABLE
@@ -270,6 +298,9 @@ _uuconf_iport_cmd (qglobal, argc, argv, qport)
| UUCONF_RELIABLE_EIGHT
| UUCONF_RELIABLE_FULLDUPLEX);
break;
+ case UUCONF_PORTTYPE_PIPE:
+ qport->uuconf_u.uuconf_spipe.uuconf_pzcmd = NULL;
+ break;
}
if (fgottype)
@@ -310,6 +341,10 @@ _uuconf_iport_cmd (qglobal, argc, argv, qport)
qcmds = asPtli_cmds;
ccmds = CTLI_CMDS;
break;
+ case UUCONF_PORTTYPE_PIPE:
+ qcmds = asPpipe_cmds;
+ ccmds = CPIPE_CMDS;
+ break;
default:
return UUCONF_SYNTAX_ERROR;
}
@@ -410,23 +445,28 @@ ipdialer (pglobal, argc, argv, pvar, pinfo)
_uuconf_uclear_dialer (qnew);
- clen = strlen (qport->uuconf_zname);
- qnew->uuconf_zname = (char *) uuconf_malloc (qport->uuconf_palloc,
- (clen
- + sizeof " dialer"));
- if (qnew->uuconf_zname == NULL)
+ if (qport->uuconf_zname == NULL)
+ qnew->uuconf_zname = (char *) "default port file dialer";
+ else
{
- qglobal->ierrno = errno;
- return (UUCONF_MALLOC_FAILED
- | UUCONF_ERROR_ERRNO
- | UUCONF_CMDTABRET_EXIT);
+ clen = strlen (qport->uuconf_zname);
+ qnew->uuconf_zname =
+ (char *) uuconf_malloc (qport->uuconf_palloc,
+ clen + sizeof " dialer");
+ if (qnew->uuconf_zname == NULL)
+ {
+ qglobal->ierrno = errno;
+ return (UUCONF_MALLOC_FAILED
+ | UUCONF_ERROR_ERRNO
+ | UUCONF_CMDTABRET_EXIT);
+ }
+
+ memcpy ((pointer) qnew->uuconf_zname,
+ (pointer) qport->uuconf_zname, clen);
+ memcpy ((pointer) (qnew->uuconf_zname + clen),
+ (pointer) " dialer", sizeof " dialer");
}
- memcpy ((pointer) qnew->uuconf_zname,
- (pointer) qport->uuconf_zname, clen);
- memcpy ((pointer) (qnew->uuconf_zname + clen), (pointer) " dialer",
- sizeof " dialer");
-
qnew->uuconf_palloc = qport->uuconf_palloc;
qmodem->uuconf_qdialer = qnew;
diff --git a/gnu/libexec/uucp/libuuconf/tsinfo.c b/gnu/libexec/uucp/libuuconf/tsinfo.c
index 0a04ea0469f2..8d69f6ab05c5 100644
--- a/gnu/libexec/uucp/libuuconf/tsinfo.c
+++ b/gnu/libexec/uucp/libuuconf/tsinfo.c
@@ -1,7 +1,7 @@
/* tsinfo.c
Get information about a system from the Taylor UUCP configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tsinfo_rcsid[] = "$Id: tsinfo.c,v 1.1 1993/08/05 18:26:13 conklin Exp $";
+const char _uuconf_tsinfo_rcsid[] = "$Id: tsinfo.c,v 1.2 1994/05/07 18:13:12 ache Exp $";
#endif
#include <errno.h>
@@ -54,6 +54,7 @@ CMDTABFN (iisize);
CMDTABFN (iibaud_range);
CMDTABFN (iiport);
CMDTABFN (iichat);
+CMDTABFN (iidebug);
CMDTABFN (iicalled_login);
CMDTABFN (iiproto_param);
CMDTABFN (iirequest);
@@ -136,8 +137,8 @@ static const struct cmdtab_offset asIcmds[] =
offsetof (struct uuconf_system, uuconf_qproto_params), iiproto_param },
{ "called-chat", UUCONF_CMDTABTYPE_PREFIX | 0,
offsetof (struct uuconf_system, uuconf_scalled_chat), iichat },
- { "debug", UUCONF_CMDTABTYPE_STRING,
- offsetof (struct uuconf_system, uuconf_zdebug), NULL },
+ { "debug", UUCONF_CMDTABTYPE_FN | 0,
+ offsetof (struct uuconf_system, uuconf_zdebug), iidebug },
{ "max-remote-debug", UUCONF_CMDTABTYPE_STRING,
offsetof (struct uuconf_system, uuconf_zmax_remote_debug), NULL },
{ "send-request", UUCONF_CMDTABTYPE_BOOLEAN,
@@ -708,6 +709,25 @@ iichat (pglobal, argc, argv, pvar, pinfo)
return iret;
}
+/* Local interface to the _uuconf_idebug_cmd function, which handles
+ the "debug" command. */
+
+static int
+iidebug (pglobal, argc, argv, pvar, pinfo)
+ pointer pglobal;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sglobal *qglobal = (struct sglobal *) pglobal;
+ struct sinfo *qinfo = (struct sinfo *) pinfo;
+ char **pzdebug = (char **) pvar;
+
+ return _uuconf_idebug_cmd (qglobal, pzdebug, argc, argv,
+ qinfo->qsys->uuconf_palloc);
+}
+
/* Handle the "called-login" command. This only needs to be in a
function because there can be additional arguments listing the
remote systems which are permitted to use this login name. The
diff --git a/gnu/libexec/uucp/libuuconf/tsnams.c b/gnu/libexec/uucp/libuuconf/tsnams.c
index 2c2029cab6a7..67ec1f969fad 100644
--- a/gnu/libexec/uucp/libuuconf/tsnams.c
+++ b/gnu/libexec/uucp/libuuconf/tsnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tsnams_rcsid[] = "$Id: tsnams.c,v 1.1 1993/08/05 18:26:14 conklin Exp $";
+const char _uuconf_tsnams_rcsid[] = "$Id: tsnams.c,v 1.2 1994/05/07 18:13:13 ache Exp $";
#endif
/* Get all the system names from the Taylor UUCP configuration files.
diff --git a/gnu/libexec/uucp/libuuconf/tsys.c b/gnu/libexec/uucp/libuuconf/tsys.c
index 5d337a9233c3..69a8de2765f2 100644
--- a/gnu/libexec/uucp/libuuconf/tsys.c
+++ b/gnu/libexec/uucp/libuuconf/tsys.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tsys_rcsid[] = "$Id: tsys.c,v 1.1 1993/08/05 18:26:15 conklin Exp $";
+const char _uuconf_tsys_rcsid[] = "$Id: tsys.c,v 1.2 1994/05/07 18:13:14 ache Exp $";
#endif
/* Get system information from the Taylor UUCP configuration files.
diff --git a/gnu/libexec/uucp/libuuconf/tval.c b/gnu/libexec/uucp/libuuconf/tval.c
index 7e263f5d7f17..f02199ed2974 100644
--- a/gnu/libexec/uucp/libuuconf/tval.c
+++ b/gnu/libexec/uucp/libuuconf/tval.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_tval_rcsid[] = "$Id: tval.c,v 1.1 1993/08/05 18:26:16 conklin Exp $";
+const char _uuconf_tval_rcsid[] = "$Id: tval.c,v 1.2 1994/05/07 18:13:15 ache Exp $";
#endif
/* Validate a login name for a system using Taylor UUCP configuration
diff --git a/gnu/libexec/uucp/libuuconf/ugtlin.c b/gnu/libexec/uucp/libuuconf/ugtlin.c
index 79fbec8a97eb..ea85c199c3c6 100644
--- a/gnu/libexec/uucp/libuuconf/ugtlin.c
+++ b/gnu/libexec/uucp/libuuconf/ugtlin.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_ugtlin_rcsid[] = "$Id: ugtlin.c,v 1.1 1993/08/05 18:26:17 conklin Exp $";
+const char _uuconf_ugtlin_rcsid[] = "$Id: ugtlin.c,v 1.2 1994/05/07 18:13:16 ache Exp $";
#endif
/* Read a line from a file with backslash continuations. This updates
diff --git a/gnu/libexec/uucp/libuuconf/unk.c b/gnu/libexec/uucp/libuuconf/unk.c
index 9b3d95369f52..c7eee61de189 100644
--- a/gnu/libexec/uucp/libuuconf/unk.c
+++ b/gnu/libexec/uucp/libuuconf/unk.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_unk_rcsid[] = "$Id: unk.c,v 1.1 1993/08/05 18:26:18 conklin Exp $";
+const char _uuconf_unk_rcsid[] = "$Id: unk.c,v 1.2 1994/05/07 18:13:18 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/uucnfi.h b/gnu/libexec/uucp/libuuconf/uucnfi.h
index 9ce6a62dc763..98122794f104 100644
--- a/gnu/libexec/uucp/libuuconf/uucnfi.h
+++ b/gnu/libexec/uucp/libuuconf/uucnfi.h
@@ -1,7 +1,7 @@
/* uucnfi.h
Internal header file for the uuconf package.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
/* This is the internal header file for the uuconf package. It should
@@ -80,6 +80,8 @@ struct sprocess
const char *zdebug;
/* The maximum number of simultaneously executing uuxqts. */
int cmaxuuxqts;
+ /* How often to spawn a uuxqt process. */
+ const char *zrunuuxqt;
/* Whether we are reading the V2 configuration files. */
boolean fv2;
/* Whether we are reading the HDB configuration files. */
@@ -334,6 +336,12 @@ extern int _uuconf_itime_parse P((struct sglobal *qglobal, char *ztime,
/* A grade comparison function to pass to _uuconf_itime_parse. */
extern int _uuconf_itime_grade_cmp P((long, long));
+/* Parse a debugging string. */
+
+extern int _uuconf_idebug_cmd P((struct sglobal *qglobal,
+ char **pzdebug, int argc,
+ char **argv, pointer pblock));
+
/* Add a string to a NULL terminated list of strings. */
extern int _uuconf_iadd_string P((struct sglobal *qglobal,
char *zadd, boolean fcopy,
diff --git a/gnu/libexec/uucp/libuuconf/val.c b/gnu/libexec/uucp/libuuconf/val.c
index 7ead37b9e96e..7f886bcfd6da 100644
--- a/gnu/libexec/uucp/libuuconf/val.c
+++ b/gnu/libexec/uucp/libuuconf/val.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_val_rcsid[] = "$Id: val.c,v 1.1 1993/08/05 18:26:20 conklin Exp $";
+const char _uuconf_val_rcsid[] = "$Id: val.c,v 1.2 1994/05/07 18:13:20 ache Exp $";
#endif
/* Validate a login name for a system. */
diff --git a/gnu/libexec/uucp/libuuconf/vinit.c b/gnu/libexec/uucp/libuuconf/vinit.c
index 6a76351d709a..22e05b6fccb5 100644
--- a/gnu/libexec/uucp/libuuconf/vinit.c
+++ b/gnu/libexec/uucp/libuuconf/vinit.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_vinit_rcsid[] = "$Id: vinit.c,v 1.1 1993/08/05 18:26:21 conklin Exp $";
+const char _uuconf_vinit_rcsid[] = "$Id: vinit.c,v 1.2 1994/05/07 18:13:21 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/vport.c b/gnu/libexec/uucp/libuuconf/vport.c
index 38ece0f7dfce..b090001ea8ab 100644
--- a/gnu/libexec/uucp/libuuconf/vport.c
+++ b/gnu/libexec/uucp/libuuconf/vport.c
@@ -1,7 +1,7 @@
/* vport.c
Find a port in the V2 configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_vport_rcsid[] = "$Id: vport.c,v 1.1 1993/08/05 18:26:22 conklin Exp $";
+const char _uuconf_vport_rcsid[] = "$Id: vport.c,v 1.2 1994/05/07 18:13:22 ache Exp $";
#endif
#include <errno.h>
@@ -140,6 +140,8 @@ uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1];
qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
+ qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
}
else
{
@@ -162,6 +164,7 @@ uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh;
}
qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
+ qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
if (ctoks < 5)
qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
else
diff --git a/gnu/libexec/uucp/libuuconf/vsinfo.c b/gnu/libexec/uucp/libuuconf/vsinfo.c
index 4e929e092695..99784b2b9711 100644
--- a/gnu/libexec/uucp/libuuconf/vsinfo.c
+++ b/gnu/libexec/uucp/libuuconf/vsinfo.c
@@ -1,7 +1,7 @@
/* vsinfo.c
Get information about a system from the V2 configuration files.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP uuconf library.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_vsinfo_rcsid[] = "$Id: vsinfo.c,v 1.1 1993/08/05 18:26:23 conklin Exp $";
+const char _uuconf_vsinfo_rcsid[] = "$Id: vsinfo.c,v 1.2 1994/05/07 18:13:23 ache Exp $";
#endif
#include <errno.h>
@@ -77,7 +77,7 @@ _uuconf_iv2_system_internal (qglobal, zsystem, qsys)
qglobal->ilineno = 0;
- while ((cchars = getline (&zline, &cline, e)) > 0)
+ while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0)
{
int ctoks, ctimes, i;
struct uuconf_system *qset;
@@ -174,7 +174,7 @@ _uuconf_iv2_system_internal (qglobal, zsystem, qsys)
here. */
zretry = strchr (pzsplit[1], ';');
if (zretry == NULL)
- cretry = 0;
+ cretry = 55;
else
{
*zretry = '\0';
@@ -212,6 +212,11 @@ _uuconf_iv2_system_internal (qglobal, zsystem, qsys)
pblock);
if (iret != UUCONF_SUCCESS)
break;
+
+ /* Treat any time/grade setting as both a timegrade and a
+ call-timegrade. */
+ if (bgrade != UUCONF_GRADE_LOW)
+ qset->uuconf_qcalltimegrade = qset->uuconf_qtimegrade;
}
if (iret != UUCONF_SUCCESS)
@@ -259,6 +264,7 @@ _uuconf_iv2_system_internal (qglobal, zsystem, qsys)
else
qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport
= pzsplit[3];
+ qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL;
}
if (ctoks < 4)
diff --git a/gnu/libexec/uucp/libuuconf/vsnams.c b/gnu/libexec/uucp/libuuconf/vsnams.c
index 68baf9f626b5..ffc477846fd7 100644
--- a/gnu/libexec/uucp/libuuconf/vsnams.c
+++ b/gnu/libexec/uucp/libuuconf/vsnams.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_vsnams_rcsid[] = "$Id: vsnams.c,v 1.1 1993/08/05 18:26:24 conklin Exp $";
+const char _uuconf_vsnams_rcsid[] = "$Id: vsnams.c,v 1.2 1994/05/07 18:13:24 ache Exp $";
#endif
#include <errno.h>
diff --git a/gnu/libexec/uucp/libuuconf/vsys.c b/gnu/libexec/uucp/libuuconf/vsys.c
index 476ff7ca0003..a156564e6683 100644
--- a/gnu/libexec/uucp/libuuconf/vsys.c
+++ b/gnu/libexec/uucp/libuuconf/vsys.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char _uuconf_vsys_rcsid[] = "$Id: vsys.c,v 1.1 1993/08/05 18:26:25 conklin Exp $";
+const char _uuconf_vsys_rcsid[] = "$Id: vsys.c,v 1.2 1994/05/07 18:13:25 ache Exp $";
#endif
/* Get system information from the V2 configuration files. This is a
diff --git a/gnu/libexec/uucp/libuucp/MANIFEST b/gnu/libexec/uucp/libuucp/MANIFEST
index 093924858eac..4fe9c3b318e0 100644
--- a/gnu/libexec/uucp/libuucp/MANIFEST
+++ b/gnu/libexec/uucp/libuucp/MANIFEST
@@ -22,6 +22,7 @@ strncs.c
strrch.c
strstr.c
strtol.c
+strtou.c
xfree.c
xmall.c
xreall.c
diff --git a/gnu/libexec/uucp/libuucp/Makefile b/gnu/libexec/uucp/libuucp/Makefile
index 604ea21c089d..e709431abc6a 100644
--- a/gnu/libexec/uucp/libuucp/Makefile
+++ b/gnu/libexec/uucp/libuucp/Makefile
@@ -1,9 +1,10 @@
# This is the Makefile for the libuucp subdirectory of Taylor UUCP
-# $Id: Makefile,v 1.2 1993/08/16 16:22:34 jtc Exp $
+# $Id: Makefile,v 1.3 1994/05/07 18:13:29 ache Exp $
LIB= uucp
-SRCS= buffer.c crc.c debug.c escape.c getopt.c getop1.c parse.c \
- spool.c status.c xfree.c xmall.c xreall.c getlin.c
+SRCS = buffer.c crc.c debug.c escape.c getopt.c getop1.c parse.c spool.c \
+ status.c xfree.c xmall.c xreall.c \
+ getlin.c
CFLAGS+= -I$(.CURDIR)/../common_sources
NOMAN= noman
diff --git a/gnu/libexec/uucp/libuucp/buffer.c b/gnu/libexec/uucp/libuucp/buffer.c
index c44fa4513942..8ddb2219cf4f 100644
--- a/gnu/libexec/uucp/libuucp/buffer.c
+++ b/gnu/libexec/uucp/libuucp/buffer.c
@@ -1,7 +1,7 @@
/* buffer.c
Manipulate buffers used to hold strings.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of Taylor UUCP.
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -97,13 +97,31 @@ void
ubuffree (z)
char *z;
{
- size_t ioff;
struct sbuf *q;
+ /* The type of ioff should be size_t, but making it int avoids a bug
+ in some versions of the HP/UX compiler, and will always work. */
+ int ioff;
if (z == NULL)
return;
ioff = offsetof (struct sbuf, u);
q = (struct sbuf *) (pointer) (z - ioff);
+
+#ifdef DEBUG_BUFFER
+ {
+ struct sbuf *qlook;
+
+ for (qlook = qBlist; qlook != NULL; qlook = qlook->qnext)
+ {
+ if (qlook == q)
+ {
+ ulog (LOG_ERROR, "ubuffree: Attempt to free buffer twice");
+ abort ();
+ }
+ }
+ }
+#endif
+
q->qnext = qBlist;
qBlist = q;
}
diff --git a/gnu/libexec/uucp/libuucp/debug.c b/gnu/libexec/uucp/libuucp/debug.c
index 86f784154ab6..16c1b54891a8 100644
--- a/gnu/libexec/uucp/libuucp/debug.c
+++ b/gnu/libexec/uucp/libuucp/debug.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
@@ -29,6 +29,8 @@
#include "uudefs.h"
+#if DEBUG > 1
+
/* The debugging level. */
int iDebug;
@@ -63,9 +65,9 @@ idebug_parse (z)
iret = 0;
- for (ztok = strtok (zcopy, ",");
+ for (ztok = strtok (zcopy, ", \t");
ztok != NULL;
- ztok = strtok ((char *) NULL, ","))
+ ztok = strtok ((char *) NULL, ", \t"))
{
if (strcasecmp (ztok, "all") == 0)
{
@@ -91,6 +93,8 @@ idebug_parse (z)
return iret;
}
+#endif /* DEBUG > 1 */
+
/* A debugging routine used when displaying buffers. */
size_t
diff --git a/gnu/libexec/uucp/libuucp/getlin.c b/gnu/libexec/uucp/libuucp/getlin.c
index 1c204e74ee30..983da7d18751 100644
--- a/gnu/libexec/uucp/libuucp/getlin.c
+++ b/gnu/libexec/uucp/libuucp/getlin.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
diff --git a/gnu/libexec/uucp/libuucp/parse.c b/gnu/libexec/uucp/libuucp/parse.c
index e4b72435f5c6..a77350a68773 100644
--- a/gnu/libexec/uucp/libuucp/parse.c
+++ b/gnu/libexec/uucp/libuucp/parse.c
@@ -1,7 +1,7 @@
/* parse.c
Parse a UUCP command string.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char parse_rcsid[] = "$Id: parse.c,v 1.1 1993/08/05 18:26:43 conklin Exp $";
+const char parse_rcsid[] = "$Id: parse.c,v 1.2 1994/05/07 18:13:33 ache Exp $";
#endif
#include "uudefs.h"
@@ -59,6 +59,7 @@ fparse_cmd (zcmd, qcmd)
&& qcmd->bcmd != 'P')
return FALSE;
+ qcmd->bgrade = '\0';
qcmd->pseq = NULL;
qcmd->zfrom = NULL;
qcmd->zto = NULL;
@@ -164,10 +165,21 @@ fparse_cmd (zcmd, qcmd)
z = strtok ((char *) NULL, " \t\n");
if (z == NULL)
return FALSE;
- qcmd->imode = (int) strtol (z, &zend, 8);
+ qcmd->imode = (int) strtol (z, &zend, 0);
if (*zend != '\0')
return FALSE;
+ /* As a magic special case, if the mode came out as the decimal
+ values 666 or 777, assume that they actually meant the octal
+ values. Most systems use a leading zero, but a few do not.
+ Since both 666 and 777 are greater than the largest legal mode
+ value, which is 0777 == 511, this hack does not restrict any
+ legal values. */
+ if (qcmd->imode == 666)
+ qcmd->imode = 0666;
+ else if (qcmd->imode == 777)
+ qcmd->imode = 0777;
+
z = strtok ((char *) NULL, " \t\n");
if (qcmd->bcmd == 'E' && z == NULL)
return FALSE;
diff --git a/gnu/libexec/uucp/libuucp/status.c b/gnu/libexec/uucp/libuucp/status.c
index bee5f83dd08f..65e854ebdca2 100644
--- a/gnu/libexec/uucp/libuucp/status.c
+++ b/gnu/libexec/uucp/libuucp/status.c
@@ -7,6 +7,22 @@
/* Status strings. These must match enum tstatus_type. */
+#if USE_TRADITIONAL_STATUS
+
+const char *azStatus[] =
+{
+ "SUCCESSFUL",
+ "DEVICE FAILED",
+ "DIAL FAILED",
+ "LOGIN FAILED",
+ "STARTUP FAILED",
+ "CONVERSATION FAILED",
+ "TALKING",
+ "WRONG TIME TO CALL"
+};
+
+#else
+
const char *azStatus[] =
{
"Conversation complete",
@@ -18,3 +34,5 @@ const char *azStatus[] =
"Talking",
"Wrong time to call"
};
+
+#endif
diff --git a/gnu/libexec/uucp/libuucp/strtou.c b/gnu/libexec/uucp/libuucp/strtou.c
new file mode 100644
index 000000000000..cd22506da301
--- /dev/null
+++ b/gnu/libexec/uucp/libuucp/strtou.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#define UNSIGNED 1
+
+#include "lib/strtol.c"
diff --git a/gnu/libexec/uucp/sample/Makefile b/gnu/libexec/uucp/sample/Makefile
index c3917289933f..dda3a5939dfe 100644
--- a/gnu/libexec/uucp/sample/Makefile
+++ b/gnu/libexec/uucp/sample/Makefile
@@ -1,6 +1,8 @@
-# $Id: Makefile,v 1.1 1993/10/14 12:18:29 rgrimes Exp $
+# $Id: Makefile,v 1.2 1994/04/25 16:17:59 jkh Exp $
+
+FILES= call.sample config.sample dial.sample dialcode.sample passwd.sample \
+ port.sample sys1.sample sys2.sample
-FILES= call config dial dialcode passwd port sys1 sys2
NOOBJ= noobj
BINOWN= $(owner)
diff --git a/gnu/libexec/uucp/sample/call b/gnu/libexec/uucp/sample/call.sample
index de4190ce6125..de4190ce6125 100644
--- a/gnu/libexec/uucp/sample/call
+++ b/gnu/libexec/uucp/sample/call.sample
diff --git a/gnu/libexec/uucp/sample/config b/gnu/libexec/uucp/sample/config.sample
index e7d683bb0367..e7d683bb0367 100644
--- a/gnu/libexec/uucp/sample/config
+++ b/gnu/libexec/uucp/sample/config.sample
diff --git a/gnu/libexec/uucp/sample/dial b/gnu/libexec/uucp/sample/dial
deleted file mode 100644
index f0d4bdd8aa54..000000000000
--- a/gnu/libexec/uucp/sample/dial
+++ /dev/null
@@ -1,35 +0,0 @@
-# This is an example of dial, the dialer configuration file for Taylor
-# UUCP. To use it, you must compile the package with
-# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy
-# this file to newconfigdir as set in Makefile.in (the default is
-# /usr/local/conf/uucp), and edit it as appropriate for your system.
-
-# Everything after a '#' character is a comment. To uncomment any of
-# the sample lines below, just delete the '#'.
-
-# All dialers named in the port (or sys) file must be described in the
-# dial file. It is also possible to describe a dialer directly in the
-# port (or sys) file.
-
-# This is a typical Hayes modem definition.
-dialer hayes
-
-# The chat script used to dial the phone.
-# This means:
-# 1) expect nothing (i.e., continue with step 2)
-# 2) send "ATZ", then a carriage return, then sleep for 1 to 2
-# seconds. The \c means to not send a final carriage return.
-# 3) wait until the modem echoes "OK"
-# 4) send "ATDT", then the telephone number (after translating any
-# dialcodes).
-# 5) wait until the modem echoes "CONNECT"
-chat "" ATZ\r\d\c OK ATDT\T CONNECT
-
-# If we get "BUSY" or "NO CARRIER" during the dial chat script we
-# abort the dial immediately.
-chat-fail BUSY
-chat-fail NO\sCARRIER
-
-# When the call is over, we make sure we hangup the modem.
-complete \d\d+++\d\dATH\r\c
-abort \d\d+++\d\dATH\r\c
diff --git a/gnu/libexec/uucp/sample/dial.sample b/gnu/libexec/uucp/sample/dial.sample
new file mode 100644
index 000000000000..7eb00871b458
--- /dev/null
+++ b/gnu/libexec/uucp/sample/dial.sample
@@ -0,0 +1,39 @@
+# This is an example of dial, the dialer configuration file for Taylor
+# UUCP. To use it, you must compile the package with
+# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy
+# this file to newconfigdir as set in Makefile.in (the default is
+# /usr/local/conf/uucp), and edit it as appropriate for your system.
+
+# Everything after a '#' character is a comment. To uncomment any of
+# the sample lines below, just delete the '#'.
+
+# All dialers named in the port (or sys) file must be described in the
+# dial file. It is also possible to describe a dialer directly in the
+# port (or sys) file.
+
+# This is a typical Hayes modem definition.
+dialer hayes
+
+# The chat script used to dial the phone.
+# This means:
+# 1) expect nothing (i.e., continue with step 2)
+# 2) send "ATZ", then a carriage return, then sleep for 1 to 2
+# seconds. The \c means to not send a final carriage return.
+# 3) wait until the modem echoes "OK"
+# 4) send "ATDT", then the telephone number (after translating any
+# dialcodes).
+# 5) wait until the modem echoes "CONNECT"
+# 6) Wait a little more, if your modem give CONNECT before carrier up
+chat "" ATZ\r\d\c OK ATDT\T CONNECT \p\c
+
+# If we get "BUSY" or "NO CARRIER" during the dial chat script we
+# abort the dial immediately.
+chat-fail BUSY
+chat-fail ERROR
+chat-fail NO\sDIALTONE
+chat-fail NO\sCARRIER
+
+# When the call is over, we make sure we hangup the modem.
+# You don't need this stuff, if you modem can handle DTR drop properly
+complete \d\d+++\d\dATH\r\c
+abort \d\d+++\d\dATH\r\c
diff --git a/gnu/libexec/uucp/sample/dialcode b/gnu/libexec/uucp/sample/dialcode.sample
index 710a07bf7343..710a07bf7343 100644
--- a/gnu/libexec/uucp/sample/dialcode
+++ b/gnu/libexec/uucp/sample/dialcode.sample
diff --git a/gnu/libexec/uucp/sample/passwd b/gnu/libexec/uucp/sample/passwd.sample
index 2b04e13a3435..2b04e13a3435 100644
--- a/gnu/libexec/uucp/sample/passwd
+++ b/gnu/libexec/uucp/sample/passwd.sample
diff --git a/gnu/libexec/uucp/sample/port b/gnu/libexec/uucp/sample/port.sample
index 8e481869b568..8e481869b568 100644
--- a/gnu/libexec/uucp/sample/port
+++ b/gnu/libexec/uucp/sample/port.sample
diff --git a/gnu/libexec/uucp/sample/sys1 b/gnu/libexec/uucp/sample/sys1.sample
index fa9e7709e1cf..fa9e7709e1cf 100644
--- a/gnu/libexec/uucp/sample/sys1
+++ b/gnu/libexec/uucp/sample/sys1.sample
diff --git a/gnu/libexec/uucp/sample/sys2 b/gnu/libexec/uucp/sample/sys2.sample
index 856529a500a0..856529a500a0 100644
--- a/gnu/libexec/uucp/sample/sys2
+++ b/gnu/libexec/uucp/sample/sys2.sample
diff --git a/gnu/libexec/uucp/tstuu.c b/gnu/libexec/uucp/tstuu.c
index ec1066a32e49..3ea3fc435c50 100644
--- a/gnu/libexec/uucp/tstuu.c
+++ b/gnu/libexec/uucp/tstuu.c
@@ -1,7 +1,7 @@
/* tstuu.c
Test the uucp package on a UNIX system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.1 1993/08/05 18:22:27 conklin Exp $";
+const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.2 1994/05/07 18:08:16 ache Exp $";
#endif
#include "sysdep.h"
@@ -46,7 +46,9 @@ const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.1 1993/08/05 18:22:27 conklin Exp $
#endif
#if HAVE_SELECT
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -75,9 +77,11 @@ const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.1 1993/08/05 18:22:27 conklin Exp $
#define O_RDWR 2
#endif
-#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT)
+#if HAVE_TIME_H
+#if ! HAVE_SYS_TIME_H || ! HAVE_SELECT || TIME_WITH_SYS_TIME
#include <time.h>
#endif
+#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
@@ -264,7 +268,7 @@ main (argc, argv)
break;
default:
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ "Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
fprintf (stderr,
"Usage: tstuu [-xn] [-t #] [-u] [-1 cmd] [-2 cmd]\n");
@@ -501,6 +505,9 @@ main (argc, argv)
if (close (oslave1) < 0)
perror ("close");
+ /* This is said to improve the tests on Linux. */
+ sleep (3);
+
if (zDebug != NULL)
fprintf (stderr, "About to exec first process\n");
@@ -538,6 +545,9 @@ main (argc, argv)
if (close (oslave2) < 0)
perror ("close");
+ /* This is said to improve the tests on Linux. */
+ sleep (5);
+
if (zDebug != NULL)
fprintf (stderr, "About to exec second process\n");
@@ -959,14 +969,13 @@ uprepare_test (fmake, itest, fcall_uucico, zsys)
fprintf (e, "port stdin\n");
fprintf (e, "type stdin\n");
- fprintf (e, "pty true\n");
xfclose (e);
e = xfopen ("/usr/tmp/tstuu/Call1", "w");
fprintf (e, "Call out password file\n");
- fprintf (e, "%s test1 pass1\n", zsys);
+ fprintf (e, "%s test1 pass\\s1\n", zsys);
xfclose (e);
@@ -1035,7 +1044,7 @@ uprepare_test (fmake, itest, fcall_uucico, zsys)
e = xfopen ("/usr/tmp/tstuu/Pass2", "w");
fprintf (e, "# Call in password file\n");
- fprintf (e, "test1 pass1\n");
+ fprintf (e, "test1 pass\\s1\n");
xfclose (e);
}
diff --git a/gnu/libexec/uucp/uuchk/Makefile b/gnu/libexec/uucp/uuchk/Makefile
index 7081d94e2a22..8757ec68a731 100644
--- a/gnu/libexec/uucp/uuchk/Makefile
+++ b/gnu/libexec/uucp/uuchk/Makefile
@@ -1,8 +1,10 @@
# Makefile for uuchk
-# $Id: Makefile,v 1.1 1993/08/05 18:27:05 conklin Exp $
+# $Id: Makefile,v 1.3 1994/05/31 05:46:20 ache Exp $
BINDIR= $(sbindir)
BINOWN= $(owner)
+BINGRP= $(group)
+BINMODE= 550
PROG= uuchk
SRCS= uuchk.c
diff --git a/gnu/libexec/uucp/uuchk/uuchk.c b/gnu/libexec/uucp/uuchk/uuchk.c
index 5df394aa2f3c..30d84f892ed3 100644
--- a/gnu/libexec/uucp/uuchk/uuchk.c
+++ b/gnu/libexec/uucp/uuchk/uuchk.c
@@ -1,7 +1,7 @@
/* uuchk.c
Display what we think the permissions of systems are.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uuchk_rcsid[] = "$Id: uuchk.c,v 1.1 1993/08/05 18:27:06 conklin Exp $";
+const char uuchk_rcsid[] = "$Id: uuchk.c,v 1.2 1994/05/07 18:13:37 ache Exp $";
#endif
#include "getopt.h"
@@ -36,6 +36,7 @@ const char uuchk_rcsid[] = "$Id: uuchk.c,v 1.1 1993/08/05 18:27:06 conklin Exp $
/* Local functions. */
static void ukusage P((void));
+static void ukhelp P((void));
static void ukshow P((const struct uuconf_system *qsys,
pointer puuconf));
static int ikshow_port P((struct uuconf_port *qport, pointer pinfo));
@@ -44,6 +45,7 @@ static void ukshow_chat P((const struct uuconf_chat *qchat,
const char *zhdr));
static void ukshow_size P((struct uuconf_timespan *q, boolean fcall,
boolean flocal));
+static void ukshow_reliable P ((int i, const char *zhdr));
static void ukshow_proto_params P((struct uuconf_proto_param *pas,
int cindent));
static void ukshow_time P((const struct uuconf_timespan *));
@@ -62,8 +64,18 @@ struct sinfo
boolean fgot;
};
+/* Program name. */
+static const char *zKprogram;
+
/* Long getopt options. */
-static const struct option asKlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asKlongopts[] =
+{
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -77,7 +89,9 @@ main (argc, argv)
pointer puuconf;
char **pzsystems;
- while ((iopt = getopt_long (argc, argv, "I:x:", asKlongopts,
+ zKprogram = argv[0];
+
+ while ((iopt = getopt_long (argc, argv, "I:vx:", asKlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -92,18 +106,34 @@ main (argc, argv)
information for this program. */
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zKprogram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ ukhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
ukusage ();
- break;
+ /*NOTREACHED*/
}
}
if (optind != argc)
- ukusage ();
+ {
+ fprintf (stderr, "%s: too many arguments", zKprogram);
+ ukusage ();
+ }
iret = uuconf_init (&puuconf, (const char *) NULL, zconfig);
if (iret != UUCONF_SUCCESS)
@@ -113,6 +143,12 @@ main (argc, argv)
if (iret != UUCONF_SUCCESS)
ukuuconf_error (puuconf, iret);
+ if (*pzsystems == NULL)
+ {
+ fprintf (stderr, "%s: no systems found\n", zKprogram);
+ exit (EXIT_FAILURE);
+ }
+
while (*pzsystems != NULL)
{
struct uuconf_system ssys;
@@ -136,18 +172,26 @@ main (argc, argv)
/* Print a usage message and die. */
-static void
-ukusage ()
+static void ukusage ()
{
- fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
- VERSION);
- fprintf (stderr,
- "Usage: uuchk [-I file]\n");
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ fprintf (stderr, "Usage: %s [{-I,--config} file]\n", zKprogram);
+ fprintf (stderr, "Use %s --help for help\n", zKprogram);
exit (EXIT_FAILURE);
}
+
+/* Print a help message. */
+
+static void
+ukhelp ()
+{
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ VERSION);
+ printf ("Usage: %s [{-I,--config} file] [-v] [--version] [--help]\n",
+ zKprogram);
+ printf (" -I,--config file: Set configuration file to use\n");
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
+}
/* Dump out the information for a system. */
@@ -310,6 +354,8 @@ ukshow (qsys, puuconf)
iret = uuconf_callout (puuconf, qsys, &zlogin, &zpass);
if (iret == UUCONF_NOT_FOUND)
printf (" Can not determine login name or password\n");
+ else if (UUCONF_ERROR_VALUE (iret) == UUCONF_FOPEN_FAILED)
+ printf (" Can not read call out file\n");
else if (iret != UUCONF_SUCCESS)
ukuuconf_error (puuconf, iret);
else
@@ -401,7 +447,7 @@ ukshow (qsys, puuconf)
if (fcalled)
{
ukshow_size (qsys->uuconf_qcalled_local_size, FALSE, TRUE);
- ukshow_size (qsys->uuconf_qcalled_remote_size, FALSE, TRUE);
+ ukshow_size (qsys->uuconf_qcalled_remote_size, FALSE, FALSE);
}
if (fcall)
@@ -498,7 +544,9 @@ ikshow_port (qport, pinfo)
struct sinfo *qi = (struct sinfo *) pinfo;
char **pz;
struct uuconf_modem_port *qmodem;
+ struct uuconf_tcp_port *qtcp;
struct uuconf_tli_port *qtli;
+ struct uuconf_pipe_port *qpipe;
qi->fgot = TRUE;
@@ -513,13 +561,21 @@ ikshow_port (qport, pinfo)
if (qport->uuconf_u.uuconf_sdirect.uuconf_zdevice != NULL)
printf (" Device %s\n",
qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
+ else
+ printf (" Using port name as device name\n");
printf (" Speed %ld\n", qport->uuconf_u.uuconf_sdirect.uuconf_ibaud);
+ printf (" Carrier %savailable\n",
+ qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier ? "" : "not ");
+ printf (" Hardware flow control %savailable\n",
+ qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow ? "" : "not ");
break;
case UUCONF_PORTTYPE_MODEM:
qmodem = &qport->uuconf_u.uuconf_smodem;
printf (" Port type modem\n");
if (qmodem->uuconf_zdevice != NULL)
printf (" Device %s\n", qmodem->uuconf_zdevice);
+ else
+ printf (" Using port name as device name\n");
if (qmodem->uuconf_zdial_device != NULL)
printf (" Dial device %s\n", qmodem->uuconf_zdial_device);
printf (" Speed %ld\n", qmodem->uuconf_ibaud);
@@ -528,6 +584,8 @@ ikshow_port (qport, pinfo)
qmodem->uuconf_ihighbaud);
printf (" Carrier %savailable\n",
qmodem->uuconf_fcarrier ? "" : "not ");
+ printf (" Hardware flow control %savailable\n",
+ qmodem->uuconf_fhardflow ? "" : "not ");
if (qmodem->uuconf_qdialer != NULL)
{
printf (" Specially defined dialer\n");
@@ -589,9 +647,17 @@ ikshow_port (qport, pinfo)
printf (" *** No dialer information\n");
break;
case UUCONF_PORTTYPE_TCP:
+ qtcp = &qport->uuconf_u.uuconf_stcp;
printf (" Port type tcp\n");
- printf (" TCP service %s\n",
- qport->uuconf_u.uuconf_stcp.uuconf_zport);
+ printf (" TCP service %s\n", qtcp->uuconf_zport);
+ if (qtcp->uuconf_pzdialer != NULL
+ && qtcp->uuconf_pzdialer[0] != NULL)
+ {
+ printf (" Dialer sequence");
+ for (pz = qtcp->uuconf_pzdialer; *pz != NULL; pz++)
+ printf (" %s", *pz);
+ printf ("\n");
+ }
break;
case UUCONF_PORTTYPE_TLI:
qtli = &qport->uuconf_u.uuconf_stli;
@@ -599,6 +665,8 @@ ikshow_port (qport, pinfo)
qtli->uuconf_fstream ? "S" : "");
if (qtli->uuconf_zdevice != NULL)
printf (" Device %s\n", qtli->uuconf_zdevice);
+ else
+ printf (" Using port name as device name\n");
if (qtli->uuconf_pzpush != NULL)
{
printf (" Push");
@@ -617,6 +685,17 @@ ikshow_port (qport, pinfo)
if (qtli->uuconf_zservaddr != NULL)
printf (" Server address %s\n", qtli->uuconf_zservaddr);
break;
+ case UUCONF_PORTTYPE_PIPE:
+ qpipe = &qport->uuconf_u.uuconf_spipe;
+ printf (" Port type pipe\n");
+ if (qpipe->uuconf_pzcmd != NULL)
+ {
+ printf (" Command");
+ for (pz = qpipe->uuconf_pzcmd; *pz != NULL; pz++)
+ printf (" %s", *pz);
+ printf ("\n");
+ }
+ break;
default:
fprintf (stderr, " CAN'T HAPPEN\n");
break;
@@ -628,6 +707,9 @@ ikshow_port (qport, pinfo)
if (qport->uuconf_zlockname != NULL)
printf (" Will use lockname %s\n", qport->uuconf_zlockname);
+ if ((qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
+ ukshow_reliable (qport->uuconf_ireliable, " ");
+
if (qport->uuconf_qproto_params != NULL)
ukshow_proto_params (qport->uuconf_qproto_params, 3);
@@ -656,6 +738,8 @@ ukshow_dialer (q)
}
ukshow_chat (&q->uuconf_scomplete, " When complete chat");
ukshow_chat (&q->uuconf_sabort, " When aborting chat");
+ if ((q->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
+ ukshow_reliable (q->uuconf_ireliable, " ");
if (q->uuconf_qproto_params != NULL)
ukshow_proto_params (q->uuconf_qproto_params, 4);
}
@@ -744,6 +828,29 @@ ukshow_size (qspan, fcall, flocal)
printf (" (At other times may send files of any size)\n");
}
+/* Show reliability information. */
+
+static void
+ukshow_reliable (i, zhdr)
+ int i;
+ const char *zhdr;
+{
+ printf ("%sCharacteristics:", zhdr);
+ if ((i & UUCONF_RELIABLE_EIGHT) != 0)
+ printf (" eight-bit-clean");
+ else
+ printf (" not-eight-bit-clean");
+ if ((i & UUCONF_RELIABLE_RELIABLE) != 0)
+ printf (" reliable");
+ if ((i & UUCONF_RELIABLE_ENDTOEND) != 0)
+ printf (" end-to-end");
+ if ((i & UUCONF_RELIABLE_FULLDUPLEX) != 0)
+ printf (" fullduplex");
+ else
+ printf (" halfduplex");
+ printf ("\n");
+}
+
/* Show protocol parameters. */
static void
@@ -849,8 +956,8 @@ ukuuconf_error (puuconf, iret)
(void) uuconf_error_string (puuconf, iret, ab, sizeof ab);
if ((iret & UUCONF_ERROR_FILENAME) == 0)
- fprintf (stderr, "uuchk: %s\n", ab);
+ fprintf (stderr, "%s: %s\n", zKprogram, ab);
else
- fprintf (stderr, "uuchk:%s\n", ab);
+ fprintf (stderr, "%s:%s\n", zKprogram, ab);
exit (EXIT_FAILURE);
}
diff --git a/gnu/libexec/uucp/uucico/Makefile b/gnu/libexec/uucp/uucico/Makefile
index 6cd270934bbf..f6ba17130d0c 100644
--- a/gnu/libexec/uucp/uucico/Makefile
+++ b/gnu/libexec/uucp/uucico/Makefile
@@ -1,9 +1,9 @@
# Makefile for uucico
-# $Id: Makefile,v 1.2 1993/08/06 23:38:23 rgrimes Exp $
+# $Id: Makefile,v 1.6 1994/05/31 15:55:43 ache Exp $
BINDIR= $(sbindir)
BINOWN= $(owner)
-BINMODE= 4555
+BINMODE= 4555
PROG= uucico
SRCS= uucico.c trans.c send.c rec.c xcmd.c prot.c protg.c protf.c \
@@ -12,7 +12,7 @@ SRCS= uucico.c trans.c send.c rec.c xcmd.c prot.c protg.c protf.c \
LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
CFLAGS+= -I$(.CURDIR)/../common_sources\
- -DVERSION=\"$(VERSION)\"
+ -DVERSION=\"$(VERSION)\" -DOWNER=\"$(owner)\"
MAN8= uucico.8
diff --git a/gnu/libexec/uucp/uucico/prote.c b/gnu/libexec/uucp/uucico/prote.c
index 9b824651c2f7..c5cb0cf649ad 100644
--- a/gnu/libexec/uucp/uucico/prote.c
+++ b/gnu/libexec/uucp/uucico/prote.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char prote_rcsid[] = "$Id: prote.c,v 1.1 1993/08/05 18:27:09 conklin Exp $";
+const char prote_rcsid[] = "$Id: prote.c,v 1.2 1994/05/07 18:13:43 ache Exp $";
#endif
#include "uudefs.h"
diff --git a/gnu/libexec/uucp/uucico/protf.c b/gnu/libexec/uucp/uucico/protf.c
index 96b213157cee..8ba786ea127c 100644
--- a/gnu/libexec/uucp/uucico/protf.c
+++ b/gnu/libexec/uucp/uucico/protf.c
@@ -1,7 +1,7 @@
/* protf.c
The 'f' protocol.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char protf_rcsid[] = "$Id: protf.c,v 1.1 1993/08/05 18:27:10 conklin Exp $";
+const char protf_rcsid[] = "$Id: protf.c,v 1.2 1994/05/07 18:13:45 ache Exp $";
#endif
#include <ctype.h>
@@ -340,6 +340,10 @@ ffprocess_data (qdaemon, pfexit, pcneed)
{
for (i = iPrecstart; i < CRECBUFLEN && i != iPrecend; i++)
{
+ /* Some systems seem to send characters with parity, so
+ strip the parity bit. */
+ abPrecbuf[i] &= 0x7f;
+
if (abPrecbuf[i] == '\r')
{
int istart;
@@ -395,7 +399,9 @@ ffprocess_data (qdaemon, pfexit, pcneed)
{
int b;
- b = *zfrom++ & 0xff;
+ /* Some systems seem to send characters with parity, so
+ strip the parity bit. */
+ b = *zfrom++ & 0x7f;
if (b < 040 || b > 0176)
{
ulog (LOG_ERROR, "Illegal byte %d", b);
diff --git a/gnu/libexec/uucp/uucico/protg.c b/gnu/libexec/uucp/uucico/protg.c
index 39a79212cf77..0b58197a1da1 100644
--- a/gnu/libexec/uucp/uucico/protg.c
+++ b/gnu/libexec/uucp/uucico/protg.c
@@ -1,7 +1,7 @@
/* protg.c
The 'g' protocol.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char protg_rcsid[] = "$Id: protg.c,v 1.1 1993/08/05 18:27:11 conklin Exp $";
+const char protg_rcsid[] = "$Id: protg.c,v 1.2 1994/05/07 18:13:46 ache Exp $";
#endif
#include <ctype.h>
@@ -346,6 +346,12 @@ static long cGbad_order;
received). */
static long cGremote_rejects;
+/* Number of duplicate RR packets treated as RJ packets. Some UUCP
+ packages appear to never send RJ packets, but only RR packets. If
+ no RJ has been seen, fgprocess_data treats a duplicate RR as an RJ
+ and increments this variable. */
+static long cGremote_duprrs;
+
/* The error level. This is the total number of errors as adjusted by
cGerror_decay. */
static long cGerror_level;
@@ -419,6 +425,7 @@ fgstart (qdaemon, pzlog)
cGbad_checksum = 0;
cGbad_order = 0;
cGremote_rejects = 0;
+ cGremote_duprrs = 0;
cGerror_level = 0;
cGexpect_bad_order = 0;
@@ -440,6 +447,13 @@ fgstart (qdaemon, pzlog)
iseg = 1;
}
+ if (iGrequest_winsize <= 0 || iGrequest_winsize > 7)
+ {
+ ulog (LOG_ERROR, "Illegal window size %d for '%c' protocol",
+ iGrequest_winsize, qdaemon->qproto->bname);
+ iGrequest_winsize = IWINDOW;
+ }
+
fgota = FALSE;
fgotb = FALSE;
for (i = 0; i < cGstartup_retries; i++)
@@ -503,10 +517,14 @@ fgstart (qdaemon, pzlog)
if (! fginit_sendbuffers (TRUE))
return FALSE;
- *pzlog = zbufalc (sizeof "protocol '' packet size window " + 50);
- sprintf (*pzlog, "protocol '%c' packet size %d window %d",
+ *pzlog =
+ zbufalc (sizeof "protocol '' sending packet/window / receiving /"
+ + 64);
+ sprintf (*pzlog,
+ "protocol '%c' sending packet/window %d/%d receiving %d/%d",
qdaemon->qproto->bname, (int) iGremote_packsize,
- (int) iGremote_winsize);
+ (int) iGremote_winsize, (int) iGrequest_packsize,
+ (int) iGrequest_winsize);
return TRUE;
}
@@ -528,6 +546,22 @@ fbiggstart (qdaemon, pzlog)
fGshort_packets = FALSE;
return fgstart (qdaemon, pzlog);
}
+
+/* The 'v' protocol is identical to the 'g' protocol, except that the
+ packet size defaults to 512 bytes. Rather than really get it
+ right, we automatically switch from the usual default of 64 to 512.
+ This won't work correctly if somebody does protocol-parameter v
+ packet-size 64. */
+
+boolean
+fvstart (qdaemon, pzlog)
+ struct sdaemon *qdaemon;
+ char **pzlog;
+{
+ if (iGrequest_packsize == IPACKSIZE)
+ iGrequest_packsize = 1024;
+ return fgstart (qdaemon, pzlog);
+}
/* Exchange initialization messages with the other system.
@@ -671,10 +705,12 @@ fgshutdown (qdaemon)
if (cGbad_hdr != 0
|| cGbad_checksum != 0
|| cGbad_order != 0
- || cGremote_rejects != 0)
+ || cGremote_rejects != 0
+ || cGremote_duprrs != 0)
ulog (LOG_NORMAL,
"Errors: header %ld, checksum %ld, order %ld, remote rejects %ld",
- cGbad_hdr, cGbad_checksum, cGbad_order, cGremote_rejects);
+ cGbad_hdr, cGbad_checksum, cGbad_order,
+ cGremote_duprrs + cGremote_rejects);
/* Reset all the parameters to their default values, so that the
protocol parameters used for this connection do not affect the
@@ -739,7 +775,8 @@ fgsendcmd (qdaemon, z, ilocal, iremote)
}
memcpy (zpacket, z, clen);
- bzero (zpacket + clen, csize - clen);
+ if (csize > clen)
+ bzero (zpacket + clen, csize - clen);
fagain = FALSE;
if (! fgsenddata (qdaemon, zpacket, csize, 0, 0, (long) 0))
@@ -894,7 +931,8 @@ fgsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos)
--zdata;
zdata[0] = (char) cshort;
zdata[-1] = '\0';
- bzero (zdata + cdata + 1, cshort - 1);
+ if (cshort > 1)
+ bzero (zdata + cdata + 1, cshort - 1);
}
else
{
@@ -1568,12 +1606,15 @@ fgprocess_data (qdaemon, fdoacks, freturncontrol, pfexit, pcneed, pffound)
/* Annoyingly, some UUCP packages appear to send an RR packet
rather than an RJ packet when they want a packet to be
- resent. If we get a duplicate RR, we treat it as an RJ. */
+ resent. If we get a duplicate RR and we've never seen an RJ,
+ we treat the RR as an RJ. */
fduprr = FALSE;
- if (CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL
+ if (cGremote_rejects == 0
+ && CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL
&& CONTROL_XXX (ab[IFRAME_CONTROL]) == RR
&& iGremote_ack == CONTROL_YYY (ab[IFRAME_CONTROL])
- && INEXTSEQ (iGremote_ack) != iGsendseq)
+ && INEXTSEQ (iGremote_ack) != iGsendseq
+ && iGretransmit_seq != -1)
{
DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL,
"fgprocess_data: Treating duplicate RR as RJ");
@@ -1581,11 +1622,12 @@ fgprocess_data (qdaemon, fdoacks, freturncontrol, pfexit, pcneed, pffound)
}
/* Update the received sequence number from the yyy field of a
- data packet or an RR control packet. If we've been delaying
- sending packets until we received an ack, this may send out
- some packets. */
- if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL
- || CONTROL_XXX (ab[IFRAME_CONTROL]) == RR)
+ data packet (if it is the one we are expecting) or an RR
+ control packet. If we've been delaying sending packets until
+ we received an ack, this may send out some packets. */
+ if ((CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL
+ && CONTROL_XXX (ab[IFRAME_CONTROL]) == INEXTSEQ (iGrecseq))
+ || (CONTROL_XXX (ab[IFRAME_CONTROL]) == RR && ! fduprr))
{
if (! fggot_ack (qdaemon, CONTROL_YYY (ab[IFRAME_CONTROL])))
return FALSE;
@@ -1773,7 +1815,10 @@ fgprocess_data (qdaemon, fdoacks, freturncontrol, pfexit, pcneed, pffound)
iGsendseq, iGretransmit_seq);
++cGresent_packets;
- ++cGremote_rejects;
+ if (fduprr)
+ ++cGremote_duprrs;
+ else
+ ++cGremote_rejects;
++cGerror_level;
if (! fgcheck_errors (qdaemon))
return FALSE;
diff --git a/gnu/libexec/uucp/uucico/proti.c b/gnu/libexec/uucp/uucico/proti.c
index d14d42b42db0..fd243de23731 100644
--- a/gnu/libexec/uucp/uucico/proti.c
+++ b/gnu/libexec/uucp/uucico/proti.c
@@ -1,7 +1,7 @@
/* proti.c
The 'i' protocol.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char proti_rcsid[] = "$Id: proti.c,v 1.1 1993/08/05 18:27:12 conklin Exp $";
+const char proti_rcsid[] = "$Id: proti.c,v 1.2 1994/05/07 18:13:48 ache Exp $";
#endif
#include <ctype.h>
@@ -153,7 +153,10 @@ const char proti_rcsid[] = "$Id: proti.c,v 1.1 1993/08/05 18:27:12 conklin Exp $
#define IMAXSEQ 32
/* Get the next sequence number given a sequence number. */
-#define INEXTSEQ(i) ((i + 1) & (IMAXSEQ - 1))
+#define INEXTSEQ(i) (((i) + 1) & (IMAXSEQ - 1))
+
+/* Get the previous sequence number given a sequence number. */
+#define IPREVSEQ(i) (((i) + IMAXSEQ - 1) & (IMAXSEQ - 1))
/* Compute i1 - i2 in sequence space (i.e., the number of packets from
i2 to i1). */
@@ -216,17 +219,14 @@ static int iIremote_packsize;
static int iIalc_packsize;
/* Forced remote packet size, used if non-zero (protocol parameter
- ``remote-packet-size''). */
+ ``remote-packet-size''). There is no forced remote window size
+ because the ACK strategy requires that both sides agree on the
+ window size. */
static int iIforced_remote_packsize = 0;
-/* Remote window size (set from SYNC packet or from
- iIforced_remote_winsize). */
+/* Remote window size (set from SYNC packet). */
static int iIremote_winsize;
-/* Forced remote window size, used if non-zero (protocol parameter
- ``remote-window''). */
-static int iIforced_remote_winsize = 0;
-
/* Timeout to use when sending the SYNC packet (protocol
parameter ``sync-timeout''). */
int cIsync_timeout = CSYNC_TIMEOUT;
@@ -251,6 +251,11 @@ static int cIerrors = CERRORS;
the error level by one (protocol parameter ``error-decay''). */
static int cIerror_decay = CERROR_DECAY;
+/* The number of packets we should wait to receive before sending an
+ ACK; this is set by default to half the window size we have
+ requested (protocol parameter ``ack-frequency''). */
+static int cIack_frequency = 0;
+
/* The set of characters to avoid (protocol parameter ``avoid'').
This is actually part of the 'j' protocol; it is defined in this
file because the 'i' and 'j' protocols use the same protocol
@@ -334,8 +339,6 @@ struct uuconf_cmdtab asIproto_params[] =
{ "window", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_winsize, NULL },
{ "remote-packet-size", UUCONF_CMDTABTYPE_INT,
(pointer) &iIforced_remote_packsize, NULL },
- { "remote-window", UUCONF_CMDTABTYPE_INT,
- (pointer) &iIforced_remote_winsize, NULL },
{ "sync-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_timeout,
NULL },
{ "sync-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_retries,
@@ -344,6 +347,7 @@ struct uuconf_cmdtab asIproto_params[] =
{ "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIretries, NULL },
{ "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cIerrors, NULL },
{ "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cIerror_decay, NULL },
+ { "ack-frequency", UUCONF_CMDTABTYPE_INT, (pointer) &cIack_frequency, NULL },
/* The ``avoid'' protocol parameter is part of the 'j' protocol, but
it is convenient for the 'i' and 'j' protocols to share the same
protocol parameter table. */
@@ -398,7 +402,7 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
boolean (*pfreceive) P((struct sconnection *qconn, size_t cneed,
size_t *pcrec, int ctimeout, boolean freport));
{
- char ab[CHDRLEN + 3 + CCKSUMLEN];
+ char ab[CHDRLEN + 4 + CCKSUMLEN];
unsigned long icksum;
int ctries;
int csyncs;
@@ -414,10 +418,6 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
else
iIremote_packsize = iIforced_remote_packsize;
iIalc_packsize = 0;
- if (iIforced_remote_winsize <= 0 || iIforced_remote_winsize >= IMAXSEQ)
- iIforced_remote_winsize = 0;
- else
- iIremote_winsize = iIforced_remote_winsize;
iIsendseq = 1;
iIrecseq = 0;
@@ -435,16 +435,41 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
cIbad_cksum = 0;
cIremote_rejects = 0;
+ if (iIrequest_packsize < 0 || iIrequest_packsize > imaxpacksize)
+ {
+ ulog (LOG_ERROR, "Illegal protocol '%c' packet size; using %d",
+ qdaemon->qproto->bname, imaxpacksize);
+ iIrequest_packsize = imaxpacksize;
+ }
+
+ /* The maximum permissible window size is 16. Otherwise the
+ protocol can get confused because a duplicated packet may arrive
+ out of order. If the window size is large in such a case, the
+ duplicate packet may be treated as a packet in the upcoming
+ window, causing the protocol to assume that all intermediate
+ packets have been lost, leading to immense confusion. */
+ if (iIrequest_winsize < 0 || iIrequest_winsize > IMAXSEQ / 2)
+ {
+ ulog (LOG_ERROR, "Illegal protocol '%c' window size; using %d",
+ qdaemon->qproto->bname, IREQUEST_WINSIZE);
+ iIrequest_winsize = IREQUEST_WINSIZE;
+ }
+
+ /* The default for the ACK frequency is half the window size. */
+ if (cIack_frequency <= 0 || cIack_frequency >= iIrequest_winsize)
+ cIack_frequency = iIrequest_winsize / 2;
+
ab[IHDR_INTRO] = IINTRO;
ab[IHDR_LOCAL] = ab[IHDR_REMOTE] = IHDRWIN_SET (0, 0);
- ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3);
- ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3);
+ ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 4);
+ ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 4);
ab[IHDR_CHECK] = IHDRCHECK_VAL (ab);
ab[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff;
ab[CHDRLEN + 1] = iIrequest_packsize & 0xff;
ab[CHDRLEN + 2] = iIrequest_winsize;
- icksum = icrc (ab + CHDRLEN, 3, ICRCINIT);
- UCKSUM_SET (ab + CHDRLEN + 3, icksum);
+ ab[CHDRLEN + 3] = qdaemon->cchans;
+ icksum = icrc (ab + CHDRLEN, 4, ICRCINIT);
+ UCKSUM_SET (ab + CHDRLEN + 4, icksum);
/* The static cIsyncs is incremented each time a SYNC packet is
received. */
@@ -455,11 +480,11 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
{
boolean ftimedout;
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fistart: Sending SYNC packsize %d winsize %d",
- iIrequest_packsize, iIrequest_winsize);
+ DEBUG_MESSAGE3 (DEBUG_PROTO,
+ "fistart: Sending SYNC packsize %d winsize %d channels %d",
+ iIrequest_packsize, iIrequest_winsize, qdaemon->cchans);
- if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 3 + CCKSUMLEN,
+ if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 4 + CCKSUMLEN,
TRUE))
return FALSE;
@@ -509,11 +534,15 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
if (iseq >= IMAXSEQ)
{
- *pzlog = zbufalc (sizeof "protocol 'i' packet size %d window %d"
- + 50);
- sprintf (*pzlog, "protocol '%c' packet size %d window %d",
- qdaemon->qproto->bname, iIremote_packsize,
- iIremote_winsize);
+ *pzlog =
+ zbufalc (sizeof "protocol '' sending packet/window / receiving /"
+ + 64);
+ sprintf (*pzlog,
+ "protocol '%c' sending packet/window %d/%d receiving %d/%d",
+ qdaemon->qproto->bname, (int) iIremote_packsize,
+ (int) iIremote_winsize, (int) iIrequest_packsize,
+ (int) iIrequest_winsize);
+
iIalc_packsize = iIremote_packsize;
return TRUE;
@@ -575,13 +604,13 @@ fishutdown (qdaemon)
iIrequest_packsize = IREQUEST_PACKSIZE;
iIrequest_winsize = IREQUEST_WINSIZE;
iIforced_remote_packsize = 0;
- iIforced_remote_winsize = 0;
cIsync_timeout = CSYNC_TIMEOUT;
cIsync_retries = CSYNC_RETRIES;
cItimeout = CTIMEOUT;
cIretries = CRETRIES;
cIerrors = CERRORS;
cIerror_decay = CERROR_DECAY;
+ cIack_frequency = 0;
zJavoid_parameter = ZAVOID;
return TRUE;
@@ -835,8 +864,9 @@ fisenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos)
iIlocal_ack = iIrecseq;
zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr);
- DEBUG_MESSAGE2 (DEBUG_PROTO, "fisenddata: Sending packet %d (%d bytes)",
- iIsendseq, (int) cdata);
+ DEBUG_MESSAGE4 (DEBUG_PROTO,
+ "fisenddata: Sending packet %d size %d local %d remote %d",
+ iIsendseq, (int) cdata, ilocal, iremote);
iIsendseq = INEXTSEQ (iIsendseq);
++cIsent_packets;
@@ -977,6 +1007,8 @@ ficheck_errors (qdaemon)
char absync[CHDRLEN + 3 + CCKSUMLEN];
unsigned long icksum;
+ /* Don't bother sending the number of channels in this
+ packet. */
iIrequest_packsize /= 2;
absync[IHDR_INTRO] = IINTRO;
absync[IHDR_LOCAL] = IHDRWIN_SET (0, 0);
@@ -1127,9 +1159,9 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed)
if (iIrequest_winsize > 0
&& CSEQDIFF (iseq, iIlocal_ack) > iIrequest_winsize)
{
- DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
- "fiprocess_data: Out of order packet %d",
- iseq);
+ DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
+ "fiprocess_data: Out of order packet %d (ack %d)",
+ iseq, iIlocal_ack);
++cIbad_order;
if (! ficheck_errors (qdaemon))
@@ -1253,7 +1285,27 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed)
if (iseq != -1)
{
- afInaked[iseq] = FALSE;
+ /* If we already sent a NAK for this packet, and we have not
+ seen the previous packet, then forget that we sent a NAK
+ for this and any preceding packets. This is to handle
+ the following sequence:
+ receive packet 0
+ packets 1 and 2 lost
+ receive packet 3
+ send NAK 1
+ send NAK 2
+ packet 1 lost
+ receive packet 2
+ At this point we want to send NAK 1. */
+ if (afInaked[iseq]
+ && azIrecbuffers[IPREVSEQ (iseq)] == NULL)
+ {
+ for (i = INEXTSEQ (iIrecseq);
+ i != iseq;
+ i = INEXTSEQ (i))
+ afInaked[i] = FALSE;
+ afInaked[iseq] = FALSE;
+ }
/* If we haven't handled all previous packets, we must save
off this packet and deal with it later. */
@@ -1263,16 +1315,16 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed)
|| (iIrequest_winsize > 0
&& CSEQDIFF (iseq, iIrecseq) > iIrequest_winsize))
{
- DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
- "fiprocess_data: Ignoring out of order packet %d",
- iseq);
+ DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
+ "fiprocess_data: Ignoring out of order packet %d (recseq %d)",
+ iseq, iIrecseq);
continue;
}
else
{
- DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
- "fiprocess_data: Saving unexpected packet %d",
- iseq);
+ DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
+ "fiprocess_data: Saving unexpected packet %d (recseq %d)",
+ iseq, iIrecseq);
if (azIrecbuffers[iseq] == NULL)
{
@@ -1352,7 +1404,7 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed)
However, it can happen if we receive a burst of short
packets, such as a set of command acknowledgements. */
if (iIrequest_winsize > 0
- && CSEQDIFF (iIrecseq, iIlocal_ack) >= iIrequest_winsize / 2)
+ && CSEQDIFF (iIrecseq, iIlocal_ack) >= cIack_frequency)
{
char aback[CHDRLEN];
@@ -1401,9 +1453,11 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit)
boolean fret;
iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]);
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fiprocess_packet: Got DATA packet %d size %d",
- iseq, cfirst + csecond);
+ DEBUG_MESSAGE4 (DEBUG_PROTO,
+ "fiprocess_packet: Got DATA packet %d size %d local %d remote %d",
+ iseq, cfirst + csecond,
+ IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]),
+ IHDRWIN_GETCHAN (zhdr[IHDR_LOCAL]));
fret = fgot_data (qdaemon, zfirst, (size_t) cfirst,
zsecond, (size_t) csecond,
IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]),
@@ -1417,7 +1471,7 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit)
case SYNC:
{
- int ipack, iwin;
+ int ipack, iwin, cchans;
/* We accept a SYNC packet to adjust the packet and window
sizes at any time. */
@@ -1436,16 +1490,31 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit)
else
iwin = zsecond[2 - cfirst];
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fiprocess_packet: Got SYNC packsize %d winsize %d",
- ipack, iwin);
+ /* The fourth byte in a SYNC packet is the number of channels
+ to use. This is optional. Switching the number of
+ channels in the middle of a conversation may cause
+ problems. */
+ if (cfirst + csecond <= 3)
+ cchans = 0;
+ else
+ {
+ if (cfirst > 3)
+ cchans = zfirst[3];
+ else
+ cchans = zsecond[3 - cfirst];
+ if (cchans > 0 && cchans < 8)
+ qdaemon->cchans = cchans;
+ }
+
+ DEBUG_MESSAGE3 (DEBUG_PROTO,
+ "fiprocess_packet: Got SYNC packsize %d winsize %d channels %d",
+ ipack, iwin, cchans);
if (iIforced_remote_packsize == 0
&& (iIalc_packsize == 0
|| ipack <= iIalc_packsize))
iIremote_packsize = ipack;
- if (iIforced_remote_winsize == 0)
- iIremote_winsize = iwin;
+ iIremote_winsize = iwin;
/* We increment a static variable to tell the initialization
code that a SYNC was received, and we set *pfexit to TRUE
@@ -1477,44 +1546,68 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit)
iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]);
- /* The timeout code will send a NAK for the packet the remote
- side wants. So we may see a NAK here for the packet we are
- about to send. */
- if (iseq == iIsendseq
- || (iIremote_winsize > 0
- && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize
- || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize)))
+ /* If the remote side times out while waiting for a packet, it
+ will send a NAK for the next packet it wants to see. If we
+ have not sent that packet yet, and we have no
+ unacknowledged data, it implies that the remote side has a
+ window full of data to send, which implies that our ACK has
+ been lost. Therefore, we send an ACK. */
+ if (iseq == iIsendseq &&
+ INEXTSEQ (iIremote_ack) == iIsendseq)
{
- DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
- "fiprocess_packet: Ignoring out of order NAK %d",
- iseq);
- return TRUE;
- }
+ char aback[CHDRLEN];
+
+ aback[IHDR_INTRO] = IINTRO;
+ aback[IHDR_LOCAL] = IHDRWIN_SET (0, 0);
+ aback[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
+ iIlocal_ack = iIrecseq;
+ aback[IHDR_CONTENTS1] = IHDRCON_SET1 (ACK, qdaemon->fcaller, 0);
+ aback[IHDR_CONTENTS2] = IHDRCON_SET2 (ACK, qdaemon->fcaller, 0);
+ aback[IHDR_CHECK] = IHDRCHECK_VAL (aback);
- DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
- "fiprocess_packet: Got NAK %d; resending packet",
- iseq);
+ DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Sending ACK %d",
+ iIrecseq);
- /* Update the received sequence number. */
- zsend = azIsendbuffers[iseq] + CHDROFFSET;
- if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq)
+ return (*pfIsend) (qdaemon->qconn, aback, CHDRLEN, TRUE);
+ }
+ else
{
- int iremote;
+ if (iseq == iIsendseq
+ || (iIremote_winsize > 0
+ && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize
+ || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize)))
+ {
+ DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
+ "fiprocess_packet: Ignoring out of order NAK %d (sendseq %d)",
+ iseq, iIsendseq);
+ return TRUE;
+ }
- iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]);
- zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote);
- zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend);
- iIlocal_ack = iIrecseq;
- }
+ DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
+ "fiprocess_packet: Got NAK %d; resending packet",
+ iseq);
+
+ /* Update the received sequence number. */
+ zsend = azIsendbuffers[iseq] + CHDROFFSET;
+ if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq)
+ {
+ int iremote;
+
+ iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]);
+ zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote);
+ zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend);
+ iIlocal_ack = iIrecseq;
+ }
- ++cIresent_packets;
+ ++cIresent_packets;
- clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1],
- zsend[IHDR_CONTENTS2]);
+ clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1],
+ zsend[IHDR_CONTENTS2]);
- return (*pfIsend) (qdaemon->qconn, zsend,
- CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0),
- TRUE);
+ return (*pfIsend) (qdaemon->qconn, zsend,
+ CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0),
+ TRUE);
+ }
}
case SPOS:
diff --git a/gnu/libexec/uucp/uucico/protj.c b/gnu/libexec/uucp/uucico/protj.c
index 5717bb916dfb..e61b499f1c73 100644
--- a/gnu/libexec/uucp/uucico/protj.c
+++ b/gnu/libexec/uucp/uucico/protj.c
@@ -1,7 +1,7 @@
/* protj.c
The 'j' protocol.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,19 +20,20 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char protj_rcsid[] = "$Id: protj.c,v 1.1 1993/08/05 18:27:14 conklin Exp $";
+const char protj_rcsid[] = "$Id: protj.c,v 1.2 1994/05/07 18:13:50 ache Exp $";
#endif
#include <ctype.h>
#include <errno.h>
#include "uudefs.h"
+#include "uuconf.h"
#include "conn.h"
#include "trans.h"
#include "system.h"
diff --git a/gnu/libexec/uucp/uucico/prott.c b/gnu/libexec/uucp/uucico/prott.c
index 44763958349a..bbbd7616eed6 100644
--- a/gnu/libexec/uucp/uucico/prott.c
+++ b/gnu/libexec/uucp/uucico/prott.c
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char prott_rcsid[] = "$Id: prott.c,v 1.1 1993/08/05 18:27:15 conklin Exp $";
+const char prott_rcsid[] = "$Id: prott.c,v 1.2 1994/05/07 18:13:51 ache Exp $";
#endif
#include "uudefs.h"
@@ -133,7 +133,8 @@ ftsendcmd (qdaemon, z, ilocal, iremote)
zalc = zbufalc (csend);
memcpy (zalc, z, clen);
- bzero (zalc + clen, csend - clen);
+ if (csend > clen)
+ bzero (zalc + clen, csend - clen);
fret = fsend_data (qdaemon->qconn, zalc, csend, TRUE);
ubuffree (zalc);
diff --git a/gnu/libexec/uucp/uucico/protz.c b/gnu/libexec/uucp/uucico/protz.c
index 6510df7d798e..c99ea8fb8d91 100644
--- a/gnu/libexec/uucp/uucico/protz.c
+++ b/gnu/libexec/uucp/uucico/protz.c
@@ -181,7 +181,7 @@
#include "uucp.h"
#if USE_RCS_ID
-const char protz_rcsid[] = "$Id: protz.c,v 1.1 1993/08/05 18:27:16 conklin Exp $";
+const char protz_rcsid[] = "$Id: protz.c,v 1.2 1994/05/07 18:13:52 ache Exp $";
#endif
#include <errno.h>
@@ -2084,7 +2084,7 @@ fifi:
cZheaders_received++;
break;
}
- DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%x",
+ DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%lx",
ZZHEADER_NAME(c), rclhdr (hdr));
return c;
diff --git a/gnu/libexec/uucp/uucico/rec.c b/gnu/libexec/uucp/uucico/rec.c
index b55d7f2c401f..c85647d56787 100644
--- a/gnu/libexec/uucp/uucico/rec.c
+++ b/gnu/libexec/uucp/uucico/rec.c
@@ -1,7 +1,7 @@
/* rec.c
Routines to receive a file.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char rec_rcsid[] = "$Id: rec.c,v 1.1 1993/08/05 18:27:18 conklin Exp $";
+const char rec_rcsid[] = "$Id: rec.c,v 1.2 1994/05/07 18:13:55 ache Exp $";
#endif
#include <errno.h>
@@ -308,13 +308,22 @@ flocal_rec_send_request (qtrans, qdaemon)
boolean fret;
qinfo->ztemp = zsysdep_receive_temp (qdaemon->qsys, qinfo->zfile,
- (const char *) NULL);
+ (const char *) NULL,
+ (qdaemon->qproto->frestart
+ && (qdaemon->ifeatures
+ & FEATURE_RESTART) != 0));
if (qinfo->ztemp == NULL)
{
urrec_free (qtrans);
return FALSE;
}
+ qtrans->fcmd = TRUE;
+ qtrans->precfn = flocal_rec_await_reply;
+
+ if (! fqueue_receive (qdaemon, qtrans))
+ return FALSE;
+
/* Check the amount of free space available for both the temporary
file and the real file. */
cbytes = csysdep_bytes_free (qinfo->ztemp);
@@ -354,16 +363,11 @@ flocal_rec_send_request (qtrans, qdaemon)
fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
qtrans->iremote);
ubuffree (zsend);
- if (! fret)
- {
- urrec_free (qtrans);
- return FALSE;
- }
- qtrans->fcmd = TRUE;
- qtrans->precfn = flocal_rec_await_reply;
+ if (! fret)
+ urrec_free (qtrans);
- return fqueue_receive (qdaemon, qtrans);
+ return fret;
}
/* This is called when a reply is received for the request. */
@@ -377,8 +381,8 @@ flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata)
size_t cdata;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
- long crestart;
const char *zlog;
+ char *zend;
if (zdata[0] != 'R'
|| (zdata[1] != 'Y' && zdata[1] != 'N'))
@@ -407,6 +411,18 @@ flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata)
zerr = "too large to receive now";
fnever = FALSE;
}
+ else if (zdata[2] == '9')
+ {
+ /* Remote has run out of channels. */
+ zerr = "too many channels for remote";
+ fnever = FALSE;
+
+ /* Drop one channel; using exactly one channel causes
+ slightly different behahaviour in a few places, so don't
+ decrement to one. */
+ if (qdaemon->cchans > 2)
+ --qdaemon->cchans;
+ }
else
zerr = "unknown reason";
@@ -423,16 +439,25 @@ flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata)
/* The mode should have been sent as "RY 0%o". If it wasn't, we use
0666. */
qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2),
- (char **) NULL, 8);
+ &zend, 8);
if (qtrans->s.imode == 0)
qtrans->s.imode = 0666;
+ /* If there is an M after the mode, the remote has requested a
+ hangup. */
+ if (*zend == 'M' && qdaemon->fmaster)
+ {
+ DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
+ "flocal_rec_await_reply: Remote has requested transfer of control");
+ qdaemon->fhangup_requested = TRUE;
+ }
+
/* Open the file to receive into. We just ignore any restart count,
since we have no way to tell it to the other side. SVR4 may have
some way to do this, but I don't know what it is. */
qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile,
(const char *) NULL, qinfo->ztemp,
- &crestart);
+ (long *) NULL);
if (! ffileisopen (qtrans->e))
return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
"cannot open file");
@@ -570,7 +595,15 @@ fremote_send_file_init (qdaemon, qcmd, iremote)
}
else
{
- zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir);
+ boolean fbadname;
+
+ zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir,
+ &fbadname);
+ if (zfile == NULL && fbadname)
+ {
+ ulog (LOG_ERROR, "%s: bad local file name", qcmd->zto);
+ return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
+ }
if (zfile != NULL)
{
char *zadd;
@@ -603,7 +636,10 @@ fremote_send_file_init (qdaemon, qcmd, iremote)
}
}
- ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp);
+ ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp,
+ (qdaemon->qproto->frestart
+ && (qdaemon->ifeatures
+ & FEATURE_RESTART) != 0));
/* Adjust the number of bytes we are prepared to receive according
to the amount of free space we are supposed to leave available
@@ -646,7 +682,13 @@ fremote_send_file_init (qdaemon, qcmd, iremote)
/* Open the file to receive into. This may find an old copy of the
file, which will be used for file restart if the other side
supports it. */
- e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp, &crestart);
+ crestart = -1;
+ e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp,
+ ((qdaemon->qproto->frestart
+ && (qdaemon->ifeatures
+ & FEATURE_RESTART) != 0)
+ ? &crestart
+ : (long *) NULL));
if (! ffileisopen (e))
{
ubuffree (ztemp);
@@ -656,21 +698,16 @@ fremote_send_file_init (qdaemon, qcmd, iremote)
if (crestart > 0)
{
- if ((qdaemon->ifeatures & FEATURE_RESTART) == 0)
- crestart = -1;
- else
+ DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
+ "fremote_send_file_init: Restarting receive from %ld",
+ crestart);
+ if (! ffileseek (e, crestart))
{
- DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
- "fremote_send_file_init: Restarting receive from %ld",
- crestart);
- if (! ffileseek (e, crestart))
- {
- ulog (LOG_ERROR, "seek: %s", strerror (errno));
- (void) ffileclose (e);
- ubuffree (ztemp);
- ubuffree (zfile);
- return FALSE;
- }
+ ulog (LOG_ERROR, "seek: %s", strerror (errno));
+ (void) ffileclose (e);
+ ubuffree (ztemp);
+ ubuffree (zfile);
+ return FALSE;
}
}
@@ -705,8 +742,24 @@ fremote_send_file_init (qdaemon, qcmd, iremote)
else
zlog = qinfo->zfile;
}
- qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog));
+ qtrans->zlog = zbufalc (sizeof "Receiving ( bytes resume at )"
+ + strlen (zlog) + 50);
sprintf (qtrans->zlog, "Receiving %s", zlog);
+ if (crestart > 0 || qcmd->cbytes > 0)
+ {
+ strcat (qtrans->zlog, " (");
+ if (qcmd->cbytes > 0)
+ {
+ sprintf (qtrans->zlog + strlen (qtrans->zlog), "%ld bytes",
+ qcmd->cbytes);
+ if (crestart > 0)
+ strcat (qtrans->zlog, " ");
+ }
+ if (crestart > 0)
+ sprintf (qtrans->zlog + strlen (qtrans->zlog), "resume at %ld",
+ crestart);
+ strcat (qtrans->zlog, ")");
+ }
return fqueue_remote (qdaemon, qtrans);
}
@@ -719,8 +772,20 @@ fremote_send_reply (qtrans, qdaemon)
struct sdaemon *qdaemon;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
+ boolean fret;
char ab[50];
+ /* If the file has been completely received, we just want to send
+ the final confirmation. Otherwise, we must wait for the file
+ first. */
+ qtrans->psendfn = frec_file_send_confirm;
+ if (qinfo->freceived)
+ fret = fqueue_send (qdaemon, qtrans);
+ else
+ fret = fqueue_receive (qdaemon, qtrans);
+ if (! fret)
+ return FALSE;
+
ab[0] = qtrans->s.bcmd;
ab[1] = 'Y';
if (qtrans->ipos <= 0)
@@ -751,18 +816,9 @@ fremote_send_reply (qtrans, qdaemon)
urrec_free (qtrans);
return FALSE;
}
- if (fhandled)
- return TRUE;
}
- /* If the file has been completely received, we just want to send
- the final confirmation. Otherwise, we must wait for the file
- first. */
- qtrans->psendfn = frec_file_send_confirm;
- if (qinfo->freceived)
- return fqueue_send (qdaemon, qtrans);
- else
- return fqueue_receive (qdaemon, qtrans);
+ return TRUE;
}
/* If we can't receive a file, queue up a response to the remote
@@ -784,7 +840,7 @@ fremote_send_fail (qdaemon, qcmd, twhy, iremote)
/* If the protocol does not support multiple channels (cchans <= 1),
then we have essentially already received the entire file. */
- qinfo->freceived = qdaemon->qproto->cchans <= 1;
+ qinfo->freceived = qdaemon->cchans <= 1;
qtrans = qtransalc (qcmd);
qtrans->psendfn = fremote_send_fail_send;
@@ -807,6 +863,13 @@ fremote_send_fail_send (qtrans, qdaemon)
char ab[4];
boolean fret;
+ /* Wait for the end of file marker if we haven't gotten it yet. */
+ if (! qinfo->freceived)
+ {
+ if (! fqueue_receive (qdaemon, qtrans))
+ return FALSE;
+ }
+
ab[0] = qtrans->s.bcmd;
ab[1] = 'N';
@@ -840,13 +903,7 @@ fremote_send_fail_send (qtrans, qdaemon)
qinfo->fsent = TRUE;
- /* Wait for the end of file marker if we haven't gotten it yet. */
- if (! qinfo->freceived)
- {
- if (! fqueue_receive (qdaemon, qtrans))
- fret = FALSE;
- }
- else
+ if (qinfo->freceived)
{
xfree (qtrans->pinfo);
utransfree (qtrans);
@@ -902,6 +959,7 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
size_t cdata;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
+ char *zalc;
const char *zerr;
boolean fnever;
@@ -929,10 +987,13 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
fnever = FALSE;
+ zalc = NULL;
+
if (! ffileclose (qtrans->e))
{
zerr = strerror (errno);
ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr);
+ (void) remove (qinfo->ztemp);
}
else if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool,
FALSE, ! qinfo->fspool,
@@ -940,7 +1001,49 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
? qtrans->s.zuser
: (const char *) NULL)))
{
- zerr = "could not move to final location";
+ long cspace;
+
+ /* Keep the temporary file if there is 1.5 times the amount of
+ required free space. This is just a random guess, to make an
+ unusual situtation potentially less painful. */
+ cspace = csysdep_bytes_free (qinfo->ztemp);
+ if (cspace == -1)
+ cspace = FREE_SPACE_DELTA;
+ cspace -= (qdaemon->qsys->uuconf_cfree_space
+ + qdaemon->qsys->uuconf_cfree_space / 2);
+ if (cspace < 0)
+ {
+ (void) remove (qinfo->ztemp);
+ zerr = "could not move to final location";
+ }
+ else
+ {
+ const char *az[20];
+ int i;
+
+ zalc = zbufalc (sizeof "could not move to final location (left as )"
+ + strlen (qinfo->ztemp));
+ sprintf (zalc, "could not move to final location (left as %s)",
+ qinfo->ztemp);
+ zerr = zalc;
+
+ i = 0;
+ az[i++] = "The file\n\t";
+ az[i++] = qinfo->ztemp;
+ az[i++] =
+ "\nwas saved because the move to the final location failed.\n";
+ az[i++] = "See the UUCP logs for more details.\n";
+ az[i++] = "The file transfer was from\n\t";
+ az[i++] = qdaemon->qsys->uuconf_zname;
+ az[i++] = "!";
+ az[i++] = qtrans->s.zfrom;
+ az[i++] = "\nto\n\t";
+ az[i++] = qtrans->s.zto;
+ az[i++] = "\nand was requested by\n\t";
+ az[i++] = qtrans->s.zuser;
+ az[i++] = "\n";
+ (void) fsysdep_mail (OWNER, "UUCP temporary file saved", i, az);
+ }
ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr);
fnever = TRUE;
}
@@ -963,12 +1066,10 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
zerr = NULL;
}
- if (zerr != NULL)
- (void) remove (qinfo->ztemp);
-
ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname,
FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros,
qdaemon->fmaster);
+ qdaemon->creceived += qtrans->cbytes;
if (zerr == NULL)
{
@@ -1011,6 +1112,8 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
}
}
+ ubuffree (zalc);
+
/* If this is an execution request, we must create the execution
file itself. */
if (qtrans->s.bcmd == 'E' && zerr == NULL)
@@ -1040,7 +1143,10 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
uuxqt might pick up the file before we have finished writing
it. */
e = NULL;
- ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0");
+ ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0",
+ (qdaemon->qproto->frestart
+ && (qdaemon->ifeatures
+ & FEATURE_RESTART) != 0));
if (ztemp != NULL)
e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE);
@@ -1077,7 +1183,10 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
{
if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE,
(const char *) NULL))
- fbad = TRUE;
+ {
+ (void) remove (ztemp);
+ fbad = TRUE;
+ }
}
ubuffree (zxqtfile);
@@ -1090,6 +1199,21 @@ frec_file_end (qtrans, qdaemon, zdata, cdata)
}
}
+ /* See if we should spawn a uuxqt process. */
+ if (zerr == NULL
+ && (qtrans->s.bcmd == 'E'
+ || (qinfo->fspool && qtrans->s.zto[0] == 'X')))
+ {
+ ++qdaemon->cxfiles_received;
+ if (qdaemon->irunuuxqt > 0
+ && qdaemon->cxfiles_received >= qdaemon->irunuuxqt)
+ {
+ if (fspawn_uuxqt (TRUE, qdaemon->qsys->uuconf_zname,
+ qdaemon->zconfig))
+ qdaemon->cxfiles_received = 0;
+ }
+ }
+
/* Prepare to send the completion string to the remote system. If
we have not yet replied to the remote send request, we leave the
transfer structure on the remote queue. Otherwise we add it to
diff --git a/gnu/libexec/uucp/uucico/send.c b/gnu/libexec/uucp/uucico/send.c
index 8e2c55ef3724..60c3924ec694 100644
--- a/gnu/libexec/uucp/uucico/send.c
+++ b/gnu/libexec/uucp/uucico/send.c
@@ -1,7 +1,7 @@
/* send.c
Routines to send a file.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char send_rcsid[] = "$Id: send.c,v 1.1 1993/08/05 18:27:19 conklin Exp $";
+const char send_rcsid[] = "$Id: send.c,v 1.2 1994/05/07 18:13:57 ache Exp $";
#endif
#include <errno.h>
@@ -51,7 +51,9 @@ struct ssendinfo
boolean flocal;
/* TRUE if this is a spool directory file. */
boolean fspool;
- /* TRUE if the file has been completely sent. */
+ /* TRUE if the file has been completely sent. Also used in
+ flocal_send_cancelled to mean that the file send will never
+ succeed. */
boolean fsent;
/* Execution file for sending an unsupported E request. */
char *zexec;
@@ -62,7 +64,7 @@ struct ssendinfo
static void usfree_send P((struct stransfer *qtrans));
static boolean flocal_send_fail P((struct stransfer *qtrans,
struct scmd *qcmd,
- const struct uuconf_system *qsys,
+ struct sdaemon *qdaemon,
const char *zwhy));
static boolean flocal_send_request P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
@@ -150,10 +152,9 @@ usfree_send (qtrans)
flocal_send_request.
If flocal_send_await_reply is called before the entire file has
- been sent: if it gets an SN, it calls flocal_send_cancelled to send
- an empty data block to inform the remote system that the file
- transfer has stopped. If it gets a file position request, it must
- adjust the file position accordingly.
+ been sent: if it gets an SN, it sets the file position to the end
+ and arranges to call flocal_send_cancelled. If it gets a file
+ position request, it must adjust the file position accordingly.
If flocal_send_await_reply is called after the entire file has been
sent: if it gets an SN, it can simply delete the request. It can
@@ -197,7 +198,7 @@ flocal_send_file_init (qdaemon, qcmd)
is possible, but it might have changed since then. */
if (! qsys->uuconf_fcall_transfer
&& ! qsys->uuconf_fcalled_transfer)
- return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys,
+ return flocal_send_fail ((struct stransfer *) NULL, qcmd, qdaemon,
"not permitted to transfer files");
/* We can't do the request now, but it may get done later. */
@@ -214,7 +215,7 @@ flocal_send_file_init (qdaemon, qcmd)
qsys->uuconf_pzlocal_send,
qsys->uuconf_zpubdir, TRUE,
TRUE, qcmd->zuser))
- return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys,
+ return flocal_send_fail ((struct stransfer *) NULL, qcmd, qdaemon,
"not permitted to send");
zfile = zbufcpy (qcmd->zfrom);
}
@@ -234,12 +235,13 @@ flocal_send_file_init (qdaemon, qcmd)
{
ubuffree (zfile);
if (cbytes != -1)
- return FALSE;
+ return flocal_send_fail ((struct stransfer *) NULL, qcmd, qdaemon,
+ "can not get size");
/* A cbytes value of -1 means that the file does not exist.
This can happen legitimately if it has already been sent from
the spool directory. */
if (! fspool)
- return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys,
+ return flocal_send_fail ((struct stransfer *) NULL, qcmd, qdaemon,
"does not exist");
(void) fsysdep_did_work (qcmd->pseq);
return TRUE;
@@ -264,7 +266,7 @@ flocal_send_file_init (qdaemon, qcmd)
if (qdaemon->cmax_ever != -1
&& qdaemon->cmax_ever < qcmd->cbytes)
- return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys,
+ return flocal_send_fail ((struct stransfer *) NULL, qcmd, qdaemon,
"too large to send");
return TRUE;
@@ -280,7 +282,7 @@ flocal_send_file_init (qdaemon, qcmd)
qinfo->zmail = zbufcpy (qcmd->zuser);
qinfo->zfile = zfile;
qinfo->cbytes = cbytes;
- qinfo->flocal = TRUE;
+ qinfo->flocal = strchr (qcmd->zuser, '!') == NULL;
qinfo->fspool = fspool;
qinfo->fsent = FALSE;
qinfo->zexec = NULL;
@@ -296,32 +298,48 @@ flocal_send_file_init (qdaemon, qcmd)
this reports an error to the log file and to the user. */
static boolean
-flocal_send_fail (qtrans, qcmd, qsys, zwhy)
+flocal_send_fail (qtrans, qcmd, qdaemon, zwhy)
struct stransfer *qtrans;
struct scmd *qcmd;
- const struct uuconf_system *qsys;
+ struct sdaemon *qdaemon;
const char *zwhy;
{
if (zwhy != NULL)
{
+ const char *zfrom;
char *zfree;
+ const char *ztemp;
if (qcmd->bcmd != 'E')
- zfree = NULL;
+ {
+ zfrom = qcmd->zfrom;
+ zfree = NULL;
+ }
else
{
- zfree = zbufalc (sizeof "Execution of \"\": "
- + strlen (qcmd->zcmd)
- + strlen (zwhy));
- sprintf (zfree, "Execution of \"%s\": %s", qcmd->zcmd, zwhy);
- zwhy = zfree;
+ zfree = zbufalc (strlen (qcmd->zfrom)
+ + sizeof " (execution of \"\")"
+ + strlen (qcmd->zcmd));
+ sprintf (zfree, "%s (execution of \"%s\")", qcmd->zfrom,
+ qcmd->zcmd);
+ zfrom = zfree;
}
- ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy);
+ ulog (LOG_ERROR, "%s: %s", zfrom, zwhy);
+
+ /* We only save the temporary file if this is a request from the
+ local system; otherwise a remote system could launch a denial
+ of service attack by filling up the .Preserve directory
+ (local users have much simpler methods for this type of
+ denial of service attack, so there is little point to using a
+ more sophisticated scheme). */
+ if (strchr (qcmd->zuser, '!') == NULL)
+ ztemp = zsysdep_save_temp_file (qcmd->pseq);
+ else
+ ztemp = NULL;
(void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL,
- zwhy, qcmd->zfrom, (const char *) NULL,
- qcmd->zto, qsys->uuconf_zname,
- zsysdep_save_temp_file (qcmd->pseq));
+ zwhy, zfrom, (const char *) NULL,
+ qcmd->zto, qdaemon->qsys->uuconf_zname, ztemp);
ubuffree (zfree);
}
@@ -353,9 +371,37 @@ flocal_send_request (qtrans, qdaemon)
/* Make sure the file meets any remote size restrictions. */
if (qdaemon->cmax_receive != -1
&& qdaemon->cmax_receive < qinfo->cbytes)
- return flocal_send_fail (qtrans, &qtrans->s, qdaemon->qsys,
+ return flocal_send_fail (qtrans, &qtrans->s, qdaemon,
"too large for receiver");
+ /* Make sure the file still exists--it may have been removed between
+ the conversation startup and now. After we have sent over the S
+ command we must give an error if we can't find the file. */
+ if (! fsysdep_file_exists (qinfo->zfile))
+ {
+ (void) fsysdep_did_work (qtrans->s.pseq);
+ usfree_send (qtrans);
+ return TRUE;
+ }
+
+ /* If we are using a protocol which can make multiple channels, then
+ we can open and send the file whenever we are ready. This is
+ because we will be able to distinguish the response by the
+ channel it is directed to. This assumes that every protocol
+ which supports multiple channels also supports sending the file
+ position in mid-stream, since otherwise we would not be able to
+ restart files. */
+ qtrans->fcmd = TRUE;
+ qtrans->psendfn = flocal_send_open_file;
+ qtrans->precfn = flocal_send_await_reply;
+
+ if (qdaemon->cchans > 1)
+ fret = fqueue_send (qdaemon, qtrans);
+ else
+ fret = fqueue_receive (qdaemon, qtrans);
+ if (! fret)
+ return FALSE;
+
/* Construct the notify string to send. If we are going to send a
size or an execution command, it must be non-empty. */
znotify = qtrans->s.znotify;
@@ -452,27 +498,11 @@ flocal_send_request (qtrans, qdaemon)
fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
qtrans->iremote);
ubuffree (zsend);
- if (! fret)
- {
- usfree_send (qtrans);
- return FALSE;
- }
- /* If we are using a protocol which can make multiple channels, then
- we can open and send the file whenever we are ready. This is
- because we will be able to distinguish the response by the
- channel it is directed to. This assumes that every protocol
- which supports multiple channels also supports sending the file
- position in mid-stream, since otherwise we would not be able to
- restart files. */
- qtrans->fcmd = TRUE;
- qtrans->psendfn = flocal_send_open_file;
- qtrans->precfn = flocal_send_await_reply;
+ if (! fret)
+ usfree_send (qtrans);
- if (qdaemon->qproto->cchans > 1)
- return fqueue_send (qdaemon, qtrans);
- else
- return fqueue_receive (qdaemon, qtrans);
+ return fret;
}
/* This is called when a reply is received for the send request. As
@@ -535,21 +565,36 @@ flocal_send_await_reply (qtrans, qdaemon, zdata, cdata)
is no need to resend the file. */
zerr = NULL;
}
+ else if (zdata[2] == '9')
+ {
+ /* Remote has run out of channels. */
+ zerr = "too many channels for remote";
+ fnever = FALSE;
+
+ /* Drop one channel; using exactly one channel causes
+ slightly different behahaviour in a few places, so don't
+ decrement to one. */
+ if (qdaemon->cchans > 2)
+ --qdaemon->cchans;
+ }
else
zerr = "unknown reason";
- if (! fnever)
+ if (! fnever
+ || (qtrans->s.bcmd == 'E'
+ && (qdaemon->ifeatures & FEATURE_EXEC) == 0
+ && qinfo->zexec == NULL))
{
if (qtrans->s.bcmd == 'E')
- ulog (LOG_ERROR, "Execution of \"%s\": %s", qtrans->s.zcmd,
- zerr);
+ ulog (LOG_ERROR, "%s (execution of \"%s\"): %s",
+ qtrans->s.zfrom, qtrans->s.zcmd, zerr);
else
ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr);
}
else
{
if (! flocal_send_fail ((struct stransfer *) NULL, &qtrans->s,
- qdaemon->qsys, zerr))
+ qdaemon, zerr))
return FALSE;
}
@@ -558,16 +603,39 @@ flocal_send_await_reply (qtrans, qdaemon, zdata, cdata)
the remote side knows that we have finished sending the file
data. If we have already sent the entire file, there will be
no confusion. */
- if (qdaemon->qproto->cchans == 1 || qinfo->fsent)
+ if (qdaemon->cchans == 1 || qinfo->fsent)
{
+ /* If we are breaking a 'E' command into two 'S' commands,
+ and that was for the first 'S' command, we still have to
+ send the second one. */
+ if (fnever
+ && qtrans->s.bcmd == 'E'
+ && (qdaemon->ifeatures & FEATURE_EXEC) == 0
+ && qinfo->zexec == NULL)
+ return fsend_exec_file_init (qtrans, qdaemon);
+
usfree_send (qtrans);
return TRUE;
}
else
{
+ /* Seek to the end of the file so that the next read will
+ send end of file. We have to be careful here, because we
+ may have actually already sent end of file--we could be
+ being called because of data received while the end of
+ file block was sent. */
+ if (! ffileseekend (qtrans->e))
+ {
+ ulog (LOG_ERROR, "seek to end: %s", strerror (errno));
+ usfree_send (qtrans);
+ return FALSE;
+ }
qtrans->psendfn = flocal_send_cancelled;
qtrans->precfn = NULL;
- qtrans->fsendfile = FALSE;
+
+ /* Reuse fsent to pass fnever to flocal_send_cancelled. */
+ qinfo->fsent = fnever;
+
return fqueue_send (qdaemon, qtrans);
}
}
@@ -603,7 +671,7 @@ flocal_send_await_reply (qtrans, qdaemon, zdata, cdata)
qtrans->precfn = fsend_await_confirm;
if (qinfo->fsent)
return fqueue_receive (qdaemon, qtrans);
- else if (qdaemon->qproto->cchans <= 1)
+ else if (qdaemon->cchans <= 1)
return fqueue_send (qdaemon, qtrans);
else
return TRUE;
@@ -638,7 +706,9 @@ flocal_send_open_file (qtrans, qdaemon)
qtrans->s.zfrom, (const char *) NULL,
qtrans->s.zto,
qdaemon->qsys->uuconf_zname,
- zsysdep_save_temp_file (qtrans->s.pseq));
+ (qinfo->flocal
+ ? zsysdep_save_temp_file (qtrans->s.pseq)
+ : (const char *) NULL));
(void) fsysdep_did_work (qtrans->s.pseq);
usfree_send (qtrans);
@@ -688,8 +758,15 @@ flocal_send_open_file (qtrans, qdaemon)
sprintf (zalc, "%s (%s)", qtrans->s.zcmd, qtrans->s.zfrom);
zsend = zalc;
}
- qtrans->zlog = zbufalc (sizeof "Sending " + strlen (zsend));
- sprintf (qtrans->zlog, "Sending %s", zsend);
+
+ qtrans->zlog = zbufalc (sizeof "Sending ( bytes resume at )"
+ + strlen (zsend) + 50);
+ sprintf (qtrans->zlog, "Sending %s (%ld bytes", zsend, qinfo->cbytes);
+ if (qtrans->ipos > 0)
+ sprintf (qtrans->zlog + strlen (qtrans->zlog), " resume at %ld",
+ qtrans->ipos);
+ strcat (qtrans->zlog, ")");
+
ubuffree (zalc);
}
@@ -698,7 +775,8 @@ flocal_send_open_file (qtrans, qdaemon)
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE,
- qinfo->cbytes, &fhandled))
+ qinfo->cbytes - qtrans->ipos,
+ &fhandled))
{
usfree_send (qtrans);
return FALSE;
@@ -719,32 +797,29 @@ flocal_send_open_file (qtrans, qdaemon)
return fqueue_send (qdaemon, qtrans);
}
-/* Cancel a file send by sending an empty buffer. This is only called
- for a protocol which supports multiple channels. It is needed
- so that both systems agree as to when a channel is no longer
- needed. */
+/* Cancel a file send. This is only called for a protocol which
+ supports multiple channels. It is needed so that both systems
+ agree as to when a channel is no longer needed. */
static boolean
flocal_send_cancelled (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
- char *zdata;
- size_t cdata;
- boolean fret;
-
- zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata);
- if (zdata == NULL)
- {
- usfree_send (qtrans);
- return FALSE;
- }
+ struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
+
+ /* If we are breaking a 'E' command into two 'S' commands, and that
+ was for the first 'S' command, and the first 'S' command will
+ never be sent (passed as qinfo->fsent), we still have to send the
+ second one. */
+ if (qinfo->fsent
+ && qtrans->s.bcmd == 'E'
+ && (qdaemon->ifeatures & FEATURE_EXEC) == 0
+ && qinfo->zexec == NULL)
+ return fsend_exec_file_init (qtrans, qdaemon);
- fret = (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, (size_t) 0,
- qtrans->ilocal, qtrans->iremote,
- qtrans->ipos);
usfree_send (qtrans);
- return fret;
+ return TRUE;
}
/* A remote request to receive a file (meaning that we have to send a
@@ -765,6 +840,7 @@ fremote_rec_file_init (qdaemon, qcmd, iremote)
{
const struct uuconf_system *qsys;
char *zfile;
+ boolean fbadname;
long cbytes;
unsigned int imode;
openfile_t e;
@@ -786,7 +862,12 @@ fremote_rec_file_init (qdaemon, qcmd, iremote)
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
}
- zfile = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir);
+ zfile = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir, &fbadname);
+ if (zfile == NULL && fbadname)
+ {
+ ulog (LOG_ERROR, "%s: bad local file name", qcmd->zfrom);
+ return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
+ }
if (zfile != NULL)
{
char *zbased;
@@ -875,8 +956,24 @@ fremote_rec_reply (qtrans, qdaemon)
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
char absend[50];
- sprintf (absend, "RY 0%o 0x%lx", qtrans->s.imode,
- (unsigned long) qinfo->cbytes);
+ qtrans->fsendfile = TRUE;
+ qtrans->psendfn = fsend_file_end;
+ qtrans->precfn = fsend_await_confirm;
+
+ if (! fqueue_send (qdaemon, qtrans))
+ return FALSE;
+
+ /* We send the file size because SVR4 UUCP does. We don't look for
+ it. We send a trailing M if we want to request a hangup. We
+ send it both after the mode and at the end of the entire string;
+ I don't know where programs look for it. */
+ if (qdaemon->frequest_hangup)
+ DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
+ "fremote_rec_reply: Requesting remote to transfer control");
+ sprintf (absend, "RY 0%o%s 0x%lx%s", qtrans->s.imode,
+ qdaemon->frequest_hangup ? "M" : "",
+ (unsigned long) qinfo->cbytes,
+ qdaemon->frequest_hangup ? "M" : "");
if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, absend, qtrans->ilocal,
qtrans->iremote))
{
@@ -885,8 +982,10 @@ fremote_rec_reply (qtrans, qdaemon)
return FALSE;
}
- qtrans->zlog = zbufalc (sizeof "Sending " + strlen (qtrans->s.zfrom));
- sprintf (qtrans->zlog, "Sending %s", qtrans->s.zfrom);
+ qtrans->zlog = zbufalc (sizeof "Sending ( bytes) "
+ + strlen (qtrans->s.zfrom) + 25);
+ sprintf (qtrans->zlog, "Sending %s (%ld bytes)", qtrans->s.zfrom,
+ qinfo->cbytes);
if (qdaemon->qproto->pffile != NULL)
{
@@ -898,16 +997,9 @@ fremote_rec_reply (qtrans, qdaemon)
usfree_send (qtrans);
return FALSE;
}
-
- if (fhandled)
- return TRUE;
}
- qtrans->fsendfile = TRUE;
- qtrans->psendfn = fsend_file_end;
- qtrans->precfn = fsend_await_confirm;
-
- return fqueue_send (qdaemon, qtrans);
+ return TRUE;
}
/* If we can't send a file as requested by the remote system, queue up
@@ -1057,6 +1149,7 @@ fsend_await_confirm (qtrans, qdaemon, zdata, cdata)
ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname,
TRUE, qtrans->cbytes, qtrans->isecs, qtrans->imicros,
qdaemon->fmaster);
+ qdaemon->csent += qtrans->cbytes;
if (zerr == NULL)
{
diff --git a/gnu/libexec/uucp/uucico/time.c b/gnu/libexec/uucp/uucico/time.c
index 4305e990e245..727a4c8066c6 100644
--- a/gnu/libexec/uucp/uucico/time.c
+++ b/gnu/libexec/uucp/uucico/time.c
@@ -1,7 +1,7 @@
/* time.c
Routines to deal with UUCP time spans.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,18 +20,20 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char time_rcsid[] = "$Id: time.c,v 1.1 1993/08/05 18:27:20 conklin Exp $";
+const char time_rcsid[] = "$Id: time.c,v 1.2 1994/05/07 18:13:58 ache Exp $";
#endif
#include <ctype.h>
-#if HAVE_TIME_H
+#if TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
#include <time.h>
#endif
diff --git a/gnu/libexec/uucp/uucico/trans.c b/gnu/libexec/uucp/uucico/trans.c
index 2bb4d228195c..f53aa3b1244f 100644
--- a/gnu/libexec/uucp/uucico/trans.c
+++ b/gnu/libexec/uucp/uucico/trans.c
@@ -1,7 +1,7 @@
/* trans.c
Routines to handle file transfers.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char trans_rcsid[] = "$Id: trans.c,v 1.1 1993/08/05 18:27:21 conklin Exp $";
+const char trans_rcsid[] = "$Id: trans.c,v 1.2 1994/05/07 18:13:59 ache Exp $";
#endif
#include <errno.h>
@@ -233,7 +233,39 @@ fqueue_send (qdaemon, qtrans)
ulog (LOG_FATAL, "fqueue_send: Bad call");
#endif
utdequeue (qtrans);
- utqueue (&qTsend, qtrans, FALSE);
+
+ /* Sort the send queue to always send commands before files, and to
+ sort jobs by grade. */
+ if (qTsend == NULL)
+ utqueue (&qTsend, qtrans, FALSE);
+ else
+ {
+ register struct stransfer *q;
+ boolean ffirst;
+
+ ffirst = TRUE;
+ q = qTsend;
+ do
+ {
+ if (! qtrans->fsendfile && q->fsendfile)
+ break;
+ if ((! qtrans->fsendfile || q->fsendfile)
+ && UUCONF_GRADE_CMP (qtrans->s.bgrade, q->s.bgrade) < 0)
+ break;
+
+ ffirst = FALSE;
+ q = q->qnext;
+ }
+ while (q != qTsend);
+
+ qtrans->qnext = q;
+ qtrans->qprev = q->qprev;
+ q->qprev = qtrans;
+ qtrans->qprev->qnext = qtrans;
+ if (ffirst)
+ qTsend = qtrans;
+ qtrans->pqqueue = &qTsend;
+ }
/* Since we're now going to wait to send data, don't charge this
transfer for receive time. */
@@ -273,7 +305,7 @@ utchanalc (qdaemon, qtrans)
do
{
++iTchan;
- if (iTchan > qdaemon->qproto->cchans)
+ if (iTchan > qdaemon->cchans)
iTchan = 1;
}
while (aqTchan[iTchan] != NULL);
@@ -388,6 +420,7 @@ utransfree (q)
}
#if DEBUG > 0
+ q->e = EFILECLOSED;
q->zcmd = NULL;
q->s.zfrom = NULL;
q->s.zto = NULL;
@@ -625,18 +658,12 @@ static boolean
fcheck_queue (qdaemon)
struct sdaemon *qdaemon;
{
- int cchans;
-
/* Only check if we are the master, or if there are multiple
channels, or if we aren't already trying to get the other side to
hang up. Otherwise, there's nothing we can do with any new jobs
we might find. */
- if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
- cchans = 1;
- else
- cchans = qdaemon->qproto->cchans;
if (qdaemon->fmaster
- || cchans > 1
+ || qdaemon->cchans > 1
|| ! qdaemon->frequest_hangup)
{
boolean fany;
@@ -649,7 +676,7 @@ fcheck_queue (qdaemon)
/* If we found something to do, and we're not the master, and we
don't have multiple channels to send new jobs over, try to
get the other side to hang up. */
- if (fany && ! qdaemon->fmaster && cchans <= 1)
+ if (fany && ! qdaemon->fmaster && qdaemon->cchans <= 1)
qdaemon->frequest_hangup = TRUE;
}
@@ -663,17 +690,8 @@ boolean
floop (qdaemon)
struct sdaemon *qdaemon;
{
- int cchans;
boolean fret;
- /* If we are using a half-duplex line, act as though we have only a
- single channel; otherwise we might start a send and a receive at
- the same time. */
- if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
- cchans = 1;
- else
- cchans = qdaemon->qproto->cchans;
-
fret = TRUE;
while (! qdaemon->fhangup)
@@ -759,9 +777,9 @@ floop (qdaemon)
/* If we are the master, or if we have multiple channels, try to
queue up additional local jobs. */
- if (qdaemon->fmaster || cchans > 1)
+ if (qdaemon->fmaster || qdaemon->cchans > 1)
{
- while (qTlocal != NULL && cTchans < cchans)
+ while (qTlocal != NULL && cTchans < qdaemon->cchans)
{
/* We have room for an additional channel. */
q = qTlocal;
@@ -821,11 +839,14 @@ floop (qdaemon)
q->zlog = NULL;
}
- /* We can read the file in a tight loop until qTremote
- changes or until we have transferred the entire file.
- We can disregard any changes to qTlocal since we
- already have something to send anyhow. */
- while (qTremote == NULL)
+ /* We can read the file in a tight loop until we have a
+ command to send, or the file send has been cancelled,
+ or we have a remote job to deal with. We can
+ disregard any changes to qTlocal since we already
+ have something to send anyhow. */
+ while (q == qTsend
+ && q->fsendfile
+ && qTremote == NULL)
{
char *zdata;
size_t cdata;
@@ -865,11 +886,6 @@ floop (qdaemon)
break;
}
- /* It is possible that this transfer has just been
- cancelled. */
- if (q != qTsend || ! q->fsendfile)
- break;
-
if (cdata == 0)
{
/* We must update the time now, because this
@@ -978,7 +994,6 @@ fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos,
else
{
/* Get the transfer structure this data is intended for. */
-
q = qtchan (ilocal);
}
@@ -1014,7 +1029,8 @@ fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos,
else
cnew = cfirst;
znew = zbufalc (q->ccmd + cnew + 1);
- memcpy (znew, q->zcmd, q->ccmd);
+ if (q->ccmd > 0)
+ memcpy (znew, q->zcmd, q->ccmd);
memcpy (znew + q->ccmd, zfirst, cnew);
znew[q->ccmd + cnew] = '\0';
ubuffree (q->zcmd);
@@ -1206,6 +1222,12 @@ ftadd_cmd (qdaemon, z, clen, iremote, flast)
return TRUE;
}
+ /* Some systems seem to sometimes send garbage at the end of the
+ command. Avoid interpreting it as a size if sizes are not
+ supported. */
+ if ((qdaemon->ifeatures & FEATURE_SIZES) == 0)
+ s.cbytes = -1;
+
if (s.bcmd != 'H' && s.bcmd != 'Y' && s.bcmd != 'N')
ulog_user (s.zuser);
else
@@ -1391,9 +1413,15 @@ ufailed (qdaemon)
{
if ((q->fsendfile || q->frecfile)
&& q->cbytes > 0)
- ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
- q->fsendfile, q->cbytes, q->isecs, q->imicros,
- FALSE);
+ {
+ ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
+ q->fsendfile, q->cbytes, q->isecs, q->imicros,
+ FALSE);
+ if (q->fsendfile)
+ qdaemon->csent += q->cbytes;
+ else
+ qdaemon->creceived += q->cbytes;
+ }
if (q->frecfile)
(void) frec_discard_temp (qdaemon, q);
q = q->qnext;
@@ -1408,9 +1436,15 @@ ufailed (qdaemon)
{
if ((q->fsendfile || q->frecfile)
&& q->cbytes > 0)
- ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
- q->fsendfile, q->cbytes, q->isecs, q->imicros,
- FALSE);
+ {
+ ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
+ q->fsendfile, q->cbytes, q->isecs, q->imicros,
+ FALSE);
+ if (q->fsendfile)
+ qdaemon->csent += q->cbytes;
+ else
+ qdaemon->creceived += q->cbytes;
+ }
if (q->frecfile)
(void) frec_discard_temp (qdaemon, q);
q = q->qnext;
diff --git a/gnu/libexec/uucp/uucico/uucico.8 b/gnu/libexec/uucp/uucico/uucico.8
index ccc93afab563..3915e82f163c 100644
--- a/gnu/libexec/uucp/uucico/uucico.8
+++ b/gnu/libexec/uucp/uucico/uucico.8
@@ -1,5 +1,5 @@
-''' $Id: uucico.8,v 1.1.2.1 1994/05/01 16:02:47 jkh Exp $
-.TH uucico 8 "Taylor UUCP 1.04"
+''' $Id: uucico.8,v 1.3 1994/05/07 18:14:01 ache Exp $
+.TH uucico 8 "Taylor UUCP 1.05"
.SH NAME
uucico \- UUCP file transfer daemon
.SH SYNOPSIS
@@ -23,17 +23,17 @@ entries in the
.I crontab
table(s).
-When invoked with the
-.B \-r1
-option or the
-.B \-s
+When invoked with
+.B \-r1,
+.B \-\-master,
+.B \-s,
+.B \-\-system,
or
-.B \-S
-option, the daemon will place a call to a remote system, running in
-master mode.
-Otherwise the daemon will start in slave mode, accepting a
-call from a remote system. Typically a special login name will be set
-up for UUCP which automatically invokes
+.B \-S,
+the daemon will place a call to a remote system, running in master
+mode. Otherwise the daemon will start in slave mode, accepting a call
+from a remote system. Typically a special login name will be set up
+for UUCP which automatically invokes
.I uucico
when a call is made.
@@ -43,6 +43,8 @@ terminates, it invokes the
.I uuxqt
(8) daemon, unless the
.B \-q
+or
+.B \-\-nouuxqt
option is given;
.I uuxqt
(8) executes any work orders created by
@@ -54,29 +56,48 @@ If a call fails,
.I uucico
will normally refuse to retry the
call until a certain (configurable) amount of time
-has passed. This may be overridden by the
-.B -f
-or the
+has passed. This may be overriden by the
+.B -f,
+.B --force,
+or
.B -S
option.
The
-.B \-l
+.B \-l,
+.B \-\-prompt,
+.B \-e,
or
-.B \-e
-option may be used to force
+.B \-\-loop
+options may be used to force
.I uucico
to produce its own prompts of "login: " and "Password:". When another
-daemon calls in, it will see these prompts and log in as usual; the
-login name and password will be checked against a separate list kept
-specially for
+daemon calls in, it will see these prompts and log in as usual. The
+login name and password will normally be checked against a separate
+list kept specially for
.I uucico
rather than the
.I /etc/passwd
+file; it is possible on some systems to direct
+.I uucico
+to use the
+.I /etc/passwd
file. The
.B \-l
-option will prompt once and then exit. The
+or
+.B \--prompt
+option will prompt once and then exit; in this mode the UUCP
+administrator or the superuser may use the
+.B \-u
+or
+.B \--login
+option to force a login name, in which case
+.I uucico
+will not prompt for one.
+The
.B \-e
+or
+.B \--loop
option will prompt again after the first session is over; in this mode
.I uucico
will permanently control a port.
@@ -87,9 +108,13 @@ receives a SIGQUIT, SIGTERM or SIGPIPE signal, it will cleanly abort
any current conversation with a remote system and exit. If it
receives a SIGHUP signal it will abort any current conversation, but
will continue to place calls to (if invoked with
-.B \-r1)
+.B \-r1
+or
+.B \-\-master)
and accept calls from (if invoked with
-.B \-e)
+.B \-e
+or
+.B \-\-loop)
other systems. If it receives a
SIGINT signal it will finish the current conversation, but will not
place or accept any more calls.
@@ -97,72 +122,91 @@ place or accept any more calls.
The following options may be given to
.I uucico.
.TP 5
-.B \-r1
+.B \-r1, \-\-master
Start in master mode (call out to a system); implied by
-.B \-s
+.B \-s,
+.B \-\-system,
or
.B \-S.
If no system is specified, call any system for which work is waiting
to be done.
.TP 5
-.B \-r0
+.B \-r0, \-\-slave
Start in slave mode. This is the default.
.TP 5
-.B \-s system
+.B \-s system, \-\-system system
Call the named system.
.TP 5
.B \-S system
-Call the named system, ignoring any required wait.
+Call the named system, ignoring any required wait. This is equivalent
+to
+.B \-s system \-f.
.TP 5
-.B \-f
+.B \-f, \-\-force
Ignore any required wait for any systems to be called.
.TP 5
-.B \-l
+.B \-l, \-\-prompt
Prompt for login name and password using "login: " and "Password:".
This allows
.I uucico
to be easily run from
.I inetd
(8). The login name and password are checked against the UUCP
-password file, which has no connection to the file
+password file, which probably has no connection to the file
.I /etc/passwd.
+The
+.B \-\-login
+option may be used to force a login name, in which cause
+.I uucico
+will only prompt for a password.
.TP 5
-.B \-p port
-Specify a port to call out on or to listen to. In slave mode, this
-implies
-.B \-e.
+.B \-p port, \-\-port port
+Specify a port to call out on or to listen to.
.TP 5
-.B \-e
+.B \-e, \-\-loop
Enter endless loop of login/password prompts and slave mode daemon
execution. The program will not stop by itself; you must use
.I kill
(1) to shut it down.
.TP 5
-.B \-w
+.B \-w, \-\-wait
After calling out (to a particular system when
-.B \-s
+.B \-s,
+.B \-\-system,
or
.B \-S
-is specified, or to all systems which have work when
+is specifed, or to all systems which have work when just
.B \-r1
-is specified), begin an endless loop as with
-.B \-e.
+or
+.B \-\-master
+is specifed), begin an endless loop as with
+.B \-\-loop.
.TP 5
-.B \-q
+.B \-q, \-\-nouuxqt
Do not start the
.I uuxqt
(8) daemon when finished.
.TP 5
-.B \-c
+.B \-c, \-\-quiet
If no calls are permitted at this time, then don't make the call, but
also do not put an error message in the log file and do not update the
system status (as reported by
.I uustat
(1)). This can be convenient for automated polling scripts, which may
want to simply attempt to call every system rather than worry about
-which particular systems may be called at the moment.
+which particular systems may be called at the moment. This option
+also suppresses the log message indicating that there is no work to be
+done.
.TP 5
-.B \-D
+.B \-C, \-\-ifwork
+Only call the system named by
+.B \-s,
+.B \-\-system
+or
+.B \-S
+if there is work for that system.
+.TP 5
+.B \-D, \-\-nodetach
Do not detach from the controlling terminal. Normally
.I uucico
detaches from the terminal before each call out to another system and
@@ -170,29 +214,57 @@ before invoking
.I uuxqt.
This option prevents this.
.TP 5
-.B \-x type, \-X type
+.B \-u name, \-\-login name
+Set the login name to use instead of that of the invoking user. This
+option may only be used by the UUCP administrator or the superuser.
+If used with
+.B \-\-prompt,
+this will cause
+.I uucico
+to prompt only for the password, not the login name.
+.TP 5
+.B \-z, \-\-try-next
+If a call fails after the remote system is reached, try the next
+alternate rather than simply exiting.
+.TP 5
+.B \-i type, \-\-stdin type
+Set the type of port to use when using standard input. The only
+support port type is TLI, and this is only available on machines which
+support the TLI networking interface. Specifying
+.B \-iTLI
+causes
+.I uucico
+to use TLI calls to perform I/O.
+.TP 5
+.B \-x type, \-X type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
+.B \-\-debug abnormal,chat.
The debugging output is sent to the debugging file, usually one of
/usr/spool/uucp/Debug, /usr/spool/uucp/DEBUG, or
/usr/spool/uucp/.Admin/audit.local.
.TP 5
-.B \-I file
+.B \-I file, \-\-config file
Set configuration file to use. This option may not be available,
depending upon how
.I uucico
was compiled.
.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
+.TP 5
.B \-u login
This option is ignored. It is only included because some versions of
uucpd invoke
@@ -222,4 +294,4 @@ Debugging file.
kill(1), uucp(1), uux(1), uustat(1), uuxqt(8)
.SH AUTHOR
Ian Lance Taylor
-(ian@airs.com or uunet!airs!ian)
+<ian@airs.com>
diff --git a/gnu/libexec/uucp/uucico/uucico.c b/gnu/libexec/uucp/uucico/uucico.c
index 01717c4bcf4f..29a42573e859 100644
--- a/gnu/libexec/uucp/uucico/uucico.c
+++ b/gnu/libexec/uucp/uucico/uucico.c
@@ -1,7 +1,7 @@
/* uucico.c
This is the main UUCP communication program.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uucico_rcsid[] = "$Id: uucico.c,v 1.1 1993/08/05 18:27:24 conklin Exp $";
+const char uucico_rcsid[] = "$Id: uucico.c,v 1.3 1994/05/25 20:14:52 ache Exp $";
#endif
#include <ctype.h>
@@ -45,10 +45,21 @@ const char uucico_rcsid[] = "$Id: uucico.c,v 1.1 1993/08/05 18:27:24 conklin Exp
#include "prot.h"
#include "trans.h"
#include "system.h"
-
-/* The program name. */
-char abProgram[] = "uucico";
+#if HAVE_ENCRYPTED_PASSWORDS
+#ifndef crypt
+extern char *crypt ();
+#endif
+#endif
+
+/* Coherent already had a different meaning for the -c option. What a
+ pain. */
+#ifdef __COHERENT__
+#define COHERENT_C_OPTION 1
+#else
+#define COHERENT_C_OPTION 0
+#endif
+
/* Define the known protocols. */
#define TCP_PROTO \
@@ -58,30 +69,33 @@ char abProgram[] = "uucico";
static const struct sprotocol asProtocols[] =
{
- { 't', TCP_PROTO, 1,
+ { 't', TCP_PROTO, 1, TRUE,
asTproto_params, ftstart, ftshutdown, ftsendcmd, ztgetspace,
ftsenddata, ftwait, ftfile },
- { 'e', TCP_PROTO, 1,
+ { 'e', TCP_PROTO, 1, TRUE,
asEproto_params, festart, feshutdown, fesendcmd, zegetspace,
fesenddata, fewait, fefile },
- { 'i', UUCONF_RELIABLE_EIGHT, 7,
+ { 'i', UUCONF_RELIABLE_EIGHT, 7, TRUE,
asIproto_params, fistart, fishutdown, fisendcmd, zigetspace,
fisenddata, fiwait, NULL },
- { 'a', UUCONF_RELIABLE_EIGHT, 1,
+ { 'a', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asZproto_params, fzstart, fzshutdown, fzsendcmd, zzgetspace,
fzsenddata, fzwait, fzfile },
- { 'g', UUCONF_RELIABLE_EIGHT, 1,
+ { 'g', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asGproto_params, fgstart, fgshutdown, fgsendcmd, zggetspace,
fgsenddata, fgwait, NULL },
- { 'G', UUCONF_RELIABLE_EIGHT, 1,
+ { 'G', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asGproto_params, fbiggstart, fgshutdown, fgsendcmd, zggetspace,
fgsenddata, fgwait, NULL },
- { 'j', UUCONF_RELIABLE_EIGHT, 7,
+ { 'j', UUCONF_RELIABLE_EIGHT, 7, TRUE,
asIproto_params, fjstart, fjshutdown, fisendcmd, zigetspace,
fisenddata, fiwait, NULL },
- { 'f', UUCONF_RELIABLE_RELIABLE, 1,
+ { 'f', UUCONF_RELIABLE_RELIABLE, 1, FALSE,
asFproto_params, ffstart, ffshutdown, ffsendcmd, zfgetspace,
ffsenddata, ffwait, fffile },
+ { 'v', UUCONF_RELIABLE_EIGHT, 1, TRUE,
+ asGproto_params, fvstart, fgshutdown, fgsendcmd, zggetspace,
+ fgsenddata, fgwait, NULL }
};
#define CPROTOCOLS (sizeof asProtocols / sizeof asProtocols[0])
@@ -112,12 +126,13 @@ struct spass
/* Local functions. */
static void uusage P((void));
+static void uhelp P((void));
static void uabort P((void));
-static boolean fcall P((pointer puuconf,
+static boolean fcall P((pointer puuconf, const char *zconfig, boolean fuuxqt,
const struct uuconf_system *qsys,
struct uuconf_port *qport, boolean fifwork,
boolean fforce, boolean fdetach,
- boolean ftimewarn));
+ boolean fquiet, boolean ftrynext));
static boolean fconn_call P((struct sdaemon *qdaemon,
struct uuconf_port *qport,
struct sstatus *qstat, int cretry,
@@ -127,11 +142,19 @@ static boolean fdo_call P((struct sdaemon *qdaemon,
const struct uuconf_dialer *qdialer,
boolean *pfcalled, enum tstatus_type *pterr));
static int iuport_lock P((struct uuconf_port *qport, pointer pinfo));
-static boolean flogin_prompt P((pointer puuconf,
- struct sconnection *qconn));
-static boolean faccept_call P((pointer puuconf, const char *zlogin,
+static boolean flogin_prompt P((pointer puuconf, const char *zconfig,
+ boolean fuuxqt, struct sconnection *qconn,
+ const char *zlogin));
+static int icallin_cmp P((int iwhich, pointer pinfo, const char *zfile));
+static boolean faccept_call P((pointer puuconf, const char *zconfig,
+ boolean fuuxqt, const char *zlogin,
struct sconnection *qconn,
const char **pzsystem));
+static void uaccept_call_cleanup P((pointer puuconf,
+ struct uuconf_system *qfreesys,
+ struct uuconf_port *qport,
+ struct uuconf_port *qfreeport,
+ char *zloc));
static void uapply_proto_params P((pointer puuconf, int bproto,
struct uuconf_cmdtab *qcmds,
struct uuconf_proto_param *pas));
@@ -142,21 +165,47 @@ static char *zget_uucp_cmd P((struct sconnection *qconn,
static char *zget_typed_line P((struct sconnection *qconn));
/* Long getopt options. */
-static const struct option asLongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asLongopts[] =
+{
+ { "quiet", no_argument, NULL, 2 },
+ { "ifwork", no_argument, NULL, 'C' },
+ { "nodetach", no_argument, NULL, 'D' },
+ { "loop", no_argument, NULL, 'e' },
+ { "force", no_argument, NULL, 'f'},
+ { "stdin", required_argument, NULL, 'i' },
+ { "prompt", no_argument, NULL, 'l' },
+ { "port", required_argument, NULL, 'p' },
+ { "nouuxqt", no_argument, NULL, 'q' },
+ { "master", no_argument, NULL, 3 },
+ { "slave", no_argument, NULL, 4 },
+ { "system", required_argument, NULL, 's' },
+ { "login", required_argument, NULL, 'u' },
+ { "wait", no_argument, NULL, 'w' },
+ { "try-next", no_argument, NULL, 'z' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
int argc;
char **argv;
{
- /* -c: Whether to warn if a call is attempted at a bad time. */
- boolean ftimewarn = TRUE;
+ /* -c: Whether to be quiet. */
+ boolean fquiet = FALSE;
+ /* -C: Only call the system if there is work. */
+ boolean fifwork = FALSE;
/* -D: don't detach from controlling terminal. */
boolean fdetach = TRUE;
/* -e: Whether to do an endless loop of accepting calls. */
boolean fendless = FALSE;
/* -f: Whether to force a call despite status of previous call. */
boolean fforce = FALSE;
+ /* -i type: type of port to use for stdin. */
+ enum uuconf_porttype tstdintype = UUCONF_PORTTYPE_STDIN;
/* -I file: configuration file name. */
const char *zconfig = NULL;
/* -l: Whether to give a single login prompt. */
@@ -172,8 +221,13 @@ main (argc, argv)
boolean fmaster = FALSE;
/* -s,-S system: system to call. */
const char *zsystem = NULL;
+ /* -u: Login name to use. */
+ const char *zlogin = NULL;
/* -w: Whether to wait for a call after doing one. */
boolean fwait = FALSE;
+ /* -z: Try next alternate if call fails. */
+ boolean ftrynext = FALSE;
+ const char *zopts;
int iopt;
struct uuconf_port *qport;
struct uuconf_port sport;
@@ -184,15 +238,40 @@ main (argc, argv)
int iholddebug;
#endif
- while ((iopt = getopt_long (argc, argv,
- "cDefI:lp:qr:s:S:u:x:X:w",
+ zProgram = argv[0];
+
+ /* When uucico is invoked by login, the first character of the
+ program will be a dash. We don't want that. */
+ if (*zProgram == '-')
+ ++zProgram;
+
+#if COHERENT_C_OPTION
+ zopts = "c:CDefi:I:lp:qr:s:S:u:x:X:vwz";
+#else
+ zopts = "cCDefi:I:lp:qr:s:S:u:x:X:vwz";
+#endif
+
+ while ((iopt = getopt_long (argc, argv, zopts,
asLongopts, (int *) NULL)) != EOF)
{
+#if COHERENT_C_OPTION
+ if (iopt == 'c')
+ {
+ iopt = 's';
+ fifwork = TRUE;
+ }
+#endif
switch (iopt)
{
+ case 2:
case 'c':
- /* Don't warn if a call is attempted at a bad time. */
- ftimewarn = FALSE;
+ /* Don't warn if a call is attempted at a bad time, and
+ don't print the "No work" message. */
+ fquiet = TRUE;
+ break;
+
+ case 'C':
+ fifwork = TRUE;
break;
case 'D':
@@ -211,10 +290,23 @@ main (argc, argv)
fforce = TRUE;
break;
- case 'I':
- /* Set configuration file name (default is in sysdep.h). */
- if (fsysdep_other_config (optarg))
- zconfig = optarg;
+ case 'i':
+ /* Type of port to use for standard input. Only TLI is
+ supported here, and only if HAVE_TLI is true. This
+ permits the Network Listener to tell uucico to use TLI
+ I/O calls. */
+ if (strcasecmp (optarg, "tli") != 0)
+ fprintf (stderr, "%s: unsupported port type \"%s\"\n",
+ zProgram, optarg);
+ else
+ {
+#if HAVE_TLI
+ tstdintype = UUCONF_PORTTYPE_TLI;
+#else
+ fprintf (stderr, "%s: not compiled with TLI support\n",
+ zProgram);
+#endif
+ }
break;
case 'l':
@@ -257,31 +349,71 @@ main (argc, argv)
case 'u':
/* Some versions of uucpd invoke uucico with a -u argument
- specifying the login name. I'm told it is safe to ignore
- this value, although perhaps we should use it rather than
- zsysdep_login_name (). */
+ specifying the login name. If invoked by a privileged
+ user, we use it instead of the result of
+ zsysdep_login_name. */
+ if (fsysdep_privileged ())
+ zlogin = optarg;
+ else
+ fprintf (stderr,
+ "%s: ignoring command line login name: not a privileged user\n",
+ zProgram);
+ break;
+
+ case 'w':
+ /* Call out and then wait for a call in */
+ fwait = TRUE;
+ break;
+
+ case 'z':
+ /* Try next alternate if call fails. */
+ ftrynext = TRUE;
+ break;
+
+ case 'I':
+ /* Set configuration file name (default is in sysdep.h). */
+ if (fsysdep_other_config (optarg))
+ zconfig = optarg;
break;
case 'x':
case 'X':
#if DEBUG > 1
- /* Set debugging level */
+ /* Set debugging level. */
iDebug |= idebug_parse (optarg);
#endif
break;
- case 'w':
- /* Call out and then wait for a call in */
- fwait = TRUE;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 4:
+ /* --slave. */
+ fmaster = FALSE;
+ break;
+
+ case 3:
+ /* --master. */
+ fmaster = TRUE;
break;
+ case 1:
+ /* --help. */
+ uhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found, and flag value set. */
break;
default:
uusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -290,7 +422,7 @@ main (argc, argv)
if (fwait && zport == NULL)
{
- ulog (LOG_ERROR, "-w requires -e");
+ fprintf (stderr, "%s: -w requires -p", zProgram);
uusage ();
}
@@ -321,7 +453,7 @@ main (argc, argv)
pointer))) NULL,
(pointer) NULL, &sport);
if (iuuconf == UUCONF_NOT_FOUND)
- ulog (LOG_FATAL, "%s: Port not found", zport);
+ ulog (LOG_FATAL, "%s: port not found", zport);
else if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
qport = &sport;
@@ -384,8 +516,8 @@ main (argc, argv)
else
{
fLocked_system = TRUE;
- fret = fcall (puuconf, &sLocked_system, qport, FALSE,
- fforce, fdetach, ftimewarn);
+ fret = fcall (puuconf, zconfig, fuuxqt, &sLocked_system, qport,
+ fifwork, fforce, fdetach, fquiet, ftrynext);
if (fLocked_system)
{
(void) fsysdep_unlock_system (&sLocked_system);
@@ -468,8 +600,9 @@ main (argc, argv)
else
{
fLocked_system = TRUE;
- if (! fcall (puuconf, &sLocked_system, qport, TRUE,
- fforce, fdetach, ftimewarn))
+ if (! fcall (puuconf, zconfig, fuuxqt, &sLocked_system,
+ qport, TRUE, fforce, fdetach, fquiet,
+ ftrynext))
fret = FALSE;
/* Now ignore any SIGHUP that we got. */
@@ -493,7 +626,7 @@ main (argc, argv)
xfree ((pointer) pznames);
- if (! fdidone)
+ if (! fdidone && ! fquiet)
ulog (LOG_NORMAL, "No work");
}
@@ -520,7 +653,7 @@ main (argc, argv)
fret = TRUE;
zsystem = NULL;
- if (! fconn_init (qport, &sconn))
+ if (! fconn_init (qport, &sconn, tstdintype))
fret = FALSE;
if (qport != NULL)
@@ -531,9 +664,6 @@ main (argc, argv)
if (fdetach
&& qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
usysdep_detach ();
-
- /* If a port was given, we loop forever. */
- fendless = TRUE;
}
if (fconn_lock (&sconn, TRUE))
@@ -558,17 +688,14 @@ main (argc, argv)
if (fendless)
{
while (! FGOT_SIGNAL ()
- && flogin_prompt (puuconf, &sconn))
+ && flogin_prompt (puuconf, zconfig, fuuxqt, &sconn,
+ (const char *) NULL))
{
- /* Now ignore any SIGHUP that we got. */
- afSignal[INDEXSIG_SIGHUP] = FALSE;
-
- if (fLocked_system)
- {
- (void) fsysdep_unlock_system (&sLocked_system);
- fLocked_system = FALSE;
- }
- if (! fconn_reset (&sconn))
+ /* Close and reopen the port in between calls. */
+ if (! fconn_close (&sconn, puuconf,
+ (struct uuconf_dialer *) NULL,
+ TRUE)
+ || ! fconn_open (&sconn, (long) 0, (long) 0, TRUE))
break;
}
fret = FALSE;
@@ -576,13 +703,16 @@ main (argc, argv)
else
{
if (flogin)
- fret = flogin_prompt (puuconf, &sconn);
+ fret = flogin_prompt (puuconf, zconfig, fuuxqt, &sconn,
+ zlogin);
else
{
#if DEBUG > 1
iholddebug = iDebug;
#endif
- fret = faccept_call (puuconf, zsysdep_login_name (),
+ if (zlogin == NULL)
+ zlogin = zsysdep_login_name ();
+ fret = faccept_call (puuconf, zconfig, fuuxqt, zlogin,
&sconn, &zsystem);
#if DEBUG > 1
iDebug = iholddebug;
@@ -602,12 +732,6 @@ main (argc, argv)
if (flocked)
(void) fconn_unlock (&sconn);
- if (fLocked_system)
- {
- (void) fsysdep_unlock_system (&sLocked_system);
- fLocked_system = FALSE;
- }
-
uconn_free (&sconn);
}
@@ -622,19 +746,19 @@ main (argc, argv)
if (fuuxqt)
{
- /* Detach from the controlling terminal before starting up uuxqt,
- so that it runs as a true daemon. */
- if (fdetach)
- usysdep_detach ();
- if (zsystem == NULL)
- {
- if (! fsysdep_run ("uuxqt", (const char *) NULL,
- (const char *) NULL))
- fret = FALSE;
- }
- else
+ int irunuuxqt;
+
+ iuuconf = uuconf_runuuxqt (puuconf, &irunuuxqt);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ else if (irunuuxqt == UUCONF_RUNUUXQT_ONCE)
{
- if (! fsysdep_run ("uuxqt", "-s", zsystem))
+ /* Detach from the controlling terminal before starting up uuxqt,
+ so that it runs as a true daemon. */
+ if (fdetach)
+ usysdep_detach ();
+
+ if (! fspawn_uuxqt (FALSE, zsystem, zconfig))
fret = FALSE;
}
}
@@ -645,40 +769,46 @@ main (argc, argv)
return 0;
}
-/* Print out a usage message. */
+/* Print out a usage message and die. */
static void
uusage ()
{
- fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ fprintf (stderr, "Usage: %s [options]\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+uhelp ()
+{
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
- fprintf (stderr,
- "Usage: uucico [options]\n");
- fprintf (stderr,
- " -s,-S system: Call system (-S implies -f)\n");
- fprintf (stderr,
- " -f: Force call despite system status\n");
- fprintf (stderr,
- " -r state: 1 for master, 0 for slave (default)\n");
- fprintf (stderr,
- " -p port: Specify port (implies -e)\n");
- fprintf (stderr,
- " -l: prompt for login name and password\n");
- fprintf (stderr,
- " -e: Endless loop of login prompts and daemon execution\n");
- fprintf (stderr,
- " -w: After calling out, wait for incoming calls\n");
- fprintf (stderr,
- " -q: Don't start uuxqt when done\n");
- fprintf (stderr,
- " -x,-X debug: Set debugging level\n");
+ printf ("Usage: %s [options]\n", zProgram);
+ printf (" -s,-S,--system system: Call system (-S implies -f)\n");
+ printf (" -f,--force: Force call despite system status\n");
+ printf (" -r state: 1 for master, 0 for slave (default)\n");
+ printf (" --master: Act as master\n");
+ printf (" --slave: Act as slave (default)\n");
+ printf (" -p,--port port: Specify port\n");
+ printf (" -l,--prompt: prompt for login name and password\n");
+ printf (" -e,--loop: Endless loop of login prompts and daemon execution\n");
+ printf (" -w,--wait: After calling out, wait for incoming calls\n");
+ printf (" -q,--nouuxqt: Don't start uuxqt when done\n");
+ printf (" -c,--quiet: Don't log bad time or no work warnings\n");
+ printf (" -C,--ifwork: Only call named system if there is work\n");
+ printf (" -D,--nodetach: Don't detach from controlling terminal\n");
+ printf (" -u,--login: Set login name (privileged users only)\n");
+ printf (" -i,--stdin type: Type of standard input (only TLI supported)\n");
+ printf (" -z,--try-next: If a call fails, try the next alternate\n");
+ printf (" -x,-X,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
-
- exit (EXIT_FAILURE);
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
}
/* This function is called when a LOG_FATAL error occurs. */
@@ -713,28 +843,36 @@ uabort ()
usysdep_exit (FALSE);
}
+/* The number of seconds in one day. We must cast to long for this
+ to be calculated correctly on a machine with 16 bit ints. */
+#define SECS_PER_DAY ((long) 24 * (long) 60 * (long) 60)
+
/* Call another system, trying all the possible sets of calling
instructions. The qsys argument is the system to call. The qport
argument is the port to use, and may be NULL. If the fifwork
argument is TRUE, the call is only placed if there is work to be
done. If the fforce argument is TRUE, a call is forced even if not
- enough time has passed since the last failed call. If the
- ftimewarn argument is TRUE (the normal case), then a warning is
- given if calls are not permitted at this time. */
+ enough time has passed since the last failed call. If the fquiet
+ argument is FALSE (the normal case), then a warning is given if
+ calls are not permitted at this time. */
static boolean
-fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
+fcall (puuconf, zconfig, fuuxqt, qorigsys, qport, fifwork, fforce, fdetach,
+ fquiet, ftrynext)
pointer puuconf;
+ const char *zconfig;
+ boolean fuuxqt;
const struct uuconf_system *qorigsys;
struct uuconf_port *qport;
boolean fifwork;
boolean fforce;
boolean fdetach;
- boolean ftimewarn;
+ boolean fquiet;
+ boolean ftrynext;
{
struct sstatus sstat;
long inow;
- boolean fbadtime, fnevertime;
+ boolean fbadtime, fnevertime, ffoundwork;
const struct uuconf_system *qsys;
if (! fsysdep_get_status (qorigsys, &sstat, (boolean *) NULL))
@@ -744,21 +882,24 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
that we haven't exceeded the maximum number of retries. Even if
we are over the limit on retries, we permit a call to be made if
24 hours have passed. This 24 hour limit is still controlled by
- the retry time. */
+ the retry time. We ignore times in the future, presumably the
+ result of some sort of error. */
inow = ixsysdep_time ((long *) NULL);
if (! fforce)
{
if (qorigsys->uuconf_cmax_retries > 0
&& sstat.cretries >= qorigsys->uuconf_cmax_retries
- && sstat.ilast + 24 * 60 * 60 < inow)
+ && sstat.ilast <= inow
+ && sstat.ilast + SECS_PER_DAY > inow)
{
ulog (LOG_ERROR, "Too many retries");
return FALSE;
}
- if (sstat.ttype == STATUS_COMPLETE
- ? sstat.ilast + qorigsys->uuconf_csuccess_wait > inow
- : sstat.ilast + sstat.cwait > inow)
+ if ((sstat.ttype == STATUS_COMPLETE
+ ? sstat.ilast + qorigsys->uuconf_csuccess_wait > inow
+ : sstat.ilast + sstat.cwait > inow)
+ && sstat.ilast <= inow)
{
ulog (LOG_NORMAL, "Retry time not reached");
return FALSE;
@@ -766,25 +907,21 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
}
sDaemon.puuconf = puuconf;
- sDaemon.qsys = NULL;
- sDaemon.zlocalname = NULL;
- sDaemon.qconn = NULL;
- sDaemon.qproto = NULL;
- sDaemon.clocal_size = -1;
- sDaemon.cremote_size = -1;
- sDaemon.cmax_ever = -2;
- sDaemon.cmax_receive = -1;
- sDaemon.ifeatures = 0;
- sDaemon.frequest_hangup = FALSE;
- sDaemon.fhangup_requested = FALSE;
- sDaemon.fhangup = FALSE;
- sDaemon.fmaster = TRUE;
- sDaemon.fcaller = TRUE;
- sDaemon.ireliable = 0;
- sDaemon.bgrade = '\0';
+ sDaemon.zconfig = zconfig;
+ if (! fuuxqt)
+ sDaemon.irunuuxqt = UUCONF_RUNUUXQT_NEVER;
+ else
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_runuuxqt (puuconf, &sDaemon.irunuuxqt);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ }
fbadtime = TRUE;
fnevertime = TRUE;
+ ffoundwork = FALSE;
for (qsys = qorigsys; qsys != NULL; qsys = qsys->uuconf_qalternate)
{
@@ -804,7 +941,28 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
&cretry))
continue;
+ fbadtime = FALSE;
+
sDaemon.qsys = qsys;
+ sDaemon.zlocalname = NULL;
+ sDaemon.qconn = NULL;
+ sDaemon.qproto = NULL;
+ sDaemon.cchans = 1;
+ sDaemon.clocal_size = -1;
+ sDaemon.cremote_size = -1;
+ sDaemon.cmax_ever = -2;
+ sDaemon.cmax_receive = -1;
+ sDaemon.csent = 0;
+ sDaemon.creceived = 0;
+ sDaemon.cxfiles_received = 0;
+ sDaemon.ifeatures = 0;
+ sDaemon.frequest_hangup = FALSE;
+ sDaemon.fhangup_requested = FALSE;
+ sDaemon.fhangup = FALSE;
+ sDaemon.fmaster = TRUE;
+ sDaemon.fcaller = TRUE;
+ sDaemon.ireliable = 0;
+ sDaemon.bgrade = '\0';
/* Queue up any work there is to do. */
if (! fqueue (&sDaemon, &fany))
@@ -820,7 +978,7 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
continue;
}
- fbadtime = FALSE;
+ ffoundwork = TRUE;
fret = fconn_call (&sDaemon, qport, &sstat, cretry, &fcalled);
@@ -828,7 +986,7 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
if (fret)
return TRUE;
- if (fcalled)
+ if (fcalled && ! ftrynext)
return FALSE;
/* Now we have to dump that port so that we can aquire a new
@@ -845,9 +1003,16 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
}
}
- if (fbadtime && ftimewarn)
+ /* We only get here if no call succeeded. If fbadtime is TRUE it
+ was the wrong time for all the alternates. Otherwise, if
+ ffoundwork is FALSE there was no work for any of the alternates.
+ Otherwise, we attempted a call and fconn_call logged an error
+ message. */
+
+ if (fbadtime)
{
- ulog (LOG_NORMAL, "Wrong time to call");
+ if (! fquiet)
+ ulog (LOG_NORMAL, "Wrong time to call");
/* Update the status, unless the system can never be called. If
the system can never be called, there is little point to
@@ -862,6 +1027,12 @@ fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn)
(void) fsysdep_set_status (qorigsys, &sstat);
}
}
+ else if (! ffoundwork)
+ {
+ if (! fquiet)
+ ulog (LOG_NORMAL, "No work");
+ return TRUE;
+ }
return FALSE;
}
@@ -905,7 +1076,7 @@ fconn_call (qdaemon, qport, qstat, cretry, pfcalled)
qport = qsys->uuconf_qport;
if (qport != NULL)
{
- if (! fconn_init (qport, &sconn))
+ if (! fconn_init (qport, &sconn, UUCONF_PORTTYPE_UNKNOWN))
return FALSE;
if (! fconn_lock (&sconn, FALSE))
{
@@ -972,6 +1143,7 @@ fconn_call (qdaemon, qport, qstat, cretry, pfcalled)
if (! fconn_dial (&sconn, puuconf, qsys, qsys->uuconf_zphone,
&sdialer, &tdialer))
{
+ tdialer = DIALERFOUND_FALSE;
terr = STATUS_DIAL_FAILED;
fret = FALSE;
}
@@ -1068,7 +1240,8 @@ fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
if (strncmp (zstr, "Shere", 5) != 0)
{
- ulog (LOG_ERROR, "Bad initialization string");
+ ulog (LOG_ERROR, "Bad startup string (expected \"Shere\" got \"%s\")",
+ zstr);
ubuffree (zstr);
return FALSE;
}
@@ -1218,7 +1391,7 @@ fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
if (zstr[0] != 'R')
{
- ulog (LOG_ERROR, "Bad reponse to handshake string (%s)",
+ ulog (LOG_ERROR, "Bad response to handshake string (%s)",
zstr);
ubuffree (zstr);
return FALSE;
@@ -1376,6 +1549,14 @@ fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
qdaemon->qproto = &asProtocols[i];
+ /* If we are using a half-duplex line, act as though we have only
+ a single channel; otherwise we might start a send and a receive
+ at the same time. */
+ if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
+ qdaemon->cchans = 1;
+ else
+ qdaemon->cchans = asProtocols[i].cchans;
+
sprintf (ab, "U%c", qdaemon->qproto->bname);
if (! fsend_uucp_cmd (qconn, ab))
return FALSE;
@@ -1449,8 +1630,12 @@ fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
iend_time = ixsysdep_time ((long *) NULL);
- ulog (LOG_NORMAL, "Call complete (%ld seconds)",
- iend_time - istart_time);
+ ulog (LOG_NORMAL, "Call complete (%ld seconds %ld bytes %ld bps)",
+ iend_time - istart_time,
+ qdaemon->csent + qdaemon->creceived,
+ (iend_time != istart_time
+ ? (qdaemon->csent + qdaemon->creceived) / (iend_time - istart_time)
+ : 0));
if (fret)
{
@@ -1459,6 +1644,11 @@ fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
(void) fsysdep_set_status (qsys, qstat);
}
+ if (qdaemon->irunuuxqt == UUCONF_RUNUUXQT_PERCALL
+ || (qdaemon->irunuuxqt > 0 && qdaemon->cxfiles_received > 0))
+ (void) fspawn_uuxqt (TRUE, qdaemon->qsys->uuconf_zname,
+ qdaemon->zconfig);
+
return fret;
}
}
@@ -1477,7 +1667,7 @@ iuport_lock (qport, pinfo)
q->fmatched = TRUE;
- if (! fconn_init (qport, q->qconn))
+ if (! fconn_init (qport, q->qconn, UUCONF_PORTTYPE_UNKNOWN))
return UUCONF_NOT_FOUND;
else if (! fconn_lock (q->qconn, FALSE))
{
@@ -1491,31 +1681,49 @@ iuport_lock (qport, pinfo)
}
}
+/* The information structure used for the uuconf_callin comparison
+ function. */
+
+struct scallin_info
+{
+ const char *zuser;
+ const char *zpass;
+};
+
/* Prompt for a login name and a password, and run as the slave. */
static boolean
-flogin_prompt (puuconf, qconn)
+flogin_prompt (puuconf, zconfig, fuuxqt, qconn, zlogin)
pointer puuconf;
+ const char *zconfig;
+ boolean fuuxqt;
struct sconnection *qconn;
+ const char *zlogin;
{
char *zuser, *zpass;
boolean fret;
int iuuconf;
+ struct scallin_info s;
DEBUG_MESSAGE0 (DEBUG_HANDSHAKE, "flogin_prompt: Waiting for login");
zuser = NULL;
- do
+ if (zlogin == NULL)
{
- ubuffree (zuser);
- if (! fconn_write (qconn, "login: ", sizeof "login: " - 1))
- return FALSE;
- zuser = zget_typed_line (qconn);
- }
- while (zuser != NULL && *zuser == '\0');
+ do
+ {
+ ubuffree (zuser);
+ if (! fconn_write (qconn, "login: ", sizeof "login: " - 1))
+ return FALSE;
+ zuser = zget_typed_line (qconn);
+ }
+ while (zuser != NULL && *zuser == '\0');
- if (zuser == NULL)
- return TRUE;
+ if (zuser == NULL)
+ return TRUE;
+
+ zlogin = zuser;
+ }
if (! fconn_write (qconn, "Password:", sizeof "Password:" - 1))
{
@@ -1532,8 +1740,12 @@ flogin_prompt (puuconf, qconn)
fret = TRUE;
- iuuconf = uuconf_callin (puuconf, zuser, zpass);
+ s.zuser = zlogin;
+ s.zpass = zpass;
+ iuuconf = uuconf_callin (puuconf, icallin_cmp, &s);
+
ubuffree (zpass);
+
if (iuuconf == UUCONF_NOT_FOUND)
ulog (LOG_ERROR, "Bad login");
else if (iuuconf != UUCONF_SUCCESS)
@@ -1553,7 +1765,8 @@ flogin_prompt (puuconf, qconn)
#if DEBUG > 1
iholddebug = iDebug;
#endif
- (void) faccept_call (puuconf, zuser, qconn, (const char **) NULL);
+ (void) faccept_call (puuconf, zconfig, fuuxqt, zlogin, qconn,
+ (const char **) NULL);
#if DEBUG > 1
iDebug = iholddebug;
#endif
@@ -1564,12 +1777,43 @@ flogin_prompt (puuconf, qconn)
return fret;
}
+/* The comparison function which we pass to uuconf_callin. This
+ expands escape sequences in the login name, and either encrypts or
+ expands escape sequences in the password. */
+
+static int
+icallin_cmp (iwhich, pinfo, zfile)
+ int iwhich;
+ pointer pinfo;
+ const char *zfile;
+{
+ struct scallin_info *qinfo = (struct scallin_info *) pinfo;
+ char *zcopy;
+ int icmp;
+
+#if HAVE_ENCRYPTED_PASSWORDS
+ if (iwhich != 0)
+ return strcmp (crypt (qinfo->zpass, zfile), zfile) == 0;
+#endif
+
+ zcopy = zbufcpy (zfile);
+ (void) cescape (zcopy);
+ if (iwhich == 0)
+ icmp = strcmp (qinfo->zuser, zcopy);
+ else
+ icmp = strcmp (qinfo->zpass, zcopy);
+ ubuffree (zcopy);
+ return icmp == 0;
+}
+
/* Accept a call from a remote system. If pqsys is not NULL, *pqsys
will be set to the system that called in if known. */
static boolean
-faccept_call (puuconf, zlogin, qconn, pzsystem)
+faccept_call (puuconf, zconfig, fuuxqt, zlogin, qconn, pzsystem)
pointer puuconf;
+ const char *zconfig;
+ boolean fuuxqt;
const char *zlogin;
struct sconnection *qconn;
const char **pzsystem;
@@ -1635,6 +1879,9 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ (struct uuconf_port *) NULL,
+ &sport, (char *) NULL);
return FALSE;
}
else
@@ -1669,14 +1916,27 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
}
sDaemon.puuconf = puuconf;
+ sDaemon.zconfig = zconfig;
+ if (! fuuxqt)
+ sDaemon.irunuuxqt = UUCONF_RUNUUXQT_NEVER;
+ else
+ {
+ iuuconf = uuconf_runuuxqt (puuconf, &sDaemon.irunuuxqt);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ }
sDaemon.qsys = NULL;
sDaemon.zlocalname = NULL;
sDaemon.qconn = qconn;
sDaemon.qproto = NULL;
+ sDaemon.cchans = 1;
sDaemon.clocal_size = -1;
sDaemon.cremote_size = -1;
sDaemon.cmax_ever = -2;
sDaemon.cmax_receive = -1;
+ sDaemon.csent = 0;
+ sDaemon.creceived = 0;
+ sDaemon.cxfiles_received = 0;
sDaemon.ifeatures = 0;
sDaemon.frequest_hangup = FALSE;
sDaemon.fhangup_requested = FALSE;
@@ -1695,11 +1955,17 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
sDaemon.zlocalname = zsysdep_localname ();
if (sDaemon.zlocalname == NULL)
- return FALSE;
+ {
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, (char *) NULL);
+ return FALSE;
+ }
}
else
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, (char *) NULL);
return FALSE;
}
@@ -1709,16 +1975,26 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
fret = fsend_uucp_cmd (qconn, zsend);
ubuffree (zsend);
if (! fret)
- return FALSE;
+ {
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
+ return FALSE;
+ }
zstr = zget_uucp_cmd (qconn, TRUE);
if (zstr == NULL)
- return FALSE;
+ {
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
+ return FALSE;
+ }
if (zstr[0] != 'S')
{
ulog (LOG_ERROR, "Bad introduction string");
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
return FALSE;
}
@@ -1740,6 +2016,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
xfree ((pointer) zscript);
(void) fsend_uucp_cmd (qconn, "RYou are unknown to me");
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
return FALSE;
}
xfree ((pointer) zscript);
@@ -1748,6 +2026,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
return FALSE;
}
@@ -1756,6 +2036,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
(void) fsend_uucp_cmd (qconn, "RYou are unknown to me");
ulog (LOG_ERROR, "Call from unknown system %s", zstr + 1);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
return FALSE;
}
}
@@ -1763,6 +2045,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
+ qport, &sport, zloc);
return FALSE;
}
@@ -1791,6 +2075,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
}
@@ -1801,6 +2086,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
ulog (LOG_ERROR, "System %s used wrong login name %s",
zstr + 1, zlogin);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -1834,15 +2120,25 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
ubuffree (zsysdep_spool_commands (qsys, UUCONF_GRADE_HIGH, 0,
(const struct scmd *) NULL));
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return TRUE;
}
/* We only permit one call at a time from a remote system. Lock it. */
if (! fsysdep_lock_system (qsys))
{
+ if (qsys->uuconf_fsequence)
+ {
+ /* At this point the calling system has already incremented
+ its sequence number, so we increment ours. This will
+ only cause a mismatch if the other system is not what it
+ says it is. */
+ (void) ixsysdep_get_sequence (qsys);
+ }
(void) fsend_uucp_cmd (qconn, "RLCK");
ulog (LOG_ERROR, "System already locked");
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
sLocked_system = *qsys;
@@ -1946,6 +2242,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
(void) fsysdep_set_status (qsys, &sstat);
xfree ((pointer) paz);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport,
+ zloc);
return FALSE;
}
fgotseq = TRUE;
@@ -1983,6 +2281,8 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
iwant = (1 << iwant) - 1;
if (qsys->uuconf_zmax_remote_debug != NULL)
iwant &= idebug_parse (qsys->uuconf_zmax_remote_debug);
+ else
+ iwant &= DEBUG_ABNORMAL | DEBUG_CHAT | DEBUG_HANDSHAKE;
if ((iDebug | iwant) != iDebug)
{
iDebug |= iwant;
@@ -2009,6 +2309,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
ulog (LOG_ERROR, "No sequence number (call rejected)");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2047,6 +2348,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
}
@@ -2122,6 +2424,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2131,15 +2434,17 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
- if (zstr[0] != 'U' || zstr[2] != '\0')
+ if (zstr[0] != 'U')
{
ulog (LOG_ERROR, "Bad protocol response string");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2149,6 +2454,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
ubuffree (zstr);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2163,11 +2469,20 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
ulog (LOG_ERROR, "No supported protocol");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
sDaemon.qproto = &asProtocols[i];
+ /* If we are using a half-duplex line, act as though we have only a
+ single channel; otherwise we might start a send and a receive at
+ the same time. */
+ if ((sDaemon.ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
+ sDaemon.cchans = 1;
+ else
+ sDaemon.cchans = asProtocols[i].cchans;
+
/* Run the chat script for when a call is received. */
if (! fchat (qconn, puuconf, &qsys->uuconf_scalled_chat, qsys,
(const struct uuconf_dialer *) NULL, (const char *) NULL,
@@ -2176,6 +2491,7 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
sstat.ttype = STATUS_FAILED;
sstat.ilast = ixsysdep_time ((long *) NULL);
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2202,15 +2518,16 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
if (qdialer == &sdialer)
(void) uuconf_dialer_free (puuconf, &sdialer);
- /* Get any jobs queued for the system, and turn on the selected
- protocol. */
- if (! fqueue (&sDaemon, (boolean *) NULL)
- || ! (*sDaemon.qproto->pfstart) (&sDaemon, &zlog))
+ /* Turn on the selected protocol and get any jobs queued for the
+ system. */
+ if (! (*sDaemon.qproto->pfstart) (&sDaemon, &zlog)
+ || ! fqueue (&sDaemon, (boolean *) NULL))
{
uclear_queue (&sDaemon);
sstat.ttype = STATUS_FAILED;
sstat.ilast = ixsysdep_time ((long *) NULL);
(void) fsysdep_set_status (qsys, &sstat);
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
@@ -2276,8 +2593,12 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
iend_time = ixsysdep_time ((long *) NULL);
- ulog (LOG_NORMAL, "Call complete (%ld seconds)",
- iend_time - istart_time);
+ ulog (LOG_NORMAL, "Call complete (%ld seconds %ld bytes %ld bps)",
+ iend_time - istart_time,
+ sDaemon.csent + sDaemon.creceived,
+ (iend_time != istart_time
+ ? (sDaemon.csent + sDaemon.creceived) / (iend_time - istart_time)
+ : 0));
uclear_queue (&sDaemon);
@@ -2288,14 +2609,38 @@ faccept_call (puuconf, zlogin, qconn, pzsystem)
sstat.ilast = iend_time;
(void) fsysdep_set_status (qsys, &sstat);
- (void) uuconf_system_free (puuconf, &ssys);
- if (qport == &sport)
- (void) uuconf_port_free (puuconf, &sport);
- xfree ((pointer) zloc);
+ if (sDaemon.irunuuxqt == UUCONF_RUNUUXQT_PERCALL
+ || (sDaemon.irunuuxqt > 0 && sDaemon.cxfiles_received > 0))
+ (void) fspawn_uuxqt (TRUE, qsys->uuconf_zname, zconfig);
+
+ uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return fret;
}
}
+
+/* Clean up after faccept_call. */
+
+static void
+uaccept_call_cleanup (puuconf, qfreesys, qport, qfreeport, zloc)
+ pointer puuconf;
+ struct uuconf_system *qfreesys;
+ struct uuconf_port *qport;
+ struct uuconf_port *qfreeport;
+ char *zloc;
+{
+ if (fLocked_system)
+ {
+ (void) fsysdep_unlock_system (&sLocked_system);
+ fLocked_system = FALSE;
+ }
+ if (qfreesys != NULL)
+ (void) uuconf_system_free (puuconf, qfreesys);
+ if (qport == qfreeport)
+ (void) uuconf_port_free (puuconf, qfreeport);
+ xfree ((pointer) zloc);
+ ulog_system ((const char *) NULL);
+}
/* Apply protocol parameters, once we know the protocol. */
@@ -2482,7 +2827,8 @@ zget_uucp_cmd (qconn, frequired)
calc += CINCREMENT;
znew = zbufalc (calc);
- memcpy (znew, zalc, cgot);
+ if (cgot > 0)
+ memcpy (znew, zalc, cgot);
ubuffree (zalc);
zalc = znew;
}
@@ -2518,13 +2864,16 @@ zget_uucp_cmd (qconn, frequired)
return NULL;
}
-/* Read a sequence of characters up to a newline or carriage return, and
- return the line without the line terminating character. */
+/* Read a sequence of characters up to a newline or carriage return,
+ and return the line without the line terminating character.
+ Remember whether the last string we returned ended in \r; if it
+ did, ignore a leading \n to account for \r\n pairs. */
static char *
zget_typed_line (qconn)
struct sconnection *qconn;
{
+ static boolean flastcr;
char *zalc;
size_t calc;
size_t cgot;
@@ -2563,11 +2912,15 @@ zget_typed_line (qconn)
}
#endif
ubuffree (zalc);
+ flastcr = FALSE;
return NULL;
}
if (b == -1)
- continue;
+ {
+ flastcr = FALSE;
+ continue;
+ }
#if DEBUG > 1
if (FDEBUGGING (DEBUG_CHAT))
@@ -2586,19 +2939,34 @@ zget_typed_line (qconn)
}
#endif
+ if (b == '\n' && cgot == 0 && flastcr)
+ {
+ /* Ignore \n in \r\n pair. */
+ flastcr = FALSE;
+ continue;
+ }
+
+ flastcr = FALSE;
+
if (cgot >= calc)
{
char *znew;
calc += CINCREMENT;
znew = zbufalc (calc);
- memcpy (znew, zalc, cgot);
+ if (cgot > 0)
+ memcpy (znew, zalc, cgot);
ubuffree (zalc);
zalc = znew;
}
- if (b == '\r' || b == '\n')
+ if (b == '\n')
b = '\0';
+ else if (b == '\r')
+ {
+ flastcr = TRUE;
+ b = '\0';
+ }
zalc[cgot] = (char) b;
++cgot;
@@ -2616,3 +2984,45 @@ zget_typed_line (qconn)
}
}
}
+
+/* Spawn a uuxqt job. This probably belongs in some other file, but I
+ don't have a good place for it. */
+
+boolean
+fspawn_uuxqt (ffork, zsys, zconfig)
+ boolean ffork;
+ const char *zsys;
+ const char *zconfig;
+{
+ char *zsysarg;
+ char *zconfigarg;
+ boolean fret;
+
+ if (zsys == NULL)
+ zsysarg = NULL;
+ else
+ {
+ zsysarg = zbufalc (sizeof "-s" + strlen (zsys));
+ sprintf (zsysarg, "-s%s", zsys);
+ }
+
+ if (zconfig == NULL)
+ zconfigarg = NULL;
+ else
+ {
+ zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
+ sprintf (zconfigarg, "-I%s", zconfig);
+ if (zsysarg == NULL)
+ {
+ zsysarg = zconfigarg;
+ zconfigarg = NULL;
+ }
+ }
+
+ fret = fsysdep_run (ffork, "uuxqt", zsysarg, zconfigarg);
+
+ ubuffree (zsysarg);
+ ubuffree (zconfigarg);
+
+ return fret;
+}
diff --git a/gnu/libexec/uucp/uucico/xcmd.c b/gnu/libexec/uucp/uucico/xcmd.c
index cadf6383dff9..a3dc8671d052 100644
--- a/gnu/libexec/uucp/uucico/xcmd.c
+++ b/gnu/libexec/uucp/uucico/xcmd.c
@@ -1,7 +1,7 @@
/* xcmd.c
Routines to handle work requests.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char xcmd_rcsid[] = "$Id: xcmd.c,v 1.1 1993/08/05 18:27:25 conklin Exp $";
+const char xcmd_rcsid[] = "$Id: xcmd.c,v 1.2 1994/05/07 18:14:04 ache Exp $";
#endif
#include <errno.h>
@@ -77,6 +77,13 @@ flocal_xcmd_request (qtrans, qdaemon)
ulog (LOG_NORMAL, "Requesting work: %s to %s", qtrans->s.zfrom,
qtrans->s.zto);
+
+ qtrans->fcmd = TRUE;
+ qtrans->precfn = flocal_xcmd_await_reply;
+
+ if (! fqueue_receive (qdaemon, qtrans))
+ return FALSE;
+
/* We send the string
X from to user options
We put a dash in front of options. */
@@ -89,16 +96,11 @@ flocal_xcmd_request (qtrans, qdaemon)
fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
qtrans->iremote);
ubuffree (zsend);
- if (! fret)
- {
- utransfree (qtrans);
- return FALSE;
- }
- qtrans->fcmd = TRUE;
- qtrans->precfn = flocal_xcmd_await_reply;
+ if (! fret)
+ utransfree (qtrans);
- return fqueue_receive (qdaemon, qtrans);
+ return fret;
}
/* Get a reply to an execution request from the remote system. */
@@ -179,7 +181,8 @@ fremote_xcmd_init (qdaemon, qcmd, iremote)
else
zconst = zexclam + 1;
- zdestfile = zsysdep_local_file (zconst, qsys->uuconf_zpubdir);
+ zdestfile = zsysdep_local_file (zconst, qsys->uuconf_zpubdir,
+ (boolean *) NULL);
if (zdestfile == NULL)
return FALSE;
@@ -252,7 +255,8 @@ fremote_xcmd_init (qdaemon, qcmd, iremote)
/* Now we have to process each source file. The source
specification may or may use wildcards. */
- zfrom = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir);
+ zfrom = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir,
+ (boolean *) NULL);
if (zfrom == NULL)
{
ubuffree (zdestfile);
@@ -341,6 +345,7 @@ fremote_xcmd_init (qdaemon, qcmd, iremote)
char *zjobid;
ssend.bcmd = 'S';
+ ssend.bgrade = BDEFAULT_UUCP_GRADE;
ssend.pseq = NULL;
ssend.zfrom = zfile;
ssend.zto = zdestfile;
diff --git a/gnu/libexec/uucp/uuconv/Makefile b/gnu/libexec/uucp/uuconv/Makefile
index 3bac702630d6..ad5ede05357f 100644
--- a/gnu/libexec/uucp/uuconv/Makefile
+++ b/gnu/libexec/uucp/uuconv/Makefile
@@ -1,8 +1,10 @@
# Makefile for uuconv
-# $Id: Makefile,v 1.1 1993/08/05 18:27:28 conklin Exp $
+# $Id: Makefile,v 1.3 1994/05/31 05:46:34 ache Exp $
BINDIR= $(sbindir)
BINOWN= $(owner)
+BINGRP= $(group)
+BINMODE= 550
PROG= uuconv
SRCS= uuconv.c
diff --git a/gnu/libexec/uucp/uuconv/uuconv.c b/gnu/libexec/uucp/uuconv/uuconv.c
index d91a4e6c7a57..6001000295c4 100644
--- a/gnu/libexec/uucp/uuconv/uuconv.c
+++ b/gnu/libexec/uucp/uuconv/uuconv.c
@@ -1,7 +1,7 @@
/* uuconv.c
Convert one type of UUCP configuration file to another.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucnfi.h"
#if USE_RCS_ID
-const char uuconv_rcsid[] = "$Id: uuconv.c,v 1.1 1993/08/05 18:27:29 conklin Exp $";
+const char uuconv_rcsid[] = "$Id: uuconv.c,v 1.2 1994/05/07 18:14:06 ache Exp $";
#endif
#include "getopt.h"
@@ -34,6 +34,7 @@ const char uuconv_rcsid[] = "$Id: uuconv.c,v 1.1 1993/08/05 18:27:29 conklin Exp
/* Local functions. */
static void uvusage P((void));
+static void uvhelp P((void));
static void uvwrite_time P((FILE *e, struct uuconf_timespan *qtime));
static void uvwrite_string P((FILE *e, const char *zarg, const char *zcmd));
static void uvwrite_size P((FILE *e, struct uuconf_timespan *qsize,
@@ -76,6 +77,9 @@ static void uvwrite_taylor_dialer P((FILE *e, struct uuconf_dialer *qdialer,
static void uvwrite_hdb_dialer P((FILE *e, struct uuconf_dialer *qdialer));
static void uvuuconf_error P((pointer puuconf, int iret));
+/* The program name. */
+const char *zProgram;
+
/* A list of Permissions entries built when writing out HDB system
information. */
static struct shpermissions *qVperms;
@@ -89,7 +93,17 @@ enum tconfig
};
/* Long getopt options. */
-static const struct option asVlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asVlongopts[] =
+{
+ { "input", required_argument, NULL, 'i' },
+ { "output", required_argument, NULL, 'o' },
+ { "program", required_argument, NULL, 'p' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -109,7 +123,9 @@ main (argc, argv)
int iret;
pointer pinput;
- while ((iopt = getopt_long (argc, argv, "i:I:o:p:x:", asVlongopts,
+ zProgram = argv[0];
+
+ while ((iopt = getopt_long (argc, argv, "i:I:o:p:vx:", asVlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -138,8 +154,23 @@ main (argc, argv)
/* Set the debugging level. */
break;
+ case 'v':
+ /* Print version and exit. */
+ fprintf
+ (stderr,
+ "%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ uvhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
- /* Long option found and flag set. */
+ /* Long option found, and flag value set. */
break;
default:
@@ -471,6 +502,9 @@ main (argc, argv)
}
exit (EXIT_SUCCESS);
+
+ /* Avoid complaints about not returning. */
+ return 0;
}
/* Print out a usage message and die. */
@@ -478,20 +512,35 @@ main (argc, argv)
static void
uvusage ()
{
+ fprintf (stderr, "Usage: %s -i input-type -o output-type [-p program]\n",
+ zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+uvhelp ()
+{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ "Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
+ fprintf (stderr, "Converts UUCP configuration files from one format to another.\n");
fprintf (stderr,
- "Usage: uuconv -i input -o output [-p program] [-I file]\n");
+ "Usage: %s -i input -o output [-p program] [-I file]\n", zProgram);
fprintf (stderr,
- " -i input: Set input type (one of taylor, v2, hdb)\n");
+ " -i,--input input: Set input type (one of taylor, v2, hdb)\n");
fprintf (stderr,
- " -o output: Set output type (one of taylor, v2, hdb)\n");
+ " -o,--output output: Set output type (one of taylor, v2, hdb)\n");
fprintf (stderr,
- " -p program: Program to convert (e.g., uucp or cu)\n");
+ " -p,--program program: Program to convert (e.g., uucp or cu)\n");
fprintf (stderr,
- " -I file: Set Taylor UUCP configuration file to use\n");
- exit (EXIT_FAILURE);
+ " -I,--config file: Set Taylor UUCP configuration file to use\n");
+ fprintf (stderr,
+ " -v,--version: Print version and exit\n");
+ fprintf (stderr,
+ " --help: Print help and exit\n");
}
/* Write out a timespan. */
@@ -1229,18 +1278,17 @@ uvwrite_hdb_system (e, qsys)
/* Compare two strings from a Permissions entry, returning TRUE if
they are the same. */
+
static boolean
fvperm_string_cmp (z1, z2)
const char *z1;
const char *z2;
{
- if (z1 == NULL
- ? z2 != NULL
- : z2 == NULL)
- return FALSE;
-
if (z1 == NULL)
- return TRUE;
+ return z2 == NULL;
+
+ if (z2 == NULL)
+ return FALSE;
return strcmp (z1, z2) == 0;
}
@@ -1253,13 +1301,11 @@ fvperm_array_cmp (pz1, pz2)
const char **pz1;
const char **pz2;
{
- if (pz1 == NULL
- ? pz2 != NULL
- : pz2 == NULL)
- return FALSE;
-
if (pz1 == NULL)
- return TRUE;
+ return pz2 == NULL;
+
+ if (pz2 == NULL)
+ return FALSE;
for (; *pz1 != NULL && *pz2 != NULL; pz1++, pz2++)
if (strcmp (*pz1, *pz2) != 0)
@@ -1629,6 +1675,9 @@ uvwrite_taylor_port (e, qport, zprefix)
case UUCONF_PORTTYPE_TLI:
ztype = "tli";
break;
+ case UUCONF_PORTTYPE_PIPE:
+ ztype = "pipe";
+ break;
}
fprintf (e, "%stype %s\n", zprefix, ztype);
@@ -1681,6 +1730,8 @@ uvwrite_taylor_port (e, qport, zprefix)
qm->uuconf_ihighbaud);
if (! qm->uuconf_fcarrier)
fprintf (e, "%scarrier false\n", zprefix);
+ if (! qm->uuconf_fhardflow)
+ fprintf (e, "%shardflow false\n", zprefix);
if (qm->uuconf_pzdialer != NULL)
{
if (qm->uuconf_pzdialer[1] == NULL)
@@ -1707,12 +1758,23 @@ uvwrite_taylor_port (e, qport, zprefix)
fprintf (e, "%sdevice %s\n", zprefix, qd->uuconf_zdevice);
if (qd->uuconf_ibaud != 0)
fprintf (e, "%sbaud %ld\n", zprefix, qd->uuconf_ibaud);
+ if (qd->uuconf_fcarrier)
+ fprintf (e, "%scarrier true\n", zprefix);
+ if (! qd->uuconf_fhardflow)
+ fprintf (e, "%shardflow false\n", zprefix);
}
break;
case UUCONF_PORTTYPE_TCP:
if (qport->uuconf_u.uuconf_stcp.uuconf_zport != NULL)
fprintf (e, "%sservice %s\n", zprefix,
qport->uuconf_u.uuconf_stcp.uuconf_zport);
+ if (qport->uuconf_u.uuconf_stcp.uuconf_pzdialer != NULL)
+ {
+ sprintf (ab, "%sdialer-sequence", zprefix);
+ uvwrite_string_array (e,
+ qport->uuconf_u.uuconf_stcp.uuconf_pzdialer,
+ ab);
+ }
break;
case UUCONF_PORTTYPE_TLI:
{
@@ -1738,6 +1800,18 @@ uvwrite_taylor_port (e, qport, zprefix)
qt->uuconf_zservaddr);
}
break;
+ case UUCONF_PORTTYPE_PIPE:
+ {
+ struct uuconf_pipe_port *qp;
+
+ qp = &qport->uuconf_u.uuconf_spipe;
+ if (qp->uuconf_pzcmd != NULL)
+ {
+ sprintf (ab, "%scommad", zprefix);
+ uvwrite_string_array (e, qp->uuconf_pzcmd, ab);
+ }
+ }
+ break;
}
}
@@ -1849,6 +1923,8 @@ ivwrite_hdb_port (qport, pinfo)
}
else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP)
{
+ char **pz;
+
fprintf (e, "TCP");
if (qport->uuconf_zprotocols != NULL)
fprintf (e, ",%s", qport->uuconf_zprotocols);
@@ -1858,6 +1934,10 @@ ivwrite_hdb_port (qport, pinfo)
else
fprintf (e, "%s", qport->uuconf_u.uuconf_stcp.uuconf_zport);
fprintf (e, " - -");
+ pz = qport->uuconf_u.uuconf_stcp.uuconf_pzdialer;
+ if (pz != NULL)
+ for (; *pz != NULL; pz++)
+ fprintf (e, " %s", *pz);
}
else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI)
{
diff --git a/gnu/libexec/uucp/uucp/Makefile b/gnu/libexec/uucp/uucp/Makefile
index 26f2450a48bb..b6af00ea421a 100644
--- a/gnu/libexec/uucp/uucp/Makefile
+++ b/gnu/libexec/uucp/uucp/Makefile
@@ -1,9 +1,9 @@
# Makefile for uucp
-# $Id: Makefile,v 1.1 1993/08/05 18:27:34 conklin Exp $
+# $Id: Makefile,v 1.3 1994/05/31 07:37:14 ache Exp $
BINDIR= $(bindir)
BINOWN= $(owner)
-BINMODE= 4555
+BINMODE= 4555
PROG= uucp
SRCS= uucp.c util.c log.c copy.c
diff --git a/gnu/libexec/uucp/uucp/uucp.1 b/gnu/libexec/uucp/uucp/uucp.1
index dec039160de0..36d748b92962 100644
--- a/gnu/libexec/uucp/uucp/uucp.1
+++ b/gnu/libexec/uucp/uucp/uucp.1
@@ -1,5 +1,5 @@
-''' $Id: uucp.1,v 1.1 1993/08/05 18:27:35 conklin Exp $
-.TH uucp 1 "Taylor UUCP 1.04"
+''' $Id: uucp.1,v 1.2 1994/05/07 18:14:08 ache Exp $
+.TH uucp 1 "Taylor UUCP 1.05"
.SH NAME
uucp \- Unix to Unix copy
.SH SYNOPSIS
@@ -34,6 +34,8 @@ system1!system2!path.
Any pathname that does not begin with / or ~ will be appended to the
current directory (unless the
.B \-W
+or
+.B \--noexpand
option is used); this resulting path will not necessarily exist on a
remote system. A pathname beginning with a simple ~ starts at the
UUCP public directory; a pathname beginning with ~name starts at the
@@ -51,13 +53,15 @@ The copy does not take place immediately, but is queued up for the
.I uucico
(8) daemon; the daemon is started immediately unless the
.B \-r
+or
+.B \-\-nouucico
switch is given. In any case, the next time the remote system is called the
file(s) will be copied.
.SH OPTIONS
The following options may be given to
.I uucp.
.TP 5
-.B \-c
+.B \-c, \-\-nocopy
Do not copy local source files to the spool directory. If they are
removed before being processed by the
.I uucico
@@ -65,40 +69,40 @@ removed before being processed by the
.I uucico
(8) daemon, and by the invoking user.
.TP 5
-.B \-C
+.B \-C, \-\-copy
Copy local source files to the spool directory. This is the default.
.TP 5
-.B \-d
+.B \-d, \-\-directories
Create all necessary directories when doing the copy. This is the
default.
.TP 5
-.B \-f
+.B \-f, \-\-nodirectories
If any necessary directories do not exist for the destination path,
abort the copy.
.TP 5
-.B \-g grade
+.B \-g grade, \-\-grade grade
Set the grade of the file transfer command. Jobs of a higher grade
are executed first. Grades run 0 ... 9 A ... Z a ... z from high to
low.
.TP 5
-.B \-m
+.B \-m, \-\-mail
Report completion or failure of the file transfer by
.I mail
(1).
.TP 5
-.B \-n user
+.B \-n user, \-\-notify user
Report completion or failure of the file transfer by
.I mail
(1) to the named
user on the remote system.
.TP 5
-.B \-r
+.B \-r, \-\-nouucico
Do not start
.I uucico
(8) daemon immediately; merely queue up the file transfer for later
execution.
.TP 5
-.B \-j
+.B \-j, \-\-jobid
Print jobid on standard output. The job may be
later cancelled by passing the jobid to the
.B \-k
@@ -108,18 +112,21 @@ switch of
It is possible for some complex operations to produce more than one
jobid, in which case each will be printed on a separate line. For
example
-.EX
-uucp sys1!~user1/file1 sys2!~user2/file2 /usr/spool/uucppublic
-.EE
+.br
+.in +0.5i
+.nf
+uucp sys1!~user1/file1 sys2!~user2/file2 ~user3
+.fi
+.in -0.5i
will generate two separate jobs, one for the system
.I sys1
and one for the system
.I sys2.
.TP 5
-.B \-W
+.B \-W, \-\-noexpand
Do not prepend remote relative path names with the current directory.
.TP 5
-.B \-x type
+.B \-x type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing. Only abnormal, config,
@@ -127,18 +134,24 @@ spooldir and execute are meaningful for
.I uucp.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
+.B \-\-debug abnormal,chat.
.TP 5
-.B \-I file
+.B \-I file, \-\-config file
Set configuration file to use. This option may not be available,
depending upon how
.I uucp
was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
.SH FILES
The file names may be changed at compilation time or by the
configuration file, so these are only approximations.
@@ -172,4 +185,4 @@ File modes are not preserved, except for the execute bit. The
resulting file is owned by the uucp user.
.SH AUTHOR
Ian Lance Taylor
-(ian@airs.com or uunet!airs!ian)
+<ian@airs.com>
diff --git a/gnu/libexec/uucp/uucp/uucp.c b/gnu/libexec/uucp/uucp/uucp.c
index 931c84e7b338..53681071dba9 100644
--- a/gnu/libexec/uucp/uucp/uucp.c
+++ b/gnu/libexec/uucp/uucp/uucp.c
@@ -1,7 +1,7 @@
/* uucp.c
Prepare to copy a file to or from a remote system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uucp_rcsid[] = "$Id: uucp.c,v 1.1 1993/08/05 18:27:36 conklin Exp $";
+const char uucp_rcsid[] = "$Id: uucp.c,v 1.2 1994/05/07 18:14:10 ache Exp $";
#endif
#include <ctype.h>
@@ -41,6 +41,7 @@ const char uucp_rcsid[] = "$Id: uucp.c,v 1.1 1993/08/05 18:27:36 conklin Exp $";
/* Local functions. */
static void ucusage P((void));
+static void uchelp P((void));
static void ucdirfile P((const char *zdir, const char *zfile,
pointer pinfo));
static void uccopy P((const char *zfile, const char *zdest));
@@ -51,11 +52,29 @@ static const char *zcone_system P((boolean *pfany));
static void ucrecord_file P((const char *zfile));
static void ucabort P((void));
-/* The program name. */
-char abProgram[] = "uucp";
-
/* Long getopt options. */
-static const struct option asClongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asClongopts[] =
+{
+ { "copy", no_argument, NULL, 'C' },
+ { "nocopy", no_argument, NULL, 'c' },
+ { "directories", no_argument, NULL, 'd' },
+ { "nodirectories", no_argument, NULL, 'f' },
+ { "grade", required_argument, NULL, 'g' },
+ { "jobid", no_argument, NULL, 'j' },
+ { "mail", no_argument, NULL, 'm' },
+ { "notify", required_argument, NULL, 'n' },
+ { "nouucico", no_argument, NULL, 'r' },
+ { "recursive", no_argument, NULL, 'R' },
+ { "status", required_argument, NULL, 's' },
+ { "uuto", no_argument, NULL, 't' },
+ { "user", required_argument, NULL, 'u' },
+ { "noexpand", no_argument, NULL, 'w' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
/* Local variables. There are a bunch of these, mostly set by the
options and the last (the destination) argument. These have file
@@ -137,13 +156,16 @@ main (argc, argv)
int iuuconf;
int i;
boolean fgetcwd;
+ struct uuconf_system slocalsys;
char *zexclam;
char *zdestfile;
const char *zdestsys;
char *zoptions;
boolean fexit;
- while ((iopt = getopt_long (argc, argv, "cCdfg:I:jmn:prRs:tu:Wx:",
+ zProgram = argv[0];
+
+ while ((iopt = getopt_long (argc, argv, "cCdfg:I:jmn:prRs:tu:Wvx:",
asClongopts, (int *) NULL)) != EOF)
{
switch (iopt)
@@ -232,13 +254,26 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ uchelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
ucusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -335,6 +370,18 @@ main (argc, argv)
else if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ /* Get the local system information. */
+ iuuconf = uuconf_system_info (puuconf, zClocalname, &slocalsys);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ iuuconf = uuconf_system_local (puuconf, &slocalsys);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ slocalsys.uuconf_zname = (char *) zClocalname;
+ }
+
/* If we are emulating uuto, translate the destination argument, and
notify the destination user. This had better not turn into
something that requires the current directory, or we may have
@@ -378,6 +425,8 @@ main (argc, argv)
*zoptions++ = 'm';
*zoptions = '\0';
+ argv[argc - 1] = zremove_local_sys (&slocalsys, argv[argc - 1]);
+
zexclam = strchr (argv[argc - 1], '!');
if (zexclam == NULL)
{
@@ -445,7 +494,8 @@ main (argc, argv)
/* Turn the destination into an absolute path, unless it is on a
remote system and -W was used. */
if (fClocaldest)
- zdestfile = zsysdep_local_file_cwd (zdestfile, sCdestsys.uuconf_zpubdir);
+ zdestfile = zsysdep_local_file_cwd (zdestfile, sCdestsys.uuconf_zpubdir,
+ (boolean *) NULL);
else if (fCexpand)
zdestfile = zsysdep_add_cwd (zdestfile);
if (zdestfile == NULL)
@@ -462,6 +512,8 @@ main (argc, argv)
fCneeds_cwd = FALSE;
+ argv[i] = zremove_local_sys (&slocalsys, argv[i]);
+
if (strchr (argv[i], '!') != NULL)
{
flocal = FALSE;
@@ -476,7 +528,8 @@ main (argc, argv)
if (fsysdep_needs_cwd (argv[i]))
fCneeds_cwd = TRUE;
zfrom = zsysdep_local_file_cwd (argv[i],
- sCdestsys.uuconf_zpubdir);
+ sCdestsys.uuconf_zpubdir,
+ (boolean *) NULL);
if (zfrom == NULL)
ucabort ();
}
@@ -524,12 +577,35 @@ main (argc, argv)
boolean fany;
zsys = zcone_system (&fany);
- if (zsys != NULL)
- fexit = fsysdep_run ("uucico", "-s", zsys);
- else if (fany)
- fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL);
- else
+
+ if (zsys == NULL && ! fany)
fexit = TRUE;
+ else
+ {
+ const char *zarg;
+ char *zconfigarg;
+
+ if (zsys == NULL)
+ zarg = "-r1";
+ else
+ {
+ char *z;
+
+ z = zbufalc (sizeof "-Cs" + strlen (zsys));
+ sprintf (z, "-Cs%s", zsys);
+ zarg = z;
+ }
+
+ if (zconfig == NULL)
+ zconfigarg = NULL;
+ else
+ {
+ zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
+ sprintf (zconfigarg, "-I%s", zconfig);
+ }
+
+ fexit = fsysdep_run (FALSE, "uucico", zarg, zconfigarg);
+ }
}
usysdep_exit (fexit);
@@ -538,49 +614,45 @@ main (argc, argv)
return 0;
}
+/* Print usage message and die. */
+
static void
ucusage ()
{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ "Usage: %s [options] file1 [file2 ...] dest\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print help message. */
+
+static void
+uchelp ()
+{
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
- fprintf (stderr,
- "Usage: uucp [options] file1 [file2 ...] dest\n");
- fprintf (stderr,
- " -c: Do not copy local files to spool directory\n");
- fprintf (stderr,
- " -C, -p: Copy local files to spool directory (default)\n");
- fprintf (stderr,
- " -d: Create necessary directories (default)\n");
- fprintf (stderr,
- " -f: Do not create directories (fail if they do not exist)\n");
- fprintf (stderr,
- " -g grade: Set job grade (must be alphabetic)\n");
- fprintf (stderr,
- " -m: Report status of copy by mail\n");
- fprintf (stderr,
- " -n user: Report status of copy by mail to remote user\n");
- fprintf (stderr,
- " -R: Copy directories recursively\n");
- fprintf (stderr,
- " -r: Do not start uucico daemon\n");
- fprintf (stderr,
- " -s file: Report completion status to file\n");
- fprintf (stderr,
- " -j: Report job id\n");
- fprintf (stderr,
- " -W: Do not add current directory to remote filenames\n");
- fprintf (stderr,
- " -t: Emulate uuto\n");
- fprintf (stderr,
- " -u name: Set user name\n");
- fprintf (stderr,
- " -x debug: Set debugging level\n");
+ printf ("Usage: %s [options] file1 [file2 ...] dest\n", zProgram);
+ printf (" -c,--nocopy: Do not copy local files to spool directory\n");
+ printf (" -C,-p,--copy: Copy local files to spool directory (default)\n");
+ printf (" -d,--directories: Create necessary directories (default)\n");
+ printf (" -f,--nodirectories: Do not create directories (fail if they do not exist)\n");
+ printf (" -g,--grade grade: Set job grade (must be alphabetic)\n");
+ printf (" -m,--mail: Report status of copy by mail\n");
+ printf (" -n,--notify user: Report status of copy by mail to remote user\n");
+ printf (" -R,--recursive: Copy directories recursively\n");
+ printf (" -r,--nouucico: Do not start uucico daemon\n");
+ printf (" -s,--status file: Report completion status to file\n");
+ printf (" -j,--jobid: Report job id\n");
+ printf (" -W,--noexpand: Do not add current directory to remote filenames\n");
+ printf (" -t,--uuto: Emulate uuto\n");
+ printf (" -u,--usage name: Set user name\n");
+ printf (" -x,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
- exit (EXIT_FAILURE);
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
}
/* This is called for each file in a directory heirarchy. */
@@ -713,7 +785,9 @@ uccopy (zfile, zdest)
(fCremote
? (const char *) NULL
: zCuser)))
- ulog (LOG_FATAL, "Not permitted to send %s", zfile);
+ ulog (LOG_FATAL,
+ "Daemon not permitted to send %s (suggest --copy)",
+ zfile);
}
else
{
@@ -730,6 +804,7 @@ uccopy (zfile, zdest)
{
/* We're not forwarding. Just send the file. */
s.bcmd = 'S';
+ s.bgrade = bCgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (zfile);
s.zto = zbufcpy (zdest);
@@ -794,6 +869,7 @@ uccopy (zfile, zdest)
/* Send the execution file. */
s.bcmd = 'S';
+ s.bgrade = bCgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (abxtname);
s.zto = zbufcpy (abxname);
@@ -815,6 +891,7 @@ uccopy (zfile, zdest)
/* Send the data file. */
s.bcmd = 'S';
+ s.bgrade = bCgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (zfile);
s.zto = zbufcpy (abdname);
@@ -851,6 +928,7 @@ uccopy (zfile, zdest)
clen = zfrom - zexclam - 1;
zforward = zbufalc (clen + 1);
memcpy (zforward, zexclam + 1, clen);
+ zforward[clen] = '\0';
}
++zfrom;
@@ -925,6 +1003,7 @@ uccopy (zfile, zdest)
zto = zbufcpy (zdest);
}
+ s.bgrade = bCgrade;
s.pseq = NULL;
s.zfrom = zfrom;
s.zto = zto;
@@ -999,6 +1078,7 @@ uccopy (zfile, zdest)
/* Send the execution file. */
s.bcmd = 'S';
+ s.bgrade = bCgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (abtname);
s.zto = zbufcpy (abxname);
diff --git a/gnu/libexec/uucp/uulog/uulog.c b/gnu/libexec/uucp/uulog/uulog.c
index 8756e523bbba..73862a05cb73 100644
--- a/gnu/libexec/uucp/uulog/uulog.c
+++ b/gnu/libexec/uucp/uulog/uulog.c
@@ -1,7 +1,7 @@
/* uulog.c
Display the UUCP log file.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uulog_rcsid[] = "$Id: uulog.c,v 1.1 1993/08/05 18:27:40 conklin Exp $";
+const char uulog_rcsid[] = "$Id: uulog.c,v 1.2 1994/05/07 18:14:12 ache Exp $";
#endif
#include <ctype.h>
@@ -42,15 +42,27 @@ const char uulog_rcsid[] = "$Id: uulog.c,v 1.1 1993/08/05 18:27:40 conklin Exp $
is a very useful program anyhow. It only takes a single -s and/or
-u switch. When using HAVE_HDB_LOGGING it requires a system. */
-/* The program name. */
-char abProgram[] = "uulog";
-
/* Local functions. */
static void ulusage P((void));
+static void ulhelp P((void));
/* Long getopt options. */
-static const struct option asLlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asLlongopts[] =
+{
+ { "debuglog", no_argument, NULL, 'D' },
+ { "follow", optional_argument, NULL, 2 },
+ { "lines", required_argument, NULL, 'n' },
+ { "system", required_argument, NULL, 's' },
+ { "statslog", no_argument, NULL, 'S' },
+ { "user", required_argument, NULL, 'u' },
+ { "uuxqtlog", no_argument, NULL, 'x' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'X' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -89,6 +101,8 @@ main (argc, argv)
char *zline;
size_t cline;
+ zProgram = argv[0];
+
/* Look for a straight number argument, and convert it to -n before
passing the arguments to getopt. */
for (i = 0; i < argc; i++)
@@ -107,7 +121,7 @@ main (argc, argv)
}
}
- while ((iopt = getopt_long (argc, argv, "Df:FI:n:s:Su:xX:", asLlongopts,
+ while ((iopt = getopt_long (argc, argv, "Df:FI:n:s:Su:vxX:", asLlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -170,13 +184,35 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 2:
+ /* --follow. */
+ fforever = TRUE;
+ if (cshow == 0)
+ cshow = 10;
+ if (optarg != NULL)
+ zsystem = optarg;
+ break;
+
+ case 1:
+ /* --help. */
+ ulhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
ulusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -211,7 +247,7 @@ main (argc, argv)
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- usysdep_initialize (puuconf, 0);
+ usysdep_initialize (puuconf, INIT_NOCHDIR);
if (zsystem != NULL)
{
@@ -221,15 +257,16 @@ main (argc, argv)
{
struct uuconf_system ssys;
+ /* Canonicalize the system name. If we can't find the
+ system information, just use whatever we were given so
+ that people can check on systems that logged in
+ anonymously. */
iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
- if (iuuconf != UUCONF_SUCCESS)
+ if (iuuconf == UUCONF_SUCCESS)
{
- if (iuuconf != UUCONF_NOT_FOUND)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- ulog (LOG_FATAL, "%s: System not found", zsystem);
+ zsystem = zbufcpy (ssys.uuconf_zname);
+ (void) uuconf_system_free (puuconf, &ssys);
}
- zsystem = zbufcpy (ssys.uuconf_zname);
- (void) uuconf_system_free (puuconf, &ssys);
}
}
@@ -247,7 +284,8 @@ main (argc, argv)
/* We need a system to find a HDB log file. */
if (zsystem == NULL)
- ulusage ();
+ ulog (LOG_FATAL,
+ "system name (-s argument) required for HDB format log files");
if (fuuxqt)
zprogram = "uuxqt";
@@ -261,6 +299,9 @@ main (argc, argv)
sprintf (zalc, zlogfile, zprogram, zsystem);
zfile = zalc;
+ if (! fsysdep_file_exists (zfile))
+ ulog (LOG_FATAL, "no log file available for system %s", zsystem);
+
if (strcmp (zsystem, "ANY") == 0)
zsystem = NULL;
#endif
@@ -344,7 +385,7 @@ main (argc, argv)
zlsys = znext;
clsys = strcspn (znext, "!");
znext += clsys + 1;
- zlsys = znext;
+ zluser = znext;
clsys = strcspn (znext, " \t");
#endif
}
@@ -411,34 +452,41 @@ static void
ulusage ()
{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ "Usage: %s [-n #] [-sf system] [-u user] [-xDSF] [-I file] [-X debug]\n",
+ zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+ulhelp ()
+{
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
- fprintf (stderr,
- "Usage: uulog [-n #] [-sf system] [-u user] [-xDSF] [-I file] [-X debug]\n");
- fprintf (stderr,
- " -n: show given number of lines from end of log\n");
- fprintf (stderr,
- " -s: print entries for named system\n");
- fprintf (stderr,
- " -f: follow entries for named system\n");
- fprintf (stderr,
- " -u: print entries for named user\n");
#if HAVE_HDB_LOGGING
- fprintf (stderr,
- " -x: print uuxqt log rather than uucico log\n");
+ printf ("Usage: %s [-n #] [-sf system] [-u user] [-xDS] [-I file] [-X debug]\n",
+ zProgram);
#else
- fprintf (stderr,
- " -F: follow entries for any system\n");
+ printf ("Usage: %s [-n #] [-sf system] [-u user] [-DSF] [-I file] [-X debug]\n",
+ zProgram);
#endif
- fprintf (stderr,
- " -S: show statistics file\n");
- fprintf (stderr,
- " -D: show debugging file\n");
- fprintf (stderr,
- " -X debug: Set debugging level (0 for none, 9 is max)\n");
+ printf (" -n,--lines: show given number of lines from end of log\n");
+ printf (" -s,--system: print entries for named system\n");
+ printf (" -f system,--follow=system: follow entries for named system\n");
+ printf (" -u,--user user: print entries for named user\n");
+#if HAVE_HDB_LOGGING
+ printf (" -x,--uuxqt: print uuxqt log rather than uucico log\n");
+#else
+ printf (" -F,--follow: follow entries for any system\n");
+#endif
+ printf (" -S,--statslog: show statistics file\n");
+ printf (" -D,--debuglog: show debugging file\n");
+ printf (" -X,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
- exit (EXIT_FAILURE);
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
}
diff --git a/gnu/libexec/uucp/uuname/uuname.c b/gnu/libexec/uucp/uuname/uuname.c
index 27e34fa0386e..489170e7512e 100644
--- a/gnu/libexec/uucp/uuname/uuname.c
+++ b/gnu/libexec/uucp/uuname/uuname.c
@@ -1,7 +1,7 @@
/* uuname.c
List the names of known remote UUCP sites.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uuname_rcsid[] = "$Id: uuname.c,v 1.1 1993/08/05 18:27:43 conklin Exp $";
+const char uuname_rcsid[] = "$Id: uuname.c,v 1.2 1994/05/07 18:14:13 ache Exp $";
#endif
#include "getopt.h"
@@ -35,16 +35,22 @@ const char uuname_rcsid[] = "$Id: uuname.c,v 1.1 1993/08/05 18:27:43 conklin Exp
#include "uuconf.h"
#include "system.h"
-/* The program name. */
-char abProgram[] = "uuname";
-
/* Local functions. */
static void unusage P((void));
-static void unuuconf_error P((pointer puuconf, int iuuconf));
+static void unhelp P((void));
/* Long getopt options. */
-static const struct option asNlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asNlongopts[] =
+{
+ { "aliases", no_argument, NULL, 'a' },
+ { "local", no_argument, NULL, 'l' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -61,7 +67,9 @@ main (argc, argv)
pointer puuconf;
int iuuconf;
- while ((iopt = getopt_long (argc, argv, "alI:x:", asNlongopts,
+ zProgram = argv[0];
+
+ while ((iopt = getopt_long (argc, argv, "alI:vx:", asNlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -89,13 +97,26 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ unhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
unusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -104,7 +125,7 @@ main (argc, argv)
iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
if (iuuconf != UUCONF_SUCCESS)
- unuuconf_error (puuconf, iuuconf);
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
#if DEBUG > 1
{
@@ -118,7 +139,7 @@ main (argc, argv)
}
#endif
- usysdep_initialize (puuconf, INIT_SUID);
+ usysdep_initialize (puuconf, INIT_SUID | INIT_NOCHDIR);
if (flocal)
{
@@ -132,7 +153,7 @@ main (argc, argv)
usysdep_exit (FALSE);
}
else if (iuuconf != UUCONF_SUCCESS)
- unuuconf_error (puuconf, iuuconf);
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
printf ("%s\n", zlocalname);
}
else
@@ -141,7 +162,7 @@ main (argc, argv)
iuuconf = uuconf_system_names (puuconf, &pznames, falias);
if (iuuconf != UUCONF_SUCCESS)
- unuuconf_error (puuconf, iuuconf);
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
for (pz = pznames; *pz != NULL; pz++)
printf ("%s\n", *pz);
@@ -159,34 +180,23 @@ static void
unusage ()
{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
- VERSION);
- fprintf (stderr,
- "Usage: uuname [-a] [-l] [-I file]\n");
- fprintf (stderr,
- " -a: display aliases\n");
- fprintf (stderr,
- " -l: print local name\n");
-#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
-#endif /* HAVE_TAYLOR_CONFIG */
+ "Usage: %s [-a] [-l] [-I file]\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
exit (EXIT_FAILURE);
}
-/* Display a uuconf error and exit. */
+/* Print a help message. */
-static void
-unuuconf_error (puuconf, iret)
- pointer puuconf;
- int iret;
+static void unhelp ()
{
- char ab[512];
-
- (void) uuconf_error_string (puuconf, iret, ab, sizeof ab);
- if ((iret & UUCONF_ERROR_FILENAME) == 0)
- fprintf (stderr, "uuname: %s\n", ab);
- else
- fprintf (stderr, "uuname:%s\n", ab);
- exit (EXIT_FAILURE);
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ VERSION);
+ printf ("Usage: %s [-a] [-l] [-I file]\n", zProgram);
+ printf (" -a,--aliases: display aliases\n");
+ printf (" -l,--local: print local name\n");
+#if HAVE_TAYLOR_CONFIG
+ printf (" -I,--config file: Set configuration file to use\n");
+#endif /* HAVE_TAYLOR_CONFIG */
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
}
diff --git a/gnu/libexec/uucp/uupick/uupick.c b/gnu/libexec/uucp/uupick/uupick.c
index a28c265abed1..d31e63780e1b 100644
--- a/gnu/libexec/uucp/uupick/uupick.c
+++ b/gnu/libexec/uucp/uupick/uupick.c
@@ -1,7 +1,7 @@
/* uupick.c
Get files stored in the public directory by uucp -t.
- Copyright (C) 1992 Ian Lance Taylor
+ Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uupick_rcsid[] = "$Id: uupick.c,v 1.1 1993/08/05 18:27:50 conklin Exp $";
+const char uupick_rcsid[] = "$Id: uupick.c,v 1.2 1994/05/07 18:14:15 ache Exp $";
#endif
#include <errno.h>
@@ -43,15 +43,21 @@ static void upmovedir P((const char *zfull, const char *zrelative,
pointer pinfo));
static void upmove P((const char *zfrom, const char *zto));
-/* The program name. */
-char abProgram[] = "uupick";
-
/* Long getopt options. */
-static const struct option asPlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asPlongopts[] =
+{
+ { "system", required_argument, NULL, 's' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
/* Local functions. */
static void upusage P((void));
+static void uphelp P((void));
int
main (argc, argv)
@@ -72,7 +78,9 @@ main (argc, argv)
char ab[1000];
boolean fquit;
- while ((iopt = getopt_long (argc, argv, "I:s:x:", asPlongopts,
+ zProgram = "uupick";
+
+ while ((iopt = getopt_long (argc, argv, "I:s:vx:", asPlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -95,13 +103,28 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ fprintf
+ (stderr,
+ "%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ uphelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
upusage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -152,6 +175,8 @@ main (argc, argv)
do
{
+ boolean fbadname;
+
fcontinue = FALSE;
if (zallsys == NULL
@@ -196,9 +221,15 @@ main (argc, argv)
case 'a':
zto = ab + 1 + strspn (ab + 1, " \t");
zto[strcspn (zto, " \t\n")] = '\0';
- zlocal = zsysdep_uupick_local_file (zto);
+ zlocal = zsysdep_uupick_local_file (zto, &fbadname);
if (zlocal == NULL)
- usysdep_exit (FALSE);
+ {
+ if (! fbadname)
+ usysdep_exit (FALSE);
+ ulog (LOG_ERROR, "%s: bad local file name", zto);
+ fcontinue = TRUE;
+ break;
+ }
zto = zsysdep_in_dir (zlocal, zfile);
ubuffree (zlocal);
if (zto == NULL)
@@ -271,25 +302,37 @@ main (argc, argv)
return 0;
}
-/* Print usage message. */
+/* Print usage message and die. */
static void
upusage ()
{
fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
- VERSION);
+ "Usage: %s [-s system] [-I config] [-x debug]\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print help message. */
+
+static void
+uphelp ()
+{
fprintf (stderr,
- "Usage: uupick [-s system] [-I config] [-x debug]\n");
+ "Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ VERSION);
fprintf (stderr,
- " -s system: Only consider files from named system\n");
+ " -s,--system system: Only consider files from named system\n");
fprintf (stderr,
- " -x debug: Set debugging level\n");
+ " -x,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ " -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
- exit (EXIT_FAILURE);
+ fprintf (stderr,
+ " -v,--version: Print version and exit\n");
+ fprintf (stderr,
+ " --help: Print help and exit\n");
}
/* This routine is called by usysdep_walk_tree when moving the
diff --git a/gnu/libexec/uucp/uusched/uusched.in b/gnu/libexec/uucp/uusched/uusched.in
index e539b902fbab..5acb86a5c484 100644
--- a/gnu/libexec/uucp/uusched/uusched.in
+++ b/gnu/libexec/uucp/uusched/uusched.in
@@ -1,8 +1,8 @@
-:
+#!/bin/sh
# uusched
# Call all systems which have work in a random order
#
-# Copyright (C) 1992 Ian Lance Taylor
+# Copyright (C) 1992, 1993 Ian Lance Taylor
#
# Please feel free do whatever you like with this exciting shell
# script.
@@ -10,4 +10,4 @@
# This is pretty trivial, since all the functionality was moved into
# uucico itself.
#
-@SBINDIR@/uucico -r1 $*
+exec @SBINDIR@/uucico -r1 $*
diff --git a/gnu/libexec/uucp/uustat/uustat.1 b/gnu/libexec/uucp/uustat/uustat.1
index 5d0ed2a08bbc..39b434c00f0e 100644
--- a/gnu/libexec/uucp/uustat/uustat.1
+++ b/gnu/libexec/uucp/uustat/uustat.1
@@ -1,38 +1,102 @@
-''' $Id: uustat.1,v 1.1 1993/08/05 18:28:04 conklin Exp $
-.TH uustat 1 "Taylor UUCP 1.04"
+''' $Id: uustat.1,v 1.2 1994/05/07 18:14:22 ache Exp $
+.TH uustat 1 "Taylor UUCP 1.05"
.SH NAME
uustat \- UUCP status inquiry and control
.SH SYNOPSIS
.B uustat \-a
.PP
+.B uustat \-\-all
+.PP
.B uustat
[
-.B \-eKiMNQ ] [
+.B \-eKRiMNQ ] [
.B \-sS
system ] [
.B \-uU
user ] [
.B \-cC
command ] [
-.B \-o
-hours ] [
-.B \-y
+.B \-oy
hours ] [
.B \-B
+lines ] [
+.B \-\-executions
+] [
+.B \-\-kill-all
+] [
+.B \-\-rejuvenate-all
+] [
+.B \-\-prompt
+] [
+.B \-\-mail
+] [
+.B \-\-notify
+] [
+.B \-\-no-list
+] [
+.B \-\-system
+system ] [
+.B \-\-not-system
+system ] [
+.B \-\-user
+user ] [
+.B \-\-not-user
+user ] [
+.B \-\-command
+command ] [
+.B \-\-not-command
+command ] [
+.B \-\-older-than
+hours ] [
+.B \-\-younger-than
+hours ] [
+.B \-\-mail-lines
lines ]
.PP
.B uustat
[
-.B \-k
+.B \-kr
jobid ] [
-.B \-r
+.B \-\-kill
+jobid ] [
+.B \-\-rejuvenate
jobid ]
.PP
-.B uustat \-q
+.B uustat \-q [
+.B \-sS
+system ] [
+.B \-oy
+hours ] [
+.B \-\-system
+system ] [
+.B \-\-not-system
+system ] [
+.B \-\-older-than
+hours ] [
+.B \-\-younger-than
+hours ]
+.PP
+.B uustat \-\-list [
+.B \-sS
+system ] [
+.B \-oy
+hours ] [
+.B \-\-system
+system ] [
+.B \-\-not-system
+system ] [
+.B \-\-older-than
+hours ] [
+.B \-\-younger-than
+hours ]
.PP
.B uustat \-m
.PP
+.B uustat \-\-status
+.PP
.B uustat \-p
+.PP
+.B uustat \-\-ps
.SH DESCRIPTION
The
.I uustat
@@ -46,35 +110,47 @@ system. It can also be used to cancel or rejuvenate requests made by
By default
.I uustat
displays all jobs queued up for the invoking user, as if given the
-.B \-u
+.B \-\-user
option with the appropriate argument.
If any of the
.B \-a,
+.B \-\-all,
.B \-e,
+.B \-\-executions,
.B \-s,
+.B \-\-system,
.B \-S,
+.B \-\-not-system,
.B \-u,
+.B \-\-user,
.B \-U,
+.B \-\-not-user,
.B \-c,
+.B \-\-command,
.B \-C,
+.B \-\-not-command,
.B \-o,
-.B \-y
+.B \-\-older-than,
+.B \-y,
+.B \-\-younger-than
options are given, then all jobs which match the combined
specifications are displayed.
The
.B \-K
+or
+.B \-\-kill-all
option may be used to kill off a selected group of jobs, such as all
jobs more than 7 days old.
.SH OPTIONS
The following options may be given to
.I uustat.
.TP 5
-.B \-a
+.B \-a, \-\-all
List all queued file transfer requests.
.TP 5
-.B \-e
+.B \-e, \-\-executions
List queued execution requests rather than queued file transfer
requests. Queued execution requests are processed by
.I uuxqt
@@ -86,62 +162,82 @@ of
.I uux
(1).
.TP 5
-.B \-s system
-List all jobs queued up for the named system. This option may be
+.B \-s system, \-\-system system
+List all jobs queued up for the named system. These options may be
specified multiple times, in which case all jobs for all the systems
-will be listed.
+will be listed. If used with
+.B \-\-list
+only the systems named will be listed.
.TP 5
-.B \-S system
-List all jobs queued for systems other than the one named. This
-option may be specified multiple times, in which case no jobs from any
-of the specified systems will be listed. This option may not be used
-with
-.B \-s.
+.B \-S system, \-\-not-system system
+List all jobs queued for systems other than the one named. These
+options may be specified multiple times, in which case no jobs from
+any of the specified systems will be listed. If used with
+.B \-\-list
+only the systems not named will be listed. These options may not be
+used with
+.B \-s
+or
+.B \-\-system.
.TP 5
-.B \-u user
-List all jobs queued up for the named user. This option may be
+.B \-u user, \-\-user user
+List all jobs queued up for the named user. These options may be
specified multiple times, in which case all jobs for all the users
will be listed.
.TP 5
-.B \-U user
-List all jobs queued up for users other than the one named. This
-option may be specified multiple times, in which case no jobs from any
-of the specified users will be listed. This option may not be used
-with
-.B \-u.
+.B \-U user, \-\-not-user user
+List all jobs queued up for users other than the one named. These
+options may be specified multiple times, in which case no jobs from
+any of the specified users will be listed. These options may not be
+used with
+.B \-u
+or
+.B \-\-user.
.TP 5
-.B \-c command
+.B \-c command, \-\-command command
List all jobs requesting the execution of the named command. If
.B command
is
.I ALL
this will list all jobs requesting the execution of some command (as
-opposed to simply requesting a file transfer). This option may be
+opposed to simply requesting a file transfer). These options may be
specified multiple times, in which case all jobs requesting any of the
commands will be listed.
.TP 5
-.B \-C command
+.B \-C command, \-\-not-command command
List all jobs requesting execution of some command other than the
named command, or, if
.B command
is
.I ALL,
list all jobs that simply request a file transfer (as opposed to
-requesting the execution of some command). This option may be
+requesting the execution of some command). These options may be
specified multiple times, in which case no job requesting one of the
-specified commands will be listed. This option may not be used with
-.B \-c.
+specified commands will be listed. These options may not be used with
+.B \-c
+or
+.B \-\-command.
.TP 5
-.B \-o hours
-List all queued jobs older than the given number of hours.
+.B \-o hours, \-\-older-than hours
+List all queued jobs older than the given number of hours. If used
+with
+.B \-\-list
+only systems whose oldest job is older than the given number of hours
+will be listed.
.TP 5
-.B \-y hours
-List all queued jobs younger than the given number of hours.
+.B \-y hours, \-\-younger-than hours
+List all queued jobs younger than the given number of hours. If used
+with
+.B \-\-list
+only systems whose oldest job is younger than the given number of
+hours will be listed.
.TP 5
-.B \-k jobid
+.B \-k jobid, \-\-kill jobid
Kill the named job. The job id is shown by the default output format,
as well as by the
.B \-j
+or
+.B \-\-jobid
option to
.I uucp
(1) or
@@ -149,40 +245,59 @@ option to
(1). A job may only be killed by the user who created the job, or by
the UUCP administrator or the superuser. The
.B \-k
-option may be used multiple times on the command line to kill several
+or
+.B \-\-kill
+options may be used multiple times on the command line to kill several
jobs.
.TP 5
-.B \-r jobid
+.B \-r jobid, \-\-rejuvenate jobid
Rejuvenate the named job. This will mark it as having been invoked at
the current time, affecting the output of the
-.B \-o
+.B \-o,
+.B \-\-older-than,
+.B \-y,
or
-.B \-y
+.B \-\-younger-than
options and preserving it from any automated cleanup daemon. The job
id is shown by the default output format, as well as by the
.B \-j
-option to
+or
+.B \-\-jobid
+options to
.I uucp
(1) or
.I uux
(1). A job may only be rejuvenated by the user who created the job,
or by the UUCP administrator or the superuser. The
.B \-r
-option may be used multiple times on the command line to rejuvenate
+or
+.B \-\-rejuvenate
+options may be used multiple times on the command line to rejuvenate
several jobs.
.TP 5
-.B \-q
+.B \-q, \-\-list
Display the status of commands, executions and conversations for all
-remote systems for which commands or executions are queued.
+remote systems for which commands or executions are queued. The
+.B \-s,
+.B \-\-system,
+.B \-S,
+.B \-\-not-system,
+.B \-o,
+.B \-\-older-than,
+.B \-y,
+and
+.B \-\-younger-than
+options may be used to restrict the systems which are listed. Systems
+for which no commands or executions are queued will never be listed.
.TP 5
-.B \-m
+.B \-m, \-\-status
Display the status of conversations for all remote systems.
.TP 5
-.B \-p
+.B \-p, \-\-ps
Display the status of all processes holding UUCP locks on systems or
ports.
.TP 5
-.B \-i
+.B \-i, \-\-prompt
For each listed job, prompt whether to kill the job or not. If the
first character of the input line is
.I y
@@ -190,53 +305,66 @@ or
.I Y
the job will be killed.
.TP 5
-.B \-K
+.B \-K, \-\-kill-all
Automatically kill each listed job. This can be useful for automatic
cleanup scripts, in conjunction with the
-.B \-M
+.B \-\-mail
and
-.B \-N
+.B \-\-notify
options.
.TP 5
-.B \-M
+.B \-R, \-\-rejuvenate-all
+Automatically rejuvenate each listed job. This may not be used with
+.B \-\-kill-all.
+.TP 5
+.B \-M, \-\-mail
For each listed job, send mail to the UUCP administrator. If the job
is killed (due to
-.B \-K
+.B \-\-kill-all
or
-.B \-i
+.B \-\-prompt
with an affirmative response) the mail will indicate that. A comment
specified by the
-.B \-W
+.B \-\-comment
option may be included. If the job is an execution, the initial
portion of its standard input will be included in the mail message;
the number of lines to include may be set with the
-.B \-B
+.B \-\-mail-lines
option (the default is 100). If the standard input contains null
characters, it is assumed to be a binary file and is not included.
.TP 5
-.B \-N
+.B \-N, \-\-notify
For each listed job, send mail to the user who requested the job. The
mail is identical to that sent by the
.B \-M
-option.
+or
+.B \-\-mail
+options.
.TP 5
-.B \-W
+.B \-W, \-\-comment
Specify a comment to be included in mail sent with the
-.B \-M
+.B \-M,
+.B \-\-mail,
+.B \-N,
or
-.B \-N
+.B \-\-notify
options.
.TP 5
-.B \-Q
+.B \-Q, \-\-no-list
Do not actually list the job, but only take any actions indicated by
the
.B \-i,
+.B \-\-prompt,
.B \-K,
+.B \-\-kill-all,
.B \-M,
+.B \-\-mail,
.B \-N
+or
+.B \-\-notify
options.
.TP 5
-.B \-x type
+.B \-x type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing. Only abnormal, config,
@@ -244,94 +372,122 @@ spooldir and execute are meaningful for
.I uustat.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
+.B \-\-debug abnormal,chat.
.TP 5
-.B \-I file
+.B \-I file, \-\-config file
Set configuration file to use. This option may not be available,
depending upon how
.I uustat
was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
.SH EXAMPLES
-.EX
-uustat -a
-.EE
+.br
+.nf
+uustat --all
+.fi
Display status of all jobs. A sample output line is as follows:
-.EX
+.br
+.in +0.5i
+.nf
bugsA027h bugs ian 04-01 13:50 Executing rmail ian@airs.com (sending 1283 bytes)
-.EE
+.fi
+.in -0.5i
The format is
-.EX
+.br
+.in +0.5i
+.nf
jobid system user queue-date command (size)
-.EE
+.fi
+.in -0.5i
The jobid may be passed to the
-.B \-k
+.B \-\-kill
or
-.B \-r
+.B \-\-rejuvenate
options.
The size indicates how much data is to be transferred to the remote
system, and is absent for a file receive request.
The
-.B \-s,
-.B \-S,
-.B \-u,
-.B \-U,
-.B \-c,
-.B \-C,
-.B \-o,
+.B \-\-system,
+.B \-\-not-system,
+.B \-\-user,
+.B \-\-not-user,
+.B \-\-command,
+.B \-\-not-command,
+.B \-\-older-than,
and
-.B \-y
+.B \-\-younger-than
options may be used to control which jobs are listed.
-.EX
-uustat -e
-.EE
+.br
+.nf
+uustat --executions
+.fi
Display status of queued up execution requests. A sample output line
is as follows:
-.EX
+.br
+.in +0.5i
+.nf
bugs bugs!ian 05-20 12:51 rmail ian
-.EE
+.fi
+.in -0.5i
The format is
-.EX
+.br
+.in +0.5i
+.nf
system requestor queue-date command
-.EE
+.fi
+.in -0.5i
The
-.B \-s,
-.B \-S,
-.B \-u,
-.B \-U,
-.B \-c,
-.B \-C,
-.B \-o,
+.B \-\-system,
+.B \-\-not-system,
+.B \-\-user,
+.B \-\-not-user,
+.B \-\-command,
+.B \-\-not-command,
+.B \-\-older-than,
and
-.B \-y
+.B \-\-younger-than
options may be used to control which requests are listed.
-.EX
-uustat -q
-.EE
+.br
+.nf
+uustat --list
+.fi
Display status for all systems with queued up commands. A sample
output line is as follows:
-.EX
+.br
+.in +0.5i
+.nf
bugs 4C (1 hour) 0X (0 secs) 04-01 14:45 Dial failed
-.EE
+.fi
+.in -0.5i
This indicates the system, the number of queued commands, the age of
the oldest queued command, the number of queued local executions, the
age of the oldest queued execution, the date of the last conversation,
and the status of that conversation.
-.EX
-uustat -m
-.EE
+.br
+.nf
+uustat --status
+.fi
Display conversation status for all remote systems. A sample output
line is as follows:
-.EX
+.br
+.in +0.5i
+.nf
bugs 04-01 15:51 Conversation complete
-.EE
+.fi
+.in -0.5i
This indicates the system, the date of the last conversation, and the
status of that conversation. If the last conversation failed,
.I uustat
@@ -340,9 +496,10 @@ the retry period is currently preventing calls to that system,
.I uustat
also displays the time when the next call will be permitted.
-.EX
-uustat -p
-.EE
+.br
+.nf
+uustat --ps
+.fi
Display the status of all processes holding UUCP locks. The output
format is system dependent, as
.I uustat
@@ -350,18 +507,21 @@ simply invokes
.I ps
(1) on each process holding a lock.
-.EX
-uustat -c rmail -o 168 -K -Q -M -N -W"Queued for over 1 week"
-.EE
+.br
+.in +0.5i
+.nf
+uustat --command rmail --older-than 168 --kill-all --no-list --mail --notify --comment "Queued for over 1 week"
+.fi
+.in -0.5i
This will kill all
.I rmail
commands that have been queued up waiting for delivery for over 1 week
(168 hours). For each such command, mail will be sent both to the
UUCP administrator and to the user who requested the rmail execution.
The mail message sent will include the string given by the
-.B \-W
+.B \-\-comment
option. The
-.B \-Q
+.B \-\-no-list
option prevents any of the jobs from being listed on the terminal, so
any output from the program will be error messages.
.SH FILES
@@ -377,4 +537,4 @@ UUCP spool directory.
ps(1), rmail(1), uucp(1), uux(1), uucico(8), uuxqt(8)
.SH AUTHOR
Ian Lance Taylor
-(ian@airs.com or uunet!airs!ian)
+(ian@airs.com)
diff --git a/gnu/libexec/uucp/uustat/uustat.c b/gnu/libexec/uucp/uustat/uustat.c
index 450f9e03e521..5bba1a9f5df6 100644
--- a/gnu/libexec/uucp/uustat/uustat.c
+++ b/gnu/libexec/uucp/uustat/uustat.c
@@ -1,7 +1,7 @@
/* uustat.c
UUCP status program
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,19 +20,21 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uustat_rcsid[] = "$Id: uustat.c,v 1.1 1993/08/05 18:28:05 conklin Exp $";
+const char uustat_rcsid[] = "$Id: uustat.c,v 1.2 1994/05/07 18:14:24 ache Exp $";
#endif
#include <ctype.h>
#include <errno.h>
-#if HAVE_TIME_H
+#if TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
#include <time.h>
#endif
@@ -71,16 +73,14 @@ const char uustat_rcsid[] = "$Id: uustat.c,v 1.1 1993/08/05 18:28:05 conklin Exp
-xdebug set debugging level
-yhour report jobs younger than specified number of hours */
-/* The program name. */
-char abProgram[] = "uustat";
-
/* What to do with a job that matches the selection criteria; these
values may be or'red together. */
#define JOB_SHOW (01)
#define JOB_INQUIRE (02)
#define JOB_KILL (04)
-#define JOB_MAIL (010)
-#define JOB_NOTIFY (020)
+#define JOB_REJUVENATE (010)
+#define JOB_MAIL (020)
+#define JOB_NOTIFY (040)
/* This structure is used to accumulate all the lines in a single
command file, so that they can all be displayed at once and so that
@@ -96,6 +96,7 @@ struct scmdlist
/* Local functions. */
static void ususage P((void));
+static void ushelp P((void));
static boolean fsxqt_file_read P((pointer puuconf, const char *zfile));
static void usxqt_file_free P((void));
static int isxqt_cmd P((pointer puuconf, int argc, char **argv, pointer pvar,
@@ -139,16 +140,48 @@ static boolean fsexecutions P((pointer puuconf, int icmd, int csystems,
static boolean fsnotify P((pointer puuconf, int icmd, const char *zcomment,
int cstdin, boolean fkilled, const char *zcmd,
struct scmdlist *qcmd, const char *zid,
- const char *zuser,
+ long itime, const char *zuser,
const struct uuconf_system *qsys,
const char *zstdin, pointer pstdinseq,
const char *zrequestor));
-static boolean fsquery P((pointer puuconf));
+static boolean fsquery P((pointer puuconf, int csystems,
+ char **pazsystems, boolean fnotsystems,
+ long iold, long iyoung));
static int csunits_show P((long idiff));
static boolean fsmachines P((void));
/* Long getopt options. */
-static const struct option asSlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asSlongopts[] =
+{
+ { "all", no_argument, NULL, 'a' },
+ { "mail-lines", required_argument, NULL, 'B' },
+ { "command", required_argument, NULL, 'c' },
+ { "not-command", required_argument, NULL, 'C' },
+ { "executions", no_argument, NULL, 'e' },
+ { "prompt", no_argument, NULL, 'i' },
+ { "kill", required_argument, NULL, 'k' },
+ { "kill-all", no_argument, NULL, 'K' },
+ { "status", no_argument, NULL, 'm' },
+ { "mail", no_argument, NULL, 'M' },
+ { "notify", no_argument, NULL, 'N' },
+ { "older-than", required_argument, NULL, 'o' },
+ { "ps", no_argument, NULL, 'p' },
+ { "list", no_argument, NULL, 'q' },
+ { "no-list", no_argument, NULL, 'Q' },
+ { "rejuvenate", required_argument, NULL, 'r' },
+ { "rejuvenate-all", no_argument, NULL, 'R' },
+ { "system", required_argument, NULL, 's' },
+ { "not-system", required_argument, NULL, 'S' },
+ { "user", required_argument, NULL, 'u' },
+ { "not-user", required_argument, NULL, 'U' },
+ { "comment", required_argument, NULL, 'W' },
+ { "younger-than", required_argument, NULL, 'y' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -204,8 +237,10 @@ main (argc, argv)
const char *azoneuser[1];
boolean fret;
+ zProgram = argv[0];
+
while ((iopt = getopt_long (argc, argv,
- "aB:c:C:eiI:k:KmMNo:pqQr:s:S:u:U:W:x:y:",
+ "aB:c:C:eiI:k:KmMNo:pqQr:Rs:S:u:U:vW:x:y:",
asSlongopts, (int *) NULL)) != EOF)
{
switch (iopt)
@@ -304,6 +339,11 @@ main (argc, argv)
pazrejuvs[crejuvs - 1] = optarg;
break;
+ case 'R':
+ /* Rejuvenate each listed job. */
+ icmd |= JOB_REJUVENATE;
+ break;
+
case 'S':
/* List jobs for other than specified system. */
fnotsystems = TRUE;
@@ -345,13 +385,26 @@ main (argc, argv)
iyounghours = (int) strtol (optarg, (char **) NULL, 10);
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ ushelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
default:
ususage ();
- break;
+ /*NOTREACHED*/
}
}
@@ -371,15 +424,23 @@ main (argc, argv)
++ccmds;
if (fps)
++ccmds;
- if (fquery)
- ++ccmds;
- if (fexecute || csystems > 0 || cusers > 0 || ioldhours != -1
+ if (fexecute || fquery || csystems > 0 || cusers > 0 || ioldhours != -1
|| iyounghours != -1 || ccommands > 0)
++ccmds;
+ if (fexecute && fquery)
+ ++ccmds;
if (ccmds > 1)
{
- ulog (LOG_ERROR, "Too many options");
+ fprintf (stderr, "%s: too many options\n", zProgram);
+ ususage ();
+ }
+
+ if ((icmd & JOB_KILL) != 0
+ && (icmd & JOB_REJUVENATE) != 0)
+ {
+ fprintf (stderr, "%s: can not both rejuvenate and kill jobs\n",
+ zProgram);
ususage ();
}
@@ -453,6 +514,7 @@ main (argc, argv)
}
if (! fexecute
+ && ! fquery
&& (fall
|| csystems > 0
|| cusers > 0
@@ -471,12 +533,22 @@ main (argc, argv)
else if (icmd != JOB_SHOW)
{
ulog (LOG_ERROR,
- "-i, -K, -M, -N, -Q not supported with -k, -m, -p, -q, -r");
+ "-i, -K, -M, -N, -Q, -R not supported with -k, -m, -p, -q, -r");
ususage ();
fret = FALSE;
}
else if (fquery)
- fret = fsquery (puuconf);
+ {
+ if (cusers > 0 || ccommands > 0)
+ {
+ ulog (LOG_ERROR, "-u, -c not supported with -q");
+ ususage ();
+ fret = FALSE;
+ }
+ else
+ fret = fsquery (puuconf, csystems, pazsystems, fnotsystems,
+ iold, iyoung);
+ }
else if (fmachine)
fret = fsmachines ();
else if (ckills > 0 || crejuvs > 0)
@@ -515,62 +587,48 @@ main (argc, argv)
static void
ususage ()
{
- fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
- VERSION);
- fprintf (stderr,
- "Usage: uustat [options]\n");
- fprintf (stderr,
- " -a: list all UUCP jobs\n");
- fprintf (stderr,
- " -B num: number of lines to return in -M or -N mail message\n");
- fprintf (stderr,
- " -c command: list requests for named command\n");
- fprintf (stderr,
- " -C command: list requests for other than named command\n");
- fprintf (stderr,
- " -e: list queued executions rather than job requests\n");
- fprintf (stderr,
- " -i: prompt for whether to kill each listed job\n");
- fprintf (stderr,
- " -k job: kill specified UUCP job\n");
- fprintf (stderr,
- " -K: kill each listed job\n");
- fprintf (stderr,
- " -m: report status for all remote machines\n");
- fprintf (stderr,
- " -M: mail report on each listed job to UUCP administrator\n");
- fprintf (stderr,
- " -N: mail report on each listed job to requestor\n");
- fprintf (stderr,
- " -o hours: list all jobs older than given number of hours\n");
- fprintf (stderr,
- " -p: show status of all processes holding UUCP locks\n");
- fprintf (stderr,
- " -q: list number of jobs for each system\n");
- fprintf (stderr,
- " -Q: don't list jobs, just take actions (-i, -K, -M, -N)\n");
- fprintf (stderr,
- " -r job: rejuvenate specified UUCP job\n");
- fprintf (stderr,
- " -s system: list all jobs for specified system\n");
- fprintf (stderr,
- " -S system: list all jobs for other than specified system\n");
- fprintf (stderr,
- " -u user: list all jobs for specified user\n");
- fprintf (stderr,
- " -U user: list all jobs for other than specified user\n");
- fprintf (stderr,
- " -W comment: comment to include in mail messages\n");
- fprintf (stderr,
- " -y hours: list all jobs younger than given number of hours\n");
- fprintf (stderr,
- " -x debug: Set debugging level (0 for none, 9 is max)\n");
+ fprintf (stderr, "Usage: %s [options]\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+ushelp ()
+{
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ VERSION);
+ printf ("Usage: %s [options]\n", zProgram);
+ printf (" -a,--all: list all UUCP jobs\n");
+ printf (" -B,--mail-lines num: number of lines to return in -M or -N mail message\n");
+ printf (" -c,--command command: list requests for named command\n");
+ printf (" -C,--not-command command: list requests for other than named command\n");
+ printf (" -e,--executions: list queued executions rather than job requests\n");
+ printf (" -i,--prompt: prompt for whether to kill each listed job\n");
+ printf (" -k,--kill job: kill specified UUCP job\n");
+ printf (" -K,--kill-all: kill each listed job\n");
+ printf (" -m,--status: report status for all remote machines\n");
+ printf (" -M,--mail: mail report on each listed job to UUCP administrator\n");
+ printf (" -N,--notify: mail report on each listed job to requestor\n");
+ printf (" -o,--older-than hours: list all jobs older than given number of hours\n");
+ printf (" -p,--ps: show status of all processes holding UUCP locks\n");
+ printf (" -q,--list: list number of jobs for each system\n");
+ printf (" -Q,--no-list: don't list jobs, just take actions (-i, -K, -M, -N)\n");
+ printf (" -r,--rejuvenate job: rejuvenate specified UUCP job\n");
+ printf (" -R,--rejuvenate-all: rejuvenate each listed job\n");
+ printf (" -s,--system system: list all jobs for specified system\n");
+ printf (" -S,--not-system system: list all jobs for other than specified system\n");
+ printf (" -u,--user user: list all jobs for specified user\n");
+ printf (" -U,--not-user user: list all jobs for other than specified user\n");
+ printf (" -W,--comment comment: comment to include in mail messages\n");
+ printf (" -y,--younger-than hours: list all jobs younger than given number of hours\n");
+ printf (" -x,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
- exit (EXIT_FAILURE);
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
}
/* We need to be able to read information from an execution file. */
@@ -1051,15 +1109,12 @@ fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands,
else
zfile = zbufcpy (qshow->s.zfrom);
if (zfile == NULL)
- cbytes = 0;
+ cbytes = -1;
else
- {
- cbytes = csysdep_size (zfile);
- if (cbytes < 0)
- cbytes = 0;
- }
- printf ("Sending %s (%ld bytes) to %s",
- qshow->s.zfrom, cbytes, qshow->s.zto);
+ cbytes = csysdep_size (zfile);
+ if (cbytes >= 0)
+ printf ("Sending %s (%ld bytes) to %s",
+ qshow->s.zfrom, cbytes, qshow->s.zto);
ubuffree (zfile);
break;
case 'R':
@@ -1206,25 +1261,28 @@ fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands,
if (fmatch)
{
- boolean fkill;
+ boolean fkill_or_rejuv;
- fkill = FALSE;
+ fkill_or_rejuv = FALSE;
if ((icmd & JOB_INQUIRE) != 0)
{
int b;
/* Ask stdin whether this job should be killed. */
- fprintf (stderr, "%s: Kill %s? ", abProgram, zlistid);
+ fprintf (stderr, "%s: %s %s?",
+ (icmd & JOB_REJUVENATE) != 0 ? "Rejuvenate" : "Kill",
+ zProgram, zlistid);
(void) fflush (stderr);
b = getchar ();
- fkill = b == 'y' || b == 'Y';
+ fkill_or_rejuv = b == 'y' || b == 'Y';
while (b != EOF && b != '\n')
b = getchar ();
}
- else if ((icmd & JOB_KILL) != 0)
- fkill = TRUE;
+ else if ((icmd & JOB_KILL) != 0
+ || (icmd & JOB_REJUVENATE) != 0)
+ fkill_or_rejuv = TRUE;
- if (fkill
+ if (fkill_or_rejuv
&& (qlist->s.zuser == NULL
|| strcmp (zsysdep_login_name (), qlist->s.zuser) != 0)
&& ! fsysdep_privileged ())
@@ -1233,16 +1291,27 @@ fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands,
{
if ((icmd & (JOB_MAIL | JOB_NOTIFY)) != 0)
{
- if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill,
- zcmd, qlist, zlistid, qlist->s.zuser,
- qsys, zstdin, qlist->s.pseq, zrequestor))
+ if (! fsnotify (puuconf, icmd, zcomment, cstdin,
+ (fkill_or_rejuv &&
+ (icmd & JOB_REJUVENATE) == 0),
+ zcmd, qlist, zlistid, qlist->itime,
+ qlist->s.zuser, qsys, zstdin,
+ qlist->s.pseq, zrequestor))
return FALSE;
}
- if (fkill)
+ if (fkill_or_rejuv)
{
- if (! fsysdep_kill_job (puuconf, zlistid))
- return FALSE;
+ if ((icmd & JOB_REJUVENATE) == 0)
+ {
+ if (! fsysdep_kill_job (puuconf, zlistid))
+ return FALSE;
+ }
+ else
+ {
+ if (! fsysdep_rejuvenate_job (puuconf, zlistid))
+ return FALSE;
+ }
}
}
}
@@ -1433,7 +1502,7 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
if (fmatch)
{
- boolean fbad, fkill;
+ boolean fbad, fkill_or_rejuv;
struct uuconf_system ssys;
fbad = FALSE;
@@ -1456,23 +1525,26 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
printf ("%s\n", zSxqt_cmd);
}
- fkill = FALSE;
+ fkill_or_rejuv = FALSE;
if ((icmd & JOB_INQUIRE) != 0)
{
int b;
/* Ask stdin whether this job should be killed. */
- fprintf (stderr, "%s: Kill %s? ", abProgram, zSxqt_cmd);
+ fprintf (stderr, "%s: %s %s?",
+ (icmd & JOB_REJUVENATE) != 0 ? "Rejuvenate" : "Kill",
+ zProgram, zSxqt_cmd);
(void) fflush (stderr);
b = getchar ();
- fkill = b == 'y' || b == 'Y';
+ fkill_or_rejuv = b == 'y' || b == 'Y';
while (b != EOF && b != '\n')
b = getchar ();
}
- else if ((icmd & JOB_KILL) != 0)
- fkill = TRUE;
+ else if ((icmd & JOB_KILL) != 0
+ || (icmd & JOB_REJUVENATE) != 0)
+ fkill_or_rejuv = TRUE;
- if (fkill)
+ if (fkill_or_rejuv)
{
if ((strcmp (zSxqt_user, zsysdep_login_name ()) != 0
|| strcmp (zsystem, zlocalname) != 0)
@@ -1513,9 +1585,10 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
if (! fbad && (icmd & (JOB_MAIL | JOB_NOTIFY)) != 0)
{
- if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill,
+ if (! fsnotify (puuconf, icmd, zcomment, cstdin,
+ fkill_or_rejuv && (icmd & JOB_REJUVENATE) == 0,
zSxqt_cmd, (struct scmdlist *) NULL,
- (const char *) NULL, zSxqt_user, &ssys,
+ (const char *) NULL, itime, zSxqt_user, &ssys,
zSxqt_stdin, (pointer) NULL, zSxqt_requestor))
{
ferr = TRUE;
@@ -1526,7 +1599,7 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
}
}
- if (! fbad && fkill)
+ if (! fbad && fkill_or_rejuv)
{
for (i = 0; i < cSxqt_files; i++)
{
@@ -1536,13 +1609,21 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
(pointer) NULL);
if (z != NULL)
{
- (void) remove (z);
+ if ((icmd & JOB_REJUVENATE) != 0)
+ (void) fsysdep_touch_file (z);
+ else
+ (void) remove (z);
ubuffree (z);
}
}
- if (remove (zfile) != 0)
- ulog (LOG_ERROR, "remove (%s): %s", zfile,
- strerror (errno));
+ if ((icmd & JOB_REJUVENATE) != 0)
+ (void) fsysdep_touch_file (zfile);
+ else
+ {
+ if (remove (zfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfile,
+ strerror (errno));
+ }
}
if (! fbad)
@@ -1562,8 +1643,8 @@ fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
/* When a job is killed, send mail to the appropriate people. */
static boolean
-fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
- qsys, zstdin, pstdinseq, zrequestor)
+fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, itime,
+ zuser, qsys, zstdin, pstdinseq, zrequestor)
pointer puuconf;
int icmd;
const char *zcomment;
@@ -1572,6 +1653,7 @@ fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
const char *zcmd;
struct scmdlist *qcmd;
const char *zid;
+ long itime;
const char *zuser;
const struct uuconf_system *qsys;
const char *zstdin;
@@ -1581,6 +1663,8 @@ fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
const char **pz;
int cgot;
int i, istdin;
+ struct tm stime;
+ char ab[sizeof "1991-12-31 12:00:00"];
const char *zsubject;
boolean fret;
@@ -1615,7 +1699,14 @@ fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
pz[i++] = "\n";
}
- pz[i++] = "The job ";
+ pz[i++] = "The job was queued at ";
+ usysdep_localtime (itime, &stime);
+ sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d",
+ stime.tm_year + 1900, stime.tm_mon + 1, stime.tm_mday,
+ stime.tm_hour, stime.tm_min, stime.tm_sec);
+ pz[i++] = ab;
+ pz[i++] = ".\nIt ";
+
if (fkilled)
pz[i++] = "was\n";
else
@@ -1651,6 +1742,7 @@ fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
break;
case 'P':
pz[i++] = "\tpoll ";
+ break;
#if DEBUG > 0
case 'E':
ulog (LOG_FATAL, "fsnotify: Can't happen");
@@ -1677,7 +1769,8 @@ fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
if (fspool)
zfile = zsysdep_spool_file_name (qsys, zstdin, pstdinseq);
else
- zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir);
+ zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir,
+ (boolean *) NULL);
if (zfile != NULL
&& (fspool
@@ -1827,15 +1920,23 @@ struct sxqtlist
static boolean fsquery_system P((const struct uuconf_system *qsys,
struct sxqtlist **pq,
- long inow, const char *zlocalname));
+ long inow, const char *zlocalname,
+ int csystems, char **pazsystems,
+ boolean fnotsystems, long iold, long iyoung));
static boolean fsquery_show P((const struct uuconf_system *qsys, int cwork,
- long ifirstwork,
- struct sxqtlist *qxqt,
- long inow, const char *zlocalname));
+ long ifirstwork, struct sxqtlist *qxqt,
+ long inow, const char *zlocalname,
+ int csystems, char **pazsystems,
+ boolean fnotsystems, long iold, long iyoung));
static boolean
-fsquery (puuconf)
+fsquery (puuconf, csystems, pazsystems, fnotsystems, iold, iyoung)
pointer puuconf;
+ int csystems;
+ char **pazsystems;
+ boolean fnotsystems;
+ long iold;
+ long iyoung;
{
int iuuconf;
const char *zlocalname;
@@ -1926,7 +2027,8 @@ fsquery (puuconf)
continue;
}
- if (! fsquery_system (&ssys, &qlist, inow, zlocalname))
+ if (! fsquery_system (&ssys, &qlist, inow, zlocalname, csystems,
+ pazsystems, fnotsystems, iold, iyoung))
fret = FALSE;
(void) uuconf_system_free (puuconf, &ssys);
@@ -1965,7 +2067,9 @@ fsquery (puuconf)
ssys.uuconf_zname = (char *) zlocalname;
}
- if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname))
+ if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname,
+ csystems, pazsystems, fnotsystems,
+ iold, iyoung))
fret = FALSE;
(void) uuconf_system_free (puuconf, &ssys);
qfree = *pq;
@@ -1991,7 +2095,8 @@ fsquery (puuconf)
break;
}
- if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname))
+ if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname,
+ csystems, pazsystems, fnotsystems, iold, iyoung))
fret = FALSE;
(void) uuconf_system_free (puuconf, &ssys);
qnext = qlist->qnext;
@@ -2006,11 +2111,17 @@ fsquery (puuconf)
/* Query a single known system. */
static boolean
-fsquery_system (qsys, pq, inow, zlocalname)
+fsquery_system (qsys, pq, inow, zlocalname, csystems, pazsystems,
+ fnotsystems, iold, iyoung)
const struct uuconf_system *qsys;
struct sxqtlist **pq;
long inow;
const char *zlocalname;
+ int csystems;
+ char **pazsystems;
+ boolean fnotsystems;
+ long iold;
+ long iyoung;
{
int cwork;
long ifirstwork;
@@ -2065,7 +2176,9 @@ fsquery_system (qsys, pq, inow, zlocalname)
if (cwork == 0 && *pq == NULL)
return TRUE;
- fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow, zlocalname);
+ fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow,
+ zlocalname, csystems, pazsystems, fnotsystems,
+ iold, iyoung);
if (*pq != NULL)
{
@@ -2084,13 +2197,19 @@ fsquery_system (qsys, pq, inow, zlocalname)
local system specially. */
static boolean
-fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname)
+fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname,
+ csystems, pazsystems, fnotsystems, iold, iyoung)
const struct uuconf_system *qsys;
int cwork;
long ifirstwork;
struct sxqtlist *qxqt;
long inow;
const char *zlocalname;
+ int csystems;
+ char **pazsystems;
+ boolean fnotsystems;
+ long iold;
+ long iyoung;
{
boolean flocal;
struct sstatus sstat;
@@ -2098,6 +2217,34 @@ fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname)
struct tm stime;
int cpad;
+ /* Make sure this is one of the systems we are printing. */
+ if (csystems > 0)
+ {
+ boolean fmatch;
+ int i;
+
+ fmatch = fnotsystems;
+ for (i = 0; i < csystems; i++)
+ {
+ if (strcmp (pazsystems[i], qsys->uuconf_zname) == 0)
+ {
+ fmatch = ! fmatch;
+ break;
+ }
+ }
+ if (! fmatch)
+ return TRUE;
+ }
+
+ /* Make sure the commands are within the time bounds. */
+ if ((iold != (long) -1
+ && (cwork == 0 || ifirstwork > iold)
+ && (qxqt == NULL || qxqt->ifirst > iold))
+ || (iyoung != (long) -1
+ && (cwork == 0 || ifirstwork < iyoung)
+ && (qxqt == NULL || qxqt->ifirst < iyoung)))
+ return TRUE;
+
flocal = strcmp (qsys->uuconf_zname, zlocalname) == 0;
if (! flocal)
diff --git a/gnu/libexec/uucp/uuto/uuto.in b/gnu/libexec/uucp/uuto/uuto.in
index 2d7d96a95870..26a0dc7c15f5 100644
--- a/gnu/libexec/uucp/uuto/uuto.in
+++ b/gnu/libexec/uucp/uuto/uuto.in
@@ -1,8 +1,8 @@
-:
+#!/bin/sh
# uuto
# Send files to a user on another system.
#
-# Copyright (C) 1992 Ian Lance Taylor
+# Copyright (C) 1992, 1993 Ian Lance Taylor
#
# Please feel free do whatever you like with this exciting shell
# script.
@@ -13,4 +13,4 @@
# -c means to not copy the files to the spool directory (may be
# overriden by -C or -p).
#
-@BINDIR@/uucp -t -R -c $*
+exec @BINDIR@/uucp -t -R -c $*
diff --git a/gnu/libexec/uucp/uux/Makefile b/gnu/libexec/uucp/uux/Makefile
index fdb54f87b70a..1fe92f2fa2c2 100644
--- a/gnu/libexec/uucp/uux/Makefile
+++ b/gnu/libexec/uucp/uux/Makefile
@@ -1,9 +1,9 @@
# Makefile for uux
-# $Id: Makefile,v 1.1 1993/08/05 18:28:14 conklin Exp $
+# $Id: Makefile,v 1.3 1994/05/31 07:37:25 ache Exp $
BINDIR= $(bindir)
BINOWN= $(owner)
-BINMODE= 4555
+BINMODE= 4555
PROG= uux
SRCS= uux.c util.c log.c copy.c
diff --git a/gnu/libexec/uucp/uux/uux.1 b/gnu/libexec/uucp/uux/uux.1
index d52c77e4d94c..eb8c90de5a24 100644
--- a/gnu/libexec/uucp/uux/uux.1
+++ b/gnu/libexec/uucp/uux/uux.1
@@ -1,5 +1,5 @@
-''' $Id: uux.1,v 1.1 1993/08/05 18:28:17 conklin Exp $
-.TH uux 1 "Taylor UUCP 1.04"
+''' $Id: uux.1,v 1.2 1994/05/07 18:14:33 ache Exp $
+.TH uux 1 "Taylor UUCP 1.05"
.SH NAME
uux \- Remote command execution over UUCP
.SH SYNOPSIS
@@ -14,9 +14,11 @@ The command
is not executed immediately; the request is queued until the
.I uucico
(8) daemon calls the system and executes it. The daemon is
-started automatically unless the
+started automatically unless one of the
.B \-r
-switch is given.
+or
+.B \-\-nouucico
+options is given.
The actual command execution is done by the
.I uuxqt
@@ -54,9 +56,12 @@ not work.
All specified files are gathered together into a single directory
before execution of the command begins. This means that each file
must have a distinct base name. For example,
-.EX
+.br
+.in +0.5i
+.nf
uux 'sys1!diff sys2!~user1/foo sys3!~user2/foo >!foo.diff'
-.EE
+.fi
+.in -0.5i
will fail because both files will be copied to sys1 and stored under
the name foo.
@@ -68,11 +73,11 @@ command on a remote system.
The following options may be given to
.I uux.
.TP 5
-.B \-,\-p
+.B \-, \-p, \-\-stdin
Read standard input and use it as the standard input for the command
to be executed.
.TP 5
-.B \-c
+.B \-c, \-\-nocopy
Do not copy local files to the spool directory. This is the default.
If they are
removed before being processed by the
@@ -83,20 +88,22 @@ removed before being processed by the
as well as the by the invoker of
.I uux.
.TP 5
-.B \-C
+.B \-C, \-\-copy
Copy local files to the spool directory.
.TP 5
-.B \-l
+.B \-l, \-\-link
Link local files into the spool directory. If a file can not be
linked because it is on a different device, it will be copied unless
-the
+one of the
.B \-c
-option also appears (in other words, use of
-.B \-l
+or
+.B \-\-nocopy
+options also appears (in other words, use of
+.B \-\-link
switches the default from
-.B \-c
+.B \-\-nocopy
to
-.B \-C).
+.B \-\-copy).
If the files are changed before being processed by the
.I uucico
(8) daemon, the changed versions will be used. The files must be
@@ -105,51 +112,50 @@ readable by the
(8) daemon, as well as by the invoker of
.I uux.
.TP 5
-.B \-g grade
+.B \-g grade, \-\-grade grade
Set the grade of the file transfer command. Jobs of a higher grade
are executed first. Grades run 0 ... 9 A ... Z a ... z from high to
low.
.TP 5
-.B \-n
+.B \-n, \-\-notification=no
Do not send mail about the status of the job, even if it fails.
.TP 5
-.B \-z
+.B \-z, \-\-notification=error
Send mail about the status of the job if an error occurs. For many
.I uuxqt
daemons, including the Taylor UUCP
.I uuxqt,
this is the default action; for those,
-.B \-z
+.B \-\-notification=error
will have no effect. However, some
.I uuxqt
daemons will send mail if the job succeeds unless the
-.B \-z
+.B \-\-notification=error
option is used, and some other
.I uuxqt
daemons will not send mail if the job fails unless the
-.B \-z
+.B \-\-notification=error
option is used.
.TP 5
-.B \-r
+.B \-r, \-\-nouucico
Do not start the
.I uucico
(8) daemon immediately; merely queue up the execution request for later
processing.
.TP 5
-.B \-j
+.B \-j, \-\-jobid
Print jobids on standard output. A jobid will be generated for each
file copy operation required to perform the operation. These file
-copies may be cancelled by
-passing the jobid to the
-.B \-k
+copies may be cancelled by passing the jobid to the
+.B \-\-kill
switch of
.I uustat
(1), which will make the execution impossible to complete.
.TP 5
-.B \-a address
+.B \-a address, \-\-requestor address
Report job status to the specified e-mail address.
.TP 5
-.B \-x type
+.B \-x type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing. Only abnormal, config,
@@ -157,40 +163,51 @@ spooldir and execute are meaningful for
.I uux.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
+.B \-\-debug abnormal,chat.
.TP 5
-.B \-I file
+.B \-I file, \-\-config file
Set configuration file to use. This option may not be available,
depending upon how
.I uux
was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
.SH EXAMPLES
-.EX
+.br
+.nf
uux -z - sys1!rmail user1
-.EE
+.fi
Execute the command ``rmail user1'' on the system sys1, giving it as
standard input whatever is given to
.I uux
as standard input. If a failure occurs, send a message using
.I mail
(1).
-.EX
+
+.br
+.nf
uux 'diff -c sys1!~user1/file1 sys2!~user2/file2 >!file.diff'
-.EE
+.fi
Fetch the two named files from system sys1 and system sys2 and execute
.I diff
putting the result in file.diff in the current directory. The current
directory must be writable by the
.I uuxqt
(8) daemon for this to work.
-.EX
+
+.br
+.nf
uux 'sys1!uucp ~user1/file1 (sys2!~user2/file2)'
-.EE
+.fi
Execute
.I uucp
on the system sys1 copying file1 (on system sys1) to sys2. This
@@ -226,9 +243,9 @@ mail(1), uustat(1), uucp(1), uucico(8), uuxqt(8)
Files can not be referenced across multiple systems.
Too many jobids are output by
-.B \-j,
+.B \-\-jobid,
and there is no good way to cancel a local execution requiring remote
files.
.SH AUTHOR
Ian Lance Taylor
-(ian@airs.com or uunet!airs!ian)
+(ian@airs.com)
diff --git a/gnu/libexec/uucp/uux/uux.c b/gnu/libexec/uucp/uux/uux.c
index cdcd5f454a6c..8ae0a2e02c60 100644
--- a/gnu/libexec/uucp/uux/uux.c
+++ b/gnu/libexec/uucp/uux/uux.c
@@ -1,7 +1,7 @@
/* uux.c
Prepare to execute a command on a remote system.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uux_rcsid[] = "$Id: uux.c,v 1.1 1993/08/05 18:28:19 conklin Exp $";
+const char uux_rcsid[] = "$Id: uux.c,v 1.4 1994/05/07 18:14:35 ache Exp $";
#endif
#include "uudefs.h"
@@ -54,9 +54,6 @@ const char uux_rcsid[] = "$Id: uux.c,v 1.1 1993/08/05 18:28:19 conklin Exp $";
operators. */
#define ZSHELLNONREDIRSEPS ";&*| \t"
-/* The program name. */
-char abProgram[] = "uux";
-
/* The name of the execute file. */
const char *zXxqt_name;
@@ -69,9 +66,14 @@ static int cXcmds;
/* A file to close if we're forced to exit. */
static FILE *eXclose;
+
+/* A list of file names which will match the file names which appear
+ in the uucico logs. */
+static char *zXnames;
/* Local functions. */
static void uxusage P((void));
+static void uxhelp P((void));
static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2));
static void uxadd_send_file P((const char *zfrom, const char *zto,
const char *zoptions, const char *ztemp,
@@ -82,9 +84,29 @@ static void uxadd_send_file P((const char *zfrom, const char *zto,
static void uxcopy_stdin P((FILE *e));
static void uxrecord_file P((const char *zfile));
static void uxabort P((void));
+static void uxadd_name P((const char *));
/* Long getopt options. */
-static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asXlongopts[] =
+{
+ { "requestor", required_argument, NULL, 'a' },
+ { "return-stdin", no_argument, NULL, 'b' },
+ { "nocopy", no_argument, NULL, 'c' },
+ { "copy", no_argument, NULL, 'C' },
+ { "grade", required_argument, NULL, 'g' },
+ { "jobid", no_argument, NULL, 'j' },
+ { "link", no_argument, NULL, 'l' },
+ { "notification", required_argument, NULL, 2 },
+ { "stdin", no_argument, NULL, 'p' },
+ { "nouucico", no_argument, NULL, 'r' },
+ { "status", required_argument, NULL, 's' },
+ { "noexpand", no_argument, NULL, 'W' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
/* The main routine. */
@@ -153,40 +175,31 @@ main (argc, argv)
struct uuconf_system slocalsys;
boolean fneedshell;
char *zfullcmd;
+ char aboptions[10];
boolean fexit;
+ zProgram = argv[0];
+
/* We need to be able to read a single - as an option, which getopt
- won't do. So that we can still use getopt, we run through the
- options looking for an option "-"; if we find one we change it to
- "-p", which is equivalent to "-". */
- for (i = 1; i < argc; i++)
+ won't do. We handle this by using getopt to scan the argument
+ list multiple times, replacing any single "-" with "-p". */
+ opterr = 0;
+ while (1)
{
- if (argv[i][0] != '-')
+ while (getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wvx:z",
+ asXlongopts, (int *) NULL) != EOF)
+ ;
+ if (optind >= argc || strcmp (argv[optind], "-") != 0)
break;
- if (argv[i][1] == '\0')
- argv[i] = zbufcpy ("-p");
- else
- {
- const char *z;
-
- for (z = argv[i] + 1; *z != '\0'; z++)
- {
- /* If the option takes an argument, and the argument is
- not appended, then skip the next argument. */
- if (*z == 'a' || *z == 'g' || *z == 'I'
- || *z == 's' || *z == 'x')
- {
- if (z[1] == '\0')
- i++;
- break;
- }
- }
- }
+ argv[optind] = zbufcpy ("-p");
+ optind = 0;
}
+ opterr = 1;
+ optind = 0;
/* The leading + in the getopt string means to stop processing
options as soon as a non-option argument is seen. */
- while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wx:z",
+ while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wvx:z",
asXlongopts, (int *) NULL)) != EOF)
{
switch (iopt)
@@ -271,6 +284,41 @@ main (argc, argv)
ferror_ack = TRUE;
break;
+ case 2:
+ /* --notify={true,false,error}. */
+ if (*optarg == 't'
+ || *optarg == 'T'
+ || *optarg == 'y'
+ || *optarg == 'Y'
+ || *optarg == 'e'
+ || *optarg == 'E')
+ {
+ ferror_ack = TRUE;
+ fno_ack = FALSE;
+ }
+ else if (*optarg == 'f'
+ || *optarg == 'F'
+ || *optarg == 'n'
+ || *optarg == 'N')
+ {
+ ferror_ack = FALSE;
+ fno_ack = TRUE;
+ }
+ break;
+
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ uxhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
@@ -444,32 +492,12 @@ main (argc, argv)
iuuconf = uuconf_system_local (puuconf, &slocalsys);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ slocalsys.uuconf_zname = (char *) zlocalname;
}
- /* Figure out which system the command is to be executed on. Some
- mailers apparently pass local!rmail, so we must explicitly check
- for that. */
+ /* Figure out which system the command is to be executed on. */
+ zcmd = zremove_local_sys (&slocalsys, zcmd);
zexclam = strchr (zcmd, '!');
- while (zexclam != NULL)
- {
- *zexclam = '\0';
- if (strcmp (zcmd, zlocalname) == 0)
- ;
- else if (slocalsys.uuconf_pzalias == NULL)
- break;
- else
- {
- char **pzal;
-
- for (pzal = slocalsys.uuconf_pzalias; *pzal != NULL; pzal++)
- if (strcmp (zcmd, *pzal) == 0)
- break;
- if (*pzal == NULL)
- break;
- }
- zcmd = zexclam + 1;
- zexclam = strchr (zcmd, '!');
- }
if (zexclam == NULL)
{
zsys = zlocalname;
@@ -478,6 +506,7 @@ main (argc, argv)
}
else
{
+ *zexclam = '\0';
zsys = zcmd;
zcmd = zexclam + 1;
fxqtlocal = FALSE;
@@ -587,6 +616,12 @@ main (argc, argv)
if (zexclam == NULL && ! finput && ! foutput)
continue;
+ if (zexclam != NULL)
+ {
+ pzargs[i] = zremove_local_sys (&slocalsys, pzargs[i]);
+ zexclam = strchr (pzargs[i], '!');
+ }
+
/* Get the system name and file name for this file. */
if (zexclam == NULL)
{
@@ -599,22 +634,13 @@ main (argc, argv)
{
*zexclam = '\0';
zsystem = pzargs[i];
- if (*zsystem != '\0')
- flocal = FALSE;
- else
- {
- zsystem = zlocalname;
- flocal = TRUE;
- }
zfile = zexclam + 1;
+ flocal = FALSE;
zexclam = strrchr (zfile, '!');
if (zexclam == NULL)
zforw = NULL;
else
{
- if (flocal)
- ulog (LOG_FATAL, "!%s: Can't figure out where to get file",
- zfile);
*zexclam = '\0';
zforw = zfile;
zfile = zexclam + 1;
@@ -653,7 +679,8 @@ main (argc, argv)
/* Turn the file into an absolute path. */
if (flocal)
- zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir);
+ zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir,
+ (boolean *) NULL);
else if (fexpand)
zfile = zsysdep_add_cwd (zfile);
if (zfile == NULL)
@@ -918,6 +945,7 @@ main (argc, argv)
spool directory; normally such requests are rejected.
This privilege is easy to abuse. */
s.bcmd = 'R';
+ s.bgrade = bgrade;
s.pseq = NULL;
s.zfrom = zfile;
s.zto = zbufcpy (abtname);
@@ -1113,11 +1141,11 @@ main (argc, argv)
if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL)
{
struct scmd s;
- char aboptions[10];
char *zoptions;
/* Set up an E command. */
s.bcmd = 'E';
+ s.bgrade = bgrade;
s.pseq = NULL;
s.zuser = zuser;
s.zfrom = zinput_from;
@@ -1147,6 +1175,8 @@ main (argc, argv)
pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
cXcmds * sizeof (struct scmd));
pasXcmds[cXcmds - 1] = s;
+
+ uxadd_name (zinput_from);
}
else
{
@@ -1225,20 +1255,41 @@ main (argc, argv)
ulog_system (sxqtsys.uuconf_zname);
ulog_user (zuser);
- ulog (LOG_NORMAL, "Queuing %s", zfullcmd);
+ if (zXnames == NULL)
+ ulog (LOG_NORMAL, "Queuing %s", zfullcmd);
+ else
+ ulog (LOG_NORMAL, "Queuing %s (%s)", zfullcmd, zXnames);
ulog_close ();
- if (! fuucico)
+ if (! fuucico
+ || (zcall_system == NULL && ! fcall_any))
fexit = TRUE;
else
{
- if (zcall_system != NULL)
- fexit = fsysdep_run ("uucico", "-s", zcall_system);
- else if (fcall_any)
- fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL);
+ const char *zcicoarg;
+ char *zconfigarg;
+
+ if (zcall_system == NULL)
+ zcicoarg = "-r1";
+ else
+ {
+ char *z;
+
+ z = zbufalc (sizeof "-Cs" + strlen (zcall_system));
+ sprintf (z, "-Cs%s", zcall_system);
+ zcicoarg = z;
+ }
+
+ if (zconfig == NULL)
+ zconfigarg = NULL;
else
- fexit = TRUE;
+ {
+ zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
+ sprintf (zconfigarg, "-I%s", zconfig);
+ }
+
+ fexit = fsysdep_run (FALSE, "uucico", zcicoarg, zconfigarg);
}
usysdep_exit (fexit);
@@ -1250,43 +1301,37 @@ main (argc, argv)
/* Report command usage. */
static void
-uxusage ()
+uxhelp ()
{
- fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
- VERSION);
- fprintf (stderr,
- "Usage: uux [options] [-] command\n");
- fprintf (stderr,
- " -,-p: Read standard input for standard input of command\n");
- fprintf (stderr,
- " -c: Do not copy local files to spool directory (default)\n");
- fprintf (stderr,
- " -C: Copy local files to spool directory\n");
- fprintf (stderr,
- " -l: link local files to spool directory\n");
- fprintf (stderr,
- " -g grade: Set job grade (must be alphabetic)\n");
- fprintf (stderr,
- " -n: Do not report completion status\n");
- fprintf (stderr,
- " -z: Report completion status only on error\n");
- fprintf (stderr,
- " -r: Do not start uucico daemon\n");
- fprintf (stderr,
- " -a address: Address to mail status report to\n");
- fprintf (stderr,
- " -b: Return standard input with status report\n");
- fprintf (stderr,
- " -s file: Report completion status to file\n");
- fprintf (stderr,
- " -j: Report job id\n");
- fprintf (stderr,
- " -x debug: Set debugging level\n");
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ VERSION);
+ printf ("Usage: %s [options] [-] command\n", zProgram);
+ printf (" -,-p,--stdin: Read standard input for standard input of command\n");
+ printf (" -c,--nocopy: Do not copy local files to spool directory (default)\n");
+ printf (" -C,--copy: Copy local files to spool directory\n");
+ printf (" -l,--link: link local files to spool directory\n");
+ printf (" -g,--grade grade: Set job grade (must be alphabetic)\n");
+ printf (" -n,--notification=no: Do not report completion status\n");
+ printf (" -z,--notification=error: Report completion status only on error\n");
+ printf (" -r,--nouucico: Do not start uucico daemon\n");
+ printf (" -a,--requestor address: Address to mail status report to\n");
+ printf (" -b,--return-stdin: Return standard input with status report\n");
+ printf (" -s,--status file: Report completion status to file\n");
+ printf (" -j,--jobid: Report job id\n");
+ printf (" -x,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
+}
+
+static void
+uxusage ()
+{
+ fprintf (stderr,
+ "Usage: %s [options] [-] command\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
exit (EXIT_FAILURE);
}
@@ -1366,6 +1411,7 @@ uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc,
/* Send the execution file. */
s.bcmd = 'S';
+ s.bgrade = bgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (abtname);
s.zto = zbufcpy (abxname);
@@ -1383,12 +1429,15 @@ uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc,
cXcmds * sizeof (struct scmd));
pasXcmds[cXcmds - 1] = s;
+ uxadd_name (abtname);
+
/* Send the data file to abdname where the execution file will
expect it. */
zto = abdname;
}
s.bcmd = 'S';
+ s.bgrade = bgrade;
s.pseq = NULL;
s.zfrom = zbufcpy (zfrom);
s.zto = zbufcpy (zto);
@@ -1405,6 +1454,8 @@ uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc,
pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
cXcmds * sizeof (struct scmd));
pasXcmds[cXcmds - 1] = s;
+
+ uxadd_name (zfrom);
}
/* Copy stdin to a file. This is a separate function because it may
@@ -1500,3 +1551,31 @@ uxabort ()
ulog_close ();
usysdep_exit (FALSE);
}
+
+/* Add a name to the list of file names we are going to log. We log
+ all the file names which will appear in the uucico log file. This
+ permits people to associate the file send in the uucico log with
+ the uux entry which created the file. Normally only one file name
+ will appear. */
+
+static void
+uxadd_name (z)
+ const char *z;
+{
+ if (zXnames == NULL)
+ zXnames = zbufcpy (z);
+ else
+ {
+ size_t cold, cadd;
+ char *znew;
+
+ cold = strlen (zXnames);
+ cadd = strlen (z);
+ znew = zbufalc (cold + 2 + cadd);
+ memcpy (znew, zXnames, cold);
+ znew[cold] = ' ';
+ memcpy (znew + cold + 1, z, cadd + 1);
+ ubuffree (zXnames);
+ zXnames = znew;
+ }
+}
diff --git a/gnu/libexec/uucp/uuxqt/Makefile b/gnu/libexec/uucp/uuxqt/Makefile
index 13de6ccfd94a..dd28c2c91ac7 100644
--- a/gnu/libexec/uucp/uuxqt/Makefile
+++ b/gnu/libexec/uucp/uuxqt/Makefile
@@ -1,16 +1,17 @@
# Makefile for uuxqt
-# $Id: Makefile,v 1.2 1993/08/06 23:38:29 rgrimes Exp $
+# $Id: Makefile,v 1.5 1994/05/31 05:46:42 ache Exp $
BINDIR= $(sbindir)
BINOWN= $(owner)
-BINMODE= 4555
+BINGRP= $(group)
+BINMODE= 4550
PROG= uuxqt
SRCS= uuxqt.c util.c log.c copy.c
LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
CFLAGS+= -I$(.CURDIR)/../common_sources\
- -DVERSION=\"$(VERSION)\"
+ -DVERSION=\"$(VERSION)\" -DOWNER=\"$(owner)\"
MAN8= uuxqt.8
diff --git a/gnu/libexec/uucp/uuxqt/uuxqt.8 b/gnu/libexec/uucp/uuxqt/uuxqt.8
index 3664a81f0821..dc48bbb6ca94 100644
--- a/gnu/libexec/uucp/uuxqt/uuxqt.8
+++ b/gnu/libexec/uucp/uuxqt/uuxqt.8
@@ -1,5 +1,5 @@
-''' $Id: uuxqt.8,v 1.1 1993/08/05 18:28:26 conklin Exp $
-.TH uuxqt 8 "Taylor UUCP 1.04"
+''' $Id: uuxqt.8,v 1.2 1994/05/07 18:14:41 ache Exp $
+.TH uuxqt 8 "Taylor UUCP 1.05"
.SH NAME
uuxqt \- UUCP execution daemon
.SH SYNOPSIS
@@ -17,6 +17,8 @@ It is started automatically by the
.I uucico
(8) is given the
.B \-q
+or
+.B \-\-nouuxqt
option).
There is normally no need to run this command, since it will be
@@ -34,16 +36,19 @@ configuration command.
The following options may be given to
.I uuxqt.
.TP 5
-.B \-c command
+.B \-c command, \-\-command command
Only execute requests for the specified command. For example:
-.EX
-uuxqt -c rmail
-.EE
+.br
+.in +0.5i
+.nf
+uuxqt --command rmail
+.fi
+.in -0.5i
.TP 5
-.B \-s system
+.B \-s system, \-\-system system
Only execute requests originating from the specified system.
.TP 5
-.B \-x type
+.B \-x type, \-\-debug type
Turn on particular debugging types. The following types are
recognized: abnormal, chat, handshake, uucp-proto, proto, port,
config, spooldir, execute, incoming, outgoing. Only abnormal, config,
@@ -51,22 +56,28 @@ spooldir and execute are meaningful for
.I uuxqt.
Multiple types may be given, separated by commas, and the
-.B \-x
+.B \-\-debug
option may appear multiple times. A number may also be given, which
will turn on that many types from the foregoing list; for example,
-.B \-x 2
+.B \-\-debug 2
is equivalent to
-.B \-x abnormal,chat.
+.B \-\-debug abnormal,chat.
The debugging output is sent to the debugging file, usually one of
/usr/spool/uucp/Debug, /usr/spool/uucp/DEBUG, or
/usr/spool/uucp/.Admin/audit.local.
.TP 5
-.B \-I file
+.B \-I file, \-\-config
Set configuration file to use. This option may not be available,
depending upon how
.I uuxqt
was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
.SH FILES
The file names may be changed at compilation time or by the
configuration file, so these are only approximations.
@@ -89,4 +100,4 @@ Debugging file.
uucp(1), uux(1), uucico(8)
.SH AUTHOR
Ian Lance Taylor
-(ian@airs.com or uunet!airs!ian)
+(ian@airs.com)
diff --git a/gnu/libexec/uucp/uuxqt/uuxqt.c b/gnu/libexec/uucp/uuxqt/uuxqt.c
index e645e1f242e4..f1c29e02de81 100644
--- a/gnu/libexec/uucp/uuxqt/uuxqt.c
+++ b/gnu/libexec/uucp/uuxqt/uuxqt.c
@@ -1,7 +1,7 @@
/* uuxqt.c
Run uux commands.
- Copyright (C) 1991, 1992 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -20,13 +20,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
*/
#include "uucp.h"
#if USE_RCS_ID
-const char uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.1 1993/08/05 18:28:27 conklin Exp $";
+const char uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.2 1994/05/07 18:14:43 ache Exp $";
#endif
#include <errno.h>
@@ -38,9 +38,6 @@ const char uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.1 1993/08/05 18:28:27 conklin Exp $
#include "uuconf.h"
#include "system.h"
-/* The program name. */
-char abProgram[] = "uuxqt";
-
/* Static variables used to unlock things if we get a fatal error. */
static int iQlock_seq = -1;
static const char *zQunlock_cmd;
@@ -54,6 +51,7 @@ static char *zQmail;
/* Local functions. */
static void uqusage P((void));
+static void uqhelp P((void));
static void uqabort P((void));
static void uqdo_xqt_file P((pointer puuconf, const char *zfile,
const char *zbase,
@@ -65,7 +63,16 @@ static boolean fqforward P((const char *zfile, char **pzallowed,
const char *zlog, const char *zmail));
/* Long getopt options. */
-static const struct option asQlongopts[] = { { NULL, 0, NULL, 0 } };
+static const struct option asQlongopts[] =
+{
+ { "command", required_argument, 0, 'c' },
+ { "system", required_argument, 0, 's' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
int
main (argc, argv)
@@ -88,7 +95,9 @@ main (argc, argv)
boolean fsys;
struct uuconf_system ssys;
- while ((iopt = getopt_long (argc, argv, "c:I:s:x:", asQlongopts,
+ zProgram = argv[0];
+
+ while ((iopt = getopt_long (argc, argv, "c:I:s:vx:", asQlongopts,
(int *) NULL)) != EOF)
{
switch (iopt)
@@ -115,6 +124,19 @@ main (argc, argv)
#endif
break;
+ case 'v':
+ /* Print version and exit. */
+ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 1:
+ /* --help. */
+ uqhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
case 0:
/* Long option found and flag set. */
break;
@@ -181,15 +203,28 @@ main (argc, argv)
fsys = FALSE;
- /* If we were given a system name, canonicalize it, since the system
- dependent layer will not be returning aliases. */
+ /* If we were given a system name, canonicalize it. */
if (zdosys != NULL)
{
iuuconf = uuconf_system_info (puuconf, zdosys, &ssys);
- if (iuuconf == UUCONF_NOT_FOUND)
- ulog (LOG_FATAL, "%s: System not found", zdosys);
- else if (iuuconf != UUCONF_SUCCESS)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ if (strcmp (zdosys, zlocalname) == 0)
+ {
+ iuuconf = uuconf_system_local (puuconf, &ssys);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ ssys.uuconf_zname = (char *) zlocalname;
+ }
+ else
+ {
+ if (! funknown_system (puuconf, zdosys, &ssys))
+ ulog (LOG_FATAL, "%s: system not found", zdosys);
+ }
+ }
zdosys = zbufcpy (ssys.uuconf_zname);
fsys = TRUE;
@@ -225,15 +260,8 @@ main (argc, argv)
boolean fprocessed;
char *zbase;
- /* It would be more efficient to pass zdosys down to the
- routines which retrieve execute files. */
- if (zdosys != NULL && strcmp (zdosys, zgetsys) != 0)
- {
- ubuffree (z);
- ubuffree (zgetsys);
- continue;
- }
-
+ /* Get the system information for the system returned by
+ zsysdep_get_xqt. */
if (! fsys || strcmp (ssys.uuconf_zname, zgetsys) != 0)
{
if (fsys)
@@ -260,6 +288,7 @@ main (argc, argv)
ubuffree (zgetsys);
continue;
}
+ ssys.uuconf_zname = (char *) zlocalname;
}
else
{
@@ -287,6 +316,15 @@ main (argc, argv)
break;
}
+ /* Make sure we are supposed to be executing jobs for this
+ system. */
+ if (zdosys != NULL && strcmp (zdosys, ssys.uuconf_zname) != 0)
+ {
+ ubuffree (z);
+ ubuffree (zgetsys);
+ continue;
+ }
+
zloc = ssys.uuconf_zlocalname;
if (zloc == NULL)
zloc = zlocalname;
@@ -323,23 +361,27 @@ main (argc, argv)
}
static void
-uqusage ()
+uqhelp ()
{
- fprintf (stderr,
- "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ printf ("Taylor UUCP %s, copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor\n",
VERSION);
- fprintf (stderr,
- "Usage: uuxqt [-c cmd] [-I file] [-s system] [-x debug]\n");
- fprintf (stderr,
- " -c cmd: Set type of command to execute\n");
- fprintf (stderr,
- " -s system: Execute commands only for named system\n");
- fprintf (stderr,
- " -x debug: Set debugging level (0 for none, 9 is max)\n");
+ printf ("Usage: %s [-c,--command cmd] [-s,--system system]\n", zProgram);
+ printf (" -c,--command cmd: Set type of command to execute\n");
+ printf (" -s,--system system: Execute commands only for named system\n");
+ printf (" -x,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
- fprintf (stderr,
- " -I file: Set configuration file to use\n");
+ printf (" -I,--config file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
+ printf (" -v,--version: Print version and exit\n");
+ printf (" --help: Print help and exit\n");
+}
+
+static void
+uqusage ()
+{
+ fprintf (stderr,
+ "Usage: %s [-c,--command cmd] [-s,--system system]\n", zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
exit (EXIT_FAILURE);
}
@@ -449,23 +491,25 @@ static int iquser P((pointer puuconf, int argc, char **argv, pointer pvar,
static int iqset P((pointer puuconf, int argc, char **argv, pointer pvar,
pointer pinfo));
+/* We are lax about the number of arguments the functions accept,
+ because there is a lot of variation in what other (buggy) UUCP
+ packages generate. Unused arguments are ignored. */
+
static const struct uuconf_cmdtab asQcmds[] =
{
{ "C", UUCONF_CMDTABTYPE_FN | 0, NULL, iqcmd },
{ "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zQinput, NULL },
{ "O", UUCONF_CMDTABTYPE_FN | 0, NULL, iqout },
{ "F", UUCONF_CMDTABTYPE_FN | 0, NULL, iqfile },
- { "R", UUCONF_CMDTABTYPE_FN, NULL, iqrequestor },
- { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, iquser },
- { "N", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQno_ack, iqset },
- { "n", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQsuccess_ack, iqset },
- /* Some systems create execution files in which B takes an argument;
- I don't know what it means, so I just ignore it. */
+ { "R", UUCONF_CMDTABTYPE_FN | 0, NULL, iqrequestor },
+ { "U", UUCONF_CMDTABTYPE_FN | 0, NULL, iquser },
+ { "N", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQno_ack, iqset },
+ { "n", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsuccess_ack, iqset },
{ "B", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsend_input, iqset },
#if ALLOW_SH_EXECUTION
- { "e", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_sh, iqset },
+ { "e", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQuse_sh, iqset },
#endif
- { "E", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_exec, iqset },
+ { "E", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQuse_exec, iqset },
{ "M", UUCONF_CMDTABTYPE_STRING, (pointer) &zQstatus_file, NULL },
{ NULL, 0, NULL, NULL }
};
@@ -519,17 +563,9 @@ iqout (puuconf, argc, argv, pvar, pinfo)
pointer pvar;
pointer pinfo;
{
- const char *zbase = (const char *) pinfo;
-
- if (argc != 2 && argc != 3)
- {
- ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
- zbase, argv[0]);
- return UUCONF_CMDTABRET_CONTINUE;
- }
-
- zQoutfile = zbufcpy (argv[1]);
- if (argc == 3)
+ if (argc > 1)
+ zQoutfile = zbufcpy (argv[1]);
+ if (argc > 2)
zQoutsys = zbufcpy (argv[2]);
return UUCONF_CMDTABRET_CONTINUE;
@@ -546,14 +582,8 @@ iqfile (puuconf, argc, argv, pvar, pinfo)
pointer pvar;
pointer pinfo;
{
- const char *zbase = (const char *) pinfo;
-
- if (argc != 2 && argc != 3)
- {
- ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
- zbase, argv[0]);
- return UUCONF_CMDTABRET_CONTINUE;
- }
+ if (argc < 2)
+ return UUCONF_CMDTABRET_CONTINUE;
/* If this file is not in the spool directory, just ignore it. */
if (! fspool_file (argv[1]))
@@ -566,7 +596,7 @@ iqfile (puuconf, argc, argv, pvar, pinfo)
cQfiles * sizeof (char *));
azQfiles[cQfiles - 1] = zbufcpy (argv[1]);
- if (argc == 3)
+ if (argc > 2)
azQfiles_to[cQfiles - 1] = zbufcpy (argv[2]);
else
azQfiles_to[cQfiles - 1] = NULL;
@@ -585,22 +615,13 @@ iqrequestor (puuconf, argc, argv, pvar, pinfo)
pointer pvar;
pointer pinfo;
{
- const char *zbase = (const char *) pinfo;
-
- if (argc != 2 && argc != 3)
- {
- ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
- zbase, argv[0]);
- return UUCONF_CMDTABRET_CONTINUE;
- }
-
/* We normally have a single argument, which is the ``requestor''
address, to which we should send any success or error messages.
Apparently the DOS program UUPC sends two arguments, which are
the username and the host. */
if (argc == 2)
zQrequestor = zbufcpy (argv[1]);
- else
+ else if (argc > 2)
{
zQrequestor = zbufalc (strlen (argv[1]) + strlen (argv[2])
+ sizeof "!");
@@ -621,8 +642,10 @@ iquser (puuconf, argc, argv, pvar, pinfo)
pointer pvar;
pointer pinfo;
{
- zQuser = argv[1];
- zQsystem = argv[2];
+ if (argc > 1)
+ zQuser = argv[1];
+ if (argc > 2)
+ zQsystem = argv[2];
return UUCONF_CMDTABRET_KEEP;
}
@@ -680,6 +703,7 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
const char *zmail;
char *zoutput;
char *zinput;
+ boolean fbadname;
char abtemp[CFILE_NAME_LEN];
char abdata[CFILE_NAME_LEN];
char *zerror;
@@ -724,6 +748,40 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ /* If we got a non-transient error, we notify the administrator.
+ We can't bounce it back to the original requestor, because we
+ don't know how to read the file to figure out who it is (it
+ would probably be possible to read the file and work it out,
+ but it doesn't seem worth it for such an unlikely error). */
+ if (UUCONF_ERROR_VALUE (iuuconf) == UUCONF_SYNTAX_ERROR
+ || UUCONF_ERROR_VALUE (iuuconf) == UUCONF_UNKNOWN_COMMAND)
+ {
+ const char *az[20];
+ char *znew;
+
+ i = 0;
+ az[i++] = "The execution file\n\t";
+ az[i++] = zfile;
+ az[i++] = "\nfor system\n\t";
+ az[i++] = qsys->uuconf_zname;
+ az[i++] = "\nwas corrupt. ";
+ znew = zsysdep_save_corrupt_file (zfile);
+ if (znew == NULL)
+ {
+ az[i++] = "The file could not be preserved.\n";
+ (void) remove (zfile);
+ }
+ else
+ {
+ az[i++] = "It has been moved to\n\t";
+ az[i++] = znew;
+ az[i++] = "\n";
+ }
+ (void) fsysdep_mail (OWNER, "Corrupt execution file", i, az);
+ ubuffree (znew);
+ }
+
return;
}
@@ -780,6 +838,16 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
else
ulog_user ("unknown");
+ /* zQsystem, if it is set, comes from the execution file, which
+ means that we do not trust it. We only retain it if
+ qsys->uuconf_zname is a prefix of it, since that can happen with
+ a job from an anonymous system on certain spool directory types,
+ and is unlikely to cause any trouble anyhow. */
+ if (zQsystem == NULL
+ || strncmp (zQsystem, qsys->uuconf_zname,
+ strlen (qsys->uuconf_zname)) != 0)
+ zQsystem = qsys->uuconf_zname;
+
/* Make sure that all the required files exist, and get their
full names in the spool directory. */
for (i = 0; i < cQfiles; i++)
@@ -823,7 +891,6 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
else if (zQuser != NULL)
zmail = zQuser;
if (zmail != NULL
- && zQsystem != NULL
#if HAVE_INTERNET_MAIL
&& strchr (zmail, '@') == NULL
#endif
@@ -846,7 +913,7 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
char *zfrom, *zto;
boolean fmany;
char **azargs;
- const char *zuser, *zsystem;
+ const char *zuser;
zfrom = NULL;
zto = NULL;
@@ -904,12 +971,9 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
zuser = zQuser;
if (zuser == NULL)
zuser = "uucp";
- zsystem = zQsystem;
- if (zsystem == NULL)
- zsystem = qsys->uuconf_zname;
- azargs[1] = zbufalc (strlen (zsystem) + strlen (zuser)
+ azargs[1] = zbufalc (strlen (zQsystem) + strlen (zuser)
+ sizeof "-u!");
- sprintf (azargs[1], "-u%s!%s", zsystem, zuser);
+ sprintf (azargs[1], "-u%s!%s", zQsystem, zuser);
memcpy (azargs + 2, azQargs + 1, i * sizeof (char *));
xfree ((pointer) azQargs);
azQargs = azargs;
@@ -1067,11 +1131,14 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
char *zreal;
fspool = fspool_file (zQinput);
- if (fspool)
- zreal = zsysdep_spool_file_name (qsys, zQinput, (pointer) NULL);
+ if (! fspool)
+ zreal = zsysdep_local_file (zQinput, qsys->uuconf_zpubdir, &fbadname);
else
- zreal = zsysdep_local_file (zQinput, qsys->uuconf_zpubdir);
- if (zreal == NULL)
+ {
+ zreal = zsysdep_spool_file_name (qsys, zQinput, (pointer) NULL);
+ fbadname = FALSE;
+ }
+ if (zreal == NULL && ! fbadname)
{
/* If we get an error, try again later. */
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
@@ -1079,13 +1146,17 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
return;
}
- zQinput = zreal;
- iclean |= FREE_QINPUT;
+ if (zreal != NULL)
+ {
+ zQinput = zreal;
+ iclean |= FREE_QINPUT;
+ }
- if (! fspool
- && ! fin_directory_list (zQinput, qsys->uuconf_pzremote_send,
- qsys->uuconf_zpubdir, TRUE, TRUE,
- (const char *) NULL))
+ if (zreal == NULL
+ || (! fspool
+ && ! fin_directory_list (zQinput, qsys->uuconf_pzremote_send,
+ qsys->uuconf_zpubdir, TRUE, TRUE,
+ (const char *) NULL)))
{
ulog (LOG_ERROR, "Not permitted to read %s", zQinput);
@@ -1176,22 +1247,30 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
fok = FALSE;
else
{
- zoutput = zsysdep_local_file (zQoutfile, qsys->uuconf_zpubdir);
+ zoutput = zsysdep_local_file (zQoutfile, qsys->uuconf_zpubdir,
+ &fbadname);
if (zoutput == NULL)
{
- /* If we get an error, try again later. */
- uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
- *pfprocessed = FALSE;
- return;
+ if (! fbadname)
+ {
+ /* If we get an error, try again later. */
+ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
+ *pfprocessed = FALSE;
+ return;
+ }
+ fok = FALSE;
+ }
+ else
+ {
+ ubuffree (zQoutfile);
+ zQoutfile = zoutput;
+
+ /* Make sure it's OK to receive this file. */
+ fok = fin_directory_list (zQoutfile,
+ qsys->uuconf_pzremote_receive,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL);
}
- ubuffree (zQoutfile);
- zQoutfile = zoutput;
-
- /* Make sure it's OK to receive this file. */
- fok = fin_directory_list (zQoutfile,
- qsys->uuconf_pzremote_receive,
- qsys->uuconf_zpubdir, TRUE, FALSE,
- (const char *) NULL);
}
if (! fok)
@@ -1369,6 +1448,7 @@ uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
/* Fill in the command structure. */
s.bcmd = 'S';
+ s.bgrade = BDEFAULT_UUX_GRADE;
s.pseq = NULL;
s.zfrom = abtemp;
s.zto = zQoutfile;
diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile
index 2296ca1c8e88..f755f6ac7fb8 100644
--- a/gnu/usr.bin/Makefile
+++ b/gnu/usr.bin/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.1 1994/01/30 00:31:48 rgrimes Exp $
+# $Id: Makefile,v 1.3 1994/06/10 16:51:29 paul Exp $
-SUBDIR= as awk bc cc cpio cvs dc diff diff3 gdb grep groff gzip ld \
- man patch pr rcs sdiff sort tar
+SUBDIR= as awk bc cc cpio cvs dc diff diff3 gdb grep groff gzip kgdb ld \
+ man patch ptx pr rcs sdiff sort tar
.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/awk/ACKNOWLEDGMENT b/gnu/usr.bin/awk/ACKNOWLEDGMENT
index b6c3b0b0c692..cb4021f7d633 100644
--- a/gnu/usr.bin/awk/ACKNOWLEDGMENT
+++ b/gnu/usr.bin/awk/ACKNOWLEDGMENT
@@ -8,12 +8,16 @@ platforms and providing a great deal of feedback. They are:
Hal Peterson <hrp@pecan.cray.com> (Cray)
Pat Rankin <gawk.rankin@EQL.Caltech.Edu> (VMS)
- Michal Jaegermann <NTOMCZAK@vm.ucs.UAlberta.CA> (Atari, NeXT, DEC 3100)
+ Michal Jaegermann <michal@gortel.phys.UAlberta.CA> (Atari, NeXT, DEC 3100)
Mike Lijewski <mjlx@eagle.cnsf.cornell.edu> (IBM RS6000)
- Scott Deifik <scottd@amgen.com> (MSDOS 2.14)
+ Scott Deifik <scottd@amgen.com> (MSDOS 2.14 and 2.15)
Kent Williams (MSDOS 2.11)
Conrad Kwok (MSDOS earlier versions)
Scott Garfinkle (MSDOS earlier versions)
+ Kai Uwe Rommel <rommel@ars.muc.de> (OS/2)
+ Darrel Hankerson <hankedr@mail.auburn.edu> (OS/2)
+ Mark Moraes <Mark-Moraes@deshaw.com> (Code Center, Purify)
+ Kaveh Ghazi <ghazi@noc.rutgers.edu> (Lots of Unix variants)
Last, but far from least, we would like to thank Brian Kernighan who
has helped to clear up many dark corners of the language and provided a
diff --git a/gnu/usr.bin/awk/FUTURES b/gnu/usr.bin/awk/FUTURES
index b09656046b27..6250584fdfd5 100644
--- a/gnu/usr.bin/awk/FUTURES
+++ b/gnu/usr.bin/awk/FUTURES
@@ -1,14 +1,26 @@
This file lists future projects and enhancements for gawk. Items are listed
in roughly the order they will be done for a given release. This file is
-mainly for use by the developers to help keep themselves on track, please
+mainly for use by the developer(s) to help keep themselves on track, please
don't bug us too much about schedules or what all this really means.
+(An `x' indicates that some progress has been made, but that the feature is
+not complete yet.)
+
For 2.16
========
-David:
- Move to autoconf-based configure system.
+x Move to autoconf-based configure system.
+
+x Research awk `fflush' function.
+
+x Generalize IGNORECASE
+ any value makes it work, not just numeric non-zero
+ make it apply to *all* string comparisons
+
+x Fix FILENAME to have an initial value of "", not "-"
- Allow RS to be a regexp.
+In 2.17
+=======
+x Allow RS to be a regexp.
RT variable to hold text of record terminator
@@ -16,46 +28,24 @@ David:
Feedback alloca.s changes to FSF
- Extensible hashing in memory of awk arrays
+x Split() with null string as third arg to split up strings
- Split() with null string as third arg to split up strings
-
- Analogously, setting FS="" would split the input record into individual
+x Analogously, setting FS="" would split the input record into individual
characters.
-Arnold:
- Generalize IGNORECASE
- any value makes it work, not just numeric non-zero
- make it apply to *all* string comparisons
-
- Fix FILENAME to have an initial value of "", not "-"
-
- Clean up code by isolating system-specific functions in separate files.
+x Clean up code by isolating system-specific functions in separate files.
Undertake significant directory reorganization.
- Extensive manual cleanup:
+x Extensive manual cleanup:
Use of texinfo 2.0 features
Lots more examples
Document all of the above.
-In 2.17
-=======
-David:
-
- Incorporate newer dfa.c and regex.c (go to POSIX regexps)
+x Go to POSIX regexps
Make regex + dfa less dependant on gawk header file includes
- General sub functions:
- edit(line, pat, sub) and gedit(line, pat, sub)
- that return the substituted strings and allow \1 etc. in the sub string.
-
-Arnold:
- DBM storage of awk arrays. Try to allow multiple dbm packages
-
- ? Have strftime() pay attention to the value of ENVIRON["TZ"]
-
Additional manual features:
Document posix regexps
Document use of dbm arrays
@@ -67,19 +57,26 @@ Arnold:
For 2.18
========
+ DBM storage of awk arrays. Try to allow multiple dbm packages
-Arnold:
+ General sub functions:
+ edit(line, pat, sub) and gedit(line, pat, sub)
+ that return the substituted strings and allow \1 etc. in the sub
+ string.
+
+ ? Have strftime() pay attention to the value of ENVIRON["TZ"]
+
+For 2.19
+========
Add chdir and stat built-in functions.
Add function pointers as valid variable types.
Add an `ftw' built-in function that takes a function pointer.
-David:
-
Do an optimization pass over parse tree?
-For 2.19 or later:
+For 2.20 or later:
==================
Add variables similar to C's __FILE__ and __LINE__ for better diagnostics
from within awk programs.
@@ -101,7 +98,7 @@ Make awk '/foo/' files... run at egrep speeds
Do a reference card
-Allow OFMT to be other than a floating point format.
+Allow OFMT and CONVFMT to be other than a floating point format.
Allow redefining of builtin functions?
diff --git a/gnu/usr.bin/awk/LIMITATIONS b/gnu/usr.bin/awk/LIMITATIONS
index 5877197aeb55..64eab85f164b 100644
--- a/gnu/usr.bin/awk/LIMITATIONS
+++ b/gnu/usr.bin/awk/LIMITATIONS
@@ -12,3 +12,5 @@ Characters in a character class: 2^(# of bits per byte)
# of pipe redirections: min(# of processes per user, # of open files)
double-precision floating point
Length of source line: unlimited
+Number of input records in one file: MAX_LONG
+Number of input records total: MAX_LONG
diff --git a/gnu/usr.bin/awk/Makefile b/gnu/usr.bin/awk/Makefile
index 3ef9894d175d..dad9f5772be3 100644
--- a/gnu/usr.bin/awk/Makefile
+++ b/gnu/usr.bin/awk/Makefile
@@ -1,13 +1,13 @@
-PROG= awk
-SRCS= main.c eval.c builtin.c msg.c iop.c io.c field.c array.c \
- node.c version.c re.c awk.c regex.c dfa.c \
- getopt.c getopt1.c
-CFLAGS+= -DGAWK
-LDADD= -lm
-DPADD= ${LIBM}
-CLEANFILES+= awk.c y.tab.h
+PROG= awk
+SRCS= main.c eval.c builtin.c msg.c iop.c io.c field.c getopt1.c \
+ getopt.c array.c \
+ node.c version.c re.c awk.c regex.c dfa.c
+DPADD= ${LIBM}
+LDADD= -lm
+CFLAGS+=-I${.CURDIR} -DGAWK
+CLEANFILES+=awk.c y.tab.h
-MAN1= awk.1
+MAN1= awk.1
.include <bsd.prog.mk>
-.include "../../usr.bin/Makefile.inc"
+#.include "../../usr.bin/Makefile.inc"
diff --git a/gnu/usr.bin/awk/NEWS b/gnu/usr.bin/awk/NEWS
index 6711373d6ea5..4df69e7d0bf8 100644
--- a/gnu/usr.bin/awk/NEWS
+++ b/gnu/usr.bin/awk/NEWS
@@ -1,5 +1,191 @@
+Changes from 2.15.4 to 2.15.5
+-----------------------------
+
+FUTURES file updated and re-arranged some with more rational schedule.
+
+Many prototypes handled better for ANSI C in protos.h.
+
+getopt.c updated somewhat.
+
+test/Makefile now removes junk directory, `bardargtest' renamed `badargs.'
+
+Bug fix in iop.c for RS = "". Eat trailing newlines off of record separator.
+
+Bug fix in Makefile.bsd44, use leading tab in actions.
+
+Fix in field.c:set_FS for FS == "\\" and IGNORECASE != 0.
+
+Config files updated or added:
+ cray60, DEC OSF/1 2.0, Utek, sgi405, next21, next30, atari/config.h,
+ sco.
+
+Fix in io.c for ENFILE as well as EMFILE, update decl of groupset to
+include OSF/1.
+
+Rationalized printing as integers if numbers are outside the range of a long.
+Changes to node.c:force_string and builtin.c.
+
+Made internal NF, NR, and FNR variables longs instead of ints.
+
+Add LIMITS_H_MISSING stuff to config.in and awk.h, and default defs for
+INT_MAX and LONG_MAX, if no limits.h file. Add a standard decl of
+the time() function for __STDC__. From ghazi@noc.rutgers.edu.
+
+Fix tree_eval in awk.h and r_tree_eval in eval.c to deal better with
+function parameters, particularly ones that are arrays.
+
+Fix eval.c to print out array names of arrays used in scalar contexts.
+
+Fix eval.c in interpret to zero out source and sourceline initially. This
+does a better job of providing source file and line number information.
+
+Fix to re_parse_field in field.c to not use isspace when RS = "", but rather
+to explicitly look for blank and tab.
+
+Fix to sc_parse_field in field.c to catch the case of the FS character at the
+end of a record.
+
+Lots of miscellanious bug fixes for memory leaks, courtesy Mark Moraes,
+also fixes for arrays.
+
+io.c fixed to warn about lack of explicit closes if --lint.
+
+Updated missing/strftime.c to match posted strftime 6.2.
+
+Bug fix in builtin.c, in case of non-match in sub_common.
+
+Updated constant used for division in builtin.c:do_rand for DEC Alpha
+and CRAY Y-MP.
+
+POSIXLY_CORRECT in the environment turns on --posix (fixed in main.c).
+
+Updated srandom prototype and calls in builtin.c.
+
+Fix awk.y to enforce posix semantics of unary +: result is numeric.
+
+Fix array.c to not rearrange the hash chain upon finding an index in
+the array. This messed things up in cases like:
+ for (index1 in array) {
+ blah
+ if (index2 in array) # blew away the for
+ stuff
+ }
+
+Fixed spelling errors in the man page.
+
+Fixes in awk.y so that
+ gawk '' /path/to/file
+will work without core dumping or finding parse errors.
+
+Fix main.c so that --lint will fuss about an empty program.
+Yet another fix for argument parsing in the case of unrecognized options.
+
+Bug fix in dfa.c to not attempt to free null pointers.
+
+Bug fix in builtin.c to only use DEFAULT_G_PRECISION for %g or %G.
+
+Bug fix in field.c to achieve call by value semantics for split.
+
+Changes from 2.15.3 to 2.15.4
+-----------------------------
+
+Lots of lint fixes, and do_sprintf made mostly ANSI C compatible.
+
+Man page updated and edited.
+
+Copyrights updated.
+
+Arrays now grow dynamically, initially scaling up by an order of magnitude
+ and then doubling, up to ~ 64K. This should keep gawk's performance
+ graceful under heavy load.
+
+New `delete array' feature added. Only documented in the man page.
+
+Switched to dfa and regex suites from grep-2.0. These offer the ability to
+ move to POSIX regexps in the next release.
+
+Disabled GNU regex ops.
+
+Research awk -m option now recognized. It does nothing in gawk, since gawk
+ has no static limits. Only documented in the man page.
+
+New bionic (faster, better, stronger than before) hashing function.
+
+Bug fix in argument handling. `gawk -X' now notices there was no program.
+ Additional bug fixes to make --compat and --lint work again.
+
+Many changes for systems where sizeof(int) != sizeof(void *).
+
+Add explicit alloca(0) in io.c to recover space from C alloca.
+
+Fixed file descriptor leak in io.c.
+
+The --version option now follows the GNU coding standards and exits.
+
+Fixed several prototypes in protos.h.
+
+Several tests updated. On Solaris, warn that the out? tests will fail.
+
+Configuration files for SunOS with cc and Solaris 2.x added.
+
+Improved error messages in awk.y on gawk extensions if do_unix or do_compat.
+
+INSTALL file added.
+
+Fixed Atari Makefile and several VMS specific changes.
+
+Better conversion of numbers to strings on systems with broken sprintfs.
+
+Changes from 2.15.2 to 2.15.3
+-----------------------------
+
+Increased HASHSIZE to a decent number, 127 was way too small.
+
+FILENAME is now the null string in a BEGIN rule.
+
+Argument processing fixed for invalid options and missing arguments.
+
+This version will build on VMS. This included a fix to close all files
+ and pipes opened with redirections before closing stdout and stderr.
+
+More getpgrp() defines.
+
+Changes for BSD44: <sys/param.h> in io.c and Makefile.bsd44.
+
+All directories in the distribution are now writable.
+
+Separated LDFLAGS and CFLAGS in Makefile. CFLAGS can now be overridden by
+ user.
+
+Make dist now builds compressed archives ending in .gz and runs doschk.
+
+Amiga port.
+
+New getopt.c fixes Alpha OSF/1 problem.
+
+Make clean now removes possible test output.
+
+Improved algorithm for multiple adjacent string concatenations leads to
+ performance improvements.
+
+Fix nasty bug whereby command-line assignments, both with -v and at run time,
+ could create variables with syntactically illegal names.
+
+Fix obscure bug in printf with %0 flag and filling.
+
+Add a lint check for substr if provided length exceeds remaining characters
+ in string.
+
+Update atari support.
+
+PC support enhanced to include support for both DOS and OS/2. (Lots more
+ #ifdefs. Sigh.)
+
+Config files for Hitachi Unix and OSF/1, courtesy of Yoko Morishita
+ (morisita@sra.co.jp)
+
Changes from 2.15.1 to 2.15.2
----------------------------
+-----------------------------
Additions to the FUTURES file.
@@ -11,7 +197,6 @@ Clean up the distribution generation in Makefile.in: the info files are
now included, the distributed files are marked read-only and patched
distributions are now unpacked in a directory named with the patch level.
-
Changes from 2.15 to 2.15.1
---------------------------
@@ -161,7 +346,7 @@ Added code to do better diagnoses of weird or null file names.
Allow continue outside of a loop, unless in strict posix mode. Lint option
will issue warning.
-New missing/strftime.c. There has been one chage that affects gawk. Posix
+New missing/strftime.c. There has been one change that affects gawk. Posix
now defines a %V conversion so the vms conversion has been changed to %v.
If this version is used with gawk -Wlint and they use %V in a call to
strftime, they'll get a warning.
@@ -189,7 +374,7 @@ Fixed a couple of bugs for reference to $0 when $0 is "" -- particularly in
Fixed premature freeing in construct "$0 = $0".
Removed the call to wait_any() in gawk_popen(), since on at least some systems,
- if gawk's input was from a pipe, the predecssor process in the pipe was a
+ if gawk's input was from a pipe, the predecessor process in the pipe was a
child of gawk and this caused a deadlock.
Regexp can (once again) match a newline, if given explicitly.
@@ -215,7 +400,7 @@ Fixed bug when NF is set by user -- fields_arr must be expanded if necessary
Fixed several bugs in [g]sub() for no match found or the match is 0-length.
-Fixed bug where in gsub() a pattern anchorred at the beginning would still
+Fixed bug where in gsub() a pattern anchored at the beginning would still
substitute throughout the string.
make test does not assume the . is in PATH.
@@ -235,7 +420,7 @@ Fixed hanging of pipe redirection to getline
Fixed coredump on access to $0 inside BEGIN block.
Fixed treatment of RS = "". It now parses the fields correctly and strips
- leading whitspace from a record if FS is a space.
+ leading whitespace from a record if FS is a space.
Fixed faking of /dev/stdin.
@@ -279,7 +464,7 @@ Update to config/bsd43.
Added config/apollo, config/msc60, config/cray2-50, config/interactive2.2
-sgi33.cc added for compilation using cc ratther than gcc.
+sgi33.cc added for compilation using cc rather than gcc.
Ultrix41 now propagates to config.h properly -- as part of a general
mechanism in configure for kludges -- #define anything from a config file
@@ -600,7 +785,7 @@ Fixed bug in output flushing introduced a few patches back. This caused
Changes from 2.12.22 to 2.12.23
-------------------------------
-Accidently left config/cray2-60 out of last patch.
+Accidentally left config/cray2-60 out of last patch.
Added some missing dependencies to Makefile.
@@ -750,7 +935,7 @@ Changes from 2.12.14 to 2.12.15
-------------------------------
Changed config/* to a condensed form that can be used with mkconf to generate
- a config.h from config.h-dist -- much easier to maintain. Please chaeck
+ a config.h from config.h-dist -- much easier to maintain. Please check
carefully against what you had before for a particular system and report
any problems. vms.h remains separate since the stuff at the bottom
didn't quite fit the mkconf model -- hopefully cleared up later.
@@ -1102,7 +1287,7 @@ Changes from 2.11beta to 2.11.1 (production)
Went from "beta" to production status!!!
Now flushes stdout before closing pipes or redirected files to
-synchonize output.
+synchronize output.
MS-DOS changes added in.
@@ -1217,7 +1402,7 @@ Cleaned up and fixed close_redir().
Fixed an obscure bug to do with redirection. Intermingled ">" and ">>"
redirects did not output in a predictable order.
-Improved handling of output bufferring: now all print[f]s redirected to a tty
+Improved handling of output buffering: now all print[f]s redirected to a tty
or pipe are flushed immediately and non-redirected output to a tty is flushed
before the next input record is read.
diff --git a/gnu/usr.bin/awk/PORTS b/gnu/usr.bin/awk/PORTS
index 95e133f9dd03..5087a4301af9 100644
--- a/gnu/usr.bin/awk/PORTS
+++ b/gnu/usr.bin/awk/PORTS
@@ -18,15 +18,18 @@ OpenVMS AXP V1.0
MSDOS - Microsoft C 5.1, compiles and runs very simple testing
BSD 4.4alpha
-From: ghazi@caip.rutgers.edu (Kaveh R. Ghazi):
+From: ghazi@noc.rutgers.edu (Kaveh R. Ghazi):
arch configured as:
---- --------------
+Dec Alpha OSF 1.3 osf1
Hpux 9.0 hpux8x
NeXTStep 2.0 next20
-Sgi Irix 4.0.5 (/bin/cc) sgi405.cc (new file)
+Sgi Irix 4.0.5 (/bin/cc) sgi405.cc
Stardent Titan 1500 OSv2.5 sysv3
Stardent Vistra (i860) SVR4 sysv4
-SunOS 4.1.2 sunos41
+Solaris 2.3 solaris2.cc
+SunOS 4.1.3 sunos41
Tektronix XD88 (UTekV 3.2e) sysv3
+Tektronix 4300 (UTek 4.0) utek
Ultrix 4.2 ultrix41
diff --git a/gnu/usr.bin/awk/PROBLEMS b/gnu/usr.bin/awk/PROBLEMS
index 3b7c5148bd8e..a43618002119 100644
--- a/gnu/usr.bin/awk/PROBLEMS
+++ b/gnu/usr.bin/awk/PROBLEMS
@@ -3,4 +3,8 @@ Hopefully they will all be fixed in the next major release of gawk.
Please keep in mind that the code is still undergoing significant evolution.
-1. Gawk's printf is probably still not POSIX compliant.
+1. The interactions with the lexer and yyerror need reworking. It is possible
+ to get line numbers that are one line off if --compat or --posix is
+ true and either `next file' or `delete array' are used.
+
+ Really the whole lexical analysis stuff needs reworking.
diff --git a/gnu/usr.bin/awk/README b/gnu/usr.bin/awk/README
index f4bd3df806c8..90ed9c29f63a 100644
--- a/gnu/usr.bin/awk/README
+++ b/gnu/usr.bin/awk/README
@@ -1,8 +1,7 @@
README:
-This is GNU Awk 2.15. It should be upwardly compatible with the
-System V Release 4 awk. It is almost completely compliant with draft 11.3
-of POSIX 1003.2.
+This is GNU Awk 2.15. It should be upwardly compatible with the System
+V Release 4 awk. It is almost completely compliant with POSIX 1003.2.
This release adds new features -- see NEWS for details.
@@ -10,7 +9,7 @@ See the installation instructions, below.
Known problems are given in the PROBLEMS file. Work to be done is
described briefly in the FUTURES file. Verified ports are listed in
-the PORTS file. Changes in this version are summarized in the CHANGES file.
+the PORTS file. Changes in this version are summarized in the NEWS file.
Please read the LIMITATIONS and ACKNOWLEDGMENT files.
Read the file POSIX for a discussion of how the standard says comparisons
@@ -28,6 +27,8 @@ INSTALLATION:
Check whether there is a system-specific README file for your system.
+A quick overview of the installation process is in the file INSTALL.
+
Makefile.in may need some tailoring. The only changes necessary should
be to change installation targets or to change compiler flags.
The changes to make in Makefile.in are commented and should be obvious.
@@ -54,10 +55,12 @@ proceed.
The next release will use the FSF autoconfig program, so we are no longer
soliciting new config files.
-If you have an MS-DOS system, use the stuff in the pc directory.
+If you have an MS-DOS or OS/2 system, use the stuff in the pc directory.
For an Atari there is an atari directory and similarly one for VMS.
Chapter 16 of The GAWK Manual discusses configuration in detail.
+(However, it does not discuss OS/2 configuration, see README.pc for
+the details. The manual is being massively revised for 2.16.)
After successful compilation, do 'make test' to run a small test
suite. There should be no output from the 'cmp' invocations except in
@@ -67,7 +70,7 @@ problem.
PRINTING THE MANUAL
-The 'support' directory contains texinfo.tex 2.65, which will be necessary
+The 'support' directory contains texinfo.tex 2.115, which will be necessary
for printing the manual, and the texindex.c program from the texinfo
distribution which is also necessary. See the makefile for the steps needed
to get a DVI file from the manual.
@@ -91,7 +94,7 @@ INTERNET: david@cs.dal.ca
Arnold Robbins
1736 Reindeer Drive
-Atlanta, GA, 30329, USA
+Atlanta, GA, 30329-3528, USA
INTERNET: arnold@skeeve.atl.ga.us
UUCP: { gatech, emory, emoryu1 }!skeeve!arnold
@@ -113,4 +116,10 @@ VMS:
Atari ST:
Michal Jaegermann
- NTOMCZAK@vm.ucs.UAlberta.CA (e-mail only)
+ michal@gortel.phys.ualberta.ca (e-mail only)
+
+OS/2:
+ Kai Uwe Rommel
+ rommel@ars.muc.de (e-mail only)
+ Darrel Hankerson
+ hankedr@mail.auburn.edu (e-mail only)
diff --git a/gnu/usr.bin/awk/array.c b/gnu/usr.bin/awk/array.c
index 59be340c04df..d42f9a6c5847 100644
--- a/gnu/usr.bin/awk/array.c
+++ b/gnu/usr.bin/awk/array.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -23,9 +23,24 @@
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * Tree walks (``for (iggy in foo)'') and array deletions use expensive
+ * linear searching. So what we do is start out with small arrays and
+ * grow them as needed, so that our arrays are hopefully small enough,
+ * most of the time, that they're pretty full and we're not looking at
+ * wasted space.
+ *
+ * The decision is made to grow the array if the average chain length is
+ * ``too big''. This is defined as the total number of entries in the table
+ * divided by the size of the array being greater than some constant.
+ */
+
+#define AVG_CHAIN_MAX 10 /* don't want to linear search more than this */
+
#include "awk.h"
static NODE *assoc_find P((NODE *symbol, NODE *subs, int hash1));
+static void grow_table P((NODE *symbol));
NODE *
concat_exp(tree)
@@ -34,9 +49,9 @@ register NODE *tree;
register NODE *r;
char *str;
char *s;
- unsigned len;
+ size_t len;
int offset;
- int subseplen;
+ size_t subseplen;
char *subsep;
if (tree->type != Node_expression_list)
@@ -84,7 +99,7 @@ NODE *symbol;
if (symbol->var_array == 0)
return;
- for (i = 0; i < HASHSIZE; i++) {
+ for (i = 0; i < symbol->array_size; i++) {
for (bucket = symbol->var_array[i]; bucket; bucket = next) {
next = bucket->ahnext;
unref(bucket->ahname);
@@ -93,17 +108,26 @@ NODE *symbol;
}
symbol->var_array[i] = 0;
}
+ free(symbol->var_array);
+ symbol->var_array = NULL;
+ symbol->array_size = symbol->table_size = 0;
+ symbol->flags &= ~ARRAYMAXED;
}
/*
* calculate the hash function of the string in subs
*/
unsigned int
-hash(s, len)
-register char *s;
-register int len;
+hash(s, len, hsize)
+register const char *s;
+register size_t len;
+unsigned long hsize;
{
- register unsigned long h = 0, g;
+ register unsigned long h = 0;
+
+#ifdef this_is_really_slow
+
+ register unsigned long g;
while (len--) {
h = (h << 4) + *s++;
@@ -113,10 +137,84 @@ register int len;
h = h ^ g;
}
}
- if (h < HASHSIZE)
- return h;
- else
- return h%HASHSIZE;
+
+#else /* this_is_really_slow */
+/*
+ * This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
+ * units. On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * OZ's original sdbm hash, copied from Margo Seltzers db package.
+ *
+ */
+
+/* Even more speed: */
+/* #define HASHC h = *s++ + 65599 * h */
+/* Because 65599 = pow(2,6) + pow(2,16) - 1 we multiply by shifts */
+#define HASHC htmp = (h << 6); \
+ h = *s++ + htmp + (htmp << 10) - h
+
+ unsigned long htmp;
+
+ h = 0;
+
+#if defined(VAXC)
+/*
+ * [This was an implementation of "Duff's Device", but it has been
+ * redone, separating the switch for extra iterations from the loop.
+ * This is necessary because the DEC VAX-C compiler is STOOPID.]
+ */
+ switch (len & (8 - 1)) {
+ case 7: HASHC;
+ case 6: HASHC;
+ case 5: HASHC;
+ case 4: HASHC;
+ case 3: HASHC;
+ case 2: HASHC;
+ case 1: HASHC;
+ default: break;
+ }
+
+ if (len > (8 - 1)) {
+ register size_t loop = len >> 3;
+ do {
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ } while (--loop);
+ }
+#else /* !VAXC */
+ /* "Duff's Device" for those who can handle it */
+ if (len > 0) {
+ register size_t loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do { /* All fall throughs */
+ HASHC;
+ case 7: HASHC;
+ case 6: HASHC;
+ case 5: HASHC;
+ case 4: HASHC;
+ case 3: HASHC;
+ case 2: HASHC;
+ case 1: HASHC;
+ } while (--loop);
+ }
+ }
+#endif /* !VAXC */
+#endif /* this_is_really_slow - not */
+
+ if (h >= hsize)
+ h %= hsize;
+ return h;
}
/*
@@ -132,11 +230,19 @@ int hash1;
for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) {
if (cmp_nodes(bucket->ahname, subs) == 0) {
+#if 0
+ /*
+ * Disable this code for now. It screws things up if we have
+ * a ``for (iggy in foo)'' in progress. Interestingly enough,
+ * this was not a problem in 2.15.3, only in 2.15.4. I'm not
+ * sure why it works in 2.15.3.
+ */
if (prev) { /* move found to front of chain */
prev->ahnext = bucket->ahnext;
bucket->ahnext = symbol->var_array[hash1];
symbol->var_array[hash1] = bucket;
}
+#endif
return bucket;
} else
prev = bucket; /* save previous list entry */
@@ -158,7 +264,7 @@ NODE *symbol, *subs;
if (symbol->var_array == 0)
return 0;
subs = concat_exp(subs); /* concat_exp returns a string node */
- hash1 = hash(subs->stptr, subs->stlen);
+ hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size);
if (assoc_find(symbol, subs, hash1) == NULL) {
free_temp(subs);
return 0;
@@ -183,17 +289,17 @@ NODE *symbol, *subs;
register NODE *bucket;
(void) force_string(subs);
- hash1 = hash(subs->stptr, subs->stlen);
-
- if (symbol->var_array == 0) { /* this table really should grow
- * dynamically */
- unsigned size;
- size = sizeof(NODE *) * HASHSIZE;
- emalloc(symbol->var_array, NODE **, size, "assoc_lookup");
- memset((char *)symbol->var_array, 0, size);
+ if (symbol->var_array == 0) {
symbol->type = Node_var_array;
+ symbol->array_size = symbol->table_size = 0; /* sanity */
+ symbol->flags &= ~ARRAYMAXED;
+ grow_table(symbol);
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
} else {
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
bucket = assoc_find(symbol, subs, hash1);
if (bucket != NULL) {
free_temp(subs);
@@ -205,6 +311,17 @@ NODE *symbol, *subs;
if (do_lint && subs->stlen == 0)
warning("subscript of array `%s' is null string",
symbol->vname);
+
+ /* first see if we would need to grow the array, before installing */
+ symbol->table_size++;
+ if ((symbol->flags & ARRAYMAXED) == 0
+ && symbol->table_size/symbol->array_size > AVG_CHAIN_MAX) {
+ grow_table(symbol);
+ /* have to recompute hash value for new size */
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
+ }
+
getnode(bucket);
bucket->type = Node_ahash;
if (subs->flags & TEMP)
@@ -240,7 +357,7 @@ NODE *symbol, *tree;
if (symbol->var_array == 0)
return;
subs = concat_exp(tree); /* concat_exp returns string node */
- hash1 = hash(subs->stptr, subs->stlen);
+ hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size);
last = NULL;
for (bucket = symbol->var_array[hash1]; bucket; last = bucket, bucket = bucket->ahnext)
@@ -256,6 +373,15 @@ NODE *symbol, *tree;
unref(bucket->ahname);
unref(bucket->ahvalue);
freenode(bucket);
+ symbol->table_size--;
+ if (symbol->table_size <= 0) {
+ memset(symbol->var_array, '\0',
+ sizeof(NODE *) * symbol->array_size);
+ symbol->table_size = symbol->array_size = 0;
+ symbol->flags &= ~ARRAYMAXED;
+ free((char *) symbol->var_array);
+ symbol->var_array = NULL;
+ }
}
void
@@ -263,31 +389,127 @@ assoc_scan(symbol, lookat)
NODE *symbol;
struct search *lookat;
{
- if (!symbol->var_array) {
- lookat->retval = NULL;
- return;
- }
- lookat->arr_ptr = symbol->var_array;
- lookat->arr_end = lookat->arr_ptr + HASHSIZE; /* added */
- lookat->bucket = symbol->var_array[0];
- assoc_next(lookat);
+ lookat->sym = symbol;
+ lookat->idx = 0;
+ lookat->bucket = NULL;
+ lookat->retval = NULL;
+ if (symbol->var_array != NULL)
+ assoc_next(lookat);
}
void
assoc_next(lookat)
struct search *lookat;
{
- while (lookat->arr_ptr < lookat->arr_end) {
- if (lookat->bucket != 0) {
- lookat->retval = lookat->bucket->ahname;
- lookat->bucket = lookat->bucket->ahnext;
+ register NODE *symbol = lookat->sym;
+
+ if (symbol == NULL)
+ fatal("null symbol in assoc_next");
+ if (symbol->var_array == NULL || lookat->idx > symbol->array_size) {
+ lookat->retval = NULL;
+ return;
+ }
+ /*
+ * This is theoretically unsafe. The element bucket might have
+ * been freed if the body of the scan did a delete on the next
+ * element of the bucket. The only way to do that is by array
+ * reference, which is unlikely. Basically, if the user is doing
+ * anything other than an operation on the current element of an
+ * assoc array while walking through it sequentially, all bets are
+ * off. (The safe way is to register all search structs on an
+ * array with the array, and update all of them on a delete or
+ * insert)
+ */
+ if (lookat->bucket != NULL) {
+ lookat->retval = lookat->bucket->ahname;
+ lookat->bucket = lookat->bucket->ahnext;
+ return;
+ }
+ for (; lookat->idx < symbol->array_size; lookat->idx++) {
+ NODE *bucket;
+
+ if ((bucket = symbol->var_array[lookat->idx]) != NULL) {
+ lookat->retval = bucket->ahname;
+ lookat->bucket = bucket->ahnext;
+ lookat->idx++;
return;
}
- lookat->arr_ptr++;
- if (lookat->arr_ptr < lookat->arr_end)
- lookat->bucket = *(lookat->arr_ptr);
- else
- lookat->retval = NULL;
}
+ lookat->retval = NULL;
+ lookat->bucket = NULL;
return;
}
+
+/* grow_table --- grow a hash table */
+
+static void
+grow_table(symbol)
+NODE *symbol;
+{
+ NODE **old, **new, *chain, *next;
+ int i, j;
+ unsigned long hash1;
+ unsigned long oldsize, newsize;
+ /*
+ * This is an array of primes. We grow the table by an order of
+ * magnitude each time (not just doubling) so that growing is a
+ * rare operation. We expect, on average, that it won't happen
+ * more than twice. The final size is also chosen to be small
+ * enough so that MS-DOG mallocs can handle it. When things are
+ * very large (> 8K), we just double more or less, instead of
+ * just jumping from 8K to 64K.
+ */
+ static long sizes[] = { 13, 127, 1021, 8191, 16381, 32749, 65497 };
+
+ /* find next biggest hash size */
+ oldsize = symbol->array_size;
+ newsize = 0;
+ for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
+ if (oldsize < sizes[i]) {
+ newsize = sizes[i];
+ break;
+ }
+ }
+
+ if (newsize == oldsize) { /* table already at max (!) */
+ symbol->flags |= ARRAYMAXED;
+ return;
+ }
+
+ /* allocate new table */
+ emalloc(new, NODE **, newsize * sizeof(NODE *), "grow_table");
+ memset(new, '\0', newsize * sizeof(NODE *));
+
+ /* brand new hash table, set things up and return */
+ if (symbol->var_array == NULL) {
+ symbol->table_size = 0;
+ goto done;
+ }
+
+ /* old hash table there, move stuff to new, free old */
+ old = symbol->var_array;
+ for (i = 0; i < oldsize; i++) {
+ if (old[i] == NULL)
+ continue;
+
+ for (chain = old[i]; chain != NULL; chain = next) {
+ next = chain->ahnext;
+ hash1 = hash(chain->ahname->stptr,
+ chain->ahname->stlen, newsize);
+
+ /* remove from old list, add to new */
+ chain->ahnext = new[hash1];
+ new[hash1] = chain;
+
+ }
+ }
+ free(old);
+
+done:
+ /*
+ * note that symbol->table_size does not change if an old array,
+ * and is explicitly set to 0 if a new one.
+ */
+ symbol->var_array = new;
+ symbol->array_size = newsize;
+}
diff --git a/gnu/usr.bin/awk/awk.1 b/gnu/usr.bin/awk/awk.1
index 0338485e8db8..a98c99d1608b 100644
--- a/gnu/usr.bin/awk/awk.1
+++ b/gnu/usr.bin/awk/awk.1
@@ -1,7 +1,7 @@
.ds PX \s-1POSIX\s+1
.ds UX \s-1UNIX\s+1
.ds AN \s-1ANSI\s+1
-.TH GAWK 1 "Apr 15 1993" "Free Software Foundation" "Utility Commands"
+.TH GAWK 1 "Apr 18 1994" "Free Software Foundation" "Utility Commands"
.SH NAME
gawk \- pattern scanning and processing language
.SH SYNOPSIS
@@ -71,6 +71,11 @@ option.
Each
.B \-W
option has a corresponding GNU style long option, as detailed below.
+Arguments to GNU style long options are either joined with the option
+by an
+.B =
+sign, with no intervening spaces, or they may be provided in the
+next command line argument.
.PP
.I Gawk
accepts the following options.
@@ -114,6 +119,26 @@ Multiple
(or
.BR \-\^\-file )
options may be used.
+.TP
+.PD 0
+.BI \-mf= NNN
+.TP
+.BI \-mr= NNN
+Set various memory limits to the value
+.IR NNN .
+The
+.B f
+flag sets the maximum number of fields, and the
+.B r
+flag sets the maximum record size. These two flags and the
+.B \-m
+option are from the AT&T Bell Labs research version of \*(UX
+.IR awk .
+They are ignored by
+.IR gawk ,
+since
+.I gawk
+has no pre-defined limits.
.TP \w'\fB\-\^\-copyright\fR'u+1n
.PD 0
.B "\-W compat"
@@ -158,6 +183,8 @@ the error output.
.B \-\^\-usage
Print a relatively short summary of the available options on
the error output.
+Per the GNU Coding Standards, these options cause an immediate,
+successful exit.
.TP
.PD 0
.B "\-W lint"
@@ -248,6 +275,8 @@ This is useful mainly for knowing if the current copy of
on your system
is up to date with respect to whatever the Free Software Foundation
is distributing.
+Per the GNU Coding Standards, these options cause an immediate,
+successful exit.
.TP
.B \-\^\-
Signal the end of options. This is useful to allow further arguments to the
@@ -255,7 +284,13 @@ AWK program itself to start with a ``\-''.
This is mainly for consistency with the argument parsing convention used
by most other \*(PX programs.
.PP
-Any other options are flagged as illegal, but are otherwise ignored.
+In compatibility mode,
+any other options are flagged as illegal, but are otherwise ignored.
+In normal operation, as long as program text has been supplied, unknown
+options are passed on to the AWK program in the
+.B ARGV
+array for processing. This is particularly useful for running AWK
+programs via the ``#!'' executable interpreter mechanism.
.SH AWK PROGRAM EXECUTION
.PP
An AWK program consists of a sequence of pattern-action statements
@@ -270,23 +305,23 @@ and optional function definitions.
.I Gawk
first reads the program source from the
.IR program-file (s)
-if specified, or from the first non-option argument on the command line.
+if specified,
+from arguments to
+.BR "\-W source=" ,
+or from the first non-option argument on the command line.
The
.B \-f
-option may be used multiple times on the command line.
+and
+.B "\-W source="
+options may be used multiple times on the command line.
.I Gawk
will read the program text as if all the
.IR program-file s
+and command line source texts
had been concatenated together. This is useful for building libraries
of AWK functions, without having to include them in each new AWK
-program that uses them. To use a library function in a file from a
-program typed in on the command line, specify
-.B /dev/tty
-as one of the
-.IR program-file s,
-type your program, and end it with a
-.B ^D
-(control-d).
+program that uses them. It also provides the ability to mix library
+functions with command line programs.
.PP
The environment variable
.B AWKPATH
@@ -302,11 +337,13 @@ option contains a ``/'' character, no path search is performed.
.I Gawk
executes AWK programs in the following order.
First,
+all variable assignments specified via the
+.B \-v
+option are performed.
+Next,
.I gawk
compiles the program into an internal form.
-Next, all variable assignments specified via the
-.B \-v
-option are performed. Then,
+Then,
.I gawk
executes the code in the
.B BEGIN
@@ -359,8 +396,8 @@ block(s) (if any).
AWK variables are dynamic; they come into existence when they are
first used. Their values are either floating-point numbers or strings,
or both,
-depending upon how they are used. AWK also has one dimension
-arrays; multiply dimensioned arrays may be simulated.
+depending upon how they are used. AWK also has one dimensional
+arrays; arrays with multiple dimensions may be simulated.
Several pre-defined variables are set as a program
runs; these will be described as needed and summarized below.
.SS Fields
@@ -435,6 +472,7 @@ cause the value of
.B $0
to be recomputed, with the fields being separated by the value of
.BR OFS .
+References to negative numbered fields cause a fatal error.
.SS Built-in Variables
.PP
AWK's built-in variables are:
@@ -482,7 +520,7 @@ If a system error occurs either doing a redirection for
during a read for
.BR getline ,
or during a
-.BR close ,
+.BR close() ,
then
.B ERRNO
will contain
@@ -505,6 +543,11 @@ The name of the current input file.
If no files are specified on the command line, the value of
.B FILENAME
is ``\-''.
+However,
+.B FILENAME
+is undefined inside the
+.B BEGIN
+block.
.TP
.B FNR
The input record number in the current input file.
@@ -644,6 +687,9 @@ loop to iterate over all the elements of an array.
An element may be deleted from an array using the
.B delete
statement.
+The
+.B delete
+statement may also be used to delete the entire contents of an array.
.SS Variable Typing And Conversion
.PP
Variables and fields
@@ -680,7 +726,7 @@ b = a ""
.PP
the variable
.B b
-has a value of \fB"12"\fR and not \fB"12.00"\fR.
+has a string value of \fB"12"\fR and not \fB"12.00"\fR.
.PP
.I Gawk
performs comparisons as follows:
@@ -809,7 +855,8 @@ the third. Only one of the second and third patterns is evaluated.
.PP
The
.IB pattern1 ", " pattern2
-form of an expression is called a range pattern.
+form of an expression is called a
+.IR "range pattern" .
It matches all input records starting with a line that matches
.IR pattern1 ,
and continuing until a record that matches
@@ -982,6 +1029,7 @@ as follows:
\fBbreak\fR
\fBcontinue\fR
\fBdelete \fIarray\^\fB[\^\fIindex\^\fB]\fR
+\fBdelete \fIarray\^\fR
\fBexit\fR [ \fIexpression\fR ]
\fB{ \fIstatements \fB}
.fi
@@ -1046,10 +1094,20 @@ Prints the current record.
.TP
.BI print " expr-list"
Prints expressions.
+Each expression is separated by the value of the
+.B OFS
+variable. The output record is terminated with the value of the
+.B ORS
+variable.
.TP
.BI print " expr-list" " >" file
Prints expressions on
.IR file .
+Each expression is separated by the value of the
+.B OFS
+variable. The output record is terminated with the value of the
+.B ORS
+variable.
.TP
.BI printf " fmt, expr-list"
Format and print.
@@ -1078,8 +1136,9 @@ In a similar fashion,
.IB command " | getline"
pipes into
.BR getline .
-.BR Getline
-will return 0 on end of file, and \-1 on an error.
+The
+.BR getline
+command will return 0 on end of file, and \-1 on an error.
.SS The \fIprintf\fP\^ Statement
.PP
The AWK versions of the
@@ -1153,6 +1212,7 @@ The expression should be left-justified within its field.
The field should be padded to this width. If the number has a leading
zero, then the field will be padded with zeros.
Otherwise it is padded with blanks.
+This applies even to the non-numeric output formats.
.TP
.BI . prec
A number indicating the maximum width of strings or digits to the right
@@ -1229,7 +1289,7 @@ is the value of the
system call.
If there are any additional fields, they are the group IDs returned by
.IR getgroups (2).
-(Multiple groups may not be supported on all systems.)
+Multiple groups may not be supported on all systems.
.TP
.B /dev/stdin
The standard input.
@@ -1360,6 +1420,9 @@ and returns the number of fields. If
is omitted,
.B FS
is used instead.
+The array
+.I a
+is cleared first.
.TP
.BI sprintf( fmt , " expr-list" )
prints
@@ -1477,11 +1540,11 @@ the
As in \*(AN C, all following hexadecimal digits are considered part of
the escape sequence.
(This feature should tell us something about language design by committee.)
-E.g., "\ex1B" is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
+E.g., \fB"\ex1B"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
.TP
.BI \e ddd
The character represented by the 1-, 2-, or 3-digit sequence of octal
-digits. E.g. "\e033" is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
+digits. E.g. \fB"\e033"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
.TP
.BI \e c
The literal character
@@ -1562,7 +1625,15 @@ Concatenate and line number (a variation on a theme):
.ft R
.fi
.SH SEE ALSO
-.IR egrep (1)
+.IR egrep (1),
+.IR getpid (2),
+.IR getppid (2),
+.IR getpgrp (2),
+.IR getuid (2),
+.IR geteuid (2),
+.IR getgid (2),
+.IR getegid (2),
+.IR getgroups (2)
.PP
.IR "The AWK Programming Language" ,
Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger,
@@ -1600,7 +1671,7 @@ block was run. Applications came to depend on this ``feature.''
When
.I awk
was changed to match its documentation, this option was added to
-accomodate applications that depended upon the old behavior.
+accommodate applications that depended upon the old behavior.
(This feature was agreed upon by both the AT&T and GNU developers.)
.PP
The
@@ -1610,7 +1681,11 @@ option for implementation specific features is from the \*(PX standard.
When processing arguments,
.I gawk
uses the special option ``\fB\-\^\-\fP'' to signal the end of
-arguments, and warns about, but otherwise ignores, undefined options.
+arguments.
+In compatibility mode, it will warn about, but otherwise ignore,
+undefined options.
+In normal operation, such arguments are passed on to the AWK program for
+it to process.
.PP
The AWK book does not define the return value of
.BR srand() .
@@ -1706,6 +1781,11 @@ environment variable is not special.
The use of
.B "next file"
to abandon processing of the current input file.
+.TP
+\(bu
+The use of
+.BI delete " array"
+to delete the entire contents of an array.
.RE
.PP
The AWK book does not define the return value of the
@@ -1733,7 +1813,7 @@ option is ``t'', then
will be set to the tab character.
Since this is a rather ugly special case, it is not the default behavior.
This behavior also does not occur if
-.B \-Wposix
+.B "\-W posix"
has been specified.
.ig
.PP
@@ -1785,7 +1865,7 @@ a = length($0)
This feature is marked as ``deprecated'' in the \*(PX standard, and
.I gawk
will issue a warning about its use if
-.B \-Wlint
+.B "\-W lint"
is specified on the command line.
.PP
The other feature is the use of the
@@ -1801,8 +1881,21 @@ equivalent to the
statement.
.I Gawk
will support this usage if
-.B \-Wposix
+.B "\-W posix"
has not been specified.
+.SH ENVIRONMENT VARIABLES
+If
+.B POSIXLY_CORRECT
+exists in the environment, then
+.I gawk
+behaves exactly as if
+.B \-\-posix
+had been specified on the command line.
+If
+.B \-\-lint
+has been specified,
+.I gawk
+will issue a warning message to this effect.
.SH BUGS
The
.B \-F
@@ -1844,6 +1937,7 @@ the
and
.B \-e
options of the 2.11 version are no longer recognized.
+This fact will not even be documented in the manual page for version 2.16.
.SH AUTHORS
The original version of \*(UX
.I awk
@@ -1867,6 +1961,8 @@ compatible with the new version of \*(UX
The initial DOS port was done by Conrad Kwok and Scott Garfinkle.
Scott Deifik is the current DOS maintainer. Pat Rankin did the
port to VMS, and Michal Jaegermann did the port to the Atari ST.
+The port to OS/2 was done by Kai Uwe Rommel, with contributions and
+help from Darrel Hankerson.
.SH ACKNOWLEDGEMENTS
Brian Kernighan of Bell Labs
provided valuable assistance during testing and debugging.
diff --git a/gnu/usr.bin/awk/awk.h b/gnu/usr.bin/awk/awk.h
index ca3997f11d4b..066bf444f9f3 100644
--- a/gnu/usr.bin/awk/awk.h
+++ b/gnu/usr.bin/awk/awk.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -24,14 +24,18 @@
*/
/* ------------------------------ Includes ------------------------------ */
+#include "config.h"
+
#include <stdio.h>
+#ifndef LIMITS_H_MISSING
#include <limits.h>
+#endif
#include <ctype.h>
#include <setjmp.h>
#include <varargs.h>
#include <time.h>
#include <errno.h>
-#if !defined(errno) && !defined(MSDOS)
+#if !defined(errno) && !defined(MSDOS) && !defined(OS2)
extern int errno;
#endif
#ifdef __GNU_LIBRARY__
@@ -42,6 +46,10 @@ extern int errno;
/* ----------------- System dependencies (with more includes) -----------*/
+#if defined(__FreeBSD__)
+# include <floatingpoint.h>
+#endif
+
#if !defined(VMS) || (!defined(VAXC) && !defined(__DECC))
#include <sys/types.h>
#include <sys/stat.h>
@@ -53,8 +61,6 @@ extern int errno;
#include <signal.h>
-#include "config.h"
-
#ifdef __STDC__
#define P(s) s
#define MALLOC_ARG_T size_t
@@ -88,7 +94,7 @@ typedef unsigned int size_t;
#if defined(atarist) || defined(VMS)
#include <unixlib.h>
#else /* atarist || VMS */
-#ifndef MSDOS
+#if !defined(MSDOS) && !defined(_MSC_VER)
#include <unistd.h>
#endif /* MSDOS */
#endif /* atarist || VMS */
@@ -111,7 +117,11 @@ extern char *alloca();
#endif
#else /* not sparc */
#if !defined(alloca) && !defined(ALLOCA_PROTO)
+#if defined(_MSC_VER)
+#include <malloc.h>
+#else
extern char *alloca();
+#endif /* _MSC_VER */
#endif
#endif /* sparc */
#endif /* __GNUC__ */
@@ -150,7 +160,7 @@ extern FILE *popen P((const char *,const char *));
extern int pclose P((FILE *));
extern void vms_arg_fixup P((int *,char ***));
/* some things not in STDC_HEADERS */
-extern int gnu_strftime P((char *,size_t,const char *,const struct tm *));
+extern size_t gnu_strftime P((char *,size_t,const char *,const struct tm *));
extern int unlink P((const char *));
extern int getopt P((int,char **,char *));
extern int isatty P((int));
@@ -158,14 +168,9 @@ extern int isatty P((int));
extern int fileno P((FILE *));
#endif
extern int close(), dup(), dup2(), fstat(), read(), stat();
+extern int getpgrp P((void));
#endif /*VMS*/
-#ifdef MSDOS
-#include <io.h>
-extern FILE *popen P((char *, char *));
-extern int pclose P((FILE *));
-#endif
-
#define GNU_REGEX
#ifdef GNU_REGEX
#include "regex.h"
@@ -173,7 +178,7 @@ extern int pclose P((FILE *));
typedef struct Regexp {
struct re_pattern_buffer pat;
struct re_registers regs;
- struct regexp dfareg;
+ struct dfa dfareg;
int dfa;
} Regexp;
#define RESTART(rp,s) (rp)->regs.start[0]
@@ -184,6 +189,9 @@ typedef struct Regexp {
#ifdef atarist
#define read _text_read /* we do not want all these CR's to mess our input */
extern int _text_read (int, char *, int);
+#ifndef __MINT__
+#undef NGROUPS_MAX
+#endif /* __MINT__ */
#endif
#ifndef DEFPATH
@@ -194,6 +202,8 @@ extern int _text_read (int, char *, int);
#define ENVSEP ':'
#endif
+extern double double_to_int P((double d));
+
/* ------------------ Constants, Structures, Typedefs ------------------ */
#define AWKNUM double
@@ -331,6 +341,7 @@ typedef struct exp_node {
union {
struct exp_node *lptr;
char *param_name;
+ long ll;
} l;
union {
struct exp_node *rptr;
@@ -343,6 +354,7 @@ typedef struct exp_node {
union {
char *name;
struct exp_node *extra;
+ long xl;
} x;
short number;
unsigned char reflags;
@@ -362,7 +374,7 @@ typedef struct exp_node {
struct {
struct exp_node *next;
char *name;
- int length;
+ size_t length;
struct exp_node *value;
} hash;
#define hnext sub.hash.next
@@ -388,8 +400,8 @@ typedef struct exp_node {
# define NUM 32 /* numeric value is current */
# define NUMBER 64 /* assigned as number */
# define MAYBE_NUM 128 /* user input: if NUMERIC then
- * a NUMBER
- */
+ * a NUMBER */
+# define ARRAYMAXED 256 /* array is at max size */
char *vname; /* variable's name */
} NODE;
@@ -422,6 +434,8 @@ typedef struct exp_node {
#define var_value lnode
#define var_array sub.nodep.r.av
+#define array_size sub.nodep.l.ll
+#define table_size sub.nodep.x.xl
#define condpair lnode
#define triggered sub.nodep.r.r_ent
@@ -429,8 +443,6 @@ typedef struct exp_node {
#ifdef DONTDEF
int primes[] = {31, 61, 127, 257, 509, 1021, 2053, 4099, 8191, 16381};
#endif
-/* a quick profile suggests that the following is a good value */
-#define HASHSIZE 127
typedef struct for_loop_header {
NODE *init;
@@ -440,8 +452,8 @@ typedef struct for_loop_header {
/* for "for(iggy in foo) {" */
struct search {
- NODE **arr_ptr;
- NODE **arr_end;
+ NODE *sym;
+ size_t idx;
NODE *bucket;
NODE *retval;
};
@@ -499,13 +511,25 @@ struct src {
/* Return means return from a function call; leave value in ret_node */
#define TAG_RETURN 3
+#ifndef INT_MAX
+#define INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
+#endif
+#ifndef LONG_MAX
+#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
+#endif
+#ifndef ULONG_MAX
+#define ULONG_MAX (~(unsigned long)0)
+#endif
+#ifndef LONG_MIN
+#define LONG_MIN (-LONG_MAX - 1)
+#endif
#define HUGE INT_MAX
/* -------------------------- External variables -------------------------- */
/* gawk builtin variables */
-extern int NF;
-extern int NR;
-extern int FNR;
+extern long NF;
+extern long NR;
+extern long FNR;
extern int IGNORECASE;
extern char *RS;
extern char *OFS;
@@ -558,17 +582,20 @@ extern int in_end_rule;
#ifdef DEBUG
#define tree_eval(t) r_tree_eval(t)
+#define get_lhs(p, a) r_get_lhs((p), (a))
+#undef freenode
#else
-#define tree_eval(t) (_t = (t),(_t) == NULL ? Nnull_string : \
- ((_t)->type == Node_val ? (_t) : \
- ((_t)->type == Node_var ? (_t)->var_value : \
- ((_t)->type == Node_param_list ? \
- (stack_ptr[(_t)->param_cnt])->var_value : \
- r_tree_eval((_t))))))
+#define get_lhs(p, a) ((p)->type == Node_var ? (&(p)->var_value) : \
+ r_get_lhs((p), (a)))
+#define tree_eval(t) (_t = (t),_t == NULL ? Nnull_string : \
+ (_t->type == Node_param_list ? r_tree_eval(_t) : \
+ (_t->type == Node_val ? _t : \
+ (_t->type == Node_var ? _t->var_value : \
+ r_tree_eval(_t)))))
#endif
-#define make_number(x) mk_number((x), (MALLOC|NUM|NUMBER))
-#define tmp_number(x) mk_number((x), (MALLOC|TEMP|NUM|NUMBER))
+#define make_number(x) mk_number((x), (unsigned int)(MALLOC|NUM|NUMBER))
+#define tmp_number(x) mk_number((x), (unsigned int)(MALLOC|TEMP|NUM|NUMBER))
#define free_temp(n) do {if ((n)->flags&TEMP) { unref(n); }} while (0)
#define make_string(s,l) make_str_node((s), SZTC (l),0)
@@ -620,7 +647,7 @@ extern double _msc51bug;
/* array.c */
extern NODE *concat_exp P((NODE *tree));
extern void assoc_clear P((NODE *symbol));
-extern unsigned int hash P((char *s, int len));
+extern unsigned int hash P((const char *s, size_t len, unsigned long hsize));
extern int in_array P((NODE *symbol, NODE *subs));
extern NODE **assoc_lookup P((NODE *symbol, NODE *subs));
extern void do_delete P((NODE *symbol, NODE *tree));
@@ -631,7 +658,7 @@ extern char *tokexpand P((void));
extern char nextc P((void));
extern NODE *node P((NODE *left, NODETYPE op, NODE *right));
extern NODE *install P((char *name, NODE *value));
-extern NODE *lookup P((char *name));
+extern NODE *lookup P((const char *name));
extern NODE *variable P((char *name, int can_free));
extern int yyparse P((void));
/* builtin.c */
@@ -663,7 +690,7 @@ extern NODE *do_sub P((NODE *tree));
extern int interpret P((NODE *volatile tree));
extern NODE *r_tree_eval P((NODE *tree));
extern int cmp_nodes P((NODE *t1, NODE *t2));
-extern NODE **get_lhs P((NODE *ptr, Func_ptr *assign));
+extern NODE **r_get_lhs P((NODE *ptr, Func_ptr *assign));
extern void set_IGNORECASE P((void));
void set_OFS P((void));
void set_ORS P((void));
@@ -687,8 +714,8 @@ extern struct redirect *redirect P((NODE *tree, int *errflg));
extern NODE *do_close P((NODE *tree));
extern int flush_io P((void));
extern int close_io P((void));
-extern int devopen P((char *name, char *mode));
-extern int pathopen P((char *file));
+extern int devopen P((const char *name, const char *mode));
+extern int pathopen P((const char *file));
extern NODE *do_getline P((NODE *tree));
extern void do_nextfile P((void));
/* iop.c */
@@ -702,13 +729,12 @@ extern void load_environ P((void));
extern char *arg_assign P((char *arg));
extern SIGTYPE catchsig P((int sig, int code));
/* msg.c */
-#ifdef MSDOS
-extern void err P((char *s, char *emsg, char *va_list, ...));
-extern void msg P((char *va_alist, ...));
-extern void warning P((char *va_alist, ...));
-extern void fatal P((char *va_alist, ...));
+extern void err P((const char *s, const char *emsg, va_list argp));
+#if _MSC_VER == 510
+extern void msg P((va_list va_alist, ...));
+extern void warning P((va_list va_alist, ...));
+extern void fatal P((va_list va_alist, ...));
#else
-extern void err ();
extern void msg ();
extern void warning ();
extern void fatal ();
@@ -727,8 +753,9 @@ extern void freenode P((NODE *it));
extern void unref P((NODE *tmp));
extern int parse_escape P((char **string_ptr));
/* re.c */
-extern Regexp *make_regexp P((char *s, int len, int ignorecase, int dfa));
-extern int research P((Regexp *rp, char *str, int start, int len, int need_start));
+extern Regexp *make_regexp P((char *s, size_t len, int ignorecase, int dfa));
+extern int research P((Regexp *rp, char *str, int start,
+ size_t len, int need_start));
extern void refree P((Regexp *rp));
extern void reg_error P((const char *s));
extern Regexp *re_update P((NODE *t));
diff --git a/gnu/usr.bin/awk/awk.y b/gnu/usr.bin/awk/awk.y
index 6e87f1c449cc..175cea90a8cd 100644
--- a/gnu/usr.bin/awk/awk.y
+++ b/gnu/usr.bin/awk/awk.y
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -56,9 +56,10 @@ static char *thisline = NULL;
#define YYDEBUG_LEXER_TEXT (lexeme)
static int param_counter;
static char *tokstart = NULL;
-static char *token = NULL;
+static char *tok = NULL;
static char *tokend;
+#define HASHSIZE 1021 /* this constant only used here */
NODE *variables[HASHSIZE];
extern char *source;
@@ -116,6 +117,7 @@ extern NODE *end_block;
%left LEX_GETLINE
%nonassoc LEX_IN
%left FUNC_CALL LEX_BUILTIN LEX_LENGTH
+%nonassoc ','
%nonassoc MATCHOP
%nonassoc RELOP '<' '>' '|' APPEND_OP
%left CONCAT_OP
@@ -161,6 +163,7 @@ program
}
| error { $$ = NULL; }
| program error { $$ = NULL; }
+ | /* empty */ { $$ = NULL; }
;
rule
@@ -276,7 +279,7 @@ function_body
pattern
: exp
{ $$ = $1; }
- | exp comma exp
+ | exp ',' exp
{ $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); }
;
@@ -290,7 +293,7 @@ regexp
REGEXP '/'
{
NODE *n;
- int len;
+ size_t len;
getnode(n);
n->type = Node_regex;
@@ -385,10 +388,19 @@ statement
if ($2 && $2 == lookup("file")) {
if (do_lint)
warning("`next file' is a gawk extension");
- else if (do_unix || do_posix)
- yyerror("`next file' is a gawk extension");
- else if (! io_allowed)
- yyerror("`next file' used in BEGIN or END action");
+ if (do_unix || do_posix) {
+ /*
+ * can't use yyerror, since may have overshot
+ * the source line
+ */
+ errcount++;
+ msg("`next file' is a gawk extension");
+ }
+ if (! io_allowed) {
+ /* same thing */
+ errcount++;
+ msg("`next file' used in BEGIN or END action");
+ }
type = Node_K_nextfile;
} else {
if (! io_allowed)
@@ -405,6 +417,20 @@ statement
{ $$ = node ($3, Node_K_return, (NODE *)NULL); }
| LEX_DELETE NAME '[' expression_list ']' statement_term
{ $$ = node (variable($2,1), Node_K_delete, $4); }
+ | LEX_DELETE NAME statement_term
+ {
+ if (do_lint)
+ warning("`delete array' is a gawk extension");
+ if (do_unix || do_posix) {
+ /*
+ * can't use yyerror, since may have overshot
+ * the source line
+ */
+ errcount++;
+ msg("`delete array' is a gawk extension");
+ }
+ $$ = node (variable($2,1), Node_K_delete, (NODE *) NULL);
+ }
| exp statement_term
{ $$ = $1; }
;
@@ -693,7 +719,11 @@ non_post_simp_exp
$$ = node ($2, Node_unary_minus, (NODE *)NULL);
}
| '+' simp_exp %prec UNARY
- { $$ = $2; }
+ {
+ /* was: $$ = $2 */
+ /* POSIX semantics: force a conversion to numeric type */
+ $$ = node (make_number(0.0), Node_plus, $2);
+ }
;
opt_variable
@@ -745,7 +775,7 @@ comma : ',' opt_nls { yyerrok; }
%%
struct token {
- char *operator; /* text to match */
+ const char *operator; /* text to match */
NODETYPE value; /* node type */
int class; /* lexical class */
unsigned flags; /* # of args. allowed and compatability */
@@ -819,14 +849,15 @@ yyerror(va_alist)
va_dcl
{
va_list args;
- char *mesg = NULL;
+ const char *mesg = NULL;
register char *bp, *cp;
char *scan;
char buf[120];
+ static char end_of_file_line[] = "(END OF FILE)";
errcount++;
/* Find the current line in the input file */
- if (lexptr) {
+ if (lexptr && lexeme) {
if (!thisline) {
cp = lexeme;
if (*cp == '\n') {
@@ -834,7 +865,7 @@ va_dcl
mesg = "unexpected newline";
}
for ( ; cp != lexptr_begin && *cp != '\n'; --cp)
- ;
+ continue;
if (*cp == '\n')
cp++;
thisline = cp;
@@ -844,8 +875,8 @@ va_dcl
while (bp < lexend && *bp && *bp != '\n')
bp++;
} else {
- thisline = "(END OF FILE)";
- bp = thisline + 13;
+ thisline = end_of_file_line;
+ bp = thisline + strlen(thisline);
}
msg("%.*s", (int) (bp - thisline), thisline);
bp = buf;
@@ -882,12 +913,22 @@ get_src_buf()
static int did_newline = 0;
# define SLOP 128 /* enough space to hold most source lines */
+again:
if (nextfile > numfiles)
return NULL;
if (srcfiles[nextfile].stype == CMDLINE) {
if (len == 0) {
len = strlen(srcfiles[nextfile].val);
+ if (len == 0) {
+ /*
+ * Yet Another Special case:
+ * gawk '' /path/name
+ * Sigh.
+ */
+ ++nextfile;
+ goto again;
+ }
sourceline = 1;
lexptr = lexptr_begin = srcfiles[nextfile].val;
lexend = lexptr + len;
@@ -973,6 +1014,7 @@ get_src_buf()
if (n == 0) {
samefile = 0;
nextfile++;
+ *lexeme = '\0';
len = 0;
return get_src_buf();
}
@@ -981,7 +1023,7 @@ get_src_buf()
return buf;
}
-#define tokadd(x) (*token++ = (x), token == tokend ? tokexpand() : token)
+#define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
char *
tokexpand()
@@ -989,15 +1031,15 @@ tokexpand()
static int toksize = 60;
int tokoffset;
- tokoffset = token - tokstart;
+ tokoffset = tok - tokstart;
toksize *= 2;
if (tokstart)
erealloc(tokstart, char *, toksize, "tokexpand");
else
emalloc(tokstart, char *, toksize, "tokexpand");
tokend = tokstart + toksize;
- token = tokstart + tokoffset;
- return token;
+ tok = tokstart + tokoffset;
+ return tok;
}
#if DEBUG
@@ -1036,13 +1078,23 @@ yylex()
if (!nextc())
return 0;
pushback();
+#ifdef OS2
+ /*
+ * added for OS/2's extproc feature of cmd.exe
+ * (like #! in BSD sh)
+ */
+ if (strncasecmp(lexptr, "extproc ", 8) == 0) {
+ while (*lexptr && *lexptr != '\n')
+ lexptr++;
+ }
+#endif
lexeme = lexptr;
thisline = NULL;
if (want_regexp) {
int in_brack = 0;
want_regexp = 0;
- token = tokstart;
+ tok = tokstart;
while ((c = nextc()) != 0) {
switch (c) {
case '[':
@@ -1079,11 +1131,11 @@ yylex()
}
retry:
while ((c = nextc()) == ' ' || c == '\t')
- ;
+ continue;
lexeme = lexptr ? lexptr - 1 : lexptr;
thisline = NULL;
- token = tokstart;
+ tok = tokstart;
yylval.nodetypeval = Node_illegal;
switch (c) {
@@ -1104,18 +1156,28 @@ retry:
case '\\':
#ifdef RELAXED_CONTINUATION
- if (!do_unix) { /* strip trailing white-space and/or comment */
- while ((c = nextc()) == ' ' || c == '\t') continue;
+ /*
+ * This code puports to allow comments and/or whitespace
+ * after the `\' at the end of a line used for continuation.
+ * Use it at your own risk. We think it's a bad idea, which
+ * is why it's not on by default.
+ */
+ if (!do_unix) {
+ /* strip trailing white-space and/or comment */
+ while ((c = nextc()) == ' ' || c == '\t')
+ continue;
if (c == '#')
- while ((c = nextc()) != '\n') if (!c) break;
+ while ((c = nextc()) != '\n')
+ if (c == '\0')
+ break;
pushback();
}
-#endif /*RELAXED_CONTINUATION*/
+#endif /* RELAXED_CONTINUATION */
if (nextc() == '\n') {
sourceline++;
goto retry;
} else
- yyerror("inappropriate use of backslash");
+ yyerror("backslash not last character on line");
break;
case '$':
@@ -1296,7 +1358,7 @@ retry:
tokadd(c);
}
yylval.nodeval = make_str_node(tokstart,
- token - tokstart, esc_seen ? SCAN : 0);
+ tok - tokstart, esc_seen ? SCAN : 0);
yylval.nodeval->flags |= PERM;
return YSTRING;
@@ -1384,7 +1446,7 @@ retry:
break;
if (c == '#') {
while ((c = nextc()) != '\n' && c != '\0')
- ;
+ continue;
if (c == '\0')
break;
}
@@ -1410,7 +1472,7 @@ retry:
break;
if (c == '#') {
while ((c = nextc()) != '\n' && c != '\0')
- ;
+ continue;
if (c == '\0')
break;
}
@@ -1432,14 +1494,14 @@ retry:
yyerror("Invalid char '%c' in expression\n", c);
/* it's some type of name-type-thing. Find its length */
- token = tokstart;
+ tok = tokstart;
while (is_identchar(c)) {
tokadd(c);
c = nextc();
}
tokadd('\0');
- emalloc(tokkey, char *, token - tokstart, "yylex");
- memcpy(tokkey, tokstart, token - tokstart);
+ emalloc(tokkey, char *, tok - tokstart, "yylex");
+ memcpy(tokkey, tokstart, tok - tokstart);
pushback();
/* See if it is a special token. */
@@ -1478,6 +1540,7 @@ retry:
else
yylval.nodetypeval = tokentab[mid].value;
+ free(tokkey);
return tokentab[mid].class;
}
}
@@ -1638,10 +1701,11 @@ char *name;
NODE *value;
{
register NODE *hp;
- register int len, bucket;
+ register size_t len;
+ register int bucket;
len = strlen(name);
- bucket = hash(name, len);
+ bucket = hash(name, len, (unsigned long) HASHSIZE);
getnode(hp);
hp->type = Node_hashnode;
hp->hnext = variables[bucket];
@@ -1656,13 +1720,13 @@ NODE *value;
/* find the most recent hash node for name installed by install */
NODE *
lookup(name)
-char *name;
+const char *name;
{
register NODE *bucket;
- register int len;
+ register size_t len;
len = strlen(name);
- bucket = variables[hash(name, len)];
+ bucket = variables[hash(name, len, (unsigned long) HASHSIZE)];
while (bucket) {
if (bucket->hlength == len && STREQN(bucket->hname, name, len))
return bucket->hvalue;
@@ -1721,12 +1785,12 @@ NODE *np;
int freeit;
{
register NODE *bucket, **save;
- register int len;
+ register size_t len;
char *name;
name = np->param;
len = strlen(name);
- save = &(variables[hash(name, len)]);
+ save = &(variables[hash(name, len, (unsigned long) HASHSIZE)]);
for (bucket = *save; bucket; bucket = bucket->hnext) {
if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
*save = bucket->hnext;
diff --git a/gnu/usr.bin/awk/builtin.c b/gnu/usr.bin/awk/builtin.c
index 9d5e3b302fde..96411de70df4 100644
--- a/gnu/usr.bin/awk/builtin.c
+++ b/gnu/usr.bin/awk/builtin.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -26,9 +26,8 @@
#include "awk.h"
-
#ifndef SRANDOM_PROTO
-extern void srandom P((int seed));
+extern void srandom P((unsigned int seed));
#endif
#ifndef linux
extern char *initstate P((unsigned seed, char *state, int n));
@@ -40,10 +39,7 @@ extern NODE **fields_arr;
extern int output_is_tty;
static NODE *sub_common P((NODE *tree, int global));
-
-#ifdef GFMT_WORKAROUND
-char *gfmt P((double g, int prec, char *buf));
-#endif
+NODE *format_tree P((const char *, int, NODE *));
#ifdef _CRAY
/* Work around a problem in conversion of doubles to exact integers. */
@@ -63,12 +59,35 @@ double (*Log)() = log;
#define Ceil(n) ceil(n)
#endif
+#define DEFAULT_G_PRECISION 6
+
+#ifdef GFMT_WORKAROUND
+/* semi-temporary hack, mostly to gracefully handle VMS */
+static void sgfmt P((char *buf, const char *format, int alt,
+ int fwidth, int precision, double value));
+#endif /* GFMT_WORKAROUND */
+
+/*
+ * On the alpha, LONG_MAX is too big for doing rand().
+ * On the Cray (Y-MP, anyway), ints and longs are 64 bits, but
+ * random() does things in terms of 32 bits. So we have to chop
+ * LONG_MAX down.
+ */
+#if (defined(__alpha) && defined(__osf__)) || defined(_CRAY)
+#define GAWK_RANDOM_MAX (LONG_MAX & 0x7fffffff)
+#else
+#define GAWK_RANDOM_MAX LONG_MAX
+#endif
+
+static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp,
+ const char *from, struct redirect *rp,int flush));
+
static void
efwrite(ptr, size, count, fp, from, rp, flush)
-void *ptr;
-unsigned size, count;
+const void *ptr;
+size_t size, count;
FILE *fp;
-char *from;
+const char *from;
struct redirect *rp;
int flush;
{
@@ -117,7 +136,7 @@ NODE *tree;
{
NODE *s1, *s2;
register char *p1, *p2;
- register int l1, l2;
+ register size_t l1, l2;
long ret;
@@ -160,21 +179,30 @@ NODE *tree;
return tmp_number((AWKNUM) ret);
}
+double
+double_to_int(d)
+double d;
+{
+ double floor P((double));
+ double ceil P((double));
+
+ if (d >= 0)
+ d = Floor(d);
+ else
+ d = Ceil(d);
+ return d;
+}
+
NODE *
do_int(tree)
NODE *tree;
{
NODE *tmp;
- double floor P((double));
- double ceil P((double));
double d;
tmp = tree_eval(tree->lnode);
d = force_number(tmp);
- if (d >= 0)
- d = Floor(d);
- else
- d = Ceil(d);
+ d = double_to_int(d);
free_temp(tmp);
return tmp_number((AWKNUM) d);
}
@@ -184,7 +212,7 @@ do_length(tree)
NODE *tree;
{
NODE *tmp;
- int len;
+ size_t len;
tmp = tree_eval(tree->lnode);
len = force_string(tmp)->stlen;
@@ -211,27 +239,54 @@ NODE *tree;
return tmp_number((AWKNUM) d);
}
-/* %e and %f formats are not properly implemented. Someone should fix them */
-/* Actually, this whole thing should be reimplemented. */
+/*
+ * format_tree() formats nodes of a tree, starting with a left node,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library. Returns a string node which value
+ * is a formatted string. Called by sprintf function.
+ *
+ * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
NODE *
-do_sprintf(tree)
-NODE *tree;
+format_tree(fmt_string, n0, carg)
+const char *fmt_string;
+int n0;
+register NODE *carg;
{
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
#define bchunk(s,l) if(l) {\
while((l)>ofre) {\
- erealloc(obuf, char *, osiz*2, "do_sprintf");\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
ofre+=osiz;\
osiz*=2;\
+ obufout = obuf + olen;\
}\
- memcpy(obuf+olen,s,(l));\
- olen+=(l);\
+ memcpy(obufout,s,(size_t)(l));\
+ obufout+=(l);\
ofre-=(l);\
}
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) {\
+ if(ofre <= 0) {\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
+ ofre+=osiz;\
+ osiz*=2;\
+ obufout = obuf + olen;\
+ }\
+ *obufout++ = *s;\
+ --ofre;\
+ }
/* Is there space for something L big in the buffer? */
#define chksize(l) if((l)>ofre) {\
- erealloc(obuf, char *, osiz*2, "do_sprintf");\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
+ obufout = obuf + olen;\
ofre+=osiz;\
osiz*=2;\
}
@@ -250,15 +305,14 @@ NODE *tree;
NODE *r;
int toofew = 0;
- char *obuf;
- int osiz, ofre, olen;
- static char chbuf[] = "0123456789abcdef";
- static char sp[] = " ";
- char *s0, *s1;
- int n0;
- NODE *sfmt, *arg;
- register NODE *carg;
- long fw, prec, lj, alt, big;
+ char *obuf, *obufout;
+ size_t osiz, ofre;
+ char *chbuf;
+ const char *s0, *s1;
+ int cs1;
+ NODE *arg;
+ long fw, prec;
+ int lj, alt, big, have_prec;
long *cur;
long val;
#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */
@@ -266,26 +320,26 @@ NODE *tree;
#endif
unsigned long uval;
int sgn;
- int base;
+ int base = 0;
char cpbuf[30]; /* if we have numbers bigger than 30 */
char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
char *cp;
char *fill;
double tmpval;
- char *pr_str;
- int ucasehex = 0;
char signchar = 0;
- int len;
-
+ size_t len;
+ static char sp[] = " ";
+ static char zero_string[] = "0";
+ static char lchbuf[] = "0123456789abcdef";
+ static char Uchbuf[] = "0123456789ABCDEF";
- emalloc(obuf, char *, 120, "do_sprintf");
+ emalloc(obuf, char *, 120, "format_tree");
+ obufout = obuf;
osiz = 120;
ofre = osiz - 1;
- olen = 0;
- sfmt = tree_eval(tree->lnode);
- sfmt = force_string(sfmt);
- carg = tree->rnode;
- for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
+
+ s0 = s1 = fmt_string;
+ while (n0-- > 0) {
if (*s1 != '%') {
s1++;
continue;
@@ -295,24 +349,31 @@ NODE *tree;
cur = &fw;
fw = 0;
prec = 0;
+ have_prec = 0;
lj = alt = big = 0;
fill = sp;
cp = cend;
+ chbuf = lchbuf;
s1++;
retry:
--n0;
- switch (*s1++) {
+ switch (cs1 = *s1++) {
+ case (-1): /* dummy case to allow for checking */
+check_pos:
+ if (cur != &fw)
+ break; /* reject as a valid format */
+ goto retry;
case '%':
- bchunk("%", 1);
+ bchunk_one("%");
s0 = s1;
break;
case '0':
- if (fill != sp || lj)
- goto lose;
+ if (lj)
+ goto retry;
if (cur == &fw)
- fill = "0"; /* FALL through */
+ fill = zero_string; /* FALL through */
case '1':
case '2':
case '3':
@@ -323,44 +384,65 @@ retry:
case '8':
case '9':
if (cur == 0)
- goto lose;
- *cur = s1[-1] - '0';
+ /* goto lose; */
+ break;
+ if (prec >= 0)
+ *cur = cs1 - '0';
+ /* with a negative precision *cur is already set */
+ /* to -1, so it will remain negative, but we have */
+ /* to "eat" precision digits in any case */
while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
--n0;
*cur = *cur * 10 + *s1++ - '0';
}
+ if (prec < 0) /* negative precision is discarded */
+ have_prec = 0;
+ if (cur == &prec)
+ cur = 0;
goto retry;
case '*':
if (cur == 0)
- goto lose;
+ /* goto lose; */
+ break;
parse_next_arg();
*cur = force_number(arg);
free_temp(arg);
+ if (cur == &prec)
+ cur = 0;
goto retry;
case ' ': /* print ' ' or '-' */
+ /* 'space' flag is ignored */
+ /* if '+' already present */
+ if (signchar != 0)
+ goto check_pos;
+ /* FALL THROUGH */
case '+': /* print '+' or '-' */
- signchar = *(s1-1);
- goto retry;
+ signchar = cs1;
+ goto check_pos;
case '-':
- if (lj || fill != sp)
- goto lose;
- lj++;
- goto retry;
+ if (prec < 0)
+ break;
+ if (cur == &prec) {
+ prec = -1;
+ goto retry;
+ }
+ fill = sp; /* if left justified then other */
+ lj++; /* filling is ignored */
+ goto check_pos;
case '.':
if (cur != &fw)
- goto lose;
+ break;
cur = &prec;
+ have_prec++;
goto retry;
case '#':
- if (alt)
- goto lose;
alt++;
- goto retry;
+ goto check_pos;
case 'l':
if (big)
- goto lose;
+ break;
big++;
- goto retry;
+ goto check_pos;
case 'c':
parse_next_arg();
if (arg->flags & NUMBER) {
@@ -372,240 +454,189 @@ retry:
#endif
cpbuf[0] = uval;
prec = 1;
- pr_str = cpbuf;
- goto dopr_string;
+ cp = cpbuf;
+ goto pr_tail;
}
- if (! prec)
+ if (have_prec == 0)
prec = 1;
else if (prec > arg->stlen)
prec = arg->stlen;
- pr_str = arg->stptr;
- goto dopr_string;
+ cp = arg->stptr;
+ goto pr_tail;
case 's':
parse_next_arg();
arg = force_string(arg);
- if (!prec || prec > arg->stlen)
+ if (have_prec == 0 || prec > arg->stlen)
prec = arg->stlen;
- pr_str = arg->stptr;
-
- dopr_string:
- if (fw > prec && !lj) {
- while (fw > prec) {
- bchunk(sp, 1);
- fw--;
- }
- }
- bchunk(pr_str, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(sp, 1);
- fw--;
- }
- }
- s0 = s1;
- free_temp(arg);
- break;
+ cp = arg->stptr;
+ goto pr_tail;
case 'd':
case 'i':
parse_next_arg();
- val = (long) force_number(arg);
- free_temp(arg);
+ tmpval = force_number(arg);
+ if (tmpval > LONG_MAX || tmpval < LONG_MIN) {
+ /* out of range - emergency use of %g format */
+ cs1 = 'g';
+ goto format_float;
+ }
+ val = (long) tmpval;
+
if (val < 0) {
sgn = 1;
- val = -val;
- } else
+ if (val > LONG_MIN)
+ uval = (unsigned long) -val;
+ else
+ uval = (unsigned long)(-(LONG_MIN + 1))
+ + (unsigned long)1;
+ } else {
sgn = 0;
+ uval = (unsigned long) val;
+ }
do {
- *--cp = '0' + val % 10;
- val /= 10;
- } while (val);
+ *--cp = (char) ('0' + uval % 10);
+ uval /= 10;
+ } while (uval);
if (sgn)
*--cp = '-';
else if (signchar)
*--cp = signchar;
+ if (have_prec != 0) /* ignore '0' flag if */
+ fill = sp; /* precision given */
if (prec > fw)
fw = prec;
prec = cend - cp;
- if (fw > prec && !lj) {
- if (fill != sp && (*cp == '-' || signchar)) {
- bchunk(cp, 1);
- cp++;
- prec--;
- fw--;
- }
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
+ if (fw > prec && ! lj && fill != sp
+ && (*cp == '-' || signchar)) {
+ bchunk_one(cp);
+ cp++;
+ prec--;
+ fw--;
}
- bchunk(cp, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
- }
- s0 = s1;
- break;
- case 'u':
- base = 10;
- goto pr_unsigned;
- case 'o':
- base = 8;
- goto pr_unsigned;
+ goto pr_tail;
case 'X':
- ucasehex = 1;
+ chbuf = Uchbuf; /* FALL THROUGH */
case 'x':
- base = 16;
- goto pr_unsigned;
- pr_unsigned:
+ base += 6; /* FALL THROUGH */
+ case 'u':
+ base += 2; /* FALL THROUGH */
+ case 'o':
+ base += 8;
parse_next_arg();
- uval = (unsigned long) force_number(arg);
- free_temp(arg);
+ tmpval = force_number(arg);
+ if (tmpval > ULONG_MAX || tmpval < LONG_MIN) {
+ /* out of range - emergency use of %g format */
+ cs1 = 'g';
+ goto format_float;
+ }
+ uval = (unsigned long)tmpval;
+ if (have_prec != 0) /* ignore '0' flag if */
+ fill = sp; /* precision given */
do {
*--cp = chbuf[uval % base];
- if (ucasehex && isalpha(*cp))
- *cp = toupper(*cp);
uval /= base;
} while (uval);
- if (alt && (base == 8 || base == 16)) {
+ if (alt) {
if (base == 16) {
- if (ucasehex)
- *--cp = 'X';
- else
- *--cp = 'x';
- }
- *--cp = '0';
+ *--cp = cs1;
+ *--cp = '0';
+ if (fill != sp) {
+ bchunk(cp, 2);
+ cp += 2;
+ fw -= 2;
+ }
+ } else if (base == 8)
+ *--cp = '0';
}
+ base = 0;
prec = cend - cp;
- if (fw > prec && !lj) {
+ pr_tail:
+ if (! lj) {
while (fw > prec) {
- bchunk(fill, 1);
+ bchunk_one(fill);
fw--;
}
}
bchunk(cp, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
+ while (fw > prec) {
+ bchunk_one(fill);
+ fw--;
}
s0 = s1;
+ free_temp(arg);
break;
case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
parse_next_arg();
tmpval = force_number(arg);
+ format_float:
free_temp(arg);
+ if (have_prec == 0)
+ prec = DEFAULT_G_PRECISION;
chksize(fw + prec + 9); /* 9==slop */
cp = cpbuf;
*cp++ = '%';
if (lj)
*cp++ = '-';
+ if (signchar)
+ *cp++ = signchar;
+ if (alt)
+ *cp++ = '#';
if (fill != sp)
*cp++ = '0';
+ cp = strcpy(cp, "*.*") + 3;
+ *cp++ = cs1;
+ *cp = '\0';
#ifndef GFMT_WORKAROUND
- if (cur != &fw) {
- (void) strcpy(cp, "*.*g");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*g");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
+ (void) sprintf(obufout, cpbuf,
+ (int) fw, (int) prec, (double) tmpval);
#else /* GFMT_WORKAROUND */
- {
- char *gptr, gbuf[120];
-#define DEFAULT_G_PRECISION 6
- if (fw + prec + 9 > sizeof gbuf) { /* 9==slop */
- emalloc(gptr, char *, fw+prec+9, "do_sprintf(gfmt)");
- } else
- gptr = gbuf;
- (void) gfmt((double) tmpval, cur != &fw ?
- (int) prec : DEFAULT_G_PRECISION, gptr);
- *cp++ = '*', *cp++ = 's', *cp = '\0';
- (void) sprintf(obuf + olen, cpbuf, (int) fw, gptr);
- if (fill != sp && *gptr == ' ') {
- char *p = gptr;
- do { *p++ = '0'; } while (*p == ' ');
- }
- if (gptr != gbuf) free(gptr);
- }
+ if (cs1 == 'g' || cs1 == 'G')
+ sgfmt(obufout, cpbuf, (int) alt,
+ (int) fw, (int) prec, (double) tmpval);
+ else
+ (void) sprintf(obufout, cpbuf,
+ (int) fw, (int) prec, (double) tmpval);
#endif /* GFMT_WORKAROUND */
- len = strlen(obuf + olen);
- ofre -= len;
- olen += len;
- s0 = s1;
- break;
-
- case 'f':
- parse_next_arg();
- tmpval = force_number(arg);
- free_temp(arg);
- chksize(fw + prec + 9); /* 9==slop */
-
- cp = cpbuf;
- *cp++ = '%';
- if (lj)
- *cp++ = '-';
- if (fill != sp)
- *cp++ = '0';
- if (cur != &fw) {
- (void) strcpy(cp, "*.*f");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*f");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
- len = strlen(obuf + olen);
- ofre -= len;
- olen += len;
- s0 = s1;
- break;
- case 'e':
- parse_next_arg();
- tmpval = force_number(arg);
- free_temp(arg);
- chksize(fw + prec + 9); /* 9==slop */
- cp = cpbuf;
- *cp++ = '%';
- if (lj)
- *cp++ = '-';
- if (fill != sp)
- *cp++ = '0';
- if (cur != &fw) {
- (void) strcpy(cp, "*.*e");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*e");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
- len = strlen(obuf + olen);
+ len = strlen(obufout);
ofre -= len;
- olen += len;
+ obufout += len;
s0 = s1;
break;
-
default:
- lose:
break;
}
if (toofew)
fatal("%s\n\t%s\n\t%*s%s",
"not enough arguments to satisfy format string",
- sfmt->stptr, s1 - sfmt->stptr - 2, "",
+ fmt_string, s1 - fmt_string - 2, "",
"^ ran out for this one"
);
}
if (do_lint && carg != NULL)
warning("too many arguments supplied for format string");
bchunk(s0, s1 - s0);
- free_temp(sfmt);
- r = make_str_node(obuf, olen, ALREADY_MALLOCED);
+ r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
r->flags |= TEMP;
return r;
}
+NODE *
+do_sprintf(tree)
+NODE *tree;
+{
+ NODE *r;
+ NODE *sfmt = force_string(tree_eval(tree->lnode));
+
+ r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode);
+ free_temp(sfmt);
+ return r;
+}
+
+
void
do_printf(tree)
register NODE *tree;
@@ -654,6 +685,7 @@ NODE *tree;
NODE *r;
register int indx;
size_t length;
+ int is_long;
t1 = tree_eval(tree->lnode);
t2 = tree_eval(tree->rnode->lnode);
@@ -669,12 +701,16 @@ NODE *tree;
t1 = force_string(t1);
if (indx < 0)
indx = 0;
- if (indx >= t1->stlen || length <= 0) {
+ if (indx >= t1->stlen || (long) length <= 0) {
free_temp(t1);
return Nnull_string;
}
- if (indx + length > t1->stlen || LONG_MAX - indx < length)
+ if ((is_long = (indx + length > t1->stlen)) || LONG_MAX - indx < length) {
length = t1->stlen - indx;
+ if (do_lint && is_long)
+ warning("substr: length %d at position %d exceeds length of first argument",
+ length, indx+1);
+ }
r = tmp_string(t1->stptr + indx, length);
free_temp(t1);
return r;
@@ -688,7 +724,6 @@ NODE *tree;
struct tm *tm;
time_t fclock;
char buf[100];
- int ret;
t1 = force_string(tree_eval(tree->lnode));
@@ -701,9 +736,7 @@ NODE *tree;
}
tm = localtime(&fclock);
- ret = strftime(buf, 100, t1->stptr, tm);
-
- return tmp_string(buf, ret);
+ return tmp_string(buf, strftime(buf, 100, t1->stptr, tm));
}
NODE *
@@ -723,18 +756,43 @@ NODE *tree;
NODE *tmp;
int ret = 0;
char *cmd;
+ char save;
- (void) flush_io (); /* so output is synchronous with gawk's */
+ (void) flush_io (); /* so output is synchronous with gawk's */
tmp = tree_eval(tree->lnode);
cmd = force_string(tmp)->stptr;
+
if (cmd && *cmd) {
+ /* insure arg to system is zero-terminated */
+
+ /*
+ * From: David Trueman <emory!cs.dal.ca!david>
+ * To: arnold@cc.gatech.edu (Arnold Robbins)
+ * Date: Wed, 3 Nov 1993 12:49:41 -0400
+ *
+ * It may not be necessary to save the character, but
+ * I'm not sure. It would normally be the field
+ * separator. If the parse has not yet gone beyond
+ * that, it could mess up (although I doubt it). If
+ * FIELDWIDTHS is being used, it might be the first
+ * character of the next field. Unless someone wants
+ * to check it out exhaustively, I suggest saving it
+ * for now...
+ */
+ save = cmd[tmp->stlen];
+ cmd[tmp->stlen] = '\0';
+
ret = system(cmd);
ret = (ret >> 8) & 0xff;
+
+ cmd[tmp->stlen] = save;
}
free_temp(tmp);
return tmp_number((AWKNUM) ret);
}
+extern NODE **fmt_list; /* declared in eval.c */
+
void
do_print(tree)
register NODE *tree;
@@ -763,10 +821,18 @@ register NODE *tree;
if (OFMTidx == CONVFMTidx)
(void) force_string(t1);
else {
+#ifndef GFMT_WORKAROUND
char buf[100];
- sprintf(buf, OFMT, t1->numbr);
+ (void) sprintf(buf, OFMT, t1->numbr);
+ free_temp(t1);
t1 = tmp_string(buf, strlen(buf));
+#else /* GFMT_WORKAROUND */
+ free_temp(t1);
+ t1 = format_tree(OFMT,
+ fmt_list[OFMTidx]->stlen,
+ tree);
+#endif /* GFMT_WORKAROUND */
}
}
efwrite(t1->stptr, sizeof(char), t1->stlen, fp, "print", rp, 0);
@@ -775,12 +841,13 @@ register NODE *tree;
if (tree) {
s = OFS;
if (OFSlen)
- efwrite(s, sizeof(char), OFSlen, fp, "print", rp, 0);
+ efwrite(s, sizeof(char), (size_t)OFSlen,
+ fp, "print", rp, 0);
}
}
s = ORS;
if (ORSlen)
- efwrite(s, sizeof(char), ORSlen, fp, "print", rp, 1);
+ efwrite(s, sizeof(char), (size_t)ORSlen, fp, "print", rp, 1);
}
NODE *
@@ -863,7 +930,7 @@ NODE *tree;
}
static int firstrand = 1;
-static char state[256];
+static char state[512];
/* ARGSUSED */
NODE *
@@ -875,7 +942,7 @@ NODE *tree;
srandom(1);
firstrand = 0;
}
- return tmp_number((AWKNUM) random() / LONG_MAX);
+ return tmp_number((AWKNUM) random() / GAWK_RANDOM_MAX);
}
NODE *
@@ -892,10 +959,10 @@ NODE *tree;
(void) setstate(state);
if (!tree)
- srandom((int) (save_seed = (long) time((time_t *) 0)));
+ srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
else {
tmp = tree_eval(tree->lnode);
- srandom((int) (save_seed = (long) force_number(tmp)));
+ srandom((unsigned int) (save_seed = (long) force_number(tmp)));
free_temp(tmp);
}
firstrand = 0;
@@ -938,15 +1005,15 @@ int global;
register char *scan;
register char *bp, *cp;
char *buf;
- int buflen;
+ size_t buflen;
register char *matchend;
- register int len;
+ register size_t len;
char *matchstart;
char *text;
- int textlen;
+ size_t textlen;
char *repl;
char *replend;
- int repllen;
+ size_t repllen;
int sofar;
int ampersands;
int matches = 0;
@@ -970,9 +1037,9 @@ int global;
/* do the search early to avoid work on non-match */
if (research(rp, t->stptr, 0, t->stlen, 1) == -1 ||
- (RESTART(rp, t->stptr) > t->stlen) && (matches = 1)) {
+ RESTART(rp, t->stptr) > t->stlen) {
free_temp(t);
- return tmp_number((AWKNUM) matches);
+ return tmp_number((AWKNUM) 0.0);
}
if (tmp->type == Node_val)
@@ -1001,13 +1068,15 @@ int global;
repl = s->stptr;
replend = repl + s->stlen;
repllen = replend - repl;
- emalloc(buf, char *, buflen, "do_sub");
+ emalloc(buf, char *, buflen + 2, "do_sub");
+ buf[buflen] = '\0';
+ buf[buflen + 1] = '\0';
ampersands = 0;
for (scan = repl; scan < replend; scan++) {
if (*scan == '&') {
repllen--;
ampersands++;
- } else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) {
+ } else if (*scan == '\\' && *(scan+1) == '&') {
repllen--;
scan++;
}
@@ -1026,7 +1095,7 @@ int global;
len = matchstart - text + repllen
+ ampersands * (matchend - matchstart);
sofar = bp - buf;
- while (buflen - sofar - len - 1 < 0) {
+ while ((long)(buflen - sofar - len - 1) < 0) {
buflen *= 2;
erealloc(buf, char *, buflen, "do_sub");
bp = buf + sofar;
@@ -1037,18 +1106,20 @@ int global;
if (*scan == '&')
for (cp = matchstart; cp < matchend; cp++)
*bp++ = *cp;
- else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) {
+ else if (*scan == '\\' && *(scan+1) == '&') {
scan++;
*bp++ = *scan;
} else
*bp++ = *scan;
+
+ /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */
if (global && matchstart == matchend && matchend < text + textlen) {
*bp++ = *matchend;
matchend++;
}
textlen = text + textlen - matchend;
text = matchend;
- if (!global || textlen <= 0 ||
+ if (!global || (long)textlen <= 0 ||
research(rp, t->stptr, text-t->stptr, textlen, 1) == -1)
break;
}
@@ -1060,6 +1131,7 @@ int global;
}
for (scan = matchend; scan < text + textlen; scan++)
*bp++ = *scan;
+ *bp = '\0';
textlen = bp - buf;
free(t->stptr);
t->stptr = buf;
@@ -1093,41 +1165,75 @@ NODE *tree;
}
#ifdef GFMT_WORKAROUND
- /*
- * printf's %g format [can't rely on gcvt()]
- * caveat: don't use as argument to *printf()!
- */
-char *
-gfmt(g, prec, buf)
-double g; /* value to format */
-int prec; /* indicates desired significant digits, not decimal places */
+/*
+ * printf's %g format [can't rely on gcvt()]
+ * caveat: don't use as argument to *printf()!
+ * 'format' string HAS to be of "<flags>*.*g" kind, or we bomb!
+ */
+static void
+sgfmt(buf, format, alt, fwidth, prec, g)
char *buf; /* return buffer; assumed big enough to hold result */
+const char *format;
+int alt; /* use alternate form flag */
+int fwidth; /* field width in a format */
+int prec; /* indicates desired significant digits, not decimal places */
+double g; /* value to format */
{
- if (g == 0.0) {
- (void) strcpy(buf, "0"); /* easy special case */
- } else {
- register char *d, *e, *p;
-
- /* start with 'e' format (it'll provide nice exponent) */
- if (prec < 1) prec = 1; /* at least 1 significant digit */
- (void) sprintf(buf, "%.*e", prec - 1, g);
- if ((e = strchr(buf, 'e')) != 0) { /* find exponent */
- int exp = atoi(e+1); /* fetch exponent */
- if (exp >= -4 && exp < prec) { /* per K&R2, B1.2 */
- /* switch to 'f' format and re-do */
- prec -= (exp + 1); /* decimal precision */
- (void) sprintf(buf, "%.*f", prec, g);
- e = buf + strlen(buf);
- }
- if ((d = strchr(buf, '.')) != 0) {
- /* remove trailing zeroes and decimal point */
- for (p = e; p > d && *--p == '0'; ) continue;
- if (*p == '.') --p;
- if (++p < e) /* copy exponent and NUL */
- while ((*p++ = *e++) != '\0') continue;
- }
+ char dform[40];
+ register char *gpos;
+ register char *d, *e, *p;
+ int again = 0;
+
+ strncpy(dform, format, sizeof dform - 1);
+ dform[sizeof dform - 1] = '\0';
+ gpos = strrchr(dform, '.');
+
+ if (g == 0.0 && alt == 0) { /* easy special case */
+ *gpos++ = 'd';
+ *gpos = '\0';
+ (void) sprintf(buf, dform, fwidth, 0);
+ return;
+ }
+ gpos += 2; /* advance to location of 'g' in the format */
+
+ if (prec <= 0) /* negative precision is ignored */
+ prec = (prec < 0 ? DEFAULT_G_PRECISION : 1);
+
+ if (*gpos == 'G')
+ again = 1;
+ /* start with 'e' format (it'll provide nice exponent) */
+ *gpos = 'e';
+ prec -= 1;
+ (void) sprintf(buf, dform, fwidth, prec, g);
+ if ((e = strrchr(buf, 'e')) != NULL) { /* find exponent */
+ int exp = atoi(e+1); /* fetch exponent */
+ if (exp >= -4 && exp <= prec) { /* per K&R2, B1.2 */
+ /* switch to 'f' format and re-do */
+ *gpos = 'f';
+ prec -= exp; /* decimal precision */
+ (void) sprintf(buf, dform, fwidth, prec, g);
+ e = buf + strlen(buf);
+ while (*--e == ' ')
+ continue;
+ e += 1;
+ }
+ else if (again != 0)
+ *gpos = 'E';
+
+ /* if 'alt' in force, then trailing zeros are not removed */
+ if (alt == 0 && (d = strrchr(buf, '.')) != NULL) {
+ /* throw away an excess of precision */
+ for (p = e; p > d && *--p == '0'; )
+ prec -= 1;
+ if (d == p)
+ prec -= 1;
+ if (prec < 0)
+ prec = 0;
+ /* and do that once again */
+ again = 1;
}
+ if (again != 0)
+ (void) sprintf(buf, dform, fwidth, prec, g);
}
- return buf;
}
#endif /* GFMT_WORKAROUND */
diff --git a/gnu/usr.bin/awk/config.h b/gnu/usr.bin/awk/config.h
index 8c20953ed531..0b3cca1d8299 100644
--- a/gnu/usr.bin/awk/config.h
+++ b/gnu/usr.bin/awk/config.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -92,6 +92,13 @@
*/
#define HAVE_UNDERSCORE_SETJMP 1
+/*
+ * LIMITS_H_MISSING
+ *
+ * You don't have a <limits.h> include file.
+ */
+/* #define LIMITS_H_MISSING 1 */
+
/***********************************************/
/* Missing library subroutines or system calls */
/***********************************************/
@@ -147,7 +154,7 @@
* Your system does not have the strtod() routine for converting
* strings to double precision floating point values.
*/
-/* #define STRTOD_MISSING 1 */
+/* #define STRTOD_MISSING 1 */
/*
* STRFTIME_MISSING
@@ -177,6 +184,15 @@
/* #define TZNAME_MISSING 1 */
/*
+ * TM_ZONE_MISSING
+ *
+ * Your "struct tm" is missing the tm_zone field.
+ * If this is the case *and* strftime() is missing *and* tzname is missing,
+ * define this.
+ */
+/* #define TM_ZONE_MISSING 1 */
+
+/*
* STDC_HEADERS
*
* If your system does have ANSI compliant header files that
@@ -269,4 +285,22 @@
*/
#define SRANDOM_PROTO 1
+/*
+ * getpgrp() in sysvr4 and POSIX takes no argument
+ */
+/* #define GETPGRP_NOARG 0 */
+
+/*
+ * define const to nothing if not __STDC__
+ */
+#ifndef __STDC__
+#define const
+#endif
+
+/* If svr4 and not gcc */
+/* #define SVR4 0 */
+#ifdef SVR4
+#define __svr4__ 1
+#endif
+
/* anything that follows is for system-specific short-term kludges */
diff --git a/gnu/usr.bin/awk/dfa.c b/gnu/usr.bin/awk/dfa.c
index 5293c755871d..47ad35e9cc2e 100644
--- a/gnu/usr.bin/awk/dfa.c
+++ b/gnu/usr.bin/awk/dfa.c
@@ -1,182 +1,146 @@
-/* dfa.c - determinisitic extended regexp routines for GNU
+/* dfa.c - deterministic extended regexp routines for GNU
Copyright (C) 1988 Free Software Foundation, Inc.
- Written June, 1988 by Mike Haertel
- Modified July, 1988 by Arthur David Olson
- to assist BMG speedups
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
-NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
-WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
-OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
-DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
-A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
-PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
-as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1988 Free Software Foundation, Inc."; and include following the
-copyright notice a verbatim copy of the above disclaimer of warranty
-and of this License. You may charge a distribution fee for the
-physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file 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 or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution 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 unrelated program with this program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other program under the scope of these terms.
-
- 3. You may copy and distribute this program or any portion of it in
-compiled, executable or object code form under the terms of Paragraphs
-1 and 2 above provided that you do 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
- shipping charge) 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.)
-
-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.
-
- 4. You may not copy, sublicense, distribute or transfer this program
-except as expressly provided under this License Agreement. Any attempt
-otherwise to copy, sublicense, distribute or transfer this program is void and
-your rights to use the program under this License agreement shall be
-automatically terminated. However, parties who have received computer
-software programs from you with this License Agreement will not have
-their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
-programs whose distribution conditions are different, write to the Free
-Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
-worked out a simple rule that can be stated here, but we will often permit
-this. We will be guided by the two goals of preserving the free status of
-all derivatives our free software and of promoting the sharing and reuse of
-software.
-
-
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-#include "awk.h"
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written June, 1988 by Mike Haertel
+ Modified July, 1988 by Arthur David Olson to assist BMG speedups */
+
#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#include <sys/types.h>
+extern char *calloc(), *malloc(), *realloc();
+extern void free();
+#endif
-#ifdef setbit /* surprise - setbit and clrbit are macros on NeXT */
-#undef setbit
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#undef index
+#define index strchr
+#else
+#include <strings.h>
#endif
-#ifdef clrbit
-#undef clrbit
+
+#ifndef DEBUG /* use the same approach as regex.c */
+#undef assert
+#define assert(e)
+#endif /* DEBUG */
+
+#ifndef isgraph
+#define isgraph(C) (isprint(C) && !isspace(C))
#endif
+#ifdef isascii
+#define ISALPHA(C) (isascii(C) && isalpha(C))
+#define ISUPPER(C) (isascii(C) && isupper(C))
+#define ISLOWER(C) (isascii(C) && islower(C))
+#define ISDIGIT(C) (isascii(C) && isdigit(C))
+#define ISXDIGIT(C) (isascii(C) && isxdigit(C))
+#define ISSPACE(C) (isascii(C) && isspace(C))
+#define ISPUNCT(C) (isascii(C) && ispunct(C))
+#define ISALNUM(C) (isascii(C) && isalnum(C))
+#define ISPRINT(C) (isascii(C) && isprint(C))
+#define ISGRAPH(C) (isascii(C) && isgraph(C))
+#define ISCNTRL(C) (isascii(C) && iscntrl(C))
+#else
+#define ISALPHA(C) isalpha(C)
+#define ISUPPER(C) isupper(C)
+#define ISLOWER(C) islower(C)
+#define ISDIGIT(C) isdigit(C)
+#define ISXDIGIT(C) isxdigit(C)
+#define ISSPACE(C) isspace(C)
+#define ISPUNCT(C) ispunct(C)
+#define ISALNUM(C) isalnum(C)
+#define ISPRINT(C) isprint(C)
+#define ISGRAPH(C) isgraph(C)
+#define ISCNTRL(C) iscntrl(C)
+#endif
+
+#include "regex.h"
+#include "dfa.h"
+
#ifdef __STDC__
typedef void *ptr_t;
#else
typedef char *ptr_t;
+#ifndef const
+#define const
+#endif
#endif
-typedef struct {
- char ** in;
- char * left;
- char * right;
- char * is;
-} must;
+static void dfamust _RE_ARGS((struct dfa *dfa));
-static ptr_t xcalloc P((int n, size_t s));
-static ptr_t xmalloc P((size_t n));
-static ptr_t xrealloc P((ptr_t p, size_t n));
-static int tstbit P((int b, _charset c));
-static void setbit P((int b, _charset c));
-static void clrbit P((int b, _charset c));
-static void copyset P((const _charset src, _charset dst));
-static void zeroset P((_charset s));
-static void notset P((_charset s));
-static int equal P((const _charset s1, const _charset s2));
-static int charset_index P((const _charset s));
-static _token lex P((void));
-static void addtok P((_token t));
-static void atom P((void));
-static void closure P((void));
-static void branch P((void));
-static void regexp P((void));
-static void copy P((const _position_set *src, _position_set *dst));
-static void insert P((_position p, _position_set *s));
-static void merge P((_position_set *s1, _position_set *s2, _position_set *m));
-static void delete P((_position p, _position_set *s));
-static int state_index P((struct regexp *r, _position_set *s,
+static ptr_t xcalloc _RE_ARGS((size_t n, size_t s));
+static ptr_t xmalloc _RE_ARGS((size_t n));
+static ptr_t xrealloc _RE_ARGS((ptr_t p, size_t n));
+#ifdef DEBUG
+static void prtok _RE_ARGS((token t));
+#endif
+static int tstbit _RE_ARGS((int b, charclass c));
+static void setbit _RE_ARGS((int b, charclass c));
+static void clrbit _RE_ARGS((int b, charclass c));
+static void copyset _RE_ARGS((charclass src, charclass dst));
+static void zeroset _RE_ARGS((charclass s));
+static void notset _RE_ARGS((charclass s));
+static int equal _RE_ARGS((charclass s1, charclass s2));
+static int charclass_index _RE_ARGS((charclass s));
+static int looking_at _RE_ARGS((const char *s));
+static token lex _RE_ARGS((void));
+static void addtok _RE_ARGS((token t));
+static void atom _RE_ARGS((void));
+static int nsubtoks _RE_ARGS((int tindex));
+static void copytoks _RE_ARGS((int tindex, int ntokens));
+static void closure _RE_ARGS((void));
+static void branch _RE_ARGS((void));
+static void regexp _RE_ARGS((int toplevel));
+static void copy _RE_ARGS((position_set *src, position_set *dst));
+static void insert _RE_ARGS((position p, position_set *s));
+static void merge _RE_ARGS((position_set *s1, position_set *s2, position_set *m));
+static void delete _RE_ARGS((position p, position_set *s));
+static int state_index _RE_ARGS((struct dfa *d, position_set *s,
int newline, int letter));
-static void epsclosure P((_position_set *s, struct regexp *r));
-static void build_state P((int s, struct regexp *r));
-static void build_state_zero P((struct regexp *r));
-static char *icatalloc P((char *old, const char *new));
-static char *icpyalloc P((const char *string));
-static char *istrstr P((char *lookin, char *lookfor));
-static void ifree P((char *cp));
-static void freelist P((char **cpp));
-static char **enlist P((char **cpp, char *new, size_t len));
-static char **comsubs P((char *left, char *right));
-static char **addlists P((char **old, char **new));
-static char **inboth P((char **left, char **right));
-static void resetmust P((must *mp));
-static void regmust P((struct regexp *r));
-
-#undef P
+static void build_state _RE_ARGS((int s, struct dfa *d));
+static void build_state_zero _RE_ARGS((struct dfa *d));
+static char *icatalloc _RE_ARGS((char *old, char *new));
+static char *icpyalloc _RE_ARGS((char *string));
+static char *istrstr _RE_ARGS((char *lookin, char *lookfor));
+static void ifree _RE_ARGS((char *cp));
+static void freelist _RE_ARGS((char **cpp));
+static char **enlist _RE_ARGS((char **cpp, char *new, size_t len));
+static char **comsubs _RE_ARGS((char *left, char *right));
+static char **addlists _RE_ARGS((char **old, char **new));
+static char **inboth _RE_ARGS((char **left, char **right));
static ptr_t
xcalloc(n, s)
- int n;
+ size_t n;
size_t s;
{
ptr_t r = calloc(n, s);
- if (NULL == r)
- reg_error("Memory exhausted"); /* reg_error does not return */
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
@@ -187,8 +151,8 @@ xmalloc(n)
ptr_t r = malloc(n);
assert(n != 0);
- if (NULL == r)
- reg_error("Memory exhausted");
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
@@ -200,13 +164,12 @@ xrealloc(p, n)
ptr_t r = realloc(p, n);
assert(n != 0);
- if (NULL == r)
- reg_error("Memory exhausted");
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
-#define CALLOC(p, t, n) ((p) = (t *) xcalloc((n), sizeof (t)))
-#undef MALLOC
+#define CALLOC(p, t, n) ((p) = (t *) xcalloc((size_t)(n), sizeof (t)))
#define MALLOC(p, t, n) ((p) = (t *) xmalloc((n) * sizeof (t)))
#define REALLOC(p, t, n) ((p) = (t *) xrealloc((ptr_t) (p), (n) * sizeof (t)))
@@ -218,13 +181,52 @@ xrealloc(p, n)
(nalloc) *= 2; \
REALLOC(p, t, nalloc); \
}
-
-/* Stuff pertaining to charsets. */
+
+#ifdef DEBUG
+
+static void
+prtok(t)
+ token t;
+{
+ char *s;
+
+ if (t < 0)
+ fprintf(stderr, "END");
+ else if (t < NOTCHAR)
+ fprintf(stderr, "%c", t);
+ else
+ {
+ switch (t)
+ {
+ case EMPTY: s = "EMPTY"; break;
+ case BACKREF: s = "BACKREF"; break;
+ case BEGLINE: s = "BEGLINE"; break;
+ case ENDLINE: s = "ENDLINE"; break;
+ case BEGWORD: s = "BEGWORD"; break;
+ case ENDWORD: s = "ENDWORD"; break;
+ case LIMWORD: s = "LIMWORD"; break;
+ case NOTLIMWORD: s = "NOTLIMWORD"; break;
+ case QMARK: s = "QMARK"; break;
+ case STAR: s = "STAR"; break;
+ case PLUS: s = "PLUS"; break;
+ case CAT: s = "CAT"; break;
+ case OR: s = "OR"; break;
+ case ORTOP: s = "ORTOP"; break;
+ case LPAREN: s = "LPAREN"; break;
+ case RPAREN: s = "RPAREN"; break;
+ default: s = "CSET"; break;
+ }
+ fprintf(stderr, "%s", s);
+ }
+}
+#endif /* DEBUG */
+
+/* Stuff pertaining to charclasses. */
static int
tstbit(b, c)
int b;
- _charset c;
+ charclass c;
{
return c[b / INTBITS] & 1 << b % INTBITS;
}
@@ -232,7 +234,7 @@ tstbit(b, c)
static void
setbit(b, c)
int b;
- _charset c;
+ charclass c;
{
c[b / INTBITS] |= 1 << b % INTBITS;
}
@@ -240,84 +242,84 @@ setbit(b, c)
static void
clrbit(b, c)
int b;
- _charset c;
+ charclass c;
{
c[b / INTBITS] &= ~(1 << b % INTBITS);
}
static void
copyset(src, dst)
- const _charset src;
- _charset dst;
+ charclass src;
+ charclass dst;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
dst[i] = src[i];
}
static void
zeroset(s)
- _charset s;
+ charclass s;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
s[i] = 0;
}
static void
notset(s)
- _charset s;
+ charclass s;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
s[i] = ~s[i];
}
static int
equal(s1, s2)
- const _charset s1;
- const _charset s2;
+ charclass s1;
+ charclass s2;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
if (s1[i] != s2[i])
return 0;
return 1;
}
-
-/* A pointer to the current regexp is kept here during parsing. */
-static struct regexp *reg;
-/* Find the index of charset s in reg->charsets, or allocate a new charset. */
+/* A pointer to the current dfa is kept here during parsing. */
+static struct dfa *dfa;
+
+/* Find the index of charclass s in dfa->charclasses, or allocate a new charclass. */
static int
-charset_index(s)
- const _charset s;
+charclass_index(s)
+ charclass s;
{
int i;
- for (i = 0; i < reg->cindex; ++i)
- if (equal(s, reg->charsets[i]))
+ for (i = 0; i < dfa->cindex; ++i)
+ if (equal(s, dfa->charclasses[i]))
return i;
- REALLOC_IF_NECESSARY(reg->charsets, _charset, reg->calloc, reg->cindex);
- ++reg->cindex;
- copyset(s, reg->charsets[i]);
+ REALLOC_IF_NECESSARY(dfa->charclasses, charclass, dfa->calloc, dfa->cindex);
+ ++dfa->cindex;
+ copyset(s, dfa->charclasses[i]);
return i;
}
/* Syntax bits controlling the behavior of the lexical analyzer. */
-static syntax_bits, syntax_bits_set;
+static reg_syntax_t syntax_bits, syntax_bits_set;
/* Flag for case-folding letters into sets. */
-static case_fold;
+static int case_fold;
/* Entry point to set syntax options. */
void
-regsyntax(bits, fold)
- long bits;
+dfasyntax(bits, fold)
+ reg_syntax_t bits;
int fold;
{
syntax_bits_set = 1;
@@ -325,63 +327,136 @@ regsyntax(bits, fold)
case_fold = fold;
}
-/* Lexical analyzer. */
-static const char *lexstart; /* Pointer to beginning of input string. */
-static const char *lexptr; /* Pointer to next input character. */
+/* Lexical analyzer. All the dross that deals with the obnoxious
+ GNU Regex syntax bits is located here. The poor, suffering
+ reader is referred to the GNU Regex documentation for the
+ meaning of the @#%!@#%^!@ syntax bits. */
+
+static char *lexstart; /* Pointer to beginning of input string. */
+static char *lexptr; /* Pointer to next input character. */
static lexleft; /* Number of characters remaining. */
-static caret_allowed; /* True if backward context allows ^
- (meaningful only if RE_CONTEXT_INDEP_OPS
- is turned off). */
-static closure_allowed; /* True if backward context allows closures
- (meaningful only if RE_CONTEXT_INDEP_OPS
- is turned off). */
+static token lasttok; /* Previous token returned; initially END. */
+static int laststart; /* True if we're separated from beginning or (, |
+ only by zero-width characters. */
+static int parens; /* Count of outstanding left parens. */
+static int minrep, maxrep; /* Repeat counts for {m,n}. */
/* Note that characters become unsigned here. */
#define FETCH(c, eoferr) \
{ \
if (! lexleft) \
- if (eoferr != NULL) \
- reg_error(eoferr); \
+ if (eoferr != 0) \
+ dfaerror(eoferr); \
else \
- return _END; \
+ return lasttok = END; \
(c) = (unsigned char) *lexptr++; \
--lexleft; \
}
-static _token
+#ifdef __STDC__
+#define FUNC(F, P) static int F(int c) { return P(c); }
+#else
+#define FUNC(F, P) static int F(c) int c; { return P(c); }
+#endif
+
+FUNC(is_alpha, ISALPHA)
+FUNC(is_upper, ISUPPER)
+FUNC(is_lower, ISLOWER)
+FUNC(is_digit, ISDIGIT)
+FUNC(is_xdigit, ISXDIGIT)
+FUNC(is_space, ISSPACE)
+FUNC(is_punct, ISPUNCT)
+FUNC(is_alnum, ISALNUM)
+FUNC(is_print, ISPRINT)
+FUNC(is_graph, ISGRAPH)
+FUNC(is_cntrl, ISCNTRL)
+
+/* The following list maps the names of the Posix named character classes
+ to predicate functions that determine whether a given character is in
+ the class. The leading [ has already been eaten by the lexical analyzer. */
+static struct {
+ const char *name;
+ int (*pred) _RE_ARGS((int));
+} prednames[] = {
+ { ":alpha:]", is_alpha },
+ { ":upper:]", is_upper },
+ { ":lower:]", is_lower },
+ { ":digit:]", is_digit },
+ { ":xdigit:]", is_xdigit },
+ { ":space:]", is_space },
+ { ":punct:]", is_punct },
+ { ":alnum:]", is_alnum },
+ { ":print:]", is_print },
+ { ":graph:]", is_graph },
+ { ":cntrl:]", is_cntrl },
+ { 0 }
+};
+
+static int
+looking_at(s)
+ const char *s;
+{
+ size_t len;
+
+ len = strlen(s);
+ if (lexleft < len)
+ return 0;
+ return strncmp(s, lexptr, len) == 0;
+}
+
+static token
lex()
{
- _token c, c2;
- int invert;
- _charset cset;
+ token c, c1, c2;
+ int backslash = 0, invert;
+ charclass ccl;
+ int i;
- FETCH(c, (char *) 0);
- switch (c)
+ /* Basic plan: We fetch a character. If it's a backslash,
+ we set the backslash flag and go through the loop again.
+ On the plus side, this avoids having a duplicate of the
+ main switch inside the backslash case. On the minus side,
+ it means that just about every case begins with
+ "if (backslash) ...". */
+ for (i = 0; i < 2; ++i)
{
- case '^':
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS)
- && (!caret_allowed ||
- ((syntax_bits & RE_TIGHT_VBAR) && lexptr - 1 != lexstart)))
- goto normal_char;
- caret_allowed = 0;
- return syntax_bits & RE_TIGHT_VBAR ? _ALLBEGLINE : _BEGLINE;
-
- case '$':
- if (syntax_bits & RE_CONTEXT_INDEP_OPS || !lexleft
- || (! (syntax_bits & RE_TIGHT_VBAR)
- && ((syntax_bits & RE_NO_BK_PARENS
- ? lexleft > 0 && *lexptr == ')'
- : lexleft > 1 && *lexptr == '\\' && lexptr[1] == ')')
- || (syntax_bits & RE_NO_BK_VBAR
- ? lexleft > 0 && *lexptr == '|'
- : lexleft > 1 && *lexptr == '\\' && lexptr[1] == '|'))))
- return syntax_bits & RE_TIGHT_VBAR ? _ALLENDLINE : _ENDLINE;
- goto normal_char;
-
- case '\\':
- FETCH(c, "Unfinished \\ quote");
+ FETCH(c, 0);
switch (c)
{
+ case '\\':
+ if (backslash)
+ goto normal_char;
+ if (lexleft == 0)
+ dfaerror("Unfinished \\ escape");
+ backslash = 1;
+ break;
+
+ case '^':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lasttok == END
+ || lasttok == LPAREN
+ || lasttok == OR)
+ return lasttok = BEGLINE;
+ goto normal_char;
+
+ case '$':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lexleft == 0
+ || (syntax_bits & RE_NO_BK_PARENS
+ ? lexleft > 0 && *lexptr == ')'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == ')')
+ || (syntax_bits & RE_NO_BK_VBAR
+ ? lexleft > 0 && *lexptr == '|'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == '|')
+ || ((syntax_bits & RE_NEWLINE_ALT)
+ && lexleft > 0 && *lexptr == '\n'))
+ return lasttok = ENDLINE;
+ goto normal_char;
+
case '1':
case '2':
case '3':
@@ -391,236 +466,315 @@ lex()
case '7':
case '8':
case '9':
- caret_allowed = 0;
- closure_allowed = 1;
- return _BACKREF;
+ if (backslash && !(syntax_bits & RE_NO_BK_REFS))
+ {
+ laststart = 0;
+ return lasttok = BACKREF;
+ }
+ goto normal_char;
case '<':
- caret_allowed = 0;
- return _BEGWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = BEGWORD;
+ goto normal_char;
case '>':
- caret_allowed = 0;
- return _ENDWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = ENDWORD;
+ goto normal_char;
case 'b':
- caret_allowed = 0;
- return _LIMWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = LIMWORD;
+ goto normal_char;
case 'B':
- caret_allowed = 0;
- return _NOTLIMWORD;
-
- case 'w':
- case 'W':
- zeroset(cset);
- for (c2 = 0; c2 < _NOTCHAR; ++c2)
- if (ISALNUM(c2))
- setbit(c2, cset);
- if (c == 'W')
- notset(cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = NOTLIMWORD;
+ goto normal_char;
case '?':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto qmark;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = QMARK;
+
+ case '*':
+ if (backslash)
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = STAR;
case '+':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto plus;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = PLUS;
+
+ case '{':
+ if (!(syntax_bits & RE_INTERVALS))
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_BRACES) == 0))
+ goto normal_char;
+ minrep = maxrep = 0;
+ /* Cases:
+ {M} - exact count
+ {M,} - minimum count, maximum is infinity
+ {,M} - 0 through M
+ {M,N} - M through N */
+ FETCH(c, "unfinished repeat count");
+ if (ISDIGIT(c))
+ {
+ minrep = c - '0';
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ minrep = 10 * minrep + c - '0';
+ }
+ }
+ else if (c != ',')
+ dfaerror("malformed repeat count");
+ if (c == ',')
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ maxrep = 10 * maxrep + c - '0';
+ }
+ else
+ maxrep = minrep;
+ if (!(syntax_bits & RE_NO_BK_BRACES))
+ {
+ if (c != '\\')
+ dfaerror("malformed repeat count");
+ FETCH(c, "unfinished repeat count");
+ }
+ if (c != '}')
+ dfaerror("malformed repeat count");
+ laststart = 0;
+ return lasttok = REPMN;
case '|':
- if (! (syntax_bits & RE_NO_BK_VBAR))
- goto or;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_VBAR) == 0))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
+
+ case '\n':
+ if (syntax_bits & RE_LIMITED_OPS
+ || backslash
+ || !(syntax_bits & RE_NEWLINE_ALT))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
case '(':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto lparen;
- goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ ++parens;
+ laststart = 1;
+ return lasttok = LPAREN;
case ')':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto rparen;
- goto normal_char;
-
- default:
- goto normal_char;
- }
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ if (parens == 0 && syntax_bits & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ --parens;
+ laststart = 0;
+ return lasttok = RPAREN;
+
+ case '.':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
+ notset(ccl);
+ if (!(syntax_bits & RE_DOT_NEWLINE))
+ clrbit('\n', ccl);
+ if (syntax_bits & RE_DOT_NOT_NULL)
+ clrbit('\0', ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
- case '?':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto normal_char;
- qmark:
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _QMARK;
-
- case '*':
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _STAR;
-
- case '+':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto normal_char;
- plus:
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _PLUS;
-
- case '|':
- if (! (syntax_bits & RE_NO_BK_VBAR))
- goto normal_char;
- or:
- caret_allowed = 1;
- closure_allowed = 0;
- return _OR;
-
- case '\n':
- if (! (syntax_bits & RE_NEWLINE_OR))
- goto normal_char;
- goto or;
-
- case '(':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto normal_char;
- lparen:
- caret_allowed = 1;
- closure_allowed = 0;
- return _LPAREN;
-
- case ')':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto normal_char;
- rparen:
- caret_allowed = 0;
- closure_allowed = 1;
- return _RPAREN;
-
- case '.':
- zeroset(cset);
- notset(cset);
- clrbit('\n', cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
-
- case '[':
- zeroset(cset);
- FETCH(c, "Unbalanced [");
- if (c == '^')
- {
+ case 'w':
+ case 'W':
+ if (!backslash || (syntax_bits & RE_NO_GNU_OPS))
+ goto normal_char;
+ zeroset(ccl);
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if (ISALNUM(c2))
+ setbit(c2, ccl);
+ if (c == 'W')
+ notset(ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
+
+ case '[':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
FETCH(c, "Unbalanced [");
- invert = 1;
- }
- else
- invert = 0;
- do
- {
- FETCH(c2, "Unbalanced [");
- if ((syntax_bits & RE_AWK_CLASS_HACK) && c == '\\')
+ if (c == '^')
{
- c = c2;
- FETCH(c2, "Unbalanced [");
+ FETCH(c, "Unbalanced [");
+ invert = 1;
}
- if (c2 == '-')
+ else
+ invert = 0;
+ do
{
- FETCH(c2, "Unbalanced [");
- if (c2 == ']' && (syntax_bits & RE_AWK_CLASS_HACK))
+ /* Nobody ever said this had to be fast. :-)
+ Note that if we're looking at some other [:...:]
+ construct, we just treat it as a bunch of ordinary
+ characters. We can do this because we assume
+ regex has checked for syntax errors before
+ dfa is ever called. */
+ if (c == '[' && (syntax_bits & RE_CHAR_CLASSES))
+ for (c1 = 0; prednames[c1].name; ++c1)
+ if (looking_at(prednames[c1].name))
+ {
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if ((*prednames[c1].pred)(c2))
+ setbit(c2, ccl);
+ lexptr += strlen(prednames[c1].name);
+ lexleft -= strlen(prednames[c1].name);
+ FETCH(c1, "Unbalanced [");
+ goto skip;
+ }
+ if (c == '\\' && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ if (c1 == '-')
{
- setbit(c, cset);
- setbit('-', cset);
- break;
- }
+ FETCH(c2, "Unbalanced [");
+ if (c2 == ']')
+ {
+ /* In the case [x-], the - is an ordinary hyphen,
+ which is left in c1, the lookahead character. */
+ --lexptr;
+ ++lexleft;
+ c2 = c;
+ }
+ else
+ {
+ if (c2 == '\\'
+ && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c2, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ }
+ }
+ else
+ c2 = c;
while (c <= c2)
- setbit(c++, cset);
- FETCH(c, "Unbalanced [");
+ {
+ setbit(c, ccl);
+ if (case_fold)
+ if (ISUPPER(c))
+ setbit(tolower(c), ccl);
+ else if (ISLOWER(c))
+ setbit(toupper(c), ccl);
+ ++c;
+ }
+ skip:
+ ;
}
- else
+ while ((c = c1) != ']');
+ if (invert)
{
- setbit(c, cset);
- c = c2;
+ notset(ccl);
+ if (syntax_bits & RE_HAT_LISTS_NOT_NEWLINE)
+ clrbit('\n', ccl);
}
- }
- while (c != ']');
- if (invert)
- notset(cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
- default:
- normal_char:
- caret_allowed = 0;
- closure_allowed = 1;
- if (case_fold && ISALPHA(c))
- {
- zeroset(cset);
- if (isupper(c))
- c = tolower(c);
- setbit(c, cset);
- setbit(toupper(c), cset);
- return _SET + charset_index(cset);
+ default:
+ normal_char:
+ laststart = 0;
+ if (case_fold && ISALPHA(c))
+ {
+ zeroset(ccl);
+ setbit(c, ccl);
+ if (isupper(c))
+ setbit(tolower(c), ccl);
+ else
+ setbit(toupper(c), ccl);
+ return lasttok = CSET + charclass_index(ccl);
+ }
+ return c;
}
- return c;
}
+
+ /* The above loop should consume at most a backslash
+ and some other character. */
+ abort();
}
-
+
/* Recursive descent parser for regular expressions. */
-static _token tok; /* Lookahead token. */
+static token tok; /* Lookahead token. */
static depth; /* Current depth of a hypothetical stack
holding deferred productions. This is
used to determine the depth that will be
required of the real stack later on in
- reganalyze(). */
+ dfaanalyze(). */
/* Add the given token to the parse tree, maintaining the depth count and
updating the maximum depth if necessary. */
static void
addtok(t)
- _token t;
+ token t;
{
- REALLOC_IF_NECESSARY(reg->tokens, _token, reg->talloc, reg->tindex);
- reg->tokens[reg->tindex++] = t;
+ REALLOC_IF_NECESSARY(dfa->tokens, token, dfa->talloc, dfa->tindex);
+ dfa->tokens[dfa->tindex++] = t;
switch (t)
{
- case _QMARK:
- case _STAR:
- case _PLUS:
+ case QMARK:
+ case STAR:
+ case PLUS:
break;
- case _CAT:
- case _OR:
+ case CAT:
+ case OR:
+ case ORTOP:
--depth;
break;
default:
- ++reg->nleaves;
- case _EMPTY:
+ ++dfa->nleaves;
+ case EMPTY:
++depth;
break;
}
- if (depth > reg->depth)
- reg->depth = depth;
+ if (depth > dfa->depth)
+ dfa->depth = depth;
}
/* The grammar understood by the parser is as follows.
- start:
- regexp
- _ALLBEGLINE regexp
- regexp _ALLENDLINE
- _ALLBEGLINE regexp _ALLENDLINE
-
regexp:
- regexp _OR branch
+ regexp OR branch
branch
branch:
@@ -628,144 +782,187 @@ addtok(t)
closure
closure:
- closure _QMARK
- closure _STAR
- closure _PLUS
+ closure QMARK
+ closure STAR
+ closure PLUS
atom
atom:
<normal character>
- _SET
- _BACKREF
- _BEGLINE
- _ENDLINE
- _BEGWORD
- _ENDWORD
- _LIMWORD
- _NOTLIMWORD
+ CSET
+ BACKREF
+ BEGLINE
+ ENDLINE
+ BEGWORD
+ ENDWORD
+ LIMWORD
+ NOTLIMWORD
<empty>
The parser builds a parse tree in postfix form in an array of tokens. */
-#ifdef __STDC__
-static void regexp(void);
-#else
-static void regexp();
-#endif
-
static void
atom()
{
- if (tok >= 0 && (tok < _NOTCHAR || tok >= _SET || tok == _BACKREF
- || tok == _BEGLINE || tok == _ENDLINE || tok == _BEGWORD
- || tok == _ENDWORD || tok == _LIMWORD || tok == _NOTLIMWORD))
+ if ((tok >= 0 && tok < NOTCHAR) || tok >= CSET || tok == BACKREF
+ || tok == BEGLINE || tok == ENDLINE || tok == BEGWORD
+ || tok == ENDWORD || tok == LIMWORD || tok == NOTLIMWORD)
{
addtok(tok);
tok = lex();
}
- else if (tok == _LPAREN)
+ else if (tok == LPAREN)
{
tok = lex();
- regexp();
- if (tok != _RPAREN)
- reg_error("Unbalanced (");
+ regexp(0);
+ if (tok != RPAREN)
+ dfaerror("Unbalanced (");
tok = lex();
}
else
- addtok(_EMPTY);
+ addtok(EMPTY);
+}
+
+/* Return the number of tokens in the given subexpression. */
+static int
+nsubtoks(tindex)
+int tindex;
+{
+ int ntoks1;
+
+ switch (dfa->tokens[tindex - 1])
+ {
+ default:
+ return 1;
+ case QMARK:
+ case STAR:
+ case PLUS:
+ return 1 + nsubtoks(tindex - 1);
+ case CAT:
+ case OR:
+ case ORTOP:
+ ntoks1 = nsubtoks(tindex - 1);
+ return 1 + ntoks1 + nsubtoks(tindex - 1 - ntoks1);
+ }
+}
+
+/* Copy the given subexpression to the top of the tree. */
+static void
+copytoks(tindex, ntokens)
+ int tindex, ntokens;
+{
+ int i;
+
+ for (i = 0; i < ntokens; ++i)
+ addtok(dfa->tokens[tindex + i]);
}
static void
closure()
{
+ int tindex, ntokens, i;
+
atom();
- while (tok == _QMARK || tok == _STAR || tok == _PLUS)
- {
- addtok(tok);
- tok = lex();
- }
+ while (tok == QMARK || tok == STAR || tok == PLUS || tok == REPMN)
+ if (tok == REPMN)
+ {
+ ntokens = nsubtoks(dfa->tindex);
+ tindex = dfa->tindex - ntokens;
+ if (maxrep == 0)
+ addtok(PLUS);
+ if (minrep == 0)
+ addtok(QMARK);
+ for (i = 1; i < minrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(CAT);
+ }
+ for (; i < maxrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(QMARK);
+ addtok(CAT);
+ }
+ tok = lex();
+ }
+ else
+ {
+ addtok(tok);
+ tok = lex();
+ }
}
static void
branch()
{
closure();
- while (tok != _RPAREN && tok != _OR && tok != _ALLENDLINE && tok >= 0)
+ while (tok != RPAREN && tok != OR && tok >= 0)
{
closure();
- addtok(_CAT);
+ addtok(CAT);
}
}
static void
-regexp()
+regexp(toplevel)
+ int toplevel;
{
branch();
- while (tok == _OR)
+ while (tok == OR)
{
tok = lex();
branch();
- addtok(_OR);
+ if (toplevel)
+ addtok(ORTOP);
+ else
+ addtok(OR);
}
}
/* Main entry point for the parser. S is a string to be parsed, len is the
- length of the string, so s can include NUL characters. R is a pointer to
- the struct regexp to parse into. */
+ length of the string, so s can include NUL characters. D is a pointer to
+ the struct dfa to parse into. */
void
-regparse(s, len, r)
- const char *s;
+dfaparse(s, len, d)
+ char *s;
size_t len;
- struct regexp *r;
+ struct dfa *d;
+
{
- reg = r;
+ dfa = d;
lexstart = lexptr = s;
lexleft = len;
- caret_allowed = 1;
- closure_allowed = 0;
+ lasttok = END;
+ laststart = 1;
+ parens = 0;
if (! syntax_bits_set)
- reg_error("No syntax specified");
+ dfaerror("No syntax specified");
tok = lex();
- depth = r->depth;
+ depth = d->depth;
- if (tok == _ALLBEGLINE)
- {
- addtok(_BEGLINE);
- tok = lex();
- regexp();
- addtok(_CAT);
- }
- else
- regexp();
+ regexp(1);
- if (tok == _ALLENDLINE)
- {
- addtok(_ENDLINE);
- addtok(_CAT);
- tok = lex();
- }
+ if (tok != END)
+ dfaerror("Unbalanced )");
- if (tok != _END)
- reg_error("Unbalanced )");
+ addtok(END - d->nregexps);
+ addtok(CAT);
- addtok(_END - r->nregexps);
- addtok(_CAT);
+ if (d->nregexps)
+ addtok(ORTOP);
- if (r->nregexps)
- addtok(_OR);
-
- ++r->nregexps;
+ ++d->nregexps;
}
-
+
/* Some primitives for operating on sets of positions. */
/* Copy one set to another; the destination must be large enough. */
static void
copy(src, dst)
- const _position_set *src;
- _position_set *dst;
+ position_set *src;
+ position_set *dst;
{
int i;
@@ -780,14 +977,14 @@ copy(src, dst)
S->elems must point to an array large enough to hold the resulting set. */
static void
insert(p, s)
- _position p;
- _position_set *s;
+ position p;
+ position_set *s;
{
int i;
- _position t1, t2;
+ position t1, t2;
for (i = 0; i < s->nelem && p.index < s->elems[i].index; ++i)
- ;
+ continue;
if (i < s->nelem && p.index == s->elems[i].index)
s->elems[i].constraint |= p.constraint;
else
@@ -807,9 +1004,9 @@ insert(p, s)
the positions of both sets were inserted into an initially empty set. */
static void
merge(s1, s2, m)
- _position_set *s1;
- _position_set *s2;
- _position_set *m;
+ position_set *s1;
+ position_set *s2;
+ position_set *m;
{
int i = 0, j = 0;
@@ -833,8 +1030,8 @@ merge(s1, s2, m)
/* Delete a position from a set. */
static void
delete(p, s)
- _position p;
- _position_set *s;
+ position p;
+ position_set *s;
{
int i;
@@ -845,19 +1042,19 @@ delete(p, s)
for (--s->nelem; i < s->nelem; ++i)
s->elems[i] = s->elems[i + 1];
}
-
+
/* Find the index of the state corresponding to the given position set with
the given preceding context, or create a new state if there is no such
state. Newline and letter tell whether we got here on a newline or
letter, respectively. */
static int
-state_index(r, s, newline, letter)
- struct regexp *r;
- _position_set *s;
+state_index(d, s, newline, letter)
+ struct dfa *d;
+ position_set *s;
int newline;
int letter;
{
- int lhash = 0;
+ int hash = 0;
int constraint;
int i, j;
@@ -865,78 +1062,80 @@ state_index(r, s, newline, letter)
letter = letter ? 1 : 0;
for (i = 0; i < s->nelem; ++i)
- lhash ^= s->elems[i].index + s->elems[i].constraint;
+ hash ^= s->elems[i].index + s->elems[i].constraint;
/* Try to find a state that exactly matches the proposed one. */
- for (i = 0; i < r->sindex; ++i)
+ for (i = 0; i < d->sindex; ++i)
{
- if (lhash != r->states[i].hash || s->nelem != r->states[i].elems.nelem
- || newline != r->states[i].newline || letter != r->states[i].letter)
+ if (hash != d->states[i].hash || s->nelem != d->states[i].elems.nelem
+ || newline != d->states[i].newline || letter != d->states[i].letter)
continue;
for (j = 0; j < s->nelem; ++j)
if (s->elems[j].constraint
- != r->states[i].elems.elems[j].constraint
- || s->elems[j].index != r->states[i].elems.elems[j].index)
+ != d->states[i].elems.elems[j].constraint
+ || s->elems[j].index != d->states[i].elems.elems[j].index)
break;
if (j == s->nelem)
return i;
}
/* We'll have to create a new state. */
- REALLOC_IF_NECESSARY(r->states, _dfa_state, r->salloc, r->sindex);
- r->states[i].hash = lhash;
- MALLOC(r->states[i].elems.elems, _position, s->nelem);
- copy(s, &r->states[i].elems);
- r->states[i].newline = newline;
- r->states[i].letter = letter;
- r->states[i].backref = 0;
- r->states[i].constraint = 0;
- r->states[i].first_end = 0;
+ REALLOC_IF_NECESSARY(d->states, dfa_state, d->salloc, d->sindex);
+ d->states[i].hash = hash;
+ MALLOC(d->states[i].elems.elems, position, s->nelem);
+ copy(s, &d->states[i].elems);
+ d->states[i].newline = newline;
+ d->states[i].letter = letter;
+ d->states[i].backref = 0;
+ d->states[i].constraint = 0;
+ d->states[i].first_end = 0;
for (j = 0; j < s->nelem; ++j)
- if (r->tokens[s->elems[j].index] < 0)
+ if (d->tokens[s->elems[j].index] < 0)
{
constraint = s->elems[j].constraint;
- if (_SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 0)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 1)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 0)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 1))
- r->states[i].constraint |= constraint;
- if (! r->states[i].first_end)
- r->states[i].first_end = r->tokens[s->elems[j].index];
+ if (SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 1)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 1))
+ d->states[i].constraint |= constraint;
+ if (! d->states[i].first_end)
+ d->states[i].first_end = d->tokens[s->elems[j].index];
}
- else if (r->tokens[s->elems[j].index] == _BACKREF)
+ else if (d->tokens[s->elems[j].index] == BACKREF)
{
- r->states[i].constraint = _NO_CONSTRAINT;
- r->states[i].backref = 1;
+ d->states[i].constraint = NO_CONSTRAINT;
+ d->states[i].backref = 1;
}
- ++r->sindex;
+ ++d->sindex;
return i;
}
-
+
/* Find the epsilon closure of a set of positions. If any position of the set
contains a symbol that matches the empty string in some context, replace
that position with the elements of its follow labeled with an appropriate
constraint. Repeat exhaustively until no funny positions are left.
S->elems must be large enough to hold the result. */
+static void epsclosure _RE_ARGS((position_set *s, struct dfa *d));
+
static void
-epsclosure(s, r)
- _position_set *s;
- struct regexp *r;
+epsclosure(s, d)
+ position_set *s;
+ struct dfa *d;
{
int i, j;
int *visited;
- _position p, old;
+ position p, old;
- MALLOC(visited, int, r->tindex);
- for (i = 0; i < r->tindex; ++i)
+ MALLOC(visited, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
visited[i] = 0;
for (i = 0; i < s->nelem; ++i)
- if (r->tokens[s->elems[i].index] >= _NOTCHAR
- && r->tokens[s->elems[i].index] != _BACKREF
- && r->tokens[s->elems[i].index] < _SET)
+ if (d->tokens[s->elems[i].index] >= NOTCHAR
+ && d->tokens[s->elems[i].index] != BACKREF
+ && d->tokens[s->elems[i].index] < CSET)
{
old = s->elems[i];
p.constraint = old.constraint;
@@ -947,32 +1146,32 @@ epsclosure(s, r)
continue;
}
visited[old.index] = 1;
- switch (r->tokens[old.index])
+ switch (d->tokens[old.index])
{
- case _BEGLINE:
- p.constraint &= _BEGLINE_CONSTRAINT;
+ case BEGLINE:
+ p.constraint &= BEGLINE_CONSTRAINT;
break;
- case _ENDLINE:
- p.constraint &= _ENDLINE_CONSTRAINT;
+ case ENDLINE:
+ p.constraint &= ENDLINE_CONSTRAINT;
break;
- case _BEGWORD:
- p.constraint &= _BEGWORD_CONSTRAINT;
+ case BEGWORD:
+ p.constraint &= BEGWORD_CONSTRAINT;
break;
- case _ENDWORD:
- p.constraint &= _ENDWORD_CONSTRAINT;
+ case ENDWORD:
+ p.constraint &= ENDWORD_CONSTRAINT;
break;
- case _LIMWORD:
- p.constraint &= _ENDWORD_CONSTRAINT;
+ case LIMWORD:
+ p.constraint &= LIMWORD_CONSTRAINT;
break;
- case _NOTLIMWORD:
- p.constraint &= _NOTLIMWORD_CONSTRAINT;
+ case NOTLIMWORD:
+ p.constraint &= NOTLIMWORD_CONSTRAINT;
break;
default:
break;
}
- for (j = 0; j < r->follows[old.index].nelem; ++j)
+ for (j = 0; j < d->follows[old.index].nelem; ++j)
{
- p.index = r->follows[old.index].elems[j].index;
+ p.index = d->follows[old.index].elems[j].index;
insert(p, s);
}
/* Force rescan to start at the beginning. */
@@ -981,41 +1180,41 @@ epsclosure(s, r)
free(visited);
}
-
+
/* Perform bottom-up analysis on the parse tree, computing various functions.
Note that at this point, we're pretending constructs like \< are real
characters rather than constraints on what can follow them.
Nullable: A node is nullable if it is at the root of a regexp that can
match the empty string.
- * _EMPTY leaves are nullable.
+ * EMPTY leaves are nullable.
* No other leaf is nullable.
- * A _QMARK or _STAR node is nullable.
- * A _PLUS node is nullable if its argument is nullable.
- * A _CAT node is nullable if both its arguments are nullable.
- * An _OR node is nullable if either argument is nullable.
+ * A QMARK or STAR node is nullable.
+ * A PLUS node is nullable if its argument is nullable.
+ * A CAT node is nullable if both its arguments are nullable.
+ * An OR node is nullable if either argument is nullable.
Firstpos: The firstpos of a node is the set of positions (nonempty leaves)
that could correspond to the first character of a string matching the
regexp rooted at the given node.
- * _EMPTY leaves have empty firstpos.
+ * EMPTY leaves have empty firstpos.
* The firstpos of a nonempty leaf is that leaf itself.
- * The firstpos of a _QMARK, _STAR, or _PLUS node is the firstpos of its
+ * The firstpos of a QMARK, STAR, or PLUS node is the firstpos of its
argument.
- * The firstpos of a _CAT node is the firstpos of the left argument, union
+ * The firstpos of a CAT node is the firstpos of the left argument, union
the firstpos of the right if the left argument is nullable.
- * The firstpos of an _OR node is the union of firstpos of each argument.
+ * The firstpos of an OR node is the union of firstpos of each argument.
Lastpos: The lastpos of a node is the set of positions that could
correspond to the last character of a string matching the regexp at
the given node.
- * _EMPTY leaves have empty lastpos.
+ * EMPTY leaves have empty lastpos.
* The lastpos of a nonempty leaf is that leaf itself.
- * The lastpos of a _QMARK, _STAR, or _PLUS node is the lastpos of its
+ * The lastpos of a QMARK, STAR, or PLUS node is the lastpos of its
argument.
- * The lastpos of a _CAT node is the lastpos of its right argument, union
+ * The lastpos of a CAT node is the lastpos of its right argument, union
the lastpos of the left if the right argument is nullable.
- * The lastpos of an _OR node is the union of the lastpos of each argument.
+ * The lastpos of an OR node is the union of the lastpos of each argument.
Follow: The follow of a position is the set of positions that could
correspond to the character following a character matching the node in
@@ -1024,9 +1223,9 @@ epsclosure(s, r)
Later, if we find that a special symbol is in a follow set, we will
replace it with the elements of its follow, labeled with an appropriate
constraint.
- * Every node in the firstpos of the argument of a _STAR or _PLUS node is in
+ * Every node in the firstpos of the argument of a STAR or PLUS node is in
the follow of every node in the lastpos.
- * Every node in the firstpos of the second argument of a _CAT node is in
+ * Every node in the firstpos of the second argument of a CAT node is in
the follow of every node in the lastpos of the first argument.
Because of the postfix representation of the parse tree, the depth-first
@@ -1035,48 +1234,61 @@ epsclosure(s, r)
scheme; the number of elements in each set deeper in the stack can be
used to determine the address of a particular set's array. */
void
-reganalyze(r, searchflag)
- struct regexp *r;
+dfaanalyze(d, searchflag)
+ struct dfa *d;
int searchflag;
{
int *nullable; /* Nullable stack. */
int *nfirstpos; /* Element count stack for firstpos sets. */
- _position *firstpos; /* Array where firstpos elements are stored. */
+ position *firstpos; /* Array where firstpos elements are stored. */
int *nlastpos; /* Element count stack for lastpos sets. */
- _position *lastpos; /* Array where lastpos elements are stored. */
+ position *lastpos; /* Array where lastpos elements are stored. */
int *nalloc; /* Sizes of arrays allocated to follow sets. */
- _position_set tmp; /* Temporary set for merging sets. */
- _position_set merged; /* Result of merging sets. */
+ position_set tmp; /* Temporary set for merging sets. */
+ position_set merged; /* Result of merging sets. */
int wants_newline; /* True if some position wants newline info. */
int *o_nullable;
int *o_nfirst, *o_nlast;
- _position *o_firstpos, *o_lastpos;
+ position *o_firstpos, *o_lastpos;
int i, j;
- _position *pos;
+ position *pos;
- r->searchflag = searchflag;
+#ifdef DEBUG
+ fprintf(stderr, "dfaanalyze:\n");
+ for (i = 0; i < d->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(d->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
- MALLOC(nullable, int, r->depth);
+ d->searchflag = searchflag;
+
+ MALLOC(nullable, int, d->depth);
o_nullable = nullable;
- MALLOC(nfirstpos, int, r->depth);
+ MALLOC(nfirstpos, int, d->depth);
o_nfirst = nfirstpos;
- MALLOC(firstpos, _position, r->nleaves);
- o_firstpos = firstpos, firstpos += r->nleaves;
- MALLOC(nlastpos, int, r->depth);
+ MALLOC(firstpos, position, d->nleaves);
+ o_firstpos = firstpos, firstpos += d->nleaves;
+ MALLOC(nlastpos, int, d->depth);
o_nlast = nlastpos;
- MALLOC(lastpos, _position, r->nleaves);
- o_lastpos = lastpos, lastpos += r->nleaves;
- MALLOC(nalloc, int, r->tindex);
- for (i = 0; i < r->tindex; ++i)
+ MALLOC(lastpos, position, d->nleaves);
+ o_lastpos = lastpos, lastpos += d->nleaves;
+ MALLOC(nalloc, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
nalloc[i] = 0;
- MALLOC(merged.elems, _position, r->nleaves);
+ MALLOC(merged.elems, position, d->nleaves);
- CALLOC(r->follows, _position_set, r->tindex);
+ CALLOC(d->follows, position_set, d->tindex);
- for (i = 0; i < r->tindex; ++i)
- switch (r->tokens[i])
+ for (i = 0; i < d->tindex; ++i)
+#ifdef DEBUG
+ { /* Nonsyntactic #ifdef goo... */
+#endif
+ switch (d->tokens[i])
{
- case _EMPTY:
+ case EMPTY:
/* The empty set is nullable. */
*nullable++ = 1;
@@ -1084,8 +1296,8 @@ reganalyze(r, searchflag)
*nfirstpos++ = *nlastpos++ = 0;
break;
- case _STAR:
- case _PLUS:
+ case STAR:
+ case PLUS:
/* Every element in the firstpos of the argument is in the follow
of every element in the lastpos. */
tmp.nelem = nfirstpos[-1];
@@ -1093,19 +1305,19 @@ reganalyze(r, searchflag)
pos = lastpos;
for (j = 0; j < nlastpos[-1]; ++j)
{
- merge(&tmp, &r->follows[pos[j].index], &merged);
- REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position,
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
nalloc[pos[j].index], merged.nelem - 1);
- copy(&merged, &r->follows[pos[j].index]);
+ copy(&merged, &d->follows[pos[j].index]);
}
- case _QMARK:
- /* A _QMARK or _STAR node is automatically nullable. */
- if (r->tokens[i] != _PLUS)
+ case QMARK:
+ /* A QMARK or STAR node is automatically nullable. */
+ if (d->tokens[i] != PLUS)
nullable[-1] = 1;
break;
- case _CAT:
+ case CAT:
/* Every element in the firstpos of the second argument is in the
follow of every element in the lastpos of the first argument. */
tmp.nelem = nfirstpos[-1];
@@ -1113,13 +1325,13 @@ reganalyze(r, searchflag)
pos = lastpos + nlastpos[-1];
for (j = 0; j < nlastpos[-2]; ++j)
{
- merge(&tmp, &r->follows[pos[j].index], &merged);
- REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position,
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
nalloc[pos[j].index], merged.nelem - 1);
- copy(&merged, &r->follows[pos[j].index]);
+ copy(&merged, &d->follows[pos[j].index]);
}
- /* The firstpos of a _CAT node is the firstpos of the first argument,
+ /* The firstpos of a CAT node is the firstpos of the first argument,
union that of the second argument if the first is nullable. */
if (nullable[-2])
nfirstpos[-2] += nfirstpos[-1];
@@ -1127,7 +1339,7 @@ reganalyze(r, searchflag)
firstpos += nfirstpos[-1];
--nfirstpos;
- /* The lastpos of a _CAT node is the lastpos of the second argument,
+ /* The lastpos of a CAT node is the lastpos of the second argument,
union that of the first argument if the second is nullable. */
if (nullable[-1])
nlastpos[-2] += nlastpos[-1];
@@ -1141,12 +1353,13 @@ reganalyze(r, searchflag)
}
--nlastpos;
- /* A _CAT node is nullable if both arguments are nullable. */
+ /* A CAT node is nullable if both arguments are nullable. */
nullable[-2] = nullable[-1] && nullable[-2];
--nullable;
break;
- case _OR:
+ case OR:
+ case ORTOP:
/* The firstpos is the union of the firstpos of each argument. */
nfirstpos[-2] += nfirstpos[-1];
--nfirstpos;
@@ -1155,7 +1368,7 @@ reganalyze(r, searchflag)
nlastpos[-2] += nlastpos[-1];
--nlastpos;
- /* An _OR node is nullable if either argument is nullable. */
+ /* An OR node is nullable if either argument is nullable. */
nullable[-2] = nullable[-1] || nullable[-2];
--nullable;
break;
@@ -1166,31 +1379,63 @@ reganalyze(r, searchflag)
an "epsilon closure" effectively makes them nullable later.
Backreferences have to get a real position so we can detect
transitions on them later. But they are nullable. */
- *nullable++ = r->tokens[i] == _BACKREF;
+ *nullable++ = d->tokens[i] == BACKREF;
/* This position is in its own firstpos and lastpos. */
*nfirstpos++ = *nlastpos++ = 1;
--firstpos, --lastpos;
firstpos->index = lastpos->index = i;
- firstpos->constraint = lastpos->constraint = _NO_CONSTRAINT;
+ firstpos->constraint = lastpos->constraint = NO_CONSTRAINT;
/* Allocate the follow set for this position. */
nalloc[i] = 1;
- MALLOC(r->follows[i].elems, _position, nalloc[i]);
+ MALLOC(d->follows[i].elems, position, nalloc[i]);
break;
}
+#ifdef DEBUG
+ /* ... balance the above nonsyntactic #ifdef goo... */
+ fprintf(stderr, "node %d:", i);
+ prtok(d->tokens[i]);
+ putc('\n', stderr);
+ fprintf(stderr, nullable[-1] ? " nullable: yes\n" : " nullable: no\n");
+ fprintf(stderr, " firstpos:");
+ for (j = nfirstpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", firstpos[j].index);
+ prtok(d->tokens[firstpos[j].index]);
+ }
+ fprintf(stderr, "\n lastpos:");
+ for (j = nlastpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", lastpos[j].index);
+ prtok(d->tokens[lastpos[j].index]);
+ }
+ putc('\n', stderr);
+ }
+#endif
/* For each follow set that is the follow set of a real position, replace
it with its epsilon closure. */
- for (i = 0; i < r->tindex; ++i)
- if (r->tokens[i] < _NOTCHAR || r->tokens[i] == _BACKREF
- || r->tokens[i] >= _SET)
+ for (i = 0; i < d->tindex; ++i)
+ if (d->tokens[i] < NOTCHAR || d->tokens[i] == BACKREF
+ || d->tokens[i] >= CSET)
{
- copy(&r->follows[i], &merged);
- epsclosure(&merged, r);
- if (r->follows[i].nelem < merged.nelem)
- REALLOC(r->follows[i].elems, _position, merged.nelem);
- copy(&merged, &r->follows[i]);
+#ifdef DEBUG
+ fprintf(stderr, "follows(%d:", i);
+ prtok(d->tokens[i]);
+ fprintf(stderr, "):");
+ for (j = d->follows[i].nelem - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", d->follows[i].elems[j].index);
+ prtok(d->tokens[d->follows[i].elems[j].index]);
+ }
+ putc('\n', stderr);
+#endif
+ copy(&d->follows[i], &merged);
+ epsclosure(&merged, d);
+ if (d->follows[i].nelem < merged.nelem)
+ REALLOC(d->follows[i].elems, position, merged.nelem);
+ copy(&merged, &d->follows[i]);
}
/* Get the epsilon closure of the firstpos of the regexp. The result will
@@ -1198,19 +1443,19 @@ reganalyze(r, searchflag)
merged.nelem = 0;
for (i = 0; i < nfirstpos[-1]; ++i)
insert(firstpos[i], &merged);
- epsclosure(&merged, r);
+ epsclosure(&merged, d);
/* Check if any of the positions of state 0 will want newline context. */
wants_newline = 0;
for (i = 0; i < merged.nelem; ++i)
- if (_PREV_NEWLINE_DEPENDENT(merged.elems[i].constraint))
+ if (PREV_NEWLINE_DEPENDENT(merged.elems[i].constraint))
wants_newline = 1;
/* Build the initial state. */
- r->salloc = 1;
- r->sindex = 0;
- MALLOC(r->states, _dfa_state, r->salloc);
- state_index(r, &merged, wants_newline, 0);
+ d->salloc = 1;
+ d->sindex = 0;
+ MALLOC(d->states, dfa_state, d->salloc);
+ state_index(d, &merged, wants_newline, 0);
free(o_nullable);
free(o_nfirst);
@@ -1220,8 +1465,8 @@ reganalyze(r, searchflag)
free(nalloc);
free(merged.elems);
}
-
-/* Find, for each character, the transition out of state s of r, and store
+
+/* Find, for each character, the transition out of state s of d, and store
it in the appropriate slot of trans.
We divide the positions of s into groups (positions can appear in more
@@ -1252,25 +1497,25 @@ reganalyze(r, searchflag)
create a new group labeled with the characters of C and insert this
position in that group. */
void
-regstate(s, r, trans)
+dfastate(s, d, trans)
int s;
- struct regexp *r;
+ struct dfa *d;
int trans[];
{
- _position_set grps[_NOTCHAR]; /* As many as will ever be needed. */
- _charset labels[_NOTCHAR]; /* Labels corresponding to the groups. */
+ position_set grps[NOTCHAR]; /* As many as will ever be needed. */
+ charclass labels[NOTCHAR]; /* Labels corresponding to the groups. */
int ngrps = 0; /* Number of groups actually used. */
- _position pos; /* Current position being considered. */
- _charset matches; /* Set of matching characters. */
+ position pos; /* Current position being considered. */
+ charclass matches; /* Set of matching characters. */
int matchesf; /* True if matches is nonempty. */
- _charset intersect; /* Intersection with some label set. */
+ charclass intersect; /* Intersection with some label set. */
int intersectf; /* True if intersect is nonempty. */
- _charset leftovers; /* Stuff in the label that didn't match. */
+ charclass leftovers; /* Stuff in the label that didn't match. */
int leftoversf; /* True if leftovers is nonempty. */
- static _charset letters; /* Set of characters considered letters. */
- static _charset newline; /* Set of characters that aren't newline. */
- _position_set follows; /* Union of the follows of some group. */
- _position_set tmp; /* Temporary space for merging sets. */
+ static charclass letters; /* Set of characters considered letters. */
+ static charclass newline; /* Set of characters that aren't newline. */
+ position_set follows; /* Union of the follows of some group. */
+ position_set tmp; /* Temporary space for merging sets. */
int state; /* New state. */
int wants_newline; /* New state wants to know newline context. */
int state_newline; /* New state on a newline transition. */
@@ -1283,7 +1528,7 @@ regstate(s, r, trans)
if (! initialized)
{
initialized = 1;
- for (i = 0; i < _NOTCHAR; ++i)
+ for (i = 0; i < NOTCHAR; ++i)
if (ISALNUM(i))
setbit(i, letters);
setbit('\n', newline);
@@ -1291,40 +1536,40 @@ regstate(s, r, trans)
zeroset(matches);
- for (i = 0; i < r->states[s].elems.nelem; ++i)
+ for (i = 0; i < d->states[s].elems.nelem; ++i)
{
- pos = r->states[s].elems.elems[i];
- if (r->tokens[pos.index] >= 0 && r->tokens[pos.index] < _NOTCHAR)
- setbit(r->tokens[pos.index], matches);
- else if (r->tokens[pos.index] >= _SET)
- copyset(r->charsets[r->tokens[pos.index] - _SET], matches);
+ pos = d->states[s].elems.elems[i];
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR)
+ setbit(d->tokens[pos.index], matches);
+ else if (d->tokens[pos.index] >= CSET)
+ copyset(d->charclasses[d->tokens[pos.index] - CSET], matches);
else
continue;
- /* Some characters may need to be climinated from matches because
+ /* Some characters may need to be eliminated from matches because
they fail in the current context. */
- if (pos.constraint != 0xff)
+ if (pos.constraint != 0xFF)
{
- if (! _MATCHES_NEWLINE_CONTEXT(pos.constraint,
- r->states[s].newline, 1))
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 1))
clrbit('\n', matches);
- if (! _MATCHES_NEWLINE_CONTEXT(pos.constraint,
- r->states[s].newline, 0))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= newline[j];
- if (! _MATCHES_LETTER_CONTEXT(pos.constraint,
- r->states[s].letter, 1))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 1))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= ~letters[j];
- if (! _MATCHES_LETTER_CONTEXT(pos.constraint,
- r->states[s].letter, 0))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= letters[j];
/* If there are no characters left, there's no point in going on. */
- for (j = 0; j < _CHARSET_INTS && !matches[j]; ++j)
- ;
- if (j == _CHARSET_INTS)
+ for (j = 0; j < CHARCLASS_INTS && !matches[j]; ++j)
+ continue;
+ if (j == CHARCLASS_INTS)
continue;
}
@@ -1333,27 +1578,27 @@ regstate(s, r, trans)
/* If matches contains a single character only, and the current
group's label doesn't contain that character, go on to the
next group. */
- if (r->tokens[pos.index] >= 0 && r->tokens[pos.index] < _NOTCHAR
- && !tstbit(r->tokens[pos.index], labels[j]))
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR
+ && !tstbit(d->tokens[pos.index], labels[j]))
continue;
/* Check if this group's label has a nonempty intersection with
matches. */
intersectf = 0;
- for (k = 0; k < _CHARSET_INTS; ++k)
- (intersect[k] = matches[k] & labels[j][k]) ? intersectf = 1 : 0;
+ for (k = 0; k < CHARCLASS_INTS; ++k)
+ (intersect[k] = matches[k] & labels[j][k]) ? (intersectf = 1) : 0;
if (! intersectf)
continue;
/* It does; now find the set differences both ways. */
leftoversf = matchesf = 0;
- for (k = 0; k < _CHARSET_INTS; ++k)
+ for (k = 0; k < CHARCLASS_INTS; ++k)
{
/* Even an optimizing compiler can't know this for sure. */
int match = matches[k], label = labels[j][k];
- (leftovers[k] = ~match & label) ? leftoversf = 1 : 0;
- (matches[k] = match & ~label) ? matchesf = 1 : 0;
+ (leftovers[k] = ~match & label) ? (leftoversf = 1) : 0;
+ (matches[k] = match & ~label) ? (matchesf = 1) : 0;
}
/* If there were leftovers, create a new group labeled with them. */
@@ -1361,7 +1606,7 @@ regstate(s, r, trans)
{
copyset(leftovers, labels[ngrps]);
copyset(intersect, labels[j]);
- MALLOC(grps[ngrps].elems, _position, r->nleaves);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
copy(&grps[j], &grps[ngrps]);
++ngrps;
}
@@ -1382,46 +1627,50 @@ regstate(s, r, trans)
{
copyset(matches, labels[ngrps]);
zeroset(matches);
- MALLOC(grps[ngrps].elems, _position, r->nleaves);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
grps[ngrps].nelem = 1;
grps[ngrps].elems[0] = pos;
++ngrps;
}
}
- MALLOC(follows.elems, _position, r->nleaves);
- MALLOC(tmp.elems, _position, r->nleaves);
+ MALLOC(follows.elems, position, d->nleaves);
+ MALLOC(tmp.elems, position, d->nleaves);
/* If we are a searching matcher, the default transition is to a state
containing the positions of state 0, otherwise the default transition
is to fail miserably. */
- if (r->searchflag)
+ if (d->searchflag)
{
wants_newline = 0;
wants_letter = 0;
- for (i = 0; i < r->states[0].elems.nelem; ++i)
+ for (i = 0; i < d->states[0].elems.nelem; ++i)
{
- if (_PREV_NEWLINE_DEPENDENT(r->states[0].elems.elems[i].constraint))
+ if (PREV_NEWLINE_DEPENDENT(d->states[0].elems.elems[i].constraint))
wants_newline = 1;
- if (_PREV_LETTER_DEPENDENT(r->states[0].elems.elems[i].constraint))
+ if (PREV_LETTER_DEPENDENT(d->states[0].elems.elems[i].constraint))
wants_letter = 1;
}
- copy(&r->states[0].elems, &follows);
- state = state_index(r, &follows, 0, 0);
+ copy(&d->states[0].elems, &follows);
+ state = state_index(d, &follows, 0, 0);
if (wants_newline)
- state_newline = state_index(r, &follows, 1, 0);
+ state_newline = state_index(d, &follows, 1, 0);
else
state_newline = state;
if (wants_letter)
- state_letter = state_index(r, &follows, 0, 1);
+ state_letter = state_index(d, &follows, 0, 1);
else
state_letter = state;
- for (i = 0; i < _NOTCHAR; ++i)
- trans[i] = (ISALNUM(i)) ? state_letter : state ;
- trans['\n'] = state_newline;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ trans[i] = state_newline;
+ else if (ISALNUM(i))
+ trans[i] = state_letter;
+ else
+ trans[i] = state;
}
else
- for (i = 0; i < _NOTCHAR; ++i)
+ for (i = 0; i < NOTCHAR; ++i)
trans[i] = -1;
for (i = 0; i < ngrps; ++i)
@@ -1431,44 +1680,44 @@ regstate(s, r, trans)
/* Find the union of the follows of the positions of the group.
This is a hideously inefficient loop. Fix it someday. */
for (j = 0; j < grps[i].nelem; ++j)
- for (k = 0; k < r->follows[grps[i].elems[j].index].nelem; ++k)
- insert(r->follows[grps[i].elems[j].index].elems[k], &follows);
+ for (k = 0; k < d->follows[grps[i].elems[j].index].nelem; ++k)
+ insert(d->follows[grps[i].elems[j].index].elems[k], &follows);
/* If we are building a searching matcher, throw in the positions
of state 0 as well. */
- if (r->searchflag)
- for (j = 0; j < r->states[0].elems.nelem; ++j)
- insert(r->states[0].elems.elems[j], &follows);
+ if (d->searchflag)
+ for (j = 0; j < d->states[0].elems.nelem; ++j)
+ insert(d->states[0].elems.elems[j], &follows);
/* Find out if the new state will want any context information. */
wants_newline = 0;
if (tstbit('\n', labels[i]))
for (j = 0; j < follows.nelem; ++j)
- if (_PREV_NEWLINE_DEPENDENT(follows.elems[j].constraint))
+ if (PREV_NEWLINE_DEPENDENT(follows.elems[j].constraint))
wants_newline = 1;
wants_letter = 0;
- for (j = 0; j < _CHARSET_INTS; ++j)
+ for (j = 0; j < CHARCLASS_INTS; ++j)
if (labels[i][j] & letters[j])
break;
- if (j < _CHARSET_INTS)
+ if (j < CHARCLASS_INTS)
for (j = 0; j < follows.nelem; ++j)
- if (_PREV_LETTER_DEPENDENT(follows.elems[j].constraint))
+ if (PREV_LETTER_DEPENDENT(follows.elems[j].constraint))
wants_letter = 1;
/* Find the state(s) corresponding to the union of the follows. */
- state = state_index(r, &follows, 0, 0);
+ state = state_index(d, &follows, 0, 0);
if (wants_newline)
- state_newline = state_index(r, &follows, 1, 0);
+ state_newline = state_index(d, &follows, 1, 0);
else
state_newline = state;
if (wants_letter)
- state_letter = state_index(r, &follows, 0, 1);
+ state_letter = state_index(d, &follows, 0, 1);
else
state_letter = state;
/* Set the transitions for each character in the current label. */
- for (j = 0; j < _CHARSET_INTS; ++j)
+ for (j = 0; j < CHARCLASS_INTS; ++j)
for (k = 0; k < INTBITS; ++k)
if (labels[i][j] & 1 << k)
{
@@ -1478,7 +1727,7 @@ regstate(s, r, trans)
trans[c] = state_newline;
else if (ISALNUM(c))
trans[c] = state_letter;
- else if (c < _NOTCHAR)
+ else if (c < NOTCHAR)
trans[c] = state;
}
}
@@ -1488,18 +1737,18 @@ regstate(s, r, trans)
free(follows.elems);
free(tmp.elems);
}
-
-/* Some routines for manipulating a compiled regexp's transition tables.
+
+/* Some routines for manipulating a compiled dfa's transition tables.
Each state may or may not have a transition table; if it does, and it
- is a non-accepting state, then r->trans[state] points to its table.
- If it is an accepting state then r->fails[state] points to its table.
- If it has no table at all, then r->trans[state] is NULL.
+ is a non-accepting state, then d->trans[state] points to its table.
+ If it is an accepting state then d->fails[state] points to its table.
+ If it has no table at all, then d->trans[state] is NULL.
TODO: Improve this comment, get rid of the unnecessary redundancy. */
static void
-build_state(s, r)
+build_state(s, d)
int s;
- struct regexp *r;
+ struct dfa *d;
{
int *trans; /* The new transition table. */
int i;
@@ -1508,87 +1757,87 @@ build_state(s, r)
exist at once. 1024 is arbitrary. The idea is that the frequently
used transition tables will be quickly rebuilt, whereas the ones that
were only needed once or twice will be cleared away. */
- if (r->trcount >= 1024)
+ if (d->trcount >= 1024)
{
- for (i = 0; i < r->tralloc; ++i)
- if (r->trans[i])
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
{
- free((ptr_t) r->trans[i]);
- r->trans[i] = NULL;
+ free((ptr_t) d->trans[i]);
+ d->trans[i] = NULL;
}
- else if (r->fails[i])
+ else if (d->fails[i])
{
- free((ptr_t) r->fails[i]);
- r->fails[i] = NULL;
+ free((ptr_t) d->fails[i]);
+ d->fails[i] = NULL;
}
- r->trcount = 0;
+ d->trcount = 0;
}
- ++r->trcount;
+ ++d->trcount;
/* Set up the success bits for this state. */
- r->success[s] = 0;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 1, r->states[s].letter, 0,
- s, *r))
- r->success[s] |= 4;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 0, r->states[s].letter, 1,
- s, *r))
- r->success[s] |= 2;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 0, r->states[s].letter, 0,
- s, *r))
- r->success[s] |= 1;
-
- MALLOC(trans, int, _NOTCHAR);
- regstate(s, r, trans);
+ d->success[s] = 0;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 1, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 4;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 1,
+ s, *d))
+ d->success[s] |= 2;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 1;
+
+ MALLOC(trans, int, NOTCHAR);
+ dfastate(s, d, trans);
/* Now go through the new transition table, and make sure that the trans
and fail arrays are allocated large enough to hold a pointer for the
largest state mentioned in the table. */
- for (i = 0; i < _NOTCHAR; ++i)
- if (trans[i] >= r->tralloc)
+ for (i = 0; i < NOTCHAR; ++i)
+ if (trans[i] >= d->tralloc)
{
- int oldalloc = r->tralloc;
-
- while (trans[i] >= r->tralloc)
- r->tralloc *= 2;
- REALLOC(r->realtrans, int *, r->tralloc + 1);
- r->trans = r->realtrans + 1;
- REALLOC(r->fails, int *, r->tralloc);
- REALLOC(r->success, int, r->tralloc);
- REALLOC(r->newlines, int, r->tralloc);
- while (oldalloc < r->tralloc)
+ int oldalloc = d->tralloc;
+
+ while (trans[i] >= d->tralloc)
+ d->tralloc *= 2;
+ REALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ REALLOC(d->fails, int *, d->tralloc);
+ REALLOC(d->success, int, d->tralloc);
+ REALLOC(d->newlines, int, d->tralloc);
+ while (oldalloc < d->tralloc)
{
- r->trans[oldalloc] = NULL;
- r->fails[oldalloc++] = NULL;
+ d->trans[oldalloc] = NULL;
+ d->fails[oldalloc++] = NULL;
}
}
/* Keep the newline transition in a special place so we can use it as
a sentinel. */
- r->newlines[s] = trans['\n'];
+ d->newlines[s] = trans['\n'];
trans['\n'] = -1;
- if (ACCEPTING(s, *r))
- r->fails[s] = trans;
+ if (ACCEPTING(s, *d))
+ d->fails[s] = trans;
else
- r->trans[s] = trans;
+ d->trans[s] = trans;
}
static void
-build_state_zero(r)
- struct regexp *r;
+build_state_zero(d)
+ struct dfa *d;
{
- r->tralloc = 1;
- r->trcount = 0;
- CALLOC(r->realtrans, int *, r->tralloc + 1);
- r->trans = r->realtrans + 1;
- CALLOC(r->fails, int *, r->tralloc);
- MALLOC(r->success, int, r->tralloc);
- MALLOC(r->newlines, int, r->tralloc);
- build_state(0, r);
+ d->tralloc = 1;
+ d->trcount = 0;
+ CALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ CALLOC(d->fails, int *, d->tralloc);
+ MALLOC(d->success, int, d->tralloc);
+ MALLOC(d->newlines, int, d->tralloc);
+ build_state(0, d);
}
-
-/* Search through a buffer looking for a match to the given struct regexp.
+
+/* Search through a buffer looking for a match to the given struct dfa.
Find the first occurrence of a string matching the regexp in the buffer,
and the shortest possible version thereof. Return a pointer to the first
character after the match, or NULL if none is found. Begin points to
@@ -1602,8 +1851,8 @@ build_state_zero(r)
match needs to be verified by a backtracking matcher. Otherwise
we store a 0 in *backref. */
char *
-regexecute(r, begin, end, newline, count, backref)
- struct regexp *r;
+dfaexec(d, begin, end, newline, count, backref)
+ struct dfa *d;
char *begin;
char *end;
int newline;
@@ -1612,9 +1861,9 @@ regexecute(r, begin, end, newline, count, backref)
{
register s, s1, tmp; /* Current state. */
register unsigned char *p; /* Current input character. */
- register **trans, *t; /* Copy of r->trans so it can be optimized
+ register **trans, *t; /* Copy of d->trans so it can be optimized
into a register. */
- static sbit[_NOTCHAR]; /* Table for anding with r->success. */
+ static sbit[NOTCHAR]; /* Table for anding with d->success. */
static sbit_init;
if (! sbit_init)
@@ -1622,41 +1871,54 @@ regexecute(r, begin, end, newline, count, backref)
int i;
sbit_init = 1;
- for (i = 0; i < _NOTCHAR; ++i)
- sbit[i] = (ISALNUM(i)) ? 2 : 1;
- sbit['\n'] = 4;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ sbit[i] = 4;
+ else if (ISALNUM(i))
+ sbit[i] = 2;
+ else
+ sbit[i] = 1;
}
- if (! r->tralloc)
- build_state_zero(r);
+ if (! d->tralloc)
+ build_state_zero(d);
s = s1 = 0;
p = (unsigned char *) begin;
- trans = r->trans;
+ trans = d->trans;
*end = '\n';
for (;;)
{
- while ((t = trans[s]) != 0) { /* hand-optimized loop */
- s1 = t[*p++];
- if ((t = trans[s1]) == 0) {
- tmp = s ; s = s1 ; s1 = tmp ; /* swap */
- break;
- }
- s = t[*p++];
- }
+ /* The dreaded inner loop. */
+ if ((t = trans[s]) != 0)
+ do
+ {
+ s1 = t[*p++];
+ if (! (t = trans[s1]))
+ goto last_was_s;
+ s = t[*p++];
+ }
+ while ((t = trans[s]) != 0);
+ goto last_was_s1;
+ last_was_s:
+ tmp = s, s = s1, s1 = tmp;
+ last_was_s1:
- if (s >= 0 && p <= (unsigned char *) end && r->fails[s])
+ if (s >= 0 && p <= (unsigned char *) end && d->fails[s])
{
- if (r->success[s] & sbit[*p])
+ if (d->success[s] & sbit[*p])
{
if (backref)
- *backref = (r->states[s].backref != 0);
+ if (d->states[s].backref)
+ *backref = 1;
+ else
+ *backref = 0;
return (char *) p;
}
s1 = s;
- s = r->fails[s][*p++];
+ s = d->fails[s][*p++];
continue;
}
@@ -1665,627 +1927,662 @@ regexecute(r, begin, end, newline, count, backref)
++*count;
/* Check if we've run off the end of the buffer. */
- if ((char *) p >= end)
+ if ((char *) p > end)
return NULL;
if (s >= 0)
{
- build_state(s, r);
- trans = r->trans;
+ build_state(s, d);
+ trans = d->trans;
continue;
}
if (p[-1] == '\n' && newline)
{
- s = r->newlines[s1];
+ s = d->newlines[s1];
continue;
}
s = 0;
}
}
-
-/* Initialize the components of a regexp that the other routines don't
+
+/* Initialize the components of a dfa that the other routines don't
initialize for themselves. */
void
-reginit(r)
- struct regexp *r;
+dfainit(d)
+ struct dfa *d;
{
- r->calloc = 1;
- MALLOC(r->charsets, _charset, r->calloc);
- r->cindex = 0;
+ d->calloc = 1;
+ MALLOC(d->charclasses, charclass, d->calloc);
+ d->cindex = 0;
+
+ d->talloc = 1;
+ MALLOC(d->tokens, token, d->talloc);
+ d->tindex = d->depth = d->nleaves = d->nregexps = 0;
- r->talloc = 1;
- MALLOC(r->tokens, _token, r->talloc);
- r->tindex = r->depth = r->nleaves = r->nregexps = 0;
+ d->searchflag = 0;
+ d->tralloc = 0;
- r->searchflag = 0;
- r->tralloc = 0;
+ d->musts = 0;
}
/* Parse and analyze a single string of the given length. */
void
-regcompile(s, len, r, searchflag)
- const char *s;
+dfacomp(s, len, d, searchflag)
+ char *s;
size_t len;
- struct regexp *r;
+ struct dfa *d;
int searchflag;
{
- if (case_fold) /* dummy folding in service of regmust() */
+ if (case_fold) /* dummy folding in service of dfamust() */
{
- char *regcopy;
+ char *lcopy;
int i;
- regcopy = malloc(len);
- if (!regcopy)
- reg_error("out of memory");
+ lcopy = malloc(len);
+ if (!lcopy)
+ dfaerror("out of memory");
- /* This is a complete kludge and could potentially break
- \<letter> escapes . . . */
+ /* This is a kludge. */
case_fold = 0;
for (i = 0; i < len; ++i)
if (ISUPPER(s[i]))
- regcopy[i] = tolower(s[i]);
+ lcopy[i] = tolower(s[i]);
else
- regcopy[i] = s[i];
-
- reginit(r);
- r->mustn = 0;
- r->must[0] = '\0';
- regparse(regcopy, len, r);
- free(regcopy);
- regmust(r);
- reganalyze(r, searchflag);
+ lcopy[i] = s[i];
+
+ dfainit(d);
+ dfaparse(lcopy, len, d);
+ free(lcopy);
+ dfamust(d);
+ d->cindex = d->tindex = d->depth = d->nleaves = d->nregexps = 0;
case_fold = 1;
- reginit(r);
- regparse(s, len, r);
- reganalyze(r, searchflag);
+ dfaparse(s, len, d);
+ dfaanalyze(d, searchflag);
}
else
{
- reginit(r);
- regparse(s, len, r);
- regmust(r);
- reganalyze(r, searchflag);
+ dfainit(d);
+ dfaparse(s, len, d);
+ dfamust(d);
+ dfaanalyze(d, searchflag);
}
}
-/* Free the storage held by the components of a regexp. */
+/* Free the storage held by the components of a dfa. */
void
-reg_free(r)
- struct regexp *r;
+dfafree(d)
+ struct dfa *d;
{
int i;
-
- free((ptr_t) r->charsets);
- free((ptr_t) r->tokens);
- for (i = 0; i < r->sindex; ++i)
- free((ptr_t) r->states[i].elems.elems);
- free((ptr_t) r->states);
- for (i = 0; i < r->tindex; ++i)
- if (r->follows[i].elems)
- free((ptr_t) r->follows[i].elems);
- free((ptr_t) r->follows);
- for (i = 0; i < r->tralloc; ++i)
- if (r->trans[i])
- free((ptr_t) r->trans[i]);
- else if (r->fails[i])
- free((ptr_t) r->fails[i]);
- if (r->realtrans)
- free((ptr_t) r->realtrans);
- if (r->fails)
- free((ptr_t) r->fails);
- if (r->newlines)
- free((ptr_t) r->newlines);
+ struct dfamust *dm, *ndm;
+
+ free((ptr_t) d->charclasses);
+ free((ptr_t) d->tokens);
+ for (i = 0; i < d->sindex; ++i)
+ free((ptr_t) d->states[i].elems.elems);
+ free((ptr_t) d->states);
+ for (i = 0; i < d->tindex; ++i)
+ if (d->follows[i].elems)
+ free((ptr_t) d->follows[i].elems);
+ free((ptr_t) d->follows);
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
+ free((ptr_t) d->trans[i]);
+ else if (d->fails[i])
+ free((ptr_t) d->fails[i]);
+ if (d->realtrans) free((ptr_t) d->realtrans);
+ if (d->fails) free((ptr_t) d->fails);
+ if (d->newlines) free((ptr_t) d->newlines);
+ for (dm = d->musts; dm; dm = ndm)
+ {
+ ndm = dm->next;
+ free(dm->must);
+ free((ptr_t) dm);
+ }
}
-/*
-Having found the postfix representation of the regular expression,
-try to find a long sequence of characters that must appear in any line
-containing the r.e.
-Finding a "longest" sequence is beyond the scope here;
-we take an easy way out and hope for the best.
-(Take "(ab|a)b"--please.)
-
-We do a bottom-up calculation of sequences of characters that must appear
-in matches of r.e.'s represented by trees rooted at the nodes of the postfix
-representation:
+/* Having found the postfix representation of the regular expression,
+ try to find a long sequence of characters that must appear in any line
+ containing the r.e.
+ Finding a "longest" sequence is beyond the scope here;
+ we take an easy way out and hope for the best.
+ (Take "(ab|a)b"--please.)
+
+ We do a bottom-up calculation of sequences of characters that must appear
+ in matches of r.e.'s represented by trees rooted at the nodes of the postfix
+ representation:
sequences that must appear at the left of the match ("left")
sequences that must appear at the right of the match ("right")
lists of sequences that must appear somewhere in the match ("in")
sequences that must constitute the match ("is")
-When we get to the root of the tree, we use one of the longest of its
-calculated "in" sequences as our answer. The sequence we find is returned in
-r->must (where "r" is the single argument passed to "regmust");
-the length of the sequence is returned in r->mustn.
-
-The sequences calculated for the various types of node (in pseudo ANSI c)
-are shown below. "p" is the operand of unary operators (and the left-hand
-operand of binary operators); "q" is the right-hand operand of binary operators
-.
-"ZERO" means "a zero-length sequence" below.
-
-Type left right is in
----- ---- ----- -- --
-char c # c # c # c # c
-
-SET ZERO ZERO ZERO ZERO
-
-STAR ZERO ZERO ZERO ZERO
-
-QMARK ZERO ZERO ZERO ZERO
-
-PLUS p->left p->right ZERO p->in
-
-CAT (p->is==ZERO)? (q->is==ZERO)? (p->is!=ZERO && p->in plus
- p->left : q->right : q->is!=ZERO) ? q->in plus
- p->is##q->left p->right##q->is p->is##q->is : p->right##q->left
- ZERO
-
-OR longest common longest common (do p->is and substrings common to
- leading trailing q->is have same p->in and q->in
- (sub)sequence (sub)sequence length and
- of p->left of p->right content) ?
- and q->left and q->right p->is : NULL
-
-If there's anything else we recognize in the tree, all four sequences get set
-to zero-length sequences. If there's something we don't recognize in the tree,
-we just return a zero-length sequence.
-
-Break ties in favor of infrequent letters (choosing 'zzz' in preference to
-'aaa')?
-And. . .is it here or someplace that we might ponder "optimizations" such as
+ When we get to the root of the tree, we use one of the longest of its
+ calculated "in" sequences as our answer. The sequence we find is returned in
+ d->must (where "d" is the single argument passed to "dfamust");
+ the length of the sequence is returned in d->mustn.
+
+ The sequences calculated for the various types of node (in pseudo ANSI c)
+ are shown below. "p" is the operand of unary operators (and the left-hand
+ operand of binary operators); "q" is the right-hand operand of binary
+ operators.
+
+ "ZERO" means "a zero-length sequence" below.
+
+ Type left right is in
+ ---- ---- ----- -- --
+ char c # c # c # c # c
+
+ CSET ZERO ZERO ZERO ZERO
+
+ STAR ZERO ZERO ZERO ZERO
+
+ QMARK ZERO ZERO ZERO ZERO
+
+ PLUS p->left p->right ZERO p->in
+
+ CAT (p->is==ZERO)? (q->is==ZERO)? (p->is!=ZERO && p->in plus
+ p->left : q->right : q->is!=ZERO) ? q->in plus
+ p->is##q->left p->right##q->is p->is##q->is : p->right##q->left
+ ZERO
+
+ OR longest common longest common (do p->is and substrings common to
+ leading trailing q->is have same p->in and q->in
+ (sub)sequence (sub)sequence length and
+ of p->left of p->right content) ?
+ and q->left and q->right p->is : NULL
+
+ If there's anything else we recognize in the tree, all four sequences get set
+ to zero-length sequences. If there's something we don't recognize in the tree,
+ we just return a zero-length sequence.
+
+ Break ties in favor of infrequent letters (choosing 'zzz' in preference to
+ 'aaa')?
+
+ And. . .is it here or someplace that we might ponder "optimizations" such as
egrep 'psi|epsilon' -> egrep 'psi'
egrep 'pepsi|epsilon' -> egrep 'epsi'
(Yes, we now find "epsi" as a "string
that must occur", but we might also
- simplify the *entire* r.e. being sought
-)
+ simplify the *entire* r.e. being sought)
grep '[c]' -> grep 'c'
grep '(ab|a)b' -> grep 'ab'
grep 'ab*' -> grep 'a'
grep 'a*b' -> grep 'b'
-There are several issues:
- Is optimization easy (enough)?
- Does optimization actually accomplish anything,
- or is the automaton you get from "psi|epsilon" (for example)
- the same as the one you get from "psi" (for example)?
+ There are several issues:
- Are optimizable r.e.'s likely to be used in real-life situations
- (something like 'ab*' is probably unlikely; something like is
- 'psi|epsilon' is likelier)?
-*/
+ Is optimization easy (enough)?
+
+ Does optimization actually accomplish anything,
+ or is the automaton you get from "psi|epsilon" (for example)
+ the same as the one you get from "psi" (for example)?
+
+ Are optimizable r.e.'s likely to be used in real-life situations
+ (something like 'ab*' is probably unlikely; something like is
+ 'psi|epsilon' is likelier)? */
static char *
icatalloc(old, new)
-char * old;
-const char * new;
+ char *old;
+ char *new;
{
- register char * result;
- register int oldsize, newsize;
-
- newsize = (new == NULL) ? 0 : strlen(new);
- if (old == NULL)
- oldsize = 0;
- else if (newsize == 0)
- return old;
- else oldsize = strlen(old);
- if (old == NULL)
- result = (char *) malloc(newsize + 1);
- else result = (char *) realloc((void *) old, oldsize + newsize + 1);
- if (result != NULL && new != NULL)
- (void) strcpy(result + oldsize, new);
- return result;
+ char *result;
+ size_t oldsize, newsize;
+
+ newsize = (new == NULL) ? 0 : strlen(new);
+ if (old == NULL)
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if (old == NULL)
+ result = (char *) malloc(newsize + 1);
+ else
+ result = (char *) realloc((void *) old, oldsize + newsize + 1);
+ if (result != NULL && new != NULL)
+ (void) strcpy(result + oldsize, new);
+ return result;
}
static char *
icpyalloc(string)
-const char * string;
+ char *string;
{
- return icatalloc((char *) NULL, string);
+ return icatalloc((char *) NULL, string);
}
static char *
istrstr(lookin, lookfor)
-char * lookin;
-register char * lookfor;
+ char *lookin;
+ char *lookfor;
{
- register char * cp;
- register int len;
-
- len = strlen(lookfor);
- for (cp = lookin; *cp != '\0'; ++cp)
- if (strncmp(cp, lookfor, len) == 0)
- return cp;
- return NULL;
+ char *cp;
+ size_t len;
+
+ len = strlen(lookfor);
+ for (cp = lookin; *cp != '\0'; ++cp)
+ if (strncmp(cp, lookfor, len) == 0)
+ return cp;
+ return NULL;
}
static void
ifree(cp)
-char * cp;
+ char *cp;
{
- if (cp != NULL)
- free(cp);
+ if (cp != NULL)
+ free(cp);
}
static void
freelist(cpp)
-register char ** cpp;
+ char **cpp;
{
- register int i;
+ int i;
- if (cpp == NULL)
- return;
- for (i = 0; cpp[i] != NULL; ++i) {
- free(cpp[i]);
- cpp[i] = NULL;
- }
+ if (cpp == NULL)
+ return;
+ for (i = 0; cpp[i] != NULL; ++i)
+ {
+ free(cpp[i]);
+ cpp[i] = NULL;
+ }
}
static char **
enlist(cpp, new, len)
-register char ** cpp;
-register char * new;
-#ifdef __STDC__
-size_t len;
-#else
-int len;
-#endif
+ char **cpp;
+ char *new;
+ size_t len;
{
- register int i, j;
+ int i, j;
- if (cpp == NULL)
- return NULL;
- if ((new = icpyalloc(new)) == NULL) {
- freelist(cpp);
- return NULL;
- }
- new[len] = '\0';
- /*
- ** Is there already something in the list that's new (or longer)?
- */
- for (i = 0; cpp[i] != NULL; ++i)
- if (istrstr(cpp[i], new) != NULL) {
- free(new);
- return cpp;
- }
- /*
- ** Eliminate any obsoleted strings.
- */
- j = 0;
- while (cpp[j] != NULL)
- if (istrstr(new, cpp[j]) == NULL)
- ++j;
- else {
- free(cpp[j]);
- if (--i == j)
- break;
- cpp[j] = cpp[i];
- }
- /*
- ** Add the new string.
- */
- cpp = (char **) realloc((char *) cpp, (i + 2) * sizeof *cpp);
- if (cpp == NULL)
- return NULL;
- cpp[i] = new;
- cpp[i + 1] = NULL;
+ if (cpp == NULL)
+ return NULL;
+ if ((new = icpyalloc(new)) == NULL)
+ {
+ freelist(cpp);
+ return NULL;
+ }
+ new[len] = '\0';
+ /* Is there already something in the list that's new (or longer)? */
+ for (i = 0; cpp[i] != NULL; ++i)
+ if (istrstr(cpp[i], new) != NULL)
+ {
+ free(new);
return cpp;
+ }
+ /* Eliminate any obsoleted strings. */
+ j = 0;
+ while (cpp[j] != NULL)
+ if (istrstr(new, cpp[j]) == NULL)
+ ++j;
+ else
+ {
+ free(cpp[j]);
+ if (--i == j)
+ break;
+ cpp[j] = cpp[i];
+ cpp[i] = NULL;
+ }
+ /* Add the new string. */
+ cpp = (char **) realloc((char *) cpp, (i + 2) * sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[i] = new;
+ cpp[i + 1] = NULL;
+ return cpp;
}
-/*
-** Given pointers to two strings,
-** return a pointer to an allocated list of their distinct common substrings.
-** Return NULL if something seems wild.
-*/
-
+/* Given pointers to two strings, return a pointer to an allocated
+ list of their distinct common substrings. Return NULL if something
+ seems wild. */
static char **
comsubs(left, right)
-char * left;
-char * right;
+ char *left;
+ char *right;
{
- register char ** cpp;
- register char * lcp;
- register char * rcp;
- register int i, len;
-
- if (left == NULL || right == NULL)
- return NULL;
- cpp = (char **) malloc(sizeof *cpp);
- if (cpp == NULL)
- return NULL;
- cpp[0] = NULL;
- for (lcp = left; *lcp != '\0'; ++lcp) {
- len = 0;
- rcp = strchr(right, *lcp);
- while (rcp != NULL) {
- for (i = 1; lcp[i] != '\0' && lcp[i] == rcp[i]; ++i)
- ;
- if (i > len)
- len = i;
- rcp = strchr(rcp + 1, *lcp);
- }
- if (len == 0)
- continue;
-#ifdef __STDC__
- if ((cpp = enlist(cpp, lcp, (size_t)len)) == NULL)
-#else
- if ((cpp = enlist(cpp, lcp, len)) == NULL)
-#endif
- break;
+ char **cpp;
+ char *lcp;
+ char *rcp;
+ size_t i, len;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ cpp = (char **) malloc(sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[0] = NULL;
+ for (lcp = left; *lcp != '\0'; ++lcp)
+ {
+ len = 0;
+ rcp = index(right, *lcp);
+ while (rcp != NULL)
+ {
+ for (i = 1; lcp[i] != '\0' && lcp[i] == rcp[i]; ++i)
+ continue;
+ if (i > len)
+ len = i;
+ rcp = index(rcp + 1, *lcp);
}
- return cpp;
+ if (len == 0)
+ continue;
+ if ((cpp = enlist(cpp, lcp, len)) == NULL)
+ break;
+ }
+ return cpp;
}
static char **
addlists(old, new)
-char ** old;
-char ** new;
+char **old;
+char **new;
{
- register int i;
-
- if (old == NULL || new == NULL)
- return NULL;
- for (i = 0; new[i] != NULL; ++i) {
- old = enlist(old, new[i], strlen(new[i]));
- if (old == NULL)
- break;
- }
- return old;
-}
+ int i;
-/*
-** Given two lists of substrings,
-** return a new list giving substrings common to both.
-*/
+ if (old == NULL || new == NULL)
+ return NULL;
+ for (i = 0; new[i] != NULL; ++i)
+ {
+ old = enlist(old, new[i], strlen(new[i]));
+ if (old == NULL)
+ break;
+ }
+ return old;
+}
+/* Given two lists of substrings, return a new list giving substrings
+ common to both. */
static char **
inboth(left, right)
-char ** left;
-char ** right;
+ char **left;
+ char **right;
{
- register char ** both;
- register char ** temp;
- register int lnum, rnum;
-
- if (left == NULL || right == NULL)
- return NULL;
- both = (char **) malloc(sizeof *both);
- if (both == NULL)
- return NULL;
- both[0] = NULL;
- for (lnum = 0; left[lnum] != NULL; ++lnum) {
- for (rnum = 0; right[rnum] != NULL; ++rnum) {
- temp = comsubs(left[lnum], right[rnum]);
- if (temp == NULL) {
- freelist(both);
- return NULL;
- }
- both = addlists(both, temp);
- freelist(temp);
- if (both == NULL)
- return NULL;
- }
+ char **both;
+ char **temp;
+ int lnum, rnum;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ both = (char **) malloc(sizeof *both);
+ if (both == NULL)
+ return NULL;
+ both[0] = NULL;
+ for (lnum = 0; left[lnum] != NULL; ++lnum)
+ {
+ for (rnum = 0; right[rnum] != NULL; ++rnum)
+ {
+ temp = comsubs(left[lnum], right[rnum]);
+ if (temp == NULL)
+ {
+ freelist(both);
+ return NULL;
+ }
+ both = addlists(both, temp);
+ freelist(temp);
+ if (both == NULL)
+ return NULL;
}
- return both;
+ }
+ return both;
}
-/*
-typedef struct {
- char ** in;
- char * left;
- char * right;
- char * is;
+typedef struct
+{
+ char **in;
+ char *left;
+ char *right;
+ char *is;
} must;
- */
+
static void
resetmust(mp)
-register must * mp;
+must *mp;
{
- mp->left[0] = mp->right[0] = mp->is[0] = '\0';
- freelist(mp->in);
+ mp->left[0] = mp->right[0] = mp->is[0] = '\0';
+ freelist(mp->in);
}
static void
-regmust(r)
-register struct regexp * r;
+dfamust(dfa)
+struct dfa *dfa;
{
- register must * musts;
- register must * mp;
- register char * result = "";
- register int ri;
- register int i;
- register _token t;
- static must must0;
-
- reg->mustn = 0;
- reg->must[0] = '\0';
- musts = (must *) malloc((reg->tindex + 1) * sizeof *musts);
- if (musts == NULL)
- return;
- mp = musts;
- for (i = 0; i <= reg->tindex; ++i)
- mp[i] = must0;
- for (i = 0; i <= reg->tindex; ++i) {
- mp[i].in = (char **) malloc(sizeof *mp[i].in);
- mp[i].left = malloc(2);
- mp[i].right = malloc(2);
- mp[i].is = malloc(2);
- if (mp[i].in == NULL || mp[i].left == NULL ||
- mp[i].right == NULL || mp[i].is == NULL)
- goto done;
- mp[i].left[0] = mp[i].right[0] = mp[i].is[0] = '\0';
- mp[i].in[0] = NULL;
- }
- for (ri = 0; ri < reg->tindex; ++ri) {
- switch (t = reg->tokens[ri]) {
- case _ALLBEGLINE:
- case _ALLENDLINE:
- case _LPAREN:
- case _RPAREN:
- goto done; /* "cannot happen" */
- case _EMPTY:
- case _BEGLINE:
- case _ENDLINE:
- case _BEGWORD:
- case _ENDWORD:
- case _LIMWORD:
- case _NOTLIMWORD:
- case _BACKREF:
- resetmust(mp);
- break;
- case _STAR:
- case _QMARK:
- if (mp <= musts)
- goto done; /* "cannot happen" */
- --mp;
- resetmust(mp);
- break;
- case _OR:
- if (mp < &musts[2])
- goto done; /* "cannot happen" */
- {
- register char ** new;
- register must * lmp;
- register must * rmp;
- register int j, ln, rn, n;
-
- rmp = --mp;
- lmp = --mp;
- /* Guaranteed to be. Unlikely, but. . . */
- if (strcmp(lmp->is, rmp->is) != 0)
- lmp->is[0] = '\0';
- /* Left side--easy */
- i = 0;
- while (lmp->left[i] != '\0' &&
- lmp->left[i] == rmp->left[i])
- ++i;
- lmp->left[i] = '\0';
- /* Right side */
- ln = strlen(lmp->right);
- rn = strlen(rmp->right);
- n = ln;
- if (n > rn)
- n = rn;
- for (i = 0; i < n; ++i)
- if (lmp->right[ln - i - 1] !=
- rmp->right[rn - i - 1])
- break;
- for (j = 0; j < i; ++j)
- lmp->right[j] =
- lmp->right[(ln - i) + j];
- lmp->right[j] = '\0';
- new = inboth(lmp->in, rmp->in);
- if (new == NULL)
- goto done;
- freelist(lmp->in);
- free((char *) lmp->in);
- lmp->in = new;
- }
- break;
- case _PLUS:
- if (mp <= musts)
- goto done; /* "cannot happen" */
- --mp;
- mp->is[0] = '\0';
- break;
- case _END:
- if (mp != &musts[1])
- goto done; /* "cannot happen" */
- for (i = 0; musts[0].in[i] != NULL; ++i)
- if (strlen(musts[0].in[i]) > strlen(result))
- result = musts[0].in[i];
- goto done;
- case _CAT:
- if (mp < &musts[2])
- goto done; /* "cannot happen" */
- {
- register must * lmp;
- register must * rmp;
-
- rmp = --mp;
- lmp = --mp;
- /*
- ** In. Everything in left, plus everything in
- ** right, plus catenation of
- ** left's right and right's left.
- */
- lmp->in = addlists(lmp->in, rmp->in);
- if (lmp->in == NULL)
- goto done;
- if (lmp->right[0] != '\0' &&
- rmp->left[0] != '\0') {
- register char * tp;
-
- tp = icpyalloc(lmp->right);
- if (tp == NULL)
- goto done;
- tp = icatalloc(tp, rmp->left);
- if (tp == NULL)
- goto done;
- lmp->in = enlist(lmp->in, tp,
- strlen(tp));
- free(tp);
- if (lmp->in == NULL)
- goto done;
- }
- /* Left-hand */
- if (lmp->is[0] != '\0') {
- lmp->left = icatalloc(lmp->left,
- rmp->left);
- if (lmp->left == NULL)
- goto done;
- }
- /* Right-hand */
- if (rmp->is[0] == '\0')
- lmp->right[0] = '\0';
- lmp->right = icatalloc(lmp->right, rmp->right);
- if (lmp->right == NULL)
- goto done;
- /* Guaranteed to be */
- if (lmp->is[0] != '\0' && rmp->is[0] != '\0') {
- lmp->is = icatalloc(lmp->is, rmp->is);
- if (lmp->is == NULL)
- goto done;
- }
- }
- break;
- default:
- if (t < _END) {
- /* "cannot happen" */
- goto done;
- } else if (t == '\0') {
- /* not on *my* shift */
- goto done;
- } else if (t >= _SET) {
- /* easy enough */
- resetmust(mp);
- } else {
- /* plain character */
- resetmust(mp);
- mp->is[0] = mp->left[0] = mp->right[0] = t;
- mp->is[1] = mp->left[1] = mp->right[1] = '\0';
- mp->in = enlist(mp->in, mp->is, 1);
- if (mp->in == NULL)
- goto done;
- }
- break;
- }
- ++mp;
- }
-done:
- (void) strncpy(reg->must, result, MUST_MAX - 1);
- reg->must[MUST_MAX - 1] = '\0';
- reg->mustn = strlen(reg->must);
- mp = musts;
- for (i = 0; i <= reg->tindex; ++i) {
- freelist(mp[i].in);
- ifree((char *) mp[i].in);
- ifree(mp[i].left);
- ifree(mp[i].right);
- ifree(mp[i].is);
+ must *musts;
+ must *mp;
+ char *result;
+ int ri;
+ int i;
+ int exact;
+ token t;
+ static must must0;
+ struct dfamust *dm;
+ static char empty_string[] = "";
+
+ result = empty_string;
+ exact = 0;
+ musts = (must *) malloc((dfa->tindex + 1) * sizeof *musts);
+ if (musts == NULL)
+ return;
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ mp[i] = must0;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ mp[i].in = (char **) malloc(sizeof *mp[i].in);
+ mp[i].left = malloc(2);
+ mp[i].right = malloc(2);
+ mp[i].is = malloc(2);
+ if (mp[i].in == NULL || mp[i].left == NULL ||
+ mp[i].right == NULL || mp[i].is == NULL)
+ goto done;
+ mp[i].left[0] = mp[i].right[0] = mp[i].is[0] = '\0';
+ mp[i].in[0] = NULL;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "dfamust:\n");
+ for (i = 0; i < dfa->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(dfa->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
+ for (ri = 0; ri < dfa->tindex; ++ri)
+ {
+ switch (t = dfa->tokens[ri])
+ {
+ case LPAREN:
+ case RPAREN:
+ goto done; /* "cannot happen" */
+ case EMPTY:
+ case BEGLINE:
+ case ENDLINE:
+ case BEGWORD:
+ case ENDWORD:
+ case LIMWORD:
+ case NOTLIMWORD:
+ case BACKREF:
+ resetmust(mp);
+ break;
+ case STAR:
+ case QMARK:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ resetmust(mp);
+ break;
+ case OR:
+ case ORTOP:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ char **new;
+ must *lmp;
+ must *rmp;
+ int j, ln, rn, n;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* Guaranteed to be. Unlikely, but. . . */
+ if (strcmp(lmp->is, rmp->is) != 0)
+ lmp->is[0] = '\0';
+ /* Left side--easy */
+ i = 0;
+ while (lmp->left[i] != '\0' && lmp->left[i] == rmp->left[i])
+ ++i;
+ lmp->left[i] = '\0';
+ /* Right side */
+ ln = strlen(lmp->right);
+ rn = strlen(rmp->right);
+ n = ln;
+ if (n > rn)
+ n = rn;
+ for (i = 0; i < n; ++i)
+ if (lmp->right[ln - i - 1] != rmp->right[rn - i - 1])
+ break;
+ for (j = 0; j < i; ++j)
+ lmp->right[j] = lmp->right[(ln - i) + j];
+ lmp->right[j] = '\0';
+ new = inboth(lmp->in, rmp->in);
+ if (new == NULL)
+ goto done;
+ freelist(lmp->in);
+ free((char *) lmp->in);
+ lmp->in = new;
+ }
+ break;
+ case PLUS:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ mp->is[0] = '\0';
+ break;
+ case END:
+ if (mp != &musts[1])
+ goto done; /* "cannot happen" */
+ for (i = 0; musts[0].in[i] != NULL; ++i)
+ if (strlen(musts[0].in[i]) > strlen(result))
+ result = musts[0].in[i];
+ if (strcmp(result, musts[0].is) == 0)
+ exact = 1;
+ goto done;
+ case CAT:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ must *lmp;
+ must *rmp;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* In. Everything in left, plus everything in
+ right, plus catenation of
+ left's right and right's left. */
+ lmp->in = addlists(lmp->in, rmp->in);
+ if (lmp->in == NULL)
+ goto done;
+ if (lmp->right[0] != '\0' &&
+ rmp->left[0] != '\0')
+ {
+ char *tp;
+
+ tp = icpyalloc(lmp->right);
+ if (tp == NULL)
+ goto done;
+ tp = icatalloc(tp, rmp->left);
+ if (tp == NULL)
+ goto done;
+ lmp->in = enlist(lmp->in, tp,
+ strlen(tp));
+ free(tp);
+ if (lmp->in == NULL)
+ goto done;
+ }
+ /* Left-hand */
+ if (lmp->is[0] != '\0')
+ {
+ lmp->left = icatalloc(lmp->left,
+ rmp->left);
+ if (lmp->left == NULL)
+ goto done;
+ }
+ /* Right-hand */
+ if (rmp->is[0] == '\0')
+ lmp->right[0] = '\0';
+ lmp->right = icatalloc(lmp->right, rmp->right);
+ if (lmp->right == NULL)
+ goto done;
+ /* Guaranteed to be */
+ if (lmp->is[0] != '\0' && rmp->is[0] != '\0')
+ {
+ lmp->is = icatalloc(lmp->is, rmp->is);
+ if (lmp->is == NULL)
+ goto done;
+ }
+ else
+ lmp->is[0] = '\0';
+ }
+ break;
+ default:
+ if (t < END)
+ {
+ /* "cannot happen" */
+ goto done;
+ }
+ else if (t == '\0')
+ {
+ /* not on *my* shift */
+ goto done;
+ }
+ else if (t >= CSET)
+ {
+ /* easy enough */
+ resetmust(mp);
+ }
+ else
+ {
+ /* plain character */
+ resetmust(mp);
+ mp->is[0] = mp->left[0] = mp->right[0] = t;
+ mp->is[1] = mp->left[1] = mp->right[1] = '\0';
+ mp->in = enlist(mp->in, mp->is, (size_t)1);
+ if (mp->in == NULL)
+ goto done;
+ }
+ break;
}
- free((char *) mp);
+#ifdef DEBUG
+ fprintf(stderr, " node: %d:", ri);
+ prtok(dfa->tokens[ri]);
+ fprintf(stderr, "\n in:");
+ for (i = 0; mp->in[i]; ++i)
+ fprintf(stderr, " \"%s\"", mp->in[i]);
+ fprintf(stderr, "\n is: \"%s\"\n", mp->is);
+ fprintf(stderr, " left: \"%s\"\n", mp->left);
+ fprintf(stderr, " right: \"%s\"\n", mp->right);
+#endif
+ ++mp;
+ }
+ done:
+ if (strlen(result))
+ {
+ dm = (struct dfamust *) malloc(sizeof (struct dfamust));
+ dm->exact = exact;
+ dm->must = malloc(strlen(result) + 1);
+ strcpy(dm->must, result);
+ dm->next = dfa->musts;
+ dfa->musts = dm;
+ }
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ freelist(mp[i].in);
+ ifree((char *) mp[i].in);
+ ifree(mp[i].left);
+ ifree(mp[i].right);
+ ifree(mp[i].is);
+ }
+ free((char *) mp);
}
diff --git a/gnu/usr.bin/awk/dfa.h b/gnu/usr.bin/awk/dfa.h
index 65fc49565a7c..cc27d7a6a964 100644
--- a/gnu/usr.bin/awk/dfa.h
+++ b/gnu/usr.bin/awk/dfa.h
@@ -1,318 +1,130 @@
/* dfa.h - declarations for GNU deterministic regexp compiler
Copyright (C) 1988 Free Software Foundation, Inc.
- Written June, 1988 by Mike Haertel
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
-NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
-WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
-OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
-DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
-A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
-PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
-as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1988 Free Software Foundation, Inc."; and include following the
-copyright notice a verbatim copy of the above disclaimer of warranty
-and of this License. You may charge a distribution fee for the
-physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file 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 or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution 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 unrelated program with this program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other program under the scope of these terms.
-
- 3. You may copy and distribute this program or any portion of it in
-compiled, executable or object code form under the terms of Paragraphs
-1 and 2 above provided that you do 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
- shipping charge) 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.)
-
-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.
-
- 4. You may not copy, sublicense, distribute or transfer this program
-except as expressly provided under this License Agreement. Any attempt
-otherwise to copy, sublicense, distribute or transfer this program is void and
-your rights to use the program under this License agreement shall be
-automatically terminated. However, parties who have received computer
-software programs from you with this License Agreement will not have
-their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
-programs whose distribution conditions are different, write to the Free
-Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
-worked out a simple rule that can be stated here, but we will often permit
-this. We will be guided by the two goals of preserving the free status of
-all derivatives our free software and of promoting the sharing and reuse of
-software.
-
-
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-#ifdef __STDC__
-#ifdef SOMEDAY
-#define ISALNUM(c) isalnum(c)
-#define ISALPHA(c) isalpha(c)
-#define ISUPPER(c) isupper(c)
-#else
-#define ISALNUM(c) (isascii(c) && isalnum(c))
-#define ISALPHA(c) (isascii(c) && isalpha(c))
-#define ISUPPER(c) (isascii(c) && isupper(c))
-#endif
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-#else /* ! __STDC__ */
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-#define const
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#define ISALNUM(c) (isascii(c) && isalnum(c))
-#define ISALPHA(c) (isascii(c) && isalpha(c))
-#define ISUPPER(c) (isascii(c) && isupper(c))
+/* Written June, 1988 by Mike Haertel */
-#endif /* ! __STDC__ */
-
-/* 1 means plain parentheses serve as grouping, and backslash
- parentheses are needed for literal searching.
- 0 means backslash-parentheses are grouping, and plain parentheses
- are for literal searching. */
-#define RE_NO_BK_PARENS 1L
-
-/* 1 means plain | serves as the "or"-operator, and \| is a literal.
- 0 means \| serves as the "or"-operator, and | is a literal. */
-#define RE_NO_BK_VBAR (1L << 1)
-
-/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
- 1 means \+, \? are operators and plain +, ? are literals. */
-#define RE_BK_PLUS_QM (1L << 2)
-
-/* 1 means | binds tighter than ^ or $.
- 0 means the contrary. */
-#define RE_TIGHT_VBAR (1L << 3)
-
-/* 1 means treat \n as an _OR operator
- 0 means treat it as a normal character */
-#define RE_NEWLINE_OR (1L << 4)
-
-/* 0 means that a special characters (such as *, ^, and $) always have
- their special meaning regardless of the surrounding context.
- 1 means that special characters may act as normal characters in some
- contexts. Specifically, this applies to:
- ^ - only special at the beginning, or after ( or |
- $ - only special at the end, or before ) or |
- *, +, ? - only special when not after the beginning, (, or | */
-#define RE_CONTEXT_INDEP_OPS (1L << 5)
-
-/* 1 means that \ in a character class escapes the next character (typically
- a hyphen. It also is overloaded to mean that hyphen at the end of the range
- is allowable and means that the hyphen is to be taken literally. */
-#define RE_AWK_CLASS_HACK (1L << 6)
-
-/* Now define combinations of bits for the standard possibilities. */
-#ifdef notdef
-#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
-#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR)
-#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
-#define RE_SYNTAX_EMACS 0
-#endif
-
-/* The NULL pointer. */
-#ifndef NULL
-#define NULL 0
-#endif
+/* FIXME:
+ 2. We should not export so much of the DFA internals.
+ In addition to clobbering modularity, we eat up valuable
+ name space. */
/* Number of bits in an unsigned char. */
-#ifndef CHARBITS
#define CHARBITS 8
-#endif
/* First integer value that is greater than any character code. */
-#define _NOTCHAR (1 << CHARBITS)
+#define NOTCHAR (1 << CHARBITS)
/* INTBITS need not be exact, just a lower bound. */
-#ifndef INTBITS
#define INTBITS (CHARBITS * sizeof (int))
-#endif
/* Number of ints required to hold a bit for every character. */
-#define _CHARSET_INTS ((_NOTCHAR + INTBITS - 1) / INTBITS)
+#define CHARCLASS_INTS ((NOTCHAR + INTBITS - 1) / INTBITS)
/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
-typedef int _charset[_CHARSET_INTS];
+typedef int charclass[CHARCLASS_INTS];
/* The regexp is parsed into an array of tokens in postfix form. Some tokens
are operators and others are terminal symbols. Most (but not all) of these
codes are returned by the lexical analyzer. */
-#ifdef __STDC__
typedef enum
{
- _END = -1, /* _END is a terminal symbol that matches the
- end of input; any value of _END or less in
+ END = -1, /* END is a terminal symbol that matches the
+ end of input; any value of END or less in
the parse tree is such a symbol. Accepting
states of the DFA are those that would have
- a transition on _END. */
+ a transition on END. */
/* Ordinary character values are terminal symbols that match themselves. */
- _EMPTY = _NOTCHAR, /* _EMPTY is a terminal symbol that matches
+ EMPTY = NOTCHAR, /* EMPTY is a terminal symbol that matches
the empty string. */
- _BACKREF, /* _BACKREF is generated by \<digit>; it
+ BACKREF, /* BACKREF is generated by \<digit>; it
it not completely handled. If the scanner
detects a transition on backref, it returns
a kind of "semi-success" indicating that
the match will have to be verified with
a backtracking matcher. */
- _BEGLINE, /* _BEGLINE is a terminal symbol that matches
+ BEGLINE, /* BEGLINE is a terminal symbol that matches
the empty string if it is at the beginning
of a line. */
- _ALLBEGLINE, /* _ALLBEGLINE is a terminal symbol that
- matches the empty string if it is at the
- beginning of a line; _ALLBEGLINE applies
- to the entire regexp and can only occur
- as the first token thereof. _ALLBEGLINE
- never appears in the parse tree; a _BEGLINE
- is prepended with _CAT to the entire
- regexp instead. */
-
- _ENDLINE, /* _ENDLINE is a terminal symbol that matches
+ ENDLINE, /* ENDLINE is a terminal symbol that matches
the empty string if it is at the end of
a line. */
- _ALLENDLINE, /* _ALLENDLINE is to _ENDLINE as _ALLBEGLINE
- is to _BEGLINE. */
-
- _BEGWORD, /* _BEGWORD is a terminal symbol that matches
+ BEGWORD, /* BEGWORD is a terminal symbol that matches
the empty string if it is at the beginning
of a word. */
- _ENDWORD, /* _ENDWORD is a terminal symbol that matches
+ ENDWORD, /* ENDWORD is a terminal symbol that matches
the empty string if it is at the end of
a word. */
- _LIMWORD, /* _LIMWORD is a terminal symbol that matches
+ LIMWORD, /* LIMWORD is a terminal symbol that matches
the empty string if it is at the beginning
or the end of a word. */
- _NOTLIMWORD, /* _NOTLIMWORD is a terminal symbol that
+ NOTLIMWORD, /* NOTLIMWORD is a terminal symbol that
matches the empty string if it is not at
the beginning or end of a word. */
- _QMARK, /* _QMARK is an operator of one argument that
+ QMARK, /* QMARK is an operator of one argument that
matches zero or one occurences of its
argument. */
- _STAR, /* _STAR is an operator of one argument that
+ STAR, /* STAR is an operator of one argument that
matches the Kleene closure (zero or more
occurrences) of its argument. */
- _PLUS, /* _PLUS is an operator of one argument that
+ PLUS, /* PLUS is an operator of one argument that
matches the positive closure (one or more
occurrences) of its argument. */
- _CAT, /* _CAT is an operator of two arguments that
+ REPMN, /* REPMN is a lexical token corresponding
+ to the {m,n} construct. REPMN never
+ appears in the compiled token vector. */
+
+ CAT, /* CAT is an operator of two arguments that
matches the concatenation of its
- arguments. _CAT is never returned by the
+ arguments. CAT is never returned by the
lexical analyzer. */
- _OR, /* _OR is an operator of two arguments that
+ OR, /* OR is an operator of two arguments that
matches either of its arguments. */
- _LPAREN, /* _LPAREN never appears in the parse tree,
+ ORTOP, /* OR at the toplevel in the parse tree.
+ This is used for a boyer-moore heuristic. */
+
+ LPAREN, /* LPAREN never appears in the parse tree,
it is only a lexeme. */
- _RPAREN, /* _RPAREN never appears in the parse tree. */
+ RPAREN, /* RPAREN never appears in the parse tree. */
- _SET /* _SET and (and any value greater) is a
+ CSET /* CSET and (and any value greater) is a
terminal symbol that matches any of a
class of characters. */
-} _token;
+} token;
-#else /* ! __STDC__ */
-
-typedef short _token;
-
-#define _END -1
-#define _EMPTY _NOTCHAR
-#define _BACKREF (_EMPTY + 1)
-#define _BEGLINE (_EMPTY + 2)
-#define _ALLBEGLINE (_EMPTY + 3)
-#define _ENDLINE (_EMPTY + 4)
-#define _ALLENDLINE (_EMPTY + 5)
-#define _BEGWORD (_EMPTY + 6)
-#define _ENDWORD (_EMPTY + 7)
-#define _LIMWORD (_EMPTY + 8)
-#define _NOTLIMWORD (_EMPTY + 9)
-#define _QMARK (_EMPTY + 10)
-#define _STAR (_EMPTY + 11)
-#define _PLUS (_EMPTY + 12)
-#define _CAT (_EMPTY + 13)
-#define _OR (_EMPTY + 14)
-#define _LPAREN (_EMPTY + 15)
-#define _RPAREN (_EMPTY + 16)
-#define _SET (_EMPTY + 17)
-
-#endif /* ! __STDC__ */
-
-/* Sets are stored in an array in the compiled regexp; the index of the
- array corresponding to a given set token is given by _SET_INDEX(t). */
-#define _SET_INDEX(t) ((t) - _SET)
+/* Sets are stored in an array in the compiled dfa; the index of the
+ array corresponding to a given set token is given by SET_INDEX(t). */
+#define SET_INDEX(t) ((t) - CSET)
/* Sometimes characters can only be matched depending on the surrounding
context. Such context decisions depend on what the previous character
@@ -332,36 +144,36 @@ typedef short _token;
Word-constituent characters are those that satisfy isalnum().
- The macro _SUCCEEDS_IN_CONTEXT determines whether a a given constraint
+ The macro SUCCEEDS_IN_CONTEXT determines whether a a given constraint
succeeds in a particular context. Prevn is true if the previous character
was a newline, currn is true if the lookahead character is a newline.
Prevl and currl similarly depend upon whether the previous and current
characters are word-constituent letters. */
-#define _MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
- ((constraint) & (1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4)))
-#define _MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
- ((constraint) & (1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0))))
-#define _SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
- (_MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
- && _MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
+#define MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ ((constraint) & 1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4))
+#define MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
+ ((constraint) & 1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0)))
+#define SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
+ (MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ && MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
/* The following macros give information about what a constraint depends on. */
-#define _PREV_NEWLINE_DEPENDENT(constraint) \
+#define PREV_NEWLINE_DEPENDENT(constraint) \
(((constraint) & 0xc0) >> 2 != ((constraint) & 0x30))
-#define _PREV_LETTER_DEPENDENT(constraint) \
+#define PREV_LETTER_DEPENDENT(constraint) \
(((constraint) & 0x0c) >> 2 != ((constraint) & 0x03))
/* Tokens that match the empty string subject to some constraint actually
work by applying that constraint to determine what may follow them,
taking into account what has gone before. The following values are
the constraints corresponding to the special tokens previously defined. */
-#define _NO_CONSTRAINT 0xff
-#define _BEGLINE_CONSTRAINT 0xcf
-#define _ENDLINE_CONSTRAINT 0xaf
-#define _BEGWORD_CONSTRAINT 0xf2
-#define _ENDWORD_CONSTRAINT 0xf4
-#define _LIMWORD_CONSTRAINT 0xf6
-#define _NOTLIMWORD_CONSTRAINT 0xf9
+#define NO_CONSTRAINT 0xff
+#define BEGLINE_CONSTRAINT 0xcf
+#define ENDLINE_CONSTRAINT 0xaf
+#define BEGWORD_CONSTRAINT 0xf2
+#define ENDWORD_CONSTRAINT 0xf4
+#define LIMWORD_CONSTRAINT 0xf6
+#define NOTLIMWORD_CONSTRAINT 0xf9
/* States of the recognizer correspond to sets of positions in the parse
tree, together with the constraints under which they may be matched.
@@ -371,44 +183,48 @@ typedef struct
{
unsigned index; /* Index into the parse array. */
unsigned constraint; /* Constraint for matching this position. */
-} _position;
+} position;
/* Sets of positions are stored as arrays. */
typedef struct
{
- _position *elems; /* Elements of this position set. */
+ position *elems; /* Elements of this position set. */
int nelem; /* Number of elements in this set. */
-} _position_set;
+} position_set;
-/* A state of the regexp consists of a set of positions, some flags,
+/* A state of the dfa consists of a set of positions, some flags,
and the token value of the lowest-numbered position of the state that
- contains an _END token. */
+ contains an END token. */
typedef struct
{
int hash; /* Hash of the positions of this state. */
- _position_set elems; /* Positions this state could match. */
+ position_set elems; /* Positions this state could match. */
char newline; /* True if previous state matched newline. */
char letter; /* True if previous state matched a letter. */
char backref; /* True if this state matches a \<digit>. */
unsigned char constraint; /* Constraint for this state to accept. */
- int first_end; /* Token value of the first _END in elems. */
-} _dfa_state;
+ int first_end; /* Token value of the first END in elems. */
+} dfa_state;
-/* If an r.e. is at most MUST_MAX characters long, we look for a string which
- must appear in it; whatever's found is dropped into the struct reg. */
-
-#define MUST_MAX 50
+/* Element of a list of strings, at least one of which is known to
+ appear in any R.E. matching the DFA. */
+struct dfamust
+{
+ int exact;
+ char *must;
+ struct dfamust *next;
+};
/* A compiled regular expression. */
-struct regexp
+struct dfa
{
/* Stuff built by the scanner. */
- _charset *charsets; /* Array of character sets for _SET tokens. */
- int cindex; /* Index for adding new charsets. */
- int calloc; /* Number of charsets currently allocated. */
+ charclass *charclasses; /* Array of character sets for CSET tokens. */
+ int cindex; /* Index for adding new charclasses. */
+ int calloc; /* Number of charclasses currently allocated. */
/* Stuff built by the parser. */
- _token *tokens; /* Postfix parse array. */
+ token *tokens; /* Postfix parse array. */
int tindex; /* Index for adding new tokens. */
int talloc; /* Number of tokens currently allocated. */
int depth; /* Depth required of an evaluation stack
@@ -416,15 +232,15 @@ struct regexp
parse tree. */
int nleaves; /* Number of leaves on the parse tree. */
int nregexps; /* Count of parallel regexps being built
- with regparse(). */
+ with dfaparse(). */
/* Stuff owned by the state builder. */
- _dfa_state *states; /* States of the regexp. */
+ dfa_state *states; /* States of the dfa. */
int sindex; /* Index for adding new states. */
int salloc; /* Number of states currently allocated. */
/* Stuff built by the structure analyzer. */
- _position_set *follows; /* Array of follow sets, indexed by position
+ position_set *follows; /* Array of follow sets, indexed by position
index. The follow of a position is the set
of positions containing characters that
could conceivably follow a character
@@ -454,7 +270,7 @@ struct regexp
int **fails; /* Transition tables after failing to accept
on a state that potentially could do so. */
int *success; /* Table of acceptance conditions used in
- regexecute and computed in build_state. */
+ dfaexec and computed in build_state. */
int *newlines; /* Transitions on newlines. The entry for a
newline in any transition table is always
-1 so we can count lines without wasting
@@ -462,40 +278,41 @@ struct regexp
newline is stored separately and handled
as a special case. Newline is also used
as a sentinel at the end of the buffer. */
- char must[MUST_MAX];
- int mustn;
+ struct dfamust *musts; /* List of strings, at least one of which
+ is known to appear in any r.e. matching
+ the dfa. */
};
-/* Some macros for user access to regexp internals. */
+/* Some macros for user access to dfa internals. */
/* ACCEPTING returns true if s could possibly be an accepting state of r. */
#define ACCEPTING(s, r) ((r).states[s].constraint)
/* ACCEPTS_IN_CONTEXT returns true if the given state accepts in the
specified context. */
-#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, reg) \
- _SUCCEEDS_IN_CONTEXT((reg).states[state].constraint, \
+#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, dfa) \
+ SUCCEEDS_IN_CONTEXT((dfa).states[state].constraint, \
prevn, currn, prevl, currl)
/* FIRST_MATCHING_REGEXP returns the index number of the first of parallel
regexps that a given state could accept. Parallel regexps are numbered
starting at 1. */
-#define FIRST_MATCHING_REGEXP(state, reg) (-(reg).states[state].first_end)
+#define FIRST_MATCHING_REGEXP(state, dfa) (-(dfa).states[state].first_end)
/* Entry points. */
#ifdef __STDC__
-/* Regsyntax() takes two arguments; the first sets the syntax bits described
+/* dfasyntax() takes two arguments; the first sets the syntax bits described
earlier in this file, and the second sets the case-folding flag. */
-extern void regsyntax(long, int);
+extern void dfasyntax(reg_syntax_t, int);
-/* Compile the given string of the given length into the given struct regexp.
+/* Compile the given string of the given length into the given struct dfa.
Final argument is a flag specifying whether to build a searching or an
exact matcher. */
-extern void regcompile(const char *, size_t, struct regexp *, int);
+extern void dfacomp(char *, size_t, struct dfa *, int);
-/* Execute the given struct regexp on the buffer of characters. The
+/* Execute the given struct dfa on the buffer of characters. The
first char * points to the beginning, and the second points to the
first character after the end of the buffer, which must be a writable
place so a sentinel end-of-buffer marker can be stored there. The
@@ -507,37 +324,37 @@ extern void regcompile(const char *, size_t, struct regexp *, int);
order to verify backreferencing; otherwise the flag will be cleared.
Returns NULL if no match is found, or a pointer to the first
character after the first & shortest matching string in the buffer. */
-extern char *regexecute(struct regexp *, char *, char *, int, int *, int *);
+extern char *dfaexec(struct dfa *, char *, char *, int, int *, int *);
-/* Free the storage held by the components of a struct regexp. */
-extern void reg_free(struct regexp *);
+/* Free the storage held by the components of a struct dfa. */
+extern void dfafree(struct dfa *);
/* Entry points for people who know what they're doing. */
-/* Initialize the components of a struct regexp. */
-extern void reginit(struct regexp *);
+/* Initialize the components of a struct dfa. */
+extern void dfainit(struct dfa *);
-/* Incrementally parse a string of given length into a struct regexp. */
-extern void regparse(const char *, size_t, struct regexp *);
+/* Incrementally parse a string of given length into a struct dfa. */
+extern void dfaparse(char *, size_t, struct dfa *);
/* Analyze a parsed regexp; second argument tells whether to build a searching
or an exact matcher. */
-extern void reganalyze(struct regexp *, int);
+extern void dfaanalyze(struct dfa *, int);
/* Compute, for each possible character, the transitions out of a given
state, storing them in an array of integers. */
-extern void regstate(int, struct regexp *, int []);
+extern void dfastate(int, struct dfa *, int []);
/* Error handling. */
-/* Regerror() is called by the regexp routines whenever an error occurs. It
+/* dfaerror() is called by the regexp routines whenever an error occurs. It
takes a single argument, a NUL-terminated string describing the error.
- The default reg_error() prints the error message to stderr and exits.
- The user can provide a different reg_free() if so desired. */
-extern void reg_error(const char *);
+ The default dfaerror() prints the error message to stderr and exits.
+ The user can provide a different dfafree() if so desired. */
+extern void dfaerror(const char *);
#else /* ! __STDC__ */
-extern void regsyntax(), regcompile(), reg_free(), reginit(), regparse();
-extern void reganalyze(), regstate(), reg_error();
-extern char *regexecute();
-#endif
+extern void dfasyntax(), dfacomp(), dfafree(), dfainit(), dfaparse();
+extern void dfaanalyze(), dfastate(), dfaerror();
+extern char *dfaexec();
+#endif /* ! __STDC__ */
diff --git a/gnu/usr.bin/awk/eval.c b/gnu/usr.bin/awk/eval.c
index f640f3733ada..18f67fd2b592 100644
--- a/gnu/usr.bin/awk/eval.c
+++ b/gnu/usr.bin/awk/eval.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -137,6 +137,10 @@ register NODE *volatile tree;
NODE *volatile stable_tree;
int volatile traverse = 1; /* True => loop thru tree (Node_rule_list) */
+ /* avoid false source indications */
+ source = NULL;
+ sourceline = 0;
+
if (tree == NULL)
return 1;
sourceline = tree->source_line;
@@ -318,7 +322,10 @@ register NODE *volatile tree;
break;
case Node_K_delete:
- do_delete(tree->lnode, tree->rnode);
+ if (tree->rnode != NULL)
+ do_delete(tree->lnode, tree->rnode);
+ else
+ assoc_clear(tree->lnode);
break;
case Node_K_next:
@@ -378,7 +385,7 @@ register NODE *tree;
register int di;
AWKNUM x, x1, x2;
long lx;
-#ifdef CRAY
+#ifdef _CRAY
long lx2;
#endif
@@ -386,21 +393,25 @@ register NODE *tree;
if (tree == NULL)
return Nnull_string;
if (tree->type == Node_val) {
- if (tree->stref <= 0) cant_happen();
+ if ((char)tree->stref <= 0) cant_happen();
return tree;
}
if (tree->type == Node_var) {
- if (tree->var_value->stref <= 0) cant_happen();
+ if ((char)tree->var_value->stref <= 0) cant_happen();
return tree->var_value;
}
+#endif
+
if (tree->type == Node_param_list) {
- if (stack_ptr[tree->param_cnt] == NULL)
+ tree = stack_ptr[tree->param_cnt];
+ if (tree == NULL)
return Nnull_string;
- else
- return stack_ptr[tree->param_cnt]->var_value;
}
-#endif
+
switch (tree->type) {
+ case Node_var:
+ return tree->var_value;
+
case Node_and:
return tmp_number((AWKNUM) (eval_condition(tree->lnode)
&& eval_condition(tree->rnode)));
@@ -443,7 +454,7 @@ register NODE *tree;
return *lhs;
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", tree->vname);
case Node_unary_minus:
t1 = tree_eval(tree->subnode);
@@ -489,32 +500,52 @@ register NODE *tree;
case Node_concat:
{
#define STACKSIZE 10
- NODE *stack[STACKSIZE];
- register NODE **sp;
- register int len;
+ NODE *treelist[STACKSIZE+1];
+ NODE *strlist[STACKSIZE+1];
+ register NODE **treep;
+ register NODE **strp;
+ register size_t len;
char *str;
register char *dest;
- sp = stack;
- len = 0;
+ /*
+ * This is an efficiency hack for multiple adjacent string
+ * concatenations, to avoid recursion and string copies.
+ *
+ * Node_concat trees grow downward to the left, so
+ * descend to lowest (first) node, accumulating nodes
+ * to evaluate to strings as we go.
+ */
+ treep = treelist;
while (tree->type == Node_concat) {
- *sp = force_string(tree_eval(tree->lnode));
- tree = tree->rnode;
- len += (*sp)->stlen;
- if (++sp == &stack[STACKSIZE-2]) /* one more and NULL */
+ *treep++ = tree->rnode;
+ tree = tree->lnode;
+ if (treep == &treelist[STACKSIZE])
break;
}
- *sp = force_string(tree_eval(tree));
- len += (*sp)->stlen;
- *++sp = NULL;
+ *treep = tree;
+ /*
+ * Now, evaluate to strings in LIFO order, accumulating
+ * the string length, so we can do a single malloc at the
+ * end.
+ */
+ strp = strlist;
+ len = 0;
+ while (treep >= treelist) {
+ *strp = force_string(tree_eval(*treep--));
+ len += (*strp)->stlen;
+ strp++;
+ }
+ *strp = NULL;
emalloc(str, char *, len+2, "tree_eval");
+ str[len] = str[len+1] = '\0'; /* for good measure */
dest = str;
- sp = stack;
- while (*sp) {
- memcpy(dest, (*sp)->stptr, (*sp)->stlen);
- dest += (*sp)->stlen;
- free_temp(*sp);
- sp++;
+ strp = strlist;
+ while (*strp) {
+ memcpy(dest, (*strp)->stptr, (*strp)->stlen);
+ dest += (*strp)->stlen;
+ free_temp(*strp);
+ strp++;
}
r = make_str_node(str, len, ALREADY_MALLOCED);
r->flags |= TEMP;
@@ -629,7 +660,7 @@ register NODE *tree;
return tmp_number(x1 - x2);
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", tree->vname);
default:
fatal("illegal type (%d) in tree_eval", tree->type);
@@ -696,7 +727,7 @@ cmp_nodes(t1, t2)
register NODE *t1, *t2;
{
register int ret;
- register int len1, len2;
+ register size_t len1, len2;
if (t1 == t2)
return 0;
@@ -944,22 +975,26 @@ NODE *arg_list; /* Node_expression_list of calling args. */
if (arg->type == Node_param_list)
arg = stack_ptr[arg->param_cnt];
n = *sp++;
- if (arg->type == Node_var && n->type == Node_var_array) {
+ if ((arg->type == Node_var || arg->type == Node_var_array)
+ && n->type == Node_var_array) {
/* should we free arg->var_value ? */
arg->var_array = n->var_array;
arg->type = Node_var_array;
+ arg->array_size = n->array_size;
+ arg->table_size = n->table_size;
+ arg->flags = n->flags;
}
- unref(n->lnode);
+ /* n->lnode overlays the array size, don't unref it if array */
+ if (n->type != Node_var_array)
+ unref(n->lnode);
freenode(n);
count--;
}
while (count-- > 0) {
n = *sp++;
/* if n is an (local) array, all the elements should be freed */
- if (n->type == Node_var_array) {
+ if (n->type == Node_var_array)
assoc_clear(n);
- free(n->var_array);
- }
unref(n->lnode);
freenode(n);
}
@@ -985,7 +1020,7 @@ NODE *arg_list; /* Node_expression_list of calling args. */
*/
NODE **
-get_lhs(ptr, assign)
+r_get_lhs(ptr, assign)
register NODE *ptr;
Func_ptr *assign;
{
@@ -994,11 +1029,11 @@ Func_ptr *assign;
switch (ptr->type) {
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", ptr->vname);
case Node_var:
aptr = &(ptr->var_value);
#ifdef DEBUG
- if (ptr->var_value->stref <= 0)
+ if ((char)ptr->var_value->stref <= 0)
cant_happen();
#endif
break;
@@ -1170,7 +1205,7 @@ set_ORS()
ORS[ORSlen] = '\0';
}
-static NODE **fmt_list = NULL;
+NODE **fmt_list = NULL;
static int fmt_ok P((NODE *n));
static int fmt_index P((NODE *n));
diff --git a/gnu/usr.bin/awk/field.c b/gnu/usr.bin/awk/field.c
index d8f9a5455631..17dce9b684e5 100644
--- a/gnu/usr.bin/awk/field.c
+++ b/gnu/usr.bin/awk/field.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -25,26 +25,28 @@
#include "awk.h"
-static int (*parse_field) P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+typedef void (* Setfunc) P((int, char*, int, NODE *));
+
+static long (*parse_field) P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
static void rebuild_record P((void));
-static int re_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int def_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int sc_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int fw_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+static long re_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long def_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long sc_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long fw_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
static void set_element P((int, char *, int, NODE *));
-static void grow_fields_arr P((int num));
+static void grow_fields_arr P((long num));
static void set_field P((int num, char *str, int len, NODE *dummy));
static Regexp *FS_regexp = NULL;
static char *parse_extent; /* marks where to restart parse of record */
-static int parse_high_water=0; /* field number that we have parsed so far */
-static int nf_high_water = 0; /* size of fields_arr */
+static long parse_high_water=0; /* field number that we have parsed so far */
+static long nf_high_water = 0; /* size of fields_arr */
static int resave_fs;
static NODE *save_FS; /* save current value of FS when line is read,
* to be used in deferred parsing
@@ -74,7 +76,7 @@ init_fields()
static void
grow_fields_arr(num)
-int num;
+long num;
{
register int t;
register NODE *n;
@@ -112,13 +114,13 @@ NODE *dummy; /* not used -- just to make interface same as set_element */
static void
rebuild_record()
{
- register int tlen;
+ register size_t tlen;
register NODE *tmp;
NODE *ofs;
char *ops;
register char *cops;
register NODE **ptr;
- register int ofslen;
+ register size_t ofslen;
tlen = 0;
ofs = force_string(OFS_node->var_value);
@@ -130,9 +132,9 @@ rebuild_record()
ptr--;
}
tlen += (NF - 1) * ofslen;
- if (tlen < 0)
+ if ((long)tlen < 0)
tlen = 0;
- emalloc(ops, char *, tlen + 2, "fix_fields");
+ emalloc(ops, char *, tlen + 2, "rebuild_record");
cops = ops;
ops[0] = '\0';
for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
@@ -204,7 +206,7 @@ set_NF()
{
register int i;
- NF = (int) force_number(NF_node->var_value);
+ NF = (long) force_number(NF_node->var_value);
if (NF > nf_high_water)
grow_fields_arr(NF);
for (i = parse_high_water + 1; i <= NF; i++) {
@@ -219,14 +221,14 @@ set_NF()
* via (*parse_field)(). This variation is for when FS is a regular
* expression -- either user-defined or because RS=="" and FS==" "
*/
-static int
+static long
re_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -240,22 +242,23 @@ NODE *n;
return nf;
if (*RS == 0 && default_FS)
- while (scan < end && isspace(*scan))
+ while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
scan++;
field = scan;
while (scan < end
- && research(rp, scan, 0, (int)(end - scan), 1) != -1
+ && research(rp, scan, 0, (end - scan), 1) != -1
&& nf < up_to) {
- if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
+ if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
scan++;
if (scan == end) {
- (*set)(++nf, field, scan - field, n);
+ (*set)(++nf, field, (int)(scan - field), n);
up_to = nf;
break;
}
continue;
}
- (*set)(++nf, field, scan + RESTART(rp, scan) - field, n);
+ (*set)(++nf, field,
+ (int)(scan + RESTART(rp, scan) - field), n);
scan += REEND(rp, scan);
field = scan;
if (scan == end) /* FS at end of record */
@@ -274,14 +277,14 @@ NODE *n;
* via (*parse_field)(). This variation is for when FS is a single space
* character.
*/
-static int
+static long
def_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -328,14 +331,14 @@ NODE *n;
* via (*parse_field)(). This variation is for when FS is a single character
* other than space.
*/
-static int
+static long
sc_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -360,14 +363,18 @@ NODE *n;
/* because it will be destroyed now: */
*end = fschar; /* sentinel character */
- for (; nf < up_to; scan++) {
+ for (; nf < up_to;) {
field = scan;
- while (*scan++ != fschar)
- ;
- scan--;
+ while (*scan != fschar)
+ scan++;
(*set)(++nf, field, (int)(scan - field), n);
if (scan == end)
break;
+ scan++;
+ if (scan == end) { /* FS at end of record */
+ (*set)(++nf, field, 0, n);
+ break;
+ }
}
/* everything done, restore original char at *end */
@@ -381,18 +388,18 @@ NODE *n;
* this is called both from get_field() and from do_split()
* via (*parse_field)(). This variation is for fields are fixed widths.
*/
-static int
+static long
fw_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
- register int nf = parse_high_water;
+ register long nf = parse_high_water;
register char *end = scan + len;
if (up_to == HUGE)
@@ -512,11 +519,21 @@ NODE *tree;
NODE *t1, *t2, *t3, *tmp;
NODE *fs;
char *s;
- int (*parseit)P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+ long (*parseit)P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
Regexp *rp = NULL;
- t1 = tree_eval(tree->lnode);
+
+ /*
+ * do dupnode(), to avoid problems like
+ * x = split(a[1], a, "blah")
+ * since we assoc_clear the array. gack.
+ * this also gives up complete call by value semantics.
+ */
+ tmp = tree_eval(tree->lnode);
+ t1 = dupnode(tmp);
+ free_temp(tmp);
+
t2 = tree->rnode->lnode;
t3 = tree->rnode->rnode->lnode;
@@ -549,7 +566,7 @@ NODE *tree;
s = t1->stptr;
tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
fs, rp, set_element, t2));
- free_temp(t1);
+ unref(t1);
free_temp(t3);
return tmp;
}
@@ -557,10 +574,16 @@ NODE *tree;
void
set_FS()
{
- NODE *tmp = NULL;
char buf[10];
NODE *fs;
+ /*
+ * If changing the way fields are split, obey least-suprise
+ * semantics, and force $0 to be split totally.
+ */
+ if (fields_arr != NULL)
+ (void) get_field(HUGE - 1, 0);
+
buf[0] = '\0';
default_FS = 0;
if (FS_regexp) {
@@ -586,6 +609,9 @@ set_FS()
else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
if (IGNORECASE == 0)
parse_field = sc_parse_field;
+ else if (fs->stptr[0] == '\\')
+ /* yet another special case */
+ strcpy(buf, "[\\\\]");
else
sprintf(buf, "[%c]", fs->stptr[0]);
}
@@ -625,6 +651,13 @@ set_FIELDWIDTHS()
if (do_unix) /* quick and dirty, does the trick */
return;
+ /*
+ * If changing the way fields are split, obey least-suprise
+ * semantics, and force $0 to be split totally.
+ */
+ if (fields_arr != NULL)
+ (void) get_field(HUGE - 1, 0);
+
parse_field = fw_parse_field;
scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
end = scan + 1;
diff --git a/gnu/usr.bin/awk/getopt.c b/gnu/usr.bin/awk/getopt.c
index bbf345c33ca2..fd142f5a207a 100644
--- a/gnu/usr.bin/awk/getopt.c
+++ b/gnu/usr.bin/awk/getopt.c
@@ -3,44 +3,74 @@
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 1994
+ 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.
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#ifdef GAWK
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
#include "config.h"
#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
#include <stdio.h>
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
-#ifdef __GNU_LIBRARY__
+#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
#include <stdlib.h>
-#include <string.h>
-#endif /* GNU C library. */
-
-
-#ifndef __STDC__
-#define const
-#endif
+#else
+extern char *getenv ();
+#endif /* __GNU_LIBRARY || STDC_HEADERS */
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
- being phased out. */
-#define GETOPT_COMPAT
+ being phased out. */
+/* #define GETOPT_COMPAT */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
@@ -78,6 +108,7 @@ char *optarg = 0;
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
+/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
@@ -94,6 +125,12 @@ static char *nextchar;
int opterr = 1;
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
@@ -128,41 +165,46 @@ static enum
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
-#ifdef __GNU_LIBRARY__
+#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
#include <string.h>
#define my_index strchr
-#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
-char *getenv ();
-
static char *
-my_index (string, chr)
- char *string;
+my_index (str, chr)
+ const char *str;
int chr;
{
- while (*string)
+ while (*str)
{
- if (*string == chr)
- return string;
- string++;
+ if (*str == chr)
+ return (char *) str;
+ str++;
}
return 0;
}
-static void
-my_bcopy (from, to, size)
- char *from, *to;
- int size;
-{
- int i;
- for (i = 0; i < size; i++)
- to[i] = from[i];
-}
-#endif /* GNU C library. */
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it.
+ (Supposedly there are some machines where it might get a warning,
+ but changing this conditional to __STDC__ is too risky.) */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* __GNU_LIBRARY__ || STDC_HEADERS */
/* Handle permutation of arguments. */
@@ -186,17 +228,51 @@ static void
exchange (argv)
char **argv;
{
- int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
- char **temp = (char **) malloc (nonopts_size);
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
- /* Interchange the two blocks of data in ARGV. */
+ /* 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. */
- my_bcopy (&argv[first_nonopt], temp, nonopts_size);
- my_bcopy (&argv[last_nonopt], &argv[first_nonopt],
- (optind - last_nonopt) * sizeof (char *));
- my_bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
- free(temp);
+ /* 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;
+ }
+ /* 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;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
/* Update records for the slots the non-options now occupy. */
@@ -394,8 +470,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
- int indfound = 0;
- extern int strncmp();
+ int indfound;
while (*s && *s != '=')
s++;
@@ -441,7 +516,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
- allow it to be used on enums. */
+ allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 1;
else
@@ -473,7 +548,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
- return '?';
+ return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
@@ -489,7 +564,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
/* 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. */
+ Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
@@ -527,12 +602,18 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (opterr)
{
+#if 0
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
}
+ optopt = c;
return '?';
}
if (temp[1] == ':')
@@ -562,9 +643,21 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
else if (optind == argc)
{
if (opterr)
- fprintf (stderr, "%s: option `-%c' requires an argument\n",
- argv[0], c);
- c = '?';
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
}
else
/* We already incremented `optind' once;
@@ -588,6 +681,8 @@ getopt (argc, argv, optstring)
(int *) 0,
0);
}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
diff --git a/gnu/usr.bin/awk/getopt.h b/gnu/usr.bin/awk/getopt.h
index de027434f7cb..b0fc4ffb6d76 100644
--- a/gnu/usr.bin/awk/getopt.h
+++ b/gnu/usr.bin/awk/getopt.h
@@ -1,19 +1,19 @@
/* Declarations for getopt.
- Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 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.
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
@@ -49,6 +49,10 @@ extern int optind;
extern int opterr;
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
@@ -72,7 +76,7 @@ extern int opterr;
struct option
{
-#if __STDC__
+#ifdef __STDC__
const char *name;
#else
char *name;
@@ -86,14 +90,11 @@ struct option
/* Names for the values of the `has_arg' field of `struct option'. */
-enum _argtype
-{
- no_argument,
- required_argument,
- optional_argument
-};
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
-#if __STDC__
+#ifdef __STDC__
#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
diff --git a/gnu/usr.bin/awk/getopt1.c b/gnu/usr.bin/awk/getopt1.c
index e2127cd58d42..7739b51215f9 100644
--- a/gnu/usr.bin/awk/getopt1.c
+++ b/gnu/usr.bin/awk/getopt1.c
@@ -1,40 +1,64 @@
-/* Getopt for GNU.
- Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
-
-This file is part of the libiberty library.
-Libiberty 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.
-
-Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#ifdef LIBC
-/* For when compiled as part of the GNU C library. */
-#include <ansidecl.h>
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
#include "getopt.h"
#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
#define const
#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
-#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#if defined(__GNU_LIBRARY__) || defined(OS2) || defined(MSDOS) || defined(atarist)
#include <stdlib.h>
-#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+#else
char *getenv ();
-#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+#endif
-#if !defined (NULL)
+#ifndef NULL
#define NULL 0
#endif
@@ -52,9 +76,9 @@ getopt_long (argc, argv, options, long_options, opt_index)
/* 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. */
+ instead. */
-int
+int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
@@ -64,6 +88,9 @@ getopt_long_only (argc, argv, options, long_options, opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
diff --git a/gnu/usr.bin/awk/io.c b/gnu/usr.bin/awk/io.c
index 7004aedd519d..7fe21ecf016f 100644
--- a/gnu/usr.bin/awk/io.c
+++ b/gnu/usr.bin/awk/io.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -23,6 +23,9 @@
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#if !defined(VMS) && !defined(VMS_POSIX) && !defined(_MSC_VER)
+#include <sys/param.h>
+#endif
#include "awk.h"
#ifndef O_RDONLY
@@ -33,13 +36,17 @@
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
+#ifndef ENFILE
+#define ENFILE EMFILE
+#endif
+
#ifndef atarist
#define INVALID_HANDLE (-1)
#else
#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
#endif
-#if defined(MSDOS) || defined(atarist)
+#if defined(MSDOS) || defined(OS2) || defined(atarist)
#define PIPES_SIMULATED
#endif
@@ -48,17 +55,34 @@ static int inrec P((IOBUF *iop));
static int iop_close P((IOBUF *iop));
struct redirect *redirect P((NODE *tree, int *errflg));
static void close_one P((void));
-static int close_redir P((struct redirect *rp));
+static int close_redir P((struct redirect *rp, int exitwarn));
#ifndef PIPES_SIMULATED
static int wait_any P((int interesting));
#endif
static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
-static IOBUF *iop_open P((char *file, char *how));
+static IOBUF *iop_open P((const char *file, const char *how));
static int gawk_pclose P((struct redirect *rp));
-static int do_pathopen P((char *file));
+static int do_pathopen P((const char *file));
+static int str2mode P((const char *mode));
+static void spec_setup P((IOBUF *iop, int len, int allocate));
+static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
+static int pidopen P((IOBUF *iop, const char *name, const char *mode));
+static int useropen P((IOBUF *iop, const char *name, const char *mode));
extern FILE *fdopen();
+
+#if defined (MSDOS)
+#include "popen.h"
+#define popen(c,m) os_popen(c,m)
+#define pclose(f) os_pclose(f)
+#elif defined (OS2) /* OS/2, but not family mode */
+#if defined (_MSC_VER)
+#define popen(c,m) _popen(c,m)
+#define pclose(f) _pclose(f)
+#endif
+#else
extern FILE *popen();
+#endif
static struct redirect *red_head = NULL;
@@ -87,7 +111,6 @@ int skipping;
static int i = 1;
static int files = 0;
NODE *arg;
- int fd = INVALID_HANDLE;
static IOBUF *curfile = NULL;
if (skipping) {
@@ -121,8 +144,7 @@ int skipping;
/* NOTREACHED */
/* This is a kludge. */
unref(FILENAME_node->var_value);
- FILENAME_node->var_value =
- dupnode(arg);
+ FILENAME_node->var_value = dupnode(arg);
FNR = 0;
i++;
break;
@@ -131,8 +153,8 @@ int skipping;
if (files == 0) {
files++;
/* no args. -- use stdin */
- /* FILENAME is init'ed to "-" */
/* FNR is init'ed to 0 */
+ FILENAME_node->var_value = make_string("-", 1);
curfile = iop_alloc(fileno(stdin));
}
return curfile;
@@ -141,13 +163,13 @@ int skipping;
void
set_FNR()
{
- FNR = (int) FNR_node->var_value->numbr;
+ FNR = (long) FNR_node->var_value->numbr;
}
void
set_NR()
{
- NR = (int) NR_node->var_value->numbr;
+ NR = (long) NR_node->var_value->numbr;
}
/*
@@ -238,12 +260,15 @@ do_input()
IOBUF *iop;
extern int exiting;
- if (setjmp(filebuf) != 0) {
- }
+ (void) setjmp(filebuf);
+
while ((iop = nextfile(0)) != NULL) {
if (inrec(iop) == 0)
while (interpret(expression_value) && inrec(iop) == 0)
- ;
+ continue;
+ /* recover any space from C based alloca */
+ (void) alloca(0);
+
if (exiting)
break;
}
@@ -260,10 +285,10 @@ int *errflg;
register char *str;
int tflag = 0;
int outflag = 0;
- char *direction = "to";
- char *mode;
+ const char *direction = "to";
+ const char *mode;
int fd;
- char *what = NULL;
+ const char *what = NULL;
switch (tree->type) {
case Node_redirect_append:
@@ -376,15 +401,19 @@ int *errflg;
rp->fp = stdout;
else if (fd == fileno(stderr))
rp->fp = stderr;
- else
- rp->fp = fdopen(fd, mode);
- if (isatty(fd))
+ else {
+ rp->fp = fdopen(fd, (char *) mode);
+ /* don't leak file descriptors */
+ if (rp->fp == NULL)
+ close(fd);
+ }
+ if (rp->fp != NULL && isatty(fd))
rp->flag |= RED_NOBUF;
}
}
if (rp->fp == NULL && rp->iop == NULL) {
/* too many files open -- close one and try again */
- if (errno == EMFILE)
+ if (errno == EMFILE || errno == ENFILE)
close_one();
else {
/*
@@ -454,16 +483,18 @@ NODE *tree;
if (rp == NULL) /* no match */
return tmp_number((AWKNUM) 0.0);
fflush(stdout); /* synchronize regular output */
- tmp = tmp_number((AWKNUM)close_redir(rp));
+ tmp = tmp_number((AWKNUM)close_redir(rp, 0));
rp = NULL;
return tmp;
}
static int
-close_redir(rp)
+close_redir(rp, exitwarn)
register struct redirect *rp;
+int exitwarn;
{
int status = 0;
+ char *what;
if (rp == NULL)
return 0;
@@ -482,14 +513,19 @@ register struct redirect *rp;
rp->iop = NULL;
}
}
+
+ what = (rp->flag & RED_PIPE) ? "pipe" : "file";
+
+ if (exitwarn)
+ warning("no explicit close of %s \"%s\" provided",
+ what, rp->value);
+
/* SVR4 awk checks and warns about status of close */
if (status) {
char *s = strerror(errno);
- warning("failure status (%d) on %s close of \"%s\" (%s).",
- status,
- (rp->flag & RED_PIPE) ? "pipe" :
- "file", rp->value, s);
+ warning("failure status (%d) on %s close of \"%s\" (%s)",
+ status, what, rp->value, s);
if (! do_unix) {
/* set ERRNO too so that program can get at it */
@@ -544,20 +580,27 @@ close_io ()
int status = 0;
errno = 0;
- if (fclose(stdout)) {
+ for (rp = red_head; rp != NULL; rp = next) {
+ next = rp->next;
+ /* close_redir() will print a message if needed */
+ /* if do_lint, warn about lack of explicit close */
+ if (close_redir(rp, do_lint))
+ status++;
+ rp = NULL;
+ }
+ /*
+ * Some of the non-Unix os's have problems doing an fclose
+ * on stdout and stderr. Since we don't really need to close
+ * them, we just flush them, and do that across the board.
+ */
+ if (fflush(stdout)) {
warning("error writing standard output (%s).", strerror(errno));
status++;
}
- if (fclose(stderr)) {
+ if (fflush(stderr)) {
warning("error writing standard error (%s).", strerror(errno));
status++;
}
- for (rp = red_head; rp != NULL; rp = next) {
- next = rp->next;
- if (close_redir(rp))
- status++;
- rp = NULL;
- }
return status;
}
@@ -565,7 +608,7 @@ close_io ()
static int
str2mode(mode)
-char *mode;
+const char *mode;
{
int ret;
@@ -581,7 +624,9 @@ char *mode;
case 'a':
ret = O_WRONLY|O_APPEND|O_CREAT;
break;
+
default:
+ ret = 0; /* lint */
cant_happen();
}
return ret;
@@ -598,10 +643,10 @@ char *mode;
int
devopen(name, mode)
-char *name, *mode;
+const char *name, *mode;
{
int openfd = INVALID_HANDLE;
- char *cp, *ptr;
+ const char *cp, *ptr;
int flag = 0;
struct stat buf;
extern double strtod();
@@ -618,7 +663,7 @@ char *name, *mode;
if (STREQ(name, "-"))
openfd = fileno(stdin);
- else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
+ else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
cp = name + 5;
if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
@@ -647,7 +692,7 @@ strictopen:
/* spec_setup --- setup an IOBUF for a special internal file */
-void
+static void
spec_setup(iop, len, allocate)
IOBUF *iop;
int len;
@@ -674,10 +719,10 @@ int allocate;
/* specfdopen --- open a fd special file */
-int
+static int
specfdopen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
int fd;
IOBUF *tp;
@@ -694,23 +739,43 @@ char *name, *mode;
return 0;
}
+/*
+ * Following mess will improve in 2.16; this is written to avoid
+ * long lines, avoid splitting #if with backslash, and avoid #elif
+ * to maximize portability.
+ */
+#ifndef GETPGRP_NOARG
+#if defined(__svr4__) || defined(BSD4_4) || defined(_POSIX_SOURCE)
+#define GETPGRP_NOARG
+#else
+#if defined(i860) || defined(_AIX) || defined(hpux) || defined(VMS)
+#define GETPGRP_NOARG
+#else
+#if defined(OS2) || defined(MSDOS) || defined(AMIGA) || defined(atarist)
+#define GETPGRP_NOARG
+#endif
+#endif
+#endif
+#endif
+
+#ifdef GETPGRP_NOARG
+#define getpgrp_ARG /* nothing */
+#else
+#define getpgrp_ARG getpid()
+#endif
+
/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
-int
+static int
pidopen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
char tbuf[BUFSIZ];
int i;
if (name[6] == 'g')
-/* following #if will improve in 2.16 */
-#if defined(__svr4__) || defined(i860) || defined(_AIX) || defined(BSD4_4) || defined(__386BSD__)
- sprintf(tbuf, "%d\n", getpgrp());
-#else
- sprintf(tbuf, "%d\n", getpgrp(getpid()));
-#endif
+ sprintf(tbuf, "%d\n", getpgrp( getpgrp_ARG ));
else if (name[6] == 'i')
sprintf(tbuf, "%d\n", getpid());
else
@@ -733,15 +798,19 @@ char *name, *mode;
* supplementary group set.
*/
-int
+static int
useropen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
char tbuf[BUFSIZ], *cp;
int i;
#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
+#if defined(atarist) || defined(__svr4__) || defined(__osf__)
+ gid_t groupset[NGROUPS_MAX];
+#else
int groupset[NGROUPS_MAX];
+#endif
int ngroups;
#endif
@@ -755,7 +824,7 @@ char *name, *mode;
for (i = 0; i < ngroups; i++) {
*cp++ = ' ';
- sprintf(cp, "%d", groupset[i]);
+ sprintf(cp, "%d", (int)groupset[i]);
cp += strlen(cp);
}
#endif
@@ -773,18 +842,16 @@ char *name, *mode;
static IOBUF *
iop_open(name, mode)
-char *name, *mode;
+const char *name, *mode;
{
int openfd = INVALID_HANDLE;
- char *cp, *ptr;
int flag = 0;
- int i;
struct stat buf;
IOBUF *iop;
static struct internal {
- char *name;
+ const char *name;
int compare;
- int (*fp)();
+ int (*fp) P((IOBUF*,const char *,const char *));
IOBUF iob;
} table[] = {
{ "/dev/fd/", 8, specfdopen },
@@ -805,12 +872,12 @@ char *name, *mode;
if (STREQ(name, "-"))
openfd = fileno(stdin);
- else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
+ else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
int i;
for (i = 0; i < devcount; i++) {
if (STREQN(name, table[i].name, table[i].compare)) {
- IOBUF *iop = & table[i].iob;
+ iop = & table[i].iob;
if (iop->buf != NULL) {
spec_setup(iop, 0, 0);
@@ -939,8 +1006,9 @@ struct redirect *rp;
#else /* PIPES_SIMULATED */
/* use temporary file rather than pipe */
+ /* except if popen() provides real pipes too */
-#ifdef VMS
+#if defined(VMS) || defined(OS2) || defined (MSDOS)
static IOBUF *
gawk_popen(cmd, rp)
char *cmd;
@@ -958,7 +1026,7 @@ gawk_pclose(rp)
struct redirect *rp;
{
int rval, aval, fd = rp->iop->fd;
- FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
+ FILE *kludge = fdopen(fd, (char *) "r"); /* pclose needs FILE* w/ right fileno */
rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
rval = iop_close(rp->iop);
@@ -966,7 +1034,7 @@ struct redirect *rp;
aval = pclose(kludge);
return (rval < 0 ? rval : aval);
}
-#else /* VMS */
+#else /* VMS || OS2 || MSDOS */
static
struct {
@@ -1016,7 +1084,7 @@ struct redirect *rp;
free(pipes[cur].command);
return rval;
}
-#endif /* VMS */
+#endif /* VMS || OS2 || MSDOS */
#endif /* PIPES_SIMULATED */
@@ -1041,7 +1109,7 @@ NODE *tree;
rp = redirect(tree->rnode, &redir_error);
if (rp == NULL && redir_error) { /* failed redirect */
if (! do_unix) {
- char *s = strerror(redir_error);
+ s = strerror(redir_error);
unref(ERRNO_node->var_value);
ERRNO_node->var_value =
@@ -1056,7 +1124,7 @@ NODE *tree;
errcode = 0;
cnt = get_a_record(&s, iop, *RS, & errcode);
if (! do_unix && errcode != 0) {
- char *s = strerror(errcode);
+ s = strerror(errcode);
unref(ERRNO_node->var_value);
ERRNO_node->var_value = make_string(s, strlen(s));
@@ -1102,7 +1170,7 @@ NODE *tree;
int
pathopen (file)
-char *file;
+const char *file;
{
int fd = do_pathopen(file);
@@ -1134,12 +1202,12 @@ char *file;
static int
do_pathopen (file)
-char *file;
+const char *file;
{
- static char *savepath = DEFPATH; /* defined in config.h */
+ static const char *savepath = DEFPATH; /* defined in config.h */
static int first = 1;
- char *awkpath, *cp;
- char trypath[BUFSIZ];
+ const char *awkpath;
+ char *cp, trypath[BUFSIZ];
int fd;
if (STREQ(file, "-"))
@@ -1160,7 +1228,7 @@ char *file;
if (strchr(file, ':') != strchr(file, ']')
|| strchr(file, '>') != strchr(file, '/'))
#else /*!VMS*/
-#ifdef MSDOS
+#if defined(MSDOS) || defined(OS2)
if (strchr(file, '/') != strchr(file, '\\')
|| strchr(file, ':') != NULL)
#else
@@ -1169,6 +1237,12 @@ char *file;
#endif /*VMS*/
return (devopen(file, "r"));
+#if defined(MSDOS) || defined(OS2)
+ _searchenv(file, "AWKPATH", trypath);
+ if (trypath[0] == '\0')
+ _searchenv(file, "PATH", trypath);
+ return (trypath[0] == '\0') ? 0 : devopen(trypath, "r");
+#else
do {
trypath[0] = '\0';
/* this should take into account limits on size of trypath */
@@ -1180,7 +1254,7 @@ char *file;
#ifdef VMS
if (strchr(":]>/", *(cp-1)) == NULL)
#else
-#ifdef MSDOS
+#if defined(MSDOS) || defined(OS2)
if (strchr(":\\/", *(cp-1)) == NULL)
#else
if (*(cp-1) != '/')
@@ -1204,4 +1278,5 @@ char *file;
* Therefore try to open the file in the current directory.
*/
return (devopen(file, "r"));
+#endif
}
diff --git a/gnu/usr.bin/awk/iop.c b/gnu/usr.bin/awk/iop.c
index 0d7af1213db6..897daefbeb7c 100644
--- a/gnu/usr.bin/awk/iop.c
+++ b/gnu/usr.bin/awk/iop.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -62,7 +62,7 @@ int fd;
else if (fstat(fd, &stb) < 0)
return 8*512; /* conservative in case of DECnet access */
else
- return 24*512;
+ return 32*512;
#else
/*
@@ -146,17 +146,16 @@ int *errcode;
register char *bp = iop->off;
char *bufend;
char *start = iop->off; /* beginning of record */
- int saw_newline;
char rs;
- int eat_whitespace;
+ int saw_newline = 0, eat_whitespace = 0; /* used iff grRS==0 */
- if (iop->cnt == EOF) /* previous read hit EOF */
+ if (iop->cnt == EOF) { /* previous read hit EOF */
+ *out = NULL;
return EOF;
+ }
if (grRS == 0) { /* special case: grRS == "" */
rs = '\n';
- eat_whitespace = 0;
- saw_newline = 0;
} else
rs = (char) grRS;
@@ -181,9 +180,6 @@ int *errcode;
char *oldsplit = iop->buf + iop->secsiz;
long len; /* record length so far */
- if ((iop->flag & IOP_IS_INTERNAL) != 0)
- cant_happen();
-
len = bp - start;
if (len > iop->secsiz) {
/* expand secondary buffer */
@@ -245,7 +241,8 @@ int *errcode;
extern int default_FS;
if (default_FS && (bp == start || eat_whitespace)) {
- while (bp < iop->end && isspace(*bp))
+ while (bp < iop->end
+ && (*bp == ' ' || *bp == '\t' || *bp == '\n'))
bp++;
if (bp == iop->end) {
eat_whitespace = 1;
@@ -275,8 +272,10 @@ int *errcode;
iop->cnt = bp - start;
}
if (iop->cnt == EOF
- && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp))
+ && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp)) {
+ *out = NULL;
return EOF;
+ }
iop->off = bp;
bp--;
@@ -284,6 +283,10 @@ int *errcode;
bp++;
*bp = '\0';
if (grRS == 0) {
+ /* there could be more newlines left, clean 'em out now */
+ while (*(iop->off) == rs && iop->off <= iop->end)
+ (iop->off)++;
+
if (*--bp == rs)
*bp = '\0';
else
diff --git a/gnu/usr.bin/awk/main.c b/gnu/usr.bin/awk/main.c
index 77d0bf74e143..a14efffe15cf 100644
--- a/gnu/usr.bin/awk/main.c
+++ b/gnu/usr.bin/awk/main.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -55,9 +55,9 @@ NODE *ENVIRON_node, *IGNORECASE_node;
NODE *ARGC_node, *ARGV_node, *ARGIND_node;
NODE *FIELDWIDTHS_node;
-int NF;
-int NR;
-int FNR;
+long NF;
+long NR;
+long FNR;
int IGNORECASE;
char *RS;
char *OFS;
@@ -134,10 +134,19 @@ char **argv;
{
int c;
char *scan;
+ /* the + on the front tells GNU getopt not to rearrange argv */
+ const char *optlist = "+F:f:v:W:m:";
+ int stopped_early = 0;
+ int old_optind;
extern int optind;
extern int opterr;
extern char *optarg;
- int i;
+
+#ifdef __EMX__
+ _response(&argc, &argv);
+ _wildcard(&argc, &argv);
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+#endif
(void) signal(SIGFPE, (SIGTYPE (*) P((int))) catchsig);
(void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig);
@@ -165,7 +174,6 @@ char **argv;
Nnull_string->flags = (PERM|STR|STRING|NUM|NUMBER);
/* Set up the special variables */
-
/*
* Note that this must be done BEFORE arg parsing else -F
* breaks horribly
@@ -179,11 +187,16 @@ char **argv;
/* Tell the regex routines how they should work. . . */
resetup();
+#ifdef fpsetmask
+ fpsetmask(~0xff);
+#endif
/* we do error messages ourselves on invalid options */
opterr = 0;
- /* the + on the front tells GNU getopt not to rearrange argv */
- while ((c = getopt_long(argc, argv, "+F:f:v:W:", optab, NULL)) != EOF) {
+ /* option processing. ready, set, go! */
+ for (optopt = 0, old_optind = 1;
+ (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
+ optopt = 0, old_optind = optind) {
if (do_posix)
opterr = 1;
switch (c) {
@@ -215,6 +228,19 @@ char **argv;
pre_assign(optarg);
break;
+ case 'm':
+ /*
+ * Research awk extension.
+ * -mf=nnn set # fields, gawk ignores
+ * -mr=nnn set record length, ditto
+ */
+ if (do_lint)
+ warning("-m[fr] option irrelevant");
+ if ((optarg[0] != 'r' && optarg[0] != 'f')
+ || optarg[1] != '=')
+ warning("-m option usage: -m[fn]=nnn");
+ break;
+
case 'W': /* gawk specific options */
gawk_option(optarg);
break;
@@ -233,7 +259,7 @@ char **argv;
break;
case 's':
- if (strlen(optarg) == 0)
+ if (optarg[0] == '\0')
warning("empty argument to --source ignored");
else {
srcfiles[++numfiles].stype = CMDLINE;
@@ -247,6 +273,14 @@ char **argv;
break;
#endif
+ case 0:
+ /*
+ * getopt_long found an option that sets a variable
+ * instead of returning a letter. Do nothing, just
+ * cycle around for the next one.
+ */
+ break;
+
case '?':
default:
/*
@@ -254,9 +288,27 @@ char **argv;
* option stops argument processing so that it can
* go into ARGV for the awk program to see. This
* makes use of ``#! /bin/gawk -f'' easier.
+ *
+ * However, it's never simple. If optopt is set,
+ * an option that requires an argument didn't get the
+ * argument. We care because if opterr is 0, then
+ * getopt_long won't print the error message for us.
*/
- if (! do_posix)
+ if (! do_posix
+ && (optopt == 0 || strchr(optlist, optopt) == NULL)) {
+ /*
+ * can't just do optind--. In case of an
+ * option with >=2 letters, getopt_long
+ * won't have incremented optind.
+ */
+ optind = old_optind;
+ stopped_early = 1;
goto out;
+ } else if (optopt)
+ /* Use 1003.2 required message format */
+ fprintf (stderr,
+ "%s: option requires an argument -- %c\n",
+ myname, optopt);
/* else
let getopt print error message for us */
break;
@@ -267,6 +319,14 @@ out:
if (do_nostalgia)
nostalgia();
+ /* check for POSIXLY_CORRECT environment variable */
+ if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
+ do_posix = 1;
+ if (do_lint)
+ warning(
+ "environment variable `POSIXLY_CORRECT' set: turning on --posix");
+ }
+
/* POSIX compliance also implies no Unix extensions either */
if (do_posix)
do_unix = 1;
@@ -278,7 +338,7 @@ out:
output_is_tty = 1;
/* No -f or --source options, use next arg */
if (numfiles == -1) {
- if (optind > argc - 1) /* no args left */
+ if (optind > argc - 1 || stopped_early) /* no args left or no program */
usage(1);
srcfiles[++numfiles].stype = CMDLINE;
srcfiles[numfiles].val = argv[optind];
@@ -294,6 +354,10 @@ out:
/* Set up the field variables */
init_fields();
+ if (do_lint && begin_block == NULL && expression_value == NULL
+ && end_block == NULL)
+ warning("no program");
+
if (begin_block) {
in_begin_rule = 1;
(void) interpret(begin_block);
@@ -318,25 +382,29 @@ static void
usage(exitval)
int exitval;
{
- char *opt1 = " -f progfile [--]";
- char *opt2 = " [--] 'program'";
- char *regops = " [POSIX or GNU style options]";
+ const char *opt1 = " -f progfile [--]";
+#if defined(MSDOS) || defined(OS2) || defined(VMS)
+ const char *opt2 = " [--] \"program\"";
+#else
+ const char *opt2 = " [--] 'program'";
+#endif
+ const char *regops = " [POSIX or GNU style options]";
- version();
- fprintf(stderr, "usage: %s%s%s file ...\n %s%s%s file ...\n",
+ fprintf(stderr, "Usage:\t%s%s%s file ...\n\t%s%s%s file ...\n",
myname, regops, opt1, myname, regops, opt2);
/* GNU long options info. Gack. */
- fputs("\nPOSIX options:\t\tGNU long options:\n", stderr);
+ fputs("POSIX options:\t\tGNU long options:\n", stderr);
fputs("\t-f progfile\t\t--file=progfile\n", stderr);
fputs("\t-F fs\t\t\t--field-separator=fs\n", stderr);
fputs("\t-v var=val\t\t--assign=var=val\n", stderr);
+ fputs("\t-m[fr]=val\n", stderr);
fputs("\t-W compat\t\t--compat\n", stderr);
fputs("\t-W copyleft\t\t--copyleft\n", stderr);
fputs("\t-W copyright\t\t--copyright\n", stderr);
fputs("\t-W help\t\t\t--help\n", stderr);
fputs("\t-W lint\t\t\t--lint\n", stderr);
-#if 0
+#ifdef NOSTALGIA
fputs("\t-W nostalgia\t\t--nostalgia\n", stderr);
#endif
#ifdef DEBUG
@@ -371,7 +439,6 @@ GNU General Public License for more details.\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
- version();
fputs(blurb_part1, stderr);
fputs(blurb_part2, stderr);
fputs(blurb_part3, stderr);
@@ -383,7 +450,8 @@ cmdline_fs(str)
char *str;
{
register NODE **tmp;
- int len = strlen(str);
+ /* int len = strlen(str); *//* don't do that - we want to
+ avoid mismatched types */
tmp = get_lhs(FS_node, (Func_ptr *) 0);
unref(*tmp);
@@ -400,7 +468,7 @@ char *str;
if (do_unix && ! do_posix)
str[0] = '\t';
}
- *tmp = make_str_node(str, len, SCAN); /* do process escapes */
+ *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
set_FS();
}
@@ -432,9 +500,9 @@ char **argv;
*/
struct varinit {
NODE **spec;
- char *name;
+ const char *name;
NODETYPE type;
- char *strval;
+ const char *strval;
AWKNUM numval;
Func_ptr assign;
};
@@ -446,7 +514,7 @@ static struct varinit varinit[] = {
{&FS_node, "FS", Node_FS, " ", 0, 0 },
{&RS_node, "RS", Node_RS, "\n", 0, set_RS },
{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE, 0, 0, set_IGNORECASE },
-{&FILENAME_node, "FILENAME", Node_var, "-", 0, 0 },
+{&FILENAME_node, "FILENAME", Node_var, "", 0, 0 },
{&OFS_node, "OFS", Node_OFS, " ", 0, set_OFS },
{&ORS_node, "ORS", Node_ORS, "\n", 0, set_ORS },
{&OFMT_node, "OFMT", Node_OFMT, "%.6g", 0, set_OFMT },
@@ -465,9 +533,10 @@ init_vars()
register struct varinit *vp;
for (vp = varinit; vp->name; vp++) {
- *(vp->spec) = install(vp->name,
+ *(vp->spec) = install((char *) vp->name,
node(vp->strval == 0 ? make_number(vp->numval)
- : make_string(vp->strval, strlen(vp->strval)),
+ : make_string((char *) vp->strval,
+ strlen(vp->strval)),
vp->type, (NODE *) NULL));
if (vp->assign)
(*(vp->assign))();
@@ -477,7 +546,7 @@ init_vars()
void
load_environ()
{
-#if !defined(MSDOS) && !(defined(VMS) && defined(__DECC))
+#if !defined(MSDOS) && !defined(OS2) && !(defined(VMS) && defined(__DECC))
extern char **environ;
#endif
register char *var, *val;
@@ -510,7 +579,8 @@ char *
arg_assign(arg)
char *arg;
{
- char *cp;
+ char *cp, *cp2;
+ int badvar;
Func_ptr after_assign = NULL;
NODE *var;
NODE *it;
@@ -519,6 +589,19 @@ char *arg;
cp = strchr(arg, '=');
if (cp != NULL) {
*cp++ = '\0';
+ /* first check that the variable name has valid syntax */
+ badvar = 0;
+ if (! isalpha(arg[0]) && arg[0] != '_')
+ badvar = 1;
+ else
+ for (cp2 = arg+1; *cp2; cp2++)
+ if (! isalnum(*cp2) && *cp2 != '_') {
+ badvar = 1;
+ break;
+ }
+ if (badvar)
+ fatal("illegal name `%s' in variable assignment", arg);
+
/*
* Recent versions of nawk expand escapes inside assignments.
* This makes sense, so we do it too.
@@ -657,7 +740,7 @@ char *optstr;
if (strncasecmp(cp, "source=", 7) != 0)
goto unknown;
cp += 7;
- if (strlen(cp) == 0)
+ if (cp[0] == '\0')
warning("empty argument to -Wsource ignored");
else {
srcfiles[++numfiles].stype = CMDLINE;
@@ -689,40 +772,43 @@ static void
version()
{
fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+ /* per GNU coding standards, exit successfully, do nothing else */
+ exit(0);
}
-/* static */
+/* this mess will improve in 2.16 */
char *
gawk_name(filespec)
char *filespec;
{
- char *p;
-
+ char *p;
+
#ifdef VMS /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */
- char *q;
+ char *q;
- p = strrchr(filespec, ']'); /* directory punctuation */
- q = strrchr(filespec, '>'); /* alternate <international> punct */
+ p = strrchr(filespec, ']'); /* directory punctuation */
+ q = strrchr(filespec, '>'); /* alternate <international> punct */
- if (p == NULL || q > p) p = q;
+ if (p == NULL || q > p) p = q;
p = strdup(p == NULL ? filespec : (p + 1));
if ((q = strrchr(p, '.')) != NULL) *q = '\0'; /* strip .typ;vers */
return p;
#endif /*VMS*/
-#if defined(MSDOS) || defined(atarist)
- char *q;
+#if defined(MSDOS) || defined(OS2) || defined(atarist)
+ char *q;
- p = filespec;
-
- if (q = strrchr(p, '\\'))
- p = q + 1;
- if (q = strchr(p, '.'))
- *q = '\0';
- strlwr(p);
+ for (p = filespec; (p = strchr(p, '\\')); *p = '/')
+ ;
+ p = filespec;
+ if ((q = strrchr(p, '/')))
+ p = q + 1;
+ if ((q = strchr(p, '.')))
+ *q = '\0';
+ strlwr(p);
- return (p == NULL ? filespec : p);
+ return (p == NULL ? filespec : p);
#endif /* MSDOS || atarist */
/* "path/name" -> "name" */
diff --git a/gnu/usr.bin/awk/msg.c b/gnu/usr.bin/awk/msg.c
index b60fe9d1e5e9..4bd9f901b559 100644
--- a/gnu/usr.bin/awk/msg.c
+++ b/gnu/usr.bin/awk/msg.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -31,8 +31,8 @@ char *source = NULL;
/* VARARGS2 */
void
err(s, emsg, argp)
-char *s;
-char *emsg;
+const char *s;
+const char *emsg;
va_list argp;
{
char *file;
@@ -49,9 +49,10 @@ va_list argp;
}
if (FNR) {
file = FILENAME_node->var_value->stptr;
+ (void) putc('(', stderr);
if (file)
- (void) fprintf(stderr, "(FILENAME=%s ", file);
- (void) fprintf(stderr, "FNR=%d) ", FNR);
+ (void) fprintf(stderr, "FILENAME=%s ", file);
+ (void) fprintf(stderr, "FNR=%ld) ", FNR);
}
(void) fprintf(stderr, s);
vfprintf(stderr, emsg, argp);
diff --git a/gnu/usr.bin/awk/node.c b/gnu/usr.bin/awk/node.c
index 65ecb0ed1723..dca4ad191b9f 100644
--- a/gnu/usr.bin/awk/node.c
+++ b/gnu/usr.bin/awk/node.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -35,7 +35,7 @@ register NODE *n;
register char *cpend;
char save;
char *ptr;
- unsigned int newflags = 0;
+ unsigned int newflags;
#ifdef DEBUG
if (n == NULL)
@@ -69,7 +69,8 @@ register NODE *n;
if (n->flags & MAYBE_NUM) {
newflags = NUMBER;
n->flags &= ~MAYBE_NUM;
- }
+ } else
+ newflags = 0;
if (cpend - cp == 1) {
if (isdigit(*cp)) {
n->numbr = (AWKNUM)(*cp - '0');
@@ -101,7 +102,7 @@ register NODE *n;
* (more complicated) variations on this theme didn't seem to pay off, but
* systematic testing might be in order at some point
*/
-static char *values[] = {
+static const char *values[] = {
"0",
"1",
"2",
@@ -121,7 +122,7 @@ register NODE *s;
{
char buf[128];
register char *sp = buf;
- register long num = 0;
+ double val;
#ifdef DEBUG
if (s == NULL) cant_happen();
@@ -131,26 +132,56 @@ register NODE *s;
if (s->stref != 0) ; /*cant_happen();*/
#endif
- /* avoids floating point exception in DOS*/
- if ( s->numbr <= LONG_MAX && s->numbr >= -LONG_MAX)
- num = (long)s->numbr;
- if ((AWKNUM) num == s->numbr) { /* integral value */
+ /* not an integral value, or out of range */
+ if ((val = double_to_int(s->numbr)) != s->numbr
+ || val < LONG_MIN || val > LONG_MAX) {
+#ifdef GFMT_WORKAROUND
+ NODE *dummy, *r;
+ unsigned short oflags;
+ extern NODE *format_tree P((const char *, int, NODE *));
+ extern NODE **fmt_list; /* declared in eval.c */
+
+ /* create dummy node for a sole use of format_tree */
+ getnode(dummy);
+ dummy->lnode = s;
+ dummy->rnode = NULL;
+ oflags = s->flags;
+ s->flags |= PERM; /* prevent from freeing by format_tree() */
+ r = format_tree(CONVFMT, fmt_list[CONVFMTidx]->stlen, dummy);
+ s->flags = oflags;
+ s->stfmt = (char)CONVFMTidx;
+ s->stlen = r->stlen;
+ s->stptr = r->stptr;
+ freenode(r); /* Do not free_temp(r)! We want */
+ freenode(dummy); /* to keep s->stptr == r->stpr. */
+
+ goto no_malloc;
+#else
+ /*
+ * no need for a "replacement" formatting by gawk,
+ * just use sprintf
+ */
+ sprintf(sp, CONVFMT, s->numbr);
+ s->stlen = strlen(sp);
+ s->stfmt = (char)CONVFMTidx;
+#endif /* GFMT_WORKAROUND */
+ } else {
+ /* integral value */
+ /* force conversion to long only once */
+ register long num = (long) val;
if (num < NVAL && num >= 0) {
- sp = values[num];
+ sp = (char *) values[num];
s->stlen = 1;
} else {
(void) sprintf(sp, "%ld", num);
s->stlen = strlen(sp);
}
s->stfmt = -1;
- } else {
- (void) sprintf(sp, CONVFMT, s->numbr);
- s->stlen = strlen(sp);
- s->stfmt = (char)CONVFMTidx;
}
- s->stref = 1;
emalloc(s->stptr, char *, s->stlen + 2, "force_string");
memcpy(s->stptr, sp, s->stlen+1);
+no_malloc:
+ s->stref = 1;
s->flags |= STR;
return s;
}
@@ -182,7 +213,8 @@ NODE *n;
if (n->type == Node_val && (n->flags & STR)) {
r->stref = 1;
emalloc(r->stptr, char *, r->stlen + 2, "dupnode");
- memcpy(r->stptr, n->stptr, r->stlen+1);
+ memcpy(r->stptr, n->stptr, r->stlen);
+ r->stptr[r->stlen] = '\0';
}
return r;
}
@@ -285,8 +317,10 @@ more_nodes()
/* get more nodes and initialize list */
emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
- for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
+ for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++) {
+ np->flags = 0;
np->nextp = np + 1;
+ }
np->nextp = NULL;
np = nextfree;
nextfree = nextfree->nextp;
diff --git a/gnu/usr.bin/awk/patchlevel.h b/gnu/usr.bin/awk/patchlevel.h
index c6161a1f274c..c80ca154ec62 100644
--- a/gnu/usr.bin/awk/patchlevel.h
+++ b/gnu/usr.bin/awk/patchlevel.h
@@ -1 +1 @@
-#define PATCHLEVEL 2
+#define PATCHLEVEL 5
diff --git a/gnu/usr.bin/awk/protos.h b/gnu/usr.bin/awk/protos.h
index 25af32165b02..1d4ac9987e1c 100644
--- a/gnu/usr.bin/awk/protos.h
+++ b/gnu/usr.bin/awk/protos.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1991, 1992, the Free Software Foundation, Inc.
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -32,14 +32,16 @@ extern aptr_t malloc P((MALLOC_ARG_T));
extern aptr_t realloc P((aptr_t, MALLOC_ARG_T));
extern aptr_t calloc P((MALLOC_ARG_T, MALLOC_ARG_T));
+#if !defined(sun) && !defined(__sun__)
extern void free P((aptr_t));
-extern char *getenv P((char *));
+#endif
+extern char *getenv P((const char *));
extern char *strcpy P((char *, const char *));
extern char *strcat P((char *, const char *));
-extern char *strncpy P((char *, const char *, int));
extern int strcmp P((const char *, const char *));
-extern int strncmp P((const char *, const char *, int));
+extern char *strncpy P((char *, const char *, size_t));
+extern int strncmp P((const char *, const char *, size_t));
#ifndef VMS
extern char *strerror P((int));
#else
@@ -48,22 +50,29 @@ extern char *strerror P((int,...));
extern char *strchr P((const char *, int));
extern char *strrchr P((const char *, int));
extern char *strstr P((const char *s1, const char *s2));
-extern int strlen P((const char *));
+extern size_t strlen P((const char *));
extern long strtol P((const char *, char **, int));
#if !defined(_MSC_VER) && !defined(__GNU_LIBRARY__)
-extern int strftime P((char *, int, const char *, const struct tm *));
+extern size_t strftime P((char *, size_t, const char *, const struct tm *));
#endif
+#ifdef __STDC__
extern time_t time P((time_t *));
+#else
+extern long time();
+#endif
extern aptr_t memset P((aptr_t, int, size_t));
extern aptr_t memcpy P((aptr_t, const aptr_t, size_t));
extern aptr_t memmove P((aptr_t, const aptr_t, size_t));
extern aptr_t memchr P((const aptr_t, int, size_t));
extern int memcmp P((const aptr_t, const aptr_t, size_t));
-/* extern int fprintf P((FILE *, char *, ...)); */
-extern int fprintf P(());
+extern int fprintf P((FILE *, const char *, ...));
#if !defined(MSDOS) && !defined(__GNU_LIBRARY__)
-extern int fwrite P((const char *, int, int, FILE *));
+#ifdef __STDC__
+extern size_t fwrite P((const aptr_t, size_t, size_t, FILE *));
+#else
+extern int fwrite();
+#endif
extern int fputs P((const char *, FILE *));
extern int unlink P((const char *));
#endif
@@ -75,7 +84,7 @@ extern void abort P(());
extern int isatty P((int));
extern void exit P((int));
extern int system P((const char *));
-extern int sscanf P((/* char *, char *, ... */));
+extern int sscanf P((const char *, const char *, ...));
#ifndef toupper
extern int toupper P((int));
#endif
@@ -84,32 +93,30 @@ extern int tolower P((int));
#endif
extern double pow P((double x, double y));
-extern double atof P((char *));
+extern double atof P((const char *));
extern double strtod P((const char *, char **));
extern int fstat P((int, struct stat *));
extern int stat P((const char *, struct stat *));
extern off_t lseek P((int, off_t, int));
extern int fseek P((FILE *, long, int));
extern int close P((int));
-extern int creat P(());
-extern int open P(());
+extern int creat P((const char *, mode_t));
+extern int open P((const char *, int, ...));
extern int pipe P((int *));
extern int dup P((int));
extern int dup2 P((int,int));
extern int fork P(());
extern int execl P((/* char *, char *, ... */));
+#ifndef __STDC__
extern int read P((int, char *, int));
+#endif
extern int wait P((int *));
extern void _exit P((int));
-#ifndef __STDC__
-extern long time P((long *));
-#endif
-
#ifdef NON_STD_SPRINTF
-extern char *sprintf();
+extern char *sprintf P((char *, const char*, ...));
#else
-extern int sprintf();
+extern int sprintf P((char *, const char*, ...));
#endif /* SPRINTF_INT */
#undef aptr_t
diff --git a/gnu/usr.bin/awk/re.c b/gnu/usr.bin/awk/re.c
index 495b0963cadb..4ea22c232685 100644
--- a/gnu/usr.bin/awk/re.c
+++ b/gnu/usr.bin/awk/re.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -30,12 +30,12 @@
Regexp *
make_regexp(s, len, ignorecase, dfa)
char *s;
-int len;
+size_t len;
int ignorecase;
int dfa;
{
Regexp *rp;
- char *err;
+ const char *rerr;
char *src = s;
char *temp;
char *end = s + len;
@@ -90,7 +90,7 @@ int dfa;
*dest = '\0' ; /* Only necessary if we print dest ? */
emalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
memset((char *) rp, 0, sizeof(*rp));
- emalloc(rp->pat.buffer, char *, 16, "make_regexp");
+ emalloc(rp->pat.buffer, unsigned char *, 16, "make_regexp");
rp->pat.allocated = 16;
emalloc(rp->pat.fastmap, char *, 256, "make_regexp");
@@ -99,13 +99,14 @@ int dfa;
else
rp->pat.translate = NULL;
len = dest - temp;
- if ((err = re_compile_pattern(temp, (size_t) len, &(rp->pat))) != NULL)
- fatal("%s: /%s/", err, temp);
+ if ((rerr = re_compile_pattern(temp, len, &(rp->pat))) != NULL)
+ fatal("%s: /%s/", rerr, temp);
if (dfa && !ignorecase) {
- regcompile(temp, len, &(rp->dfareg), 1);
+ dfacomp(temp, len, &(rp->dfareg), 1);
rp->dfa = 1;
} else
rp->dfa = 0;
+
free(temp);
return rp;
}
@@ -115,24 +116,24 @@ research(rp, str, start, len, need_start)
Regexp *rp;
register char *str;
int start;
-register int len;
+register size_t len;
int need_start;
{
char *ret = str;
if (rp->dfa) {
- char save1;
- char save2;
+ char save;
int count = 0;
int try_backref;
- save1 = str[start+len];
- str[start+len] = '\n';
- save2 = str[start+len+1];
- ret = regexecute(&(rp->dfareg), str+start, str+start+len+1, 1,
+ /*
+ * dfa likes to stick a '\n' right after the matched
+ * text. So we just save and restore the character.
+ */
+ save = str[start+len];
+ ret = dfaexec(&(rp->dfareg), str+start, str+start+len, 1,
&count, &try_backref);
- str[start+len] = save1;
- str[start+len+1] = save2;
+ str[start+len] = save;
}
if (ret) {
if (need_start || rp->dfa == 0)
@@ -151,12 +152,12 @@ Regexp *rp;
free(rp->pat.buffer);
free(rp->pat.fastmap);
if (rp->dfa)
- reg_free(&(rp->dfareg));
+ dfafree(&(rp->dfareg));
free(rp);
}
void
-reg_error(s)
+dfaerror(s)
const char *s;
{
fatal(s);
@@ -194,7 +195,8 @@ NODE *t;
t->re_text = dupnode(t1);
free_temp(t1);
}
- t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen, IGNORECASE, t->re_cnt);
+ t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen,
+ IGNORECASE, t->re_cnt);
t->re_flags &= ~CASE;
t->re_flags |= IGNORECASE;
return t->re_reg;
@@ -203,6 +205,8 @@ NODE *t;
void
resetup()
{
- (void) re_set_syntax(RE_SYNTAX_AWK);
- regsyntax(RE_SYNTAX_AWK, 0);
+ reg_syntax_t syn = RE_SYNTAX_AWK;
+
+ (void) re_set_syntax(syn);
+ dfasyntax(syn, 0);
}
diff --git a/gnu/usr.bin/awk/regex.c b/gnu/usr.bin/awk/regex.c
index f4dd4c2cd24d..6a36f3de8178 100644
--- a/gnu/usr.bin/awk/regex.c
+++ b/gnu/usr.bin/awk/regex.c
@@ -1,9 +1,13 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (Implements POSIX draft P10003.2/D11.2, except for
+ internationalization features.)
+
+ 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 1, or (at your option)
+ the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
@@ -15,75 +19,63 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+ #pragma alloca
+#endif
-/* To test, compile with -Dtest. This Dtestable feature turns this into
- a self-contained program which reads a pattern, describes how it
- compiles, then reads a string and searches for it.
-
- On the other hand, if you compile with both -Dtest and -Dcanned you
- can run some tests we've already thought of. */
+#define _GNU_SOURCE
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
-#ifdef emacs
+#if defined(STDC_HEADERS) && !defined(emacs)
+#include <stddef.h>
+#else
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+#include <sys/types.h>
+#endif
-/* The `emacs' switch turns on certain special matching commands
- that make sense only in emacs. */
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
#include "lisp.h"
#include "buffer.h"
#include "syntax.h"
-/* We write fatal error messages on standard error. */
-#include <stdio.h>
-
-/* isalpha(3) etc. are used for the character classes. */
-#include <ctype.h>
-
-#else /* not emacs */
+/* Emacs uses `NULL' as a predicate. */
+#undef NULL
-#include "awk.h"
+#else /* not emacs */
-#define NO_ALLOCA /* try it out for now */
-#ifndef NO_ALLOCA
-/* Make alloca work the best possible way. */
-#ifdef __GNUC__
-#ifndef atarist
-#ifndef alloca
-#define alloca __builtin_alloca
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+ `BSTRING', as far as I know, and neither of them use this code. */
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
#endif
-#endif /* atarist */
#else
-#if defined(sparc) && !defined(__GNUC__)
-#include <alloca.h>
+#include <strings.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
#else
-char *alloca ();
+char *malloc ();
+char *realloc ();
#endif
-#endif /* __GNUC__ */
-
-#define FREE_AND_RETURN_VOID(stackb) return
-#define FREE_AND_RETURN(stackb,val) return(val)
-#define DOUBLE_STACK(stackx,stackb,len) \
- (stackx = (unsigned char **) alloca (2 * len \
- * sizeof (unsigned char *)),\
- /* Only copy what is in use. */ \
- (unsigned char **) memcpy (stackx, stackb, len * sizeof (char *)))
-#else /* NO_ALLOCA defined */
-#define FREE_AND_RETURN_VOID(stackb) free(stackb);return
-#define FREE_AND_RETURN(stackb,val) free(stackb);return(val)
-#define DOUBLE_STACK(stackx,stackb,len) \
- (unsigned char **) realloc (stackb, 2 * len * sizeof (unsigned char *))
-#endif /* NO_ALLOCA */
-
-static void store_jump P((char *, int, char *));
-static void insert_jump P((int, char *, char *, char *));
-static void store_jump_n P((char *, int, char *, unsigned));
-static void insert_jump_n P((int, char *, char *, char *, unsigned));
-static void insert_op_2 P((int, char *, char *, int, int ));
-static int memcmp_translate P((unsigned char *, unsigned char *,
- int, unsigned char *));
-long re_set_syntax P((long));
-
-/* Define the syntax stuff, so we can do the \<, \>, etc. */
+
+
+/* Define the syntax stuff for \<, \>, etc. */
/* This must be nonzero for the wordchar and notwordchar pattern
commands in re_match_2. */
@@ -91,18 +83,16 @@ long re_set_syntax P((long));
#define Sword 1
#endif
-#define SYNTAX(c) re_syntax_table[c]
-
-
#ifdef SYNTAX_TABLE
-char *re_syntax_table;
+extern char *re_syntax_table;
#else /* not SYNTAX_TABLE */
-static char re_syntax_table[256];
-static void init_syntax_once P((void));
+/* How many characters in the character set. */
+#define CHAR_SET_SIZE 256
+static char re_syntax_table[CHAR_SET_SIZE];
static void
init_syntax_once ()
@@ -113,7 +103,7 @@ init_syntax_once ()
if (done)
return;
- memset (re_syntax_table, 0, sizeof re_syntax_table);
+ bzero (re_syntax_table, sizeof re_syntax_table);
for (c = 'a'; c <= 'z'; c++)
re_syntax_table[c] = Sword;
@@ -123,1504 +113,2900 @@ init_syntax_once ()
for (c = '0'; c <= '9'; c++)
re_syntax_table[c] = Sword;
-
- /* Add specific syntax for ISO Latin-1. */
- for (c = 0300; c <= 0377; c++)
- re_syntax_table[c] = Sword;
- re_syntax_table[0327] = 0;
- re_syntax_table[0367] = 0;
+
+ re_syntax_table['_'] = Sword;
done = 1;
}
-#endif /* SYNTAX_TABLE */
-#undef P
-#endif /* emacs */
+#endif /* not SYNTAX_TABLE */
+#define SYNTAX(c) re_syntax_table[c]
-/* Sequents are missing isgraph. */
-#ifndef isgraph
-#define isgraph(c) (isprint((c)) && !isspace((c)))
-#endif
-
+#endif /* not emacs */
+
/* Get the interface, including the syntax bits. */
#include "regex.h"
+/* isalpha etc. are used for the character classes. */
+#include <ctype.h>
-/* These are the command codes that appear in compiled regular
- expressions, one per byte. Some command codes are followed by
- argument bytes. A command code can specify any interpretation
- whatsoever for its arguments. Zero-bytes may appear in the compiled
- regular expression.
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+#if ! defined (isascii) || defined (STDC_HEADERS)
+#undef isascii
+#define isascii(c) 1
+#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))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+ since ours (we hope) works properly with all combinations of
+ machines, compilers, `char' and `unsigned char' argument types.
+ (Per Bothner suggested the basic approach.) */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
+ use `alloca' instead of `malloc'. This is because using malloc in
+ re_search* or re_match* could cause memory leaks when C-g is used in
+ Emacs; also, malloc is slower and causes storage fragmentation. On
+ the other hand, malloc is more portable, and easier to debug.
- The value of `exactn' is needed in search.c (search_buffer) in emacs.
+ Because we sometimes use alloca, some routines have to be macros,
+ not functions -- `alloca'-allocated space disappears at the end of the
+ function it is called in. */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+
+#else /* not REGEX_MALLOC */
+
+/* Emacs already defines alloca, sometimes. */
+#ifndef alloca
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top. */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable. */
+#define REGEX_REALLOCATE(source, osize, nsize) \
+ (destination = (char *) alloca (nsize), \
+ bcopy (source, destination, osize), \
+ destination)
+
+#endif /* not REGEX_MALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+ `string1' or just past its end. This works if PTR is NULL, which is
+ a good thing. */
+#define FIRST_STRING_P(ptr) \
+ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail. */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits. */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+/* These are the command codes that appear in compiled regular
+ expressions. Some opcodes are followed by argument bytes. A
+ command code can specify any interpretation whatsoever for its
+ arguments. Zero bytes may appear in the compiled regular expression.
+
+ The value of `exactn' is needed in search.c (search_buffer) in Emacs.
So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
`exactn' we use here must also be 1. */
-enum regexpcode
- {
- unused=0,
- exactn=1, /* Followed by one byte giving n, then by n literal bytes. */
- begline, /* Fail unless at beginning of line. */
- endline, /* Fail unless at end of line. */
- jump, /* Followed by two bytes giving relative address to jump to. */
- on_failure_jump, /* Followed by two bytes giving relative address of
- place to resume at in case of failure. */
- finalize_jump, /* Throw away latest failure point and then jump to
- address. */
- maybe_finalize_jump, /* Like jump but finalize if safe to do so.
- This is used to jump back to the beginning
- of a repeat. If the command that follows
- this jump is clearly incompatible with the
- one at the beginning of the repeat, such that
- we can be sure that there is no use backtracking
- out of repetitions already completed,
- then we finalize. */
- dummy_failure_jump, /* Jump, and push a dummy failure point. This
- failure point will be thrown away if an attempt
- is made to use it for a failure. A + construct
- makes this before the first repeat. Also
- use it as an intermediary kind of jump when
- compiling an or construct. */
- succeed_n, /* Used like on_failure_jump except has to succeed n times;
- then gets turned into an on_failure_jump. The relative
- address following it is useless until then. The
- address is followed by two bytes containing n. */
- jump_n, /* Similar to jump, but jump n times only; also the relative
- address following is in turn followed by yet two more bytes
- containing n. */
- set_number_at, /* Set the following relative location to the
- subsequent number. */
- anychar, /* Matches any (more or less) one character. */
- charset, /* Matches any one char belonging to specified set.
- First following byte is number of bitmap bytes.
- Then come bytes for a bitmap saying which chars are in.
- Bits in each byte are ordered low-bit-first.
- A character is in the set if its bit is 1.
- A character too large to have a bit in the map
- is automatically not in the set. */
- charset_not, /* Same parameters as charset, but match any character
- that is not one of those specified. */
- start_memory, /* Start remembering the text that is matched, for
- storing in a memory register. Followed by one
- byte containing the register number. Register numbers
- must be in the range 0 through RE_NREGS. */
- stop_memory, /* Stop remembering the text that is matched
- and store it in a memory register. Followed by
- one byte containing the register number. Register
- numbers must be in the range 0 through RE_NREGS. */
- duplicate, /* Match a duplicate of something remembered.
- Followed by one byte containing the index of the memory
- register. */
- before_dot, /* Succeeds if before point. */
- at_dot, /* Succeeds if at point. */
- after_dot, /* Succeeds if after point. */
- begbuf, /* Succeeds if at beginning of buffer. */
- endbuf, /* Succeeds if at end of buffer. */
- wordchar, /* Matches any word-constituent character. */
- notwordchar, /* Matches any char that is not a word-constituent. */
- wordbeg, /* Succeeds if at word beginning. */
- wordend, /* Succeeds if at word end. */
- wordbound, /* Succeeds if at a word boundary. */
- notwordbound,/* Succeeds if not at a word boundary. */
- syntaxspec, /* Matches any character whose syntax is specified.
- followed by a byte which contains a syntax code,
- e.g., Sword. */
- notsyntaxspec /* Matches any character whose syntax differs from
- that specified. */
- };
-
+typedef enum
+{
+ no_op = 0,
+
+ /* Followed by one byte giving n, then by n literal bytes. */
+ exactn = 1,
+
+ /* Matches any (more or less) character. */
+ anychar,
+
+ /* Matches any one char belonging to specified set. First
+ following byte is number of bitmap bytes. Then come bytes
+ for a bitmap saying which chars are in. Bits in each byte
+ are ordered low-bit-first. A character is in the set if its
+ bit is 1. A character too large to have a bit in the map is
+ automatically not in the set. */
+ charset,
+
+ /* Same parameters as charset, but match any character that is
+ not one of those specified. */
+ charset_not,
+
+ /* Start remembering the text that is matched, for storing in a
+ register. Followed by one byte with the register number, in
+ the range 0 to one less than the pattern buffer's re_nsub
+ field. Then followed by one byte with the number of groups
+ inner to this one. (This last has to be part of the
+ start_memory only because we need it in the on_failure_jump
+ of re_match_2.) */
+ start_memory,
+
+ /* Stop remembering the text that is matched and store it in a
+ memory register. Followed by one byte with the register
+ number, in the range 0 to one less than `re_nsub' in the
+ pattern buffer, and one byte with the number of inner groups,
+ just like `start_memory'. (We need the number of inner
+ groups here because we don't have any easy way of finding the
+ corresponding start_memory when we're at a stop_memory.) */
+ stop_memory,
+
+ /* Match a duplicate of something remembered. Followed by one
+ byte containing the register number. */
+ duplicate,
+
+ /* Fail unless at beginning of line. */
+ begline,
+
+ /* Fail unless at end of line. */
+ endline,
+
+ /* Succeeds if at beginning of buffer (if emacs) or at beginning
+ of string to be matched (if not). */
+ begbuf,
+
+ /* Analogously, for end of buffer/string. */
+ endbuf,
-/* Number of failure points to allocate space for initially,
- when matching. If this number is exceeded, more space is allocated,
- so it is not a hard limit. */
+ /* Followed by two byte relative address to which to jump. */
+ jump,
+
+ /* Same as jump, but marks the end of an alternative. */
+ jump_past_alt,
+
+ /* Followed by two-byte relative address of place to resume at
+ in case of failure. */
+ on_failure_jump,
+
+ /* Like on_failure_jump, but pushes a placeholder instead of the
+ current string position when executed. */
+ on_failure_keep_string_jump,
+
+ /* Throw away latest failure point and then jump to following
+ two-byte relative address. */
+ pop_failure_jump,
+
+ /* Change to pop_failure_jump if know won't have to backtrack to
+ match; otherwise change to jump. This is used to jump
+ back to the beginning of a repeat. If what follows this jump
+ clearly won't match what the repeat does, such that we can be
+ sure that there is no use backtracking out of repetitions
+ already matched, then we change it to a pop_failure_jump.
+ Followed by two-byte address. */
+ maybe_pop_jump,
+
+ /* Jump to following two-byte address, and push a dummy failure
+ point. This failure point will be thrown away if an attempt
+ is made to use it for a failure. A `+' construct makes this
+ before the first repeat. Also used as an intermediary kind
+ of jump when compiling an alternative. */
+ dummy_failure_jump,
+
+ /* Push a dummy failure point and continue. Used at the end of
+ alternatives. */
+ push_dummy_failure,
+
+ /* Followed by two-byte relative address and two-byte number n.
+ After matching N times, jump to the address upon failure. */
+ succeed_n,
+
+ /* Followed by two-byte relative address, and two-byte number n.
+ Jump to the address N times, then fail. */
+ jump_n,
+
+ /* Set the following two-byte relative address to the
+ subsequent two-byte number. The address *includes* the two
+ bytes of number. */
+ set_number_at,
+
+ wordchar, /* Matches any word-constituent character. */
+ notwordchar, /* Matches any char that is not a word-constituent. */
+
+ wordbeg, /* Succeeds if at word beginning. */
+ wordend, /* Succeeds if at word end. */
+
+ wordbound, /* Succeeds if at a word boundary. */
+ notwordbound /* Succeeds if not at a word boundary. */
-#ifndef NFAILURES
-#define NFAILURES 80
-#endif
+#ifdef emacs
+ ,before_dot, /* Succeeds if before point. */
+ at_dot, /* Succeeds if at point. */
+ after_dot, /* Succeeds if after point. */
-#ifdef CHAR_UNSIGNED
-#define SIGN_EXTEND_CHAR(c) ((c)>(char)127?(c)-256:(c)) /* for IBM RT */
-#endif
-#ifndef SIGN_EXTEND_CHAR
-#define SIGN_EXTEND_CHAR(x) (x)
-#endif
-
+ /* Matches any character whose syntax is specified. Followed by
+ a byte which contains a syntax code, e.g., Sword. */
+ syntaxspec,
+
+ /* Matches any character whose syntax is not that specified. */
+ notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+
+/* Common operations on the compiled pattern. */
/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
+
#define STORE_NUMBER(destination, number) \
- { (destination)[0] = (number) & 0377; \
- (destination)[1] = (number) >> 8; }
-
-/* Same as STORE_NUMBER, except increment the destination pointer to
- the byte after where the number is stored. Watch out that values for
- DESTINATION such as p + 1 won't work, whereas p will. */
-#define STORE_NUMBER_AND_INCR(destination, number) \
- { STORE_NUMBER(destination, number); \
- (destination) += 2; }
+ do { \
+ (destination)[0] = (number) & 0377; \
+ (destination)[1] = (number) >> 8; \
+ } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+ the byte after where the number is stored. Therefore, DESTINATION
+ must be an lvalue. */
+#define STORE_NUMBER_AND_INCR(destination, number) \
+ do { \
+ STORE_NUMBER (destination, number); \
+ (destination) += 2; \
+ } while (0)
-/* Put into DESTINATION a number stored in two contingous bytes starting
+/* Put into DESTINATION a number stored in two contiguous bytes starting
at SOURCE. */
+
#define EXTRACT_NUMBER(destination, source) \
- { (destination) = *(source) & 0377; \
- (destination) += SIGN_EXTEND_CHAR (*(char *)((source) + 1)) << 8; }
+ do { \
+ (destination) = *(source) & 0377; \
+ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
+ } while (0)
+
+#ifdef DEBUG
+static void extract_number _RE_ARGS((int *dest, unsigned char *source));
+static void
+extract_number (dest, source)
+ int *dest;
+ unsigned char *source;
+{
+ int temp = SIGN_EXTEND_CHAR (*(source + 1));
+ *dest = *source & 0377;
+ *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros. */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+ SOURCE must be an lvalue. */
-/* Same as EXTRACT_NUMBER, except increment the pointer for source to
- point to second byte of SOURCE. Note that SOURCE has to be a value
- such as p, not, e.g., p + 1. */
#define EXTRACT_NUMBER_AND_INCR(destination, source) \
- { EXTRACT_NUMBER (destination, source); \
- (source) += 2; }
+ do { \
+ EXTRACT_NUMBER (destination, source); \
+ (source) += 2; \
+ } while (0)
+
+#ifdef DEBUG
+static void extract_number_and_incr _RE_ARGS((int *destination,
+ unsigned char **source));
+static void
+extract_number_and_incr (destination, source)
+ int *destination;
+ unsigned char **source;
+{
+ extract_number (destination, *source);
+ *source += 2;
+}
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+ extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
-/* 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. */
+#endif /* DEBUG */
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+ it is doing (if the variable `debug' is nonzero). If linked with the
+ main program in `iregex.c', you can enter patterns and strings
+ interactively. And if linked with the main program in `main.c' and
+ the other test files, you can run the already-written tests. */
-long
-re_set_syntax (syntax)
- long syntax;
+#ifdef DEBUG
+
+/* We use standard I/O for debugging. */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging. */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
+ if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
+ if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+extern void printchar ();
+
+/* Print the fastmap in human-readable form. */
+
+void
+print_fastmap (fastmap)
+ char *fastmap;
{
- long ret;
+ unsigned was_a_range = 0;
+ unsigned i = 0;
+
+ while (i < (1 << BYTEWIDTH))
+ {
+ if (fastmap[i++])
+ {
+ was_a_range = 0;
+ printchar (i - 1);
+ while (i < (1 << BYTEWIDTH) && fastmap[i])
+ {
+ was_a_range = 1;
+ i++;
+ }
+ if (was_a_range)
+ {
+ printf ("-");
+ printchar (i - 1);
+ }
+ }
+ }
+ putchar ('\n');
+}
- ret = obscure_syntax;
- obscure_syntax = syntax;
- return ret;
+
+/* Print a compiled pattern string in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+void
+print_partial_compiled_pattern (start, end)
+ unsigned char *start;
+ unsigned char *end;
+{
+ int mcnt, mcnt2;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* Loop over pattern commands. */
+ while (p < pend)
+ {
+ printf ("%d:\t", p - start);
+
+ switch ((re_opcode_t) *p++)
+ {
+ case no_op:
+ printf ("/no_op");
+ break;
+
+ case exactn:
+ mcnt = *p++;
+ printf ("/exactn/%d", mcnt);
+ do
+ {
+ putchar ('/');
+ printchar (*p++);
+ }
+ while (--mcnt);
+ break;
+
+ case start_memory:
+ mcnt = *p++;
+ printf ("/start_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case stop_memory:
+ mcnt = *p++;
+ printf ("/stop_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case duplicate:
+ printf ("/duplicate/%d", *p++);
+ break;
+
+ case anychar:
+ printf ("/anychar");
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ register int c, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ printchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ printchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ printchar (last);
+
+ putchar (']');
+
+ p += 1 + *p;
+ }
+ break;
+
+ case begline:
+ printf ("/begline");
+ break;
+
+ case endline:
+ printf ("/endline");
+ break;
+
+ case on_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+ break;
+
+ case wordbound:
+ printf ("/wordbound");
+ break;
+
+ case notwordbound:
+ printf ("/notwordbound");
+ break;
+
+ case wordbeg:
+ printf ("/wordbeg");
+ break;
+
+ case wordend:
+ printf ("/wordend");
+
+#ifdef emacs
+ case before_dot:
+ printf ("/before_dot");
+ break;
+
+ case at_dot:
+ printf ("/at_dot");
+ break;
+
+ case after_dot:
+ printf ("/after_dot");
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+#endif /* emacs */
+
+ case wordchar:
+ printf ("/wordchar");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar");
+ break;
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *buffer = bufp->buffer;
+
+ print_partial_compiled_pattern (buffer, buffer + bufp->used);
+ printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+ if (bufp->fastmap_accurate && bufp->fastmap)
+ {
+ printf ("fastmap: ");
+ print_fastmap (bufp->fastmap);
+ }
+
+ printf ("re_nsub: %d\t", bufp->re_nsub);
+ printf ("regs_alloc: %d\t", bufp->regs_allocated);
+ printf ("can_be_null: %d\t", bufp->can_be_null);
+ printf ("newline_anchor: %d\n", bufp->newline_anchor);
+ printf ("no_sub: %d\t", bufp->no_sub);
+ printf ("not_bol: %d\t", bufp->not_bol);
+ printf ("not_eol: %d\t", bufp->not_eol);
+ printf ("syntax: %d\n", bufp->syntax);
+ /* Perhaps we should print the translate table? */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+ const char *where;
+ const char *string1;
+ const char *string2;
+ int size1;
+ int size2;
+{
+ unsigned this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (FIRST_STRING_P (where))
+ {
+ for (this_char = where - string1; this_char < size1; this_char++)
+ printchar (string1[this_char]);
+
+ where = string2;
+ }
+
+ for (this_char = where - string2; this_char < size2; this_char++)
+ printchar (string2[this_char]);
+ }
}
-/* Set by re_set_syntax to the current regexp syntax to recognize. */
-long obscure_syntax = 0;
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+#endif /* not DEBUG */
-/* Macros for re_compile_pattern, which is found below these definitions. */
+/* 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. */
+reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
-#define CHAR_CLASS_MAX_LENGTH 6
-/* Fetch the next character in the uncompiled pattern, translating it if
- necessary. */
+/* 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 (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+
+/* 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. */
+
+static const char *re_error_msg[] =
+ { NULL, /* REG_NOERROR */
+ "No match", /* REG_NOMATCH */
+ "Invalid regular expression", /* REG_BADPAT */
+ "Invalid collation character", /* REG_ECOLLATE */
+ "Invalid character class name", /* REG_ECTYPE */
+ "Trailing backslash", /* REG_EESCAPE */
+ "Invalid back reference", /* REG_ESUBREG */
+ "Unmatched [ or [^", /* REG_EBRACK */
+ "Unmatched ( or \\(", /* REG_EPAREN */
+ "Unmatched \\{", /* REG_EBRACE */
+ "Invalid content of \\{\\}", /* REG_BADBR */
+ "Invalid range end", /* REG_ERANGE */
+ "Memory exhausted", /* REG_ESPACE */
+ "Invalid preceding regular expression", /* REG_BADRPT */
+ "Premature end of regular expression", /* REG_EEND */
+ "Regular expression too big", /* REG_ESIZE */
+ "Unmatched ) or \\)", /* REG_ERPAREN */
+ };
+
+/* Subroutine declarations and macros for regex_compile. */
+
+static reg_errcode_t regex_compile _RE_ARGS((const char *pattern, size_t size,
+ reg_syntax_t syntax,
+ struct re_pattern_buffer *bufp));
+static void store_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc, int arg));
+static void store_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg1, int arg2));
+static void insert_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg, unsigned char *end));
+static void insert_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg1, int arg2, unsigned char *end));
+static boolean at_begline_loc_p _RE_ARGS((const char *pattern, const char *p,
+ reg_syntax_t syntax));
+static boolean at_endline_loc_p _RE_ARGS((const char *p, const char *pend,
+ reg_syntax_t syntax));
+static reg_errcode_t compile_range _RE_ARGS((const char **p_ptr,
+ const char *pend,
+ char *translate,
+ reg_syntax_t syntax,
+ unsigned char *b));
+
+/* Fetch the next character in the uncompiled pattern---translating it
+ if necessary. Also cast from a signed character in the constant
+ string passed to us by the user to an unsigned char that we can use
+ as an array index (in, e.g., `translate'). */
#define PATFETCH(c) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; \
- if (translate) c = translate[c]; }
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ if (translate) c = translate[c]; \
+ } while (0)
/* Fetch the next character in the uncompiled pattern, with no
translation. */
#define PATFETCH_RAW(c) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; }
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ } while (0)
+/* Go backwards one character in the pattern. */
#define PATUNFETCH p--
+/* If `translate' is non-null, return translate[D], else just D. We
+ cast the subscript to translate because some data is declared as
+ `char *', to avoid warnings when a string constant is passed. But
+ when we use a character as a subscript we must make it unsigned. */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'. */
+
/* If the buffer isn't allocated when it comes in, use this. */
-#define INIT_BUF_SIZE 28
+#define INIT_BUF_SIZE 32
/* Make sure we have at least N more bytes of space in buffer. */
#define GET_BUFFER_SPACE(n) \
- { \
- while (b - bufp->buffer + (n) >= bufp->allocated) \
- EXTEND_BUFFER; \
- }
+ while (b - bufp->buffer + (n) > bufp->allocated) \
+ EXTEND_BUFFER ()
-/* Make sure we have one more byte of buffer space and then add CH to it. */
-#define BUFPUSH(ch) \
- { \
+/* Make sure we have one more byte of buffer space and then add C to it. */
+#define BUF_PUSH(c) \
+ do { \
GET_BUFFER_SPACE (1); \
- *b++ = (char) (ch); \
- }
-
-/* Extend the buffer by twice its current size via reallociation and
- reset the pointers that pointed into the old allocation to point to
- the correct places in the new allocation. If extending the buffer
- results in it being larger than 1 << 16, then flag memory exhausted. */
-#define EXTEND_BUFFER \
- { char *old_buffer = bufp->buffer; \
- if (bufp->allocated == (1L<<16)) goto too_big; \
- bufp->allocated *= 2; \
- if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \
- bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated); \
- if (bufp->buffer == 0) \
- goto memory_exhausted; \
- b = (b - old_buffer) + bufp->buffer; \
- if (fixup_jump) \
- fixup_jump = (fixup_jump - old_buffer) + bufp->buffer; \
- if (laststart) \
- laststart = (laststart - old_buffer) + bufp->buffer; \
- begalt = (begalt - old_buffer) + bufp->buffer; \
- if (pending_exact) \
- pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
- }
+ *b++ = (unsigned char) (c); \
+ } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
+#define BUF_PUSH_2(c1, c2) \
+ do { \
+ GET_BUFFER_SPACE (2); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes. */
+#define BUF_PUSH_3(c1, c2, c3) \
+ do { \
+ GET_BUFFER_SPACE (3); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ *b++ = (unsigned char) (c3); \
+ } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO. We store a
+ relative address offset by the three bytes the jump itself occupies. */
+#define STORE_JUMP(op, loc, to) \
+ store_op1 (op, loc, (int)((to) - (loc) - 3))
+
+/* Likewise, for a two-argument jump. */
+#define STORE_JUMP2(op, loc, to, arg) \
+ store_op2 (op, loc, (int)((to) - (loc) - 3), arg)
+
+/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP(op, loc, to) \
+ insert_op1 (op, loc, (int)((to) - (loc) - 3), b)
+
+/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP2(op, loc, to, arg) \
+ insert_op2 (op, loc, (int)((to) - (loc) - 3), arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+ into the pattern are two bytes long. So if 2^16 bytes turns out to
+ be too small, many things would have to change. */
+/* Any other compiler which, like MSC, has allocation limit below 2^16
+ bytes will have to use approach similar to what was done below for
+ MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up
+ reallocating to 0 bytes. Such thing is not going to work too well.
+ You have been warned!! */
+#ifdef _MSC_VER
+/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
+ The REALLOC define eliminates a flurry of conversion warnings,
+ but is not required. */
+#define MAX_BUF_SIZE 65500L
+#define REALLOC(p,s) realloc((p), (size_t) (s))
+#else
+#define MAX_BUF_SIZE (1L << 16)
+#define REALLOC realloc
+#endif
-/* Set the bit for character C in a character set list. */
-#define SET_LIST_BIT(c) (b[(c) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH))
+/* Extend the buffer by twice its current size via realloc and
+ reset the pointers that pointed into the old block to point to the
+ correct places in the new one. If extending the buffer results in it
+ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
+#define EXTEND_BUFFER() \
+ do { \
+ unsigned char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == MAX_BUF_SIZE) \
+ return REG_ESIZE; \
+ bufp->allocated <<= 1; \
+ if (bufp->allocated > MAX_BUF_SIZE) \
+ bufp->allocated = MAX_BUF_SIZE; \
+ bufp->buffer = (unsigned char *) REALLOC(bufp->buffer, bufp->allocated);\
+ if (bufp->buffer == NULL) \
+ return REG_ESPACE; \
+ /* If the buffer moved, move all the pointers into it. */ \
+ if (old_buffer != bufp->buffer) \
+ { \
+ b = (b - old_buffer) + bufp->buffer; \
+ begalt = (begalt - old_buffer) + bufp->buffer; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+ if (laststart) \
+ laststart = (laststart - old_buffer) + bufp->buffer; \
+ if (pending_exact) \
+ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
+ } \
+ } while (0)
-/* Get the next unsigned number in the uncompiled pattern. */
-#define GET_UNSIGNED_NUMBER(num) \
- { if (p != pend) \
- { \
- PATFETCH (c); \
- while (isdigit (c)) \
- { \
- if (num < 0) \
- num = 0; \
- num = num * 10 + c - '0'; \
- if (p == pend) \
- break; \
- PATFETCH (c); \
- } \
- } \
- }
-/* Subroutines for re_compile_pattern. */
-/* static void store_jump (), insert_jump (), store_jump_n (),
- insert_jump_n (), insert_op_2 (); */
+/* Since we have one byte reserved for the register number argument to
+ {start,stop}_memory, the maximum number of groups we can report
+ things about is what fits in that byte. */
+#define MAX_REGNUM 255
+/* But patterns can have more than `MAX_REGNUM' registers. We just
+ ignore the excess. */
+typedef unsigned regnum_t;
-/* re_compile_pattern takes a regular-expression string
- and converts it into a buffer full of byte commands for matching.
- PATTERN is the address of the pattern string
- SIZE is the length of it.
- BUFP is a struct re_pattern_buffer * which points to the info
- on where to store the byte commands.
- This structure contains a char * which points to the
- actual space, which should have been obtained with malloc.
- re_compile_pattern may use realloc to grow the buffer space.
+/* Macros for the compile stack. */
- The number of bytes of commands can be found out by looking in
- the `struct re_pattern_buffer' that bufp pointed to, after
- re_compile_pattern returns. */
+/* Since offsets can go either forwards or backwards, this type needs to
+ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
+/* int may be not enough when sizeof(int) == 2 */
+typedef long pattern_offset_t;
-char *
-re_compile_pattern (pattern, size, bufp)
- char *pattern;
- size_t size;
- struct re_pattern_buffer *bufp;
+typedef struct
{
- register char *b = bufp->buffer;
- register char *p = pattern;
- char *pend = pattern + size;
- register unsigned c, c1;
- char *p0;
- unsigned char *translate = (unsigned char *) bufp->translate;
-
- /* Address of the count-byte of the most recently inserted `exactn'
- command. This makes it possible to tell whether a new exact-match
- character can be added to that command or requires a new `exactn'
- command. */
-
- char *pending_exact = 0;
+ pattern_offset_t begalt_offset;
+ pattern_offset_t fixup_alt_jump;
+ pattern_offset_t inner_group_offset;
+ pattern_offset_t laststart_offset;
+ regnum_t regnum;
+} compile_stack_elt_t;
- /* Address of the place where a forward-jump should go to the end of
- the containing expression. Each alternative of an `or', except the
- last, ends with a forward-jump of this sort. */
- char *fixup_jump = 0;
+typedef struct
+{
+ compile_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} compile_stack_type;
- /* Address of start of the most recently finished expression.
- This tells postfix * where to find the start of its operand. */
- char *laststart = 0;
+#define INIT_COMPILE_STACK_SIZE 32
- /* In processing a repeat, 1 means zero matches is allowed. */
+#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
- char zero_times_ok;
+/* The next available element. */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
- /* In processing a repeat, 1 means many matches is allowed. */
- char many_times_ok;
+/* Set the bit for character C in a list. */
+#define SET_LIST_BIT(c) \
+ (b[((unsigned char) (c)) / BYTEWIDTH] \
+ |= 1 << (((unsigned char) c) % BYTEWIDTH))
- /* Address of beginning of regexp, or inside of last \(. */
- char *begalt = b;
+/* Get the next unsigned number in the uncompiled pattern. */
+#define GET_UNSIGNED_NUMBER(num) \
+ { if (p != pend) \
+ { \
+ PATFETCH (c); \
+ while (ISDIGIT (c)) \
+ { \
+ if (num < 0) \
+ num = 0; \
+ num = num * 10 + c - '0'; \
+ if (p == pend) \
+ break; \
+ PATFETCH (c); \
+ } \
+ } \
+ }
+
+#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"))
+
+static boolean group_in_compile_stack _RE_ARGS((compile_stack_type
+ compile_stack,
+ regnum_t regnum));
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+ Returns one of error codes defined in `regex.h', or zero for success.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate'
+ fields are set in BUFP on entry.
+
+ If it succeeds, results are put in BUFP (if it returns an error, the
+ contents of BUFP are undefined):
+ `buffer' is the compiled pattern;
+ `syntax' is set to SYNTAX;
+ `used' is set to the length of the compiled pattern;
+ `fastmap_accurate' is zero;
+ `re_nsub' is the number of subexpressions in PATTERN;
+ `not_bol' and `not_eol' are zero;
+
+ The `fastmap' and `newline_anchor' fields are neither
+ examined nor set. */
- /* In processing an interval, at least this many matches must be made. */
- int lower_bound;
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+ const char *pattern;
+ size_t size;
+ reg_syntax_t syntax;
+ struct re_pattern_buffer *bufp;
+{
+ /* We fetch characters from PATTERN here. Even though PATTERN is
+ `char *' (i.e., signed), we declare these variables as unsigned, so
+ they can be reliably used as array indices. */
+ register unsigned char c, c1;
+
+ /* A random tempory spot in PATTERN. */
+ const char *p1;
- /* In processing an interval, at most this many matches can be made. */
- int upper_bound;
+ /* Points to the end of the buffer, where we should append. */
+ register unsigned char *b;
+
+ /* Keeps track of unclosed groups. */
+ compile_stack_type compile_stack;
- /* Place in pattern (i.e., the {) to which to go back if the interval
- is invalid. */
- char *beg_interval = 0;
+ /* Points to the current (ending) position in the pattern. */
+ const char *p = pattern;
+ const char *pend = pattern + size;
- /* Stack of information saved by \( and restored by \).
- Four stack elements are pushed by each \(:
- First, the value of b.
- Second, the value of fixup_jump.
- Third, the value of regnum.
- Fourth, the value of begalt. */
+ /* How to translate the characters in the pattern. */
+ char *translate = bufp->translate;
- int stackb[40];
- int *stackp = stackb;
- int *stacke = stackb + 40;
- int *stackt;
+ /* Address of the count-byte of the most recently inserted `exactn'
+ command. This makes it possible to tell if a new exact-match
+ character can be added to that command or if the character requires
+ a new `exactn' command. */
+ unsigned char *pending_exact = 0;
- /* Counts \('s as they are encountered. Remembered for the matching \),
- where it becomes the register number to put in the stop_memory
- command. */
+ /* Address of start of the most recently finished expression.
+ This tells, e.g., postfix * where to find the start of its
+ operand. Reset at the beginning of groups and alternatives. */
+ unsigned char *laststart = 0;
- int regnum = 1;
+ /* Address of beginning of regexp, or inside of last group. */
+ unsigned char *begalt;
+
+ /* Place in the uncompiled pattern (i.e., the {) to
+ which to go back if the interval is invalid. */
+ const char *beg_interval;
+
+ /* Address of the place where a forward jump should go to the end of
+ the containing expression. Each alternative of an `or' -- except the
+ last -- ends with a forward jump of this sort. */
+ unsigned char *fixup_alt_jump = 0;
+
+ /* Counts open-groups as they are encountered. Remembered for the
+ matching close-group on the compile stack, so the same register
+ number is put in the stop_memory as the start_memory. */
+ regnum_t regnum = 0;
+
+#ifdef DEBUG
+ DEBUG_PRINT1 ("\nCompiling pattern: ");
+ if (debug)
+ {
+ unsigned debug_count;
+
+ for (debug_count = 0; debug_count < size; debug_count++)
+ printchar (pattern[debug_count]);
+ putchar ('\n');
+ }
+#endif /* DEBUG */
+ /* Initialize the compile stack. */
+ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+ if (compile_stack.stack == NULL)
+ return REG_ESPACE;
+
+ compile_stack.size = INIT_COMPILE_STACK_SIZE;
+ compile_stack.avail = 0;
+
+ /* Initialize the pattern buffer. */
+ bufp->syntax = syntax;
bufp->fastmap_accurate = 0;
+ bufp->not_bol = bufp->not_eol = 0;
-#ifndef emacs
-#ifndef SYNTAX_TABLE
+ /* Set `used' to zero, so that if we return an error, the pattern
+ printer (for debugging) will think there's no pattern. We reset it
+ at the end. */
+ bufp->used = 0;
+
+ /* Always count groups, whether or not bufp->no_sub is set. */
+ bufp->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
/* Initialize the syntax table. */
- init_syntax_once();
-#endif
+ init_syntax_once ();
#endif
if (bufp->allocated == 0)
{
- bufp->allocated = INIT_BUF_SIZE;
if (bufp->buffer)
- /* EXTEND_BUFFER loses when bufp->allocated is 0. */
- bufp->buffer = (char *) realloc (bufp->buffer, INIT_BUF_SIZE);
+ { /* 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. */
+ RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+ }
else
- /* Caller did not allocate a buffer. Do it for them. */
- bufp->buffer = (char *) malloc (INIT_BUF_SIZE);
- if (!bufp->buffer) goto memory_exhausted;
- begalt = b = bufp->buffer;
+ { /* Caller did not allocate a buffer. Do it for them. */
+ bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+ }
+ if (!bufp->buffer) return REG_ESPACE;
+
+ bufp->allocated = INIT_BUF_SIZE;
}
+ begalt = b = bufp->buffer;
+
+ /* Loop through the uncompiled pattern until we're at the end. */
while (p != pend)
{
PATFETCH (c);
switch (c)
- {
- case '$':
- {
- char *p1 = p;
- /* When testing what follows the $,
- look past the \-constructs that don't consume anything. */
- if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- while (p1 != pend)
- {
- if (*p1 == '\\' && p1 + 1 != pend
- && (p1[1] == '<' || p1[1] == '>'
- || p1[1] == '`' || p1[1] == '\''
-#ifdef emacs
- || p1[1] == '='
-#endif
- || p1[1] == 'b' || p1[1] == 'B'))
- p1 += 2;
- else
- break;
- }
- if (obscure_syntax & RE_TIGHT_VBAR)
- {
- if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p1 != pend)
- goto normal_char;
- /* Make operand of last vbar end before this `$'. */
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
- fixup_jump = 0;
- BUFPUSH (endline);
- break;
- }
- /* $ means succeed if at end of line, but only in special contexts.
- If validly in the middle of a pattern, it is a normal character. */
-
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && p1 != pend)
- goto invalid_pattern;
- if (p1 == pend || *p1 == '\n'
- || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
- || (obscure_syntax & RE_NO_BK_PARENS
- ? *p1 == ')'
- : *p1 == '\\' && p1[1] == ')')
- || (obscure_syntax & RE_NO_BK_VBAR
- ? *p1 == '|'
- : *p1 == '\\' && p1[1] == '|'))
- {
- BUFPUSH (endline);
- break;
- }
- goto normal_char;
+ {
+ case '^':
+ {
+ if ( /* If at start of pattern, it's an operator. */
+ p == pattern + 1
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's come before. */
+ || at_begline_loc_p (pattern, p, syntax))
+ BUF_PUSH (begline);
+ else
+ goto normal_char;
}
- case '^':
- /* ^ means succeed if at beg of line, but only if no preceding
- pattern. */
-
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && laststart)
- goto invalid_pattern;
- if (laststart && p - 2 >= pattern && p[-2] != '\n'
- && !(obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- if (obscure_syntax & RE_TIGHT_VBAR)
- {
- if (p != pattern + 1
- && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- BUFPUSH (begline);
- begalt = b;
- }
- else
- BUFPUSH (begline);
- break;
+ break;
+
+
+ case '$':
+ {
+ if ( /* If at end of pattern, it's an operator. */
+ p == pend
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's next. */
+ || at_endline_loc_p (p, pend, syntax))
+ BUF_PUSH (endline);
+ else
+ goto normal_char;
+ }
+ break;
+
case '+':
- case '?':
- if ((obscure_syntax & RE_BK_PLUS_QM)
- || (obscure_syntax & RE_LIMITED_OPS))
- goto normal_char;
- handle_plus:
- case '*':
- /* If there is no previous pattern, char not special. */
- if (!laststart)
+ case '?':
+ if ((syntax & RE_BK_PLUS_QM)
+ || (syntax & RE_LIMITED_OPS))
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern... */
+ if (!laststart)
{
- if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- goto invalid_pattern;
- else if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ return REG_BADRPT;
+ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
}
- /* If there is a sequence of repetition chars,
- collapse it down to just one. */
- zero_times_ok = 0;
- many_times_ok = 0;
- while (1)
- {
- zero_times_ok |= c != '+';
- many_times_ok |= c != '?';
- if (p == pend)
- break;
- PATFETCH (c);
- if (c == '*')
- ;
- else if (!(obscure_syntax & RE_BK_PLUS_QM)
- && (c == '+' || c == '?'))
- ;
- else if ((obscure_syntax & RE_BK_PLUS_QM)
- && c == '\\')
- {
- /* int c1; */
- PATFETCH (c1);
- if (!(c1 == '+' || c1 == '?'))
- {
- PATUNFETCH;
- PATUNFETCH;
- break;
- }
- c = c1;
- }
- else
- {
- PATUNFETCH;
- break;
- }
- }
- /* Star, etc. applied to an empty pattern is equivalent
- to an empty pattern. */
- if (!laststart)
- break;
+ {
+ /* Are we optimizing this jump? */
+ boolean keep_string_p = false;
+
+ /* 1 means zero (many) matches is allowed. */
+ char zero_times_ok = 0, many_times_ok = 0;
+
+ /* If there is a sequence of repetition chars, collapse it
+ down to just one (the right one). We can't combine
+ interval operators with these because of, e.g., `a{2}*',
+ which should only match an even number of `a's. */
+
+ for (;;)
+ {
+ zero_times_ok |= c != '+';
+ many_times_ok |= c != '?';
+
+ if (p == pend)
+ break;
+
+ PATFETCH (c);
+
+ if (c == '*'
+ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+ ;
+
+ else if (syntax & RE_BK_PLUS_QM && c == '\\')
+ {
+ if (p == pend) return REG_EESCAPE;
+
+ PATFETCH (c1);
+ if (!(c1 == '+' || c1 == '?'))
+ {
+ PATUNFETCH;
+ PATUNFETCH;
+ break;
+ }
+
+ c = c1;
+ }
+ else
+ {
+ PATUNFETCH;
+ break;
+ }
- /* Now we know whether or not zero matches is allowed
- and also whether or not two or more matches is allowed. */
- if (many_times_ok)
- {
- /* If more than one repetition is allowed, put in at the
- end a backward relative jump from b to before the next
- jump we're going to put in below (which jumps from
- laststart to after this jump). */
- GET_BUFFER_SPACE (3);
- store_jump (b, maybe_finalize_jump, laststart - 3);
- b += 3; /* Because store_jump put stuff here. */
- }
- /* On failure, jump from laststart to b + 3, which will be the
- end of the buffer after this jump is inserted. */
- GET_BUFFER_SPACE (3);
- insert_jump (on_failure_jump, laststart, b + 3, b);
- pending_exact = 0;
- b += 3;
- if (!zero_times_ok)
- {
- /* At least one repetition is required, so insert a
- dummy-failure before the initial on-failure-jump
- instruction of the loop. This effects a skip over that
- instruction the first time we hit that loop. */
- GET_BUFFER_SPACE (6);
- insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
- b += 3;
- }
+ /* If we get here, we found another repeat character. */
+ }
+
+ /* Star, etc. applied to an empty pattern is equivalent
+ to an empty pattern. */
+ if (!laststart)
+ break;
+
+ /* Now we know whether or not zero matches is allowed
+ and also whether or not two or more matches is allowed. */
+ if (many_times_ok)
+ { /* More than one repetition is allowed, so put in at the
+ end a backward relative jump from `b' to before the next
+ jump we're going to put in below (which jumps from
+ laststart to after this jump).
+
+ But if we are at the `*' in the exact sequence `.*\n',
+ insert an unconditional jump backwards to the .,
+ instead of the beginning of the loop. This way we only
+ push a failure point once, instead of every time
+ through the loop. */
+ assert (p - 1 > pattern);
+
+ /* Allocate the space for the jump. */
+ GET_BUFFER_SPACE (3);
+
+ /* We know we are not at the first character of the pattern,
+ because laststart was nonzero. And we've already
+ incremented `p', by the way, to be the character after
+ the `*'. Do we have to do something analogous here
+ for null bytes, because of RE_DOT_NOT_NULL? */
+ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+ && zero_times_ok
+ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+ && !(syntax & RE_DOT_NEWLINE))
+ { /* We have .*\n. */
+ STORE_JUMP (jump, b, laststart);
+ keep_string_p = true;
+ }
+ else
+ /* Anything else. */
+ STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+ /* We've added more stuff to the buffer. */
+ b += 3;
+ }
+
+ /* On failure, jump from laststart to b + 3, which will be the
+ end of the buffer after this jump is inserted. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+ : on_failure_jump,
+ laststart, b + 3);
+ pending_exact = 0;
+ b += 3;
+
+ if (!zero_times_ok)
+ {
+ /* At least one repetition is required, so insert a
+ `dummy_failure_jump' before the initial
+ `on_failure_jump' instruction of the loop. This
+ effects a skip over that instruction the first time
+ we hit that loop. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+ b += 3;
+ }
+ }
break;
+
case '.':
- laststart = b;
- BUFPUSH (anychar);
- break;
+ laststart = b;
+ BUF_PUSH (anychar);
+ break;
+
case '[':
- if (p == pend)
- goto invalid_pattern;
- while (b - bufp->buffer
- > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
- EXTEND_BUFFER;
-
- laststart = b;
- if (*p == '^')
- {
- BUFPUSH (charset_not);
- p++;
- }
- else
- BUFPUSH (charset);
- p0 = p;
+ {
+ boolean had_char_class = false;
- BUFPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
- /* Clear the whole map */
- memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH);
-
- if ((obscure_syntax & RE_HAT_NOT_NEWLINE) && b[-2] == charset_not)
- SET_LIST_BIT ('\n');
+ if (p == pend) return REG_EBRACK;
+ /* Ensure that we have enough space to push a charset: the
+ opcode, the length count, and the bitset; 34 bytes in all. */
+ GET_BUFFER_SPACE (34);
- /* Read in characters and ranges, setting map bits. */
- while (1)
- {
- /* Don't translate while fetching, in case it's a range bound.
- When we set the bit for the character, we translate it. */
- PATFETCH_RAW (c);
-
- /* If set, \ escapes characters when inside [...]. */
- if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\')
- {
- PATFETCH(c1);
- SET_LIST_BIT (c1);
- continue;
- }
- if (c == ']')
- {
- if (p == p0 + 1)
- {
- /* If this is an empty bracket expression. */
- if ((obscure_syntax & RE_NO_EMPTY_BRACKETS)
- && p == pend)
- goto invalid_pattern;
- }
- else
- /* Stop if this isn't merely a ] inside a bracket
- expression, but rather the end of a bracket
- expression. */
- break;
- }
- /* Get a range. */
- if (p[0] == '-' && p[1] != ']')
- {
- PATFETCH (c1);
- /* Don't translate the range bounds while fetching them. */
- PATFETCH_RAW (c1);
-
- if ((obscure_syntax & RE_NO_EMPTY_RANGES) && c > c1)
- goto invalid_pattern;
-
- if ((obscure_syntax & RE_NO_HYPHEN_RANGE_END)
- && c1 == '-' && *p != ']')
- goto invalid_pattern;
-
- while (c <= c1)
- {
- /* Translate each char that's in the range. */
- if (translate)
- SET_LIST_BIT (translate[c]);
- else
- SET_LIST_BIT (c);
- c++;
- }
- }
- else if ((obscure_syntax & RE_CHAR_CLASSES)
- && c == '[' && p[0] == ':')
- {
- /* Longest valid character class word has six characters. */
- char str[CHAR_CLASS_MAX_LENGTH];
- PATFETCH (c);
- c1 = 0;
- /* If no ] at end. */
- if (p == pend)
- goto invalid_pattern;
- while (1)
- {
- /* Don't translate the ``character class'' characters. */
- PATFETCH_RAW (c);
- if (c == ':' || c == ']' || p == pend
- || c1 == CHAR_CLASS_MAX_LENGTH)
- break;
- str[c1++] = c;
- }
- str[c1] = '\0';
- if (p == pend
- || c == ']' /* End of the bracket expression. */
- || p[0] != ']'
- || p + 1 == pend
- || (strcmp (str, "alpha") != 0
- && strcmp (str, "upper") != 0
- && strcmp (str, "lower") != 0
- && strcmp (str, "digit") != 0
- && strcmp (str, "alnum") != 0
- && strcmp (str, "xdigit") != 0
- && strcmp (str, "space") != 0
- && strcmp (str, "print") != 0
- && strcmp (str, "punct") != 0
- && strcmp (str, "graph") != 0
- && strcmp (str, "cntrl") != 0))
- {
- /* Undo the ending character, the letters, and leave
- the leading : and [ (but set bits for them). */
- c1++;
- while (c1--)
- PATUNFETCH;
- SET_LIST_BIT ('[');
- SET_LIST_BIT (':');
- }
- else
- {
- /* The ] at the end of the character class. */
- PATFETCH (c);
- if (c != ']')
- goto invalid_pattern;
- for (c = 0; c < (1 << BYTEWIDTH); c++)
- {
- if ((strcmp (str, "alpha") == 0 && isalpha (c))
- || (strcmp (str, "upper") == 0 && isupper (c))
- || (strcmp (str, "lower") == 0 && islower (c))
- || (strcmp (str, "digit") == 0 && isdigit (c))
- || (strcmp (str, "alnum") == 0 && isalnum (c))
- || (strcmp (str, "xdigit") == 0 && isxdigit (c))
- || (strcmp (str, "space") == 0 && isspace (c))
- || (strcmp (str, "print") == 0 && isprint (c))
- || (strcmp (str, "punct") == 0 && ispunct (c))
- || (strcmp (str, "graph") == 0 && isgraph (c))
- || (strcmp (str, "cntrl") == 0 && iscntrl (c)))
- SET_LIST_BIT (c);
- }
- }
- }
- else if (translate)
- SET_LIST_BIT (translate[c]);
- else
- SET_LIST_BIT (c);
- }
+ laststart = b;
+
+ /* We test `*p == '^' twice, instead of using an if
+ statement, so we only need one BUF_PUSH. */
+ BUF_PUSH (*p == '^' ? charset_not : charset);
+ if (*p == '^')
+ p++;
- /* Discard any character set/class bitmap bytes that are all
- 0 at the end of the map. Decrement the map-length byte too. */
- while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
- b[-1]--;
- b += b[-1];
+ /* Remember the first position in the bracket expression. */
+ p1 = p;
+
+ /* Push the number of bytes in the bitmap. */
+ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* Clear the whole map. */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* charset_not matches newline according to a syntax bit. */
+ if ((re_opcode_t) b[-2] == charset_not
+ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+ SET_LIST_BIT ('\n');
+
+ /* Read in characters and ranges, setting map bits. */
+ for (;;)
+ {
+ if (p == pend) return REG_EBRACK;
+
+ PATFETCH (c);
+
+ /* \ might escape characters inside [...] and [^...]. */
+ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+ {
+ if (p == pend) return REG_EESCAPE;
+
+ PATFETCH (c1);
+ SET_LIST_BIT (c1);
+ continue;
+ }
+
+ /* Could be the end of the bracket expression. If it's
+ not (i.e., when the bracket expression is `[]' so
+ far), the ']' character bit gets set way below. */
+ if (c == ']' && p != p1 + 1)
+ break;
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character class. */
+ if (had_char_class && c == '-' && *p != ']')
+ return REG_ERANGE;
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character: if this is a hyphen not at the
+ beginning or the end of a list, then it's the range
+ operator. */
+ if (c == '-'
+ && !(p - 2 >= pattern && p[-2] == '[')
+ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+ && *p != ']')
+ {
+ reg_errcode_t ret
+ = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) return ret;
+ }
+
+ else if (p[0] == '-' && p[1] != ']')
+ { /* This handles ranges made up of characters only. */
+ reg_errcode_t ret;
+
+ /* Move past the `-'. */
+ PATFETCH (c1);
+
+ ret = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) return ret;
+ }
+
+ /* See if we're at the beginning of a possible character
+ class. */
+
+ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+ { /* Leave room for the null. */
+ char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+ PATFETCH (c);
+ c1 = 0;
+
+ /* If pattern is `[[:'. */
+ if (p == pend) return REG_EBRACK;
+
+ for (;;)
+ {
+ PATFETCH (c);
+ if (c == ':' || c == ']' || p == pend
+ || c1 == CHAR_CLASS_MAX_LENGTH)
+ break;
+ str[c1++] = c;
+ }
+ str[c1] = '\0';
+
+ /* If isn't a word bracketed by `[:' and:`]':
+ undo the ending character, the letters, and leave
+ the leading `:' and `[' (but set bits for them). */
+ if (c == ':' && *p == ']')
+ {
+ int ch;
+ boolean is_alnum = STREQ (str, "alnum");
+ boolean is_alpha = STREQ (str, "alpha");
+ boolean is_blank = STREQ (str, "blank");
+ boolean is_cntrl = STREQ (str, "cntrl");
+ boolean is_digit = STREQ (str, "digit");
+ boolean is_graph = STREQ (str, "graph");
+ boolean is_lower = STREQ (str, "lower");
+ boolean is_print = STREQ (str, "print");
+ boolean is_punct = STREQ (str, "punct");
+ boolean is_space = STREQ (str, "space");
+ boolean is_upper = STREQ (str, "upper");
+ boolean is_xdigit = STREQ (str, "xdigit");
+
+ if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
+
+ /* Throw away the ] at the end of the character
+ class. */
+ PATFETCH (c);
+
+ if (p == pend) return REG_EBRACK;
+
+ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+ {
+ if ( (is_alnum && ISALNUM (ch))
+ || (is_alpha && ISALPHA (ch))
+ || (is_blank && ISBLANK (ch))
+ || (is_cntrl && ISCNTRL (ch))
+ || (is_digit && ISDIGIT (ch))
+ || (is_graph && ISGRAPH (ch))
+ || (is_lower && ISLOWER (ch))
+ || (is_print && ISPRINT (ch))
+ || (is_punct && ISPUNCT (ch))
+ || (is_space && ISSPACE (ch))
+ || (is_upper && ISUPPER (ch))
+ || (is_xdigit && ISXDIGIT (ch)))
+ SET_LIST_BIT (ch);
+ }
+ had_char_class = true;
+ }
+ else
+ {
+ c1++;
+ while (c1--)
+ PATUNFETCH;
+ SET_LIST_BIT ('[');
+ SET_LIST_BIT (':');
+ had_char_class = false;
+ }
+ }
+ else
+ {
+ had_char_class = false;
+ SET_LIST_BIT (c);
+ }
+ }
+
+ /* Discard any (non)matching list bytes that are all 0 at the
+ end of the map. Decrease the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+ }
break;
+
case '(':
- if (! (obscure_syntax & RE_NO_BK_PARENS))
- goto normal_char;
- else
- goto handle_open;
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_open;
+ else
+ goto normal_char;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_close;
+ else
+ goto normal_char;
- case ')':
- if (! (obscure_syntax & RE_NO_BK_PARENS))
- goto normal_char;
- else
- goto handle_close;
case '\n':
- if (! (obscure_syntax & RE_NEWLINE_OR))
- goto normal_char;
- else
- goto handle_bar;
+ if (syntax & RE_NEWLINE_ALT)
+ goto handle_alt;
+ else
+ goto normal_char;
+
case '|':
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- && (! laststart || p == pend))
- goto invalid_pattern;
- else if (! (obscure_syntax & RE_NO_BK_VBAR))
- goto normal_char;
- else
- goto handle_bar;
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_alt;
+ else
+ goto normal_char;
- case '{':
- if (! ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- && (obscure_syntax & RE_INTERVALS)))
- goto normal_char;
- else
+
+ case '{':
+ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
goto handle_interval;
-
+ else
+ goto normal_char;
+
+
case '\\':
- if (p == pend) goto invalid_pattern;
- PATFETCH_RAW (c);
- switch (c)
- {
- case '(':
- if (obscure_syntax & RE_NO_BK_PARENS)
- goto normal_backsl;
- handle_open:
- if (stackp == stacke) goto nesting_too_deep;
-
- /* Laststart should point to the start_memory that we are about
- to push (unless the pattern has RE_NREGS or more ('s). */
- *stackp++ = b - bufp->buffer;
- if (regnum < RE_NREGS)
- {
- BUFPUSH (start_memory);
- BUFPUSH (regnum);
- }
- *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
- *stackp++ = regnum++;
- *stackp++ = begalt - bufp->buffer;
- fixup_jump = 0;
- laststart = 0;
- begalt = b;
- break;
-
- case ')':
- if (obscure_syntax & RE_NO_BK_PARENS)
- goto normal_backsl;
- handle_close:
- if (stackp == stackb) goto unmatched_close;
- begalt = *--stackp + bufp->buffer;
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
- if (stackp[-1] < RE_NREGS)
- {
- BUFPUSH (stop_memory);
- BUFPUSH (stackp[-1]);
- }
- stackp -= 2;
- fixup_jump = *stackp ? *stackp + bufp->buffer - 1 : 0;
- laststart = *--stackp + bufp->buffer;
- break;
-
- case '|':
- if ((obscure_syntax & RE_LIMITED_OPS)
- || (obscure_syntax & RE_NO_BK_VBAR))
- goto normal_backsl;
- handle_bar:
- if (obscure_syntax & RE_LIMITED_OPS)
- goto normal_char;
- /* Insert before the previous alternative a jump which
- jumps to this alternative if the former fails. */
- GET_BUFFER_SPACE (6);
- insert_jump (on_failure_jump, begalt, b + 6, b);
- pending_exact = 0;
- b += 3;
- /* The alternative before the previous alternative has a
- jump after it which gets executed if it gets matched.
- Adjust that jump so it will jump to the previous
- alternative's analogous jump (put in below, which in
- turn will jump to the next (if any) alternative's such
- jump, etc.). The last such jump jumps to the correct
- final destination. */
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
+ if (p == pend) return REG_EESCAPE;
+
+ /* Do not translate the character after the \, so that we can
+ distinguish, e.g., \B from \b, even if we normally would
+ translate, e.g., B to b. */
+ PATFETCH_RAW (c);
+
+ switch (c)
+ {
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto normal_backslash;
+
+ handle_open:
+ bufp->re_nsub++;
+ regnum++;
+
+ if (COMPILE_STACK_FULL)
+ {
+ RETALLOC (compile_stack.stack, compile_stack.size << 1,
+ compile_stack_elt_t);
+ if (compile_stack.stack == NULL) return REG_ESPACE;
+
+ compile_stack.size <<= 1;
+ }
+
+ /* These are the values to restore when we hit end of this
+ group. They are all relative offsets, so that if the
+ whole pattern moves because of realloc, they will still
+ be valid. */
+ COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+ COMPILE_STACK_TOP.fixup_alt_jump
+ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+ COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+ COMPILE_STACK_TOP.regnum = regnum;
+
+ /* We will eventually replace the 0 with the number of
+ groups inner to this one. But do not push a
+ start_memory for groups beyond the last one we can
+ represent in the compiled pattern. */
+ if (regnum <= MAX_REGNUM)
+ {
+ COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+ BUF_PUSH_3 (start_memory, regnum, 0);
+ }
- /* Leave space for a jump after previous alternative---to be
- filled in later. */
- fixup_jump = b;
- b += 3;
+ compile_stack.avail++;
+ fixup_alt_jump = 0;
laststart = 0;
- begalt = b;
- break;
+ begalt = b;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ break;
- case '{':
- if (! (obscure_syntax & RE_INTERVALS)
- /* Let \{ be a literal. */
- || ((obscure_syntax & RE_INTERVALS)
- && (obscure_syntax & RE_NO_BK_CURLY_BRACES))
- /* If it's the string "\{". */
- || (p - 2 == pattern && p == pend))
- goto normal_backsl;
- handle_interval:
- beg_interval = p - 1; /* The {. */
- /* If there is no previous pattern, this isn't an interval. */
- if (!laststart)
- {
- if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- goto invalid_pattern;
- else
- goto normal_backsl;
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_backslash;
+ else
+ return REG_ERPAREN;
+
+ handle_close:
+ if (fixup_alt_jump)
+ { /* Push a dummy failure point at the end of the
+ alternative for a possible future
+ `pop_failure_jump' to pop. See comments at
+ `push_dummy_failure' in `re_match_2'. */
+ BUF_PUSH (push_dummy_failure);
+
+ /* We allocated space for this jump when we assigned
+ to `fixup_alt_jump', in the `handle_alt' case below. */
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
}
- /* It also isn't an interval if not preceded by an re
- matching a single character or subexpression, or if
- the current type of intervals can't handle back
- references and the previous thing is a back reference. */
- if (! (*laststart == anychar
- || *laststart == charset
- || *laststart == charset_not
- || *laststart == start_memory
- || (*laststart == exactn && laststart[1] == 1)
- || (! (obscure_syntax & RE_NO_BK_REFS)
- && *laststart == duplicate)))
- {
- if (obscure_syntax & RE_NO_BK_CURLY_BRACES)
- goto normal_char;
-
- /* Posix extended syntax is handled in previous
- statement; this is for Posix basic syntax. */
- if (obscure_syntax & RE_INTERVALS)
- goto invalid_pattern;
+
+ /* See similar code for backslashed left paren above. */
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ else
+ return REG_ERPAREN;
+
+ /* Since we just checked for an empty stack above, this
+ ``can't happen''. */
+ assert (compile_stack.avail != 0);
+ {
+ /* We don't just want to restore into `regnum', because
+ later groups should continue to be numbered higher,
+ as in `(ab)c(de)' -- the second group is #2. */
+ regnum_t this_group_regnum;
+
+ compile_stack.avail--;
+ begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+ fixup_alt_jump
+ = COMPILE_STACK_TOP.fixup_alt_jump
+ ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+ : 0;
+ laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+ this_group_regnum = COMPILE_STACK_TOP.regnum;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* We're at the end of the group, so now we know how many
+ groups were inside this one. */
+ if (this_group_regnum <= MAX_REGNUM)
+ {
+ unsigned char *inner_group_loc
+ = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
- goto normal_backsl;
- }
- lower_bound = -1; /* So can see if are set. */
- upper_bound = -1;
- GET_UNSIGNED_NUMBER (lower_bound);
- if (c == ',')
- {
- GET_UNSIGNED_NUMBER (upper_bound);
- if (upper_bound < 0)
- upper_bound = RE_DUP_MAX;
- }
- if (upper_bound < 0)
- upper_bound = lower_bound;
- if (! (obscure_syntax & RE_NO_BK_CURLY_BRACES))
- {
- if (c != '\\')
- goto invalid_pattern;
- PATFETCH (c);
- }
- if (c != '}' || lower_bound < 0 || upper_bound > RE_DUP_MAX
- || lower_bound > upper_bound
- || ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- && p != pend && *p == '{'))
- {
- if (obscure_syntax & RE_NO_BK_CURLY_BRACES)
- goto unfetch_interval;
- else
- goto invalid_pattern;
- }
+ *inner_group_loc = regnum - this_group_regnum;
+ BUF_PUSH_3 (stop_memory, this_group_regnum,
+ regnum - this_group_regnum);
+ }
+ }
+ break;
- /* If upper_bound is zero, don't want to succeed at all;
- jump from laststart to b + 3, which will be the end of
- the buffer after this jump is inserted. */
-
- if (upper_bound == 0)
- {
- GET_BUFFER_SPACE (3);
- insert_jump (jump, laststart, b + 3, b);
- b += 3;
- }
- /* Otherwise, after lower_bound number of succeeds, jump
- to after the jump_n which will be inserted at the end
- of the buffer, and insert that jump_n. */
- else
- { /* Set to 5 if only one repetition is allowed and
- hence no jump_n is inserted at the current end of
- the buffer; then only space for the succeed_n is
- needed. Otherwise, need space for both the
- succeed_n and the jump_n. */
-
- unsigned slots_needed = upper_bound == 1 ? 5 : 10;
-
- GET_BUFFER_SPACE (slots_needed);
- /* Initialize the succeed_n to n, even though it will
- be set by its attendant set_number_at, because
- re_compile_fastmap will need to know it. Jump to
- what the end of buffer will be after inserting
- this succeed_n and possibly appending a jump_n. */
- insert_jump_n (succeed_n, laststart, b + slots_needed,
- b, lower_bound);
- b += 5; /* Just increment for the succeed_n here. */
-
- /* More than one repetition is allowed, so put in at
- the end of the buffer a backward jump from b to the
- succeed_n we put in above. By the time we've gotten
- to this jump when matching, we'll have matched once
- already, so jump back only upper_bound - 1 times. */
-
- if (upper_bound > 1)
- {
- store_jump_n (b, jump_n, laststart, upper_bound - 1);
- b += 5;
- /* When hit this when matching, reset the
- preceding jump_n's n to upper_bound - 1. */
- BUFPUSH (set_number_at);
- GET_BUFFER_SPACE (2);
- STORE_NUMBER_AND_INCR (b, -5);
- STORE_NUMBER_AND_INCR (b, upper_bound - 1);
- }
- /* When hit this when matching, set the succeed_n's n. */
- GET_BUFFER_SPACE (5);
- insert_op_2 (set_number_at, laststart, b, 5, lower_bound);
- b += 5;
- }
+ case '|': /* `\|'. */
+ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+ goto normal_backslash;
+ handle_alt:
+ if (syntax & RE_LIMITED_OPS)
+ goto normal_char;
+
+ /* Insert before the previous alternative a jump which
+ jumps to this alternative if the former fails. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (on_failure_jump, begalt, b + 6);
pending_exact = 0;
- beg_interval = 0;
+ b += 3;
+
+ /* The alternative before this one has a jump after it
+ which gets executed if it gets matched. Adjust that
+ jump so it will jump to this alternative's analogous
+ jump (put in below, which in turn will jump to the next
+ (if any) alternative's such jump, etc.). The last such
+ jump jumps to the correct final destination. A picture:
+ _____ _____
+ | | | |
+ | v | v
+ a | b | c
+
+ If we are at `b', then fixup_alt_jump right now points to a
+ three-byte space after `a'. We'll put in the jump, set
+ fixup_alt_jump to right after `b', and leave behind three
+ bytes which we'll fill in when we get to after `c'. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ /* Mark and leave space for a jump after this alternative,
+ to be filled in later either by next alternative or
+ when know we're at the end of a series of alternatives. */
+ fixup_alt_jump = b;
+ GET_BUFFER_SPACE (3);
+ b += 3;
+
+ laststart = 0;
+ begalt = b;
break;
+ case '{':
+ /* If \{ is a literal. */
+ if (!(syntax & RE_INTERVALS)
+ /* If we're at `\{' and it's not the open-interval
+ operator. */
+ || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ || (p - 2 == pattern && p == pend))
+ goto normal_backslash;
+
+ handle_interval:
+ {
+ /* If got here, then the syntax allows intervals. */
+
+ /* At least (most) this many matches must be made. */
+ int lower_bound = -1, upper_bound = -1;
+
+ beg_interval = p - 1;
+
+ if (p == pend)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ return REG_EBRACE;
+ }
+
+ GET_UNSIGNED_NUMBER (lower_bound);
+
+ if (c == ',')
+ {
+ GET_UNSIGNED_NUMBER (upper_bound);
+ if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+ }
+ else
+ /* Interval such as `{1}' => match exactly once. */
+ upper_bound = lower_bound;
+
+ if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+ || lower_bound > upper_bound)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ return REG_BADBR;
+ }
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (c != '\\') return REG_EBRACE;
+
+ PATFETCH (c);
+ }
+
+ if (c != '}')
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ return REG_BADBR;
+ }
+
+ /* We just parsed a valid interval. */
+
+ /* If it's invalid to have no preceding re. */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ return REG_BADRPT;
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ laststart = b;
+ else
+ goto unfetch_interval;
+ }
+
+ /* If the upper bound is zero, don't want to succeed at
+ all; jump from `laststart' to `b + 3', which will be
+ the end of the buffer after we insert the jump. */
+ if (upper_bound == 0)
+ {
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (jump, laststart, b + 3);
+ b += 3;
+ }
+
+ /* Otherwise, we have a nontrivial interval. When
+ we're all done, the pattern will look like:
+ set_number_at <jump count> <upper bound>
+ set_number_at <succeed_n count> <lower bound>
+ succeed_n <after jump addr> <succed_n count>
+ <body of loop>
+ jump_n <succeed_n addr> <jump count>
+ (The upper bound and `jump_n' are omitted if
+ `upper_bound' is 1, though.) */
+ else
+ { /* If the upper bound is > 1, we need to insert
+ more at the end of the loop. */
+ unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+ GET_BUFFER_SPACE (nbytes);
+
+ /* Initialize lower bound of the `succeed_n', even
+ though it will be set during matching by its
+ attendant `set_number_at' (inserted next),
+ because `re_compile_fastmap' needs to know.
+ Jump to the `jump_n' we might insert below. */
+ INSERT_JUMP2 (succeed_n, laststart,
+ b + 5 + (upper_bound > 1) * 5,
+ lower_bound);
+ b += 5;
+
+ /* Code to initialize the lower bound. Insert
+ before the `succeed_n'. The `5' is the last two
+ bytes of this `set_number_at', plus 3 bytes of
+ the following `succeed_n'. */
+ insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+ b += 5;
+
+ if (upper_bound > 1)
+ { /* More than one repetition is allowed, so
+ append a backward jump to the `succeed_n'
+ that starts this interval.
+
+ When we've reached this during matching,
+ we'll have matched the interval once, so
+ jump back only `upper_bound - 1' times. */
+ STORE_JUMP2 (jump_n, b, laststart + 5,
+ upper_bound - 1);
+ b += 5;
+
+ /* The location we want to set is the second
+ parameter of the `jump_n'; that is `b-2' as
+ an absolute address. `laststart' will be
+ the `set_number_at' we're about to insert;
+ `laststart+3' the number to set, the source
+ for the relative address. But we are
+ inserting into the middle of the pattern --
+ so everything is getting moved up by 5.
+ Conclusion: (b - 2) - (laststart + 3) + 5,
+ i.e., b - laststart.
+
+ We insert this at the beginning of the loop
+ so that if we fail during matching, we'll
+ reinitialize the bounds. */
+ insert_op2 (set_number_at, laststart, b - laststart,
+ upper_bound - 1, b);
+ b += 5;
+ }
+ }
+ pending_exact = 0;
+ beg_interval = NULL;
+ }
+ break;
+
unfetch_interval:
- /* If an invalid interval, match the characters as literals. */
- if (beg_interval)
- p = beg_interval;
- else
+ /* If an invalid interval, match the characters as literals. */
+ assert (beg_interval);
+ p = beg_interval;
+ beg_interval = NULL;
+
+ /* normal_char and normal_backslash need `c'. */
+ PATFETCH (c);
+
+ if (!(syntax & RE_NO_BK_BRACES))
{
- fprintf (stderr,
- "regex: no interval beginning to which to backtrack.\n");
- exit (1);
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
}
-
- beg_interval = 0;
- PATFETCH (c); /* normal_char expects char in `c'. */
- goto normal_char;
- break;
+ goto normal_char;
#ifdef emacs
- case '=':
- BUFPUSH (at_dot);
- break;
-
- case 's':
- laststart = b;
- BUFPUSH (syntaxspec);
- PATFETCH (c);
- BUFPUSH (syntax_spec_code[c]);
- break;
-
- case 'S':
- laststart = b;
- BUFPUSH (notsyntaxspec);
- PATFETCH (c);
- BUFPUSH (syntax_spec_code[c]);
- break;
+ /* There is no way to specify the before_dot and after_dot
+ operators. rms says this is ok. --karl */
+ case '=':
+ BUF_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
#endif /* emacs */
- case 'w':
- laststart = b;
- BUFPUSH (wordchar);
- break;
-
- case 'W':
- laststart = b;
- BUFPUSH (notwordchar);
- break;
-
- case '<':
- BUFPUSH (wordbeg);
- break;
-
- case '>':
- BUFPUSH (wordend);
- break;
-
- case 'b':
- BUFPUSH (wordbound);
- break;
-
- case 'B':
- BUFPUSH (notwordbound);
- break;
-
- case '`':
- BUFPUSH (begbuf);
- break;
-
- case '\'':
- BUFPUSH (endbuf);
- break;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (obscure_syntax & RE_NO_BK_REFS)
+
+ case 'w':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (endbuf);
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (syntax & RE_NO_BK_REFS)
goto normal_char;
+
c1 = c - '0';
- if (c1 >= regnum)
- {
- if (obscure_syntax & RE_NO_EMPTY_BK_REF)
- goto invalid_pattern;
- else
- goto normal_char;
- }
+
+ if (c1 > regnum)
+ return REG_ESUBREG;
+
/* Can't back reference to a subexpression if inside of it. */
- for (stackt = stackp - 2; stackt > stackb; stackt -= 4)
- if (*stackt == c1)
- goto normal_char;
- laststart = b;
- BUFPUSH (duplicate);
- BUFPUSH (c1);
- break;
-
- case '+':
- case '?':
- if (obscure_syntax & RE_BK_PLUS_QM)
- goto handle_plus;
- else
- goto normal_backsl;
+ if (group_in_compile_stack (compile_stack, (regnum_t)c1))
+ goto normal_char;
+
+ laststart = b;
+ BUF_PUSH_2 (duplicate, c1);
break;
+
+ case '+':
+ case '?':
+ if (syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+ else
+ goto normal_backslash;
+
default:
- normal_backsl:
- /* You might think it would be useful for \ to mean
- not to translate; but if we don't translate it
- it will never match anything. */
- if (translate) c = translate[c];
- goto normal_char;
- }
- break;
+ normal_backslash:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ c = TRANSLATE (c);
+ goto normal_char;
+ }
+ break;
+
default:
- normal_char: /* Expects the character in `c'. */
- if (!pending_exact || pending_exact + *pending_exact + 1 != b
- || *pending_exact == 0177 || *p == '*' || *p == '^'
- || ((obscure_syntax & RE_BK_PLUS_QM)
+ /* Expects the character in `c'. */
+ normal_char:
+ /* If no exactn currently being built. */
+ if (!pending_exact
+
+ /* If last exactn not at current position. */
+ || pending_exact + *pending_exact + 1 != b
+
+ /* We have only one byte following the exactn for the count. */
+ || *pending_exact == (1 << BYTEWIDTH) - 1
+
+ /* If followed by a repetition operator. */
+ || *p == '*' || *p == '^'
+ || ((syntax & RE_BK_PLUS_QM)
? *p == '\\' && (p[1] == '+' || p[1] == '?')
: (*p == '+' || *p == '?'))
- || ((obscure_syntax & RE_INTERVALS)
- && ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
? *p == '{'
: (p[0] == '\\' && p[1] == '{'))))
{
- laststart = b;
- BUFPUSH (exactn);
- pending_exact = b;
- BUFPUSH (0);
- }
- BUFPUSH (c);
- (*pending_exact)++;
- }
- }
+ /* Start building a new exactn. */
+
+ laststart = b;
+
+ BUF_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ BUF_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
+ if (!COMPILE_STACK_EMPTY)
+ return REG_EPAREN;
- if (stackp != stackb) goto unmatched_open;
+ free (compile_stack.stack);
+ /* We have succeeded; set the length of the buffer. */
bufp->used = b - bufp->buffer;
- return 0;
- invalid_pattern:
- return "Invalid regular expression";
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
- unmatched_open:
- return "Unmatched \\(";
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'. */
- unmatched_close:
- return "Unmatched \\)";
+/* Store OP at LOC followed by two-byte integer parameter ARG. */
- end_of_pattern:
- return "Premature end of regular expression";
+static void
+store_op1 (op, loc, arg)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg);
+}
- nesting_too_deep:
- return "Nesting too deep";
- too_big:
- return "Regular expression too big";
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
- memory_exhausted:
- return "Memory exhausted";
+static void
+store_op2 (op, loc, arg1, arg2)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg1);
+ STORE_NUMBER (loc + 3, arg2);
}
-/* Store a jump of the form <OPCODE> <relative address>.
- Store in the location FROM a jump operation to jump to relative
- address FROM - TO. OPCODE is the opcode to store. */
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+ for OP followed by two-byte integer parameter ARG. */
static void
-store_jump (from, opcode, to)
- char *from, *to;
- int opcode;
+insert_op1 (op, loc, arg, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+ unsigned char *end;
{
- from[0] = (char)opcode;
- STORE_NUMBER(from + 1, to - (from + 3));
-}
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 3;
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op1 (op, loc, arg);
+}
-/* Open up space before char FROM, and insert there a jump to TO.
- CURRENT_END gives the end of the storage not in use, so we know
- how much data to copy up. OP is the opcode of the jump to insert.
- If you call this function, you must zero out pending_exact. */
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
static void
-insert_jump (op, from, to, current_end)
- int op;
- char *from, *to, *current_end;
+insert_op2 (op, loc, arg1, arg2, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+ unsigned char *end;
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 3; /* ...to here. */
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 5;
- while (pfrom != from)
+ while (pfrom != loc)
*--pto = *--pfrom;
- store_jump (from, op, to);
+
+ store_op2 (op, loc, arg1, arg2);
}
-/* Store a jump of the form <opcode> <relative address> <n> .
+/* P points to just after a ^ in PATTERN. Return true if that ^ comes
+ after an alternative or a begin-subexpression. We assume there is at
+ least one character before the ^. */
- Store in the location FROM a jump operation to jump to relative
- address FROM - TO. OPCODE is the opcode to store, N is a number the
- jump uses, say, to decide how many times to jump.
-
- If you call this function, you must zero out pending_exact. */
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+ const char *pattern, *p;
+ reg_syntax_t syntax;
+{
+ const char *prev = p - 2;
+ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+ return
+ /* After a subexpression? */
+ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+ /* After an alternative? */
+ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
-static void
-store_jump_n (from, opcode, to, n)
- char *from, *to;
- int opcode;
- unsigned n;
+
+/* The dual of at_begline_loc_p. This one is for $. We assume there is
+ at least one character after the $, i.e., `P < PEND'. */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+ const char *p, *pend;
+ reg_syntax_t syntax;
{
- from[0] = (char)opcode;
- STORE_NUMBER (from + 1, to - (from + 3));
- STORE_NUMBER (from + 3, n);
+ const char *next = p;
+ boolean next_backslash = *next == '\\';
+ const char *next_next = p + 1 < pend ? p + 1 : NULL;
+
+ return
+ /* Before a subexpression? */
+ (syntax & RE_NO_BK_PARENS ? *next == ')'
+ : next_backslash && next_next && *next_next == ')')
+ /* Before an alternative? */
+ || (syntax & RE_NO_BK_VBAR ? *next == '|'
+ : next_backslash && next_next && *next_next == '|');
}
-/* Similar to insert_jump, but handles a jump which needs an extra
- number to handle minimum and maximum cases. Open up space at
- location FROM, and insert there a jump to TO. CURRENT_END gives the
- end of the storage in use, so we know how much data to copy up. OP is
- the opcode of the jump to insert.
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+ false if it's not. */
- If you call this function, you must zero out pending_exact. */
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+ compile_stack_type compile_stack;
+ regnum_t regnum;
+{
+ int this_element;
-static void
-insert_jump_n (op, from, to, current_end, n)
- int op;
- char *from, *to, *current_end;
- unsigned n;
+ for (this_element = compile_stack.avail - 1;
+ this_element >= 0;
+ this_element--)
+ if (compile_stack.stack[this_element].regnum == regnum)
+ return true;
+
+ return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+ uncompiled pattern *P_PTR (which ends at PEND). We assume the
+ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
+ Then we set the translation of all bits between the starting and
+ ending characters (inclusive) in the compiled pattern B.
+
+ Return an error code.
+
+ We use these short variable names so we can use the same macros as
+ `regex_compile' itself. */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+ const char **p_ptr, *pend;
+ char *translate;
+ reg_syntax_t syntax;
+ unsigned char *b;
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
+ unsigned this_char;
- while (pfrom != from)
- *--pto = *--pfrom;
- store_jump_n (from, op, to, n);
+ const char *p = *p_ptr;
+ int range_start, range_end;
+
+ if (p == pend)
+ return REG_ERANGE;
+
+ /* Even though the pattern is a signed `char *', we need to fetch
+ with unsigned char *'s; if the high bit of the pattern character
+ is set, the range endpoints will be negative if we fetch using a
+ signed char *.
+
+ We also want to fetch the endpoints without translating them; the
+ appropriate translation is done in the bit-setting loop below. */
+ range_start = ((unsigned char *) p)[-2];
+ range_end = ((unsigned char *) p)[0];
+
+ /* Have to increment the pointer into the pattern string, so the
+ caller isn't still at the ending character. */
+ (*p_ptr)++;
+
+ /* If the start is after the end, the range is empty. */
+ if (range_start > range_end)
+ return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+ /* Here we see why `this_char' has to be larger than an `unsigned
+ char' -- the range is inclusive, so if `range_end' == 0xff
+ (assuming 8-bit characters), we would otherwise go into an infinite
+ loop, since all characters <= 0xff. */
+ for (this_char = range_start; this_char <= range_end; this_char++)
+ {
+ SET_LIST_BIT (TRANSLATE (this_char));
+ }
+
+ return REG_NOERROR;
}
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+ re_match_2 use a failure stack. These have to be macros because of
+ REGEX_ALLOCATE. */
+
+/* Number of failure points for which to initially allocate space
+ when matching. If this number is exceeded, we allocate more
+ space, so it is not a hard limit. */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
-/* Open up space at location THERE, and insert operation OP followed by
- NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so
- we know how much data to copy up.
+/* Roughly the maximum number of failure points on the stack. Would be
+ exactly that if always used MAX_FAILURE_SPACE each time we failed.
+ This is a variable only so users of regex can assign to it; we never
+ change it ourselves. */
+int re_max_failures = 2000;
- If you call this function, you must zero out pending_exact. */
+typedef const unsigned char *fail_stack_elt_t;
-static void
-insert_op_2 (op, there, current_end, num_1, num_2)
- int op;
- char *there, *current_end;
- int num_1, num_2;
+typedef struct
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
+ fail_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} fail_stack_type;
- while (pfrom != there)
- *--pto = *--pfrom;
-
- there[0] = (char)op;
- STORE_NUMBER (there + 1, num_1);
- STORE_NUMBER (there + 3, num_2);
-}
+#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
+#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail])
+
+
+/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */
+
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.stack = (fail_stack_elt_t *) \
+ REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+ \
+ if (fail_stack.stack == NULL) \
+ return -2; \
+ \
+ fail_stack.size = INIT_FAILURE_ALLOC; \
+ fail_stack.avail = 0; \
+ } while (0)
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+ Return 1 if succeeds, and 0 if either ran out of memory
+ allocating space for it or it was already too large.
+
+ REGEX_REALLOCATE requires `destination' be declared. */
+
+#define DOUBLE_FAIL_STACK(fail_stack) \
+ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
+ ? 0 \
+ : ((fail_stack).stack = (fail_stack_elt_t *) \
+ REGEX_REALLOCATE ((fail_stack).stack, \
+ (fail_stack).size * sizeof (fail_stack_elt_t), \
+ ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
+ \
+ (fail_stack).stack == NULL \
+ ? 0 \
+ : ((fail_stack).size <<= 1, \
+ 1)))
+
+
+/* Push PATTERN_OP on FAIL_STACK.
+
+ Return 1 if was able to do so and 0 if ran out of memory allocating
+ space to do so. */
+#define PUSH_PATTERN_OP(pattern_op, fail_stack) \
+ ((FAIL_STACK_FULL () \
+ && !DOUBLE_FAIL_STACK (fail_stack)) \
+ ? 0 \
+ : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \
+ 1))
+
+/* This pushes an item onto the failure stack. Must be a four-byte
+ value. Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_ITEM(item) \
+ fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
+
+/* The complement operation. Assumes `fail_stack' is nonempty. */
+#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging. */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_ITEM
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+ if we ever fail back to it.
+
+ Requires variables fail_stack, regstart, regend, reg_info, and
+ num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
+ declared.
+
+ Does `return FAILURE_CODE' if runs out of memory. */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
+ do { \
+ char *destination; \
+ /* Must be int, so when we don't save any registers, the arithmetic \
+ of 0 + -1 isn't done as unsigned. */ \
+ /* Can't be int, since there is not a shred of a guarantee that int \
+ is wide enough to hold a value of something to which pointer can \
+ be assigned */ \
+ s_reg_t this_reg; \
+ \
+ DEBUG_STATEMENT (failure_id++); \
+ DEBUG_STATEMENT (nfailure_points_pushed++); \
+ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
+ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
+ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
+ \
+ DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
+ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
+ \
+ /* Ensure we have enough space allocated for what we will push. */ \
+ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
+ { \
+ if (!DOUBLE_FAIL_STACK (fail_stack)) \
+ return failure_code; \
+ \
+ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
+ (fail_stack).size); \
+ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+ }
+
+#define PUSH_FAILURE_POINT2(pattern_place, string_place, failure_code) \
+ /* Push the info, starting with the registers. */ \
+ DEBUG_PRINT1 ("\n"); \
+ \
+ PUSH_FAILURE_POINT_LOOP (); \
+ \
+ DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
+ PUSH_FAILURE_ITEM (lowest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
+ PUSH_FAILURE_ITEM (highest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
+ PUSH_FAILURE_ITEM (pattern_place); \
+ \
+ DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
+ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
+ size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ PUSH_FAILURE_ITEM (string_place); \
+ \
+ DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
+ DEBUG_PUSH (failure_id); \
+ } while (0)
+
+/* Pulled out of PUSH_FAILURE_POINT() to shorten the definition
+ of that macro. (for VAX C) */
+#define PUSH_FAILURE_POINT_LOOP() \
+ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+ this_reg++) \
+ { \
+ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
+ DEBUG_STATEMENT (num_regs_pushed++); \
+ \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ PUSH_FAILURE_ITEM (regstart[this_reg]); \
+ \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ PUSH_FAILURE_ITEM (regend[this_reg]); \
+ \
+ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
+ DEBUG_PRINT2 (" match_null=%d", \
+ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" matched_something=%d", \
+ MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" ever_matched=%d", \
+ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT1 ("\n"); \
+ PUSH_FAILURE_ITEM (reg_info[this_reg].word); \
+ }
+
+/* This is the number of items that are pushed and popped on the stack
+ for each register. */
+#define NUM_REG_ITEMS 3
+
+/* Individual items aside from the registers. */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack. */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items. */
+#define NUM_FAILURE_ITEMS \
+ ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
+ + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it. */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+ We restore into the parameters, all of which should be lvalues:
+ STR -- the saved data position.
+ PAT -- the saved pattern position.
+ LOW_REG, HIGH_REG -- the highest and lowest active registers.
+ REGSTART, REGEND -- arrays of string positions.
+ REG_INFO -- array of information about each subexpression.
+
+ Also assumes the variables `fail_stack' and (if debugging), `bufp',
+ `pend', `string1', `size1', `string2', and `size2'. */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{ \
+ DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
+ s_reg_t this_reg; \
+ const unsigned char *string_temp; \
+ \
+ assert (!FAIL_STACK_EMPTY ()); \
+ \
+ /* Remove failure points and point to how many regs pushed. */ \
+ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
+ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
+ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
+ \
+ assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
+ \
+ DEBUG_POP (&failure_id); \
+ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
+ \
+ /* If the saved string location is NULL, it came from an \
+ on_failure_keep_string_jump opcode, and we want to throw away the \
+ saved NULL, thus retaining our current position in the string. */ \
+ string_temp = POP_FAILURE_ITEM (); \
+ if (string_temp != NULL) \
+ str = (const char *) string_temp; \
+ \
+ DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
+ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ \
+ pat = (unsigned char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
+ \
+ POP_FAILURE_POINT2 (low_reg, high_reg, regstart, regend, reg_info);
+/* Pulled out of POP_FAILURE_POINT() to shorten the definition
+ of that macro. (for MSC 5.1) */
+#define POP_FAILURE_POINT2(low_reg, high_reg, regstart, regend, reg_info) \
+ \
+ /* Restore register info. */ \
+ high_reg = (active_reg_t) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
+ \
+ low_reg = (active_reg_t) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
+ \
+ for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
+ { \
+ DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
+ \
+ reg_info[this_reg].word = POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
+ \
+ regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ \
+ regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ } \
+ \
+ DEBUG_STATEMENT (nfailure_points_popped++); \
+} /* POP_FAILURE_POINT */
-/* Given a pattern, compute a fastmap from it. The fastmap records
- which of the (1 << BYTEWIDTH) possible characters can start a string
- that matches the pattern. This fastmap is used by re_search to skip
- quickly over totally implausible text.
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
+ characters can start a string that matches the pattern. This fastmap
+ is used by re_search to skip quickly over impossible starting points.
- The caller must supply the address of a (1 << BYTEWIDTH)-byte data
- area as bufp->fastmap.
- The other components of bufp describe the pattern to be used. */
+ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+ area as BUFP->fastmap.
+
+ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+ the pattern buffer.
-void
+ Returns 0 if we succeed, -2 if an internal error. */
+
+int
re_compile_fastmap (bufp)
struct re_pattern_buffer *bufp;
{
- unsigned char *pattern = (unsigned char *) bufp->buffer;
- int size = bufp->used;
+ int j, k;
+ fail_stack_type fail_stack;
+#ifndef REGEX_MALLOC
+ char *destination;
+#endif
+ /* We don't push any register information onto the failure stack. */
+ unsigned num_regs = 0;
+
register char *fastmap = bufp->fastmap;
- register unsigned char *p = pattern;
- register unsigned char *pend = pattern + size;
- register int j, k;
- unsigned char *translate = (unsigned char *) bufp->translate;
- unsigned is_a_succeed_n;
+ unsigned char *pattern = bufp->buffer;
+ const unsigned char *p = pattern;
+ register unsigned char *pend = pattern + bufp->used;
-#ifndef NO_ALLOCA
- unsigned char *stackb[NFAILURES];
- unsigned char **stackp = stackb;
+ /* Assume that each path through the pattern can be null until
+ proven otherwise. We set this false at the bottom of switch
+ statement, to which we get only if a particular path doesn't
+ match the empty string. */
+ boolean path_can_be_null = true;
-#else
- unsigned char **stackb;
- unsigned char **stackp;
- stackb = (unsigned char **) malloc (NFAILURES * sizeof (unsigned char *));
- stackp = stackb;
-
-#endif /* NO_ALLOCA */
- memset (fastmap, 0, (1 << BYTEWIDTH));
- bufp->fastmap_accurate = 1;
+ /* We aren't doing a `succeed_n' to begin with. */
+ boolean succeed_n_p = false;
+
+ assert (fastmap != NULL && p != NULL);
+
+ INIT_FAIL_STACK ();
+ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
+ bufp->fastmap_accurate = 1; /* It will be when we're done. */
bufp->can_be_null = 0;
- while (p)
+ while (p != pend || !FAIL_STACK_EMPTY ())
{
- is_a_succeed_n = 0;
if (p == pend)
- {
- bufp->can_be_null = 1;
- break;
+ {
+ bufp->can_be_null |= path_can_be_null;
+
+ /* Reset for next path. */
+ path_can_be_null = true;
+
+ p = fail_stack.stack[--fail_stack.avail];
}
+
+ /* We should never be about to go beyond the end of the pattern. */
+ assert (p < pend);
+
#ifdef SWITCH_ENUM_BUG
- switch ((int) ((enum regexpcode) *p++))
+ switch ((int) ((re_opcode_t) *p++))
#else
- switch ((enum regexpcode) *p++)
+ switch ((re_opcode_t) *p++)
#endif
{
+
+ /* I guess the idea here is to simply not bother with a fastmap
+ if a backreference is used, since it's too hard to figure out
+ the fastmap for the corresponding group. Setting
+ `can_be_null' stops `re_search_2' from using the fastmap, so
+ that is all we do. */
+ case duplicate:
+ bufp->can_be_null = 1;
+ return 0;
+
+
+ /* Following are the cases which match a character. These end
+ with `break'. */
+
case exactn:
- if (translate)
- fastmap[translate[p[1]]] = 1;
- else
- fastmap[p[1]] = 1;
+ fastmap[p[1]] = 1;
break;
- case begline:
- case before_dot:
+
+ case charset:
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ fastmap[j] = 1;
+ break;
+
+
+ case charset_not:
+ /* Chars beyond end of map must be allowed. */
+ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ fastmap[j] = 1;
+ break;
+
+
+ case wordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case notwordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case anychar:
+ /* `.' matches anything ... */
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ /* ... except perhaps newline. */
+ if (!(bufp->syntax & RE_DOT_NEWLINE))
+ fastmap['\n'] = 0;
+
+ /* Return if we have already set `can_be_null'; if we have,
+ then the fastmap is irrelevant. Something's wrong here. */
+ else if (bufp->can_be_null)
+ return 0;
+
+ /* Otherwise, have to check alternative paths. */
+ break;
+
+
+#ifdef emacs
+ case syntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ case notsyntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ /* All cases after this match the empty string. These end with
+ `continue'. */
+
+
+ case before_dot:
case at_dot:
case after_dot:
+ continue;
+#endif /* not emacs */
+
+
+ case no_op:
+ case begline:
+ case endline:
case begbuf:
case endbuf:
case wordbound:
case notwordbound:
case wordbeg:
case wordend:
+ case push_dummy_failure:
continue;
- case endline:
- if (translate)
- fastmap[translate['\n']] = 1;
- else
- fastmap['\n'] = 1;
-
- if (bufp->can_be_null != 1)
- bufp->can_be_null = 2;
- break;
case jump_n:
- case finalize_jump:
- case maybe_finalize_jump:
+ case pop_failure_jump:
+ case maybe_pop_jump:
case jump:
+ case jump_past_alt:
case dummy_failure_jump:
EXTRACT_NUMBER_AND_INCR (j, p);
p += j;
if (j > 0)
continue;
- /* Jump backward reached implies we just went through
- the body of a loop and matched nothing.
- Opcode jumped to should be an on_failure_jump.
- Just treat it like an ordinary jump.
- For a * loop, it has pushed its failure point already;
- If so, discard that as redundant. */
-
- if ((enum regexpcode) *p != on_failure_jump
- && (enum regexpcode) *p != succeed_n)
+
+ /* Jump backward implies we just went through the body of a
+ loop and matched nothing. Opcode jumped to should be
+ `on_failure_jump' or `succeed_n'. Just treat it like an
+ ordinary jump. For a * loop, it has pushed its failure
+ point already; if so, discard that as redundant. */
+ if ((re_opcode_t) *p != on_failure_jump
+ && (re_opcode_t) *p != succeed_n)
continue;
+
p++;
EXTRACT_NUMBER_AND_INCR (j, p);
p += j;
- if (stackp != stackb && *stackp == p)
- stackp--;
- continue;
+ /* If what's on the stack is where we are now, pop it. */
+ if (!FAIL_STACK_EMPTY ()
+ && fail_stack.stack[fail_stack.avail - 1] == p)
+ fail_stack.avail--;
+
+ continue;
+
+
case on_failure_jump:
+ case on_failure_keep_string_jump:
handle_on_failure_jump:
EXTRACT_NUMBER_AND_INCR (j, p);
- *++stackp = p + j;
- if (is_a_succeed_n)
- EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
- continue;
+
+ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+ end of the pattern. We don't want to push such a point,
+ since when we restore it above, entering the switch will
+ increment `p' past the end of the pattern. We don't need
+ to push such a point since we obviously won't find any more
+ fastmap entries beyond `pend'. Such a pattern can match
+ the null string, though. */
+ if (p + j < pend)
+ {
+ if (!PUSH_PATTERN_OP (p + j, fail_stack))
+ return -2;
+ }
+ else
+ bufp->can_be_null = 1;
+
+ if (succeed_n_p)
+ {
+ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
+ succeed_n_p = false;
+ }
+
+ continue;
+
case succeed_n:
- is_a_succeed_n = 1;
/* Get to the number of times to succeed. */
p += 2;
- /* Increment p past the n for when k != 0. */
+
+ /* Increment p past the n for when k != 0. */
EXTRACT_NUMBER_AND_INCR (k, p);
if (k == 0)
{
p -= 4;
+ succeed_n_p = true; /* Spaghetti code alert. */
goto handle_on_failure_jump;
}
continue;
-
+
+
case set_number_at:
p += 4;
continue;
- case start_memory:
- case stop_memory:
- p++;
- continue;
-
- case duplicate:
- bufp->can_be_null = 1;
- fastmap['\n'] = 1;
- case anychar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (j != '\n')
- fastmap[j] = 1;
- if (bufp->can_be_null)
- {
- FREE_AND_RETURN_VOID(stackb);
- }
- /* Don't return; check the alternative paths
- so we can set can_be_null if appropriate. */
- break;
-
- case wordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == Sword)
- fastmap[j] = 1;
- break;
-
- case notwordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != Sword)
- fastmap[j] = 1;
- break;
-#ifdef emacs
- case syntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
- case notsyntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
-#else /* not emacs */
- case syntaxspec:
- case notsyntaxspec:
- break;
-#endif /* not emacs */
+ case start_memory:
+ case stop_memory:
+ p += 2;
+ continue;
- case charset:
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
- {
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
- }
- break;
- case charset_not:
- /* Chars beyond end of map must be allowed */
- for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
+ default:
+ abort (); /* We have listed all the cases. */
+ } /* switch *p++ */
+
+ /* Getting here means we have found the possible starting
+ characters for one path of the pattern -- and that the empty
+ string does not match. We need not follow this path further.
+ Instead, look at the next alternative (remembered on the
+ stack), or quit if no more. The test at the top of the loop
+ does these things. */
+ path_can_be_null = false;
+ p = pend;
+ } /* while p */
+
+ /* Set `can_be_null' for the last path (also the first path, if the
+ pattern is empty). */
+ bufp->can_be_null |= path_can_be_null;
+ return 0;
+} /* re_compile_fastmap */
+
+/* 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.
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
- {
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
- }
- break;
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
- case unused: /* pacify gcc -Wall */
- break;
- }
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
- /* Get here means we have successfully found the possible starting
- characters of one path of the pattern. We need not follow this
- path any farther. Instead, look at the next alternative
- remembered in the stack. */
- if (stackp != stackb)
- p = *stackp--;
- else
- break;
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = 0;
}
- FREE_AND_RETURN_VOID(stackb);
}
-
-
+/* Searching routines. */
+
/* Like re_search_2, below, but only one string is specified, and
doesn't let you say where to stop matching. */
int
-re_search (pbufp, string, size, startpos, range, regs)
- struct re_pattern_buffer *pbufp;
- char *string;
+re_search (bufp, string, size, startpos, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
int size, startpos, range;
struct re_registers *regs;
{
- return re_search_2 (pbufp, (char *) 0, 0, string, size, startpos, range,
+ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
regs, size);
}
-/* Using the compiled pattern in PBUFP->buffer, first tries to match the
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
virtual concatenation of STRING1 and STRING2, starting first at index
- STARTPOS, then at STARTPOS + 1, and so on. RANGE is the number of
- places to try before giving up. If RANGE is negative, it searches
- backwards, i.e., the starting positions tried are STARTPOS, STARTPOS
- - 1, etc. STRING1 and STRING2 are of SIZE1 and SIZE2, respectively.
+ STARTPOS, then at STARTPOS + 1, and so on.
+
+ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+ RANGE is how far to scan while trying to match. RANGE = 0 means try
+ only at STARTPOS; in general, the last start tried is STARTPOS +
+ RANGE.
+
In REGS, return the indices of the virtual concatenation of STRING1
- and STRING2 that matched the entire PBUFP->buffer and its contained
- subexpressions. Do not consider matching one past the index MSTOP in
- the virtual concatenation of STRING1 and STRING2.
+ and STRING2 that matched the entire BUFP->buffer and its contained
+ subexpressions.
+
+ Do not consider matching one past the index STOP in the virtual
+ concatenation of STRING1 and STRING2.
- The value returned is the position in the strings at which the match
- was found, or -1 if no match was found, or -2 if error (such as
- failure stack overflow). */
+ We return either the position in the strings at which the match was
+ found, -1 if no match, or -2 if error (such as failure
+ stack overflow). */
int
-re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
- regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1, *string2;
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
int size1, size2;
int startpos;
- register int range;
+ int range;
struct re_registers *regs;
- int mstop;
+ int stop;
{
- register char *fastmap = pbufp->fastmap;
- register unsigned char *translate = (unsigned char *) pbufp->translate;
+ int val;
+ register char *fastmap = bufp->fastmap;
+ register char *translate = bufp->translate;
int total_size = size1 + size2;
int endpos = startpos + range;
- int val;
- /* Check for out-of-range starting position. */
- if (startpos < 0 || startpos > total_size)
+ /* Check for out-of-range STARTPOS. */
+ if (startpos < 0 || startpos > total_size)
return -1;
- /* Fix up range if it would eventually take startpos outside of the
- virtual concatenation of string1 and string2. */
+ /* Fix up RANGE if it might eventually take us outside
+ the virtual concatenation of STRING1 and STRING2. */
if (endpos < -1)
range = -1 - startpos;
else if (endpos > total_size)
range = total_size - startpos;
- /* Update the fastmap now if not correct already. */
- if (fastmap && !pbufp->fastmap_accurate)
- re_compile_fastmap (pbufp);
-
/* If the search isn't to be a backwards one, don't waste time in a
- long search for a pattern that says it is anchored. */
- if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
- && range > 0)
+ search for a pattern that must be anchored. */
+ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
{
if (startpos > 0)
return -1;
@@ -1628,65 +3014,68 @@ re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
range = 1;
}
- while (1)
+ /* Update the fastmap now if not correct already. */
+ if (fastmap && !bufp->fastmap_accurate)
+ if (re_compile_fastmap (bufp) == -2)
+ return -2;
+
+ /* Loop through the string, looking for a place to start matching. */
+ for (;;)
{
/* If a fastmap is supplied, skip quickly over characters that
- cannot possibly be the start of a match. Note, however, that
- if the pattern can possibly match the null string, we must
- test it at each starting point so that we take the first null
- string we get. */
-
- if (fastmap && startpos < total_size && pbufp->can_be_null != 1)
+ cannot be the start of a match. If the pattern can match the
+ null string, however, we don't need to skip characters; we want
+ the first null string. */
+ if (fastmap && startpos < total_size && !bufp->can_be_null)
{
if (range > 0) /* Searching forwards. */
{
+ register const char *d;
register int lim = 0;
- register unsigned char *p;
int irange = range;
- if (startpos < size1 && startpos + range >= size1)
- lim = range - (size1 - startpos);
- p = ((unsigned char *)
- &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
+ if (startpos < size1 && startpos + range >= size1)
+ lim = range - (size1 - startpos);
+
+ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+ /* Written out as an if-else to avoid testing `translate'
+ inside the loop. */
+ if (translate)
+ while (range > lim
+ && !fastmap[(unsigned char)
+ translate[(unsigned char) *d++]])
+ range--;
+ else
+ while (range > lim && !fastmap[(unsigned char) *d++])
+ range--;
- while (range > lim && !fastmap[translate
- ? translate[*p++]
- : *p++])
- range--;
startpos += irange - range;
}
else /* Searching backwards. */
{
- register unsigned char c;
-
- if (string1 == 0 || startpos >= size1)
- c = string2[startpos - size1];
- else
- c = string1[startpos];
+ register char c = (size1 == 0 || startpos >= size1
+ ? string2[startpos - size1]
+ : string1[startpos]);
- c &= 0xff;
- if (translate ? !fastmap[translate[c]] : !fastmap[c])
+ if (!fastmap[(unsigned char) TRANSLATE (c)])
goto advance;
}
}
- if (range >= 0 && startpos == total_size
- && fastmap && pbufp->can_be_null == 0)
+ /* If can't match the null string, and that's all we have left, fail. */
+ if (range >= 0 && startpos == total_size && fastmap
+ && !bufp->can_be_null)
return -1;
- val = re_match_2 (pbufp, string1, size1, string2, size2, startpos,
- regs, mstop);
+ val = re_match_2 (bufp, string1, size1, string2, size2,
+ startpos, regs, stop);
if (val >= 0)
return startpos;
+
if (val == -2)
return -2;
-#ifndef NO_ALLOCA
-#ifdef C_ALLOCA
- alloca (0);
-#endif /* C_ALLOCA */
-
-#endif /* NO_ALLOCA */
advance:
if (!range)
break;
@@ -1702,245 +3091,236 @@ re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
}
}
return -1;
-}
-
-
+} /* re_search_2 */
-#ifndef emacs /* emacs never uses this. */
-int
-re_match (pbufp, string, size, pos, regs)
- struct re_pattern_buffer *pbufp;
- char *string;
- int size, pos;
- struct re_registers *regs;
-{
- return re_match_2 (pbufp, (char *) 0, 0, string, size, pos, regs, size);
-}
-#endif /* not emacs */
-
-
-/* The following are used for re_match_2, defined below: */
-
-/* Roughly the maximum number of failure points on the stack. Would be
- exactly that if always pushed MAX_NUM_FAILURE_ITEMS each time we failed. */
+/* Structure for per-register (a.k.a. per-group) information.
+ This must not be longer than one word, because we push this value
+ onto the failure stack. Other register information, such as the
+ starting and ending positions (which are addresses), and the list of
+ inner groups (which is a bits list) are maintained in separate
+ variables.
-int re_max_failures = 2000;
-
-/* Routine used by re_match_2. */
-/* static int memcmp_translate (); *//* already declared */
-
+ We are making a (strictly speaking) nonportable assumption here: that
+ the compiler will pack our bit fields into something that fits into
+ the type of `word', i.e., is something that fits into one item on the
+ failure stack. */
-/* Structure and accessing macros used in re_match_2: */
+/* Declarations and macros for re_match_2. */
-struct register_info
+typedef union
{
- unsigned is_active : 1;
- unsigned matched_something : 1;
-};
-
-#define IS_ACTIVE(R) ((R).is_active)
-#define MATCHED_SOMETHING(R) ((R).matched_something)
-
-
-/* Macros used by re_match_2: */
-
-
-/* I.e., regstart, regend, and reg_info. */
-
-#define NUM_REG_ITEMS 3
-
-/* We push at most this many things on the stack whenever we
- fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are
- arguments to the PUSH_FAILURE_POINT macro. */
-
-#define MAX_NUM_FAILURE_ITEMS (RE_NREGS * NUM_REG_ITEMS + 2)
-
-
-/* We push this many things on the stack whenever we fail. */
-
-#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + 2)
-
-
-/* This pushes most of the information about the current state we will want
- if we ever fail back to it. */
-
-#define PUSH_FAILURE_POINT(pattern_place, string_place) \
- { \
- long last_used_reg, this_reg; \
- \
- /* Find out how many registers are active or have been matched. \
- (Aside from register zero, which is only set at the end.) */ \
- for (last_used_reg = RE_NREGS - 1; last_used_reg > 0; last_used_reg--)\
- if (regstart[last_used_reg] != (unsigned char *)(-1L)) \
- break; \
- \
- if (stacke - stackp < NUM_FAILURE_ITEMS) \
- { \
- unsigned char **stackx; \
- unsigned int len = stacke - stackb; \
- if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \
- { \
- FREE_AND_RETURN(stackb,(-2)); \
- } \
- \
- /* Roughly double the size of the stack. */ \
- stackx = DOUBLE_STACK(stackx,stackb,len); \
- /* Rearrange the pointers. */ \
- stackp = stackx + (stackp - stackb); \
- stackb = stackx; \
- stacke = stackb + 2 * len; \
- } \
- \
- /* Now push the info for each of those registers. */ \
- for (this_reg = 1; this_reg <= last_used_reg; this_reg++) \
- { \
- *stackp++ = regstart[this_reg]; \
- *stackp++ = regend[this_reg]; \
- *stackp++ = (unsigned char *) &reg_info[this_reg]; \
- } \
- \
- /* Push how many registers we saved. */ \
- *stackp++ = (unsigned char *) last_used_reg; \
- \
- *stackp++ = pattern_place; \
- *stackp++ = string_place; \
- }
-
-
-/* This pops what PUSH_FAILURE_POINT pushes. */
-
-#define POP_FAILURE_POINT() \
- { \
- int temp; \
- stackp -= 2; /* Remove failure points. */ \
- temp = (int) *--stackp; /* How many regs pushed. */ \
- temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \
- stackp -= temp; /* Remove the register info. */ \
- }
-
+ fail_stack_elt_t word;
+ struct
+ {
+ /* This field is one if this group can match the empty string,
+ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
+#define MATCH_NULL_UNSET_VALUE 3
+ unsigned match_null_string_p : 2;
+ unsigned is_active : 1;
+ unsigned matched_something : 1;
+ unsigned ever_matched_something : 1;
+ } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R) ((R).bits.is_active)
+#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
+
+static boolean group_match_null_string_p _RE_ARGS((unsigned char **p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static boolean alt_match_null_string_p _RE_ARGS((unsigned char *p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static boolean common_op_match_null_string_p _RE_ARGS((unsigned char **p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static int bcmp_translate _RE_ARGS((const char *s1, const char *s2,
+ int len, char *translate));
+
+/* Call this when have matched a real character; it sets `matched' flags
+ for the subexpressions which we are currently inside. Also records
+ that those subexprs have matched. */
+#define SET_REGS_MATCHED() \
+ do \
+ { \
+ active_reg_t r; \
+ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
+ { \
+ MATCHED_SOMETHING (reg_info[r]) \
+ = EVER_MATCHED_SOMETHING (reg_info[r]) \
+ = 1; \
+ } \
+ } \
+ while (0)
+
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+ and `string2' into an offset from the beginning of that string. */
+#define POINTER_TO_OFFSET(ptr) \
+ (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
+
+/* Registers are set to a sentinel when they haven't yet matched. */
+#define REG_UNSET_VALUE ((char *) -1)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+
+/* Macros for dealing with the split strings in re_match_2. */
#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
-/* Is true if there is a first string and if PTR is pointing anywhere
- inside it or just past the end. */
-
-#define IS_IN_FIRST_STRING(ptr) \
- (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
-
/* Call before fetching a character with *d. This switches over to
string2 if necessary. */
+#define PREFETCH() \
+ while (d == dend) \
+ { \
+ /* End of string2 => fail. */ \
+ if (dend == end_match_2) \
+ goto fail; \
+ /* End of string1 => advance to string2. */ \
+ d = string2; \
+ dend = end_match_2; \
+ }
-#define PREFETCH \
- while (d == dend) \
- { \
- /* end of string2 => fail. */ \
- if (dend == end_match_2) \
- goto fail; \
- /* end of string1 => advance to string2. */ \
- d = string2; \
- dend = end_match_2; \
- }
-
-
-/* Call this when have matched something; it sets `matched' flags for the
- registers corresponding to the subexpressions of which we currently
- are inside. */
-#define SET_REGS_MATCHED \
- { unsigned this_reg; \
- for (this_reg = 0; this_reg < RE_NREGS; this_reg++) \
- { \
- if (IS_ACTIVE(reg_info[this_reg])) \
- MATCHED_SOMETHING(reg_info[this_reg]) = 1; \
- else \
- MATCHED_SOMETHING(reg_info[this_reg]) = 0; \
- } \
- }
/* Test if at very beginning or at very end of the virtual concatenation
- of string1 and string2. If there is only one string, we've put it in
- string2. */
-
-#define AT_STRINGS_BEG (d == (size1 ? string1 : string2) || !size2)
-#define AT_STRINGS_END (d == end2)
-
-#define AT_WORD_BOUNDARY \
- (AT_STRINGS_BEG || AT_STRINGS_END || IS_A_LETTER (d - 1) != IS_A_LETTER (d))
-
-/* We have two special cases to check for:
- 1) if we're past the end of string1, we have to look at the first
- character in string2;
- 2) if we're before the beginning of string2, we have to look at the
- last character in string1; we assume there is a string1, so use
- this in conjunction with AT_STRINGS_BEG. */
-#define IS_A_LETTER(d) \
- (SYNTAX ((d) == end1 ? *string2 : (d) == string2 - 1 ? *(end1 - 1) : *(d))\
+ of `string1' and `string2'. If only one string, it's `string2'. */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent. We have
+ two special cases to check for: if past the end of string1, look at
+ the first character in string2; and if before the beginning of
+ string2, look at the last character in string1. */
+#define WORDCHAR_P(d) \
+ (SYNTAX ((d) == end1 ? *string2 \
+ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
== Sword)
+/* Test if the character before D and the one at D differ with respect
+ to being word-constituent. */
+#define AT_WORD_BOUNDARY(d) \
+ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
+ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc. */
+#ifdef REGEX_MALLOC
+#define FREE_VAR(var) if (var) free (var); var = NULL
+#define FREE_VARIABLES() \
+ do { \
+ FREE_VAR (fail_stack.stack); \
+ FREE_VAR (regstart); \
+ FREE_VAR (regend); \
+ FREE_VAR (old_regstart); \
+ FREE_VAR (old_regend); \
+ FREE_VAR (best_regstart); \
+ FREE_VAR (best_regend); \
+ FREE_VAR (reg_info); \
+ FREE_VAR (reg_dummy); \
+ FREE_VAR (reg_info_dummy); \
+ } while (0)
+#else /* not REGEX_MALLOC */
+/* Some MIPS systems (at least) want this to free alloca'd storage. */
+#define FREE_VARIABLES() alloca (0)
+#endif /* not REGEX_MALLOC */
+
+
+/* These values must meet several constraints. They must not be valid
+ register values; since we have a limit of 255 registers (because
+ we use only one byte in the pattern for the register number), we can
+ use numbers larger than 255. They must differ by 1, because of
+ NUM_FAILURE_ITEMS above. And the value for the lowest register must
+ be larger than the value for the highest register, so we do not try
+ to actually save any registers when none are active. */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+/* Matching routines. */
-/* Match the pattern described by PBUFP against the virtual
- concatenation of STRING1 and STRING2, which are of SIZE1 and SIZE2,
- respectively. Start the match at index POS in the virtual
- concatenation of STRING1 and STRING2. In REGS, return the indices of
- the virtual concatenation of STRING1 and STRING2 that matched the
- entire PBUFP->buffer and its contained subexpressions. Do not
- consider matching one past the index MSTOP in the virtual
- concatenation of STRING1 and STRING2.
+#ifndef emacs /* Emacs never uses this. */
+/* re_match is like re_match_2 except it takes only a single string. */
- If pbufp->fastmap is nonzero, then it had better be up to date.
+int
+re_match (bufp, string, size, pos, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, pos;
+ struct re_registers *regs;
+ {
+ return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
+}
+#endif /* not emacs */
- The reason that the data to match are specified as two components
- which are to be regarded as concatenated is so this function can be
- used directly on the contents of an Emacs buffer.
- -1 is returned if there is no match. -2 is returned if there is an
- error (such as match stack overflow). Otherwise the value is the
- length of the substring which was matched. */
+/* re_match_2 matches the compiled pattern in BUFP against the
+ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+ and SIZE2, respectively). We start matching at POS, and stop
+ matching at STOP.
+
+ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+ store offsets for the substring each group matched in REGS. See the
+ documentation for exactly how many groups we fill.
+
+ We return -1 if no match, -2 if an internal error (such as the
+ failure stack overflowing). Otherwise, we return the length of the
+ matched substring. */
int
-re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1_arg, *string2_arg;
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
int size1, size2;
int pos;
struct re_registers *regs;
- int mstop;
+ int stop;
{
- register unsigned char *p = (unsigned char *) pbufp->buffer;
-
- /* Pointer to beyond end of buffer. */
- register unsigned char *pend = p + pbufp->used;
+ /* General temporaries. */
+ int mcnt;
+ unsigned char *p1;
- unsigned char *string1 = (unsigned char *) string1_arg;
- unsigned char *string2 = (unsigned char *) string2_arg;
- unsigned char *end1; /* Just past end of first string. */
- unsigned char *end2; /* Just past end of second string. */
+ /* Just past the end of the corresponding string. */
+ const char *end1, *end2;
/* Pointers into string1 and string2, just past the last characters in
each to consider matching. */
- unsigned char *end_match_1, *end_match_2;
-
- register unsigned char *d, *dend;
- register int mcnt; /* Multipurpose. */
- unsigned char *translate = (unsigned char *) pbufp->translate;
- unsigned is_a_jump_n = 0;
-
- /* Failure point stack. Each place that can handle a failure further
- down the line pushes a failure point on this stack. It consists of
- restart, regend, and reg_info for all registers corresponding to the
- subexpressions we're currently inside, plus the number of such
- registers, and, finally, two char *'s. The first char * is where to
- resume scanning the pattern; the second one is where to resume
- scanning the strings. If the latter is zero, the failure point is a
- ``dummy''; if a failure happens and the failure point is a dummy, it
- gets discarded and the next next one is tried. */
-
-#ifndef NO_ALLOCA
- unsigned char *initial_stack[MAX_NUM_FAILURE_ITEMS * NFAILURES];
+ const char *end_match_1, *end_match_2;
+
+ /* Where we are in the data, and the end of the current string. */
+ const char *d, *dend;
+
+ /* Where we are in the pattern, and the end of the pattern. */
+ unsigned char *p = bufp->buffer;
+ register unsigned char *pend = p + bufp->used;
+
+ /* We use this to map every character in the string. */
+ char *translate = bufp->translate;
+
+ /* Failure point stack. Each place that can handle a failure further
+ down the line pushes a failure point on this stack. It consists of
+ restart, regend, and reg_info for all registers corresponding to
+ the subexpressions we're currently inside, plus the number of such
+ registers, and, finally, two char *'s. The first char * is where
+ to resume scanning the pattern; the second one is where to resume
+ scanning the strings. If the latter is zero, the failure point is
+ a ``dummy''; if a failure happens and the failure point is a dummy,
+ it gets discarded and the next next one is tried. */
+ fail_stack_type fail_stack;
+#ifdef DEBUG
+ static unsigned failure_id = 0;
+ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
#endif
- unsigned char **stackb;
- unsigned char **stackp;
- unsigned char **stacke;
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ an element for register zero. */
+ size_t num_regs = bufp->re_nsub + 1;
+
+ /* The currently active registers. */
+ active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
/* Information on the contents of registers. These are pointers into
the input strings; they record just what was matched (on this
@@ -1949,9 +3329,14 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
matching and the regnum-th regend points to right after where we
stopped matching the regnum-th subexpression. (The zeroth register
keeps track of what the whole pattern matches.) */
-
- unsigned char *regstart[RE_NREGS];
- unsigned char *regend[RE_NREGS];
+ const char **regstart = 0, **regend = 0;
+
+ /* If a group that's operated upon by a repetition operator fails to
+ match anything, then the register for its start will need to be
+ restored because it will have been set to wherever in the string we
+ are when we last see its open-group operator. Similarly for a
+ register's end. */
+ const char **old_regstart = 0, **old_regend = 0;
/* The is_active field of reg_info helps us keep track of which (possibly
nested) subexpressions we are currently in. The matched_something
@@ -1959,50 +3344,97 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
matched any of the pattern so far this time through the reg_num-th
subexpression. These two fields get reset each time through any
loop their register is in. */
-
- struct register_info reg_info[RE_NREGS];
-
+ register_info_type *reg_info = 0;
/* The following record the register info as found in the above
variables when we find a match better than any we've seen before.
This happens as we backtrack through the failure points, which in
- turn happens only if we have not yet matched the entire string. */
-
- unsigned best_regs_set = 0;
- unsigned char *best_regstart[RE_NREGS];
- unsigned char *best_regend[RE_NREGS];
-
- /* Initialize the stack. */
-#ifdef NO_ALLOCA
- stackb = (unsigned char **) malloc (MAX_NUM_FAILURE_ITEMS * NFAILURES * sizeof (char *));
-#else
- stackb = initial_stack;
+ turn happens only if we have not yet matched the entire string. */
+ unsigned best_regs_set = false;
+ const char **best_regstart = 0, **best_regend = 0;
+
+ /* Logically, this is `best_regend[0]'. But we don't want to have to
+ allocate space for that if we're not allocating space for anything
+ else (see below). Also, we never need info about register 0 for
+ any of the other register vectors, and it seems rather a kludge to
+ treat `best_regend' differently than the rest. So we keep track of
+ the end of the best match so far in a separate variable. We
+ initialize this to NULL so that when we backtrack the first time
+ and need to test it, it's not garbage. */
+ const char *match_end = NULL;
+
+ /* Used when we pop values we don't care about. */
+ const char **reg_dummy = 0;
+ register_info_type *reg_info_dummy = 0;
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
#endif
- stackp = stackb;
- stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES];
-#ifdef DEBUG_REGEX
- fprintf (stderr, "Entering re_match_2(%s%s)\n", string1_arg, string2_arg);
-#endif
+ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+ INIT_FAIL_STACK ();
+
+ /* Do not bother to initialize all the register variables if there are
+ no groups in the pattern, as it takes a fair amount of time. If
+ there are groups, we include space for register 0 (the whole
+ pattern), even though we never use it, since it simplifies the
+ array indexing. We should fix this. */
+ if (bufp->re_nsub)
+ {
+ regstart = REGEX_TALLOC (num_regs, const char *);
+ regend = REGEX_TALLOC (num_regs, const char *);
+ old_regstart = REGEX_TALLOC (num_regs, const char *);
+ old_regend = REGEX_TALLOC (num_regs, const char *);
+ best_regstart = REGEX_TALLOC (num_regs, const char *);
+ best_regend = REGEX_TALLOC (num_regs, const char *);
+ reg_info = REGEX_TALLOC (num_regs, register_info_type);
+ reg_dummy = REGEX_TALLOC (num_regs, const char *);
+ reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+ if (!(regstart && regend && old_regstart && old_regend && reg_info
+ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+#ifdef REGEX_MALLOC
+ else
+ {
+ /* We must initialize all our variables to NULL, so that
+ `FREE_VARIABLES' doesn't try to free them. */
+ regstart = regend = old_regstart = old_regend = best_regstart
+ = best_regend = reg_dummy = NULL;
+ reg_info = reg_info_dummy = (register_info_type *) NULL;
+ }
+#endif /* REGEX_MALLOC */
+ /* The starting position is bogus. */
+ if (pos < 0 || pos > size1 + size2)
+ {
+ FREE_VARIABLES ();
+ return -1;
+ }
+
/* Initialize subexpression text positions to -1 to mark ones that no
- \( or ( and \) or ) has been seen for. Also set all registers to
- inactive and mark them as not having matched anything or ever
- failed. */
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
+ start_memory/stop_memory has been seen for. Also initialize the
+ register information struct. */
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
{
- regstart[mcnt] = regend[mcnt] = (unsigned char *) (-1L);
+ regstart[mcnt] = regend[mcnt]
+ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
IS_ACTIVE (reg_info[mcnt]) = 0;
MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
}
- if (regs)
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
- regs->start[mcnt] = regs->end[mcnt] = -1;
-
- /* Set up pointers to ends of strings.
- Don't allow the second string to be empty unless both are empty. */
- if (size2 == 0)
+ /* We move `string1' into `string2' if the latter's empty -- but not if
+ `string1' is null. */
+ if (size2 == 0 && string1 != NULL)
{
string2 = string1;
size2 = size1;
@@ -2013,66 +3445,73 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
end2 = string2 + size2;
/* Compute where to stop matching, within the two strings. */
- if (mstop <= size1)
+ if (stop <= size1)
{
- end_match_1 = string1 + mstop;
+ end_match_1 = string1 + stop;
end_match_2 = string2;
}
else
{
end_match_1 = end1;
- end_match_2 = string2 + mstop - size1;
+ end_match_2 = string2 + stop - size1;
}
- /* `p' scans through the pattern as `d' scans through the data. `dend'
- is the end of the input string that `d' points within. `d' is
- advanced into the following input string whenever necessary, but
+ /* `p' scans through the pattern as `d' scans through the data.
+ `dend' is the end of the input string that `d' points within. `d'
+ is advanced into the following input string whenever necessary, but
this happens before fetching; therefore, at the beginning of the
loop, `d' can be pointing at the end of a string, but it cannot
- equal string2. */
-
- if (size1 != 0 && pos <= size1)
- d = string1 + pos, dend = end_match_1;
+ equal `string2'. */
+ if (size1 > 0 && pos <= size1)
+ {
+ d = string1 + pos;
+ dend = end_match_1;
+ }
else
- d = string2 + pos - size1, dend = end_match_2;
-
+ {
+ d = string2 + pos - size1;
+ dend = end_match_2;
+ }
+ DEBUG_PRINT1 ("The compiled pattern is: ");
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+ DEBUG_PRINT1 ("The string to match is: `");
+ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+ DEBUG_PRINT1 ("'\n");
+
/* This loops over pattern commands. It exits by returning from the
- function if match is complete, or it drops through if match fails
- at this starting point in the input data. */
-
- while (1)
+ function if the match is complete, or it drops through if the match
+ fails at this starting point in the input data. */
+ for (;;)
{
-#ifdef DEBUG_REGEX
- fprintf (stderr,
- "regex loop(%d): matching 0x%02d\n",
- p - (unsigned char *) pbufp->buffer,
- *p);
-#endif
- is_a_jump_n = 0;
- /* End of pattern means we might have succeeded. */
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+
if (p == pend)
- {
- /* If not end of string, try backtracking. Otherwise done. */
+ { /* End of pattern means we might have succeeded. */
+ DEBUG_PRINT1 ("end of pattern ... ");
+
+ /* If we haven't matched the entire string, and we want the
+ longest match, try backtracking. */
if (d != end_match_2)
{
- if (stackp != stackb)
- {
- /* More failure points to try. */
-
- unsigned in_same_string =
- IS_IN_FIRST_STRING (best_regend[0])
- == MATCHING_IN_FIRST_STRING;
+ DEBUG_PRINT1 ("backtracking.\n");
+
+ if (!FAIL_STACK_EMPTY ())
+ { /* More failure points to try. */
+ boolean same_str_p = (FIRST_STRING_P (match_end)
+ == MATCHING_IN_FIRST_STRING);
/* If exceeds best match so far, save it. */
- if (! best_regs_set
- || (in_same_string && d > best_regend[0])
- || (! in_same_string && ! MATCHING_IN_FIRST_STRING))
+ if (!best_regs_set
+ || (same_str_p && d > match_end)
+ || (!same_str_p && !MATCHING_IN_FIRST_STRING))
{
- best_regs_set = 1;
- best_regend[0] = d; /* Never use regstart[0]. */
+ best_regs_set = true;
+ match_end = d;
- for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
{
best_regstart[mcnt] = regstart[mcnt];
best_regend[mcnt] = regend[mcnt];
@@ -2080,123 +3519,395 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
}
goto fail;
}
+
/* If no failure points, don't restore garbage. */
else if (best_regs_set)
{
- restore_best_regs:
- /* Restore best match. */
- d = best_regend[0];
+ restore_best_regs:
+ /* Restore best match. It may happen that `dend ==
+ end_match_1' while the restored d is in string2.
+ For example, the pattern `x.*y.*z' against the
+ strings `x-' and `y-z-', if the two strings are
+ not consecutive in memory. */
+ DEBUG_PRINT1 ("Restoring best registers.\n");
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
+ d = match_end;
+ dend = ((d >= string1 && d <= end1)
+ ? end_match_1 : end_match_2);
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
{
regstart[mcnt] = best_regstart[mcnt];
regend[mcnt] = best_regend[mcnt];
}
}
- }
+ } /* d != end_match_2 */
+
+ DEBUG_PRINT1 ("Accepting match.\n");
- /* If caller wants register contents data back, convert it
- to indices. */
- if (regs)
+ /* If caller wants register contents data back, do it. */
+ if (regs && !bufp->no_sub)
{
- regs->start[0] = pos;
- if (MATCHING_IN_FIRST_STRING)
- regs->end[0] = d - string1;
- else
- regs->end[0] = d - string2 + size1;
- for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ /* Have the register data arrays been allocated? */
+ if (bufp->regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. We need one
+ extra element beyond `num_regs' for the `-1' marker
+ GNU code uses. */
+ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+ regs->start = TALLOC (regs->num_regs, regoff_t);
+ regs->end = TALLOC (regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ return -2;
+ bufp->regs_allocated = REGS_REALLOCATE;
+ }
+ else if (bufp->regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (regs->num_regs < num_regs + 1)
+ {
+ regs->num_regs = num_regs + 1;
+ RETALLOC (regs->start, regs->num_regs, regoff_t);
+ RETALLOC (regs->end, regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ return -2;
+ }
+ }
+ else
{
- if (regend[mcnt] == (unsigned char *)(-1L))
- {
- regs->start[mcnt] = -1;
- regs->end[mcnt] = -1;
- continue;
- }
- if (IS_IN_FIRST_STRING (regstart[mcnt]))
- regs->start[mcnt] = regstart[mcnt] - string1;
- else
- regs->start[mcnt] = regstart[mcnt] - string2 + size1;
-
- if (IS_IN_FIRST_STRING (regend[mcnt]))
- regs->end[mcnt] = regend[mcnt] - string1;
- else
- regs->end[mcnt] = regend[mcnt] - string2 + size1;
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ assert (bufp->regs_allocated == REGS_FIXED);
}
- }
- FREE_AND_RETURN(stackb,
- (d - pos - (MATCHING_IN_FIRST_STRING ?
- string1 :
- string2 - size1)));
+
+ /* Convert the pointer data in `regstart' and `regend' to
+ indices. Register zero has to be set differently,
+ since we haven't kept track of any info for it. */
+ if (regs->num_regs > 0)
+ {
+ regs->start[0] = pos;
+ regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
+ : d - string2 + size1);
+ }
+
+ /* Go through the first `min (num_regs, regs->num_regs)'
+ registers, since that is all we initialized. */
+ for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+ {
+ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ else
+ {
+ regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
+ regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
+ }
+ }
+
+ /* If the regs structure we return has more elements than
+ were in the pattern, set the extra elements to -1. If
+ we (re)allocated the registers, this is the case,
+ because we always allocate enough to have at least one
+ -1 at the end. */
+ for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ } /* regs && !bufp->no_sub */
+
+ FREE_VARIABLES ();
+ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+ nfailure_points_pushed, nfailure_points_popped,
+ nfailure_points_pushed - nfailure_points_popped);
+ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+ ? string1
+ : string2 - size1);
+
+ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+ return mcnt;
}
/* Otherwise match next pattern command. */
#ifdef SWITCH_ENUM_BUG
- switch ((int) ((enum regexpcode) *p++))
+ switch ((int) ((re_opcode_t) *p++))
#else
- switch ((enum regexpcode) *p++)
+ switch ((re_opcode_t) *p++)
#endif
{
+ /* Ignore these. Used to ignore the n of succeed_n's which
+ currently have n == 0. */
+ case no_op:
+ DEBUG_PRINT1 ("EXECUTING no_op.\n");
+ break;
+
+
+ /* Match the next n pattern characters exactly. The following
+ byte in the pattern defines n, and the n bytes after that
+ are the characters to match. */
+ case exactn:
+ mcnt = *p++;
+ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+ /* This is written out as an if-else so we don't waste time
+ testing `translate' inside the loop. */
+ if (translate)
+ {
+ do
+ {
+ PREFETCH ();
+ if (translate[(unsigned char) *d++] != (char) *p++)
+ goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH ();
+ if (*d++ != (char) *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ SET_REGS_MATCHED ();
+ break;
+
+
+ /* Match any character except possibly a newline or a null. */
+ case anychar:
+ DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+ PREFETCH ();
+
+ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+ goto fail;
+
+ SET_REGS_MATCHED ();
+ DEBUG_PRINT2 (" Matched `%d'.\n", *d);
+ d++;
+ break;
+
+
+ case charset:
+ case charset_not:
+ {
+ register unsigned char c;
+ boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+ DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+ PREFETCH ();
+ c = TRANSLATE (*d); /* The character to match. */
+
+ /* Cast to `unsigned' instead of `unsigned char' in case the
+ bit list is a full 32 bytes long. */
+ if (c < (unsigned) (*p * BYTEWIDTH)
+ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) goto fail;
+
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+ }
+
+
+ /* The beginning of a group is represented by start_memory.
+ The arguments are the register number in the next byte, and the
+ number of groups inner to this one in the next. The text
+ matched within the group is recorded (in the internal
+ registers data structure) under the register number. */
+ case start_memory:
+ DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+ /* Find out if this group can match the empty string. */
+ p1 = p; /* To send to group_match_null_string_p. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[*p])
+ = group_match_null_string_p (&p1, pend, reg_info);
+
+ /* Save the position in the string where we were the last time
+ we were at this open-group operator in case the group is
+ operated upon by a repetition operator, e.g., with `(a*)*b'
+ against `ab'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+ : regstart[*p];
+ DEBUG_PRINT2 (" old_regstart: %d\n",
+ POINTER_TO_OFFSET (old_regstart[*p]));
- /* \( [or `(', as appropriate] is represented by start_memory,
- \) by stop_memory. Both of those commands are followed by
- a register number in the next byte. The text matched
- within the \( and \) is recorded under that number. */
- case start_memory:
regstart[*p] = d;
+ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
IS_ACTIVE (reg_info[*p]) = 1;
MATCHED_SOMETHING (reg_info[*p]) = 0;
- p++;
+
+ /* This is the new highest active register. */
+ highest_active_reg = *p;
+
+ /* If nothing was active before, this is the new lowest active
+ register. */
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *p;
+
+ /* Move past the register number and inner group count. */
+ p += 2;
break;
+
+ /* The stop_memory opcode represents the end of a group. Its
+ arguments are the same as start_memory's: the register
+ number, and the number of inner groups. */
case stop_memory:
+ DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+ /* We need to save the string position the last time we were at
+ this close-group operator in case the group is operated
+ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+ against `aba'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regend[*p]) ? d : regend[*p]
+ : regend[*p];
+ DEBUG_PRINT2 (" old_regend: %d\n",
+ POINTER_TO_OFFSET (old_regend[*p]));
+
regend[*p] = d;
- IS_ACTIVE (reg_info[*p]) = 0;
+ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
- /* If just failed to match something this time around with a sub-
- expression that's in a loop, try to force exit from the loop. */
- if ((! MATCHED_SOMETHING (reg_info[*p])
- || (enum regexpcode) p[-3] == start_memory)
- && (p + 1) != pend)
+ /* This register isn't active anymore. */
+ IS_ACTIVE (reg_info[*p]) = 0;
+
+ /* If this was the only register active, nothing is active
+ anymore. */
+ if (lowest_active_reg == highest_active_reg)
{
- register unsigned char *p2 = p + 1;
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ { /* We must scan for the new highest active register, since
+ it isn't necessarily one less than now: consider
+ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
+ new highest active register is 1. */
+ unsigned char r = *p - 1;
+ while (r > 0 && !IS_ACTIVE (reg_info[r]))
+ r--;
+
+ /* If we end up at register zero, that means that we saved
+ the registers as the result of an `on_failure_jump', not
+ a `start_memory', and we jumped to past the innermost
+ `stop_memory'. For example, in ((.)*) we save
+ registers 1 and 2 as a result of the *, but when we pop
+ back to the second ), we are at the stop_memory 1.
+ Thus, nothing is active. */
+ if (r == 0)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ highest_active_reg = r;
+ }
+
+ /* If just failed to match something this time around with a
+ group that's operated on by a repetition operator, try to
+ force exit from the ``loop'', and restore the register
+ information for this group that we had before trying this
+ last match. */
+ if ((!MATCHED_SOMETHING (reg_info[*p])
+ || (re_opcode_t) p[-3] == start_memory)
+ && (p + 2) < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ p1 = p + 2;
mcnt = 0;
- switch (*p2++)
+ switch ((re_opcode_t) *p1++)
{
case jump_n:
- is_a_jump_n = 1;
- case finalize_jump:
- case maybe_finalize_jump:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
case jump:
case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
if (is_a_jump_n)
- p2 += 2;
+ p1 += 2;
break;
+
+ default:
+ /* do nothing */ ;
}
- p2 += mcnt;
+ p1 += mcnt;
/* If the next operation is a jump backwards in the pattern
- to an on_failure_jump, exit from the loop by forcing a
- failure after pushing on the stack the on_failure_jump's
- jump in the pattern, and d. */
- if (mcnt < 0 && (enum regexpcode) *p2++ == on_failure_jump)
+ to an on_failure_jump right before the start_memory
+ corresponding to this stop_memory, exit from the loop
+ by forcing a failure after pushing on the stack the
+ on_failure_jump's jump in the pattern, and d. */
+ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+ && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
{
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
- PUSH_FAILURE_POINT (p2 + mcnt, d);
+ /* If this group ever matched anything, then restore
+ what its registers were before trying this last
+ failed match, e.g., with `(a*)*b' against `ab' for
+ regstart[1], and, e.g., with `((a*)*(b*)*)*'
+ against `aba' for regend[3].
+
+ Also restore the registers for inner groups for,
+ e.g., `((a*)(b*))*' against `aba' (register 3 would
+ otherwise get trashed). */
+
+ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+ {
+ unsigned r;
+
+ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Restore this and inner groups' (if any) registers. */
+ for (r = *p; r < *p + *(p + 1); r++)
+ {
+ regstart[r] = old_regstart[r];
+
+ /* xx why this test? */
+ if ((s_reg_t) old_regend[r] >= (s_reg_t) regstart[r])
+ regend[r] = old_regend[r];
+ }
+ }
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+ PUSH_FAILURE_POINT2(p1 + mcnt, d, -2);
+
goto fail;
}
}
- p++;
+
+ /* Move past the register number and the inner group count. */
+ p += 2;
break;
+
/* \<digit> has been turned into a `duplicate' command which is
followed by the numeric value of <digit> as the register number. */
case duplicate:
{
- int regno = *p++; /* Get which register to match against */
- register unsigned char *d2, *dend2;
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
- /* Where in input to try to start matching. */
+ /* Can't back reference a group which we've never matched. */
+ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+ goto fail;
+
+ /* Where in input to try to start matching. */
d2 = regstart[regno];
/* Where to stop matching; if both the place to start and
@@ -2204,10 +3915,10 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
set to the place to stop, otherwise, for now have to use
the end of the first string. */
- dend2 = ((IS_IN_FIRST_STRING (regstart[regno])
- == IS_IN_FIRST_STRING (regend[regno]))
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
? regend[regno] : end_match_1);
- while (1)
+ for (;;)
{
/* If necessary, advance to next segment in register
contents. */
@@ -2215,13 +3926,16 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
{
if (dend2 == end_match_2) break;
if (dend2 == regend[regno]) break;
- d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */
+
+ /* End of string1 => advance to string2. */
+ d2 = string2;
+ dend2 = regend[regno];
}
/* At end of register contents => success */
if (d2 == dend2) break;
/* If necessary, advance to next segment in data. */
- PREFETCH;
+ PREFETCH ();
/* How many characters left in this segment to match. */
mcnt = dend - d;
@@ -2234,196 +3948,335 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
/* Compare that many; failure if mismatch, else move
past them. */
if (translate
- ? memcmp_translate (d, d2, mcnt, translate)
- : memcmp ((char *)d, (char *)d2, mcnt))
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : bcmp (d, d2, mcnt))
goto fail;
d += mcnt, d2 += mcnt;
}
}
break;
- case anychar:
- PREFETCH; /* Fetch a data character. */
- /* Match anything but a newline, maybe even a null. */
- if ((translate ? translate[*d] : *d) == '\n'
- || ((obscure_syntax & RE_DOT_NOT_NULL)
- && (translate ? translate[*d] : *d) == '\000'))
- goto fail;
- SET_REGS_MATCHED;
- d++;
- break;
- case charset:
- case charset_not:
- {
- int not = 0; /* Nonzero for charset_not. */
- register int c;
- if (*(p - 1) == (unsigned char) charset_not)
- not = 1;
-
- PREFETCH; /* Fetch a data character. */
+ /* begline matches the empty string at the beginning of the string
+ (unless `not_bol' is set in `bufp'), and, if
+ `newline_anchor' is set, after newlines. */
+ case begline:
+ DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+ if (AT_STRINGS_BEG (d))
+ {
+ if (!bufp->not_bol) break;
+ }
+ else if (d[-1] == '\n' && bufp->newline_anchor)
+ {
+ break;
+ }
+ /* In all other cases, we fail. */
+ goto fail;
- if (translate)
- c = translate[*d];
- else
- c = *d;
- if (c < *p * BYTEWIDTH
- && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
- p += 1 + *p;
+ if (AT_STRINGS_END (d))
+ {
+ if (!bufp->not_eol) break;
+ }
+
+ /* We have to ``prefetch'' the next character. */
+ else if ((d == end1 ? *string2 : *d) == '\n'
+ && bufp->newline_anchor)
+ {
+ break;
+ }
+ goto fail;
- if (!not) goto fail;
- SET_REGS_MATCHED;
- d++;
- break;
- }
- case begline:
- if ((size1 != 0 && d == string1)
- || (size1 == 0 && size2 != 0 && d == string2)
- || (d && d[-1] == '\n')
- || (size1 == 0 && size2 == 0))
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
break;
- else
- goto fail;
-
- case endline:
- if (d == end2
- || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END (d))
break;
- goto fail;
+ goto fail;
- /* `or' constructs are handled by starting each alternative with
- an on_failure_jump that points to the start of the next
- alternative. Each alternative except the last ends with a
- jump to the joining point. (Actually, each jump except for
- the last one really jumps to the following jump, because
- tensioning the jumps is a hassle.) */
- /* The start of a stupid repeat has an on_failure_jump that points
- past the end of the repeat text. This makes a failure point so
- that on failure to match a repetition, matching restarts past
- as many repetitions have been found with no way to fail and
- look for another one. */
+ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
+ pushes NULL as the value for the string on the stack. Then
+ `pop_failure_point' will keep the current value for the
+ string, instead of restoring it. To see why, consider
+ matching `foo\nbar' against `.*\n'. The .* matches the foo;
+ then the . fails against the \n. But the next thing we want
+ to do is match the \n against the \n; if we restored the
+ string value, we would be back at the foo.
+
+ Because this is used only in specific cases, we don't need to
+ check all the things that `on_failure_jump' does, to make
+ sure the right things get saved on the stack. Hence we don't
+ share its code. The only reason to push anything on the
+ stack at all is that otherwise we would have to change
+ `anychar's code to do something besides goto fail in this
+ case; that seems worse than this. */
+ case on_failure_keep_string_jump:
+ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+ PUSH_FAILURE_POINT2(p + mcnt, NULL, -2);
+ break;
- /* A smart repeat is similar but loops back to the on_failure_jump
- so that each repetition makes another failure point. */
+ /* Uses of on_failure_jump:
+
+ Each alternative starts with an on_failure_jump that points
+ to the beginning of the next alternative. Each alternative
+ except the last ends with a jump that in effect jumps past
+ the rest of the alternatives. (They really jump to the
+ ending jump of the following alternative, because tensioning
+ these jumps is a hassle.)
+
+ Repeats start with an on_failure_jump that points past both
+ the repetition text and either the following jump or
+ pop_failure_jump back to this on_failure_jump. */
case on_failure_jump:
on_failure:
+ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
EXTRACT_NUMBER_AND_INCR (mcnt, p);
- PUSH_FAILURE_POINT (p + mcnt, d);
+ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+ /* If this on_failure_jump comes right before a group (i.e.,
+ the original * applied to a group), save the information
+ for that group and all inner ones, so that if we fail back
+ to this point, the group's information will be correct.
+ For example, in \(a*\)*\1, we need the preceding group,
+ and in \(\(a*\)b*\)\2, we need the inner group. */
+
+ /* We can't use `p' to check ahead because we push
+ a failure point to `p + mcnt' after we do this. */
+ p1 = p;
+
+ /* We need to skip no_op's before we look for the
+ start_memory in case this on_failure_jump is happening as
+ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+ against aba. */
+ while (p1 < pend && (re_opcode_t) *p1 == no_op)
+ p1++;
+
+ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+ {
+ /* We have a new highest active register now. This will
+ get reset at the start_memory we are about to get to,
+ but we will have saved all the registers relevant to
+ this repetition op, as described above. */
+ highest_active_reg = *(p1 + 1) + *(p1 + 2);
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *(p1 + 1);
+ }
+
+ DEBUG_PRINT1 (":\n");
+ PUSH_FAILURE_POINT (p + mcnt, d, -2);
+ PUSH_FAILURE_POINT2(p + mcnt, d, -2);
break;
- /* The end of a smart repeat has a maybe_finalize_jump back.
- Change it either to a finalize_jump or an ordinary jump. */
- case maybe_finalize_jump:
+
+ /* A smart repeat ends with `maybe_pop_jump'.
+ We change it to either `pop_failure_jump' or `jump'. */
+ case maybe_pop_jump:
EXTRACT_NUMBER_AND_INCR (mcnt, p);
- {
+ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+ {
register unsigned char *p2 = p;
- /* Compare what follows with the beginning of the repeat.
- If we can establish that there is nothing that they would
- both match, we can change to finalize_jump. */
- while (p2 + 1 != pend
- && (*p2 == (unsigned char) stop_memory
- || *p2 == (unsigned char) start_memory))
- p2 += 2; /* Skip over reg number. */
- if (p2 == pend)
- p[-3] = (unsigned char) finalize_jump;
- else if (*p2 == (unsigned char) exactn
- || *p2 == (unsigned char) endline)
+
+ /* Compare the beginning of the repeat with what in the
+ pattern follows its end. If we can establish that there
+ is nothing that they would both match, i.e., that we
+ would have to backtrack because of (as in, e.g., `a*a')
+ then we can change to pop_failure_jump, because we'll
+ never have to backtrack.
+
+ This is not true in the case of alternatives: in
+ `(a|ab)*' we do need to backtrack to the `ab' alternative
+ (e.g., if the string was `ab'). But instead of trying to
+ detect that here, the alternative has put on a dummy
+ failure point which is what we will end up popping. */
+
+ /* Skip over open/close-group commands. */
+ while (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3; /* Skip over args, too. */
+
+ /* If we're at the end of the pattern, we can change. */
+ if (p2 == pend)
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
+ }
+
+ else if ((re_opcode_t) *p2 == exactn
+ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
{
- register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
- register unsigned char *p1 = p + mcnt;
- /* p1[0] ... p1[2] are an on_failure_jump.
- Examine what follows that. */
- if (p1[3] == (unsigned char) exactn && p1[5] != c)
- p[-3] = (unsigned char) finalize_jump;
- else if (p1[3] == (unsigned char) charset
- || p1[3] == (unsigned char) charset_not)
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+ p1 = p + mcnt;
+
+ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+ to the `maybe_finalize_jump' of this case. Examine what
+ follows. */
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset
+ || (re_opcode_t) p1[3] == charset_not)
{
- int not = p1[3] == (unsigned char) charset_not;
- if (c < p1[4] * BYTEWIDTH
+ int not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned char) (p1[4] * BYTEWIDTH)
&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
not = !not;
- /* `not' is 1 if c would match. */
- /* That means it is not safe to finalize. */
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
if (!not)
- p[-3] = (unsigned char) finalize_jump;
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
}
}
}
p -= 2; /* Point at relative address again. */
- if (p[-1] != (unsigned char) finalize_jump)
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
{
- p[-1] = (unsigned char) jump;
- goto nofinalize;
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
}
/* Note fall through. */
- /* The end of a stupid repeat has a finalize_jump back to the
- start, where another failure point will be made which will
- point to after all the repetitions found so far. */
- /* Take off failure points put on by matching on_failure_jump
- because didn't fail. Also remove the register information
- put on by the on_failure_jump. */
- case finalize_jump:
- POP_FAILURE_POINT ();
- /* Note fall through. */
-
- /* Jump without taking off any failure points. */
+ /* The end of a simple repeat has a pop_failure_jump back to
+ its matching on_failure_jump, where the latter will push a
+ failure point. The pop_failure_jump takes off failure
+ points put on by this pop_failure_jump's matching
+ on_failure_jump; we got through the pattern to here from the
+ matching on_failure_jump, so didn't fail. */
+ case pop_failure_jump:
+ {
+ /* We need to pass separate storage for the lowest and
+ highest registers, even though we don't care about the
+ actual values. Otherwise, we will restore only one
+ register from the stack, since lowest will == highest in
+ `pop_failure_point'. */
+ active_reg_t dummy_low_reg, dummy_high_reg;
+ unsigned char *pdummy;
+ const char *sdummy;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ POP_FAILURE_POINT (sdummy, pdummy,
+ dummy_low_reg, dummy_high_reg,
+ reg_dummy, reg_dummy, reg_info_dummy);
+ }
+ /* Note fall through. */
+
+
+ /* Unconditionally jump (without popping any failure points). */
case jump:
- nofinalize:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- p += mcnt;
+ unconditional_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+ p += mcnt; /* Do the jump. */
+ DEBUG_PRINT2 ("(to 0x%x).\n", p);
break;
- case dummy_failure_jump:
- /* Normally, the on_failure_jump pushes a failure point, which
- then gets popped at finalize_jump. We will end up at
- finalize_jump, also, and with a pattern of, say, `a+', we
- are skipping over the on_failure_jump, so we have to push
- something meaningless for finalize_jump to pop. */
- PUSH_FAILURE_POINT (0, 0);
- goto nofinalize;
+
+ /* We need this opcode so we can detect where alternatives end
+ in `group_match_null_string_p' et al. */
+ case jump_past_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+ goto unconditional_jump;
+
+ /* Normally, the on_failure_jump pushes a failure point, which
+ then gets popped at pop_failure_jump. We will end up at
+ pop_failure_jump, also, and with a pattern of, say, `a+', we
+ are skipping over the on_failure_jump, so we have to push
+ something meaningless for pop_failure_jump to pop. */
+ case dummy_failure_jump:
+ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+ /* It doesn't matter what we push for the string here. What
+ the code at `fail' tests is the value for the pattern. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ PUSH_FAILURE_POINT2(0, 0, -2);
+ goto unconditional_jump;
+
+
+ /* At the end of an alternative, we need to push a dummy failure
+ point in case we are followed by a `pop_failure_jump', because
+ we don't want the failure point for the alternative to be
+ popped. For example, matching `(a|ab)*' against `aab'
+ requires that we match the `ab' alternative. */
+ case push_dummy_failure:
+ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+ /* See comments just above at `dummy_failure_jump' about the
+ two zeroes. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ PUSH_FAILURE_POINT2(0, 0, -2);
+ break;
- /* Have to succeed matching what follows at least n times. Then
- just handle like an on_failure_jump. */
+ /* Have to succeed matching what follows at least n times.
+ After that, handle like `on_failure_jump'. */
case succeed_n:
EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ assert (mcnt >= 0);
/* Originally, this is how many times we HAVE to succeed. */
- if (mcnt)
+ if (mcnt > 0)
{
mcnt--;
p += 2;
STORE_NUMBER_AND_INCR (p, mcnt);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
}
else if (mcnt == 0)
{
- p[2] = unused;
- p[3] = unused;
+ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
+ p[2] = (unsigned char) no_op;
+ p[3] = (unsigned char) no_op;
goto on_failure;
}
- else
- {
- fprintf (stderr, "regex: the succeed_n's n is not set.\n");
- exit (1);
- }
break;
case jump_n:
EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
/* Originally, this is how many times we CAN jump. */
if (mcnt)
{
mcnt--;
- STORE_NUMBER(p + 2, mcnt);
- goto nofinalize; /* Do the jump without taking off
- any failure points. */
+ STORE_NUMBER (p + 2, mcnt);
+ goto unconditional_jump;
}
/* If don't have to jump any more, skip over the rest of command. */
else
@@ -2432,223 +4285,494 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
case set_number_at:
{
- register unsigned char *p1;
+ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
EXTRACT_NUMBER_AND_INCR (mcnt, p);
p1 = p + mcnt;
EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
STORE_NUMBER (p1, mcnt);
break;
}
- /* Ignore these. Used to ignore the n of succeed_n's which
- currently have n == 0. */
- case unused:
- break;
-
case wordbound:
- if (AT_WORD_BOUNDARY)
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
break;
- goto fail;
+ goto fail;
case notwordbound:
- if (AT_WORD_BOUNDARY)
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
goto fail;
- break;
+ break;
case wordbeg:
- if (IS_A_LETTER (d) && (!IS_A_LETTER (d - 1) || AT_STRINGS_BEG))
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
break;
- goto fail;
+ goto fail;
case wordend:
- /* Have to check if AT_STRINGS_BEG before looking at d - 1. */
- if (!AT_STRINGS_BEG && IS_A_LETTER (d - 1)
- && (!IS_A_LETTER (d) || AT_STRINGS_END))
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
break;
- goto fail;
+ goto fail;
#ifdef emacs
- case before_dot:
- if (PTR_CHAR_POS (d) >= point)
- goto fail;
- break;
-
+#ifdef emacs19
+ case before_dot:
+ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) != point)
+ goto fail;
+ break;
+
+ case after_dot:
+ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+ goto fail;
+ break;
+#else /* not emacs19 */
case at_dot:
- if (PTR_CHAR_POS (d) != point)
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
goto fail;
break;
-
- case after_dot:
- if (PTR_CHAR_POS (d) <= point)
- goto fail;
- break;
-
- case wordchar:
- mcnt = (int) Sword;
- goto matchsyntax;
+#endif /* not emacs19 */
case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
mcnt = *p++;
- matchsyntax:
- PREFETCH;
- if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
- break;
-
- case notwordchar:
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
mcnt = (int) Sword;
- goto matchnotsyntax;
+ matchsyntax:
+ PREFETCH ();
+ if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
case notsyntaxspec:
+ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
mcnt = *p++;
- matchnotsyntax:
- PREFETCH;
- if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
+ goto matchnotsyntax;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax:
+ PREFETCH ();
+ if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
break;
#else /* not emacs */
-
case wordchar:
- PREFETCH;
- if (!IS_A_LETTER (d))
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
goto fail;
- SET_REGS_MATCHED;
+ SET_REGS_MATCHED ();
+ d++;
break;
case notwordchar:
- PREFETCH;
- if (IS_A_LETTER (d))
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
goto fail;
- SET_REGS_MATCHED;
- break;
-
- case before_dot:
- case at_dot:
- case after_dot:
- case syntaxspec:
- case notsyntaxspec:
+ SET_REGS_MATCHED ();
+ d++;
break;
-
#endif /* not emacs */
-
- case begbuf:
- if (AT_STRINGS_BEG)
- break;
- goto fail;
-
- case endbuf:
- if (AT_STRINGS_END)
- break;
- goto fail;
-
- case exactn:
- /* Match the next few pattern characters exactly.
- mcnt is how many characters to match. */
- mcnt = *p++;
- /* This is written out as an if-else so we don't waste time
- testing `translate' inside the loop. */
- if (translate)
- {
- do
- {
- PREFETCH;
- if (translate[*d++] != *p++) goto fail;
- }
- while (--mcnt);
- }
- else
- {
- do
- {
- PREFETCH;
- if (*d++ != *p++) goto fail;
- }
- while (--mcnt);
- }
- SET_REGS_MATCHED;
- break;
+
+ default:
+ abort ();
}
continue; /* Successfully executed one pattern command; keep going. */
- /* Jump here if any matching operation fails. */
+
+ /* We goto here if a matching operation fails. */
fail:
- if (stackp != stackb)
- /* A restart point is known. Restart there and pop it. */
- {
- short last_used_reg, this_reg;
-
- /* If this failure point is from a dummy_failure_point, just
- skip it. */
- if (!stackp[-2])
+ if (!FAIL_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ POP_FAILURE_POINT (d, p,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info);
+
+ /* If this failure point is a dummy, try the next one. */
+ if (!p)
+ goto fail;
+
+ /* If we failed to the end of the pattern, don't examine *p. */
+ assert (p <= pend);
+ if (p < pend)
{
- POP_FAILURE_POINT ();
- goto fail;
+ boolean is_a_jump_n = false;
+
+ /* If failed to a backwards jump that's part of a repetition
+ loop, need to pop this failure point and use the next one. */
+ switch ((re_opcode_t) *p)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case jump:
+ p1 = p + 1;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+
+ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+ || (!is_a_jump_n
+ && (re_opcode_t) *p1 == on_failure_jump))
+ goto fail;
+ break;
+ default:
+ /* do nothing */ ;
+ }
}
- d = *--stackp;
- p = *--stackp;
if (d >= string1 && d <= end1)
dend = end_match_1;
- /* Restore register info. */
- last_used_reg = (long) *--stackp;
-
- /* Make the ones that weren't saved -1 or 0 again. */
- for (this_reg = RE_NREGS - 1; this_reg > last_used_reg; this_reg--)
- {
- regend[this_reg] = (unsigned char *) (-1L);
- regstart[this_reg] = (unsigned char *) (-1L);
- IS_ACTIVE (reg_info[this_reg]) = 0;
- MATCHED_SOMETHING (reg_info[this_reg]) = 0;
- }
-
- /* And restore the rest from the stack. */
- for ( ; this_reg > 0; this_reg--)
- {
- reg_info[this_reg] = *(struct register_info *) *--stackp;
- regend[this_reg] = *--stackp;
- regstart[this_reg] = *--stackp;
- }
- }
+ }
else
break; /* Matching at this starting point really fails. */
- }
+ } /* for (;;) */
if (best_regs_set)
goto restore_best_regs;
- FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */
-}
+ FREE_VARIABLES ();
+
+ return -1; /* Failure to match. */
+} /* re_match_2 */
+
+/* Subroutine definitions for re_match_2. */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+ Return true if the pattern up to the corresponding stop_memory can
+ match the empty string, and false otherwise.
+
+ If we find the matching stop_memory, sets P to point to one past its number.
+ Otherwise, sets P to an undefined byte less than or equal to END.
+
+ We don't handle duplicates properly (yet). */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ /* Point to after the args to the start_memory. */
+ unsigned char *p1 = *p + 2;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and return true or
+ false, as appropriate, when we get to one that can't, or to the
+ matching stop_memory. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* Could be either a loop or a series of alternatives. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ /* If the next operation is not a jump backwards in the
+ pattern. */
+
+ if (mcnt >= 0)
+ {
+ /* Go through the on_failure_jumps of the alternatives,
+ seeing if any of the alternatives cannot match nothing.
+ The last alternative starts with only a jump,
+ whereas the rest start with on_failure_jump and end
+ with a jump, e.g., here is the pattern for `a|b|c':
+
+ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+ /exactn/1/c
+
+ So, we have to first go through the first (n-1)
+ alternatives and then deal with the last one separately. */
+
+
+ /* Deal with the first (n-1) alternatives, which start
+ with an on_failure_jump (see above) that jumps to right
+ past a jump_past_alt. */
+
+ while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+ {
+ /* `mcnt' holds how many bytes long the alternative
+ is, including the ending `jump_past_alt' and
+ its number. */
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+ reg_info))
+ return false;
+
+ /* Move to right after this alternative, including the
+ jump_past_alt. */
+ p1 += mcnt;
+
+ /* Break if it's the beginning of an n-th alternative
+ that doesn't begin with an on_failure_jump. */
+ if ((re_opcode_t) *p1 != on_failure_jump)
+ break;
+
+ /* Still have to check that it's not an n-th
+ alternative that starts with an on_failure_jump. */
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+ {
+ /* Get to the beginning of the n-th alternative. */
+ p1 -= 3;
+ break;
+ }
+ }
+
+ /* Deal with the last alternative: go back and get number
+ of the `jump_past_alt' just before it. `mcnt' contains
+ the length of the alternative. */
+ EXTRACT_NUMBER (mcnt, p1 - 2);
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+ return false;
+
+ p1 += mcnt; /* Get past the n-th alternative. */
+ } /* if mcnt > 0 */
+ break;
+
+
+ case stop_memory:
+ assert (p1[1] == **p);
+ *p = p1 + 2;
+ return true;
+
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+ It expects P to be the first byte of a single alternative and END one
+ byte past the last. The alternative can contain groups. */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+ unsigned char *p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ unsigned char *p1 = p;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and break when we get
+ to one that can't. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* It's a loop. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ break;
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+ alt_match_null_string_p.
+
+ Sets P to one after the op and its arguments, if any. */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ boolean ret;
+ int reg_no;
+ unsigned char *p1 = *p;
+
+ switch ((re_opcode_t) *p1++)
+ {
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+#ifdef emacs
+ case before_dot:
+ case at_dot:
+ case after_dot:
+#endif
+ break;
+
+ case start_memory:
+ reg_no = *p1;
+ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+ ret = group_match_null_string_p (&p1, end, reg_info);
+
+ /* Have to set this here in case we're checking a group which
+ contains a group and a back reference to it. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+ if (!ret)
+ return false;
+ break;
+
+ /* If this is an optimized succeed_n for zero times, make the jump. */
+ case jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (mcnt >= 0)
+ p1 += mcnt;
+ else
+ return false;
+ break;
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p1 += 2;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ if (mcnt == 0)
+ {
+ p1 -= 4;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ }
+ else
+ return false;
+ break;
+
+ case duplicate:
+ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+ return false;
+ break;
+
+ case set_number_at:
+ p1 += 4;
+
+ default:
+ /* All other opcodes mean we cannot match the empty string. */
+ return false;
+ }
+
+ *p = p1;
+ return true;
+} /* common_op_match_null_string_p */
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+ bytes; nonzero otherwise. */
+
static int
-memcmp_translate (s1, s2, len, translate)
- unsigned char *s1, *s2;
+bcmp_translate (s1, s2, len, translate)
+ const char *s1, *s2;
register int len;
- unsigned char *translate;
+ char *translate;
{
- register unsigned char *p1 = s1, *p2 = s2;
+ register const unsigned char *p1 = (const unsigned char *) s1,
+ *p2 = (const unsigned char *) s2;
while (len)
{
- if (translate [*p1++] != translate [*p2++]) return 1;
+ if (translate[*p1++] != translate[*p2++]) return 1;
len--;
}
return 0;
}
+
+/* Entry points for GNU code. */
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length SIZE) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry.
+
+ We call regex_compile to do the actual compilation. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ size_t length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* GNU code is written to assume at least RE_NREGS registers will be set
+ (and at least one extra will be -1). */
+ bufp->regs_allocated = REGS_UNALLOCATED;
+
+ /* 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 no_sub. */
+ bufp->no_sub = 0;
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = regex_compile (pattern, length, re_syntax_options, bufp);
+ return re_error_msg[(int) ret];
+}
-/* Entry points compatible with 4.2 BSD regex library. */
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them if this is an Emacs or POSIX compilation. */
-#if !defined(emacs) && !defined(GAWK)
+#if !defined (emacs) && !defined (_POSIX_SOURCE)
+/* BSD has one and only one pattern buffer. */
static struct re_pattern_buffer re_comp_buf;
char *
re_comp (s)
- char *s;
+ const char *s;
{
+ reg_errcode_t ret;
+
if (!s)
{
if (!re_comp_buf.buffer)
@@ -2658,197 +4782,289 @@ re_comp (s)
if (!re_comp_buf.buffer)
{
- if (!(re_comp_buf.buffer = (char *) malloc (200)))
- return "Memory exhausted";
+ re_comp_buf.buffer = (unsigned char *) malloc (200);
+ if (re_comp_buf.buffer == NULL)
+ return "Memory exhausted";
re_comp_buf.allocated = 200;
- if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
+
+ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+ if (re_comp_buf.fastmap == NULL)
return "Memory exhausted";
}
- return re_compile_pattern (s, strlen (s), &re_comp_buf);
+
+ /* 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.newline_anchor = 1;
+
+ ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+ /* Yes, we're discarding `const' here. */
+ return (char *) re_error_msg[(int) ret];
}
+
int
re_exec (s)
- char *s;
+ const char *s;
{
- int len = strlen (s);
- return 0 <= re_search (&re_comp_buf, s, len, 0, len,
- (struct re_registers *) 0);
+ const int len = strlen (s);
+ return
+ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
}
-#endif /* not emacs && not GAWK */
+#endif /* not emacs and not _POSIX_SOURCE */
+
+/* POSIX.2 functions. Don't define these for Emacs. */
+#ifndef emacs
-
-#ifdef test
+/* regcomp takes a regular expression as a string and compiles it.
-#ifdef atarist
-long _stksize = 2L; /* reserve memory for stack */
-#endif
-#include <stdio.h>
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
-/* Indexed by a character, gives the upper case equivalent of the
- character. */
-
-char upcase[0400] =
- { 000, 001, 002, 003, 004, 005, 006, 007,
- 010, 011, 012, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 024, 025, 026, 027,
- 030, 031, 032, 033, 034, 035, 036, 037,
- 040, 041, 042, 043, 044, 045, 046, 047,
- 050, 051, 052, 053, 054, 055, 056, 057,
- 060, 061, 062, 063, 064, 065, 066, 067,
- 070, 071, 072, 073, 074, 075, 076, 077,
- 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
- 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
- 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
- 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
- 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
- 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
- 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
- 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
- };
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' and `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
-#ifdef canned
+ PATTERN is the address of the pattern string.
-#include "tests.h"
+ CFLAGS is a series of bits which affect compilation.
-typedef enum { extended_test, basic_test } test_type;
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
-/* Use this to run the tests we've thought of. */
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
-void
-main ()
-{
- test_type t = extended_test;
+ 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.) */
- if (t == basic_test)
+int
+regcomp (preg, pattern, cflags)
+ regex_t *preg;
+ const char *pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax
+ = (cflags & REG_EXTENDED) ?
+ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+ /* regex_compile will allocate the space for the compiled pattern. */
+ preg->buffer = 0;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Don't bother to use a fastmap when searching. This simplifies the
+ REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+ characters after newlines into the fastmap. This way, we just try
+ every character. */
+ preg->fastmap = 0;
+
+ if (cflags & REG_ICASE)
{
- printf ("Running basic tests:\n\n");
- test_posix_basic ();
+ unsigned i;
+
+ preg->translate = (char *) malloc (CHAR_SET_SIZE);
+ if (preg->translate == NULL)
+ return (int) REG_ESPACE;
+
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < CHAR_SET_SIZE; i++)
+ preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
}
- else if (t == extended_test)
- {
- printf ("Running extended tests:\n\n");
- test_posix_extended ();
+ else
+ preg->translate = NULL;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
}
+ else
+ preg->newline_anchor = 0;
+
+ preg->no_sub = !!(cflags & REG_NOSUB);
+
+ /* POSIX says a null character in the pattern terminates it, so we
+ can use strlen here in compiling the pattern. */
+ ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+ /* 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;
+
+ return (int) ret;
}
-#else /* not canned */
-/* Use this to run interactive tests. */
+/* 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. */
-void
-main (argc, argv)
- int argc;
- char **argv;
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *preg;
+ const char *string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
{
- char pat[80];
- struct re_pattern_buffer buf;
- int i;
- char c;
- char fastmap[(1 << BYTEWIDTH)];
-
- /* Allow a command argument to specify the style of syntax. */
- if (argc > 1)
- obscure_syntax = atol (argv[1]);
-
- buf.allocated = 40;
- buf.buffer = (char *) malloc (buf.allocated);
- buf.fastmap = fastmap;
- buf.translate = upcase;
-
- while (1)
+ int ret;
+ struct re_registers regs;
+ regex_t private_preg;
+ int len = strlen (string);
+ boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+ private_preg = *preg;
+
+ private_preg.not_bol = !!(eflags & REG_NOTBOL);
+ private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+ /* The user has told us exactly how many registers to return
+ information about, via `nmatch'. We have to pass that on to the
+ matching routines. */
+ private_preg.regs_allocated = REGS_FIXED;
+
+ if (want_reg_info)
{
- gets (pat);
+ regs.num_regs = nmatch;
+ regs.start = TALLOC (nmatch, regoff_t);
+ regs.end = TALLOC (nmatch, regoff_t);
+ if (regs.start == NULL || regs.end == NULL)
+ return (int) REG_NOMATCH;
+ }
- if (*pat)
- {
- re_compile_pattern (pat, strlen(pat), &buf);
+ /* Perform the searching operation. */
+ ret = re_search (&private_preg, string, len,
+ /* start: */ 0, /* range: */ len,
+ want_reg_info ? &regs : (struct re_registers *) 0);
+
+ /* Copy the register information to the POSIX structure. */
+ if (want_reg_info)
+ {
+ if (ret >= 0)
+ {
+ unsigned r;
- for (i = 0; i < buf.used; i++)
- printchar (buf.buffer[i]);
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
- putchar ('\n');
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ free (regs.end);
+ }
- printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
- re_compile_fastmap (&buf);
- printf ("Allowed by fastmap: ");
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (fastmap[i]) printchar (i);
- putchar ('\n');
- }
- gets (pat); /* Now read the string to match against */
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
- i = re_match (&buf, pat, strlen (pat), 0, 0);
- printf ("Match value %d.\n", i);
- }
-}
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
-#endif
+ if (errcode < 0
+ || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[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 = re_error_msg[errcode];
-#ifdef NOTDEF
-print_buf (bufp)
- struct re_pattern_buffer *bufp;
-{
- int i;
+ /* POSIX doesn't require that we do anything in this case, but why
+ not be nice. */
+ if (! msg)
+ msg = "Success";
- printf ("buf is :\n----------------\n");
- for (i = 0; i < bufp->used; i++)
- printchar (bufp->buffer[i]);
-
- printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
+ msg_size = strlen (msg) + 1; /* Includes the null. */
- printf ("Allowed by fastmap: ");
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (bufp->fastmap[i])
- printchar (i);
- printf ("\nAllowed by translate: ");
- if (bufp->translate)
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (bufp->translate[i])
- printchar (i);
- printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
- printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
-}
-#endif /* NOTDEF */
-
-printchar (c)
- char c;
-{
- if (c < 040 || c >= 0177)
+ if (errbuf_size != 0)
{
- putchar ('\\');
- putchar (((c >> 6) & 3) + '0');
- putchar (((c >> 3) & 7) + '0');
- putchar ((c & 7) + '0');
+ if (msg_size > errbuf_size)
+ {
+ strncpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ strcpy (errbuf, msg);
}
- else
- putchar (c);
+
+ return msg_size;
}
-error (string)
- char *string;
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
{
- puts (string);
- exit (1);
+ if (preg->buffer != NULL)
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ if (preg->fastmap != NULL)
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ if (preg->translate != NULL)
+ free (preg->translate);
+ preg->translate = NULL;
}
-#endif /* test */
+
+#endif /* not emacs */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/awk/regex.h b/gnu/usr.bin/awk/regex.h
index fce11c3a97dd..757dbacf7a28 100644
--- a/gnu/usr.bin/awk/regex.h
+++ b/gnu/usr.bin/awk/regex.h
@@ -1,10 +1,11 @@
-/* Definitions for data structures callers pass the regex library.
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
+ Copyright (C) 1985, 1989, 1990, 1991, 1992, 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 1, or (at your option)
+ the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
@@ -16,245 +17,489 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
-#ifndef __REGEXP_LIBRARY
-#define __REGEXP_LIBRARY
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
-/* Define number of parens for which we record the beginnings and ends.
- This affects how much space the `struct re_registers' type takes up. */
-#ifndef RE_NREGS
-#define RE_NREGS 10
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
#endif
-#define BYTEWIDTH 8
+/* 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 s_reg_t;
+typedef unsigned long active_reg_t;
-/* Maximum number of duplicates an interval can allow. */
-#ifndef RE_DUP_MAX
-#define RE_DUP_MAX ((1 << 15) - 1)
-#endif
+/* 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 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 RE_BACKSLASH_ESCAPE_IN_LISTS (1L)
+/* 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 RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
-/* This defines the various regexp syntaxes. */
-extern long obscure_syntax;
-
-
-/* The following bits are used in the obscure_syntax variable to choose among
- alternative regexp syntaxes. */
-
-/* If this bit is set, plain parentheses serve as grouping, and backslash
- parentheses are needed for literal searching.
- If not set, backslash-parentheses are grouping, and plain parentheses
- are for literal searching. */
-#define RE_NO_BK_PARENS 1L
-
-/* If this bit is set, plain | serves as the `or'-operator, and \| is a
- literal.
- If not set, \| serves as the `or'-operator, and | is a literal. */
-#define RE_NO_BK_VBAR (1L << 1)
-
-/* If this bit is not set, plain + or ? serves as an operator, and \+, \? are
- literals.
- If set, \+, \? are operators and plain +, ? are literals. */
-#define RE_BK_PLUS_QM (1L << 2)
-
-/* If this bit is set, | binds tighter than ^ or $.
- If not set, the contrary. */
-#define RE_TIGHT_VBAR (1L << 3)
-
-/* If this bit is set, then treat newline as an OR operator.
- If not set, treat it as a normal character. */
-#define RE_NEWLINE_OR (1L << 4)
-
-/* If this bit is set, then special characters may act as normal
- characters in some contexts. Specifically, this applies to:
- ^ -- only special at the beginning, or after ( or |;
- $ -- only special at the end, or before ) or |;
- *, +, ? -- only special when not after the beginning, (, or |.
- If this bit is not set, special characters (such as *, ^, and $)
- always have their special meaning regardless of the surrounding
- context. */
-#define RE_CONTEXT_INDEP_OPS (1L << 5)
-
-/* If this bit is not set, then \ before anything inside [ and ] is taken as
- a real \.
- If set, then such a \ escapes the following character. This is a
- special case for awk. */
-#define RE_AWK_CLASS_HACK (1L << 6)
-
-/* If this bit is set, then \{ and \} or { and } serve as interval operators.
- If not set, then \{ and \} and { and } are treated as literals. */
-#define RE_INTERVALS (1L << 7)
-
-/* If this bit is not set, then \{ and \} serve as interval operators and
- { and } are literals.
- If set, then { and } serve as interval operators and \{ and \} are
- literals. */
-#define RE_NO_BK_CURLY_BRACES (1L << 8)
-
-/* If this bit is set, then character classes are supported; they are:
- [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+/* 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 RE_CHAR_CLASSES (1L << 9)
-
-/* If this bit is set, then the dot re doesn't match a null byte.
- If not set, it does. */
-#define RE_DOT_NOT_NULL (1L << 10)
-
-/* If this bit is set, then [^...] doesn't match a newline.
- If not set, it does. */
-#define RE_HAT_NOT_NEWLINE (1L << 11)
-
-/* If this bit is set, back references are recognized.
- If not set, they aren't. */
-#define RE_NO_BK_REFS (1L << 12)
-
-/* If this bit is set, back references must refer to a preceding
- subexpression. If not set, a back reference to a nonexistent
- subexpression is treated as literal characters. */
-#define RE_NO_EMPTY_BK_REF (1L << 13)
-
-/* If this bit is set, bracket expressions can't be empty.
- If it is set, they can be empty. */
-#define RE_NO_EMPTY_BRACKETS (1L << 14)
-
-/* If this bit is set, then *, +, ? and { cannot be first in an re or
- immediately after a |, or a (. Furthermore, a | cannot be first or
- last in an re, or immediately follow another | or a (. Also, a ^
- cannot appear in a nonleading position and a $ cannot appear in a
- nontrailing position (outside of bracket expressions, that is). */
-#define RE_CONTEXTUAL_INVALID_OPS (1L << 15)
-
-/* If this bit is set, then +, ? and | aren't recognized as operators.
- If it's not, they are. */
-#define RE_LIMITED_OPS (1L << 16)
-
-/* If this bit is set, then an ending range point has to collate higher
- or equal to the starting range point.
- If it's not set, then when the ending range point collates higher
- than the starting range point, the range is just considered empty. */
-#define RE_NO_EMPTY_RANGES (1L << 17)
-
-/* If this bit is set, then a hyphen (-) can't be an ending range point.
- If it isn't, then it can. */
-#define RE_NO_HYPHEN_RANGE_END (1L << 18)
-
-
-/* Define combinations of bits for the standard possibilities. */
-#define RE_SYNTAX_POSIX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
- | RE_CONTEXT_INDEP_OPS)
-#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_AWK_CLASS_HACK)
-#define RE_SYNTAX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
- | RE_CONTEXT_INDEP_OPS | RE_NEWLINE_OR)
-#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* 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 RE_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 RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* 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 RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* 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 RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* 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, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ IF not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* 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 RE_SYNTAX_EMACS 0
-#define RE_SYNTAX_POSIX_BASIC (RE_INTERVALS | RE_BK_PLUS_QM \
- | RE_CHAR_CLASSES | RE_DOT_NOT_NULL \
- | RE_HAT_NOT_NEWLINE | RE_NO_EMPTY_BK_REF \
- | RE_NO_EMPTY_BRACKETS | RE_LIMITED_OPS \
- | RE_NO_EMPTY_RANGES | RE_NO_HYPHEN_RANGE_END)
-
-#define RE_SYNTAX_POSIX_EXTENDED (RE_INTERVALS | RE_NO_BK_CURLY_BRACES \
- | RE_NO_BK_VBAR | RE_NO_BK_PARENS \
- | RE_HAT_NOT_NEWLINE | RE_CHAR_CLASSES \
- | RE_NO_EMPTY_BRACKETS | RE_CONTEXTUAL_INVALID_OPS \
- | RE_NO_BK_REFS | RE_NO_EMPTY_RANGES \
- | RE_NO_HYPHEN_RANGE_END)
-
-
-/* This data structure is used to represent a compiled pattern. */
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_GNU_AWK | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+/* if sizeof(int) == 2, then ((1 << 15) - 1) overflows */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* 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 (REG_EXTENDED << 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 (REG_ICASE << 1)
+
+/* 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 (REG_NEWLINE << 1)
+
+
+/* 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)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `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
- {
- char *buffer; /* Space holding the compiled pattern commands. */
- long allocated; /* Size of space that `buffer' points to. */
- long used; /* Length of portion of buffer actually occupied */
- char *fastmap; /* Pointer to fastmap, if any, or zero if none. */
- /* re_search uses the fastmap, if there is one,
- to skip over totally implausible characters. */
- char *translate; /* Translate table to apply to all characters before
- comparing, or zero for no translation.
- The translation is applied to a pattern when it is
- compiled and to data when it is matched. */
- char fastmap_accurate;
- /* Set to zero when a new pattern is stored,
- set to one when the fastmap is updated from it. */
- char can_be_null; /* Set to one by compiling fastmap
- if this pattern might match the null string.
- It does not necessarily match the null string
- in that case, but if this is zero, it cannot.
- 2 as value means can match null string
- but at end of range or before a character
- listed in the fastmap. */
- };
-
-
-/* search.c (search_buffer) needs this one value. It is defined both in
- regex.c and here. */
+{
+/* [[[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 *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t 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 *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. */
+ char *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 can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned 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 fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
-/* Structure to store register contents data in.
-
- Pass the address of such a structure as an argument to re_match, etc.,
- if you want this information back.
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
- For i from 1 to RE_NREGS - 1, start[i] records the starting index in
- the string of where the ith subexpression matched, and end[i] records
- one after the ending index. start[0] and end[0] are analogous, for
- the entire pattern. */
-struct re_registers
- {
- int start[RE_NREGS];
- int end[RE_NREGS];
- };
+/* If `regs_allocated' is REGS_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 RE_NREGS
+#define RE_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. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
#ifdef __STDC__
-extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *);
-/* Is this really advertised? */
-extern void re_compile_fastmap (struct re_pattern_buffer *);
-extern int re_search (struct re_pattern_buffer *, char*, int, int, int,
- struct re_registers *);
-extern int re_search_2 (struct re_pattern_buffer *, char *, int,
- char *, int, int, int,
- struct re_registers *, int);
-extern int re_match (struct re_pattern_buffer *, char *, int, int,
- struct re_registers *);
-extern int re_match_2 (struct re_pattern_buffer *, char *, int,
- char *, int, int, struct re_registers *, int);
-extern long re_set_syntax (long syntax);
-
-#ifndef GAWK
-/* 4.2 bsd compatibility. */
-extern char *re_comp (char *);
-extern int re_exec (char *);
-#endif
+#define _RE_ARGS(args) args
-#else /* !__STDC__ */
+#else /* not __STDC__ */
-extern char *re_compile_pattern ();
-/* Is this really advertised? */
-extern void re_compile_fastmap ();
-extern int re_search (), re_search_2 ();
-extern int re_match (), re_match_2 ();
-extern long re_set_syntax();
+#define _RE_ARGS(args) ()
-#ifndef GAWK
-/* 4.2 bsd compatibility. */
-extern char *re_comp ();
-extern int re_exec ();
-#endif
+#endif /* not __STDC__ */
-#endif /* __STDC__ */
+/* 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 _RE_ARGS ((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
+ _RE_ARGS ((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 _RE_ARGS ((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->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int 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 int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
-#ifdef SYNTAX_TABLE
-extern char *re_syntax_table;
-#endif
-#endif /* !__REGEXP_LIBRARY */
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int 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
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/awk/version.c b/gnu/usr.bin/awk/version.c
index adea5fafacfb..89b6cc055fb0 100644
--- a/gnu/usr.bin/awk/version.c
+++ b/gnu/usr.bin/awk/version.c
@@ -42,5 +42,6 @@ char *version_string = "@(#)Gnu Awk (gawk) 2.15";
/* 2.14 Mostly bug fixes. */
/* 2.15 Bug fixes plus intermixing of command-line source and files,
- GNU long options, ARGIND, ERRNO and Plan 9 style /dev/ files. */
+ GNU long options, ARGIND, ERRNO and Plan 9 style /dev/ files.
+ `delete array'. OS/2 port added. */
diff --git a/gnu/usr.bin/cc/cc/gcc.c b/gnu/usr.bin/cc/cc/gcc.c
index 4223d23f62bd..7522b433a2f5 100644
--- a/gnu/usr.bin/cc/cc/gcc.c
+++ b/gnu/usr.bin/cc/cc/gcc.c
@@ -35,6 +35,7 @@ compilation is specified by a string called a "spec". */
#include <signal.h>
#include <sys/stat.h>
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#include <sys/errno.h>
#include "config.h"
#include "obstack.h"
@@ -103,9 +104,6 @@ compilation is specified by a string called a "spec". */
extern void free ();
extern char *getenv ();
-extern int errno, sys_nerr;
-extern char *sys_errlist[];
-
extern int execv (), execvp ();
/* If a stage of compilation returns an exit status >= 1,
@@ -1181,7 +1179,7 @@ static char *standard_startfile_prefix_1 = "/lib/";
static char *standard_startfile_prefix_2 = "/usr/lib/";
#ifndef TOOLDIR_BASE_PREFIX
-#define TOOLDIR_BASE_PREFIX "/usr/local/"
+#define TOOLDIR_BASE_PREFIX "/usr/libexec/"
#endif
static char *tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
static char *tooldir_prefix;
diff --git a/gnu/usr.bin/cc/cpp/cccp.c b/gnu/usr.bin/cc/cpp/cccp.c
index 86ba2cfaa70e..ae2c5b18bc60 100644
--- a/gnu/usr.bin/cc/cpp/cccp.c
+++ b/gnu/usr.bin/cc/cpp/cccp.c
@@ -186,8 +186,6 @@ extern char *getenv ();
extern FILE *fdopen ();
extern char *version_string;
extern struct tm *localtime ();
-extern int sys_nerr;
-extern char *sys_errlist[];
#ifndef errno
extern int errno;
diff --git a/gnu/usr.bin/cc/lib/Makefile b/gnu/usr.bin/cc/lib/Makefile
index 233f45711cca..30eeb5168743 100644
--- a/gnu/usr.bin/cc/lib/Makefile
+++ b/gnu/usr.bin/cc/lib/Makefile
@@ -1,6 +1,9 @@
LIB = gcc2
-CFLAGS += -I${.CURDIR} -DNOFPU
+CFLAGS += -I${.CURDIR}
+.if !defined(CCFPU)
+CFLAGS+= -DNOFPU
+.endif
NOPROFILE=no
NOPIC=no
diff --git a/gnu/usr.bin/cc/libgcc/Makefile b/gnu/usr.bin/cc/libgcc/Makefile
index c139126bdfa9..4995e593c043 100644
--- a/gnu/usr.bin/cc/libgcc/Makefile
+++ b/gnu/usr.bin/cc/libgcc/Makefile
@@ -1,10 +1,9 @@
-# $Id: Makefile,v 1.11 1993/12/24 02:35:33 jkh Exp $
+# $Id: Makefile,v 1.13 1994/06/21 16:00:55 jkh Exp $
LIB= gcc
-NOPROFILE=
-INSTALL_PIC_ARCHIVE=
+INSTALL_PIC_ARCHIVE=yes
SHLIB_MAJOR= 1
-SHLIB_MINOR= 0
+SHLIB_MINOR= 1
CFLAGS+=-I${.CURDIR}/../lib -I${.CURDIR}/../${MACHINE}
@@ -28,6 +27,8 @@ LIB2OBJS= _muldi3.o _divdi3.o _moddi3.o _udivdi3.o _umoddi3.o _negdi2.o \
OBJS= ${LIB1OBJS} ${LIB2OBJS}
LIB1SOBJS=${LIB1OBJS:.o=.so}
LIB2SOBJS=${LIB2OBJS:.o=.so}
+P1OBJS=${LIB1OBJS:.o=.po}
+P2OBJS=${LIB2OBJS:.o=.po}
${LIB1OBJS}: libgcc1.c
${CC} -c ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
@@ -47,4 +48,12 @@ ${LIB2SOBJS}: libgcc2.c
${CC} -c -fpic ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
.endif
+.if !defined(NOPROFILE)
+${P1OBJS}: libgcc1.c
+ ${CC} -c -p ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
+
+${P2OBJS}: libgcc2.c
+ ${CC} -c -p ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
+.endif
+
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/cc/libgcc/libgcc2.c b/gnu/usr.bin/cc/libgcc/libgcc2.c
index 9dcccbe3d011..55d9d6d75a51 100644
--- a/gnu/usr.bin/cc/libgcc/libgcc2.c
+++ b/gnu/usr.bin/cc/libgcc/libgcc2.c
@@ -1097,6 +1097,8 @@ __fixunssfsi (SFtype a)
Reult is negative if S1 is less than S2,
positive if S1 is greater, 0 if S1 and S2 are equal. */
+#include <sys/types.h>
+
int
__gcc_bcmp (s1, s2, size)
unsigned char *s1, *s2;
@@ -1318,6 +1320,9 @@ __bb_init_func (blocks)
/* frills for C++ */
#ifdef L_op_new
+
+#include <sys/types.h>
+
typedef void (*vfp)(void);
extern vfp __new_handler;
diff --git a/gnu/usr.bin/cc25/Freebsd.gcc258.patch b/gnu/usr.bin/cc25/Freebsd.gcc258.patch
new file mode 100644
index 000000000000..97af031aad05
--- /dev/null
+++ b/gnu/usr.bin/cc25/Freebsd.gcc258.patch
@@ -0,0 +1,39 @@
+# Last updated 19940220 phk@login.dkuug.dk
+# These are patches to FreeBSD-current, to make it compile with gcc-2.5.8
+# Eventually these, or maybe better ones should make it into the FreeBSD
+# source tree.
+
+./gnu/usr.bin/cc/lib/tm.h
+ Define ____386BSD____ __FreeBSD__ if not so already.
+./gnu/usr.bin/rcs/lib/conf.h
+ make compilable by gcc2.5.8
+
+diff -U3 /usr/src-current/./gnu/usr.bin/cc/lib/tm.h ./gnu/usr.bin/cc/lib/tm.h
+--- /usr/src-current/./gnu/usr.bin/cc/lib/tm.h Mon Jan 10 23:48:12 1994
++++ ./gnu/usr.bin/cc/lib/tm.h Fri Feb 18 00:54:15 1994
+@@ -2,6 +2,13 @@
+
+ /* This is tested by i386gas.h. */
+ #define YES_UNDERSCORES
++#ifndef ____386BSD____
++#define ____386BSD____
++#endif
++
++#ifndef __FreeBSD__
++#define __FreeBSD__
++#endif
+
+ #include "i386/gstabs.h"
+
+diff -U3 /usr/src-current/./gnu/usr.bin/rcs/lib/conf.h ./gnu/usr.bin/rcs/lib/conf.h
+--- /usr/src-current/./gnu/usr.bin/rcs/lib/conf.h Fri Jun 18 06:22:13 1993
++++ ./gnu/usr.bin/rcs/lib/conf.h Fri Feb 18 00:54:17 1994
+@@ -219,7 +219,7 @@
+ /* Adjust the following declarations as needed. */
+
+
+-#if __GNUC__ && !__STRICT_ANSI__
++#if __GNUC__ && !__STRICT_ANSI__ && !__FreeBSD__
+ # define exiting volatile /* GCC extension: function cannot return */
+ #else
+ # define exiting
diff --git a/gnu/usr.bin/cc25/Makefile b/gnu/usr.bin/cc25/Makefile
new file mode 100644
index 000000000000..67dff93dba18
--- /dev/null
+++ b/gnu/usr.bin/cc25/Makefile
@@ -0,0 +1,6 @@
+
+PGMDIR= gcc_int xgcc cccp cc1 cc1plus cc1obj g++ usr.bin.cpp usr.bin.f77
+LIBDIR= libgcc libobjc
+SUBDIR= $(PGMDIR) $(LIBDIR)
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/cc25/README b/gnu/usr.bin/cc25/README
new file mode 100644
index 000000000000..566908f2c026
--- /dev/null
+++ b/gnu/usr.bin/cc25/README
@@ -0,0 +1,209 @@
+ ----------------------------------------------------------------------------
+ "THE BEER-WARE LICENSE" (Revision 42):
+ <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+ can do whatever you want with this stuff. If we meet some day, and you think
+ this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ ----------------------------------------------------------------------------
+
+ $Id: README,v 1.2 1994/02/27 21:42:34 phk Exp $
+
+"If you're looking for trouble,
+ you've come to the right place !"
+ The King.
+
+(I have taken the time to rewrite the README. It had become a proper mess,
+just like any other workspace of mine.)
+
+What is this ?
+--------------
+My intention is that this will be the link between the GNU-release of GCC,
+and the FreeBSD integrated version of GCC. The problem^H^H^H^H^H^Hchallenge
+is that FreeBSD uses BSD style Makefiles, whereas GNU uses their own scheme.
+Thus, everytime GNU adds a file, changes a flag and so on, we have to find
+out what consequences this should have for the FreeBSD Makefiles. This
+stuff, should make that process easier, and reproducible.
+
+The next challenge^H^H^H^H^H^H^H^H^Hproblem is that we need some modifications
+to the GNU source. For instance: we use gcc to compile FORTRAN via f2c, so
+we need to add the rules for that to gcc.c.
+
+In case you have ever wondered about what "dark runes" was, this is that.
+
+Overview:
+---------
+When a new release of GCC is to be brought into FreeBSD, this is what must
+be done:
+
+ - modify gnu2bsd.tcl as needed, until the resulting FreeBSD-tree
+ is compilable. It may not yet be correct, but it must be compilable.
+ - patch the GNU-tree as needed until the compiler generated from
+ the BSD-tree is correct.
+
+I think this will be the simplest way to do the second part:
+
+ - Run a virgin GNU-gcc-(N) through gnu2bsd.tcl.
+ - Create a patch from this to the patched FreeBSD-gcc-(N).
+ - Run a virgin GNU-gcc-(N+a) through gnu2bsd.tcl
+ - Apply as much of the above patch as makes sense.
+ - Twiddle until it works.
+ - Submit the needed patches to the GNU people, to avoid
+ needless diversion from their base.
+
+It is of course clear from the above, that unless you feel that you are
+sure why you need to do this, you shouldn't do it. There is some very
+interesting ways this can hose your system. Don't tell me I didn't
+warn you.
+
+Installation:
+-------------
+
+ 0. Needed ingredients:
+ ======================
+ bison and tcl.
+
+ 1. Create a emergency ready copy of your old gcc.
+ =================================================
+ Move the old compiler to a safe place
+ mv /usr/src/gnu/usr.bin/cc /usr/src/gnu/usr.bin/cc.old
+ for instance.
+
+ cd into the directory of the old compiler, and do:
+ find . -name 'obj' -exec rm -f {} \;
+ make clean all
+
+ It is necessary to remove the 'obj' sym-links, as a make world
+ is likely to remove the stuff they point at. Doing it this way
+ you can, in case you hose the installed c-compiler, go down here
+ and do a
+ make install
+ and things should work for you again.
+
+ 2. Create the foundations for a new gcc.
+ ========================================
+ Create a new directory /usr/src/gnu/usr.bin/cc The name can
+ be anything you like actually, but some Makefiles "know" this place.
+ This directory is $BSDDIR in the rest of this instruction.
+
+ Copy the usr.bin.cpp and usr.bin.f77 with contents to $BSDDIR from
+ somewhere, either they came with this stuff, or you can take it
+ from the old cc on your system.
+
+ Copy Makefile and gnu2bsd.tcl also, and if any gcc???-freebsd.patch
+ files are there, you should copy those along too. This file (README)
+ will be nice to have too.
+
+ 3. Install a GNU-release of GCC somewhere.
+ ==========================================
+ This can be anywhere you have the necesary disk-space. ($GNUDIR)
+
+ Apply patches to the GNU-dist. If any of the gcc???-freebsd.patch
+ has the same version as the GCC you're installing, use that, if you
+ are installing a newer version of gcc, you're a bit on your own. Try
+ the most recent of the gcc???-freebsd.patch files, and prepare for
+ some work.
+
+ 4. Create the BSD-tree from the GNU-tree
+ ========================================
+ Edit gnu2bsd.tcl so that the various "TWEAKS" are right. If this is
+ a new version of GCC, all bets are off, and you might need to modify
+ in the main-part of the script too.
+
+ And now, the great moment:
+ cd $GNUDIR
+ configure
+ make realclean
+ configure
+ cd $BSDDIR
+ tclsh gnu2bsd.tcl
+
+ 5. Bootstrap the new compiler
+ =============================
+
+ cd $BSDDIR
+ make clean obj clean depend
+ make -k ; make -k install
+ # The first make might fail on libgcc for instance,
+ # install the bits which was OK.
+ make clean all install
+ # this should succeed.
+ make clean all install
+ # Now things should be A1-OK.
+
+History:
+--------
+
+199402272230
+ Received blessed patch for the ((packed)) problem from GNU.
+
+199402211500 (v5):
+
+ Got more patches from Richard to expmed.c, not quite right yet.
+
+ Tried to make a patch from 245 to 258 (FreeBSD-style directories),
+ uncompressed size: 4.4 Mb (the whole 258 is 10Mb). This actually
+ resolves my doubts about the renaming of 'lib' to 'gcc_int' &c &c.
+ We save nothing really by trying to make a patch.
+
+ I think that we should move from src/gnu/usr.bin/cc to
+ src/gnu/usr.bin/cc25 (and so on) to facilitate testing.
+
+ People tell me that usr.bin.cpp usr.bin.f77 should stay as
+ subdirs of gcc. OK, I don't really care...
+
+ Added %{Z} to gcc.c as per patch to -current.
+
+ README rewritten.
+
+revision: 199402140030 (v4)
+
+ Added the same patch to expmed.c for reading bit-fields.
+
+ The patch in v3 to gcc was wrong, sorry.
+
+revision: 199402132300 (v3)
+
+ Please notice that the both the patchfiles have changed.
+
+ Please use -O2 as much as possible, we must try to stress this
+ bugger to the limit. If you want to change the global defaults
+ you should change CFLAGS in /usr/src/share/mk/sys.mk and do a
+ make (or directly in /usr/share/mk/sys.mk but make world will
+ loose that change then). I suggest -O2, and -m486 in case you
+ have one. Sideeffect is faster machine, you can insert wait-
+ states or disable cache-memory if this is a problem for you :-)
+
+ cc1, abort(3)'s on this bit of code, modelled on
+ init386() in sys/i386/i386/machdep.c:
+
+ extern union descriptor gdt[40];
+ struct region_descriptor {
+ unsigned rd_limit:16;
+ unsigned rd_base:32 __attribute__ ((packed));
+ };
+ void foo() {
+ struct region_descriptor r_gdt;
+ r_gdt.rd_base = (unsigned) gdt;
+ }
+
+ I got a new expmed.c from Richard, and had to fix a problem
+ in it. This is all in the gcc258-freebsd.patch.3 file.
+
+ It seems that groff/grops chokes, but this could be libg++ which
+ should be updated. Nothing done about it for now.
+
+ Richard Kenner said that there will probably never be a 2.5.9 and that
+ 2.6.0 should hit the ground between late March and May. I think that
+ if 1.2 is at 1st June, then we need to go ahead with 2.5.8, and
+ if 2.6.0 comes early, consider defecting to it. Comments invited.
+
+revision: 199402121100 (v2)
+ .size was -1 in /usr/src/lib/libc/errlst.o, this choked ld(1), which
+ went into a spin. Fixed by pulling in stuff from osfrose.h. As a
+ consequence the patch against the gnu-dist changed.
+ I have made the linked compier static for now, this is a temporary
+ measure to curtail havoc when things break. It works just as fine
+ when linked dynamic.
+
+revision: 199402111700 (v1)
+ First released version.
+
diff --git a/gnu/usr.bin/cc25/gcc258-freebsd.patch b/gnu/usr.bin/cc25/gcc258-freebsd.patch
new file mode 100644
index 000000000000..bcc8ef2728bd
--- /dev/null
+++ b/gnu/usr.bin/cc25/gcc258-freebsd.patch
@@ -0,0 +1,1188 @@
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/config/i386/freebsd.h gcc-2.5.8/config/i386/freebsd.h
+*** gcc-2.5.8.gnu/config/i386/freebsd.h Thu Jan 1 01:00:00 1970
+--- gcc-2.5.8/config/i386/freebsd.h Sun Feb 27 00:40:55 1994
+***************
+*** 0 ****
+--- 1,341 ----
++ /* Configuration for an i386 running FreeBSD as the target machine.
++ *
++ * 7th feb 1994, Poul-Henning Kamp <phk@login.dkuug.dk>
++ * Made to fit FreeBSD 1.1 and GCC 2.5.8
++ */
++
++ /* This goes away when the math-emulator is fixed */
++ #define TARGET_CPU_DEFAULT 0400 /* TARGET_NO_FANCY_MATH_387 */
++
++ /* Just in case. (Cross-compilations &c) */
++ #ifndef __FreeBSD__
++ #define __FreeBSD__ 1
++ #endif
++
++ /* This is tested by i386gas.h. */
++ #define YES_UNDERSCORES
++
++ #include "i386/gstabs.h"
++
++ /* Get perform_* macros to build libgcc.a. */
++ #include "i386/perform.h"
++
++ #undef CPP_PREDEFINES
++ #define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -D__386BSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
++
++ #define INCLUDE_DEFAULTS { \
++ { "/usr/include", 0 }, \
++ { "/usr/include/g++", 1 }, \
++ { 0, 0} \
++ }
++
++ /* Like the default, except no -lg. */
++ #define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
++
++ #undef SIZE_TYPE
++ #define SIZE_TYPE "unsigned int"
++
++ #undef PTRDIFF_TYPE
++ #define PTRDIFF_TYPE "int"
++
++ #undef WCHAR_TYPE
++ #define WCHAR_TYPE "short unsigned int"
++
++ #define WCHAR_UNSIGNED 1
++
++ #undef WCHAR_TYPE_SIZE
++ #define WCHAR_TYPE_SIZE 16
++
++ #define HAVE_ATEXIT
++
++ /* Redefine this to use %eax instead of %edx. */
++ #undef FUNCTION_PROFILER
++ #define FUNCTION_PROFILER(FILE, LABELNO) \
++ { \
++ if (flag_pic) \
++ { \
++ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%eax\n", \
++ LPREFIX, (LABELNO)); \
++ fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \
++ } \
++ else \
++ { \
++ fprintf (FILE, "\tmovl $%sP%d,%%eax\n", LPREFIX, (LABELNO)); \
++ fprintf (FILE, "\tcall mcount\n"); \
++ } \
++ }
++
++ /* There are conflicting reports about whether this system uses
++ a different assembler syntax. wilson@cygnus.com says # is right. */
++ #undef COMMENT_BEGIN
++ #define COMMENT_BEGIN "#"
++
++ #undef ASM_APP_ON
++ #define ASM_APP_ON "#APP\n"
++
++ #undef ASM_APP_OFF
++ #define ASM_APP_OFF "#NO_APP\n"
++
++ /* The following macros are stolen from i386v4.h */
++ /* These have to be defined to get PIC code correct */
++
++ /* This is how to output an element of a case-vector that is relative.
++ This is only used for PIC code. See comments by the `casesi' insn in
++ i386.md for an explanation of the expression this outputs. */
++
++ #undef ASM_OUTPUT_ADDR_DIFF_ELT
++ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
++ fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
++
++ /* Indicate that jump tables go in the text section. This is
++ necessary when compiling PIC code. */
++
++ #define JUMP_TABLES_IN_TEXT_SECTION
++
++ /* Don't default to pcc-struct-return, because gcc is the only compiler, and
++ we want to retain compatibility with older gcc versions. */
++ #define DEFAULT_PCC_STRUCT_RETURN 0
++
++ /*
++ * Some imports from svr4.h in support of shared libraries.
++ * Currently, we need the DECLARE_OBJECT_SIZE stuff.
++ */
++
++ /* Define the strings used for the special svr4 .type and .size directives.
++ These strings generally do not vary from one system running svr4 to
++ another, but if a given system (e.g. m88k running svr) needs to use
++ different pseudo-op names for these, they may be overridden in the
++ file which includes this one. */
++
++ #define TYPE_ASM_OP ".type"
++ #define SIZE_ASM_OP ".size"
++ #define WEAK_ASM_OP ".weak"
++
++ /* The following macro defines the format used to output the second
++ operand of the .type assembler directive. Different svr4 assemblers
++ expect various different forms for this operand. The one given here
++ is just a default. You may need to override it in your machine-
++ specific tm.h file (depending upon the particulars of your assembler). */
++
++ #define TYPE_OPERAND_FMT "@%s"
++
++ /* Write the extra assembler code needed to declare a function's result.
++ Most svr4 assemblers don't require any special declaration of the
++ result value, but there are exceptions. */
++
++ #ifndef ASM_DECLARE_RESULT
++ #define ASM_DECLARE_RESULT(FILE, RESULT)
++ #endif
++
++ /* These macros generate the special .type and .size directives which
++ are used to set the corresponding fields of the linker symbol table
++ entries in an ELF object file under SVR4. These macros also output
++ the starting labels for the relevant functions/objects. */
++
++ /* Write the extra assembler code needed to declare a function properly.
++ Some svr4 assemblers need to also have something extra said about the
++ function's return value. We allow for that here. */
++
++ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
++ do { \
++ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
++ assemble_name (FILE, NAME); \
++ putc (',', FILE); \
++ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
++ putc ('\n', FILE); \
++ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
++ ASM_OUTPUT_LABEL(FILE, NAME); \
++ } while (0)
++
++ /* Write the extra assembler code needed to declare an object properly. */
++
++ #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
++ do { \
++ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
++ assemble_name (FILE, NAME); \
++ putc (',', FILE); \
++ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
++ putc ('\n', FILE); \
++ size_directive_output = 0; \
++ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
++ { \
++ size_directive_output = 1; \
++ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
++ assemble_name (FILE, NAME); \
++ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
++ } \
++ ASM_OUTPUT_LABEL(FILE, NAME); \
++ } while (0)
++
++ /* Output the size directive for a decl in rest_of_decl_compilation
++ in the case where we did not do so before the initializer.
++ Once we find the error_mark_node, we know that the value of
++ size_directive_output was set
++ by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
++
++ #define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
++ do { \
++ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
++ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
++ && ! AT_END && TOP_LEVEL \
++ && DECL_INITIAL (DECL) == error_mark_node \
++ && !size_directive_output) \
++ { \
++ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
++ assemble_name (FILE, name); \
++ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
++ } \
++ } while (0)
++
++
++ /* This is how to declare the size of a function. */
++
++ #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
++ do { \
++ if (!flag_inhibit_size_directive) \
++ { \
++ char label[256]; \
++ static int labelno; \
++ labelno++; \
++ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
++ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
++ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
++ assemble_name (FILE, (FNAME)); \
++ fprintf (FILE, ","); \
++ assemble_name (FILE, label); \
++ fprintf (FILE, "-"); \
++ assemble_name (FILE, (FNAME)); \
++ putc ('\n', FILE); \
++ } \
++ } while (0)
++
++ #define ASM_SPEC " %| %{fpic:-k} %{fPIC:-k}"
++ #define LINK_SPEC \
++ "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*}"
++
++ #define CUSTOM_DEFAULT_COMPILERS \
++ /***** ljo's Fortran rule *****/ \
++ {".f", "@f2c"}, \
++ {"@f2c", \
++ "f2c %{checksubscripts:-C} %{I2} %{onetrip} %{honorcase:-U} %{u} %{w}\
++ %{ANSIC:-A} %{a} %{C++}\
++ %{c} %{E} %{ec} %{ext} %{f} %{72} %{g} %{h} %{i2} %{kr}\
++ %{P} %{p} %{r} %{r8} %{s} %{w8} %{z} %{N*}\
++ %i %{!pipe: -o %g.c} %{pipe:-o -}|\n", \
++ "gcpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
++ %{C:%{!E:%eGNU C does not support -C without using -E}}\
++ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
++ -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
++ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
++ %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
++ %{traditional-cpp:-traditional}\
++ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
++ %{pipe:-} %{!pipe:%g.c} %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n", \
++ "%{!M:%{!MM:%{!E:gcc1 %{!pipe:%g.i} %1 \
++ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
++ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
++ %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
++ %{aux-info*}\
++ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
++ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
++ %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
++ %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
++ %{!pipe:%g.s} %A\n }}}}"}, \
++ /***** End of ljo's Fortran rule *****/
++
++ /* This section stolen from i386/osfrose.h */
++
++ /* A C statement or compound statement to output to FILE some
++ assembler code to initialize basic-block profiling for the current
++ object module. This code should call the subroutine
++ `__bb_init_func' once per object module, passing it as its sole
++ argument the address of a block allocated in the object module.
++
++ The name of the block is a local symbol made with this statement:
++
++ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
++
++ Of course, since you are writing the definition of
++ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
++ can take a short cut in the definition of this macro and use the
++ name that you know will result.
++
++ The first word of this block is a flag which will be nonzero if the
++ object module has already been initialized. So test this word
++ first, and do not call `__bb_init_func' if the flag is nonzero. */
++
++ #undef FUNCTION_BLOCK_PROFILER
++ #define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO) \
++ do \
++ { \
++ if (!flag_pic) \
++ { \
++ fprintf (STREAM, "\tcmpl $0,%sPBX0\n", LPREFIX); \
++ fprintf (STREAM, "\tjne 0f\n"); \
++ fprintf (STREAM, "\tpushl $%sPBX0\n", LPREFIX); \
++ fprintf (STREAM, "\tcall ___bb_init_func\n"); \
++ fprintf (STREAM, "0:\n"); \
++ } \
++ else \
++ { \
++ fprintf (STREAM, "\tpushl %eax\n"); \
++ fprintf (STREAM, "\tmovl %sPBX0@GOT(%ebx),%eax\n"); \
++ fprintf (STREAM, "\tcmpl $0,(%eax)\n"); \
++ fprintf (STREAM, "\tjne 0f\n"); \
++ fprintf (STREAM, "\tpushl %eax\n"); \
++ fprintf (STREAM, "\tcall ___bb_init_func@PLT\n"); \
++ fprintf (STREAM, "0:\n"); \
++ fprintf (STREAM, "\tpopl %eax\n"); \
++ } \
++ } \
++ while (0)
++
++ /* A C statement or compound statement to increment the count
++ associated with the basic block number BLOCKNO. Basic blocks are
++ numbered separately from zero within each compilation. The count
++ associated with block number BLOCKNO is at index BLOCKNO in a
++ vector of words; the name of this array is a local symbol made
++ with this statement:
++
++ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
++
++ Of course, since you are writing the definition of
++ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
++ can take a short cut in the definition of this macro and use the
++ name that you know will result. */
++
++ #undef BLOCK_PROFILER
++ #define BLOCK_PROFILER(STREAM, BLOCKNO) \
++ do \
++ { \
++ if (!flag_pic) \
++ fprintf (STREAM, "\tincl %sPBX2+%d\n", LPREFIX, (BLOCKNO)*4); \
++ else \
++ { \
++ fprintf (STREAM, "\tpushl %eax\n"); \
++ fprintf (STREAM, "\tmovl %sPBX2@GOT(%ebx),%eax\n", LPREFIX); \
++ fprintf (STREAM, "\tincl %d(%eax)\n", (BLOCKNO)*4); \
++ fprintf (STREAM, "\tpopl %eax\n"); \
++ } \
++ } \
++ while (0)
++
++ /* This is defined when gcc is compiled in the BSD-directory-tree, and must
++ * make up for the gap to all the stuff done in the GNU-makefiles.
++ * XXX Do these right
++ */
++
++ #ifdef FREEBSD_NATIVE
++
++ #undef MD_EXEC_PREFIX
++ #define MD_EXEC_PREFIX "/usr/libexec/"
++
++ #undef STANDARD_STARTFILE_PREFIX
++ #define STANDARD_STARTFILE_PREFIX "/usr/lib"
++
++ #define DEFAULT_TARGET_MACHINE "i386-unknown-freebsd_1.0"
++ #define GPLUSPLUS_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
++ #define TOOL_INCLUDE_DIR "/usr/local/i386-unknown-freebsd_1.0/include"
++ #define GCC_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
++
++ #endif /* FREEBSD_NATIVE */
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/config/i386/i386.h gcc-2.5.8/config/i386/i386.h
+*** gcc-2.5.8.gnu/config/i386/i386.h Wed Oct 13 07:02:27 1993
+--- gcc-2.5.8/config/i386/i386.h Sun Feb 27 00:40:56 1994
+***************
+*** 90,95 ****
+--- 90,99 ----
+ the 387 to be used, which is compatible with most calling conventions. */
+ #define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & 0200)
+
++ /* Disable generation of FP sin, cos and sqrt operations for 387.
++ This is because FreeBSD lacks these in the math-emulator-code */
++ #define TARGET_NO_FANCY_MATH_387 (target_flags & 0400)
++
+ /* Macro to define tables used to set the flags.
+ This is a list in braces of pairs in braces,
+ each pair being { "NAME", VALUE }
+***************
+*** 114,119 ****
+--- 118,125 ----
+ { "no-ieee-fp", -0100}, \
+ { "fp-ret-in-387", 0200}, \
+ { "no-fp-ret-in-387", -0200}, \
++ { "no-fancy-math-387", 0400}, \
++ { "fancy-math-387", -0400}, \
+ SUBTARGET_SWITCHES \
+ { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
+
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/config/i386/i386.md gcc-2.5.8/config/i386/i386.md
+*** gcc-2.5.8.gnu/config/i386/i386.md Tue Oct 5 06:43:30 1993
+--- gcc-2.5.8/config/i386/i386.md Sun Feb 27 00:40:59 1994
+***************
+*** 2935,3012 ****
+ (define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "general_operand" "0")))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "general_operand" "0")))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (float_extend:DF
+ (match_operand:SF 1 "general_operand" "0"))))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn "sqrtxf2"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (match_operand:XF 1 "general_operand" "0")))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:DF 1 "general_operand" "0"))))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:SF 1 "general_operand" "0"))))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsqrt")
+
+ (define_insn "sindf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsin")
+
+ (define_insn "sinsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsin")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 1))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fsin")
+
+ (define_insn "cosdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fcos")
+
+ (define_insn "cossf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fcos")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 2))]
+! "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
+ "fcos")
+
+ ;;- one complement instructions
+--- 2935,3024 ----
+ (define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "general_operand" "0")))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "general_operand" "0")))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (float_extend:DF
+ (match_operand:SF 1 "general_operand" "0"))))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn "sqrtxf2"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (match_operand:XF 1 "general_operand" "0")))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:DF 1 "general_operand" "0"))))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:SF 1 "general_operand" "0"))))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt")
+
+ (define_insn "sindf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsin")
+
+ (define_insn "sinsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsin")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 1))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fsin")
+
+ (define_insn "cosdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fcos")
+
+ (define_insn "cossf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fcos")
+
+ (define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 2))]
+! "(!TARGET_NO_FANCY_MATH_387) && TARGET_80387 &&
+! (TARGET_IEEE_FP || flag_fast_math) "
+ "fcos")
+
+ ;;- one complement instructions
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/config.guess gcc-2.5.8/config.guess
+*** gcc-2.5.8.gnu/config.guess Sun Dec 12 12:50:10 1993
+--- gcc-2.5.8/config.guess Sun Feb 27 00:41:00 1994
+***************
+*** 171,176 ****
+--- 171,179 ----
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
++ i[34]86:FreeBSD:*:*)
++ echo ${UNAME_MACHINE}-unknown-freebsd
++ exit 0 ;;
+ i[34]86:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/config.sub gcc-2.5.8/config.sub
+*** gcc-2.5.8.gnu/config.sub Thu Jan 13 11:43:23 1994
+--- gcc-2.5.8/config.sub Sun Feb 27 00:41:00 1994
+***************
+*** 534,540 ****
+ | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+ | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+! | -hiux* | -386bsd* | -netbsd* | -riscix* | -lynxos*)
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+--- 534,540 ----
+ | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+ | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+! | -hiux* | -386bsd* | -netbsd* | -riscix* | -lynxos* | -freebsd*)
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/configure gcc-2.5.8/configure
+*** gcc-2.5.8.gnu/configure Fri Nov 19 22:44:16 1993
+--- gcc-2.5.8/configure Sun Feb 27 00:41:03 1994
+***************
+*** 385,390 ****
+--- 385,394 ----
+ tmake_file=i386/t-next
+ xmake_file=i386/x-next
+ ;;
++ i[34]86-*-freebsd*)
++ cpu_type=i386
++ tm_file=i386/freebsd.h
++ ;;
+ i[34]86-*-bsd*)
+ cpu_type=i386
+ tm_file=i386/386bsd.h
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/expmed.c gcc-2.5.8/expmed.c
+*** gcc-2.5.8.gnu/expmed.c Sun Nov 14 04:50:40 1993
+--- gcc-2.5.8/expmed.c Sun Feb 27 22:17:01 1994
+***************
+*** 1,6 ****
+ /* Medium-level subroutines: convert bit-field store and extract
+ and shifts, multiplies and divides to rtl instructions.
+! Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+--- 1,6 ----
+ /* Medium-level subroutines: convert bit-field store and extract
+ and shifts, multiplies and divides to rtl instructions.
+! Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+***************
+*** 421,427 ****
+ /* If xop0 is a register, we need it in MAXMODE
+ to make it acceptable to the format of insv. */
+ if (GET_CODE (xop0) == SUBREG)
+! PUT_MODE (xop0, maxmode);
+ if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
+ xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);
+
+--- 421,429 ----
+ /* If xop0 is a register, we need it in MAXMODE
+ to make it acceptable to the format of insv. */
+ if (GET_CODE (xop0) == SUBREG)
+! /* We can't just change the mode, because this might clobber op0,
+! and we will need the original value of op0 if insv fails. */
+! xop0 = gen_rtx (SUBREG, maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0));
+ if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
+ xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);
+
+***************
+*** 556,561 ****
+--- 558,573 ----
+
+ total_bits = GET_MODE_BITSIZE (mode);
+
++ /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
++ be be in the range 0 to total_bits-1, and put any excess bytes in
++ OFFSET. */
++ if (bitpos >= total_bits)
++ {
++ offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
++ bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
++ * BITS_PER_UNIT);
++ }
++
+ /* Get ref to an aligned byte, halfword, or word containing the field.
+ Adjust BITPOS to be position within a word,
+ and OFFSET to be the offset of that word.
+***************
+*** 691,697 ****
+ {
+ rtx word = gen_lowpart_common (word_mode, value);
+
+! if (word)
+ value = word;
+ else
+ value = gen_lowpart_common (word_mode,
+--- 703,709 ----
+ {
+ rtx word = gen_lowpart_common (word_mode, value);
+
+! if (word && (value != word))
+ value = word;
+ else
+ value = gen_lowpart_common (word_mode,
+***************
+*** 721,731 ****
+ >> (bitsize - bitsdone - thissize))
+ & (((HOST_WIDE_INT) 1 << thissize) - 1));
+ else
+! /* The args are chosen so that the last part
+! includes the lsb. */
+! part = extract_fixed_bit_field (word_mode, value, 0, thissize,
+! BITS_PER_WORD - bitsize + bitsdone,
+! NULL_RTX, 1, align);
+ #else
+ /* Fetch successively more significant portions. */
+ if (GET_CODE (value) == CONST_INT)
+--- 733,751 ----
+ >> (bitsize - bitsdone - thissize))
+ & (((HOST_WIDE_INT) 1 << thissize) - 1));
+ else
+! {
+! /* The args are chosen so that the last part
+! includes the lsb. */
+! int bit_offset = 0;
+! /* If the value isn't in memory, then it must be right aligned
+! if a register, so skip past the padding on the left. If it
+! is in memory, then there is no padding on the left. */
+! if (GET_CODE (value) != MEM)
+! bit_offset = BITS_PER_WORD - bitsize;
+! part = extract_fixed_bit_field (word_mode, value, 0, thissize,
+! bit_offset + bitsdone,
+! NULL_RTX, 1, align);
+! }
+ #else
+ /* Fetch successively more significant portions. */
+ if (GET_CODE (value) == CONST_INT)
+***************
+*** 1592,1597 ****
+--- 1612,1625 ----
+
+ op1 = expand_expr (amount, NULL_RTX, VOIDmode, 0);
+
++ #if SHIFT_COUNT_TRUNCATED
++ if (SHIFT_COUNT_TRUNCATED
++ && GET_CODE (op1) == CONST_INT
++ && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode))
++ op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
++ % GET_MODE_BITSIZE (mode));
++ #endif
++
+ if (op1 == const0_rtx)
+ return shifted;
+
+***************
+*** 1843,1852 ****
+ int cost_limit;
+ {
+ int m;
+! struct algorithm *best_alg
+! = (struct algorithm *)alloca (sizeof (struct algorithm));
+! struct algorithm *alg_in
+! = (struct algorithm *)alloca (sizeof (struct algorithm));
+ unsigned int cost;
+ unsigned HOST_WIDE_INT q;
+
+--- 1871,1877 ----
+ int cost_limit;
+ {
+ int m;
+! struct algorithm *alg_in, *best_alg;
+ unsigned int cost;
+ unsigned HOST_WIDE_INT q;
+
+***************
+*** 1881,1886 ****
+--- 1906,1916 ----
+ }
+ }
+
++ /* We'll be needing a couple extra algorithm structures now. */
++
++ alg_in = (struct algorithm *)alloca (sizeof (struct algorithm));
++ best_alg = (struct algorithm *)alloca (sizeof (struct algorithm));
++
+ /* If we have a group of zero bits at the low-order part of T, try
+ multiplying by the remaining bits and then doing a shift. */
+
+***************
+*** 2043,2058 ****
+ }
+ }
+
+- /* If we are getting a too long sequence for `struct algorithm'
+- to record, make this search fail. */
+- if (best_alg->ops == MAX_BITS_PER_WORD)
+- return;
+-
+ /* If cost_limit has not decreased since we stored it in alg_out->cost,
+ we have not found any algorithm. */
+ if (cost_limit == alg_out->cost)
+ return;
+
+ /* Copy the algorithm from temporary space to the space at alg_out.
+ We avoid using structure assignment because the majority of
+ best_alg is normally undefined, and this is a critical function. */
+--- 2073,2088 ----
+ }
+ }
+
+ /* If cost_limit has not decreased since we stored it in alg_out->cost,
+ we have not found any algorithm. */
+ if (cost_limit == alg_out->cost)
+ return;
+
++ /* If we are getting a too long sequence for `struct algorithm'
++ to record, make this search fail. */
++ if (best_alg->ops == MAX_BITS_PER_WORD)
++ return;
++
+ /* Copy the algorithm from temporary space to the space at alg_out.
+ We avoid using structure assignment because the majority of
+ best_alg is normally undefined, and this is a critical function. */
+***************
+*** 2153,2161 ****
+ for (opno = 1; opno < alg.ops; opno++)
+ {
+ int log = alg.log[opno];
+! rtx shift_subtarget = preserve_subexpressions_p () ? 0 : accum;
+ rtx add_target = opno == alg.ops - 1 && target != 0 ? target : 0;
+!
+ switch (alg.op[opno])
+ {
+ case alg_shift:
+--- 2183,2193 ----
+ for (opno = 1; opno < alg.ops; opno++)
+ {
+ int log = alg.log[opno];
+! int preserve = preserve_subexpressions_p ();
+! rtx shift_subtarget = preserve ? 0 : accum;
+ rtx add_target = opno == alg.ops - 1 && target != 0 ? target : 0;
+! rtx accum_target = preserve ? 0 : accum;
+!
+ switch (alg.op[opno])
+ {
+ case alg_shift:
+***************
+*** 2168,2174 ****
+ tem = expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+! add_target ? add_target : accum);
+ val_so_far += (HOST_WIDE_INT) 1 << log;
+ break;
+
+--- 2200,2206 ----
+ tem = expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+! add_target ? add_target : accum_target);
+ val_so_far += (HOST_WIDE_INT) 1 << log;
+ break;
+
+***************
+*** 2176,2198 ****
+ tem = expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (MINUS, mode, accum, tem),
+! add_target ? add_target : accum);
+ val_so_far -= (HOST_WIDE_INT) 1 << log;
+ break;
+
+ case alg_add_t2_m:
+ accum = expand_shift (LSHIFT_EXPR, mode, accum,
+! build_int_2 (log, 0), accum, 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, op0),
+! add_target ? add_target : accum);
+ val_so_far = (val_so_far << log) + 1;
+ break;
+
+ case alg_sub_t2_m:
+ accum = expand_shift (LSHIFT_EXPR, mode, accum,
+! build_int_2 (log, 0), accum, 0);
+ accum = force_operand (gen_rtx (MINUS, mode, accum, op0),
+! add_target ? add_target : accum);
+ val_so_far = (val_so_far << log) - 1;
+ break;
+
+--- 2208,2232 ----
+ tem = expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (MINUS, mode, accum, tem),
+! add_target ? add_target : accum_target);
+ val_so_far -= (HOST_WIDE_INT) 1 << log;
+ break;
+
+ case alg_add_t2_m:
+ accum = expand_shift (LSHIFT_EXPR, mode, accum,
+! build_int_2 (log, 0), shift_subtarget,
+! 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, op0),
+! add_target ? add_target : accum_target);
+ val_so_far = (val_so_far << log) + 1;
+ break;
+
+ case alg_sub_t2_m:
+ accum = expand_shift (LSHIFT_EXPR, mode, accum,
+! build_int_2 (log, 0), shift_subtarget,
+! 0);
+ accum = force_operand (gen_rtx (MINUS, mode, accum, op0),
+! add_target ? add_target : accum_target);
+ val_so_far = (val_so_far << log) - 1;
+ break;
+
+***************
+*** 2200,2206 ****
+ tem = expand_shift (LSHIFT_EXPR, mode, accum,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+! add_target ? add_target : accum);
+ val_so_far += val_so_far << log;
+ break;
+
+--- 2234,2240 ----
+ tem = expand_shift (LSHIFT_EXPR, mode, accum,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+! add_target ? add_target : accum_target);
+ val_so_far += val_so_far << log;
+ break;
+
+***************
+*** 2208,2214 ****
+ tem = expand_shift (LSHIFT_EXPR, mode, accum,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (MINUS, mode, tem, accum),
+! add_target ? add_target : tem);
+ val_so_far = (val_so_far << log) - val_so_far;
+ break;
+
+--- 2242,2249 ----
+ tem = expand_shift (LSHIFT_EXPR, mode, accum,
+ build_int_2 (log, 0), NULL_RTX, 0);
+ accum = force_operand (gen_rtx (MINUS, mode, tem, accum),
+! (add_target ? add_target
+! : preserve ? 0 : tem));
+ val_so_far = (val_so_far << log) - val_so_far;
+ break;
+
+***************
+*** 3196,3198 ****
+--- 3231,3234 ----
+
+ return tem;
+ }
++
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/gcc.c gcc-2.5.8/gcc.c
+*** gcc-2.5.8.gnu/gcc.c Thu Dec 23 23:49:43 1993
+--- gcc-2.5.8/gcc.c Sun Feb 27 00:41:06 1994
+***************
+*** 586,591 ****
+--- 586,594 ----
+ "%{!S:%{!gnatc:%{!gnats:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ %{!pipe:%g.s} %A\n}}} "},
++ #ifdef CUSTOM_DEFAULT_COMPILERS
++ CUSTOM_DEFAULT_COMPILERS
++ #endif /* CUSTOM_DEFAULT_COMPILERS */
+ /* Mark end of table */
+ {0, 0}
+ };
+***************
+*** 608,614 ****
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %D %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
+ #else
+--- 611,617 ----
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %D %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
+ #else
+***************
+*** 617,623 ****
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
+ #else
+--- 620,626 ----
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
+ #else
+***************
+*** 625,631 ****
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %D %{T*} %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}}";
+ #endif
+--- 628,634 ----
+ static char *link_command_spec = "\
+ %{!fsyntax-only: \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+! %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
+ %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
+ %{L*} %D %{T*} %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}}";
+ #endif
+***************
+*** 3202,3224 ****
+ {
+ if (! strncmp (y, "-D", 2))
+ {
+! *x++ = *y++;
+! *x++ = *y++;
+
+ if (strncmp (y, "__", 2))
+ {
+ /* Stick __ at front of macro name. */
+ *x++ = '_';
+ *x++ = '_';
+- }
+-
+- /* Copy the macro name. */
+- while (*y && *y != '=' && *y != ' ' && *y != '\t')
+- *x++ = *y++;
+
+! /* Copy the value given, if any. */
+! while (*y && *y != ' ' && *y != '\t')
+! *x++ = *y++;
+ }
+ else if (*y == ' ' || *y == '\t')
+ /* Copy whitespace to the result. */
+--- 3205,3235 ----
+ {
+ if (! strncmp (y, "-D", 2))
+ {
+! y++;
+! y++;
+
+ if (strncmp (y, "__", 2))
+ {
++ *x++ = '-';
++ *x++ = 'D';
+ /* Stick __ at front of macro name. */
+ *x++ = '_';
+ *x++ = '_';
+
+! /* Copy the macro name. */
+! while (*y && *y != '=' && *y != ' ' && *y != '\t')
+! *x++ = *y++;
+!
+! /* Copy the value given, if any. */
+! while (*y && *y != ' ' && *y != '\t')
+! *x++ = *y++;
+! }
+! else
+! {
+! /* Skip this one, we have done it once already */
+! while (*y && *y != ' ' && *y != '\t')
+! y++;
+! }
+ }
+ else if (*y == ' ' || *y == '\t')
+ /* Copy whitespace to the result. */
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/gstdarg.h gcc-2.5.8/gstdarg.h
+*** gcc-2.5.8.gnu/gstdarg.h Sat Nov 13 02:53:58 1993
+--- gcc-2.5.8/gstdarg.h Sun Feb 27 00:41:06 1994
+***************
+*** 136,148 ****
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+! #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__)
+ /* The macro _VA_LIST is used in SCO Unix 3.2. */
+ #ifndef _VA_LIST
+ /* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+ #ifndef _VA_LIST_T_H
+ #define _VA_LIST_T_H
+! #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__))
+ #define _VA_LIST_
+ #endif
+ #define _VA_LIST
+--- 136,148 ----
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+! #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__FreeBSD__)
+ /* The macro _VA_LIST is used in SCO Unix 3.2. */
+ #ifndef _VA_LIST
+ /* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+ #ifndef _VA_LIST_T_H
+ #define _VA_LIST_T_H
+! #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__FreeBSD__))
+ #define _VA_LIST_
+ #endif
+ #define _VA_LIST
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/gstddef.h gcc-2.5.8/gstddef.h
+*** gcc-2.5.8.gnu/gstddef.h Fri Dec 3 12:46:59 1993
+--- gcc-2.5.8/gstddef.h Sun Feb 27 00:41:07 1994
+***************
+*** 22,28 ****
+
+ /* On 4.3bsd-net2, make sure ansi.h is included, so we have
+ one less case to deal with in the following. */
+! #if defined (__BSD_NET2__) || defined (____386BSD____)
+ #include <machine/ansi.h>
+ #endif
+
+--- 22,28 ----
+
+ /* On 4.3bsd-net2, make sure ansi.h is included, so we have
+ one less case to deal with in the following. */
+! #if defined (__BSD_NET2__) || defined (____386BSD____) || defined (__FreeBSD__)
+ #include <machine/ansi.h>
+ #endif
+
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/gvarargs.h gcc-2.5.8/gvarargs.h
+*** gcc-2.5.8.gnu/gvarargs.h Sat Nov 13 09:33:23 1993
+--- gcc-2.5.8/gvarargs.h Sun Feb 27 00:41:07 1994
+***************
+*** 150,162 ****
+ /* Michael Eriksson <mer@sics.se> at Thu Sep 30 11:00:57 1993:
+ Sequent defines _VA_LIST_ in <machine/machtypes.h> to be the type to
+ use for va_list (``typedef _VA_LIST_ va_list'') */
+! #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__)
+ /* The macro _VA_LIST is used in SCO Unix 3.2. */
+ #ifndef _VA_LIST
+ /* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+ #ifndef _VA_LIST_T_H
+ #define _VA_LIST_T_H
+! #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__))
+ #define _VA_LIST_
+ #endif
+ #define _VA_LIST
+--- 150,162 ----
+ /* Michael Eriksson <mer@sics.se> at Thu Sep 30 11:00:57 1993:
+ Sequent defines _VA_LIST_ in <machine/machtypes.h> to be the type to
+ use for va_list (``typedef _VA_LIST_ va_list'') */
+! #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)
+ /* The macro _VA_LIST is used in SCO Unix 3.2. */
+ #ifndef _VA_LIST
+ /* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+ #ifndef _VA_LIST_T_H
+ #define _VA_LIST_T_H
+! #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
+ #define _VA_LIST_
+ #endif
+ #define _VA_LIST
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/invoke.texi gcc-2.5.8/invoke.texi
+*** gcc-2.5.8.gnu/invoke.texi Thu Nov 11 14:31:43 1993
+--- gcc-2.5.8/invoke.texi Sun Feb 27 00:41:10 1994
+***************
+*** 252,258 ****
+
+ @emph{i386 Options}
+ -m486 -mno-486 -msoft-float -msvr3-shlib -mieee-fp
+! -mno-fp-ret-in-387
+
+ @emph{HPPA Options}
+ -mpa-risc-1-0
+--- 252,258 ----
+
+ @emph{i386 Options}
+ -m486 -mno-486 -msoft-float -msvr3-shlib -mieee-fp
+! -mno-fp-ret-in-387 -mno-fancy-math-387
+
+ @emph{HPPA Options}
+ -mpa-risc-1-0
+***************
+*** 3090,3095 ****
+--- 3090,3103 ----
+
+ The option @samp{-mno-fp-ret-in-387} causes such values to be returned
+ in ordinary CPU registers instead.
++
++ @item -mno-fancy-math-387
++ Do not generate sin, cos and sqrt instructions to the 387.
++
++ Some 387-emulators are less complete than one would expect, and usually
++ the hard parts are missing, this option fixes one such case for the
++ FreeBSD OS, where this option is set as default.
++
+ @c FIXME!! What about these options listed in @node Option Summary ??
+ @c -msvr3-shlib -mieee-fp
+ @end table
+diff -C3 -r --unidirectional-new-file gcc-2.5.8.gnu/objc/objects.c gcc-2.5.8/objc/objects.c
+*** gcc-2.5.8.gnu/objc/objects.c Thu Nov 18 09:07:33 1993
+--- gcc-2.5.8/objc/objects.c Sun Feb 27 00:41:11 1994
+***************
+*** 24,30 ****
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+! #include "../tconfig.h" /* include defs of bzero for target */
+ #include "runtime.h" /* the kitchen sink */
+
+ id __objc_object_alloc(Class*);
+--- 24,30 ----
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+! #include "tconfig.h" /* include defs of bzero for target */
+ #include "runtime.h" /* the kitchen sink */
+
+ id __objc_object_alloc(Class*);
diff --git a/gnu/usr.bin/cc25/gnu2bsd.tcl b/gnu/usr.bin/cc25/gnu2bsd.tcl
new file mode 100755
index 000000000000..66644f028e30
--- /dev/null
+++ b/gnu/usr.bin/cc25/gnu2bsd.tcl
@@ -0,0 +1,470 @@
+#!/usr/local/bin/tclsh
+#
+# This Tcl script tries to build a GCC-source in a BSD-structured tree from
+# the GNU-structured one. This code isn't for people with faint hearts.
+#
+# "Med dens egne Vaaben skal jeg tugte Hoben,
+# som med Skrig og Raaben bryder Byens Fred.
+# Se engang til Taaben,
+# som med Munden aaben glor paa mig med Maaben."
+#
+# Fra Carl Nielsens "Maskerade".
+#
+# To change something in gcc for FreeBSD use this plan:
+# 1. modify the GNU-gcc distribution as needed.
+# 2. modify this script as needed.
+# 3. run this script
+# 4. try the result, goto 1 until you got it right.
+# 5. send a patch to the GNU people !
+#
+# Written Jan/Feb 1994 by Poul-Henning Kamp <phk@login.dkuug.dk>
+# For FreeBSD 1.0 and 1.1 versus GCC 2.5.8
+# Also seems to work for GCC.2.4.5
+#
+# In case GNU changes the setup of their tree (again), this code will loose
+# badly. I have parameterized as much as possible, but a lot of Makefiles
+# get made inline in the code. Good luck.
+#############################################################################
+# Tweakable things, set for GCC 2.5.8, below they can be enabled for 2.4.5
+
+# TWEAK: Which GCC version ?
+set ver 2.5.8
+
+# TWEAK: Where is the GNU-tree ?
+set gnu /phk/tmp/gcc-2.5.8
+
+# TWEAK: Where is the BSD-tree ?
+set bsd .
+
+# TWEAK: Whats the names in the GNU Makefile of the programs.
+set pgm {cc1 cc1plus cc1obj cccp xgcc g++}
+
+# TWEAK: Where should the programs be installed
+set pgm_install(cc1) /usr/libexec/cc1
+set pgm_install(cc1plus) /usr/libexec/cc1plus
+set pgm_install(cc1obj) /usr/libexec/cc1obj
+set pgm_install(cccp) /usr/libexec/cpp
+set pgm_install(xgcc) /usr/bin/gcc
+set pgm_install(g++) /usr/bin/g++
+
+# TWEAK: What links to make to each program
+set pgm_link(xgcc) /usr/bin/cc
+set pgm_link(g++) /usr/bin/c++
+set pgm_link(cccp) { /usr/libexec/gccp }
+
+# TWEAK: What is the man.1 file named in the GNU-dist
+set pgm_man1(xgcc) gcc.1
+set pgm_man1(g++) g++.1
+set pgm_man1(cccp) cccp.1
+
+# TWEAK: What names should the man-page be installed under
+set pgm_dst1(xgcc) {gcc.1 cc.1}
+set pgm_dst1(g++) {g++.1 c++.1}
+set pgm_dst1(cccp) {cpp.1}
+
+# TWEAK: What files must be explicitly installed ?
+set config {i386/gstabs.h i386/perform.h i386/gas.h i386/i386.h i386/bsd.h
+ i386/freebsd.h i386/unix.h cp-input.c bc-opcode.h bc-arity.h
+ config.status md insn-attr.h insn-flags.h insn-codes.h c-parse.h}
+
+
+############################################################################
+# For gcc-2.4.5 we simply overwrite some of the tweaks...
+
+if {$ver == "2.4.5"} {
+ set gnu /usr/tmp/gcc-2.4.5
+ set bsd cc245
+ set pgm {cc1 cc1plus cc1obj cccp xgcc}
+ set config {i386/gstabs.h i386/perform.h i386/gas.h i386/i386.h i386/bsd.h
+ i386/386bsd.h i386/unix.h cp-input.c config.status md insn-attr.h
+ insn-flags.h insn-codes.h c-parse.h}
+}
+
+############################################################################
+
+# Try to make the GNU-Makefile produce a file for us.
+proc makefile {name} {
+ global gnu
+ puts "------> Trying to make $name <-----"
+ flush stdout
+ catch {exec sh -c "cd $gnu ; make $name" >&@ stdout}
+}
+
+# Locate a source file, possibly making it on the fly.
+proc find_source {name} {
+ global gnu
+ set n1 $name
+ regsub {\.o$} $n1 {.c} n1
+ if {[file exists $gnu/$n1]} {return $n1}
+ makefile $n1
+ if {[file exists $gnu/$n1]} {return $n1}
+ makefile $name
+ if {[file exists $gnu/$n1]} {return $n1}
+ puts stderr "
+find_source cannot locate or make a \"$n1\" for \"$name\"
+"
+ exit 1
+}
+
+# Define a macro in a makefile, to contain MANY files.
+proc write_names {fd mac lst {suf ""}} {
+ set lst [lsort $lst]
+ set a "$mac =\t"
+ for {set i 0} {$i < [llength $lst]} {} {
+ set j [lindex $lst $i]$suf
+ if {[string length $a]+[string length $j]+1 < 68} {
+ lappend a $j
+ incr i
+ continue;
+ }
+ puts $fd "$a \\"
+ set a "\t"
+ }
+ puts $fd "$a"
+}
+
+############################################################################
+#
+# "Som en Samson skal jeg samle
+# Kraften i mit Styrkebaelte,
+# jeg skal gaa til deres Telte,
+# deres Stoetter skal jeg vaelte,
+# deres Tag skal sammen ramle,
+# om i Moerket skal de famle,
+# deres Knokkelrad skal skramle,
+# deres Rygmarv skal jeg smaelte,
+# deres Hjerne skal jeg aelte !"
+#
+# Fra Carl Nielsens "Maskerade".
+
+puts "2bsd from $gnu to $bsd"
+
+puts "Remove old directories if any, and create new ones."
+
+# In case the BSD dir isn't there:
+catch {exec mkdir $bsd}
+
+# Throw the BSD/gcc_int dir away, and make a fresh.
+catch {exec sh -c "rm -rf $bsd/gcc_int ; mkdir $bsd/gcc_int $bsd/gcc_int/i386"}
+
+# Throw the BSD/libgcc dir away, and make a fresh.
+catch {exec sh -c "rm -rf $bsd/libgcc ; mkdir $bsd/libgcc"}
+
+# Throw the BSD/libobjc dir away, and make a fresh.
+catch {exec sh -c "rm -rf $bsd/libobjc ; mkdir $bsd/libobjc"}
+
+# Throw the BSD/$pgm dirs away too, and make some fresh.
+foreach i $pgm {catch {exec sh -c "rm -rf $bsd/$i ; mkdir $bsd/$i"}}
+
+puts "Check that $gnu directory is configured."
+
+# configure makes this file, which we can use to check
+if {![file exists $gnu/config.status]} {
+ puts stderr "
+Please go to the $gnu directory and execute these two commands:
+ make distclean
+ configure
+Then restart this program.
+"
+ exit 1
+}
+
+if 1 {
+# XXX
+puts "Create $bsd/libgcc"
+
+# Make a temporary Makefile in the GNU-tree
+exec cp $gnu/Makefile $gnu/2bsd.t02
+
+# Add targets to tell us what we want to know
+set fi [open $gnu/2bsd.t02 a]
+puts $fi "\nFo1:\n\t@echo \$(LIB1FUNCS)"
+puts $fi "\nFo2:\n\t@echo \$(LIB2FUNCS)"
+close $fi
+
+# Try it out...
+set t01 [exec sh -c "( cd $gnu ; make -f 2bsd.t02 Fo1)"]
+set t02 [exec sh -c "( cd $gnu ; make -f 2bsd.t02 Fo2)"]
+
+# Remove it again
+exec rm -f $gnu/2bsd.t02
+
+# Copy the sources
+exec cp $gnu/libgcc1.c $gnu/libgcc2.c $bsd/libgcc
+
+# Create the Makefile
+set fo [open $bsd/libgcc/Makefile w]
+puts $fo {
+LIB = gcc
+NOPROFILE = 1
+SHLIB_MAJOR= 1
+SHLIB_MINOR= 0
+
+CFLAGS += -I$(.CURDIR)/../gcc_int -DFREEBSD_NATIVE
+}
+
+write_names $fo LIB1OBJS $t01 .o
+write_names $fo LIB2OBJS $t02 .o
+puts $fo {
+OBJS= ${LIB1OBJS} ${LIB2OBJS}
+LIB1SOBJS=${LIB1OBJS:.o=.so}
+LIB2SOBJS=${LIB2OBJS:.o=.so}
+
+${LIB1OBJS}: libgcc1.c
+ ${CC} -c ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+${LIB2OBJS}: libgcc2.c
+ ${CC} -c ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.if !defined(NOPIC)
+${LIB1SOBJS}: libgcc1.c
+ ${CC} -c -fpic ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
+
+${LIB2SOBJS}: libgcc2.c
+ ${CC} -c -fpic ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
+.endif
+
+.include <bsd.lib.mk>
+}
+
+close $fo
+
+# Try to find out which .o files goes into which programs.
+foreach i $pgm {
+
+ puts "Disecting $i."
+
+ # Try to snatch the link-stmt from the GNU-Makefile
+ set t01 [exec grep " *-o *$i *" $gnu/Makefile]
+
+ # Make a temporary Makefile in the GNU-tree
+ exec cp $gnu/Makefile $gnu/2bsd.t02
+
+ # Add a target to tell us what we want to know
+ set fi [open $gnu/2bsd.t02 a]
+ puts $fi "\nFoO:\n\t@echo $t01"
+ close $fi
+
+ # Try it out...
+ set t02 [exec sh -c "( cd $gnu ; make -f 2bsd.t02 FoO)"]
+
+ # Remove it again
+ exec rm -f $gnu/2bsd.t02
+
+ # Extract the .o files from it.
+ set o ""
+ foreach j $t02 {
+ if {[regexp {\.o$} $j]} {
+ lappend o $j
+ # count the number of times each is used.
+ if {[catch {incr t04($j)} x]} {set t04($j) 1}
+ }
+ # Save that goes into this program
+ set t05($i) $o
+ }
+}
+
+# get a sorted list of all known objects
+set l [lsort [array names t04]]
+
+puts "Copy source files to $bsd/gcc_int"
+
+# What goes into the libgcc_int ?
+set lib ""
+foreach i $l {
+ # Used more than once, and we take it.
+ if {$t04($i) > 1} {
+ set s [find_source $i]
+ lappend lib $s
+ # Copy the file
+ exec cp $gnu/$s $bsd/gcc_int
+ }
+}
+
+puts "Creating Makefile in $bsd/gcc_int"
+set fo [open $bsd/gcc_int/Makefile w]
+
+# Define SRCS to all the sourcefiles.
+write_names $fo SRCS $lib
+
+# Put the rest in there.
+set lv [split $ver .]
+
+# Shared-lib code-gen. Will not work without much coding.
+#puts $fo "SHLIB_MAJOR = [format %d%02d [lindex $lv 0] [lindex $lv 1]]"
+#puts $fo "SHLIB_MINOR = [lindex $lv 2]"
+# REQ's patch to /usr/share/mk/bsd.lib.mk XXX
+#puts $fo "NOSTATIC = 1"
+
+puts $fo {
+LIB = gcc_int
+NOPROFILE = 1
+CFLAGS += -I$(.CURDIR) -DFREEBSD_NATIVE
+
+install:
+ @true
+
+.include <bsd.lib.mk>
+
+}
+close $fo
+
+# Now for each of the programs in turn
+foreach i $pgm {
+ puts "Copy source files to $bsd/$i"
+ set o ""
+ foreach j $t05($i) {
+ if {$t04($j) == 1} {
+ set s [find_source $j]
+ lappend o $s
+ exec cp $gnu/$s $bsd/$i
+ }
+ }
+
+ puts "Creating Makefile in $bsd/$i"
+
+ set fo [open $bsd/$i/Makefile w]
+ write_names $fo SRCS $o
+ puts $fo "PROG =\t$i"
+ puts $fo {
+.if exists($(.CURDIR)/../gcc_int/obj)
+DPADD += $(.CURDIR)/../gcc_int/obj/libgcc_int.a
+LDADD += -L$(.CURDIR)/../gcc_int/obj -lgcc_int
+.else
+DPADD += $(.CURDIR)/../gcc_int/libgcc_int.a
+LDADD += -L$(.CURDIR)/../gcc_int -lgcc_int
+.endif
+
+LDADD+= -lgnumalloc -static
+DPADD+= ${LIBGNUMALLOC}
+
+CFLAGS += -I$(.CURDIR)/../gcc_int -DFREEBSD_NATIVE
+}
+
+ if {[catch {set pgm_install($i)} x]} {
+ puts stderr "Needs to know where to install $i, pgm_install wont tell us."
+ exit 1
+ }
+ puts $fo "\ninstall: $i\n\t\install \$(COPY) -o \${BINOWN} -g \${BINGRP} -m \${BINMODE} $i \$(DESTDIR)$pgm_install($i)"
+ if {![catch {set pgm_link($i)} x]} {
+ foreach j $x {
+ puts $fo "\t@rm -f \$(DESTDIR)$j"
+ puts $fo "\t@ln -s `basename $pgm_install($i)` \$(DESTDIR)$j"
+ }
+ }
+ if {![catch {set pgm_man1($i)} x]} {
+ exec cp $gnu/$x $bsd/$i/$i.1
+ if {[catch {set pgm_dst1($i)} x]} {
+ puts stderr "Needs to know where to install manpage for $i, pgm_dst1 wont tell us."
+ exit 1
+ }
+ puts $fo "\t\install \$(COPY) -m \$(MANMODE) -o \$(MANOWN) -g \$(MANGRP) \$(.CURDIR)/$i.1 \$(DESTDIR)/usr/share/man/man1/[lindex $x 0]"
+ foreach j [lrange $x 1 end] {
+ puts $fo "\trm -f \$(DESTDIR)/usr/share/man/man1/$j"
+ puts $fo "\tln -s [lindex $x 0] \$(DESTDIR)/usr/share/man/man1/$j"
+ }
+ }
+ puts $fo ""
+ puts $fo {.include <bsd.prog.mk>}
+
+ close $fo
+}
+
+puts "Copy config files to $bsd/gcc_int"
+
+# Get everything ending in .h and .def
+exec sh -c "cp $gnu/*.h $gnu/*.def $bsd/gcc_int"
+
+# Get anything still missing
+foreach s $config {
+ # Try to copy right away
+ if {![catch {exec cp $gnu/$s $bsd/gcc_int/$s} x]} continue
+ # Try to copy from below the config subdir
+ if {![catch {exec cp $gnu/config/$s $bsd/gcc_int/$s} x]} continue
+ # Try to make the file then...
+ makefile $s
+ if {![catch {exec cp $gnu/$s $bsd/gcc_int/$s} x]} continue
+ # Too BAD.
+ puts stderr "I'm having troble finding the \"config\" file $s"
+ exit 1
+}
+}
+
+puts "Create $bsd/libobjc"
+
+# Make a temporary Makefile in the GNU-tree
+exec cp $gnu/objc/Makefile $gnu/objc/2bsd.t02
+
+puts "Squeeze Makefile"
+
+# Add targets to tell us what we want to know
+set fi [open $gnu/objc/2bsd.t02 a]
+puts $fi "\nFo1:\n\t@echo \$(OBJC_O)"
+puts $fi "\nFo2:\n\t@echo \$(OBJC_H)"
+close $fi
+
+# Try it out...
+set t01 [exec sh -c "( cd $gnu/objc ; make -f 2bsd.t02 Fo1)"]
+set t02 [exec sh -c "( cd $gnu/objc ; make -f 2bsd.t02 Fo2)"]
+
+# Remove it again
+exec rm -f $gnu/objc/2bsd.t02
+
+puts "Copy sources"
+set l ""
+foreach i $t01 {
+ regsub {\.o} $i {} j
+ if {[file exists $gnu/objc/$j.m]} {
+ lappend l $j.m
+ exec cp $gnu/objc/$j.m $bsd/libobjc
+ } elseif {[file exists $gnu/objc/$j.c]} {
+ lappend l $j.c
+ exec cp $gnu/objc/$j.c $bsd/libobjc
+ } else {
+ puts stderr "Cannot locate source for objc/$i"
+ exit 1
+ }
+}
+
+puts "Copy includes"
+exec sh -c "cp $gnu/objc/*.h $bsd/libobjc"
+
+# This is a trick to make #include <objc/...> work here.
+exec sh -c "ln -s . $bsd/libobjc/objc"
+
+puts "Create Makefile"
+set fo [open $bsd/libobjc/Makefile w]
+puts $fo {
+
+LIB = objc
+}
+write_names $fo SRCS $l
+write_names $fo HDRS $t02
+puts $fo {
+CFLAGS += -I${.CURDIR} -I${.CURDIR}/../gcc_int
+
+.include <bsd.lib.mk>
+
+.SUFFIXES: .m
+
+.m.o:
+ $(CC) -fgnu-runtime -c $(CFLAGS) $<
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.m.po:
+ $(CC) -p -fgnu-runtime -c $(CFLAGS) -o ${.TARGET} $<
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+afterinstall:
+ rm -rf /usr/include/objc
+ mkdir /usr/include/objc
+ cd $(.CURDIR) ; install $(COPY) -o ${BINOWN} -g ${BINGRP} -m 444 $(HDRS) $(DESTDIR)/usr/include/objc
+}
+
+close $fo
diff --git a/gnu/usr.bin/cc25/usr.bin.cpp/Makefile b/gnu/usr.bin/cc25/usr.bin.cpp/Makefile
new file mode 100644
index 000000000000..eac1bec4dae0
--- /dev/null
+++ b/gnu/usr.bin/cc25/usr.bin.cpp/Makefile
@@ -0,0 +1,10 @@
+
+install:
+ install -c -o $(BINOWN) -g $(BINGRP) -m $(BINMODE) \
+ $(.CURDIR)/cpp.script $(DESTDIR)/usr/bin/cpp
+ @/bin/rm -rf $(DESTDIR)/usr/bin/gcpp
+ @cd $(DESTDIR)/usr/bin; ln -s cpp gcpp
+ @echo $(DESTDIR)/usr/bin/gcpp -\> $(DESTDIR)/usr/bin/cpp
+
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc25/usr.bin.cpp/cpp.script b/gnu/usr.bin/cc25/usr.bin.cpp/cpp.script
new file mode 100644
index 000000000000..b95b36fde8cc
--- /dev/null
+++ b/gnu/usr.bin/cc25/usr.bin.cpp/cpp.script
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# Copyright (c) 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# the Systems Programming Group of the University of Utah Computer
+# Science Department.
+#
+# 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.
+#
+# @(#)usr.bin.cpp.sh 6.5 (Berkeley) 4/1/91
+#
+# Transitional front end to CCCP to make it behave like (Reiser) CCP:
+# specifies -traditional
+# doesn't search gcc-include
+#
+PATH=/usr/bin:/bin
+CPP=/usr/libexec/cpp
+ALST="-traditional -D__GNUC__ -$ "
+NSI=no
+OPTS=""
+INCS="-nostdinc"
+FOUNDFILES=no
+
+for A
+do
+ case $A in
+ -nostdinc)
+ NSI=yes
+ ;;
+ -traditional)
+ ;;
+ -I*)
+ INCS="$INCS $A"
+ ;;
+ -U__GNUC__)
+ ALST=`echo $ALST | sed -e 's/-D__GNUC__//'`
+ ;;
+ -*)
+ OPTS="$OPTS '$A'"
+ ;;
+ *)
+ FOUNDFILES=yes
+ if [ $NSI = "no" ]
+ then
+ INCS="$INCS -I/usr/include"
+ NSI=skip
+ fi
+ eval $CPP $ALST $INCS $LIBS $CSU $OPTS $A || exit $?
+ ;;
+ esac
+done
+
+if [ $FOUNDFILES = "no" ]
+then
+ # read standard input
+ if [ $NSI = "no" ]
+ then
+ INCS="$INCS -I/usr/include"
+ fi
+ eval exec $CPP $ALST $INCS $LIBS $CSU $OPTS
+fi
+
+exit 0
diff --git a/gnu/usr.bin/cc25/usr.bin.f77/Makefile b/gnu/usr.bin/cc25/usr.bin.f77/Makefile
new file mode 100644
index 000000000000..9b5117d7b380
--- /dev/null
+++ b/gnu/usr.bin/cc25/usr.bin.f77/Makefile
@@ -0,0 +1,7 @@
+
+install:
+ install -c -o $(BINOWN) -g $(BINGRP) -m $(BINMODE) \
+ $(.CURDIR)/f77.script $(DESTDIR)/usr/bin/f77
+
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc25/usr.bin.f77/f77.script b/gnu/usr.bin/cc25/usr.bin.f77/f77.script
new file mode 100644
index 000000000000..f218a03d9625
--- /dev/null
+++ b/gnu/usr.bin/cc25/usr.bin.f77/f77.script
@@ -0,0 +1,114 @@
+#!/bin/sh
+# Compile Fortran code, adding -lf2c.
+# This is a slightly modified g++ script.
+
+: || exec /bin/sh -f $0 $argv:q
+
+# The compiler name might be different when doing cross-compilation
+# (this should be configured)
+gcc_name=gcc
+speclang=-xnone
+
+# replace the command name by the name of the new command
+progname=`basename $0`
+case "$0" in
+ */*)
+ gcc=`echo $0 | sed -e "s;/[^/]*$;;"`/$gcc_name
+ ;;
+ *)
+ gcc=$gcc_name
+ ;;
+esac
+
+# $first is yes for first arg, no afterwards.
+first=yes
+# If next arg is the argument of an option, $quote is non-empty.
+# More precisely, it is the option that wants an argument.
+quote=
+# $library is made empty to disable use of libf2c.
+#library=-lF77 -lI77 -lm
+library="-lf2c -lm"
+numargs=$#
+
+# ash requires the newline before `do'.
+for arg
+do
+ if [ $first = yes ]
+ then
+ # Need some 1st arg to `set' which does not begin with `-'.
+ # We get rid of it after the loop ends.
+ set gcc
+ first=no
+ fi
+ # If you have to ask what this does, you should not edit this file. :-)
+ # The ``S'' at the start is so that echo -nostdinc does not eat the
+ # -nostdinc.
+ arg=`echo "S$arg" | sed "s/^S//; s/'/'\\\\\\\\''/g"`
+ if [ x$quote != x ]
+ then
+ quote=
+ else
+ quote=
+ case $arg in
+ -nostdlib)
+ # Inhibit linking with -lf2c.
+ library=
+ ;;
+ -lm | -lmath)
+ # Because libf2c uses things from the math library, make sure it
+ # always comes before the math library. We recognize both -lm
+ # and -lmath, since on some systems (e.g. m88k SVR3), it
+ # doesn't call it libm.a for some reason.
+ #set "$@" $library
+ #library=""
+ ;;
+ -[bBVDUoeTuIYmLiA] | -Tdata)
+ # these switches take following word as argument,
+ # so don't treat it as a file name.
+ quote=$arg
+ ;;
+ -[cSEM] | -MM)
+ # Don't specify libraries if we won't link,
+ # since that would cause a warning.
+ library=
+ ;;
+ -x*)
+ speclang=$arg
+ ;;
+ -v)
+ # catch `f77 -v'
+ if [ $numargs = 1 ] ; then library="" ; fi
+ ;;
+ -*)
+ # Pass other options through; they don't need -x and aren't inputs.
+ ;;
+ *)
+ # If file ends in .i, put options around it.
+ # But not if a specified -x option is currently active.
+ case "$speclang $arg" in -xnone\ *.i)
+ set "$@" -xf2c "'$arg'" -xnone
+ continue
+ esac
+ ;;
+ esac
+ fi
+ set "$@" "'$arg'"
+done
+
+# Get rid of that initial 1st arg
+if [ $first = no ]; then
+ shift
+else
+ echo "$0: No input files specified."
+ exit 1
+fi
+
+if [ x$quote != x ]
+then
+ echo "$0: argument to \`$quote' missing"
+ exit 1
+fi
+
+eval $gcc "$@" $library
+
+
diff --git a/gnu/usr.bin/cvs/cvs/Makefile b/gnu/usr.bin/cvs/cvs/Makefile
index be35c2f95f62..6af8b8132594 100644
--- a/gnu/usr.bin/cvs/cvs/Makefile
+++ b/gnu/usr.bin/cvs/cvs/Makefile
@@ -1,4 +1,9 @@
+.if !defined(FREEBSD_DEVELOPER)
PROG = cvs
+.else
+PROG = ncvs
+.endif
+
CFLAGS += -I${.CURDIR}/../lib \
-DDIRENT -DSTDC_HEADERS -DPOSIX -DBROKEN_SIGISMEMBER \
-DFTIME_MISSING -DHAVE_TIMEZONE -DUTIME_NULL_MISSING
@@ -9,6 +14,12 @@ LDADD= -L${.CURDIR}/../lib/obj -lcvs
LDADD= -L${.CURDIR}/../lib/ -lcvs
.endif
+.if defined(FREEBSD_DEVELOPER)
+CFLAGS+= -DFREEBSD_DEVELOPER
+BINGRP= ncvs
+#BINMODE=2555
+.endif
+
SRCS = add.c admin.c checkin.c checkout.c classify.c commit.c \
create_adm.c diff.c entries.c find_names.c history.c ignore.c \
import.c lock.c log.c logmsg.c main.c rcs.c modules.c \
diff --git a/gnu/usr.bin/cvs/cvs/checkin.c b/gnu/usr.bin/cvs/cvs/checkin.c
index 14f7c055e2ae..44b733e970bc 100644
--- a/gnu/usr.bin/cvs/cvs/checkin.c
+++ b/gnu/usr.bin/cvs/cvs/checkin.c
@@ -65,8 +65,15 @@ Checkin (type, file, repository, rcs, rev, tag, message, entries)
*/
/* XXX - make sure -k options are used on the co; and tag/date? */
+#ifdef FREEBSD_DEVELOPER
+ run_setup ("%s%s -q %s%s %s", Rcsbin, RCS_CO,
+ rev ? "-r" : "", rev ? rev : "",
+ freebsd ? "-KeAuthor,Date,Header,Id,Locker,Log,"
+ "RCSfile,Revision,Source,State -KiFreeBSD" : "");
+#else
run_setup ("%s%s -q %s%s", Rcsbin, RCS_CO,
rev ? "-r" : "", rev ? rev : "");
+#endif /* FREEBSD_DEVELOPER */
run_arg (rcs);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
xchmod (file, 1);
diff --git a/gnu/usr.bin/cvs/cvs/checkout.c b/gnu/usr.bin/cvs/cvs/checkout.c
index ad5a5b8115af..e7bc60818787 100644
--- a/gnu/usr.bin/cvs/cvs/checkout.c
+++ b/gnu/usr.bin/cvs/cvs/checkout.c
@@ -70,6 +70,7 @@ static char *checkout_usage[] =
"\t-r rev\tCheck out revision or tag. (implies -P)\n",
"\t-D date\tCheck out revisions as of date. (implies -P)\n",
"\t-d dir\tCheck out into dir instead of module name.\n",
+ "\t-K key\tUse RCS key -K option on checkout.\n",
"\t-k kopt\tUse RCS kopt -k option on checkout.\n",
"\t-j rev\tMerge in changes made between current revision and rev.\n",
NULL
@@ -100,6 +101,7 @@ static char *date = NULL;
static char *join_rev1 = NULL;
static char *join_rev2 = NULL;
static char *preload_update_dir = NULL;
+static char *K_flag = NULL;
int
checkout (argc, argv)
@@ -129,7 +131,7 @@ checkout (argc, argv)
}
else
{
- valid_options = "ANnk:d:flRpQqcsr:D:j:P";
+ valid_options = "ANnk:d:flRpQqcsr:D:j:PK:";
valid_usage = checkout_usage;
}
@@ -207,6 +209,9 @@ checkout (argc, argv)
else
join_rev1 = optarg;
break;
+ case 'K':
+ K_flag = optarg;
+ break;
case '?':
default:
usage (valid_usage);
@@ -216,6 +221,12 @@ checkout (argc, argv)
argc -= optind;
argv += optind;
+#ifdef FREEBSD_DEVELOPER
+ if (!K_flag && freebsd) {
+ /* XXX Note: The leading -K is not needed, it gets added later! */
+ K_flag = "eAuthor,Date,Header,Id,Locker,Log,RCSfile,Revision,Source,State -KiFreeBSD";
+ }
+#endif /* FREEBSD_DEVELOPER */
if (shorten == -1)
shorten = 0;
@@ -597,6 +608,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
force_tag_match, 0 /* !local */ ,
1 /* update -d */ , aflag, checkout_prune_dirs,
pipeout, which, join_rev1, join_rev2,
+ K_flag,
preload_update_dir);
free (preload_update_dir);
preload_update_dir = oldupdate;
@@ -639,7 +651,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
err += do_update (*pargc - 1, argv + 1, options, tag, date,
force_tag_match, local_specified, 1 /* update -d */,
aflag, checkout_prune_dirs, pipeout, which, join_rev1,
- join_rev2, preload_update_dir);
+ join_rev2, K_flag, preload_update_dir);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (err);
diff --git a/gnu/usr.bin/cvs/cvs/cvs.h b/gnu/usr.bin/cvs/cvs/cvs.h
index ec47581143de..3e1f8f457782 100644
--- a/gnu/usr.bin/cvs/cvs/cvs.h
+++ b/gnu/usr.bin/cvs/cvs/cvs.h
@@ -257,6 +257,9 @@ extern int cvswrite;
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
extern int logoff; /* Don't write history entry */
+#ifdef FREEBSD_DEVELOPER
+extern int freebsd; /* Assume option defaults for FreBSD */
+#endif /* FREEBSD_DEVELOPER */
/* Externs that are included directly in the CVS sources */
#if __STDC__
@@ -348,7 +351,8 @@ int do_recursion (int (*xfileproc) (), int (*xfilesdoneproc) (),
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_rev2, char *preload_update_dir);
+ char *xjoin_rev1, char *xjoin_rev2,
+ char *xK_flag, char *preload_update_dir);
void history_write (int type, char *update_dir, char *revs, char *name,
char *repository);
int start_recursion (int (*fileproc) (), int (*filesdoneproc) (),
diff --git a/gnu/usr.bin/cvs/cvs/diff.c b/gnu/usr.bin/cvs/cvs/diff.c
index db8b4b746e8d..003c2e3c602a 100644
--- a/gnu/usr.bin/cvs/cvs/diff.c
+++ b/gnu/usr.bin/cvs/cvs/diff.c
@@ -22,6 +22,7 @@ static char rcsid[] = "@(#)diff.c 1.52 92/04/10";
#if __STDC__
static Dtype diff_dirproc (char *dir, char *pos_repos, char *update_dir);
+static int diff_filesdoneproc (int err, char *repos, char *update_dir);
static int diff_dirleaveproc (char *dir, int err, char *update_dir);
static int diff_file_nodiff (char *file, char *repository, List *entries,
List *srcfiles, Vers_TS *vers);
@@ -31,6 +32,7 @@ static void diff_mark_errors (int err);
#else
static int diff_fileproc ();
static Dtype diff_dirproc ();
+static int diff_filesdoneproc ();
static int diff_dirleaveproc ();
static int diff_file_nodiff ();
static void diff_mark_errors ();
@@ -151,7 +153,7 @@ diff (argc, argv)
options = xstrdup ("");
/* start the recursion processor */
- err = start_recursion (diff_fileproc, (int (*) ()) NULL, diff_dirproc,
+ err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
diff_dirleaveproc, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1);
@@ -226,7 +228,14 @@ diff_fileproc (file, update_dir, repository, entries, srcfiles)
return (0);
}
+ /* Output an "Index:" line for patch to use */
(void) fflush (stdout);
+ if (update_dir[0])
+ (void) printf ("Index: %s/%s\n", update_dir, file);
+ else
+ (void) printf ("Index: %s\n", file);
+ (void) fflush (stdout);
+
if (use_rev2)
{
run_setup ("%s%s %s %s -r%s -r%s", Rcsbin, RCS_DIFF,
@@ -288,7 +297,20 @@ diff_dirproc (dir, pos_repos, update_dir)
}
/*
- * Concoct the proper exit status.
+ * Concoct the proper exit status - done with files
+ */
+/* ARGSUSED */
+static int
+diff_filesdoneproc (err, repos, update_dir)
+ int err;
+ char *repos;
+ char *update_dir;
+{
+ return (diff_errors);
+}
+
+/*
+ * Concoct the proper exit status - leaving directories
*/
/* ARGSUSED */
static int
diff --git a/gnu/usr.bin/cvs/cvs/ignore.c b/gnu/usr.bin/cvs/cvs/ignore.c
index 74ab90c785ad..823648786c60 100644
--- a/gnu/usr.bin/cvs/cvs/ignore.c
+++ b/gnu/usr.bin/cvs/cvs/ignore.c
@@ -147,7 +147,7 @@ ign_add (ign, hold)
* (saving it if necessary). We also catch * as a special case in a
* global ignore file as an optimization
*/
- if (isspace (*(ign + 1)) && (*ign == '!' || *ign == '*'))
+ if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
{
if (!hold)
{
diff --git a/gnu/usr.bin/cvs/cvs/import.c b/gnu/usr.bin/cvs/cvs/import.c
index 095a80042f07..288b9b265ba7 100644
--- a/gnu/usr.bin/cvs/cvs/import.c
+++ b/gnu/usr.bin/cvs/cvs/import.c
@@ -330,10 +330,14 @@ import_descend (message, vtag, targc, targv)
{
while ((dp = readdir (dirp)) != NULL)
{
- if (ign_name (dp->d_name) || !isdir (dp->d_name))
+ if (!strcmp(".", dp->d_name) || !strcmp("..", dp->d_name))
+ continue;
+ if (!isdir (dp->d_name) || ign_name (dp->d_name))
continue;
err += import_descend_dir (message, dp->d_name,
vtag, targc, targv);
+ /* need to re-load .cvsignore after each dir traversal */
+ ign_add_file (CVSDOTIGNORE, 1);
}
(void) closedir (dirp);
}
diff --git a/gnu/usr.bin/cvs/cvs/main.c b/gnu/usr.bin/cvs/cvs/main.c
index 03f4a2ca85c9..d6ad2584327a 100644
--- a/gnu/usr.bin/cvs/cvs/main.c
+++ b/gnu/usr.bin/cvs/cvs/main.c
@@ -93,6 +93,10 @@ int tag ();
int update ();
#endif /* __STDC__ */
+#ifdef FREEBSD_DEVELOPER
+int freebsd = TRUE; /* Use the FreeBSD -K flags!! */
+#endif
+
struct cmd
{
char *fullname; /* Full name of the function (e.g. "commit") */
@@ -137,6 +141,9 @@ static char *usg[] =
" -b bindir Find RCS programs in 'bindir'\n",
" -e editor Use 'editor' for editing log information\n",
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n",
+#ifdef FREEBSD_DEVELOPER
+ " -x Do NOT use the FreeBSD -K default flags\n",
+#endif
"\n",
" and where 'command' is:\n",
" add Adds a new file/directory to the repository\n",
@@ -209,7 +216,11 @@ main (argc, argv)
cvswrite = FALSE;
optind = 1;
+#ifdef FREEBSD_DEVELOPER
+ while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:Hx")) != -1)
+#else
while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:H")) != -1)
+#endif /* FREEBSD_DEVELOPER */
{
switch (c)
{
@@ -255,6 +266,11 @@ main (argc, argv)
case 'H':
help = TRUE;
break;
+#ifdef FREEBSD_DEVELOPER
+ case 'x':
+ freebsd = FALSE;
+ break;
+#endif /* FREEBSD_DEVELOPER */
case '?':
default:
usage (usg);
diff --git a/gnu/usr.bin/cvs/cvs/patch.c b/gnu/usr.bin/cvs/cvs/patch.c
index 11134a714989..abc02fd73936 100644
--- a/gnu/usr.bin/cvs/cvs/patch.c
+++ b/gnu/usr.bin/cvs/cvs/patch.c
@@ -43,6 +43,8 @@ static char *rev1 = NULL;
static char *rev2 = NULL;
static char *date1 = NULL;
static char *date2 = NULL;
+static char *K_flag1 = NULL;
+static char *K_flag2 = NULL;
static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1];
static int unidiff = 0;
@@ -60,6 +62,7 @@ static char *patch_usage[] =
"\t-D date\tDate.\n",
"\t-r rev\tRevision - symbolic or numeric.\n",
"\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n",
+ "\t-K key\tUse RCS key -K option on checkout.\n",
NULL
};
@@ -77,7 +80,7 @@ patch (argc, argv)
usage (patch_usage);
optind = 1;
- while ((c = gnu_getopt (argc, argv, "V:k:cuftsQqlRD:r:")) != -1)
+ while ((c = gnu_getopt (argc, argv, "V:k:cuftsQqlRD:r:K:")) != -1)
{
switch (c)
{
@@ -139,6 +142,14 @@ patch (argc, argv)
case 'c': /* Context diff */
unidiff = 0;
break;
+ case 'K':
+ if (K_flag2 != NULL)
+ error (1, 0, "no more than two -K flags can be specified");
+ if (K_flag1 != NULL)
+ K_flag2 = optarg;
+ else
+ K_flag1 = optarg;
+ break;
case '?':
default:
usage (patch_usage);
@@ -149,6 +160,11 @@ patch (argc, argv)
argv += optind;
/* Sanity checks */
+ /* Check for dummy -K flags */
+ if (K_flag1 && K_flag1[0] != 'e' && K_flag1[0] != 'i')
+ error (1, 0, "-K flag does not start e or i");
+ if (K_flag2 && K_flag2[0] != 'e' && K_flag2[0] != 'i')
+ error (1, 0, "-K flag does not start e or i");
if (argc < 1)
usage (patch_usage);
@@ -364,7 +380,8 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles)
}
if (vers_tag != NULL)
{
- run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_tag);
+ run_setup ("%s%s %s -p -q -r%s %s%s", Rcsbin, RCS_CO, options,
+ vers_tag, K_flag1 ? "-K" : "", K_flag1 ? K_flag1 : "");
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, tmpfile1, RUN_TTY, RUN_NORMAL)) != 0)
{
@@ -382,7 +399,8 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles)
}
if (vers_head != NULL)
{
- run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_head);
+ run_setup ("%s%s %s -p -q -r%s %s%s", Rcsbin, RCS_CO, options,
+ vers_head, K_flag2 ? "-K" : "", K_flag2 ? K_flag2 : "");
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, tmpfile2, RUN_TTY, RUN_NORMAL)) != 0)
{
diff --git a/gnu/usr.bin/cvs/cvs/release.c b/gnu/usr.bin/cvs/cvs/release.c
index 34d36bc33229..e2a941a6f284 100644
--- a/gnu/usr.bin/cvs/cvs/release.c
+++ b/gnu/usr.bin/cvs/cvs/release.c
@@ -155,7 +155,11 @@ release (argc, argv)
* is "popen()" instead of "Popen()" since we don't want "-n" to
* stop it.
*/
+#ifdef FREEBSD_DEVELOPER
+ fp = popen ("ncvs -n -q update", "r");
+#else
fp = popen ("cvs -n -q update", "r");
+#endif /* FREEBSD_DEVELOPER */
c = 0;
while (fgets (line, sizeof (line), fp))
{
diff --git a/gnu/usr.bin/cvs/cvs/update.c b/gnu/usr.bin/cvs/cvs/update.c
index c25bc757f549..d91ffdd4153d 100644
--- a/gnu/usr.bin/cvs/cvs/update.c
+++ b/gnu/usr.bin/cvs/cvs/update.c
@@ -75,6 +75,7 @@ static char *tag = NULL;
static char *date = NULL;
static char *join_rev1, *date_rev1;
static char *join_rev2, *date_rev2;
+static char *K_flag;
static int aflag = 0;
static int force_tag_match = 1;
static int update_build_dirs = 0;
@@ -99,6 +100,7 @@ static char *update_usage[] =
"\t-D date\tSet date to update from.\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-K key\tUse RCS key -K option on checkout.\n",
NULL
};
@@ -121,7 +123,7 @@ update (argc, argv)
/* parse the args */
optind = 1;
- while ((c = gnu_getopt (argc, argv, "ApPflRQqdk:r:D:j:I:")) != -1)
+ while ((c = gnu_getopt (argc, argv, "ApPflRQqdk:r:D:j:I:K:")) != -1)
{
switch (c)
{
@@ -175,6 +177,9 @@ update (argc, argv)
else
join_rev1 = optarg;
break;
+ case 'K':
+ K_flag = optarg;
+ break;
case '?':
default:
usage (update_usage);
@@ -184,6 +189,13 @@ update (argc, argv)
argc -= optind;
argv += optind;
+#ifdef FREEBSD_DEVELOPER
+ if (!K_flag && freebsd) {
+ /* XXX Note: The leading -K is not needed, it gets added later! */
+ K_flag = "eAuthor,eDate,eHeader,eId,eLocker,eLog,eRCSfile,eRevision,eSource,eState,iFreeBSD";
+ }
+#endif /* FREEBSD_DEVELOPER */
+
/*
* 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
@@ -209,7 +221,8 @@ update (argc, argv)
/* 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, join_rev1, join_rev2, (char *) NULL);
+ pipeout, which, join_rev1, join_rev2,
+ K_flag, (char *) NULL);
/* free the space Make_Date allocated if necessary */
if (date != NULL)
@@ -223,7 +236,8 @@ update (argc, argv)
*/
int
do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
- xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir)
+ xprune, xpipeout, which, xjoin_rev1, xjoin_rev2,
+ xK_flag, preload_update_dir)
int argc;
char *argv[];
char *xoptions;
@@ -238,6 +252,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
int which;
char *xjoin_rev1;
char *xjoin_rev2;
+ char *xK_flag;
char *preload_update_dir;
{
int err = 0;
@@ -253,6 +268,8 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
update_prune_dirs = xprune;
pipeout = xpipeout;
+ K_flag = xK_flag;
+
/* setup the join support */
join_rev1 = xjoin_rev1;
join_rev2 = xjoin_rev2;
@@ -650,8 +667,8 @@ checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir)
(void) unlink_file (backup);
}
- run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs,
- vers_ts->options);
+ run_setup ("%s%s -q -r%s %s %s%s", Rcsbin, RCS_CO, vers_ts->vn_rcs,
+ vers_ts->options, K_flag ? "-K" : "", K_flag ? K_flag : "");
/*
* if we are checking out to stdout, print a nice message to stderr, and
diff --git a/gnu/usr.bin/gdb/COPYING b/gnu/usr.bin/gdb/COPYING
index 9a1703758111..a43ea2126fb6 100644
--- a/gnu/usr.bin/gdb/COPYING
+++ b/gnu/usr.bin/gdb/COPYING
@@ -1,38 +1,40 @@
-
GNU GENERAL PUBLIC LICENSE
- Version 1, February 1989
+ Version 2, June 1991
- Copyright (C) 1989 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
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
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU 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.
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+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.
+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 software, or if you modify it.
- For example, if you distribute copies of a such a program, whether
+ For example, if you distribute copies of 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.
+source code. And you must show them these terms so they know 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,
@@ -45,120 +47,207 @@ 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.
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
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.
+ 0. This License 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 derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 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 License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary 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
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
- 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
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (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.
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing 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 for copying, distributing or modifying
+the Program or works based on it.
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.
+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.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
- 7. The Free Software Foundation may publish revised and/or new versions
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. 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
+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 Program does not specify a version number of
-the license, you may choose any version ever published by the Free Software
+this 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
+ 10. 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
@@ -168,7 +257,7 @@ of promoting the sharing and reuse of software generally.
NO WARRANTY
- 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ 11. 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
@@ -178,7 +267,7 @@ 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
+ 12. 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
@@ -193,22 +282,21 @@ POSSIBILITY OF SUCH DAMAGES.
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.
+possible use to the public, 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.
+ 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.
+ 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
@@ -224,26 +312,28 @@ 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 version 69, Copyright (C) 19yy 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.
+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:
+necessary. Here is 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.
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
-That's all there is to it!
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/COPYING.LIB b/gnu/usr.bin/gdb/COPYING.LIB
new file mode 100644
index 000000000000..eb685a5ec981
--- /dev/null
+++ b/gnu/usr.bin/gdb/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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/gnu/usr.bin/gdb/Makefile b/gnu/usr.bin/gdb/Makefile
index 550ed07a7575..8536444cda0b 100644
--- a/gnu/usr.bin/gdb/Makefile
+++ b/gnu/usr.bin/gdb/Makefile
@@ -1,38 +1,3 @@
-# @(#)Makefile 6.4 (Berkley) 5/6/91
+SUBDIR= bfd libiberty mmalloc gdb
-PROG= gdb
-GDBSRCS= blockframe.c breakpoint.c command.c copying.c core.c \
- cplus-dem.c dbxread.c environ.c eval.c expprint.c \
- expread.y findvar.c infcmd.c inflow.c infrun.c \
- main.c obstack.c printcmd.c regex.c remote.c \
- remote-sl.c source.c stack.c symmisc.c symtab.c \
- utils.c valarith.c valops.c valprint.c values.c \
- version.c
-READLINESRCS= funmap.c history.c keymaps.c readline.c
-SRCS= $(CONFIGSRCS) $(GDBSRCS) $(READLINESRCS) init.c
-CFLAGS+= -I. -I$(.CURDIR) -I$(.CURDIR)/config -I$(.CURDIR)/readline \
- -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG -DNEWVM
-LDADD= -ltermcap
-YFLAGS=
-.PATH: $(.CURDIR)/config $(.CURDIR)/readline
-
-depend:
-
-.include "config/Makefile.$(MACHINE)"
-.include <bsd.prog.mk>
-
-$(OBJS): param.h
-
-#
-# Generate the constructor
-#
-init.c: $(CONFIGSRCS) $(GDBSRCS) $(READLINESRCS)
- -((cd $(.CURDIR)/config; \
- egrep -h '^_initialize_[^ ]* *\(\)' $(CONFIGSRCS)); \
- (cd $(.CURDIR); egrep -h '^_initialize_[^ ]* *\(\)' $(GDBSRCS)); \
- (cd $(.CURDIR)/readline; \
- egrep -h '^_initialize_[^ ]* *\(\)' $(READLINESRCS))) | \
- (echo 'void initialize_all_files () {'; sed -e 's/$$/;/'; echo '}') \
- > init.c
-
-CLEANFILES+= init.c param.h
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/gdb/README.FreeBSD b/gnu/usr.bin/gdb/README.FreeBSD
new file mode 100644
index 000000000000..75a30b2cb431
--- /dev/null
+++ b/gnu/usr.bin/gdb/README.FreeBSD
@@ -0,0 +1,15 @@
+This is a greatly pared down version of GDB-4.12 for FreeBSD 1.1.5 that
+supports debugging of shared executables and the new a.out format.
+
+I've collapsed some of the directories and removed lots of files from others.
+All that's included is those necessary to compile on FreeBSD 1.1.5, this was
+to keep the replacement for GDB-3 compact since none of the multiple
+architecture stuff is used. All the documentation has been put in the doc/
+directory.
+
+A full port of each library will probably be done for FreeBSD 2.0 and
+included as system libraries so that other build tools can share them.
+At that time a more complete port of GDB-4 will be done that allows
+configuration for different systems and uses the full libraries.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/VERSION b/gnu/usr.bin/gdb/VERSION
new file mode 100644
index 000000000000..b849ff8ebf1f
--- /dev/null
+++ b/gnu/usr.bin/gdb/VERSION
@@ -0,0 +1 @@
+4.11
diff --git a/gnu/usr.bin/gdb/bfd/COPYING b/gnu/usr.bin/gdb/bfd/COPYING
new file mode 100644
index 000000000000..a43ea2126fb6
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU 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. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, 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 software, or if you modify it.
+
+ For example, if you distribute copies of 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 show them these terms so they know 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.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ 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 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 derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 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 License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary 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
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing 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 for copying, distributing or modifying
+the Program or works based on it.
+
+ 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.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. 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 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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. 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 the public, 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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) 19yy 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 is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/bfd/Makefile b/gnu/usr.bin/gdb/bfd/Makefile
new file mode 100644
index 000000000000..ea29afed0d86
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/Makefile
@@ -0,0 +1,17 @@
+LIB = bfd
+SRCS = archive.c archures.c bfd.c cache.c coffgen.c core.c ctor.c \
+ format.c init.c libbfd.c opncls.c reloc.c seclet.c section.c syms.c \
+ targets.c ecoff.c elf.c srec.c freebsd386.c aout32.c stab-syms.c \
+ cpu-i386.c trad-core.c
+
+CFLAGS+= -I$(.CURDIR)/. -I$(.CURDIR)/../gdb/.
+CFLAGS+= -DDEFAULT_VECTOR=freebsd386_vec -DSELECT_VECS='&freebsd386_vec' \
+ -DSELECT_ARCHITECTURES='bfd_i386_arch' -DTRAD_CORE
+
+NOPROFILE=no
+NOPIC=no
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/bfd/README.FreeBSD b/gnu/usr.bin/gdb/bfd/README.FreeBSD
new file mode 100644
index 000000000000..204119c1af74
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libbfd directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libbfd will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/bfd/VERSION b/gnu/usr.bin/gdb/bfd/VERSION
new file mode 100644
index 000000000000..8bbe6cf74a1e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/VERSION
@@ -0,0 +1 @@
+2.2
diff --git a/gnu/usr.bin/gdb/bfd/aout-target.h b/gnu/usr.bin/gdb/bfd/aout-target.h
new file mode 100644
index 000000000000..65a22fff9b04
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aout-target.h
@@ -0,0 +1,429 @@
+/* Define a target vector and some small routines for a variant of a.out.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+#include "aout/ar.h"
+/*#include "libaout.h"*/
+
+extern CONST struct reloc_howto_struct * NAME(aout,reloc_type_lookup) ();
+
+/* Set parameters about this a.out file that are machine-dependent.
+ This routine is called from some_aout_object_p just before it returns. */
+#ifndef MY_callback
+static bfd_target *
+DEFUN(MY(callback),(abfd),
+ bfd *abfd)
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+
+ /* Calculate the file positions of the parts of a newly read aout header */
+ obj_textsec (abfd)->_raw_size = N_TXTSIZE(*execp);
+
+ /* The virtual memory addresses of the sections */
+ obj_textsec (abfd)->vma = N_TXTADDR(*execp);
+ obj_datasec (abfd)->vma = N_DATADDR(*execp);
+ obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
+
+ /* The file offsets of the sections */
+ obj_textsec (abfd)->filepos = N_TXTOFF (*execp);
+ obj_datasec (abfd)->filepos = N_DATOFF (*execp);
+
+ /* The file offsets of the relocation info */
+ obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp);
+ obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp);
+
+ /* The file offsets of the string table and symbol table. */
+ obj_sym_filepos (abfd) = N_SYMOFF (*execp);
+ obj_str_filepos (abfd) = N_STROFF (*execp);
+
+ /* Determine the architecture and machine type of the object file. */
+#ifdef SET_ARCH_MACH
+ SET_ARCH_MACH(abfd, *execp);
+#else
+ bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0);
+#endif
+
+ /* Don't set sizes now -- can't be sure until we know arch & mach.
+ Sizes get set in set_sizes callback, later. */
+#if 0
+ adata(abfd).page_size = PAGE_SIZE;
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+#endif
+
+ return abfd->xvec;
+}
+#endif
+
+#ifndef MY_object_p
+/* Finish up the reading of an a.out file header */
+
+static bfd_target *
+DEFUN(MY(object_p),(abfd),
+ bfd *abfd)
+{
+ struct external_exec exec_bytes; /* Raw exec header from file */
+ struct internal_exec exec; /* Cleaned-up exec header */
+ bfd_target *target;
+
+ if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd)
+ != EXEC_BYTES_SIZE) {
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+#ifdef NO_SWAP_MAGIC
+ memcpy (&exec.a_info, exec_bytes.e_info, sizeof(exec.a_info));
+#else
+ exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info);
+#endif /* NO_SWAP_MAGIC */
+
+ if (N_BADMAG (exec)) return 0;
+#ifdef MACHTYPE_OK
+ if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0;
+#endif
+
+ NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec);
+ target = NAME(aout,some_aout_object_p) (abfd, &exec, MY(callback));
+
+#ifdef ENTRY_CAN_BE_ZERO
+ /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage)
+ * means that it isn't obvious if EXEC_P should be set.
+ * All of the following must be true for an executable:
+ * There must be no relocations, the bfd can be neither an
+ * archive nor an archive element, and the file must be executable. */
+
+ if (exec.a_trsize + exec.a_drsize == 0
+ && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL)
+ {
+ struct stat buf;
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+ if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR))
+ abfd->flags |= EXEC_P;
+ }
+#endif /* ENTRY_CAN_BE_ZERO */
+
+ return target;
+}
+#define MY_object_p MY(object_p)
+#endif
+
+
+#ifndef MY_mkobject
+static boolean
+DEFUN(MY(mkobject),(abfd),
+ bfd *abfd)
+{
+ if (NAME(aout,mkobject)(abfd) == false)
+ return false;
+#if 0 /* Sizes get set in set_sizes callback, later, after we know
+ the architecture and machine. */
+ adata(abfd).page_size = PAGE_SIZE;
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+#endif
+ return true;
+}
+#define MY_mkobject MY(mkobject)
+#endif
+
+/* Write an object file.
+ Section contents have already been written. We write the
+ file header, symbols, and relocation. */
+
+#ifndef MY_write_object_contents
+static boolean
+DEFUN(MY(write_object_contents),(abfd),
+ bfd *abfd)
+{
+ struct external_exec exec_bytes;
+ struct internal_exec *execp = exec_hdr (abfd);
+
+#if CHOOSE_RELOC_SIZE
+ CHOOSE_RELOC_SIZE(abfd);
+#else
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+#endif
+
+ WRITE_HEADERS(abfd, execp);
+
+ return true;
+}
+#define MY_write_object_contents MY(write_object_contents)
+#endif
+
+#ifndef MY_set_sizes
+static boolean
+DEFUN(MY(set_sizes),(abfd), bfd *abfd)
+{
+ adata(abfd).page_size = PAGE_SIZE;
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+ return true;
+}
+#define MY_set_sizes MY(set_sizes)
+#endif
+
+#ifndef MY_backend_data
+static CONST struct aout_backend_data MY(backend_data) = {
+ 0, /* zmagic contiguous */
+ 0, /* text incl header */
+ 0, /* text vma? */
+ MY_set_sizes,
+ 0, /* exec header is counted */
+};
+#define MY_backend_data &MY(backend_data)
+#endif
+
+/* We assume BFD generic archive files. */
+#ifndef MY_openr_next_archived_file
+#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file
+#endif
+#ifndef MY_generic_stat_arch_elt
+#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#endif
+#ifndef MY_slurp_armap
+#define MY_slurp_armap bfd_slurp_bsd_armap
+#endif
+#ifndef MY_slurp_extended_name_table
+#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table
+#endif
+#ifndef MY_write_armap
+#define MY_write_armap bsd_write_armap
+#endif
+#ifndef MY_truncate_arname
+#define MY_truncate_arname bfd_bsd_truncate_arname
+#endif
+
+/* No core file defined here -- configure in trad-core.c separately. */
+#ifndef MY_core_file_failing_command
+#define MY_core_file_failing_command _bfd_dummy_core_file_failing_command
+#endif
+#ifndef MY_core_file_failing_signal
+#define MY_core_file_failing_signal _bfd_dummy_core_file_failing_signal
+#endif
+#ifndef MY_core_file_matches_executable_p
+#define MY_core_file_matches_executable_p \
+ _bfd_dummy_core_file_matches_executable_p
+#endif
+#ifndef MY_core_file_p
+#define MY_core_file_p _bfd_dummy_target
+#endif
+
+#ifndef MY_bfd_debug_info_start
+#define MY_bfd_debug_info_start bfd_void
+#endif
+#ifndef MY_bfd_debug_info_end
+#define MY_bfd_debug_info_end bfd_void
+#endif
+#ifndef MY_bfd_debug_info_accumulate
+#define MY_bfd_debug_info_accumulate \
+ (void (*) PARAMS ((bfd*, struct sec *))) bfd_void
+#endif
+
+#ifndef MY_core_file_failing_command
+#define MY_core_file_failing_command NAME(aout,core_file_failing_command)
+#endif
+#ifndef MY_core_file_failing_signal
+#define MY_core_file_failing_signal NAME(aout,core_file_failing_signal)
+#endif
+#ifndef MY_core_file_matches_executable_p
+#define MY_core_file_matches_executable_p NAME(aout,core_file_matches_executable_p)
+#endif
+#ifndef MY_slurp_armap
+#define MY_slurp_armap NAME(aout,slurp_armap)
+#endif
+#ifndef MY_slurp_extended_name_table
+#define MY_slurp_extended_name_table NAME(aout,slurp_extended_name_table)
+#endif
+#ifndef MY_truncate_arname
+#define MY_truncate_arname NAME(aout,truncate_arname)
+#endif
+#ifndef MY_write_armap
+#define MY_write_armap NAME(aout,write_armap)
+#endif
+#ifndef MY_close_and_cleanup
+#define MY_close_and_cleanup NAME(aout,close_and_cleanup)
+#endif
+#ifndef MY_set_section_contents
+#define MY_set_section_contents NAME(aout,set_section_contents)
+#endif
+#ifndef MY_get_section_contents
+#define MY_get_section_contents NAME(aout,get_section_contents)
+#endif
+#ifndef MY_new_section_hook
+#define MY_new_section_hook NAME(aout,new_section_hook)
+#endif
+#ifndef MY_get_symtab_upper_bound
+#define MY_get_symtab_upper_bound NAME(aout,get_symtab_upper_bound)
+#endif
+#ifndef MY_get_symtab
+#define MY_get_symtab NAME(aout,get_symtab)
+#endif
+#ifndef MY_get_reloc_upper_bound
+#define MY_get_reloc_upper_bound NAME(aout,get_reloc_upper_bound)
+#endif
+#ifndef MY_canonicalize_reloc
+#define MY_canonicalize_reloc NAME(aout,canonicalize_reloc)
+#endif
+#ifndef MY_make_empty_symbol
+#define MY_make_empty_symbol NAME(aout,make_empty_symbol)
+#endif
+#ifndef MY_print_symbol
+#define MY_print_symbol NAME(aout,print_symbol)
+#endif
+#ifndef MY_get_symbol_info
+#define MY_get_symbol_info NAME(aout,get_symbol_info)
+#endif
+#ifndef MY_get_lineno
+#define MY_get_lineno NAME(aout,get_lineno)
+#endif
+#ifndef MY_set_arch_mach
+#define MY_set_arch_mach NAME(aout,set_arch_mach)
+#endif
+#ifndef MY_openr_next_archived_file
+#define MY_openr_next_archived_file NAME(aout,openr_next_archived_file)
+#endif
+#ifndef MY_find_nearest_line
+#define MY_find_nearest_line NAME(aout,find_nearest_line)
+#endif
+#ifndef MY_generic_stat_arch_elt
+#define MY_generic_stat_arch_elt NAME(aout,generic_stat_arch_elt)
+#endif
+#ifndef MY_sizeof_headers
+#define MY_sizeof_headers NAME(aout,sizeof_headers)
+#endif
+#ifndef MY_bfd_debug_info_start
+#define MY_bfd_debug_info_start NAME(aout,bfd_debug_info_start)
+#endif
+#ifndef MY_bfd_debug_info_end
+#define MY_bfd_debug_info_end NAME(aout,bfd_debug_info_end)
+#endif
+#ifndef MY_bfd_debug_info_accumulat
+#define MY_bfd_debug_info_accumulat NAME(aout,bfd_debug_info_accumulat)
+#endif
+#ifndef MY_reloc_howto_type_lookup
+#define MY_reloc_howto_type_lookup NAME(aout,reloc_type_lookup)
+#endif
+#ifndef MY_make_debug_symbol
+#define MY_make_debug_symbol 0
+#endif
+
+/* Aout symbols normally have leading underscores */
+#ifndef MY_symbol_leading_char
+#define MY_symbol_leading_char '_'
+#endif
+
+/* Aout archives normally use spaces for padding */
+#ifndef AR_PAD_CHAR
+#define AR_PAD_CHAR ' '
+#endif
+
+#ifndef MY_BFD_TARGET
+bfd_target MY(vec) =
+{
+ TARGETNAME, /* name */
+ bfd_target_aout_flavour,
+#ifdef TARGET_IS_BIG_ENDIAN_P
+ true, /* target byte order (big) */
+ true, /* target headers byte order (big) */
+#else
+ false, /* target byte order (little) */
+ false, /* target headers byte order (little) */
+#endif
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ MY_symbol_leading_char,
+ AR_PAD_CHAR, /* ar_pad_char */
+ 15, /* ar_max_namelen */
+ 3, /* minimum alignment */
+#ifdef TARGET_IS_BIG_ENDIAN_P
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+#else
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+#endif
+ {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, MY_core_file_p},
+ {bfd_false, MY_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
+ {bfd_false, MY_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ MY_core_file_failing_command,
+ MY_core_file_failing_signal,
+ MY_core_file_matches_executable_p,
+ MY_slurp_armap,
+ MY_slurp_extended_name_table,
+ MY_truncate_arname,
+ MY_write_armap,
+ MY_close_and_cleanup,
+ MY_set_section_contents,
+ MY_get_section_contents,
+ MY_new_section_hook,
+ MY_get_symtab_upper_bound,
+ MY_get_symtab,
+ MY_get_reloc_upper_bound,
+ MY_canonicalize_reloc,
+ MY_make_empty_symbol,
+ MY_print_symbol,
+ MY_get_symbol_info,
+ MY_get_lineno,
+ MY_set_arch_mach,
+ MY_openr_next_archived_file,
+ MY_find_nearest_line,
+ MY_generic_stat_arch_elt,
+ MY_sizeof_headers,
+ MY_bfd_debug_info_start,
+ MY_bfd_debug_info_end,
+ MY_bfd_debug_info_accumulate,
+ bfd_generic_get_relocated_section_contents,
+ bfd_generic_relax_section,
+ bfd_generic_seclet_link,
+ MY_reloc_howto_type_lookup,
+ MY_make_debug_symbol,
+ (PTR) MY_backend_data,
+};
+#endif /* MY_BFD_TARGET */
diff --git a/gnu/usr.bin/gdb/bfd/aout32.c b/gnu/usr.bin/gdb/bfd/aout32.c
new file mode 100644
index 000000000000..84d20872fc96
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aout32.c
@@ -0,0 +1,23 @@
+/* BFD back-end for 32-bit a.out files.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define ARCH_SIZE 32
+
+#include "aoutx.h"
diff --git a/gnu/usr.bin/gdb/bfd/aoutx.h b/gnu/usr.bin/gdb/bfd/aoutx.h
new file mode 100644
index 000000000000..1ab442926ff2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aoutx.h
@@ -0,0 +1,2568 @@
+/* BFD semi-generic back-end for a.out binaries.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ a.out backends
+
+
+DESCRIPTION
+
+ BFD supports a number of different flavours of a.out format,
+ though the major differences are only the sizes of the
+ structures on disk, and the shape of the relocation
+ information.
+
+ The support is split into a basic support file @code{aoutx.h}
+ and other files which derive functions from the base. One
+ derivation file is @code{aoutf1.h} (for a.out flavour 1), and
+ adds to the basic a.out functions support for sun3, sun4, 386
+ and 29k a.out files, to create a target jump vector for a
+ specific target.
+
+ This information is further split out into more specific files
+ for each machine, including @code{sunos.c} for sun3 and sun4,
+ @code{newsos3.c} for the Sony NEWS, and @code{demo64.c} for a
+ demonstration of a 64 bit a.out format.
+
+ The base file @code{aoutx.h} defines general mechanisms for
+ reading and writing records to and from disk, and various
+ other methods which BFD requires. It is included by
+ @code{aout32.c} and @code{aout64.c} to form the names
+ aout_32_swap_exec_header_in, aout_64_swap_exec_header_in, etc.
+
+ As an example, this is what goes on to make the back end for a
+ sun4, from aout32.c
+
+| #define ARCH_SIZE 32
+| #include "aoutx.h"
+
+ Which exports names:
+
+| ...
+| aout_32_canonicalize_reloc
+| aout_32_find_nearest_line
+| aout_32_get_lineno
+| aout_32_get_reloc_upper_bound
+| ...
+
+ from sunos.c
+
+| #define ARCH 32
+| #define TARGET_NAME "a.out-sunos-big"
+| #define VECNAME sunos_big_vec
+| #include "aoutf1.h"
+
+ requires all the names from aout32.c, and produces the jump vector
+
+| sunos_big_vec
+
+ The file host-aout.c is a special case. It is for a large set
+ of hosts that use ``more or less standard'' a.out files, and
+ for which cross-debugging is not interesting. It uses the
+ standard 32-bit a.out support routines, but determines the
+ file offsets and addresses of the text, data, and BSS
+ sections, the machine architecture and machine type, and the
+ entry point address, in a host-dependent manner. Once these
+ values have been determined, generic code is used to handle
+ the object file.
+
+ When porting it to run on a new system, you must supply:
+
+| HOST_PAGE_SIZE
+| HOST_SEGMENT_SIZE
+| HOST_MACHINE_ARCH (optional)
+| HOST_MACHINE_MACHINE (optional)
+| HOST_TEXT_START_ADDR
+| HOST_STACK_END_ADDR
+
+ in the file <<../include/sys/h-XXX.h>> (for your host). These
+ values, plus the structures and macros defined in <<a.out.h>> on
+ your host system, will produce a BFD target that will access
+ ordinary a.out files on your host. To configure a new machine
+ to use <<host-aout.c>., specify:
+
+| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec
+| TDEPFILES= host-aout.o trad-core.o
+
+ in the <<config/mt-XXX>> file, and modify configure.in to use the
+ <<mt-XXX>> file (by setting "<<bfd_target=XXX>>") when your
+ configuration is selected.
+
+*/
+
+/* Some assumptions:
+ * Any BFD with D_PAGED set is ZMAGIC, and vice versa.
+ Doesn't matter what the setting of WP_TEXT is on output, but it'll
+ get set on input.
+ * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC.
+ * Any BFD with both flags clear is OMAGIC.
+ (Just want to make these explicit, so the conditions tested in this
+ file make sense if you're more familiar with a.out than with BFD.) */
+
+#define KEEPIT flags
+#define KEEPITTYPE int
+
+#include <assert.h>
+#include <string.h> /* For strchr and friends */
+#include "bfd.h"
+#include <sysdep.h>
+#include <ansidecl.h>
+
+struct external_exec;
+#include "libaout.h"
+#include "libbfd.h"
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+#include "aout/ar.h"
+
+extern void (*bfd_error_trap)();
+
+/*
+SUBSECTION
+ relocations
+
+DESCRIPTION
+ The file @code{aoutx.h} caters for both the @emph{standard}
+ and @emph{extended} forms of a.out relocation records.
+
+ The standard records are characterised by containing only an
+ address, a symbol index and a type field. The extended records
+ (used on 29ks and sparcs) also have a full integer for an
+ addend.
+
+*/
+#define CTOR_TABLE_RELOC_IDX 2
+
+#define howto_table_ext NAME(aout,ext_howto_table)
+#define howto_table_std NAME(aout,std_howto_table)
+
+reloc_howto_type howto_table_ext[] =
+{
+ /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
+ HOWTO(RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", false, 0,0x000000ff, false),
+ HOWTO(RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", false, 0,0xffffffff, false),
+ HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, complain_overflow_signed,0,"DISP8", false, 0,0x000000ff, false),
+ HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, complain_overflow_signed,0,"DISP16", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, complain_overflow_signed,0,"DISP32", false, 0,0xffffffff, false),
+ HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, complain_overflow_signed,0,"WDISP30", false, 0,0x3fffffff, false),
+ HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, complain_overflow_signed,0,"WDISP22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_HI22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"HI22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"13", false, 0,0x00001fff, false),
+ HOWTO(RELOC_LO10, 0, 2, 10, false, 0, complain_overflow_dont,0,"LO10", false, 0,0x000003ff, false),
+ HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false),
+ HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false),
+ HOWTO(RELOC_BASE10, 0, 2, 16, false, 0, complain_overflow_bitfield,0,"BASE10", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_BASE13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"BASE13", false, 0,0x00001fff, false),
+ HOWTO(RELOC_BASE22, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASE22", false, 0,0x00000000, false),
+ HOWTO(RELOC_PC10, 0, 2, 10, false, 0, complain_overflow_bitfield,0,"PC10", false, 0,0x000003ff, false),
+ HOWTO(RELOC_PC22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"PC22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_JMP_TBL,0, 2, 32, false, 0, complain_overflow_bitfield,0,"JMP_TBL", false, 0,0xffffffff, false),
+ HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, complain_overflow_bitfield,0,"SEGOFF16", false, 0,0x00000000, false),
+ HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"GLOB_DAT", false, 0,0x00000000, false),
+ HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_SLOT", false, 0,0x00000000, false),
+ HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false),
+};
+
+/* Convert standard reloc records to "arelent" format (incl byte swap). */
+
+reloc_howto_type howto_table_std[] = {
+ /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
+HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false),
+HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false),
+HOWTO( 3, 0, 4, 64, false, 0, complain_overflow_bitfield,0,"64", true, 0xdeaddead,0xdeaddead, false),
+HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, false),
+HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, false),
+HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", true, 0xfeedface,0xfeedface, false),
+{ -1 },
+HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false),
+HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false),
+};
+
+#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0]))
+
+CONST struct reloc_howto_struct *
+DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
+ bfd *abfd AND
+ bfd_reloc_code_real_type code)
+{
+#define EXT(i,j) case i: return &howto_table_ext[j]
+#define STD(i,j) case i: return &howto_table_std[j]
+ int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
+ if (code == BFD_RELOC_CTOR)
+ switch (bfd_get_arch_info (abfd)->bits_per_address)
+ {
+ case 32:
+ code = BFD_RELOC_32;
+ break;
+ }
+ if (ext)
+ switch (code)
+ {
+ EXT (BFD_RELOC_32, 2);
+ EXT (BFD_RELOC_HI22, 8);
+ EXT (BFD_RELOC_LO10, 11);
+ EXT (BFD_RELOC_32_PCREL_S2, 6);
+ default: return (CONST struct reloc_howto_struct *) 0;
+ }
+ else
+ /* std relocs */
+ switch (code)
+ {
+ STD (BFD_RELOC_16, 1);
+ STD (BFD_RELOC_32, 2);
+ STD (BFD_RELOC_8_PCREL, 4);
+ STD (BFD_RELOC_16_PCREL, 5);
+ STD (BFD_RELOC_32_PCREL, 6);
+ STD (BFD_RELOC_16_BASEREL, 9);
+ STD (BFD_RELOC_32_BASEREL, 10);
+ default: return (CONST struct reloc_howto_struct *) 0;
+ }
+}
+
+extern bfd_error_vector_type bfd_error_vector;
+
+/*
+SUBSECTION
+ Internal Entry Points
+
+DESCRIPTION
+ @code{aoutx.h} exports several routines for accessing the
+ contents of an a.out file, which are gathered and exported in
+ turn by various format specific files (eg sunos.c).
+
+*/
+
+/*
+FUNCTION
+ aout_<size>_swap_exec_header_in
+
+DESCRIPTION
+ Swaps the information in an executable header taken from a raw
+ byte stream memory image, into the internal exec_header
+ structure.
+
+SYNOPSIS
+ void aout_<size>_swap_exec_header_in,
+ (bfd *abfd,
+ struct external_exec *raw_bytes,
+ struct internal_exec *execp);
+*/
+
+#ifndef NAME_swap_exec_header_in
+void
+DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
+ bfd *abfd AND
+ struct external_exec *raw_bytes AND
+ struct internal_exec *execp)
+{
+ struct external_exec *bytes = (struct external_exec *)raw_bytes;
+
+ /* The internal_exec structure has some fields that are unused in this
+ configuration (IE for i960), so ensure that all such uninitialized
+ fields are zero'd out. There are places where two of these structs
+ are memcmp'd, and thus the contents do matter. */
+ memset (execp, 0, sizeof (struct internal_exec));
+ /* Now fill in fields in the execp, from the bytes in the raw data. */
+ execp->a_info = bfd_h_get_32 (abfd, bytes->e_info);
+ execp->a_text = GET_WORD (abfd, bytes->e_text);
+ execp->a_data = GET_WORD (abfd, bytes->e_data);
+ execp->a_bss = GET_WORD (abfd, bytes->e_bss);
+ execp->a_syms = GET_WORD (abfd, bytes->e_syms);
+ execp->a_entry = GET_WORD (abfd, bytes->e_entry);
+ execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
+ execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
+}
+#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in)
+#endif
+
+/*
+FUNCTION
+ aout_<size>_swap_exec_header_out
+
+DESCRIPTION
+ Swaps the information in an internal exec header structure
+ into the supplied buffer ready for writing to disk.
+
+SYNOPSIS
+ void aout_<size>_swap_exec_header_out
+ (bfd *abfd,
+ struct internal_exec *execp,
+ struct external_exec *raw_bytes);
+*/
+void
+DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes),
+ bfd *abfd AND
+ struct internal_exec *execp AND
+ struct external_exec *raw_bytes)
+{
+ struct external_exec *bytes = (struct external_exec *)raw_bytes;
+
+ /* Now fill in fields in the raw data, from the fields in the exec struct. */
+ bfd_h_put_32 (abfd, execp->a_info , bytes->e_info);
+ PUT_WORD (abfd, execp->a_text , bytes->e_text);
+ PUT_WORD (abfd, execp->a_data , bytes->e_data);
+ PUT_WORD (abfd, execp->a_bss , bytes->e_bss);
+ PUT_WORD (abfd, execp->a_syms , bytes->e_syms);
+ PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
+ PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
+ PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
+}
+
+
+
+/*
+FUNCTION
+ aout_<size>_some_aout_object_p
+
+DESCRIPTION
+ Some A.OUT variant thinks that the file whose format we're
+ checking is an a.out file. Do some more checking, and set up
+ for access if it really is. Call back to the calling
+ environments "finish up" function just before returning, to
+ handle any last-minute setup.
+
+SYNOPSIS
+ bfd_target *aout_<size>_some_aout_object_p
+ (bfd *abfd,
+ bfd_target *(*callback_to_real_object_p)());
+*/
+
+bfd_target *
+DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
+ bfd *abfd AND
+ struct internal_exec *execp AND
+ bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)))
+{
+ struct aout_data_struct *rawptr, *oldrawptr;
+ bfd_target *result;
+
+ rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+ if (rawptr == NULL) {
+ bfd_error = no_memory;
+ return 0;
+ }
+
+ oldrawptr = abfd->tdata.aout_data;
+ abfd->tdata.aout_data = rawptr;
+
+ /* Copy the contents of the old tdata struct.
+ In particular, we want the subformat, since for hpux it was set in
+ hp300hpux.c:swap_exec_header_in and will be used in
+ hp300hpux.c:callback. */
+ if (oldrawptr != NULL)
+ *abfd->tdata.aout_data = *oldrawptr;
+
+ abfd->tdata.aout_data->a.hdr = &rawptr->e;
+ *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct */
+ execp = abfd->tdata.aout_data->a.hdr;
+
+ /* Set the file flags */
+ abfd->flags = NO_FLAGS;
+ if (execp->a_drsize || execp->a_trsize)
+ abfd->flags |= HAS_RELOC;
+ /* Setting of EXEC_P has been deferred to the bottom of this function */
+ if (execp->a_syms)
+ abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
+
+ if (N_MAGIC (*execp) == ZMAGIC)
+ {
+ abfd->flags |= D_PAGED|WP_TEXT;
+ adata(abfd).magic = z_magic;
+ }
+ else if (N_MAGIC (*execp) == NMAGIC)
+ {
+ abfd->flags |= WP_TEXT;
+ adata(abfd).magic = n_magic;
+ }
+ else
+ adata(abfd).magic = o_magic;
+
+ bfd_get_start_address (abfd) = execp->a_entry;
+
+ obj_aout_symbols (abfd) = (aout_symbol_type *)NULL;
+ bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
+
+ /* The default relocation entry size is that of traditional V7 Unix. */
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+
+ /* The default symbol entry size is that of traditional Unix. */
+ obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
+
+ /* Create the sections. This is raunchy, but bfd_close wants to reclaim
+ them. */
+
+ obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text");
+ obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data");
+ obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss");
+
+#if 0
+ (void)bfd_make_section (abfd, ".text");
+ (void)bfd_make_section (abfd, ".data");
+ (void)bfd_make_section (abfd, ".bss");
+#endif
+
+ obj_datasec (abfd)->_raw_size = execp->a_data;
+ obj_bsssec (abfd)->_raw_size = execp->a_bss;
+
+ obj_textsec (abfd)->flags = (execp->a_trsize != 0 ?
+ (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) :
+ (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
+ obj_datasec (abfd)->flags = (execp->a_drsize != 0 ?
+ (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) :
+ (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
+ obj_bsssec (abfd)->flags = SEC_ALLOC;
+
+#ifdef THIS_IS_ONLY_DOCUMENTATION
+ /* The common code can't fill in these things because they depend
+ on either the start address of the text segment, the rounding
+ up of virtual addersses between segments, or the starting file
+ position of the text segment -- all of which varies among different
+ versions of a.out. */
+
+ /* Call back to the format-dependent code to fill in the rest of the
+ fields and do any further cleanup. Things that should be filled
+ in by the callback: */
+
+ struct exec *execp = exec_hdr (abfd);
+
+ obj_textsec (abfd)->size = N_TXTSIZE(*execp);
+ obj_textsec (abfd)->raw_size = N_TXTSIZE(*execp);
+ /* data and bss are already filled in since they're so standard */
+
+ /* The virtual memory addresses of the sections */
+ obj_textsec (abfd)->vma = N_TXTADDR(*execp);
+ obj_datasec (abfd)->vma = N_DATADDR(*execp);
+ obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
+
+ /* The file offsets of the sections */
+ obj_textsec (abfd)->filepos = N_TXTOFF(*execp);
+ obj_datasec (abfd)->filepos = N_DATOFF(*execp);
+
+ /* The file offsets of the relocation info */
+ obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp);
+ obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp);
+
+ /* The file offsets of the string table and symbol table. */
+ obj_str_filepos (abfd) = N_STROFF (*execp);
+ obj_sym_filepos (abfd) = N_SYMOFF (*execp);
+
+ /* Determine the architecture and machine type of the object file. */
+ switch (N_MACHTYPE (*exec_hdr (abfd))) {
+ default:
+ abfd->obj_arch = bfd_arch_obscure;
+ break;
+ }
+
+ adata(abfd)->page_size = PAGE_SIZE;
+ adata(abfd)->segment_size = SEGMENT_SIZE;
+ adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
+
+ return abfd->xvec;
+
+ /* The architecture is encoded in various ways in various a.out variants,
+ or is not encoded at all in some of them. The relocation size depends
+ on the architecture and the a.out variant. Finally, the return value
+ is the bfd_target vector in use. If an error occurs, return zero and
+ set bfd_error to the appropriate error code.
+
+ Formats such as b.out, which have additional fields in the a.out
+ header, should cope with them in this callback as well. */
+#endif /* DOCUMENTATION */
+
+ result = (*callback_to_real_object_p)(abfd);
+
+ /* Now that the segment addresses have been worked out, take a better
+ guess at whether the file is executable. If the entry point
+ is within the text segment, assume it is. (This makes files
+ executable even if their entry point address is 0, as long as
+ their text starts at zero.)
+
+ At some point we should probably break down and stat the file and
+ declare it executable if (one of) its 'x' bits are on... */
+ if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
+ (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
+ abfd->flags |= EXEC_P;
+ if (result)
+ {
+#if 0 /* These should be set correctly anyways. */
+ abfd->sections = obj_textsec (abfd);
+ obj_textsec (abfd)->next = obj_datasec (abfd);
+ obj_datasec (abfd)->next = obj_bsssec (abfd);
+#endif
+ }
+ else
+ {
+ free (rawptr);
+ abfd->tdata.aout_data = oldrawptr;
+ }
+ return result;
+}
+
+/*
+FUNCTION
+ aout_<size>_mkobject
+
+DESCRIPTION
+ This routine initializes a BFD for use with a.out files.
+
+SYNOPSIS
+ boolean aout_<size>_mkobject, (bfd *);
+*/
+
+boolean
+DEFUN(NAME(aout,mkobject),(abfd),
+ bfd *abfd)
+{
+ struct aout_data_struct *rawptr;
+
+ bfd_error = system_call_error;
+
+ /* Use an intermediate variable for clarity */
+ rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+
+ if (rawptr == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ abfd->tdata.aout_data = rawptr;
+ exec_hdr (abfd) = &(rawptr->e);
+
+ /* For simplicity's sake we just make all the sections right here. */
+
+ obj_textsec (abfd) = (asection *)NULL;
+ obj_datasec (abfd) = (asection *)NULL;
+ obj_bsssec (abfd) = (asection *)NULL;
+ bfd_make_section (abfd, ".text");
+ bfd_make_section (abfd, ".data");
+ bfd_make_section (abfd, ".bss");
+ bfd_make_section (abfd, BFD_ABS_SECTION_NAME);
+ bfd_make_section (abfd, BFD_UND_SECTION_NAME);
+ bfd_make_section (abfd, BFD_COM_SECTION_NAME);
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ aout_<size>_machine_type
+
+DESCRIPTION
+ Keep track of machine architecture and machine type for
+ a.out's. Return the machine_type for a particular
+ arch&machine, or M_UNKNOWN if that exact arch&machine can't be
+ represented in a.out format.
+
+ If the architecture is understood, machine type 0 (default)
+ should always be understood.
+
+SYNOPSIS
+ enum machine_type aout_<size>_machine_type
+ (enum bfd_architecture arch,
+ unsigned long machine));
+*/
+
+enum machine_type
+DEFUN(NAME(aout,machine_type),(arch, machine),
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ enum machine_type arch_flags;
+
+ arch_flags = M_UNKNOWN;
+
+ switch (arch) {
+ case bfd_arch_sparc:
+ if (machine == 0) arch_flags = M_SPARC;
+ break;
+
+ case bfd_arch_m68k:
+ switch (machine) {
+ case 0: arch_flags = M_68010; break;
+ case 68000: arch_flags = M_UNKNOWN; break;
+ case 68010: arch_flags = M_68010; break;
+ case 68020: arch_flags = M_68020; break;
+ default: arch_flags = M_UNKNOWN; break;
+ }
+ break;
+
+ case bfd_arch_i386:
+ if (machine == 0) arch_flags = M_386;
+ break;
+
+ case bfd_arch_a29k:
+ if (machine == 0) arch_flags = M_29K;
+ break;
+
+ case bfd_arch_mips:
+ switch (machine) {
+ case 0:
+ case 2000:
+ case 3000: arch_flags = M_MIPS1; break;
+ case 4000:
+ case 4400:
+ case 6000: arch_flags = M_MIPS2; break;
+ default: arch_flags = M_UNKNOWN; break;
+ }
+ break;
+
+ default:
+ arch_flags = M_UNKNOWN;
+ }
+ return arch_flags;
+}
+
+
+/*
+FUNCTION
+ aout_<size>_set_arch_mach
+
+DESCRIPTION
+ Sets the architecture and the machine of the BFD to those
+ values supplied. Verifies that the format can support the
+ architecture required.
+
+SYNOPSIS
+ boolean aout_<size>_set_arch_mach,
+ (bfd *,
+ enum bfd_architecture,
+ unsigned long machine));
+*/
+
+boolean
+DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ if (! bfd_default_set_arch_mach (abfd, arch, machine))
+ return false;
+
+ if (arch != bfd_arch_unknown &&
+ NAME(aout,machine_type) (arch, machine) == M_UNKNOWN)
+ return false; /* We can't represent this type */
+
+ /* Determine the size of a relocation entry */
+ switch (arch) {
+ case bfd_arch_sparc:
+ case bfd_arch_a29k:
+ case bfd_arch_mips:
+ obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
+ break;
+ default:
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+ break;
+ }
+
+ return (*aout_backend_info(abfd)->set_sizes) (abfd);
+}
+
+boolean
+DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
+ bfd *abfd AND bfd_size_type *text_size AND file_ptr *text_end)
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+ if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL))
+ {
+ bfd_error = invalid_operation;
+ return false;
+ }
+ if (adata(abfd).magic != undecided_magic) return true;
+ obj_textsec(abfd)->_raw_size =
+ align_power(obj_textsec(abfd)->_raw_size,
+ obj_textsec(abfd)->alignment_power);
+
+ *text_size = obj_textsec (abfd)->_raw_size;
+ /* Rule (heuristic) for when to pad to a new page. Note that there
+ * are (at least) two ways demand-paged (ZMAGIC) files have been
+ * handled. Most Berkeley-based systems start the text segment at
+ * (PAGE_SIZE). However, newer versions of SUNOS start the text
+ * segment right after the exec header; the latter is counted in the
+ * text segment size, and is paged in by the kernel with the rest of
+ * the text. */
+
+ /* This perhaps isn't the right way to do this, but made it simpler for me
+ to understand enough to implement it. Better would probably be to go
+ right from BFD flags to alignment/positioning characteristics. But the
+ old code was sloppy enough about handling the flags, and had enough
+ other magic, that it was a little hard for me to understand. I think
+ I understand it better now, but I haven't time to do the cleanup this
+ minute. */
+ if (adata(abfd).magic == undecided_magic)
+ {
+ if (abfd->flags & D_PAGED)
+ /* Whether or not WP_TEXT is set -- let D_PAGED override. */
+ /* @@ What about QMAGIC? */
+ adata(abfd).magic = z_magic;
+ else if (abfd->flags & WP_TEXT)
+ adata(abfd).magic = n_magic;
+ else
+ adata(abfd).magic = o_magic;
+ }
+
+#ifdef BFD_AOUT_DEBUG /* requires gcc2 */
+#if __GNUC__ >= 2
+ fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n",
+ ({ char *str;
+ switch (adata(abfd).magic) {
+ case n_magic: str = "NMAGIC"; break;
+ case o_magic: str = "OMAGIC"; break;
+ case z_magic: str = "ZMAGIC"; break;
+ default: abort ();
+ }
+ str;
+ }),
+ obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->alignment_power,
+ obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->alignment_power,
+ obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size, obj_bsssec(abfd)->alignment_power);
+#endif
+#endif
+
+ switch (adata(abfd).magic)
+ {
+ case o_magic:
+ {
+ file_ptr pos = adata (abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad = 0;
+
+ obj_textsec(abfd)->filepos = pos;
+ pos += obj_textsec(abfd)->_raw_size;
+ vma += obj_textsec(abfd)->_raw_size;
+ if (!obj_datasec(abfd)->user_set_vma)
+ {
+#if 0 /* ?? Does alignment in the file image really matter? */
+ pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma;
+#endif
+ obj_textsec(abfd)->_raw_size += pad;
+ pos += pad;
+ vma += pad;
+ obj_datasec(abfd)->vma = vma;
+ }
+ obj_datasec(abfd)->filepos = pos;
+ pos += obj_datasec(abfd)->_raw_size;
+ vma += obj_datasec(abfd)->_raw_size;
+ if (!obj_bsssec(abfd)->user_set_vma)
+ {
+#if 0
+ pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma;
+#endif
+ obj_datasec(abfd)->_raw_size += pad;
+ pos += pad;
+ vma += pad;
+ obj_bsssec(abfd)->vma = vma;
+ }
+ obj_bsssec(abfd)->filepos = pos;
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ execp->a_data = obj_datasec(abfd)->_raw_size;
+ execp->a_bss = obj_bsssec(abfd)->_raw_size;
+ N_SET_MAGIC (*execp, OMAGIC);
+ }
+ break;
+ case z_magic:
+ {
+ bfd_size_type data_pad, text_pad;
+ file_ptr text_end;
+ CONST struct aout_backend_data *abdp;
+ int ztih;
+ bfd_vma data_vma;
+
+ abdp = aout_backend_info (abfd);
+ ztih = abdp && abdp->text_includes_header;
+ obj_textsec(abfd)->filepos = (ztih
+ ? adata(abfd).exec_bytes_size
+ : adata(abfd).page_size);
+ if (! obj_textsec(abfd)->user_set_vma)
+ /* ?? Do we really need to check for relocs here? */
+ obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC)
+ ? 0
+ : (ztih
+ ? (abdp->default_text_vma
+ + adata(abfd).exec_bytes_size)
+ : abdp->default_text_vma));
+ /* Could take strange alignment of text section into account here? */
+
+ /* Find start of data. */
+ text_end = obj_textsec(abfd)->filepos + obj_textsec(abfd)->_raw_size;
+ text_pad = BFD_ALIGN (text_end, adata(abfd).page_size) - text_end;
+ obj_textsec(abfd)->_raw_size += text_pad;
+ text_end += text_pad;
+
+ if (!obj_datasec(abfd)->user_set_vma)
+ {
+ bfd_vma vma;
+ vma = obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size;
+ obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size);
+ }
+ data_vma = obj_datasec(abfd)->vma;
+ if (abdp && abdp->zmagic_mapped_contiguous)
+ {
+ text_pad = (obj_datasec(abfd)->vma
+ - obj_textsec(abfd)->vma
+ - obj_textsec(abfd)->_raw_size);
+ obj_textsec(abfd)->_raw_size += text_pad;
+ }
+ obj_datasec(abfd)->filepos = (obj_textsec(abfd)->filepos
+ + obj_textsec(abfd)->_raw_size);
+
+ /* Fix up exec header while we're at it. */
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
+ execp->a_text += adata(abfd).exec_bytes_size;
+ N_SET_MAGIC (*execp, ZMAGIC);
+ /* Spec says data section should be rounded up to page boundary. */
+ /* If extra space in page is left after data section, fudge data
+ in the header so that the bss section looks smaller by that
+ amount. We'll start the bss section there, and lie to the OS. */
+ obj_datasec(abfd)->_raw_size
+ = align_power (obj_datasec(abfd)->_raw_size,
+ obj_bsssec(abfd)->alignment_power);
+ execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size,
+ adata(abfd).page_size);
+ data_pad = execp->a_data - obj_datasec(abfd)->_raw_size;
+
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma
+ + obj_datasec(abfd)->_raw_size);
+ if (data_pad > obj_bsssec(abfd)->_raw_size)
+ execp->a_bss = 0;
+ else
+ execp->a_bss = obj_bsssec(abfd)->_raw_size - data_pad;
+ }
+ break;
+ case n_magic:
+ {
+ file_ptr pos = adata(abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad;
+
+ obj_textsec(abfd)->filepos = pos;
+ if (!obj_textsec(abfd)->user_set_vma)
+ obj_textsec(abfd)->vma = vma;
+ else
+ vma = obj_textsec(abfd)->vma;
+ pos += obj_textsec(abfd)->_raw_size;
+ vma += obj_textsec(abfd)->_raw_size;
+ obj_datasec(abfd)->filepos = pos;
+ if (!obj_datasec(abfd)->user_set_vma)
+ obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size);
+ vma = obj_datasec(abfd)->vma;
+
+ /* Since BSS follows data immediately, see if it needs alignment. */
+ vma += obj_datasec(abfd)->_raw_size;
+ pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma;
+ obj_datasec(abfd)->_raw_size += pad;
+ pos += obj_datasec(abfd)->_raw_size;
+
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = vma;
+ else
+ vma = obj_bsssec(abfd)->vma;
+ }
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ execp->a_data = obj_datasec(abfd)->_raw_size;
+ execp->a_bss = obj_bsssec(abfd)->_raw_size;
+ N_SET_MAGIC (*execp, NMAGIC);
+ break;
+ default:
+ abort ();
+ }
+#ifdef BFD_AOUT_DEBUG
+ fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n",
+ obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->filepos,
+ obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->filepos,
+ obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size);
+#endif
+ return true;
+}
+
+/*
+FUNCTION
+ aout_<size>_new_section_hook
+
+DESCRIPTION
+ Called by the BFD in response to a @code{bfd_make_section}
+ request.
+
+SYNOPSIS
+ boolean aout_<size>_new_section_hook,
+ (bfd *abfd,
+ asection *newsect));
+*/
+boolean
+DEFUN(NAME(aout,new_section_hook),(abfd, newsect),
+ bfd *abfd AND
+ asection *newsect)
+{
+ /* align to double at least */
+ newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power;
+
+
+ if (bfd_get_format (abfd) == bfd_object)
+ {
+ if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) {
+ obj_textsec(abfd)= newsect;
+ newsect->target_index = N_TEXT | N_EXT;
+ return true;
+ }
+
+ if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) {
+ obj_datasec(abfd) = newsect;
+ newsect->target_index = N_DATA | N_EXT;
+ return true;
+ }
+
+ if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) {
+ obj_bsssec(abfd) = newsect;
+ newsect->target_index = N_BSS | N_EXT;
+ return true;
+ }
+
+ }
+
+ /* We allow more than three sections internally */
+ return true;
+}
+
+boolean
+DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ file_ptr text_end;
+ bfd_size_type text_size;
+
+ if (abfd->output_has_begun == false)
+ {
+ if (NAME(aout,adjust_sizes_and_vmas) (abfd,
+ &text_size,
+ &text_end) == false)
+ return false;
+ }
+
+ /* regardless, once we know what we're doing, we might as well get going */
+ if (section != obj_bsssec(abfd))
+ {
+ bfd_seek (abfd, section->filepos + offset, SEEK_SET);
+
+ if (count) {
+ return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
+ true : false;
+ }
+ return true;
+ }
+ return true;
+}
+
+/* Classify stabs symbols */
+
+#define sym_in_text_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT)
+
+#define sym_in_data_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA)
+
+#define sym_in_bss_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS)
+
+/* Symbol is undefined if type is N_UNDF|N_EXT and if it has
+ zero in the "value" field. Nonzeroes there are fortrancommon
+ symbols. */
+#define sym_is_undefined(sym) \
+ ((sym)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0)
+
+/* Symbol is a global definition if N_EXT is on and if it has
+ a nonzero type field. */
+#define sym_is_global_defn(sym) \
+ (((sym)->type & N_EXT) && (sym)->type & N_TYPE)
+
+/* Symbol is debugger info if any bits outside N_TYPE or N_EXT
+ are on. */
+#define sym_is_debugger_info(sym) \
+ (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN)
+
+#define sym_is_fortrancommon(sym) \
+ (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0)
+
+/* Symbol is absolute if it has N_ABS set */
+#define sym_is_absolute(sym) \
+ (((sym)->type & N_TYPE)== N_ABS)
+
+
+#define sym_is_indirect(sym) \
+ (((sym)->type & N_ABS)== N_ABS)
+
+/* Only in their own functions for ease of debugging; when sym flags have
+ stabilised these should be inlined into their (single) caller */
+
+static void
+DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd),
+ struct external_nlist *sym_pointer AND
+ aout_symbol_type * cache_ptr AND
+ bfd * abfd)
+{
+ cache_ptr->symbol.section = 0;
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_SETA:
+ case N_SETT:
+ case N_SETD:
+ case N_SETB:
+ {
+ char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+ asection *section;
+ asection *into_section;
+
+ arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+ strcpy (copy, cache_ptr->symbol.name);
+
+ /* Make sure that this bfd has a section with the right contructor
+ name */
+ section = bfd_get_section_by_name (abfd, copy);
+ if (!section)
+ section = bfd_make_section (abfd, copy);
+
+ /* Build a relocation entry for the constructor */
+ switch ((cache_ptr->type & N_TYPE))
+ {
+ case N_SETA:
+ into_section = &bfd_abs_section;
+ cache_ptr->type = N_ABS;
+ break;
+ case N_SETT:
+ into_section = (asection *) obj_textsec (abfd);
+ cache_ptr->type = N_TEXT;
+ break;
+ case N_SETD:
+ into_section = (asection *) obj_datasec (abfd);
+ cache_ptr->type = N_DATA;
+ break;
+ case N_SETB:
+ into_section = (asection *) obj_bsssec (abfd);
+ cache_ptr->type = N_BSS;
+ break;
+ default:
+ abort ();
+ }
+
+ /* Build a relocation pointing into the constuctor section
+ pointing at the symbol in the set vector specified */
+
+ reloc->relent.addend = cache_ptr->symbol.value;
+ cache_ptr->symbol.section = into_section->symbol->section;
+ reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr;
+
+
+ /* We modify the symbol to belong to a section depending upon the
+ name of the symbol - probably __CTOR__ or __DTOR__ but we don't
+ really care, and add to the size of the section to contain a
+ pointer to the symbol. Build a reloc entry to relocate to this
+ symbol attached to this section. */
+
+ section->flags = SEC_CONSTRUCTOR;
+
+
+ section->reloc_count++;
+ section->alignment_power = 2;
+
+ reloc->next = section->constructor_chain;
+ section->constructor_chain = reloc;
+ reloc->relent.address = section->_raw_size;
+ section->_raw_size += sizeof (int *);
+
+ reloc->relent.howto
+ = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE
+ ? howto_table_ext : howto_table_std)
+ + CTOR_TABLE_RELOC_IDX;
+ cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
+ }
+ break;
+ default:
+ if (cache_ptr->type == N_WARNING)
+ {
+ /* This symbol is the text of a warning message, the next symbol
+ is the symbol to associate the warning with */
+ cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
+
+ /* @@ Stuffing pointers into integers is a no-no.
+ We can usually get away with it if the integer is
+ large enough though. */
+ if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
+ abort ();
+ cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
+
+ /* We furgle with the next symbol in place.
+ We don't want it to be undefined, we'll trample the type */
+ (sym_pointer + 1)->e_type[0] = 0xff;
+ break;
+ }
+ if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT))
+ {
+ /* Two symbols in a row for an INDR message. The first symbol
+ contains the name we will match, the second symbol contains
+ the name the first name is translated into. It is supplied to
+ us undefined. This is good, since we want to pull in any files
+ which define it */
+ cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT;
+
+ /* @@ Stuffing pointers into integers is a no-no.
+ We can usually get away with it if the integer is
+ large enough though. */
+ if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
+ abort ();
+
+ cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
+ cache_ptr->symbol.section = &bfd_ind_section;
+ }
+
+ else if (sym_is_debugger_info (cache_ptr))
+ {
+ cache_ptr->symbol.flags = BSF_DEBUGGING;
+ /* Work out the section correct for this symbol */
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_TEXT:
+ case N_FN:
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ cache_ptr->symbol.value -= obj_textsec (abfd)->vma;
+ break;
+ case N_DATA:
+ cache_ptr->symbol.value -= obj_datasec (abfd)->vma;
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ break;
+ case N_BSS:
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= obj_bsssec (abfd)->vma;
+ break;
+ default:
+ case N_ABS:
+
+ cache_ptr->symbol.section = &bfd_abs_section;
+ break;
+ }
+ }
+ else
+ {
+
+ if (sym_is_fortrancommon (cache_ptr))
+ {
+ cache_ptr->symbol.flags = 0;
+ cache_ptr->symbol.section = &bfd_com_section;
+ }
+ else
+ {
+
+
+ }
+
+ /* In a.out, the value of a symbol is always relative to the
+ * start of the file, if this is a data symbol we'll subtract
+ * the size of the text section to get the section relative
+ * value. If this is a bss symbol (which would be strange)
+ * we'll subtract the size of the previous two sections
+ * to find the section relative address.
+ */
+
+ if (sym_in_text_section (cache_ptr))
+ {
+ cache_ptr->symbol.value -= obj_textsec (abfd)->vma;
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ }
+ else if (sym_in_data_section (cache_ptr))
+ {
+ cache_ptr->symbol.value -= obj_datasec (abfd)->vma;
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ }
+ else if (sym_in_bss_section (cache_ptr))
+ {
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= obj_bsssec (abfd)->vma;
+ }
+ else if (sym_is_undefined (cache_ptr))
+ {
+ cache_ptr->symbol.flags = 0;
+ cache_ptr->symbol.section = &bfd_und_section;
+ }
+ else if (sym_is_absolute (cache_ptr))
+ {
+ cache_ptr->symbol.section = &bfd_abs_section;
+ }
+
+ if (sym_is_global_defn (cache_ptr))
+ {
+ cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
+ }
+ else
+ {
+ cache_ptr->symbol.flags = BSF_LOCAL;
+ }
+ }
+ }
+ if (cache_ptr->symbol.section == 0)
+ abort ();
+}
+
+
+
+static void
+DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd),
+ struct external_nlist *sym_pointer AND
+ asymbol *cache_ptr AND
+ bfd *abfd)
+{
+ bfd_vma value = cache_ptr->value;
+
+ /* mask out any existing type bits in case copying from one section
+ to another */
+ sym_pointer->e_type[0] &= ~N_TYPE;
+
+
+ /* We attempt to order these tests by decreasing frequency of success,
+ according to tcov when linking the linker. */
+ if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) {
+ sym_pointer->e_type[0] |= N_ABS;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
+ sym_pointer->e_type[0] |= N_TEXT;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
+ sym_pointer->e_type[0] |= N_DATA;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
+ sym_pointer->e_type[0] |= N_BSS;
+ }
+ else if (bfd_get_output_section(cache_ptr) == &bfd_und_section)
+ {
+ sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+ }
+ else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section)
+ {
+ sym_pointer->e_type[0] = N_INDR;
+ }
+ else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) {
+ sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+ }
+ else {
+ if (cache_ptr->section->output_section)
+ {
+
+ bfd_error_vector.nonrepresentable_section(abfd,
+ bfd_get_output_section(cache_ptr)->name);
+ }
+ else
+ {
+ bfd_error_vector.nonrepresentable_section(abfd,
+ cache_ptr->section->name);
+
+ }
+
+ }
+ /* Turn the symbol from section relative to absolute again */
+
+ value += cache_ptr->section->output_section->vma + cache_ptr->section->output_offset ;
+
+
+ if (cache_ptr->flags & (BSF_WARNING)) {
+ (sym_pointer+1)->e_type[0] = 1;
+ }
+
+ if (cache_ptr->flags & BSF_DEBUGGING) {
+ sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type;
+ }
+ else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
+ sym_pointer->e_type[0] |= N_EXT;
+ }
+ if (cache_ptr->flags & BSF_CONSTRUCTOR) {
+ int type = ((aout_symbol_type *)cache_ptr)->type;
+ switch (type)
+ {
+ case N_ABS: type = N_SETA; break;
+ case N_TEXT: type = N_SETT; break;
+ case N_DATA: type = N_SETD; break;
+ case N_BSS: type = N_SETB; break;
+ }
+ sym_pointer->e_type[0] = type;
+ }
+
+ PUT_WORD(abfd, value, sym_pointer->e_value);
+}
+
+/* Native-level interface to symbols. */
+
+/* We read the symbols into a buffer, which is discarded when this
+function exits. We read the strings into a buffer large enough to
+hold them all plus all the cached symbol entries. */
+
+asymbol *
+DEFUN(NAME(aout,make_empty_symbol),(abfd),
+ bfd *abfd)
+{
+ aout_symbol_type *new =
+ (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type));
+ new->symbol.the_bfd = abfd;
+
+ return &new->symbol;
+}
+
+boolean
+DEFUN(NAME(aout,slurp_symbol_table),(abfd),
+ bfd *abfd)
+{
+ bfd_size_type symbol_size;
+ bfd_size_type string_size;
+ unsigned char string_chars[BYTES_IN_WORD];
+ struct external_nlist *syms;
+ char *strings;
+ aout_symbol_type *cached;
+
+ /* If there's no work to be done, don't do any */
+ if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true;
+ symbol_size = exec_hdr(abfd)->a_syms;
+ if (symbol_size == 0)
+ {
+ bfd_error = no_symbols;
+ return false;
+ }
+
+ bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD)
+ return false;
+ string_size = GET_WORD (abfd, string_chars);
+
+ strings =(char *) bfd_alloc(abfd, string_size + 1);
+ cached = (aout_symbol_type *)
+ bfd_zalloc(abfd, (bfd_size_type)(bfd_get_symcount (abfd) * sizeof(aout_symbol_type)));
+
+ /* malloc this, so we can free it if simply. The symbol caching
+ might want to allocate onto the bfd's obstack */
+ syms = (struct external_nlist *) bfd_xmalloc(symbol_size);
+ bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size)
+ {
+ bailout:
+ if (syms)
+ free (syms);
+ if (cached)
+ bfd_release (abfd, cached);
+ if (strings)
+ bfd_release (abfd, strings);
+ return false;
+ }
+
+ bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size)
+ {
+ goto bailout;
+ }
+ strings[string_size] = 0; /* Just in case. */
+
+ /* OK, now walk the new symtable, cacheing symbol properties */
+ {
+ register struct external_nlist *sym_pointer;
+ register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd);
+ register aout_symbol_type *cache_ptr = cached;
+
+ /* Run through table and copy values */
+ for (sym_pointer = syms, cache_ptr = cached;
+ sym_pointer < sym_end; sym_pointer ++, cache_ptr++)
+ {
+ long x = GET_WORD(abfd, sym_pointer->e_strx);
+ cache_ptr->symbol.the_bfd = abfd;
+ if (x == 0)
+ cache_ptr->symbol.name = "";
+ else if (x >= 0 && x < string_size)
+ cache_ptr->symbol.name = x + strings;
+ else
+ goto bailout;
+
+ cache_ptr->symbol.value = GET_SWORD(abfd, sym_pointer->e_value);
+ cache_ptr->desc = bfd_h_get_16(abfd, sym_pointer->e_desc);
+ cache_ptr->other = bfd_h_get_8(abfd, sym_pointer->e_other);
+ cache_ptr->type = bfd_h_get_8(abfd, sym_pointer->e_type);
+ cache_ptr->symbol.udata = 0;
+ translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd);
+ }
+ }
+
+ obj_aout_symbols (abfd) = cached;
+ free((PTR)syms);
+
+ return true;
+}
+
+
+/* Possible improvements:
+ + look for strings matching trailing substrings of other strings
+ + better data structures? balanced trees?
+ + smaller per-string or per-symbol data? re-use some of the symbol's
+ data fields?
+ + also look at reducing memory use elsewhere -- maybe if we didn't have to
+ construct the entire symbol table at once, we could get by with smaller
+ amounts of VM? (What effect does that have on the string table
+ reductions?)
+ + rip this out of here, put it into its own file in bfd or libiberty, so
+ coff and elf can use it too. I'll work on this soon, but have more
+ pressing tasks right now.
+
+ A hash table might(?) be more efficient for handling exactly the cases that
+ are handled now, but for trailing substring matches, I think we want to
+ examine the `nearest' values (reverse-)lexically, not merely impose a strict
+ order, nor look only for exact-match or not-match. I don't think a hash
+ table would be very useful for that, and I don't feel like fleshing out two
+ completely different implementations. [raeburn:930419.0331EDT] */
+
+struct stringtab_entry {
+ /* Hash value for this string. Only useful so long as we aren't doing
+ substring matches. */
+ unsigned int hash;
+
+ /* Next node to look at, depending on whether the hash value of the string
+ being searched for is less than or greater than the hash value of the
+ current node. For now, `equal to' is lumped in with `greater than', for
+ space efficiency. It's not a common enough case to warrant another field
+ to be used for all nodes. */
+ struct stringtab_entry *less;
+ struct stringtab_entry *greater;
+
+ /* The string itself. */
+ CONST char *string;
+
+ /* The index allocated for this string. */
+ bfd_size_type index;
+
+#ifdef GATHER_STATISTICS
+ /* How many references have there been to this string? (Not currently used;
+ could be dumped out for anaylsis, if anyone's interested.) */
+ unsigned long count;
+#endif
+
+ /* Next node in linked list, in suggested output order. */
+ struct stringtab_entry *next_to_output;
+};
+
+struct stringtab_data {
+ /* Tree of string table entries. */
+ struct stringtab_entry *strings;
+
+ /* Fudge factor used to center top node of tree. */
+ int hash_zero;
+
+ /* Next index value to issue. */
+ bfd_size_type index;
+
+ /* Index used for empty strings. Cached here because checking for them
+ is really easy, and we can avoid searching the tree. */
+ bfd_size_type empty_string_index;
+
+ /* These fields indicate the two ends of a singly-linked list that indicates
+ the order strings should be written out in. Use this order, and no
+ seeking will need to be done, so output efficiency should be maximized. */
+ struct stringtab_entry **end;
+ struct stringtab_entry *output_order;
+
+#ifdef GATHER_STATISTICS
+ /* Number of strings which duplicate strings already in the table. */
+ unsigned long duplicates;
+
+ /* Number of bytes saved by not having to write all the duplicate strings. */
+ unsigned long bytes_saved;
+
+ /* Number of zero-length strings. Currently, these all turn into
+ references to the null byte at the end of the first string. In some
+ cases (possibly not all? explore this...), it should be possible to
+ simply write out a zero index value. */
+ unsigned long empty_strings;
+
+ /* Number of times the hash values matched but the strings were different.
+ Note that this includes the number of times the other string(s) occurs, so
+ there may only be two strings hashing to the same value, even if this
+ number is very large. */
+ unsigned long bad_hash_matches;
+
+ /* Null strings aren't counted in this one.
+ This will probably only be nonzero if we've got an input file
+ which was produced by `ld -r' (i.e., it's already been processed
+ through this code). Under some operating systems, native tools
+ may make all empty strings have the same index; but the pointer
+ check won't catch those, because to get to that stage we'd already
+ have to compute the checksum, which requires reading the string,
+ so we short-circuit that case with empty_string_index above. */
+ unsigned long pointer_matches;
+
+ /* Number of comparisons done. I figure with the algorithms in use below,
+ the average number of comparisons done (per symbol) should be roughly
+ log-base-2 of the number of unique strings. */
+ unsigned long n_compares;
+#endif
+};
+
+/* Some utility functions for the string table code. */
+
+/* For speed, only hash on the first this many bytes of strings.
+ This number was chosen by profiling ld linking itself, with -g. */
+#define HASHMAXLEN 25
+
+#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
+
+static INLINE unsigned int
+hash (string, len)
+ unsigned char *string;
+ register unsigned int len;
+{
+ register unsigned int sum = 0;
+
+ if (len > HASHMAXLEN)
+ {
+ HASH_CHAR (len);
+ len = HASHMAXLEN;
+ }
+
+ while (len--)
+ {
+ HASH_CHAR (*string++);
+ }
+ return sum;
+}
+
+static INLINE void
+stringtab_init (tab)
+ struct stringtab_data *tab;
+{
+ tab->strings = 0;
+ tab->output_order = 0;
+ tab->end = &tab->output_order;
+
+ /* Initial string table length includes size of length field. */
+ tab->index = BYTES_IN_WORD;
+ tab->empty_string_index = -1;
+#ifdef GATHER_STATISTICS
+ tab->duplicates = 0;
+ tab->empty_strings = 0;
+ tab->bad_hash_matches = 0;
+ tab->pointer_matches = 0;
+ tab->bytes_saved = 0;
+ tab->n_compares = 0;
+#endif
+}
+
+static INLINE int
+compare (entry, str, hash)
+ struct stringtab_entry *entry;
+ CONST char *str;
+ unsigned int hash;
+{
+ return hash - entry->hash;
+}
+
+#ifdef GATHER_STATISTICS
+/* Don't want to have to link in math library with all bfd applications... */
+static INLINE double
+log2 (num)
+ int num;
+{
+ double d = num;
+ int n = 0;
+ while (d >= 2.0)
+ n++, d /= 2.0;
+ return ((d > 1.41) ? 0.5 : 0) + n;
+}
+#endif
+
+/* Main string table routines. */
+/* Returns index in string table. Whether or not this actually adds an
+ entry into the string table should be irrelevant -- it just has to
+ return a valid index. */
+static bfd_size_type
+add_to_stringtab (abfd, str, tab, check)
+ bfd *abfd;
+ CONST char *str;
+ struct stringtab_data *tab;
+ int check;
+{
+ struct stringtab_entry **ep;
+ register struct stringtab_entry *entry;
+ unsigned int hashval, len;
+
+ if (str[0] == 0)
+ {
+ bfd_size_type index;
+ CONST bfd_size_type minus_one = -1;
+
+#ifdef GATHER_STATISTICS
+ tab->empty_strings++;
+#endif
+ index = tab->empty_string_index;
+ if (index != minus_one)
+ {
+ got_empty:
+#ifdef GATHER_STATISTICS
+ tab->bytes_saved++;
+ tab->duplicates++;
+#endif
+ return index;
+ }
+
+ /* Need to find it. */
+ entry = tab->strings;
+ if (entry)
+ {
+ index = entry->index + strlen (entry->string);
+ tab->empty_string_index = index;
+ goto got_empty;
+ }
+ len = 0;
+ }
+ else
+ len = strlen (str);
+
+ /* The hash_zero value is chosen such that the first symbol gets a value of
+ zero. With a balanced tree, this wouldn't be very useful, but without it,
+ we might get a more even split at the top level, instead of skewing it
+ badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */
+ hashval = hash (str, len) ^ tab->hash_zero;
+ ep = &tab->strings;
+ if (!*ep)
+ {
+ tab->hash_zero = hashval;
+ hashval = 0;
+ goto add_it;
+ }
+
+ while (*ep)
+ {
+ register int cmp;
+
+ entry = *ep;
+#ifdef GATHER_STATISTICS
+ tab->n_compares++;
+#endif
+ cmp = compare (entry, str, hashval);
+ /* The not-equal cases are more frequent, so check them first. */
+ if (cmp > 0)
+ ep = &entry->greater;
+ else if (cmp < 0)
+ ep = &entry->less;
+ else
+ {
+ if (entry->string == str)
+ {
+#ifdef GATHER_STATISTICS
+ tab->pointer_matches++;
+#endif
+ goto match;
+ }
+ /* Compare the first bytes to save a function call if they
+ don't match. */
+ if (entry->string[0] == str[0] && !strcmp (entry->string, str))
+ {
+ match:
+#ifdef GATHER_STATISTICS
+ entry->count++;
+ tab->bytes_saved += len + 1;
+ tab->duplicates++;
+#endif
+ /* If we're in the linker, and the new string is from a new
+ input file which might have already had these reductions
+ run over it, we want to keep the new string pointer. I
+ don't think we're likely to see any (or nearly as many,
+ at least) cases where a later string is in the same location
+ as an earlier one rather than this one. */
+ entry->string = str;
+ return entry->index;
+ }
+#ifdef GATHER_STATISTICS
+ tab->bad_hash_matches++;
+#endif
+ ep = &entry->greater;
+ }
+ }
+
+ /* If we get here, nothing that's in the table already matched.
+ EP points to the `next' field at the end of the chain; stick a
+ new entry on here. */
+ add_it:
+ entry = (struct stringtab_entry *)
+ bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry));
+
+ entry->less = entry->greater = 0;
+ entry->hash = hashval;
+ entry->index = tab->index;
+ entry->string = str;
+ entry->next_to_output = 0;
+#ifdef GATHER_STATISTICS
+ entry->count = 1;
+#endif
+
+ assert (*tab->end == 0);
+ *(tab->end) = entry;
+ tab->end = &entry->next_to_output;
+ assert (*tab->end == 0);
+
+ {
+ tab->index += len + 1;
+ if (len == 0)
+ tab->empty_string_index = entry->index;
+ }
+ assert (*ep == 0);
+ *ep = entry;
+ return entry->index;
+}
+
+static void
+emit_strtab (abfd, tab)
+ bfd *abfd;
+ struct stringtab_data *tab;
+{
+ struct stringtab_entry *entry;
+#ifdef GATHER_STATISTICS
+ int count = 0;
+#endif
+
+ /* Be sure to put string length into correct byte ordering before writing
+ it out. */
+ char buffer[BYTES_IN_WORD];
+
+ PUT_WORD (abfd, tab->index, (unsigned char *) buffer);
+ bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd);
+
+ for (entry = tab->output_order; entry; entry = entry->next_to_output)
+ {
+ bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd);
+#ifdef GATHER_STATISTICS
+ count++;
+#endif
+ }
+
+#ifdef GATHER_STATISTICS
+ /* Short form only, for now.
+ To do: Specify output file. Conditionalize on environment? Detailed
+ analysis if desired. */
+ {
+ int n_syms = bfd_get_symcount (abfd);
+
+ fprintf (stderr, "String table data for output file:\n");
+ fprintf (stderr, " %8d symbols output\n", n_syms);
+ fprintf (stderr, " %8d duplicate strings\n", tab->duplicates);
+ fprintf (stderr, " %8d empty strings\n", tab->empty_strings);
+ fprintf (stderr, " %8d unique strings output\n", count);
+ fprintf (stderr, " %8d pointer matches\n", tab->pointer_matches);
+ fprintf (stderr, " %8d bytes saved\n", tab->bytes_saved);
+ fprintf (stderr, " %8d bad hash matches\n", tab->bad_hash_matches);
+ fprintf (stderr, " %8d hash-val comparisons\n", tab->n_compares);
+ if (n_syms)
+ {
+ double n_compares = tab->n_compares;
+ double avg_compares = n_compares / n_syms;
+ /* The second value here should usually be near one. */
+ fprintf (stderr,
+ "\t average %f comparisons per symbol (%f * log2 nstrings)\n",
+ avg_compares, avg_compares / log2 (count));
+ }
+ }
+#endif
+
+/* Old code:
+ unsigned int count;
+ generic = bfd_get_outsymbols(abfd);
+ for (count = 0; count < bfd_get_symcount(abfd); count++)
+ {
+ asymbol *g = *(generic++);
+
+ if (g->name)
+ {
+ size_t length = strlen(g->name)+1;
+ bfd_write((PTR)g->name, 1, length, abfd);
+ }
+ g->KEEPIT = (KEEPITTYPE) count;
+ } */
+}
+
+void
+DEFUN(NAME(aout,write_syms),(abfd),
+ bfd *abfd)
+{
+ unsigned int count ;
+ asymbol **generic = bfd_get_outsymbols (abfd);
+ struct stringtab_data strtab;
+
+ stringtab_init (&strtab);
+
+ for (count = 0; count < bfd_get_symcount (abfd); count++)
+ {
+ asymbol *g = generic[count];
+ struct external_nlist nsp;
+
+ if (g->name)
+ PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab),
+ (unsigned char *) nsp.e_strx);
+ else
+ PUT_WORD (abfd, 0, (unsigned char *)nsp.e_strx);
+
+ if (bfd_asymbol_flavour(g) == abfd->xvec->flavour)
+ {
+ bfd_h_put_16(abfd, aout_symbol(g)->desc, nsp.e_desc);
+ bfd_h_put_8(abfd, aout_symbol(g)->other, nsp.e_other);
+ bfd_h_put_8(abfd, aout_symbol(g)->type, nsp.e_type);
+ }
+ else
+ {
+ bfd_h_put_16(abfd,0, nsp.e_desc);
+ bfd_h_put_8(abfd, 0, nsp.e_other);
+ bfd_h_put_8(abfd, 0, nsp.e_type);
+ }
+
+ translate_to_native_sym_flags (&nsp, g, abfd);
+
+ bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd);
+
+ /* NB: `KEEPIT' currently overlays `flags', so set this only
+ here, at the end. */
+ g->KEEPIT = count;
+ }
+
+ emit_strtab (abfd, &strtab);
+}
+
+
+unsigned int
+DEFUN(NAME(aout,get_symtab),(abfd, location),
+ bfd *abfd AND
+ asymbol **location)
+{
+ unsigned int counter = 0;
+ aout_symbol_type *symbase;
+
+ if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+
+ for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);)
+ *(location++) = (asymbol *)( symbase++);
+ *location++ =0;
+ return bfd_get_symcount (abfd);
+}
+
+
+/* Standard reloc stuff */
+/* Output standard relocation information to a file in target byte order. */
+
+void
+DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
+ bfd *abfd AND
+ arelent *g AND
+ struct reloc_std_external *natptr)
+{
+ int r_index;
+ asymbol *sym = *(g->sym_ptr_ptr);
+ int r_extern;
+ unsigned int r_length;
+ int r_pcrel;
+ int r_baserel, r_jmptable, r_relative;
+ unsigned int r_addend;
+ asection *output_section = sym->section->output_section;
+
+ PUT_WORD(abfd, g->address, natptr->r_address);
+
+ r_length = g->howto->size ; /* Size as a power of two */
+ r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */
+ /* XXX This relies on relocs coming from a.out files. */
+ r_baserel = (g->howto->type & 8) != 0;
+ /* r_jmptable, r_relative??? FIXME-soon */
+ r_jmptable = 0;
+ r_relative = 0;
+
+ r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+
+ /* name was clobbered by aout_write_syms to be symbol index */
+
+ /* If this relocation is relative to a symbol then set the
+ r_index to the symbols index, and the r_extern bit.
+
+ Absolute symbols can come in in two ways, either as an offset
+ from the abs section, or as a symbol which has an abs value.
+ check for that here
+ */
+
+
+ if (bfd_is_com_section (output_section)
+ || output_section == &bfd_abs_section
+ || output_section == &bfd_und_section)
+ {
+ if (bfd_abs_section.symbol == sym)
+ {
+ /* Whoops, looked like an abs symbol, but is really an offset
+ from the abs section */
+ r_index = 0;
+ r_extern = 0;
+ }
+ else
+ {
+ /* Fill in symbol */
+ r_extern = 1;
+ r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT);
+
+ }
+ }
+ else
+ {
+ /* Just an ordinary section */
+ r_extern = 0;
+ r_index = output_section->target_index;
+ }
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ natptr->r_index[0] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[2] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_STD_BITS_EXTERN_BIG: 0)
+ | (r_pcrel? RELOC_STD_BITS_PCREL_BIG: 0)
+ | (r_baserel? RELOC_STD_BITS_BASEREL_BIG: 0)
+ | (r_jmptable? RELOC_STD_BITS_JMPTABLE_BIG: 0)
+ | (r_relative? RELOC_STD_BITS_RELATIVE_BIG: 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
+ } else {
+ natptr->r_index[2] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[0] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0)
+ | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0)
+ | (r_baserel? RELOC_STD_BITS_BASEREL_LITTLE: 0)
+ | (r_jmptable? RELOC_STD_BITS_JMPTABLE_LITTLE: 0)
+ | (r_relative? RELOC_STD_BITS_RELATIVE_LITTLE: 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
+ }
+}
+
+
+/* Extended stuff */
+/* Output extended relocation information to a file in target byte order. */
+
+void
+DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
+ bfd *abfd AND
+ arelent *g AND
+ register struct reloc_ext_external *natptr)
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_type;
+ unsigned int r_addend;
+ asymbol *sym = *(g->sym_ptr_ptr);
+ asection *output_section = sym->section->output_section;
+
+ PUT_WORD (abfd, g->address, natptr->r_address);
+
+ r_type = (unsigned int) g->howto->type;
+
+ r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+
+ /* If this relocation is relative to a symbol then set the
+ r_index to the symbols index, and the r_extern bit.
+
+ Absolute symbols can come in in two ways, either as an offset
+ from the abs section, or as a symbol which has an abs value.
+ check for that here. */
+
+ if (bfd_is_com_section (output_section)
+ || output_section == &bfd_abs_section
+ || output_section == &bfd_und_section)
+ {
+ if (bfd_abs_section.symbol == sym)
+ {
+ /* Whoops, looked like an abs symbol, but is really an offset
+ from the abs section */
+ r_index = 0;
+ r_extern = 0;
+ }
+ else
+ {
+ r_extern = 1;
+ r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT);
+ }
+ }
+ else
+ {
+ /* Just an ordinary section */
+ r_extern = 0;
+ r_index = output_section->target_index;
+ }
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ natptr->r_index[0] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[2] = r_index;
+ natptr->r_type[0] =
+ ((r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
+ | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG));
+ } else {
+ natptr->r_index[2] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[0] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
+ | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+ }
+
+ PUT_WORD (abfd, r_addend, natptr->r_addend);
+}
+
+/* BFD deals internally with all things based from the section they're
+ in. so, something in 10 bytes into a text section with a base of
+ 50 would have a symbol (.text+10) and know .text vma was 50.
+
+ Aout keeps all it's symbols based from zero, so the symbol would
+ contain 60. This macro subs the base of each section from the value
+ to give the true offset from the section */
+
+
+#define MOVE_ADDRESS(ad) \
+ if (r_extern) { \
+ /* undefined symbol */ \
+ cache_ptr->sym_ptr_ptr = symbols + r_index; \
+ cache_ptr->addend = ad; \
+ } else { \
+ /* defined, section relative. replace symbol with pointer to \
+ symbol which points to section */ \
+ switch (r_index) { \
+ case N_TEXT: \
+ case N_TEXT | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->textsec->vma; \
+ break; \
+ case N_DATA: \
+ case N_DATA | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->datasec->vma; \
+ break; \
+ case N_BSS: \
+ case N_BSS | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->bsssec->vma; \
+ break; \
+ default: \
+ case N_ABS: \
+ case N_ABS | N_EXT: \
+ cache_ptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; \
+ cache_ptr->addend = ad; \
+ break; \
+ } \
+ } \
+
+void
+DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
+ bfd *abfd AND
+ struct reloc_ext_external *bytes AND
+ arelent *cache_ptr AND
+ asymbol **symbols)
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_type;
+ struct aoutdata *su = &(abfd->tdata.aout_data->a);
+
+ cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ r_index = (bytes->r_index[0] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[2];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
+ r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+ >> RELOC_EXT_BITS_TYPE_SH_BIG;
+ } else {
+ r_index = (bytes->r_index[2] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[0];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
+ r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+ >> RELOC_EXT_BITS_TYPE_SH_LITTLE;
+ }
+
+ cache_ptr->howto = howto_table_ext + r_type;
+ MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend));
+}
+
+void
+DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
+ bfd *abfd AND
+ struct reloc_std_external *bytes AND
+ arelent *cache_ptr AND
+ asymbol **symbols)
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_length;
+ int r_pcrel;
+ int r_baserel, r_jmptable, r_relative;
+ struct aoutdata *su = &(abfd->tdata.aout_data->a);
+ int howto_idx;
+
+ cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address);
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ r_index = (bytes->r_index[0] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[2];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
+ r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
+ r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+ r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+ r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
+ r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
+ >> RELOC_STD_BITS_LENGTH_SH_BIG;
+ } else {
+ r_index = (bytes->r_index[2] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[0];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
+ r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
+ r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+ r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+ r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
+ r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
+ >> RELOC_STD_BITS_LENGTH_SH_LITTLE;
+ }
+
+ howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel;
+ BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
+ cache_ptr->howto = howto_table_std + howto_idx;
+ BFD_ASSERT (cache_ptr->howto->type != -1);
+ BFD_ASSERT (r_jmptable == 0);
+ BFD_ASSERT (r_relative == 0);
+ /* FIXME-soon: Roll jmptable, relative bits into howto setting */
+
+ MOVE_ADDRESS(0);
+}
+
+/* Reloc hackery */
+
+boolean
+DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
+ bfd *abfd AND
+ sec_ptr asect AND
+ asymbol **symbols)
+{
+ unsigned int count;
+ bfd_size_type reloc_size;
+ PTR relocs;
+ arelent *reloc_cache;
+ size_t each_size;
+
+ if (asect->relocation) return true;
+
+ if (asect->flags & SEC_CONSTRUCTOR) return true;
+
+ if (asect == obj_datasec (abfd)) {
+ reloc_size = exec_hdr(abfd)->a_drsize;
+ goto doit;
+ }
+
+ if (asect == obj_textsec (abfd)) {
+ reloc_size = exec_hdr(abfd)->a_trsize;
+ goto doit;
+ }
+
+ bfd_error = invalid_operation;
+ return false;
+
+ doit:
+ bfd_seek (abfd, asect->rel_filepos, SEEK_SET);
+ each_size = obj_reloc_entry_size (abfd);
+
+ count = reloc_size / each_size;
+
+
+ reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t)(count * sizeof
+ (arelent)));
+ if (!reloc_cache) {
+nomem:
+ bfd_error = no_memory;
+ return false;
+ }
+
+ relocs = (PTR) bfd_alloc (abfd, reloc_size);
+ if (!relocs) {
+ bfd_release (abfd, reloc_cache);
+ goto nomem;
+ }
+
+ if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) {
+ bfd_release (abfd, relocs);
+ bfd_release (abfd, reloc_cache);
+ bfd_error = system_call_error;
+ return false;
+ }
+
+ if (each_size == RELOC_EXT_SIZE) {
+ register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
+ unsigned int counter = 0;
+ arelent *cache_ptr = reloc_cache;
+
+ for (; counter < count; counter++, rptr++, cache_ptr++) {
+ NAME(aout,swap_ext_reloc_in)(abfd, rptr, cache_ptr, symbols);
+ }
+ } else {
+ register struct reloc_std_external *rptr = (struct reloc_std_external*) relocs;
+ unsigned int counter = 0;
+ arelent *cache_ptr = reloc_cache;
+
+ for (; counter < count; counter++, rptr++, cache_ptr++) {
+ NAME(aout,swap_std_reloc_in)(abfd, rptr, cache_ptr, symbols);
+ }
+
+ }
+
+ bfd_release (abfd,relocs);
+ asect->relocation = reloc_cache;
+ asect->reloc_count = count;
+ return true;
+}
+
+
+
+/* Write out a relocation section into an object file. */
+
+boolean
+DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
+ bfd *abfd AND
+ asection *section)
+{
+ arelent **generic;
+ unsigned char *native, *natptr;
+ size_t each_size;
+
+ unsigned int count = section->reloc_count;
+ size_t natsize;
+
+ if (count == 0) return true;
+
+ each_size = obj_reloc_entry_size (abfd);
+ natsize = each_size * count;
+ native = (unsigned char *) bfd_zalloc (abfd, natsize);
+ if (!native) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ generic = section->orelocation;
+
+ if (each_size == RELOC_EXT_SIZE)
+ {
+ for (natptr = native;
+ count != 0;
+ --count, natptr += each_size, ++generic)
+ NAME(aout,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr);
+ }
+ else
+ {
+ for (natptr = native;
+ count != 0;
+ --count, natptr += each_size, ++generic)
+ NAME(aout,swap_std_reloc_out)(abfd, *generic, (struct reloc_std_external *)natptr);
+ }
+
+ if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) {
+ bfd_release(abfd, native);
+ return false;
+ }
+ bfd_release (abfd, native);
+
+ return true;
+}
+
+/* This is stupid. This function should be a boolean predicate */
+unsigned int
+DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols),
+ bfd *abfd AND
+ sec_ptr section AND
+ arelent **relptr AND
+ asymbol **symbols)
+{
+ arelent *tblptr = section->relocation;
+ unsigned int count;
+
+ if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols)))
+ return 0;
+
+ if (section->flags & SEC_CONSTRUCTOR) {
+ arelent_chain *chain = section->constructor_chain;
+ for (count = 0; count < section->reloc_count; count ++) {
+ *relptr ++ = &chain->relent;
+ chain = chain->next;
+ }
+ }
+ else {
+ tblptr = section->relocation;
+ if (!tblptr) return 0;
+
+ for (count = 0; count++ < section->reloc_count;)
+ {
+ *relptr++ = tblptr++;
+ }
+ }
+ *relptr = 0;
+
+ return section->reloc_count;
+}
+
+unsigned int
+DEFUN(NAME(aout,get_reloc_upper_bound),(abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (bfd_get_format (abfd) != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ if (asect->flags & SEC_CONSTRUCTOR) {
+ return (sizeof (arelent *) * (asect->reloc_count+1));
+ }
+
+
+ if (asect == obj_datasec (abfd))
+ return (sizeof (arelent *) *
+ ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd))
+ +1));
+
+ if (asect == obj_textsec (abfd))
+ return (sizeof (arelent *) *
+ ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd))
+ +1));
+
+ bfd_error = invalid_operation;
+ return 0;
+}
+
+
+ unsigned int
+DEFUN(NAME(aout,get_symtab_upper_bound),(abfd),
+ bfd *abfd)
+{
+ if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+
+ return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
+}
+ alent *
+DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol),
+ bfd *ignore_abfd AND
+ asymbol *ignore_symbol)
+{
+return (alent *)NULL;
+}
+
+void
+DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
+ bfd *ignore_abfd AND
+ asymbol *symbol AND
+ symbol_info *ret)
+{
+ bfd_symbol_info (symbol, ret);
+
+ if (ret->type == '?')
+ {
+ int type_code = aout_symbol(symbol)->type & 0xff;
+ CONST char *stab_name = aout_stab_name(type_code);
+ static char buf[10];
+
+ if (stab_name == NULL)
+ {
+ sprintf(buf, "(%d)", type_code);
+ stab_name = buf;
+ }
+ ret->type = '-';
+ ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff);
+ ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff);
+ ret->stab_name = stab_name;
+ }
+}
+
+void
+DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
+ bfd *ignore_abfd AND
+ PTR afile AND
+ asymbol *symbol AND
+ bfd_print_symbol_type how)
+{
+ FILE *file = (FILE *)afile;
+
+ switch (how) {
+ case bfd_print_symbol_name:
+ if (symbol->name)
+ fprintf(file,"%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff),
+ (unsigned)(aout_symbol(symbol)->other & 0xff),
+ (unsigned)(aout_symbol(symbol)->type));
+ break;
+ case bfd_print_symbol_all:
+ {
+ CONST char *section_name = symbol->section->name;
+
+
+ bfd_print_symbol_vandf((PTR)file,symbol);
+
+ fprintf(file," %-5s %04x %02x %02x",
+ section_name,
+ (unsigned)(aout_symbol(symbol)->desc & 0xffff),
+ (unsigned)(aout_symbol(symbol)->other & 0xff),
+ (unsigned)(aout_symbol(symbol)->type & 0xff));
+ if (symbol->name)
+ fprintf(file," %s", symbol->name);
+ }
+ break;
+ }
+}
+
+/*
+ provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location.
+*/
+
+boolean
+DEFUN(NAME(aout,find_nearest_line),(abfd,
+ section,
+ symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **symbols AND
+ bfd_vma offset AND
+ CONST char **filename_ptr AND
+ CONST char **functionname_ptr AND
+ unsigned int *line_ptr)
+{
+ /* Run down the file looking for the filename, function and linenumber */
+ asymbol **p;
+ static char buffer[100];
+ static char filename_buffer[200];
+ CONST char *directory_name = NULL;
+ CONST char *main_file_name = NULL;
+ CONST char *current_file_name = NULL;
+ CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */
+ bfd_vma high_line_vma = ~0;
+ bfd_vma low_func_vma = 0;
+ asymbol *func = 0;
+ *filename_ptr = abfd->filename;
+ *functionname_ptr = 0;
+ *line_ptr = 0;
+ if (symbols != (asymbol **)NULL) {
+ for (p = symbols; *p; p++) {
+ aout_symbol_type *q = (aout_symbol_type *)(*p);
+ next:
+ switch (q->type){
+ case N_SO:
+ main_file_name = current_file_name = q->symbol.name;
+ /* Look ahead to next symbol to check if that too is an N_SO. */
+ p++;
+ if (*p == NULL)
+ break;
+ q = (aout_symbol_type *)(*p);
+ if (q->type != (int)N_SO)
+ goto next;
+
+ /* Found a second N_SO First is directory; second is filename. */
+ directory_name = current_file_name;
+ main_file_name = current_file_name = q->symbol.name;
+ if (obj_textsec(abfd) != section)
+ goto done;
+ break;
+ case N_SOL:
+ current_file_name = q->symbol.name;
+ break;
+
+ case N_SLINE:
+
+ case N_DSLINE:
+ case N_BSLINE:
+ /* We'll keep this if it resolves nearer than the one we have already */
+ if (q->symbol.value >= offset &&
+ q->symbol.value < high_line_vma) {
+ *line_ptr = q->desc;
+ high_line_vma = q->symbol.value;
+ line_file_name = current_file_name;
+ }
+ break;
+ case N_FUN:
+ {
+ /* We'll keep this if it is nearer than the one we have already */
+ if (q->symbol.value >= low_func_vma &&
+ q->symbol.value <= offset) {
+ low_func_vma = q->symbol.value;
+ func = (asymbol *)q;
+ }
+ if (*line_ptr && func) {
+ CONST char *function = func->name;
+ char *p;
+ strncpy(buffer, function, sizeof(buffer)-1);
+ buffer[sizeof(buffer)-1] = 0;
+ /* Have to remove : stuff */
+ p = strchr(buffer,':');
+ if (p != NULL) { *p = '\0'; }
+ *functionname_ptr = buffer;
+ goto done;
+
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ done:
+ if (*line_ptr)
+ main_file_name = line_file_name;
+ if (main_file_name) {
+ if (main_file_name[0] == '/' || directory_name == NULL)
+ *filename_ptr = main_file_name;
+ else {
+ sprintf(filename_buffer, "%.140s%.50s",
+ directory_name, main_file_name);
+ *filename_ptr = filename_buffer;
+ }
+ }
+ return true;
+
+}
+
+int
+DEFUN(NAME(aout,sizeof_headers),(abfd, execable),
+ bfd *abfd AND
+ boolean execable)
+{
+ return adata(abfd).exec_bytes_size;
+}
diff --git a/gnu/usr.bin/gdb/bfd/archive.c b/gnu/usr.bin/gdb/bfd/archive.c
new file mode 100644
index 000000000000..5edae9d3db0a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archive.c
@@ -0,0 +1,1770 @@
+/* BFD back-end for archive files (libraries).
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+@setfilename archive-info
+SECTION
+ Archives
+
+DESCRIPTION
+ Archives are supported in BFD in <<archive.c>>.
+
+ An archive (or library) is just another BFD. It has a symbol
+ table, although there's not much a user program will do with it.
+
+ The big difference between an archive BFD and an ordinary BFD
+ is that the archive doesn't have sections. Instead it has a
+ chain of BFDs considered its contents. These BFDs can be
+ manipulated just like any other. The BFDs contained in an
+ archive opened for reading will all be opened for reading; you
+ may put either input or output BFDs into an archive opened for
+ output; it will be handled correctly when the archive is closed.
+
+ Use <<bfd_openr_next_archived_file>> to step through all
+ the contents of an archive opened for input. It's not
+ required that you read the entire archive if you don't want
+ to! Read it until you find what you want.
+
+ Archive contents of output BFDs are chained through the
+ <<next>> pointer in a BFD. The first one is findable through
+ the <<archive_head>> slot of the archive. Set it with
+ <<set_archive_head>> (q.v.). A given BFD may be in only one
+ open output archive at a time.
+
+ As expected, the BFD archive code is more general than the
+ archive code of any given environment. BFD archives may
+ contain files of different formats (e.g., a.out and coff) and
+ even different architectures. You may even place archives
+ recursively into archives!
+
+ This can cause unexpected confusion, since some archive
+ formats are more expressive than others. For instance, Intel
+ COFF archives can preserve long filenames; Sun a.out archives
+ cannot. If you move a file from the first to the second
+ format and back again, the filename may be truncated.
+ Likewise, different a.out environments have different
+ conventions as to how they truncate filenames, whether they
+ preserve directory names in filenames, etc. When
+ interoperating with native tools, be sure your files are
+ homogeneous.
+
+ Beware: most of these formats do not react well to the
+ presence of spaces in filenames. We do the best we can, but
+ can't always handle this due to restrctions in the format of
+ archives. Many unix utilities are braindead in regards to
+ spaces and such in filenames anyway, so this shouldn't be much
+ of a restriction.
+*/
+
+/* Assumes:
+ o - all archive elements start on an even boundary, newline padded;
+ o - all arch headers are char *;
+ o - all arch headers are the same size (across architectures).
+*/
+
+/* Some formats provide a way to cram a long filename into the short
+ (16 chars) space provided by a bsd archive. The trick is: make a
+ special "file" in the front of the archive, sort of like the SYMDEF
+ entry. If the filename is too long to fit, put it in the extended
+ name table, and use its index as the filename. To prevent
+ confusion prepend the index with a space. This means you can't
+ have filenames that start with a space, but then again, many unix
+ utilities can't handle that anyway.
+
+ This scheme unfortunately requires that you stand on your head in
+ order to write an archive since you need to put a magic file at the
+ front, and need to touch every entry to do so. C'est la vie.
+
+ We support two variants of this idea:
+ The SVR4 format (extended name table is named "//"),
+ and an extended pseudo-BSD variant (extended name table is named
+ "ARFILENAMES/"). The origin of the latter format is uncertain.
+
+ BSD 4.4 uses a third scheme: It writes a long filename
+ directly after the header. This allows 'ar q' to work.
+ We current can read BSD 4.4 archives, but not write them.
+*/
+
+/* Summary of archive member names:
+
+ Symbol table (must be first):
+ "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib.
+ "/ " - Symbol table, system 5 style.
+
+ Long name table (must be before regular file members):
+ "// " - Long name table, System 5 R4 style.
+ "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4).
+
+ Regular file members with short names:
+ "filename.o/ " - Regular file, System 5 style (embedded spaces ok).
+ "filename.o " - Regular file, Berkeley style (no embedded spaces).
+
+ Regular files with long names (or embedded spaces, for BSD variants):
+ "/18 " - SVR4 style, name at offset 18 in name table.
+ "#1/23 " - Long name (or embedded paces) 23 characters long,
+ BSD 4.4 style, full name follows header.
+ Implemented for reading, not writing.
+ " 18 " - Long name 18 characters long, extended pseudo-BSD.
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "aout/ar.h"
+#include "aout/ranlib.h"
+#include <errno.h>
+#include <string.h> /* For memchr, strrchr and friends */
+#include <ctype.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef GNU960
+#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB)
+#endif
+
+/* Can't define this in hosts/*.h, because (e.g. in gprof) the hosts file
+ is included, then obstack.h, which thinks if offsetof is defined, it
+ doesn't need to include stddef.h. */
+/* Define offsetof for those systems which lack it */
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* We keep a cache of archive filepointers to archive elements to
+ speed up searching the archive by filepos. We only add an entry to
+ the cache when we actually read one. We also don't sort the cache;
+ it's generally short enough to search linearly.
+ Note that the pointers here point to the front of the ar_hdr, not
+ to the front of the contents!
+*/
+struct ar_cache {
+ file_ptr ptr;
+ bfd* arelt;
+ struct ar_cache *next;
+};
+
+#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char)
+#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
+
+#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data))
+#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header)
+
+/* Forward declarations of functions */
+
+boolean
+compute_and_write_armap PARAMS ((bfd *arch, unsigned int elength));
+
+static boolean
+bsd_update_armap_timestamp PARAMS ((bfd *arch));
+
+
+
+boolean
+_bfd_generic_mkarchive (abfd)
+ bfd *abfd;
+{
+ abfd->tdata.aout_ar_data = (struct artdata *)bfd_zalloc(abfd,
+ sizeof (struct artdata));
+
+ if (bfd_ardata (abfd) == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ bfd_ardata(abfd)->cache = 0;
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_get_next_mapent
+
+SYNOPSIS
+ symindex bfd_get_next_mapent(bfd *, symindex previous, carsym ** sym);
+
+DESCRIPTION
+ This function steps through an archive's symbol table (if it
+ has one). Successively updates <<sym>> with the next symbol's
+ information, returning that symbol's (internal) index into the
+ symbol table.
+
+ Supply BFD_NO_MORE_SYMBOLS as the <<previous>> entry to get
+ the first one; returns BFD_NO_MORE_SYMBOLS when you're already
+ got the last one.
+
+ A <<carsym>> is a canonical archive symbol. The only
+ user-visible element is its name, a null-terminated string.
+*/
+
+symindex
+DEFUN(bfd_get_next_mapent,(abfd, prev, entry),
+ bfd *abfd AND
+ symindex prev AND
+ carsym **entry)
+{
+ if (!bfd_has_map (abfd)) {
+ bfd_error = invalid_operation;
+ return BFD_NO_MORE_SYMBOLS;
+ }
+
+ if (prev == BFD_NO_MORE_SYMBOLS) prev = 0;
+ else if (++prev >= bfd_ardata (abfd)->symdef_count)
+ return BFD_NO_MORE_SYMBOLS;
+
+ *entry = (bfd_ardata (abfd)->symdefs + prev);
+ return prev;
+}
+
+/* To be called by backends only */
+
+bfd *
+_bfd_create_empty_archive_element_shell (obfd)
+ bfd *obfd;
+{
+ bfd *nbfd;
+
+ nbfd = new_bfd_contained_in(obfd);
+ if (nbfd == NULL)
+ {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ return nbfd;
+}
+
+/*
+FUNCTION
+ bfd_set_archive_head
+
+SYNOPSIS
+ boolean bfd_set_archive_head(bfd *output, bfd *new_head);
+
+DESCRIPTION
+ Used whilst processing archives. Sets the head of the chain of
+ BFDs contained in an archive to @var{new_head}.
+*/
+
+boolean
+DEFUN(bfd_set_archive_head,(output_archive, new_head),
+ bfd *output_archive AND
+ bfd *new_head)
+{
+
+ output_archive->archive_head = new_head;
+ return true;
+}
+
+bfd *
+look_for_bfd_in_cache (arch_bfd, filepos)
+ bfd *arch_bfd;
+ file_ptr filepos;
+{
+ struct ar_cache *current;
+
+ for (current = bfd_ardata (arch_bfd)->cache; current != NULL;
+ current = current->next)
+ if (current->ptr == filepos) return current->arelt;
+
+ return NULL;
+}
+
+/* Kind of stupid to call cons for each one, but we don't do too many */
+boolean
+add_bfd_to_cache (arch_bfd, filepos, new_elt)
+ bfd *arch_bfd, *new_elt;
+ file_ptr filepos;
+{
+ struct ar_cache *new_cache = (struct ar_cache *)
+ bfd_zalloc(arch_bfd, sizeof (struct ar_cache));
+
+ if (new_cache == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ new_cache->ptr = filepos;
+ new_cache->arelt = new_elt;
+ new_cache->next = (struct ar_cache *)NULL;
+ if (bfd_ardata (arch_bfd)->cache == NULL)
+ bfd_ardata (arch_bfd)->cache = new_cache;
+ else {
+ struct ar_cache *current = bfd_ardata (arch_bfd)->cache;
+
+ for (; current->next != NULL; current = current->next);
+ current->next = new_cache;
+ }
+
+ return true;
+}
+
+
+
+/* The name begins with space. Hence the rest of the name is an index into
+ the string table. */
+char *
+get_extended_arelt_filename (arch, name)
+ bfd *arch;
+ char *name;
+{
+ unsigned long index = 0;
+
+ /* Should extract string so that I can guarantee not to overflow into
+ the next region, but I'm too lazy. */
+ errno = 0;
+ /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
+ index = strtol (name+1, NULL, 10);
+ if (errno != 0) {
+ bfd_error = malformed_archive;
+ return NULL;
+ }
+
+ return bfd_ardata (arch)->extended_names + index;
+}
+
+/* This functions reads an arch header and returns an areltdata pointer, or
+ NULL on error.
+
+ Presumes the file pointer is already in the right place (ie pointing
+ to the ar_hdr in the file). Moves the file pointer; on success it
+ should be pointing to the front of the file contents; on failure it
+ could have been moved arbitrarily.
+*/
+
+struct areltdata *
+snarf_ar_hdr (abfd)
+ bfd *abfd;
+{
+#ifndef errno
+ extern int errno;
+#endif
+
+ struct ar_hdr hdr;
+ char *hdrp = (char *) &hdr;
+ unsigned int parsed_size;
+ struct areltdata *ared;
+ char *filename = NULL;
+ unsigned int namelen = 0;
+ unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
+ char *allocptr = 0;
+
+ if (bfd_read ((PTR)hdrp, 1, sizeof (struct ar_hdr), abfd)
+ != sizeof (struct ar_hdr)) {
+ bfd_error = no_more_archived_files;
+ return NULL;
+ }
+ if (strncmp ((hdr.ar_fmag), ARFMAG, 2)) {
+ bfd_error = malformed_archive;
+ return NULL;
+ }
+
+ errno = 0;
+ parsed_size = strtol (hdr.ar_size, NULL, 10);
+ if (errno != 0) {
+ bfd_error = malformed_archive;
+ return NULL;
+ }
+
+ /* extract the filename from the archive - there are two ways to
+ specify an extendend name table, either the first char of the
+ name is a space, or it's a slash. */
+ if ((hdr.ar_name[0] == '/'
+ || (hdr.ar_name[0] == ' '
+ && memchr (hdr.ar_name, '/', ar_maxnamelen(abfd)) == NULL))
+ && bfd_ardata (abfd)->extended_names != NULL) {
+ filename = get_extended_arelt_filename (abfd, hdr.ar_name);
+ if (filename == NULL) {
+ bfd_error = malformed_archive;
+ return NULL;
+ }
+ }
+ /* BSD4.4-style long filename.
+ Only implemented for reading, so far! */
+ else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1'
+ && hdr.ar_name[2] == '/' && isdigit(hdr.ar_name[3]))
+ {
+ /* BSD-4.4 extended name */
+ namelen = atoi (&hdr.ar_name[3]);
+ allocsize += namelen + 1;
+ parsed_size -= namelen;
+
+ allocptr = bfd_zalloc(abfd, allocsize);
+ if (allocptr == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ filename = allocptr
+ + (sizeof (struct areltdata) + sizeof (struct ar_hdr));
+ if (bfd_read (filename, 1, namelen, abfd) != namelen) {
+ bfd_error = no_more_archived_files;
+ return NULL;
+ }
+ filename[namelen] = '\0';
+ }
+ else
+ {
+ /* We judge the end of the name by looking for '/' or ' '.
+ Note: The SYSV format (terminated by '/') allows embedded
+ spaces, so only look for ' ' if we don't find '/'. */
+
+ namelen = 0;
+ while (hdr.ar_name[namelen] != '\0' &&
+ hdr.ar_name[namelen] != '/') {
+ namelen++;
+ if (namelen == (unsigned)ar_maxnamelen(abfd)) {
+ namelen = 0;
+ while (hdr.ar_name[namelen] != ' '
+ && namelen < (unsigned)ar_maxnamelen(abfd)) {
+ namelen++;
+ }
+ break;
+ }
+ }
+
+ allocsize += namelen + 1;
+ }
+
+ if (!allocptr) {
+ allocptr = bfd_zalloc(abfd, allocsize);
+ if (allocptr == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ }
+
+ ared = (struct areltdata *) allocptr;
+
+ ared->arch_header = allocptr + sizeof (struct areltdata);
+ memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr));
+ ared->parsed_size = parsed_size;
+
+ if (filename != NULL) ared->filename = filename;
+ else {
+ ared->filename = allocptr + (sizeof (struct areltdata) +
+ sizeof (struct ar_hdr));
+ if (namelen)
+ memcpy (ared->filename, hdr.ar_name, namelen);
+ ared->filename[namelen] = '\0';
+ }
+
+ return ared;
+}
+
+/* This is an internal function; it's mainly used when indexing
+ through the archive symbol table, but also used to get the next
+ element, since it handles the bookkeeping so nicely for us.
+*/
+
+bfd *
+get_elt_at_filepos (archive, filepos)
+ bfd *archive;
+ file_ptr filepos;
+{
+ struct areltdata *new_areldata;
+ bfd *n_nfd;
+
+ n_nfd = look_for_bfd_in_cache (archive, filepos);
+ if (n_nfd)
+ return n_nfd;
+
+ if (0 > bfd_seek (archive, filepos, SEEK_SET))
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+
+ if ((new_areldata = snarf_ar_hdr (archive)) == NULL)
+ return NULL;
+
+ n_nfd = _bfd_create_empty_archive_element_shell (archive);
+ if (n_nfd == NULL)
+ {
+ bfd_release (archive, (PTR)new_areldata);
+ return NULL;
+ }
+
+ n_nfd->origin = bfd_tell (archive);
+ n_nfd->arelt_data = (PTR) new_areldata;
+ n_nfd->filename = new_areldata->filename;
+
+ if (add_bfd_to_cache (archive, filepos, n_nfd))
+ return n_nfd;
+
+ /* huh? */
+ bfd_release (archive, (PTR)n_nfd);
+ bfd_release (archive, (PTR)new_areldata);
+ return NULL;
+}
+
+/*
+FUNCTION
+ bfd_get_elt_at_index
+
+SYNOPSIS
+ bfd *bfd_get_elt_at_index(bfd * archive, int index);
+
+DESCRIPTION
+ Return the bfd which is referenced by the symbol indexed by <<index>>.
+ <<index>> should have been returned by <<bfd_get_next_mapent>> (q.v.).
+
+*/
+bfd *
+DEFUN(bfd_get_elt_at_index,(abfd, index),
+ bfd *abfd AND
+ int index)
+{
+ bfd *result =
+ get_elt_at_filepos
+ (abfd, (bfd_ardata (abfd)->symdefs + index)->file_offset);
+ return result;
+}
+
+/*
+FUNCTION
+ bfd_openr_next_archived_file
+
+SYNOPSIS
+ bfd* bfd_openr_next_archived_file(bfd *archive, bfd *previous);
+
+DESCRIPTION
+ Initially provided a BFD containing an archive and NULL, opens
+ an inpout BFD on the first contained element and returns that.
+ Subsequent calls to bfd_openr_next_archived_file should pass
+ the archive and the previous return value to return a created
+ BFD to the next contained element. NULL is returned when there
+ are no more.
+
+*/
+
+bfd *
+bfd_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
+{
+ if ((bfd_get_format (archive) != bfd_archive) ||
+ (archive->direction == write_direction))
+ {
+ bfd_error = invalid_operation;
+ return NULL;
+ }
+
+ return BFD_SEND (archive,
+ openr_next_archived_file,
+ (archive,
+ last_file));
+}
+
+bfd *
+bfd_generic_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
+{
+ file_ptr filestart;
+
+ if (!last_file)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else {
+ unsigned int size = arelt_size(last_file);
+ /* Pad to an even boundary...
+ Note that last_file->origin can be odd in the case of
+ BSD-4.4-style element with a long odd size. */
+ filestart = last_file->origin + size;
+ filestart += filestart % 2;
+ }
+
+ return get_elt_at_filepos (archive, filestart);
+}
+
+
+bfd_target *
+bfd_generic_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG+1];
+
+ if (bfd_read ((PTR)armag, 1, SARMAG, abfd) != SARMAG) {
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+#ifdef GNU960
+ if (strncmp (armag, BFD_GNU960_ARMAG(abfd), SARMAG)) return 0;
+#else
+ if (strncmp (armag, ARMAG, SARMAG) &&
+ strncmp (armag, ARMAGB, SARMAG)) return 0;
+#endif
+
+
+
+ /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
+ involves a cast, we can't do it as the left operand of assignment. */
+ abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc(abfd,sizeof (struct artdata));
+
+ if (bfd_ardata (abfd) == NULL) {
+ bfd_error = no_memory;
+ return 0;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+
+ if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) {
+ bfd_release(abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return 0;
+ }
+
+ if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) {
+ bfd_release(abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return 0;
+ }
+
+ return abfd->xvec;
+}
+
+/* Returns false on error, true otherwise */
+static boolean
+DEFUN (do_slurp_bsd_armap, (abfd),
+ bfd *abfd)
+{
+ struct areltdata *mapdata;
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int parsed_size;
+
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
+
+ raw_armap = (int *) bfd_zalloc(abfd, parsed_size);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) {
+ bfd_error = malformed_archive;
+ byebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ return false;
+ }
+
+ ardata->symdef_count =
+ bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
+
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > parsed_size - sizeof (*raw_armap)) {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebye;
+ }
+
+ ardata->cache = 0;
+ rbase = raw_armap+1;
+ ardata->symdefs = (carsym *) rbase;
+ stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+
+ for (;counter < ardata->symdef_count; counter++) {
+ struct symdef *sym = ((struct symdef *) rbase) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
+
+/* Returns false on error, true otherwise */
+static boolean
+DEFUN (do_slurp_coff_armap, (abfd),
+ bfd *abfd)
+{
+ struct areltdata *mapdata;
+ int *raw_armap, *rawptr;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ unsigned int parsed_size;
+ carsym *carsyms;
+ unsigned int nsymz; /* Number of symbols in armap. */
+
+ bfd_vma (*swap) PARAMS ((bfd_byte*));
+ char int_buf[sizeof(long)];
+ unsigned int carsym_size, ptrsize, i;
+
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
+
+ if (bfd_read ((PTR)int_buf, 1, 4, abfd) != 4) {
+ bfd_error = malformed_archive;
+ return false;
+ }
+ /* It seems that all numeric information in a coff archive is always
+ in big endian format, nomatter the host or target. */
+ swap = bfd_getb32;
+ nsymz = bfd_getb32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+
+#if 1
+ /* ... except that some archive formats are broken, and it may be our
+ fault - the i960 little endian coff sometimes has big and sometimes
+ little, because our tools changed. Here's a horrible hack to clean
+ up the crap. */
+
+ if (stringsize > 0xfffff) {
+ /* This looks dangerous, let's do it the other way around */
+ nsymz = bfd_getl32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+ swap = bfd_getl32;
+ }
+#endif
+
+ /* The coff armap must be read sequentially. So we construct a bsd-style
+ one in core all at once, for simplicity. */
+
+ carsym_size = (nsymz * sizeof (carsym));
+ ptrsize = (4 * nsymz);
+
+ ardata->symdefs = (carsym *) bfd_zalloc(abfd, carsym_size + stringsize + 1);
+ if (ardata->symdefs == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ carsyms = ardata->symdefs;
+ stringbase = ((char *) ardata->symdefs) + carsym_size;
+
+ /* Allocate and read in the raw offsets. */
+ raw_armap = (int *) bfd_alloc(abfd, ptrsize);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ goto release_symdefs;
+ }
+ if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize
+ || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) {
+ bfd_error = malformed_archive;
+ goto release_raw_armap;
+ }
+
+ /* OK, build the carsyms */
+ for (i = 0; i < nsymz; i++) {
+ rawptr = raw_armap + i;
+ carsyms->file_offset = swap((PTR)rawptr);
+ carsyms->name = stringbase;
+ while (*stringbase++) ;
+ carsyms++;
+ }
+ *stringbase = 0;
+
+ ardata->symdef_count = nsymz;
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata->first_file_filepos) %2;
+
+ bfd_has_map (abfd) = true;
+ bfd_release (abfd, (PTR)raw_armap);
+ return true;
+
+ release_raw_armap:
+ bfd_release (abfd, (PTR)raw_armap);
+ release_symdefs:
+ bfd_release (abfd, (PTR)(ardata)->symdefs);
+ return false;
+}
+
+/* This routine can handle either coff-style or bsd-style armaps.
+ Returns false on error, true otherwise */
+
+boolean
+bfd_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ int i = bfd_read ((PTR)nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+ else if (!strncmp (nextname, "/ ", 16))
+ return do_slurp_coff_armap (abfd);
+
+ bfd_has_map (abfd) = false;
+ return true;
+}
+
+/* Returns false on error, true otherwise */
+/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
+ header is in a slightly different order and the map name is '/'.
+ This flavour is used by hp300hpux. */
+boolean
+bfd_slurp_bsd_armap_f2 (abfd)
+ bfd *abfd;
+{
+ struct areltdata *mapdata;
+ char nextname[17];
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ int i = bfd_read ((PTR)nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ /* The archive has at least 16 bytes in it */
+ bfd_seek (abfd, -16L, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+
+ if (strncmp (nextname, "/ ", 16))
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+
+ raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size);
+ if (raw_armap == NULL)
+ {
+ bfd_error = no_memory;
+ byebye:
+ bfd_release (abfd, (PTR)mapdata);
+ return false;
+ }
+
+ if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) !=
+ mapdata->parsed_size)
+ {
+ bfd_error = malformed_archive;
+ byebyebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ goto byebye;
+ }
+
+ ardata->symdef_count = bfd_h_get_16(abfd, (PTR)raw_armap);
+
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > mapdata->parsed_size - sizeof (*raw_armap))
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebyebye;
+ }
+
+ ardata->cache = 0;
+
+ stringsize = bfd_h_get_32(abfd, (PTR)(((char*)raw_armap)+2));
+ /* skip sym count and string sz */
+ rbase = (int*)(((char*)raw_armap) + 6);
+ stringbase = (char *) rbase;
+ ardata->symdefs = (carsym *)(((char*) rbase) + stringsize);
+
+ for (;counter < ardata->symdef_count; counter++)
+ {
+ struct symdef *sym = ((struct symdef *) ardata->symdefs) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
+
+/** Extended name table.
+
+ Normally archives support only 14-character filenames.
+
+ Intel has extended the format: longer names are stored in a special
+ element (the first in the archive, or second if there is an armap);
+ the name in the ar_hdr is replaced by <space><index into filename
+ element>. Index is the P.R. of an int (decimal). Data General have
+ extended the format by using the prefix // for the special element */
+
+/* Returns false on error, true otherwise */
+boolean
+_bfd_slurp_extended_name_table (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ struct areltdata *namedata;
+
+ /* FIXME: Formatting sucks here, and in case of failure of BFD_READ,
+ we probably don't want to return true. */
+ if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) {
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
+ strncmp (nextname, "// ", 16) != 0)
+ {
+ bfd_ardata (abfd)->extended_names = NULL;
+ return true;
+ }
+
+ namedata = snarf_ar_hdr (abfd);
+ if (namedata == NULL) return false;
+
+ bfd_ardata (abfd)->extended_names = bfd_zalloc(abfd,namedata->parsed_size);
+ if (bfd_ardata (abfd)->extended_names == NULL) {
+ bfd_error = no_memory;
+ byebye:
+ bfd_release (abfd, (PTR)namedata);
+ return false;
+ }
+
+ if (bfd_read ((PTR)bfd_ardata (abfd)->extended_names, 1,
+ namedata->parsed_size, abfd) != namedata->parsed_size) {
+ bfd_error = malformed_archive;
+ bfd_release (abfd, (PTR)(bfd_ardata (abfd)->extended_names));
+ bfd_ardata (abfd)->extended_names = NULL;
+ goto byebye;
+ }
+
+ /* Since the archive is supposed to be printable if it contains
+ text, the entries in the list are newline-padded, not null
+ padded. In SVR4-style archives, the names also have a
+ trailing '/'. We'll fix both problems here.. */
+ {
+ char *temp = bfd_ardata (abfd)->extended_names;
+ char *limit = temp + namedata->parsed_size;
+ for (; temp < limit; ++temp)
+ if (*temp == '\n')
+ temp[temp[-1] == '/' ? -1 : 0] = '\0';
+ }
+
+ /* Pad to an even boundary if you have to */
+ bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd);
+ bfd_ardata (abfd)->first_file_filepos +=
+ (bfd_ardata (abfd)->first_file_filepos) %2;
+
+ /* FIXME, we can't release namedata here because it was allocated
+ below extended_names on the obstack... */
+ /* bfd_release (abfd, namedata); */
+ }
+ return true;
+}
+
+#ifdef VMS
+
+/* Return a copy of the stuff in the filename between any :]> and a
+ semicolon */
+static CONST char *
+DEFUN(normalize,(file),
+ CONST char *file)
+{
+ CONST char *first;
+ CONST char *last;
+ char *copy;
+
+ first = file + strlen(file)-1;
+ last = first+1;
+
+ while (first != file)
+ {
+ if (*first == ';')
+ last = first;
+ if (*first == ':' || *first == ']' ||*first == '>')
+ {
+ first++;
+ break;
+ }
+ first --;
+ }
+
+
+ copy = bfd_xmalloc(last - first + 1);
+ memcpy(copy, first, last-first);
+ copy[last-first] = 0;
+
+ return copy;
+}
+
+#else
+static CONST char *
+DEFUN (normalize, (file),
+ CONST char *file)
+{
+ CONST char * filename = strrchr(file, '/');
+
+ if (filename != (char *)NULL) {
+ filename ++;
+ }
+ else {
+ filename = file;
+ }
+ return filename;
+}
+#endif
+/* Follows archive_head and produces an extended name table if necessary.
+ Returns (in tabloc) a pointer to an extended name table, and in tablen
+ the length of the table. If it makes an entry it clobbers the filename
+ so that the element may be written without further massage.
+ Returns true if it ran successfully, false if something went wrong.
+ A successful return may still involve a zero-length tablen!
+ */
+boolean
+DEFUN (bfd_construct_extended_name_table, (abfd, tabloc, tablen),
+ bfd *abfd AND
+ char **tabloc AND
+ unsigned int *tablen)
+{
+ unsigned int maxname = abfd->xvec->ar_max_namelen;
+ unsigned int total_namelen = 0;
+ bfd *current;
+ char *strptr;
+
+ *tablen = 0;
+
+ /* Figure out how long the table should be */
+ for (current = abfd->archive_head; current != NULL; current = current->next){
+ unsigned int thislen = strlen (normalize(current->filename));
+ if (thislen > maxname) total_namelen += thislen + 1; /* leave room for \n */
+ }
+
+ if (total_namelen == 0) return true;
+
+ *tabloc = bfd_zalloc (abfd,total_namelen);
+ if (*tabloc == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ *tablen = total_namelen;
+ strptr = *tabloc;
+
+ for (current = abfd->archive_head; current != NULL; current =
+ current->next) {
+ CONST char *normal =normalize( current->filename);
+ unsigned int thislen = strlen (normal);
+ if (thislen > maxname) {
+ /* Works for now; may need to be re-engineered if we encounter an oddball
+ archive format and want to generalise this hack. */
+ struct ar_hdr *hdr = arch_hdr(current);
+ strcpy (strptr, normal);
+ strptr[thislen] = '\n';
+ hdr->ar_name[0] = ' ';
+ /* We know there will always be enough room (one of the few cases
+ where you may safely use sprintf). */
+ sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc));
+ /* Kinda Kludgy. We should just use the returned value of sprintf
+ but not all implementations get this right */
+ {
+ char *temp = hdr->ar_name +2;
+ for (; temp < hdr->ar_name + maxname; temp++)
+ if (*temp == '\0') *temp = ' ';
+ }
+ strptr += thislen + 1;
+ }
+ }
+
+ return true;
+}
+
+/** A couple of functions for creating ar_hdrs */
+
+/* Takes a filename, returns an arelt_data for it, or NULL if it can't make one.
+ The filename must refer to a filename in the filesystem.
+ The filename field of the ar_hdr will NOT be initialized
+*/
+
+struct areltdata *
+DEFUN(bfd_ar_hdr_from_filesystem, (abfd,filename),
+ bfd* abfd AND
+ CONST char *filename)
+{
+ struct stat status;
+ struct areltdata *ared;
+ struct ar_hdr *hdr;
+ char *temp, *temp1;
+
+
+ if (stat (filename, &status) != 0) {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+
+ ared = (struct areltdata *) bfd_zalloc(abfd, sizeof (struct ar_hdr) +
+ sizeof (struct areltdata));
+ if (ared == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
+
+ /* ar headers are space padded, not null padded! */
+ temp = (char *) hdr;
+ temp1 = temp + sizeof (struct ar_hdr) - 2;
+ for (; temp < temp1; *(temp++) = ' ');
+ strncpy (hdr->ar_fmag, ARFMAG, 2);
+
+ /* Goddamned sprintf doesn't permit MAXIMUM field lengths */
+ sprintf ((hdr->ar_date), "%-12ld", status.st_mtime);
+ sprintf ((hdr->ar_uid), "%d", status.st_uid);
+ sprintf ((hdr->ar_gid), "%d", status.st_gid);
+ sprintf ((hdr->ar_mode), "%-8o", (unsigned) status.st_mode);
+ sprintf ((hdr->ar_size), "%-10ld", status.st_size);
+ /* Correct for a lossage in sprintf whereby it null-terminates. I cannot
+ understand how these C losers could design such a ramshackle bunch of
+ IO operations */
+ temp = (char *) hdr;
+ temp1 = temp + sizeof (struct ar_hdr) - 2;
+ for (; temp < temp1; temp++) {
+ if (*temp == '\0') *temp = ' ';
+ }
+ strncpy (hdr->ar_fmag, ARFMAG, 2);
+ ared->parsed_size = status.st_size;
+ ared->arch_header = (char *) hdr;
+
+ return ared;
+}
+
+/* This is magic required by the "ar" program. Since it's
+ undocumented, it's undocumented. You may think that it would
+ take a strong stomach to write this, and it does, but it takes
+ even a stronger stomach to try to code around such a thing!
+*/
+
+struct ar_hdr *
+DEFUN(bfd_special_undocumented_glue, (abfd, filename),
+ bfd *abfd AND
+ char *filename)
+{
+ struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename);
+ if (ar_elt == NULL)
+ return NULL;
+ return (struct ar_hdr *) ar_elt->arch_header;
+}
+
+
+/* Analogous to stat call */
+int
+bfd_generic_stat_arch_elt (abfd, buf)
+ bfd *abfd;
+ struct stat *buf;
+{
+ struct ar_hdr *hdr;
+ char *aloser;
+
+ if (abfd->arelt_data == NULL) {
+ bfd_error = invalid_operation;
+ return -1;
+ }
+
+ hdr = arch_hdr (abfd);
+
+#define foo(arelt, stelt, size) \
+ buf->stelt = strtol (hdr->arelt, &aloser, size); \
+ if (aloser == hdr->arelt) return -1;
+
+ foo (ar_date, st_mtime, 10);
+ foo (ar_uid, st_uid, 10);
+ foo (ar_gid, st_gid, 10);
+ foo (ar_mode, st_mode, 8);
+
+ buf->st_size = arch_eltdata (abfd)->parsed_size;
+
+ return 0;
+}
+
+void
+bfd_dont_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ /* FIXME: This interacts unpleasantly with ar's quick-append option.
+ Fortunately ic960 users will never use that option. Fixing this
+ is very hard; fortunately I know how to do it and will do so once
+ intel's release is out the door. */
+
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = normalize(pathname);
+ int maxlen = ar_maxnamelen (abfd);
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+
+ if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd);
+ return;
+
+}
+
+void
+bfd_bsd_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = strrchr (pathname, '/');
+ int maxlen = ar_maxnamelen (abfd);
+
+
+ if (filename == NULL)
+ filename = pathname;
+ else
+ ++filename;
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+ else {
+ /* pathname: meet procrustes */
+ memcpy (hdr->ar_name, filename, maxlen);
+ length = maxlen;
+ }
+
+ if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd);
+}
+
+/* Store name into ar header. Truncates the name to fit.
+ 1> strip pathname to be just the basename.
+ 2> if it's short enuf to fit, stuff it in.
+ 3> If it doesn't end with .o, truncate it to fit
+ 4> truncate it before the .o, append .o, stuff THAT in.
+*/
+
+/* This is what gnu ar does. It's better but incompatible with the bsd ar. */
+void
+bfd_gnu_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = strrchr (pathname, '/');
+ int maxlen = ar_maxnamelen (abfd);
+
+ if (filename == NULL)
+ filename = pathname;
+ else
+ ++filename;
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+ else { /* pathname: meet procrustes */
+ memcpy (hdr->ar_name, filename, maxlen);
+ if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) {
+ hdr->ar_name[maxlen - 2] = '.';
+ hdr->ar_name[maxlen - 1] = 'o';
+ }
+ length = maxlen;
+ }
+
+ if (length < 16) (hdr->ar_name)[length] = ar_padchar (abfd);
+}
+
+
+/* The BFD is open for write and has its format set to bfd_archive */
+boolean
+_bfd_write_archive_contents (arch)
+ bfd *arch;
+{
+ bfd *current;
+ char *etable = NULL;
+ unsigned int elength = 0;
+ boolean makemap = bfd_has_map (arch);
+ boolean hasobjects = false; /* if no .o's, don't bother to make a map */
+ unsigned int i;
+ int tries;
+
+ /* Verify the viability of all entries; if any of them live in the
+ filesystem (as opposed to living in an archive open for input)
+ then construct a fresh ar_hdr for them.
+ */
+ for (current = arch->archive_head; current; current = current->next) {
+ if (bfd_write_p (current)) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+ if (!current->arelt_data) {
+ current->arelt_data =
+ (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename);
+ if (!current->arelt_data) return false;
+
+ /* Put in the file name */
+
+ BFD_SEND (arch, _bfd_truncate_arname,(arch,
+ current->filename,
+ (char *) arch_hdr(current)));
+
+
+ }
+
+ if (makemap) { /* don't bother if we won't make a map! */
+ if ((bfd_check_format (current, bfd_object))
+#if 0 /* FIXME -- these are not set correctly */
+ && ((bfd_get_file_flags (current) & HAS_SYMS))
+#endif
+ )
+ hasobjects = true;
+ }
+ }
+
+ if (!bfd_construct_extended_name_table (arch, &etable, &elength))
+ return false;
+
+ bfd_seek (arch, (file_ptr) 0, SEEK_SET);
+#ifdef GNU960
+ bfd_write (BFD_GNU960_ARMAG(arch), 1, SARMAG, arch);
+#else
+ bfd_write (ARMAG, 1, SARMAG, arch);
+#endif
+
+ if (makemap && hasobjects) {
+
+ if (compute_and_write_armap (arch, elength) != true) {
+ return false;
+ }
+ }
+
+ if (elength != 0) {
+ struct ar_hdr hdr;
+
+ memset ((char *)(&hdr), 0, sizeof (struct ar_hdr));
+ sprintf (&(hdr.ar_name[0]), "ARFILENAMES/");
+ sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
+ bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch);
+ bfd_write (etable, 1, elength, arch);
+ if ((elength % 2) == 1) bfd_write ("\n", 1, 1, arch);
+
+ }
+
+ for (current = arch->archive_head; current; current = current->next) {
+ char buffer[DEFAULT_BUFFERSIZE];
+ unsigned int remaining = arelt_size (current);
+ struct ar_hdr *hdr = arch_hdr(current);
+ /* write ar header */
+
+ if (bfd_write ((char *)hdr, 1, sizeof(*hdr), arch) != sizeof(*hdr)) {
+ syserr:
+ bfd_error = system_call_error;
+ return false;
+ }
+ if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto syserr;
+ while (remaining)
+ {
+ unsigned int amt = DEFAULT_BUFFERSIZE;
+ if (amt > remaining) {
+ amt = remaining;
+ }
+ errno = 0;
+ if (bfd_read (buffer, amt, 1, current) != amt) {
+ if (errno) goto syserr;
+ /* Looks like a truncated archive. */
+ bfd_error = malformed_archive;
+ return false;
+ }
+ if (bfd_write (buffer, amt, 1, arch) != amt) goto syserr;
+ remaining -= amt;
+ }
+ if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch);
+ }
+
+ /* Verify the timestamp in the archive file. If it would
+ not be accepted by the linker, rewrite it until it would be.
+ If anything odd happens, break out and just return.
+ (The Berkeley linker checks the timestamp and refuses to read the
+ table-of-contents if it is >60 seconds less than the file's
+ modified-time. That painful hack requires this painful hack. */
+
+ tries = 1;
+ do {
+ /* FIXME! This kludge is to avoid adding a member to the xvec,
+ while generating a small patch for Adobe. FIXME! The
+ update_armap_timestamp function call should be in the xvec,
+ thus:
+
+ if (bfd_update_armap_timestamp (arch) == true) break;
+ ^
+
+ Instead, we check whether in a BSD archive, and call directly. */
+
+ if (arch->xvec->write_armap != bsd_write_armap)
+ break;
+ if (bsd_update_armap_timestamp(arch) == true) /* FIXME!!! Vector it */
+ break;
+ if (tries > 0)
+ fprintf (stderr,
+ "Warning: writing archive was slow: rewriting timestamp\n");
+ } while (++tries < 6 );
+
+ return true;
+}
+
+/* Note that the namidx for the first symbol is 0 */
+
+boolean
+compute_and_write_armap (arch, elength)
+ bfd *arch;
+ unsigned int elength;
+{
+ bfd *current;
+ file_ptr elt_no = 0;
+ struct orl *map;
+ int orl_max = 15000; /* fine initial default */
+ int orl_count = 0;
+ int stridx = 0; /* string index */
+
+ /* Dunno if this is the best place for this info... */
+ if (elength != 0) elength += sizeof (struct ar_hdr);
+ elength += elength %2 ;
+
+ map = (struct orl *) bfd_zalloc (arch,orl_max * sizeof (struct orl));
+ if (map == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ /* Drop all the files called __.SYMDEF, we're going to make our
+ own */
+ while (arch->archive_head &&
+ strcmp(arch->archive_head->filename,"__.SYMDEF") == 0)
+ {
+ arch->archive_head = arch->archive_head->next;
+ }
+ /* Map over each element */
+ for (current = arch->archive_head;
+ current != (bfd *)NULL;
+ current = current->next, elt_no++)
+ {
+ if ((bfd_check_format (current, bfd_object) == true)
+ && ((bfd_get_file_flags (current) & HAS_SYMS))) {
+ asymbol **syms;
+ unsigned int storage;
+ unsigned int symcount;
+ unsigned int src_count;
+
+ storage = get_symtab_upper_bound (current);
+ if (storage != 0) {
+
+ syms = (asymbol **) bfd_zalloc (arch,storage);
+ if (syms == NULL) {
+ bfd_error = no_memory; /* FIXME -- memory leak */
+ return false;
+ }
+ symcount = bfd_canonicalize_symtab (current, syms);
+
+
+ /* Now map over all the symbols, picking out the ones we want */
+ for (src_count = 0; src_count <symcount; src_count++) {
+ flagword flags =
+ (syms[src_count])->flags;
+ asection *sec =
+ syms[src_count]->section;
+
+ if ((flags & BSF_GLOBAL ||
+ flags & BSF_WEAK ||
+ flags & BSF_INDIRECT ||
+ bfd_is_com_section (sec))
+ && (sec != &bfd_und_section)) {
+
+ /* This symbol will go into the archive header */
+ if (orl_count == orl_max)
+ {
+ orl_max *= 2;
+ map = (struct orl *) bfd_realloc (arch, (char *) map,
+ orl_max * sizeof (struct orl));
+ }
+
+ (map[orl_count]).name = (char **) &((syms[src_count])->name);
+ (map[orl_count]).pos = (file_ptr) current;
+ (map[orl_count]).namidx = stridx;
+
+ stridx += strlen ((syms[src_count])->name) + 1;
+ ++orl_count;
+ }
+ }
+ }
+ }
+ }
+ /* OK, now we have collected all the data, let's write them out */
+ if (!BFD_SEND (arch, write_armap,
+ (arch, elength, map, orl_count, stridx))) {
+
+ return false;
+ }
+
+
+ return true;
+}
+
+boolean
+bsd_write_armap (arch, elength, map, orl_count, stridx)
+ bfd *arch;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ int padit = stridx & 1;
+ unsigned int ranlibsize = orl_count * sizeof (struct ranlib);
+ unsigned int stringsize = stridx + padit;
+ /* Include 8 bytes to store ranlibsize and stringsize in output. */
+ unsigned int mapsize = ranlibsize + stringsize + 8;
+ file_ptr firstreal;
+ bfd *current = arch->archive_head;
+ bfd *last_elt = current; /* last element arch seen */
+ int temp;
+ int count;
+ struct ar_hdr hdr;
+ struct stat statbuf;
+ unsigned int i;
+
+ firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
+
+ stat (arch->filename, &statbuf);
+ memset ((char *)(&hdr), 0, sizeof (struct ar_hdr));
+ sprintf (hdr.ar_name, RANLIBMAG);
+ /* Remember the timestamp, to keep it holy. But fudge it a little. */
+ bfd_ardata(arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET;
+ bfd_ardata(arch)->armap_datepos = SARMAG +
+ offsetof(struct ar_hdr, ar_date[0]);
+ sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp);
+ sprintf (hdr.ar_uid, "%d", getuid());
+ sprintf (hdr.ar_gid, "%d", getgid());
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
+ bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch);
+ bfd_h_put_32(arch, (bfd_vma) ranlibsize, (PTR)&temp);
+ bfd_write (&temp, 1, sizeof (temp), arch);
+
+ for (count = 0; count < orl_count; count++) {
+ struct symdef outs;
+ struct symdef *outp = &outs;
+
+ if (((bfd *)(map[count]).pos) != last_elt) {
+ do {
+ firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ firstreal += firstreal % 2;
+ current = current->next;
+ } while (current != (bfd *)(map[count]).pos);
+ } /* if new archive element */
+
+ last_elt = current;
+ bfd_h_put_32(arch, ((map[count]).namidx),(PTR) &outs.s.string_offset);
+ bfd_h_put_32(arch, firstreal,(PTR) &outs.file_offset);
+ bfd_write ((char *)outp, 1, sizeof (outs), arch);
+ }
+
+ /* now write the strings themselves */
+ bfd_h_put_32(arch, stringsize, (PTR)&temp);
+ bfd_write ((PTR)&temp, 1, sizeof (temp), arch);
+ for (count = 0; count < orl_count; count++)
+ bfd_write (*((map[count]).name), 1, strlen (*((map[count]).name))+1, arch);
+
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for sun's ar we use a null. */
+ if (padit)
+ bfd_write("\0",1,1,arch);
+
+ return true;
+}
+
+
+/* At the end of archive file handling, update the timestamp in the
+ file, so the linker will accept it.
+
+ Return true if the timestamp was OK, or an unusual problem happened.
+ Return false if we updated the timestamp. */
+
+static boolean
+bsd_update_armap_timestamp (arch)
+ bfd *arch;
+{
+ struct stat archstat;
+ struct ar_hdr hdr;
+ int i;
+
+ /* Flush writes, get last-write timestamp from file, and compare it
+ to the timestamp IN the file. */
+ bfd_flush (arch);
+ if (bfd_stat (arch, &archstat) == -1) {
+ perror ("Reading archive file mod timestamp");
+ return true; /* Can't read mod time for some reason */
+ }
+ if (archstat.st_mtime <= bfd_ardata(arch)->armap_timestamp)
+ return true; /* OK by the linker's rules */
+
+ /* Update the timestamp. */
+ bfd_ardata(arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET;
+
+ /* Prepare an ASCII version suitable for writing. */
+ memset (hdr.ar_date, 0, sizeof (hdr.ar_date));
+ sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp);
+ for (i = 0; i < sizeof (hdr.ar_date); i++)
+ if (hdr.ar_date[i] == '\0')
+ (hdr.ar_date)[i] = ' ';
+
+ /* Write it into the file. */
+ bfd_seek (arch, bfd_ardata(arch)->armap_datepos, SEEK_SET);
+ if (bfd_write (hdr.ar_date, sizeof(hdr.ar_date), 1, arch)
+ != sizeof(hdr.ar_date)) {
+ perror ("Writing updated armap timestamp");
+ return true; /* Some error while writing */
+ }
+
+ return false; /* We updated the timestamp successfully. */
+}
+
+
+/* A coff armap looks like :
+ lARMAG
+ struct ar_hdr with name = '/'
+ number of symbols
+ offset of file for symbol 0
+ offset of file for symbol 1
+
+ offset of file for symbol n-1
+ symbol name 0
+ symbol name 1
+
+ symbol name n-1
+
+*/
+
+boolean
+coff_write_armap (arch, elength, map, symbol_count, stridx)
+ bfd *arch;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int symbol_count;
+ int stridx;
+{
+ /* The size of the ranlib is the number of exported symbols in the
+ archive * the number of bytes in a int, + an int for the count */
+
+ unsigned int ranlibsize = (symbol_count * 4) + 4;
+ unsigned int stringsize = stridx;
+ unsigned int mapsize = stringsize + ranlibsize;
+ file_ptr archive_member_file_ptr;
+ bfd *current = arch->archive_head;
+ int count;
+ struct ar_hdr hdr;
+ unsigned int i;
+ int padit = mapsize & 1;
+
+ if (padit) mapsize ++;
+
+ /* work out where the first object file will go in the archive */
+ archive_member_file_ptr = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
+
+ memset ((char *)(&hdr), 0, sizeof (struct ar_hdr));
+ hdr.ar_name[0] = '/';
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+ sprintf (hdr.ar_date, "%ld", (long)time (NULL));
+ /* This, at least, is what Intel coff sets the values to.: */
+ sprintf ((hdr.ar_uid), "%d", 0);
+ sprintf ((hdr.ar_gid), "%d", 0);
+ sprintf ((hdr.ar_mode), "%-7o",(unsigned ) 0);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
+
+ /* Write the ar header for this item and the number of symbols */
+
+
+ bfd_write ((PTR)&hdr, 1, sizeof (struct ar_hdr), arch);
+
+ bfd_write_bigendian_4byte_int(arch, symbol_count);
+
+ /* Two passes, first write the file offsets for each symbol -
+ remembering that each offset is on a two byte boundary. */
+
+ /* Write out the file offset for the file associated with each
+ symbol, and remember to keep the offsets padded out. */
+
+ current = arch->archive_head;
+ count = 0;
+ while (current != (bfd *)NULL && count < symbol_count) {
+ /* For each symbol which is used defined in this object, write out
+ the object file's address in the archive */
+
+ while (((bfd *)(map[count]).pos) == current) {
+ bfd_write_bigendian_4byte_int(arch, archive_member_file_ptr);
+ count++;
+ }
+ /* Add size of this archive entry */
+ archive_member_file_ptr += arelt_size (current) + sizeof (struct
+ ar_hdr);
+ /* remember aboout the even alignment */
+ archive_member_file_ptr += archive_member_file_ptr % 2;
+ current = current->next;
+ }
+
+
+
+ /* now write the strings themselves */
+ for (count = 0; count < symbol_count; count++) {
+ bfd_write ((PTR)*((map[count]).name),
+ 1,
+ strlen (*((map[count]).name))+1, arch);
+
+ }
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for arc960 we use a null. */
+ if (padit)
+ bfd_write("\0",1,1,arch);
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/archures.c b/gnu/usr.bin/gdb/bfd/archures.c
new file mode 100644
index 000000000000..9697904bd733
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archures.c
@@ -0,0 +1,731 @@
+/* BFD library support routines for architectures.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Hacked by John Gilmore and Steve Chamberlain of Cygnus Support.
+
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+SECTION
+ Architectures
+
+ BFD's idea of an architecture is implimented in
+ <<archures.c>>. BFD keeps one atom in a BFD describing the
+ architecture of the data attached to the BFD; a pointer to a
+ <<bfd_arch_info_type>>.
+
+ Pointers to structures can be requested independently of a bfd
+ so that an architecture's information can be interrogated
+ without access to an open bfd.
+
+ The arch information is provided by each architecture package.
+ The set of default architectures is selected by the #define
+ <<SELECT_ARCHITECTURES>>. This is normally set up in the
+ <<config/target.mt>> file of your choice. If the name is not
+ defined, then all the architectures supported are included.
+
+ When BFD starts up, all the architectures are called with an
+ initialize method. It is up to the architecture back end to
+ insert as many items into the list of architectures as it wants to;
+ generally this would be one for each machine and one for the
+ default case (an item with a machine field of 0).
+*/
+
+/*
+
+SUBSECTION
+ bfd_architecture
+
+DESCRIPTION
+ This enum gives the object file's CPU architecture, in a
+ global sense --- i.e., what processor family does it belong to?
+ There is another field, which indicates what processor within
+ the family is in use. The machine gives a number which
+ distingushes different versions of the architecture,
+ containing for example 2 and 3 for Intel i960 KA and i960 KB,
+ and 68020 and 68030 for Motorola 68020 and 68030.
+
+.enum bfd_architecture
+.{
+. bfd_arch_unknown, {* File arch not known *}
+. bfd_arch_obscure, {* Arch known, not one of these *}
+. bfd_arch_m68k, {* Motorola 68xxx *}
+. bfd_arch_vax, {* DEC Vax *}
+. bfd_arch_i960, {* Intel 960 *}
+. {* The order of the following is important.
+. lower number indicates a machine type that
+. only accepts a subset of the instructions
+. available to machines with higher numbers.
+. The exception is the "ca", which is
+. incompatible with all other machines except
+. "core". *}
+.
+.#define bfd_mach_i960_core 1
+.#define bfd_mach_i960_ka_sa 2
+.#define bfd_mach_i960_kb_sb 3
+.#define bfd_mach_i960_mc 4
+.#define bfd_mach_i960_xa 5
+.#define bfd_mach_i960_ca 6
+.
+. bfd_arch_a29k, {* AMD 29000 *}
+. bfd_arch_sparc, {* SPARC *}
+. bfd_arch_mips, {* MIPS Rxxxx *}
+. bfd_arch_i386, {* Intel 386 *}
+. bfd_arch_we32k, {* AT&T WE32xxx *}
+. bfd_arch_tahoe, {* CCI/Harris Tahoe *}
+. bfd_arch_i860, {* Intel 860 *}
+. bfd_arch_romp, {* IBM ROMP PC/RT *}
+. bfd_arch_alliant, {* Alliant *}
+. bfd_arch_convex, {* Convex *}
+. bfd_arch_m88k, {* Motorola 88xxx *}
+. bfd_arch_pyramid, {* Pyramid Technology *}
+. bfd_arch_h8300, {* Hitachi H8/300 *}
+.#define bfd_mach_h8300 1
+.#define bfd_mach_h8300h 2
+. bfd_arch_rs6000, {* IBM RS/6000 *}
+. bfd_arch_hppa, {* HP PA RISC *}
+. bfd_arch_z8k, {* Zilog Z8000 *}
+.#define bfd_mach_z8001 1
+.#define bfd_mach_z8002 2
+. bfd_arch_h8500, {* Hitachi H8/500 *}
+. bfd_arch_sh, {* Hitachi SH *}
+. bfd_arch_alpha, {* Dec Alpha *}
+. bfd_arch_last
+. };
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+
+SUBSECTION
+ bfd_arch_info
+
+DESCRIPTION
+ This structure contains information on architectures for use
+ within BFD.
+
+.
+.typedef struct bfd_arch_info
+.{
+. int bits_per_word;
+. int bits_per_address;
+. int bits_per_byte;
+. enum bfd_architecture arch;
+. long mach;
+. char *arch_name;
+. CONST char *printable_name;
+. unsigned int section_align_power;
+. {* true if this is the default machine for the architecture *}
+. boolean the_default;
+. CONST struct bfd_arch_info * (*compatible)
+. PARAMS ((CONST struct bfd_arch_info *a,
+. CONST struct bfd_arch_info *b));
+.
+. boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *));
+. {* How to disassemble an instruction, producing a printable
+. representation on a specified stdio stream. This isn't
+. defined for most processors at present, because of the size
+. of the additional tables it would drag in, and because gdb
+. wants to use a different interface. *}
+. unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data,
+. PTR stream));
+.
+. struct bfd_arch_info *next;
+.} bfd_arch_info_type;
+*/
+
+bfd_arch_info_type *bfd_arch_info_list;
+
+
+/*
+FUNCTION
+ bfd_printable_name
+
+SYNOPSIS
+ CONST char *bfd_printable_name(bfd *abfd);
+
+DESCRIPTION
+ Return a printable string representing the architecture and machine
+ from the pointer to the arch info structure
+
+*/
+
+CONST char *
+DEFUN(bfd_printable_name, (abfd),
+ bfd *abfd)
+{
+ return abfd->arch_info->printable_name;
+}
+
+
+
+/*
+FUNCTION
+ bfd_scan_arch
+
+SYNOPSIS
+ bfd_arch_info_type *bfd_scan_arch(CONST char *);
+
+DESCRIPTION
+ This routine is provided with a string and tries to work out
+ if bfd supports any cpu which could be described with the name
+ provided. The routine returns a pointer to an arch_info
+ structure if a machine is found, otherwise NULL.
+
+*/
+
+bfd_arch_info_type *
+DEFUN(bfd_scan_arch,(string),
+ CONST char *string)
+{
+ struct bfd_arch_info *ap;
+
+ /* Look through all the installed architectures */
+ for (ap = bfd_arch_info_list;
+ ap != (bfd_arch_info_type *)NULL;
+ ap = ap->next) {
+
+ if (ap->scan(ap, string))
+ return ap;
+ }
+ return (bfd_arch_info_type *)NULL;
+}
+
+
+
+/*
+FUNCTION
+ bfd_arch_get_compatible
+
+SYNOPSIS
+ CONST bfd_arch_info_type *bfd_arch_get_compatible(
+ CONST bfd *abfd,
+ CONST bfd *bbfd);
+
+DESCRIPTION
+ This routine is used to determine whether two BFDs'
+ architectures and achine types are compatible. It calculates
+ the lowest common denominator between the two architectures
+ and machine types implied by the BFDs and returns a pointer to
+ an arch_info structure describing the compatible machine.
+*/
+
+CONST bfd_arch_info_type *
+DEFUN(bfd_arch_get_compatible,(abfd, bbfd),
+CONST bfd *abfd AND
+CONST bfd *bbfd)
+
+{
+ return abfd->arch_info->compatible(abfd->arch_info,bbfd->arch_info);
+}
+
+
+/*
+INTERNAL_DEFINITION
+ bfd_default_arch_struct
+
+DESCRIPTION
+ The <<bfd_default_arch_struct>> is an item of
+ <<bfd_arch_info_type>> which has been initialized to a fairly
+ generic state. A BFD starts life by pointing to this
+ structure, until the correct back end has determined the real
+ architecture of the file.
+
+.extern bfd_arch_info_type bfd_default_arch_struct;
+
+*/
+
+bfd_arch_info_type bfd_default_arch_struct =
+{
+ 32,32,8,bfd_arch_unknown,0,"unknown","unknown",2,true,
+ bfd_default_compatible,
+ bfd_default_scan,
+ 0,
+};
+
+/*
+FUNCTION
+ bfd_set_arch_info
+
+SYNOPSIS
+ void bfd_set_arch_info(bfd *, bfd_arch_info_type *);
+
+*/
+
+void DEFUN(bfd_set_arch_info,(abfd, arg),
+bfd *abfd AND
+bfd_arch_info_type *arg)
+{
+ abfd->arch_info = arg;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_set_arch_mach
+
+SYNOPSIS
+ boolean bfd_default_set_arch_mach(bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long mach);
+
+DESCRIPTION
+ Set the architecture and machine type in a bfd. This finds the
+ correct pointer to structure and inserts it into the arch_info
+ pointer.
+*/
+
+boolean DEFUN(bfd_default_set_arch_mach,(abfd, arch, mach),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ unsigned long mach)
+{
+ static struct bfd_arch_info *old_ptr = &bfd_default_arch_struct;
+ boolean found = false;
+ /* run through the table to find the one we want, we keep a little
+ cache to speed things up */
+ if (old_ptr == 0 || arch != old_ptr->arch || mach != old_ptr->mach) {
+ bfd_arch_info_type *ptr;
+ old_ptr = (bfd_arch_info_type *)NULL;
+ for (ptr = bfd_arch_info_list;
+ ptr != (bfd_arch_info_type *)NULL;
+ ptr= ptr->next) {
+ if (ptr->arch == arch &&
+ ((ptr->mach == mach) || (ptr->the_default && mach == 0))) {
+ old_ptr = ptr;
+ found = true;
+ break;
+ }
+ }
+ if (found==false) {
+ /*looked for it and it wasn't there, so put in the default */
+ old_ptr = &bfd_default_arch_struct;
+ bfd_error = bad_value;
+ }
+ }
+ else {
+ /* it was in the cache */
+ found = true;
+ }
+
+ abfd->arch_info = old_ptr;
+
+ return found;
+}
+
+
+
+
+
+/*
+FUNCTION
+ bfd_get_arch
+
+SYNOPSIS
+ enum bfd_architecture bfd_get_arch(bfd *abfd);
+
+DESCRIPTION
+ Returns the enumerated type which describes the supplied bfd's
+ architecture
+
+*/
+
+enum bfd_architecture DEFUN(bfd_get_arch, (abfd), bfd *abfd)
+{
+ return abfd->arch_info->arch;
+}
+
+/*
+FUNCTION
+ bfd_get_mach
+
+SYNOPSIS
+ unsigned long bfd_get_mach(bfd *abfd);
+
+DESCRIPTION
+ Returns the long type which describes the supplied bfd's
+ machine
+*/
+
+unsigned long
+DEFUN(bfd_get_mach, (abfd), bfd *abfd)
+{
+ return abfd->arch_info->mach;
+}
+
+/*
+FUNCTION
+ bfd_arch_bits_per_byte
+
+SYNOPSIS
+ unsigned int bfd_arch_bits_per_byte(bfd *abfd);
+
+DESCRIPTION
+ Returns the number of bits in one of the architectures bytes
+
+*/
+
+unsigned int DEFUN(bfd_arch_bits_per_byte, (abfd), bfd *abfd)
+ {
+ return abfd->arch_info->bits_per_byte;
+ }
+
+/*
+FUNCTION
+ bfd_arch_bits_per_address
+
+SYNOPSIS
+ unsigned int bfd_arch_bits_per_address(bfd *abfd);
+
+DESCRIPTION
+ Returns the number of bits in one of the architectures addresses
+*/
+
+unsigned int DEFUN(bfd_arch_bits_per_address, (abfd), bfd *abfd)
+ {
+ return abfd->arch_info->bits_per_address;
+ }
+
+
+extern void bfd_a29k_arch PARAMS ((void));
+extern void bfd_alpha_arch PARAMS ((void));
+extern void bfd_h8300_arch PARAMS ((void));
+extern void bfd_h8500_arch PARAMS ((void));
+extern void bfd_hppa_arch PARAMS ((void));
+extern void bfd_i386_arch PARAMS ((void));
+extern void bfd_i960_arch PARAMS ((void));
+extern void bfd_m68k_arch PARAMS ((void));
+extern void bfd_m88k_arch PARAMS ((void));
+extern void bfd_mips_arch PARAMS ((void));
+extern void bfd_rs6000_arch PARAMS ((void));
+extern void bfd_sh_arch PARAMS ((void));
+extern void bfd_sparc_arch PARAMS ((void));
+extern void bfd_vax_arch PARAMS ((void));
+extern void bfd_we32k_arch PARAMS ((void));
+extern void bfd_z8k_arch PARAMS ((void));
+
+static void (*archures_init_table[]) PARAMS ((void)) =
+{
+#ifdef SELECT_ARCHITECTURES
+ SELECT_ARCHITECTURES,
+#else
+ bfd_a29k_arch,
+ bfd_alpha_arch,
+ bfd_h8300_arch,
+ bfd_h8500_arch,
+ bfd_hppa_arch,
+ bfd_i386_arch,
+ bfd_i960_arch,
+ bfd_m68k_arch,
+ bfd_m88k_arch,
+ bfd_mips_arch,
+ bfd_rs6000_arch,
+ bfd_sh_arch,
+ bfd_sparc_arch,
+ bfd_vax_arch,
+ bfd_we32k_arch,
+ bfd_z8k_arch,
+#endif
+ 0
+ };
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_arch_init
+
+SYNOPSIS
+ void bfd_arch_init(void);
+
+DESCRIPTION
+ This routine initializes the architecture dispatch table by
+ calling all installed architecture packages and getting them
+ to poke around.
+*/
+
+void
+DEFUN_VOID(bfd_arch_init)
+{
+ void (**ptable) PARAMS ((void));
+ for (ptable = archures_init_table;
+ *ptable ;
+ ptable++)
+ {
+ (*ptable)();
+ }
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_arch_linkin
+
+SYNOPSIS
+ void bfd_arch_linkin(bfd_arch_info_type *);
+
+DESCRIPTION
+ Link the provided arch info structure into the list
+*/
+
+void DEFUN(bfd_arch_linkin,(ptr),
+ bfd_arch_info_type *ptr)
+{
+ ptr->next = bfd_arch_info_list;
+ bfd_arch_info_list = ptr;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_compatible
+
+SYNOPSIS
+ CONST bfd_arch_info_type *bfd_default_compatible
+ (CONST bfd_arch_info_type *a,
+ CONST bfd_arch_info_type *b);
+
+DESCRIPTION
+ The default function for testing for compatibility.
+*/
+
+CONST bfd_arch_info_type *
+DEFUN(bfd_default_compatible,(a,b),
+ CONST bfd_arch_info_type *a AND
+ CONST bfd_arch_info_type *b)
+{
+ if(a->arch != b->arch) return NULL;
+
+ if (a->mach > b->mach) {
+ return a;
+ }
+ if (b->mach > a->mach) {
+ return b;
+ }
+ return a;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_scan
+
+SYNOPSIS
+ boolean bfd_default_scan(CONST struct bfd_arch_info *, CONST char *);
+
+DESCRIPTION
+ The default function for working out whether this is an
+ architecture hit and a machine hit.
+*/
+
+boolean
+DEFUN(bfd_default_scan,(info, string),
+CONST struct bfd_arch_info *info AND
+CONST char *string)
+{
+ CONST char *ptr_src;
+ CONST char *ptr_tst;
+ unsigned long number;
+ enum bfd_architecture arch;
+ /* First test for an exact match */
+ if (strcmp(string, info->printable_name) == 0) return true;
+
+ /* See how much of the supplied string matches with the
+ architecture, eg the string m68k:68020 would match the 68k entry
+ up to the :, then we get left with the machine number */
+
+ for (ptr_src = string,
+ ptr_tst = info->arch_name;
+ *ptr_src && *ptr_tst;
+ ptr_src++,
+ ptr_tst++)
+ {
+ if (*ptr_src != *ptr_tst) break;
+ }
+
+ /* Chewed up as much of the architecture as will match, skip any
+ colons */
+ if (*ptr_src == ':') ptr_src++;
+
+ if (*ptr_src == 0) {
+ /* nothing more, then only keep this one if it is the default
+ machine for this architecture */
+ return info->the_default;
+ }
+ number = 0;
+ while (isdigit(*ptr_src)) {
+ number = number * 10 + *ptr_src - '0';
+ ptr_src++;
+ }
+
+ switch (number)
+ {
+ case 300:
+ arch = bfd_arch_h8300;
+ break;
+
+ case 500:
+ arch = bfd_arch_h8500;
+ break;
+
+ case 68010:
+ case 68020:
+ case 68030:
+ case 68040:
+ case 68332:
+ case 68050:
+ case 68000:
+ arch = bfd_arch_m68k;
+ break;
+ case 386:
+ case 80386:
+ case 486:
+ case 80486:
+ arch = bfd_arch_i386;
+ break;
+ case 29000:
+ arch = bfd_arch_a29k;
+ break;
+
+ case 8000:
+ arch = bfd_arch_z8k;
+ break;
+
+ case 32000:
+ arch = bfd_arch_we32k;
+ break;
+
+ case 860:
+ case 80860:
+ arch = bfd_arch_i860;
+ break;
+ case 960:
+ case 80960:
+ arch = bfd_arch_i960;
+ break;
+
+ case 2000:
+ case 3000:
+ case 4000:
+ case 4400:
+ arch = bfd_arch_mips;
+ break;
+
+ case 6000:
+ arch = bfd_arch_rs6000;
+ break;
+
+ default:
+ return false;
+ }
+ if (arch != info->arch)
+ return false;
+
+ if (number != info->mach)
+ return false;
+
+ return true;
+}
+
+
+
+
+/*
+FUNCTION
+ bfd_get_arch_info
+
+
+SYNOPSIS
+ bfd_arch_info_type * bfd_get_arch_info(bfd *);
+
+*/
+
+bfd_arch_info_type *
+DEFUN(bfd_get_arch_info,(abfd),
+bfd *abfd)
+{
+ return abfd->arch_info;
+}
+
+
+/*
+FUNCTION
+ bfd_lookup_arch
+
+SYNOPSIS
+ bfd_arch_info_type *bfd_lookup_arch
+ (enum bfd_architecture
+ arch,
+ long machine);
+
+DESCRIPTION
+ Look for the architecure info struct which matches the
+ arguments given. A machine of 0 will match the
+ machine/architecture structure which marks itself as the
+ default.
+*/
+
+bfd_arch_info_type *
+DEFUN(bfd_lookup_arch,(arch, machine),
+enum bfd_architecture arch AND
+long machine)
+{
+ bfd_arch_info_type *ap;
+ bfd_check_init();
+ for (ap = bfd_arch_info_list;
+ ap != (bfd_arch_info_type *)NULL;
+ ap = ap->next) {
+ if (ap->arch == arch &&
+ ((ap->mach == machine)
+ || (ap->the_default && machine == 0))) {
+ return ap;
+ }
+ }
+ return (bfd_arch_info_type *)NULL;
+}
+
+
+
+/*
+FUNCTION
+ bfd_printable_arch_mach
+
+SYNOPSIS
+ CONST char * bfd_printable_arch_mach
+ (enum bfd_architecture arch, unsigned long machine);
+
+DESCRIPTION
+ Return a printable string representing the architecture and
+ machine type.
+
+ NB. The use of this routine is depreciated.
+*/
+
+CONST char *
+DEFUN(bfd_printable_arch_mach,(arch, machine),
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ bfd_arch_info_type *ap = bfd_lookup_arch(arch, machine);
+ if(ap) return ap->printable_name;
+ return "UNKNOWN!";
+}
diff --git a/gnu/usr.bin/gdb/bfd/bfd.c b/gnu/usr.bin/gdb/bfd/bfd.c
new file mode 100644
index 000000000000..a994cd170a00
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.c
@@ -0,0 +1,733 @@
+/* Generic BFD library interface and support routines.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ <<typedef bfd>>
+
+ A BFD is has type <<bfd>>; objects of this type are the
+ cornerstone of any application using <<libbfd>>. References
+ though the BFD and to data in the BFD give the entire BFD
+ functionality.
+
+ Here is the struct used to define the type <<bfd>>. This
+ contains the major data about the file, and contains pointers
+ to the rest of the data.
+
+CODE_FRAGMENT
+.
+.struct _bfd
+.{
+. {* The filename the application opened the BFD with. *}
+. CONST char *filename;
+.
+. {* A pointer to the target jump table. *}
+. struct bfd_target *xvec;
+.
+. {* To avoid dragging too many header files into every file that
+. includes `<<bfd.h>>', IOSTREAM has been declared as a "char
+. *", and MTIME as a "long". Their correct types, to which they
+. are cast when used, are "FILE *" and "time_t". The iostream
+. is the result of an fopen on the filename. *}
+. char *iostream;
+.
+. {* Is the file being cached *}
+.
+. boolean cacheable;
+.
+. {* Marks whether there was a default target specified when the
+. BFD was opened. This is used to select what matching algorithm
+. to use to chose the back end. *}
+.
+. boolean target_defaulted;
+.
+. {* The caching routines use these to maintain a
+. least-recently-used list of BFDs *}
+.
+. struct _bfd *lru_prev, *lru_next;
+.
+. {* When a file is closed by the caching routines, BFD retains
+. state information on the file here:
+. *}
+.
+. file_ptr where;
+.
+. {* and here:*}
+.
+. boolean opened_once;
+.
+. {* Set if we have a locally maintained mtime value, rather than
+. getting it from the file each time: *}
+.
+. boolean mtime_set;
+.
+. {* File modified time, if mtime_set is true: *}
+.
+. long mtime;
+.
+. {* Reserved for an unimplemented file locking extension.*}
+.
+. int ifd;
+.
+. {* The format which belongs to the BFD.*}
+.
+. bfd_format format;
+.
+. {* The direction the BFD was opened with*}
+.
+. enum bfd_direction {no_direction = 0,
+. read_direction = 1,
+. write_direction = 2,
+. both_direction = 3} direction;
+.
+. {* Format_specific flags*}
+.
+. flagword flags;
+.
+. {* Currently my_archive is tested before adding origin to
+. anything. I believe that this can become always an add of
+. origin, with origin set to 0 for non archive files. *}
+.
+. file_ptr origin;
+.
+. {* Remember when output has begun, to stop strange things
+. happening. *}
+. boolean output_has_begun;
+.
+. {* Pointer to linked list of sections*}
+. struct sec *sections;
+.
+. {* The number of sections *}
+. unsigned int section_count;
+.
+. {* Stuff only useful for object files:
+. The start address. *}
+. bfd_vma start_address;
+.
+. {* Used for input and output*}
+. unsigned int symcount;
+.
+. {* Symbol table for output BFD*}
+. struct symbol_cache_entry **outsymbols;
+.
+. {* Pointer to structure which contains architecture information*}
+. struct bfd_arch_info *arch_info;
+.
+. {* Stuff only useful for archives:*}
+. PTR arelt_data;
+. struct _bfd *my_archive;
+. struct _bfd *next;
+. struct _bfd *archive_head;
+. boolean has_armap;
+.
+. {* Used by the back end to hold private data. *}
+.
+. union
+. {
+. struct aout_data_struct *aout_data;
+. struct artdata *aout_ar_data;
+. struct _oasys_data *oasys_obj_data;
+. struct _oasys_ar_data *oasys_ar_data;
+. struct coff_tdata *coff_obj_data;
+. struct ecoff_tdata *ecoff_obj_data;
+. struct ieee_data_struct *ieee_data;
+. struct ieee_ar_data_struct *ieee_ar_data;
+. struct srec_data_struct *srec_data;
+. struct tekhex_data_struct *tekhex_data;
+. struct elf_obj_tdata *elf_obj_data;
+. struct nlm_obj_tdata *nlm_obj_data;
+. struct bout_data_struct *bout_data;
+. struct sun_core_struct *sun_core_data;
+. struct trad_core_struct *trad_core_data;
+. struct hppa_data_struct *hppa_data;
+. struct hpux_core_struct *hpux_core_data;
+. struct sgi_core_struct *sgi_core_data;
+. struct lynx_core_struct *lynx_core_data;
+. struct osf_core_struct *osf_core_data;
+. PTR any;
+. } tdata;
+.
+. {* Used by the application to hold private data*}
+. PTR usrdata;
+.
+. {* Where all the allocated stuff under this BFD goes *}
+. struct obstack memory;
+.
+. {* Is this really needed in addition to usrdata? *}
+. asymbol **ld_symbols;
+.};
+.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "libcoff.h"
+#include "libecoff.h"
+#undef obj_symbols
+#include "libelf.h"
+
+#undef strerror
+extern char *strerror();
+
+/** Error handling
+ o - Most functions return nonzero on success (check doc for
+ precise semantics); 0 or NULL on error.
+ o - Internal errors are documented by the value of bfd_error.
+ If that is system_call_error then check errno.
+ o - The easiest way to report this to the user is to use bfd_perror.
+*/
+
+bfd_ec bfd_error = no_error;
+
+CONST char *CONST bfd_errmsgs[] = {
+ "No error",
+ "System call error",
+ "Invalid target",
+ "File in wrong format",
+ "Invalid operation",
+ "Memory exhausted",
+ "No symbols",
+ "No relocation info",
+ "No more archived files",
+ "Malformed archive",
+ "Symbol not found",
+ "File format not recognized",
+ "File format is ambiguous",
+ "Section has no contents",
+ "Nonrepresentable section on output",
+ "Symbol needs debug section which does not exist",
+ "Bad value",
+ "File truncated",
+ "#<Invalid error code>"
+ };
+
+static
+void
+DEFUN(bfd_nonrepresentable_section,(abfd, name),
+ CONST bfd * CONST abfd AND
+ CONST char * CONST name)
+{
+ fprintf(stderr,
+ "bfd error writing file %s, format %s can't represent section %s\n",
+ abfd->filename,
+ abfd->xvec->name,
+ name);
+ exit(1);
+}
+
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_undefined_symbol,(relent, seclet),
+ CONST arelent *relent AND
+ CONST struct bfd_seclet *seclet)
+{
+ asymbol *symbol = *(relent->sym_ptr_ptr);
+ fprintf(stderr, "bfd error relocating, symbol %s is undefined\n",
+ symbol->name);
+ exit(1);
+}
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_reloc_value_truncated,(relent, seclet),
+ CONST arelent *relent AND
+ struct bfd_seclet *seclet)
+{
+ fprintf(stderr, "bfd error relocating, value truncated\n");
+ exit(1);
+}
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_reloc_is_dangerous,(relent, seclet),
+ CONST arelent *relent AND
+ CONST struct bfd_seclet *seclet)
+{
+ fprintf(stderr, "bfd error relocating, dangerous\n");
+ exit(1);
+}
+
+bfd_error_vector_type bfd_error_vector =
+ {
+ bfd_nonrepresentable_section ,
+ bfd_undefined_symbol,
+ bfd_reloc_value_truncated,
+ bfd_reloc_is_dangerous,
+ };
+
+
+CONST char *
+bfd_errmsg (error_tag)
+ bfd_ec error_tag;
+{
+#ifndef errno
+ extern int errno;
+#endif
+ if (error_tag == system_call_error)
+ return strerror (errno);
+
+ if ((((int)error_tag <(int) no_error) ||
+ ((int)error_tag > (int)invalid_error_code)))
+ error_tag = invalid_error_code;/* sanity check */
+
+ return bfd_errmsgs [(int)error_tag];
+}
+
+void
+DEFUN (bfd_default_error_trap, (error_tag),
+ bfd_ec error_tag)
+{
+ fprintf(stderr, "bfd assert fail (%s)\n", bfd_errmsg(error_tag));
+}
+
+void (*bfd_error_trap) PARAMS ((bfd_ec)) = bfd_default_error_trap;
+void (*bfd_error_nonrepresentabltrap) PARAMS ((bfd_ec)) = bfd_default_error_trap;
+
+void
+DEFUN(bfd_perror,(message),
+ CONST char *message)
+{
+ if (bfd_error == system_call_error)
+ perror((char *)message); /* must be system error then... */
+ else {
+ if (message == NULL || *message == '\0')
+ fprintf (stderr, "%s\n", bfd_errmsg (bfd_error));
+ else
+ fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error));
+ }
+}
+
+
+/** Symbols */
+
+
+/*
+FUNCTION
+ bfd_get_reloc_upper_bound
+
+SYNOPSIS
+ unsigned int bfd_get_reloc_upper_bound(bfd *abfd, asection *sect);
+
+DESCRIPTION
+ This function return the number of bytes required to store the
+ relocation information associated with section <<sect>>
+ attached to bfd <<abfd>>
+
+*/
+
+
+unsigned int
+DEFUN(bfd_get_reloc_upper_bound,(abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (abfd->format != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+
+ return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect));
+}
+
+/*
+FUNCTION
+ bfd_canonicalize_reloc
+
+SYNOPSIS
+ unsigned int bfd_canonicalize_reloc
+ (bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms);
+
+DESCRIPTION
+ This function calls the back end associated with the open
+ <<abfd>> and translates the external form of the relocation
+ information attached to <<sec>> into the internal canonical
+ form. The table is placed into memory at <<loc>>, which has
+ been preallocated, usually by a call to
+ <<bfd_get_reloc_upper_bound>>.
+
+ The <<syms>> table is also needed for horrible internal magic
+ reasons.
+
+
+*/
+unsigned int
+DEFUN(bfd_canonicalize_reloc,(abfd, asect, location, symbols),
+ bfd *abfd AND
+ sec_ptr asect AND
+ arelent **location AND
+ asymbol **symbols)
+{
+ if (abfd->format != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ return BFD_SEND (abfd, _bfd_canonicalize_reloc,
+ (abfd, asect, location, symbols));
+ }
+
+
+/*
+FUNCTION
+ bfd_set_file_flags
+
+SYNOPSIS
+ boolean bfd_set_file_flags(bfd *abfd, flagword flags);
+
+DESCRIPTION
+ This function attempts to set the flag word in the referenced
+ BFD structure to the value supplied.
+
+ Possible errors are:
+ o wrong_format - The target bfd was not of object format.
+ o invalid_operation - The target bfd was open for reading.
+ o invalid_operation -
+ The flag word contained a bit which was not applicable to the
+ type of file. eg, an attempt was made to set the D_PAGED bit
+ on a bfd format which does not support demand paging
+
+*/
+
+boolean
+bfd_set_file_flags (abfd, flags)
+ bfd *abfd;
+ flagword flags;
+{
+ if (abfd->format != bfd_object) {
+ bfd_error = wrong_format;
+ return false;
+ }
+
+ if (bfd_read_p (abfd)) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ bfd_get_file_flags (abfd) = flags;
+ if ((flags & bfd_applicable_file_flags (abfd)) != flags) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+return true;
+}
+
+/*
+FUNCTION
+ bfd_set_reloc
+
+SYNOPSIS
+ void bfd_set_reloc
+ (bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+DESCRIPTION
+ This function sets the relocation pointer and count within a
+ section to the supplied values.
+
+*/
+/*ARGSUSED*/
+void
+bfd_set_reloc (ignore_abfd, asect, location, count)
+ bfd *ignore_abfd;
+ sec_ptr asect;
+ arelent **location;
+ unsigned int count;
+{
+ asect->orelocation = location;
+ asect->reloc_count = count;
+}
+
+void
+bfd_assert(file, line)
+char *file;
+int line;
+{
+ fprintf(stderr, "bfd assertion fail %s:%d\n",file,line);
+}
+
+
+/*
+FUNCTION
+ bfd_set_start_address
+
+DESCRIPTION
+ Marks the entry point of an output BFD.
+
+RETURNS
+ Returns <<true>> on success, <<false>> otherwise.
+
+SYNOPSIS
+ boolean bfd_set_start_address(bfd *, bfd_vma);
+*/
+
+boolean
+bfd_set_start_address(abfd, vma)
+bfd *abfd;
+bfd_vma vma;
+{
+ abfd->start_address = vma;
+ return true;
+}
+
+
+/*
+FUNCTION
+ The bfd_get_mtime function
+
+SYNOPSIS
+ long bfd_get_mtime(bfd *);
+
+DESCRIPTION
+ Return file modification time (as read from file system, or
+ from archive header for archive members).
+
+*/
+
+long
+bfd_get_mtime (abfd)
+ bfd *abfd;
+{
+ FILE *fp;
+ struct stat buf;
+
+ if (abfd->mtime_set)
+ return abfd->mtime;
+
+ fp = bfd_cache_lookup (abfd);
+ if (0 != fstat (fileno (fp), &buf))
+ return 0;
+
+ abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
+ return buf.st_mtime;
+}
+
+/*
+FUNCTION
+ The bfd_get_size function
+
+SYNOPSIS
+ long bfd_get_size(bfd *);
+
+DESCRIPTION
+ Return file size (as read from file system) for the file
+ associated with a bfd.
+
+ Note that the initial motivation for, and use of, this routine is not
+ so we can get the exact size of the object the bfd applies to, since
+ that might not be generally possible (archive members for example?).
+ Although it would be ideal if someone could eventually modify
+ it so that such results were guaranteed.
+
+ Instead, we want to ask questions like "is this NNN byte sized
+ object I'm about to try read from file offset YYY reasonable?"
+ As as example of where we might want to do this, some object formats
+ use string tables for which the first sizeof(long) bytes of the table
+ contain the size of the table itself, including the size bytes.
+ If an application tries to read what it thinks is one of these
+ string tables, without some way to validate the size, and for
+ some reason the size is wrong (byte swapping error, wrong location
+ for the string table, etc), the only clue is likely to be a read
+ error when it tries to read the table, or a "virtual memory
+ exhausted" error when it tries to allocated 15 bazillon bytes
+ of space for the 15 bazillon byte table it is about to read.
+ This function at least allows us to answer the quesion, "is the
+ size reasonable?".
+*/
+
+long
+bfd_get_size (abfd)
+ bfd *abfd;
+{
+ FILE *fp;
+ struct stat buf;
+
+ fp = bfd_cache_lookup (abfd);
+ if (0 != fstat (fileno (fp), &buf))
+ return 0;
+
+ return buf.st_size;
+}
+
+/*
+FUNCTION
+ The bfd_get_gp_size function
+
+SYNOPSIS
+ int bfd_get_gp_size(bfd *);
+
+DESCRIPTION
+ Get the maximum size of objects to be optimized using the GP
+ register under MIPS ECOFF. This is typically set by the -G
+ argument to the compiler, assembler or linker.
+*/
+
+int
+bfd_get_gp_size (abfd)
+ bfd *abfd;
+{
+ if (abfd->xvec->flavour == bfd_target_ecoff_flavour)
+ return ecoff_data (abfd)->gp_size;
+ return 0;
+}
+
+/*
+FUNCTION
+ The bfd_set_gp_size function
+
+SYNOPSIS
+ void bfd_set_gp_size(bfd *, int);
+
+DESCRIPTION
+ Set the maximum size of objects to be optimized using the GP
+ register under ECOFF or MIPS ELF. This is typically set by
+ the -G argument to the compiler, assembler or linker.
+*/
+
+void
+bfd_set_gp_size (abfd, i)
+ bfd *abfd;
+ int i;
+{
+ if (abfd->xvec->flavour == bfd_target_ecoff_flavour)
+ ecoff_data (abfd)->gp_size = i;
+ else if (abfd->xvec->flavour == bfd_target_elf_flavour)
+ elf_gp_size (abfd) = i;
+}
+
+/*
+FUNCTION
+ bfd_scan_vma
+
+DESCRIPTION
+ Converts, like strtoul, a numerical expression as a
+ string into a bfd_vma integer, and returns that integer.
+ (Though without as many bells and whistles as strtoul.)
+ The expression is assumed to be unsigned (i.e. positive).
+ If given a base, it is used as the base for conversion.
+ A base of 0 causes the function to interpret the string
+ in hex if a leading "0x" or "0X" is found, otherwise
+ in octal if a leading zero is found, otherwise in decimal.
+
+ Overflow is not detected.
+
+SYNOPSIS
+ bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base);
+*/
+
+bfd_vma
+DEFUN(bfd_scan_vma,(string, end, base),
+ CONST char *string AND
+ CONST char **end AND
+ int base)
+{
+ bfd_vma value;
+ int digit;
+
+ /* Let the host do it if possible. */
+ if (sizeof(bfd_vma) <= sizeof(unsigned long))
+ return (bfd_vma) strtoul (string, 0, base);
+
+ /* A negative base makes no sense, and we only need to go as high as hex. */
+ if ((base < 0) || (base > 16))
+ return (bfd_vma) 0;
+
+ if (base == 0)
+ {
+ if (string[0] == '0')
+ {
+ if ((string[1] == 'x') || (string[1] == 'X'))
+ base = 16;
+ /* XXX should we also allow "0b" or "0B" to set base to 2? */
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+ if ((base == 16) &&
+ (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X')))
+ string += 2;
+ /* XXX should we also skip over "0b" or "0B" if base is 2? */
+
+/* Speed could be improved with a table like hex_value[] in gas. */
+#define HEX_VALUE(c) \
+ (isxdigit(c) ? \
+ (isdigit(c) ? \
+ (c - '0') : \
+ (10 + c - (islower(c) ? 'a' : 'A'))) : \
+ 42)
+
+ for (value = 0; (digit = HEX_VALUE(*string)) < base; string++)
+ {
+ value = value * base + digit;
+ }
+
+ if (end)
+ *end = string;
+
+ return value;
+}
+
+/*
+FUNCTION
+ stuff
+
+DESCRIPTION
+ stuff which should be documented
+
+.#define bfd_sizeof_headers(abfd, reloc) \
+. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc))
+.
+.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line))
+.
+. {* Do these three do anything useful at all, for any back end? *}
+.#define bfd_debug_info_start(abfd) \
+. BFD_SEND (abfd, _bfd_debug_info_start, (abfd))
+.
+.#define bfd_debug_info_end(abfd) \
+. BFD_SEND (abfd, _bfd_debug_info_end, (abfd))
+.
+.#define bfd_debug_info_accumulate(abfd, section) \
+. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section))
+.
+.
+.#define bfd_stat_arch_elt(abfd, stat) \
+. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat))
+.
+.#define bfd_set_arch_mach(abfd, arch, mach)\
+. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach))
+.
+.#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \
+. BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable))
+.
+.#define bfd_relax_section(abfd, section, symbols) \
+. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols))
+.
+.#define bfd_seclet_link(abfd, data, relocateable) \
+. BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable))
+
+*/
diff --git a/gnu/usr.bin/gdb/bfd/bfd.h b/gnu/usr.bin/gdb/bfd/bfd.h
new file mode 100644
index 000000000000..fbe0f0f36ba4
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.h
@@ -0,0 +1,1803 @@
+/* Main header file for the bfd library -- portable access to object files.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them;
+** instead, change bfd-in.h or the other BFD source files processed to
+** generate these files.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* bfd.h -- The only header file required by users of the bfd library
+
+The bfd.h file is generated from bfd-in.h and various .c files; if you
+change it, your changes will probably be lost.
+
+All the prototypes and definitions following the comment "THE FOLLOWING
+IS EXTRACTED FROM THE SOURCE" are extracted from the source files for
+BFD. If you change it, someone oneday will extract it from the source
+again, and your changes will be lost. To save yourself from this bind,
+change the definitions in the source in the bfd directory. Type "make
+docs" and then "make headers" in that directory, and magically this file
+will change to reflect your changes.
+
+If you don't have the tools to perform the extraction, then you are
+safe from someone on your system trampling over your header files.
+You should still maintain the equivalence between the source and this
+file though; every change you make to the .c file should be reflected
+here. */
+
+#ifndef __BFD_H_SEEN__
+#define __BFD_H_SEEN__
+
+#include "ansidecl.h"
+#include "obstack.h"
+
+#define BFD_VERSION "2.2"
+
+#define BFD_ARCH_SIZE 32
+
+#if BFD_ARCH_SIZE >= 64
+#define BFD64
+#endif
+
+#ifndef INLINE
+#if __GNUC__ >= 2
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+#endif
+
+/* 64-bit type definition (if any) from bfd's sysdep.h goes here */
+
+
+/* forward declaration */
+typedef struct _bfd bfd;
+
+/* To squelch erroneous compiler warnings ("illegal pointer
+ combination") from the SVR3 compiler, we would like to typedef
+ boolean to int (it doesn't like functions which return boolean.
+ Making sure they are never implicitly declared to return int
+ doesn't seem to help). But this file is not configured based on
+ the host. */
+/* General rules: functions which are boolean return true on success
+ and false on failure (unless they're a predicate). -- bfd.doc */
+/* I'm sure this is going to break something and someone is going to
+ force me to change it. */
+/* typedef enum boolean {false, true} boolean; */
+/* Yup, SVR4 has a "typedef enum boolean" in <sys/types.h> -fnf */
+typedef enum bfd_boolean {false, true} boolean;
+
+/* A pointer to a position in a file. */
+/* FIXME: This should be using off_t from <sys/types.h>.
+ For now, try to avoid breaking stuff by not including <sys/types.h> here.
+ This will break on systems with 64-bit file offsets (e.g. 4.4BSD).
+ Probably the best long-term answer is to avoid using file_ptr AND off_t
+ in this header file, and to handle this in the BFD implementation
+ rather than in its interface. */
+/* typedef off_t file_ptr; */
+typedef long int file_ptr;
+
+/* Support for different sizes of target format ints and addresses. If the
+ host implements 64-bit values, it defines HOST_64_BIT to be the appropriate
+ type. Otherwise, this code will fall back on gcc's "long long" type if gcc
+ is being used. HOST_64_BIT must be defined in such a way as to be a valid
+ type name by itself or with "unsigned" prefixed. It should be a signed
+ type by itself.
+
+ If neither is the case, then compilation will fail if 64-bit targets are
+ requested. If you don't request any 64-bit targets, you should be safe. */
+
+#ifdef BFD64
+
+#if defined (__GNUC__) && !defined (HOST_64_BIT)
+#define HOST_64_BIT long long
+typedef HOST_64_BIT int64_type;
+typedef unsigned HOST_64_BIT uint64_type;
+#endif
+
+#if !defined (uint64_type) && defined (__GNUC__)
+#define uint64_type unsigned long long
+#define int64_type long long
+#define uint64_typeLOW(x) (unsigned long)(((x) & 0xffffffff))
+#define uint64_typeHIGH(x) (unsigned long)(((x) >> 32) & 0xffffffff)
+#endif
+
+typedef unsigned HOST_64_BIT bfd_vma;
+typedef HOST_64_BIT bfd_signed_vma;
+typedef unsigned HOST_64_BIT bfd_size_type;
+typedef unsigned HOST_64_BIT symvalue;
+#define fprintf_vma(s,x) \
+ fprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x))
+#define sprintf_vma(s,x) \
+ sprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x))
+#else /* not BFD64 */
+
+/* Represent a target address. Also used as a generic unsigned type
+ which is guaranteed to be big enough to hold any arithmetic types
+ we need to deal with. */
+typedef unsigned long bfd_vma;
+
+/* A generic signed type which is guaranteed to be big enough to hold any
+ arithmetic types we need to deal with. Can be assumed to be compatible
+ with bfd_vma in the same way that signed and unsigned ints are compatible
+ (as parameters, in assignment, etc). */
+typedef long bfd_signed_vma;
+
+typedef unsigned long symvalue;
+typedef unsigned long bfd_size_type;
+
+/* Print a bfd_vma x on stream s. */
+#define fprintf_vma(s,x) fprintf(s, "%08lx", x)
+#define sprintf_vma(s,x) sprintf(s, "%08lx", x)
+#endif /* not BFD64 */
+#define printf_vma(x) fprintf_vma(stdout,x)
+
+typedef unsigned int flagword; /* 32 bits of flags */
+
+/** File formats */
+
+typedef enum bfd_format {
+ bfd_unknown = 0, /* file format is unknown */
+ bfd_object, /* linker/assember/compiler output */
+ bfd_archive, /* object archive file */
+ bfd_core, /* core dump */
+ bfd_type_end} /* marks the end; don't use it! */
+ bfd_format;
+
+/* Object file flag values */
+#define NO_FLAGS 0x00
+#define HAS_RELOC 0x01
+#define EXEC_P 0x02
+#define HAS_LINENO 0x04
+#define HAS_DEBUG 0x08
+#define HAS_SYMS 0x10
+#define HAS_LOCALS 0x20
+#define DYNAMIC 0x40
+#define WP_TEXT 0x80
+#define D_PAGED 0x100
+#define BFD_IS_RELAXABLE 0x200
+
+/* symbols and relocation */
+
+typedef unsigned long symindex;
+
+#define BFD_NO_MORE_SYMBOLS ((symindex) ~0)
+
+typedef enum bfd_symclass {
+ bfd_symclass_unknown = 0,
+ bfd_symclass_fcommon, /* fortran common symbols */
+ bfd_symclass_global, /* global symbol, what a surprise */
+ bfd_symclass_debugger, /* some debugger symbol */
+ bfd_symclass_undefined /* none known */
+ } symclass;
+
+
+/* general purpose part of a symbol;
+ target specific parts will be found in libcoff.h, liba.out.h etc */
+
+
+#define bfd_get_section(x) ((x)->section)
+#define bfd_get_output_section(x) ((x)->section->output_section)
+#define bfd_set_section(x,y) ((x)->section) = (y)
+#define bfd_asymbol_base(x) ((x)->section->vma)
+#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value)
+#define bfd_asymbol_name(x) ((x)->name)
+/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/
+#define bfd_asymbol_bfd(x) ((x)->the_bfd)
+#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour)
+
+/* This is a type pun with struct ranlib on purpose! */
+typedef struct carsym {
+ char *name;
+ file_ptr file_offset; /* look here to find the file */
+} carsym; /* to make these you call a carsymogen */
+
+
+/* Used in generating armaps. Perhaps just a forward definition would do? */
+struct orl { /* output ranlib */
+ char **name; /* symbol name */
+ file_ptr pos; /* bfd* or file position */
+ int namidx; /* index into string table */
+};
+
+
+
+/* Linenumber stuff */
+typedef struct lineno_cache_entry {
+ unsigned int line_number; /* Linenumber from start of function*/
+ union {
+ struct symbol_cache_entry *sym; /* Function name */
+ unsigned long offset; /* Offset into section */
+ } u;
+} alent;
+
+/* object and core file sections */
+
+
+#define align_power(addr, align) \
+ ( ((addr) + ((1<<(align))-1)) & (-1 << (align)))
+
+typedef struct sec *sec_ptr;
+
+#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0)
+#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0)
+#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0)
+#define bfd_section_name(bfd, ptr) ((ptr)->name)
+#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr))
+#define bfd_section_vma(bfd, ptr) ((ptr)->vma)
+#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power)
+#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0)
+#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata)
+
+#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0)
+
+#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = true), true)
+#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true)
+#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true)
+
+typedef struct stat stat_type;
+
+/** Error handling */
+
+typedef enum bfd_error {
+ no_error = 0, system_call_error, invalid_target,
+ wrong_format, invalid_operation, no_memory,
+ no_symbols, no_relocation_info,
+ no_more_archived_files, malformed_archive,
+ symbol_not_found, file_not_recognized,
+ file_ambiguously_recognized, no_contents,
+ bfd_error_nonrepresentable_section,
+ no_debug_section, bad_value,
+
+ /* An input file is shorter than expected. */
+ file_truncated,
+
+ invalid_error_code} bfd_ec;
+
+extern bfd_ec bfd_error;
+struct reloc_cache_entry;
+struct bfd_seclet;
+
+
+typedef struct bfd_error_vector {
+ void (* nonrepresentable_section ) PARAMS ((CONST bfd *CONST abfd,
+ CONST char *CONST name));
+ void (* undefined_symbol) PARAMS ((CONST struct reloc_cache_entry *rel,
+ CONST struct bfd_seclet *sec));
+ void (* reloc_value_truncated) PARAMS ((CONST struct
+ reloc_cache_entry *rel,
+ struct bfd_seclet *sec));
+
+ void (* reloc_dangerous) PARAMS ((CONST struct reloc_cache_entry *rel,
+ CONST struct bfd_seclet *sec));
+
+} bfd_error_vector_type;
+
+CONST char *bfd_errmsg PARAMS ((bfd_ec error_tag));
+void bfd_perror PARAMS ((CONST char *message));
+
+
+typedef enum bfd_print_symbol
+{
+ bfd_print_symbol_name,
+ bfd_print_symbol_more,
+ bfd_print_symbol_all
+} bfd_print_symbol_type;
+
+
+/* Information about a symbol that nm needs. */
+
+typedef struct _symbol_info
+{
+ symvalue value;
+ char type; /* */
+ CONST char *name; /* Symbol name. */
+ char stab_other; /* Unused. */
+ short stab_desc; /* Info for N_TYPE. */
+ CONST char *stab_name;
+} symbol_info;
+
+/* The code that implements targets can initialize a jump table with this
+ macro. It must name all its routines the same way (a prefix plus
+ the standard routine suffix), or it must #define the routines that
+ are not so named, before calling JUMP_TABLE in the initializer. */
+
+/* Semi-portable string concatenation in cpp.
+ The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors.
+ The problem is, "32_" is not a valid preprocessing token, and we don't
+ want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the
+ inner CAT macros to be evaluated first, producing still-valid pp-tokens.
+ Then the final concatenation can be done. (Sigh.) */
+#ifndef CAT
+#ifdef SABER
+#define CAT(a,b) a##b
+#define CAT3(a,b,c) a##b##c
+#define CAT4(a,b,c,d) a##b##c##d
+#else
+#ifdef __STDC__
+#define CAT(a,b) a##b
+#define CAT3(a,b,c) a##b##c
+#define XCAT2(a,b) CAT(a,b)
+#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d))
+#else
+#define CAT(a,b) a/**/b
+#define CAT3(a,b,c) a/**/b/**/c
+#define CAT4(a,b,c,d) a/**/b/**/c/**/d
+#endif
+#endif
+#endif
+
+#define JUMP_TABLE(NAME)\
+CAT(NAME,_core_file_failing_command),\
+CAT(NAME,_core_file_failing_signal),\
+CAT(NAME,_core_file_matches_executable_p),\
+CAT(NAME,_slurp_armap),\
+CAT(NAME,_slurp_extended_name_table),\
+CAT(NAME,_truncate_arname),\
+CAT(NAME,_write_armap),\
+CAT(NAME,_close_and_cleanup),\
+CAT(NAME,_set_section_contents),\
+CAT(NAME,_get_section_contents),\
+CAT(NAME,_new_section_hook),\
+CAT(NAME,_get_symtab_upper_bound),\
+CAT(NAME,_get_symtab),\
+CAT(NAME,_get_reloc_upper_bound),\
+CAT(NAME,_canonicalize_reloc),\
+CAT(NAME,_make_empty_symbol),\
+CAT(NAME,_print_symbol),\
+CAT(NAME,_get_symbol_info),\
+CAT(NAME,_get_lineno),\
+CAT(NAME,_set_arch_mach),\
+CAT(NAME,_openr_next_archived_file),\
+CAT(NAME,_find_nearest_line),\
+CAT(NAME,_generic_stat_arch_elt),\
+CAT(NAME,_sizeof_headers),\
+CAT(NAME,_bfd_debug_info_start),\
+CAT(NAME,_bfd_debug_info_end),\
+CAT(NAME,_bfd_debug_info_accumulate),\
+CAT(NAME,_bfd_get_relocated_section_contents),\
+CAT(NAME,_bfd_relax_section),\
+CAT(NAME,_bfd_seclet_link),\
+CAT(NAME,_bfd_reloc_type_lookup),\
+CAT(NAME,_bfd_make_debug_symbol)
+
+#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table
+
+
+/* User program access to BFD facilities */
+
+/* Cast from const char * to char * so that caller can assign to
+ a char * without a warning. */
+#define bfd_get_filename(abfd) ((char *) (abfd)->filename)
+#define bfd_get_format(abfd) ((abfd)->format)
+#define bfd_get_target(abfd) ((abfd)->xvec->name)
+#define bfd_get_file_flags(abfd) ((abfd)->flags)
+#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags)
+#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags)
+#define bfd_my_archive(abfd) ((abfd)->my_archive)
+#define bfd_has_map(abfd) ((abfd)->has_armap)
+
+#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
+#define bfd_usrdata(abfd) ((abfd)->usrdata)
+
+#define bfd_get_start_address(abfd) ((abfd)->start_address)
+#define bfd_get_symcount(abfd) ((abfd)->symcount)
+#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols)
+#define bfd_count_sections(abfd) ((abfd)->section_count)
+
+#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char)
+
+/* Byte swapping routines. */
+
+bfd_vma bfd_getb64 PARAMS ((unsigned char *));
+bfd_vma bfd_getl64 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_64 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_64 PARAMS ((unsigned char *));
+bfd_vma bfd_getb32 PARAMS ((unsigned char *));
+bfd_vma bfd_getl32 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_32 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_32 PARAMS ((unsigned char *));
+bfd_vma bfd_getb16 PARAMS ((unsigned char *));
+bfd_vma bfd_getl16 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_16 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_16 PARAMS ((unsigned char *));
+void bfd_putb64 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl64 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putb32 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl32 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putb16 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl16 PARAMS ((bfd_vma, unsigned char *));
+
+/* And more from the source. */
+void
+bfd_init PARAMS ((void));
+
+bfd *
+bfd_openr PARAMS ((CONST char *filename, CONST char*target));
+
+bfd *
+bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd));
+
+bfd *
+bfd_openw PARAMS ((CONST char *filename, CONST char *target));
+
+boolean
+bfd_close PARAMS ((bfd *));
+
+boolean
+bfd_close_all_done PARAMS ((bfd *));
+
+bfd_size_type
+bfd_alloc_size PARAMS ((bfd *abfd));
+
+bfd *
+bfd_create PARAMS ((CONST char *filename, bfd *templ));
+
+
+ /* Byte swapping macros for user section data. */
+
+#define bfd_put_8(abfd, val, ptr) \
+ (*((unsigned char *)(ptr)) = (unsigned char)val)
+#define bfd_put_signed_8 \
+ bfd_put_8
+#define bfd_get_8(abfd, ptr) \
+ (*(unsigned char *)(ptr))
+#define bfd_get_signed_8(abfd, ptr) \
+ ((*(unsigned char *)(ptr) ^ 0x80) - 0x80)
+
+#define bfd_put_16(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx16, ((val),(ptr)))
+#define bfd_put_signed_16 \
+ bfd_put_16
+#define bfd_get_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx16, (ptr))
+#define bfd_get_signed_16(abfd, ptr) \
+ BFD_SEND (abfd, bfd_getx_signed_16, (ptr))
+
+#define bfd_put_32(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx32, ((val),(ptr)))
+#define bfd_put_signed_32 \
+ bfd_put_32
+#define bfd_get_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx32, (ptr))
+#define bfd_get_signed_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx_signed_32, (ptr))
+
+#define bfd_put_64(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx64, ((val), (ptr)))
+#define bfd_put_signed_64 \
+ bfd_put_64
+#define bfd_get_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx64, (ptr))
+#define bfd_get_signed_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
+
+
+ /* Byte swapping macros for file header data. */
+
+#define bfd_h_put_8(abfd, val, ptr) \
+ bfd_put_8 (abfd, val, ptr)
+#define bfd_h_put_signed_8(abfd, val, ptr) \
+ bfd_put_8 (abfd, val, ptr)
+#define bfd_h_get_8(abfd, ptr) \
+ bfd_get_8 (abfd, ptr)
+#define bfd_h_get_signed_8(abfd, ptr) \
+ bfd_get_signed_8 (abfd, ptr)
+
+#define bfd_h_put_16(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx16,(val,ptr))
+#define bfd_h_put_signed_16 \
+ bfd_h_put_16
+#define bfd_h_get_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx16,(ptr))
+#define bfd_h_get_signed_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr))
+
+#define bfd_h_put_32(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx32,(val,ptr))
+#define bfd_h_put_signed_32 \
+ bfd_h_put_32
+#define bfd_h_get_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx32,(ptr))
+#define bfd_h_get_signed_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr))
+
+#define bfd_h_put_64(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx64,(val, ptr))
+#define bfd_h_put_signed_64 \
+ bfd_h_put_64
+#define bfd_h_get_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx64,(ptr))
+#define bfd_h_get_signed_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr))
+
+typedef struct sec
+{
+ /* The name of the section, the name isn't a copy, the pointer is
+ the same as that passed to bfd_make_section. */
+
+ CONST char *name;
+
+ /* Which section is it 0.nth */
+
+ int index;
+
+ /* The next section in the list belonging to the BFD, or NULL. */
+
+ struct sec *next;
+
+ /* The field flags contains attributes of the section. Some of
+ flags are read in from the object file, and some are
+ synthesized from other information. */
+
+ flagword flags;
+
+#define SEC_NO_FLAGS 0x000
+
+ /* Tells the OS to allocate space for this section when loaded.
+ This would clear for a section containing debug information
+ only. */
+#define SEC_ALLOC 0x001
+
+ /* Tells the OS to load the section from the file when loading.
+ This would be clear for a .bss section */
+#define SEC_LOAD 0x002
+
+ /* The section contains data still to be relocated, so there will
+ be some relocation information too. */
+#define SEC_RELOC 0x004
+
+#if 0 /* Obsolete ? */
+#define SEC_BALIGN 0x008
+#endif
+
+ /* A signal to the OS that the section contains read only
+ data. */
+#define SEC_READONLY 0x010
+
+ /* The section contains code only. */
+#define SEC_CODE 0x020
+
+ /* The section contains data only. */
+#define SEC_DATA 0x040
+
+ /* The section will reside in ROM. */
+#define SEC_ROM 0x080
+
+ /* The section contains constructor information. This section
+ type is used by the linker to create lists of constructors and
+ destructors used by <<g++>>. When a back end sees a symbol
+ which should be used in a constructor list, it creates a new
+ section for the type of name (eg <<__CTOR_LIST__>>), attaches
+ the symbol to it and builds a relocation. To build the lists
+ of constructors, all the linker has to do is catenate all the
+ sections called <<__CTOR_LIST__>> and relocte the data
+ contained within - exactly the operations it would peform on
+ standard data. */
+#define SEC_CONSTRUCTOR 0x100
+
+ /* The section is a constuctor, and should be placed at the
+ end of the text, data, or bss section(?). */
+#define SEC_CONSTRUCTOR_TEXT 0x1100
+#define SEC_CONSTRUCTOR_DATA 0x2100
+#define SEC_CONSTRUCTOR_BSS 0x3100
+
+ /* The section has contents - a data section could be
+ <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>, a debug section could be
+ <<SEC_HAS_CONTENTS>> */
+#define SEC_HAS_CONTENTS 0x200
+
+ /* An instruction to the linker not to output sections
+ containing this flag even if they have information which
+ would normally be written. */
+#define SEC_NEVER_LOAD 0x400
+
+ /* The section is a shared library section. The linker must leave
+ these completely alone, as the vma and size are used when
+ the executable is loaded. */
+#define SEC_SHARED_LIBRARY 0x800
+
+ /* The section is a common section (symbols may be defined
+ multiple times, the value of a symbol is the amount of
+ space it requires, and the largest symbol value is the one
+ used). Most targets have exactly one of these (which we
+ translate to bfd_com_section), but ECOFF has two. */
+#define SEC_IS_COMMON 0x8000
+
+ /* The section contains only debugging information. For
+ example, this is set for ELF .debug and .stab sections.
+ strip tests this flag to see if a section can be
+ discarded. */
+#define SEC_DEBUGGING 0x10000
+
+ /* End of section flags. */
+
+ /* The virtual memory address of the section - where it will be
+ at run time. The symbols are relocated against this. The
+ user_set_vma flag is maintained by bfd; if it's not set, the
+ backend can assign addresses (for example, in <<a.out>>, where
+ the default address for <<.data>> is dependent on the specific
+ target and various flags). */
+
+ bfd_vma vma;
+ boolean user_set_vma;
+
+ /* The load address of the section - where it would be in a
+ rom image, really only used for writing section header
+ information. */
+
+ bfd_vma lma;
+
+ /* The size of the section in bytes, as it will be output.
+ contains a value even if the section has no contents (eg, the
+ size of <<.bss>>). This will be filled in after relocation */
+
+ bfd_size_type _cooked_size;
+
+ /* The size on disk of the section in bytes originally. Normally this
+ value is the same as the size, but if some relaxing has
+ been done, then this value will be bigger. */
+
+ bfd_size_type _raw_size;
+
+ /* If this section is going to be output, then this value is the
+ offset into the output section of the first byte in the input
+ section. Eg, if this was going to start at the 100th byte in
+ the output section, this value would be 100. */
+
+ bfd_vma output_offset;
+
+ /* The output section through which to map on output. */
+
+ struct sec *output_section;
+
+ /* The alignment requirement of the section, as an exponent - eg
+ 3 aligns to 2^3 (or 8) */
+
+ unsigned int alignment_power;
+
+ /* If an input section, a pointer to a vector of relocation
+ records for the data in this section. */
+
+ struct reloc_cache_entry *relocation;
+
+ /* If an output section, a pointer to a vector of pointers to
+ relocation records for the data in this section. */
+
+ struct reloc_cache_entry **orelocation;
+
+ /* The number of relocation records in one of the above */
+
+ unsigned reloc_count;
+
+ /* Information below is back end specific - and not always used
+ or updated. */
+
+ /* File position of section data */
+
+ file_ptr filepos;
+
+ /* File position of relocation info */
+
+ file_ptr rel_filepos;
+
+ /* File position of line data */
+
+ file_ptr line_filepos;
+
+ /* Pointer to data for applications */
+
+ PTR userdata;
+
+ struct lang_output_section *otheruserdata;
+
+ /* Attached line number information */
+
+ alent *lineno;
+
+ /* Number of line number records */
+
+ unsigned int lineno_count;
+
+ /* When a section is being output, this value changes as more
+ linenumbers are written out */
+
+ file_ptr moving_line_filepos;
+
+ /* what the section number is in the target world */
+
+ int target_index;
+
+ PTR used_by_bfd;
+
+ /* If this is a constructor section then here is a list of the
+ relocations created to relocate items within it. */
+
+ struct relent_chain *constructor_chain;
+
+ /* The BFD which owns the section. */
+
+ bfd *owner;
+
+ boolean reloc_done;
+ /* A symbol which points at this section only */
+ struct symbol_cache_entry *symbol;
+ struct symbol_cache_entry **symbol_ptr_ptr;
+
+ struct bfd_seclet *seclets_head;
+ struct bfd_seclet *seclets_tail;
+} asection ;
+
+
+ /* These sections are global, and are managed by BFD. The application
+ and target back end are not permitted to change the values in
+ these sections. */
+#define BFD_ABS_SECTION_NAME "*ABS*"
+#define BFD_UND_SECTION_NAME "*UND*"
+#define BFD_COM_SECTION_NAME "*COM*"
+#define BFD_IND_SECTION_NAME "*IND*"
+
+ /* the absolute section */
+extern asection bfd_abs_section;
+ /* Pointer to the undefined section */
+extern asection bfd_und_section;
+ /* Pointer to the common section */
+extern asection bfd_com_section;
+ /* Pointer to the indirect section */
+extern asection bfd_ind_section;
+
+extern struct symbol_cache_entry *bfd_abs_symbol;
+extern struct symbol_cache_entry *bfd_com_symbol;
+extern struct symbol_cache_entry *bfd_und_symbol;
+extern struct symbol_cache_entry *bfd_ind_symbol;
+#define bfd_get_section_size_before_reloc(section) \
+ (section->reloc_done ? (abort(),1): (section)->_raw_size)
+#define bfd_get_section_size_after_reloc(section) \
+ ((section->reloc_done) ? (section)->_cooked_size: (abort(),1))
+asection *
+bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name));
+
+asection *
+bfd_make_section_old_way PARAMS ((bfd *, CONST char *name));
+
+asection *
+bfd_make_section_anyway PARAMS ((bfd *, CONST char *name));
+
+asection *
+bfd_make_section PARAMS ((bfd *, CONST char *name));
+
+boolean
+bfd_set_section_flags PARAMS ((bfd *, asection *, flagword));
+
+void
+bfd_map_over_sections PARAMS ((bfd *abfd,
+ void (*func)(bfd *abfd,
+ asection *sect,
+ PTR obj),
+ PTR obj));
+
+boolean
+bfd_set_section_size PARAMS ((bfd *, asection *, bfd_size_type val));
+
+boolean
+bfd_set_section_contents
+ PARAMS ((bfd *abfd,
+ asection *section,
+ PTR data,
+ file_ptr offset,
+ bfd_size_type count));
+
+boolean
+bfd_get_section_contents
+ PARAMS ((bfd *abfd, asection *section, PTR location,
+ file_ptr offset, bfd_size_type count));
+
+enum bfd_architecture
+{
+ bfd_arch_unknown, /* File arch not known */
+ bfd_arch_obscure, /* Arch known, not one of these */
+ bfd_arch_m68k, /* Motorola 68xxx */
+ bfd_arch_vax, /* DEC Vax */
+ bfd_arch_i960, /* Intel 960 */
+ /* The order of the following is important.
+ lower number indicates a machine type that
+ only accepts a subset of the instructions
+ available to machines with higher numbers.
+ The exception is the "ca", which is
+ incompatible with all other machines except
+ "core". */
+
+#define bfd_mach_i960_core 1
+#define bfd_mach_i960_ka_sa 2
+#define bfd_mach_i960_kb_sb 3
+#define bfd_mach_i960_mc 4
+#define bfd_mach_i960_xa 5
+#define bfd_mach_i960_ca 6
+
+ bfd_arch_a29k, /* AMD 29000 */
+ bfd_arch_sparc, /* SPARC */
+ bfd_arch_mips, /* MIPS Rxxxx */
+ bfd_arch_i386, /* Intel 386 */
+ bfd_arch_we32k, /* AT&T WE32xxx */
+ bfd_arch_tahoe, /* CCI/Harris Tahoe */
+ bfd_arch_i860, /* Intel 860 */
+ bfd_arch_romp, /* IBM ROMP PC/RT */
+ bfd_arch_alliant, /* Alliant */
+ bfd_arch_convex, /* Convex */
+ bfd_arch_m88k, /* Motorola 88xxx */
+ bfd_arch_pyramid, /* Pyramid Technology */
+ bfd_arch_h8300, /* Hitachi H8/300 */
+#define bfd_mach_h8300 1
+#define bfd_mach_h8300h 2
+ bfd_arch_rs6000, /* IBM RS/6000 */
+ bfd_arch_hppa, /* HP PA RISC */
+ bfd_arch_z8k, /* Zilog Z8000 */
+#define bfd_mach_z8001 1
+#define bfd_mach_z8002 2
+ bfd_arch_h8500, /* Hitachi H8/500 */
+ bfd_arch_sh, /* Hitachi SH */
+ bfd_arch_alpha, /* Dec Alpha */
+ bfd_arch_last
+ };
+
+typedef struct bfd_arch_info
+{
+ int bits_per_word;
+ int bits_per_address;
+ int bits_per_byte;
+ enum bfd_architecture arch;
+ long mach;
+ char *arch_name;
+ CONST char *printable_name;
+ unsigned int section_align_power;
+ /* true if this is the default machine for the architecture */
+ boolean the_default;
+ CONST struct bfd_arch_info * (*compatible)
+ PARAMS ((CONST struct bfd_arch_info *a,
+ CONST struct bfd_arch_info *b));
+
+ boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *));
+ /* How to disassemble an instruction, producing a printable
+ representation on a specified stdio stream. This isn't
+ defined for most processors at present, because of the size
+ of the additional tables it would drag in, and because gdb
+ wants to use a different interface. */
+ unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data,
+ PTR stream));
+
+ struct bfd_arch_info *next;
+} bfd_arch_info_type;
+CONST char *
+bfd_printable_name PARAMS ((bfd *abfd));
+
+bfd_arch_info_type *
+bfd_scan_arch PARAMS ((CONST char *));
+
+CONST bfd_arch_info_type *
+bfd_arch_get_compatible PARAMS ((
+ CONST bfd *abfd,
+ CONST bfd *bbfd));
+
+void
+bfd_set_arch_info PARAMS ((bfd *, bfd_arch_info_type *));
+
+enum bfd_architecture
+bfd_get_arch PARAMS ((bfd *abfd));
+
+unsigned long
+bfd_get_mach PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_byte PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_address PARAMS ((bfd *abfd));
+
+bfd_arch_info_type *
+bfd_get_arch_info PARAMS ((bfd *));
+
+bfd_arch_info_type *
+bfd_lookup_arch
+ PARAMS ((enum bfd_architecture
+ arch,
+ long machine));
+
+CONST char *
+bfd_printable_arch_mach
+ PARAMS ((enum bfd_architecture arch, unsigned long machine));
+
+typedef enum bfd_reloc_status
+{
+ /* No errors detected */
+ bfd_reloc_ok,
+
+ /* The relocation was performed, but there was an overflow. */
+ bfd_reloc_overflow,
+
+ /* The address to relocate was not within the section supplied. */
+ bfd_reloc_outofrange,
+
+ /* Used by special functions */
+ bfd_reloc_continue,
+
+ /* Unused */
+ bfd_reloc_notsupported,
+
+ /* Unsupported relocation size requested. */
+ bfd_reloc_other,
+
+ /* The symbol to relocate against was undefined. */
+ bfd_reloc_undefined,
+
+ /* The relocation was performed, but may not be ok - presently
+ generated only when linking i960 coff files with i960 b.out
+ symbols. */
+ bfd_reloc_dangerous
+ }
+ bfd_reloc_status_type;
+
+
+typedef struct reloc_cache_entry
+{
+ /* A pointer into the canonical table of pointers */
+ struct symbol_cache_entry **sym_ptr_ptr;
+
+ /* offset in section */
+ bfd_size_type address;
+
+ /* addend for relocation value */
+ bfd_vma addend;
+
+ /* Pointer to how to perform the required relocation */
+ CONST struct reloc_howto_struct *howto;
+
+} arelent;
+enum complain_overflow
+{
+ /* Do not complain on overflow. */
+ complain_overflow_dont,
+
+ /* Complain if the bitfield overflows, whether it is considered
+ as signed or unsigned. */
+ complain_overflow_bitfield,
+
+ /* Complain if the value overflows when considered as signed
+ number. */
+ complain_overflow_signed,
+
+ /* Complain if the value overflows when considered as an
+ unsigned number. */
+ complain_overflow_unsigned
+};
+
+typedef CONST struct reloc_howto_struct
+{
+ /* The type field has mainly a documetary use - the back end can
+ to what it wants with it, though the normally the back end's
+ external idea of what a reloc number would be would be stored
+ in this field. For example, the a PC relative word relocation
+ in a coff environment would have the type 023 - because that's
+ what the outside world calls a R_PCRWORD reloc. */
+ unsigned int type;
+
+ /* The value the final relocation is shifted right by. This drops
+ unwanted data from the relocation. */
+ unsigned int rightshift;
+
+ /* The size of the item to be relocated. This is *not* a
+ power-of-two measure.
+ 0 : one byte
+ 1 : two bytes
+ 2 : four bytes
+ 3 : nothing done (unless special_function is nonzero)
+ 4 : eight bytes
+ -2 : two bytes, result should be subtracted from the
+ data instead of added
+ There is currently no trivial way to extract a "number of
+ bytes" from a howto pointer. */
+ int size;
+
+ /* The number of bits in the item to be relocated. This is used
+ when doing overflow checking. */
+ unsigned int bitsize;
+
+ /* Notes that the relocation is relative to the location in the
+ data section of the addend. The relocation function will
+ subtract from the relocation value the address of the location
+ being relocated. */
+ boolean pc_relative;
+
+ /* The bit position of the reloc value in the destination.
+ The relocated value is left shifted by this amount. */
+ unsigned int bitpos;
+
+ /* What type of overflow error should be checked for when
+ relocating. */
+ enum complain_overflow complain_on_overflow;
+
+ /* If this field is non null, then the supplied function is
+ called rather than the normal function. This allows really
+ strange relocation methods to be accomodated (e.g., i960 callj
+ instructions). */
+ bfd_reloc_status_type (*special_function)
+ PARAMS ((bfd *abfd,
+ arelent *reloc_entry,
+ struct symbol_cache_entry *symbol,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd));
+
+ /* The textual name of the relocation type. */
+ char *name;
+
+ /* When performing a partial link, some formats must modify the
+ relocations rather than the data - this flag signals this.*/
+ boolean partial_inplace;
+
+ /* The src_mask is used to select what parts of the read in data
+ are to be used in the relocation sum. E.g., if this was an 8 bit
+ bit of data which we read and relocated, this would be
+ 0x000000ff. When we have relocs which have an addend, such as
+ sun4 extended relocs, the value in the offset part of a
+ relocating field is garbage so we never use it. In this case
+ the mask would be 0x00000000. */
+ bfd_vma src_mask;
+
+ /* The dst_mask is what parts of the instruction are replaced
+ into the instruction. In most cases src_mask == dst_mask,
+ except in the above special case, where dst_mask would be
+ 0x000000ff, and src_mask would be 0x00000000. */
+ bfd_vma dst_mask;
+
+ /* When some formats create PC relative instructions, they leave
+ the value of the pc of the place being relocated in the offset
+ slot of the instruction, so that a PC relative relocation can
+ be made just by adding in an ordinary offset (e.g., sun3 a.out).
+ Some formats leave the displacement part of an instruction
+ empty (e.g., m88k bcs), this flag signals the fact.*/
+ boolean pcrel_offset;
+
+} reloc_howto_type;
+#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+ {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC}
+#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN)
+
+#define HOWTO_PREPARE(relocation, symbol) \
+ { \
+ if (symbol != (asymbol *)NULL) { \
+ if (bfd_is_com_section (symbol->section)) { \
+ relocation = 0; \
+ } \
+ else { \
+ relocation = symbol->value; \
+ } \
+ } \
+}
+typedef unsigned char bfd_byte;
+
+typedef struct relent_chain {
+ arelent relent;
+ struct relent_chain *next;
+} arelent_chain;
+bfd_reloc_status_type
+
+bfd_perform_relocation
+ PARAMS ((bfd * abfd,
+ arelent *reloc_entry,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd));
+
+typedef enum bfd_reloc_code_real
+{
+ /* Basic absolute relocations */
+ BFD_RELOC_64,
+ BFD_RELOC_32,
+ BFD_RELOC_16,
+ BFD_RELOC_8,
+
+ /* PC-relative relocations */
+ BFD_RELOC_64_PCREL,
+ BFD_RELOC_32_PCREL,
+ BFD_RELOC_24_PCREL, /* used by i960 */
+ BFD_RELOC_16_PCREL,
+ BFD_RELOC_8_PCREL,
+
+ /* Linkage-table relative */
+ BFD_RELOC_32_BASEREL,
+ BFD_RELOC_16_BASEREL,
+ BFD_RELOC_8_BASEREL,
+
+ /* The type of reloc used to build a contructor table - at the moment
+ probably a 32 bit wide abs address, but the cpu can choose. */
+ BFD_RELOC_CTOR,
+
+ /* 8 bits wide, but used to form an address like 0xffnn */
+ BFD_RELOC_8_FFnn,
+
+ /* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit
+ word displacement, e.g. for SPARC) */
+ BFD_RELOC_32_PCREL_S2,
+
+ /* High 22 bits of 32-bit value, placed into lower 22 bits of
+ target word; simple reloc. */
+ BFD_RELOC_HI22,
+ /* Low 10 bits. */
+ BFD_RELOC_LO10,
+
+ /* Reloc types used for i960/b.out. */
+ BFD_RELOC_I960_CALLJ,
+
+ /* now for the sparc/elf codes */
+ BFD_RELOC_NONE, /* actually used */
+ BFD_RELOC_SPARC_WDISP22,
+ BFD_RELOC_SPARC22,
+ BFD_RELOC_SPARC13,
+ BFD_RELOC_SPARC_GOT10,
+ BFD_RELOC_SPARC_GOT13,
+ BFD_RELOC_SPARC_GOT22,
+ BFD_RELOC_SPARC_PC10,
+ BFD_RELOC_SPARC_PC22,
+ BFD_RELOC_SPARC_WPLT30,
+ BFD_RELOC_SPARC_COPY,
+ BFD_RELOC_SPARC_GLOB_DAT,
+ BFD_RELOC_SPARC_JMP_SLOT,
+ BFD_RELOC_SPARC_RELATIVE,
+ BFD_RELOC_SPARC_UA32,
+
+ /* these are a.out specific? */
+ BFD_RELOC_SPARC_BASE13,
+ BFD_RELOC_SPARC_BASE22,
+
+
+ /* Bits 27..2 of the relocation address shifted right 2 bits;
+ simple reloc otherwise. */
+ BFD_RELOC_MIPS_JMP,
+
+ /* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) */
+ BFD_RELOC_16_PCREL_S2,
+
+ /* High 16 bits of 32-bit value; simple reloc. */
+ BFD_RELOC_HI16,
+ /* High 16 bits of 32-bit value but the low 16 bits will be sign
+ extended and added to form the final result. If the low 16
+ bits form a negative number, we need to add one to the high value
+ to compensate for the borrow when the low bits are added. */
+ BFD_RELOC_HI16_S,
+ /* Low 16 bits. */
+ BFD_RELOC_LO16,
+
+ /* 16 bit relocation relative to the global pointer. */
+ BFD_RELOC_MIPS_GPREL,
+
+ /* These are, so far, specific to HPPA processors. I'm not sure that some
+ don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL.
+ Also, many more were in the list I got that don't fit in well in the
+ model BFD uses, so I've omitted them for now. If we do make this reloc
+ type get used for code that really does implement the funky reloc types,
+ they'll have to be added to this list. */
+ BFD_RELOC_HPPA_32,
+ BFD_RELOC_HPPA_11,
+ BFD_RELOC_HPPA_14,
+ BFD_RELOC_HPPA_17,
+
+ BFD_RELOC_HPPA_L21,
+ BFD_RELOC_HPPA_R11,
+ BFD_RELOC_HPPA_R14,
+ BFD_RELOC_HPPA_R17,
+ BFD_RELOC_HPPA_LS21,
+ BFD_RELOC_HPPA_RS11,
+ BFD_RELOC_HPPA_RS14,
+ BFD_RELOC_HPPA_RS17,
+ BFD_RELOC_HPPA_LD21,
+ BFD_RELOC_HPPA_RD11,
+ BFD_RELOC_HPPA_RD14,
+ BFD_RELOC_HPPA_RD17,
+ BFD_RELOC_HPPA_LR21,
+ BFD_RELOC_HPPA_RR14,
+ BFD_RELOC_HPPA_RR17,
+
+ BFD_RELOC_HPPA_GOTOFF_11,
+ BFD_RELOC_HPPA_GOTOFF_14,
+ BFD_RELOC_HPPA_GOTOFF_L21,
+ BFD_RELOC_HPPA_GOTOFF_R11,
+ BFD_RELOC_HPPA_GOTOFF_R14,
+ BFD_RELOC_HPPA_GOTOFF_LS21,
+ BFD_RELOC_HPPA_GOTOFF_RS11,
+ BFD_RELOC_HPPA_GOTOFF_RS14,
+ BFD_RELOC_HPPA_GOTOFF_LD21,
+ BFD_RELOC_HPPA_GOTOFF_RD11,
+ BFD_RELOC_HPPA_GOTOFF_RD14,
+ BFD_RELOC_HPPA_GOTOFF_LR21,
+ BFD_RELOC_HPPA_GOTOFF_RR14,
+
+ BFD_RELOC_HPPA_DLT_32,
+ BFD_RELOC_HPPA_DLT_11,
+ BFD_RELOC_HPPA_DLT_14,
+ BFD_RELOC_HPPA_DLT_L21,
+ BFD_RELOC_HPPA_DLT_R11,
+ BFD_RELOC_HPPA_DLT_R14,
+
+ BFD_RELOC_HPPA_ABS_CALL_11,
+ BFD_RELOC_HPPA_ABS_CALL_14,
+ BFD_RELOC_HPPA_ABS_CALL_17,
+ BFD_RELOC_HPPA_ABS_CALL_L21,
+ BFD_RELOC_HPPA_ABS_CALL_R11,
+ BFD_RELOC_HPPA_ABS_CALL_R14,
+ BFD_RELOC_HPPA_ABS_CALL_R17,
+ BFD_RELOC_HPPA_ABS_CALL_LS21,
+ BFD_RELOC_HPPA_ABS_CALL_RS11,
+ BFD_RELOC_HPPA_ABS_CALL_RS14,
+ BFD_RELOC_HPPA_ABS_CALL_RS17,
+ BFD_RELOC_HPPA_ABS_CALL_LD21,
+ BFD_RELOC_HPPA_ABS_CALL_RD11,
+ BFD_RELOC_HPPA_ABS_CALL_RD14,
+ BFD_RELOC_HPPA_ABS_CALL_RD17,
+ BFD_RELOC_HPPA_ABS_CALL_LR21,
+ BFD_RELOC_HPPA_ABS_CALL_RR14,
+ BFD_RELOC_HPPA_ABS_CALL_RR17,
+
+ BFD_RELOC_HPPA_PCREL_CALL_11,
+ BFD_RELOC_HPPA_PCREL_CALL_12,
+ BFD_RELOC_HPPA_PCREL_CALL_14,
+ BFD_RELOC_HPPA_PCREL_CALL_17,
+ BFD_RELOC_HPPA_PCREL_CALL_L21,
+ BFD_RELOC_HPPA_PCREL_CALL_R11,
+ BFD_RELOC_HPPA_PCREL_CALL_R14,
+ BFD_RELOC_HPPA_PCREL_CALL_R17,
+ BFD_RELOC_HPPA_PCREL_CALL_LS21,
+ BFD_RELOC_HPPA_PCREL_CALL_RS11,
+ BFD_RELOC_HPPA_PCREL_CALL_RS14,
+ BFD_RELOC_HPPA_PCREL_CALL_RS17,
+ BFD_RELOC_HPPA_PCREL_CALL_LD21,
+ BFD_RELOC_HPPA_PCREL_CALL_RD11,
+ BFD_RELOC_HPPA_PCREL_CALL_RD14,
+ BFD_RELOC_HPPA_PCREL_CALL_RD17,
+ BFD_RELOC_HPPA_PCREL_CALL_LR21,
+ BFD_RELOC_HPPA_PCREL_CALL_RR14,
+ BFD_RELOC_HPPA_PCREL_CALL_RR17,
+
+ BFD_RELOC_HPPA_PLABEL_32,
+ BFD_RELOC_HPPA_PLABEL_11,
+ BFD_RELOC_HPPA_PLABEL_14,
+ BFD_RELOC_HPPA_PLABEL_L21,
+ BFD_RELOC_HPPA_PLABEL_R11,
+ BFD_RELOC_HPPA_PLABEL_R14,
+
+ BFD_RELOC_HPPA_UNWIND_ENTRY,
+ BFD_RELOC_HPPA_UNWIND_ENTRIES,
+
+ /* i386/elf relocations */
+ BFD_RELOC_386_GOT32,
+ BFD_RELOC_386_PLT32,
+ BFD_RELOC_386_COPY,
+ BFD_RELOC_386_GLOB_DAT,
+ BFD_RELOC_386_JUMP_SLOT,
+ BFD_RELOC_386_RELATIVE,
+ BFD_RELOC_386_GOTOFF,
+ BFD_RELOC_386_GOTPC,
+
+ /* this must be the highest numeric value */
+ BFD_RELOC_UNUSED
+ } bfd_reloc_code_real_type;
+CONST struct reloc_howto_struct *
+
+bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+
+
+typedef struct symbol_cache_entry
+{
+ /* A pointer to the BFD which owns the symbol. This information
+ is necessary so that a back end can work out what additional
+ information (invisible to the application writer) is carried
+ with the symbol.
+
+ This field is *almost* redundant, since you can use section->owner
+ instead, except that some symbols point to the global sections
+ bfd_{abs,com,und}_section. This could be fixed by making
+ these globals be per-bfd (or per-target-flavor). FIXME. */
+
+ struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */
+
+ /* The text of the symbol. The name is left alone, and not copied - the
+ application may not alter it. */
+ CONST char *name;
+
+ /* The value of the symbol. This really should be a union of a
+ numeric value with a pointer, since some flags indicate that
+ a pointer to another symbol is stored here. */
+ symvalue value;
+
+ /* Attributes of a symbol: */
+
+#define BSF_NO_FLAGS 0x00
+
+ /* The symbol has local scope; <<static>> in <<C>>. The value
+ is the offset into the section of the data. */
+#define BSF_LOCAL 0x01
+
+ /* The symbol has global scope; initialized data in <<C>>. The
+ value is the offset into the section of the data. */
+#define BSF_GLOBAL 0x02
+
+ /* The symbol has global scope, and is exported. The value is
+ the offset into the section of the data. */
+#define BSF_EXPORT BSF_GLOBAL /* no real difference */
+
+ /* A normal C symbol would be one of:
+ <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or
+ <<BSF_GLOBAL>> */
+
+ /* The symbol is a debugging record. The value has an arbitary
+ meaning. */
+#define BSF_DEBUGGING 0x08
+
+ /* The symbol denotes a function entry point. Used in ELF,
+ perhaps others someday. */
+#define BSF_FUNCTION 0x10
+
+ /* Used by the linker. */
+#define BSF_KEEP 0x20
+#define BSF_KEEP_G 0x40
+
+ /* A weak global symbol, overridable without warnings by
+ a regular global symbol of the same name. */
+#define BSF_WEAK 0x80
+
+ /* This symbol was created to point to a section, e.g. ELF's
+ STT_SECTION symbols. */
+#define BSF_SECTION_SYM 0x100
+
+ /* The symbol used to be a common symbol, but now it is
+ allocated. */
+#define BSF_OLD_COMMON 0x200
+
+ /* The default value for common data. */
+#define BFD_FORT_COMM_DEFAULT_VALUE 0
+
+ /* In some files the type of a symbol sometimes alters its
+ location in an output file - ie in coff a <<ISFCN>> symbol
+ which is also <<C_EXT>> symbol appears where it was
+ declared and not at the end of a section. This bit is set
+ by the target BFD part to convey this information. */
+
+#define BSF_NOT_AT_END 0x400
+
+ /* Signal that the symbol is the label of constructor section. */
+#define BSF_CONSTRUCTOR 0x800
+
+ /* Signal that the symbol is a warning symbol. If the symbol
+ is a warning symbol, then the value field (I know this is
+ tacky) will point to the asymbol which when referenced will
+ cause the warning. */
+#define BSF_WARNING 0x1000
+
+ /* Signal that the symbol is indirect. The value of the symbol
+ is a pointer to an undefined asymbol which contains the
+ name to use instead. */
+#define BSF_INDIRECT 0x2000
+
+ /* BSF_FILE marks symbols that contain a file name. This is used
+ for ELF STT_FILE symbols. */
+#define BSF_FILE 0x4000
+
+ flagword flags;
+
+ /* A pointer to the section to which this symbol is
+ relative. This will always be non NULL, there are special
+ sections for undefined and absolute symbols */
+ struct sec *section;
+
+ /* Back end special data. This is being phased out in favour
+ of making this a union. */
+ PTR udata;
+
+} asymbol;
+#define get_symtab_upper_bound(abfd) \
+ BFD_SEND (abfd, _get_symtab_upper_bound, (abfd))
+#define bfd_canonicalize_symtab(abfd, location) \
+ BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+ (abfd, location))
+boolean
+bfd_set_symtab PARAMS ((bfd *, asymbol **, unsigned int ));
+
+void
+bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol));
+
+#define bfd_make_empty_symbol(abfd) \
+ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd))
+#define bfd_make_debug_symbol(abfd,ptr,size) \
+ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size))
+int
+bfd_decode_symclass PARAMS ((asymbol *symbol));
+
+void
+bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret));
+
+struct _bfd
+{
+ /* The filename the application opened the BFD with. */
+ CONST char *filename;
+
+ /* A pointer to the target jump table. */
+ struct bfd_target *xvec;
+
+ /* To avoid dragging too many header files into every file that
+ includes `<<bfd.h>>', IOSTREAM has been declared as a "char
+ *", and MTIME as a "long". Their correct types, to which they
+ are cast when used, are "FILE *" and "time_t". The iostream
+ is the result of an fopen on the filename. */
+ char *iostream;
+
+ /* Is the file being cached */
+
+ boolean cacheable;
+
+ /* Marks whether there was a default target specified when the
+ BFD was opened. This is used to select what matching algorithm
+ to use to chose the back end. */
+
+ boolean target_defaulted;
+
+ /* The caching routines use these to maintain a
+ least-recently-used list of BFDs */
+
+ struct _bfd *lru_prev, *lru_next;
+
+ /* When a file is closed by the caching routines, BFD retains
+ state information on the file here:
+ */
+
+ file_ptr where;
+
+ /* and here:*/
+
+ boolean opened_once;
+
+ /* Set if we have a locally maintained mtime value, rather than
+ getting it from the file each time: */
+
+ boolean mtime_set;
+
+ /* File modified time, if mtime_set is true: */
+
+ long mtime;
+
+ /* Reserved for an unimplemented file locking extension.*/
+
+ int ifd;
+
+ /* The format which belongs to the BFD.*/
+
+ bfd_format format;
+
+ /* The direction the BFD was opened with*/
+
+ enum bfd_direction {no_direction = 0,
+ read_direction = 1,
+ write_direction = 2,
+ both_direction = 3} direction;
+
+ /* Format_specific flags*/
+
+ flagword flags;
+
+ /* Currently my_archive is tested before adding origin to
+ anything. I believe that this can become always an add of
+ origin, with origin set to 0 for non archive files. */
+
+ file_ptr origin;
+
+ /* Remember when output has begun, to stop strange things
+ happening. */
+ boolean output_has_begun;
+
+ /* Pointer to linked list of sections*/
+ struct sec *sections;
+
+ /* The number of sections */
+ unsigned int section_count;
+
+ /* Stuff only useful for object files:
+ The start address. */
+ bfd_vma start_address;
+
+ /* Used for input and output*/
+ unsigned int symcount;
+
+ /* Symbol table for output BFD*/
+ struct symbol_cache_entry **outsymbols;
+
+ /* Pointer to structure which contains architecture information*/
+ struct bfd_arch_info *arch_info;
+
+ /* Stuff only useful for archives:*/
+ PTR arelt_data;
+ struct _bfd *my_archive;
+ struct _bfd *next;
+ struct _bfd *archive_head;
+ boolean has_armap;
+
+ /* Used by the back end to hold private data. */
+
+ union
+ {
+ struct aout_data_struct *aout_data;
+ struct artdata *aout_ar_data;
+ struct _oasys_data *oasys_obj_data;
+ struct _oasys_ar_data *oasys_ar_data;
+ struct coff_tdata *coff_obj_data;
+ struct ecoff_tdata *ecoff_obj_data;
+ struct ieee_data_struct *ieee_data;
+ struct ieee_ar_data_struct *ieee_ar_data;
+ struct srec_data_struct *srec_data;
+ struct tekhex_data_struct *tekhex_data;
+ struct elf_obj_tdata *elf_obj_data;
+ struct nlm_obj_tdata *nlm_obj_data;
+ struct bout_data_struct *bout_data;
+ struct sun_core_struct *sun_core_data;
+ struct trad_core_struct *trad_core_data;
+ struct hppa_data_struct *hppa_data;
+ struct hpux_core_struct *hpux_core_data;
+ struct sgi_core_struct *sgi_core_data;
+ struct lynx_core_struct *lynx_core_data;
+ struct osf_core_struct *osf_core_data;
+ PTR any;
+ } tdata;
+
+ /* Used by the application to hold private data*/
+ PTR usrdata;
+
+ /* Where all the allocated stuff under this BFD goes */
+ struct obstack memory;
+
+ /* Is this really needed in addition to usrdata? */
+ asymbol **ld_symbols;
+};
+
+unsigned int
+bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect));
+
+unsigned int
+bfd_canonicalize_reloc
+ PARAMS ((bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms));
+
+boolean
+bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags));
+
+void
+bfd_set_reloc
+ PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+ );
+
+boolean
+bfd_set_start_address PARAMS ((bfd *, bfd_vma));
+
+long
+bfd_get_mtime PARAMS ((bfd *));
+
+long
+bfd_get_size PARAMS ((bfd *));
+
+int
+bfd_get_gp_size PARAMS ((bfd *));
+
+void
+bfd_set_gp_size PARAMS ((bfd *, int));
+
+bfd_vma
+bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base));
+
+#define bfd_sizeof_headers(abfd, reloc) \
+ BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc))
+
+#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+ BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line))
+
+ /* Do these three do anything useful at all, for any back end? */
+#define bfd_debug_info_start(abfd) \
+ BFD_SEND (abfd, _bfd_debug_info_start, (abfd))
+
+#define bfd_debug_info_end(abfd) \
+ BFD_SEND (abfd, _bfd_debug_info_end, (abfd))
+
+#define bfd_debug_info_accumulate(abfd, section) \
+ BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section))
+
+
+#define bfd_stat_arch_elt(abfd, stat) \
+ BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat))
+
+#define bfd_set_arch_mach(abfd, arch, mach)\
+ BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach))
+
+#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \
+ BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable))
+
+#define bfd_relax_section(abfd, section, symbols) \
+ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols))
+
+#define bfd_seclet_link(abfd, data, relocateable) \
+ BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable))
+symindex
+bfd_get_next_mapent PARAMS ((bfd *, symindex previous, carsym ** sym));
+
+boolean
+bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head));
+
+bfd *
+bfd_get_elt_at_index PARAMS ((bfd * archive, int index));
+
+bfd*
+bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous));
+
+CONST char *
+bfd_core_file_failing_command PARAMS ((bfd *));
+
+int
+bfd_core_file_failing_signal PARAMS ((bfd *));
+
+boolean
+core_file_matches_executable_p
+ PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+#define BFD_SEND(bfd, message, arglist) \
+ ((*((bfd)->xvec->message)) arglist)
+#define BFD_SEND_FMT(bfd, message, arglist) \
+ (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+typedef struct bfd_target
+{
+ char *name;
+ enum target_flavour {
+ bfd_target_unknown_flavour,
+ bfd_target_aout_flavour,
+ bfd_target_coff_flavour,
+ bfd_target_ecoff_flavour,
+ bfd_target_elf_flavour,
+ bfd_target_ieee_flavour,
+ bfd_target_nlm_flavour,
+ bfd_target_oasys_flavour,
+ bfd_target_tekhex_flavour,
+ bfd_target_srec_flavour,
+ bfd_target_hppa_flavour} flavour;
+ boolean byteorder_big_p;
+ boolean header_byteorder_big_p;
+ flagword object_flags;
+ flagword section_flags;
+ char symbol_leading_char;
+ char ar_pad_char;
+ unsigned short ar_max_namelen;
+ unsigned int align_power_min;
+ bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *));
+ void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *));
+ void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *));
+ void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *));
+ boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *));
+ boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *));
+ char * (*_core_file_failing_command) PARAMS ((bfd *));
+ int (*_core_file_failing_signal) PARAMS ((bfd *));
+ boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+ boolean (*_bfd_slurp_armap) PARAMS ((bfd *));
+ boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *));
+ void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *));
+ boolean (*write_armap) PARAMS ((bfd *arch,
+ unsigned int elength,
+ struct orl *map,
+ unsigned int orl_count,
+ int stridx));
+ boolean (*_close_and_cleanup) PARAMS ((bfd *));
+ boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+ boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+ boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+ unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *));
+ unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+ struct symbol_cache_entry **));
+ unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+ unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+ struct symbol_cache_entry **));
+ struct symbol_cache_entry *
+ (*_bfd_make_empty_symbol) PARAMS ((bfd *));
+ void (*_bfd_print_symbol) PARAMS ((bfd *, PTR,
+ struct symbol_cache_entry *,
+ bfd_print_symbol_type));
+#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e))
+ void (*_bfd_get_symbol_info) PARAMS ((bfd *,
+ struct symbol_cache_entry *,
+ symbol_info *));
+#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e))
+ alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+
+ boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+
+ bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+
+ boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd,
+ struct sec *section, struct symbol_cache_entry **symbols,
+ bfd_vma offset, CONST char **file, CONST char **func,
+ unsigned int *line));
+
+ int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+
+ int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+
+ void (*_bfd_debug_info_start) PARAMS ((bfd *));
+ void (*_bfd_debug_info_end) PARAMS ((bfd *));
+ void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *));
+
+ bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+ struct bfd_seclet *, bfd_byte *data,
+ boolean relocateable));
+
+ boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+ struct symbol_cache_entry **));
+
+ boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data,
+ boolean relocateable));
+ /* See documentation on reloc types. */
+ CONST struct reloc_howto_struct *
+ (*reloc_type_lookup) PARAMS ((bfd *abfd,
+ bfd_reloc_code_real_type code));
+
+ /* Back-door to allow format-aware applications to create debug symbols
+ while using BFD for everything else. Currently used by the assembler
+ when creating COFF files. */
+ asymbol * (*_bfd_make_debug_symbol) PARAMS ((
+ bfd *abfd,
+ void *ptr,
+ unsigned long size));
+ PTR backend_data;
+} bfd_target;
+bfd_target *
+bfd_find_target PARAMS ((CONST char *, bfd *));
+
+CONST char **
+bfd_target_list PARAMS ((void));
+
+boolean
+bfd_check_format PARAMS ((bfd *abfd, bfd_format format));
+
+boolean
+bfd_set_format PARAMS ((bfd *, bfd_format));
+
+CONST char *
+bfd_format_string PARAMS ((bfd_format));
+
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/cache.c b/gnu/usr.bin/gdb/bfd/cache.c
new file mode 100644
index 000000000000..f8cfd19fed5c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cache.c
@@ -0,0 +1,311 @@
+/* BFD library -- caching of file descriptors.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ File Caching
+
+ The file caching mechanism is embedded within BFD and allows
+ the application to open as many BFDs as it wants without
+ regard to the underlying operating system's file descriptor
+ limit (often as low as 20 open files). The module in
+ <<cache.c>> maintains a least recently used list of
+ <<BFD_CACHE_MAX_OPEN>> files, and exports the name
+ <<bfd_cache_lookup>> which runs around and makes sure that
+ the required BFD is open. If not, then it chooses a file to
+ close, closes it and opens the one wanted, returning its file
+ handle.
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+INTERNAL_FUNCTION
+ BFD_CACHE_MAX_OPEN macro
+
+DESCRIPTION
+ The maximum number of files which the cache will keep open at
+ one time.
+
+.#define BFD_CACHE_MAX_OPEN 10
+
+*/
+
+
+static boolean
+bfd_cache_delete PARAMS ((bfd *));
+
+/* Number of bfds on the chain. All such bfds have their file open;
+ if it closed, they get snipd()d from the chain. */
+
+static int open_files;
+
+static bfd *cache_sentinel; /* Chain of BFDs with active fds we've
+ opened */
+
+/*
+INTERNAL_FUNCTION
+ bfd_last_cache
+
+SYNOPSIS
+ extern bfd *bfd_last_cache;
+
+DESCRIPTION
+ Zero, or a pointer to the topmost BFD on the chain. This is
+ used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to
+ determine when it can avoid a function call.
+*/
+
+bfd *bfd_last_cache;
+
+/*
+ * INTERNAL_FUNCTION
+ * bfd_cache_lookup
+ *
+ * DESCRIPTION
+ * Checks to see if the required BFD is the same as the last one
+ * looked up. If so then it can use the iostream in the BFD with
+ * impunity, since it can't have changed since the last lookup,
+ * otherwise it has to perform the complicated lookup function
+ *
+ * .#define bfd_cache_lookup(x) \
+ * . ((x)==bfd_last_cache? \
+ * . (FILE*)(bfd_last_cache->iostream): \
+ * . bfd_cache_lookup_worker(x))
+ *
+ *
+ */
+
+static void
+DEFUN_VOID(close_one)
+{
+ bfd *kill = cache_sentinel;
+ if (kill == 0) /* Nothing in the cache */
+ return ;
+
+ /* We can only close files that want to play this game. */
+ while (!kill->cacheable) {
+ kill = kill->lru_prev;
+ if (kill == cache_sentinel) /* Nobody wants to play */
+ return ;
+ }
+
+ kill->where = ftell((FILE *)(kill->iostream));
+ (void) bfd_cache_delete(kill);
+}
+
+/* Cuts the BFD abfd out of the chain in the cache */
+static void
+DEFUN(snip,(abfd),
+ bfd *abfd)
+{
+ abfd->lru_prev->lru_next = abfd->lru_next;
+ abfd->lru_next->lru_prev = abfd->lru_prev;
+ if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL;
+}
+
+static boolean
+DEFUN(bfd_cache_delete,(abfd),
+ bfd *abfd)
+{
+ boolean ret;
+
+ if (fclose ((FILE *)(abfd->iostream)) == 0)
+ ret = true;
+ else
+ {
+ ret = false;
+ bfd_error = system_call_error;
+ }
+ snip (abfd);
+ abfd->iostream = NULL;
+ open_files--;
+ bfd_last_cache = 0;
+ return ret;
+}
+
+static bfd *
+DEFUN(insert,(x,y),
+ bfd *x AND
+ bfd *y)
+{
+ if (y) {
+ x->lru_next = y;
+ x->lru_prev = y->lru_prev;
+ y->lru_prev->lru_next = x;
+ y->lru_prev = x;
+
+ }
+ else {
+ x->lru_prev = x;
+ x->lru_next = x;
+ }
+ return x;
+}
+
+
+/* Initialize a BFD by putting it on the cache LRU. */
+
+void
+DEFUN(bfd_cache_init,(abfd),
+ bfd *abfd)
+{
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ close_one ();
+ cache_sentinel = insert(abfd, cache_sentinel);
+ ++open_files;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_close
+
+DESCRIPTION
+ Remove the BFD from the cache. If the attached file is open,
+ then close it too.
+
+SYNOPSIS
+ boolean bfd_cache_close (bfd *);
+
+RETURNS
+ <<false>> is returned if closing the file fails, <<true>> is
+ returned if all is well.
+*/
+boolean
+DEFUN(bfd_cache_close,(abfd),
+ bfd *abfd)
+{
+ /* If this file is open then remove from the chain */
+ if (abfd->iostream)
+ {
+ return bfd_cache_delete(abfd);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_open_file
+
+DESCRIPTION
+ Call the OS to open a file for this BFD. Returns the FILE *
+ (possibly null) that results from this operation. Sets up the
+ BFD so that future accesses know the file is open. If the FILE
+ * returned is null, then there is won't have been put in the
+ cache, so it won't have to be removed from it.
+
+SYNOPSIS
+ FILE* bfd_open_file(bfd *);
+*/
+
+FILE *
+DEFUN(bfd_open_file, (abfd),
+ bfd *abfd)
+{
+ abfd->cacheable = true; /* Allow it to be closed later. */
+
+ if(open_files >= BFD_CACHE_MAX_OPEN) {
+ close_one();
+ }
+
+ switch (abfd->direction) {
+ case read_direction:
+ case no_direction:
+ abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RB);
+ break;
+ case both_direction:
+ case write_direction:
+ if (abfd->opened_once == true) {
+ abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RUB);
+ if (!abfd->iostream) {
+ abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WUB);
+ }
+ } else {
+ /*open for creat */
+ abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WB);
+ abfd->opened_once = true;
+ }
+ break;
+ }
+
+ if (abfd->iostream) {
+ bfd_cache_init (abfd);
+ }
+
+ return (FILE *)(abfd->iostream);
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_lookup_worker
+
+DESCRIPTION
+ Called when the macro <<bfd_cache_lookup>> fails to find a
+ quick answer. Finds a file descriptor for this BFD. If
+ necessary, it open it. If there are already more than
+ BFD_CACHE_MAX_OPEN files open, it trys to close one first, to
+ avoid running out of file descriptors.
+
+SYNOPSIS
+ FILE *bfd_cache_lookup_worker(bfd *);
+
+*/
+
+FILE *
+DEFUN(bfd_cache_lookup_worker,(abfd),
+ bfd *abfd)
+{
+ if (abfd->my_archive)
+ {
+ abfd = abfd->my_archive;
+ }
+ /* Is this file already open .. if so then quick exit */
+ if (abfd->iostream)
+ {
+ if (abfd != cache_sentinel) {
+ /* Place onto head of lru chain */
+ snip (abfd);
+ cache_sentinel = insert(abfd, cache_sentinel);
+ }
+ }
+ /* This is a BFD without a stream -
+ so it must have been closed or never opened.
+ find an empty cache entry and use it. */
+ else
+ {
+
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ {
+ close_one();
+ }
+
+ BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ;
+ fseek((FILE *)(abfd->iostream), abfd->where, false);
+ }
+ bfd_last_cache = abfd;
+ return (FILE *)(abfd->iostream);
+}
diff --git a/gnu/usr.bin/gdb/bfd/coffgen.c b/gnu/usr.bin/gdb/bfd/coffgen.c
new file mode 100644
index 000000000000..94cc225d098c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coffgen.c
@@ -0,0 +1,1519 @@
+/* Support for the generic parts of COFF, for BFD.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Most of this hacked by Steve Chamberlain, sac@cygnus.com.
+ Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */
+
+/* This file contains COFF code that is not dependent on any
+ particular COFF target. There is only one version of this file in
+ libbfd.a, so no target specific code may be put in here. Or, to
+ put it another way,
+
+ ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE **********
+
+ If you need to add some target specific behaviour, add a new hook
+ function to bfd_coff_backend_data.
+
+ Some of these functions are also called by the ECOFF routines.
+ Those functions may not use any COFF specific information, such as
+ coff_data (abfd). */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "seclet.h"
+#include "libcoff.h"
+
+static asection bfd_debug_section = { "*DEBUG*" };
+
+/* Take a section header read from a coff file (in HOST byte order),
+ and make a BFD "section" out of it. This is used by ECOFF. */
+static boolean
+DEFUN(make_a_section_from_file,(abfd, hdr, target_index),
+ bfd *abfd AND
+ struct internal_scnhdr *hdr AND
+ unsigned int target_index)
+{
+ asection *return_section;
+ char *name;
+
+ /* Assorted wastage to null-terminate the name, thanks AT&T! */
+ name = bfd_alloc(abfd, sizeof (hdr->s_name)+1);
+ if (name == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
+ name[sizeof (hdr->s_name)] = 0;
+
+ return_section = bfd_make_section(abfd, name);
+ if (return_section == NULL)
+ return_section = bfd_coff_make_section_hook (abfd, name);
+
+ /* Handle several sections of the same name. For example, if an executable
+ has two .bss sections, GDB better be able to find both of them
+ (PR 3562). */
+ if (return_section == NULL)
+ return_section = bfd_make_section_anyway (abfd, name);
+
+ if (return_section == NULL)
+ return false;
+
+ /* s_paddr is presumed to be = to s_vaddr */
+
+ return_section->vma = hdr->s_vaddr;
+ return_section->_raw_size = hdr->s_size;
+ return_section->filepos = hdr->s_scnptr;
+ return_section->rel_filepos = hdr->s_relptr;
+ return_section->reloc_count = hdr->s_nreloc;
+
+ bfd_coff_set_alignment_hook (abfd, return_section, hdr);
+
+ return_section->line_filepos = hdr->s_lnnoptr;
+
+ return_section->lineno_count = hdr->s_nlnno;
+ return_section->userdata = NULL;
+ return_section->next = (asection *) NULL;
+ return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr);
+
+ return_section->target_index = target_index;
+
+ /* At least on i386-coff, the line number count for a shared library
+ section must be ignored. */
+ if ((return_section->flags & SEC_SHARED_LIBRARY) != 0)
+ return_section->lineno_count = 0;
+
+ if (hdr->s_nreloc != 0)
+ return_section->flags |= SEC_RELOC;
+ /* FIXME: should this check 'hdr->s_size > 0' */
+ if (hdr->s_scnptr != 0)
+ return_section->flags |= SEC_HAS_CONTENTS;
+ return true;
+}
+
+/* Read in a COFF object and make it into a BFD. This is used by
+ ECOFF as well. */
+
+static
+bfd_target *
+DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a),
+ bfd *abfd AND
+ unsigned nscns AND
+ struct internal_filehdr *internal_f AND
+ struct internal_aouthdr *internal_a)
+{
+ PTR tdata;
+ size_t readsize; /* length of file_info */
+ unsigned int scnhsz;
+ char *external_sections;
+
+ /* Build a play area */
+ tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a);
+ if (tdata == NULL)
+ return 0;
+
+ scnhsz = bfd_coff_scnhsz (abfd);
+ readsize = nscns * scnhsz;
+ external_sections = (char *)bfd_alloc(abfd, readsize);
+
+ if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) {
+ goto fail;
+ }
+
+ /* Now copy data as required; construct all asections etc */
+ if (nscns != 0) {
+ unsigned int i;
+ for (i = 0; i < nscns; i++) {
+ struct internal_scnhdr tmp;
+ bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz),
+ (PTR) &tmp);
+ make_a_section_from_file(abfd,&tmp, i+1);
+ }
+ }
+
+/* make_abs_section(abfd);*/
+
+ if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false)
+ goto fail;
+
+ if (!(internal_f->f_flags & F_RELFLG))
+ abfd->flags |= HAS_RELOC;
+ if ((internal_f->f_flags & F_EXEC))
+ abfd->flags |= EXEC_P;
+ if (!(internal_f->f_flags & F_LNNO))
+ abfd->flags |= HAS_LINENO;
+ if (!(internal_f->f_flags & F_LSYMS))
+ abfd->flags |= HAS_LOCALS;
+
+
+ bfd_get_symcount(abfd) = internal_f->f_nsyms;
+ if (internal_f->f_nsyms)
+ abfd->flags |= HAS_SYMS;
+
+ if (internal_a != (struct internal_aouthdr *) NULL)
+ bfd_get_start_address (abfd) = internal_a->entry;
+ else
+ bfd_get_start_address (abfd) = 0;
+
+ return abfd->xvec;
+ fail:
+ bfd_release(abfd, tdata);
+ return (bfd_target *)NULL;
+}
+
+/* Turn a COFF file into a BFD, but fail with wrong_format if it is
+ not a COFF file. This is also used by ECOFF. */
+
+bfd_target *
+DEFUN(coff_object_p,(abfd),
+ bfd *abfd)
+{
+ unsigned int filhsz;
+ unsigned int aoutsz;
+ int nscns;
+ PTR filehdr;
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+
+ bfd_error = system_call_error;
+
+ /* figure out how much to read */
+ filhsz = bfd_coff_filhsz (abfd);
+ aoutsz = bfd_coff_aoutsz (abfd);
+
+ filehdr = bfd_alloc (abfd, filhsz);
+ if (filehdr == NULL)
+ return 0;
+ if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz)
+ return 0;
+ bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f);
+ bfd_release (abfd, filehdr);
+
+ if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) {
+ bfd_error = wrong_format;
+ return 0;
+ }
+ nscns =internal_f.f_nscns;
+
+ if (internal_f.f_opthdr) {
+ PTR opthdr;
+
+ opthdr = bfd_alloc (abfd, aoutsz);
+ if (opthdr == NULL)
+ return 0;;
+ if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) {
+ return 0;
+ }
+ bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a);
+ }
+
+ /* Seek past the opt hdr stuff */
+ bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET);
+
+ return coff_real_object_p(abfd, nscns, &internal_f,
+ (internal_f.f_opthdr != 0
+ ? &internal_a
+ : (struct internal_aouthdr *) NULL));
+}
+
+/* Get the BFD section from a COFF symbol section number. */
+
+struct sec *
+DEFUN(coff_section_from_bfd_index,(abfd, index),
+ bfd *abfd AND
+ int index)
+{
+ struct sec *answer = abfd->sections;
+
+ if (index == N_ABS)
+ {
+ return &bfd_abs_section;
+ }
+ if (index == N_UNDEF)
+ {
+ return &bfd_und_section;
+ }
+ if(index == N_DEBUG)
+ {
+ return &bfd_debug_section;
+
+ }
+
+ while (answer) {
+ if (answer->target_index == index)
+ return answer;
+ answer = answer->next;
+ }
+ BFD_ASSERT(0);
+ return &bfd_und_section; /* For gcc -W and lint. Never executed. */
+}
+
+/* Get the upper bound of a COFF symbol table. */
+
+unsigned int
+coff_get_symtab_upper_bound(abfd)
+bfd *abfd;
+{
+ if (!bfd_coff_slurp_symbol_table(abfd))
+ return 0;
+
+ return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *));
+}
+
+
+/* Canonicalize a COFF symbol table. */
+
+unsigned int
+DEFUN(coff_get_symtab, (abfd, alocation),
+ bfd *abfd AND
+ asymbol **alocation)
+{
+ unsigned int counter = 0;
+ coff_symbol_type *symbase;
+ coff_symbol_type **location = (coff_symbol_type **) (alocation);
+ if (!bfd_coff_slurp_symbol_table(abfd))
+ return 0;
+
+ symbase = obj_symbols(abfd);
+ while (counter < bfd_get_symcount(abfd))
+ {
+ /* This nasty code looks at the symbol to decide whether or
+ not it is descibes a constructor/destructor entry point. It
+ is structured this way to (hopefully) speed non matches */
+#if 0
+ if (0 && symbase->symbol.name[9] == '$')
+ {
+ bfd_constructor_entry(abfd,
+ (asymbol **)location,
+ symbase->symbol.name[10] == 'I' ?
+ "CTOR" : "DTOR");
+ }
+#endif
+ *(location++) = symbase++;
+ counter++;
+ }
+ *location++ = 0;
+ return bfd_get_symcount(abfd);
+}
+
+/* Set lineno_count for the output sections of a COFF file. */
+
+int
+DEFUN(coff_count_linenumbers,(abfd),
+ bfd *abfd)
+{
+ unsigned int limit = bfd_get_symcount(abfd);
+ unsigned int i;
+ int total = 0;
+ asymbol **p;
+ {
+ asection *s = abfd->sections->output_section;
+ while (s) {
+ BFD_ASSERT(s->lineno_count == 0);
+ s = s->next;
+ }
+ }
+
+
+ for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) {
+ asymbol *q_maybe = *p;
+ if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) {
+ coff_symbol_type *q = coffsymbol(q_maybe);
+ if (q->lineno) {
+ /*
+ This symbol has a linenumber, increment the owning
+ section's linenumber count
+ */
+ alent *l = q->lineno;
+ q->symbol.section->output_section->lineno_count++;
+ total ++;
+ l++;
+ while (l->line_number) {
+ total ++;
+ q->symbol.section->output_section->lineno_count++;
+ l++;
+ }
+ }
+ }
+ }
+ return total;
+}
+
+/* Takes a bfd and a symbol, returns a pointer to the coff specific
+ area of the symbol if there is one. */
+
+coff_symbol_type *
+DEFUN(coff_symbol_from,(ignore_abfd, symbol),
+ bfd *ignore_abfd AND
+ asymbol *symbol)
+{
+ if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour)
+ return (coff_symbol_type *)NULL;
+
+ if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL)
+ return (coff_symbol_type *)NULL;
+
+ return (coff_symbol_type *) symbol;
+}
+
+static void
+DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment),
+coff_symbol_type *coff_symbol_ptr AND
+struct internal_syment *syment)
+{
+
+ /* Normalize the symbol flags */
+ if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) {
+ /* a common symbol is undefined with a value */
+ syment->n_scnum = N_UNDEF;
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) {
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ else if (coff_symbol_ptr->symbol.section == & bfd_und_section) {
+ syment->n_scnum = N_UNDEF;
+ syment->n_value = 0;
+ }
+ else {
+ if (coff_symbol_ptr->symbol.section) {
+ syment->n_scnum =
+ coff_symbol_ptr->symbol.section->output_section->target_index;
+
+ syment->n_value =
+ coff_symbol_ptr->symbol.value +
+ coff_symbol_ptr->symbol.section->output_offset +
+ coff_symbol_ptr->symbol.section->output_section->vma;
+ }
+ else {
+ BFD_ASSERT(0);
+ /* This can happen, but I don't know why yet (steve@cygnus.com) */
+ syment->n_scnum = N_ABS;
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ }
+}
+
+/* run through all the symbols in the symbol table and work out what
+ their indexes into the symbol table will be when output
+
+ Coff requires that each C_FILE symbol points to the next one in the
+ chain, and that the last one points to the first external symbol. We
+ do that here too.
+
+*/
+void
+DEFUN(coff_renumber_symbols,(bfd_ptr),
+ bfd *bfd_ptr)
+{
+ unsigned int symbol_count = bfd_get_symcount(bfd_ptr);
+ asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
+ unsigned int native_index = 0;
+ struct internal_syment *last_file = (struct internal_syment *)NULL;
+ unsigned int symbol_index;
+
+ /* COFF demands that undefined symbols come after all other symbols.
+ Since we don't need to impose this extra knowledge on all our client
+ programs, deal with that here. Sort the symbol table; just move the
+ undefined symbols to the end, leaving the rest alone. */
+ /* @@ Do we have some condition we could test for, so we don't always
+ have to do this? I don't think relocatability is quite right, but
+ I'm not certain. [raeburn:19920508.1711EST] */
+ {
+ asymbol **newsyms;
+ int i;
+
+ newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr,
+ sizeof (asymbol *)
+ * (symbol_count + 1));
+ bfd_ptr->outsymbols = newsyms;
+ for (i = 0; i < symbol_count; i++)
+ if (symbol_ptr_ptr[i]->section != &bfd_und_section)
+ *newsyms++ = symbol_ptr_ptr[i];
+ for (i = 0; i < symbol_count; i++)
+ if (symbol_ptr_ptr[i]->section == &bfd_und_section)
+ *newsyms++ = symbol_ptr_ptr[i];
+ *newsyms = (asymbol *) NULL;
+ symbol_ptr_ptr = bfd_ptr->outsymbols;
+ }
+
+ for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
+ {
+ coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]);
+ if (coff_symbol_ptr && coff_symbol_ptr->native) {
+ combined_entry_type *s = coff_symbol_ptr->native;
+ int i;
+
+ if (s->u.syment.n_sclass == C_FILE)
+ {
+ if (last_file != (struct internal_syment *)NULL) {
+ last_file->n_value = native_index;
+ }
+ last_file = &(s->u.syment);
+ }
+ else {
+
+ /* Modify the symbol values according to their section and
+ type */
+
+ fixup_symbol_value(coff_symbol_ptr, &(s->u.syment));
+ }
+ for (i = 0; i < s->u.syment.n_numaux + 1; i++) {
+ s[i].offset = native_index ++;
+ }
+ }
+ else {
+ native_index++;
+ }
+ }
+ obj_conv_table_size (bfd_ptr) = native_index;
+}
+
+/*
+ Run thorough the symbol table again, and fix it so that all pointers to
+ entries are changed to the entries' index in the output symbol table.
+
+*/
+void
+DEFUN(coff_mangle_symbols,(bfd_ptr),
+ bfd *bfd_ptr)
+{
+ unsigned int symbol_count = bfd_get_symcount(bfd_ptr);
+ asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
+ unsigned int symbol_index;
+
+ for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
+ {
+ coff_symbol_type *coff_symbol_ptr =
+ coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]);
+
+ if (coff_symbol_ptr && coff_symbol_ptr->native) {
+ int i;
+ combined_entry_type *s = coff_symbol_ptr->native;
+
+ for (i = 0; i < s->u.syment.n_numaux ; i++) {
+ combined_entry_type *a = s + i + 1;
+ if (a->fix_tag) {
+ a->u.auxent.x_sym.x_tagndx.l =
+ a->u.auxent.x_sym.x_tagndx.p->offset;
+ a->fix_tag = 0;
+ }
+ if (a->fix_end) {
+ a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l =
+ a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset;
+ a->fix_end = 0;
+
+ }
+
+ }
+ }
+ }
+}
+
+static int string_size;
+
+static void
+DEFUN(coff_fix_symbol_name,(abfd, symbol, native),
+ bfd *abfd AND
+ asymbol *symbol AND
+ combined_entry_type *native)
+{
+ unsigned int name_length;
+ union internal_auxent *auxent;
+ char * name = ( char *)(symbol->name);
+
+ if (name == (char *) NULL) {
+ /* coff symbols always have names, so we'll make one up */
+ symbol->name = "strange";
+ name = (char *)symbol->name;
+ }
+ name_length = strlen(name);
+
+ if (native->u.syment.n_sclass == C_FILE) {
+ strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN);
+ auxent = &(native+1)->u.auxent;
+
+ if (bfd_coff_long_filenames (abfd)) {
+ if (name_length <= FILNMLEN) {
+ strncpy(auxent->x_file.x_fname, name, FILNMLEN);
+ }
+ else {
+ auxent->x_file.x_n.x_offset = string_size + 4;
+ auxent->x_file.x_n.x_zeroes = 0;
+ string_size += name_length + 1;
+ }
+ }
+ else {
+ strncpy(auxent->x_file.x_fname, name, FILNMLEN);
+ if (name_length > FILNMLEN) {
+ name[FILNMLEN] = '\0';
+ }
+ }
+ }
+ else
+ { /* NOT A C_FILE SYMBOL */
+ if (name_length <= SYMNMLEN) {
+ /* This name will fit into the symbol neatly */
+ strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN);
+ }
+ else {
+ native->u.syment._n._n_n._n_offset = string_size + 4;
+ native->u.syment._n._n_n._n_zeroes = 0;
+ string_size += name_length + 1;
+ }
+ }
+}
+
+#define set_index(symbol, idx) ((symbol)->udata =(PTR) (idx))
+
+static unsigned int
+DEFUN(coff_write_symbol,(abfd, symbol, native, written),
+bfd *abfd AND
+asymbol *symbol AND
+combined_entry_type *native AND
+unsigned int written)
+{
+ unsigned int numaux = native->u.syment.n_numaux;
+ int type = native->u.syment.n_type;
+ int class = native->u.syment.n_sclass;
+ PTR buf;
+ bfd_size_type symesz;
+
+ /* @@ bfd_debug_section isn't accessible outside this file, but we know
+ that C_FILE symbols belong there. So move them. */
+ if (native->u.syment.n_sclass == C_FILE)
+ symbol->section = &bfd_debug_section;
+
+ if (symbol->section == &bfd_abs_section)
+ {
+ native->u.syment.n_scnum = N_ABS;
+ }
+ else if (symbol->section == &bfd_debug_section)
+ {
+ native->u.syment.n_scnum = N_DEBUG;
+ }
+ else if (symbol->section == &bfd_und_section)
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ }
+ else
+ {
+ native->u.syment.n_scnum =
+ symbol->section->output_section->target_index;
+ }
+
+
+ coff_fix_symbol_name(abfd, symbol, native);
+
+ symesz = bfd_coff_symesz (abfd);
+ buf = bfd_alloc (abfd, symesz);
+ bfd_coff_swap_sym_out(abfd, &native->u.syment, buf);
+ bfd_write(buf, 1, symesz, abfd);
+ bfd_release (abfd, buf);
+
+ if (native->u.syment.n_numaux > 0)
+ {
+ bfd_size_type auxesz;
+ unsigned int j;
+
+ auxesz = bfd_coff_auxesz (abfd);
+ buf = bfd_alloc (abfd, auxesz);
+ for (j = 0; j < native->u.syment.n_numaux; j++)
+ {
+ bfd_coff_swap_aux_out(abfd,
+ &((native + j + 1)->u.auxent),
+ type,
+ class,
+ buf);
+ bfd_write(buf, 1, auxesz, abfd);
+ }
+ bfd_release (abfd, buf);
+ }
+ /*
+ Reuse somewhere in the symbol to keep the index
+ */
+ set_index(symbol, written);
+ return written + 1 + numaux;
+}
+
+
+static unsigned int
+DEFUN(coff_write_alien_symbol,(abfd, symbol, written),
+ bfd *abfd AND
+ asymbol *symbol AND
+ unsigned int written)
+{
+ /*
+ This symbol has been created by the loader, or come from a non
+ coff format. It has no native element to inherit, make our
+ own
+ */
+ combined_entry_type *native;
+ combined_entry_type dummy;
+ native = &dummy;
+ native->u.syment.n_type = T_NULL;
+ native->u.syment.n_flags = 0;
+ if (symbol->section == &bfd_und_section)
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ native->u.syment.n_value = symbol->value;
+ }
+ else if (bfd_is_com_section (symbol->section))
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ native->u.syment.n_value = symbol->value;
+
+ }
+
+ else if (symbol->flags & BSF_DEBUGGING) {
+ /*
+ remove name so it doesn't take up any space
+ */
+ symbol->name = "";
+ }
+ else {
+ native->u.syment.n_scnum = symbol->section->output_section->target_index;
+ native->u.syment.n_value = symbol->value +
+ symbol->section->output_section->vma +
+ symbol->section->output_offset;
+ /* Copy the any flags from the the file hdr into the symbol */
+ {
+ coff_symbol_type *c = coff_symbol_from(abfd, symbol);
+ if (c != (coff_symbol_type *)NULL) {
+ native->u.syment.n_flags = bfd_asymbol_bfd(&c->symbol)->flags;
+ }
+ }
+ }
+
+ native->u.syment.n_type = 0;
+ if (symbol->flags & BSF_LOCAL)
+ native->u.syment.n_sclass = C_STAT;
+ else
+ native->u.syment.n_sclass = C_EXT;
+ native->u.syment.n_numaux = 0;
+
+ return coff_write_symbol(abfd, symbol, native, written);
+}
+
+static unsigned int
+DEFUN(coff_write_native_symbol,(abfd, symbol, written),
+bfd *abfd AND
+coff_symbol_type *symbol AND
+unsigned int written)
+{
+ /*
+ Does this symbol have an ascociated line number - if so then
+ make it remember this symbol index. Also tag the auxent of
+ this symbol to point to the right place in the lineno table
+ */
+ combined_entry_type *native = symbol->native;
+
+ alent *lineno = symbol->lineno;
+
+ if (lineno && !symbol->done_lineno) {
+ unsigned int count = 0;
+ lineno[count].u.offset = written;
+ if (native->u.syment.n_numaux) {
+ union internal_auxent *a = &((native+1)->u.auxent);
+
+ a->x_sym.x_fcnary.x_fcn.x_lnnoptr =
+ symbol->symbol.section->output_section->moving_line_filepos;
+ }
+ /*
+ And count and relocate all other linenumbers
+ */
+
+ count++;
+ while (lineno[count].line_number) {
+#if 0
+/* 13 april 92. sac
+I've been told this, but still need proof:
+> The second bug is also in `bfd/coffcode.h'. This bug causes the linker to screw
+> up the pc-relocations for all the line numbers in COFF code. This bug isn't
+> only specific to A29K implementations, but affects all systems using COFF
+> format binaries. Note that in COFF object files, the line number core offsets
+> output by the assembler are relative to the start of each procedure, not
+> to the start of the .text section. This patch relocates the line numbers
+> relative to the `native->u.syment.n_value' instead of the section virtual
+> address. modular!olson@cs.arizona.edu (Jon Olson)
+*/
+ lineno[count].u.offset += native->u.syment.n_value;
+
+#else
+ lineno[count].u.offset +=
+ symbol->symbol.section->output_section->vma +
+ symbol->symbol.section->output_offset;
+#endif
+ count++;
+ }
+ symbol->done_lineno = true;
+
+ symbol->symbol.section->output_section->moving_line_filepos +=
+ count * bfd_coff_linesz (abfd);
+ }
+ return coff_write_symbol(abfd, &( symbol->symbol), native,written);
+}
+
+void
+DEFUN(coff_write_symbols,(abfd),
+ bfd *abfd)
+{
+ unsigned int i;
+ unsigned int limit = bfd_get_symcount(abfd);
+ unsigned int written = 0;
+
+ asymbol **p;
+
+ string_size = 0;
+
+
+ /* Seek to the right place */
+ bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET);
+
+ /* Output all the symbols we have */
+
+ written = 0;
+ for (p = abfd->outsymbols, i = 0; i < limit; i++, p++)
+ {
+ asymbol *symbol = *p;
+ coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol);
+
+ if (c_symbol == (coff_symbol_type *) NULL ||
+ c_symbol->native == (combined_entry_type *)NULL)
+ {
+ written = coff_write_alien_symbol(abfd, symbol, written);
+ }
+ else
+ {
+ written = coff_write_native_symbol(abfd, c_symbol, written);
+ }
+
+ }
+
+ bfd_get_symcount(abfd) = written;
+
+ /* Now write out strings */
+
+ if (string_size != 0)
+ {
+ unsigned int size = string_size + 4;
+ bfd_byte buffer[4];
+
+ bfd_h_put_32(abfd, size, buffer);
+ bfd_write((PTR) buffer, 1, sizeof(buffer), abfd);
+ for (p = abfd->outsymbols, i = 0;
+ i < limit;
+ i++, p++)
+ {
+ asymbol *q = *p;
+ size_t name_length = strlen(q->name);
+ int maxlen;
+ coff_symbol_type* c_symbol = coff_symbol_from(abfd, q);
+ maxlen = ((c_symbol != NULL && c_symbol->native != NULL) &&
+ (c_symbol->native->u.syment.n_sclass == C_FILE)) ?
+ FILNMLEN : SYMNMLEN;
+
+ if (name_length > maxlen) {
+ bfd_write((PTR) (q->name), 1, name_length + 1, abfd);
+ }
+ }
+ }
+ else {
+ /* We would normally not write anything here, but we'll write
+ out 4 so that any stupid coff reader which tries to read
+ the string table even when there isn't one won't croak. */
+ unsigned int size = 4;
+ bfd_byte buffer[4];
+
+ bfd_h_put_32 (abfd, size, buffer);
+ bfd_write((PTR) buffer, 1, sizeof (buffer), abfd);
+ }
+}
+
+void
+DEFUN(coff_write_linenumbers,(abfd),
+ bfd *abfd)
+{
+ asection *s;
+ bfd_size_type linesz;
+ PTR buff;
+
+ linesz = bfd_coff_linesz (abfd);
+ buff = bfd_alloc (abfd, linesz);
+ for (s = abfd->sections; s != (asection *) NULL; s = s->next) {
+ if (s->lineno_count) {
+ asymbol **q = abfd->outsymbols;
+ bfd_seek(abfd, s->line_filepos, SEEK_SET);
+ /* Find all the linenumbers in this section */
+ while (*q) {
+ asymbol *p = *q;
+ if (p->section->output_section == s) {
+ alent *l =
+ BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p));
+ if (l) {
+ /* Found a linenumber entry, output */
+ struct internal_lineno out;
+ memset( (PTR)&out, 0, sizeof(out));
+ out.l_lnno = 0;
+ out.l_addr.l_symndx = l->u.offset;
+ bfd_coff_swap_lineno_out(abfd, &out, buff);
+ bfd_write(buff, 1, linesz, abfd);
+ l++;
+ while (l->line_number) {
+ out.l_lnno = l->line_number;
+ out.l_addr.l_symndx = l->u.offset;
+ bfd_coff_swap_lineno_out(abfd, &out, buff);
+ bfd_write(buff, 1, linesz, abfd);
+ l++;
+ }
+ }
+ }
+ q++;
+ }
+ }
+ }
+ bfd_release (abfd, buff);
+}
+
+alent *
+DEFUN(coff_get_lineno,(ignore_abfd, symbol),
+ bfd *ignore_abfd AND
+ asymbol *symbol)
+{
+ return coffsymbol(symbol)->lineno;
+}
+
+asymbol *
+coff_section_symbol (abfd, name)
+ bfd *abfd;
+ char *name;
+{
+ asection *sec = bfd_make_section_old_way (abfd, name);
+ asymbol *sym;
+ combined_entry_type *csym;
+
+ sym = sec->symbol;
+ csym = coff_symbol_from (abfd, sym)->native;
+ /* Make sure back-end COFF stuff is there. */
+ if (csym == 0)
+ {
+ struct foo {
+ coff_symbol_type sym;
+ /* @@FIXME This shouldn't use a fixed size!! */
+ combined_entry_type e[10];
+ };
+ struct foo *f;
+ f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f));
+ memset ((char *) f, 0, sizeof (*f));
+ coff_symbol_from (abfd, sym)->native = csym = f->e;
+ }
+ csym[0].u.syment.n_sclass = C_STAT;
+ csym[0].u.syment.n_numaux = 1;
+/* SF_SET_STATICS (sym); @@ ??? */
+ csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size;
+ csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count;
+ csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count;
+
+ if (sec->output_section == NULL)
+ {
+ sec->output_section = sec;
+ sec->output_offset = 0;
+ }
+
+ return sym;
+}
+
+/* This function transforms the offsets into the symbol table into
+ pointers to syments. */
+
+static void
+DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent),
+bfd *abfd AND
+combined_entry_type *table_base AND
+int type AND
+int class AND
+combined_entry_type *auxent)
+{
+ /* Don't bother if this is a file or a section */
+ if (class == C_STAT && type == T_NULL) return;
+ if (class == C_FILE) return;
+
+ /* Otherwise patch up */
+#define N_TMASK coff_data (abfd)->local_n_tmask
+#define N_BTSHFT coff_data (abfd)->local_n_btshft
+ if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) {
+ auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base +
+ auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l;
+ auxent->fix_end = 1;
+ }
+ /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can
+ generate one, so we must be careful to ignore it. */
+ if (auxent->u.auxent.x_sym.x_tagndx.l > 0) {
+ auxent->u.auxent.x_sym.x_tagndx.p =
+ table_base + auxent->u.auxent.x_sym.x_tagndx.l;
+ auxent->fix_tag = 1;
+ }
+}
+
+static char *
+DEFUN(build_string_table,(abfd),
+bfd *abfd)
+{
+ char string_table_size_buffer[4];
+ unsigned int string_table_size;
+ char *string_table;
+
+ /* At this point we should be "seek"'d to the end of the
+ symbols === the symbol table size. */
+ if (bfd_read((char *) string_table_size_buffer,
+ sizeof(string_table_size_buffer),
+ 1, abfd) != sizeof(string_table_size)) {
+ bfd_error = system_call_error;
+ return (NULL);
+ } /* on error */
+
+ string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer);
+
+ if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) {
+ bfd_error = no_memory;
+ return (NULL);
+ } /* on mallocation error */
+ if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) {
+ bfd_error = system_call_error;
+ return (NULL);
+ }
+ return string_table;
+}
+
+/* Allocate space for the ".debug" section, and read it.
+ We did not read the debug section until now, because
+ we didn't want to go to the trouble until someone needed it. */
+
+static char *
+DEFUN(build_debug_section,(abfd),
+ bfd *abfd)
+{
+ char *debug_section;
+ long position;
+
+ asection *sect = bfd_get_section_by_name (abfd, ".debug");
+
+ if (!sect) {
+ bfd_error = no_debug_section;
+ return NULL;
+ }
+
+ debug_section = (PTR) bfd_alloc (abfd,
+ bfd_get_section_size_before_reloc (sect));
+ if (debug_section == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ /* Seek to the beginning of the `.debug' section and read it.
+ Save the current position first; it is needed by our caller.
+ Then read debug section and reset the file pointer. */
+
+ position = bfd_tell (abfd);
+ bfd_seek (abfd, sect->filepos, SEEK_SET);
+ if (bfd_read (debug_section,
+ bfd_get_section_size_before_reloc (sect), 1, abfd)
+ != bfd_get_section_size_before_reloc(sect)) {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ bfd_seek (abfd, position, SEEK_SET);
+ return debug_section;
+}
+
+
+/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be
+ \0-terminated, but will not exceed 'maxlen' characters. The copy *will*
+ be \0-terminated. */
+static char *
+DEFUN(copy_name,(abfd, name, maxlen),
+ bfd *abfd AND
+ char *name AND
+ int maxlen)
+{
+ int len;
+ char *newname;
+
+ for (len = 0; len < maxlen; ++len) {
+ if (name[len] == '\0') {
+ break;
+ }
+ }
+
+ if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) {
+ bfd_error = no_memory;
+ return (NULL);
+ }
+ strncpy(newname, name, len);
+ newname[len] = '\0';
+ return newname;
+}
+
+/* Read a symbol table into freshly bfd_allocated memory, swap it, and
+ knit the symbol names into a normalized form. By normalized here I
+ mean that all symbols have an n_offset pointer that points to a null-
+ terminated string. */
+
+combined_entry_type *
+DEFUN(coff_get_normalized_symtab,(abfd),
+bfd *abfd)
+{
+ combined_entry_type *internal;
+ combined_entry_type *internal_ptr;
+ combined_entry_type *symbol_ptr;
+ combined_entry_type *internal_end;
+ bfd_size_type symesz;
+ PTR raw;
+ char *raw_src;
+ char *raw_end;
+ char *string_table = NULL;
+ char *debug_section = NULL;
+ unsigned long size;
+
+ unsigned int raw_size;
+ if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) {
+ return obj_raw_syments(abfd);
+ }
+ if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) {
+ bfd_error = no_symbols;
+ return (NULL);
+ }
+
+ internal = (combined_entry_type *)bfd_alloc(abfd, size);
+ internal_end = internal + bfd_get_symcount(abfd);
+
+ symesz = bfd_coff_symesz (abfd);
+ raw_size = bfd_get_symcount(abfd) * symesz;
+ raw = bfd_alloc(abfd,raw_size);
+
+ if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1
+ || bfd_read(raw, raw_size, 1, abfd) != raw_size) {
+ bfd_error = system_call_error;
+ return (NULL);
+ }
+ /* mark the end of the symbols */
+ raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz;
+ /*
+ FIXME SOMEDAY. A string table size of zero is very weird, but
+ probably possible. If one shows up, it will probably kill us.
+ */
+
+ /* Swap all the raw entries */
+ for (raw_src = (char *) raw, internal_ptr = internal;
+ raw_src < raw_end;
+ raw_src += symesz, internal_ptr++) {
+
+ unsigned int i;
+ bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment);
+ internal_ptr->fix_tag = 0;
+ internal_ptr->fix_end = 0;
+ symbol_ptr = internal_ptr;
+
+ for (i = 0;
+ i < symbol_ptr->u.syment.n_numaux;
+ i++)
+ {
+ internal_ptr++;
+ raw_src += symesz;
+
+ internal_ptr->fix_tag = 0;
+ internal_ptr->fix_end = 0;
+ bfd_coff_swap_aux_in(abfd, (PTR) raw_src,
+ symbol_ptr->u.syment.n_type,
+ symbol_ptr->u.syment.n_sclass,
+ &(internal_ptr->u.auxent));
+ /* Remember that bal entries arn't pointerized */
+ if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC)
+ {
+
+ coff_pointerize_aux(abfd,
+ internal,
+ symbol_ptr->u.syment.n_type,
+ symbol_ptr->u.syment.n_sclass,
+ internal_ptr);
+ }
+
+ }
+ }
+
+ /* Free all the raw stuff */
+ bfd_release(abfd, raw);
+
+ for (internal_ptr = internal; internal_ptr < internal_end;
+ internal_ptr ++)
+ {
+ if (internal_ptr->u.syment.n_sclass == C_FILE) {
+ /* make a file symbol point to the name in the auxent, since
+ the text ".file" is redundant */
+ if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) {
+ /* the filename is a long one, point into the string table */
+ if (string_table == NULL) {
+ string_table = build_string_table(abfd);
+ }
+
+ internal_ptr->u.syment._n._n_n._n_offset =
+ (long) (string_table - 4 +
+ (internal_ptr+1)->u.auxent.x_file.x_n.x_offset);
+ }
+ else {
+ /* ordinary short filename, put into memory anyway */
+ internal_ptr->u.syment._n._n_n._n_offset = (long)
+ copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname,
+ FILNMLEN);
+ }
+ }
+ else {
+ if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) {
+ /* This is a "short" name. Make it long. */
+ unsigned long i = 0;
+ char *newstring = NULL;
+
+ /* find the length of this string without walking into memory
+ that isn't ours. */
+ for (i = 0; i < 8; ++i) {
+ if (internal_ptr->u.syment._n._n_name[i] == '\0') {
+ break;
+ } /* if end of string */
+ } /* possible lengths of this string. */
+
+ if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) {
+ bfd_error = no_memory;
+ return (NULL);
+ } /* on error */
+ memset(newstring, 0, i);
+ strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1);
+ internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring;
+ internal_ptr->u.syment._n._n_n._n_zeroes = 0;
+ }
+ else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) {
+ /* Long name already. Point symbol at the string in the table. */
+ if (string_table == NULL) {
+ string_table = build_string_table(abfd);
+ }
+ internal_ptr->u.syment._n._n_n._n_offset = (long int)
+ (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset);
+ }
+ else {
+ /* Long name in debug section. Very similar. */
+ if (debug_section == NULL) {
+ debug_section = build_debug_section(abfd);
+ }
+ internal_ptr->u.syment._n._n_n._n_offset = (long int)
+ (debug_section + internal_ptr->u.syment._n._n_n._n_offset);
+ }
+ }
+ internal_ptr += internal_ptr->u.syment.n_numaux;
+ }
+
+ obj_raw_syments(abfd) = internal;
+ obj_raw_syment_count(abfd) = internal_ptr - internal;
+
+ return (internal);
+} /* coff_get_normalized_symtab() */
+
+unsigned int
+DEFUN (coff_get_reloc_upper_bound, (abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (bfd_get_format(abfd) != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ return (asect->reloc_count + 1) * sizeof(arelent *);
+}
+
+asymbol *
+DEFUN (coff_make_empty_symbol, (abfd),
+ bfd *abfd)
+{
+ coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
+ if (new == NULL) {
+ bfd_error = no_memory;
+ return (NULL);
+ } /* on error */
+ new->symbol.section = 0;
+ new->native = 0;
+ new->lineno = (alent *) NULL;
+ new->done_lineno = false;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+/* Make a debugging symbol. */
+
+asymbol *
+coff_bfd_make_debug_symbol (abfd, ptr, sz)
+ bfd *abfd;
+ PTR ptr;
+ unsigned long sz;
+{
+ coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
+ if (new == NULL) {
+ bfd_error = no_memory;
+ return (NULL);
+ } /* on error */
+ /* @@ This shouldn't be using a constant multiplier. */
+ new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10);
+ new->symbol.section = &bfd_debug_section;
+ new->lineno = (alent *) NULL;
+ new->done_lineno = false;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+void
+coff_get_symbol_info (abfd, symbol, ret)
+ bfd *abfd;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/* Print out information about COFF symbol. */
+
+void
+coff_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ FILE *file = (FILE *) filep;
+
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+
+ case bfd_print_symbol_more:
+ fprintf (file, "coff %s %s",
+ coffsymbol(symbol)->native ? "n" : "g",
+ coffsymbol(symbol)->lineno ? "l" : " ");
+ break;
+
+ case bfd_print_symbol_all:
+ if (coffsymbol(symbol)->native)
+ {
+ unsigned int aux;
+ combined_entry_type *combined = coffsymbol (symbol)->native;
+ combined_entry_type *root = obj_raw_syments (abfd);
+ struct lineno_cache_entry *l = coffsymbol(symbol)->lineno;
+
+ fprintf (file,"[%3d]", combined - root);
+
+ fprintf (file,
+ "(sc %2d)(fl 0x%02x)(ty %3x)(sc %3d) (nx %d) 0x%08x %s",
+ combined->u.syment.n_scnum,
+ combined->u.syment.n_flags,
+ combined->u.syment.n_type,
+ combined->u.syment.n_sclass,
+ combined->u.syment.n_numaux,
+ combined->u.syment.n_value,
+ symbol->name);
+
+ for (aux = 0; aux < combined->u.syment.n_numaux; aux++)
+ {
+ combined_entry_type *auxp = combined + aux + 1;
+ long tagndx;
+
+ if (auxp->fix_tag)
+ tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root;
+ else
+ tagndx = auxp->u.auxent.x_sym.x_tagndx.l;
+
+ fprintf (file, "\n");
+ switch (combined->u.syment.n_sclass)
+ {
+ case C_FILE:
+ fprintf (file, "File ");
+ break;
+ default:
+
+ fprintf (file, "AUX lnno %d size 0x%x tagndx %d",
+ auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno,
+ auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size,
+ tagndx);
+ break;
+ }
+ }
+
+ if (l)
+ {
+ fprintf (file, "\n%s :", l->u.sym->name);
+ l++;
+ while (l->line_number)
+ {
+ fprintf (file, "\n%4d : 0x%x",
+ l->line_number,
+ l->u.offset + symbol->section->vma);
+ l++;
+ }
+ }
+ }
+ else
+ {
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ fprintf (file, " %-5s %s %s %s",
+ symbol->section->name,
+ coffsymbol(symbol)->native ? "n" : "g",
+ coffsymbol(symbol)->lineno ? "l" : " ",
+ symbol->name);
+ }
+ }
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location. */
+
+boolean
+DEFUN(coff_find_nearest_line,(abfd,
+ section,
+ ignore_symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **ignore_symbols AND
+ bfd_vma offset AND
+ CONST char **filename_ptr AND
+ CONST char **functionname_ptr AND
+ unsigned int *line_ptr)
+{
+ static bfd *cache_abfd;
+ static asection *cache_section;
+ static bfd_vma cache_offset;
+ static unsigned int cache_i;
+ static CONST char *cache_function;
+ static unsigned int line_base = 0;
+
+ unsigned int i = 0;
+ coff_data_type *cof = coff_data(abfd);
+ /* Run through the raw syments if available */
+ combined_entry_type *p;
+ alent *l;
+
+
+ *filename_ptr = 0;
+ *functionname_ptr = 0;
+ *line_ptr = 0;
+
+ /* Don't try and find line numbers in a non coff file */
+ if (abfd->xvec->flavour != bfd_target_coff_flavour)
+ return false;
+
+ if (cof == NULL)
+ return false;
+
+ p = cof->raw_syments;
+
+ for (i = 0; i < cof->raw_syment_count; i++) {
+ if (p->u.syment.n_sclass == C_FILE) {
+ /* File name has been moved into symbol */
+ *filename_ptr = (char *) p->u.syment._n._n_n._n_offset;
+ break;
+ }
+ p += 1 + p->u.syment.n_numaux;
+ }
+ /* Now wander though the raw linenumbers of the section */
+ /*
+ If this is the same BFD as we were previously called with and this is
+ the same section, and the offset we want is further down then we can
+ prime the lookup loop
+ */
+ if (abfd == cache_abfd &&
+ section == cache_section &&
+ offset >= cache_offset) {
+ i = cache_i;
+ *functionname_ptr = cache_function;
+ }
+ else {
+ i = 0;
+ }
+ l = &section->lineno[i];
+
+ for (; i < section->lineno_count; i++) {
+ if (l->line_number == 0) {
+ /* Get the symbol this line number points at */
+ coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
+ if (coff->symbol.value > offset)
+ break;
+ *functionname_ptr = coff->symbol.name;
+ if (coff->native) {
+ combined_entry_type *s = coff->native;
+ s = s + 1 + s->u.syment.n_numaux;
+ /*
+ S should now point to the .bf of the function
+ */
+ if (s->u.syment.n_numaux) {
+ /*
+ The linenumber is stored in the auxent
+ */
+ union internal_auxent *a = &((s + 1)->u.auxent);
+ line_base = a->x_sym.x_misc.x_lnsz.x_lnno;
+ *line_ptr = line_base;
+ }
+ }
+ }
+ else {
+ if (l->u.offset > offset)
+ break;
+ *line_ptr = l->line_number + line_base - 1;
+ }
+ l++;
+ }
+
+ cache_abfd = abfd;
+ cache_section = section;
+ cache_offset = offset;
+ cache_i = i;
+ cache_function = *functionname_ptr;
+
+ return true;
+}
+
+int
+DEFUN(coff_sizeof_headers,(abfd, reloc),
+ bfd *abfd AND
+ boolean reloc)
+{
+ size_t size;
+
+ if (reloc == false) {
+ size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd);
+ }
+ else {
+ size = bfd_coff_filhsz (abfd);
+ }
+
+ size += abfd->section_count * bfd_coff_scnhsz (abfd);
+ return size;
+}
diff --git a/gnu/usr.bin/gdb/bfd/core.c b/gnu/usr.bin/gdb/bfd/core.c
new file mode 100644
index 000000000000..c428775fbf3f
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/core.c
@@ -0,0 +1,106 @@
+/* Core file generic interface routines for BFD.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Core files
+
+DESCRIPTION
+ Buff output this facinating topic
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+FUNCTION
+ bfd_core_file_failing_command
+
+SYNOPSIS
+ CONST char *bfd_core_file_failing_command(bfd *);
+
+DESCRIPTION
+ Returns a read-only string explaining what program was running
+ when it failed and produced the core file being read
+
+*/
+
+CONST char *
+DEFUN(bfd_core_file_failing_command,(abfd),
+ bfd *abfd)
+{
+ if (abfd->format != bfd_core) {
+ bfd_error = invalid_operation;
+ return NULL;
+ }
+ return BFD_SEND (abfd, _core_file_failing_command, (abfd));
+}
+
+/*
+FUNCTION
+ bfd_core_file_failing_signal
+
+SYNOPSIS
+ int bfd_core_file_failing_signal(bfd *);
+
+DESCRIPTION
+ Returns the signal number which caused the core dump which
+ generated the file the BFD is attached to.
+*/
+
+int
+bfd_core_file_failing_signal (abfd)
+ bfd *abfd;
+{
+ if (abfd->format != bfd_core) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ return BFD_SEND (abfd, _core_file_failing_signal, (abfd));
+}
+
+
+/*
+FUNCTION
+ core_file_matches_executable_p
+
+SYNOPSIS
+ boolean core_file_matches_executable_p
+ (bfd *core_bfd, bfd *exec_bfd);
+
+DESCRIPTION
+ Returns <<true>> if the core file attached to @var{core_bfd}
+ was generated by a run of the executable file attached to
+ @var{exec_bfd}, or else <<false>>.
+*/
+boolean
+core_file_matches_executable_p (core_bfd, exec_bfd)
+ bfd *core_bfd, *exec_bfd;
+{
+ if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) {
+ bfd_error = wrong_format;
+ return false;
+ }
+
+ return BFD_SEND (core_bfd, _core_file_matches_executable_p,
+ (core_bfd, exec_bfd));
+}
diff --git a/gnu/usr.bin/gdb/bfd/cpu-i386.c b/gnu/usr.bin/gdb/bfd/cpu-i386.c
new file mode 100644
index 000000000000..b4afdb2392bb
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cpu-i386.c
@@ -0,0 +1,43 @@
+/* BFD support for the Intel 386 architecture.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+static bfd_arch_info_type arch_info_struct =
+ {
+ 32, /* 32 bits in a word */
+ 32, /* 32 bits in an address */
+ 8, /* 8 bits in a byte */
+ bfd_arch_i386,
+ 0, /* only 1 machine */
+ "i386",
+ "i386",
+ 3,
+ true, /* the one and only */
+ bfd_default_compatible,
+ bfd_default_scan ,
+ 0,
+ };
+
+void DEFUN_VOID(bfd_i386_arch)
+{
+ bfd_arch_linkin(&arch_info_struct);
+}
diff --git a/gnu/usr.bin/gdb/bfd/ctor.c b/gnu/usr.bin/gdb/bfd/ctor.c
new file mode 100644
index 000000000000..adc69195ff6a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ctor.c
@@ -0,0 +1,148 @@
+/* BFD library support routines for constructors
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+
+ Hacked by Steve Chamberlain of Cygnus Support. With some help from
+ Judy Chamberlain too.
+
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Constructors
+
+ Classes in C++ have `constructors' and `destructors'. These
+ are functions which are called automatically by the language
+ whenever data of a class is created or destroyed. Class data
+ which is static data may also be have a type which requires
+ `construction', the contructor must be called before the data
+ can be referenced, so the contructor must be called before the
+ program begins.
+
+ The common solution to this problem is for the compiler to
+ call a magic function as the first statement <<main>>.
+ This magic function, (often called <<__main>>) runs around
+ calling the constructors for all the things needing it.
+
+ With COFF the compile has a bargain with the linker et al.
+ All constructors are given strange names, for example
+ <<__GLOBAL__$I$foo>> might be the label of a contructor for
+ the class @var{foo}. The solution on unfortunate systems
+ (most system V machines) is to perform a partial link on all
+ the <<.o>> files, do an <<nm>> on the result, run <<awk>> or some
+ such over the result looking for strange <<__GLOBAL__$>>
+ symbols, generate a C program from this, compile it and link
+ with the partially linked input. This process is usually
+ called <<collect>>.
+
+ Some versions of <<a.out>> use something called the
+ <<set_vector>> mechanism. The constructor symbols are output
+ from the compiler with a special stab code saying that they
+ are constructors, and the linker can deal with them directly.
+
+ BFD allows applications (ie the linker) to deal with
+ constructor information independently of their external
+ implimentation by providing a set of entry points for the
+ indiviual object back ends to call which maintains a database
+ of the contructor information. The application can
+ interrogate the database to find out what it wants. The
+ construction data essential for the linker to be able to
+ perform its job are:
+
+ o asymbol -
+ The asymbol of the contructor entry point contains all the
+ information necessary to call the function.
+
+ o table id -
+ The type of symbol, i.e., is it a constructor, a destructor or
+ something else someone dreamed up to make our lives difficult.
+
+ This module takes this information and then builds extra
+ sections attached to the bfds which own the entry points. It
+ creates these sections as if they were tables of pointers to
+ the entry points, and builds relocation entries to go with
+ them so that the tables can be relocated along with the data
+ they reference.
+
+ These sections are marked with a special bit
+ (<<SEC_CONSTRUCTOR>>) which the linker notices and do with
+ what it wants.
+
+*/
+
+#include <bfd.h>
+#include <sysdep.h>
+#include <libbfd.h>
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_constructor_entry
+
+SYNOPSIS
+ void bfd_constructor_entry(bfd *abfd,
+ asymbol **symbol_ptr_ptr,
+ CONST char*type);
+
+
+DESCRIPTION
+ This function is called with an a symbol describing the
+ function to be called, an string which descibes the xtor type,
+ e.g., something like "CTOR" or "DTOR" would be fine. And the bfd
+ which owns the function. Its duty is to create a section
+ called "CTOR" or "DTOR" or whatever if the bfd doesn't already
+ have one, and grow a relocation table for the entry points as
+ they accumulate.
+
+*/
+
+
+void DEFUN(bfd_constructor_entry,(abfd, symbol_ptr_ptr, type),
+ bfd *abfd AND
+ asymbol **symbol_ptr_ptr AND
+ CONST char *type)
+
+{
+ /* Look up the section we're using to store the table in */
+ asection *rel_section = bfd_get_section_by_name (abfd, type);
+ if (rel_section == (asection *)NULL) {
+ rel_section = bfd_make_section (abfd, type);
+ rel_section->flags = SEC_CONSTRUCTOR;
+ rel_section->alignment_power = 2;
+ }
+
+ /* Create a relocation into the section which references the entry
+ point */
+ {
+ arelent_chain *reloc = (arelent_chain *)bfd_alloc(abfd,
+ sizeof(arelent_chain));
+
+/* reloc->relent.section = (asection *)NULL;*/
+ reloc->relent.addend = 0;
+
+ reloc->relent.sym_ptr_ptr = symbol_ptr_ptr;
+ reloc->next = rel_section->constructor_chain;
+ rel_section->constructor_chain = reloc;
+ reloc->relent.address = rel_section->_cooked_size;
+ /* ask the cpu which howto to use */
+ reloc->relent.howto = bfd_reloc_type_lookup(abfd, BFD_RELOC_CTOR);
+ rel_section->_cooked_size += sizeof(int *);
+ rel_section->reloc_count++;
+ }
+
+}
diff --git a/gnu/usr.bin/gdb/bfd/ecoff.c b/gnu/usr.bin/gdb/bfd/ecoff.c
new file mode 100644
index 000000000000..e3b7c937aa05
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ecoff.c
@@ -0,0 +1,3994 @@
+/* Generic ECOFF (Extended-COFF) routines.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Original version by Per Bothner.
+ Full support added by Ian Lance Taylor, ian@cygnus.com.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "seclet.h"
+#include "aout/ar.h"
+#include "aout/ranlib.h"
+
+/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
+ some other stuff which we don't want and which conflicts with stuff
+ we do want. */
+#include "libaout.h"
+#include "aout/aout64.h"
+#undef N_ABS
+#undef exec_hdr
+#undef obj_sym_filepos
+
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+#include "coff/ecoff.h"
+#include "libcoff.h"
+#include "libecoff.h"
+
+/* Prototypes for static functions. */
+
+static int ecoff_get_magic PARAMS ((bfd *abfd));
+static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
+ asymbol *asym, int ext,
+ asymbol **indirect_ptr_ptr));
+static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string,
+ RNDXR *rndx, long isym,
+ CONST char *which));
+static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr,
+ unsigned int indx, int bigendian));
+static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
+ asymbol **symbols));
+static void ecoff_clear_output_flags PARAMS ((bfd *abfd));
+static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet,
+ asection *output_section, PTR data,
+ boolean relocateable));
+static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet,
+ asection *section, PTR data,
+ boolean relocateable));
+static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr,
+ CONST char *string, boolean external));
+static boolean ecoff_get_debug PARAMS ((bfd *output_bfd,
+ bfd_seclet_type *seclet,
+ asection *section,
+ boolean relocateable));
+static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
+static unsigned int ecoff_armap_hash PARAMS ((CONST char *s,
+ unsigned int *rehash,
+ unsigned int size,
+ unsigned int hlog));
+
+/* This stuff is somewhat copied from coffcode.h. */
+
+static asection bfd_debug_section = { "*DEBUG*" };
+
+/* Create an ECOFF object. */
+
+boolean
+ecoff_mkobject (abfd)
+ bfd *abfd;
+{
+ abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
+ bfd_zalloc (abfd, sizeof (ecoff_data_type)));
+ if (abfd->tdata.ecoff_obj_data == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ /* Always create a .scommon section for every BFD. This is a hack so
+ that the linker has something to attach scSCommon symbols to. */
+ if (bfd_make_section (abfd, SCOMMON) == NULL)
+ return false;
+
+ return true;
+}
+
+/* This is a hook called by coff_real_object_p to create any backend
+ specific information. */
+
+PTR
+ecoff_mkobject_hook (abfd, filehdr, aouthdr)
+ bfd *abfd;
+ PTR filehdr;
+ PTR aouthdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
+ ecoff_data_type *ecoff;
+ asection *regsec;
+
+ if (ecoff_mkobject (abfd) == false)
+ return NULL;
+
+ ecoff = ecoff_data (abfd);
+ ecoff->gp_size = 8;
+ ecoff->sym_filepos = internal_f->f_symptr;
+
+ /* Create the .reginfo section to give programs outside BFD a way to
+ see the information stored in the a.out header. See the comment
+ in coff/ecoff.h. */
+ regsec = bfd_make_section (abfd, REGINFO);
+ if (regsec == NULL)
+ return NULL;
+
+ if (internal_a != (struct internal_aouthdr *) NULL)
+ {
+ int i;
+
+ ecoff->text_start = internal_a->text_start;
+ ecoff->text_end = internal_a->text_start + internal_a->tsize;
+ ecoff->gp = internal_a->gp_value;
+ ecoff->gprmask = internal_a->gprmask;
+ for (i = 0; i < 4; i++)
+ ecoff->cprmask[i] = internal_a->cprmask[i];
+ ecoff->fprmask = internal_a->fprmask;
+ if (internal_a->magic == ECOFF_AOUT_ZMAGIC)
+ abfd->flags |= D_PAGED;
+ }
+
+ /* It turns out that no special action is required by the MIPS or
+ Alpha ECOFF backends. They have different information in the
+ a.out header, but we just copy it all (e.g., gprmask, cprmask and
+ fprmask) and let the swapping routines ensure that only relevant
+ information is written out. */
+
+ return (PTR) ecoff;
+}
+
+/* This is a hook needed by SCO COFF, but we have nothing to do. */
+
+asection *
+ecoff_make_section_hook (abfd, name)
+ bfd *abfd;
+ char *name;
+{
+ return (asection *) NULL;
+}
+
+/* Initialize a new section. */
+
+boolean
+ecoff_new_section_hook (abfd, section)
+ bfd *abfd;
+ asection *section;
+{
+ section->alignment_power = abfd->xvec->align_power_min;
+
+ if (strcmp (section->name, _TEXT) == 0)
+ section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+ else if (strcmp (section->name, _DATA) == 0
+ || strcmp (section->name, _SDATA) == 0)
+ section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ else if (strcmp (section->name, _RDATA) == 0
+ || strcmp (section->name, _LIT8) == 0
+ || strcmp (section->name, _LIT4) == 0)
+ section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+ else if (strcmp (section->name, _BSS) == 0
+ || strcmp (section->name, _SBSS) == 0)
+ section->flags |= SEC_ALLOC;
+ else if (strcmp (section->name, REGINFO) == 0)
+ {
+ section->flags |= SEC_HAS_CONTENTS | SEC_NEVER_LOAD;
+ section->_raw_size = sizeof (struct ecoff_reginfo);
+ }
+
+ /* Probably any other section name is SEC_NEVER_LOAD, but I'm
+ uncertain about .init on some systems and I don't know how shared
+ libraries work. */
+
+ return true;
+}
+
+/* Determine the machine architecture and type. This is called from
+ the generic COFF routines. It is the inverse of ecoff_get_magic,
+ below. This could be an ECOFF backend routine, with one version
+ for each target, but there aren't all that many ECOFF targets. */
+
+boolean
+ecoff_set_arch_mach_hook (abfd, filehdr)
+ bfd *abfd;
+ PTR filehdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ enum bfd_architecture arch;
+ unsigned long mach;
+
+ switch (internal_f->f_magic)
+ {
+ case MIPS_MAGIC_1:
+ case MIPS_MAGIC_LITTLE:
+ case MIPS_MAGIC_BIG:
+ arch = bfd_arch_mips;
+ mach = 3000;
+ break;
+
+ case MIPS_MAGIC_LITTLE2:
+ case MIPS_MAGIC_BIG2:
+ /* MIPS ISA level 2: the r6000 */
+ arch = bfd_arch_mips;
+ mach = 6000;
+ break;
+
+ case MIPS_MAGIC_LITTLE3:
+ case MIPS_MAGIC_BIG3:
+ /* MIPS ISA level 3: the r4000 */
+ arch = bfd_arch_mips;
+ mach = 4000;
+ break;
+
+ case ALPHA_MAGIC:
+ arch = bfd_arch_alpha;
+ mach = 0;
+ break;
+
+ default:
+ arch = bfd_arch_obscure;
+ mach = 0;
+ break;
+ }
+
+ return bfd_default_set_arch_mach (abfd, arch, mach);
+}
+
+/* Get the magic number to use based on the architecture and machine.
+ This is the inverse of ecoff_set_arch_mach_hook, above. */
+
+static int
+ecoff_get_magic (abfd)
+ bfd *abfd;
+{
+ int big, little;
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_mips:
+ switch (bfd_get_mach (abfd))
+ {
+ default:
+ case 0:
+ case 3000:
+ big = MIPS_MAGIC_BIG;
+ little = MIPS_MAGIC_LITTLE;
+ break;
+
+ case 6000:
+ big = MIPS_MAGIC_BIG2;
+ little = MIPS_MAGIC_LITTLE2;
+ break;
+
+ case 4000:
+ big = MIPS_MAGIC_BIG3;
+ little = MIPS_MAGIC_LITTLE3;
+ break;
+ }
+
+ return abfd->xvec->byteorder_big_p ? big : little;
+
+ case bfd_arch_alpha:
+ return ALPHA_MAGIC;
+
+ default:
+ abort ();
+ return 0;
+ }
+}
+
+/* Get the section s_flags to use for a section. */
+
+long
+ecoff_sec_to_styp_flags (name, flags)
+ CONST char *name;
+ flagword flags;
+{
+ long styp;
+
+ styp = 0;
+
+ if (strcmp (name, _TEXT) == 0)
+ styp = STYP_TEXT;
+ else if (strcmp (name, _DATA) == 0)
+ styp = STYP_DATA;
+ else if (strcmp (name, _SDATA) == 0)
+ styp = STYP_SDATA;
+ else if (strcmp (name, _RDATA) == 0)
+ styp = STYP_RDATA;
+ else if (strcmp (name, _LIT8) == 0)
+ styp = STYP_LIT8;
+ else if (strcmp (name, _LIT4) == 0)
+ styp = STYP_LIT4;
+ else if (strcmp (name, _BSS) == 0)
+ styp = STYP_BSS;
+ else if (strcmp (name, _SBSS) == 0)
+ styp = STYP_SBSS;
+ else if (strcmp (name, _INIT) == 0)
+ styp = STYP_ECOFF_INIT;
+ else if (strcmp (name, _FINI) == 0)
+ styp = STYP_ECOFF_FINI;
+ else if (flags & SEC_CODE)
+ styp = STYP_TEXT;
+ else if (flags & SEC_DATA)
+ styp = STYP_DATA;
+ else if (flags & SEC_READONLY)
+ styp = STYP_RDATA;
+ else if (flags & SEC_LOAD)
+ styp = STYP_REG;
+ else
+ styp = STYP_BSS;
+
+ if (flags & SEC_NEVER_LOAD)
+ styp |= STYP_NOLOAD;
+
+ return styp;
+}
+
+/* Get the BFD flags to use for a section. */
+
+flagword
+ecoff_styp_to_sec_flags (abfd, hdr)
+ bfd *abfd;
+ PTR hdr;
+{
+ struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
+ long styp_flags = internal_s->s_flags;
+ flagword sec_flags=0;
+
+ if (styp_flags & STYP_NOLOAD)
+ sec_flags |= SEC_NEVER_LOAD;
+
+ /* For 386 COFF, at least, an unloadable text or data section is
+ actually a shared library section. */
+ if ((styp_flags & STYP_TEXT)
+ || (styp_flags & STYP_ECOFF_INIT)
+ || (styp_flags & STYP_ECOFF_FINI))
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_CODE | SEC_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+ }
+ else if ((styp_flags & STYP_DATA)
+ || (styp_flags & STYP_RDATA)
+ || (styp_flags & STYP_SDATA))
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ if (styp_flags & STYP_RDATA)
+ sec_flags |= SEC_READONLY;
+ }
+ else if ((styp_flags & STYP_BSS)
+ || (styp_flags & STYP_SBSS))
+ {
+ sec_flags |= SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_INFO)
+ {
+ sec_flags |= SEC_NEVER_LOAD;
+ }
+ else if ((styp_flags & STYP_LIT8)
+ || (styp_flags & STYP_LIT4))
+ {
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+ }
+ else
+ {
+ sec_flags |= SEC_ALLOC | SEC_LOAD;
+ }
+
+ return sec_flags;
+}
+
+/* Routines to swap auxiliary information in and out. I am assuming
+ that the auxiliary information format is always going to be target
+ independent. */
+
+/* Swap in a type information record.
+ BIGEND says whether AUX symbols are big-endian or little-endian; this
+ info comes from the file header record (fh-fBigendian). */
+
+void
+ecoff_swap_tir_in (bigend, ext_copy, intern)
+ int bigend;
+ struct tir_ext *ext_copy;
+ TIR *intern;
+{
+ struct tir_ext ext[1];
+
+ *ext = *ext_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
+ intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
+ intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
+ >> TIR_BITS1_BT_SH_BIG;
+ intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
+ >> TIR_BITS_TQ4_SH_BIG;
+ intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
+ >> TIR_BITS_TQ5_SH_BIG;
+ intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
+ >> TIR_BITS_TQ0_SH_BIG;
+ intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
+ >> TIR_BITS_TQ1_SH_BIG;
+ intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
+ >> TIR_BITS_TQ2_SH_BIG;
+ intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
+ >> TIR_BITS_TQ3_SH_BIG;
+ } else {
+ intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
+ intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
+ intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
+ >> TIR_BITS1_BT_SH_LITTLE;
+ intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
+ >> TIR_BITS_TQ4_SH_LITTLE;
+ intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
+ >> TIR_BITS_TQ5_SH_LITTLE;
+ intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
+ >> TIR_BITS_TQ0_SH_LITTLE;
+ intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
+ >> TIR_BITS_TQ1_SH_LITTLE;
+ intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
+ >> TIR_BITS_TQ2_SH_LITTLE;
+ intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
+ >> TIR_BITS_TQ3_SH_LITTLE;
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap out a type information record.
+ BIGEND says whether AUX symbols are big-endian or little-endian; this
+ info comes from the file header record (fh-fBigendian). */
+
+void
+ecoff_swap_tir_out (bigend, intern_copy, ext)
+ int bigend;
+ TIR *intern_copy;
+ struct tir_ext *ext;
+{
+ TIR intern[1];
+
+ *intern = *intern_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
+ | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
+ | ((intern->bt << TIR_BITS1_BT_SH_BIG)
+ & TIR_BITS1_BT_BIG));
+ ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
+ & TIR_BITS_TQ4_BIG)
+ | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
+ & TIR_BITS_TQ5_BIG));
+ ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
+ & TIR_BITS_TQ0_BIG)
+ | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
+ & TIR_BITS_TQ1_BIG));
+ ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
+ & TIR_BITS_TQ2_BIG)
+ | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
+ & TIR_BITS_TQ3_BIG));
+ } else {
+ ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
+ | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
+ | ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
+ & TIR_BITS1_BT_LITTLE));
+ ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
+ & TIR_BITS_TQ4_LITTLE)
+ | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
+ & TIR_BITS_TQ5_LITTLE));
+ ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
+ & TIR_BITS_TQ0_LITTLE)
+ | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
+ & TIR_BITS_TQ1_LITTLE));
+ ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
+ & TIR_BITS_TQ2_LITTLE)
+ | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
+ & TIR_BITS_TQ3_LITTLE));
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap in a relative symbol record. BIGEND says whether it is in
+ big-endian or little-endian format.*/
+
+void
+ecoff_swap_rndx_in (bigend, ext_copy, intern)
+ int bigend;
+ struct rndx_ext *ext_copy;
+ RNDXR *intern;
+{
+ struct rndx_ext ext[1];
+
+ *ext = *ext_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
+ | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
+ >> RNDX_BITS1_RFD_SH_BIG);
+ intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
+ << RNDX_BITS1_INDEX_SH_LEFT_BIG)
+ | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
+ | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
+ } else {
+ intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
+ | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
+ << RNDX_BITS1_RFD_SH_LEFT_LITTLE);
+ intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
+ >> RNDX_BITS1_INDEX_SH_LITTLE)
+ | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
+ | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap out a relative symbol record. BIGEND says whether it is in
+ big-endian or little-endian format.*/
+
+void
+ecoff_swap_rndx_out (bigend, intern_copy, ext)
+ int bigend;
+ RNDXR *intern_copy;
+ struct rndx_ext *ext;
+{
+ RNDXR intern[1];
+
+ *intern = *intern_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
+ ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
+ & RNDX_BITS1_RFD_BIG)
+ | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
+ & RNDX_BITS1_INDEX_BIG));
+ ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
+ ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
+ } else {
+ ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
+ ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
+ & RNDX_BITS1_RFD_LITTLE)
+ | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
+ & RNDX_BITS1_INDEX_LITTLE));
+ ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
+ ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Read in and swap the important symbolic information for an ECOFF
+ object file. This is called by gdb. */
+
+boolean
+ecoff_slurp_symbolic_info (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ bfd_size_type external_hdr_size;
+ HDRR *internal_symhdr;
+ bfd_size_type raw_base;
+ bfd_size_type raw_size;
+ PTR raw;
+ bfd_size_type external_fdr_size;
+ char *fraw_src;
+ char *fraw_end;
+ struct fdr *fdr_ptr;
+ bfd_size_type raw_end;
+ bfd_size_type cb_end;
+
+ /* Check whether we've already gotten it, and whether there's any to
+ get. */
+ if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
+ return true;
+ if (ecoff_data (abfd)->sym_filepos == 0)
+ {
+ bfd_get_symcount (abfd) = 0;
+ return true;
+ }
+
+ /* At this point bfd_get_symcount (abfd) holds the number of symbols
+ as read from the file header, but on ECOFF this is always the
+ size of the symbolic information header. It would be cleaner to
+ handle this when we first read the file in coffgen.c. */
+ external_hdr_size = backend->external_hdr_size;
+ if (bfd_get_symcount (abfd) != external_hdr_size)
+ {
+ bfd_error = bad_value;
+ return false;
+ }
+
+ /* Read the symbolic information header. */
+ raw = (PTR) alloca (external_hdr_size);
+ if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
+ || (bfd_read (raw, external_hdr_size, 1, abfd)
+ != external_hdr_size))
+ {
+ bfd_error = system_call_error;
+ return false;
+ }
+ internal_symhdr = &ecoff_data (abfd)->symbolic_header;
+ (*backend->swap_hdr_in) (abfd, raw, internal_symhdr);
+
+ if (internal_symhdr->magic != backend->sym_magic)
+ {
+ bfd_error = bad_value;
+ return false;
+ }
+
+ /* Now we can get the correct number of symbols. */
+ bfd_get_symcount (abfd) = (internal_symhdr->isymMax
+ + internal_symhdr->iextMax);
+
+ /* Read all the symbolic information at once. */
+ raw_base = ecoff_data (abfd)->sym_filepos + external_hdr_size;
+
+ /* Alpha ecoff makes the determination of raw_size difficult. It has
+ an undocumented debug data section between the symhdr and the first
+ documented section. And the ordering of the sections varies between
+ statically and dynamically linked executables.
+ If bfd supports SEEK_END someday, this code could be simplified. */
+
+ raw_end = 0;
+
+#define UPDATE_RAW_END(start, count, size) \
+ cb_end = internal_symhdr->start + internal_symhdr->count * (size); \
+ if (cb_end > raw_end) \
+ raw_end = cb_end
+
+ UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char));
+ UPDATE_RAW_END (cbDnOffset, idnMax, backend->external_dnr_size);
+ UPDATE_RAW_END (cbPdOffset, ipdMax, backend->external_pdr_size);
+ UPDATE_RAW_END (cbSymOffset, isymMax, backend->external_sym_size);
+ UPDATE_RAW_END (cbOptOffset, ioptMax, backend->external_opt_size);
+ UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext));
+ UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char));
+ UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char));
+ UPDATE_RAW_END (cbFdOffset, ifdMax, backend->external_fdr_size);
+ UPDATE_RAW_END (cbRfdOffset, crfd, backend->external_rfd_size);
+ UPDATE_RAW_END (cbExtOffset, iextMax, backend->external_ext_size);
+
+#undef UPDATE_RAW_END
+
+ raw_size = raw_end - raw_base;
+ if (raw_size == 0)
+ {
+ ecoff_data (abfd)->sym_filepos = 0;
+ return true;
+ }
+ raw = (PTR) bfd_alloc (abfd, raw_size);
+ if (raw == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ if (bfd_read (raw, raw_size, 1, abfd) != raw_size)
+ {
+ bfd_error = system_call_error;
+ bfd_release (abfd, raw);
+ return false;
+ }
+
+ ecoff_data (abfd)->raw_size = raw_size;
+ ecoff_data (abfd)->raw_syments = raw;
+
+ /* Get pointers for the numeric offsets in the HDRR structure. */
+#define FIX(off1, off2, type) \
+ if (internal_symhdr->off1 == 0) \
+ ecoff_data (abfd)->off2 = (type) NULL; \
+ else \
+ ecoff_data (abfd)->off2 = (type) ((char *) raw \
+ + internal_symhdr->off1 \
+ - raw_base)
+ FIX (cbLineOffset, line, unsigned char *);
+ FIX (cbDnOffset, external_dnr, PTR);
+ FIX (cbPdOffset, external_pdr, PTR);
+ FIX (cbSymOffset, external_sym, PTR);
+ FIX (cbOptOffset, external_opt, PTR);
+ FIX (cbAuxOffset, external_aux, union aux_ext *);
+ FIX (cbSsOffset, ss, char *);
+ FIX (cbSsExtOffset, ssext, char *);
+ FIX (cbFdOffset, external_fdr, PTR);
+ FIX (cbRfdOffset, external_rfd, PTR);
+ FIX (cbExtOffset, external_ext, PTR);
+#undef FIX
+
+ /* I don't want to always swap all the data, because it will just
+ waste time and most programs will never look at it. The only
+ time the linker needs most of the debugging information swapped
+ is when linking big-endian and little-endian MIPS object files
+ together, which is not a common occurrence.
+
+ We need to look at the fdr to deal with a lot of information in
+ the symbols, so we swap them here. */
+ ecoff_data (abfd)->fdr =
+ (struct fdr *) bfd_alloc (abfd,
+ (internal_symhdr->ifdMax *
+ sizeof (struct fdr)));
+ if (ecoff_data (abfd)->fdr == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ external_fdr_size = backend->external_fdr_size;
+ fdr_ptr = ecoff_data (abfd)->fdr;
+ fraw_src = (char *) ecoff_data (abfd)->external_fdr;
+ fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
+ for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
+ (*backend->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+
+ return true;
+}
+
+/* ECOFF symbol table routines. The ECOFF symbol table is described
+ in gcc/mips-tfile.c. */
+
+/* ECOFF uses two common sections. One is the usual one, and the
+ other is for small objects. All the small objects are kept
+ together, and then referenced via the gp pointer, which yields
+ faster assembler code. This is what we use for the small common
+ section. */
+static asection ecoff_scom_section;
+static asymbol ecoff_scom_symbol;
+static asymbol *ecoff_scom_symbol_ptr;
+
+/* Create an empty symbol. */
+
+asymbol *
+ecoff_make_empty_symbol (abfd)
+ bfd *abfd;
+{
+ ecoff_symbol_type *new;
+
+ new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type));
+ if (new == (ecoff_symbol_type *) NULL)
+ {
+ bfd_error = no_memory;
+ return (asymbol *) NULL;
+ }
+ memset (new, 0, sizeof *new);
+ new->symbol.section = (asection *) NULL;
+ new->fdr = (FDR *) NULL;
+ new->local = false;
+ new->native = NULL;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+/* Set the BFD flags and section for an ECOFF symbol. */
+
+static void
+ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
+ bfd *abfd;
+ SYMR *ecoff_sym;
+ asymbol *asym;
+ int ext;
+ asymbol **indirect_ptr_ptr;
+{
+ asym->the_bfd = abfd;
+ asym->value = ecoff_sym->value;
+ asym->section = &bfd_debug_section;
+ asym->udata = NULL;
+
+ /* An indirect symbol requires two consecutive stabs symbols. */
+ if (*indirect_ptr_ptr != (asymbol *) NULL)
+ {
+ BFD_ASSERT (ECOFF_IS_STAB (ecoff_sym));
+
+ /* @@ Stuffing pointers into integers is a no-no.
+ We can usually get away with it if the integer is
+ large enough though. */
+ if (sizeof (asym) > sizeof (bfd_vma))
+ abort ();
+ (*indirect_ptr_ptr)->value = (bfd_vma) asym;
+
+ asym->flags = BSF_DEBUGGING;
+ asym->section = &bfd_und_section;
+ *indirect_ptr_ptr = NULL;
+ return;
+ }
+
+ if (ECOFF_IS_STAB (ecoff_sym)
+ && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT))
+ {
+ asym->flags = BSF_DEBUGGING | BSF_INDIRECT;
+ asym->section = &bfd_ind_section;
+ /* Pass this symbol on to the next call to this function. */
+ *indirect_ptr_ptr = asym;
+ return;
+ }
+
+ /* Most symbol types are just for debugging. */
+ switch (ecoff_sym->st)
+ {
+ case stGlobal:
+ case stStatic:
+ case stLabel:
+ case stProc:
+ case stStaticProc:
+ break;
+ case stNil:
+ if (ECOFF_IS_STAB (ecoff_sym))
+ {
+ asym->flags = BSF_DEBUGGING;
+ return;
+ }
+ break;
+ default:
+ asym->flags = BSF_DEBUGGING;
+ return;
+ }
+
+ if (ext)
+ asym->flags = BSF_EXPORT | BSF_GLOBAL;
+ else
+ asym->flags = BSF_LOCAL;
+ switch (ecoff_sym->sc)
+ {
+ case scNil:
+ /* Used for compiler generated labels. Leave them in the
+ debugging section, and mark them as local. If BSF_DEBUGGING
+ is set, then nm does not display them for some reason. If no
+ flags are set then the linker whines about them. */
+ asym->flags = BSF_LOCAL;
+ break;
+ case scText:
+ asym->section = bfd_make_section_old_way (abfd, ".text");
+ asym->value -= asym->section->vma;
+ break;
+ case scData:
+ asym->section = bfd_make_section_old_way (abfd, ".data");
+ asym->value -= asym->section->vma;
+ break;
+ case scBss:
+ asym->section = bfd_make_section_old_way (abfd, ".bss");
+ asym->value -= asym->section->vma;
+ break;
+ case scRegister:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scAbs:
+ asym->section = &bfd_abs_section;
+ break;
+ case scUndefined:
+ asym->section = &bfd_und_section;
+ asym->flags = 0;
+ asym->value = 0;
+ break;
+ case scCdbLocal:
+ case scBits:
+ case scCdbSystem:
+ case scRegImage:
+ case scInfo:
+ case scUserStruct:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scSData:
+ asym->section = bfd_make_section_old_way (abfd, ".sdata");
+ asym->value -= asym->section->vma;
+ break;
+ case scSBss:
+ asym->section = bfd_make_section_old_way (abfd, ".sbss");
+ asym->value -= asym->section->vma;
+ break;
+ case scRData:
+ asym->section = bfd_make_section_old_way (abfd, ".rdata");
+ asym->value -= asym->section->vma;
+ break;
+ case scVar:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scCommon:
+ if (asym->value > ecoff_data (abfd)->gp_size)
+ {
+ asym->section = &bfd_com_section;
+ asym->flags = 0;
+ break;
+ }
+ /* Fall through. */
+ case scSCommon:
+ if (ecoff_scom_section.name == NULL)
+ {
+ /* Initialize the small common section. */
+ ecoff_scom_section.name = SCOMMON;
+ ecoff_scom_section.flags = SEC_IS_COMMON;
+ ecoff_scom_section.output_section = &ecoff_scom_section;
+ ecoff_scom_section.symbol = &ecoff_scom_symbol;
+ ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
+ ecoff_scom_symbol.name = SCOMMON;
+ ecoff_scom_symbol.flags = BSF_SECTION_SYM;
+ ecoff_scom_symbol.section = &ecoff_scom_section;
+ ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
+ }
+ asym->section = &ecoff_scom_section;
+ asym->flags = 0;
+ break;
+ case scVarRegister:
+ case scVariant:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scSUndefined:
+ asym->section = &bfd_und_section;
+ asym->flags = 0;
+ asym->value = 0;
+ break;
+ case scInit:
+ asym->section = bfd_make_section_old_way (abfd, ".init");
+ asym->value -= asym->section->vma;
+ break;
+ case scBasedVar:
+ case scXData:
+ case scPData:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scFini:
+ asym->section = bfd_make_section_old_way (abfd, ".fini");
+ asym->value -= asym->section->vma;
+ break;
+ default:
+ break;
+ }
+
+ /* Look for special constructors symbols and make relocation entries
+ in a special construction section. These are produced by the
+ -fgnu-linker argument to g++. */
+ if (ECOFF_IS_STAB (ecoff_sym))
+ {
+ switch (ECOFF_UNMARK_STAB (ecoff_sym->index))
+ {
+ default:
+ break;
+
+ case N_SETA:
+ case N_SETT:
+ case N_SETD:
+ case N_SETB:
+ {
+ const char *name;
+ asection *section;
+ arelent_chain *reloc_chain;
+ unsigned int bitsize;
+
+ /* Get a section with the same name as the symbol (usually
+ __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the
+ name ___CTOR_LIST (three underscores). We need
+ __CTOR_LIST (two underscores), since ECOFF doesn't use
+ a leading underscore. This should be handled by gcc,
+ but instead we do it here. Actually, this should all
+ be done differently anyhow. */
+ name = bfd_asymbol_name (asym);
+ if (name[0] == '_' && name[1] == '_' && name[2] == '_')
+ {
+ ++name;
+ asym->name = name;
+ }
+ section = bfd_get_section_by_name (abfd, name);
+ if (section == (asection *) NULL)
+ {
+ char *copy;
+
+ copy = (char *) bfd_alloc (abfd, strlen (name) + 1);
+ strcpy (copy, name);
+ section = bfd_make_section (abfd, copy);
+ }
+
+ /* Build a reloc pointing to this constructor. */
+ reloc_chain =
+ (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+ reloc_chain->relent.sym_ptr_ptr =
+ bfd_get_section (asym)->symbol_ptr_ptr;
+ reloc_chain->relent.address = section->_raw_size;
+ reloc_chain->relent.addend = asym->value;
+ reloc_chain->relent.howto =
+ ecoff_backend (abfd)->constructor_reloc;
+
+ /* Set up the constructor section to hold the reloc. */
+ section->flags = SEC_CONSTRUCTOR;
+ ++section->reloc_count;
+
+ /* Constructor sections must be rounded to a boundary
+ based on the bitsize. These are not real sections--
+ they are handled specially by the linker--so the ECOFF
+ 16 byte alignment restriction does not apply. */
+ bitsize = ecoff_backend (abfd)->constructor_bitsize;
+ section->alignment_power = 1;
+ while ((1 << section->alignment_power) < bitsize / 8)
+ ++section->alignment_power;
+
+ reloc_chain->next = section->constructor_chain;
+ section->constructor_chain = reloc_chain;
+ section->_raw_size += bitsize / 8;
+
+ /* Mark the symbol as a constructor. */
+ asym->flags |= BSF_CONSTRUCTOR;
+ }
+ break;
+ }
+ }
+}
+
+/* Read an ECOFF symbol table. */
+
+boolean
+ecoff_slurp_symbol_table (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ const bfd_size_type external_ext_size = backend->external_ext_size;
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->swap_sym_in;
+ bfd_size_type internal_size;
+ ecoff_symbol_type *internal;
+ ecoff_symbol_type *internal_ptr;
+ asymbol *indirect_ptr;
+ char *eraw_src;
+ char *eraw_end;
+ FDR *fdr_ptr;
+ FDR *fdr_end;
+
+ /* If we've already read in the symbol table, do nothing. */
+ if (ecoff_data (abfd)->canonical_symbols != NULL)
+ return true;
+
+ /* Get the symbolic information. */
+ if (ecoff_slurp_symbolic_info (abfd) == false)
+ return false;
+ if (bfd_get_symcount (abfd) == 0)
+ return true;
+
+ internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type);
+ internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
+ if (internal == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ internal_ptr = internal;
+ indirect_ptr = NULL;
+ eraw_src = (char *) ecoff_data (abfd)->external_ext;
+ eraw_end = (eraw_src
+ + (ecoff_data (abfd)->symbolic_header.iextMax
+ * external_ext_size));
+ for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++)
+ {
+ EXTR internal_esym;
+
+ (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym);
+ internal_ptr->symbol.name = (ecoff_data (abfd)->ssext
+ + internal_esym.asym.iss);
+ ecoff_set_symbol_info (abfd, &internal_esym.asym,
+ &internal_ptr->symbol, 1, &indirect_ptr);
+ /* The alpha uses a negative ifd field for section symbols. */
+ if (internal_esym.ifd >= 0)
+ internal_ptr->fdr = ecoff_data (abfd)->fdr + internal_esym.ifd;
+ else
+ internal_ptr->fdr = NULL;
+ internal_ptr->local = false;
+ internal_ptr->native = (PTR) eraw_src;
+ }
+ BFD_ASSERT (indirect_ptr == (asymbol *) NULL);
+
+ /* The local symbols must be accessed via the fdr's, because the
+ string and aux indices are relative to the fdr information. */
+ fdr_ptr = ecoff_data (abfd)->fdr;
+ fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax;
+ for (; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ char *lraw_src;
+ char *lraw_end;
+
+ lraw_src = ((char *) ecoff_data (abfd)->external_sym
+ + fdr_ptr->isymBase * external_sym_size);
+ lraw_end = lraw_src + fdr_ptr->csym * external_sym_size;
+ for (;
+ lraw_src < lraw_end;
+ lraw_src += external_sym_size, internal_ptr++)
+ {
+ SYMR internal_sym;
+
+ (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym);
+ internal_ptr->symbol.name = (ecoff_data (abfd)->ss
+ + fdr_ptr->issBase
+ + internal_sym.iss);
+ ecoff_set_symbol_info (abfd, &internal_sym,
+ &internal_ptr->symbol, 0, &indirect_ptr);
+ internal_ptr->fdr = fdr_ptr;
+ internal_ptr->local = true;
+ internal_ptr->native = (PTR) lraw_src;
+ }
+ }
+ BFD_ASSERT (indirect_ptr == (asymbol *) NULL);
+
+ ecoff_data (abfd)->canonical_symbols = internal;
+
+ return true;
+}
+
+/* Return the amount of space needed for the canonical symbols. */
+
+unsigned int
+ecoff_get_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ if (ecoff_slurp_symbolic_info (abfd) == false
+ || bfd_get_symcount (abfd) == 0)
+ return 0;
+
+ return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
+}
+
+/* Get the canonicals symbols. */
+
+unsigned int
+ecoff_get_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ unsigned int counter = 0;
+ ecoff_symbol_type *symbase;
+ ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
+
+ if (ecoff_slurp_symbol_table (abfd) == false
+ || bfd_get_symcount (abfd) == 0)
+ return 0;
+
+ symbase = ecoff_data (abfd)->canonical_symbols;
+ while (counter < bfd_get_symcount (abfd))
+ {
+ *(location++) = symbase++;
+ counter++;
+ }
+ *location++ = (ecoff_symbol_type *) NULL;
+ return bfd_get_symcount (abfd);
+}
+
+/* Turn ECOFF type information into a printable string.
+ ecoff_emit_aggregate and ecoff_type_to_string are from
+ gcc/mips-tdump.c, with swapping added and used_ptr removed. */
+
+/* Write aggregate information to a string. */
+
+static void
+ecoff_emit_aggregate (abfd, string, rndx, isym, which)
+ bfd *abfd;
+ char *string;
+ RNDXR *rndx;
+ long isym;
+ CONST char *which;
+{
+ int ifd = rndx->rfd;
+ int indx = rndx->index;
+ int sym_base, ss_base;
+ CONST char *name;
+
+ if (ifd == 0xfff)
+ ifd = isym;
+
+ sym_base = ecoff_data (abfd)->fdr[ifd].isymBase;
+ ss_base = ecoff_data (abfd)->fdr[ifd].issBase;
+
+ if (indx == indexNil)
+ name = "/* no name */";
+ else
+ {
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ SYMR sym;
+
+ indx += sym_base;
+ (*backend->swap_sym_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_sym
+ + indx * backend->external_sym_size),
+ &sym);
+ name = ecoff_data (abfd)->ss + ss_base + sym.iss;
+ }
+
+ sprintf (string,
+ "%s %s { ifd = %d, index = %d }",
+ which, name, ifd,
+ indx + ecoff_data (abfd)->symbolic_header.iextMax);
+}
+
+/* Convert the type information to string format. */
+
+static char *
+ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
+ bfd *abfd;
+ union aux_ext *aux_ptr;
+ unsigned int indx;
+ int bigendian;
+{
+ AUXU u;
+ struct qual {
+ unsigned int type;
+ int low_bound;
+ int high_bound;
+ int stride;
+ } qualifiers[7];
+
+ unsigned int basic_type;
+ int i;
+ static char buffer1[1024];
+ static char buffer2[1024];
+ char *p1 = buffer1;
+ char *p2 = buffer2;
+ RNDXR rndx;
+
+ for (i = 0; i < 7; i++)
+ {
+ qualifiers[i].low_bound = 0;
+ qualifiers[i].high_bound = 0;
+ qualifiers[i].stride = 0;
+ }
+
+ if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1)
+ return "-1 (no type)";
+ ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
+
+ basic_type = u.ti.bt;
+ qualifiers[0].type = u.ti.tq0;
+ qualifiers[1].type = u.ti.tq1;
+ qualifiers[2].type = u.ti.tq2;
+ qualifiers[3].type = u.ti.tq3;
+ qualifiers[4].type = u.ti.tq4;
+ qualifiers[5].type = u.ti.tq5;
+ qualifiers[6].type = tqNil;
+
+ /*
+ * Go get the basic type.
+ */
+ switch (basic_type)
+ {
+ case btNil: /* undefined */
+ strcpy (p1, "nil");
+ break;
+
+ case btAdr: /* address - integer same size as pointer */
+ strcpy (p1, "address");
+ break;
+
+ case btChar: /* character */
+ strcpy (p1, "char");
+ break;
+
+ case btUChar: /* unsigned character */
+ strcpy (p1, "unsigned char");
+ break;
+
+ case btShort: /* short */
+ strcpy (p1, "short");
+ break;
+
+ case btUShort: /* unsigned short */
+ strcpy (p1, "unsigned short");
+ break;
+
+ case btInt: /* int */
+ strcpy (p1, "int");
+ break;
+
+ case btUInt: /* unsigned int */
+ strcpy (p1, "unsigned int");
+ break;
+
+ case btLong: /* long */
+ strcpy (p1, "long");
+ break;
+
+ case btULong: /* unsigned long */
+ strcpy (p1, "unsigned long");
+ break;
+
+ case btFloat: /* float (real) */
+ strcpy (p1, "float");
+ break;
+
+ case btDouble: /* Double (real) */
+ strcpy (p1, "double");
+ break;
+
+ /* Structures add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to struct def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btStruct: /* Structure (Record) */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "struct");
+ indx++; /* skip aux words */
+ break;
+
+ /* Unions add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to union def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btUnion: /* Union */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "union");
+ indx++; /* skip aux words */
+ break;
+
+ /* Enumerations add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to enum def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btEnum: /* Enumeration */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "enum");
+ indx++; /* skip aux words */
+ break;
+
+ case btTypedef: /* defined via a typedef, isymRef points */
+ strcpy (p1, "typedef");
+ break;
+
+ case btRange: /* subrange of int */
+ strcpy (p1, "subrange");
+ break;
+
+ case btSet: /* pascal sets */
+ strcpy (p1, "set");
+ break;
+
+ case btComplex: /* fortran complex */
+ strcpy (p1, "complex");
+ break;
+
+ case btDComplex: /* fortran double complex */
+ strcpy (p1, "double complex");
+ break;
+
+ case btIndirect: /* forward or unnamed typedef */
+ strcpy (p1, "forward/unamed typedef");
+ break;
+
+ case btFixedDec: /* Fixed Decimal */
+ strcpy (p1, "fixed decimal");
+ break;
+
+ case btFloatDec: /* Float Decimal */
+ strcpy (p1, "float decimal");
+ break;
+
+ case btString: /* Varying Length Character String */
+ strcpy (p1, "string");
+ break;
+
+ case btBit: /* Aligned Bit String */
+ strcpy (p1, "bit");
+ break;
+
+ case btPicture: /* Picture */
+ strcpy (p1, "picture");
+ break;
+
+ case btVoid: /* Void */
+ strcpy (p1, "void");
+ break;
+
+ default:
+ sprintf (p1, "Unknown basic type %d", (int) basic_type);
+ break;
+ }
+
+ p1 += strlen (buffer1);
+
+ /*
+ * If this is a bitfield, get the bitsize.
+ */
+ if (u.ti.fBitfield)
+ {
+ int bitsize;
+
+ bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]);
+ sprintf (p1, " : %d", bitsize);
+ p1 += strlen (buffer1);
+ }
+
+
+ /*
+ * Deal with any qualifiers.
+ */
+ if (qualifiers[0].type != tqNil)
+ {
+ /*
+ * Snarf up any array bounds in the correct order. Arrays
+ * store 5 successive words in the aux. table:
+ * word 0 RNDXR to type of the bounds (ie, int)
+ * word 1 Current file descriptor index
+ * word 2 low bound
+ * word 3 high bound (or -1 if [])
+ * word 4 stride size in bits
+ */
+ for (i = 0; i < 7; i++)
+ {
+ if (qualifiers[i].type == tqArray)
+ {
+ qualifiers[i].low_bound =
+ AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]);
+ qualifiers[i].high_bound =
+ AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]);
+ qualifiers[i].stride =
+ AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]);
+ indx += 5;
+ }
+ }
+
+ /*
+ * Now print out the qualifiers.
+ */
+ for (i = 0; i < 6; i++)
+ {
+ switch (qualifiers[i].type)
+ {
+ case tqNil:
+ case tqMax:
+ break;
+
+ case tqPtr:
+ strcpy (p2, "ptr to ");
+ p2 += sizeof ("ptr to ")-1;
+ break;
+
+ case tqVol:
+ strcpy (p2, "volatile ");
+ p2 += sizeof ("volatile ")-1;
+ break;
+
+ case tqFar:
+ strcpy (p2, "far ");
+ p2 += sizeof ("far ")-1;
+ break;
+
+ case tqProc:
+ strcpy (p2, "func. ret. ");
+ p2 += sizeof ("func. ret. ");
+ break;
+
+ case tqArray:
+ {
+ int first_array = i;
+ int j;
+
+ /* Print array bounds reversed (ie, in the order the C
+ programmer writes them). C is such a fun language.... */
+
+ while (i < 5 && qualifiers[i+1].type == tqArray)
+ i++;
+
+ for (j = i; j >= first_array; j--)
+ {
+ strcpy (p2, "array [");
+ p2 += sizeof ("array [")-1;
+ if (qualifiers[j].low_bound != 0)
+ sprintf (p2,
+ "%ld:%ld {%ld bits}",
+ (long) qualifiers[j].low_bound,
+ (long) qualifiers[j].high_bound,
+ (long) qualifiers[j].stride);
+
+ else if (qualifiers[j].high_bound != -1)
+ sprintf (p2,
+ "%ld {%ld bits}",
+ (long) (qualifiers[j].high_bound + 1),
+ (long) (qualifiers[j].stride));
+
+ else
+ sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride));
+
+ p2 += strlen (p2);
+ strcpy (p2, "] of ");
+ p2 += sizeof ("] of ")-1;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ strcpy (p2, buffer1);
+ return buffer2;
+}
+
+/* Return information about ECOFF symbol SYMBOL in RET. */
+
+void
+ecoff_get_symbol_info (abfd, symbol, ret)
+ bfd *abfd; /* Ignored. */
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/* Print information about an ECOFF symbol. */
+
+void
+ecoff_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ FILE *file = (FILE *)filep;
+
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ if (ecoffsymbol (symbol)->local)
+ {
+ SYMR ecoff_sym;
+
+ (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_sym);
+ fprintf (file, "ecoff local ");
+ fprintf_vma (file, (bfd_vma) ecoff_sym.value);
+ fprintf (file, " %x %x", (unsigned) ecoff_sym.st,
+ (unsigned) ecoff_sym.sc);
+ }
+ else
+ {
+ EXTR ecoff_ext;
+
+ (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext);
+ fprintf (file, "ecoff extern ");
+ fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
+ fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st,
+ (unsigned) ecoff_ext.asym.sc);
+ }
+ break;
+ case bfd_print_symbol_all:
+ /* Print out the symbols in a reasonable way */
+ {
+ char type;
+ int pos;
+ EXTR ecoff_ext;
+ char jmptbl;
+ char cobol_main;
+ char weakext;
+
+ if (ecoffsymbol (symbol)->local)
+ {
+ (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext.asym);
+ type = 'l';
+ pos = ((((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->external_sym)
+ / backend->external_sym_size)
+ + ecoff_data (abfd)->symbolic_header.iextMax);
+ jmptbl = ' ';
+ cobol_main = ' ';
+ weakext = ' ';
+ }
+ else
+ {
+ (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext);
+ type = 'e';
+ pos = (((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->external_ext)
+ / backend->external_ext_size);
+ jmptbl = ecoff_ext.jmptbl ? 'j' : ' ';
+ cobol_main = ecoff_ext.cobol_main ? 'c' : ' ';
+ weakext = ecoff_ext.weakext ? 'w' : ' ';
+ }
+
+ fprintf (file, "[%3d] %c ",
+ pos, type);
+ fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
+ fprintf (file, " st %x sc %x indx %x %c%c%c %s",
+ (unsigned) ecoff_ext.asym.st,
+ (unsigned) ecoff_ext.asym.sc,
+ (unsigned) ecoff_ext.asym.index,
+ jmptbl, cobol_main, weakext,
+ symbol->name);
+
+ if (ecoffsymbol (symbol)->fdr != NULL
+ && ecoff_ext.asym.index != indexNil)
+ {
+ unsigned int indx;
+ int bigendian;
+ bfd_size_type sym_base;
+ union aux_ext *aux_base;
+
+ indx = ecoff_ext.asym.index;
+
+ /* sym_base is used to map the fdr relative indices which
+ appear in the file to the position number which we are
+ using. */
+ sym_base = ecoffsymbol (symbol)->fdr->isymBase;
+ if (ecoffsymbol (symbol)->local)
+ sym_base += ecoff_data (abfd)->symbolic_header.iextMax;
+
+ /* aux_base is the start of the aux entries for this file;
+ asym.index is an offset from this. */
+ aux_base = (ecoff_data (abfd)->external_aux
+ + ecoffsymbol (symbol)->fdr->iauxBase);
+
+ /* The aux entries are stored in host byte order; the
+ order is indicated by a bit in the fdr. */
+ bigendian = ecoffsymbol (symbol)->fdr->fBigendian;
+
+ /* This switch is basically from gcc/mips-tdump.c */
+ switch (ecoff_ext.asym.st)
+ {
+ case stNil:
+ case stLabel:
+ break;
+
+ case stFile:
+ case stBlock:
+ fprintf (file, "\n End+1 symbol: %ld",
+ (long) (indx + sym_base));
+ break;
+
+ case stEnd:
+ if (ecoff_ext.asym.sc == scText
+ || ecoff_ext.asym.sc == scInfo)
+ fprintf (file, "\n First symbol: %ld",
+ (long) (indx + sym_base));
+ else
+ fprintf (file, "\n First symbol: %ld",
+ (long) (AUX_GET_ISYM (bigendian,
+ &aux_base[ecoff_ext.asym.index])
+ + sym_base));
+ break;
+
+ case stProc:
+ case stStaticProc:
+ if (ECOFF_IS_STAB (&ecoff_ext.asym))
+ ;
+ else if (ecoffsymbol (symbol)->local)
+ fprintf (file, "\n End+1 symbol: %-7ld Type: %s",
+ (long) (AUX_GET_ISYM (bigendian,
+ &aux_base[ecoff_ext.asym.index])
+ + sym_base),
+ ecoff_type_to_string (abfd, aux_base, indx + 1,
+ bigendian));
+ else
+ fprintf (file, "\n Local symbol: %d",
+ (indx
+ + sym_base
+ + ecoff_data (abfd)->symbolic_header.iextMax));
+ break;
+
+ default:
+ if (! ECOFF_IS_STAB (&ecoff_ext.asym))
+ fprintf (file, "\n Type: %s",
+ ecoff_type_to_string (abfd, aux_base, indx,
+ bigendian));
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/* Read in the relocs for a section. */
+
+static boolean
+ecoff_slurp_reloc_table (abfd, section, symbols)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ arelent *internal_relocs;
+ bfd_size_type external_reloc_size;
+ bfd_size_type external_relocs_size;
+ char *external_relocs;
+ arelent *rptr;
+ unsigned int i;
+
+ if (section->relocation != (arelent *) NULL
+ || section->reloc_count == 0
+ || (section->flags & SEC_CONSTRUCTOR) != 0)
+ return true;
+
+ if (ecoff_slurp_symbol_table (abfd) == false)
+ return false;
+
+ internal_relocs = (arelent *) bfd_alloc (abfd,
+ (sizeof (arelent)
+ * section->reloc_count));
+ external_reloc_size = backend->external_reloc_size;
+ external_relocs_size = external_reloc_size * section->reloc_count;
+ external_relocs = (char *) bfd_alloc (abfd, external_relocs_size);
+ if (internal_relocs == (arelent *) NULL
+ || external_relocs == (char *) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0)
+ return false;
+ if (bfd_read (external_relocs, 1, external_relocs_size, abfd)
+ != external_relocs_size)
+ {
+ bfd_error = system_call_error;
+ return false;
+ }
+
+ for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
+ {
+ struct internal_reloc intern;
+
+ (*backend->swap_reloc_in) (abfd,
+ external_relocs + i * external_reloc_size,
+ &intern);
+
+ if (intern.r_extern)
+ {
+ /* r_symndx is an index into the external symbols. */
+ BFD_ASSERT (intern.r_symndx >= 0
+ && (intern.r_symndx
+ < ecoff_data (abfd)->symbolic_header.iextMax));
+ rptr->sym_ptr_ptr = symbols + intern.r_symndx;
+ rptr->addend = 0;
+ }
+ else if (intern.r_symndx == RELOC_SECTION_NONE
+ || intern.r_symndx == RELOC_SECTION_ABS)
+ {
+ rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
+ rptr->addend = 0;
+ }
+ else
+ {
+ CONST char *sec_name;
+ asection *sec;
+
+ /* r_symndx is a section key. */
+ switch (intern.r_symndx)
+ {
+ case RELOC_SECTION_TEXT: sec_name = ".text"; break;
+ case RELOC_SECTION_RDATA: sec_name = ".rdata"; break;
+ case RELOC_SECTION_DATA: sec_name = ".data"; break;
+ case RELOC_SECTION_SDATA: sec_name = ".sdata"; break;
+ case RELOC_SECTION_SBSS: sec_name = ".sbss"; break;
+ case RELOC_SECTION_BSS: sec_name = ".bss"; break;
+ case RELOC_SECTION_INIT: sec_name = ".init"; break;
+ case RELOC_SECTION_LIT8: sec_name = ".lit8"; break;
+ case RELOC_SECTION_LIT4: sec_name = ".lit4"; break;
+ case RELOC_SECTION_XDATA: sec_name = ".xdata"; break;
+ case RELOC_SECTION_PDATA: sec_name = ".pdata"; break;
+ case RELOC_SECTION_LITA: sec_name = ".lita"; break;
+ default: abort ();
+ }
+
+ sec = bfd_get_section_by_name (abfd, sec_name);
+ if (sec == (asection *) NULL)
+ abort ();
+ rptr->sym_ptr_ptr = sec->symbol_ptr_ptr;
+
+ rptr->addend = - bfd_get_section_vma (abfd, sec);
+ }
+
+ rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section);
+
+ /* Let the backend select the howto field and do any other
+ required processing. */
+ (*backend->finish_reloc) (abfd, &intern, rptr);
+ }
+
+ bfd_release (abfd, external_relocs);
+
+ section->relocation = internal_relocs;
+
+ return true;
+}
+
+/* Get a canonical list of relocs. */
+
+unsigned int
+ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
+ bfd *abfd;
+ asection *section;
+ arelent **relptr;
+ asymbol **symbols;
+{
+ unsigned int count;
+
+ if (section->flags & SEC_CONSTRUCTOR)
+ {
+ arelent_chain *chain;
+
+ /* This section has relocs made up by us, not the file, so take
+ them out of their chain and place them into the data area
+ provided. */
+ for (count = 0, chain = section->constructor_chain;
+ count < section->reloc_count;
+ count++, chain = chain->next)
+ *relptr++ = &chain->relent;
+ }
+ else
+ {
+ arelent *tblptr;
+
+ if (ecoff_slurp_reloc_table (abfd, section, symbols) == false)
+ return 0;
+
+ tblptr = section->relocation;
+ if (tblptr == (arelent *) NULL)
+ return 0;
+
+ for (count = 0; count < section->reloc_count; count++)
+ *relptr++ = tblptr++;
+ }
+
+ *relptr = (arelent *) NULL;
+
+ return section->reloc_count;
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location. */
+
+boolean
+ecoff_find_nearest_line (abfd,
+ section,
+ ignore_symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ retline_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **ignore_symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *retline_ptr;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ FDR *fdr_ptr;
+ FDR *fdr_start;
+ FDR *fdr_end;
+ FDR *fdr_hold;
+ bfd_size_type external_pdr_size;
+ char *pdr_ptr;
+ char *pdr_end;
+ PDR pdr;
+ unsigned char *line_ptr;
+ unsigned char *line_end;
+ int lineno;
+
+ /* If we're not in the .text section, we don't have any line
+ numbers. */
+ if (strcmp (section->name, _TEXT) != 0
+ || offset < ecoff_data (abfd)->text_start
+ || offset >= ecoff_data (abfd)->text_end)
+ return false;
+
+ /* Make sure we have the FDR's. */
+ if (ecoff_slurp_symbolic_info (abfd) == false
+ || bfd_get_symcount (abfd) == 0)
+ return false;
+
+ /* Each file descriptor (FDR) has a memory address. Here we track
+ down which FDR we want. The FDR's are stored in increasing
+ memory order. If speed is ever important, this can become a
+ binary search. We must ignore FDR's with no PDR entries; they
+ will have the adr of the FDR before or after them. */
+ fdr_start = ecoff_data (abfd)->fdr;
+ fdr_end = fdr_start + ecoff_data (abfd)->symbolic_header.ifdMax;
+ fdr_hold = (FDR *) NULL;
+ for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ if (fdr_ptr->cpd == 0)
+ continue;
+ if (offset < fdr_ptr->adr)
+ break;
+ fdr_hold = fdr_ptr;
+ }
+ if (fdr_hold == (FDR *) NULL)
+ return false;
+ fdr_ptr = fdr_hold;
+
+ /* Each FDR has a list of procedure descriptors (PDR). PDR's also
+ have an address, which is relative to the FDR address, and are
+ also stored in increasing memory order. */
+ offset -= fdr_ptr->adr;
+ external_pdr_size = backend->external_pdr_size;
+ pdr_ptr = ((char *) ecoff_data (abfd)->external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
+ (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+
+ /* The address of the first PDR is an offset which applies to the
+ addresses of all the PDR's. */
+ offset += pdr.adr;
+
+ for (pdr_ptr += external_pdr_size;
+ pdr_ptr < pdr_end;
+ pdr_ptr += external_pdr_size)
+ {
+ (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ if (offset < pdr.adr)
+ break;
+ }
+
+ /* Now we can look for the actual line number. The line numbers are
+ stored in a very funky format, which I won't try to describe.
+ Note that right here pdr_ptr and pdr hold the PDR *after* the one
+ we want; we need this to compute line_end. */
+ line_end = ecoff_data (abfd)->line;
+ if (pdr_ptr == pdr_end)
+ line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
+ else
+ line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
+
+ /* Now change pdr and pdr_ptr to the one we want. */
+ pdr_ptr -= external_pdr_size;
+ (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+
+ offset -= pdr.adr;
+ lineno = pdr.lnLow;
+ line_ptr = (ecoff_data (abfd)->line
+ + fdr_ptr->cbLineOffset
+ + pdr.cbLineOffset);
+ while (line_ptr < line_end)
+ {
+ int delta;
+ int count;
+
+ delta = *line_ptr >> 4;
+ if (delta >= 0x8)
+ delta -= 0x10;
+ count = (*line_ptr & 0xf) + 1;
+ ++line_ptr;
+ if (delta == -8)
+ {
+ delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
+ if (delta >= 0x8000)
+ delta -= 0x10000;
+ line_ptr += 2;
+ }
+ lineno += delta;
+ if (offset < count * 4)
+ break;
+ offset -= count * 4;
+ }
+
+ /* If fdr_ptr->rss is -1, then this file does not have full symbols,
+ at least according to gdb/mipsread.c. */
+ if (fdr_ptr->rss == -1)
+ {
+ *filename_ptr = NULL;
+ if (pdr.isym == -1)
+ *functionname_ptr = NULL;
+ else
+ {
+ EXTR proc_ext;
+
+ (*backend->swap_ext_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_ext
+ + pdr.isym * backend->external_ext_size),
+ &proc_ext);
+ *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss;
+ }
+ }
+ else
+ {
+ SYMR proc_sym;
+
+ *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss;
+ (*backend->swap_sym_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_sym
+ + ((fdr_ptr->isymBase + pdr.isym)
+ * backend->external_sym_size)),
+ &proc_sym);
+ *functionname_ptr = (ecoff_data (abfd)->ss
+ + fdr_ptr->issBase
+ + proc_sym.iss);
+ }
+ if (lineno == ilineNil)
+ lineno = 0;
+ *retline_ptr = lineno;
+ return true;
+}
+
+/* We can't use the generic linking routines for ECOFF, because we
+ have to handle all the debugging information. The generic link
+ routine just works out the section contents and attaches a list of
+ symbols.
+
+ We link by looping over all the seclets. We make two passes. On
+ the first we set the actual section contents and determine the size
+ of the debugging information. On the second we accumulate the
+ debugging information and write it out.
+
+ This currently always accumulates the debugging information, which
+ is incorrect, because it ignores the -s and -S options of the
+ linker. The linker needs to be modified to give us that
+ information in a more useful format (currently it just provides a
+ list of symbols which should appear in the output file). */
+
+/* Clear the output_has_begun flag for all the input BFD's. We use it
+ to avoid linking in the debugging information for a BFD more than
+ once. */
+
+static void
+ecoff_clear_output_flags (abfd)
+ bfd *abfd;
+{
+ register asection *o;
+ register bfd_seclet_type *p;
+
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ if (p->type == bfd_indirect_seclet)
+ p->u.indirect.section->owner->output_has_begun = false;
+}
+
+/* Handle an indirect seclet on the first pass. Set the contents of
+ the output section, and accumulate the debugging information if
+ any. */
+
+static boolean
+ecoff_rel (output_bfd, seclet, output_section, data, relocateable)
+ bfd *output_bfd;
+ bfd_seclet_type *seclet;
+ asection *output_section;
+ PTR data;
+ boolean relocateable;
+{
+ bfd *input_bfd;
+ HDRR *output_symhdr;
+ HDRR *input_symhdr;
+
+ if ((output_section->flags & SEC_HAS_CONTENTS)
+ && !(output_section->flags & SEC_NEVER_LOAD)
+ && (output_section->flags & SEC_LOAD)
+ && seclet->size)
+ {
+ data = (PTR) bfd_get_relocated_section_contents (output_bfd,
+ seclet,
+ data,
+ relocateable);
+ if (bfd_set_section_contents (output_bfd,
+ output_section,
+ data,
+ seclet->offset,
+ seclet->size)
+ == false)
+ {
+ abort();
+ }
+ }
+
+ input_bfd = seclet->u.indirect.section->owner;
+
+ /* We want to figure out how much space will be required to
+ incorporate all the debugging information from input_bfd. We use
+ the output_has_begun field to avoid adding it in more than once.
+ The actual incorporation is done in the second pass, in
+ ecoff_get_debug. The code has to parallel that code in its
+ manipulations of output_symhdr. */
+
+ if (input_bfd->output_has_begun)
+ return true;
+ input_bfd->output_has_begun = true;
+
+ output_symhdr = &ecoff_data (output_bfd)->symbolic_header;
+
+ if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+ {
+ asymbol **symbols;
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+
+ /* We just accumulate local symbols from a non-ECOFF BFD. The
+ external symbols are handled separately. */
+
+ symbols = (asymbol **) bfd_alloc (output_bfd,
+ get_symtab_upper_bound (input_bfd));
+ if (symbols == (asymbol **) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+ for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++)
+ {
+ size_t len;
+
+ len = strlen ((*sym_ptr)->name);
+ if (((*sym_ptr)->flags & BSF_EXPORT) == 0)
+ {
+ ++output_symhdr->isymMax;
+ output_symhdr->issMax += len + 1;
+ }
+ }
+
+ bfd_release (output_bfd, (PTR) symbols);
+
+ ++output_symhdr->ifdMax;
+
+ return true;
+ }
+
+ /* We simply add in the information from another ECOFF BFD. First
+ we make sure we have the symbolic information. */
+ if (ecoff_slurp_symbol_table (input_bfd) == false)
+ return false;
+ if (bfd_get_symcount (input_bfd) == 0)
+ return true;
+
+ input_symhdr = &ecoff_data (input_bfd)->symbolic_header;
+
+ /* Figure out how much information we are going to be putting in.
+ The external symbols are handled separately. */
+ output_symhdr->ilineMax += input_symhdr->ilineMax;
+ output_symhdr->cbLine += input_symhdr->cbLine;
+ output_symhdr->idnMax += input_symhdr->idnMax;
+ output_symhdr->ipdMax += input_symhdr->ipdMax;
+ output_symhdr->isymMax += input_symhdr->isymMax;
+ output_symhdr->ioptMax += input_symhdr->ioptMax;
+ output_symhdr->iauxMax += input_symhdr->iauxMax;
+ output_symhdr->issMax += input_symhdr->issMax;
+ output_symhdr->ifdMax += input_symhdr->ifdMax;
+
+ /* The RFD's are special, since we create them if needed. */
+ if (input_symhdr->crfd > 0)
+ output_symhdr->crfd += input_symhdr->crfd;
+ else
+ output_symhdr->crfd += input_symhdr->ifdMax;
+
+ return true;
+}
+
+/* Handle an arbitrary seclet on the first pass. */
+
+static boolean
+ecoff_dump_seclet (abfd, seclet, section, data, relocateable)
+ bfd *abfd;
+ bfd_seclet_type *seclet;
+ asection *section;
+ PTR data;
+ boolean relocateable;
+{
+ switch (seclet->type)
+ {
+ case bfd_indirect_seclet:
+ /* The contents of this section come from another one somewhere
+ else. */
+ return ecoff_rel (abfd, seclet, section, data, relocateable);
+
+ case bfd_fill_seclet:
+ /* Fill in the section with fill.value. This is used to pad out
+ sections, but we must avoid padding the .bss section. */
+ if ((section->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ if (seclet->u.fill.value != 0)
+ abort ();
+ }
+ else
+ {
+ char *d = (char *) bfd_alloc (abfd, seclet->size);
+ unsigned int i;
+ boolean ret;
+
+ for (i = 0; i < seclet->size; i+=2)
+ d[i] = seclet->u.fill.value >> 8;
+ for (i = 1; i < seclet->size; i+=2)
+ d[i] = seclet->u.fill.value;
+ ret = bfd_set_section_contents (abfd, section, d, seclet->offset,
+ seclet->size);
+ bfd_release (abfd, (PTR) d);
+ return ret;
+ }
+ break;
+
+ default:
+ abort();
+ }
+
+ return true;
+}
+
+/* Add a string to the debugging information we are accumulating for a
+ file. Return the offset from the fdr string base or from the
+ external string base. */
+
+static long
+ecoff_add_string (output_bfd, fdr, string, external)
+ bfd *output_bfd;
+ FDR *fdr;
+ CONST char *string;
+ boolean external;
+{
+ HDRR *symhdr;
+ size_t len;
+ long ret;
+
+ symhdr = &ecoff_data (output_bfd)->symbolic_header;
+ len = strlen (string);
+ if (external)
+ {
+ strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string);
+ ret = symhdr->issExtMax;
+ symhdr->issExtMax += len + 1;
+ }
+ else
+ {
+ strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string);
+ ret = fdr->cbSs;
+ symhdr->issMax += len + 1;
+ fdr->cbSs += len + 1;
+ }
+ return ret;
+}
+
+/* Accumulate the debugging information from an input section. */
+
+static boolean
+ecoff_get_debug (output_bfd, seclet, section, relocateable)
+ bfd *output_bfd;
+ bfd_seclet_type *seclet;
+ asection *section;
+ boolean relocateable;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (output_bfd);
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ const bfd_size_type external_pdr_size = backend->external_pdr_size;
+ const bfd_size_type external_fdr_size = backend->external_fdr_size;
+ const bfd_size_type external_rfd_size = backend->external_rfd_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->swap_sym_in;
+ void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
+ = backend->swap_sym_out;
+ void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *))
+ = backend->swap_pdr_in;
+ void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
+ = backend->swap_fdr_out;
+ void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
+ = backend->swap_rfd_out;
+ bfd *input_bfd;
+ HDRR *output_symhdr;
+ HDRR *input_symhdr;
+ ecoff_data_type *output_ecoff;
+ ecoff_data_type *input_ecoff;
+ unsigned int count;
+ char *sym_out;
+ ecoff_symbol_type *esym_ptr;
+ ecoff_symbol_type *esym_end;
+ FDR *fdr_ptr;
+ FDR *fdr_end;
+ char *fdr_out;
+
+ input_bfd = seclet->u.indirect.section->owner;
+
+ /* Don't get the information more than once. */
+ if (input_bfd->output_has_begun)
+ return true;
+ input_bfd->output_has_begun = true;
+
+ output_ecoff = ecoff_data (output_bfd);
+ output_symhdr = &output_ecoff->symbolic_header;
+
+ if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+ {
+ FDR fdr;
+ asymbol **symbols;
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+
+ /* This is not an ECOFF BFD. Just gather the symbols. */
+
+ memset (&fdr, 0, sizeof fdr);
+
+ fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset;
+ fdr.issBase = output_symhdr->issMax;
+ fdr.cbSs = 0;
+ fdr.rss = ecoff_add_string (output_bfd,
+ &fdr,
+ bfd_get_filename (input_bfd),
+ false);
+ fdr.isymBase = output_symhdr->isymMax;
+
+ /* Get the local symbols from the input BFD. */
+ symbols = (asymbol **) bfd_alloc (output_bfd,
+ get_symtab_upper_bound (input_bfd));
+ if (symbols == (asymbol **) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+ /* Handle the local symbols. Any external symbols are handled
+ separately. */
+ fdr.csym = 0;
+ for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
+ {
+ SYMR internal_sym;
+
+ if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
+ continue;
+ memset (&internal_sym, 0, sizeof internal_sym);
+ internal_sym.iss = ecoff_add_string (output_bfd,
+ &fdr,
+ (*sym_ptr)->name,
+ false);
+
+ if (bfd_is_com_section ((*sym_ptr)->section)
+ || (*sym_ptr)->section == &bfd_und_section)
+ internal_sym.value = (*sym_ptr)->value;
+ else
+ internal_sym.value = ((*sym_ptr)->value
+ + (*sym_ptr)->section->output_offset
+ + (*sym_ptr)->section->output_section->vma);
+ internal_sym.st = stNil;
+ internal_sym.sc = scUndefined;
+ internal_sym.index = indexNil;
+ (*swap_sym_out) (output_bfd, &internal_sym,
+ ((char *) output_ecoff->external_sym
+ + output_symhdr->isymMax * external_sym_size));
+ ++fdr.csym;
+ ++output_symhdr->isymMax;
+ }
+
+ bfd_release (output_bfd, (PTR) symbols);
+
+ /* Leave everything else in the FDR zeroed out. This will cause
+ the lang field to be langC. The fBigendian field will
+ indicate little endian format, but it doesn't matter because
+ it only applies to aux fields and there are none. */
+
+ (*swap_fdr_out) (output_bfd, &fdr,
+ ((char *) output_ecoff->external_fdr
+ + output_symhdr->ifdMax * external_fdr_size));
+ ++output_symhdr->ifdMax;
+ return true;
+ }
+
+ /* This is an ECOFF BFD. We want to grab the information from
+ input_bfd and attach it to output_bfd. */
+ count = bfd_get_symcount (input_bfd);
+ if (count == 0)
+ return true;
+ input_ecoff = ecoff_data (input_bfd);
+ input_symhdr = &input_ecoff->symbolic_header;
+
+ /* I think that it is more efficient to simply copy the debugging
+ information from the input BFD to the output BFD. Because ECOFF
+ uses relative pointers for most of the debugging information,
+ only a little of it has to be changed at all. */
+
+ /* Swap in the local symbols, adjust their values, and swap them out
+ again. The external symbols are handled separately. */
+ sym_out = ((char *) output_ecoff->external_sym
+ + output_symhdr->isymMax * external_sym_size);
+
+ esym_ptr = ecoff_data (input_bfd)->canonical_symbols;
+ esym_end = esym_ptr + count;
+ for (; esym_ptr < esym_end; esym_ptr++)
+ {
+ if (esym_ptr->local)
+ {
+ SYMR sym;
+
+ (*swap_sym_in) (input_bfd, esym_ptr->native, &sym);
+
+ /* If we're producing an executable, move common symbols
+ into bss. */
+ if (relocateable == false)
+ {
+ if (sym.sc == scCommon)
+ sym.sc = scBss;
+ else if (sym.sc == scSCommon)
+ sym.sc = scSBss;
+ }
+
+ if (! bfd_is_com_section (esym_ptr->symbol.section)
+ && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0
+ && esym_ptr->symbol.section != &bfd_und_section)
+ sym.value = (esym_ptr->symbol.value
+ + esym_ptr->symbol.section->output_offset
+ + esym_ptr->symbol.section->output_section->vma);
+ (*swap_sym_out) (output_bfd, &sym, sym_out);
+ sym_out += external_sym_size;
+ }
+ }
+
+ /* That should have accounted for all the local symbols in
+ input_bfd. */
+
+ /* Copy the information that does not need swapping. */
+ memcpy (output_ecoff->line + output_symhdr->cbLine,
+ input_ecoff->line,
+ input_symhdr->cbLine * sizeof (unsigned char));
+ memcpy (output_ecoff->external_aux + output_symhdr->iauxMax,
+ input_ecoff->external_aux,
+ input_symhdr->iauxMax * sizeof (union aux_ext));
+ memcpy (output_ecoff->ss + output_symhdr->issMax,
+ input_ecoff->ss,
+ input_symhdr->issMax * sizeof (char));
+
+ /* Some of the information may need to be swapped. */
+ if (output_bfd->xvec->header_byteorder_big_p
+ == input_bfd->xvec->header_byteorder_big_p)
+ {
+ /* The two BFD's have the same endianness, so memcpy will
+ suffice. */
+ if (input_symhdr->idnMax > 0)
+ memcpy (((char *) output_ecoff->external_dnr
+ + output_symhdr->idnMax * backend->external_dnr_size),
+ input_ecoff->external_dnr,
+ input_symhdr->idnMax * backend->external_dnr_size);
+ if (input_symhdr->ipdMax > 0)
+ memcpy (((char *) output_ecoff->external_pdr
+ + output_symhdr->ipdMax * external_pdr_size),
+ input_ecoff->external_pdr,
+ input_symhdr->ipdMax * external_pdr_size);
+ if (input_symhdr->ioptMax > 0)
+ memcpy (((char *) output_ecoff->external_opt
+ + output_symhdr->ioptMax * backend->external_opt_size),
+ input_ecoff->external_opt,
+ input_symhdr->ioptMax * backend->external_opt_size);
+ }
+ else
+ {
+ bfd_size_type sz;
+ char *in;
+ char *end;
+ char *out;
+
+ /* The two BFD's have different endianness, so we must swap
+ everything in and out. This code would always work, but it
+ would be slow in the normal case. */
+ sz = backend->external_dnr_size;
+ in = (char *) input_ecoff->external_dnr;
+ end = in + input_symhdr->idnMax * sz;
+ out = (char *) output_ecoff->external_dnr + output_symhdr->idnMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ DNR dnr;
+
+ (*backend->swap_dnr_in) (input_bfd, in, &dnr);
+ (*backend->swap_dnr_out) (output_bfd, &dnr, out);
+ }
+
+ sz = external_pdr_size;
+ in = (char *) input_ecoff->external_pdr;
+ end = in + input_symhdr->ipdMax * sz;
+ out = (char *) output_ecoff->external_pdr + output_symhdr->ipdMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ PDR pdr;
+
+ (*swap_pdr_in) (input_bfd, in, &pdr);
+ (*backend->swap_pdr_out) (output_bfd, &pdr, out);
+ }
+
+ sz = backend->external_opt_size;
+ in = (char *) input_ecoff->external_opt;
+ end = in + input_symhdr->ioptMax * sz;
+ out = (char *) output_ecoff->external_opt + output_symhdr->ioptMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ OPTR opt;
+
+ (*backend->swap_opt_in) (input_bfd, in, &opt);
+ (*backend->swap_opt_out) (output_bfd, &opt, out);
+ }
+ }
+
+ /* Set ifdbase so that the external symbols know how to adjust their
+ ifd values. */
+ input_ecoff->ifdbase = output_symhdr->ifdMax;
+
+ fdr_ptr = input_ecoff->fdr;
+ fdr_end = fdr_ptr + input_symhdr->ifdMax;
+ fdr_out = ((char *) output_ecoff->external_fdr
+ + output_symhdr->ifdMax * external_fdr_size);
+ for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out += external_fdr_size)
+ {
+ FDR fdr;
+ unsigned long pdr_off;
+
+ fdr = *fdr_ptr;
+
+ /* The memory address for this fdr is the address for the seclet
+ plus the offset to this fdr within input_bfd. For some
+ reason the offset of the first procedure pointer is also
+ added in. */
+ if (fdr.cpd == 0)
+ pdr_off = 0;
+ else
+ {
+ PDR pdr;
+
+ (*swap_pdr_in) (input_bfd,
+ ((char *) input_ecoff->external_pdr
+ + fdr.ipdFirst * external_pdr_size),
+ &pdr);
+ pdr_off = pdr.adr;
+ }
+ fdr.adr = (bfd_get_section_vma (output_bfd, section)
+ + seclet->offset
+ + (fdr_ptr->adr - input_ecoff->fdr->adr)
+ + pdr_off);
+
+ fdr.issBase += output_symhdr->issMax;
+ fdr.isymBase += output_symhdr->isymMax;
+ fdr.ilineBase += output_symhdr->ilineMax;
+ fdr.ioptBase += output_symhdr->ioptMax;
+ fdr.ipdFirst += output_symhdr->ipdMax;
+ fdr.iauxBase += output_symhdr->iauxMax;
+ fdr.rfdBase += output_symhdr->crfd;
+
+ /* If there are no RFD's, we are going to add some. We don't
+ want to adjust irfd for this, so that all the FDR's can share
+ the RFD's. */
+ if (input_symhdr->crfd == 0)
+ fdr.crfd = input_symhdr->ifdMax;
+
+ if (fdr.cbLine != 0)
+ fdr.cbLineOffset += output_symhdr->cbLine;
+
+ (*swap_fdr_out) (output_bfd, &fdr, fdr_out);
+ }
+
+ if (input_symhdr->crfd > 0)
+ {
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = backend->swap_rfd_in;
+ char *rfd_in;
+ char *rfd_end;
+ char *rfd_out;
+
+ /* Swap and adjust the RFD's. RFD's are only created by the
+ linker, so this will only be necessary if one of the input
+ files is the result of a partial link. Presumably all
+ necessary RFD's are present. */
+ rfd_in = (char *) input_ecoff->external_rfd;
+ rfd_end = rfd_in + input_symhdr->crfd * external_rfd_size;
+ rfd_out = ((char *) output_ecoff->external_rfd
+ + output_symhdr->crfd * external_rfd_size);
+ for (;
+ rfd_in < rfd_end;
+ rfd_in += external_rfd_size, rfd_out += external_rfd_size)
+ {
+ RFDT rfd;
+
+ (*swap_rfd_in) (input_bfd, rfd_in, &rfd);
+ rfd += output_symhdr->ifdMax;
+ (*swap_rfd_out) (output_bfd, &rfd, rfd_out);
+ }
+ output_symhdr->crfd += input_symhdr->crfd;
+ }
+ else
+ {
+ char *rfd_out;
+ char *rfd_end;
+ RFDT rfd;
+
+ /* Create RFD's. Some of the debugging information includes
+ relative file indices. These indices are taken as indices to
+ the RFD table if there is one, or to the global table if
+ there is not. If we did not create RFD's, we would have to
+ parse and adjust all the debugging information which contains
+ file indices. */
+ rfd = output_symhdr->ifdMax;
+ rfd_out = ((char *) output_ecoff->external_rfd
+ + output_symhdr->crfd * external_rfd_size);
+ rfd_end = rfd_out + input_symhdr->ifdMax * external_rfd_size;
+ for (; rfd_out < rfd_end; rfd_out += external_rfd_size, rfd++)
+ (*swap_rfd_out) (output_bfd, &rfd, rfd_out);
+ output_symhdr->crfd += input_symhdr->ifdMax;
+ }
+
+ /* Combine the register masks. Not all of these are used on all
+ targets, but that's OK because only the relevant ones will be
+ swapped in and out. */
+ {
+ int i;
+
+ output_ecoff->gprmask |= input_ecoff->gprmask;
+ output_ecoff->fprmask |= input_ecoff->fprmask;
+ for (i = 0; i < 4; i++)
+ output_ecoff->cprmask[i] |= input_ecoff->cprmask[i];
+ }
+
+ /* Update the counts. */
+ output_symhdr->ilineMax += input_symhdr->ilineMax;
+ output_symhdr->cbLine += input_symhdr->cbLine;
+ output_symhdr->idnMax += input_symhdr->idnMax;
+ output_symhdr->ipdMax += input_symhdr->ipdMax;
+ output_symhdr->isymMax += input_symhdr->isymMax;
+ output_symhdr->ioptMax += input_symhdr->ioptMax;
+ output_symhdr->iauxMax += input_symhdr->iauxMax;
+ output_symhdr->issMax += input_symhdr->issMax;
+ output_symhdr->ifdMax += input_symhdr->ifdMax;
+
+ return true;
+}
+
+/* This is the actual link routine. It makes two passes over all the
+ seclets. */
+
+boolean
+ecoff_bfd_seclet_link (abfd, data, relocateable)
+ bfd *abfd;
+ PTR data;
+ boolean relocateable;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ HDRR *symhdr;
+ int ipass;
+ register asection *o;
+ register bfd_seclet_type *p;
+ asymbol **sym_ptr_ptr;
+ bfd_size_type debug_align;
+ bfd_size_type size;
+ char *raw;
+
+ /* We accumulate the debugging information counts in the symbolic
+ header. */
+ symhdr = &ecoff_data (abfd)->symbolic_header;
+ symhdr->magic = backend->sym_magic;
+ /* FIXME: What should the version stamp be? */
+ symhdr->vstamp = 0;
+ symhdr->ilineMax = 0;
+ symhdr->cbLine = 0;
+ symhdr->idnMax = 0;
+ symhdr->ipdMax = 0;
+ symhdr->isymMax = 0;
+ symhdr->ioptMax = 0;
+ symhdr->iauxMax = 0;
+ symhdr->issMax = 0;
+ symhdr->issExtMax = 0;
+ symhdr->ifdMax = 0;
+ symhdr->crfd = 0;
+ symhdr->iextMax = 0;
+
+ /* We need to copy over the debugging symbols from each input BFD.
+ When we do this copying, we have to adjust the text address in
+ the FDR structures, so we have to know the text address used for
+ the input BFD. Since we only want to copy the symbols once per
+ input BFD, but we are going to look at each input BFD multiple
+ times (once for each section it provides), we arrange to always
+ look at the text section first. That means that when we copy the
+ debugging information, we always know the text address. So we
+ actually do each pass in two sub passes; first the text sections,
+ then the non-text sections. We use the output_has_begun flag to
+ determine whether we have copied over the debugging information
+ yet. */
+
+ /* Do the first pass: set the output section contents and count the
+ debugging information. */
+ ecoff_clear_output_flags (abfd);
+ for (ipass = 0; ipass < 2; ipass++)
+ {
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ /* If this is a fake section, just forget it. The register
+ information is handled in another way. */
+ if (strcmp (o->name, SCOMMON) == 0
+ || strcmp (o->name, REGINFO) == 0)
+ continue;
+
+ /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false,
+ so they are done on pass 0. For other sections the
+ expression is true, so they are done on pass 1. */
+ if (((o->flags & SEC_CODE) == 0) != ipass)
+ continue;
+
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ {
+ if (ecoff_dump_seclet (abfd, p, o, data, relocateable)
+ == false)
+ return false;
+ }
+ }
+ }
+
+ /* We handle the external symbols differently. We use the ones
+ attached to the output_bfd. The linker will have already
+ determined which symbols are to be attached. Here we just
+ determine how much space we will need for them. */
+ sym_ptr_ptr = bfd_get_outsymbols (abfd);
+ if (sym_ptr_ptr != NULL)
+ {
+ asymbol **sym_end;
+
+ sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
+ for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
+ {
+ if (((*sym_ptr_ptr)->flags & BSF_DEBUGGING) == 0
+ && ((*sym_ptr_ptr)->flags & BSF_LOCAL) == 0)
+ {
+ ++symhdr->iextMax;
+ symhdr->issExtMax += strlen ((*sym_ptr_ptr)->name) + 1;
+ }
+ }
+ }
+
+ /* Adjust the counts so that structures are longword aligned. */
+ debug_align = backend->debug_align;
+ --debug_align;
+ symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align;
+ symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align;
+ symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align;
+
+ /* Now the counts in symhdr are the correct size for the debugging
+ information. We allocate the right amount of space, and reset
+ the counts so that the second pass can use them as indices. It
+ would be possible to output the debugging information directly to
+ the file in pass 2, rather than to build it in memory and then
+ write it out. Outputting to the file would require a lot of
+ seeks and small writes, though, and I think this approach is
+ faster. */
+ size = (symhdr->cbLine * sizeof (unsigned char)
+ + symhdr->idnMax * backend->external_dnr_size
+ + symhdr->ipdMax * backend->external_pdr_size
+ + symhdr->isymMax * backend->external_sym_size
+ + symhdr->ioptMax * backend->external_opt_size
+ + symhdr->iauxMax * sizeof (union aux_ext)
+ + symhdr->issMax * sizeof (char)
+ + symhdr->issExtMax * sizeof (char)
+ + symhdr->ifdMax * backend->external_fdr_size
+ + symhdr->crfd * backend->external_rfd_size
+ + symhdr->iextMax * backend->external_ext_size);
+ raw = (char *) bfd_alloc (abfd, size);
+ if (raw == (char *) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ ecoff_data (abfd)->raw_size = size;
+ ecoff_data (abfd)->raw_syments = (PTR) raw;
+
+ /* Initialize the raw pointers. */
+#define SET(field, count, type, size) \
+ ecoff_data (abfd)->field = (type) raw; \
+ raw += symhdr->count * size
+
+ SET (line, cbLine, unsigned char *, sizeof (unsigned char));
+ SET (external_dnr, idnMax, PTR, backend->external_dnr_size);
+ SET (external_pdr, ipdMax, PTR, backend->external_pdr_size);
+ SET (external_sym, isymMax, PTR, backend->external_sym_size);
+ SET (external_opt, ioptMax, PTR, backend->external_opt_size);
+ SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext));
+ SET (ss, issMax, char *, sizeof (char));
+ SET (ssext, issExtMax, char *, sizeof (char));
+ SET (external_fdr, ifdMax, PTR, backend->external_fdr_size);
+ SET (external_rfd, crfd, PTR, backend->external_rfd_size);
+ SET (external_ext, iextMax, PTR, backend->external_ext_size);
+#undef SET
+
+ /* Reset the counts so the second pass can use them to know how far
+ it has gotten. */
+ symhdr->ilineMax = 0;
+ symhdr->cbLine = 0;
+ symhdr->idnMax = 0;
+ symhdr->ipdMax = 0;
+ symhdr->isymMax = 0;
+ symhdr->ioptMax = 0;
+ symhdr->iauxMax = 0;
+ symhdr->issMax = 0;
+ symhdr->issExtMax = 0;
+ symhdr->ifdMax = 0;
+ symhdr->crfd = 0;
+ symhdr->iextMax = 0;
+
+ /* Do the second pass: accumulate the debugging information. */
+ ecoff_clear_output_flags (abfd);
+ for (ipass = 0; ipass < 2; ipass++)
+ {
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ if (strcmp (o->name, SCOMMON) == 0
+ || strcmp (o->name, REGINFO) == 0)
+ continue;
+ if (((o->flags & SEC_CODE) == 0) != ipass)
+ continue;
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_indirect_seclet)
+ {
+ if (ecoff_get_debug (abfd, p, o, relocateable) == false)
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Put in the external symbols. */
+ sym_ptr_ptr = bfd_get_outsymbols (abfd);
+ if (sym_ptr_ptr != NULL)
+ {
+ const bfd_size_type external_ext_size = backend->external_ext_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
+ = backend->swap_ext_out;
+ char *ssext;
+ char *external_ext;
+
+ ssext = ecoff_data (abfd)->ssext;
+ external_ext = (char *) ecoff_data (abfd)->external_ext;
+ for (; *sym_ptr_ptr != NULL; sym_ptr_ptr++)
+ {
+ asymbol *sym_ptr;
+ EXTR esym;
+
+ sym_ptr = *sym_ptr_ptr;
+
+ if ((sym_ptr->flags & BSF_DEBUGGING) != 0
+ || (sym_ptr->flags & BSF_LOCAL) != 0)
+ continue;
+
+ /* The native pointer can be NULL for a symbol created by
+ the linker via ecoff_make_empty_symbol. */
+ if (bfd_asymbol_flavour (sym_ptr) != bfd_target_ecoff_flavour
+ || ecoffsymbol (sym_ptr)->native == NULL)
+ {
+ esym.jmptbl = 0;
+ esym.cobol_main = 0;
+ esym.weakext = 0;
+ esym.reserved = 0;
+ esym.ifd = ifdNil;
+ /* FIXME: we can do better than this for st and sc. */
+ esym.asym.st = stGlobal;
+ esym.asym.sc = scAbs;
+ esym.asym.reserved = 0;
+ esym.asym.index = indexNil;
+ }
+ else
+ {
+ ecoff_symbol_type *ecoff_sym_ptr;
+
+ ecoff_sym_ptr = ecoffsymbol (sym_ptr);
+ if (ecoff_sym_ptr->local)
+ abort ();
+ (*swap_ext_in) (abfd, ecoff_sym_ptr->native, &esym);
+
+ /* If we're producing an executable, move common symbols
+ into bss. */
+ if (relocateable == false)
+ {
+ if (esym.asym.sc == scCommon)
+ esym.asym.sc = scBss;
+ else if (esym.asym.sc == scSCommon)
+ esym.asym.sc = scSBss;
+ }
+
+ /* Adjust the FDR index for the symbol by that used for
+ the input BFD. */
+ esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase;
+ }
+
+ esym.asym.iss = symhdr->issExtMax;
+
+ if (bfd_is_com_section (sym_ptr->section)
+ || sym_ptr->section == &bfd_und_section)
+ esym.asym.value = sym_ptr->value;
+ else
+ esym.asym.value = (sym_ptr->value
+ + sym_ptr->section->output_offset
+ + sym_ptr->section->output_section->vma);
+
+ (*swap_ext_out) (abfd, &esym, external_ext);
+
+ ecoff_set_sym_index (sym_ptr, symhdr->iextMax);
+
+ external_ext += external_ext_size;
+ ++symhdr->iextMax;
+
+ strcpy (ssext + symhdr->issExtMax, sym_ptr->name);
+ symhdr->issExtMax += strlen (sym_ptr->name) + 1;
+ }
+ }
+
+ /* Adjust the counts so that structures are longword aligned. */
+ symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align;
+ symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align;
+ symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align;
+
+ return true;
+}
+
+/* Set the architecture. The supported architecture is stored in the
+ backend pointer. We always set the architecture anyhow, since many
+ callers ignore the return value. */
+
+boolean
+ecoff_set_arch_mach (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ bfd_default_set_arch_mach (abfd, arch, machine);
+ return arch == ecoff_backend (abfd)->arch;
+}
+
+/* Get the size of the section headers. We do not output the .scommon
+ section which we created in ecoff_mkobject, nor do we output any
+ .reginfo section. */
+
+int
+ecoff_sizeof_headers (abfd, reloc)
+ bfd *abfd;
+ boolean reloc;
+{
+ asection *current;
+ int c;
+
+ c = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ if (strcmp (current->name, SCOMMON) != 0
+ && strcmp (current->name, REGINFO) != 0)
+ ++c;
+
+ return (bfd_coff_filhsz (abfd)
+ + bfd_coff_aoutsz (abfd)
+ + c * bfd_coff_scnhsz (abfd));
+}
+
+
+/* Get the contents of a section. This is where we handle reading the
+ .reginfo section, which implicitly holds the contents of an
+ ecoff_reginfo structure. */
+
+boolean
+ecoff_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ ecoff_data_type *tdata = ecoff_data (abfd);
+ struct ecoff_reginfo s;
+ int i;
+
+ if (strcmp (section->name, REGINFO) != 0)
+ return bfd_generic_get_section_contents (abfd, section, location,
+ offset, count);
+
+ s.gp_value = tdata->gp;
+ s.gprmask = tdata->gprmask;
+ for (i = 0; i < 4; i++)
+ s.cprmask[i] = tdata->cprmask[i];
+ s.fprmask = tdata->fprmask;
+
+ /* bfd_get_section_contents has already checked that the offset and
+ size is reasonable. We don't have to worry about swapping or any
+ such thing; the .reginfo section is defined such that the
+ contents are an ecoff_reginfo structure as seen on the host. */
+ memcpy (location, ((char *) &s) + offset, count);
+ return true;
+}
+
+/* Calculate the file position for each section, and set
+ reloc_filepos. */
+
+static void
+ecoff_compute_section_file_positions (abfd)
+ bfd *abfd;
+{
+ asection *current;
+ file_ptr sofar;
+ file_ptr old_sofar;
+ boolean first_data;
+
+ if (bfd_get_start_address (abfd))
+ abfd->flags |= EXEC_P;
+
+ sofar = ecoff_sizeof_headers (abfd, false);
+
+ first_data = true;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ /* Only deal with sections which have contents */
+ if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0
+ || strcmp (current->name, SCOMMON) == 0
+ || strcmp (current->name, REGINFO) == 0)
+ continue;
+
+ /* On Ultrix, the data sections in an executable file must be
+ aligned to a page boundary within the file. This does not
+ affect the section size, though. FIXME: Does this work for
+ other platforms? */
+ if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0
+ && first_data != false
+ && (current->flags & SEC_CODE) == 0)
+ {
+ const bfd_vma round = ecoff_backend (abfd)->round;
+
+ sofar = (sofar + round - 1) &~ (round - 1);
+ first_data = false;
+ }
+
+ /* Align the sections in the file to the same boundary on
+ which they are aligned in virtual memory. */
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+
+ current->filepos = sofar;
+
+ sofar += current->_raw_size;
+
+ /* make sure that this section is of the right size too */
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+ current->_raw_size += sofar - old_sofar;
+ }
+
+ ecoff_data (abfd)->reloc_filepos = sofar;
+}
+
+/* Set the contents of a section. This is where we handle setting the
+ contents of the .reginfo section, which implicitly holds a
+ ecoff_reginfo structure. */
+
+boolean
+ecoff_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (abfd->output_has_begun == false)
+ ecoff_compute_section_file_positions (abfd);
+
+ if (strcmp (section->name, REGINFO) == 0)
+ {
+ ecoff_data_type *tdata = ecoff_data (abfd);
+ struct ecoff_reginfo s;
+ int i;
+
+ /* If the caller is only changing part of the structure, we must
+ retrieve the current information before the memcpy. */
+ if (offset != 0 || count != sizeof (struct ecoff_reginfo))
+ {
+ s.gp_value = tdata->gp;
+ s.gprmask = tdata->gprmask;
+ for (i = 0; i < 4; i++)
+ s.cprmask[i] = tdata->cprmask[i];
+ s.fprmask = tdata->fprmask;
+ }
+
+ /* bfd_set_section_contents has already checked that the offset
+ and size is reasonable. We don't have to worry about
+ swapping or any such thing; the .reginfo section is defined
+ such that the contents are an ecoff_reginfo structure as seen
+ on the host. */
+ memcpy (((char *) &s) + offset, location, count);
+
+ tdata->gp = s.gp_value;
+ tdata->gprmask = s.gprmask;
+ for (i = 0; i < 4; i++)
+ tdata->cprmask[i] = s.cprmask[i];
+ tdata->fprmask = s.fprmask;
+
+ return true;
+
+ }
+
+ bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET);
+
+ if (count != 0)
+ return (bfd_write (location, 1, count, abfd) == count) ? true : false;
+
+ return true;
+}
+
+/* Write out an ECOFF file. */
+
+boolean
+ecoff_write_object_contents (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ const bfd_vma round = backend->round;
+ const bfd_size_type filhsz = bfd_coff_filhsz (abfd);
+ const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd);
+ const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd);
+ const bfd_size_type external_hdr_size = backend->external_hdr_size;
+ const bfd_size_type external_reloc_size = backend->external_reloc_size;
+ void (* const swap_reloc_out) PARAMS ((bfd *,
+ const struct internal_reloc *,
+ PTR))
+ = backend->swap_reloc_out;
+ asection *current;
+ unsigned int count;
+ file_ptr scn_base;
+ file_ptr reloc_base;
+ file_ptr sym_base;
+ unsigned long reloc_size;
+ unsigned long text_size;
+ unsigned long text_start;
+ unsigned long data_size;
+ unsigned long data_start;
+ unsigned long bss_size;
+ PTR buff;
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+ int i;
+
+ bfd_error = system_call_error;
+
+ if(abfd->output_has_begun == false)
+ ecoff_compute_section_file_positions(abfd);
+
+ if (abfd->sections != (asection *) NULL)
+ scn_base = abfd->sections->filepos;
+ else
+ scn_base = 0;
+ reloc_base = ecoff_data (abfd)->reloc_filepos;
+
+ count = 1;
+ reloc_size = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ {
+ if (strcmp (current->name, SCOMMON) == 0
+ || strcmp (current->name, REGINFO) == 0)
+ continue;
+ current->target_index = count;
+ ++count;
+ if (current->reloc_count != 0)
+ {
+ bfd_size_type relsize;
+
+ current->rel_filepos = reloc_base;
+ relsize = current->reloc_count * external_reloc_size;
+ reloc_size += relsize;
+ reloc_base += relsize;
+ }
+ else
+ current->rel_filepos = 0;
+ }
+
+ sym_base = reloc_base + reloc_size;
+
+ /* At least on Ultrix, the symbol table of an executable file must
+ be aligned to a page boundary. FIXME: Is this true on other
+ platforms? */
+ if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0)
+ sym_base = (sym_base + round - 1) &~ (round - 1);
+
+ ecoff_data (abfd)->sym_filepos = sym_base;
+
+ if ((abfd->flags & D_PAGED) != 0)
+ text_size = ecoff_sizeof_headers (abfd, false);
+ else
+ text_size = 0;
+ text_start = 0;
+ data_size = 0;
+ data_start = 0;
+ bss_size = 0;
+
+ /* Write section headers to the file. */
+
+ buff = (PTR) alloca (scnhsz);
+ internal_f.f_nscns = 0;
+ if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0)
+ return false;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ struct internal_scnhdr section;
+ bfd_vma vma;
+
+ if (strcmp (current->name, SCOMMON) == 0)
+ {
+ BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0
+ && current->reloc_count == 0);
+ continue;
+ }
+ if (strcmp (current->name, REGINFO) == 0)
+ {
+ BFD_ASSERT (current->reloc_count == 0);
+ continue;
+ }
+
+ ++internal_f.f_nscns;
+
+ strncpy (section.s_name, current->name, sizeof section.s_name);
+
+ /* FIXME: is this correct for shared libraries? I think it is
+ but I have no platform to check. Ian Lance Taylor. */
+ vma = bfd_get_section_vma (abfd, current);
+ if (strcmp (current->name, _LIB) == 0)
+ section.s_vaddr = 0;
+ else
+ section.s_vaddr = vma;
+
+ section.s_paddr = vma;
+ section.s_size = bfd_get_section_size_before_reloc (current);
+
+ /* If this section is unloadable then the scnptr will be 0. */
+ if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ section.s_scnptr = 0;
+ else
+ section.s_scnptr = current->filepos;
+ section.s_relptr = current->rel_filepos;
+
+ /* FIXME: the lnnoptr of the .sbss or .sdata section of an
+ object file produced by the assembler is supposed to point to
+ information about how much room is required by objects of
+ various different sizes. I think this only matters if we
+ want the linker to compute the best size to use, or
+ something. I don't know what happens if the information is
+ not present. */
+ section.s_lnnoptr = 0;
+
+ section.s_nreloc = current->reloc_count;
+ section.s_nlnno = 0;
+ section.s_flags = ecoff_sec_to_styp_flags (current->name,
+ current->flags);
+
+ bfd_coff_swap_scnhdr_out (abfd, (PTR) &section, buff);
+ if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz)
+ return false;
+
+ if ((section.s_flags & STYP_TEXT) != 0)
+ {
+ text_size += bfd_get_section_size_before_reloc (current);
+ if (text_start == 0 || text_start > vma)
+ text_start = vma;
+ }
+ else if ((section.s_flags & STYP_RDATA) != 0
+ || (section.s_flags & STYP_DATA) != 0
+ || (section.s_flags & STYP_LIT8) != 0
+ || (section.s_flags & STYP_LIT4) != 0
+ || (section.s_flags & STYP_SDATA) != 0)
+ {
+ data_size += bfd_get_section_size_before_reloc (current);
+ if (data_start == 0 || data_start > vma)
+ data_start = vma;
+ }
+ else if ((section.s_flags & STYP_BSS) != 0
+ || (section.s_flags & STYP_SBSS) != 0)
+ bss_size += bfd_get_section_size_before_reloc (current);
+ }
+
+ /* Set up the file header. */
+
+ internal_f.f_magic = ecoff_get_magic (abfd);
+
+ /* We will NOT put a fucking timestamp in the header here. Every
+ time you put it back, I will come in and take it out again. I'm
+ sorry. This field does not belong here. We fill it with a 0 so
+ it compares the same but is not a reasonable time. --
+ gnu@cygnus.com. */
+ internal_f.f_timdat = 0;
+
+ if (bfd_get_symcount (abfd) != 0)
+ {
+ /* The ECOFF f_nsyms field is not actually the number of
+ symbols, it's the size of symbolic information header. */
+ internal_f.f_nsyms = external_hdr_size;
+ internal_f.f_symptr = sym_base;
+ }
+ else
+ {
+ internal_f.f_nsyms = 0;
+ internal_f.f_symptr = 0;
+ }
+
+ internal_f.f_opthdr = aoutsz;
+
+ internal_f.f_flags = F_LNNO;
+ if (reloc_size == 0)
+ internal_f.f_flags |= F_RELFLG;
+ if (bfd_get_symcount (abfd) == 0)
+ internal_f.f_flags |= F_LSYMS;
+ if (abfd->flags & EXEC_P)
+ internal_f.f_flags |= F_EXEC;
+
+ if (! abfd->xvec->byteorder_big_p)
+ internal_f.f_flags |= F_AR32WR;
+ else
+ internal_f.f_flags |= F_AR32W;
+
+ /* Set up the ``optional'' header. */
+ if ((abfd->flags & D_PAGED) != 0)
+ internal_a.magic = ECOFF_AOUT_ZMAGIC;
+ else
+ internal_a.magic = ECOFF_AOUT_OMAGIC;
+
+ /* FIXME: This is what Ultrix puts in, and it makes the Ultrix
+ linker happy. But, is it right? */
+ internal_a.vstamp = 0x20a;
+
+ /* At least on Ultrix, these have to be rounded to page boundaries.
+ FIXME: Is this true on other platforms? */
+ if ((abfd->flags & D_PAGED) != 0)
+ {
+ internal_a.tsize = (text_size + round - 1) &~ (round - 1);
+ internal_a.text_start = text_start &~ (round - 1);
+ internal_a.dsize = (data_size + round - 1) &~ (round - 1);
+ internal_a.data_start = data_start &~ (round - 1);
+ }
+ else
+ {
+ internal_a.tsize = text_size;
+ internal_a.text_start = text_start;
+ internal_a.dsize = data_size;
+ internal_a.data_start = data_start;
+ }
+
+ /* On Ultrix, the initial portions of the .sbss and .bss segments
+ are at the end of the data section. The bsize field in the
+ optional header records how many bss bytes are required beyond
+ those in the data section. The value is not rounded to a page
+ boundary. */
+ if (bss_size < internal_a.dsize - data_size)
+ bss_size = 0;
+ else
+ bss_size -= internal_a.dsize - data_size;
+ internal_a.bsize = bss_size;
+ internal_a.bss_start = internal_a.data_start + internal_a.dsize;
+
+ internal_a.entry = bfd_get_start_address (abfd);
+
+ internal_a.gp_value = ecoff_data (abfd)->gp;
+
+ internal_a.gprmask = ecoff_data (abfd)->gprmask;
+ internal_a.fprmask = ecoff_data (abfd)->fprmask;
+ for (i = 0; i < 4; i++)
+ internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i];
+
+ /* Write out the file header and the optional header. */
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+
+ buff = (PTR) alloca (filhsz);
+ bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff);
+ if (bfd_write (buff, 1, filhsz, abfd) != filhsz)
+ return false;
+
+ buff = (PTR) alloca (aoutsz);
+ bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff);
+ if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz)
+ return false;
+
+ /* Write out the relocs. */
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ arelent **reloc_ptr_ptr;
+ arelent **reloc_end;
+ char *out_ptr;
+
+ if (current->reloc_count == 0)
+ continue;
+
+ buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size);
+ if (buff == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ reloc_ptr_ptr = current->orelocation;
+ reloc_end = reloc_ptr_ptr + current->reloc_count;
+ out_ptr = (char *) buff;
+ for (;
+ reloc_ptr_ptr < reloc_end;
+ reloc_ptr_ptr++, out_ptr += external_reloc_size)
+ {
+ arelent *reloc;
+ asymbol *sym;
+ struct internal_reloc in;
+
+ memset (&in, 0, sizeof in);
+
+ reloc = *reloc_ptr_ptr;
+ sym = *reloc->sym_ptr_ptr;
+
+ in.r_vaddr = reloc->address + bfd_get_section_vma (abfd, current);
+ in.r_type = reloc->howto->type;
+
+ if ((sym->flags & BSF_SECTION_SYM) == 0)
+ {
+ in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr);
+ in.r_extern = 1;
+ }
+ else
+ {
+ CONST char *name;
+
+ name = bfd_get_section_name (abfd, bfd_get_section (sym));
+ if (strcmp (name, ".text") == 0)
+ in.r_symndx = RELOC_SECTION_TEXT;
+ else if (strcmp (name, ".rdata") == 0)
+ in.r_symndx = RELOC_SECTION_RDATA;
+ else if (strcmp (name, ".data") == 0)
+ in.r_symndx = RELOC_SECTION_DATA;
+ else if (strcmp (name, ".sdata") == 0)
+ in.r_symndx = RELOC_SECTION_SDATA;
+ else if (strcmp (name, ".sbss") == 0)
+ in.r_symndx = RELOC_SECTION_SBSS;
+ else if (strcmp (name, ".bss") == 0)
+ in.r_symndx = RELOC_SECTION_BSS;
+ else if (strcmp (name, ".init") == 0)
+ in.r_symndx = RELOC_SECTION_INIT;
+ else if (strcmp (name, ".lit8") == 0)
+ in.r_symndx = RELOC_SECTION_LIT8;
+ else if (strcmp (name, ".lit4") == 0)
+ in.r_symndx = RELOC_SECTION_LIT4;
+ else
+ abort ();
+ in.r_extern = 0;
+ }
+
+ (*swap_reloc_out) (abfd, &in, (PTR) out_ptr);
+ }
+
+ if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0)
+ return false;
+ if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd)
+ != external_reloc_size * current->reloc_count)
+ return false;
+ bfd_release (abfd, buff);
+ }
+
+ /* Write out the symbolic debugging information. */
+ if (bfd_get_symcount (abfd) > 0)
+ {
+ HDRR *symhdr;
+ unsigned long sym_offset;
+
+ /* Set up the offsets in the symbolic header. */
+ symhdr = &ecoff_data (abfd)->symbolic_header;
+ sym_offset = ecoff_data (abfd)->sym_filepos + external_hdr_size;
+
+#define SET(offset, size, ptr) \
+ if (symhdr->size == 0) \
+ symhdr->offset = 0; \
+ else \
+ symhdr->offset = (((char *) ecoff_data (abfd)->ptr \
+ - (char *) ecoff_data (abfd)->raw_syments) \
+ + sym_offset);
+
+ SET (cbLineOffset, cbLine, line);
+ SET (cbDnOffset, idnMax, external_dnr);
+ SET (cbPdOffset, ipdMax, external_pdr);
+ SET (cbSymOffset, isymMax, external_sym);
+ SET (cbOptOffset, ioptMax, external_opt);
+ SET (cbAuxOffset, iauxMax, external_aux);
+ SET (cbSsOffset, issMax, ss);
+ SET (cbSsExtOffset, issExtMax, ssext);
+ SET (cbFdOffset, ifdMax, external_fdr);
+ SET (cbRfdOffset, crfd, external_rfd);
+ SET (cbExtOffset, iextMax, external_ext);
+#undef SET
+
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos,
+ SEEK_SET) != 0)
+ return false;
+ buff = (PTR) alloca (external_hdr_size);
+ (*backend->swap_hdr_out) (abfd, &ecoff_data (abfd)->symbolic_header,
+ buff);
+ if (bfd_write (buff, 1, external_hdr_size, abfd) != external_hdr_size)
+ return false;
+ if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1,
+ ecoff_data (abfd)->raw_size, abfd)
+ != ecoff_data (abfd)->raw_size)
+ return false;
+ }
+ else if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0)
+ {
+ char c;
+
+ /* A demand paged executable must occupy an even number of
+ pages. */
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
+ SEEK_SET) != 0)
+ return false;
+ if (bfd_read (&c, 1, 1, abfd) == 0)
+ c = 0;
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
+ SEEK_SET) != 0)
+ return false;
+ if (bfd_write (&c, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/* Archive handling. ECOFF uses what appears to be a unique type of
+ archive header (which I call an armap). The byte ordering of the
+ armap and the contents are encoded in the name of the armap itself.
+ At least for now, we only support archives with the same byte
+ ordering in the armap and the contents.
+
+ The first four bytes in the armap are the number of symbol
+ definitions. This is always a power of two.
+
+ This is followed by the symbol definitions. Each symbol definition
+ occupies 8 bytes. The first four bytes are the offset from the
+ start of the armap strings to the null-terminated string naming
+ this symbol. The second four bytes are the file offset to the
+ archive member which defines this symbol. If the second four bytes
+ are 0, then this is not actually a symbol definition, and it should
+ be ignored.
+
+ The symbols are hashed into the armap with a closed hashing scheme.
+ See the functions below for the details of the algorithm.
+
+ We could use the hash table when looking up symbols in a library.
+ This would require a new BFD target entry point to replace the
+ bfd_get_next_mapent function used by the linker.
+
+ After the symbol definitions comes four bytes holding the size of
+ the string table, followed by the string table itself. */
+
+/* The name of an archive headers looks like this:
+ __________E[BL]E[BL]_ (with a trailing space).
+ The trailing space is changed to an X if the archive is changed to
+ indicate that the armap is out of date.
+
+ The Alpha seems to use ________64E[BL]E[BL]_. */
+
+#define ARMAP_BIG_ENDIAN 'B'
+#define ARMAP_LITTLE_ENDIAN 'L'
+#define ARMAP_MARKER 'E'
+#define ARMAP_START_LENGTH 10
+#define ARMAP_HEADER_MARKER_INDEX 10
+#define ARMAP_HEADER_ENDIAN_INDEX 11
+#define ARMAP_OBJECT_MARKER_INDEX 12
+#define ARMAP_OBJECT_ENDIAN_INDEX 13
+#define ARMAP_END_INDEX 14
+#define ARMAP_END "_ "
+
+/* This is a magic number used in the hashing algorithm. */
+#define ARMAP_HASH_MAGIC 0x9dd68ab5
+
+/* This returns the hash value to use for a string. It also sets
+ *REHASH to the rehash adjustment if the first slot is taken. SIZE
+ is the number of entries in the hash table, and HLOG is the log
+ base 2 of SIZE. */
+
+static unsigned int
+ecoff_armap_hash (s, rehash, size, hlog)
+ CONST char *s;
+ unsigned int *rehash;
+ unsigned int size;
+ unsigned int hlog;
+{
+ unsigned int hash;
+
+ hash = *s++;
+ while (*s != '\0')
+ hash = ((hash >> 27) | (hash << 5)) + *s++;
+ hash *= ARMAP_HASH_MAGIC;
+ *rehash = (hash & (size - 1)) | 1;
+ return hash >> (32 - hlog);
+}
+
+/* Read in the armap. */
+
+boolean
+ecoff_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ unsigned int i;
+ struct areltdata *mapdata;
+ bfd_size_type parsed_size;
+ char *raw_armap;
+ struct artdata *ardata;
+ unsigned int count;
+ char *raw_ptr;
+ struct symdef *symdef_ptr;
+ char *stringbase;
+
+ /* Get the name of the first element. */
+ i = bfd_read ((PTR) nextname, 1, 16, abfd);
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ /* Irix 4.0.5F apparently can use either an ECOFF armap or a
+ standard COFF armap. We could move the ECOFF armap stuff into
+ bfd_slurp_armap, but that seems inappropriate since no other
+ target uses this format. Instead, we check directly for a COFF
+ armap. */
+ if (strncmp (nextname, "/ ", 16) == 0)
+ return bfd_slurp_armap (abfd);
+
+ /* See if the first element is an armap. */
+ if (strncmp (nextname, ecoff_backend (abfd)->armap_start,
+ ARMAP_START_LENGTH) != 0
+ || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER
+ || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
+ && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
+ || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER
+ || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
+ && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
+ || strncmp (nextname + ARMAP_END_INDEX,
+ ARMAP_END, sizeof ARMAP_END - 1) != 0)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ /* Make sure we have the right byte ordering. */
+ if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
+ ^ (abfd->xvec->header_byteorder_big_p != false))
+ || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
+ ^ (abfd->xvec->byteorder_big_p != false)))
+ {
+ bfd_error = wrong_format;
+ return false;
+ }
+
+ /* Read in the armap. */
+ ardata = bfd_ardata (abfd);
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == (struct areltdata *) NULL)
+ return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR) mapdata);
+
+ raw_armap = (char *) bfd_alloc (abfd, parsed_size);
+ if (raw_armap == (char *) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size)
+ {
+ bfd_error = malformed_archive;
+ bfd_release (abfd, (PTR) raw_armap);
+ return false;
+ }
+
+ count = bfd_h_get_32 (abfd, (PTR) raw_armap);
+
+ ardata->symdef_count = 0;
+ ardata->cache = (struct ar_cache *) NULL;
+
+ /* This code used to overlay the symdefs over the raw archive data,
+ but that doesn't work on a 64 bit host. */
+
+ stringbase = raw_armap + count * 8 + 8;
+
+#ifdef CHECK_ARMAP_HASH
+ {
+ unsigned int hlog;
+
+ /* Double check that I have the hashing algorithm right by making
+ sure that every symbol can be looked up successfully. */
+ hlog = 0;
+ for (i = 1; i < count; i <<= 1)
+ hlog++;
+ BFD_ASSERT (i == count);
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ {
+ unsigned int name_offset, file_offset;
+ unsigned int hash, rehash, srch;
+
+ name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+ file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4));
+ if (file_offset == 0)
+ continue;
+ hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count,
+ hlog);
+ if (hash == i)
+ continue;
+
+ /* See if we can rehash to this location. */
+ for (srch = (hash + rehash) & (count - 1);
+ srch != hash && srch != i;
+ srch = (srch + rehash) & (count - 1))
+ BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8))
+ != 0);
+ BFD_ASSERT (srch == i);
+ }
+ }
+
+#endif /* CHECK_ARMAP_HASH */
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0)
+ ++ardata->symdef_count;
+
+ symdef_ptr = ((struct symdef *)
+ bfd_alloc (abfd,
+ ardata->symdef_count * sizeof (struct symdef)));
+ ardata->symdefs = (carsym *) symdef_ptr;
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ {
+ unsigned int name_offset, file_offset;
+
+ file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4));
+ if (file_offset == 0)
+ continue;
+ name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+ symdef_ptr->s.name = stringbase + name_offset;
+ symdef_ptr->file_offset = file_offset;
+ ++symdef_ptr;
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary. */
+ ardata->first_file_filepos += ardata->first_file_filepos % 2;
+
+ bfd_has_map (abfd) = true;
+
+ return true;
+}
+
+/* Write out an armap. */
+
+boolean
+ecoff_write_armap (abfd, elength, map, orl_count, stridx)
+ bfd *abfd;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ unsigned int hashsize, hashlog;
+ unsigned int symdefsize;
+ int padit;
+ unsigned int stringsize;
+ unsigned int mapsize;
+ file_ptr firstreal;
+ struct ar_hdr hdr;
+ struct stat statbuf;
+ unsigned int i;
+ bfd_byte temp[4];
+ bfd_byte *hashtable;
+ bfd *current;
+ bfd *last_elt;
+
+ /* Ultrix appears to use as a hash table size the least power of two
+ greater than twice the number of entries. */
+ for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++)
+ ;
+ hashsize = 1 << hashlog;
+
+ symdefsize = hashsize * 8;
+ padit = stridx % 2;
+ stringsize = stridx + padit;
+
+ /* Include 8 bytes to store symdefsize and stringsize in output. */
+ mapsize = symdefsize + stringsize + 8;
+
+ firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength;
+
+ memset ((PTR) &hdr, 0, sizeof hdr);
+
+ /* Work out the ECOFF armap name. */
+ strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start);
+ hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER;
+ hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] =
+ (abfd->xvec->header_byteorder_big_p
+ ? ARMAP_BIG_ENDIAN
+ : ARMAP_LITTLE_ENDIAN);
+ hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER;
+ hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] =
+ abfd->xvec->byteorder_big_p ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN;
+ memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1);
+
+ /* Write the timestamp of the archive header to be just a little bit
+ later than the timestamp of the file, otherwise the linker will
+ complain that the index is out of date. Actually, the Ultrix
+ linker just checks the archive name; the GNU linker may check the
+ date. */
+ stat (abfd->filename, &statbuf);
+ sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60));
+
+ /* The DECstation uses zeroes for the uid, gid and mode of the
+ armap. */
+ hdr.ar_uid[0] = '0';
+ hdr.ar_gid[0] = '0';
+ hdr.ar_mode[0] = '0';
+
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+
+ hdr.ar_fmag[0] = '`';
+ hdr.ar_fmag[1] = '\n';
+
+ /* Turn all null bytes in the header into spaces. */
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0')
+ (((char *)(&hdr))[i]) = ' ';
+
+ if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd)
+ != sizeof (struct ar_hdr))
+ return false;
+
+ bfd_h_put_32 (abfd, hashsize, temp);
+ if (bfd_write (temp, 1, 4, abfd) != 4)
+ return false;
+
+ hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
+
+ current = abfd->archive_head;
+ last_elt = current;
+ for (i = 0; i < orl_count; i++)
+ {
+ unsigned int hash, rehash;
+
+ /* Advance firstreal to the file position of this archive
+ element. */
+ if (((bfd *) map[i].pos) != last_elt)
+ {
+ do
+ {
+ firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ firstreal += firstreal % 2;
+ current = current->next;
+ }
+ while (current != (bfd *) map[i].pos);
+ }
+
+ last_elt = current;
+
+ hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog);
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0)
+ {
+ unsigned int srch;
+
+ /* The desired slot is already taken. */
+ for (srch = (hash + rehash) & (hashsize - 1);
+ srch != hash;
+ srch = (srch + rehash) & (hashsize - 1))
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0)
+ break;
+
+ BFD_ASSERT (srch != hash);
+
+ hash = srch;
+ }
+
+ bfd_h_put_32 (abfd, map[i].namidx, (PTR) (hashtable + hash * 8));
+ bfd_h_put_32 (abfd, firstreal, (PTR) (hashtable + hash * 8 + 4));
+ }
+
+ if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize)
+ return false;
+
+ bfd_release (abfd, hashtable);
+
+ /* Now write the strings. */
+ bfd_h_put_32 (abfd, stringsize, temp);
+ if (bfd_write (temp, 1, 4, abfd) != 4)
+ return false;
+ for (i = 0; i < orl_count; i++)
+ {
+ bfd_size_type len;
+
+ len = strlen (*map[i].name) + 1;
+ if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len)
+ return false;
+ }
+
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for DECstation ar we use a null. */
+ if (padit)
+ {
+ if (bfd_write ("\0", 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/* See whether this BFD is an archive. If it is, read in the armap
+ and the extended name table. */
+
+bfd_target *
+ecoff_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG + 1];
+
+ if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG
+ || strncmp (armag, ARMAG, SARMAG) != 0)
+ {
+ bfd_error = wrong_format;
+ return (bfd_target *) NULL;
+ }
+
+ /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
+ involves a cast, we can't do it as the left operand of
+ assignment. */
+ abfd->tdata.aout_ar_data =
+ (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata));
+
+ if (bfd_ardata (abfd) == (struct artdata *) NULL)
+ {
+ bfd_error = no_memory;
+ return (bfd_target *) NULL;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+
+ if (ecoff_slurp_armap (abfd) == false
+ || ecoff_slurp_extended_name_table (abfd) == false)
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = (struct artdata *) NULL;
+ return (bfd_target *) NULL;
+ }
+
+ return abfd->xvec;
+}
diff --git a/gnu/usr.bin/gdb/bfd/elf.c b/gnu/usr.bin/gdb/bfd/elf.c
new file mode 100644
index 000000000000..2fcf2f143439
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf.c
@@ -0,0 +1,248 @@
+/* ELF executable support for BFD.
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+SECTION
+ ELF backends
+
+ BFD support for ELF formats is being worked on.
+ Currently, the best supported back ends are for sparc and i386
+ (running svr4 or Solaris 2).
+
+ Documentation of the internals of the support code still needs
+ to be written. The code is changing quickly enough that we
+ haven't bothered yet.
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#define ARCH_SIZE 0
+#include "libelf.h"
+
+/* Standard ELF hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. (Well, you would if this
+ were being used yet.) */
+unsigned long
+DEFUN (bfd_elf_hash, (name),
+ CONST unsigned char *name)
+{
+ unsigned long h = 0;
+ unsigned long g;
+ int ch;
+
+ while ((ch = *name++) != '\0')
+ {
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0)
+ {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ }
+ return h;
+}
+
+/* Read a specified number of bytes at a specified offset in an ELF
+ file, into a newly allocated buffer, and return a pointer to the
+ buffer. */
+
+static char *
+DEFUN (elf_read, (abfd, offset, size),
+ bfd * abfd AND
+ long offset AND
+ int size)
+{
+ char *buf;
+
+ if ((buf = bfd_alloc (abfd, size)) == NULL)
+ {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ if (bfd_seek (abfd, offset, SEEK_SET) == -1)
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ if (bfd_read ((PTR) buf, size, 1, abfd) != size)
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ return buf;
+}
+
+boolean
+DEFUN (elf_mkobject, (abfd), bfd * abfd)
+{
+ /* this just does initialization */
+ /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */
+ elf_tdata (abfd) = (struct elf_obj_tdata *)
+ bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+ if (elf_tdata (abfd) == 0)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ /* since everything is done at close time, do we need any
+ initialization? */
+
+ return true;
+}
+
+char *
+DEFUN (elf_get_str_section, (abfd, shindex),
+ bfd * abfd AND
+ unsigned int shindex)
+{
+ Elf_Internal_Shdr **i_shdrp;
+ char *shstrtab = NULL;
+ unsigned int offset;
+ unsigned int shstrtabsize;
+
+ i_shdrp = elf_elfsections (abfd);
+ if (i_shdrp == 0 || i_shdrp[shindex] == 0)
+ return 0;
+
+ shstrtab = i_shdrp[shindex]->rawdata;
+ if (shstrtab == NULL)
+ {
+ /* No cached one, attempt to read, and cache what we read. */
+ offset = i_shdrp[shindex]->sh_offset;
+ shstrtabsize = i_shdrp[shindex]->sh_size;
+ shstrtab = elf_read (abfd, offset, shstrtabsize);
+ i_shdrp[shindex]->rawdata = (void *) shstrtab;
+ }
+ return shstrtab;
+}
+
+char *
+DEFUN (elf_string_from_elf_section, (abfd, shindex, strindex),
+ bfd * abfd AND
+ unsigned int shindex AND
+ unsigned int strindex)
+{
+ Elf_Internal_Shdr *hdr;
+
+ if (strindex == 0)
+ return "";
+
+ hdr = elf_elfsections (abfd)[shindex];
+
+ if (!hdr->rawdata
+ && elf_get_str_section (abfd, shindex) == NULL)
+ return NULL;
+
+ return ((char *) hdr->rawdata) + strindex;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_elf_find_section
+
+SYNOPSIS
+ struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name);
+
+DESCRIPTION
+ Helper functions for GDB to locate the string tables.
+ Since BFD hides string tables from callers, GDB needs to use an
+ internal hook to find them. Sun's .stabstr, in particular,
+ isn't even pointed to by the .stab section, so ordinary
+ mechanisms wouldn't work to find it, even if we had some.
+*/
+
+struct elf_internal_shdr *
+DEFUN (bfd_elf_find_section, (abfd, name),
+ bfd * abfd AND
+ char *name)
+{
+ Elf_Internal_Shdr **i_shdrp;
+ char *shstrtab;
+ unsigned int max;
+ unsigned int i;
+
+ i_shdrp = elf_elfsections (abfd);
+ if (i_shdrp != NULL)
+ {
+ shstrtab = elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx);
+ if (shstrtab != NULL)
+ {
+ max = elf_elfheader (abfd)->e_shnum;
+ for (i = 1; i < max; i++)
+ if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name))
+ return i_shdrp[i];
+ }
+ }
+ return 0;
+}
+
+const struct bfd_elf_arch_map bfd_elf_arch_map[] = {
+ { bfd_arch_sparc, EM_SPARC },
+ { bfd_arch_i386, EM_386 },
+ { bfd_arch_m68k, EM_68K },
+ { bfd_arch_m88k, EM_88K },
+ { bfd_arch_i860, EM_860 },
+ { bfd_arch_mips, EM_MIPS },
+ { bfd_arch_hppa, EM_HPPA },
+};
+
+const int bfd_elf_arch_map_size = sizeof (bfd_elf_arch_map) / sizeof (bfd_elf_arch_map[0]);
+
+const char *const bfd_elf_section_type_names[] = {
+ "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
+ "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
+ "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
+};
+
+/* ELF relocs are against symbols. If we are producing relocateable
+ output, and the reloc is against an external symbol, and nothing
+ has given us any additional addend, the resulting reloc will also
+ be against the same symbol. In such a case, we don't want to
+ change anything about the way the reloc is handled, since it will
+ all be done at final link time. Rather than put special case code
+ into bfd_perform_relocation, all the reloc types use this howto
+ function. It just short circuits the reloc if producing
+ relocateable output against an external symbol. */
+
+bfd_reloc_status_type
+bfd_elf_generic_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+{
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ return bfd_reloc_continue;
+}
diff --git a/gnu/usr.bin/gdb/bfd/format.c b/gnu/usr.bin/gdb/bfd/format.c
new file mode 100644
index 000000000000..6a80ed7082ae
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/format.c
@@ -0,0 +1,258 @@
+/* Generic BFD support for file formats.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ File Formats
+
+ A format is a BFD concept of high level file contents. The
+ formats supported by BFD are:
+
+ o bfd_object
+
+ The BFD may contain data, symbols, relocations and debug info.
+
+ o bfd_archive
+
+ The BFD contains other BFDs and an optional index.
+
+ o bfd_core
+
+ The BFD contains the result of an executable core dump.
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+extern bfd_target *target_vector[];
+extern bfd_target *default_vector[];
+
+
+/*
+FUNCTION
+ bfd_check_format
+
+SYNOPSIS
+ boolean bfd_check_format(bfd *abfd, bfd_format format);
+
+DESCRIPTION
+ This routine is supplied a BFD and a format. It attempts to
+ verify if the file attached to the BFD is indeed compatible
+ with the format specified (ie, one of <<bfd_object>>,
+ <<bfd_archive>> or <<bfd_core>>).
+
+ If the BFD has been set to a specific @var{target} before the
+ call, only the named target and format combination will be
+ checked. If the target has not been set, or has been set to
+ <<default>> then all the known target backends will be
+ interrogated to determine a match. If the default target
+ matches, it is used. If not, exactly one target must recognize
+ the file, or an error results.
+
+ The function returns <<true>> on success, otherwise <<false>>
+ with one of the following error codes:
+
+ o invalid_operation -
+ if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or
+ <<bfd_core>>.
+
+ o system_call_error -
+ if an error occured during a read - even some file mismatches
+ can cause system_call_errors
+
+ o file_not_recognised -
+ none of the backends recognised the file format
+
+ o file_ambiguously_recognized -
+ more than one backend recognised the file format.
+
+*/
+
+boolean
+DEFUN(bfd_check_format,(abfd, format),
+ bfd *abfd AND
+ bfd_format format)
+{
+ bfd_target **target, *save_targ, *right_targ;
+ int match_count;
+
+ if (!bfd_read_p (abfd) ||
+ ((int)(abfd->format) < (int)bfd_unknown) ||
+ ((int)(abfd->format) >= (int)bfd_type_end)) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ if (abfd->format != bfd_unknown)
+ return (abfd->format == format)? true: false;
+
+
+ /* Since the target type was defaulted, check them
+ all in the hope that one will be uniquely recognized. */
+
+ save_targ = abfd->xvec;
+ match_count = 0;
+ right_targ = 0;
+
+
+ /* presume the answer is yes */
+ abfd->format = format;
+
+ /* If the target type was explicitly specified, just check that target. */
+
+ if (!abfd->target_defaulted) {
+ bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */
+
+ right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (right_targ) {
+ abfd->xvec = right_targ; /* Set the target as returned */
+ return true; /* File position has moved, BTW */
+ }
+ }
+
+ for (target = target_vector; *target != NULL; target++) {
+ bfd_target *temp;
+
+ abfd->xvec = *target; /* Change BFD's target temporarily */
+ bfd_seek (abfd, (file_ptr)0, SEEK_SET);
+ /* If _bfd_check_format neglects to set bfd_error, assume wrong_format.
+ We didn't used to even pay any attention to bfd_error, so I suspect
+ that some _bfd_check_format might have this problem. */
+ bfd_error = wrong_format;
+ temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (temp) { /* This format checks out as ok! */
+ right_targ = temp;
+ match_count++;
+ /* If this is the default target, accept it, even if other targets
+ might match. People who want those other targets have to set
+ the GNUTARGET variable. */
+ if (temp == default_vector[0])
+ {
+ match_count = 1;
+ break;
+ }
+#ifdef GNU960
+ /* Big- and little-endian b.out archives look the same, but it doesn't
+ * matter: there is no difference in their headers, and member file byte
+ * orders will (I hope) be handled appropriately by bfd. Ditto for big
+ * and little coff archives. And the 4 coff/b.out object formats are
+ * unambiguous. So accept the first match we find.
+ */
+ break;
+#endif
+ } else if (bfd_error != wrong_format) {
+ abfd->xvec = save_targ;
+ abfd->format = bfd_unknown;
+ return false;
+ }
+ }
+
+ if (match_count == 1) {
+ abfd->xvec = right_targ; /* Change BFD's target permanently */
+ return true; /* File position has moved, BTW */
+ }
+
+ abfd->xvec = save_targ; /* Restore original target type */
+ abfd->format = bfd_unknown; /* Restore original format */
+ bfd_error = ((match_count == 0) ? file_not_recognized :
+ file_ambiguously_recognized);
+ return false;
+}
+
+
+/*
+FUNCTION
+ bfd_set_format
+
+SYNOPSIS
+ boolean bfd_set_format(bfd *, bfd_format);
+
+DESCRIPTION
+ This function sets the file format of the supplied BFD to the
+ format requested. If the target set in the BFD does not
+ support the format requested, the format is illegal or the BFD
+ is not open for writing than an error occurs.
+
+*/
+
+boolean
+DEFUN(bfd_set_format,(abfd, format),
+ bfd *abfd AND
+ bfd_format format)
+{
+
+ if (bfd_read_p (abfd) ||
+ ((int)abfd->format < (int)bfd_unknown) ||
+ ((int)abfd->format >= (int)bfd_type_end)) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ if (abfd->format != bfd_unknown)
+ return (abfd->format == format) ? true:false;
+
+ /* presume the answer is yes */
+ abfd->format = format;
+
+ if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) {
+ abfd->format = bfd_unknown;
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_format_string
+
+SYNOPSIS
+ CONST char *bfd_format_string(bfd_format);
+
+DESCRIPTION
+ This function takes one argument, and enumerated type
+ (bfd_format) and returns a pointer to a const string
+ <<invalid>>, <<object>>, <<archive>>, <<core>> or <<unknown>>
+ depending upon the value of the enumeration.
+*/
+
+CONST char *
+DEFUN(bfd_format_string,(format),
+ bfd_format format)
+{
+ if (((int)format <(int) bfd_unknown)
+ || ((int)format >=(int) bfd_type_end))
+ return "invalid";
+
+ switch (format) {
+ case bfd_object:
+ return "object"; /* linker/assember/compiler output */
+ case bfd_archive:
+ return "archive"; /* object archive file */
+ case bfd_core:
+ return "core"; /* core dump */
+ default:
+ return "unknown";
+ }
+}
diff --git a/gnu/usr.bin/gdb/bfd/freebsd386.c b/gnu/usr.bin/gdb/bfd/freebsd386.c
new file mode 100644
index 000000000000..22cbd6ad1701
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/freebsd386.c
@@ -0,0 +1,110 @@
+/* BFD back-end for i386 a.out binaries under BSD.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This data should be correct for the format used under all the various
+ BSD ports for 386 machines. */
+
+#define BYTES_IN_WORD 4
+#define ARCH 32
+
+/* ZMAGIC files never have the header in the text. */
+#define N_HEADER_IN_TEXT(x) 0
+
+/* ZMAGIC files start at address 0. This does not apply to QMAGIC. */
+#define TEXT_START_ADDR 0
+
+#define SEGMENT_SIZE PAGE_SIZE
+
+#define DEFAULT_ARCH bfd_arch_i386
+#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN)
+
+#define MY(OP) CAT(freebsd386_,OP)
+#define TARGETNAME "a.out-freebsd-386"
+
+#define N_MAGIC(ex) \
+ ((ex).a_info & 0xffff)
+#define N_MACHTYPE(ex) \
+ ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETMID_NET(ex) : \
+ ((ex).a_info >> 16) & 0x03ff )
+#define N_FLAGS(ex) \
+ ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETFLAG_NET(ex) : \
+ ((ex).a_info >> 26) & 0x3f )
+#define N_SET_INFO(ex,mag,mid,flag) \
+ ( (ex).a_info = (((flag) & 0x3f) <<26) | (((mid) & 0x03ff) << 16) | \
+ ((mag) & 0xffff) )
+
+#define N_GETMAGIC_NET(ex) \
+ (ntohl((ex).a_info) & 0xffff)
+#define N_GETMID_NET(ex) \
+ ((ntohl((ex).a_info) >> 16) & 0x03ff)
+#define N_GETFLAG_NET(ex) \
+ ((ntohl((ex).a_info) >> 26) & 0x3f)
+#define N_SETMAGIC_NET(ex,mag,mid,flag) \
+ ( (ex).a_info = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \
+ (((mag)&0xffff)) ) )
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h"
+
+#define N_ALIGN(ex,x) \
+ (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC || \
+ N_GETMAGIC_NET(ex) == ZMAGIC || N_GETMAGIC_NET(ex) == QMAGIC ? \
+ ((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) : (x))
+
+/* Valid magic number check. */
+#define N_BADMAG(ex) \
+ (N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != NMAGIC && \
+ N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC && \
+ N_GETMAGIC_NET(ex) != OMAGIC && N_GETMAGIC_NET(ex) != NMAGIC && \
+ N_GETMAGIC_NET(ex) != ZMAGIC && N_GETMAGIC_NET(ex) != QMAGIC)
+
+/* Address of the bottom of the text segment. */
+#define N_TXTADDR(ex) \
+ ((N_MAGIC(ex) == OMAGIC || N_MAGIC(ex) == NMAGIC || \
+ N_MAGIC(ex) == ZMAGIC) ? 0 : PAGE_SIZE)
+
+/* Address of the bottom of the data segment. */
+#define N_DATADDR(ex) \
+ N_ALIGN(ex, N_TXTADDR(ex) + (ex).a_text)
+
+/* Text segment offset. */
+#define N_TXTOFF(ex) \
+ (N_MAGIC(ex) == ZMAGIC ? PAGE_SIZE : (N_MAGIC(ex) == QMAGIC || \
+ N_GETMAGIC_NET(ex) == ZMAGIC) ? 0 : EXEC_BYTES_SIZE)
+
+/* Data segment offset. */
+#define N_DATOFF(ex) \
+ N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text)
+
+/* Relocation table offset. */
+#define N_RELOFF(ex) \
+ N_ALIGN(ex, N_DATOFF(ex) + (ex).a_data)
+
+/* Symbol table offset. */
+#define N_SYMOFF(ex) \
+ (N_RELOFF(ex) + (ex).a_trsize + (ex).a_drsize)
+
+/* String table offset. */
+#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms)
+
+#define NO_SWAP_MAGIC /* magic number already in correct endian format */
+
+#include "aout-target.h"
diff --git a/gnu/usr.bin/gdb/bfd/init.c b/gnu/usr.bin/gdb/bfd/init.c
new file mode 100644
index 000000000000..30a275935c10
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/init.c
@@ -0,0 +1,78 @@
+/* bfd initialization stuff
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Steve Chamberlain of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+extern void DEFUN_VOID (bfd_section_init);
+
+static boolean initialized = false;
+
+/*
+SECTION
+ Initialization
+
+ This is the initialization section
+
+*/
+
+/*
+FUNCTION
+ bfd_init
+
+SYNOPSIS
+ void bfd_init(void);
+
+DESCRIPTION
+ This routine must be called before any other bfd function to
+ initialize magical internal data structures.
+*/
+
+void DEFUN_VOID(bfd_init)
+{
+ if (initialized == false) {
+ initialized = true;
+
+ bfd_arch_init();
+ }
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_check_init
+
+DESCRIPTION
+ This routine is called before any other bfd function using
+ initialized data is used to ensure that the structures have
+ been initialized. Soon this function will go away, and the bfd
+ library will assume that bfd_init has been called.
+
+SYNOPSIS
+ void bfd_check_init(void);
+*/
+
+void DEFUN_VOID(bfd_check_init)
+{
+ if (initialized == false) {
+ bfd_init();
+ }
+}
diff --git a/gnu/usr.bin/gdb/bfd/libaout.h b/gnu/usr.bin/gdb/bfd/libaout.h
new file mode 100644
index 000000000000..0d99d0c43dba
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libaout.h
@@ -0,0 +1,393 @@
+/* BFD back-end data structures for a.out (and similar) files.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* We try to encapsulate the differences in the various a.out file
+ variants in a few routines, and otherwise share large masses of code.
+ This means we only have to fix bugs in one place, most of the time. */
+
+/* Parameterize the a.out code based on whether it is being built
+ for a 32-bit architecture or a 64-bit architecture. */
+#if ARCH_SIZE==64
+#define GET_WORD bfd_h_get_64
+#define GET_SWORD bfd_h_get_signed_64
+#define PUT_WORD bfd_h_put_64
+#ifndef NAME
+#define NAME(x,y) CAT3(x,_64_,y)
+#endif
+#define JNAME(x) CAT(x,_64)
+#define BYTES_IN_WORD 8
+#else /* ARCH_SIZE == 32 */
+#define GET_WORD bfd_h_get_32
+#define GET_SWORD bfd_h_get_signed_32
+#define PUT_WORD bfd_h_put_32
+#ifndef NAME
+#define NAME(x,y) CAT3(x,_32_,y)
+#endif
+#define JNAME(x) CAT(x,_32)
+#define BYTES_IN_WORD 4
+#endif /* ARCH_SIZE==32 */
+
+/* Declare these types at file level, since they are used in parameter
+ lists, which have wierd scope. */
+struct external_exec;
+struct internal_exec;
+
+/* Back-end information for various a.out targets. */
+struct aout_backend_data
+{
+ /* Are ZMAGIC files mapped contiguously? If so, the text section may
+ need more padding, if the segment size (granularity for memory access
+ control) is larger than the page size. */
+ unsigned char zmagic_mapped_contiguous;
+ /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the
+ text section, which starts immediately after the file header.
+ If not, the text section starts on the next page. */
+ unsigned char text_includes_header;
+
+ /* If the text section VMA isn't specified, and we need an absolute
+ address, use this as the default. If we're producing a relocatable
+ file, zero is always used. */
+ /* ?? Perhaps a callback would be a better choice? Will this do anything
+ reasonable for a format that handles multiple CPUs with different
+ load addresses for each? */
+ bfd_vma default_text_vma;
+
+ /* Callback for setting the page and segment sizes, if they can't be
+ trivially determined from the architecture. */
+ boolean (*set_sizes) PARAMS ((bfd *));
+
+ /* zmagic files only. For go32, the length of the exec header contributes
+ to the size of the text section in the file for alignment purposes but
+ does *not* get counted in the length of the text section. */
+ unsigned char exec_header_not_counted;
+};
+#define aout_backend_info(abfd) \
+ ((CONST struct aout_backend_data *)((abfd)->xvec->backend_data))
+
+/* This is the layout in memory of a "struct exec" while we process it.
+ All 'lengths' are given as a number of bytes.
+ All 'alignments' are for relinkable files only; an alignment of
+ 'n' indicates the corresponding segment must begin at an
+ address that is a multiple of (2**n). */
+
+struct internal_exec
+{
+ long a_info; /* Magic number and flags, packed */
+ bfd_vma a_text; /* length of text, in bytes */
+ bfd_vma a_data; /* length of data, in bytes */
+ bfd_vma a_bss; /* length of uninitialized data area in mem */
+ bfd_vma a_syms; /* length of symbol table data in file */
+ bfd_vma a_entry; /* start address */
+ bfd_vma a_trsize; /* length of text's relocation info, in bytes */
+ bfd_vma a_drsize; /* length of data's relocation info, in bytes */
+ /* Added for i960 */
+ bfd_vma a_tload; /* Text runtime load address */
+ bfd_vma a_dload; /* Data runtime load address */
+ unsigned char a_talign; /* Alignment of text segment */
+ unsigned char a_dalign; /* Alignment of data segment */
+ unsigned char a_balign; /* Alignment of bss segment */
+ char a_relaxable; /* Enough info for linker relax */
+};
+
+/* Magic number is written
+< MSB >
+3130292827262524232221201918171615141312111009080706050403020100
+< FLAGS >< MACHINE TYPE >< MAGIC NUMBER >
+*/
+/* Magic number for NetBSD is
+<MSB >
+3130292827262524232221201918171615141312111009080706050403020100
+< FLAGS >< >< MAGIC NUMBER >
+*/
+
+enum machine_type {
+ M_UNKNOWN = 0,
+ M_68010 = 1,
+ M_68020 = 2,
+ M_SPARC = 3,
+ /* skip a bunch so we don't run into any of suns numbers */
+ M_386 = 100,
+ M_29K = 101, /* AMD 29000 */
+ M_386_DYNIX = 102, /* Sequent running dynix */
+ M_386_NETBSD = 134, /* NetBSD/386 binary */
+ M_MIPS1 = 151, /* MIPS R2000/R3000 binary */
+ M_MIPS2 = 152, /* MIPS R4000/R6000 binary */
+ M_HP200 = 200, /* HP 200 (68010) BSD binary */
+ M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */
+ M_HPUX = (0x20c % 256)/* HP 200/300 HPUX binary */
+};
+
+#define N_DYNAMIC(exec) ((exec).a_info & 0x8000000)
+
+#ifndef N_MAGIC
+# define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+
+#ifndef N_MACHTYPE
+# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#endif
+
+#ifndef N_FLAGS
+# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#endif
+
+#ifndef N_SET_INFO
+# define N_SET_INFO(exec, magic, type, flags) \
+((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#endif
+
+#ifndef N_SET_MAGIC
+# define N_SET_MAGIC(exec, magic) \
+((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+#endif
+
+#ifndef N_SET_MACHTYPE
+# define N_SET_MACHTYPE(exec, machtype) \
+((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+#endif
+
+#ifndef N_SET_FLAGS
+# define N_SET_FLAGS(exec, flags) \
+((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+#endif
+
+typedef struct aout_symbol {
+ asymbol symbol;
+ short desc;
+ char other;
+ unsigned char type;
+} aout_symbol_type;
+
+/* The `tdata' struct for all a.out-like object file formats.
+ Various things depend on this struct being around any time an a.out
+ file is being handled. An example is dbxread.c in GDB. */
+
+struct aoutdata {
+ struct internal_exec *hdr; /* exec file header */
+ aout_symbol_type *symbols; /* symtab for input bfd */
+
+ /* For ease, we do this */
+ asection *textsec;
+ asection *datasec;
+ asection *bsssec;
+
+ /* We remember these offsets so that after check_file_format, we have
+ no dependencies on the particular format of the exec_hdr. */
+ file_ptr sym_filepos;
+ file_ptr str_filepos;
+
+ /* Size of a relocation entry in external form */
+ unsigned reloc_entry_size;
+
+ /* Size of a symbol table entry in external form */
+ unsigned symbol_entry_size;
+
+ /* Page size - needed for alignment of demand paged files. */
+ unsigned long page_size;
+
+ /* Segment size - needed for alignment of demand paged files. */
+ unsigned long segment_size;
+
+ unsigned exec_bytes_size;
+ unsigned vma_adjusted : 1;
+
+ /* used when a bfd supports several highly similar formats */
+ enum {
+ default_format = 0,
+ gnu_encap_format } subformat;
+
+ enum {
+ undecided_magic = 0,
+ z_magic,
+ o_magic,
+ n_magic } magic;
+};
+
+struct aout_data_struct {
+ struct aoutdata a;
+ struct internal_exec e;
+};
+
+#define adata(bfd) ((bfd)->tdata.aout_data->a)
+#define exec_hdr(bfd) (adata(bfd).hdr)
+#define obj_aout_symbols(bfd) (adata(bfd).symbols)
+#define obj_textsec(bfd) (adata(bfd).textsec)
+#define obj_datasec(bfd) (adata(bfd).datasec)
+#define obj_bsssec(bfd) (adata(bfd).bsssec)
+#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos)
+#define obj_str_filepos(bfd) (adata(bfd).str_filepos)
+#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size)
+#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size)
+#define obj_aout_subformat(bfd) (adata(bfd).subformat)
+
+/* We take the address of the first element of an asymbol to ensure that the
+ macro is only ever applied to an asymbol */
+#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd))
+
+/* Prototype declarations for functions defined in aoutx.h */
+
+boolean
+NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section));
+
+bfd_target *
+NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd,
+ struct internal_exec *execp,
+ bfd_target * (*callback)(bfd *)));
+
+boolean
+NAME(aout,mkobject) PARAMS ((bfd *abfd));
+
+enum machine_type
+NAME(aout,machine_type) PARAMS ((enum bfd_architecture arch,
+ unsigned long machine));
+
+boolean
+NAME(aout,set_arch_mach) PARAMS ((bfd *abfd, enum bfd_architecture arch,
+ unsigned long machine));
+
+boolean
+NAME(aout,new_section_hook) PARAMS ((bfd *abfd, asection *newsect));
+
+boolean
+NAME(aout,set_section_contents) PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset, bfd_size_type count));
+
+asymbol *
+NAME(aout,make_empty_symbol) PARAMS ((bfd *abfd));
+
+boolean
+NAME(aout,slurp_symbol_table) PARAMS ((bfd *abfd));
+
+void
+NAME(aout,write_syms) PARAMS ((bfd *abfd));
+
+void
+NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd));
+
+unsigned int
+NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd));
+
+unsigned int
+NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location));
+
+boolean
+NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect,
+ asymbol **symbols));
+
+unsigned int
+NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section,
+ arelent **relptr, asymbol **symbols));
+
+unsigned int
+NAME(aout,get_reloc_upper_bound) PARAMS ((bfd *abfd, sec_ptr asect));
+
+void
+NAME(aout,reclaim_reloc) PARAMS ((bfd *ignore_abfd, sec_ptr ignore));
+
+alent *
+NAME(aout,get_lineno) PARAMS ((bfd *ignore_abfd, asymbol *ignore_symbol));
+
+void
+NAME(aout,print_symbol) PARAMS ((bfd *ignore_abfd, PTR file,
+ asymbol *symbol, bfd_print_symbol_type how));
+
+void
+NAME(aout,get_symbol_info) PARAMS ((bfd *ignore_abfd,
+ asymbol *symbol, symbol_info *ret));
+
+boolean
+NAME(aout,close_and_cleanup) PARAMS ((bfd *abfd));
+
+boolean
+NAME(aout,find_nearest_line) PARAMS ((bfd *abfd, asection *section,
+ asymbol **symbols, bfd_vma offset, CONST char **filename_ptr,
+ CONST char **functionname_ptr, unsigned int *line_ptr));
+
+int
+NAME(aout,sizeof_headers) PARAMS ((bfd *abfd, boolean exec));
+
+boolean
+NAME(aout,adjust_sizes_and_vmas) PARAMS ((bfd *abfd,
+ bfd_size_type *text_size, file_ptr *text_end));
+
+void
+NAME(aout,swap_exec_header_in) PARAMS ((bfd *abfd,
+ struct external_exec *raw_bytes, struct internal_exec *execp));
+
+void
+NAME(aout,swap_exec_header_out) PARAMS ((bfd *abfd,
+ struct internal_exec *execp, struct external_exec *raw_bytes));
+
+/* Prototypes for functions in stab-syms.c. */
+
+CONST char *
+aout_stab_name PARAMS ((int code));
+
+/* A.out uses the generic versions of these routines... */
+
+#define aout_32_get_section_contents bfd_generic_get_section_contents
+#define aout_32_close_and_cleanup bfd_generic_close_and_cleanup
+
+#define aout_64_get_section_contents bfd_generic_get_section_contents
+#define aout_64_close_and_cleanup bfd_generic_close_and_cleanup
+#ifndef NO_WRITE_HEADER_KLUDGE
+#define NO_WRITE_HEADER_KLUDGE 0
+#endif
+
+#ifndef WRITE_HEADERS
+#define WRITE_HEADERS(abfd, execp) \
+ { \
+ bfd_size_type text_size; /* dummy vars */ \
+ file_ptr text_end; \
+ if (adata(abfd).magic == undecided_magic) \
+ NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \
+ \
+ execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \
+ execp->a_entry = bfd_get_start_address (abfd); \
+ \
+ execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \
+ obj_reloc_entry_size (abfd)); \
+ execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \
+ obj_reloc_entry_size (abfd)); \
+ NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \
+ \
+ bfd_seek (abfd, (file_ptr) 0, SEEK_SET); \
+ bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd); \
+ /* Now write out reloc info, followed by syms and strings */ \
+ \
+ if (bfd_get_symcount (abfd) != 0) \
+ { \
+ bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET); \
+ \
+ NAME(aout,write_syms)(abfd); \
+ \
+ bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET); \
+ \
+ if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) return false; \
+ bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET); \
+ \
+ if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) return false; \
+ } \
+ }
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.c b/gnu/usr.bin/gdb/bfd/libbfd.c
new file mode 100644
index 000000000000..1bf8f7fb8e02
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.c
@@ -0,0 +1,850 @@
+/* Assorted BFD support routines, only used internally.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+SECTION
+ libbfd
+
+DESCRIPTION
+ This file contains various routines which are used within BFD.
+ They are not intended for export, but are documented here for
+ completeness.
+*/
+
+boolean
+DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect),
+ bfd *ignore AND
+ asection *ignore_newsect)
+{
+ return true;
+}
+
+boolean
+DEFUN(bfd_false ,(ignore),
+ bfd *ignore)
+{
+ return false;
+}
+
+boolean
+DEFUN(bfd_true,(ignore),
+ bfd *ignore)
+{
+ return true;
+}
+
+PTR
+DEFUN(bfd_nullvoidptr,(ignore),
+ bfd *ignore)
+{
+ return (PTR)NULL;
+}
+
+int
+DEFUN(bfd_0,(ignore),
+ bfd *ignore)
+{
+ return 0;
+}
+
+unsigned int
+DEFUN(bfd_0u,(ignore),
+ bfd *ignore)
+{
+ return 0;
+}
+
+void
+DEFUN(bfd_void,(ignore),
+ bfd *ignore)
+{
+}
+
+boolean
+DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd),
+ bfd *ignore_core_bfd AND
+ bfd *ignore_exec_bfd)
+{
+ bfd_error = invalid_operation;
+ return false;
+}
+
+/* of course you can't initialize a function to be the same as another, grr */
+
+char *
+DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return (char *)NULL;
+}
+
+int
+DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return 0;
+}
+
+bfd_target *
+DEFUN(_bfd_dummy_target,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return 0;
+}
+
+/** zalloc -- allocate and clear storage */
+
+
+#ifndef zalloc
+char *
+DEFUN(zalloc,(size),
+ bfd_size_type size)
+{
+ char *ptr = (char *) malloc ((size_t)size);
+
+ if ((ptr != NULL) && (size != 0))
+ memset(ptr,0, (size_t) size);
+
+ return ptr;
+}
+#endif
+
+/*
+INTERNAL_FUNCTION
+ bfd_xmalloc
+
+SYNOPSIS
+ PTR bfd_xmalloc( bfd_size_type size);
+
+DESCRIPTION
+ Like malloc, but exit if no more memory.
+
+*/
+
+/** There is major inconsistency in how running out of memory is handled.
+ Some routines return a NULL, and set bfd_error to no_memory.
+ However, obstack routines can't do this ... */
+
+
+DEFUN(PTR bfd_xmalloc,(size),
+ bfd_size_type size)
+{
+ static CONST char no_memory_message[] = "Virtual memory exhausted!\n";
+ PTR ptr;
+ if (size == 0) size = 1;
+ ptr = (PTR)malloc((size_t) size);
+ if (!ptr)
+ {
+ write (2, no_memory_message, sizeof(no_memory_message)-1);
+ exit (-1);
+ }
+ return ptr;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_xmalloc_by_size_t
+
+SYNOPSIS
+ PTR bfd_xmalloc_by_size_t ( size_t size);
+
+DESCRIPTION
+ Like malloc, but exit if no more memory.
+ Uses size_t, so it's suitable for use as obstack_chunk_alloc.
+ */
+PTR
+DEFUN(bfd_xmalloc_by_size_t, (size),
+ size_t size)
+{
+ return bfd_xmalloc ((bfd_size_type) size);
+}
+
+/* Some IO code */
+
+
+/* Note that archive entries don't have streams; they share their parent's.
+ This allows someone to play with the iostream behind BFD's back.
+
+ Also, note that the origin pointer points to the beginning of a file's
+ contents (0 for non-archive elements). For archive entries this is the
+ first octet in the file, NOT the beginning of the archive header. */
+
+static
+int DEFUN(real_read,(where, a,b, file),
+ PTR where AND
+ int a AND
+ int b AND
+ FILE *file)
+{
+ return fread(where, a,b,file);
+}
+bfd_size_type
+DEFUN(bfd_read,(ptr, size, nitems, abfd),
+ PTR ptr AND
+ bfd_size_type size AND
+ bfd_size_type nitems AND
+ bfd *abfd)
+{
+ int nread;
+ nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd));
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (nread > 0)
+ abfd->where += nread;
+#endif
+ return nread;
+}
+
+bfd_size_type
+DEFUN(bfd_write,(ptr, size, nitems, abfd),
+ CONST PTR ptr AND
+ bfd_size_type size AND
+ bfd_size_type nitems AND
+ bfd *abfd)
+{
+ int nwrote = fwrite (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd));
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (nwrote > 0)
+ abfd->where += nwrote;
+#endif
+ return nwrote;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_write_bigendian_4byte_int
+
+SYNOPSIS
+ void bfd_write_bigendian_4byte_int(bfd *abfd, int i);
+
+DESCRIPTION
+ Writes a 4 byte integer to the outputing bfd, in big endian
+ mode regardless of what else is going on. This is useful in
+ archives.
+
+*/
+void
+DEFUN(bfd_write_bigendian_4byte_int,(abfd, i),
+ bfd *abfd AND
+ int i)
+{
+ bfd_byte buffer[4];
+ bfd_putb32(i, buffer);
+ bfd_write((PTR)buffer, 4, 1, abfd);
+}
+
+long
+DEFUN(bfd_tell,(abfd),
+ bfd *abfd)
+{
+ file_ptr ptr;
+
+ ptr = ftell (bfd_cache_lookup(abfd));
+
+ if (abfd->my_archive)
+ ptr -= abfd->origin;
+ abfd->where = ptr;
+ return ptr;
+}
+
+int
+DEFUN(bfd_flush,(abfd),
+ bfd *abfd)
+{
+ return fflush (bfd_cache_lookup(abfd));
+}
+
+int
+DEFUN(bfd_stat,(abfd, statbuf),
+ bfd *abfd AND
+ struct stat *statbuf)
+{
+ return fstat (fileno(bfd_cache_lookup(abfd)), statbuf);
+}
+
+int
+DEFUN(bfd_seek,(abfd, position, direction),
+ bfd * CONST abfd AND
+ CONST file_ptr position AND
+ CONST int direction)
+{
+ int result;
+ FILE *f;
+ file_ptr file_position;
+ /* For the time being, a BFD may not seek to it's end. The problem
+ is that we don't easily have a way to recognize the end of an
+ element in an archive. */
+
+ BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
+
+ if (direction == SEEK_CUR && position == 0)
+ return 0;
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (abfd->format != bfd_archive && abfd->my_archive == 0)
+ {
+#ifndef NDEBUG
+ /* Explanation for this code: I'm only about 95+% sure that the above
+ conditions are sufficient and that all i/o calls are properly
+ adjusting the `where' field. So this is sort of an `assert'
+ that the `where' field is correct. If we can go a while without
+ tripping the abort, we can probably safely disable this code,
+ so that the real optimizations happen. */
+ file_ptr where_am_i_now;
+ where_am_i_now = ftell (bfd_cache_lookup (abfd));
+ if (abfd->my_archive)
+ where_am_i_now -= abfd->origin;
+ if (where_am_i_now != abfd->where)
+ abort ();
+#endif
+ if (direction == SEEK_SET && position == abfd->where)
+ return 0;
+ }
+ else
+ {
+ /* We need something smarter to optimize access to archives.
+ Currently, anything inside an archive is read via the file
+ handle for the archive. Which means that a bfd_seek on one
+ component affects the `current position' in the archive, as
+ well as in any other component.
+
+ It might be sufficient to put a spike through the cache
+ abstraction, and look to the archive for the file position,
+ but I think we should try for something cleaner.
+
+ In the meantime, no optimization for archives. */
+ }
+#endif
+
+ f = bfd_cache_lookup (abfd);
+ file_position = position;
+ if (direction == SEEK_SET && abfd->my_archive != NULL)
+ file_position += abfd->origin;
+
+ result = fseek (f, file_position, direction);
+
+ if (result != 0)
+ /* Force redetermination of `where' field. */
+ bfd_tell (abfd);
+ else
+ {
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ /* Adjust `where' field. */
+ if (direction == SEEK_SET)
+ abfd->where = position;
+ else
+ abfd->where += position;
+#endif
+ }
+ return result;
+}
+
+/** Make a string table */
+
+/*>bfd.h<
+ Add string to table pointed to by table, at location starting with free_ptr.
+ resizes the table if necessary (if it's NULL, creates it, ignoring
+ table_length). Updates free_ptr, table, table_length */
+
+boolean
+DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr),
+ char **table AND
+ char *new_string AND
+ unsigned int *table_length AND
+ char **free_ptr)
+{
+ size_t string_length = strlen (new_string) + 1; /* include null here */
+ char *base = *table;
+ size_t space_length = *table_length;
+ unsigned int offset = (base ? *free_ptr - base : 0);
+
+ if (base == NULL) {
+ /* Avoid a useless regrow if we can (but of course we still
+ take it next time */
+ space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ?
+ DEFAULT_STRING_SPACE_SIZE : string_length+1);
+ base = zalloc ((bfd_size_type) space_length);
+
+ if (base == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ }
+
+ if ((size_t)(offset + string_length) >= space_length) {
+ /* Make sure we will have enough space */
+ while ((size_t)(offset + string_length) >= space_length)
+ space_length += space_length/2; /* grow by 50% */
+
+ base = (char *) realloc (base, space_length);
+ if (base == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ }
+
+ memcpy (base + offset, new_string, string_length);
+ *table = base;
+ *table_length = space_length;
+ *free_ptr = base + offset + string_length;
+
+ return true;
+}
+
+/** The do-it-yourself (byte) sex-change kit */
+
+/* The middle letter e.g. get<b>short indicates Big or Little endian
+ target machine. It doesn't matter what the byte order of the host
+ machine is; these routines work for either. */
+
+/* FIXME: Should these take a count argument?
+ Answer (gnu@cygnus.com): No, but perhaps they should be inline
+ functions in swap.h #ifdef __GNUC__.
+ Gprof them later and find out. */
+
+/*
+FUNCTION
+ bfd_put_size
+FUNCTION
+ bfd_get_size
+
+DESCRIPTION
+ These macros as used for reading and writing raw data in
+ sections; each access (except for bytes) is vectored through
+ the target format of the BFD and mangled accordingly. The
+ mangling performs any necessary endian translations and
+ removes alignment restrictions. Note that types accepted and
+ returned by these macros are identical so they can be swapped
+ around in macros--for example libaout.h defines GET_WORD to
+ either bfd_get_32 or bfd_get_64.
+
+ In the put routines, val must be a bfd_vma. If we are on a
+ system without prototypes, the caller is responsible for making
+ sure that is true, with a cast if necessary. We don't cast
+ them in the macro definitions because that would prevent lint
+ or gcc -Wall from detecting sins such as passing a pointer.
+ To detect calling these with less than a bfd_vma, use gcc
+ -Wconversion on a host with 64 bit bfd_vma's.
+
+.
+.{* Byte swapping macros for user section data. *}
+.
+.#define bfd_put_8(abfd, val, ptr) \
+. (*((unsigned char *)(ptr)) = (unsigned char)val)
+.#define bfd_put_signed_8 \
+. bfd_put_8
+.#define bfd_get_8(abfd, ptr) \
+. (*(unsigned char *)(ptr))
+.#define bfd_get_signed_8(abfd, ptr) \
+. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80)
+.
+.#define bfd_put_16(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx16, ((val),(ptr)))
+.#define bfd_put_signed_16 \
+. bfd_put_16
+.#define bfd_get_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx16, (ptr))
+.#define bfd_get_signed_16(abfd, ptr) \
+. BFD_SEND (abfd, bfd_getx_signed_16, (ptr))
+.
+.#define bfd_put_32(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx32, ((val),(ptr)))
+.#define bfd_put_signed_32 \
+. bfd_put_32
+.#define bfd_get_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx32, (ptr))
+.#define bfd_get_signed_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx_signed_32, (ptr))
+.
+.#define bfd_put_64(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx64, ((val), (ptr)))
+.#define bfd_put_signed_64 \
+. bfd_put_64
+.#define bfd_get_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx64, (ptr))
+.#define bfd_get_signed_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
+.
+*/
+
+/*
+FUNCTION
+ bfd_h_put_size
+FUNCTION
+ bfd_h_get_size
+
+DESCRIPTION
+ These macros have the same function as their <<bfd_get_x>>
+ bretherin, except that they are used for removing information
+ for the header records of object files. Believe it or not,
+ some object files keep their header records in big endian
+ order, and their data in little endian order.
+.
+.{* Byte swapping macros for file header data. *}
+.
+.#define bfd_h_put_8(abfd, val, ptr) \
+. bfd_put_8 (abfd, val, ptr)
+.#define bfd_h_put_signed_8(abfd, val, ptr) \
+. bfd_put_8 (abfd, val, ptr)
+.#define bfd_h_get_8(abfd, ptr) \
+. bfd_get_8 (abfd, ptr)
+.#define bfd_h_get_signed_8(abfd, ptr) \
+. bfd_get_signed_8 (abfd, ptr)
+.
+.#define bfd_h_put_16(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx16,(val,ptr))
+.#define bfd_h_put_signed_16 \
+. bfd_h_put_16
+.#define bfd_h_get_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx16,(ptr))
+.#define bfd_h_get_signed_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr))
+.
+.#define bfd_h_put_32(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx32,(val,ptr))
+.#define bfd_h_put_signed_32 \
+. bfd_h_put_32
+.#define bfd_h_get_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx32,(ptr))
+.#define bfd_h_get_signed_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr))
+.
+.#define bfd_h_put_64(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx64,(val, ptr))
+.#define bfd_h_put_signed_64 \
+. bfd_h_put_64
+.#define bfd_h_get_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx64,(ptr))
+.#define bfd_h_get_signed_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr))
+.
+*/
+
+/* Sign extension to bfd_signed_vma. */
+#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000)
+#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000)
+#define EIGHT_GAZILLION (((HOST_64_BIT)0x80000000) << 32)
+#define COERCE64(x) \
+ (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION)
+
+bfd_vma
+DEFUN(bfd_getb16,(addr),
+ register bfd_byte *addr)
+{
+ return (addr[0] << 8) | addr[1];
+}
+
+bfd_vma
+DEFUN(bfd_getl16,(addr),
+ register bfd_byte *addr)
+{
+ return (addr[1] << 8) | addr[0];
+}
+
+bfd_signed_vma
+DEFUN(bfd_getb_signed_16,(addr),
+ register bfd_byte *addr)
+{
+ return COERCE16((addr[0] << 8) | addr[1]);
+}
+
+bfd_signed_vma
+DEFUN(bfd_getl_signed_16,(addr),
+ register bfd_byte *addr)
+{
+ return COERCE16((addr[1] << 8) | addr[0]);
+}
+
+void
+DEFUN(bfd_putb16,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte)(data >> 8);
+ addr[1] = (bfd_byte )data;
+}
+
+void
+DEFUN(bfd_putl16,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte )data;
+ addr[1] = (bfd_byte)(data >> 8);
+}
+
+bfd_vma
+bfd_getb32 (addr)
+ register bfd_byte *addr;
+{
+ return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
+ | addr[2]) << 8 | addr[3];
+}
+
+bfd_vma
+bfd_getl32 (addr)
+ register bfd_byte *addr;
+{
+ return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+bfd_signed_vma
+bfd_getb_signed_32 (addr)
+ register bfd_byte *addr;
+{
+ return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
+ | addr[2]) << 8 | addr[3]);
+}
+
+bfd_signed_vma
+bfd_getl_signed_32 (addr)
+ register bfd_byte *addr;
+{
+ return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0]);
+}
+
+bfd_vma
+DEFUN(bfd_getb64,(addr),
+ register bfd_byte *addr)
+{
+#ifdef BFD64
+ bfd_vma low, high;
+
+ high= ((((((((addr[0]) << 8) |
+ addr[1]) << 8) |
+ addr[2]) << 8) |
+ addr[3]) );
+
+ low = (((((((((bfd_vma)addr[4]) << 8) |
+ addr[5]) << 8) |
+ addr[6]) << 8) |
+ addr[7]));
+
+ return high << 32 | low;
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+
+}
+
+bfd_vma
+DEFUN(bfd_getl64,(addr),
+ register bfd_byte *addr)
+{
+
+#ifdef BFD64
+ bfd_vma low, high;
+ high= (((((((addr[7] << 8) |
+ addr[6]) << 8) |
+ addr[5]) << 8) |
+ addr[4]));
+
+ low = ((((((((bfd_vma)addr[3] << 8) |
+ addr[2]) << 8) |
+ addr[1]) << 8) |
+ addr[0]) );
+
+ return high << 32 | low;
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+
+}
+
+bfd_signed_vma
+DEFUN(bfd_getb_signed_64,(addr),
+ register bfd_byte *addr)
+{
+#ifdef BFD64
+ bfd_vma low, high;
+
+ high= ((((((((addr[0]) << 8) |
+ addr[1]) << 8) |
+ addr[2]) << 8) |
+ addr[3]) );
+
+ low = (((((((((bfd_vma)addr[4]) << 8) |
+ addr[5]) << 8) |
+ addr[6]) << 8) |
+ addr[7]));
+
+ return COERCE64(high << 32 | low);
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+
+}
+
+bfd_signed_vma
+DEFUN(bfd_getl_signed_64,(addr),
+ register bfd_byte *addr)
+{
+
+#ifdef BFD64
+ bfd_vma low, high;
+ high= (((((((addr[7] << 8) |
+ addr[6]) << 8) |
+ addr[5]) << 8) |
+ addr[4]));
+
+ low = ((((((((bfd_vma)addr[3] << 8) |
+ addr[2]) << 8) |
+ addr[1]) << 8) |
+ addr[0]) );
+
+ return COERCE64(high << 32 | low);
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+
+}
+
+void
+DEFUN(bfd_putb32,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte)(data >> 24);
+ addr[1] = (bfd_byte)(data >> 16);
+ addr[2] = (bfd_byte)(data >> 8);
+ addr[3] = (bfd_byte)data;
+}
+
+void
+DEFUN(bfd_putl32,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte)data;
+ addr[1] = (bfd_byte)(data >> 8);
+ addr[2] = (bfd_byte)(data >> 16);
+ addr[3] = (bfd_byte)(data >> 24);
+}
+void
+DEFUN(bfd_putb64,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+#ifdef BFD64
+ addr[0] = (bfd_byte)(data >> (7*8));
+ addr[1] = (bfd_byte)(data >> (6*8));
+ addr[2] = (bfd_byte)(data >> (5*8));
+ addr[3] = (bfd_byte)(data >> (4*8));
+ addr[4] = (bfd_byte)(data >> (3*8));
+ addr[5] = (bfd_byte)(data >> (2*8));
+ addr[6] = (bfd_byte)(data >> (1*8));
+ addr[7] = (bfd_byte)(data >> (0*8));
+#else
+ BFD_FAIL();
+#endif
+
+}
+
+void
+DEFUN(bfd_putl64,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+#ifdef BFD64
+ addr[7] = (bfd_byte)(data >> (7*8));
+ addr[6] = (bfd_byte)(data >> (6*8));
+ addr[5] = (bfd_byte)(data >> (5*8));
+ addr[4] = (bfd_byte)(data >> (4*8));
+ addr[3] = (bfd_byte)(data >> (3*8));
+ addr[2] = (bfd_byte)(data >> (2*8));
+ addr[1] = (bfd_byte)(data >> (1*8));
+ addr[0] = (bfd_byte)(data >> (0*8));
+#else
+ BFD_FAIL();
+#endif
+
+}
+
+
+/* Default implementation */
+
+boolean
+DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ if (count == 0)
+ return true;
+ if ((bfd_size_type)(offset+count) > section->_raw_size
+ || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
+ || bfd_read(location, (bfd_size_type)1, count, abfd) != count)
+ return (false); /* on error */
+ return (true);
+}
+
+/* This generic function can only be used in implementations where creating
+ NEW sections is disallowed. It is useful in patching existing sections
+ in read-write files, though. See other set_section_contents functions
+ to see why it doesn't work for new sections. */
+boolean
+DEFUN(bfd_generic_set_section_contents, (abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ if (count == 0)
+ return true;
+ if ((bfd_size_type)(offset+count) > bfd_get_section_size_after_reloc(section)
+ || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
+ || bfd_write(location, (bfd_size_type)1, count, abfd) != count)
+ return (false); /* on error */
+ return (true);
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_log2
+
+DESCRIPTION
+ Return the log base 2 of the value supplied, rounded up. eg an
+ arg of 1025 would return 11.
+
+SYNOPSIS
+ unsigned int bfd_log2(bfd_vma x);
+*/
+
+unsigned
+bfd_log2(x)
+ bfd_vma x;
+{
+ unsigned result = 0;
+ while ( (bfd_vma)(1<< result) < x)
+ result++;
+ return result;
+}
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.h b/gnu/usr.bin/gdb/bfd/libbfd.h
new file mode 100644
index 000000000000..fcd5bbca8de8
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.h
@@ -0,0 +1,273 @@
+/* libbfd.h -- Declarations used by bfd library *implementation*.
+ (This include file is not for users of the library.)
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Align an address upward to a boundary, expressed as a number of bytes.
+ E.g. align to an 8-byte boundary with argument of 8. */
+#define BFD_ALIGN(this, boundary) \
+ ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
+
+/* If you want to read and write large blocks, you might want to do it
+ in quanta of this amount */
+#define DEFAULT_BUFFERSIZE 8192
+
+/* Set a tdata field. Can't use the other macros for this, since they
+ do casts, and casting to the left of assignment isn't portable. */
+#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v))
+
+/* tdata for an archive. For an input archive, cache
+ needs to be free()'d. For an output archive, symdefs do. */
+
+struct artdata {
+ file_ptr first_file_filepos;
+ /* Speed up searching the armap */
+ struct ar_cache *cache;
+ bfd *archive_head; /* Only interesting in output routines */
+ carsym *symdefs; /* the symdef entries */
+ symindex symdef_count; /* how many there are */
+ char *extended_names; /* clever intel extension */
+ time_t armap_timestamp; /* Timestamp value written into armap.
+ This is used for BSD archives to check
+ that the timestamp is recent enough
+ for the BSD linker to not complain,
+ just before we finish writing an
+ archive. */
+ file_ptr armap_datepos; /* Position within archive to seek to
+ rewrite the date field. */
+};
+
+#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data)
+
+/* Goes in bfd's arelt_data slot */
+struct areltdata {
+ char * arch_header; /* it's actually a string */
+ unsigned int parsed_size; /* octets of filesize not including ar_hdr */
+ char *filename; /* null-terminated */
+};
+
+#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
+
+char *zalloc PARAMS ((bfd_size_type size));
+
+/* These routines allocate and free things on the BFD's obstack. Note
+ that realloc can never occur in place. */
+
+PTR bfd_alloc PARAMS ((bfd *abfd, size_t size));
+PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size));
+PTR bfd_realloc PARAMS ((bfd *abfd, PTR orig, size_t new));
+void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size));
+PTR bfd_alloc_finish PARAMS ((bfd *abfd));
+PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted));
+
+#define bfd_release(x,y) (void) obstack_free(&(x->memory),y)
+
+
+bfd_size_type bfd_read PARAMS ((PTR ptr, bfd_size_type size,
+ bfd_size_type nitems, bfd *abfd));
+bfd_size_type bfd_write PARAMS ((CONST PTR ptr, bfd_size_type size,
+ bfd_size_type nitems, bfd *abfd));
+int bfd_seek PARAMS ((bfd* CONST abfd, CONST file_ptr fp,
+ CONST int direction));
+long bfd_tell PARAMS ((bfd *abfd));
+
+int bfd_flush PARAMS ((bfd *abfd));
+int bfd_stat PARAMS ((bfd *abfd, struct stat *));
+
+bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd));
+bfd * look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index));
+boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd));
+struct areltdata * snarf_ar_hdr PARAMS ((bfd *abfd));
+bfd_target * bfd_generic_archive_p PARAMS ((bfd *abfd));
+boolean bfd_slurp_armap PARAMS ((bfd *abfd));
+boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd));
+#define bfd_slurp_bsd_armap bfd_slurp_armap
+#define bfd_slurp_coff_armap bfd_slurp_armap
+boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd));
+boolean _bfd_write_archive_contents PARAMS ((bfd *abfd));
+bfd * new_bfd PARAMS (());
+
+#define DEFAULT_STRING_SPACE_SIZE 0x2000
+boolean bfd_add_to_string_table PARAMS ((char **table, char *new_string,
+ unsigned int *table_length,
+ char **free_ptr));
+
+boolean bfd_false PARAMS ((bfd *ignore));
+boolean bfd_true PARAMS ((bfd *ignore));
+PTR bfd_nullvoidptr PARAMS ((bfd *ignore));
+int bfd_0 PARAMS ((bfd *ignore));
+unsigned int bfd_0u PARAMS ((bfd *ignore));
+void bfd_void PARAMS ((bfd *ignore));
+
+bfd * new_bfd_contained_in PARAMS ((bfd *));
+boolean _bfd_dummy_new_section_hook PARAMS ((bfd *ignore, asection *newsect));
+char * _bfd_dummy_core_file_failing_command PARAMS ((bfd *abfd));
+int _bfd_dummy_core_file_failing_signal PARAMS ((bfd *abfd));
+boolean _bfd_dummy_core_file_matches_executable_p PARAMS ((bfd *core_bfd,
+ bfd *exec_bfd));
+bfd_target * _bfd_dummy_target PARAMS ((bfd *abfd));
+
+void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+
+boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength,
+ struct orl *map, unsigned int orl_count, int stridx));
+
+boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength,
+ struct orl *map, unsigned int orl_count, int stridx));
+
+bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive,
+ bfd *last_file));
+
+int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
+
+boolean bfd_generic_get_section_contents PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset,
+ bfd_size_type count));
+
+boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset,
+ bfd_size_type count));
+
+/* Macros to tell if bfds are read or write enabled.
+
+ Note that bfds open for read may be scribbled into if the fd passed
+ to bfd_fdopenr is actually open both for read and write
+ simultaneously. However an output bfd will never be open for
+ read. Therefore sometimes you want to check bfd_read_p or
+ !bfd_read_p, and only sometimes bfd_write_p.
+*/
+
+#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction)
+#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction)
+
+void bfd_assert PARAMS ((char*,int));
+
+#define BFD_ASSERT(x) \
+{ if (!(x)) bfd_assert(__FILE__,__LINE__); }
+
+#define BFD_FAIL() \
+{ bfd_assert(__FILE__,__LINE__); }
+
+FILE * bfd_cache_lookup_worker PARAMS ((bfd *));
+
+extern bfd *bfd_last_cache;
+
+/* Now Steve, what's the story here? */
+#ifdef lint
+#define itos(x) "l"
+#define stoi(x) 1
+#else
+#define itos(x) ((char*)(x))
+#define stoi(x) ((int)(x))
+#endif
+
+/* Generic routine for close_and_cleanup is really just bfd_true. */
+#define bfd_generic_close_and_cleanup bfd_true
+
+/* And more follows */
+
+void
+bfd_check_init PARAMS ((void));
+
+PTR
+bfd_xmalloc PARAMS (( bfd_size_type size));
+
+PTR
+bfd_xmalloc_by_size_t PARAMS (( size_t size));
+
+void
+bfd_write_bigendian_4byte_int PARAMS ((bfd *abfd, int i));
+
+unsigned int
+bfd_log2 PARAMS ((bfd_vma x));
+
+#define BFD_CACHE_MAX_OPEN 10
+extern bfd *bfd_last_cache;
+
+#define bfd_cache_lookup(x) \
+ ((x)==bfd_last_cache? \
+ (FILE*)(bfd_last_cache->iostream): \
+ bfd_cache_lookup_worker(x))
+boolean
+bfd_cache_close PARAMS ((bfd *));
+
+FILE*
+bfd_open_file PARAMS ((bfd *));
+
+FILE *
+bfd_cache_lookup_worker PARAMS ((bfd *));
+
+void
+bfd_constructor_entry PARAMS ((bfd *abfd,
+ asymbol **symbol_ptr_ptr,
+ CONST char*type));
+
+CONST struct reloc_howto_struct *
+bfd_default_reloc_type_lookup
+ PARAMS ((bfd *abfd AND
+ bfd_reloc_code_real_type code));
+
+boolean
+bfd_generic_relax_section
+ PARAMS ((bfd *abfd,
+ asection *section,
+ asymbol **symbols));
+
+bfd_byte *
+
+bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd,
+ struct bfd_seclet *seclet,
+ bfd_byte *data,
+ boolean relocateable));
+
+boolean
+bfd_generic_seclet_link
+ PARAMS ((bfd *abfd,
+ PTR data,
+ boolean relocateable));
+
+extern bfd_arch_info_type bfd_default_arch_struct;
+boolean
+bfd_default_set_arch_mach PARAMS ((bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long mach));
+
+void
+bfd_arch_init PARAMS ((void));
+
+void
+bfd_arch_linkin PARAMS ((bfd_arch_info_type *));
+
+CONST bfd_arch_info_type *
+bfd_default_compatible
+ PARAMS ((CONST bfd_arch_info_type *a,
+ CONST bfd_arch_info_type *b));
+
+boolean
+bfd_default_scan PARAMS ((CONST struct bfd_arch_info *, CONST char *));
+
+struct elf_internal_shdr *
+bfd_elf_find_section PARAMS ((bfd *abfd, char *name));
+
diff --git a/gnu/usr.bin/gdb/bfd/libcoff.h b/gnu/usr.bin/gdb/bfd/libcoff.h
new file mode 100644
index 000000000000..2aa6ad4b1615
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libcoff.h
@@ -0,0 +1,352 @@
+/* BFD COFF object file private structure.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Object file tdata; access macros */
+
+#define coff_data(bfd) ((bfd)->tdata.coff_obj_data)
+#define exec_hdr(bfd) (coff_data(bfd)->hdr)
+#define obj_symbols(bfd) (coff_data(bfd)->symbols)
+#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos)
+
+#define obj_relocbase(bfd) (coff_data(bfd)->relocbase)
+#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments)
+#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count)
+#define obj_convert(bfd) (coff_data(bfd)->conversion_table)
+#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size)
+#if CFILE_STUFF
+#define obj_symbol_slew(bfd) (coff_data(bfd)->symbol_index_slew)
+#else
+#define obj_symbol_slew(bfd) 0
+#endif
+
+
+/* `Tdata' information kept for COFF files. */
+
+typedef struct coff_tdata
+{
+ struct coff_symbol_struct *symbols; /* symtab for input bfd */
+ unsigned int *conversion_table;
+ int conv_table_size;
+ file_ptr sym_filepos;
+
+ long symbol_index_slew; /* used during read to mark whether a
+ C_FILE symbol as been added. */
+
+ struct coff_ptr_struct *raw_syments;
+ struct lineno *raw_linenos;
+ unsigned int raw_syment_count;
+ unsigned short flags;
+
+ /* These are only valid once writing has begun */
+ long int relocbase;
+
+ /* These members communicate important constants about the symbol table
+ to GDB's symbol-reading code. These `constants' unfortunately vary
+ from coff implementation to implementation... */
+ unsigned local_n_btmask;
+ unsigned local_n_btshft;
+ unsigned local_n_tmask;
+ unsigned local_n_tshift;
+ unsigned local_symesz;
+ unsigned local_auxesz;
+ unsigned local_linesz;
+} coff_data_type;
+
+/* We take the address of the first element of a asymbol to ensure that the
+ * macro is only ever applied to an asymbol. */
+#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd)))
+
+/* Functions in coffgen.c. */
+extern bfd_target *coff_object_p PARAMS ((bfd *));
+extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int));
+extern unsigned int coff_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int coff_get_symtab PARAMS ((bfd *, asymbol **));
+extern int coff_count_linenumbers PARAMS ((bfd *));
+extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *));
+extern void coff_renumber_symbols PARAMS ((bfd *));
+extern void coff_mangle_symbols PARAMS ((bfd *));
+extern void coff_write_symbols PARAMS ((bfd *));
+extern void coff_write_linenumbers PARAMS ((bfd *));
+extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *));
+extern asymbol *coff_section_symbol PARAMS ((bfd *, char *));
+extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *));
+extern unsigned int coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern asymbol *coff_make_empty_symbol PARAMS ((bfd *));
+extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *,
+ bfd_print_symbol_type how));
+extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *ret));
+extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR,
+ unsigned long));
+extern boolean coff_find_nearest_line PARAMS ((bfd *,
+ asection *,
+ asymbol **,
+ bfd_vma offset,
+ CONST char **filename_ptr,
+ CONST char **functionname_ptr,
+ unsigned int *line_ptr));
+extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc));
+extern boolean bfd_coff_reloc16_relax_section PARAMS ((bfd *,
+ asection *,
+ asymbol **));
+extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents
+ PARAMS ((bfd *, struct bfd_seclet *, bfd_byte *, boolean relocateable));
+extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *,
+ struct bfd_seclet *));
+
+/* And more taken from the source .. */
+
+typedef struct coff_ptr_struct
+{
+
+ /* Remembers the offset from the first symbol in the file for
+ this symbol. Generated by coff_renumber_symbols. */
+unsigned int offset;
+
+ /* Should the tag field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+char fix_tag;
+
+ /* Should the endidx field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+char fix_end;
+
+ /* The container for the symbol structure as read and translated
+ from the file. */
+
+union {
+ union internal_auxent auxent;
+ struct internal_syment syment;
+ } u;
+} combined_entry_type;
+
+
+ /* Each canonical asymbol really looks like this: */
+
+typedef struct coff_symbol_struct
+{
+ /* The actual symbol which the rest of BFD works with */
+asymbol symbol;
+
+ /* A pointer to the hidden information for this symbol */
+combined_entry_type *native;
+
+ /* A pointer to the linenumber information for this symbol */
+struct lineno_cache_entry *lineno;
+
+ /* Have the line numbers been relocated yet ? */
+boolean done_lineno;
+} coff_symbol_type;
+typedef struct
+{
+ void (*_bfd_coff_swap_aux_in) PARAMS ((
+ bfd *abfd ,
+ PTR ext,
+ int type,
+ int class ,
+ PTR in));
+
+ void (*_bfd_coff_swap_sym_in) PARAMS ((
+ bfd *abfd ,
+ PTR ext,
+ PTR in));
+
+ void (*_bfd_coff_swap_lineno_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+
+ unsigned int (*_bfd_coff_swap_aux_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ int type,
+ int class,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_sym_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_lineno_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_reloc_out) PARAMS ((
+ bfd *abfd,
+ PTR src,
+ PTR dst));
+
+ unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int _bfd_filhsz;
+ unsigned int _bfd_aoutsz;
+ unsigned int _bfd_scnhsz;
+ unsigned int _bfd_symesz;
+ unsigned int _bfd_auxesz;
+ unsigned int _bfd_linesz;
+ boolean _bfd_coff_long_filenames;
+ void (*_bfd_coff_swap_filehdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ void (*_bfd_coff_swap_aouthdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ void (*_bfd_coff_swap_scnhdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ boolean (*_bfd_coff_bad_format_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr));
+ boolean (*_bfd_coff_set_arch_mach_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr));
+ PTR (*_bfd_coff_mkobject_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr,
+ PTR internal_aouthdr));
+ flagword (*_bfd_styp_to_sec_flags_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_scnhdr));
+ asection *(*_bfd_make_section_hook) PARAMS ((
+ bfd *abfd,
+ char *name));
+ void (*_bfd_set_alignment_hook) PARAMS ((
+ bfd *abfd,
+ asection *sec,
+ PTR internal_scnhdr));
+ boolean (*_bfd_coff_slurp_symbol_table) PARAMS ((
+ bfd *abfd));
+ boolean (*_bfd_coff_symname_in_debug) PARAMS ((
+ bfd *abfd,
+ struct internal_syment *sym));
+ void (*_bfd_coff_reloc16_extra_cases) PARAMS ((
+ bfd *abfd,
+ struct bfd_seclet *seclet,
+ arelent *reloc,
+ bfd_byte *data,
+ unsigned int *src_ptr,
+ unsigned int *dst_ptr));
+ int (*_bfd_coff_reloc16_estimate) PARAMS ((
+ asection *input_section,
+ asymbol **symbols,
+ arelent *r,
+ unsigned int shrink));
+
+} bfd_coff_backend_data;
+
+#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data)
+
+#define bfd_coff_swap_aux_in(a,e,t,c,i) \
+ ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,i))
+
+#define bfd_coff_swap_sym_in(a,e,i) \
+ ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i))
+
+#define bfd_coff_swap_lineno_in(a,e,i) \
+ ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i))
+
+#define bfd_coff_swap_reloc_out(abfd, i, o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o))
+
+#define bfd_coff_swap_lineno_out(abfd, i, o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o))
+
+#define bfd_coff_swap_aux_out(abfd, i, t,c,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aux_out) (abfd, i,t,c, o))
+
+#define bfd_coff_swap_sym_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o))
+
+#define bfd_coff_swap_scnhdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o))
+
+#define bfd_coff_swap_filehdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o))
+
+#define bfd_coff_swap_aouthdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o))
+
+#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz)
+#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz)
+#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz)
+#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz)
+#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz)
+#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz)
+#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames)
+#define bfd_coff_swap_filehdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o))
+
+#define bfd_coff_swap_aouthdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o))
+
+#define bfd_coff_swap_scnhdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o))
+
+#define bfd_coff_bad_format_hook(abfd, filehdr) \
+ ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr))
+
+#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\
+ ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr))
+#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\
+ ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr))
+
+#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr)\
+ ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr))
+
+#define bfd_coff_make_section_hook(abfd, name)\
+ ((coff_backend_info (abfd)->_bfd_make_section_hook) (abfd, name))
+
+#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\
+ ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr))
+
+#define bfd_coff_slurp_symbol_table(abfd)\
+ ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd))
+
+#define bfd_coff_symname_in_debug(abfd, sym)\
+ ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym))
+
+#define bfd_coff_reloc16_extra_cases(abfd, seclet, reloc, data, src_ptr, dst_ptr)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\
+ (abfd, seclet, reloc, data, src_ptr, dst_ptr))
+
+#define bfd_coff_reloc16_estimate(abfd, section, symbols, reloc, shrink)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\
+ (section, symbols, reloc, shrink))
+
+
diff --git a/gnu/usr.bin/gdb/bfd/libecoff.h b/gnu/usr.bin/gdb/bfd/libecoff.h
new file mode 100644
index 000000000000..ad3e8f223aa4
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libecoff.h
@@ -0,0 +1,265 @@
+/* BFD ECOFF object file private structure.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is the backend information kept for ECOFF files. This
+ structure is constant for a particular backend. The first element
+ is the COFF backend data structure, so that ECOFF targets can use
+ the generic COFF code. */
+
+#define ecoff_backend(abfd) \
+ ((struct ecoff_backend_data *) (abfd)->xvec->backend_data)
+
+struct ecoff_backend_data
+{
+ /* COFF backend information. This must be the first field. */
+ bfd_coff_backend_data coff;
+ /* Supported architecture. */
+ enum bfd_architecture arch;
+ /* Symbol table magic number. */
+ int sym_magic;
+ /* Initial portion of armap string. */
+ const char *armap_start;
+ /* Alignment of debugging information. E.g., 4. */
+ bfd_size_type debug_align;
+ /* The page boundary used to align sections in a demand-paged
+ executable file. E.g., 0x1000. */
+ bfd_vma round;
+ /* Bitsize of constructor entries. */
+ unsigned int constructor_bitsize;
+ /* Reloc to use for constructor entries. */
+ CONST struct reloc_howto_struct *constructor_reloc;
+ /* Sizes of external symbolic information. */
+ bfd_size_type external_hdr_size;
+ bfd_size_type external_dnr_size;
+ bfd_size_type external_pdr_size;
+ bfd_size_type external_sym_size;
+ bfd_size_type external_opt_size;
+ bfd_size_type external_fdr_size;
+ bfd_size_type external_rfd_size;
+ bfd_size_type external_ext_size;
+ /* Functions to swap in external symbolic data. */
+ void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *));
+ void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *));
+ void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *));
+ void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *));
+ void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *));
+ void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *));
+ void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *));
+ void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *));
+ /* Functions to swap out external symbolic data. */
+ void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR));
+ void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR));
+ void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR));
+ void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR));
+ void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR));
+ void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR));
+ void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR));
+ void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR));
+ /* It so happens that the auxiliary type information has the same
+ type and format for all known ECOFF targets. I don't see any
+ reason that that should change, so at least for now the auxiliary
+ swapping information is not in this table. */
+ /* External reloc size. */
+ bfd_size_type external_reloc_size;
+ /* Reloc swapping functions. */
+ void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *));
+ void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR));
+ /* Backend reloc tweaking. */
+ void (*finish_reloc) PARAMS ((bfd *, struct internal_reloc *, arelent *));
+};
+
+/* This is the target specific information kept for ECOFF files. */
+
+#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data)
+
+typedef struct ecoff_tdata
+{
+ /* The reloc file position, set by
+ ecoff_compute_section_file_positions. */
+ file_ptr reloc_filepos;
+
+ /* The symbol table file position, set by ecoff_mkobject_hook. */
+ file_ptr sym_filepos;
+
+ /* The start and end of the text segment. Only valid for an
+ existing file, not for one we are creating. */
+ unsigned long text_start;
+ unsigned long text_end;
+
+ /* The cached gp value. This is used when relocating. */
+ bfd_vma gp;
+
+ /* The maximum size of objects to optimize using gp. This is
+ typically set by the -G option to the compiler, assembler or
+ linker. */
+ int gp_size;
+
+ /* The register masks. When linking, all the masks found in the
+ input files are combined into the masks of the output file.
+ These are not all used for all targets, but that's OK, because
+ the relevant ones are the only ones swapped in and out. */
+ unsigned long gprmask;
+ unsigned long fprmask;
+ unsigned long cprmask[4];
+
+ /* The size of the unswapped ECOFF symbolic information. */
+ bfd_size_type raw_size;
+
+ /* The unswapped ECOFF symbolic information. */
+ PTR raw_syments;
+
+ /* The swapped ECOFF symbolic header. */
+ HDRR symbolic_header;
+
+ /* Pointers to the unswapped symbolic information. */
+ unsigned char *line;
+ PTR external_dnr; /* struct dnr_ext */
+ PTR external_pdr; /* struct pdr_ext */
+ PTR external_sym; /* struct sym_ext */
+ PTR external_opt; /* struct opt_ext */
+ union aux_ext *external_aux;
+ char *ss;
+ char *ssext;
+ PTR external_fdr; /* struct fdr_ext */
+ PTR external_rfd; /* struct rfd_ext */
+ PTR external_ext; /* struct ext_ext */
+
+ /* The swapped FDR information. */
+ FDR *fdr;
+
+ /* The FDR index. This is set for an input BFD to a link so that
+ the external symbols can set their FDR index correctly. */
+ unsigned int ifdbase;
+
+ /* The canonical BFD symbols. */
+ struct ecoff_symbol_struct *canonical_symbols;
+
+} ecoff_data_type;
+
+/* Each canonical asymbol really looks like this. */
+
+typedef struct ecoff_symbol_struct
+{
+ /* The actual symbol which the rest of BFD works with */
+ asymbol symbol;
+
+ /* The fdr for this symbol. */
+ FDR *fdr;
+
+ /* true if this is a local symbol rather than an external one. */
+ boolean local;
+
+ /* A pointer to the unswapped hidden information for this symbol.
+ This is either a struct sym_ext or a struct ext_ext, depending on
+ the value of the local field above. */
+ PTR native;
+} ecoff_symbol_type;
+
+/* We take the address of the first element of a asymbol to ensure that the
+ macro is only ever applied to an asymbol. */
+#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd)))
+
+/* This is a hack borrowed from coffcode.h; we need to save the index
+ of an external symbol when we write it out so that can set the
+ symbol index correctly when we write out the relocs. */
+#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata)
+#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx))
+
+/* Make an ECOFF object. */
+extern boolean ecoff_mkobject PARAMS ((bfd *));
+
+/* Read in the ECOFF symbolic debugging information. */
+extern boolean ecoff_slurp_symbolic_info PARAMS ((bfd *));
+
+/* Generic ECOFF BFD backend vectors. */
+extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
+extern unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
+extern unsigned int ecoff_get_symtab PARAMS ((bfd *abfd,
+ asymbol **alocation));
+extern void ecoff_get_symbol_info PARAMS ((bfd *abfd,
+ asymbol *symbol,
+ symbol_info *ret));
+extern void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep,
+ asymbol *symbol,
+ bfd_print_symbol_type how));
+extern unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd,
+ asection *section,
+ arelent **relptr,
+ asymbol **symbols));
+extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
+ asection *section,
+ asymbol **symbols,
+ bfd_vma offset,
+ CONST char **filename_ptr,
+ CONST char **fnname_ptr,
+ unsigned int *retline_ptr));
+extern boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data,
+ boolean relocateable));
+extern boolean ecoff_set_arch_mach PARAMS ((bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long machine));
+extern int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc));
+extern boolean ecoff_set_section_contents PARAMS ((bfd *abfd,
+ asection *section,
+ PTR location,
+ file_ptr offset,
+ bfd_size_type count));
+extern boolean ecoff_get_section_contents PARAMS ((bfd *abfd,
+ asection *section,
+ PTR location,
+ file_ptr offset,
+ bfd_size_type count));
+extern boolean ecoff_write_object_contents PARAMS ((bfd *abfd));
+extern boolean ecoff_slurp_armap PARAMS ((bfd *abfd));
+extern boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength,
+ struct orl *map,
+ unsigned int orl_count,
+ int stridx));
+#define ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table
+extern bfd_target *ecoff_archive_p PARAMS ((bfd *abfd));
+#define ecoff_get_lineno \
+ ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr)
+#define ecoff_truncate_arname bfd_dont_truncate_arname
+#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file
+#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#define ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound
+#define ecoff_close_and_cleanup bfd_generic_close_and_cleanup
+#define ecoff_bfd_debug_info_start bfd_void
+#define ecoff_bfd_debug_info_end bfd_void
+#define ecoff_bfd_debug_info_accumulate \
+ ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void)
+#define ecoff_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#define ecoff_bfd_relax_section bfd_generic_relax_section
+#define ecoff_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+/* Hook functions for the generic COFF section reading code. */
+extern PTR ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr));
+extern asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
+extern boolean ecoff_new_section_hook PARAMS ((bfd *abfd,
+ asection *section));
+#define ecoff_set_alignment_hook \
+ ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
+extern boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr));
+extern long ecoff_sec_to_styp_flags PARAMS ((CONST char *name,
+ flagword flags));
+extern flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr));
+extern boolean ecoff_slurp_symbol_table PARAMS ((bfd *abfd));
diff --git a/gnu/usr.bin/gdb/bfd/libelf.h b/gnu/usr.bin/gdb/bfd/libelf.h
new file mode 100644
index 000000000000..187c51a29c0b
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libelf.h
@@ -0,0 +1,249 @@
+/* BFD back-end data structures for ELF files.
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _LIBELF_H_
+#define _LIBELF_H_ 1
+
+#include "elf/common.h"
+#include "elf/internal.h"
+#include "elf/external.h"
+
+/* If size isn't specified as 64 or 32, NAME macro should fail. */
+#ifndef NAME
+#if ARCH_SIZE==64
+#define NAME(x,y) CAT4(x,64,_,y)
+#endif
+#if ARCH_SIZE==32
+#define NAME(x,y) CAT4(x,32,_,y)
+#endif
+#endif
+
+#ifndef NAME
+#define NAME(x,y) CAT4(x,NOSIZE,_,y)
+#endif
+
+#define ElfNAME(X) NAME(Elf,X)
+#define elfNAME(X) NAME(elf,X)
+
+typedef struct
+{
+ asymbol symbol;
+ Elf_Internal_Sym internal_elf_sym;
+ union
+ {
+ unsigned int hppa_arg_reloc;
+ PTR any;
+ }
+ tc_data;
+} elf_symbol_type;
+
+struct elf_backend_data
+{
+ int use_rela_p;
+ int elf_64_p;
+ enum bfd_architecture arch;
+ void (*elf_info_to_howto) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rela *));
+ void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rel *));
+ bfd_vma maxpagesize;
+ void (*write_relocs) PARAMS ((bfd *, asection *, PTR));
+
+ void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *));
+ boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, elf_symbol_type *, int));
+ boolean (*elf_backend_section_processing) PARAMS ((bfd *, Elf32_Internal_Shdr *));
+ boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
+ boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+ boolean (*elf_backend_section_from_bfd_section) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
+};
+
+struct elf_sym_extra
+{
+ int elf_sym_num; /* sym# after locals/globals are reordered */
+};
+
+typedef struct elf_sym_extra Elf_Sym_Extra;
+
+struct bfd_elf_arch_map {
+ enum bfd_architecture bfd_arch;
+ int elf_arch;
+};
+
+extern const struct bfd_elf_arch_map bfd_elf_arch_map[];
+extern const int bfd_elf_arch_map_size;
+
+struct bfd_elf_section_data {
+ Elf_Internal_Shdr this_hdr;
+ Elf_Internal_Shdr rel_hdr;
+ int this_idx, rel_idx;
+};
+#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd)
+#define shdr_name(abfd,shdr) (elf_shstrtab (abfd)->tab + (shdr)->sh_name)
+
+#define get_elf_backend_data(abfd) \
+ ((struct elf_backend_data *) (abfd)->xvec->backend_data)
+
+struct strtab
+{
+ char *tab;
+ int nentries;
+ int length;
+};
+
+/* Some private data is stashed away for future use using the tdata pointer
+ in the bfd structure. */
+
+struct elf_obj_tdata
+{
+ Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */
+ Elf_Internal_Shdr **elf_sect_ptr;
+ Elf_Internal_Phdr *phdr;
+ struct strtab *strtab_ptr;
+ int num_locals;
+ int num_globals;
+ Elf_Internal_Sym *internal_syms;
+ elf_symbol_type *symbols; /* elf_symbol_type */
+ Elf_Sym_Extra *sym_extra;
+ asymbol **section_syms; /* STT_SECTION symbols for each section */
+ int num_section_syms; /* number of section_syms allocated */
+ Elf_Internal_Shdr symtab_hdr;
+ Elf_Internal_Shdr shstrtab_hdr;
+ Elf_Internal_Shdr strtab_hdr;
+ int symtab_section, shstrtab_section, strtab_section;
+ file_ptr next_file_pos;
+ void *prstatus; /* The raw /proc prstatus structure */
+ void *prpsinfo; /* The raw /proc prpsinfo structure */
+ bfd_vma gp; /* The gp value (MIPS only, for now) */
+ int gp_size; /* The gp size (MIPS only, for now) */
+};
+
+#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data)
+#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header)
+#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr)
+#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr)
+#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section)
+#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals)
+#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals)
+#define elf_sym_extra(bfd) (elf_tdata(bfd) -> sym_extra)
+#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms)
+#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms)
+#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo)
+#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus)
+#define obj_symbols(bfd) (elf_tdata(bfd) -> symbols)
+#define obj_internal_syms(bfd) (elf_tdata(bfd) -> internal_syms)
+#define elf_gp(bfd) (elf_tdata(bfd) -> gp)
+#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size)
+
+extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned));
+extern char * elf_get_str_section PARAMS ((bfd *, unsigned));
+
+#define bfd_elf32_mkobject bfd_elf_mkobject
+#define bfd_elf64_mkobject bfd_elf_mkobject
+#define elf_mkobject bfd_elf_mkobject
+
+extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *));
+
+extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *,
+ arelent *,
+ asymbol *,
+ PTR,
+ asection *,
+ bfd *));
+extern boolean bfd_elf_mkobject PARAMS ((bfd *));
+extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *));
+
+extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *));
+extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *));
+
+extern bfd_target *bfd_elf32_object_p PARAMS ((bfd *));
+extern bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *));
+extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *));
+extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *));
+extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *,
+ bfd *));
+extern boolean bfd_elf32_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr,
+ bfd_size_type));
+
+extern unsigned int bfd_elf32_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int bfd_elf32_get_symtab PARAMS ((bfd *, asymbol **));
+extern unsigned int bfd_elf32_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern unsigned int bfd_elf32_canonicalize_reloc PARAMS ((bfd *, sec_ptr,
+ arelent **,
+ asymbol **));
+extern asymbol *bfd_elf32_make_empty_symbol PARAMS ((bfd *));
+extern void bfd_elf32_print_symbol PARAMS ((bfd *, PTR, asymbol *,
+ bfd_print_symbol_type));
+extern void bfd_elf32_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *));
+extern alent *bfd_elf32_get_lineno PARAMS ((bfd *, asymbol *));
+extern boolean bfd_elf32_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+extern boolean bfd_elf32_find_nearest_line PARAMS ((bfd *, asection *,
+ asymbol **,
+ bfd_vma, CONST char **,
+ CONST char **,
+ unsigned int *));
+extern int bfd_elf32_sizeof_headers PARAMS ((bfd *, boolean));
+extern void bfd_elf32__write_relocs PARAMS ((bfd *, asection *, PTR));
+extern boolean bfd_elf32_new_section_hook PARAMS ((bfd *, asection *));
+
+/* If the target doesn't have reloc handling written yet: */
+extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *,
+ Elf32_Internal_Rela *));
+
+extern bfd_target *bfd_elf64_object_p PARAMS ((bfd *));
+extern bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *));
+extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *));
+extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *));
+extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *,
+ bfd *));
+extern boolean bfd_elf64_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr,
+ bfd_size_type));
+
+extern unsigned int bfd_elf64_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int bfd_elf64_get_symtab PARAMS ((bfd *, asymbol **));
+extern unsigned int bfd_elf64_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern unsigned int bfd_elf64_canonicalize_reloc PARAMS ((bfd *, sec_ptr,
+ arelent **,
+ asymbol **));
+extern asymbol *bfd_elf64_make_empty_symbol PARAMS ((bfd *));
+extern void bfd_elf64_print_symbol PARAMS ((bfd *, PTR, asymbol *,
+ bfd_print_symbol_type));
+extern void bfd_elf64_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *));
+extern alent *bfd_elf64_get_lineno PARAMS ((bfd *, asymbol *));
+extern boolean bfd_elf64_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+extern boolean bfd_elf64_find_nearest_line PARAMS ((bfd *, asection *,
+ asymbol **,
+ bfd_vma, CONST char **,
+ CONST char **,
+ unsigned int *));
+extern int bfd_elf64_sizeof_headers PARAMS ((bfd *, boolean));
+extern void bfd_elf64__write_relocs PARAMS ((bfd *, asection *, PTR));
+extern boolean bfd_elf64_new_section_hook PARAMS ((bfd *, asection *));
+
+/* If the target doesn't have reloc handling written yet: */
+extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *,
+ Elf64_Internal_Rela *));
+
+#endif /* _LIBELF_H_ */
diff --git a/gnu/usr.bin/gdb/bfd/opncls.c b/gnu/usr.bin/gdb/bfd/opncls.c
new file mode 100644
index 000000000000..42858c25919e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/opncls.c
@@ -0,0 +1,534 @@
+/* opncls.c -- open and close a BFD.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "obstack.h"
+extern void bfd_cache_init PARAMS ((bfd *));
+FILE *bfd_open_file PARAMS ((bfd *));
+
+/* fdopen is a loser -- we should use stdio exclusively. Unfortunately
+ if we do that we can't use fcntl. */
+
+
+#define obstack_chunk_alloc bfd_xmalloc_by_size_t
+#define obstack_chunk_free free
+
+/* Return a new BFD. All BFD's are allocated through this routine. */
+
+bfd *
+new_bfd PARAMS ((void))
+{
+ bfd *nbfd;
+
+ nbfd = (bfd *)zalloc (sizeof (bfd));
+ if (!nbfd)
+ return 0;
+
+ bfd_check_init();
+ obstack_begin((PTR)&nbfd->memory, 128);
+
+ nbfd->arch_info = &bfd_default_arch_struct;
+
+ nbfd->direction = no_direction;
+ nbfd->iostream = NULL;
+ nbfd->where = 0;
+ nbfd->sections = (asection *)NULL;
+ nbfd->format = bfd_unknown;
+ nbfd->my_archive = (bfd *)NULL;
+ nbfd->origin = 0;
+ nbfd->opened_once = false;
+ nbfd->output_has_begun = false;
+ nbfd->section_count = 0;
+ nbfd->usrdata = (PTR)NULL;
+ nbfd->cacheable = false;
+ nbfd->flags = NO_FLAGS;
+ nbfd->mtime_set = false;
+
+ return nbfd;
+}
+
+/* Allocate a new BFD as a member of archive OBFD. */
+
+bfd *
+new_bfd_contained_in (obfd)
+ bfd *obfd;
+{
+ bfd *nbfd;
+
+ nbfd = new_bfd();
+ nbfd->xvec = obfd->xvec;
+ nbfd->my_archive = obfd;
+ nbfd->direction = read_direction;
+ nbfd->target_defaulted = obfd->target_defaulted;
+ return nbfd;
+}
+
+/*
+SECTION
+ Opening and Closing BFDs
+
+*/
+
+/*
+FUNCTION
+ bfd_openr
+
+SYNOPSIS
+ bfd *bfd_openr(CONST char *filename, CONST char*target);
+
+DESCRIPTION
+ This function opens the file supplied (using <<fopen>>) with the target
+ supplied, it returns a pointer to the created BFD.
+
+ If NULL is returned then an error has occured. Possible errors
+ are <<no_memory>>, <<invalid_target>> or <<system_call>> error.
+*/
+
+bfd *
+DEFUN(bfd_openr, (filename, target),
+ CONST char *filename AND
+ CONST char *target)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+
+ nbfd = new_bfd();
+ if (nbfd == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ bfd_error = invalid_target;
+ return NULL;
+ }
+
+ nbfd->filename = filename;
+ nbfd->direction = read_direction;
+
+ if (bfd_open_file (nbfd) == NULL) {
+ bfd_error = system_call_error; /* File didn't exist, or some such */
+ bfd_release(nbfd,0);
+ return NULL;
+ }
+ return nbfd;
+}
+
+
+/* Don't try to `optimize' this function:
+
+ o - We lock using stack space so that interrupting the locking
+ won't cause a storage leak.
+ o - We open the file stream last, since we don't want to have to
+ close it if anything goes wrong. Closing the stream means closing
+ the file descriptor too, even though we didn't open it.
+ */
+/*
+FUNCTION
+ bfd_fdopenr
+
+SYNOPSIS
+ bfd *bfd_fdopenr(CONST char *filename, CONST char *target, int fd);
+
+DESCRIPTION
+ bfd_fdopenr is to bfd_fopenr much like fdopen is to fopen.
+ It opens a BFD on a file already described by the @var{fd}
+ supplied.
+
+ When the file is later bfd_closed, the file descriptor will be closed.
+
+ If the caller desires that this file descriptor be cached by BFD
+ (opened as needed, closed as needed to free descriptors for
+ other opens), with the supplied @var{fd} used as an initial
+ file descriptor (but subject to closure at any time), set
+ bfd->cacheable nonzero in the returned BFD. The default is to
+ assume no cacheing; the file descriptor will remain open until
+ bfd_close, and will not be affected by BFD operations on other
+ files.
+
+ Possible errors are no_memory, invalid_target and system_call
+ error.
+*/
+
+bfd *
+DEFUN(bfd_fdopenr,(filename, target, fd),
+ CONST char *filename AND
+ CONST char *target AND
+ int fd)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+ int fdflags;
+
+ bfd_error = system_call_error;
+
+#ifdef NO_FCNTL
+ fdflags = O_RDWR; /* Assume full access */
+#else
+ fdflags = fcntl (fd, F_GETFL, NULL);
+#endif
+ if (fdflags == -1) return NULL;
+
+ nbfd = new_bfd();
+
+ if (nbfd == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ bfd_error = invalid_target;
+ return NULL;
+ }
+#if defined(VMS) || defined(__GO32__)
+ nbfd->iostream = (char *)fopen(filename, FOPEN_RB);
+#else
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (fdflags & (O_ACCMODE)) {
+ case O_RDONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RB); break;
+ case O_WRONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break;
+ case O_RDWR: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break;
+ default: abort ();
+ }
+#endif
+ if (nbfd->iostream == NULL) {
+ (void) obstack_free (&nbfd->memory, (PTR)0);
+ return NULL;
+ }
+
+ /* OK, put everything where it belongs */
+
+ nbfd->filename = filename;
+
+ /* As a special case we allow a FD open for read/write to
+ be written through, although doing so requires that we end
+ the previous clause with a preposition. */
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (fdflags & (O_ACCMODE)) {
+ case O_RDONLY: nbfd->direction = read_direction; break;
+ case O_WRONLY: nbfd->direction = write_direction; break;
+ case O_RDWR: nbfd->direction = both_direction; break;
+ default: abort ();
+ }
+
+ bfd_cache_init (nbfd);
+
+ return nbfd;
+}
+
+/** bfd_openw -- open for writing.
+ Returns a pointer to a freshly-allocated BFD on success, or NULL.
+
+ See comment by bfd_fdopenr before you try to modify this function. */
+
+/*
+FUNCTION
+ bfd_openw
+
+SYNOPSIS
+ bfd *bfd_openw(CONST char *filename, CONST char *target);
+
+DESCRIPTION
+ Creates a BFD, associated with file @var{filename}, using the
+ file format @var{target}, and returns a pointer to it.
+
+ Possible errors are system_call_error, no_memory,
+ invalid_target.
+*/
+
+bfd *
+DEFUN(bfd_openw,(filename, target),
+ CONST char *filename AND
+ CONST char *target)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+
+ bfd_error = system_call_error;
+
+ /* nbfd has to point to head of malloc'ed block so that bfd_close may
+ reclaim it correctly. */
+
+ nbfd = new_bfd();
+ if (nbfd == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) return NULL;
+
+ nbfd->filename = filename;
+ nbfd->direction = write_direction;
+
+ if (bfd_open_file (nbfd) == NULL) {
+ bfd_error = system_call_error; /* File not writeable, etc */
+ (void) obstack_free (&nbfd->memory, (PTR)0);
+ return NULL;
+ }
+ return nbfd;
+}
+
+/*
+
+FUNCTION
+ bfd_close
+
+SYNOPSIS
+ boolean bfd_close(bfd *);
+
+DESCRIPTION
+
+ This function closes a BFD. If the BFD was open for writing,
+ then pending operations are completed and the file written out
+ and closed. If the created file is executable, then
+ <<chmod>> is called to mark it as such.
+
+ All memory attached to the BFD's obstacks is released.
+
+ The file descriptor associated with the BFD is closed (even
+ if it was passed in to BFD by bfd_fdopenr).
+
+RETURNS
+ <<true>> is returned if all is ok, otherwise <<false>>.
+*/
+
+
+boolean
+DEFUN(bfd_close,(abfd),
+ bfd *abfd)
+{
+ boolean ret;
+
+ if (!bfd_read_p(abfd))
+ if (BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)) != true)
+ return false;
+
+ if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false;
+
+ ret = bfd_cache_close(abfd);
+
+ /* If the file was open for writing and is now executable,
+ make it so */
+ if (ret == true
+ && abfd->direction == write_direction
+ && abfd->flags & EXEC_P) {
+ struct stat buf;
+ stat(abfd->filename, &buf);
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010 /* Execute by group. */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001 /* Execute by others. */
+#endif
+
+ chmod(abfd->filename, 0777 & (buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH));
+ }
+ (void) obstack_free (&abfd->memory, (PTR)0);
+ (void) free(abfd);
+ return ret;
+}
+
+/*
+FUNCTION
+ bfd_close_all_done
+
+SYNOPSIS
+ boolean bfd_close_all_done(bfd *);
+
+DESCRIPTION
+ This function closes a BFD. It differs from <<bfd_close>>
+ since it does not complete any pending operations. This
+ routine would be used if the application had just used BFD for
+ swapping and didn't want to use any of the writing code.
+
+ If the created file is executable, then <<chmod>> is called
+ to mark it as such.
+
+ All memory attached to the BFD's obstacks is released.
+
+RETURNS
+ <<true>> is returned if all is ok, otherwise <<false>>.
+
+*/
+
+boolean
+DEFUN(bfd_close_all_done,(abfd),
+ bfd *abfd)
+{
+ boolean ret;
+
+ ret = bfd_cache_close(abfd);
+
+ /* If the file was open for writing and is now executable,
+ make it so */
+ if (ret == true
+ && abfd->direction == write_direction
+ && abfd->flags & EXEC_P) {
+ struct stat buf;
+ stat(abfd->filename, &buf);
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010 /* Execute by group. */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001 /* Execute by others. */
+#endif
+
+ chmod(abfd->filename, 0x777 &(buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH));
+ }
+ (void) obstack_free (&abfd->memory, (PTR)0);
+ (void) free(abfd);
+ return ret;
+}
+
+
+/*
+FUNCTION
+ bfd_alloc_size
+
+SYNOPSIS
+ bfd_size_type bfd_alloc_size(bfd *abfd);
+
+DESCRIPTION
+ Return the number of bytes in the obstacks connected to the
+ supplied BFD.
+
+*/
+
+bfd_size_type
+DEFUN(bfd_alloc_size,(abfd),
+ bfd *abfd)
+{
+ struct _obstack_chunk *chunk = abfd->memory.chunk;
+ size_t size = 0;
+ while (chunk) {
+ size += chunk->limit - &(chunk->contents[0]);
+ chunk = chunk->prev;
+ }
+ return size;
+}
+
+
+
+/*
+FUNCTION
+ bfd_create
+
+SYNOPSIS
+ bfd *bfd_create(CONST char *filename, bfd *templ);
+
+DESCRIPTION
+ This routine creates a new BFD in the manner of
+ <<bfd_openw>>, but without opening a file. The new BFD
+ takes the target from the target used by @var{template}. The
+ format is always set to <<bfd_object>>.
+
+*/
+
+bfd *
+DEFUN(bfd_create,(filename, templ),
+ CONST char *filename AND
+ bfd *templ)
+{
+ bfd *nbfd = new_bfd();
+ if (nbfd == (bfd *)NULL) {
+ bfd_error = no_memory;
+ return (bfd *)NULL;
+ }
+ nbfd->filename = filename;
+ if(templ) {
+ nbfd->xvec = templ->xvec;
+ }
+ nbfd->direction = no_direction;
+ bfd_set_format(nbfd, bfd_object);
+ return nbfd;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_alloc_by_size_t
+
+SYNOPSIS
+ PTR bfd_alloc_by_size_t(bfd *abfd, size_t wanted);
+
+DESCRIPTION
+ This function allocates a block of memory in the obstack
+ attatched to <<abfd>> and returns a pointer to it.
+*/
+
+
+PTR
+DEFUN(bfd_alloc_by_size_t,(abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ PTR res = obstack_alloc(&(abfd->memory), size);
+ return res;
+}
+
+DEFUN(void bfd_alloc_grow,(abfd, ptr, size),
+ bfd *abfd AND
+ PTR ptr AND
+ size_t size)
+{
+ (void) obstack_grow(&(abfd->memory), ptr, size);
+}
+DEFUN(PTR bfd_alloc_finish,(abfd),
+ bfd *abfd)
+{
+ return obstack_finish(&(abfd->memory));
+}
+
+DEFUN(PTR bfd_alloc, (abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ return bfd_alloc_by_size_t(abfd, (size_t)size);
+}
+
+DEFUN(PTR bfd_zalloc,(abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ PTR res;
+ res = bfd_alloc(abfd, size);
+ memset(res, 0, (size_t)size);
+ return res;
+}
+
+DEFUN(PTR bfd_realloc,(abfd, old, size),
+ bfd *abfd AND
+ PTR old AND
+ size_t size)
+{
+ PTR res = bfd_alloc(abfd, size);
+ memcpy(res, old, (size_t)size);
+ return res;
+}
diff --git a/gnu/usr.bin/gdb/bfd/reloc.c b/gnu/usr.bin/gdb/bfd/reloc.c
new file mode 100644
index 000000000000..f2dd5201d44b
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/reloc.c
@@ -0,0 +1,1225 @@
+/* BFD support for handling relocation entries.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Relocations
+
+ BFD maintains relocations in much the same was as it maintains
+ symbols; they are left alone until required, then read in
+ en-mass and traslated into an internal form. There is a common
+ routine <<bfd_perform_relocation>> which acts upon the
+ canonical form to do the actual fixup.
+
+ Note that relocations are maintained on a per section basis,
+ whilst symbols are maintained on a per BFD basis.
+
+ All a back end has to do to fit the BFD interface is to create
+ as many <<struct reloc_cache_entry>> as there are relocations
+ in a particular section, and fill in the right bits:
+
+@menu
+@* typedef arelent::
+@* howto manager::
+@end menu
+
+*/
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "seclet.h"
+/*
+DOCDD
+INODE
+ typedef arelent, howto manager, Relocations, Relocations
+
+SUBSECTION
+ typedef arelent
+
+ This is the structure of a relocation entry:
+
+CODE_FRAGMENT
+.
+.typedef enum bfd_reloc_status
+.{
+. {* No errors detected *}
+. bfd_reloc_ok,
+.
+. {* The relocation was performed, but there was an overflow. *}
+. bfd_reloc_overflow,
+.
+. {* The address to relocate was not within the section supplied. *}
+. bfd_reloc_outofrange,
+.
+. {* Used by special functions *}
+. bfd_reloc_continue,
+.
+. {* Unused *}
+. bfd_reloc_notsupported,
+.
+. {* Unsupported relocation size requested. *}
+. bfd_reloc_other,
+.
+. {* The symbol to relocate against was undefined. *}
+. bfd_reloc_undefined,
+.
+. {* The relocation was performed, but may not be ok - presently
+. generated only when linking i960 coff files with i960 b.out
+. symbols. *}
+. bfd_reloc_dangerous
+. }
+. bfd_reloc_status_type;
+.
+.
+.typedef struct reloc_cache_entry
+.{
+. {* A pointer into the canonical table of pointers *}
+. struct symbol_cache_entry **sym_ptr_ptr;
+.
+. {* offset in section *}
+. bfd_size_type address;
+.
+. {* addend for relocation value *}
+. bfd_vma addend;
+.
+. {* Pointer to how to perform the required relocation *}
+. CONST struct reloc_howto_struct *howto;
+.
+.} arelent;
+
+*/
+
+/*
+DESCRIPTION
+
+ Here is a description of each of the fields within a relent:
+
+ o sym_ptr_ptr
+
+ The symbol table pointer points to a pointer to the symbol
+ associated with the relocation request. This would naturally
+ be the pointer into the table returned by the back end's
+ get_symtab action. @xref{Symbols}. The symbol is referenced
+ through a pointer to a pointer so that tools like the linker
+ can fix up all the symbols of the same name by modifying only
+ one pointer. The relocation routine looks in the symbol and
+ uses the base of the section the symbol is attached to and the
+ value of the symbol as the initial relocation offset. If the
+ symbol pointer is zero, then the section provided is looked up.
+
+ o address
+
+ The address field gives the offset in bytes from the base of
+ the section data which owns the relocation record to the first
+ byte of relocatable information. The actual data relocated
+ will be relative to this point - for example, a relocation
+ type which modifies the bottom two bytes of a four byte word
+ would not touch the first byte pointed to in a big endian
+ world.
+
+ o addend
+
+ The addend is a value provided by the back end to be added (!)
+ to the relocation offset. Its interpretation is dependent upon
+ the howto. For example, on the 68k the code:
+
+
+| char foo[];
+| main()
+| {
+| return foo[0x12345678];
+| }
+
+ Could be compiled into:
+
+| linkw fp,#-4
+| moveb @@#12345678,d0
+| extbl d0
+| unlk fp
+| rts
+
+
+ This could create a reloc pointing to foo, but leave the
+ offset in the data (something like)
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000006 32 _foo
+|
+|00000000 4e56 fffc ; linkw fp,#-4
+|00000004 1039 1234 5678 ; moveb @@#12345678,d0
+|0000000a 49c0 ; extbl d0
+|0000000c 4e5e ; unlk fp
+|0000000e 4e75 ; rts
+
+
+ Using coff and an 88k, some instructions don't have enough
+ space in them to represent the full address range, and
+ pointers have to be loaded in two parts. So you'd get something like:
+
+
+| or.u r13,r0,hi16(_foo+0x12345678)
+| ld.b r2,r13,lo16(_foo+0x12345678)
+| jmp r1
+
+
+ This should create two relocs, both pointing to _foo, and with
+ 0x12340000 in their addend field. The data would consist of:
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000002 HVRT16 _foo+0x12340000
+|00000006 LVRT16 _foo+0x12340000
+
+|00000000 5da05678 ; or.u r13,r0,0x5678
+|00000004 1c4d5678 ; ld.b r2,r13,0x5678
+|00000008 f400c001 ; jmp r1
+
+
+ The relocation routine digs out the value from the data, adds
+ it to the addend to get the original offset and then adds the
+ value of _foo. Note that all 32 bits have to be kept around
+ somewhere, to cope with carry from bit 15 to bit 16.
+
+ One further example is the sparc and the a.out format. The
+ sparc has a similar problem to the 88k, in that some
+ instructions don't have room for an entire offset, but on the
+ sparc the parts are created odd sized lumps. The designers of
+ the a.out format chose not to use the data within the section
+ for storing part of the offset; all the offset is kept within
+ the reloc. Any thing in the data should be ignored.
+
+| save %sp,-112,%sp
+| sethi %hi(_foo+0x12345678),%g2
+| ldsb [%g2+%lo(_foo+0x12345678)],%i0
+| ret
+| restore
+
+ Both relocs contains a pointer to foo, and the offsets would
+ contain junk.
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000004 HI22 _foo+0x12345678
+|00000008 LO10 _foo+0x12345678
+
+|00000000 9de3bf90 ; save %sp,-112,%sp
+|00000004 05000000 ; sethi %hi(_foo+0),%g2
+|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0
+|0000000c 81c7e008 ; ret
+|00000010 81e80000 ; restore
+
+
+ o howto
+
+ The howto field can be imagined as a
+ relocation instruction. It is a pointer to a struct which
+ contains information on what to do with all the other
+ information in the reloc record and data section. A back end
+ would normally have a relocation instruction set and turn
+ relocations into pointers to the correct structure on input -
+ but it would be possible to create each howto field on demand.
+
+*/
+
+/*
+SUBSUBSECTION
+ <<enum complain_overflow>>
+
+ Indicates what sort of overflow checking should be done when
+ performing a relocation.
+
+CODE_FRAGMENT
+.
+.enum complain_overflow
+.{
+. {* Do not complain on overflow. *}
+. complain_overflow_dont,
+.
+. {* Complain if the bitfield overflows, whether it is considered
+. as signed or unsigned. *}
+. complain_overflow_bitfield,
+.
+. {* Complain if the value overflows when considered as signed
+. number. *}
+. complain_overflow_signed,
+.
+. {* Complain if the value overflows when considered as an
+. unsigned number. *}
+. complain_overflow_unsigned
+.};
+
+*/
+
+/*
+SUBSUBSECTION
+ <<reloc_howto_type>>
+
+ The <<reloc_howto_type>> is a structure which contains all the
+ information that BFD needs to know to tie up a back end's data.
+
+CODE_FRAGMENT
+.struct symbol_cache_entry; {* Forward declaration *}
+.
+.typedef CONST struct reloc_howto_struct
+.{
+. {* The type field has mainly a documetary use - the back end can
+. to what it wants with it, though the normally the back end's
+. external idea of what a reloc number would be would be stored
+. in this field. For example, the a PC relative word relocation
+. in a coff environment would have the type 023 - because that's
+. what the outside world calls a R_PCRWORD reloc. *}
+. unsigned int type;
+.
+. {* The value the final relocation is shifted right by. This drops
+. unwanted data from the relocation. *}
+. unsigned int rightshift;
+.
+. {* The size of the item to be relocated. This is *not* a
+. power-of-two measure.
+. 0 : one byte
+. 1 : two bytes
+. 2 : four bytes
+. 3 : nothing done (unless special_function is nonzero)
+. 4 : eight bytes
+. -2 : two bytes, result should be subtracted from the
+. data instead of added
+. There is currently no trivial way to extract a "number of
+. bytes" from a howto pointer. *}
+. int size;
+.
+. {* The number of bits in the item to be relocated. This is used
+. when doing overflow checking. *}
+. unsigned int bitsize;
+.
+. {* Notes that the relocation is relative to the location in the
+. data section of the addend. The relocation function will
+. subtract from the relocation value the address of the location
+. being relocated. *}
+. boolean pc_relative;
+.
+. {* The bit position of the reloc value in the destination.
+. The relocated value is left shifted by this amount. *}
+. unsigned int bitpos;
+.
+. {* What type of overflow error should be checked for when
+. relocating. *}
+. enum complain_overflow complain_on_overflow;
+.
+. {* If this field is non null, then the supplied function is
+. called rather than the normal function. This allows really
+. strange relocation methods to be accomodated (e.g., i960 callj
+. instructions). *}
+. bfd_reloc_status_type (*special_function)
+. PARAMS ((bfd *abfd,
+. arelent *reloc_entry,
+. struct symbol_cache_entry *symbol,
+. PTR data,
+. asection *input_section,
+. bfd *output_bfd));
+.
+. {* The textual name of the relocation type. *}
+. char *name;
+.
+. {* When performing a partial link, some formats must modify the
+. relocations rather than the data - this flag signals this.*}
+. boolean partial_inplace;
+.
+. {* The src_mask is used to select what parts of the read in data
+. are to be used in the relocation sum. E.g., if this was an 8 bit
+. bit of data which we read and relocated, this would be
+. 0x000000ff. When we have relocs which have an addend, such as
+. sun4 extended relocs, the value in the offset part of a
+. relocating field is garbage so we never use it. In this case
+. the mask would be 0x00000000. *}
+. bfd_vma src_mask;
+.
+. {* The dst_mask is what parts of the instruction are replaced
+. into the instruction. In most cases src_mask == dst_mask,
+. except in the above special case, where dst_mask would be
+. 0x000000ff, and src_mask would be 0x00000000. *}
+. bfd_vma dst_mask;
+.
+. {* When some formats create PC relative instructions, they leave
+. the value of the pc of the place being relocated in the offset
+. slot of the instruction, so that a PC relative relocation can
+. be made just by adding in an ordinary offset (e.g., sun3 a.out).
+. Some formats leave the displacement part of an instruction
+. empty (e.g., m88k bcs), this flag signals the fact.*}
+. boolean pcrel_offset;
+.
+.} reloc_howto_type;
+
+*/
+
+/*
+FUNCTION
+ the HOWTO macro
+
+DESCRIPTION
+ The HOWTO define is horrible and will go away.
+
+
+.#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+. {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC}
+
+DESCRIPTION
+ And will be replaced with the totally magic way. But for the
+ moment, we are compatible, so do it this way..
+
+
+.#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN)
+.
+DESCRIPTION
+ Helper routine to turn a symbol into a relocation value.
+
+.#define HOWTO_PREPARE(relocation, symbol) \
+. { \
+. if (symbol != (asymbol *)NULL) { \
+. if (bfd_is_com_section (symbol->section)) { \
+. relocation = 0; \
+. } \
+. else { \
+. relocation = symbol->value; \
+. } \
+. } \
+.}
+
+*/
+
+/*
+TYPEDEF
+ reloc_chain
+
+DESCRIPTION
+
+ How relocs are tied together
+
+.typedef unsigned char bfd_byte;
+.
+.typedef struct relent_chain {
+. arelent relent;
+. struct relent_chain *next;
+.} arelent_chain;
+
+*/
+
+
+
+/*
+FUNCTION
+ bfd_perform_relocation
+
+SYNOPSIS
+ bfd_reloc_status_type
+ bfd_perform_relocation
+ (bfd * abfd,
+ arelent *reloc_entry,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd);
+
+DESCRIPTION
+ If an output_bfd is supplied to this function the generated
+ image will be relocatable, the relocations are copied to the
+ output file after they have been changed to reflect the new
+ state of the world. There are two ways of reflecting the
+ results of partial linkage in an output file; by modifying the
+ output data in place, and by modifying the relocation record.
+ Some native formats (e.g., basic a.out and basic coff) have no
+ way of specifying an addend in the relocation type, so the
+ addend has to go in the output data. This is no big deal
+ since in these formats the output data slot will always be big
+ enough for the addend. Complex reloc types with addends were
+ invented to solve just this problem.
+
+*/
+
+
+bfd_reloc_status_type
+DEFUN(bfd_perform_relocation,(abfd,
+ reloc_entry,
+ data,
+ input_section,
+ output_bfd),
+ bfd *abfd AND
+ arelent *reloc_entry AND
+ PTR data AND
+ asection *input_section AND
+ bfd *output_bfd)
+{
+ bfd_vma relocation;
+ bfd_reloc_status_type flag = bfd_reloc_ok;
+ bfd_size_type addr = reloc_entry->address ;
+ bfd_vma output_base = 0;
+ reloc_howto_type *howto = reloc_entry->howto;
+ asection *reloc_target_output_section ;
+
+ asymbol *symbol;
+
+ symbol = *( reloc_entry->sym_ptr_ptr);
+ if ((symbol->section == &bfd_abs_section)
+ && output_bfd != (bfd *)NULL)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* If we are not producing relocateable output, return an error if
+ the symbol is not defined. An undefined weak symbol is
+ considered to have a value of zero (SVR4 ABI, p. 4-27). */
+ if (symbol->section == &bfd_und_section
+ && (symbol->flags & BSF_WEAK) == 0
+ && output_bfd == (bfd *) NULL)
+ flag = bfd_reloc_undefined;
+
+ /* If there is a function supplied to handle this relocation type,
+ call it. It'll return `bfd_reloc_continue' if further processing
+ can be done. */
+ if (howto->special_function)
+ {
+ bfd_reloc_status_type cont;
+ cont = howto->special_function (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd);
+ if (cont != bfd_reloc_continue)
+ return cont;
+ }
+
+ /* Is the address of the relocation really within the section? */
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ /* Work out which section the relocation is targetted at and the
+ initial relocation command value. */
+
+ /* Get symbol value. (Common symbols are special.) */
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+
+ reloc_target_output_section = symbol->section->output_section;
+
+ /* Convert input-section-relative symbol value to absolute. */
+ if (output_bfd && howto->partial_inplace==false)
+ output_base = 0;
+ else
+ output_base = reloc_target_output_section->vma;
+
+ relocation += output_base + symbol->section->output_offset;
+
+ /* Add in supplied addend. */
+ relocation += reloc_entry->addend;
+
+ /* Here the variable relocation holds the final address of the
+ symbol we are relocating against, plus any addend. */
+
+ if (howto->pc_relative == true)
+ {
+ /* This is a PC relative relocation. We want to set RELOCATION
+ to the distance between the address of the symbol and the
+ location. RELOCATION is already the address of the symbol.
+
+ We start by subtracting the address of the section containing
+ the location.
+
+ If pcrel_offset is set, we must further subtract the position
+ of the location within the section. Some targets arrange for
+ the addend to be the negative of the position of the location
+ within the section; for example, i386-aout does this. For
+ i386-aout, pcrel_offset is false. Some other targets do not
+ include the position of the location; for example, m88kbcs,
+ or ELF. For those targets, pcrel_offset is true.
+
+ If we are producing relocateable output, then we must ensure
+ that this reloc will be correctly computed when the final
+ relocation is done. If pcrel_offset is false we want to wind
+ up with the negative of the location within the section,
+ which means we must adjust the existing addend by the change
+ in the location within the section. If pcrel_offset is true
+ we do not want to adjust the existing addend at all.
+
+ FIXME: This seems logical to me, but for the case of
+ producing relocateable output it is not what the code
+ actually does. I don't want to change it, because it seems
+ far too likely that something will break. */
+
+ relocation -=
+ input_section->output_section->vma + input_section->output_offset;
+
+ if (howto->pcrel_offset == true)
+ relocation -= reloc_entry->address;
+ }
+
+ if (output_bfd!= (bfd *)NULL)
+ {
+ if ( howto->partial_inplace == false)
+ {
+ /* This is a partial relocation, and we want to apply the relocation
+ to the reloc entry rather than the raw data. Modify the reloc
+ inplace to reflect what we now know. */
+ reloc_entry->addend = relocation;
+ reloc_entry->address += input_section->output_offset;
+ return flag;
+ }
+ else
+ {
+ /* This is a partial relocation, but inplace, so modify the
+ reloc record a bit.
+
+ If we've relocated with a symbol with a section, change
+ into a ref to the section belonging to the symbol. */
+
+ reloc_entry->address += input_section->output_offset;
+
+ /* WTF?? */
+ if (abfd->xvec->flavour == bfd_target_coff_flavour)
+ {
+ relocation -= reloc_entry->addend;
+ reloc_entry->addend = 0;
+ }
+ else
+ {
+ reloc_entry->addend = relocation;
+ }
+ }
+ }
+ else
+ {
+ reloc_entry->addend = 0;
+ }
+
+ /* FIXME: This overflow checking is incomplete, because the value
+ might have overflowed before we get here. For a correct check we
+ need to compute the value in a size larger than bitsize, but we
+ can't reasonably do that for a reloc the same size as a host
+ machine word.
+ FIXME: We should also do overflow checking on the result after
+ adding in the value contained in the object file. */
+ if (howto->complain_on_overflow != complain_overflow_dont)
+ {
+ bfd_vma check;
+
+ /* Get the value that will be used for the relocation, but
+ starting at bit position zero. */
+ if (howto->rightshift > howto->bitpos)
+ check = relocation >> (howto->rightshift - howto->bitpos);
+ else
+ check = relocation << (howto->bitpos - howto->rightshift);
+ switch (howto->complain_on_overflow)
+ {
+ case complain_overflow_signed:
+ {
+ /* Assumes two's complement. */
+ bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
+ bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+
+ /* The above right shift is incorrect for a signed value.
+ Fix it up by forcing on the upper bits. */
+ if (howto->rightshift > howto->bitpos
+ && (bfd_signed_vma) relocation < 0)
+ check |= ((bfd_vma) -1
+ &~ ((bfd_vma) -1
+ >> (howto->rightshift - howto->bitpos)));
+ if ((bfd_signed_vma) check > reloc_signed_max
+ || (bfd_signed_vma) check < reloc_signed_min)
+ flag = bfd_reloc_overflow;
+ }
+ break;
+ case complain_overflow_unsigned:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_unsigned_max =
+ (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if ((bfd_vma) check > reloc_unsigned_max)
+ flag = bfd_reloc_overflow;
+ }
+ break;
+ case complain_overflow_bitfield:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if (((bfd_vma) check &~ reloc_bits) != 0
+ && ((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits))
+ {
+ /* The above right shift is incorrect for a signed
+ value. See if turning on the upper bits fixes the
+ overflow. */
+ if (howto->rightshift > howto->bitpos
+ && (bfd_signed_vma) relocation < 0)
+ {
+ check |= ((bfd_vma) -1
+ &~ ((bfd_vma) -1
+ >> (howto->rightshift - howto->bitpos)));
+ if (((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits))
+ flag = bfd_reloc_overflow;
+ }
+ else
+ flag = bfd_reloc_overflow;
+ }
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /*
+ Either we are relocating all the way, or we don't want to apply
+ the relocation to the reloc entry (probably because there isn't
+ any room in the output format to describe addends to relocs)
+ */
+ relocation >>= howto->rightshift;
+
+ /* Shift everything up to where it's going to be used */
+
+ relocation <<= howto->bitpos;
+
+ /* Wait for the day when all have the mask in them */
+
+ /* What we do:
+ i instruction to be left alone
+ o offset within instruction
+ r relocation offset to apply
+ S src mask
+ D dst mask
+ N ~dst mask
+ A part 1
+ B part 2
+ R result
+
+ Do this:
+ i i i i i o o o o o from bfd_get<size>
+ and S S S S S to get the size offset we want
+ + r r r r r r r r r r to get the final value to place
+ and D D D D D to chop to right size
+ -----------------------
+ A A A A A
+ And this:
+ ... i i i i i o o o o o from bfd_get<size>
+ and N N N N N get instruction
+ -----------------------
+ ... B B B B B
+
+ And then:
+ B B B B B
+ or A A A A A
+ -----------------------
+ R R R R R R R R R R put into bfd_put<size>
+ */
+
+#define DOIT(x) \
+ x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask))
+
+ switch (howto->size)
+ {
+ case 0:
+ {
+ char x = bfd_get_8(abfd, (char *)data + addr);
+ DOIT(x);
+ bfd_put_8(abfd,x, (unsigned char *) data + addr);
+ }
+ break;
+
+ case 1:
+ if (relocation)
+ {
+ short x = bfd_get_16(abfd, (bfd_byte *)data + addr);
+ DOIT(x);
+ bfd_put_16(abfd, x, (unsigned char *)data + addr);
+ }
+ break;
+ case 2:
+ if (relocation)
+ {
+ long x = bfd_get_32 (abfd, (bfd_byte *) data + addr);
+ DOIT (x);
+ bfd_put_32 (abfd, x, (bfd_byte *)data + addr);
+ }
+ break;
+ case -2:
+ {
+ long x = bfd_get_32(abfd, (bfd_byte *) data + addr);
+ relocation = -relocation;
+ DOIT(x);
+ bfd_put_32(abfd,x, (bfd_byte *)data + addr);
+ }
+ break;
+
+ case 3:
+ /* Do nothing */
+ break;
+
+ case 4:
+#ifdef BFD64
+ if (relocation)
+ {
+ bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr);
+ DOIT (x);
+ bfd_put_64 (abfd, x, (bfd_byte *) data + addr);
+ }
+#else
+ abort ();
+#endif
+ break;
+ default:
+ return bfd_reloc_other;
+ }
+
+ return flag;
+}
+
+
+
+/*
+DOCDD
+INODE
+ howto manager, , typedef arelent, Relocations
+
+SECTION
+ The howto manager
+
+ When an application wants to create a relocation, but doesn't
+ know what the target machine might call it, it can find out by
+ using this bit of code.
+
+*/
+
+/*
+TYPEDEF
+ bfd_reloc_code_type
+
+DESCRIPTION
+ The insides of a reloc code. The idea is that, eventually, there
+ will be one enumerator for every type of relocation we ever do.
+ Pass one of these values to <<bfd_reloc_type_lookup>>, and it'll
+ return a howto pointer.
+
+ This does mean that the application must determine the correct
+ enumerator value; you can't get a howto pointer from a random set
+ of attributes.
+
+CODE_FRAGMENT
+.
+.typedef enum bfd_reloc_code_real
+.{
+. {* Basic absolute relocations *}
+. BFD_RELOC_64,
+. BFD_RELOC_32,
+. BFD_RELOC_16,
+. BFD_RELOC_8,
+.
+. {* PC-relative relocations *}
+. BFD_RELOC_64_PCREL,
+. BFD_RELOC_32_PCREL,
+. BFD_RELOC_24_PCREL, {* used by i960 *}
+. BFD_RELOC_16_PCREL,
+. BFD_RELOC_8_PCREL,
+.
+. {* Linkage-table relative *}
+. BFD_RELOC_32_BASEREL,
+. BFD_RELOC_16_BASEREL,
+. BFD_RELOC_8_BASEREL,
+.
+. {* The type of reloc used to build a contructor table - at the moment
+. probably a 32 bit wide abs address, but the cpu can choose. *}
+. BFD_RELOC_CTOR,
+.
+. {* 8 bits wide, but used to form an address like 0xffnn *}
+. BFD_RELOC_8_FFnn,
+.
+. {* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit
+. word displacement, e.g. for SPARC) *}
+. BFD_RELOC_32_PCREL_S2,
+.
+. {* High 22 bits of 32-bit value, placed into lower 22 bits of
+. target word; simple reloc. *}
+. BFD_RELOC_HI22,
+. {* Low 10 bits. *}
+. BFD_RELOC_LO10,
+.
+. {* Reloc types used for i960/b.out. *}
+. BFD_RELOC_I960_CALLJ,
+.
+. {* now for the sparc/elf codes *}
+. BFD_RELOC_NONE, {* actually used *}
+. BFD_RELOC_SPARC_WDISP22,
+. BFD_RELOC_SPARC22,
+. BFD_RELOC_SPARC13,
+. BFD_RELOC_SPARC_GOT10,
+. BFD_RELOC_SPARC_GOT13,
+. BFD_RELOC_SPARC_GOT22,
+. BFD_RELOC_SPARC_PC10,
+. BFD_RELOC_SPARC_PC22,
+. BFD_RELOC_SPARC_WPLT30,
+. BFD_RELOC_SPARC_COPY,
+. BFD_RELOC_SPARC_GLOB_DAT,
+. BFD_RELOC_SPARC_JMP_SLOT,
+. BFD_RELOC_SPARC_RELATIVE,
+. BFD_RELOC_SPARC_UA32,
+.
+. {* these are a.out specific? *}
+. BFD_RELOC_SPARC_BASE13,
+. BFD_RELOC_SPARC_BASE22,
+.
+.
+. {* Bits 27..2 of the relocation address shifted right 2 bits;
+. simple reloc otherwise. *}
+. BFD_RELOC_MIPS_JMP,
+.
+. {* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) *}
+. BFD_RELOC_16_PCREL_S2,
+.
+. {* High 16 bits of 32-bit value; simple reloc. *}
+. BFD_RELOC_HI16,
+. {* High 16 bits of 32-bit value but the low 16 bits will be sign
+. extended and added to form the final result. If the low 16
+. bits form a negative number, we need to add one to the high value
+. to compensate for the borrow when the low bits are added. *}
+. BFD_RELOC_HI16_S,
+. {* Low 16 bits. *}
+. BFD_RELOC_LO16,
+.
+. {* 16 bit relocation relative to the global pointer. *}
+. BFD_RELOC_MIPS_GPREL,
+.
+. {* These are, so far, specific to HPPA processors. I'm not sure that some
+. don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL.
+. Also, many more were in the list I got that don't fit in well in the
+. model BFD uses, so I've omitted them for now. If we do make this reloc
+. type get used for code that really does implement the funky reloc types,
+. they'll have to be added to this list. *}
+. BFD_RELOC_HPPA_32,
+. BFD_RELOC_HPPA_11,
+. BFD_RELOC_HPPA_14,
+. BFD_RELOC_HPPA_17,
+.
+. BFD_RELOC_HPPA_L21,
+. BFD_RELOC_HPPA_R11,
+. BFD_RELOC_HPPA_R14,
+. BFD_RELOC_HPPA_R17,
+. BFD_RELOC_HPPA_LS21,
+. BFD_RELOC_HPPA_RS11,
+. BFD_RELOC_HPPA_RS14,
+. BFD_RELOC_HPPA_RS17,
+. BFD_RELOC_HPPA_LD21,
+. BFD_RELOC_HPPA_RD11,
+. BFD_RELOC_HPPA_RD14,
+. BFD_RELOC_HPPA_RD17,
+. BFD_RELOC_HPPA_LR21,
+. BFD_RELOC_HPPA_RR14,
+. BFD_RELOC_HPPA_RR17,
+.
+. BFD_RELOC_HPPA_GOTOFF_11,
+. BFD_RELOC_HPPA_GOTOFF_14,
+. BFD_RELOC_HPPA_GOTOFF_L21,
+. BFD_RELOC_HPPA_GOTOFF_R11,
+. BFD_RELOC_HPPA_GOTOFF_R14,
+. BFD_RELOC_HPPA_GOTOFF_LS21,
+. BFD_RELOC_HPPA_GOTOFF_RS11,
+. BFD_RELOC_HPPA_GOTOFF_RS14,
+. BFD_RELOC_HPPA_GOTOFF_LD21,
+. BFD_RELOC_HPPA_GOTOFF_RD11,
+. BFD_RELOC_HPPA_GOTOFF_RD14,
+. BFD_RELOC_HPPA_GOTOFF_LR21,
+. BFD_RELOC_HPPA_GOTOFF_RR14,
+.
+. BFD_RELOC_HPPA_DLT_32,
+. BFD_RELOC_HPPA_DLT_11,
+. BFD_RELOC_HPPA_DLT_14,
+. BFD_RELOC_HPPA_DLT_L21,
+. BFD_RELOC_HPPA_DLT_R11,
+. BFD_RELOC_HPPA_DLT_R14,
+.
+. BFD_RELOC_HPPA_ABS_CALL_11,
+. BFD_RELOC_HPPA_ABS_CALL_14,
+. BFD_RELOC_HPPA_ABS_CALL_17,
+. BFD_RELOC_HPPA_ABS_CALL_L21,
+. BFD_RELOC_HPPA_ABS_CALL_R11,
+. BFD_RELOC_HPPA_ABS_CALL_R14,
+. BFD_RELOC_HPPA_ABS_CALL_R17,
+. BFD_RELOC_HPPA_ABS_CALL_LS21,
+. BFD_RELOC_HPPA_ABS_CALL_RS11,
+. BFD_RELOC_HPPA_ABS_CALL_RS14,
+. BFD_RELOC_HPPA_ABS_CALL_RS17,
+. BFD_RELOC_HPPA_ABS_CALL_LD21,
+. BFD_RELOC_HPPA_ABS_CALL_RD11,
+. BFD_RELOC_HPPA_ABS_CALL_RD14,
+. BFD_RELOC_HPPA_ABS_CALL_RD17,
+. BFD_RELOC_HPPA_ABS_CALL_LR21,
+. BFD_RELOC_HPPA_ABS_CALL_RR14,
+. BFD_RELOC_HPPA_ABS_CALL_RR17,
+.
+. BFD_RELOC_HPPA_PCREL_CALL_11,
+. BFD_RELOC_HPPA_PCREL_CALL_12,
+. BFD_RELOC_HPPA_PCREL_CALL_14,
+. BFD_RELOC_HPPA_PCREL_CALL_17,
+. BFD_RELOC_HPPA_PCREL_CALL_L21,
+. BFD_RELOC_HPPA_PCREL_CALL_R11,
+. BFD_RELOC_HPPA_PCREL_CALL_R14,
+. BFD_RELOC_HPPA_PCREL_CALL_R17,
+. BFD_RELOC_HPPA_PCREL_CALL_LS21,
+. BFD_RELOC_HPPA_PCREL_CALL_RS11,
+. BFD_RELOC_HPPA_PCREL_CALL_RS14,
+. BFD_RELOC_HPPA_PCREL_CALL_RS17,
+. BFD_RELOC_HPPA_PCREL_CALL_LD21,
+. BFD_RELOC_HPPA_PCREL_CALL_RD11,
+. BFD_RELOC_HPPA_PCREL_CALL_RD14,
+. BFD_RELOC_HPPA_PCREL_CALL_RD17,
+. BFD_RELOC_HPPA_PCREL_CALL_LR21,
+. BFD_RELOC_HPPA_PCREL_CALL_RR14,
+. BFD_RELOC_HPPA_PCREL_CALL_RR17,
+.
+. BFD_RELOC_HPPA_PLABEL_32,
+. BFD_RELOC_HPPA_PLABEL_11,
+. BFD_RELOC_HPPA_PLABEL_14,
+. BFD_RELOC_HPPA_PLABEL_L21,
+. BFD_RELOC_HPPA_PLABEL_R11,
+. BFD_RELOC_HPPA_PLABEL_R14,
+.
+. BFD_RELOC_HPPA_UNWIND_ENTRY,
+. BFD_RELOC_HPPA_UNWIND_ENTRIES,
+.
+. {* i386/elf relocations *}
+. BFD_RELOC_386_GOT32,
+. BFD_RELOC_386_PLT32,
+. BFD_RELOC_386_COPY,
+. BFD_RELOC_386_GLOB_DAT,
+. BFD_RELOC_386_JUMP_SLOT,
+. BFD_RELOC_386_RELATIVE,
+. BFD_RELOC_386_GOTOFF,
+. BFD_RELOC_386_GOTPC,
+.
+. {* this must be the highest numeric value *}
+. BFD_RELOC_UNUSED
+. } bfd_reloc_code_real_type;
+*/
+
+
+/*
+SECTION
+ bfd_reloc_type_lookup
+
+SYNOPSIS
+ CONST struct reloc_howto_struct *
+ bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ This routine returns a pointer to a howto struct which when
+ invoked, will perform the supplied relocation on data from the
+ architecture noted.
+
+*/
+
+
+CONST struct reloc_howto_struct *
+DEFUN(bfd_reloc_type_lookup,(abfd, code),
+ bfd *abfd AND
+ bfd_reloc_code_real_type code)
+{
+ return BFD_SEND (abfd, reloc_type_lookup, (abfd, code));
+}
+
+static reloc_howto_type bfd_howto_32 =
+ HOWTO(0, 00,2,32,false,0,complain_overflow_bitfield,0,"VRT32", false,0xffffffff,0xffffffff,true);
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_reloc_type_lookup
+
+SYNOPSIS
+ CONST struct reloc_howto_struct *bfd_default_reloc_type_lookup
+ (bfd *abfd AND
+ bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ Provides a default relocation lookup routine for any architecture.
+
+
+*/
+
+CONST struct reloc_howto_struct *
+DEFUN(bfd_default_reloc_type_lookup, (abfd, code),
+ bfd *abfd AND
+ bfd_reloc_code_real_type code)
+{
+ switch (code)
+ {
+ case BFD_RELOC_CTOR:
+ /* The type of reloc used in a ctor, which will be as wide as the
+ address - so either a 64, 32, or 16 bitter. */
+ switch (bfd_get_arch_info (abfd)->bits_per_address) {
+ case 64:
+ BFD_FAIL();
+ case 32:
+ return &bfd_howto_32;
+ case 16:
+ BFD_FAIL();
+ default:
+ BFD_FAIL();
+ }
+ default:
+ BFD_FAIL();
+ }
+ return (CONST struct reloc_howto_struct *)NULL;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_relax_section
+
+SYNOPSIS
+ boolean bfd_generic_relax_section
+ (bfd *abfd,
+ asection *section,
+ asymbol **symbols);
+
+DESCRIPTION
+ Provides default handling for relaxing for back ends which
+ don't do relaxing -- i.e., does nothing.
+*/
+
+boolean
+DEFUN(bfd_generic_relax_section,(abfd, section, symbols),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **symbols)
+{
+
+ return false;
+
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_get_relocated_section_contents
+
+SYNOPSIS
+ bfd_byte *
+ bfd_generic_get_relocated_section_contents (bfd *abfd,
+ struct bfd_seclet *seclet,
+ bfd_byte *data,
+ boolean relocateable);
+
+DESCRIPTION
+ Provides default handling of relocation effort for back ends
+ which can't be bothered to do it efficiently.
+
+*/
+
+bfd_byte *
+DEFUN(bfd_generic_get_relocated_section_contents,(abfd,
+ seclet,
+ data,
+ relocateable),
+ bfd *abfd AND
+ struct bfd_seclet *seclet AND
+ bfd_byte *data AND
+ boolean relocateable)
+{
+ extern bfd_error_vector_type bfd_error_vector;
+
+ /* Get enough memory to hold the stuff */
+ bfd *input_bfd = seclet->u.indirect.section->owner;
+ asection *input_section = seclet->u.indirect.section;
+
+
+
+ size_t reloc_size = bfd_get_reloc_upper_bound(input_bfd, input_section);
+ arelent **reloc_vector = (arelent **) alloca(reloc_size);
+
+ /* read in the section */
+ bfd_get_section_contents(input_bfd,
+ input_section,
+ data,
+ 0,
+ input_section->_raw_size);
+
+/* We're not relaxing the section, so just copy the size info */
+ input_section->_cooked_size = input_section->_raw_size;
+ input_section->reloc_done = true;
+
+
+ if (bfd_canonicalize_reloc(input_bfd,
+ input_section,
+ reloc_vector,
+ seclet->u.indirect.symbols) )
+ {
+ arelent **parent;
+ for (parent = reloc_vector; * parent != (arelent *)NULL;
+ parent++)
+ {
+ bfd_reloc_status_type r=
+ bfd_perform_relocation(input_bfd,
+ *parent,
+ data,
+ input_section,
+ relocateable ? abfd : (bfd *) NULL);
+
+ if (relocateable)
+ {
+ asection *os = input_section->output_section;
+
+ /* A partial link, so keep the relocs */
+ os->orelocation[os->reloc_count] = *parent;
+ os->reloc_count++;
+ }
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ case bfd_reloc_undefined:
+ bfd_error_vector.undefined_symbol(*parent, seclet);
+ break;
+ case bfd_reloc_dangerous:
+ bfd_error_vector.reloc_dangerous(*parent, seclet);
+ break;
+ case bfd_reloc_outofrange:
+ case bfd_reloc_overflow:
+ bfd_error_vector.reloc_value_truncated(*parent, seclet);
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ }
+ }
+ }
+
+
+ return data;
+
+
+}
diff --git a/gnu/usr.bin/gdb/bfd/seclet.c b/gnu/usr.bin/gdb/bfd/seclet.c
new file mode 100644
index 000000000000..5dcc59ab0ef8
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/seclet.c
@@ -0,0 +1,185 @@
+/* seclet.c
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module is part of BFD */
+
+
+/* The intention is that one day, all the code which uses sections
+ will change and use seclets instead - maybe seglet would have been
+ a better name..
+
+ Anyway, a seclet contains enough info to be able to describe an
+ area of output memory in one go.
+
+ The only description so far catered for is that of the
+ <<bfd_indirect_seclet>>, which is a select which points to a
+ <<section>> and the <<asymbols>> associated with the section, so
+ that relocation can be done when needed.
+
+ One day there will be more types - they will at least migrate from
+ the linker's data structures - also there could be extra stuff,
+ like a bss seclet, which descibes a lump of memory as containing
+ zeros compactly, without the horrible SEC_* flag cruft.
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "seclet.h"
+#include "coff/internal.h"
+
+/* Create a new seclet and attach it to a section. */
+
+bfd_seclet_type *
+DEFUN(bfd_new_seclet,(abfd, section),
+ bfd *abfd AND
+ asection *section)
+{
+ bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type));
+ if (section->seclets_tail != (bfd_seclet_type *)NULL) {
+ section->seclets_tail->next = n;
+ }
+ else
+ {
+ section->seclets_head = n;
+ }
+ section->seclets_tail = n;
+
+ return n;
+}
+
+/* Given an indirect seclet which points to an input section, relocate
+ the contents of the seclet and put the data in its final
+ destination. */
+
+static boolean
+DEFUN(rel,(abfd, seclet, output_section, data, relocateable),
+ bfd *abfd AND
+ bfd_seclet_type *seclet AND
+ asection *output_section AND
+ PTR data AND
+ boolean relocateable)
+{
+ if ((output_section->flags & SEC_HAS_CONTENTS) != 0
+ && seclet->size)
+ {
+ data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data,
+ relocateable);
+ if(bfd_set_section_contents(abfd,
+ output_section,
+ data,
+ seclet->offset,
+ seclet->size) == false)
+ {
+ abort();
+ }
+ }
+ return true;
+}
+
+/* Put the contents of a seclet in its final destination. */
+
+static boolean
+DEFUN(seclet_dump_seclet,(abfd, seclet, section, data, relocateable),
+ bfd *abfd AND
+ bfd_seclet_type *seclet AND
+ asection *section AND
+ PTR data AND
+ boolean relocateable)
+{
+ switch (seclet->type)
+ {
+ case bfd_indirect_seclet:
+ /* The contents of this section come from another one somewhere
+ else */
+ return rel(abfd, seclet, section, data, relocateable);
+
+ case bfd_fill_seclet:
+ /* Fill in the section with us */
+ {
+ char *d = bfd_xmalloc(seclet->size);
+ unsigned int i;
+ for (i =0; i < seclet->size; i+=2) {
+ d[i] = seclet->u.fill.value >> 8;
+ }
+ for (i = 1; i < seclet->size; i+=2) {
+ d[i] = seclet->u.fill.value ;
+ }
+ /* Don't bother to fill in empty sections */
+ if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS))
+ {
+ return true;
+ }
+ return bfd_set_section_contents(abfd, section, d, seclet->offset,
+ seclet->size);
+ }
+
+ default:
+ abort();
+ }
+
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_seclet_link
+
+SYNOPSIS
+ boolean bfd_generic_seclet_link
+ (bfd *abfd,
+ PTR data,
+ boolean relocateable);
+
+DESCRIPTION
+
+ The generic seclet linking routine. The caller should have
+ set up seclets for all the output sections. The DATA argument
+ should point to a memory area large enough to hold the largest
+ section. This function looks through the seclets and moves
+ the contents into the output sections. If RELOCATEABLE is
+ true, the orelocation fields of the output sections must
+ already be initialized.
+
+*/
+
+boolean
+DEFUN(bfd_generic_seclet_link,(abfd, data, relocateable),
+ bfd *abfd AND
+ PTR data AND
+ boolean relocateable)
+{
+ asection *o = abfd->sections;
+ while (o != (asection *)NULL)
+ {
+ bfd_seclet_type *p = o->seclets_head;
+ while (p != (bfd_seclet_type *)NULL)
+ {
+ if (seclet_dump_seclet(abfd, p, o, data, relocateable) == false)
+ return false;
+ p = p ->next;
+ }
+ o = o->next;
+ }
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/seclet.h b/gnu/usr.bin/gdb/bfd/seclet.h
new file mode 100644
index 000000000000..de5fdff0bb14
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/seclet.h
@@ -0,0 +1,55 @@
+/* Definitions of little sections (seclets) for BFD.
+ Copyright 1992 Free Software Foundation, Inc.
+ Hacked by Steve Chamberlain of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _SECLET_H
+#define _SECLET_H
+
+enum bfd_seclet_enum
+{
+ bfd_indirect_seclet,
+ bfd_fill_seclet
+};
+
+struct bfd_seclet
+{
+ struct bfd_seclet *next;
+ enum bfd_seclet_enum type;
+ unsigned int offset;
+ unsigned int size;
+ union
+ {
+ struct
+ {
+ asection *section;
+ asymbol **symbols;
+ } indirect;
+ struct {
+ int value;
+ } fill;
+ }
+ u;
+};
+
+typedef struct bfd_seclet bfd_seclet_type;
+
+bfd_seclet_type *
+bfd_new_seclet PARAMS ((bfd *, asection *));
+
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/section.c b/gnu/usr.bin/gdb/bfd/section.c
new file mode 100644
index 000000000000..547c69e2cb84
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/section.c
@@ -0,0 +1,899 @@
+/* Object file "section" support for the BFD library.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Sections
+
+ Sections are supported in BFD in <<section.c>>.
+
+ The raw data contained within a BFD is maintained through the
+ section abstraction. A single BFD may have any number of
+ sections, and keeps hold of them by pointing to the first,
+ each one points to the next in the list.
+
+@menu
+@* Section Input::
+@* Section Output::
+@* typedef asection::
+@* section prototypes::
+@end menu
+
+INODE
+Section Input, Section Output, Sections, Sections
+SUBSECTION
+ Section Input
+
+ When a BFD is opened for reading, the section structures are
+ created and attached to the BFD.
+
+ Each section has a name which describes the section in the
+ outside world - for example, <<a.out>> would contain at least
+ three sections, called <<.text>>, <<.data>> and <<.bss>>.
+
+ Names need not be unique; for example a COFF file may have several
+ sections named .data.
+
+ Sometimes a BFD will contain more than the 'natural' number of
+ sections. A back end may attach other sections containing
+ constructor data, or an application may add a section (using
+ bfd_make_section) to the sections attached to an already open
+ BFD. For example, the linker creates a supernumary section
+ <<COMMON>> for each input file's BFD to hold information about
+ common storage.
+
+ The raw data is not necessarily read in at the same time as
+ the section descriptor is created. Some targets may leave the
+ data in place until a <<bfd_get_section_contents>> call is
+ made. Other back ends may read in all the data at once - For
+ example; an S-record file has to be read once to determine the
+ size of the data. An IEEE-695 file doesn't contain raw data in
+ sections, but data and relocation expressions intermixed, so
+ the data area has to be parsed to get out the data and
+ relocations.
+
+INODE
+Section Output, typedef asection, Section Input, Sections
+
+SUBSECTION
+ Section Output
+
+ To write a new object style BFD, the various sections to be
+ written have to be created. They are attached to the BFD in
+ the same way as input sections, data is written to the
+ sections using <<bfd_set_section_contents>>.
+
+ Any program that creates or combines sections (e.g., the assembler
+ and linker) must use the fields <<output_section>> and
+ <<output_offset>> to indicate the file sections to which each
+ section must be written. (If the section is being created from
+ scratch, <<output_section>> should probably point to the section
+ itself, and <<output_offset>> should probably be zero.)
+
+ The data to be written comes from input sections attached to
+ the output sections. The output section structure can be
+ considered a filter for the input section, the output section
+ determines the vma of the output data and the name, but the
+ input section determines the offset into the output section of
+ the data to be written.
+
+ E.g., to create a section "O", starting at 0x100, 0x123 long,
+ containing two subsections, "A" at offset 0x0 (ie at vma
+ 0x100) and "B" at offset 0x20 (ie at vma 0x120) the structures
+ would look like:
+
+| section name "A"
+| output_offset 0x00
+| size 0x20
+| output_section -----------> section name "O"
+| | vma 0x100
+| section name "B" | size 0x123
+| output_offset 0x20 |
+| size 0x103 |
+| output_section --------|
+
+
+SUBSECTION
+ Seglets
+
+ The data within a section is stored in a <<seglet>>. These
+ are much like the fixups in <<gas>>. The seglet abstraction
+ allows the a section to grow and shrink within itself.
+
+ A seglet knows how big it is, and which is the next seglet and
+ where the raw data for it is, and also points to a list of
+ relocations which apply to it.
+
+ The seglet is used by the linker to perform relaxing on final
+ code. The application creates code which is as big as
+ necessary to make it work without relaxing, and the user can
+ select whether to relax. Sometimes relaxing takes a lot of
+ time. The linker runs around the relocations to see if any
+ are attached to data which can be shrunk, if so it does it on
+ a seglet by seglet basis.
+
+*/
+
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+DOCDD
+INODE
+typedef asection, section prototypes, Section Output, Sections
+SUBSECTION
+ typedef asection
+
+ The shape of a section struct:
+
+CODE_FRAGMENT
+.
+.typedef struct sec
+.{
+. {* The name of the section, the name isn't a copy, the pointer is
+. the same as that passed to bfd_make_section. *}
+.
+. CONST char *name;
+.
+. {* Which section is it 0.nth *}
+.
+. int index;
+.
+. {* The next section in the list belonging to the BFD, or NULL. *}
+.
+. struct sec *next;
+.
+. {* The field flags contains attributes of the section. Some of
+. flags are read in from the object file, and some are
+. synthesized from other information. *}
+.
+. flagword flags;
+.
+.#define SEC_NO_FLAGS 0x000
+.
+. {* Tells the OS to allocate space for this section when loaded.
+. This would clear for a section containing debug information
+. only. *}
+.#define SEC_ALLOC 0x001
+.
+. {* Tells the OS to load the section from the file when loading.
+. This would be clear for a .bss section *}
+.#define SEC_LOAD 0x002
+.
+. {* The section contains data still to be relocated, so there will
+. be some relocation information too. *}
+.#define SEC_RELOC 0x004
+.
+.#if 0 {* Obsolete ? *}
+.#define SEC_BALIGN 0x008
+.#endif
+.
+. {* A signal to the OS that the section contains read only
+. data. *}
+.#define SEC_READONLY 0x010
+.
+. {* The section contains code only. *}
+.#define SEC_CODE 0x020
+.
+. {* The section contains data only. *}
+.#define SEC_DATA 0x040
+.
+. {* The section will reside in ROM. *}
+.#define SEC_ROM 0x080
+.
+. {* The section contains constructor information. This section
+. type is used by the linker to create lists of constructors and
+. destructors used by <<g++>>. When a back end sees a symbol
+. which should be used in a constructor list, it creates a new
+. section for the type of name (eg <<__CTOR_LIST__>>), attaches
+. the symbol to it and builds a relocation. To build the lists
+. of constructors, all the linker has to do is catenate all the
+. sections called <<__CTOR_LIST__>> and relocte the data
+. contained within - exactly the operations it would peform on
+. standard data. *}
+.#define SEC_CONSTRUCTOR 0x100
+.
+. {* The section is a constuctor, and should be placed at the
+. end of the text, data, or bss section(?). *}
+.#define SEC_CONSTRUCTOR_TEXT 0x1100
+.#define SEC_CONSTRUCTOR_DATA 0x2100
+.#define SEC_CONSTRUCTOR_BSS 0x3100
+.
+. {* The section has contents - a data section could be
+. <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>, a debug section could be
+. <<SEC_HAS_CONTENTS>> *}
+.#define SEC_HAS_CONTENTS 0x200
+.
+. {* An instruction to the linker not to output sections
+. containing this flag even if they have information which
+. would normally be written. *}
+.#define SEC_NEVER_LOAD 0x400
+.
+. {* The section is a shared library section. The linker must leave
+. these completely alone, as the vma and size are used when
+. the executable is loaded. *}
+.#define SEC_SHARED_LIBRARY 0x800
+.
+. {* The section is a common section (symbols may be defined
+. multiple times, the value of a symbol is the amount of
+. space it requires, and the largest symbol value is the one
+. used). Most targets have exactly one of these (which we
+. translate to bfd_com_section), but ECOFF has two. *}
+.#define SEC_IS_COMMON 0x8000
+.
+. {* The section contains only debugging information. For
+. example, this is set for ELF .debug and .stab sections.
+. strip tests this flag to see if a section can be
+. discarded. *}
+.#define SEC_DEBUGGING 0x10000
+.
+. {* End of section flags. *}
+.
+. {* The virtual memory address of the section - where it will be
+. at run time. The symbols are relocated against this. The
+. user_set_vma flag is maintained by bfd; if it's not set, the
+. backend can assign addresses (for example, in <<a.out>>, where
+. the default address for <<.data>> is dependent on the specific
+. target and various flags). *}
+.
+. bfd_vma vma;
+. boolean user_set_vma;
+.
+. {* The load address of the section - where it would be in a
+. rom image, really only used for writing section header
+. information. *}
+.
+. bfd_vma lma;
+.
+. {* The size of the section in bytes, as it will be output.
+. contains a value even if the section has no contents (eg, the
+. size of <<.bss>>). This will be filled in after relocation *}
+.
+. bfd_size_type _cooked_size;
+.
+. {* The size on disk of the section in bytes originally. Normally this
+. value is the same as the size, but if some relaxing has
+. been done, then this value will be bigger. *}
+.
+. bfd_size_type _raw_size;
+.
+. {* If this section is going to be output, then this value is the
+. offset into the output section of the first byte in the input
+. section. Eg, if this was going to start at the 100th byte in
+. the output section, this value would be 100. *}
+.
+. bfd_vma output_offset;
+.
+. {* The output section through which to map on output. *}
+.
+. struct sec *output_section;
+.
+. {* The alignment requirement of the section, as an exponent - eg
+. 3 aligns to 2^3 (or 8) *}
+.
+. unsigned int alignment_power;
+.
+. {* If an input section, a pointer to a vector of relocation
+. records for the data in this section. *}
+.
+. struct reloc_cache_entry *relocation;
+.
+. {* If an output section, a pointer to a vector of pointers to
+. relocation records for the data in this section. *}
+.
+. struct reloc_cache_entry **orelocation;
+.
+. {* The number of relocation records in one of the above *}
+.
+. unsigned reloc_count;
+.
+. {* Information below is back end specific - and not always used
+. or updated. *}
+.
+. {* File position of section data *}
+.
+. file_ptr filepos;
+.
+. {* File position of relocation info *}
+.
+. file_ptr rel_filepos;
+.
+. {* File position of line data *}
+.
+. file_ptr line_filepos;
+.
+. {* Pointer to data for applications *}
+.
+. PTR userdata;
+.
+. struct lang_output_section *otheruserdata;
+.
+. {* Attached line number information *}
+.
+. alent *lineno;
+.
+. {* Number of line number records *}
+.
+. unsigned int lineno_count;
+.
+. {* When a section is being output, this value changes as more
+. linenumbers are written out *}
+.
+. file_ptr moving_line_filepos;
+.
+. {* what the section number is in the target world *}
+.
+. int target_index;
+.
+. PTR used_by_bfd;
+.
+. {* If this is a constructor section then here is a list of the
+. relocations created to relocate items within it. *}
+.
+. struct relent_chain *constructor_chain;
+.
+. {* The BFD which owns the section. *}
+.
+. bfd *owner;
+.
+. boolean reloc_done;
+. {* A symbol which points at this section only *}
+. struct symbol_cache_entry *symbol;
+. struct symbol_cache_entry **symbol_ptr_ptr;
+.
+. struct bfd_seclet *seclets_head;
+. struct bfd_seclet *seclets_tail;
+.} asection ;
+.
+.
+. {* These sections are global, and are managed by BFD. The application
+. and target back end are not permitted to change the values in
+. these sections. *}
+.#define BFD_ABS_SECTION_NAME "*ABS*"
+.#define BFD_UND_SECTION_NAME "*UND*"
+.#define BFD_COM_SECTION_NAME "*COM*"
+.#define BFD_IND_SECTION_NAME "*IND*"
+.
+. {* the absolute section *}
+.extern asection bfd_abs_section;
+. {* Pointer to the undefined section *}
+.extern asection bfd_und_section;
+. {* Pointer to the common section *}
+.extern asection bfd_com_section;
+. {* Pointer to the indirect section *}
+.extern asection bfd_ind_section;
+.
+.extern struct symbol_cache_entry *bfd_abs_symbol;
+.extern struct symbol_cache_entry *bfd_com_symbol;
+.extern struct symbol_cache_entry *bfd_und_symbol;
+.extern struct symbol_cache_entry *bfd_ind_symbol;
+.#define bfd_get_section_size_before_reloc(section) \
+. (section->reloc_done ? (abort(),1): (section)->_raw_size)
+.#define bfd_get_section_size_after_reloc(section) \
+. ((section->reloc_done) ? (section)->_cooked_size: (abort(),1))
+*/
+
+/* These symbols are global, not specific to any BFD. Therefore, anything
+ that tries to change them is broken, and should be repaired. */
+static CONST asymbol global_syms[] = {
+ /* the_bfd, name, value, attr, section [, udata] */
+ { 0, BFD_COM_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_com_section },
+ { 0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_und_section },
+ { 0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_abs_section },
+ { 0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_ind_section },
+};
+
+#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \
+ asymbol *SYM = (asymbol *) &global_syms[IDX]; \
+ asection SEC = { NAME, 0, 0, FLAGS, 0, 0, (boolean) 0, 0, 0, 0, &SEC,\
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \
+ (asymbol *) &global_syms[IDX], &SYM, }
+
+STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol, BFD_COM_SECTION_NAME, 0);
+STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1);
+STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2);
+STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3);
+#undef STD_SECTION
+
+/*
+DOCDD
+INODE
+section prototypes, , typedef asection, Sections
+SUBSECTION
+ section prototypes
+
+These are the functions exported by the section handling part of
+<<libbfd>.
+*/
+
+/*
+FUNCTION
+ bfd_get_section_by_name
+
+SYNOPSIS
+ asection *bfd_get_section_by_name(bfd *abfd, CONST char *name);
+
+DESCRIPTION
+ Runs through the provided @var{abfd} and returns the one of the
+ <<asection>>s who's name matches that provided, otherwise NULL.
+ @xref{Sections}, for more information.
+
+ This should only be used in special cases; the normal way to process
+ all sections of a given name is to use bfd_map_over_sections and
+ strcmp on the name (or better yet, base it on the section flags
+ or something else) for each section.
+*/
+
+asection *
+DEFUN(bfd_get_section_by_name,(abfd, name),
+ bfd *abfd AND
+ CONST char *name)
+{
+ asection *sect;
+
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ if (!strcmp (sect->name, name)) return sect;
+ return NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_make_section_old_way
+
+SYNOPSIS
+ asection *bfd_make_section_old_way(bfd *, CONST char *name);
+
+DESCRIPTION
+ This function creates a new empty section called @var{name}
+ and attaches it to the end of the chain of sections for the
+ BFD supplied. An attempt to create a section with a name which
+ is already in use, returns its pointer without changing the
+ section chain.
+
+ It has the funny name since this is the way it used to be
+ before is was rewritten...
+
+ Possible errors are:
+ o invalid_operation -
+ If output has already started for this BFD.
+ o no_memory -
+ If obstack alloc fails.
+
+*/
+
+
+asection *
+DEFUN(bfd_make_section_old_way,(abfd, name),
+ bfd *abfd AND
+ CONST char * name)
+{
+ asection *sec = bfd_get_section_by_name(abfd, name);
+ if (sec == (asection *)NULL)
+ {
+ sec = bfd_make_section(abfd, name);
+ }
+ return sec;
+}
+
+/*
+FUNCTION
+ bfd_make_section_anyway
+
+SYNOPSIS
+ asection *bfd_make_section_anyway(bfd *, CONST char *name);
+
+DESCRIPTION
+ Create a new empty section called @var{name} and attach it to the end of
+ the chain of sections for @var{abfd}. Create a new section even if there
+ is already a section with that name.
+
+ Returns NULL and sets bfd_error on error; possible errors are:
+ o invalid_operation - If output has already started for @var{abfd}.
+ o no_memory - If obstack alloc fails.
+*/
+
+sec_ptr
+bfd_make_section_anyway (abfd, name)
+ bfd *abfd;
+ CONST char *name;
+{
+ asection *newsect;
+ asection **prev = &abfd->sections;
+ asection * sect = abfd->sections;
+
+ if (abfd->output_has_begun)
+ {
+ bfd_error = invalid_operation;
+ return NULL;
+ }
+
+ while (sect) {
+ prev = &sect->next;
+ sect = sect->next;
+ }
+
+ newsect = (asection *) bfd_zalloc(abfd, sizeof (asection));
+ if (newsect == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ newsect->name = name;
+ newsect->index = abfd->section_count++;
+ newsect->flags = SEC_NO_FLAGS;
+
+ newsect->userdata = 0;
+ newsect->next = (asection *)NULL;
+ newsect->relocation = (arelent *)NULL;
+ newsect->reloc_count = 0;
+ newsect->line_filepos =0;
+ newsect->owner = abfd;
+
+ /* Create a symbol whos only job is to point to this section. This is
+ useful for things like relocs which are relative to the base of a
+ section. */
+ newsect->symbol = bfd_make_empty_symbol(abfd);
+ newsect->symbol->name = name;
+ newsect->symbol->value = 0;
+ newsect->symbol->section = newsect;
+ newsect->symbol->flags = BSF_SECTION_SYM;
+
+ newsect->symbol_ptr_ptr = &newsect->symbol;
+
+ if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) {
+ free (newsect);
+ return NULL;
+ }
+
+ *prev = newsect;
+ return newsect;
+}
+
+/*
+FUNCTION
+ bfd_make_section
+
+SYNOPSIS
+ asection *bfd_make_section(bfd *, CONST char *name);
+
+DESCRIPTION
+ Like bfd_make_section_anyway, but return NULL (without setting
+ bfd_error) without changing the section chain if there is already a
+ section named @var{name}. If there is an error, return NULL and set
+ bfd_error.
+*/
+
+sec_ptr
+DEFUN(bfd_make_section,(abfd, name),
+ bfd *abfd AND
+ CONST char * name)
+{
+ asection * sect = abfd->sections;
+
+ if (strcmp(name, BFD_ABS_SECTION_NAME) == 0)
+ {
+ return &bfd_abs_section;
+ }
+ if (strcmp(name, BFD_COM_SECTION_NAME) == 0)
+ {
+ return &bfd_com_section;
+ }
+ if (strcmp(name, BFD_UND_SECTION_NAME) == 0)
+ {
+ return &bfd_und_section;
+ }
+
+ if (strcmp(name, BFD_IND_SECTION_NAME) == 0)
+ {
+ return &bfd_ind_section;
+ }
+
+ while (sect) {
+ if (!strcmp(sect->name, name)) return NULL;
+ sect = sect->next;
+ }
+
+ /* The name is not already used; go ahead and make a new section. */
+ return bfd_make_section_anyway (abfd, name);
+}
+
+
+/*
+FUNCTION
+ bfd_set_section_flags
+
+SYNOPSIS
+ boolean bfd_set_section_flags(bfd *, asection *, flagword);
+
+DESCRIPTION
+ Attempts to set the attributes of the section named in the BFD
+ supplied to the value. Returns true on success, false on
+ error. Possible error returns are:
+
+ o invalid operation -
+ The section cannot have one or more of the attributes
+ requested. For example, a .bss section in <<a.out>> may not
+ have the <<SEC_HAS_CONTENTS>> field set.
+
+*/
+
+boolean
+DEFUN(bfd_set_section_flags,(abfd, section, flags),
+ bfd *abfd AND
+ sec_ptr section AND
+ flagword flags)
+{
+#if 0
+ /* If you try to copy a text section from an input file (where it
+ has the SEC_CODE flag set) to an output file, this loses big if
+ the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE
+ set - which it doesn't, at least not for a.out. FIXME */
+
+ if ((flags & bfd_applicable_section_flags (abfd)) != flags) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+#endif
+
+ section->flags = flags;
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_map_over_sections
+
+SYNOPSIS
+ void bfd_map_over_sections(bfd *abfd,
+ void (*func)(bfd *abfd,
+ asection *sect,
+ PTR obj),
+ PTR obj);
+
+DESCRIPTION
+ Calls the provided function @var{func} for each section
+ attached to the BFD @var{abfd}, passing @var{obj} as an
+ argument. The function will be called as if by
+
+| func(abfd, the_section, obj);
+
+ This is the prefered method for iterating over sections, an
+ alternative would be to use a loop:
+
+| section *p;
+| for (p = abfd->sections; p != NULL; p = p->next)
+| func(abfd, p, ...)
+
+
+*/
+
+/*VARARGS2*/
+void
+DEFUN(bfd_map_over_sections,(abfd, operation, user_storage),
+ bfd *abfd AND
+ void (*operation) PARAMS ((bfd *abfd, asection *sect, PTR obj)) AND
+ PTR user_storage)
+{
+ asection *sect;
+ int i = 0;
+
+ for (sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ (*operation) (abfd, sect, user_storage);
+
+ if (i != abfd->section_count) /* Debugging */
+ abort();
+}
+
+
+/*
+FUNCTION
+ bfd_set_section_size
+
+SYNOPSIS
+ boolean bfd_set_section_size(bfd *, asection *, bfd_size_type val);
+
+DESCRIPTION
+ Sets @var{section} to the size @var{val}. If the operation is
+ ok, then <<true>> is returned, else <<false>>.
+
+ Possible error returns:
+ o invalid_operation -
+ Writing has started to the BFD, so setting the size is invalid
+
+*/
+
+boolean
+DEFUN(bfd_set_section_size,(abfd, ptr, val),
+ bfd *abfd AND
+ sec_ptr ptr AND
+ bfd_size_type val)
+{
+ /* Once you've started writing to any section you cannot create or change
+ the size of any others. */
+
+ if (abfd->output_has_begun) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ ptr->_cooked_size = val;
+ ptr->_raw_size = val;
+
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_set_section_contents
+
+SYNOPSIS
+ boolean bfd_set_section_contents
+ (bfd *abfd,
+ asection *section,
+ PTR data,
+ file_ptr offset,
+ bfd_size_type count);
+
+
+DESCRIPTION
+ Sets the contents of the section @var{section} in BFD
+ @var{abfd} to the data starting in memory at @var{data}. The
+ data is written to the output section starting at offset
+ @var{offset} for @var{count} bytes.
+
+
+
+ Normally <<true>> is returned, else <<false>>. Possible error
+ returns are:
+ o no_contents -
+ The output section does not have the <<SEC_HAS_CONTENTS>>
+ attribute, so nothing can be written to it.
+ o and some more too
+
+ This routine is front end to the back end function
+ <<_bfd_set_section_contents>>.
+
+
+*/
+
+#define bfd_get_section_size_now(abfd,sec) \
+(sec->reloc_done \
+ ? bfd_get_section_size_after_reloc (sec) \
+ : bfd_get_section_size_before_reloc (sec))
+
+boolean
+DEFUN(bfd_set_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ bfd_size_type sz;
+
+ if (!bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)
+ {
+ bfd_error = no_contents;
+ return(false);
+ }
+
+ if (offset < 0)
+ {
+ bad_val:
+ bfd_error = bad_value;
+ return false;
+ }
+ sz = bfd_get_section_size_now (abfd, section);
+ if (offset > sz
+ || count > sz
+ || offset + count > sz)
+ goto bad_val;
+
+ switch (abfd->direction)
+ {
+ case read_direction:
+ case no_direction:
+ bfd_error = invalid_operation;
+ return false;
+
+ case write_direction:
+ break;
+
+ case both_direction:
+ /* File is opened for update. `output_has_begun' some time ago when
+ the file was created. Do not recompute sections sizes or alignments
+ in _bfd_set_section_content. */
+ abfd->output_has_begun = true;
+ break;
+ }
+
+ if (BFD_SEND (abfd, _bfd_set_section_contents,
+ (abfd, section, location, offset, count)))
+ {
+ abfd->output_has_begun = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+FUNCTION
+ bfd_get_section_contents
+
+SYNOPSIS
+ boolean bfd_get_section_contents
+ (bfd *abfd, asection *section, PTR location,
+ file_ptr offset, bfd_size_type count);
+
+DESCRIPTION
+ This function reads data from @var{section} in BFD @var{abfd}
+ into memory starting at @var{location}. The data is read at an
+ offset of @var{offset} from the start of the input section,
+ and is read for @var{count} bytes.
+
+ If the contents of a constuctor with the <<SEC_CONSTUCTOR>>
+ flag set are requested, then the @var{location} is filled with
+ zeroes. If no errors occur, <<true>> is returned, else
+ <<false>>.
+
+
+
+*/
+boolean
+DEFUN(bfd_get_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ bfd_size_type sz;
+
+ if (section->flags & SEC_CONSTRUCTOR)
+ {
+ memset(location, 0, (unsigned)count);
+ return true;
+ }
+
+ if (offset < 0)
+ {
+ bad_val:
+ bfd_error = bad_value;
+ return false;
+ }
+ sz = bfd_get_section_size_now (abfd, section);
+ if (offset > sz
+ || count > sz
+ || offset + count > sz)
+ goto bad_val;
+
+ if (count == 0)
+ /* Don't bother. */
+ return true;
+
+ return BFD_SEND (abfd, _bfd_get_section_contents,
+ (abfd, section, location, offset, count));
+}
diff --git a/gnu/usr.bin/gdb/bfd/srec.c b/gnu/usr.bin/gdb/bfd/srec.c
new file mode 100644
index 000000000000..88ba9570e34e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/srec.c
@@ -0,0 +1,1001 @@
+/* BFD back-end for s-record objects.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SUBSECTION
+ S-Record handling
+
+DESCRIPTION
+
+ Ordinary S-Records cannot hold anything but addresses and
+ data, so that's all that we implement.
+
+ The only interesting thing is that S-Records may come out of
+ order and there is no header, so an initial scan is required
+ to discover the minimum and maximum addresses used to create
+ the vma and size of the only section we create. We
+ arbitrarily call this section ".text".
+
+ When bfd_get_section_contents is called the file is read
+ again, and this time the data is placed into a bfd_alloc'd
+ area.
+
+ Any number of sections may be created for output, we save them
+ up and output them when it's time to close the bfd.
+
+ An s record looks like:
+
+EXAMPLE
+ S<type><length><address><data><checksum>
+
+DESCRIPTION
+ Where
+ o length
+ is the number of bytes following upto the checksum. Note that
+ this is not the number of chars following, since it takes two
+ chars to represent a byte.
+ o type
+ is one of:
+ 0) header record
+ 1) two byte address data record
+ 2) three byte address data record
+ 3) four byte address data record
+ 7) four byte address termination record
+ 8) three byte address termination record
+ 9) two byte address termination record
+
+ o address
+ is the start address of the data following, or in the case of
+ a termination record, the start address of the image
+ o data
+ is the data.
+ o checksum
+ is the sum of all the raw byte data in the record, from the length
+ upwards, modulo 256 and subtracted from 255.
+
+
+SUBSECTION
+ Symbol S-Record handling
+
+DESCRIPTION
+ Some ICE equipment understands an addition to the standard
+ S-Record format; symbols and their addresses can be sent
+ before the data.
+
+ The format of this is:
+ ($$ <modulename>
+ (<space> <symbol> <address>)*)
+ $$
+
+ so a short symbol table could look like:
+
+EXAMPLE
+ $$ flash.x
+ $$ flash.c
+ _port6 $0
+ _delay $4
+ _start $14
+ _etext $8036
+ _edata $8036
+ _end $8036
+ $$
+
+DESCRIPTION
+ We allow symbols to be anywhere in the data stream - the module names
+ are always ignored.
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/* Macros for converting between hex and binary */
+
+static CONST char digs[] = "0123456789ABCDEF";
+
+static char hex_value[1 + (unsigned char)~0];
+
+#define NOT_HEX 20
+#define NIBBLE(x) hex_value[(unsigned char)(x)]
+#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
+#define TOHEX(d, x, ch) \
+ d[1] = digs[(x) & 0xf]; \
+ d[0] = digs[((x)>>4)&0xf]; \
+ ch += ((x) & 0xff);
+#define ISHEX(x) (hex_value[(unsigned char)(x)] != NOT_HEX)
+
+
+
+static void
+DEFUN_VOID(srec_init)
+{
+ unsigned int i;
+ static boolean inited = false;
+
+ if (inited == false)
+ {
+
+ inited = true;
+
+ for (i = 0; i < sizeof (hex_value); i++)
+ {
+ hex_value[i] = NOT_HEX;
+ }
+
+ for (i = 0; i < 10; i++)
+ {
+ hex_value[i + '0'] = i;
+
+ }
+ for (i = 0; i < 6; i++)
+ {
+ hex_value[i + 'a'] = i+10;
+ hex_value[i + 'A'] = i+10;
+ }
+ }
+}
+
+
+/* The maximum number of bytes on a line is FF */
+#define MAXCHUNK 0xff
+/* The number of bytes we fit onto a line on output */
+#define CHUNK 21
+
+/* We cannot output our srecords as we see them, we have to glue them
+ together, this is done in this structure : */
+
+struct srec_data_list_struct
+{
+ unsigned char *data;
+ bfd_vma where;
+ bfd_size_type size;
+ struct srec_data_list_struct *next;
+
+
+} ;
+typedef struct srec_data_list_struct srec_data_list_type;
+
+
+typedef struct srec_data_struct
+{
+ srec_data_list_type *head;
+ unsigned int type;
+
+ int done_symbol_read;
+ int count;
+ asymbol *symbols;
+ char *strings;
+ int symbol_idx;
+ int string_size;
+ int string_idx;
+} tdata_type;
+
+
+/*
+ called once per input S-Record, used to work out vma and size of data.
+ */
+
+static bfd_vma low,high;
+
+static void
+size_symbols(abfd, buf, len, val)
+bfd *abfd;
+char *buf;
+int len;
+int val;
+{
+ abfd->symcount ++;
+ abfd->tdata.srec_data->string_size += len + 1;
+}
+
+static void
+fillup_symbols(abfd, buf, len, val)
+bfd *abfd;
+char *buf;
+int len;
+int val;
+{
+ if (!abfd->tdata.srec_data->done_symbol_read)
+ {
+ asymbol *p;
+ if (abfd->tdata.srec_data->symbols == 0)
+ {
+ abfd->tdata.srec_data->symbols = (asymbol *)bfd_alloc(abfd, abfd->symcount * sizeof(asymbol));
+ abfd->tdata.srec_data->strings = (char*)bfd_alloc(abfd, abfd->tdata.srec_data->string_size);
+ abfd->tdata.srec_data->symbol_idx = 0;
+ abfd->tdata.srec_data->string_idx = 0;
+ }
+
+ p = abfd->tdata.srec_data->symbols + abfd->tdata.srec_data->symbol_idx++;
+ p->the_bfd = abfd;
+ p->name = abfd->tdata.srec_data->strings + abfd->tdata.srec_data->string_idx;
+ memcpy((char *)(p->name), buf, len+1);
+ abfd->tdata.srec_data->string_idx += len + 1;
+ p->value = val;
+ p->flags = BSF_EXPORT | BSF_GLOBAL;
+ p->section = &bfd_abs_section;
+ p->udata = 0;
+ }
+}
+static void
+DEFUN(size_srec,(abfd, section, address, raw, length),
+ bfd *abfd AND
+ asection *section AND
+ bfd_vma address AND
+ bfd_byte *raw AND
+ unsigned int length)
+{
+ if (address < low)
+ low = address;
+ if (address + length > high)
+ high = address + length -1;
+}
+
+
+/*
+ called once per input S-Record, copies data from input into bfd_alloc'd area
+ */
+
+static void
+DEFUN(fillup,(abfd, section, address, raw, length),
+bfd *abfd AND
+asection *section AND
+bfd_vma address AND
+bfd_byte *raw AND
+unsigned int length)
+{
+ unsigned int i;
+ bfd_byte *dst =
+ (bfd_byte *)(section->used_by_bfd) + address - section->vma;
+ /* length -1 because we don't read in the checksum */
+ for (i = 0; i < length -1 ; i++) {
+ *dst = HEX(raw);
+ dst++;
+ raw+=2;
+ }
+}
+
+/* Pass over an S-Record file, calling one of the above functions on each
+ record. */
+
+static int white(x)
+char x;
+{
+return (x== ' ' || x == '\t' || x == '\n' || x == '\r');
+}
+static int
+skipwhite(src,abfd)
+char *src;
+bfd *abfd;
+{
+ int eof = 0;
+ while (white(*src) && !eof)
+ {
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ }
+ return eof;
+}
+
+static boolean
+DEFUN(srec_mkobject, (abfd),
+ bfd *abfd)
+{
+ if (abfd->tdata.srec_data == 0)
+ {
+ tdata_type *tdata = (tdata_type *)bfd_alloc(abfd, sizeof(tdata_type));
+ abfd->tdata.srec_data = tdata;
+ tdata->type = 1;
+ tdata->head = (srec_data_list_type *)NULL;
+ }
+ return true;
+
+}
+
+static void
+DEFUN(pass_over,(abfd, func, symbolfunc, section),
+ bfd *abfd AND
+ void (*func)() AND
+ void (*symbolfunc)() AND
+ asection *section)
+{
+ unsigned int bytes_on_line;
+ boolean eof = false;
+
+ srec_mkobject(abfd);
+ /* To the front of the file */
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ while (eof == false)
+ {
+ char buffer[MAXCHUNK];
+ char *src = buffer;
+ char type;
+ bfd_vma address = 0;
+
+ /* Find first 'S' or $ */
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ switch (*src)
+ {
+ default:
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ if (eof) return;
+ break;
+
+ case '$':
+ /* Inside a symbol definition - just ignore the module name */
+ while (*src != '\n' && !eof)
+ {
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ }
+ break;
+
+ case ' ':
+ /* spaces - maybe just before a symbol */
+ while (*src != '\n' && white(*src)) {
+ eof = skipwhite(src, abfd);
+
+{
+ int val = 0;
+ int slen = 0;
+ char symbol[MAXCHUNK];
+
+ /* get the symbol part */
+ while (!eof && !white(*src) && slen < MAXCHUNK)
+ {
+ symbol[slen++] = *src;
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ }
+ symbol[slen] = 0;
+ eof = skipwhite(src, abfd);
+ /* skip the $ for the hex value */
+ if (*src == '$')
+ {
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ }
+
+ /* Scan off the hex number */
+ while (isxdigit(*src ))
+ {
+ val *= 16;
+ if (isdigit(*src))
+ val += *src - '0';
+ else if (isupper(*src)) {
+ val += *src - 'A' + 10;
+ }
+ else {
+ val += *src - 'a' + 10;
+ }
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ }
+ symbolfunc(abfd, symbol, slen, val);
+ }
+}
+ break;
+ case 'S':
+ src++;
+
+ /* Fetch the type and the length */
+ bfd_read(src, 1, 3, abfd);
+
+ type = *src++;
+
+ if (!ISHEX (src[0]) || !ISHEX (src[1]))
+ break;
+
+ bytes_on_line = HEX(src);
+
+ if (bytes_on_line > MAXCHUNK/2)
+ break;
+ src+=2 ;
+
+ bfd_read(src, 1 , bytes_on_line * 2, abfd);
+
+ switch (type) {
+ case '0':
+ case '5':
+ /* Prologue - ignore */
+ break;
+ case '3':
+ address = HEX(src);
+ src+=2;
+ bytes_on_line--;
+
+ case '2':
+ address = HEX(src) | (address<<8) ;
+ src+=2;
+ bytes_on_line--;
+ case '1':
+ address = HEX(src) | (address<<8) ;
+ src+=2;
+ address = HEX(src) | (address<<8) ;
+ src+=2;
+ bytes_on_line-=2;
+ func(abfd,section, address, src, bytes_on_line);
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+}
+
+static bfd_target *
+object_p(abfd)
+bfd *abfd;
+{
+ asection *section;
+ /* We create one section called .text for all the contents,
+ and allocate enough room for the entire file. */
+
+ section = bfd_make_section(abfd, ".text");
+ section->_raw_size = 0;
+ section->vma = 0xffffffff;
+ low = 0xffffffff;
+ high = 0;
+ pass_over(abfd, size_srec, size_symbols, section);
+ section->_raw_size = high - low;
+ section->vma = low;
+ section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
+
+ if (abfd->symcount)
+ abfd->flags |= HAS_SYMS;
+ return abfd->xvec;
+}
+
+static bfd_target *
+DEFUN(srec_object_p, (abfd),
+ bfd *abfd)
+{
+ char b[4];
+
+ srec_init();
+
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ bfd_read(b, 1, 4, abfd);
+
+ if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3]))
+ return (bfd_target*) NULL;
+
+ /* We create one section called .text for all the contents,
+ and allocate enough room for the entire file. */
+
+ return object_p(abfd);
+}
+
+
+static bfd_target *
+DEFUN(symbolsrec_object_p, (abfd),
+ bfd *abfd)
+{
+ char b[4];
+
+ srec_init();
+
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ bfd_read(b, 1, 4, abfd);
+
+ if (b[0] != '$' || b[1] != '$')
+ return (bfd_target*) NULL;
+
+ return object_p(abfd);
+}
+
+
+static boolean
+DEFUN(srec_get_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ asection *section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ if (section->used_by_bfd == (PTR)NULL)
+ {
+ section->used_by_bfd = (PTR)bfd_alloc (abfd, section->_raw_size);
+
+ pass_over(abfd, fillup, fillup_symbols, section);
+ }
+ (void) memcpy((PTR)location,
+ (PTR)((char *)(section->used_by_bfd) + offset),
+ count);
+ return true;
+}
+
+
+
+boolean
+DEFUN(srec_set_arch_mach,(abfd, arch, machine),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ return bfd_default_set_arch_mach(abfd, arch, machine);
+}
+
+
+/* we have to save up all the Srecords for a splurge before output,
+ also remember */
+
+static boolean
+DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type bytes_to_do)
+{
+ tdata_type *tdata = abfd->tdata.srec_data;
+ srec_data_list_type *entry = (srec_data_list_type *)
+ bfd_alloc(abfd, sizeof(srec_data_list_type));
+
+ if ((section->flags & SEC_ALLOC)
+ && (section->flags & SEC_LOAD))
+ {
+ unsigned char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do);
+ memcpy(data, location, bytes_to_do);
+
+ if ((section->lma + offset + bytes_to_do) <= 0xffff)
+ {
+
+ }
+ else if ((section->lma + offset + bytes_to_do) <= 0xffffff
+ && tdata->type < 2)
+ {
+ tdata->type = 2;
+ }
+ else
+ {
+ tdata->type = 3;
+ }
+
+ entry->data = data;
+ entry->where = section->lma + offset;
+ entry->size = bytes_to_do;
+ entry->next = tdata->head;
+ tdata->head = entry;
+ }
+ return true;
+}
+
+/* Write a record of type, of the supplied number of bytes. The
+ supplied bytes and length don't have a checksum. That's worked out
+ here
+*/
+static
+void DEFUN(srec_write_record,(abfd, type, address, data, end),
+ bfd *abfd AND
+ char type AND
+ bfd_vma address AND
+ CONST unsigned char *data AND
+ CONST unsigned char *end)
+
+{
+ char buffer[MAXCHUNK];
+
+ unsigned int check_sum = 0;
+ unsigned CONST char *src = data;
+ char *dst =buffer;
+ char *length;
+
+
+ *dst++ = 'S';
+ *dst++ = '0' + type;
+
+ length = dst;
+ dst+=2; /* leave room for dst*/
+
+ switch (type)
+ {
+ case 3:
+ case 7:
+ TOHEX(dst, (address >> 24), check_sum);
+ dst+=2;
+ case 8:
+ case 2:
+ TOHEX(dst, (address >> 16), check_sum);
+ dst+=2;
+ case 9:
+ case 1:
+ case 0:
+ TOHEX(dst, (address >> 8), check_sum);
+ dst+=2;
+ TOHEX(dst, (address), check_sum);
+ dst+=2;
+ break;
+
+ }
+ for (src = data; src < end; src++)
+ {
+ TOHEX(dst, *src, check_sum);
+ dst+=2;
+ }
+
+ /* Fill in the length */
+ TOHEX(length, (dst - length)/2, check_sum);
+ check_sum &= 0xff;
+ check_sum = 255 - check_sum;
+ TOHEX(dst, check_sum, check_sum);
+ dst+=2;
+
+ *dst ++ = '\r';
+ *dst ++ = '\n';
+ bfd_write((PTR)buffer, 1, dst - buffer , abfd);
+}
+
+
+
+static void
+DEFUN(srec_write_header,(abfd),
+ bfd *abfd)
+{
+ unsigned char buffer[MAXCHUNK];
+ unsigned char *dst = buffer;
+ unsigned int i;
+
+ /* I'll put an arbitary 40 char limit on header size */
+ for (i = 0; i < 40 && abfd->filename[i]; i++)
+ {
+ *dst++ = abfd->filename[i];
+ }
+ srec_write_record(abfd,0, 0, buffer, dst);
+}
+
+static void
+DEFUN(srec_write_section,(abfd, tdata, list),
+ bfd *abfd AND
+ tdata_type *tdata AND
+ srec_data_list_type *list)
+{
+ unsigned int bytes_written = 0;
+ unsigned char *location = list->data;
+
+ while (bytes_written < list->size)
+ {
+ bfd_vma address;
+
+ unsigned int bytes_this_chunk = list->size - bytes_written;
+
+ if (bytes_this_chunk > CHUNK)
+ {
+ bytes_this_chunk = CHUNK;
+ }
+
+ address = list->where + bytes_written;
+
+ srec_write_record(abfd,
+ tdata->type,
+ address,
+ location,
+ location + bytes_this_chunk);
+
+ bytes_written += bytes_this_chunk;
+ location += bytes_this_chunk;
+ }
+
+}
+
+static void
+DEFUN(srec_write_terminator,(abfd, tdata),
+ bfd *abfd AND
+ tdata_type *tdata)
+{
+ unsigned char buffer[2];
+
+ srec_write_record(abfd, 10 - tdata->type,
+ abfd->start_address, buffer, buffer);
+}
+
+
+
+static void
+srec_write_symbols(abfd)
+ bfd *abfd;
+{
+ char buffer[MAXCHUNK];
+ /* Dump out the symbols of a bfd */
+ int i;
+ int len = bfd_get_symcount(abfd);
+
+ if (len)
+ {
+ asymbol **table = bfd_get_outsymbols(abfd);
+ sprintf(buffer, "$$ %s\r\n", abfd->filename);
+
+ bfd_write(buffer, strlen(buffer), 1, abfd);
+
+ for (i = 0; i < len; i++)
+ {
+ asymbol *s = table[i];
+#if 0
+ int len = strlen(s->name);
+
+ /* If this symbol has a .[ocs] in it, it's probably a file name
+ and we'll output that as the module name */
+
+ if (len > 3 && s->name[len-2] == '.')
+ {
+ int l;
+ sprintf(buffer, "$$ %s\r\n", s->name);
+ l = strlen(buffer);
+ bfd_write(buffer, l, 1, abfd);
+ }
+ else
+#endif
+ if (s->flags & (BSF_GLOBAL | BSF_LOCAL)
+ && (s->flags & BSF_DEBUGGING) == 0
+ && s->name[0] != '.'
+ && s->name[0] != 't')
+ {
+ /* Just dump out non debug symbols */
+
+ int l;
+ char buf2[40], *p;
+
+ sprintf_vma (buf2, s->value + s->section->lma);
+ p = buf2;
+ while (p[0] == '0' && p[1] != 0)
+ p++;
+ sprintf (buffer, " %s $%s\r\n", s->name, p);
+ l = strlen(buffer);
+ bfd_write(buffer, l, 1,abfd);
+ }
+ }
+ sprintf(buffer, "$$ \r\n");
+ bfd_write(buffer, strlen(buffer), 1, abfd);
+ }
+}
+
+static boolean
+internal_srec_write_object_contents(abfd, symbols)
+ bfd *abfd;
+ int symbols;
+{
+ int bytes_written;
+ tdata_type *tdata = abfd->tdata.srec_data;
+ srec_data_list_type *list;
+
+ bytes_written = 0;
+
+
+ if (symbols)
+ srec_write_symbols(abfd);
+
+ srec_write_header(abfd);
+
+ /* Now wander though all the sections provided and output them */
+ list = tdata->head;
+
+ while (list != (srec_data_list_type*)NULL)
+ {
+ srec_write_section(abfd, tdata, list);
+ list = list->next;
+ }
+ srec_write_terminator(abfd, tdata);
+ return true;
+}
+
+static boolean
+srec_write_object_contents(abfd)
+ bfd *abfd;
+{
+ return internal_srec_write_object_contents(abfd, 0);
+}
+
+static boolean
+symbolsrec_write_object_contents(abfd)
+ bfd *abfd;
+{
+ return internal_srec_write_object_contents(abfd, 1);
+}
+
+static int
+DEFUN(srec_sizeof_headers,(abfd, exec),
+ bfd *abfd AND
+ boolean exec)
+{
+return 0;
+}
+
+static asymbol *
+DEFUN(srec_make_empty_symbol, (abfd),
+ bfd*abfd)
+{
+ asymbol *new= (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
+ new->the_bfd = abfd;
+ return new;
+}
+
+static unsigned int
+srec_get_symtab_upper_bound(abfd)
+bfd *abfd;
+{
+ /* Read in all the info */
+ srec_get_section_contents(abfd,abfd->sections,0,0,0);
+ return (bfd_get_symcount(abfd) + 1) * (sizeof(asymbol *));
+}
+
+static unsigned int
+DEFUN(srec_get_symtab, (abfd, alocation),
+ bfd *abfd AND
+ asymbol **alocation)
+{
+ int lim = abfd->symcount;
+ int i;
+ for (i = 0; i < lim; i++) {
+ alocation[i] = abfd->tdata.srec_data->symbols + i;
+ }
+ alocation[i] = 0;
+ return lim;
+}
+
+void
+DEFUN(srec_get_symbol_info,(ignore_abfd, symbol, ret),
+ bfd *ignore_abfd AND
+ asymbol *symbol AND
+ symbol_info *ret)
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+void
+DEFUN(srec_print_symbol,(ignore_abfd, afile, symbol, how),
+ bfd *ignore_abfd AND
+ PTR afile AND
+ asymbol *symbol AND
+ bfd_print_symbol_type how)
+{
+ FILE *file = (FILE *)afile;
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ default:
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ fprintf (file, " %-5s %s",
+ symbol->section->name,
+ symbol->name);
+
+ }
+}
+
+#define FOO PROTO
+#define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
+
+#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
+#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
+
+
+
+#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
+#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
+#define srec_generic_stat_arch_elt (FOO(int, (*), (bfd *,struct stat *))) bfd_0
+
+
+#define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
+#define srec_core_file_failing_signal (int (*)())bfd_0
+#define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
+#define srec_slurp_armap bfd_true
+#define srec_slurp_extended_name_table bfd_true
+#define srec_truncate_arname (void (*)())bfd_nullvoidptr
+#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
+#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
+#define srec_close_and_cleanup bfd_generic_close_and_cleanup
+#define srec_bfd_debug_info_start bfd_void
+#define srec_bfd_debug_info_end bfd_void
+#define srec_bfd_debug_info_accumulate (FOO(void, (*), (bfd *, asection *))) bfd_void
+#define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
+#define srec_bfd_relax_section bfd_generic_relax_section
+#define srec_bfd_seclet_link bfd_generic_seclet_link
+#define srec_bfd_reloc_type_lookup \
+ ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr)
+#define srec_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+bfd_target srec_vec =
+{
+ "srec", /* name */
+ bfd_target_srec_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
+ (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
+ |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 1, /* minimum alignment */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+ {
+ _bfd_dummy_target,
+ srec_object_p, /* bfd_check_format */
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ srec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+ JUMP_TABLE(srec)
+ };
+
+
+
+bfd_target symbolsrec_vec =
+{
+ "symbolsrec", /* name */
+ bfd_target_srec_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
+ (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
+ |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 1, /* minimum alignment */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+ {
+ _bfd_dummy_target,
+ symbolsrec_object_p, /* bfd_check_format */
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ symbolsrec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+ JUMP_TABLE(srec),
+ (PTR) 0
+ };
+
diff --git a/gnu/usr.bin/gdb/bfd/stab-syms.c b/gnu/usr.bin/gdb/bfd/stab-syms.c
new file mode 100644
index 000000000000..88cf8506e47d
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/stab-syms.c
@@ -0,0 +1,59 @@
+/* Table of stab names for the BFD library.
+ Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+
+#define ARCH_SIZE 32 /* Value doesn't matter. */
+#include "libaout.h"
+#include "aout/aout64.h"
+
+/* Create a table of debugging stab-codes and corresponding names. */
+
+#define __define_name(CODE, STRING) {(int)CODE, STRING},
+#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING)
+CONST struct {short code; char string[10];} aout_stab_names[]
+ = {
+#include "aout/stab.def"
+
+/* These are not really stab symbols, but it is
+ convenient to have them here for the sake of nm.
+ For completeness, we could also add N_TEXT etc, but those
+ are never needed, since nm treats those specially. */
+__define_name (N_SETA, "SETA") /* Absolute set element symbol */
+__define_name (N_SETT, "SETT") /* Text set element symbol */
+__define_name (N_SETD, "SETD") /* Data set element symbol */
+__define_name (N_SETB, "SETB") /* Bss set element symbol */
+__define_name (N_SETV, "SETV") /* Pointer to set vector in data area. */
+__define_name (N_INDR, "INDR")
+__define_name (N_WARNING, "WARNING")
+ };
+#undef __define_stab
+#undef GNU_EXTRA_STABS
+
+CONST char *
+DEFUN(aout_stab_name,(code),
+int code)
+{
+ register int i = sizeof(aout_stab_names) / sizeof(aout_stab_names[0]);
+ while (--i >= 0)
+ if (aout_stab_names[i].code == code)
+ return aout_stab_names[i].string;
+ return 0;
+}
diff --git a/gnu/usr.bin/gdb/bfd/syms.c b/gnu/usr.bin/gdb/bfd/syms.c
new file mode 100644
index 000000000000..89ac00124e3c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/syms.c
@@ -0,0 +1,527 @@
+/* Generic symbol-table support for the BFD library.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Symbols
+
+ BFD trys to maintain as much symbol information as it can when
+ it moves information from file to file. BFD passes information
+ to applications though the <<asymbol>> structure. When the
+ application requests the symbol table, BFD reads the table in
+ the native form and translates parts of it into the internal
+ format. To maintain more than the infomation passed to
+ applications some targets keep some information `behind the
+ scenes', in a structure only the particular back end knows
+ about. For example, the coff back end keeps the original
+ symbol table structure as well as the canonical structure when
+ a BFD is read in. On output, the coff back end can reconstruct
+ the output symbol table so that no information is lost, even
+ information unique to coff which BFD doesn't know or
+ understand. If a coff symbol table was read, but was written
+ through an a.out back end, all the coff specific information
+ would be lost. The symbol table of a BFD
+ is not necessarily read in until a canonicalize request is
+ made. Then the BFD back end fills in a table provided by the
+ application with pointers to the canonical information. To
+ output symbols, the application provides BFD with a table of
+ pointers to pointers to <<asymbol>>s. This allows applications
+ like the linker to output a symbol as read, since the `behind
+ the scenes' information will be still available.
+@menu
+@* Reading Symbols::
+@* Writing Symbols::
+@* typedef asymbol::
+@* symbol handling functions::
+@end menu
+
+INODE
+Reading Symbols, Writing Symbols, Symbols, Symbols
+SUBSECTION
+ Reading Symbols
+
+ There are two stages to reading a symbol table from a BFD;
+ allocating storage, and the actual reading process. This is an
+ excerpt from an appliction which reads the symbol table:
+
+| unsigned int storage_needed;
+| asymbol **symbol_table;
+| unsigned int number_of_symbols;
+| unsigned int i;
+|
+| storage_needed = get_symtab_upper_bound (abfd);
+|
+| if (storage_needed == 0) {
+| return ;
+| }
+| symbol_table = (asymbol **) bfd_xmalloc (storage_needed);
+| ...
+| number_of_symbols =
+| bfd_canonicalize_symtab (abfd, symbol_table);
+|
+| for (i = 0; i < number_of_symbols; i++) {
+| process_symbol (symbol_table[i]);
+| }
+
+ All storage for the symbols themselves is in an obstack
+ connected to the BFD, and is freed when the BFD is closed.
+
+
+INODE
+Writing Symbols, typedef asymbol, Reading Symbols, Symbols
+SUBSECTION
+ Writing Symbols
+
+ Writing of a symbol table is automatic when a BFD open for
+ writing is closed. The application attaches a vector of
+ pointers to pointers to symbols to the BFD being written, and
+ fills in the symbol count. The close and cleanup code reads
+ through the table provided and performs all the necessary
+ operations. The outputing code must always be provided with an
+ 'owned' symbol; one which has come from another BFD, or one
+ which has been created using <<bfd_make_empty_symbol>>. An
+ example showing the creation of a symbol table with only one element:
+
+| #include "bfd.h"
+| main()
+| {
+| bfd *abfd;
+| asymbol *ptrs[2];
+| asymbol *new;
+|
+| abfd = bfd_openw("foo","a.out-sunos-big");
+| bfd_set_format(abfd, bfd_object);
+| new = bfd_make_empty_symbol(abfd);
+| new->name = "dummy_symbol";
+| new->section = bfd_make_section_old_way(abfd, ".text");
+| new->flags = BSF_GLOBAL;
+| new->value = 0x12345;
+|
+| ptrs[0] = new;
+| ptrs[1] = (asymbol *)0;
+|
+| bfd_set_symtab(abfd, ptrs, 1);
+| bfd_close(abfd);
+| }
+|
+| ./makesym
+| nm foo
+| 00012345 A dummy_symbol
+
+ Many formats cannot represent arbitary symbol information; for
+ instance the <<a.out>> object format does not allow an
+ arbitary number of sections. A symbol pointing to a section
+ which is not one of <<.text>>, <<.data>> or <<.bss>> cannot
+ be described.
+
+*/
+
+
+
+/*
+DOCDD
+INODE
+typedef asymbol, symbol handling functions, Writing Symbols, Symbols
+
+*/
+/*
+SUBSECTION
+ typedef asymbol
+
+ An <<asymbol>> has the form:
+
+*/
+
+/*
+CODE_FRAGMENT
+
+.
+.typedef struct symbol_cache_entry
+.{
+. {* A pointer to the BFD which owns the symbol. This information
+. is necessary so that a back end can work out what additional
+. information (invisible to the application writer) is carried
+. with the symbol.
+.
+. This field is *almost* redundant, since you can use section->owner
+. instead, except that some symbols point to the global sections
+. bfd_{abs,com,und}_section. This could be fixed by making
+. these globals be per-bfd (or per-target-flavor). FIXME. *}
+.
+. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *}
+.
+. {* The text of the symbol. The name is left alone, and not copied - the
+. application may not alter it. *}
+. CONST char *name;
+.
+. {* The value of the symbol. This really should be a union of a
+. numeric value with a pointer, since some flags indicate that
+. a pointer to another symbol is stored here. *}
+. symvalue value;
+.
+. {* Attributes of a symbol: *}
+.
+.#define BSF_NO_FLAGS 0x00
+.
+. {* The symbol has local scope; <<static>> in <<C>>. The value
+. is the offset into the section of the data. *}
+.#define BSF_LOCAL 0x01
+.
+. {* The symbol has global scope; initialized data in <<C>>. The
+. value is the offset into the section of the data. *}
+.#define BSF_GLOBAL 0x02
+.
+. {* The symbol has global scope, and is exported. The value is
+. the offset into the section of the data. *}
+.#define BSF_EXPORT BSF_GLOBAL {* no real difference *}
+.
+. {* A normal C symbol would be one of:
+. <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or
+. <<BSF_GLOBAL>> *}
+.
+. {* The symbol is a debugging record. The value has an arbitary
+. meaning. *}
+.#define BSF_DEBUGGING 0x08
+.
+. {* The symbol denotes a function entry point. Used in ELF,
+. perhaps others someday. *}
+.#define BSF_FUNCTION 0x10
+.
+. {* Used by the linker. *}
+.#define BSF_KEEP 0x20
+.#define BSF_KEEP_G 0x40
+.
+. {* A weak global symbol, overridable without warnings by
+. a regular global symbol of the same name. *}
+.#define BSF_WEAK 0x80
+.
+. {* This symbol was created to point to a section, e.g. ELF's
+. STT_SECTION symbols. *}
+.#define BSF_SECTION_SYM 0x100
+.
+. {* The symbol used to be a common symbol, but now it is
+. allocated. *}
+.#define BSF_OLD_COMMON 0x200
+.
+. {* The default value for common data. *}
+.#define BFD_FORT_COMM_DEFAULT_VALUE 0
+.
+. {* In some files the type of a symbol sometimes alters its
+. location in an output file - ie in coff a <<ISFCN>> symbol
+. which is also <<C_EXT>> symbol appears where it was
+. declared and not at the end of a section. This bit is set
+. by the target BFD part to convey this information. *}
+.
+.#define BSF_NOT_AT_END 0x400
+.
+. {* Signal that the symbol is the label of constructor section. *}
+.#define BSF_CONSTRUCTOR 0x800
+.
+. {* Signal that the symbol is a warning symbol. If the symbol
+. is a warning symbol, then the value field (I know this is
+. tacky) will point to the asymbol which when referenced will
+. cause the warning. *}
+.#define BSF_WARNING 0x1000
+.
+. {* Signal that the symbol is indirect. The value of the symbol
+. is a pointer to an undefined asymbol which contains the
+. name to use instead. *}
+.#define BSF_INDIRECT 0x2000
+.
+. {* BSF_FILE marks symbols that contain a file name. This is used
+. for ELF STT_FILE symbols. *}
+.#define BSF_FILE 0x4000
+.
+. flagword flags;
+.
+. {* A pointer to the section to which this symbol is
+. relative. This will always be non NULL, there are special
+. sections for undefined and absolute symbols *}
+. struct sec *section;
+.
+. {* Back end special data. This is being phased out in favour
+. of making this a union. *}
+. PTR udata;
+.
+.} asymbol;
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+
+#include "libbfd.h"
+#include "aout/stab_gnu.h"
+
+/*
+DOCDD
+INODE
+symbol handling functions, , typedef asymbol, Symbols
+SUBSECTION
+ Symbol Handling Functions
+*/
+
+/*
+FUNCTION
+ get_symtab_upper_bound
+
+DESCRIPTION
+ Returns the number of bytes required in a vector of pointers
+ to <<asymbols>> for all the symbols in the supplied BFD,
+ including a terminal NULL pointer. If there are no symbols in
+ the BFD, then 0 is returned.
+
+.#define get_symtab_upper_bound(abfd) \
+. BFD_SEND (abfd, _get_symtab_upper_bound, (abfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_canonicalize_symtab
+
+DESCRIPTION
+ Supplied a BFD and a pointer to an uninitialized vector of
+ pointers. This reads in the symbols from the BFD, and fills in
+ the table with pointers to the symbols, and a trailing NULL.
+ The routine returns the actual number of symbol pointers not
+ including the NULL.
+
+
+.#define bfd_canonicalize_symtab(abfd, location) \
+. BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+. (abfd, location))
+
+*/
+
+
+/*
+FUNCTION
+ bfd_set_symtab
+
+DESCRIPTION
+ Provided a table of pointers to symbols and a count, writes to
+ the output BFD the symbols when closed.
+
+SYNOPSIS
+ boolean bfd_set_symtab (bfd *, asymbol **, unsigned int );
+*/
+
+boolean
+bfd_set_symtab (abfd, location, symcount)
+ bfd *abfd;
+ asymbol **location;
+ unsigned int symcount;
+{
+ if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ bfd_get_outsymbols (abfd) = location;
+ bfd_get_symcount (abfd) = symcount;
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_print_symbol_vandf
+
+DESCRIPTION
+ Prints the value and flags of the symbol supplied to the stream file.
+
+SYNOPSIS
+ void bfd_print_symbol_vandf(PTR file, asymbol *symbol);
+*/
+void
+DEFUN(bfd_print_symbol_vandf,(file, symbol),
+PTR file AND
+asymbol *symbol)
+{
+ flagword type = symbol->flags;
+ if (symbol->section != (asection *)NULL)
+ {
+ fprintf_vma(file, symbol->value+symbol->section->vma);
+ }
+ else
+ {
+ fprintf_vma(file, symbol->value);
+ }
+ fprintf(file," %c%c%c%c%c%c%c",
+ (type & BSF_LOCAL) ? 'l':' ',
+ (type & BSF_GLOBAL) ? 'g' : ' ',
+ (type & BSF_WEAK) ? 'w' : ' ',
+ (type & BSF_CONSTRUCTOR) ? 'C' : ' ',
+ (type & BSF_WARNING) ? 'W' : ' ',
+ (type & BSF_INDIRECT) ? 'I' : ' ',
+ (type & BSF_DEBUGGING) ? 'd' :' ');
+
+}
+
+
+/*
+FUNCTION
+ bfd_make_empty_symbol
+
+DESCRIPTION
+ This function creates a new <<asymbol>> structure for the BFD,
+ and returns a pointer to it.
+
+ This routine is necessary, since each back end has private
+ information surrounding the <<asymbol>>. Building your own
+ <<asymbol>> and pointing to it will not create the private
+ information, and will cause problems later on.
+
+.#define bfd_make_empty_symbol(abfd) \
+. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd))
+*/
+
+/*
+FUNCTION
+ bfd_make_debug_symbol
+
+DESCRIPTION
+ This function creates a new <<asymbol>> structure for the BFD,
+ to be used as a debugging symbol. Further details of its use have
+ yet to be worked out.
+
+.#define bfd_make_debug_symbol(abfd,ptr,size) \
+. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size))
+*/
+
+struct section_to_type
+{
+ CONST char *section;
+ char type;
+};
+
+/* Map COFF section names to POSIX/BSD single-character symbol types.
+ This table is probably incomplete. It is sorted for convenience of
+ adding entries. Since it is so short, a linear search is used. */
+static CONST struct section_to_type stt[] = {
+ {"*DEBUG*", 'N'},
+ {".bss", 'b'},
+ {".data", 'd'},
+ {".sbss", 's'}, /* Small BSS (uninitialized data) */
+ {".scommon", 'c'}, /* Small common */
+ {".sdata", 'g'}, /* Small initialized data */
+ {".text", 't'},
+ {0, 0}
+};
+
+/* Return the single-character symbol type corresponding to
+ COFF section S, or '?' for an unknown COFF section. */
+
+static char
+coff_section_type (s)
+ char *s;
+{
+ CONST struct section_to_type *t;
+
+ for (t = &stt[0]; t->section; t++)
+ if (!strcmp (s, t->section))
+ return t->type;
+ return '?';
+}
+
+#ifndef islower
+#define islower(c) ((c) >= 'a' && (c) <= 'z')
+#endif
+#ifndef toupper
+#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c))
+#endif
+
+/*
+FUNCTION
+ bfd_decode_symclass
+
+DESCRIPTION
+ Return a character corresponding to the symbol
+ class of symbol, or '?' for an unknown class.
+
+SYNOPSIS
+ int bfd_decode_symclass(asymbol *symbol);
+*/
+int
+DEFUN(bfd_decode_symclass,(symbol),
+asymbol *symbol)
+{
+ char c;
+
+ if (bfd_is_com_section (symbol->section))
+ return 'C';
+ if (symbol->section == &bfd_und_section)
+ return 'U';
+ if (symbol->section == &bfd_ind_section)
+ return 'I';
+ if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL)))
+ return '?';
+
+ if (symbol->section == &bfd_abs_section)
+ c = 'a';
+ else if (symbol->section)
+ c = coff_section_type (symbol->section->name);
+ else
+ return '?';
+ if (symbol->flags & BSF_GLOBAL)
+ c = toupper (c);
+ return c;
+
+ /* We don't have to handle these cases just yet, but we will soon:
+ N_SETV: 'v';
+ N_SETA: 'l';
+ N_SETT: 'x';
+ N_SETD: 'z';
+ N_SETB: 's';
+ N_INDR: 'i';
+ */
+}
+
+/*
+FUNCTION
+ bfd_symbol_info
+
+DESCRIPTION
+ Fill in the basic info about symbol that nm needs.
+ Additional info may be added by the back-ends after
+ calling this function.
+
+SYNOPSIS
+ void bfd_symbol_info(asymbol *symbol, symbol_info *ret);
+*/
+
+void
+DEFUN(bfd_symbol_info,(symbol, ret),
+ asymbol *symbol AND
+ symbol_info *ret)
+{
+ ret->type = bfd_decode_symclass (symbol);
+ if (ret->type != 'U')
+ ret->value = symbol->value+symbol->section->vma;
+ else
+ ret->value = 0;
+ ret->name = symbol->name;
+}
+
+void
+bfd_symbol_is_absolute()
+{
+ abort();
+}
+
diff --git a/gnu/usr.bin/gdb/bfd/sysdep.h b/gnu/usr.bin/gdb/bfd/sysdep.h
new file mode 100644
index 000000000000..dd7328b1d0f0
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/sysdep.h
@@ -0,0 +1,47 @@
+#ifndef hosts_i386bsd_H
+/* Intel 386 running any BSD Unix */
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include <machine/param.h>
+#include <machine/vmparam.h>
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+
+#define HOST_PAGE_SIZE NBPG
+#define HOST_MACHINE_ARCH bfd_arch_i386
+#define HOST_TEXT_START_ADDR USRTEXT
+
+/* Jolitz suggested defining HOST_STACK_END_ADDR to
+ (u.u_kproc.kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ), which should work on
+ both BSDI and 386BSD, but that is believed not to work for BSD 4.4. */
+
+#ifdef __bsdi__
+/* This seems to be the right thing for BSDI. */
+#define HOST_STACK_END_ADDR USRSTACK
+#else
+/* This seems to be the right thing for 386BSD release 0.1. */
+#define HOST_STACK_END_ADDR (USRSTACK - MAXSSIZ)
+#endif
+
+#define HOST_DATA_START_ADDR ((bfd_vma)u.u_kproc.kp_eproc.e_vm.vm_daddr)
+
+#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \
+ ((core_bfd)->tdata.trad_core_data->u.u_sig)
+#define u_comm u_kproc.kp_proc.p_comm
+
+#include "fopen-same.h"
+
+#define hosts_i386bsd_H
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/targets.c b/gnu/usr.bin/gdb/bfd/targets.c
new file mode 100644
index 000000000000..d6a966588c45
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/targets.c
@@ -0,0 +1,635 @@
+/* Generic target-file-type support for the BFD library.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+SECTION
+ Targets
+
+DESCRIPTION
+ Each port of BFD to a different machine requries the creation
+ of a target back end. All the back end provides to the root
+ part of BFD is a structure containing pointers to functions
+ which perform certain low level operations on files. BFD
+ translates the applications's requests through a pointer into
+ calls to the back end routines.
+
+ When a file is opened with <<bfd_openr>>, its format and
+ target are unknown. BFD uses various mechanisms to determine
+ how to interpret the file. The operations performed are:
+
+ o First a BFD is created by calling the internal routine
+ <<new_bfd>>, then <<bfd_find_target>> is called with the
+ target string supplied to <<bfd_openr>> and the new BFD pointer.
+
+ o If a null target string was provided to <<bfd_find_target>>,
+ it looks up the environment variable <<GNUTARGET>> and uses
+ that as the target string.
+
+ o If the target string is still NULL, or the target string is
+ <<default>>, then the first item in the target vector is used
+ as the target type, and <<target_defaulted>> is set to
+ cause <<bfd_check_format>> to loop through all the targets.
+ @xref{bfd_target}. @xref{Formats}.
+
+ o Otherwise, the elements in the target vector are inspected
+ one by one, until a match on target name is found. When found,
+ that is used.
+
+ o Otherwise the error <<invalid_target>> is returned to
+ <<bfd_openr>>.
+
+ o <<bfd_openr>> attempts to open the file using
+ <<bfd_open_file>>, and returns the BFD.
+
+ Once the BFD has been opened and the target selected, the file
+ format may be determined. This is done by calling
+ <<bfd_check_format>> on the BFD with a suggested format.
+ If <<target_defaulted>> has been set, each possible target
+ type is tried to see if it recognizes the specified format. The
+ routine returns <<true>> when the application guesses right.
+@menu
+@* bfd_target::
+@end menu
+*/
+
+
+/*
+
+INODE
+ bfd_target, , Targets, Targets
+DOCDD
+SUBSECTION
+ bfd_target
+
+DESCRIPTION
+ This structure contains everything that BFD knows about a
+ target. It includes things like its byte order, name, what
+ routines to call to do various operations, etc.
+
+ Every BFD points to a target structure with its <<xvec>>
+ member.
+
+ These macros are used to dispatch to functions through the
+ bfd_target vector. They are used in a number of macros further
+ down in @file{bfd.h}, and are also used when calling various
+ routines by hand inside the BFD implementation. The "arglist"
+ argument must be parenthesized; it contains all the arguments
+ to the called function.
+
+ They make the documentation (more) unpleasant to read, so if
+ someone wants to fix this and not break the above, please do.
+
+.#define BFD_SEND(bfd, message, arglist) \
+. ((*((bfd)->xvec->message)) arglist)
+
+ For operations which index on the BFD format
+
+.#define BFD_SEND_FMT(bfd, message, arglist) \
+. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+
+ This is the struct which defines the type of BFD this is. The
+ <<xvec>> member of the struct <<bfd>> itself points here. Each
+ module that implements access to a different target under BFD,
+ defines one of these.
+
+
+ FIXME, these names should be rationalised with the names of
+ the entry points which call them. Too bad we can't have one
+ macro to define them both!
+
+.typedef struct bfd_target
+.{
+
+Identifies the kind of target, eg SunOS4, Ultrix, etc.
+
+. char *name;
+
+The "flavour" of a back end is a general indication about the contents
+of a file.
+
+. enum target_flavour {
+. bfd_target_unknown_flavour,
+. bfd_target_aout_flavour,
+. bfd_target_coff_flavour,
+. bfd_target_ecoff_flavour,
+. bfd_target_elf_flavour,
+. bfd_target_ieee_flavour,
+. bfd_target_nlm_flavour,
+. bfd_target_oasys_flavour,
+. bfd_target_tekhex_flavour,
+. bfd_target_srec_flavour,
+. bfd_target_hppa_flavour} flavour;
+
+The order of bytes within the data area of a file.
+
+. boolean byteorder_big_p;
+
+The order of bytes within the header parts of a file.
+
+. boolean header_byteorder_big_p;
+
+This is a mask of all the flags which an executable may have set -
+from the set <<NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>.
+
+. flagword object_flags;
+
+This is a mask of all the flags which a section may have set - from
+the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>.
+
+. flagword section_flags;
+
+The character normally found at the front of a symbol
+(if any), perhaps _.
+
+. char symbol_leading_char;
+
+The pad character for filenames within an archive header.
+
+. char ar_pad_char;
+
+The maximum number of characters in an archive header.
+
+. unsigned short ar_max_namelen;
+
+The minimum alignment restriction for any section.
+
+. unsigned int align_power_min;
+
+Entries for byte swapping for data. These are different to the other
+entry points, since they don't take BFD as first arg. Certain other handlers
+could do the same.
+
+. bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *));
+. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *));
+. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *));
+. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+
+Byte swapping for the headers
+
+. bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *));
+. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *));
+. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *));
+. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+
+Format dependent routines: these are vectors of entry points
+within the target vector structure, one for each format to check.
+
+Check the format of a file being read. Return bfd_target * or zero.
+
+. struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *));
+
+Set the format of a file being written.
+
+. boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *));
+
+Write cached information into a file being written, at bfd_close.
+
+. boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *));
+
+The following functions are defined in <<JUMP_TABLE>>. The idea is
+that the back end writer of <<foo>> names all the routines
+<<foo_>>@var{entry_point}, <<JUMP_TABLE>> will built the entries
+in this structure in the right order.
+
+Core file entry points
+
+. char * (*_core_file_failing_command) PARAMS ((bfd *));
+. int (*_core_file_failing_signal) PARAMS ((bfd *));
+. boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+
+Archive entry points
+
+. boolean (*_bfd_slurp_armap) PARAMS ((bfd *));
+. boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *));
+. void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *));
+. boolean (*write_armap) PARAMS ((bfd *arch,
+. unsigned int elength,
+. struct orl *map,
+. unsigned int orl_count,
+. int stridx));
+
+Standard stuff.
+
+. boolean (*_close_and_cleanup) PARAMS ((bfd *));
+. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+
+Symbols and relocations
+
+. unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *));
+. unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+. struct symbol_cache_entry **));
+. unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+. unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+. struct symbol_cache_entry **));
+. struct symbol_cache_entry *
+. (*_bfd_make_empty_symbol) PARAMS ((bfd *));
+. void (*_bfd_print_symbol) PARAMS ((bfd *, PTR,
+. struct symbol_cache_entry *,
+. bfd_print_symbol_type));
+.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e))
+. void (*_bfd_get_symbol_info) PARAMS ((bfd *,
+. struct symbol_cache_entry *,
+. symbol_info *));
+.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e))
+
+. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+.
+. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+. unsigned long));
+.
+. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+.
+. boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd,
+. struct sec *section, struct symbol_cache_entry **symbols,
+. bfd_vma offset, CONST char **file, CONST char **func,
+. unsigned int *line));
+.
+. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+.
+. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+.
+. void (*_bfd_debug_info_start) PARAMS ((bfd *));
+. void (*_bfd_debug_info_end) PARAMS ((bfd *));
+. void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *));
+.
+. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+. struct bfd_seclet *, bfd_byte *data,
+. boolean relocateable));
+.
+. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+. struct symbol_cache_entry **));
+.
+. boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data,
+. boolean relocateable));
+
+. {* See documentation on reloc types. *}
+. CONST struct reloc_howto_struct *
+. (*reloc_type_lookup) PARAMS ((bfd *abfd,
+. bfd_reloc_code_real_type code));
+.
+. {* Back-door to allow format-aware applications to create debug symbols
+. while using BFD for everything else. Currently used by the assembler
+. when creating COFF files. *}
+. asymbol * (*_bfd_make_debug_symbol) PARAMS ((
+. bfd *abfd,
+. void *ptr,
+. unsigned long size));
+
+Data for use by back-end routines, which isn't generic enough to belong
+in this structure.
+
+. PTR backend_data;
+.} bfd_target;
+
+*/
+
+/* All known xvecs (even those that don't compile on all systems).
+ Alphabetized for easy reference.
+ They are listed a second time below, since
+ we can't intermix extern's and initializers. */
+extern bfd_target a29kcoff_big_vec;
+extern bfd_target a_out_adobe_vec;
+extern bfd_target aout_mips_big_vec;
+extern bfd_target aout_mips_little_vec;
+extern bfd_target apollocoff_vec;
+extern bfd_target b_out_vec_big_host;
+extern bfd_target b_out_vec_little_host;
+extern bfd_target bfd_elf32_big_generic_vec;
+extern bfd_target bfd_elf32_bigmips_vec;
+extern bfd_target bfd_elf32_hppa_vec;
+extern bfd_target bfd_elf32_i386_vec;
+extern bfd_target bfd_elf32_i860_vec;
+extern bfd_target bfd_elf32_little_generic_vec;
+extern bfd_target bfd_elf32_littlemips_vec;
+extern bfd_target bfd_elf32_m68k_vec;
+extern bfd_target bfd_elf32_m88k_vec;
+extern bfd_target bfd_elf32_sparc_vec;
+extern bfd_target bfd_elf64_big_generic_vec;
+extern bfd_target bfd_elf64_little_generic_vec;
+extern bfd_target demo_64_vec;
+extern bfd_target ecoff_big_vec;
+extern bfd_target ecoff_little_vec;
+extern bfd_target ecoffalpha_little_vec;
+extern bfd_target h8300coff_vec;
+extern bfd_target h8500coff_vec;
+extern bfd_target host_aout_vec;
+extern bfd_target hp300bsd_vec;
+extern bfd_target hp300hpux_vec;
+extern bfd_target hppa_vec;
+extern bfd_target i386aout_vec;
+extern bfd_target i386bsd_vec;
+extern bfd_target netbsd386_vec;
+extern bfd_target freebsd386_vec;
+extern bfd_target i386coff_vec;
+extern bfd_target i386linux_vec;
+extern bfd_target i386lynx_aout_vec;
+extern bfd_target i386lynx_coff_vec;
+extern bfd_target icoff_big_vec;
+extern bfd_target icoff_little_vec;
+extern bfd_target ieee_vec;
+extern bfd_target m68kcoff_vec;
+extern bfd_target m68kcoffun_vec;
+extern bfd_target m68klynx_aout_vec;
+extern bfd_target m68klynx_coff_vec;
+extern bfd_target m88kbcs_vec;
+extern bfd_target newsos3_vec;
+extern bfd_target nlm32_big_generic_vec;
+extern bfd_target nlm32_i386_vec;
+extern bfd_target nlm32_little_generic_vec;
+extern bfd_target nlm64_big_generic_vec;
+extern bfd_target nlm64_little_generic_vec;
+extern bfd_target oasys_vec;
+extern bfd_target rs6000coff_vec;
+extern bfd_target shcoff_vec;
+extern bfd_target sunos_big_vec;
+extern bfd_target tekhex_vec;
+extern bfd_target we32kcoff_vec;
+extern bfd_target z8kcoff_vec;
+
+/* srec is always included. */
+extern bfd_target srec_vec;
+extern bfd_target symbolsrec_vec;
+
+/* All of the xvecs for core files. */
+extern bfd_target aix386_core_vec;
+extern bfd_target hpux_core_vec;
+extern bfd_target osf_core_vec;
+extern bfd_target sco_core_vec;
+extern bfd_target trad_core_vec;
+
+bfd_target *target_vector[] = {
+
+#ifdef SELECT_VECS
+
+ SELECT_VECS,
+
+#else /* not SELECT_VECS */
+
+#ifdef DEFAULT_VECTOR
+ &DEFAULT_VECTOR,
+#endif
+ /* This list is alphabetized to make it easy to compare
+ with other vector lists -- the decls above and
+ the case statement in configure.in.
+ Vectors that don't compile on all systems, or aren't finished,
+ should have an entry here with #if 0 around it, to show that
+ it wasn't omitted by mistake. */
+ &a29kcoff_big_vec,
+ &a_out_adobe_vec,
+#if 0 /* No one seems to use this. */
+ &aout_mips_big_vec,
+#endif
+ &aout_mips_little_vec,
+ &b_out_vec_big_host,
+ &b_out_vec_little_host,
+#if 0 /* No one seems to use this. */
+ &bfd_elf32_big_generic_vec,
+ &bfd_elf32_bigmips_vec,
+#endif
+#if 0
+ &bfd_elf32_hppa_vec,
+#endif
+ &bfd_elf32_i386_vec,
+ &bfd_elf32_i860_vec,
+#if 0 /* No one seems to use this. */
+ &bfd_elf32_little_generic_vec,
+ &bfd_elf32_littlemips_vec,
+#endif
+ &bfd_elf32_m68k_vec,
+ &bfd_elf32_m88k_vec,
+ &bfd_elf32_sparc_vec,
+#ifdef BFD64 /* No one seems to use this. */
+ &bfd_elf64_big_generic_vec,
+ &bfd_elf64_little_generic_vec,
+#endif
+#ifdef BFD64
+ &demo_64_vec, /* Only compiled if host has long-long support */
+#endif
+ &ecoff_big_vec,
+ &ecoff_little_vec,
+#if 0
+ &ecoffalpha_little_vec,
+#endif
+ &h8300coff_vec,
+ &h8500coff_vec,
+#if 0
+ &host_aout_vec,
+#endif
+#if 0 /* Clashes with sunos_big_vec magic no. */
+ &hp300bsd_vec,
+#endif
+ &hp300hpux_vec,
+#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD)
+ &hppa_vec,
+#endif
+ &i386aout_vec,
+ &i386bsd_vec,
+ &netbsd386_vec,
+ &freebsd386_vec,
+ &i386coff_vec,
+#if 0
+ &i386linux_vec,
+#endif
+ &i386lynx_aout_vec,
+ &i386lynx_coff_vec,
+ &icoff_big_vec,
+ &icoff_little_vec,
+ &ieee_vec,
+ &m68kcoff_vec,
+ &m68kcoffun_vec,
+ &m68klynx_aout_vec,
+ &m68klynx_coff_vec,
+ &m88kbcs_vec,
+ &newsos3_vec,
+#if 0 /* No one seems to use this. */
+ &nlm32_big_generic_vec,
+#endif
+ &nlm32_i386_vec,
+#if 0 /* No one seems to use this. */
+ &nlm32_little_generic_vec,
+#endif
+#ifdef BFD64
+ &nlm64_big_generic_vec,
+ &nlm64_little_generic_vec,
+#endif
+#if 0
+ /* We have no oasys tools anymore, so we can't test any of this
+ anymore. If you want to test the stuff yourself, go ahead...
+ steve@cygnus.com
+ Worse, since there is no magic number for archives, there
+ can be annoying target mis-matches. */
+ &oasys_vec,
+#endif
+ &rs6000coff_vec,
+ &shcoff_vec,
+ &sunos_big_vec,
+#if 0
+ &tekhex_vec,
+#endif
+ &we32kcoff_vec,
+ &z8kcoff_vec,
+
+#endif /* not SELECT_VECS */
+
+/* Always support S-records, for convenience. */
+ &srec_vec,
+ &symbolsrec_vec,
+
+/* Add any required traditional-core-file-handler. */
+
+#ifdef AIX386_CORE
+ &aix386_core_vec,
+#endif
+#ifdef HPUX_CORE
+ &hpux_core_vec,
+#endif
+#ifdef OSF_CORE
+ &osf_core_vec,
+#endif
+#ifdef SCO_CORE
+ &sco_core_vec,
+#endif
+#ifdef TRAD_CORE
+ &trad_core_vec,
+#endif
+
+ NULL /* end of list marker */
+};
+
+/* default_vector[0] contains either the address of the default vector,
+ if there is one, or zero if there isn't. */
+
+bfd_target *default_vector[] = {
+#ifdef DEFAULT_VECTOR
+ &DEFAULT_VECTOR,
+#endif
+ NULL
+};
+
+
+
+
+/*
+FUNCTION
+ bfd_find_target
+
+DESCRIPTION
+ Returns a pointer to the transfer vector for the object target
+ named target_name. If target_name is NULL, chooses the one in
+ the environment variable GNUTARGET; if that is null or not
+ defined thenthe first entry in the target list is chosen.
+ Passing in the string "default" or setting the environment
+ variable to "default" will cause the first entry in the target
+ list to be returned, and "target_defaulted" will be set in the
+ BFD. This causes <<bfd_check_format>> to loop over all the
+ targets to find the one that matches the file being read.
+
+SYNOPSIS
+ bfd_target *bfd_find_target(CONST char *, bfd *);
+*/
+
+bfd_target *
+DEFUN(bfd_find_target,(target_name, abfd),
+ CONST char *target_name AND
+ bfd *abfd)
+{
+ bfd_target **target;
+ extern char *getenv ();
+ CONST char *targname = (target_name ? target_name :
+ (CONST char *) getenv ("GNUTARGET"));
+
+ /* This is safe; the vector cannot be null */
+ if (targname == NULL || !strcmp (targname, "default")) {
+ abfd->target_defaulted = true;
+ return abfd->xvec = target_vector[0];
+ }
+
+ abfd->target_defaulted = false;
+
+ for (target = &target_vector[0]; *target != NULL; target++) {
+ if (!strcmp (targname, (*target)->name))
+ return abfd->xvec = *target;
+ }
+
+ bfd_error = invalid_target;
+ return NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_target_list
+
+DESCRIPTION
+ This function returns a freshly malloced NULL-terminated
+ vector of the names of all the valid BFD targets. Do not
+ modify the names
+
+SYNOPSIS
+ CONST char **bfd_target_list(void);
+
+*/
+
+CONST char **
+DEFUN_VOID(bfd_target_list)
+{
+ int vec_length= 0;
+#ifdef NATIVE_HPPAHPUX_COMPILER
+ /* The native compiler on the HP9000/700 has a bug which causes it
+ to loop endlessly when compiling this file. This avoids it. */
+ volatile
+#endif
+ bfd_target **target;
+ CONST char **name_list, **name_ptr;
+
+ for (target = &target_vector[0]; *target != NULL; target++)
+ vec_length++;
+
+ name_ptr =
+ name_list = (CONST char **) zalloc ((vec_length + 1) * sizeof (char **));
+
+ if (name_list == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ for (target = &target_vector[0]; *target != NULL; target++)
+ *(name_ptr++) = (*target)->name;
+
+ return name_list;
+}
diff --git a/gnu/usr.bin/gdb/bfd/trad-core.c b/gnu/usr.bin/gdb/bfd/trad-core.c
new file mode 100644
index 000000000000..203c80e6a832
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/trad-core.c
@@ -0,0 +1,384 @@
+/* BFD back end for traditional Unix core files (U-area and raw sections)
+ Copyright 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by John Gilmore of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To use this file on a particular host, configure the host with these
+ parameters in the config/h-HOST file:
+
+ HDEFINES=-DTRAD_CORE
+ HDEPFILES=trad-core.o
+
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h" /* BFD a.out internal data structures */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+
+#include <sys/user.h> /* After a.out.h */
+#if 0
+/* file.h is included by std-host.h. So we better not try to include it
+ twice; on some systems (dpx2) it is not protected against multiple
+ inclusion. I have checked that all the hosts which use this file
+ include sys/file.h in the hosts file. */
+#include <sys/file.h>
+#endif
+
+#include <errno.h>
+
+ struct trad_core_struct
+ {
+ asection *data_section;
+ asection *stack_section;
+ asection *reg_section;
+ struct user u;
+ } *rawptr;
+
+#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u))
+#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section)
+#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
+#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section)
+
+/* forward declarations */
+
+bfd_target * trad_unix_core_file_p PARAMS ((bfd *abfd));
+char * trad_unix_core_file_failing_command PARAMS ((bfd *abfd));
+int trad_unix_core_file_failing_signal PARAMS ((bfd *abfd));
+boolean trad_unix_core_file_matches_executable_p
+ PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */
+
+/* ARGSUSED */
+bfd_target *
+trad_unix_core_file_p (abfd)
+ bfd *abfd;
+
+{
+ int val;
+ struct user u;
+
+#ifdef TRAD_CORE_USER_OFFSET
+ /* If defined, this macro is the file position of the user struct. */
+ if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) == 0)
+ return 0;
+#endif
+
+ val = bfd_read ((void *)&u, 1, sizeof u, abfd);
+ if (val != sizeof u)
+ {
+ /* Too small to be a core file */
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+ /* Sanity check perhaps??? */
+ if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */
+ {
+ bfd_error = wrong_format;
+ return 0;
+ }
+ if (u.u_ssize > 0x1000000)
+ {
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+ /* Check that the size claimed is no greater than the file size. */
+ {
+ FILE *stream = bfd_cache_lookup (abfd);
+ struct stat statbuf;
+ if (stream == NULL)
+ return 0;
+ if (fstat (fileno (stream), &statbuf) < 0)
+ {
+ bfd_error = system_call_error;
+ return 0;
+ }
+ if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) > statbuf.st_size)
+ {
+ bfd_error = file_truncated;
+ return 0;
+ }
+ if (NBPG * (UPAGES + u.u_dsize + u.u_ssize)
+#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
+ /* Some systems write the file too big. */
+ + TRAD_CORE_EXTRA_SIZE_ALLOWED
+#endif
+ < statbuf.st_size)
+ {
+ /* The file is too big. Maybe it's not a core file
+ or we otherwise have bad values for u_dsize and u_ssize). */
+ bfd_error = wrong_format;
+ return 0;
+ }
+ }
+
+ /* OK, we believe you. You're a core file (sure, sure). */
+
+ /* Allocate both the upage and the struct core_data at once, so
+ a single free() will free them both. */
+ rawptr = (struct trad_core_struct *)
+ bfd_zalloc (abfd, sizeof (struct trad_core_struct));
+ if (rawptr == NULL) {
+ bfd_error = no_memory;
+ return 0;
+ }
+
+ abfd->tdata.trad_core_data = rawptr;
+
+ rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
+
+ /* Create the sections. This is raunchy, but bfd_close wants to free
+ them separately. */
+
+ core_stacksec(abfd) = (asection *) zalloc (sizeof (asection));
+ if (core_stacksec (abfd) == NULL) {
+ loser:
+ bfd_error = no_memory;
+ free ((void *)rawptr);
+ return 0;
+ }
+ core_datasec (abfd) = (asection *) zalloc (sizeof (asection));
+ if (core_datasec (abfd) == NULL) {
+ loser1:
+ free ((void *)core_stacksec (abfd));
+ goto loser;
+ }
+ core_regsec (abfd) = (asection *) zalloc (sizeof (asection));
+ if (core_regsec (abfd) == NULL) {
+ free ((void *)core_datasec (abfd));
+ goto loser1;
+ }
+
+ core_stacksec (abfd)->name = ".stack";
+ core_datasec (abfd)->name = ".data";
+ core_regsec (abfd)->name = ".reg";
+
+ core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
+ core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
+ core_regsec (abfd)->flags = SEC_ALLOC + SEC_HAS_CONTENTS;
+
+ core_datasec (abfd)->_raw_size = NBPG * u.u_dsize;
+ core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize;
+ core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */
+
+ /* What a hack... we'd like to steal it from the exec file,
+ since the upage does not seem to provide it. FIXME. */
+#ifdef HOST_DATA_START_ADDR
+ core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
+#else
+ core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
+#endif
+/* a hack, but it works for FreeBSD !! */
+#include <vm/vm_param.h>
+/* this should really be in <vm/vm_param.h>, but somebody forgot it */
+#ifndef vm_page_size
+#define vm_page_size 4096
+#endif
+#define HOST_STACK_START_ADDR trunc_page(u.u_kproc.kp_eproc.e_vm.vm_maxsaddr \
++ MAXSSIZ - ctob(u.u_ssize))
+#ifdef HOST_STACK_START_ADDR
+ core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
+#else
+ core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
+#endif
+
+ /* This is tricky. As the "register section", we give them the entire
+ upage and stack. u.u_ar0 points to where "register 0" is stored.
+ There are two tricks with this, though. One is that the rest of the
+ registers might be at positive or negative (or both) displacements
+ from *u_ar0. The other is that u_ar0 is sometimes an absolute address
+ in kernel memory, and on other systems it is an offset from the beginning
+ of the `struct user'.
+
+ As a practical matter, we don't know where the registers actually are,
+ so we have to pass the whole area to GDB. We encode the value of u_ar0
+ by setting the .regs section up so that its virtual memory address
+ 0 is at the place pointed to by u_ar0 (by setting the vma of the start
+ of the section to -u_ar0). GDB uses this info to locate the regs,
+ using minor trickery to get around the offset-or-absolute-addr problem. */
+ core_regsec (abfd)->vma = 0 - (int) u.u_ar0;
+
+ core_datasec (abfd)->filepos = NBPG * UPAGES;
+#ifdef TRAD_CORE_STACK_FILEPOS
+ core_stacksec (abfd)->filepos = TRAD_CORE_STACK_FILEPOS;
+#else
+ core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize;
+#endif
+ core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
+
+ /* Align to word at least */
+ core_stacksec (abfd)->alignment_power = 2;
+ core_datasec (abfd)->alignment_power = 2;
+ core_regsec (abfd)->alignment_power = 2;
+
+ abfd->sections = core_stacksec (abfd);
+ core_stacksec (abfd)->next = core_datasec (abfd);
+ core_datasec (abfd)->next = core_regsec (abfd);
+ abfd->section_count = 3;
+
+ return abfd->xvec;
+}
+
+char *
+trad_unix_core_file_failing_command (abfd)
+ bfd *abfd;
+{
+#ifndef NO_CORE_COMMAND
+ char *com = abfd->tdata.trad_core_data->u.u_comm;
+ if (*com)
+ return com;
+ else
+#endif
+ return 0;
+}
+
+/* ARGSUSED */
+int
+trad_unix_core_file_failing_signal (ignore_abfd)
+ bfd *ignore_abfd;
+{
+#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
+ return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
+#else
+ return -1; /* FIXME, where is it? */
+#endif
+}
+
+/* ARGSUSED */
+boolean
+trad_unix_core_file_matches_executable_p (core_bfd, exec_bfd)
+ bfd *core_bfd, *exec_bfd;
+{
+ return true; /* FIXME, We have no way of telling at this point */
+}
+
+/* No archive file support via this BFD */
+#define trad_unix_openr_next_archived_file bfd_generic_openr_next_archived_file
+#define trad_unix_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#define trad_unix_slurp_armap bfd_false
+#define trad_unix_slurp_extended_name_table bfd_true
+#define trad_unix_write_armap (boolean (*) PARAMS \
+ ((bfd *arch, unsigned int elength, struct orl *map, \
+ unsigned int orl_count, int stridx))) bfd_false
+#define trad_unix_truncate_arname bfd_dont_truncate_arname
+#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file
+
+#define trad_unix_close_and_cleanup bfd_generic_close_and_cleanup
+#define trad_unix_set_section_contents (boolean (*) PARAMS \
+ ((bfd *abfd, asection *section, PTR data, file_ptr offset, \
+ bfd_size_type count))) bfd_false
+#define trad_unix_get_section_contents bfd_generic_get_section_contents
+#define trad_unix_new_section_hook (boolean (*) PARAMS \
+ ((bfd *, sec_ptr))) bfd_true
+#define trad_unix_get_symtab_upper_bound bfd_0u
+#define trad_unix_get_symtab (unsigned int (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry **))) bfd_0u
+#define trad_unix_get_reloc_upper_bound (unsigned int (*) PARAMS \
+ ((bfd *, sec_ptr))) bfd_0u
+#define trad_unix_canonicalize_reloc (unsigned int (*) PARAMS \
+ ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u
+#define trad_unix_make_empty_symbol (struct symbol_cache_entry * \
+ (*) PARAMS ((bfd *))) bfd_false
+#define trad_unix_print_symbol (void (*) PARAMS \
+ ((bfd *, PTR, struct symbol_cache_entry *, \
+ bfd_print_symbol_type))) bfd_false
+#define trad_unix_get_symbol_info (void (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry *, \
+ symbol_info *))) bfd_false
+#define trad_unix_get_lineno (alent * (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr
+#define trad_unix_set_arch_mach (boolean (*) PARAMS \
+ ((bfd *, enum bfd_architecture, unsigned long))) bfd_false
+#define trad_unix_find_nearest_line (boolean (*) PARAMS \
+ ((bfd *abfd, struct sec *section, \
+ struct symbol_cache_entry **symbols,bfd_vma offset, \
+ CONST char **file, CONST char **func, unsigned int *line))) bfd_false
+#define trad_unix_sizeof_headers (int (*) PARAMS \
+ ((bfd *, boolean))) bfd_0
+
+#define trad_unix_bfd_debug_info_start bfd_void
+#define trad_unix_bfd_debug_info_end bfd_void
+#define trad_unix_bfd_debug_info_accumulate (void (*) PARAMS \
+ ((bfd *, struct sec *))) bfd_void
+#define trad_unix_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
+#define trad_unix_bfd_relax_section bfd_generic_relax_section
+#define trad_unix_bfd_seclet_link \
+ ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false)
+#define trad_unix_bfd_reloc_type_lookup \
+ ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr)
+#define trad_unix_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+/* If somebody calls any byte-swapping routines, shoot them. */
+void
+swap_abort()
+{
+ abort(); /* This way doesn't require any declaration for ANSI to fuck up */
+}
+#define NO_GET ((bfd_vma (*) PARAMS (( bfd_byte *))) swap_abort )
+#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort )
+#define NO_SIGNED_GET ((bfd_signed_vma (*) PARAMS ((bfd_byte *))) swap_abort )
+
+bfd_target trad_core_vec =
+ {
+ "trad-core",
+ bfd_target_unknown_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* symbol prefix */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 3, /* minimum alignment power */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */
+
+ { /* bfd_check_format */
+ _bfd_dummy_target, /* unknown format */
+ _bfd_dummy_target, /* object file */
+ _bfd_dummy_target, /* archive */
+ trad_unix_core_file_p /* a core file */
+ },
+ { /* bfd_set_format */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+ { /* bfd_write_contents */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+
+ JUMP_TABLE(trad_unix),
+ (PTR) 0 /* backend_data */
+};
diff --git a/gnu/usr.bin/gdb/config/i386bsd-dep.c b/gnu/usr.bin/gdb/config/i386bsd-dep.c
deleted file mode 100644
index 80e11fa137c1..000000000000
--- a/gnu/usr.bin/gdb/config/i386bsd-dep.c
+++ /dev/null
@@ -1,1886 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)i386bsd-dep.c 6.10 (Berkeley) 6/26/91";
-#endif /* not lint */
-
-/* Low level interface to ptrace, for GDB when running on the Intel 386.
- Copyright (C) 1988, 1989 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-GDB is free software; you can 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.
-
-GDB is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdio.h>
-#include "defs.h"
-#include "param.h"
-#include "frame.h"
-#include "inferior.h"
-#include "value.h"
-
-#include <sys/param.h>
-#include <sys/dir.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#include <a.out.h>
-
-#ifndef N_SET_MAGIC
-#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
-#endif
-
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/uio.h>
-#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
-#include <sys/user.h>
-#undef curpcb
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/ptrace.h>
-
-#include <machine/reg.h>
-
-#ifdef KERNELDEBUG
-#ifndef NEWVM
-#include <sys/vmmac.h>
-#include <machine/pte.h>
-#else
-#include <sys/proc.h> /* for curproc */
-#endif
-#include <machine/vmparam.h>
-#include <machine/cpu.h>
-#include <ctype.h>
-#include "symtab.h" /* XXX */
-
-#undef vtophys /* XXX */
-
-extern int kernel_debugging;
-
-#define KERNOFF ((unsigned)KERNBASE)
-#ifndef NEWVM
-#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr))
-#define INUPAGE(x) \
- ((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + NBPG)
-#else
-#define INKERNEL(x) ((x) >= KERNOFF)
-#endif
-
-#define PT_ADDR_ANY ((caddr_t) 1)
-
-/*
- * Convert from sysmap pte index to system virtual address & vice-versa.
- * (why aren't these in one of the system vm macro files???)
- */
-#define smxtob(a) (sbr + (a) * sizeof(pte))
-#define btosmx(b) (((b) - sbr) / sizeof(pte))
-
-static int ok_to_cache();
-static int found_pcb;
-#ifdef NEWVM
-static CORE_ADDR curpcb;
-static CORE_ADDR kstack;
-#endif
-
-static void setregmap();
-
-extern int errno;
-
-/*
- * This function simply calls ptrace with the given arguments. It exists so
- * that all calls to ptrace are isolated in this machine-dependent file.
- */
-int
-call_ptrace(request, pid, arg3, arg4)
- int request;
- pid_t pid;
- caddr_t arg3;
- int arg4;
-{
- return(ptrace(request, pid, arg3, arg4));
-}
-
-kill_inferior()
-{
- if (remote_debugging) {
-#ifdef KERNELDEBUG
- if (kernel_debugging)
- /*
- * It's a very, very bad idea to go away leaving
- * breakpoints in a remote kernel or to leave it
- * stopped at a breakpoint.
- */
- clear_breakpoints();
-#endif
- remote_close(0);
- inferior_died();
- } else if (inferior_pid != 0) {
- ptrace(PT_KILL, inferior_pid, 0, 0);
- wait(0);
- inferior_died();
- }
-}
-
-/*
- * This is used when GDB is exiting. It gives less chance of error.
- */
-kill_inferior_fast()
-{
- if (remote_debugging) {
-#ifdef KERNELDEBUG
- if (kernel_debugging)
- clear_breakpoints();
-#endif
- remote_close(0);
- return;
- }
- if (inferior_pid == 0)
- return;
-
- ptrace(PT_KILL, inferior_pid, 0, 0);
- wait(0);
-}
-
-/*
- * Resume execution of the inferior process. If STEP is nonzero, single-step
- * it. If SIGNAL is nonzero, give it that signal.
- */
-void
-resume(step, signal)
- int step;
- int signal;
-{
- errno = 0;
- if (remote_debugging)
- remote_resume(step, signal);
- else {
- ptrace(step ? PT_STEP : PT_CONTINUE, inferior_pid,
- PT_ADDR_ANY, signal);
- if (errno)
- perror_with_name("ptrace");
- }
-}
-
-#ifdef ATTACH_DETACH
-extern int attach_flag;
-
-/*
- * Start debugging the process whose number is PID.
- */
-attach(pid)
- int pid;
-{
- errno = 0;
- ptrace(PT_ATTACH, pid, 0, 0);
- if (errno)
- perror_with_name("ptrace");
- attach_flag = 1;
- return pid;
-}
-
-/*
- * Stop debugging the process whose number is PID and continue it
- * with signal number SIGNAL. SIGNAL = 0 means just continue it.
- */
-void
-detach(signal)
- int signal;
-{
- errno = 0;
- ptrace(PT_DETACH, inferior_pid, PT_ADDR_ANY, signal);
- if (errno)
- perror_with_name("ptrace");
- attach_flag = 0;
-}
-#endif /* ATTACH_DETACH */
-
-static unsigned int
-get_register_offset()
-{
- unsigned int offset;
- struct user u; /* XXX */
- unsigned int flags = (char *) &u.u_pcb.pcb_flags - (char *) &u;
-
- setregmap(ptrace(PT_READ_U, inferior_pid, (caddr_t)flags, 0));
-
-#ifdef NEWVM
- offset = (char *) &u.u_kproc.kp_proc.p_regs - (char *) &u;
- offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
- USRSTACK;
-#else
- offset = (char *) &u.u_ar0 - (char *) &u;
- offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
- KERNEL_U_ADDR;
-#endif
-
- return offset;
-}
-
-void
-fetch_inferior_registers()
-{
- register int regno;
- register unsigned int regaddr;
- char buf[MAX_REGISTER_RAW_SIZE];
- register int i;
- unsigned int offset;
-
- if (remote_debugging) {
- extern char registers[];
-
- remote_fetch_registers(registers);
- return;
- }
-
- offset = get_register_offset();
-
- for (regno = 0; regno < NUM_REGS; regno++) {
- regaddr = register_addr(regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
- *(int *)&buf[i] = ptrace(PT_READ_U, inferior_pid,
- (caddr_t)regaddr, 0);
- regaddr += sizeof(int);
- }
- supply_register(regno, buf);
- }
-}
-
-/*
- * Store our register values back into the inferior. If REGNO is -1, do this
- * for all registers. Otherwise, REGNO specifies which register (so we can
- * save time).
- */
-store_inferior_registers(regno)
- int regno;
-{
- register unsigned int regaddr;
- char buf[80];
- extern char registers[];
- register int i;
- unsigned int offset;
-
- if (remote_debugging) {
- extern char registers[];
-
- remote_store_registers(registers);
- return;
- }
-
- offset = get_register_offset();
-
- if (regno >= 0) {
- regaddr = register_addr(regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
- errno = 0;
- ptrace(PT_WRITE_U, inferior_pid, (caddr_t)regaddr,
- *(int *) &registers[REGISTER_BYTE(regno) + i]);
- if (errno != 0) {
- sprintf(buf, "writing register number %d(%d)",
- regno, i);
- perror_with_name(buf);
- }
- regaddr += sizeof(int);
- }
- } else
- for (regno = 0; regno < NUM_REGS; regno++) {
- regaddr = register_addr(regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE(regno);
- i += sizeof(int)) {
- errno = 0;
- ptrace(PT_WRITE_U, inferior_pid,
- (caddr_t)regaddr,
- *(int *) &registers[REGISTER_BYTE(regno) + i]);
- if (errno != 0) {
- sprintf(buf,
- "writing register number %d(%d)",
- regno, i);
- perror_with_name(buf);
- }
- regaddr += sizeof(int);
- }
- }
-}
-
-/*
- * Copy LEN bytes from inferior's memory starting at MEMADDR to debugger
- * memory starting at MYADDR. On failure (cannot read from inferior, usually
- * because address is out of bounds) returns the value of errno.
- */
-int
-read_inferior_memory(memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
-{
- register int i;
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr = memaddr & -sizeof(int);
- /* Round ending address up; get number of longwords that makes. */
- register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
- sizeof(int);
- /* Allocate buffer of that many longwords. */
- register int *buffer = (int *) alloca(count * sizeof(int));
- extern int errno;
-
- if (remote_debugging)
- return (remote_read_inferior_memory(memaddr, myaddr, len));
-
- /* Read all the longwords */
- errno = 0;
- for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
- buffer[i] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
-
- /* Copy appropriate bytes out of the buffer. */
- bcopy((char *) buffer + (memaddr & (sizeof(int) - 1)), myaddr, len);
- return(errno);
-}
-
-/*
- * Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory
- * at MEMADDR. On failure (cannot write the inferior) returns the value of
- * errno.
- */
-
-int
-write_inferior_memory(memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
-{
- register int i;
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr = memaddr & -sizeof(int);
- /* Round ending address up; get number of longwords that makes. */
- register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
- sizeof(int);
- /* Allocate buffer of that many longwords. */
- register int *buffer = (int *) alloca(count * sizeof(int));
- extern int errno;
-
- /*
- * Fill start and end extra bytes of buffer with existing memory
- * data.
- */
- if (remote_debugging)
- return (remote_write_inferior_memory(memaddr, myaddr, len));
-
- /*
- * Fill start and end extra bytes of buffer with existing memory
- * data.
- */
- buffer[0] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
-
- if (count > 1)
- buffer[count - 1] = ptrace(PT_READ_I, inferior_pid,
- (caddr_t)addr + (count - 1) * sizeof(int), 0);
-
- /* Copy data to be written over corresponding part of buffer */
-
- bcopy(myaddr, (char *) buffer + (memaddr & (sizeof(int) - 1)), len);
-
- /* Write the entire buffer. */
-
- errno = 0;
- for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
- ptrace(PT_WRITE_I, inferior_pid, (caddr_t)addr, buffer[i]);
-
- return(errno);
-}
-
-
-/*
- * Work with core dump and executable files, for GDB.
- * This code would be in core.c if it weren't machine-dependent.
- */
-
-#ifndef N_TXTADDR
-#define N_TXTADDR(hdr) 0
-#endif /* no N_TXTADDR */
-
-#ifndef N_DATADDR
-#define N_DATADDR(hdr) hdr.a_text
-#endif /* no N_DATADDR */
-
-/*
- * Make COFF and non-COFF names for things a little more compatible to reduce
- * conditionals later.
- */
-
-#ifndef AOUTHDR
-#define AOUTHDR struct exec
-#endif
-
-extern char *sys_siglist[];
-
-
-/* Hook for `exec_file_command' command to call. */
-
-extern void (*exec_file_display_hook) ();
-
-/* File names of core file and executable file. */
-
-extern char *corefile;
-extern char *execfile;
-
-/* Descriptors on which core file and executable file are open.
- Note that the execchan is closed when an inferior is created
- and reopened if the inferior dies or is killed. */
-
-extern int corechan;
-extern int execchan;
-
-/* Last modification time of executable file.
- Also used in source.c to compare against mtime of a source file. */
-
-extern int exec_mtime;
-
-/* Virtual addresses of bounds of the two areas of memory in the core file. */
-
-extern CORE_ADDR data_start;
-extern CORE_ADDR data_end;
-extern CORE_ADDR stack_start;
-extern CORE_ADDR stack_end;
-
-/* Virtual addresses of bounds of two areas of memory in the exec file.
- Note that the data area in the exec file is used only when there is no core file. */
-
-extern CORE_ADDR text_start;
-extern CORE_ADDR text_end;
-
-extern CORE_ADDR exec_data_start;
-extern CORE_ADDR exec_data_end;
-
-/* Address in executable file of start of text area data. */
-
-extern int text_offset;
-
-/* Address in executable file of start of data area data. */
-
-extern int exec_data_offset;
-
-/* Address in core file of start of data area data. */
-
-extern int data_offset;
-
-/* Address in core file of start of stack area data. */
-
-extern int stack_offset;
-
-/* a.out header saved in core file. */
-
-extern AOUTHDR core_aouthdr;
-
-/* a.out header of exec file. */
-
-extern AOUTHDR exec_aouthdr;
-
-extern void validate_files ();
-
-extern int (*core_file_hook)();
-
-#ifdef KERNELDEBUG
-/*
- * Kernel debugging routines.
- */
-
-#define IOTOP 0x100000 /* XXX should get this from include file */
-#define IOBASE 0xa0000 /* XXX should get this from include file */
-
-static CORE_ADDR file_offset;
-static CORE_ADDR lowram;
-static CORE_ADDR sbr;
-static CORE_ADDR slr;
-static struct pcb pcb;
-
-static CORE_ADDR
-ksym_lookup(name)
- char *name;
-{
- struct symbol *sym;
- int i;
-
- if ((i = lookup_misc_func(name)) < 0)
- error("kernel symbol `%s' not found.", name);
-
- return (misc_function_vector[i].address);
-}
-
-/*
- * return true if 'len' bytes starting at 'addr' can be read out as
- * longwords and/or locally cached (this is mostly for memory mapped
- * i/o register access when debugging remote kernels).
- *
- * XXX the HP code does this differently with NEWVM
- */
-static int
-ok_to_cache(addr, len)
-{
- static CORE_ADDR atdevbase;
-
- if (! atdevbase)
- atdevbase = ksym_lookup("atdevbase");
-
- if (addr >= atdevbase && addr < atdevbase + (IOTOP - IOBASE))
- return (0);
-
- return (1);
-}
-
-static
-physrd(addr, dat, len)
- u_int addr;
- char *dat;
-{
- if (lseek(corechan, addr - file_offset, L_SET) == -1)
- return (-1);
- if (read(corechan, dat, len) != len)
- return (-1);
-
- return (0);
-}
-
-/*
- * When looking at kernel data space through /dev/mem or with a core file, do
- * virtual memory mapping.
- */
-#ifdef NEWVM
-static CORE_ADDR
-vtophys(addr)
- CORE_ADDR addr;
-{
- CORE_ADDR v;
- struct pte pte;
- static CORE_ADDR PTD = -1;
- CORE_ADDR current_ptd;
-
- /*
- * If we're looking at the kernel stack,
- * munge the address to refer to the user space mapping instead;
- * that way we get the requested process's kstack, not the running one.
- */
- if (addr >= kstack && addr < kstack + ctob(UPAGES))
- addr = (addr - kstack) + curpcb;
-
- /*
- * We may no longer have a linear system page table...
- *
- * Here's the scoop. IdlePTD contains the physical address
- * of a page table directory that always maps the kernel.
- * IdlePTD is in memory that is mapped 1-to-1, so we can
- * find it easily given its 'virtual' address from ksym_lookup().
- * For hysterical reasons, the value of IdlePTD is stored in sbr.
- *
- * To look up a kernel address, we first convert it to a 1st-level
- * address and look it up in IdlePTD. This gives us the physical
- * address of a page table page; we extract the 2nd-level part of
- * VA and read the 2nd-level pte. Finally, we add the offset part
- * of the VA into the physical address from the pte and return it.
- *
- * User addresses are a little more complicated. If we don't have
- * a current PCB from read_pcb(), we use PTD, which is the (fixed)
- * virtual address of the current ptd. Since it's NOT in 1-to-1
- * kernel space, we must look it up using IdlePTD. If we do have
- * a pcb, we get the ptd from pcb_ptd.
- */
-
- if (INKERNEL(addr))
- current_ptd = sbr;
- else if (found_pcb == 0) {
- if (PTD == -1)
- PTD = vtophys(ksym_lookup("PTD"));
- current_ptd = PTD;
- } else
- current_ptd = pcb.pcb_ptd;
-
- /*
- * Read the first-level page table (ptd).
- */
- v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte;
- if (physrd(v, (char *)&pte, sizeof pte) || pte.pg_v == 0)
- return (~0);
-
- /*
- * Read the second-level page table.
- */
- v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte;
- if (physrd(v, (char *) &pte, sizeof(pte)) || pte.pg_v == 0)
- return (~0);
-
- addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET);
-#if 0
- printf("vtophys(%x) -> %x\n", oldaddr, addr);
-#endif
- return (addr);
-}
-#else
-static CORE_ADDR
-vtophys(addr)
- CORE_ADDR addr;
-{
- CORE_ADDR v;
- struct pte pte;
- CORE_ADDR oldaddr = addr;
-
- if (found_pcb == 0 && INUPAGE(addr)) {
- static CORE_ADDR pSwtchmap;
-
- if (pSwtchmap == 0)
- pSwtchmap = vtophys(ksym_lookup("Swtchmap"));
- addr = pSwtchmap;
- } else if (INKERNEL(addr)) {
- /*
- * In system space get system pte. If valid or reclaimable
- * then physical address is combination of its page number
- * and the page offset of the original address.
- */
- addr = smxtob(btop(addr - KERNOFF)) - KERNOFF;
- } else {
- v = btop(addr);
- if (v < pcb.pcb_p0lr)
- addr = (CORE_ADDR) pcb.pcb_p0br +
- v * sizeof (struct pte);
- else if (v >= pcb.pcb_p1lr && v < P1PAGES)
- addr = (CORE_ADDR) pcb.pcb_p0br +
- ((pcb.pcb_szpt * NPTEPG - HIGHPAGES) -
- (BTOPUSRSTACK - v)) * sizeof (struct pte);
- else
- return (~0);
-
- /*
- * For p0/p1 address, user-level page table should be in
- * kernel vm. Do second-level indirect by recursing.
- */
- if (!INKERNEL(addr))
- return (~0);
-
- addr = vtophys(addr);
- }
- /*
- * Addr is now address of the pte of the page we are interested in;
- * get the pte and paste up the physical address.
- */
- if (physrd(addr, (char *) &pte, sizeof(pte)))
- return (~0);
-
- if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
- return (~0);
-
- addr = (CORE_ADDR)ptob(pte.pg_pfnum) + (oldaddr & PGOFSET);
-#if 0
- printf("vtophys(%x) -> %x\n", oldaddr, addr);
-#endif
- return (addr);
-}
-
-#endif
-
-static
-kvread(addr)
- CORE_ADDR addr;
-{
- CORE_ADDR paddr = vtophys(addr);
-
- if (paddr != ~0)
- if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0);
- return (addr);
-
- return (~0);
-}
-
-static void
-read_pcb(uaddr)
- u_int uaddr;
-{
- int i;
- int *pcb_regs = (int *)&pcb;
-
-#ifdef NEWVM
- if (physrd(uaddr, (char *)&pcb, sizeof pcb))
- error("cannot read pcb at %x\n", uaddr);
- printf("current pcb at %x\n", uaddr);
-#else
- if (physrd(uaddr, (char *)&pcb, sizeof pcb))
- error("cannot read pcb at %x\n", uaddr);
- printf("p0br %x p0lr %x p1br %x p1lr %x\n",
- pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr);
-#endif
-
- /*
- * get the register values out of the sys pcb and
- * store them where `read_register' will find them.
- */
- for (i = 0; i < 8; ++i)
- supply_register(i, &pcb_regs[i+10]);
- supply_register(8, &pcb_regs[8]); /* eip */
- supply_register(9, &pcb_regs[9]); /* eflags */
- for (i = 10; i < 13; ++i) /* cs, ss, ds */
- supply_register(i, &pcb_regs[i+9]);
- supply_register(13, &pcb_regs[18]); /* es */
- for (i = 14; i < 16; ++i) /* fs, gs */
- supply_register(i, &pcb_regs[i+8]);
-
- /* XXX 80387 registers? */
-}
-
-static void
-setup_kernel_debugging()
-{
- struct stat stb;
- int devmem = 0;
- CORE_ADDR addr;
-
- fstat(corechan, &stb);
- if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0))
- devmem = 1;
-
-#ifdef NEWVM
- physrd(ksym_lookup("IdlePTD") - KERNOFF, &sbr, sizeof sbr);
- slr = 2 * NPTEPG; /* XXX temporary */
- printf("IdlePTD %x\n", sbr);
- curpcb = ksym_lookup("curpcb") - KERNOFF;
- physrd(curpcb, &curpcb, sizeof curpcb);
- kstack = ksym_lookup("kstack");
-#else
- sbr = ksym_lookup("Sysmap");
- slr = ksym_lookup("Syssize");
- printf("sbr %x slr %x\n", sbr, slr);
-#endif
-
- /*
- * pcb where "panic" saved registers in first thing in current
- * u area.
- */
-#ifndef NEWVM
- read_pcb(vtophys(ksym_lookup("u")));
-#endif
- found_pcb = 1;
- if (!devmem) {
- /* find stack frame */
- CORE_ADDR panicstr;
- char buf[256];
- register char *cp;
-
- panicstr = kvread(ksym_lookup("panicstr"));
- if (panicstr == ~0)
- return;
- (void) kernel_core_file_hook(panicstr, buf, sizeof(buf));
- for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
- if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
- *cp = '?';
- if (*cp)
- *cp = '\0';
- printf("panic: %s\n", buf);
- read_pcb(ksym_lookup("dumppcb") - KERNOFF);
- }
-#ifdef NEWVM
- else
- read_pcb(vtophys(kstack));
-#endif
-
- stack_start = USRSTACK;
- stack_end = USRSTACK + ctob(UPAGES);
-}
-
-set_paddr_command(arg)
- char *arg;
-{
- u_int uaddr;
-
- if (!arg)
- error_no_arg("ps-style address for new current process");
- if (!kernel_debugging)
- error("not debugging kernel");
- uaddr = (u_int) parse_and_eval_address(arg);
-#ifndef NEWVM
- read_pcb(ctob(uaddr));
-#else
- /* p_addr is now a pcb virtual address */
- read_pcb(vtophys(uaddr));
- curpcb = uaddr;
-#endif
-
- flush_cached_frames();
- set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc()));
- select_frame(get_current_frame(), 0);
-}
-
-/*
- * read len bytes from kernel virtual address 'addr' into local
- * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read
- * errors, portion of buffer not read is zeroed.
- */
-kernel_core_file_hook(addr, buf, len)
- CORE_ADDR addr;
- char *buf;
- int len;
-{
- int i;
- CORE_ADDR paddr;
-
- while (len > 0) {
- paddr = vtophys(addr);
- if (paddr == ~0) {
- bzero(buf, len);
- return (1);
- }
- /* we can't read across a page boundary */
- i = min(len, NBPG - (addr & PGOFSET));
- if (physrd(paddr, buf, i)) {
- bzero(buf, len);
- return (1);
- }
- buf += i;
- addr += i;
- len -= i;
- }
- return (0);
-}
-#endif
-
-core_file_command(filename, from_tty)
- char *filename;
- int from_tty;
-{
- int val;
- extern char registers[];
-#ifdef KERNELDEBUG
- struct stat stb;
-#endif
-
- /*
- * Discard all vestiges of any previous core file and mark data and
- * stack spaces as empty.
- */
- if (corefile)
- free(corefile);
- corefile = 0;
- core_file_hook = 0;
-
- if (corechan >= 0)
- close(corechan);
- corechan = -1;
-
- /* Now, if a new core file was specified, open it and digest it. */
-
- if (filename == 0) {
- if (from_tty)
- printf("No core file now.\n");
- return;
- }
- filename = tilde_expand(filename);
- make_cleanup(free, filename);
- if (have_inferior_p())
- error("To look at a core file, you must kill the inferior with \"kill\".");
- corechan = open(filename, O_RDONLY, 0);
- if (corechan < 0)
- perror_with_name(filename);
-
-#ifdef KERNELDEBUG
- fstat(corechan, &stb);
-
- if (kernel_debugging) {
- setup_kernel_debugging();
- core_file_hook = kernel_core_file_hook;
- } else if ((stb.st_mode & S_IFMT) == S_IFCHR &&
- stb.st_rdev == makedev(2, 1)) {
- /* looking at /dev/kmem */
- data_offset = data_start = KERNOFF;
- data_end = ~0; /* XXX */
- stack_end = stack_start = data_end;
- } else
-#endif
- {
- /*
- * 4.2-style core dump file.
- */
- struct user u;
- unsigned int reg_offset;
-
- val = myread(corechan, &u, sizeof u);
- if (val < 0)
- perror_with_name("Not a core file: reading upage");
- if (val != sizeof u)
- error("Not a core file: could only read %d bytes", val);
-
- /*
- * We are depending on exec_file_command having been
- * called previously to set exec_data_start. Since
- * the executable and the core file share the same
- * text segment, the address of the data segment will
- * be the same in both.
- */
- data_start = exec_data_start;
-
-#ifndef NEWVM
- data_end = data_start + NBPG * u.u_dsize;
- stack_start = stack_end - NBPG * u.u_ssize;
- data_offset = NBPG * UPAGES;
- stack_offset = NBPG * (UPAGES + u.u_dsize);
-
- /*
- * Some machines put an absolute address in here and
- * some put the offset in the upage of the regs.
- */
- reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
-#else
- data_end = data_start +
- NBPG * u.u_kproc.kp_eproc.e_vm.vm_dsize;
- stack_start = stack_end -
- NBPG * u.u_kproc.kp_eproc.e_vm.vm_ssize;
- data_offset = NBPG * UPAGES;
- stack_offset = NBPG *
- (UPAGES + u.u_kproc.kp_eproc.e_vm.vm_dsize);
-
- reg_offset = (int) u.u_kproc.kp_proc.p_regs - USRSTACK;
-#endif
-
- setregmap(u.u_pcb.pcb_flags);
-
- /*
- * I don't know where to find this info. So, for now,
- * mark it as not available.
- */
- /* N_SET_MAGIC (core_aouthdr, 0); */
- bzero ((char *) &core_aouthdr, sizeof core_aouthdr);
-
- /*
- * Read the register values out of the core file and
- * store them where `read_register' will find them.
- */
- {
- register int regno;
-
- for (regno = 0; regno < NUM_REGS; regno++) {
- char buf[MAX_REGISTER_RAW_SIZE];
-
- val = lseek(corechan, register_addr(regno, reg_offset), 0);
- if (val < 0
- || (val = myread(corechan, buf, sizeof buf)) < 0) {
- char *buffer = (char *) alloca(strlen(reg_names[regno]) + 30);
- strcpy(buffer, "Reading register ");
- strcat(buffer, reg_names[regno]);
- perror_with_name(buffer);
- }
- supply_register(regno, buf);
- }
- }
- }
-#endif
- if (filename[0] == '/')
- corefile = savestring(filename, strlen(filename));
- else
- corefile = concat(current_directory, "/", filename);
-
- set_current_frame(create_new_frame(read_register(FP_REGNUM),
- read_pc()));
- select_frame(get_current_frame(), 0);
- validate_files();
-}
-
-exec_file_command(filename, from_tty)
- char *filename;
- int from_tty;
-{
- int val;
-
- /*
- * Eliminate all traces of old exec file. Mark text segment as empty.
- */
-
- if (execfile)
- free(execfile);
- execfile = 0;
- data_start = 0;
- data_end = 0;
- stack_start = 0;
- stack_end = 0;
- text_start = 0;
- text_end = 0;
- exec_data_start = 0;
- exec_data_end = 0;
- if (execchan >= 0)
- close(execchan);
- execchan = -1;
-
- /* Now open and digest the file the user requested, if any. */
-
- if (filename) {
- filename = tilde_expand(filename);
- make_cleanup(free, filename);
-
- execchan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0,
- &execfile);
- if (execchan < 0)
- perror_with_name(filename);
-
- {
- struct stat st_exec;
-
-#ifdef HEADER_SEEK_FD
- HEADER_SEEK_FD(execchan);
-#endif
-
- val = myread(execchan, &exec_aouthdr, sizeof(AOUTHDR));
-
- if (val < 0)
- perror_with_name(filename);
-
-#ifdef KERNELDEBUG
- if (kernel_debugging) {
- /* Gross and disgusting XXX */
- text_start = KERNTEXT_BASE;
- exec_data_start = KERNTEXT_BASE +
- (exec_aouthdr.a_text + 4095) & ~ 4095;
- } else {
-#endif
- text_start = N_TXTADDR(exec_aouthdr);
- exec_data_start = N_DATADDR(exec_aouthdr);
-#ifdef KERNELDEBUG
- }
-#endif
-
- text_offset = N_TXTOFF(exec_aouthdr);
- exec_data_offset = N_TXTOFF(exec_aouthdr) + exec_aouthdr.a_text;
-
- text_end = text_start + exec_aouthdr.a_text;
- exec_data_end = exec_data_start + exec_aouthdr.a_data;
-
- fstat(execchan, &st_exec);
- exec_mtime = st_exec.st_mtime;
- }
-
- validate_files();
- } else if (from_tty)
- printf("No exec file now.\n");
-
- /* Tell display code (if any) about the changed file name. */
- if (exec_file_display_hook)
- (*exec_file_display_hook) (filename);
-}
-
-int dummy_code[] = {
- 0xb8909090, /* nop; nop; nop; movl $0x32323232,%eax */
- 0x32323232,
-#define DUMMY_CALL_INDEX 1
- 0x90ccd0ff, /* call %eax; int3; nop */
-};
-
-/*
- * Build `dummy' call instructions on inferior's stack to cause
- * it to call a subroutine.
- *
- * N.B. - code in wait_for_inferior requires that sp < pc < fp when
- * we take the trap 2 above so it will recognize that we stopped
- * at a `dummy' call. So, after the call sp is *not* decremented
- * to clean the arguments, code & other stuff we lay on the stack.
- * Since the regs are restored to saved values at the breakpoint,
- * sp will get reset correctly. Also, this restore means we don't
- * have to construct frame linkage info to save pc & fp. The lack
- * of frame linkage means we can't do a backtrace, etc., if the
- * called function gets a fault or hits a breakpoint but code in
- * run_stack_dummy makes this impossible anyway.
- */
-CORE_ADDR
-setup_dummy(sp, funaddr, nargs, args, struct_return_bytes, pushfn)
- CORE_ADDR sp;
- CORE_ADDR funaddr;
- int nargs;
- value *args;
- int struct_return_bytes;
- CORE_ADDR (*pushfn)();
-{
- int padding, i;
- CORE_ADDR top = sp, struct_addr, pc;
-
- i = arg_stacklen(nargs, args) + struct_return_bytes
- + sizeof(dummy_code);
- if (i & 3)
- padding = 4 - (i & 3);
- else
- padding = 0;
- pc = sp - sizeof(dummy_code);
- sp = pc - padding - struct_return_bytes;
- struct_addr = sp;
- while (--nargs >= 0)
- sp = (*pushfn)(sp, *args++);
- if (struct_return_bytes)
- STORE_STRUCT_RETURN(struct_addr, sp);
- write_register(SP_REGNUM, sp);
-
- dummy_code[DUMMY_CALL_INDEX] = (int)funaddr;
- write_memory(pc, (char *)dummy_code, sizeof(dummy_code));
-
- return pc;
-}
-
-/* helper functions for m-i386.h */
-
-/* stdio style buffering to minimize calls to ptrace */
-static CORE_ADDR codestream_next_addr;
-static CORE_ADDR codestream_addr;
-static unsigned char codestream_buf[sizeof (int)];
-static int codestream_off;
-static int codestream_cnt;
-
-#define codestream_tell() (codestream_addr + codestream_off)
-#define codestream_peek() (codestream_cnt == 0 ? \
- codestream_fill(1): codestream_buf[codestream_off])
-#define codestream_get() (codestream_cnt-- == 0 ? \
- codestream_fill(0) : codestream_buf[codestream_off++])
-
-static unsigned char
-codestream_fill (peek_flag)
-{
- codestream_addr = codestream_next_addr;
- codestream_next_addr += sizeof (int);
- codestream_off = 0;
- codestream_cnt = sizeof (int);
- read_memory (codestream_addr,
- (unsigned char *)codestream_buf,
- sizeof (int));
-
- if (peek_flag)
- return (codestream_peek());
- else
- return (codestream_get());
-}
-
-static void
-codestream_seek (place)
-{
- codestream_next_addr = place & -sizeof (int);
- codestream_cnt = 0;
- codestream_fill (1);
- while (codestream_tell() != place)
- codestream_get ();
-}
-
-static void
-codestream_read (buf, count)
- unsigned char *buf;
-{
- unsigned char *p;
- int i;
- p = buf;
- for (i = 0; i < count; i++)
- *p++ = codestream_get ();
-}
-
-/* next instruction is a jump, move to target */
-static
-i386_follow_jump ()
-{
- int long_delta;
- short short_delta;
- char byte_delta;
- int data16;
- int pos;
-
- pos = codestream_tell ();
-
- data16 = 0;
- if (codestream_peek () == 0x66)
- {
- codestream_get ();
- data16 = 1;
- }
-
- switch (codestream_get ())
- {
- case 0xe9:
- /* relative jump: if data16 == 0, disp32, else disp16 */
- if (data16)
- {
- codestream_read ((unsigned char *)&short_delta, 2);
- pos += short_delta + 3; /* include size of jmp inst */
- }
- else
- {
- codestream_read ((unsigned char *)&long_delta, 4);
- pos += long_delta + 5;
- }
- break;
- case 0xeb:
- /* relative jump, disp8 (ignore data16) */
- codestream_read ((unsigned char *)&byte_delta, 1);
- pos += byte_delta + 2;
- break;
- }
- codestream_seek (pos + data16);
-}
-
-/*
- * find & return amound a local space allocated, and advance codestream to
- * first register push (if any)
- *
- * if entry sequence doesn't make sense, return -1, and leave
- * codestream pointer random
- */
-static long
-i386_get_frame_setup (pc)
-{
- unsigned char op;
-
- codestream_seek (pc);
-
- i386_follow_jump ();
-
- op = codestream_get ();
-
- if (op == 0x58) /* popl %eax */
- {
- /*
- * this function must start with
- *
- * popl %eax 0x58
- * xchgl %eax, (%esp) 0x87 0x04 0x24
- * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
- *
- * (the system 5 compiler puts out the second xchg
- * inst, and the assembler doesn't try to optimize it,
- * so the 'sib' form gets generated)
- *
- * this sequence is used to get the address of the return
- * buffer for a function that returns a structure
- */
- int pos;
- unsigned char buf[4];
- static unsigned char proto1[3] = { 0x87,0x04,0x24 };
- static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
- pos = codestream_tell ();
- codestream_read (buf, 4);
- if (bcmp (buf, proto1, 3) == 0)
- pos += 3;
- else if (bcmp (buf, proto2, 4) == 0)
- pos += 4;
-
- codestream_seek (pos);
- op = codestream_get (); /* update next opcode */
- }
-
- if (op == 0x55) /* pushl %esp */
- {
- /* check for movl %esp, %ebp - can be written two ways */
- switch (codestream_get ())
- {
- case 0x8b:
- if (codestream_get () != 0xec)
- return (-1);
- break;
- case 0x89:
- if (codestream_get () != 0xe5)
- return (-1);
- break;
- default:
- return (-1);
- }
- /* check for stack adjustment
- *
- * subl $XXX, %esp
- *
- * note: you can't subtract a 16 bit immediate
- * from a 32 bit reg, so we don't have to worry
- * about a data16 prefix
- */
- op = codestream_peek ();
- if (op == 0x83)
- {
- /* subl with 8 bit immed */
- codestream_get ();
- if (codestream_get () != 0xec)
- return (-1);
- /* subl with signed byte immediate
- * (though it wouldn't make sense to be negative)
- */
- return (codestream_get());
- }
- else if (op == 0x81)
- {
- /* subl with 32 bit immed */
- int locals;
- codestream_get();
- if (codestream_get () != 0xec)
- return (-1);
- /* subl with 32 bit immediate */
- codestream_read ((unsigned char *)&locals, 4);
- return (locals);
- }
- else
- {
- return (0);
- }
- }
- else if (op == 0xc8)
- {
- /* enter instruction: arg is 16 bit unsigned immed */
- unsigned short slocals;
- codestream_read ((unsigned char *)&slocals, 2);
- codestream_get (); /* flush final byte of enter instruction */
- return (slocals);
- }
- return (-1);
-}
-
-/* Return number of args passed to a frame.
- Can return -1, meaning no way to tell. */
-
-/* on the 386, the instruction following the call could be:
- * popl %ecx - one arg
- * addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
- * anything else - zero args
- */
-
-int
-i386_frame_num_args (fi)
- struct frame_info fi;
-{
- int retpc;
- unsigned char op;
- struct frame_info *pfi;
-
- pfi = get_prev_frame_info ((fi));
- if (pfi == 0)
- {
- /* Note: this can happen if we are looking at the frame for
- main, because FRAME_CHAIN_VALID won't let us go into
- start. If we have debugging symbols, that's not really
- a big deal; it just means it will only show as many arguments
- to main as are declared. */
- return -1;
- }
- else
- {
- retpc = pfi->pc;
- op = read_memory_integer (retpc, 1);
- if (op == 0x59)
- /* pop %ecx */
- return 1;
- else if (op == 0x83)
- {
- op = read_memory_integer (retpc+1, 1);
- if (op == 0xc4)
- /* addl $<signed imm 8 bits>, %esp */
- return (read_memory_integer (retpc+2,1)&0xff)/4;
- else
- return 0;
- }
- else if (op == 0x81)
- { /* add with 32 bit immediate */
- op = read_memory_integer (retpc+1, 1);
- if (op == 0xc4)
- /* addl $<imm 32>, %esp */
- return read_memory_integer (retpc+2, 4) / 4;
- else
- return 0;
- }
- else
- {
- return 0;
- }
- }
-}
-
-/*
- * parse the first few instructions of the function to see
- * what registers were stored.
- *
- * We handle these cases:
- *
- * The startup sequence can be at the start of the function,
- * or the function can start with a branch to startup code at the end.
- *
- * %ebp can be set up with either the 'enter' instruction, or
- * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
- * but was once used in the sys5 compiler)
- *
- * Local space is allocated just below the saved %ebp by either the
- * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
- * a 16 bit unsigned argument for space to allocate, and the
- * 'addl' instruction could have either a signed byte, or
- * 32 bit immediate.
- *
- * Next, the registers used by this function are pushed. In
- * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
- * (and sometimes a harmless bug causes it to also save but not restore %eax);
- * however, the code below is willing to see the pushes in any order,
- * and will handle up to 8 of them.
- *
- * If the setup sequence is at the end of the function, then the
- * next instruction will be a branch back to the start.
- */
-
-i386_frame_find_saved_regs (fip, fsrp)
- struct frame_info *fip;
- struct frame_saved_regs *fsrp;
-{
- unsigned long locals;
- unsigned char *p;
- unsigned char op;
- CORE_ADDR dummy_bottom;
- CORE_ADDR adr;
- int i;
-
- bzero (fsrp, sizeof *fsrp);
-
-#if 0
- /* if frame is the end of a dummy, compute where the
- * beginning would be
- */
- dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH;
-
- /* check if the PC is in the stack, in a dummy frame */
- if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
- {
- /* all regs were saved by push_call_dummy () */
- adr = fip->frame - 4;
- for (i = 0; i < NUM_REGS; i++)
- {
- fsrp->regs[i] = adr;
- adr -= 4;
- }
- return;
- }
-#endif
-
- locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
-
- if (locals >= 0)
- {
- adr = fip->frame - 4 - locals;
- for (i = 0; i < 8; i++)
- {
- op = codestream_get ();
- if (op < 0x50 || op > 0x57)
- break;
- fsrp->regs[op - 0x50] = adr;
- adr -= 4;
- }
- }
-
- fsrp->regs[PC_REGNUM] = fip->frame + 4;
- fsrp->regs[FP_REGNUM] = fip->frame;
-}
-
-/* return pc of first real instruction */
-i386_skip_prologue (pc)
-{
- unsigned char op;
- int i;
-
- if (i386_get_frame_setup (pc) < 0)
- return (pc);
-
- /* found valid frame setup - codestream now points to
- * start of push instructions for saving registers
- */
-
- /* skip over register saves */
- for (i = 0; i < 8; i++)
- {
- op = codestream_peek ();
- /* break if not pushl inst */
- if (op < 0x50 || op > 0x57)
- break;
- codestream_get ();
- }
-
- i386_follow_jump ();
-
- return (codestream_tell ());
-}
-
-i386_pop_frame ()
-{
- FRAME frame = get_current_frame ();
- CORE_ADDR fp;
- int regnum;
- struct frame_saved_regs fsr;
- struct frame_info *fi;
-
- fi = get_frame_info (frame);
- fp = fi->frame;
- get_frame_saved_regs (fi, &fsr);
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- {
- CORE_ADDR adr;
- adr = fsr.regs[regnum];
- if (adr)
- write_register (regnum, read_memory_integer (adr, 4));
- }
- write_register (FP_REGNUM, read_memory_integer (fp, 4));
- write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
- write_register (SP_REGNUM, fp + 8);
- flush_cached_frames ();
- set_current_frame ( create_new_frame (read_register (FP_REGNUM),
- read_pc ()));
-}
-
-/* this table must line up with REGISTER_NAMES in m-i386.h */
-/* symbols like 'EAX' come from <sys/reg.h> */
-static int trapmap[] =
-{
- tEAX, tECX, tEDX, tEBX,
- tESP, tEBP, tESI, tEDI,
- tEIP, tEFLAGS, tCS, tSS,
- tDS, tES, tES, tES /* lies: no fs or gs */
-};
-#if defined(FM_TRAP) || defined(EX_TRAPSTK)
-static int syscallmap[] =
-{
- sEAX, sECX, sEDX, sEBX,
- sESP, sEBP, sESI, sEDI,
- sEIP, sEFLAGS, sCS, sSS,
- sCS, sCS, sCS, sCS /* lies: no ds, es, fs or gs */
-};
-#endif
-static int *regmap;
-
-static void
-setregmap(flags)
- int flags;
-{
-#ifdef FM_TRAP
- regmap = flags & FM_TRAP ? trapmap: syscallmap;
-#elif EX_TRAPSTK
- regmap = flags & EX_TRAPSTK ? trapmap : syscallmap;
-#else
- regmap = trapmap; /* the lesser evil */
-#endif
-}
-
-/* blockend is the value of u.u_ar0, and points to the
- * place where GS is stored
- */
-i386_register_u_addr (blockend, regnum)
-{
-#if 0
- /* this will be needed if fp registers are reinstated */
- /* for now, you can look at them with 'info float'
- * sys5 wont let you change them with ptrace anyway
- */
- if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
- {
- int ubase, fpstate;
- struct user u;
- ubase = blockend + 4 * (SS + 1) - KSTKSZ;
- fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
- return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
- }
- else
-#endif
- return (blockend + 4 * regmap[regnum]);
-}
-
-i387_to_double (from, to)
- char *from;
- char *to;
-{
- long *lp;
- /* push extended mode on 387 stack, then pop in double mode
- *
- * first, set exception masks so no error is generated -
- * number will be rounded to inf or 0, if necessary
- */
- asm ("pushl %eax"); /* grab a stack slot */
- asm ("fstcw (%esp)"); /* get 387 control word */
- asm ("movl (%esp),%eax"); /* save old value */
- asm ("orl $0x3f,%eax"); /* mask all exceptions */
- asm ("pushl %eax");
- asm ("fldcw (%esp)"); /* load new value into 387 */
-
- asm ("movl 8(%ebp),%eax");
- asm ("fldt (%eax)"); /* push extended number on 387 stack */
- asm ("fwait");
- asm ("movl 12(%ebp),%eax");
- asm ("fstpl (%eax)"); /* pop double */
- asm ("fwait");
-
- asm ("popl %eax"); /* flush modified control word */
- asm ("fnclex"); /* clear exceptions */
- asm ("fldcw (%esp)"); /* restore original control word */
- asm ("popl %eax"); /* flush saved copy */
-}
-
-double_to_i387 (from, to)
- char *from;
- char *to;
-{
- /* push double mode on 387 stack, then pop in extended mode
- * no errors are possible because every 64-bit pattern
- * can be converted to an extended
- */
- asm ("movl 8(%ebp),%eax");
- asm ("fldl (%eax)");
- asm ("fwait");
- asm ("movl 12(%ebp),%eax");
- asm ("fstpt (%eax)");
- asm ("fwait");
-}
-
-struct env387
-{
- unsigned short control;
- unsigned short r0;
- unsigned short status;
- unsigned short r1;
- unsigned short tag;
- unsigned short r2;
- unsigned long eip;
- unsigned short code_seg;
- unsigned short opcode;
- unsigned long operand;
- unsigned short operand_seg;
- unsigned short r3;
- unsigned char regs[8][10];
-};
-
-static
-print_387_control_word (control)
-unsigned short control;
-{
- printf ("control 0x%04x: ", control);
- printf ("compute to ");
- switch ((control >> 8) & 3)
- {
- case 0: printf ("24 bits; "); break;
- case 1: printf ("(bad); "); break;
- case 2: printf ("53 bits; "); break;
- case 3: printf ("64 bits; "); break;
- }
- printf ("round ");
- switch ((control >> 10) & 3)
- {
- case 0: printf ("NEAREST; "); break;
- case 1: printf ("DOWN; "); break;
- case 2: printf ("UP; "); break;
- case 3: printf ("CHOP; "); break;
- }
- if (control & 0x3f)
- {
- printf ("mask:");
- if (control & 0x0001) printf (" INVALID");
- if (control & 0x0002) printf (" DENORM");
- if (control & 0x0004) printf (" DIVZ");
- if (control & 0x0008) printf (" OVERF");
- if (control & 0x0010) printf (" UNDERF");
- if (control & 0x0020) printf (" LOS");
- printf (";");
- }
- printf ("\n");
- if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
- control & 0xe080);
-}
-
-static
-print_387_status_word (status)
- unsigned short status;
-{
- printf ("status 0x%04x: ", status);
- if (status & 0xff)
- {
- printf ("exceptions:");
- if (status & 0x0001) printf (" INVALID");
- if (status & 0x0002) printf (" DENORM");
- if (status & 0x0004) printf (" DIVZ");
- if (status & 0x0008) printf (" OVERF");
- if (status & 0x0010) printf (" UNDERF");
- if (status & 0x0020) printf (" LOS");
- if (status & 0x0040) printf (" FPSTACK");
- printf ("; ");
- }
- printf ("flags: %d%d%d%d; ",
- (status & 0x4000) != 0,
- (status & 0x0400) != 0,
- (status & 0x0200) != 0,
- (status & 0x0100) != 0);
-
- printf ("top %d\n", (status >> 11) & 7);
-}
-
-static
-print_387_status (status, ep)
- unsigned short status;
- struct env387 *ep;
-{
- int i;
- int bothstatus;
- int top;
- int fpreg;
- unsigned char *p;
-
- bothstatus = ((status != 0) && (ep->status != 0));
- if (status != 0)
- {
- if (bothstatus)
- printf ("u: ");
- print_387_status_word (status);
- }
-
- if (ep->status != 0)
- {
- if (bothstatus)
- printf ("e: ");
- print_387_status_word (ep->status);
- }
-
- print_387_control_word (ep->control);
- printf ("last exception: ");
- printf ("opcode 0x%x; ", ep->opcode);
- printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
- printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
-
- top = (ep->status >> 11) & 7;
-
- printf (" regno tag msb lsb value\n");
- for (fpreg = 7; fpreg >= 0; fpreg--)
- {
- int st_regno;
- double val;
-
- /* The physical regno `fpreg' is only relevant as an index into the
- * tag word. Logical `%st' numbers are required for indexing `p->regs.
- */
- st_regno = (fpreg + 8 - top) & 0x7;
-
- printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
-
- switch ((ep->tag >> (fpreg * 2)) & 3)
- {
- case 0: printf ("valid "); break;
- case 1: printf ("zero "); break;
- case 2: printf ("trap "); break;
- case 3: printf ("empty "); break;
- }
- for (i = 9; i >= 0; i--)
- printf ("%02x", ep->regs[st_regno][i]);
-
- i387_to_double (ep->regs[st_regno], (char *)&val);
- printf (" %g\n", val);
- }
-#if 0 /* reserved fields are always 0xffff on 486's */
- if (ep->r0)
- printf ("warning: reserved0 is 0x%x\n", ep->r0);
- if (ep->r1)
- printf ("warning: reserved1 is 0x%x\n", ep->r1);
- if (ep->r2)
- printf ("warning: reserved2 is 0x%x\n", ep->r2);
- if (ep->r3)
- printf ("warning: reserved3 is 0x%x\n", ep->r3);
-#endif
-}
-
-#ifdef __386BSD__
-#define fpstate save87
-#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
-#endif
-
-#ifndef U_FPSTATE
-#define U_FPSTATE(u) u.u_fpstate
-#endif
-
-i386_float_info ()
-{
- struct user u; /* just for address computations */
- int i;
- /* fpstate defined in <sys/user.h> */
- struct fpstate *fpstatep;
- char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
- unsigned int uaddr;
- char fpvalid;
- unsigned int rounded_addr;
- unsigned int rounded_size;
- extern int corechan;
- int skip;
-
-#ifndef __386BSD__ /* XXX - look at pcb flags */
- uaddr = (char *)&u.u_fpvalid - (char *)&u;
- if (have_inferior_p())
- {
- unsigned int data;
- unsigned int mask;
-
- rounded_addr = uaddr & -sizeof (int);
- data = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
- mask = 0xff << ((uaddr - rounded_addr) * 8);
-
- fpvalid = ((data & mask) != 0);
- }
- else
- {
- if (lseek (corechan, uaddr, 0) < 0)
- perror ("seek on core file");
- if (myread (corechan, &fpvalid, 1) < 0)
- perror ("read on core file");
-
- }
-
- if (fpvalid == 0)
- {
- printf ("no floating point status saved\n");
- return;
- }
-#endif /* not __386BSD__ */
-
- uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
- if (have_inferior_p ())
- {
- int *ip;
-
- rounded_addr = uaddr & -sizeof (int);
- rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
- sizeof (int) - 1) / sizeof (int);
- skip = uaddr - rounded_addr;
-
- ip = (int *)buf;
- for (i = 0; i < rounded_size; i++)
- {
- *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
- rounded_addr += sizeof (int);
- }
- }
- else
- {
- if (lseek (corechan, uaddr, 0) < 0)
- perror_with_name ("seek on core file");
- if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
- perror_with_name ("read from core file");
- skip = 0;
- }
-
-#ifdef __386BSD__
- print_387_status (0, (struct env387 *)buf);
-#else
- fpstatep = (struct fpstate *)(buf + skip);
- print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
-#endif
-}
-
-void
-_initialize_i386bsd_dep()
-{
-#ifdef KERNELDEBUG
- add_com ("process-address", class_obscure, set_paddr_command,
- "The process identified by (ps-style) ADDR becomes the\n\
-\"current\" process context for kernel debugging.");
- add_com_alias ("paddr", "process-address", class_obscure, 0);
-#endif
-}
diff --git a/gnu/usr.bin/gdb/doc/ChangeLog b/gnu/usr.bin/gdb/doc/ChangeLog
new file mode 100644
index 000000000000..fb867193a4aa
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/ChangeLog
@@ -0,0 +1,783 @@
+Tue Oct 19 14:21:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Sourc Path): index entries for $cwd, $pdir
+
+ * a4rc.sed: update to work with Andreas Vogel papersize params
+
+ * refcard.tex: use Andreas Vogel simplifications of papersize
+ params; remove useless version info; update copyright date.
+
+Tue Oct 19 10:46:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Symbols): Add class NAME to doc for ptype.
+
+Tue Oct 12 09:11:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Files): Say what address the load command loads it at.
+
+ * stabs.texinfo (Common Blocks): Minor cleanups.
+
+ * stabs.texinfo: Update ld stabs in elf relocation to reflect the fact
+ that Sun has backed away from the linker kludge and thus the relevant
+ issue is changes to the SunPRO tools, not the Solaris linker.
+
+ * stabs.texinfo (Traditional Integer Types): Clean up description
+ of octal bounds a little bit. Document extra leading zeroes.
+
+Thu Oct 7 16:15:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Signaling): Update for symbolic symbol names
+ and add a section explaining the difference between the GDB
+ signal command and the shell kill utility.
+
+Wed Oct 6 13:23:01 1993 Tom Lord (lord@rtl.cygnus.com)
+
+ * libgdb.texinfo: added `@' to braces that were unescaped.
+
+Mon Oct 4 10:42:18 1993 Tom Lord (lord@rtl.cygnus.com)
+
+ * libgdb.texinfo: new file. Spec for the gdb library.
+
+Sun Oct 3 15:26:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Include Files): Fix typo (start -> end).
+
+Thu Sep 30 18:24:56 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, remote.texi: assorted small improvements, mostly
+ from Melissa at FSF's editing pass.
+
+Thu Sep 30 11:54:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo: Remove stuff about ar and 14 character filenames.
+ I believe this was fixed by the 13 Sep 89 change to print_frame_info.
+ Also, modern versions of ar like BSD 4.4 or SVR4 don't have this bug.
+
+Wed Sep 22 21:22:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * remote.texi (Bootstrapping): Discuss 386 call gates.
+
+Sat Sep 18 17:10:44 1993 Jim Kingdon (kingdon@poseidon.cygnus.com)
+
+ * stabs.texinfo (Based Variables): New node.
+
+Thu Sep 16 17:48:55 1993 Jim Kingdon (kingdon@cirdan.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Re-write discussions of
+ names, sizes, and formats to suggest how not to lose.
+
+Sat Sep 11 09:35:11 1993 Jim Kingdon (kingdon@poseidon.cygnus.com)
+
+ * stabs.texinfo (Methods): Fix typo.
+
+Fri Sep 10 06:34:20 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * gdb.texinfo: Fix a few typos.
+
+Wed Sep 8 09:11:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo: Clarify how well it works with Fortran.
+
+ * stabs.texinfo (Stabs In ELF, Statics, ELF Transformations):
+ More on relocating stabs in ELF files.
+
+Tue Sep 7 13:45:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs In ELF): Talk about N_FUN value.
+
+Mon Sep 6 19:23:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Local Variable Parameters): Talk about nameless
+ parameters on VAX.
+
+Fri Sep 3 17:06:08 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: @up/@down -> @raisesections/@lowersections
+
+Fri Sep 3 12:04:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Make info author notice match the TeX author notice.
+
+Tue Aug 31 13:21:06 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * stabs.texinfo: Initial-caps all words in node names and
+ non-trivial words in section names.
+
+Mon Aug 30 11:13:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Many minor cleanups.
+
+ * stabs.texinfo: Remove @deffn except from Expanded Reference node.
+
+Sat Aug 28 12:08:09 1993 David J. MacKenzie (djm@edison.eng.umd.edu)
+
+ * stabs.texinfo: Remove full description of big example.
+ It's not really helpful; just use pieces of it where appropriate.
+ Add more Texinfo formatting directives (@samp, etc.).
+ Use @deffn to define stab types.
+ Eliminate some wordiness. Break up some nodes.
+ Add an (alphabetized) index of symbol types.
+ Use consistent capitalization style in node and section names.
+
+Thu Aug 26 06:36:31 1993 Fred Fish (fnf@deneb.cygnus.com)
+
+ * gdb.texinfo: Change typo "Two two" to "The two".
+
+Sun Aug 22 12:15:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (XCOFF-differences): Remove references to
+ non-existent types N_DECL and N_RPSYM.
+
+ * stabs.texinfo (String Field): Say that type attributes bug is
+ fixed in GDB 4.10, since it is.
+
+ * stabs.texinfo: Clean up djm cleanups, and more cleanups of my own.
+
+Sat Aug 21 04:32:28 1993 David MacKenzie (djm@cygnus.com)
+
+ * stabs.texinfo: Formatting cleanups.
+
+Fri Aug 20 20:49:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: When explaining the n_type of a stab, standardize
+ how we do it ('#' as a comment indicator, "36 is N_FUN" as text,
+ no tabs, use @r).
+ (Global Variables): Clean up.
+
+Tue Aug 17 15:57:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stack Variables): Re-write.
+
+Mon Aug 16 21:20:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs-in-elf): Talk about getting the start
+ addresses of a source file. Also revise formatting.
+ Change "object module" or "object file" to "source file".
+ Various: Miscellaneous cleanups.
+
+Thu Aug 12 15:11:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Point to mangling info in gcc's gpcompare.texi.
+
+Tue Aug 10 16:57:49 1993 Stan Shebs (shebs@rtl.cygnus.com)
+
+ * gdbint.texinfo: Removed many nonsensical machine-collected
+ host and target conditionals, described some of the remainder.
+
+Tue Aug 10 13:28:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdbint.texinfo (Getting Started): Use @itemize, not @table.
+
+ * gdbint.texinfo (Top): Add name to @top line, and re-write the
+ paragraph which follows.
+
+ * gdbint.texinfo (Host): Use @code not @samp for Makefile
+ variables. Looks better and avoids overful hbox.
+
+Fri Jul 30 18:26:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Procedures): Improve stuff on nested functions.
+
+Thu Jul 29 15:10:58 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * remote.texi: (MIPS Remote) clearer doc for set/show timeout,
+ retransmit-timeout
+
+Thu Jul 29 13:16:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdbint.texinfo: Update statement about `some ancient Unix
+ systems, like Ultrix 4.0' to Ultrix 4.2.
+
+Wed Jul 28 15:26:53 1993 Roland H. Pesch (pesch@el_bosque.cygnus.com)
+
+ * h8-cfg.texi, all-cfg.texi: new flag GDBSERVER
+
+ * Makefile.in: depend on remote.texi rather than gdbinv-s.texi
+
+ * remote.texi: (Server) New node on gdbserver. (Remote Serial,
+ ST2000 Remote, MIPS Remote): mention `host:port' syntax for TCP.
+
+ * remote.texi: new name for former gdbinv-s.texi
+
+ * gdb.texinfo: use remote.texi rather than gdbinv-s.texi
+
+Wed Jul 28 08:26:24 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * gdbinv-s.texi: Documented timeout and retransmit-timeout
+ variables for MIPS remote debugging protocol.
+
+Mon Jul 26 13:00:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): FORTRAN LOGICAL fix.
+
+Tue Jul 20 16:30:41 1993 Jim Kingdon (kingdon@deneb.cygnus.com)
+
+ * Makefile.in (refcard.dvi): Use srcdir where necessary.
+
+Mon Jul 19 12:02:50 1993 Roland H. Pesch (pesch@cygnus.com)
+
+ * gdb.texinfo: repair conditional bugs in text markup
+
+Fri Jul 16 18:57:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, all-cfg.texi, h8-cfg.texi: introduce MOD2 switch
+ to select Modula-2 material.
+
+Thu Jul 15 13:15:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Cleanups regarding statics.
+
+ * gdbinv-s.texi (Bootstrapping): Document exceptionHandler.
+ (Debug Session): Mention exceptionHandler. Add xref to Bootstrapping.
+
+Mon Jul 12 13:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: N_MAIN is sometimes used for C.
+
+Fri Jul 9 09:47:02 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * gdbint.texinfo (Host, Target Conditionals): Remove TM_FILE_OVERRIDE.
+
+Tue Jul 6 12:41:28 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo (Target Conditionals): Remove NO_TYPEDEFS,
+ removed from the code by Kingdon.
+
+Tue Jul 6 12:24:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Break Commands): Remove stuff about flushing terminal
+ input when evaluating breakpoint conditions; the bug has been fixed.
+
+ * gdb.texinfo (Continuing and Stepping): Argument to "continue"
+ sets the ignore count to N-1, not to N.
+
+Thu Jul 1 14:57:42 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * refcard.tex (\hoffset): correct longstanding error to match
+ intended offset; avoids cutting off edge on some printers
+
+Wed Jun 30 18:23:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Parameters): Say that order of stabs is significant.
+
+Fri Jun 25 21:34:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Common Blocks): Say what Sun FORTRAN does.
+
+Fri Jun 25 16:15:10 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * Makefile.in: (REFEDITS) new var to control whether PS or CM
+ fonts and whether US or A4 paper for GDB refcard; (refcard.dvi)
+ collect sed edits if any, apply to refcard before formatting;
+ (refcard.ps) stop implying PS fonts if PS output requested;
+ (lrefcard.ps) delete extra target for variant PS fonts
+
+ * refcard.tex: parametrize papersize dependent info, collect
+ in easily replaced spot
+
+ * a4rc.sed: new file, edits to refcard for A4 paper
+
+Fri Jun 25 14:21:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Type -16 is 4 bytes.
+
+Wed Jun 23 15:02:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Minor character cleanups.
+
+Tue Jun 22 16:31:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Express disapproval of 'D' symbol descriptor
+ politely rather than rudely.
+
+Fri Jun 18 19:42:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Document common blocks.
+
+Fri Jun 18 12:12:57 1993 Fred Fish (fnf@cygnus.com)
+
+ * stabs.texinfo: Add some basic info about stabs-in-elf.
+
+Fri Jun 18 13:57:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Top): Minor cleanup.
+
+Mon Jun 14 16:16:51 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com)
+
+ * Makefile.in (install-info): remove parentdir support
+
+Tue Jun 15 18:11:39 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Copying): delete this node and references to it;
+ RMS says this manual need not carry GPL. (passim): Improvements
+ from last round at FSF, largely due to Ian Taylor review, and
+ minor formatting improvements.
+
+ * gdbinv-s.texi (passim): Improvements from last round at FSF,
+ largely due to Ian Taylor review. (Debug Session): minor edits to
+ new text.
+
+Sun Jun 13 12:52:39 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * Makefile.in (realclean): Remove info and dvi files too.
+
+Sat Jun 12 16:09:22 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * {all,h8}-config.texi: Rename to *-cfg.texi for 14 char filenames.
+ * Makefile.in: Change accordingly. gdb-config.texi -> gdb-cfg.texi.
+ * gdb.texinfo: Change accordingly.
+
+ * stabs.texinfo: Clean up N_{L,R}BRAC. Discuss what addresses of
+ N_{L,R}BRAC,N_SLINE are relative to.
+
+Fri Jun 11 15:15:55 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * Makefile.in (GDBvn.texi): Update atomically.
+
+Wed Jun 9 10:58:16 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbinv-s.texi (Debug Session): Document exceptionHook.
+
+Tue Jun 8 13:42:04 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdb.texinfo (Print Settings): Move all stuff relating to symbolic
+ addresses together. Also motivate the set print symbol-filename
+ command and suggest other solutions.
+
+Tue Jun 1 22:46:43 1993 Fred Fish (fnf@cygnus.com)
+
+ * gdb.texinfo (set print elements): Note that the number of
+ elements is set to unlimited by "set print elements 0".
+
+Mon May 31 08:06:55 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Builtin Type Descriptors): Try to clarify what
+ NF_LDOUBLE means.
+ (Stab Types): Include Solaris stab types.
+ (Procedures): Document Solaris extensions.
+
+Thu May 27 06:20:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * gdb.texinfo: Add `set print symbol-filename' doc.
+
+Wed May 26 00:26:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Arrays): Talk about type definition vs. type
+ information.
+
+ * stabs.texinfo (Builtin Type Descriptors): Talk about omitting
+ the trailing semicolon.
+
+Tue May 25 14:49:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Line Numbers, Source Files): Re-write these two nodes
+ and merge in other parts of the document addressing these subjects.
+ gdbint.texinfo (XCOFF): Remove info which is now in stabs.texinfo.
+
+ * stabs.texinfo (Subranges, Arrays): Try to explain about the semicolon
+ at the end of a range type.
+
+ * stabs.texinfo (Subranges): "A offset" and "T offset" are not
+ AIX extensions.
+
+Mon May 24 09:00:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs Format): Misc fixes.
+
+Sat May 22 10:40:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Constants): Allow an `e' constant to be non-enum.
+ (Traditional builtin types): Document convex convention for long long.
+ (Negative builtin types): Discuss type names, and misc fixes.
+
+Fri May 21 11:20:31 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Builtin Type Descriptors): Document the floating
+ point types used with @samp{R} type descriptor.
+ (Symbol Descriptors): Describe how to handle conflict between
+ different meanings of @samp{P} symbol descriptor.
+
+Thu May 20 13:35:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Remove node Quick Reference and put its children
+ directly under the main menu.
+
+ * stabs.texinfo: Many more changes to bring it into line with
+ AIX documentation and reality. I think it now has all the
+ information from the AIX documentation, except that I burned
+ out when I got to variant records (Pascal and Modula-2) and
+ all the COBOL types. Oh well, we can add them later when we're
+ worrying more about those languages.
+
+ * stabs.texinfo (Automatic variables): Talk about what it means
+ to omit the symbol descriptor.
+
+Tue May 18 17:59:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Parameters): Add "(sometimes)" when describing
+ gcc2 behavior with promoted args.
+
+Fri May 14 21:35:29 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: include readline appendices in info version of manual
+
+Fri May 7 11:56:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi (Remote Serial): describe new ^C behavior in
+ target remote.
+
+ * gdb.texinfo (Machine Code): more index entries for disassemble
+
+Fri May 7 10:12:30 1993 Fred Fish (fnf@cygnus.com)
+
+ * Clarify the intended use of the gdb-testers and gdb-patches
+ mailing lists, and shrink gzip comment.
+
+Thu May 6 16:39:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Shell Commands): do not mention SHELL env var in
+ DOSHOST configuration of manual.
+
+ * gdb.texinfo (MIPS Stack): new node.
+
+ * all-config.texi (MIPS) new switch.
+
+ * gdbinv-s.texi (Nindy Options) Remove two instances of future
+ tense; (MIPS Remote) new node.
+
+ * gdb.texinfo (passim) rephrases to work around makeinfo @value
+ bug; (Environment) less passive, other small cleanups in text about
+ .cshrc/.bashrc; (Invoking GDB) new MIPS Remote menu entry;
+ (Remote) new MIPS Remote menu entry.
+
+Thu Apr 29 09:36:25 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Many changes to include information from the
+ AIX documentation.
+
+ * gdb.texinfo (Environment): Mention pitfall with .cshrc.
+
+Tue Apr 27 14:02:57 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbint.texinfo (new node Debugging GDB, elsewhere):
+ Move a bunch of information from ../README.
+ (Getting Started): New node.
+
+Fri Apr 23 17:21:13 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi, gdb.texinfo: include Hitachi SH target
+
+ * gdb.texinfo: advance manual revision dates to present
+
+ * gdbinv-s.texi, gdb.texinfo, all-config.texi, h8-config.texi:
+ stop using silly Roman numerals in @set variable names
+
+Fri Apr 23 07:30:01 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): Keep trying to get this right.
+
+Wed Apr 21 15:18:47 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): More on "local parameters".
+
+Mon Apr 19 08:00:51 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): Re-do "local parameters" section.
+
+Sun Apr 18 09:47:45 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Symbol descriptors): Re-do using @table and @xref.
+ (Parameters): Rewrite.
+ (xcoff-differences, Sun-differences): Minor changes.
+
+Thu Apr 15 02:35:24 1993 John Gilmore (gnu@cacophony.cygnus.com)
+
+ * stabs.texinfo: Minor cleanup.
+
+Wed Apr 14 17:31:00 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbint.texinfo: Minor xcoff stuff.
+
+Wed Apr 7 14:11:07 1993 Fred Fish (fnf@cygnus.com)
+
+ * gdbint.texinfo: Update for new config directory structure.
+ Add info about internal type data structures.
+
+Mon Apr 5 09:06:30 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * Makefile.in (SFILES_INCLUDED): gdb-config.texi is no longer in
+ $(srcdir).
+ (gdb-config.texi): Depend on file in $(srcdir).
+
+Fri Apr 2 16:55:13 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Fixes about N_SO.
+
+Fri Mar 26 18:00:35 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: include list of nonstandard init file names
+
+ * *-config.texi: new switch GENERIC for text that applies *only*
+ to (usual) multiple-target version of manual
+
+ * gdb.texinfo, gdbinv-s.texi: Update conditional markup to correct
+ h8 config
+
+ * gdb.texinfo: depend on latest fixed makeinfo, use conditionals
+ in menus (rather than conditionally selected multiple alternative
+ menus).
+
+ * Makefile.in: define and use DOC_CONFIG var to select
+ configuration for GDB user manual.
+
+ * gdb-config.texi: delete from repository, generate from Makefile.
+
+ * all-config.texi: normal `generic' configuration file, formerly
+ stored as gdb-config.texi
+
+Wed Mar 24 14:03:19 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com)
+
+ * Makefile.in: add dvi target to build all .dvi files
+
+Tue Mar 23 16:03:24 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdvinv-s.texinfo: formatting improvements.
+
+Fri Mar 19 21:46:50 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Doc NO_MMALLOC and NO_MMALLOC_CHECK as
+ host conditionals.
+ * stabs.texinfo: More array fixes inspired by Jim's.
+
+Fri Mar 19 10:23:34 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Fixes re arrays and continuations.
+
+ * gdbint.texinfo: Add XCOFF node.
+
+Mon Mar 8 15:52:18 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Add `set print max-symbolic-offset' doc.
+
+Sun Feb 21 17:09:38 1993 Per Bothner (bothner@rtl.cygnus.com)
+
+ * stabs.texinfo: Fix for array types to mention lower bounds.
+
+Thu Feb 18 01:19:49 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Update PTRACE_ARG3_TYPE doc, pull PT_*.
+
+Wed Feb 17 08:15:24 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Remove SET_STACK_LIMIT_HUGE from target defines.
+
+Thu Feb 11 10:38:40 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Fix thinko (NM_FILE => NAT_FILE). Found
+ by Michael Ben-Gershon <mybg@CS.HUJI.AC.IL>.
+
+Wed Feb 10 23:59:19 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Eliminate IBM6000_HOST, document IBM6000_TARGET.
+
+Tue Feb 9 18:26:21 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdbinv-s.texi: misc updates
+
+Sat Feb 6 10:25:47 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Brief documentation for longjmp support,
+ from an email msg by Stu.
+
+Fri Feb 5 14:10:15 1993 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Fix description of floating point "range"
+ types (which really define basic types). Reported by Jim Meehan,
+ <meehan@src.dec.com>.
+
+ * gdbint.texinfo: Remove COFF_NO_LONG_FILE_NAMES define, now gone.
+
+Thu Feb 4 13:56:46 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * gdbint.texinfo: Slightly expand section on supporting a new
+ object file format.
+
+Thu Feb 4 01:49:04 1993 John Gilmore (gnu@cygnus.com)
+
+ * Makefile.in (refcard.ps, lrefcard.ps): Remove psref.tex
+ intermediate file.
+
+Tue Feb 2 12:18:06 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdbinv-s.texi: miscellaneous stylistic cleanups
+
+Mon Feb 1 15:35:47 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi: z8000 simulator target name is just "sim"
+
+ * gdbinv-s.texi: Mention that Z8000 simulator can simulate Z8001
+ as well as Z8002.
+
+Sat Nov 28 06:51:35 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add sections on clean design and on how to send
+ in changes.
+
+Mon Nov 9 23:57:02 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add how to declare the result of make_cleanup.
+
+Mon Oct 26 11:09:47 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Fix typo, reported by Karl Berry.
+
+Fri Oct 23 00:41:21 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Add opcodes dir to GDB distribution description.
+
+Sat Oct 10 18:04:58 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * gdbint.texinfo: fixed a stray email address (needs @@),
+ added @table @code to node "Native Conditionals"
+
+Tue Sep 22 00:34:15 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Describe coding style of GDB.
+
+Mon Sep 21 19:32:16 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Minor wording changes.
+
+Tue Sep 15 02:57:09 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Improve release doc slightly.
+
+Fri Sep 11 01:34:25 1992 John Gilmore (gnu@sphagnum.cygnus.com)
+
+ * gdbint.texinfo: Improve doc of GDB config macros.
+
+Wed Sep 9 16:52:06 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Remove Bothner's changes for C++ nested types.
+ These will be reinserted when examined.
+
+Mon Aug 24 01:17:55 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Make a start at documenting all the #if macros
+ in GDB. At least list them all, and start separating them into
+ host-specific and target-specific.
+
+Tue Aug 18 15:59:13 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.m4.in: refrain from using @cartouche for just a few
+ examples (not consistent w others).
+ gdb.texinfo: issue disclaimer paragraph on cmdline options only
+ for generic vn of doc
+
+Tue Aug 18 14:53:27 1992 Ian Lance Taylor (ian@cygnus.com)
+
+ * Makefile.in: always create installation directories.
+
+Tue Aug 18 14:11:50 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: in h8 config, do not describe searching commands.
+
+Mon Aug 17 18:07:59 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, none.m4, h8.m4, gdbinv-s.m4.in: improve H8/300
+ conditionals; introduce a few generic switches that may be
+ useful for other cross-dev or dos-hosted configs.
+
+ * gdb.texinfo: fix typo in "info reg" description
+
+Sun Aug 16 01:16:18 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Minor updates from running TeX over it.
+ * Makefile.in (stabs.dvi, stabs.ps): Add.
+
+Sat Aug 15 20:52:24 1992 Per Bothner (bothner@rtl.cygnus.com)
+
+ * stabs.texinfo: Stabs documentation, written by Julia Menapace.
+ First pass at converting it to texinfo.
+
+Sat Aug 15 03:14:59 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo, refcard.tex: Document mult args on `info reg'.
+ * Makefile.in (refcard.ps, lrefcard.ps): Add missing $(srdir).
+
+Fri Aug 14 21:08:47 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add section on partial symbol tables.
+
+Sat Jun 20 16:31:10 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: document `set remotedebug' and `set
+ rstack_high_address'.
+
+Thu May 14 17:09:48 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: slight expansion of new text on reading info files
+ * gdbinv-s.m4.in: correct and expand info on cross-debugging
+ H8/300 from DOS.
+
+Tue May 12 12:22:47 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: `info user' => `show user'. Noticed by David Taylor.
+
+Mon May 11 19:06:27 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: Say how to read the `info' files.
+
+Tue May 5 12:11:38 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in: gm4 -> m4.
+
+Fri Apr 10 17:50:43 1992 John Gilmore (gnu at rtl.cygnus.com)
+
+ * gdb.texinfo: Update for GDB-4.5. Move `Formatting
+ Documentation' ahead of `Installing GDB' to match README.
+ Update shared library doc, -readnow and -mapped, and directory
+ structure (add glob and mmalloc). Update configure doc.
+
+Tue Mar 24 23:28:38 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in: remove $(srcdir) from gdb.info rule.
+
+Sat Mar 7 18:44:50 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in: commented out gdb-all.texinfo rule. This is
+ temporary.
+
+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.
+
+Fri Dec 13 09:47:31 1991 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: Improve how we ask for bug reports.
+
+Tue Dec 10 04:07:21 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: infodir belongs in datadir.
+
+Fri Dec 6 23:57:34 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: remove spaces following hyphens, bsd make can't
+ cope. install using INSTALL_DATA. added clean-info. added
+ standards.text support.
+
+Thu Dec 5 22:46:12 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.
+
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gnu/usr.bin/gdb/doc/Makefile b/gnu/usr.bin/gdb/doc/Makefile
new file mode 100644
index 000000000000..8cde5d4b5350
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/Makefile
@@ -0,0 +1,340 @@
+# This file was generated automatically by configure. Do not edit.
+VPATH = .
+links =
+host_alias = i386-unknown-freebsd
+host_cpu = i386
+host_vendor = unknown
+host_os = freebsd
+host_canonical = i386-unknown-freebsd
+target_alias = i386-unknown-freebsd
+target_cpu = i386
+target_vendor = unknown
+target_os = freebsd
+target_canonical = i386-unknown-freebsd
+##Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+# Makefile for GDB documentation.
+# This file is part of GDB.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = .
+
+prefix = /usr/gnu
+
+infodir = $(prefix)/info
+
+SHELL = /bin/sh
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+# main GDB source directory
+gdbdir = $(srcdir)/..
+
+# where to find texinfo; GDB dist should include a recent one
+TEXIDIR=${gdbdir}/../texinfo
+
+# where to find makeinfo, preferably one designed for texinfo-2
+MAKEINFO=makeinfo
+
+# where to find texi2roff, ditto
+TEXI2ROFF=texi2roff
+
+# Where is the source dir for the READLINE library doc?
+# Traditionally readline is in .. or .
+READLINE_DIR = ${gdbdir}/../readline/doc
+
+SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS
+
+# There may be alternate predefined collections of switches to configure
+# the GDB manual. Normally this is not done in synch with the software
+# config system, since this choice tends to be independent; most people
+# want a doc config of `all' for a generic manual, regardless of sw config.
+DOC_CONFIG = all
+
+# This list of sed edits will edit the GDB reference card
+# for what fonts and what papersize to use.
+# By default (NO edits applied), the refcard uses:
+# - Computer Modern (CM) fonts
+# - US letter paper (8.5x11in)
+# List some of the following files for alternative fonts and paper:
+# a4rc.sed use A4 paper (297 x 210 mm)
+# psrc.sed use PostScript fonts (Karl Berry short TeX names)
+# lpsrc.sed use PostScript fonts (full PostScript names in TeX)
+# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed
+# for A4, CM fonts: REFEDITS = a4rc.sed
+# for US, PS fonts: REFEDITS = psrc.sed
+# for default:
+REFEDITS =
+
+# Don Knuth's TeX formatter
+TEX = tex
+
+# auxiliary program for sorting Texinfo indices
+TEXINDEX = texindex
+
+# Main GDB manual's source files
+SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi
+
+SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED)
+
+SFILES_DOC = $(SFILES_LOCAL) \
+ $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi
+
+#### Host, target, and site specific Makefile fragments come in here.
+###
+
+all install:
+
+info: gdb.info gdbint.info stabs.info
+dvi: gdb.dvi refcard.dvi gdbint.dvi
+all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi
+
+install-info: info
+ for i in *.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+STAGESTUFF = *.info* gdb-all.texi GDBvn.texi
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ -(cd stage1 ; mv -f * ..)
+ -rmdir stage1
+
+de-stage2: force
+ -(cd stage2 ; mv -f * ..)
+ -rmdir stage2
+
+de-stage3: force
+ -(cd stage3 ; mv -f * ..)
+ -rmdir stage3
+
+clean-info:
+ rm -f gdb.info* gdbint.info* stabs.info*
+
+clean-dvi:
+ rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi
+
+mostlyclean: clean-info clean-dvi
+ rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me
+ rm -f links2roff
+ rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~
+ rm -f gdbint.?? gdbint.??? stabs.?? stabs.???
+
+clean: mostlyclean
+ rm -f GDBvn.texi rluser.texinfo inc-hist.texi
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean clean-dvi clean-info
+
+# GDB QUICK REFERENCE (dvi output)
+refcard.dvi : refcard.tex $(REFEDITS)
+ if [ -z "$(REFEDITS)" ]; then \
+ cp $(srcdir)/refcard.tex sedref.tex ; \
+ else \
+ echo > tmp.sed ; \
+ for f in "$(REFEDITS)" ; do \
+ cat $(srcdir)/$$f >>tmp.sed ; done ; \
+ sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \
+ fi
+ $(SET_TEXINPUTS) $(TEX) sedref.tex
+ mv sedref.dvi refcard.dvi
+ rm -f sedref.log sedref.tex tmp.sed
+
+refcard.ps : refcard.dvi
+ dvips -t landscape refcard.dvi -o
+
+# File to record current GDB version number (copied from main dir Makefile.in)
+GDBvn.texi : ${gdbdir}/Makefile.in
+ echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new
+ mv GDBvn.new GDBvn.texi
+
+# Updated atomically
+.PRECIOUS: GDBvn.texi
+
+# Choose configuration for GDB manual (normally `all'; normally not tied into
+# `configure' script because most users prefer generic version of manual,
+# not one for their binary config---which may not be specifically
+# defined anyways).
+gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi
+ ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi
+
+# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear
+# If your texinfo or makeinfo don't support these, get a new texinfo release
+#
+# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make.
+# Note that we can *generate* GDBvn.texi, but since we distribute one in the
+# source directory for the benefit of people who *don't* use this makefile,
+# VPATH will often tell make not to bother building it, because the one
+# in the srcdir is up to date. (if not, then make should build one here).
+
+# GDB MANUAL: TeX dvi file
+gdb.dvi: ${SFILES_DOC}
+ if [ ! -f ./GDBvn.texi ]; then \
+ ln -s $(srcdir)/GDBvn.texi . || \
+ ln $(srcdir)/GDBvn.texi . || \
+ cp $(srcdir)/GDBvn.texi . ; else true; fi
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(TEXINDEX) gdb.??
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s
+
+# GDB MANUAL: info file
+# We're using texinfo2, and older makeinfo's may not be able to
+# cope with all the markup.
+gdb.info: ${SFILES_DOC}
+ $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo
+
+# GDB MANUAL: roff translations
+# Try to use a recent texi2roff. v2 was put on prep in jan91.
+# If you want an index, see texi2roff doc for postprocessing
+# and add -i to texi2roff invocations below.
+# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete
+# corresponding -e lines when later texi2roff's are current)
+# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs.
+# + @c's deleted explicitly because texi2roff sees texinfo commands in them
+# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank
+# + @alphaenumerate is ridiculously new, turned into @enumerate
+
+# texi2roff doesn't have a notion of include dirs, so we have to fake
+# it out for gdb manual's include files---but only if not configured
+# in main sourcedir.
+links2roff: $(SFILES_INCLUDED)
+ if [ ! -f gdb.texinfo ]; then \
+ ln -s $(SFILES_INCLUDED) . || \
+ ln $(SFILES_INCLUDED) . || \
+ cp $(SFILES_INCLUDED) . ; \
+ fi
+ touch links2roff
+
+# "Readline" appendices. Get them also due to lack of includes,
+# regardless of whether or not configuring in main sourcedir.
+# @ftable removed due to bug in texi2roff-2; if your texi2roff
+# is newer, try just ln or cp
+rluser.texinfo: ${READLINE_DIR}/rluser.texinfo
+ sed -e 's/^@ftable/@table/g' \
+ -e 's/^@end ftable/@end table/g' \
+ ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo
+
+inc-hist.texi: ${READLINE_DIR}/inc-hist.texi
+ ln -s ${READLINE_DIR}/inc-hist.texi . || \
+ ln ${READLINE_DIR}/inc-hist.texi . || \
+ cp ${READLINE_DIR}/inc-hist.texi .
+
+# gdb manual suitable for [gtn]roff -me
+gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -me | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.me
+
+# gdb manual suitable for [gtn]roff -ms
+gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -ms | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.ms
+
+# gdb manual suitable for [tn]roff -mm
+# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer,
+# try leaving them in
+gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -mm | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.mm
+
+# GDB INTERNALS MANUAL: TeX dvi file
+gdbint.dvi : gdbint.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ $(TEXINDEX) gdbint.??
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \
+ gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs
+
+# GDB INTERNALS MANUAL: info file
+gdb-internals: gdbint.info
+
+gdbint.info: gdbint.texinfo
+ $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo
+
+stabs.info: stabs.texinfo
+ $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo
+
+# STABS DOCUMENTATION: TeX dvi file
+stabs.dvi : stabs.texinfo
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ $(TEXINDEX) stabs.??
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \
+ stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs
+
+stabs.ps: stabs.dvi
+ dvips -o stabs.ps stabs
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
diff --git a/gnu/usr.bin/gdb/doc/Makefile.in b/gnu/usr.bin/gdb/doc/Makefile.in
new file mode 100644
index 000000000000..d5ae2904f700
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/Makefile.in
@@ -0,0 +1,327 @@
+##Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+# Makefile for GDB documentation.
+# This file is part of GDB.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = .
+
+prefix = /usr/local
+
+infodir = $(prefix)/info
+
+SHELL = /bin/sh
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+# main GDB source directory
+gdbdir = $(srcdir)/..
+
+# where to find texinfo; GDB dist should include a recent one
+TEXIDIR=${gdbdir}/../texinfo
+
+# where to find makeinfo, preferably one designed for texinfo-2
+MAKEINFO=makeinfo
+
+# where to find texi2roff, ditto
+TEXI2ROFF=texi2roff
+
+# Where is the source dir for the READLINE library doc?
+# Traditionally readline is in .. or .
+READLINE_DIR = ${gdbdir}/../readline/doc
+
+SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS
+
+# There may be alternate predefined collections of switches to configure
+# the GDB manual. Normally this is not done in synch with the software
+# config system, since this choice tends to be independent; most people
+# want a doc config of `all' for a generic manual, regardless of sw config.
+DOC_CONFIG = all
+
+# This list of sed edits will edit the GDB reference card
+# for what fonts and what papersize to use.
+# By default (NO edits applied), the refcard uses:
+# - Computer Modern (CM) fonts
+# - US letter paper (8.5x11in)
+# List some of the following files for alternative fonts and paper:
+# a4rc.sed use A4 paper (297 x 210 mm)
+# psrc.sed use PostScript fonts (Karl Berry short TeX names)
+# lpsrc.sed use PostScript fonts (full PostScript names in TeX)
+# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed
+# for A4, CM fonts: REFEDITS = a4rc.sed
+# for US, PS fonts: REFEDITS = psrc.sed
+# for default:
+REFEDITS =
+
+# Don Knuth's TeX formatter
+TEX = tex
+
+# auxiliary program for sorting Texinfo indices
+TEXINDEX = texindex
+
+# Main GDB manual's source files
+SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi
+
+SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED)
+
+SFILES_DOC = $(SFILES_LOCAL) \
+ $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi
+
+#### Host, target, and site specific Makefile fragments come in here.
+###
+
+all install:
+
+info: gdb.info gdbint.info stabs.info
+dvi: gdb.dvi refcard.dvi gdbint.dvi
+all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi
+
+install-info: info
+ for i in *.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+STAGESTUFF = *.info* gdb-all.texi GDBvn.texi
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ -(cd stage1 ; mv -f * ..)
+ -rmdir stage1
+
+de-stage2: force
+ -(cd stage2 ; mv -f * ..)
+ -rmdir stage2
+
+de-stage3: force
+ -(cd stage3 ; mv -f * ..)
+ -rmdir stage3
+
+clean-info:
+ rm -f gdb.info* gdbint.info* stabs.info*
+
+clean-dvi:
+ rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi
+
+mostlyclean: clean-info clean-dvi
+ rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me
+ rm -f links2roff
+ rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~
+ rm -f gdbint.?? gdbint.??? stabs.?? stabs.???
+
+clean: mostlyclean
+ rm -f GDBvn.texi rluser.texinfo inc-hist.texi
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean clean-dvi clean-info
+
+# GDB QUICK REFERENCE (dvi output)
+refcard.dvi : refcard.tex $(REFEDITS)
+ if [ -z "$(REFEDITS)" ]; then \
+ cp $(srcdir)/refcard.tex sedref.tex ; \
+ else \
+ echo > tmp.sed ; \
+ for f in "$(REFEDITS)" ; do \
+ cat $(srcdir)/$$f >>tmp.sed ; done ; \
+ sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \
+ fi
+ $(SET_TEXINPUTS) $(TEX) sedref.tex
+ mv sedref.dvi refcard.dvi
+ rm -f sedref.log sedref.tex tmp.sed
+
+refcard.ps : refcard.dvi
+ dvips -t landscape refcard.dvi -o
+
+# File to record current GDB version number (copied from main dir Makefile.in)
+GDBvn.texi : ${gdbdir}/Makefile.in
+ echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new
+ mv GDBvn.new GDBvn.texi
+
+# Updated atomically
+.PRECIOUS: GDBvn.texi
+
+# Choose configuration for GDB manual (normally `all'; normally not tied into
+# `configure' script because most users prefer generic version of manual,
+# not one for their binary config---which may not be specifically
+# defined anyways).
+gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi
+ ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi
+
+# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear
+# If your texinfo or makeinfo don't support these, get a new texinfo release
+#
+# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make.
+# Note that we can *generate* GDBvn.texi, but since we distribute one in the
+# source directory for the benefit of people who *don't* use this makefile,
+# VPATH will often tell make not to bother building it, because the one
+# in the srcdir is up to date. (if not, then make should build one here).
+
+# GDB MANUAL: TeX dvi file
+gdb.dvi: ${SFILES_DOC}
+ if [ ! -f ./GDBvn.texi ]; then \
+ ln -s $(srcdir)/GDBvn.texi . || \
+ ln $(srcdir)/GDBvn.texi . || \
+ cp $(srcdir)/GDBvn.texi . ; else true; fi
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(TEXINDEX) gdb.??
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s
+
+# GDB MANUAL: info file
+# We're using texinfo2, and older makeinfo's may not be able to
+# cope with all the markup.
+gdb.info: ${SFILES_DOC}
+ $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo
+
+# GDB MANUAL: roff translations
+# Try to use a recent texi2roff. v2 was put on prep in jan91.
+# If you want an index, see texi2roff doc for postprocessing
+# and add -i to texi2roff invocations below.
+# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete
+# corresponding -e lines when later texi2roff's are current)
+# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs.
+# + @c's deleted explicitly because texi2roff sees texinfo commands in them
+# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank
+# + @alphaenumerate is ridiculously new, turned into @enumerate
+
+# texi2roff doesn't have a notion of include dirs, so we have to fake
+# it out for gdb manual's include files---but only if not configured
+# in main sourcedir.
+links2roff: $(SFILES_INCLUDED)
+ if [ ! -f gdb.texinfo ]; then \
+ ln -s $(SFILES_INCLUDED) . || \
+ ln $(SFILES_INCLUDED) . || \
+ cp $(SFILES_INCLUDED) . ; \
+ fi
+ touch links2roff
+
+# "Readline" appendices. Get them also due to lack of includes,
+# regardless of whether or not configuring in main sourcedir.
+# @ftable removed due to bug in texi2roff-2; if your texi2roff
+# is newer, try just ln or cp
+rluser.texinfo: ${READLINE_DIR}/rluser.texinfo
+ sed -e 's/^@ftable/@table/g' \
+ -e 's/^@end ftable/@end table/g' \
+ ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo
+
+inc-hist.texi: ${READLINE_DIR}/inc-hist.texi
+ ln -s ${READLINE_DIR}/inc-hist.texi . || \
+ ln ${READLINE_DIR}/inc-hist.texi . || \
+ cp ${READLINE_DIR}/inc-hist.texi .
+
+# gdb manual suitable for [gtn]roff -me
+gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -me | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.me
+
+# gdb manual suitable for [gtn]roff -ms
+gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -ms | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.ms
+
+# gdb manual suitable for [tn]roff -mm
+# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer,
+# try leaving them in
+gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -mm | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.mm
+
+# GDB INTERNALS MANUAL: TeX dvi file
+gdbint.dvi : gdbint.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ $(TEXINDEX) gdbint.??
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \
+ gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs
+
+# GDB INTERNALS MANUAL: info file
+gdb-internals: gdbint.info
+
+gdbint.info: gdbint.texinfo
+ $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo
+
+stabs.info: stabs.texinfo
+ $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo
+
+# STABS DOCUMENTATION: TeX dvi file
+stabs.dvi : stabs.texinfo
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ $(TEXINDEX) stabs.??
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \
+ stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs
+
+stabs.ps: stabs.dvi
+ dvips -o stabs.ps stabs
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
diff --git a/gnu/usr.bin/gdb/doc/a4rc.sed b/gnu/usr.bin/gdb/doc/a4rc.sed
new file mode 100644
index 000000000000..22922904efc9
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/a4rc.sed
@@ -0,0 +1,11 @@
+/--- Papersize params:/,/--- end papersize params/c\
+%------- Papersize params:\
+%% A4 paper (297x210mm)\
+%%\
+\\totalwidth=297mm % total width of paper\
+\\totalheight=210mm % total height of paper\
+\\hmargin=5mm % horizontal margin width\
+\\vmargin=10mm % vertical margin width\
+\\secskip=.6pc % space between refcard secs\
+\\lskip=1pt % extra skip between \\sec entries\
+%------- end papersize params
diff --git a/gnu/usr.bin/gdb/doc/all-cfg.texi b/gnu/usr.bin/gdb/doc/all-cfg.texi
new file mode 100644
index 000000000000..ec64da105ed3
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/all-cfg.texi
@@ -0,0 +1,117 @@
+@c GDB MANUAL configuration file.
+@c Copyright (c) 1993 Free Software Foundation, Inc.
+@c
+@c NOTE: While the GDB manual is configurable (by changing these
+@c switches), its configuration is ***NOT*** automatically tied in to
+@c source configuration---because the authors expect that, save in
+@c unusual cases, the most inclusive form of the manual is appropriate
+@c no matter how the program itself is configured.
+@c
+@c The only automatically-varying variable is the GDB version number,
+@c which the Makefile rewrites based on the VERSION variable from
+@c `../Makefile.in'.
+@c
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@c ----------------------------------------------------------------------
+@c PLATFORM FLAGS:
+@set GENERIC
+@c
+@c Hitachi H8/300 target:
+@set H8
+@c Hitachi H8/300 target ONLY:
+@clear H8EXCLUSIVE
+@c
+@c remote MIPS target:
+@set MIPS
+@c
+@c SPARC target:
+@set SPARC
+@c
+@c AMD 29000 target:
+@set AMD29K
+@c
+@c Intel 960 target:
+@set I960
+@c
+@c Tandem ST2000 (phone switch) target:
+@set ST2000
+@c
+@c Zilog 8000 target:
+@set Z8K
+@c
+@c Lucid "Energize" environment:
+@clear LUCID
+@c
+@c Wind River Systems VxWorks environment:
+@set VXWORKS
+@c
+@c ----------------------------------------------------------------------
+@c DOC FEATURE FLAGS:
+@c
+@c Include change-from-old?
+@set NOVEL
+@c
+@c Bare-board target?
+@clear BARETARGET
+@c
+@c Restrict languages discussed to C?
+@c This is backward. As time permits, change this to language-specific
+@c switches for what to include.
+@clear CONLY
+@c Discuss Fortran?
+@set FORTRAN
+@c
+@c Discuss Modula 2?
+@set MOD2
+@c
+@c Specifically for host machine running DOS?
+@clear DOSHOST
+@c
+@c Talk about CPU simulator targets?
+@set SIMS
+@c
+@c Is manual stand-alone, or part of an agglomeration, with overall GPL?
+@clear AGGLOMERATION
+@c
+@c Remote serial line settings of interest?
+@set SERIAL
+@c
+@c Discuss features requiring Posix or similar OS environment?
+@set POSIX
+@c
+@c Discuss remote serial debugging stub?
+@set REMOTESTUB
+@c
+@c Discuss gdbserver?
+@set GDBSERVER
+@c
+@c Refrain from discussing how to configure sw and format doc?
+@clear PRECONFIGURED
+@c
+@c Refrain from referring to unfree publications?
+@set FSFDOC
+@c
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of host. Should not be used in generic configs, but generic
+@c value may catch some flubs.
+@set HOST machine specific
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
+
diff --git a/gnu/usr.bin/gdb/doc/config.status b/gnu/usr.bin/gdb/doc/config.status
new file mode 100755
index 000000000000..5d2c6dd679a3
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/config.status
@@ -0,0 +1,5 @@
+#!/bin/sh
+# This file was generated automatically by configure. Do not edit.
+# This directory was configured as follows:
+../../configure --host=i386-unknown-freebsd --target=i386-unknown-freebsd -norecursion
+#
diff --git a/gnu/usr.bin/gdb/doc/configure.in b/gnu/usr.bin/gdb/doc/configure.in
new file mode 100644
index 000000000000..1d2b47e78cc5
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/configure.in
@@ -0,0 +1,7 @@
+srcname="GDB doc"
+srctrigger=gdb.texinfo
+# per-host:
+# per-target:
+
+files=""
+links=""
diff --git a/gnu/usr.bin/gdb/doc/gdb-cfg.texi b/gnu/usr.bin/gdb/doc/gdb-cfg.texi
new file mode 100644
index 000000000000..ec64da105ed3
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb-cfg.texi
@@ -0,0 +1,117 @@
+@c GDB MANUAL configuration file.
+@c Copyright (c) 1993 Free Software Foundation, Inc.
+@c
+@c NOTE: While the GDB manual is configurable (by changing these
+@c switches), its configuration is ***NOT*** automatically tied in to
+@c source configuration---because the authors expect that, save in
+@c unusual cases, the most inclusive form of the manual is appropriate
+@c no matter how the program itself is configured.
+@c
+@c The only automatically-varying variable is the GDB version number,
+@c which the Makefile rewrites based on the VERSION variable from
+@c `../Makefile.in'.
+@c
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@c ----------------------------------------------------------------------
+@c PLATFORM FLAGS:
+@set GENERIC
+@c
+@c Hitachi H8/300 target:
+@set H8
+@c Hitachi H8/300 target ONLY:
+@clear H8EXCLUSIVE
+@c
+@c remote MIPS target:
+@set MIPS
+@c
+@c SPARC target:
+@set SPARC
+@c
+@c AMD 29000 target:
+@set AMD29K
+@c
+@c Intel 960 target:
+@set I960
+@c
+@c Tandem ST2000 (phone switch) target:
+@set ST2000
+@c
+@c Zilog 8000 target:
+@set Z8K
+@c
+@c Lucid "Energize" environment:
+@clear LUCID
+@c
+@c Wind River Systems VxWorks environment:
+@set VXWORKS
+@c
+@c ----------------------------------------------------------------------
+@c DOC FEATURE FLAGS:
+@c
+@c Include change-from-old?
+@set NOVEL
+@c
+@c Bare-board target?
+@clear BARETARGET
+@c
+@c Restrict languages discussed to C?
+@c This is backward. As time permits, change this to language-specific
+@c switches for what to include.
+@clear CONLY
+@c Discuss Fortran?
+@set FORTRAN
+@c
+@c Discuss Modula 2?
+@set MOD2
+@c
+@c Specifically for host machine running DOS?
+@clear DOSHOST
+@c
+@c Talk about CPU simulator targets?
+@set SIMS
+@c
+@c Is manual stand-alone, or part of an agglomeration, with overall GPL?
+@clear AGGLOMERATION
+@c
+@c Remote serial line settings of interest?
+@set SERIAL
+@c
+@c Discuss features requiring Posix or similar OS environment?
+@set POSIX
+@c
+@c Discuss remote serial debugging stub?
+@set REMOTESTUB
+@c
+@c Discuss gdbserver?
+@set GDBSERVER
+@c
+@c Refrain from discussing how to configure sw and format doc?
+@clear PRECONFIGURED
+@c
+@c Refrain from referring to unfree publications?
+@set FSFDOC
+@c
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of host. Should not be used in generic configs, but generic
+@c value may catch some flubs.
+@set HOST machine specific
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info b/gnu/usr.bin/gdb/doc/gdb.info
new file mode 100644
index 000000000000..c32646954b36
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info
@@ -0,0 +1,213 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+Indirect:
+gdb.info-1: 992
+gdb.info-2: 50863
+gdb.info-3: 98423
+gdb.info-4: 145674
+gdb.info-5: 194815
+gdb.info-6: 244253
+gdb.info-7: 290141
+gdb.info-8: 335234
+
+Tag Table:
+(Indirect)
+Node: Top992
+Node: Summary2561
+Node: Free Software3754
+Node: Contributors4492
+Node: New Features8199
+Node: Sample Session12215
+Node: Invocation19094
+Node: Invoking GDB19559
+Node: File Options21298
+Node: Mode Options24476
+Node: Quitting GDB26641
+Node: Shell Commands27359
+Node: Commands28106
+Node: Command Syntax28739
+Node: Completion30598
+Node: Help34666
+Node: Running38442
+Node: Compilation39426
+Node: Starting41224
+Node: Arguments44411
+Node: Environment45412
+Node: Working Directory48518
+Node: Input/Output49258
+Node: Attach50863
+Node: Kill Process53122
+Node: Process Information54097
+Node: Stopping55350
+Node: Breakpoints56423
+Node: Set Breaks58622
+Node: Set Watchpoints65221
+Node: Exception Handling66051
+Node: Delete Breaks68610
+Node: Disabling70238
+Node: Conditions72881
+Node: Break Commands77378
+Node: Breakpoint Menus80225
+Node: Error in Breakpoints81935
+Node: Continuing and Stepping82839
+Node: Signals89318
+Node: Stack92940
+Node: Frames94414
+Node: Backtrace96691
+Node: Selection98423
+Node: Frame Info100917
+Node: MIPS Stack102984
+Node: Source103857
+Node: List104806
+Node: Search108286
+Node: Source Path109085
+Node: Machine Code111763
+Node: Data114236
+Node: Expressions116111
+Node: Variables117793
+Node: Arrays120314
+Node: Output Formats122397
+Node: Memory124456
+Node: Auto Display128727
+Node: Print Settings132474
+Node: Value History140630
+Node: Convenience Vars143017
+Node: Registers145674
+Node: Floating Point Hardware150276
+Node: Languages150781
+Node: Setting151949
+Node: Manually152483
+Node: Automatically153663
+Node: Show154980
+Node: Checks155888
+Node: Type Checking157244
+Node: Range Checking159924
+Node: Support162265
+Node: C163185
+Node: C Operators164016
+Node: C Constants168071
+Node: Cplus expressions169974
+Node: C Defaults172597
+Node: C Checks173215
+Node: Debugging C173926
+Node: Debugging C plus plus174404
+Node: Modula-2176416
+Node: M2 Operators177308
+Node: Built-In Func/Proc180308
+Node: M2 Constants183051
+Node: M2 Defaults184640
+Node: Deviations185239
+Node: M2 Checks186330
+Node: M2 Scope187130
+Node: GDB/M2188142
+Node: Symbols189081
+Node: Altering194815
+Node: Assignment195797
+Node: Jumping197907
+Node: Signaling199914
+Node: Returning201034
+Node: Calling202226
+Node: Patching202700
+Node: GDB Files203782
+Node: Files204247
+Node: Symbol Errors214466
+Node: Targets218064
+Node: Active Targets218954
+Node: Target Commands220530
+Node: Remote223904
+Node: Remote Serial225315
+Node: Stub Contents227768
+Node: Bootstrapping229877
+Node: Debug Session233057
+Node: Protocol236218
+Node: Server239069
+Node: i960-Nindy Remote242748
+Node: Nindy Startup243568
+Node: Nindy Options244253
+Node: Nindy Reset245867
+Node: UDI29K Remote246251
+Node: EB29K Remote247172
+Node: Comms (EB29K)248006
+Node: gdb-EB29K251189
+Node: Remote Log252555
+Node: ST2000 Remote253030
+Node: VxWorks Remote254499
+Node: VxWorks Connection256224
+Node: VxWorks Download257150
+Node: VxWorks Attach258886
+Node: Hitachi Remote259281
+Node: MIPS Remote260790
+Node: Simulator262861
+Node: Controlling GDB264351
+Node: Prompt264962
+Node: Editing265571
+Node: History266338
+Node: Screen Size269024
+Node: Numbers270420
+Node: Messages/Warnings271538
+Node: Sequences274587
+Node: Define275147
+Node: Hooks277144
+Node: Command Files278547
+Node: Output280302
+Node: Emacs282714
+Node: GDB Bugs288669
+Node: Bug Criteria289387
+Node: Bug Reporting290141
+Node: Command Line Editing297342
+Node: Introduction and Notation297763
+Node: Readline Interaction298780
+Node: Readline Bare Essentials299914
+Node: Readline Movement Commands301417
+Node: Readline Killing Commands302303
+Node: Readline Arguments303941
+Node: Readline Init File304887
+Node: Readline Init Syntax305708
+Node: Commands For Moving309640
+Node: Commands For History310260
+Node: Commands For Text311330
+Node: Commands For Killing313046
+Node: Numeric Arguments314168
+Node: Commands For Completion314606
+Node: Miscellaneous Commands315325
+Node: Readline Vi Mode316077
+Node: Using History Interactively316784
+Node: History Interaction317141
+Node: Event Designators318189
+Node: Word Designators318828
+Node: Modifiers319724
+Node: Renamed Commands320469
+Node: Formatting Documentation322131
+Node: Installing GDB325465
+Node: Separate Objdir328945
+Node: Config Names331490
+Node: configure Options332918
+Node: Index335234
+
+End Tag Table
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-1 b/gnu/usr.bin/gdb/doc/gdb.info-1
new file mode 100644
index 000000000000..a1d71201a5c8
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-1
@@ -0,0 +1,1304 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Top, Next: Summary, Prev: (DIR), Up: (DIR)
+
+Debugging with GDB
+******************
+
+ This file describes GDB, the GNU symbolic debugger.
+
+ This is Edition 4.09, August 1993, for GDB Version 4.11.
+
+* Menu:
+
+* Summary:: Summary of GDB
+
+* New Features:: New features since GDB version 3.5
+
+* Sample Session:: A sample GDB session
+
+* Invocation:: Getting in and out of GDB
+* Commands:: GDB commands
+* Running:: Running programs under GDB
+* Stopping:: Stopping and continuing
+* Stack:: Examining the stack
+* Source:: Examining source files
+* Data:: Examining data
+
+* Languages:: Using GDB with different languages
+
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: GDB files
+* Targets:: Specifying a debugging target
+* Controlling GDB:: Controlling GDB
+* Sequences:: Canned sequences of commands
+
+* Emacs:: Using GDB under GNU Emacs
+
+* GDB Bugs:: Reporting bugs in GDB
+* Command Line Editing:: Facilities of the readline library
+* Using History Interactively::
+
+* Renamed Commands::
+
+* Formatting Documentation:: How to format and print GDB documentation
+* Installing GDB:: Installing GDB
+
+* Index:: Index
+
+
+File: gdb.info, Node: Summary, Next: New Features, Prev: Top, Up: Top
+
+Summary of GDB
+**************
+
+ The purpose of a debugger such as GDB is to allow you to see what is
+going on "inside" another program while it executes--or what another
+program was doing at the moment it crashed.
+
+ GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+ * Start your program, specifying anything that might affect its
+ behavior.
+
+ * Make your program stop on specified conditions.
+
+ * Examine what has happened, when your program has stopped.
+
+ * Change things in your program, so you can experiment with
+ correcting the effects of one bug and go on to learn about another.
+
+ You can use GDB to debug programs written in C, C++, and Modula-2.
+G{No Value For "DBN"} can be used to debug programs written in Fortran,
+although it does not yet support entering expressions, printing values,
+etc. using Fortran syntax. It may be necessary to refer to some
+variables with a trailing underscore.
+
+* Menu:
+
+* Free Software:: Freely redistributable software
+* Contributors:: Contributors to GDB
+
+
+File: gdb.info, Node: Free Software, Next: Contributors, Up: Summary
+
+Free software
+=============
+
+ GDB is "free software", protected by the GNU General Public License
+(GPL). The GPL gives you the freedom to copy or adapt a licensed
+program--but every person getting a copy also gets with it the freedom
+to modify that copy (which means that they must get access to the
+source code), and the freedom to distribute further copies. Typical
+software companies use copyrights to limit your freedoms; the Free
+Software Foundation uses the GPL to preserve these freedoms.
+
+ Fundamentally, the General Public License is a license which says
+that you have these freedoms and that you cannot take these freedoms
+away from anyone else.
+
+
+File: gdb.info, Node: Contributors, Prev: Free Software, Up: Summary
+
+Contributors to GDB
+===================
+
+ Richard Stallman was the original author of GDB, and of many other
+GNU programs. Many others have contributed to its development. This
+section attempts to credit major contributors. One of the virtues of
+free software is that everyone is free to contribute to it; with
+regret, we cannot actually acknowledge everyone here. The file
+`ChangeLog' in the GDB distribution approximates a blow-by-blow account.
+
+ Changes much prior to version 2.0 are lost in the mists of time.
+
+ *Plea:* Additions to this section are particularly welcome. If you
+ or your friends (or enemies, to be evenhanded) have been unfairly
+ omitted from this list, we would like to add your names!
+
+ So that they may not regard their long labor as thankless, we
+particularly thank those who shepherded GDB through major releases: Fred
+Fish (releases 4.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases
+4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and
+3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases
+3.2, 3.1, 3.0). As major maintainer of GDB for some period, each
+contributed significantly to the structure, stability, and capabilities
+of the entire debugger.
+
+ Richard Stallman, assisted at various times by Peter TerMaat, Chris
+Hanson, and Richard Mlynarik, handled releases through 2.8.
+
+ Michael Tiemann is the author of most of the GNU C++ support in GDB,
+with significant additional contributions from Per Bothner. James
+Clark wrote the GNU C++ demangler. Early work on C++ was by Peter
+TerMaat (who also did much general update work leading to release 3.0).
+
+ GDB 4 uses the BFD subroutine library to examine multiple
+object-file formats; BFD was a joint project of David V.
+Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore.
+
+ David Johnson wrote the original COFF support; Pace Willison did the
+original support for encapsulated COFF.
+
+ Adam de Boor and Bradley Davis contributed the ISI Optimum V support.
+Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS
+support. Jean-Daniel Fekete contributed Sun 386i support. Chris
+Hanson improved the HP9000 support. Noboyuki Hikichi and Tomoyuki
+Hasei contributed Sony/News OS 3 support. David Johnson contributed
+Encore Umax support. Jyrki Kuoppala contributed Altos 3068 support.
+Keith Packard contributed NS32K support. Doug Rabson contributed Acorn
+Risc Machine support. Chris Smith contributed Convex support (and
+Fortran debugging). Jonathan Stone contributed Pyramid support.
+Michael Tiemann contributed SPARC support. Tim Tucker contributed
+support for the Gould NP1 and Gould Powernode. Pace Willison
+contributed Intel 386 support. Jay Vosburgh contributed Symmetry
+support.
+
+ Rich Schaefer and Peter Schauer helped with support of SunOS shared
+libraries.
+
+ Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about
+several machine instruction sets.
+
+ Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped
+develop remote debugging. Intel Corporation and Wind River Systems
+contributed remote debugging modules for their products.
+
+ Brian Fox is the author of the readline libraries providing
+command-line editing and command history.
+
+ Andrew Beers of SUNY Buffalo wrote the language-switching code, the
+Modula-2 support, and contributed the Languages chapter of this manual.
+
+ Fred Fish wrote most of the support for Unix System Vr4. He also
+enhanced the command-completion support to cover C++ overloaded symbols.
+
+ Hitachi America, Ltd. sponsored the support for Hitachi
+microprocessors.
+
+
+File: gdb.info, Node: New Features, Next: Sample Session, Prev: Summary, Up: Top
+
+New Features since GDB Version 3.5
+**********************************
+
+*Targets*
+ Using the new command `target', you can select at runtime whether
+ you are debugging local files, local processes, standalone systems
+ over a serial port, realtime systems over a TCP/IP connection,
+ etc. The command `load' can download programs into a remote
+ system. Serial stubs are available for Motorola 680x0, Intel
+ 80386, and Sparc remote systems; GDB also supports debugging
+ realtime processes running under VxWorks, using SunRPC Remote
+ Procedure Calls over TCP/IP to talk to a debugger stub on the
+ target system. Internally, GDB now uses a function vector to
+ mediate access to different targets; if you need to add your own
+ support for a remote protocol, this makes it much easier.
+
+*Watchpoints*
+ GDB now sports watchpoints as well as breakpoints. You can use a
+ watchpoint to stop execution whenever the value of an expression
+ changes, without having to predict a particular place in your
+ program where this may happen.
+
+*Wide Output*
+ Commands that issue wide output now insert newlines at places
+ designed to make the output more readable.
+
+*Object Code Formats*
+ GDB uses a new library called the Binary File Descriptor (BFD)
+ Library to permit it to switch dynamically, without
+ reconfiguration or recompilation, between different object-file
+ formats. Formats currently supported are COFF, ELF, a.out, Intel
+ 960 b.out, MIPS ECOFF, HPPA SOM (with stabs debugging), and
+ S-records; files may be read as .o files, archive libraries, or
+ core dumps. BFD is available as a subroutine library so that
+ other programs may take advantage of it, and the other GNU binary
+ utilities are being converted to use it.
+
+*Configuration and Ports*
+ Compile-time configuration (to select a particular architecture and
+ operating system) is much easier. The script `configure' now
+ allows you to configure GDB as either a native debugger or a
+ cross-debugger. *Note Installing GDB::, for details on how to
+ configure.
+
+*Interaction*
+ The user interface to the GDB control variables is simpler, and is
+ consolidated in two commands, `set' and `show'. Output lines are
+ now broken at readable places, rather than overflowing onto the
+ next line. You can suppress output of machine-level addresses,
+ displaying only source language information.
+
+*C++*
+ GDB now supports C++ multiple inheritance (if used with a GCC
+ version 2 compiler), and also has limited support for C++ exception
+ handling, with the commands `catch' and `info catch': GDB can
+ break when an exception is raised, before the stack is peeled back
+ to the exception handler's context.
+
+*Modula-2*
+ GDB now has preliminary support for the GNU Modula-2 compiler,
+ currently under development at the State University of New York at
+ Buffalo. Coordinated development of both GDB and the GNU Modula-2
+ compiler will continue. Other Modula-2 compilers are currently
+ not supported, and attempting to debug programs compiled with them
+ will likely result in an error as the symbol table of the
+ executable is read in.
+
+*Command Rationalization*
+ Many GDB commands have been renamed to make them easier to remember
+ and use. In particular, the subcommands of `info' and
+ `show'/`set' are grouped to make the former refer to the state of
+ your program, and the latter refer to the state of GDB itself.
+ *Note Renamed Commands::, for details on what commands were
+ renamed.
+
+*Shared Libraries*
+ GDB 4 can debug programs and core files that use SunOS, SVR4, or
+ IBM RS/6000 shared libraries.
+
+*Reference Card*
+ GDB 4 has a reference card. *Note Formatting the Documentation:
+ Formatting Documentation, for instructions about how to print it.
+
+
+File: gdb.info, Node: Sample Session, Next: Invocation, Prev: New Features, Up: Top
+
+A Sample GDB Session
+********************
+
+ You can use this manual at your leisure to read all about GDB.
+However, a handful of commands are enough to get started using the
+debugger. This chapter illustrates those commands.
+
+ One of the preliminary versions of GNU `m4' (a generic macro
+processor) exhibits the following bug: sometimes, when we change its
+quote strings from the default, the commands used to capture one macro
+definition within another stop working. In the following short `m4'
+session, we define a macro `foo' which expands to `0000'; we then use
+the `m4' built-in `defn' to define `bar' as the same thing. However,
+when we change the open quote string to `<QUOTE>' and the close quote
+string to `<UNQUOTE>', the same procedure fails to define a new synonym
+`baz':
+
+ $ cd gnu/m4
+ $ ./m4
+ define(foo,0000)
+
+ foo
+ 0000
+ define(bar,defn(`foo'))
+
+ bar
+ 0000
+ changequote(<QUOTE>,<UNQUOTE>)
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+ baz
+ C-d
+ m4: End of input: 0: fatal error: EOF in string
+
+Let us use GDB to try to see what is going on.
+
+ $ gdb m4
+ GDB is free software and you are welcome to distribute copies
+ of it under certain conditions; type "show copying" to see
+ the conditions.
+ There is absolutely no warranty for GDB; type "show warranty"
+ for details.
+ GDB 4.11, Copyright 1993 Free Software Foundation, Inc...
+ (gdb)
+
+GDB reads only enough symbol data to know where to find the rest when
+needed; as a result, the first prompt comes up very quickly. We now
+tell GDB to use a narrower display width than usual, so that examples
+will fit in this manual.
+
+ (gdb) set width 70
+
+We need to see how the `m4' built-in `changequote' works. Having
+looked at the source, we know the relevant subroutine is
+`m4_changequote', so we set a breakpoint there with the GDB `break'
+command.
+
+ (gdb) break m4_changequote
+ Breakpoint 1 at 0x62f4: file builtin.c, line 879.
+
+Using the `run' command, we start `m4' running under GDB control; as
+long as control does not reach the `m4_changequote' subroutine, the
+program runs as usual:
+
+ (gdb) run
+ Starting program: /work/Editorial/gdb/gnu/m4/m4
+ define(foo,0000)
+
+ foo
+ 0000
+
+To trigger the breakpoint, we call `changequote'. GDB suspends
+execution of `m4', displaying information about the context where it
+stops.
+
+ changequote(<QUOTE>,<UNQUOTE>)
+
+ Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:879
+ 879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
+
+Now we use the command `n' (`next') to advance execution to the next
+line of the current function.
+
+ (gdb) n
+ 882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
+ : nil,
+
+`set_quotes' looks like a promising subroutine. We can go into it by
+using the command `s' (`step') instead of `next'. `step' goes to the
+next line to be executed in *any* subroutine, so it steps into
+`set_quotes'.
+
+ (gdb) s
+ set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+The display that shows the subroutine where `m4' is now suspended (and
+its arguments) is called a stack frame display. It shows a summary of
+the stack. We can use the `backtrace' command (which can also be
+spelled `bt'), to see where we are in the stack as a whole: the
+`backtrace' command displays a stack frame for each active subroutine.
+
+ (gdb) bt
+ #0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+ #1 0x6344 in m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:882
+ #2 0x8174 in expand_macro (sym=0x33320) at macro.c:242
+ #3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30)
+ at macro.c:71
+ #4 0x79dc in expand_input () at macro.c:40
+ #5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195
+
+We will step through a few more lines to see what happens. The first
+two times, we can use `s'; the next two times we use `n' to avoid
+falling into the `xstrdup' subroutine.
+
+ (gdb) s
+ 0x3b5c 532 if (rquote != def_rquote)
+ (gdb) s
+ 0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \
+ def_lquote : xstrdup(lq);
+ (gdb) n
+ 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup(rq);
+ (gdb) n
+ 538 len_lquote = strlen(rquote);
+
+The last line displayed looks a little odd; we can examine the variables
+`lquote' and `rquote' to see if they are in fact the new left and right
+quotes we specified. We use the command `p' (`print') to see their
+values.
+
+ (gdb) p lquote
+ $1 = 0x35d40 "<QUOTE>"
+ (gdb) p rquote
+ $2 = 0x35d50 "<UNQUOTE>"
+
+`lquote' and `rquote' are indeed the new left and right quotes. To
+look at some context, we can display ten lines of source surrounding
+the current line with the `l' (`list') command.
+
+ (gdb) l
+ 533 xfree(rquote);
+ 534
+ 535 lquote = (lq == nil || *lq == '\0') ? def_lquote\
+ : xstrdup (lq);
+ 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup (rq);
+ 537
+ 538 len_lquote = strlen(rquote);
+ 539 len_rquote = strlen(lquote);
+ 540 }
+ 541
+ 542 void
+
+Let us step past the two lines that set `len_lquote' and `len_rquote',
+and then examine the values of those variables.
+
+ (gdb) n
+ 539 len_rquote = strlen(lquote);
+ (gdb) n
+ 540 }
+ (gdb) p len_lquote
+ $3 = 9
+ (gdb) p len_rquote
+ $4 = 7
+
+That certainly looks wrong, assuming `len_lquote' and `len_rquote' are
+meant to be the lengths of `lquote' and `rquote' respectively. We can
+set them to better values using the `p' command, since it can print the
+value of any expression--and that expression can include subroutine
+calls and assignments.
+
+ (gdb) p len_lquote=strlen(lquote)
+ $5 = 7
+ (gdb) p len_rquote=strlen(rquote)
+ $6 = 9
+
+Is that enough to fix the problem of using the new quotes with the `m4'
+built-in `defn'? We can allow `m4' to continue executing with the `c'
+(`continue') command, and then try the example that caused trouble
+initially:
+
+ (gdb) c
+ Continuing.
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+
+ baz
+ 0000
+
+Success! The new quotes now work just as well as the default ones. The
+problem seems to have been just the two typos defining the wrong
+lengths. We allow `m4' exit by giving it an EOF as input:
+
+ C-d
+ Program exited normally.
+
+The message `Program exited normally.' is from GDB; it indicates `m4'
+has finished executing. We can end our GDB session with the GDB `quit'
+command.
+
+ (gdb) quit
+
+
+File: gdb.info, Node: Invocation, Next: Commands, Prev: Sample Session, Up: Top
+
+Getting In and Out of GDB
+*************************
+
+ This chapter discusses how to start GDB, and how to get out of it.
+(The essentials: type `gdb' to start GDB, and type `quit' or `C-d' to
+exit.)
+
+* Menu:
+
+* Invoking GDB:: How to start GDB
+* Quitting GDB:: How to quit GDB
+* Shell Commands:: How to use shell commands inside GDB
+
+
+File: gdb.info, Node: Invoking GDB, Next: Quitting GDB, Up: Invocation
+
+Invoking GDB
+============
+
+ Invoke GDB by running the program `gdb'. Once started, GDB reads
+commands from the terminal until you tell it to exit.
+
+ You can also run `gdb' with a variety of arguments and options, to
+specify more of your debugging environment at the outset.
+
+ The command-line options described here are designed to cover a
+variety of situations; in some environments, some of these options may
+effectively be unavailable.
+
+ The most usual way to start GDB is with one argument, specifying an
+executable program:
+
+ gdb PROGRAM
+
+You can also start with both an executable program and a core file
+specified:
+
+ gdb PROGRAM CORE
+
+ You can, instead, specify a process ID as a second argument, if you
+want to debug a running process:
+
+ gdb PROGRAM 1234
+
+would attach GDB to process `1234' (unless you also have a file named
+`1234'; GDB does check for a core file first).
+
+ Taking advantage of the second command-line argument requires a
+fairly complete operating system; when you use GDB as a remote debugger
+attached to a bare board, there may not be any notion of "process", and
+there is often no way to get a core dump.
+
+You can further control how GDB starts up by using command-line
+options. GDB itself can remind you of the options available.
+
+Type
+
+ gdb -help
+
+to display all available options and briefly describe their use (`gdb
+-h' is a shorter equivalent).
+
+ All options and command line arguments you give are processed in
+sequential order. The order makes a difference when the `-x' option is
+used.
+
+* Menu:
+
+
+
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+
+
+File: gdb.info, Node: File Options, Next: Mode Options, Up: Invoking GDB
+
+Choosing files
+--------------
+
+ When GDB starts, it reads any arguments other than options as
+specifying an executable file and core file (or process ID). This is
+the same as if the arguments were specified by the `-se' and `-c'
+options respectively. (GDB reads the first argument that does not have
+an associated option flag as equivalent to the `-se' option followed by
+that argument; and the second argument that does not have an associated
+option flag, if any, as equivalent to the `-c' option followed by that
+argument.)
+
+ Many options have both long and short forms; both are shown in the
+following list. GDB also recognizes the long forms if you truncate
+them, so long as enough of the option is present to be unambiguous.
+(If you prefer, you can flag option arguments with `--' rather than
+`-', though we illustrate the more usual convention.)
+
+`-symbols FILE'
+`-s FILE'
+ Read symbol table from file FILE.
+
+`-exec FILE'
+`-e FILE'
+ Use file FILE as the executable file to execute when appropriate,
+ and for examining pure data in conjunction with a core dump.
+
+`-se FILE'
+ Read symbol table from file FILE and use it as the executable file.
+
+`-core FILE'
+`-c FILE'
+ Use file FILE as a core dump to examine.
+
+`-c NUMBER'
+ Connect to process ID NUMBER, as with the `attach' command (unless
+ there is a file in core-dump format named NUMBER, in which case
+ `-c' specifies that file as a core dump to read).
+
+`-command FILE'
+`-x FILE'
+ Execute GDB commands from file FILE. *Note Command files: Command
+ Files.
+
+`-directory DIRECTORY'
+`-d DIRECTORY'
+ Add DIRECTORY to the path to search for source files.
+
+`-m'
+`-mapped'
+ *Warning: this option depends on operating system facilities that
+ are not supported on all systems.*
+ If memory-mapped files are available on your system through the
+ `mmap' system call, you can use this option to have GDB write the
+ symbols from your program into a reusable file in the current
+ directory. If the program you are debugging is called
+ `/tmp/fred', the mapped symbol file will be `./fred.syms'. Future
+ GDB debugging sessions will notice the presence of this file, and
+ will quickly map in symbol information from it, rather than reading
+ the symbol table from the executable program.
+
+ The `.syms' file is specific to the host machine where GDB is run.
+ It holds an exact image of the internal GDB symbol table. It
+ cannot be shared across multiple host platforms.
+
+`-r'
+`-readnow'
+ Read each symbol file's entire symbol table immediately, rather
+ than the default, which is to read it incrementally as it is
+ needed. This makes startup slower, but makes future operations
+ faster.
+
+ The `-mapped' and `-readnow' options are typically combined in order
+to build a `.syms' file that contains complete symbol information.
+(*Note Commands to specify files: Files, for information on `.syms'
+files.) A simple GDB invocation to do nothing but build a `.syms' file
+for future use is:
+
+ gdb -batch -nx -mapped -readnow programname
+
+
+File: gdb.info, Node: Mode Options, Prev: File Options, Up: Invoking GDB
+
+Choosing modes
+--------------
+
+ You can run GDB in various alternative modes--for example, in batch
+mode or quiet mode.
+
+`-nx'
+`-n'
+ Do not execute commands from any initialization files (normally
+ called `.gdbinit'). Normally, the commands in these files are
+ executed after all the command options and arguments have been
+ processed. *Note Command files: Command Files.
+
+`-quiet'
+`-q'
+ "Quiet". Do not print the introductory and copyright messages.
+ These messages are also suppressed in batch mode.
+
+`-batch'
+ Run in batch mode. Exit with status `0' after processing all the
+ command files specified with `-x' (and all commands from
+ initialization files, if not inhibited with `-n'). Exit with
+ nonzero status if an error occurs in executing the GDB commands in
+ the command files.
+
+ Batch mode may be useful for running GDB as a filter, for example
+ to download and run a program on another computer; in order to
+ make this more useful, the message
+
+ Program exited normally.
+
+ (which is ordinarily issued whenever a program running under GDB
+ control terminates) is not issued when running in batch mode.
+
+`-cd DIRECTORY'
+ Run GDB using DIRECTORY as its working directory, instead of the
+ current directory.
+
+`-fullname'
+`-f'
+ Emacs sets this option when it runs GDB as a subprocess. It tells
+ GDB to output the full file name and line number in a standard,
+ recognizable fashion each time a stack frame is displayed (which
+ includes each time your program stops). This recognizable format
+ looks like two `\032' characters, followed by the file name, line
+ number and character position separated by colons, and a newline.
+ The Emacs-to-GDB interface program uses the two `\032' characters
+ as a signal to display the source code for the frame.
+
+`-b BPS'
+ Set the line speed (baud rate or bits per second) of any serial
+ interface used by GDB for remote debugging.
+
+`-tty DEVICE'
+ Run using DEVICE for your program's standard input and output.
+
+
+File: gdb.info, Node: Quitting GDB, Next: Shell Commands, Prev: Invoking GDB, Up: Invocation
+
+Quitting GDB
+============
+
+`quit'
+ To exit GDB, use the `quit' command (abbreviated `q'), or type an
+ end-of-file character (usually `C-d').
+
+ An interrupt (often `C-c') will not exit from GDB, but rather will
+terminate the action of any GDB command that is in progress and return
+to GDB command level. It is safe to type the interrupt character at
+any time because GDB does not allow it to take effect until a time when
+it is safe.
+
+ If you have been using GDB to control an attached process or device,
+you can release it with the `detach' command (*note Debugging an
+already-running process: Attach.).
+
+
+File: gdb.info, Node: Shell Commands, Prev: Quitting GDB, Up: Invocation
+
+Shell commands
+==============
+
+ If you need to execute occasional shell commands during your
+debugging session, there is no need to leave or suspend GDB; you can
+just use the `shell' command.
+
+`shell COMMAND STRING'
+ Invoke a the standard shell to execute COMMAND STRING. If it
+ exists, the environment variable `SHELL' determines which shell to
+ run. Otherwise GDB uses `/bin/sh'.
+
+ The utility `make' is often needed in development environments. You
+do not have to use the `shell' command for this purpose in GDB:
+
+`make MAKE-ARGS'
+ Execute the `make' program with the specified arguments. This is
+ equivalent to `shell make MAKE-ARGS'.
+
+
+File: gdb.info, Node: Commands, Next: Running, Prev: Invocation, Up: Top
+
+GDB Commands
+************
+
+ You can abbreviate a GDB command to the first few letters of the
+command name, if that abbreviation is unambiguous; and you can repeat
+certain GDB commands by typing just RET. You can also use the TAB key
+to get GDB to fill out the rest of a word in a command (or to show you
+the alternatives available, if there is more than one possibility).
+
+* Menu:
+
+* Command Syntax:: How to give commands to GDB
+* Completion:: Command completion
+* Help:: How to ask GDB for help
+
+
+File: gdb.info, Node: Command Syntax, Next: Completion, Up: Commands
+
+Command syntax
+==============
+
+ A GDB command is a single line of input. There is no limit on how
+long it can be. It starts with a command name, which is followed by
+arguments whose meaning depends on the command name. For example, the
+command `step' accepts an argument which is the number of times to
+step, as in `step 5'. You can also use the `step' command with no
+arguments. Some command names do not allow any arguments.
+
+ GDB command names may always be truncated if that abbreviation is
+unambiguous. Other possible command abbreviations are listed in the
+documentation for individual commands. In some cases, even ambiguous
+abbreviations are allowed; for example, `s' is specially defined as
+equivalent to `step' even though there are other commands whose names
+start with `s'. You can test abbreviations by using them as arguments
+to the `help' command.
+
+ A blank line as input to GDB (typing just RET) means to repeat the
+previous command. Certain commands (for example, `run') will not repeat
+this way; these are commands for which unintentional repetition might
+cause trouble and which you are unlikely to want to repeat.
+
+ The `list' and `x' commands, when you repeat them with RET,
+construct new arguments rather than repeating exactly as typed. This
+permits easy scanning of source or memory.
+
+ GDB can also use RET in another way: to partition lengthy output, in
+a way similar to the common utility `more' (*note Screen size: Screen
+Size.). Since it is easy to press one RET too many in this situation,
+GDB disables command repetition after any command that generates this
+sort of display.
+
+ Any text from a `#' to the end of the line is a comment; it does
+nothing. This is useful mainly in command files (*note Command files:
+Command Files.).
+
+
+File: gdb.info, Node: Completion, Next: Help, Prev: Command Syntax, Up: Commands
+
+Command completion
+==================
+
+ GDB can fill in the rest of a word in a command for you, if there is
+only one possibility; it can also show you what the valid possibilities
+are for the next word in a command, at any time. This works for GDB
+commands, GDB subcommands, and the names of symbols in your program.
+
+ Press the TAB key whenever you want GDB to fill out the rest of a
+word. If there is only one possibility, GDB will fill in the word, and
+wait for you to finish the command (or press RET to enter it). For
+example, if you type
+
+ (gdb) info bre TAB
+
+GDB fills in the rest of the word `breakpoints', since that is the only
+`info' subcommand beginning with `bre':
+
+ (gdb) info breakpoints
+
+You can either press RET at this point, to run the `info breakpoints'
+command, or backspace and enter something else, if `breakpoints' does
+not look like the command you expected. (If you were sure you wanted
+`info breakpoints' in the first place, you might as well just type RET
+immediately after `info bre', to exploit command abbreviations rather
+than command completion).
+
+ If there is more than one possibility for the next word when you
+press TAB, GDB will sound a bell. You can either supply more
+characters and try again, or just press TAB a second time, and GDB will
+display all the possible completions for that word. For example, you
+might want to set a breakpoint on a subroutine whose name begins with
+`make_', but when you type `b make_TAB' GDB just sounds the bell.
+Typing TAB again will display all the function names in your program
+that begin with those characters, for example:
+
+ (gdb) b make_ TAB
+GDB sounds bell; press TAB again, to see:
+ make_a_section_from_file make_environ
+ make_abs_section make_function_type
+ make_blockvector make_pointer_type
+ make_cleanup make_reference_type
+ make_command make_symbol_completion_list
+ (gdb) b make_
+
+After displaying the available possibilities, GDB copies your partial
+input (`b make_' in the example) so you can finish the command.
+
+ If you just want to see the list of alternatives in the first place,
+you can press `M-?' rather than pressing TAB twice. `M-?' means `META
+?'. You can type this either by holding down a key designated as the
+META shift on your keyboard (if there is one) while typing `?', or as
+ESC followed by `?'.
+
+ Sometimes the string you need, while logically a "word", may contain
+parentheses or other characters that GDB normally excludes from its
+notion of a word. To permit word completion to work in this situation,
+you may enclose words in `'' (single quote marks) in GDB commands.
+
+ The most likely situation where you might need this is in typing the
+name of a C++ function. This is because C++ allows function overloading
+(multiple definitions of the same function, distinguished by argument
+type). For example, when you want to set a breakpoint you may need to
+distinguish whether you mean the version of `name' that takes an `int'
+parameter, `name(int)', or the version that takes a `float' parameter,
+`name(float)'. To use the word-completion facilities in this
+situation, type a single quote `'' at the beginning of the function
+name. This alerts GDB that it may need to consider more information
+than usual when you press TAB or `M-?' to request word completion:
+
+ (gdb) b 'bubble( M-?
+ bubble(double,double) bubble(int,int)
+ (gdb) b 'bubble(
+
+ In some cases, GDB can tell that completing a name will require
+quotes. When this happens, GDB will insert the quote for you (while
+completing as much as it can) if you do not type the quote in the first
+place:
+
+ (gdb) b bub TAB
+GDB alters your input line to the following, and rings a bell:
+ (gdb) b 'bubble(
+
+In general, GDB can tell that a quote is needed (and inserts it) if you
+have not yet started typing the argument list when you ask for
+completion on an overloaded symbol.
+
+
+File: gdb.info, Node: Help, Prev: Completion, Up: Commands
+
+Getting help
+============
+
+ You can always ask GDB itself for information on its commands, using
+the command `help'.
+
+`help'
+`h'
+ You can use `help' (abbreviated `h') with no arguments to display
+ a short list of named classes of commands:
+
+ (gdb) help
+ List of classes of commands:
+
+ running -- Running the program
+ stack -- Examining the stack
+ data -- Examining data
+ breakpoints -- Making program stop at certain points
+ files -- Specifying and examining files
+ status -- Status inquiries
+ support -- Support facilities
+ user-defined -- User-defined commands
+ aliases -- Aliases of other commands
+ obscure -- Obscure features
+
+ Type "help" followed by a class name for a list of
+ commands in that class.
+ Type "help" followed by command name for full
+ documentation.
+ Command name abbreviations are allowed if unambiguous.
+ (gdb)
+
+`help CLASS'
+ Using one of the general help classes as an argument, you can get a
+ list of the individual commands in that class. For example, here
+ is the help display for the class `status':
+
+ (gdb) help status
+ Status inquiries.
+
+ List of commands:
+
+ show -- Generic command for showing things set
+ with "set"
+ info -- Generic command for printing status
+
+ Type "help" followed by command name for full
+ documentation.
+ Command name abbreviations are allowed if unambiguous.
+ (gdb)
+
+`help COMMAND'
+ With a command name as `help' argument, GDB will display a short
+ paragraph on how to use that command.
+
+ In addition to `help', you can use the GDB commands `info' and
+`show' to inquire about the state of your program, or the state of GDB
+itself. Each command supports many topics of inquiry; this manual
+introduces each of them in the appropriate context. The listings under
+`info' and under `show' in the Index point to all the sub-commands.
+*Note Index::.
+
+`info'
+ This command (abbreviated `i') is for describing the state of your
+ program. For example, you can list the arguments given to your
+ program with `info args', list the registers currently in use with
+ `info registers', or list the breakpoints you have set with `info
+ breakpoints'. You can get a complete list of the `info'
+ sub-commands with `help info'.
+
+`show'
+ In contrast, `show' is for describing the state of GDB itself.
+ You can change most of the things you can `show', by using the
+ related command `set'; for example, you can control what number
+ system is used for displays with `set radix', or simply inquire
+ which is currently in use with `show radix'.
+
+ To display all the settable parameters and their current values,
+ you can use `show' with no arguments; you may also use `info set'.
+ Both commands produce the same display.
+
+ Here are three miscellaneous `show' subcommands, all of which are
+exceptional in lacking corresponding `set' commands:
+
+`show version'
+ Show what version of GDB is running. You should include this
+ information in GDB bug-reports. If multiple versions of GDB are in
+ use at your site, you may occasionally want to determine which
+ version of GDB you are running; as GDB evolves, new commands are
+ introduced, and old ones may wither away. The version number is
+ also announced when you start GDB.
+
+`show copying'
+ Display information about permission for copying GDB.
+
+`show warranty'
+ Display the GNU "NO WARRANTY" statement.
+
+
+File: gdb.info, Node: Running, Next: Stopping, Prev: Commands, Up: Top
+
+Running Programs Under GDB
+**************************
+
+ When you run a program under GDB, you must first generate debugging
+information when you compile it. You may start it with its arguments,
+if any, in an environment of your choice. You may redirect your
+program's input and output, debug an already running process, or kill a
+child process.
+
+* Menu:
+
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+
+* Arguments:: Your program's arguments
+* Environment:: Your program's environment
+* Working Directory:: Your program's working directory
+* Input/Output:: Your program's input and output
+* Attach:: Debugging an already-running process
+* Kill Process:: Killing the child process
+* Process Information:: Additional process information
+
+
+File: gdb.info, Node: Compilation, Next: Starting, Up: Running
+
+Compiling for debugging
+=======================
+
+ In order to debug a program effectively, you need to generate
+debugging information when you compile it. This debugging information
+is stored in the object file; it describes the data type of each
+variable or function and the correspondence between source line numbers
+and addresses in the executable code.
+
+ To request debugging information, specify the `-g' option when you
+run the compiler.
+
+ Many C compilers are unable to handle the `-g' and `-O' options
+together. Using those compilers, you cannot generate optimized
+executables containing debugging information.
+
+ GCC, the GNU C compiler, supports `-g' with or without `-O', making
+it possible to debug optimized code. We recommend that you *always*
+use `-g' whenever you compile a program. You may think your program is
+correct, but there is no sense in pushing your luck.
+
+ When you debug a program compiled with `-g -O', remember that the
+optimizer is rearranging your code; the debugger will show you what is
+really there. Do not be too surprised when the execution path does not
+exactly match your source file! An extreme example: if you define a
+variable, but never use it, GDB will never see that variable--because
+the compiler optimizes it out of existence.
+
+ Some things do not work as well with `-g -O' as with just `-g',
+particularly on machines with instruction scheduling. If in doubt,
+recompile with `-g' alone, and if this fixes the problem, please report
+it as a bug (including a test case!).
+
+ Older versions of the GNU C compiler permitted a variant option
+`-gg' for debugging information. GDB no longer supports this format;
+if your GNU C compiler has this option, do not use it.
+
+
+File: gdb.info, Node: Starting, Next: Arguments, Prev: Compilation, Up: Running
+
+Starting your program
+=====================
+
+`run'
+`r'
+ Use the `run' command to start your program under GDB. You must
+ first specify the program name (except on VxWorks) with an
+ argument to GDB (*note Getting In and Out of GDB: Invocation.), or
+ by using the `file' or `exec-file' command (*note Commands to
+ specify files: Files.).
+
+ If you are running your program in an execution environment that
+supports processes, `run' creates an inferior process and makes that
+process run your program. (In environments without processes, `run'
+jumps to the start of your program.)
+
+ The execution of a program is affected by certain information it
+receives from its superior. GDB provides ways to specify this
+information, which you must do *before* starting your program. (You
+can change it after starting your program, but such changes will only
+affect your program the next time you start it.) This information may
+be divided into four categories:
+
+The *arguments.*
+ Specify the arguments to give your program as the arguments of the
+ `run' command. If a shell is available on your target, the shell
+ is used to pass the arguments, so that you may use normal
+ conventions (such as wildcard expansion or variable substitution)
+ in describing the arguments. In Unix systems, you can control
+ which shell is used with the `SHELL' environment variable. *Note
+ Your program's arguments: Arguments.
+
+The *environment.*
+ Your program normally inherits its environment from GDB, but you
+ can use the GDB commands `set environment' and `unset environment'
+ to change parts of the environment that will be given to your
+ program. *Note Your program's environment: Environment.
+
+The *working directory.*
+ Your program inherits its working directory from GDB. You can set
+ the GDB working directory with the `cd' command in GDB. *Note
+ Your program's working directory: Working Directory.
+
+The *standard input and output.*
+ Your program normally uses the same device for standard input and
+ standard output as GDB is using. You can redirect input and output
+ in the `run' command line, or you can use the `tty' command to set
+ a different device for your program. *Note Your program's input
+ and output: Input/Output.
+
+ *Warning:* While input and output redirection work, you cannot use
+ pipes to pass the output of the program you are debugging to
+ another program; if you attempt this, GDB is likely to wind up
+ debugging the wrong program.
+
+ When you issue the `run' command, your program begins to execute
+immediately. *Note Stopping and continuing: Stopping, for discussion
+of how to arrange for your program to stop. Once your program has
+stopped, you may call functions in your program, using the `print' or
+`call' commands. *Note Examining Data: Data.
+
+ If the modification time of your symbol file has changed since the
+last time GDB read its symbols, GDB will discard its symbol table and
+re-read it. When it does this, GDB tries to retain your current
+breakpoints.
+
+
+File: gdb.info, Node: Arguments, Next: Environment, Prev: Starting, Up: Running
+
+Your program's arguments
+========================
+
+ The arguments to your program can be specified by the arguments of
+the `run' command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to your program.
+Your `SHELL' environment variable (if it exists) specifies what shell
+GDB if you do not define `SHELL', GDB uses `/bin/sh'.
+
+ `run' with no arguments uses the same arguments used by the previous
+`run', or those set by the `set args' command.
+
+`set args'
+ Specify the arguments to be used the next time your program is
+ run. If `set args' has no arguments, `run' will execute your
+ program with no arguments. Once you have run your program with
+ arguments, using `set args' before the next `run' is the only way
+ to run it again without arguments.
+
+`show args'
+ Show the arguments to give your program when it is started.
+
+
+File: gdb.info, Node: Environment, Next: Working Directory, Prev: Arguments, Up: Running
+
+Your program's environment
+==========================
+
+ The "environment" consists of a set of environment variables and
+their values. Environment variables conventionally record such things
+as your user name, your home directory, your terminal type, and your
+search path for programs to run. Usually you set up environment
+variables with the shell and they are inherited by all the other
+programs you run. When debugging, it can be useful to try running your
+program with a modified environment without having to start GDB over
+again.
+
+`path DIRECTORY'
+ Add DIRECTORY to the front of the `PATH' environment variable (the
+ search path for executables), for both GDB and your program. You
+ may specify several directory names, separated by `:' or
+ whitespace. If DIRECTORY is already in the path, it is moved to
+ the front, so it will be searched sooner.
+
+ You can use the string `$cwd' to refer to whatever is the current
+ working directory at the time GDB searches the path. If you use
+ `.' instead, it refers to the directory where you executed the
+ `path' command. GDB replaces `.' in the DIRECTORY argument (with
+ the current path) before adding DIRECTORY to the search path.
+
+`show paths'
+ Display the list of search paths for executables (the `PATH'
+ environment variable).
+
+`show environment [VARNAME]'
+ Print the value of environment variable VARNAME to be given to
+ your program when it starts. If you do not supply VARNAME, print
+ the names and values of all environment variables to be given to
+ your program. You can abbreviate `environment' as `env'.
+
+`set environment VARNAME [=] VALUE'
+ Set environment variable VARNAME to VALUE. The value changes for
+ your program only, not for GDB itself. VALUE may be any string;
+ the values of environment variables are just strings, and any
+ interpretation is supplied by your program itself. The VALUE
+ parameter is optional; if it is eliminated, the variable is set to
+ a null value.
+
+ For example, this command:
+
+ set env USER = foo
+
+ tells a Unix program, when subsequently run, that its user is named
+ `foo'. (The spaces around `=' are used for clarity here; they are
+ not actually required.)
+
+`unset environment VARNAME'
+ Remove variable VARNAME from the environment to be passed to your
+ program. This is different from `set env VARNAME ='; `unset
+ environment' removes the variable from the environment, rather
+ than assigning it an empty value.
+
+ *Warning:* GDB runs your program using the shell indicated by your
+`SHELL' environment variable if it exists (or `/bin/sh' if not). If
+your `SHELL' variable names a shell that runs an initialization
+file--such as `.cshrc' for C-shell, or `.bashrc' for BASH--any
+variables you set in that file will affect your program. You may wish
+to move setting of environment variables to files that are only run
+when you sign on, such as `.login' or `.profile'.
+
+
+File: gdb.info, Node: Working Directory, Next: Input/Output, Prev: Environment, Up: Running
+
+Your program's working directory
+================================
+
+ Each time you start your program with `run', it inherits its working
+directory from the current working directory of GDB. The GDB working
+directory is initially whatever it inherited from its parent process
+(typically the shell), but you can specify a new working directory in
+GDB with the `cd' command.
+
+ The GDB working directory also serves as a default for the commands
+that specify files for GDB to operate on. *Note Commands to specify
+files: Files.
+
+`cd DIRECTORY'
+ Set the GDB working directory to DIRECTORY.
+
+`pwd'
+ Print the GDB working directory.
+
+
+File: gdb.info, Node: Input/Output, Next: Attach, Prev: Working Directory, Up: Running
+
+Your program's input and output
+===============================
+
+ By default, the program you run under GDB does input and output to
+the same terminal that GDB uses. GDB switches the terminal to its own
+terminal modes to interact with you, but it records the terminal modes
+your program was using and switches back to them when you continue
+running your program.
+
+`info terminal'
+ Displays information recorded by GDB about the terminal modes your
+ program is using.
+
+ You can redirect your program's input and/or output using shell
+redirection with the `run' command. For example,
+
+ run > outfile
+
+starts your program, diverting its output to the file `outfile'.
+
+ Another way to specify where your program should do input and output
+is with the `tty' command. This command accepts a file name as
+argument, and causes this file to be the default for future `run'
+commands. It also resets the controlling terminal for the child
+process, for future `run' commands. For example,
+
+ tty /dev/ttyb
+
+directs that processes started with subsequent `run' commands default
+to do input and output on the terminal `/dev/ttyb' and have that as
+their controlling terminal.
+
+ An explicit redirection in `run' overrides the `tty' command's
+effect on the input/output device, but not its effect on the controlling
+terminal.
+
+ When you use the `tty' command or redirect input in the `run'
+command, only the input *for your program* is affected. The input for
+GDB still comes from your terminal.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-2 b/gnu/usr.bin/gdb/doc/gdb.info-2
new file mode 100644
index 000000000000..e8be2fa7d906
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-2
@@ -0,0 +1,1165 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Attach, Next: Kill Process, Prev: Input/Output, Up: Running
+
+Debugging an already-running process
+====================================
+
+`attach PROCESS-ID'
+ This command attaches to a running process--one that was started
+ outside GDB. (`info files' will show your active targets.) The
+ command takes as argument a process ID. The usual way to find out
+ the process-id of a Unix process is with the `ps' utility, or with
+ the `jobs -l' shell command.
+
+ `attach' will not repeat if you press RET a second time after
+ executing the command.
+
+ To use `attach', your program must be running in an environment
+which supports processes; for example, `attach' does not work for
+programs on bare-board targets that lack an operating system. You must
+also have permission to send the process a signal.
+
+ When using `attach', you should first use the `file' command to
+specify the program running in the process and load its symbol table.
+*Note Commands to Specify Files: Files.
+
+ The first thing GDB does after arranging to debug the specified
+process is to stop it. You can examine and modify an attached process
+with all the GDB commands that are ordinarily available when you start
+processes with `run'. You can insert breakpoints; you can step and
+continue; you can modify storage. If you would rather the process
+continue running, you may use the `continue' command after attaching
+GDB to the process.
+
+`detach'
+ When you have finished debugging the attached process, you can use
+ the `detach' command to release it from GDB control. Detaching
+ the process continues its execution. After the `detach' command,
+ that process and GDB become completely independent once more, and
+ you are ready to `attach' another process or start one with `run'.
+ `detach' will not repeat if you press RET again after executing
+ the command.
+
+ If you exit GDB or use the `run' command while you have an attached
+process, you kill that process. By default, you will be asked for
+confirmation if you try to do either of these things; you can control
+whether or not you need to confirm by using the `set confirm' command
+(*note Optional warnings and messages: Messages/Warnings.).
+
+
+File: gdb.info, Node: Kill Process, Next: Process Information, Prev: Attach, Up: Running
+
+Killing the child process
+=========================
+
+`kill'
+ Kill the child process in which your program is running under GDB.
+
+ This command is useful if you wish to debug a core dump instead of a
+running process. GDB ignores any core dump file while your program is
+running.
+
+ On some operating systems, a program cannot be executed outside GDB
+while you have breakpoints set on it inside GDB. You can use the
+`kill' command in this situation to permit running your program outside
+the debugger.
+
+ The `kill' command is also useful if you wish to recompile and
+relink your program, since on many systems it is impossible to modify an
+executable file while it is running in a process. In this case, when
+you next type `run', GDB will notice that the file has changed, and
+will re-read the symbol table (while trying to preserve your current
+breakpoint settings).
+
+
+File: gdb.info, Node: Process Information, Prev: Kill Process, Up: Running
+
+Additional process information
+==============================
+
+ Some operating systems provide a facility called `/proc' that can be
+used to examine the image of a running process using file-system
+subroutines. If GDB is configured for an operating system with this
+facility, the command `info proc' is available to report on several
+kinds of information about the process running your program.
+
+`info proc'
+ Summarize available information about the process.
+
+`info proc mappings'
+ Report on the address ranges accessible in the program, with
+ information on whether your program may read, write, or execute
+ each range.
+
+`info proc times'
+ Starting time, user CPU time, and system CPU time for your program
+ and its children.
+
+`info proc id'
+ Report on the process IDs related to your program: its own process
+ ID, the ID of its parent, the process group ID, and the session ID.
+
+`info proc status'
+ General information on the state of the process. If the process is
+ stopped, this report includes the reason for stopping, and any
+ signal received.
+
+`info proc all'
+ Show all the above information about the process.
+
+
+File: gdb.info, Node: Stopping, Next: Stack, Prev: Running, Up: Top
+
+Stopping and Continuing
+***********************
+
+ The principal purposes of using a debugger are so that you can stop
+your program before it terminates; or so that, if your program runs into
+trouble, you can investigate and find out why.
+
+ Inside GDB, your program may stop for any of several reasons, such as
+a signal, a breakpoint, or reaching a new line after a GDB command such
+as `step'. You may then examine and change variables, set new
+breakpoints or remove old ones, and then continue execution. Usually,
+the messages shown by GDB provide ample explanation of the status of
+your program--but you can also explicitly request this information at
+any time.
+
+`info program'
+ Display information about the status of your program: whether it is
+ running or not, what process it is, and why it stopped.
+
+* Menu:
+
+
+* Breakpoints:: Breakpoints, watchpoints, and exceptions
+
+
+* Continuing and Stepping:: Resuming execution
+
+* Signals:: Signals
+
+
+File: gdb.info, Node: Breakpoints, Next: Continuing and Stepping, Up: Stopping
+
+Breakpoints, watchpoints, and exceptions
+========================================
+
+ A "breakpoint" makes your program stop whenever a certain point in
+the program is reached. For each breakpoint, you can add various
+conditions to control in finer detail whether your program will stop.
+You can set breakpoints with the `break' command and its variants
+(*note Setting breakpoints: Set Breaks.), to specify the place where
+your program should stop by line number, function name or exact address
+in the program. In languages with exception handling (such as GNU
+C++), you can also set breakpoints where an exception is raised (*note
+Breakpoints and exceptions: Exception Handling.).
+
+ A "watchpoint" is a special breakpoint that stops your program when
+the value of an expression changes. You must use a different command
+to set watchpoints (*note Setting watchpoints: Set Watchpoints.), but
+aside from that, you can manage a watchpoint like any other breakpoint:
+you enable, disable, and delete both breakpoints and watchpoints using
+the same commands.
+
+ You can arrange to have values from your program displayed
+automatically whenever GDB stops at a breakpoint. *Note Automatic
+display: Auto Display.
+
+ GDB assigns a number to each breakpoint or watchpoint when you
+create it; these numbers are successive integers starting with one. In
+many of the commands for controlling various features of breakpoints you
+use the breakpoint number to say which breakpoint you want to change.
+Each breakpoint may be "enabled" or "disabled"; if disabled, it has no
+effect on your program until you enable it again.
+
+* Menu:
+
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+
+* Exception Handling:: Breakpoints and exceptions
+
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+
+* Breakpoint Menus:: Breakpoint menus
+
+* Error in Breakpoints:: "Cannot insert breakpoints"
+
+
+File: gdb.info, Node: Set Breaks, Next: Set Watchpoints, Up: Breakpoints
+
+Setting breakpoints
+-------------------
+
+ Breakpoints are set with the `break' command (abbreviated `b'). The
+debugger convenience variable `$bpnum' records the number of the
+beakpoint you've set most recently; see *Note Convenience variables:
+Convenience Vars, for a discussion of what you can do with convenience
+variables.
+
+ You have several ways to say where the breakpoint should go.
+
+`break FUNCTION'
+ Set a breakpoint at entry to function FUNCTION. When using source
+ languages that permit overloading of symbols, such as C++,
+ FUNCTION may refer to more than one possible place to break.
+ *Note Breakpoint menus: Breakpoint Menus, for a discussion of that
+ situation.
+
+`break +OFFSET'
+`break -OFFSET'
+ Set a breakpoint some number of lines forward or back from the
+ position at which execution stopped in the currently selected
+ frame.
+
+`break LINENUM'
+ Set a breakpoint at line LINENUM in the current source file. That
+ file is the last file whose source text was printed. This
+ breakpoint will stop your program just before it executes any of
+ the code on that line.
+
+`break FILENAME:LINENUM'
+ Set a breakpoint at line LINENUM in source file FILENAME.
+
+`break FILENAME:FUNCTION'
+ Set a breakpoint at entry to function FUNCTION found in file
+ FILENAME. Specifying a file name as well as a function name is
+ superfluous except when multiple files contain similarly named
+ functions.
+
+`break *ADDRESS'
+ Set a breakpoint at address ADDRESS. You can use this to set
+ breakpoints in parts of your program which do not have debugging
+ information or source files.
+
+`break'
+ When called without any arguments, `break' sets a breakpoint at
+ the next instruction to be executed in the selected stack frame
+ (*note Examining the Stack: Stack.). In any selected frame but the
+ innermost, this will cause your program to stop as soon as control
+ returns to that frame. This is similar to the effect of a
+ `finish' command in the frame inside the selected frame--except
+ that `finish' does not leave an active breakpoint. If you use
+ `break' without an argument in the innermost frame, GDB will stop
+ the next time it reaches the current location; this may be useful
+ inside loops.
+
+ GDB normally ignores breakpoints when it resumes execution, until
+ at least one instruction has been executed. If it did not do
+ this, you would be unable to proceed past a breakpoint without
+ first disabling the breakpoint. This rule applies whether or not
+ the breakpoint already existed when your program stopped.
+
+`break ... if COND'
+ Set a breakpoint with condition COND; evaluate the expression COND
+ each time the breakpoint is reached, and stop only if the value is
+ nonzero--that is, if COND evaluates as true. `...' stands for one
+ of the possible arguments described above (or no argument)
+ specifying where to break. *Note Break conditions: Conditions,
+ for more information on breakpoint conditions.
+
+`tbreak ARGS'
+ Set a breakpoint enabled only for one stop. ARGS are the same as
+ for the `break' command, and the breakpoint is set in the same
+ way, but the breakpoint is automatically disabled after the first
+ time your program stops there. *Note Disabling breakpoints:
+ Disabling.
+
+`rbreak REGEX'
+ Set breakpoints on all functions matching the regular expression
+ REGEX. This command sets an unconditional breakpoint on all
+ matches, printing a list of all breakpoints it set. Once these
+ breakpoints are set, they are treated just like the breakpoints
+ set with the `break' command. They can be deleted, disabled, made
+ conditional, etc., in the standard ways.
+
+ When debugging C++ programs, `rbreak' is useful for setting
+ breakpoints on overloaded functions that are not members of any
+ special classes.
+
+`info breakpoints [N]'
+`info break [N]'
+`info watchpoints [N]'
+ Print a table of all breakpoints and watchpoints set and not
+ deleted, with the following columns for each breakpoint:
+
+ *Breakpoint Numbers*
+ *Type*
+ Breakpoint or watchpoint.
+
+ *Disposition*
+ Whether the breakpoint is marked to be disabled or deleted
+ when hit.
+
+ *Enabled or Disabled*
+ Enabled breakpoints are marked with `y'. `n' marks
+ breakpoints that are not enabled.
+
+ *Address*
+ Where the breakpoint is in your program, as a memory address
+
+ *What*
+ Where the breakpoint is in the source for your program, as a
+ file and line number.
+
+ If a breakpoint is conditional, `info break' shows the condition on
+ the line following the affected breakpoint; breakpoint commands,
+ if any, are listed after that.
+
+ `info break' with a breakpoint number N as argument lists only
+ that breakpoint. The convenience variable `$_' and the default
+ examining-address for the `x' command are set to the address of
+ the last breakpoint listed (*note Examining memory: Memory.).
+
+ GDB allows you to set any number of breakpoints at the same place in
+your program. There is nothing silly or meaningless about this. When
+the breakpoints are conditional, this is even useful (*note Break
+conditions: Conditions.).
+
+ GDB itself sometimes sets breakpoints in your program for special
+purposes, such as proper handling of `longjmp' (in C programs). These
+internal breakpoints are assigned negative numbers, starting with `-1';
+`info breakpoints' does not display them.
+
+ You can see these breakpoints with the GDB maintenance command
+`maint info breakpoints'.
+
+`maint info breakpoints'
+ Using the same format as `info breakpoints', display both the
+ breakpoints you've set explicitly, and those GDB is using for
+ internal purposes. Internal breakpoints are shown with negative
+ breakpoint numbers. The type column identifies what kind of
+ breakpoint is shown:
+
+ `breakpoint'
+ Normal, explicitly set breakpoint.
+
+ `watchpoint'
+ Normal, explicitly set watchpoint.
+
+ `longjmp'
+ Internal breakpoint, used to handle correctly stepping through
+ `longjmp' calls.
+
+ `longjmp resume'
+ Internal breakpoint at the target of a `longjmp'.
+
+ `until'
+ Temporary internal breakpoint used by the GDB `until' command.
+
+ `finish'
+ Temporary internal breakpoint used by the GDB `finish'
+ command.
+
+
+File: gdb.info, Node: Set Watchpoints, Next: Exception Handling, Prev: Set Breaks, Up: Breakpoints
+
+Setting watchpoints
+-------------------
+
+ You can use a watchpoint to stop execution whenever the value of an
+expression changes, without having to predict a particular place where
+this may happen.
+
+ Watchpoints currently execute two orders of magnitude more slowly
+than other breakpoints, but this can be well worth it to catch errors
+where you have no clue what part of your program is the culprit. Some
+processors provide special hardware to support watchpoint evaluation;
+future releases of GDB will use such hardware if it is available.
+
+`watch EXPR'
+ Set a watchpoint for an expression.
+
+`info watchpoints'
+ This command prints a list of watchpoints and breakpoints; it is
+ the same as `info break'.
+
+
+File: gdb.info, Node: Exception Handling, Next: Delete Breaks, Prev: Set Watchpoints, Up: Breakpoints
+
+Breakpoints and exceptions
+--------------------------
+
+ Some languages, such as GNU C++, implement exception handling. You
+can use GDB to examine what caused your program to raise an exception,
+and to list the exceptions your program is prepared to handle at a
+given point in time.
+
+`catch EXCEPTIONS'
+ You can set breakpoints at active exception handlers by using the
+ `catch' command. EXCEPTIONS is a list of names of exceptions to
+ catch.
+
+ You can use `info catch' to list active exception handlers. *Note
+Information about a frame: Frame Info.
+
+ There are currently some limitations to exception handling in GDB.
+These will be corrected in a future release.
+
+ * If you call a function interactively, GDB normally returns control
+ to you when the function has finished executing. If the call
+ raises an exception, however, the call may bypass the mechanism
+ that returns control to you and cause your program to simply
+ continue running until it hits a breakpoint, catches a signal that
+ GDB is listening for, or exits.
+
+ * You cannot raise an exception interactively.
+
+ * You cannot interactively install an exception handler.
+
+ Sometimes `catch' is not the best way to debug exception handling:
+if you need to know exactly where an exception is raised, it is better
+to stop *before* the exception handler is called, since that way you
+can see the stack before any unwinding takes place. If you set a
+breakpoint in an exception handler instead, it may not be easy to find
+out where the exception was raised.
+
+ To stop just before an exception handler is called, you need some
+knowledge of the implementation. In the case of GNU C++, exceptions are
+raised by calling a library function named `__raise_exception' which
+has the following ANSI C interface:
+
+ /* ADDR is where the exception identifier is stored.
+ ID is the exception identifier. */
+ void __raise_exception (void **ADDR, void *ID);
+
+To make the debugger catch all exceptions before any stack unwinding
+takes place, set a breakpoint on `__raise_exception' (*note
+Breakpoints; watchpoints; and exceptions: Breakpoints.).
+
+ With a conditional breakpoint (*note Break conditions: Conditions.)
+that depends on the value of ID, you can stop your program when a
+specific exception is raised. You can use multiple conditional
+breakpoints to stop your program when any of a number of exceptions are
+raised.
+
+
+File: gdb.info, Node: Delete Breaks, Next: Disabling, Prev: Exception Handling, Up: Breakpoints
+
+Deleting breakpoints
+--------------------
+
+ It is often necessary to eliminate a breakpoint or watchpoint once it
+has done its job and you no longer want your program to stop there.
+This is called "deleting" the breakpoint. A breakpoint that has been
+deleted no longer exists; it is forgotten.
+
+ With the `clear' command you can delete breakpoints according to
+where they are in your program. With the `delete' command you can
+delete individual breakpoints or watchpoints by specifying their
+breakpoint numbers.
+
+ It is not necessary to delete a breakpoint to proceed past it. GDB
+automatically ignores breakpoints on the first instruction to be
+executed when you continue execution without changing the execution
+address.
+
+`clear'
+ Delete any breakpoints at the next instruction to be executed in
+ the selected stack frame (*note Selecting a frame: Selection.).
+ When the innermost frame is selected, this is a good way to delete
+ a breakpoint where your program just stopped.
+
+`clear FUNCTION'
+`clear FILENAME:FUNCTION'
+ Delete any breakpoints set at entry to the function FUNCTION.
+
+`clear LINENUM'
+`clear FILENAME:LINENUM'
+ Delete any breakpoints set at or within the code of the specified
+ line.
+
+`delete [breakpoints] [BNUMS...]'
+ Delete the breakpoints or watchpoints of the numbers specified as
+ arguments. If no argument is specified, delete all breakpoints
+ (GDB asks confirmation, unless you have `set confirm off'). You
+ can abbreviate this command as `d'.
+
+
+File: gdb.info, Node: Disabling, Next: Conditions, Prev: Delete Breaks, Up: Breakpoints
+
+Disabling breakpoints
+---------------------
+
+ Rather than deleting a breakpoint or watchpoint, you might prefer to
+"disable" it. This makes the breakpoint inoperative as if it had been
+deleted, but remembers the information on the breakpoint so that you
+can "enable" it again later.
+
+ You disable and enable breakpoints and watchpoints with the `enable'
+and `disable' commands, optionally specifying one or more breakpoint
+numbers as arguments. Use `info break' or `info watch' to print a list
+of breakpoints or watchpoints if you do not know which numbers to use.
+
+ A breakpoint or watchpoint can have any of four different states of
+enablement:
+
+ * Enabled. The breakpoint will stop your program. A breakpoint set
+ with the `break' command starts out in this state.
+
+ * Disabled. The breakpoint has no effect on your program.
+
+ * Enabled once. The breakpoint will stop your program, but when it
+ does so it will become disabled. A breakpoint set with the
+ `tbreak' command starts out in this state.
+
+ * Enabled for deletion. The breakpoint will stop your program, but
+ immediately after it does so it will be deleted permanently.
+
+ You can use the following commands to enable or disable breakpoints
+and watchpoints:
+
+`disable [breakpoints] [BNUMS...]'
+ Disable the specified breakpoints--or all breakpoints, if none are
+ listed. A disabled breakpoint has no effect but is not forgotten.
+ All options such as ignore-counts, conditions and commands are
+ remembered in case the breakpoint is enabled again later. You may
+ abbreviate `disable' as `dis'.
+
+`enable [breakpoints] [BNUMS...]'
+ Enable the specified breakpoints (or all defined breakpoints).
+ They become effective once again in stopping your program.
+
+`enable [breakpoints] once BNUMS...'
+ Enable the specified breakpoints temporarily. Each will be
+ disabled again the next time it stops your program.
+
+`enable [breakpoints] delete BNUMS...'
+ Enable the specified breakpoints to work once and then die. Each
+ of the breakpoints will be deleted the next time it stops your
+ program.
+
+ Save for a breakpoint set with `tbreak' (*note Setting breakpoints:
+Set Breaks.), breakpoints that you set are initially enabled;
+subsequently, they become disabled or enabled only when you use one of
+the commands above. (The command `until' can set and delete a
+breakpoint of its own, but it will not change the state of your other
+breakpoints; see *Note Continuing and stepping: Continuing and
+Stepping.)
+
+
+File: gdb.info, Node: Conditions, Next: Break Commands, Prev: Disabling, Up: Breakpoints
+
+Break conditions
+----------------
+
+ The simplest sort of breakpoint breaks every time your program
+reaches a specified place. You can also specify a "condition" for a
+breakpoint. A condition is just a Boolean expression in your
+programming language (*note Expressions: Expressions.). A breakpoint
+with a condition evaluates the expression each time your program
+reaches it, and your program stops only if the condition is *true*.
+
+ This is the converse of using assertions for program validation; in
+that situation, you want to stop when the assertion is violated--that
+is, when the condition is false. In C, if you want to test an
+assertion expressed by the condition ASSERT, you should set the
+condition `! ASSERT' on the appropriate breakpoint.
+
+ Conditions are also accepted for watchpoints; you may not need them,
+since a watchpoint is inspecting the value of an expression anyhow--but
+it might be simpler, say, to just set a watchpoint on a variable name,
+and specify a condition that tests whether the new value is an
+interesting one.
+
+ Break conditions can have side effects, and may even call functions
+in your program. This can be useful, for example, to activate functions
+that log program progress, or to use your own print functions to format
+special data structures. The effects are completely predictable unless
+there is another enabled breakpoint at the same address. (In that
+case, GDB might see the other breakpoint first and stop your program
+without checking the condition of this one.) Note that breakpoint
+commands are usually more convenient and flexible for the purpose of
+performing side effects when a breakpoint is reached (*note Breakpoint
+command lists: Break Commands.).
+
+ Break conditions can be specified when a breakpoint is set, by using
+`if' in the arguments to the `break' command. *Note Setting
+breakpoints: Set Breaks. They can also be changed at any time with the
+`condition' command. The `watch' command does not recognize the `if'
+keyword; `condition' is the only way to impose a further condition on a
+watchpoint.
+
+`condition BNUM EXPRESSION'
+ Specify EXPRESSION as the break condition for breakpoint or
+ watchpoint number BNUM. From now on, this breakpoint will stop
+ your program only if the value of EXPRESSION is true (nonzero, in
+ C). When you use `condition', GDB checks EXPRESSION immediately
+ for syntactic correctness, and to determine whether symbols in it
+ have referents in the context of your breakpoint. GDB does not
+ actually evaluate EXPRESSION at the time the `condition' command
+ is given, however. *Note Expressions: Expressions.
+
+`condition BNUM'
+ Remove the condition from breakpoint number BNUM. It becomes an
+ ordinary unconditional breakpoint.
+
+ A special case of a breakpoint condition is to stop only when the
+breakpoint has been reached a certain number of times. This is so
+useful that there is a special way to do it, using the "ignore count"
+of the breakpoint. Every breakpoint has an ignore count, which is an
+integer. Most of the time, the ignore count is zero, and therefore has
+no effect. But if your program reaches a breakpoint whose ignore count
+is positive, then instead of stopping, it just decrements the ignore
+count by one and continues. As a result, if the ignore count value is
+N, the breakpoint will not stop the next N times it is reached.
+
+`ignore BNUM COUNT'
+ Set the ignore count of breakpoint number BNUM to COUNT. The next
+ COUNT times the breakpoint is reached, your program's execution
+ will not stop; other than to decrement the ignore count, GDB takes
+ no action.
+
+ To make the breakpoint stop the next time it is reached, specify a
+ count of zero.
+
+ When you use `continue' to resume execution of your program from a
+ breakpoint, you can specify an ignore count directly as an
+ argument to `continue', rather than using `ignore'. *Note
+ Continuing and stepping: Continuing and Stepping.
+
+ If a breakpoint has a positive ignore count and a condition, the
+ condition is not checked. Once the ignore count reaches zero, the
+ condition will be checked.
+
+ You could achieve the effect of the ignore count with a condition
+ such as `$foo-- <= 0' using a debugger convenience variable that
+ is decremented each time. *Note Convenience variables:
+ Convenience Vars.
+
+
+File: gdb.info, Node: Break Commands, Next: Breakpoint Menus, Prev: Conditions, Up: Breakpoints
+
+Breakpoint command lists
+------------------------
+
+ You can give any breakpoint (or watchpoint) a series of commands to
+execute when your program stops due to that breakpoint. For example,
+you might want to print the values of certain expressions, or enable
+other breakpoints.
+
+`commands [BNUM]'
+`... COMMAND-LIST ...'
+`end'
+ Specify a list of commands for breakpoint number BNUM. The
+ commands themselves appear on the following lines. Type a line
+ containing just `end' to terminate the commands.
+
+ To remove all commands from a breakpoint, type `commands' and
+ follow it immediately with `end'; that is, give no commands.
+
+ With no BNUM argument, `commands' refers to the last breakpoint or
+ watchpoint set (not to the breakpoint most recently encountered).
+
+ Pressing RET as a means of repeating the last GDB command is
+disabled within a COMMAND-LIST.
+
+ You can use breakpoint commands to start your program up again.
+Simply use the `continue' command, or `step', or any other command that
+resumes execution.
+
+ Any other commands in the command list, after a command that resumes
+execution, are ignored. This is because any time you resume execution
+(even with a simple `next' or `step'), you may encounter another
+breakpoint--which could have its own command list, leading to
+ambiguities about which list to execute.
+
+ If the first command you specify in a command list is `silent', the
+usual message about stopping at a breakpoint is not printed. This may
+be desirable for breakpoints that are to print a specific message and
+then continue. If none of the remaining commands print anything, you
+will see no sign that the breakpoint was reached. `silent' is
+meaningful only at the beginning of a breakpoint command list.
+
+ The commands `echo', `output', and `printf' allow you to print
+precisely controlled output, and are often useful in silent
+breakpoints. *Note Commands for controlled output: Output.
+
+ For example, here is how you could use breakpoint commands to print
+the value of `x' at entry to `foo' whenever `x' is positive.
+
+ break foo if x>0
+ commands
+ silent
+ printf "x is %d\n",x
+ cont
+ end
+
+ One application for breakpoint commands is to compensate for one bug
+so you can test for another. Put a breakpoint just after the erroneous
+line of code, give it a condition to detect the case in which something
+erroneous has been done, and give it commands to assign correct values
+to any variables that need them. End with the `continue' command so
+that your program does not stop, and start with the `silent' command so
+that no output is produced. Here is an example:
+
+ break 403
+ commands
+ silent
+ set x = y + 4
+ cont
+ end
+
+
+File: gdb.info, Node: Breakpoint Menus, Next: Error in Breakpoints, Prev: Break Commands, Up: Breakpoints
+
+Breakpoint menus
+----------------
+
+ Some programming languages (notably C++) permit a single function
+name to be defined several times, for application in different contexts.
+This is called "overloading". When a function name is overloaded,
+`break FUNCTION' is not enough to tell GDB where you want a breakpoint.
+If you realize this will be a problem, you can use something like
+`break FUNCTION(TYPES)' to specify which particular version of the
+function you want. Otherwise, GDB offers you a menu of numbered
+choices for different possible breakpoints, and waits for your
+selection with the prompt `>'. The first two options are always `[0]
+cancel' and `[1] all'. Typing `1' sets a breakpoint at each definition
+of FUNCTION, and typing `0' aborts the `break' command without setting
+any new breakpoints.
+
+ For example, the following session excerpt shows an attempt to set a
+breakpoint at the overloaded symbol `String::after'. We choose three
+particular definitions of that function name:
+
+ (gdb) b String::after
+ [0] cancel
+ [1] all
+ [2] file:String.cc; line number:867
+ [3] file:String.cc; line number:860
+ [4] file:String.cc; line number:875
+ [5] file:String.cc; line number:853
+ [6] file:String.cc; line number:846
+ [7] file:String.cc; line number:735
+ > 2 4 6
+ Breakpoint 1 at 0xb26c: file String.cc, line 867.
+ Breakpoint 2 at 0xb344: file String.cc, line 875.
+ Breakpoint 3 at 0xafcc: file String.cc, line 846.
+ Multiple breakpoints were set.
+ Use the "delete" command to delete unwanted
+ breakpoints.
+ (gdb)
+
+
+File: gdb.info, Node: Error in Breakpoints, Prev: Breakpoint Menus, Up: Breakpoints
+
+"Cannot insert breakpoints"
+---------------------------
+
+ Under some operating systems, breakpoints cannot be used in a
+program if any other process is running that program. In this
+situation, attempting to run or continue a program with a breakpoint
+causes GDB to stop the other process.
+
+ When this happens, you have three ways to proceed:
+
+ 1. Remove or disable the breakpoints, then continue.
+
+ 2. Suspend GDB, and copy the file containing your program to a new
+ name. Resume GDB and use the `exec-file' command to specify that
+ GDB should run your program under that name. Then start your
+ program again.
+
+ 3. Relink your program so that the text segment is nonsharable, using
+ the linker option `-N'. The operating system limitation may not
+ apply to nonsharable executables.
+
+
+File: gdb.info, Node: Continuing and Stepping, Next: Signals, Prev: Breakpoints, Up: Stopping
+
+Continuing and stepping
+=======================
+
+ "Continuing" means resuming program execution until your program
+completes normally. In contrast, "stepping" means executing just one
+more "step" of your program, where "step" may mean either one line of
+source code, or one machine instruction (depending on what particular
+command you use). Either when continuing or when stepping, your
+program may stop even sooner, due to a breakpoint or a signal. (If due
+to a signal, you may want to use `handle', or use `signal 0' to resume
+execution. *Note Signals: Signals.)
+
+`continue [IGNORE-COUNT]'
+`c [IGNORE-COUNT]'
+`fg [IGNORE-COUNT]'
+ Resume program execution, at the address where your program last
+ stopped; any breakpoints set at that address are bypassed. The
+ optional argument IGNORE-COUNT allows you to specify a further
+ number of times to ignore a breakpoint at this location; its
+ effect is like that of `ignore' (*note Break conditions:
+ Conditions.).
+
+ The argument IGNORE-COUNT is meaningful only when your program
+ stopped due to a breakpoint. At other times, the argument to
+ `continue' is ignored.
+
+ The synonyms `c' and `fg' are provided purely for convenience, and
+ have exactly the same behavior as `continue'.
+
+ To resume execution at a different place, you can use `return'
+(*note Returning from a function: Returning.) to go back to the calling
+function; or `jump' (*note Continuing at a different address: Jumping.)
+to go to an arbitrary location in your program.
+
+ A typical technique for using stepping is to set a breakpoint (*note
+Breakpoints; watchpoints; and exceptions: Breakpoints.) at the
+beginning of the function or the section of your program where a
+problem is believed to lie, run your program until it stops at that
+breakpoint, and then step through the suspect area, examining the
+variables that are interesting, until you see the problem happen.
+
+`step'
+ Continue running your program until control reaches a different
+ source line, then stop it and return control to GDB. This command
+ is abbreviated `s'.
+
+ *Warning:* If you use the `step' command while control is
+ within a function that was compiled without debugging
+ information, execution proceeds until control reaches a
+ function that does have debugging information.
+
+`step COUNT'
+ Continue running as in `step', but do so COUNT times. If a
+ breakpoint is reached, or a signal not related to stepping occurs
+ before COUNT steps, stepping stops right away.
+
+`next [COUNT]'
+ Continue to the next source line in the current (innermost) stack
+ frame. Similar to `step', but any function calls appearing within
+ the line of code are executed without stopping. Execution stops
+ when control reaches a different line of code at the stack level
+ which was executing when the `next' command was given. This
+ command is abbreviated `n'.
+
+ An argument COUNT is a repeat count, as for `step'.
+
+ `next' within a function that lacks debugging information acts like
+ `step', but any function calls appearing within the code of the
+ function are executed without stopping.
+
+`finish'
+ Continue running until just after function in the selected stack
+ frame returns. Print the returned value (if any).
+
+ Contrast this with the `return' command (*note Returning from a
+ function: Returning.).
+
+`until'
+`u'
+ Continue running until a source line past the current line, in the
+ current stack frame, is reached. This command is used to avoid
+ single stepping through a loop more than once. It is like the
+ `next' command, except that when `until' encounters a jump, it
+ automatically continues execution until the program counter is
+ greater than the address of the jump.
+
+ This means that when you reach the end of a loop after single
+ stepping though it, `until' will cause your program to continue
+ execution until the loop is exited. In contrast, a `next' command
+ at the end of a loop will simply step back to the beginning of the
+ loop, which would force you to step through the next iteration.
+
+ `until' always stops your program if it attempts to exit the
+ current stack frame.
+
+ `until' may produce somewhat counterintuitive results if the order
+ of machine code does not match the order of the source lines. For
+ example, in the following excerpt from a debugging session, the `f'
+ (`frame') command shows that execution is stopped at line `206';
+ yet when we use `until', we get to line `195':
+
+ (gdb) f
+ #0 main (argc=4, argv=0xf7fffae8) at m4.c:206
+ 206 expand_input();
+ (gdb) until
+ 195 for ( ; argc > 0; NEXTARG) {
+
+ This happened because, for execution efficiency, the compiler had
+ generated code for the loop closure test at the end, rather than
+ the start, of the loop--even though the test in a C `for'-loop is
+ written before the body of the loop. The `until' command appeared
+ to step back to the beginning of the loop when it advanced to this
+ expression; however, it has not really gone to an earlier
+ statement--not in terms of the actual machine code.
+
+ `until' with no argument works by means of single instruction
+ stepping, and hence is slower than `until' with an argument.
+
+`until LOCATION'
+`u LOCATION'
+ Continue running your program until either the specified location
+ is reached, or the current stack frame returns. LOCATION is any of
+ the forms of argument acceptable to `break' (*note Setting
+ breakpoints: Set Breaks.). This form of the command uses
+ breakpoints, and hence is quicker than `until' without an argument.
+
+`stepi'
+`si'
+ Execute one machine instruction, then stop and return to the
+ debugger.
+
+ It is often useful to do `display/i $pc' when stepping by machine
+ instructions. This will cause the next instruction to be executed
+ to be displayed automatically at each stop. *Note Automatic
+ display: Auto Display.
+
+ An argument is a repeat count, as in `step'.
+
+`nexti'
+`ni'
+ Execute one machine instruction, but if it is a function call,
+ proceed until the function returns.
+
+ An argument is a repeat count, as in `next'.
+
+
+File: gdb.info, Node: Signals, Prev: Continuing and Stepping, Up: Stopping
+
+Signals
+=======
+
+ A signal is an asynchronous event that can happen in a program. The
+operating system defines the possible kinds of signals, and gives each
+kind a name and a number. For example, in Unix `SIGINT' is the signal
+a program gets when you type an interrupt (often `C-c'); `SIGSEGV' is
+the signal a program gets from referencing a place in memory far away
+from all the areas in use; `SIGALRM' occurs when the alarm clock timer
+goes off (which happens only if your program has requested an alarm).
+
+ Some signals, including `SIGALRM', are a normal part of the
+functioning of your program. Others, such as `SIGSEGV', indicate
+errors; these signals are "fatal" (kill your program immediately) if the
+program has not specified in advance some other way to handle the
+signal. `SIGINT' does not indicate an error in your program, but it is
+normally fatal so it can carry out the purpose of the interrupt: to
+kill the program.
+
+ GDB has the ability to detect any occurrence of a signal in your
+program. You can tell GDB in advance what to do for each kind of
+signal.
+
+ Normally, GDB is set up to ignore non-erroneous signals like
+`SIGALRM' (so as not to interfere with their role in the functioning of
+your program) but to stop your program immediately whenever an error
+signal happens. You can change these settings with the `handle'
+command.
+
+`info signals'
+ Print a table of all the kinds of signals and how GDB has been
+ told to handle each one. You can use this to see the signal
+ numbers of all the defined types of signals.
+
+`handle SIGNAL KEYWORDS...'
+ Change the way GDB handles signal SIGNAL. SIGNAL can be the
+ number of a signal or its name (with or without the `SIG' at the
+ beginning). The KEYWORDS say what change to make.
+
+ The keywords allowed by the `handle' command can be abbreviated.
+Their full names are:
+
+`nostop'
+ GDB should not stop your program when this signal happens. It may
+ still print a message telling you that the signal has come in.
+
+`stop'
+ GDB should stop your program when this signal happens. This
+ implies the `print' keyword as well.
+
+`print'
+ GDB should print a message when this signal happens.
+
+`noprint'
+ GDB should not mention the occurrence of the signal at all. This
+ implies the `nostop' keyword as well.
+
+`pass'
+ GDB should allow your program to see this signal; your program
+ will be able to handle the signal, or may be terminated if the
+ signal is fatal and not handled.
+
+`nopass'
+ GDB should not allow your program to see this signal.
+
+ When a signal stops your program, the signal is not visible until you
+continue. Your program will see the signal then, if `pass' is in
+effect for the signal in question *at that time*. In other words,
+after GDB reports a signal, you can use the `handle' command with
+`pass' or `nopass' to control whether that signal will be seen by your
+program when you later continue it.
+
+ You can also use the `signal' command to prevent your program from
+seeing a signal, or cause it to see a signal it normally would not see,
+or to give it any signal at any time. For example, if your program
+stopped due to some sort of memory reference error, you might store
+correct values into the erroneous variables and continue, hoping to see
+more execution; but your program would probably terminate immediately as
+a result of the fatal signal once it saw the signal. To prevent this,
+you can continue with `signal 0'. *Note Giving your program a signal:
+Signaling.
+
+
+File: gdb.info, Node: Stack, Next: Source, Prev: Stopping, Up: Top
+
+Examining the Stack
+*******************
+
+ When your program has stopped, the first thing you need to know is
+where it stopped and how it got there.
+
+ Each time your program performs a function call, the information
+about where in your program the call was made from is saved in a block
+of data called a "stack frame". The frame also contains the arguments
+of the call and the local variables of the function that was called.
+All the stack frames are allocated in a region of memory called the
+"call stack".
+
+ When your program stops, the GDB commands for examining the stack
+allow you to see all of this information.
+
+ One of the stack frames is "selected" by GDB and many GDB commands
+refer implicitly to the selected frame. In particular, whenever you
+ask GDB for the value of a variable in your program, the value is found
+in the selected frame. There are special GDB commands to select
+whichever frame you are interested in.
+
+ When your program stops, GDB automatically selects the currently
+executing frame and describes it briefly as the `frame' command does
+(*note Information about a frame: Frame Info.).
+
+* Menu:
+
+* Frames:: Stack frames
+* Backtrace:: Backtraces
+* Selection:: Selecting a frame
+* Frame Info:: Information on a frame
+
+* MIPS Stack:: MIPS machines and the function stack
+
+
+File: gdb.info, Node: Frames, Next: Backtrace, Up: Stack
+
+Stack frames
+============
+
+ The call stack is divided up into contiguous pieces called "stack
+frames", or "frames" for short; each frame is the data associated with
+one call to one function. The frame contains the arguments given to
+the function, the function's local variables, and the address at which
+the function is executing.
+
+ When your program is started, the stack has only one frame, that of
+the function `main'. This is called the "initial" frame or the
+"outermost" frame. Each time a function is called, a new frame is
+made. Each time a function returns, the frame for that function
+invocation is eliminated. If a function is recursive, there can be
+many frames for the same function. The frame for the function in which
+execution is actually occurring is called the "innermost" frame. This
+is the most recently created of all the stack frames that still exist.
+
+ Inside your program, stack frames are identified by their addresses.
+A stack frame consists of many bytes, each of which has its own
+address; each kind of computer has a convention for choosing one of
+those bytes whose address serves as the address of the frame. Usually
+this address is kept in a register called the "frame pointer register"
+while execution is going on in that frame.
+
+ GDB assigns numbers to all existing stack frames, starting with zero
+for the innermost frame, one for the frame that called it, and so on
+upward. These numbers do not really exist in your program; they are
+assigned by GDB to give you a way of designating stack frames in GDB
+commands.
+
+ Some compilers provide a way to compile functions so that they
+operate without stack frames. (For example, the `gcc' option
+`-fomit-frame-pointer' will generate functions without a frame.) This
+is occasionally done with heavily used library functions to save the
+frame setup time. GDB has limited facilities for dealing with these
+function invocations. If the innermost function invocation has no
+stack frame, GDB will nevertheless regard it as though it had a
+separate frame, which is numbered zero as usual, allowing correct
+tracing of the function call chain. However, GDB has no provision for
+frameless functions elsewhere in the stack.
+
+
+File: gdb.info, Node: Backtrace, Next: Selection, Prev: Frames, Up: Stack
+
+Backtraces
+==========
+
+ A backtrace is a summary of how your program got where it is. It
+shows one line per frame, for many frames, starting with the currently
+executing frame (frame zero), followed by its caller (frame one), and
+on up the stack.
+
+`backtrace'
+`bt'
+ Print a backtrace of the entire stack: one line per frame for all
+ frames in the stack.
+
+ You can stop the backtrace at any time by typing the system
+ interrupt character, normally `C-c'.
+
+`backtrace N'
+`bt N'
+ Similar, but print only the innermost N frames.
+
+`backtrace -N'
+`bt -N'
+ Similar, but print only the outermost N frames.
+
+ The names `where' and `info stack' (abbreviated `info s') are
+additional aliases for `backtrace'.
+
+ Each line in the backtrace shows the frame number and the function
+name. The program counter value is also shown--unless you use `set
+print address off'. The backtrace also shows the source file name and
+line number, as well as the arguments to the function. The program
+counter value is omitted if it is at the beginning of the code for that
+line number.
+
+ Here is an example of a backtrace. It was made with the command `bt
+3', so it shows the innermost three frames.
+
+ #0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8)
+ at builtin.c:993
+ #1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242
+ #2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08)
+ at macro.c:71
+ (More stack frames follow...)
+
+The display for frame zero does not begin with a program counter value,
+indicating that your program has stopped at the beginning of the code
+for line `993' of `builtin.c'.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-3 b/gnu/usr.bin/gdb/doc/gdb.info-3
new file mode 100644
index 000000000000..aea5862a3052
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-3
@@ -0,0 +1,1264 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Selection, Next: Frame Info, Prev: Backtrace, Up: Stack
+
+Selecting a frame
+=================
+
+ Most commands for examining the stack and other data in your program
+work on whichever stack frame is selected at the moment. Here are the
+commands for selecting a stack frame; all of them finish by printing a
+brief description of the stack frame just selected.
+
+`frame N'
+`f N'
+ Select frame number N. Recall that frame zero is the innermost
+ (currently executing) frame, frame one is the frame that called the
+ innermost one, and so on. The highest-numbered frame is the one
+ for `main'.
+
+`frame ADDR'
+`f ADDR'
+ Select the frame at address ADDR. This is useful mainly if the
+ chaining of stack frames has been damaged by a bug, making it
+ impossible for GDB to assign numbers properly to all frames. In
+ addition, this can be useful when your program has multiple stacks
+ and switches between them.
+
+ On the SPARC architecture, `frame' needs two addresses to select
+ an arbitrary frame: a frame pointer and a stack pointer.
+
+`up N'
+ Move N frames up the stack. For positive numbers N, this advances
+ toward the outermost frame, to higher frame numbers, to frames
+ that have existed longer. N defaults to one.
+
+`down N'
+ Move N frames down the stack. For positive numbers N, this
+ advances toward the innermost frame, to lower frame numbers, to
+ frames that were created more recently. N defaults to one. You
+ may abbreviate `down' as `do'.
+
+ All of these commands end by printing two lines of output describing
+the frame. The first line shows the frame number, the function name,
+the arguments, and the source file and line number of execution in that
+frame. The second line shows the text of that source line.
+
+ For example:
+ (gdb) up
+ #1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
+ at env.c:10
+ 10 read_input_file (argv[i]);
+
+ After such a printout, the `list' command with no arguments will
+print ten lines centered on the point of execution in the frame. *Note
+Printing source lines: List.
+
+`up-silently N'
+`down-silently N'
+ These two commands are variants of `up' and `down', respectively;
+ they differ in that they do their work silently, without causing
+ display of the new frame. They are intended primarily for use in
+ GDB command scripts, where the output might be unnecessary and
+ distracting.
+
+
+File: gdb.info, Node: Frame Info, Next: MIPS Stack, Prev: Selection, Up: Stack
+
+Information about a frame
+=========================
+
+ There are several other commands to print information about the
+selected stack frame.
+
+`frame'
+`f'
+ When used without any argument, this command does not change which
+ frame is selected, but prints a brief description of the currently
+ selected stack frame. It can be abbreviated `f'. With an
+ argument, this command is used to select a stack frame. *Note
+ Selecting a frame: Selection.
+
+`info frame'
+`info f'
+ This command prints a verbose description of the selected stack
+ frame, including the address of the frame, the addresses of the
+ next frame down (called by this frame) and the next frame up
+ (caller of this frame), the language that the source code
+ corresponding to this frame was written in, the address of the
+ frame's arguments, the program counter saved in it (the address of
+ execution in the caller frame), and which registers were saved in
+ the frame. The verbose description is useful when something has
+ gone wrong that has made the stack format fail to fit the usual
+ conventions.
+
+`info frame ADDR'
+`info f ADDR'
+ Print a verbose description of the frame at address ADDR, without
+ selecting that frame. The selected frame remains unchanged by
+ this command.
+
+`info args'
+ Print the arguments of the selected frame, each on a separate line.
+
+`info locals'
+ Print the local variables of the selected frame, each on a separate
+ line. These are all variables (declared either static or
+ automatic) accessible at the point of execution of the selected
+ frame.
+
+`info catch'
+ Print a list of all the exception handlers that are active in the
+ current stack frame at the current point of execution. To see
+ other exception handlers, visit the associated frame (using the
+ `up', `down', or `frame' commands); then type `info catch'. *Note
+ Breakpoints and exceptions: Exception Handling.
+
+
+File: gdb.info, Node: MIPS Stack, Prev: Frame Info, Up: Stack
+
+MIPS machines and the function stack
+====================================
+
+ MIPS based computers use an unusual stack frame, which sometimes
+requires GDB to search backward in the object code to find the
+beginning of a function.
+
+ To improve response time (especially for embedded applications, where
+GDB may be restricted to a slow serial line for this search) you may
+want to limit the size of this search, using one of these commands:
+
+`set heuristic-fence-post LIMIT'
+ Restrict GDBN to examining at most LIMIT bytes in its search for
+ the beginning of a function. A value of `0' (the default) means
+ there is no limit.
+
+`show heuristic-fence-post'
+ Display the current limit.
+
+These commands are available *only* when GDB is configured for
+debugging programs on MIPS processors.
+
+
+File: gdb.info, Node: Source, Next: Data, Prev: Stack, Up: Top
+
+Examining Source Files
+**********************
+
+ GDB can print parts of your program's source, since the debugging
+information recorded in the program tells GDB what source files were
+used to build it. When your program stops, GDB spontaneously prints
+the line where it stopped. Likewise, when you select a stack frame
+(*note Selecting a frame: Selection.), GDB prints the line where
+execution in that frame has stopped. You can print other portions of
+source files by explicit command.
+
+ If you use GDB through its GNU Emacs interface, you may prefer to use
+Emacs facilities to view source; *note Using GDB under GNU Emacs:
+Emacs..
+
+* Menu:
+
+* List:: Printing source lines
+
+* Search:: Searching source files
+
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+
+
+File: gdb.info, Node: List, Next: Search, Up: Source
+
+Printing source lines
+=====================
+
+ To print lines from a source file, use the `list' command
+(abbreviated `l'). There are several ways to specify what part of the
+file you want to print.
+
+ Here are the forms of the `list' command most commonly used:
+
+`list LINENUM'
+ Print lines centered around line number LINENUM in the current
+ source file.
+
+`list FUNCTION'
+ Print lines centered around the beginning of function FUNCTION.
+
+`list'
+ Print more lines. If the last lines printed were printed with a
+ `list' command, this prints lines following the last lines
+ printed; however, if the last line printed was a solitary line
+ printed as part of displaying a stack frame (*note Examining the
+ Stack: Stack.), this prints lines centered around that line.
+
+`list -'
+ Print lines just before the lines last printed.
+
+ By default, GDB prints ten source lines with any of these forms of
+the `list' command. You can change this using `set listsize':
+
+`set listsize COUNT'
+ Make the `list' command display COUNT source lines (unless the
+ `list' argument explicitly specifies some other number).
+
+`show listsize'
+ Display the number of lines that `list' will currently display by
+ default.
+
+ Repeating a `list' command with RET discards the argument, so it is
+equivalent to typing just `list'. This is more useful than listing the
+same lines again. An exception is made for an argument of `-'; that
+argument is preserved in repetition so that each repetition moves up in
+the source file.
+
+ In general, the `list' command expects you to supply zero, one or two
+"linespecs". Linespecs specify source lines; there are several ways of
+writing them but the effect is always to specify some source line.
+Here is a complete description of the possible arguments for `list':
+
+`list LINESPEC'
+ Print lines centered around the line specified by LINESPEC.
+
+`list FIRST,LAST'
+ Print lines from FIRST to LAST. Both arguments are linespecs.
+
+`list ,LAST'
+ Print lines ending with LAST.
+
+`list FIRST,'
+ Print lines starting with FIRST.
+
+`list +'
+ Print lines just after the lines last printed.
+
+`list -'
+ Print lines just before the lines last printed.
+
+`list'
+ As described in the preceding table.
+
+ Here are the ways of specifying a single source line--all the kinds
+of linespec.
+
+`NUMBER'
+ Specifies line NUMBER of the current source file. When a `list'
+ command has two linespecs, this refers to the same source file as
+ the first linespec.
+
+`+OFFSET'
+ Specifies the line OFFSET lines after the last line printed. When
+ used as the second linespec in a `list' command that has two, this
+ specifies the line OFFSET lines down from the first linespec.
+
+`-OFFSET'
+ Specifies the line OFFSET lines before the last line printed.
+
+`FILENAME:NUMBER'
+ Specifies line NUMBER in the source file FILENAME.
+
+`FUNCTION'
+ Specifies the line of the open-brace that begins the body of the
+ function FUNCTION.
+
+`FILENAME:FUNCTION'
+ Specifies the line of the open-brace that begins the body of the
+ function FUNCTION in the file FILENAME. You only need the file
+ name with a function name to avoid ambiguity when there are
+ identically named functions in different source files.
+
+`*ADDRESS'
+ Specifies the line containing the program address ADDRESS.
+ ADDRESS may be any expression.
+
+
+File: gdb.info, Node: Search, Next: Source Path, Prev: List, Up: Source
+
+Searching source files
+======================
+
+ There are two commands for searching through the current source file
+for a regular expression.
+
+`forward-search REGEXP'
+`search REGEXP'
+ The command `forward-search REGEXP' checks each line, starting
+ with the one following the last line listed, for a match for
+ REGEXP. It lists the line that is found. You can use synonym
+ `search REGEXP' or abbreviate the command name as `fo'.
+
+`reverse-search REGEXP'
+ The command `reverse-search REGEXP' checks each line, starting
+ with the one before the last line listed and going backward, for a
+ match for REGEXP. It lists the line that is found. You can
+ abbreviate this command as `rev'.
+
+
+File: gdb.info, Node: Source Path, Next: Machine Code, Prev: Search, Up: Source
+
+Specifying source directories
+=============================
+
+ Executable programs sometimes do not record the directories of the
+source files from which they were compiled, just the names. Even when
+they do, the directories could be moved between the compilation and
+your debugging session. GDB has a list of directories to search for
+source files; this is called the "source path". Each time GDB wants a
+source file, it tries all the directories in the list, in the order
+they are present in the list, until it finds a file with the desired
+name. Note that the executable search path is *not* used for this
+purpose. Neither is the current working directory, unless it happens
+to be in the source path.
+
+ If GDB cannot find a source file in the source path, and the object
+program records a directory, GDB tries that directory too. If the
+source path is empty, and there is no record of the compilation
+directory, GDB will, as a last resort, look in the current directory.
+
+ Whenever you reset or rearrange the source path, GDB will clear out
+any information it has cached about where source files are found, where
+each line is in the file, etc.
+
+ When you start GDB, its source path is empty. To add other
+directories, use the `directory' command.
+
+`directory DIRNAME ...'
+ Add directory DIRNAME to the front of the source path. Several
+ directory names may be given to this command, separated by `:' or
+ whitespace. You may specify a directory that is already in the
+ source path; this moves it forward, so it will be searched sooner.
+
+ You can use the string `$cdir' to refer to the compilation
+ directory (if one is recorded), and `$cwd' to refer to the current
+ working directory. `$cwd' is not the same as `.'--the former
+ tracks the current working directory as it changes during your GDB
+ session, while the latter is immediately expanded to the current
+ directory at the time you add an entry to the source path.
+
+`directory'
+ Reset the source path to empty again. This requires confirmation.
+
+`show directories'
+ Print the source path: show which directories it contains.
+
+ If your source path is cluttered with directories that are no longer
+of interest, GDB may sometimes cause confusion by finding the wrong
+versions of source. You can correct the situation as follows:
+
+ 1. Use `directory' with no argument to reset the source path to empty.
+
+ 2. Use `directory' with suitable arguments to reinstall the
+ directories you want in the source path. You can add all the
+ directories in one command.
+
+
+File: gdb.info, Node: Machine Code, Prev: Source Path, Up: Source
+
+Source and machine code
+=======================
+
+ You can use the command `info line' to map source lines to program
+addresses (and vice versa), and the command `disassemble' to display a
+range of addresses as machine instructions.
+
+`info line LINESPEC'
+ Print the starting and ending addresses of the compiled code for
+ source line LINESPEC. You can specify source lines in any of the
+ ways understood by the `list' command (*note Printing source
+ lines: List.).
+
+ For example, we can use `info line' to discover the location of the
+object code for the first line of function `m4_changequote':
+
+ (gdb) info line m4_changecom
+ Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
+
+We can also inquire (using `*ADDR' as the form for LINESPEC) what
+source line covers a particular address:
+ (gdb) info line *0x63ff
+ Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
+
+ After `info line', the default address for the `x' command is
+changed to the starting address of the line, so that `x/i' is
+sufficient to begin examining the machine code (*note Examining memory:
+Memory.). Also, this address is saved as the value of the convenience
+variable `$_' (*note Convenience variables: Convenience Vars.).
+
+`disassemble'
+ This specialized command dumps a range of memory as machine
+ instructions. The default memory range is the function
+ surrounding the program counter of the selected frame. A single
+ argument to this command is a program counter value; the function
+ surrounding this value will be dumped. Two arguments specify a
+ range of addresses (first inclusive, second exclusive) to dump.
+
+ We can use `disassemble' to inspect the object code range shown in
+the last `info line' example (the example shows SPARC machine
+instructions):
+
+ (gdb) disas 0x63e4 0x6404
+ Dump of assembler code from 0x63e4 to 0x6404:
+ 0x63e4 <builtin_init+5340>: ble 0x63f8 <builtin_init+5360>
+ 0x63e8 <builtin_init+5344>: sethi %hi(0x4c00), %o0
+ 0x63ec <builtin_init+5348>: ld [%i1+4], %o0
+ 0x63f0 <builtin_init+5352>: b 0x63fc <builtin_init+5364>
+ 0x63f4 <builtin_init+5356>: ld [%o0+4], %o0
+ 0x63f8 <builtin_init+5360>: or %o0, 0x1a4, %o0
+ 0x63fc <builtin_init+5364>: call 0x9288 <path_search>
+ 0x6400 <builtin_init+5368>: nop
+ End of assembler dump.
+
+
+File: gdb.info, Node: Data, Next: Languages, Prev: Source, Up: Top
+
+Examining Data
+**************
+
+ The usual way to examine data in your program is with the `print'
+command (abbreviated `p'), or its synonym `inspect'. It evaluates and
+prints the value of an expression of the language your program is
+written in (*note Using GDB with Different Languages: Languages.).
+
+`print EXP'
+`print /F EXP'
+ EXP is an expression (in the source language). By default the
+ value of EXP is printed in a format appropriate to its data type;
+ you can choose a different format by specifying `/F', where F is a
+ letter specifying the format; *note Output formats: Output
+ Formats..
+
+`print'
+`print /F'
+ If you omit EXP, GDB displays the last value again (from the
+ "value history"; *note Value history: Value History.). This
+ allows you to conveniently inspect the same value in an
+ alternative format.
+
+ A more low-level way of examining data is with the `x' command. It
+examines data in memory at a specified address and prints it in a
+specified format. *Note Examining memory: Memory.
+
+ If you are interested in information about types, or about how the
+fields of a struct or class are declared, use the `ptype EXP' command
+rather than `print'. *Note Examining the Symbol Table: Symbols.
+
+* Menu:
+
+* Expressions:: Expressions
+* Variables:: Program variables
+* Arrays:: Artificial arrays
+* Output Formats:: Output formats
+* Memory:: Examining memory
+* Auto Display:: Automatic display
+* Print Settings:: Print settings
+* Value History:: Value history
+* Convenience Vars:: Convenience variables
+* Registers:: Registers
+
+* Floating Point Hardware:: Floating point hardware
+
+
+File: gdb.info, Node: Expressions, Next: Variables, Up: Data
+
+Expressions
+===========
+
+ `print' and many other GDB commands accept an expression and compute
+its value. Any kind of constant, variable or operator defined by the
+programming language you are using is valid in an expression in GDB.
+This includes conditional expressions, function calls, casts and string
+constants. It unfortunately does not include symbols defined by
+preprocessor `#define' commands.
+
+ Because C is so widespread, most of the expressions shown in
+examples in this manual are in C. *Note Using GDB with Different
+Languages: Languages, for information on how to use expressions in other
+languages.
+
+ In this section, we discuss operators that you can use in GDB
+expressions regardless of your programming language.
+
+ Casts are supported in all languages, not just in C, because it is so
+useful to cast a number into a pointer so as to examine a structure at
+that address in memory.
+
+ GDB supports these operators in addition to those of programming
+languages:
+
+`@'
+ `@' is a binary operator for treating parts of memory as arrays.
+ *Note Artificial arrays: Arrays, for more information.
+
+`::'
+ `::' allows you to specify a variable in terms of the file or
+ function where it is defined. *Note Program variables: Variables.
+
+`{TYPE} ADDR'
+ Refers to an object of type TYPE stored at address ADDR in memory.
+ ADDR may be any expression whose value is an integer or pointer
+ (but parentheses are required around binary operators, just as in
+ a cast). This construct is allowed regardless of what kind of
+ data is normally supposed to reside at ADDR.
+
+
+File: gdb.info, Node: Variables, Next: Arrays, Prev: Expressions, Up: Data
+
+Program variables
+=================
+
+ The most common kind of expression to use is the name of a variable
+in your program.
+
+ Variables in expressions are understood in the selected stack frame
+(*note Selecting a frame: Selection.); they must either be global (or
+static) or be visible according to the scope rules of the programming
+language from the point of execution in that frame. This means that in
+the function
+
+ foo (a)
+ int a;
+ {
+ bar (a);
+ {
+ int b = test ();
+ bar (b);
+ }
+ }
+
+you can examine and use the variable `a' whenever your program is
+executing within the function `foo', but you can only use or examine
+the variable `b' while your program is executing inside the block where
+`b' is declared.
+
+ There is an exception: you can refer to a variable or function whose
+scope is a single source file even if the current execution point is not
+in this file. But it is possible to have more than one such variable or
+function with the same name (in different source files). If that
+happens, referring to that name has unpredictable effects. If you wish,
+you can specify a static variable in a particular function or file,
+using the colon-colon notation:
+
+ FILE::VARIABLE
+ FUNCTION::VARIABLE
+
+Here FILE or FUNCTION is the name of the context for the static
+VARIABLE. In the case of file names, you can use quotes to make sure
+GDB parses the file name as a single word--for example, to print a
+global value of `x' defined in `f2.c':
+
+ (gdb) p 'f2.c'::x
+
+ This use of `::' is very rarely in conflict with the very similar
+use of the same notation in C++. GDB also supports use of the C++
+scope resolution operator in GDB expressions.
+
+ *Warning:* Occasionally, a local variable may appear to have the
+ wrong value at certain points in a function--just after entry to a
+ new scope, and just before exit.
+ You may see this problem when you are stepping by machine
+instructions. This is because on most machines, it takes more than one
+instruction to set up a stack frame (including local variable
+definitions); if you are stepping by machine instructions, variables
+may appear to have the wrong values until the stack frame is completely
+built. On exit, it usually also takes more than one machine
+instruction to destroy a stack frame; after you begin stepping through
+that group of instructions, local variable definitions may be gone.
+
+
+File: gdb.info, Node: Arrays, Next: Output Formats, Prev: Variables, Up: Data
+
+Artificial arrays
+=================
+
+ It is often useful to print out several successive objects of the
+same type in memory; a section of an array, or an array of dynamically
+determined size for which only a pointer exists in the program.
+
+ You can do this by referring to a contiguous span of memory as an
+"artificial array", using the binary operator `@'. The left operand of
+`@' should be the first element of the desired array, as an individual
+object. The right operand should be the desired length of the array.
+The result is an array value whose elements are all of the type of the
+left argument. The first element is actually the left argument; the
+second element comes from bytes of memory immediately following those
+that hold the first element, and so on. Here is an example. If a
+program says
+
+ int *array = (int *) malloc (len * sizeof (int));
+
+you can print the contents of `array' with
+
+ p *array@len
+
+ The left operand of `@' must reside in memory. Array values made
+with `@' in this way behave just like other arrays in terms of
+subscripting, and are coerced to pointers when used in expressions.
+Artificial arrays most often appear in expressions via the value history
+(*note Value history: Value History.), after printing one out.
+
+ Sometimes the artificial array mechanism is not quite enough; in
+moderately complex data structures, the elements of interest may not
+actually be adjacent--for example, if you are interested in the values
+of pointers in an array. One useful work-around in this situation is
+to use a convenience variable (*note Convenience variables: Convenience
+Vars.) as a counter in an expression that prints the first interesting
+value, and then repeat that expression via RET. For instance, suppose
+you have an array `dtab' of pointers to structures, and you are
+interested in the values of a field `fv' in each structure. Here is an
+example of what you might type:
+
+ set $i = 0
+ p dtab[$i++]->fv
+ RET
+ RET
+ ...
+
+
+File: gdb.info, Node: Output Formats, Next: Memory, Prev: Arrays, Up: Data
+
+Output formats
+==============
+
+ By default, GDB prints a value according to its data type. Sometimes
+this is not what you want. For example, you might want to print a
+number in hex, or a pointer in decimal. Or you might want to view data
+in memory at a certain address as a character string or as an
+instruction. To do these things, specify an "output format" when you
+print a value.
+
+ The simplest use of output formats is to say how to print a value
+already computed. This is done by starting the arguments of the
+`print' command with a slash and a format letter. The format letters
+supported are:
+
+`x'
+ Regard the bits of the value as an integer, and print the integer
+ in hexadecimal.
+
+`d'
+ Print as integer in signed decimal.
+
+`u'
+ Print as integer in unsigned decimal.
+
+`o'
+ Print as integer in octal.
+
+`t'
+ Print as integer in binary. The letter `t' stands for "two". (1)
+
+`a'
+ Print as an address, both absolute in hex and as an offset from the
+ nearest preceding symbol. This format can be used to discover
+ where (in what function) an unknown address is located:
+
+ (gdb) p/a 0x54320
+ $3 = 0x54320 <_initialize_vx+396>
+
+`c'
+ Regard as an integer and print it as a character constant.
+
+`f'
+ Regard the bits of the value as a floating point number and print
+ using typical floating point syntax.
+
+ For example, to print the program counter in hex (*note
+Registers::.), type
+
+ p/x $pc
+
+Note that no space is required before the slash; this is because command
+names in GDB cannot contain a slash.
+
+ To reprint the last value in the value history with a different
+format, you can use the `print' command with just a format and no
+expression. For example, `p/x' reprints the last value in hex.
+
+ ---------- Footnotes ----------
+
+ (1) `b' cannot be used because these format letters are also used
+with the `x' command, where `b' stands for "byte"; *note Examining
+memory: Memory..
+
+
+File: gdb.info, Node: Memory, Next: Auto Display, Prev: Output Formats, Up: Data
+
+Examining memory
+================
+
+ You can use the command `x' (for "examine") to examine memory in any
+of several formats, independently of your program's data types.
+
+`x/NFU ADDR'
+`x ADDR'
+`x'
+ Use the `x' command to examine memory.
+
+ N, F, and U are all optional parameters that specify how much memory
+to display and how to format it; ADDR is an expression giving the
+address where you want to start displaying memory. If you use defaults
+for NFU, you need not type the slash `/'. Several commands set
+convenient defaults for ADDR.
+
+N, the repeat count
+ The repeat count is a decimal integer; the default is 1. It
+ specifies how much memory (counting by units U) to display.
+
+F, the display format
+ The display format is one of the formats used by `print', or `s'
+ (null-terminated string) or `i' (machine instruction). The
+ default is `x' (hexadecimal) initially, or the format from the
+ last time you used either `x' or `print'.
+
+U, the unit size
+ The unit size is any of
+
+ `b'
+ Bytes.
+
+ `h'
+ Halfwords (two bytes).
+
+ `w'
+ Words (four bytes). This is the initial default.
+
+ `g'
+ Giant words (eight bytes).
+
+ Each time you specify a unit size with `x', that size becomes the
+ default unit the next time you use `x'. (For the `s' and `i'
+ formats, the unit size is ignored and is normally not written.)
+
+ADDR, starting display address
+ ADDR is the address where you want GDB to begin displaying memory.
+ The expression need not have a pointer value (though it may); it
+ is always interpreted as an integer address of a byte of memory.
+ *Note Expressions: Expressions, for more information on
+ expressions. The default for ADDR is usually just after the last
+ address examined--but several other commands also set the default
+ address: `info breakpoints' (to the address of the last breakpoint
+ listed), `info line' (to the starting address of a line), and
+ `print' (if you use it to display a value from memory).
+
+ For example, `x/3uh 0x54320' is a request to display three halfwords
+(`h') of memory, formatted as unsigned decimal integers (`u'), starting
+at address `0x54320'. `x/4xw $sp' prints the four words (`w') of
+memory above the stack pointer (here, `$sp'; *note Registers::.) in
+hexadecimal (`x').
+
+ Since the letters indicating unit sizes are all distinct from the
+letters specifying output formats, you do not have to remember whether
+unit size or format comes first; either order will work. The output
+specifications `4xw' and `4wx' mean exactly the same thing. (However,
+the count N must come first; `wx4' will not work.)
+
+ Even though the unit size U is ignored for the formats `s' and `i',
+you might still want to use a count N; for example, `3i' specifies that
+you want to see three machine instructions, including any operands.
+The command `disassemble' gives an alternative way of inspecting
+machine instructions; *note Source and machine code: Machine Code..
+
+ All the defaults for the arguments to `x' are designed to make it
+easy to continue scanning memory with minimal specifications each time
+you use `x'. For example, after you have inspected three machine
+instructions with `x/3i ADDR', you can inspect the next seven with just
+`x/7'. If you use RET to repeat the `x' command, the repeat count N is
+used again; the other arguments default as for successive uses of `x'.
+
+ The addresses and contents printed by the `x' command are not saved
+in the value history because there is often too much of them and they
+would get in the way. Instead, GDB makes these values available for
+subsequent use in expressions as values of the convenience variables
+`$_' and `$__'. After an `x' command, the last address examined is
+available for use in expressions in the convenience variable `$_'. The
+contents of that address, as examined, are available in the convenience
+variable `$__'.
+
+ If the `x' command has a repeat count, the address and contents saved
+are from the last memory unit printed; this is not the same as the last
+address printed if several units were printed on the last line of
+output.
+
+
+File: gdb.info, Node: Auto Display, Next: Print Settings, Prev: Memory, Up: Data
+
+Automatic display
+=================
+
+ If you find that you want to print the value of an expression
+frequently (to see how it changes), you might want to add it to the
+"automatic display list" so that GDB will print its value each time
+your program stops. Each expression added to the list is given a
+number to identify it; to remove an expression from the list, you
+specify that number. The automatic display looks like this:
+
+ 2: foo = 38
+ 3: bar[5] = (struct hack *) 0x3804
+
+This display shows item numbers, expressions and their current values.
+As with displays you request manually using `x' or `print', you can
+specify the output format you prefer; in fact, `display' decides
+whether to use `print' or `x' depending on how elaborate your format
+specification is--it uses `x' if you specify a unit size, or one of the
+two formats (`i' and `s') that are only supported by `x'; otherwise it
+uses `print'.
+
+`display EXP'
+ Add the expression EXP to the list of expressions to display each
+ time your program stops. *Note Expressions: Expressions.
+
+ `display' will not repeat if you press RET again after using it.
+
+`display/FMT EXP'
+ For FMT specifying only a display format and not a size or count,
+ add the expression EXP to the auto-display list but arrange to
+ display it each time in the specified format FMT. *Note Output
+ formats: Output Formats.
+
+`display/FMT ADDR'
+ For FMT `i' or `s', or including a unit-size or a number of units,
+ add the expression ADDR as a memory address to be examined each
+ time your program stops. Examining means in effect doing `x/FMT
+ ADDR'. *Note Examining memory: Memory.
+
+ For example, `display/i $pc' can be helpful, to see the machine
+instruction about to be executed each time execution stops (`$pc' is a
+common name for the program counter; *note Registers::.).
+
+`undisplay DNUMS...'
+`delete display DNUMS...'
+ Remove item numbers DNUMS from the list of expressions to display.
+
+ `undisplay' will not repeat if you press RET after using it.
+ (Otherwise you would just get the error `No display number ...'.)
+
+`disable display DNUMS...'
+ Disable the display of item numbers DNUMS. A disabled display
+ item is not printed automatically, but is not forgotten. It may be
+ enabled again later.
+
+`enable display DNUMS...'
+ Enable display of item numbers DNUMS. It becomes effective once
+ again in auto display of its expression, until you specify
+ otherwise.
+
+`display'
+ Display the current values of the expressions on the list, just as
+ is done when your program stops.
+
+`info display'
+ Print the list of expressions previously set up to display
+ automatically, each one with its item number, but without showing
+ the values. This includes disabled expressions, which are marked
+ as such. It also includes expressions which would not be
+ displayed right now because they refer to automatic variables not
+ currently available.
+
+ If a display expression refers to local variables, then it does not
+make sense outside the lexical context for which it was set up. Such an
+expression is disabled when execution enters a context where one of its
+variables is not defined. For example, if you give the command
+`display last_char' while inside a function with an argument
+`last_char', then this argument will be displayed while your program
+continues to stop inside that function. When it stops elsewhere--where
+there is no variable `last_char'--display is disabled. The next time
+your program stops where `last_char' is meaningful, you can enable the
+display expression once again.
+
+
+File: gdb.info, Node: Print Settings, Next: Value History, Prev: Auto Display, Up: Data
+
+Print settings
+==============
+
+ GDB provides the following ways to control how arrays, structures,
+and symbols are printed.
+
+These settings are useful for debugging programs in any language:
+
+`set print address'
+`set print address on'
+ GDB will print memory addresses showing the location of stack
+ traces, structure values, pointer values, breakpoints, and so
+ forth, even when it also displays the contents of those addresses.
+ The default is on. For example, this is what a stack frame
+ display looks like, with `set print address on':
+
+ (gdb) f
+ #0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+`set print address off'
+ Do not print addresses when displaying their contents. For
+ example, this is the same stack frame displayed with `set print
+ address off':
+
+ (gdb) set print addr off
+ (gdb) f
+ #0 set_quotes (lq="<<", rq=">>") at input.c:530
+ 530 if (lquote != def_lquote)
+
+ You can use `set print address off' to eliminate all machine
+ dependent displays from the GDB interface. For example, with
+ `print address off', you should get the same text for backtraces on
+ all machines--whether or not they involve pointer arguments.
+
+`show print address'
+ Show whether or not addresses are to be printed.
+
+ When GDB prints a symbolic address, it normally prints the closest
+earlier symbol plus an offset. If that symbol does not uniquely
+identify the address (for example, it is a name whose scope is a single
+source file), you may need to disambiguate. One way to do this is with
+`info line', for example `info line *0x4537'. Alternately, you can set
+GDB to print the source file and line number when it prints a symbolic
+address:
+
+`set print symbol-filename on'
+ Tell GDB to print the source file name and line number of a symbol
+ in the symbolic form of an address.
+
+`set print symbol-filename off'
+ Do not print source file name and line number of a symbol. This
+ is the default.
+
+`show print symbol-filename'
+ Show whether or not GDB will print the source file name and line
+ number of a symbol in the symbolic form of an address.
+
+ Also, you may wish to see the symbolic form only if the address being
+printed is reasonably close to the closest earlier symbol:
+
+`set print max-symbolic-offset MAX-OFFSET'
+ Tell GDB to only display the symbolic form of an address if the
+ offset between the closest earlier symbol and the address is less
+ than MAX-OFFSET. The default is 0, which means to always print the
+ symbolic form of an address, if any symbol precedes it.
+
+`show print max-symbolic-offset'
+ Ask how large the maximum offset is that GDB will print in a
+ symbolic address.
+
+`set print array'
+`set print array on'
+ GDB will pretty-print arrays. This format is more convenient to
+ read, but uses more space. The default is off.
+
+`set print array off'
+ Return to compressed format for arrays.
+
+`show print array'
+ Show whether compressed or pretty format is selected for displaying
+ arrays.
+
+`set print elements NUMBER-OF-ELEMENTS'
+ If GDB is printing a large array, it will stop printing after it
+ has printed the number of elements set by the `set print elements'
+ command. This limit also applies to the display of strings.
+ Setting the number of elements to zero means that the printing is
+ unlimited.
+
+`show print elements'
+ Display the number of elements of a large array that GDB will print
+ before losing patience.
+
+`set print pretty on'
+ Cause GDB to print structures in an indented format with one
+ member per line, like this:
+
+ $1 = {
+ next = 0x0,
+ flags = {
+ sweet = 1,
+ sour = 1
+ },
+ meat = 0x54 "Pork"
+ }
+
+`set print pretty off'
+ Cause GDB to print structures in a compact format, like this:
+
+ $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, \
+ meat = 0x54 "Pork"}
+
+ This is the default format.
+
+`show print pretty'
+ Show which format GDB will use to print structures.
+
+`set print sevenbit-strings on'
+ Print using only seven-bit characters; if this option is set, GDB
+ will display any eight-bit characters (in strings or character
+ values) using the notation `\'NNN. For example, `M-a' is
+ displayed as `\341'.
+
+`set print sevenbit-strings off'
+ Print using either seven-bit or eight-bit characters, as required.
+ This is the default.
+
+`show print sevenbit-strings'
+ Show whether or not GDB will print only seven-bit characters.
+
+`set print union on'
+ Tell GDB to print unions which are contained in structures. This
+ is the default setting.
+
+`set print union off'
+ Tell GDB not to print unions which are contained in structures.
+
+`show print union'
+ Ask GDB whether or not it will print unions which are contained in
+ structures.
+
+ For example, given the declarations
+
+ typedef enum {Tree, Bug} Species;
+ typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
+ typedef enum {Caterpillar, Cocoon, Butterfly}
+ Bug_forms;
+
+ struct thing {
+ Species it;
+ union {
+ Tree_forms tree;
+ Bug_forms bug;
+ } form;
+ };
+
+ struct thing foo = {Tree, {Acorn}};
+
+ with `set print union on' in effect `p foo' would print
+
+ $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
+
+ and with `set print union off' in effect it would print
+
+ $1 = {it = Tree, form = {...}}
+
+These settings are of interest when debugging C++ programs:
+
+`set print demangle'
+`set print demangle on'
+ Print C++ names in their source form rather than in the encoded
+ ("mangled") form passed to the assembler and linker for type-safe
+ linkage. The default is `on'.
+
+`show print demangle'
+ Show whether C++ names will be printed in mangled or demangled
+ form.
+
+`set print asm-demangle'
+`set print asm-demangle on'
+ Print C++ names in their source form rather than their mangled
+ form, even in assembler code printouts such as instruction
+ disassemblies. The default is off.
+
+`show print asm-demangle'
+ Show whether C++ names in assembly listings will be printed in
+ mangled or demangled form.
+
+`set demangle-style STYLE'
+ Choose among several encoding schemes used by different compilers
+ to represent C++ names. The choices for STYLE are currently:
+
+ `auto'
+ Allow GDB to choose a decoding style by inspecting your
+ program.
+
+ `gnu'
+ Decode based on the GNU C++ compiler (`g++') encoding
+ algorithm.
+
+ `lucid'
+ Decode based on the Lucid C++ compiler (`lcc') encoding
+ algorithm.
+
+ `arm'
+ Decode using the algorithm in the `C++ Annotated Reference
+ Manual'. *Warning:* this setting alone is not sufficient to
+ allow debugging `cfront'-generated executables. GDB would
+ require further enhancement to permit that.
+
+`show demangle-style'
+ Display the encoding style currently in use for decoding C++
+ symbols.
+
+`set print object'
+`set print object on'
+ When displaying a pointer to an object, identify the *actual*
+ (derived) type of the object rather than the *declared* type, using
+ the virtual function table.
+
+`set print object off'
+ Display only the declared type of objects, without reference to the
+ virtual function table. This is the default setting.
+
+`show print object'
+ Show whether actual, or declared, object types will be displayed.
+
+`set print vtbl'
+`set print vtbl on'
+ Pretty print C++ virtual function tables. The default is off.
+
+`set print vtbl off'
+ Do not pretty print C++ virtual function tables.
+
+`show print vtbl'
+ Show whether C++ virtual function tables are pretty printed, or
+ not.
+
+
+File: gdb.info, Node: Value History, Next: Convenience Vars, Prev: Print Settings, Up: Data
+
+Value history
+=============
+
+ Values printed by the `print' command are saved in the GDB "value
+history" so that you can refer to them in other expressions. Values are
+kept until the symbol table is re-read or discarded (for example with
+the `file' or `symbol-file' commands). When the symbol table changes,
+the value history is discarded, since the values may contain pointers
+back to the types defined in the symbol table.
+
+ The values printed are given "history numbers" by which you can
+refer to them. These are successive integers starting with one.
+`print' shows you the history number assigned to a value by printing
+`$NUM = ' before the value; here NUM is the history number.
+
+ To refer to any previous value, use `$' followed by the value's
+history number. The way `print' labels its output is designed to
+remind you of this. Just `$' refers to the most recent value in the
+history, and `$$' refers to the value before that. `$$N' refers to the
+Nth value from the end; `$$2' is the value just prior to `$$', `$$1' is
+equivalent to `$$', and `$$0' is equivalent to `$'.
+
+ For example, suppose you have just printed a pointer to a structure
+and want to see the contents of the structure. It suffices to type
+
+ p *$
+
+ If you have a chain of structures where the component `next' points
+to the next one, you can print the contents of the next one with this:
+
+ p *$.next
+
+You can print successive links in the chain by repeating this
+command--which you can do by just typing RET.
+
+ Note that the history records values, not expressions. If the value
+of `x' is 4 and you type these commands:
+
+ print x
+ set x=5
+
+then the value recorded in the value history by the `print' command
+remains 4 even though the value of `x' has changed.
+
+`show values'
+ Print the last ten values in the value history, with their item
+ numbers. This is like `p $$9' repeated ten times, except that
+ `show values' does not change the history.
+
+`show values N'
+ Print ten history values centered on history item number N.
+
+`show values +'
+ Print ten history values just after the values last printed. If
+ no more values are available, produces no display.
+
+ Pressing RET to repeat `show values N' has exactly the same effect
+as `show values +'.
+
+
+File: gdb.info, Node: Convenience Vars, Next: Registers, Prev: Value History, Up: Data
+
+Convenience variables
+=====================
+
+ GDB provides "convenience variables" that you can use within GDB to
+hold on to a value and refer to it later. These variables exist
+entirely within GDB; they are not part of your program, and setting a
+convenience variable has no direct effect on further execution of your
+program. That is why you can use them freely.
+
+ Convenience variables are prefixed with `$'. Any name preceded by
+`$' can be used for a convenience variable, unless it is one of the
+predefined machine-specific register names (*note Registers::.).
+(Value history references, in contrast, are *numbers* preceded by `$'.
+*Note Value history: Value History.)
+
+ You can save a value in a convenience variable with an assignment
+expression, just as you would set a variable in your program. For
+example:
+
+ set $foo = *object_ptr
+
+would save in `$foo' the value contained in the object pointed to by
+`object_ptr'.
+
+ Using a convenience variable for the first time creates it, but its
+value is `void' until you assign a new value. You can alter the value
+with another assignment at any time.
+
+ Convenience variables have no fixed types. You can assign a
+convenience variable any type of value, including structures and
+arrays, even if that variable already has a value of a different type.
+The convenience variable, when used as an expression, has the type of
+its current value.
+
+`show convenience'
+ Print a list of convenience variables used so far, and their
+ values. Abbreviated `show con'.
+
+ One of the ways to use a convenience variable is as a counter to be
+incremented or a pointer to be advanced. For example, to print a field
+from successive elements of an array of structures:
+
+ set $i = 0
+ print bar[$i++]->contents
+ ... repeat that command by typing RET.
+
+ Some convenience variables are created automatically by GDB and given
+values likely to be useful.
+
+`$_'
+ The variable `$_' is automatically set by the `x' command to the
+ last address examined (*note Examining memory: Memory.). Other
+ commands which provide a default address for `x' to examine also
+ set `$_' to that address; these commands include `info line' and
+ `info breakpoint'. The type of `$_' is `void *' except when set
+ by the `x' command, in which case it is a pointer to the type of
+ `$__'.
+
+`$__'
+ The variable `$__' is automatically set by the `x' command to the
+ value found in the last address examined. Its type is chosen to
+ match the format in which the data was printed.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-4 b/gnu/usr.bin/gdb/doc/gdb.info-4
new file mode 100644
index 000000000000..b0758fa5ef6a
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-4
@@ -0,0 +1,1349 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Registers, Next: Floating Point Hardware, Prev: Convenience Vars, Up: Data
+
+Registers
+=========
+
+ You can refer to machine register contents, in expressions, as
+variables with names starting with `$'. The names of registers are
+different for each machine; use `info registers' to see the names used
+on your machine.
+
+`info registers'
+ Print the names and values of all registers except floating-point
+ registers (in the selected stack frame).
+
+`info all-registers'
+ Print the names and values of all registers, including
+ floating-point registers.
+
+`info registers REGNAME ...'
+ Print the relativized value of each specified register REGNAME.
+ rEGNAME may be any register name valid on the machine you are
+ using, with or without the initial `$'.
+
+ GDB has four "standard" register names that are available (in
+expressions) on most machines--whenever they do not conflict with an
+architecture's canonical mnemonics for registers. The register names
+`$pc' and `$sp' are used for the program counter register and the stack
+pointer. `$fp' is used for a register that contains a pointer to the
+current stack frame, and `$ps' is used for a register that contains the
+processor status. For example, you could print the program counter in
+hex with
+
+ p/x $pc
+
+or print the instruction to be executed next with
+
+ x/i $pc
+
+or add four to the stack pointer(1) with
+
+ set $sp += 4
+
+ Whenever possible, these four standard register names are available
+on your machine even though the machine has different canonical
+mnemonics, so long as there is no conflict. The `info registers'
+command shows the canonical names. For example, on the SPARC, `info
+registers' displays the processor status register as `$psr' but you can
+also refer to it as `$ps'.
+
+ GDB always considers the contents of an ordinary register as an
+integer when the register is examined in this way. Some machines have
+special registers which can hold nothing but floating point; these
+registers are considered to have floating point values. There is no way
+to refer to the contents of an ordinary register as floating point value
+(although you can *print* it as a floating point value with `print/f
+$REGNAME').
+
+ Some registers have distinct "raw" and "virtual" data formats. This
+means that the data format in which the register contents are saved by
+the operating system is not the same one that your program normally
+sees. For example, the registers of the 68881 floating point
+coprocessor are always saved in "extended" (raw) format, but all C
+programs expect to work with "double" (virtual) format. In such cases,
+GDB normally works with the virtual format only (the format that makes
+sense for your program), but the `info registers' command prints the
+data in both formats.
+
+ Normally, register values are relative to the selected stack frame
+(*note Selecting a frame: Selection.). This means that you get the
+value that the register would contain if all stack frames farther in
+were exited and their saved registers restored. In order to see the
+true contents of hardware registers, you must select the innermost
+frame (with `frame 0').
+
+ However, GDB must deduce where registers are saved, from the machine
+code generated by your compiler. If some registers are not saved, or if
+GDB is unable to locate the saved registers, the selected stack frame
+will make no difference.
+
+`set rstack_high_address ADDRESS'
+ On AMD 29000 family processors, registers are saved in a separate
+ "register stack". There is no way for GDB to determine the extent
+ of this stack. Normally, GDB just assumes that the stack is "large
+ enough". This may result in GDB referencing memory locations that
+ do not exist. If necessary, you can get around this problem by
+ specifying the ending address of the register stack with the `set
+ rstack_high_address' command. The argument should be an address,
+ which you will probably want to precede with `0x' to specify in
+ hexadecimal.
+
+`show rstack_high_address'
+ Display the current limit of the register stack, on AMD 29000
+ family processors.
+
+ ---------- Footnotes ----------
+
+ (1) This is a way of removing one word from the stack, on machines
+where stacks grow downward in memory (most machines, nowadays). This
+assumes that the innermost stack frame is selected; setting `$sp' is
+not allowed when other stack frames are selected. To pop entire frames
+off the stack, regardless of machine architecture, use `return'; *note
+Returning from a function: Returning..
+
+
+File: gdb.info, Node: Floating Point Hardware, Prev: Registers, Up: Data
+
+Floating point hardware
+=======================
+
+ Depending on the host machine architecture, GDB may be able to give
+you more information about the status of the floating point hardware.
+
+`info float'
+ Display hardware-dependent information about the floating point
+ unit. The exact contents and layout vary depending on the
+ floating point chip; on some platforms, `info float' is not
+ available at all.
+
+
+File: gdb.info, Node: Languages, Next: Symbols, Prev: Data, Up: Top
+
+Using GDB with Different Languages
+**********************************
+
+ Although programming languages generally have common aspects, they
+are rarely expressed in the same manner. For instance, in ANSI C,
+dereferencing a pointer `p' is accomplished by `*p', but in Modula-2,
+it is accomplished by `p^'. Values can also be represented (and
+displayed) differently. Hex numbers in C are written like `0x1ae',
+while in Modula-2 they appear as `1AEH'.
+
+ Language-specific information is built into GDB for some languages,
+allowing you to express operations like the above in your program's
+native language, and allowing GDB to output values in a manner
+consistent with the syntax of your program's native language. The
+language you use to build expressions, called the "working language",
+can be selected manually, or GDB can set it automatically.
+
+* Menu:
+
+* Setting:: Switching between source languages
+* Show:: Displaying the language
+
+* Checks:: Type and range checks
+
+* Support:: Supported languages
+
+
+File: gdb.info, Node: Setting, Next: Show, Up: Languages
+
+Switching between source languages
+==================================
+
+ There are two ways to control the working language--either have GDB
+set it automatically, or select it manually yourself. You can use the
+`set language' command for either purpose. On startup, GDB defaults to
+setting the language automatically.
+
+* Menu:
+
+* Manually:: Setting the working language manually
+* Automatically:: Having GDB infer the source language
+
+
+File: gdb.info, Node: Manually, Next: Automatically, Up: Setting
+
+Setting the working language
+----------------------------
+
+ If you allow GDB to set the language automatically, expressions are
+interpreted the same way in your debugging session and your program.
+
+ If you wish, you may set the language manually. To do this, issue
+the command `set language LANG', where LANG is the name of a language,
+such as `c' or `modula-2'. For a list of the supported languages, type
+`set language'.
+
+ Setting the language manually prevents GDB from updating the working
+language automatically. This can lead to confusion if you try to debug
+a program when the working language is not the same as the source
+language, when an expression is acceptable to both languages--but means
+different things. For instance, if the current source file were
+written in C, and GDB was parsing Modula-2, a command such as:
+
+ print a = b + c
+
+might not have the effect you intended. In C, this means to add `b'
+and `c' and place the result in `a'. The result printed would be the
+value of `a'. In Modula-2, this means to compare `a' to the result of
+`b+c', yielding a `BOOLEAN' value.
+
+
+File: gdb.info, Node: Automatically, Prev: Manually, Up: Setting
+
+Having GDB infer the source language
+------------------------------------
+
+ To have GDB set the working language automatically, use `set
+language local' or `set language auto'. GDB then infers the language
+that a program was written in by looking at the name of its source
+files, and examining their extensions:
+
+`*.mod'
+ Modula-2 source file
+
+`*.c'
+ C source file
+
+`*.C'
+`*.cc'
+ C++ source file
+
+ This information is recorded for each function or procedure in a
+source file. When your program stops in a frame (usually by
+encountering a breakpoint), GDB sets the working language to the
+language recorded for the function in that frame. If the language for
+a frame is unknown (that is, if the function or block corresponding to
+the frame was defined in a source file that does not have a recognized
+extension), the current working language is not changed, and GDB issues
+a warning.
+
+ This may not seem necessary for most programs, which are written
+entirely in one source language. However, program modules and libraries
+written in one source language can be used by a main program written in
+a different source language. Using `set language auto' in this case
+frees you from having to set the working language manually.
+
+
+File: gdb.info, Node: Show, Next: Checks, Prev: Setting, Up: Languages
+
+Displaying the language
+=======================
+
+ The following commands will help you find out which language is the
+working language, and also what language source files were written in.
+
+`show language'
+ Display the current working language. This is the language you
+ can use with commands such as `print' to build and compute
+ expressions that may involve variables in your program.
+
+`info frame'
+ Among the other information listed here (*note Information about a
+ frame: Frame Info.) is the source language for this frame. This
+ is the language that will become the working language if you ever
+ use an identifier that is in this frame.
+
+`info source'
+ Among the other information listed here (*note Examining the
+ Symbol Table: Symbols.) is the source language of this source file.
+
+
+File: gdb.info, Node: Checks, Next: Support, Prev: Show, Up: Languages
+
+Type and range checking
+=======================
+
+ *Warning:* In this release, the GDB commands for type and range
+ checking are included, but they do not yet have any effect. This
+ section documents the intended facilities.
+
+ Some languages are designed to guard you against making seemingly
+common errors through a series of compile- and run-time checks. These
+include checking the type of arguments to functions and operators, and
+making sure mathematical overflows are caught at run time. Checks such
+as these help to ensure a program's correctness once it has been
+compiled by eliminating type mismatches, and providing active checks
+for range errors when your program is running.
+
+ GDB can check for conditions like the above if you wish. Although
+GDB will not check the statements in your program, it can check
+expressions entered directly into GDB for evaluation via the `print'
+command, for example. As with the working language, GDB can also
+decide whether or not to check automatically based on your program's
+source language. *Note Supported languages: Support, for the default
+settings of supported languages.
+
+* Menu:
+
+* Type Checking:: An overview of type checking
+* Range Checking:: An overview of range checking
+
+
+File: gdb.info, Node: Type Checking, Next: Range Checking, Up: Checks
+
+An overview of type checking
+----------------------------
+
+ Some languages, such as Modula-2, are strongly typed, meaning that
+the arguments to operators and functions have to be of the correct type,
+otherwise an error occurs. These checks prevent type mismatch errors
+from ever causing any run-time problems. For example,
+
+ 1 + 2 => 3
+but
+ error--> 1 + 2.3
+
+ The second example fails because the `CARDINAL' 1 is not
+type-compatible with the `REAL' 2.3.
+
+ For expressions you use in GDB commands, you can tell the GDB type
+checker to skip checking; to treat any mismatches as errors and abandon
+the expression; or only issue warnings when type mismatches occur, but
+evaluate the expression anyway. When you choose the last of these, GDB
+evaluates expressions like the second example above, but also issues a
+warning.
+
+ Even though you may turn type checking off, other type-based reasons
+may prevent GDB from evaluating an expression. For instance, GDB does
+not know how to add an `int' and a `struct foo'. These particular type
+errors have nothing to do with the language in use, and usually arise
+from expressions, such as the one described above, which make little
+sense to evaluate anyway.
+
+ Each language defines to what degree it is strict about type. For
+instance, both Modula-2 and C require the arguments to arithmetical
+operators to be numbers. In C, enumerated types and pointers can be
+represented as numbers, so that they are valid arguments to mathematical
+operators. *Note Supported languages: Support, for further details on
+specific languages.
+
+ GDB provides some additional commands for controlling the type
+checker:
+
+`set check type auto'
+ Set type checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check type on'
+`set check type off'
+ Set type checking on or off, overriding the default setting for the
+ current working language. Issue a warning if the setting does not
+ match the language default. If any type mismatches occur in
+ evaluating an expression while typechecking is on, GDB prints a
+ message and aborts evaluation of the expression.
+
+`set check type warn'
+ Cause the type checker to issue warnings, but to always attempt to
+ evaluate the expression. Evaluating the expression may still be
+ impossible for other reasons. For example, GDB cannot add numbers
+ and structures.
+
+`show type'
+ Show the current setting of the type checker, and whether or not
+ GDB is setting it automatically.
+
+
+File: gdb.info, Node: Range Checking, Prev: Type Checking, Up: Checks
+
+An overview of range checking
+-----------------------------
+
+ In some languages (such as Modula-2), it is an error to exceed the
+bounds of a type; this is enforced with run-time checks. Such range
+checking is meant to ensure program correctness by making sure
+computations do not overflow, or indices on an array element access do
+not exceed the bounds of the array.
+
+ For expressions you use in GDB commands, you can tell GDB to treat
+range errors in one of three ways: ignore them, always treat them as
+errors and abandon the expression, or issue warnings but evaluate the
+expression anyway.
+
+ A range error can result from numerical overflow, from exceeding an
+array index bound, or when you type a constant that is not a member of
+any type. Some languages, however, do not treat overflows as an error.
+In many implementations of C, mathematical overflow causes the result
+to "wrap around" to lower values--for example, if M is the largest
+integer value, and S is the smallest, then
+
+ M + 1 => S
+
+ This, too, is specific to individual languages, and in some cases
+specific to individual compilers or machines. *Note Supported
+languages: Support, for further details on specific languages.
+
+ GDB provides some additional commands for controlling the range
+checker:
+
+`set check range auto'
+ Set range checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check range on'
+`set check range off'
+ Set range checking on or off, overriding the default setting for
+ the current working language. A warning is issued if the setting
+ does not match the language default. If a range error occurs,
+ then a message is printed and evaluation of the expression is
+ aborted.
+
+`set check range warn'
+ Output messages when the GDB range checker detects a range error,
+ but attempt to evaluate the expression anyway. Evaluating the
+ expression may still be impossible for other reasons, such as
+ accessing memory that the process does not own (a typical example
+ from many Unix systems).
+
+`show range'
+ Show the current setting of the range checker, and whether or not
+ it is being set automatically by GDB.
+
+
+File: gdb.info, Node: Support, Prev: Checks, Up: Languages
+
+Supported languages
+===================
+
+ GDB 4 supports C, C++, and Modula-2. Some GDB features may be used
+in expressions regardless of the language you use: the GDB `@' and `::'
+operators, and the `{type}addr' construct (*note Expressions:
+Expressions.) can be used with the constructs of any supported language.
+
+ The following sections detail to what degree each source language is
+supported by GDB. These sections are not meant to be language
+tutorials or references, but serve only as a reference guide to what the
+GDB expression parser will accept, and what input and output formats
+should look like for different languages. There are many good books
+written on each of these languages; please look to these for a language
+reference or tutorial.
+
+* Menu:
+
+* C:: C and C++
+* Modula-2:: Modula-2
+
+
+File: gdb.info, Node: C, Next: Modula-2, Up: Support
+
+C and C++
+---------
+
+ Since C and C++ are so closely related, many features of GDB apply
+to both languages. Whenever this is the case, we discuss both languages
+together.
+
+ The C++ debugging facilities are jointly implemented by the GNU C++
+compiler and GDB. Therefore, to debug your C++ code effectively, you
+must compile your C++ programs with the GNU C++ compiler, `g++'.
+
+* Menu:
+
+* C Operators:: C and C++ operators
+* C Constants:: C and C++ constants
+* Cplus expressions:: C++ expressions
+* C Defaults:: Default settings for C and C++
+
+* C Checks:: C and C++ type and range checks
+
+* Debugging C:: GDB and C
+* Debugging C plus plus:: Special features for C++
+
+
+File: gdb.info, Node: C Operators, Next: C Constants, Up: C
+
+C and C++ operators
+-------------------
+
+ Operators must be defined on values of specific types. For instance,
+`+' is defined on numbers, but not on structures. Operators are often
+defined on groups of types.
+
+ For the purposes of C and C++, the following definitions hold:
+
+ * *Integral types* include `int' with any of its storage-class
+ specifiers; `char'; and `enum'.
+
+ * *Floating-point types* include `float' and `double'.
+
+ * *Pointer types* include all types defined as `(TYPE *)'.
+
+ * *Scalar types* include all of the above.
+
+The following operators are supported. They are listed here in order
+of increasing precedence:
+
+`,'
+ The comma or sequencing operator. Expressions in a
+ comma-separated list are evaluated from left to right, with the
+ result of the entire expression being the last expression
+ evaluated.
+
+`='
+ Assignment. The value of an assignment expression is the value
+ assigned. Defined on scalar types.
+
+`OP='
+ Used in an expression of the form `A OP= B', and translated to
+ `A = A OP B'. `OP=' and `=' have the same precendence. OP is any
+ one of the operators `|', `^', `&', `<<', `>>', `+', `-', `*',
+ `/', `%'.
+
+`?:'
+ The ternary operator. `A ? B : C' can be thought of as: if A
+ then B else C. A should be of an integral type.
+
+`||'
+ Logical OR. Defined on integral types.
+
+`&&'
+ Logical AND. Defined on integral types.
+
+`|'
+ Bitwise OR. Defined on integral types.
+
+`^'
+ Bitwise exclusive-OR. Defined on integral types.
+
+`&'
+ Bitwise AND. Defined on integral types.
+
+`==, !='
+ Equality and inequality. Defined on scalar types. The value of
+ these expressions is 0 for false and non-zero for true.
+
+`<, >, <=, >='
+ Less than, greater than, less than or equal, greater than or equal.
+ Defined on scalar types. The value of these expressions is 0 for
+ false and non-zero for true.
+
+`<<, >>'
+ left shift, and right shift. Defined on integral types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction. Defined on integral types,
+ floating-point types and pointer types.
+
+`*, /, %'
+ Multiplication, division, and modulus. Multiplication and
+ division are defined on integral and floating-point types.
+ Modulus is defined on integral types.
+
+`++, --'
+ Increment and decrement. When appearing before a variable, the
+ operation is performed before the variable is used in an
+ expression; when appearing after it, the variable's value is used
+ before the operation takes place.
+
+`*'
+ Pointer dereferencing. Defined on pointer types. Same precedence
+ as `++'.
+
+`&'
+ Address operator. Defined on variables. Same precedence as `++'.
+
+ For debugging C++, GDB implements a use of `&' beyond what is
+ allowed in the C++ language itself: you can use `&(&REF)' (or, if
+ you prefer, simply `&&REF') to examine the address where a C++
+ reference variable (declared with `&REF') is stored.
+
+`-'
+ Negative. Defined on integral and floating-point types. Same
+ precedence as `++'.
+
+`!'
+ Logical negation. Defined on integral types. Same precedence as
+ `++'.
+
+`~'
+ Bitwise complement operator. Defined on integral types. Same
+ precedence as `++'.
+
+`., ->'
+ Structure member, and pointer-to-structure member. For
+ convenience, GDB regards the two as equivalent, choosing whether
+ to dereference a pointer based on the stored type information.
+ Defined on `struct' and `union' data.
+
+`[]'
+ Array indexing. `A[I]' is defined as `*(A+I)'. Same precedence
+ as `->'.
+
+`()'
+ Function parameter list. Same precedence as `->'.
+
+`::'
+ C++ scope resolution operator. Defined on `struct', `union', and
+ `class' types.
+
+`::'
+ Doubled colons also represent the GDB scope operator (*note
+ Expressions: Expressions.). Same precedence as `::', above.
+
+
+File: gdb.info, Node: C Constants, Next: Cplus expressions, Prev: C Operators, Up: C
+
+C and C++ constants
+-------------------
+
+ GDB allows you to express the constants of C and C++ in the
+following ways:
+
+ * Integer constants are a sequence of digits. Octal constants are
+ specified by a leading `0' (ie. zero), and hexadecimal constants by
+ a leading `0x' or `0X'. Constants may also end with a letter `l',
+ specifying that the constant should be treated as a `long' value.
+
+ * Floating point constants are a sequence of digits, followed by a
+ decimal point, followed by a sequence of digits, and optionally
+ followed by an exponent. An exponent is of the form:
+ `e[[+]|-]NNN', where NNN is another sequence of digits. The `+'
+ is optional for positive exponents.
+
+ * Enumerated constants consist of enumerated identifiers, or their
+ integral equivalents.
+
+ * Character constants are a single character surrounded by single
+ quotes (`''), or a number--the ordinal value of the corresponding
+ character (usually its ASCII value). Within quotes, the single
+ character may be represented by a letter or by "escape sequences",
+ which are of the form `\NNN', where NNN is the octal representation
+ of the character's ordinal value; or of the form `\X', where `X'
+ is a predefined special character--for example, `\n' for newline.
+
+ * String constants are a sequence of character constants surrounded
+ by double quotes (`"').
+
+ * Pointer constants are an integral value. You can also write
+ pointers to constants using the C operator `&'.
+
+ * Array constants are comma-separated lists surrounded by braces `{'
+ and `}'; for example, `{1,2,3}' is a three-element array of
+ integers, `{{1,2}, {3,4}, {5,6}}' is a three-by-two array, and
+ `{&"hi", &"there", &"fred"}' is a three-element array of pointers.
+
+
+File: gdb.info, Node: Cplus expressions, Next: C Defaults, Prev: C Constants, Up: C
+
+C++ expressions
+---------------
+
+ GDB expression handling has a number of extensions to interpret a
+significant subset of C++ expressions.
+
+ *Warning:* Most of these extensions depend on the use of additional
+ debugging information in the symbol table, and thus require a rich,
+ extendable object code format. In particular, if your system uses
+ a.out, MIPS ECOFF, RS/6000 XCOFF, or Sun ELF with stabs extensions
+ to the symbol table, these facilities are all available. Where
+ the object code format is standard COFF, on the other hand, most
+ of the C++ support in GDB will *not* work, nor can it. For the
+ standard SVr4 debugging format, DWARF in ELF, the standard is
+ still evolving, so the C++ support in GDB is still fragile; when
+ this debugging format stabilizes, however, C++ support will also
+ be available on systems that use it.
+
+ 1. Member function calls are allowed; you can use expressions like
+
+ count = aml->GetOriginal(x, y)
+
+ 2. While a member function is active (in the selected stack frame),
+ your expressions have the same namespace available as the member
+ function; that is, GDB allows implicit references to the class
+ instance pointer `this' following the same rules as C++.
+
+ 3. You can call overloaded functions; GDB will resolve the function
+ call to the right definition, with one restriction--you must use
+ arguments of the type required by the function that you want to
+ call. GDB will not perform conversions requiring constructors or
+ user-defined type operators.
+
+ 4. GDB understands variables declared as C++ references; you can use
+ them in expressions just as you do in C++ source--they are
+ automatically dereferenced.
+
+ In the parameter list shown when GDB displays a frame, the values
+ of reference variables are not displayed (unlike other variables);
+ this avoids clutter, since references are often used for large
+ structures. The *address* of a reference variable is always
+ shown, unless you have specified `set print address off'.
+
+ 5. GDB supports the C++ name resolution operator `::'--your
+ expressions can use it just as expressions in your program do.
+ Since one scope may be defined in another, you can use `::'
+ repeatedly if necessary, for example in an expression like
+ `SCOPE1::SCOPE2::NAME'. GDB also allows resolving name scope by
+ reference to source files, in both C and C++ debugging (*note
+ Program variables: Variables.).
+
+
+File: gdb.info, Node: C Defaults, Next: C Checks, Prev: Cplus expressions, Up: C
+
+C and C++ defaults
+------------------
+
+ If you allow GDB to set type and range checking automatically, they
+both default to `off' whenever the working language changes to C or
+C++. This happens regardless of whether you, or GDB, selected the
+working language.
+
+ If you allow GDB to set the language automatically, it sets the
+working language to C or C++ on entering code compiled from a source
+file whose name ends with `.c', `.C', or `.cc'. *Note Having GDB infer
+the source language: Automatically, for further details.
+
+
+File: gdb.info, Node: C Checks, Next: Debugging C, Prev: C Defaults, Up: C
+
+C and C++ type and range checks
+-------------------------------
+
+ By default, when GDB parses C or C++ expressions, type checking is
+not used. However, if you turn type checking on, GDB will consider two
+variables type equivalent if:
+
+ * The two variables are structured and have the same structure,
+ union, or enumerated tag.
+
+ * Two two variables have the same type name, or types that have been
+ declared equivalent through `typedef'.
+
+ Range checking, if turned on, is done on mathematical operations.
+Array indices are not checked, since they are often used to index a
+pointer that is not itself an array.
+
+
+File: gdb.info, Node: Debugging C, Next: Debugging C plus plus, Prev: C Checks, Up: C
+
+GDB and C
+---------
+
+ The `set print union' and `show print union' commands apply to the
+`union' type. When set to `on', any `union' that is inside a `struct'
+or `class' will also be printed. Otherwise, it will appear as `{...}'.
+
+ The `@' operator aids in the debugging of dynamic arrays, formed
+with pointers and a memory allocation function. *Note Expressions:
+Expressions.
+
+
+File: gdb.info, Node: Debugging C plus plus, Prev: Debugging C, Up: C
+
+GDB features for C++
+--------------------
+
+ Some GDB commands are particularly useful with C++, and some are
+designed specifically for use with C++. Here is a summary:
+
+`breakpoint menus'
+ When you want a breakpoint in a function whose name is overloaded,
+ GDB breakpoint menus help you specify which function definition
+ you want. *Note Breakpoint menus: Breakpoint Menus.
+
+`rbreak REGEX'
+ Setting breakpoints using regular expressions is helpful for
+ setting breakpoints on overloaded functions that are not members
+ of any special classes. *Note Setting breakpoints: Set Breaks.
+
+`catch EXCEPTIONS'
+`info catch'
+ Debug C++ exception handling using these commands. *Note
+ Breakpoints and exceptions: Exception Handling.
+
+`ptype TYPENAME'
+ Print inheritance relationships as well as other information for
+ type TYPENAME. *Note Examining the Symbol Table: Symbols.
+
+`set print demangle'
+`show print demangle'
+`set print asm-demangle'
+`show print asm-demangle'
+ Control whether C++ symbols display in their source form, both when
+ displaying code as C++ source and when displaying disassemblies.
+ *Note Print settings: Print Settings.
+
+`set print object'
+`show print object'
+ Choose whether to print derived (actual) or declared types of
+ objects. *Note Print settings: Print Settings.
+
+`set print vtbl'
+`show print vtbl'
+ Control the format for printing virtual function tables. *Note
+ Print settings: Print Settings.
+
+`Overloaded symbol names'
+ You can specify a particular definition of an overloaded symbol,
+ using the same notation that is used to declare such symbols in
+ C++: type `SYMBOL(TYPES)' rather than just SYMBOL. You can also
+ use the GDB command-line word completion facilities to list the
+ available choices, or to finish the type list for you. *Note
+ Command completion: Completion, for details on how to do this.
+
+
+File: gdb.info, Node: Modula-2, Prev: C, Up: Support
+
+Modula-2
+--------
+
+ The extensions made to GDB to support Modula-2 only support output
+from the GNU Modula-2 compiler (which is currently being developed).
+Other Modula-2 compilers are not currently supported, and attempting to
+debug executables produced by them will most likely result in an error
+as GDB reads in the executable's symbol table.
+
+* Menu:
+
+* M2 Operators:: Built-in operators
+* Built-In Func/Proc:: Built-in functions and procedures
+* M2 Constants:: Modula-2 constants
+* M2 Defaults:: Default settings for Modula-2
+* Deviations:: Deviations from standard Modula-2
+* M2 Checks:: Modula-2 type and range checks
+* M2 Scope:: The scope operators `::' and `.'
+* GDB/M2:: GDB and Modula-2
+
+
+File: gdb.info, Node: M2 Operators, Next: Built-In Func/Proc, Up: Modula-2
+
+Operators
+---------
+
+ Operators must be defined on values of specific types. For instance,
+`+' is defined on numbers, but not on structures. Operators are often
+defined on groups of types. For the purposes of Modula-2, the
+following definitions hold:
+
+ * *Integral types* consist of `INTEGER', `CARDINAL', and their
+ subranges.
+
+ * *Character types* consist of `CHAR' and its subranges.
+
+ * *Floating-point types* consist of `REAL'.
+
+ * *Pointer types* consist of anything declared as `POINTER TO TYPE'.
+
+ * *Scalar types* consist of all of the above.
+
+ * *Set types* consist of `SET' and `BITSET' types.
+
+ * *Boolean types* consist of `BOOLEAN'.
+
+The following operators are supported, and appear in order of
+increasing precedence:
+
+`,'
+ Function argument or array index separator.
+
+`:='
+ Assignment. The value of VAR `:=' VALUE is VALUE.
+
+`<, >'
+ Less than, greater than on integral, floating-point, or enumerated
+ types.
+
+`<=, >='
+ Less than, greater than, less than or equal to, greater than or
+ equal to on integral, floating-point and enumerated types, or set
+ inclusion on set types. Same precedence as `<'.
+
+`=, <>, #'
+ Equality and two ways of expressing inequality, valid on scalar
+ types. Same precedence as `<'. In GDB scripts, only `<>' is
+ available for inequality, since `#' conflicts with the script
+ comment character.
+
+`IN'
+ Set membership. Defined on set types and the types of their
+ members. Same precedence as `<'.
+
+`OR'
+ Boolean disjunction. Defined on boolean types.
+
+`AND, &'
+ Boolean conjuction. Defined on boolean types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction on integral and floating-point types, or
+ union and difference on set types.
+
+`*'
+ Multiplication on integral and floating-point types, or set
+ intersection on set types.
+
+`/'
+ Division on floating-point types, or symmetric set difference on
+ set types. Same precedence as `*'.
+
+`DIV, MOD'
+ Integer division and remainder. Defined on integral types. Same
+ precedence as `*'.
+
+`-'
+ Negative. Defined on `INTEGER' and `REAL' data.
+
+`^'
+ Pointer dereferencing. Defined on pointer types.
+
+`NOT'
+ Boolean negation. Defined on boolean types. Same precedence as
+ `^'.
+
+`.'
+ `RECORD' field selector. Defined on `RECORD' data. Same
+ precedence as `^'.
+
+`[]'
+ Array indexing. Defined on `ARRAY' data. Same precedence as `^'.
+
+`()'
+ Procedure argument list. Defined on `PROCEDURE' objects. Same
+ precedence as `^'.
+
+`::, .'
+ GDB and Modula-2 scope operators.
+
+ *Warning:* Sets and their operations are not yet supported, so GDB
+ will treat the use of the operator `IN', or the use of operators
+ `+', `-', `*', `/', `=', , `<>', `#', `<=', and `>=' on sets as an
+ error.
+
+
+File: gdb.info, Node: Built-In Func/Proc, Next: M2 Constants, Prev: M2 Operators, Up: Modula-2
+
+Built-in functions and procedures
+---------------------------------
+
+ Modula-2 also makes available several built-in procedures and
+functions. In describing these, the following metavariables are used:
+
+A
+ represents an `ARRAY' variable.
+
+C
+ represents a `CHAR' constant or variable.
+
+I
+ represents a variable or constant of integral type.
+
+M
+ represents an identifier that belongs to a set. Generally used in
+ the same function with the metavariable S. The type of S should
+ be `SET OF MTYPE' (where MTYPE is the type of M).
+
+N
+ represents a variable or constant of integral or floating-point
+ type.
+
+R
+ represents a variable or constant of floating-point type.
+
+T
+ represents a type.
+
+V
+ represents a variable.
+
+X
+ represents a variable or constant of one of many types. See the
+ explanation of the function for details.
+
+ All Modula-2 built-in procedures also return a result, described
+below.
+
+`ABS(N)'
+ Returns the absolute value of N.
+
+`CAP(C)'
+ If C is a lower case letter, it returns its upper case equivalent,
+ otherwise it returns its argument
+
+`CHR(I)'
+ Returns the character whose ordinal value is I.
+
+`DEC(V)'
+ Decrements the value in the variable V. Returns the new value.
+
+`DEC(V,I)'
+ Decrements the value in the variable V by I. Returns the new
+ value.
+
+`EXCL(M,S)'
+ Removes the element M from the set S. Returns the new set.
+
+`FLOAT(I)'
+ Returns the floating point equivalent of the integer I.
+
+`HIGH(A)'
+ Returns the index of the last member of A.
+
+`INC(V)'
+ Increments the value in the variable V. Returns the new value.
+
+`INC(V,I)'
+ Increments the value in the variable V by I. Returns the new
+ value.
+
+`INCL(M,S)'
+ Adds the element M to the set S if it is not already there.
+ Returns the new set.
+
+`MAX(T)'
+ Returns the maximum value of the type T.
+
+`MIN(T)'
+ Returns the minimum value of the type T.
+
+`ODD(I)'
+ Returns boolean TRUE if I is an odd number.
+
+`ORD(X)'
+ Returns the ordinal value of its argument. For example, the
+ ordinal value of a character is its ASCII value (on machines
+ supporting the ASCII character set). X must be of an ordered
+ type, which include integral, character and enumerated types.
+
+`SIZE(X)'
+ Returns the size of its argument. X can be a variable or a type.
+
+`TRUNC(R)'
+ Returns the integral part of R.
+
+`VAL(T,I)'
+ Returns the member of the type T whose ordinal value is I.
+
+ *Warning:* Sets and their operations are not yet supported, so
+ GDB will treat the use of procedures `INCL' and `EXCL' as an error.
+
+
+File: gdb.info, Node: M2 Constants, Next: M2 Defaults, Prev: Built-In Func/Proc, Up: Modula-2
+
+Constants
+---------
+
+ GDB allows you to express the constants of Modula-2 in the following
+ways:
+
+ * Integer constants are simply a sequence of digits. When used in an
+ expression, a constant is interpreted to be type-compatible with
+ the rest of the expression. Hexadecimal integers are specified by
+ a trailing `H', and octal integers by a trailing `B'.
+
+ * Floating point constants appear as a sequence of digits, followed
+ by a decimal point and another sequence of digits. An optional
+ exponent can then be specified, in the form `E[+|-]NNN', where
+ `[+|-]NNN' is the desired exponent. All of the digits of the
+ floating point constant must be valid decimal (base 10) digits.
+
+ * Character constants consist of a single character enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). They may
+ also be expressed by their ordinal value (their ASCII value,
+ usually) followed by a `C'.
+
+ * String constants consist of a sequence of characters enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). Escape
+ sequences in the style of C are also allowed. *Note C and C++
+ constants: C Constants, for a brief explanation of escape
+ sequences.
+
+ * Enumerated constants consist of an enumerated identifier.
+
+ * Boolean constants consist of the identifiers `TRUE' and `FALSE'.
+
+ * Pointer constants consist of integral values only.
+
+ * Set constants are not yet supported.
+
+
+File: gdb.info, Node: M2 Defaults, Next: Deviations, Prev: M2 Constants, Up: Modula-2
+
+Modula-2 defaults
+-----------------
+
+ If type and range checking are set automatically by GDB, they both
+default to `on' whenever the working language changes to Modula-2.
+This happens regardless of whether you, or GDB, selected the working
+language.
+
+ If you allow GDB to set the language automatically, then entering
+code compiled from a file whose name ends with `.mod' will set the
+working language to Modula-2. *Note Having GDB set the language
+automatically: Automatically, for further details.
+
+
+File: gdb.info, Node: Deviations, Next: M2 Checks, Prev: M2 Defaults, Up: Modula-2
+
+Deviations from standard Modula-2
+---------------------------------
+
+ A few changes have been made to make Modula-2 programs easier to
+debug. This is done primarily via loosening its type strictness:
+
+ * Unlike in standard Modula-2, pointer constants can be formed by
+ integers. This allows you to modify pointer variables during
+ debugging. (In standard Modula-2, the actual address contained in
+ a pointer variable is hidden from you; it can only be modified
+ through direct assignment to another pointer variable or
+ expression that returned a pointer.)
+
+ * C escape sequences can be used in strings and characters to
+ represent non-printable characters. GDB will print out strings
+ with these escape sequences embedded. Single non-printable
+ characters are printed using the `CHR(NNN)' format.
+
+ * The assignment operator (`:=') returns the value of its right-hand
+ argument.
+
+ * All built-in procedures both modify *and* return their argument.
+
+
+File: gdb.info, Node: M2 Checks, Next: M2 Scope, Prev: Deviations, Up: Modula-2
+
+Modula-2 type and range checks
+------------------------------
+
+ *Warning:* in this release, GDB does not yet perform type or range
+ checking.
+
+ GDB considers two Modula-2 variables type equivalent if:
+
+ * They are of types that have been declared equivalent via a `TYPE
+ T1 = T2' statement
+
+ * They have been declared on the same line. (Note: This is true of
+ the GNU Modula-2 compiler, but it may not be true of other
+ compilers.)
+
+ As long as type checking is enabled, any attempt to combine variables
+whose types are not equivalent is an error.
+
+ Range checking is done on all mathematical operations, assignment,
+array index bounds, and all built-in functions and procedures.
+
+
+File: gdb.info, Node: M2 Scope, Next: GDB/M2, Prev: M2 Checks, Up: Modula-2
+
+The scope operators `::' and `.'
+--------------------------------
+
+ There are a few subtle differences between the Modula-2 scope
+operator (`.') and the GDB scope operator (`::'). The two have similar
+syntax:
+
+
+ MODULE . ID
+ SCOPE :: ID
+
+where SCOPE is the name of a module or a procedure, MODULE the name of
+a module, and ID is any declared identifier within your program, except
+another module.
+
+ Using the `::' operator makes GDB search the scope specified by
+SCOPE for the identifier ID. If it is not found in the specified
+scope, then GDB will search all scopes enclosing the one specified by
+SCOPE.
+
+ Using the `.' operator makes GDB search the current scope for the
+identifier specified by ID that was imported from the definition module
+specified by MODULE. With this operator, it is an error if the
+identifier ID was not imported from definition module MODULE, or if ID
+is not an identifier in MODULE.
+
+
+File: gdb.info, Node: GDB/M2, Prev: M2 Scope, Up: Modula-2
+
+GDB and Modula-2
+----------------
+
+ Some GDB commands have little use when debugging Modula-2 programs.
+Five subcommands of `set print' and `show print' apply specifically to
+C and C++: `vtbl', `demangle', `asm-demangle', `object', and `union'.
+The first four apply to C++, and the last to the C `union' type, which
+has no direct analogue in Modula-2.
+
+ The `@' operator (*note Expressions: Expressions.), while available
+while using any language, is not useful with Modula-2. Its intent is
+to aid the debugging of "dynamic arrays", which cannot be created in
+Modula-2 as they can in C or C++. However, because an address can be
+specified by an integral constant, the construct `{TYPE}ADREXP' is
+still useful. (*note Expressions: Expressions.)
+
+ In GDB scripts, the Modula-2 inequality operator `#' is interpreted
+as the beginning of a comment. Use `<>' instead.
+
+
+File: gdb.info, Node: Symbols, Next: Altering, Prev: Languages, Up: Top
+
+Examining the Symbol Table
+**************************
+
+ The commands described in this section allow you to inquire about the
+symbols (names of variables, functions and types) defined in your
+program. This information is inherent in the text of your program and
+does not change as your program executes. GDB finds it in your
+program's symbol table, in the file indicated when you started GDB
+(*note Choosing files: File Options.), or by one of the file-management
+commands (*note Commands to specify files: Files.).
+
+ Occasionally, you may need to refer to symbols that contain unusual
+characters, which GDB ordinarily treats as word delimiters. The most
+frequent case is in referring to static variables in other source files
+(*note Program variables: Variables.). File names are recorded in
+object files as debugging symbols, but GDB would ordinarily parse a
+typical file name, like `foo.c', as the three words `foo' `.' `c'. To
+allow GDB to recognize `foo.c' as a single symbol, enclose it in single
+quotes; for example,
+
+ p 'foo.c'::x
+
+looks up the value of `x' in the scope of the file `foo.c'.
+
+`info address SYMBOL'
+ Describe where the data for SYMBOL is stored. For a register
+ variable, this says which register it is kept in. For a
+ non-register local variable, this prints the stack-frame offset at
+ which the variable is always stored.
+
+ Note the contrast with `print &SYMBOL', which does not work at all
+ for a register variable, and for a stack local variable prints the
+ exact address of the current instantiation of the variable.
+
+`whatis EXP'
+ Print the data type of expression EXP. EXP is not actually
+ evaluated, and any side-effecting operations (such as assignments
+ or function calls) inside it do not take place. *Note
+ Expressions: Expressions.
+
+`whatis'
+ Print the data type of `$', the last value in the value history.
+
+`ptype TYPENAME'
+ Print a description of data type TYPENAME. TYPENAME may be the
+ name of a type, or for C code it may have the form `class
+ CLASS-NAME', `struct STRUCT-TAG', `union UNION-TAG' or `enum
+ ENUM-TAG'.
+
+`ptype EXP'
+`ptype'
+ Print a description of the type of expression EXP. `ptype'
+ differs from `whatis' by printing a detailed description, instead
+ of just the name of the type.
+
+ For example, for this variable declaration:
+
+ struct complex {double real; double imag;} v;
+
+ the two commands give this output:
+
+ (gdb) whatis v
+ type = struct complex
+ (gdb) ptype v
+ type = struct complex {
+ double real;
+ double imag;
+ }
+
+ As with `whatis', using `ptype' without an argument refers to the
+ type of `$', the last value in the value history.
+
+`info types REGEXP'
+`info types'
+ Print a brief description of all types whose name matches REGEXP
+ (or all types in your program, if you supply no argument). Each
+ complete typename is matched as though it were a complete line;
+ thus, `i type value' gives information on all types in your
+ program whose name includes the string `value', but `i type
+ ^value$' gives information only on types whose complete name is
+ `value'.
+
+ This command differs from `ptype' in two ways: first, like
+ `whatis', it does not print a detailed description; second, it
+ lists all source files where a type is defined.
+
+`info source'
+ Show the name of the current source file--that is, the source file
+ for the function containing the current point of execution--and
+ the language it was written in.
+
+`info sources'
+ Print the names of all source files in your program for which
+ there is debugging information, organized into two lists: files
+ whose symbols have already been read, and files whose symbols will
+ be read when needed.
+
+`info functions'
+ Print the names and data types of all defined functions.
+
+`info functions REGEXP'
+ Print the names and data types of all defined functions whose
+ names contain a match for regular expression REGEXP. Thus, `info
+ fun step' finds all functions whose names include `step'; `info
+ fun ^step' finds those whose names start with `step'.
+
+`info variables'
+ Print the names and data types of all variables that are declared
+ outside of functions (i.e., excluding local variables).
+
+`info variables REGEXP'
+ Print the names and data types of all variables (except for local
+ variables) whose names contain a match for regular expression
+ REGEXP.
+
+`maint print symbols FILENAME'
+`maint print psymbols FILENAME'
+`maint print msymbols FILENAME'
+ Write a dump of debugging symbol data into the file FILENAME.
+ These commands are used to debug the GDB symbol-reading code. Only
+ symbols with debugging data are included. If you use `maint print
+ symbols', GDB includes all the symbols for which it has already
+ collected full details: that is, FILENAME reflects symbols for
+ only those files whose symbols GDB has read. You can use the
+ command `info sources' to find out which files these are. If you
+ use `maint print psymbols' instead, the dump shows information
+ about symbols that GDB only knows partially--that is, symbols
+ defined in files that GDB has skimmed, but not yet read
+ completely. Finally, `maint print msymbols' dumps just the
+ minimal symbol information required for each object file from
+ which GDB has read some symbols. *Note Commands to specify files:
+ Files, for a discussion of how GDB reads symbols (in the
+ description of `symbol-file').
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-5 b/gnu/usr.bin/gdb/doc/gdb.info-5
new file mode 100644
index 000000000000..ecf3d18b96f5
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-5
@@ -0,0 +1,1215 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Altering, Next: GDB Files, Prev: Symbols, Up: Top
+
+Altering Execution
+******************
+
+ Once you think you have found an error in your program, you might
+want to find out for certain whether correcting the apparent error
+would lead to correct results in the rest of the run. You can find the
+answer by experiment, using the GDB features for altering execution of
+the program.
+
+ For example, you can store new values into variables or memory
+locations, give your program a signal, restart it at a different
+address, or even return prematurely from a function to its caller.
+
+* Menu:
+
+* Assignment:: Assignment to variables
+* Jumping:: Continuing at a different address
+
+* Signaling:: Giving your program a signal
+
+* Returning:: Returning from a function
+* Calling:: Calling your program's functions
+* Patching:: Patching your program
+
+
+File: gdb.info, Node: Assignment, Next: Jumping, Up: Altering
+
+Assignment to variables
+=======================
+
+ To alter the value of a variable, evaluate an assignment expression.
+*Note Expressions: Expressions. For example,
+
+ print x=4
+
+stores the value 4 into the variable `x', and then prints the value of
+the assignment expression (which is 4). *Note Using GDB with Different
+Languages: Languages, for more information on operators in supported
+languages.
+
+ If you are not interested in seeing the value of the assignment, use
+the `set' command instead of the `print' command. `set' is really the
+same as `print' except that the expression's value is not printed and
+is not put in the value history (*note Value history: Value History.).
+The expression is evaluated only for its effects.
+
+ If the beginning of the argument string of the `set' command appears
+identical to a `set' subcommand, use the `set variable' command instead
+of just `set'. This command is identical to `set' except for its lack
+of subcommands. For example, if your program has a variable `width',
+you get an error if you try to set a new value with just `set width=13',
+because GDB has the command `set width':
+
+ (gdb) whatis width
+ type = double
+ (gdb) p width
+ $4 = 13
+ (gdb) set width=47
+ Invalid syntax in expression.
+
+The invalid expression, of course, is `=47'. In order to actually set
+the program's variable `width', use
+
+ (gdb) set var width=47
+
+ GDB allows more implicit conversions in assignments than C; you can
+freely store an integer value into a pointer variable or vice versa,
+and you can convert any structure to any other structure that is the
+same length or shorter.
+
+ To store values into arbitrary places in memory, use the `{...}'
+construct to generate a value of specified type at a specified address
+(*note Expressions: Expressions.). For example, `{int}0x83040' refers
+to memory location `0x83040' as an integer (which implies a certain size
+and representation in memory), and
+
+ set {int}0x83040 = 4
+
+stores the value 4 into that memory location.
+
+
+File: gdb.info, Node: Jumping, Next: Signaling, Prev: Assignment, Up: Altering
+
+Continuing at a different address
+=================================
+
+ Ordinarily, when you continue your program, you do so at the place
+where it stopped, with the `continue' command. You can instead
+continue at an address of your own choosing, with the following
+commands:
+
+`jump LINESPEC'
+ Resume execution at line LINESPEC. Execution will stop
+ immediately if there is a breakpoint there. *Note Printing source
+ lines: List, for a description of the different forms of LINESPEC.
+
+ The `jump' command does not change the current stack frame, or the
+ stack pointer, or the contents of any memory location or any
+ register other than the program counter. If line LINESPEC is in a
+ different function from the one currently executing, the results
+ may be bizarre if the two functions expect different patterns of
+ arguments or of local variables. For this reason, the `jump'
+ command requests confirmation if the specified line is not in the
+ function currently executing. However, even bizarre results are
+ predictable if you are well acquainted with the machine-language
+ code of your program.
+
+`jump *ADDRESS'
+ Resume execution at the instruction at address ADDRESS.
+
+ You can get much the same effect as the `jump' command by storing a
+new value into the register `$pc'. The difference is that this does
+not start your program running; it only changes the address where it
+*will* run when it is continued. For example,
+
+ set $pc = 0x485
+
+causes the next `continue' command or stepping command to execute at
+address `0x485', rather than at the address where your program stopped.
+*Note Continuing and stepping: Continuing and Stepping.
+
+ The most common occasion to use the `jump' command is to back up,
+perhaps with more breakpoints set, over a portion of a program that has
+already executed, in order to examine its execution in more detail.
+
+
+File: gdb.info, Node: Signaling, Next: Returning, Prev: Jumping, Up: Altering
+
+Giving your program a signal
+============================
+
+`signal SIGNAL'
+ Resume execution where your program stopped, but immediately give
+ it the signal SIGNAL. SIGNAL can be the name or the number of a
+ signal. For example, on many systems `signal 2' and `signal
+ SIGINT' are both ways of sending an interrupt signal.
+
+ Alternatively, if SIGNAL is zero, continue execution without
+ giving a signal. This is useful when your program stopped on
+ account of a signal and would ordinary see the signal when resumed
+ with the `continue' command; `signal 0' causes it to resume
+ without a signal.
+
+ `signal' does not repeat when you press RET a second time after
+ executing the command.
+
+ Invoking the `signal' command is not the same as invoking the `kill'
+utility from the shell. Sending a signal with `kill' causes GDB to
+decide what to do with the signal depending on the signal handling
+tables (*note Signals::.). The `signal' command passes the signal
+directly to your program.
+
+
+File: gdb.info, Node: Returning, Next: Calling, Prev: Signaling, Up: Altering
+
+Returning from a function
+=========================
+
+`return'
+`return EXPRESSION'
+ You can cancel execution of a function call with the `return'
+ command. If you give an EXPRESSION argument, its value is used as
+ the function's return value.
+
+ When you use `return', GDB discards the selected stack frame (and
+all frames within it). You can think of this as making the discarded
+frame return prematurely. If you wish to specify a value to be
+returned, give that value as the argument to `return'.
+
+ This pops the selected stack frame (*note Selecting a frame:
+Selection.), and any other frames inside of it, leaving its caller as
+the innermost remaining frame. That frame becomes selected. The
+specified value is stored in the registers used for returning values of
+functions.
+
+ The `return' command does not resume execution; it leaves the
+program stopped in the state that would exist if the function had just
+returned. In contrast, the `finish' command (*note Continuing and
+stepping: Continuing and Stepping.) resumes execution until the
+selected stack frame returns naturally.
+
+
+File: gdb.info, Node: Calling, Next: Patching, Prev: Returning, Up: Altering
+
+Calling program functions
+=========================
+
+`call EXPR'
+ Evaluate the expression EXPR without displaying `void' returned
+ values.
+
+ You can use this variant of the `print' command if you want to
+execute a function from your program, but without cluttering the output
+with `void' returned values. The result is printed and saved in the
+value history, if it is not void.
+
+
+File: gdb.info, Node: Patching, Prev: Calling, Up: Altering
+
+Patching programs
+=================
+
+ By default, GDB opens the file containing your program's executable
+code (or the corefile) read-only. This prevents accidental alterations
+to machine code; but it also prevents you from intentionally patching
+your program's binary.
+
+ If you'd like to be able to patch the binary, you can specify that
+explicitly with the `set write' command. For example, you might want
+to turn on internal debugging flags, or even to make emergency repairs.
+
+`set write on'
+`set write off'
+ If you specify `set write on', GDB will open executable and core
+ files for both reading and writing; if you specify `set write off'
+ (the default), GDB will open them read-only.
+
+ If you have already loaded a file, you must load it again (using
+ the `exec-file' or `core-file' command) after changing `set
+ write', for your new setting to take effect.
+
+`show write'
+ Display whether executable files and core files will be opened for
+ writing as well as reading.
+
+
+File: gdb.info, Node: GDB Files, Next: Targets, Prev: Altering, Up: Top
+
+GDB Files
+*********
+
+ GDB needs to know the file name of the program to be debugged, both
+in order to read its symbol table and in order to start your program.
+To debug a core dump of a previous run, you must also tell GDB the name
+of the core dump file.
+
+* Menu:
+
+* Files:: Commands to specify files
+* Symbol Errors:: Errors reading symbol files
+
+
+File: gdb.info, Node: Files, Next: Symbol Errors, Up: GDB Files
+
+Commands to specify files
+=========================
+
+ The usual way to specify executable and core dump file names is with
+the command arguments given when you start GDB (*note Getting In and
+Out of GDB: Invocation..
+
+ Occasionally it is necessary to change to a different file during a
+GDB session. Or you may run GDB and forget to specify a file you want
+to use. In these situations the GDB commands to specify new files are
+useful.
+
+`file FILENAME'
+ Use FILENAME as the program to be debugged. It is read for its
+ symbols and for the contents of pure memory. It is also the
+ program executed when you use the `run' command. If you do not
+ specify a directory and the file is not found in the GDB working
+ directory, GDB uses the environment variable `PATH' as a list of
+ directories to search, just as the shell does when looking for a
+ program to run. You can change the value of this variable, for
+ both GDB and your program, using the `path' command.
+
+ On systems with memory-mapped files, an auxiliary symbol table file
+ `FILENAME.syms' may be available for FILENAME. If it is, GDB will
+ map in the symbol table from `FILENAME.syms', starting up more
+ quickly. See the descriptions of the options `-mapped' and
+ `-readnow' (available on the command line, and with the commands
+ `file', `symbol-file', or `add-symbol-file'), for more information.
+
+`file'
+ `file' with no argument makes GDB discard any information it has
+ on both executable file and the symbol table.
+
+`exec-file [ FILENAME ]'
+ Specify that the program to be run (but not the symbol table) is
+ found in FILENAME. GDB will search the environment variable `PATH'
+ if necessary to locate your program. Omitting FILENAME means to
+ discard information on the executable file.
+
+`symbol-file [ FILENAME ]'
+ Read symbol table information from file FILENAME. `PATH' is
+ searched when necessary. Use the `file' command to get both symbol
+ table and program to run from the same file.
+
+ `symbol-file' with no argument clears out GDB information on your
+ program's symbol table.
+
+ The `symbol-file' command causes GDB to forget the contents of its
+ convenience variables, the value history, and all breakpoints and
+ auto-display expressions. This is because they may contain
+ pointers to the internal data recording symbols and data types,
+ which are part of the old symbol table data being discarded inside
+ GDB.
+
+ `symbol-file' will not repeat if you press RET again after
+ executing it once.
+
+ When GDB is configured for a particular environment, it will
+ understand debugging information in whatever format is the standard
+ generated for that environment; you may use either a GNU compiler,
+ or other compilers that adhere to the local conventions. Best
+ results are usually obtained from GNU compilers; for example,
+ using `gcc' you can generate debugging information for optimized
+ code.
+
+ On some kinds of object files, the `symbol-file' command does not
+ normally read the symbol table in full right away. Instead, it
+ scans the symbol table quickly to find which source files and
+ which symbols are present. The details are read later, one source
+ file at a time, as they are needed.
+
+ The purpose of this two-stage reading strategy is to make GDB
+ start up faster. For the most part, it is invisible except for
+ occasional pauses while the symbol table details for a particular
+ source file are being read. (The `set verbose' command can turn
+ these pauses into messages if desired. *Note Optional warnings
+ and messages: Messages/Warnings.)
+
+ We have not implemented the two-stage strategy for COFF yet. When
+ the symbol table is stored in COFF format, `symbol-file' reads the
+ symbol table data in full right away.
+
+`symbol-file FILENAME [ -readnow ] [ -mapped ]'
+`file FILENAME [ -readnow ] [ -mapped ]'
+ You can override the GDB two-stage strategy for reading symbol
+ tables by using the `-readnow' option with any of the commands that
+ load symbol table information, if you want to be sure GDB has the
+ entire symbol table available.
+
+ If memory-mapped files are available on your system through the
+ `mmap' system call, you can use another option, `-mapped', to
+ cause GDB to write the symbols for your program into a reusable
+ file. Future GDB debugging sessions will map in symbol information
+ from this auxiliary symbol file (if the program has not changed),
+ rather than spending time reading the symbol table from the
+ executable program. Using the `-mapped' option has the same
+ effect as starting GDB with the `-mapped' command-line option.
+
+ You can use both options together, to make sure the auxiliary
+ symbol file has all the symbol information for your program.
+
+ The auxiliary symbol file for a program called MYPROG is called
+ `MYPROG.syms'. Once this file exists (so long as it is newer than
+ the corresponding executable), GDB will always attempt to use it
+ when you debug MYPROG; no special options or commands are needed.
+
+ The `.syms' file is specific to the host machine where you run
+ GDB. It holds an exact image of the internal GDB symbol table.
+ It cannot be shared across multiple host platforms.
+
+`core-file [ FILENAME ]'
+ Specify the whereabouts of a core dump file to be used as the
+ "contents of memory". Traditionally, core files contain only some
+ parts of the address space of the process that generated them; GDB
+ can access the executable file itself for other parts.
+
+ `core-file' with no argument specifies that no core file is to be
+ used.
+
+ Note that the core file is ignored when your program is actually
+ running under GDB. So, if you have been running your program and
+ you wish to debug a core file instead, you must kill the
+ subprocess in which the program is running. To do this, use the
+ `kill' command (*note Killing the child process: Kill Process.).
+
+`load FILENAME'
+ Depending on what remote debugging facilities are configured into
+ GDB, the `load' command may be available. Where it exists, it is
+ meant to make FILENAME (an executable) available for debugging on
+ the remote system--by downloading, or dynamic linking, for example.
+ `load' also records the FILENAME symbol table in GDB, like the
+ `add-symbol-file' command.
+
+ If your GDB does not have a `load' command, attempting to execute
+ it gets the error message "`You can't do that when your target is
+ ...'"
+
+ The file is loaded at whatever address is specified in the
+ executable. For some object file formats, like a.out, the object
+ file format fixes the address and so it won't necessarily match
+ the address you gave to the linker.
+
+ On VxWorks, `load' will dynamically link FILENAME on the current
+ target system as well as adding its symbols in GDB.
+
+ With the Nindy interface to an Intel 960 board, `load' will
+ download FILENAME to the 960 as well as adding its symbols in GDB.
+
+ When you select remote debugging to a Hitachi SH, H8/300, or
+ H8/500 board (*note GDB and Hitachi Microprocessors: Hitachi
+ Remote.), the `load' command downloads your program to the Hitachi
+ board and also opens it as the current executable target for GDB
+ on your host (like the `file' command).
+
+ `load' will not repeat if you press RET again after using it.
+
+`add-symbol-file FILENAME ADDRESS'
+`add-symbol-file FILENAME ADDRESS [ -readnow ] [ -mapped ]'
+ The `add-symbol-file' command reads additional symbol table
+ information from the file FILENAME. You would use this command
+ when FILENAME has been dynamically loaded (by some other means)
+ into the program that is running. ADDRESS should be the memory
+ address at which the file has been loaded; GDB cannot figure this
+ out for itself. You can specify ADDRESS as an expression.
+
+ The symbol table of the file FILENAME is added to the symbol table
+ originally read with the `symbol-file' command. You can use the
+ `add-symbol-file' command any number of times; the new symbol data
+ thus read keeps adding to the old. To discard all old symbol data
+ instead, use the `symbol-file' command.
+
+ `add-symbol-file' will not repeat if you press RET after using it.
+
+ You can use the `-mapped' and `-readnow' options just as with the
+ `symbol-file' command, to change how GDB manages the symbol table
+ information for FILENAME.
+
+`info files'
+`info target'
+ `info files' and `info target' are synonymous; both print the
+ current target (*note Specifying a Debugging Target: Targets.),
+ including the names of the executable and core dump files
+ currently in use by GDB, and the files from which symbols were
+ loaded. The command `help targets' lists all possible targets
+ rather than current ones.
+
+ All file-specifying commands allow both absolute and relative file
+names as arguments. GDB always converts the file name to an absolute
+path name and remembers it that way.
+
+ GDB supports SunOS, SVR4, and IBM RS/6000 shared libraries. GDB
+automatically loads symbol definitions from shared libraries when you
+use the `run' command, or when you examine a core file. (Before you
+issue the `run' command, GDB will not understand references to a
+function in a shared library, however--unless you are debugging a core
+file).
+
+`info share'
+`info sharedlibrary'
+ Print the names of the shared libraries which are currently loaded.
+
+`sharedlibrary REGEX'
+`share REGEX'
+ This is an obsolescent command; you can use it to explicitly load
+ shared object library symbols for files matching a Unix regular
+ expression, but as with files loaded automatically, it will only
+ load shared libraries required by your program for a core file or
+ after typing `run'. If REGEX is omitted all shared libraries
+ required by your program are loaded.
+
+
+File: gdb.info, Node: Symbol Errors, Prev: Files, Up: GDB Files
+
+Errors reading symbol files
+===========================
+
+ While reading a symbol file, GDB will occasionally encounter
+problems, such as symbol types it does not recognize, or known bugs in
+compiler output. By default, GDB does not notify you of such problems,
+since they are relatively common and primarily of interest to people
+debugging compilers. If you are interested in seeing information about
+ill-constructed symbol tables, you can either ask GDB to print only one
+message about each such type of problem, no matter how many times the
+problem occurs; or you can ask GDB to print more messages, to see how
+many times the problems occur, with the `set complaints' command (*note
+Optional warnings and messages: Messages/Warnings.).
+
+ The messages currently printed, and their meanings, include:
+
+`inner block not inside outer block in SYMBOL'
+ The symbol information shows where symbol scopes begin and end
+ (such as at the start of a function or a block of statements).
+ This error indicates that an inner scope block is not fully
+ contained in its outer scope blocks.
+
+ GDB circumvents the problem by treating the inner block as if it
+ had the same scope as the outer block. In the error message,
+ SYMBOL may be shown as "`(don't know)'" if the outer block is not a
+ function.
+
+`block at ADDRESS out of order'
+ The symbol information for symbol scope blocks should occur in
+ order of increasing addresses. This error indicates that it does
+ not do so.
+
+ GDB does not circumvent this problem, and will have trouble
+ locating symbols in the source file whose symbols it is reading.
+ (You can often determine what source file is affected by specifying
+ `set verbose on'. *Note Optional warnings and messages:
+ Messages/Warnings.)
+
+`bad block start address patched'
+ The symbol information for a symbol scope block has a start address
+ smaller than the address of the preceding source line. This is
+ known to occur in the SunOS 4.1.1 (and earlier) C compiler.
+
+ GDB circumvents the problem by treating the symbol scope block as
+ starting on the previous source line.
+
+`bad string table offset in symbol N'
+ Symbol number N contains a pointer into the string table which is
+ larger than the size of the string table.
+
+ GDB circumvents the problem by considering the symbol to have the
+ name `foo', which may cause other problems if many symbols end up
+ with this name.
+
+`unknown symbol type `0xNN''
+ The symbol information contains new data types that GDB does not
+ yet know how to read. `0xNN' is the symbol type of the
+ misunderstood information, in hexadecimal.
+
+ GDB circumvents the error by ignoring this symbol information.
+ This will usually allow your program to be debugged, though
+ certain symbols will not be accessible. If you encounter such a
+ problem and feel like debugging it, you can debug `gdb' with
+ itself, breakpoint on `complain', then go up to the function
+ `read_dbx_symtab' and examine `*bufp' to see the symbol.
+
+`stub type has NULL name'
+ GDB could not find the full definition for a struct or class.
+
+`const/volatile indicator missing (ok if using g++ v1.x), got...'
+ The symbol information for a C++ member function is missing some
+ information that recent versions of the compiler should have output
+ for it.
+
+`info mismatch between compiler and debugger'
+ GDB could not parse a type specification output by the compiler.
+
+
+File: gdb.info, Node: Targets, Next: Controlling GDB, Prev: GDB Files, Up: Top
+
+Specifying a Debugging Target
+*****************************
+
+ A "target" is the execution environment occupied by your program.
+Often, GDB runs in the same host environment as your program; in that
+case, the debugging target is specified as a side effect when you use
+the `file' or `core' commands. When you need more flexibility--for
+example, running GDB on a physically separate host, or controlling a
+standalone system over a serial port or a realtime system over a TCP/IP
+connection--you can use the `target' command to specify one of the
+target types configured for GDB (*note Commands for managing targets:
+Target Commands.).
+
+* Menu:
+
+* Active Targets:: Active targets
+* Target Commands:: Commands for managing targets
+* Remote:: Remote debugging
+
+
+File: gdb.info, Node: Active Targets, Next: Target Commands, Up: Targets
+
+Active targets
+==============
+
+ There are three classes of targets: processes, core files, and
+executable files. GDB can work concurrently on up to three active
+targets, one in each class. This allows you to (for example) start a
+process and inspect its activity without abandoning your work on a core
+file.
+
+ For example, if you execute `gdb a.out', then the executable file
+`a.out' is the only active target. If you designate a core file as
+well--presumably from a prior run that crashed and coredumped--then GDB
+has two active targets and will use them in tandem, looking first in
+the corefile target, then in the executable file, to satisfy requests
+for memory addresses. (Typically, these two classes of target are
+complementary, since core files contain only a program's read-write
+memory--variables and so on--plus machine status, while executable
+files contain only the program text and initialized data.)
+
+ When you type `run', your executable file becomes an active process
+target as well. When a process target is active, all GDB commands
+requesting memory addresses refer to that target; addresses in an
+active core file or executable file target are obscured while the
+process target is active.
+
+ Use the `core-file' and `exec-file' commands to select a new core
+file or executable target (*note Commands to specify files: Files.).
+To specify as a target a process that is already running, use the
+`attach' command (*note Debugging an already-running process: Attach.).
+
+
+File: gdb.info, Node: Target Commands, Next: Remote, Prev: Active Targets, Up: Targets
+
+Commands for managing targets
+=============================
+
+`target TYPE PARAMETERS'
+ Connects the GDB host environment to a target machine or process.
+ A target is typically a protocol for talking to debugging
+ facilities. You use the argument TYPE to specify the type or
+ protocol of the target machine.
+
+ Further PARAMETERS are interpreted by the target protocol, but
+ typically include things like device names or host names to connect
+ with, process numbers, and baud rates.
+
+ The `target' command will not repeat if you press RET again after
+ executing the command.
+
+`help target'
+ Displays the names of all targets available. To display targets
+ currently selected, use either `info target' or `info files'
+ (*note Commands to specify files: Files.).
+
+`help target NAME'
+ Describe a particular target, including any parameters necessary to
+ select it.
+
+ Here are some common targets (available, or not, depending on the GDB
+configuration):
+
+`target exec PROGRAM'
+ An executable file. `target exec PROGRAM' is the same as
+ `exec-file PROGRAM'.
+
+`target core FILENAME'
+ A core dump file. `target core FILENAME' is the same as
+ `core-file FILENAME'.
+
+`target remote DEV'
+ Remote serial target in GDB-specific protocol. The argument DEV
+ specifies what serial device to use for the connection (e.g.
+ `/dev/ttya'). *Note Remote debugging: Remote.
+
+`target sim'
+ CPU simulator. *Note Simulated CPU Target: Simulator.
+
+`target udi KEYWORD'
+ Remote AMD29K target, using the AMD UDI protocol. The KEYWORD
+ argument specifies which 29K board or simulator to use. *Note GDB
+ and the UDI protocol for AMD29K: UDI29K Remote.
+
+`target amd-eb DEV SPEED PROG'
+ Remote PC-resident AMD EB29K board, attached over serial lines.
+ dEV is the serial device, as for `target remote'; SPEED allows you
+ to specify the linespeed; and PROG is the name of the program to
+ be debugged, as it appears to DOS on the PC. *Note GDB with a
+ remote EB29K: EB29K Remote.
+
+`target hms'
+ A Hitachi SH, H8/300, or H8/500 board, attached via serial line to
+ your host. Use special commands `device' and `speed' to control
+ the serial line and the communications speed used. *Note GDB and
+ Hitachi Microprocessors: Hitachi Remote.
+
+`target nindy DEVICENAME'
+ An Intel 960 board controlled by a Nindy Monitor. DEVICENAME is
+ the name of the serial device to use for the connection, e.g.
+ `/dev/ttya'. *Note GDB with a remote i960 (Nindy): i960-Nindy
+ Remote.
+
+`target st2000 DEV SPEED'
+ A Tandem ST2000 phone switch, running Tandem's STDBUG protocol.
+ dEV is the name of the device attached to the ST2000 serial line;
+ SPEED is the communication line speed. The arguments are not used
+ if GDB is configured to connect to the ST2000 using TCP or Telnet.
+ *Note GDB with a Tandem ST2000: ST2000 Remote.
+
+`target vxworks MACHINENAME'
+ A VxWorks system, attached via TCP/IP. The argument MACHINENAME
+ is the target system's machine name or IP address. *Note GDB and
+ VxWorks: VxWorks Remote.
+
+ Different targets are available on different configurations of GDB;
+your configuration may have more or fewer targets.
+
+
+File: gdb.info, Node: Remote, Prev: Target Commands, Up: Targets
+
+Remote debugging
+================
+
+ If you are trying to debug a program running on a machine that
+cannot run GDB in the usual way, it is often useful to use remote
+debugging. For example, you might use remote debugging on an operating
+system kernel, or on a small system which does not have a general
+purpose operating system powerful enough to run a full-featured
+debugger.
+
+ Some configurations of GDB have special serial or TCP/IP interfaces
+to make this work with particular debugging targets. In addition, GDB
+comes with a generic serial protocol (specific to GDB, but not specific
+to any particular target system) which you can use if you write the
+remote stubs--the code that will run on the remote system to
+communicate with GDB.
+
+ Other remote targets may be available in your configuration of GDB;
+use `help targets' to list them.
+
+* Menu:
+
+
+* Remote Serial:: GDB remote serial protocol
+
+* i960-Nindy Remote:: GDB with a remote i960 (Nindy)
+
+* UDI29K Remote:: GDB and the UDI protocol for AMD29K
+* EB29K Remote:: GDB with a remote EB29K
+
+* VxWorks Remote:: GDB and VxWorks
+
+* ST2000 Remote:: GDB with a Tandem ST2000
+
+* Hitachi Remote:: GDB and Hitachi Microprocessors
+
+* MIPS Remote:: GDB and MIPS boards
+
+* Simulator:: Simulated CPU target
+
+
+File: gdb.info, Node: Remote Serial, Next: i960-Nindy Remote, Up: Remote
+
+The GDB remote serial protocol
+------------------------------
+
+ To debug a program running on another machine (the debugging
+"target" machine), you must first arrange for all the usual
+prerequisites for the program to run by itself. For example, for a C
+program, you need
+
+ 1. A startup routine to set up the C runtime environment; these
+ usually have a name like `crt0'. The startup routine may be
+ supplied by your hardware supplier, or you may have to write your
+ own.
+
+ 2. You probably need a C subroutine library to support your program's
+ subroutine calls, notably managing input and output.
+
+ 3. A way of getting your program to the other machine--for example, a
+ download program. These are often supplied by the hardware
+ manufacturer, but you may have to write your own from hardware
+ documentation.
+
+ The next step is to arrange for your program to use a serial port to
+communicate with the machine where GDB is running (the "host" machine).
+In general terms, the scheme looks like this:
+
+*On the host,*
+ GDB already understands how to use this protocol; when everything
+ else is set up, you can simply use the `target remote' command
+ (*note Specifying a Debugging Target: Targets.).
+
+*On the target,*
+ you must link with your program a few special-purpose subroutines
+ that implement the GDB remote serial protocol. The file
+ containing these subroutines is called a "debugging stub".
+
+ On certain remote targets, you can use an auxiliary program
+ `gdbserver' instead of linking a stub into your program. *Note
+ Using the `gdbserver' program: Server, for details.
+
+ The debugging stub is specific to the architecture of the remote
+machine; for example, use `sparc-stub.c' to debug programs on SPARC
+boards.
+
+ These working remote stubs are distributed with GDB:
+
+`sparc-stub.c'
+ For SPARC architectures.
+
+`m68k-stub.c'
+ For Motorola 680x0 architectures.
+
+`i386-stub.c'
+ For Intel 386 and compatible architectures.
+
+ The `README' file in the GDB distribution may list other recently
+added stubs.
+
+* Menu:
+
+* Stub Contents:: What the stub can do for you
+* Bootstrapping:: What you must do for the stub
+* Debug Session:: Putting it all together
+* Protocol:: Outline of the communication protocol
+
+* Server:: Using the `gdbserver' program
+
+
+File: gdb.info, Node: Stub Contents, Next: Bootstrapping, Up: Remote Serial
+
+What the stub can do for you
+----------------------------
+
+ The debugging stub for your architecture supplies these three
+subroutines:
+
+`set_debug_traps'
+ This routine arranges for `handle_exception' to run when your
+ program stops. You must call this subroutine explicitly near the
+ beginning of your program.
+
+`handle_exception'
+ This is the central workhorse, but your program never calls it
+ explicitly--the setup code arranges for `handle_exception' to run
+ when a trap is triggered.
+
+ `handle_exception' takes control when your program stops during
+ execution (for example, on a breakpoint), and mediates
+ communications with GDB on the host machine. This is where the
+ communications protocol is implemented; `handle_exception' acts as
+ the GDB representative on the target machine; it begins by sending
+ summary information on the state of your program, then continues
+ to execute, retrieving and transmitting any information GDB needs,
+ until you execute a GDB command that makes your program resume; at
+ that point, `handle_exception' returns control to your own code on
+ the target machine.
+
+`breakpoint'
+ Use this auxiliary subroutine to make your program contain a
+ breakpoint. Depending on the particular situation, this may be
+ the only way for GDB to get control. For instance, if your target
+ machine has some sort of interrupt button, you won't need to call
+ this; pressing the interrupt button will transfer control to
+ `handle_exception'--in effect, to GDB. On some machines, simply
+ receiving characters on the serial port may also trigger a trap;
+ again, in that situation, you don't need to call `breakpoint' from
+ your own program--simply running `target remote' from the host GDB
+ session will get control.
+
+ Call `breakpoint' if none of these is true, or if you simply want
+ to make certain your program stops at a predetermined point for the
+ start of your debugging session.
+
+
+File: gdb.info, Node: Bootstrapping, Next: Debug Session, Prev: Stub Contents, Up: Remote Serial
+
+What you must do for the stub
+-----------------------------
+
+ The debugging stubs that come with GDB are set up for a particular
+chip architecture, but they have no information about the rest of your
+debugging target machine. To allow the stub to work, you must supply
+these special low-level subroutines:
+
+`int getDebugChar()'
+ Write this subroutine to read a single character from the serial
+ port. It may be identical to `getchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+`void putDebugChar(int)'
+ Write this subroutine to write a single character to the serial
+ port. It may be identical to `putchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+`void exceptionHandler (int EXCEPTION_NUMBER, void *EXCEPTION_ADDRESS)'
+ Write this function to install EXCEPTION_ADDRESS in the exception
+ handling tables. You need to do this because the stub does not
+ have any way of knowing what the exception handling tables on your
+ target system are like (for example, the processor's table might
+ be in ROM, containing entries which point to a table in RAM).
+ eXCEPTION_NUMBER is the exception number which should be changed;
+ its meaning is architecture-dependent (for example, different
+ numbers might represent divide by zero, misaligned access, etc).
+ When this exception occurs, control should be transferred directly
+ to EXCEPTION_ADDRESS, and the processor state (stack, registers,
+ etc.) should be just as it is when a processor exception occurs.
+ So if you want to use a jump instruction to reach
+ EXCEPTION_ADDRESS, it should be a simple jump, not a jump to
+ subroutine.
+
+ For the 386, EXCEPTION_ADDRESS should be installed as an interrupt
+ gate so that interrupts are masked while the handler runs. The
+ gate should be at privilege level 0 (the most privileged level).
+ The SPARC and 68k stubs are able to mask interrupts themself
+ without help from `exceptionHandler'.
+
+`void flush_i_cache()'
+ Write this subroutine to flush the instruction cache, if any, on
+ your target machine. If there is no instruction cache, this
+ subroutine may be a no-op.
+
+ On target machines that have instruction caches, GDB requires this
+ function to make certain that the state of your program is stable.
+
+You must also make sure this library routine is available:
+
+`void *memset(void *, int, int)'
+ This is the standard library function `memset' that sets an area of
+ memory to a known value. If you have one of the free versions of
+ `libc.a', `memset' can be found there; otherwise, you must either
+ obtain it from your hardware manufacturer, or write your own.
+
+ If you do not use the GNU C compiler, you may need other standard
+library subroutines as well; this will vary from one stub to another,
+but in general the stubs are likely to use any of the common library
+subroutines which `gcc' generates as inline code.
+
+
+File: gdb.info, Node: Debug Session, Next: Protocol, Prev: Bootstrapping, Up: Remote Serial
+
+Putting it all together
+-----------------------
+
+ In summary, when your program is ready to debug, you must follow
+these steps.
+
+ 1. Make sure you have the supporting low-level routines (*note What
+ you must do for the stub: Bootstrapping.):
+ `getDebugChar', `putDebugChar',
+ `flush_i_cache', `memset', `exceptionHandler'.
+
+ 2. Insert these lines near the top of your program:
+
+ set_debug_traps();
+ breakpoint();
+
+ 3. For the 680x0 stub only, you need to provide a variable called
+ `exceptionHook'. Normally you just use
+
+ void (*exceptionHook)() = 0;
+
+ but if before calling `set_debug_traps', you set it to point to a
+ function in your program, that function is called when `GDB'
+ continues after stopping on a trap (for example, bus error). The
+ function indicated by `exceptionHook' is called with one
+ parameter: an `int' which is the exception number.
+
+ 4. Compile and link together: your program, the GDB debugging stub for
+ your target architecture, and the supporting subroutines.
+
+ 5. Make sure you have a serial connection between your target machine
+ and the GDB host, and identify the serial port used for this on
+ the host.
+
+ 6. Download your program to your target machine (or get it there by
+ whatever means the manufacturer provides), and start it.
+
+ 7. To start remote debugging, run GDB on the host machine, and specify
+ as an executable file the program that is running in the remote
+ machine. This tells GDB how to find your program's symbols and
+ the contents of its pure text.
+
+ Then establish communication using the `target remote' command.
+ Its argument specifies how to communicate with the target
+ machine--either via a devicename attached to a direct serial line,
+ or a TCP port (usually to a terminal server which in turn has a
+ serial line to the target). For example, to use a serial line
+ connected to the device named `/dev/ttyb':
+
+ target remote /dev/ttyb
+
+ To use a TCP connection, use an argument of the form `HOST:port'.
+ For example, to connect to port 2828 on a terminal server named
+ `manyfarms':
+
+ target remote manyfarms:2828
+
+ Now you can use all the usual commands to examine and change data
+and to step and continue the remote program.
+
+ To resume the remote program and stop debugging it, use the `detach'
+command.
+
+ Whenever GDB is waiting for the remote program, if you type the
+interrupt character (often C-C), GDB attempts to stop the program.
+This may or may not succeed, depending in part on the hardware and the
+serial drivers the remote system uses. If you type the interrupt
+character once again, GDB displays this prompt:
+
+ Interrupted while waiting for the program.
+ Give up (and stop debugging it)? (y or n)
+
+ If you type `y', GDB abandons the remote debugging session. (If you
+decide you want to try again later, you can use `target remote' again
+to connect once more.) If you type `n', GDB goes back to waiting.
+
+
+File: gdb.info, Node: Protocol, Next: Server, Prev: Debug Session, Up: Remote Serial
+
+Outline of the communication protocol
+-------------------------------------
+
+ The stub files provided with GDB implement the target side of the
+communication protocol, and the GDB side is implemented in the GDB
+source file `remote.c'. Normally, you can simply allow these
+subroutines to communicate, and ignore the details. (If you're
+implementing your own stub file, you can still ignore the details: start
+with one of the existing stub files. `sparc-stub.c' is the best
+organized, and therefore the easiest to read.)
+
+ However, there may be occasions when you need to know something about
+the protocol--for example, if there is only one serial port to your
+target machine, you might want your program to do something special if
+it recognizes a packet meant for GDB.
+
+ All GDB commands and responses (other than acknowledgements, which
+are single characters) are sent as a packet which includes a checksum.
+A packet is introduced with the character `$', and ends with the
+character `#' followed by a two-digit checksum:
+
+ $PACKET INFO#CHECKSUM
+
+CHECKSUM is computed as the modulo 256 sum of the PACKET INFO
+characters.
+
+ When either the host or the target machine receives a packet, the
+first response expected is an acknowledgement: a single character,
+either `+' (to indicate the package was received correctly) or `-' (to
+request retransmission).
+
+ The host (GDB) sends commands, and the target (the debugging stub
+incorporated in your program) sends data in response. The target also
+sends data when your program stops.
+
+ Command packets are distinguished by their first character, which
+identifies the kind of command.
+
+ These are the commands currently supported:
+
+`g'
+ Requests the values of CPU registers.
+
+`G'
+ Sets the values of CPU registers.
+
+`mADDR,COUNT'
+ Read COUNT bytes at location ADDR.
+
+`MADDR,COUNT:...'
+ Write COUNT bytes at location ADDR.
+
+`c'
+`cADDR'
+ Resume execution at the current address (or at ADDR if supplied).
+
+`s'
+`sADDR'
+ Step the target program for one instruction, from either the
+ current program counter or from ADDR if supplied.
+
+`k'
+ Kill the target program.
+
+`?'
+ Report the most recent signal. To allow you to take advantage of
+ the GDB signal handling commands, one of the functions of the
+ debugging stub is to report CPU traps as the corresponding POSIX
+ signal values.
+
+ If you have trouble with the serial connection, you can use the
+command `set remotedebug'. This makes GDB report on all packets sent
+back and forth across the serial line to the remote machine. The
+packet-debugging information is printed on the GDB standard output
+stream. `set remotedebug off' turns it off, and `show remotedebug'
+will show you its current state.
+
+
+File: gdb.info, Node: Server, Prev: Protocol, Up: Remote Serial
+
+Using the `gdbserver' program
+-----------------------------
+
+ `gdbserver' is a control program for Unix-like systems, which allows
+you to connect your program with a remote GDB via `target remote'--but
+without linking in the usual debugging stub.
+
+ `gdbserver' is not a complete replacement for the debugging stubs,
+because it requires essentially the same operating-system facilities
+that GDB itself does. In fact, a system that can run `gdbserver' to
+connect to a remote GDB could also run GDBN locally! `gdbserver' is
+sometimes useful nevertheless, because it is a much smaller program
+than GDB itself. It is also easier to port than all of GDBN, so you
+may be able to get started more quickly on a new system by using
+`gdbserver'.
+
+ GDB and `gdbserver' communicate via either a serial line or a TCP
+connection, using the standard GDB remote serial protocol.
+
+*On the target,*
+ you need to have a copy of the program you want to debug.
+ `gdbserver' does not need your program's symbol table, so you can
+ strip the program if necessary to save space. GDB on the host
+ system does all the symbol handling.
+
+ To use the server, you must tell it how to communicate with {No
+ Value For "GDB"}; the name of your program; and the arguments for
+ your program. The syntax is:
+
+ target> gdbserver COMM PROGRAM [ ARGS ... ]
+
+ COMM is either a device name (to use a serial line) or a TCP
+ hostname and portnumber. For example, to debug emacs with the
+ argument `foo.txt' and communicate with GDB over the serial port
+ `/dev/com1':
+
+ target> gdbserver /dev/com1 emacs foo.txt
+
+ `gdbserver' waits passively for the host GDB to communicate with
+ it.
+
+ To use a TCP connection instead of a serial line:
+
+ target> gdbserver host:2345 emacs foo.txt
+
+ The only difference from the previous example is the first
+ argument, specifying that you are communicating with the host GDB
+ via TCP. The `host:2345' argument means that `gdbserver' is to
+ expect a TCP connection from machine `host' to local TCP port 2345.
+ (Currently, the `host' part is ignored.) You can choose any number
+ you want for the port number as long as it does not conflict with
+ any TCP ports already in use on the target system.(1) You must use
+ the same port number with the host GDB `target remote' command.
+
+*On the host,*
+ you need an unstripped copy of your program, since GDB needs
+ symbols and debugging information. Start up GDB as usual, using
+ the name of the local copy of your program as the first argument.
+ (You may also need the `--baud' option if the serial line is
+ running at anything other than 9600 bps.) After that, use `target
+ remote' to establish communications with `gdbserver'. Its
+ argument is either a device name (usually a serial device, like
+ `/dev/ttyb'), or a TCP port descriptof in the form `HOST:PORT'.
+ For example:
+
+ (gdb) target remote /dev/ttyb
+
+ communicates with the server via serial line `/dev/ttyb', and
+
+ (gdb) target remote the-target:2345
+
+ communicates via a TCP connection to port 2345 on host
+ `the-target'. For TCP connections, you must start up `gdbserver'
+ prior to using the `target remote' command. Otherwise you may get
+ an error whose text depends on the host system, but which usually
+ looks something like `Connection refused'.
+
+ ---------- Footnotes ----------
+
+ (1) If you choose a port number that conflicts with another
+service, `gdbserver' prints an error message and exits.
+
+
+File: gdb.info, Node: i960-Nindy Remote, Next: UDI29K Remote, Prev: Remote Serial, Up: Remote
+
+GDB with a remote i960 (Nindy)
+------------------------------
+
+ "Nindy" is a ROM Monitor program for Intel 960 target systems. When
+GDB is configured to control a remote Intel 960 using Nindy, you can
+tell GDB how to connect to the 960 in several ways:
+
+ * Through command line options specifying serial port, version of the
+ Nindy protocol, and communications speed;
+
+ * By responding to a prompt on startup;
+
+ * By using the `target' command at any point during your GDB
+ session. *Note Commands for managing targets: Target Commands.
+
+* Menu:
+
+* Nindy Startup:: Startup with Nindy
+* Nindy Options:: Options for Nindy
+* Nindy Reset:: Nindy reset command
+
+
+File: gdb.info, Node: Nindy Startup, Next: Nindy Options, Up: i960-Nindy Remote
+
+Startup with Nindy
+------------------
+
+ If you simply start `gdb' without using any command-line options,
+you are prompted for what serial port to use, *before* you reach the
+ordinary GDB prompt:
+
+ Attach /dev/ttyNN -- specify NN, or "quit" to quit:
+
+Respond to the prompt with whatever suffix (after `/dev/tty')
+identifies the serial port you want to use. You can, if you choose,
+simply start up with no Nindy connection by responding to the prompt
+with an empty line. If you do this and later wish to attach to Nindy,
+use `target' (*note Commands for managing targets: Target Commands.).
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-6 b/gnu/usr.bin/gdb/doc/gdb.info-6
new file mode 100644
index 000000000000..8a746fd77b6d
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-6
@@ -0,0 +1,1220 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Nindy Options, Next: Nindy Reset, Prev: Nindy Startup, Up: i960-Nindy Remote
+
+Options for Nindy
+-----------------
+
+ These are the startup options for beginning your GDB session with a
+Nindy-960 board attached:
+
+`-r PORT'
+ Specify the serial port name of a serial interface to be used to
+ connect to the target system. This option is only available when
+ GDB is configured for the Intel 960 target architecture. You may
+ specify PORT as any of: a full pathname (e.g. `-r /dev/ttya'), a
+ device name in `/dev' (e.g. `-r ttya'), or simply the unique
+ suffix for a specific `tty' (e.g. `-r a').
+
+`-O'
+ (An uppercase letter "O", not a zero.) Specify that GDB should use
+ the "old" Nindy monitor protocol to connect to the target system.
+ This option is only available when GDB is configured for the Intel
+ 960 target architecture.
+
+ *Warning:* if you specify `-O', but are actually trying to
+ connect to a target system that expects the newer protocol,
+ the connection fails, appearing to be a speed mismatch. GDB
+ repeatedly attempts to reconnect at several different line
+ speeds. You can abort this process with an interrupt.
+
+`-brk'
+ Specify that GDB should first send a `BREAK' signal to the target
+ system, in an attempt to reset it, before connecting to a Nindy
+ target.
+
+ *Warning:* Many target systems do not have the hardware that
+ this requires; it only works with a few boards.
+
+ The standard `-b' option controls the line speed used on the serial
+port.
+
+
+File: gdb.info, Node: Nindy Reset, Prev: Nindy Options, Up: i960-Nindy Remote
+
+Nindy reset command
+-------------------
+
+`reset'
+ For a Nindy target, this command sends a "break" to the remote
+ target system; this is only useful if the target has been equipped
+ with a circuit to perform a hard reset (or some other interesting
+ action) when a break is detected.
+
+
+File: gdb.info, Node: UDI29K Remote, Next: EB29K Remote, Prev: i960-Nindy Remote, Up: Remote
+
+GDB and the UDI protocol for AMD29K
+-----------------------------------
+
+ GDB supports AMD's UDI ("Universal Debugger Interface") protocol for
+debugging the a29k processor family. To use this configuration with
+AMD targets running the MiniMON monitor, you need the program `MONTIP',
+available from AMD at no charge. You can also use GDB with the UDI
+conformant a29k simulator program `ISSTIP', also available from AMD.
+
+`target udi KEYWORD'
+ Select the UDI interface to a remote a29k board or simulator, where
+ KEYWORD is an entry in the AMD configuration file `udi_soc'. This
+ file contains keyword entries which specify parameters used to
+ connect to a29k targets. If the `udi_soc' file is not in your
+ working directory, you must set the environment variable `UDICONF'
+ to its pathname.
+
+
+File: gdb.info, Node: EB29K Remote, Next: VxWorks Remote, Prev: UDI29K Remote, Up: Remote
+
+GDB and the EBMON protocol for AMD29K
+-------------------------------------
+
+ AMD distributes a 29K development board meant to fit in a PC,
+together with a DOS-hosted monitor program called `EBMON'. As a
+shorthand term, this development system is called the "EB29K". To use
+GDB from a Unix system to run programs on the EB29K board, you must
+first connect a serial cable between the PC (which hosts the EB29K
+board) and a serial port on the Unix system. In the following, we
+assume you've hooked the cable between the PC's `COM1' port and
+`/dev/ttya' on the Unix system.
+
+* Menu:
+
+* Comms (EB29K):: Communications setup
+* gdb-EB29K:: EB29K cross-debugging
+* Remote Log:: Remote log
+
+
+File: gdb.info, Node: Comms (EB29K), Next: gdb-EB29K, Up: EB29K Remote
+
+Communications setup
+--------------------
+
+ The next step is to set up the PC's port, by doing something like
+this in DOS on the PC:
+
+ C:\> MODE com1:9600,n,8,1,none
+
+This example--run on an MS DOS 4.0 system--sets the PC port to 9600
+bps, no parity, eight data bits, one stop bit, and no "retry" action;
+you must match the communications parameters when establishing the Unix
+end of the connection as well.
+
+ To give control of the PC to the Unix side of the serial line, type
+the following at the DOS console:
+
+ C:\> CTTY com1
+
+(Later, if you wish to return control to the DOS console, you can use
+the command `CTTY con'--but you must send it over the device that had
+control, in our example over the `COM1' serial line).
+
+ From the Unix host, use a communications program such as `tip' or
+`cu' to communicate with the PC; for example,
+
+ cu -s 9600 -l /dev/ttya
+
+The `cu' options shown specify, respectively, the linespeed and the
+serial port to use. If you use `tip' instead, your command line may
+look something like the following:
+
+ tip -9600 /dev/ttya
+
+Your system may require a different name where we show `/dev/ttya' as
+the argument to `tip'. The communications parameters, including which
+port to use, are associated with the `tip' argument in the "remote"
+descriptions file--normally the system table `/etc/remote'.
+
+ Using the `tip' or `cu' connection, change the DOS working directory
+to the directory containing a copy of your 29K program, then start the
+PC program `EBMON' (an EB29K control program supplied with your board
+by AMD). You should see an initial display from `EBMON' similar to the
+one that follows, ending with the `EBMON' prompt `#'--
+
+ C:\> G:
+
+ G:\> CD \usr\joe\work29k
+
+ G:\USR\JOE\WORK29K> EBMON
+ Am29000 PC Coprocessor Board Monitor, version 3.0-18
+ Copyright 1990 Advanced Micro Devices, Inc.
+ Written by Gibbons and Associates, Inc.
+
+ Enter '?' or 'H' for help
+
+ PC Coprocessor Type = EB29K
+ I/O Base = 0x208
+ Memory Base = 0xd0000
+
+ Data Memory Size = 2048KB
+ Available I-RAM Range = 0x8000 to 0x1fffff
+ Available D-RAM Range = 0x80002000 to 0x801fffff
+
+ PageSize = 0x400
+ Register Stack Size = 0x800
+ Memory Stack Size = 0x1800
+
+ CPU PRL = 0x3
+ Am29027 Available = No
+ Byte Write Available = Yes
+
+ # ~.
+
+ Then exit the `cu' or `tip' program (done in the example by typing
+`~.' at the `EBMON' prompt). `EBMON' will keep running, ready for GDB
+to take over.
+
+ For this example, we've assumed what is probably the most convenient
+way to make sure the same 29K program is on both the PC and the Unix
+system: a PC/NFS connection that establishes "drive `G:'" on the PC as
+a file system on the Unix host. If you do not have PC/NFS or something
+similar connecting the two systems, you must arrange some other
+way--perhaps floppy-disk transfer--of getting the 29K program from the
+Unix system to the PC; GDB will *not* download it over the serial line.
+
+
+File: gdb.info, Node: gdb-EB29K, Next: Remote Log, Prev: Comms (EB29K), Up: EB29K Remote
+
+EB29K cross-debugging
+---------------------
+
+ Finally, `cd' to the directory containing an image of your 29K
+program on the Unix system, and start GDB--specifying as argument the
+name of your 29K program:
+
+ cd /usr/joe/work29k
+ gdb myfoo
+
+ Now you can use the `target' command:
+
+ target amd-eb /dev/ttya 9600 MYFOO
+
+In this example, we've assumed your program is in a file called
+`myfoo'. Note that the filename given as the last argument to `target
+amd-eb' should be the name of the program as it appears to DOS. In our
+example this is simply `MYFOO', but in general it can include a DOS
+path, and depending on your transfer mechanism may not resemble the
+name on the Unix side.
+
+ At this point, you can set any breakpoints you wish; when you are
+ready to see your program run on the 29K board, use the GDB command
+`run'.
+
+ To stop debugging the remote program, use the GDB `detach' command.
+
+ To return control of the PC to its console, use `tip' or `cu' once
+again, after your GDB session has concluded, to attach to `EBMON'. You
+can then type the command `q' to shut down `EBMON', returning control
+to the DOS command-line interpreter. Type `CTTY con' to return command
+input to the main DOS console, and type `~.' to leave `tip' or `cu'.
+
+
+File: gdb.info, Node: Remote Log, Prev: gdb-EB29K, Up: EB29K Remote
+
+Remote log
+----------
+
+ The `target amd-eb' command creates a file `eb.log' in the current
+working directory, to help debug problems with the connection.
+`eb.log' records all the output from `EBMON', including echoes of the
+commands sent to it. Running `tail -f' on this file in another window
+often helps to understand trouble with `EBMON', or unexpected events on
+the PC side of the connection.
+
+
+File: gdb.info, Node: ST2000 Remote, Next: Hitachi Remote, Prev: VxWorks Remote, Up: Remote
+
+GDB with a Tandem ST2000
+------------------------
+
+ To connect your ST2000 to the host system, see the manufacturer's
+manual. Once the ST2000 is physically attached, you can run
+
+ target st2000 DEV SPEED
+
+to establish it as your debugging environment. DEV is normally the
+name of a serial device, such as `/dev/ttya', connected to the ST2000
+via a serial line. You can instead specify DEV as a TCP connection
+(for example, to a serial line attached via a terminal concentrator)
+using the syntax `HOSTNAME:PORTNUMBER'.
+
+ The `load' and `attach' commands are *not* defined for this target;
+you must load your program into the ST2000 as you normally would for
+standalone operation. GDB will read debugging information (such as
+symbols) from a separate, debugging version of the program available on
+your host computer.
+
+ These auxiliary GDB commands are available to help you with the
+ST2000 environment:
+
+`st2000 COMMAND'
+ Send a COMMAND to the STDBUG monitor. See the manufacturer's
+ manual for available commands.
+
+`connect'
+ Connect the controlling terminal to the STDBUG command monitor.
+ When you are done interacting with STDBUG, typing either of two
+ character sequences will get you back to the GDB command prompt:
+ `RET~.' (Return, followed by tilde and period) or `RET~C-d'
+ (Return, followed by tilde and control-D).
+
+
+File: gdb.info, Node: VxWorks Remote, Next: ST2000 Remote, Prev: EB29K Remote, Up: Remote
+
+GDB and VxWorks
+---------------
+
+ GDB enables developers to spawn and debug tasks running on networked
+VxWorks targets from a Unix host. Already-running tasks spawned from
+the VxWorks shell can also be debugged. GDB uses code that runs on
+both the Unix host and on the VxWorks target. The program `gdb' is
+installed and executed on the Unix host. (It may be installed with the
+name `vxgdb', to distinguish it from a GDB for debugging programs on
+the host itself.)
+
+ The following information on connecting to VxWorks was current when
+this manual was produced; newer releases of VxWorks may use revised
+procedures.
+
+ The remote debugging interface (RDB) routines are installed and
+executed on the VxWorks target. These routines are included in the
+VxWorks library `rdb.a' and are incorporated into the system image when
+source-level debugging is enabled in the VxWorks configuration.
+
+ If you wish, you can define `INCLUDE_RDB' in the VxWorks
+configuration file `configAll.h' to include the RDB interface routines
+and spawn the source debugging task `tRdbTask' when VxWorks is booted.
+For more information on configuring and remaking VxWorks, see the
+manufacturer's manual.
+
+ Once you have included the RDB interface in your VxWorks system image
+and set your Unix execution search path to find GDB, you are ready to
+run GDB. From your Unix host, run `gdb' (or `vxgdb', depending on your
+installation).
+
+ GDB comes up showing the prompt:
+
+ (vxgdb)
+
+* Menu:
+
+* VxWorks Connection:: Connecting to VxWorks
+* VxWorks Download:: VxWorks download
+* VxWorks Attach:: Running tasks
+
+
+File: gdb.info, Node: VxWorks Connection, Next: VxWorks Download, Up: VxWorks Remote
+
+Connecting to VxWorks
+---------------------
+
+ The GDB command `target' lets you connect to a VxWorks target on the
+network. To connect to a target whose host name is "`tt'", type:
+
+ (vxgdb) target vxworks tt
+
+ GDB displays messages like these:
+
+ Attaching remote machine across net...
+ Connected to tt.
+
+ GDB then attempts to read the symbol tables of any object modules
+loaded into the VxWorks target since it was last booted. GDB locates
+these files by searching the directories listed in the command search
+path (*note Your program's environment: Environment.); if it fails to
+find an object file, it displays a message such as:
+
+ prog.o: No such file or directory.
+
+ When this happens, add the appropriate directory to the search path
+with the GDB command `path', and execute the `target' command again.
+
+
+File: gdb.info, Node: VxWorks Download, Next: VxWorks Attach, Prev: VxWorks Connection, Up: VxWorks Remote
+
+VxWorks download
+----------------
+
+ If you have connected to the VxWorks target and you want to debug an
+object that has not yet been loaded, you can use the GDB `load' command
+to download a file from Unix to VxWorks incrementally. The object file
+given as an argument to the `load' command is actually opened twice:
+first by the VxWorks target in order to download the code, then by GDB
+in order to read the symbol table. This can lead to problems if the
+current working directories on the two systems differ. If both systems
+have NFS mounted the same filesystems, you can avoid these problems by
+using absolute paths. Otherwise, it is simplest to set the working
+directory on both systems to the directory in which the object file
+resides, and then to reference the file by its name, without any path.
+For instance, a program `prog.o' may reside in `VXPATH/vw/demo/rdb' in
+VxWorks and in `HOSTPATH/vw/demo/rdb' on the host. To load this
+program, type this on VxWorks:
+
+ -> cd "VXPATH/vw/demo/rdb"
+
+ Then, in GDB, type:
+
+ (vxgdb) cd HOSTPATH/vw/demo/rdb
+ (vxgdb) load prog.o
+
+ GDB displays a response similar to this:
+
+ Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+
+ You can also use the `load' command to reload an object module after
+editing and recompiling the corresponding source file. Note that this
+will cause GDB to delete all currently-defined breakpoints,
+auto-displays, and convenience variables, and to clear the value
+history. (This is necessary in order to preserve the integrity of
+debugger data structures that reference the target system's symbol
+table.)
+
+
+File: gdb.info, Node: VxWorks Attach, Prev: VxWorks Download, Up: VxWorks Remote
+
+Running tasks
+-------------
+
+ You can also attach to an existing task using the `attach' command as
+follows:
+
+ (vxgdb) attach TASK
+
+where TASK is the VxWorks hexadecimal task ID. The task can be running
+or suspended when you attach to it. If running, it will be suspended at
+the time of attachment.
+
+
+File: gdb.info, Node: Hitachi Remote, Next: MIPS Remote, Prev: ST2000 Remote, Up: Remote
+
+GDB and Hitachi Microprocessors
+-------------------------------
+
+ GDB needs to know these things to talk to your Hitachi SH, H8/300,
+or H8/500:
+
+ 1. that you want to use `target hms', the remote debugging interface
+ for Hitachi microprocessors (this is the default when GDB is
+ configured specifically for the Hitachi SH, H8/300, or H8/500);
+
+ 2. what serial device connects your host to your Hitachi board (the
+ first serial device available on your host is the default);
+
+
+ Use the special `gdb' command `device PORT' if you need to
+explicitly set the serial device. The default PORT is the first
+available port on your host. This is only necessary on Unix hosts,
+where it is typically something like `/dev/ttya'.
+
+ `gdb' has another special command to set the communications speed:
+`speed BPS'. This command also is only used from Unix hosts; on DOS
+hosts, set the line speed as usual from outside GDB with the DOS `mode'
+command (for instance, `mode com2:9600,n,8,1,p' for a 9600 bps
+connection).
+
+ The `device' and `speed' commands are available only when you use a
+Unix host to debug your Hitachi microprocessor programs. If you use a
+DOS host, GDB depends on an auxiliary terminate-and-stay-resident
+program called `asynctsr' to communicate with the development board
+through a PC serial port. You must also use the DOS `mode' command to
+set up the serial port on the DOS side.
+
+
+File: gdb.info, Node: MIPS Remote, Next: Simulator, Prev: Hitachi Remote, Up: Remote
+
+GDB and remote MIPS boards
+--------------------------
+
+ GDB can use the MIPS remote debugging protocol to talk to a MIPS
+board attached to a serial line. This is available when you configure
+GDB with `--target=mips-idt-ecoff'.
+
+ To run a program on the board, start up `gdb' with the name of your
+program as the argument. To connect to the board, use the command
+`target mips PORT', where PORT is the name of the serial port connected
+to the board. If the program has not already been downloaded to the
+board, you may use the `load' command to download it. You can then use
+all the usual GDB commands.
+
+ You can also specify PORT as a TCP connection (for instance, to a
+serial line managed by a terminal concentrator), using the syntax
+`HOSTNAME:PORTNUMBER'.
+
+ You can see some debugging information about communications with the
+board by setting the `remotedebug' variable. If you set it to 1 using
+`set remotedebug 1' every packet will be displayed. If you set it to 2
+every character will be displayed. You can check the current value at
+any time with the command `show remotedebug'.
+
+ You can control the timeout used while waiting for a packet, in the
+MIPS remote protocol, with the `set timeout SECONDS' command. The
+default is 5 seconds. Similarly, you can control the timeout used while
+waiting for an acknowledgement of a packet with the `set
+retransmit-timeout SECONDS' command. The default is 3 seconds. You
+can inspect both values with `show timeout' and `show
+retransmit-timeout'. (These commands are *only* available when GDB is
+configured for `--target=mips-idt-ecoff'.)
+
+ If your target board does not support the MIPS floating point
+coprocessor, you should use the command `set mipsfpu off' (you may wish
+to put this in your .gdbinit file). This tells GDB how to find the
+return value of functions which return floating point values. It also
+allows GDB to avoid saving the floating point registers when calling
+functions on the board.
+
+
+File: gdb.info, Node: Simulator, Prev: MIPS Remote, Up: Remote
+
+Simulated CPU target
+--------------------
+
+ For some configurations, GDB includes a CPU simulator that you can
+use instead of a hardware CPU to debug your programs. Currently, a
+simulator is available when GDB is configured to debug Zilog Z8000 or
+Hitachi microprocessor targets.
+
+ For the Z8000 family, `target sim' simulates either the Z8002 (the
+unsegmented variant of the Z8000 architecture) or the Z8001 (the
+segmented variant). The simulator recognizes which architecture is
+appropriate by inspecting the object code.
+
+`target sim'
+ Debug programs on a simulated CPU (which CPU depends on the GDB
+ configuration)
+
+After specifying this target, you can debug programs for the simulated
+CPU in the same style as programs for your host computer; use the
+`file' command to load a new program image, the `run' command to run
+your program, and so on.
+
+ As well as making available all the usual machine registers (see
+`info reg'), this debugging target provides three additional items of
+information as specially named registers:
+
+`cycles'
+ Counts clock-ticks in the simulator.
+
+`insts'
+ Counts instructions run in the simulator.
+
+`time'
+ Execution time in 60ths of a second.
+
+ You can refer to these values in GDB expressions with the usual
+conventions; for example, `b fputc if $cycles>5000' sets a conditional
+breakpoint that will suspend only after at least 5000 simulated clock
+ticks.
+
+
+File: gdb.info, Node: Controlling GDB, Next: Sequences, Prev: Targets, Up: Top
+
+Controlling GDB
+***************
+
+ You can alter the way GDB interacts with you by using the `set'
+command. For commands controlling how GDB displays data, *note Print
+settings: Print Settings.; other settings are described here.
+
+* Menu:
+
+* Prompt:: Prompt
+* Editing:: Command editing
+* History:: Command history
+* Screen Size:: Screen size
+* Numbers:: Numbers
+* Messages/Warnings:: Optional warnings and messages
+
+
+File: gdb.info, Node: Prompt, Next: Editing, Up: Controlling GDB
+
+Prompt
+======
+
+ GDB indicates its readiness to read a command by printing a string
+called the "prompt". This string is normally `(gdb)'. You can change
+the prompt string with the `set prompt' command. For instance, when
+debugging GDB with GDB, it is useful to change the prompt in one of the
+GDB sessions so that you can always tell which one you are talking to.
+
+`set prompt NEWPROMPT'
+ Directs GDB to use NEWPROMPT as its prompt string henceforth.
+
+`show prompt'
+ Prints a line of the form: `Gdb's prompt is: YOUR-PROMPT'
+
+
+File: gdb.info, Node: Editing, Next: History, Prev: Prompt, Up: Controlling GDB
+
+Command editing
+===============
+
+ GDB reads its input commands via the "readline" interface. This GNU
+library provides consistent behavior for programs which provide a
+command line interface to the user. Advantages are `emacs'-style or
+`vi'-style inline editing of commands, `csh'-like history substitution,
+and a storage and recall of command history across debugging sessions.
+
+ You may control the behavior of command line editing in GDB with the
+command `set'.
+
+`set editing'
+`set editing on'
+ Enable command line editing (enabled by default).
+
+`set editing off'
+ Disable command line editing.
+
+`show editing'
+ Show whether command line editing is enabled.
+
+
+File: gdb.info, Node: History, Next: Screen Size, Prev: Editing, Up: Controlling GDB
+
+Command history
+===============
+
+ GDB can keep track of the commands you type during your debugging
+sessions, so that you can be certain of precisely what happened. Use
+these commands to manage the GDB command history facility.
+
+`set history filename FNAME'
+ Set the name of the GDB command history file to FNAME. This is
+ the file from which GDB will read an initial command history list
+ or to which it will write this list when it exits. This list is
+ accessed through history expansion or through the history command
+ editing characters listed below. This file defaults to the value
+ of the environment variable `GDBHISTFILE', or to `./.gdb_history'
+ if this variable is not set.
+
+`set history save'
+`set history save on'
+ Record command history in a file, whose name may be specified with
+ the `set history filename' command. By default, this option is
+ disabled.
+
+`set history save off'
+ Stop recording command history in a file.
+
+`set history size SIZE'
+ Set the number of commands which GDB will keep in its history list.
+ This defaults to the value of the environment variable `HISTSIZE',
+ or to 256 if this variable is not set.
+
+ History expansion assigns special meaning to the character `!'.
+
+ Since `!' is also the logical not operator in C, history expansion
+is off by default. If you decide to enable history expansion with the
+`set history expansion on' command, you may sometimes need to follow
+`!' (when it is used as logical not, in an expression) with a space or
+a tab to prevent it from being expanded. The readline history
+facilities will not attempt substitution on the strings `!=' and `!(',
+even when history expansion is enabled.
+
+ The commands to control history expansion are:
+
+`set history expansion on'
+`set history expansion'
+ Enable history expansion. History expansion is off by default.
+
+`set history expansion off'
+ Disable history expansion.
+
+ The readline code comes with more complete documentation of
+ editing and history expansion features. Users unfamiliar with
+ `emacs' or `vi' may wish to read it.
+
+`show history'
+`show history filename'
+`show history save'
+`show history size'
+`show history expansion'
+ These commands display the state of the GDB history parameters.
+ `show history' by itself displays all four states.
+
+`show commands'
+ Display the last ten commands in the command history.
+
+`show commands N'
+ Print ten commands centered on command number N.
+
+`show commands +'
+ Print ten commands just after the commands last printed.
+
+
+File: gdb.info, Node: Screen Size, Next: Numbers, Prev: History, Up: Controlling GDB
+
+Screen size
+===========
+
+ Certain commands to GDB may produce large amounts of information
+output to the screen. To help you read all of it, GDB pauses and asks
+you for input at the end of each page of output. Type RET when you
+want to continue the output, or `q' to discard the remaining output.
+Also, the screen width setting determines when to wrap lines of output.
+Depending on what is being printed, GDB tries to break the line at a
+readable place, rather than simply letting it overflow onto the
+following line.
+
+ Normally GDB knows the size of the screen from the termcap data base
+together with the value of the `TERM' environment variable and the
+`stty rows' and `stty cols' settings. If this is not correct, you can
+override it with the `set height' and `set width' commands:
+
+`set height LPP'
+`show height'
+`set width CPL'
+`show width'
+ These `set' commands specify a screen height of LPP lines and a
+ screen width of CPL characters. The associated `show' commands
+ display the current settings.
+
+ If you specify a height of zero lines, GDB will not pause during
+ output no matter how long the output is. This is useful if output
+ is to a file or to an editor buffer.
+
+ Likewise, you can specify `set width 0' to prevent GDB from
+ wrapping its output.
+
+
+File: gdb.info, Node: Numbers, Next: Messages/Warnings, Prev: Screen Size, Up: Controlling GDB
+
+Numbers
+=======
+
+ You can always enter numbers in octal, decimal, or hexadecimal in
+GDB by the usual conventions: octal numbers begin with `0', decimal
+numbers end with `.', and hexadecimal numbers begin with `0x'. Numbers
+that begin with none of these are, by default, entered in base 10;
+likewise, the default display for numbers--when no particular format is
+specified--is base 10. You can change the default base for both input
+and output with the `set radix' command.
+
+`set radix BASE'
+ Set the default base for numeric input and display. Supported
+ choices for BASE are decimal 8, 10, or 16. BASE must itself be
+ specified either unambiguously or using the current default radix;
+ for example, any of
+
+ set radix 012
+ set radix 10.
+ set radix 0xa
+
+ will set the base to decimal. On the other hand, `set radix 10'
+ will leave the radix unchanged no matter what it was.
+
+`show radix'
+ Display the current default base for numeric input and display.
+
+
+File: gdb.info, Node: Messages/Warnings, Prev: Numbers, Up: Controlling GDB
+
+Optional warnings and messages
+==============================
+
+ By default, GDB is silent about its inner workings. If you are
+running on a slow machine, you may want to use the `set verbose'
+command. It will make GDB tell you when it does a lengthy internal
+operation, so you will not think it has crashed.
+
+ Currently, the messages controlled by `set verbose' are those which
+announce that the symbol table for a source file is being read; see
+`symbol-file' in *Note Commands to specify files: Files.
+
+`set verbose on'
+ Enables GDB output of certain informational messages.
+
+`set verbose off'
+ Disables GDB output of certain informational messages.
+
+`show verbose'
+ Displays whether `set verbose' is on or off.
+
+ By default, if GDB encounters bugs in the symbol table of an object
+file, it is silent; but if you are debugging a compiler, you may find
+this information useful (*note Errors reading symbol files: Symbol
+Errors.).
+
+`set complaints LIMIT'
+ Permits GDB to output LIMIT complaints about each type of unusual
+ symbols before becoming silent about the problem. Set LIMIT to
+ zero to suppress all complaints; set it to a large number to
+ prevent complaints from being suppressed.
+
+`show complaints'
+ Displays how many symbol complaints GDB is permitted to produce.
+
+ By default, GDB is cautious, and asks what sometimes seems to be a
+lot of stupid questions to confirm certain commands. For example, if
+you try to run a program which is already running:
+
+ (gdb) run
+ The program being debugged has been started already.
+ Start it from the beginning? (y or n)
+
+ If you are willing to unflinchingly face the consequences of your own
+commands, you can disable this "feature":
+
+`set confirm off'
+ Disables confirmation requests.
+
+`set confirm on'
+ Enables confirmation requests (the default).
+
+`show confirm'
+ Displays state of confirmation requests.
+
+ Some systems allow individual object files that make up your program
+to be replaced without stopping and restarting your program. For
+example, in VxWorks you can simply recompile a defective object file
+and keep on running. If you are running on one of these systems, you
+can allow GDB to reload the symbols for automatically relinked modules:
+
+`set symbol-reloading on'
+ Replace symbol definitions for the corresponding source file when
+ an object file with a particular name is seen again.
+
+`set symbol-reloading off'
+ Do not replace symbol definitions when re-encountering object
+ files of the same name. This is the default state; if you are not
+ running on a system that permits automatically relinking modules,
+ you should leave `symbol-reloading' off, since otherwise GDB may
+ discard symbols when linking large programs, that may contain
+ several modules (from different directories or libraries) with the
+ same name.
+
+`show symbol-reloading'
+ Show the current `on' or `off' setting.
+
+
+File: gdb.info, Node: Sequences, Next: Emacs, Prev: Controlling GDB, Up: Top
+
+Canned Sequences of Commands
+****************************
+
+ Aside from breakpoint commands (*note Breakpoint command lists:
+Break Commands.), GDB provides two ways to store sequences of commands
+for execution as a unit: user-defined commands and command files.
+
+* Menu:
+
+* Define:: User-defined commands
+* Hooks:: User-defined command hooks
+* Command Files:: Command files
+* Output:: Commands for controlled output
+
+
+File: gdb.info, Node: Define, Next: Hooks, Up: Sequences
+
+User-defined commands
+=====================
+
+ A "user-defined command" is a sequence of GDB commands to which you
+assign a new name as a command. This is done with the `define' command.
+
+`define COMMANDNAME'
+ Define a command named COMMANDNAME. If there is already a command
+ by that name, you are asked to confirm that you want to redefine
+ it.
+
+ The definition of the command is made up of other GDB command
+ lines, which are given following the `define' command. The end of
+ these commands is marked by a line containing `end'.
+
+`document COMMANDNAME'
+ Give documentation to the user-defined command COMMANDNAME. The
+ command COMMANDNAME must already be defined. This command reads
+ lines of documentation just as `define' reads the lines of the
+ command definition, ending with `end'. After the `document'
+ command is finished, `help' on command COMMANDNAME will print the
+ documentation you have specified.
+
+ You may use the `document' command again to change the
+ documentation of a command. Redefining the command with `define'
+ does not change the documentation.
+
+`help user-defined'
+ List all user-defined commands, with the first line of the
+ documentation (if any) for each.
+
+`show user'
+`show user COMMANDNAME'
+ Display the GDB commands used to define COMMANDNAME (but not its
+ documentation). If no COMMANDNAME is given, display the
+ definitions for all user-defined commands.
+
+ User-defined commands do not take arguments. When they are
+executed, the commands of the definition are not printed. An error in
+any command stops execution of the user-defined command.
+
+ Commands that would ask for confirmation if used interactively
+proceed without asking when used inside a user-defined command. Many
+GDB commands that normally print messages to say what they are doing
+omit the messages when used in a user-defined command.
+
+
+File: gdb.info, Node: Hooks, Next: Command Files, Prev: Define, Up: Sequences
+
+User-defined command hooks
+==========================
+
+ You may define *hooks*, which are a special kind of user-defined
+command. Whenever you run the command `foo', if the user-defined
+command `hook-foo' exists, it is executed (with no arguments) before
+that command.
+
+ In addition, a pseudo-command, `stop' exists. Defining
+(`hook-stop') makes the associated commands execute every time
+execution stops in your program: before breakpoint commands are run,
+displays are printed, or the stack frame is printed.
+
+ For example, to ignore `SIGALRM' signals while single-stepping, but
+treat them normally during normal execution, you could define:
+
+ define hook-stop
+ handle SIGALRM nopass
+ end
+
+ define hook-run
+ handle SIGALRM pass
+ end
+
+ define hook-continue
+ handle SIGLARM pass
+ end
+
+ You can define a hook for any single-word command in GDB, but not
+for command aliases; you should define a hook for the basic command
+name, e.g. `backtrace' rather than `bt'. If an error occurs during
+the execution of your hook, execution of GDB commands stops and GDB
+issues a prompt (before the command that you actually typed had a
+chance to run).
+
+ If you try to define a hook which does not match any known command,
+you will get a warning from the `define' command.
+
+
+File: gdb.info, Node: Command Files, Next: Output, Prev: Hooks, Up: Sequences
+
+Command files
+=============
+
+ A command file for GDB is a file of lines that are GDB commands.
+Comments (lines starting with `#') may also be included. An empty line
+in a command file does nothing; it does not mean to repeat the last
+command, as it would from the terminal.
+
+ When you start GDB, it automatically executes commands from its
+"init files". These are files named `.gdbinit'. GDB reads the init
+file (if any) in your home directory and then the init file (if any) in
+the current working directory. (The init files are not executed if you
+use the `-nx' option; *note Choosing modes: Mode Options..)
+
+ On some configurations of GDB, the init file is known by a different
+name (these are typically environments where a specialized form of GDB
+may need to coexist with other forms, hence a different name for the
+specialized version's init file). These are the environments with
+special init file names:
+
+ * VxWorks (Wind River Systems real-time OS): `.vxgdbinit'
+
+ * OS68K (Enea Data Systems real-time OS): `.os68gdbinit'
+
+ * ES-1800 (Ericsson Telecom AB M68000 emulator): `.esgdbinit'
+
+ You can also request the execution of a command file with the
+`source' command:
+
+`source FILENAME'
+ Execute the command file FILENAME.
+
+ The lines in a command file are executed sequentially. They are not
+printed as they are executed. An error in any command terminates
+execution of the command file.
+
+ Commands that would ask for confirmation if used interactively
+proceed without asking when used in a command file. Many GDB commands
+that normally print messages to say what they are doing omit the
+messages when called from command files.
+
+
+File: gdb.info, Node: Output, Prev: Command Files, Up: Sequences
+
+Commands for controlled output
+==============================
+
+ During the execution of a command file or a user-defined command,
+normal GDB output is suppressed; the only output that appears is what is
+explicitly printed by the commands in the definition. This section
+describes three commands useful for generating exactly the output you
+want.
+
+`echo TEXT'
+ Print TEXT. Nonprinting characters can be included in TEXT using
+ C escape sequences, such as `\n' to print a newline. *No newline
+ will be printed unless you specify one.* In addition to the
+ standard C escape sequences, a backslash followed by a space
+ stands for a space. This is useful for displaying a string with
+ spaces at the beginning or the end, since leading and trailing
+ spaces are otherwise trimmed from all arguments. To print ` and
+ foo = ', use the command `echo \ and foo = \ '.
+
+ A backslash at the end of TEXT can be used, as in C, to continue
+ the command onto subsequent lines. For example,
+
+ echo This is some text\n\
+ which is continued\n\
+ onto several lines.\n
+
+ produces the same output as
+
+ echo This is some text\n
+ echo which is continued\n
+ echo onto several lines.\n
+
+`output EXPRESSION'
+ Print the value of EXPRESSION and nothing but that value: no
+ newlines, no `$NN = '. The value is not entered in the value
+ history either. *Note Expressions: Expressions, for more
+ information on expressions.
+
+`output/FMT EXPRESSION'
+ Print the value of EXPRESSION in format FMT. You can use the same
+ formats as for `print'. *Note Output formats: Output Formats, for
+ more information.
+
+`printf STRING, EXPRESSIONS...'
+ Print the values of the EXPRESSIONS under the control of STRING.
+ The EXPRESSIONS are separated by commas and may be either numbers
+ or pointers. Their values are printed as specified by STRING,
+ exactly as if your program were to execute the C subroutine
+
+ printf (STRING, EXPRESSIONS...);
+
+ For example, you can print two values in hex like this:
+
+ printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+
+ The only backslash-escape sequences that you can use in the format
+ string are the simple ones that consist of backslash followed by a
+ letter.
+
+
+File: gdb.info, Node: Emacs, Next: GDB Bugs, Prev: Sequences, Up: Top
+
+Using GDB under GNU Emacs
+*************************
+
+ A special interface allows you to use GNU Emacs to view (and edit)
+the source files for the program you are debugging with GDB.
+
+ To use this interface, use the command `M-x gdb' in Emacs. Give the
+executable file you want to debug as an argument. This command starts
+GDB as a subprocess of Emacs, with input and output through a newly
+created Emacs buffer.
+
+ Using GDB under Emacs is just like using GDB normally except for two
+things:
+
+ * All "terminal" input and output goes through the Emacs buffer.
+
+ This applies both to GDB commands and their output, and to the input
+and output done by the program you are debugging.
+
+ This is useful because it means that you can copy the text of
+previous commands and input them again; you can even use parts of the
+output in this way.
+
+ All the facilities of Emacs' Shell mode are available for interacting
+with your program. In particular, you can send signals the usual
+way--for example, `C-c C-c' for an interrupt, `C-c C-z' for a stop.
+
+ * GDB displays source code through Emacs.
+
+ Each time GDB displays a stack frame, Emacs automatically finds the
+source file for that frame and puts an arrow (`=>') at the left margin
+of the current line. Emacs uses a separate buffer for source display,
+and splits the screen to show both your GDB session and the source.
+
+ Explicit GDB `list' or search commands still produce output as
+usual, but you probably will have no reason to use them.
+
+ *Warning:* If the directory where your program resides is not your
+ current directory, it can be easy to confuse Emacs about the
+ location of the source files, in which case the auxiliary display
+ buffer will not appear to show your source. GDB can find programs
+ by searching your environment's `PATH' variable, so the GDB input
+ and output session will proceed normally; but Emacs does not get
+ enough information back from GDB to locate the source files in
+ this situation. To avoid this problem, either start GDB mode from
+ the directory where your program resides, or specify a full path
+ name when prompted for the `M-x gdb' argument.
+
+ A similar confusion can result if you use the GDB `file' command to
+ switch to debugging a program in some other location, from an
+ existing GDB buffer in Emacs.
+
+ By default, `M-x gdb' calls the program called `gdb'. If you need
+to call GDB by a different name (for example, if you keep several
+configurations around, with different names) you can set the Emacs
+variable `gdb-command-name'; for example,
+
+ (setq gdb-command-name "mygdb")
+
+(preceded by `ESC ESC', or typed in the `*scratch*' buffer, or in your
+`.emacs' file) will make Emacs call the program named "`mygdb'" instead.
+
+ In the GDB I/O buffer, you can use these special Emacs commands in
+addition to the standard Shell mode commands:
+
+`C-h m'
+ Describe the features of Emacs' GDB Mode.
+
+`M-s'
+ Execute to another source line, like the GDB `step' command; also
+ update the display window to show the current file and location.
+
+`M-n'
+ Execute to next source line in this function, skipping all function
+ calls, like the GDB `next' command. Then update the display window
+ to show the current file and location.
+
+`M-i'
+ Execute one instruction, like the GDB `stepi' command; update
+ display window accordingly.
+
+`M-x gdb-nexti'
+ Execute to next instruction, using the GDB `nexti' command; update
+ display window accordingly.
+
+`C-c C-f'
+ Execute until exit from the selected stack frame, like the GDB
+ `finish' command.
+
+`M-c'
+ Continue execution of your program, like the GDB `continue'
+ command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-p'.
+
+`M-u'
+ Go up the number of frames indicated by the numeric argument
+ (*note Numeric Arguments: (emacs)Arguments.), like the GDB `up'
+ command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-u'.
+
+`M-d'
+ Go down the number of frames indicated by the numeric argument,
+ like the GDB `down' command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-d'.
+
+`C-x &'
+ Read the number where the cursor is positioned, and insert it at
+ the end of the GDB I/O buffer. For example, if you wish to
+ disassemble code around an address that was displayed earlier,
+ type `disassemble'; then move the cursor to the address display,
+ and pick up the argument for `disassemble' by typing `C-x &'.
+
+ You can customize this further by defining elements of the list
+ `gdb-print-command'; once it is defined, you can format or
+ otherwise process numbers picked up by `C-x &' before they are
+ inserted. A numeric argument to `C-x &' will both indicate that
+ you wish special formatting, and act as an index to pick an
+ element of the list. If the list element is a string, the number
+ to be inserted is formatted using the Emacs function `format';
+ otherwise the number is passed as an argument to the corresponding
+ list element.
+
+ In any source file, the Emacs command `C-x SPC' (`gdb-break') tells
+GDB to set a breakpoint on the source line point is on.
+
+ If you accidentally delete the source-display buffer, an easy way to
+get it back is to type the command `f' in the GDB buffer, to request a
+frame display; when you run under Emacs, this will recreate the source
+buffer if necessary to show you the context of the current frame.
+
+ The source files displayed in Emacs are in ordinary Emacs buffers
+which are visiting the source files in the usual way. You can edit the
+files with these buffers if you wish; but keep in mind that GDB
+communicates with Emacs in terms of line numbers. If you add or delete
+lines from the text, the line numbers that GDB knows will cease to
+correspond properly with the code.
+
+
+File: gdb.info, Node: GDB Bugs, Next: Command Line Editing, Prev: Emacs, Up: Top
+
+Reporting Bugs in GDB
+*********************
+
+ Your bug reports play an essential role in making GDB reliable.
+
+ Reporting a bug may help you by bringing a solution to your problem,
+or it may not. But in any case the principal function of a bug report
+is to help the entire community by making the next version of GDB work
+better. Bug reports are your contribution to the maintenance of GDB.
+
+ In order for a bug report to serve its purpose, you must include the
+information that enables us to fix the bug.
+
+* Menu:
+
+* Bug Criteria:: Have you found a bug?
+* Bug Reporting:: How to report bugs
+
+
+File: gdb.info, Node: Bug Criteria, Next: Bug Reporting, Up: GDB Bugs
+
+Have you found a bug?
+=====================
+
+ If you are not sure whether you have found a bug, here are some
+guidelines:
+
+ * If the debugger gets a fatal signal, for any input whatever, that
+ is a GDB bug. Reliable debuggers never crash.
+
+ * If GDB produces an error message for valid input, that is a bug.
+
+ * If GDB does not produce an error message for invalid input, that
+ is a bug. However, you should note that your idea of "invalid
+ input" might be our idea of "an extension" or "support for
+ traditional practice".
+
+ * If you are an experienced user of debugging tools, your suggestions
+ for improvement of GDB are welcome in any case.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-7 b/gnu/usr.bin/gdb/doc/gdb.info-7
new file mode 100644
index 000000000000..963527ef774a
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-7
@@ -0,0 +1,1233 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Bug Reporting, Prev: Bug Criteria, Up: GDB Bugs
+
+How to report bugs
+==================
+
+ A number of companies and individuals offer support for GNU products.
+If you obtained GDB from a support organization, we recommend you
+contact that organization first.
+
+ You can find contact information for many support companies and
+individuals in the file `etc/SERVICE' in the GNU Emacs distribution.
+
+ In any event, we also recommend that you send bug reports for GDB to
+one of these addresses:
+
+ bug-gdb@prep.ai.mit.edu
+ {ucbvax|mit-eddie|uunet}!prep.ai.mit.edu!bug-gdb
+
+ *Do not send bug reports to `info-gdb', or to `help-gdb', or to any
+newsgroups.* Most users of GDB do not want to receive bug reports.
+Those that do, have arranged to receive `bug-gdb'.
+
+ The mailing list `bug-gdb' has a newsgroup `gnu.gdb.bug' which
+serves as a repeater. The mailing list and the newsgroup carry exactly
+the same messages. Often people think of posting bug reports to the
+newsgroup instead of mailing them. This appears to work, but it has one
+problem which can be crucial: a newsgroup posting often lacks a mail
+path back to the sender. Thus, if we need to ask for more information,
+we may be unable to reach you. For this reason, it is better to send
+bug reports to the mailing list.
+
+ As a last resort, send bug reports on paper to:
+
+ GNU Debugger Bugs
+ Free Software Foundation
+ 545 Tech Square
+ Cambridge, MA 02139
+
+ The fundamental principle of reporting bugs usefully is this:
+*report all the facts*. If you are not sure whether to state a fact or
+leave it out, state it!
+
+ Often people omit facts because they think they know what causes the
+problem and assume that some details do not matter. Thus, you might
+assume that the name of the variable you use in an example does not
+matter. Well, probably it does not, but one cannot be sure. Perhaps
+the bug is a stray memory reference which happens to fetch from the
+location where that name is stored in memory; perhaps, if the name were
+different, the contents of that location would fool the debugger into
+doing the right thing despite the bug. Play it safe and give a
+specific, complete example. That is the easiest thing for you to do,
+and the most helpful.
+
+ Keep in mind that the purpose of a bug report is to enable us to fix
+the bug if it is new to us. It is not as important as what happens if
+the bug is already known. Therefore, always write your bug reports on
+the assumption that the bug has not been reported previously.
+
+ Sometimes people give a few sketchy facts and ask, "Does this ring a
+bell?" Those bug reports are useless, and we urge everyone to *refuse
+to respond to them* except to chide the sender to report bugs properly.
+
+ To enable us to fix the bug, you should include all these things:
+
+ * The version of GDB. GDB announces it if you start with no
+ arguments; you can also print it at any time using `show version'.
+
+ Without this, we will not know whether there is any point in
+ looking for the bug in the current version of GDB.
+
+ * The type of machine you are using, and the operating system name
+ and version number.
+
+ * What compiler (and its version) was used to compile GDB--e.g.
+ "gcc-2.0".
+
+ * What compiler (and its version) was used to compile the program you
+ are debugging--e.g. "gcc-2.0".
+
+ * The command arguments you gave the compiler to compile your
+ example and observe the bug. For example, did you use `-O'? To
+ guarantee you will not omit something important, list them all. A
+ copy of the Makefile (or the output from make) is sufficient.
+
+ If we were to try to guess the arguments, we would probably guess
+ wrong and then we might not encounter the bug.
+
+ * A complete input script, and all necessary source files, that will
+ reproduce the bug.
+
+ * A description of what behavior you observe that you believe is
+ incorrect. For example, "It gets a fatal signal."
+
+ Of course, if the bug is that GDB gets a fatal signal, then we will
+ certainly notice it. But if the bug is incorrect output, we might
+ not notice unless it is glaringly wrong. We are human, after all.
+ You might as well not give us a chance to make a mistake.
+
+ Even if the problem you experience is a fatal signal, you should
+ still say so explicitly. Suppose something strange is going on,
+ such as, your copy of GDB is out of synch, or you have encountered
+ a bug in the C library on your system. (This has happened!) Your
+ copy might crash and ours would not. If you told us to expect a
+ crash, then when ours fails to crash, we would know that the bug
+ was not happening for us. If you had not told us to expect a
+ crash, then we would not be able to draw any conclusion from our
+ observations.
+
+ * If you wish to suggest changes to the GDB source, send us context
+ diffs. If you even discuss something in the GDB source, refer to
+ it by context, not by line number.
+
+ The line numbers in our development sources will not match those
+ in your sources. Your line numbers would convey no useful
+ information to us.
+
+ Here are some things that are not necessary:
+
+ * A description of the envelope of the bug.
+
+ Often people who encounter a bug spend a lot of time investigating
+ which changes to the input file will make the bug go away and which
+ changes will not affect it.
+
+ This is often time consuming and not very useful, because the way
+ we will find the bug is by running a single example under the
+ debugger with breakpoints, not by pure deduction from a series of
+ examples. We recommend that you save your time for something else.
+
+ Of course, if you can find a simpler example to report *instead*
+ of the original one, that is a convenience for us. Errors in the
+ output will be easier to spot, running under the debugger will take
+ less time, etc.
+
+ However, simplification is not vital; if you do not want to do
+ this, report the bug anyway and send us the entire test case you
+ used.
+
+ * A patch for the bug.
+
+ A patch for the bug does help us if it is a good one. But do not
+ omit the necessary information, such as the test case, on the
+ assumption that a patch is all we need. We might see problems
+ with your patch and decide to fix the problem another way, or we
+ might not understand it at all.
+
+ Sometimes with a program as complicated as GDB it is very hard to
+ construct an example that will make the program follow a certain
+ path through the code. If you do not send us the example, we will
+ not be able to construct one, so we will not be able to verify
+ that the bug is fixed.
+
+ And if we cannot understand what bug you are trying to fix, or why
+ your patch should be an improvement, we will not install it. A
+ test case will help us to understand.
+
+ * A guess about what the bug is or what it depends on.
+
+ Such guesses are usually wrong. Even we cannot guess right about
+ such things without first using the debugger to find the facts.
+
+
+File: gdb.info, Node: Command Line Editing, Next: Using History Interactively, Prev: GDB Bugs, Up: Top
+
+Command Line Editing
+********************
+
+ This text describes GNU's command line editing interface.
+
+* Menu:
+
+* Introduction and Notation:: Notation used in this text.
+* Readline Interaction:: The minimum set of commands for editing a line.
+* Readline Init File:: Customizing Readline from a user's view.
+
+
+File: gdb.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing
+
+Introduction to Line Editing
+============================
+
+ The following paragraphs describe the notation we use to represent
+keystrokes.
+
+ The text C-k is read as `Control-K' and describes the character
+produced when the Control key is depressed and the k key is struck.
+
+ The text M-k is read as `Meta-K' and describes the character
+produced when the meta key (if you have one) is depressed, and the k
+key is struck. If you do not have a meta key, the identical keystroke
+can be generated by typing ESC first, and then typing k. Either
+process is known as "metafying" the k key.
+
+ The text M-C-k is read as `Meta-Control-k' and describes the
+character produced by "metafying" C-k.
+
+ In addition, several keys have their own names. Specifically, DEL,
+ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this
+text, or in an init file (*note Readline Init File::., for more info).
+
+
+File: gdb.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing
+
+Readline Interaction
+====================
+
+ Often during an interactive session you type in a long line of text,
+only to notice that the first word on the line is misspelled. The
+Readline library gives you a set of commands for manipulating the text
+as you type it in, allowing you to just fix your typo, and not forcing
+you to retype the majority of the line. Using these editing commands,
+you move the cursor to the place that needs correction, and delete or
+insert the text of the corrections. Then, when you are satisfied with
+the line, you simply press RETURN. You do not have to be at the end of
+the line to press RETURN; the entire line is accepted regardless of the
+location of the cursor within the line.
+
+* Menu:
+
+* Readline Bare Essentials:: The least you need to know about Readline.
+* Readline Movement Commands:: Moving about the input line.
+* Readline Killing Commands:: How to delete text, and how to get it back!
+* Readline Arguments:: Giving numeric arguments to commands.
+
+
+File: gdb.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction
+
+Readline Bare Essentials
+------------------------
+
+ In order to enter characters into the line, simply type them. The
+typed character appears where the cursor was, and then the cursor moves
+one space to the right. If you mistype a character, you can use DEL to
+back up, and delete the mistyped character.
+
+ Sometimes you may miss typing a character that you wanted to type,
+and not notice your error until you have typed several other
+characters. In that case, you can type C-b to move the cursor to the
+left, and then correct your mistake. Aftwerwards, you can move the
+cursor to the right with C-f.
+
+ When you add text in the middle of a line, you will notice that
+characters to the right of the cursor get `pushed over' to make room
+for the text that you have inserted. Likewise, when you delete text
+behind the cursor, characters to the right of the cursor get `pulled
+back' to fill in the blank space created by the removal of the text. A
+list of the basic bare essentials for editing the text of an input line
+follows.
+
+C-b
+ Move back one character.
+
+C-f
+ Move forward one character.
+
+DEL
+ Delete the character to the left of the cursor.
+
+C-d
+ Delete the character underneath the cursor.
+
+Printing characters
+ Insert itself into the line at the cursor.
+
+C-_
+ Undo the last thing that you did. You can undo all the way back
+ to an empty line.
+
+
+File: gdb.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction
+
+Readline Movement Commands
+--------------------------
+
+ The above table describes the most basic possible keystrokes that
+you need in order to do editing of the input line. For your
+convenience, many other commands have been added in addition to C-b,
+C-f, C-d, and DEL. Here are some commands for moving more rapidly
+about the line.
+
+C-a
+ Move to the start of the line.
+
+C-e
+ Move to the end of the line.
+
+M-f
+ Move forward a word.
+
+M-b
+ Move backward a word.
+
+C-l
+ Clear the screen, reprinting the current line at the top.
+
+ Notice how C-f moves forward a character, while M-f moves forward a
+word. It is a loose convention that control keystrokes operate on
+characters while meta keystrokes operate on words.
+
+
+File: gdb.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction
+
+Readline Killing Commands
+-------------------------
+
+ "Killing" text means to delete the text from the line, but to save
+it away for later use, usually by "yanking" it back into the line. If
+the description for a command says that it `kills' text, then you can
+be sure that you can get the text back in a different (or the same)
+place later.
+
+ Here is the list of commands for killing text.
+
+C-k
+ Kill the text from the current cursor position to the end of the
+ line.
+
+M-d
+ Kill from the cursor to the end of the current word, or if between
+ words, to the end of the next word.
+
+M-DEL
+ Kill from the cursor to the start of the previous word, or if
+ between words, to the start of the previous word.
+
+C-w
+ Kill from the cursor to the previous whitespace. This is
+ different than M-DEL because the word boundaries differ.
+
+ And, here is how to "yank" the text back into the line. Yanking is
+
+C-y
+ Yank the most recently killed text back into the buffer at the
+ cursor.
+
+M-y
+ Rotate the kill-ring, and yank the new top. You can only do this
+ if the prior command is C-y or M-y.
+
+ When you use a kill command, the text is saved in a "kill-ring".
+Any number of consecutive kills save all of the killed text together, so
+that when you yank it back, you get it in one clean sweep. The kill
+ring is not line specific; the text that you killed on a previously
+typed line is available to be yanked back later, when you are typing
+another line.
+
+
+File: gdb.info, Node: Readline Arguments, Prev: Readline Killing Commands, Up: Readline Interaction
+
+Readline Arguments
+------------------
+
+ You can pass numeric arguments to Readline commands. Sometimes the
+argument acts as a repeat count, other times it is the sign of the
+argument that is significant. If you pass a negative argument to a
+command which normally acts in a forward direction, that command will
+act in a backward direction. For example, to kill text back to the
+start of the line, you might type M- C-k.
+
+ The general way to pass numeric arguments to a command is to type
+meta digits before the command. If the first `digit' you type is a
+minus sign (-), then the sign of the argument will be negative. Once
+you have typed one meta digit to get the argument started, you can type
+the remainder of the digits, and then the command. For example, to give
+the C-d command an argument of 10, you could type M-1 0 C-d.
+
+
+File: gdb.info, Node: Readline Init File, Prev: Readline Interaction, Up: Command Line Editing
+
+Readline Init File
+==================
+
+ Although the Readline library comes with a set of Emacs-like
+keybindings, it is possible that you would like to use a different set
+of keybindings. You can customize programs that use Readline by putting
+commands in an "init" file in your home directory. The name of this
+file is `~/.inputrc'.
+
+ When a program which uses the Readline library starts up, the
+`~/.inputrc' file is read, and the keybindings are set.
+
+ In addition, the C-x C-r command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+* Menu:
+
+* Readline Init Syntax:: Syntax for the commands in `~/.inputrc'.
+* Readline Vi Mode:: Switching to `vi' mode in Readline.
+
+
+File: gdb.info, Node: Readline Init Syntax, Next: Readline Vi Mode, Up: Readline Init File
+
+Readline Init Syntax
+--------------------
+
+ There are only four constructs allowed in the `~/.inputrc' file:
+
+Variable Settings
+ You can change the state of a few variables in Readline. You do
+ this by using the `set' command within the init file. Here is how
+ you would specify that you wish to use Vi line editing commands:
+
+ set editing-mode vi
+
+ Right now, there are only a few variables which can be set; so few
+ in fact, that we just iterate them here:
+
+ `editing-mode'
+ The `editing-mode' variable controls which editing mode you
+ are using. By default, GNU Readline starts up in Emacs
+ editing mode, where the keystrokes are most similar to Emacs.
+ This variable can either be set to `emacs' or `vi'.
+
+ `horizontal-scroll-mode'
+ This variable can either be set to `On' or `Off'. Setting it
+ to `On' means that the text of the lines that you edit will
+ scroll horizontally on a single screen line when they are
+ larger than the width of the screen, instead of wrapping onto
+ a new screen line. By default, this variable is set to `Off'.
+
+ `mark-modified-lines'
+ This variable when set to `On', says to display an asterisk
+ (`*') at the starts of history lines which have been modified.
+ This variable is off by default.
+
+ `prefer-visible-bell'
+ If this variable is set to `On' it means to use a visible
+ bell if one is available, rather than simply ringing the
+ terminal bell. By default, the value is `Off'.
+
+Key Bindings
+ The syntax for controlling keybindings in the `~/.inputrc' file is
+ simple. First you have to know the name of the command that you
+ want to change. The following pages contain tables of the command
+ name, the default keybinding, and a short description of what the
+ command does.
+
+ Once you know the name of the command, simply place the name of
+ the key you wish to bind the command to, a colon, and then the
+ name of the command on a line in the `~/.inputrc' file. The name
+ of the key can be expressed in different ways, depending on which
+ is most comfortable for you.
+
+ KEYNAME: FUNCTION-NAME or MACRO
+ KEYNAME is the name of a key spelled out in English. For
+ example:
+ Control-u: universal-argument
+ Meta-Rubout: backward-kill-word
+ Control-o: ">&output"
+
+ In the above example, C-u is bound to the function
+ `universal-argument', and C-o is bound to run the macro
+ expressed on the right hand side (that is, to insert the text
+ `>&output' into the line).
+
+ "KEYSEQ": FUNCTION-NAME or MACRO
+ KEYSEQ differs from KEYNAME above in that strings denoting an
+ entire key sequence can be specified. Simply place the key
+ sequence in double quotes. GNU Emacs style key escapes can
+ be used, as in the following example:
+
+ "\C-u": universal-argument
+ "\C-x\C-r": re-read-init-file
+ "\e[11~": "Function Key 1"
+
+ In the above example, C-u is bound to the function
+ `universal-argument' (just as it was in the first example),
+ C-x C-r is bound to the function `re-read-init-file', and ESC
+ [ 1 1 ~ is bound to insert the text `Function Key 1'.
+
+* Menu:
+
+* Commands For Moving:: Moving about the line.
+* Commands For History:: Getting at previous lines.
+* Commands For Text:: Commands for changing text.
+* Commands For Killing:: Commands for killing and yanking.
+* Numeric Arguments:: Specifying numeric arguments, repeat counts.
+* Commands For Completion:: Getting Readline to do the typing for you.
+* Miscellaneous Commands:: Other miscillaneous commands.
+
+
+File: gdb.info, Node: Commands For Moving, Next: Commands For History, Up: Readline Init Syntax
+
+Commands For Moving
+-------------------
+
+`beginning-of-line (C-a)'
+ Move to the start of the current line.
+
+`end-of-line (C-e)'
+ Move to the end of the line.
+
+`forward-char (C-f)'
+ Move forward a character.
+
+`backward-char (C-b)'
+ Move back a character.
+
+`forward-word (M-f)'
+ Move forward to the end of the next word.
+
+`backward-word (M-b)'
+ Move back to the start of this, or the previous, word.
+
+`clear-screen (C-l)'
+ Clear the screen leaving the current line at the top of the screen.
+
+
+File: gdb.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Readline Init Syntax
+
+Commands For Manipulating The History
+-------------------------------------
+
+`accept-line (Newline, Return)'
+ Accept the line regardless of where the cursor is. If this line is
+ non-empty, add it to the history list. If this line was a history
+ line, then restore the history line to its original state.
+
+`previous-history (C-p)'
+ Move `up' through the history list.
+
+`next-history (C-n)'
+ Move `down' through the history list.
+
+`beginning-of-history (M-<)'
+ Move to the first line in the history.
+
+`end-of-history (M->)'
+ Move to the end of the input history, i.e., the line you are
+ entering!
+
+`reverse-search-history (C-r)'
+ Search backward starting at the current line and moving `up'
+ through the history as necessary. This is an incremental search.
+
+`forward-search-history (C-s)'
+ Search forward starting at the current line and moving `down'
+ through the the history as neccessary.
+
+
+File: gdb.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Readline Init Syntax
+
+Commands For Changing Text
+--------------------------
+
+`delete-char (C-d)'
+ Delete the character under the cursor. If the cursor is at the
+ beginning of the line, and there are no characters in the line, and
+ the last character typed was not C-d, then return EOF.
+
+`backward-delete-char (Rubout)'
+ Delete the character behind the cursor. A numeric arg says to kill
+ the characters instead of deleting them.
+
+`quoted-insert (C-q, C-v)'
+ Add the next character that you type to the line verbatim. This is
+ how to insert things like C-q for example.
+
+`tab-insert (M-TAB)'
+ Insert a tab character.
+
+`self-insert (a, b, A, 1, !, ...)'
+ Insert yourself.
+
+`transpose-chars (C-t)'
+ Drag the character before point forward over the character at
+ point. Point moves forward as well. If point is at the end of
+ the line, then transpose the two characters before point.
+ Negative args don't work.
+
+`transpose-words (M-t)'
+ Drag the word behind the cursor past the word in front of the
+ cursor moving the cursor over that word as well.
+
+`upcase-word (M-u)'
+ Uppercase all letters in the current (or following) word. With a
+ negative argument, do the previous word, but do not move point.
+
+`downcase-word (M-l)'
+ Lowercase all letters in the current (or following) word. With a
+ negative argument, do the previous word, but do not move point.
+
+`capitalize-word (M-c)'
+ Uppercase the first letter in the current (or following) word.
+ With a negative argument, do the previous word, but do not move
+ point.
+
+
+File: gdb.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Readline Init Syntax
+
+Killing And Yanking
+-------------------
+
+`kill-line (C-k)'
+ Kill the text from the current cursor position to the end of the
+ line.
+
+`backward-kill-line ()'
+ Kill backward to the beginning of the line. This is normally
+ unbound.
+
+`kill-word (M-d)'
+ Kill from the cursor to the end of the current word, or if between
+ words, to the end of the next word.
+
+`backward-kill-word (M-DEL)'
+ Kill the word behind the cursor.
+
+`unix-line-discard (C-u)'
+ Do what C-u used to do in Unix line input. We save the killed
+ text on the kill-ring, though.
+
+`unix-word-rubout (C-w)'
+ Do what C-w used to do in Unix line input. The killed text is
+ saved on the kill-ring. This is different than backward-kill-word
+ because the word boundaries differ.
+
+`yank (C-y)'
+ Yank the top of the kill ring into the buffer at point.
+
+`yank-pop (M-y)'
+ Rotate the kill-ring, and yank the new top. You can only do this
+ if the prior command is yank or yank-pop.
+
+
+File: gdb.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Readline Init Syntax
+
+Specifying Numeric Arguments
+----------------------------
+
+`digit-argument (M-0, M-1, ... M--)'
+ Add this digit to the argument already accumulating, or start a new
+ argument. M- starts a negative argument.
+
+`universal-argument ()'
+ Do what C-u does in emacs. By default, this is not bound.
+
+
+File: gdb.info, Node: Commands For Completion, Next: Miscellaneous Commands, Prev: Numeric Arguments, Up: Readline Init Syntax
+
+Letting Readline Type For You
+-----------------------------
+
+`complete (TAB)'
+ Attempt to do completion on the text before point. This is
+ implementation defined. Generally, if you are typing a filename
+ argument, you can do filename completion; if you are typing a
+ command, you can do command completion, if you are typing in a
+ symbol to GDB, you can do symbol name completion, if you are
+ typing in a variable to Bash, you can do variable name
+ completion...
+
+`possible-completions (M-?)'
+ List the possible completions of the text before point.
+
+
+File: gdb.info, Node: Miscellaneous Commands, Prev: Commands For Completion, Up: Readline Init Syntax
+
+Some Miscellaneous Commands
+---------------------------
+
+`re-read-init-file (C-x C-r)'
+ Read in the contents of your `~/.inputrc' file, and incorporate
+ any bindings found there.
+
+`abort (C-g)'
+ Stop running the current editing command.
+
+`prefix-meta (ESC)'
+ Make the next character that you type be metafied. This is for
+ people without a meta key. Typing ESC f is equivalent to typing
+ M-f.
+
+`undo (C-_)'
+ Incremental undo, separately remembered for each line.
+
+`revert-line (M-r)'
+ Undo all changes made to this line. This is like typing the `undo'
+ command enough times to get back to the beginning.
+
+
+File: gdb.info, Node: Readline Vi Mode, Prev: Readline Init Syntax, Up: Readline Init File
+
+Readline Vi Mode
+----------------
+
+ While the Readline library does not have a full set of Vi editing
+functions, it does contain enough to allow simple editing of the line.
+
+ In order to switch interactively between Emacs and Vi editing modes,
+use the command M-C-j (toggle-editing-mode).
+
+ When you enter a line in Vi mode, you are already placed in
+`insertion' mode, as if you had typed an `i'. Pressing ESC switches
+you into `edit' mode, where you can edit the text of the line with the
+standard Vi movement keys, move to previous history lines with `k', and
+following lines with `j', and so forth.
+
+
+File: gdb.info, Node: Using History Interactively, Next: Renamed Commands, Prev: Command Line Editing, Up: Top
+
+Using History Interactively
+***************************
+
+ This chapter describes how to use the GNU History Library
+interactively, from a user's standpoint.
+
+* Menu:
+
+* History Interaction:: What it feels like using History as a user.
+
+
+File: gdb.info, Node: History Interaction, Up: Using History Interactively
+
+History Interaction
+===================
+
+ The History library provides a history expansion feature that is
+similar to the history expansion in Csh. The following text describes
+the sytax that you use to manipulate the history information.
+
+ History expansion takes place in two parts. The first is to
+determine which line from the previous history should be used during
+substitution. The second is to select portions of that line for
+inclusion into the current one. The line selected from the previous
+history is called the "event", and the portions of that line that are
+acted upon are called "words". The line is broken into words in the
+same fashion that the Bash shell does, so that several English (or
+Unix) words surrounded by quotes are considered as one word.
+
+* Menu:
+
+* Event Designators:: How to specify which history line to use.
+* Word Designators:: Specifying which words are of interest.
+* Modifiers:: Modifying the results of susbstitution.
+
+
+File: gdb.info, Node: Event Designators, Next: Word Designators, Up: History Interaction
+
+Event Designators
+-----------------
+
+ An event designator is a reference to a command line entry in the
+history list.
+
+`!'
+ Start a history subsititution, except when followed by a space,
+ tab, or the end of the line... = or (.
+
+`!!'
+ Refer to the previous command. This is a synonym for `!-1'.
+
+`!n'
+ Refer to command line N.
+
+`!-n'
+ Refer to the command line N lines back.
+
+`!string'
+ Refer to the most recent command starting with STRING.
+
+`!?string'[`?']
+ Refer to the most recent command containing STRING.
+
+
+File: gdb.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction
+
+Word Designators
+----------------
+
+ A : separates the event specification from the word designator. It
+can be omitted if the word designator begins with a ^, $, * or %.
+Words are numbered from the beginning of the line, with the first word
+being denoted by a 0 (zero).
+
+`0 (zero)'
+ The zero'th word. For many applications, this is the command word.
+
+`n'
+ The N'th word.
+
+`^'
+ The first argument. that is, word 1.
+
+`$'
+ The last argument.
+
+`%'
+ The word matched by the most recent `?string?' search.
+
+`x-y'
+ A range of words; `-Y' Abbreviates `0-Y'.
+
+`*'
+ All of the words, excepting the zero'th. This is a synonym for
+ `1-$'. It is not an error to use * if there is just one word in
+ the event. The empty string is returned in that case.
+
+
+File: gdb.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction
+
+Modifiers
+---------
+
+ After the optional word designator, you can add a sequence of one or
+more of the following modifiers, each preceded by a :.
+
+`#'
+ The entire command line typed so far. This means the current
+ command, not the previous command, so it really isn't a word
+ designator, and doesn't belong in this section.
+
+`h'
+ Remove a trailing pathname component, leaving only the head.
+
+`r'
+ Remove a trailing suffix of the form `.'SUFFIX, leaving the
+ basename.
+
+`e'
+ Remove all but the suffix.
+
+`t'
+ Remove all leading pathname components, leaving the tail.
+
+`p'
+ Print the new command but do not execute it.
+
+
+File: gdb.info, Node: Renamed Commands, Next: Formatting Documentation, Prev: Using History Interactively, Up: Top
+
+Renamed Commands
+****************
+
+ The following commands were renamed in GDB 4, in order to make the
+command set as a whole more consistent and easier to use and remember:
+
+ OLD COMMAND NEW COMMAND
+ --------------- -------------------------------
+ add-syms add-symbol-file
+ delete environment unset environment
+ info convenience show convenience
+ info copying show copying
+ info directories show directories
+ info editing show commands
+ info history show values
+ info targets help target
+ info values show values
+ info version show version
+ info warranty show warranty
+ set/show addressprint set/show print address
+ set/show array-max set/show print elements
+ set/show arrayprint set/show print array
+ set/show asm-demangle set/show print asm-demangle
+ set/show caution set/show confirm
+ set/show demangle set/show print demangle
+ set/show history write set/show history save
+ set/show prettyprint set/show print pretty
+ set/show screen-height set/show height
+ set/show screen-width set/show width
+ set/show sevenbit-strings set/show print sevenbit-strings
+ set/show unionprint set/show print union
+ set/show vtblprint set/show print vtbl
+
+ unset [No longer an alias for delete]
+
+
+File: gdb.info, Node: Formatting Documentation, Next: Installing GDB, Prev: Renamed Commands, Up: Top
+
+Formatting Documentation
+************************
+
+ The GDB 4 release includes an already-formatted reference card, ready
+for printing with PostScript or GhostScript, in the `gdb' subdirectory
+of the main source directory(1). If you can use PostScript or
+GhostScript with your printer, you can print the reference card
+immediately with `refcard.ps'.
+
+ The release also includes the source for the reference card. You
+can format it, using TeX, by typing:
+
+ make refcard.dvi
+
+ The GDB reference card is designed to print in landscape mode on US
+"letter" size paper; that is, on a sheet 11 inches wide by 8.5 inches
+high. You will need to specify this form of printing as an option to
+your DVI output program.
+
+ All the documentation for GDB comes as part of the machine-readable
+distribution. The documentation is written in Texinfo format, which is
+a documentation system that uses a single source file to produce both
+on-line information and a printed manual. You can use one of the Info
+formatting commands to create the on-line version of the documentation
+and TeX (or `texi2roff') to typeset the printed version.
+
+ GDB includes an already formatted copy of the on-line Info version of
+this manual in the `gdb' subdirectory. The main Info file is
+`gdb-VERSION-NUMBER/gdb/gdb.info', and it refers to subordinate files
+matching `gdb.info*' in the same directory. If necessary, you can
+print out these files, or read them with any editor; but they are
+easier to read using the `info' subsystem in GNU Emacs or the
+standalone `info' program, available as part of the GNU Texinfo
+distribution.
+
+ If you want to format these Info files yourself, you need one of the
+Info formatting programs, such as `texinfo-format-buffer' or `makeinfo'.
+
+ If you have `makeinfo' installed, and are in the top level GDB
+source directory (`gdb-4.11', in the case of version 4.11), you can
+make the Info file by typing:
+
+ cd gdb
+ make gdb.info
+
+ If you want to typeset and print copies of this manual, you need TeX,
+a program to print its DVI output files, and `texinfo.tex', the Texinfo
+definitions file.
+
+ TeX is a typesetting program; it does not print files directly, but
+produces output files called DVI files. To print a typeset document,
+you need a program to print DVI files. If your system has TeX
+installed, chances are it has such a program. The precise command to
+use depends on your system; `lpr -d' is common; another (for PostScript
+devices) is `dvips'. The DVI print command may require a file name
+without any extension or a `.dvi' extension.
+
+ TeX also requires a macro definitions file called `texinfo.tex'.
+This file tells TeX how to typeset a document written in Texinfo
+format. On its own, TeX cannot read, much less typeset a Texinfo file.
+`texinfo.tex' is distributed with GDB and is located in the
+`gdb-VERSION-NUMBER/texinfo' directory.
+
+ If you have TeX and a DVI printer program installed, you can typeset
+and print this manual. First switch to the the `gdb' subdirectory of
+the main source directory (for example, to `gdb-4.11/gdb') and then
+type:
+
+ make gdb.dvi
+
+ ---------- Footnotes ----------
+
+ (1) In `gdb-4.11/gdb/refcard.ps' of the version 4.11 release.
+
+
+File: gdb.info, Node: Installing GDB, Next: Index, Prev: Formatting Documentation, Up: Top
+
+Installing GDB
+**************
+
+ GDB comes with a `configure' script that automates the process of
+preparing GDB for installation; you can then use `make' to build the
+`gdb' program.
+
+ The GDB distribution includes all the source code you need for GDB in
+a single directory, whose name is usually composed by appending the
+version number to `gdb'.
+
+ For example, the GDB version 4.11 distribution is in the `gdb-4.11'
+directory. That directory contains:
+
+`gdb-4.11/configure (and supporting files)'
+ script for configuring GDB and all its supporting libraries.
+
+`gdb-4.11/gdb'
+ the source specific to GDB itself
+
+`gdb-4.11/bfd'
+ source for the Binary File Descriptor library
+
+`gdb-4.11/include'
+ GNU include files
+
+`gdb-4.11/libiberty'
+ source for the `-liberty' free software library
+
+`gdb-4.11/opcodes'
+ source for the library of opcode tables and disassemblers
+
+`gdb-4.11/readline'
+ source for the GNU command-line interface
+
+`gdb-4.11/glob'
+ source for the GNU filename pattern-matching subroutine
+
+`gdb-4.11/mmalloc'
+ source for the GNU memory-mapped malloc package
+
+ The simplest way to configure and build GDB is to run `configure'
+from the `gdb-VERSION-NUMBER' source directory, which in this example
+is the `gdb-4.11' directory.
+
+ First switch to the `gdb-VERSION-NUMBER' source directory if you are
+not already in it; then run `configure'. Pass the identifier for the
+platform on which GDB will run as an argument.
+
+ For example:
+
+ cd gdb-4.11
+ ./configure HOST
+ make
+
+where HOST is an identifier such as `sun4' or `decstation', that
+identifies the platform where GDB will run. (You can often leave off
+HOST; `configure' tries to guess the correct value by examining your
+system.)
+
+ Running `configure HOST' and then running `make' builds the `bfd',
+`readline', `mmalloc', and `libiberty' libraries, then `gdb' itself.
+The configured source files, and the binaries, are left in the
+corresponding source directories.
+
+ `configure' is a Bourne-shell (`/bin/sh') script; if your system
+does not recognize this automatically when you run a different shell,
+you may need to run `sh' on it explicitly:
+
+ sh configure HOST
+
+ If you run `configure' from a directory that contains source
+directories for multiple libraries or programs, such as the `gdb-4.11'
+source directory for version 4.11, `configure' creates configuration
+files for every directory level underneath (unless you tell it not to,
+with the `--norecursion' option).
+
+ You can run the `configure' script from any of the subordinate
+directories in the GDB distribution if you only want to configure that
+subdirectory, but be sure to specify a path to it.
+
+ For example, with version 4.11, type the following to configure only
+the `bfd' subdirectory:
+
+ cd gdb-4.11/bfd
+ ../configure HOST
+
+ You can install `gdb' anywhere; it has no hardwired paths. However,
+you should make sure that the shell on your path (named by the `SHELL'
+environment variable) is publicly readable. Remember that GDB uses the
+shell to start your program--some systems refuse to let GDB debug child
+processes whose programs are not readable.
+
+* Menu:
+
+* Separate Objdir:: Compiling GDB in another directory
+* Config Names:: Specifying names for hosts and targets
+* configure Options:: Summary of options for configure
+
+
+File: gdb.info, Node: Separate Objdir, Next: Config Names, Up: Installing GDB
+
+Compiling GDB in another directory
+==================================
+
+ If you want to run GDB versions for several host or target machines,
+you need a different `gdb' compiled for each combination of host and
+target. `configure' is designed to make this easy by allowing you to
+generate each configuration in a separate subdirectory, rather than in
+the source directory. If your `make' program handles the `VPATH'
+feature (GNU `make' does), running `make' in each of these directories
+builds the `gdb' program specified there.
+
+ To build `gdb' in a separate directory, run `configure' with the
+`--srcdir' option to specify where to find the source. (You also need
+to specify a path to find `configure' itself from your working
+directory. If the path to `configure' would be the same as the
+argument to `--srcdir', you can leave out the `--srcdir' option; it
+will be assumed.)
+
+ For example, with version 4.11, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+ cd gdb-4.11
+ mkdir ../gdb-sun4
+ cd ../gdb-sun4
+ ../gdb-4.11/configure sun4
+ make
+
+ When `configure' builds a configuration using a remote source
+directory, it creates a tree for the binaries with the same structure
+(and using the same names) as the tree under the source directory. In
+the example, you'd find the Sun 4 library `libiberty.a' in the
+directory `gdb-sun4/libiberty', and GDB itself in `gdb-sun4/gdb'.
+
+ One popular reason to build several GDB configurations in separate
+directories is to configure GDB for cross-compiling (where GDB runs on
+one machine--the host--while debugging programs that run on another
+machine--the target). You specify a cross-debugging target by giving
+the `--target=TARGET' option to `configure'.
+
+ When you run `make' to build a program or library, you must run it
+in a configured directory--whatever directory you were in when you
+called `configure' (or one of its subdirectories).
+
+ The `Makefile' that `configure' generates in each source directory
+also runs recursively. If you type `make' in a source directory such
+as `gdb-4.11' (or in a separate configured directory configured with
+`--srcdir=PATH/gdb-4.11'), you will build all the required libraries,
+and then build GDB.
+
+ When you have multiple hosts or targets configured in separate
+directories, you can run `make' on them in parallel (for example, if
+they are NFS-mounted on each of the hosts); they will not interfere
+with each other.
+
+
+File: gdb.info, Node: Config Names, Next: configure Options, Prev: Separate Objdir, Up: Installing GDB
+
+Specifying names for hosts and targets
+======================================
+
+ The specifications used for hosts and targets in the `configure'
+script are based on a three-part naming scheme, but some short
+predefined aliases are also supported. The full naming scheme encodes
+three pieces of information in the following pattern:
+
+ ARCHITECTURE-VENDOR-OS
+
+ For example, you can use the alias `sun4' as a HOST argument, or as
+the value for TARGET in a `--target=TARGET' option. The equivalent
+full name is `sparc-sun-sunos4'.
+
+ The `configure' script accompanying GDB does not provide any query
+facility to list all supported host and target names or aliases.
+`configure' calls the Bourne shell script `config.sub' to map
+abbreviations to full names; you can read the script, if you wish, or
+you can use it to test your guesses on abbreviations--for example:
+
+ % sh config.sub sun4
+ sparc-sun-sunos4.1.1
+ % sh config.sub sun3
+ m68k-sun-sunos4.1.1
+ % sh config.sub decstation
+ mips-dec-ultrix4.2
+ % sh config.sub hp300bsd
+ m68k-hp-bsd
+ % sh config.sub i386v
+ i386-unknown-sysv
+ % sh config.sub i786v
+ Invalid configuration `i786v': machine `i786v' not recognized
+
+`config.sub' is also distributed in the GDB source directory
+(`gdb-4.11', for version 4.11).
+
+
+File: gdb.info, Node: configure Options, Prev: Config Names, Up: Installing GDB
+
+`configure' options
+===================
+
+ Here is a summary of the `configure' options and arguments that are
+most often useful for building GDB. `configure' also has several other
+options not listed here. *note : (configure.info)What Configure Does,
+for a full explanation of `configure'.
+
+ configure [--help]
+ [--prefix=DIR]
+ [--srcdir=PATH]
+ [--norecursion] [--rm]
+ [--target=TARGET] HOST
+
+You may introduce options with a single `-' rather than `--' if you
+prefer; but you may abbreviate option names if you use `--'.
+
+`--help'
+ Display a quick summary of how to invoke `configure'.
+
+`-prefix=DIR'
+ Configure the source to install programs and files under directory
+ `DIR'.
+
+`--srcdir=PATH'
+ *Warning: using this option requires GNU `make', or another `make'
+ that implements the `VPATH' feature.*
+ Use this option to make configurations in directories separate
+ from the GDB source directories. Among other things, you can use
+ this to build (or maintain) several configurations simultaneously,
+ in separate directories. `configure' writes configuration
+ specific files in the current directory, but arranges for them to
+ use the source in the directory PATH. `configure' will create
+ directories under the working directory in parallel to the source
+ directories below PATH.
+
+`--norecursion'
+ Configure only the directory level where `configure' is executed;
+ do not propagate configuration to subdirectories.
+
+`--rm'
+ *Remove* files otherwise built during configuration.
+
+`--target=TARGET'
+ Configure GDB for cross-debugging programs running on the specified
+ TARGET. Without this option, GDB is configured to debug programs
+ that run on the same machine (HOST) as GDB itself.
+
+ There is no convenient way to generate a list of all available
+ targets.
+
+`HOST ...'
+ Configure GDB to run on the specified HOST.
+
+ There is no convenient way to generate a list of all available
+ hosts.
+
+`configure' accepts other options, for compatibility with configuring
+other GNU tools recursively; but these are the only options that affect
+GDB or its supporting libraries.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-8 b/gnu/usr.bin/gdb/doc/gdb.info-8
new file mode 100644
index 000000000000..1d259e043236
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-8
@@ -0,0 +1,657 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+
+ 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.
+
+
+File: gdb.info, Node: Index, Prev: Installing GDB, Up: Top
+
+Index
+*****
+
+* Menu:
+
+* #: Command Syntax.
+* $bpnum: Set Breaks.
+* $cdir: Source Path.
+* $cwd: Source Path.
+* $_: Convenience Vars.
+* $__: Convenience Vars.
+* .: M2 Scope.
+* .esgdbinit: Command Files.
+* .os68gdbinit: Command Files.
+* .vxgdbinit: Command Files.
+* /proc: Process Information.
+* 386: Remote Serial.
+* 680x0: Remote Serial.
+* @: Arrays.
+* # in Modula-2: GDB/M2.
+* $$: Value History.
+* $_ and info breakpoints: Set Breaks.
+* $_ and info line: Machine Code.
+* $_, $__, and value history: Memory.
+* $: Value History.
+* breakpoint subroutine, remote: Stub Contents.
+* heuristic-fence-post (MIPS): MIPS Stack.
+* remotedebug, MIPS protocol: MIPS Remote.
+* retransmit-timeout, MIPS protocol: MIPS Remote.
+* timeout, MIPS protocol: MIPS Remote.
+* vi style command editing: Readline Vi Mode.
+* .gdbinit: Command Files.
+* COFF versus C++: Cplus expressions.
+* ECOFF and C++: Cplus expressions.
+* ELF/DWARF and C++: Cplus expressions.
+* ELF/stabs and C++: Cplus expressions.
+* XCOFF and C++: Cplus expressions.
+* GDB bugs, reporting: Bug Reporting.
+* {TYPE}: Expressions.
+* a.out and C++: Cplus expressions.
+* abbreviation: Command Syntax.
+* active targets: Active Targets.
+* add-symbol-file: Files.
+* add-syms: Renamed Commands.
+* AMD 29K register stack: Registers.
+* AMD EB29K: Target Commands.
+* AMD29K via UDI: UDI29K Remote.
+* arguments (to your program): Arguments.
+* artificial array: Arrays.
+* assembly instructions: Machine Code.
+* assignment: Assignment.
+* attach: Attach.
+* attach: Attach.
+* automatic display: Auto Display.
+* b: Set Breaks.
+* backtrace: Backtrace.
+* break: Set Breaks.
+* break in overloaded functions: Debugging C plus plus.
+* breakpoint commands: Break Commands.
+* breakpoint conditions: Conditions.
+* breakpoint numbers: Breakpoints.
+* breakpoint on memory address: Breakpoints.
+* breakpoint on variable modification: Breakpoints.
+* breakpoints: Breakpoints.
+* bt: Backtrace.
+* bug criteria: Bug Criteria.
+* bug reports: Bug Reporting.
+* bugs in GDB: GDB Bugs.
+* c: Continuing and Stepping.
+* C and C++: C.
+* C and C++ checks: C Checks.
+* C and C++ constants: C Operators.
+* C and C++ defaults: C Defaults.
+* C and C++ operators: C.
+* C++: C.
+* C++ and object formats: Cplus expressions.
+* C++ exception handling: Debugging C plus plus.
+* C++ scope resolution: Variables.
+* C++ support, not in COFF: Cplus expressions.
+* C++ symbol decoding style: Print Settings.
+* C++ symbol display: Debugging C plus plus.
+* call: Calling.
+* call overloaded functions: Cplus expressions.
+* call stack: Stack.
+* calling functions: Calling.
+* calling make: Shell Commands.
+* casts, to view memory: Expressions.
+* catch: Exception Handling.
+* catch exceptions: Frame Info.
+* cd: Working Directory.
+* cdir: Source Path.
+* checks, range: Type Checking.
+* checks, type: Checks.
+* checksum, for GDB remote: Protocol.
+* clear: Delete Breaks.
+* clearing breakpoints, watchpoints: Delete Breaks.
+* colon, doubled as scope operator: M2 Scope.
+* colon-colon: M2 Scope.
+* colon-colon: Variables.
+* command files: Hooks.
+* command files: Command Files.
+* command line editing: Editing.
+* commands: Break Commands.
+* commands for C++: Debugging C plus plus.
+* commands to STDBUG (ST2000): ST2000 Remote.
+* comment: Command Syntax.
+* compilation directory: Source Path.
+* completion: Completion.
+* completion of quoted strings: Completion.
+* condition: Conditions.
+* conditional breakpoints: Conditions.
+* configuring GDB: Installing GDB.
+* confirmation: Messages/Warnings.
+* connect (to STDBUG): ST2000 Remote.
+* continue: Continuing and Stepping.
+* continuing: Continuing and Stepping.
+* controlling terminal: Input/Output.
+* convenience variables: Convenience Vars.
+* core: Files.
+* core dump file: Files.
+* core-file: Files.
+* CPU simulator: Simulator.
+* crash of debugger: Bug Criteria.
+* current directory: Source Path.
+* cwd: Source Path.
+* d: Delete Breaks.
+* debugger crash: Bug Criteria.
+* debugging optimized code: Compilation.
+* debugging stub, example: Protocol.
+* debugging target: Targets.
+* define: Define.
+* delete: Delete Breaks.
+* delete breakpoints: Delete Breaks.
+* delete display: Auto Display.
+* delete environment: Renamed Commands.
+* deleting breakpoints, watchpoints: Delete Breaks.
+* detach: Attach.
+* device: Hitachi Remote.
+* directories for source files: Source Path.
+* directory: Source Path.
+* directory, compilation: Source Path.
+* directory, current: Source Path.
+* dis: Disabling.
+* disable: Disabling.
+* disable breakpoints: Disabling.
+* disable display: Auto Display.
+* disabled breakpoints: Disabling.
+* disassemble: Machine Code.
+* display: Auto Display.
+* display of expressions: Auto Display.
+* do: Selection.
+* document: Define.
+* documentation: Formatting Documentation.
+* down: Selection.
+* down-silently: Selection.
+* download to H8/300 or H8/500: Files.
+* download to Hitachi SH: Files.
+* download to Nindy-960: Files.
+* download to VxWorks: VxWorks Download.
+* dynamic linking: Files.
+* eb.log: Remote Log.
+* EB29K board: EB29K Remote.
+* EBMON: Comms (EB29K).
+* echo: Output.
+* editing: Editing.
+* editing-mode: Readline Init Syntax.
+* emacs: Emacs.
+* enable: Disabling.
+* enable breakpoints: Disabling.
+* enable display: Auto Display.
+* enabled breakpoints: Disabling.
+* end: Break Commands.
+* entering numbers: Numbers.
+* environment (of your program): Environment.
+* error on valid input: Bug Criteria.
+* event designators: Event Designators.
+* examining data: Data.
+* examining memory: Memory.
+* exception handlers: Exception Handling.
+* exception handlers: Frame Info.
+* exceptionHandler: Bootstrapping.
+* exec-file: Files.
+* executable file: Files.
+* exiting GDB: Quitting GDB.
+* expansion: History Interaction.
+* expressions: Expressions.
+* expressions in C or C++: C.
+* expressions in C++: Cplus expressions.
+* expressions in Modula-2: Modula-2.
+* f: Selection.
+* fatal signal: Bug Criteria.
+* fatal signals: Signals.
+* fg: Continuing and Stepping.
+* file: Files.
+* finish: Continuing and Stepping.
+* flinching: Messages/Warnings.
+* floating point: Floating Point Hardware.
+* floating point registers: Registers.
+* floating point, MIPS remote: MIPS Remote.
+* flush_i_cache: Bootstrapping.
+* foo: Symbol Errors.
+* format options: Print Settings.
+* formatted output: Output Formats.
+* Fortran: Summary.
+* forward-search: Search.
+* frame: Selection.
+* frame: Frames.
+* frame number: Frames.
+* frame pointer: Frames.
+* frameless execution: Frames.
+* g++: C.
+* GDB reference card: Formatting Documentation.
+* gdbserver: Server.
+* getDebugChar: Bootstrapping.
+* GNU C++: C.
+* h: Help.
+* H8/300 or H8/500 download: Files.
+* H8/300 or H8/500 simulator: Simulator.
+* handle: Signals.
+* handle_exception: Stub Contents.
+* handling signals: Signals.
+* help: Help.
+* help target: Target Commands.
+* help user-defined: Define.
+* history expansion: History.
+* history file: History.
+* history number: Value History.
+* history save: History.
+* history size: History.
+* history substitution: History.
+* Hitachi SH download: Files.
+* Hitachi SH simulator: Simulator.
+* horizontal-scroll-mode: Readline Init Syntax.
+* i: Help.
+* i/o: Input/Output.
+* i386-stub.c: Remote Serial.
+* i960: i960-Nindy Remote.
+* ignore: Conditions.
+* ignore count (of breakpoint): Conditions.
+* INCLUDE_RDB: VxWorks Remote.
+* info: Help.
+* info address: Symbols.
+* info all-registers: Registers.
+* info args: Frame Info.
+* info breakpoints: Set Breaks.
+* info catch: Frame Info.
+* info convenience: Renamed Commands.
+* info copying: Renamed Commands.
+* info directories: Renamed Commands.
+* info display: Auto Display.
+* info editing: Renamed Commands.
+* info f: Frame Info.
+* info files: Files.
+* info float: Floating Point Hardware.
+* info frame: Frame Info.
+* info frame: Show.
+* info functions: Symbols.
+* info history: Renamed Commands.
+* info line: Machine Code.
+* info locals: Frame Info.
+* info proc: Process Information.
+* info proc id: Process Information.
+* info proc mappings: Process Information.
+* info proc status: Process Information.
+* info proc times: Process Information.
+* info program: Stopping.
+* info registers: Registers.
+* info s: Backtrace.
+* info set: Help.
+* info share: Files.
+* info sharedlibrary: Files.
+* info signals: Signals.
+* info source: Symbols.
+* info source: Show.
+* info sources: Symbols.
+* info stack: Backtrace.
+* info target: Files.
+* info targets: Renamed Commands.
+* info terminal: Input/Output.
+* info types: Symbols.
+* info values: Renamed Commands.
+* info variables: Symbols.
+* info version: Renamed Commands.
+* info warranty: Renamed Commands.
+* info watchpoints: Set Watchpoints.
+* inheritance: Debugging C plus plus.
+* init file: Command Files.
+* init file name: Command Files.
+* initial frame: Frames.
+* innermost frame: Frames.
+* inspect: Data.
+* installation: Installing GDB.
+* instructions, assembly: Machine Code.
+* Intel: Remote Serial.
+* interaction, readline: Readline Interaction.
+* internal GDB breakpoints: Set Breaks.
+* interrupt: Quitting GDB.
+* interrupting remote programs: Debug Session.
+* invalid input: Bug Criteria.
+* jump: Jumping.
+* kill: Kill Process.
+* l: List.
+* languages: Languages.
+* latest breakpoint: Set Breaks.
+* leaving GDB: Quitting GDB.
+* linespec: List.
+* list: List.
+* listing machine instructions: Machine Code.
+* load: Files.
+* log file for EB29K: Remote Log.
+* m68k-stub.c: Remote Serial.
+* machine instructions: Machine Code.
+* maint info breakpoints: Set Breaks.
+* maint print psymbols: Symbols.
+* maint print symbols: Symbols.
+* make: Shell Commands.
+* mapped: Files.
+* mark-modified-lines: Readline Init Syntax.
+* member functions: Cplus expressions.
+* memory tracing: Breakpoints.
+* memory, viewing as typed object: Expressions.
+* memory-mapped symbol file: Files.
+* memset: Bootstrapping.
+* MIPS boards: MIPS Remote.
+* MIPS remote floating point: MIPS Remote.
+* MIPS stack: MIPS Stack.
+* Modula-2: Modula-2.
+* Modula-2 built-ins: M2 Operators.
+* Modula-2 checks: M2 Checks.
+* Modula-2 constants: Built-In Func/Proc.
+* Modula-2 defaults: M2 Defaults.
+* Modula-2 operators: M2 Operators.
+* Modula-2, deviations from: Deviations.
+* Motorola 680x0: Remote Serial.
+* multiple targets: Active Targets.
+* n: Continuing and Stepping.
+* names of symbols: Symbols.
+* namespace in C++: Cplus expressions.
+* negative breakpoint numbers: Set Breaks.
+* next: Continuing and Stepping.
+* nexti: Continuing and Stepping.
+* ni: Continuing and Stepping.
+* Nindy: i960-Nindy Remote.
+* number representation: Numbers.
+* numbers for breakpoints: Breakpoints.
+* object formats and C++: Cplus expressions.
+* online documentation: Help.
+* optimized code, debugging: Compilation.
+* outermost frame: Frames.
+* output: Output.
+* output formats: Output Formats.
+* overloading: Breakpoint Menus.
+* overloading in C++: Debugging C plus plus.
+* packets, reporting on stdout: Protocol.
+* partial symbol dump: Symbols.
+* patching binaries: Patching.
+* path: Environment.
+* pauses in output: Screen Size.
+* pipes: Starting.
+* prefer-visible-bell: Readline Init Syntax.
+* print: Data.
+* print settings: Print Settings.
+* printf: Output.
+* printing data: Data.
+* process image: Process Information.
+* prompt: Prompt.
+* protocol, GDB remote serial: Protocol.
+* ptype: Symbols.
+* putDebugChar: Bootstrapping.
+* pwd: Working Directory.
+* q: Quitting GDB.
+* quit: Quitting GDB.
+* quotes in commands: Completion.
+* quoting names: Symbols.
+* raise exceptions: Exception Handling.
+* range checking: Type Checking.
+* rbreak: Set Breaks.
+* reading symbols immediately: Files.
+* readline: Editing.
+* readnow: Files.
+* redirection: Input/Output.
+* reference card: Formatting Documentation.
+* reference declarations: Cplus expressions.
+* register stack, AMD29K: Registers.
+* registers: Registers.
+* regular expression: Set Breaks.
+* reloading symbols: Messages/Warnings.
+* remote connection without stubs: Server.
+* remote debugging: Remote.
+* remote programs, interrupting: Debug Session.
+* remote serial debugging summary: Debug Session.
+* remote serial debugging, overview: Remote Serial.
+* remote serial protocol: Protocol.
+* remote serial stub: Stub Contents.
+* remote serial stub list: Remote Serial.
+* remote serial stub, initialization: Stub Contents.
+* remote serial stub, main routine: Stub Contents.
+* remote stub, example: Protocol.
+* remote stub, support routines: Bootstrapping.
+* repeating commands: Command Syntax.
+* reporting bugs in GDB: GDB Bugs.
+* reset: Nindy Reset.
+* response time, MIPS debugging: MIPS Stack.
+* resuming execution: Continuing and Stepping.
+* RET: Command Syntax.
+* return: Returning.
+* returning from a function: Returning.
+* reverse-search: Search.
+* run: Starting.
+* running: Starting.
+* running 29K programs: EB29K Remote.
+* running VxWorks tasks: VxWorks Attach.
+* s: Continuing and Stepping.
+* saving symbol table: Files.
+* scope: M2 Scope.
+* search: Search.
+* searching: Search.
+* selected frame: Stack.
+* serial connections, debugging: Protocol.
+* serial device, Hitachi micros: Hitachi Remote.
+* serial line speed, Hitachi micros: Hitachi Remote.
+* serial line, target remote: Debug Session.
+* serial protocol, GDB remote: Protocol.
+* set addressprint: Renamed Commands.
+* set args: Arguments.
+* set array-max: Renamed Commands.
+* set arrayprint: Renamed Commands.
+* set asm-demangle: Renamed Commands.
+* set caution: Renamed Commands.
+* set check: Range Checking.
+* set check: Type Checking.
+* set check range: Range Checking.
+* set check type: Type Checking.
+* set complaints: Messages/Warnings.
+* set confirm: Messages/Warnings.
+* set demangle: Renamed Commands.
+* set demangle-style: Print Settings.
+* set editing: Editing.
+* set environment: Environment.
+* set height: Screen Size.
+* set history expansion: History.
+* set history filename: History.
+* set history save: History.
+* set history size: History.
+* set history write: Renamed Commands.
+* set language: Manually.
+* set listsize: List.
+* set mipsfpu off: MIPS Remote.
+* set prettyprint: Renamed Commands.
+* set print address: Print Settings.
+* set print array: Print Settings.
+* set print asm-demangle: Print Settings.
+* set print demangle: Print Settings.
+* set print elements: Print Settings.
+* set print max-symbolic-offset: Print Settings.
+* set print object: Print Settings.
+* set print pretty: Print Settings.
+* set print sevenbit-strings: Print Settings.
+* set print symbol-filename: Print Settings.
+* set print union: Print Settings.
+* set print vtbl: Print Settings.
+* set prompt: Prompt.
+* set radix: Numbers.
+* set remotedebug: Protocol.
+* set retransmit-timeout: MIPS Remote.
+* set rstack_high_address: Registers.
+* set screen-height: Renamed Commands.
+* set screen-width: Renamed Commands.
+* set sevenbit-strings: Renamed Commands.
+* set symbol-reloading: Messages/Warnings.
+* set timeout: MIPS Remote.
+* set unionprint: Renamed Commands.
+* set variable: Assignment.
+* set verbose: Messages/Warnings.
+* set vtblprint: Renamed Commands.
+* set width: Screen Size.
+* set write: Patching.
+* setting variables: Assignment.
+* setting watchpoints: Set Watchpoints.
+* set_debug_traps: Stub Contents.
+* share: Files.
+* shared libraries: Files.
+* sharedlibrary: Files.
+* shell: Shell Commands.
+* shell escape: Shell Commands.
+* show: Help.
+* show addressprint: Renamed Commands.
+* show args: Arguments.
+* show array-max: Renamed Commands.
+* show arrayprint: Renamed Commands.
+* show asm-demangle: Renamed Commands.
+* show caution: Renamed Commands.
+* show check range: Range Checking.
+* show check type: Type Checking.
+* show commands: History.
+* show complaints: Messages/Warnings.
+* show confirm: Messages/Warnings.
+* show convenience: Convenience Vars.
+* show copying: Help.
+* show demangle: Renamed Commands.
+* show demangle-style: Print Settings.
+* show directories: Source Path.
+* show editing: Editing.
+* show environment: Environment.
+* show height: Screen Size.
+* show history: History.
+* show history write: Renamed Commands.
+* show language: Show.
+* show listsize: List.
+* show paths: Environment.
+* show prettyprint: Renamed Commands.
+* show print address: Print Settings.
+* show print array: Print Settings.
+* show print asm-demangle: Print Settings.
+* show print demangle: Print Settings.
+* show print elements: Print Settings.
+* show print max-symbolic-offset: Print Settings.
+* show print object: Print Settings.
+* show print pretty: Print Settings.
+* show print sevenbit-strings: Print Settings.
+* show print symbol-filename: Print Settings.
+* show print union: Print Settings.
+* show print vtbl: Print Settings.
+* show prompt: Prompt.
+* show radix: Numbers.
+* show remotedebug: Protocol.
+* show retransmit-timeout: MIPS Remote.
+* show rstack_high_address: Registers.
+* show screen-height: Renamed Commands.
+* show screen-width: Renamed Commands.
+* show sevenbit-strings: Renamed Commands.
+* show timeout: MIPS Remote.
+* show unionprint: Renamed Commands.
+* show user: Define.
+* show values: Value History.
+* show verbose: Messages/Warnings.
+* show version: Help.
+* show vtblprint: Renamed Commands.
+* show warranty: Help.
+* show width: Screen Size.
+* show write: Patching.
+* si: Continuing and Stepping.
+* signal: Signaling.
+* signals: Signals.
+* silent: Break Commands.
+* sim: Simulator.
+* simulator: Simulator.
+* simulator, H8/300 or H8/500: Simulator.
+* simulator, Hitachi SH: Simulator.
+* simulator, Z8000: Simulator.
+* size of screen: Screen Size.
+* source: Command Files.
+* source path: Source Path.
+* sparc-stub.c: Remote Serial.
+* speed: Hitachi Remote.
+* st2000 CMD: ST2000 Remote.
+* ST2000 auxiliary commands: ST2000 Remote.
+* stack frame: Frames.
+* stack on MIPS: MIPS Stack.
+* stacking targets: Active Targets.
+* starting: Starting.
+* STDBUG commands (ST2000): ST2000 Remote.
+* step: Continuing and Stepping.
+* stepi: Continuing and Stepping.
+* stepping: Continuing and Stepping.
+* stub example, remote debugging: Protocol.
+* stupid questions: Messages/Warnings.
+* symbol decoding style, C++: Print Settings.
+* symbol dump: Symbols.
+* symbol names: Symbols.
+* symbol overloading: Breakpoint Menus.
+* symbol table: Files.
+* symbol-file: Files.
+* symbols, reading immediately: Files.
+* target: Targets.
+* target amd-eb: Target Commands.
+* target core: Target Commands.
+* target exec: Target Commands.
+* target hms: Target Commands.
+* target mips PORT: MIPS Remote.
+* target nindy: Target Commands.
+* target remote: Target Commands.
+* target sim: Target Commands.
+* target sim: Simulator.
+* target st2000: Target Commands.
+* target udi: Target Commands.
+* target vxworks: Target Commands.
+* tbreak: Set Breaks.
+* TCP port, target remote: Debug Session.
+* terminal: Input/Output.
+* this: Cplus expressions.
+* toggle-editing-mode: Readline Vi Mode.
+* tty: Input/Output.
+* type casting memory: Expressions.
+* type checking: Checks.
+* type conversions in C++: Cplus expressions.
+* u: Continuing and Stepping.
+* udi: UDI29K Remote.
+* UDI: UDI29K Remote.
+* undisplay: Auto Display.
+* unset: Renamed Commands.
+* unset environment: Environment.
+* until: Continuing and Stepping.
+* up: Selection.
+* up-silently: Selection.
+* user-defined command: Define.
+* value history: Value History.
+* variable name conflict: Variables.
+* variable values, wrong: Variables.
+* variables, setting: Assignment.
+* version number: Help.
+* VxWorks: VxWorks Remote.
+* watch: Set Watchpoints.
+* watchpoints: Breakpoints.
+* whatis: Symbols.
+* where: Backtrace.
+* word completion: Completion.
+* working directory: Source Path.
+* working directory (of your program): Working Directory.
+* working language: Languages.
+* writing into corefiles: Patching.
+* writing into executables: Patching.
+* wrong values: Variables.
+* x: Memory.
+* Z8000 simulator: Simulator.
+
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.texinfo b/gnu/usr.bin/gdb/doc/gdb.texinfo
new file mode 100644
index 000000000000..a2f293deb2a8
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.texinfo
@@ -0,0 +1,8591 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright (c) 1988 1989 1990 1991 1992 1993 Free Software Foundation, Inc.
+@c
+@c %**start of header
+@c makeinfo ignores cmds prev to setfilename, so its arg cannot make use
+@c of @set vars. However, you can override filename with makeinfo -o.
+@setfilename gdb.info
+@c
+@include gdb-cfg.texi
+@c
+@ifset GENERIC
+@settitle Debugging with @value{GDBN}
+@end ifset
+@ifclear GENERIC
+@settitle Debugging with @value{GDBN} (@value{TARGET})
+@end ifclear
+@setchapternewpage odd
+@c %**end of header
+
+@iftex
+@c @smallbook
+@c @cropmarks
+@end iftex
+
+@finalout
+@syncodeindex ky cp
+
+@c readline appendices use @vindex
+@syncodeindex vr cp
+
+@c ===> NOTE! <==
+@c Determine the edition number in *three* places by hand:
+@c 1. First ifinfo section 2. title page 3. top node
+@c To find the locations, search for !!set
+
+@c GDB CHANGELOG CONSULTED BETWEEN:
+@c Fri Oct 11 23:27:06 1991 John Gilmore (gnu at cygnus.com)
+@c Sat Dec 22 02:51:40 1990 John Gilmore (gnu at cygint)
+
+@c THIS MANUAL REQUIRES TEXINFO-2 macros and info-makers to format properly.
+
+@ifinfo
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree. zoo@cygnus.com is developing this facility.
+@format
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+@c
+@c
+@ifinfo
+This file documents the GNU debugger @value{GDBN}.
+
+@c !!set edition, date, version
+This is Edition 4.09, August 1993,
+of @cite{Debugging with @value{GDBN}: the GNU Source-Level Debugger}
+for GDB Version @value{GDBVN}.
+
+Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software Foundation, Inc.
+
+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.
+
+@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 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.
+@end ifinfo
+
+@titlepage
+@title Debugging with @value{GDBN}
+@subtitle The GNU Source-Level Debugger
+@ifclear GENERIC
+@subtitle (@value{TARGET})
+@end ifclear
+@sp 1
+@c !!set edition, date, version
+@subtitle Edition 4.09, for @value{GDBN} version @value{GDBVN}
+@subtitle August 1993
+@author Richard M. Stallman and Roland H. Pesch
+@page
+@tex
+{\parskip=0pt
+\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@prep.ai.mit.edu.)\par
+\hfill {\it Debugging with @value{GDBN}}\par
+\hfill \TeX{}info \texinfoversion\par
+\hfill pesch\@cygnus.com\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+@sp 2
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA @*
+Printed copies are available for $20 each. @*
+ISBN 1-882114-11-6 @*
+
+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.
+@end titlepage
+@page
+
+@ifinfo
+@node Top
+@top Debugging with @value{GDBN}
+
+This file describes @value{GDBN}, the GNU symbolic debugger.
+
+@c !!set edition, date, version
+This is Edition 4.09, August 1993, for GDB Version @value{GDBVN}.
+
+@menu
+* Summary:: Summary of @value{GDBN}
+@ifset NOVEL
+* New Features:: New features since GDB version 3.5
+@end ifset
+@ifclear BARETARGET
+* Sample Session:: A sample @value{GDBN} session
+@end ifclear
+
+* Invocation:: Getting in and out of @value{GDBN}
+* Commands:: @value{GDBN} commands
+* Running:: Running programs under @value{GDBN}
+* Stopping:: Stopping and continuing
+* Stack:: Examining the stack
+* Source:: Examining source files
+* Data:: Examining data
+@ifclear CONLY
+* Languages:: Using @value{GDBN} with different languages
+@end ifclear
+@ifset CONLY
+* C:: C language support
+@end ifset
+@c remnant makeinfo bug, blank line needed after two end-ifs?
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: @value{GDBN} files
+* Targets:: Specifying a debugging target
+* Controlling GDB:: Controlling @value{GDBN}
+* Sequences:: Canned sequences of commands
+@ifclear DOSHOST
+* Emacs:: Using @value{GDBN} under GNU Emacs
+@end ifclear
+
+* GDB Bugs:: Reporting bugs in @value{GDBN}
+* Command Line Editing:: Facilities of the readline library
+* Using History Interactively::
+@ifset NOVEL
+* Renamed Commands::
+@end ifset
+@ifclear PRECONFIGURED
+* Formatting Documentation:: How to format and print GDB documentation
+* Installing GDB:: Installing GDB
+@end ifclear
+
+* Index:: Index
+@end menu
+@end ifinfo
+
+@node Summary
+@unnumbered Summary of @value{GDBN}
+
+The purpose of a debugger such as @value{GDBN} is to allow you to see what is
+going on ``inside'' another program while it executes---or what another
+program was doing at the moment it crashed.
+
+@value{GDBN} can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+@itemize @bullet
+@item
+Start your program, specifying anything that might affect its behavior.
+
+@item
+Make your program stop on specified conditions.
+
+@item
+Examine what has happened, when your program has stopped.
+
+@item
+Change things in your program, so you can experiment with correcting the
+effects of one bug and go on to learn about another.
+@end itemize
+
+@ifclear CONLY
+@ifclear MOD2
+You can use @value{GDBN} to debug programs written in C or C++.
+@end ifclear
+@ifset MOD2
+You can use @value{GDBN} to debug programs written in C, C++, and
+Modula-2.
+@end ifset
+@ifset FORTRAN
+@cindex Fortran
+@value{GDBN} can be used to debug programs written in Fortran, although
+it does not yet support entering expressions, printing values, etc.
+using Fortran syntax. It may be necessary to refer to some variables
+with a trailing underscore.
+@end ifset
+@end ifclear
+
+@menu
+* Free Software:: Freely redistributable software
+* Contributors:: Contributors to GDB
+@end menu
+
+@node Free Software
+@unnumberedsec Free software
+
+@value{GDBN} is @dfn{free software}, protected by the GNU General Public License
+(GPL). The GPL gives you the freedom to copy or adapt a licensed
+program---but every person getting a copy also gets with it the
+freedom to modify that copy (which means that they must get access to
+the source code), and the freedom to distribute further copies.
+Typical software companies use copyrights to limit your freedoms; the
+Free Software Foundation uses the GPL to preserve these freedoms.
+
+Fundamentally, the General Public License is a license which says that
+you have these freedoms and that you cannot take these freedoms away
+from anyone else.
+
+@node Contributors
+@unnumberedsec Contributors to GDB
+
+Richard Stallman was the original author of GDB, and of many other GNU
+programs. Many others have contributed to its development. This
+section attempts to credit major contributors. One of the virtues of
+free software is that everyone is free to contribute to it; with
+regret, we cannot actually acknowledge everyone here. The file
+@file{ChangeLog} in the GDB distribution approximates a blow-by-blow
+account.
+
+Changes much prior to version 2.0 are lost in the mists of time.
+
+@quotation
+@emph{Plea:} Additions to this section are particularly welcome. If you
+or your friends (or enemies, to be evenhanded) have been unfairly
+omitted from this list, we would like to add your names!
+@end quotation
+
+So that they may not regard their long labor as thankless, we
+particularly thank those who shepherded GDB through major releases: Fred
+Fish (releases 4.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases
+4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and
+3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases
+3.2, 3.1, 3.0). As major maintainer of GDB for some period, each
+contributed significantly to the structure, stability, and capabilities
+of the entire debugger.
+
+Richard Stallman, assisted at various times by Peter TerMaat, Chris
+Hanson, and Richard Mlynarik, handled releases through 2.8.
+
+@ifclear CONLY
+Michael Tiemann is the author of most of the GNU C++ support in GDB,
+with significant additional contributions from Per Bothner. James
+Clark wrote the GNU C++ demangler. Early work on C++ was by Peter
+TerMaat (who also did much general update work leading to release 3.0).
+@end ifclear
+
+GDB 4 uses the BFD subroutine library to examine multiple
+object-file formats; BFD was a joint project of David V.
+Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore.
+
+David Johnson wrote the original COFF support; Pace Willison did
+the original support for encapsulated COFF.
+
+Adam de Boor and Bradley Davis contributed the ISI Optimum V support.
+Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS
+support. Jean-Daniel Fekete contributed Sun 386i support. Chris
+Hanson improved the HP9000 support. Noboyuki Hikichi and Tomoyuki
+Hasei contributed Sony/News OS 3 support. David Johnson contributed
+Encore Umax support. Jyrki Kuoppala contributed Altos 3068 support.
+Keith Packard contributed NS32K support. Doug Rabson contributed
+Acorn Risc Machine support. Chris Smith contributed Convex support
+(and Fortran debugging). Jonathan Stone contributed Pyramid support.
+Michael Tiemann contributed SPARC support. Tim Tucker contributed
+support for the Gould NP1 and Gould Powernode. Pace Willison
+contributed Intel 386 support. Jay Vosburgh contributed Symmetry
+support.
+
+Rich Schaefer and Peter Schauer helped with support of SunOS shared
+libraries.
+
+Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about
+several machine instruction sets.
+
+Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped
+develop remote debugging. Intel Corporation and Wind River Systems
+contributed remote debugging modules for their products.
+
+Brian Fox is the author of the readline libraries providing
+command-line editing and command history.
+
+Andrew Beers of SUNY Buffalo wrote the language-switching code,
+@ifset MOD2
+the Modula-2 support,
+@end ifset
+and contributed the Languages chapter of this manual.
+
+Fred Fish wrote most of the support for Unix System Vr4.
+@ifclear CONLY
+He also enhanced the command-completion support to cover C++ overloaded
+symbols.
+@end ifclear
+
+Hitachi America, Ltd. sponsored the support for Hitachi microprocessors.
+
+@ifset NOVEL
+@node New Features
+@unnumbered New Features since GDB Version 3.5
+
+@table @emph
+@item Targets
+Using the new command @code{target}, you can select at runtime whether
+you are debugging local files, local processes, standalone systems over
+a serial port, realtime systems over a TCP/IP connection, etc. The
+command @code{load} can download programs into a remote system. Serial
+stubs are available for Motorola 680x0, Intel 80386, and Sparc remote
+systems; GDB also supports debugging realtime processes running under
+VxWorks, using SunRPC Remote Procedure Calls over TCP/IP to talk to a
+debugger stub on the target system. Internally, GDB now uses a function
+vector to mediate access to different targets; if you need to add your
+own support for a remote protocol, this makes it much easier.
+
+@item Watchpoints
+GDB now sports watchpoints as well as breakpoints. You can use a
+watchpoint to stop execution whenever the value of an expression
+changes, without having to predict a particular place in your program
+where this may happen.
+
+@item Wide Output
+Commands that issue wide output now insert newlines at places designed
+to make the output more readable.
+
+@item Object Code Formats
+GDB uses a new library called the Binary File Descriptor (BFD) Library
+to permit it to switch dynamically, without reconfiguration or
+recompilation, between different object-file formats. Formats currently
+supported are COFF, ELF, a.out, Intel 960 b.out, MIPS ECOFF, HPPA SOM
+(with stabs debugging), and S-records; files may be read as .o files,
+archive libraries, or core dumps. BFD is available as a subroutine
+library so that other programs may take advantage of it, and the other
+GNU binary utilities are being converted to use it.
+
+@item Configuration and Ports
+Compile-time configuration (to select a particular architecture and
+operating system) is much easier. The script @code{configure} now
+allows you to configure GDB as either a native debugger or a
+cross-debugger. @xref{Installing GDB}, for details on how to
+configure.
+
+@item Interaction
+The user interface to the GDB control variables is simpler,
+and is consolidated in two commands, @code{set} and @code{show}. Output
+lines are now broken at readable places, rather than overflowing onto
+the next line. You can suppress output of machine-level addresses,
+displaying only source language information.
+
+@item C++
+GDB now supports C++ multiple inheritance (if used with a GCC
+version 2 compiler), and also has limited support for C++ exception
+handling, with the commands @code{catch} and @code{info catch}: GDB
+can break when an exception is raised, before the stack is peeled back
+to the exception handler's context.
+
+@ifset MOD2
+@item Modula-2
+GDB now has preliminary support for the GNU Modula-2 compiler, currently
+under development at the State University of New York at Buffalo.
+Coordinated development of both GDB and the GNU Modula-2 compiler will
+continue. Other Modula-2 compilers are currently not supported, and
+attempting to debug programs compiled with them will likely result in an
+error as the symbol table of the executable is read in.
+@end ifset
+
+@item Command Rationalization
+Many GDB commands have been renamed to make them easier to remember
+and use. In particular, the subcommands of @code{info} and
+@code{show}/@code{set} are grouped to make the former refer to the state
+of your program, and the latter refer to the state of GDB itself.
+@xref{Renamed Commands}, for details on what commands were renamed.
+
+@item Shared Libraries
+GDB 4 can debug programs and core files that use SunOS, SVR4, or IBM RS/6000
+shared libraries.
+
+@item Reference Card
+GDB 4 has a reference card. @xref{Formatting Documentation,,Formatting
+the Documentation}, for instructions about how to print it.
+@end table
+@end ifset
+
+@ifclear BARETARGET
+@node Sample Session
+@chapter A Sample @value{GDBN} Session
+
+You can use this manual at your leisure to read all about @value{GDBN}.
+However, a handful of commands are enough to get started using the
+debugger. This chapter illustrates those commands.
+
+@iftex
+In this sample session, we emphasize user input like this: @b{input},
+to make it easier to pick out from the surrounding output.
+@end iftex
+
+@c FIXME: this example may not be appropriate for some configs, where
+@c FIXME...primary interest is in remote use.
+
+One of the preliminary versions of GNU @code{m4} (a generic macro
+processor) exhibits the following bug: sometimes, when we change its
+quote strings from the default, the commands used to capture one macro
+definition within another stop working. In the following short @code{m4}
+session, we define a macro @code{foo} which expands to @code{0000}; we
+then use the @code{m4} built-in @code{defn} to define @code{bar} as the
+same thing. However, when we change the open quote string to
+@code{<QUOTE>} and the close quote string to @code{<UNQUOTE>}, the same
+procedure fails to define a new synonym @code{baz}:
+
+@smallexample
+$ @b{cd gnu/m4}
+$ @b{./m4}
+@b{define(foo,0000)}
+
+@b{foo}
+0000
+@b{define(bar,defn(`foo'))}
+
+@b{bar}
+0000
+@b{changequote(<QUOTE>,<UNQUOTE>)}
+
+@b{define(baz,defn(<QUOTE>foo<UNQUOTE>))}
+@b{baz}
+@b{C-d}
+m4: End of input: 0: fatal error: EOF in string
+@end smallexample
+
+@noindent
+Let us use @value{GDBN} to try to see what is going on.
+
+@smallexample
+$ @b{@value{GDBP} m4}
+@c FIXME: this falsifies the exact text played out, to permit smallbook
+@c FIXME... format to come out better.
+GDB is free software and you are welcome to distribute copies
+ of it under certain conditions; type "show copying" to see
+ the conditions.
+There is absolutely no warranty for GDB; type "show warranty"
+ for details.
+GDB @value{GDBVN}, Copyright 1993 Free Software Foundation, Inc...
+(@value{GDBP})
+@end smallexample
+
+@noindent
+@value{GDBN} reads only enough symbol data to know where to find the rest when
+needed; as a result, the first prompt comes up very quickly. We now
+tell @value{GDBN} to use a narrower display width than usual, so that examples
+will fit in this manual.
+
+@smallexample
+(@value{GDBP}) @b{set width 70}
+@end smallexample
+
+@noindent
+We need to see how the @code{m4} built-in @code{changequote} works.
+Having looked at the source, we know the relevant subroutine is
+@code{m4_changequote}, so we set a breakpoint there with the @value{GDBN}
+@code{break} command.
+
+@smallexample
+(@value{GDBP}) @b{break m4_changequote}
+Breakpoint 1 at 0x62f4: file builtin.c, line 879.
+@end smallexample
+
+@noindent
+Using the @code{run} command, we start @code{m4} running under @value{GDBN}
+control; as long as control does not reach the @code{m4_changequote}
+subroutine, the program runs as usual:
+
+@smallexample
+(@value{GDBP}) @b{run}
+Starting program: /work/Editorial/gdb/gnu/m4/m4
+@b{define(foo,0000)}
+
+@b{foo}
+0000
+@end smallexample
+
+@noindent
+To trigger the breakpoint, we call @code{changequote}. @value{GDBN}
+suspends execution of @code{m4}, displaying information about the
+context where it stops.
+
+@smallexample
+@b{changequote(<QUOTE>,<UNQUOTE>)}
+
+Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:879
+879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
+@end smallexample
+
+@noindent
+Now we use the command @code{n} (@code{next}) to advance execution to
+the next line of the current function.
+
+@smallexample
+(@value{GDBP}) @b{n}
+882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
+ : nil,
+@end smallexample
+
+@noindent
+@code{set_quotes} looks like a promising subroutine. We can go into it
+by using the command @code{s} (@code{step}) instead of @code{next}.
+@code{step} goes to the next line to be executed in @emph{any}
+subroutine, so it steps into @code{set_quotes}.
+
+@smallexample
+(@value{GDBP}) @b{s}
+set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+530 if (lquote != def_lquote)
+@end smallexample
+
+@noindent
+The display that shows the subroutine where @code{m4} is now
+suspended (and its arguments) is called a stack frame display. It
+shows a summary of the stack. We can use the @code{backtrace}
+command (which can also be spelled @code{bt}), to see where we are
+in the stack as a whole: the @code{backtrace} command displays a
+stack frame for each active subroutine.
+
+@smallexample
+(@value{GDBP}) @b{bt}
+#0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+#1 0x6344 in m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:882
+#2 0x8174 in expand_macro (sym=0x33320) at macro.c:242
+#3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30)
+ at macro.c:71
+#4 0x79dc in expand_input () at macro.c:40
+#5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195
+@end smallexample
+
+@noindent
+We will step through a few more lines to see what happens. The first two
+times, we can use @samp{s}; the next two times we use @code{n} to avoid
+falling into the @code{xstrdup} subroutine.
+
+@smallexample
+(@value{GDBP}) @b{s}
+0x3b5c 532 if (rquote != def_rquote)
+(@value{GDBP}) @b{s}
+0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \
+def_lquote : xstrdup(lq);
+(@value{GDBP}) @b{n}
+536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup(rq);
+(@value{GDBP}) @b{n}
+538 len_lquote = strlen(rquote);
+@end smallexample
+
+@noindent
+The last line displayed looks a little odd; we can examine the variables
+@code{lquote} and @code{rquote} to see if they are in fact the new left
+and right quotes we specified. We use the command @code{p}
+(@code{print}) to see their values.
+
+@smallexample
+(@value{GDBP}) @b{p lquote}
+$1 = 0x35d40 "<QUOTE>"
+(@value{GDBP}) @b{p rquote}
+$2 = 0x35d50 "<UNQUOTE>"
+@end smallexample
+
+@noindent
+@code{lquote} and @code{rquote} are indeed the new left and right quotes.
+To look at some context, we can display ten lines of source
+surrounding the current line with the @code{l} (@code{list}) command.
+
+@smallexample
+(@value{GDBP}) @b{l}
+533 xfree(rquote);
+534
+535 lquote = (lq == nil || *lq == '\0') ? def_lquote\
+ : xstrdup (lq);
+536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup (rq);
+537
+538 len_lquote = strlen(rquote);
+539 len_rquote = strlen(lquote);
+540 @}
+541
+542 void
+@end smallexample
+
+@noindent
+Let us step past the two lines that set @code{len_lquote} and
+@code{len_rquote}, and then examine the values of those variables.
+
+@smallexample
+(@value{GDBP}) @b{n}
+539 len_rquote = strlen(lquote);
+(@value{GDBP}) @b{n}
+540 @}
+(@value{GDBP}) @b{p len_lquote}
+$3 = 9
+(@value{GDBP}) @b{p len_rquote}
+$4 = 7
+@end smallexample
+
+@noindent
+That certainly looks wrong, assuming @code{len_lquote} and
+@code{len_rquote} are meant to be the lengths of @code{lquote} and
+@code{rquote} respectively. We can set them to better values using
+the @code{p} command, since it can print the value of
+any expression---and that expression can include subroutine calls and
+assignments.
+
+@smallexample
+(@value{GDBP}) @b{p len_lquote=strlen(lquote)}
+$5 = 7
+(@value{GDBP}) @b{p len_rquote=strlen(rquote)}
+$6 = 9
+@end smallexample
+
+@noindent
+Is that enough to fix the problem of using the new quotes with the
+@code{m4} built-in @code{defn}? We can allow @code{m4} to continue
+executing with the @code{c} (@code{continue}) command, and then try the
+example that caused trouble initially:
+
+@smallexample
+(@value{GDBP}) @b{c}
+Continuing.
+
+@b{define(baz,defn(<QUOTE>foo<UNQUOTE>))}
+
+baz
+0000
+@end smallexample
+
+@noindent
+Success! The new quotes now work just as well as the default ones. The
+problem seems to have been just the two typos defining the wrong
+lengths. We allow @code{m4} exit by giving it an EOF as input:
+
+@smallexample
+@b{C-d}
+Program exited normally.
+@end smallexample
+
+@noindent
+The message @samp{Program exited normally.} is from @value{GDBN}; it
+indicates @code{m4} has finished executing. We can end our @value{GDBN}
+session with the @value{GDBN} @code{quit} command.
+
+@smallexample
+(@value{GDBP}) @b{quit}
+@end smallexample
+@end ifclear
+
+@node Invocation
+@chapter Getting In and Out of @value{GDBN}
+
+This chapter discusses how to start @value{GDBN}, and how to get out of it.
+(The essentials: type @samp{@value{GDBP}} to start GDB, and type @kbd{quit}
+or @kbd{C-d} to exit.)
+
+@menu
+* Invoking GDB:: How to start @value{GDBN}
+* Quitting GDB:: How to quit @value{GDBN}
+* Shell Commands:: How to use shell commands inside @value{GDBN}
+@end menu
+
+@node Invoking GDB
+@section Invoking @value{GDBN}
+
+@ifset H8EXCLUSIVE
+For details on starting up @value{GDBP} as a
+remote debugger attached to a Hitachi microprocessor, see @ref{Hitachi
+Remote,,@value{GDBN} and Hitachi Microprocessors}.
+@end ifset
+
+Invoke @value{GDBN} by running the program @code{@value{GDBP}}. Once started,
+@value{GDBN} reads commands from the terminal until you tell it to exit.
+
+You can also run @code{@value{GDBP}} with a variety of arguments and options,
+to specify more of your debugging environment at the outset.
+
+@ifset GENERIC
+The command-line options described here are designed
+to cover a variety of situations; in some environments, some of these
+options may effectively be unavailable.
+@end ifset
+
+The most usual way to start @value{GDBN} is with one argument,
+specifying an executable program:
+
+@example
+@value{GDBP} @var{program}
+@end example
+
+@ifclear BARETARGET
+@noindent
+You can also start with both an executable program and a core file
+specified:
+
+@example
+@value{GDBP} @var{program} @var{core}
+@end example
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+
+@example
+@value{GDBP} @var{program} 1234
+@end example
+
+@noindent
+would attach @value{GDBN} to process @code{1234} (unless you also have a file
+named @file{1234}; @value{GDBN} does check for a core file first).
+
+Taking advantage of the second command-line argument requires a fairly
+complete operating system; when you use @value{GDBN} as a remote debugger
+attached to a bare board, there may not be any notion of ``process'',
+and there is often no way to get a core dump.
+@end ifclear
+
+@noindent
+You can further control how @value{GDBN} starts up by using command-line
+options. @value{GDBN} itself can remind you of the options available.
+
+@noindent
+Type
+
+@example
+@value{GDBP} -help
+@end example
+
+@noindent
+to display all available options and briefly describe their use
+(@samp{@value{GDBP} -h} is a shorter equivalent).
+
+All options and command line arguments you give are processed
+in sequential order. The order makes a difference when the
+@samp{-x} option is used.
+
+
+@menu
+@ifclear GENERIC
+@ifset REMOTESTUB
+* Remote Serial:: @value{GDBN} remote serial protocol
+@end ifset
+@ifset I960
+* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy)
+@end ifset
+@ifset AMD29K
+* UDI29K Remote:: @value{GDBN} and the UDI protocol for AMD29K
+* EB29K Remote:: @value{GDBN} with a remote EB29K
+@end ifset
+@ifset VXWORKS
+* VxWorks Remote:: @value{GDBN} and VxWorks
+@end ifset
+@ifset ST2000
+* ST2000 Remote:: @value{GDBN} with a Tandem ST2000
+@end ifset
+@ifset H8
+* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors
+@end ifset
+@ifset MIPS
+* MIPS Remote:: @value{GDBN} and MIPS boards
+@end ifset
+@ifset SIMS
+* Simulator:: Simulated CPU target
+@end ifset
+@end ifclear
+@c remnant makeinfo bug requires this blank line after *two* end-ifblahs:
+
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+@end menu
+
+@ifclear GENERIC
+@include remote.texi
+@end ifclear
+
+@node File Options
+@subsection Choosing files
+
+@ifclear BARETARGET
+When @value{GDBN} starts, it reads any arguments other than options as
+specifying an executable file and core file (or process ID). This is
+the same as if the arguments were specified by the @samp{-se} and
+@samp{-c} options respectively. (@value{GDBN} reads the first argument
+that does not have an associated option flag as equivalent to the
+@samp{-se} option followed by that argument; and the second argument
+that does not have an associated option flag, if any, as equivalent to
+the @samp{-c} option followed by that argument.)
+@end ifclear
+@ifset BARETARGET
+When @value{GDBN} starts, it reads any argument other than options as
+specifying an executable file. This is the same as if the argument was
+specified by the @samp{-se} option.
+@end ifset
+
+Many options have both long and short forms; both are shown in the
+following list. @value{GDBN} also recognizes the long forms if you truncate
+them, so long as enough of the option is present to be unambiguous.
+(If you prefer, you can flag option arguments with @samp{--} rather
+than @samp{-}, though we illustrate the more usual convention.)
+
+@table @code
+@item -symbols @var{file}
+@itemx -s @var{file}
+Read symbol table from file @var{file}.
+
+@item -exec @var{file}
+@itemx -e @var{file}
+Use file @var{file} as the executable file to execute when
+@ifset BARETARGET
+appropriate.
+@end ifset
+@ifclear BARETARGET
+appropriate, and for examining pure data in conjunction with a core
+dump.
+@end ifclear
+
+@item -se @var{file}
+Read symbol table from file @var{file} and use it as the executable
+file.
+
+@ifclear BARETARGET
+@item -core @var{file}
+@itemx -c @var{file}
+Use file @var{file} as a core dump to examine.
+
+@item -c @var{number}
+Connect to process ID @var{number}, as with the @code{attach} command
+(unless there is a file in core-dump format named @var{number}, in which
+case @samp{-c} specifies that file as a core dump to read).
+@end ifclear
+
+@item -command @var{file}
+@itemx -x @var{file}
+Execute @value{GDBN} commands from file @var{file}. @xref{Command
+Files,, Command files}.
+
+@item -directory @var{directory}
+@itemx -d @var{directory}
+Add @var{directory} to the path to search for source files.
+
+@ifclear BARETARGET
+@item -m
+@itemx -mapped
+@emph{Warning: this option depends on operating system facilities that are not
+supported on all systems.}@*
+If memory-mapped files are available on your system through the @code{mmap}
+system call, you can use this option
+to have @value{GDBN} write the symbols from your
+program into a reusable file in the current directory. If the program you are debugging is
+called @file{/tmp/fred}, the mapped symbol file will be @file{./fred.syms}.
+Future @value{GDBN} debugging sessions will notice the presence of this file,
+and will quickly map in symbol information from it, rather than reading
+the symbol table from the executable program.
+
+@c FIXME! Really host, not target?
+The @file{.syms} file is specific to the host machine where @value{GDBN}
+is run. It holds an exact image of the internal @value{GDBN} symbol
+table. It cannot be shared across multiple host platforms.
+@end ifclear
+
+@item -r
+@itemx -readnow
+Read each symbol file's entire symbol table immediately, rather than
+the default, which is to read it incrementally as it is needed.
+This makes startup slower, but makes future operations faster.
+@end table
+
+@ifclear BARETARGET
+The @code{-mapped} and @code{-readnow} options are typically combined in
+order to build a @file{.syms} file that contains complete symbol
+information. (@xref{Files,,Commands to specify files}, for information
+on @file{.syms} files.) A simple GDB invocation to do nothing but build
+a @file{.syms} file for future use is:
+
+@example
+ gdb -batch -nx -mapped -readnow programname
+@end example
+@end ifclear
+
+@node Mode Options
+@subsection Choosing modes
+
+You can run @value{GDBN} in various alternative modes---for example, in
+batch mode or quiet mode.
+
+@table @code
+@item -nx
+@itemx -n
+Do not execute commands from any initialization files (normally called
+@file{@value{GDBINIT}}). Normally, the commands in these files are
+executed after all the command options and arguments have been
+processed. @xref{Command Files,,Command files}.
+
+@item -quiet
+@itemx -q
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+@item -batch
+Run in batch mode. Exit with status @code{0} after processing all the
+command files specified with @samp{-x} (and all commands from
+initialization files, if not inhibited with @samp{-n}). Exit with
+nonzero status if an error occurs in executing the @value{GDBN} commands
+in the command files.
+
+Batch mode may be useful for running @value{GDBN} as a filter, for example to
+download and run a program on another computer; in order to make this
+more useful, the message
+
+@example
+Program exited normally.
+@end example
+
+@noindent
+(which is ordinarily issued whenever a program running under @value{GDBN} control
+terminates) is not issued when running in batch mode.
+
+@item -cd @var{directory}
+Run @value{GDBN} using @var{directory} as its working directory,
+instead of the current directory.
+
+@ifset LUCID
+@item -context @var{authentication}
+When the Energize programming system starts up @value{GDBN}, it uses this
+option to trigger an alternate mode of interaction.
+@var{authentication} is a pair of numeric codes that identify @value{GDBN}
+as a client in the Energize environment. Avoid this option when you run
+@value{GDBN} directly from the command line. See @ref{Energize,,Using
+@value{GDBN} with Energize} for more discussion of using @value{GDBN} with Energize.
+@end ifset
+
+@ifclear DOSHOST
+@item -fullname
+@itemx -f
+Emacs sets this option when it runs @value{GDBN} as a subprocess. It tells @value{GDBN}
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time your program stops). This recognizable format looks
+like two @samp{\032} characters, followed by the file name, line number
+and character position separated by colons, and a newline. The
+Emacs-to-@value{GDBN} interface program uses the two @samp{\032} characters as
+a signal to display the source code for the frame.
+@end ifclear
+
+@ifset SERIAL
+@item -b @var{bps}
+Set the line speed (baud rate or bits per second) of any serial
+interface used by @value{GDBN} for remote debugging.
+
+@item -tty @var{device}
+Run using @var{device} for your program's standard input and output.
+@c FIXME: kingdon thinks there is more to -tty. Investigate.
+@end ifset
+@end table
+
+@node Quitting GDB
+@section Quitting @value{GDBN}
+@cindex exiting @value{GDBN}
+@cindex leaving @value{GDBN}
+
+@table @code
+@item quit
+@kindex quit
+@kindex q
+To exit @value{GDBN}, use the @code{quit} command (abbreviated @code{q}), or type
+an end-of-file character (usually @kbd{C-d}).
+@end table
+
+@cindex interrupt
+An interrupt (often @kbd{C-c}) will not exit from @value{GDBN}, but rather
+will terminate the action of any @value{GDBN} command that is in progress and
+return to @value{GDBN} command level. It is safe to type the interrupt
+character at any time because @value{GDBN} does not allow it to take effect
+until a time when it is safe.
+
+@ifclear BARETARGET
+If you have been using @value{GDBN} to control an attached process or
+device, you can release it with the @code{detach} command
+(@pxref{Attach, ,Debugging an already-running process}).
+@end ifclear
+
+@node Shell Commands
+@section Shell commands
+
+If you need to execute occasional shell commands during your
+debugging session, there is no need to leave or suspend @value{GDBN}; you can
+just use the @code{shell} command.
+
+@table @code
+@item shell @var{command string}
+@kindex shell
+@cindex shell escape
+Invoke a the standard shell to execute @var{command string}.
+@ifclear DOSHOST
+If it exists, the environment variable @code{SHELL} determines which
+shell to run. Otherwise @value{GDBN} uses @code{/bin/sh}.
+@end ifclear
+@end table
+
+The utility @code{make} is often needed in development environments.
+You do not have to use the @code{shell} command for this purpose in
+@value{GDBN}:
+
+@table @code
+@item make @var{make-args}
+@kindex make
+@cindex calling make
+Execute the @code{make} program with the specified
+arguments. This is equivalent to @samp{shell make @var{make-args}}.
+@end table
+
+@node Commands
+@chapter @value{GDBN} Commands
+
+You can abbreviate a @value{GDBN} command to the first few letters of the command
+name, if that abbreviation is unambiguous; and you can repeat certain
+@value{GDBN} commands by typing just @key{RET}. You can also use the @key{TAB}
+key to get @value{GDBN} to fill out the rest of a word in a command (or to
+show you the alternatives available, if there is more than one possibility).
+
+@menu
+* Command Syntax:: How to give commands to @value{GDBN}
+* Completion:: Command completion
+* Help:: How to ask @value{GDBN} for help
+@end menu
+
+@node Command Syntax
+@section Command syntax
+
+A @value{GDBN} command is a single line of input. There is no limit on
+how long it can be. It starts with a command name, which is followed by
+arguments whose meaning depends on the command name. For example, the
+command @code{step} accepts an argument which is the number of times to
+step, as in @samp{step 5}. You can also use the @code{step} command
+with no arguments. Some command names do not allow any arguments.
+
+@cindex abbreviation
+@value{GDBN} command names may always be truncated if that abbreviation is
+unambiguous. Other possible command abbreviations are listed in the
+documentation for individual commands. In some cases, even ambiguous
+abbreviations are allowed; for example, @code{s} is specially defined as
+equivalent to @code{step} even though there are other commands whose
+names start with @code{s}. You can test abbreviations by using them as
+arguments to the @code{help} command.
+
+@cindex repeating commands
+@kindex RET
+A blank line as input to @value{GDBN} (typing just @key{RET}) means to
+repeat the previous command. Certain commands (for example, @code{run})
+will not repeat this way; these are commands for which unintentional
+repetition might cause trouble and which you are unlikely to want to
+repeat.
+
+The @code{list} and @code{x} commands, when you repeat them with
+@key{RET}, construct new arguments rather than repeating
+exactly as typed. This permits easy scanning of source or memory.
+
+@value{GDBN} can also use @key{RET} in another way: to partition lengthy
+output, in a way similar to the common utility @code{more}
+(@pxref{Screen Size,,Screen size}). Since it is easy to press one
+@key{RET} too many in this situation, @value{GDBN} disables command
+repetition after any command that generates this sort of display.
+
+@kindex #
+@cindex comment
+Any text from a @kbd{#} to the end of the line is a comment; it does
+nothing. This is useful mainly in command files (@pxref{Command
+Files,,Command files}).
+
+@node Completion
+@section Command completion
+
+@cindex completion
+@cindex word completion
+@value{GDBN} can fill in the rest of a word in a command for you, if there is
+only one possibility; it can also show you what the valid possibilities
+are for the next word in a command, at any time. This works for @value{GDBN}
+commands, @value{GDBN} subcommands, and the names of symbols in your program.
+
+Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest
+of a word. If there is only one possibility, @value{GDBN} will fill in the
+word, and wait for you to finish the command (or press @key{RET} to
+enter it). For example, if you type
+
+@c FIXME "@key" does not distinguish its argument sufficiently to permit
+@c complete accuracy in these examples; space introduced for clarity.
+@c If texinfo enhancements make it unnecessary, it would be nice to
+@c replace " @key" by "@key" in the following...
+@example
+(@value{GDBP}) info bre @key{TAB}
+@end example
+
+@noindent
+@value{GDBN} fills in the rest of the word @samp{breakpoints}, since that is
+the only @code{info} subcommand beginning with @samp{bre}:
+
+@example
+(@value{GDBP}) info breakpoints
+@end example
+
+@noindent
+You can either press @key{RET} at this point, to run the @code{info
+breakpoints} command, or backspace and enter something else, if
+@samp{breakpoints} does not look like the command you expected. (If you
+were sure you wanted @code{info breakpoints} in the first place, you
+might as well just type @key{RET} immediately after @samp{info bre},
+to exploit command abbreviations rather than command completion).
+
+If there is more than one possibility for the next word when you press
+@key{TAB}, @value{GDBN} will sound a bell. You can either supply more
+characters and try again, or just press @key{TAB} a second time, and
+@value{GDBN} will display all the possible completions for that word. For
+example, you might want to set a breakpoint on a subroutine whose name
+begins with @samp{make_}, but when you type @kbd{b make_@key{TAB}} @value{GDBN}
+just sounds the bell. Typing @key{TAB} again will display all the
+function names in your program that begin with those characters, for
+example:
+
+@example
+(@value{GDBP}) b make_ @key{TAB}
+@exdent @value{GDBN} sounds bell; press @key{TAB} again, to see:
+make_a_section_from_file make_environ
+make_abs_section make_function_type
+make_blockvector make_pointer_type
+make_cleanup make_reference_type
+make_command make_symbol_completion_list
+(@value{GDBP}) b make_
+@end example
+
+@noindent
+After displaying the available possibilities, @value{GDBN} copies your
+partial input (@samp{b make_} in the example) so you can finish the
+command.
+
+If you just want to see the list of alternatives in the first place, you
+can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?}
+means @kbd{@key{META} ?}. You can type this
+@ifclear DOSHOST
+either by holding down a
+key designated as the @key{META} shift on your keyboard (if there is
+one) while typing @kbd{?}, or
+@end ifclear
+as @key{ESC} followed by @kbd{?}.
+
+@cindex quotes in commands
+@cindex completion of quoted strings
+Sometimes the string you need, while logically a ``word'', may contain
+parentheses or other characters that @value{GDBN} normally excludes from its
+notion of a word. To permit word completion to work in this situation,
+you may enclose words in @code{'} (single quote marks) in @value{GDBN} commands.
+
+@ifclear CONLY
+The most likely situation where you might need this is in typing the
+name of a C++ function. This is because C++ allows function overloading
+(multiple definitions of the same function, distinguished by argument
+type). For example, when you want to set a breakpoint you may need to
+distinguish whether you mean the version of @code{name} that takes an
+@code{int} parameter, @code{name(int)}, or the version that takes a
+@code{float} parameter, @code{name(float)}. To use the word-completion
+facilities in this situation, type a single quote @code{'} at the
+beginning of the function name. This alerts @value{GDBN} that it may need to
+consider more information than usual when you press @key{TAB} or
+@kbd{M-?} to request word completion:
+
+@example
+(@value{GDBP}) b 'bubble( @key{M-?}
+bubble(double,double) bubble(int,int)
+(@value{GDBP}) b 'bubble(
+@end example
+
+In some cases, @value{GDBN} can tell that completing a name will require
+quotes. When this happens, @value{GDBN} will insert the quote for you (while
+completing as much as it can) if you do not type the quote in the first
+place:
+
+@example
+(@value{GDBP}) b bub @key{TAB}
+@exdent @value{GDBN} alters your input line to the following, and rings a bell:
+(@value{GDBP}) b 'bubble(
+@end example
+
+@noindent
+In general, @value{GDBN} can tell that a quote is needed (and inserts it) if
+you have not yet started typing the argument list when you ask for
+completion on an overloaded symbol.
+@end ifclear
+
+
+@node Help
+@section Getting help
+@cindex online documentation
+@kindex help
+
+You can always ask @value{GDBN} itself for information on its commands, using the
+command @code{help}.
+
+@table @code
+@item help
+@itemx h
+@kindex h
+You can use @code{help} (abbreviated @code{h}) with no arguments to
+display a short list of named classes of commands:
+
+@smallexample
+(@value{GDBP}) help
+List of classes of commands:
+
+running -- Running the program
+stack -- Examining the stack
+data -- Examining data
+breakpoints -- Making program stop at certain points
+files -- Specifying and examining files
+status -- Status inquiries
+support -- Support facilities
+user-defined -- User-defined commands
+aliases -- Aliases of other commands
+obscure -- Obscure features
+
+Type "help" followed by a class name for a list of
+commands in that class.
+Type "help" followed by command name for full
+documentation.
+Command name abbreviations are allowed if unambiguous.
+(@value{GDBP})
+@end smallexample
+
+@item help @var{class}
+Using one of the general help classes as an argument, you can get a
+list of the individual commands in that class. For example, here is the
+help display for the class @code{status}:
+
+@smallexample
+(@value{GDBP}) help status
+Status inquiries.
+
+List of commands:
+
+@c Line break in "show" line falsifies real output, but needed
+@c to fit in smallbook page size.
+show -- Generic command for showing things set
+ with "set"
+info -- Generic command for printing status
+
+Type "help" followed by command name for full
+documentation.
+Command name abbreviations are allowed if unambiguous.
+(@value{GDBP})
+@end smallexample
+
+@item help @var{command}
+With a command name as @code{help} argument, @value{GDBN} will display a
+short paragraph on how to use that command.
+@end table
+
+In addition to @code{help}, you can use the @value{GDBN} commands @code{info}
+and @code{show} to inquire about the state of your program, or the state
+of @value{GDBN} itself. Each command supports many topics of inquiry; this
+manual introduces each of them in the appropriate context. The listings
+under @code{info} and under @code{show} in the Index point to
+all the sub-commands. @xref{Index}.
+
+@c @group
+@table @code
+@item info
+@kindex info
+@kindex i
+This command (abbreviated @code{i}) is for describing the state of your
+program. For example, you can list the arguments given to your program
+with @code{info args}, list the registers currently in use with @code{info
+registers}, or list the breakpoints you have set with @code{info breakpoints}.
+You can get a complete list of the @code{info} sub-commands with
+@w{@code{help info}}.
+
+@kindex show
+@item show
+In contrast, @code{show} is for describing the state of @value{GDBN} itself.
+You can change most of the things you can @code{show}, by using the
+related command @code{set}; for example, you can control what number
+system is used for displays with @code{set radix}, or simply inquire
+which is currently in use with @code{show radix}.
+
+@kindex info set
+To display all the settable parameters and their current
+values, you can use @code{show} with no arguments; you may also use
+@code{info set}. Both commands produce the same display.
+@c FIXME: "info set" violates the rule that "info" is for state of
+@c FIXME...program. Ck w/ GNU: "info set" to be called something else,
+@c FIXME...or change desc of rule---eg "state of prog and debugging session"?
+@end table
+@c @end group
+
+Here are three miscellaneous @code{show} subcommands, all of which are
+exceptional in lacking corresponding @code{set} commands:
+
+@table @code
+@kindex show version
+@cindex version number
+@item show version
+Show what version of @value{GDBN} is running. You should include this
+information in @value{GDBN} bug-reports. If multiple versions of @value{GDBN} are in
+use at your site, you may occasionally want to determine which version
+of @value{GDBN} you are running; as @value{GDBN} evolves, new commands are introduced,
+and old ones may wither away. The version number is also announced
+when you start @value{GDBN}.
+
+@kindex show copying
+@item show copying
+Display information about permission for copying @value{GDBN}.
+
+@kindex show warranty
+@item show warranty
+Display the GNU ``NO WARRANTY'' statement.
+@end table
+
+@node Running
+@chapter Running Programs Under @value{GDBN}
+
+When you run a program under @value{GDBN}, you must first generate
+debugging information when you compile it.
+@ifclear BARETARGET
+You may start it with its arguments, if any, in an environment of your
+choice. You may redirect your program's input and output, debug an
+already running process, or kill a child process.
+@end ifclear
+
+@menu
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+@ifclear BARETARGET
+* Arguments:: Your program's arguments
+* Environment:: Your program's environment
+* Working Directory:: Your program's working directory
+* Input/Output:: Your program's input and output
+* Attach:: Debugging an already-running process
+* Kill Process:: Killing the child process
+* Process Information:: Additional process information
+@end ifclear
+@end menu
+
+@node Compilation
+@section Compiling for debugging
+
+In order to debug a program effectively, you need to generate
+debugging information when you compile it. This debugging information
+is stored in the object file; it describes the data type of each
+variable or function and the correspondence between source line numbers
+and addresses in the executable code.
+
+To request debugging information, specify the @samp{-g} option when you run
+the compiler.
+
+Many C compilers are unable to handle the @samp{-g} and @samp{-O}
+options together. Using those compilers, you cannot generate optimized
+executables containing debugging information.
+
+@value{NGCC}, the GNU C compiler, supports @samp{-g} with or without
+@samp{-O}, making it possible to debug optimized code. We recommend
+that you @emph{always} use @samp{-g} whenever you compile a program.
+You may think your program is correct, but there is no sense in pushing
+your luck.
+
+@cindex optimized code, debugging
+@cindex debugging optimized code
+When you debug a program compiled with @samp{-g -O}, remember that the
+optimizer is rearranging your code; the debugger will show you what is
+really there. Do not be too surprised when the execution path does not
+exactly match your source file! An extreme example: if you define a
+variable, but never use it, @value{GDBN} will never see that
+variable---because the compiler optimizes it out of existence.
+
+Some things do not work as well with @samp{-g -O} as with just
+@samp{-g}, particularly on machines with instruction scheduling. If in
+doubt, recompile with @samp{-g} alone, and if this fixes the problem,
+please report it as a bug (including a test case!).
+
+Older versions of the GNU C compiler permitted a variant option
+@w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this
+format; if your GNU C compiler has this option, do not use it.
+
+@need 2000
+@node Starting
+@section Starting your program
+@cindex starting
+@cindex running
+
+@table @code
+@item run
+@itemx r
+@kindex run
+Use the @code{run} command to start your program under @value{GDBN}. You must
+first specify the program name
+@ifset VXWORKS
+(except on VxWorks)
+@end ifset
+with an argument to @value{GDBN} (@pxref{Invocation, ,Getting In and
+Out of @value{GDBN}}), or by using the @code{file} or @code{exec-file}
+command (@pxref{Files, ,Commands to specify files}).
+
+@end table
+
+@ifclear BARETARGET
+If you are running your program in an execution environment that
+supports processes, @code{run} creates an inferior process and makes
+that process run your program. (In environments without processes,
+@code{run} jumps to the start of your program.)
+
+The execution of a program is affected by certain information it
+receives from its superior. @value{GDBN} provides ways to specify this
+information, which you must do @emph{before} starting your program. (You
+can change it after starting your program, but such changes will only affect
+your program the next time you start it.) This information may be
+divided into four categories:
+
+@table @asis
+@item The @emph{arguments.}
+Specify the arguments to give your program as the arguments of the
+@code{run} command. If a shell is available on your target, the shell
+is used to pass the arguments, so that you may use normal conventions
+(such as wildcard expansion or variable substitution) in describing
+the arguments. In Unix systems, you can control which shell is used
+with the @code{SHELL} environment variable. @xref{Arguments, ,Your
+program's arguments}.
+
+@item The @emph{environment.}
+Your program normally inherits its environment from @value{GDBN}, but you can
+use the @value{GDBN} commands @code{set environment} and @code{unset
+environment} to change parts of the environment that will be given to
+your program. @xref{Environment, ,Your program's environment}.
+
+@item The @emph{working directory.}
+Your program inherits its working directory from @value{GDBN}. You can set
+the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+@xref{Working Directory, ,Your program's working directory}.
+
+@item The @emph{standard input and output.}
+Your program normally uses the same device for standard input and
+standard output as @value{GDBN} is using. You can redirect input and output
+in the @code{run} command line, or you can use the @code{tty} command to
+set a different device for your program.
+@xref{Input/Output, ,Your program's input and output}.
+
+@cindex pipes
+@emph{Warning:} While input and output redirection work, you cannot use
+pipes to pass the output of the program you are debugging to another
+program; if you attempt this, @value{GDBN} is likely to wind up debugging the
+wrong program.
+@end table
+@end ifclear
+
+When you issue the @code{run} command, your program begins to execute
+immediately. @xref{Stopping, ,Stopping and continuing}, for discussion
+of how to arrange for your program to stop. Once your program has
+stopped, you may call functions in your program, using the @code{print}
+or @code{call} commands. @xref{Data, ,Examining Data}.
+
+If the modification time of your symbol file has changed since the
+last time @value{GDBN} read its symbols, @value{GDBN} will discard its symbol table and
+re-read it. When it does this, @value{GDBN} tries to retain your current
+breakpoints.
+
+@ifclear BARETARGET
+@node Arguments
+@section Your program's arguments
+
+@cindex arguments (to your program)
+The arguments to your program can be specified by the arguments of the
+@code{run} command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to your program.
+Your @code{SHELL} environment variable (if it exists) specifies what
+shell @value{GDBN} if you do not define @code{SHELL}, @value{GDBN} uses
+@code{/bin/sh}.
+
+@code{run} with no arguments uses the same arguments used by the previous
+@code{run}, or those set by the @code{set args} command.
+
+@kindex set args
+@table @code
+@item set args
+Specify the arguments to be used the next time your program is run. If
+@code{set args} has no arguments, @code{run} will execute your program
+with no arguments. Once you have run your program with arguments,
+using @code{set args} before the next @code{run} is the only way to run
+it again without arguments.
+
+@item show args
+@kindex show args
+Show the arguments to give your program when it is started.
+@end table
+
+@node Environment
+@section Your program's environment
+
+@cindex environment (of your program)
+The @dfn{environment} consists of a set of environment variables and
+their values. Environment variables conventionally record such things as
+your user name, your home directory, your terminal type, and your search
+path for programs to run. Usually you set up environment variables with
+the shell and they are inherited by all the other programs you run. When
+debugging, it can be useful to try running your program with a modified
+environment without having to start @value{GDBN} over again.
+
+@table @code
+@item path @var{directory}
+@kindex path
+Add @var{directory} to the front of the @code{PATH} environment variable
+(the search path for executables), for both @value{GDBN} and your program.
+You may specify several directory names, separated by @samp{:} or
+whitespace. If @var{directory} is already in the path, it is moved to
+the front, so it will be searched sooner.
+
+You can use the string @samp{$cwd} to refer to whatever is the current
+working directory at the time @value{GDBN} searches the path. If you
+use @samp{.} instead, it refers to the directory where you executed the
+@code{path} command. @value{GDBN} replaces @samp{.} in the
+@var{directory} argument (with the current path) before adding
+@var{directory} to the search path.
+@c 'path' is explicitly nonrepeatable, but RMS points out it is silly to
+@c document that, since repeating it would be a no-op.
+
+@item show paths
+@kindex show paths
+Display the list of search paths for executables (the @code{PATH}
+environment variable).
+
+@item show environment @r{[}@var{varname}@r{]}
+@kindex show environment
+Print the value of environment variable @var{varname} to be given to
+your program when it starts. If you do not supply @var{varname},
+print the names and values of all environment variables to be given to
+your program. You can abbreviate @code{environment} as @code{env}.
+
+@item set environment @var{varname} @r{[}=@r{]} @var{value}
+@kindex set environment
+Set environment variable @var{varname} to @var{value}. The value
+changes for your program only, not for @value{GDBN} itself. @var{value} may
+be any string; the values of environment variables are just strings, and
+any interpretation is supplied by your program itself. The @var{value}
+parameter is optional; if it is eliminated, the variable is set to a
+null value.
+@c "any string" here does not include leading, trailing
+@c blanks. Gnu asks: does anyone care?
+
+For example, this command:
+
+@example
+set env USER = foo
+@end example
+
+@noindent
+tells a Unix program, when subsequently run, that its user is named
+@samp{foo}. (The spaces around @samp{=} are used for clarity here; they
+are not actually required.)
+
+@item unset environment @var{varname}
+@kindex unset environment
+Remove variable @var{varname} from the environment to be passed to your
+program. This is different from @samp{set env @var{varname} =};
+@code{unset environment} removes the variable from the environment,
+rather than assigning it an empty value.
+@end table
+
+@emph{Warning:} @value{GDBN} runs your program using the shell indicated
+by your @code{SHELL} environment variable if it exists (or
+@code{/bin/sh} if not). If your @code{SHELL} variable names a shell
+that runs an initialization file---such as @file{.cshrc} for C-shell, or
+@file{.bashrc} for BASH---any variables you set in that file will affect
+your program. You may wish to move setting of environment variables to
+files that are only run when you sign on, such as @file{.login} or
+@file{.profile}.
+
+@node Working Directory
+@section Your program's working directory
+
+@cindex working directory (of your program)
+Each time you start your program with @code{run}, it inherits its
+working directory from the current working directory of @value{GDBN}.
+The @value{GDBN} working directory is initially whatever it inherited
+from its parent process (typically the shell), but you can specify a new
+working directory in @value{GDBN} with the @code{cd} command.
+
+The @value{GDBN} working directory also serves as a default for the commands
+that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
+specify files}.
+
+@table @code
+@item cd @var{directory}
+@kindex cd
+Set the @value{GDBN} working directory to @var{directory}.
+
+@item pwd
+@kindex pwd
+Print the @value{GDBN} working directory.
+@end table
+
+@node Input/Output
+@section Your program's input and output
+
+@cindex redirection
+@cindex i/o
+@cindex terminal
+By default, the program you run under @value{GDBN} does input and output to
+the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal to
+its own terminal modes to interact with you, but it records the terminal
+modes your program was using and switches back to them when you continue
+running your program.
+
+@table @code
+@item info terminal
+@kindex info terminal
+Displays information recorded by @value{GDBN} about the terminal modes your
+program is using.
+@end table
+
+You can redirect your program's input and/or output using shell
+redirection with the @code{run} command. For example,
+
+@example
+run > outfile
+@end example
+
+@noindent
+starts your program, diverting its output to the file @file{outfile}.
+
+@kindex tty
+@cindex controlling terminal
+Another way to specify where your program should do input and output is
+with the @code{tty} command. This command accepts a file name as
+argument, and causes this file to be the default for future @code{run}
+commands. It also resets the controlling terminal for the child
+process, for future @code{run} commands. For example,
+
+@example
+tty /dev/ttyb
+@end example
+
+@noindent
+directs that processes started with subsequent @code{run} commands
+default to do input and output on the terminal @file{/dev/ttyb} and have
+that as their controlling terminal.
+
+An explicit redirection in @code{run} overrides the @code{tty} command's
+effect on the input/output device, but not its effect on the controlling
+terminal.
+
+When you use the @code{tty} command or redirect input in the @code{run}
+command, only the input @emph{for your program} is affected. The input
+for @value{GDBN} still comes from your terminal.
+
+@node Attach
+@section Debugging an already-running process
+@kindex attach
+@cindex attach
+
+@table @code
+@item attach @var{process-id}
+This command attaches to a running process---one that was started
+outside @value{GDBN}. (@code{info files} will show your active
+targets.) The command takes as argument a process ID. The usual way to
+find out the process-id of a Unix process is with the @code{ps} utility,
+or with the @samp{jobs -l} shell command.
+
+@code{attach} will not repeat if you press @key{RET} a second time after
+executing the command.
+@end table
+
+To use @code{attach}, your program must be running in an environment
+which supports processes; for example, @code{attach} does not work for
+programs on bare-board targets that lack an operating system. You must
+also have permission to send the process a signal.
+
+When using @code{attach}, you should first use the @code{file} command
+to specify the program running in the process and load its symbol table.
+@xref{Files, ,Commands to Specify Files}.
+
+The first thing @value{GDBN} does after arranging to debug the specified
+process is to stop it. You can examine and modify an attached process
+with all the @value{GDBN} commands that are ordinarily available when you start
+processes with @code{run}. You can insert breakpoints; you can step and
+continue; you can modify storage. If you would rather the process
+continue running, you may use the @code{continue} command after
+attaching @value{GDBN} to the process.
+
+@table @code
+@item detach
+@kindex detach
+When you have finished debugging the attached process, you can use the
+@code{detach} command to release it from @value{GDBN} control. Detaching
+the process continues its execution. After the @code{detach} command,
+that process and @value{GDBN} become completely independent once more, and you
+are ready to @code{attach} another process or start one with @code{run}.
+@code{detach} will not repeat if you press @key{RET} again after
+executing the command.
+@end table
+
+If you exit @value{GDBN} or use the @code{run} command while you have an attached
+process, you kill that process. By default, you will be asked for
+confirmation if you try to do either of these things; you can control
+whether or not you need to confirm by using the @code{set confirm} command
+(@pxref{Messages/Warnings, ,Optional warnings and messages}).
+
+@node Kill Process
+@c @group
+@section Killing the child process
+
+@table @code
+@item kill
+@kindex kill
+Kill the child process in which your program is running under @value{GDBN}.
+@end table
+
+This command is useful if you wish to debug a core dump instead of a
+running process. @value{GDBN} ignores any core dump file while your program
+is running.
+@c @end group
+
+On some operating systems, a program cannot be executed outside @value{GDBN}
+while you have breakpoints set on it inside @value{GDBN}. You can use the
+@code{kill} command in this situation to permit running your program
+outside the debugger.
+
+The @code{kill} command is also useful if you wish to recompile and
+relink your program, since on many systems it is impossible to modify an
+executable file while it is running in a process. In this case, when you
+next type @code{run}, @value{GDBN} will notice that the file has changed, and
+will re-read the symbol table (while trying to preserve your current
+breakpoint settings).
+
+@node Process Information
+@section Additional process information
+
+@kindex /proc
+@cindex process image
+Some operating systems provide a facility called @samp{/proc} that can
+be used to examine the image of a running process using file-system
+subroutines. If @value{GDBN} is configured for an operating system with this
+facility, the command @code{info proc} is available to report on several
+kinds of information about the process running your program.
+
+@table @code
+@item info proc
+@kindex info proc
+Summarize available information about the process.
+
+@item info proc mappings
+@kindex info proc mappings
+Report on the address ranges accessible in the program, with information
+on whether your program may read, write, or execute each range.
+
+@item info proc times
+@kindex info proc times
+Starting time, user CPU time, and system CPU time for your program and
+its children.
+
+@item info proc id
+@kindex info proc id
+Report on the process IDs related to your program: its own process ID,
+the ID of its parent, the process group ID, and the session ID.
+
+@item info proc status
+@kindex info proc status
+General information on the state of the process. If the process is
+stopped, this report includes the reason for stopping, and any signal
+received.
+
+@item info proc all
+Show all the above information about the process.
+@end table
+@end ifclear
+
+@node Stopping
+@chapter Stopping and Continuing
+
+The principal purposes of using a debugger are so that you can stop your
+program before it terminates; or so that, if your program runs into
+trouble, you can investigate and find out why.
+
+Inside @value{GDBN}, your program may stop for any of several reasons, such
+as
+@ifclear BARETARGET
+a signal,
+@end ifclear
+a breakpoint, or reaching a new line after a @value{GDBN}
+command such as @code{step}. You may then examine and change
+variables, set new breakpoints or remove old ones, and then continue
+execution. Usually, the messages shown by @value{GDBN} provide ample
+explanation of the status of your program---but you can also explicitly
+request this information at any time.
+
+@table @code
+@item info program
+@kindex info program
+Display information about the status of your program: whether it is
+running or not,
+@ifclear BARETARGET
+what process it is,
+@end ifclear
+and why it stopped.
+@end table
+
+@menu
+@ifclear CONLY
+* Breakpoints:: Breakpoints, watchpoints, and exceptions
+@end ifclear
+@ifset CONLY
+* Breakpoints:: Breakpoints and watchpoints
+@end ifset
+@c Remnant makeinfo bug requires blank line after *successful* end-if in menu:
+
+* Continuing and Stepping:: Resuming execution
+@ifset POSIX
+* Signals:: Signals
+@end ifset
+@end menu
+
+@c makeinfo node-defaulting requires adjacency of @node and sectioning cmds
+@c ...hence distribute @node Breakpoints over two possible @if expansions.
+@c
+@ifclear CONLY
+@node Breakpoints
+@section Breakpoints, watchpoints, and exceptions
+@end ifclear
+@ifset CONLY
+@node Breakpoints
+@section Breakpoints and watchpoints
+@end ifset
+
+@cindex breakpoints
+A @dfn{breakpoint} makes your program stop whenever a certain point in
+the program is reached. For each breakpoint, you can add various
+conditions to control in finer detail whether your program will stop.
+You can set breakpoints with the @code{break} command and its variants
+(@pxref{Set Breaks, ,Setting breakpoints}), to specify the place where
+your program should stop by line number, function name or exact address
+in the program.
+@ifclear CONLY
+In languages with exception handling (such as GNU C++), you can also set
+breakpoints where an exception is raised (@pxref{Exception Handling,
+,Breakpoints and exceptions}).
+@end ifclear
+
+@cindex watchpoints
+@cindex memory tracing
+@cindex breakpoint on memory address
+@cindex breakpoint on variable modification
+A @dfn{watchpoint} is a special breakpoint that stops your program
+when the value of an expression changes. You must use a different
+command to set watchpoints (@pxref{Set Watchpoints, ,Setting
+watchpoints}), but aside from that, you can manage a watchpoint like
+any other breakpoint: you enable, disable, and delete both breakpoints
+and watchpoints using the same commands.
+
+You can arrange to have values from your program displayed automatically
+whenever @value{GDBN} stops at a breakpoint. @xref{Auto Display,
+,Automatic display}.
+
+@cindex breakpoint numbers
+@cindex numbers for breakpoints
+@value{GDBN} assigns a number to each breakpoint or watchpoint when you
+create it; these numbers are successive integers starting with one. In
+many of the commands for controlling various features of breakpoints you
+use the breakpoint number to say which breakpoint you want to change.
+Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has
+no effect on your program until you enable it again.
+
+@menu
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+@ifclear CONLY
+* Exception Handling:: Breakpoints and exceptions
+@end ifclear
+
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+@ifclear CONLY
+* Breakpoint Menus:: Breakpoint menus
+@end ifclear
+@ifclear BARETARGET
+* Error in Breakpoints:: ``Cannot insert breakpoints''
+@end ifclear
+@end menu
+
+@node Set Breaks
+@subsection Setting breakpoints
+
+@c FIXME LMB what does GDB do if no code on line of breakpt?
+@c consider in particular declaration with/without initialization.
+@c
+@c FIXME 2 is there stuff on this already? break at fun start, already init?
+
+@kindex break
+@kindex b
+@kindex $bpnum
+@cindex latest breakpoint
+Breakpoints are set with the @code{break} command (abbreviated
+@code{b}). The debugger convenience variable @samp{$bpnum} records the
+number of the beakpoint you've set most recently; see @ref{Convenience
+Vars,, Convenience variables}, for a discussion of what you can do with
+convenience variables.
+
+You have several ways to say where the breakpoint should go.
+
+@table @code
+@item break @var{function}
+Set a breakpoint at entry to function @var{function}.
+@ifclear CONLY
+When using source languages that permit overloading of symbols, such as
+C++, @var{function} may refer to more than one possible place to break.
+@xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation.
+@end ifclear
+
+@item break +@var{offset}
+@itemx break -@var{offset}
+Set a breakpoint some number of lines forward or back from the position
+at which execution stopped in the currently selected frame.
+
+@item break @var{linenum}
+Set a breakpoint at line @var{linenum} in the current source file.
+That file is the last file whose source text was printed. This
+breakpoint will stop your program just before it executes any of the
+code on that line.
+
+@item break @var{filename}:@var{linenum}
+Set a breakpoint at line @var{linenum} in source file @var{filename}.
+
+@item break @var{filename}:@var{function}
+Set a breakpoint at entry to function @var{function} found in file
+@var{filename}. Specifying a file name as well as a function name is
+superfluous except when multiple files contain similarly named
+functions.
+
+@item break *@var{address}
+Set a breakpoint at address @var{address}. You can use this to set
+breakpoints in parts of your program which do not have debugging
+information or source files.
+
+@item break
+When called without any arguments, @code{break} sets a breakpoint at
+the next instruction to be executed in the selected stack frame
+(@pxref{Stack, ,Examining the Stack}). In any selected frame but the
+innermost, this will cause your program to stop as soon as control
+returns to that frame. This is similar to the effect of a
+@code{finish} command in the frame inside the selected frame---except
+that @code{finish} does not leave an active breakpoint. If you use
+@code{break} without an argument in the innermost frame, @value{GDBN} will stop
+the next time it reaches the current location; this may be useful
+inside loops.
+
+@value{GDBN} normally ignores breakpoints when it resumes execution, until at
+least one instruction has been executed. If it did not do this, you
+would be unable to proceed past a breakpoint without first disabling the
+breakpoint. This rule applies whether or not the breakpoint already
+existed when your program stopped.
+
+@item break @dots{} if @var{cond}
+Set a breakpoint with condition @var{cond}; evaluate the expression
+@var{cond} each time the breakpoint is reached, and stop only if the
+value is nonzero---that is, if @var{cond} evaluates as true.
+@samp{@dots{}} stands for one of the possible arguments described
+above (or no argument) specifying where to break. @xref{Conditions,
+,Break conditions}, for more information on breakpoint conditions.
+
+@item tbreak @var{args}
+@kindex tbreak
+Set a breakpoint enabled only for one stop. @var{args} are the
+same as for the @code{break} command, and the breakpoint is set in the same
+way, but the breakpoint is automatically disabled after the first time your
+program stops there. @xref{Disabling, ,Disabling breakpoints}.
+
+@item rbreak @var{regex}
+@kindex rbreak
+@cindex regular expression
+@c FIXME what kind of regexp?
+Set breakpoints on all functions matching the regular expression
+@var{regex}. This command
+sets an unconditional breakpoint on all matches, printing a list of all
+breakpoints it set. Once these breakpoints are set, they are treated
+just like the breakpoints set with the @code{break} command. They can
+be deleted, disabled, made conditional, etc., in the standard ways.
+
+@ifclear CONLY
+When debugging C++ programs, @code{rbreak} is useful for setting
+breakpoints on overloaded functions that are not members of any special
+classes.
+@end ifclear
+
+@kindex info breakpoints
+@cindex @code{$_} and @code{info breakpoints}
+@item info breakpoints @r{[}@var{n}@r{]}
+@itemx info break @r{[}@var{n}@r{]}
+@itemx info watchpoints @r{[}@var{n}@r{]}
+Print a table of all breakpoints and watchpoints set and not
+deleted, with the following columns for each breakpoint:
+
+@table @emph
+@item Breakpoint Numbers
+@item Type
+Breakpoint or watchpoint.
+@item Disposition
+Whether the breakpoint is marked to be disabled or deleted when hit.
+@item Enabled or Disabled
+Enabled breakpoints are marked with @samp{y}. @samp{n} marks breakpoints
+that are not enabled.
+@item Address
+Where the breakpoint is in your program, as a memory address
+@item What
+Where the breakpoint is in the source for your program, as a file and
+line number.
+@end table
+
+@noindent
+If a breakpoint is conditional, @code{info break} shows the condition on
+the line following the affected breakpoint; breakpoint commands, if any,
+are listed after that.
+
+@noindent
+@code{info break} with a breakpoint
+number @var{n} as argument lists only that breakpoint. The
+convenience variable @code{$_} and the default examining-address for
+the @code{x} command are set to the address of the last breakpoint
+listed (@pxref{Memory, ,Examining memory}).
+@end table
+
+@value{GDBN} allows you to set any number of breakpoints at the same place in
+your program. There is nothing silly or meaningless about this. When
+the breakpoints are conditional, this is even useful
+(@pxref{Conditions, ,Break conditions}).
+
+@cindex negative breakpoint numbers
+@cindex internal @value{GDBN} breakpoints
+@value{GDBN} itself sometimes sets breakpoints in your program for special
+purposes, such as proper handling of @code{longjmp} (in C programs).
+These internal breakpoints are assigned negative numbers, starting with
+@code{-1}; @samp{info breakpoints} does not display them.
+
+You can see these breakpoints with the @value{GDBN} maintenance command
+@samp{maint info breakpoints}.
+
+@table @code
+@kindex maint info breakpoints
+@item maint info breakpoints
+Using the same format as @samp{info breakpoints}, display both the
+breakpoints you've set explicitly, and those @value{GDBN} is using for
+internal purposes. Internal breakpoints are shown with negative
+breakpoint numbers. The type column identifies what kind of breakpoint
+is shown:
+
+@table @code
+@item breakpoint
+Normal, explicitly set breakpoint.
+
+@item watchpoint
+Normal, explicitly set watchpoint.
+
+@item longjmp
+Internal breakpoint, used to handle correctly stepping through
+@code{longjmp} calls.
+
+@item longjmp resume
+Internal breakpoint at the target of a @code{longjmp}.
+
+@item until
+Temporary internal breakpoint used by the @value{GDBN} @code{until} command.
+
+@item finish
+Temporary internal breakpoint used by the @value{GDBN} @code{finish} command.
+@end table
+
+@end table
+
+
+@node Set Watchpoints
+@subsection Setting watchpoints
+@cindex setting watchpoints
+
+You can use a watchpoint to stop execution whenever the value of an
+expression changes, without having to predict a particular place
+where this may happen.
+
+Watchpoints currently execute two orders of magnitude more slowly than
+other breakpoints, but this can be well worth it to catch errors where
+you have no clue what part of your program is the culprit. Some
+processors provide special hardware to support watchpoint evaluation; future
+releases of @value{GDBN} will use such hardware if it is available.
+
+@table @code
+@kindex watch
+@item watch @var{expr}
+Set a watchpoint for an expression.
+
+@kindex info watchpoints
+@item info watchpoints
+This command prints a list of watchpoints and breakpoints; it is the
+same as @code{info break}.
+@end table
+
+@ifclear CONLY
+@node Exception Handling
+@subsection Breakpoints and exceptions
+@cindex exception handlers
+
+Some languages, such as GNU C++, implement exception handling. You can
+use @value{GDBN} to examine what caused your program to raise an exception,
+and to list the exceptions your program is prepared to handle at a
+given point in time.
+
+@table @code
+@item catch @var{exceptions}
+@kindex catch
+You can set breakpoints at active exception handlers by using the
+@code{catch} command. @var{exceptions} is a list of names of exceptions
+to catch.
+@end table
+
+You can use @code{info catch} to list active exception handlers.
+@xref{Frame Info, ,Information about a frame}.
+
+There are currently some limitations to exception handling in @value{GDBN}.
+These will be corrected in a future release.
+
+@itemize @bullet
+@item
+If you call a function interactively, @value{GDBN} normally returns
+control to you when the function has finished executing. If the call
+raises an exception, however, the call may bypass the mechanism that
+returns control to you and cause your program to simply continue
+running until it hits a breakpoint, catches a signal that @value{GDBN} is
+listening for, or exits.
+@item
+You cannot raise an exception interactively.
+@item
+You cannot interactively install an exception handler.
+@end itemize
+
+@cindex raise exceptions
+Sometimes @code{catch} is not the best way to debug exception handling:
+if you need to know exactly where an exception is raised, it is better to
+stop @emph{before} the exception handler is called, since that way you
+can see the stack before any unwinding takes place. If you set a
+breakpoint in an exception handler instead, it may not be easy to find
+out where the exception was raised.
+
+To stop just before an exception handler is called, you need some
+knowledge of the implementation. In the case of GNU C++, exceptions are
+raised by calling a library function named @code{__raise_exception}
+which has the following ANSI C interface:
+
+@example
+ /* @var{addr} is where the exception identifier is stored.
+ ID is the exception identifier. */
+ void __raise_exception (void **@var{addr}, void *@var{id});
+@end example
+
+@noindent
+To make the debugger catch all exceptions before any stack
+unwinding takes place, set a breakpoint on @code{__raise_exception}
+(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}).
+
+With a conditional breakpoint (@pxref{Conditions, ,Break conditions})
+that depends on the value of @var{id}, you can stop your program when
+a specific exception is raised. You can use multiple conditional
+breakpoints to stop your program when any of a number of exceptions are
+raised.
+@end ifclear
+
+@node Delete Breaks
+@subsection Deleting breakpoints
+
+@cindex clearing breakpoints, watchpoints
+@cindex deleting breakpoints, watchpoints
+It is often necessary to eliminate a breakpoint or watchpoint once it
+has done its job and you no longer want your program to stop there. This
+is called @dfn{deleting} the breakpoint. A breakpoint that has been
+deleted no longer exists; it is forgotten.
+
+With the @code{clear} command you can delete breakpoints according to
+where they are in your program. With the @code{delete} command you can
+delete individual breakpoints or watchpoints by specifying their
+breakpoint numbers.
+
+It is not necessary to delete a breakpoint to proceed past it. @value{GDBN}
+automatically ignores breakpoints on the first instruction to be executed
+when you continue execution without changing the execution address.
+
+@table @code
+@item clear
+@kindex clear
+Delete any breakpoints at the next instruction to be executed in the
+selected stack frame (@pxref{Selection, ,Selecting a frame}). When
+the innermost frame is selected, this is a good way to delete a
+breakpoint where your program just stopped.
+
+@item clear @var{function}
+@itemx clear @var{filename}:@var{function}
+Delete any breakpoints set at entry to the function @var{function}.
+
+@item clear @var{linenum}
+@itemx clear @var{filename}:@var{linenum}
+Delete any breakpoints set at or within the code of the specified line.
+
+@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@cindex delete breakpoints
+@kindex delete
+@kindex d
+Delete the breakpoints or watchpoints of the numbers specified as
+arguments. If no argument is specified, delete all breakpoints (@value{GDBN}
+asks confirmation, unless you have @code{set confirm off}). You
+can abbreviate this command as @code{d}.
+@end table
+
+@node Disabling
+@subsection Disabling breakpoints
+
+@cindex disabled breakpoints
+@cindex enabled breakpoints
+Rather than deleting a breakpoint or watchpoint, you might prefer to
+@dfn{disable} it. This makes the breakpoint inoperative as if it had
+been deleted, but remembers the information on the breakpoint so that
+you can @dfn{enable} it again later.
+
+You disable and enable breakpoints and watchpoints with the
+@code{enable} and @code{disable} commands, optionally specifying one or
+more breakpoint numbers as arguments. Use @code{info break} or
+@code{info watch} to print a list of breakpoints or watchpoints if you
+do not know which numbers to use.
+
+A breakpoint or watchpoint can have any of four different states of
+enablement:
+
+@itemize @bullet
+@item
+Enabled. The breakpoint will stop your program. A breakpoint set
+with the @code{break} command starts out in this state.
+@item
+Disabled. The breakpoint has no effect on your program.
+@item
+Enabled once. The breakpoint will stop your program, but
+when it does so it will become disabled. A breakpoint set
+with the @code{tbreak} command starts out in this state.
+@item
+Enabled for deletion. The breakpoint will stop your program, but
+immediately after it does so it will be deleted permanently.
+@end itemize
+
+You can use the following commands to enable or disable breakpoints and
+watchpoints:
+
+@table @code
+@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@kindex disable breakpoints
+@kindex disable
+@kindex dis
+Disable the specified breakpoints---or all breakpoints, if none are
+listed. A disabled breakpoint has no effect but is not forgotten. All
+options such as ignore-counts, conditions and commands are remembered in
+case the breakpoint is enabled again later. You may abbreviate
+@code{disable} as @code{dis}.
+
+@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@kindex enable breakpoints
+@kindex enable
+Enable the specified breakpoints (or all defined breakpoints). They
+become effective once again in stopping your program.
+
+@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{}
+Enable the specified breakpoints temporarily. Each will be disabled
+again the next time it stops your program.
+
+@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{}
+Enable the specified breakpoints to work once and then die. Each of
+the breakpoints will be deleted the next time it stops your program.
+@end table
+
+Save for a breakpoint set with @code{tbreak} (@pxref{Set Breaks,
+,Setting breakpoints}), breakpoints that you set are initially enabled;
+subsequently, they become disabled or enabled only when you use one of
+the commands above. (The command @code{until} can set and delete a
+breakpoint of its own, but it will not change the state of your other
+breakpoints; see @ref{Continuing and Stepping, ,Continuing and
+stepping}.)
+
+@node Conditions
+@subsection Break conditions
+@cindex conditional breakpoints
+@cindex breakpoint conditions
+
+@c FIXME what is scope of break condition expr? Context where wanted?
+@c in particular for a watchpoint?
+The simplest sort of breakpoint breaks every time your program reaches a
+specified place. You can also specify a @dfn{condition} for a
+breakpoint. A condition is just a Boolean expression in your
+programming language (@pxref{Expressions, ,Expressions}). A breakpoint with
+a condition evaluates the expression each time your program reaches it,
+and your program stops only if the condition is @emph{true}.
+
+This is the converse of using assertions for program validation; in that
+situation, you want to stop when the assertion is violated---that is,
+when the condition is false. In C, if you want to test an assertion expressed
+by the condition @var{assert}, you should set the condition
+@samp{! @var{assert}} on the appropriate breakpoint.
+
+Conditions are also accepted for watchpoints; you may not need them,
+since a watchpoint is inspecting the value of an expression anyhow---but
+it might be simpler, say, to just set a watchpoint on a variable name,
+and specify a condition that tests whether the new value is an interesting
+one.
+
+Break conditions can have side effects, and may even call functions in
+your program. This can be useful, for example, to activate functions
+that log program progress, or to use your own print functions to
+format special data structures. The effects are completely predictable
+unless there is another enabled breakpoint at the same address. (In
+that case, @value{GDBN} might see the other breakpoint first and stop your
+program without checking the condition of this one.) Note that
+breakpoint commands are usually more convenient and flexible for the
+purpose of performing side effects when a breakpoint is reached
+(@pxref{Break Commands, ,Breakpoint command lists}).
+
+Break conditions can be specified when a breakpoint is set, by using
+@samp{if} in the arguments to the @code{break} command. @xref{Set
+Breaks, ,Setting breakpoints}. They can also be changed at any time
+with the @code{condition} command. The @code{watch} command does not
+recognize the @code{if} keyword; @code{condition} is the only way to
+impose a further condition on a watchpoint.
+
+@table @code
+@item condition @var{bnum} @var{expression}
+@kindex condition
+Specify @var{expression} as the break condition for breakpoint or
+watchpoint number @var{bnum}. From now on, this breakpoint will stop
+your program only if the value of @var{expression} is true (nonzero, in
+C). When you use @code{condition}, @value{GDBN} checks @var{expression}
+immediately for syntactic correctness, and to determine whether symbols
+in it have referents in the context of your breakpoint.
+@c FIXME so what does GDB do if there is no referent? Moreover, what
+@c about watchpoints?
+@value{GDBN} does
+not actually evaluate @var{expression} at the time the @code{condition}
+command is given, however. @xref{Expressions, ,Expressions}.
+
+@item condition @var{bnum}
+Remove the condition from breakpoint number @var{bnum}. It becomes
+an ordinary unconditional breakpoint.
+@end table
+
+@cindex ignore count (of breakpoint)
+A special case of a breakpoint condition is to stop only when the
+breakpoint has been reached a certain number of times. This is so
+useful that there is a special way to do it, using the @dfn{ignore
+count} of the breakpoint. Every breakpoint has an ignore count, which
+is an integer. Most of the time, the ignore count is zero, and
+therefore has no effect. But if your program reaches a breakpoint whose
+ignore count is positive, then instead of stopping, it just decrements
+the ignore count by one and continues. As a result, if the ignore count
+value is @var{n}, the breakpoint will not stop the next @var{n} times it
+is reached.
+
+@table @code
+@item ignore @var{bnum} @var{count}
+@kindex ignore
+Set the ignore count of breakpoint number @var{bnum} to @var{count}.
+The next @var{count} times the breakpoint is reached, your program's
+execution will not stop; other than to decrement the ignore count, @value{GDBN}
+takes no action.
+
+To make the breakpoint stop the next time it is reached, specify
+a count of zero.
+
+When you use @code{continue} to resume execution of your program from a
+breakpoint, you can specify an ignore count directly as an argument to
+@code{continue}, rather than using @code{ignore}. @xref{Continuing and
+Stepping,,Continuing and stepping}.
+
+If a breakpoint has a positive ignore count and a condition, the condition
+is not checked. Once the ignore count reaches zero, the condition will
+be checked.
+
+You could achieve the effect of the ignore count with a condition such
+as @w{@samp{$foo-- <= 0}} using a debugger convenience variable that
+is decremented each time. @xref{Convenience Vars, ,Convenience
+variables}.
+@end table
+
+@node Break Commands
+@subsection Breakpoint command lists
+
+@cindex breakpoint commands
+You can give any breakpoint (or watchpoint) a series of commands to
+execute when your program stops due to that breakpoint. For example, you
+might want to print the values of certain expressions, or enable other
+breakpoints.
+
+@table @code
+@item commands @r{[}@var{bnum}@r{]}
+@itemx @dots{} @var{command-list} @dots{}
+@itemx end
+@kindex commands
+@kindex end
+Specify a list of commands for breakpoint number @var{bnum}. The commands
+themselves appear on the following lines. Type a line containing just
+@code{end} to terminate the commands.
+
+To remove all commands from a breakpoint, type @code{commands} and
+follow it immediately with @code{end}; that is, give no commands.
+
+With no @var{bnum} argument, @code{commands} refers to the last
+breakpoint or watchpoint set (not to the breakpoint most recently
+encountered).
+@end table
+
+Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
+disabled within a @var{command-list}.
+
+You can use breakpoint commands to start your program up again. Simply
+use the @code{continue} command, or @code{step}, or any other command
+that resumes execution.
+
+Any other commands in the command list, after a command that resumes
+execution, are ignored. This is because any time you resume execution
+(even with a simple @code{next} or @code{step}), you may encounter
+another breakpoint---which could have its own command list, leading to
+ambiguities about which list to execute.
+
+@kindex silent
+If the first command you specify in a command list is @code{silent}, the
+usual message about stopping at a breakpoint is not printed. This may
+be desirable for breakpoints that are to print a specific message and
+then continue. If none of the remaining commands print anything, you
+will see no sign that the breakpoint was reached. @code{silent} is
+meaningful only at the beginning of a breakpoint command list.
+
+The commands @code{echo}, @code{output}, and @code{printf} allow you to
+print precisely controlled output, and are often useful in silent
+breakpoints. @xref{Output, ,Commands for controlled output}.
+
+For example, here is how you could use breakpoint commands to print the
+value of @code{x} at entry to @code{foo} whenever @code{x} is positive.
+
+@example
+break foo if x>0
+commands
+silent
+printf "x is %d\n",x
+cont
+end
+@end example
+
+One application for breakpoint commands is to compensate for one bug so
+you can test for another. Put a breakpoint just after the erroneous line
+of code, give it a condition to detect the case in which something
+erroneous has been done, and give it commands to assign correct values
+to any variables that need them. End with the @code{continue} command
+so that your program does not stop, and start with the @code{silent}
+command so that no output is produced. Here is an example:
+
+@example
+break 403
+commands
+silent
+set x = y + 4
+cont
+end
+@end example
+
+@ifclear CONLY
+@node Breakpoint Menus
+@subsection Breakpoint menus
+@cindex overloading
+@cindex symbol overloading
+
+Some programming languages (notably C++) permit a single function name
+to be defined several times, for application in different contexts.
+This is called @dfn{overloading}. When a function name is overloaded,
+@samp{break @var{function}} is not enough to tell @value{GDBN} where you want
+a breakpoint. If you realize this will be a problem, you can use
+something like @samp{break @var{function}(@var{types})} to specify which
+particular version of the function you want. Otherwise, @value{GDBN} offers
+you a menu of numbered choices for different possible breakpoints, and
+waits for your selection with the prompt @samp{>}. The first two
+options are always @samp{[0] cancel} and @samp{[1] all}. Typing @kbd{1}
+sets a breakpoint at each definition of @var{function}, and typing
+@kbd{0} aborts the @code{break} command without setting any new
+breakpoints.
+
+For example, the following session excerpt shows an attempt to set a
+breakpoint at the overloaded symbol @code{String::after}.
+We choose three particular definitions of that function name:
+
+@c FIXME! This is likely to change to show arg type lists, at least
+@smallexample
+(@value{GDBP}) b String::after
+[0] cancel
+[1] all
+[2] file:String.cc; line number:867
+[3] file:String.cc; line number:860
+[4] file:String.cc; line number:875
+[5] file:String.cc; line number:853
+[6] file:String.cc; line number:846
+[7] file:String.cc; line number:735
+> 2 4 6
+Breakpoint 1 at 0xb26c: file String.cc, line 867.
+Breakpoint 2 at 0xb344: file String.cc, line 875.
+Breakpoint 3 at 0xafcc: file String.cc, line 846.
+Multiple breakpoints were set.
+Use the "delete" command to delete unwanted
+ breakpoints.
+(@value{GDBP})
+@end smallexample
+@end ifclear
+
+@ifclear BARETARGET
+@node Error in Breakpoints
+@subsection ``Cannot insert breakpoints''
+
+@c FIXME: "cannot insert breakpoints" error, v unclear.
+@c Q in pending mail to Gilmore. ---pesch@cygnus.com, 26mar91
+@c some light may be shed by looking at instances of
+@c ONE_PROCESS_WRITETEXT. But error message seems possible otherwise
+@c too. pesch, 20sep91
+Under some operating systems, breakpoints cannot be used in a program if
+any other process is running that program. In this situation,
+attempting to run or continue a program with a breakpoint causes @value{GDBN}
+to stop the other process.
+
+When this happens, you have three ways to proceed:
+
+@enumerate
+@item
+Remove or disable the breakpoints, then continue.
+
+@item
+Suspend @value{GDBN}, and copy the file containing your program to a new name.
+Resume @value{GDBN} and use the @code{exec-file} command to specify that @value{GDBN}
+should run your program under that name. Then start your program again.
+
+@c FIXME: RMS commented here "Show example". Maybe when someone
+@c explains the first FIXME: in this section...
+
+@item
+Relink your program so that the text segment is nonsharable, using the
+linker option @samp{-N}. The operating system limitation may not apply
+to nonsharable executables.
+@end enumerate
+@end ifclear
+
+@node Continuing and Stepping
+@section Continuing and stepping
+
+@cindex stepping
+@cindex continuing
+@cindex resuming execution
+@dfn{Continuing} means resuming program execution until your program
+completes normally. In contrast, @dfn{stepping} means executing just
+one more ``step'' of your program, where ``step'' may mean either one
+line of source code, or one machine instruction (depending on what
+particular command you use). Either when continuing
+or when stepping, your program may stop even sooner, due to
+@ifset BARETARGET
+a breakpoint.
+@end ifset
+@ifclear BARETARGET
+a breakpoint or a signal. (If due to a signal, you may want to use
+@code{handle}, or use @samp{signal 0} to resume execution.
+@xref{Signals, ,Signals}.)
+@end ifclear
+
+@table @code
+@item continue @r{[}@var{ignore-count}@r{]}
+@itemx c @r{[}@var{ignore-count}@r{]}
+@itemx fg @r{[}@var{ignore-count}@r{]}
+@kindex continue
+@kindex c
+@kindex fg
+Resume program execution, at the address where your program last stopped;
+any breakpoints set at that address are bypassed. The optional argument
+@var{ignore-count} allows you to specify a further number of times to
+ignore a breakpoint at this location; its effect is like that of
+@code{ignore} (@pxref{Conditions, ,Break conditions}).
+
+The argument @var{ignore-count} is meaningful only when your program
+stopped due to a breakpoint. At other times, the argument to
+@code{continue} is ignored.
+
+The synonyms @code{c} and @code{fg} are provided purely for convenience,
+and have exactly the same behavior as @code{continue}.
+@end table
+
+To resume execution at a different place, you can use @code{return}
+(@pxref{Returning, ,Returning from a function}) to go back to the
+calling function; or @code{jump} (@pxref{Jumping, ,Continuing at a
+different address}) to go to an arbitrary location in your program.
+
+A typical technique for using stepping is to set a breakpoint
+@ifclear CONLY
+(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions})
+@end ifclear
+@ifset CONLY
+(@pxref{Breakpoints, ,Breakpoints and watchpoints})
+@end ifset
+at the
+beginning of the function or the section of your program where a
+problem is believed to lie, run your program until it stops at that
+breakpoint, and then step through the suspect area, examining the
+variables that are interesting, until you see the problem happen.
+
+@table @code
+@item step
+@kindex step
+@kindex s
+Continue running your program until control reaches a different source
+line, then stop it and return control to @value{GDBN}. This command is
+abbreviated @code{s}.
+
+@quotation
+@emph{Warning:} If you use the @code{step} command while control is
+within a function that was compiled without debugging information,
+execution proceeds until control reaches a function that does have
+debugging information.
+@end quotation
+
+@item step @var{count}
+Continue running as in @code{step}, but do so @var{count} times. If a
+breakpoint is reached,
+@ifclear BARETARGET
+or a signal not related to stepping occurs before @var{count} steps,
+@end ifclear
+stepping stops right away.
+
+@item next @r{[}@var{count}@r{]}
+@kindex next
+@kindex n
+Continue to the next source line in the current (innermost) stack frame.
+Similar to @code{step}, but any function calls appearing within the line
+of code are executed without stopping. Execution stops when control
+reaches a different line of code at the stack level which was executing
+when the @code{next} command was given. This command is abbreviated
+@code{n}.
+
+An argument @var{count} is a repeat count, as for @code{step}.
+
+@code{next} within a function that lacks debugging information acts like
+@code{step}, but any function calls appearing within the code of the
+function are executed without stopping.
+
+@item finish
+@kindex finish
+Continue running until just after function in the selected stack frame
+returns. Print the returned value (if any).
+
+Contrast this with the @code{return} command (@pxref{Returning,
+,Returning from a function}).
+
+@item until
+@kindex until
+@itemx u
+@kindex u
+Continue running until a source line past the current line, in the
+current stack frame, is reached. This command is used to avoid single
+stepping through a loop more than once. It is like the @code{next}
+command, except that when @code{until} encounters a jump, it
+automatically continues execution until the program counter is greater
+than the address of the jump.
+
+This means that when you reach the end of a loop after single stepping
+though it, @code{until} will cause your program to continue execution
+until the loop is exited. In contrast, a @code{next} command at the end
+of a loop will simply step back to the beginning of the loop, which
+would force you to step through the next iteration.
+
+@code{until} always stops your program if it attempts to exit the current
+stack frame.
+
+@code{until} may produce somewhat counterintuitive results if the order
+of machine code does not match the order of the source lines. For
+example, in the following excerpt from a debugging session, the @code{f}
+(@code{frame}) command shows that execution is stopped at line
+@code{206}; yet when we use @code{until}, we get to line @code{195}:
+
+@example
+(@value{GDBP}) f
+#0 main (argc=4, argv=0xf7fffae8) at m4.c:206
+206 expand_input();
+(@value{GDBP}) until
+195 for ( ; argc > 0; NEXTARG) @{
+@end example
+
+This happened because, for execution efficiency, the compiler had
+generated code for the loop closure test at the end, rather than the
+start, of the loop---even though the test in a C @code{for}-loop is
+written before the body of the loop. The @code{until} command appeared
+to step back to the beginning of the loop when it advanced to this
+expression; however, it has not really gone to an earlier
+statement---not in terms of the actual machine code.
+
+@code{until} with no argument works by means of single
+instruction stepping, and hence is slower than @code{until} with an
+argument.
+
+@item until @var{location}
+@itemx u @var{location}
+Continue running your program until either the specified location is
+reached, or the current stack frame returns. @var{location} is any of
+the forms of argument acceptable to @code{break} (@pxref{Set Breaks,
+,Setting breakpoints}). This form of the command uses breakpoints,
+and hence is quicker than @code{until} without an argument.
+
+@item stepi
+@itemx si
+@kindex stepi
+@kindex si
+Execute one machine instruction, then stop and return to the debugger.
+
+It is often useful to do @samp{display/i $pc} when stepping by machine
+instructions. This will cause the next instruction to be executed to
+be displayed automatically at each stop. @xref{Auto Display,
+,Automatic display}.
+
+An argument is a repeat count, as in @code{step}.
+
+@need 750
+@item nexti
+@itemx ni
+@kindex nexti
+@kindex ni
+Execute one machine instruction, but if it is a function call,
+proceed until the function returns.
+
+An argument is a repeat count, as in @code{next}.
+@end table
+
+@ifset POSIX
+@node Signals
+@section Signals
+@cindex signals
+
+A signal is an asynchronous event that can happen in a program. The
+operating system defines the possible kinds of signals, and gives each
+kind a name and a number. For example, in Unix @code{SIGINT} is the
+signal a program gets when you type an interrupt (often @kbd{C-c});
+@code{SIGSEGV} is the signal a program gets from referencing a place in
+memory far away from all the areas in use; @code{SIGALRM} occurs when
+the alarm clock timer goes off (which happens only if your program has
+requested an alarm).
+
+@cindex fatal signals
+Some signals, including @code{SIGALRM}, are a normal part of the
+functioning of your program. Others, such as @code{SIGSEGV}, indicate
+errors; these signals are @dfn{fatal} (kill your program immediately) if the
+program has not specified in advance some other way to handle the signal.
+@code{SIGINT} does not indicate an error in your program, but it is normally
+fatal so it can carry out the purpose of the interrupt: to kill the program.
+
+@value{GDBN} has the ability to detect any occurrence of a signal in your
+program. You can tell @value{GDBN} in advance what to do for each kind of
+signal.
+
+@cindex handling signals
+Normally, @value{GDBN} is set up to ignore non-erroneous signals like @code{SIGALRM}
+(so as not to interfere with their role in the functioning of your program)
+but to stop your program immediately whenever an error signal happens.
+You can change these settings with the @code{handle} command.
+
+@table @code
+@item info signals
+@kindex info signals
+Print a table of all the kinds of signals and how @value{GDBN} has been told to
+handle each one. You can use this to see the signal numbers of all
+the defined types of signals.
+
+@item handle @var{signal} @var{keywords}@dots{}
+@kindex handle
+Change the way @value{GDBN} handles signal @var{signal}. @var{signal} can be the
+number of a signal or its name (with or without the @samp{SIG} at the
+beginning). The @var{keywords} say what change to make.
+@end table
+
+@c @group
+The keywords allowed by the @code{handle} command can be abbreviated.
+Their full names are:
+
+@table @code
+@item nostop
+@value{GDBN} should not stop your program when this signal happens. It may
+still print a message telling you that the signal has come in.
+
+@item stop
+@value{GDBN} should stop your program when this signal happens. This implies
+the @code{print} keyword as well.
+
+@item print
+@value{GDBN} should print a message when this signal happens.
+
+@item noprint
+@value{GDBN} should not mention the occurrence of the signal at all. This
+implies the @code{nostop} keyword as well.
+
+@item pass
+@value{GDBN} should allow your program to see this signal; your program will be
+able to handle the signal, or may be terminated if the signal is fatal
+and not handled.
+
+@item nopass
+@value{GDBN} should not allow your program to see this signal.
+@end table
+@c @end group
+
+When a signal stops your program, the signal is not visible until you
+continue. Your program will see the signal then, if @code{pass} is in
+effect for the signal in question @emph{at that time}. In other words,
+after @value{GDBN} reports a signal, you can use the @code{handle}
+command with @code{pass} or @code{nopass} to control whether that
+signal will be seen by your program when you later continue it.
+
+You can also use the @code{signal} command to prevent your program from
+seeing a signal, or cause it to see a signal it normally would not see,
+or to give it any signal at any time. For example, if your program stopped
+due to some sort of memory reference error, you might store correct
+values into the erroneous variables and continue, hoping to see more
+execution; but your program would probably terminate immediately as
+a result of the fatal signal once it saw the signal. To prevent this,
+you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your
+program a signal}.
+@end ifset
+
+@node Stack
+@chapter Examining the Stack
+
+When your program has stopped, the first thing you need to know is where it
+stopped and how it got there.
+
+@cindex call stack
+Each time your program performs a function call, the information about
+where in your program the call was made from is saved in a block of data
+called a @dfn{stack frame}. The frame also contains the arguments of the
+call and the local variables of the function that was called. All the
+stack frames are allocated in a region of memory called the @dfn{call
+stack}.
+
+When your program stops, the @value{GDBN} commands for examining the
+stack allow you to see all of this information.
+
+@cindex selected frame
+One of the stack frames is @dfn{selected} by @value{GDBN} and many
+@value{GDBN} commands refer implicitly to the selected frame. In
+particular, whenever you ask @value{GDBN} for the value of a variable in
+your program, the value is found in the selected frame. There are
+special @value{GDBN} commands to select whichever frame you are
+interested in.
+
+When your program stops, @value{GDBN} automatically selects the
+currently executing frame and describes it briefly as the @code{frame}
+command does (@pxref{Frame Info, ,Information about a frame}).
+
+@menu
+* Frames:: Stack frames
+* Backtrace:: Backtraces
+* Selection:: Selecting a frame
+* Frame Info:: Information on a frame
+@ifset MIPS
+* MIPS Stack:: MIPS machines and the function stack
+@end ifset
+@end menu
+
+@node Frames
+@section Stack frames
+
+@cindex frame
+@cindex stack frame
+The call stack is divided up into contiguous pieces called @dfn{stack
+frames}, or @dfn{frames} for short; each frame is the data associated
+with one call to one function. The frame contains the arguments given
+to the function, the function's local variables, and the address at
+which the function is executing.
+
+@cindex initial frame
+@cindex outermost frame
+@cindex innermost frame
+When your program is started, the stack has only one frame, that of the
+function @code{main}. This is called the @dfn{initial} frame or the
+@dfn{outermost} frame. Each time a function is called, a new frame is
+made. Each time a function returns, the frame for that function invocation
+is eliminated. If a function is recursive, there can be many frames for
+the same function. The frame for the function in which execution is
+actually occurring is called the @dfn{innermost} frame. This is the most
+recently created of all the stack frames that still exist.
+
+@cindex frame pointer
+Inside your program, stack frames are identified by their addresses. A
+stack frame consists of many bytes, each of which has its own address; each
+kind of computer has a convention for choosing one of those bytes whose
+address serves as the address of the frame. Usually this address is kept
+in a register called the @dfn{frame pointer register} while execution is
+going on in that frame.
+
+@cindex frame number
+@value{GDBN} assigns numbers to all existing stack frames, starting with
+zero for the innermost frame, one for the frame that called it,
+and so on upward. These numbers do not really exist in your program;
+they are assigned by @value{GDBN} to give you a way of designating stack
+frames in @value{GDBN} commands.
+
+@c below produces an acceptable overful hbox. --mew 13aug1993
+@cindex frameless execution
+Some compilers provide a way to compile functions so that they operate
+without stack frames. (For example, the @code{@value{GCC}} option
+@samp{-fomit-frame-pointer} will generate functions without a frame.)
+This is occasionally done with heavily used library functions to save
+the frame setup time. @value{GDBN} has limited facilities for dealing
+with these function invocations. If the innermost function invocation
+has no stack frame, @value{GDBN} will nevertheless regard it as though
+it had a separate frame, which is numbered zero as usual, allowing
+correct tracing of the function call chain. However, @value{GDBN} has
+no provision for frameless functions elsewhere in the stack.
+
+@node Backtrace
+@section Backtraces
+
+A backtrace is a summary of how your program got where it is. It shows one
+line per frame, for many frames, starting with the currently executing
+frame (frame zero), followed by its caller (frame one), and on up the
+stack.
+
+@table @code
+@item backtrace
+@itemx bt
+@kindex backtrace
+@kindex bt
+Print a backtrace of the entire stack: one line per frame for all
+frames in the stack.
+
+You can stop the backtrace at any time by typing the system interrupt
+character, normally @kbd{C-c}.
+
+@item backtrace @var{n}
+@itemx bt @var{n}
+Similar, but print only the innermost @var{n} frames.
+
+@item backtrace -@var{n}
+@itemx bt -@var{n}
+Similar, but print only the outermost @var{n} frames.
+@end table
+
+@kindex where
+@kindex info stack
+@kindex info s
+The names @code{where} and @code{info stack} (abbreviated @code{info s})
+are additional aliases for @code{backtrace}.
+
+Each line in the backtrace shows the frame number and the function name.
+The program counter value is also shown---unless you use @code{set
+print address off}. The backtrace also shows the source file name and
+line number, as well as the arguments to the function. The program
+counter value is omitted if it is at the beginning of the code for that
+line number.
+
+Here is an example of a backtrace. It was made with the command
+@samp{bt 3}, so it shows the innermost three frames.
+
+@smallexample
+@group
+#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8)
+ at builtin.c:993
+#1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242
+#2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08)
+ at macro.c:71
+(More stack frames follow...)
+@end group
+@end smallexample
+
+@noindent
+The display for frame zero does not begin with a program counter
+value, indicating that your program has stopped at the beginning of the
+code for line @code{993} of @code{builtin.c}.
+
+@node Selection
+@section Selecting a frame
+
+Most commands for examining the stack and other data in your program work on
+whichever stack frame is selected at the moment. Here are the commands for
+selecting a stack frame; all of them finish by printing a brief description
+of the stack frame just selected.
+
+@table @code
+@item frame @var{n}
+@itemx f @var{n}
+@kindex frame
+@kindex f
+Select frame number @var{n}. Recall that frame zero is the innermost
+(currently executing) frame, frame one is the frame that called the
+innermost one, and so on. The highest-numbered frame is the one for
+@code{main}.
+
+@item frame @var{addr}
+@itemx f @var{addr}
+Select the frame at address @var{addr}. This is useful mainly if the
+chaining of stack frames has been damaged by a bug, making it
+impossible for @value{GDBN} to assign numbers properly to all frames. In
+addition, this can be useful when your program has multiple stacks and
+switches between them.
+
+@ifset SPARC
+On the SPARC architecture, @code{frame} needs two addresses to
+select an arbitrary frame: a frame pointer and a stack pointer.
+@c note to future updaters: this is conditioned on a flag
+@c FRAME_SPECIFICATION_DYADIC in the tm-*.h files, currently only used
+@c by SPARC, hence the specific attribution. Generalize or list all
+@c possibilities if more supported machines start doing this.
+@end ifset
+
+@item up @var{n}
+@kindex up
+Move @var{n} frames up the stack. For positive numbers @var{n}, this
+advances toward the outermost frame, to higher frame numbers, to frames
+that have existed longer. @var{n} defaults to one.
+
+@item down @var{n}
+@kindex down
+@kindex do
+Move @var{n} frames down the stack. For positive numbers @var{n}, this
+advances toward the innermost frame, to lower frame numbers, to frames
+that were created more recently. @var{n} defaults to one. You may
+abbreviate @code{down} as @code{do}.
+@end table
+
+All of these commands end by printing two lines of output describing the
+frame. The first line shows the frame number, the function name, the
+arguments, and the source file and line number of execution in that
+frame. The second line shows the text of that source line.
+
+For example:
+@smallexample
+@group
+(@value{GDBP}) up
+#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
+ at env.c:10
+10 read_input_file (argv[i]);
+@end group
+@end smallexample
+
+After such a printout, the @code{list} command with no arguments will
+print ten lines centered on the point of execution in the frame.
+@xref{List, ,Printing source lines}.
+
+@table @code
+@item up-silently @var{n}
+@itemx down-silently @var{n}
+@kindex down-silently
+@kindex up-silently
+These two commands are variants of @code{up} and @code{down},
+respectively; they differ in that they do their work silently, without
+causing display of the new frame. They are intended primarily for use
+in @value{GDBN} command scripts, where the output might be unnecessary and
+distracting.
+@end table
+
+@node Frame Info
+@section Information about a frame
+
+There are several other commands to print information about the selected
+stack frame.
+
+@table @code
+@item frame
+@itemx f
+When used without any argument, this command does not change which
+frame is selected, but prints a brief description of the currently
+selected stack frame. It can be abbreviated @code{f}. With an
+argument, this command is used to select a stack frame.
+@xref{Selection, ,Selecting a frame}.
+
+@item info frame
+@itemx info f
+@kindex info frame
+@kindex info f
+This command prints a verbose description of the selected stack frame,
+including the address of the frame, the addresses of the next frame down
+(called by this frame) and the next frame up (caller of this frame), the
+language that the source code corresponding to this frame was written in,
+the address of the frame's arguments, the program counter saved in it
+(the address of execution in the caller frame), and which registers
+were saved in the frame. The verbose description is useful when
+something has gone wrong that has made the stack format fail to fit
+the usual conventions.
+
+@item info frame @var{addr}
+@itemx info f @var{addr}
+Print a verbose description of the frame at address @var{addr},
+without selecting that frame. The selected frame remains unchanged by
+this command.
+
+@item info args
+@kindex info args
+Print the arguments of the selected frame, each on a separate line.
+
+@item info locals
+@kindex info locals
+Print the local variables of the selected frame, each on a separate
+line. These are all variables (declared either static or automatic)
+accessible at the point of execution of the selected frame.
+
+@ifclear CONLY
+@item info catch
+@kindex info catch
+@cindex catch exceptions
+@cindex exception handlers
+Print a list of all the exception handlers that are active in the
+current stack frame at the current point of execution. To see other
+exception handlers, visit the associated frame (using the @code{up},
+@code{down}, or @code{frame} commands); then type @code{info catch}.
+@xref{Exception Handling, ,Breakpoints and exceptions}.
+@end ifclear
+@end table
+
+@ifset MIPS
+@node MIPS Stack
+@section MIPS machines and the function stack
+
+@cindex stack on MIPS
+@cindex MIPS stack
+MIPS based computers use an unusual stack frame, which sometimes
+requires @value{GDBN} to search backward in the object code to find the
+beginning of a function.
+
+@cindex response time, MIPS debugging
+To improve response time (especially for embedded applications, where
+@value{GDBN} may be restricted to a slow serial line for this search)
+you may want to limit the size of this search, using one of these
+commands:
+@c FIXME! So what happens when GDB does *not* find the beginning of a
+@c function?
+
+@cindex @code{heuristic-fence-post} (MIPS)
+@table @code
+@item set heuristic-fence-post @var{limit}
+Restrict @var{GDBN} to examining at most @var{limit} bytes in its search
+for the beginning of a function. A value of @code{0} (the default)
+means there is no limit.
+
+@item show heuristic-fence-post
+Display the current limit.
+@end table
+
+@noindent
+These commands are available @emph{only} when @value{GDBN} is configured
+for debugging programs on MIPS processors.
+@end ifset
+
+@node Source
+@chapter Examining Source Files
+
+@value{GDBN} can print parts of your program's source, since the debugging
+information recorded in the program tells @value{GDBN} what source files were
+used to build it. When your program stops, @value{GDBN} spontaneously prints
+the line where it stopped. Likewise, when you select a stack frame
+(@pxref{Selection, ,Selecting a frame}), @value{GDBN} prints the line where
+execution in that frame has stopped. You can print other portions of
+source files by explicit command.
+
+@ifclear DOSHOST
+If you use @value{GDBN} through its GNU Emacs interface, you may prefer to use
+Emacs facilities to view source; @pxref{Emacs, ,Using @value{GDBN} under GNU
+Emacs}.
+@end ifclear
+
+@menu
+* List:: Printing source lines
+@ifclear DOSHOST
+* Search:: Searching source files
+@end ifclear
+
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+@end menu
+
+@node List
+@section Printing source lines
+
+@kindex list
+@kindex l
+To print lines from a source file, use the @code{list} command
+(abbreviated @code{l}). There are several ways to specify what part
+of the file you want to print.
+
+Here are the forms of the @code{list} command most commonly used:
+
+@table @code
+@item list @var{linenum}
+Print lines centered around line number @var{linenum} in the
+current source file.
+
+@item list @var{function}
+Print lines centered around the beginning of function
+@var{function}.
+
+@item list
+Print more lines. If the last lines printed were printed with a
+@code{list} command, this prints lines following the last lines
+printed; however, if the last line printed was a solitary line printed
+as part of displaying a stack frame (@pxref{Stack, ,Examining the
+Stack}), this prints lines centered around that line.
+
+@item list -
+Print lines just before the lines last printed.
+@end table
+
+By default, @value{GDBN} prints ten source lines with any of these forms of
+the @code{list} command. You can change this using @code{set listsize}:
+
+@table @code
+@item set listsize @var{count}
+@kindex set listsize
+Make the @code{list} command display @var{count} source lines (unless
+the @code{list} argument explicitly specifies some other number).
+
+@item show listsize
+@kindex show listsize
+Display the number of lines that @code{list} will currently display by
+default.
+@end table
+
+Repeating a @code{list} command with @key{RET} discards the argument,
+so it is equivalent to typing just @code{list}. This is more useful
+than listing the same lines again. An exception is made for an
+argument of @samp{-}; that argument is preserved in repetition so that
+each repetition moves up in the source file.
+
+@cindex linespec
+In general, the @code{list} command expects you to supply zero, one or two
+@dfn{linespecs}. Linespecs specify source lines; there are several ways
+of writing them but the effect is always to specify some source line.
+Here is a complete description of the possible arguments for @code{list}:
+
+@table @code
+@item list @var{linespec}
+Print lines centered around the line specified by @var{linespec}.
+
+@item list @var{first},@var{last}
+Print lines from @var{first} to @var{last}. Both arguments are
+linespecs.
+
+@item list ,@var{last}
+Print lines ending with @var{last}.
+
+@item list @var{first},
+Print lines starting with @var{first}.
+
+@item list +
+Print lines just after the lines last printed.
+
+@item list -
+Print lines just before the lines last printed.
+
+@item list
+As described in the preceding table.
+@end table
+
+Here are the ways of specifying a single source line---all the
+kinds of linespec.
+
+@table @code
+@item @var{number}
+Specifies line @var{number} of the current source file.
+When a @code{list} command has two linespecs, this refers to
+the same source file as the first linespec.
+
+@item +@var{offset}
+Specifies the line @var{offset} lines after the last line printed.
+When used as the second linespec in a @code{list} command that has
+two, this specifies the line @var{offset} lines down from the
+first linespec.
+
+@item -@var{offset}
+Specifies the line @var{offset} lines before the last line printed.
+
+@item @var{filename}:@var{number}
+Specifies line @var{number} in the source file @var{filename}.
+
+@item @var{function}
+@c FIXME: "of the open-brace" is C-centric. When we add other langs...
+Specifies the line of the open-brace that begins the body of the
+function @var{function}.
+
+@item @var{filename}:@var{function}
+Specifies the line of the open-brace that begins the body of the
+function @var{function} in the file @var{filename}. You only need the
+file name with a function name to avoid ambiguity when there are
+identically named functions in different source files.
+
+@item *@var{address}
+Specifies the line containing the program address @var{address}.
+@var{address} may be any expression.
+@end table
+
+@ifclear DOSHOST
+@node Search
+@section Searching source files
+@cindex searching
+@kindex reverse-search
+
+There are two commands for searching through the current source file for a
+regular expression.
+
+@table @code
+@item forward-search @var{regexp}
+@itemx search @var{regexp}
+@kindex search
+@kindex forward-search
+The command @samp{forward-search @var{regexp}} checks each line,
+starting with the one following the last line listed, for a match for
+@var{regexp}. It lists the line that is found. You can use
+synonym @samp{search @var{regexp}} or abbreviate the command name as
+@code{fo}.
+
+@item reverse-search @var{regexp}
+The command @samp{reverse-search @var{regexp}} checks each line, starting
+with the one before the last line listed and going backward, for a match
+for @var{regexp}. It lists the line that is found. You can abbreviate
+this command as @code{rev}.
+@end table
+@end ifclear
+
+@node Source Path
+@section Specifying source directories
+
+@cindex source path
+@cindex directories for source files
+Executable programs sometimes do not record the directories of the source
+files from which they were compiled, just the names. Even when they do,
+the directories could be moved between the compilation and your debugging
+session. @value{GDBN} has a list of directories to search for source files;
+this is called the @dfn{source path}. Each time @value{GDBN} wants a source file,
+it tries all the directories in the list, in the order they are present
+in the list, until it finds a file with the desired name. Note that
+the executable search path is @emph{not} used for this purpose. Neither is
+the current working directory, unless it happens to be in the source
+path.
+
+If @value{GDBN} cannot find a source file in the source path, and the object
+program records a directory, @value{GDBN} tries that directory too. If the
+source path is empty, and there is no record of the compilation
+directory, @value{GDBN} will, as a last resort, look in the current
+directory.
+
+Whenever you reset or rearrange the source path, @value{GDBN} will clear out
+any information it has cached about where source files are found, where
+each line is in the file, etc.
+
+@kindex directory
+When you start @value{GDBN}, its source path is empty.
+To add other directories, use the @code{directory} command.
+
+@table @code
+@item directory @var{dirname} @dots{}
+Add directory @var{dirname} to the front of the source path. Several
+directory names may be given to this command, separated by @samp{:} or
+whitespace. You may specify a directory that is already in the source
+path; this moves it forward, so it will be searched sooner.
+
+@kindex cdir
+@kindex cwd
+@kindex $cdir
+@kindex $cwd
+@cindex compilation directory
+@cindex current directory
+@cindex working directory
+@cindex directory, current
+@cindex directory, compilation
+You can use the string @samp{$cdir} to refer to the compilation
+directory (if one is recorded), and @samp{$cwd} to refer to the current
+working directory. @samp{$cwd} is not the same as @samp{.}---the former
+tracks the current working directory as it changes during your @value{GDBN}
+session, while the latter is immediately expanded to the current
+directory at the time you add an entry to the source path.
+
+@item directory
+Reset the source path to empty again. This requires confirmation.
+
+@c RET-repeat for @code{directory} is explicitly disabled, but since
+@c repeating it would be a no-op we do not say that. (thanks to RMS)
+
+@item show directories
+@kindex show directories
+Print the source path: show which directories it contains.
+@end table
+
+If your source path is cluttered with directories that are no longer of
+interest, @value{GDBN} may sometimes cause confusion by finding the wrong
+versions of source. You can correct the situation as follows:
+
+@enumerate
+@item
+Use @code{directory} with no argument to reset the source path to empty.
+
+@item
+Use @code{directory} with suitable arguments to reinstall the
+directories you want in the source path. You can add all the
+directories in one command.
+@end enumerate
+
+@node Machine Code
+@section Source and machine code
+
+You can use the command @code{info line} to map source lines to program
+addresses (and vice versa), and the command @code{disassemble} to display
+a range of addresses as machine instructions.
+
+@table @code
+@item info line @var{linespec}
+@kindex info line
+Print the starting and ending addresses of the compiled code for
+source line @var{linespec}. You can specify source lines in any of
+the ways understood by the @code{list} command (@pxref{List, ,Printing
+source lines}).
+@end table
+
+For example, we can use @code{info line} to discover the location of
+the object code for the first line of function
+@code{m4_changequote}:
+
+@smallexample
+(@value{GDBP}) info line m4_changecom
+Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
+@end smallexample
+
+@noindent
+We can also inquire (using @code{*@var{addr}} as the form for
+@var{linespec}) what source line covers a particular address:
+@smallexample
+(@value{GDBP}) info line *0x63ff
+Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
+@end smallexample
+
+@cindex @code{$_} and @code{info line}
+After @code{info line}, the default address for the @code{x} command
+is changed to the starting address of the line, so that @samp{x/i} is
+sufficient to begin examining the machine code (@pxref{Memory,
+,Examining memory}). Also, this address is saved as the value of the
+convenience variable @code{$_} (@pxref{Convenience Vars, ,Convenience
+variables}).
+
+@table @code
+@kindex disassemble
+@item disassemble
+@cindex assembly instructions
+@cindex instructions, assembly
+@cindex machine instructions
+@cindex listing machine instructions
+This specialized command dumps a range of memory as machine
+instructions. The default memory range is the function surrounding the
+program counter of the selected frame. A single argument to this
+command is a program counter value; the function surrounding this value
+will be dumped. Two arguments specify a range of addresses (first
+inclusive, second exclusive) to dump.
+@end table
+
+@ifclear H8EXCLUSIVE
+We can use @code{disassemble} to inspect the object code
+range shown in the last @code{info line} example (the example
+shows SPARC machine instructions):
+
+
+@smallexample
+(@value{GDBP}) disas 0x63e4 0x6404
+Dump of assembler code from 0x63e4 to 0x6404:
+0x63e4 <builtin_init+5340>: ble 0x63f8 <builtin_init+5360>
+0x63e8 <builtin_init+5344>: sethi %hi(0x4c00), %o0
+0x63ec <builtin_init+5348>: ld [%i1+4], %o0
+0x63f0 <builtin_init+5352>: b 0x63fc <builtin_init+5364>
+0x63f4 <builtin_init+5356>: ld [%o0+4], %o0
+0x63f8 <builtin_init+5360>: or %o0, 0x1a4, %o0
+0x63fc <builtin_init+5364>: call 0x9288 <path_search>
+0x6400 <builtin_init+5368>: nop
+End of assembler dump.
+@end smallexample
+@end ifclear
+
+@ifset H8EXCLUSIVE
+For example, here is the beginning of the output for the
+disassembly of a function @code{fact}:
+
+
+@smallexample
+(@value{GDBP}) disas fact
+Dump of assembler code for function fact:
+to 0x808c:
+0x802c <fact>: 6d f2 mov.w r2,@@-r7
+0x802e <fact+2>: 6d f3 mov.w r3,@@-r7
+0x8030 <fact+4>: 6d f6 mov.w r6,@@-r7
+0x8032 <fact+6>: 0d 76 mov.w r7,r6
+0x8034 <fact+8>: 6f 70 00 08 mov.w @@(0x8,r7),r0
+0x8038 <fact+12> 19 11 sub.w r1,r1
+ .
+ .
+ .
+@end smallexample
+@end ifset
+
+@node Data
+@chapter Examining Data
+
+@cindex printing data
+@cindex examining data
+@kindex print
+@kindex inspect
+@c "inspect" is not quite a synonym if you are using Epoch, which we do not
+@c document because it is nonstandard... Under Epoch it displays in a
+@c different window or something like that.
+The usual way to examine data in your program is with the @code{print}
+command (abbreviated @code{p}), or its synonym @code{inspect}.
+@ifclear CONLY
+It evaluates and prints the value of an expression of the language your
+program is written in (@pxref{Languages, ,Using @value{GDBN} with Different
+Languages}).
+@end ifclear
+
+@table @code
+@item print @var{exp}
+@itemx print /@var{f} @var{exp}
+@var{exp} is an expression (in the source language). By default the
+value of @var{exp} is printed in a format appropriate to its data type;
+you can choose a different format by specifying @samp{/@var{f}}, where
+@var{f} is a letter specifying the format; @pxref{Output Formats,,Output
+formats}.
+
+@item print
+@itemx print /@var{f}
+If you omit @var{exp}, @value{GDBN} displays the last value again (from the
+@dfn{value history}; @pxref{Value History, ,Value history}). This allows you to
+conveniently inspect the same value in an alternative format.
+@end table
+
+A more low-level way of examining data is with the @code{x} command.
+It examines data in memory at a specified address and prints it in a
+specified format. @xref{Memory, ,Examining memory}.
+
+If you are interested in information about types, or about how the fields
+of a struct
+@ifclear CONLY
+or class
+@end ifclear
+are declared, use the @code{ptype @var{exp}}
+command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}.
+
+@menu
+* Expressions:: Expressions
+* Variables:: Program variables
+* Arrays:: Artificial arrays
+* Output Formats:: Output formats
+* Memory:: Examining memory
+* Auto Display:: Automatic display
+* Print Settings:: Print settings
+* Value History:: Value history
+* Convenience Vars:: Convenience variables
+* Registers:: Registers
+@ifclear HAVE-FLOAT
+* Floating Point Hardware:: Floating point hardware
+@end ifclear
+@end menu
+
+@node Expressions
+@section Expressions
+
+@cindex expressions
+@code{print} and many other @value{GDBN} commands accept an expression and
+compute its value. Any kind of constant, variable or operator defined
+by the programming language you are using is valid in an expression in
+@value{GDBN}. This includes conditional expressions, function calls, casts
+and string constants. It unfortunately does not include symbols defined
+by preprocessor @code{#define} commands.
+
+@ifclear CONLY
+Because C is so widespread, most of the expressions shown in examples in
+this manual are in C. @xref{Languages, , Using @value{GDBN} with Different
+Languages}, for information on how to use expressions in other
+languages.
+
+In this section, we discuss operators that you can use in @value{GDBN}
+expressions regardless of your programming language.
+
+Casts are supported in all languages, not just in C, because it is so
+useful to cast a number into a pointer so as to examine a structure
+at that address in memory.
+@c FIXME: casts supported---Mod2 true?
+@end ifclear
+
+@value{GDBN} supports these operators in addition to those of programming
+languages:
+
+@table @code
+@item @@
+@samp{@@} is a binary operator for treating parts of memory as arrays.
+@xref{Arrays, ,Artificial arrays}, for more information.
+
+@item ::
+@samp{::} allows you to specify a variable in terms of the file or
+function where it is defined. @xref{Variables, ,Program variables}.
+
+@item @{@var{type}@} @var{addr}
+@cindex @{@var{type}@}
+@cindex type casting memory
+@cindex memory, viewing as typed object
+@cindex casts, to view memory
+Refers to an object of type @var{type} stored at address @var{addr} in
+memory. @var{addr} may be any expression whose value is an integer or
+pointer (but parentheses are required around binary operators, just as in
+a cast). This construct is allowed regardless of what kind of data is
+normally supposed to reside at @var{addr}.
+@end table
+
+@node Variables
+@section Program variables
+
+The most common kind of expression to use is the name of a variable
+in your program.
+
+Variables in expressions are understood in the selected stack frame
+(@pxref{Selection, ,Selecting a frame}); they must either be global
+(or static) or be visible according to the scope rules of the
+programming language from the point of execution in that frame. This
+means that in the function
+
+@example
+foo (a)
+ int a;
+@{
+ bar (a);
+ @{
+ int b = test ();
+ bar (b);
+ @}
+@}
+@end example
+
+@noindent
+you can examine and use the variable @code{a} whenever your program is
+executing within the function @code{foo}, but you can only use or
+examine the variable @code{b} while your program is executing inside
+the block where @code{b} is declared.
+
+@cindex variable name conflict
+There is an exception: you can refer to a variable or function whose
+scope is a single source file even if the current execution point is not
+in this file. But it is possible to have more than one such variable or
+function with the same name (in different source files). If that
+happens, referring to that name has unpredictable effects. If you wish,
+you can specify a static variable in a particular function or file,
+using the colon-colon notation:
+
+@cindex colon-colon
+@iftex
+@c info cannot cope with a :: index entry, but why deprive hard copy readers?
+@kindex ::
+@end iftex
+@example
+@var{file}::@var{variable}
+@var{function}::@var{variable}
+@end example
+
+@noindent
+Here @var{file} or @var{function} is the name of the context for the
+static @var{variable}. In the case of file names, you can use quotes to
+make sure @value{GDBN} parses the file name as a single word---for example,
+to print a global value of @code{x} defined in @file{f2.c}:
+
+@example
+(@value{GDBP}) p 'f2.c'::x
+@end example
+
+@ifclear CONLY
+@cindex C++ scope resolution
+This use of @samp{::} is very rarely in conflict with the very similar
+use of the same notation in C++. @value{GDBN} also supports use of the C++
+scope resolution operator in @value{GDBN} expressions.
+@c FIXME: Um, so what happens in one of those rare cases where it's in
+@c conflict?? --mew
+@end ifclear
+
+@cindex wrong values
+@cindex variable values, wrong
+@quotation
+@emph{Warning:} Occasionally, a local variable may appear to have the
+wrong value at certain points in a function---just after entry to a new
+scope, and just before exit.
+@end quotation
+You may see this problem when you are stepping by machine instructions.
+This is because on most machines, it takes more than one instruction to
+set up a stack frame (including local variable definitions); if you are
+stepping by machine instructions, variables may appear to have the wrong
+values until the stack frame is completely built. On exit, it usually
+also takes more than one machine instruction to destroy a stack frame;
+after you begin stepping through that group of instructions, local
+variable definitions may be gone.
+
+@node Arrays
+@section Artificial arrays
+
+@cindex artificial array
+@kindex @@
+It is often useful to print out several successive objects of the
+same type in memory; a section of an array, or an array of
+dynamically determined size for which only a pointer exists in the
+program.
+
+You can do this by referring to a contiguous span of memory as an
+@dfn{artificial array}, using the binary operator @samp{@@}. The left
+operand of @samp{@@} should be the first element of the desired array,
+as an individual object. The right operand should be the desired length
+of the array. The result is an array value whose elements are all of
+the type of the left argument. The first element is actually the left
+argument; the second element comes from bytes of memory immediately
+following those that hold the first element, and so on. Here is an
+example. If a program says
+
+@example
+int *array = (int *) malloc (len * sizeof (int));
+@end example
+
+@noindent
+you can print the contents of @code{array} with
+
+@example
+p *array@@len
+@end example
+
+The left operand of @samp{@@} must reside in memory. Array values made
+with @samp{@@} in this way behave just like other arrays in terms of
+subscripting, and are coerced to pointers when used in expressions.
+Artificial arrays most often appear in expressions via the value history
+(@pxref{Value History, ,Value history}), after printing one out.
+
+Sometimes the artificial array mechanism is not quite enough; in
+moderately complex data structures, the elements of interest may not
+actually be adjacent---for example, if you are interested in the values
+of pointers in an array. One useful work-around in this situation is
+to use a convenience variable (@pxref{Convenience Vars, ,Convenience
+variables}) as a counter in an expression that prints the first
+interesting value, and then repeat that expression via @key{RET}. For
+instance, suppose you have an array @code{dtab} of pointers to
+structures, and you are interested in the values of a field @code{fv}
+in each structure. Here is an example of what you might type:
+
+@example
+set $i = 0
+p dtab[$i++]->fv
+@key{RET}
+@key{RET}
+@dots{}
+@end example
+
+@node Output Formats
+@section Output formats
+
+@cindex formatted output
+@cindex output formats
+By default, @value{GDBN} prints a value according to its data type. Sometimes
+this is not what you want. For example, you might want to print a number
+in hex, or a pointer in decimal. Or you might want to view data in memory
+at a certain address as a character string or as an instruction. To do
+these things, specify an @dfn{output format} when you print a value.
+
+The simplest use of output formats is to say how to print a value
+already computed. This is done by starting the arguments of the
+@code{print} command with a slash and a format letter. The format
+letters supported are:
+
+@table @code
+@item x
+Regard the bits of the value as an integer, and print the integer in
+hexadecimal.
+
+@item d
+Print as integer in signed decimal.
+
+@item u
+Print as integer in unsigned decimal.
+
+@item o
+Print as integer in octal.
+
+@item t
+Print as integer in binary. The letter @samp{t} stands for ``two''.
+@footnote{@samp{b} cannot be used because these format letters are also
+used with the @code{x} command, where @samp{b} stands for ``byte'';
+@pxref{Memory,,Examining memory}.}
+
+@item a
+Print as an address, both absolute in hex and as an offset from the
+nearest preceding symbol. This format can be used to discover where (in
+what function) an unknown address is located:
+
+@example
+(@value{GDBP}) p/a 0x54320
+$3 = 0x54320 <_initialize_vx+396>
+@end example
+
+@item c
+Regard as an integer and print it as a character constant.
+
+@item f
+Regard the bits of the value as a floating point number and print
+using typical floating point syntax.
+@end table
+
+For example, to print the program counter in hex (@pxref{Registers}), type
+
+@example
+p/x $pc
+@end example
+
+@noindent
+Note that no space is required before the slash; this is because command
+names in @value{GDBN} cannot contain a slash.
+
+To reprint the last value in the value history with a different format,
+you can use the @code{print} command with just a format and no
+expression. For example, @samp{p/x} reprints the last value in hex.
+
+@node Memory
+@section Examining memory
+
+You can use the command @code{x} (for ``examine'') to examine memory in
+any of several formats, independently of your program's data types.
+
+@cindex examining memory
+@table @code
+@kindex x
+@item x/@var{nfu} @var{addr}
+@itemx x @var{addr}
+@itemx x
+Use the @code{x} command to examine memory.
+@end table
+
+@var{n}, @var{f}, and @var{u} are all optional parameters that specify how
+much memory to display and how to format it; @var{addr} is an
+expression giving the address where you want to start displaying memory.
+If you use defaults for @var{nfu}, you need not type the slash @samp{/}.
+Several commands set convenient defaults for @var{addr}.
+
+@table @r
+@item @var{n}, the repeat count
+The repeat count is a decimal integer; the default is 1. It specifies
+how much memory (counting by units @var{u}) to display.
+@c This really is **decimal**; unaffected by 'set radix' as of GDB
+@c 4.1.2.
+
+@item @var{f}, the display format
+The display format is one of the formats used by @code{print},
+or @samp{s} (null-terminated string) or @samp{i} (machine instruction).
+The default is @samp{x} (hexadecimal) initially, or the format from the
+last time you used either @code{x} or @code{print}.
+
+@item @var{u}, the unit size
+The unit size is any of
+
+@table @code
+@item b
+Bytes.
+@item h
+Halfwords (two bytes).
+@item w
+Words (four bytes). This is the initial default.
+@item g
+Giant words (eight bytes).
+@end table
+
+Each time you specify a unit size with @code{x}, that size becomes the
+default unit the next time you use @code{x}. (For the @samp{s} and
+@samp{i} formats, the unit size is ignored and is normally not written.)
+
+@item @var{addr}, starting display address
+@var{addr} is the address where you want @value{GDBN} to begin displaying
+memory. The expression need not have a pointer value (though it may);
+it is always interpreted as an integer address of a byte of memory.
+@xref{Expressions, ,Expressions}, for more information on expressions. The default for
+@var{addr} is usually just after the last address examined---but several
+other commands also set the default address: @code{info breakpoints} (to
+the address of the last breakpoint listed), @code{info line} (to the
+starting address of a line), and @code{print} (if you use it to display
+a value from memory).
+@end table
+
+For example, @samp{x/3uh 0x54320} is a request to display three halfwords
+(@code{h}) of memory, formatted as unsigned decimal integers (@samp{u}),
+starting at address @code{0x54320}. @samp{x/4xw $sp} prints the four
+words (@samp{w}) of memory above the stack pointer (here, @samp{$sp};
+@pxref{Registers}) in hexadecimal (@samp{x}).
+
+Since the letters indicating unit sizes are all distinct from the
+letters specifying output formats, you do not have to remember whether
+unit size or format comes first; either order will work. The output
+specifications @samp{4xw} and @samp{4wx} mean exactly the same thing.
+(However, the count @var{n} must come first; @samp{wx4} will not work.)
+
+Even though the unit size @var{u} is ignored for the formats @samp{s}
+and @samp{i}, you might still want to use a count @var{n}; for example,
+@samp{3i} specifies that you want to see three machine instructions,
+including any operands. The command @code{disassemble} gives an
+alternative way of inspecting machine instructions; @pxref{Machine
+Code,,Source and machine code}.
+
+All the defaults for the arguments to @code{x} are designed to make it
+easy to continue scanning memory with minimal specifications each time
+you use @code{x}. For example, after you have inspected three machine
+instructions with @samp{x/3i @var{addr}}, you can inspect the next seven
+with just @samp{x/7}. If you use @key{RET} to repeat the @code{x} command,
+the repeat count @var{n} is used again; the other arguments default as
+for successive uses of @code{x}.
+
+@cindex @code{$_}, @code{$__}, and value history
+The addresses and contents printed by the @code{x} command are not saved
+in the value history because there is often too much of them and they
+would get in the way. Instead, @value{GDBN} makes these values available for
+subsequent use in expressions as values of the convenience variables
+@code{$_} and @code{$__}. After an @code{x} command, the last address
+examined is available for use in expressions in the convenience variable
+@code{$_}. The contents of that address, as examined, are available in
+the convenience variable @code{$__}.
+
+If the @code{x} command has a repeat count, the address and contents saved
+are from the last memory unit printed; this is not the same as the last
+address printed if several units were printed on the last line of output.
+
+@node Auto Display
+@section Automatic display
+@cindex automatic display
+@cindex display of expressions
+
+If you find that you want to print the value of an expression frequently
+(to see how it changes), you might want to add it to the @dfn{automatic
+display list} so that @value{GDBN} will print its value each time your program stops.
+Each expression added to the list is given a number to identify it;
+to remove an expression from the list, you specify that number.
+The automatic display looks like this:
+
+@example
+2: foo = 38
+3: bar[5] = (struct hack *) 0x3804
+@end example
+
+@noindent
+This display shows item numbers, expressions and their current values. As with
+displays you request manually using @code{x} or @code{print}, you can
+specify the output format you prefer; in fact, @code{display} decides
+whether to use @code{print} or @code{x} depending on how elaborate your
+format specification is---it uses @code{x} if you specify a unit size,
+or one of the two formats (@samp{i} and @samp{s}) that are only
+supported by @code{x}; otherwise it uses @code{print}.
+
+@table @code
+@item display @var{exp}
+@kindex display
+Add the expression @var{exp} to the list of expressions to display
+each time your program stops. @xref{Expressions, ,Expressions}.
+
+@code{display} will not repeat if you press @key{RET} again after using it.
+
+@item display/@var{fmt} @var{exp}
+For @var{fmt} specifying only a display format and not a size or
+count, add the expression @var{exp} to the auto-display list but
+arrange to display it each time in the specified format @var{fmt}.
+@xref{Output Formats,,Output formats}.
+
+@item display/@var{fmt} @var{addr}
+For @var{fmt} @samp{i} or @samp{s}, or including a unit-size or a
+number of units, add the expression @var{addr} as a memory address to
+be examined each time your program stops. Examining means in effect
+doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory, ,Examining memory}.
+@end table
+
+For example, @samp{display/i $pc} can be helpful, to see the machine
+instruction about to be executed each time execution stops (@samp{$pc}
+is a common name for the program counter; @pxref{Registers}).
+
+@table @code
+@item undisplay @var{dnums}@dots{}
+@itemx delete display @var{dnums}@dots{}
+@kindex delete display
+@kindex undisplay
+Remove item numbers @var{dnums} from the list of expressions to display.
+
+@code{undisplay} will not repeat if you press @key{RET} after using it.
+(Otherwise you would just get the error @samp{No display number @dots{}}.)
+
+@item disable display @var{dnums}@dots{}
+@kindex disable display
+Disable the display of item numbers @var{dnums}. A disabled display
+item is not printed automatically, but is not forgotten. It may be
+enabled again later.
+
+@item enable display @var{dnums}@dots{}
+@kindex enable display
+Enable display of item numbers @var{dnums}. It becomes effective once
+again in auto display of its expression, until you specify otherwise.
+
+@item display
+Display the current values of the expressions on the list, just as is
+done when your program stops.
+
+@item info display
+@kindex info display
+Print the list of expressions previously set up to display
+automatically, each one with its item number, but without showing the
+values. This includes disabled expressions, which are marked as such.
+It also includes expressions which would not be displayed right now
+because they refer to automatic variables not currently available.
+@end table
+
+If a display expression refers to local variables, then it does not make
+sense outside the lexical context for which it was set up. Such an
+expression is disabled when execution enters a context where one of its
+variables is not defined. For example, if you give the command
+@code{display last_char} while inside a function with an argument
+@code{last_char}, then this argument will be displayed while your program
+continues to stop inside that function. When it stops elsewhere---where
+there is no variable @code{last_char}---display is disabled. The next time
+your program stops where @code{last_char} is meaningful, you can enable the
+display expression once again.
+
+@node Print Settings
+@section Print settings
+
+@cindex format options
+@cindex print settings
+@value{GDBN} provides the following ways to control how arrays, structures,
+and symbols are printed.
+
+@noindent
+These settings are useful for debugging programs in any language:
+
+@table @code
+@item set print address
+@itemx set print address on
+@kindex set print address
+@value{GDBN} will print memory addresses showing the location of stack
+traces, structure values, pointer values, breakpoints, and so forth,
+even when it also displays the contents of those addresses. The default
+is on. For example, this is what a stack frame display looks like, with
+@code{set print address on}:
+
+@smallexample
+@group
+(@value{GDBP}) f
+#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
+ at input.c:530
+530 if (lquote != def_lquote)
+@end group
+@end smallexample
+
+@item set print address off
+Do not print addresses when displaying their contents. For example,
+this is the same stack frame displayed with @code{set print address off}:
+
+@smallexample
+@group
+(@value{GDBP}) set print addr off
+(@value{GDBP}) f
+#0 set_quotes (lq="<<", rq=">>") at input.c:530
+530 if (lquote != def_lquote)
+@end group
+@end smallexample
+
+You can use @samp{set print address off} to eliminate all machine
+dependent displays from the @value{GDBN} interface. For example, with
+@code{print address off}, you should get the same text for backtraces on
+all machines---whether or not they involve pointer arguments.
+
+@item show print address
+@kindex show print address
+Show whether or not addresses are to be printed.
+@end table
+
+When @value{GDBN} prints a symbolic address, it normally prints the
+closest earlier symbol plus an offset. If that symbol does not uniquely
+identify the address (for example, it is a name whose scope is a single
+source file), you may need to disambiguate. One way to do this is with
+@code{info line}, for example @code{info line *0x4537}. Alternately,
+you can set @value{GDBN} to print the source file and line number when
+it prints a symbolic address:
+
+@table @code
+@item set print symbol-filename on
+@kindex set print symbol-filename
+Tell @value{GDBN} to print the source file name and line number of a
+symbol in the symbolic form of an address.
+
+@item set print symbol-filename off
+Do not print source file name and line number of a symbol. This is the
+default.
+
+@item show print symbol-filename
+@kindex show print symbol-filename
+Show whether or not @value{GDBN} will print the source file name and
+line number of a symbol in the symbolic form of an address.
+@end table
+
+Also, you may wish to see the symbolic form only if the address being
+printed is reasonably close to the closest earlier symbol:
+
+@table @code
+@item set print max-symbolic-offset @var{max-offset}
+@kindex set print max-symbolic-offset
+Tell @value{GDBN} to only display the symbolic form of an address if the
+offset between the closest earlier symbol and the address is less than
+@var{max-offset}. The default is 0, which means to always print the
+symbolic form of an address, if any symbol precedes it.
+
+@item show print max-symbolic-offset
+@kindex show print max-symbolic-offset
+Ask how large the maximum offset is that @value{GDBN} will print in a
+symbolic address.
+@end table
+
+@table @code
+@item set print array
+@itemx set print array on
+@kindex set print array
+@value{GDBN} will pretty-print arrays. This format is more convenient to read,
+but uses more space. The default is off.
+
+@item set print array off
+Return to compressed format for arrays.
+
+@item show print array
+@kindex show print array
+Show whether compressed or pretty format is selected for displaying
+arrays.
+
+@item set print elements @var{number-of-elements}
+@kindex set print elements
+If @value{GDBN} is printing a large array, it will stop printing after it has
+printed the number of elements set by the @code{set print elements} command.
+This limit also applies to the display of strings.
+Setting the number of elements to zero means that the printing is unlimited.
+
+@item show print elements
+@kindex show print elements
+Display the number of elements of a large array that @value{GDBN} will print
+before losing patience.
+
+@item set print pretty on
+@kindex set print pretty
+Cause @value{GDBN} to print structures in an indented format with one member per
+line, like this:
+
+@smallexample
+@group
+$1 = @{
+ next = 0x0,
+ flags = @{
+ sweet = 1,
+ sour = 1
+ @},
+ meat = 0x54 "Pork"
+@}
+@end group
+@end smallexample
+
+@item set print pretty off
+Cause @value{GDBN} to print structures in a compact format, like this:
+
+@smallexample
+@group
+$1 = @{next = 0x0, flags = @{sweet = 1, sour = 1@}, \
+meat = 0x54 "Pork"@}
+@end group
+@end smallexample
+
+@noindent
+This is the default format.
+
+@item show print pretty
+@kindex show print pretty
+Show which format @value{GDBN} will use to print structures.
+
+@item set print sevenbit-strings on
+@kindex set print sevenbit-strings
+Print using only seven-bit characters; if this option is set,
+@value{GDBN} will display any eight-bit characters (in strings or character
+values) using the notation @code{\}@var{nnn}. For example, @kbd{M-a} is
+displayed as @code{\341}.
+
+@item set print sevenbit-strings off
+Print using either seven-bit or eight-bit characters, as required. This
+is the default.
+
+@item show print sevenbit-strings
+@kindex show print sevenbit-strings
+Show whether or not @value{GDBN} will print only seven-bit characters.
+
+@item set print union on
+@kindex set print union
+Tell @value{GDBN} to print unions which are contained in structures. This is the
+default setting.
+
+@item set print union off
+Tell @value{GDBN} not to print unions which are contained in structures.
+
+@item show print union
+@kindex show print union
+Ask @value{GDBN} whether or not it will print unions which are contained in
+structures.
+
+For example, given the declarations
+
+@smallexample
+typedef enum @{Tree, Bug@} Species;
+typedef enum @{Big_tree, Acorn, Seedling@} Tree_forms;
+typedef enum @{Caterpillar, Cocoon, Butterfly@}
+ Bug_forms;
+
+struct thing @{
+ Species it;
+ union @{
+ Tree_forms tree;
+ Bug_forms bug;
+ @} form;
+@};
+
+struct thing foo = @{Tree, @{Acorn@}@};
+@end smallexample
+
+@noindent
+with @code{set print union on} in effect @samp{p foo} would print
+
+@smallexample
+$1 = @{it = Tree, form = @{tree = Acorn, bug = Cocoon@}@}
+@end smallexample
+
+@noindent
+and with @code{set print union off} in effect it would print
+
+@smallexample
+$1 = @{it = Tree, form = @{...@}@}
+@end smallexample
+@end table
+
+@ifclear CONLY
+@need 1000
+@noindent
+These settings are of interest when debugging C++ programs:
+
+@table @code
+@item set print demangle
+@itemx set print demangle on
+@kindex set print demangle
+Print C++ names in their source form rather than in the encoded
+(``mangled'') form passed to the assembler and linker for type-safe
+linkage. The default is @samp{on}.
+
+@item show print demangle
+@kindex show print demangle
+Show whether C++ names will be printed in mangled or demangled form.
+
+@item set print asm-demangle
+@itemx set print asm-demangle on
+@kindex set print asm-demangle
+Print C++ names in their source form rather than their mangled form, even
+in assembler code printouts such as instruction disassemblies.
+The default is off.
+
+@item show print asm-demangle
+@kindex show print asm-demangle
+Show whether C++ names in assembly listings will be printed in mangled
+or demangled form.
+
+@item set demangle-style @var{style}
+@kindex set demangle-style
+@cindex C++ symbol decoding style
+@cindex symbol decoding style, C++
+Choose among several encoding schemes used by different compilers to
+represent C++ names. The choices for @var{style} are currently:
+
+@table @code
+@item auto
+Allow @value{GDBN} to choose a decoding style by inspecting your program.
+
+@item gnu
+Decode based on the GNU C++ compiler (@code{g++}) encoding algorithm.
+
+@item lucid
+Decode based on the Lucid C++ compiler (@code{lcc}) encoding algorithm.
+
+@item arm
+Decode using the algorithm in the @cite{C++ Annotated Reference Manual}.
+@strong{Warning:} this setting alone is not sufficient to allow
+debugging @code{cfront}-generated executables. @value{GDBN} would
+require further enhancement to permit that.
+@end table
+
+@item show demangle-style
+@kindex show demangle-style
+Display the encoding style currently in use for decoding C++ symbols.
+
+@item set print object
+@itemx set print object on
+@kindex set print object
+When displaying a pointer to an object, identify the @emph{actual}
+(derived) type of the object rather than the @emph{declared} type, using
+the virtual function table.
+
+@item set print object off
+Display only the declared type of objects, without reference to the
+virtual function table. This is the default setting.
+
+@item show print object
+@kindex show print object
+Show whether actual, or declared, object types will be displayed.
+
+@item set print vtbl
+@itemx set print vtbl on
+@kindex set print vtbl
+Pretty print C++ virtual function tables. The default is off.
+
+@item set print vtbl off
+Do not pretty print C++ virtual function tables.
+
+@item show print vtbl
+@kindex show print vtbl
+Show whether C++ virtual function tables are pretty printed, or not.
+@end table
+@end ifclear
+
+@node Value History
+@section Value history
+
+@cindex value history
+Values printed by the @code{print} command are saved in the @value{GDBN} @dfn{value
+history} so that you can refer to them in other expressions. Values are
+kept until the symbol table is re-read or discarded (for example with
+the @code{file} or @code{symbol-file} commands). When the symbol table
+changes, the value history is discarded, since the values may contain
+pointers back to the types defined in the symbol table.
+
+@cindex @code{$}
+@cindex @code{$$}
+@cindex history number
+The values printed are given @dfn{history numbers} by which you can
+refer to them. These are successive integers starting with one.
+@code{print} shows you the history number assigned to a value by
+printing @samp{$@var{num} = } before the value; here @var{num} is the
+history number.
+
+To refer to any previous value, use @samp{$} followed by the value's
+history number. The way @code{print} labels its output is designed to
+remind you of this. Just @code{$} refers to the most recent value in
+the history, and @code{$$} refers to the value before that.
+@code{$$@var{n}} refers to the @var{n}th value from the end; @code{$$2}
+is the value just prior to @code{$$}, @code{$$1} is equivalent to
+@code{$$}, and @code{$$0} is equivalent to @code{$}.
+
+For example, suppose you have just printed a pointer to a structure and
+want to see the contents of the structure. It suffices to type
+
+@example
+p *$
+@end example
+
+If you have a chain of structures where the component @code{next} points
+to the next one, you can print the contents of the next one with this:
+
+@example
+p *$.next
+@end example
+
+@noindent
+You can print successive links in the chain by repeating this
+command---which you can do by just typing @key{RET}.
+
+Note that the history records values, not expressions. If the value of
+@code{x} is 4 and you type these commands:
+
+@example
+print x
+set x=5
+@end example
+
+@noindent
+then the value recorded in the value history by the @code{print} command
+remains 4 even though the value of @code{x} has changed.
+
+@table @code
+@kindex show values
+@item show values
+Print the last ten values in the value history, with their item numbers.
+This is like @samp{p@ $$9} repeated ten times, except that @code{show
+values} does not change the history.
+
+@item show values @var{n}
+Print ten history values centered on history item number @var{n}.
+
+@item show values +
+Print ten history values just after the values last printed. If no more
+values are available, produces no display.
+@end table
+
+Pressing @key{RET} to repeat @code{show values @var{n}} has exactly the
+same effect as @samp{show values +}.
+
+@node Convenience Vars
+@section Convenience variables
+
+@cindex convenience variables
+@value{GDBN} provides @dfn{convenience variables} that you can use within
+@value{GDBN} to hold on to a value and refer to it later. These variables
+exist entirely within @value{GDBN}; they are not part of your program, and
+setting a convenience variable has no direct effect on further execution
+of your program. That is why you can use them freely.
+
+Convenience variables are prefixed with @samp{$}. Any name preceded by
+@samp{$} can be used for a convenience variable, unless it is one of
+the predefined machine-specific register names (@pxref{Registers}).
+(Value history references, in contrast, are @emph{numbers} preceded
+by @samp{$}. @xref{Value History, ,Value history}.)
+
+You can save a value in a convenience variable with an assignment
+expression, just as you would set a variable in your program.
+For example:
+
+@example
+set $foo = *object_ptr
+@end example
+
+@noindent
+would save in @code{$foo} the value contained in the object pointed to by
+@code{object_ptr}.
+
+Using a convenience variable for the first time creates it, but its
+value is @code{void} until you assign a new value. You can alter the
+value with another assignment at any time.
+
+Convenience variables have no fixed types. You can assign a convenience
+variable any type of value, including structures and arrays, even if
+that variable already has a value of a different type. The convenience
+variable, when used as an expression, has the type of its current value.
+
+@table @code
+@item show convenience
+@kindex show convenience
+Print a list of convenience variables used so far, and their values.
+Abbreviated @code{show con}.
+@end table
+
+One of the ways to use a convenience variable is as a counter to be
+incremented or a pointer to be advanced. For example, to print
+a field from successive elements of an array of structures:
+
+@example
+set $i = 0
+print bar[$i++]->contents
+@i{@dots{} repeat that command by typing @key{RET}.}
+@end example
+
+Some convenience variables are created automatically by @value{GDBN} and given
+values likely to be useful.
+
+@table @code
+@item $_
+@kindex $_
+The variable @code{$_} is automatically set by the @code{x} command to
+the last address examined (@pxref{Memory, ,Examining memory}). Other
+commands which provide a default address for @code{x} to examine also
+set @code{$_} to that address; these commands include @code{info line}
+and @code{info breakpoint}. The type of @code{$_} is @code{void *}
+except when set by the @code{x} command, in which case it is a pointer
+to the type of @code{$__}.
+
+@item $__
+@kindex $__
+The variable @code{$__} is automatically set by the @code{x} command
+to the value found in the last address examined. Its type is chosen
+to match the format in which the data was printed.
+@end table
+
+@node Registers
+@section Registers
+
+@cindex registers
+You can refer to machine register contents, in expressions, as variables
+with names starting with @samp{$}. The names of registers are different
+for each machine; use @code{info registers} to see the names used on
+your machine.
+
+@table @code
+@item info registers
+@kindex info registers
+Print the names and values of all registers except floating-point
+registers (in the selected stack frame).
+
+@item info all-registers
+@kindex info all-registers
+@cindex floating point registers
+Print the names and values of all registers, including floating-point
+registers.
+
+@item info registers @var{regname} @dots{}
+Print the relativized value of each specified register @var{regname}.
+@var{regname} may be any register name valid on the machine you are using, with
+or without the initial @samp{$}.
+@end table
+
+@value{GDBN} has four ``standard'' register names that are available (in
+expressions) on most machines---whenever they do not conflict with an
+architecture's canonical mnemonics for registers. The register names
+@code{$pc} and @code{$sp} are used for the program counter register and
+the stack pointer. @code{$fp} is used for a register that contains a
+pointer to the current stack frame, and @code{$ps} is used for a
+register that contains the processor status. For example,
+you could print the program counter in hex with
+
+@example
+p/x $pc
+@end example
+
+@noindent
+or print the instruction to be executed next with
+
+@example
+x/i $pc
+@end example
+
+@noindent
+or add four to the stack pointer@footnote{This is a way of removing
+one word from the stack, on machines where stacks grow downward in
+memory (most machines, nowadays). This assumes that the innermost
+stack frame is selected; setting @code{$sp} is not allowed when other
+stack frames are selected. To pop entire frames off the stack,
+regardless of machine architecture, use @code{return};
+@pxref{Returning, ,Returning from a function}.} with
+
+@example
+set $sp += 4
+@end example
+
+Whenever possible, these four standard register names are available on
+your machine even though the machine has different canonical mnemonics,
+so long as there is no conflict. The @code{info registers} command
+shows the canonical names. For example, on the SPARC, @code{info
+registers} displays the processor status register as @code{$psr} but you
+can also refer to it as @code{$ps}.
+
+@value{GDBN} always considers the contents of an ordinary register as an
+integer when the register is examined in this way. Some machines have
+special registers which can hold nothing but floating point; these
+registers are considered to have floating point values. There is no way
+to refer to the contents of an ordinary register as floating point value
+(although you can @emph{print} it as a floating point value with
+@samp{print/f $@var{regname}}).
+
+Some registers have distinct ``raw'' and ``virtual'' data formats. This
+means that the data format in which the register contents are saved by
+the operating system is not the same one that your program normally
+sees. For example, the registers of the 68881 floating point
+coprocessor are always saved in ``extended'' (raw) format, but all C
+programs expect to work with ``double'' (virtual) format. In such
+cases, @value{GDBN} normally works with the virtual format only (the format that
+makes sense for your program), but the @code{info registers} command
+prints the data in both formats.
+
+Normally, register values are relative to the selected stack frame
+(@pxref{Selection, ,Selecting a frame}). This means that you get the
+value that the register would contain if all stack frames farther in
+were exited and their saved registers restored. In order to see the
+true contents of hardware registers, you must select the innermost
+frame (with @samp{frame 0}).
+
+However, @value{GDBN} must deduce where registers are saved, from the machine
+code generated by your compiler. If some registers are not saved, or if
+@value{GDBN} is unable to locate the saved registers, the selected stack
+frame will make no difference.
+
+@ifset AMD29K
+@table @code
+@item set rstack_high_address @var{address}
+@kindex set rstack_high_address
+@cindex AMD 29K register stack
+@cindex register stack, AMD29K
+On AMD 29000 family processors, registers are saved in a separate
+``register stack''. There is no way for @value{GDBN} to determine the extent
+of this stack. Normally, @value{GDBN} just assumes that the stack is ``large
+enough''. This may result in @value{GDBN} referencing memory locations that
+do not exist. If necessary, you can get around this problem by
+specifying the ending address of the register stack with the @code{set
+rstack_high_address} command. The argument should be an address, which
+you will probably want to precede with @samp{0x} to specify in
+hexadecimal.
+
+@item show rstack_high_address
+@kindex show rstack_high_address
+Display the current limit of the register stack, on AMD 29000 family
+processors.
+@end table
+@end ifset
+
+@ifclear HAVE-FLOAT
+@node Floating Point Hardware
+@section Floating point hardware
+@cindex floating point
+
+@c FIXME! Really host, not target?
+Depending on the host machine architecture, @value{GDBN} may be able to give
+you more information about the status of the floating point hardware.
+
+@table @code
+@item info float
+@kindex info float
+Display hardware-dependent information about the floating
+point unit. The exact contents and layout vary depending on the
+floating point chip; on some platforms, @samp{info float} is not
+available at all.
+@end table
+@c FIXME: this is a cop-out. Try to get examples, explanations. Only
+@c FIXME...supported currently on arm's and 386's. Mark properly with
+@c FIXME... m4 macros to isolate general statements from hardware-dep,
+@c FIXME... at that point.
+@end ifclear
+
+@ifclear CONLY
+@node Languages
+@chapter Using @value{GDBN} with Different Languages
+@cindex languages
+
+@ifset MOD2
+Although programming languages generally have common aspects, they are
+rarely expressed in the same manner. For instance, in ANSI C,
+dereferencing a pointer @code{p} is accomplished by @code{*p}, but in
+Modula-2, it is accomplished by @code{p^}. Values can also be
+represented (and displayed) differently. Hex numbers in C are written
+like @samp{0x1ae}, while in Modula-2 they appear as @samp{1AEH}.
+@end ifset
+
+@cindex working language
+Language-specific information is built into @value{GDBN} for some languages,
+allowing you to express operations like the above in your program's
+native language, and allowing @value{GDBN} to output values in a manner
+consistent with the syntax of your program's native language. The
+language you use to build expressions, called the @dfn{working
+language}, can be selected manually, or @value{GDBN} can set it
+automatically.
+
+@menu
+* Setting:: Switching between source languages
+* Show:: Displaying the language
+@ifset MOD2
+* Checks:: Type and range checks
+@end ifset
+
+* Support:: Supported languages
+@end menu
+
+@node Setting
+@section Switching between source languages
+
+There are two ways to control the working language---either have @value{GDBN}
+set it automatically, or select it manually yourself. You can use the
+@code{set language} command for either purpose. On startup, @value{GDBN}
+defaults to setting the language automatically.
+
+@menu
+* Manually:: Setting the working language manually
+* Automatically:: Having @value{GDBN} infer the source language
+@end menu
+
+@node Manually
+@subsection Setting the working language
+
+If you allow @value{GDBN} to set the language automatically,
+expressions are interpreted the same way in your debugging session and
+your program.
+
+@kindex set language
+If you wish, you may set the language manually. To do this, issue the
+command @samp{set language @var{lang}}, where @var{lang} is the name of
+a language, such as
+@ifclear MOD2
+@code{c}.
+@end ifclear
+@ifset MOD2
+@code{c} or @code{modula-2}.
+@end ifset
+For a list of the supported languages, type @samp{set language}.
+@c FIXME: rms: eventually this command should be "help set language".
+
+@ifset MOD2
+Setting the language manually prevents @value{GDBN} from updating the working
+language automatically. This can lead to confusion if you try
+to debug a program when the working language is not the same as the
+source language, when an expression is acceptable to both
+languages---but means different things. For instance, if the current
+source file were written in C, and @value{GDBN} was parsing Modula-2, a
+command such as:
+
+@example
+print a = b + c
+@end example
+
+@noindent
+might not have the effect you intended. In C, this means to add
+@code{b} and @code{c} and place the result in @code{a}. The result
+printed would be the value of @code{a}. In Modula-2, this means to compare
+@code{a} to the result of @code{b+c}, yielding a @code{BOOLEAN} value.
+@end ifset
+
+@node Automatically
+@subsection Having @value{GDBN} infer the source language
+
+To have @value{GDBN} set the working language automatically, use @samp{set
+language local} or @samp{set language auto}. @value{GDBN} then infers the
+language that a program was written in by looking at the name of its
+source files, and examining their extensions:
+
+@table @file
+@ifset MOD2
+@item *.mod
+Modula-2 source file
+@end ifset
+
+@item *.c
+C source file
+
+@item *.C
+@itemx *.cc
+C++ source file
+@end table
+
+This information is recorded for each function or procedure in a source
+file. When your program stops in a frame (usually by encountering a
+breakpoint), @value{GDBN} sets the working language to the language recorded
+for the function in that frame. If the language for a frame is unknown
+(that is, if the function or block corresponding to the frame was
+defined in a source file that does not have a recognized extension), the
+current working language is not changed, and @value{GDBN} issues a warning.
+
+This may not seem necessary for most programs, which are written
+entirely in one source language. However, program modules and libraries
+written in one source language can be used by a main program written in
+a different source language. Using @samp{set language auto} in this
+case frees you from having to set the working language manually.
+
+@node Show
+@section Displaying the language
+
+The following commands will help you find out which language is the
+working language, and also what language source files were written in.
+
+@kindex show language
+@kindex info frame
+@kindex info source
+@table @code
+@item show language
+Display the current working language. This is the
+language you can use with commands such as @code{print} to
+build and compute expressions that may involve variables in your program.
+
+@item info frame
+Among the other information listed here (@pxref{Frame Info, ,Information
+about a frame}) is the source language for this frame. This is the
+language that will become the working language if you ever use an
+identifier that is in this frame.
+
+@item info source
+Among the other information listed here (@pxref{Symbols, ,Examining the
+Symbol Table}) is the source language of this source file.
+@end table
+
+@ifset MOD2
+@node Checks
+@section Type and range checking
+
+@quotation
+@emph{Warning:} In this release, the @value{GDBN} commands for type and range
+checking are included, but they do not yet have any effect. This
+section documents the intended facilities.
+@end quotation
+@c FIXME remove warning when type/range code added
+
+Some languages are designed to guard you against making seemingly common
+errors through a series of compile- and run-time checks. These include
+checking the type of arguments to functions and operators, and making
+sure mathematical overflows are caught at run time. Checks such as
+these help to ensure a program's correctness once it has been compiled
+by eliminating type mismatches, and providing active checks for range
+errors when your program is running.
+
+@value{GDBN} can check for conditions like the above if you wish.
+Although @value{GDBN} will not check the statements in your program, it
+can check expressions entered directly into @value{GDBN} for evaluation via
+the @code{print} command, for example. As with the working language,
+@value{GDBN} can also decide whether or not to check automatically based on
+your program's source language. @xref{Support, ,Supported languages},
+for the default settings of supported languages.
+
+@menu
+* Type Checking:: An overview of type checking
+* Range Checking:: An overview of range checking
+@end menu
+
+@cindex type checking
+@cindex checks, type
+@node Type Checking
+@subsection An overview of type checking
+
+Some languages, such as Modula-2, are strongly typed, meaning that the
+arguments to operators and functions have to be of the correct type,
+otherwise an error occurs. These checks prevent type mismatch
+errors from ever causing any run-time problems. For example,
+
+@example
+1 + 2 @result{} 3
+@exdent but
+@error{} 1 + 2.3
+@end example
+
+The second example fails because the @code{CARDINAL} 1 is not
+type-compatible with the @code{REAL} 2.3.
+
+For expressions you use in @value{GDBN} commands, you can tell the @value{GDBN}
+type checker to skip checking; to treat any mismatches as errors and
+abandon the expression; or only issue warnings when type mismatches
+occur, but evaluate the expression anyway. When you choose the last of
+these, @value{GDBN} evaluates expressions like the second example above, but
+also issues a warning.
+
+Even though you may turn type checking off, other type-based reasons may
+prevent @value{GDBN} from evaluating an expression. For instance, @value{GDBN} does not
+know how to add an @code{int} and a @code{struct foo}. These particular
+type errors have nothing to do with the language in use, and usually
+arise from expressions, such as the one described above, which make
+little sense to evaluate anyway.
+
+Each language defines to what degree it is strict about type. For
+instance, both Modula-2 and C require the arguments to arithmetical
+operators to be numbers. In C, enumerated types and pointers can be
+represented as numbers, so that they are valid arguments to mathematical
+operators. @xref{Support, ,Supported languages}, for further
+details on specific languages.
+
+@value{GDBN} provides some additional commands for controlling the type checker:
+
+@kindex set check
+@kindex set check type
+@kindex show check type
+@table @code
+@item set check type auto
+Set type checking on or off based on the current working language.
+@xref{Support, ,Supported languages}, for the default settings for
+each language.
+
+@item set check type on
+@itemx set check type off
+Set type checking on or off, overriding the default setting for the
+current working language. Issue a warning if the setting does not
+match the language default. If any type mismatches occur in
+evaluating an expression while typechecking is on, @value{GDBN} prints a
+message and aborts evaluation of the expression.
+
+@item set check type warn
+Cause the type checker to issue warnings, but to always attempt to
+evaluate the expression. Evaluating the expression may still
+be impossible for other reasons. For example, @value{GDBN} cannot add
+numbers and structures.
+
+@item show type
+Show the current setting of the type checker, and whether or not @value{GDBN} is
+setting it automatically.
+@end table
+
+@cindex range checking
+@cindex checks, range
+@node Range Checking
+@subsection An overview of range checking
+
+In some languages (such as Modula-2), it is an error to exceed the
+bounds of a type; this is enforced with run-time checks. Such range
+checking is meant to ensure program correctness by making sure
+computations do not overflow, or indices on an array element access do
+not exceed the bounds of the array.
+
+For expressions you use in @value{GDBN} commands, you can tell
+@value{GDBN} to treat range errors in one of three ways: ignore them,
+always treat them as errors and abandon the expression, or issue
+warnings but evaluate the expression anyway.
+
+A range error can result from numerical overflow, from exceeding an
+array index bound, or when you type a constant that is not a member
+of any type. Some languages, however, do not treat overflows as an
+error. In many implementations of C, mathematical overflow causes the
+result to ``wrap around'' to lower values---for example, if @var{m} is
+the largest integer value, and @var{s} is the smallest, then
+
+@example
+@var{m} + 1 @result{} @var{s}
+@end example
+
+This, too, is specific to individual languages, and in some cases
+specific to individual compilers or machines. @xref{Support, ,
+Supported languages}, for further details on specific languages.
+
+@value{GDBN} provides some additional commands for controlling the range checker:
+
+@kindex set check
+@kindex set check range
+@kindex show check range
+@table @code
+@item set check range auto
+Set range checking on or off based on the current working language.
+@xref{Support, ,Supported languages}, for the default settings for
+each language.
+
+@item set check range on
+@itemx set check range off
+Set range checking on or off, overriding the default setting for the
+current working language. A warning is issued if the setting does not
+match the language default. If a range error occurs, then a message
+is printed and evaluation of the expression is aborted.
+
+@item set check range warn
+Output messages when the @value{GDBN} range checker detects a range error,
+but attempt to evaluate the expression anyway. Evaluating the
+expression may still be impossible for other reasons, such as accessing
+memory that the process does not own (a typical example from many Unix
+systems).
+
+@item show range
+Show the current setting of the range checker, and whether or not it is
+being set automatically by @value{GDBN}.
+@end table
+@end ifset
+
+@node Support
+@section Supported languages
+
+@ifset MOD2
+@value{GDBN} 4 supports C, C++, and Modula-2.
+@end ifset
+@ifclear MOD2
+@value{GDBN} 4 supports C, and C++.
+@end ifclear
+Some @value{GDBN} features may be used in expressions regardless of the
+language you use: the @value{GDBN} @code{@@} and @code{::} operators,
+and the @samp{@{type@}addr} construct (@pxref{Expressions,
+,Expressions}) can be used with the constructs of any supported
+language.
+
+The following sections detail to what degree each source language is
+supported by @value{GDBN}. These sections are not meant to be language
+tutorials or references, but serve only as a reference guide to what the
+@value{GDBN} expression parser will accept, and what input and output
+formats should look like for different languages. There are many good
+books written on each of these languages; please look to these for a
+language reference or tutorial.
+
+@ifset MOD2
+@menu
+* C:: C and C++
+* Modula-2:: Modula-2
+@end menu
+
+@node C
+@subsection C and C++
+@cindex C and C++
+@cindex expressions in C or C++
+
+Since C and C++ are so closely related, many features of @value{GDBN} apply
+to both languages. Whenever this is the case, we discuss both languages
+together.
+@end ifset
+@ifclear MOD2
+@c Cancel this below, under same condition, at end of this chapter!
+@raisesections
+@end ifclear
+
+@cindex C++
+@kindex g++
+@cindex GNU C++
+The C++ debugging facilities are jointly implemented by the GNU C++
+compiler and @value{GDBN}. Therefore, to debug your C++ code effectively,
+you must compile your C++ programs with the GNU C++ compiler,
+@code{g++}.
+@end ifclear
+@ifset CONLY
+@node C
+@chapter C Language Support
+@cindex C language
+@cindex expressions in C
+
+Information specific to the C language is built into @value{GDBN} so that you
+can use C expressions while degugging. This also permits @value{GDBN} to
+output values in a manner consistent with C conventions.
+
+@menu
+* C Operators:: C operators
+* C Constants:: C constants
+* Debugging C:: @value{GDBN} and C
+@end menu
+@end ifset
+@ifclear CONLY
+@menu
+* C Operators:: C and C++ operators
+* C Constants:: C and C++ constants
+* Cplus expressions:: C++ expressions
+* C Defaults:: Default settings for C and C++
+@ifset MOD2
+* C Checks:: C and C++ type and range checks
+@end ifset
+
+* Debugging C:: @value{GDBN} and C
+* Debugging C plus plus:: Special features for C++
+@end menu
+@end ifclear
+
+@ifclear CONLY
+@cindex C and C++ operators
+@node C Operators
+@subsubsection C and C++ operators
+@end ifclear
+@ifset CONLY
+@cindex C operators
+@node C Operators
+@section C operators
+@end ifset
+
+Operators must be defined on values of specific types. For instance,
+@code{+} is defined on numbers, but not on structures. Operators are
+often defined on groups of types.
+
+@ifclear CONLY
+For the purposes of C and C++, the following definitions hold:
+@end ifclear
+
+@itemize @bullet
+@item
+@emph{Integral types} include @code{int} with any of its storage-class
+specifiers; @code{char}; and @code{enum}.
+
+@item
+@emph{Floating-point types} include @code{float} and @code{double}.
+
+@item
+@emph{Pointer types} include all types defined as @code{(@var{type}
+*)}.
+
+@item
+@emph{Scalar types} include all of the above.
+@end itemize
+
+@noindent
+The following operators are supported. They are listed here
+in order of increasing precedence:
+
+@table @code
+@item ,
+The comma or sequencing operator. Expressions in a comma-separated list
+are evaluated from left to right, with the result of the entire
+expression being the last expression evaluated.
+
+@item =
+Assignment. The value of an assignment expression is the value
+assigned. Defined on scalar types.
+
+@item @var{op}=
+Used in an expression of the form @w{@code{@var{a} @var{op}= @var{b}}},
+and translated to @w{@code{@var{a} = @var{a op b}}}.
+@w{@code{@var{op}=}} and @code{=} have the same precendence.
+@var{op} is any one of the operators @code{|}, @code{^}, @code{&},
+@code{<<}, @code{>>}, @code{+}, @code{-}, @code{*}, @code{/}, @code{%}.
+
+@item ?:
+The ternary operator. @code{@var{a} ? @var{b} : @var{c}} can be thought
+of as: if @var{a} then @var{b} else @var{c}. @var{a} should be of an
+integral type.
+
+@item ||
+Logical @sc{or}. Defined on integral types.
+
+@item &&
+Logical @sc{and}. Defined on integral types.
+
+@item |
+Bitwise @sc{or}. Defined on integral types.
+
+@item ^
+Bitwise exclusive-@sc{or}. Defined on integral types.
+
+@item &
+Bitwise @sc{and}. Defined on integral types.
+
+@item ==@r{, }!=
+Equality and inequality. Defined on scalar types. The value of these
+expressions is 0 for false and non-zero for true.
+
+@item <@r{, }>@r{, }<=@r{, }>=
+Less than, greater than, less than or equal, greater than or equal.
+Defined on scalar types. The value of these expressions is 0 for false
+and non-zero for true.
+
+@item <<@r{, }>>
+left shift, and right shift. Defined on integral types.
+
+@item @@
+The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}).
+
+@item +@r{, }-
+Addition and subtraction. Defined on integral types, floating-point types and
+pointer types.
+
+@item *@r{, }/@r{, }%
+Multiplication, division, and modulus. Multiplication and division are
+defined on integral and floating-point types. Modulus is defined on
+integral types.
+
+@item ++@r{, }--
+Increment and decrement. When appearing before a variable, the
+operation is performed before the variable is used in an expression;
+when appearing after it, the variable's value is used before the
+operation takes place.
+
+@item *
+Pointer dereferencing. Defined on pointer types. Same precedence as
+@code{++}.
+
+@item &
+Address operator. Defined on variables. Same precedence as @code{++}.
+
+@ifclear CONLY
+For debugging C++, @value{GDBN} implements a use of @samp{&} beyond what is
+allowed in the C++ language itself: you can use @samp{&(&@var{ref})}
+(or, if you prefer, simply @samp{&&@var{ref}}) to examine the address
+where a C++ reference variable (declared with @samp{&@var{ref}}) is
+stored.
+@end ifclear
+
+@item -
+Negative. Defined on integral and floating-point types. Same
+precedence as @code{++}.
+
+@item !
+Logical negation. Defined on integral types. Same precedence as
+@code{++}.
+
+@item ~
+Bitwise complement operator. Defined on integral types. Same precedence as
+@code{++}.
+
+
+@item .@r{, }->
+Structure member, and pointer-to-structure member. For convenience,
+@value{GDBN} regards the two as equivalent, choosing whether to dereference a
+pointer based on the stored type information.
+Defined on @code{struct} and @code{union} data.
+
+@item []
+Array indexing. @code{@var{a}[@var{i}]} is defined as
+@code{*(@var{a}+@var{i})}. Same precedence as @code{->}.
+
+@item ()
+Function parameter list. Same precedence as @code{->}.
+
+@ifclear CONLY
+@item ::
+C++ scope resolution operator. Defined on
+@code{struct}, @code{union}, and @code{class} types.
+@end ifclear
+
+@item ::
+Doubled colons
+@ifclear CONLY
+also
+@end ifclear
+represent the @value{GDBN} scope operator (@pxref{Expressions,
+,Expressions}).
+@ifclear CONLY
+Same precedence as @code{::}, above.
+@end ifclear
+@end table
+
+@ifclear CONLY
+@cindex C and C++ constants
+@node C Constants
+@subsubsection C and C++ constants
+
+@value{GDBN} allows you to express the constants of C and C++ in the
+following ways:
+@end ifclear
+@ifset CONLY
+@cindex C constants
+@node C Constants
+@section C constants
+
+@value{GDBN} allows you to express the constants of C in the
+following ways:
+@end ifset
+
+@itemize @bullet
+@item
+Integer constants are a sequence of digits. Octal constants are
+specified by a leading @samp{0} (ie. zero), and hexadecimal constants by
+a leading @samp{0x} or @samp{0X}. Constants may also end with a letter
+@samp{l}, specifying that the constant should be treated as a
+@code{long} value.
+
+@item
+Floating point constants are a sequence of digits, followed by a decimal
+point, followed by a sequence of digits, and optionally followed by an
+exponent. An exponent is of the form:
+@samp{@w{e@r{[[}+@r{]|}-@r{]}@var{nnn}}}, where @var{nnn} is another
+sequence of digits. The @samp{+} is optional for positive exponents.
+
+@item
+Enumerated constants consist of enumerated identifiers, or their
+integral equivalents.
+
+@item
+Character constants are a single character surrounded by single quotes
+(@code{'}), or a number---the ordinal value of the corresponding character
+(usually its @sc{ASCII} value). Within quotes, the single character may
+be represented by a letter or by @dfn{escape sequences}, which are of
+the form @samp{\@var{nnn}}, where @var{nnn} is the octal representation
+of the character's ordinal value; or of the form @samp{\@var{x}}, where
+@samp{@var{x}} is a predefined special character---for example,
+@samp{\n} for newline.
+
+@item
+String constants are a sequence of character constants surrounded
+by double quotes (@code{"}).
+
+@item
+Pointer constants are an integral value. You can also write pointers
+to constants using the C operator @samp{&}.
+
+@item
+Array constants are comma-separated lists surrounded by braces @samp{@{}
+and @samp{@}}; for example, @samp{@{1,2,3@}} is a three-element array of
+integers, @samp{@{@{1,2@}, @{3,4@}, @{5,6@}@}} is a three-by-two array,
+and @samp{@{&"hi", &"there", &"fred"@}} is a three-element array of pointers.
+@end itemize
+
+@ifclear CONLY
+@node Cplus expressions
+@subsubsection C++ expressions
+
+@cindex expressions in C++
+@value{GDBN} expression handling has a number of extensions to
+interpret a significant subset of C++ expressions.
+
+@cindex C++ support, not in @sc{coff}
+@cindex @sc{coff} versus C++
+@cindex C++ and object formats
+@cindex object formats and C++
+@cindex a.out and C++
+@cindex @sc{ecoff} and C++
+@cindex @sc{xcoff} and C++
+@cindex @sc{elf}/stabs and C++
+@cindex @sc{elf}/@sc{dwarf} and C++
+@quotation
+@emph{Warning:} Most of these extensions depend on the use of additional
+debugging information in the symbol table, and thus require a rich,
+extendable object code format. In particular, if your system uses
+a.out, MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or Sun @sc{elf} with stabs
+extensions to the symbol table, these facilities are all available.
+Where the object code format is standard @sc{coff}, on the other hand,
+most of the C++ support in @value{GDBN} will @emph{not} work, nor can it.
+For the standard SVr4 debugging format, @sc{dwarf} in @sc{elf}, the
+standard is still evolving, so the C++ support in @value{GDBN} is still
+fragile; when this debugging format stabilizes, however, C++ support
+will also be available on systems that use it.
+@end quotation
+
+@enumerate
+
+@cindex member functions
+@item
+Member function calls are allowed; you can use expressions like
+
+@example
+count = aml->GetOriginal(x, y)
+@end example
+
+@kindex this
+@cindex namespace in C++
+@item
+While a member function is active (in the selected stack frame), your
+expressions have the same namespace available as the member function;
+that is, @value{GDBN} allows implicit references to the class instance
+pointer @code{this} following the same rules as C++.
+
+@cindex call overloaded functions
+@cindex type conversions in C++
+@item
+You can call overloaded functions; @value{GDBN} will resolve the function
+call to the right definition, with one restriction---you must use
+arguments of the type required by the function that you want to call.
+@value{GDBN} will not perform conversions requiring constructors or
+user-defined type operators.
+
+@cindex reference declarations
+@item
+@value{GDBN} understands variables declared as C++ references; you can use them in
+expressions just as you do in C++ source---they are automatically
+dereferenced.
+
+In the parameter list shown when @value{GDBN} displays a frame, the values of
+reference variables are not displayed (unlike other variables); this
+avoids clutter, since references are often used for large structures.
+The @emph{address} of a reference variable is always shown, unless
+you have specified @samp{set print address off}.
+
+@item
+@value{GDBN} supports the C++ name resolution operator @code{::}---your
+expressions can use it just as expressions in your program do. Since
+one scope may be defined in another, you can use @code{::} repeatedly if
+necessary, for example in an expression like
+@samp{@var{scope1}::@var{scope2}::@var{name}}. @value{GDBN} also allows
+resolving name scope by reference to source files, in both C and C++
+debugging (@pxref{Variables, ,Program variables}).
+@end enumerate
+
+@node C Defaults
+@subsubsection C and C++ defaults
+@cindex C and C++ defaults
+
+If you allow @value{GDBN} to set type and range checking automatically, they
+both default to @code{off} whenever the working language changes to
+C or C++. This happens regardless of whether you, or @value{GDBN},
+selected the working language.
+
+If you allow @value{GDBN} to set the language automatically, it sets the
+working language to C or C++ on entering code compiled from a source file
+whose name ends with @file{.c}, @file{.C}, or @file{.cc}.
+@xref{Automatically, ,Having @value{GDBN} infer the source language}, for
+further details.
+
+@ifset MOD2
+@c Type checking is (a) primarily motivated by Modula-2, and (b)
+@c unimplemented. If (b) changes, it might make sense to let this node
+@c appear even if Mod-2 does not, but meanwhile ignore it. pesch 16jul93.
+@node C Checks
+@subsubsection C and C++ type and range checks
+@cindex C and C++ checks
+
+By default, when @value{GDBN} parses C or C++ expressions, type checking
+is not used. However, if you turn type checking on, @value{GDBN} will
+consider two variables type equivalent if:
+
+@itemize @bullet
+@item
+The two variables are structured and have the same structure, union, or
+enumerated tag.
+
+@item
+Two two variables have the same type name, or types that have been
+declared equivalent through @code{typedef}.
+
+@ignore
+@c leaving this out because neither J Gilmore nor R Pesch understand it.
+@c FIXME--beers?
+@item
+The two @code{struct}, @code{union}, or @code{enum} variables are
+declared in the same declaration. (Note: this may not be true for all C
+compilers.)
+@end ignore
+@end itemize
+
+Range checking, if turned on, is done on mathematical operations. Array
+indices are not checked, since they are often used to index a pointer
+that is not itself an array.
+@end ifset
+@end ifclear
+
+@ifclear CONLY
+@node Debugging C
+@subsubsection @value{GDBN} and C
+@end ifclear
+@ifset CONLY
+@node Debugging C
+@section @value{GDBN} and C
+@end ifset
+
+The @code{set print union} and @code{show print union} commands apply to
+the @code{union} type. When set to @samp{on}, any @code{union} that is
+inside a @code{struct}
+@ifclear CONLY
+or @code{class}
+@end ifclear
+will also be printed.
+Otherwise, it will appear as @samp{@{...@}}.
+
+The @code{@@} operator aids in the debugging of dynamic arrays, formed
+with pointers and a memory allocation function. @xref{Expressions,
+,Expressions}.
+
+@ifclear CONLY
+@node Debugging C plus plus
+@subsubsection @value{GDBN} features for C++
+
+@cindex commands for C++
+Some @value{GDBN} commands are particularly useful with C++, and some are
+designed specifically for use with C++. Here is a summary:
+
+@table @code
+@cindex break in overloaded functions
+@item @r{breakpoint menus}
+When you want a breakpoint in a function whose name is overloaded,
+@value{GDBN} breakpoint menus help you specify which function definition
+you want. @xref{Breakpoint Menus,,Breakpoint menus}.
+
+@cindex overloading in C++
+@item rbreak @var{regex}
+Setting breakpoints using regular expressions is helpful for setting
+breakpoints on overloaded functions that are not members of any special
+classes.
+@xref{Set Breaks, ,Setting breakpoints}.
+
+@cindex C++ exception handling
+@item catch @var{exceptions}
+@itemx info catch
+Debug C++ exception handling using these commands. @xref{Exception
+Handling, ,Breakpoints and exceptions}.
+
+@cindex inheritance
+@item ptype @var{typename}
+Print inheritance relationships as well as other information for type
+@var{typename}.
+@xref{Symbols, ,Examining the Symbol Table}.
+
+@cindex C++ symbol display
+@item set print demangle
+@itemx show print demangle
+@itemx set print asm-demangle
+@itemx show print asm-demangle
+Control whether C++ symbols display in their source form, both when
+displaying code as C++ source and when displaying disassemblies.
+@xref{Print Settings, ,Print settings}.
+
+@item set print object
+@itemx show print object
+Choose whether to print derived (actual) or declared types of objects.
+@xref{Print Settings, ,Print settings}.
+
+@item set print vtbl
+@itemx show print vtbl
+Control the format for printing virtual function tables.
+@xref{Print Settings, ,Print settings}.
+
+@item @r{Overloaded symbol names}
+You can specify a particular definition of an overloaded symbol, using
+the same notation that is used to declare such symbols in C++: type
+@code{@var{symbol}(@var{types})} rather than just @var{symbol}. You can
+also use the @value{GDBN} command-line word completion facilities to list the
+available choices, or to finish the type list for you.
+@xref{Completion,, Command completion}, for details on how to do this.
+@end table
+@ifclear MOD2
+@c cancels "raisesections" under same conditions near bgn of chapter
+@lowersections
+@end ifclear
+
+@ifset MOD2
+@node Modula-2
+@subsection Modula-2
+@cindex Modula-2
+
+The extensions made to @value{GDBN} to support Modula-2 only support
+output from the GNU Modula-2 compiler (which is currently being
+developed). Other Modula-2 compilers are not currently supported, and
+attempting to debug executables produced by them will most likely
+result in an error as @value{GDBN} reads in the executable's symbol
+table.
+
+@cindex expressions in Modula-2
+@menu
+* M2 Operators:: Built-in operators
+* Built-In Func/Proc:: Built-in functions and procedures
+* M2 Constants:: Modula-2 constants
+* M2 Defaults:: Default settings for Modula-2
+* Deviations:: Deviations from standard Modula-2
+* M2 Checks:: Modula-2 type and range checks
+* M2 Scope:: The scope operators @code{::} and @code{.}
+* GDB/M2:: @value{GDBN} and Modula-2
+@end menu
+
+@node M2 Operators
+@subsubsection Operators
+@cindex Modula-2 operators
+
+Operators must be defined on values of specific types. For instance,
+@code{+} is defined on numbers, but not on structures. Operators are
+often defined on groups of types. For the purposes of Modula-2, the
+following definitions hold:
+
+@itemize @bullet
+
+@item
+@emph{Integral types} consist of @code{INTEGER}, @code{CARDINAL}, and
+their subranges.
+
+@item
+@emph{Character types} consist of @code{CHAR} and its subranges.
+
+@item
+@emph{Floating-point types} consist of @code{REAL}.
+
+@item
+@emph{Pointer types} consist of anything declared as @code{POINTER TO
+@var{type}}.
+
+@item
+@emph{Scalar types} consist of all of the above.
+
+@item
+@emph{Set types} consist of @code{SET} and @code{BITSET} types.
+
+@item
+@emph{Boolean types} consist of @code{BOOLEAN}.
+@end itemize
+
+@noindent
+The following operators are supported, and appear in order of
+increasing precedence:
+
+@table @code
+@item ,
+Function argument or array index separator.
+
+@item :=
+Assignment. The value of @var{var} @code{:=} @var{value} is
+@var{value}.
+
+@item <@r{, }>
+Less than, greater than on integral, floating-point, or enumerated
+types.
+
+@item <=@r{, }>=
+Less than, greater than, less than or equal to, greater than or equal to
+on integral, floating-point and enumerated types, or set inclusion on
+set types. Same precedence as @code{<}.
+
+@item =@r{, }<>@r{, }#
+Equality and two ways of expressing inequality, valid on scalar types.
+Same precedence as @code{<}. In @value{GDBN} scripts, only @code{<>} is
+available for inequality, since @code{#} conflicts with the script
+comment character.
+
+@item IN
+Set membership. Defined on set types and the types of their members.
+Same precedence as @code{<}.
+
+@item OR
+Boolean disjunction. Defined on boolean types.
+
+@item AND@r{, }&
+Boolean conjuction. Defined on boolean types.
+
+@item @@
+The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}).
+
+@item +@r{, }-
+Addition and subtraction on integral and floating-point types, or union
+and difference on set types.
+
+@item *
+Multiplication on integral and floating-point types, or set intersection
+on set types.
+
+@item /
+Division on floating-point types, or symmetric set difference on set
+types. Same precedence as @code{*}.
+
+@item DIV@r{, }MOD
+Integer division and remainder. Defined on integral types. Same
+precedence as @code{*}.
+
+@item -
+Negative. Defined on @code{INTEGER} and @code{REAL} data.
+
+@item ^
+Pointer dereferencing. Defined on pointer types.
+
+@item NOT
+Boolean negation. Defined on boolean types. Same precedence as
+@code{^}.
+
+@item .
+@code{RECORD} field selector. Defined on @code{RECORD} data. Same
+precedence as @code{^}.
+
+@item []
+Array indexing. Defined on @code{ARRAY} data. Same precedence as @code{^}.
+
+@item ()
+Procedure argument list. Defined on @code{PROCEDURE} objects. Same precedence
+as @code{^}.
+
+@item ::@r{, }.
+@value{GDBN} and Modula-2 scope operators.
+@end table
+
+@quotation
+@emph{Warning:} Sets and their operations are not yet supported, so @value{GDBN}
+will treat the use of the operator @code{IN}, or the use of operators
+@code{+}, @code{-}, @code{*}, @code{/}, @code{=}, , @code{<>}, @code{#},
+@code{<=}, and @code{>=} on sets as an error.
+@end quotation
+
+@cindex Modula-2 built-ins
+@node Built-In Func/Proc
+@subsubsection Built-in functions and procedures
+
+Modula-2 also makes available several built-in procedures and functions.
+In describing these, the following metavariables are used:
+
+@table @var
+
+@item a
+represents an @code{ARRAY} variable.
+
+@item c
+represents a @code{CHAR} constant or variable.
+
+@item i
+represents a variable or constant of integral type.
+
+@item m
+represents an identifier that belongs to a set. Generally used in the
+same function with the metavariable @var{s}. The type of @var{s} should
+be @code{SET OF @var{mtype}} (where @var{mtype} is the type of @var{m}).
+
+@item n
+represents a variable or constant of integral or floating-point type.
+
+@item r
+represents a variable or constant of floating-point type.
+
+@item t
+represents a type.
+
+@item v
+represents a variable.
+
+@item x
+represents a variable or constant of one of many types. See the
+explanation of the function for details.
+@end table
+
+All Modula-2 built-in procedures also return a result, described below.
+
+@table @code
+@item ABS(@var{n})
+Returns the absolute value of @var{n}.
+
+@item CAP(@var{c})
+If @var{c} is a lower case letter, it returns its upper case
+equivalent, otherwise it returns its argument
+
+@item CHR(@var{i})
+Returns the character whose ordinal value is @var{i}.
+
+@item DEC(@var{v})
+Decrements the value in the variable @var{v}. Returns the new value.
+
+@item DEC(@var{v},@var{i})
+Decrements the value in the variable @var{v} by @var{i}. Returns the
+new value.
+
+@item EXCL(@var{m},@var{s})
+Removes the element @var{m} from the set @var{s}. Returns the new
+set.
+
+@item FLOAT(@var{i})
+Returns the floating point equivalent of the integer @var{i}.
+
+@item HIGH(@var{a})
+Returns the index of the last member of @var{a}.
+
+@item INC(@var{v})
+Increments the value in the variable @var{v}. Returns the new value.
+
+@item INC(@var{v},@var{i})
+Increments the value in the variable @var{v} by @var{i}. Returns the
+new value.
+
+@item INCL(@var{m},@var{s})
+Adds the element @var{m} to the set @var{s} if it is not already
+there. Returns the new set.
+
+@item MAX(@var{t})
+Returns the maximum value of the type @var{t}.
+
+@item MIN(@var{t})
+Returns the minimum value of the type @var{t}.
+
+@item ODD(@var{i})
+Returns boolean TRUE if @var{i} is an odd number.
+
+@item ORD(@var{x})
+Returns the ordinal value of its argument. For example, the ordinal
+value of a character is its ASCII value (on machines supporting the
+ASCII character set). @var{x} must be of an ordered type, which include
+integral, character and enumerated types.
+
+@item SIZE(@var{x})
+Returns the size of its argument. @var{x} can be a variable or a type.
+
+@item TRUNC(@var{r})
+Returns the integral part of @var{r}.
+
+@item VAL(@var{t},@var{i})
+Returns the member of the type @var{t} whose ordinal value is @var{i}.
+@end table
+
+@quotation
+@emph{Warning:} Sets and their operations are not yet supported, so
+@value{GDBN} will treat the use of procedures @code{INCL} and @code{EXCL} as
+an error.
+@end quotation
+
+@cindex Modula-2 constants
+@node M2 Constants
+@subsubsection Constants
+
+@value{GDBN} allows you to express the constants of Modula-2 in the following
+ways:
+
+@itemize @bullet
+
+@item
+Integer constants are simply a sequence of digits. When used in an
+expression, a constant is interpreted to be type-compatible with the
+rest of the expression. Hexadecimal integers are specified by a
+trailing @samp{H}, and octal integers by a trailing @samp{B}.
+
+@item
+Floating point constants appear as a sequence of digits, followed by a
+decimal point and another sequence of digits. An optional exponent can
+then be specified, in the form @samp{E@r{[}+@r{|}-@r{]}@var{nnn}}, where
+@samp{@r{[}+@r{|}-@r{]}@var{nnn}} is the desired exponent. All of the
+digits of the floating point constant must be valid decimal (base 10)
+digits.
+
+@item
+Character constants consist of a single character enclosed by a pair of
+like quotes, either single (@code{'}) or double (@code{"}). They may
+also be expressed by their ordinal value (their ASCII value, usually)
+followed by a @samp{C}.
+
+@item
+String constants consist of a sequence of characters enclosed by a
+pair of like quotes, either single (@code{'}) or double (@code{"}).
+Escape sequences in the style of C are also allowed. @xref{C
+Constants, ,C and C++ constants}, for a brief explanation of escape
+sequences.
+
+@item
+Enumerated constants consist of an enumerated identifier.
+
+@item
+Boolean constants consist of the identifiers @code{TRUE} and
+@code{FALSE}.
+
+@item
+Pointer constants consist of integral values only.
+
+@item
+Set constants are not yet supported.
+@end itemize
+
+@node M2 Defaults
+@subsubsection Modula-2 defaults
+@cindex Modula-2 defaults
+
+If type and range checking are set automatically by @value{GDBN}, they
+both default to @code{on} whenever the working language changes to
+Modula-2. This happens regardless of whether you, or @value{GDBN},
+selected the working language.
+
+If you allow @value{GDBN} to set the language automatically, then entering
+code compiled from a file whose name ends with @file{.mod} will set the
+working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set
+the language automatically}, for further details.
+
+@node Deviations
+@subsubsection Deviations from standard Modula-2
+@cindex Modula-2, deviations from
+
+A few changes have been made to make Modula-2 programs easier to debug.
+This is done primarily via loosening its type strictness:
+
+@itemize @bullet
+@item
+Unlike in standard Modula-2, pointer constants can be formed by
+integers. This allows you to modify pointer variables during
+debugging. (In standard Modula-2, the actual address contained in a
+pointer variable is hidden from you; it can only be modified
+through direct assignment to another pointer variable or expression that
+returned a pointer.)
+
+@item
+C escape sequences can be used in strings and characters to represent
+non-printable characters. @value{GDBN} will print out strings with these
+escape sequences embedded. Single non-printable characters are
+printed using the @samp{CHR(@var{nnn})} format.
+
+@item
+The assignment operator (@code{:=}) returns the value of its right-hand
+argument.
+
+@item
+All built-in procedures both modify @emph{and} return their argument.
+@end itemize
+
+@node M2 Checks
+@subsubsection Modula-2 type and range checks
+@cindex Modula-2 checks
+
+@quotation
+@emph{Warning:} in this release, @value{GDBN} does not yet perform type or
+range checking.
+@end quotation
+@c FIXME remove warning when type/range checks added
+
+@value{GDBN} considers two Modula-2 variables type equivalent if:
+
+@itemize @bullet
+@item
+They are of types that have been declared equivalent via a @code{TYPE
+@var{t1} = @var{t2}} statement
+
+@item
+They have been declared on the same line. (Note: This is true of the
+GNU Modula-2 compiler, but it may not be true of other compilers.)
+@end itemize
+
+As long as type checking is enabled, any attempt to combine variables
+whose types are not equivalent is an error.
+
+Range checking is done on all mathematical operations, assignment, array
+index bounds, and all built-in functions and procedures.
+
+@node M2 Scope
+@subsubsection The scope operators @code{::} and @code{.}
+@cindex scope
+@kindex .
+@cindex colon, doubled as scope operator
+@ifinfo
+@kindex colon-colon
+@c Info cannot handle :: but TeX can.
+@end ifinfo
+@iftex
+@kindex ::
+@end iftex
+
+There are a few subtle differences between the Modula-2 scope operator
+(@code{.}) and the @value{GDBN} scope operator (@code{::}). The two have
+similar syntax:
+
+@example
+
+@var{module} . @var{id}
+@var{scope} :: @var{id}
+@end example
+
+@noindent
+where @var{scope} is the name of a module or a procedure,
+@var{module} the name of a module, and @var{id} is any declared
+identifier within your program, except another module.
+
+Using the @code{::} operator makes @value{GDBN} search the scope
+specified by @var{scope} for the identifier @var{id}. If it is not
+found in the specified scope, then @value{GDBN} will search all scopes
+enclosing the one specified by @var{scope}.
+
+Using the @code{.} operator makes @value{GDBN} search the current scope for
+the identifier specified by @var{id} that was imported from the
+definition module specified by @var{module}. With this operator, it is
+an error if the identifier @var{id} was not imported from definition
+module @var{module}, or if @var{id} is not an identifier in
+@var{module}.
+
+@node GDB/M2
+@subsubsection @value{GDBN} and Modula-2
+
+Some @value{GDBN} commands have little use when debugging Modula-2 programs.
+Five subcommands of @code{set print} and @code{show print} apply
+specifically to C and C++: @samp{vtbl}, @samp{demangle},
+@samp{asm-demangle}, @samp{object}, and @samp{union}. The first four
+apply to C++, and the last to the C @code{union} type, which has no direct
+analogue in Modula-2.
+
+The @code{@@} operator (@pxref{Expressions, ,Expressions}), while available
+while using any language, is not useful with Modula-2. Its
+intent is to aid the debugging of @dfn{dynamic arrays}, which cannot be
+created in Modula-2 as they can in C or C++. However, because an
+address can be specified by an integral constant, the construct
+@samp{@{@var{type}@}@var{adrexp}} is still useful. (@pxref{Expressions, ,Expressions})
+
+@cindex @code{#} in Modula-2
+In @value{GDBN} scripts, the Modula-2 inequality operator @code{#} is
+interpreted as the beginning of a comment. Use @code{<>} instead.
+
+@end ifset
+@end ifclear
+
+@node Symbols
+@chapter Examining the Symbol Table
+
+The commands described in this section allow you to inquire about the
+symbols (names of variables, functions and types) defined in your
+program. This information is inherent in the text of your program and
+does not change as your program executes. @value{GDBN} finds it in your
+program's symbol table, in the file indicated when you started @value{GDBN}
+(@pxref{File Options, ,Choosing files}), or by one of the
+file-management commands (@pxref{Files, ,Commands to specify files}).
+
+@c FIXME! This might be intentionally specific to C and C++; if so, move
+@c to someplace in C section of lang chapter.
+@cindex symbol names
+@cindex names of symbols
+@cindex quoting names
+Occasionally, you may need to refer to symbols that contain unusual
+characters, which @value{GDBN} ordinarily treats as word delimiters. The
+most frequent case is in referring to static variables in other
+source files (@pxref{Variables,,Program variables}). File names
+are recorded in object files as debugging symbols, but @value{GDBN} would
+ordinarily parse a typical file name, like @file{foo.c}, as the three words
+@samp{foo} @samp{.} @samp{c}. To allow @value{GDBN} to recognize
+@samp{foo.c} as a single symbol, enclose it in single quotes; for example,
+
+@example
+p 'foo.c'::x
+@end example
+
+@noindent
+looks up the value of @code{x} in the scope of the file @file{foo.c}.
+
+@table @code
+@item info address @var{symbol}
+@kindex info address
+Describe where the data for @var{symbol} is stored. For a register
+variable, this says which register it is kept in. For a non-register
+local variable, this prints the stack-frame offset at which the variable
+is always stored.
+
+Note the contrast with @samp{print &@var{symbol}}, which does not work
+at all for a register variable, and for a stack local variable prints
+the exact address of the current instantiation of the variable.
+
+@item whatis @var{exp}
+@kindex whatis
+Print the data type of expression @var{exp}. @var{exp} is not
+actually evaluated, and any side-effecting operations (such as
+assignments or function calls) inside it do not take place.
+@xref{Expressions, ,Expressions}.
+
+@item whatis
+Print the data type of @code{$}, the last value in the value history.
+
+@item ptype @var{typename}
+@kindex ptype
+Print a description of data type @var{typename}. @var{typename} may be
+the name of a type, or for C code it may have the form
+@ifclear CONLY
+@samp{class @var{class-name}},
+@end ifclear
+@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or
+@samp{enum @var{enum-tag}}.
+
+@item ptype @var{exp}
+@itemx ptype
+Print a description of the type of expression @var{exp}. @code{ptype}
+differs from @code{whatis} by printing a detailed description, instead
+of just the name of the type.
+
+For example, for this variable declaration:
+
+@example
+struct complex @{double real; double imag;@} v;
+@end example
+
+@noindent
+the two commands give this output:
+
+@example
+@group
+(@value{GDBP}) whatis v
+type = struct complex
+(@value{GDBP}) ptype v
+type = struct complex @{
+ double real;
+ double imag;
+@}
+@end group
+@end example
+
+@noindent
+As with @code{whatis}, using @code{ptype} without an argument refers to
+the type of @code{$}, the last value in the value history.
+
+@item info types @var{regexp}
+@itemx info types
+@kindex info types
+Print a brief description of all types whose name matches @var{regexp}
+(or all types in your program, if you supply no argument). Each
+complete typename is matched as though it were a complete line; thus,
+@samp{i type value} gives information on all types in your program whose
+name includes the string @code{value}, but @samp{i type ^value$} gives
+information only on types whose complete name is @code{value}.
+
+This command differs from @code{ptype} in two ways: first, like
+@code{whatis}, it does not print a detailed description; second, it
+lists all source files where a type is defined.
+
+@item info source
+@kindex info source
+Show the name of the current source file---that is, the source file for
+the function containing the current point of execution---and the language
+it was written in.
+
+@item info sources
+@kindex info sources
+Print the names of all source files in your program for which there is
+debugging information, organized into two lists: files whose symbols
+have already been read, and files whose symbols will be read when needed.
+
+@item info functions
+@kindex info functions
+Print the names and data types of all defined functions.
+
+@item info functions @var{regexp}
+Print the names and data types of all defined functions
+whose names contain a match for regular expression @var{regexp}.
+Thus, @samp{info fun step} finds all functions whose names
+include @code{step}; @samp{info fun ^step} finds those whose names
+start with @code{step}.
+
+@item info variables
+@kindex info variables
+Print the names and data types of all variables that are declared
+outside of functions (i.e., excluding local variables).
+
+@item info variables @var{regexp}
+Print the names and data types of all variables (except for local
+variables) whose names contain a match for regular expression
+@var{regexp}.
+
+@ignore
+This was never implemented.
+@item info methods
+@itemx info methods @var{regexp}
+@kindex info methods
+The @code{info methods} command permits the user to examine all defined
+methods within C++ program, or (with the @var{regexp} argument) a
+specific set of methods found in the various C++ classes. Many
+C++ classes provide a large number of methods. Thus, the output
+from the @code{ptype} command can be overwhelming and hard to use. The
+@code{info-methods} command filters the methods, printing only those
+which match the regular-expression @var{regexp}.
+@end ignore
+
+@item maint print symbols @var{filename}
+@itemx maint print psymbols @var{filename}
+@itemx maint print msymbols @var{filename}
+@kindex maint print symbols
+@cindex symbol dump
+@kindex maint print psymbols
+@cindex partial symbol dump
+Write a dump of debugging symbol data into the file @var{filename}.
+These commands are used to debug the @value{GDBN} symbol-reading code. Only
+symbols with debugging data are included. If you use @samp{maint print
+symbols}, @value{GDBN} includes all the symbols for which it has already
+collected full details: that is, @var{filename} reflects symbols for
+only those files whose symbols @value{GDBN} has read. You can use the
+command @code{info sources} to find out which files these are. If you
+use @samp{maint print psymbols} instead, the dump shows information about
+symbols that @value{GDBN} only knows partially---that is, symbols defined in
+files that @value{GDBN} has skimmed, but not yet read completely. Finally,
+@samp{maint print msymbols} dumps just the minimal symbol information
+required for each object file from which @value{GDBN} has read some symbols.
+@xref{Files, ,Commands to specify files}, for a discussion of how
+@value{GDBN} reads symbols (in the description of @code{symbol-file}).
+@end table
+
+@node Altering
+@chapter Altering Execution
+
+Once you think you have found an error in your program, you might want to
+find out for certain whether correcting the apparent error would lead to
+correct results in the rest of the run. You can find the answer by
+experiment, using the @value{GDBN} features for altering execution of the
+program.
+
+For example, you can store new values into variables or memory
+locations,
+@ifclear BARETARGET
+give your program a signal, restart it
+@end ifclear
+@ifset BARETARGET
+restart your program
+@end ifset
+at a different address, or even return prematurely from a function to
+its caller.
+
+@menu
+* Assignment:: Assignment to variables
+* Jumping:: Continuing at a different address
+@ifclear BARETARGET
+* Signaling:: Giving your program a signal
+@end ifclear
+
+* Returning:: Returning from a function
+* Calling:: Calling your program's functions
+* Patching:: Patching your program
+@end menu
+
+@node Assignment
+@section Assignment to variables
+
+@cindex assignment
+@cindex setting variables
+To alter the value of a variable, evaluate an assignment expression.
+@xref{Expressions, ,Expressions}. For example,
+
+@example
+print x=4
+@end example
+
+@noindent
+stores the value 4 into the variable @code{x}, and then prints the
+value of the assignment expression (which is 4).
+@ifclear CONLY
+@xref{Languages, ,Using @value{GDBN} with Different Languages}, for more
+information on operators in supported languages.
+@end ifclear
+
+@kindex set variable
+@cindex variables, setting
+If you are not interested in seeing the value of the assignment, use the
+@code{set} command instead of the @code{print} command. @code{set} is
+really the same as @code{print} except that the expression's value is
+not printed and is not put in the value history (@pxref{Value History,
+,Value history}). The expression is evaluated only for its effects.
+
+If the beginning of the argument string of the @code{set} command
+appears identical to a @code{set} subcommand, use the @code{set
+variable} command instead of just @code{set}. This command is identical
+to @code{set} except for its lack of subcommands. For example, if
+your program has a variable @code{width}, you get
+an error if you try to set a new value with just @samp{set width=13},
+because @value{GDBN} has the command @code{set width}:
+
+@example
+(@value{GDBP}) whatis width
+type = double
+(@value{GDBP}) p width
+$4 = 13
+(@value{GDBP}) set width=47
+Invalid syntax in expression.
+@end example
+
+@noindent
+The invalid expression, of course, is @samp{=47}. In
+order to actually set the program's variable @code{width}, use
+
+@example
+(@value{GDBP}) set var width=47
+@end example
+
+@value{GDBN} allows more implicit conversions in assignments than C; you can
+freely store an integer value into a pointer variable or vice versa,
+and you can convert any structure to any other structure that is the
+same length or shorter.
+@comment FIXME: how do structs align/pad in these conversions?
+@comment /pesch@cygnus.com 18dec1990
+
+To store values into arbitrary places in memory, use the @samp{@{@dots{}@}}
+construct to generate a value of specified type at a specified address
+(@pxref{Expressions, ,Expressions}). For example, @code{@{int@}0x83040} refers
+to memory location @code{0x83040} as an integer (which implies a certain size
+and representation in memory), and
+
+@example
+set @{int@}0x83040 = 4
+@end example
+
+@noindent
+stores the value 4 into that memory location.
+
+@node Jumping
+@section Continuing at a different address
+
+Ordinarily, when you continue your program, you do so at the place where
+it stopped, with the @code{continue} command. You can instead continue at
+an address of your own choosing, with the following commands:
+
+@table @code
+@item jump @var{linespec}
+@kindex jump
+Resume execution at line @var{linespec}. Execution will stop
+immediately if there is a breakpoint there. @xref{List, ,Printing
+source lines}, for a description of the different forms of
+@var{linespec}.
+
+The @code{jump} command does not change the current stack frame, or
+the stack pointer, or the contents of any memory location or any
+register other than the program counter. If line @var{linespec} is in
+a different function from the one currently executing, the results may
+be bizarre if the two functions expect different patterns of arguments or
+of local variables. For this reason, the @code{jump} command requests
+confirmation if the specified line is not in the function currently
+executing. However, even bizarre results are predictable if you are
+well acquainted with the machine-language code of your program.
+
+@item jump *@var{address}
+Resume execution at the instruction at address @var{address}.
+@end table
+
+You can get much the same effect as the @code{jump} command by storing a
+new value into the register @code{$pc}. The difference is that this
+does not start your program running; it only changes the address where it
+@emph{will} run when it is continued. For example,
+
+@example
+set $pc = 0x485
+@end example
+
+@noindent
+causes the next @code{continue} command or stepping command to execute at
+address @code{0x485}, rather than at the address where your program stopped.
+@xref{Continuing and Stepping, ,Continuing and stepping}.
+
+The most common occasion to use the @code{jump} command is to back up,
+perhaps with more breakpoints set, over a portion of a program that has
+already executed, in order to examine its execution in more detail.
+
+@ifclear BARETARGET
+@c @group
+@node Signaling
+@section Giving your program a signal
+
+@table @code
+@item signal @var{signal}
+@kindex signal
+Resume execution where your program stopped, but immediately give it the
+signal @var{signal}. @var{signal} can be the name or the number of a
+signal. For example, on many systems @code{signal 2} and @code{signal
+SIGINT} are both ways of sending an interrupt signal.
+
+Alternatively, if @var{signal} is zero, continue execution without
+giving a signal. This is useful when your program stopped on account of
+a signal and would ordinary see the signal when resumed with the
+@code{continue} command; @samp{signal 0} causes it to resume without a
+signal.
+
+@code{signal} does not repeat when you press @key{RET} a second time
+after executing the command.
+@end table
+@c @end group
+
+Invoking the @code{signal} command is not the same as invoking the
+@code{kill} utility from the shell. Sending a signal with @code{kill}
+causes @value{GDBN} to decide what to do with the signal depending on
+the signal handling tables (@pxref{Signals}). The @code{signal} command
+passes the signal directly to your program.
+
+@end ifclear
+
+@node Returning
+@section Returning from a function
+
+@table @code
+@item return
+@itemx return @var{expression}
+@cindex returning from a function
+@kindex return
+You can cancel execution of a function call with the @code{return}
+command. If you give an
+@var{expression} argument, its value is used as the function's return
+value.
+@end table
+
+When you use @code{return}, @value{GDBN} discards the selected stack frame
+(and all frames within it). You can think of this as making the
+discarded frame return prematurely. If you wish to specify a value to
+be returned, give that value as the argument to @code{return}.
+
+This pops the selected stack frame (@pxref{Selection, ,Selecting a
+frame}), and any other frames inside of it, leaving its caller as the
+innermost remaining frame. That frame becomes selected. The
+specified value is stored in the registers used for returning values
+of functions.
+
+The @code{return} command does not resume execution; it leaves the
+program stopped in the state that would exist if the function had just
+returned. In contrast, the @code{finish} command (@pxref{Continuing
+and Stepping, ,Continuing and stepping}) resumes execution until the
+selected stack frame returns naturally.
+
+@node Calling
+@section Calling program functions
+
+@cindex calling functions
+@kindex call
+@table @code
+@item call @var{expr}
+Evaluate the expression @var{expr} without displaying @code{void}
+returned values.
+@end table
+
+You can use this variant of the @code{print} command if you want to
+execute a function from your program, but without cluttering the output
+with @code{void} returned values. The result is printed and saved in
+the value history, if it is not void.
+
+@node Patching
+@section Patching programs
+@cindex patching binaries
+@cindex writing into executables
+@ifclear BARETARGET
+@cindex writing into corefiles
+@end ifclear
+
+By default, @value{GDBN} opens the file containing your program's executable
+code
+@ifclear BARETARGET
+(or the corefile)
+@end ifclear
+read-only. This prevents accidental alterations
+to machine code; but it also prevents you from intentionally patching
+your program's binary.
+
+If you'd like to be able to patch the binary, you can specify that
+explicitly with the @code{set write} command. For example, you might
+want to turn on internal debugging flags, or even to make emergency
+repairs.
+
+@table @code
+@item set write on
+@itemx set write off
+@kindex set write
+If you specify @samp{set write on}, @value{GDBN} will open executable
+@ifclear BARETARGET
+and core
+@end ifclear
+files for both reading and writing; if you specify @samp{set write
+off} (the default), @value{GDBN} will open them read-only.
+
+If you have already loaded a file, you must load it again (using the
+@code{exec-file}
+@ifclear BARETARGET
+or @code{core-file}
+@end ifclear
+command) after changing @code{set write}, for your new setting to take
+effect.
+
+@item show write
+@kindex show write
+Display whether executable files
+@ifclear BARETARGET
+and core files
+@end ifclear
+will be opened for writing as well as reading.
+@end table
+
+@node GDB Files
+@chapter @value{GDBN} Files
+
+@value{GDBN} needs to know the file name of the program to be debugged, both in
+order to read its symbol table and in order to start your program.
+@ifclear BARETARGET
+To debug a core dump of a previous run, you must also tell @value{GDBN}
+the name of the core dump file.
+@end ifclear
+
+@menu
+* Files:: Commands to specify files
+* Symbol Errors:: Errors reading symbol files
+@end menu
+
+@node Files
+@section Commands to specify files
+@cindex symbol table
+
+@ifclear BARETARGET
+@cindex core dump file
+The usual way to specify executable and core dump file names is with
+the command arguments given when you start @value{GDBN} (@pxref{Invocation,
+,Getting In and Out of @value{GDBN}}.
+@end ifclear
+@ifset BARETARGET
+The usual way to specify an executable file name is with
+the command argument given when you start @value{GDBN}, (@pxref{Invocation,
+,Getting In and Out of @value{GDBN}}.
+@end ifset
+
+Occasionally it is necessary to change to a different file during a
+@value{GDBN} session. Or you may run @value{GDBN} and forget to specify
+a file you want to use. In these situations the @value{GDBN} commands
+to specify new files are useful.
+
+@table @code
+@item file @var{filename}
+@cindex executable file
+@kindex file
+Use @var{filename} as the program to be debugged. It is read for its
+symbols and for the contents of pure memory. It is also the program
+executed when you use the @code{run} command. If you do not specify a
+directory and the file is not found in the @value{GDBN} working directory, @value{GDBN}
+uses the environment variable @code{PATH} as a list of directories to
+search, just as the shell does when looking for a program to run. You
+can change the value of this variable, for both @value{GDBN} and your program,
+using the @code{path} command.
+
+On systems with memory-mapped files, an auxiliary symbol table file
+@file{@var{filename}.syms} may be available for @var{filename}. If it
+is, @value{GDBN} will map in the symbol table from
+@file{@var{filename}.syms}, starting up more quickly. See the
+descriptions of the options @samp{-mapped} and @samp{-readnow} (available
+on the command line, and with the commands @code{file}, @code{symbol-file},
+or @code{add-symbol-file}), for more information.
+
+@item file
+@code{file} with no argument makes @value{GDBN} discard any information it
+has on both executable file and the symbol table.
+
+@item exec-file @r{[} @var{filename} @r{]}
+@kindex exec-file
+Specify that the program to be run (but not the symbol table) is found
+in @var{filename}. @value{GDBN} will search the environment variable @code{PATH}
+if necessary to locate your program. Omitting @var{filename} means to
+discard information on the executable file.
+
+@item symbol-file @r{[} @var{filename} @r{]}
+@kindex symbol-file
+Read symbol table information from file @var{filename}. @code{PATH} is
+searched when necessary. Use the @code{file} command to get both symbol
+table and program to run from the same file.
+
+@code{symbol-file} with no argument clears out @value{GDBN} information on your
+program's symbol table.
+
+The @code{symbol-file} command causes @value{GDBN} to forget the contents of its
+convenience variables, the value history, and all breakpoints and
+auto-display expressions. This is because they may contain pointers to
+the internal data recording symbols and data types, which are part of
+the old symbol table data being discarded inside @value{GDBN}.
+
+@code{symbol-file} will not repeat if you press @key{RET} again after
+executing it once.
+
+When @value{GDBN} is configured for a particular environment, it will
+understand debugging information in whatever format is the standard
+generated for that environment; you may use either a GNU compiler, or
+other compilers that adhere to the local conventions. Best results are
+usually obtained from GNU compilers; for example, using @code{@value{GCC}}
+you can generate debugging information for optimized code.
+
+On some kinds of object files, the @code{symbol-file} command does not
+normally read the symbol table in full right away. Instead, it scans
+the symbol table quickly to find which source files and which symbols
+are present. The details are read later, one source file at a time,
+as they are needed.
+
+The purpose of this two-stage reading strategy is to make @value{GDBN} start up
+faster. For the most part, it is invisible except for occasional
+pauses while the symbol table details for a particular source file are
+being read. (The @code{set verbose} command can turn these pauses
+into messages if desired. @xref{Messages/Warnings, ,Optional warnings
+and messages}.)
+
+We have not implemented the two-stage strategy for COFF yet. When the
+symbol table is stored in COFF format, @code{symbol-file} reads the
+symbol table data in full right away.
+
+@item symbol-file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@itemx file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@kindex readnow
+@cindex reading symbols immediately
+@cindex symbols, reading immediately
+@kindex mapped
+@cindex memory-mapped symbol file
+@cindex saving symbol table
+You can override the @value{GDBN} two-stage strategy for reading symbol
+tables by using the @samp{-readnow} option with any of the commands that
+load symbol table information, if you want to be sure @value{GDBN} has the
+entire symbol table available.
+
+@ifclear BARETARGET
+If memory-mapped files are available on your system through the
+@code{mmap} system call, you can use another option, @samp{-mapped}, to
+cause @value{GDBN} to write the symbols for your program into a reusable
+file. Future @value{GDBN} debugging sessions will map in symbol information
+from this auxiliary symbol file (if the program has not changed), rather
+than spending time reading the symbol table from the executable
+program. Using the @samp{-mapped} option has the same effect as
+starting @value{GDBN} with the @samp{-mapped} command-line option.
+
+You can use both options together, to make sure the auxiliary symbol
+file has all the symbol information for your program.
+
+The auxiliary symbol file for a program called @var{myprog} is called
+@samp{@var{myprog}.syms}. Once this file exists (so long as it is newer
+than the corresponding executable), @value{GDBN} will always attempt to use
+it when you debug @var{myprog}; no special options or commands are
+needed.
+
+The @file{.syms} file is specific to the host machine where you run
+@value{GDBN}. It holds an exact image of the internal @value{GDBN}
+symbol table. It cannot be shared across multiple host platforms.
+
+@c FIXME: for now no mention of directories, since this seems to be in
+@c flux. 13mar1992 status is that in theory GDB would look either in
+@c current dir or in same dir as myprog; but issues like competing
+@c GDB's, or clutter in system dirs, mean that in practice right now
+@c only current dir is used. FFish says maybe a special GDB hierarchy
+@c (eg rooted in val of env var GDBSYMS) could exist for mappable symbol
+@c files.
+
+@item core-file @r{[} @var{filename} @r{]}
+@kindex core
+@kindex core-file
+Specify the whereabouts of a core dump file to be used as the ``contents
+of memory''. Traditionally, core files contain only some parts of the
+address space of the process that generated them; @value{GDBN} can access the
+executable file itself for other parts.
+
+@code{core-file} with no argument specifies that no core file is
+to be used.
+
+Note that the core file is ignored when your program is actually running
+under @value{GDBN}. So, if you have been running your program and you wish to
+debug a core file instead, you must kill the subprocess in which the
+program is running. To do this, use the @code{kill} command
+(@pxref{Kill Process, ,Killing the child process}).
+@end ifclear
+
+@item load @var{filename}
+@kindex load
+@ifset GENERIC
+Depending on what remote debugging facilities are configured into
+@value{GDBN}, the @code{load} command may be available. Where it exists, it
+is meant to make @var{filename} (an executable) available for debugging
+on the remote system---by downloading, or dynamic linking, for example.
+@code{load} also records the @var{filename} symbol table in @value{GDBN}, like
+the @code{add-symbol-file} command.
+
+If your @value{GDBN} does not have a @code{load} command, attempting to
+execute it gets the error message ``@code{You can't do that when your
+target is @dots{}}''
+@end ifset
+
+The file is loaded at whatever address is specified in the executable.
+For some object file formats, like a.out, the object file format fixes
+the address and so it won't necessarily match the address you gave to
+the linker.
+
+@ifset VXWORKS
+On VxWorks, @code{load} will dynamically link @var{filename} on the
+current target system as well as adding its symbols in @value{GDBN}.
+@end ifset
+
+@ifset I960
+@cindex download to Nindy-960
+With the Nindy interface to an Intel 960 board, @code{load} will
+download @var{filename} to the 960 as well as adding its symbols in
+@value{GDBN}.
+@end ifset
+
+@ifset H8
+@cindex download to H8/300 or H8/500
+@cindex H8/300 or H8/500 download
+@cindex download to Hitachi SH
+@cindex Hitachi SH download
+When you select remote debugging to a Hitachi SH, H8/300, or H8/500 board
+(@pxref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}),
+the @code{load} command downloads your program to the Hitachi board and also
+opens it as the current executable target for @value{GDBN} on your host
+(like the @code{file} command).
+@end ifset
+
+@code{load} will not repeat if you press @key{RET} again after using it.
+
+@ifclear BARETARGET
+@item add-symbol-file @var{filename} @var{address}
+@itemx add-symbol-file @var{filename} @var{address} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@kindex add-symbol-file
+@cindex dynamic linking
+The @code{add-symbol-file} command reads additional symbol table information
+from the file @var{filename}. You would use this command when @var{filename}
+has been dynamically loaded (by some other means) into the program that
+is running. @var{address} should be the memory address at which the
+file has been loaded; @value{GDBN} cannot figure this out for itself.
+You can specify @var{address} as an expression.
+
+The symbol table of the file @var{filename} is added to the symbol table
+originally read with the @code{symbol-file} command. You can use the
+@code{add-symbol-file} command any number of times; the new symbol data thus
+read keeps adding to the old. To discard all old symbol data instead,
+use the @code{symbol-file} command.
+
+@code{add-symbol-file} will not repeat if you press @key{RET} after using it.
+
+You can use the @samp{-mapped} and @samp{-readnow} options just as with
+the @code{symbol-file} command, to change how @value{GDBN} manages the symbol
+table information for @var{filename}.
+@end ifclear
+
+@item info files
+@itemx info target
+@kindex info files
+@kindex info target
+@code{info files} and @code{info target} are synonymous; both print
+the current target (@pxref{Targets, ,Specifying a Debugging Target}),
+including the
+@ifclear BARETARGET
+names of the executable and core dump files
+@end ifclear
+@ifset BARETARGET
+name of the executable file
+@end ifset
+currently in use by @value{GDBN}, and the files from which symbols were
+loaded. The command @code{help targets} lists all possible targets
+rather than current ones.
+@end table
+
+All file-specifying commands allow both absolute and relative file names
+as arguments. @value{GDBN} always converts the file name to an absolute path
+name and remembers it that way.
+
+@ifclear BARETARGET
+@cindex shared libraries
+@value{GDBN} supports SunOS, SVR4, and IBM RS/6000 shared libraries.
+@value{GDBN} automatically loads symbol definitions from shared libraries
+when you use the @code{run} command, or when you examine a core file.
+(Before you issue the @code{run} command, @value{GDBN} will not understand
+references to a function in a shared library, however---unless you are
+debugging a core file).
+@c FIXME: next @value{GDBN} release should permit some refs to undef
+@c FIXME...symbols---eg in a break cmd---assuming they are from a shared lib
+
+@table @code
+@item info share
+@itemx info sharedlibrary
+@kindex info sharedlibrary
+@kindex info share
+Print the names of the shared libraries which are currently loaded.
+
+@item sharedlibrary @var{regex}
+@itemx share @var{regex}
+@kindex sharedlibrary
+@kindex share
+This is an obsolescent command; you can use it to explicitly load shared
+object library symbols for files matching a Unix regular expression, but
+as with files loaded automatically, it will only load shared libraries
+required by your program for a core file or after typing @code{run}. If
+@var{regex} is omitted all shared libraries required by your program are
+loaded.
+@end table
+@end ifclear
+
+@node Symbol Errors
+@section Errors reading symbol files
+
+While reading a symbol file, @value{GDBN} will occasionally encounter problems,
+such as symbol types it does not recognize, or known bugs in compiler
+output. By default, @value{GDBN} does not notify you of such problems, since
+they are relatively common and primarily of interest to people
+debugging compilers. If you are interested in seeing information
+about ill-constructed symbol tables, you can either ask @value{GDBN} to print
+only one message about each such type of problem, no matter how many
+times the problem occurs; or you can ask @value{GDBN} to print more messages,
+to see how many times the problems occur, with the @code{set
+complaints} command (@pxref{Messages/Warnings, ,Optional warnings and
+messages}).
+
+The messages currently printed, and their meanings, include:
+
+@table @code
+@item inner block not inside outer block in @var{symbol}
+
+The symbol information shows where symbol scopes begin and end
+(such as at the start of a function or a block of statements). This
+error indicates that an inner scope block is not fully contained
+in its outer scope blocks.
+
+@value{GDBN} circumvents the problem by treating the inner block as if it had
+the same scope as the outer block. In the error message, @var{symbol}
+may be shown as ``@code{(don't know)}'' if the outer block is not a
+function.
+
+@item block at @var{address} out of order
+
+The symbol information for symbol scope blocks should occur in
+order of increasing addresses. This error indicates that it does not
+do so.
+
+@value{GDBN} does not circumvent this problem, and will have trouble
+locating symbols in the source file whose symbols it is reading. (You
+can often determine what source file is affected by specifying
+@code{set verbose on}. @xref{Messages/Warnings, ,Optional warnings and
+messages}.)
+
+@item bad block start address patched
+
+The symbol information for a symbol scope block has a start address
+smaller than the address of the preceding source line. This is known
+to occur in the SunOS 4.1.1 (and earlier) C compiler.
+
+@value{GDBN} circumvents the problem by treating the symbol scope block as
+starting on the previous source line.
+
+@item bad string table offset in symbol @var{n}
+
+@cindex foo
+Symbol number @var{n} contains a pointer into the string table which is
+larger than the size of the string table.
+
+@value{GDBN} circumvents the problem by considering the symbol to have the
+name @code{foo}, which may cause other problems if many symbols end up
+with this name.
+
+@item unknown symbol type @code{0x@var{nn}}
+
+The symbol information contains new data types that @value{GDBN} does not yet
+know how to read. @code{0x@var{nn}} is the symbol type of the misunderstood
+information, in hexadecimal.
+
+@value{GDBN} circumvents the error by ignoring this symbol information. This
+will usually allow your program to be debugged, though certain symbols
+will not be accessible. If you encounter such a problem and feel like
+debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint on
+@code{complain}, then go up to the function @code{read_dbx_symtab} and
+examine @code{*bufp} to see the symbol.
+
+@item stub type has NULL name
+@value{GDBN} could not find the full definition for
+@ifclear CONLY
+a struct or class.
+@end ifclear
+@ifset CONLY
+a struct.
+@end ifset
+
+@ifclear CONLY
+@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{}
+
+The symbol information for a C++ member function is missing some
+information that recent versions of the compiler should have output
+for it.
+@end ifclear
+
+@item info mismatch between compiler and debugger
+
+@value{GDBN} could not parse a type specification output by the compiler.
+@end table
+
+@node Targets
+@chapter Specifying a Debugging Target
+@cindex debugging target
+@kindex target
+
+A @dfn{target} is the execution environment occupied by your program.
+@ifclear BARETARGET
+Often, @value{GDBN} runs in the same host environment as your program; in
+that case, the debugging target is specified as a side effect when you
+use the @code{file} or @code{core} commands. When you need more
+flexibility---for example, running @value{GDBN} on a physically separate
+host, or controlling a standalone system over a serial port or a
+realtime system over a TCP/IP connection---you
+@end ifclear
+@ifset BARETARGET
+You
+@end ifset
+can use the @code{target} command to specify one of the target types
+configured for @value{GDBN} (@pxref{Target Commands, ,Commands for managing
+targets}).
+
+@menu
+* Active Targets:: Active targets
+* Target Commands:: Commands for managing targets
+* Remote:: Remote debugging
+@end menu
+
+@node Active Targets
+@section Active targets
+@cindex stacking targets
+@cindex active targets
+@cindex multiple targets
+
+@ifclear BARETARGET
+There are three classes of targets: processes, core files, and
+executable files. @value{GDBN} can work concurrently on up to three active
+targets, one in each class. This allows you to (for example) start a
+process and inspect its activity without abandoning your work on a core
+file.
+
+For example, if you execute @samp{gdb a.out}, then the executable file
+@code{a.out} is the only active target. If you designate a core file as
+well---presumably from a prior run that crashed and coredumped---then
+@value{GDBN} has two active targets and will use them in tandem, looking
+first in the corefile target, then in the executable file, to satisfy
+requests for memory addresses. (Typically, these two classes of target
+are complementary, since core files contain only a program's
+read-write memory---variables and so on---plus machine status, while
+executable files contain only the program text and initialized data.)
+@end ifclear
+
+When you type @code{run}, your executable file becomes an active process
+target as well. When a process target is active, all @value{GDBN} commands
+requesting memory addresses refer to that target; addresses in an
+@ifclear BARETARGET
+active core file or
+@end ifclear
+executable file target are obscured while the process
+target is active.
+
+@ifset BARETARGET
+Use the @code{exec-file} command to select a
+new executable target (@pxref{Files, ,Commands to specify
+files}).
+@end ifset
+@ifclear BARETARGET
+Use the @code{core-file} and @code{exec-file} commands to select a
+new core file or executable target (@pxref{Files, ,Commands to specify
+files}). To specify as a target a process that is already running, use
+the @code{attach} command (@pxref{Attach, ,Debugging an
+already-running process}).
+@end ifclear
+
+@node Target Commands
+@section Commands for managing targets
+
+@table @code
+@item target @var{type} @var{parameters}
+Connects the @value{GDBN} host environment to a target
+@ifset BARETARGET
+machine.
+@end ifset
+@ifclear BARETARGET
+machine or process. A target is typically a protocol for talking to
+debugging facilities. You use the argument @var{type} to specify the
+type or protocol of the target machine.
+
+Further @var{parameters} are interpreted by the target protocol, but
+typically include things like device names or host names to connect
+with, process numbers, and baud rates.
+@end ifclear
+
+The @code{target} command will not repeat if you press @key{RET} again
+after executing the command.
+
+@item help target
+@kindex help target
+Displays the names of all targets available. To display targets
+currently selected, use either @code{info target} or @code{info files}
+(@pxref{Files, ,Commands to specify files}).
+
+@item help target @var{name}
+Describe a particular target, including any parameters necessary to
+select it.
+@end table
+
+Here are some common targets (available, or not, depending on the GDB
+configuration):
+
+@table @code
+@item target exec @var{program}
+@kindex target exec
+An executable file. @samp{target exec @var{program}} is the same as
+@samp{exec-file @var{program}}.
+
+@ifclear BARETARGET
+@item target core @var{filename}
+@kindex target core
+A core dump file. @samp{target core @var{filename}} is the same as
+@samp{core-file @var{filename}}.
+@end ifclear
+
+@ifset REMOTESTUB
+@item target remote @var{dev}
+@kindex target remote
+Remote serial target in GDB-specific protocol. The argument @var{dev}
+specifies what serial device to use for the connection (e.g.
+@file{/dev/ttya}). @xref{Remote, ,Remote debugging}.
+@end ifset
+
+@ifset SIMS
+@item target sim
+@kindex target sim
+CPU simulator. @xref{Simulator,,Simulated CPU Target}.
+@end ifset
+
+@ifset AMD29K
+@item target udi @var{keyword}
+@kindex target udi
+Remote AMD29K target, using the AMD UDI protocol. The @var{keyword}
+argument specifies which 29K board or simulator to use. @xref{UDI29K
+Remote,,@value{GDBN} and the UDI protocol for AMD29K}.
+
+@item target amd-eb @var{dev} @var{speed} @var{PROG}
+@kindex target amd-eb
+@cindex AMD EB29K
+Remote PC-resident AMD EB29K board, attached over serial lines.
+@var{dev} is the serial device, as for @code{target remote};
+@var{speed} allows you to specify the linespeed; and @var{PROG} is the
+name of the program to be debugged, as it appears to DOS on the PC.
+@xref{EB29K Remote, ,@value{GDBN} with a remote EB29K}.
+
+@end ifset
+@ifset H8
+@item target hms
+@kindex target hms
+A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host.
+@ifclear H8EXCLUSIVE
+@c Unix only, not currently of interest for H8-only manual
+Use special commands @code{device} and @code{speed} to control the serial
+line and the communications speed used.
+@end ifclear
+@xref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}.
+
+@end ifset
+@ifset I960
+@item target nindy @var{devicename}
+@kindex target nindy
+An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is
+the name of the serial device to use for the connection, e.g.
+@file{/dev/ttya}. @xref{i960-Nindy Remote, ,@value{GDBN} with a remote i960 (Nindy)}.
+
+@end ifset
+@ifset ST2000
+@item target st2000 @var{dev} @var{speed}
+@kindex target st2000
+A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. @var{dev}
+is the name of the device attached to the ST2000 serial line;
+@var{speed} is the communication line speed. The arguments are not used
+if @value{GDBN} is configured to connect to the ST2000 using TCP or Telnet.
+@xref{ST2000 Remote,,@value{GDBN} with a Tandem ST2000}.
+
+@end ifset
+@ifset VXWORKS
+@item target vxworks @var{machinename}
+@kindex target vxworks
+A VxWorks system, attached via TCP/IP. The argument @var{machinename}
+is the target system's machine name or IP address.
+@xref{VxWorks Remote, ,@value{GDBN} and VxWorks}.
+@end ifset
+@end table
+
+@ifset GENERIC
+Different targets are available on different configurations of @value{GDBN}; your
+configuration may have more or fewer targets.
+@end ifset
+
+@node Remote
+@section Remote debugging
+@cindex remote debugging
+
+If you are trying to debug a program running on a machine that cannot run
+GDB in the usual way, it is often useful to use remote debugging. For
+example, you might use remote debugging on an operating system kernel, or on
+a small system which does not have a general purpose operating system
+powerful enough to run a full-featured debugger.
+
+Some configurations of GDB have special serial or TCP/IP interfaces
+to make this work with particular debugging targets. In addition,
+GDB comes with a generic serial protocol (specific to GDB, but
+not specific to any particular target system) which you can use if you
+write the remote stubs---the code that will run on the remote system to
+communicate with GDB.
+
+Other remote targets may be available in your
+configuration of GDB; use @code{help targets} to list them.
+
+@ifset GENERIC
+@c Text on starting up GDB in various specific cases; it goes up front
+@c in manuals configured for any of those particular situations, here
+@c otherwise.
+@menu
+@ifset REMOTESTUB
+* Remote Serial:: @value{GDBN} remote serial protocol
+@end ifset
+@ifset I960
+* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy)
+@end ifset
+@ifset AMD29K
+* UDI29K Remote:: @value{GDBN} and the UDI protocol for AMD29K
+* EB29K Remote:: @value{GDBN} with a remote EB29K
+@end ifset
+@ifset VXWORKS
+* VxWorks Remote:: @value{GDBN} and VxWorks
+@end ifset
+@ifset ST2000
+* ST2000 Remote:: @value{GDBN} with a Tandem ST2000
+@end ifset
+@ifset H8
+* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors
+@end ifset
+@ifset MIPS
+* MIPS Remote:: @value{GDBN} and MIPS boards
+@end ifset
+@ifset SIMS
+* Simulator:: Simulated CPU target
+@end ifset
+@end menu
+
+@include remote.texi
+@end ifset
+
+@node Controlling GDB
+@chapter Controlling @value{GDBN}
+
+You can alter the way @value{GDBN} interacts with you by using
+the @code{set} command. For commands controlling how @value{GDBN} displays
+data, @pxref{Print Settings, ,Print settings}; other settings are described here.
+
+@menu
+* Prompt:: Prompt
+* Editing:: Command editing
+* History:: Command history
+* Screen Size:: Screen size
+* Numbers:: Numbers
+* Messages/Warnings:: Optional warnings and messages
+@end menu
+
+@node Prompt
+@section Prompt
+@cindex prompt
+
+@value{GDBN} indicates its readiness to read a command by printing a string
+called the @dfn{prompt}. This string is normally @samp{(@value{GDBP})}. You
+can change the prompt string with the @code{set prompt} command. For
+instance, when debugging @value{GDBN} with @value{GDBN}, it is useful to change
+the prompt in one of the @value{GDBN} sessions so that you can always tell which
+one you are talking to.
+
+@table @code
+@item set prompt @var{newprompt}
+@kindex set prompt
+Directs @value{GDBN} to use @var{newprompt} as its prompt string henceforth.
+@kindex show prompt
+@item show prompt
+Prints a line of the form: @samp{Gdb's prompt is: @var{your-prompt}}
+@end table
+
+@node Editing
+@section Command editing
+@cindex readline
+@cindex command line editing
+
+@value{GDBN} reads its input commands via the @dfn{readline} interface. This
+GNU library provides consistent behavior for programs which provide a
+command line interface to the user. Advantages are @code{emacs}-style
+or @code{vi}-style inline editing of commands, @code{csh}-like history
+substitution, and a storage and recall of command history across
+debugging sessions.
+
+You may control the behavior of command line editing in @value{GDBN} with the
+command @code{set}.
+
+@table @code
+@kindex set editing
+@cindex editing
+@item set editing
+@itemx set editing on
+Enable command line editing (enabled by default).
+
+@item set editing off
+Disable command line editing.
+
+@kindex show editing
+@item show editing
+Show whether command line editing is enabled.
+@end table
+
+@node History
+@section Command history
+
+@value{GDBN} can keep track of the commands you type during your
+debugging sessions, so that you can be certain of precisely what
+happened. Use these commands to manage the @value{GDBN} command
+history facility.
+
+@table @code
+@cindex history substitution
+@cindex history file
+@kindex set history filename
+@item set history filename @var{fname}
+Set the name of the @value{GDBN} command history file to @var{fname}. This is
+the file from which @value{GDBN} will read an initial command history
+list or to which it will write this list when it exits. This list is
+accessed through history expansion or through the history
+command editing characters listed below. This file defaults to the
+value of the environment variable @code{GDBHISTFILE}, or to
+@file{./.gdb_history} if this variable is not set.
+
+@cindex history save
+@kindex set history save
+@item set history save
+@itemx set history save on
+Record command history in a file, whose name may be specified with the
+@code{set history filename} command. By default, this option is disabled.
+
+@item set history save off
+Stop recording command history in a file.
+
+@cindex history size
+@kindex set history size
+@item set history size @var{size}
+Set the number of commands which @value{GDBN} will keep in its history list.
+This defaults to the value of the environment variable
+@code{HISTSIZE}, or to 256 if this variable is not set.
+@end table
+
+@cindex history expansion
+History expansion assigns special meaning to the character @kbd{!}.
+@ifset have-readline-appendices
+@xref{Event Designators}.
+@end ifset
+
+Since @kbd{!} is also the logical not operator in C, history expansion
+is off by default. If you decide to enable history expansion with the
+@code{set history expansion on} command, you may sometimes need to
+follow @kbd{!} (when it is used as logical not, in an expression) with
+a space or a tab to prevent it from being expanded. The readline
+history facilities will not attempt substitution on the strings
+@kbd{!=} and @kbd{!(}, even when history expansion is enabled.
+
+The commands to control history expansion are:
+
+@table @code
+
+@kindex set history expansion
+@item set history expansion on
+@itemx set history expansion
+Enable history expansion. History expansion is off by default.
+
+@item set history expansion off
+Disable history expansion.
+
+The readline code comes with more complete documentation of
+editing and history expansion features. Users unfamiliar with @code{emacs}
+or @code{vi} may wish to read it.
+@ifset have-readline-appendices
+@xref{Command Line Editing}.
+@end ifset
+
+@c @group
+@kindex show history
+@item show history
+@itemx show history filename
+@itemx show history save
+@itemx show history size
+@itemx show history expansion
+These commands display the state of the @value{GDBN} history parameters.
+@code{show history} by itself displays all four states.
+@c @end group
+@end table
+
+@table @code
+@kindex show commands
+@item show commands
+Display the last ten commands in the command history.
+
+@item show commands @var{n}
+Print ten commands centered on command number @var{n}.
+
+@item show commands +
+Print ten commands just after the commands last printed.
+@end table
+
+@node Screen Size
+@section Screen size
+@cindex size of screen
+@cindex pauses in output
+
+Certain commands to @value{GDBN} may produce large amounts of
+information output to the screen. To help you read all of it,
+@value{GDBN} pauses and asks you for input at the end of each page of
+output. Type @key{RET} when you want to continue the output, or @kbd{q}
+to discard the remaining output. Also, the screen width setting
+determines when to wrap lines of output. Depending on what is being
+printed, @value{GDBN} tries to break the line at a readable place,
+rather than simply letting it overflow onto the following line.
+
+Normally @value{GDBN} knows the size of the screen from the termcap data base
+together with the value of the @code{TERM} environment variable and the
+@code{stty rows} and @code{stty cols} settings. If this is not correct,
+you can override it with the @code{set height} and @code{set
+width} commands:
+
+@table @code
+@item set height @var{lpp}
+@itemx show height
+@itemx set width @var{cpl}
+@itemx show width
+@kindex set height
+@kindex set width
+@kindex show width
+@kindex show height
+These @code{set} commands specify a screen height of @var{lpp} lines and
+a screen width of @var{cpl} characters. The associated @code{show}
+commands display the current settings.
+
+If you specify a height of zero lines, @value{GDBN} will not pause during output
+no matter how long the output is. This is useful if output is to a file
+or to an editor buffer.
+
+Likewise, you can specify @samp{set width 0} to prevent @value{GDBN}
+from wrapping its output.
+@end table
+
+@node Numbers
+@section Numbers
+@cindex number representation
+@cindex entering numbers
+
+You can always enter numbers in octal, decimal, or hexadecimal in @value{GDBN} by
+the usual conventions: octal numbers begin with @samp{0}, decimal
+numbers end with @samp{.}, and hexadecimal numbers begin with @samp{0x}.
+Numbers that begin with none of these are, by default, entered in base
+10; likewise, the default display for numbers---when no particular
+format is specified---is base 10. You can change the default base for
+both input and output with the @code{set radix} command.
+
+@table @code
+@kindex set radix
+@item set radix @var{base}
+Set the default base for numeric input and display. Supported choices
+for @var{base} are decimal 8, 10, or 16. @var{base} must itself be
+specified either unambiguously or using the current default radix; for
+example, any of
+
+@example
+set radix 012
+set radix 10.
+set radix 0xa
+@end example
+
+@noindent
+will set the base to decimal. On the other hand, @samp{set radix 10}
+will leave the radix unchanged no matter what it was.
+
+@kindex show radix
+@item show radix
+Display the current default base for numeric input and display.
+@end table
+
+@node Messages/Warnings
+@section Optional warnings and messages
+
+By default, @value{GDBN} is silent about its inner workings. If you are running
+on a slow machine, you may want to use the @code{set verbose} command.
+It will make @value{GDBN} tell you when it does a lengthy internal operation, so
+you will not think it has crashed.
+
+Currently, the messages controlled by @code{set verbose} are those
+which announce that the symbol table for a source file is being read;
+see @code{symbol-file} in @ref{Files, ,Commands to specify files}.
+
+@table @code
+@kindex set verbose
+@item set verbose on
+Enables @value{GDBN} output of certain informational messages.
+
+@item set verbose off
+Disables @value{GDBN} output of certain informational messages.
+
+@kindex show verbose
+@item show verbose
+Displays whether @code{set verbose} is on or off.
+@end table
+
+By default, if @value{GDBN} encounters bugs in the symbol table of an object
+file, it is silent; but if you are debugging a compiler, you may find
+this information useful (@pxref{Symbol Errors, ,Errors reading symbol files}).
+
+@table @code
+@kindex set complaints
+@item set complaints @var{limit}
+Permits @value{GDBN} to output @var{limit} complaints about each type of unusual
+symbols before becoming silent about the problem. Set @var{limit} to
+zero to suppress all complaints; set it to a large number to prevent
+complaints from being suppressed.
+
+@kindex show complaints
+@item show complaints
+Displays how many symbol complaints @value{GDBN} is permitted to produce.
+@end table
+
+By default, @value{GDBN} is cautious, and asks what sometimes seems to be a
+lot of stupid questions to confirm certain commands. For example, if
+you try to run a program which is already running:
+
+@example
+(@value{GDBP}) run
+The program being debugged has been started already.
+Start it from the beginning? (y or n)
+@end example
+
+If you are willing to unflinchingly face the consequences of your own
+commands, you can disable this ``feature'':
+
+@table @code
+@kindex set confirm
+@cindex flinching
+@cindex confirmation
+@cindex stupid questions
+@item set confirm off
+Disables confirmation requests.
+
+@item set confirm on
+Enables confirmation requests (the default).
+
+@item show confirm
+@kindex show confirm
+Displays state of confirmation requests.
+@end table
+
+@c FIXME this does not really belong here. But where *does* it belong?
+@cindex reloading symbols
+Some systems allow individual object files that make up your program to
+be replaced without stopping and restarting your program.
+@ifset VXWORKS
+For example, in VxWorks you can simply recompile a defective object file
+and keep on running.
+@end ifset
+If you are running on one of these systems, you can allow @value{GDBN} to
+reload the symbols for automatically relinked modules:
+
+@table @code
+@kindex set symbol-reloading
+@item set symbol-reloading on
+Replace symbol definitions for the corresponding source file when an
+object file with a particular name is seen again.
+
+@item set symbol-reloading off
+Do not replace symbol definitions when re-encountering object files of
+the same name. This is the default state; if you are not running on a
+system that permits automatically relinking modules, you should leave
+@code{symbol-reloading} off, since otherwise @value{GDBN} may discard symbols
+when linking large programs, that may contain several modules (from
+different directories or libraries) with the same name.
+
+@item show symbol-reloading
+Show the current @code{on} or @code{off} setting.
+@end table
+
+@node Sequences
+@chapter Canned Sequences of Commands
+
+Aside from breakpoint commands (@pxref{Break Commands, ,Breakpoint
+command lists}), @value{GDBN} provides two ways to store sequences of commands
+for execution as a unit: user-defined commands and command files.
+
+@menu
+* Define:: User-defined commands
+* Hooks:: User-defined command hooks
+* Command Files:: Command files
+* Output:: Commands for controlled output
+@end menu
+
+@node Define
+@section User-defined commands
+
+@cindex user-defined command
+A @dfn{user-defined command} is a sequence of @value{GDBN} commands to which you
+assign a new name as a command. This is done with the @code{define}
+command.
+
+@table @code
+@item define @var{commandname}
+@kindex define
+Define a command named @var{commandname}. If there is already a command
+by that name, you are asked to confirm that you want to redefine it.
+
+The definition of the command is made up of other @value{GDBN} command lines,
+which are given following the @code{define} command. The end of these
+commands is marked by a line containing @code{end}.
+
+@item document @var{commandname}
+@kindex document
+Give documentation to the user-defined command @var{commandname}. The
+command @var{commandname} must already be defined. This command reads
+lines of documentation just as @code{define} reads the lines of the
+command definition, ending with @code{end}. After the @code{document}
+command is finished, @code{help} on command @var{commandname} will print
+the documentation you have specified.
+
+You may use the @code{document} command again to change the
+documentation of a command. Redefining the command with @code{define}
+does not change the documentation.
+
+@item help user-defined
+@kindex help user-defined
+List all user-defined commands, with the first line of the documentation
+(if any) for each.
+
+@item show user
+@itemx show user @var{commandname}
+@kindex show user
+Display the @value{GDBN} commands used to define @var{commandname} (but not its
+documentation). If no @var{commandname} is given, display the
+definitions for all user-defined commands.
+@end table
+
+User-defined commands do not take arguments. When they are executed, the
+commands of the definition are not printed. An error in any command
+stops execution of the user-defined command.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used inside a user-defined command. Many @value{GDBN} commands
+that normally print messages to say what they are doing omit the messages
+when used in a user-defined command.
+
+@node Hooks
+@section User-defined command hooks
+@cindex command files
+
+You may define @emph{hooks}, which are a special kind of user-defined
+command. Whenever you run the command @samp{foo}, if the user-defined
+command @samp{hook-foo} exists, it is executed (with no arguments)
+before that command.
+
+In addition, a pseudo-command, @samp{stop} exists. Defining
+(@samp{hook-stop}) makes the associated commands execute every time
+execution stops in your program: before breakpoint commands are run,
+displays are printed, or the stack frame is printed.
+
+@ifclear BARETARGET
+For example, to ignore @code{SIGALRM} signals while
+single-stepping, but treat them normally during normal execution,
+you could define:
+
+@example
+define hook-stop
+handle SIGALRM nopass
+end
+
+define hook-run
+handle SIGALRM pass
+end
+
+define hook-continue
+handle SIGLARM pass
+end
+@end example
+@end ifclear
+
+You can define a hook for any single-word command in @value{GDBN}, but
+not for command aliases; you should define a hook for the basic command
+name, e.g. @code{backtrace} rather than @code{bt}.
+@c FIXME! So how does Joe User discover whether a command is an alias
+@c or not?
+If an error occurs during the execution of your hook, execution of
+@value{GDBN} commands stops and @value{GDBN} issues a prompt
+(before the command that you actually typed had a chance to run).
+
+If you try to define a hook which does not match any known command, you
+will get a warning from the @code{define} command.
+
+@node Command Files
+@section Command files
+
+@cindex command files
+A command file for @value{GDBN} is a file of lines that are @value{GDBN} commands. Comments
+(lines starting with @kbd{#}) may also be included. An empty line in a
+command file does nothing; it does not mean to repeat the last command, as
+it would from the terminal.
+
+@cindex init file
+@cindex @file{@value{GDBINIT}}
+When you start @value{GDBN}, it automatically executes commands from its
+@dfn{init files}. These are files named @file{@value{GDBINIT}}. @value{GDBN} reads
+the init file (if any) in your home directory and then the init file
+(if any) in the current working directory. (The init files are not
+executed if you use the @samp{-nx} option; @pxref{Mode Options,
+,Choosing modes}.)
+
+@ifset GENERIC
+@cindex init file name
+On some configurations of @value{GDBN}, the init file is known by a
+different name (these are typically environments where a specialized
+form of GDB may need to coexist with other forms, hence a different name
+for the specialized version's init file). These are the environments
+with special init file names:
+
+@itemize @bullet
+@kindex .vxgdbinit
+@item
+VxWorks (Wind River Systems real-time OS): @samp{.vxgdbinit}
+
+@kindex .os68gdbinit
+@item
+OS68K (Enea Data Systems real-time OS): @samp{.os68gdbinit}
+
+@kindex .esgdbinit
+@item
+ES-1800 (Ericsson Telecom AB M68000 emulator): @samp{.esgdbinit}
+@end itemize
+@end ifset
+
+You can also request the execution of a command file with the
+@code{source} command:
+
+@table @code
+@item source @var{filename}
+@kindex source
+Execute the command file @var{filename}.
+@end table
+
+The lines in a command file are executed sequentially. They are not
+printed as they are executed. An error in any command terminates execution
+of the command file.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used in a command file. Many @value{GDBN} commands that
+normally print messages to say what they are doing omit the messages
+when called from command files.
+
+@node Output
+@section Commands for controlled output
+
+During the execution of a command file or a user-defined command, normal
+@value{GDBN} output is suppressed; the only output that appears is what is
+explicitly printed by the commands in the definition. This section
+describes three commands useful for generating exactly the output you
+want.
+
+@table @code
+@item echo @var{text}
+@kindex echo
+@c I do not consider backslash-space a standard C escape sequence
+@c because it is not in ANSI.
+Print @var{text}. Nonprinting characters can be included in
+@var{text} using C escape sequences, such as @samp{\n} to print a
+newline. @strong{No newline will be printed unless you specify one.}
+In addition to the standard C escape sequences, a backslash followed
+by a space stands for a space. This is useful for displaying a
+string with spaces at the beginning or the end, since leading and
+trailing spaces are otherwise trimmed from all arguments.
+To print @samp{@w{ }and foo =@w{ }}, use the command
+@samp{echo \@w{ }and foo = \@w{ }}.
+
+A backslash at the end of @var{text} can be used, as in C, to continue
+the command onto subsequent lines. For example,
+
+@example
+echo This is some text\n\
+which is continued\n\
+onto several lines.\n
+@end example
+
+produces the same output as
+
+@example
+echo This is some text\n
+echo which is continued\n
+echo onto several lines.\n
+@end example
+
+@item output @var{expression}
+@kindex output
+Print the value of @var{expression} and nothing but that value: no
+newlines, no @samp{$@var{nn} = }. The value is not entered in the
+value history either. @xref{Expressions, ,Expressions}, for more information on
+expressions.
+
+@item output/@var{fmt} @var{expression}
+Print the value of @var{expression} in format @var{fmt}. You can use
+the same formats as for @code{print}. @xref{Output Formats,,Output
+formats}, for more information.
+
+@item printf @var{string}, @var{expressions}@dots{}
+@kindex printf
+Print the values of the @var{expressions} under the control of
+@var{string}. The @var{expressions} are separated by commas and may be
+either numbers or pointers. Their values are printed as specified by
+@var{string}, exactly as if your program were to execute the C
+subroutine
+
+@example
+printf (@var{string}, @var{expressions}@dots{});
+@end example
+
+For example, you can print two values in hex like this:
+
+@smallexample
+printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+@end smallexample
+
+The only backslash-escape sequences that you can use in the format
+string are the simple ones that consist of backslash followed by a
+letter.
+@end table
+
+@ifclear DOSHOST
+@node Emacs
+@chapter Using @value{GDBN} under GNU Emacs
+
+@cindex emacs
+A special interface allows you to use GNU Emacs to view (and
+edit) the source files for the program you are debugging with
+@value{GDBN}.
+
+To use this interface, use the command @kbd{M-x gdb} in Emacs. Give the
+executable file you want to debug as an argument. This command starts
+@value{GDBN} as a subprocess of Emacs, with input and output through a newly
+created Emacs buffer.
+
+Using @value{GDBN} under Emacs is just like using @value{GDBN} normally except for two
+things:
+
+@itemize @bullet
+@item
+All ``terminal'' input and output goes through the Emacs buffer.
+@end itemize
+
+This applies both to @value{GDBN} commands and their output, and to the input
+and output done by the program you are debugging.
+
+This is useful because it means that you can copy the text of previous
+commands and input them again; you can even use parts of the output
+in this way.
+
+All the facilities of Emacs' Shell mode are available for interacting
+with your program. In particular, you can send signals the usual
+way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a
+stop.
+
+@itemize @bullet
+@item
+@value{GDBN} displays source code through Emacs.
+@end itemize
+
+Each time @value{GDBN} displays a stack frame, Emacs automatically finds the
+source file for that frame and puts an arrow (@samp{=>}) at the
+left margin of the current line. Emacs uses a separate buffer for
+source display, and splits the screen to show both your @value{GDBN} session
+and the source.
+
+Explicit @value{GDBN} @code{list} or search commands still produce output as
+usual, but you probably will have no reason to use them.
+
+@quotation
+@emph{Warning:} If the directory where your program resides is not your
+current directory, it can be easy to confuse Emacs about the location of
+the source files, in which case the auxiliary display buffer will not
+appear to show your source. @value{GDBN} can find programs by searching your
+environment's @code{PATH} variable, so the @value{GDBN} input and output
+session will proceed normally; but Emacs does not get enough information
+back from @value{GDBN} to locate the source files in this situation. To
+avoid this problem, either start @value{GDBN} mode from the directory where
+your program resides, or specify a full path name when prompted for the
+@kbd{M-x gdb} argument.
+
+A similar confusion can result if you use the @value{GDBN} @code{file} command to
+switch to debugging a program in some other location, from an existing
+@value{GDBN} buffer in Emacs.
+@end quotation
+
+By default, @kbd{M-x gdb} calls the program called @file{gdb}. If
+you need to call @value{GDBN} by a different name (for example, if you keep
+several configurations around, with different names) you can set the
+Emacs variable @code{gdb-command-name}; for example,
+
+@example
+(setq gdb-command-name "mygdb")
+@end example
+
+@noindent
+(preceded by @kbd{ESC ESC}, or typed in the @code{*scratch*} buffer, or
+in your @file{.emacs} file) will make Emacs call the program named
+``@code{mygdb}'' instead.
+
+In the @value{GDBN} I/O buffer, you can use these special Emacs commands in
+addition to the standard Shell mode commands:
+
+@table @kbd
+@item C-h m
+Describe the features of Emacs' @value{GDBN} Mode.
+
+@item M-s
+Execute to another source line, like the @value{GDBN} @code{step} command; also
+update the display window to show the current file and location.
+
+@item M-n
+Execute to next source line in this function, skipping all function
+calls, like the @value{GDBN} @code{next} command. Then update the display window
+to show the current file and location.
+
+@item M-i
+Execute one instruction, like the @value{GDBN} @code{stepi} command; update
+display window accordingly.
+
+@item M-x gdb-nexti
+Execute to next instruction, using the @value{GDBN} @code{nexti} command; update
+display window accordingly.
+
+@item C-c C-f
+Execute until exit from the selected stack frame, like the @value{GDBN}
+@code{finish} command.
+
+@item M-c
+Continue execution of your program, like the @value{GDBN} @code{continue}
+command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-p}.
+
+@item M-u
+Go up the number of frames indicated by the numeric argument
+(@pxref{Arguments, , Numeric Arguments, emacs, The GNU Emacs Manual}),
+like the @value{GDBN} @code{up} command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-u}.
+
+@item M-d
+Go down the number of frames indicated by the numeric argument, like the
+@value{GDBN} @code{down} command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-d}.
+
+@item C-x &
+Read the number where the cursor is positioned, and insert it at the end
+of the @value{GDBN} I/O buffer. For example, if you wish to disassemble code
+around an address that was displayed earlier, type @kbd{disassemble};
+then move the cursor to the address display, and pick up the
+argument for @code{disassemble} by typing @kbd{C-x &}.
+
+You can customize this further by defining elements of the list
+@code{gdb-print-command}; once it is defined, you can format or
+otherwise process numbers picked up by @kbd{C-x &} before they are
+inserted. A numeric argument to @kbd{C-x &} will both indicate that you
+wish special formatting, and act as an index to pick an element of the
+list. If the list element is a string, the number to be inserted is
+formatted using the Emacs function @code{format}; otherwise the number
+is passed as an argument to the corresponding list element.
+@end table
+
+In any source file, the Emacs command @kbd{C-x SPC} (@code{gdb-break})
+tells @value{GDBN} to set a breakpoint on the source line point is on.
+
+If you accidentally delete the source-display buffer, an easy way to get
+it back is to type the command @code{f} in the @value{GDBN} buffer, to
+request a frame display; when you run under Emacs, this will recreate
+the source buffer if necessary to show you the context of the current
+frame.
+
+The source files displayed in Emacs are in ordinary Emacs buffers
+which are visiting the source files in the usual way. You can edit
+the files with these buffers if you wish; but keep in mind that @value{GDBN}
+communicates with Emacs in terms of line numbers. If you add or
+delete lines from the text, the line numbers that @value{GDBN} knows will cease
+to correspond properly with the code.
+
+@c The following dropped because Epoch is nonstandard. Reactivate
+@c if/when v19 does something similar. ---pesch@cygnus.com 19dec1990
+@ignore
+@kindex emacs epoch environment
+@kindex epoch
+@kindex inspect
+
+Version 18 of Emacs has a built-in window system called the @code{epoch}
+environment. Users of this environment can use a new command,
+@code{inspect} which performs identically to @code{print} except that
+each value is printed in its own window.
+@end ignore
+@end ifclear
+
+@ifset LUCID
+@node Energize
+@chapter Using @value{GDBN} with Energize
+
+@cindex Energize
+The Energize Programming System is an integrated development environment
+that includes a point-and-click interface to many programming tools.
+When you use @value{GDBN} in this environment, you can use the standard
+Energize graphical interface to drive @value{GDBN}; you can also, if you
+choose, type @value{GDBN} commands as usual in a debugging window. Even if
+you use the graphical interface, the debugging window (which uses Emacs,
+and resembles the standard Emacs interface to @value{GDBN}) displays the
+equivalent commands, so that the history of your debugging session is
+properly reflected.
+
+When Energize starts up a @value{GDBN} session, it uses one of the
+command-line options @samp{-energize} or @samp{-cadillac} (``cadillac''
+is the name of the communications protocol used by the Energize system).
+This option makes @value{GDBN} run as one of the tools in the Energize Tool
+Set: it sends all output to the Energize kernel, and accept input from
+it as well.
+
+See the user manual for the Energize Programming System for
+information on how to use the Energize graphical interface and the other
+development tools that Energize integrates with @value{GDBN}.
+
+@end ifset
+
+@node GDB Bugs
+@chapter Reporting Bugs in @value{GDBN}
+@cindex bugs in @value{GDBN}
+@cindex reporting bugs in @value{GDBN}
+
+Your bug reports play an essential role in making @value{GDBN} reliable.
+
+Reporting a bug may help you by bringing a solution to your problem, or it
+may not. But in any case the principal function of a bug report is to help
+the entire community by making the next version of @value{GDBN} work better. Bug
+reports are your contribution to the maintenance of @value{GDBN}.
+
+In order for a bug report to serve its purpose, you must include the
+information that enables us to fix the bug.
+
+@menu
+* Bug Criteria:: Have you found a bug?
+* Bug Reporting:: How to report bugs
+@end menu
+
+@node Bug Criteria
+@section Have you found a bug?
+@cindex bug criteria
+
+If you are not sure whether you have found a bug, here are some guidelines:
+
+@itemize @bullet
+@item
+@cindex fatal signal
+@cindex debugger crash
+@cindex crash of debugger
+If the debugger gets a fatal signal, for any input whatever, that is a
+@value{GDBN} bug. Reliable debuggers never crash.
+
+@item
+@cindex error on valid input
+If @value{GDBN} produces an error message for valid input, that is a bug.
+
+@item
+@cindex invalid input
+If @value{GDBN} does not produce an error message for invalid input,
+that is a bug. However, you should note that your idea of
+``invalid input'' might be our idea of ``an extension'' or ``support
+for traditional practice''.
+
+@item
+If you are an experienced user of debugging tools, your suggestions
+for improvement of @value{GDBN} are welcome in any case.
+@end itemize
+
+@node Bug Reporting
+@section How to report bugs
+@cindex bug reports
+@cindex @value{GDBN} bugs, reporting
+
+A number of companies and individuals offer support for GNU products.
+If you obtained @value{GDBN} from a support organization, we recommend you
+contact that organization first.
+
+You can find contact information for many support companies and
+individuals in the file @file{etc/SERVICE} in the GNU Emacs
+distribution.
+
+In any event, we also recommend that you send bug reports for @value{GDBN} to one
+of these addresses:
+
+@example
+bug-gdb@@prep.ai.mit.edu
+@{ucbvax|mit-eddie|uunet@}!prep.ai.mit.edu!bug-gdb
+@end example
+
+@strong{Do not send bug reports to @samp{info-gdb}, or to
+@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do not want to
+receive bug reports. Those that do, have arranged to receive @samp{bug-gdb}.
+
+The mailing list @samp{bug-gdb} has a newsgroup @samp{gnu.gdb.bug} which
+serves as a repeater. The mailing list and the newsgroup carry exactly
+the same messages. Often people think of posting bug reports to the
+newsgroup instead of mailing them. This appears to work, but it has one
+problem which can be crucial: a newsgroup posting often lacks a mail
+path back to the sender. Thus, if we need to ask for more information,
+we may be unable to reach you. For this reason, it is better to send
+bug reports to the mailing list.
+
+As a last resort, send bug reports on paper to:
+
+@example
+GNU Debugger Bugs
+Free Software Foundation
+545 Tech Square
+Cambridge, MA 02139
+@end example
+
+The fundamental principle of reporting bugs usefully is this:
+@strong{report all the facts}. If you are not sure whether to state a
+fact or leave it out, state it!
+
+Often people omit facts because they think they know what causes the
+problem and assume that some details do not matter. Thus, you might
+assume that the name of the variable you use in an example does not matter.
+Well, probably it does not, but one cannot be sure. Perhaps the bug is a
+stray memory reference which happens to fetch from the location where that
+name is stored in memory; perhaps, if the name were different, the contents
+of that location would fool the debugger into doing the right thing despite
+the bug. Play it safe and give a specific, complete example. That is the
+easiest thing for you to do, and the most helpful.
+
+Keep in mind that the purpose of a bug report is to enable us to fix
+the bug if it is new to us. It is not as important as what happens if
+the bug is already known. Therefore, always write your bug reports on
+the assumption that the bug has not been reported previously.
+
+Sometimes people give a few sketchy facts and ask, ``Does this ring a
+bell?'' Those bug reports are useless, and we urge everyone to
+@emph{refuse to respond to them} except to chide the sender to report
+bugs properly.
+
+To enable us to fix the bug, you should include all these things:
+
+@itemize @bullet
+@item
+The version of @value{GDBN}. @value{GDBN} announces it if you start with no
+arguments; you can also print it at any time using @code{show version}.
+
+Without this, we will not know whether there is any point in looking for
+the bug in the current version of @value{GDBN}.
+
+@item
+The type of machine you are using, and the operating system name and
+version number.
+
+@item
+What compiler (and its version) was used to compile @value{GDBN}---e.g.
+``@value{GCC}--2.0''.
+
+@item
+What compiler (and its version) was used to compile the program you
+are debugging---e.g. ``@value{GCC}--2.0''.
+
+@item
+The command arguments you gave the compiler to compile your example and
+observe the bug. For example, did you use @samp{-O}? To guarantee
+you will not omit something important, list them all. A copy of the
+Makefile (or the output from make) is sufficient.
+
+If we were to try to guess the arguments, we would probably guess wrong
+and then we might not encounter the bug.
+
+@item
+A complete input script, and all necessary source files, that will
+reproduce the bug.
+
+@item
+A description of what behavior you observe that you believe is
+incorrect. For example, ``It gets a fatal signal.''
+
+Of course, if the bug is that @value{GDBN} gets a fatal signal, then we will
+certainly notice it. But if the bug is incorrect output, we might not
+notice unless it is glaringly wrong. We are human, after all. You
+might as well not give us a chance to make a mistake.
+
+Even if the problem you experience is a fatal signal, you should still
+say so explicitly. Suppose something strange is going on, such as,
+your copy of @value{GDBN} is out of synch, or you have encountered a
+bug in the C library on your system. (This has happened!) Your copy
+might crash and ours would not. If you told us to expect a crash,
+then when ours fails to crash, we would know that the bug was not
+happening for us. If you had not told us to expect a crash, then we
+would not be able to draw any conclusion from our observations.
+
+@item
+If you wish to suggest changes to the @value{GDBN} source, send us context
+diffs. If you even discuss something in the @value{GDBN} source, refer to
+it by context, not by line number.
+
+The line numbers in our development sources will not match those in your
+sources. Your line numbers would convey no useful information to us.
+@end itemize
+
+Here are some things that are not necessary:
+
+@itemize @bullet
+@item
+A description of the envelope of the bug.
+
+Often people who encounter a bug spend a lot of time investigating
+which changes to the input file will make the bug go away and which
+changes will not affect it.
+
+This is often time consuming and not very useful, because the way we
+will find the bug is by running a single example under the debugger
+with breakpoints, not by pure deduction from a series of examples.
+We recommend that you save your time for something else.
+
+Of course, if you can find a simpler example to report @emph{instead}
+of the original one, that is a convenience for us. Errors in the
+output will be easier to spot, running under the debugger will take
+less time, etc.
+
+However, simplification is not vital; if you do not want to do this,
+report the bug anyway and send us the entire test case you used.
+
+@item
+A patch for the bug.
+
+A patch for the bug does help us if it is a good one. But do not omit
+the necessary information, such as the test case, on the assumption that
+a patch is all we need. We might see problems with your patch and decide
+to fix the problem another way, or we might not understand it at all.
+
+Sometimes with a program as complicated as @value{GDBN} it is very hard to
+construct an example that will make the program follow a certain path
+through the code. If you do not send us the example, we will not be able
+to construct one, so we will not be able to verify that the bug is fixed.
+
+And if we cannot understand what bug you are trying to fix, or why your
+patch should be an improvement, we will not install it. A test case will
+help us to understand.
+
+@item
+A guess about what the bug is or what it depends on.
+
+Such guesses are usually wrong. Even we cannot guess right about such
+things without first using the debugger to find the facts.
+@end itemize
+
+@c The readline documentation is distributed with the readline code
+@c and consists of the two following files:
+@c rluser.texinfo
+@c inc-hist.texi
+@c Use -I with makeinfo to point to the appropriate directory,
+@c environment var TEXINPUTS with TeX.
+@include rluser.texinfo
+@include inc-hist.texi
+
+@ifset NOVEL
+@node Renamed Commands
+@appendix Renamed Commands
+
+The following commands were renamed in GDB 4, in order to make the
+command set as a whole more consistent and easier to use and remember:
+
+@kindex add-syms
+@kindex delete environment
+@kindex info copying
+@kindex info convenience
+@kindex info directories
+@kindex info editing
+@kindex info history
+@kindex info targets
+@kindex info values
+@kindex info version
+@kindex info warranty
+@kindex set addressprint
+@kindex set arrayprint
+@kindex set prettyprint
+@kindex set screen-height
+@kindex set screen-width
+@kindex set unionprint
+@kindex set vtblprint
+@kindex set demangle
+@kindex set asm-demangle
+@kindex set sevenbit-strings
+@kindex set array-max
+@kindex set caution
+@kindex set history write
+@kindex show addressprint
+@kindex show arrayprint
+@kindex show prettyprint
+@kindex show screen-height
+@kindex show screen-width
+@kindex show unionprint
+@kindex show vtblprint
+@kindex show demangle
+@kindex show asm-demangle
+@kindex show sevenbit-strings
+@kindex show array-max
+@kindex show caution
+@kindex show history write
+@kindex unset
+
+@c TEXI2ROFF-KILL
+@ifinfo
+@c END TEXI2ROFF-KILL
+@example
+OLD COMMAND NEW COMMAND
+@c TEXI2ROFF-KILL
+--------------- -------------------------------
+@c END TEXI2ROFF-KILL
+add-syms add-symbol-file
+delete environment unset environment
+info convenience show convenience
+info copying show copying
+info directories show directories
+info editing show commands
+info history show values
+info targets help target
+info values show values
+info version show version
+info warranty show warranty
+set/show addressprint set/show print address
+set/show array-max set/show print elements
+set/show arrayprint set/show print array
+set/show asm-demangle set/show print asm-demangle
+set/show caution set/show confirm
+set/show demangle set/show print demangle
+set/show history write set/show history save
+set/show prettyprint set/show print pretty
+set/show screen-height set/show height
+set/show screen-width set/show width
+set/show sevenbit-strings set/show print sevenbit-strings
+set/show unionprint set/show print union
+set/show vtblprint set/show print vtbl
+
+unset [No longer an alias for delete]
+@end example
+@c TEXI2ROFF-KILL
+@end ifinfo
+
+@tex
+\vskip \parskip\vskip \baselineskip
+\halign{\tt #\hfil &\qquad#&\tt #\hfil\cr
+{\bf Old Command} &&{\bf New Command}\cr
+add-syms &&add-symbol-file\cr
+delete environment &&unset environment\cr
+info convenience &&show convenience\cr
+info copying &&show copying\cr
+info directories &&show directories \cr
+info editing &&show commands\cr
+info history &&show values\cr
+info targets &&help target\cr
+info values &&show values\cr
+info version &&show version\cr
+info warranty &&show warranty\cr
+set{\rm / }show addressprint &&set{\rm / }show print address\cr
+set{\rm / }show array-max &&set{\rm / }show print elements\cr
+set{\rm / }show arrayprint &&set{\rm / }show print array\cr
+set{\rm / }show asm-demangle &&set{\rm / }show print asm-demangle\cr
+set{\rm / }show caution &&set{\rm / }show confirm\cr
+set{\rm / }show demangle &&set{\rm / }show print demangle\cr
+set{\rm / }show history write &&set{\rm / }show history save\cr
+set{\rm / }show prettyprint &&set{\rm / }show print pretty\cr
+set{\rm / }show screen-height &&set{\rm / }show height\cr
+set{\rm / }show screen-width &&set{\rm / }show width\cr
+set{\rm / }show sevenbit-strings &&set{\rm / }show print sevenbit-strings\cr
+set{\rm / }show unionprint &&set{\rm / }show print union\cr
+set{\rm / }show vtblprint &&set{\rm / }show print vtbl\cr
+\cr
+unset &&\rm(No longer an alias for delete)\cr
+}
+@end tex
+@c END TEXI2ROFF-KILL
+@end ifset
+
+@ifclear PRECONFIGURED
+@node Formatting Documentation
+@appendix Formatting Documentation
+
+@cindex GDB reference card
+@cindex reference card
+The GDB 4 release includes an already-formatted reference card, ready
+for printing with PostScript or GhostScript, in the @file{gdb}
+subdirectory of the main source directory@footnote{In
+@file{gdb-@value{GDBVN}/gdb/refcard.ps} of the version @value{GDBVN}
+release.}. If you can use PostScript or GhostScript with your printer,
+you can print the reference card immediately with @file{refcard.ps}.
+
+The release also includes the source for the reference card. You
+can format it, using @TeX{}, by typing:
+
+@example
+make refcard.dvi
+@end example
+
+The GDB reference card is designed to print in landscape mode on US
+``letter'' size paper; that is, on a sheet 11 inches wide by 8.5 inches
+high. You will need to specify this form of printing as an option to
+your @sc{dvi} output program.
+
+@cindex documentation
+
+All the documentation for GDB comes as part of the machine-readable
+distribution. The documentation is written in Texinfo format, which is
+a documentation system that uses a single source file to produce both
+on-line information and a printed manual. You can use one of the Info
+formatting commands to create the on-line version of the documentation
+and @TeX{} (or @code{texi2roff}) to typeset the printed version.
+
+GDB includes an already formatted copy of the on-line Info version of
+this manual in the @file{gdb} subdirectory. The main Info file is
+@file{gdb-@var{version-number}/gdb/gdb.info}, and it refers to
+subordinate files matching @samp{gdb.info*} in the same directory. If
+necessary, you can print out these files, or read them with any editor;
+but they are easier to read using the @code{info} subsystem in GNU Emacs
+or the standalone @code{info} program, available as part of the GNU
+Texinfo distribution.
+
+If you want to format these Info files yourself, you need one of the
+Info formatting programs, such as @code{texinfo-format-buffer} or
+@code{makeinfo}.
+
+If you have @code{makeinfo} installed, and are in the top level GDB
+source directory (@file{gdb-@value{GDBVN}}, in the case of version @value{GDBVN}), you can
+make the Info file by typing:
+
+@example
+cd gdb
+make gdb.info
+@end example
+
+If you want to typeset and print copies of this manual, you need @TeX{},
+a program to print its @sc{dvi} output files, and @file{texinfo.tex}, the
+Texinfo definitions file.
+
+@TeX{} is a typesetting program; it does not print files directly, but
+produces output files called @sc{dvi} files. To print a typeset
+document, you need a program to print @sc{dvi} files. If your system
+has @TeX{} installed, chances are it has such a program. The precise
+command to use depends on your system; @kbd{lpr -d} is common; another
+(for PostScript devices) is @kbd{dvips}. The @sc{dvi} print command may
+require a file name without any extension or a @samp{.dvi} extension.
+
+@TeX{} also requires a macro definitions file called
+@file{texinfo.tex}. This file tells @TeX{} how to typeset a document
+written in Texinfo format. On its own, @TeX{} cannot read, much less
+typeset a Texinfo file. @file{texinfo.tex} is distributed with GDB
+and is located in the @file{gdb-@var{version-number}/texinfo}
+directory.
+
+If you have @TeX{} and a @sc{dvi} printer program installed, you can
+typeset and print this manual. First switch to the the @file{gdb}
+subdirectory of the main source directory (for example, to
+@file{gdb-@value{GDBVN}/gdb}) and then type:
+
+@example
+make gdb.dvi
+@end example
+
+@node Installing GDB
+@appendix Installing GDB
+@cindex configuring GDB
+@cindex installation
+
+GDB comes with a @code{configure} script that automates the process
+of preparing GDB for installation; you can then use @code{make} to
+build the @code{gdb} program.
+@iftex
+@c irrelevant in info file; it's as current as the code it lives with.
+@footnote{If you have a more recent version of GDB than @value{GDBVN},
+look at the @file{README} file in the sources; we may have improved the
+installation procedures since publishing this manual.}
+@end iftex
+
+The GDB distribution includes all the source code you need for GDB in
+a single directory, whose name is usually composed by appending the
+version number to @samp{gdb}.
+
+For example, the GDB version @value{GDBVN} distribution is in the
+@file{gdb-@value{GDBVN}} directory. That directory contains:
+
+@table @code
+@item gdb-@value{GDBVN}/configure @r{(and supporting files)}
+script for configuring GDB and all its supporting libraries.
+
+@item gdb-@value{GDBVN}/gdb
+the source specific to GDB itself
+
+@item gdb-@value{GDBVN}/bfd
+source for the Binary File Descriptor library
+
+@item gdb-@value{GDBVN}/include
+GNU include files
+
+@item gdb-@value{GDBVN}/libiberty
+source for the @samp{-liberty} free software library
+
+@item gdb-@value{GDBVN}/opcodes
+source for the library of opcode tables and disassemblers
+
+@item gdb-@value{GDBVN}/readline
+source for the GNU command-line interface
+
+@item gdb-@value{GDBVN}/glob
+source for the GNU filename pattern-matching subroutine
+
+@item gdb-@value{GDBVN}/mmalloc
+source for the GNU memory-mapped malloc package
+@end table
+
+The simplest way to configure and build GDB is to run @code{configure}
+from the @file{gdb-@var{version-number}} source directory, which in
+this example is the @file{gdb-@value{GDBVN}} directory.
+
+First switch to the @file{gdb-@var{version-number}} source directory
+if you are not already in it; then run @code{configure}. Pass the
+identifier for the platform on which GDB will run as an
+argument.
+
+For example:
+
+@example
+cd gdb-@value{GDBVN}
+./configure @var{host}
+make
+@end example
+
+@noindent
+where @var{host} is an identifier such as @samp{sun4} or
+@samp{decstation}, that identifies the platform where GDB will run.
+(You can often leave off @var{host}; @code{configure} tries to guess the
+correct value by examining your system.)
+
+Running @samp{configure @var{host}} and then running @code{make} builds the
+@file{bfd}, @file{readline}, @file{mmalloc}, and @file{libiberty}
+libraries, then @code{gdb} itself. The configured source files, and the
+binaries, are left in the corresponding source directories.
+
+@code{configure} is a Bourne-shell (@code{/bin/sh}) script; if your
+system does not recognize this automatically when you run a different
+shell, you may need to run @code{sh} on it explicitly:
+
+@example
+sh configure @var{host}
+@end example
+
+If you run @code{configure} from a directory that contains source
+directories for multiple libraries or programs, such as the
+@file{gdb-@value{GDBVN}} source directory for version @value{GDBVN}, @code{configure}
+creates configuration files for every directory level underneath (unless
+you tell it not to, with the @samp{--norecursion} option).
+
+You can run the @code{configure} script from any of the
+subordinate directories in the GDB distribution if you only want to
+configure that subdirectory, but be sure to specify a path to it.
+
+For example, with version @value{GDBVN}, type the following to configure only
+the @code{bfd} subdirectory:
+
+@example
+@group
+cd gdb-@value{GDBVN}/bfd
+../configure @var{host}
+@end group
+@end example
+
+You can install @code{@value{GDBP}} anywhere; it has no hardwired paths.
+However, you should make sure that the shell on your path (named by
+the @samp{SHELL} environment variable) is publicly readable. Remember
+that GDB uses the shell to start your program---some systems refuse to
+let GDB debug child processes whose programs are not readable.
+
+@menu
+* Separate Objdir:: Compiling GDB in another directory
+* Config Names:: Specifying names for hosts and targets
+* configure Options:: Summary of options for configure
+@end menu
+
+@node Separate Objdir
+@section Compiling GDB in another directory
+
+If you want to run GDB versions for several host or target machines,
+you need a different @code{gdb} compiled for each combination of
+host and target. @code{configure} is designed to make this easy by
+allowing you to generate each configuration in a separate subdirectory,
+rather than in the source directory. If your @code{make} program
+handles the @samp{VPATH} feature (GNU @code{make} does), running
+@code{make} in each of these directories builds the @code{gdb}
+program specified there.
+
+To build @code{gdb} in a separate directory, run @code{configure}
+with the @samp{--srcdir} option to specify where to find the source.
+(You also need to specify a path to find @code{configure}
+itself from your working directory. If the path to @code{configure}
+would be the same as the argument to @samp{--srcdir}, you can leave out
+the @samp{--srcdir} option; it will be assumed.)
+
+For example, with version @value{GDBVN}, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+@example
+@group
+cd gdb-@value{GDBVN}
+mkdir ../gdb-sun4
+cd ../gdb-sun4
+../gdb-@value{GDBVN}/configure sun4
+make
+@end group
+@end example
+
+When @code{configure} builds a configuration using a remote source
+directory, it creates a tree for the binaries with the same structure
+(and using the same names) as the tree under the source directory. In
+the example, you'd find the Sun 4 library @file{libiberty.a} in the
+directory @file{gdb-sun4/libiberty}, and GDB itself in
+@file{gdb-sun4/gdb}.
+
+One popular reason to build several GDB configurations in separate
+directories is to configure GDB for cross-compiling (where GDB
+runs on one machine---the host---while debugging programs that run on
+another machine---the target). You specify a cross-debugging target by
+giving the @samp{--target=@var{target}} option to @code{configure}.
+
+When you run @code{make} to build a program or library, you must run
+it in a configured directory---whatever directory you were in when you
+called @code{configure} (or one of its subdirectories).
+
+The @code{Makefile} that @code{configure} generates in each source
+directory also runs recursively. If you type @code{make} in a source
+directory such as @file{gdb-@value{GDBVN}} (or in a separate configured
+directory configured with @samp{--srcdir=@var{path}/gdb-@value{GDBVN}}), you
+will build all the required libraries, and then build GDB.
+
+When you have multiple hosts or targets configured in separate
+directories, you can run @code{make} on them in parallel (for example,
+if they are NFS-mounted on each of the hosts); they will not interfere
+with each other.
+
+@node Config Names
+@section Specifying names for hosts and targets
+
+The specifications used for hosts and targets in the @code{configure}
+script are based on a three-part naming scheme, but some short predefined
+aliases are also supported. The full naming scheme encodes three pieces
+of information in the following pattern:
+
+@example
+@var{architecture}-@var{vendor}-@var{os}
+@end example
+
+For example, you can use the alias @code{sun4} as a @var{host} argument,
+or as the value for @var{target} in a @code{--target=@var{target}}
+option. The equivalent full name is @samp{sparc-sun-sunos4}.
+
+The @code{configure} script accompanying GDB does not provide
+any query facility to list all supported host and target names or
+aliases. @code{configure} calls the Bourne shell script
+@code{config.sub} to map abbreviations to full names; you can read the
+script, if you wish, or you can use it to test your guesses on
+abbreviations---for example:
+
+@smallexample
+% sh config.sub sun4
+sparc-sun-sunos4.1.1
+% sh config.sub sun3
+m68k-sun-sunos4.1.1
+% sh config.sub decstation
+mips-dec-ultrix4.2
+% sh config.sub hp300bsd
+m68k-hp-bsd
+% sh config.sub i386v
+i386-unknown-sysv
+% sh config.sub i786v
+Invalid configuration `i786v': machine `i786v' not recognized
+@end smallexample
+
+@noindent
+@code{config.sub} is also distributed in the GDB source
+directory (@file{gdb-@value{GDBVN}}, for version @value{GDBVN}).
+
+@node configure Options
+@section @code{configure} options
+
+Here is a summary of the @code{configure} options and arguments that
+are most often useful for building @value{GDBN}. @code{configure} also has
+several other options not listed here. @inforef{What Configure
+Does,,configure.info}, for a full explanation of @code{configure}.
+@c FIXME: Would this be more, or less, useful as an xref (ref to printed
+@c manual in the printed manual, ref to info file only from the info file)?
+
+@example
+configure @r{[}--help@r{]}
+ @r{[}--prefix=@var{dir}@r{]}
+ @r{[}--srcdir=@var{path}@r{]}
+ @r{[}--norecursion@r{]} @r{[}--rm@r{]}
+ @r{[}--target=@var{target}@r{]} @var{host}
+@end example
+
+@noindent
+You may introduce options with a single @samp{-} rather than
+@samp{--} if you prefer; but you may abbreviate option names if you use
+@samp{--}.
+
+@table @code
+@item --help
+Display a quick summary of how to invoke @code{configure}.
+
+@item -prefix=@var{dir}
+Configure the source to install programs and files under directory
+@file{@var{dir}}.
+
+@item --srcdir=@var{path}
+@strong{Warning: using this option requires GNU @code{make}, or another
+@code{make} that implements the @code{VPATH} feature.}@*
+Use this option to make configurations in directories separate from the
+GDB source directories. Among other things, you can use this to
+build (or maintain) several configurations simultaneously, in separate
+directories. @code{configure} writes configuration specific files in
+the current directory, but arranges for them to use the source in the
+directory @var{path}. @code{configure} will create directories under
+the working directory in parallel to the source directories below
+@var{path}.
+
+@item --norecursion
+Configure only the directory level where @code{configure} is executed; do not
+propagate configuration to subdirectories.
+
+@item --rm
+@emph{Remove} files otherwise built during configuration.
+
+@c This does not work (yet if ever). FIXME.
+@c @item --parse=@var{lang} @dots{}
+@c Configure the GDB expression parser to parse the listed languages.
+@c @samp{all} configures GDB for all supported languages. To get a
+@c list of all supported languages, omit the argument. Without this
+@c option, GDB is configured to parse all supported languages.
+
+@item --target=@var{target}
+Configure GDB for cross-debugging programs running on the specified
+@var{target}. Without this option, GDB is configured to debug
+programs that run on the same machine (@var{host}) as GDB itself.
+
+There is no convenient way to generate a list of all available targets.
+
+@item @var{host} @dots{}
+Configure GDB to run on the specified @var{host}.
+
+There is no convenient way to generate a list of all available hosts.
+@end table
+
+@noindent
+@code{configure} accepts other options, for compatibility with
+configuring other GNU tools recursively; but these are the only
+options that affect GDB or its supporting libraries.
+@end ifclear
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@tex
+% I think something like @colophon should be in texinfo. In the
+% meantime:
+\long\def\colophon{\hbox to0pt{}\vfill
+\centerline{The body of this manual is set in}
+\centerline{\fontname\tenrm,}
+\centerline{with headings in {\bf\fontname\tenbf}}
+\centerline{and examples in {\tt\fontname\tentt}.}
+\centerline{{\it\fontname\tenit\/},}
+\centerline{{\bf\fontname\tenbf}, and}
+\centerline{{\sl\fontname\tensl\/}}
+\centerline{are used for emphasis.}\vfill}
+\page\colophon
+% Blame: pesch@cygnus.com, 1991.
+@end tex
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/doc/gdbint.texinfo b/gnu/usr.bin/gdb/doc/gdbint.texinfo
new file mode 100644
index 000000000000..d158bac8f81a
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdbint.texinfo
@@ -0,0 +1,2658 @@
+\input texinfo
+@setfilename gdbint.info
+@c $Id: gdbint.texinfo,v 1.1 1994/06/10 13:34:28 paul Exp $
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Gdb-Internals: (gdbint). The GNU debugger's internals.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+This file documents the internals of the GNU debugger GDB.
+
+Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+Contributed by Cygnus Support. Written by John Gilmore.
+
+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.
+
+@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 copy or distribute modified versions of this
+manual under the terms of the GPL (for which purpose this text may be
+regarded as a program in the language TeX).
+@end ifinfo
+
+@setchapternewpage off
+@settitle GDB Internals
+@titlepage
+@title{Working in GDB}
+@subtitle{A guide to the internals of the GNU debugger}
+@author John Gilmore
+@author Cygnus Support
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.1 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+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.
+
+@end titlepage
+
+@node Top
+@c Perhaps this should be the title of the document (but only for info,
+@c not for TeX). Existing GNU manuals seem inconsistent on this point.
+@top Scope of this Document
+
+This document documents the internals of the GNU debugger, GDB. It is
+intended to document aspects of GDB which apply across many different
+parts of GDB (for example, @pxref{Coding Style}), or which are global
+aspects of design (for example, what are the major modules and which
+files document them in detail?). Information which pertains to specific
+data structures, functions, variables, etc., should be put in comments
+in the source code, not here. It is more likely to get noticed and kept
+up to date there. Some of the information in this document should
+probably be moved into comments.
+
+@menu
+* README:: The README File
+* Getting Started:: Getting started working on GDB
+* Debugging GDB:: Debugging GDB with itself
+* New Architectures:: Defining a New Host or Target Architecture
+* Config:: Adding a New Configuration
+* Host:: Adding a New Host
+* Native:: Adding a New Native Configuration
+* Target:: Adding a New Target
+* Languages:: Defining New Source Languages
+* Releases:: Configuring GDB for Release
+* Partial Symbol Tables:: How GDB reads symbols quickly at startup
+* Types:: How GDB keeps track of types
+* BFD support for GDB:: How BFD and GDB interface
+* Symbol Reading:: Defining New Symbol Readers
+* Cleanups:: Cleanups
+* Wrapping:: Wrapping Output Lines
+* Frames:: Keeping track of function calls
+* Remote Stubs:: Code that runs in targets and talks to GDB
+* Longjmp Support:: Stepping through longjmp's in the target
+* Coding Style:: Strunk and White for GDB maintainers
+* Clean Design:: Frank Lloyd Wright for GDB maintainers
+* Submitting Patches:: How to get your changes into GDB releases
+* Host Conditionals:: What features exist in the host
+* Target Conditionals:: What features exist in the target
+* Native Conditionals:: Conditionals for when host and target are same
+* Obsolete Conditionals:: Conditionals that don't exist any more
+* XCOFF:: The Object file format used on IBM's RS/6000
+@end menu
+
+@node README
+@chapter The @file{README} File
+
+Check the @file{README} file, it often has useful information that does not
+appear anywhere else in the directory.
+
+@node Getting Started
+@chapter Getting Started Working on GDB
+
+GDB is a large and complicated program, and if you first starting to
+work on it, it can be hard to know where to start. Fortunately, if you
+know how to go about it, there are ways to figure out what is going on:
+
+@itemize @bullet
+@item
+This manual, the GDB Internals manual, has information which applies
+generally to many parts of GDB.
+
+@item
+Information about particular functions or data structures are located in
+comments with those functions or data structures. If you run across a
+function or a global variable which does not have a comment correctly
+explaining what is does, this can be thought of as a bug in GDB; feel
+free to submit a bug report, with a suggested comment if you can figure
+out what the comment should say (@pxref{Submitting Patches}). If you
+find a comment which is actually wrong, be especially sure to report that.
+
+Comments explaining the function of macros defined in host, target, or
+native dependent files can be in several places. Sometimes they are
+repeated every place the macro is defined. Sometimes they are where the
+macro is used. Sometimes there is a header file which supplies a
+default definition of the macro, and the comment is there. This manual
+also has a list of macros (@pxref{Host Conditionals}, @pxref{Target
+Conditionals}, @pxref{Native Conditionals}, and @pxref{Obsolete
+Conditionals}) with some documentation.
+
+@item
+Start with the header files. Once you some idea of how GDB's internal
+symbol tables are stored (see @file{symtab.h}, @file{gdbtypes.h}), you
+will find it much easier to understand the code which uses and creates
+those symbol tables.
+
+@item
+You may wish to process the information you are getting somehow, to
+enhance your understanding of it. Summarize it, translate it to another
+language, add some (perhaps trivial or non-useful) feature to GDB, use
+the code to predict what a test case would do and write the test case
+and verify your prediction, etc. If you are reading code and your eyes
+are starting to glaze over, this is a sign you need to use a more active
+approach.
+
+@item
+Once you have a part of GDB to start with, you can find more
+specifically the part you are looking for by stepping through each
+function with the @code{next} command. Do not use @code{step} or you
+will quickly get distracted; when the function you are stepping through
+calls another function try only to get a big-picture understanding
+(perhaps using the comment at the beginning of the function being
+called) of what it does. This way you can identify which of the
+functions being called by the function you are stepping through is the
+one which you are interested in. You may need to examine the data
+structures generated at each stage, with reference to the comments in
+the header files explaining what the data structures are supposed to
+look like.
+
+Of course, this same technique can be used if you are just reading the
+code, rather than actually stepping through it. The same general
+principle applies---when the code you are looking at calls something
+else, just try to understand generally what the code being called does,
+rather than worrying about all its details.
+
+@item
+A good place to start when tracking down some particular area is with a
+command which invokes that feature. Suppose you want to know how
+single-stepping works. As a GDB user, you know that the @code{step}
+command invokes single-stepping. The command is invoked via command
+tables (see @file{command.h}); by convention the function which actually
+performs the command is formed by taking the name of the command and
+adding @samp{_command}, or in the case of an @code{info} subcommand,
+@samp{_info}. For example, the @code{step} command invokes the
+@code{step_command} function and the @code{info display} command invokes
+@code{display_info}. When this convention is not followed, you might
+have to use @code{grep} or @kbd{M-x tags-search} in emacs, or run GDB on
+itself and set a breakpoint in @code{execute_command}.
+
+@item
+If all of the above fail, it may be appropriate to ask for information
+on @code{bug-gdb}. But @emph{never} post a generic question like ``I was
+wondering if anyone could give me some tips about understanding
+GDB''---if we had some magic secret we would put it in this manual.
+Suggestions for improving the manual are always welcome, of course.
+@end itemize
+
+Good luck!
+
+@node Debugging GDB
+@chapter Debugging GDB with itself
+If gdb is limping on your machine, this is the preferred way to get it
+fully functional. Be warned that in some ancient Unix systems, like
+Ultrix 4.2, a program can't be running in one process while it is being
+debugged in another. Rather than typing the command @code{@w{./gdb
+./gdb}}, which works on Suns and such, you can copy @file{gdb} to
+@file{gdb2} and then type @code{@w{./gdb ./gdb2}}.
+
+When you run gdb in the gdb source directory, it will read a
+@file{.gdbinit} file that sets up some simple things to make debugging
+gdb easier. The @code{info} command, when executed without a subcommand
+in a gdb being debugged by gdb, will pop you back up to the top level
+gdb. See @file{.gdbinit} for details.
+
+If you use emacs, you will probably want to do a @code{make TAGS} after
+you configure your distribution; this will put the machine dependent
+routines for your local machine where they will be accessed first by
+@kbd{M-.}
+
+Also, make sure that you've either compiled gdb with your local cc, or
+have run @code{fixincludes} if you are compiling with gcc.
+
+@node New Architectures
+@chapter Defining a New Host or Target Architecture
+
+When building support for a new host and/or target, much of the work you
+need to do is handled by specifying configuration files;
+@pxref{Config,,Adding a New Configuration}. Further work can be
+divided into ``host-dependent'' (@pxref{Host,,Adding a New Host}) and
+``target-dependent'' (@pxref{Target,,Adding a New Target}). The
+following discussion is meant to explain the difference between hosts
+and targets.
+
+@heading What is considered ``host-dependent'' versus ``target-dependent''?
+
+@dfn{Host} refers to attributes of the system where GDB runs.
+@dfn{Target} refers to the system where the program being debugged
+executes. In most cases they are the same machine, in which case
+a third type of @dfn{Native} attributes come into play.
+
+Defines and include files needed to build on the host are host support.
+Examples are tty support, system defined types, host byte order, host
+float format.
+
+Defines and information needed to handle the target format are target
+dependent. Examples are the stack frame format, instruction set,
+breakpoint instruction, registers, and how to set up and tear down the stack
+to call a function.
+
+Information that is only needed when the host and target are the same,
+is native dependent. One example is Unix child process support; if the
+host and target are not the same, doing a fork to start the target
+process is a bad idea. The various macros needed for finding the
+registers in the @code{upage}, running @code{ptrace}, and such are all in the
+native-dependent files.
+
+Another example of native-dependent code is support for features
+that are really part of the target environment, but which require
+@code{#include} files that are only available on the host system.
+Core file handling and @code{setjmp} handling are two common cases.
+
+When you want to make GDB work ``native'' on a particular
+machine, you have to include all three kinds of information.
+
+The dependent information in GDB is organized into files by naming
+conventions.
+
+Host-Dependent Files
+@table @file
+@item config/*/*.mh
+Sets Makefile parameters
+@item config/*/xm-*.h
+Global #include's and #define's and definitions
+@item *-xdep.c
+Global variables and functions
+@end table
+
+Native-Dependent Files
+@table @file
+@item config/*/*.mh
+Sets Makefile parameters (for @emph{both} host and native)
+@item config/*/nm-*.h
+#include's and #define's and definitions. This file
+is only included by the small number of modules that need it,
+so beware of doing feature-test #define's from its macros.
+@item *-nat.c
+global variables and functions
+@end table
+
+Target-Dependent Files
+@table @file
+@item config/*/*.mt
+Sets Makefile parameters
+@item config/*/tm-*.h
+Global #include's and #define's and definitions
+@item *-tdep.c
+Global variables and functions
+@end table
+
+At this writing, most supported hosts have had their host and native
+dependencies sorted out properly. There are a few stragglers, which
+can be recognized by the absence of NATDEPFILES lines in their
+@file{config/*/*.mh}.
+
+@node Config
+@chapter Adding a New Configuration
+
+Most of the work in making GDB compile on a new machine is in specifying
+the configuration of the machine. This is done in a dizzying variety of
+header files and configuration scripts, which we hope to make more
+sensible soon. Let's say your new host is called an @var{xxx} (e.g.
+@samp{sun4}), and its full three-part configuration name is
+@code{@var{xarch}-@var{xvend}-@var{xos}} (e.g. @samp{sparc-sun-sunos4}). In
+particular:
+
+In the top level directory, edit @file{config.sub} and add @var{xarch},
+@var{xvend}, and @var{xos} to the lists of supported architectures,
+vendors, and operating systems near the bottom of the file. Also, add
+@var{xxx} as an alias that maps to
+@code{@var{xarch}-@var{xvend}-@var{xos}}. You can test your changes by
+running
+
+@example
+./config.sub @var{xxx}
+@end example
+@noindent
+and
+@example
+./config.sub @code{@var{xarch}-@var{xvend}-@var{xos}}
+@end example
+@noindent
+which should both respond with @code{@var{xarch}-@var{xvend}-@var{xos}}
+and no error messages.
+
+Now, go to the @file{bfd} directory and
+create a new file @file{bfd/hosts/h-@var{xxx}.h}. Examine the
+other @file{h-*.h} files as templates, and create one that brings in the
+right include files for your system, and defines any host-specific
+macros needed by BFD, the Binutils, GNU LD, or the Opcodes directories.
+(They all share the bfd @file{hosts} directory and the @file{configure.host}
+file.)
+
+Then edit @file{bfd/configure.host}. Add a line to recognize your
+@code{@var{xarch}-@var{xvend}-@var{xos}} configuration, and set
+@code{my_host} to @var{xxx} when you recognize it. This will cause your
+file @file{h-@var{xxx}.h} to be linked to @file{sysdep.h} at configuration
+time. When creating the line that recognizes your configuration,
+only match the fields that you really need to match; e.g. don't match
+match the architecture or manufacturer if the OS is sufficient
+to distinguish the configuration that your @file{h-@var{xxx}.h} file supports.
+Don't match the manufacturer name unless you really need to.
+This should make future ports easier.
+
+Also, if this host requires any changes to the Makefile, create a file
+@file{bfd/config/@var{xxx}.mh}, which includes the required lines.
+
+It's possible that the @file{libiberty} and @file{readline} directories
+won't need any changes for your configuration, but if they do, you can
+change the @file{configure.in} file there to recognize your system and
+map to an @file{mh-@var{xxx}} file. Then add @file{mh-@var{xxx}}
+to the @file{config/} subdirectory, to set any makefile variables you
+need. The only current options in there are things like @samp{-DSYSV}.
+(This @file{mh-@var{xxx}} naming convention differs from elsewhere
+in GDB, by historical accident. It should be cleaned up so that all
+such files are called @file{@var{xxx}.mh}.)
+
+Aha! Now to configure GDB itself! Edit
+@file{gdb/configure.in} to recognize your system and set @code{gdb_host}
+to @var{xxx}, and (unless your desired target is already available) also
+set @code{gdb_target} to something appropriate (for instance,
+@var{xxx}). To handle new hosts, modify the segment after the comment
+@samp{# per-host}; to handle new targets, modify after @samp{#
+per-target}.
+@c Would it be simpler to just use different per-host and per-target
+@c *scripts*, and call them from {configure} ?
+
+Finally, you'll need to specify and define GDB's host-, native-, and
+target-dependent @file{.h} and @file{.c} files used for your
+configuration; the next two chapters discuss those.
+
+
+@node Host
+@chapter Adding a New Host
+
+Once you have specified a new configuration for your host
+(@pxref{Config,,Adding a New Configuration}), there are three remaining
+pieces to making GDB work on a new machine. First, you have to make it
+host on the new machine (compile there, handle that machine's terminals
+properly, etc). If you will be cross-debugging to some other kind of
+system that's already supported, you are done.
+
+If you want to use GDB to debug programs that run on the new machine,
+you have to get it to understand the machine's object files, symbol
+files, and interfaces to processes; @pxref{Target,,Adding a New Target}
+and @pxref{Native,,Adding a New Native Configuration}
+
+Several files control GDB's configuration for host systems:
+
+@table @file
+@item gdb/config/@var{arch}/@var{xxx}.mh
+Specifies Makefile fragments needed when hosting on machine @var{xxx}.
+In particular, this lists the required machine-dependent object files,
+by defining @samp{XDEPFILES=@dots{}}. Also
+specifies the header file which describes host @var{xxx}, by defining
+@code{XM_FILE= xm-@var{xxx}.h}. You can also define @code{CC},
+@code{REGEX} and @code{REGEX1}, @code{SYSV_DEFINE}, @code{XM_CFLAGS},
+@code{XM_ADD_FILES}, @code{XM_CLIBS}, @code{XM_CDEPS},
+etc.; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/xm-@var{xxx}.h
+(@file{xm.h} is a link to this file, created by configure).
+Contains C macro definitions describing the host system environment,
+such as byte order, host C compiler and library, ptrace support,
+and core file structure. Crib from existing @file{xm-*.h} files
+to create a new one.
+
+@item gdb/@var{xxx}-xdep.c
+Contains any miscellaneous C code required for this machine
+as a host. On many machines it doesn't exist at all. If it does
+exist, put @file{@var{xxx}-xdep.o} into the @code{XDEPFILES} line
+in @file{gdb/config/mh-@var{xxx}}.
+@end table
+
+@subheading Generic Host Support Files
+
+There are some ``generic'' versions of routines that can be used by
+various systems. These can be customized in various ways by macros
+defined in your @file{xm-@var{xxx}.h} file. If these routines work for
+the @var{xxx} host, you can just include the generic file's name (with
+@samp{.o}, not @samp{.c}) in @code{XDEPFILES}.
+
+Otherwise, if your machine needs custom support routines, you will need
+to write routines that perform the same functions as the generic file.
+Put them into @code{@var{xxx}-xdep.c}, and put @code{@var{xxx}-xdep.o}
+into @code{XDEPFILES}.
+
+@table @file
+@item ser-bsd.c
+This contains serial line support for Berkeley-derived Unix systems.
+
+@item ser-go32.c
+This contains serial line support for 32-bit programs running under DOS
+using the GO32 execution environment.
+
+@item ser-termios.c
+This contains serial line support for System V-derived Unix systems.
+@end table
+
+Now, you are now ready to try configuring GDB to compile using your system
+as its host. From the top level (above @file{bfd}, @file{gdb}, etc), do:
+
+@example
+./configure @var{xxx} +target=vxworks960
+@end example
+
+This will configure your system to cross-compile for VxWorks on
+the Intel 960, which is probably not what you really want, but it's
+a test case that works at this stage. (You haven't set up to be
+able to debug programs that run @emph{on} @var{xxx} yet.)
+
+If this succeeds, you can try building it all with:
+
+@example
+make
+@end example
+
+Repeat until the program configures, compiles, links, and runs.
+When run, it won't be able to do much (unless you have a VxWorks/960
+board on your network) but you will know that the host support is
+pretty well done.
+
+Good luck! Comments and suggestions about this section are particularly
+welcome; send them to @samp{bug-gdb@@prep.ai.mit.edu}.
+
+@node Native
+@chapter Adding a New Native Configuration
+
+If you are making GDB run native on the @var{xxx} machine, you have
+plenty more work to do. Several files control GDB's configuration for
+native support:
+
+@table @file
+@item gdb/config/@var{xarch}/@var{xxx}.mh
+Specifies Makefile fragments needed when hosting @emph{or native}
+on machine @var{xxx}.
+In particular, this lists the required native-dependent object files,
+by defining @samp{NATDEPFILES=@dots{}}. Also
+specifies the header file which describes native support on @var{xxx},
+by defining @samp{NAT_FILE= nm-@var{xxx}.h}.
+You can also define @samp{NAT_CFLAGS},
+@samp{NAT_ADD_FILES}, @samp{NAT_CLIBS}, @samp{NAT_CDEPS},
+etc.; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/nm-@var{xxx}.h
+(@file{nm.h} is a link to this file, created by configure).
+Contains C macro definitions describing the native system environment,
+such as child process control and core file support.
+Crib from existing @file{nm-*.h} files to create a new one.
+
+@item gdb/@var{xxx}-nat.c
+Contains any miscellaneous C code required for this native support
+of this machine. On some machines it doesn't exist at all.
+@end table
+
+@subheading Generic Native Support Files
+
+There are some ``generic'' versions of routines that can be used by
+various systems. These can be customized in various ways by macros
+defined in your @file{nm-@var{xxx}.h} file. If these routines work for
+the @var{xxx} host, you can just include the generic file's name (with
+@samp{.o}, not @samp{.c}) in @code{NATDEPFILES}.
+
+Otherwise, if your machine needs custom support routines, you will need
+to write routines that perform the same functions as the generic file.
+Put them into @code{@var{xxx}-nat.c}, and put @code{@var{xxx}-nat.o}
+into @code{NATDEPFILES}.
+
+@table @file
+
+@item inftarg.c
+This contains the @emph{target_ops vector} that supports Unix child
+processes on systems which use ptrace and wait to control the child.
+
+@item procfs.c
+This contains the @emph{target_ops vector} that supports Unix child
+processes on systems which use /proc to control the child.
+
+@item fork-child.c
+This does the low-level grunge that uses Unix system calls
+to do a "fork and exec" to start up a child process.
+
+@item infptrace.c
+This is the low level interface to inferior processes for systems
+using the Unix @code{ptrace} call in a vanilla way.
+
+@item coredep.c::fetch_core_registers()
+Support for reading registers out of a core file. This routine calls
+@code{register_addr()}, see below.
+Now that BFD is used to read core files, virtually all machines should
+use @code{coredep.c}, and should just provide @code{fetch_core_registers} in
+@code{@var{xxx}-nat.c} (or @code{REGISTER_U_ADDR} in @code{nm-@var{xxx}.h}).
+
+@item coredep.c::register_addr()
+If your @code{nm-@var{xxx}.h} file defines the macro
+@code{REGISTER_U_ADDR(addr, blockend, regno)}, it should be defined to
+set @code{addr} to the offset within the @samp{user}
+struct of GDB register number @code{regno}. @code{blockend} is the
+offset within the ``upage'' of @code{u.u_ar0}.
+If @code{REGISTER_U_ADDR} is defined,
+@file{coredep.c} will define the @code{register_addr()} function and use
+the macro in it. If you do not define @code{REGISTER_U_ADDR}, but you
+are using the standard @code{fetch_core_registers()}, you will need to
+define your own version of @code{register_addr()}, put it into your
+@code{@var{xxx}-nat.c} file, and be sure @code{@var{xxx}-nat.o} is in
+the @code{NATDEPFILES} list. If you have your own
+@code{fetch_core_registers()}, you may not need a separate
+@code{register_addr()}. Many custom @code{fetch_core_registers()}
+implementations simply locate the registers themselves.@refill
+@end table
+
+When making GDB run native on a new operating system,
+to make it possible to debug
+core files, you will need to either write specific code for parsing your
+OS's core files, or customize @file{bfd/trad-core.c}. First, use
+whatever @code{#include} files your machine uses to define the struct of
+registers that is accessible (possibly in the u-area) in a core file
+(rather than @file{machine/reg.h}), and an include file that defines whatever
+header exists on a core file (e.g. the u-area or a @samp{struct core}). Then
+modify @code{trad_unix_core_file_p()} to use these values to set up the
+section information for the data segment, stack segment, any other
+segments in the core file (perhaps shared library contents or control
+information), ``registers'' segment, and if there are two discontiguous
+sets of registers (e.g. integer and float), the ``reg2'' segment. This
+section information basically delimits areas in the core file in a
+standard way, which the section-reading routines in BFD know how to seek
+around in.
+
+Then back in GDB, you need a matching routine called
+@code{fetch_core_registers()}. If you can use the generic one, it's in
+@file{coredep.c}; if not, it's in your @file{@var{xxx}-nat.c} file.
+It will be passed a char pointer to the entire ``registers'' segment,
+its length, and a zero; or a char pointer to the entire ``regs2''
+segment, its length, and a 2. The routine should suck out the supplied
+register values and install them into GDB's ``registers'' array.
+(@xref{New Architectures,,Defining a New Host or Target Architecture},
+for more info about this.)
+
+If your system uses @file{/proc} to control processes, and uses ELF
+format core files, then you may be able to use the same routines
+for reading the registers out of processes and out of core files.
+
+@node Target
+@chapter Adding a New Target
+
+For a new target called @var{ttt}, first specify the configuration as
+described in @ref{Config,,Adding a New Configuration}. If your new
+target is the same as your new host, you've probably already done that.
+
+A variety of files specify attributes of the GDB target environment:
+
+@table @file
+@item gdb/config/@var{arch}/@var{ttt}.mt
+Contains a Makefile fragment specific to this target.
+Specifies what object files are needed for target @var{ttt}, by
+defining @samp{TDEPFILES=@dots{}}.
+Also specifies the header file which describes @var{ttt}, by defining
+@samp{TM_FILE= tm-@var{ttt}.h}. You can also define @samp{TM_CFLAGS},
+@samp{TM_CLIBS}, @samp{TM_CDEPS},
+and other Makefile variables here; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/tm-@var{ttt}.h
+(@file{tm.h} is a link to this file, created by configure).
+Contains macro definitions about the target machine's
+registers, stack frame format and instructions.
+Crib from existing @file{tm-*.h} files when building a new one.
+
+@item gdb/@var{ttt}-tdep.c
+Contains any miscellaneous code required for this target machine.
+On some machines it doesn't exist at all. Sometimes the macros
+in @file{tm-@var{ttt}.h} become very complicated, so they are
+implemented as functions here instead, and the macro is simply
+defined to call the function.
+
+@item gdb/exec.c
+Defines functions for accessing files that are
+executable on the target system. These functions open and examine an
+exec file, extract data from one, write data to one, print information
+about one, etc. Now that executable files are handled with BFD, every
+target should be able to use the generic exec.c rather than its
+own custom code.
+
+@item gdb/@var{arch}-pinsn.c
+Prints (disassembles) the target machine's instructions.
+This file is usually shared with other target machines which use the
+same processor, which is why it is @file{@var{arch}-pinsn.c} rather
+than @file{@var{ttt}-pinsn.c}.
+
+@item gdb/@var{arch}-opcode.h
+Contains some large initialized
+data structures describing the target machine's instructions.
+This is a bit strange for a @file{.h} file, but it's OK since
+it is only included in one place. @file{@var{arch}-opcode.h} is shared
+between the debugger and the assembler, if the GNU assembler has been
+ported to the target machine.
+
+@item gdb/config/@var{arch}/tm-@var{arch}.h
+This often exists to describe the basic layout of the target machine's
+processor chip (registers, stack, etc).
+If used, it is included by @file{tm-@var{xxx}.h}. It can
+be shared among many targets that use the same processor.
+
+@item gdb/@var{arch}-tdep.c
+Similarly, there are often common subroutines that are shared by all
+target machines that use this particular architecture.
+@end table
+
+When adding support for a new target machine, there are various areas
+of support that might need change, or might be OK.
+
+If you are using an existing object file format (a.out or COFF),
+there is probably little to be done. See @file{bfd/doc/bfd.texinfo}
+for more information on writing new a.out or COFF versions.
+
+If you need to add a new object file format, you must first add it to
+BFD. This is beyond the scope of this document right now. Basically
+you must build a transfer vector (of type @code{bfd_target}), which will
+mean writing all the required routines, and add it to the list in
+@file{bfd/targets.c}.
+
+You must then arrange for the BFD code to provide access to the
+debugging symbols. Generally GDB will have to call swapping routines
+from BFD and a few other BFD internal routines to locate the debugging
+information. As much as possible, GDB should not depend on the BFD
+internal data structures.
+
+For some targets (e.g., COFF), there is a special transfer vector used
+to call swapping routines, since the external data structures on various
+platforms have different sizes and layouts. Specialized routines that
+will only ever be implemented by one object file format may be called
+directly. This interface should be described in a file
+@file{bfd/libxxx.h}, which is included by GDB.
+
+If you are adding a new operating system for an existing CPU chip, add a
+@file{tm-@var{xos}.h} file that describes the operating system
+facilities that are unusual (extra symbol table info; the breakpoint
+instruction needed; etc). Then write a
+@file{tm-@var{xarch}-@var{xos}.h} that just @code{#include}s
+@file{tm-@var{xarch}.h} and @file{tm-@var{xos}.h}. (Now that we have
+three-part configuration names, this will probably get revised to
+separate the @var{xos} configuration from the @var{xarch}
+configuration.)
+
+
+@node Languages
+@chapter Adding a Source Language to GDB
+
+To add other languages to GDB's expression parser, follow the following steps:
+
+@table @emph
+@item Create the expression parser.
+
+This should reside in a file @file{@var{lang}-exp.y}. Routines for building
+parsed expressions into a @samp{union exp_element} list are in @file{parse.c}.
+
+Since we can't depend upon everyone having Bison, and YACC produces
+parsers that define a bunch of global names, the following lines
+@emph{must} be included at the top of the YACC parser, to prevent
+the various parsers from defining the same global names:
+
+@example
+#define yyparse @var{lang}_parse
+#define yylex @var{lang}_lex
+#define yyerror @var{lang}_error
+#define yylval @var{lang}_lval
+#define yychar @var{lang}_char
+#define yydebug @var{lang}_debug
+#define yypact @var{lang}_pact
+#define yyr1 @var{lang}_r1
+#define yyr2 @var{lang}_r2
+#define yydef @var{lang}_def
+#define yychk @var{lang}_chk
+#define yypgo @var{lang}_pgo
+#define yyact @var{lang}_act
+#define yyexca @var{lang}_exca
+#define yyerrflag @var{lang}_errflag
+#define yynerrs @var{lang}_nerrs
+@end example
+
+At the bottom of your parser, define a @code{struct language_defn} and
+initialize it with the right values for your language. Define an
+@code{initialize_@var{lang}} routine and have it call
+@samp{add_language(@var{lang}_language_defn)} to tell the rest of GDB
+that your language exists. You'll need some other supporting variables
+and functions, which will be used via pointers from your
+@code{@var{lang}_language_defn}. See the declaration of @code{struct
+language_defn} in @file{language.h}, and the other @file{*-exp.y} files,
+for more information.
+
+@item Add any evaluation routines, if necessary
+
+If you need new opcodes (that represent the operations of the language),
+add them to the enumerated type in @file{expression.h}. Add support
+code for these operations in @code{eval.c:evaluate_subexp()}. Add cases
+for new opcodes in two functions from @file{parse.c}:
+@code{prefixify_subexp()} and @code{length_of_subexp()}. These compute
+the number of @code{exp_element}s that a given operation takes up.
+
+@item Update some existing code
+
+Add an enumerated identifier for your language to the enumerated type
+@code{enum language} in @file{defs.h}.
+
+Update the routines in @file{language.c} so your language is included. These
+routines include type predicates and such, which (in some cases) are
+language dependent. If your language does not appear in the switch
+statement, an error is reported.
+
+Also included in @file{language.c} is the code that updates the variable
+@code{current_language}, and the routines that translate the
+@code{language_@var{lang}} enumerated identifier into a printable
+string.
+
+Update the function @code{_initialize_language} to include your language. This
+function picks the default language upon startup, so is dependent upon
+which languages that GDB is built for.
+
+Update @code{allocate_symtab} in @file{symfile.c} and/or symbol-reading
+code so that the language of each symtab (source file) is set properly.
+This is used to determine the language to use at each stack frame level.
+Currently, the language is set based upon the extension of the source
+file. If the language can be better inferred from the symbol
+information, please set the language of the symtab in the symbol-reading
+code.
+
+Add helper code to @code{expprint.c:print_subexp()} to handle any new
+expression opcodes you have added to @file{expression.h}. Also, add the
+printed representations of your operators to @code{op_print_tab}.
+
+@item Add a place of call
+
+Add a call to @code{@var{lang}_parse()} and @code{@var{lang}_error} in
+@code{parse.c:parse_exp_1()}.
+
+@item Use macros to trim code
+
+The user has the option of building GDB for some or all of the
+languages. If the user decides to build GDB for the language
+@var{lang}, then every file dependent on @file{language.h} will have the
+macro @code{_LANG_@var{lang}} defined in it. Use @code{#ifdef}s to
+leave out large routines that the user won't need if he or she is not
+using your language.
+
+Note that you do not need to do this in your YACC parser, since if GDB
+is not build for @var{lang}, then @file{@var{lang}-exp.tab.o} (the
+compiled form of your parser) is not linked into GDB at all.
+
+See the file @file{configure.in} for how GDB is configured for different
+languages.
+
+@item Edit @file{Makefile.in}
+
+Add dependencies in @file{Makefile.in}. Make sure you update the macro
+variables such as @code{HFILES} and @code{OBJS}, otherwise your code may
+not get linked in, or, worse yet, it may not get @code{tar}red into the
+distribution!
+@end table
+
+
+@node Releases
+@chapter Configuring GDB for Release
+
+From the top level directory (containing @file{gdb}, @file{bfd},
+@file{libiberty}, and so on):
+@example
+make -f Makefile.in gdb.tar.Z
+@end example
+
+This will properly configure, clean, rebuild any files that are
+distributed pre-built (e.g. @file{c-exp.tab.c} or @file{refcard.ps}),
+and will then make a tarfile. (If the top level directory has already
+beenn configured, you can just do @code{make gdb.tar.Z} instead.)
+
+This procedure requires:
+@itemize @bullet
+@item symbolic links
+@item @code{makeinfo} (texinfo2 level)
+@item @TeX{}
+@item @code{dvips}
+@item @code{yacc} or @code{bison}
+@end itemize
+@noindent
+@dots{} and the usual slew of utilities (@code{sed}, @code{tar}, etc.).
+
+@subheading TEMPORARY RELEASE PROCEDURE FOR DOCUMENTATION
+
+@file{gdb.texinfo} is currently marked up using the texinfo-2 macros,
+which are not yet a default for anything (but we have to start using
+them sometime).
+
+For making paper, the only thing this implies is the right generation of
+@file{texinfo.tex} needs to be included in the distribution.
+
+For making info files, however, rather than duplicating the texinfo2
+distribution, generate @file{gdb-all.texinfo} locally, and include the files
+@file{gdb.info*} in the distribution. Note the plural; @code{makeinfo} will
+split the document into one overall file and five or so included files.
+
+
+@node Partial Symbol Tables
+@chapter Partial Symbol Tables
+
+GDB has three types of symbol tables.
+
+@itemize @bullet
+@item full symbol tables (symtabs). These contain the main
+information about symbols and addresses.
+@item partial symbol tables (psymtabs). These contain enough
+information to know when to read the corresponding
+part of the full symbol table.
+@item minimal symbol tables (msymtabs). These contain information
+gleaned from non-debugging symbols.
+@end itemize
+
+This section describes partial symbol tables.
+
+A psymtab is constructed by doing a very quick pass over an executable
+file's debugging information. Small amounts of information are
+extracted -- enough to identify which parts of the symbol table will
+need to be re-read and fully digested later, when the user needs the
+information. The speed of this pass causes GDB to start up very
+quickly. Later, as the detailed rereading occurs, it occurs in small
+pieces, at various times, and the delay therefrom is mostly invisible to
+the user. (@xref{Symbol Reading}.)
+
+The symbols that show up in a file's psymtab should be, roughly, those
+visible to the debugger's user when the program is not running code from
+that file. These include external symbols and types, static
+symbols and types, and enum values declared at file scope.
+
+The psymtab also contains the range of instruction addresses that the
+full symbol table would represent.
+
+The idea is that there are only two ways for the user (or much of
+the code in the debugger) to reference a symbol:
+
+@itemize @bullet
+
+@item by its address
+(e.g. execution stops at some address which is inside a function
+in this file). The address will be noticed to be in the
+range of this psymtab, and the full symtab will be read in.
+@code{find_pc_function}, @code{find_pc_line}, and other @code{find_pc_@dots{}}
+functions handle this.
+
+@item by its name
+(e.g. the user asks to print a variable, or set a breakpoint on a
+function). Global names and file-scope names will be found in the
+psymtab, which will cause the symtab to be pulled in. Local names will
+have to be qualified by a global name, or a file-scope name, in which
+case we will have already read in the symtab as we evaluated the
+qualifier. Or, a local symbol can be referenced when
+we are "in" a local scope, in which case the first case applies.
+@code{lookup_symbol} does most of the work here.
+
+@end itemize
+
+The only reason that psymtabs exist is to cause a symtab to be read in
+at the right moment. Any symbol that can be elided from a psymtab,
+while still causing that to happen, should not appear in it. Since
+psymtabs don't have the idea of scope, you can't put local symbols in
+them anyway. Psymtabs don't have the idea of the type of a symbol,
+either, so types need not appear, unless they will be referenced by
+name.
+
+It is a bug for GDB to behave one way when only a psymtab has been read,
+and another way if the corresponding symtab has been read in. Such
+bugs are typically caused by a psymtab that does not contain all the
+visible symbols, or which has the wrong instruction address ranges.
+
+The psymtab for a particular section of a symbol-file (objfile)
+could be thrown away after the symtab has been read in. The symtab
+should always be searched before the psymtab, so the psymtab will
+never be used (in a bug-free environment). Currently,
+psymtabs are allocated on an obstack, and all the psymbols themselves
+are allocated in a pair of large arrays on an obstack, so there is
+little to be gained by trying to free them unless you want to do a lot
+more work.
+
+@node Types
+@chapter Types
+
+Fundamental Types (e.g., FT_VOID, FT_BOOLEAN).
+
+These are the fundamental types that gdb uses internally. Fundamental
+types from the various debugging formats (stabs, ELF, etc) are mapped into
+one of these. They are basically a union of all fundamental types that
+gdb knows about for all the languages that gdb knows about.
+
+Type Codes (e.g., TYPE_CODE_PTR, TYPE_CODE_ARRAY).
+
+Each time gdb builds an internal type, it marks it with one of these
+types. The type may be a fundamental type, such as TYPE_CODE_INT, or
+a derived type, such as TYPE_CODE_PTR which is a pointer to another
+type. Typically, several FT_* types map to one TYPE_CODE_* type, and
+are distinguished by other members of the type struct, such as whether
+the type is signed or unsigned, and how many bits it uses.
+
+Builtin Types (e.g., builtin_type_void, builtin_type_char).
+
+These are instances of type structs that roughly correspond to fundamental
+types and are created as global types for gdb to use for various ugly
+historical reasons. We eventually want to eliminate these. Note for
+example that builtin_type_int initialized in gdbtypes.c is basically the
+same as a TYPE_CODE_INT type that is initialized in c-lang.c for an
+FT_INTEGER fundamental type. The difference is that the builtin_type is
+not associated with any particular objfile, and only one instance exists,
+while c-lang.c builds as many TYPE_CODE_INT types as needed, with each
+one associated with some particular objfile.
+
+@node BFD support for GDB
+@chapter Binary File Descriptor Library Support for GDB
+
+BFD provides support for GDB in several ways:
+
+@table @emph
+@item identifying executable and core files
+BFD will identify a variety of file types, including a.out, coff, and
+several variants thereof, as well as several kinds of core files.
+
+@item access to sections of files
+BFD parses the file headers to determine the names, virtual addresses,
+sizes, and file locations of all the various named sections in files
+(such as the text section or the data section). GDB simply calls
+BFD to read or write section X at byte offset Y for length Z.
+
+@item specialized core file support
+BFD provides routines to determine the failing command name stored
+in a core file, the signal with which the program failed, and whether
+a core file matches (i.e. could be a core dump of) a particular executable
+file.
+
+@item locating the symbol information
+GDB uses an internal interface of BFD to determine where to find the
+symbol information in an executable file or symbol-file. GDB itself
+handles the reading of symbols, since BFD does not ``understand'' debug
+symbols, but GDB uses BFD's cached information to find the symbols,
+string table, etc.
+@end table
+
+@c The interface for symbol reading is described in @ref{Symbol
+@c Reading,,Symbol Reading}.
+
+
+@node Symbol Reading
+@chapter Symbol Reading
+
+GDB reads symbols from "symbol files". The usual symbol file is the
+file containing the program which gdb is debugging. GDB can be directed
+to use a different file for symbols (with the ``symbol-file''
+command), and it can also read more symbols via the ``add-file'' and ``load''
+commands, or while reading symbols from shared libraries.
+
+Symbol files are initially opened by @file{symfile.c} using the BFD
+library. BFD identifies the type of the file by examining its header.
+@code{symfile_init} then uses this identification to locate a
+set of symbol-reading functions.
+
+Symbol reading modules identify themselves to GDB by calling
+@code{add_symtab_fns} during their module initialization. The argument
+to @code{add_symtab_fns} is a @code{struct sym_fns} which contains
+the name (or name prefix) of the symbol format, the length of the prefix,
+and pointers to four functions. These functions are called at various
+times to process symbol-files whose identification matches the specified
+prefix.
+
+The functions supplied by each module are:
+
+@table @code
+@item @var{xxx}_symfile_init(struct sym_fns *sf)
+
+Called from @code{symbol_file_add} when we are about to read a new
+symbol file. This function should clean up any internal state
+(possibly resulting from half-read previous files, for example)
+and prepare to read a new symbol file. Note that the symbol file
+which we are reading might be a new "main" symbol file, or might
+be a secondary symbol file whose symbols are being added to the
+existing symbol table.
+
+The argument to @code{@var{xxx}_symfile_init} is a newly allocated
+@code{struct sym_fns} whose @code{bfd} field contains the BFD
+for the new symbol file being read. Its @code{private} field
+has been zeroed, and can be modified as desired. Typically,
+a struct of private information will be @code{malloc}'d, and
+a pointer to it will be placed in the @code{private} field.
+
+There is no result from @code{@var{xxx}_symfile_init}, but it can call
+@code{error} if it detects an unavoidable problem.
+
+@item @var{xxx}_new_init()
+
+Called from @code{symbol_file_add} when discarding existing symbols.
+This function need only handle
+the symbol-reading module's internal state; the symbol table data
+structures visible to the rest of GDB will be discarded by
+@code{symbol_file_add}. It has no arguments and no result.
+It may be called after @code{@var{xxx}_symfile_init}, if a new symbol
+table is being read, or may be called alone if all symbols are
+simply being discarded.
+
+@item @var{xxx}_symfile_read(struct sym_fns *sf, CORE_ADDR addr, int mainline)
+
+Called from @code{symbol_file_add} to actually read the symbols from a
+symbol-file into a set of psymtabs or symtabs.
+
+@code{sf} points to the struct sym_fns originally passed to
+@code{@var{xxx}_sym_init} for possible initialization. @code{addr} is the
+offset between the file's specified start address and its true address
+in memory. @code{mainline} is 1 if this is the main symbol table being
+read, and 0 if a secondary symbol file (e.g. shared library or
+dynamically loaded file) is being read.@refill
+@end table
+
+In addition, if a symbol-reading module creates psymtabs when
+@var{xxx}_symfile_read is called, these psymtabs will contain a pointer to
+a function @code{@var{xxx}_psymtab_to_symtab}, which can be called from
+any point in the GDB symbol-handling code.
+
+@table @code
+@item @var{xxx}_psymtab_to_symtab (struct partial_symtab *pst)
+
+Called from @code{psymtab_to_symtab} (or the PSYMTAB_TO_SYMTAB
+macro) if the psymtab has not already been read in and had its
+@code{pst->symtab} pointer set. The argument is the psymtab
+to be fleshed-out into a symtab. Upon return, pst->readin
+should have been set to 1, and pst->symtab should contain a
+pointer to the new corresponding symtab, or zero if there
+were no symbols in that part of the symbol file.
+@end table
+
+
+@node Cleanups
+@chapter Cleanups
+
+Cleanups are a structured way to deal with things that need to be done
+later. When your code does something (like @code{malloc} some memory, or open
+a file) that needs to be undone later (e.g. free the memory or close
+the file), it can make a cleanup. The cleanup will be done at some
+future point: when the command is finished, when an error occurs, or
+when your code decides it's time to do cleanups.
+
+You can also discard cleanups, that is, throw them away without doing
+what they say. This is only done if you ask that it be done.
+
+Syntax:
+
+@table @code
+@item struct cleanup *@var{old_chain};
+Declare a variable which will hold a cleanup chain handle.
+
+@item @var{old_chain} = make_cleanup (@var{function}, @var{arg});
+Make a cleanup which will cause @var{function} to be called with @var{arg}
+(a @code{char *}) later. The result, @var{old_chain}, is a handle that can be
+passed to @code{do_cleanups} or @code{discard_cleanups} later. Unless you are
+going to call @code{do_cleanups} or @code{discard_cleanups} yourself,
+you can ignore the result from @code{make_cleanup}.
+
+
+@item do_cleanups (@var{old_chain});
+Perform all cleanups done since @code{make_cleanup} returned @var{old_chain}.
+E.g.:
+@example
+make_cleanup (a, 0);
+old = make_cleanup (b, 0);
+do_cleanups (old);
+@end example
+@noindent
+will call @code{b()} but will not call @code{a()}. The cleanup that calls @code{a()} will remain
+in the cleanup chain, and will be done later unless otherwise discarded.@refill
+
+@item discard_cleanups (@var{old_chain});
+Same as @code{do_cleanups} except that it just removes the cleanups from the
+chain and does not call the specified functions.
+
+@end table
+
+Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they
+``should not be called when cleanups are not in place''. This means
+that any actions you need to reverse in the case of an error or
+interruption must be on the cleanup chain before you call these functions,
+since they might never return to your code (they @samp{longjmp} instead).
+
+
+@node Wrapping
+@chapter Wrapping Output Lines
+
+Output that goes through @code{printf_filtered} or @code{fputs_filtered} or
+@code{fputs_demangled} needs only to have calls to @code{wrap_here} added
+in places that would be good breaking points. The utility routines
+will take care of actually wrapping if the line width is exceeded.
+
+The argument to @code{wrap_here} is an indentation string which is printed
+@emph{only} if the line breaks there. This argument is saved away and used
+later. It must remain valid until the next call to @code{wrap_here} or
+until a newline has been printed through the @code{*_filtered} functions.
+Don't pass in a local variable and then return!
+
+It is usually best to call @code{wrap_here()} after printing a comma or space.
+If you call it before printing a space, make sure that your indentation
+properly accounts for the leading space that will print if the line wraps
+there.
+
+Any function or set of functions that produce filtered output must finish
+by printing a newline, to flush the wrap buffer, before switching to
+unfiltered (``@code{printf}'') output. Symbol reading routines that print
+warnings are a good example.
+
+
+@node Frames
+@chapter Frames
+
+A frame is a construct that GDB uses to keep track of calling and called
+functions.
+
+@table @code
+@item FRAME_FP
+in the machine description has no meaning to the machine-independent
+part of GDB, except that it is used when setting up a new frame from
+scratch, as follows:
+
+@example
+ create_new_frame (read_register (FP_REGNUM), read_pc ()));
+@end example
+
+Other than that, all the meaning imparted to @code{FP_REGNUM} is imparted by
+the machine-dependent code. So, @code{FP_REGNUM} can have any value that
+is convenient for the code that creates new frames. (@code{create_new_frame}
+calls @code{INIT_EXTRA_FRAME_INFO} if it is defined; that is where you should
+use the @code{FP_REGNUM} value, if your frames are nonstandard.)
+
+@item FRAME_CHAIN
+Given a GDB frame, determine the address of the calling function's
+frame. This will be used to create a new GDB frame struct, and then
+@code{INIT_EXTRA_FRAME_INFO} and @code{INIT_FRAME_PC} will be called for
+the new frame.
+@end table
+
+@node Remote Stubs
+@chapter Remote Stubs
+
+GDB's file @file{remote.c} talks a serial protocol to code that runs
+in the target system. GDB provides several sample ``stubs'' that can
+be integrated into target programs or operating systems for this purpose;
+they are named @file{*-stub.c}.
+
+The GDB user's manual describes how to put such a stub into your target
+code. What follows is a discussion of integrating the SPARC stub
+into a complicated operating system (rather than a simple program),
+by Stu Grossman, the author of this stub.
+
+The trap handling code in the stub assumes the following upon entry to
+trap_low:
+
+@enumerate
+@item %l1 and %l2 contain pc and npc respectively at the time of the trap
+@item traps are disabled
+@item you are in the correct trap window
+@end enumerate
+
+As long as your trap handler can guarantee those conditions, then there is no
+reason why you shouldn't be able to `share' traps with the stub. The stub has
+no requirement that it be jumped to directly from the hardware trap vector.
+That is why it calls @code{exceptionHandler()}, which is provided by the external
+environment. For instance, this could setup the hardware traps to actually
+execute code which calls the stub first, and then transfers to its own trap
+handler.
+
+For the most point, there probably won't be much of an issue with `sharing'
+traps, as the traps we use are usually not used by the kernel, and often
+indicate unrecoverable error conditions. Anyway, this is all controlled by a
+table, and is trivial to modify.
+The most important trap for us is for @code{ta 1}. Without that, we
+can't single step or do breakpoints. Everything else is unnecessary
+for the proper operation of the debugger/stub.
+
+From reading the stub, it's probably not obvious how breakpoints work. They
+are simply done by deposit/examine operations from GDB.
+
+@node Longjmp Support
+@chapter Longjmp Support
+
+GDB has support for figuring out that the target is doing a
+@code{longjmp} and for stopping at the target of the jump, if we are
+stepping. This is done with a few specialized internal breakpoints,
+which are visible in the @code{maint info breakpoint} command.
+
+To make this work, you need to define a macro called
+@code{GET_LONGJMP_TARGET}, which will examine the @code{jmp_buf}
+structure and extract the longjmp target address. Since @code{jmp_buf}
+is target specific, you will need to define it in the appropriate
+@file{tm-xxx.h} file. Look in @file{tm-sun4os4.h} and
+@file{sparc-tdep.c} for examples of how to do this.
+
+@node Coding Style
+@chapter Coding Style
+
+GDB is generally written using the GNU coding standards, as described in
+@file{standards.texi}, which is available for anonymous FTP from GNU
+archive sites. There are some additional considerations for GDB
+maintainers that reflect the unique environment and style of GDB
+maintenance. If you follow these guidelines, GDB will be more
+consistent and easier to maintain.
+
+GDB's policy on the use of prototypes is that prototypes are used
+to @emph{declare} functions but never to @emph{define} them. Simple
+macros are used in the declarations, so that a non-ANSI compiler can
+compile GDB without trouble. The simple macro calls are used like
+this:
+
+@example @code
+extern int
+memory_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+@end example
+
+Note the double parentheses around the parameter types. This allows
+an arbitrary number of parameters to be described, without freaking
+out the C preprocessor. When the function has no parameters, it
+should be described like:
+
+@example @code
+void
+noprocess PARAMS ((void));
+@end example
+
+The @code{PARAMS} macro expands to its argument in ANSI C, or to a simple
+@code{()} in traditional C.
+
+All external functions should have a @code{PARAMS} declaration in a
+header file that callers include. All static functions should have such
+a declaration near the top of their source file.
+
+We don't have a gcc option that will properly check that these rules
+have been followed, but it's GDB policy, and we periodically check it
+using the tools available (plus manual labor), and clean up any remnants.
+
+@node Clean Design
+@chapter Clean Design
+
+In addition to getting the syntax right, there's the little question of
+semantics. Some things are done in certain ways in GDB because long
+experience has shown that the more obvious ways caused various kinds of
+trouble. In particular:
+
+@table @bullet
+@item
+You can't assume the byte order of anything that comes from a
+target (including @var{value}s, object files, and instructions). Such
+things must be byte-swapped using @code{SWAP_TARGET_AND_HOST} in GDB,
+or one of the swap routines defined in @file{bfd.h}, such as @code{bfd_get_32}.
+
+@item
+You can't assume that you know what interface is being used to talk to
+the target system. All references to the target must go through the
+current @code{target_ops} vector.
+
+@item
+You can't assume that the host and target machines are the same machine
+(except in the ``native'' support modules).
+In particular, you can't assume that the target machine's header files
+will be available on the host machine. Target code must bring along its
+own header files -- written from scratch or explicitly donated by their
+owner, to avoid copyright problems.
+
+@item
+Insertion of new @code{#ifdef}'s will be frowned upon. It's much better
+to write the code portably than to conditionalize it for various systems.
+
+@item
+New @code{#ifdef}'s which test for specific compilers or manufacturers
+or operating systems are unacceptable. All @code{#ifdef}'s should test
+for features. The information about which configurations contain which
+features should be segregated into the configuration files. Experience
+has proven far too often that a feature unique to one particular system
+often creeps into other systems; and that a conditional based on
+some predefined macro for your current system will become worthless
+over time, as new versions of your system come out that behave differently
+with regard to this feature.
+
+@item
+Adding code that handles specific architectures, operating systems, target
+interfaces, or hosts, is not acceptable in generic code. If a hook
+is needed at that point, invent a generic hook and define it for your
+configuration, with something like:
+
+@example
+#ifdef WRANGLE_SIGNALS
+ WRANGLE_SIGNALS (signo);
+#endif
+@end example
+
+In your host, target, or native configuration file, as appropriate,
+define @code{WRANGLE_SIGNALS} to do the machine-dependent thing. Take
+a bit of care in defining the hook, so that it can be used by other
+ports in the future, if they need a hook in the same place.
+
+If the hook is not defined, the code should do whatever "most" machines
+want. Using @code{#ifdef}, as above, is the preferred way to do this,
+but sometimes that gets convoluted, in which case use
+
+@example
+#ifndef SPECIAL_FOO_HANDLING
+#define SPECIAL_FOO_HANDLING(pc, sp) (0)
+#endif
+@end example
+
+where the macro is used or in an appropriate header file.
+
+Whether to include a @dfn{small} hook, a hook around the exact pieces of
+code which are system-dependent, or whether to replace a whole function
+with a hook depends on the case. A good example of this dilemma can be
+found in @code{get_saved_register}. All machines that GDB 2.8 ran on
+just needed the @code{FRAME_FIND_SAVED_REGS} hook to find the saved
+registers. Then the SPARC and Pyramid came along, and
+@code{HAVE_REGISTER_WINDOWS} and @code{REGISTER_IN_WINDOW_P} were
+introduced. Then the 29k and 88k required the @code{GET_SAVED_REGISTER}
+hook. The first three are examples of small hooks; the latter replaces
+a whole function. In this specific case, it is useful to have both
+kinds; it would be a bad idea to replace all the uses of the small hooks
+with @code{GET_SAVED_REGISTER}, since that would result in much
+duplicated code. Other times, duplicating a few lines of code here or
+there is much cleaner than introducing a large number of small hooks.
+
+Another way to generalize GDB along a particular interface is with an
+attribute struct. For example, GDB has been generalized to handle
+multiple kinds of remote interfaces -- not by #ifdef's everywhere, but
+by defining the "target_ops" structure and having a current target (as
+well as a stack of targets below it, for memory references). Whenever
+something needs to be done that depends on which remote interface we are
+using, a flag in the current target_ops structure is tested (e.g.
+`target_has_stack'), or a function is called through a pointer in the
+current target_ops structure. In this way, when a new remote interface
+is added, only one module needs to be touched -- the one that actually
+implements the new remote interface. Other examples of
+attribute-structs are BFD access to multiple kinds of object file
+formats, or GDB's access to multiple source languages.
+
+Please avoid duplicating code. For example, in GDB 3.x all the code
+interfacing between @code{ptrace} and the rest of GDB was duplicated in
+@file{*-dep.c}, and so changing something was very painful. In GDB 4.x,
+these have all been consolidated into @file{infptrace.c}.
+@file{infptrace.c} can deal with variations between systems the same way
+any system-independent file would (hooks, #if defined, etc.), and
+machines which are radically different don't need to use infptrace.c at
+all.
+
+@item
+@emph{Do} write code that doesn't depend on the sizes of C data types,
+the format of the host's floating point numbers, the alignment of anything,
+or the order of evaluation of expressions. In short, follow good
+programming practices for writing portable C code.
+
+@end table
+
+@node Submitting Patches
+@chapter Submitting Patches
+
+Thanks for thinking of offering your changes back to the community of
+GDB users. In general we like to get well designed enhancements.
+Thanks also for checking in advance about the best way to transfer the
+changes.
+
+The two main problems with getting your patches in are,
+
+@table @bullet
+@item
+The GDB maintainers will only install ``cleanly designed'' patches.
+You may not always agree on what is clean design.
+@pxref{Coding Style}, @pxref{Clean Design}.
+
+@item
+If the maintainers don't have time to put the patch in when it
+arrives, or if there is any question about a patch, it
+goes into a large queue with everyone else's patches and
+bug reports.
+@end table
+
+I don't know how to get past these problems except by continuing to try.
+
+There are two issues here -- technical and legal.
+
+The legal issue is that to incorporate substantial changes requires a
+copyright assignment from you and/or your employer, granting ownership
+of the changes to the Free Software Foundation. You can get the
+standard document for doing this by sending mail to
+@code{gnu@@prep.ai.mit.edu} and asking for it. I recommend that people
+write in "All programs owned by the Free Software Foundation" as "NAME
+OF PROGRAM", so that changes in many programs (not just GDB, but GAS,
+Emacs, GCC, etc) can be contributed with only one piece of legalese
+pushed through the bureacracy and filed with the FSF. I can't start
+merging changes until this paperwork is received by the FSF (their
+rules, which I follow since I maintain it for them).
+
+Technically, the easiest way to receive changes is to receive each
+feature as a small context diff or unidiff, suitable for "patch".
+Each message sent to me should include the changes to C code and
+header files for a single feature, plus ChangeLog entries for each
+directory where files were modified, and diffs for any changes needed
+to the manuals (gdb/doc/gdb.texi or gdb/doc/gdbint.texi). If there
+are a lot of changes for a single feature, they can be split down
+into multiple messages.
+
+In this way, if I read and like the feature, I can add it to the
+sources with a single patch command, do some testing, and check it in.
+If you leave out the ChangeLog, I have to write one. If you leave
+out the doc, I have to puzzle out what needs documenting. Etc.
+
+The reason to send each change in a separate message is that I will
+not install some of the changes. They'll be returned to you with
+questions or comments. If I'm doing my job, my message back to you
+will say what you have to fix in order to make the change acceptable.
+The reason to have separate messages for separate features is so
+that other changes (which I @emph{am} willing to accept) can be installed
+while one or more changes are being reworked. If multiple features
+are sent in a single message, I tend to not put in the effort to sort
+out the acceptable changes from the unacceptable, so none of the
+features get installed until all are acceptable.
+
+If this sounds painful or authoritarian, well, it is. But I get a lot
+of bug reports and a lot of patches, and most of them don't get
+installed because I don't have the time to finish the job that the bug
+reporter or the contributor could have done. Patches that arrive
+complete, working, and well designed, tend to get installed on the day
+they arrive. The others go into a queue and get installed if and when
+I scan back over the queue -- which can literally take months
+sometimes. It's in both our interests to make patch installation easy
+-- you get your changes installed, and I make some forward progress on
+GDB in a normal 12-hour day (instead of them having to wait until I
+have a 14-hour or 16-hour day to spend cleaning up patches before I
+can install them).
+
+Please send patches to @code{bug-gdb@@prep.ai.mit.edu}, if they are less
+than about 25,000 characters. If longer than that, either make them
+available somehow (e.g. anonymous FTP), and announce it on
+@code{bug-gdb}, or send them directly to the GDB maintainers at
+@code{gdb-patches@@cygnus.com}.
+
+@node Host Conditionals
+@chapter Host Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation based on the attributes of the host
+system. These macros and their meanings are:
+
+@emph{NOTE: For now, both host and target conditionals are here.
+Eliminate target conditionals from this list as they are identified.}
+
+@table @code
+@item BLOCK_ADDRESS_FUNCTION_RELATIVE
+dbxread.c
+@item GDBINIT_FILENAME
+The default name of GDB's initialization file (normally @file{.gdbinit}).
+@item KERNELDEBUG
+tm-hppa.h
+@item MEM_FNS_DECLARED
+Your host config file defines this if it includes
+declarations of @code{memcpy} and @code{memset}. Define this
+to avoid conflicts between the native include
+files and the declarations in @file{defs.h}.
+@item NO_SYS_FILE
+dbxread.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item SIGWINCH_HANDLER_BODY
+utils.c
+@item ADDITIONAL_OPTIONS
+main.c
+@item ADDITIONAL_OPTION_CASES
+main.c
+@item ADDITIONAL_OPTION_HANDLER
+main.c
+@item ADDITIONAL_OPTION_HELP
+main.c
+@item ADDR_BITS_REMOVE
+defs.h
+@item AIX_BUGGY_PTRACE_CONTINUE
+infptrace.c
+@item ALIGN_STACK_ON_STARTUP
+main.c
+@item ALTOS
+altos-xdep.c
+@item ALTOS_AS
+xm-altos.h
+@item ASCII_COFF
+remote-adapt.c
+@item BADMAG
+coffread.c
+@item BCS
+tm-delta88.h
+@item BEFORE_MAIN_LOOP_HOOK
+main.c
+@item BELIEVE_PCC_PROMOTION
+coffread.c
+@item BELIEVE_PCC_PROMOTION_TYPE
+stabsread.c
+@item BITS_BIG_ENDIAN
+defs.h
+@item BKPT_AT_MAIN
+solib.c
+@item BLOCK_ADDRESS_ABSOLUTE
+dbxread.c
+@item BPT_VECTOR
+tm-m68k.h
+@item BREAKPOINT
+tm-m68k.h
+@item BREAKPOINT_DEBUG
+breakpoint.c
+@item BROKEN_LARGE_ALLOCA
+Avoid large @code{alloca}'s. For example, on sun's, Large alloca's fail
+because the attempt to increase the stack limit in main() fails because
+shared libraries are allocated just below the initial stack limit. The
+SunOS kernel will not allow the stack to grow into the area occupied by
+the shared libraries.
+@item BSTRING
+regex.c
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+@item CANNOT_FETCH_REGISTER
+hppabsd-xdep.c
+@item CANNOT_STORE_REGISTER
+findvar.c
+@item CFRONT_PRODUCER
+dwarfread.c
+@item CHILD_PREPARE_TO_STORE
+inftarg.c
+@item CLEAR_DEFERRED_STORES
+inflow.c
+@item CLEAR_SOLIB
+objfiles.c
+@item COFF_ENCAPSULATE
+hppabsd-tdep.c
+@item COFF_FORMAT
+symm-tdep.c
+@item CORE_NEEDS_RELOCATION
+stack.c
+@item CPLUS_MARKER
+cplus-dem.c
+@item CREATE_INFERIOR_HOOK
+infrun.c
+@item C_ALLOCA
+regex.c
+@item C_GLBLREG
+coffread.c
+@item DBXREAD_ONLY
+partial-stab.h
+@item DBX_PARM_SYMBOL_CLASS
+stabsread.c
+@item DEBUG
+remote-adapt.c
+@item DEBUG_INFO
+partial-stab.h
+@item DEBUG_PTRACE
+hppabsd-xdep.c
+@item DECR_PC_AFTER_BREAK
+breakpoint.c
+@item DEFAULT_PROMPT
+The default value of the prompt string (normally @code{"(gdb) "}).
+@item DELTA88
+m88k-xdep.c
+@item DEV_TTY
+symmisc.c
+@item DGUX
+m88k-xdep.c
+@item DISABLE_UNSETTABLE_BREAK
+breakpoint.c
+@item DONT_USE_REMOTE
+remote.c
+@item DO_DEFERRED_STORES
+infrun.c
+@item DO_REGISTERS_INFO
+infcmd.c
+@item EXTRACT_RETURN_VALUE
+tm-m68k.h
+@item EXTRACT_STRUCT_VALUE_ADDRESS
+values.c
+@item EXTRA_FRAME_INFO
+frame.h
+@item EXTRA_SYMTAB_INFO
+symtab.h
+@item FILES_INFO_HOOK
+target.c
+@item FLOAT_INFO
+infcmd.c
+@item FOPEN_RB
+defs.h
+@item FRAMELESS_FUNCTION_INVOCATION
+blockframe.c
+@item FRAME_ARGS_ADDRESS_CORRECT
+stack.c
+@item FRAME_CHAIN_COMBINE
+blockframe.c
+@item FRAME_CHAIN_VALID
+frame.h
+@item FRAME_CHAIN_VALID_ALTERNATE
+frame.h
+@item FRAME_FIND_SAVED_REGS
+stack.c
+@item FRAME_GET_BASEREG_VALUE
+frame.h
+@item FRAME_NUM_ARGS
+tm-m68k.h
+@item FRAME_SPECIFICATION_DYADIC
+stack.c
+@item FUNCTION_EPILOGUE_SIZE
+coffread.c
+@item F_OK
+xm-ultra3.h
+@item GCC2_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_MANGLE_BUG
+symtab.c
+@item GCC_PRODUCER
+dwarfread.c
+@item GET_SAVED_REGISTER
+findvar.c
+@item GPLUS_PRODUCER
+dwarfread.c
+@item HANDLE_RBRAC
+partial-stab.h
+@item HAVE_MMAP
+In some cases, use the system call @code{mmap} for reading symbol
+tables. For some machines this allows for sharing and quick updates.
+@item HAVE_REGISTER_WINDOWS
+findvar.c
+@item HAVE_SIGSETMASK
+main.c
+@item HAVE_TERMIO
+inflow.c
+@item HEADER_SEEK_FD
+arm-tdep.c
+@item HOSTING_ONLY
+xm-rtbsd.h
+@item HOST_BYTE_ORDER
+ieee-float.c
+@item HPUX_ASM
+xm-hp300hpux.h
+@item HPUX_VERSION_5
+hp300ux-xdep.c
+@item HP_OS_BUG
+infrun.c
+@item I80960
+remote-vx.c
+@item IEEE_DEBUG
+ieee-float.c
+@item IEEE_FLOAT
+valprint.c
+@item IGNORE_SYMBOL
+dbxread.c
+@item INIT_EXTRA_FRAME_INFO
+blockframe.c
+@item INIT_EXTRA_SYMTAB_INFO
+symfile.c
+@item INIT_FRAME_PC
+blockframe.c
+@item INNER_THAN
+valops.c
+@item INT_MAX
+defs.h
+@item INT_MIN
+defs.h
+@item IN_GDB
+i960-pinsn.c
+@item IN_SIGTRAMP
+infrun.c
+@item IN_SOLIB_TRAMPOLINE
+infrun.c
+@item ISATTY
+main.c
+@item IS_TRAPPED_INTERNALVAR
+values.c
+@item KERNELDEBUG
+dbxread.c
+@item KERNEL_DEBUGGING
+tm-ultra3.h
+@item KERNEL_U_ADDR
+Define this to the address of the @code{u} structure (the ``user struct'',
+also known as the ``u-page'') in kernel virtual memory. GDB needs to know
+this so that it can subtract this address from absolute addresses in
+the upage, that are obtained via ptrace or from core files. On systems
+that don't need this value, set it to zero.
+@item KERNEL_U_ADDR_BSD
+Define this to cause GDB to determine the address of @code{u} at runtime,
+by using Berkeley-style @code{nlist} on the kernel's image in the root
+directory.
+@item KERNEL_U_ADDR_HPUX
+Define this to cause GDB to determine the address of @code{u} at runtime,
+by using HP-style @code{nlist} on the kernel's image in the root
+directory.
+@item LCC_PRODUCER
+dwarfread.c
+@item LOG_FILE
+remote-adapt.c
+@item LONGERNAMES
+cplus-dem.c
+@item LONGEST
+defs.h
+@item CC_HAS_LONG_LONG
+defs.h
+@item PRINTF_HAS_LONG_LONG
+defs.h
+@item LONG_MAX
+defs.h
+@item LSEEK_NOT_LINEAR
+source.c
+@item L_LNNO32
+coffread.c
+@item L_SET
+This macro is used as the argument to lseek (or, most commonly, bfd_seek).
+FIXME, it should be replaced by SEEK_SET instead, which is the POSIX equivalent.
+@item MACHKERNELDEBUG
+hppabsd-tdep.c
+@item MAINTENANCE
+dwarfread.c
+@item MAINTENANCE_CMDS
+If the value of this is 1, then a number of optional maintenance commands
+are compiled in.
+@item MALLOC_INCOMPATIBLE
+Define this if the system's prototype for @code{malloc} differs from the
+@sc{ANSI} definition.
+@item MIPSEL
+mips-tdep.c
+@item MMAP_BASE_ADDRESS
+When using HAVE_MMAP, the first mapping should go at this address.
+@item MMAP_INCREMENT
+when using HAVE_MMAP, this is the increment between mappings.
+@item MONO
+ser-go32.c
+@item MOTOROLA
+xm-altos.h
+@item NBPG
+altos-xdep.c
+@item NEED_POSIX_SETPGID
+infrun.c
+@item NEED_TEXT_START_END
+exec.c
+@item NFAILURES
+regex.c
+@item NORETURN
+(in defs.h - is this really useful to define/undefine?)
+@item NOTDEF
+regex.c
+@item NOTDEF
+remote-adapt.c
+@item NOTDEF
+remote-mm.c
+@item NOTICE_SIGNAL_HANDLING_CHANGE
+infrun.c
+@item NO_HIF_SUPPORT
+remote-mm.c
+@item NO_JOB_CONTROL
+signals.h
+@item NO_MMALLOC
+GDB will use the @code{mmalloc} library for memory allocation for symbol
+reading, unless this symbol is defined. Define it on systems
+on which @code{mmalloc} does not
+work for some reason. One example is the DECstation, where its RPC
+library can't cope with our redefinition of @code{malloc} to call
+@code{mmalloc}. When defining @code{NO_MMALLOC}, you will also have
+to override the setting of @code{MMALLOC_LIB} to empty, in the Makefile.
+Therefore, this define is usually set on the command line by overriding
+@code{MMALLOC_DISABLE} in @file{config/*/*.mh}, rather than by defining
+it in @file{xm-*.h}.
+@item NO_MMALLOC_CHECK
+Define this if you are using @code{mmalloc}, but don't want the overhead
+of checking the heap with @code{mmcheck}.
+@item NO_SIGINTERRUPT
+remote-adapt.c
+@item NO_SINGLE_STEP
+infptrace.c
+@item NS32K_SVC_IMMED_OPERANDS
+ns32k-opcode.h
+@item NUMERIC_REG_NAMES
+mips-tdep.c
+@item N_SETV
+dbxread.c
+@item N_SET_MAGIC
+hppabsd-tdep.c
+@item NaN
+tm-umax.h
+@item ONE_PROCESS_WRITETEXT
+breakpoint.c
+@item O_BINARY
+exec.c
+@item O_RDONLY
+xm-ultra3.h
+@item PC
+convx-opcode.h
+@item PCC_SOL_BROKEN
+dbxread.c
+@item PC_IN_CALL_DUMMY
+inferior.h
+@item PC_LOAD_SEGMENT
+stack.c
+@item PRINT_RANDOM_SIGNAL
+infcmd.c
+@item PRINT_REGISTER_HOOK
+infcmd.c
+@item PRINT_TYPELESS_INTEGER
+valprint.c
+@item PROCESS_LINENUMBER_HOOK
+buildsym.c
+@item PROLOGUE_FIRSTLINE_OVERLAP
+infrun.c
+@item PSIGNAL_IN_SIGNAL_H
+defs.h
+@item PUSH_ARGUMENTS
+valops.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item PYRAMID_CORE
+pyr-xdep.c
+@item PYRAMID_PTRACE
+pyr-xdep.c
+@item REGISTER_BYTES
+remote.c
+@item REGISTER_NAMES
+tm-a29k.h
+@item REG_STACK_SEGMENT
+exec.c
+@item REG_STRUCT_HAS_ADDR
+findvar.c
+@item RE_NREGS
+regex.h
+@item R_FP
+dwarfread.c
+@item R_OK
+xm-altos.h
+@item SEEK_END
+state.c
+@item SEEK_SET
+state.c
+@item SEM
+coffread.c
+@item SET_STACK_LIMIT_HUGE
+When defined, stack limits will be raised to their maximum. Use this
+if your host supports @code{setrlimit} and you have trouble with
+@code{stringtab} in @file{dbxread.c}.
+
+Also used in @file{fork-child.c} to return stack limits before child
+processes are forked.
+@item SHELL_COMMAND_CONCAT
+infrun.c
+@item SHELL_FILE
+infrun.c
+@item SHIFT_INST_REGS
+breakpoint.c
+@item SIGN_EXTEND_CHAR
+regex.c
+@item SIGTRAP_STOP_AFTER_LOAD
+infrun.c
+@item SKIP_PROLOGUE
+tm-m68k.h
+@item SKIP_PROLOGUE_FRAMELESS_P
+blockframe.c
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item SOLIB_CREATE_INFERIOR_HOOK
+infrun.c
+@item STACK_ALIGN
+valops.c
+@item START_INFERIOR_TRAPS_EXPECTED
+infrun.c
+@item STOP_SIGNAL
+main.c
+@item STORE_RETURN_VALUE
+tm-m68k.h
+@item SUN4_COMPILER_FEATURE
+infrun.c
+@item SUN_FIXED_LBRAC_BUG
+dbxread.c
+@item SVR4_SHARED_LIBS
+solib.c
+@item SWITCH_ENUM_BUG
+regex.c
+@item SYM1
+tm-ultra3.h
+@item SYMBOL_RELOADING_DEFAULT
+symfile.c
+@item SYNTAX_TABLE
+regex.c
+@item Sword
+regex.c
+@item TDESC
+infrun.c
+@item TIOCGETC
+inflow.c
+@item TIOCGLTC
+inflow.c
+@item TIOCGPGRP
+inflow.c
+@item TIOCLGET
+inflow.c
+@item TIOCLSET
+inflow.c
+@item TIOCNOTTY
+inflow.c
+@item T_ARG
+coffread.c
+@item T_VOID
+coffread.c
+@item UINT_MAX
+defs.h
+@item UPAGES
+altos-xdep.c
+@item USER
+m88k-tdep.c
+@item USE_GAS
+xm-news.h
+@item USE_O_NOCTTY
+inflow.c
+@item USE_STRUCT_CONVENTION
+values.c
+@item USG
+Means that System V (prior to SVR4) include files are in use.
+(FIXME: This symbol is abused in @file{infrun.c}, @file{regex.c},
+@file{remote-nindy.c}, and @file{utils.c} for other things, at the moment.)
+@item USIZE
+xm-m88k.h
+@item U_FPSTATE
+i386-xdep.c
+@item VARIABLES_INSIDE_BLOCK
+dbxread.c
+@item WRS_ORIG
+remote-vx.c
+@item _LANG_c
+language.c
+@item _LANG_m2
+language.c
+@item __GNUC__
+news-xdep.c
+@item __GO32__
+inflow.c
+@item __HPUX_ASM__
+xm-hp300hpux.h
+@item __INT_VARARGS_H
+printcmd.c
+@item __not_on_pyr_yet
+pyr-xdep.c
+@item alloca
+defs.h
+@item const
+defs.h
+@item GOULD_PN
+gould-pinsn.c
+@item hp800
+xm-hppabsd.h
+@item hpux
+hppabsd-core.c
+@item lint
+valarith.c
+@item longest_to_int
+defs.h
+@item mc68020
+m68k-stub.c
+@item notdef
+gould-pinsn.c
+@item ns32k_opcodeT
+ns32k-opcode.h
+@item sgi
+mips-tdep.c
+@item sparc
+regex.c
+@item sun
+m68k-tdep.c
+@item sun386
+tm-sun386.h
+@item test
+regex.c
+@item ultrix
+xm-mips.h
+@item volatile
+defs.h
+@end table
+
+@node Target Conditionals
+@chapter Target Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation based on the attributes of the target
+system. These macros and their meanings are:
+
+@emph{NOTE: For now, both host and target conditionals are here.
+Eliminate host conditionals from this list as they are identified.}
+
+@table @code
+@item PUSH_DUMMY_FRAME
+Used in @samp{call_function_by_hand} to create an artificial stack frame.
+@item POP_FRAME
+Used in @samp{call_function_by_hand} to remove an artificial stack frame.
+@item BLOCK_ADDRESS_FUNCTION_RELATIVE
+dbxread.c
+@item KERNELDEBUG
+tm-hppa.h
+@item NO_SYS_FILE
+dbxread.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item SIGWINCH_HANDLER_BODY
+utils.c
+@item ADDITIONAL_OPTIONS
+main.c
+@item ADDITIONAL_OPTION_CASES
+main.c
+@item ADDITIONAL_OPTION_HANDLER
+main.c
+@item ADDITIONAL_OPTION_HELP
+main.c
+@item ADDR_BITS_REMOVE
+defs.h
+@item ALIGN_STACK_ON_STARTUP
+main.c
+@item ALTOS
+altos-xdep.c
+@item ALTOS_AS
+xm-altos.h
+@item ASCII_COFF
+remote-adapt.c
+@item BADMAG
+coffread.c
+@item BCS
+tm-delta88.h
+@item BEFORE_MAIN_LOOP_HOOK
+main.c
+@item BELIEVE_PCC_PROMOTION
+coffread.c
+@item BELIEVE_PCC_PROMOTION_TYPE
+stabsread.c
+@item BITS_BIG_ENDIAN
+defs.h
+@item BKPT_AT_MAIN
+solib.c
+@item BLOCK_ADDRESS_ABSOLUTE
+dbxread.c
+@item BPT_VECTOR
+tm-m68k.h
+@item BREAKPOINT
+tm-m68k.h
+@item BREAKPOINT_DEBUG
+breakpoint.c
+@item BSTRING
+regex.c
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+@item CANNOT_FETCH_REGISTER
+hppabsd-xdep.c
+@item CANNOT_STORE_REGISTER
+findvar.c
+@item CFRONT_PRODUCER
+dwarfread.c
+@item CHILD_PREPARE_TO_STORE
+inftarg.c
+@item CLEAR_DEFERRED_STORES
+inflow.c
+@item CLEAR_SOLIB
+objfiles.c
+@item COFF_ENCAPSULATE
+hppabsd-tdep.c
+@item COFF_FORMAT
+symm-tdep.c
+@item CORE_NEEDS_RELOCATION
+stack.c
+@item CPLUS_MARKER
+cplus-dem.c
+@item CREATE_INFERIOR_HOOK
+infrun.c
+@item C_ALLOCA
+regex.c
+@item C_GLBLREG
+coffread.c
+@item DBXREAD_ONLY
+partial-stab.h
+@item DBX_PARM_SYMBOL_CLASS
+stabsread.c
+@item DEBUG
+remote-adapt.c
+@item DEBUG_INFO
+partial-stab.h
+@item DEBUG_PTRACE
+hppabsd-xdep.c
+@item DECR_PC_AFTER_BREAK
+breakpoint.c
+@item DELTA88
+m88k-xdep.c
+@item DEV_TTY
+symmisc.c
+@item DGUX
+m88k-xdep.c
+@item DISABLE_UNSETTABLE_BREAK
+breakpoint.c
+@item DONT_USE_REMOTE
+remote.c
+@item DO_DEFERRED_STORES
+infrun.c
+@item DO_REGISTERS_INFO
+infcmd.c
+@item END_OF_TEXT_DEFAULT
+This is an expression that should designate the end of the text section
+(? FIXME ?)
+@item EXTRACT_RETURN_VALUE
+tm-m68k.h
+@item EXTRACT_STRUCT_VALUE_ADDRESS
+values.c
+@item EXTRA_FRAME_INFO
+frame.h
+@item EXTRA_SYMTAB_INFO
+symtab.h
+@item FILES_INFO_HOOK
+target.c
+@item FLOAT_INFO
+infcmd.c
+@item FOPEN_RB
+defs.h
+@item FP0_REGNUM
+a68v-xdep.c
+@item FPC_REGNUM
+mach386-xdep.c
+@item FP_REGNUM
+parse.c
+@item FPU
+Unused? 6-oct-92 rich@@cygnus.com. FIXME.
+@item FRAMELESS_FUNCTION_INVOCATION
+blockframe.c
+@item FRAME_ARGS_ADDRESS_CORRECT
+stack.c
+@item FRAME_CHAIN
+Given FRAME, return a pointer to the calling frame.
+@item FRAME_CHAIN_COMBINE
+blockframe.c
+@item FRAME_CHAIN_VALID
+frame.h
+@item FRAME_CHAIN_VALID_ALTERNATE
+frame.h
+@item FRAME_FIND_SAVED_REGS
+stack.c
+@item FRAME_GET_BASEREG_VALUE
+frame.h
+@item FRAME_NUM_ARGS
+tm-m68k.h
+@item FRAME_SPECIFICATION_DYADIC
+stack.c
+@item FRAME_SAVED_PC
+Given FRAME, return the pc saved there. That is, the return address.
+@item FUNCTION_EPILOGUE_SIZE
+coffread.c
+@item F_OK
+xm-ultra3.h
+@item GCC2_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_MANGLE_BUG
+symtab.c
+@item GCC_PRODUCER
+dwarfread.c
+@item GDB_TARGET_IS_HPPA
+This determines whether horrible kludge code in dbxread.c and partial-stab.h
+is used to mangle multiple-symbol-table files from HPPA's. This should all
+be ripped out, and a scheme like elfread.c used.
+@item GDB_TARGET_IS_MACH386
+mach386-xdep.c
+@item GDB_TARGET_IS_SUN3
+a68v-xdep.c
+@item GDB_TARGET_IS_SUN386
+sun386-xdep.c
+@item GET_LONGJMP_TARGET
+For most machines, this is a target-dependent parameter. On the DECstation
+and the Iris, this is a native-dependent parameter, since <setjmp.h> is
+needed to define it.
+
+This macro determines the target PC address that longjmp() will jump
+to, assuming that we have just stopped at a longjmp breakpoint. It
+takes a CORE_ADDR * as argument, and stores the target PC value through
+this pointer. It examines the current state of the machine as needed.
+@item GET_SAVED_REGISTER
+findvar.c
+@item GPLUS_PRODUCER
+dwarfread.c
+@item GR64_REGNUM
+remote-adapt.c
+@item GR64_REGNUM
+remote-mm.c
+@item HANDLE_RBRAC
+partial-stab.h
+@item HAVE_68881
+m68k-tdep.c
+@item HAVE_REGISTER_WINDOWS
+findvar.c
+@item HAVE_SIGSETMASK
+main.c
+@item HAVE_TERMIO
+inflow.c
+@item HEADER_SEEK_FD
+arm-tdep.c
+@item HOSTING_ONLY
+xm-rtbsd.h
+@item HOST_BYTE_ORDER
+ieee-float.c
+@item HPUX_ASM
+xm-hp300hpux.h
+@item HPUX_VERSION_5
+hp300ux-xdep.c
+@item HP_OS_BUG
+infrun.c
+@item I80960
+remote-vx.c
+@item IBM6000_TARGET
+Shows that we are configured for an IBM RS/6000 target. This conditional
+should be eliminated (FIXME) and replaced by feature-specific macros.
+It was introduced in haste and we are repenting at leisure.
+@item IEEE_DEBUG
+ieee-float.c
+@item IEEE_FLOAT
+valprint.c
+@item IGNORE_SYMBOL
+dbxread.c
+@item INIT_EXTRA_FRAME_INFO
+blockframe.c
+@item INIT_EXTRA_SYMTAB_INFO
+symfile.c
+@item INIT_FRAME_PC
+blockframe.c
+@item INNER_THAN
+valops.c
+@item INT_MAX
+defs.h
+@item INT_MIN
+defs.h
+@item IN_GDB
+i960-pinsn.c
+@item IN_SIGTRAMP
+infrun.c
+@item IN_SOLIB_TRAMPOLINE
+infrun.c
+@item ISATTY
+main.c
+@item IS_TRAPPED_INTERNALVAR
+values.c
+@item KERNELDEBUG
+dbxread.c
+@item KERNEL_DEBUGGING
+tm-ultra3.h
+@item LCC_PRODUCER
+dwarfread.c
+@item LOG_FILE
+remote-adapt.c
+@item LONGERNAMES
+cplus-dem.c
+@item LONGEST
+defs.h
+@item CC_HAS_LONG_LONG
+defs.h
+@item PRINTF_HAS_LONG_LONG
+defs.h
+@item LONG_MAX
+defs.h
+@item L_LNNO32
+coffread.c
+@item MACHKERNELDEBUG
+hppabsd-tdep.c
+@item MAINTENANCE
+dwarfread.c
+@item MIPSEL
+mips-tdep.c
+@item MOTOROLA
+xm-altos.h
+@item NBPG
+altos-xdep.c
+@item NEED_POSIX_SETPGID
+infrun.c
+@item NEED_TEXT_START_END
+exec.c
+@item NFAILURES
+regex.c
+@item NNPC_REGNUM
+infrun.c
+@item NOTDEF
+regex.c
+@item NOTDEF
+remote-adapt.c
+@item NOTDEF
+remote-mm.c
+@item NOTICE_SIGNAL_HANDLING_CHANGE
+infrun.c
+@item NO_HIF_SUPPORT
+remote-mm.c
+@item NO_SIGINTERRUPT
+remote-adapt.c
+@item NO_SINGLE_STEP
+infptrace.c
+@item NPC_REGNUM
+infcmd.c
+@item NS32K_SVC_IMMED_OPERANDS
+ns32k-opcode.h
+@item NUMERIC_REG_NAMES
+mips-tdep.c
+@item N_SETV
+dbxread.c
+@item N_SET_MAGIC
+hppabsd-tdep.c
+@item NaN
+tm-umax.h
+@item ONE_PROCESS_WRITETEXT
+breakpoint.c
+@item PC
+convx-opcode.h
+@item PCC_SOL_BROKEN
+dbxread.c
+@item PC_IN_CALL_DUMMY
+inferior.h
+@item PC_LOAD_SEGMENT
+stack.c
+@item PC_REGNUM
+parse.c
+@item PRINT_RANDOM_SIGNAL
+infcmd.c
+@item PRINT_REGISTER_HOOK
+infcmd.c
+@item PRINT_TYPELESS_INTEGER
+valprint.c
+@item PROCESS_LINENUMBER_HOOK
+buildsym.c
+@item PROLOGUE_FIRSTLINE_OVERLAP
+infrun.c
+@item PSIGNAL_IN_SIGNAL_H
+defs.h
+@item PS_REGNUM
+parse.c
+@item PUSH_ARGUMENTS
+valops.c
+@item REGISTER_BYTES
+remote.c
+@item REGISTER_NAMES
+tm-a29k.h
+@item REG_STACK_SEGMENT
+exec.c
+@item REG_STRUCT_HAS_ADDR
+findvar.c
+@item RE_NREGS
+regex.h
+@item R_FP
+dwarfread.c
+@item R_OK
+xm-altos.h
+@item SDB_REG_TO_REGNUM
+Define this to convert sdb register numbers
+into gdb regnums. If not defined, no conversion will be done.
+@item SEEK_END
+state.c
+@item SEEK_SET
+state.c
+@item SEM
+coffread.c
+@item SHELL_COMMAND_CONCAT
+infrun.c
+@item SHELL_FILE
+infrun.c
+@item SHIFT_INST_REGS
+breakpoint.c
+@item SIGN_EXTEND_CHAR
+regex.c
+@item SIGTRAP_STOP_AFTER_LOAD
+infrun.c
+@item SKIP_PROLOGUE
+tm-m68k.h
+@item SKIP_PROLOGUE_FRAMELESS_P
+blockframe.c
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item SOLIB_CREATE_INFERIOR_HOOK
+infrun.c
+@item SP_REGNUM
+parse.c
+@item STAB_REG_TO_REGNUM
+Define this to convert stab register numbers (as gotten from `r' declarations)
+into gdb regnums. If not defined, no conversion will be done.
+@item STACK_ALIGN
+valops.c
+@item START_INFERIOR_TRAPS_EXPECTED
+infrun.c
+@item STOP_SIGNAL
+main.c
+@item STORE_RETURN_VALUE
+tm-m68k.h
+@item SUN4_COMPILER_FEATURE
+infrun.c
+@item SUN_FIXED_LBRAC_BUG
+dbxread.c
+@item SVR4_SHARED_LIBS
+solib.c
+@item SWITCH_ENUM_BUG
+regex.c
+@item SYM1
+tm-ultra3.h
+@item SYMBOL_RELOADING_DEFAULT
+symfile.c
+@item SYNTAX_TABLE
+regex.c
+@item Sword
+regex.c
+@item TARGET_BYTE_ORDER
+defs.h
+@item TARGET_CHAR_BIT
+defs.h
+@item TARGET_COMPLEX_BIT
+defs.h
+@item TARGET_DOUBLE_BIT
+defs.h
+@item TARGET_DOUBLE_COMPLEX_BIT
+defs.h
+@item TARGET_FLOAT_BIT
+defs.h
+@item TARGET_INT_BIT
+defs.h
+@item TARGET_LONG_BIT
+defs.h
+@item TARGET_LONG_DOUBLE_BIT
+defs.h
+@item TARGET_LONG_LONG_BIT
+defs.h
+@item TARGET_PTR_BIT
+defs.h
+@item TARGET_READ_PC
+@item TARGET_WRITE_PC
+@item TARGET_READ_SP
+@item TARGET_WRITE_SP
+@item TARGET_READ_FP
+@item TARGET_WRITE_FP
+These change the behavior of @code{read_pc}, @code{write_pc},
+@code{read_sp}, @code{write_sp}, @code{read_fp} and @code{write_fp}.
+For most targets, these may be left undefined. GDB will call the
+read and write register functions with the relevant @code{_REGNUM} argument.
+
+These macros are useful when a target keeps one of these registers in a
+hard to get at place; for example, part in a segment register and part
+in an ordinary register.
+
+@item TARGET_SHORT_BIT
+defs.h
+@item TDESC
+infrun.c
+@item T_ARG
+coffread.c
+@item T_VOID
+coffread.c
+@item UINT_MAX
+defs.h
+@item USER
+m88k-tdep.c
+@item USE_GAS
+xm-news.h
+@item USE_STRUCT_CONVENTION
+values.c
+@item USIZE
+xm-m88k.h
+@item U_FPSTATE
+i386-xdep.c
+@item VARIABLES_INSIDE_BLOCK
+dbxread.c
+@item WRS_ORIG
+remote-vx.c
+@item _LANG_c
+language.c
+@item _LANG_m2
+language.c
+@item __GO32__
+inflow.c
+@item __HPUX_ASM__
+xm-hp300hpux.h
+@item __INT_VARARGS_H
+printcmd.c
+@item __not_on_pyr_yet
+pyr-xdep.c
+@item GOULD_PN
+gould-pinsn.c
+@item hp800
+xm-hppabsd.h
+@item hpux
+hppabsd-core.c
+@item longest_to_int
+defs.h
+@item mc68020
+m68k-stub.c
+@item ns32k_opcodeT
+ns32k-opcode.h
+@item sgi
+mips-tdep.c
+@item sparc
+regex.c
+@item sun
+m68k-tdep.c
+@item sun386
+tm-sun386.h
+@item test
+(Define this to enable testing code in regex.c.)
+@end table
+
+@node Native Conditionals
+@chapter Native Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation when the host and target systems
+are the same. These macros should be defined (or left undefined)
+in @file{nm-@var{system}.h}.
+
+@table @code
+@item ATTACH_DETACH
+If defined, then gdb will include support for the @code{attach} and
+@code{detach} commands.
+@item FETCH_INFERIOR_REGISTERS
+Define this if the native-dependent code will provide its
+own routines
+@code{fetch_inferior_registers} and @code{store_inferior_registers} in
+@file{@var{HOST}-nat.c}.
+If this symbol is @emph{not} defined, and @file{infptrace.c}
+is included in this configuration, the default routines in
+@file{infptrace.c} are used for these functions.
+@item GET_LONGJMP_TARGET
+For most machines, this is a target-dependent parameter. On the DECstation
+and the Iris, this is a native-dependent parameter, since <setjmp.h> is
+needed to define it.
+
+This macro determines the target PC address that longjmp() will jump
+to, assuming that we have just stopped at a longjmp breakpoint. It
+takes a CORE_ADDR * as argument, and stores the target PC value through
+this pointer. It examines the current state of the machine as needed.
+@item PROC_NAME_FMT
+Defines the format for the name of a @file{/proc} device. Should be
+defined in @file{nm.h} @emph{only} in order to override the default
+definition in @file{procfs.c}.
+@item PTRACE_FP_BUG
+mach386-xdep.c
+@item PTRACE_ARG3_TYPE
+The type of the third argument to the @code{ptrace} system call, if it exists
+and is different from @code{int}.
+@item REGISTER_U_ADDR
+Defines the offset of the registers in the ``u area''; @pxref{Host}.
+@item USE_PROC_FS
+This determines whether small routines in @file{*-tdep.c}, which
+translate register values
+between GDB's internal representation and the /proc representation,
+are compiled.
+@item U_REGS_OFFSET
+This is the offset of the registers in the upage. It need only be
+defined if the generic ptrace register access routines in
+@file{infptrace.c} are being used (that is,
+@file{infptrace.c} is configured in, and
+@code{FETCH_INFERIOR_REGISTERS} is not defined). If the default value
+from @file{infptrace.c} is good enough, leave it undefined.
+
+The default value means that u.u_ar0 @emph{points to} the location of the
+registers. I'm guessing that @code{#define U_REGS_OFFSET 0} means that
+u.u_ar0 @emph{is} the location of the registers.
+@end table
+
+@node Obsolete Conditionals
+@chapter Obsolete Conditionals
+
+Fragments of old code in GDB sometimes reference or set the following
+configuration macros. They should not be used by new code, and
+old uses should be removed as those parts of the debugger are
+otherwise touched.
+
+@table @code
+@item STACK_END_ADDR
+This macro used to define where the end of the stack appeared, for use
+in interpreting core file formats that don't record this address in the
+core file itself. This information is now configured in BFD, and GDB
+gets the info portably from there. The values in GDB's configuration
+files should be moved into BFD configuration files (if needed there),
+and deleted from all of GDB's config files.
+
+Any @file{@var{foo}-xdep.c} file that references STACK_END_ADDR
+is so old that it has never been converted to use BFD. Now that's old!
+@end table
+
+@node XCOFF
+@chapter The XCOFF Object File Format
+
+The IBM RS/6000 running AIX uses an object file format called xcoff.
+The COFF sections, symbols, and line numbers are used, but debugging
+symbols are dbx-style stabs whose strings are located in the
+@samp{.debug} section (rather than the string table). For more
+information, @xref{Top,,,stabs,The Stabs Debugging Format}, and search
+for XCOFF.
+
+The shared library scheme has a nice clean interface for figuring out
+what shared libraries are in use, but the catch is that everything which
+refers to addresses (symbol tables and breakpoints at least) needs to be
+relocated for both shared libraries and the main executable. At least
+using the standard mechanism this can only be done once the program has
+been run (or the core file has been read).
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/doc/h8-cfg.texi b/gnu/usr.bin/gdb/doc/h8-cfg.texi
new file mode 100644
index 000000000000..823c7c244b5a
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/h8-cfg.texi
@@ -0,0 +1,47 @@
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@set AGGLOMERATION
+@clear AMD29K
+@set BARETARGET
+@clear CONLY
+@set DOSHOST
+@clear FORTRAN
+@clear FSFDOC
+@clear GDBSERVER
+@clear GENERIC
+@set H8
+@set H8EXCLUSIVE
+@clear HAVE-FLOAT
+@clear I960
+@clear MOD2
+@clear NOVEL
+@clear POSIX
+@set PRECONFIGURED
+@clear REMOTESTUB
+@set SIMS
+@clear SERIAL
+@clear SPARC
+@clear ST2000
+@clear VXWORKS
+@clear Z8K
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of target.
+@set TARGET Hitachi Microprocessors
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
diff --git a/gnu/usr.bin/gdb/doc/libgdb.texinfo b/gnu/usr.bin/gdb/doc/libgdb.texinfo
new file mode 100644
index 000000000000..c67c3a88359d
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/libgdb.texinfo
@@ -0,0 +1,1471 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename libgdb.info
+@settitle Libgdb
+@setchapternewpage odd
+@c %**end of header
+
+@ifinfo
+This file documents libgdb, the GNU library for symbolic debuggers.
+
+Copyright 1993 Cygnus Support
+
+Permission is granted to ...
+@end ifinfo
+
+@c This title page illustrates only one of the
+@c two methods of forming a title page.
+
+@titlepage
+@title Libgdb
+@subtitle Version 0.1
+@subtitle 27 Sep 1993
+@author Thomas Lord
+
+@c The following two commands
+@c start the copyright page.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1993 COPYRIGHT-OWNER
+
+Published by ...
+
+Permission is granted to ...
+@end titlepage
+
+@node Top, Overview, (dir), (dir)
+
+@ifinfo
+
+Libgdb is a library which provides the core functionality of a symbolic
+debugger. It is derived from GNU GDB and depends on the BFD library.
+
+This is an early draft of this document. Subsequent versions will likely
+contain revisions, deletions and additions.
+
+This document applies to version 0.0.
+
+Text marked `[[[' indicates areas which require expansion.
+
+Many nodes describe library entry points by giving a prototype and brief
+description:
+
+@deftypefun {const char **} gdb_warranty ()
+(warranty_info)
+Return a pointer to the text of the GDB disclaimer.
+@end deftypefun
+
+The parenthesized symbols (e.g. `(warranty_info)') refer to the
+existing GDB source and generally indicate where to find code with
+which to implement the library function.
+@end ifinfo
+
+@menu
+* Copying:: Your rights and freedoms.
+* Overview:: The basics of libgdb and this document.
+* Conventions:: Programming conventions for users of libgdb.
+* Targets:: Selecting debugging targets and symbol tables.
+* Symtabs:: Accessing symbol tables and debugging information.
+* Source:: Relating inferiors to source files.
+* Running:: Creating, continuing, and stepping through an
+ inferior process.
+* Stopping:: Using breakpoints, signaling an inferior.
+* Stack:: Accessing an inferior's execution stack.
+* Expressions:: How to parse and evaluate expressions in the
+ context of an inferior.
+* Values:: Data from the inferior, the values of expressions.
+* Examining:: Formatting values as strings.
+* Types:: Examining the types of an inferiors data.
+@end menu
+
+
+@node Copying, Overview, top, top
+@comment node-name, next, previous, up
+@chapter Copying
+@cindex copying
+
+blah blah
+
+@node Overview, Conventions, Copying, top
+@comment node-name, next, previous, up
+@chapter Overview
+@cindex overview
+@cindex definitions
+
+
+Libgdb is a library which provides the core functionality of a symbolic
+debugger. It is derived from GNU GDB and depends on the BFD library.
+
+target
+inferior
+
+
+
+@node Conventions, Targets, Overview, top
+@comment node-name, next, previous, up
+@chapter Programming Conventions for Libgdb Clients
+@cindex Conventions
+
+@heading Naming Conventions
+
+Names intentionally exported from libgdb all begin @code{gdb_}
+as in @code{gdb_use_file}.
+
+
+@heading Error Returns
+
+Libgdb functions that might not succeed generally have a return
+type of @code{gdb_error_t}.
+
+@deftypefun {const char *} gdb_error_msg (gdb_error_t @var{error})
+returns a reasonable error message for @var{error}.
+@end deftypefun
+
+
+@heading Blocking I/O
+
+[[[....]]]
+
+
+@heading Global Parameters
+@subheading the current directory
+@deftypefun gdb_error_t gdb_cd (char * @var{dir})
+Specify gdb's default directory as well as the working
+directory for the inferior (when first started).@*
+(cd_command)
+@end deftypefun
+
+@deftypefun {char *} gdb_copy_pwd ()
+Make a copy of the name of gdb's default directory.@*
+(pwd_command)
+@end deftypefun
+
+
+@subheading controlling the input/output radix
+@deftypefun gdb_error_t gdb_set_base (int)
+Change the default output radix to 10 or 16, or set it to 0
+(heuristic). This command is mostly obsolete now that the print
+command allows formats to apply to aggregates, but is still handy
+occasionally.@*
+(set_base_command)
+@end deftypefun
+
+@deftypefun gdb_error_t gdb_set_input_radix (int)
+@deftypefunx gdb_error_t gdb_set_output_radix (int)
+@deftypefunx gdb_error_t gdb_set_radix (int)
+Valid output radixes are only 0 (heuristic), 10, and 16.@*
+(set_radix)
+@end deftypefun
+
+
+@subheading manipulating environments
+@deftp Type {struct environ}
+@example
+struct environ
+@{
+ int allocated;
+ char ** vector;
+@}
+@end example
+A `struct environ' holds a description of environment
+variable bindings.
+@end deftp
+
+@deftypefun {struct environ *} gdb_make_environ ()
+Create a new (empty) environment.@*
+(make_environ)
+@end deftypefun
+
+@deftypefun {void} gdb_free_environ (struct environ *)
+Free an environment allocated by `gdb_make_environ'.@*
+(free_environ)
+@end deftypefun
+
+@deftypefun {void} gdb_init_environ (struct environ * env)
+Copy the processes environment into ENV.@*
+(init_environ)
+@end deftypefun
+
+@deftypefun {char **} gdb_get_in_environ (const struct environ * @var{env}, const char * @var{var})
+Look up the binding of @var{var} in @var{env}.@*
+(get_in_environ)
+@end deftypefun
+
+
+@deftypefun {void} gdb_set_in_environ (struct environ * @var{env}, const char * @var{var}, const char * @var{value})
+Lookup/bind variables within an environment.
+(set_in_environ)
+@end deftypefun
+
+
+@subheading legal notices
+@deftypefun {char **} gdb_copying ()
+@deftypefunx {char **} gdb_warranty ()
+These return pointers to NULL terminated arrays of strings.
+They contain text which describes the conditions under which
+libgdb is distributed (`gdb_copying') and which explains to
+users that there is no warranty for libgdb (`gdb_warranty').@*
+(show_warranty_command, show_copying_command)
+@end deftypefun
+
+
+@subheading the inferior's terminal
+@deftypefun void gdb_inferiors_io (int @var{std_in}, int @var{std_out}, int @var{std_err})
+Assert that the given descriptors should be copied into
+descriptors 0, 1, and 2 of the inferior when it
+is next run.
+@end deftypefun
+
+
+@heading callbacks
+
+One idiom used in several places deserves mention.
+At times, it makes sense for libgdb functions to
+invoke functions provided by the libgdb client.
+Where this is the case, callback structures are used
+to refer to client functions. For example, here
+are the declarations for a callback to which libgdb
+will pass an integer and a character pointer.
+
+@example
+struct a_gdb_cback;
+typedef void (*a_gdb_cback_fn) (struct a_gdb_cback *,
+ int, char *);
+@end example
+
+Suppose the client wants the callback to be implemented
+by @code{foo} which we will assume takes not only the integer
+and character pointer, but also a floating point number.
+The client could use these declarations:
+
+@example
+struct my_cback
+@{
+ struct a_gdb_cback gdb_cback; /* must be first */
+ float magic_number;
+@};
+
+void
+foo_helper (struct a_gdb_cback * callback, int i, char * cp)
+@{
+ foo ( ((struct my_cback *)callback)->magic_number, i, c);
+@}
+
+struct my_cback
+@{
+ foo_helper,
+ 1079252848.8
+@} the_cback;
+@end example
+
+
+@subheading stream callbacks
+
+A common kind of callback takes just a character pointer,
+presumed to point to part or all of an informational
+message.
+
+@example
+struct gdb_stream_cback;
+typedef void (*gdb_stream_cback_fn) (struct gdb_stream_cback *,
+ char *);
+@end example
+
+
+@subheading integer callbacks
+
+Another common kind of callback takes just an integer.
+
+@example
+struct gdb_int_cback;
+typedef void (*gdb_int_cback_fn) (struct gdb_int_cback *, int);
+@end example
+
+@node Targets, Symtabs, Conventions, top
+@comment node-name, next, previous, up
+@chapter Selecting Targets and Symbol Tables for Debugging
+@cindex targets
+
+@deftypefun gdb_error_t gdb_use_file (char * @var{filename})
+Arrange to read both executable code and symbol table information
+from FILENAME.
+
+This is exactly equivalent to a sequence of two calls:
+@example
+ gdb_use_exec_file (filename);
+ gdb_use_symbol_file (filename);
+@end example
+(file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_exec_file (char * @var{filename})
+Read the code to debug from `filename'.@*
+(exec_file_command)
+@end deftypefun
+
+
+@deftypefun {char *} gdb_get_exec_file ()
+Return the name of the executable file as a string or 0
+if there is none.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_core (char * @var{filename})
+Specify the whereabouts of a core dump file to be used as the
+"contents of memory". Traditionally, core files contain only some
+parts of the address space of the process that generated them; GDB
+can access the executable file itself for other parts.
+
+If @var{filename} is @code{NULL}, no core file is used.@*
+(core_file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_symbol_file (char * @var{filename})
+Arrange to read symbol table information from `filename'.
+
+This is the same as:
+
+ gdb_symbol_file_add (filename, 1, (CORE_ADDR)0, 1, 0, 0);
+
+See @code{gdb_symbol_file_add} for finer control over the symbol
+table.@*
+(symbol_file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_symbol_file_add (@var{name}, @var{verbose}, @var{text_addr}, @var{replace}, @var{eager})
+Arrange to read additional symbol table information from
+the file `name'.
+
+The arguments are:
+@itemize @minus
+@item struct gdb_stream_cback * @var{info_out}
+
+Callback to handle informational output.
+
+@item char * @var{name}
+
+If not 0, verbose output will occur.
+
+@item int @var{be_verbose}
+
+Regulates the amount of informational output produced.
+
+@item CORE_ADDR @var{text_addr}
+
+is the address at which the named file is presumed to have
+been loaded.
+
+@item int @var{replace}@*
+
+If not 0, this will become the only file
+in the symbol table -- all previously loaded
+symbol table information will be discarded.
+
+@item int @var{readnow}
+
+If not 0, eagerly read symbols from this file,otherwise
+symbols will only be read lazily (as needed).
+@end itemize
+@end deftypefun
+
+
+@deftypefun {char *} gdb_copy_exec_path ()
+Make a copy of the execution path.@*
+[[[implement: strsave(get_in_environ (inferior_environ, "PATH"));]]]@*
+(path_info)
+@end deftypefun
+
+
+@deftypefun void gdb_mod_exec_path (char * @var{dirnames})
+Add zero or more directories to the front of the execution path.
+@var{dirnames} should be a colon separated list of directory names.@*
+(path_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_target_device (char * @var{name})
+Connects the libgdb host environment to a target machine
+or process.@*
+(target foo)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_baud (int @var{rate})
+If using a remote target connected by a serial port,
+use RATE as the communication speed.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_target_debugging (int @var{level})
+Choose the level of verboseness of with which a remote
+target produces debugging output.
+@end deftypefun
+
+@node Symtabs, Source, Targets, top
+@comment node-name, next, previous, up
+@chapter Accessing symbol tables and debugging information.
+@cindex Symtabs
+@cindex {Symbol Tables}
+
+@deftp Type {struct symtab}
+Each source file is represented by a struct symtab.
+In many contexts, @code{struct symtab *} is used in preference
+to a {char *} filename to refer to the source.
+@end deftp
+
+
+@deftypefun {char *} gdb_symtab_to_filename (struct symtab *)
+@deftypefunx {char *} gdb_symtab_to_dirname (struct symtab *)
+Return the location of the file corresponding to this symtab.
+@code{gdb_symtab_to_dirname} might return @code{NULL} if no directory
+is known. @code{gdb_symtab_to_line_count} might return -1 if line
+number information is unavailable.
+@end deftypefun
+
+@deftypefun int gdb_symtab_to_line_count (struct symtab *)
+(See also `Source')
+@end deftypefun
+
+
+@deftypefun {struct symtab *} gdb_filename_to_symtab (char * @var{filename})
+Lookup the symbol table of a source file named NAME.@*
+(lookup_symtab)
+@end deftypefun
+
+
+@deftp Type {struct symtab_and_line}
+@example
+struct symtab_and_line
+@{
+ struct symtab *symtab;
+ int line;
+ CORE_ADDR pc;
+ CORE_ADDR end;
+@}
+@end example
+
+@code{struct symtab_and_line} is used to refer to a particular line
+of source code. It is used to locate breakpoints in the source
+code and the executable.
+
+@code{line} starts at 1 and proceeds through symtab->nlines.
+0 is never a valid line number; it is used to indicate
+that line number information is not available.
+@end deftp
+
+
+@deftypefun {struct symtab_and_line} gdb_find_pc_line (CORE_ADDR @var{pc}, int @var{notcurrent})
+Find the source file and line number for a given @var{pc} value.
+Return a structure containing a symtab pointer, a line number,
+and a pc range for the entire source line.
+The value's @code{.pc} field is NOT the specified @var{pc}.
+@var{notcurrent} nonzero means, if specified pc is on a line boundary,
+use the line that ends there. Otherwise, in that case, the line
+that begins there is used.@*
+(find_pc_line)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_find_line (struct symtab_and_line * @var{out}, struct symtab *, int)
+Create a symtab_and_line for a given symtab and line number.
+In other words, if you know the source file and line,
+this returns a location for the breakpoint.@*
+(resolve_sal_pc)
+@end deftypefun
+
+
+@deftypefun {struct symtabs_and_lines} gdb_decode_line (@var{argptr}, @var{firstln}, @var{default_symtab}, @var{default_line}, @var{canonical})
+@example
+ char ** argptr;
+ int funfirstline;
+ struct symtab * default_symtab;
+ int default_line;
+ char *** canonical;
+@end example
+ Parse a string that specifies a line number in GDB syntax.
+ @var{argptr} will be advanced over the characters actually parsed.
+
+ The string can be:
+
+ LINENUM -- that line number in current file. PC returned is 0.
+ FILE:LINENUM -- that line in that file. PC returned is 0.
+ FUNCTION -- line number of openbrace of that function.
+ PC returned is the start of the function.
+ VARIABLE -- line number of definition of that variable.
+ PC returned is 0.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in minimal symbol
+ table.
+
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside a function when a function is specified.
+
+ DEFAULT_SYMTAB specifies the file to use if none is specified.
+ It defaults to current_source_symtab.
+
+ DEFAULT_LINE specifies the line number to use for relative line
+ numbers (that start with signs). Defaults to current_source_line.
+ If CANONICAL is non-NULL, store an array of strings containing the
+ canonical line specs there if necessary. Currently overloaded
+ member functions and line numbers or static functions without a
+ filename yield a canonical line spec. The array and the line spec
+ strings are allocated on the heap, it is the callers responsibility
+ to free them.
+
+ Note that it is possible to return zero for the symtab
+ if no file is validly specified. Callers must check that.
+ Also, the line number returned may be invalid.
+
+ The return value of this function includes allocated memory
+ which the caller is responsible for freeing:
+
+ struct symtabs_and_lines sals;
+ sals = decode_line_spec (arg, 1);
+ ....
+ free (sals.sals);@*
+(decode_line_1)
+@end deftypefun
+
+
+@deftp Type {struct block *}
+Lexical environments in the program are represented by struct block.
+These are useful as arguements to expression parsing functions (see
+`Expressions').
+@end deftp
+
+
+@deftypefun {struct block *} gdb_block_for_pc (CORE_ADDR)
+Return the innermost lexical block containing the
+specified pc value, or 0 if there is none.@*
+(block_for_pc)
+@end deftypefun
+
+
+@deftypefun {struct block *} gdb_get_frame_block (FRAME @var{frame})
+This returns the block being executed by a given
+stack frame (see `Stack')@*
+(get_frame_block)
+@end deftypefun
+
+
+@deftypefun int gdb_find_line_pc_range (@var{syms}, @var{line}, @var{start_out}, @var{end_out})
+@example
+struct symtab * @var{start_out};
+int @var{line};
+CORE_ADDR * @var{start_out};
+CORE_ADDR * @var{end_out};
+@end example
+Find the range of pc values in a line.@*
+Store the starting pc of the line into @code{*@var{startptr}}.
+and the ending pc (start of next line) into @code{*@var{endptr}}.
+
+Returns 1 to indicate success.@*
+Returns 0 if could not find the specified line.@*
+(find_line_pc_range)
+@end deftypefun
+
+
+@deftypefun int gdb_find_pc_partial_function (@var{pc}, @var{name}, @var{address}, @var{endaddr})
+@example
+CORE_ADDR @var{pc};
+char **@var{name};
+CORE_ADDR *@var{address};
+CORE_ADDR *@var{endaddr};
+@end example
+Finds the "function" (text symbol) that is smaller than @var{pc} but
+greatest of all of the potential text symbols. Sets @code{*@var{name}}
+and/or @code{*@var{address}} conditionally if that pointer is non-null. If
+@var{endaddr} is non-null, then set @code{*@var{endaddr}} to be the end of
+the function (exclusive), but passing @var{endaddr} as non-null means that
+the function might cause symbols to be read. This function either succeeds
+or fails (not halfway succeeds). If it succeeds, it sets
+@code{*@var{name}}, @code{*@var{address}}, and @code{*@var{endaddr}} to
+real information and returns 1. If it fails, it sets @code{*@var{name}},
+@code{*@var{address}}, and @code{*@var{endaddr}} to zero and returns 0.
+
+@example
+ pc = get_frame_pc (selected_frame);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains program counter for selected frame.\n");
+@end example
+(find_pc_partial_function)
+@end deftypefun
+
+
+@deftypefun void gdb_list_symbols (@var{info_out}, @var{regexp}, @var{class}, @var{bpt})
+@example
+struct gdb_stream_cback * @var{info_out};
+char * @var{regexp};
+int @var{class};
+int @var{bpt};
+@end example
+List all symbols (if @var{regexp} is NULL) or all symbols matching @var{regexp}.
+
+
+If @var{class} is ...
+@itemize @bullet
+@item
+0, list all symbols except functions, type names, and
+constants (enums).
+@item
+1, list only functions.
+@item
+2, list only type names.
+@item
+3, list only method names.
+@end itemize
+BPT is non-zero if set a breakpoint at the functions we find.@*
+(variables_info, functions_info, types_info, list_symbols)
+@end deftypefun
+
+
+@deftypefun int gdb_locals_info (struct gdb_stream_cback * @var{info_out}, FRAME @var{frame})
+Print all the local variables in the given frame.
+including all the blocks active in that frame
+at its current pc.
+
+Returns 1 if the job was done,
+or 0 if nothing was printed because we have no info
+on the function running in @var{frame}.@*
+(locals_info)
+@end deftypefun
+
+
+@deftypefun int print_frame_arg_vars (struct gdb_stream_cback *, FRAME)
+Similar to `gdb_locals_info'.@*
+(args_info)
+@end deftypefun
+
+@node Source, Running, Symtabs, top
+@comment node-name, next, previous, up
+@chapter Relating Inferiors to Source Files
+@cindex source
+@cindex {source files}
+
+How to find the source that corresponds to executable code and the
+executable code that corresponds to a line of source.
+
+@deftypefun {char *} gdb_copy_source_fullname (struct symtab *@var{s})
+Return a copy of the full path name to a source file.
+(See `Symtabs' for more information about filenames
+and symbol tables.).
+@end deftypefun
+
+
+@deftypefun int gdb_open_source_file (struct symtab *@var{s})
+Open a source file corresponding to @var{s}. Returns a file descriptor
+or negative number for error.
+[[[We may decide not to provide this function.]]]@*
+(open_source_file)
+@end deftypefun
+
+
+@deftypefun int gdb_source_line_pos (struct symtab * @var{s}, int @var{lineno})
+Return the byte offset of a given line of source
+or a negative number if @var{lineno} is out of range.@*
+(find_source_lines)
+@end deftypefun
+
+
+ -- IDIOM: The gdb command `show directories'.
+@example
+ puts_filtered ("Source directories searched: ");
+ puts_filtered (source_path);
+ puts_filtered ("\n");
+@end example
+(show_directories)
+
+
+@deftypefun {char *} gdb_source_path ()
+Return the path in which source files are sought.@*
+(source_path)
+@end deftypefun
+
+
+@deftypefun void gdb_modify_source_path (char * @var{dirnames})
+Change the source path according to dirnames.@*
+(directory_command)
+@end deftypefun
+
+
+See `Symtabs' for functions relating symbol tables to files.
+(source_info)
+
+
+See `Symtabs' for functions relating source lines to PC values.
+(line_info)
+
+
+[[[Try to expose sources_info without having to introduce struct object *?]]]
+(sources_info)
+
+
+@node Running, Stopping, Source, top
+@comment node-name, next, previous, up
+@chapter Creating, Continuing, and Stepping Through an Inferior Process
+@cindex running
+
+
+@deftypefun gdb_error_t gdb_target_create_inferior (@var{exec}, @var{args}, @var{environ})
+@example
+char * @var{exec_file};
+char * @var{inferior_args};
+char ** @var{inferior_environment_vector};
+@end example
+Create a running inferior.
+[[[I think the exec_file parameter is redundant. Perhaps this will take
+only two arguments.]]]@*
+(run_command, target_create_inferior)
+@end deftypefun
+
+
+@deftypefun int gdb_target_has_execution ()
+Return non-0 if an inferior is running.@*
+(target_has_execution)
+@end deftypefun
+
+
+@deftypefun void gdb_target_kill ()
+Kill the inferior process. Make it go away.
+The inferior may become a core file.
+If so, gdb_target_has_stack() will return non-0.@*
+(target_kill)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_step_1 (@var{skip_subs}, @var{single_inst}, @var{repeat_count})
+@example
+int skip_subs;
+int single_inst;
+int repeat_count;
+@end example
+Continue a program a little bit. Roughly:
+@example
+ for (; count > 0; --count)
+ gdb_clear_proceed_status ();
+ gdb_proceed (...);
+@end example
+(next_command, nexti_command, step_command, stepi_command)
+@end deftypefun
+
+
+ -- IDIOM: Continuing a program where it stopped.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed ((CORE_ADDR) -1, -1, 0);
+@end example
+(continue_command)
+
+
+ -- IDIOM: Continuing a program giving it a specified signal.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed ((CORE_ADDR) -1, signum, 0);
+@end example
+(signal_command)
+
+
+@deftypefun {char *} strtosigno (char * @var{str})
+(Typical use:)
+@example
+ signum = strtosigno (signum_exp);
+
+ if (signum == 0)
+ /* Not found as a name, try it as an expression. */
+ signum = parse_and_eval_address (signum_exp);
+
+ gdb_clear_proceed_status ();
+ gdb_proceed ();
+@end example
+@end deftypefun
+
+
+ -- IDIOM: Continuing a program at a specified address.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed (addr, 0, 0);
+@end example
+(jump_command)
+
+
+@deftypefun gdb_error_t gdb_finish ()
+"finish": Set a temporary breakpoint at the place
+the selected frame will return to, then continue.
+This is a convenience function but it summarizes a lot
+of other stuff.@*
+(finish_command)
+@end deftypefun
+
+
+@deftypefun void gdb_clear_proceed_status ()
+Clear out all variables saying what to do when inferior is continued.
+First do this, then set the ones you want, then call @code{gdb_proceed}.
+
+ [[[Some of these should be documented, others hidden.]]]
+@example
+ The variables are:
+ trap_expected = 0;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ step_over_calls = -1;
+ stop_after_trap = 0;
+ stop_soon_quietly = 0;
+ proceed_to_finish = 0;
+ breakpoint_proceeded = 1; /* We're about to proceed... */
+
+ /* Discard any remaining commands or status from previous stop. */
+ bpstat_clear (&stop_bpstat);
+@end example
+(clear_proceed_status)
+@end deftypefun
+
+
+@deftypefun void gdb_proceed (CORE_ADDR @var{addr}, int @var{signal}, int @var{step})
+Basic routine for continuing the program in various fashions.
+
+@var{addr} is the address to resume at, or -1 for resume where stopped.@*
+@var{signal} is the signal to give it, or 0 for none,
+or -1 for act according to how it stopped.@*
+@var{step} is nonzero if should trap after one instruction.
+-1 means return after that and print nothing.@*
+You should probably set various step_... variables
+before calling here, if you are stepping.
+
+You should call @code{gdb_clear_proceed_status} before calling proceed.
+(See the documentation for @code{gdb_clear_proceed_status} for more
+parameters to @code{gdb_proceed}).@*
+(proceed)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_return (value @var{return_value}, FRAME @var{frame})
+Make @var{frame} return to @var{value} to it's caller.
+Unlike the other functions in this section, this doesn't
+call proceed.
+(return_command)
+@end deftypefun
+
+
+@deftypefun int gdb_inferior_pid ()
+0 or the valid pid of an inferior.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_attach (int @var{pid})
+takes a program started up outside of gdb and
+`attaches'' to it. This stops it cold in its tracks and allows us
+to start debugging it. and wait for the trace-trap that results
+from attaching.@*
+(attach_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_detach (int @var{signal_num})
+Takes a program previously attached to and detaches it.
+The program resumes execution and will no longer stop
+on signals, etc. We better not have left any breakpoints
+in the program or it'll die when it hits one. For this
+to work, it may be necessary for the process to have been
+previously attached. It *might* work if the program was
+started via the normal ptrace (PTRACE_TRACEME).@*
+(detach_command)
+@end deftypefun
+
+@node Stopping, Stack, Running, top
+@comment node-name, next, previous, up
+@chapter Using Breakpoints, Signaling an Inferior
+@cindex stopping
+@cindex breakpoints
+
+
+@deftp Type {struct breakpoint}
+Breakpoints are typically represented @code{struct breakpoint *}.
+@end deftp
+
+
+@deftypefun {struct breakpoint *} gdb_find_breakpoint (int)
+Find a breakpoint given it's number (return 0 if it doesn't exist).
+@end deftypefun
+
+@deftypefun gdb_error_t gdb_set_break (struct breakpoint * @var{brk_out}, struct symtab_and_line)
+@deftypefunx gdb_error_t gdb_set_tbreak (struct breakpoint *, struct symtab_and_line)
+@deftypefunx gdb_error_t gdb_set_until (struct breakpoint *, struct symtab_and_line)
+These three are like their command language counterparts.
+They are front ends to `gdb_set_raw_breakpoint'.
+See `Symtabs' for sources of `struct symtab_and_line'.@*
+(break_command, break_command_1, until_command, tbreak_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_watchpt (@var{brk_out}, @var{exp_string}, @var{exp}, @var{exp_valid_block})
+@example
+struct breakpoint * @var{brk_out};
+char * @var{exp_string};
+struct expression * @var{exp};
+struct block * @var{expression_valid_block};
+@end example
+Set a watchpoint for the given expression.@*
+(watch_command)
+@end deftypefun
+
+
+@deftypefun void gdb_set_ignore_count (int @var{bptnum}, int @var{count})
+Set ignore-count of breakpoint number BPTNUM to COUNT.@*
+(set_ignore_count)
+@end deftypefun
+
+
+@deftypefun {struct gdb_bp_condition *} gdb_set_condition (@var{bp}, @var{exp_str}, @var{cond})
+@example
+int @var{pbtnum};
+char * @var{exp_str};
+struct gdb_bp_condition * @var{cond};
+
+typedef int (*gdb_bp_fn) (struct gdb_bp_condition *, int bp_num);
+struct gdb_bp_condition
+@{
+ gdb_bp_fn fn;
+@};
+@end example
+Add a condition to a breakpoint.
+The condition is a callback which should return
+0 to skip the breakpoint, and 1 to break at it.
+It is called at times when the break might occur.
+
+A useful application of these callbacks to attach
+an expression to breakpoints like the gdb `condition'
+command. See `Expressions' for the parsing and
+evaluation of expressions.@*
+(condition_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_enable_breakpoint (struct breakpoint * @var{bpt}, int @var{once})
+@deftypefunx gdb_error_t gdb_disable_breakpoint (struct breakpoint * @var{bpt})
+Enable/disable a breakpoint. If `once' is not 0, the
+breakpoint is only temporarily enabled.@*
+(enable_breakpoint, disable_breakpoint, enable_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_delete_breakpoint (struct breakpoint * @var{bpt})
+Delete a breakpoint and clean up all traces of it in the
+data structures.@*
+(delete_breakpoint)
+@end deftypefun
+
+
+@deftypefun void gdb_clear_breakpoints (struct symtabs_and_lines * @var{sals})
+Clear breakpoints from a list of program locations as
+might be returned by `gdb_decode_line' (see `Symtabs').@*
+(clear_command)
+@end deftypefun
+
+
+@deftypefun {static struct symtabs_and_lines} get_catch_sals (int @var{this_level_only})
+Return the line numbers of all exception handlers currently
+active (or `this_level_only'?? [[[?]]]).
+[[[The implementation should remember to resolve_sal_pc]]]
+@end deftypefun
+
+
+@deftp Type {struct breakpoint_cback}
+@example
+typedef void (*breakpoint_cback_fn) (struct breakpoint_cback *, int bp_num);
+struct breakpoint_cback
+@{
+ breakpoint_cback_fn fn;
+@};
+@end example
+
+Breakpoints can have an associated function which is called
+when the program is stopped by that breakpoint.@*
+(commands_command)
+@end deftp
+
+
+@deftypefun {struct breakpoint_cback *} gdb_set_breakpoint_cback (int @var{bp_num}, struct breakpoint_cback *)
+This sets a breakpoint callback and returns the previous callback value
+for that breakpoint.
+[[[In the long run, the command interpreter should be available
+ for the use of hooks like this one.]]]
+@end deftypefun
+
+
+@deftypefun {struct breakpoint_cback *} gdb_get_breakpoint_cback (int @var{bp_num})
+@end deftypefun
+
+
+@deftypefun void gdb_breakpoints_info (struct gdb_stream_cback, int @var{bp_num}, int @var{watches})
+Print information on breakpoint number @var{bnum}, or -1 if all.
+If @var{watches} is zero, process only breakpoints; if @var{watches}
+is nonzero, process only watchpoints.
+[[[In the long run, expose the information read off by this function.]]]@*
+(info breakpoints, info watchpoints, breakpoints_info, breakpoint_1)
+@end deftypefun
+
+
+@deftypefun void gdb_catch_info (struct gdb_stream_cback *)
+Print a list of all the exception handlers that are active in the
+current stack frame at the current point of execution.@*
+(catch_info)
+@end deftypefun
+
+
+@deftypefun void gdb_handle_command (char * @var{args})
+Takes arguments like the gdb command `handle' and has
+the same effect.@*
+(handle_command)
+@end deftypefun
+
+
+@deftypefun void gdb_signals_info (struct gdb_stream_cback *)
+Show how signals are handled.@*
+(signals_info)
+@end deftypefun
+
+
+@node Stack, Expressions, Stopping, top
+@comment node-name, next, previous, up
+@chapter Accessing An Inferior's Execution Stack
+@cindex stack
+@cindex FRAME
+@cindex {stack frames}
+
+
+
+@deftp Type FRAME
+This type representing active stack frames in the inferior.
+Consider this type opaque.
+@end deftp
+
+
+@deftypefun FRAME gdb_get_innermost_frame ()
+Returns the innermost frame or the frame most recently designated
+as current by a call to gdb_set_current_frame.@*
+(get_current_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_get_caller_frame (FRAME @var{frame})
+Return the frame that called @var{frame}.@*
+If @var{frame} is the original frame (it has no caller), return 0.@*
+(get_prev_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_get_called_frame (FRAME @var{frame})
+Return the frame that @var{frame} calls (0 if @var{frame} is the innermost
+frame).@*
+(get_next_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_parse_frame_specification (char * @var{frame_exp})
+Read a frame specification in whatever the appropriate format is.
+Call @code{error}() If the specification is in any way invalid (i.e.
+this function never returns NULL).@*
+(parse_frame_specification)
+@end deftypefun
+
+
+@deftypefun CORE_ADDR get_frame_pc (FRAME @var{frame})@*
+(Example use: Implementing @code{disassemble_command})@*
+(get_frame_pc)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_selected_frame ()
+The "selected" stack frame is used by default for local and
+arg access. May be @code{NULL}, for no selected frame.@*
+(variable selected_frame)
+@end deftypefun
+
+
+@deftypefun int gdb_selected_frame_level ()
+Level of the selected frame:@*
+0 for innermost,@*
+1 for its caller,@*
+or -1 for frame specified by address with no defined level.@*
+(variable selected_frame_level)
+@end deftypefun
+
+
+@deftypefun void gdb_select_frame (FRAME @var{frame}, int @var{level})
+Select frame @var{frame}, and note that its stack level is @var{level}.
+@var{level} may be -1 if an actual level number is not known.
+Calls @code{set_language} to establish the correct language for the
+selected frame.
+@end deftypefun
+
+
+ -- IDIOM: Computing Frame Levels@*
+@example
+/* Try to figure out what level this frame is as before a
+ call to gdb_select_frame. But if there is
+ no current stack, don't error out, just pass -1
+ instead. */
+frame1 = 0;
+level = -1;
+if (get_current_frame()) @{
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+@}
+@end example
+
+
+@deftypefun void gdb_print_stack_frame (@var{cback}, @var{frame}, @var{level}, @var{source})
+@example
+struct gdb_stream_cback * @var{cback};
+FRAME @var{frame};
+int @var{level};
+int @var{source};
+@end example
+Print a stack frame briefly. @var{frame} should be the frame id
+and @var{level} should be its level in the stack (or -1 for level not defined).
+This prints the level, the function executing, the arguments,
+and the file name and line number.@*
+If the pc is not at the beginning of the source line,
+the actual pc is printed at the beginning.@*
+If @var{source} is 1, print the source line as well.@*
+If @var{source} is -1, print ONLY the source line.@*
+(print_stack_frame)
+@end deftypefun
+
+
+@deftypefun void gdb_print_backtrace (cback, @var{count}, @var{from_tty})
+@example
+struct gdb_stream_cback * @var{cback};
+int @var{count};
+int @var{from_tty};
+@end example
+Print briefly all stack frames or just the innermost @var{count} frames.@*
+(backtrace_command)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_find_relative_frame (FRAME @var{frame}, int * @var{level_offset_ptr})
+Find a frame a certain number of levels away from @var{frame}.
+@var{level_offset_ptr} points to an int containing the number of levels.
+Positive means go to earlier frames (up); negative, the reverse.
+The int that contains the number of levels is counted toward
+zero as the frames for those levels are found.
+If the top or bottom frame is reached, that frame is returned,
+but the final value of @var{*level_offset_ptr} is nonzero and indicates
+how much farther the original request asked to go.
+@end deftypefun
+
+
+@deftypefun FRAME gdb_select_frame_downward (int @var{count})
+@deftypefunx FRAME gdb_select_frame_upward (int @var{count})
+Simply a combination of find_relative_frame and select_frame.
+Returns the newly selected frame.@*
+(down_silently_command, up_silently_command)
+@end deftypefun
+
+
+@deftypefun void gdb_frame_info (struct gdb_stream_cback * @var{cback}, FRAME @var{frame})
+Print verbosely the selected the argument @var{frame}.
+This means absolutely all information in the frame is printed.@*
+(frame_info)
+@end deftypefun
+
+
+@node Expressions, Values, Stack, top
+@comment node-name, next, previous, up
+@chapter How to Parse and Evaluate Expressions
+@cindex parsing
+@cindex expressions
+@cindex {expression evaluation}
+@cindex evaluation
+
+
+@deftp Type {struct expression *}
+This represents a parsed expression as might be used for a
+breakpoint condition.
+@end deftp
+
+
+@deftp Type {struct block}
+Describes a lexical environment.
+@end deftp
+
+See also `Values'
+See also `Examining'
+
+
+@deftypefun struct expression * parse_exp_1 (char ** @var{stringptr}, struct block * @var{block} int @var{comma})
+Read an expression from the string @code{*@var{stringptr}} points to,
+parse it, and return a pointer to a struct expression that we malloc.
+Use @var{block} as the lexical context for variable names;
+if @var{block} is zero, use the block of the selected stack frame.
+Meanwhile, advance @code{*@var{stringptr}} to point after the expression,
+at the first nonwhite character that is not part of the expression
+(possibly a null character).
+
+If @var{comma} is nonzero, stop if a comma is reached.
+(See `Stack' for information about the selected frame)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_evaluate_expression (value * @var{value_out}, struct expression * @var{exp})
+Evaluate an expression. See `values' for more information about
+the return type.@*
+(evaluate_expression)
+@end deftypefun
+
+
+@deftypefun value gdb_evaluate_type (struct expression @var{*exp})
+Evaluate an expression, avoiding all memory references
+and getting a value whose type alone is correct.@*
+(evaluate_type)
+@end deftypefun
+
+
+
+@node Values, Examining, Expressions, top
+@comment node-name, next, previous, up
+@chapter Data from the Inferior, the Values of Expressions
+@cindex values
+@cindex {expression values}
+
+Values are allocated by functions such as @code{gdb_evaluate_expression}.
+All currently allocated values are on the list @code{all_values} and can be
+freed by calling @code{gdb_free_all_values}.
+
+To preserve a value across calls to @code{gdb_free_all_values}, use
+@code{gdb_release_value}. Values added to the history list are automaticly
+released. To free a released value use @code{gdb_free_value}.
+
+
+@deftypefun void gdb_free_value (value)
+Free the memory associated with a released value.
+Do not call this function except on values that have been
+passed to @code{gdb_release_value}.@*
+(gdb_value_free)
+@end deftypefun
+
+
+@deftypefun void gdb_free_all_values (void)
+Free all allocated values which haven't been released.
+This should be called periodically from outside the dynamic
+scope of libgdb functions.@*
+(free_all_values)
+@end deftypefun
+
+
+@deftypefun void gdb_release_value (value @var{val})
+Remove a value from the list @code{all_values} in order to
+protect it from @code{gdb_free_all_values}.@*
+(release_value)
+@end deftypefun
+
+
+There is a `history list' -- a numbered list of values for
+future reference. These can be referred to in expressions,
+for example.
+
+@deftypefun int gdb_record_latest_value (value @var{val})
+Add a value to the history list.@*
+(record_latest_value)
+@end deftypefun
+
+
+@deftypefun value gdb_access_value_history (int @var{index})
+Retrieve a value from the history list.@*
+(access_value_history)
+@end deftypefun
+
+
+[[[At the moment, the only libgdb use for values is
+ string formatting (see `Examining'). So, they are treated
+ as opaque. It'd be useful to expose more of them in the long run.]]]
+
+
+@node Examining, Types, Values, top
+@comment node-name, next, previous, up
+@chapter Formatting Values as Strings
+@cindex examining
+@cindex printing
+@cindex formatting
+@cindex {pretty printing}
+
+
+Many functions in this section use @code{struct gdb_stream_cback}.
+That structure is explained in `Basics'.
+
+
+@deftypefun void gdb_print_formatted (struct gdb_stream_cback * @var{cback}, value @var{val}, int @var{format}, int @var{size})
+Print value @var{val} on a stream according to @var{format}, a letter or 0.
+Do not end with a newline.
+0 means print @var{val} according to its own type.
+@var{size} is the letter for the size of datum being printed.
+This is used to pad hex numbers so they line up.@*
+(print_formatted)
+@end deftypefun
+
+
+@deftypefun static void gdb_printf_command (struct gdb_stream_cback * @var{cback}, char * @var{format}, value * @var{values}, int @var{n_values})@*
+(printf_command)
+@end deftypefun
+
+
+@deftypefun int gdb_value_print (struct gdb_stream_cback * @var{cback}, @var{value}, int @var{format}, enum @var{val_prettyprint})
+Print the value @var{val} in C-ish syntax on @var{stream}.
+@var{format} is a format-letter, or 0 for print in natural format of data type.
+If the object printed is a string pointer, returns
+the number of string bytes printed.
+[[[implementation: watch the change in argument order]]]@*
+(value_print)
+@end deftypefun
+
+
+ -- IDIOM: This prints the values of all convenience variables:
+@example
+for (var = internalvars; var; var = var->next)
+@{
+printf_filtered ("$%s = ", var->name);
+value_print (var->value, stdout, 0, Val_pretty_default);
+printf_filtered ("\n");
+@}
+@end example
+
+
+@deftypefun int gdb_print_insn (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{memaddr})
+Print the instruction at @var{memaddr} and return the
+length of the instruction in bytes.@*
+(print_insn)
+@end deftypefun
+
+
+@deftypefun void gdb_print_address (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{addr})
+Print address @var{addr} symbolically on @var{stream}.
+First print it as a number. Then perhaps print
+@code{<SYMBOL + OFFSET>} after the number.@*
+(print_address)
+@end deftypefun
+
+
+ -- IDIOM: This is the core of a dissasemble command:
+@example
+for (pc = low; pc < high; )
+@{
+ print_address (pc, stdout);
+ printf_filtered (":\t");
+ pc += print_insn (pc, stdout);
+ printf_filtered ("\n");
+@}
+@end example
+Advice for computing pc extents like @code{low} and @code{high}
+can be found in `Symtabs' -- for example, @code{gdb_find_line_pc_range}.@*
+(disassemble_command)
+
+
+@deftypefun void gdb_print_registers (struct gdb_stream_cback * @var{cback}, int @var{regnum}, int @var{fpregs}, int @var{fancy})
+Print the values of registers.
+@var{regnum} can be -1 (print all the registers) or a specific register number.
+If @var{regnum} is -1, @var{fpregs} determines whether floating point registers are
+shown.@*
+(info registers, info all-registers, nofp_registers_info, all_registers_info)
+@end deftypefun
+
+
+@deftypefun char * gdb_register_name (int @var{i})
+Look up a register name by number.
+@end deftypefun
+
+
+@deftypefun int gdb_parse_register_name (char ** @var{name})
+Parse a register name and advance a text pointer.
+Return -1 for bogus names.
+@end deftypefun
+
+
+@deftypefun CORE_ADDR gdb_read_pc ()
+Return the contents of the inferior's program counter.
+@end deftypefun
+
+
+@deftypefun int gdb_is_stepping ()
+If true, the inferior is stopped after being stepped.
+@end deftypefun
+
+
+@deftypefun void gdb_current_breakpoints (gdb_int_cback)
+Call a callback for each of the current breakpoints.@*
+(program_info)
+@end deftypefun
+
+
+@deftypefun int gdb_stop_signal ()
+Return the signal that stopped the inferior.
+@end deftypefun
+
+
+@deftypefun char * strsigno (int)
+Return a symbolic name for a signal.
+@end deftypefun
+
+
+@deftypefun void gdb_target_info (struct gdb_stream_cback *)
+Print status information about target we're accessing.@*
+(target_files_info, e.g. child_files_info)
+@end deftypefun
+
+
+float_info
+[[[what is appropriate?]]]
+
+
+@deftypefun void gdb_address_info (struct gdb_stream_cback * @var{cback}, char * @var{symbol});
+Like the `info address' command -- show where @var{symbol}
+is located.@*
+(address_info)
+@end deftypefun
+
+
+@node Types, top, Examining, top
+@comment node-name, next, previous, up
+@chapter Examining the Types of an Inferior's Data
+@cindex types
+
+
+@deftp Type {struct type}
+@code{struct type *} is used to represent a type. For example, that is
+the type returned by the macro @code{VALUE_TYPE(val)} which yields the
+type of inferior data recorded in @code{val}. (see `evaluate_type' in
+`Expressions').
+@end deftp
+
+
+@deftypefun void type_print (@var{type}, @var{varstring}, @var{stream_cback}, @var{show})
+@example
+struct type @var{*type};
+char @var{*varstring};
+struct gdb_stream_cback * @var{stream_cback};
+FILE @var{*stream};
+int @var{show};
+@end example
+Print a description of a type @var{type} in the form of a declaration of a
+variable named @var{varstring}. (@var{varstring} is demangled if necessary.)
+Output goes to @var{stream_cback}.
+
+If @var{show} is positive, we show the contents of the outermost level
+of structure even if there is a type name that could be used instead.
+If @var{show} is negative, we never show the details of elements' types.
+(See `Basics' for an explanation of `struct gdb_stream_cback').
+@end deftypefun
+
+
+[[[In the long run, we need something to programmaticly read off type
+ structures in a machine/language independent way.]]]
+
+@bye
diff --git a/gnu/usr.bin/gdb/doc/lpsrc.sed b/gnu/usr.bin/gdb/doc/lpsrc.sed
new file mode 100644
index 000000000000..1c7af4aaf48f
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/lpsrc.sed
@@ -0,0 +1,13 @@
+/font defs: ---/,/end font defs ---/c\
+%-------------------- PostScript (long names) font defs: -----------------\
+\\font\\bbf=Times-Bold at 10pt\
+\\font\\vbbf=Times-Bold at 12pt\
+\\font\\smrm=Times-Roman at 6pt\
+\\font\\brm=Times-Roman at 10pt\
+\\font\\rm=Times-Roman at 8pt\
+\\font\\it=Times-Italic at 8pt\
+\\font\\tt=Courier at 8pt\
+% Used only for \copyright, replacing plain TeX macro.\
+\\font\\sym=Symbol at 7pt\
+\\def\\copyright{{\\sym\\char'323}}\
+%-------------------- end font defs ---------------------------------
diff --git a/gnu/usr.bin/gdb/doc/psrc.sed b/gnu/usr.bin/gdb/doc/psrc.sed
new file mode 100644
index 000000000000..9bb557eae21e
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/psrc.sed
@@ -0,0 +1,13 @@
+/font defs: ---/,/end font defs ---/c\
+%-------------------- PostScript (K Berry names) font defs: --------------\
+\\font\\bbf=ptmb at 10pt\
+\\font\\vbbf=ptmb at 12pt\
+\\font\\smrm=ptmr at 6pt\
+\\font\\brm=ptmr at 10pt\
+\\font\\rm=ptmr at 8pt\
+\\font\\it=ptmri at 8pt\
+\\font\\tt=pcrr at 8pt\
+% Used only for \copyright, replacing plain TeX macro.\
+\\font\\sym=psyr at 7pt\
+\\def\\copyright{{\\sym\\char'323}}\
+%-------------------- end font defs ---------------------------------
diff --git a/gnu/usr.bin/gdb/doc/refcard.ps b/gnu/usr.bin/gdb/doc/refcard.ps
new file mode 100644
index 000000000000..0046b795faf3
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/refcard.ps
@@ -0,0 +1,798 @@
+%!PS-Adobe-2.0
+%%Creator: dvips 5.47 Copyright 1986-91 Radical Eye Software
+%%Title: refcard.dvi
+%%Pages: 2 1
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%%BeginProcSet: tex.pro
+/TeXDict 200 dict def TeXDict begin /N /def load def /B{bind def}N /S /exch
+load def /X{S N}B /TR /translate load N /isls false N /vsize 10 N /@rigin{
+isls{[0 1 -1 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale
+Resolution VResolution vsize neg mul TR matrix currentmatrix dup dup 4 get
+round 4 exch put dup dup 5 get round 5 exch put setmatrix}N /@letter{/vsize 10
+N}B /@landscape{/isls true N /vsize -1 N}B /@a4{/vsize 10.6929133858 N}B /@a3{
+/vsize 15.5531 N}B /@ledger{/vsize 16 N}B /@legal{/vsize 13 N}B /@manualfeed{
+statusdict /manualfeed true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N
+/FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin
+/FontType 3 N /FontMatrix fntrx N /FontBBox FBB N string /base X array
+/BitMaps X /BuildChar{CharBuilder}N /Encoding IE N end dup{/foo setfont}2
+array copy cvx N load 0 nn put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail}
+B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont
+setfont}B /ch-width{ch-data dup length 5 sub get}B /ch-height{ch-data dup
+length 4 sub get}B /ch-xoff{128 ch-data dup length 3 sub get sub}B /ch-yoff{
+ch-data dup length 2 sub get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B
+/ch-image{ch-data dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0
+N /rw 0 N /rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S
+dup /base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0
+ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff setcachedevice
+ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image}
+imagemask restore}B /D{/cc X dup type /stringtype ne{]}if nn /base get cc ctr
+put nn /BitMaps get S ctr S sf 1 ne{dup dup length 1 sub dup 2 index S get sf
+div put}if put /ctr ctr 1 add N}B /I{cc 1 add D}B /bop{userdict /bop-hook
+known{bop-hook}if /SI save N @rigin 0 0 moveto}N /eop{clear SI restore
+showpage userdict /eop-hook known{eop-hook}if}N /@start{userdict /start-hook
+known{start-hook}if /VResolution X /Resolution X 1000 div /DVImag X /IE 256
+array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for}N /p /show load N
+/RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X
+/rulex X V}B /V statusdict begin /product where{pop product dup length 7 ge{0
+7 getinterval(Display)eq}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1
+TR 1 1 scale rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1
+-.1 TR rulex ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /a{
+moveto}B /delta 0 N /tail{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{
+S p tail}B /c{-4 M}B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B
+/j{3 M}B /k{4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w
+}B /q{p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p
+a}B /bos{/SS save N}B /eos{clear SS restore}B end
+%%EndProcSet
+TeXDict begin 1000 300 300 @start /Fa 3 104 df<0003FE0000000FFF8000003C01E000
+00F000780001C0001C00030000060006000003000C0000018018000000C018000000C030000000
+603000000060600000003060000000306000000030C000000018C000000018C000000018C00000
+0018C000000018C000000018C000000018C000000018C000000018600000003060000000306000
+0000303000000060300000006018000000C018000000C00C000001800600000300030000060001
+C0001C0000F0007800003C01E000000FFF80000003FE000025277E9D2A>13
+D<003C00E001C00180038003800380038003800380038003800380038003800380038003000700
+1C00F0001C00070003000380038003800380038003800380038003800380038003800380018001
+C000E0003C0E297D9E15>102 D<F0001C00070003000380038003800380038003800380038003
+800380038003800380018001C000E0003C00E001C0018003800380038003800380038003800380
+03800380038003800380030007001C00F0000E297D9E15>I E /Fb 1 59
+df<60F0F06004047C830C>58 D E /Fc 61 125 df<01F8000604000C0E00180E001800001800
+00180000FFFE001806001806001806001806001806001806001806001806001806001806001806
+007E1F801114809313>12 D<01FE00060E000C0E00180600180600180600180600FFFE00180600
+1806001806001806001806001806001806001806001806001806001806007E1F801114809313>
+I<4100E380618020802080208041004100820009097F9311>34 D<020002000F8032406220C210
+C270C270E220F2007F003FC00FE002E002704230E230C2308220426022C01F00020002000C187E
+9511>36 D<40E06020202040408003097D9309>39 D<01020408103020606040C0C0C0C0C0C0C0
+C0C0C040606020301008040201081E7E950D>I<80402010080C04060602030303030303030303
+03020606040C0810204080081E7E950D>I<006000006000006000006000006000006000006000
+006000006000006000FFFFF0FFFFF0006000006000006000006000006000006000006000006000
+00600000600014167E9119>43 D<40E06020202040408003097D8209>I<FFFF080280860B>I<40
+E04003037D8209>I<0010003000600060006000C000C000C00180018003000300030006000600
+06000C000C000C0018001800300030003000600060006000C000C0000C1D7E9511>I<0F0030C0
+606060604020C030C030C030C030C030C030C030C030C03040206060606030C00F000C137E9211
+>I<0C001C00EC000C000C000C000C000C000C000C000C000C000C000C000C000C000C000C00FF
+C00A137D9211>I<1F0060C06060F070F030603000700070006000C001C0018002000400081010
+1020207FE0FFE00C137E9211>I<40E0400000000000000040E040030D7D8C09>58
+D<40E0400000000000000040E06020202040408003137D8C09>I<003000003000007800007800
+007800009C00009C00011E00010E00010E0002070002070004038007FF800403800801C00801C0
+1000E03800E0FE07FC16147F9319>65 D<FFFC001C07001C03801C01C01C01C01C01C01C01C01C
+03801C07001FFE001C03801C01C01C00E01C00E01C00E01C00E01C00E01C01C01C0380FFFE0013
+147F9317>I<00FC200703600C00E0180060300060700020600020E00000E00000E00000E00000
+E00000E000006000207000203000201800400C008007030000FC0013147E9318>I<FFFC001C07
+001C01C01C00E01C00601C00701C00301C00381C00381C00381C00381C00381C00381C00301C00
+701C00601C00E01C01C01C0380FFFC0015147F9319>I<FFFF801C03801C00801C00801C00401C
+00401C08401C08001C18001FF8001C18001C08001C08201C00201C00201C00601C00401C00C01C
+01C0FFFFC013147F9316>I<00FC200703600C00E0180060300060700020600020E00000E00000
+E00000E00000E00FF8E000E06000E07000E03000E01800E00C00E007036000FC2015147E931A>
+71 D<FFC0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0000
+1C00401C00401C00401C00C01C00801C01801C0380FFFF8012147F9315>76
+D<FE000FE01E000F00170017001700170017001700138027001380270011C0470011C0470010E0
+870010E0870010E087001071070010710700103A0700103A0700101C0700101C0700381C0700FE
+083FE01B147F931E>I<FC01FC1E007017002017802013802011C02010E0201070201070201038
+20101C20100E20100F201007201003A01001E01000E01000E0380060FE002016147F9319>I<01
+F800070E001C03803801C03000C07000E0600060E00070E00070E00070E00070E00070E0007070
+00E07000E03000C03801C01C0380070E0001F80014147E9319>I<FFFC001C07001C03801C01C0
+1C01C01C01C01C01C01C01C01C03801C07001FFC001C00001C00001C00001C00001C00001C0000
+1C00001C0000FF800012147F9316>I<FFF8001C07001C03801C01C01C01C01C01C01C01C01C03
+801C07001FF8001C0E001C07001C03801C03801C03801C03801C03841C03841C01CCFF80F81614
+7F9318>82 D<7FFFF0607030407010407010807008807008807008007000007000007000007000
+00700000700000700000700000700000700000700000700007FF0015147F9318>84
+D<FF81FC1C00701C00201C00201C00201C00201C00201C00201C00201C00201C00201C00201C00
+201C00201C00200C00200E004006008003830000FC0016147F9319>I<FF1FF0FC380380303803
+80301C03C0201C03C0201E03C0600E04E0400E04E0400704E08007087080070870800388710003
+9039000390390001F03E0001E01E0001E01E0000C00C0000C00C0000C00C001E147F9321>87
+D<FF00FC3C00301E00200E004007004007808003C10001C10001E20000F6000074000038000038
+0000380000380000380000380000380000380001FF0016147F9319>89 D<208041004100820082
+008200C300E380410009097A9311>92 D<7F00E1C0E0404060006007E038606060C060C064C064
+61E43E380E0D7E8C11>97 D<F00030003000300030003000300033E034103808300C3006300630
+0630063006300C3808343023E00F147F9312>I<0FE0187020706020C000C000C000C000C00060
+00201018200FC00C0D7F8C0F>I<00780018001800180018001800180F98187820386018C018C0
+18C018C018C0186018203810580F9E0F147F9312>I<0F80104020206030C010FFF0C000C000C0
+006000201018200FC00C0D7F8C0F>I<03C00CE018E01840180018001800FF0018001800180018
+0018001800180018001800180018007F000B1480930A>I<0F3C30E62040606060606060204030
+C02F00600060003FE03FF06018C00CC00CC00C601830300FC00F147F8C11>I<F0003000300030
+0030003000300033E034303818301830183018301830183018301830183018FC7E0F147F9312>
+I<2070200000000000F03030303030303030303030FC06157F9409>I<02070200000000000F03
+0303030303030303030303030343E2E67C081B82940A>I<F00030003000300030003000300030
+F8306030403080330037003B80318030C0306030703030FC7C0E147F9311>I<F0303030303030
+303030303030303030303030FC06147F9309>I<F3E1F0343218381C0C30180C30180C30180C30
+180C30180C30180C30180C30180C30180CFC7E3F180D7F8C1B>I<F3E034303818301830183018
+301830183018301830183018FC7E0F0D7F8C12>I<0FC0186020106018C00CC00CC00CC00CC00C
+6018601838700FC00E0D7F8C11>I<F3E034303808300C30063006300630063006300C38083430
+33E030003000300030003000FC000F137F8C12>I<0F88184820386018C018C018C018C018C018
+6018203818580F9800180018001800180018007E0F137F8C11>I<F3C034E038E0304030003000
+300030003000300030003000FE000B0D7F8C0D>I<3E806180C080C080E0007E003F8003C080C0
+80C0C0C0E1809F000A0D7F8C0D>I<10001000100030007000FF80300030003000300030003000
+300030803080308011000E0009127F910D>I<F078301830183018301830183018301830183018
+303818580F9E0F0D7F8C12>I<F87C301830101820182018200C400C4006800680078003000300
+0E0D7F8C11>I<F87CF8707030305820305820188840188C40188C400D04800D06800D06800603
+00060300060300150D7F8C18>I<F87C303018600C400C800700030007800CC008E010603030F8
+7C0E0D7F8C11>I<F87C301830101820182018200C400C400680068007800300030002000200E6
+00E400E80070000E137F8C11>I<FFF0C06080C081C08180030006000C101810383030206060FF
+E00C0D7F8C0F>I<FFFFFFFF2001808821>124 D E /Fd 2 94 df<FEFEC0C0C0C0C0C0C0C0C0C0
+C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0FEFE07297C9E0C>91
+D<FEFE060606060606060606060606060606060606060606060606060606060606060606060606
+06FEFE0729809E0C>93 D E /Fe 27 123 df<001F8F000020D9800060990000C0300000C03000
+00C0300000C0300007FFFE000180300001806000018060000180600001806000030060000300C0
+000300C0000300C0000300C0000600C00006018000060180000601800004010000CCC30000C8C6
+000070780000191A819315>11 D<000FF000301800601000600000C00000C00000C00007FFE000
+C0600180600180C00180C00180C00180C00181800301900301900301900301A00300E006000006
+0000060000C40000C80000700000151A819314>I<FEFC07027D860C>45
+D<000080000180000300000300000600000600000C000018000018000030000030000060000060
+0000C0000180000180000300000300000600000C00000C00001800001800003000003000006000
+00C00000C00000800000111D7E9512>47 D<07C03F8000C00C0001600800016008000120080001
+300800023010000218100002181000020C1000040C200004042000040620000402200008034000
+080340000801C0000801C00018008000FE00800019147E9319>78 D<07B00C7010703060606060
+606060C0C0C0C8C0C841C862D03C700D0D7C8C12>97 D<7C000C00180018001800180030003700
+388030C060C060C060C060C0C180C180C1004300660038000A147C9310>I<07800C4010603040
+600060006000C000C0004020404021801E000B0D7C8C10>I<007C000C00180018001800180030
+07B00C7010703060606060606060C0C0C0C8C0C841C862D03C700E147C9312>I<07800C401020
+304060407F8060004000C0004020604021801E000B0D7C8C10>I<001C00660064006000C000C0
+00C007F800C001800180018001800180030003000300030003000200060006000600C400C80070
+000F1A81930B>I<01D8023804380C3018301830183030603060306010E019C00EC000C000C001
+80C180C3007C000D137E8C10>I<3E0006000C000C000C000C00180019E01E3018303830303030
+3030306060606460C460C4C0C8C0700E147D9312>I<02060000000000384C4C8C981818303262
+62643807147D930B>I<7C0C181818183030303060606060C0D0D0D0D06006147C9309>108
+D<30F878590D8C4E0E0C9C0E0C980C0C180C0C180C0C3018183018193018313018316030326030
+1C180D7D8C1C>I<30F05B184C189C189818181818183030303230623062606460380F0D7D8C13>
+I<03800C6018203030603060306030C060C06040C0608023001E000C0D7C8C12>I<0C78168C13
+0426062606060606060C0C0C0C0C080C101A2019C018001800300030003000FC000F137F8C12>
+I<31F05A184C109C009800180018003000300030003000600060000D0D7D8C0F>114
+D<0700188018C0308038001E001F0003800180C180810082007C000A0D7D8C0E>I<04000C000C
+000C001800FF8018001800300030003000300060006100610062006400380009127D910C>I<38
+184C184C188C3098301830183030603064306430E411E80E380E0D7D8C12>I<38104C384C108C
+10981018101810302030203040304018800F000D0D7D8C10>I<071E09E311C221802180018001
+800300030403044308C51078E0100D7F8C10>120 D<38184C184C188C30983018301830306030
+60306030E011C00EC000C000802180630046003C000D137D8C11>I<06100F2010E00040008001
+0002000C00102020203840478083000C0D7E8C0E>I E /Ff 55 123 df<0100030003000F803F
+E073704338C338C338C31073007F003FC00FE003F003384318E318E318E33073603FC00F800300
+030001000D1A7E9612>36 D<07001F8019C039C039C039C039BE3B3E3E701C701C701CE03EE06F
+E0E7C0E3C4E38E63CE7EFC3C380F147F9312>38 D<070007000700E738FFF87FF01FC01FC07FF0
+FFF8E7380700070007000D0E7E9012>42 D<038003800380038003800380FFFEFFFEFFFE038003
+8003800380038003800F0F7F9112>I<60F0F878183030E0C00509798312>I<FFF8FFF8FFF80D03
+7E8B12>I<60F0F0600404798312>I<0018003800380070007000E000E001C001C001C003800380
+070007000E000E001C001C001C003800380070007000E000E000C0000D1A7E9612>I<07C00FE0
+1C703838701C701CE00EE00EE00EE00EE00EE00EE00EE01E701C701C38381C700FE007C00F147F
+9312>I<0F803FC070E0E070E038E038403800380030007000E000C00180030006000C00183830
+387FF87FF80D147E9312>50 D<0FE03FF07838701C201C001C0038007807E007F00038001C000E
+000E400EE00EE01C78383FF00FC00F147F9312>I<E000FFFEFFFEE018E038007000E000C001C0
+0380038007000700070007000E000E000E000E000E0004000F157F9412>55
+D<60F0F06000000000000060F0F060040E798D12>58 D<0038007801F003E00F801F003C00F800
+F000F8003C001F000F8003E001F0007800380D117E9212>60 D<FFFEFFFE7FFE0000000000007F
+FEFFFEFFFE0F097F8E12>I<4000E000F0007C003E000F8007C001E000F8007800F801E007C00F
+803E007C00F000E00040000D137E9312>I<03E007F01E18381C30FC71FE739EE30EE70EE70EE7
+0EE70EE30C739C71F830F038001E0E07FE03F80F147F9312>64 D<03E60FFE1C3E381E700E700E
+600EE000E000E000E000E000E000600E700E700E381C1C380FF003E00F147F9312>67
+D<FFFEFFFE380E380E380E3800380038E038E03FE03FE038E038E03800380E380E380E380EFFFE
+FFFE0F147F9312>69 D<FFFEFFFE380E380E380E3800380038E038E03FE03FE038E038E0380038
+00380038003800FF00FF000F147F9312>I<FFE0FFE00E000E000E000E000E000E000E000E000E
+000E000E000E000E000E000E000E00FFE0FFE00B147D9312>73 D<FC7EFC7E7C7C745C76DC76DC
+76DC76DC76DC76DC77DC739C739C701C701C701C701C701CF83EF83E0F147F9312>77
+D<FEFEFEFE3E383A383B383B383B383B383B383B3839B839B839B839B839B839B838B838F8FEF8
+FEF80F147F9312>I<3FE07FF07070E038E038E038E038E038E038E038E038E038E038E038E038
+E038E03870707FF03FE00D147E9312>I<FFE0FFF8383C381C380E380E380E380E381C383C3FF8
+3FE0380038003800380038003800FE00FE000F147F9312>I<FF80FFE038F03878383838383838
+387838F03FE03FC038E0387038703870387038773877FE3EFE1C10147F9312>82
+D<1F303FF070F0E070E070E070E00070007F003FC00FE000F0003800386038E038E030F070FFE0
+CF800D147E9312>I<7FFEFFFEE38EE38EE38E0380038003800380038003800380038003800380
+0380038003801FF01FF00F147F9312>I<FE3F80FE3F80380E00380E00380E00380E00380E0038
+0E00380E00380E00380E00380E00380E00380E00380E00380E001C1C000E380007F00003E00011
+14809312>I<3F807FC070E0207000700FF03FF07870E070E070E07070F03FFE1F3E0F0E7E8D12>
+97 D<F800F80038003800380038003BE03FF03C38381C380C380E380E380E380E380C381C3C38
+3FF01BC00F147F9312>I<07F01FF8383870106000E000E000E000E0006000703838381FF007E0
+0D0E7E8D12>I<00F800F8003800380038003807B81FF8387870386038E038E038E038E0386038
+707838781FFE0FBE0F147F9312>I<07801FE0387070706038E038FFF8FFF8E000600070383838
+1FF007C00D0E7E8D12>I<007E00FF01C70382038003807FFEFFFE038003800380038003800380
+03800380038003803FF83FF81014809312>I<0F9E1FFF38E7707070707070707038E03FC03F80
+70003FE03FF83FFC701EE00EE00EE00E600C783C1FF00FE010167F8D12>I<F800F80038003800
+3800380039E03FF03E383C3838383838383838383838383838383838FE3EFE3E0F147F9312>I<
+06000F000F000600000000000000FF00FF000700070007000700070007000700070007000700FF
+F0FFF00C157D9412>I<00C001E001E000C00000000000001FE01FE000E000E000E000E000E000
+E000E000E000E000E000E000E000E000E000E040C0E1C0FF807E000B1C7E9412>I<F800F80038
+003800380038003BFC3BFC38F039E03BC03F803F803FC03DE038E038703838FC7EFC7E0F147F93
+12>I<FF00FF000700070007000700070007000700070007000700070007000700070007000700
+FFF8FFF80D147E9312>I<F71C00FFBE0079E70079E70071C70071C70071C70071C70071C70071
+C70071C70071C700F9E780F8E380110E808D12>I<F9E0FFF03E383C3838383838383838383838
+383838383838FE3EFE3E0F0E7F8D12>I<0F803FE038E07070E038E038E038E038E038F0787070
+38E03FE00F800D0E7E8D12>I<FBE0FFF03C38381C380C380E380E380E380E380C381C3C383FF0
+3BC038003800380038003800FE00FE000F157F8D12>I<079C1FFC387C703C601CE01CE01CE01C
+E01C601C703C387C1FFC079C001C001C001C001C001C007F007F10157F8D12>I<FCF8FDFC1F1C
+1E081E001C001C001C001C001C001C001C00FFC0FFC00E0E7E8D12>I<1FF03FF06070C070E000
+7F003FE00FF000786018E018F030FFE0DFC00D0E7E8D12>I<06000E000E000E007FF8FFF80E00
+0E000E000E000E000E000E000E380E380E3807F003C00D127F9112>I<F8F8F8F8383838383838
+38383838383838383838383838781FFE0FBE0F0E7F8D12>I<FC7EFC7E38383C781C701C701C70
+0EE00EE00EE006C007C007C003800F0E7F8D12>I<FEFEFEFE701C701C301838383BB83FF83FF8
+3AB838B81CF01CF01CF00F0E7F8D12>I<7C7C7C7C1CF00EE00FC007C00380078007C00EE01EF0
+1C70FC7EFC7E0F0E7F8D12>I<FC7EFC7E3C381C381C701C700E700E600E6006E006E003C003C0
+03C0038003800380778077007E003C000F157F8D12>I<3FFC7FFC7038707000E001C003800700
+0E001C1C381C701CFFFCFFFC0E0E7F8D12>I E /Fg 35 122 df<00038000000380000007C000
+0007C0000007C000000FE000000FE000001FF000001BF000001BF0000031F8000031F8000061FC
+000060FC0000E0FE0000C07E0000C07E0001803F0001FFFF0003FFFF8003001F8003001F800600
+0FC006000FC00E000FE00C0007E0FFC07FFEFFC07FFE1F1C7E9B24>65 D<FFFFF800FFFFFF000F
+C01F800FC00FC00FC007C00FC007E00FC007E00FC007E00FC007E00FC007E00FC007C00FC00F80
+0FC03F000FFFFE000FC00F800FC007C00FC007E00FC003E00FC003F00FC003F00FC003F00FC003
+F00FC003F00FC007E00FC007E00FC01FC0FFFFFF00FFFFFC001C1C7E9B22>I<001FE02000FFF8
+E003F80FE007C003E00F8001E01F0000E03E0000E03E0000607E0000607C000060FC000000FC00
+0000FC000000FC000000FC000000FC000000FC000000FC0000007C0000607E0000603E0000603E
+0000C01F0000C00F80018007C0030003F80E0000FFFC00001FE0001B1C7D9B22>I<FFFFF800FF
+FFFF000FC01FC00FC007E00FC001F00FC001F80FC000F80FC000FC0FC0007C0FC0007C0FC0007E
+0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007C0FC0007C0FC000
+7C0FC000F80FC000F80FC001F00FC007E00FC01FC0FFFFFF00FFFFF8001F1C7E9B25>I<FFFFFF
+00FFFFFF000FC01F000FC007000FC003000FC003800FC003800FC181800FC181800FC181800FC1
+80000FC380000FFF80000FFF80000FC380000FC180000FC180000FC180600FC180600FC000E00F
+C000C00FC000C00FC001C00FC001C00FC003C00FC00F80FFFFFF80FFFFFF801B1C7E9B1F>I<FF
+FFFF00FFFFFF000FC01F000FC007000FC003000FC003800FC003800FC001800FC181800FC18180
+0FC180000FC180000FC380000FFF80000FFF80000FC380000FC180000FC180000FC180000FC180
+000FC000000FC000000FC000000FC000000FC000000FC00000FFFF0000FFFF0000191C7E9B1E>
+I<000FF008007FFE3801FC07F807E001F80F8000781F0000783F0000383E0000387E0000187C00
+0018FC000000FC000000FC000000FC000000FC000000FC000000FC007FFFFC007FFF7C0001F87E
+0001F83E0001F83F0001F81F0001F80F8001F807E001F801FC07F8007FFE78000FF818201C7D9B
+26>I<FFFC3FFFFFFC3FFF0FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F0
+0FC003F00FC003F00FC003F00FFFFFF00FFFFFF00FC003F00FC003F00FC003F00FC003F00FC003
+F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F0FFFC3FFFFFFC3FFF201C
+7E9B25>I<FFFF00FFFF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000F
+C0000FC0000FC0000FC0000FC0000FC0000FC0030FC0030FC0030FC0070FC0070FC0060FC00E0F
+C01E0FC07EFFFFFEFFFFFE181C7E9B1D>76 D<FFE003FFFFE003FF0FF000300FF800300DFC0030
+0CFE00300C7E00300C3F00300C1F80300C1FC0300C0FE0300C07F0300C03F0300C01F8300C01FC
+300C00FE300C007F300C003F300C001FB00C001FF00C000FF00C0007F00C0003F00C0001F00C00
+00F00C0000F0FFC00070FFC00030201C7E9B25>78 D<FFFFF800FFFFFE000FC03F800FC00F800F
+C007C00FC007E00FC007E00FC007E00FC007E00FC007E00FC007C00FC007C00FC00F800FC03F00
+0FFFFC000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000
+000FC000000FC00000FFFC0000FFFC00001B1C7E9B21>80 D<07F8201FFEE03C07E07801E07000
+E0F000E0F00060F00060F80000FE0000FFE0007FFE003FFF003FFF800FFFC007FFE0007FE00003
+F00001F00000F0C000F0C000F0C000E0E000E0F001C0FC03C0EFFF0083FC00141C7D9B1B>83
+D<7FFFFFE07FFFFFE0781F81E0701F80E0601F8060E01F8070C01F8030C01F8030C01F8030C01F
+8030001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000
+1F8000001F8000001F8000001F8000001F8000001F8000001F800007FFFE0007FFFE001C1C7E9B
+21>I<FFFC03FFFFFC03FF0FC000300FC000300FC000300FC000300FC000300FC000300FC00030
+0FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000
+300FC000300FC0003007C0003007C0006003E000E001F001C000FC0780007FFE00000FF800201C
+7E9B25>I<FFFC7FFE0FFCFFFC7FFE0FFC0FC007E000C00FC007F000C00FE003F001C007E003F0
+018007E007F8018003F007F8030003F007F8030003F80CFC070001F80CFC060001F81CFE060001
+FC187E0E0000FC187E0C0000FC387F0C00007E303F1800007E303F1800007F601FB800003F601F
+B000003FE01FF000003FC00FF000001FC00FE000001FC00FE000000F8007C000000F8007C00000
+0F0003C0000007000380000007000380002E1C7F9B31>87 D<0FF8001C1E003E0F803E07803E07
+C01C07C00007C0007FC007E7C01F07C03C07C07C07C0F807C0F807C0F807C0780BC03E13F80FE1
+F815127F9117>97 D<FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F0000
+1F00001F3F801FE1E01F80701F00781F003C1F003C1F003E1F003E1F003E1F003E1F003E1F003E
+1F003C1F003C1F00781F80701EC1E01C3F00171D7F9C1B>I<03FC000E0E001C1F003C1F00781F
+00780E00F80000F80000F80000F80000F80000F800007800007801803C01801C03000E0E0003F8
+0011127E9115>I<000FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F000
+01F001F9F00F07F01C03F03C01F07801F07801F0F801F0F801F0F801F0F801F0F801F0F801F078
+01F07801F03C01F01C03F00F0FFE03F9FE171D7E9C1B>I<01FC000F07001C03803C01C07801C0
+7801E0F801E0F801E0FFFFE0F80000F80000F800007800007C00603C00601E00C00F038001FC00
+13127F9116>I<03F8F00E0F381E0F381C07303C07803C07803C07803C07801C07001E0F000E0E
+001BF8001000001800001800001FFF001FFFC00FFFE01FFFF07801F8F00078F00078F000787000
+707800F01E03C007FF00151B7F9118>103 D<FF0000FF00001F00001F00001F00001F00001F00
+001F00001F00001F00001F00001F0FC01F31E01F40F01F80F81F80F81F00F81F00F81F00F81F00
+F81F00F81F00F81F00F81F00F81F00F81F00F81F00F8FFE7FFFFE7FF181D7F9C1B>I<1E003F00
+3F003F003F001E00000000000000000000000000FF00FF001F001F001F001F001F001F001F001F
+001F001F001F001F001F001F00FFE0FFE00B1E7F9D0E>I<FF0000FF00001F00001F00001F0000
+1F00001F00001F00001F00001F00001F00001F0FF81F0FF81F03801F07001F0C001F18001F7000
+1FF8001FFC001FBC001F3E001F1F001F0F001F0F801F07C01F03E0FFC7FCFFC7FC161D7F9C19>
+107 D<FF00FF001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F00
+1F001F001F001F001F001F001F001F001F00FFE0FFE00B1D7F9C0E>I<FF0FC07E00FF31E18F00
+1F40F207801F80FC07C01F80FC07C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807
+C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807C0FFE7FF3FF8FFE7FF
+3FF825127F9128>I<FF0FC0FF31E01F40F01F80F81F80F81F00F81F00F81F00F81F00F81F00F8
+1F00F81F00F81F00F81F00F81F00F81F00F8FFE7FFFFE7FF18127F911B>I<01FC000F07801C01
+C03C01E07800F07800F0F800F8F800F8F800F8F800F8F800F8F800F87800F07800F03C01E01E03
+C00F078001FC0015127F9118>I<FF3F80FFE1E01F80F01F00781F007C1F003C1F003E1F003E1F
+003E1F003E1F003E1F003E1F003C1F007C1F00781F80F01FC1E01F3F001F00001F00001F00001F
+00001F00001F0000FFE000FFE000171A7F911B>I<FE3E00FE47001E8F801E8F801E8F801F0700
+1F00001F00001F00001F00001F00001F00001F00001F00001F00001F0000FFF000FFF00011127F
+9114>114 D<1FD830786018E018E018F000FF807FE07FF01FF807FC007CC01CC01CE01CE018F8
+30CFC00E127E9113>I<0300030003000300070007000F000F003FFCFFFC1F001F001F001F001F
+001F001F001F001F001F0C1F0C1F0C1F0C0F08079803F00E1A7F9913>I<FF07F8FF07F81F00F8
+1F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F01F80F01F8
+0786FF01F8FF18127F911B>I<FFC7FCFFC7FC1F81800F838007C70003EE0001FC0001F80000F8
+00007C0000FE0001DF00039F00070F800607C00C03E0FF07FCFF07FC16127F9119>120
+D<FFC1FCFFC1FC1F00601F80E00F80C00FC0C007C18007C18003E30003E30001F70001F60000FE
+0000FC0000FC00007800007800003000003000007000706000F86000F8C000F980007300003E00
+00161A7F9119>I E /Fh 47 122 df<020408103020604040C0C0C0C0C0C0C0C0404060203010
+080402071A7F920C>40 D<8040201018080C0404060606060606060604040C081810204080071A
+7E920C>I<40E060202040408003087E8209>44 D<40E04003037E8209>46
+D<0C003C00CC000C000C000C000C000C000C000C000C000C000C000C000C00FF8009107E8F0F>
+49 D<1F00618040C08060C0600060006000C00180030006000C00102020207FC0FFC00B107F8F
+0F>I<1F00218060C060C000C0008001800F00008000400060C060C060804060801F000B107F8F
+0F>I<0300030007000F000B001300330023004300C300FFE003000300030003001FE00B107F8F
+0F>I<1F00318060C0C040C060C060C06040E021E01E600060004060C0608043003E000B107F8F
+0F>57 D<40E040000000000040E060202040408003107E8A09>59 D<03E0000C180010040023C2
+004631004C0D00980C80980C80980C80980C80980C804C0C80463C8023C7001000000C038003FC
+0011117E9017>64 D<FFF8180C18061803180318031806181C1FFC180618031803180318031806
+180EFFF810117F9015>66 D<03F10C0B1807300360014001C000C000C000C000C0004001600130
+0218020C0C03F010117E9016>I<FFF800180C001803001801001801801800801800C01800C018
+00C01800C01800C01800C0180180180100180300180E00FFF80012117F9017>I<FFFE18061802
+180318011821182018601FE01860182018201800180018001800FF0010117F9014>70
+D<03F1000C0B00180700300300600100400100C00000C00000C00000C03FC0C003004003006003
+003003001803000C070003F90012117E9017>I<FF181818181818181818181818181818FF0811
+7F900B>73 D<FF0018001800180018001800180018001800180018021802180218061804181CFF
+FC0F117F9013>76 D<F81FC01C07001C020016020013020013020011820010C20010C200106200
+103200101200101A00100E00100600380600FE020012117F9016>78 D<FFF0181C180418061806
+18061804181C1FF01800180018001800180018001800FF000F117F9014>80
+D<FFE000181800180C00180600180600180600180C001818001FE000181800180C00180C00180C
+00180C00180C20180420FF03C013117F9016>82 D<1F2060E0006080208020800060003E001F80
+00C00060002080208020C040E0C09F000B117E9011>I<7FFF8060C18040C080C0C0C080C04080
+C04000C00000C00000C00000C00000C00000C00000C00000C00000C00000C0000FFC0012117F90
+16>I<FF1FC0180700180200180200180200180200180200180200180200180200180200180200
+1802000802000C040006080001F00012117F9016>I<FC07C03003003003001802001802000C04
+000C040006080006080006080003100003100001A00001A00001E00000C00000C00012117F9016
+>I<3E006300018001800F8031804180C190C19063903DE00C0B7F8A0F>97
+D<F0003000300030003000300037C038603030301830183018301830183030386027800D117F90
+11>I<1F8030C06000C000C000C000C000C000604030801F000A0B7F8A0E>I<01E0006000600060
+006000600F6030E06060C060C060C060C060C060606030E01F780D117F9011>I<1F00318060C0
+C0C0FFC0C000C000C000604030801F000A0B7F8A0E>I<07000D801800180018001800FE001800
+180018001800180018001800180018007E00091180900A>I<1EF0331061806180618033003E00
+400060003F803FC060E0C060C060C06060C01F000C117F8A0F>I<F00030003000300030003000
+33C03C6030603060306030603060306030603060FCF80D117F9011>I<30703000000000F03030
+30303030303030FC0612809108>I<F0003000300030003000300031F030C03080330036003F00
+3300318031C030C0F9F00C117F9010>107 D<F0303030303030303030303030303030FC061180
+9008>I<F3C3C03C2C20383830303030303030303030303030303030303030303030FCFCFC160B
+7F8A1A>I<F3C03C6030603060306030603060306030603060FCF80D0B7F8A11>I<1F00318060C0
+C060C060C060C060C06060C031801F000B0B7F8A0F>I<F7C03860303030183018301830183018
+3030386037803000300030003000FC000D107F8A11>I<F7003980300030003000300030003000
+30003000FC00090B7F8A0C>114 D<3E028280783E038181C2BC080B7F8A0C>I<10103030FE3030
+303030323232321C070F7F8E0C>I<F1E03060306030603060306030603060306030E00F780D0B
+7F8A11>I<F8F0706030403040188018800D000D000D00060006000C0B7F8A10>I<F9F3C060E180
+30E10030E1003131001932001A12000E1C000E1C000C0C00040800120B7F8A16>I<F8F0306030
+403040188018800D000D000F000600060004000400CC00C80070000C107F8A10>121
+D E /Fi 12 86 df<FFFFFF8000FFFFFFE00007F001F80007F000FC0007F0007E0007F0007E00
+07F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007E0007F000FE0007F000FC
+0007F003F80007FFFFF00007FFFFF00007F001FC0007F0007E0007F0003F0007F0003F8007F000
+1F8007F0001FC007F0001FC007F0001FC007F0001FC007F0001FC007F0001FC007F0003F8007F0
+003F8007F0007F0007F001FE00FFFFFFF800FFFFFFC00022227EA128>66
+D<0003FE0080001FFF818000FF01E38001F8003F8003E0001F8007C0000F800F800007801F8000
+07803F000003803F000003807F000001807E000001807E00000180FE00000000FE00000000FE00
+000000FE00000000FE00000000FE00000000FE00000000FE000000007E000000007E000001807F
+000001803F000001803F000003801F800003000F8000030007C000060003F0000C0001F8003800
+00FF00F000001FFFC0000003FE000021227DA128>I<FFFFFF8000FFFFFFF00007F003FC0007F0
+007E0007F0003F0007F0001F8007F0000FC007F00007E007F00007E007F00007F007F00003F007
+F00003F007F00003F007F00003F807F00003F807F00003F807F00003F807F00003F807F00003F8
+07F00003F807F00003F807F00003F807F00003F007F00003F007F00003F007F00007E007F00007
+E007F0000FC007F0001F8007F0003F0007F0007E0007F003FC00FFFFFFF000FFFFFF800025227E
+A12B>I<FFFFFFFCFFFFFFFC07F000FC07F0003C07F0001C07F0000C07F0000E07F0000E07F000
+0607F0180607F0180607F0180607F0180007F0380007F0780007FFF80007FFF80007F0780007F0
+380007F0180007F0180007F0180307F0180307F0000307F0000607F0000607F0000607F0000E07
+F0000E07F0001E07F0003E07F001FCFFFFFFFCFFFFFFFC20227EA125>I<FFFFFFF8FFFFFFF807
+F001F807F0007807F0003807F0001807F0001C07F0001C07F0000C07F0000C07F0180C07F0180C
+07F0180007F0180007F0380007F0780007FFF80007FFF80007F0780007F0380007F0180007F018
+0007F0180007F0180007F0000007F0000007F0000007F0000007F0000007F0000007F0000007F0
+0000FFFFE000FFFFE0001E227EA123>I<0003FE0040001FFFC0C0007F00F1C001F8003FC003F0
+000FC007C00007C00FC00003C01F800003C03F000001C03F000001C07F000000C07E000000C07E
+000000C0FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000
+FE000FFFFC7E000FFFFC7F00001FC07F00001FC03F00001FC03F00001FC01F80001FC00FC0001F
+C007E0001FC003F0001FC001FC003FC0007F80E7C0001FFFC3C00003FF00C026227DA12C>I<FF
+FFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003
+F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003
+F80003F80003F80003F80003F80003F800FFFFE0FFFFE013227FA115>73
+D<FFFF803FFCFFFF803FFC07F000038007F000070007F0000E0007F000180007F000300007F000
+E00007F001C00007F003800007F007000007F00E000007F018000007F038000007F0FC000007F1
+FE000007F3FE000007F77F000007FE7F800007F83F800007F01FC00007F01FE00007F00FE00007
+F007F00007F007F80007F003F80007F001FC0007F001FE0007F000FF0007F0007F0007F0007F80
+07F0003FC0FFFF83FFFCFFFF83FFFC26227EA12C>75 D<FFF8001FFEFFFC001FFE07FC0000C007
+FE0000C006FF0000C0067F8000C0063FC000C0061FE000C0060FE000C0060FF000C00607F800C0
+0603FC00C00601FE00C00600FE00C00600FF00C006007F80C006003FC0C006001FE0C006000FF0
+C0060007F0C0060007F8C0060003FCC0060001FEC0060000FFC00600007FC00600007FC0060000
+3FC00600001FC00600000FC006000007C006000003C006000003C0FFF00001C0FFF00000C02722
+7EA12C>78 D<0007FC0000003FFF800000FC07E00003F001F80007E000FC000FC0007E001F8000
+3F001F80003F003F00001F803F00001F807F00001FC07E00000FC07E00000FC0FE00000FE0FE00
+000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE07E
+00000FC07F00001FC07F00001FC03F00001F803F81F03F801F83F83F000FC70C7E0007E606FC00
+03F607F80000FF07E000003FFF80000007FF80200000038020000001C020000001E0E0000001FF
+E0000001FFC0000000FFC0000000FFC00000007F800000007F000000001E00232C7DA12A>81
+D<FFFFFE0000FFFFFFC00007F007F00007F001F80007F000FC0007F0007E0007F0007F0007F000
+7F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007E0007F000FC0007F001F80007F0
+07F00007FFFFC00007FFFF800007F00FE00007F007F00007F003F80007F001FC0007F001FC0007
+F001FC0007F001FC0007F001FC0007F001FC0007F001FC0007F001FC0007F001FC0607F000FE06
+07F000FF0CFFFF803FF8FFFF800FF027227EA12A>I<FFFF803FFCFFFF803FFC07F000018007F0
+00018007F000018007F000018007F000018007F000018007F000018007F000018007F000018007
+F000018007F000018007F000018007F000018007F000018007F000018007F000018007F0000180
+07F000018007F000018007F000018007F000018007F000018007F000018007F000018003F00003
+0003F800030001F800060000FC000E00007E001C00003F80F800000FFFE0000001FF000026227E
+A12B>85 D E end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 300
+TeXDict begin @landscape
+%%EndSetup
+%%Page: 1 1
+bop -225 -183 a Fi(GDB)14 b(QUICK)g(REFERENCE)22 b Fh(GDB)14
+b(V)n(ersion)h(4)-225 -91 y Fg(Essen)o(tial)c(Commands)-225
+-45 y Ff(gdb)i Fe(pr)n(o)n(gr)n(am)f Fd([)p Fe(c)n(or)n(e)p
+Fd(])24 b Fc(debug)14 b Fe(pr)n(o)n(gr)n(am)e Fd([)p Fc(using)i(coredump)g
+Fe(c)n(or)n(e)p Fd(])-225 9 y Ff(b)f Fd([)p Fe(\014le)p Ff(:)p
+Fd(])p Fe(function)68 b Fc(set)13 b(breakp)q(oin)o(t)i(at)e
+Fe(function)g Fd([)p Fc(in)h Fe(\014le)p Fd(])-225 63 y Ff(run)f
+Fd([)p Fe(ar)n(glist)p Fd(])126 b Fc(start)13 b(y)o(our)h(program)f
+Fd([)p Fc(with)h Fe(ar)n(glist)p Fd(])-225 106 y Ff(bt)274
+b Fc(bac)o(ktrace:)20 b(displa)o(y)c(program)d(stac)o(k)-225
+143 y Ff(p)g Fe(expr)214 b Fc(displa)o(y)15 b(the)f(v)n(alue)h(of)e(an)h
+(expression)-225 180 y Ff(c)292 b Fc(con)o(tin)o(ue)14 b(running)h(y)o(our)f
+(program)-225 218 y Ff(n)292 b Fc(next)14 b(line,)h(stepping)g(o)o(v)o(er)f
+(function)g(calls)-225 255 y Ff(s)292 b Fc(next)14 b(line,)h(stepping)g(in)o
+(to)f(function)h(calls)-225 352 y Fg(Starting)c(GDB)-225 398
+y Ff(gdb)256 b Fc(start)13 b(GDB,)h(with)g(no)g(debugging)g(\014les)-225
+435 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)121 b Fc(b)q(egin)14 b(debugging)g
+Fe(pr)n(o)n(gr)n(am)-225 472 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)f(c)n(or)n(e)48
+b Fc(debug)14 b(coredump)g Fe(c)n(or)n(e)f Fc(pro)q(duced)h(b)o(y)105
+510 y Fe(pr)n(o)n(gr)n(am)-225 548 y Ff(gdb)f(--help)135 b
+Fc(describ)q(e)14 b(command)g(line)g(options)-225 647 y Fg(Stopping)c(GDB)
+-225 692 y Ff(quit)238 b Fc(exit)14 b(GDB;)g(also)g Ff(q)f
+Fc(or)g Ff(EOF)g Fc(\(eg)g Ff(C-d)p Fc(\))-225 734 y Ff(INTERRUPT)148
+b Fc(\(eg)13 b Ff(C-c)p Fc(\))g(terminate)g(curren)o(t)h(command,)h(or)105
+771 y(send)g(to)e(running)i(pro)q(cess)-225 868 y Fg(Getting)c(Help)-225
+914 y Ff(help)238 b Fc(list)14 b(classes)g(of)g(commands)-225
+951 y Ff(help)e Fe(class)155 b Fc(one-line)14 b(descriptions)h(for)f
+(commands)g(in)105 988 y Fe(class)-225 1021 y Ff(help)e Fe(c)n(ommand)83
+b Fc(describ)q(e)14 b Fe(c)n(ommand)-225 1119 y Fg(Executing)e(y)o(our)h
+(Program)-225 1165 y Ff(run)g Fe(ar)n(glist)150 b Fc(start)13
+b(y)o(our)h(program)f(with)i Fe(ar)n(glist)-225 1203 y Ff(run)256
+b Fc(start)13 b(y)o(our)h(program)f(with)i(curren)o(t)f(argumen)o(t)105
+1240 y(list)-225 1273 y Ff(run)f Fb(:)7 b(:)g(:)12 b Ff(<)p
+Fe(inf)h Ff(>)p Fe(outf)32 b Fc(start)13 b(y)o(our)h(program)f(with)i(input,)
+g(output)105 1310 y(redirected)-225 1360 y Ff(kill)238 b Fc(kill)15
+b(running)g(program)-225 1434 y Ff(tty)e Fe(dev)193 b Fc(use)14
+b Fe(dev)f Fc(as)g(stdin)i(and)f(stdout)g(for)g(next)g Ff(run)-225
+1472 y(set)f(args)f Fe(ar)n(glist)66 b Fc(sp)q(ecify)15 b Fe(ar)n(glist)d
+Fc(for)i(next)g Ff(run)-225 1509 y(set)f(args)171 b Fc(sp)q(ecify)15
+b(empt)o(y)f(argumen)o(t)g(list)-225 1546 y Ff(show)e(args)154
+b Fc(displa)o(y)15 b(argumen)o(t)f(list)-225 1621 y Ff(show)e(environment)28
+b Fc(sho)o(w)13 b(all)i(en)o(vironmen)o(t)g(v)n(ariables)-225
+1659 y Ff(show)d(env)h Fe(var)110 b Fc(sho)o(w)13 b(v)n(alue)i(of)f(en)o
+(vironmen)o(t)h(v)n(ariable)f Fe(var)-225 1696 y Ff(set)f(env)g
+Fe(var)f(string)28 b Fc(set)13 b(en)o(vironmen)o(t)j(v)n(ariable)e
+Fe(var)-225 1733 y Ff(unset)e(env)h Fe(var)92 b Fc(remo)o(v)o(e)13
+b Fe(var)g Fc(from)h(en)o(vironmen)o(t)-225 1820 y Fg(Shell)d(Commands)-225
+1866 y Ff(cd)i Fe(dir)217 b Fc(c)o(hange)13 b(w)o(orking)h(directory)g(to)f
+Fe(dir)-225 1903 y Ff(pwd)256 b Fc(Prin)o(t)15 b(w)o(orking)e(directory)-225
+1941 y Ff(make)f Fb(:)7 b(:)g(:)176 b Fc(call)14 b(\\)p Ff(make)p
+Fc(")-225 1978 y Ff(shell)e Fe(cmd)146 b Fc(execute)13 b(arbitrary)h(shell)h
+(command)f(string)-225 2100 y Fd([)f(])h Fh(surround)f(optional)j(argumen)o
+(ts)45 b Fb(:)7 b(:)g(:)13 b Fh(sho)o(w)h(one)f(or)h(more)f(argumen)o(ts)-216
+2174 y(c)-230 2175 y Fa(\015)p Fh(1991,)h(1992)h(F)n(ree)d(Soft)o(w)o(are)h
+(F)n(oundation,)h(Inc.)60 b(P)o(ermissions)15 b(on)f(bac)o(k)p
+800 -217 1 9 v 800 2175 V 875 -183 a Fg(Breakp)q(oin)o(ts)d(and)j(W)l(atc)o
+(hp)q(oin)o(ts)875 -132 y Ff(break)e Fd([)p Fe(\014le)p Ff(:)p
+Fd(])p Fe(line)875 -86 y Ff(b)i Fd([)p Fe(\014le)p Ff(:)p Fd(])p
+Fe(line)1185 -132 y Fc(set)g(breakp)q(oin)o(t)g(at)f Fe(line)h
+Fc(n)o(um)o(b)q(er)h Fd([)p Fc(in)f Fe(\014le)p Fd(])1185 -94
+y Fc(eg:)33 b Ff(break)12 b(main.c:37)875 -32 y(break)g Fd([)p
+Fe(\014le)p Ff(:)p Fd(])p Fe(func)57 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f
+Fe(func)h Fd([)p Fc(in)g Fe(\014le)p Fd(])875 11 y Ff(break)e(+)p
+Fe(o\013set)875 48 y Ff(break)g(-)p Fe(o\013set)1185 11 y Fc(set)i(break)f
+(at)h Fe(o\013set)f Fc(lines)i(from)f(curren)o(t)g(stop)875
+87 y Ff(break)e(*)p Fe(addr)121 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f
+(address)h Fe(addr)875 124 y Ff(break)220 b Fc(set)14 b(breakp)q(oin)o(t)g
+(at)f(next)i(instruction)875 161 y Ff(break)d Fb(:)7 b(:)g(:)12
+b Ff(if)i Fe(expr)31 b Fc(break)14 b(conditionally)h(on)f(nonzero)f
+Fe(expr)875 211 y Ff(cond)g Fe(n)h Fd([)p Fe(expr)p Fd(])103
+b Fc(new)13 b(conditional)i(expression)g(on)e(breakp)q(oin)o(t)1206
+248 y Fe(n)p Fc(;)h(mak)o(e)g(unconditional)h(if)g(no)e Fe(expr)875
+286 y Ff(tbreak)f Fb(:)7 b(:)g(:)140 b Fc(temp)q(orary)13 b(break;)i(disable)
+f(when)g(reac)o(hed)875 324 y Ff(rbreak)e Fe(r)n(e)n(gex)115
+b Fc(break)14 b(on)f(all)i(functions)g(matc)o(hing)f Fe(r)n(e)n(gex)875
+361 y Ff(watch)e Fe(expr)143 b Fc(set)14 b(a)f(w)o(atc)o(hp)q(oin)o(t)h(for)f
+(expression)i Fe(expr)875 398 y Ff(catch)d Fe(x)192 b Fc(break)14
+b(at)f(C++)i(handler)f(for)g(exception)g Fe(x)875 473 y Ff(info)f(break)135
+b Fc(sho)o(w)13 b(de\014ned)i(breakp)q(oin)o(ts)875 511 y Ff(info)e(watch)135
+b Fc(sho)o(w)13 b(de\014ned)i(w)o(atc)o(hp)q(oin)o(ts)875 585
+y Ff(clear)220 b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(next)g(instruction)
+875 635 y Ff(clear)e Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(fun)73
+b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(en)o(try)g(to)f Fe(fun)p
+Fc(\(\))875 688 y Ff(clear)f Fd([)p Fe(\014le)p Ff(:)p Fd(])p
+Fe(line)66 b Fc(delete)14 b(breakp)q(oin)o(ts)g(on)g(source)f(line)875
+742 y Ff(delete)f Fd([)p Fe(n)p Fd(])147 b Fc(delete)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 823 y Ff(disable)c
+Fd([)p Fe(n)p Fd(])130 b Fc(disable)15 b(breakp)q(oin)o(ts)f
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 877 y Ff(enable)d
+Fd([)p Fe(n)p Fd(])147 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 931 y Ff(enable)d(once)g
+Fd([)p Fe(n)p Fd(])63 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 969
+y(disable)f(again)g(when)f(reac)o(hed)875 1018 y Ff(enable)f(del)h
+Fd([)p Fe(n)p Fd(])80 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 1055
+y(delete)e(when)h(reac)o(hed)875 1105 y Ff(ignore)e Fe(n)i(c)n(ount)76
+b Fc(ignore)13 b(breakp)q(oin)o(t)i Fe(n)p Fc(,)f Fe(c)n(ount)g
+Fc(times)875 1180 y Ff(commands)d Fe(n)946 1217 y Fd([)p Ff(silent)p
+Fd(])946 1255 y Fe(c)n(ommand-list)1185 1180 y Fc(execute)i(GDB)h
+Fe(c)n(ommand-list)e Fc(ev)o(ery)j(time)1206 1217 y(breakp)q(oin)o(t)f
+Fe(n)g Fc(is)g(reac)o(hed.)21 b Fd([)p Ff(silent)1206 1263
+y Fc(suppresses)14 b(default)h(displa)o(y)p Fd(])875 1306 y
+Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)875 1393 y
+Fg(Program)f(Stac)o(k)875 1445 y Ff(backtrace)e Fd([)p Fe(n)p
+Fd(])875 1490 y Ff(bt)i Fd([)p Fe(n)p Fd(])1185 1445 y Fc(prin)o(t)i(trace)e
+(of)g(all)h(frames)g(in)h(stac)o(k;)f(or)f(of)h Fe(n)1206 1482
+y Fc(frames|innermost)g(if)h Fe(n)p Ff(>0)p Fc(,)e(outermost)h(if)1206
+1519 y Fe(n)p Ff(<0)875 1563 y(frame)e Fd([)p Fe(n)p Fd(])165
+b Fc(select)13 b(frame)h(n)o(um)o(b)q(er)h Fe(n)f Fc(or)f(frame)h(at)g
+(address)1206 1600 y Fe(n)p Fc(;)g(if)h(no)e Fe(n)p Fc(,)i(displa)o(y)g
+(curren)o(t)f(frame)875 1639 y Ff(up)f Fe(n)242 b Fc(select)13
+b(frame)h Fe(n)g Fc(frames)g(up)875 1676 y Ff(down)f Fe(n)206
+b Fc(select)13 b(frame)h Fe(n)g Fc(frames)g(do)o(wn)875 1720
+y Ff(info)f(frame)f Fd([)p Fe(addr)p Fd(])30 b Fc(describ)q(e)14
+b(selected)g(frame,)g(or)f(frame)h(at)f Fe(addr)875 1763 y
+Ff(info)g(args)153 b Fc(argumen)o(ts)14 b(of)f(selected)h(frame)875
+1800 y Ff(info)f(locals)117 b Fc(lo)q(cal)13 b(v)n(ariables)i(of)e(selected)h
+(frame)875 1844 y Ff(info)f(reg)f Fd([)p Fe(rn)p Fd(])p Fb(:)7
+b(:)g(:)875 1889 y Ff(info)13 b(all-reg)e Fd([)p Fe(rn)p Fd(])1185
+1844 y Fc(register)i(v)n(alues)i Fd([)p Fc(for)e(regs)g Fe(rn)s
+Fd(])g Fc(in)h(selected)1206 1881 y(frame;)g Ff(all-reg)d Fc(includes)k
+(\015oating)e(p)q(oin)o(t)875 1933 y Ff(info)g(catch)135 b
+Fc(exception)14 b(handlers)h(activ)o(e)e(in)i(selected)f(frame)p
+1900 -217 V 1900 2175 V 1975 -183 a Fg(Execution)f(Con)o(trol)1975
+-138 y Ff(continue)e Fd([)p Fe(c)n(ount)p Fd(])1975 -92 y Ff(c)j
+Fd([)p Fe(c)n(ount)p Fd(])2285 -138 y Fc(con)o(tin)o(ue)g(running;)i(if)e
+Fe(c)n(ount)g Fc(sp)q(eci\014ed,)g(ignore)2306 -100 y(this)g(breakp)q(oin)o
+(t)h(next)f Fe(c)n(ount)g Fc(times)1975 -26 y Ff(step)f Fd([)p
+Fe(c)n(ount)p Fd(])1975 20 y Ff(s)h Fd([)p Fe(c)n(ount)p Fd(])2285
+-26 y Fc(execute)g(un)o(til)h(another)e(line)i(reac)o(hed;)f(rep)q(eat)2306
+12 y Fe(c)n(ount)f Fc(times)i(if)f(sp)q(eci\014ed)1975 74 y
+Ff(stepi)e Fd([)p Fe(c)n(ount)p Fd(])1975 120 y Ff(si)h Fd([)p
+Fe(c)n(ount)p Fd(])2285 74 y Fc(step)h(b)o(y)h(mac)o(hine)f(instructions)h
+(rather)f(than)2306 111 y(source)f(lines)1975 186 y Ff(next)g
+Fd([)p Fe(c)n(ount)p Fd(])1975 232 y Ff(n)h Fd([)p Fe(c)n(ount)p
+Fd(])2285 186 y Fc(execute)g(next)g(line,)h(including)h(an)o(y)e(function)
+2306 223 y(calls)1975 286 y Ff(nexti)e Fd([)p Fe(c)n(ount)p
+Fd(])1975 331 y Ff(ni)h Fd([)p Fe(c)n(ount)p Fd(])2285 286
+y Fc(next)h(mac)o(hine)h(instruction)g(rather)e(than)2306 323
+y(source)g(line)1975 398 y Ff(until)f Fd([)p Fe(lo)n(c)n(ation)p
+Fd(])67 b Fc(run)14 b(un)o(til)i(next)e(instruction)h(\(or)e
+Fe(lo)n(c)n(ation)p Fc(\))1975 441 y Ff(finish)202 b Fc(run)14
+b(un)o(til)i(selected)e(stac)o(k)f(frame)h(returns)1975 484
+y Ff(return)e Fd([)p Fe(expr)p Fd(])101 b Fc(p)q(op)14 b(selected)g(stac)o(k)
+f(frame)h(without)2306 522 y(executing)g Fd([)p Fc(setting)f(return)i(v)n
+(alue)p Fd(])1975 566 y Ff(signal)d Fe(num)125 b Fc(resume)14
+b(execution)g(with)g(signal)h Fe(s)f Fc(\(none)f(if)i Ff(0)p
+Fc(\))1975 604 y Ff(jump)e Fe(line)1975 641 y Ff(jump)g(*)p
+Fe(addr)n(ess)2285 604 y Fc(resume)h(execution)g(at)g(sp)q(eci\014ed)g
+Fe(line)f Fc(n)o(um)o(b)q(er)2306 641 y(or)g Fe(addr)n(ess)1975
+681 y Ff(set)g(var=)p Fe(expr)106 b Fc(ev)n(aluate)14 b Fe(expr)e
+Fc(without)i(displa)o(ying)i(it;)f(use)2306 718 y(for)e(altering)h(program)f
+(v)n(ariables)1975 815 y Fg(Displa)o(y)1975 867 y Ff(print)f
+Fd([)p Ff(/)p Fe(f)6 b Fd(])13 b([)p Fe(expr)p Fd(])1975 913
+y Ff(p)h Fd([)p Ff(/)p Fe(f)5 b Fd(])13 b([)p Fe(expr)p Fd(])2285
+867 y Fc(sho)o(w)h(v)n(alue)g(of)g Fe(expr)e Fd([)p Fc(or)h(last)h(v)n(alue)h
+Ff($)p Fd(])2306 904 y Fc(according)e(to)g(format)h Fe(f)p
+Fc(:)2046 956 y Ff(x)221 b Fc(hexadecimal)2046 993 y Ff(d)g
+Fc(signed)14 b(decimal)2046 1030 y Ff(u)221 b Fc(unsigned)15
+b(decimal)2046 1068 y Ff(o)221 b Fc(o)q(ctal)2046 1105 y Ff(t)g
+Fc(binary)2046 1142 y Ff(a)g Fc(address,)14 b(absolute)g(and)g(relativ)o(e)
+2046 1180 y Ff(c)221 b Fc(c)o(haracter)2046 1217 y Ff(f)g Fc(\015oating)13
+b(p)q(oin)o(t)1975 1266 y Ff(call)g Fd([)p Ff(/)p Fe(f)5 b
+Fd(])13 b Fe(expr)89 b Fc(lik)o(e)15 b Ff(print)d Fc(but)i(do)q(es)g(not)g
+(displa)o(y)h Ff(void)1975 1320 y(x)f Fd([)p Ff(/)p Fe(Nuf)5
+b Fd(])14 b Fe(expr)98 b Fc(examine)14 b(memory)g(at)g(address)g
+Fe(expr)p Fc(;)f(optional)2306 1358 y(format)g(sp)q(ec)h(follo)o(ws)g(slash)
+2011 1396 y Fe(N)249 b Fc(coun)o(t)14 b(of)f(ho)o(w)h(man)o(y)h(units)g(to)e
+(displa)o(y)2011 1433 y Fe(u)256 b Fc(unit)15 b(size;)f(one)g(of)2356
+1471 y Ff(b)f Fc(individual)k(b)o(ytes)2356 1508 y Ff(h)c Fc(halfw)o(ords)h
+(\(t)o(w)o(o)f(b)o(ytes\))2356 1545 y Ff(w)g Fc(w)o(ords)h(\(four)g(b)o
+(ytes\))2356 1583 y Ff(g)f Fc(gian)o(t)h(w)o(ords)f(\(eigh)o(t)h(b)o(ytes\))
+2011 1620 y Fe(f)263 b Fc(prin)o(ting)15 b(format.)21 b(An)o(y)14
+b Ff(print)e Fc(format,)i(or)2356 1657 y Ff(s)f Fc(n)o(ull-terminated)j
+(string)2356 1695 y Ff(i)d Fc(mac)o(hine)h(instructions)1975
+1738 y Ff(disassem)d Fd([)p Fe(addr)p Fd(])62 b Fc(displa)o(y)15
+b(memory)g(as)e(mac)o(hine)h(instructions)1975 1840 y Fg(Automatic)e(Displa)o
+(y)1975 1891 y Ff(display)g Fd([)p Ff(/)p Fe(f)5 b Fd(])13
+b Fe(expr)36 b Fc(sho)o(w)14 b(v)n(alue)g(of)g Fe(expr)e Fc(eac)o(h)i(time)g
+(program)2306 1929 y(stops)g Fd([)p Fc(according)e(to)i(format)f
+Fe(f)6 b Fd(])1975 1972 y Ff(display)184 b Fc(displa)o(y)15
+b(all)g(enabled)f(expressions)h(on)f(list)1975 2014 y Ff(undisplay)d
+Fe(n)118 b Fc(remo)o(v)o(e)14 b(n)o(um)o(b)q(er\(s\))h Fe(n)f
+Fc(from)g(list)h(of)2306 2051 y(automatically)f(displa)o(y)o(ed)h
+(expressions)1975 2091 y Ff(disable)d(disp)g Fe(n)69 b Fc(disable)15
+b(displa)o(y)g(for)f(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975
+2132 y Ff(enable)d(disp)g Fe(n)87 b Fc(enable)14 b(displa)o(y)h(for)f
+(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975 2170 y Ff(info)e(display)99
+b Fc(n)o(um)o(b)q(ered)15 b(list)g(of)e(displa)o(y)j(expressions)p
+eop
+%%Page: 2 2
+bop -225 -183 a Fg(Expressions)-225 -138 y Fe(expr)245 b Fc(an)13
+b(expression)i(in)g(C,)f(C++,)g(or)g(Mo)q(dula-2)105 -100 y(\(including)i
+(function)f(calls\),)f(or:)-225 -60 y Fe(addr)s Ff(@)p Fe(len)176
+b Fc(an)13 b(arra)o(y)h(of)f Fe(len)h Fc(elemen)o(ts)h(b)q(eginning)f(at)105
+-23 y Fe(addr)-225 10 y(\014le)p Ff(::)p Fe(nm)182 b Fc(a)13
+b(v)n(ariable)h(or)g(function)h Fe(nm)e Fc(de\014ned)i(in)f
+Fe(\014le)-225 59 y Fa(f)p Fe(typ)n(e)p Fa(g)p Fe(addr)138
+b Fc(read)13 b(memory)h(at)g Fe(addr)e Fc(as)h(sp)q(eci\014ed)h
+Fe(typ)n(e)-225 105 y Ff($)292 b Fc(most)13 b(recen)o(t)h(displa)o(y)o(ed)i
+(v)n(alue)-225 142 y Ff($)p Fe(n)273 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n
+(alue)-225 179 y Ff($$)274 b Fc(displa)o(y)o(ed)15 b(v)n(alue)g(previous)g
+(to)e($)-225 217 y Ff($$)p Fe(n)255 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n
+(alue)e(bac)o(k)g(from)g($)-225 254 y Ff($)p -205 254 11 2
+v 292 w Fc(last)g(address)g(examined)g(with)h Ff(x)-225 291
+y($)p -205 291 V -193 291 V 292 w Fc(v)n(alue)f(at)g(address)g($)p
+357 291 10 2 v -225 329 a Ff($)p Fe(var)243 b Fc(con)o(v)o(enience)14
+b(v)n(ariable;)h(assign)f(an)o(y)g(v)n(alue)-225 410 y Ff(show)e(values)g
+Fd([)p Fe(n)p Fd(])63 b Fc(sho)o(w)13 b(last)h(10)f(v)n(alues)i
+Fd([)p Fc(or)e(surrounding)i($)p Fe(n)p Fd(])-225 453 y Ff(show)d
+(convenience)28 b Fc(displa)o(y)15 b(all)f(con)o(v)o(enience)h(v)n(ariables)
+-225 550 y Fg(Sym)o(b)q(ol)d(T)l(able)-225 595 y Ff(info)g(address)g
+Fe(s)74 b Fc(sho)o(w)13 b(where)h(sym)o(b)q(ol)h Fe(s)f Fc(is)g(stored)-225
+645 y Ff(info)e(func)h Fd([)p Fe(r)n(e)n(gex)p Fd(])42 b Fc(sho)o(w)13
+b(names,)i(t)o(yp)q(es)f(of)g(de\014ned)g(functions)105 682
+y(\(all,)h(or)e(matc)o(hing)h Fe(r)n(e)n(gex)p Fc(\))-225 733
+y Ff(info)e(var)h Fd([)p Fe(r)n(e)n(gex)p Fd(])60 b Fc(sho)o(w)13
+b(names,)i(t)o(yp)q(es)f(of)g(global)f(v)n(ariables)i(\(all,)105
+770 y(or)f(matc)o(hing)g Fe(r)n(e)n(gex)p Fc(\))-225 821 y
+Ff(whatis)e Fd([)p Fe(expr)p Fd(])-225 867 y Ff(ptype)g Fd([)p
+Fe(expr)p Fd(])85 821 y Fc(sho)o(w)h(data)h(t)o(yp)q(e)g(of)g
+Fe(expr)e Fd([)p Fc(or)h Ff($)p Fd(])g Fc(without)105 858 y(ev)n(aluating;)i
+Ff(ptype)d Fc(giv)o(es)i(more)g(detail)-225 910 y Ff(ptype)e
+Fe(typ)n(e)147 b Fc(describ)q(e)14 b(t)o(yp)q(e,)h(struct,)f(union,)h(or)f
+(en)o(um)-225 1008 y Fg(GDB)f(Scripts)-225 1054 y Ff(source)f
+Fe(script)104 b Fc(read,)14 b(execute)f(GDB)h(commands)g(from)g(\014le)105
+1091 y Fe(script)-225 1147 y Ff(define)e Fe(cmd)-154 1184 y(c)n(ommand-list)
+85 1147 y Fc(create)g(new)i(GDB)g(command)g Fe(cmd)p Fc(;)f(execute)105
+1184 y(script)i(de\014ned)f(b)o(y)h Fe(c)n(ommand-list)-225
+1222 y Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)-225
+1260 y Ff(document)d Fe(cmd)-154 1297 y(help-text)85 1260 y
+Fc(create)h(online)j(do)q(cumen)o(tation)f(for)f(new)h(GDB)105
+1297 y(command)g Fe(cmd)-225 1335 y Ff(end)256 b Fc(end)14
+b(of)g Fe(help-text)-225 1432 y Fg(Signals)-225 1478 y Ff(handle)e
+Fe(signal)h(act)44 b Fc(sp)q(ecify)15 b(GDB)e(actions)h(for)f
+Fe(signal)p Fc(:)-190 1515 y Ff(print)185 b Fc(announce)13
+b(signal)-190 1553 y Ff(noprint)149 b Fc(b)q(e)13 b(silen)o(t)i(for)f(signal)
+-190 1590 y Ff(stop)203 b Fc(halt)14 b(execution)g(on)g(signal)-190
+1627 y Ff(nostop)167 b Fc(do)13 b(not)h(halt)g(execution)-190
+1665 y Ff(pass)203 b Fc(allo)o(w)13 b(y)o(our)h(program)f(to)h(handle)g
+(signal)-190 1702 y Ff(nopass)167 b Fc(do)13 b(not)h(allo)o(w)g(y)o(our)g
+(program)f(to)g(see)h(signal)-225 1739 y Ff(info)e(signals)100
+b Fc(sho)o(w)13 b(table)h(of)g(signals,)h(GDB)e(action)h(for)f(eac)o(h)-225
+1838 y Fg(Debugging)e(T)l(argets)-225 1884 y Ff(target)h Fe(typ)n(e)g(p)n(ar)
+n(am)24 b Fc(connect)13 b(to)g(target)g(mac)o(hine,)i(pro)q(cess,)e(or)h
+(\014le)-225 1921 y Ff(help)e(target)118 b Fc(displa)o(y)15
+b(a)o(v)n(ailable)g(targets)-225 1958 y Ff(attach)d Fe(p)n(ar)n(am)97
+b Fc(connect)13 b(to)g(another)h(pro)q(cess)-225 1996 y Ff(detach)202
+b Fc(release)13 b(target)f(from)i(GDB)g(con)o(trol)p 800 -217
+1 9 v 800 2175 V 875 -183 a Fg(Con)o(trollin)o(g)d(GDB)875
+-138 y Ff(set)i Fe(p)n(ar)n(am)f(value)61 b Fc(set)14 b(one)f(of)h(GDB's)g
+(in)o(ternal)h(parameters)875 -100 y Ff(show)e Fe(p)n(ar)n(am)132
+b Fc(displa)o(y)15 b(curren)o(t)f(setting)g(of)g(parameter)875
+-51 y(P)o(arameters)f(understo)q(o)q(d)h(b)o(y)h Ff(set)e Fc(and)h
+Ff(show)p Fc(:)910 -13 y Ff(complaints)d Fe(limit)i Fc(n)o(um)o(b)q(er)i(of)e
+(messages)h(on)f(un)o(usual)j(sym)o(b)q(ols)910 28 y Ff(confirm)c
+Fe(on/o\013)43 b Fc(enable)14 b(or)f(disable)i(cautionary)f(queries)910
+66 y Ff(editing)e Fe(on/o\013)43 b Fc(con)o(trol)13 b Ff(readline)e
+Fc(command-line)k(editing)910 103 y Ff(height)d Fe(lpp)110
+b Fc(n)o(um)o(b)q(er)15 b(of)e(lines)i(b)q(efore)f(pause)g(in)g(displa)o(y)
+910 145 y Ff(language)d Fe(lang)58 b Fc(Language)12 b(for)h(GDB)h
+(expressions)h(\()p Ff(auto)p Fc(,)e Ff(c)g Fc(or)1206 182
+y Ff(modula-2)p Fc(\))910 222 y Ff(listsize)e Fe(n)101 b Fc(n)o(um)o(b)q(er)
+15 b(of)e(lines)i(sho)o(wn)f(b)o(y)h Ff(list)910 259 y(prompt)d
+Fe(str)114 b Fc(use)14 b Fe(str)f Fc(as)g(GDB)h(prompt)910
+297 y Ff(radix)e Fe(b)n(ase)111 b Fc(o)q(ctal,)13 b(decimal,)i(or)e(hex)i(n)o
+(um)o(b)q(er)1206 334 y(represen)o(tation)910 374 y Ff(verbose)d
+Fe(on/o\013)43 b Fc(con)o(trol)13 b(messages)g(when)h(loading)g(sym)o(b)q
+(ols)910 411 y Ff(width)e Fe(cpl)130 b Fc(n)o(um)o(b)q(er)15
+b(of)e(c)o(haracters)g(b)q(efore)h(line)g(folded)910 449 y
+Ff(write)e Fe(on/o\013)79 b Fc(Allo)o(w)13 b(or)h(forbid)g(patc)o(hing)h
+(binary)m(,)g(core)e(\014les)1206 486 y(\(when)g(reop)q(ened)h(with)g
+Ff(exec)f Fc(or)g Ff(core)p Fc(\))910 526 y Ff(history)f Fb(:)7
+b(:)g(:)910 563 y Ff(h)14 b Fb(:)7 b(:)g(:)1185 526 y Fc(groups)14
+b(with)g(the)g(follo)o(wing)g(options:)910 598 y Ff(h)g(exp)f
+Fe(o\013/on)82 b Fc(disable/enable)14 b Ff(readline)d Fc(history)k(expansion)
+910 635 y Ff(h)f(file)e Fe(\014lename)33 b Fc(\014le)14 b(for)f(recording)h
+(GDB)f(command)h(history)910 672 y Ff(h)g(size)e Fe(size)104
+b Fc(n)o(um)o(b)q(er)15 b(of)e(commands)h(k)o(ept)h(in)f(history)h(list)910
+710 y Ff(h)f(save)e Fe(o\013/on)65 b Fc(con)o(trol)13 b(use)h(of)g(external)g
+(\014le)g(for)f(command)1206 747 y(history)910 803 y Ff(print)f
+Fb(:)7 b(:)g(:)910 840 y Ff(p)14 b Fb(:)7 b(:)g(:)1185 803
+y Fc(groups)14 b(with)g(the)g(follo)o(wing)g(options:)910 882
+y Ff(p)g(address)d Fe(on/o\013)h Fc(prin)o(t)j(memory)f(addresses)g(in)g
+(stac)o(ks,)h(v)n(alues)910 923 y Ff(p)f(array)e Fe(o\013/on)47
+b Fc(compact)13 b(or)g(attractiv)o(e)g(format)h(for)g(arra)o(ys)910
+965 y Ff(p)g(demangl)d Fe(on/o\013)h Fc(source)h(\(demangled\))h(or)g(in)o
+(ternal)g(form)g(for)1206 1002 y(C++)g(sym)o(b)q(ols)910 1042
+y Ff(p)g(asm-dem)d Fe(on/o\013)h Fc(demangle)i(C++)g(sym)o(b)q(ols)h(in)g
+(mac)o(hine-)1206 1079 y(instruction)g(output)910 1118 y Ff(p)f(elements)d
+Fe(limit)17 b Fc(n)o(um)o(b)q(er)e(of)e(arra)o(y)h(elemen)o(ts)g(to)g(displa)
+o(y)910 1160 y Ff(p)g(object)e Fe(on/o\013)29 b Fc(prin)o(t)15
+b(C++)f(deriv)o(ed)h(t)o(yp)q(es)g(for)e(ob)r(jects)910 1201
+y Ff(p)h(pretty)e Fe(o\013/on)29 b Fc(struct)14 b(displa)o(y:)23
+b(compact)13 b(or)g(inden)o(ted)910 1243 y Ff(p)h(union)e Fe(on/o\013)47
+b Fc(displa)o(y)15 b(of)f(union)h(mem)o(b)q(ers)910 1284 y
+Ff(p)f(vtbl)e Fe(o\013/on)65 b Fc(displa)o(y)15 b(of)f(C++)h(virtual)f
+(function)h(tables)875 1359 y Ff(show)e(commands)81 b Fc(sho)o(w)13
+b(last)h(10)f(commands)875 1396 y Ff(show)g(commands)e Fe(n)51
+b Fc(sho)o(w)13 b(10)g(commands)h(around)g(n)o(um)o(b)q(er)h
+Fe(n)875 1434 y Ff(show)e(commands)e(+)52 b Fc(sho)o(w)13 b(next)i(10)e
+(commands)875 1521 y Fg(W)l(orking)g(Files)875 1573 y Ff(file)g
+Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(for)h(b)q(oth)g(sym)
+o(b)q(ols)h(and)f(executable;)1206 1610 y(with)g(no)g(arg,)f(discard)h(b)q
+(oth)875 1659 y Ff(core)f Fd([)p Fe(\014le)p Fd(])156 b Fc(read)13
+b Fe(\014le)h Fc(as)f(coredump;)i(or)e(discard)875 1713 y Ff(exec)g
+Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(as)h(executable)g
+(only;)h(or)e(discard)875 1767 y Ff(symbol)f Fd([)p Fe(\014le)p
+Fd(])121 b Fc(use)14 b(sym)o(b)q(ol)h(table)f(from)g Fe(\014le)p
+Fc(;)f(or)h(discard)875 1810 y Ff(load)f Fe(\014le)180 b Fc(dynamically)15
+b(link)h Fe(\014le)f Fc(and)f(add)g(its)h(sym)o(b)q(ols)875
+1848 y Ff(add-sym)c Fe(\014le)j(addr)45 b Fc(read)13 b(additional)i(sym)o(b)q
+(ols)g(from)f Fe(\014le)p Fc(,)1206 1885 y(dynamically)h(loaded)f(at)f
+Fe(addr)875 1923 y Ff(info)g(files)135 b Fc(displa)o(y)15 b(w)o(orking)f
+(\014les)g(and)g(targets)f(in)i(use)875 1961 y Ff(path)e Fe(dirs)167
+b Fc(add)14 b Fe(dirs)f Fc(to)g(fron)o(t)h(of)g(path)g(searc)o(hed)f(for)1206
+1998 y(executable)g(and)h(sym)o(b)q(ol)h(\014les)875 2037 y
+Ff(show)e(path)153 b Fc(displa)o(y)15 b(executable)f(and)g(sym)o(b)q(ol)h
+(\014le)f(path)875 2074 y Ff(info)f(share)135 b Fc(list)15
+b(names)e(of)h(shared)g(libraries)h(curren)o(tly)1206 2111
+y(loaded)p 1900 -217 V 1900 2175 V 1975 -183 a Fg(Source)e(Files)1975
+-138 y Ff(dir)g Fe(names)148 b Fc(add)14 b(directory)g Fe(names)f
+Fc(to)h(fron)o(t)g(of)f(source)2306 -100 y(path)1975 -62 y
+Ff(dir)256 b Fc(clear)13 b(source)h(path)1975 -25 y Ff(show)f(dir)171
+b Fc(sho)o(w)14 b(curren)o(t)g(source)f(path)1975 50 y Ff(list)238
+b Fc(sho)o(w)14 b(next)g(ten)g(lines)h(of)e(source)1975 87
+y Ff(list)g(-)207 b Fc(sho)o(w)14 b(previous)g(ten)g(lines)1975
+125 y Ff(list)f Fe(lines)156 b Fc(displa)o(y)15 b(source)f(surrounding)h
+Fe(lines)p Fc(,)f(sp)q(eci\014ed)2306 162 y(as:)2011 206 y
+Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(num)122 b Fc(line)15 b(n)o(um)o(b)q(er)g
+Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 260 y([)p Fe(\014le)p
+Ff(:)p Fd(])p Fe(function)63 b Fc(b)q(eginning)15 b(of)e(function)i
+Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 303 y Ff(+)p Fe(o\013)217
+b(o\013)14 b Fc(lines)h(after)e(last)h(prin)o(ted)2011 340
+y Ff(-)p Fe(o\013)217 b(o\013)14 b Fc(lines)h(previous)f(to)g(last)g(prin)o
+(ted)2011 377 y Ff(*)p Fe(addr)n(ess)145 b Fc(line)15 b(con)o(taining)f
+Fe(addr)n(ess)1975 415 y Ff(list)f Fe(f)p Ff(,)p Fe(l)187 b
+Fc(from)14 b(line)h Fe(f)e Fc(to)g(line)i Fe(l)1975 452 y Ff(info)e(line)f
+Fe(num)76 b Fc(sho)o(w)14 b(starting,)g(ending)g(addresses)g(of)2306
+489 y(compiled)g(co)q(de)f(for)h(source)f(line)i Fe(num)1975
+528 y Ff(info)e(source)117 b Fc(sho)o(w)14 b(name)f(of)h(curren)o(t)g(source)
+f(\014le)1975 565 y Ff(info)g(sources)99 b Fc(list)15 b(all)f(source)f
+(\014les)h(in)h(use)1975 603 y Ff(forw)e Fe(r)n(e)n(gex)150
+b Fc(searc)o(h)13 b(follo)o(wing)h(source)g(lines)h(for)e Fe(r)n(e)n(gex)1975
+640 y Ff(rev)g Fe(r)n(e)n(gex)168 b Fc(searc)o(h)13 b(preceding)h(source)g
+(lines)h(for)e Fe(r)n(e)n(gex)1975 737 y Fg(GDB)g(under)f(GNU)i(Emacs)1975
+782 y Ff(M-x)f(gdb)189 b Fc(run)14 b(GDB)g(under)h(Emacs)1975
+820 y Ff(C-h)e(m)225 b Fc(describ)q(e)14 b(GDB)g(mo)q(de)1975
+857 y Ff(M-s)256 b Fc(step)14 b(one)f(line)i(\()p Ff(step)p
+Fc(\))1975 899 y Ff(M-n)256 b Fc(next)14 b(line)h(\()p Ff(next)p
+Fc(\))1975 936 y Ff(M-i)256 b Fc(step)14 b(one)f(instruction)i(\()p
+Ff(stepi)p Fc(\))1975 978 y Ff(C-c)e(C-f)189 b Fc(\014nish)15
+b(curren)o(t)f(stac)o(k)g(frame)f(\()p Ff(finish)p Fc(\))1975
+1015 y Ff(M-c)256 b Fc(con)o(tin)o(ue)14 b(\()p Ff(cont)p Fc(\))1975
+1052 y Ff(M-u)256 b Fc(up)14 b Fe(ar)n(g)f Fc(frames)h(\()p
+Ff(up)p Fc(\))1975 1094 y Ff(M-d)256 b Fc(do)o(wn)14 b Fe(ar)n(g)f
+Fc(frames)h(\()p Ff(down)p Fc(\))1975 1131 y Ff(C-x)f(&)225
+b Fc(cop)o(y)14 b(n)o(um)o(b)q(er)h(from)f(p)q(oin)o(t,)h(insert)f(at)f(end)
+1975 1169 y Ff(C-x)g(SPC)189 b Fc(\(in)14 b(source)g(\014le\))g(set)f(break)h
+(at)g(p)q(oin)o(t)1975 1267 y Fg(GDB)f(License)1975 1313 y
+Ff(show)g(copying)99 b Fc(Displa)o(y)15 b(GNU)e(General)g(Public)i(License)
+1975 1350 y Ff(show)e(warranty)81 b Fc(There)13 b(is)i(NO)e(W)l(ARRANTY)g
+(for)h(GDB.)2306 1387 y(Displa)o(y)h(full)g(no-w)o(arran)o(t)o(y)f(statemen)o
+(t.)2024 1622 y Fh(Cop)o(yrigh)o(t)2185 1621 y(c)2171 1622
+y Fa(\015)o Fh(1991,)h(1992,)f(1993)h(F)n(ree)d(Soft)o(w)o(are)i(F)n
+(oundation,)f(Inc.)2215 1660 y(Roland)i(P)o(esc)o(h)f(\(p)q(esc)o(h@cygn)o
+(us.com\))1997 1697 y(The)f(author)h(assumes)f(no)h(resp)q(onsibilit)o(y)j
+(for)c(an)o(y)h(errors)g(on)g(this)h(card.)1975 1759 y(This)g(card)e(ma)o(y)g
+(b)q(e)g(freely)h(distributed)g(under)f(the)g(terms)g(of)g(the)h(GNU)1975
+1797 y(General)h(Public)g(License.)2012 1834 y(Please)f(con)o(tribute)g(to)g
+(dev)o(elopmen)o(t)e(of)i(this)h(card)e(b)o(y)h(annotating)h(it.)1975
+1896 y(GDB)g(itself)f(is)h(free)e(soft)o(w)o(are;)g(y)o(ou)h(are)g(w)o
+(elcome)e(to)i(distribute)h(copies)f(of)1975 1934 y(it)h(under)e(the)g(terms)
+g(of)g(the)g(GNU)i(General)g(Public)g(License.)20 b(There)12
+b(is)1975 1971 y(absolutely)k(no)d(w)o(arran)o(t)o(y)i(for)e(GDB.)p
+eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/gnu/usr.bin/gdb/doc/refcard.tex b/gnu/usr.bin/gdb/doc/refcard.tex
new file mode 100644
index 000000000000..dfad02e6bb04
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/refcard.tex
@@ -0,0 +1,646 @@
+%%%%%%%%%%%%%%%% gdb-refcard.tex %%%%%%%%%%%%%%%%
+
+%This file is TeX source for a reference card describing GDB, the GNU debugger.
+%$Id: refcard.tex,v 1.1 1994/06/10 13:34:43 paul Exp $
+%Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+%Permission is granted to make and distribute verbatim copies of
+%this reference provided the copyright notices and permission notices
+%are preserved on all copies.
+%
+%TeX markup is a programming language; accordingly this file is source
+%for a program to generate a reference.
+%
+%This program is free software; you can 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 can find a copy of the GNU General Public License in the GDB
+%manual; or write to the Free Software Foundation, Inc.,
+%675 Mass Ave, Cambridge, MA 02139, USA.
+%
+%You can contact the author as: pesch@cygnus.com
+%
+% Roland Pesch
+% Cygnus Support
+% 1937 Landings Drive
+% Mountain View, CA 94043 USA
+%
+% +1 415 903 1400
+%
+%
+%
+% 22-AUG-1993 Andreas Vogel
+%
+% Modifications made in order to handle different papersizes correctly.
+% You only have to set the total width and height of the paper, the
+% horizontal and vertical margin space measured from *paper edge*
+% and the interline and interspec spacing.
+% In order to support a new papersize, you have to fiddle with the
+% latter four dimensions. Just try out a few values.
+% All other values will be computed at process time so it should be
+% quite easy to support different paper sizes - only four values to
+% guess :-)
+%
+% To find the configuration places, just search for the string
+% "CONFIGURATION".
+%
+% Andreas Vogel (av@ssw.de)
+%
+%
+%
+% Uncomment the following `magnification' command if you want to print
+% out in a larger font. Caution! You may need larger paper. You had
+% best avoid using 3-column output if you try this. See the ``Three
+% column format'' section below if you want to print in three column
+% format.
+%
+%\magnification=\magstep 1
+%
+% NOTE ON INTENTIONAL OMISSIONS: This reference card includes most GDB
+% commands, but due to space constraints there are some things I chose
+% to omit. In general, not all synonyms for commands are covered, nor
+% all variations of a command.
+% The GDB-under-Emacs section omits gdb-mode functions without default
+% keybindings. GDB startup options are not described.
+% set print sevenbit-strings, set symbol-reloading omitted.
+% printsyms, printpsyms, omitted since they're for GDB maintenance primarily
+% share omitted due to obsolescence
+% set check range/type omitted at least til code is in GDB.
+%
+%-------------------- Three column format -----------------------
+
+%%%% --- To disable three column format, comment out this entire section
+
+% Three-column format for landscape printing
+
+%-------- Papersize defs:
+
+\newdimen\totalwidth \newdimen\totalheight
+\newdimen\hmargin \newdimen\vmargin
+\newdimen\secskip \newdimen\lskip
+\newdimen\barwidth \newdimen\barheight
+\newdimen\intersecwidth
+
+%%
+%% START CONFIGURATION - PAPERSIZE DEFINITIONS
+%------- Papersize params:
+%% US letter paper (8.5x11in)
+%%
+\totalwidth=11in % total width of paper
+\totalheight=8.5in % total height of paper
+\hmargin=.25in % horizontal margin width
+\vmargin=.25in % vertical margin width
+\secskip=1pc % space between refcard secs
+\lskip=2pt % extra skip between \sec entries
+%------- end papersize params
+%%
+%% change according to personal taste, not papersize dependent
+%%
+\barwidth=.1pt % width of the cropmark bar
+\barheight=2pt % height of the cropmark bar
+\intersecwidth=0.5em % width between \itmwid and \dfnwid
+%%
+%% END CONFIGURATION - PAPERSIZE DEFINITIONS
+%%
+
+%%
+%% values to be computed - nothing to configure
+%%
+\newdimen\fullhsize % width of area without margins
+\newdimen\itmwid % width of item column
+\newdimen\dfnwid % width of definition column
+\newdimen\temp % only for temporary use
+
+%%
+%% adjust the offsets so the margins are measured *from paper edge*
+%%
+\hoffset=-1in \advance \hoffset by \hmargin
+\voffset=-1in \advance \voffset by \vmargin
+
+%%
+%% fullhsize = totalwidth - (2 * hmargin)
+%%
+\fullhsize=\totalwidth
+\temp=\hmargin \multiply \temp by 2 \advance \fullhsize by -\temp
+
+%%
+%% hsize = (fullhsize - (4 * hmargin) - (2 * barwidth)) / 3
+%%
+\hsize=\fullhsize
+\temp=\hmargin \multiply \temp by 4 \advance \hsize by -\temp
+\temp=\barwidth \multiply \temp by 2 \advance \hsize by -\temp
+\divide \hsize by 3
+
+%%
+%% vsize = totalheight - (2 * vmargin)
+%%
+\vsize=\totalheight
+\temp=\vmargin \multiply \temp by 2 \advance \vsize by -\temp
+
+%%
+%% itmwid = (hsize - intersecwidth) * 1/3
+%% dfnwid = (hsize - intersecwidth) * 2/3
+%%
+\temp=\hsize \advance \temp by -\intersecwidth \divide \temp by 3
+\itmwid=\temp
+\dfnwid=\hsize \advance \dfnwid by -\itmwid
+
+%-------- end papersize defs
+
+
+\def\fulline{\hbox to \fullhsize}
+\let\lcr=L \newbox\leftcolumn\newbox\centercolumn
+\output={\if L\lcr
+ \global\setbox\leftcolumn=\columnbox \global\let\lcr=C
+ \else
+ \if C\lcr
+ \global\setbox\centercolumn=\columnbox \global\let\lcr=R
+ \else \tripleformat \global\let\lcr=L
+ \fi
+ \fi
+% \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+ }
+
+%%
+%% START CONFIGURATION - ALTERNATIVE FOLDING GUIDES
+%%
+%% For NO printed folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+%\def\vdecor{\hskip\hmargin plus1fil\hskip\barwidth plus1fil\hskip\hmargin plus1fil}
+
+%% For SOLID LINE folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+%\def\vdecor{\hskip\hmargin plus1fil \vrule width \barwidth \hskip\hmargin plus1fil}
+
+%% For SMALL MARKS NEAR TOP AND BOTTOM as folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+\def\vdecor{\hskip\hmargin plus1fil
+\vbox to \vsize{\hbox to \barwidth{\vrule height\barheight width\barwidth}\vfill
+\hbox to \barwidth{\vrule height\barheight width\barwidth}}%THIS PERCENT SIGN IS ESSENTIAL
+\hskip\hmargin plus1fil}
+
+%%
+%% END CONFIGURATION - ALTERNATIVES FOR FOLDING GUIDES
+%%
+
+\def\tripleformat{\shipout\vbox{\fulline{\box\leftcolumn\vdecor
+ \box\centercolumn\vdecor
+ \columnbox}
+ }
+ \advancepageno}
+\def\columnbox{\leftline{\pagebody}}
+\def\bye{\par\vfill
+ \supereject
+ \if R\lcr \null\vfill\eject\fi
+ \end}
+
+%-------------------- end three column format -----------------------
+
+%-------------------- Computer Modern font defs: --------------------
+\font\bbf=cmbx10
+\font\vbbf=cmbx12
+\font\smrm=cmr6
+\font\brm=cmr10
+\font\rm=cmr7
+\font\it=cmti7
+\font\tt=cmtt8
+%-------------------- end font defs ---------------------------------
+
+%
+\hyphenpenalty=5000\tolerance=2000\raggedright\raggedbottom
+\normalbaselineskip=9pt\baselineskip=9pt
+%
+\parindent=0pt
+\parskip=0pt
+\footline={\vbox to0pt{\hss}}
+%
+\def\ctl#1{{\tt C-#1}}
+\def\opt#1{{\brm[{\rm #1}]}}
+\def\xtra#1{\noalign{\smallskip{\tt#1}}}
+%
+\long\def\sec#1;#2\endsec{\vskip \secskip
+\halign{%
+%COL 1 (of halign):
+\vtop{\hsize=\itmwid\tt
+##\par\vskip \lskip }\hfil
+%COL 2 (of halign):
+&\vtop{\hsize=\dfnwid\hangafter=1\hangindent=\intersecwidth
+\rm ##\par\vskip \lskip}\cr
+%Tail of \long\def fills in halign body with \sec args:
+\noalign{{\bbf #1}\vskip \lskip}
+#2
+}
+}
+
+{\vbbf GDB QUICK REFERENCE}\hfil{\smrm GDB Version 4}\qquad
+
+\sec Essential Commands;
+gdb {\it program} \opt{{\it core}}&debug {\it program} \opt{using
+coredump {\it core}}\cr
+b \opt{\it file\tt:}{\it function}&set breakpoint at {\it function} \opt{in \it file}\cr
+run \opt{{\it arglist}}&start your program \opt{with {\it arglist}}\cr
+bt& backtrace: display program stack\cr
+p {\it expr}&display the value of an expression\cr
+c &continue running your program\cr
+n &next line, stepping over function calls\cr
+s &next line, stepping into function calls\cr
+\endsec
+
+\sec Starting GDB;
+gdb&start GDB, with no debugging files\cr
+gdb {\it program}&begin debugging {\it program}\cr
+gdb {\it program core}&debug coredump {\it core} produced by {\it
+program}\cr
+gdb --help&describe command line options\cr
+\endsec
+
+\sec Stopping GDB;
+quit&exit GDB; also {\tt q} or {\tt EOF} (eg \ctl{d})\cr
+INTERRUPT&(eg \ctl{c}) terminate current command, or send to running process\cr
+\endsec
+
+\sec Getting Help;
+help&list classes of commands\cr
+help {\it class}&one-line descriptions for commands in {\it class}\cr
+help {\it command}&describe {\it command}\cr
+\endsec
+
+\sec Executing your Program;
+run {\it arglist}&start your program with {\it arglist}\cr
+run&start your program with current argument list\cr
+run $\ldots$ <{\it inf} >{\it outf}&start your program with input, output
+redirected\cr
+\cr
+kill&kill running program\cr
+\cr
+tty {\it dev}&use {\it dev} as stdin and stdout for next {\tt run}\cr
+set args {\it arglist}&specify {\it arglist} for next
+{\tt run}\cr
+set args&specify empty argument list\cr
+show args&display argument list\cr
+\cr
+show environment&show all environment variables\cr
+show env {\it var}&show value of environment variable {\it var}\cr
+set env {\it var} {\it string}&set environment variable {\it var}\cr
+unset env {\it var}&remove {\it var} from environment\cr
+\endsec
+
+\sec Shell Commands;
+cd {\it dir}&change working directory to {\it dir}\cr
+pwd&Print working directory\cr
+make $\ldots$&call ``{\tt make}''\cr
+shell {\it cmd}&execute arbitrary shell command string\cr
+\endsec
+
+\vfill
+\line{\smrm \opt{ } surround optional arguments \hfill $\ldots$ show
+one or more arguments}
+\vskip\baselineskip
+\centerline{\smrm \copyright 1991, 1992 Free Software Foundation, Inc.\qquad Permissions on back}
+\eject
+\sec Breakpoints and Watchpoints;
+break \opt{\it file\tt:}{\it line}\par
+b \opt{\it file\tt:}{\it line}&set breakpoint at {\it line} number \opt{in \it file}\par
+eg:\quad{\tt break main.c:37}\quad\cr
+break \opt{\it file\tt:}{\it func}&set breakpoint at {\it
+func} \opt{in \it file}\cr
+break +{\it offset}\par
+break -{\it offset}&set break at {\it offset} lines from current stop\cr
+break *{\it addr}&set breakpoint at address {\it addr}\cr
+break&set breakpoint at next instruction\cr
+break $\ldots$ if {\it expr}&break conditionally on nonzero {\it expr}\cr
+cond {\it n} \opt{\it expr}&new conditional expression on breakpoint
+{\it n}; make unconditional if no {\it expr}\cr
+tbreak $\ldots$&temporary break; disable when reached\cr
+rbreak {\it regex}&break on all functions matching {\it regex}\cr
+watch {\it expr}&set a watchpoint for expression {\it expr}\cr
+catch {\it x}&break at C++ handler for exception {\it x}\cr
+\cr
+info break&show defined breakpoints\cr
+info watch&show defined watchpoints\cr
+\cr
+clear&delete breakpoints at next instruction\cr
+clear \opt{\it file\tt:}{\it fun}&delete breakpoints at entry to {\it fun}()\cr
+clear \opt{\it file\tt:}{\it line}&delete breakpoints on source line \cr
+delete \opt{{\it n}}&delete breakpoints
+\opt{or breakpoint {\it n}}\cr
+\cr
+disable \opt{{\it n}}&disable breakpoints
+\opt{or breakpoint {\it n}}
+\cr
+enable \opt{{\it n}}&enable breakpoints
+\opt{or breakpoint {\it n}}
+\cr
+enable once \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}};
+disable again when reached
+\cr
+enable del \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}};
+delete when reached
+\cr
+\cr
+ignore {\it n} {\it count}&ignore breakpoint {\it n}, {\it count}
+times\cr
+\cr
+commands {\it n}\par
+\qquad \opt{\tt silent}\par
+\qquad {\it command-list}&execute GDB {\it command-list} every time breakpoint {\it n} is reached. \opt{{\tt silent} suppresses default
+display}\cr
+end&end of {\it command-list}\cr
+\endsec
+
+\sec Program Stack;
+backtrace \opt{\it n}\par
+bt \opt{\it n}&print trace of all frames in stack; or of {\it n}
+frames---innermost if {\it n}{\tt >0}, outermost if {\it n}{\tt <0}\cr
+frame \opt{\it n}&select frame number {\it n} or frame at address {\it
+n}; if no {\it n}, display current frame\cr
+up {\it n}&select frame {\it n} frames up\cr
+down {\it n}&select frame {\it n} frames down\cr
+info frame \opt{\it addr}&describe selected frame, or frame at
+{\it addr}\cr
+info args&arguments of selected frame\cr
+info locals&local variables of selected frame\cr
+info reg \opt{\it rn}$\ldots$\par
+info all-reg \opt{\it rn}&register values \opt{for regs {\it rn\/}} in
+selected frame; {\tt all-reg} includes floating point\cr
+info catch&exception handlers active in selected frame\cr
+\endsec
+
+\vfill\eject
+\sec Execution Control;
+continue \opt{\it count}\par
+c \opt{\it count}&continue running; if {\it count} specified, ignore
+this breakpoint next {\it count} times\cr
+\cr
+step \opt{\it count}\par
+s \opt{\it count}&execute until another line reached; repeat {\it count} times if
+specified\cr
+stepi \opt{\it count}\par
+si \opt{\it count}&step by machine instructions rather than source
+lines\cr
+\cr
+next \opt{\it count}\par
+n \opt{\it count}&execute next line, including any function calls\cr
+nexti \opt{\it count}\par
+ni \opt{\it count}&next machine instruction rather than source
+line\cr
+\cr
+until \opt{\it location}&run until next instruction (or {\it
+location})\cr
+finish&run until selected stack frame returns\cr
+return \opt{\it expr}&pop selected stack frame without executing
+\opt{setting return value}\cr
+signal {\it num}&resume execution with signal {\it s} (none if {\tt 0})\cr
+jump {\it line}\par
+jump *{\it address}&resume execution at specified {\it line} number or
+{\it address}\cr
+set var={\it expr}&evaluate {\it expr} without displaying it; use for
+altering program variables\cr
+\endsec
+
+\sec Display;
+print \opt{\tt/{\it f}\/} \opt{\it expr}\par
+p \opt{\tt/{\it f}\/} \opt{\it expr}&show value of {\it expr} \opt{or
+last value \tt \$} according to format {\it f}:\cr
+\qquad x&hexadecimal\cr
+\qquad d&signed decimal\cr
+\qquad u&unsigned decimal\cr
+\qquad o&octal\cr
+\qquad t&binary\cr
+\qquad a&address, absolute and relative\cr
+\qquad c&character\cr
+\qquad f&floating point\cr
+call \opt{\tt /{\it f}\/} {\it expr}&like {\tt print} but does not display
+{\tt void}\cr
+x \opt{\tt/{\it Nuf}\/} {\it expr}&examine memory at address {\it expr};
+optional format spec follows slash\cr
+\quad {\it N}&count of how many units to display\cr
+\quad {\it u}&unit size; one of\cr
+&{\tt\qquad b}\ individual bytes\cr
+&{\tt\qquad h}\ halfwords (two bytes)\cr
+&{\tt\qquad w}\ words (four bytes)\cr
+&{\tt\qquad g}\ giant words (eight bytes)\cr
+\quad {\it f}&printing format. Any {\tt print} format, or\cr
+&{\tt\qquad s}\ null-terminated string\cr
+&{\tt\qquad i}\ machine instructions\cr
+disassem \opt{\it addr}&display memory as machine instructions\cr
+\endsec
+
+\sec Automatic Display;
+display \opt{\tt/\it f\/} {\it expr}&show value of {\it expr} each time
+program stops \opt{according to format {\it f}\/}\cr
+display&display all enabled expressions on list\cr
+undisplay {\it n}&remove number(s) {\it n} from list of
+automatically displayed expressions\cr
+disable disp {\it n}&disable display for expression(s) number {\it
+n}\cr
+enable disp {\it n}&enable display for expression(s) number {\it
+n}\cr
+info display&numbered list of display expressions\cr
+\endsec
+
+\vfill\eject
+
+\sec Expressions;
+{\it expr}&an expression in C, C++, or Modula-2 (including function calls), or:\cr
+{\it addr\/}@{\it len}&an array of {\it len} elements beginning at {\it
+addr}\cr
+{\it file}::{\it nm}&a variable or function {\it nm} defined in {\it
+file}\cr
+$\tt\{${\it type}$\tt\}${\it addr}&read memory at {\it addr} as specified
+{\it type}\cr
+\$&most recent displayed value\cr
+\${\it n}&{\it n}th displayed value\cr
+\$\$&displayed value previous to \$\cr
+\$\${\it n}&{\it n}th displayed value back from \$\cr
+\$\_&last address examined with {\tt x}\cr
+\$\_\_&value at address \$\_\cr
+\${\it var}&convenience variable; assign any value\cr
+\cr
+show values \opt{{\it n}}&show last 10 values \opt{or surrounding
+\${\it n}}\cr
+show convenience&display all convenience variables\cr
+\endsec
+
+\sec Symbol Table;
+info address {\it s}&show where symbol {\it s} is stored\cr
+info func \opt{\it regex}&show names, types of defined functions
+(all, or matching {\it regex})\cr
+info var \opt{\it regex}&show names, types of global variables (all,
+or matching {\it regex})\cr
+whatis \opt{\it expr}\par
+ptype \opt{\it expr}&show data type of {\it expr} \opt{or \tt \$}
+without evaluating; {\tt ptype} gives more detail\cr
+ptype {\it type}&describe type, struct, union, or enum\cr
+\endsec
+
+\sec GDB Scripts;
+source {\it script}&read, execute GDB commands from file {\it
+script}\cr
+\cr
+define {\it cmd}\par
+\qquad {\it command-list}&create new GDB command {\it cmd};
+execute script defined by {\it command-list}\cr
+end&end of {\it command-list}\cr
+document {\it cmd}\par
+\qquad {\it help-text}&create online documentation
+for new GDB command {\it cmd}\cr
+end&end of {\it help-text}\cr
+\endsec
+
+\sec Signals;
+handle {\it signal} {\it act}&specify GDB actions for {\it signal}:\cr
+\quad print&announce signal\cr
+\quad noprint&be silent for signal\cr
+\quad stop&halt execution on signal\cr
+\quad nostop&do not halt execution\cr
+\quad pass&allow your program to handle signal\cr
+\quad nopass&do not allow your program to see signal\cr
+info signals&show table of signals, GDB action for each\cr
+\endsec
+
+\sec Debugging Targets;
+target {\it type} {\it param}&connect to target machine, process, or file\cr
+help target&display available targets\cr
+attach {\it param}&connect to another process\cr
+detach&release target from GDB control\cr
+\endsec
+
+\vfill\eject
+\sec Controlling GDB;
+set {\it param} {\it value}&set one of GDB's internal parameters\cr
+show {\it param}&display current setting of parameter\cr
+\xtra{\rm Parameters understood by {\tt set} and {\tt show}:}
+\quad complaints {\it limit}&number of messages on unusual symbols\cr
+\quad confirm {\it on/off}&enable or disable cautionary queries\cr
+\quad editing {\it on/off}&control {\tt readline} command-line editing\cr
+\quad height {\it lpp}&number of lines before pause in display\cr
+\quad language {\it lang}&Language for GDB expressions ({\tt auto}, {\tt c} or
+{\tt modula-2})\cr
+\quad listsize {\it n}&number of lines shown by {\tt list}\cr
+\quad prompt {\it str}&use {\it str} as GDB prompt\cr
+\quad radix {\it base}&octal, decimal, or hex number representation\cr
+\quad verbose {\it on/off}&control messages when loading
+symbols\cr
+\quad width {\it cpl}&number of characters before line folded\cr
+\quad write {\it on/off}&Allow or forbid patching binary, core files
+(when reopened with {\tt exec} or {\tt core})
+\cr
+\quad history $\ldots$\par
+\quad h $\ldots$&groups with the following options:\cr
+\quad h exp {\it off/on}&disable/enable {\tt readline} history expansion\cr
+\quad h file {\it filename}&file for recording GDB command history\cr
+\quad h size {\it size}&number of commands kept in history list\cr
+\quad h save {\it off/on}&control use of external file for
+command history\cr
+\cr
+\quad print $\ldots$\par
+\quad p $\ldots$&groups with the following options:\cr
+\quad p address {\it on/off}&print memory addresses in stacks,
+values\cr
+\quad p array {\it off/on}&compact or attractive format for
+arrays\cr
+\quad p demangl {\it on/off}&source (demangled) or internal form for C++
+symbols\cr
+\quad p asm-dem {\it on/off}&demangle C++ symbols in
+machine-instruction output\cr
+\quad p elements {\it limit}&number of array elements to display\cr
+\quad p object {\it on/off}&print C++ derived types for objects\cr
+\quad p pretty {\it off/on}&struct display: compact or indented\cr
+\quad p union {\it on/off}&display of union members\cr
+\quad p vtbl {\it off/on}&display of C++ virtual function
+tables\cr
+\cr
+show commands&show last 10 commands\cr
+show commands {\it n}&show 10 commands around number {\it n}\cr
+show commands +&show next 10 commands\cr
+\endsec
+
+\sec Working Files;
+file \opt{\it file}&use {\it file} for both symbols and executable;
+with no arg, discard both\cr
+core \opt{\it file}&read {\it file} as coredump; or discard\cr
+exec \opt{\it file}&use {\it file} as executable only; or discard\cr
+symbol \opt{\it file}&use symbol table from {\it file}; or discard\cr
+load {\it file}&dynamically link {\it file\/} and add its symbols\cr
+add-sym {\it file} {\it addr}&read additional symbols from {\it file},
+dynamically loaded at {\it addr}\cr
+info files&display working files and targets in use\cr
+path {\it dirs}&add {\it dirs} to front of path searched for
+executable and symbol files\cr
+show path&display executable and symbol file path\cr
+info share&list names of shared libraries currently loaded\cr
+\endsec
+
+\vfill\eject
+\sec Source Files;
+dir {\it names}&add directory {\it names} to front of source path\cr
+dir&clear source path\cr
+show dir&show current source path\cr
+\cr
+list&show next ten lines of source\cr
+list -&show previous ten lines\cr
+list {\it lines}&display source surrounding {\it lines},
+specified as:\cr
+\quad{\opt{\it file\tt:}\it num}&line number \opt{in named file}\cr
+\quad{\opt{\it file\tt:}\it function}&beginning of function \opt{in
+named file}\cr
+\quad{\tt +\it off}&{\it off} lines after last printed\cr
+\quad{\tt -\it off}&{\it off} lines previous to last printed\cr
+\quad{\tt*\it address}&line containing {\it address}\cr
+list {\it f},{\it l}&from line {\it f} to line {\it l}\cr
+info line {\it num}&show starting, ending addresses of compiled code for
+source line {\it num}\cr
+info source&show name of current source file\cr
+info sources&list all source files in use\cr
+forw {\it regex}&search following source lines for {\it regex}\cr
+rev {\it regex}&search preceding source lines for {\it regex}\cr
+\endsec
+
+\sec GDB under GNU Emacs;
+M-x gdb&run GDB under Emacs\cr
+\ctl{h} m&describe GDB mode\cr
+M-s&step one line ({\tt step})\cr
+M-n&next line ({\tt next})\cr
+M-i&step one instruction ({\tt stepi})\cr
+\ctl{c} \ctl{f}&finish current stack frame ({\tt finish})\cr
+M-c&continue ({\tt cont})\cr
+M-u&up {\it arg} frames ({\tt up})\cr
+M-d&down {\it arg} frames ({\tt down})\cr
+\ctl{x} \&&copy number from point, insert at end\cr
+\ctl{x} SPC&(in source file) set break at point\cr
+\endsec
+
+\sec GDB License;
+show copying&Display GNU General Public License\cr
+show warranty&There is NO WARRANTY for GDB. Display full no-warranty
+statement.\cr
+\endsec
+
+
+\vfill
+{\smrm\parskip=6pt
+\centerline{Copyright \copyright 1991, 1992, 1993 Free Software Foundation, Inc.}
+\centerline{Roland Pesch (pesch@cygnus.com)}
+\centerline{The author assumes no responsibility for any errors on this card.}
+
+This card may be freely distributed under the terms of the GNU
+General Public License.
+
+\centerline{Please contribute to development of this card by
+annotating it.}
+
+GDB itself is free software; you are welcome to distribute copies of
+it under the terms of the GNU General Public License. There is
+absolutely no warranty for GDB.
+}
+\end
diff --git a/gnu/usr.bin/gdb/doc/remote.texi b/gnu/usr.bin/gdb/doc/remote.texi
new file mode 100644
index 000000000000..5b7ec90e1e8b
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/remote.texi
@@ -0,0 +1,1294 @@
+@c -*- Texinfo -*-
+@c Copyright (c) 1990 1991 1992 1993 Free Software Foundation, Inc.
+@c This file is part of the source for the GDB manual.
+@c This text diverted to "Remote Debugging" section in general case;
+@c however, if we're doing a manual specifically for one of these, it
+@c belongs up front (in "Getting In and Out" chapter).
+
+@ifset REMOTESTUB
+@node Remote Serial
+@subsection The @value{GDBN} remote serial protocol
+
+@cindex remote serial debugging, overview
+To debug a program running on another machine (the debugging
+@dfn{target} machine), you must first arrange for all the usual
+prerequisites for the program to run by itself. For example, for a C
+program, you need
+
+@enumerate
+@item
+A startup routine to set up the C runtime environment; these usually
+have a name like @file{crt0}. The startup routine may be supplied by
+your hardware supplier, or you may have to write your own.
+
+@item
+You probably need a C subroutine library to support your program's
+subroutine calls, notably managing input and output.
+
+@item
+A way of getting your program to the other machine---for example, a
+download program. These are often supplied by the hardware
+manufacturer, but you may have to write your own from hardware
+documentation.
+@end enumerate
+
+The next step is to arrange for your program to use a serial port to
+communicate with the machine where @value{GDBN} is running (the @dfn{host}
+machine). In general terms, the scheme looks like this:
+
+@table @emph
+@item On the host,
+@value{GDBN} already understands how to use this protocol; when everything
+else is set up, you can simply use the @samp{target remote} command
+(@pxref{Targets,,Specifying a Debugging Target}).
+
+@item On the target,
+you must link with your program a few special-purpose subroutines that
+implement the @value{GDBN} remote serial protocol. The file containing these
+subroutines is called a @dfn{debugging stub}.
+
+@ifset GDBSERVER
+On certain remote targets, you can use an auxiliary program
+@code{gdbserver} instead of linking a stub into your program.
+@xref{Server,,Using the @code{gdbserver} program}, for details.
+@end ifset
+@end table
+
+The debugging stub is specific to the architecture of the remote
+machine; for example, use @file{sparc-stub.c} to debug programs on
+@sc{sparc} boards.
+
+@cindex remote serial stub list
+These working remote stubs are distributed with @value{GDBN}:
+
+@table @code
+@item sparc-stub.c
+@kindex sparc-stub.c
+For @sc{sparc} architectures.
+
+@item m68k-stub.c
+@kindex m68k-stub.c
+@cindex Motorola 680x0
+@cindex 680x0
+For Motorola 680x0 architectures.
+
+@item i386-stub.c
+@kindex i386-stub.c
+@cindex Intel
+@cindex 386
+For Intel 386 and compatible architectures.
+@end table
+
+The @file{README} file in the @value{GDBN} distribution may list other
+recently added stubs.
+
+@menu
+* Stub Contents:: What the stub can do for you
+* Bootstrapping:: What you must do for the stub
+* Debug Session:: Putting it all together
+* Protocol:: Outline of the communication protocol
+@ifset GDBSERVER
+* Server:: Using the `gdbserver' program
+@end ifset
+@end menu
+
+@node Stub Contents
+@subsubsection What the stub can do for you
+
+@cindex remote serial stub
+The debugging stub for your architecture supplies these three
+subroutines:
+
+@table @code
+@item set_debug_traps
+@kindex set_debug_traps
+@cindex remote serial stub, initialization
+This routine arranges for @code{handle_exception} to run when your
+program stops. You must call this subroutine explicitly near the
+beginning of your program.
+
+@item handle_exception
+@kindex handle_exception
+@cindex remote serial stub, main routine
+This is the central workhorse, but your program never calls it
+explicitly---the setup code arranges for @code{handle_exception} to
+run when a trap is triggered.
+
+@code{handle_exception} takes control when your program stops during
+execution (for example, on a breakpoint), and mediates communications
+with @value{GDBN} on the host machine. This is where the communications
+protocol is implemented; @code{handle_exception} acts as the @value{GDBN}
+representative on the target machine; it begins by sending summary
+information on the state of your program, then continues to execute,
+retrieving and transmitting any information @value{GDBN} needs, until you
+execute a @value{GDBN} command that makes your program resume; at that point,
+@code{handle_exception} returns control to your own code on the target
+machine.
+
+@item breakpoint
+@cindex @code{breakpoint} subroutine, remote
+Use this auxiliary subroutine to make your program contain a
+breakpoint. Depending on the particular situation, this may be the only
+way for @value{GDBN} to get control. For instance, if your target
+machine has some sort of interrupt button, you won't need to call this;
+pressing the interrupt button will transfer control to
+@code{handle_exception}---in effect, to @value{GDBN}. On some machines,
+simply receiving characters on the serial port may also trigger a trap;
+again, in that situation, you don't need to call @code{breakpoint} from
+your own program---simply running @samp{target remote} from the host
+@value{GDBN} session will get control.
+
+Call @code{breakpoint} if none of these is true, or if you simply want
+to make certain your program stops at a predetermined point for the
+start of your debugging session.
+@end table
+
+@node Bootstrapping
+@subsubsection What you must do for the stub
+
+@cindex remote stub, support routines
+The debugging stubs that come with @value{GDBN} are set up for a particular
+chip architecture, but they have no information about the rest of your
+debugging target machine. To allow the stub to work, you must supply
+these special low-level subroutines:
+
+@table @code
+@item int getDebugChar()
+@kindex getDebugChar
+Write this subroutine to read a single character from the serial port.
+It may be identical to @code{getchar} for your target system; a
+different name is used to allow you to distinguish the two if you wish.
+
+@item void putDebugChar(int)
+@kindex putDebugChar
+Write this subroutine to write a single character to the serial port.
+It may be identical to @code{putchar} for your target system; a
+different name is used to allow you to distinguish the two if you wish.
+
+@item void exceptionHandler (int @var{exception_number}, void *@var{exception_address})
+@kindex exceptionHandler
+Write this function to install @var{exception_address} in the exception
+handling tables. You need to do this because the stub does not have any
+way of knowing what the exception handling tables on your target system
+are like (for example, the processor's table might be in @sc{rom},
+containing entries which point to a table in @sc{ram}).
+@var{exception_number} is the exception number which should be changed;
+its meaning is architecture-dependent (for example, different numbers
+might represent divide by zero, misaligned access, etc). When this
+exception occurs, control should be transferred directly to
+@var{exception_address}, and the processor state (stack, registers,
+etc.) should be just as it is when a processor exception occurs. So if
+you want to use a jump instruction to reach @var{exception_address}, it
+should be a simple jump, not a jump to subroutine.
+
+For the 386, @var{exception_address} should be installed as an interrupt
+gate so that interrupts are masked while the handler runs. The gate
+should be at privilege level 0 (the most privileged level). The
+@sc{sparc} and 68k stubs are able to mask interrupts themself without
+help from @code{exceptionHandler}.
+
+@item void flush_i_cache()
+@kindex flush_i_cache
+Write this subroutine to flush the instruction cache, if any, on your
+target machine. If there is no instruction cache, this subroutine may
+be a no-op.
+
+On target machines that have instruction caches, @value{GDBN} requires this
+function to make certain that the state of your program is stable.
+@end table
+
+@noindent
+You must also make sure this library routine is available:
+
+@table @code
+@item void *memset(void *, int, int)
+@kindex memset
+This is the standard library function @code{memset} that sets an area of
+memory to a known value. If you have one of the free versions of
+@code{libc.a}, @code{memset} can be found there; otherwise, you must
+either obtain it from your hardware manufacturer, or write your own.
+@end table
+
+If you do not use the GNU C compiler, you may need other standard
+library subroutines as well; this will vary from one stub to another,
+but in general the stubs are likely to use any of the common library
+subroutines which @code{gcc} generates as inline code.
+
+
+@node Debug Session
+@subsubsection Putting it all together
+
+@cindex remote serial debugging summary
+In summary, when your program is ready to debug, you must follow these
+steps.
+
+@enumerate
+@item
+Make sure you have the supporting low-level routines
+(@pxref{Bootstrapping,,What you must do for the stub}):
+@display
+@code{getDebugChar}, @code{putDebugChar},
+@code{flush_i_cache}, @code{memset}, @code{exceptionHandler}.
+@end display
+
+@item
+Insert these lines near the top of your program:
+
+@example
+set_debug_traps();
+breakpoint();
+@end example
+
+@item
+For the 680x0 stub only, you need to provide a variable called
+@code{exceptionHook}. Normally you just use
+
+@example
+void (*exceptionHook)() = 0;
+@end example
+
+but if before calling @code{set_debug_traps}, you set it to point to a
+function in your program, that function is called when
+@code{@value{GDBN}} continues after stopping on a trap (for example, bus
+error). The function indicated by @code{exceptionHook} is called with
+one parameter: an @code{int} which is the exception number.
+
+@item
+Compile and link together: your program, the @value{GDBN} debugging stub for
+your target architecture, and the supporting subroutines.
+
+@item
+Make sure you have a serial connection between your target machine and
+the @value{GDBN} host, and identify the serial port used for this on the host.
+
+@item
+@c The "remote" target now provides a `load' command, so we should
+@c document that. FIXME.
+Download your program to your target machine (or get it there by
+whatever means the manufacturer provides), and start it.
+
+@item
+To start remote debugging, run @value{GDBN} on the host machine, and specify
+as an executable file the program that is running in the remote machine.
+This tells @value{GDBN} how to find your program's symbols and the contents
+of its pure text.
+
+@cindex serial line, @code{target remote}
+Then establish communication using the @code{target remote} command.
+Its argument specifies how to communicate with the target
+machine---either via a devicename attached to a direct serial line, or a
+TCP port (usually to a terminal server which in turn has a serial line
+to the target). For example, to use a serial line connected to the
+device named @file{/dev/ttyb}:
+
+@example
+target remote /dev/ttyb
+@end example
+
+@cindex TCP port, @code{target remote}
+To use a TCP connection, use an argument of the form
+@code{@var{host}:port}. For example, to connect to port 2828 on a
+terminal server named @code{manyfarms}:
+
+@example
+target remote manyfarms:2828
+@end example
+@end enumerate
+
+Now you can use all the usual commands to examine and change data and to
+step and continue the remote program.
+
+To resume the remote program and stop debugging it, use the @code{detach}
+command.
+
+@cindex interrupting remote programs
+@cindex remote programs, interrupting
+Whenever @value{GDBN} is waiting for the remote program, if you type the
+interrupt character (often @key{C-C}), @value{GDBN} attempts to stop the
+program. This may or may not succeed, depending in part on the hardware
+and the serial drivers the remote system uses. If you type the
+interrupt character once again, @value{GDBN} displays this prompt:
+
+@example
+Interrupted while waiting for the program.
+Give up (and stop debugging it)? (y or n)
+@end example
+
+If you type @kbd{y}, @value{GDBN} abandons the remote debugging session.
+(If you decide you want to try again later, you can use @samp{target
+remote} again to connect once more.) If you type @kbd{n}, @value{GDBN}
+goes back to waiting.
+
+@node Protocol
+@subsubsection Outline of the communication protocol
+
+@cindex debugging stub, example
+@cindex remote stub, example
+@cindex stub example, remote debugging
+The stub files provided with @value{GDBN} implement the target side of the
+communication protocol, and the @value{GDBN} side is implemented in the
+@value{GDBN} source file @file{remote.c}. Normally, you can simply allow
+these subroutines to communicate, and ignore the details. (If you're
+implementing your own stub file, you can still ignore the details: start
+with one of the existing stub files. @file{sparc-stub.c} is the best
+organized, and therefore the easiest to read.)
+
+However, there may be occasions when you need to know something about
+the protocol---for example, if there is only one serial port to your
+target machine, you might want your program to do something special if
+it recognizes a packet meant for @value{GDBN}.
+
+@cindex protocol, @value{GDBN} remote serial
+@cindex serial protocol, @value{GDBN} remote
+@cindex remote serial protocol
+All @value{GDBN} commands and responses (other than acknowledgements, which
+are single characters) are sent as a packet which includes a
+checksum. A packet is introduced with the character @samp{$}, and ends
+with the character @samp{#} followed by a two-digit checksum:
+
+@example
+$@var{packet info}#@var{checksum}
+@end example
+
+@cindex checksum, for @value{GDBN} remote
+@noindent
+@var{checksum} is computed as the modulo 256 sum of the @var{packet
+info} characters.
+
+When either the host or the target machine receives a packet, the first
+response expected is an acknowledgement: a single character, either
+@samp{+} (to indicate the package was received correctly) or @samp{-}
+(to request retransmission).
+
+The host (@value{GDBN}) sends commands, and the target (the debugging stub
+incorporated in your program) sends data in response. The target also
+sends data when your program stops.
+
+Command packets are distinguished by their first character, which
+identifies the kind of command.
+
+These are the commands currently supported:
+
+@table @code
+@item g
+Requests the values of CPU registers.
+
+@item G
+Sets the values of CPU registers.
+
+@item m@var{addr},@var{count}
+Read @var{count} bytes at location @var{addr}.
+
+@item M@var{addr},@var{count}:@dots{}
+Write @var{count} bytes at location @var{addr}.
+
+@item c
+@itemx c@var{addr}
+Resume execution at the current address (or at @var{addr} if supplied).
+
+@item s
+@itemx s@var{addr}
+Step the target program for one instruction, from either the current
+program counter or from @var{addr} if supplied.
+
+@item k
+Kill the target program.
+
+@item ?
+Report the most recent signal. To allow you to take advantage of the
+@value{GDBN} signal handling commands, one of the functions of the debugging
+stub is to report CPU traps as the corresponding POSIX signal values.
+@end table
+
+@kindex set remotedebug
+@kindex show remotedebug
+@cindex packets, reporting on stdout
+@cindex serial connections, debugging
+If you have trouble with the serial connection, you can use the command
+@code{set remotedebug}. This makes @value{GDBN} report on all packets sent
+back and forth across the serial line to the remote machine. The
+packet-debugging information is printed on the @value{GDBN} standard output
+stream. @code{set remotedebug off} turns it off, and @code{show
+remotedebug} will show you its current state.
+
+@ifset GDBSERVER
+@node Server
+@subsubsection Using the @code{gdbserver} program
+
+@kindex gdbserver
+@cindex remote connection without stubs
+@code{gdbserver} is a control program for Unix-like systems, which
+allows you to connect your program with a remote @value{GDBN} via
+@code{target remote}---but without linking in the usual debugging stub.
+
+@code{gdbserver} is not a complete replacement for the debugging stubs,
+because it requires essentially the same operating-system facilities
+that @value{GDBN} itself does. In fact, a system that can run
+@code{gdbserver} to connect to a remote @value{GDBN} could also run
+@var{GDBN} locally! @code{gdbserver} is sometimes useful nevertheless,
+because it is a much smaller program than @value{GDBN} itself. It is
+also easier to port than all of @var{GDBN}, so you may be able to get
+started more quickly on a new system by using @code{gdbserver}.
+
+@value{GDBN} and @code{gdbserver} communicate via either a serial line
+or a TCP connection, using the standard @value{GDBN} remote serial
+protocol.
+
+@table @emph
+@item On the target,
+you need to have a copy of the program you want to debug.
+@code{gdbserver} does not need your program's symbol table, so you can
+strip the program if necessary to save space. @value{GDBN} on the host
+system does all the symbol handling.
+
+To use the server, you must tell it how to communicate with @value{GDB};
+the name of your program; and the arguments for your program. The
+syntax is:
+
+@smallexample
+target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ]
+@end smallexample
+
+@var{comm} is either a device name (to use a serial line) or a TCP
+hostname and portnumber. For example, to debug emacs with the argument
+@samp{foo.txt} and communicate with @value{GDBN} over the serial port
+@file{/dev/com1}:
+
+@smallexample
+target> gdbserver /dev/com1 emacs foo.txt
+@end smallexample
+
+@code{gdbserver} waits passively for the host @value{GDBN} to communicate
+with it.
+
+To use a TCP connection instead of a serial line:
+
+@smallexample
+target> gdbserver host:2345 emacs foo.txt
+@end smallexample
+
+The only difference from the previous example is the first argument,
+specifying that you are communicating with the host @value{GDBN} via
+TCP. The @samp{host:2345} argument means that @code{gdbserver} is to
+expect a TCP connection from machine @samp{host} to local TCP port 2345.
+(Currently, the @samp{host} part is ignored.) You can choose any number
+you want for the port number as long as it does not conflict with any
+TCP ports already in use on the target system.@footnote{If you choose a
+port number that conflicts with another service, @code{gdbserver} prints
+an error message and exits.} You must use the same port number with the
+host @value{GDBN} @code{target remote} command.
+
+@item On the host,
+you need an unstripped copy of your program, since
+@value{GDBN} needs symbols and debugging information. Start up
+@value{GDBN} as usual, using the name of the local copy of your program
+as the first argument. (You may also need the
+@samp{--baud} option if the serial line is running at anything other than 9600 bps.)
+After that, use @code{target remote} to establish communications with @code{gdbserver}. Its argument is either
+a device name (usually a serial device, like @file{/dev/ttyb}), or a TCP
+port descriptof in the form @code{@var{host}:@var{PORT}}. For example:
+
+@smallexample
+(@value{GDBP}) target remote /dev/ttyb
+@end smallexample
+
+@noindent
+communicates with the server via serial line @file{/dev/ttyb}, and
+
+@smallexample
+(@value{GDBP}) target remote the-target:2345
+@end smallexample
+
+@noindent
+communicates via a TCP connection to port 2345 on host @file{the-target}.
+For TCP connections, you must start up @code{gdbserver} prior to using
+the @code{target remote} command. Otherwise you may get an error whose
+text depends on the host system, but which usually looks something like
+@samp{Connection refused}.
+@end table
+@end ifset
+
+@end ifset
+
+@ifset I960
+@node i960-Nindy Remote
+@subsection @value{GDBN} with a remote i960 (Nindy)
+
+@cindex Nindy
+@cindex i960
+@dfn{Nindy} is a ROM Monitor program for Intel 960 target systems. When
+@value{GDBN} is configured to control a remote Intel 960 using Nindy, you can
+tell @value{GDBN} how to connect to the 960 in several ways:
+
+@itemize @bullet
+@item
+Through command line options specifying serial port, version of the
+Nindy protocol, and communications speed;
+
+@item
+By responding to a prompt on startup;
+
+@item
+By using the @code{target} command at any point during your @value{GDBN}
+session. @xref{Target Commands, ,Commands for managing targets}.
+
+@end itemize
+
+@menu
+* Nindy Startup:: Startup with Nindy
+* Nindy Options:: Options for Nindy
+* Nindy Reset:: Nindy reset command
+@end menu
+
+@node Nindy Startup
+@subsubsection Startup with Nindy
+
+If you simply start @code{@value{GDBP}} without using any command-line
+options, you are prompted for what serial port to use, @emph{before} you
+reach the ordinary @value{GDBN} prompt:
+
+@example
+Attach /dev/ttyNN -- specify NN, or "quit" to quit:
+@end example
+
+@noindent
+Respond to the prompt with whatever suffix (after @samp{/dev/tty})
+identifies the serial port you want to use. You can, if you choose,
+simply start up with no Nindy connection by responding to the prompt
+with an empty line. If you do this and later wish to attach to Nindy,
+use @code{target} (@pxref{Target Commands, ,Commands for managing targets}).
+
+@node Nindy Options
+@subsubsection Options for Nindy
+
+These are the startup options for beginning your @value{GDBN} session with a
+Nindy-960 board attached:
+
+@table @code
+@item -r @var{port}
+Specify the serial port name of a serial interface to be used to connect
+to the target system. This option is only available when @value{GDBN} is
+configured for the Intel 960 target architecture. You may specify
+@var{port} as any of: a full pathname (e.g. @samp{-r /dev/ttya}), a
+device name in @file{/dev} (e.g. @samp{-r ttya}), or simply the unique
+suffix for a specific @code{tty} (e.g. @samp{-r a}).
+
+@item -O
+(An uppercase letter ``O'', not a zero.) Specify that @value{GDBN} should use
+the ``old'' Nindy monitor protocol to connect to the target system.
+This option is only available when @value{GDBN} is configured for the Intel 960
+target architecture.
+
+@quotation
+@emph{Warning:} if you specify @samp{-O}, but are actually trying to
+connect to a target system that expects the newer protocol, the connection
+fails, appearing to be a speed mismatch. @value{GDBN} repeatedly
+attempts to reconnect at several different line speeds. You can abort
+this process with an interrupt.
+@end quotation
+
+@item -brk
+Specify that @value{GDBN} should first send a @code{BREAK} signal to the target
+system, in an attempt to reset it, before connecting to a Nindy target.
+
+@quotation
+@emph{Warning:} Many target systems do not have the hardware that this
+requires; it only works with a few boards.
+@end quotation
+@end table
+
+The standard @samp{-b} option controls the line speed used on the serial
+port.
+
+@c @group
+@node Nindy Reset
+@subsubsection Nindy reset command
+
+@table @code
+@item reset
+@kindex reset
+For a Nindy target, this command sends a ``break'' to the remote target
+system; this is only useful if the target has been equipped with a
+circuit to perform a hard reset (or some other interesting action) when
+a break is detected.
+@end table
+@c @end group
+@end ifset
+
+@ifset AMD29K
+@node UDI29K Remote
+@subsection @value{GDBN} and the UDI protocol for AMD29K
+
+@cindex UDI
+@cindex AMD29K via UDI
+@value{GDBN} supports AMD's UDI (``Universal Debugger Interface'')
+protocol for debugging the a29k processor family. To use this
+configuration with AMD targets running the MiniMON monitor, you need the
+program @code{MONTIP}, available from AMD at no charge. You can also
+use @value{GDBN} with the UDI conformant a29k simulator program
+@code{ISSTIP}, also available from AMD.
+
+@table @code
+@item target udi @var{keyword}
+@kindex udi
+Select the UDI interface to a remote a29k board or simulator, where
+@var{keyword} is an entry in the AMD configuration file @file{udi_soc}.
+This file contains keyword entries which specify parameters used to
+connect to a29k targets. If the @file{udi_soc} file is not in your
+working directory, you must set the environment variable @samp{UDICONF}
+to its pathname.
+@end table
+
+@node EB29K Remote
+@subsection @value{GDBN} and the EBMON protocol for AMD29K
+
+@cindex EB29K board
+@cindex running 29K programs
+
+AMD distributes a 29K development board meant to fit in a PC, together
+with a DOS-hosted monitor program called @code{EBMON}. As a shorthand
+term, this development system is called the ``EB29K''. To use
+@value{GDBN} from a Unix system to run programs on the EB29K board, you
+must first connect a serial cable between the PC (which hosts the EB29K
+board) and a serial port on the Unix system. In the following, we
+assume you've hooked the cable between the PC's @file{COM1} port and
+@file{/dev/ttya} on the Unix system.
+
+@menu
+* Comms (EB29K):: Communications setup
+* gdb-EB29K:: EB29K cross-debugging
+* Remote Log:: Remote log
+@end menu
+
+@node Comms (EB29K)
+@subsubsection Communications setup
+
+The next step is to set up the PC's port, by doing something like this
+in DOS on the PC:
+
+@example
+C:\> MODE com1:9600,n,8,1,none
+@end example
+
+@noindent
+This example---run on an MS DOS 4.0 system---sets the PC port to 9600
+bps, no parity, eight data bits, one stop bit, and no ``retry'' action;
+you must match the communications parameters when establishing the Unix
+end of the connection as well.
+@c FIXME: Who knows what this "no retry action" crud from the DOS manual may
+@c mean? It's optional; leave it out? ---pesch@cygnus.com, 25feb91
+
+To give control of the PC to the Unix side of the serial line, type
+the following at the DOS console:
+
+@example
+C:\> CTTY com1
+@end example
+
+@noindent
+(Later, if you wish to return control to the DOS console, you can use
+the command @code{CTTY con}---but you must send it over the device that
+had control, in our example over the @file{COM1} serial line).
+
+From the Unix host, use a communications program such as @code{tip} or
+@code{cu} to communicate with the PC; for example,
+
+@example
+cu -s 9600 -l /dev/ttya
+@end example
+
+@noindent
+The @code{cu} options shown specify, respectively, the linespeed and the
+serial port to use. If you use @code{tip} instead, your command line
+may look something like the following:
+
+@example
+tip -9600 /dev/ttya
+@end example
+
+@noindent
+Your system may require a different name where we show
+@file{/dev/ttya} as the argument to @code{tip}. The communications
+parameters, including which port to use, are associated with the
+@code{tip} argument in the ``remote'' descriptions file---normally the
+system table @file{/etc/remote}.
+@c FIXME: What if anything needs doing to match the "n,8,1,none" part of
+@c the DOS side's comms setup? cu can support -o (odd
+@c parity), -e (even parity)---apparently no settings for no parity or
+@c for character size. Taken from stty maybe...? John points out tip
+@c can set these as internal variables, eg ~s parity=none; man stty
+@c suggests that it *might* work to stty these options with stdin or
+@c stdout redirected... ---pesch@cygnus.com, 25feb91
+
+@kindex EBMON
+Using the @code{tip} or @code{cu} connection, change the DOS working
+directory to the directory containing a copy of your 29K program, then
+start the PC program @code{EBMON} (an EB29K control program supplied
+with your board by AMD). You should see an initial display from
+@code{EBMON} similar to the one that follows, ending with the
+@code{EBMON} prompt @samp{#}---
+
+@example
+C:\> G:
+
+G:\> CD \usr\joe\work29k
+
+G:\USR\JOE\WORK29K> EBMON
+Am29000 PC Coprocessor Board Monitor, version 3.0-18
+Copyright 1990 Advanced Micro Devices, Inc.
+Written by Gibbons and Associates, Inc.
+
+Enter '?' or 'H' for help
+
+PC Coprocessor Type = EB29K
+I/O Base = 0x208
+Memory Base = 0xd0000
+
+Data Memory Size = 2048KB
+Available I-RAM Range = 0x8000 to 0x1fffff
+Available D-RAM Range = 0x80002000 to 0x801fffff
+
+PageSize = 0x400
+Register Stack Size = 0x800
+Memory Stack Size = 0x1800
+
+CPU PRL = 0x3
+Am29027 Available = No
+Byte Write Available = Yes
+
+# ~.
+@end example
+
+Then exit the @code{cu} or @code{tip} program (done in the example by
+typing @code{~.} at the @code{EBMON} prompt). @code{EBMON} will keep
+running, ready for @value{GDBN} to take over.
+
+For this example, we've assumed what is probably the most convenient
+way to make sure the same 29K program is on both the PC and the Unix
+system: a PC/NFS connection that establishes ``drive @code{G:}'' on the
+PC as a file system on the Unix host. If you do not have PC/NFS or
+something similar connecting the two systems, you must arrange some
+other way---perhaps floppy-disk transfer---of getting the 29K program
+from the Unix system to the PC; @value{GDBN} will @emph{not} download it over the
+serial line.
+
+@node gdb-EB29K
+@subsubsection EB29K cross-debugging
+
+Finally, @code{cd} to the directory containing an image of your 29K
+program on the Unix system, and start @value{GDBN}---specifying as argument the
+name of your 29K program:
+
+@example
+cd /usr/joe/work29k
+@value{GDBP} myfoo
+@end example
+
+Now you can use the @code{target} command:
+
+@example
+target amd-eb /dev/ttya 9600 MYFOO
+@c FIXME: test above 'target amd-eb' as spelled, with caps! caps are meant to
+@c emphasize that this is the name as seen by DOS (since I think DOS is
+@c single-minded about case of letters). ---pesch@cygnus.com, 25feb91
+@end example
+
+@noindent
+In this example, we've assumed your program is in a file called
+@file{myfoo}. Note that the filename given as the last argument to
+@code{target amd-eb} should be the name of the program as it appears to DOS.
+In our example this is simply @code{MYFOO}, but in general it can include
+a DOS path, and depending on your transfer mechanism may not resemble
+the name on the Unix side.
+
+At this point, you can set any breakpoints you wish; when you are ready
+to see your program run on the 29K board, use the @value{GDBN} command
+@code{run}.
+
+To stop debugging the remote program, use the @value{GDBN} @code{detach}
+command.
+
+To return control of the PC to its console, use @code{tip} or @code{cu}
+once again, after your @value{GDBN} session has concluded, to attach to
+@code{EBMON}. You can then type the command @code{q} to shut down
+@code{EBMON}, returning control to the DOS command-line interpreter.
+Type @code{CTTY con} to return command input to the main DOS console,
+and type @kbd{~.} to leave @code{tip} or @code{cu}.
+
+@node Remote Log
+@subsubsection Remote log
+@kindex eb.log
+@cindex log file for EB29K
+
+The @code{target amd-eb} command creates a file @file{eb.log} in the
+current working directory, to help debug problems with the connection.
+@file{eb.log} records all the output from @code{EBMON}, including echoes
+of the commands sent to it. Running @samp{tail -f} on this file in
+another window often helps to understand trouble with @code{EBMON}, or
+unexpected events on the PC side of the connection.
+
+@end ifset
+
+@ifset ST2000
+@node ST2000 Remote
+@subsection @value{GDBN} with a Tandem ST2000
+
+To connect your ST2000 to the host system, see the manufacturer's
+manual. Once the ST2000 is physically attached, you can run
+
+@example
+target st2000 @var{dev} @var{speed}
+@end example
+
+@noindent
+to establish it as your debugging environment. @var{dev} is normally
+the name of a serial device, such as @file{/dev/ttya}, connected to the
+ST2000 via a serial line. You can instead specify @var{dev} as a TCP
+connection (for example, to a serial line attached via a terminal
+concentrator) using the syntax @code{@var{hostname}:@var{portnumber}}.
+
+The @code{load} and @code{attach} commands are @emph{not} defined for
+this target; you must load your program into the ST2000 as you normally
+would for standalone operation. @value{GDBN} will read debugging information
+(such as symbols) from a separate, debugging version of the program
+available on your host computer.
+@c FIXME!! This is terribly vague; what little content is here is
+@c basically hearsay.
+
+@cindex ST2000 auxiliary commands
+These auxiliary @value{GDBN} commands are available to help you with the ST2000
+environment:
+
+@table @code
+@item st2000 @var{command}
+@kindex st2000 @var{cmd}
+@cindex STDBUG commands (ST2000)
+@cindex commands to STDBUG (ST2000)
+Send a @var{command} to the STDBUG monitor. See the manufacturer's
+manual for available commands.
+
+@item connect
+@cindex connect (to STDBUG)
+Connect the controlling terminal to the STDBUG command monitor. When
+you are done interacting with STDBUG, typing either of two character
+sequences will get you back to the @value{GDBN} command prompt:
+@kbd{@key{RET}~.} (Return, followed by tilde and period) or
+@kbd{@key{RET}~@key{C-d}} (Return, followed by tilde and control-D).
+@end table
+@end ifset
+
+@ifset VXWORKS
+@node VxWorks Remote
+@subsection @value{GDBN} and VxWorks
+@cindex VxWorks
+
+@value{GDBN} enables developers to spawn and debug tasks running on networked
+VxWorks targets from a Unix host. Already-running tasks spawned from
+the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on
+both the Unix host and on the VxWorks target. The program
+@code{gdb} is installed and executed on the Unix host. (It may be
+installed with the name @code{vxgdb}, to distinguish it from a
+@value{GDBN} for debugging programs on the host itself.)
+
+The following information on connecting to VxWorks was current when
+this manual was produced; newer releases of VxWorks may use revised
+procedures.
+
+The remote debugging interface (RDB) routines are installed and executed
+on the VxWorks target. These routines are included in the VxWorks library
+@file{rdb.a} and are incorporated into the system image when source-level
+debugging is enabled in the VxWorks configuration.
+
+@kindex INCLUDE_RDB
+If you wish, you can define @code{INCLUDE_RDB} in the VxWorks
+configuration file @file{configAll.h} to include the RDB interface
+routines and spawn the source debugging task @code{tRdbTask} when
+VxWorks is booted. For more information on configuring and remaking
+VxWorks, see the manufacturer's manual.
+@c VxWorks, see the @cite{VxWorks Programmer's Guide}.
+
+Once you have included the RDB interface in your VxWorks system image
+and set your Unix execution search path to find @value{GDBN}, you are ready
+to run @value{GDBN}. From your Unix host, run @code{gdb} (or
+@code{vxgdb}, depending on your installation).
+
+@value{GDBN} comes up showing the prompt:
+
+@example
+(vxgdb)
+@end example
+
+@menu
+* VxWorks Connection:: Connecting to VxWorks
+* VxWorks Download:: VxWorks download
+* VxWorks Attach:: Running tasks
+@end menu
+
+@node VxWorks Connection
+@subsubsection Connecting to VxWorks
+
+The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the
+network. To connect to a target whose host name is ``@code{tt}'', type:
+
+@example
+(vxgdb) target vxworks tt
+@end example
+
+@value{GDBN} displays messages like these:
+
+@smallexample
+Attaching remote machine across net...
+Connected to tt.
+@end smallexample
+
+@value{GDBN} then attempts to read the symbol tables of any object modules
+loaded into the VxWorks target since it was last booted. @value{GDBN} locates
+these files by searching the directories listed in the command search
+path (@pxref{Environment, ,Your program's environment}); if it fails
+to find an object file, it displays a message such as:
+
+@example
+prog.o: No such file or directory.
+@end example
+
+When this happens, add the appropriate directory to the search path with
+the @value{GDBN} command @code{path}, and execute the @code{target}
+command again.
+
+@node VxWorks Download
+@subsubsection VxWorks download
+
+@cindex download to VxWorks
+If you have connected to the VxWorks target and you want to debug an
+object that has not yet been loaded, you can use the @value{GDBN}
+@code{load} command to download a file from Unix to VxWorks
+incrementally. The object file given as an argument to the @code{load}
+command is actually opened twice: first by the VxWorks target in order
+to download the code, then by @value{GDBN} in order to read the symbol
+table. This can lead to problems if the current working directories on
+the two systems differ. If both systems have NFS mounted the same
+filesystems, you can avoid these problems by using absolute paths.
+Otherwise, it is simplest to set the working directory on both systems
+to the directory in which the object file resides, and then to reference
+the file by its name, without any path. For instance, a program
+@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks
+and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this
+program, type this on VxWorks:
+
+@example
+-> cd "@var{vxpath}/vw/demo/rdb"
+@end example
+
+Then, in @value{GDBN}, type:
+
+@example
+(vxgdb) cd @var{hostpath}/vw/demo/rdb
+(vxgdb) load prog.o
+@end example
+
+@value{GDBN} displays a response similar to this:
+
+@smallexample
+Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+@end smallexample
+
+You can also use the @code{load} command to reload an object module
+after editing and recompiling the corresponding source file. Note that
+this will cause @value{GDBN} to delete all currently-defined breakpoints,
+auto-displays, and convenience variables, and to clear the value
+history. (This is necessary in order to preserve the integrity of
+debugger data structures that reference the target system's symbol
+table.)
+
+@node VxWorks Attach
+@subsubsection Running tasks
+
+@cindex running VxWorks tasks
+You can also attach to an existing task using the @code{attach} command as
+follows:
+
+@example
+(vxgdb) attach @var{task}
+@end example
+
+@noindent
+where @var{task} is the VxWorks hexadecimal task ID. The task can be running
+or suspended when you attach to it. If running, it will be suspended at
+the time of attachment.
+@end ifset
+
+@ifset H8
+@node Hitachi Remote
+@subsection @value{GDBN} and Hitachi Microprocessors
+@value{GDBN} needs to know these things to talk to your
+Hitachi SH, H8/300, or H8/500:
+
+@enumerate
+@item
+that you want to use @samp{target hms}, the remote debugging interface
+for Hitachi microprocessors (this is the default when GDB is configured
+specifically for the Hitachi SH, H8/300, or H8/500);
+
+@item
+what serial device connects your host to your Hitachi board (the first
+serial device available on your host is the default);
+
+@ignore
+@c this is only for Unix hosts, not currently of interest.
+@item
+what speed to use over the serial device.
+@end ignore
+@end enumerate
+
+@ifclear H8EXCLUSIVE
+@c only for Unix hosts
+@kindex device
+@cindex serial device, Hitachi micros
+Use the special @code{@value{GDBP}} command @samp{device @var{port}} if you
+need to explicitly set the serial device. The default @var{port} is the
+first available port on your host. This is only necessary on Unix
+hosts, where it is typically something like @file{/dev/ttya}.
+
+@kindex speed
+@cindex serial line speed, Hitachi micros
+@code{@value{GDBP}} has another special command to set the communications
+speed: @samp{speed @var{bps}}. This command also is only used from Unix
+hosts; on DOS hosts, set the line speed as usual from outside GDB with
+the DOS @kbd{mode} command (for instance, @w{@samp{mode
+com2:9600,n,8,1,p}} for a 9600 bps connection).
+
+The @samp{device} and @samp{speed} commands are available only when you
+use a Unix host to debug your Hitachi microprocessor programs. If you
+use a DOS host,
+@end ifclear
+@value{GDBN} depends on an auxiliary terminate-and-stay-resident program
+called @code{asynctsr} to communicate with the development board
+through a PC serial port. You must also use the DOS @code{mode} command
+to set up the serial port on the DOS side.
+
+@ifset DOSHOST
+The following sample session illustrates the steps needed to start a
+program under @value{GDBN} control on an H8/300. The example uses a
+sample H8/300 program called @file{t.x}. The procedure is the same for
+the Hitachi SH and the H8/500.
+
+First hook up your development board. In this example, we use a
+board attached to serial port @code{COM2}; if you use a different serial
+port, substitute its name in the argument of the @code{mode} command.
+When you call @code{asynctsr}, the auxiliary comms program used by the
+degugger, you give it just the numeric part of the serial port's name;
+for example, @samp{asyncstr 2} below runs @code{asyncstr} on
+@code{COM2}.
+
+@example
+(eg-C:\H8300\TEST) mode com2:9600,n,8,1,p
+
+Resident portion of MODE loaded
+
+COM2: 9600, n, 8, 1, p
+
+(eg-C:\H8300\TEST) asynctsr 2
+@end example
+
+@quotation
+@emph{Warning:} We have noticed a bug in PC-NFS that conflicts with
+@code{asynctsr}. If you also run PC-NFS on your DOS host, you may need to
+disable it, or even boot without it, to use @code{asynctsr} to control
+your development board.
+@end quotation
+
+@kindex target hms
+Now that serial communications are set up, and the development board is
+connected, you can start up @value{GDBN}. Call @code{@value{GDBP}} with
+the name of your program as the argument. @code{@value{GDBP}} prompts
+you, as usual, with the prompt @samp{(@value{GDBP})}. Use two special
+commands to begin your debugging session: @samp{target hms} to specify
+cross-debugging to the Hitachi board, and the @code{load} command to
+download your program to the board. @code{load} displays the names of
+the program's sections, and a @samp{*} for each 2K of data downloaded.
+(If you want to refresh @value{GDBN} data on symbols or on the
+executable file without downloading, use the @value{GDBN} commands
+@code{file} or @code{symbol-file}. These commands, and @code{load}
+itself, are described in @ref{Files,,Commands to specify files}.)
+
+@smallexample
+(eg-C:\H8300\TEST) @value{GDBP} t.x
+GDB is free software and you are welcome to distribute copies
+ of it under certain conditions; type "show copying" to see
+ the conditions.
+There is absolutely no warranty for GDB; type "show warranty"
+for details.
+GDB @value{GDBVN}, Copyright 1992 Free Software Foundation, Inc...
+(gdb) target hms
+Connected to remote H8/300 HMS system.
+(gdb) load t.x
+.text : 0x8000 .. 0xabde ***********
+.data : 0xabde .. 0xad30 *
+.stack : 0xf000 .. 0xf014 *
+@end smallexample
+
+At this point, you're ready to run or debug your program. From here on,
+you can use all the usual @value{GDBN} commands. The @code{break} command
+sets breakpoints; the @code{run} command starts your program;
+@code{print} or @code{x} display data; the @code{continue} command
+resumes execution after stopping at a breakpoint. You can use the
+@code{help} command at any time to find out more about @value{GDBN} commands.
+
+Remember, however, that @emph{operating system} facilities aren't
+available on your development board; for example, if your program hangs,
+you can't send an interrupt---but you can press the @sc{reset} switch!
+
+Use the @sc{reset} button on the development board
+@itemize @bullet
+@item
+to interrupt your program (don't use @kbd{ctl-C} on the DOS host---it has
+no way to pass an interrupt signal to the development board); and
+
+@item
+to return to the @value{GDBN} command prompt after your program finishes
+normally. The communications protocol provides no other way for @value{GDBN}
+to detect program completion.
+@end itemize
+
+In either case, @value{GDBN} will see the effect of a @sc{reset} on the
+development board as a ``normal exit'' of your program.
+@end ifset
+@end ifset
+
+@ifset MIPS
+@node MIPS Remote
+@subsection @value{GDBN} and remote MIPS boards
+
+@cindex MIPS boards
+@value{GDBN} can use the MIPS remote debugging protocol to talk to a
+MIPS board attached to a serial line. This is available when
+you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}.
+
+@kindex target mips @var{port}
+To run a program on the board, start up @code{@value{GDBP}} with the
+name of your program as the argument. To connect to the board, use the
+command @samp{target mips @var{port}}, where @var{port} is the name of
+the serial port connected to the board. If the program has not already
+been downloaded to the board, you may use the @code{load} command to
+download it. You can then use all the usual @value{GDBN} commands.
+
+You can also specify @var{port} as a TCP connection (for instance, to a
+serial line managed by a terminal concentrator), using the syntax
+@code{@var{hostname}:@var{portnumber}}.
+
+@cindex @code{remotedebug}, MIPS protocol
+@c FIXME! For this to be useful, you must know something about the MIPS
+@c FIXME...protocol. Where is it described?
+You can see some debugging information about communications with the board
+by setting the @code{remotedebug} variable. If you set it to 1 using
+@samp{set remotedebug 1} every packet will be displayed. If you set it
+to 2 every character will be displayed. You can check the current value
+at any time with the command @samp{show remotedebug}.
+
+@cindex @code{timeout}, MIPS protocol
+@cindex @code{retransmit-timeout}, MIPS protocol
+@kindex set timeout
+@kindex show timeout
+@kindex set retransmit-timeout
+@kindex show retransmit-timeout
+You can control the timeout used while waiting for a packet, in the MIPS
+remote protocol, with the @code{set timeout @var{seconds}} command. The
+default is 5 seconds. Similarly, you can control the timeout used while
+waiting for an acknowledgement of a packet with the @code{set
+retransmit-timeout @var{seconds}} command. The default is 3 seconds.
+You can inspect both values with @code{show timeout} and @code{show
+retransmit-timeout}. (These commands are @emph{only} available when
+@value{GDBN} is configured for @samp{--target=mips-idt-ecoff}.)
+
+@kindex set mipsfpu off
+@cindex MIPS remote floating point
+@cindex floating point, MIPS remote
+If your target board does not support the MIPS floating point
+coprocessor, you should use the command @samp{set mipsfpu off} (you may
+wish to put this in your @value{GDBINIT} file). This tells @value{GDBN}
+how to find the return value of functions which return floating point
+values. It also allows @value{GDBN} to avoid saving the floating point
+registers when calling functions on the board.
+@end ifset
+
+@ifset SIMS
+@node Simulator
+@subsection Simulated CPU target
+
+@ifset GENERIC
+@cindex simulator
+@cindex simulator, Z8000
+@cindex Z8000 simulator
+@cindex simulator, H8/300 or H8/500
+@cindex H8/300 or H8/500 simulator
+@cindex simulator, Hitachi SH
+@cindex Hitachi SH simulator
+@cindex CPU simulator
+For some configurations, @value{GDBN} includes a CPU simulator that you
+can use instead of a hardware CPU to debug your programs. Currently,
+a simulator is available when @value{GDBN} is configured to debug Zilog
+Z8000 or Hitachi microprocessor targets.
+@end ifset
+
+@ifclear GENERIC
+@ifset H8
+@cindex simulator, H8/300 or H8/500
+@cindex Hitachi H8/300 or H8/500 simulator
+@cindex simulator, Hitachi SH
+@cindex Hitachi SH simulator
+When configured for debugging Hitachi microprocessor targets,
+@value{GDBN} includes a CPU simulator for the target chip (a Hitachi SH,
+H8/300, or H8/500).
+@end ifset
+
+@ifset Z8K
+@cindex simulator, Z8000
+@cindex Zilog Z8000 simulator
+When configured for debugging Zilog Z8000 targets, @value{GDBN} includes
+a Z8000 simulator.
+@end ifset
+@end ifclear
+
+@ifset Z8K
+For the Z8000 family, @samp{target sim} simulates either the Z8002 (the
+unsegmented variant of the Z8000 architecture) or the Z8001 (the
+segmented variant). The simulator recognizes which architecture is
+appropriate by inspecting the object code.
+@end ifset
+
+@table @code
+@item target sim
+@kindex sim
+@kindex target sim
+Debug programs on a simulated CPU
+@ifset GENERIC
+(which CPU depends on the @value{GDBN} configuration)
+@end ifset
+@end table
+
+@noindent
+After specifying this target, you can debug programs for the simulated
+CPU in the same style as programs for your host computer; use the
+@code{file} command to load a new program image, the @code{run} command
+to run your program, and so on.
+
+As well as making available all the usual machine registers (see
+@code{info reg}), this debugging target provides three additional items
+of information as specially named registers:
+
+@table @code
+@item cycles
+Counts clock-ticks in the simulator.
+
+@item insts
+Counts instructions run in the simulator.
+
+@item time
+Execution time in 60ths of a second.
+@end table
+
+You can refer to these values in @value{GDBN} expressions with the usual
+conventions; for example, @w{@samp{b fputc if $cycles>5000}} sets a
+conditional breakpoint that will suspend only after at least 5000
+simulated clock ticks.
+@end ifset
diff --git a/gnu/usr.bin/gdb/doc/stabs.texinfo b/gnu/usr.bin/gdb/doc/stabs.texinfo
new file mode 100644
index 000000000000..41b29819d551
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/stabs.texinfo
@@ -0,0 +1,3795 @@
+\input texinfo
+@setfilename stabs.info
+
+@c @finalout
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Stabs:: The "stabs" debugging information format.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+This document describes the stabs debugging symbol tables.
+
+Copyright 1992, 1993 Free Software Foundation, Inc.
+Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon,
+and David MacKenzie.
+
+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.
+
+@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 copy or distribute modified versions of this
+manual under the terms of the GPL (for which purpose this text may be
+regarded as a program in the language TeX).
+@end ifinfo
+
+@setchapternewpage odd
+@settitle STABS
+@titlepage
+@title The ``stabs'' debug format
+@author Julia Menapace, Jim Kingdon, David MacKenzie
+@author Cygnus Support
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.1 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc.
+Contributed by Cygnus Support.
+
+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.
+
+@end titlepage
+
+@ifinfo
+@node Top
+@top The "stabs" representation of debugging information
+
+This document describes the stabs debugging format.
+
+@menu
+* Overview:: Overview of stabs
+* Program Structure:: Encoding of the structure of the program
+* Constants:: Constants
+* Variables::
+* Types:: Type definitions
+* Symbol Tables:: Symbol information in symbol tables
+* Cplusplus:: Appendixes:
+* Stab Types:: Symbol types in a.out files
+* Symbol Descriptors:: Table of symbol descriptors
+* Type Descriptors:: Table of type descriptors
+* Expanded Reference:: Reference information by stab type
+* Questions:: Questions and anomolies
+* XCOFF Differences:: Differences between GNU stabs in a.out
+ and GNU stabs in XCOFF
+* Sun Differences:: Differences between GNU stabs and Sun
+ native stabs
+* Stabs In ELF:: Stabs in an ELF file.
+* Symbol Types Index:: Index of symbolic stab symbol type names.
+@end menu
+@end ifinfo
+
+
+@node Overview
+@chapter Overview of Stabs
+
+@dfn{Stabs} refers to a format for information that describes a program
+to a debugger. This format was apparently invented by
+@c FIXME! <<name of inventor>> at
+the University of California at Berkeley, for the @code{pdx} Pascal
+debugger; the format has spread widely since then.
+
+This document is one of the few published sources of documentation on
+stabs. It is believed to be comprehensive for stabs used by C. The
+lists of symbol descriptors (@pxref{Symbol Descriptors}) and type
+descriptors (@pxref{Type Descriptors}) are believed to be completely
+comprehensive. Stabs for COBOL-specific features and for variant
+records (used by Pascal and Modula-2) are poorly documented here.
+
+Other sources of information on stabs are @cite{Dbx and Dbxtool
+Interfaces}, 2nd edition, by Sun, 1988, and @cite{AIX Version 3.2 Files
+Reference}, Fourth Edition, September 1992, "dbx Stabstring Grammar" in
+the a.out section, page 2-31. This document is believed to incorporate
+the information from those two sources except where it explictly directs
+you to them for more information.
+
+@menu
+* Flow:: Overview of debugging information flow
+* Stabs Format:: Overview of stab format
+* String Field:: The string field
+* C Example:: A simple example in C source
+* Assembly Code:: The simple example at the assembly level
+@end menu
+
+@node Flow
+@section Overview of Debugging Information Flow
+
+The GNU C compiler compiles C source in a @file{.c} file into assembly
+language in a @file{.s} file, which the assembler translates into
+a @file{.o} file, which the linker combines with other @file{.o} files and
+libraries to produce an executable file.
+
+With the @samp{-g} option, GCC puts in the @file{.s} file additional
+debugging information, which is slightly transformed by the assembler
+and linker, and carried through into the final executable. This
+debugging information describes features of the source file like line
+numbers, the types and scopes of variables, and function names,
+parameters, and scopes.
+
+For some object file formats, the debugging information is encapsulated
+in assembler directives known collectively as @dfn{stab} (symbol table)
+directives, which are interspersed with the generated code. Stabs are
+the native format for debugging information in the a.out and XCOFF
+object file formats. The GNU tools can also emit stabs in the COFF and
+ECOFF object file formats.
+
+The assembler adds the information from stabs to the symbol information
+it places by default in the symbol table and the string table of the
+@file{.o} file it is building. The linker consolidates the @file{.o}
+files into one executable file, with one symbol table and one string
+table. Debuggers use the symbol and string tables in the executable as
+a source of debugging information about the program.
+
+@node Stabs Format
+@section Overview of Stab Format
+
+There are three overall formats for stab assembler directives,
+differentiated by the first word of the stab. The name of the directive
+describes which combination of four possible data fields follows. It is
+either @code{.stabs} (string), @code{.stabn} (number), or @code{.stabd}
+(dot). IBM's XCOFF assembler uses @code{.stabx} (and some other
+directives such as @code{.file} and @code{.bi}) instead of
+@code{.stabs}, @code{.stabn} or @code{.stabd}.
+
+The overall format of each class of stab is:
+
+@example
+.stabs "@var{string}",@var{type},@var{other},@var{desc},@var{value}
+.stabn @var{type},@var{other},@var{desc},@var{value}
+.stabd @var{type},@var{other},@var{desc}
+.stabx "@var{string}",@var{value},@var{type},@var{sdb-type}
+@end example
+
+@c what is the correct term for "current file location"? My AIX
+@c assembler manual calls it "the value of the current location counter".
+For @code{.stabn} and @code{.stabd}, there is no @var{string} (the
+@code{n_strx} field is zero; see @ref{Symbol Tables}). For
+@code{.stabd}, the @var{value} field is implicit and has the value of
+the current file location. For @code{.stabx}, the @var{sdb-type} field
+is unused for stabs and can always be set to zero. The @var{other}
+field is almost always unused and can be set to zero.
+
+The number in the @var{type} field gives some basic information about
+which type of stab this is (or whether it @emph{is} a stab, as opposed
+to an ordinary symbol). Each valid type number defines a different stab
+type; further, the stab type defines the exact interpretation of, and
+possible values for, any remaining @var{string}, @var{desc}, or
+@var{value} fields present in the stab. @xref{Stab Types}, for a list
+in numeric order of the valid @var{type} field values for stab directives.
+
+@node String Field
+@section The String Field
+
+For most stabs the string field holds the meat of the
+debugging information. The flexible nature of this field
+is what makes stabs extensible. For some stab types the string field
+contains only a name. For other stab types the contents can be a great
+deal more complex.
+
+The overall format of the string field for most stab types is:
+
+@example
+"@var{name}:@var{symbol-descriptor} @var{type-information}"
+@end example
+
+@var{name} is the name of the symbol represented by the stab.
+@var{name} can be omitted, which means the stab represents an unnamed
+object. For example, @samp{:t10=*2} defines type 10 as a pointer to
+type 2, but does not give the type a name. Omitting the @var{name}
+field is supported by AIX dbx and GDB after about version 4.8, but not
+other debuggers. GCC sometimes uses a single space as the name instead
+of omitting the name altogether; apparently that is supported by most
+debuggers.
+
+The @var{symbol-descriptor} following the @samp{:} is an alphabetic
+character that tells more specifically what kind of symbol the stab
+represents. If the @var{symbol-descriptor} is omitted, but type
+information follows, then the stab represents a local variable. For a
+list of symbol descriptors, see @ref{Symbol Descriptors}. The @samp{c}
+symbol descriptor is an exception in that it is not followed by type
+information. @xref{Constants}.
+
+@var{type-information} is either a @var{type-number}, or
+@samp{@var{type-number}=}. A @var{type-number} alone is a type
+reference, referring directly to a type that has already been defined.
+
+The @samp{@var{type-number}=} form is a type definition, where the
+number represents a new type which is about to be defined. The type
+definition may refer to other types by number, and those type numbers
+may be followed by @samp{=} and nested definitions.
+
+In a type definition, if the character that follows the equals sign is
+non-numeric then it is a @var{type-descriptor}, and tells what kind of
+type is about to be defined. Any other values following the
+@var{type-descriptor} vary, depending on the @var{type-descriptor}.
+@xref{Type Descriptors}, for a list of @var{type-descriptor} values. If
+a number follows the @samp{=} then the number is a @var{type-reference}.
+For a full description of types, @ref{Types}.
+
+There is an AIX extension for type attributes. Following the @samp{=}
+are any number of type attributes. Each one starts with @samp{@@} and
+ends with @samp{;}. Debuggers, including AIX's dbx and GDB 4.10, skip
+any type attributes they do not recognize. GDB 4.9 and other versions
+of dbx may not do this. Because of a conflict with C++
+(@pxref{Cplusplus}), new attributes should not be defined which begin
+with a digit, @samp{(}, or @samp{-}; GDB may be unable to distinguish
+those from the C++ type descriptor @samp{@@}. The attributes are:
+
+@table @code
+@item a@var{boundary}
+@var{boundary} is an integer specifying the alignment. I assume it
+applies to all variables of this type.
+
+@item s@var{size}
+Size in bits of a variable of this type.
+
+@item p@var{integer}
+Pointer class (for checking). Not sure what this means, or how
+@var{integer} is interpreted.
+
+@item P
+Indicate this is a packed type, meaning that structure fields or array
+elements are placed more closely in memory, to save memory at the
+expense of speed.
+@end table
+
+All of this can make the string field quite long. All
+versions of GDB, and some versions of dbx, can handle arbitrarily long
+strings. But many versions of dbx cretinously limit the strings to
+about 80 characters, so compilers which must work with such dbx's need
+to split the @code{.stabs} directive into several @code{.stabs}
+directives. Each stab duplicates exactly all but the
+string field. The string field of
+every stab except the last is marked as continued with a
+double-backslash at the end. Removing the backslashes and concatenating
+the string fields of each stab produces the original,
+long string.
+
+@node C Example
+@section A Simple Example in C Source
+
+To get the flavor of how stabs describe source information for a C
+program, let's look at the simple program:
+
+@example
+main()
+@{
+ printf("Hello world");
+@}
+@end example
+
+When compiled with @samp{-g}, the program above yields the following
+@file{.s} file. Line numbers have been added to make it easier to refer
+to parts of the @file{.s} file in the description of the stabs that
+follows.
+
+@node Assembly Code
+@section The Simple Example at the Assembly Level
+
+This simple ``hello world'' example demonstrates several of the stab
+types used to describe C language source files.
+
+@example
+1 gcc2_compiled.:
+2 .stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0
+3 .stabs "hello.c",100,0,0,Ltext0
+4 .text
+5 Ltext0:
+6 .stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0
+7 .stabs "char:t2=r2;0;127;",128,0,0,0
+8 .stabs "long int:t3=r1;-2147483648;2147483647;",128,0,0,0
+9 .stabs "unsigned int:t4=r1;0;-1;",128,0,0,0
+10 .stabs "long unsigned int:t5=r1;0;-1;",128,0,0,0
+11 .stabs "short int:t6=r1;-32768;32767;",128,0,0,0
+12 .stabs "long long int:t7=r1;0;-1;",128,0,0,0
+13 .stabs "short unsigned int:t8=r1;0;65535;",128,0,0,0
+14 .stabs "long long unsigned int:t9=r1;0;-1;",128,0,0,0
+15 .stabs "signed char:t10=r1;-128;127;",128,0,0,0
+16 .stabs "unsigned char:t11=r1;0;255;",128,0,0,0
+17 .stabs "float:t12=r1;4;0;",128,0,0,0
+18 .stabs "double:t13=r1;8;0;",128,0,0,0
+19 .stabs "long double:t14=r1;8;0;",128,0,0,0
+20 .stabs "void:t15=15",128,0,0,0
+21 .align 4
+22 LC0:
+23 .ascii "Hello, world!\12\0"
+24 .align 4
+25 .global _main
+26 .proc 1
+27 _main:
+28 .stabn 68,0,4,LM1
+29 LM1:
+30 !#PROLOGUE# 0
+31 save %sp,-136,%sp
+32 !#PROLOGUE# 1
+33 call ___main,0
+34 nop
+35 .stabn 68,0,5,LM2
+36 LM2:
+37 LBB2:
+38 sethi %hi(LC0),%o1
+39 or %o1,%lo(LC0),%o0
+40 call _printf,0
+41 nop
+42 .stabn 68,0,6,LM3
+43 LM3:
+44 LBE2:
+45 .stabn 68,0,6,LM4
+46 LM4:
+47 L1:
+48 ret
+49 restore
+50 .stabs "main:F1",36,0,0,_main
+51 .stabn 192,0,0,LBB2
+52 .stabn 224,0,0,LBE2
+@end example
+
+@node Program Structure
+@chapter Encoding the Structure of the Program
+
+The elements of the program structure that stabs encode include the name
+of the main function, the names of the source and include files, the
+line numbers, procedure names and types, and the beginnings and ends of
+blocks of code.
+
+@menu
+* Main Program:: Indicate what the main program is
+* Source Files:: The path and name of the source file
+* Include Files:: Names of include files
+* Line Numbers::
+* Procedures::
+* Nested Procedures::
+* Block Structure::
+@end menu
+
+@node Main Program
+@section Main Program
+
+@findex N_MAIN
+Most languages allow the main program to have any name. The
+@code{N_MAIN} stab type tells the debugger the name that is used in this
+program. Only the string field is significant; it is the name of
+a function which is the main program. Most C compilers do not use this
+stab (they expect the debugger to assume that the name is @code{main}),
+but some C compilers emit an @code{N_MAIN} stab for the @code{main}
+function.
+
+@node Source Files
+@section Paths and Names of the Source Files
+
+@findex N_SO
+Before any other stabs occur, there must be a stab specifying the source
+file. This information is contained in a symbol of stab type
+@code{N_SO}; the string field contains the name of the file. The
+value of the symbol is the start address of the portion of the
+text section corresponding to that file.
+
+With the Sun Solaris2 compiler, the desc field contains a
+source-language code.
+@c Do the debuggers use it? What are the codes? -djm
+
+Some compilers (for example, GCC2 and SunOS4 @file{/bin/cc}) also
+include the directory in which the source was compiled, in a second
+@code{N_SO} symbol preceding the one containing the file name. This
+symbol can be distinguished by the fact that it ends in a slash. Code
+from the @code{cfront} C++ compiler can have additional @code{N_SO} symbols for
+nonexistent source files after the @code{N_SO} for the real source file;
+these are believed to contain no useful information.
+
+For example:
+
+@example
+.stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 # @r{100 is N_SO}
+.stabs "hello.c",100,0,0,Ltext0
+ .text
+Ltext0:
+@end example
+
+Instead of @code{N_SO} symbols, XCOFF uses a @code{.file} assembler
+directive which assembles to a standard COFF @code{.file} symbol;
+explaining this in detail is outside the scope of this document.
+
+@node Include Files
+@section Names of Include Files
+
+There are several schemes for dealing with include files: the
+traditional @code{N_SOL} approach, Sun's @code{N_BINCL} approach, and the
+XCOFF @code{C_BINCL} approach (which despite the similar name has little in
+common with @code{N_BINCL}).
+
+@findex N_SOL
+An @code{N_SOL} symbol specifies which include file subsequent symbols
+refer to. The string field is the name of the file and the value is the
+text address corresponding to the end of the previous include file and
+the start of this one. To specify the main source file again, use an
+@code{N_SOL} symbol with the name of the main source file.
+
+@findex N_BINCL
+@findex N_EINCL
+@findex N_EXCL
+The @code{N_BINCL} approach works as follows. An @code{N_BINCL} symbol
+specifies the start of an include file. In an object file, only the
+string is significant; the Sun linker puts data into some of the
+other fields. The end of the include file is marked by an
+@code{N_EINCL} symbol (which has no string field). In an object
+file, there is no significant data in the @code{N_EINCL} symbol; the Sun
+linker puts data into some of the fields. @code{N_BINCL} and
+@code{N_EINCL} can be nested.
+
+If the linker detects that two source files have identical stabs between
+an @code{N_BINCL} and @code{N_EINCL} pair (as will generally be the case
+for a header file), then it only puts out the stabs once. Each
+additional occurance is replaced by an @code{N_EXCL} symbol. I believe
+the Sun (SunOS4, not sure about Solaris) linker is the only one which
+supports this feature.
+@c What do the fields of N_EXCL contain? -djm
+
+@findex C_BINCL
+@findex C_EINCL
+For the start of an include file in XCOFF, use the @file{.bi} assembler
+directive, which generates a @code{C_BINCL} symbol. A @file{.ei}
+directive, which generates a @code{C_EINCL} symbol, denotes the end of
+the include file. Both directives are followed by the name of the
+source file in quotes, which becomes the string for the symbol.
+The value of each symbol, produced automatically by the assembler
+and linker, is the offset into the executable of the beginning
+(inclusive, as you'd expect) or end (inclusive, as you would not expect)
+of the portion of the COFF line table that corresponds to this include
+file. @code{C_BINCL} and @code{C_EINCL} do not nest.
+
+@node Line Numbers
+@section Line Numbers
+
+@findex N_SLINE
+An @code{N_SLINE} symbol represents the start of a source line. The
+desc field contains the line number and the value
+contains the code address for the start of that source line. On most
+machines the address is absolute; for Sun's stabs-in-ELF, it is relative
+to the function in which the @code{N_SLINE} symbol occurs.
+
+@findex N_DSLINE
+@findex N_BSLINE
+GNU documents @code{N_DSLINE} and @code{N_BSLINE} symbols for line
+numbers in the data or bss segments, respectively. They are identical
+to @code{N_SLINE} but are relocated differently by the linker. They
+were intended to be used to describe the source location of a variable
+declaration, but I believe that GCC2 actually puts the line number in
+the desc field of the stab for the variable itself. GDB has been
+ignoring these symbols (unless they contain a string field) since
+at least GDB 3.5.
+
+For single source lines that generate discontiguous code, such as flow
+of control statements, there may be more than one line number entry for
+the same source line. In this case there is a line number entry at the
+start of each code range, each with the same line number.
+
+XCOFF does not use stabs for line numbers. Instead, it uses COFF line
+numbers (which are outside the scope of this document). Standard COFF
+line numbers cannot deal with include files, but in XCOFF this is fixed
+with the @code{C_BINCL} method of marking include files (@pxref{Include
+Files}).
+
+@node Procedures
+@section Procedures
+
+@findex N_FUN, for functions
+@findex N_FNAME
+@findex N_STSYM, for functions (Sun acc)
+@findex N_GSYM, for functions (Sun acc)
+All of the following stabs normally use the @code{N_FUN} symbol type.
+However, Sun's @code{acc} compiler on SunOS4 uses @code{N_GSYM} and
+@code{N_STSYM}, which means that the value of the stab for the function
+is useless and the debugger must get the address of the function from
+the non-stab symbols instead. BSD Fortran is said to use @code{N_FNAME}
+with the same restriction; the value of the symbol is not useful (I'm
+not sure it really does use this, because GDB doesn't handle this and no
+one has complained).
+
+A function is represented by an @samp{F} symbol descriptor for a global
+(extern) function, and @samp{f} for a static (local) function. The
+value is the address of the start of the function. For @code{a.out}, it
+is already relocated. For stabs in ELF, the SunPRO compiler version
+2.0.1 and GCC put out an address which gets relocated by the linker. In
+a future release SunPRO is planning to put out zero, in which case the
+address can be found from the ELF (non-stab) symbol. Because looking
+things up in the ELF symbols would probably be slow, I'm not sure how to
+find which symbol of that name is the right one, and this doesn't
+provide any way to deal with nested functions, it would probably be
+better to make the value of the stab an address relative to the start of
+the file. See @ref{Stabs In ELF} for more information on linker
+relocation of stabs in ELF files.
+
+The type information of the stab represents the return type of the
+function; thus @samp{foo:f5} means that foo is a function returning type
+5. There is no need to try to get the line number of the start of the
+function from the stab for the function; it is in the next
+@code{N_SLINE} symbol.
+
+@c FIXME: verify whether the "I suspect" below is true or not.
+Some compilers (such as Sun's Solaris compiler) support an extension for
+specifying the types of the arguments. I suspect this extension is not
+used for old (non-prototyped) function definitions in C. If the
+extension is in use, the type information of the stab for the function
+is followed by type information for each argument, with each argument
+preceded by @samp{;}. An argument type of 0 means that additional
+arguments are being passed, whose types and number may vary (@samp{...}
+in ANSI C). GDB has tolerated this extension (parsed the syntax, if not
+necessarily used the information) since at least version 4.8; I don't
+know whether all versions of dbx tolerate it. The argument types given
+here are not redundant with the symbols for the formal parameters
+(@pxref{Parameters}); they are the types of the arguments as they are
+passed, before any conversions might take place. For example, if a C
+function which is declared without a prototype takes a @code{float}
+argument, the value is passed as a @code{double} but then converted to a
+@code{float}. Debuggers need to use the types given in the arguments
+when printing values, but when calling the function they need to use the
+types given in the symbol defining the function.
+
+If the return type and types of arguments of a function which is defined
+in another source file are specified (i.e., a function prototype in ANSI
+C), traditionally compilers emit no stab; the only way for the debugger
+to find the information is if the source file where the function is
+defined was also compiled with debugging symbols. As an extension the
+Solaris compiler uses symbol descriptor @samp{P} followed by the return
+type of the function, followed by the arguments, each preceded by
+@samp{;}, as in a stab with symbol descriptor @samp{f} or @samp{F}.
+This use of symbol descriptor @samp{P} can be distinguished from its use
+for register parameters (@pxref{Register Parameters}) by the fact that it has
+symbol type @code{N_FUN}.
+
+The AIX documentation also defines symbol descriptor @samp{J} as an
+internal function. I assume this means a function nested within another
+function. It also says symbol descriptor @samp{m} is a module in
+Modula-2 or extended Pascal.
+
+Procedures (functions which do not return values) are represented as
+functions returning the @code{void} type in C. I don't see why this couldn't
+be used for all languages (inventing a @code{void} type for this purpose if
+necessary), but the AIX documentation defines @samp{I}, @samp{P}, and
+@samp{Q} for internal, global, and static procedures, respectively.
+These symbol descriptors are unusual in that they are not followed by
+type information.
+
+The following example shows a stab for a function @code{main} which
+returns type number @code{1}. The @code{_main} specified for the value
+is a reference to an assembler label which is used to fill in the start
+address of the function.
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+@end example
+
+The stab representing a procedure is located immediately following the
+code of the procedure. This stab is in turn directly followed by a
+group of other stabs describing elements of the procedure. These other
+stabs describe the procedure's parameters, its block local variables, and
+its block structure.
+
+@node Nested Procedures
+@section Nested Procedures
+
+For any of the symbol descriptors representing procedures, after the
+symbol descriptor and the type information is optionally a scope
+specifier. This consists of a comma, the name of the procedure, another
+comma, and the name of the enclosing procedure. The first name is local
+to the scope specified, and seems to be redundant with the name of the
+symbol (before the @samp{:}). This feature is used by GCC, and
+presumably Pascal, Modula-2, etc., compilers, for nested functions.
+
+If procedures are nested more than one level deep, only the immediately
+containing scope is specified. For example, this code:
+
+@example
+int
+foo (int x)
+@{
+ int bar (int y)
+ @{
+ int baz (int z)
+ @{
+ return x + y + z;
+ @}
+ return baz (x + 2 * y);
+ @}
+ return x + bar (3 * x);
+@}
+@end example
+
+@noindent
+produces the stabs:
+
+@example
+.stabs "baz:f1,baz,bar",36,0,0,_baz.15 # @r{36 is N_FUN}
+.stabs "bar:f1,bar,foo",36,0,0,_bar.12
+.stabs "foo:F1",36,0,0,_foo
+@end example
+
+@node Block Structure
+@section Block Structure
+
+@findex N_LBRAC
+@findex N_RBRAC
+The program's block structure is represented by the @code{N_LBRAC} (left
+brace) and the @code{N_RBRAC} (right brace) stab types. The variables
+defined inside a block precede the @code{N_LBRAC} symbol for most
+compilers, including GCC. Other compilers, such as the Convex, Acorn
+RISC machine, and Sun @code{acc} compilers, put the variables after the
+@code{N_LBRAC} symbol. The values of the @code{N_LBRAC} and
+@code{N_RBRAC} symbols are the start and end addresses of the code of
+the block, respectively. For most machines, they are relative to the
+starting address of this source file. For the Gould NP1, they are
+absolute. For Sun's stabs-in-ELF, they are relative to the function in
+which they occur.
+
+The @code{N_LBRAC} and @code{N_RBRAC} stabs that describe the block
+scope of a procedure are located after the @code{N_FUN} stab that
+represents the procedure itself.
+
+Sun documents the desc field of @code{N_LBRAC} and
+@code{N_RBRAC} symbols as containing the nesting level of the block.
+However, dbx seems to not care, and GCC always sets desc to
+zero.
+
+@node Constants
+@chapter Constants
+
+The @samp{c} symbol descriptor indicates that this stab represents a
+constant. This symbol descriptor is an exception to the general rule
+that symbol descriptors are followed by type information. Instead, it
+is followed by @samp{=} and one of the following:
+
+@table @code
+@item b @var{value}
+Boolean constant. @var{value} is a numeric value; I assume it is 0 for
+false or 1 for true.
+
+@item c @var{value}
+Character constant. @var{value} is the numeric value of the constant.
+
+@item e @var{type-information} , @var{value}
+Constant whose value can be represented as integral.
+@var{type-information} is the type of the constant, as it would appear
+after a symbol descriptor (@pxref{String Field}). @var{value} is the
+numeric value of the constant. GDB 4.9 does not actually get the right
+value if @var{value} does not fit in a host @code{int}, but it does not
+do anything violent, and future debuggers could be extended to accept
+integers of any size (whether unsigned or not). This constant type is
+usually documented as being only for enumeration constants, but GDB has
+never imposed that restriction; I don't know about other debuggers.
+
+@item i @var{value}
+Integer constant. @var{value} is the numeric value. The type is some
+sort of generic integer type (for GDB, a host @code{int}); to specify
+the type explicitly, use @samp{e} instead.
+
+@item r @var{value}
+Real constant. @var{value} is the real value, which can be @samp{INF}
+(optionally preceded by a sign) for infinity, @samp{QNAN} for a quiet
+NaN (not-a-number), or @samp{SNAN} for a signalling NaN. If it is a
+normal number the format is that accepted by the C library function
+@code{atof}.
+
+@item s @var{string}
+String constant. @var{string} is a string enclosed in either @samp{'}
+(in which case @samp{'} characters within the string are represented as
+@samp{\'} or @samp{"} (in which case @samp{"} characters within the
+string are represented as @samp{\"}).
+
+@item S @var{type-information} , @var{elements} , @var{bits} , @var{pattern}
+Set constant. @var{type-information} is the type of the constant, as it
+would appear after a symbol descriptor (@pxref{String Field}).
+@var{elements} is the number of elements in the set (does this means
+how many bits of @var{pattern} are actually used, which would be
+redundant with the type, or perhaps the number of bits set in
+@var{pattern}? I don't get it), @var{bits} is the number of bits in the
+constant (meaning it specifies the length of @var{pattern}, I think),
+and @var{pattern} is a hexadecimal representation of the set. AIX
+documentation refers to a limit of 32 bytes, but I see no reason why
+this limit should exist. This form could probably be used for arbitrary
+constants, not just sets; the only catch is that @var{pattern} should be
+understood to be target, not host, byte order and format.
+@end table
+
+The boolean, character, string, and set constants are not supported by
+GDB 4.9, but it ignores them. GDB 4.8 and earlier gave an error
+message and refused to read symbols from the file containing the
+constants.
+
+The above information is followed by @samp{;}.
+
+@node Variables
+@chapter Variables
+
+Different types of stabs describe the various ways that variables can be
+allocated: on the stack, globally, in registers, in common blocks,
+statically, or as arguments to a function.
+
+@menu
+* Stack Variables:: Variables allocated on the stack.
+* Global Variables:: Variables used by more than one source file.
+* Register Variables:: Variables in registers.
+* Common Blocks:: Variables statically allocated together.
+* Statics:: Variables local to one source file.
+* Based Variables:: Fortran pointer based variables.
+* Parameters:: Variables for arguments to functions.
+@end menu
+
+@node Stack Variables
+@section Automatic Variables Allocated on the Stack
+
+If a variable's scope is local to a function and its lifetime is only as
+long as that function executes (C calls such variables
+@dfn{automatic}), it can be allocated in a register (@pxref{Register
+Variables}) or on the stack.
+
+@findex N_LSYM
+Each variable allocated on the stack has a stab with the symbol
+descriptor omitted. Since type information should begin with a digit,
+@samp{-}, or @samp{(}, only those characters precluded from being used
+for symbol descriptors. However, the Acorn RISC machine (ARM) is said
+to get this wrong: it puts out a mere type definition here, without the
+preceding @samp{@var{type-number}=}. This is a bad idea; there is no
+guarantee that type descriptors are distinct from symbol descriptors.
+Stabs for stack variables use the @code{N_LSYM} stab type.
+
+The value of the stab is the offset of the variable within the
+local variables. On most machines this is an offset from the frame
+pointer and is negative. The location of the stab specifies which block
+it is defined in; see @ref{Block Structure}.
+
+For example, the following C code:
+
+@example
+int
+main ()
+@{
+ int x;
+@}
+@end example
+
+produces the following stabs:
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+.stabs "x:1",128,0,0,-12 # @r{128 is N_LSYM}
+.stabn 192,0,0,LBB2 # @r{192 is N_LBRAC}
+.stabn 224,0,0,LBE2 # @r{224 is N_RBRAC}
+@end example
+
+@xref{Procedures} for more information on the @code{N_FUN} stab, and
+@ref{Block Structure} for more information on the @code{N_LBRAC} and
+@code{N_RBRAC} stabs.
+
+@node Global Variables
+@section Global Variables
+
+@findex N_GSYM
+A variable whose scope is not specific to just one source file is
+represented by the @samp{G} symbol descriptor. These stabs use the
+@code{N_GSYM} stab type. The type information for the stab
+(@pxref{String Field}) gives the type of the variable.
+
+For example, the following source code:
+
+@example
+char g_foo = 'c';
+@end example
+
+@noindent
+yields the following assembly code:
+
+@example
+.stabs "g_foo:G2",32,0,0,0 # @r{32 is N_GSYM}
+ .global _g_foo
+ .data
+_g_foo:
+ .byte 99
+@end example
+
+The address of the variable represented by the @code{N_GSYM} is not
+contained in the @code{N_GSYM} stab. The debugger gets this information
+from the external symbol for the global variable. In the example above,
+the @code{.global _g_foo} and @code{_g_foo:} lines tell the assembler to
+produce an external symbol.
+
+@node Register Variables
+@section Register Variables
+
+@findex N_RSYM
+@c According to an old version of this manual, AIX uses C_RPSYM instead
+@c of C_RSYM. I am skeptical; this should be verified.
+Register variables have their own stab type, @code{N_RSYM}, and their
+own symbol descriptor, @samp{r}. The stab's value is the
+number of the register where the variable data will be stored.
+@c .stabs "name:type",N_RSYM,0,RegSize,RegNumber (Sun doc)
+
+AIX defines a separate symbol descriptor @samp{d} for floating point
+registers. This seems unnecessary; why not just just give floating
+point registers different register numbers? I have not verified whether
+the compiler actually uses @samp{d}.
+
+If the register is explicitly allocated to a global variable, but not
+initialized, as in:
+
+@example
+register int g_bar asm ("%g5");
+@end example
+
+@noindent
+then the stab may be emitted at the end of the object file, with
+the other bss symbols.
+
+@node Common Blocks
+@section Common Blocks
+
+A common block is a statically allocated section of memory which can be
+referred to by several source files. It may contain several variables.
+I believe Fortran is the only language with this feature.
+
+@findex N_BCOMM
+@findex N_ECOMM
+@findex C_BCOMM
+@findex C_ECOMM
+A @code{N_BCOMM} stab begins a common block and an @code{N_ECOMM} stab
+ends it. The only field that is significant in these two stabs is the
+string, which names a normal (non-debugging) symbol that gives the
+address of the common block. According to IBM documentation, only the
+@code{N_BCOMM} has the name of the common block (even though their
+compiler actually puts it both places).
+
+@findex N_ECOML
+@findex C_ECOML
+The stabs for the members of the common block are between the
+@code{N_BCOMM} and the @code{N_ECOMM}; the value of each stab is the
+offset within the common block of that variable. IBM uses the
+@code{C_ECOML} stab type, and there is a corresponding @code{N_ECOML}
+stab type, but Sun's Fortran compiler uses @code{N_GSYM} instead. The
+variables within a common block use the @samp{V} symbol descriptor (I
+believe this is true of all Fortran variables). Other stabs (at least
+type declarations using @code{C_DECL}) can also be between the
+@code{N_BCOMM} and the @code{N_ECOMM}.
+
+@node Statics
+@section Static Variables
+
+Initialized static variables are represented by the @samp{S} and
+@samp{V} symbol descriptors. @samp{S} means file scope static, and
+@samp{V} means procedure scope static.
+
+@c This is probably not worth mentioning; it is only true on the sparc
+@c for `double' variables which although declared const are actually in
+@c the data segment (the text segment can't guarantee 8 byte alignment).
+@c (although GCC
+@c 2.4.5 has a bug in that it uses @code{N_FUN}, so neither dbx nor GDB can
+@c find the variables)
+@findex N_STSYM
+@findex N_LCSYM
+@findex N_FUN, for variables
+@findex N_ROSYM
+In a.out files, @code{N_STSYM} means the data section, @code{N_FUN}
+means the text section, and @code{N_LCSYM} means the bss section. For
+those systems with a read-only data section separate from the text
+section (Solaris), @code{N_ROSYM} means the read-only data section.
+
+For example, the source lines:
+
+@example
+static const int var_const = 5;
+static int var_init = 2;
+static int var_noinit;
+@end example
+
+@noindent
+yield the following stabs:
+
+@example
+.stabs "var_const:S1",36,0,0,_var_const # @r{36 is N_FUN}
+@dots{}
+.stabs "var_init:S1",38,0,0,_var_init # @r{38 is N_STSYM}
+@dots{}
+.stabs "var_noinit:S1",40,0,0,_var_noinit # @r{40 is N_LCSYM}
+@end example
+
+In XCOFF files, each symbol has a section number, so the stab type
+need not indicate the section.
+
+In ECOFF files, the storage class is used to specify the section, so the
+stab type need not indicate the section.
+
+In ELF files, for the SunPRO compiler version 2.0.1, symbol descriptor
+@samp{S} means that the address is absolute (the linker relocates it)
+and symbol descriptor @samp{V} means that the address is relative to the
+start of the relevant section for that compilation unit. SunPRO has
+plans to have the linker stop relocating stabs; I suspect that their the
+debugger gets the address from the corresponding ELF (not stab) symbol.
+I'm not sure how to find which symbol of that name is the right one.
+The clean way to do all this would be to have a the value of a symbol
+descriptor @samp{S} symbol be an offset relative to the start of the
+file, just like everything else, but that introduces obvious
+compatibility problems. For more information on linker stab relocation,
+@xref{Stabs In ELF}.
+
+@node Based Variables
+@section Fortran Based Variables
+
+Fortran (at least, the Sun and SGI dialects of FORTRAN-77) has a feature
+which allows allocating arrays with @code{malloc}, but which avoids
+blurring the line between arrays and pointers the way that C does. In
+stabs such a variable uses the @samp{b} symbol descriptor.
+
+For example, the Fortran declarations
+
+@example
+real foo, foo10(10), foo10_5(10,5)
+pointer (foop, foo)
+pointer (foo10p, foo10)
+pointer (foo105p, foo10_5)
+@end example
+
+produce the stabs
+
+@example
+foo:b6
+foo10:bar3;1;10;6
+foo10_5:bar3;1;5;ar3;1;10;6
+@end example
+
+In this example, @code{real} is type 6 and type 3 is an integral type
+which is the type of the subscripts of the array (probably
+@code{integer}).
+
+The @samp{b} symbol descriptor is like @samp{V} in that it denotes a
+statically allocated symbol whose scope is local to a function; see
+@xref{Statics}. The value of the symbol, instead of being the address
+of the variable itself, is the address of a pointer to that variable.
+So in the above example, the value of the @code{foo} stab is the address
+of a pointer to a real, the value of the @code{foo10} stab is the
+address of a pointer to a 10-element array of reals, and the value of
+the @code{foo10_5} stab is the address of a pointer to a 5-element array
+of 10-element arrays of reals.
+
+@node Parameters
+@section Parameters
+
+Formal parameters to a function are represented by a stab (or sometimes
+two; see below) for each parameter. The stabs are in the order in which
+the debugger should print the parameters (i.e., the order in which the
+parameters are declared in the source file). The exact form of the stab
+depends on how the parameter is being passed.
+
+@findex N_PSYM
+Parameters passed on the stack use the symbol descriptor @samp{p} and
+the @code{N_PSYM} symbol type. The value of the symbol is an offset
+used to locate the parameter on the stack; its exact meaning is
+machine-dependent, but on most machines it is an offset from the frame
+pointer.
+
+As a simple example, the code:
+
+@example
+main (argc, argv)
+ int argc;
+ char **argv;
+@end example
+
+produces the stabs:
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+.stabs "argc:p1",160,0,0,68 # @r{160 is N_PSYM}
+.stabs "argv:p20=*21=*2",160,0,0,72
+@end example
+
+The type definition of @code{argv} is interesting because it contains
+several type definitions. Type 21 is pointer to type 2 (char) and
+@code{argv} (type 20) is pointer to type 21.
+
+@c FIXME: figure out what these mean and describe them coherently.
+The following symbol descriptors are also said to go with @code{N_PSYM}.
+The value of the symbol is said to be an offset from the argument
+pointer (I'm not sure whether this is true or not).
+
+@example
+pP (<<??>>)
+pF Fortran function parameter
+X (function result variable)
+@end example
+
+@menu
+* Register Parameters::
+* Local Variable Parameters::
+* Reference Parameters::
+* Conformant Arrays::
+@end menu
+
+@node Register Parameters
+@subsection Passing Parameters in Registers
+
+If the parameter is passed in a register, then traditionally there are
+two symbols for each argument:
+
+@example
+.stabs "arg:p1" . . . ; N_PSYM
+.stabs "arg:r1" . . . ; N_RSYM
+@end example
+
+Debuggers use the second one to find the value, and the first one to
+know that it is an argument.
+
+@findex C_RPSYM
+@findex N_RSYM, for parameters
+Because that approach is kind of ugly, some compilers use symbol
+descriptor @samp{P} or @samp{R} to indicate an argument which is in a
+register. Symbol type @code{C_RPSYM} is used with @samp{R} and
+@code{N_RSYM} is used with @samp{P}. The symbol's value is
+the register number. @samp{P} and @samp{R} mean the same thing; the
+difference is that @samp{P} is a GNU invention and @samp{R} is an IBM
+(XCOFF) invention. As of version 4.9, GDB should handle either one.
+
+There is at least one case where GCC uses a @samp{p} and @samp{r} pair
+rather than @samp{P}; this is where the argument is passed in the
+argument list and then loaded into a register.
+
+According to the AIX documentation, symbol descriptor @samp{D} is for a
+parameter passed in a floating point register. This seems
+unnecessary---why not just use @samp{R} with a register number which
+indicates that it's a floating point register? I haven't verified
+whether the system actually does what the documentation indicates.
+
+@c FIXME: On the hppa this is for any type > 8 bytes, I think, and not
+@c for small structures (investigate).
+On the sparc and hppa, for a @samp{P} symbol whose type is a structure
+or union, the register contains the address of the structure. On the
+sparc, this is also true of a @samp{p} and @samp{r} pair (using Sun
+@code{cc}) or a @samp{p} symbol. However, if a (small) structure is
+really in a register, @samp{r} is used. And, to top it all off, on the
+hppa it might be a structure which was passed on the stack and loaded
+into a register and for which there is a @samp{p} and @samp{r} pair! I
+believe that symbol descriptor @samp{i} is supposed to deal with this
+case (it is said to mean "value parameter by reference, indirect
+access"; I don't know the source for this information), but I don't know
+details or what compilers or debuggers use it, if any (not GDB or GCC).
+It is not clear to me whether this case needs to be dealt with
+differently than parameters passed by reference (@pxref{Reference Parameters}).
+
+@node Local Variable Parameters
+@subsection Storing Parameters as Local Variables
+
+There is a case similar to an argument in a register, which is an
+argument that is actually stored as a local variable. Sometimes this
+happens when the argument was passed in a register and then the compiler
+stores it as a local variable. If possible, the compiler should claim
+that it's in a register, but this isn't always done.
+
+@findex N_LSYM, for parameter
+Some compilers use the pair of symbols approach described above
+(@samp{@var{arg}:p} followed by @samp{@var{arg}:}); this includes GCC1
+(not GCC2) on the sparc when passing a small structure and GCC2
+(sometimes) when the argument type is @code{float} and it is passed as a
+@code{double} and converted to @code{float} by the prologue (in the
+latter case the type of the @samp{@var{arg}:p} symbol is @code{double}
+and the type of the @samp{@var{arg}:} symbol is @code{float}).
+
+GCC, at least on the 960, has another solution to the same problem. It
+uses a single @samp{p} symbol descriptor for an argument which is stored
+as a local variable but uses @code{N_LSYM} instead of @code{N_PSYM}. In
+this case, the value of the symbol is an offset relative to the local
+variables for that function, not relative to the arguments; on some
+machines those are the same thing, but not on all.
+
+@c This is mostly just background info; the part that logically belongs
+@c here is the last sentence.
+On the VAX or on other machines in which the calling convention includes
+the number of words of arguments actually passed, the debugger (GDB at
+least) uses the parameter symbols to keep track of whether it needs to
+print nameless arguments in addition to the formal parameters which it
+has printed because each one has a stab. For example, in
+
+@example
+extern int fprintf (FILE *stream, char *format, @dots{});
+@dots{}
+fprintf (stdout, "%d\n", x);
+@end example
+
+there are stabs for @code{stream} and @code{format}. On most machines,
+the debugger can only print those two arguments (because it has no way
+of knowing that additional arguments were passed), but on the VAX or
+other machines with a calling convention which indicates the number of
+words of arguments, the debugger can print all three arguments. To do
+so, the parameter symbol (symbol descriptor @samp{p}) (not necessarily
+@samp{r} or symbol descriptor omitted symbols) needs to contain the
+actual type as passed (for example, @code{double} not @code{float} if it
+is passed as a double and converted to a float).
+
+@node Reference Parameters
+@subsection Passing Parameters by Reference
+
+If the parameter is passed by reference (e.g., Pascal @code{VAR}
+parameters), then the symbol descriptor is @samp{v} if it is in the
+argument list, or @samp{a} if it in a register. Other than the fact
+that these contain the address of the parameter rather than the
+parameter itself, they are identical to @samp{p} and @samp{R},
+respectively. I believe @samp{a} is an AIX invention; @samp{v} is
+supported by all stabs-using systems as far as I know.
+
+@node Conformant Arrays
+@subsection Passing Conformant Array Parameters
+
+@c Is this paragraph correct? It is based on piecing together patchy
+@c information and some guesswork
+Conformant arrays are a feature of Modula-2, and perhaps other
+languages, in which the size of an array parameter is not known to the
+called function until run-time. Such parameters have two stabs: a
+@samp{x} for the array itself, and a @samp{C}, which represents the size
+of the array. The value of the @samp{x} stab is the offset in the
+argument list where the address of the array is stored (it this right?
+it is a guess); the value of the @samp{C} stab is the offset in the
+argument list where the size of the array (in elements? in bytes?) is
+stored.
+
+@node Types
+@chapter Defining Types
+
+The examples so far have described types as references to previously
+defined types, or defined in terms of subranges of or pointers to
+previously defined types. This chapter describes the other type
+descriptors that may follow the @samp{=} in a type definition.
+
+@menu
+* Builtin Types:: Integers, floating point, void, etc.
+* Miscellaneous Types:: Pointers, sets, files, etc.
+* Cross-References:: Referring to a type not yet defined.
+* Subranges:: A type with a specific range.
+* Arrays:: An aggregate type of same-typed elements.
+* Strings:: Like an array but also has a length.
+* Enumerations:: Like an integer but the values have names.
+* Structures:: An aggregate type of different-typed elements.
+* Typedefs:: Giving a type a name.
+* Unions:: Different types sharing storage.
+* Function Types::
+@end menu
+
+@node Builtin Types
+@section Builtin Types
+
+Certain types are built in (@code{int}, @code{short}, @code{void},
+@code{float}, etc.); the debugger recognizes these types and knows how
+to handle them. Thus, don't be surprised if some of the following ways
+of specifying builtin types do not specify everything that a debugger
+would need to know about the type---in some cases they merely specify
+enough information to distinguish the type from other types.
+
+The traditional way to define builtin types is convolunted, so new ways
+have been invented to describe them. Sun's @code{acc} uses special
+builtin type descriptors (@samp{b} and @samp{R}), and IBM uses negative
+type numbers. GDB accepts all three ways, as of version 4.8; dbx just
+accepts the traditional builtin types and perhaps one of the other two
+formats. The following sections describe each of these formats.
+
+@menu
+* Traditional Builtin Types:: Put on your seatbelts and prepare for kludgery
+* Builtin Type Descriptors:: Builtin types with special type descriptors
+* Negative Type Numbers:: Builtin types using negative type numbers
+@end menu
+
+@node Traditional Builtin Types
+@subsection Traditional Builtin Types
+
+This is the traditional, convoluted method for defining builtin types.
+There are several classes of such type definitions: integer, floating
+point, and @code{void}.
+
+@menu
+* Traditional Integer Types::
+* Traditional Other Types::
+@end menu
+
+@node Traditional Integer Types
+@subsubsection Traditional Integer Types
+
+Often types are defined as subranges of themselves. If the bounding values
+fit within an @code{int}, then they are given normally. For example:
+
+@example
+.stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 # @r{128 is N_LSYM}
+.stabs "char:t2=r2;0;127;",128,0,0,0
+@end example
+
+Builtin types can also be described as subranges of @code{int}:
+
+@example
+.stabs "unsigned short:t6=r1;0;65535;",128,0,0,0
+@end example
+
+If the lower bound of a subrange is 0 and the upper bound is -1,
+the type is an unsigned integral type whose bounds are too
+big to describe in an @code{int}. Traditionally this is only used for
+@code{unsigned int} and @code{unsigned long}:
+
+@example
+.stabs "unsigned int:t4=r1;0;-1;",128,0,0,0
+@end example
+
+For larger types, GCC 2.4.5 puts out bounds in octal, with one or more
+leading zeroes. In this case a negative bound consists of a number
+which is a 1 bit (for the sign bit) followed by a 0 bit for each bit in
+the number (except the sign bit), and a positive bound is one which is a
+1 bit for each bit in the number (except possibly the sign bit). All
+known versions of dbx and GDB version 4 accept this (at least in the
+sense of not refusing to process the file), but GDB 3.5 refuses to read
+the whole file containing such symbols. So GCC 2.3.3 did not output the
+proper size for these types. As an example of octal bounds, the string
+fields of the stabs for 64 bit integer types look like:
+
+@c .stabs directives, etc., omitted to make it fit on the page.
+@example
+long int:t3=r1;001000000000000000000000;000777777777777777777777;
+long unsigned int:t5=r1;000000000000000000000000;001777777777777777777777;
+@end example
+
+If the lower bound of a subrange is 0 and the upper bound is negative,
+the type is an unsigned integral type whose size in bytes is the
+absolute value of the upper bound. I believe this is a Convex
+convention for @code{unsigned long long}.
+
+If the lower bound of a subrange is negative and the upper bound is 0,
+the type is a signed integral type whose size in bytes is
+the absolute value of the lower bound. I believe this is a Convex
+convention for @code{long long}. To distinguish this from a legitimate
+subrange, the type should be a subrange of itself. I'm not sure whether
+this is the case for Convex.
+
+@node Traditional Other Types
+@subsubsection Traditional Other Types
+
+If the upper bound of a subrange is 0 and the lower bound is positive,
+the type is a floating point type, and the lower bound of the subrange
+indicates the number of bytes in the type:
+
+@example
+.stabs "float:t12=r1;4;0;",128,0,0,0
+.stabs "double:t13=r1;8;0;",128,0,0,0
+@end example
+
+However, GCC writes @code{long double} the same way it writes
+@code{double}, so there is no way to distinguish.
+
+@example
+.stabs "long double:t14=r1;8;0;",128,0,0,0
+@end example
+
+Complex types are defined the same way as floating-point types; there is
+no way to distinguish a single-precision complex from a double-precision
+floating-point type.
+
+The C @code{void} type is defined as itself:
+
+@example
+.stabs "void:t15=15",128,0,0,0
+@end example
+
+I'm not sure how a boolean type is represented.
+
+@node Builtin Type Descriptors
+@subsection Defining Builtin Types Using Builtin Type Descriptors
+
+This is the method used by Sun's @code{acc} for defining builtin types.
+These are the type descriptors to define builtin types:
+
+@table @code
+@c FIXME: clean up description of width and offset, once we figure out
+@c what they mean
+@item b @var{signed} @var{char-flag} @var{width} ; @var{offset} ; @var{nbits} ;
+Define an integral type. @var{signed} is @samp{u} for unsigned or
+@samp{s} for signed. @var{char-flag} is @samp{c} which indicates this
+is a character type, or is omitted. I assume this is to distinguish an
+integral type from a character type of the same size, for example it
+might make sense to set it for the C type @code{wchar_t} so the debugger
+can print such variables differently (Solaris does not do this). Sun
+sets it on the C types @code{signed char} and @code{unsigned char} which
+arguably is wrong. @var{width} and @var{offset} appear to be for small
+objects stored in larger ones, for example a @code{short} in an
+@code{int} register. @var{width} is normally the number of bytes in the
+type. @var{offset} seems to always be zero. @var{nbits} is the number
+of bits in the type.
+
+Note that type descriptor @samp{b} used for builtin types conflicts with
+its use for Pascal space types (@pxref{Miscellaneous Types}); they can
+be distinguished because the character following the type descriptor
+will be a digit, @samp{(}, or @samp{-} for a Pascal space type, or
+@samp{u} or @samp{s} for a builtin type.
+
+@item w
+Documented by AIX to define a wide character type, but their compiler
+actually uses negative type numbers (@pxref{Negative Type Numbers}).
+
+@item R @var{fp-type} ; @var{bytes} ;
+Define a floating point type. @var{fp-type} has one of the following values:
+
+@table @code
+@item 1 (NF_SINGLE)
+IEEE 32-bit (single precision) floating point format.
+
+@item 2 (NF_DOUBLE)
+IEEE 64-bit (double precision) floating point format.
+
+@item 3 (NF_COMPLEX)
+@item 4 (NF_COMPLEX16)
+@item 5 (NF_COMPLEX32)
+@c "GDB source" really means @file{include/aout/stab_gnu.h}, but trying
+@c to put that here got an overfull hbox.
+These are for complex numbers. A comment in the GDB source describes
+them as Fortran @code{complex}, @code{double complex}, and
+@code{complex*16}, respectively, but what does that mean? (i.e., Single
+precision? Double precison?).
+
+@item 6 (NF_LDOUBLE)
+Long double. This should probably only be used for Sun format
+@code{long double}, and new codes should be used for other floating
+point formats (@code{NF_DOUBLE} can be used if a @code{long double} is
+really just an IEEE double, of course).
+@end table
+
+@var{bytes} is the number of bytes occupied by the type. This allows a
+debugger to perform some operations with the type even if it doesn't
+understand @var{fp-type}.
+
+@item g @var{type-information} ; @var{nbits}
+Documented by AIX to define a floating type, but their compiler actually
+uses negative type numbers (@pxref{Negative Type Numbers}).
+
+@item c @var{type-information} ; @var{nbits}
+Documented by AIX to define a complex type, but their compiler actually
+uses negative type numbers (@pxref{Negative Type Numbers}).
+@end table
+
+The C @code{void} type is defined as a signed integral type 0 bits long:
+@example
+.stabs "void:t19=bs0;0;0",128,0,0,0
+@end example
+The Solaris compiler seems to omit the trailing semicolon in this case.
+Getting sloppy in this way is not a swift move because if a type is
+embedded in a more complex expression it is necessary to be able to tell
+where it ends.
+
+I'm not sure how a boolean type is represented.
+
+@node Negative Type Numbers
+@subsection Negative Type Numbers
+
+This is the method used in XCOFF for defining builtin types.
+Since the debugger knows about the builtin types anyway, the idea of
+negative type numbers is simply to give a special type number which
+indicates the builtin type. There is no stab defining these types.
+
+There are several subtle issues with negative type numbers.
+
+One is the size of the type. A builtin type (for example the C types
+@code{int} or @code{long}) might have different sizes depending on
+compiler options, the target architecture, the ABI, etc. This issue
+doesn't come up for IBM tools since (so far) they just target the
+RS/6000; the sizes indicated below for each size are what the IBM
+RS/6000 tools use. To deal with differing sizes, either define separate
+negative type numbers for each size (which works but requires changing
+the debugger, and, unless you get both AIX dbx and GDB to accept the
+change, introduces an incompatibility), or use a type attribute
+(@pxref{String Field}) to define a new type with the appropriate size
+(which merely requires a debugger which understands type attributes,
+like AIX dbx). For example,
+
+@example
+.stabs "boolean:t10=@@s8;-16",128,0,0,0
+@end example
+
+defines an 8-bit boolean type, and
+
+@example
+.stabs "boolean:t10=@@s64;-16",128,0,0,0
+@end example
+
+defines a 64-bit boolean type.
+
+A similar issue is the format of the type. This comes up most often for
+floating-point types, which could have various formats (particularly
+extended doubles, which vary quite a bit even among IEEE systems).
+Again, it is best to define a new negative type number for each
+different format; changing the format based on the target system has
+various problems. One such problem is that the Alpha has both VAX and
+IEEE floating types. One can easily imagine one library using the VAX
+types and another library in the same executable using the IEEE types.
+Another example is that the interpretation of whether a boolean is true
+or false can be based on the least significant bit, most significant
+bit, whether it is zero, etc., and different compilers (or different
+options to the same compiler) might provide different kinds of boolean.
+
+The last major issue is the names of the types. The name of a given
+type depends @emph{only} on the negative type number given; these do not
+vary depending on the language, the target system, or anything else.
+One can always define separate type numbers---in the following list you
+will see for example separate @code{int} and @code{integer*4} types
+which are identical except for the name. But compatibility can be
+maintained by not inventing new negative type numbers and instead just
+defining a new type with a new name. For example:
+
+@example
+.stabs "CARDINAL:t10=-8",128,0,0,0
+@end example
+
+Here is the list of negative type numbers. The phrase @dfn{integral
+type} is used to mean twos-complement (I strongly suspect that all
+machines which use stabs use twos-complement; most machines use
+twos-complement these days).
+
+@table @code
+@item -1
+@code{int}, 32 bit signed integral type.
+
+@item -2
+@code{char}, 8 bit type holding a character. Both GDB and dbx on AIX
+treat this as signed. GCC uses this type whether @code{char} is signed
+or not, which seems like a bad idea. The AIX compiler (@code{xlc}) seems to
+avoid this type; it uses -5 instead for @code{char}.
+
+@item -3
+@code{short}, 16 bit signed integral type.
+
+@item -4
+@code{long}, 32 bit signed integral type.
+
+@item -5
+@code{unsigned char}, 8 bit unsigned integral type.
+
+@item -6
+@code{signed char}, 8 bit signed integral type.
+
+@item -7
+@code{unsigned short}, 16 bit unsigned integral type.
+
+@item -8
+@code{unsigned int}, 32 bit unsigned integral type.
+
+@item -9
+@code{unsigned}, 32 bit unsigned integral type.
+
+@item -10
+@code{unsigned long}, 32 bit unsigned integral type.
+
+@item -11
+@code{void}, type indicating the lack of a value.
+
+@item -12
+@code{float}, IEEE single precision.
+
+@item -13
+@code{double}, IEEE double precision.
+
+@item -14
+@code{long double}, IEEE double precision. The compiler claims the size
+will increase in a future release, and for binary compatibility you have
+to avoid using @code{long double}. I hope when they increase it they
+use a new negative type number.
+
+@item -15
+@code{integer}. 32 bit signed integral type.
+
+@item -16
+@code{boolean}. 32 bit type. How is the truth value encoded? Is it
+the least significant bit or is it a question of whether the whole value
+is zero or non-zero?
+
+@item -17
+@code{short real}. IEEE single precision.
+
+@item -18
+@code{real}. IEEE double precision.
+
+@item -19
+@code{stringptr}. @xref{Strings}.
+
+@item -20
+@code{character}, 8 bit unsigned character type.
+
+@item -21
+@code{logical*1}, 8 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -22
+@code{logical*2}, 16 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -23
+@code{logical*4}, 32 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -24
+@code{logical}, 32 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -25
+@code{complex}. A complex type consisting of two IEEE single-precision
+floating point values.
+
+@item -26
+@code{complex}. A complex type consisting of two IEEE double-precision
+floating point values.
+
+@item -27
+@code{integer*1}, 8 bit signed integral type.
+
+@item -28
+@code{integer*2}, 16 bit signed integral type.
+
+@item -29
+@code{integer*4}, 32 bit signed integral type.
+
+@item -30
+@code{wchar}. Wide character, 16 bits wide, unsigned (what format?
+Unicode?).
+@end table
+
+@node Miscellaneous Types
+@section Miscellaneous Types
+
+@table @code
+@item b @var{type-information} ; @var{bytes}
+Pascal space type. This is documented by IBM; what does it mean?
+
+This use of the @samp{b} type descriptor can be distinguished
+from its use for builtin integral types (@pxref{Builtin Type
+Descriptors}) because the character following the type descriptor is
+always a digit, @samp{(}, or @samp{-}.
+
+@item B @var{type-information}
+A volatile-qualified version of @var{type-information}. This is
+a Sun extension. References and stores to a variable with a
+volatile-qualified type must not be optimized or cached; they
+must occur as the user specifies them.
+
+@item d @var{type-information}
+File of type @var{type-information}. As far as I know this is only used
+by Pascal.
+
+@item k @var{type-information}
+A const-qualified version of @var{type-information}. This is a Sun
+extension. A variable with a const-qualified type cannot be modified.
+
+@item M @var{type-information} ; @var{length}
+Multiple instance type. The type seems to composed of @var{length}
+repetitions of @var{type-information}, for example @code{character*3} is
+represented by @samp{M-2;3}, where @samp{-2} is a reference to a
+character type (@pxref{Negative Type Numbers}). I'm not sure how this
+differs from an array. This appears to be a Fortran feature.
+@var{length} is a bound, like those in range types; see @ref{Subranges}.
+
+@item S @var{type-information}
+Pascal set type. @var{type-information} must be a small type such as an
+enumeration or a subrange, and the type is a bitmask whose length is
+specified by the number of elements in @var{type-information}.
+
+@item * @var{type-information}
+Pointer to @var{type-information}.
+@end table
+
+@node Cross-References
+@section Cross-References to Other Types
+
+A type can be used before it is defined; one common way to deal with
+that situation is just to use a type reference to a type which has not
+yet been defined.
+
+Another way is with the @samp{x} type descriptor, which is followed by
+@samp{s} for a structure tag, @samp{u} for a union tag, or @samp{e} for
+a enumerator tag, followed by the name of the tag, followed by @samp{:}.
+For example, the following C declarations:
+
+@example
+struct foo;
+struct foo *bar;
+@end example
+
+@noindent
+produce:
+
+@example
+.stabs "bar:G16=*17=xsfoo:",32,0,0,0
+@end example
+
+Not all debuggers support the @samp{x} type descriptor, so on some
+machines GCC does not use it. I believe that for the above example it
+would just emit a reference to type 17 and never define it, but I
+haven't verified that.
+
+Modula-2 imported types, at least on AIX, use the @samp{i} type
+descriptor, which is followed by the name of the module from which the
+type is imported, followed by @samp{:}, followed by the name of the
+type. There is then optionally a comma followed by type information for
+the type. This differs from merely naming the type (@pxref{Typedefs}) in
+that it identifies the module; I don't understand whether the name of
+the type given here is always just the same as the name we are giving
+it, or whether this type descriptor is used with a nameless stab
+(@pxref{String Field}), or what. The symbol ends with @samp{;}.
+
+@node Subranges
+@section Subrange Types
+
+The @samp{r} type descriptor defines a type as a subrange of another
+type. It is followed by type information for the type of which it is a
+subrange, a semicolon, an integral lower bound, a semicolon, an
+integral upper bound, and a semicolon. The AIX documentation does not
+specify the trailing semicolon, in an effort to specify array indexes
+more cleanly, but a subrange which is not an array index has always
+included a trailing semicolon (@pxref{Arrays}).
+
+Instead of an integer, either bound can be one of the following:
+
+@table @code
+@item A @var{offset}
+The bound is passed by reference on the stack at offset @var{offset}
+from the argument list. @xref{Parameters}, for more information on such
+offsets.
+
+@item T @var{offset}
+The bound is passed by value on the stack at offset @var{offset} from
+the argument list.
+
+@item a @var{register-number}
+The bound is pased by reference in register number
+@var{register-number}.
+
+@item t @var{register-number}
+The bound is passed by value in register number @var{register-number}.
+
+@item J
+There is no bound.
+@end table
+
+Subranges are also used for builtin types; see @ref{Traditional Builtin Types}.
+
+@node Arrays
+@section Array Types
+
+Arrays use the @samp{a} type descriptor. Following the type descriptor
+is the type of the index and the type of the array elements. If the
+index type is a range type, it ends in a semicolon; otherwise
+(for example, if it is a type reference), there does not
+appear to be any way to tell where the types are separated. In an
+effort to clean up this mess, IBM documents the two types as being
+separated by a semicolon, and a range type as not ending in a semicolon
+(but this is not right for range types which are not array indexes,
+@pxref{Subranges}). I think probably the best solution is to specify
+that a semicolon ends a range type, and that the index type and element
+type of an array are separated by a semicolon, but that if the index
+type is a range type, the extra semicolon can be omitted. GDB (at least
+through version 4.9) doesn't support any kind of index type other than a
+range anyway; I'm not sure about dbx.
+
+It is well established, and widely used, that the type of the index,
+unlike most types found in the stabs, is merely a type definition, not
+type information (@pxref{String Field}) (that is, it need not start with
+@samp{@var{type-number}=} if it is defining a new type). According to a
+comment in GDB, this is also true of the type of the array elements; it
+gives @samp{ar1;1;10;ar1;1;10;4} as a legitimate way to express a two
+dimensional array. According to AIX documentation, the element type
+must be type information. GDB accepts either.
+
+The type of the index is often a range type, expressed as the type
+descriptor @samp{r} and some parameters. It defines the size of the
+array. In the example below, the range @samp{r1;0;2;} defines an index
+type which is a subrange of type 1 (integer), with a lower bound of 0
+and an upper bound of 2. This defines the valid range of subscripts of
+a three-element C array.
+
+For example, the definition:
+
+@example
+char char_vec[3] = @{'a','b','c'@};
+@end example
+
+@noindent
+produces the output:
+
+@example
+.stabs "char_vec:G19=ar1;0;2;2",32,0,0,0
+ .global _char_vec
+ .align 4
+_char_vec:
+ .byte 97
+ .byte 98
+ .byte 99
+@end example
+
+If an array is @dfn{packed}, the elements are spaced more
+closely than normal, saving memory at the expense of speed. For
+example, an array of 3-byte objects might, if unpacked, have each
+element aligned on a 4-byte boundary, but if packed, have no padding.
+One way to specify that something is packed is with type attributes
+(@pxref{String Field}). In the case of arrays, another is to use the
+@samp{P} type descriptor instead of @samp{a}. Other than specifying a
+packed array, @samp{P} is identical to @samp{a}.
+
+@c FIXME-what is it? A pointer?
+An open array is represented by the @samp{A} type descriptor followed by
+type information specifying the type of the array elements.
+
+@c FIXME: what is the format of this type? A pointer to a vector of pointers?
+An N-dimensional dynamic array is represented by
+
+@example
+D @var{dimensions} ; @var{type-information}
+@end example
+
+@c Does dimensions really have this meaning? The AIX documentation
+@c doesn't say.
+@var{dimensions} is the number of dimensions; @var{type-information}
+specifies the type of the array elements.
+
+@c FIXME: what is the format of this type? A pointer to some offsets in
+@c another array?
+A subarray of an N-dimensional array is represented by
+
+@example
+E @var{dimensions} ; @var{type-information}
+@end example
+
+@c Does dimensions really have this meaning? The AIX documentation
+@c doesn't say.
+@var{dimensions} is the number of dimensions; @var{type-information}
+specifies the type of the array elements.
+
+@node Strings
+@section Strings
+
+Some languages, like C or the original Pascal, do not have string types,
+they just have related things like arrays of characters. But most
+Pascals and various other languages have string types, which are
+indicated as follows:
+
+@table @code
+@item n @var{type-information} ; @var{bytes}
+@var{bytes} is the maximum length. I'm not sure what
+@var{type-information} is; I suspect that it means that this is a string
+of @var{type-information} (thus allowing a string of integers, a string
+of wide characters, etc., as well as a string of characters). Not sure
+what the format of this type is. This is an AIX feature.
+
+@item z @var{type-information} ; @var{bytes}
+Just like @samp{n} except that this is a gstring, not an ordinary
+string. I don't know the difference.
+
+@item N
+Pascal Stringptr. What is this? This is an AIX feature.
+@end table
+
+@node Enumerations
+@section Enumerations
+
+Enumerations are defined with the @samp{e} type descriptor.
+
+@c FIXME: Where does this information properly go? Perhaps it is
+@c redundant with something we already explain.
+The source line below declares an enumeration type at file scope.
+The type definition is located after the @code{N_RBRAC} that marks the end of
+the previous procedure's block scope, and before the @code{N_FUN} that marks
+the beginning of the next procedure's block scope. Therefore it does not
+describe a block local symbol, but a file local one.
+
+The source line:
+
+@example
+enum e_places @{first,second=3,last@};
+@end example
+
+@noindent
+generates the following stab:
+
+@example
+.stabs "e_places:T22=efirst:0,second:3,last:4,;",128,0,0,0
+@end example
+
+The symbol descriptor (@samp{T}) says that the stab describes a
+structure, enumeration, or union tag. The type descriptor @samp{e},
+following the @samp{22=} of the type definition narrows it down to an
+enumeration type. Following the @samp{e} is a list of the elements of
+the enumeration. The format is @samp{@var{name}:@var{value},}. The
+list of elements ends with @samp{;}.
+
+There is no standard way to specify the size of an enumeration type; it
+is determined by the architecture (normally all enumerations types are
+32 bits). There should be a way to specify an enumeration type of
+another size; type attributes would be one way to do this. @xref{Stabs
+Format}.
+
+@node Structures
+@section Structures
+
+The encoding of structures in stabs can be shown with an example.
+
+The following source code declares a structure tag and defines an
+instance of the structure in global scope. Then a @code{typedef} equates the
+structure tag with a new type. Seperate stabs are generated for the
+structure tag, the structure @code{typedef}, and the structure instance. The
+stabs for the tag and the @code{typedef} are emited when the definitions are
+encountered. Since the structure elements are not initialized, the
+stab and code for the structure variable itself is located at the end
+of the program in the bss section.
+
+@example
+struct s_tag @{
+ int s_int;
+ float s_float;
+ char s_char_vec[8];
+ struct s_tag* s_next;
+@} g_an_s;
+
+typedef struct s_tag s_typedef;
+@end example
+
+The structure tag has an @code{N_LSYM} stab type because, like the
+enumeration, the symbol has file scope. Like the enumeration, the
+symbol descriptor is @samp{T}, for enumeration, structure, or tag type.
+The type descriptor @samp{s} following the @samp{16=} of the type
+definition narrows the symbol type to structure.
+
+Following the @samp{s} type descriptor is the number of bytes the
+structure occupies, followed by a description of each structure element.
+The structure element descriptions are of the form @var{name:type, bit
+offset from the start of the struct, number of bits in the element}.
+
+@c FIXME: phony line break. Can probably be fixed by using an example
+@c with fewer fields.
+@example
+# @r{128 is N_LSYM}
+.stabs "s_tag:T16=s20s_int:1,0,32;s_float:12,32,32;
+ s_char_vec:17=ar1;0;7;2,64,64;s_next:18=*16,128,32;;",128,0,0,0
+@end example
+
+In this example, the first two structure elements are previously defined
+types. For these, the type following the @samp{@var{name}:} part of the
+element description is a simple type reference. The other two structure
+elements are new types. In this case there is a type definition
+embedded after the @samp{@var{name}:}. The type definition for the
+array element looks just like a type definition for a standalone array.
+The @code{s_next} field is a pointer to the same kind of structure that
+the field is an element of. So the definition of structure type 16
+contains a type definition for an element which is a pointer to type 16.
+
+@node Typedefs
+@section Giving a Type a Name
+
+To give a type a name, use the @samp{t} symbol descriptor. The type
+is specified by the type information (@pxref{String Field}) for the stab.
+For example,
+
+@example
+.stabs "s_typedef:t16",128,0,0,0 # @r{128 is N_LSYM}
+@end example
+
+specifies that @code{s_typedef} refers to type number 16. Such stabs
+have symbol type @code{N_LSYM} (or @code{C_DECL} for XCOFF).
+
+If you are specifying the tag name for a structure, union, or
+enumeration, use the @samp{T} symbol descriptor instead. I believe C is
+the only language with this feature.
+
+If the type is an opaque type (I believe this is a Modula-2 feature),
+AIX provides a type descriptor to specify it. The type descriptor is
+@samp{o} and is followed by a name. I don't know what the name
+means---is it always the same as the name of the type, or is this type
+descriptor used with a nameless stab (@pxref{String Field})? There
+optionally follows a comma followed by type information which defines
+the type of this type. If omitted, a semicolon is used in place of the
+comma and the type information, and the type is much like a generic
+pointer type---it has a known size but little else about it is
+specified.
+
+@node Unions
+@section Unions
+
+@example
+union u_tag @{
+ int u_int;
+ float u_float;
+ char* u_char;
+@} an_u;
+@end example
+
+This code generates a stab for a union tag and a stab for a union
+variable. Both use the @code{N_LSYM} stab type. If a union variable is
+scoped locally to the procedure in which it is defined, its stab is
+located immediately preceding the @code{N_LBRAC} for the procedure's block
+start.
+
+The stab for the union tag, however, is located preceding the code for
+the procedure in which it is defined. The stab type is @code{N_LSYM}. This
+would seem to imply that the union type is file scope, like the struct
+type @code{s_tag}. This is not true. The contents and position of the stab
+for @code{u_type} do not convey any infomation about its procedure local
+scope.
+
+@c FIXME: phony line break. Can probably be fixed by using an example
+@c with fewer fields.
+@smallexample
+# @r{128 is N_LSYM}
+.stabs "u_tag:T23=u4u_int:1,0,32;u_float:12,0,32;u_char:21,0,32;;",
+ 128,0,0,0
+@end smallexample
+
+The symbol descriptor @samp{T}, following the @samp{name:} means that
+the stab describes an enumeration, structure, or union tag. The type
+descriptor @samp{u}, following the @samp{23=} of the type definition,
+narrows it down to a union type definition. Following the @samp{u} is
+the number of bytes in the union. After that is a list of union element
+descriptions. Their format is @var{name:type, bit offset into the
+union, number of bytes for the element;}.
+
+The stab for the union variable is:
+
+@example
+.stabs "an_u:23",128,0,0,-20 # @r{128 is N_LSYM}
+@end example
+
+@samp{-20} specifies where the variable is stored (@pxref{Stack
+Variables}).
+
+@node Function Types
+@section Function Types
+
+Various types can be defined for function variables. These types are
+not used in defining functions (@pxref{Procedures}); they are used for
+things like pointers to functions.
+
+The simple, traditional, type is type descriptor @samp{f} is followed by
+type information for the return type of the function, followed by a
+semicolon.
+
+This does not deal with functions for which the number and types of the
+parameters are part of the type, as in Modula-2 or ANSI C. AIX provides
+extensions to specify these, using the @samp{f}, @samp{F}, @samp{p}, and
+@samp{R} type descriptors.
+
+First comes the type descriptor. If it is @samp{f} or @samp{F}, this
+type involves a function rather than a procedure, and the type
+information for the return type of the function follows, followed by a
+comma. Then comes the number of parameters to the function and a
+semicolon. Then, for each parameter, there is the name of the parameter
+followed by a colon (this is only present for type descriptors @samp{R}
+and @samp{F} which represent Pascal function or procedure parameters),
+type information for the parameter, a comma, 0 if passed by reference or
+1 if passed by value, and a semicolon. The type definition ends with a
+semicolon.
+
+For example, this variable definition:
+
+@example
+int (*g_pf)();
+@end example
+
+@noindent
+generates the following code:
+
+@example
+.stabs "g_pf:G24=*25=f1",32,0,0,0
+ .common _g_pf,4,"bss"
+@end example
+
+The variable defines a new type, 24, which is a pointer to another new
+type, 25, which is a function returning @code{int}.
+
+@node Symbol Tables
+@chapter Symbol Information in Symbol Tables
+
+This chapter describes the format of symbol table entries
+and how stab assembler directives map to them. It also describes the
+transformations that the assembler and linker make on data from stabs.
+
+@menu
+* Symbol Table Format::
+* Transformations On Symbol Tables::
+@end menu
+
+@node Symbol Table Format
+@section Symbol Table Format
+
+Each time the assembler encounters a stab directive, it puts
+each field of the stab into a corresponding field in a symbol table
+entry of its output file. If the stab contains a string field, the
+symbol table entry for that stab points to a string table entry
+containing the string data from the stab. Assembler labels become
+relocatable addresses. Symbol table entries in a.out have the format:
+
+@c FIXME: should refer to external, not internal.
+@example
+struct internal_nlist @{
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+@};
+@end example
+
+If the stab has a string, the @code{n_strx} field holds the offset in
+bytes of the string within the string table. The string is terminated
+by a NUL character. If the stab lacks a string (for example, it was
+produced by a @code{.stabn} or @code{.stabd} directive), the
+@code{n_strx} field is zero.
+
+Symbol table entries with @code{n_type} field values greater than 0x1f
+originated as stabs generated by the compiler (with one random
+exception). The other entries were placed in the symbol table of the
+executable by the assembler or the linker.
+
+@node Transformations On Symbol Tables
+@section Transformations on Symbol Tables
+
+The linker concatenates object files and does fixups of externally
+defined symbols.
+
+You can see the transformations made on stab data by the assembler and
+linker by examining the symbol table after each pass of the build. To
+do this, use @samp{nm -ap}, which dumps the symbol table, including
+debugging information, unsorted. For stab entries the columns are:
+@var{value}, @var{other}, @var{desc}, @var{type}, @var{string}. For
+assembler and linker symbols, the columns are: @var{value}, @var{type},
+@var{string}.
+
+The low 5 bits of the stab type tell the linker how to relocate the
+value of the stab. Thus for stab types like @code{N_RSYM} and
+@code{N_LSYM}, where the value is an offset or a register number, the
+low 5 bits are @code{N_ABS}, which tells the linker not to relocate the
+value.
+
+Where the value of a stab contains an assembly language label,
+it is transformed by each build step. The assembler turns it into a
+relocatable address and the linker turns it into an absolute address.
+
+@menu
+* Transformations On Static Variables::
+* Transformations On Global Variables::
+* ELF Transformations:: In ELF, things are a bit different.
+@end menu
+
+@node Transformations On Static Variables
+@subsection Transformations on Static Variables
+
+This source line defines a static variable at file scope:
+
+@example
+static int s_g_repeat
+@end example
+
+@noindent
+The following stab describes the symbol:
+
+@example
+.stabs "s_g_repeat:S1",38,0,0,_s_g_repeat
+@end example
+
+@noindent
+The assembler transforms the stab into this symbol table entry in the
+@file{.o} file. The location is expressed as a data segment offset.
+
+@example
+00000084 - 00 0000 STSYM s_g_repeat:S1
+@end example
+
+@noindent
+In the symbol table entry from the executable, the linker has made the
+relocatable address absolute.
+
+@example
+0000e00c - 00 0000 STSYM s_g_repeat:S1
+@end example
+
+@node Transformations On Global Variables
+@subsection Transformations on Global Variables
+
+Stabs for global variables do not contain location information. In
+this case, the debugger finds location information in the assembler or
+linker symbol table entry describing the variable. The source line:
+
+@example
+char g_foo = 'c';
+@end example
+
+@noindent
+generates the stab:
+
+@example
+.stabs "g_foo:G2",32,0,0,0
+@end example
+
+The variable is represented by two symbol table entries in the object
+file (see below). The first one originated as a stab. The second one
+is an external symbol. The upper case @samp{D} signifies that the
+@code{n_type} field of the symbol table contains 7, @code{N_DATA} with
+local linkage. The stab's value is zero since the value is not used for
+@code{N_GSYM} stabs. The value of the linker symbol is the relocatable
+address corresponding to the variable.
+
+@example
+00000000 - 00 0000 GSYM g_foo:G2
+00000080 D _g_foo
+@end example
+
+@noindent
+These entries as transformed by the linker. The linker symbol table
+entry now holds an absolute address:
+
+@example
+00000000 - 00 0000 GSYM g_foo:G2
+@dots{}
+0000e008 D _g_foo
+@end example
+
+@node ELF Transformations
+@subsection Transformations of Stabs in ELF Files
+
+For ELF files, use @code{objdump --stabs} instead of @code{nm} to show
+the stabs in an object or executable file. @code{objdump} is a GNU
+utility; Sun does not provide any equivalent.
+
+The following example is for a stab whose value is an address is
+relative to the compilation unit (@pxref{Stabs In ELF}). For example,
+if the source line
+
+@example
+static int ld = 5;
+@end example
+
+appears within a function, then the assembly language output from the
+compiler contains:
+
+@example
+.Ddata.data:
+@dots{}
+ .stabs "ld:V(0,3)",0x26,0,4,.L18-Ddata.data # @r{0x26 is N_STSYM}
+@dots{}
+.L18:
+ .align 4
+ .word 0x5
+@end example
+
+Because the value is formed by subtracting one symbol from another, the
+value is absolute, not relocatable, and so the object file contains
+
+@example
+Symnum n_type n_othr n_desc n_value n_strx String
+31 STSYM 0 4 00000004 680 ld:V(0,3)
+@end example
+
+without any relocations, and the executable file also contains
+
+@example
+Symnum n_type n_othr n_desc n_value n_strx String
+31 STSYM 0 4 00000004 680 ld:V(0,3)
+@end example
+
+@node Cplusplus
+@chapter GNU C++ Stabs
+
+@menu
+* Basic Cplusplus Types::
+* Simple Classes::
+* Class Instance::
+* Methods:: Method definition
+* Protections::
+* Method Modifiers::
+* Virtual Methods::
+* Inheritence::
+* Virtual Base Classes::
+* Static Members::
+@end menu
+
+Type descriptors added for C++ descriptions:
+
+@table @code
+@item #
+method type (@code{##} if minimal debug)
+
+@item @@
+Member (class and variable) type. It is followed by type information
+for the offset basetype, a comma, and type information for the type of
+the field being pointed to. (FIXME: this is acknowledged to be
+gibberish. Can anyone say what really goes here?).
+
+Note that there is a conflict between this and type attributes
+(@pxref{String Field}); both use type descriptor @samp{@@}.
+Fortunately, the @samp{@@} type descriptor used in this C++ sense always
+will be followed by a digit, @samp{(}, or @samp{-}, and type attributes
+never start with those things.
+@end table
+
+@node Basic Cplusplus Types
+@section Basic Types For C++
+
+<< the examples that follow are based on a01.C >>
+
+
+C++ adds two more builtin types to the set defined for C. These are
+the unknown type and the vtable record type. The unknown type, type
+16, is defined in terms of itself like the void type.
+
+The vtable record type, type 17, is defined as a structure type and
+then as a structure tag. The structure has four fields: delta, index,
+pfn, and delta2. pfn is the function pointer.
+
+<< In boilerplate $vtbl_ptr_type, what are the fields delta,
+index, and delta2 used for? >>
+
+This basic type is present in all C++ programs even if there are no
+virtual methods defined.
+
+@display
+.stabs "struct_name:sym_desc(type)type_def(17)=type_desc(struct)struct_bytes(8)
+ elem_name(delta):type_ref(short int),bit_offset(0),field_bits(16);
+ elem_name(index):type_ref(short int),bit_offset(16),field_bits(16);
+ elem_name(pfn):type_def(18)=type_desc(ptr to)type_ref(void),
+ bit_offset(32),field_bits(32);
+ elem_name(delta2):type_def(short int);bit_offset(32),field_bits(16);;"
+ N_LSYM, NIL, NIL
+@end display
+
+@smallexample
+.stabs "$vtbl_ptr_type:t17=s8
+ delta:6,0,16;index:6,16,16;pfn:18=*15,32,32;delta2:6,32,16;;"
+ ,128,0,0,0
+@end smallexample
+
+@display
+.stabs "name:sym_dec(struct tag)type_ref($vtbl_ptr_type)",N_LSYM,NIL,NIL,NIL
+@end display
+
+@example
+.stabs "$vtbl_ptr_type:T17",128,0,0,0
+@end example
+
+@node Simple Classes
+@section Simple Class Definition
+
+The stabs describing C++ language features are an extension of the
+stabs describing C. Stabs representing C++ class types elaborate
+extensively on the stab format used to describe structure types in C.
+Stabs representing class type variables look just like stabs
+representing C language variables.
+
+Consider the following very simple class definition.
+
+@example
+class baseA @{
+public:
+ int Adat;
+ int Ameth(int in, char other);
+@};
+@end example
+
+The class @code{baseA} is represented by two stabs. The first stab describes
+the class as a structure type. The second stab describes a structure
+tag of the class type. Both stabs are of stab type @code{N_LSYM}. Since the
+stab is not located between an @code{N_FUN} and an @code{N_LBRAC} stab this indicates
+that the class is defined at file scope. If it were, then the @code{N_LSYM}
+would signify a local variable.
+
+A stab describing a C++ class type is similar in format to a stab
+describing a C struct, with each class member shown as a field in the
+structure. The part of the struct format describing fields is
+expanded to include extra information relevent to C++ class members.
+In addition, if the class has multiple base classes or virtual
+functions the struct format outside of the field parts is also
+augmented.
+
+In this simple example the field part of the C++ class stab
+representing member data looks just like the field part of a C struct
+stab. The section on protections describes how its format is
+sometimes extended for member data.
+
+The field part of a C++ class stab representing a member function
+differs substantially from the field part of a C struct stab. It
+still begins with @samp{name:} but then goes on to define a new type number
+for the member function, describe its return type, its argument types,
+its protection level, any qualifiers applied to the method definition,
+and whether the method is virtual or not. If the method is virtual
+then the method description goes on to give the vtable index of the
+method, and the type number of the first base class defining the
+method.
+
+When the field name is a method name it is followed by two colons rather
+than one. This is followed by a new type definition for the method.
+This is a number followed by an equal sign and the type descriptor
+@samp{#}, indicating a method type, and a second @samp{#}, indicating
+that this is the @dfn{minimal} type of method definition used by GCC2,
+not larger method definitions used by earlier versions of GCC. This is
+followed by a type reference showing the return type of the method and a
+semi-colon.
+
+The format of an overloaded operator method name differs from that of
+other methods. It is @samp{op$::@var{operator-name}.} where
+@var{operator-name} is the operator name such as @samp{+} or @samp{+=}.
+The name ends with a period, and any characters except the period can
+occur in the @var{operator-name} string.
+
+The next part of the method description represents the arguments to the
+method, preceeded by a colon and ending with a semi-colon. The types of
+the arguments are expressed in the same way argument types are expressed
+in C++ name mangling. In this example an @code{int} and a @code{char}
+map to @samp{ic}.
+
+This is followed by a number, a letter, and an asterisk or period,
+followed by another semicolon. The number indicates the protections
+that apply to the member function. Here the 2 means public. The
+letter encodes any qualifier applied to the method definition. In
+this case, @samp{A} means that it is a normal function definition. The dot
+shows that the method is not virtual. The sections that follow
+elaborate further on these fields and describe the additional
+information present for virtual methods.
+
+
+@display
+.stabs "class_name:sym_desc(type)type_def(20)=type_desc(struct)struct_bytes(4)
+ field_name(Adat):type(int),bit_offset(0),field_bits(32);
+
+ method_name(Ameth)::type_def(21)=type_desc(method)return_type(int);
+ :arg_types(int char);
+ protection(public)qualifier(normal)virtual(no);;"
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "baseA:t20=s4Adat:1,0,32;Ameth::21=##1;:ic;2A.;;",128,0,0,0
+
+.stabs "class_name:sym_desc(struct tag)",N_LSYM,NIL,NIL,NIL
+
+.stabs "baseA:T20",128,0,0,0
+@end smallexample
+
+@node Class Instance
+@section Class Instance
+
+As shown above, describing even a simple C++ class definition is
+accomplished by massively extending the stab format used in C to
+describe structure types. However, once the class is defined, C stabs
+with no modifications can be used to describe class instances. The
+following source:
+
+@example
+main () @{
+ baseA AbaseA;
+@}
+@end example
+
+@noindent
+yields the following stab describing the class instance. It looks no
+different from a standard C stab describing a local variable.
+
+@display
+.stabs "name:type_ref(baseA)", N_LSYM, NIL, NIL, frame_ptr_offset
+@end display
+
+@example
+.stabs "AbaseA:20",128,0,0,-20
+@end example
+
+@node Methods
+@section Method Definition
+
+The class definition shown above declares Ameth. The C++ source below
+defines Ameth:
+
+@example
+int
+baseA::Ameth(int in, char other)
+@{
+ return in;
+@};
+@end example
+
+
+This method definition yields three stabs following the code of the
+method. One stab describes the method itself and following two describe
+its parameters. Although there is only one formal argument all methods
+have an implicit argument which is the @code{this} pointer. The @code{this}
+pointer is a pointer to the object on which the method was called. Note
+that the method name is mangled to encode the class name and argument
+types. Name mangling is described in the @sc{arm} (@cite{The Annotated
+C++ Reference Manual}, by Ellis and Stroustrup, @sc{isbn}
+0-201-51459-1); @file{gpcompare.texi} in Cygnus GCC distributions
+describes the differences between GNU mangling and @sc{arm}
+mangling.
+@c FIXME: Use @xref, especially if this is generally installed in the
+@c info tree.
+@c FIXME: This information should be in a net release, either of GCC or
+@c GDB. But gpcompare.texi doesn't seem to be in the FSF GCC.
+
+@example
+.stabs "name:symbol_desriptor(global function)return_type(int)",
+ N_FUN, NIL, NIL, code_addr_of_method_start
+
+.stabs "Ameth__5baseAic:F1",36,0,0,_Ameth__5baseAic
+@end example
+
+Here is the stab for the @code{this} pointer implicit argument. The
+name of the @code{this} pointer is always @code{this}. Type 19, the
+@code{this} pointer is defined as a pointer to type 20, @code{baseA},
+but a stab defining @code{baseA} has not yet been emited. Since the
+compiler knows it will be emited shortly, here it just outputs a cross
+reference to the undefined symbol, by prefixing the symbol name with
+@samp{xs}.
+
+@example
+.stabs "name:sym_desc(register param)type_def(19)=
+ type_desc(ptr to)type_ref(baseA)=
+ type_desc(cross-reference to)baseA:",N_RSYM,NIL,NIL,register_number
+
+.stabs "this:P19=*20=xsbaseA:",64,0,0,8
+@end example
+
+The stab for the explicit integer argument looks just like a parameter
+to a C function. The last field of the stab is the offset from the
+argument pointer, which in most systems is the same as the frame
+pointer.
+
+@example
+.stabs "name:sym_desc(value parameter)type_ref(int)",
+ N_PSYM,NIL,NIL,offset_from_arg_ptr
+
+.stabs "in:p1",160,0,0,72
+@end example
+
+<< The examples that follow are based on A1.C >>
+
+@node Protections
+@section Protections
+
+
+In the simple class definition shown above all member data and
+functions were publicly accessable. The example that follows
+contrasts public, protected and privately accessable fields and shows
+how these protections are encoded in C++ stabs.
+
+@c FIXME: What does "part of the string" mean?
+Protections for class member data are signified by two characters
+embedded in the stab defining the class type. These characters are
+located after the name: part of the string. @samp{/0} means private,
+@samp{/1} means protected, and @samp{/2} means public. If these
+characters are omited this means that the member is public. The
+following C++ source:
+
+@example
+class all_data @{
+private:
+ int priv_dat;
+protected:
+ char prot_dat;
+public:
+ float pub_dat;
+@};
+@end example
+
+@noindent
+generates the following stab to describe the class type all_data.
+
+@display
+.stabs "class_name:sym_desc(type)type_def(19)=type_desc(struct)struct_bytes
+ data_name:/protection(private)type_ref(int),bit_offset,num_bits;
+ data_name:/protection(protected)type_ref(char),bit_offset,num_bits;
+ data_name:(/num omited, private)type_ref(float),bit_offset,num_bits;;"
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "all_data:t19=s12
+ priv_dat:/01,0,32;prot_dat:/12,32,8;pub_dat:12,64,32;;",128,0,0,0
+@end smallexample
+
+Protections for member functions are signified by one digit embeded in
+the field part of the stab describing the method. The digit is 0 if
+private, 1 if protected and 2 if public. Consider the C++ class
+definition below:
+
+@example
+class all_methods @{
+private:
+ int priv_meth(int in)@{return in;@};
+protected:
+ char protMeth(char in)@{return in;@};
+public:
+ float pubMeth(float in)@{return in;@};
+@};
+@end example
+
+It generates the following stab. The digit in question is to the left
+of an @samp{A} in each case. Notice also that in this case two symbol
+descriptors apply to the class name struct tag and struct type.
+
+@display
+.stabs "class_name:sym_desc(struct tag&type)type_def(21)=
+ sym_desc(struct)struct_bytes(1)
+ meth_name::type_def(22)=sym_desc(method)returning(int);
+ :args(int);protection(private)modifier(normal)virtual(no);
+ meth_name::type_def(23)=sym_desc(method)returning(char);
+ :args(char);protection(protected)modifier(normal)virual(no);
+ meth_name::type_def(24)=sym_desc(method)returning(float);
+ :args(float);protection(public)modifier(normal)virtual(no);;",
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "all_methods:Tt21=s1priv_meth::22=##1;:i;0A.;protMeth::23=##2;:c;1A.;
+ pubMeth::24=##12;:f;2A.;;",128,0,0,0
+@end smallexample
+
+@node Method Modifiers
+@section Method Modifiers (@code{const}, @code{volatile}, @code{const volatile})
+
+<< based on a6.C >>
+
+In the class example described above all the methods have the normal
+modifier. This method modifier information is located just after the
+protection information for the method. This field has four possible
+character values. Normal methods use @samp{A}, const methods use
+@samp{B}, volatile methods use @samp{C}, and const volatile methods use
+@samp{D}. Consider the class definition below:
+
+@example
+class A @{
+public:
+ int ConstMeth (int arg) const @{ return arg; @};
+ char VolatileMeth (char arg) volatile @{ return arg; @};
+ float ConstVolMeth (float arg) const volatile @{return arg; @};
+@};
+@end example
+
+This class is described by the following stab:
+
+@display
+.stabs "class(A):sym_desc(struct)type_def(20)=type_desc(struct)struct_bytes(1)
+ meth_name(ConstMeth)::type_def(21)sym_desc(method)
+ returning(int);:arg(int);protection(public)modifier(const)virtual(no);
+ meth_name(VolatileMeth)::type_def(22)=sym_desc(method)
+ returning(char);:arg(char);protection(public)modifier(volatile)virt(no)
+ meth_name(ConstVolMeth)::type_def(23)=sym_desc(method)
+ returning(float);:arg(float);protection(public)modifer(const volatile)
+ virtual(no);;", @dots{}
+@end display
+
+@example
+.stabs "A:T20=s1ConstMeth::21=##1;:i;2B.;VolatileMeth::22=##2;:c;2C.;
+ ConstVolMeth::23=##12;:f;2D.;;",128,0,0,0
+@end example
+
+@node Virtual Methods
+@section Virtual Methods
+
+<< The following examples are based on a4.C >>
+
+The presence of virtual methods in a class definition adds additional
+data to the class description. The extra data is appended to the
+description of the virtual method and to the end of the class
+description. Consider the class definition below:
+
+@example
+class A @{
+public:
+ int Adat;
+ virtual int A_virt (int arg) @{ return arg; @};
+@};
+@end example
+
+This results in the stab below describing class A. It defines a new
+type (20) which is an 8 byte structure. The first field of the class
+struct is @samp{Adat}, an integer, starting at structure offset 0 and
+occupying 32 bits.
+
+The second field in the class struct is not explicitly defined by the
+C++ class definition but is implied by the fact that the class
+contains a virtual method. This field is the vtable pointer. The
+name of the vtable pointer field starts with @samp{$vf} and continues with a
+type reference to the class it is part of. In this example the type
+reference for class A is 20 so the name of its vtable pointer field is
+@samp{$vf20}, followed by the usual colon.
+
+Next there is a type definition for the vtable pointer type (21).
+This is in turn defined as a pointer to another new type (22).
+
+Type 22 is the vtable itself, which is defined as an array, indexed by
+a range of integers between 0 and 1, and whose elements are of type
+17. Type 17 was the vtable record type defined by the boilerplate C++
+type definitions, as shown earlier.
+
+The bit offset of the vtable pointer field is 32. The number of bits
+in the field are not specified when the field is a vtable pointer.
+
+Next is the method definition for the virtual member function @code{A_virt}.
+Its description starts out using the same format as the non-virtual
+member functions described above, except instead of a dot after the
+@samp{A} there is an asterisk, indicating that the function is virtual.
+Since is is virtual some addition information is appended to the end
+of the method description.
+
+The first number represents the vtable index of the method. This is a
+32 bit unsigned number with the high bit set, followed by a
+semi-colon.
+
+The second number is a type reference to the first base class in the
+inheritence hierarchy defining the virtual member function. In this
+case the class stab describes a base class so the virtual function is
+not overriding any other definition of the method. Therefore the
+reference is to the type number of the class that the stab is
+describing (20).
+
+This is followed by three semi-colons. One marks the end of the
+current sub-section, one marks the end of the method field, and the
+third marks the end of the struct definition.
+
+For classes containing virtual functions the very last section of the
+string part of the stab holds a type reference to the first base
+class. This is preceeded by @samp{~%} and followed by a final semi-colon.
+
+@display
+.stabs "class_name(A):type_def(20)=sym_desc(struct)struct_bytes(8)
+ field_name(Adat):type_ref(int),bit_offset(0),field_bits(32);
+ field_name(A virt func ptr):type_def(21)=type_desc(ptr to)type_def(22)=
+ sym_desc(array)index_type_ref(range of int from 0 to 1);
+ elem_type_ref(vtbl elem type),
+ bit_offset(32);
+ meth_name(A_virt)::typedef(23)=sym_desc(method)returning(int);
+ :arg_type(int),protection(public)normal(yes)virtual(yes)
+ vtable_index(1);class_first_defining(A);;;~%first_base(A);",
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@c FIXME: bogus line break.
+@example
+.stabs "A:t20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32;
+ A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0
+@end example
+
+@node Inheritence
+@section Inheritence
+
+Stabs describing C++ derived classes include additional sections that
+describe the inheritence hierarchy of the class. A derived class stab
+also encodes the number of base classes. For each base class it tells
+if the base class is virtual or not, and if the inheritence is private
+or public. It also gives the offset into the object of the portion of
+the object corresponding to each base class.
+
+This additional information is embeded in the class stab following the
+number of bytes in the struct. First the number of base classes
+appears bracketed by an exclamation point and a comma.
+
+Then for each base type there repeats a series: two digits, a number,
+a comma, another number, and a semi-colon.
+
+The first of the two digits is 1 if the base class is virtual and 0 if
+not. The second digit is 2 if the derivation is public and 0 if not.
+
+The number following the first two digits is the offset from the start
+of the object to the part of the object pertaining to the base class.
+
+After the comma, the second number is a type_descriptor for the base
+type. Finally a semi-colon ends the series, which repeats for each
+base class.
+
+The source below defines three base classes @code{A}, @code{B}, and
+@code{C} and the derived class @code{D}.
+
+
+@example
+class A @{
+public:
+ int Adat;
+ virtual int A_virt (int arg) @{ return arg; @};
+@};
+
+class B @{
+public:
+ int B_dat;
+ virtual int B_virt (int arg) @{return arg; @};
+@};
+
+class C @{
+public:
+ int Cdat;
+ virtual int C_virt (int arg) @{return arg; @};
+@};
+
+class D : A, virtual B, public C @{
+public:
+ int Ddat;
+ virtual int A_virt (int arg ) @{ return arg+1; @};
+ virtual int B_virt (int arg) @{ return arg+2; @};
+ virtual int C_virt (int arg) @{ return arg+3; @};
+ virtual int D_virt (int arg) @{ return arg; @};
+@};
+@end example
+
+Class stabs similar to the ones described earlier are generated for
+each base class.
+
+@c FIXME!!! the linebreaks in the following example probably make the
+@c examples literally unusable, but I don't know any other way to get
+@c them on the page.
+@c One solution would be to put some of the type definitions into
+@c separate stabs, even if that's not exactly what the compiler actually
+@c emits.
+@smallexample
+.stabs "A:T20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32;
+ A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0
+
+.stabs "B:Tt25=s8Bdat:1,0,32;$vf25:21,32;B_virt::26=##1;
+ :i;2A*-2147483647;25;;;~%25;",128,0,0,0
+
+.stabs "C:Tt28=s8Cdat:1,0,32;$vf28:21,32;C_virt::29=##1;
+ :i;2A*-2147483647;28;;;~%28;",128,0,0,0
+@end smallexample
+
+In the stab describing derived class @code{D} below, the information about
+the derivation of this class is encoded as follows.
+
+@display
+.stabs "derived_class_name:symbol_descriptors(struct tag&type)=
+ type_descriptor(struct)struct_bytes(32)!num_bases(3),
+ base_virtual(no)inheritence_public(no)base_offset(0),
+ base_class_type_ref(A);
+ base_virtual(yes)inheritence_public(no)base_offset(NIL),
+ base_class_type_ref(B);
+ base_virtual(no)inheritence_public(yes)base_offset(64),
+ base_class_type_ref(C); @dots{}
+@end display
+
+@c FIXME! fake linebreaks.
+@smallexample
+.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:
+ 1,160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt:
+ :32:i;2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;
+ 28;;D_virt::32:i;2A*-2147483646;31;;;~%20;",128,0,0,0
+@end smallexample
+
+@node Virtual Base Classes
+@section Virtual Base Classes
+
+A derived class object consists of a concatination in memory of the data
+areas defined by each base class, starting with the leftmost and ending
+with the rightmost in the list of base classes. The exception to this
+rule is for virtual inheritence. In the example above, class @code{D}
+inherits virtually from base class @code{B}. This means that an
+instance of a @code{D} object will not contain its own @code{B} part but
+merely a pointer to a @code{B} part, known as a virtual base pointer.
+
+In a derived class stab, the base offset part of the derivation
+information, described above, shows how the base class parts are
+ordered. The base offset for a virtual base class is always given as 0.
+Notice that the base offset for @code{B} is given as 0 even though
+@code{B} is not the first base class. The first base class @code{A}
+starts at offset 0.
+
+The field information part of the stab for class @code{D} describes the field
+which is the pointer to the virtual base class @code{B}. The vbase pointer
+name is @samp{$vb} followed by a type reference to the virtual base class.
+Since the type id for @code{B} in this example is 25, the vbase pointer name
+is @samp{$vb25}.
+
+@c FIXME!! fake linebreaks below
+@smallexample
+.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:1,
+ 160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt::32:i;
+ 2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;28;;D_virt:
+ :32:i;2A*-2147483646;31;;;~%20;",128,0,0,0
+@end smallexample
+
+Following the name and a semicolon is a type reference describing the
+type of the virtual base class pointer, in this case 24. Type 24 was
+defined earlier as the type of the @code{B} class @code{this} pointer. The
+@code{this} pointer for a class is a pointer to the class type.
+
+@example
+.stabs "this:P24=*25=xsB:",64,0,0,8
+@end example
+
+Finally the field offset part of the vbase pointer field description
+shows that the vbase pointer is the first field in the @code{D} object,
+before any data fields defined by the class. The layout of a @code{D}
+class object is a follows, @code{Adat} at 0, the vtable pointer for
+@code{A} at 32, @code{Cdat} at 64, the vtable pointer for C at 96, the
+virtual base pointer for @code{B} at 128, and @code{Ddat} at 160.
+
+
+@node Static Members
+@section Static Members
+
+The data area for a class is a concatenation of the space used by the
+data members of the class. If the class has virtual methods, a vtable
+pointer follows the class data. The field offset part of each field
+description in the class stab shows this ordering.
+
+<< How is this reflected in stabs? See Cygnus bug #677 for some info. >>
+
+@node Stab Types
+@appendix Table of Stab Types
+
+The following are all the possible values for the stab type field, for
+@code{a.out} files, in numeric order. This does not apply to XCOFF, but
+it does apply to stabs in ELF. Stabs in ECOFF use these values but add
+0x8f300 to distinguish them from non-stab symbols.
+
+The symbolic names are defined in the file @file{include/aout/stabs.def}.
+
+@menu
+* Non-Stab Symbol Types:: Types from 0 to 0x1f
+* Stab Symbol Types:: Types from 0x20 to 0xff
+@end menu
+
+@node Non-Stab Symbol Types
+@appendixsec Non-Stab Symbol Types
+
+The following types are used by the linker and assembler, not by stab
+directives. Since this document does not attempt to describe aspects of
+object file format other than the debugging format, no details are
+given.
+
+@c Try to get most of these to fit on a single line.
+@iftex
+@tableindent=1.5in
+@end iftex
+
+@table @code
+@item 0x0 N_UNDF
+Undefined symbol
+
+@item 0x2 N_ABS
+File scope absolute symbol
+
+@item 0x3 N_ABS | N_EXT
+External absolute symbol
+
+@item 0x4 N_TEXT
+File scope text symbol
+
+@item 0x5 N_TEXT | N_EXT
+External text symbol
+
+@item 0x6 N_DATA
+File scope data symbol
+
+@item 0x7 N_DATA | N_EXT
+External data symbol
+
+@item 0x8 N_BSS
+File scope BSS symbol
+
+@item 0x9 N_BSS | N_EXT
+External BSS symbol
+
+@item 0x0c N_FN_SEQ
+Same as @code{N_FN}, for Sequent compilers
+
+@item 0x0a N_INDR
+Symbol is indirected to another symbol
+
+@item 0x12 N_COMM
+Common---visible after shared library dynamic link
+
+@item 0x14 N_SETA
+Absolute set element
+
+@item 0x16 N_SETT
+Text segment set element
+
+@item 0x18 N_SETD
+Data segment set element
+
+@item 0x1a N_SETB
+BSS segment set element
+
+@item 0x1c N_SETV
+Pointer to set vector
+
+@item 0x1e N_WARNING
+Print a warning message during linking
+
+@item 0x1f N_FN
+File name of a @file{.o} file
+@end table
+
+@node Stab Symbol Types
+@appendixsec Stab Symbol Types
+
+The following symbol types indicate that this is a stab. This is the
+full list of stab numbers, including stab types that are used in
+languages other than C.
+
+@table @code
+@item 0x20 N_GSYM
+Global symbol; see @ref{Global Variables}.
+
+@item 0x22 N_FNAME
+Function name (for BSD Fortran); see @ref{Procedures}.
+
+@item 0x24 N_FUN
+Function name (@pxref{Procedures}) or text segment variable
+(@pxref{Statics}).
+
+@item 0x26 N_STSYM
+Data segment file-scope variable; see @ref{Statics}.
+
+@item 0x28 N_LCSYM
+BSS segment file-scope variable; see @ref{Statics}.
+
+@item 0x2a N_MAIN
+Name of main routine; see @ref{Main Program}.
+
+@item 0x2c N_ROSYM
+Variable in @code{.rodata} section; see @ref{Statics}.
+
+@item 0x30 N_PC
+Global symbol (for Pascal); see @ref{N_PC}.
+
+@item 0x32 N_NSYMS
+Number of symbols (according to Ultrix V4.0); see @ref{N_NSYMS}.
+
+@item 0x34 N_NOMAP
+No DST map; see @ref{N_NOMAP}.
+
+@c FIXME: describe this solaris feature in the body of the text (see
+@c comments in include/aout/stab.def).
+@item 0x38 N_OBJ
+Object file (Solaris2).
+
+@c See include/aout/stab.def for (a little) more info.
+@item 0x3c N_OPT
+Debugger options (Solaris2).
+
+@item 0x40 N_RSYM
+Register variable; see @ref{Register Variables}.
+
+@item 0x42 N_M2C
+Modula-2 compilation unit; see @ref{N_M2C}.
+
+@item 0x44 N_SLINE
+Line number in text segment; see @ref{Line Numbers}.
+
+@item 0x46 N_DSLINE
+Line number in data segment; see @ref{Line Numbers}.
+
+@item 0x48 N_BSLINE
+Line number in bss segment; see @ref{Line Numbers}.
+
+@item 0x48 N_BROWS
+Sun source code browser, path to @file{.cb} file; see @ref{N_BROWS}.
+
+@item 0x4a N_DEFD
+GNU Modula2 definition module dependency; see @ref{N_DEFD}.
+
+@item 0x4c N_FLINE
+Function start/body/end line numbers (Solaris2).
+
+@item 0x50 N_EHDECL
+GNU C++ exception variable; see @ref{N_EHDECL}.
+
+@item 0x50 N_MOD2
+Modula2 info "for imc" (according to Ultrix V4.0); see @ref{N_MOD2}.
+
+@item 0x54 N_CATCH
+GNU C++ @code{catch} clause; see @ref{N_CATCH}.
+
+@item 0x60 N_SSYM
+Structure of union element; see @ref{N_SSYM}.
+
+@item 0x62 N_ENDM
+Last stab for module (Solaris2).
+
+@item 0x64 N_SO
+Path and name of source file; see @ref{Source Files}.
+
+@item 0x80 N_LSYM
+Stack variable (@pxref{Stack Variables}) or type (@pxref{Typedefs}).
+
+@item 0x82 N_BINCL
+Beginning of an include file (Sun only); see @ref{Include Files}.
+
+@item 0x84 N_SOL
+Name of include file; see @ref{Include Files}.
+
+@item 0xa0 N_PSYM
+Parameter variable; see @ref{Parameters}.
+
+@item 0xa2 N_EINCL
+End of an include file; see @ref{Include Files}.
+
+@item 0xa4 N_ENTRY
+Alternate entry point; see @ref{N_ENTRY}.
+
+@item 0xc0 N_LBRAC
+Beginning of a lexical block; see @ref{Block Structure}.
+
+@item 0xc2 N_EXCL
+Place holder for a deleted include file; see @ref{Include Files}.
+
+@item 0xc4 N_SCOPE
+Modula2 scope information (Sun linker); see @ref{N_SCOPE}.
+
+@item 0xe0 N_RBRAC
+End of a lexical block; see @ref{Block Structure}.
+
+@item 0xe2 N_BCOMM
+Begin named common block; see @ref{Common Blocks}.
+
+@item 0xe4 N_ECOMM
+End named common block; see @ref{Common Blocks}.
+
+@item 0xe8 N_ECOML
+Member of a common block; see @ref{Common Blocks}.
+
+@c FIXME: How does this really work? Move it to main body of document.
+@item 0xea N_WITH
+Pascal @code{with} statement: type,,0,0,offset (Solaris2).
+
+@item 0xf0 N_NBTEXT
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf2 N_NBDATA
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf4 N_NBBSS
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf6 N_NBSTS
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf8 N_NBLCS
+Gould non-base registers; see @ref{Gould}.
+@end table
+
+@c Restore the default table indent
+@iftex
+@tableindent=.8in
+@end iftex
+
+@node Symbol Descriptors
+@appendix Table of Symbol Descriptors
+
+The symbol descriptor is the character which follows the colon in many
+stabs, and which tells what kind of stab it is. @xref{String Field},
+for more information about their use.
+
+@c Please keep this alphabetical
+@table @code
+@c In TeX, this looks great, digit is in italics. But makeinfo insists
+@c on putting it in `', not realizing that @var should override @code.
+@c I don't know of any way to make makeinfo do the right thing. Seems
+@c like a makeinfo bug to me.
+@item @var{digit}
+@itemx (
+@itemx -
+Variable on the stack; see @ref{Stack Variables}.
+
+@item a
+Parameter passed by reference in register; see @ref{Reference Parameters}.
+
+@item b
+Based variable; see @ref{Based Variables}.
+
+@item c
+Constant; see @ref{Constants}.
+
+@item C
+Conformant array bound (Pascal, maybe other languages); @ref{Conformant
+Arrays}. Name of a caught exception (GNU C++). These can be
+distinguished because the latter uses @code{N_CATCH} and the former uses
+another symbol type.
+
+@item d
+Floating point register variable; see @ref{Register Variables}.
+
+@item D
+Parameter in floating point register; see @ref{Register Parameters}.
+
+@item f
+File scope function; see @ref{Procedures}.
+
+@item F
+Global function; see @ref{Procedures}.
+
+@item G
+Global variable; see @ref{Global Variables}.
+
+@item i
+@xref{Register Parameters}.
+
+@item I
+Internal (nested) procedure; see @ref{Nested Procedures}.
+
+@item J
+Internal (nested) function; see @ref{Nested Procedures}.
+
+@item L
+Label name (documented by AIX, no further information known).
+
+@item m
+Module; see @ref{Procedures}.
+
+@item p
+Argument list parameter; see @ref{Parameters}.
+
+@item pP
+@xref{Parameters}.
+
+@item pF
+Fortran Function parameter; see @ref{Parameters}.
+
+@item P
+Unfortunately, three separate meanings have been independently invented
+for this symbol descriptor. At least the GNU and Sun uses can be
+distinguished by the symbol type. Global Procedure (AIX) (symbol type
+used unknown); see @ref{Procedures}. Register parameter (GNU) (symbol
+type @code{N_PSYM}); see @ref{Parameters}. Prototype of function
+referenced by this file (Sun @code{acc}) (symbol type @code{N_FUN}).
+
+@item Q
+Static Procedure; see @ref{Procedures}.
+
+@item R
+Register parameter; see @ref{Register Parameters}.
+
+@item r
+Register variable; see @ref{Register Variables}.
+
+@item S
+File scope variable; see @ref{Statics}.
+
+@item t
+Type name; see @ref{Typedefs}.
+
+@item T
+Enumeration, structure, or union tag; see @ref{Typedefs}.
+
+@item v
+Parameter passed by reference; see @ref{Reference Parameters}.
+
+@item V
+Procedure scope static variable; see @ref{Statics}.
+
+@item x
+Conformant array; see @ref{Conformant Arrays}.
+
+@item X
+Function return variable; see @ref{Parameters}.
+@end table
+
+@node Type Descriptors
+@appendix Table of Type Descriptors
+
+The type descriptor is the character which follows the type number and
+an equals sign. It specifies what kind of type is being defined.
+@xref{String Field}, for more information about their use.
+
+@table @code
+@item @var{digit}
+@itemx (
+Type reference; see @ref{String Field}.
+
+@item -
+Reference to builtin type; see @ref{Negative Type Numbers}.
+
+@item #
+Method (C++); see @ref{Cplusplus}.
+
+@item *
+Pointer; see @ref{Miscellaneous Types}.
+
+@item &
+Reference (C++).
+
+@item @@
+Type Attributes (AIX); see @ref{String Field}. Member (class and variable)
+type (GNU C++); see @ref{Cplusplus}.
+
+@item a
+Array; see @ref{Arrays}.
+
+@item A
+Open array; see @ref{Arrays}.
+
+@item b
+Pascal space type (AIX); see @ref{Miscellaneous Types}. Builtin integer
+type (Sun); see @ref{Builtin Type Descriptors}.
+
+@item B
+Volatile-qualified type; see @ref{Miscellaneous Types}.
+
+@item c
+Complex builtin type; see @ref{Builtin Type Descriptors}.
+
+@item C
+COBOL Picture type. See AIX documentation for details.
+
+@item d
+File type; see @ref{Miscellaneous Types}.
+
+@item D
+N-dimensional dynamic array; see @ref{Arrays}.
+
+@item e
+Enumeration type; see @ref{Enumerations}.
+
+@item E
+N-dimensional subarray; see @ref{Arrays}.
+
+@item f
+Function type; see @ref{Function Types}.
+
+@item F
+Pascal function parameter; see @ref{Function Types}
+
+@item g
+Builtin floating point type; see @ref{Builtin Type Descriptors}.
+
+@item G
+COBOL Group. See AIX documentation for details.
+
+@item i
+Imported type; see @ref{Cross-References}.
+
+@item k
+Const-qualified type; see @ref{Miscellaneous Types}.
+
+@item K
+COBOL File Descriptor. See AIX documentation for details.
+
+@item M
+Multiple instance type; see @ref{Miscellaneous Types}.
+
+@item n
+String type; see @ref{Strings}.
+
+@item N
+Stringptr; see @ref{Strings}.
+
+@item o
+Opaque type; see @ref{Typedefs}.
+
+@item p
+Procedure; see @ref{Function Types}.
+
+@item P
+Packed array; see @ref{Arrays}.
+
+@item r
+Range type; see @ref{Subranges}.
+
+@item R
+Builtin floating type; see @ref{Builtin Type Descriptors} (Sun). Pascal
+subroutine parameter; see @ref{Function Types} (AIX). Detecting this
+conflict is possible with careful parsing (hint: a Pascal subroutine
+parameter type will always contain a comma, and a builtin type
+descriptor never will).
+
+@item s
+Structure type; see @ref{Structures}.
+
+@item S
+Set type; see @ref{Miscellaneous Types}.
+
+@item u
+Union; see @ref{Unions}.
+
+@item v
+Variant record. This is a Pascal and Modula-2 feature which is like a
+union within a struct in C. See AIX documentation for details.
+
+@item w
+Wide character; see @ref{Builtin Type Descriptors}.
+
+@item x
+Cross-reference; see @ref{Cross-References}.
+
+@item z
+gstring; see @ref{Strings}.
+@end table
+
+@node Expanded Reference
+@appendix Expanded Reference by Stab Type
+
+@c FIXME: This appendix should go away; see N_PSYM or N_SO for an example.
+
+For a full list of stab types, and cross-references to where they are
+described, see @ref{Stab Types}. This appendix just duplicates certain
+information from the main body of this document; eventually the
+information will all be in one place.
+
+Format of an entry:
+
+The first line is the symbol type (see @file{include/aout/stab.def}).
+
+The second line describes the language constructs the symbol type
+represents.
+
+The third line is the stab format with the significant stab fields
+named and the rest NIL.
+
+Subsequent lines expand upon the meaning and possible values for each
+significant stab field. @samp{#} stands in for the type descriptor.
+
+Finally, any further information.
+
+@menu
+* N_PC:: Pascal global symbol
+* N_NSYMS:: Number of symbols
+* N_NOMAP:: No DST map
+* N_M2C:: Modula-2 compilation unit
+* N_BROWS:: Path to .cb file for Sun source code browser
+* N_DEFD:: GNU Modula2 definition module dependency
+* N_EHDECL:: GNU C++ exception variable
+* N_MOD2:: Modula2 information "for imc"
+* N_CATCH:: GNU C++ "catch" clause
+* N_SSYM:: Structure or union element
+* N_ENTRY:: Alternate entry point
+* N_SCOPE:: Modula2 scope information (Sun only)
+* Gould:: non-base register symbols used on Gould systems
+* N_LENG:: Length of preceding entry
+@end menu
+
+@node N_PC
+@section N_PC
+
+@deffn @code{.stabs} N_PC
+@findex N_PC
+Global symbol (for Pascal).
+
+@example
+"name" -> "symbol_name" <<?>>
+value -> supposedly the line number (stab.def is skeptical)
+@end example
+
+@display
+@file{stabdump.c} says:
+
+global pascal symbol: name,,0,subtype,line
+<< subtype? >>
+@end display
+@end deffn
+
+@node N_NSYMS
+@section N_NSYMS
+
+@deffn @code{.stabn} N_NSYMS
+@findex N_NSYMS
+Number of symbols (according to Ultrix V4.0).
+
+@display
+ 0, files,,funcs,lines (stab.def)
+@end display
+@end deffn
+
+@node N_NOMAP
+@section N_NOMAP
+
+@deffn @code{.stabs} N_NOMAP
+@findex N_NOMAP
+No DST map for symbol (according to Ultrix V4.0). I think this means a
+variable has been optimized out.
+
+@display
+ name, ,0,type,ignored (stab.def)
+@end display
+@end deffn
+
+@node N_M2C
+@section N_M2C
+
+@deffn @code{.stabs} N_M2C
+@findex N_M2C
+Modula-2 compilation unit.
+
+@example
+"string" -> "unit_name,unit_time_stamp[,code_time_stamp]"
+desc -> unit_number
+value -> 0 (main unit)
+ 1 (any other unit)
+@end example
+@end deffn
+
+@node N_BROWS
+@section N_BROWS
+
+@deffn @code{.stabs} N_BROWS
+@findex N_BROWS
+Sun source code browser, path to @file{.cb} file
+
+<<?>>
+"path to associated @file{.cb} file"
+
+Note: N_BROWS has the same value as N_BSLINE.
+@end deffn
+
+@node N_DEFD
+@section N_DEFD
+
+@deffn @code{.stabn} N_DEFD
+@findex N_DEFD
+GNU Modula2 definition module dependency.
+
+GNU Modula-2 definition module dependency. The value is the
+modification time of the definition file. The other field is non-zero
+if it is imported with the GNU M2 keyword @code{%INITIALIZE}. Perhaps
+@code{N_M2C} can be used if there are enough empty fields?
+@end deffn
+
+@node N_EHDECL
+@section N_EHDECL
+
+@deffn @code{.stabs} N_EHDECL
+@findex N_EHDECL
+GNU C++ exception variable <<?>>.
+
+"@var{string} is variable name"
+
+Note: conflicts with @code{N_MOD2}.
+@end deffn
+
+@node N_MOD2
+@section N_MOD2
+
+@deffn @code{.stab?} N_MOD2
+@findex N_MOD2
+Modula2 info "for imc" (according to Ultrix V4.0)
+
+Note: conflicts with @code{N_EHDECL} <<?>>
+@end deffn
+
+@node N_CATCH
+@section N_CATCH
+
+@deffn @code{.stabn} N_CATCH
+@findex N_CATCH
+GNU C++ @code{catch} clause
+
+GNU C++ @code{catch} clause. The value is its address. The desc field
+is nonzero if this entry is immediately followed by a @code{CAUGHT} stab
+saying what exception was caught. Multiple @code{CAUGHT} stabs means
+that multiple exceptions can be caught here. If desc is 0, it means all
+exceptions are caught here.
+@end deffn
+
+@node N_SSYM
+@section N_SSYM
+
+@deffn @code{.stabn} N_SSYM
+@findex N_SSYM
+Structure or union element.
+
+The value is the offset in the structure.
+
+<<?looking at structs and unions in C I didn't see these>>
+@end deffn
+
+@node N_ENTRY
+@section N_ENTRY
+
+@deffn @code{.stabn} N_ENTRY
+@findex N_ENTRY
+Alternate entry point.
+The value is its address.
+<<?>>
+@end deffn
+
+@node N_SCOPE
+@section N_SCOPE
+
+@deffn @code{.stab?} N_SCOPE
+@findex N_SCOPE
+Modula2 scope information (Sun linker)
+<<?>>
+@end deffn
+
+@node Gould
+@section Non-base registers on Gould systems
+
+@deffn @code{.stab?} N_NBTEXT
+@deffnx @code{.stab?} N_NBDATA
+@deffnx @code{.stab?} N_NBBSS
+@deffnx @code{.stab?} N_NBSTS
+@deffnx @code{.stab?} N_NBLCS
+@findex N_NBTEXT
+@findex N_NBDATA
+@findex N_NBBSS
+@findex N_NBSTS
+@findex N_NBLCS
+These are used on Gould systems for non-base registers syms.
+
+However, the following values are not the values used by Gould; they are
+the values which GNU has been documenting for these values for a long
+time, without actually checking what Gould uses. I include these values
+only because perhaps some someone actually did something with the GNU
+information (I hope not, why GNU knowingly assigned wrong values to
+these in the header file is a complete mystery to me).
+
+@example
+240 0xf0 N_NBTEXT ??
+242 0xf2 N_NBDATA ??
+244 0xf4 N_NBBSS ??
+246 0xf6 N_NBSTS ??
+248 0xf8 N_NBLCS ??
+@end example
+@end deffn
+
+@node N_LENG
+@section N_LENG
+
+@deffn @code{.stabn} N_LENG
+@findex N_LENG
+Second symbol entry containing a length-value for the preceding entry.
+The value is the length.
+@end deffn
+
+@node Questions
+@appendix Questions and Anomalies
+
+@itemize @bullet
+@item
+@c I think this is changed in GCC 2.4.5 to put the line number there.
+For GNU C stabs defining local and global variables (@code{N_LSYM} and
+@code{N_GSYM}), the desc field is supposed to contain the source
+line number on which the variable is defined. In reality the desc
+field is always 0. (This behavior is defined in @file{dbxout.c} and
+putting a line number in desc is controlled by @samp{#ifdef
+WINNING_GDB}, which defaults to false). GDB supposedly uses this
+information if you say @samp{list @var{var}}. In reality, @var{var} can
+be a variable defined in the program and GDB says @samp{function
+@var{var} not defined}.
+
+@item
+In GNU C stabs, there seems to be no way to differentiate tag types:
+structures, unions, and enums (symbol descriptor @samp{T}) and typedefs
+(symbol descriptor @samp{t}) defined at file scope from types defined locally
+to a procedure or other more local scope. They all use the @code{N_LSYM}
+stab type. Types defined at procedure scope are emited after the
+@code{N_RBRAC} of the preceding function and before the code of the
+procedure in which they are defined. This is exactly the same as
+types defined in the source file between the two procedure bodies.
+GDB overcompensates by placing all types in block #1, the block for
+symbols of file scope. This is true for default, @samp{-ansi} and
+@samp{-traditional} compiler options. (Bugs gcc/1063, gdb/1066.)
+
+@item
+What ends the procedure scope? Is it the proc block's @code{N_RBRAC} or the
+next @code{N_FUN}? (I believe its the first.)
+
+@item
+@c FIXME: This should go with the other stuff about global variables.
+Global variable stabs don't have location information. This comes
+from the external symbol for the same variable. The external symbol
+has a leading underbar on the _name of the variable and the stab does
+not. How do we know these two symbol table entries are talking about
+the same symbol when their names are different? (Answer: the debugger
+knows that external symbols have leading underbars).
+
+@c FIXME: This is absurdly vague; there all kinds of differences, some
+@c of which are the same between gnu & sun, and some of which aren't.
+@c In particular, I'm pretty sure GCC works with Sun dbx by default.
+@c @item
+@c Can GCC be configured to output stabs the way the Sun compiler
+@c does, so that their native debugging tools work? <NO?> It doesn't by
+@c default. GDB reads either format of stab. (GCC or SunC). How about
+@c dbx?
+@end itemize
+
+@node XCOFF Differences
+@appendix Differences Between GNU Stabs in a.out and GNU Stabs in XCOFF
+
+@c FIXME: Merge *all* these into the main body of the document.
+The AIX/RS6000 native object file format is XCOFF with stabs. This
+appendix only covers those differences which are not covered in the main
+body of this document.
+
+@itemize @bullet
+@item
+BSD a.out stab types correspond to AIX XCOFF storage classes. In general
+the mapping is @code{N_@var{stabtype}} becomes @code{C_@var{stabtype}}.
+Some stab types in a.out are not supported in XCOFF; most of these use
+@code{C_DECL}.
+
+@c FIXME: Get C_* types for the block, figure out whether it is always
+@c used (I suspect not), explain clearly, and move to node Statics.
+Exception: initialised static @code{N_STSYM} and un-initialized static
+@code{N_LCSYM} both map to the @code{C_STSYM} storage class. But the
+distinction is preserved because in XCOFF @code{N_STSYM} and
+@code{N_LCSYM} must be emited in a named static block. Begin the block
+with @samp{.bs s[RW] data_section_name} for @code{N_STSYM} or @samp{.bs
+s bss_section_name} for @code{N_LCSYM}. End the block with @samp{.es}.
+
+@c FIXME: I think they are trying to say something about whether the
+@c assembler defaults the value to the location counter.
+@item
+If the XCOFF stab is an @code{N_FUN} (@code{C_FUN}) then follow the
+string field with @samp{,.} instead of just @samp{,}.
+@end itemize
+
+I think that's it for @file{.s} file differences. They could stand to be
+better presented. This is just a list of what I have noticed so far.
+There are a @emph{lot} of differences in the information in the symbol
+tables of the executable and object files.
+
+Mapping of a.out stab types to XCOFF storage classes:
+
+@example
+stab type storage class
+-------------------------------
+N_GSYM C_GSYM
+N_FNAME unused
+N_FUN C_FUN
+N_STSYM C_STSYM
+N_LCSYM C_STSYM
+N_MAIN unknown
+N_PC unknown
+N_RSYM C_RSYM
+unknown C_RPSYM
+N_M2C unknown
+N_SLINE unknown
+N_DSLINE unknown
+N_BSLINE unknown
+N_BROWSE unchanged
+N_CATCH unknown
+N_SSYM unknown
+N_SO unknown
+N_LSYM C_LSYM
+various C_DECL
+N_BINCL unknown
+N_SOL unknown
+N_PSYM C_PSYM
+N_EINCL unknown
+N_ENTRY C_ENTRY
+N_LBRAC unknown
+N_EXCL unknown
+N_SCOPE unknown
+N_RBRAC unknown
+N_BCOMM C_BCOMM
+N_ECOMM C_ECOMM
+N_ECOML C_ECOML
+
+N_LENG unknown
+@end example
+
+@node Sun Differences
+@appendix Differences Between GNU Stabs and Sun Native Stabs
+
+@c FIXME: Merge all this stuff into the main body of the document.
+
+@itemize @bullet
+@item
+GNU C stabs define @emph{all} types, file or procedure scope, as
+@code{N_LSYM}. Sun doc talks about using @code{N_GSYM} too.
+
+@item
+Sun C stabs use type number pairs in the format
+(@var{file-number},@var{type-number}) where @var{file-number} is a
+number starting with 1 and incremented for each sub-source file in the
+compilation. @var{type-number} is a number starting with 1 and
+incremented for each new type defined in the compilation. GNU C stabs
+use the type number alone, with no source file number.
+@end itemize
+
+@node Stabs In ELF
+@appendix Using Stabs With The ELF Object File Format
+
+The ELF object file format allows tools to create object files with
+custom sections containing any arbitrary data. To use stabs in ELF
+object files, the tools create two custom sections, a section named
+@code{.stab} which contains an array of fixed length structures, one
+struct per stab, and a section named @code{.stabstr} containing all the
+variable length strings that are referenced by stabs in the @code{.stab}
+section. The byte order of the stabs binary data matches the byte order
+of the ELF file itself, as determined from the @code{EI_DATA} field in
+the @code{e_ident} member of the ELF header.
+
+The first stab in the @code{.stab} section for each compilation unit is
+synthetic, generated entirely by the assembler, with no corresponding
+@code{.stab} directive as input to the assembler. This stab contains
+the following fields:
+
+@table @code
+@item n_strx
+Offset in the @code{.stabstr} section to the source filename.
+
+@item n_type
+@code{N_UNDF}.
+
+@item n_other
+Unused field, always zero.
+
+@item n_desc
+Count of upcoming symbols, i.e., the number of remaining stabs for this
+source file.
+
+@item n_value
+Size of the string table fragment associated with this source file, in
+bytes.
+@end table
+
+The @code{.stabstr} section always starts with a null byte (so that string
+offsets of zero reference a null string), followed by random length strings,
+each of which is null byte terminated.
+
+The ELF section header for the @code{.stab} section has its
+@code{sh_link} member set to the section number of the @code{.stabstr}
+section, and the @code{.stabstr} section has its ELF section
+header @code{sh_type} member set to @code{SHT_STRTAB} to mark it as a
+string table.
+
+To keep linking fast, it is a bad idea to have the linker relocating
+stabs, so (except for a few cases, see below) none of the addresses in
+the @code{n_value} field of the stabs are relocated by the linker.
+Instead they are relative to the source file (or some entity smaller
+than a source file, like a function). To find the address of each
+section corresponding to a given source file, the compiler puts out
+symbols giving the address of each section for a given source file.
+Since these are ELF (not stab) symbols, the linker relocates them
+correctly without having to touch the stabs section. They are named
+@code{Bbss.bss} for the bss section, @code{Ddata.data} for the data
+section, and @code{Drodata.rodata} for the rodata section. For the text
+section, there is no such symbol (but there should be, see below). For
+an example of how these symbols work, @xref{ELF Transformations}. GCC
+does not provide these symbols; it instead relies on the stabs getting
+relocated, which slows down linking. Thus addresses which would
+normally be relative to @code{Bbss.bss}, etc., are already relocated.
+The Sun linker provided with Solaris 2.2 and earlier relocates stabs
+using normal ELF relocation information, as it would do for any section.
+Sun has been threatening to kludge their linker to not do this (to speed
+up linking), even though the correct way to avoid having the linker do
+these relocations is to have the compiler no longer output relocatable
+values. Last I heard they had been talked out of the linker kludge.
+See Sun point patch 101052-01 and Sun bug 1142109. This affects
+@samp{S} symbol descriptor stabs (@pxref{Statics}) and functions
+(@pxref{Procedures}). In the latter case, to adopt the clean solution
+(making the value of the stab relative to the start of the compilation
+unit), it would be necessary to invent a @code{Ttext.text} symbol,
+analogous to the @code{Bbss.bss}, etc., symbols. I recommend this
+rather than using a zero value and getting the address from the ELF
+symbols.
+
+@node Symbol Types Index
+@unnumbered Symbol Types Index
+
+@printindex fn
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb.1
deleted file mode 100644
index 57d744b29368..000000000000
--- a/gnu/usr.bin/gdb/gdb.1
+++ /dev/null
@@ -1,3 +0,0 @@
-.\" %W% (Berkeley) %G%
-.\"
-.\" placeholder, until we can produce the manual page
diff --git a/gnu/usr.bin/gdb/gdb/COPYING b/gnu/usr.bin/gdb/gdb/COPYING
new file mode 100644
index 000000000000..a43ea2126fb6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU 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. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, 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 software, or if you modify it.
+
+ For example, if you distribute copies of 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 show them these terms so they know 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.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ 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 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 derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 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 License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary 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
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing 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 for copying, distributing or modifying
+the Program or works based on it.
+
+ 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.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. 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 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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. 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 the public, 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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) 19yy 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 is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/gdb/Makefile b/gnu/usr.bin/gdb/gdb/Makefile
new file mode 100644
index 000000000000..2fac3dbd1c1d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/Makefile
@@ -0,0 +1,72 @@
+PROG = gdb
+BINDIR= /usr/bin
+SRCS = main.c blockframe.c breakpoint.c findvar.c stack.c thread.c \
+ source.c values.c eval.c valops.c valarith.c valprint.c printcmd.c \
+ symtab.c symfile.c symmisc.c infcmd.c infrun.c command.c utils.c \
+ expprint.c environ.c gdbtypes.c copying.c i386-tdep.c i386-pinsn.c \
+ freebsd-solib.c ser-unix.c exec.c fork-child.c infptrace.c inftarg.c \
+ corelow.c coredep.c freebsd-nat.c remote.c dcache.c remote-utils.c \
+ mem-break.c target.c putenv.c parse.c language.c buildsym.c \
+ objfiles.c minsyms.c maint.c demangle.c dbxread.c coffread.c \
+ elfread.c dwarfread.c mipsread.c stabsread.c core.c c-lang.c \
+ ch-lang.c m2-lang.c complaints.c typeprint.c c-typeprint.c \
+ ch-typeprint.c m2-typeprint.c c-valprint.c cp-valprint.c ch-valprint.c \
+ m2-valprint.c nlmread.c serial.c inflow.c regex.c init.c \
+ c-exp.tab.c ch-exp.tab.c m2-exp.tab.c version.c i386-dis.c dis-buf.c
+
+c-exp.tab.c: $(.CURDIR)/c-exp.y
+ yacc -d -p c_ $(.CURDIR)/c-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > c-exp.new
+ rm y.tab.c
+ mv c-exp.new ./c-exp.tab.c
+
+ch-exp.tab.c: $(.CURDIR)/ch-exp.y
+ yacc -d -p ch_ $(.CURDIR)/ch-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > ch-exp.new
+ rm y.tab.c
+ mv ch-exp.new ./ch-exp.tab.c
+
+m2-exp.tab.c: $(.CURDIR)/m2-exp.y
+ yacc -d -p m2_ $(.CURDIR)/m2-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > m2-exp.new
+ rm y.tab.c
+ mv m2-exp.new ./m2-exp.tab.c
+
+
+
+CFLAGS+= -I$(.CURDIR)/. -I/usr/include/readline -I$(.CURDIR)/../bfd
+DPADD+= $(LIBREADLINE) $(LIBTERM)
+LDADD+= -lreadline -ltermcap
+
+.if exists(${.CURDIR}/../libiberty/obj)
+LDADD+= -L${.CURDIR}/../libiberty/obj -liberty
+DPADD+= ${.CURDIR}/../libiberty/obj/libiberty.a
+.else
+LDADD+= -L${.CURDIR}/../libiberty/ -liberty
+DPADD+= ${.CURDIR}/../libiberty/libiberty.a
+.endif
+
+.if exists(${.CURDIR}/../bfd/obj)
+LDADD+= -L${.CURDIR}/../bfd/obj -lbfd
+DPADD+= ${.CURDIR}/../bfd/obj/libbfd.a
+.else
+LDADD+= -L${.CURDIR}/../bfd/ -lbfd
+DPADD+= ${.CURDIR}/../bfd/libbfd.a
+.endif
+
+.if exists(${.CURDIR}/../mmalloc/obj)
+LDADD+= -L${.CURDIR}/../mmalloc/obj -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/obj/libmmalloc.a
+.else
+LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a
+.endif
+
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/gdb/gdb/ansidecl.h b/gnu/usr.bin/gdb/gdb/ansidecl.h
new file mode 100644
index 000000000000..fdc4072120ed
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ansidecl.h
@@ -0,0 +1,139 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macro ANSI C definition Traditional C definition
+ ----- ---- - ---------- ----------- - ----------
+ PTR `void *' `char *'
+ LONG_DOUBLE `long double' `double'
+ VOLATILE `volatile' `'
+ SIGNED `signed' `'
+ PTRCONST `void *const' `char *'
+
+ CONST is also defined, but is obsolete. Just use const.
+
+ DEFUN (name, arglist, args)
+
+ Defines function NAME.
+
+ ARGLIST lists the arguments, separated by commas and enclosed in
+ parentheses. ARGLIST becomes the argument list in traditional C.
+
+ ARGS list the arguments with their types. It becomes a prototype in
+ ANSI C, and the type declarations in traditional C. Arguments should
+ be separated with `AND'. For functions with a variable number of
+ arguments, the last thing listed should be `DOTS'.
+
+ DEFUN_VOID (name)
+
+ Defines a function NAME, which takes no arguments.
+
+ obsolete -- EXFUN (name, (prototype)) -- obsolete.
+
+ Replaced by PARAMS. Do not use; will disappear someday soon.
+ Was used in external function declarations.
+ In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in
+ parentheses). In traditional C it is `NAME()'.
+ For a function that takes no arguments, PROTOTYPE should be `(void)'.
+
+ PARAMS ((args))
+
+ We could use the EXFUN macro to handle prototype declarations, but
+ the name is misleading and the result is ugly. So we just define a
+ simple macro to handle the parameter lists, as in:
+
+ static int foo PARAMS ((int, char));
+
+ This produces: `static int foo();' or `static int foo (int, char);'
+
+ EXFUN would have done it like this:
+
+ static int EXFUN (foo, (int, char));
+
+ but the function is not external...and it's hard to visually parse
+ the function name out of the mess. EXFUN should be considered
+ obsolete; new code should be written to use PARAMS.
+
+ For example:
+ extern int printf PARAMS ((CONST char *format DOTS));
+ int DEFUN(fprintf, (stream, format),
+ FILE *stream AND CONST char *format DOTS) { ... }
+ void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef _ANSIDECL_H
+
+#define _ANSIDECL_H 1
+
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4))
+/* All known AIX compilers implement these things (but don't always
+ define __STDC__). The RISC/OS MIPS compiler defines these things
+ in SVR4 mode, but does not define __STDC__. */
+
+#define PTR void *
+#define PTRCONST void *CONST
+#define LONG_DOUBLE long double
+
+#define AND ,
+#define NOARGS void
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+#define DOTS , ...
+
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(void)
+
+#define PROTO(type, name, arglist) type name arglist
+#define PARAMS(paramlist) paramlist
+
+#else /* Not ANSI C. */
+
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define AND ;
+#define NOARGS
+#define CONST
+#ifndef const /* some systems define it in header files for non-ansi mode */
+#define const
+#endif
+#define VOLATILE
+#define SIGNED
+#define DOTS
+
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+#define PROTO(type, name, arglist) type name ()
+#define PARAMS(paramlist) ()
+
+#endif /* ANSI C. */
+
+#endif /* ansidecl.h */
diff --git a/gnu/usr.bin/gdb/gdb/aout/aout64.h b/gnu/usr.bin/gdb/gdb/aout/aout64.h
new file mode 100644
index 000000000000..018e6ddb0685
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/aout64.h
@@ -0,0 +1,431 @@
+/* `a.out' object-file definitions, including extensions to 64-bit fields */
+
+#ifndef __A_OUT_64_H__
+#define __A_OUT_64_H__
+
+/* This is the layout on disk of the 32-bit or 64-bit exec header. */
+
+#ifndef external_exec
+struct external_exec
+{
+ bfd_byte e_info[4]; /* magic number and stuff */
+ bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */
+ bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */
+ bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */
+ bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */
+ bfd_byte e_entry[BYTES_IN_WORD]; /* start address */
+ bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */
+ bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */
+};
+
+#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7)
+
+/* Magic numbers for a.out files */
+
+#if ARCH_SIZE==64
+#define OMAGIC 0x1001 /* Code indicating object file */
+#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */
+#define NMAGIC 0x1003 /* Code indicating pure executable. */
+
+/* There is no 64-bit QMAGIC as far as I know. */
+
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#else
+#define OMAGIC 0407 /* ...object file or impure executable. */
+#define NMAGIC 0410 /* Code indicating pure executable. */
+#define ZMAGIC 0413 /* Code indicating demand-paged executable. */
+
+/* This indicates a demand-paged executable with the header in the text.
+ As far as I know it is only used by 386BSD and/or BSDI. */
+#define QMAGIC 0314
+# ifndef N_BADMAG
+# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC \
+ && N_MAGIC(x) != QMAGIC)
+# endif /* N_BADMAG */
+#endif
+
+#endif
+
+#ifdef QMAGIC
+#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC)
+#else
+#define N_IS_QMAGIC(x) (0)
+#endif
+
+/* The difference between PAGE_SIZE and N_SEGSIZE is that PAGE_SIZE is
+ the the finest granularity at which you can page something, thus it
+ controls the padding (if any) before the text segment of a ZMAGIC
+ file. N_SEGSIZE is the resolution at which things can be marked as
+ read-only versus read/write, so it controls the padding between the
+ text segment and the data segment (in memory; on disk the padding
+ between them is PAGE_SIZE). PAGE_SIZE and N_SEGSIZE are the same
+ for most machines, but different for sun3. */
+
+/* By default, segment size is constant. But some machines override this
+ to be a function of the a.out header (e.g. machine type). */
+
+#ifndef N_SEGSIZE
+#define N_SEGSIZE(x) SEGMENT_SIZE
+#endif
+
+/* Virtual memory address of the text section.
+ This is getting very complicated. A good reason to discard a.out format
+ for something that specifies these fields explicitly. But til then...
+
+ * OMAGIC and NMAGIC files:
+ (object files: text for "relocatable addr 0" right after the header)
+ start at 0, offset is EXEC_BYTES_SIZE, size as stated.
+ * The text address, offset, and size of ZMAGIC files depend
+ on the entry point of the file:
+ * entry point below TEXT_START_ADDR:
+ (hack for SunOS shared libraries)
+ start at 0, offset is 0, size as stated.
+ * If N_HEADER_IN_TEXT(x) is true (which defaults to being the
+ case when the entry point is EXEC_BYTES_SIZE or further into a page):
+ no padding is needed; text can start after exec header. Sun
+ considers the text segment of such files to include the exec header;
+ for BFD's purposes, we don't, which makes more work for us.
+ start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE,
+ size as stated minus EXEC_BYTES_SIZE.
+ * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when
+ the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page
+ aligned)): (padding is needed so that text can start at a page boundary)
+ start at TEXT_START_ADDR, offset PAGE_SIZE, size as stated.
+
+ Specific configurations may want to hardwire N_HEADER_IN_TEXT,
+ for efficiency or to allow people to play games with the entry point.
+ In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos,
+ and as 0 for most other hosts (Sony News, Vax Ultrix, etc).
+ (Do this in the appropriate bfd target file.)
+ (The default is a heuristic that will break if people try changing
+ the entry point, perhaps with the ld -e flag.)
+
+ * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true,
+ and for which the starting address is PAGE_SIZE (or should this be
+ SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC).
+ */
+
+/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header
+ in the text. */
+#ifndef N_HEADER_IN_TEXT
+#define N_HEADER_IN_TEXT(x) (((x).a_entry & (PAGE_SIZE-1)) >= EXEC_BYTES_SIZE)
+#endif
+
+/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC
+ files. */
+#ifndef N_SHARED_LIB
+#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR)
+#endif
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) \
+ (/* The address of a QMAGIC file is always one page in, */ \
+ /* with the header in the text. */ \
+ N_IS_QMAGIC (x) ? PAGE_SIZE + EXEC_BYTES_SIZE : \
+ N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\
+ TEXT_START_ADDR /* a page of padding */\
+ )
+#endif
+
+/* Offset in an a.out of the start of the text section. */
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) \
+ (/* For {O,N,Q}MAGIC, no padding. */ \
+ N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ EXEC_BYTES_SIZE : /* no padding */\
+ PAGE_SIZE /* a page of padding */\
+ )
+#endif
+/* Size of the text section. It's always as stated, except that we
+ offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF
+ for ZMAGIC files that nominally include the exec header
+ as part of the first page of text. (BFD doesn't consider the
+ exec header to be part of the text segment.) */
+#ifndef N_TXTSIZE
+#define N_TXTSIZE(x) \
+ (/* For QMAGIC, we don't consider the header part of the text section. */\
+ N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \
+ (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \
+ N_HEADER_IN_TEXT(x) ? \
+ (x).a_text - EXEC_BYTES_SIZE: /* no padding */\
+ (x).a_text /* a page of padding */\
+ )
+#endif
+/* The address of the data segment in virtual memory.
+ It is the text segment address, plus text segment size, rounded
+ up to a N_SEGSIZE boundary for pure or pageable files. */
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \
+ : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1))))
+#endif
+/* The address of the BSS segment -- immediately after the data segment. */
+
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+
+/* Offsets of the various portions of the file after the text segment. */
+
+/* For {N,Q,Z}MAGIC, there is padding to make the data segment start
+ on a page boundary. Most of the time the a_text field (and thus
+ N_TXTSIZE) already contains this padding. But if it doesn't (I
+ think maybe this happens on BSDI and/or 386BSD), then add it. */
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) \
+ (N_MAGIC(x) == OMAGIC ? N_TXTOFF(x) + N_TXTSIZE(x) : \
+ PAGE_SIZE + ((N_TXTOFF(x) + N_TXTSIZE(x) - 1) & ~(PAGE_SIZE - 1)))
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
+#endif
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
+#endif
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
+#endif
+#ifndef N_STROFF
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#endif
+
+/* Symbols */
+#ifndef external_nlist
+struct external_nlist {
+ bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
+ bfd_byte e_type[1]; /* type of symbol */
+ bfd_byte e_other[1]; /* misc info (usually empty) */
+ bfd_byte e_desc[2]; /* description field */
+ bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
+};
+#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD)
+#endif
+
+struct internal_nlist {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+};
+
+/* The n_type field is the symbol type, containing: */
+
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol -- defined at particular addr */
+#define N_TEXT 4 /* Text sym -- defined at offset in text seg */
+#define N_DATA 6 /* Data sym -- defined at offset in data seg */
+#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */
+#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */
+#define N_FN 0x1f /* File name of .o file */
+#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */
+/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT,
+ N_DATA, or N_BSS. When the low-order bit of other types is set,
+ (e.g. N_WARNING versus N_FN), they are two different types. */
+#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */
+#define N_TYPE 0x1e
+#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */
+
+#define N_INDR 0x0a
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ elements value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+/* Warning symbol. The text gives a warning message, the next symbol
+ in the table will be undefined. When the symbol is referenced, the
+ message is printed. */
+
+#define N_WARNING 0x1e
+
+/* Relocations
+
+ There are two types of relocation flavours for a.out systems,
+ standard and extended. The standard form is used on systems where the
+ instruction has room for all the bits of an offset to the operand, whilst
+ the extended form is used when an address operand has to be split over n
+ instructions. Eg, on the 68k, each move instruction can reference
+ the target with a displacement of 16 or 32 bits. On the sparc, move
+ instructions use an offset of 14 bits, so the offset is stored in
+ the reloc field, and the data in the section is ignored.
+*/
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct reloc_std_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+};
+
+#define RELOC_STD_BITS_PCREL_BIG 0x80
+#define RELOC_STD_BITS_PCREL_LITTLE 0x01
+
+#define RELOC_STD_BITS_LENGTH_BIG 0x60
+#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */
+#define RELOC_STD_BITS_LENGTH_LITTLE 0x06
+#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
+
+#define RELOC_STD_BITS_EXTERN_BIG 0x10
+#define RELOC_STD_BITS_EXTERN_LITTLE 0x08
+
+#define RELOC_STD_BITS_BASEREL_BIG 0x08
+#define RELOC_STD_BITS_BASEREL_LITTLE 0x08
+
+#define RELOC_STD_BITS_JMPTABLE_BIG 0x04
+#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04
+
+#define RELOC_STD_BITS_RELATIVE_BIG 0x02
+#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02
+
+#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */
+
+struct reloc_std_internal
+{
+ bfd_vma r_address; /* Address (within segment) to be relocated. */
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in files the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* The next three bits are for SunOS shared libraries, and seem to
+ be undocumented. */
+ unsigned int r_baserel:1; /* Linkage table relative */
+ unsigned int r_jmptable:1; /* pc-relative to jump table */
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+};
+
+
+/* EXTENDED RELOCS */
+
+struct reloc_ext_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+ bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */
+};
+
+#define RELOC_EXT_BITS_EXTERN_BIG 0x80
+#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01
+
+#define RELOC_EXT_BITS_TYPE_BIG 0x1F
+#define RELOC_EXT_BITS_TYPE_SH_BIG 0
+#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8
+#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
+
+/* Bytes per relocation entry */
+#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD)
+
+enum reloc_type
+{
+ /* simple relocations */
+ RELOC_8, /* data[0:7] = addend + sv */
+ RELOC_16, /* data[0:15] = addend + sv */
+ RELOC_32, /* data[0:31] = addend + sv */
+ /* pc-rel displacement */
+ RELOC_DISP8, /* data[0:7] = addend - pc + sv */
+ RELOC_DISP16, /* data[0:15] = addend - pc + sv */
+ RELOC_DISP32, /* data[0:31] = addend - pc + sv */
+ /* Special */
+ RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */
+ RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */
+ RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */
+ RELOC_22, /* data[0:21] = (addend + sv) */
+ RELOC_13, /* data[0:12] = (addend + sv) */
+ RELOC_LO10, /* data[0:9] = (addend + sv) */
+ RELOC_SFA_BASE,
+ RELOC_SFA_OFF13,
+ /* P.I.C. (base-relative) */
+ RELOC_BASE10, /* Not sure - maybe we can do this the */
+ RELOC_BASE13, /* right way now */
+ RELOC_BASE22,
+ /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_PC10,
+ RELOC_PC22,
+ /* P.I.C. jump table */
+ RELOC_JMP_TBL,
+ /* reputedly for shared libraries somehow */
+ RELOC_SEGOFF16,
+ RELOC_GLOB_DAT,
+ RELOC_JMP_SLOT,
+ RELOC_RELATIVE,
+
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */
+ RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG,
+ RELOC_CONST,
+ RELOC_CONSTH,
+
+
+ /* Q .
+ What are the other ones,
+ Since this is a clean slate, can we throw away the ones we dont
+ understand ? Should we sort the values ? What about using a
+ microcode format like the 68k ?
+ */
+ NO_RELOC
+ };
+
+
+struct reloc_internal {
+ bfd_vma r_address; /* offset of of data to relocate */
+ long r_index; /* symbol table index of symbol */
+ enum reloc_type r_type; /* relocation type */
+ bfd_vma r_addend; /* datum addend */
+};
+
+/* Q.
+ Should the length of the string table be 4 bytes or 8 bytes ?
+
+ Q.
+ What about archive indexes ?
+
+ */
+
+#endif /* __A_OUT_64_H__ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/ar.h b/gnu/usr.bin/gdb/gdb/aout/ar.h
new file mode 100644
index 000000000000..cca636d81936
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/ar.h
@@ -0,0 +1,32 @@
+/* archive file definition for GNU software */
+
+/* So far this is correct for BSDish archives. Don't forget that
+ files must begin on an even byte boundary. */
+
+#ifndef __GNU_AR_H__
+#define __GNU_AR_H__
+
+#define ARMAG "!<arch>\n" /* For COFF and a.out archives */
+#define ARMAGB "!<bout>\n" /* For b.out archives */
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+/* The ar_date field of the armap (__.SYMDEF) member of an archive
+ must be greater than the modified date of the entire file, or
+ BSD-derived linkers complain. We originally write the ar_date with
+ this offset from the real file's mod-time. After finishing the
+ file, we rewrite ar_date if it's not still greater than the mod date. */
+
+#define ARMAP_TIME_OFFSET 60
+
+struct ar_hdr {
+ char ar_name[16]; /* name of this member */
+ char ar_date[12]; /* file mtime */
+ char ar_uid[6]; /* owner uid; printed as decimal */
+ char ar_gid[6]; /* owner gid; printed as decimal */
+ char ar_mode[8]; /* file mode, printed as octal */
+ char ar_size[10]; /* file size, printed as decimal */
+ char ar_fmag[2]; /* should contain ARFMAG */
+};
+
+#endif /* __GNU_AR_H__ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/ranlib.h b/gnu/usr.bin/gdb/gdb/aout/ranlib.h
new file mode 100644
index 000000000000..53e35ce2e0e7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/ranlib.h
@@ -0,0 +1,62 @@
+/* ranlib.h -- archive library index member definition for GNU.
+ Copyright 1990-1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The Symdef member of an archive contains two things:
+ a table that maps symbol-string offsets to file offsets,
+ and a symbol-string table. All the symbol names are
+ run together (each with trailing null) in the symbol-string
+ table. There is a single longword bytecount on the front
+ of each of these tables. Thus if we have two symbols,
+ "foo" and "_bar", that are in archive members at offsets
+ 200 and 900, it would look like this:
+ 16 ; byte count of index table
+ 0 ; offset of "foo" in string table
+ 200 ; offset of foo-module in file
+ 4 ; offset of "bar" in string table
+ 900 ; offset of bar-module in file
+ 9 ; byte count of string table
+ "foo\0_bar\0" ; string table */
+
+#define RANLIBMAG "__.SYMDEF" /* Archive file name containing index */
+#define RANLIBSKEW 3 /* Creation time offset */
+
+/* Format of __.SYMDEF:
+ First, a longword containing the size of the 'symdef' data that follows.
+ Second, zero or more 'symdef' structures.
+ Third, a longword containing the length of symbol name strings.
+ Fourth, zero or more symbol name strings (each followed by a null). */
+
+struct symdef
+ {
+ union
+ {
+ unsigned long string_offset; /* In the file */
+ char *name; /* In memory, sometimes */
+ } s;
+ /* this points to the front of the file header (AKA member header --
+ a struct ar_hdr), not to the front of the file or into the file).
+ in other words it only tells you which file to read */
+ unsigned long file_offset;
+ };
+
+/* Compatability with BSD code */
+
+#define ranlib symdef
+#define ran_un s
+#define ran_strx string_offset
+#define ran_name name
+#define ran_off file_offset
diff --git a/gnu/usr.bin/gdb/gdb/aout/stab.def b/gnu/usr.bin/gdb/gdb/aout/stab.def
new file mode 100644
index 000000000000..9d1da7d6eb8f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/stab.def
@@ -0,0 +1,264 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files
+ overlaps the N_UNDF used for ordinary symbols. In ELF files, the
+ debug information is in a different file section, so there is no conflict.
+ This symbol's n_value gives the size of the string section associated
+ with this file. The symbol's n_strx (relative to the just-updated
+ string section start address) gives the name of the source file,
+ e.g. "foo.c", without any path information. The symbol's n_desc gives
+ the count of upcoming symbols associated with this file (not including
+ this one). */
+/* __define_stab (N_UNDF, 0x00, "UNDF") */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address.
+ "Static Sym". */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Solaris2: Read-only data symbols. */
+__define_stab (N_ROSYM, 0x2c, "ROSYM")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
+__define_stab (N_NSYMS, 0x32, "NSYMS")
+
+/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
+__define_stab (N_NOMAP, 0x34, "NOMAP")
+
+/* New stab from Solaris 2. Like N_SO, but for the object file. Two in
+ a row provide the build directory and the relative path of the .o from it.
+ Solaris2 uses this to avoid putting the stabs info into the linked
+ executable; this stab goes into the ".stab.index" section, and the debugger
+ reads the real stabs directly from the .o files instead. */
+__define_stab (N_OBJ, 0x38, "OBJ")
+
+/* New stab from Solaris 2. Options for the debugger, related to the
+ source language for this module. E.g. whether to use ANSI
+ integral promotions or traditional integral promotions. */
+__define_stab (N_OPT, 0x3c, "OPT")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. On Solaris2, the line number is
+ relative to the start of the current function. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Sun's source-code browser stabs. ?? Don't know what the fields are.
+ Supposedly the field is "path to associated .cb file". THIS VALUE
+ OVERLAPS WITH N_BSLINE! */
+__define_stab (N_BROWS, 0x48, "BROWS")
+
+/* GNU Modula-2 definition module dependency. Value is the modification time
+ of the definition file. Other is non-zero if it is imported with the
+ GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
+ are enough empty fields? */
+__define_stab(N_DEFD, 0x4a, "DEFD")
+
+/* New in Solaris2. Function start/body/end line numbers. */
+__define_stab(N_FLINE, 0x4C, "FLINE")
+
+/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
+ and one is for C++. Still,... */
+/* GNU C++ exception variable. Name is variable name. */
+__define_stab (N_EHDECL, 0x50, "EHDECL")
+/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
+__define_stab (N_MOD2, 0x50, "MOD2")
+
+/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
+ this entry is immediately followed by a CAUGHT stab saying what exception
+ was caught. Multiple CAUGHT stabs means that multiple exceptions
+ can be caught here. If Desc is 0, it means all exceptions are caught
+ here. */
+__define_stab (N_CATCH, 0x54, "CATCH")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Solaris2: Last stab emitted for module. */
+__define_stab (N_ENDM, 0x62, "ENDM")
+
+/* Name of main source file.
+ Value is starting text address of the compilation.
+ If multiple N_SO's appear, the first to contain a trailing / is the
+ compilation directory. The first to not contain a trailing / is the
+ source file name, relative to the compilation directory. Others (perhaps
+ resulting from cfront) are ignored.
+ On Solaris2, value is undefined, but desc is a source-language code. */
+
+__define_stab (N_SO, 0x64, "SO")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+
+/* Name of sub-source file (#include file).
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* End of an include file. No name.
+ This and N_BINCL act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+
+/* Place holder for deleted include file. Replaces a N_BINCL and everything
+ up to the corresponding N_EINCL. The Sun linker generates these when
+ it finds multiple identical copies of the symbols from an include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
+
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+
+/* End named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+
+/* Member of a common block; value is offset within the common block.
+ This should occur within a BCOMM/ECOMM pair. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+
+/* Solaris2: Pascal "with" statement: type,,0,0,offset */
+__define_stab (N_WITH, 0xea, "WITH")
+
+/* These STAB's are used on Gould systems for Non-Base register symbols
+ or something like that. FIXME. I have assigned the values at random
+ since I don't have a Gould here. Fixups from Gould folk welcome... */
+__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
+__define_stab (N_NBDATA, 0xF2, "NBDATA")
+__define_stab (N_NBBSS, 0xF4, "NBBSS")
+__define_stab (N_NBSTS, 0xF6, "NBSTS")
+__define_stab (N_NBLCS, 0xF8, "NBLCS")
+
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* The above information, in matrix format.
+
+ STAB MATRIX
+ _________________________________________________
+ | 00 - 1F are not dbx stab symbols |
+ | In most cases, the low bit is the EXTernal bit|
+
+ | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
+ | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
+
+ | 08 BSS | 0A INDR | 0C FN_SEQ | 0E |
+ | 09 |EXT | 0B | 0D | 0F |
+
+ | 10 | 12 COMM | 14 SETA | 16 SETT |
+ | 11 | 13 | 15 | 17 |
+
+ | 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
+ | 19 | 1B | 1D | 1F FN |
+
+ |_______________________________________________|
+ | Debug entries with bit 01 set are unused. |
+ | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
+ | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E |
+ | 30 PC | 32 NSYMS | 34 NOMAP | 36 |
+ | 38 OBJ | 3A | 3C OPT | 3E |
+ | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
+ | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E |
+ | 50 EHDECL*| 52 | 54 CATCH | 56 |
+ | 58 | 5A | 5C | 5E |
+ | 60 SSYM | 62 ENDM | 64 SO | 66 |
+ | 68 | 6A | 6C | 6E |
+ | 70 | 72 | 74 | 76 |
+ | 78 | 7A | 7C | 7E |
+ | 80 LSYM | 82 BINCL | 84 SOL | 86 |
+ | 88 | 8A | 8C | 8E |
+ | 90 | 92 | 94 | 96 |
+ | 98 | 9A | 9C | 9E |
+ | A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
+ | A8 | AA | AC | AE |
+ | B0 | B2 | B4 | B6 |
+ | B8 | BA | BC | BE |
+ | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
+ | C8 | CA | CC | CE |
+ | D0 | D2 | D4 | D6 |
+ | D8 | DA | DC | DE |
+ | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
+ | E8 ECOML | EA WITH | EC | EE |
+ | F0 | F2 | F4 | F6 |
+ | F8 | FA | FC | FE LENG |
+ +-----------------------------------------------+
+ * 50 EHDECL is also MOD2.
+ * 48 BSLINE is also BROWS.
+ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h
new file mode 100644
index 000000000000..477b87d6d86d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h
@@ -0,0 +1,36 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "aout/stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+/* Definitions of "desc" field for N_SO stabs in Solaris2. */
+
+#define N_SO_AS 1
+#define N_SO_C 2
+#define N_SO_ANSI_C 3
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5
+#define N_SO_PASCAL 6
+
+/* Solaris2: Floating point type values in basic types. */
+
+#define NF_NONE 0
+#define NF_SINGLE 1 /* IEEE 32-bit */
+#define NF_DOUBLE 2 /* IEEE 64-bit */
+#define NF_COMPLEX 3 /* Fortran complex */
+#define NF_COMPLEX16 4 /* Fortran double complex */
+#define NF_COMPLEX32 5 /* Fortran complex*16 */
+#define NF_LDOUBLE 6 /* Long double (whatever that is) */
+
+#endif /* __GNU_STAB_ */
diff --git a/gnu/usr.bin/gdb/gdb/blockframe.c b/gnu/usr.bin/gdb/gdb/blockframe.c
new file mode 100644
index 000000000000..c7b3fdce26bd
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/blockframe.c
@@ -0,0 +1,821 @@
+/* Get info from stack frames;
+ convert between frames, blocks, functions and pc values.
+ Copyright 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "value.h" /* for read_register */
+#include "target.h" /* for target_has_stack */
+#include "inferior.h" /* for read_pc */
+
+/* Is ADDR inside the startup file? Note that if your machine
+ has a way to detect the bottom of the stack, there is no need
+ to call this function from FRAME_CHAIN_VALID; the reason for
+ doing so is that some machines have no way of detecting bottom
+ of stack.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_entry_file (addr)
+ CORE_ADDR addr;
+{
+ if (addr == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ /* Do not stop backtracing if the pc is in the call dummy
+ at the entry point. */
+ if (PC_IN_CALL_DUMMY (addr, 0, 0))
+ return 0;
+#endif
+ return (addr >= symfile_objfile -> ei.entry_file_lowpc &&
+ addr < symfile_objfile -> ei.entry_file_highpc);
+}
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the main() function. See comments above for why
+ we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_main_func (pc)
+CORE_ADDR pc;
+{
+ if (pc == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+ return (symfile_objfile -> ei.main_func_lowpc <= pc &&
+ symfile_objfile -> ei.main_func_highpc > pc);
+}
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the process entry point function. See comments
+ in objfiles.h for why we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_entry_func (pc)
+CORE_ADDR pc;
+{
+ if (pc == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ /* Do not stop backtracing if the pc is in the call dummy
+ at the entry point. */
+ if (PC_IN_CALL_DUMMY (pc, 0, 0))
+ return 0;
+#endif
+ return (symfile_objfile -> ei.entry_func_lowpc <= pc &&
+ symfile_objfile -> ei.entry_func_highpc > pc);
+}
+
+/* Address of innermost stack frame (contents of FP register) */
+
+static FRAME current_frame;
+
+/*
+ * Cache for frame addresses already read by gdb. Valid only while
+ * inferior is stopped. Control variables for the frame cache should
+ * be local to this module.
+ */
+struct obstack frame_cache_obstack;
+
+/* Return the innermost (currently executing) stack frame. */
+
+FRAME
+get_current_frame ()
+{
+ /* We assume its address is kept in a general register;
+ param.h says which register. */
+
+ return current_frame;
+}
+
+void
+set_current_frame (frame)
+ FRAME frame;
+{
+ current_frame = frame;
+}
+
+FRAME
+create_new_frame (addr, pc)
+ FRAME_ADDR addr;
+ CORE_ADDR pc;
+{
+ struct frame_info *fci; /* Same type as FRAME */
+ char *name;
+
+ fci = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ /* Arbitrary frame */
+ fci->next = (struct frame_info *) 0;
+ fci->prev = (struct frame_info *) 0;
+ fci->frame = addr;
+ fci->pc = pc;
+ find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ fci->signal_handler_caller = IN_SIGTRAMP (fci->pc, name);
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO (0, fci);
+#endif
+
+ return fci;
+}
+
+/* Return the frame that called FRAME.
+ If FRAME is the original frame (it has no caller), return 0. */
+
+FRAME
+get_prev_frame (frame)
+ FRAME frame;
+{
+ /* We're allowed to know that FRAME and "struct frame_info *" are
+ the same */
+ return get_prev_frame_info (frame);
+}
+
+/* Return the frame that FRAME calls (0 if FRAME is the innermost
+ frame). */
+
+FRAME
+get_next_frame (frame)
+ FRAME frame;
+{
+ /* We're allowed to know that FRAME and "struct frame_info *" are
+ the same */
+ return frame->next;
+}
+
+/*
+ * Flush the entire frame cache.
+ */
+void
+flush_cached_frames ()
+{
+ /* Since we can't really be sure what the first object allocated was */
+ obstack_free (&frame_cache_obstack, 0);
+ obstack_init (&frame_cache_obstack);
+
+ current_frame = (struct frame_info *) 0; /* Invalidate cache */
+}
+
+/* Flush the frame cache, and start a new one if necessary. */
+void
+reinit_frame_cache ()
+{
+ flush_cached_frames ();
+ if (target_has_stack)
+ {
+ set_current_frame (create_new_frame (read_fp (), read_pc ()));
+ select_frame (get_current_frame (), 0);
+ }
+ else
+ {
+ set_current_frame (0);
+ select_frame ((FRAME) 0, -1);
+ }
+}
+
+/* Return a structure containing various interesting information
+ about a specified stack frame. */
+/* How do I justify including this function? Well, the FRAME
+ identifier format has gone through several changes recently, and
+ it's not completely inconceivable that it could happen again. If
+ it does, have this routine around will help */
+
+struct frame_info *
+get_frame_info (frame)
+ FRAME frame;
+{
+ return frame;
+}
+
+/* If a machine allows frameless functions, it should define a macro
+ FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct
+ frame_info for the frame, and FRAMELESS should be set to nonzero
+ if it represents a frameless function invocation. */
+
+/* Return nonzero if the function for this frame lacks a prologue. Many
+ machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
+ function. */
+
+int
+frameless_look_for_prologue (frame)
+ FRAME frame;
+{
+ CORE_ADDR func_start, after_prologue;
+ func_start = (get_pc_function_start (frame->pc) +
+ FUNCTION_START_OFFSET);
+ if (func_start)
+ {
+ after_prologue = func_start;
+#ifdef SKIP_PROLOGUE_FRAMELESS_P
+ /* This is faster, since only care whether there *is* a prologue,
+ not how long it is. */
+ SKIP_PROLOGUE_FRAMELESS_P (after_prologue);
+#else
+ SKIP_PROLOGUE (after_prologue);
+#endif
+ return after_prologue == func_start;
+ }
+ else
+ /* If we can't find the start of the function, we don't really
+ know whether the function is frameless, but we should be able
+ to get a reasonable (i.e. best we can do under the
+ circumstances) backtrace by saying that it isn't. */
+ return 0;
+}
+
+/* Default a few macros that people seldom redefine. */
+
+#if !defined (INIT_FRAME_PC)
+#define INIT_FRAME_PC(fromleaf, prev) \
+ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
+ prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
+#endif
+
+#ifndef FRAME_CHAIN_COMBINE
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+#endif
+
+/* Return a structure containing various interesting information
+ about the frame that called NEXT_FRAME. Returns NULL
+ if there is no such frame. */
+
+struct frame_info *
+get_prev_frame_info (next_frame)
+ FRAME next_frame;
+{
+ FRAME_ADDR address = 0;
+ struct frame_info *prev;
+ int fromleaf = 0;
+ char *name;
+
+ /* If the requested entry is in the cache, return it.
+ Otherwise, figure out what the address should be for the entry
+ we're about to add to the cache. */
+
+ if (!next_frame)
+ {
+#if 0
+ /* This screws value_of_variable, which just wants a nice clean
+ NULL return from block_innermost_frame if there are no frames.
+ I don't think I've ever seen this message happen otherwise.
+ And returning NULL here is a perfectly legitimate thing to do. */
+ if (!current_frame)
+ {
+ error ("You haven't set up a process's stack to examine.");
+ }
+#endif
+
+ return current_frame;
+ }
+
+ /* If we have the prev one, return it */
+ if (next_frame->prev)
+ return next_frame->prev;
+
+ /* On some machines it is possible to call a function without
+ setting up a stack frame for it. On these machines, we
+ define this macro to take two args; a frameinfo pointer
+ identifying a frame and a variable to set or clear if it is
+ or isn't leafless. */
+#ifdef FRAMELESS_FUNCTION_INVOCATION
+ /* Still don't want to worry about this except on the innermost
+ frame. This macro will set FROMLEAF if NEXT_FRAME is a
+ frameless function invocation. */
+ if (!(next_frame->next))
+ {
+ FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf);
+ if (fromleaf)
+ address = next_frame->frame;
+ }
+#endif
+
+ if (!fromleaf)
+ {
+ /* Two macros defined in tm.h specify the machine-dependent
+ actions to be performed here.
+ First, get the frame's chain-pointer.
+ If that is zero, the frame is the outermost frame or a leaf
+ called by the outermost frame. This means that if start
+ calls main without a frame, we'll return 0 (which is fine
+ anyway).
+
+ Nope; there's a problem. This also returns when the current
+ routine is a leaf of main. This is unacceptable. We move
+ this to after the ffi test; I'd rather have backtraces from
+ start go curfluy than have an abort called from main not show
+ main. */
+ address = FRAME_CHAIN (next_frame);
+ if (!FRAME_CHAIN_VALID (address, next_frame))
+ return 0;
+ address = FRAME_CHAIN_COMBINE (address, next_frame);
+ }
+ if (address == 0)
+ return 0;
+
+ prev = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ if (next_frame)
+ next_frame->prev = prev;
+ prev->next = next_frame;
+ prev->prev = (struct frame_info *) 0;
+ prev->frame = address;
+ prev->signal_handler_caller = 0;
+
+/* This change should not be needed, FIXME! We should
+ determine whether any targets *need* INIT_FRAME_PC to happen
+ after INIT_EXTRA_FRAME_INFO and come up with a simple way to
+ express what goes on here.
+
+ INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame
+ (where the PC is already set up) and here (where it isn't).
+ INIT_FRAME_PC is only called from here, always after
+ INIT_EXTRA_FRAME_INFO.
+
+ The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC
+ value (which hasn't been set yet). Some other machines appear to
+ require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC. Phoo.
+
+ We shouldn't need INIT_FRAME_PC_FIRST to add more complication to
+ an already overcomplicated part of GDB. gnu@cygnus.com, 15Sep92.
+
+ To answer the question, yes the sparc needs INIT_FRAME_PC after
+ INIT_EXTRA_FRAME_INFO. Suggested scheme:
+
+ SETUP_INNERMOST_FRAME()
+ Default version is just create_new_frame (read_fp ()),
+ read_pc ()). Machines with extra frame info would do that (or the
+ local equivalent) and then set the extra fields.
+ SETUP_ARBITRARY_FRAME(argc, argv)
+ Only change here is that create_new_frame would no longer init extra
+ frame info; SETUP_ARBITRARY_FRAME would have to do that.
+ INIT_PREV_FRAME(fromleaf, prev)
+ Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC.
+ std_frame_pc(fromleaf, prev)
+ This is the default setting for INIT_PREV_FRAME. It just does what
+ the default INIT_FRAME_PC does. Some machines will call it from
+ INIT_PREV_FRAME (either at the beginning, the end, or in the middle).
+ Some machines won't use it.
+ kingdon@cygnus.com, 13Apr93. */
+
+#ifdef INIT_FRAME_PC_FIRST
+ INIT_FRAME_PC_FIRST (fromleaf, prev);
+#endif
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO(fromleaf, prev);
+#endif
+
+ /* This entry is in the frame queue now, which is good since
+ FRAME_SAVED_PC may use that queue to figure out it's value
+ (see tm-sparc.h). We want the pc saved in the inferior frame. */
+ INIT_FRAME_PC(fromleaf, prev);
+
+ find_pc_partial_function (prev->pc, &name,
+ (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ if (IN_SIGTRAMP (prev->pc, name))
+ prev->signal_handler_caller = 1;
+
+ return prev;
+}
+
+CORE_ADDR
+get_frame_pc (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ fi = get_frame_info (frame);
+ return fi->pc;
+}
+
+#if defined (FRAME_FIND_SAVED_REGS)
+/* Find the addresses in which registers are saved in FRAME. */
+
+void
+get_frame_saved_regs (frame_info_addr, saved_regs_addr)
+ struct frame_info *frame_info_addr;
+ struct frame_saved_regs *saved_regs_addr;
+{
+ FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
+}
+#endif
+
+/* Return the innermost lexical block in execution
+ in a specified stack frame. The frame address is assumed valid. */
+
+struct block *
+get_frame_block (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ CORE_ADDR pc;
+
+ fi = get_frame_info (frame);
+
+ pc = fi->pc;
+ if (fi->next != 0 && fi->next->signal_handler_caller == 0)
+ /* We are not in the innermost frame and we were not interrupted
+ by a signal. We need to subtract one to get the correct block,
+ in case the call instruction was the last instruction of the block.
+ If there are any machines on which the saved pc does not point to
+ after the call insn, we probably want to make fi->pc point after
+ the call insn anyway. */
+ --pc;
+ return block_for_pc (pc);
+}
+
+struct block *
+get_current_block ()
+{
+ return block_for_pc (read_pc ());
+}
+
+CORE_ADDR
+get_pc_function_start (pc)
+ CORE_ADDR pc;
+{
+ register struct block *bl;
+ register struct symbol *symbol;
+ register struct minimal_symbol *msymbol;
+ CORE_ADDR fstart;
+
+ if ((bl = block_for_pc (pc)) != NULL &&
+ (symbol = block_function (bl)) != NULL)
+ {
+ bl = SYMBOL_BLOCK_VALUE (symbol);
+ fstart = BLOCK_START (bl);
+ }
+ else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL)
+ {
+ fstart = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ else
+ {
+ fstart = 0;
+ }
+ return (fstart);
+}
+
+/* Return the symbol for the function executing in frame FRAME. */
+
+struct symbol *
+get_frame_function (frame)
+ FRAME frame;
+{
+ register struct block *bl = get_frame_block (frame);
+ if (bl == 0)
+ return 0;
+ return block_function (bl);
+}
+
+/* Return the blockvector immediately containing the innermost lexical block
+ containing the specified pc value, or 0 if there is none.
+ PINDEX is a pointer to the index value of the block. If PINDEX
+ is NULL, we don't pass this information back to the caller. */
+
+struct blockvector *
+blockvector_for_pc (pc, pindex)
+ register CORE_ADDR pc;
+ int *pindex;
+{
+ register struct block *b;
+ register int bot, top, half;
+ register struct symtab *s;
+ struct blockvector *bl;
+
+ /* First search all symtabs for one whose file contains our pc */
+ s = find_pc_symtab (pc);
+ if (s == 0)
+ return 0;
+
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+
+ /* Then search that symtab for the smallest block that wins. */
+ /* Use binary search to find the last block that starts before PC. */
+
+ bot = 0;
+ top = BLOCKVECTOR_NBLOCKS (bl);
+
+ while (top - bot > 1)
+ {
+ half = (top - bot + 1) >> 1;
+ b = BLOCKVECTOR_BLOCK (bl, bot + half);
+ if (BLOCK_START (b) <= pc)
+ bot += half;
+ else
+ top = bot + half;
+ }
+
+ /* Now search backward for a block that ends after PC. */
+
+ while (bot >= 0)
+ {
+ b = BLOCKVECTOR_BLOCK (bl, bot);
+ if (BLOCK_END (b) > pc)
+ {
+ if (pindex)
+ *pindex = bot;
+ return bl;
+ }
+ bot--;
+ }
+
+ return 0;
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+
+struct block *
+block_for_pc (pc)
+ register CORE_ADDR pc;
+{
+ register struct blockvector *bl;
+ int index;
+
+ bl = blockvector_for_pc (pc, &index);
+ if (bl)
+ return BLOCKVECTOR_BLOCK (bl, index);
+ return 0;
+}
+
+/* Return the function containing pc value PC.
+ Returns 0 if function is not known. */
+
+struct symbol *
+find_pc_function (pc)
+ CORE_ADDR pc;
+{
+ register struct block *b = block_for_pc (pc);
+ if (b == 0)
+ return 0;
+ return block_function (b);
+}
+
+/* These variables are used to cache the most recent result
+ * of find_pc_partial_function. */
+
+static CORE_ADDR cache_pc_function_low = 0;
+static CORE_ADDR cache_pc_function_high = 0;
+static char *cache_pc_function_name = 0;
+
+/* Clear cache, e.g. when symbol table is discarded. */
+
+void
+clear_pc_function_cache()
+{
+ cache_pc_function_low = 0;
+ cache_pc_function_high = 0;
+ cache_pc_function_name = (char *)0;
+}
+
+/* Finds the "function" (text symbol) that is smaller than PC but
+ greatest of all of the potential text symbols. Sets *NAME and/or
+ *ADDRESS conditionally if that pointer is non-null. If ENDADDR is
+ non-null, then set *ENDADDR to be the end of the function
+ (exclusive), but passing ENDADDR as non-null means that the
+ function might cause symbols to be read. This function either
+ succeeds or fails (not halfway succeeds). If it succeeds, it sets
+ *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
+ If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero
+ and returns 0. */
+
+int
+find_pc_partial_function (pc, name, address, endaddr)
+ CORE_ADDR pc;
+ char **name;
+ CORE_ADDR *address;
+ CORE_ADDR *endaddr;
+{
+ struct partial_symtab *pst;
+ struct symbol *f;
+ struct minimal_symbol *msymbol;
+ struct partial_symbol *psb;
+ struct obj_section *sec;
+
+ if (pc >= cache_pc_function_low && pc < cache_pc_function_high)
+ goto return_cached_value;
+
+ /* If sigtramp is in the u area, it counts as a function (especially
+ important for step_1). */
+#if defined SIGTRAMP_START
+ if (IN_SIGTRAMP (pc, (char *)NULL))
+ {
+ cache_pc_function_low = SIGTRAMP_START;
+ cache_pc_function_high = SIGTRAMP_END;
+ cache_pc_function_name = "<sigtramp>";
+
+ goto return_cached_value;
+ }
+#endif
+
+ msymbol = lookup_minimal_symbol_by_pc (pc);
+ pst = find_pc_psymtab (pc);
+ if (pst)
+ {
+ /* Need to read the symbols to get a good value for the end address. */
+ if (endaddr != NULL && !pst->readin)
+ {
+ /* Need to get the terminal in case symbol-reading produces
+ output. */
+ target_terminal_ours_for_output ();
+ PSYMTAB_TO_SYMTAB (pst);
+ }
+
+ if (pst->readin)
+ {
+ /* Checking whether the msymbol has a larger value is for the
+ "pathological" case mentioned in print_frame_info. */
+ f = find_pc_function (pc);
+ if (f != NULL
+ && (msymbol == NULL
+ || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
+ >= SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
+ cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
+ cache_pc_function_name = SYMBOL_NAME (f);
+ goto return_cached_value;
+ }
+ }
+ else
+ {
+ /* Now that static symbols go in the minimal symbol table, perhaps
+ we could just ignore the partial symbols. But at least for now
+ we use the partial or minimal symbol, whichever is larger. */
+ psb = find_pc_psymbol (pst, pc);
+
+ if (psb
+ && (msymbol == NULL ||
+ (SYMBOL_VALUE_ADDRESS (psb)
+ >= SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ /* This case isn't being cached currently. */
+ if (address)
+ *address = SYMBOL_VALUE_ADDRESS (psb);
+ if (name)
+ *name = SYMBOL_NAME (psb);
+ /* endaddr non-NULL can't happen here. */
+ return 1;
+ }
+ }
+ }
+
+ /* Not in the normal symbol tables, see if the pc is in a known section.
+ If it's not, then give up. This ensures that anything beyond the end
+ of the text seg doesn't appear to be part of the last function in the
+ text segment. */
+
+ sec = find_pc_section (pc);
+
+ if (!sec)
+ msymbol = NULL;
+
+ /* Must be in the minimal symbol table. */
+ if (msymbol == NULL)
+ {
+ /* No available symbol. */
+ if (name != NULL)
+ *name = 0;
+ if (address != NULL)
+ *address = 0;
+ if (endaddr != NULL)
+ *endaddr = 0;
+ return 0;
+ }
+
+ /* See if we're in a transfer table for Sun shared libs. */
+
+ if (msymbol -> type == mst_text)
+ cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
+ else
+ /* It is a transfer table for Sun shared libraries. */
+ cache_pc_function_low = pc - FUNCTION_START_OFFSET;
+
+ cache_pc_function_name = SYMBOL_NAME (msymbol);
+
+ /* Use the lesser of the next minimal symbol, or the end of the section, as
+ the end of the function. */
+
+ if (SYMBOL_NAME (msymbol + 1) != NULL
+ && SYMBOL_VALUE_ADDRESS (msymbol + 1) < sec->endaddr)
+ cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1);
+ else
+ /* We got the start address from the last msymbol in the objfile.
+ So the end address is the end of the section. */
+ cache_pc_function_high = sec->endaddr;
+
+ return_cached_value:
+ if (address)
+ *address = cache_pc_function_low;
+ if (name)
+ *name = cache_pc_function_name;
+ if (endaddr)
+ *endaddr = cache_pc_function_high;
+ return 1;
+}
+
+/* Return the innermost stack frame executing inside of BLOCK,
+ or NULL if there is no such frame. If BLOCK is NULL, just return NULL. */
+
+FRAME
+block_innermost_frame (block)
+ struct block *block;
+{
+ struct frame_info *fi;
+ register FRAME frame;
+ register CORE_ADDR start;
+ register CORE_ADDR end;
+
+ if (block == NULL)
+ return NULL;
+
+ start = BLOCK_START (block);
+ end = BLOCK_END (block);
+
+ frame = 0;
+ while (1)
+ {
+ frame = get_prev_frame (frame);
+ if (frame == 0)
+ return 0;
+ fi = get_frame_info (frame);
+ if (fi->pc >= start && fi->pc < end)
+ return frame;
+ }
+}
+
+#ifdef SIGCONTEXT_PC_OFFSET
+/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */
+
+CORE_ADDR
+sigtramp_saved_pc (frame)
+ FRAME frame;
+{
+ CORE_ADDR sigcontext_addr;
+ char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+ int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
+
+ /* Get sigcontext address, it is the third parameter on the stack. */
+ if (frame->next)
+ sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next)
+ + FRAME_ARGS_SKIP + sigcontext_offs,
+ ptrbytes);
+ else
+ sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
+ + sigcontext_offs,
+ ptrbytes);
+
+ /* Don't cause a memory_error when accessing sigcontext in case the stack
+ layout has changed or the stack is corrupt. */
+ target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
+ return extract_unsigned_integer (buf, ptrbytes);
+}
+#endif /* SIGCONTEXT_PC_OFFSET */
+
+void
+_initialize_blockframe ()
+{
+ obstack_init (&frame_cache_obstack);
+}
diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.c b/gnu/usr.bin/gdb/gdb/breakpoint.c
new file mode 100644
index 000000000000..69694c016f67
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.c
@@ -0,0 +1,3301 @@
+/* Everything about breakpoints, for GDB.
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "ctype.h"
+#include "command.h"
+#include "inferior.h"
+#include "target.h"
+#include "language.h"
+#include <string.h>
+#include "demangle.h"
+
+/* local function prototypes */
+
+static void
+catch_command_1 PARAMS ((char *, int, int));
+
+static void
+enable_delete_command PARAMS ((char *, int));
+
+static void
+enable_delete_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_once_command PARAMS ((char *, int));
+
+static void
+enable_once_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+disable_command PARAMS ((char *, int));
+
+static void
+disable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_command PARAMS ((char *, int));
+
+static void
+enable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *)));
+
+static void
+ignore_command PARAMS ((char *, int));
+
+static int
+breakpoint_re_set_one PARAMS ((char *));
+
+static void
+delete_command PARAMS ((char *, int));
+
+static void
+clear_command PARAMS ((char *, int));
+
+static void
+catch_command PARAMS ((char *, int));
+
+static struct symtabs_and_lines
+get_catch_sals PARAMS ((int));
+
+static void
+watch_command PARAMS ((char *, int));
+
+static void
+tbreak_command PARAMS ((char *, int));
+
+static void
+break_command_1 PARAMS ((char *, int, int));
+
+static void
+mention PARAMS ((struct breakpoint *));
+
+static struct breakpoint *
+set_raw_breakpoint PARAMS ((struct symtab_and_line));
+
+static void
+check_duplicates PARAMS ((CORE_ADDR));
+
+static void
+describe_other_breakpoints PARAMS ((CORE_ADDR));
+
+static void
+breakpoints_info PARAMS ((char *, int));
+
+static void
+breakpoint_1 PARAMS ((int, int));
+
+static bpstat
+bpstat_alloc PARAMS ((struct breakpoint *, bpstat));
+
+static int
+breakpoint_cond_eval PARAMS ((char *));
+
+static void
+cleanup_executing_breakpoints PARAMS ((int));
+
+static void
+commands_command PARAMS ((char *, int));
+
+static void
+condition_command PARAMS ((char *, int));
+
+static int
+get_number PARAMS ((char **));
+
+static void
+set_breakpoint_count PARAMS ((int));
+
+
+extern int addressprint; /* Print machine addresses? */
+extern int demangle; /* Print de-mangled symbol names? */
+
+/* Are we executing breakpoint commands? */
+static int executing_breakpoint_commands;
+
+/* Walk the following statement or block through all breakpoints.
+ ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
+ breakpoint. */
+
+#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next)
+
+#define ALL_BREAKPOINTS_SAFE(b,tmp) \
+ for (b = breakpoint_chain; \
+ b? (tmp=b->next, 1): 0; \
+ b = tmp)
+
+/* Chain of all breakpoints defined. */
+
+struct breakpoint *breakpoint_chain;
+
+/* Number of last breakpoint made. */
+
+static int breakpoint_count;
+
+/* Set breakpoint count to NUM. */
+static void
+set_breakpoint_count (num)
+ int num;
+{
+ breakpoint_count = num;
+ set_internalvar (lookup_internalvar ("bpnum"),
+ value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Default address, symtab and line to put a breakpoint at
+ for "break" command with no arg.
+ if default_breakpoint_valid is zero, the other three are
+ not valid, and "break" with no arg is an error.
+
+ This set by print_stack_frame, which calls set_default_breakpoint. */
+
+int default_breakpoint_valid;
+CORE_ADDR default_breakpoint_address;
+struct symtab *default_breakpoint_symtab;
+int default_breakpoint_line;
+
+/* Flag indicating extra verbosity for xgdb. */
+extern int xgdb_verbose;
+
+/* *PP is a string denoting a breakpoint. Get the number of the breakpoint.
+ Advance *PP after the string and any trailing whitespace.
+
+ Currently the string can either be a number or "$" followed by the name
+ of a convenience variable. Making it an expression wouldn't work well
+ for map_breakpoint_numbers (e.g. "4 + 5 + 6"). */
+static int
+get_number (pp)
+ char **pp;
+{
+ int retval;
+ char *p = *pp;
+
+ if (p == NULL)
+ /* Empty line means refer to the last breakpoint. */
+ return breakpoint_count;
+ else if (*p == '$')
+ {
+ /* Make a copy of the name, so we can null-terminate it
+ to pass to lookup_internalvar(). */
+ char *varname;
+ char *start = ++p;
+ value val;
+
+ while (isalnum (*p) || *p == '_')
+ p++;
+ varname = (char *) alloca (p - start + 1);
+ strncpy (varname, start, p - start);
+ varname[p - start] = '\0';
+ val = value_of_internalvar (lookup_internalvar (varname));
+ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_INT)
+ error (
+"Convenience variables used to specify breakpoints must have integer values."
+ );
+ retval = (int) value_as_long (val);
+ }
+ else
+ {
+ if (*p == '-')
+ ++p;
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ if (p == *pp)
+ /* There is no number here. (e.g. "cond a == b"). */
+ error_no_arg ("breakpoint number");
+ retval = atoi (*pp);
+ }
+ if (!(isspace (*p) || *p == '\0'))
+ error ("breakpoint number expected");
+ while (isspace (*p))
+ p++;
+ *pp = p;
+ return retval;
+}
+
+/* condition N EXP -- set break condition of breakpoint N to EXP. */
+
+static void
+condition_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b;
+ char *p;
+ register int bnum;
+
+ if (arg == 0)
+ error_no_arg ("breakpoint number");
+
+ p = arg;
+ bnum = get_number (&p);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (b->cond)
+ {
+ free ((PTR)b->cond);
+ b->cond = 0;
+ }
+ if (b->cond_string != NULL)
+ free ((PTR)b->cond_string);
+
+ if (*p == 0)
+ {
+ b->cond = 0;
+ b->cond_string = NULL;
+ if (from_tty)
+ printf_filtered ("Breakpoint %d now unconditional.\n", bnum);
+ }
+ else
+ {
+ arg = p;
+ /* I don't know if it matters whether this is the string the user
+ typed in or the decompiled expression. */
+ b->cond_string = savestring (arg, strlen (arg));
+ b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0);
+ if (*arg)
+ error ("Junk at end of expression");
+ }
+ return;
+ }
+
+ error ("No breakpoint number %d.", bnum);
+}
+
+/* ARGSUSED */
+static void
+commands_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b;
+ char *p;
+ register int bnum;
+ struct command_line *l;
+
+ /* If we allowed this, we would have problems with when to
+ free the storage, if we change the commands currently
+ being read from. */
+
+ if (executing_breakpoint_commands)
+ error ("Can't use the \"commands\" command among a breakpoint's commands.");
+
+ p = arg;
+ bnum = get_number (&p);
+ if (p && *p)
+ error ("Unexpected extra arguments following breakpoint number.");
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (from_tty && input_from_terminal_p ())
+ printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\
+End with a line saying just \"end\".\n", bnum);
+ l = read_command_lines ();
+ free_command_lines (&b->commands);
+ b->commands = l;
+ return;
+ }
+ error ("No breakpoint number %d.", bnum);
+}
+
+extern int memory_breakpoint_size; /* from mem-break.c */
+
+/* Like target_read_memory() but if breakpoints are inserted, return
+ the shadow contents instead of the breakpoints themselves.
+
+ Read "memory data" from whatever target or inferior we have.
+ Returns zero if successful, errno value if not. EIO is used
+ for address out of bounds. If breakpoints are inserted, returns
+ shadow contents, not the breakpoints themselves. From breakpoint.c. */
+
+int
+read_memory_nobpt (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ unsigned len;
+{
+ int status;
+ struct breakpoint *b;
+
+ if (memory_breakpoint_size < 0)
+ /* No breakpoints on this machine. FIXME: This should be
+ dependent on the debugging target. Probably want
+ target_insert_breakpoint to return a size, saying how many
+ bytes of the shadow contents are used, or perhaps have
+ something like target_xfer_shadow. */
+ return target_read_memory (memaddr, myaddr, len);
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_watchpoint || !b->inserted)
+ continue;
+ else if (b->address + memory_breakpoint_size <= memaddr)
+ /* The breakpoint is entirely before the chunk of memory
+ we are reading. */
+ continue;
+ else if (b->address >= memaddr + len)
+ /* The breakpoint is entirely after the chunk of memory we
+ are reading. */
+ continue;
+ else
+ {
+ /* Copy the breakpoint from the shadow contents, and recurse
+ for the things before and after. */
+
+ /* Addresses and length of the part of the breakpoint that
+ we need to copy. */
+ CORE_ADDR membpt = b->address;
+ unsigned int bptlen = memory_breakpoint_size;
+ /* Offset within shadow_contents. */
+ int bptoffset = 0;
+
+ if (membpt < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bptlen -= memaddr - membpt;
+ bptoffset = memaddr - membpt;
+ membpt = memaddr;
+ }
+
+ if (membpt + bptlen > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bptlen -= (membpt + bptlen) - (memaddr + len);
+ }
+
+ memcpy (myaddr + membpt - memaddr,
+ b->shadow_contents + bptoffset, bptlen);
+
+ if (membpt > memaddr)
+ {
+ /* Copy the section of memory before the breakpoint. */
+ status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr);
+ if (status != 0)
+ return status;
+ }
+
+ if (membpt + bptlen < memaddr + len)
+ {
+ /* Copy the section of memory after the breakpoint. */
+ status = read_memory_nobpt
+ (membpt + bptlen,
+ myaddr + membpt + bptlen - memaddr,
+ memaddr + len - (membpt + bptlen));
+ if (status != 0)
+ return status;
+ }
+ return 0;
+ }
+ }
+ /* Nothing overlaps. Just call read_memory_noerr. */
+ return target_read_memory (memaddr, myaddr, len);
+}
+
+/* insert_breakpoints is used when starting or continuing the program.
+ remove_breakpoints is used when the program stops.
+ Both return zero if successful,
+ or an `errno' value if could not write the inferior. */
+
+int
+insert_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val = 0;
+ int disabled_breaks = 0;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type != bp_watchpoint
+ && b->enable != disabled
+ && ! b->inserted
+ && ! b->duplicate)
+ {
+ val = target_insert_breakpoint(b->address, b->shadow_contents);
+ if (val)
+ {
+ /* Can't set the breakpoint. */
+#if defined (DISABLE_UNSETTABLE_BREAK)
+ if (DISABLE_UNSETTABLE_BREAK (b->address))
+ {
+ val = 0;
+ b->enable = disabled;
+ if (!disabled_breaks)
+ {
+ fprintf (stderr,
+ "Cannot insert breakpoint %d:\n", b->number);
+ printf_filtered ("Disabling shared library breakpoints:\n");
+ }
+ disabled_breaks = 1;
+ printf_filtered ("%d ", b->number);
+ }
+ else
+#endif
+ {
+ fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
+#ifdef ONE_PROCESS_WRITETEXT
+ fprintf (stderr,
+ "The same program may be running in another process.\n");
+#endif
+ memory_error (val, b->address); /* which bombs us out */
+ }
+ }
+ else
+ b->inserted = 1;
+ }
+ if (disabled_breaks)
+ printf_filtered ("\n");
+ return val;
+}
+
+int
+remove_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val;
+
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removing breakpoints.\n");
+#endif /* BREAKPOINT_DEBUG */
+
+ ALL_BREAKPOINTS (b)
+ if (b->type != bp_watchpoint && b->inserted)
+ {
+ val = target_remove_breakpoint(b->address, b->shadow_contents);
+ if (val)
+ return val;
+ b->inserted = 0;
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removed breakpoint at %s",
+ local_hex_string((unsigned long) b->address));
+ printf (", shadow %s",
+ local_hex_string((unsigned long) b->shadow_contents[0]));
+ printf (", %s.\n",
+ local_hex_string((unsigned long) b->shadow_contents[1]));
+#endif /* BREAKPOINT_DEBUG */
+ }
+
+ return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints. */
+
+void
+mark_breakpoints_out ()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->inserted = 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints and delete any breakpoints
+ which should go away between runs of the program. */
+
+void
+breakpoint_init_inferior ()
+{
+ register struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ b->inserted = 0;
+
+ /* If the call dummy breakpoint is at the entry point it will
+ cause problems when the inferior is rerun, so we better
+ get rid of it. */
+ if (b->type == bp_call_dummy)
+ delete_breakpoint (b);
+ }
+}
+
+/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC.
+ When continuing from a location with a breakpoint,
+ we actually single step once before calling insert_breakpoints. */
+
+int
+breakpoint_here_p (pc)
+ CORE_ADDR pc;
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && b->address == pc)
+ return 1;
+
+ return 0;
+}
+
+/* breakpoint_match_thread (PC, PID) returns true if the breakpoint at PC
+ is valid for process/thread PID. */
+
+int
+breakpoint_thread_match (pc, pid)
+ CORE_ADDR pc;
+ int pid;
+{
+ struct breakpoint *b;
+ int thread;
+
+ thread = pid_to_thread_id (pid);
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled
+ && b->address == pc
+ && (b->thread == -1 || b->thread == thread))
+ return 1;
+
+ return 0;
+}
+
+
+/* bpstat stuff. External routines' interfaces are documented
+ in breakpoint.h. */
+
+/* Clear a bpstat so that it says we are not at any breakpoint.
+ Also free any storage that is part of a bpstat. */
+
+void
+bpstat_clear (bsp)
+ bpstat *bsp;
+{
+ bpstat p;
+ bpstat q;
+
+ if (bsp == 0)
+ return;
+ p = *bsp;
+ while (p != NULL)
+ {
+ q = p->next;
+ if (p->old_val != NULL)
+ value_free (p->old_val);
+ free ((PTR)p);
+ p = q;
+ }
+ *bsp = NULL;
+}
+
+/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
+ is part of the bpstat is copied as well. */
+
+bpstat
+bpstat_copy (bs)
+ bpstat bs;
+{
+ bpstat p = NULL;
+ bpstat tmp;
+ bpstat retval = NULL;
+
+ if (bs == NULL)
+ return bs;
+
+ for (; bs != NULL; bs = bs->next)
+ {
+ tmp = (bpstat) xmalloc (sizeof (*tmp));
+ memcpy (tmp, bs, sizeof (*tmp));
+ if (p == NULL)
+ /* This is the first thing in the chain. */
+ retval = tmp;
+ else
+ p->next = tmp;
+ p = tmp;
+ }
+ p->next = NULL;
+ return retval;
+}
+
+/* Find the bpstat associated with this breakpoint */
+
+bpstat
+bpstat_find_breakpoint(bsp, breakpoint)
+ bpstat bsp;
+ struct breakpoint *breakpoint;
+{
+ if (bsp == NULL) return NULL;
+
+ for (;bsp != NULL; bsp = bsp->next) {
+ if (bsp->breakpoint_at == breakpoint) return bsp;
+ }
+ return NULL;
+}
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+ at. *BSP upon return is a bpstat which points to the remaining
+ breakpoints stopped at (but which is not guaranteed to be good for
+ anything but further calls to bpstat_num).
+ Return 0 if passed a bpstat which does not indicate any breakpoints. */
+
+int
+bpstat_num (bsp)
+ bpstat *bsp;
+{
+ struct breakpoint *b;
+
+ if ((*bsp) == NULL)
+ return 0; /* No more breakpoint values */
+ else
+ {
+ b = (*bsp)->breakpoint_at;
+ *bsp = (*bsp)->next;
+ if (b == NULL)
+ return -1; /* breakpoint that's been deleted since */
+ else
+ return b->number; /* We have its number */
+ }
+}
+
+/* Modify BS so that the actions will not be performed. */
+
+void
+bpstat_clear_actions (bs)
+ bpstat bs;
+{
+ for (; bs != NULL; bs = bs->next)
+ {
+ bs->commands = NULL;
+ if (bs->old_val != NULL)
+ {
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ }
+ }
+}
+
+/* Stub for cleaning up our state if we error-out of a breakpoint command */
+/* ARGSUSED */
+static void
+cleanup_executing_breakpoints (ignore)
+ int ignore;
+{
+ executing_breakpoint_commands = 0;
+}
+
+/* Execute all the commands associated with all the breakpoints at this
+ location. Any of these commands could cause the process to proceed
+ beyond this point, etc. We look out for such changes by checking
+ the global "breakpoint_proceeded" after each command. */
+
+void
+bpstat_do_actions (bsp)
+ bpstat *bsp;
+{
+ bpstat bs;
+ struct cleanup *old_chain;
+
+ executing_breakpoint_commands = 1;
+ old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
+
+top:
+ bs = *bsp;
+
+ breakpoint_proceeded = 0;
+ for (; bs != NULL; bs = bs->next)
+ {
+ while (bs->commands)
+ {
+ char *line = bs->commands->line;
+ bs->commands = bs->commands->next;
+ execute_command (line, 0);
+ /* If the inferior is proceeded by the command, bomb out now.
+ The bpstat chain has been blown away by wait_for_inferior.
+ But since execution has stopped again, there is a new bpstat
+ to look at, so start over. */
+ if (breakpoint_proceeded)
+ goto top;
+ }
+ }
+
+ executing_breakpoint_commands = 0;
+ discard_cleanups (old_chain);
+}
+
+/* This is the normal print_it function for a bpstat. In the future,
+ much of this logic could (should?) be moved to bpstat_stop_status,
+ by having it set different print_it functions. */
+
+static int
+print_it_normal (bs)
+ bpstat bs;
+{
+ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+ which has since been deleted. */
+ if (bs->breakpoint_at == NULL
+ || (bs->breakpoint_at->type != bp_breakpoint
+ && bs->breakpoint_at->type != bp_watchpoint))
+ return 0;
+
+ if (bs->breakpoint_at->type == bp_breakpoint)
+ {
+ /* I think the user probably only wants to see one breakpoint
+ number, not all of them. */
+ printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
+ return 0;
+ }
+
+ if (bs->old_val != NULL)
+ {
+ printf_filtered ("\nWatchpoint %d, ", bs->breakpoint_at->number);
+ print_expression (bs->breakpoint_at->exp, stdout);
+ printf_filtered ("\nOld value = ");
+ value_print (bs->old_val, stdout, 0, Val_pretty_default);
+ printf_filtered ("\nNew value = ");
+ value_print (bs->breakpoint_at->val, stdout, 0,
+ Val_pretty_default);
+ printf_filtered ("\n");
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ return 0;
+ }
+ /* We can't deal with it. Maybe another member of the bpstat chain can. */
+ return -1;
+}
+
+/* Print a message indicating what happened. Returns nonzero to
+ say that only the source line should be printed after this (zero
+ return means print the frame as well as the source line). */
+/* Currently we always return zero. */
+int
+bpstat_print (bs)
+ bpstat bs;
+{
+ int val;
+
+ if (bs == NULL)
+ return 0;
+
+ val = (*bs->print_it) (bs);
+ if (val >= 0)
+ return val;
+
+ /* Maybe another breakpoint in the chain caused us to stop.
+ (Currently all watchpoints go on the bpstat whether hit or
+ not. That probably could (should) be changed, provided care is taken
+ with respect to bpstat_explains_signal). */
+ if (bs->next)
+ return bpstat_print (bs->next);
+
+ /* We reached the end of the chain without printing anything. */
+ return 0;
+}
+
+/* Evaluate the expression EXP and return 1 if value is zero.
+ This is used inside a catch_errors to evaluate the breakpoint condition.
+ The argument is a "struct expression *" that has been cast to char * to
+ make it pass through catch_errors. */
+
+static int
+breakpoint_cond_eval (exp)
+ char *exp;
+{
+ return !value_true (evaluate_expression ((struct expression *)exp));
+}
+
+/* Allocate a new bpstat and chain it to the current one. */
+
+static bpstat
+bpstat_alloc (b, cbs)
+ register struct breakpoint *b;
+ bpstat cbs; /* Current "bs" value */
+{
+ bpstat bs;
+
+ bs = (bpstat) xmalloc (sizeof (*bs));
+ cbs->next = bs;
+ bs->breakpoint_at = b;
+ /* If the condition is false, etc., don't do the commands. */
+ bs->commands = NULL;
+ bs->old_val = NULL;
+ bs->print_it = print_it_normal;
+ return bs;
+}
+
+/* Return the frame which we can use to evaluate the expression
+ whose valid block is valid_block, or NULL if not in scope.
+
+ This whole concept is probably not the way to do things (it is incredibly
+ slow being the main reason, not to mention fragile (e.g. the sparc
+ frame pointer being fetched as 0 bug causes it to stop)). Instead,
+ introduce a version of "struct frame" which survives over calls to the
+ inferior, but which is better than FRAME_ADDR in the sense that it lets
+ us evaluate expressions relative to that frame (on some machines, it
+ can just be a FRAME_ADDR). Save one of those instead of (or in addition
+ to) the exp_valid_block, and then use it to evaluate the watchpoint
+ expression, with no need to do all this backtracing every time.
+
+ Or better yet, what if it just copied the struct frame and its next
+ frame? Off the top of my head, I would think that would work
+ because things like (a29k) rsize and msize, or (sparc) bottom just
+ depend on the frame, and aren't going to be different just because
+ the inferior has done something. Trying to recalculate them
+ strikes me as a lot of work, possibly even impossible. Saving the
+ next frame is needed at least on a29k, where get_saved_register
+ uses fi->next->saved_msp. For figuring out whether that frame is
+ still on the stack, I guess this needs to be machine-specific (e.g.
+ a29k) but I think
+
+ read_fp () INNER_THAN watchpoint_frame->frame
+
+ would generally work.
+
+ Of course the scope of the expression could be less than a whole
+ function; perhaps if the innermost frame is the one which the
+ watchpoint is relative to (another machine-specific thing, usually
+
+ FRAMELESS_FUNCTION_INVOCATION (get_current_frame(), fromleaf)
+ read_fp () == wp_frame->frame
+ && !fromleaf
+
+ ), *then* it could do a
+
+ contained_in (get_current_block (), wp->exp_valid_block).
+
+ */
+
+FRAME
+within_scope (valid_block)
+ struct block *valid_block;
+{
+ FRAME fr = get_current_frame ();
+ struct frame_info *fi = get_frame_info (fr);
+ CORE_ADDR func_start;
+
+ /* If caller_pc_valid is true, we are stepping through
+ a function prologue, which is bounded by callee_func_start
+ (inclusive) and callee_prologue_end (exclusive).
+ caller_pc is the pc of the caller.
+
+ Yes, this is hairy. */
+ static int caller_pc_valid = 0;
+ static CORE_ADDR caller_pc;
+ static CORE_ADDR callee_func_start;
+ static CORE_ADDR callee_prologue_end;
+
+ find_pc_partial_function (fi->pc, (PTR)NULL, &func_start, (CORE_ADDR *)NULL);
+ func_start += FUNCTION_START_OFFSET;
+ if (fi->pc == func_start)
+ {
+ /* We just called a function. The only other case I
+ can think of where the pc would equal the pc of the
+ start of a function is a frameless function (i.e.
+ no prologue) where we branch back to the start
+ of the function. In that case, SKIP_PROLOGUE won't
+ find one, and we'll clear caller_pc_valid a few lines
+ down. */
+ caller_pc_valid = 1;
+ caller_pc = SAVED_PC_AFTER_CALL (fr);
+ callee_func_start = func_start;
+ SKIP_PROLOGUE (func_start);
+ callee_prologue_end = func_start;
+ }
+ if (caller_pc_valid)
+ {
+ if (fi->pc < callee_func_start
+ || fi->pc >= callee_prologue_end)
+ caller_pc_valid = 0;
+ }
+
+ if (contained_in (block_for_pc (caller_pc_valid
+ ? caller_pc
+ : fi->pc),
+ valid_block))
+ {
+ return fr;
+ }
+ fr = get_prev_frame (fr);
+
+ /* If any active frame is in the exp_valid_block, then it's
+ OK. Note that this might not be the same invocation of
+ the exp_valid_block that we were watching a little while
+ ago, or the same one as when the watchpoint was set (e.g.
+ we are watching a local variable in a recursive function.
+ When we return from a recursive invocation, then we are
+ suddenly watching a different instance of the variable).
+
+ At least for now I am going to consider this a feature. */
+ for (; fr != NULL; fr = get_prev_frame (fr))
+ {
+ fi = get_frame_info (fr);
+ if (contained_in (block_for_pc (fi->pc),
+ valid_block))
+ {
+ return fr;
+ }
+ }
+ return NULL;
+}
+
+/* Possible return values for watchpoint_check (this can't be an enum
+ because of check_errors). */
+/* The watchpoint has been disabled. */
+#define WP_DISABLED 1
+/* The value has changed. */
+#define WP_VALUE_CHANGED 2
+/* The value has not changed. */
+#define WP_VALUE_NOT_CHANGED 3
+
+/* Check watchpoint condition. */
+static int
+watchpoint_check (p)
+ char *p;
+{
+ bpstat bs = (bpstat) p;
+ FRAME fr;
+
+ int within_current_scope;
+ if (bs->breakpoint_at->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ fr = within_scope (bs->breakpoint_at->exp_valid_block);
+ within_current_scope = fr != NULL;
+ if (within_current_scope)
+ /* If we end up stopping, the current frame will get selected
+ in normal_stop. So this call to select_frame won't affect
+ the user. */
+ select_frame (fr, -1);
+ }
+
+ if (within_current_scope)
+ {
+ /* We use value_{,free_to_}mark because it could be a
+ *long* time before we return to the command level and
+ call free_all_values. We can't call free_all_values because
+ we might be in the middle of evaluating a function call. */
+
+ value mark = value_mark ();
+ value new_val = evaluate_expression (bs->breakpoint_at->exp);
+ if (!value_equal (bs->breakpoint_at->val, new_val))
+ {
+ release_value (new_val);
+ value_free_to_mark (mark);
+ bs->old_val = bs->breakpoint_at->val;
+ bs->breakpoint_at->val = new_val;
+ /* We will stop here */
+ return WP_VALUE_CHANGED;
+ }
+ else
+ {
+ /* Nothing changed, don't do anything. */
+ value_free_to_mark (mark);
+ /* We won't stop here */
+ return WP_VALUE_NOT_CHANGED;
+ }
+ }
+ else
+ {
+ /* This seems like the only logical thing to do because
+ if we temporarily ignored the watchpoint, then when
+ we reenter the block in which it is valid it contains
+ garbage (in the case of a function, it may have two
+ garbage values, one before and one after the prologue).
+ So we can't even detect the first assignment to it and
+ watch after that (since the garbage may or may not equal
+ the first value assigned). */
+ bs->breakpoint_at->enable = disabled;
+ printf_filtered ("\
+Watchpoint %d disabled because the program has left the block in\n\
+which its expression is valid.\n", bs->breakpoint_at->number);
+ return WP_DISABLED;
+ }
+}
+
+/* This is used when everything which needs to be printed has
+ already been printed. But we still want to print the frame. */
+static int
+print_it_done (bs)
+ bpstat bs;
+{
+ return 0;
+}
+
+/* This is used when nothing should be printed for this bpstat entry. */
+
+static int
+print_it_noop (bs)
+ bpstat bs;
+{
+ return -1;
+}
+
+/* Get a bpstat associated with having just stopped at address *PC
+ and frame address FRAME_ADDRESS. Update *PC to point at the
+ breakpoint (if we hit a breakpoint). NOT_A_BREAKPOINT is nonzero
+ if this is known to not be a real breakpoint (it could still be a
+ watchpoint, though). */
+
+/* Determine whether we stopped at a breakpoint, etc, or whether we
+ don't understand this stop. Result is a chain of bpstat's such that:
+
+ if we don't understand the stop, the result is a null pointer.
+
+ if we understand why we stopped, the result is not null.
+
+ Each element of the chain refers to a particular breakpoint or
+ watchpoint at which we have stopped. (We may have stopped for
+ several reasons concurrently.)
+
+ Each element of the chain has valid next, breakpoint_at,
+ commands, FIXME??? fields.
+
+ */
+
+bpstat
+bpstat_stop_status (pc, frame_address, not_a_breakpoint)
+ CORE_ADDR *pc;
+ FRAME_ADDR frame_address;
+ int not_a_breakpoint;
+{
+ register struct breakpoint *b;
+ CORE_ADDR bp_addr;
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ /* True if we've hit a breakpoint (as opposed to a watchpoint). */
+ int real_breakpoint = 0;
+#endif
+ /* Root of the chain of bpstat's */
+ struct bpstat root_bs[1];
+ /* Pointer to the last thing in the chain currently. */
+ bpstat bs = root_bs;
+
+ /* Get the address where the breakpoint would have been. */
+ bp_addr = *pc - DECR_PC_AFTER_BREAK;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->enable == disabled)
+ continue;
+
+ if (b->type != bp_watchpoint && b->address != bp_addr)
+ continue;
+
+ if (b->type != bp_watchpoint && not_a_breakpoint)
+ continue;
+
+ /* Come here if it's a watchpoint, or if the break address matches */
+
+ bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+
+ bs->stop = 1;
+ bs->print = 1;
+
+ if (b->type == bp_watchpoint)
+ {
+ static char message1[] =
+ "Error evaluating expression for watchpoint %d\n";
+ char message[sizeof (message1) + 30 /* slop */];
+ sprintf (message, message1, b->number);
+ switch (catch_errors (watchpoint_check, (char *) bs, message,
+ RETURN_MASK_ALL))
+ {
+ case WP_DISABLED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ /* Stop. */
+ break;
+ case WP_VALUE_NOT_CHANGED:
+ /* Don't stop. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ default:
+ /* Can't happen. */
+ /* FALLTHROUGH */
+ case 0:
+ /* Error from catch_errors. */
+ b->enable = disabled;
+ printf_filtered ("Watchpoint %d disabled.\n", b->number);
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ }
+ }
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ else
+ real_breakpoint = 1;
+#endif
+
+ if (b->frame && b->frame != frame_address)
+ bs->stop = 0;
+ else
+ {
+ int value_is_zero = 0;
+
+ if (b->cond)
+ {
+ /* Need to select the frame, with all that implies
+ so that the conditions will have the right context. */
+ select_frame (get_current_frame (), 0);
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, (char *)(b->cond),
+ "Error in testing breakpoint condition:\n",
+ RETURN_MASK_ALL);
+ /* FIXME-someday, should give breakpoint # */
+ free_all_values ();
+ }
+ if (b->cond && value_is_zero)
+ {
+ bs->stop = 0;
+ }
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ bs->stop = 0;
+ }
+ else
+ {
+ /* We will stop here */
+ if (b->disposition == disable)
+ b->enable = disabled;
+ bs->commands = b->commands;
+ if (b->silent)
+ bs->print = 0;
+ if (bs->commands && STREQ ("silent", bs->commands->line))
+ {
+ bs->commands = bs->commands->next;
+ bs->print = 0;
+ }
+ }
+ }
+ /* Print nothing for this entry if we dont stop or if we dont print. */
+ if (bs->stop == 0 || bs->print == 0)
+ bs->print_it = print_it_noop;
+ }
+
+ bs->next = NULL; /* Terminate the chain */
+ bs = root_bs->next; /* Re-grab the head of the chain */
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ if (bs)
+ {
+ if (real_breakpoint)
+ {
+ *pc = bp_addr;
+#if defined (SHIFT_INST_REGS)
+ SHIFT_INST_REGS();
+#else /* No SHIFT_INST_REGS. */
+ write_pc (bp_addr);
+#endif /* No SHIFT_INST_REGS. */
+ }
+ }
+#endif /* DECR_PC_AFTER_BREAK != 0. */
+ return bs;
+}
+
+/* Tell what to do about this bpstat. */
+struct bpstat_what
+bpstat_what (bs)
+ bpstat bs;
+{
+ /* Classify each bpstat as one of the following. */
+ enum class {
+ /* This bpstat element has no effect on the main_action. */
+ no_effect = 0,
+
+ /* There was a watchpoint, stop but don't print. */
+ wp_silent,
+
+ /* There was a watchpoint, stop and print. */
+ wp_noisy,
+
+ /* There was a breakpoint but we're not stopping. */
+ bp_nostop,
+
+ /* There was a breakpoint, stop but don't print. */
+ bp_silent,
+
+ /* There was a breakpoint, stop and print. */
+ bp_noisy,
+
+ /* We hit the longjmp breakpoint. */
+ long_jump,
+
+ /* We hit the longjmp_resume breakpoint. */
+ long_resume,
+
+ /* This is just used to count how many enums there are. */
+ class_last
+ };
+
+ /* Here is the table which drives this routine. So that we can
+ format it pretty, we define some abbreviations for the
+ enum bpstat_what codes. */
+#define keep_c BPSTAT_WHAT_KEEP_CHECKING
+#define stop_s BPSTAT_WHAT_STOP_SILENT
+#define stop_n BPSTAT_WHAT_STOP_NOISY
+#define single BPSTAT_WHAT_SINGLE
+#define setlr BPSTAT_WHAT_SET_LONGJMP_RESUME
+#define clrlr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
+#define clrlrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
+/* "Can't happen." Might want to print an error message.
+ abort() is not out of the question, but chances are GDB is just
+ a bit confused, not unusable. */
+#define err BPSTAT_WHAT_STOP_NOISY
+
+ /* Given an old action and a class, come up with a new action. */
+ /* One interesting property of this table is that wp_silent is the same
+ as bp_silent and wp_noisy is the same as bp_noisy. That is because
+ after stopping, the check for whether to step over a breakpoint
+ (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without
+ reference to how we stopped. We retain separate wp_silent and bp_silent
+ codes in case we want to change that someday. */
+ static const enum bpstat_what_main_action
+ table[(int)class_last][(int)BPSTAT_WHAT_LAST] =
+ {
+ /* old action */
+ /* keep_c stop_s stop_n single setlr clrlr clrlrs */
+
+/*no_effect*/ {keep_c, stop_s, stop_n, single, setlr , clrlr , clrlrs},
+/*wp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s},
+/*wp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n},
+/*bp_nostop*/ {single, stop_s, stop_n, single, setlr , clrlrs, clrlrs},
+/*bp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s},
+/*bp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n},
+/*long_jump*/ {setlr , stop_s, stop_n, setlr , err , err , err },
+/*long_resume*/ {clrlr , stop_s, stop_n, clrlrs, err , err , err }
+ };
+#undef keep_c
+#undef stop_s
+#undef stop_n
+#undef single
+#undef setlr
+#undef clrlr
+#undef clrlrs
+#undef err
+ enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
+ struct bpstat_what retval;
+
+ retval.call_dummy = 0;
+ retval.step_resume = 0;
+ for (; bs != NULL; bs = bs->next)
+ {
+ enum class bs_class = no_effect;
+ if (bs->breakpoint_at == NULL)
+ /* I suspect this can happen if it was a momentary breakpoint
+ which has since been deleted. */
+ continue;
+ switch (bs->breakpoint_at->type)
+ {
+ case bp_breakpoint:
+ case bp_until:
+ case bp_finish:
+ if (bs->stop)
+ {
+ if (bs->print)
+ bs_class = bp_noisy;
+ else
+ bs_class = bp_silent;
+ }
+ else
+ bs_class = bp_nostop;
+ break;
+ case bp_watchpoint:
+ if (bs->stop)
+ {
+ if (bs->print)
+ bs_class = wp_noisy;
+ else
+ bs_class = wp_silent;
+ }
+ else
+ /* There was a watchpoint, but we're not stopping. This requires
+ no further action. */
+ bs_class = no_effect;
+ break;
+ case bp_longjmp:
+ bs_class = long_jump;
+ break;
+ case bp_longjmp_resume:
+ bs_class = long_resume;
+ break;
+ case bp_step_resume:
+#if 0
+ /* Need to temporarily disable this until we can fix the bug
+ with nexting over a breakpoint with ->stop clear causing
+ an infinite loop. For now, treat the breakpoint as having
+ been hit even if the frame is wrong. */
+ if (bs->stop)
+ {
+#endif
+ retval.step_resume = 1;
+ /* We don't handle this via the main_action. */
+ bs_class = no_effect;
+#if 0
+ }
+ else
+ /* It is for the wrong frame. */
+ bs_class = bp_nostop;
+#endif
+ break;
+ case bp_call_dummy:
+ /* Make sure the action is stop (silent or noisy), so infrun.c
+ pops the dummy frame. */
+ bs_class = bp_silent;
+ retval.call_dummy = 1;
+ break;
+ }
+ current_action = table[(int)bs_class][(int)current_action];
+ }
+ retval.main_action = current_action;
+ return retval;
+}
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
+
+int
+bpstat_should_step ()
+{
+ struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->enable == enabled && b->type == bp_watchpoint)
+ return 1;
+ return 0;
+}
+
+/* Print information on breakpoint number BNUM, or -1 if all.
+ If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS
+ is nonzero, process only watchpoints. */
+
+static void
+breakpoint_1 (bnum, allflag)
+ int bnum;
+ int allflag;
+{
+ register struct breakpoint *b;
+ register struct command_line *l;
+ register struct symbol *sym;
+ CORE_ADDR last_addr = (CORE_ADDR)-1;
+ int found_a_breakpoint = 0;
+ static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint",
+ "longjmp", "longjmp resume", "step resume",
+ "call dummy" };
+ static char *bpdisps[] = {"del", "dis", "keep"};
+ static char bpenables[] = "ny";
+ char wrap_indent[80];
+
+ ALL_BREAKPOINTS (b)
+ if (bnum == -1
+ || bnum == b->number)
+ {
+/* We only print out user settable breakpoints unless the allflag is set. */
+ if (!allflag
+ && b->type != bp_breakpoint
+ && b->type != bp_watchpoint)
+ continue;
+
+ if (!found_a_breakpoint++)
+ printf_filtered ("Num Type Disp Enb %sWhat\n",
+ addressprint ? "Address " : "");
+
+ printf_filtered ("%-3d %-14s %-4s %-3c ",
+ b->number,
+ bptypes[(int)b->type],
+ bpdisps[(int)b->disposition],
+ bpenables[(int)b->enable]);
+ strcpy (wrap_indent, " ");
+ if (addressprint)
+ strcat (wrap_indent, " ");
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ print_expression (b->exp, stdout);
+ break;
+
+ case bp_breakpoint:
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ case bp_call_dummy:
+ if (addressprint)
+ printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l"));
+
+ last_addr = b->address;
+ if (b->source_file)
+ {
+ sym = find_pc_function (b->address);
+ if (sym)
+ {
+ fputs_filtered ("in ", stdout);
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout);
+ wrap_here (wrap_indent);
+ fputs_filtered (" at ", stdout);
+ }
+ fputs_filtered (b->source_file, stdout);
+ printf_filtered (":%d", b->line_number);
+ }
+ else
+ print_address_symbolic (b->address, stdout, demangle, " ");
+ break;
+ }
+
+ printf_filtered ("\n");
+
+ if (b->frame)
+ printf_filtered ("\tstop only in stack frame at %s\n",
+ local_hex_string((unsigned long) b->frame));
+ if (b->cond)
+ {
+ printf_filtered ("\tstop only if ");
+ print_expression (b->cond, stdout);
+ printf_filtered ("\n");
+ }
+ if (b->ignore_count)
+ printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+ if ((l = b->commands))
+ while (l)
+ {
+ fputs_filtered ("\t", stdout);
+ fputs_filtered (l->line, stdout);
+ fputs_filtered ("\n", stdout);
+ l = l->next;
+ }
+ }
+
+ if (!found_a_breakpoint)
+ {
+ if (bnum == -1)
+ printf_filtered ("No breakpoints or watchpoints.\n");
+ else
+ printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum);
+ }
+ else
+ /* Compare against (CORE_ADDR)-1 in case some compiler decides
+ that a comparison of an unsigned with -1 is always false. */
+ if (last_addr != (CORE_ADDR)-1)
+ set_next_address (last_addr);
+}
+
+/* ARGSUSED */
+static void
+breakpoints_info (bnum_exp, from_tty)
+ char *bnum_exp;
+ int from_tty;
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_address (bnum_exp);
+
+ breakpoint_1 (bnum, 0);
+}
+
+#if MAINTENANCE_CMDS
+
+/* ARGSUSED */
+static void
+maintenance_info_breakpoints (bnum_exp, from_tty)
+ char *bnum_exp;
+ int from_tty;
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_address (bnum_exp);
+
+ breakpoint_1 (bnum, 1);
+}
+
+#endif
+
+/* Print a message describing any breakpoints set at PC. */
+
+static void
+describe_other_breakpoints (pc)
+ register CORE_ADDR pc;
+{
+ register int others = 0;
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ others++;
+ if (others > 0)
+ {
+ printf ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ {
+ others--;
+ printf ("%d%s%s ",
+ b->number,
+ (b->enable == disabled) ? " (disabled)" : "",
+ (others > 1) ? "," : ((others == 1) ? " and" : ""));
+ }
+ printf ("also set at pc %s.\n", local_hex_string((unsigned long) pc));
+ }
+}
+
+/* Set the default place to put a breakpoint
+ for the `break' command with no arguments. */
+
+void
+set_default_breakpoint (valid, addr, symtab, line)
+ int valid;
+ CORE_ADDR addr;
+ struct symtab *symtab;
+ int line;
+{
+ default_breakpoint_valid = valid;
+ default_breakpoint_address = addr;
+ default_breakpoint_symtab = symtab;
+ default_breakpoint_line = line;
+}
+
+/* Rescan breakpoints at address ADDRESS,
+ marking the first one as "first" and any others as "duplicates".
+ This is so that the bpt instruction is only inserted once. */
+
+static void
+check_duplicates (address)
+ CORE_ADDR address;
+{
+ register struct breakpoint *b;
+ register int count = 0;
+
+ if (address == 0) /* Watchpoints are uninteresting */
+ return;
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && b->address == address)
+ {
+ count++;
+ b->duplicate = count > 1;
+ }
+}
+
+/* Low level routine to set a breakpoint.
+ Takes as args the three things that every breakpoint must have.
+ Returns the breakpoint object so caller can set other things.
+ Does not set the breakpoint number!
+ Does not print anything.
+
+ ==> This routine should not be called if there is a chance of later
+ error(); otherwise it leaves a bogus breakpoint on the chain. Validate
+ your arguments BEFORE calling this routine! */
+
+static struct breakpoint *
+set_raw_breakpoint (sal)
+ struct symtab_and_line sal;
+{
+ register struct breakpoint *b, *b1;
+
+ b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+ memset (b, 0, sizeof (*b));
+ b->address = sal.pc;
+ if (sal.symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file = savestring (sal.symtab->filename,
+ strlen (sal.symtab->filename));
+ b->thread = -1;
+ b->line_number = sal.line;
+ b->enable = enabled;
+ b->next = 0;
+ b->silent = 0;
+ b->ignore_count = 0;
+ b->commands = NULL;
+ b->frame = 0;
+
+ /* Add this breakpoint to the end of the chain
+ so that a list of breakpoints will come out in order
+ of increasing numbers. */
+
+ b1 = breakpoint_chain;
+ if (b1 == 0)
+ breakpoint_chain = b;
+ else
+ {
+ while (b1->next)
+ b1 = b1->next;
+ b1->next = b;
+ }
+
+ check_duplicates (sal.pc);
+
+ return b;
+}
+
+static void
+create_longjmp_breakpoint(func_name)
+ char *func_name;
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ static int internal_breakpoint_number = -1;
+
+ if (func_name != NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol(func_name, (struct objfile *)NULL);
+ if (m)
+ sal.pc = SYMBOL_VALUE_ADDRESS (m);
+ else
+ return;
+ }
+ else
+ sal.pc = 0;
+
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ b = set_raw_breakpoint(sal);
+ if (!b) return;
+
+ b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume;
+ b->disposition = donttouch;
+ b->enable = disabled;
+ b->silent = 1;
+ if (func_name)
+ b->addr_string = strsave(func_name);
+ b->number = internal_breakpoint_number--;
+}
+
+/* Call this routine when stepping and nexting to enable a breakpoint if we do
+ a longjmp(). When we hit that breakpoint, call
+ set_longjmp_resume_breakpoint() to figure out where we are going. */
+
+void
+enable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp)
+ {
+ b->enable = enabled;
+ check_duplicates (b->address);
+ }
+}
+
+void
+disable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if ( b->type == bp_longjmp
+ || b->type == bp_longjmp_resume)
+ {
+ b->enable = disabled;
+ check_duplicates (b->address);
+ }
+}
+
+/* Call this after hitting the longjmp() breakpoint. Use this to set a new
+ breakpoint at the target of the jmp_buf.
+
+ FIXME - This ought to be done by setting a temporary breakpoint that gets
+ deleted automatically...
+*/
+
+void
+set_longjmp_resume_breakpoint(pc, frame)
+ CORE_ADDR pc;
+ FRAME frame;
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp_resume)
+ {
+ b->address = pc;
+ b->enable = enabled;
+ if (frame != NULL)
+ b->frame = FRAME_FP(frame);
+ else
+ b->frame = 0;
+ check_duplicates (b->address);
+ return;
+ }
+}
+
+/* Set a breakpoint that will evaporate an end of command
+ at address specified by SAL.
+ Restrict it to frame FRAME if FRAME is nonzero. */
+
+struct breakpoint *
+set_momentary_breakpoint (sal, frame, type)
+ struct symtab_and_line sal;
+ FRAME frame;
+ enum bptype type;
+{
+ register struct breakpoint *b;
+ b = set_raw_breakpoint (sal);
+ b->type = type;
+ b->enable = enabled;
+ b->disposition = donttouch;
+ b->frame = (frame ? FRAME_FP (frame) : 0);
+ return b;
+}
+
+#if 0
+void
+clear_momentary_breakpoints ()
+{
+ register struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->disposition == delete)
+ {
+ delete_breakpoint (b);
+ break;
+ }
+}
+#endif
+
+/* Tell the user we have just set a breakpoint B. */
+static void
+mention (b)
+ struct breakpoint *b;
+{
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ printf_filtered ("Watchpoint %d: ", b->number);
+ print_expression (b->exp, stdout);
+ break;
+ case bp_breakpoint:
+ printf_filtered ("Breakpoint %d at %s", b->number,
+ local_hex_string((unsigned long) b->address));
+ if (b->source_file)
+ printf_filtered (": file %s, line %d.",
+ b->source_file, b->line_number);
+ break;
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ break;
+ }
+ printf_filtered ("\n");
+}
+
+#if 0
+/* Nobody calls this currently. */
+/* Set a breakpoint from a symtab and line.
+ If TEMPFLAG is nonzero, it is a temporary breakpoint.
+ ADDR_STRING is a malloc'd string holding the name of where we are
+ setting the breakpoint. This is used later to re-set it after the
+ program is relinked and symbols are reloaded.
+ Print the same confirmation messages that the breakpoint command prints. */
+
+void
+set_breakpoint (s, line, tempflag, addr_string)
+ struct symtab *s;
+ int line;
+ int tempflag;
+ char *addr_string;
+{
+ register struct breakpoint *b;
+ struct symtab_and_line sal;
+
+ sal.symtab = s;
+ sal.line = line;
+ sal.pc = 0;
+ resolve_sal_pc (&sal); /* Might error out */
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = 0;
+ b->addr_string = addr_string;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+}
+#endif /* 0 */
+
+/* Set a breakpoint according to ARG (function, linenum or *address)
+ and make it temporary if TEMPFLAG is nonzero. */
+
+static void
+break_command_1 (arg, tempflag, from_tty)
+ char *arg;
+ int tempflag, from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct expression *cond = 0;
+ register struct breakpoint *b;
+
+ /* Pointers in arg to the start, and one past the end, of the condition. */
+ char *cond_start = NULL;
+ char *cond_end = NULL;
+ /* Pointers in arg to the start, and one past the end,
+ of the address part. */
+ char *addr_start = NULL;
+ char *addr_end = NULL;
+ struct cleanup *old_chain;
+ struct cleanup *canonical_strings_chain = NULL;
+ char **canonical = (char **)NULL;
+ int i;
+ int thread;
+
+ sals.sals = NULL;
+ sals.nelts = 0;
+
+ sal.line = sal.pc = sal.end = 0;
+ sal.symtab = 0;
+
+ /* If no arg given, or if first arg is 'if ', use the default breakpoint. */
+
+ if (!arg || (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+ if (default_breakpoint_valid)
+ {
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sal.pc = default_breakpoint_address;
+ sal.line = default_breakpoint_line;
+ sal.symtab = default_breakpoint_symtab;
+ sals.sals[0] = sal;
+ sals.nelts = 1;
+ }
+ else
+ error ("No default breakpoint address now.");
+ }
+ else
+ {
+ addr_start = arg;
+
+ /* Force almost all breakpoints to be in terms of the
+ current_source_symtab (which is decode_line_1's default). This
+ should produce the results we want almost all of the time while
+ leaving default_breakpoint_* alone. */
+ if (default_breakpoint_valid
+ && (!current_source_symtab
+ || (arg && (*arg == '+' || *arg == '-'))))
+ sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+ default_breakpoint_line, &canonical);
+ else
+ sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical);
+
+ addr_end = arg;
+ }
+
+ if (! sals.nelts)
+ return;
+
+ /* Make sure that all storage allocated in decode_line_1 gets freed in case
+ the following `for' loop errors out. */
+ old_chain = make_cleanup (free, sals.sals);
+ if (canonical != (char **)NULL)
+ {
+ make_cleanup (free, canonical);
+ canonical_strings_chain = make_cleanup (null_cleanup, 0);
+ for (i = 0; i < sals.nelts; i++)
+ {
+ if (canonical[i] != NULL)
+ make_cleanup (free, canonical[i]);
+ }
+ }
+
+ thread = -1; /* No specific thread yet */
+
+ /* Resolve all line numbers to PC's, and verify that conditions
+ can be parsed, before setting any breakpoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ char *tok, *end_tok;
+ int toklen;
+
+ resolve_sal_pc (&sals.sals[i]);
+
+ tok = arg;
+
+ while (tok && *tok)
+ {
+ while (*tok == ' ' || *tok == '\t')
+ tok++;
+
+ end_tok = tok;
+
+ while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+ end_tok++;
+
+ toklen = end_tok - tok;
+
+ if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+ {
+ tok = cond_start = end_tok + 1;
+ cond = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
+ cond_end = tok;
+ }
+ else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ char *tmptok;
+
+ tok = end_tok + 1;
+ tmptok = tok;
+ thread = strtol (tok, &tok, 0);
+ if (tok == tmptok)
+ error ("Junk after thread keyword.");
+ if (!valid_thread_id (thread))
+ error ("Unknown thread %d\n", thread);
+ }
+ else
+ error ("Junk at end of arguments.");
+ }
+ }
+
+ /* Remove the canonical strings from the cleanup, they are needed below. */
+ if (canonical != (char **)NULL)
+ discard_cleanups (canonical_strings_chain);
+
+ /* Now set all the breakpoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = cond;
+ b->thread = thread;
+
+ /* If a canonical line spec is needed use that instead of the
+ command string. */
+ if (canonical != (char **)NULL && canonical[i] != NULL)
+ b->addr_string = canonical[i];
+ else if (addr_start)
+ b->addr_string = savestring (addr_start, addr_end - addr_start);
+ if (cond_start)
+ b->cond_string = savestring (cond_start, cond_end - cond_start);
+
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf ("Multiple breakpoints were set.\n");
+ printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+ }
+ do_cleanups (old_chain);
+}
+
+/* Helper function for break_command_1 and disassemble_command. */
+
+void
+resolve_sal_pc (sal)
+ struct symtab_and_line *sal;
+{
+ CORE_ADDR pc;
+
+ if (sal->pc == 0 && sal->symtab != 0)
+ {
+ pc = find_line_pc (sal->symtab, sal->line);
+ if (pc == 0)
+ error ("No line %d in file \"%s\".",
+ sal->line, sal->symtab->filename);
+ sal->pc = pc;
+ }
+}
+
+void
+break_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, 0, from_tty);
+}
+
+static void
+tbreak_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, 1, from_tty);
+}
+
+/* ARGSUSED */
+static void
+watch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct breakpoint *b;
+ struct symtab_and_line sal;
+ struct expression *exp;
+ struct block *exp_valid_block;
+ struct value *val;
+
+ sal.pc = 0;
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ /* Parse arguments. */
+ innermost_block = NULL;
+ exp = parse_expression (arg);
+ exp_valid_block = innermost_block;
+ val = evaluate_expression (exp);
+ release_value (val);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_watchpoint;
+ b->disposition = donttouch;
+ b->exp = exp;
+ b->exp_valid_block = exp_valid_block;
+ b->val = val;
+ b->cond = 0;
+ b->cond_string = NULL;
+ b->exp_string = savestring (arg, strlen (arg));
+ mention (b);
+}
+
+/*
+ * Helper routine for the until_command routine in infcmd.c. Here
+ * because it uses the mechanisms of breakpoints.
+ */
+/* ARGSUSED */
+void
+until_break_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ FRAME prev_frame = get_prev_frame (selected_frame);
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+
+ clear_proceed_status ();
+
+ /* Set a breakpoint where the user wants it and at return from
+ this function */
+
+ if (default_breakpoint_valid)
+ sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+ default_breakpoint_line, (char ***)NULL);
+ else
+ sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, (char ***)NULL);
+
+ if (sals.nelts != 1)
+ error ("Couldn't get information on specified line.");
+
+ sal = sals.sals[0];
+ free ((PTR)sals.sals); /* malloc'd, so freed */
+
+ if (*arg)
+ error ("Junk at end of arguments.");
+
+ resolve_sal_pc (&sal);
+
+ breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
+
+ old_chain = make_cleanup(delete_breakpoint, breakpoint);
+
+ /* Keep within the current frame */
+
+ if (prev_frame)
+ {
+ struct frame_info *fi;
+
+ fi = get_frame_info (prev_frame);
+ sal = find_pc_line (fi->pc, 0);
+ sal.pc = fi->pc;
+ breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
+ make_cleanup(delete_breakpoint, breakpoint);
+ }
+
+ proceed (-1, -1, 0);
+ do_cleanups(old_chain);
+}
+
+#if 0
+/* These aren't used; I don't konw what they were for. */
+/* Set a breakpoint at the catch clause for NAME. */
+static int
+catch_breakpoint (name)
+ char *name;
+{
+}
+
+static int
+disable_catch_breakpoint ()
+{
+}
+
+static int
+delete_catch_breakpoint ()
+{
+}
+
+static int
+enable_catch_breakpoint ()
+{
+}
+#endif /* 0 */
+
+struct sal_chain
+{
+ struct sal_chain *next;
+ struct symtab_and_line sal;
+};
+
+#if 0
+/* This isn't used; I don't know what it was for. */
+/* For each catch clause identified in ARGS, run FUNCTION
+ with that clause as an argument. */
+static struct symtabs_and_lines
+map_catch_names (args, function)
+ char *args;
+ int (*function)();
+{
+ register char *p = args;
+ register char *p1;
+ struct symtabs_and_lines sals;
+#if 0
+ struct sal_chain *sal_chain = 0;
+#endif
+
+ if (p == 0)
+ error_no_arg ("one or more catch names");
+
+ sals.nelts = 0;
+ sals.sals = NULL;
+
+ while (*p)
+ {
+ p1 = p;
+ /* Don't swallow conditional part. */
+ if (p1[0] == 'i' && p1[1] == 'f'
+ && (p1[2] == ' ' || p1[2] == '\t'))
+ break;
+
+ if (isalpha (*p1))
+ {
+ p1++;
+ while (isalnum (*p1) || *p1 == '_' || *p1 == '$')
+ p1++;
+ }
+
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be catch names.");
+
+ *p1 = 0;
+#if 0
+ if (function (p))
+ {
+ struct sal_chain *next
+ = (struct sal_chain *)alloca (sizeof (struct sal_chain));
+ next->next = sal_chain;
+ next->sal = get_catch_sal (p);
+ sal_chain = next;
+ goto win;
+ }
+#endif
+ printf ("No catch clause for exception %s.\n", p);
+#if 0
+ win:
+#endif
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+}
+#endif /* 0 */
+
+/* This shares a lot of code with `print_frame_label_vars' from stack.c. */
+
+static struct symtabs_and_lines
+get_catch_sals (this_level_only)
+ int this_level_only;
+{
+ register struct blockvector *bl;
+ register struct block *block;
+ int index, have_default = 0;
+ struct frame_info *fi;
+ CORE_ADDR pc;
+ struct symtabs_and_lines sals;
+ struct sal_chain *sal_chain = 0;
+ char *blocks_searched;
+
+ /* Not sure whether an error message is always the correct response,
+ but it's better than a core dump. */
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ block = get_frame_block (selected_frame);
+ fi = get_frame_info (selected_frame);
+ pc = fi->pc;
+
+ sals.nelts = 0;
+ sals.sals = NULL;
+
+ if (block == 0)
+ error ("No symbol table info available.\n");
+
+ bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+ blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+ memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+ while (block != 0)
+ {
+ CORE_ADDR end = BLOCK_END (block) - 4;
+ int last_index;
+
+ if (bl != blockvector_for_pc (end, &index))
+ error ("blockvector blotch");
+ if (BLOCKVECTOR_BLOCK (bl, index) != block)
+ error ("blockvector botch");
+ last_index = BLOCKVECTOR_NBLOCKS (bl);
+ index += 1;
+
+ /* Don't print out blocks that have gone by. */
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+ index++;
+
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+ {
+ if (blocks_searched[index] == 0)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (bl, index);
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (STREQ (SYMBOL_NAME (sym), "default"))
+ {
+ if (have_default)
+ continue;
+ have_default = 1;
+ }
+ if (SYMBOL_CLASS (sym) == LOC_LABEL)
+ {
+ struct sal_chain *next = (struct sal_chain *)
+ alloca (sizeof (struct sal_chain));
+ next->next = sal_chain;
+ next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+ sal_chain = next;
+ }
+ }
+ blocks_searched[index] = 1;
+ }
+ index++;
+ }
+ if (have_default)
+ break;
+ if (sal_chain && this_level_only)
+ break;
+
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (sal_chain)
+ {
+ struct sal_chain *tmp_chain;
+
+ /* Count the number of entries. */
+ for (index = 0, tmp_chain = sal_chain; tmp_chain;
+ tmp_chain = tmp_chain->next)
+ index++;
+
+ sals.nelts = index;
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (index * sizeof (struct symtab_and_line));
+ for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
+ sals.sals[index] = sal_chain->sal;
+ }
+
+ return sals;
+}
+
+/* Commands to deal with catching exceptions. */
+
+static void
+catch_command_1 (arg, tempflag, from_tty)
+ char *arg;
+ int tempflag;
+ int from_tty;
+{
+ /* First, translate ARG into something we can deal with in terms
+ of breakpoints. */
+
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct expression *cond = 0;
+ register struct breakpoint *b;
+ char *save_arg;
+ int i;
+
+ sal.line = sal.pc = sal.end = 0;
+ sal.symtab = 0;
+
+ /* If no arg given, or if first arg is 'if ', all active catch clauses
+ are breakpointed. */
+
+ if (!arg || (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+ /* Grab all active catch clauses. */
+ sals = get_catch_sals (0);
+ }
+ else
+ {
+ /* Grab selected catch clauses. */
+ error ("catch NAME not implemented");
+#if 0
+ /* This isn't used; I don't know what it was for. */
+ sals = map_catch_names (arg, catch_breakpoint);
+#endif
+ }
+
+ if (! sals.nelts)
+ return;
+
+ save_arg = arg;
+ for (i = 0; i < sals.nelts; i++)
+ {
+ resolve_sal_pc (&sals.sals[i]);
+
+ while (arg && *arg)
+ {
+ if (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t'))
+ cond = parse_exp_1 ((arg += 2, &arg),
+ block_for_pc (sals.sals[i].pc), 0);
+ else
+ error ("Junk at end of arguments.");
+ }
+ arg = save_arg;
+ }
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = cond;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf ("Multiple breakpoints were set.\n");
+ printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+ }
+ free ((PTR)sals.sals);
+}
+
+#if 0
+/* These aren't used; I don't know what they were for. */
+/* Disable breakpoints on all catch clauses described in ARGS. */
+static void
+disable_catch (args)
+ char *args;
+{
+ /* Map the disable command to catch clauses described in ARGS. */
+}
+
+/* Enable breakpoints on all catch clauses described in ARGS. */
+static void
+enable_catch (args)
+ char *args;
+{
+ /* Map the disable command to catch clauses described in ARGS. */
+}
+
+/* Delete breakpoints on all catch clauses in the active scope. */
+static void
+delete_catch (args)
+ char *args;
+{
+ /* Map the delete command to catch clauses described in ARGS. */
+}
+#endif /* 0 */
+
+static void
+catch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ catch_command_1 (arg, 0, from_tty);
+}
+
+static void
+clear_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b, *b1;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct breakpoint *found;
+ int i;
+
+ if (arg)
+ {
+ sals = decode_line_spec (arg, 1);
+ }
+ else
+ {
+ sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
+ sal.line = default_breakpoint_line;
+ sal.symtab = default_breakpoint_symtab;
+ sal.pc = 0;
+ if (sal.symtab == 0)
+ error ("No source file specified.");
+
+ sals.sals[0] = sal;
+ sals.nelts = 1;
+ }
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ /* If exact pc given, clear bpts at that pc.
+ But if sal.pc is zero, clear all bpts on specified line. */
+ sal = sals.sals[i];
+ found = (struct breakpoint *) 0;
+ while (breakpoint_chain
+ && (sal.pc
+ ? breakpoint_chain->address == sal.pc
+ : (breakpoint_chain->source_file != NULL
+ && sal.symtab != NULL
+ && STREQ (breakpoint_chain->source_file,
+ sal.symtab->filename)
+ && breakpoint_chain->line_number == sal.line)))
+ {
+ b1 = breakpoint_chain;
+ breakpoint_chain = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ ALL_BREAKPOINTS (b)
+ while (b->next
+ && b->next->type != bp_watchpoint
+ && (sal.pc
+ ? b->next->address == sal.pc
+ : (b->next->source_file != NULL
+ && sal.symtab != NULL
+ && STREQ (b->next->source_file, sal.symtab->filename)
+ && b->next->line_number == sal.line)))
+ {
+ b1 = b->next;
+ b->next = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ if (found == 0)
+ {
+ if (arg)
+ error ("No breakpoint at %s.", arg);
+ else
+ error ("No breakpoint at this line.");
+ }
+
+ if (found->next) from_tty = 1; /* Always report if deleted more than one */
+ if (from_tty) printf ("Deleted breakpoint%s ", found->next ? "s" : "");
+ while (found)
+ {
+ if (from_tty) printf ("%d ", found->number);
+ b1 = found->next;
+ delete_breakpoint (found);
+ found = b1;
+ }
+ if (from_tty) putchar ('\n');
+ }
+ free ((PTR)sals.sals);
+}
+
+/* Delete breakpoint in BS if they are `delete' breakpoints.
+ This is called after any breakpoint is hit, or after errors. */
+
+void
+breakpoint_auto_delete (bs)
+ bpstat bs;
+{
+ for (; bs; bs = bs->next)
+ if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete
+ && bs->stop)
+ delete_breakpoint (bs->breakpoint_at);
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data structures. */
+
+void
+delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ register struct breakpoint *b;
+ register bpstat bs;
+
+ if (bpt->inserted)
+ target_remove_breakpoint(bpt->address, bpt->shadow_contents);
+
+ if (breakpoint_chain == bpt)
+ breakpoint_chain = bpt->next;
+
+ ALL_BREAKPOINTS (b)
+ if (b->next == bpt)
+ {
+ b->next = bpt->next;
+ break;
+ }
+
+ check_duplicates (bpt->address);
+ /* If this breakpoint was inserted, and there is another breakpoint
+ at the same address, we need to insert the other breakpoint. */
+ if (bpt->inserted)
+ {
+ ALL_BREAKPOINTS (b)
+ if (b->address == bpt->address
+ && !b->duplicate
+ && b->enable != disabled)
+ {
+ int val;
+ val = target_insert_breakpoint (b->address, b->shadow_contents);
+ if (val != 0)
+ {
+ fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
+ memory_error (val, b->address); /* which bombs us out */
+ }
+ else
+ b->inserted = 1;
+ }
+ }
+
+ free_command_lines (&bpt->commands);
+ if (bpt->cond)
+ free (bpt->cond);
+ if (bpt->cond_string != NULL)
+ free (bpt->cond_string);
+ if (bpt->addr_string != NULL)
+ free (bpt->addr_string);
+ if (bpt->exp_string != NULL)
+ free (bpt->exp_string);
+ if (bpt->source_file != NULL)
+ free (bpt->source_file);
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf ("breakpoint #%d deleted\n", bpt->number);
+
+ /* Be sure no bpstat's are pointing at it after it's been freed. */
+ /* FIXME, how can we find all bpstat's? We just check stop_bpstat for now. */
+ for (bs = stop_bpstat; bs; bs = bs->next)
+ if (bs->breakpoint_at == bpt)
+ bs->breakpoint_at = NULL;
+ free ((PTR)bpt);
+}
+
+static void
+delete_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+
+ if (arg == 0)
+ {
+ /* Ask user only if there are some breakpoints to delete. */
+ if (!from_tty
+ || (breakpoint_chain && query ("Delete all breakpoints? ", 0, 0)))
+ {
+ /* No arg; clear all breakpoints. */
+ while (breakpoint_chain)
+ delete_breakpoint (breakpoint_chain);
+ }
+ }
+ else
+ map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Reset a breakpoint given it's struct breakpoint * BINT.
+ The value we return ends up being the return value from catch_errors.
+ Unused in this case. */
+
+static int
+breakpoint_re_set_one (bint)
+ char *bint;
+{
+ struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */
+ int i;
+ struct symtabs_and_lines sals;
+ char *s;
+ enum enable save_enable;
+
+ switch (b->type)
+ {
+ case bp_breakpoint:
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return 0;
+ }
+ /* In case we have a problem, disable this breakpoint. We'll restore
+ its status if we succeed. */
+ save_enable = b->enable;
+ b->enable = disabled;
+
+ s = b->addr_string;
+ sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0, (char ***)NULL);
+ for (i = 0; i < sals.nelts; i++)
+ {
+ resolve_sal_pc (&sals.sals[i]);
+
+ /* Reparse conditions, they might contain references to the
+ old symtab. */
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ if (b->cond)
+ free ((PTR)b->cond);
+ b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
+ }
+
+ /* We need to re-set the breakpoint if the address changes...*/
+ if (b->address != sals.sals[i].pc
+ /* ...or new and old breakpoints both have source files, and
+ the source file name or the line number changes... */
+ || (b->source_file != NULL
+ && sals.sals[i].symtab != NULL
+ && (!STREQ (b->source_file, sals.sals[i].symtab->filename)
+ || b->line_number != sals.sals[i].line)
+ )
+ /* ...or we switch between having a source file and not having
+ one. */
+ || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
+ )
+ {
+ if (b->source_file != NULL)
+ free (b->source_file);
+ if (sals.sals[i].symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file =
+ savestring (sals.sals[i].symtab->filename,
+ strlen (sals.sals[i].symtab->filename));
+ b->line_number = sals.sals[i].line;
+ b->address = sals.sals[i].pc;
+
+ check_duplicates (b->address);
+
+ mention (b);
+ }
+ b->enable = save_enable; /* Restore it, this worked. */
+ }
+ free ((PTR)sals.sals);
+ break;
+
+ case bp_watchpoint:
+ innermost_block = NULL;
+ /* The issue arises of what context to evaluate this in. The same
+ one as when it was set, but what does that mean when symbols have
+ been re-read? We could save the filename and functionname, but
+ if the context is more local than that, the best we could do would
+ be something like how many levels deep and which index at that
+ particular level, but that's going to be less stable than filenames
+ or functionnames. */
+ /* So for now, just use a global context. */
+ b->exp = parse_expression (b->exp_string);
+ b->exp_valid_block = innermost_block;
+ b->val = evaluate_expression (b->exp);
+ release_value (b->val);
+ if (VALUE_LAZY (b->val))
+ value_fetch_lazy (b->val);
+
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ b->cond = parse_exp_1 (&s, (struct block *)0, 0);
+ }
+ if (b->enable == enabled)
+ mention (b);
+ break;
+
+ default:
+ printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+ /* fall through */
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_call_dummy:
+ delete_breakpoint (b);
+ break;
+ }
+
+ return 0;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded. */
+void
+breakpoint_re_set ()
+{
+ struct breakpoint *b, *temp;
+ static char message1[] = "Error in re-setting breakpoint %d:\n";
+ char message[sizeof (message1) + 30 /* slop */];
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ sprintf (message, message1, b->number); /* Format possible error msg */
+ catch_errors (breakpoint_re_set_one, (char *) b, message,
+ RETURN_MASK_ALL);
+ }
+
+ create_longjmp_breakpoint("longjmp");
+ create_longjmp_breakpoint("_longjmp");
+ create_longjmp_breakpoint("siglongjmp");
+ create_longjmp_breakpoint(NULL);
+
+#if 0
+ /* Took this out (temporaliy at least), since it produces an extra
+ blank line at startup. This messes up the gdbtests. -PB */
+ /* Blank line to finish off all those mention() messages we just printed. */
+ printf_filtered ("\n");
+#endif
+}
+
+/* Set ignore-count of breakpoint number BPTNUM to COUNT.
+ If from_tty is nonzero, it prints a message to that effect,
+ which ends with a period (no newline). */
+
+void
+set_ignore_count (bptnum, count, from_tty)
+ int bptnum, count, from_tty;
+{
+ register struct breakpoint *b;
+
+ if (count < 0)
+ count = 0;
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bptnum)
+ {
+ b->ignore_count = count;
+ if (!from_tty)
+ return;
+ else if (count == 0)
+ printf_filtered ("Will stop next time breakpoint %d is reached.",
+ bptnum);
+ else if (count == 1)
+ printf_filtered ("Will ignore next crossing of breakpoint %d.",
+ bptnum);
+ else
+ printf_filtered ("Will ignore next %d crossings of breakpoint %d.",
+ count, bptnum);
+ return;
+ }
+
+ error ("No breakpoint number %d.", bptnum);
+}
+
+/* Clear the ignore counts of all breakpoints. */
+void
+breakpoint_clear_ignore_counts ()
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->ignore_count = 0;
+}
+
+/* Command to set ignore-count of breakpoint N to COUNT. */
+
+static void
+ignore_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *p = args;
+ register int num;
+
+ if (p == 0)
+ error_no_arg ("a breakpoint number");
+
+ num = get_number (&p);
+
+ if (*p == 0)
+ error ("Second argument (specified ignore-count) is missing.");
+
+ set_ignore_count (num,
+ longest_to_int (value_as_long (parse_and_eval (p))),
+ from_tty);
+ printf_filtered ("\n");
+}
+
+/* Call FUNCTION on each of the breakpoints
+ whose numbers are given in ARGS. */
+
+static void
+map_breakpoint_numbers (args, function)
+ char *args;
+ void (*function) PARAMS ((struct breakpoint *));
+{
+ register char *p = args;
+ char *p1;
+ register int num;
+ register struct breakpoint *b;
+
+ if (p == 0)
+ error_no_arg ("one or more breakpoint numbers");
+
+ while (*p)
+ {
+ p1 = p;
+
+ num = get_number (&p1);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == num)
+ {
+ function (b);
+ goto win;
+ }
+ printf ("No breakpoint number %d.\n", num);
+ win:
+ p = p1;
+ }
+}
+
+static void
+enable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ FRAME save_selected_frame = NULL;
+ int save_selected_frame_level = -1;
+
+ bpt->enable = enabled;
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf ("breakpoint #%d enabled\n", bpt->number);
+
+ check_duplicates (bpt->address);
+ if (bpt->type == bp_watchpoint)
+ {
+ if (bpt->exp_valid_block != NULL)
+ {
+ FRAME fr = within_scope (bpt->exp_valid_block);
+ if (fr == NULL)
+ {
+ printf_filtered ("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n", bpt->number);
+ bpt->enable = disabled;
+ return;
+ }
+ save_selected_frame = selected_frame;
+ save_selected_frame_level = selected_frame_level;
+ select_frame (fr, -1);
+ }
+
+ value_free (bpt->val);
+
+ bpt->val = evaluate_expression (bpt->exp);
+ release_value (bpt->val);
+ if (VALUE_LAZY (bpt->val))
+ value_fetch_lazy (bpt->val);
+
+ if (save_selected_frame_level >= 0)
+ select_frame (save_selected_frame, save_selected_frame_level);
+ }
+}
+
+/* ARGSUSED */
+static void
+enable_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_watchpoint:
+ enable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+disable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = disabled;
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf_filtered ("breakpoint #%d disabled\n", bpt->number);
+
+ check_duplicates (bpt->address);
+}
+
+/* ARGSUSED */
+static void
+disable_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_watchpoint:
+ disable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = enabled;
+ bpt->disposition = disable;
+
+ check_duplicates (bpt->address);
+}
+
+/* ARGSUSED */
+static void
+enable_once_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = enabled;
+ bpt->disposition = delete;
+
+ check_duplicates (bpt->address);
+}
+
+/* ARGSUSED */
+static void
+enable_delete_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ map_breakpoint_numbers (args, enable_delete_breakpoint);
+}
+
+/*
+ * Use default_breakpoint_'s, or nothing if they aren't valid.
+ */
+struct symtabs_and_lines
+decode_line_spec_1 (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtabs_and_lines sals;
+ if (string == 0)
+ error ("Empty line specification.");
+ if (default_breakpoint_valid)
+ sals = decode_line_1 (&string, funfirstline,
+ default_breakpoint_symtab, default_breakpoint_line,
+ (char ***)NULL);
+ else
+ sals = decode_line_1 (&string, funfirstline,
+ (struct symtab *)NULL, 0, (char ***)NULL);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+void
+_initialize_breakpoint ()
+{
+ breakpoint_chain = 0;
+ /* Don't bother to call set_breakpoint_count. $bpnum isn't useful
+ before a breakpoint is set. */
+ breakpoint_count = 0;
+
+ add_com ("ignore", class_breakpoint, ignore_command,
+ "Set ignore-count of breakpoint number N to COUNT.");
+
+ add_com ("commands", class_breakpoint, commands_command,
+ "Set commands to be executed when a breakpoint is hit.\n\
+Give breakpoint number as argument after \"commands\".\n\
+With no argument, the targeted breakpoint is the last one set.\n\
+The commands themselves follow starting on the next line.\n\
+Type a line containing \"end\" to indicate the end of them.\n\
+Give \"silent\" as the first line to make the breakpoint silent;\n\
+then no output is printed when it is hit, except what the commands print.");
+
+ add_com ("condition", class_breakpoint, condition_command,
+ "Specify breakpoint number N to break only if COND is true.\n\
+N is an integer; COND is an expression to be evaluated whenever\n\
+breakpoint N is reached. ");
+
+ add_com ("tbreak", class_breakpoint, tbreak_command,
+ "Set a temporary breakpoint. Args like \"break\" command.\n\
+Like \"break\" except the breakpoint is only enabled temporarily,\n\
+so it will be disabled when hit. Equivalent to \"break\" followed\n\
+by using \"enable once\" on the breakpoint number.");
+
+ add_prefix_cmd ("enable", class_breakpoint, enable_command,
+ "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+With no subcommand, breakpoints are enabled until you command otherwise.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+With a subcommand you can enable temporarily.",
+ &enablelist, "enable ", 1, &cmdlist);
+
+ add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
+ "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+May be abbreviated to simply \"enable\".\n",
+ &enablebreaklist, "enable breakpoints ", 1, &enablelist);
+
+ add_cmd ("once", no_class, enable_once_command,
+ "Enable breakpoints for one hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &enablebreaklist);
+
+ add_cmd ("delete", no_class, enable_delete_command,
+ "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+ &enablebreaklist);
+
+ add_cmd ("delete", no_class, enable_delete_command,
+ "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+ &enablelist);
+
+ add_cmd ("once", no_class, enable_once_command,
+ "Enable breakpoints for one hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &enablelist);
+
+ add_prefix_cmd ("disable", class_breakpoint, disable_command,
+ "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.",
+ &disablelist, "disable ", 1, &cmdlist);
+ add_com_alias ("dis", "disable", class_breakpoint, 1);
+ add_com_alias ("disa", "disable", class_breakpoint, 1);
+
+ add_cmd ("breakpoints", class_alias, disable_command,
+ "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
+This command may be abbreviated \"disable\".",
+ &disablelist);
+
+ add_prefix_cmd ("delete", class_breakpoint, delete_command,
+ "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+\n\
+Also a prefix command for deletion of other GDB objects.\n\
+The \"unset\" command is also an alias for \"delete\".",
+ &deletelist, "delete ", 1, &cmdlist);
+ add_com_alias ("d", "delete", class_breakpoint, 1);
+
+ add_cmd ("breakpoints", class_alias, delete_command,
+ "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+This command may be abbreviated \"delete\".",
+ &deletelist);
+
+ add_com ("clear", class_breakpoint, clear_command,
+ "Clear breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, all breakpoints in that line are cleared.\n\
+If function is specified, breakpoints at beginning of function are cleared.\n\
+If an address is specified, breakpoints at that address are cleared.\n\n\
+With no argument, clears all breakpoints in the line that the selected frame\n\
+is executing in.\n\
+\n\
+See also the \"delete\" command which clears breakpoints by number.");
+
+ add_com ("break", class_breakpoint, break_command,
+ "Set breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, break at start of code for that line.\n\
+If function is specified, break at start of code for that function.\n\
+If an address is specified, break at that exact address.\n\
+With no arg, uses current execution address of selected stack frame.\n\
+This is useful for breaking on return to a stack frame.\n\
+\n\
+Multiple breakpoints at one place are permitted, and useful if conditional.\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+ add_com_alias ("b", "break", class_run, 1);
+ add_com_alias ("br", "break", class_run, 1);
+ add_com_alias ("bre", "break", class_run, 1);
+ add_com_alias ("brea", "break", class_run, 1);
+
+ add_info ("breakpoints", breakpoints_info,
+ "Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint - normal breakpoint\n\
+\twatchpoint - watchpoint\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.");
+
+#if MAINTENANCE_CMDS
+
+ add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints,
+ "Status of all breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint - normal breakpoint\n\
+\twatchpoint - watchpoint\n\
+\tlongjmp - internal breakpoint used to step through longjmp()\n\
+\tlongjmp resume - internal breakpoint at the target of longjmp()\n\
+\tuntil - internal breakpoint used by the \"until\" command\n\
+\tfinish - internal breakpoint used by the \"finish\" command\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.",
+ &maintenanceinfolist);
+
+#endif /* MAINTENANCE_CMDS */
+
+ add_com ("catch", class_breakpoint, catch_command,
+ "Set breakpoints to catch exceptions that are raised.\n\
+Argument may be a single exception to catch, multiple exceptions\n\
+to catch, or the default exception \"default\". If no arguments\n\
+are given, breakpoints are set at all exception handlers catch clauses\n\
+within the current scope.\n\
+\n\
+A condition specified for the catch applies to all breakpoints set\n\
+with this command\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+
+ add_com ("watch", class_breakpoint, watch_command,
+ "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression changes.");
+
+ add_info ("watchpoints", breakpoints_info,
+ "Synonym for ``info breakpoints''.");
+}
+
+/* OK, when we call objfile_relocate, we need to relocate breakpoints
+ too. breakpoint_re_set is not a good choice--for example, if
+ addr_string contains just a line number without a file name the
+ breakpoint might get set in a different file. In general, there is
+ no need to go all the way back to the user's string (though this might
+ work if some effort were made to canonicalize it), since symtabs and
+ everything except addresses are still valid.
+
+ Probably the best way to solve this is to have each breakpoint save
+ the objfile and the section number that was used to set it (if set
+ by "*addr", probably it is best to use find_pc_line to get a symtab
+ and use the objfile and block_line_section for that symtab). Then
+ objfile_relocate can call fixup_breakpoints with the objfile and
+ the new_offsets, and it can relocate only the appropriate breakpoints. */
+
+#ifdef IBM6000_TARGET
+/* But for now, just kludge it based on the concept that before an
+ objfile is relocated the breakpoint is below 0x10000000, and afterwards
+ it is higher, so that way we only relocate each breakpoint once. */
+
+void
+fixup_breakpoints (low, high, delta)
+ CORE_ADDR low;
+ CORE_ADDR high;
+ CORE_ADDR delta;
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->address >= low && b->address <= high)
+ b->address += delta;
+ }
+}
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.h b/gnu/usr.bin/gdb/gdb/breakpoint.h
new file mode 100644
index 000000000000..5005450804dc
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.h
@@ -0,0 +1,372 @@
+/* Data structures associated with breakpoints in GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BREAKPOINT_H)
+#define BREAKPOINT_H 1
+
+#include "frame.h"
+#include "value.h"
+
+/* This is the maximum number of bytes a breakpoint instruction can take.
+ Feel free to increase it. It's just used in a few places to size
+ arrays that should be independent of the target architecture. */
+
+#define BREAKPOINT_MAX 16
+
+/* Type of breakpoint. */
+/* FIXME In the future, we should fold all other breakpoint-like things into
+ here. This includes:
+
+ * single-step (for machines where we have to simulate single stepping)
+ (probably, though perhaps it is better for it to look as much as
+ possible like a single-step to wait_for_inferior). */
+
+enum bptype {
+ bp_breakpoint, /* Normal breakpoint */
+ bp_until, /* used by until command */
+ bp_finish, /* used by finish command */
+ bp_watchpoint, /* Watchpoint */
+ bp_longjmp, /* secret breakpoint to find longjmp() */
+ bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
+
+ /* Used by wait_for_inferior for stepping over subroutine calls, for
+ stepping over signal handlers, and for skipping prologues. */
+ bp_step_resume,
+
+ /* The breakpoint at the end of a call dummy. */
+ /* FIXME: What if the function we are calling longjmp()s out of the
+ call, or the user gets out with the "return" command? We currently
+ have no way of cleaning up the breakpoint in these (obscure) situations.
+ (Probably can solve this by noticing longjmp, "return", etc., it's
+ similar to noticing when a watchpoint on a local variable goes out
+ of scope (with hardware support for watchpoints)). */
+ bp_call_dummy
+};
+
+/* States of enablement of breakpoint. */
+
+enum enable { disabled, enabled};
+
+/* Disposition of breakpoint. Ie: what to do after hitting it. */
+
+enum bpdisp {
+ delete, /* Delete it */
+ disable, /* Disable it */
+ donttouch /* Leave it alone */
+};
+
+/* Note that the ->silent field is not currently used by any commands
+ (though the code is in there if it was to be, and set_raw_breakpoint
+ does set it to 0). I implemented it because I thought it would be
+ useful for a hack I had to put in; I'm going to leave it in because
+ I can see how there might be times when it would indeed be useful */
+
+/* This is for a breakpoint or a watchpoint. */
+
+struct breakpoint
+{
+ struct breakpoint *next;
+ /* Type of breakpoint. */
+ enum bptype type;
+ /* Zero means disabled; remember the info but don't break here. */
+ enum enable enable;
+ /* What to do with this breakpoint after we hit it. */
+ enum bpdisp disposition;
+ /* Number assigned to distinguish breakpoints. */
+ int number;
+
+ /* Address to break at, or NULL if not a breakpoint. */
+ CORE_ADDR address;
+
+ /* Line number of this address. Only matters if address is
+ non-NULL. */
+
+ int line_number;
+
+ /* Source file name of this address. Only matters if address is
+ non-NULL. */
+
+ char *source_file;
+
+ /* Non-zero means a silent breakpoint (don't print frame info
+ if we stop here). */
+ unsigned char silent;
+ /* Number of stops at this breakpoint that should
+ be continued automatically before really stopping. */
+ int ignore_count;
+ /* "Real" contents of byte where breakpoint has been inserted.
+ Valid only when breakpoints are in the program. Under the complete
+ control of the target insert_breakpoint and remove_breakpoint routines.
+ No other code should assume anything about the value(s) here. */
+ char shadow_contents[BREAKPOINT_MAX];
+ /* Nonzero if this breakpoint is now inserted. Only matters if address
+ is non-NULL. */
+ char inserted;
+ /* Nonzero if this is not the first breakpoint in the list
+ for the given address. Only matters if address is non-NULL. */
+ char duplicate;
+ /* Chain of command lines to execute when this breakpoint is hit. */
+ struct command_line *commands;
+ /* Stack depth (address of frame). If nonzero, break only if fp
+ equals this. */
+ FRAME_ADDR frame;
+ /* Conditional. Break only if this expression's value is nonzero. */
+ struct expression *cond;
+
+ /* String we used to set the breakpoint (malloc'd). Only matters if
+ address is non-NULL. */
+ char *addr_string;
+ /* String form of the breakpoint condition (malloc'd), or NULL if there
+ is no condition. */
+ char *cond_string;
+ /* String form of exp (malloc'd), or NULL if none. */
+ char *exp_string;
+
+ /* The expression we are watching, or NULL if not a watchpoint. */
+ struct expression *exp;
+ /* The largest block within which it is valid, or NULL if it is
+ valid anywhere (e.g. consists just of global symbols). */
+ struct block *exp_valid_block;
+ /* Value of the watchpoint the last time we checked it. */
+ value val;
+ /* Thread number for thread-specific breakpoint, or -1 if don't care */
+ int thread;
+};
+
+/* The following stuff is an abstract data type "bpstat" ("breakpoint status").
+ This provides the ability to determine whether we have stopped at a
+ breakpoint, and what we should do about it. */
+
+typedef struct bpstat *bpstat;
+
+/* Interface: */
+/* Clear a bpstat so that it says we are not at any breakpoint.
+ Also free any storage that is part of a bpstat. */
+extern void bpstat_clear PARAMS ((bpstat *));
+
+/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
+ is part of the bpstat is copied as well. */
+extern bpstat bpstat_copy PARAMS ((bpstat));
+
+/* FIXME: prototypes uses equivalence between FRAME_ADDR and CORE_ADDR */
+extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, CORE_ADDR, int));
+
+/* This bpstat_what stuff tells wait_for_inferior what to do with a
+ breakpoint (a challenging task). */
+
+enum bpstat_what_main_action {
+ /* Perform various other tests; that is, this bpstat does not
+ say to perform any action (e.g. failed watchpoint and nothing
+ else). */
+ BPSTAT_WHAT_KEEP_CHECKING,
+
+ /* Rather than distinguish between noisy and silent stops here, it
+ might be cleaner to have bpstat_print make that decision (also
+ taking into account stop_print_frame and source_only). But the
+ implications are a bit scary (interaction with auto-displays, etc.),
+ so I won't try it. */
+
+ /* Stop silently. */
+ BPSTAT_WHAT_STOP_SILENT,
+
+ /* Stop and print. */
+ BPSTAT_WHAT_STOP_NOISY,
+
+ /* Remove breakpoints, single step once, then put them back in and
+ go back to what we were doing. It's possible that this should be
+ removed from the main_action and put into a separate field, to more
+ cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */
+ BPSTAT_WHAT_SINGLE,
+
+ /* Set longjmp_resume breakpoint, remove all other breakpoints,
+ and continue. The "remove all other breakpoints" part is required
+ if we are also stepping over another breakpoint as well as doing
+ the longjmp handling. */
+ BPSTAT_WHAT_SET_LONGJMP_RESUME,
+
+ /* Clear longjmp_resume breakpoint, then handle as
+ BPSTAT_WHAT_KEEP_CHECKING. */
+ BPSTAT_WHAT_CLEAR_LONGJMP_RESUME,
+
+ /* Clear longjmp_resume breakpoint, then handle as BPSTAT_WHAT_SINGLE. */
+ BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE,
+
+ /* This is just used to keep track of how many enums there are. */
+ BPSTAT_WHAT_LAST
+};
+
+struct bpstat_what {
+ enum bpstat_what_main_action main_action;
+
+ /* Did we hit the step resume breakpoint? This is separate from the
+ main_action to allow for it to be combined with any of the main
+ actions. */
+ int step_resume;
+
+ /* Did we hit a call dummy breakpoint? This only goes with a main_action
+ of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of
+ continuing from a call dummy without popping the frame is not a
+ useful one). */
+ int call_dummy;
+};
+
+/* Tell what to do about this bpstat. */
+struct bpstat_what bpstat_what PARAMS ((bpstat));
+
+/* Find the bpstat associated with a breakpoint. NULL otherwise. */
+bpstat bpstat_find_breakpoint PARAMS ((bpstat, struct breakpoint *));
+
+/* Nonzero if a signal that we got in wait() was due to circumstances
+ explained by the BS. */
+/* Currently that is true if we have hit a breakpoint, or if there is
+ a watchpoint enabled. */
+#define bpstat_explains_signal(bs) ((bs) != NULL)
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
+extern int bpstat_should_step PARAMS ((void));
+
+/* Print a message indicating what happened. Returns nonzero to
+ say that only the source line should be printed after this (zero
+ return means print the frame as well as the source line). */
+extern int bpstat_print PARAMS ((bpstat));
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+ at. *BSP upon return is a bpstat which points to the remaining
+ breakpoints stopped at (but which is not guaranteed to be good for
+ anything but further calls to bpstat_num).
+ Return 0 if passed a bpstat which does not indicate any breakpoints. */
+extern int bpstat_num PARAMS ((bpstat *));
+
+/* Perform actions associated with having stopped at *BSP. Actually, we just
+ use this for breakpoint commands. Perhaps other actions will go here
+ later, but this is executed at a late time (from the command loop). */
+extern void bpstat_do_actions PARAMS ((bpstat *));
+
+/* Modify BS so that the actions will not be performed. */
+extern void bpstat_clear_actions PARAMS ((bpstat));
+
+/* Implementation: */
+struct bpstat
+{
+ /* Linked list because there can be two breakpoints at the
+ same place, and a bpstat reflects the fact that both have been hit. */
+ bpstat next;
+ /* Breakpoint that we are at. */
+ struct breakpoint *breakpoint_at;
+ /* Commands left to be done. */
+ struct command_line *commands;
+ /* Old value associated with a watchpoint. */
+ value old_val;
+
+ /* Nonzero if this breakpoint tells us to print the frame. */
+ char print;
+
+ /* Nonzero if this breakpoint tells us to stop. */
+ char stop;
+
+ /* Function called by bpstat_print to print stuff associated with
+ this element of the bpstat chain. Returns 0 or 1 just like
+ bpstat_print, or -1 if it can't deal with it. */
+ int (*print_it) PARAMS((bpstat bs));
+};
+
+/* Prototypes for breakpoint-related functions. */
+
+#ifdef __STDC__ /* Forward declarations for prototypes */
+struct frame_info;
+#endif
+
+extern int
+breakpoint_here_p PARAMS ((CORE_ADDR));
+
+extern int
+breakpoint_thread_match PARAMS ((CORE_ADDR, int));
+
+extern void
+until_break_command PARAMS ((char *, int));
+
+extern void
+breakpoint_re_set PARAMS ((void));
+
+extern void
+clear_momentary_breakpoints PARAMS ((void));
+
+/* FIXME: Prototype uses equivalence of "struct frame_info *" and FRAME */
+extern struct breakpoint *
+set_momentary_breakpoint PARAMS ((struct symtab_and_line,
+ struct frame_info *,
+ enum bptype));
+
+extern void
+set_ignore_count PARAMS ((int, int, int));
+
+extern void
+set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int));
+
+extern void
+mark_breakpoints_out PARAMS ((void));
+
+extern void
+breakpoint_init_inferior PARAMS ((void));
+
+extern void
+delete_breakpoint PARAMS ((struct breakpoint *));
+
+extern void
+breakpoint_auto_delete PARAMS ((bpstat));
+
+extern void
+breakpoint_clear_ignore_counts PARAMS ((void));
+
+extern void
+break_command PARAMS ((char *, int));
+
+extern int
+insert_breakpoints PARAMS ((void));
+
+extern int
+remove_breakpoints PARAMS ((void));
+
+extern void
+enable_longjmp_breakpoint PARAMS ((void));
+
+extern void
+disable_longjmp_breakpoint PARAMS ((void));
+
+extern void
+set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR, FRAME));
+
+/* The following are for displays, which aren't really breakpoints, but
+ here is as good a place as any for them. */
+
+extern void
+disable_current_display PARAMS ((void));
+
+extern void
+do_displays PARAMS ((void));
+
+extern void
+disable_display PARAMS ((int));
+
+extern void
+clear_displays PARAMS ((void));
+
+#endif /* !defined (BREAKPOINT_H) */
diff --git a/gnu/usr.bin/gdb/gdb/buildsym.c b/gnu/usr.bin/gdb/gdb/buildsym.c
new file mode 100644
index 000000000000..dfa9be131625
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/buildsym.c
@@ -0,0 +1,950 @@
+/* Support routines for building symbol tables in GDB's internal format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides subroutines used for creating and adding to
+ the symbol table. These routines are called from various symbol-
+ file-reading routines.
+
+ Routines to support specific debugging information formats (stabs,
+ DWARF, etc) belong somewhere else. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "symfile.h" /* Needed for "struct complaint" */
+#include "objfiles.h"
+#include "complaints.h"
+#include <string.h>
+
+/* Ask buildsym.h to define the vars it normally declares `extern'. */
+#define EXTERN /**/
+#include "buildsym.h" /* Our own declarations */
+#undef EXTERN
+
+static int
+compare_line_numbers PARAMS ((const void *, const void *));
+
+static struct blockvector *
+make_blockvector PARAMS ((struct objfile *));
+
+
+/* Initial sizes of data structures. These are realloc'd larger if needed,
+ and realloc'd down to the size actually used, when completed. */
+
+#define INITIAL_CONTEXT_STACK_SIZE 10
+#define INITIAL_LINE_VECTOR_LENGTH 1000
+
+
+/* Complaints about the symbols we have encountered. */
+
+struct complaint innerblock_complaint =
+ {"inner block not inside outer block in %s", 0, 0};
+
+struct complaint innerblock_anon_complaint =
+ {"inner block not inside outer block", 0, 0};
+
+struct complaint blockvector_complaint =
+ {"block at 0x%lx out of order", 0, 0};
+
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+
+void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ register struct pending *link;
+
+ /* We keep PENDINGSIZE symbols in each link of the list.
+ If we don't have a link with room in it, add a new link. */
+ if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE)
+ {
+ if (free_pendings)
+ {
+ link = free_pendings;
+ free_pendings = link->next;
+ }
+ else
+ {
+ link = (struct pending *) xmalloc (sizeof (struct pending));
+ }
+
+ link->next = *listhead;
+ *listhead = link;
+ link->nsyms = 0;
+ }
+
+ (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* Find a symbol named NAME on a LIST. NAME need not be '\0'-terminated;
+ LENGTH is the length of the name. */
+
+struct symbol *
+find_symbol_in_list (list, name, length)
+ struct pending *list;
+ char *name;
+ int length;
+{
+ int j;
+ char *pp;
+
+ while (list != NULL)
+ {
+ for (j = list->nsyms; --j >= 0; )
+ {
+ pp = SYMBOL_NAME (list->symbol[j]);
+ if (*pp == *name && strncmp (pp, name, length) == 0 &&
+ pp[length] == '\0')
+ {
+ return (list->symbol[j]);
+ }
+ }
+ list = list->next;
+ }
+ return (NULL);
+}
+
+/* At end of reading syms, or in case of quit,
+ really free as many `struct pending's as we can easily find. */
+
+/* ARGSUSED */
+void
+really_free_pendings (foo)
+ int foo;
+{
+ struct pending *next, *next1;
+#if 0
+ struct pending_block *bnext, *bnext1;
+#endif
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ free_pendings = NULL;
+
+#if 0 /* Now we make the links in the symbol_obstack, so don't free them. */
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ free ((PTR)bnext);
+ }
+#endif
+ pending_blocks = NULL;
+
+ for (next = file_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ file_symbols = NULL;
+
+ for (next = global_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ global_symbols = NULL;
+}
+
+/* Take one of the lists of symbols and make a block from it.
+ Keep the order the symbols have in the list (reversed from the input file).
+ Put the block on the list of pending blocks. */
+
+void
+finish_block (symbol, listhead, old_blocks, start, end, objfile)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+ struct objfile *objfile;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+ register int j;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0;
+ next;
+ i += next->nsyms, next = next->next)
+ {
+ /*EMPTY*/;
+ }
+
+ block = (struct block *) obstack_alloc (&objfile -> symbol_obstack,
+ (sizeof (struct block) + ((i - 1) * sizeof (struct symbol *))));
+
+ /* Copy the symbols into the block. */
+
+ BLOCK_NSYMS (block) = i;
+ for (next = *listhead; next; next = next->next)
+ {
+ for (j = next->nsyms - 1; j >= 0; j--)
+ {
+ BLOCK_SYM (block, --i) = next->symbol[j];
+ }
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ /* Superblock filled in when containing block is made */
+ BLOCK_SUPERBLOCK (block) = NULL;
+ BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+ /* Put the block in as the value of the symbol that names it. */
+
+ if (symbol)
+ {
+ SYMBOL_BLOCK_VALUE (symbol) = block;
+ BLOCK_FUNCTION (block) = symbol;
+ }
+ else
+ {
+ BLOCK_FUNCTION (block) = NULL;
+ }
+
+ /* Now "free" the links of the list, and empty the list. */
+
+ for (next = *listhead; next; next = next1)
+ {
+ next1 = next->next;
+ next->next = free_pendings;
+ free_pendings = next;
+ }
+ *listhead = NULL;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = NULL;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
+ {
+#if 1
+ /* Check to be sure the blocks are nested as we receive them.
+ If the compiler/assembler/linker work, this just burns a small
+ amount of time. */
+ if (BLOCK_START (pblock->block) < BLOCK_START (block) ||
+ BLOCK_END (pblock->block) > BLOCK_END (block))
+ {
+ if (symbol)
+ {
+ complain (&innerblock_complaint,
+ SYMBOL_SOURCE_NAME (symbol));
+ }
+ else
+ {
+ complain (&innerblock_anon_complaint);
+ }
+ BLOCK_START (pblock->block) = BLOCK_START (block);
+ BLOCK_END (pblock->block) = BLOCK_END (block);
+ }
+#endif
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ }
+ opblock = pblock;
+ }
+
+ /* Record this block on the list of all blocks in the file.
+ Put it after opblock, or at the beginning if opblock is 0.
+ This puts the block in the list after all its subblocks. */
+
+ /* Allocate in the symbol_obstack to save time.
+ It wastes a little space. */
+ pblock = (struct pending_block *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ sizeof (struct pending_block));
+ pblock->block = block;
+ if (opblock)
+ {
+ pblock->next = opblock->next;
+ opblock->next = pblock;
+ }
+ else
+ {
+ pblock->next = pending_blocks;
+ pending_blocks = pblock;
+ }
+}
+
+static struct blockvector *
+make_blockvector (objfile)
+ struct objfile *objfile;
+{
+ register struct pending_block *next;
+ register struct blockvector *blockvector;
+ register int i;
+
+ /* Count the length of the list of blocks. */
+
+ for (next = pending_blocks, i = 0; next; next = next->next, i++) {;}
+
+ blockvector = (struct blockvector *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ (sizeof (struct blockvector)
+ + (i - 1) * sizeof (struct block *)));
+
+ /* Copy the blocks into the blockvector.
+ This is done in reverse order, which happens to put
+ the blocks into the proper order (ascending starting address).
+ finish_block has hair to insert each block into the list
+ after its subblocks in order to make sure this is true. */
+
+ BLOCKVECTOR_NBLOCKS (blockvector) = i;
+ for (next = pending_blocks; next; next = next->next)
+ {
+ BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+ }
+
+#if 0 /* Now we make the links in the obstack, so don't free them. */
+ /* Now free the links of the list, and empty the list. */
+
+ for (next = pending_blocks; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+#endif
+ pending_blocks = NULL;
+
+#if 1 /* FIXME, shut this off after a while to speed up symbol reading. */
+ /* Some compilers output blocks in the wrong order, but we depend
+ on their being in the right order so we can binary search.
+ Check the order and moan about it. FIXME. */
+ if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
+ {
+ for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++)
+ {
+ if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1))
+ > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)))
+ {
+ complain (&blockvector_complaint,
+ (unsigned long) BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)));
+ }
+ }
+ }
+#endif
+
+ return (blockvector);
+}
+
+
+/* Start recording information about source code that came from an included
+ (or otherwise merged-in) source file with a different name. NAME is
+ the name of the file (cannot be NULL), DIRNAME is the directory in which
+ it resides (or NULL if not known). */
+
+void
+start_subfile (name, dirname)
+ char *name;
+ char *dirname;
+{
+ register struct subfile *subfile;
+
+ /* See if this subfile is already known as a subfile of the
+ current main source file. */
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (STREQ (subfile->name, name))
+ {
+ current_subfile = subfile;
+ return;
+ }
+ }
+
+ /* This subfile is not known. Add an entry for it.
+ Make an entry for this subfile in the list of all subfiles
+ of the current main source file. */
+
+ subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
+ subfile->next = subfiles;
+ subfiles = subfile;
+ current_subfile = subfile;
+
+ /* Save its name and compilation directory name */
+ subfile->name = (name == NULL)? NULL : strdup (name);
+ subfile->dirname = (dirname == NULL) ? NULL : strdup (dirname);
+
+ /* Initialize line-number recording for this subfile. */
+ subfile->line_vector = NULL;
+
+ /* Default the source language to whatever can be deduced from
+ the filename. If nothing can be deduced (such as for a C/C++
+ include file with a ".h" extension), then inherit whatever
+ language the previous subfile had. This kludgery is necessary
+ because there is no standard way in some object formats to
+ record the source language. Also, when symtabs are allocated
+ we try to deduce a language then as well, but it is too late
+ for us to use that information while reading symbols, since
+ symtabs aren't allocated until after all the symbols have
+ been processed for a given source file. */
+
+ subfile->language = deduce_language_from_filename (subfile->name);
+ if (subfile->language == language_unknown &&
+ subfile->next != NULL)
+ {
+ subfile->language = subfile->next->language;
+ }
+
+ /* cfront output is a C program, so in most ways it looks like a C
+ program. But to demangle we need to set the language to C++. We
+ can distinguish cfront code by the fact that it has #line
+ directives which specify a file name ending in .C.
+
+ So if the filename of this subfile ends in .C, then change the language
+ of any pending subfiles from C to C++. We also accept any other C++
+ suffixes accepted by deduce_language_from_filename (in particular,
+ some people use .cxx with cfront). */
+
+ if (subfile->name)
+ {
+ struct subfile *s;
+
+ if (deduce_language_from_filename (subfile->name) == language_cplus)
+ for (s = subfiles; s != NULL; s = s->next)
+ if (s->language == language_c)
+ s->language = language_cplus;
+ }
+
+ /* And patch up this file if necessary. */
+ if (subfile->language == language_c
+ && subfile->next != NULL
+ && subfile->next->language == language_cplus)
+ {
+ subfile->language = language_cplus;
+ }
+}
+
+/* For stabs readers, the first N_SO symbol is assumed to be the source
+ file name, and the subfile struct is initialized using that assumption.
+ If another N_SO symbol is later seen, immediately following the first
+ one, then the first one is assumed to be the directory name and the
+ second one is really the source file name.
+
+ So we have to patch up the subfile struct by moving the old name value to
+ dirname and remembering the new name. Some sanity checking is performed
+ to ensure that the state of the subfile struct is reasonable and that the
+ old name we are assuming to be a directory name actually is (by checking
+ for a trailing '/'). */
+
+void
+patch_subfile_names (subfile, name)
+ struct subfile *subfile;
+ char *name;
+{
+ if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL
+ && subfile->name[strlen(subfile->name)-1] == '/')
+ {
+ subfile->dirname = subfile->name;
+ subfile->name = strdup (name);
+
+ /* Default the source language to whatever can be deduced from
+ the filename. If nothing can be deduced (such as for a C/C++
+ include file with a ".h" extension), then inherit whatever
+ language the previous subfile had. This kludgery is necessary
+ because there is no standard way in some object formats to
+ record the source language. Also, when symtabs are allocated
+ we try to deduce a language then as well, but it is too late
+ for us to use that information while reading symbols, since
+ symtabs aren't allocated until after all the symbols have
+ been processed for a given source file. */
+
+ subfile->language = deduce_language_from_filename (subfile->name);
+ if (subfile->language == language_unknown &&
+ subfile->next != NULL)
+ {
+ subfile->language = subfile->next->language;
+ }
+ }
+}
+
+
+/* Handle the N_BINCL and N_EINCL symbol types
+ that act like N_SOL for switching source files
+ (different subfiles, as we call them) within one object file,
+ but using a stack rather than in an arbitrary order. */
+
+void
+push_subfile ()
+{
+ register struct subfile_stack *tem
+ = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
+
+ tem->next = subfile_stack;
+ subfile_stack = tem;
+ if (current_subfile == NULL || current_subfile->name == NULL)
+ {
+ abort ();
+ }
+ tem->name = current_subfile->name;
+}
+
+char *
+pop_subfile ()
+{
+ register char *name;
+ register struct subfile_stack *link = subfile_stack;
+
+ if (link == NULL)
+ {
+ abort ();
+ }
+ name = link->name;
+ subfile_stack = link->next;
+ free ((PTR)link);
+ return (name);
+}
+
+
+/* Add a linetable entry for line number LINE and address PC to the line
+ vector for SUBFILE. */
+
+void
+record_line (subfile, line, pc)
+ register struct subfile *subfile;
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Ignore the dummy line number in libg.o */
+
+ if (line == 0xffff)
+ {
+ return;
+ }
+
+ /* Make sure line vector exists and is big enough. */
+ if (!subfile->line_vector)
+ {
+ subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH;
+ subfile->line_vector = (struct linetable *)
+ xmalloc (sizeof (struct linetable)
+ + subfile->line_vector_length * sizeof (struct linetable_entry));
+ subfile->line_vector->nitems = 0;
+ }
+
+ if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length)
+ {
+ subfile->line_vector_length *= 2;
+ subfile->line_vector = (struct linetable *)
+ xrealloc ((char *) subfile->line_vector, (sizeof (struct linetable)
+ + subfile->line_vector_length * sizeof (struct linetable_entry)));
+ }
+
+ e = subfile->line_vector->item + subfile->line_vector->nitems++;
+ e->line = line; e->pc = pc;
+}
+
+
+/* Needed in order to sort line tables from IBM xcoff files. Sigh! */
+
+static int
+compare_line_numbers (ln1p, ln2p)
+ const PTR ln1p;
+ const PTR ln2p;
+{
+ struct linetable_entry *ln1 = (struct linetable_entry *) ln1p;
+ struct linetable_entry *ln2 = (struct linetable_entry *) ln2p;
+
+ /* Note: this code does not assume that CORE_ADDRs can fit in ints.
+ Please keep it that way. */
+ if (ln1->pc < ln2->pc)
+ return -1;
+
+ if (ln1->pc > ln2->pc)
+ return 1;
+
+ /* If pc equal, sort by line. I'm not sure whether this is optimum
+ behavior (see comment at struct linetable in symtab.h). */
+ return ln1->line - ln2->line;
+}
+
+
+/* Start a new symtab for a new source file.
+ Called, for example, when a stabs symbol of type N_SO is seen, or when
+ a DWARF TAG_compile_unit DIE is seen.
+ It indicates the start of data for one original source file. */
+
+void
+start_symtab (name, dirname, start_addr)
+ char *name;
+ char *dirname;
+ CORE_ADDR start_addr;
+{
+
+ last_source_file = name;
+ last_source_start_addr = start_addr;
+ file_symbols = NULL;
+ global_symbols = NULL;
+ within_function = 0;
+
+ /* Context stack is initially empty. Allocate first one with room for
+ 10 levels; reuse it forever afterward. */
+ if (context_stack == NULL)
+ {
+ context_stack_size = INITIAL_CONTEXT_STACK_SIZE;
+ context_stack = (struct context_stack *)
+ xmalloc (context_stack_size * sizeof (struct context_stack));
+ }
+ context_stack_depth = 0;
+
+ /* Initialize the list of sub source files with one entry
+ for this file (the top-level source file). */
+
+ subfiles = NULL;
+ current_subfile = NULL;
+ start_subfile (name, dirname);
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the struct symtab
+ for that file and put it in the list of all such.
+
+ END_ADDR is the address of the end of the file's text.
+ SECTION is the section number (in objfile->section_offsets) of
+ the blockvector and linetable.
+
+ Note that it is possible for end_symtab() to return NULL. In particular,
+ for the DWARF case at least, it will return NULL when it finds a
+ compilation unit that has exactly one DIE, a TAG_compile_unit DIE. This
+ can happen when we link in an object file that was compiled from an empty
+ source file. Returning NULL is probably not the correct thing to do,
+ because then gdb will never know about this empty file (FIXME). */
+
+struct symtab *
+end_symtab (end_addr, sort_pending, sort_linevec, objfile, section)
+ CORE_ADDR end_addr;
+ int sort_pending;
+ int sort_linevec;
+ struct objfile *objfile;
+ int section;
+{
+ register struct symtab *symtab = NULL;
+ register struct blockvector *blockvector;
+ register struct subfile *subfile;
+ register struct context_stack *cstk;
+ struct subfile *nextsub;
+
+ /* Finish the lexical context of the last function in the file;
+ pop the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ context_stack_depth--;
+ cstk = &context_stack[context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, end_addr, objfile);
+
+ if (context_stack_depth > 0)
+ {
+ /* This is said to happen with SCO. The old coffread.c code
+ simply emptied the context stack, so we do the same. FIXME:
+ Find out why it is happening. This is not believed to happen
+ in most cases (even for coffread.c); it used to be an abort(). */
+ static struct complaint msg =
+ {"Context stack not empty in end_symtab", 0, 0};
+ complain (&msg);
+ context_stack_depth = 0;
+ }
+ }
+
+ /* It is unfortunate that in xcoff, pending blocks might not be ordered
+ in this stage. Especially, blocks for static functions will show up at
+ the end. We need to sort them, so tools like `find_pc_function' and
+ `find_pc_block' can work reliably. */
+
+ if (sort_pending && pending_blocks)
+ {
+ /* FIXME! Remove this horrid bubble sort and use qsort!!! */
+ int swapped;
+ do
+ {
+ struct pending_block *pb, *pbnext;
+
+ pb = pending_blocks;
+ pbnext = pb->next;
+ swapped = 0;
+
+ while (pbnext)
+ {
+ /* swap blocks if unordered! */
+
+ if (BLOCK_START(pb->block) < BLOCK_START(pbnext->block))
+ {
+ struct block *tmp = pb->block;
+ pb->block = pbnext->block;
+ pbnext->block = tmp;
+ swapped = 1;
+ }
+ pb = pbnext;
+ pbnext = pbnext->next;
+ }
+ } while (swapped);
+ }
+
+ /* Cleanup any undefined types that have been left hanging around
+ (this needs to be done before the finish_blocks so that
+ file_symbols is still good).
+
+ Both cleanup_undefined_types and finish_global_stabs are stabs
+ specific, but harmless for other symbol readers, since on gdb
+ startup or when finished reading stabs, the state is set so these
+ are no-ops. FIXME: Is this handled right in case of QUIT? Can
+ we make this cleaner? */
+
+ cleanup_undefined_types ();
+ finish_global_stabs (objfile);
+
+ if (pending_blocks == NULL
+ && file_symbols == NULL
+ && global_symbols == NULL)
+ {
+ /* Ignore symtabs that have no functions with real debugging info */
+ blockvector = NULL;
+ }
+ else
+ {
+ /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the blockvector. */
+ finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr,
+ objfile);
+ finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
+ objfile);
+ blockvector = make_blockvector (objfile);
+ }
+
+#ifdef PROCESS_LINENUMBER_HOOK
+ PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */
+#endif
+
+ /* Now create the symtab objects proper, one for each subfile. */
+ /* (The main file is the last one on the chain.) */
+
+ for (subfile = subfiles; subfile; subfile = nextsub)
+ {
+ int linetablesize = 0;
+ /* If we have blocks of symbols, make a symtab.
+ Otherwise, just ignore this file and any line number info in it. */
+ symtab = NULL;
+ if (blockvector)
+ {
+ if (subfile->line_vector)
+ {
+ linetablesize = sizeof (struct linetable) +
+ subfile->line_vector->nitems * sizeof (struct linetable_entry);
+#if 0
+ /* I think this is artifact from before it went on the obstack.
+ I doubt we'll need the memory between now and when we
+ free it later in this function. */
+ /* First, shrink the linetable to make more memory. */
+ subfile->line_vector = (struct linetable *)
+ xrealloc ((char *) subfile->line_vector, linetablesize);
+#endif
+ /* If sort_linevec is false, we might want just check to make
+ sure they are sorted and complain() if not, as a way of
+ tracking down compilers/symbol readers which don't get
+ them sorted right. */
+
+ if (sort_linevec)
+ qsort (subfile->line_vector->item,
+ subfile->line_vector->nitems,
+ sizeof (struct linetable_entry), compare_line_numbers);
+ }
+
+ /* Now, allocate a symbol table. */
+ symtab = allocate_symtab (subfile->name, objfile);
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ if (subfile->line_vector)
+ {
+ /* Reallocate the line table on the symbol obstack */
+ symtab->linetable = (struct linetable *)
+ obstack_alloc (&objfile -> symbol_obstack, linetablesize);
+ memcpy (symtab->linetable, subfile->line_vector, linetablesize);
+ }
+ else
+ {
+ symtab->linetable = NULL;
+ }
+ symtab->block_line_section = section;
+ if (subfile->dirname)
+ {
+ /* Reallocate the dirname on the symbol obstack */
+ symtab->dirname = (char *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ strlen (subfile -> dirname) + 1);
+ strcpy (symtab->dirname, subfile->dirname);
+ }
+ else
+ {
+ symtab->dirname = NULL;
+ }
+ symtab->free_code = free_linetable;
+ symtab->free_ptr = NULL;
+
+ /* Use whatever language we have been using for this subfile,
+ not the one that was deduced in allocate_symtab from the
+ filename. We already did our own deducing when we created
+ the subfile, and we may have altered our opinion of what
+ language it is from things we found in the symbols. */
+ symtab->language = subfile->language;
+
+ /* All symtabs for the main file and the subfiles share a
+ blockvector, so we need to clear primary for everything but
+ the main file. */
+
+ symtab->primary = 0;
+ }
+ if (subfile->name != NULL)
+ {
+ free ((PTR) subfile->name);
+ }
+ if (subfile->dirname != NULL)
+ {
+ free ((PTR) subfile->dirname);
+ }
+ if (subfile->line_vector != NULL)
+ {
+ free ((PTR) subfile->line_vector);
+ }
+
+ nextsub = subfile->next;
+ free ((PTR)subfile);
+ }
+
+ /* Set this for the main source file. */
+ if (symtab)
+ {
+ symtab->primary = 1;
+ }
+
+ last_source_file = NULL;
+ current_subfile = NULL;
+
+ return (symtab);
+}
+
+
+/* Push a context block. Args are an identifying nesting level (checkable
+ when you pop it), and the starting PC address of this context. */
+
+struct context_stack *
+push_context (desc, valu)
+ int desc;
+ CORE_ADDR valu;
+{
+ register struct context_stack *new;
+
+ if (context_stack_depth == context_stack_size)
+ {
+ context_stack_size *= 2;
+ context_stack = (struct context_stack *)
+ xrealloc ((char *) context_stack,
+ (context_stack_size * sizeof (struct context_stack)));
+ }
+
+ new = &context_stack[context_stack_depth++];
+ new->depth = desc;
+ new->locals = local_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = valu;
+ new->name = NULL;
+
+ local_symbols = NULL;
+
+ return (new);
+}
+
+
+/* Compute a small integer hash code for the given name. */
+
+int
+hashname (name)
+ char *name;
+{
+ register char *p = name;
+ register int total = p[0];
+ register int c;
+
+ c = p[1];
+ total += c << 2;
+ if (c)
+ {
+ c = p[2];
+ total += c << 4;
+ if (c)
+ {
+ total += p[3] << 6;
+ }
+ }
+
+ /* Ensure result is positive. */
+ if (total < 0)
+ {
+ total += (1000 << 6);
+ }
+ return (total % HASHSIZE);
+}
+
+
+/* Initialize anything that needs initializing when starting to read
+ a fresh piece of a symbol file, e.g. reading in the stuff corresponding
+ to a psymtab. */
+
+void
+buildsym_init ()
+{
+ free_pendings = NULL;
+ file_symbols = NULL;
+ global_symbols = NULL;
+ pending_blocks = NULL;
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+void
+buildsym_new_init ()
+{
+ buildsym_init ();
+}
+
+/* Initializer for this module */
+
+void
+_initialize_buildsym ()
+{
+}
diff --git a/gnu/usr.bin/gdb/gdb/buildsym.h b/gnu/usr.bin/gdb/gdb/buildsym.h
new file mode 100644
index 000000000000..e034863f396a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/buildsym.h
@@ -0,0 +1,259 @@
+/* Build symbol tables in GDB's internal format.
+ Copyright (C) 1986-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUILDSYM_H)
+#define BUILDSYM_H 1
+
+/* This module provides definitions used for creating and adding to
+ the symbol table. These routines are called from various symbol-
+ file-reading routines.
+
+ They originated in dbxread.c of gdb-4.2, and were split out to
+ make xcoffread.c more maintainable by sharing code.
+
+ Variables declared in this file can be defined by #define-ing
+ the name EXTERN to null. It is used to declare variables that
+ are normally extern, but which get defined in a single module
+ using this technique. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define HASHSIZE 127 /* Size of things hashed via hashname() */
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol of type N_SO. */
+
+EXTERN char *last_source_file;
+
+/* Core address of start of text of current source file.
+ This too comes from the N_SO symbol. */
+
+EXTERN CORE_ADDR last_source_start_addr;
+
+/* The list of sub-source-files within the current individual compilation.
+ Each file gets its own symtab with its own linetable and associated info,
+ but they all share one blockvector. */
+
+struct subfile
+{
+ struct subfile *next;
+ char *name;
+ char *dirname;
+ struct linetable *line_vector;
+ int line_vector_length;
+ enum language language;
+};
+
+EXTERN struct subfile *subfiles;
+
+EXTERN struct subfile *current_subfile;
+
+/* Global variable which, when set, indicates that we are processing a
+ .o file compiled with gcc */
+
+EXTERN unsigned char processing_gcc_compilation;
+
+/* When set, we are processing a .o file compiled by sun acc. This is
+ misnamed; it refers to all stabs-in-elf implementations which use
+ N_UNDF the way Sun does, including Solaris gcc. Hopefully all
+ stabs-in-elf implementations ever invented will choose to be
+ compatible. */
+
+EXTERN unsigned char processing_acc_compilation;
+
+/* Count symbols as they are processed, for error messages. */
+
+EXTERN unsigned int symnum;
+
+/* Record the symbols defined for each context in a list.
+ We don't create a struct block for the context until we
+ know how long to make it. */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+ struct pending *next;
+ int nsyms;
+ struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse. */
+
+EXTERN struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on. */
+
+EXTERN struct pending *file_symbols; /* static at top level, and types */
+
+EXTERN struct pending *global_symbols; /* global functions and variables */
+
+EXTERN struct pending *local_symbols; /* everything local to lexic context */
+
+/* Stack representing unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ /* Outer locals at the time we entered */
+
+ struct pending *locals;
+
+ /* Pointer into blocklist as of entry */
+
+ struct pending_block *old_blocks;
+
+ /* Name of function, if any, defining context*/
+
+ struct symbol *name;
+
+ /* PC where this context starts */
+
+ CORE_ADDR start_addr;
+
+ /* Temp slot for exception handling. */
+
+ CORE_ADDR end_addr;
+
+ /* For error-checking matching push/pop */
+
+ int depth;
+
+};
+
+EXTERN struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack. */
+
+EXTERN int context_stack_depth;
+
+/* Currently allocated size of context stack. */
+
+EXTERN int context_stack_size;
+
+/* Macro "function" for popping contexts from the stack. Pushing is done
+ by a real function, push_context. This returns a pointer to a struct
+ context_stack. */
+
+#define pop_context() (&context_stack[--context_stack_depth]);
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+EXTERN int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+ This is used at the end to make the blockvector. */
+
+struct pending_block
+{
+ struct pending_block *next;
+ struct block *block;
+};
+
+EXTERN struct pending_block *pending_blocks;
+
+
+struct subfile_stack
+{
+ struct subfile_stack *next;
+ char *name;
+};
+
+EXTERN struct subfile_stack *subfile_stack;
+
+#define next_symbol_text() (*next_symbol_text_func)()
+
+/* Function to invoke get the next symbol. Return the symbol name. */
+
+EXTERN char *(*next_symbol_text_func) PARAMS ((void));
+
+/* Vector of types defined so far, indexed by their type numbers.
+ Used for both stabs and coff.
+ (In newer sun systems, dbx uses a pair of numbers in parens,
+ as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be
+ translated through the type_translations hash table to get
+ the index into the type vector.) */
+
+EXTERN struct type **type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+EXTERN int type_vector_length;
+
+/* Initial size of type vector. Is realloc'd larger if needed,
+ and realloc'd down to the size actually used, when completed. */
+
+#define INITIAL_TYPE_VECTOR_LENGTH 160
+
+extern void
+add_symbol_to_list PARAMS ((struct symbol *, struct pending **));
+
+extern struct symbol *
+find_symbol_in_list PARAMS ((struct pending *, char *, int));
+
+extern void
+finish_block PARAMS ((struct symbol *, struct pending **,
+ struct pending_block *, CORE_ADDR, CORE_ADDR,
+ struct objfile *));
+
+extern void
+really_free_pendings PARAMS ((int foo));
+
+extern void
+start_subfile PARAMS ((char *, char *));
+
+extern void
+patch_subfile_names PARAMS ((struct subfile *subfile, char *name));
+
+extern void
+push_subfile PARAMS ((void));
+
+extern char *
+pop_subfile PARAMS ((void));
+
+extern struct symtab *
+end_symtab PARAMS ((CORE_ADDR, int, int, struct objfile *, int));
+
+extern void
+scan_file_globals PARAMS ((struct objfile *));
+
+extern void
+buildsym_new_init PARAMS ((void));
+
+extern void
+buildsym_init PARAMS ((void));
+
+extern struct context_stack *
+push_context PARAMS ((int, CORE_ADDR));
+
+extern void
+record_line PARAMS ((struct subfile *, int, CORE_ADDR));
+
+extern void
+start_symtab PARAMS ((char *, char *, CORE_ADDR));
+
+extern int
+hashname PARAMS ((char *));
+
+#undef EXTERN
+
+#endif /* defined (BUILDSYM_H) */
diff --git a/gnu/usr.bin/gdb/gdb/c-exp.y b/gnu/usr.bin/gdb/gdb/c-exp.y
new file mode 100644
index 000000000000..0e7d39ac6c2f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-exp.y
@@ -0,0 +1,1601 @@
+/* YACC parser for C expressions, for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a C expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include "defs.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "value.h"
+#include "language.h"
+#include "c-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth c_maxdepth
+#define yyparse c_parse
+#define yylex c_lex
+#define yyerror c_error
+#define yylval c_lval
+#define yychar c_char
+#define yydebug c_debug
+#define yypact c_pact
+#define yyr1 c_r1
+#define yyr2 c_r2
+#define yydef c_def
+#define yychk c_chk
+#define yypgo c_pgo
+#define yyact c_act
+#define yyexca c_exca
+#define yyerrflag c_errflag
+#define yynerrs c_nerrs
+#define yyps c_ps
+#define yypv c_pv
+#define yys c_s
+#define yy_yys c_yys
+#define yystate c_state
+#define yytmp c_tmp
+#define yyv c_v
+#define yy_yyv c_yyv
+#define yyval c_val
+#define yylloc c_lloc
+#define yyreds c_reds /* With YYDEBUG defined */
+#define yytoks c_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%{
+/* YYSTYPE gets defined by %union */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+%}
+
+%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> rcurly
+%type <tval> type typebase
+%type <tvec> nonempty_typelist
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+%type <lval> array_mod
+
+%token <typed_val> INT
+%token <dval> FLOAT
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+ and both convey their data as strings.
+ But a TYPENAME is a string that happens to be defined as a typedef
+ or builtin type name (such as int or char)
+ and a NAME is any other symbol.
+ Contexts where this distinction is not important can use the
+ nonterminal "name", which matches either NAME or TYPENAME. */
+
+%token <sval> STRING
+%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <tsym> TYPENAME
+%type <sval> name
+%type <ssym> name_not_typename
+%type <tsym> typename
+
+/* A NAME_OR_INT is a symbol which is not known in the symbol table,
+ but which would parse as a valid number in the current input radix.
+ E.g. "c" when input_radix==16. Depending on the parse, it will be
+ turned into a name or into a number. */
+
+%token <ssym> NAME_OR_INT
+
+%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON
+%token TEMPLATE
+%token ERROR
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD
+%token <lval> LAST REGNAME
+
+%token <ivar> VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+/* C++ */
+%token THIS
+
+%left ','
+%left ABOVE_COMMA
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+%right ARROW '.' '[' '('
+%token <ssym> BLOCKNAME
+%type <bval> block
+%left COLONCOLON
+
+
+%%
+
+start : exp1
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);}
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '*' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_IND); }
+
+exp : '&' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_ADDR); }
+
+exp : '-' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '!' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+exp : '~' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ ;
+
+exp : INCREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ ;
+
+exp : DECREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ ;
+
+exp : exp INCREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ ;
+
+exp : exp DECREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ ;
+
+exp : SIZEOF exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ ;
+
+exp : exp ARROW name
+ { write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ ;
+
+exp : exp ARROW qualified_name
+ { /* exp->type::name becomes exp->*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+exp : exp ARROW '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+
+exp : exp '.' name
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+exp : exp '.' qualified_name
+ { /* exp.type::name becomes exp.*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '.' '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '[' exp1 ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { start_arglist (); }
+ arglist ')' %prec ARROW
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ ;
+
+lcurly : '{'
+ { start_arglist (); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+rcurly : '}'
+ { $$ = end_arglist () - 1; }
+ ;
+exp : lcurly arglist rcurly %prec ARROW
+ { write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) $3);
+ write_exp_elt_opcode (OP_ARRAY); }
+ ;
+
+exp : lcurly type rcurly exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ ;
+
+exp : '(' type ')' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_CAST); }
+ ;
+
+exp : '(' exp1 ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+
+exp : exp '@' exp
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp '%' exp
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '-' exp
+ { write_exp_elt_opcode (BINOP_SUB); }
+ ;
+
+exp : exp LSH exp
+ { write_exp_elt_opcode (BINOP_LSH); }
+ ;
+
+exp : exp RSH exp
+ { write_exp_elt_opcode (BINOP_RSH); }
+ ;
+
+exp : exp EQUAL exp
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ ;
+
+exp : exp LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp GEQ exp
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ ;
+
+exp : exp '<' exp
+ { write_exp_elt_opcode (BINOP_LESS); }
+ ;
+
+exp : exp '>' exp
+ { write_exp_elt_opcode (BINOP_GTR); }
+ ;
+
+exp : exp '&' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ ;
+
+exp : exp '^' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ ;
+
+exp : exp '|' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ ;
+
+exp : exp ANDAND exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OROR exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp '?' exp ':' exp %prec '?'
+ { write_exp_elt_opcode (TERNOP_COND); }
+ ;
+
+exp : exp '=' exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+exp : exp ASSIGN_MODIFY exp
+ { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode ($2);
+ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : INT
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST)($1.val));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : NAME_OR_INT
+ { YYSTYPE val;
+ parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val);
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (val.typed_val.type);
+ write_exp_elt_longcst ((LONGEST)val.typed_val.val);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+
+exp : FLOAT
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE); }
+ ;
+
+exp : variable
+ ;
+
+exp : LAST
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LAST); }
+ ;
+
+exp : REGNAME
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_REGISTER); }
+ ;
+
+exp : VARIABLE
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+ ;
+
+exp : SIZEOF '(' type ')' %prec UNARY
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : STRING
+ { /* C strings are converted into array constants with
+ an explicit null byte added at the end. Thus
+ the array upper bound is the string length.
+ There is no such thing in C as a completely empty
+ string. */
+ char *sp = $1.ptr; int count = $1.length;
+ while (count-- > 0)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_longcst ((LONGEST)(*sp++));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_longcst ((LONGEST)'\0');
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) ($1.length));
+ write_exp_elt_opcode (OP_ARRAY); }
+ ;
+
+/* C++. */
+exp : THIS
+ { write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS); }
+ ;
+
+/* end of C++. */
+
+block : BLOCKNAME
+ {
+ if ($1.sym != 0)
+ $$ = SYMBOL_BLOCK_VALUE ($1.sym);
+ else
+ {
+ struct symtab *tem =
+ lookup_symtab (copy_name ($1.stoken));
+ if (tem)
+ $$ = BLOCKVECTOR_BLOCK
+ (BLOCKVECTOR (tem), STATIC_BLOCK);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name ($3));
+ $$ = SYMBOL_BLOCK_VALUE (tem); }
+ ;
+
+variable: block COLONCOLON name
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name ($3));
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* block_found is set by lookup_symbol. */
+ write_exp_elt_block (block_found);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+qualified_name: typebase COLONCOLON name
+ {
+ struct type *type = $1;
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string ($3);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ | typebase COLONCOLON '~' name
+ {
+ struct type *type = $1;
+ struct stoken tmp_token;
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ if (!STREQ (type_name_no_tag (type), $4.ptr))
+ error ("invalid destructor `%s::~%s'",
+ type_name_no_tag (type), $4.ptr);
+
+ tmp_token.ptr = (char*) alloca ($4.length + 2);
+ tmp_token.length = $4.length + 1;
+ tmp_token.ptr[0] = '~';
+ memcpy (tmp_token.ptr+1, $4.ptr, $4.length);
+ tmp_token.ptr[tmp_token.length] = 0;
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string (tmp_token);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ ;
+
+variable: qualified_name
+ | COLONCOLON name
+ {
+ char *name = copy_name ($2);
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+
+ sym =
+ lookup_symbol (name, (const struct block *) NULL,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym)
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ break;
+ }
+
+ msymbol = lookup_minimal_symbol (name,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.", name);
+ }
+ ;
+
+variable: name_not_typename
+ { struct symbol *sym = $1.sym;
+
+ if (sym)
+ {
+ if (symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* We want to use the selected frame, not
+ another more inner frame which happens to
+ be in the same block. */
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ else if ($1.is_a_field_of_this)
+ {
+ /* C++: it hangs off of `this'. Must
+ not inadvertently convert from a method call
+ to data ref. */
+ if (innermost_block == 0 ||
+ contained_in (block_found, innermost_block))
+ innermost_block = block_found;
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($1.stoken);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ register char *arg = copy_name ($1.stoken);
+
+ msymbol = lookup_minimal_symbol (arg,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+
+/* shift/reduce conflict: "typebase ." and the token is '('. (Shows up
+ twice, once where qualified_name is a possibility and once where
+ it is not). */
+/* shift/reduce conflict: "typebase CONST_KEYWORD ." and the token is '('. */
+/* shift/reduce conflict: "typebase VOLATILE_KEYWORD ." and the token is
+ '('. */
+ptype : typebase
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ before the type is currently handled in the typebase rule. */
+ | typebase CONST_KEYWORD
+ | typebase VOLATILE_KEYWORD
+ | typebase abs_decl
+ { $$ = follow_types ($1); }
+ | typebase CONST_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
+ | typebase VOLATILE_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
+ ;
+
+abs_decl: '*'
+ { push_type (tp_pointer); $$ = 0; }
+ | '*' abs_decl
+ { push_type (tp_pointer); $$ = $2; }
+ | '&'
+ { push_type (tp_reference); $$ = 0; }
+ | '&' abs_decl
+ { push_type (tp_reference); $$ = $2; }
+ | direct_abs_decl
+ ;
+
+direct_abs_decl: '(' abs_decl ')'
+ { $$ = $2; }
+ | direct_abs_decl array_mod
+ {
+ push_type_int ($2);
+ push_type (tp_array);
+ }
+ | array_mod
+ {
+ push_type_int ($1);
+ push_type (tp_array);
+ $$ = 0;
+ }
+
+ /* shift/reduce conflict. "direct_abs_decl . func_mod", and the token
+ is '('. */
+
+ | direct_abs_decl func_mod
+ { push_type (tp_function); }
+ | func_mod
+ { push_type (tp_function); }
+ ;
+
+array_mod: '[' ']'
+ { $$ = -1; }
+ | '[' INT ']'
+ { $$ = $2.val; }
+ ;
+
+func_mod: '(' ')'
+ { $$ = 0; }
+ | '(' nonempty_typelist ')'
+ { free ((PTR)$2); $$ = 0; }
+ ;
+
+/* shift/reduce conflict: "type '(' typebase COLONCOLON '*' ')' ." and the
+ token is '('. */
+type : ptype
+ | typebase COLONCOLON '*'
+ { $$ = lookup_member_type (builtin_type_int, $1); }
+ | type '(' typebase COLONCOLON '*' ')'
+ { $$ = lookup_member_type ($1, $3); }
+ | type '(' typebase COLONCOLON '*' ')' '(' ')'
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3); }
+ | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3);
+ free ((PTR)$8); }
+ ;
+
+typebase /* Implements (approximately): (type-qualifier)* type-specifier */
+ : TYPENAME
+ { $$ = $1.type; }
+ | INT_KEYWORD
+ { $$ = builtin_type_int; }
+ | LONG
+ { $$ = builtin_type_long; }
+ | SHORT
+ { $$ = builtin_type_short; }
+ | LONG INT_KEYWORD
+ { $$ = builtin_type_long; }
+ | UNSIGNED LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long; }
+ | LONG LONG
+ { $$ = builtin_type_long_long; }
+ | LONG LONG INT_KEYWORD
+ { $$ = builtin_type_long_long; }
+ | UNSIGNED LONG LONG
+ { $$ = builtin_type_unsigned_long_long; }
+ | UNSIGNED LONG LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long_long; }
+ | SHORT INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | UNSIGNED SHORT INT_KEYWORD
+ { $$ = builtin_type_unsigned_short; }
+ | STRUCT name
+ { $$ = lookup_struct (copy_name ($2),
+ expression_context_block); }
+ | CLASS name
+ { $$ = lookup_struct (copy_name ($2),
+ expression_context_block); }
+ | UNION name
+ { $$ = lookup_union (copy_name ($2),
+ expression_context_block); }
+ | ENUM name
+ { $$ = lookup_enum (copy_name ($2),
+ expression_context_block); }
+ | UNSIGNED typename
+ { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); }
+ | UNSIGNED
+ { $$ = builtin_type_unsigned_int; }
+ | SIGNED_KEYWORD typename
+ { $$ = lookup_signed_typename (TYPE_NAME($2.type)); }
+ | SIGNED_KEYWORD
+ { $$ = builtin_type_int; }
+ | TEMPLATE name '<' type '>'
+ { $$ = lookup_template_type(copy_name($2), $4,
+ expression_context_block);
+ }
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ after the type is handled in the ptype rule. I think these could
+ be too. */
+ | CONST_KEYWORD typebase { $$ = $2; }
+ | VOLATILE_KEYWORD typebase { $$ = $2; }
+ ;
+
+typename: TYPENAME
+ | INT_KEYWORD
+ {
+ $$.stoken.ptr = "int";
+ $$.stoken.length = 3;
+ $$.type = builtin_type_int;
+ }
+ | LONG
+ {
+ $$.stoken.ptr = "long";
+ $$.stoken.length = 4;
+ $$.type = builtin_type_long;
+ }
+ | SHORT
+ {
+ $$.stoken.ptr = "short";
+ $$.stoken.length = 5;
+ $$.type = builtin_type_short;
+ }
+ ;
+
+nonempty_typelist
+ : type
+ { $$ = (struct type **) malloc (sizeof (struct type *) * 2);
+ $<ivec>$[0] = 1; /* Number of types in vector */
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
+ $$ = (struct type **) realloc ((char *) $1, len);
+ $$[$<ivec>$[0]] = $3;
+ }
+ ;
+
+name : NAME { $$ = $1.stoken; }
+ | BLOCKNAME { $$ = $1.stoken; }
+ | TYPENAME { $$ = $1.stoken; }
+ | NAME_OR_INT { $$ = $1.stoken; }
+ ;
+
+name_not_typename : NAME
+ | BLOCKNAME
+/* These would be useful if name_not_typename was useful, but it is just
+ a fake for "variable", so these cause reduce/reduce conflicts because
+ the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable,
+ =exp) or just an exp. If name_not_typename was ever used in an lvalue
+ context where only a name could occur, this might be useful.
+ | NAME_OR_INT
+ */
+ ;
+
+%%
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (p, len, parsed_float, putithere)
+ register char *p;
+ register int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ register LONGEST n = 0;
+ register LONGEST prevn = 0;
+ register int i = 0;
+ register int c;
+ register int base = input_radix;
+ int unsigned_p = 0;
+ int long_p = 0;
+ unsigned LONGEST high_bit;
+ struct type *signed_type;
+ struct type *unsigned_type;
+
+ if (parsed_float)
+ {
+ /* It's a float since it contains a point or an exponent. */
+ putithere->dval = atof (p);
+ return FLOAT;
+ }
+
+ /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
+ if (p[0] == '0')
+ switch (p[1])
+ {
+ case 'x':
+ case 'X':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ break;
+
+ case 't':
+ case 'T':
+ case 'd':
+ case 'D':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 10;
+ len -= 2;
+ }
+ break;
+
+ default:
+ base = 8;
+ break;
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != 'l' && c != 'u')
+ n *= base;
+ if (c >= '0' && c <= '9')
+ n += i = c - '0';
+ else
+ {
+ if (base > 10 && c >= 'a' && c <= 'f')
+ n += i = c - 'a' + 10;
+ else if (len == 0 && c == 'l')
+ long_p = 1;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else
+ return ERROR; /* Char not a digit */
+ }
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base */
+
+ /* Portably test for overflow (only works for nonzero values, so make
+ a second check for zero). */
+ if((prevn >= n) && n != 0)
+ unsigned_p=1; /* Try something unsigned */
+ /* If range checking enabled, portably test for unsigned overflow. */
+ if(RANGE_CHECK && n!=0)
+ {
+ if((unsigned_p && (unsigned)prevn >= (unsigned)n))
+ range_error("Overflow on numeric constant.");
+ }
+ prevn=n;
+ }
+
+ /* If the number is too big to be an int, or it's got an l suffix
+ then it's a long. Work out if this has to be a long by
+ shifting right and and seeing if anything remains, and the
+ target int size is different to the target long size.
+
+ In the expression below, we could have tested
+ (n >> TARGET_INT_BIT)
+ to see if it was zero,
+ but too many compilers warn about that, when ints and longs
+ are the same size. So we shift it twice, with fewer bits
+ each time, for the same result. */
+
+ if ( (TARGET_INT_BIT != TARGET_LONG_BIT
+ && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */
+ || long_p)
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1);
+ unsigned_type = builtin_type_unsigned_int;
+ signed_type = builtin_type_int;
+ }
+
+ putithere->typed_val.val = n;
+
+ /* If the high bit of the worked out type is set then this number
+ has to be unsigned. */
+
+ if (unsigned_p || (n & high_bit))
+ {
+ putithere->typed_val.type = unsigned_type;
+ }
+ else
+ {
+ putithere->typed_val.type = signed_type;
+ }
+
+ return INT;
+}
+
+struct token
+{
+ char *operator;
+ int token;
+ enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+ {
+ {">>=", ASSIGN_MODIFY, BINOP_RSH},
+ {"<<=", ASSIGN_MODIFY, BINOP_LSH}
+ };
+
+static const struct token tokentab2[] =
+ {
+ {"+=", ASSIGN_MODIFY, BINOP_ADD},
+ {"-=", ASSIGN_MODIFY, BINOP_SUB},
+ {"*=", ASSIGN_MODIFY, BINOP_MUL},
+ {"/=", ASSIGN_MODIFY, BINOP_DIV},
+ {"%=", ASSIGN_MODIFY, BINOP_REM},
+ {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
+ {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
+ {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
+ {"++", INCREMENT, BINOP_END},
+ {"--", DECREMENT, BINOP_END},
+ {"->", ARROW, BINOP_END},
+ {"&&", ANDAND, BINOP_END},
+ {"||", OROR, BINOP_END},
+ {"::", COLONCOLON, BINOP_END},
+ {"<<", LSH, BINOP_END},
+ {">>", RSH, BINOP_END},
+ {"==", EQUAL, BINOP_END},
+ {"!=", NOTEQUAL, BINOP_END},
+ {"<=", LEQ, BINOP_END},
+ {">=", GEQ, BINOP_END}
+ };
+
+/* Read one token, getting characters through lexptr. */
+
+static int
+yylex ()
+{
+ int c;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *tokptr;
+ int tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (STREQN (tokstart, tokentab3[i].operator, 3))
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (STREQN (tokstart, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ /* We either have a character constant ('0' or '\177' for example)
+ or we have a quoted symbol reference ('foo(int,int)' in C++
+ for example). */
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+
+ yylval.typed_val.val = c;
+ yylval.typed_val.type = builtin_type_char;
+
+ c = *lexptr++;
+ if (c != '\'')
+ {
+ namelen = skip_quoted (tokstart) - tokstart;
+ if (namelen > 2)
+ {
+ lexptr = tokstart + namelen;
+ if (lexptr[-1] != '\'')
+ error ("Unmatched single quote.");
+ namelen -= 2;
+ tokstart++;
+ goto tryname;
+ }
+ error ("Invalid character constant.");
+ }
+ return INT;
+
+ case '(':
+ paren_depth++;
+ lexptr++;
+ return c;
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return c;
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return c;
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ goto symbol; /* Nope, must be a symbol. */
+ /* FALL THRU into number case. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0, toktype;
+ register char *p = tokstart;
+ int hex = input_radix > 10;
+
+ if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ hex = 1;
+ }
+ else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+ {
+ p += 2;
+ hex = 0;
+ }
+
+ for (;; ++p)
+ {
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
+ if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ /* This test does not include !hex, because a '.' always indicates
+ a decimal floating point number regardless of the radix. */
+ else if (!got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ /* We will take any letters or digits. parse_number will
+ complain if past the radix, or if L or U are not final. */
+ else if ((*p < '0' || *p > '9')
+ && ((*p < 'a' || *p > 'z')
+ && (*p < 'A' || *p > 'Z')))
+ break;
+ }
+ toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ symbol:
+ lexptr++;
+ return c;
+
+ case '"':
+
+ /* Build the gdb internal form of the input string in tempbuf,
+ translating any standard C escape forms seen. Note that the
+ buffer is null byte terminated *only* for the convenience of
+ debugging gdb itself and printing the buffer contents when
+ the buffer contains no embedded nulls. Gdb does not depend
+ upon the buffer being null byte terminated, it uses the length
+ string instead. This allows gdb to handle C strings (as well
+ as strings in other languages) with embedded null bytes */
+
+ tokptr = ++tokstart;
+ tempbufindex = 0;
+
+ do {
+ /* Grow the static temp buffer if necessary, including allocating
+ the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+ }
+ switch (*tokptr)
+ {
+ case '\0':
+ case '"':
+ /* Do nothing, loop will terminate. */
+ break;
+ case '\\':
+ tokptr++;
+ c = parse_escape (&tokptr);
+ if (c == -1)
+ {
+ continue;
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ default:
+ tempbuf[tempbufindex++] = *tokptr++;
+ break;
+ }
+ } while ((*tokptr != '"') && (*tokptr != '\0'));
+ if (*tokptr++ != '"')
+ {
+ error ("Unterminated string in expression.");
+ }
+ tempbuf[tempbufindex] = '\0'; /* See note above */
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = tokptr;
+ return (STRING);
+ }
+
+ if (!(c == '_' || c == '$'
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+ c = tokstart[++namelen])
+ ;
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+ and $$digits (equivalent to $<-digits> if you could type that).
+ Make token type LAST, and put the number (the digits) in yylval. */
+
+ tryname:
+ if (*tokstart == '$')
+ {
+ register int negate = 0;
+ c = 1;
+ /* Double dollar means negate the number and add -1 as well.
+ Thus $$ alone means -1. */
+ if (namelen >= 2 && tokstart[1] == '$')
+ {
+ negate = 1;
+ c = 2;
+ }
+ if (c == namelen)
+ {
+ /* Just dollars (one or two) */
+ yylval.lval = - negate;
+ return LAST;
+ }
+ /* Is the rest of the token digits? */
+ for (; c < namelen; c++)
+ if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
+ break;
+ if (c == namelen)
+ {
+ yylval.lval = atoi (tokstart + 1 + negate);
+ if (negate)
+ yylval.lval = - yylval.lval;
+ return LAST;
+ }
+ }
+
+ /* Handle tokens that refer to machine registers:
+ $ followed by a register name. */
+
+ if (*tokstart == '$') {
+ for (c = 0; c < NUM_REGS; c++)
+ if (namelen - 1 == strlen (reg_names[c])
+ && STREQN (tokstart + 1, reg_names[c], namelen - 1))
+ {
+ yylval.lval = c;
+ return REGNAME;
+ }
+ for (c = 0; c < num_std_regs; c++)
+ if (namelen - 1 == strlen (std_regs[c].name)
+ && STREQN (tokstart + 1, std_regs[c].name, namelen - 1))
+ {
+ yylval.lval = std_regs[c].regnum;
+ return REGNAME;
+ }
+ }
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (STREQN (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "template", 8))
+ return TEMPLATE;
+ if (STREQN (tokstart, "volatile", 8))
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (STREQN (tokstart, "struct", 6))
+ return STRUCT;
+ if (STREQN (tokstart, "signed", 6))
+ return SIGNED_KEYWORD;
+ if (STREQN (tokstart, "sizeof", 6))
+ return SIZEOF;
+ break;
+ case 5:
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "class", 5))
+ return CLASS;
+ if (STREQN (tokstart, "union", 5))
+ return UNION;
+ if (STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (STREQN (tokstart, "const", 5))
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (STREQN (tokstart, "enum", 4))
+ return ENUM;
+ if (STREQN (tokstart, "long", 4))
+ return LONG;
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "this", 4))
+ {
+ static const char this_name[] =
+ { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
+
+ if (lookup_symbol (this_name, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL))
+ return THIS;
+ }
+ break;
+ case 3:
+ if (STREQN (tokstart, "int", 3))
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ /* Any other names starting in $ are debugger internal variables. */
+
+ if (*tokstart == '$')
+ {
+ yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1);
+ return VARIABLE;
+ }
+
+ /* Use token-type BLOCKNAME for symbols that happen to be defined as
+ functions or symtabs. If this is not so, then ...
+ Use token-type TYPENAME for symbols that happen to be defined
+ currently as names of types; NAME for other symbols.
+ The caller is not constrained to care about the distinction. */
+ {
+ char *tmp = copy_name (yylval.sval);
+ struct symbol *sym;
+ int is_a_field_of_this = 0;
+ int hextype;
+
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE,
+ current_language->la_language == language_cplus
+ ? &is_a_field_of_this : (int *) NULL,
+ (struct symtab **) NULL);
+ if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) ||
+ lookup_partial_symtab (tmp))
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ char *p;
+ char *namestart;
+ struct symbol *best_sym;
+
+ /* Look ahead to detect nested types. This probably should be
+ done in the grammar, but trying seemed to introduce a lot
+ of shift/reduce and reduce/reduce conflicts. It's possible
+ that it could be done, though. Or perhaps a non-grammar, but
+ less ad hoc, approach would work well. */
+
+ /* Since we do not currently have any way of distinguishing
+ a nested type from a non-nested one (the stabs don't tell
+ us whether a type is nested), we just ignore the
+ containing type. */
+
+ p = lexptr;
+ best_sym = sym;
+ while (1)
+ {
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ if (*p == ':' && p[1] == ':')
+ {
+ /* Skip the `::'. */
+ p += 2;
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ namestart = p;
+ while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
+ || (*p >= 'a' && *p <= 'z')
+ || (*p >= 'A' && *p <= 'Z'))
+ ++p;
+ if (p != namestart)
+ {
+ struct symbol *cur_sym;
+ /* As big as the whole rest of the expression, which is
+ at least big enough. */
+ char *tmp = alloca (strlen (namestart));
+
+ memcpy (tmp, namestart, p - namestart);
+ tmp[p - namestart] = '\0';
+ cur_sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (cur_sym)
+ {
+ if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF)
+ {
+ best_sym = cur_sym;
+ lexptr = p;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ yylval.tsym.type = SYMBOL_TYPE (best_sym);
+ return TYPENAME;
+ }
+ if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
+ return TYPENAME;
+
+ /* Input names that aren't symbols but ARE valid hex numbers,
+ when the input radix permits them, can be names or numbers
+ depending on the parse. Note we support radixes > 16 here. */
+ if (!sym &&
+ ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INT)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME_OR_INT;
+ }
+ }
+
+ /* Any other kind of symbol */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ error (msg ? msg : "Invalid syntax in expression.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/c-lang.c b/gnu/usr.bin/gdb/gdb/c-lang.c
new file mode 100644
index 000000000000..ea0795915f56
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.c
@@ -0,0 +1,447 @@
+/* C language support routines for GDB, the GNU debugger.
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific. */
+
+static void
+emit_char (c, stream, quoter)
+ register int c;
+ FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+static void
+c_printchar (c, stream)
+ int c;
+ FILE *stream;
+{
+ fputs_filtered ("'", stream);
+ emit_char (c, stream, '\'');
+ fputs_filtered ("'", stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */
+
+static void
+c_printstr (stream, string, length, force_ellipses)
+ FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+ extern int inspect_it;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in traditional C
+ style. */
+ if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
+ length--;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stdout);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ fputs_filtered (", ", stream);
+ need_comma = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ c_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ if (!in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ in_quotes = 1;
+ }
+ emit_char (string[i], stream, '"');
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ }
+
+ if (force_ellipses || i < length)
+ fputs_filtered ("...", stream);
+}
+
+/* Create a fundamental C type using default reasonable for the current
+ target machine.
+
+ Some object/debugging file formats (DWARF version 1, COFF, etc) do not
+ define fundamental types such as "int" or "double". Others (stabs or
+ DWARF version 2, etc) do define fundamental types. For the formats which
+ don't provide fundamental types, gdb can create such types using this
+ function.
+
+ FIXME: Some compilers distinguish explicitly signed integral types
+ (signed short, signed int, signed long) from "regular" integral types
+ (short, int, long) in the debugging information. There is some dis-
+ agreement as to how useful this feature is. In particular, gcc does
+ not support this. Also, only some debugging formats allow the
+ distinction to be passed on to a debugger. For now, we always just
+ use "short", "int", or "long" as the type name, for both the implicit
+ and explicitly signed types. This also makes life easier for the
+ gdb test suite since we don't have to account for the differences
+ in output depending upon what the compiler and debugging format
+ support. We will probably have to re-examine the issue when gdb
+ starts taking it's fundamental type information directly from the
+ debugging information supplied by the compiler. fnf@cygnus.com */
+
+static struct type *
+c_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "<?type?>", objfile);
+ warning ("internal error: no C/C++ fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ type = init_type (TYPE_CODE_VOID,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "void", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "char", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "signed char", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
+ break;
+ case FT_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "short", objfile); /* FIXME-fnf */
+ break;
+ case FT_UNSIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
+ break;
+ case FT_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile);
+ break;
+ case FT_SIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "int", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
+ break;
+ case FT_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile);
+ break;
+ case FT_SIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "long", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
+ break;
+ case FT_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long long", objfile);
+ break;
+ case FT_SIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "signed long long", objfile);
+ break;
+ case FT_UNSIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "double", objfile);
+ break;
+ case FT_EXT_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long double", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+static const struct op_print c_op_print_tab[] =
+ {
+ {",", BINOP_COMMA, PREC_COMMA, 0},
+ {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+ {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+ {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+ {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {">>", BINOP_RSH, PREC_SHIFT, 0},
+ {"<<", BINOP_LSH, PREC_SHIFT, 0},
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"%", BINOP_REM, PREC_MUL, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+ {"*", UNOP_IND, PREC_PREFIX, 0},
+ {"&", UNOP_ADDR, PREC_PREFIX, 0},
+ {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
+ {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+ {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+ /* C++ */
+ {"::", BINOP_SCOPE, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+struct type ** const (c_builtin_types[]) =
+{
+ &builtin_type_int,
+ &builtin_type_long,
+ &builtin_type_short,
+ &builtin_type_char,
+ &builtin_type_float,
+ &builtin_type_double,
+ &builtin_type_void,
+ &builtin_type_long_long,
+ &builtin_type_signed_char,
+ &builtin_type_unsigned_char,
+ &builtin_type_unsigned_short,
+ &builtin_type_unsigned_int,
+ &builtin_type_unsigned_long,
+ &builtin_type_unsigned_long_long,
+ &builtin_type_long_double,
+ &builtin_type_complex,
+ &builtin_type_double_complex,
+ 0
+};
+
+const struct language_defn c_language_defn = {
+ "c", /* Language name */
+ language_c,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ c_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_create_fundamental_type, /* Create fundamental type in this language */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &builtin_type_double, /* longest floating point type */ /*FIXME*/
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ c_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+const struct language_defn cplus_language_defn = {
+ "c++", /* Language name */
+ language_cplus,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ c_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_create_fundamental_type, /* Create fundamental type in this language */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &builtin_type_double, /* longest floating point type */ /*FIXME*/
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ c_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+void
+_initialize_c_language ()
+{
+ add_language (&c_language_defn);
+ add_language (&cplus_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/c-lang.h b/gnu/usr.bin/gdb/gdb/c-lang.h
new file mode 100644
index 000000000000..4c343a9a5aa7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.h
@@ -0,0 +1,31 @@
+/* C language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern int
+c_parse PARAMS ((void)); /* Defined in c-exp.y */
+
+extern void
+c_error PARAMS ((char *)); /* Defined in c-exp.y */
+
+extern void /* Defined in c-typeprint.c */
+c_print_type PARAMS ((struct type *, char *, FILE *, int, int));
+
+extern int
+c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ int, enum val_prettyprint));
diff --git a/gnu/usr.bin/gdb/gdb/c-typeprint.c b/gnu/usr.bin/gdb/gdb/c-typeprint.c
new file mode 100644
index 000000000000..fa4035b00ac8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-typeprint.c
@@ -0,0 +1,797 @@
+/* Support for printing C and C++ types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "c-lang.h"
+#include "typeprint.h"
+
+#include <string.h>
+#include <errno.h>
+
+extern int demangle; /* whether to print C++ syms raw or source-form */
+
+static void
+c_type_print_args PARAMS ((struct type *, FILE *));
+
+static void
+c_type_print_varspec_suffix PARAMS ((struct type *, FILE *, int, int, int));
+
+static void
+cp_type_print_derivation_info PARAMS ((FILE *, struct type *));
+
+void
+c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int));
+
+void
+c_type_print_base PARAMS ((struct type *, FILE *, int, int));
+
+
+/* Print a description of a type in the format of a
+ typedef for the current language.
+ NEW is the new name for a type TYPE. */
+
+void
+c_typedef_print (type, new, stream)
+ struct type *type;
+ struct symbol *new;
+ FILE *stream;
+{
+ switch (current_language->la_language)
+ {
+#ifdef _LANG_c
+ case language_c:
+ case language_cplus:
+ fprintf_filtered(stream, "typedef ");
+ type_print(type,"",stream,0);
+ if(TYPE_NAME ((SYMBOL_TYPE (new))) == 0
+ || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new)))
+ fprintf_filtered(stream, " %s", SYMBOL_SOURCE_NAME(new));
+ break;
+#endif
+#ifdef _LANG_m2
+ case language_m2:
+ fprintf_filtered(stream, "TYPE ");
+ if(!TYPE_NAME(SYMBOL_TYPE(new)) ||
+ !STREQ (TYPE_NAME(SYMBOL_TYPE(new)), SYMBOL_NAME(new)))
+ fprintf_filtered(stream, "%s = ", SYMBOL_SOURCE_NAME(new));
+ else
+ fprintf_filtered(stream, "<builtin> = ");
+ type_print(type,"",stream,0);
+ break;
+#endif
+#ifdef _LANG_chill
+ case language_chill:
+ error ("Missing Chill support in function c_typedef_print."); /*FIXME*/
+#endif
+ default:
+ error("Language not supported.");
+ }
+ fprintf_filtered(stream, ";\n");
+}
+
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+c_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ register enum type_code code;
+ int demangled_args;
+
+ c_type_print_base (type, stream, show, level);
+ code = TYPE_CODE (type);
+ if ((varstring != NULL && *varstring != '\0')
+ ||
+ /* Need a space if going to print stars or brackets;
+ but not if we will print just a type name. */
+ ((show > 0 || TYPE_NAME (type) == 0)
+ &&
+ (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+ || code == TYPE_CODE_METHOD
+ || code == TYPE_CODE_ARRAY
+ || code == TYPE_CODE_MEMBER
+ || code == TYPE_CODE_REF)))
+ fputs_filtered (" ", stream);
+ c_type_print_varspec_prefix (type, stream, show, 0);
+
+ fputs_filtered (varstring, stream);
+
+ /* For demangled function names, we have the arglist as part of the name,
+ so don't print an additional pair of ()'s */
+
+ demangled_args = varstring[strlen(varstring) - 1] == ')';
+ c_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+
+}
+
+/* Print the C++ method arguments ARGS to the file STREAM. */
+
+void
+cp_type_print_method_args (args, prefix, varstring, staticp, stream)
+ struct type **args;
+ char *prefix;
+ char *varstring;
+ int staticp;
+ FILE *stream;
+{
+ int i;
+
+ fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI);
+ fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI);
+ fputs_filtered (" (", stream);
+ if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID)
+ {
+ i = !staticp; /* skip the class variable */
+ while (1)
+ {
+ type_print (args[i++], "", stream, 0);
+ if (!args[i])
+ {
+ fprintf_filtered (stream, " ...");
+ break;
+ }
+ else if (args[i]->code != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ else break;
+ }
+ }
+ fprintf_filtered (stream, ")");
+}
+
+/* If TYPE is a derived type, then print out derivation information.
+ Print only the actual base classes of this type, not the base classes
+ of the base classes. I.E. for the derivation hierarchy:
+
+ class A { int a; };
+ class B : public A {int b; };
+ class C : public B {int c; };
+
+ Print the type of class C as:
+
+ class C : public B {
+ int c;
+ }
+
+ Not as the following (like gdb used to), which is not legal C++ syntax for
+ derived types and may be confused with the multiple inheritance form:
+
+ class C : public B : public A {
+ int c;
+ }
+
+ In general, gdb should try to print the types as closely as possible to
+ the form that they appear in the source code. */
+
+static void
+cp_type_print_derivation_info (stream, type)
+ FILE *stream;
+ struct type *type;
+{
+ char *name;
+ int i;
+
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ fputs_filtered (i == 0 ? ": " : ", ", stream);
+ fprintf_filtered (stream, "%s%s ",
+ BASETYPE_VIA_PUBLIC (type, i) ? "public" : "private",
+ BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : "");
+ name = type_name_no_tag (TYPE_BASECLASS (type, i));
+ fprintf_filtered (stream, "%s", name ? name : "(null)");
+ }
+ if (i > 0)
+ {
+ fputs_filtered (" ", stream);
+ }
+}
+
+/* Print any asterisks or open-parentheses needed before the
+ variable name (to describe its type).
+
+ On outermost call, pass 0 for PASSED_A_PTR.
+ On outermost call, SHOW > 0 means should ignore
+ any typename for TYPE and show its details.
+ SHOW is always zero on recursive calls. */
+
+void
+c_type_print_varspec_prefix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ char *name;
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "*");
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ fprintf_filtered (stream, " ");
+ name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ {
+ fprintf_filtered (stream, " ");
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ }
+ break;
+
+ case TYPE_CODE_REF:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "&");
+ break;
+
+ case TYPE_CODE_FUNC:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_ARRAY:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_BITSTRING:
+ /* These types need no prefix. They are listed here so that
+ gcc -Wall will reveal any types that haven't been handled. */
+ break;
+ }
+}
+
+static void
+c_type_print_args (type, stream)
+ struct type *type;
+ FILE *stream;
+{
+ int i;
+ struct type **args;
+
+ fprintf_filtered (stream, "(");
+ args = TYPE_ARG_TYPES (type);
+ if (args != NULL)
+ {
+ if (args[1] == NULL)
+ {
+ fprintf_filtered (stream, "...");
+ }
+ else
+ {
+ for (i = 1;
+ args[i] != NULL && args[i]->code != TYPE_CODE_VOID;
+ i++)
+ {
+ c_print_type (args[i], "", stream, -1, 0);
+ if (args[i+1] == NULL)
+ {
+ fprintf_filtered (stream, "...");
+ }
+ else if (args[i+1]->code != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, ",");
+ wrap_here (" ");
+ }
+ }
+ }
+ }
+ fprintf_filtered (stream, ")");
+}
+
+/* Print any array sizes, function arguments or close parentheses
+ needed after the variable name (to describe its type).
+ Args work like c_type_print_varspec_prefix. */
+
+static void
+c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+ int demangled_args;
+{
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+
+ fprintf_filtered (stream, "[");
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ fprintf_filtered (stream, "%d",
+ (TYPE_LENGTH (type)
+ / TYPE_LENGTH (TYPE_TARGET_TYPE (type))));
+ fprintf_filtered (stream, "]");
+
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ if (passed_a_ptr)
+ {
+ c_type_print_args (type, stream);
+ }
+ break;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0);
+ break;
+
+ case TYPE_CODE_FUNC:
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ if (!demangled_args)
+ fprintf_filtered (stream, "()");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_BITSTRING:
+ /* These types do not need a suffix. They are listed so that
+ gcc -Wall will report types that may not have been considered. */
+ break;
+ }
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element), or the description of a
+ structure or union.
+
+ SHOW positive means print details about the type (e.g. enum values),
+ and print structure elements passing SHOW - 1 for show.
+ SHOW zero means just print the type name or struct tag if there is one.
+ If there is no name, print something sensible but concise like
+ "struct {...}".
+ SHOW negative means the same things as SHOW zero. The difference is that
+ zero is used for printing structure elements and -1 is used for the
+ "whatis" command. But I don't see any need to distinguish.
+
+ LEVEL is the number of spaces to indent by.
+ We increase it for some recursive calls. */
+
+void
+c_type_print_base (type, stream, show, level)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int level;
+{
+ register int i;
+ register int len;
+ register int lastval;
+ char *mangled_name;
+ char *demangled_name;
+ enum {s_none, s_public, s_private, s_protected} section_type;
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", stream);
+ return;
+ }
+
+ /* When SHOW is zero or less, and there is a valid type name, then always
+ just print the type name directly from the type. */
+ /* If we have "typedef struct foo {. . .} bar;" do we want to print it
+ as "struct foo" or as "bar"? Pick the latter, because C++ folk tend
+ to expect things like "class5 *foo" rather than "struct class5 *foo". */
+
+ if (show <= 0
+ && TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
+ c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ fprintf_filtered (stream, "class ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "struct ");
+ }
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ fprintf_filtered (stream, "union ");
+
+ struct_union:
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+ wrap_here (" ");
+ if (show <= 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0)
+ {
+ check_stub_type (type);
+
+ cp_type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "{\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ else
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+
+ /* Start off with no specific section type, so we can print
+ one for the first field we find, and use that section type
+ thereafter until we find another type. */
+
+ section_type = s_none;
+
+ /* If there is a base class for this type,
+ do not print the field that it occupies. */
+
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ /* Don't print out virtual function table. */
+ if ((TYPE_FIELD_NAME (type, i))[5] == CPLUS_MARKER &&
+ !strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5))
+ continue;
+
+ /* If this is a C++ class we can print the various C++ section
+ labels. */
+
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ if (TYPE_FIELD_PROTECTED (type, i))
+ {
+ if (section_type != s_protected)
+ {
+ section_type = s_protected;
+ fprintfi_filtered (level + 2, stream,
+ "protected:\n");
+ }
+ }
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ {
+ if (section_type != s_private)
+ {
+ section_type = s_private;
+ fprintfi_filtered (level + 2, stream, "private:\n");
+ }
+ }
+ else
+ {
+ if (section_type != s_public)
+ {
+ section_type = s_public;
+ fprintfi_filtered (level + 2, stream, "public:\n");
+ }
+ }
+ }
+
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ fprintf_filtered (stream, "static ");
+ }
+ c_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ if (!TYPE_FIELD_STATIC (type, i)
+ && TYPE_FIELD_PACKED (type, i))
+ {
+ /* It is a bitfield. This code does not attempt
+ to look at the bitpos and reconstruct filler,
+ unnamed fields. This would lead to misleading
+ results if the compiler does not put out fields
+ for such things (I don't know what it does). */
+ fprintf_filtered (stream, " : %d",
+ TYPE_FIELD_BITSIZE (type, i));
+ }
+ fprintf_filtered (stream, ";\n");
+ }
+
+ /* If there are both fields and methods, put a space between. */
+ len = TYPE_NFN_FIELDS (type);
+ if (len && section_type != s_none)
+ fprintf_filtered (stream, "\n");
+
+ /* C++: print out the methods */
+
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ char *method_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ char *name = type_name_no_tag (type);
+ int is_constructor = name && STREQ(method_name, name);
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_PROTECTED (f, j))
+ {
+ if (section_type != s_protected)
+ {
+ section_type = s_protected;
+ fprintfi_filtered (level + 2, stream,
+ "protected:\n");
+ }
+ }
+ else if (TYPE_FN_FIELD_PRIVATE (f, j))
+ {
+ if (section_type != s_private)
+ {
+ section_type = s_private;
+ fprintfi_filtered (level + 2, stream, "private:\n");
+ }
+ }
+ else
+ {
+ if (section_type != s_public)
+ {
+ section_type = s_public;
+ fprintfi_filtered (level + 2, stream, "public:\n");
+ }
+ }
+
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ fprintf_filtered (stream, "virtual ");
+ else if (TYPE_FN_FIELD_STATIC_P (f, j))
+ fprintf_filtered (stream, "static ");
+ if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) == 0)
+ {
+ /* Keep GDB from crashing here. */
+ fprintf (stream, "<undefined type> %s;\n",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ break;
+ }
+ else if (!is_constructor)
+ {
+ type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
+ "", stream, 0);
+ fputs_filtered (" ", stream);
+ }
+ if (TYPE_FN_FIELD_STUB (f, j))
+ {
+ /* Build something we can demangle. */
+ mangled_name = gdb_mangle_name (type, i, j);
+ demangled_name =
+ cplus_demangle (mangled_name,
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ fprintf_filtered (stream, "<badly mangled name %s>",
+ mangled_name);
+ else
+ {
+ char *demangled_no_class =
+ strchr (demangled_name, ':');
+
+ if (demangled_no_class == NULL)
+ demangled_no_class = demangled_name;
+ else
+ {
+ if (*++demangled_no_class == ':')
+ ++demangled_no_class;
+ }
+ fputs_filtered (demangled_no_class, stream);
+ free (demangled_name);
+ }
+ free (mangled_name);
+ }
+ else if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1,
+ "~", method_name, 0, stream);
+ else
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
+ method_name,
+ TYPE_FN_FIELD_STATIC_P (f, j),
+ stream);
+
+ fprintf_filtered (stream, ";\n");
+ }
+ }
+
+ fprintfi_filtered (level, stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ fprintf_filtered (stream, "enum ");
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+
+ wrap_here (" ");
+ if (show <= 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0)
+ {
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ lastval = 0;
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i) fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ if (lastval != TYPE_FIELD_BITPOS (type, i))
+ {
+ fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i));
+ lastval = TYPE_FIELD_BITPOS (type, i);
+ }
+ lastval++;
+ }
+ fprintf_filtered (stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ fprintf_filtered (stream, "struct <unknown>");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<unknown type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* This should not occur */
+ fprintf_filtered (stream, "<range type>");
+ break;
+
+ default:
+ /* Handle types not explicitly handled by the other cases,
+ such as fundamental types. For these, just print whatever
+ the type name is, as recorded in the type itself. If there
+ is no type name, then complain. */
+ if (TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ }
+ else
+ {
+ /* At least for dump_symtab, it is important that this not be
+ an error (). */
+ fprintf_filtered (stream, "<invalid type code %d>",
+ TYPE_CODE (type));
+ }
+ break;
+ }
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/c-valprint.c b/gnu/usr.bin/gdb/gdb/c-valprint.c
new file mode 100644
index 000000000000..bcf0a2876732
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-valprint.c
@@ -0,0 +1,416 @@
+/* Support for printing C values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "language.h"
+
+/* BEGIN-FIXME */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+extern int demangle; /* whether to print C++ syms raw or src-form */
+
+extern void
+cp_print_class_member PARAMS ((char *, struct type *, FILE *, char *));
+
+extern void
+cp_print_class_method PARAMS ((char *, struct type *, FILE *));
+
+extern void
+cp_print_value_fields PARAMS ((struct type *, char *, FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+extern int
+cp_is_vtbl_ptr_type PARAMS ((struct type *));
+
+extern int
+cp_is_vtbl_member PARAMS ((struct type *));
+
+/* END-FIXME */
+
+
+/* BEGIN-FIXME: Hooks into c-typeprint.c */
+
+extern void
+c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ FILE *));
+/* END-FIXME */
+
+
+extern struct obstack dont_print_obstack;
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter or 0 for natural format). The data at VALADDR is in
+ target byte order.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting. */
+
+int
+c_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ register unsigned int i = 0; /* Number of characters printed */
+ unsigned len;
+ struct type *elttype;
+ unsigned eltlen;
+ LONGEST val;
+ CORE_ADDR addr;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+ if (prettyprint_arrays)
+ {
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ /* For an array of chars, print with string syntax. */
+ if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && (format == 0 || format == 's'))
+ {
+ LA_PRINT_STRING (stream, valaddr, len, 0);
+ i = len;
+ }
+ else
+ {
+ fprintf_filtered (stream, "{");
+ /* If this is a virtual function table, print the 0th
+ entry specially, and the rest of the members normally. */
+ if (cp_is_vtbl_ptr_type (elttype))
+ {
+ i = 1;
+ fprintf_filtered (stream, "%d vtable entries", len - 1);
+ }
+ else
+ {
+ i = 0;
+ }
+ val_print_array_elements (type, valaddr, address, stream,
+ format, deref_ref, recurse, pretty, i);
+ fprintf_filtered (stream, "}");
+ }
+ break;
+ }
+ /* Array of unspecified length: treat like pointer to first elt. */
+ addr = address;
+ goto print_unpacked_pointer;
+
+ case TYPE_CODE_PTR:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
+ {
+ cp_print_class_method (valaddr, type, stream);
+ }
+ else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ cp_print_class_member (valaddr,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "&");
+ }
+ else
+ {
+ addr = unpack_pointer (type, valaddr);
+ print_unpacked_pointer:
+ elttype = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+ {
+ /* Try to print what function it points to. */
+ print_address_demangle (addr, stream, demangle);
+ /* Return value is irrelevant except for string pointers. */
+ return (0);
+ }
+
+ if (addressprint && format != 's')
+ {
+ fprintf_filtered (stream, "0x%lx", (unsigned long)addr);
+ }
+
+ /* For a pointer to char or unsigned char, also print the string
+ pointed to, unless pointer is null. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && (format == 0 || format == 's')
+ && addr != 0)
+ {
+ i = val_print_string (addr, 0, stream);
+ }
+ else if (cp_is_vtbl_member(type))
+ {
+ /* print vtbl's nicely */
+ CORE_ADDR vt_address = unpack_pointer (type, valaddr);
+
+ struct minimal_symbol *msymbol =
+ lookup_minimal_symbol_by_pc (vt_address);
+ if ((msymbol != NULL) &&
+ (vt_address == SYMBOL_VALUE_ADDRESS (msymbol)))
+ {
+ fputs_filtered (" <", stream);
+ fputs_filtered (SYMBOL_SOURCE_NAME (msymbol), stream);
+ fputs_filtered (">", stream);
+ }
+ if (vtblprint)
+ {
+ value vt_val;
+ struct symbol *wsym = (struct symbol *)NULL;
+ struct type *wtype;
+ struct symtab *s;
+ struct block *block = (struct block *)NULL;
+ int is_this_fld;
+
+
+ wsym = lookup_symbol (SYMBOL_NAME(msymbol), block,
+ VAR_NAMESPACE, &is_this_fld, &s);
+
+ if (wsym)
+ {
+ wtype = SYMBOL_TYPE(wsym);
+ }
+ else
+ {
+ wtype = TYPE_TARGET_TYPE(type);
+ }
+ vt_val = value_at (wtype, vt_address);
+ val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val),
+ VALUE_ADDRESS (vt_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ }
+ }
+
+ /* Return number of characters printed, plus one for the
+ terminating null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ }
+ break;
+
+ case TYPE_CODE_MEMBER:
+ error ("not implemented: member type in c_val_print");
+ break;
+
+ case TYPE_CODE_REF:
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ cp_print_class_member (valaddr,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "");
+ break;
+ }
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "@0x%lx",
+ unpack_long (builtin_type_int, valaddr));
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr));
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ VALUE_ADDRESS (deref_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+
+ case TYPE_CODE_UNION:
+ if (recurse && !unionprint)
+ {
+ fprintf_filtered (stream, "{...}");
+ break;
+ }
+ /* Fall through. */
+ case TYPE_CODE_STRUCT:
+ if (vtblprint && cp_is_vtbl_ptr_type(type))
+ {
+ /* Print the unmangled name if desired. */
+ print_address_demangle(*((int *) (valaddr + /* FIXME bytesex */
+ TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8)),
+ stream, demangle);
+ break;
+ }
+ cp_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ 0);
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = unpack_long (type, valaddr);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (val == TYPE_FIELD_BITPOS (type, i))
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ /* FIXME, we should consider, at least for ANSI C language, eliminating
+ the distinction made between FUNCs and POINTERs to FUNCs. */
+ fprintf_filtered (stream, "{");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, "} ");
+ /* Try to print what function it points to, and its address. */
+ print_address_demangle (address, stream, demangle);
+ break;
+
+ case TYPE_CODE_BOOL:
+ /* Do something at least vaguely reasonable, for example if the
+ language is set wrong. */
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr, stream);
+ /* C and C++ has no single byte int type, char is used instead.
+ Since we don't know whether the value is really intended to
+ be used as an integer or a character, print the character
+ equivalent as well. */
+ if (TYPE_LENGTH (type) == 1)
+ {
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr),
+ stream);
+ }
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, TYPE_UNSIGNED (type) ? "%u" : "%d",
+ unpack_long (type, valaddr));
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<error type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* FIXME, we should not ever have to print one of these yet. */
+ fprintf_filtered (stream, "<range type>");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ default:
+ error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type));
+ }
+ fflush (stream);
+ return (0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/call-cmds.h b/gnu/usr.bin/gdb/gdb/call-cmds.h
new file mode 100644
index 000000000000..9030d8495cfd
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/call-cmds.h
@@ -0,0 +1,28 @@
+/* Prototypes for GDB commands that are called internally by other functions.
+ Copyright 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern void
+initialize_all_files PARAMS ((void));
+
+extern void
+exec_file_command PARAMS ((char *, int));
+
+extern void
+core_file_command PARAMS ((char *, int));
+
+extern void
+break_command PARAMS ((char *, int));
diff --git a/gnu/usr.bin/gdb/gdb/ch-exp.y b/gnu/usr.bin/gdb/gdb/ch-exp.y
new file mode 100644
index 000000000000..b6370f3241f0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-exp.y
@@ -0,0 +1,1997 @@
+/* YACC grammar for Chill expressions, for GDB.
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a Chill expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator.
+
+ Also note that the language accepted by this parser is more liberal
+ than the one accepted by an actual Chill compiler. For example, the
+ language rule that a simple name string can not be one of the reserved
+ simple name strings is not enforced (e.g "case" is not treated as a
+ reserved name). Another example is that Chill is a strongly typed
+ language, and certain expressions that violate the type constraints
+ may still be evaluated if gdb can do so in a meaningful manner, while
+ such expressions would be rejected by the compiler. The reason for
+ this more liberal behavior is the philosophy that the debugger
+ is intended to be a tool that is used by the programmer when things
+ go wrong, and as such, it should provide as few artificial barriers
+ to it's use as possible. If it can do something meaningful, even
+ something that violates language contraints that are enforced by the
+ compiler, it should do so without complaint.
+
+ */
+
+%{
+
+#include "defs.h"
+#include <ctype.h>
+#include "expression.h"
+#include "language.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "ch-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth chill_maxdepth
+#define yyparse chill_parse
+#define yylex chill_lex
+#define yyerror chill_error
+#define yylval chill_lval
+#define yychar chill_char
+#define yydebug chill_debug
+#define yypact chill_pact
+#define yyr1 chill_r1
+#define yyr2 chill_r2
+#define yydef chill_def
+#define yychk chill_chk
+#define yypgo chill_pgo
+#define yyact chill_act
+#define yyexca chill_exca
+#define yyerrflag chill_errflag
+#define yynerrs chill_nerrs
+#define yyps chill_ps
+#define yypv chill_pv
+#define yys chill_s
+#define yy_yys chill_yys
+#define yystate chill_state
+#define yytmp chill_tmp
+#define yyv chill_v
+#define yy_yyv chill_yyv
+#define yyval chill_val
+#define yylloc chill_lloc
+#define yyreds chill_reds /* With YYDEBUG defined */
+#define yytoks chill_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ unsigned LONGEST ulval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%token <voidval> FIXME_01
+%token <voidval> FIXME_02
+%token <voidval> FIXME_03
+%token <voidval> FIXME_04
+%token <voidval> FIXME_05
+%token <voidval> FIXME_06
+%token <voidval> FIXME_07
+%token <voidval> FIXME_08
+%token <voidval> FIXME_09
+%token <voidval> FIXME_10
+%token <voidval> FIXME_11
+%token <voidval> FIXME_12
+%token <voidval> FIXME_13
+%token <voidval> FIXME_14
+%token <voidval> FIXME_15
+%token <voidval> FIXME_16
+%token <voidval> FIXME_17
+%token <voidval> FIXME_18
+%token <voidval> FIXME_19
+%token <voidval> FIXME_20
+%token <voidval> FIXME_21
+%token <voidval> FIXME_22
+%token <voidval> FIXME_24
+%token <voidval> FIXME_25
+%token <voidval> FIXME_26
+%token <voidval> FIXME_27
+%token <voidval> FIXME_28
+%token <voidval> FIXME_29
+%token <voidval> FIXME_30
+
+%token <typed_val> INTEGER_LITERAL
+%token <ulval> BOOLEAN_LITERAL
+%token <typed_val> CHARACTER_LITERAL
+%token <dval> FLOAT_LITERAL
+%token <ssym> GENERAL_PROCEDURE_NAME
+%token <ssym> LOCATION_NAME
+%token <voidval> SET_LITERAL
+%token <voidval> EMPTINESS_LITERAL
+%token <sval> CHARACTER_STRING_LITERAL
+%token <sval> BIT_STRING_LITERAL
+%token <tsym> TYPENAME
+%token <sval> FIELD_NAME
+
+%token <voidval> '.'
+%token <voidval> ';'
+%token <voidval> ':'
+%token <voidval> CASE
+%token <voidval> OF
+%token <voidval> ESAC
+%token <voidval> LOGIOR
+%token <voidval> ORIF
+%token <voidval> LOGXOR
+%token <voidval> LOGAND
+%token <voidval> ANDIF
+%token <voidval> '='
+%token <voidval> NOTEQUAL
+%token <voidval> '>'
+%token <voidval> GTR
+%token <voidval> '<'
+%token <voidval> LEQ
+%token <voidval> IN
+%token <voidval> '+'
+%token <voidval> '-'
+%token <voidval> '*'
+%token <voidval> '/'
+%token <voidval> SLASH_SLASH
+%token <voidval> MOD
+%token <voidval> REM
+%token <voidval> NOT
+%token <voidval> POINTER
+%token <voidval> RECEIVE
+%token <voidval> '['
+%token <voidval> ']'
+%token <voidval> '('
+%token <voidval> ')'
+%token <voidval> UP
+%token <voidval> IF
+%token <voidval> THEN
+%token <voidval> ELSE
+%token <voidval> FI
+%token <voidval> ELSIF
+%token <voidval> ILLEGAL_TOKEN
+%token <voidval> NUM
+%token <voidval> PRED
+%token <voidval> SUCC
+%token <voidval> ABS
+%token <voidval> CARD
+%token <voidval> MAX_TOKEN
+%token <voidval> MIN_TOKEN
+%token <voidval> SIZE
+%token <voidval> UPPER
+%token <voidval> LOWER
+%token <voidval> LENGTH
+
+/* Tokens which are not Chill tokens used in expressions, but rather GDB
+ specific things that we recognize in the same context as Chill tokens
+ (register names for example). */
+
+%token <lval> GDB_REGNAME /* Machine register name */
+%token <lval> GDB_LAST /* Value history */
+%token <ivar> GDB_VARIABLE /* Convenience variable */
+%token <voidval> GDB_ASSIGNMENT /* Assign value to somewhere */
+
+%type <voidval> location
+%type <voidval> access_name
+%type <voidval> primitive_value
+%type <voidval> location_contents
+%type <voidval> value_name
+%type <voidval> literal
+%type <voidval> tuple
+%type <voidval> value_string_element
+%type <voidval> value_string_slice
+%type <voidval> value_array_element
+%type <voidval> value_array_slice
+%type <voidval> value_structure_field
+%type <voidval> expression_conversion
+%type <voidval> value_procedure_call
+%type <voidval> value_built_in_routine_call
+%type <voidval> chill_value_built_in_routine_call
+%type <voidval> start_expression
+%type <voidval> zero_adic_operator
+%type <voidval> parenthesised_expression
+%type <voidval> value
+%type <voidval> undefined_value
+%type <voidval> expression
+%type <voidval> conditional_expression
+%type <voidval> then_alternative
+%type <voidval> else_alternative
+%type <voidval> sub_expression
+%type <voidval> value_case_alternative
+%type <voidval> operand_0
+%type <voidval> operand_1
+%type <voidval> operand_2
+%type <voidval> operand_3
+%type <voidval> operand_4
+%type <voidval> operand_5
+%type <voidval> operand_6
+%type <voidval> synonym_name
+%type <voidval> value_enumeration_name
+%type <voidval> value_do_with_name
+%type <voidval> value_receive_name
+%type <voidval> string_primitive_value
+%type <voidval> start_element
+%type <voidval> left_element
+%type <voidval> right_element
+%type <voidval> slice_size
+%type <voidval> array_primitive_value
+%type <voidval> expression_list
+%type <voidval> lower_element
+%type <voidval> upper_element
+%type <voidval> first_element
+%type <voidval> mode_argument
+%type <voidval> upper_lower_argument
+%type <voidval> length_argument
+%type <voidval> array_mode_name
+%type <voidval> string_mode_name
+%type <voidval> variant_structure_mode_name
+%type <voidval> boolean_expression
+%type <voidval> case_selector_list
+%type <voidval> subexpression
+%type <voidval> case_label_specification
+%type <voidval> buffer_location
+%type <voidval> single_assignment_action
+%type <tsym> mode_name
+
+%%
+
+/* Z.200, 5.3.1 */
+
+start : value { }
+ | mode_name
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1.type);
+ write_exp_elt_opcode(OP_TYPE);}
+ ;
+
+value : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | undefined_value
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+undefined_value : FIXME_01
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 4.2.1 */
+
+location : access_name
+ | primitive_value POINTER
+ {
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ ;
+
+/* Z.200, 4.2.2 */
+
+access_name : LOCATION_NAME
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ | GDB_LAST /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ($1);
+ write_exp_elt_opcode (OP_LAST);
+ }
+ | GDB_REGNAME /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ($1);
+ write_exp_elt_opcode (OP_REGISTER);
+ }
+ | GDB_VARIABLE /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ }
+ | FIXME_03
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 4.2.8 */
+
+expression_list : expression
+ {
+ arglist_len = 1;
+ }
+ | expression_list ',' expression
+ {
+ arglist_len++;
+ }
+
+/* Z.200, 5.2.1 */
+
+primitive_value : location_contents
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | literal
+ {
+ $$ = 0; /* FIXME */
+ }
+ | tuple
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_string_element
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_string_slice
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_array_element
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_array_slice
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_structure_field
+ {
+ $$ = 0; /* FIXME */
+ }
+ | expression_conversion
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_procedure_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_built_in_routine_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ | start_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | zero_adic_operator
+ {
+ $$ = 0; /* FIXME */
+ }
+ | parenthesised_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.2 */
+
+location_contents: location
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.3 */
+
+value_name : synonym_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_enumeration_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_do_with_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_receive_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | GENERAL_PROCEDURE_NAME
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ ;
+
+/* Z.200, 5.2.4.1 */
+
+literal : INTEGER_LITERAL
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST) ($1.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ | BOOLEAN_LITERAL
+ {
+ write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL);
+ }
+ | CHARACTER_LITERAL
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST) ($1.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ | FLOAT_LITERAL
+ {
+ write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE);
+ }
+ | SET_LITERAL
+ {
+ $$ = 0; /* FIXME */
+ }
+ | EMPTINESS_LITERAL
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CHARACTER_STRING_LITERAL
+ {
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_STRING);
+ }
+ | BIT_STRING_LITERAL
+ {
+ write_exp_elt_opcode (OP_BITSTRING);
+ write_exp_bitstring ($1);
+ write_exp_elt_opcode (OP_BITSTRING);
+ }
+ ;
+
+/* Z.200, 5.2.5 */
+
+tuple : FIXME_04
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 5.2.6 */
+
+value_string_element: string_primitive_value '(' start_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.7 */
+
+value_string_slice: string_primitive_value '(' left_element ':' right_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | string_primitive_value '(' start_element UP slice_size ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.8 */
+
+value_array_element: array_primitive_value '('
+ /* This is to save the value of arglist_len
+ being accumulated for each dimension. */
+ { start_arglist (); }
+ expression_list ')'
+ {
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ }
+ ;
+
+/* Z.200, 5.2.9 */
+
+value_array_slice: array_primitive_value '(' lower_element ':' upper_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | array_primitive_value '(' first_element UP slice_size ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.10 */
+
+value_structure_field: primitive_value FIELD_NAME
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($2);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ ;
+
+/* Z.200, 5.2.11 */
+
+expression_conversion: mode_name parenthesised_expression
+ {
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ ;
+
+/* Z.200, 5.2.12 */
+
+value_procedure_call: FIXME_05
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.13 */
+
+value_built_in_routine_call: chill_value_built_in_routine_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.14 */
+
+start_expression: FIXME_06
+ {
+ $$ = 0; /* FIXME */
+ } /* Not in GNU-Chill */
+ ;
+
+/* Z.200, 5.2.15 */
+
+zero_adic_operator: FIXME_07
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.16 */
+
+parenthesised_expression: '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.2 */
+
+expression : operand_0
+ {
+ $$ = 0; /* FIXME */
+ }
+ | single_assignment_action
+ {
+ $$ = 0; /* FIXME */
+ }
+ | conditional_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+conditional_expression : IF boolean_expression then_alternative else_alternative FI
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CASE case_selector_list OF value_case_alternative '[' ELSE sub_expression ']' ESAC
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+then_alternative: THEN subexpression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+else_alternative: ELSE subexpression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | ELSIF boolean_expression then_alternative else_alternative
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+sub_expression : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+value_case_alternative: case_label_specification ':' sub_expression ';'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.3 */
+
+operand_0 : operand_1
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_0 LOGIOR operand_1
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_IOR);
+ }
+ | operand_0 ORIF operand_1
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_0 LOGXOR operand_1
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_XOR);
+ }
+ ;
+
+/* Z.200, 5.3.4 */
+
+operand_1 : operand_2
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_1 LOGAND operand_2
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_AND);
+ }
+ | operand_1 ANDIF operand_2
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.5 */
+
+operand_2 : operand_3
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_2 '=' operand_3
+ {
+ write_exp_elt_opcode (BINOP_EQUAL);
+ }
+ | operand_2 NOTEQUAL operand_3
+ {
+ write_exp_elt_opcode (BINOP_NOTEQUAL);
+ }
+ | operand_2 '>' operand_3
+ {
+ write_exp_elt_opcode (BINOP_GTR);
+ }
+ | operand_2 GTR operand_3
+ {
+ write_exp_elt_opcode (BINOP_GEQ);
+ }
+ | operand_2 '<' operand_3
+ {
+ write_exp_elt_opcode (BINOP_LESS);
+ }
+ | operand_2 LEQ operand_3
+ {
+ write_exp_elt_opcode (BINOP_LEQ);
+ }
+ | operand_2 IN operand_3
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 5.3.6 */
+
+operand_3 : operand_4
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_3 '+' operand_4
+ {
+ write_exp_elt_opcode (BINOP_ADD);
+ }
+ | operand_3 '-' operand_4
+ {
+ write_exp_elt_opcode (BINOP_SUB);
+ }
+ | operand_3 SLASH_SLASH operand_4
+ {
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+ ;
+
+/* Z.200, 5.3.7 */
+
+operand_4 : operand_5
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_4 '*' operand_5
+ {
+ write_exp_elt_opcode (BINOP_MUL);
+ }
+ | operand_4 '/' operand_5
+ {
+ write_exp_elt_opcode (BINOP_DIV);
+ }
+ | operand_4 MOD operand_5
+ {
+ write_exp_elt_opcode (BINOP_MOD);
+ }
+ | operand_4 REM operand_5
+ {
+ write_exp_elt_opcode (BINOP_REM);
+ }
+ ;
+
+/* Z.200, 5.3.8 */
+
+operand_5 : operand_6
+ {
+ $$ = 0; /* FIXME */
+ }
+ | '-' operand_6
+ {
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+ | NOT operand_6
+ {
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ | parenthesised_expression literal
+/* We require the string operand to be a literal, to avoid some
+ nasty parsing ambiguities. */
+ {
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+ ;
+
+/* Z.200, 5.3.9 */
+
+operand_6 : POINTER location
+ {
+ write_exp_elt_opcode (UNOP_ADDR);
+ }
+ | RECEIVE buffer_location
+ {
+ $$ = 0; /* FIXME */
+ }
+ | primitive_value
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 6.2 */
+
+single_assignment_action :
+ location GDB_ASSIGNMENT value
+ {
+ write_exp_elt_opcode (BINOP_ASSIGN);
+ }
+ ;
+
+/* Z.200, 6.20.3 */
+
+chill_value_built_in_routine_call :
+ NUM '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | PRED '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SUCC '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | ABS '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CARD '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | MAX_TOKEN '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | MIN_TOKEN '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SIZE '(' location ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SIZE '(' mode_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | UPPER '(' upper_lower_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | LOWER '(' upper_lower_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | LENGTH '(' length_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+mode_argument : mode_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | array_mode_name '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | string_mode_name '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | variant_structure_mode_name '(' expression_list ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+mode_name : TYPENAME
+ ;
+
+upper_lower_argument : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | mode_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+length_argument : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 12.4.3 */
+
+array_primitive_value : primitive_value
+ {
+ $$ = 0;
+ }
+ ;
+
+
+/* Things which still need productions... */
+
+array_mode_name : FIXME_08 { $$ = 0; }
+string_mode_name : FIXME_09 { $$ = 0; }
+variant_structure_mode_name: FIXME_10 { $$ = 0; }
+synonym_name : FIXME_11 { $$ = 0; }
+value_enumeration_name : FIXME_12 { $$ = 0; }
+value_do_with_name : FIXME_13 { $$ = 0; }
+value_receive_name : FIXME_14 { $$ = 0; }
+string_primitive_value : FIXME_15 { $$ = 0; }
+start_element : FIXME_16 { $$ = 0; }
+left_element : FIXME_17 { $$ = 0; }
+right_element : FIXME_18 { $$ = 0; }
+slice_size : FIXME_19 { $$ = 0; }
+lower_element : FIXME_20 { $$ = 0; }
+upper_element : FIXME_21 { $$ = 0; }
+first_element : FIXME_22 { $$ = 0; }
+boolean_expression : FIXME_26 { $$ = 0; }
+case_selector_list : FIXME_27 { $$ = 0; }
+subexpression : FIXME_28 { $$ = 0; }
+case_label_specification: FIXME_29 { $$ = 0; }
+buffer_location : FIXME_30 { $$ = 0; }
+
+%%
+
+/* Implementation of a dynamically expandable buffer for processing input
+ characters acquired through lexptr and building a value to return in
+ yylval. */
+
+static char *tempbuf; /* Current buffer contents */
+static int tempbufsize; /* Size of allocated buffer */
+static int tempbufindex; /* Current index into buffer */
+
+#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */
+
+#define CHECKBUF(size) \
+ do { \
+ if (tempbufindex + (size) >= tempbufsize) \
+ { \
+ growbuf_by_size (size); \
+ } \
+ } while (0);
+
+/* Grow the static temp buffer if necessary, including allocating the first one
+ on demand. */
+
+static void
+growbuf_by_size (count)
+ int count;
+{
+ int growby;
+
+ growby = max (count, GROWBY_MIN_SIZE);
+ tempbufsize += growby;
+ if (tempbuf == NULL)
+ {
+ tempbuf = (char *) malloc (tempbufsize);
+ }
+ else
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize);
+ }
+}
+
+/* Try to consume a simple name string token. If successful, returns
+ a pointer to a nullbyte terminated copy of the name that can be used
+ in symbol table lookups. If not successful, returns NULL. */
+
+static char *
+match_simple_name_string ()
+{
+ char *tokptr = lexptr;
+
+ if (isalpha (*tokptr))
+ {
+ char *result;
+ do {
+ tokptr++;
+ } while (isalnum (*tokptr) || (*tokptr == '_'));
+ yylval.sval.ptr = lexptr;
+ yylval.sval.length = tokptr - lexptr;
+ lexptr = tokptr;
+ result = copy_name (yylval.sval);
+ for (tokptr = result; *tokptr; tokptr++)
+ if (isupper (*tokptr))
+ *tokptr = tolower(*tokptr);
+ return result;
+ }
+ return (NULL);
+}
+
+/* Start looking for a value composed of valid digits as set by the base
+ in use. Note that '_' characters are valid anywhere, in any quantity,
+ and are simply ignored. Since we must find at least one valid digit,
+ or reject this token as an integer literal, we keep track of how many
+ digits we have encountered. */
+
+static int
+decode_integer_value (base, tokptrptr, ivalptr)
+ int base;
+ char **tokptrptr;
+ int *ivalptr;
+{
+ char *tokptr = *tokptrptr;
+ int temp;
+ int digits = 0;
+
+ while (*tokptr != '\0')
+ {
+ temp = tolower (*tokptr);
+ tokptr++;
+ switch (temp)
+ {
+ case '_':
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ temp -= '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ temp -= 'a';
+ temp += 10;
+ break;
+ default:
+ temp = base;
+ break;
+ }
+ if (temp < base)
+ {
+ digits++;
+ *ivalptr *= base;
+ *ivalptr += temp;
+ }
+ else
+ {
+ /* Found something not in domain for current base. */
+ tokptr--; /* Unconsume what gave us indigestion. */
+ break;
+ }
+ }
+
+ /* If we didn't find any digits, then we don't have a valid integer
+ value, so reject the entire token. Otherwise, update the lexical
+ scan pointer, and return non-zero for success. */
+
+ if (digits == 0)
+ {
+ return (0);
+ }
+ else
+ {
+ *tokptrptr = tokptr;
+ return (1);
+ }
+}
+
+static int
+decode_integer_literal (valptr, tokptrptr)
+ int *valptr;
+ char **tokptrptr;
+{
+ char *tokptr = *tokptrptr;
+ int base = 0;
+ int ival = 0;
+ int explicit_base = 0;
+
+ /* Look for an explicit base specifier, which is optional. */
+
+ switch (*tokptr)
+ {
+ case 'd':
+ case 'D':
+ explicit_base++;
+ base = 10;
+ tokptr++;
+ break;
+ case 'b':
+ case 'B':
+ explicit_base++;
+ base = 2;
+ tokptr++;
+ break;
+ case 'h':
+ case 'H':
+ explicit_base++;
+ base = 16;
+ tokptr++;
+ break;
+ case 'o':
+ case 'O':
+ explicit_base++;
+ base = 8;
+ tokptr++;
+ break;
+ default:
+ base = 10;
+ break;
+ }
+
+ /* If we found an explicit base ensure that the character after the
+ explicit base is a single quote. */
+
+ if (explicit_base && (*tokptr++ != '\''))
+ {
+ return (0);
+ }
+
+ /* Attempt to decode whatever follows as an integer value in the
+ indicated base, updating the token pointer in the process and
+ computing the value into ival. Also, if we have an explicit
+ base, then the next character must not be a single quote, or we
+ have a bitstring literal, so reject the entire token in this case.
+ Otherwise, update the lexical scan pointer, and return non-zero
+ for success. */
+
+ if (!decode_integer_value (base, &tokptr, &ival))
+ {
+ return (0);
+ }
+ else if (explicit_base && (*tokptr == '\''))
+ {
+ return (0);
+ }
+ else
+ {
+ *valptr = ival;
+ *tokptrptr = tokptr;
+ return (1);
+ }
+}
+
+/* If it wasn't for the fact that floating point values can contain '_'
+ characters, we could just let strtod do all the hard work by letting it
+ try to consume as much of the current token buffer as possible and
+ find a legal conversion. Unfortunately we need to filter out the '_'
+ characters before calling strtod, which we do by copying the other
+ legal chars to a local buffer to be converted. However since we also
+ need to keep track of where the last unconsumed character in the input
+ buffer is, we have transfer only as many characters as may compose a
+ legal floating point value. */
+
+static int
+match_float_literal ()
+{
+ char *tokptr = lexptr;
+ char *buf;
+ char *copy;
+ double dval;
+ extern double strtod ();
+
+ /* Make local buffer in which to build the string to convert. This is
+ required because underscores are valid in chill floating point numbers
+ but not in the string passed to strtod to convert. The string will be
+ no longer than our input string. */
+
+ copy = buf = (char *) alloca (strlen (tokptr) + 1);
+
+ /* Transfer all leading digits to the conversion buffer, discarding any
+ underscores. */
+
+ while (isdigit (*tokptr) || *tokptr == '_')
+ {
+ if (*tokptr != '_')
+ {
+ *copy++ = *tokptr;
+ }
+ tokptr++;
+ }
+
+ /* Now accept either a '.', or one of [eEdD]. Dot is legal regardless
+ of whether we found any leading digits, and we simply accept it and
+ continue on to look for the fractional part and/or exponent. One of
+ [eEdD] is legal only if we have seen digits, and means that there
+ is no fractional part. If we find neither of these, then this is
+ not a floating point number, so return failure. */
+
+ switch (*tokptr++)
+ {
+ case '.':
+ /* Accept and then look for fractional part and/or exponent. */
+ *copy++ = '.';
+ break;
+
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ if (copy == buf)
+ {
+ return (0);
+ }
+ *copy++ = 'e';
+ goto collect_exponent;
+ break;
+
+ default:
+ return (0);
+ break;
+ }
+
+ /* We found a '.', copy any fractional digits to the conversion buffer, up
+ to the first nondigit, non-underscore character. */
+
+ while (isdigit (*tokptr) || *tokptr == '_')
+ {
+ if (*tokptr != '_')
+ {
+ *copy++ = *tokptr;
+ }
+ tokptr++;
+ }
+
+ /* Look for an exponent, which must start with one of [eEdD]. If none
+ is found, jump directly to trying to convert what we have collected
+ so far. */
+
+ switch (*tokptr)
+ {
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ *copy++ = 'e';
+ tokptr++;
+ break;
+ default:
+ goto convert_float;
+ break;
+ }
+
+ /* Accept an optional '-' or '+' following one of [eEdD]. */
+
+ collect_exponent:
+ if (*tokptr == '+' || *tokptr == '-')
+ {
+ *copy++ = *tokptr++;
+ }
+
+ /* Now copy an exponent into the conversion buffer. Note that at the
+ moment underscores are *not* allowed in exponents. */
+
+ while (isdigit (*tokptr))
+ {
+ *copy++ = *tokptr++;
+ }
+
+ /* If we transfered any chars to the conversion buffer, try to interpret its
+ contents as a floating point value. If any characters remain, then we
+ must not have a valid floating point string. */
+
+ convert_float:
+ *copy = '\0';
+ if (copy != buf)
+ {
+ dval = strtod (buf, &copy);
+ if (*copy == '\0')
+ {
+ yylval.dval = dval;
+ lexptr = tokptr;
+ return (FLOAT_LITERAL);
+ }
+ }
+ return (0);
+}
+
+/* Recognize a string literal. A string literal is a nonzero sequence
+ of characters enclosed in matching single or double quotes, except that
+ a single character inside single quotes is a character literal, which
+ we reject as a string literal. To embed the terminator character inside
+ a string, it is simply doubled (I.E. "this""is""one""string") */
+
+static int
+match_string_literal ()
+{
+ char *tokptr = lexptr;
+
+ for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++)
+ {
+ CHECKBUF (1);
+ if (*tokptr == *lexptr)
+ {
+ if (*(tokptr + 1) == *lexptr)
+ {
+ tokptr++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ tempbuf[tempbufindex++] = *tokptr;
+ }
+ if (*tokptr == '\0' /* no terminator */
+ || tempbufindex == 0 /* no string */
+ || (tempbufindex == 1 && *tokptr == '\'')) /* char literal */
+ {
+ return (0);
+ }
+ else
+ {
+ tempbuf[tempbufindex] = '\0';
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = ++tokptr;
+ return (CHARACTER_STRING_LITERAL);
+ }
+}
+
+/* Recognize a character literal. A character literal is single character
+ or a control sequence, enclosed in single quotes. A control sequence
+ is a comma separated list of one or more integer literals, enclosed
+ in parenthesis and introduced with a circumflex character.
+
+ EX: 'a' '^(7)' '^(7,8)'
+
+ As a GNU chill extension, the syntax C'xx' is also recognized as a
+ character literal, where xx is a hex value for the character.
+
+ Note that more than a single character, enclosed in single quotes, is
+ a string literal.
+
+ Also note that the control sequence form is not in GNU Chill since it
+ is ambiguous with the string literal form using single quotes. I.E.
+ is '^(7)' a character literal or a string literal. In theory it it
+ possible to tell by context, but GNU Chill doesn't accept the control
+ sequence form, so neither do we (for now the code is disabled).
+
+ Returns CHARACTER_LITERAL if a match is found.
+ */
+
+static int
+match_character_literal ()
+{
+ char *tokptr = lexptr;
+ int ival = 0;
+
+ if ((tolower (*tokptr) == 'c') && (*(tokptr + 1) == '\''))
+ {
+ /* We have a GNU chill extension form, so skip the leading "C'",
+ decode the hex value, and then ensure that we have a trailing
+ single quote character. */
+ tokptr += 2;
+ if (!decode_integer_value (16, &tokptr, &ival) || (*tokptr != '\''))
+ {
+ return (0);
+ }
+ tokptr++;
+ }
+ else if (*tokptr == '\'')
+ {
+ tokptr++;
+
+ /* Determine which form we have, either a control sequence or the
+ single character form. */
+
+ if ((*tokptr == '^') && (*(tokptr + 1) == '('))
+ {
+#if 0 /* Disable, see note above. -fnf */
+ /* Match and decode a control sequence. Return zero if we don't
+ find a valid integer literal, or if the next unconsumed character
+ after the integer literal is not the trailing ')'.
+ FIXME: We currently don't handle the multiple integer literal
+ form. */
+ tokptr += 2;
+ if (!decode_integer_literal (&ival, &tokptr) || (*tokptr++ != ')'))
+ {
+ return (0);
+ }
+#else
+ return (0);
+#endif
+ }
+ else
+ {
+ ival = *tokptr++;
+ }
+
+ /* The trailing quote has not yet been consumed. If we don't find
+ it, then we have no match. */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ /* Not a character literal. */
+ return (0);
+ }
+ yylval.typed_val.val = ival;
+ yylval.typed_val.type = builtin_type_chill_char;
+ lexptr = tokptr;
+ return (CHARACTER_LITERAL);
+}
+
+/* Recognize an integer literal, as specified in Z.200 sec 5.2.4.2.
+ Note that according to 5.2.4.2, a single "_" is also a valid integer
+ literal, however GNU-chill requires there to be at least one "digit"
+ in any integer literal. */
+
+static int
+match_integer_literal ()
+{
+ char *tokptr = lexptr;
+ int ival;
+
+ if (!decode_integer_literal (&ival, &tokptr))
+ {
+ return (0);
+ }
+ else
+ {
+ yylval.typed_val.val = ival;
+ yylval.typed_val.type = builtin_type_int;
+ lexptr = tokptr;
+ return (INTEGER_LITERAL);
+ }
+}
+
+/* Recognize a bit-string literal, as specified in Z.200 sec 5.2.4.8
+ Note that according to 5.2.4.8, a single "_" is also a valid bit-string
+ literal, however GNU-chill requires there to be at least one "digit"
+ in any bit-string literal. */
+
+static int
+match_bitstring_literal ()
+{
+ char *tokptr = lexptr;
+ int mask;
+ int bitoffset = 0;
+ int bitcount = 0;
+ int base;
+ int digit;
+
+ tempbufindex = 0;
+
+ /* Look for the required explicit base specifier. */
+
+ switch (*tokptr++)
+ {
+ case 'b':
+ case 'B':
+ base = 2;
+ break;
+ case 'o':
+ case 'O':
+ base = 8;
+ break;
+ case 'h':
+ case 'H':
+ base = 16;
+ break;
+ default:
+ return (0);
+ break;
+ }
+
+ /* Ensure that the character after the explicit base is a single quote. */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+
+ while (*tokptr != '\0' && *tokptr != '\'')
+ {
+ digit = tolower (*tokptr);
+ tokptr++;
+ switch (digit)
+ {
+ case '_':
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ digit -= '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ digit -= 'a';
+ digit += 10;
+ break;
+ default:
+ return (0);
+ break;
+ }
+ if (digit >= base)
+ {
+ /* Found something not in domain for current base. */
+ return (0);
+ }
+ else
+ {
+ /* Extract bits from digit, starting with the msbit appropriate for
+ the current base, and packing them into the bitstring byte,
+ starting at the lsbit. */
+ for (mask = (base >> 1); mask > 0; mask >>= 1)
+ {
+ bitcount++;
+ CHECKBUF (1);
+ if (digit & mask)
+ {
+ tempbuf[tempbufindex] |= (1 << bitoffset);
+ }
+ bitoffset++;
+ if (bitoffset == HOST_CHAR_BIT)
+ {
+ bitoffset = 0;
+ tempbufindex++;
+ }
+ }
+ }
+ }
+
+ /* Verify that we consumed everything up to the trailing single quote,
+ and that we found some bits (IE not just underbars). */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+ else
+ {
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = bitcount;
+ lexptr = tokptr;
+ return (BIT_STRING_LITERAL);
+ }
+}
+
+/* Recognize tokens that start with '$'. These include:
+
+ $regname A native register name or a "standard
+ register name".
+ Return token GDB_REGNAME.
+
+ $variable A convenience variable with a name chosen
+ by the user.
+ Return token GDB_VARIABLE.
+
+ $digits Value history with index <digits>, starting
+ from the first value which has index 1.
+ Return GDB_LAST.
+
+ $$digits Value history with index <digits> relative
+ to the last value. I.E. $$0 is the last
+ value, $$1 is the one previous to that, $$2
+ is the one previous to $$1, etc.
+ Return token GDB_LAST.
+
+ $ | $0 | $$0 The last value in the value history.
+ Return token GDB_LAST.
+
+ $$ An abbreviation for the second to the last
+ value in the value history, I.E. $$1
+ Return token GDB_LAST.
+
+ Note that we currently assume that register names and convenience
+ variables follow the convention of starting with a letter or '_'.
+
+ */
+
+static int
+match_dollar_tokens ()
+{
+ char *tokptr;
+ int regno;
+ int namelength;
+ int negate;
+ int ival;
+
+ /* We will always have a successful match, even if it is just for
+ a single '$', the abbreviation for $$0. So advance lexptr. */
+
+ tokptr = ++lexptr;
+
+ if (*tokptr == '_' || isalpha (*tokptr))
+ {
+ /* Look for a match with a native register name, usually something
+ like "r0" for example. */
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ namelength = strlen (reg_names[regno]);
+ if (STREQN (tokptr, reg_names[regno], namelength)
+ && !isalnum (tokptr[namelength]))
+ {
+ yylval.lval = regno;
+ lexptr += namelength + 1;
+ return (GDB_REGNAME);
+ }
+ }
+
+ /* Look for a match with a standard register name, usually something
+ like "pc", which gdb always recognizes as the program counter
+ regardless of what the native register name is. */
+
+ for (regno = 0; regno < num_std_regs; regno++)
+ {
+ namelength = strlen (std_regs[regno].name);
+ if (STREQN (tokptr, std_regs[regno].name, namelength)
+ && !isalnum (tokptr[namelength]))
+ {
+ yylval.lval = std_regs[regno].regnum;
+ lexptr += namelength;
+ return (GDB_REGNAME);
+ }
+ }
+
+ /* Attempt to match against a convenience variable. Note that
+ this will always succeed, because if no variable of that name
+ already exists, the lookup_internalvar will create one for us.
+ Also note that both lexptr and tokptr currently point to the
+ start of the input string we are trying to match, and that we
+ have already tested the first character for non-numeric, so we
+ don't have to treat it specially. */
+
+ while (*tokptr == '_' || isalnum (*tokptr))
+ {
+ tokptr++;
+ }
+ yylval.sval.ptr = lexptr;
+ yylval.sval.length = tokptr - lexptr;
+ yylval.ivar = lookup_internalvar (copy_name (yylval.sval));
+ lexptr = tokptr;
+ return (GDB_VARIABLE);
+ }
+
+ /* Since we didn't match against a register name or convenience
+ variable, our only choice left is a history value. */
+
+ if (*tokptr == '$')
+ {
+ negate = 1;
+ ival = 1;
+ tokptr++;
+ }
+ else
+ {
+ negate = 0;
+ ival = 0;
+ }
+
+ /* Attempt to decode more characters as an integer value giving
+ the index in the history list. If successful, the value will
+ overwrite ival (currently 0 or 1), and if not, ival will be
+ left alone, which is good since it is currently correct for
+ the '$' or '$$' case. */
+
+ decode_integer_literal (&ival, &tokptr);
+ yylval.lval = negate ? -ival : ival;
+ lexptr = tokptr;
+ return (GDB_LAST);
+}
+
+struct token
+{
+ char *operator;
+ int token;
+};
+
+static const struct token idtokentab[] =
+{
+ { "length", LENGTH },
+ { "lower", LOWER },
+ { "upper", UPPER },
+ { "andif", ANDIF },
+ { "pred", PRED },
+ { "succ", SUCC },
+ { "card", CARD },
+ { "size", SIZE },
+ { "orif", ORIF },
+ { "num", NUM },
+ { "abs", ABS },
+ { "max", MAX_TOKEN },
+ { "min", MIN_TOKEN },
+ { "mod", MOD },
+ { "rem", REM },
+ { "not", NOT },
+ { "xor", LOGXOR },
+ { "and", LOGAND },
+ { "in", IN },
+ { "or", LOGIOR }
+};
+
+static const struct token tokentab2[] =
+{
+ { ":=", GDB_ASSIGNMENT },
+ { "//", SLASH_SLASH },
+ { "->", POINTER },
+ { "/=", NOTEQUAL },
+ { "<=", LEQ },
+ { ">=", GTR }
+};
+
+/* Read one token, getting characters through lexptr. */
+/* This is where we will check to make sure that the language and the
+ operators used are compatible. */
+
+static int
+yylex ()
+{
+ unsigned int i;
+ int token;
+ char *simplename;
+ struct symbol *sym;
+
+ /* Skip over any leading whitespace. */
+ while (isspace (*lexptr))
+ {
+ lexptr++;
+ }
+ /* Look for special single character cases which can't be the first
+ character of some other multicharacter token. */
+ switch (*lexptr)
+ {
+ case '\0':
+ return (0);
+ case ',':
+ case '=':
+ case ';':
+ case '!':
+ case '+':
+ case '*':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ return (*lexptr++);
+ }
+ /* Look for characters which start a particular kind of multicharacter
+ token, such as a character literal, register name, convenience
+ variable name, string literal, etc. */
+ switch (*lexptr)
+ {
+ case '\'':
+ case '\"':
+ /* First try to match a string literal, which is any nonzero
+ sequence of characters enclosed in matching single or double
+ quotes, except that a single character inside single quotes
+ is a character literal, so we have to catch that case also. */
+ token = match_string_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ if (*lexptr == '\'')
+ {
+ token = match_character_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ }
+ break;
+ case 'C':
+ case 'c':
+ token = match_character_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ break;
+ case '$':
+ token = match_dollar_tokens ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ break;
+ }
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++)
+ {
+ if (STREQN (lexptr, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ return (tokentab2[i].token);
+ }
+ }
+ /* Look for single character cases which which could be the first
+ character of some other multicharacter token, but aren't, or we
+ would already have found it. */
+ switch (*lexptr)
+ {
+ case '-':
+ case ':':
+ case '/':
+ case '<':
+ case '>':
+ return (*lexptr++);
+ }
+ /* Look for a float literal before looking for an integer literal, so
+ we match as much of the input stream as possible. */
+ token = match_float_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ token = match_bitstring_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ token = match_integer_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+
+ /* Try to match a simple name string, and if a match is found, then
+ further classify what sort of name it is and return an appropriate
+ token. Note that attempting to match a simple name string consumes
+ the token from lexptr, so we can't back out if we later find that
+ we can't classify what sort of name it is. */
+
+ simplename = match_simple_name_string ();
+
+ if (simplename != NULL)
+ {
+ /* See if it is a reserved identifier. */
+ for (i = 0; i < sizeof (idtokentab) / sizeof (idtokentab[0]); i++)
+ {
+ if (STREQ (simplename, idtokentab[i].operator))
+ {
+ return (idtokentab[i].token);
+ }
+ }
+
+ /* Look for other special tokens. */
+ if (STREQ (simplename, "true"))
+ {
+ yylval.ulval = 1;
+ return (BOOLEAN_LITERAL);
+ }
+ if (STREQ (simplename, "false"))
+ {
+ yylval.ulval = 0;
+ return (BOOLEAN_LITERAL);
+ }
+
+ sym = lookup_symbol (simplename, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym != NULL)
+ {
+ yylval.ssym.stoken.ptr = NULL;
+ yylval.ssym.stoken.length = 0;
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = 0; /* FIXME, C++'ism */
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_BLOCK:
+ /* Found a procedure name. */
+ return (GENERAL_PROCEDURE_NAME);
+ case LOC_STATIC:
+ /* Found a global or local static variable. */
+ return (LOCATION_NAME);
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ if (innermost_block == NULL
+ || contained_in (block_found, innermost_block))
+ {
+ innermost_block = block_found;
+ }
+ return (LOCATION_NAME);
+ break;
+ case LOC_CONST:
+ case LOC_LABEL:
+ return (LOCATION_NAME);
+ break;
+ case LOC_TYPEDEF:
+ yylval.tsym.type = SYMBOL_TYPE (sym);
+ return TYPENAME;
+ case LOC_UNDEF:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ error ("Symbol \"%s\" names no location.", simplename);
+ break;
+ }
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ {
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ }
+ else
+ {
+ error ("No symbol \"%s\" in current context.", simplename);
+ }
+ }
+
+ /* Catch single character tokens which are not part of some
+ longer token. */
+
+ switch (*lexptr)
+ {
+ case '.': /* Not float for example. */
+ lexptr++;
+ while (isspace (*lexptr)) lexptr++;
+ simplename = match_simple_name_string ();
+ if (!simplename)
+ return '.';
+ return FIELD_NAME;
+ }
+
+ return (ILLEGAL_TOKEN);
+}
+
+void
+yyerror (msg)
+ char *msg; /* unused */
+{
+ printf ("Parsing: %s\n", lexptr);
+ if (yychar < 256)
+ {
+ error ("Invalid syntax in expression near character '%c'.", yychar);
+ }
+ else
+ {
+ error ("Invalid syntax in expression");
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.c b/gnu/usr.bin/gdb/gdb/ch-lang.c
new file mode 100644
index 000000000000..2f7406103d0c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.c
@@ -0,0 +1,341 @@
+/* Chill language support routines for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ch-lang.h"
+
+
+/* For now, Chill uses a simple mangling algorithm whereby you simply
+ discard everything after the occurance of two successive CPLUS_MARKER
+ characters to derive the demangled form. */
+
+char *
+chill_demangle (mangled)
+ const char *mangled;
+{
+ char *joiner;
+ char *demangled;
+
+ joiner = strchr (mangled, CPLUS_MARKER);
+ if (joiner != NULL && *(joiner + 1) == CPLUS_MARKER)
+ {
+ demangled = savestring (mangled, joiner - mangled);
+ }
+ else
+ {
+ demangled = NULL;
+ }
+ return (demangled);
+}
+
+static void
+chill_printchar (c, stream)
+ register int c;
+ FILE *stream;
+{
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ fprintf_filtered (stream, "'%c'", c);
+ }
+ else
+ {
+ fprintf_filtered (stream, "C'%.2x'", (unsigned int) c);
+ }
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ Note that gdb maintains the length of strings without counting the
+ terminating null byte, while chill strings are typically written with
+ an explicit null byte. So we always assume an implied null byte
+ until gdb is able to maintain non-null terminated strings as well
+ as null terminated strings (FIXME).
+ */
+
+static void
+chill_printstr (stream, string, length, force_ellipses)
+ FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_literal_form = 0;
+ int in_control_form = 0;
+ int need_slashslash = 0;
+ unsigned int c;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ if (length == 0)
+ {
+ chill_printchar ('\0', stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_slashslash)
+ {
+ fputs_filtered ("//", stream);
+ need_slashslash = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ c = string[i];
+ if (reps > repeat_count_threshold)
+ {
+ if (in_control_form || in_literal_form)
+ {
+ fputs_filtered ("'//", stream);
+ in_control_form = in_literal_form = 0;
+ }
+ chill_printchar (c, stream);
+ fprintf_filtered (stream, "<repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_slashslash = 1;
+ }
+ else
+ {
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (!in_literal_form)
+ {
+ if (in_control_form)
+ {
+ fputs_filtered ("'//", stream);
+ in_control_form = 0;
+ }
+ fputs_filtered ("'", stream);
+ in_literal_form = 1;
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ if (!in_control_form)
+ {
+ if (in_literal_form)
+ {
+ fputs_filtered ("'//", stream);
+ in_literal_form = 0;
+ }
+ fputs_filtered ("c'", stream);
+ in_control_form = 1;
+ }
+ fprintf_filtered (stream, "%.2x", c);
+ }
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_literal_form || in_control_form)
+ {
+ fputs_filtered ("'", stream);
+ }
+ if (force_ellipses || (i < length))
+ {
+ fputs_filtered ("...", stream);
+ }
+}
+
+static struct type *
+chill_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT, 2, 0, "<?type?>", objfile);
+ warning ("internal error: no chill fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ /* FIXME: Currently the GNU Chill compiler emits some DWARF entries for
+ typedefs, unrelated to anything directly in the code being compiled,
+ that have some FT_VOID types. Just fake it for now. */
+ type = init_type (TYPE_CODE_VOID, 0, 0, "<?VOID?>", objfile);
+ break;
+ case FT_BOOLEAN:
+ type = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, "BOOL", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, "CHAR", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_SIGNED, "BYTE", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, "UBYTE", objfile);
+ break;
+ case FT_SHORT: /* Chill ints are 2 bytes */
+ type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_SIGNED, "INT", objfile);
+ break;
+ case FT_UNSIGNED_SHORT: /* Chill ints are 2 bytes */
+ type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, "UINT", objfile);
+ break;
+ case FT_INTEGER: /* FIXME? */
+ case FT_SIGNED_INTEGER: /* FIXME? */
+ case FT_LONG: /* Chill longs are 4 bytes */
+ case FT_SIGNED_LONG: /* Chill longs are 4 bytes */
+ type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_SIGNED, "LONG", objfile);
+ break;
+ case FT_UNSIGNED_INTEGER: /* FIXME? */
+ case FT_UNSIGNED_LONG: /* Chill longs are 4 bytes */
+ type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, "ULONG", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT, 4, 0, "REAL", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT, 8, 0, "LONG_REAL", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table of operators and their precedences for printing expressions. */
+
+static const struct op_print chill_op_print_tab[] = {
+ {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"MOD", BINOP_MOD, PREC_MUL, 0},
+ {"REM", BINOP_REM, PREC_MUL, 0},
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"=", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"//", BINOP_CONCAT, PREC_PREFIX, 0}, /* FIXME: precedence? */
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+
+/* The built-in types of Chill. */
+
+struct type *builtin_type_chill_bool;
+struct type *builtin_type_chill_char;
+struct type *builtin_type_chill_long;
+struct type *builtin_type_chill_ulong;
+struct type *builtin_type_chill_real;
+
+struct type ** const (chill_builtin_types[]) =
+{
+ &builtin_type_chill_bool,
+ &builtin_type_chill_char,
+ &builtin_type_chill_long,
+ &builtin_type_chill_ulong,
+ &builtin_type_chill_real,
+ 0
+};
+
+const struct language_defn chill_language_defn = {
+ "chill",
+ language_chill,
+ chill_builtin_types,
+ range_check_on,
+ type_check_on,
+ chill_parse, /* parser */
+ chill_error, /* parser error function */
+ chill_printchar, /* print a character constant */
+ chill_printstr, /* function to print a string constant */
+ chill_create_fundamental_type,/* Create fundamental type in this language */
+ chill_print_type, /* Print a type using appropriate syntax */
+ chill_val_print, /* Print a value using appropriate syntax */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &builtin_type_chill_real, /* longest floating point type */
+ {"", "B'", "", ""}, /* Binary format info */
+ {"O'%lo", "O'", "o", ""}, /* Octal format info */
+ {"D'%ld", "D'", "d", ""}, /* Decimal format info */
+ {"H'%lx", "H'", "x", ""}, /* Hex format info */
+ chill_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialization for Chill */
+
+void
+_initialize_chill_language ()
+{
+ builtin_type_chill_bool =
+ init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "BOOL", (struct objfile *) NULL);
+ builtin_type_chill_char =
+ init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CHAR", (struct objfile *) NULL);
+ builtin_type_chill_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "LONG", (struct objfile *) NULL);
+ builtin_type_chill_ulong =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "ULONG", (struct objfile *) NULL);
+ builtin_type_chill_real =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "LONG_REAL", (struct objfile *) NULL);
+
+ add_language (&chill_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.h b/gnu/usr.bin/gdb/gdb/ch-lang.h
new file mode 100644
index 000000000000..13579d9d47cb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.h
@@ -0,0 +1,31 @@
+/* Chill language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern int
+chill_parse PARAMS ((void)); /* Defined in ch-exp.y */
+
+extern void
+chill_error PARAMS ((char *)); /* Defined in ch-exp.y */
+
+extern void /* Defined in ch-typeprint.c */
+chill_print_type PARAMS ((struct type *, char *, FILE *, int, int));
+
+extern int
+chill_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ int, enum val_prettyprint));
diff --git a/gnu/usr.bin/gdb/gdb/ch-typeprint.c b/gnu/usr.bin/gdb/gdb/ch-typeprint.c
new file mode 100644
index 000000000000..c3cdcd2a1885
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-typeprint.c
@@ -0,0 +1,225 @@
+/* Support for printing Chill types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "ch-lang.h"
+
+#include <string.h>
+#include <errno.h>
+
+static void
+chill_type_print_base PARAMS ((struct type *, FILE *, int, int));
+
+void
+chill_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ if (varstring != NULL && *varstring != '\0')
+ {
+ fputs_filtered (varstring, stream);
+ fputs_filtered (" ", stream);
+ }
+ chill_type_print_base (type, stream, show, level);
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element).
+
+ SHOW nonzero means don't print this type as just its name;
+ show its real definition even if it has a name.
+ SHOW zero means print just typename or tag if there is one
+ SHOW negative means abbreviate structure elements.
+ SHOW is decremented for printing of structure elements.
+
+ LEVEL is the depth to indent by.
+ We increase it for some recursive calls. */
+
+static void
+chill_type_print_base (type, stream, show, level)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int level;
+{
+ char *name;
+ register int len;
+ register int i;
+ struct type *index_type;
+ struct type *range_type;
+ LONGEST low_bound;
+ LONGEST high_bound;
+
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", stream);
+ return;
+ }
+
+ /* When SHOW is zero or less, and there is a valid type name, then always
+ just print the type name directly from the type. */
+
+ if ((show <= 0) && (TYPE_NAME (type) != NULL))
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, "PTR");
+ break;
+ }
+ fprintf_filtered (stream, "REF ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_ARRAY:
+ range_type = TYPE_FIELD_TYPE (type, 0);
+ index_type = TYPE_TARGET_TYPE (range_type);
+ low_bound = TYPE_FIELD_BITPOS (range_type, 0);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ fputs_filtered ("ARRAY (", stream);
+ print_type_scalar (index_type, low_bound, stream);
+ fputs_filtered (":", stream);
+ print_type_scalar (index_type, high_bound, stream);
+ fputs_filtered (") ", stream);
+ chill_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
+ break;
+
+ case TYPE_CODE_STRING:
+ range_type = TYPE_FIELD_TYPE (type, 0);
+ index_type = TYPE_TARGET_TYPE (range_type);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ fputs_filtered ("CHAR (", stream);
+ print_type_scalar (index_type, high_bound + 1, stream);
+ fputs_filtered (")", stream);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ fprintf_filtered (stream, "MEMBER ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+ case TYPE_CODE_REF:
+ fprintf_filtered (stream, "/*LOC*/ ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+ case TYPE_CODE_FUNC:
+ fprintf_filtered (stream, "PROC (?)");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ fprintf_filtered (stream, "STRUCT ");
+ if ((name = type_name_no_tag (type)) != NULL)
+ {
+ fputs_filtered (name, stream);
+ fputs_filtered (" ", stream);
+ wrap_here (" ");
+ }
+ if (show < 0)
+ {
+ fprintf_filtered (stream, "(...)");
+ }
+ else
+ {
+ check_stub_type (type);
+ fprintf_filtered (stream, "(\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ }
+ else
+ {
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+ }
+ else
+ {
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ print_spaces_filtered (level + 4, stream);
+ chill_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ if (i < (len - 1))
+ {
+ fputs_filtered (",", stream);
+ }
+ fputs_filtered ("\n", stream);
+ }
+ }
+ fprintfi_filtered (level, stream, ")");
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_METHOD:
+ error ("missing language support in chill_type_print_base");
+ break;
+
+ default:
+
+ /* Handle types not explicitly handled by the other cases,
+ such as fundamental types. For these, just print whatever
+ the type name is, as recorded in the type itself. If there
+ is no type name, then complain. */
+
+ if (TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ }
+ else
+ {
+ error ("Unrecognized type code (%d) in symbol table.",
+ TYPE_CODE (type));
+ }
+ break;
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-valprint.c b/gnu/usr.bin/gdb/gdb/ch-valprint.c
new file mode 100644
index 000000000000..261b22ee62c6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-valprint.c
@@ -0,0 +1,332 @@
+/* Support for printing Chill values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "valprint.h"
+#include "expression.h"
+#include "value.h"
+#include "language.h"
+#include "demangle.h"
+
+static void
+chill_print_value_fields PARAMS ((struct type *, char *, FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter or 0 for natural format). The data at VALADDR is in
+ target byte order.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting. */
+
+int
+chill_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ LONGEST val;
+ unsigned int i = 0; /* Number of characters printed. */
+ struct type *elttype;
+ CORE_ADDR addr;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ if (prettyprint_arrays)
+ {
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ fprintf_filtered (stream, "[");
+ val_print_array_elements (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty, 0);
+ fprintf_filtered (stream, "]");
+ }
+ else
+ {
+ error ("unimplemented in chill_val_print; unspecified array length");
+ }
+ break;
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr, stream);
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr),
+ stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_BOOL:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val = unpack_long (builtin_type_chill_bool, valaddr);
+ fprintf_filtered (stream, val ? "TRUE" : "FALSE");
+ }
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ case TYPE_CODE_PTR:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ addr = unpack_pointer (type, valaddr);
+ elttype = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+ {
+ /* Try to print what function it points to. */
+ print_address_demangle (addr, stream, demangle);
+ /* Return value is irrelevant except for string pointers. */
+ return (0);
+ }
+ if (addressprint && format != 's')
+ {
+ fprintf_filtered (stream, "H'%lx", (unsigned long) addr);
+ }
+
+ /* For a pointer to char or unsigned char, also print the string
+ pointed to, unless pointer is null. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_CHAR
+ && (format == 0 || format == 's')
+ && addr != 0
+ && /* If print_max is UINT_MAX, the alloca below will fail.
+ In that case don't try to print the string. */
+ print_max < UINT_MAX)
+ {
+ i = val_print_string (addr, 0, stream);
+ }
+ /* Return number of characters printed, plus one for the
+ terminating null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ break;
+
+ case TYPE_CODE_STRING:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ if (addressprint && format != 's')
+ {
+ /* This used to say `addr', which is unset at this point.
+ Is `address' what is meant? */
+ fprintf_filtered (stream, "H'%lx ", (unsigned long) address);
+ }
+ i = TYPE_LENGTH (type);
+ LA_PRINT_STRING (stream, valaddr, i, 0);
+ /* Return number of characters printed, plus one for the terminating
+ null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ break;
+
+ case TYPE_CODE_STRUCT:
+ chill_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ 0);
+ break;
+
+ case TYPE_CODE_REF:
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "LOC(H'%lx)",
+ unpack_long (builtin_type_int, valaddr));
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr));
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ VALUE_ADDRESS (deref_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ c_val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_RANGE:
+ default:
+ /* Let's derfer printing to the C printer, rather than
+ print an error message. FIXME! */
+ c_val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty);
+ }
+ fflush (stream);
+ return (0);
+}
+
+/* Mutually recursive subroutines of cplus_print_value and c_val_print to
+ print out a structure's fields: cp_print_value_fields and cplus_print_value.
+
+ TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
+ same meanings as in cplus_print_value and c_val_print.
+
+ DONT_PRINT is an array of baseclass types that we
+ should not print, or zero if called from top level. */
+
+static void
+chill_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ dont_print)
+ struct type *type;
+ char *valaddr;
+ FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ int i, len;
+ int fields_seen = 0;
+
+ check_stub_type (type);
+
+ fprintf_filtered (stream, "[");
+ len = TYPE_NFIELDS (type);
+ if (len == 0)
+ {
+ fprintf_filtered (stream, "<No data fields>");
+ }
+ else
+ {
+ for (i = 0; i < len; i++)
+ {
+ if (fields_seen)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ fields_seen = 1;
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ wrap_here (n_spaces (2 + 2 * recurse));
+ }
+ fputs_filtered (".", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_chill, DMGL_NO_OPTS);
+ fputs_filtered (": ", stream);
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ value v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ v = value_from_longest (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr, i));
+
+ chill_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ else
+ {
+ chill_val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "]");
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/coff/ecoff.h b/gnu/usr.bin/gdb/gdb/coff/ecoff.h
new file mode 100644
index 000000000000..8c7cee243ea9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/ecoff.h
@@ -0,0 +1,262 @@
+#ifndef ECOFF_H
+#define ECOFF_H
+
+/* Generic ECOFF support.
+ This does not include symbol information, found in sym.h and
+ symconst.h. */
+
+/* Mips magic numbers used in filehdr. MIPS_MAGIC_LITTLE is used on
+ little endian machines. MIPS_MAGIC_BIG is used on big endian
+ machines. Where is MIPS_MAGIC_1 from? */
+#define MIPS_MAGIC_1 0x0180
+#define MIPS_MAGIC_LITTLE 0x0162
+#define MIPS_MAGIC_BIG 0x0160
+
+/* These are the magic numbers used for MIPS code compiled at ISA
+ level 2. */
+#define MIPS_MAGIC_LITTLE2 0x0166
+#define MIPS_MAGIC_BIG2 0x0163
+
+/* These are the magic numbers used for MIPS code compiled at ISA
+ level 3. */
+#define MIPS_MAGIC_LITTLE3 0x142
+#define MIPS_MAGIC_BIG3 0x140
+
+/* Alpha magic numbers used in filehdr. */
+#define ALPHA_MAGIC 0x183
+
+/* Magic numbers used in a.out header. */
+#define ECOFF_AOUT_OMAGIC 0407 /* not demand paged (ld -N). */
+#define ECOFF_AOUT_ZMAGIC 0413 /* demand load format, eg normal ld output */
+
+/* Names of special sections. */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _RDATA ".rdata"
+#define _SDATA ".sdata"
+#define _SBSS ".sbss"
+#define _LIT4 ".lit4"
+#define _LIT8 ".lit8"
+#define _LIB ".lib"
+#define _INIT ".init"
+#define _FINI ".fini"
+
+/* ECOFF uses some additional section flags. */
+#define STYP_RDATA 0x100
+#define STYP_SDATA 0x200
+#define STYP_SBSS 0x400
+#define STYP_ECOFF_FINI 0x1000000
+#define STYP_LIT8 0x8000000
+#define STYP_LIT4 0x10000000
+#define STYP_ECOFF_INIT 0x80000000
+#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI)
+
+/* The linker needs a section to hold small common variables while
+ linking. There is no convenient way to create it when the linker
+ needs it, so we always create one for each BFD. We then avoid
+ writing it out. */
+#define SCOMMON ".scommon"
+
+/* The ECOFF a.out header carries information about register masks and
+ the gp value. The assembler needs to be able to write out this
+ information, and objcopy needs to be able to copy it from one file
+ to another. To handle this in BFD, we use a dummy section to hold
+ the information. We call this section .reginfo, since MIPS ELF has
+ a .reginfo section which serves a similar purpose. When BFD
+ recognizes an ECOFF object, it copies the information into a
+ private data structure. When the .reginfo section is read, the
+ information is retrieved from the private data structure. When the
+ .reginfo section is written, the information in the private data
+ structure is updated. The contents of the .reginfo section, as
+ seen by programs outside BFD, is a ecoff_reginfo structure. The
+ contents of the structure are as seen on the host, so no swapping
+ issues arise.
+
+ The assembler used to update the private BFD data structures
+ directly. With this approach, it instead just creates a .reginfo
+ section and updates that. The real advantage of this approach is
+ that objcopy works automatically. */
+#define REGINFO ".reginfo"
+struct ecoff_reginfo
+{
+ bfd_vma gp_value; /* GP register value. */
+ unsigned long gprmask; /* General registers used. */
+ unsigned long cprmask[4]; /* Coprocessor registers used. */
+ unsigned long fprmask; /* Floating pointer registers used. */
+};
+
+/* If the extern bit in a reloc is 1, then r_symndx is an index into
+ the external symbol table. If the extern bit is 0, then r_symndx
+ indicates a section, and is one of the following values. */
+#define RELOC_SECTION_NONE 0
+#define RELOC_SECTION_TEXT 1
+#define RELOC_SECTION_RDATA 2
+#define RELOC_SECTION_DATA 3
+#define RELOC_SECTION_SDATA 4
+#define RELOC_SECTION_SBSS 5
+#define RELOC_SECTION_BSS 6
+#define RELOC_SECTION_INIT 7
+#define RELOC_SECTION_LIT8 8
+#define RELOC_SECTION_LIT4 9
+#define RELOC_SECTION_XDATA 10
+#define RELOC_SECTION_PDATA 11
+#define RELOC_SECTION_FINI 12
+#define RELOC_SECTION_LITA 13
+#define RELOC_SECTION_ABS 14
+
+/********************** STABS **********************/
+
+/* gcc uses mips-tfile to output type information in special stabs
+ entries. These must match the corresponding definition in
+ gcc/config/mips.h. At some point, these should probably go into a
+ shared include file, but currently gcc and gdb do not share any
+ directories. */
+#define CODE_MASK 0x8F300
+#define ECOFF_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK)
+#define ECOFF_MARK_STAB(code) ((code)+CODE_MASK)
+#define ECOFF_UNMARK_STAB(code) ((code)-CODE_MASK)
+#define STABS_SYMBOL "@stabs"
+
+/********************** COFF **********************/
+
+/* gcc also uses mips-tfile to output COFF debugging information.
+ These are the values it uses when outputting the .type directive.
+ These should also be in a shared include file. */
+#define N_BTMASK (017)
+#define N_TMASK (060)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+/********************** AUX **********************/
+
+/* The auxiliary type information is the same on all known ECOFF
+ targets. I can't see any reason that it would ever change, so I am
+ going to gamble and define the external structures here, in the
+ target independent ECOFF header file. The internal forms are
+ defined in coff/sym.h, which was originally donated by MIPS
+ Computer Systems. */
+
+/* Type information external record */
+
+struct tir_ext {
+ unsigned char t_bits1[1];
+ unsigned char t_tq45[1];
+ unsigned char t_tq01[1];
+ unsigned char t_tq23[1];
+};
+
+#define TIR_BITS1_FBITFIELD_BIG 0x80
+#define TIR_BITS1_FBITFIELD_LITTLE 0x01
+
+#define TIR_BITS1_CONTINUED_BIG 0x40
+#define TIR_BITS1_CONTINUED_LITTLE 0x02
+
+#define TIR_BITS1_BT_BIG 0x3F
+#define TIR_BITS1_BT_SH_BIG 0
+#define TIR_BITS1_BT_LITTLE 0xFC
+#define TIR_BITS1_BT_SH_LITTLE 2
+
+#define TIR_BITS_TQ4_BIG 0xF0
+#define TIR_BITS_TQ4_SH_BIG 4
+#define TIR_BITS_TQ5_BIG 0x0F
+#define TIR_BITS_TQ5_SH_BIG 0
+#define TIR_BITS_TQ4_LITTLE 0x0F
+#define TIR_BITS_TQ4_SH_LITTLE 0
+#define TIR_BITS_TQ5_LITTLE 0xF0
+#define TIR_BITS_TQ5_SH_LITTLE 4
+
+#define TIR_BITS_TQ0_BIG 0xF0
+#define TIR_BITS_TQ0_SH_BIG 4
+#define TIR_BITS_TQ1_BIG 0x0F
+#define TIR_BITS_TQ1_SH_BIG 0
+#define TIR_BITS_TQ0_LITTLE 0x0F
+#define TIR_BITS_TQ0_SH_LITTLE 0
+#define TIR_BITS_TQ1_LITTLE 0xF0
+#define TIR_BITS_TQ1_SH_LITTLE 4
+
+#define TIR_BITS_TQ2_BIG 0xF0
+#define TIR_BITS_TQ2_SH_BIG 4
+#define TIR_BITS_TQ3_BIG 0x0F
+#define TIR_BITS_TQ3_SH_BIG 0
+#define TIR_BITS_TQ2_LITTLE 0x0F
+#define TIR_BITS_TQ2_SH_LITTLE 0
+#define TIR_BITS_TQ3_LITTLE 0xF0
+#define TIR_BITS_TQ3_SH_LITTLE 4
+
+/* Relative symbol external record */
+
+struct rndx_ext {
+ unsigned char r_bits[4];
+};
+
+#define RNDX_BITS0_RFD_SH_LEFT_BIG 4
+#define RNDX_BITS1_RFD_BIG 0xF0
+#define RNDX_BITS1_RFD_SH_BIG 4
+
+#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0
+#define RNDX_BITS1_RFD_LITTLE 0x0F
+#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8
+
+#define RNDX_BITS1_INDEX_BIG 0x0F
+#define RNDX_BITS1_INDEX_SH_LEFT_BIG 16
+#define RNDX_BITS2_INDEX_SH_LEFT_BIG 8
+#define RNDX_BITS3_INDEX_SH_LEFT_BIG 0
+
+#define RNDX_BITS1_INDEX_LITTLE 0xF0
+#define RNDX_BITS1_INDEX_SH_LITTLE 4
+#define RNDX_BITS2_INDEX_SH_LEFT_LITTLE 4
+#define RNDX_BITS3_INDEX_SH_LEFT_LITTLE 12
+
+/* Auxiliary symbol information external record */
+
+union aux_ext {
+ struct tir_ext a_ti;
+ struct rndx_ext a_rndx;
+ unsigned char a_dnLow[4];
+ unsigned char a_dnHigh[4];
+ unsigned char a_isym[4];
+ unsigned char a_iss[4];
+ unsigned char a_width[4];
+ unsigned char a_count[4];
+};
+
+#define AUX_GET_ANY(bigend, ax, field) \
+ ((bigend) ? bfd_getb32 ((ax)->field) : bfd_getl32 ((ax)->field))
+
+#define AUX_GET_DNLOW(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnLow)
+#define AUX_GET_DNHIGH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnHigh)
+#define AUX_GET_ISYM(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_isym)
+#define AUX_GET_ISS(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_iss)
+#define AUX_GET_WIDTH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_width)
+#define AUX_GET_COUNT(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_count)
+
+#define AUX_PUT_ANY(bigend, val, ax, field) \
+ ((bigend) \
+ ? (bfd_putb32 ((bfd_vma) (val), (ax)->field), 0) \
+ : (bfd_putl32 ((bfd_vma) (val), (ax)->field), 0))
+
+#define AUX_PUT_DNLOW(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_dnLow)
+#define AUX_PUT_DNHIGH(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_dnHigh)
+#define AUX_PUT_ISYM(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_isym)
+#define AUX_PUT_ISS(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_iss)
+#define AUX_PUT_WIDTH(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_width)
+#define AUX_PUT_COUNT(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_count)
+
+/* Prototypes for the swapping functions. These require that sym.h be
+ included before this file. */
+
+extern void ecoff_swap_tir_in PARAMS ((int bigend, struct tir_ext *, TIR *));
+extern void ecoff_swap_tir_out PARAMS ((int bigend, TIR *, struct tir_ext *));
+extern void ecoff_swap_rndx_in PARAMS ((int bigend, struct rndx_ext *,
+ RNDXR *));
+extern void ecoff_swap_rndx_out PARAMS ((int bigend, RNDXR *,
+ struct rndx_ext *));
+
+#endif /* ! defined (ECOFF_H) */
diff --git a/gnu/usr.bin/gdb/gdb/coff/internal.h b/gnu/usr.bin/gdb/gdb/coff/internal.h
new file mode 100644
index 000000000000..e8cf98470cfb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/internal.h
@@ -0,0 +1,538 @@
+/* Internal format of COFF object file data structures, for GNU BFD.
+ This file is part of BFD, the Binary File Descriptor library. */
+
+/* First, make "signed char" work, even on old compilers. */
+#ifndef signed
+#ifndef __STDC__
+#define signed /**/
+#endif
+#endif
+
+/********************** FILE HEADER **********************/
+struct internal_filehdr
+{
+ unsigned short f_magic; /* magic number */
+ unsigned short f_nscns; /* number of sections */
+ long f_timdat; /* time & date stamp */
+ bfd_vma f_symptr; /* file pointer to symtab */
+ long f_nsyms; /* number of symtab entries */
+ unsigned short f_opthdr; /* sizeof(optional hdr) */
+ unsigned short f_flags; /* flags */
+};
+
+/* Bits for f_flags:
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (no unresolved external references)
+ * F_LNNO line numbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_AR16WR file is 16-bit little-endian
+ * F_AR32WR file is 32-bit little-endian
+ * F_AR32W file is 32-bit big-endian
+ * F_DYNLOAD rs/6000 aix: dynamically loadable w/imports & exports
+ * F_SHROBJ rs/6000 aix: file is a shared object
+ */
+
+#define F_RELFLG (0x0001)
+#define F_EXEC (0x0002)
+#define F_LNNO (0x0004)
+#define F_LSYMS (0x0008)
+#define F_AR16WR (0x0080)
+#define F_AR32WR (0x0100)
+#define F_AR32W (0x0200)
+#define F_DYNLOAD (0x1000)
+#define F_SHROBJ (0x2000)
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+struct internal_aouthdr
+{
+ short magic; /* type of file */
+ short vstamp; /* version stamp */
+ bfd_vma tsize; /* text size in bytes, padded to FW bdry*/
+ bfd_vma dsize; /* initialized data " " */
+ bfd_vma bsize; /* uninitialized data " " */
+ bfd_vma entry; /* entry pt. */
+ bfd_vma text_start; /* base of text used for this file */
+ bfd_vma data_start; /* base of data used for this file */
+
+ /* i960 stuff */
+ unsigned long tagentries; /* number of tag entries to follow */
+
+ /* RS/6000 stuff */
+ unsigned long o_toc; /* address of TOC */
+ short o_snentry; /* section number for entry point */
+ short o_sntext; /* section number for text */
+ short o_sndata; /* section number for data */
+ short o_sntoc; /* section number for toc */
+ short o_snloader; /* section number for loader section */
+ short o_snbss; /* section number for bss */
+ short o_algntext; /* max alignment for text */
+ short o_algndata; /* max alignment for data */
+ short o_modtype; /* Module type field, 1R,RE,RO */
+ unsigned long o_maxstack; /* max stack size allowed. */
+
+ /* ECOFF stuff */
+ bfd_vma bss_start; /* Base of bss section. */
+ bfd_vma gp_value; /* GP register value. */
+ unsigned long gprmask; /* General registers used. */
+ unsigned long cprmask[4]; /* Coprocessor registers used. */
+ unsigned long fprmask; /* Floating pointer registers used. */
+
+ /* Apollo stuff */
+ long o_inlib;
+ long o_sri;
+ long vid[2];
+};
+
+/********************** STORAGE CLASSES **********************/
+
+/* This used to be defined as -1, but now n_sclass is unsigned. */
+#define C_EFCN 0xff /* physical end of function */
+#define C_NULL 0
+#define C_AUTO 1 /* automatic variable */
+#define C_EXT 2 /* external symbol */
+#define C_STAT 3 /* static */
+#define C_REG 4 /* register variable */
+#define C_EXTDEF 5 /* external definition */
+#define C_LABEL 6 /* label */
+#define C_ULABEL 7 /* undefined label */
+#define C_MOS 8 /* member of structure */
+#define C_ARG 9 /* function argument */
+#define C_STRTAG 10 /* structure tag */
+#define C_MOU 11 /* member of union */
+#define C_UNTAG 12 /* union tag */
+#define C_TPDEF 13 /* type definition */
+#define C_USTATIC 14 /* undefined static */
+#define C_ENTAG 15 /* enumeration tag */
+#define C_MOE 16 /* member of enumeration */
+#define C_REGPARM 17 /* register parameter */
+#define C_FIELD 18 /* bit field */
+#define C_AUTOARG 19 /* auto argument */
+#define C_LASTENT 20 /* dummy entry (end of block) */
+#define C_BLOCK 100 /* ".bb" or ".eb" */
+#define C_FCN 101 /* ".bf" or ".ef" */
+#define C_EOS 102 /* end of structure */
+#define C_FILE 103 /* file name */
+#define C_LINE 104 /* line # reformatted as symbol table entry */
+#define C_ALIAS 105 /* duplicate tag */
+#define C_HIDDEN 106 /* ext symbol in dmert public lib */
+
+ /* New storage classes for 80960 */
+
+/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */
+#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */
+
+#define C_SCALL 107 /* Procedure reachable via system call */
+#define C_LEAFEXT 108 /* External leaf */
+#define C_LEAFSTAT 113 /* Static leaf */
+#define C_OPTVAR 109 /* Optimized variable */
+#define C_DEFINE 110 /* Preprocessor #define */
+#define C_PRAGMA 111 /* Advice to compiler or linker */
+#define C_SEGMENT 112 /* 80960 segment name */
+
+ /* Storage classes for m88k */
+#define C_SHADOW 107 /* shadow symbol */
+#define C_VERSION 108 /* coff version symbol */
+
+ /* New storage classes for RS/6000 */
+#define C_HIDEXT 107 /* Un-named external symbol */
+#define C_BINCL 108 /* Marks beginning of include file */
+#define C_EINCL 109 /* Marks ending of include file */
+
+ /* storage classes for stab symbols for RS/6000 */
+#define C_GSYM (0x80)
+#define C_LSYM (0x81)
+#define C_PSYM (0x82)
+#define C_RSYM (0x83)
+#define C_RPSYM (0x84)
+#define C_STSYM (0x85)
+#define C_TCSYM (0x86)
+#define C_BCOMM (0x87)
+#define C_ECOML (0x88)
+#define C_ECOMM (0x89)
+#define C_DECL (0x8c)
+#define C_ENTRY (0x8d)
+#define C_FUN (0x8e)
+#define C_BSTAT (0x8f)
+#define C_ESTAT (0x90)
+
+/********************** SECTION HEADER **********************/
+struct internal_scnhdr
+{
+ char s_name[8]; /* section name */
+ bfd_vma s_paddr; /* physical address, aliased s_nlib */
+ bfd_vma s_vaddr; /* virtual address */
+ bfd_vma s_size; /* section size */
+ bfd_vma s_scnptr; /* file ptr to raw data for section */
+ bfd_vma s_relptr; /* file ptr to relocation */
+ bfd_vma s_lnnoptr; /* file ptr to line numbers */
+ unsigned long s_nreloc; /* number of relocation entries */
+ unsigned long s_nlnno; /* number of line number entries*/
+ long s_flags; /* flags */
+ long s_align; /* used on I960 */
+};
+
+/*
+ * s_flags "type"
+ */
+#define STYP_REG (0x0000) /* "regular": allocated, relocated, loaded */
+#define STYP_DSECT (0x0001) /* "dummy": relocated only*/
+#define STYP_NOLOAD (0x0002) /* "noload": allocated, relocated, not loaded */
+#define STYP_GROUP (0x0004) /* "grouped": formed of input sections */
+#define STYP_PAD (0x0008) /* "padding": not allocated, not relocated, loaded */
+#define STYP_COPY (0x0010) /* "copy": for decision function used by field update; not allocated, not relocated,
+ loaded; reloc & lineno entries processed normally */
+#define STYP_TEXT (0x0020) /* section contains text only */
+#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile
+ will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will
+ update all process invocations. */
+#define STYP_DATA (0x0040) /* section contains data only */
+#define STYP_BSS (0x0080) /* section contains bss only */
+#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */
+#define STYP_INFO (0x0200) /* comment: not allocated not relocated, not loaded */
+#define STYP_OVER (0x0400) /* overlay: relocated not allocated or loaded */
+#define STYP_LIB (0x0800) /* for .lib: same as INFO */
+#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */
+#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a
+
+ word of contiguous bytes
+ beginning on a word boundary. */
+
+#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+
+struct internal_lineno
+{
+ union
+ {
+ long l_symndx; /* function name symbol index, iff l_lnno == 0*/
+ long l_paddr; /* (physical) address of line number */
+ } l_addr;
+ unsigned long l_lnno; /* line number */
+};
+
+/********************** SYMBOLS **********************/
+
+#define SYMNMLEN 8 /* # characters in a symbol name */
+#define FILNMLEN 14 /* # characters in a file name */
+#define DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct internal_syment
+{
+ union
+ {
+ char _n_name[SYMNMLEN]; /* old COFF version */
+ struct
+ {
+ long _n_zeroes; /* new == 0 */
+ long _n_offset; /* offset into string table */
+ } _n_n;
+ char *_n_nptr[2]; /* allows for overlaying */
+ } _n;
+ long n_value; /* value of symbol */
+ short n_scnum; /* section number */
+ unsigned short n_flags; /* copy of flags from filhdr */
+ unsigned short n_type; /* type and derived type */
+ unsigned char n_sclass; /* storage class */
+ char n_numaux; /* number of aux. entries */
+};
+
+#define n_name _n._n_name
+#define n_zeroes _n._n_n._n_zeroes
+#define n_offset _n._n_n._n_offset
+
+
+/* Relocatable symbols have number of the section in which they are defined,
+ or one of the following: */
+
+#define N_UNDEF ((short)0) /* undefined symbol */
+#define N_ABS ((short)-1) /* value of symbol is absolute */
+#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */
+#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */
+#define P_TV ((short)-4) /* indicates symbol needs postload transfer vector*/
+
+/*
+ * Type of a symbol, in low N bits of the word
+ */
+#define T_NULL 0
+#define T_VOID 1 /* function argument (only used by compiler) */
+#define T_CHAR 2 /* character */
+#define T_SHORT 3 /* short integer */
+#define T_INT 4 /* integer */
+#define T_LONG 5 /* long integer */
+#define T_FLOAT 6 /* floating point */
+#define T_DOUBLE 7 /* double word */
+#define T_STRUCT 8 /* structure */
+#define T_UNION 9 /* union */
+#define T_ENUM 10 /* enumeration */
+#define T_MOE 11 /* member of enumeration*/
+#define T_UCHAR 12 /* unsigned character */
+#define T_USHORT 13 /* unsigned short */
+#define T_UINT 14 /* unsigned integer */
+#define T_ULONG 15 /* unsigned long */
+#define T_LNGDBL 16 /* long double */
+
+/*
+ * derived types, in n_type
+*/
+#define DT_NON (0) /* no derived type */
+#define DT_PTR (1) /* pointer */
+#define DT_FCN (2) /* function */
+#define DT_ARY (3) /* array */
+
+#define BTYPE(x) ((x) & N_BTMASK)
+
+#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG)
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+
+
+union internal_auxent
+{
+ struct
+ {
+
+ union
+ {
+ long l; /* str, un, or enum tag indx */
+ struct coff_ptr_struct *p;
+ } x_tagndx;
+
+ union
+ {
+ struct
+ {
+ unsigned short x_lnno; /* declaration line number */
+ unsigned short x_size; /* str/union/array size */
+ } x_lnsz;
+ long x_fsize; /* size of function */
+ } x_misc;
+
+ union
+ {
+ struct
+ { /* if ISFCN, tag, or .bb */
+ long x_lnnoptr; /* ptr to fcn line # */
+ union
+ { /* entry ndx past block end */
+ long l;
+ struct coff_ptr_struct *p;
+ } x_endndx;
+ } x_fcn;
+
+ struct
+ { /* if ISARY, up to 4 dimen. */
+ unsigned short x_dimen[DIMNUM];
+ } x_ary;
+ } x_fcnary;
+
+ unsigned short x_tvndx; /* tv index */
+ } x_sym;
+
+ union
+ {
+ char x_fname[FILNMLEN];
+ struct
+ {
+ long x_zeroes;
+ long x_offset;
+ } x_n;
+ } x_file;
+
+ struct
+ {
+ long x_scnlen; /* section length */
+ unsigned short x_nreloc; /* # relocation entries */
+ unsigned short x_nlinno; /* # line numbers */
+ } x_scn;
+
+ struct
+ {
+ long x_tvfill; /* tv fill value */
+ unsigned short x_tvlen; /* length of .tv */
+ unsigned short x_tvran[2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+ /******************************************
+ * RS/6000-specific auxent - last auxent for every external symbol
+ ******************************************/
+ struct
+ {
+ long x_scnlen; /* csect length */
+ long x_parmhash; /* parm type hash index */
+ unsigned short x_snhash; /* sect num with parm hash */
+ unsigned char x_smtyp; /* symbol align and type */
+ /* 0-4 - Log 2 of alignment */
+ /* 5-7 - symbol type */
+ unsigned char x_smclas; /* storage mapping class */
+ long x_stab; /* dbx stab info index */
+ unsigned short x_snstab; /* sect num with dbx stab */
+ } x_csect; /* csect definition information */
+
+/* x_smtyp values: */
+
+#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */
+#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */
+/* Symbol type values: */
+#define XTY_ER 0 /* External reference */
+#define XTY_SD 1 /* Csect definition */
+#define XTY_LD 2 /* Label definition */
+#define XTY_CM 3 /* .BSS */
+#define XTY_EM 4 /* Error message */
+#define XTY_US 5 /* "Reserved for internal use" */
+
+/* x_smclas values: */
+
+#define XMC_PR 0 /* Read-only program code */
+#define XMC_RO 1 /* Read-only constant */
+#define XMC_DB 2 /* Read-only debug dictionary table */
+#define XMC_TC 3 /* Read-write general TOC entry */
+#define XMC_UA 4 /* Read-write unclassified */
+#define XMC_RW 5 /* Read-write data */
+#define XMC_GL 6 /* Read-only global linkage */
+#define XMC_XO 7 /* Read-only extended operation (simulated insn) */
+#define XMC_SV 8 /* Read-only supervisor call */
+#define XMC_BS 9 /* Read-write BSS */
+#define XMC_DS 10 /* Read-write descriptor csect */
+#define XMC_UC 11 /* Read-write unnamed Fortran common */
+#define XMC_TI 12 /* Read-only traceback index csect */
+#define XMC_TB 13 /* Read-only traceback table csect */
+/* 14 ??? */
+#define XMC_TC0 15 /* Read-write TOC anchor for TOC addressability */
+
+
+ /******************************************
+ * I960-specific *2nd* aux. entry formats
+ ******************************************/
+ struct
+ {
+ /* This is a very old typo that keeps getting propagated. */
+#define x_stdindx x_stindx
+ long x_stindx; /* sys. table entry */
+ } x_sc; /* system call entry */
+
+ struct
+ {
+ unsigned long x_balntry; /* BAL entry point */
+ } x_bal; /* BAL-callable function */
+
+ struct
+ {
+ unsigned long x_timestamp; /* time stamp */
+ char x_idstring[20]; /* producer identity string */
+ } x_ident; /* Producer ident info */
+
+};
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct internal_reloc
+{
+ bfd_vma r_vaddr; /* Virtual address of reference */
+ long r_symndx; /* Index into symbol table */
+ unsigned short r_type; /* Relocation type */
+ unsigned char r_size; /* Used by RS/6000 and ECOFF */
+ unsigned char r_extern; /* Used by ECOFF */
+ unsigned long r_offset; /* Used by RS/6000 and ECOFF */
+};
+
+#define R_RELBYTE 017
+#define R_RELWORD 020
+#define R_PCRBYTE 022
+#define R_PCRWORD 023
+#define R_PCRLONG 024
+
+#define R_DIR16 01
+#define R_DIR32 06
+#define R_PCLONG 020
+#define R_RELBYTE 017
+#define R_RELWORD 020
+
+
+
+#define R_PCR16L 128
+#define R_PCR26L 129
+#define R_VRT16 130
+#define R_HVRT16 131
+#define R_LVRT16 132
+#define R_VRT32 133
+#define R_RELLONG (0x11) /* Direct 32-bit relocation */
+#define R_IPRSHORT (0x18)
+#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */
+#define R_IPRLONG (0x1a)
+#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */
+#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */
+#define R_GETSEG (0x1d)
+#define R_GETPA (0x1e)
+#define R_TAGWORD (0x1f)
+#define R_JUMPTARG 0x20 /* strange 29k 00xx00xx reloc */
+
+
+#define R_MOVB1 0x41 /* Special h8 16bit or 8 bit reloc for mov.b */
+#define R_MOVB2 0x42 /* Special h8 opcode for 8bit which could be 16 */
+#define R_JMP1 0x43 /* Special h8 16bit jmp which could be pcrel */
+#define R_JMP2 0x44 /* a branch which used to be a jmp */
+#define R_RELLONG_NEG 0x45
+
+#define R_JMPL1 0x46 /* Special h8 24bit jmp which could be pcrel */
+#define R_JMPL_B8 0x47 /* a 8 bit pcrel which used to be a jmp */
+
+#define R_MOVLB1 0x48 /* Special h8 24bit or 8 bit reloc for mov.b */
+#define R_MOVLB2 0x49 /* Special h8 opcode for 8bit which could be 24 */
+
+/* Z8k modes */
+#define R_IMM16 0x01 /* 16 bit abs */
+#define R_JR 0x02 /* jr 8 bit disp */
+#define R_IMM4L 0x23 /* low nibble */
+#define R_IMM8 0x22 /* 8 bit abs */
+#define R_IMM32 R_RELLONG /* 32 bit abs */
+#define R_CALL R_DA /* Absolute address which could be a callr */
+#define R_JP R_DA /* Absolute address which could be a jp */
+#define R_REL16 0x04 /* 16 bit PC rel */
+#define R_CALLR 0x05 /* callr 12 bit disp */
+#define R_SEG 0x10 /* set if in segmented mode */
+#define R_IMM4H 0x24 /* high nibble */
+
+
+/* H8500 modes */
+
+#define R_H8500_IMM8 1 /* 8 bit immediate */
+#define R_H8500_IMM16 2 /* 16 bit immediate */
+#define R_H8500_PCREL8 3 /* 8 bit pcrel */
+#define R_H8500_PCREL16 4 /* 16 bit pcrel */
+#define R_H8500_HIGH8 5 /* high 8 bits of 24 bit address */
+#define R_H8500_LOW16 7 /* low 16 bits of 24 bit immediate */
+#define R_H8500_IMM24 6 /* 24 bit immediate */
+#define R_H8500_IMM32 8 /* 32 bit immediate */
+#define R_H8500_HIGH16 9 /* high 16 bits of 32 bit immediate */
+
+/* SH modes */
+
+#define R_SH_PCREL8 3 /* 8 bit pcrel */
+#define R_SH_PCREL16 4 /* 16 bit pcrel */
+#define R_SH_HIGH8 5 /* high 8 bits of 24 bit address */
+#define R_SH_LOW16 7 /* low 16 bits of 24 bit immediate */
+#define R_SH_IMM24 6 /* 24 bit immediate */
+#define R_SH_PCDISP8BY4 9 /* PC rel 8 bits *4 +ve */
+#define R_SH_PCDISP8BY2 10 /* PC rel 8 bits *2 +ve */
+#define R_SH_PCDISP8 11 /* 8 bit branch */
+#define R_SH_PCDISP 12 /* 12 bit branch */
+#define R_SH_IMM32 14 /* 32 bit immediate */
+#define R_SH_IMM8 16
+#define R_SH_IMM8BY2 17
+#define R_SH_IMM8BY4 18
+#define R_SH_IMM4 19
+#define R_SH_IMM4BY2 20
+#define R_SH_IMM4BY4 21
+#define R_SH_PCRELIMM8BY2 22
+#define R_SH_PCRELIMM8BY4 23
+
+
+
diff --git a/gnu/usr.bin/gdb/gdb/coff/sym.h b/gnu/usr.bin/gdb/gdb/coff/sym.h
new file mode 100644
index 000000000000..990eeacc6809
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/sym.h
@@ -0,0 +1,477 @@
+/* Declarations of internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+#ifndef _SYM_H
+#define _SYM_H
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/*
+ * This file contains the definition of the Third Eye Symbol Table.
+ *
+ * Symbols are assumed to be in 'encounter order' - i.e. the order that
+ * the things they represent were encountered by the compiler/assembler/loader.
+ * EXCEPT for globals! These are assumed to be bunched together,
+ * probably right after the last 'normal' symbol. Globals ARE sorted
+ * in ascending order.
+ *
+ * -----------------------------------------------------------------------
+ * A brief word about Third Eye naming/use conventions:
+ *
+ * All arrays and index's are 0 based.
+ * All "ifooMax" values are the highest legal value PLUS ONE. This makes
+ * them good for allocating arrays, etc. All checks are "ifoo < ifooMax".
+ *
+ * "isym" Index into the SYMbol table.
+ * "ipd" Index into the Procedure Descriptor array.
+ * "ifd" Index into the File Descriptor array.
+ * "iss" Index into String Space.
+ * "cb" Count of Bytes.
+ * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR.
+ * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR.
+ */
+
+
+/*
+ * Symbolic Header (HDR) structure.
+ * As long as all the pointers are set correctly,
+ * we don't care WHAT order the various sections come out in!
+ *
+ * A file produced solely for the use of CDB will probably NOT have
+ * any instructions or data areas in it, as these are available
+ * in the original.
+ */
+
+typedef struct {
+ short magic; /* to verify validity of the table */
+ short vstamp; /* version stamp */
+ long ilineMax; /* number of line number entries */
+ bfd_vma cbLine; /* number of bytes for line number entries */
+ bfd_vma cbLineOffset; /* offset to start of line number entries*/
+ long idnMax; /* max index into dense number table */
+ bfd_vma cbDnOffset; /* offset to start dense number table */
+ long ipdMax; /* number of procedures */
+ bfd_vma cbPdOffset; /* offset to procedure descriptor table */
+ long isymMax; /* number of local symbols */
+ bfd_vma cbSymOffset; /* offset to start of local symbols*/
+ long ioptMax; /* max index into optimization symbol entries */
+ bfd_vma cbOptOffset; /* offset to optimization symbol entries */
+ long iauxMax; /* number of auxillary symbol entries */
+ bfd_vma cbAuxOffset; /* offset to start of auxillary symbol entries*/
+ long issMax; /* max index into local strings */
+ bfd_vma cbSsOffset; /* offset to start of local strings */
+ long issExtMax; /* max index into external strings */
+ bfd_vma cbSsExtOffset; /* offset to start of external strings */
+ long ifdMax; /* number of file descriptor entries */
+ bfd_vma cbFdOffset; /* offset to file descriptor table */
+ long crfd; /* number of relative file descriptor entries */
+ bfd_vma cbRfdOffset; /* offset to relative file descriptor table */
+ long iextMax; /* max index into external symbols */
+ bfd_vma cbExtOffset; /* offset to start of external symbol entries*/
+ /* If you add machine dependent fields, add them here */
+ } HDRR, *pHDRR;
+#define cbHDRR sizeof(HDRR)
+#define hdrNil ((pHDRR)0)
+
+/*
+ * The FDR and PDR structures speed mapping of address <-> name.
+ * They are sorted in ascending memory order and are kept in
+ * memory by CDB at runtime.
+ */
+
+/*
+ * File Descriptor
+ *
+ * There is one of these for EVERY FILE, whether compiled with
+ * full debugging symbols or not. The name of a file should be
+ * the path name given to the compiler. This allows the user
+ * to simply specify the names of the directories where the COMPILES
+ * were done, and we will be able to find their files.
+ * A field whose comment starts with "R - " indicates that it will be
+ * setup at runtime.
+ */
+typedef struct fdr {
+ bfd_vma adr; /* memory address of beginning of file */
+ long rss; /* file name (of source, if known) */
+ long issBase; /* file's string space */
+ bfd_vma cbSs; /* number of bytes in the ss */
+ long isymBase; /* beginning of symbols */
+ long csym; /* count file's of symbols */
+ long ilineBase; /* file's line symbols */
+ long cline; /* count of file's line symbols */
+ long ioptBase; /* file's optimization entries */
+ long copt; /* count of file's optimization entries */
+ unsigned short ipdFirst;/* start of procedures for this file */
+ short cpd; /* count of procedures for this file */
+ long iauxBase; /* file's auxiliary entries */
+ long caux; /* count of file's auxiliary entries */
+ long rfdBase; /* index into the file indirect table */
+ long crfd; /* count file indirect entries */
+ unsigned lang: 5; /* language for this file */
+ unsigned fMerge : 1; /* whether this file can be merged */
+ unsigned fReadin : 1; /* true if it was read in (not just created) */
+ unsigned fBigendian : 1;/* if set, was compiled on big endian machine */
+ /* aux's will be in compile host's sex */
+ unsigned glevel : 2; /* level this file was compiled with */
+ unsigned reserved : 22; /* reserved for future use */
+ bfd_vma cbLineOffset; /* byte offset from header for this file ln's */
+ bfd_vma cbLine; /* size of lines for this file */
+ } FDR, *pFDR;
+#define cbFDR sizeof(FDR)
+#define fdNil ((pFDR)0)
+#define ifdNil -1
+#define ifdTemp 0
+#define ilnNil -1
+
+
+/*
+ * Procedure Descriptor
+ *
+ * There is one of these for EVERY TEXT LABEL.
+ * If a procedure is in a file with full symbols, then isym
+ * will point to the PROC symbols, else it will point to the
+ * global symbol for the label.
+ */
+
+typedef struct pdr {
+ bfd_vma adr; /* memory address of start of procedure */
+ long isym; /* start of local symbol entries */
+ long iline; /* start of line number entries*/
+ long regmask; /* save register mask */
+ long regoffset; /* save register offset */
+ long iopt; /* start of optimization symbol entries*/
+ long fregmask; /* save floating point register mask */
+ long fregoffset; /* save floating point register offset */
+ long frameoffset; /* frame size */
+ short framereg; /* frame pointer register */
+ short pcreg; /* offset or reg of return pc */
+ long lnLow; /* lowest line in the procedure */
+ long lnHigh; /* highest line in the procedure */
+ bfd_vma cbLineOffset; /* byte offset for this procedure from the fd base */
+ /* These fields are new for 64 bit ECOFF. */
+ unsigned gp_prologue : 8; /* byte size of GP prologue */
+ unsigned gp_used : 1; /* true if the procedure uses GP */
+ unsigned reg_frame : 1; /* true if register frame procedure */
+ unsigned reserved : 14; /* reserved: must be zero */
+ unsigned localoff : 8; /* offset of local variables from vfp */
+ } PDR, *pPDR;
+#define cbPDR sizeof(PDR)
+#define pdNil ((pPDR) 0)
+#define ipdNil -1
+
+/*
+ * The structure of the runtime procedure descriptor created by the loader
+ * for use by the static exception system.
+ */
+typedef struct runtime_pdr {
+ unsigned long adr; /* memory address of start of procedure */
+ long regmask; /* save register mask */
+ long regoffset; /* save register offset */
+ long fregmask; /* save floating point register mask */
+ long fregoffset; /* save floating point register offset */
+ long frameoffset; /* frame size */
+ short framereg; /* frame pointer register */
+ short pcreg; /* offset or reg of return pc */
+ long irpss; /* index into the runtime string table */
+ long reserved;
+ struct exception_info *exception_info;/* pointer to exception array */
+} RPDR, *pRPDR;
+#define cbRPDR sizeof(RPDR)
+#define rpdNil ((pRPDR) 0)
+
+/*
+ * Line Numbers
+ *
+ * Line Numbers are segregated from the normal symbols because they
+ * are [1] smaller , [2] are of no interest to your
+ * average loader, and [3] are never needed in the middle of normal
+ * scanning and therefore slow things down.
+ *
+ * By definition, the first LINER for any given procedure will have
+ * the first line of a procedure and represent the first address.
+ */
+
+typedef long LINER, *pLINER;
+#define lineNil ((pLINER)0)
+#define cbLINER sizeof(LINER)
+#define ilineNil -1
+
+
+
+/*
+ * The Symbol Structure (GFW, to those who Know!)
+ */
+
+typedef struct {
+ long iss; /* index into String Space of name */
+ long value; /* value of symbol */
+ unsigned st : 6; /* symbol type */
+ unsigned sc : 5; /* storage class - text, data, etc */
+ unsigned reserved : 1; /* reserved */
+ unsigned index : 20; /* index into sym/aux table */
+ } SYMR, *pSYMR;
+#define symNil ((pSYMR)0)
+#define cbSYMR sizeof(SYMR)
+#define isymNil -1
+#define indexNil 0xfffff
+#define issNil -1
+#define issNull 0
+
+
+/* The following converts a memory resident string to an iss.
+ * This hack is recognized in SbFIss, in sym.c of the debugger.
+ */
+#define IssFSb(sb) (0x80000000 | ((unsigned long)(sb)))
+
+/* E X T E R N A L S Y M B O L R E C O R D
+ *
+ * Same as the SYMR except it contains file context to determine where
+ * the index is.
+ */
+typedef struct {
+ unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */
+ unsigned cobol_main:1; /* symbol is a cobol main procedure */
+ unsigned weakext:1; /* symbol is weak external */
+ unsigned reserved:13; /* reserved for future use */
+ int ifd; /* where the iss and index fields point into */
+ SYMR asym; /* symbol for the external */
+ } EXTR, *pEXTR;
+#define extNil ((pEXTR)0)
+#define cbEXTR sizeof(EXTR)
+
+
+/* A U X I L L A R Y T Y P E I N F O R M A T I O N */
+
+/*
+ * Type Information Record
+ */
+typedef struct {
+ unsigned fBitfield : 1; /* set if bit width is specified */
+ unsigned continued : 1; /* indicates additional TQ info in next AUX */
+ unsigned bt : 6; /* basic type */
+ unsigned tq4 : 4;
+ unsigned tq5 : 4;
+ /* ---- 16 bit boundary ---- */
+ unsigned tq0 : 4;
+ unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
+ unsigned tq2 : 4;
+ unsigned tq3 : 4;
+ } TIR, *pTIR;
+#define cbTIR sizeof(TIR)
+#define tiNil ((pTIR)0)
+#define itqMax 6
+
+/*
+ * Relative symbol record
+ *
+ * If the rfd field is 4095, the index field indexes into the global symbol
+ * table.
+ */
+
+typedef struct {
+ unsigned rfd : 12; /* index into the file indirect table */
+ unsigned index : 20; /* index int sym/aux/iss tables */
+ } RNDXR, *pRNDXR;
+#define cbRNDXR sizeof(RNDXR)
+#define rndxNil ((pRNDXR)0)
+
+/* dense numbers or sometimes called block numbers are stored in this type,
+ * a rfd of 0xffffffff is an index into the global table.
+ */
+typedef struct {
+ unsigned long rfd; /* index into the file table */
+ unsigned long index; /* index int sym/aux/iss tables */
+ } DNR, *pDNR;
+#define cbDNR sizeof(DNR)
+#define dnNil ((pDNR)0)
+
+
+
+/*
+ * Auxillary information occurs only if needed.
+ * It ALWAYS occurs in this order when present.
+
+ isymMac used by stProc only
+ TIR type info
+ TIR additional TQ info (if first TIR was not enough)
+ rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange,
+ btTypedef):
+ rsym.index == iaux for btSet or btRange
+ else rsym.index == isym
+ dimLow btRange, btSet
+ dimMac btRange, btSet
+ rndx0 As many as there are tq arrays
+ dimLow0
+ dimHigh0
+ ...
+ rndxMax-1
+ dimLowMax-1
+ dimHighMax-1
+ width in bits if (bit field), width in bits.
+ */
+#define cAuxMax (6 + (idimMax*3))
+
+/* a union of all possible info in the AUX universe */
+typedef union {
+ TIR ti; /* type information record */
+ RNDXR rndx; /* relative index into symbol table */
+ long dnLow; /* low dimension */
+ long dnHigh; /* high dimension */
+ long isym; /* symbol table index (end of proc) */
+ long iss; /* index into string space (not used) */
+ long width; /* width for non-default sized struc fields */
+ long count; /* count of ranges for variant arm */
+ } AUXU, *pAUXU;
+#define cbAUXU sizeof(AUXU)
+#define auxNil ((pAUXU)0)
+#define iauxNil -1
+
+
+/*
+ * Optimization symbols
+ *
+ * Optimization symbols contain some overlap information with the normal
+ * symbol table. In particular, the proc information
+ * is somewhat redundant but necessary to easily find the other information
+ * present.
+ *
+ * All of the offsets are relative to the beginning of the last otProc
+ */
+
+typedef struct {
+ unsigned ot: 8; /* optimization type */
+ unsigned value: 24; /* address where we are moving it to */
+ RNDXR rndx; /* points to a symbol or opt entry */
+ unsigned long offset; /* relative offset this occured */
+ } OPTR, *pOPTR;
+#define optNil ((pOPTR) 0)
+#define cbOPTR sizeof(OPTR)
+#define ioptNil -1
+
+/*
+ * File Indirect
+ *
+ * When a symbol is referenced across files the following procedure is used:
+ * 1) use the file index to get the File indirect entry.
+ * 2) use the file indirect entry to get the File descriptor.
+ * 3) add the sym index to the base of that file's sym table
+ *
+ */
+
+typedef long RFDT, *pRFDT;
+#define cbRFDT sizeof(RFDT)
+#define rfdNil -1
+
+/*
+ * The file indirect table in the mips loader is known as an array of FITs.
+ * This is done to keep the code in the loader readable in the area where
+ * these tables are merged. Note this is only a name change.
+ */
+typedef long FIT, *pFIT;
+#define cbFIT sizeof(FIT)
+#define ifiNil -1
+#define fiNil ((pFIT) 0)
+
+#ifdef _LANGUAGE_PASCAL
+#define ifdNil -1
+#define ilnNil -1
+#define ipdNil -1
+#define ilineNil -1
+#define isymNil -1
+#define indexNil 16#fffff
+#define issNil -1
+#define issNull 0
+#define itqMax 6
+#define iauxNil -1
+#define ioptNil -1
+#define rfdNil -1
+#define ifiNil -1
+#endif /* _LANGUAGE_PASCAL */
+
+
+/* Dense numbers
+ *
+ * Rather than use file index, symbol index pairs to represent symbols
+ * and globals, we use dense number so that they can be easily embeded
+ * in intermediate code and the programs that process them can
+ * use direct access tabls instead of hash table (which would be
+ * necesary otherwise because of the sparse name space caused by
+ * file index, symbol index pairs. Dense number are represented
+ * by RNDXRs.
+ */
+
+/*
+ * The following table defines the meaning of each SYM field as
+ * a function of the "st". (scD/B == scData OR scBss)
+ *
+ * Note: the value "isymMac" is used by symbols that have the concept
+ * of enclosing a block of related information. This value is the
+ * isym of the first symbol AFTER the end associated with the primary
+ * symbol. For example if a procedure was at isym==90 and had an
+ * isymMac==155, the associated end would be at isym==154, and the
+ * symbol at 155 would probably (although not necessarily) be the
+ * symbol for the next procedure. This allows rapid skipping over
+ * internal information of various sorts. "stEnd"s ALWAYS have the
+ * isym of the primary symbol that started the block.
+ *
+
+ST SC VALUE INDEX
+-------- ------ -------- ------
+stFile scText address isymMac
+stLabel scText address ---
+stGlobal scD/B address iaux
+stStatic scD/B address iaux
+stParam scAbs offset iaux
+stLocal scAbs offset iaux
+stProc scText address iaux (isymMac is first AUX)
+stStaticProc scText address iaux (isymMac is first AUX)
+
+stMember scNil ordinal --- (if member of enum)
+ (mipsread thinks the case below has a bit, not byte, offset.)
+stMember scNil byte offset iaux (if member of struct/union)
+stMember scBits bit offset iaux (bit field spec)
+
+stBlock scText address isymMac (text block)
+ (the code seems to think that rather than scNil, we see scInfo for
+ the two cases below.)
+stBlock scNil cb isymMac (struct/union member define)
+stBlock scNil cMembers isymMac (enum member define)
+
+ (New types added by SGI to simplify things:)
+stStruct scInfo cb isymMac (struct type define)
+stUnion scInfo cb isymMac (union type define)
+stEnum scInfo cMembers isymMac (enum type define)
+
+stEnd scText address isymStart
+stEnd scNil ------- isymStart (struct/union/enum)
+
+stTypedef scNil ------- iaux
+stRegReloc sc??? value old register number
+stForward sc??? new address isym to original symbol
+
+stConstant scInfo value --- (scalar)
+stConstant scInfo iss --- (complex, e.g. string)
+
+ *
+ */
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/coff/symconst.h b/gnu/usr.bin/gdb/gdb/coff/symconst.h
new file mode 100644
index 000000000000..e4ed620131dc
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/symconst.h
@@ -0,0 +1,175 @@
+/* Declarations of constants for internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/* glevels for field in FDR */
+#define GLEVEL_0 2
+#define GLEVEL_1 1
+#define GLEVEL_2 0 /* for upward compat reasons. */
+#define GLEVEL_3 3
+
+/* magic number fo symheader */
+#define magicSym 0x7009
+/* The Alpha uses this value instead, for some reason. */
+#define magicSym2 0x1992
+
+/* Language codes */
+#define langC 0
+#define langPascal 1
+#define langFortran 2
+#define langAssembler 3 /* one Assembley inst might map to many mach */
+#define langMachine 4
+#define langNil 5
+#define langAda 6
+#define langPl1 7
+#define langCobol 8
+#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */
+#define langCplusplus 9 /* FIXME: Collides with langStdc */
+#define langCplusplusV2 10 /* SGI addition */
+#define langMax 11 /* maximun allowed 32 -- 5 bits */
+
+/* The following are value definitions for the fields in the SYMR */
+
+/*
+ * Storage Classes
+ */
+
+#define scNil 0
+#define scText 1 /* text symbol */
+#define scData 2 /* initialized data symbol */
+#define scBss 3 /* un-initialized data symbol */
+#define scRegister 4 /* value of symbol is register number */
+#define scAbs 5 /* value of symbol is absolute */
+#define scUndefined 6 /* who knows? */
+#define scCdbLocal 7 /* variable's value is IN se->va.?? */
+#define scBits 8 /* this is a bit field */
+#define scCdbSystem 9 /* variable's value is IN CDB's address space */
+#define scDbx 9 /* overlap dbx internal use */
+#define scRegImage 10 /* register value saved on stack */
+#define scInfo 11 /* symbol contains debugger information */
+#define scUserStruct 12 /* address in struct user for current process */
+#define scSData 13 /* load time only small data */
+#define scSBss 14 /* load time only small common */
+#define scRData 15 /* load time only read only data */
+#define scVar 16 /* Var parameter (fortran,pascal) */
+#define scCommon 17 /* common variable */
+#define scSCommon 18 /* small common */
+#define scVarRegister 19 /* Var parameter in a register */
+#define scVariant 20 /* Variant record */
+#define scSUndefined 21 /* small undefined(external) data */
+#define scInit 22 /* .init section symbol */
+#define scBasedVar 23 /* Fortran or PL/1 ptr based var */
+#define scXData 24 /* exception handling data */
+#define scPData 25 /* Procedure section */
+#define scFini 26 /* .fini section */
+#define scMax 32
+
+
+/*
+ * Symbol Types
+ */
+
+#define stNil 0 /* Nuthin' special */
+#define stGlobal 1 /* external symbol */
+#define stStatic 2 /* static */
+#define stParam 3 /* procedure argument */
+#define stLocal 4 /* local variable */
+#define stLabel 5 /* label */
+#define stProc 6 /* " " Procedure */
+#define stBlock 7 /* beginnning of block */
+#define stEnd 8 /* end (of anything) */
+#define stMember 9 /* member (of anything - struct/union/enum */
+#define stTypedef 10 /* type definition */
+#define stFile 11 /* file name */
+#define stRegReloc 12 /* register relocation */
+#define stForward 13 /* forwarding address */
+#define stStaticProc 14 /* load time only static procs */
+#define stConstant 15 /* const */
+#define stStaParam 16 /* Fortran static parameters */
+ /* These new symbol types have been recently added to SGI machines. */
+#define stStruct 26 /* Beginning of block defining a struct type */
+#define stUnion 27 /* Beginning of block defining a union type */
+#define stEnum 28 /* Beginning of block defining an enum type */
+ /* Psuedo-symbols - internal to debugger */
+#define stStr 60 /* string */
+#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */
+#define stExpr 62 /* 2+2 vs. 4 */
+#define stType 63 /* post-coersion SER */
+#define stMax 64
+
+/* definitions for fields in TIR */
+
+/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */
+#define tqNil 0 /* bt is what you see */
+#define tqPtr 1 /* pointer */
+#define tqProc 2 /* procedure */
+#define tqArray 3 /* duh */
+#define tqFar 4 /* longer addressing - 8086/8 land */
+#define tqVol 5 /* volatile */
+#define tqConst 6 /* const */
+#define tqMax 8
+
+/* basic types as seen in ti.bt */
+#define btNil 0 /* undefined (also, enum members) */
+#define btAdr 1 /* address - integer same size as pointer */
+#define btChar 2 /* character */
+#define btUChar 3 /* unsigned character */
+#define btShort 4 /* short */
+#define btUShort 5 /* unsigned short */
+#define btInt 6 /* int */
+#define btUInt 7 /* unsigned int */
+#define btLong 8 /* long */
+#define btULong 9 /* unsigned long */
+#define btFloat 10 /* float (real) */
+#define btDouble 11 /* Double (real) */
+#define btStruct 12 /* Structure (Record) */
+#define btUnion 13 /* Union (variant) */
+#define btEnum 14 /* Enumerated */
+#define btTypedef 15 /* defined via a typedef, isymRef points */
+#define btRange 16 /* subrange of int */
+#define btSet 17 /* pascal sets */
+#define btComplex 18 /* fortran complex */
+#define btDComplex 19 /* fortran double complex */
+#define btIndirect 20 /* forward or unnamed typedef */
+#define btFixedDec 21 /* Fixed Decimal */
+#define btFloatDec 22 /* Float Decimal */
+#define btString 23 /* Varying Length Character String */
+#define btBit 24 /* Aligned Bit String */
+#define btPicture 25 /* Picture */
+#define btVoid 26 /* void */
+#define btLongLong 27 /* long long */
+#define btULongLong 28 /* unsigned long long */
+#define btMax 64
+
+#if (_MFG == _MIPS)
+/* optimization type codes */
+#define otNil 0
+#define otReg 1 /* move var to reg */
+#define otBlock 2 /* begin basic block */
+#define otProc 3 /* procedure */
+#define otInline 4 /* inline procedure */
+#define otEnd 5 /* whatever you started */
+#define otMax 6 /* KEEP UP TO DATE */
+#endif /* (_MFG == _MIPS) */
diff --git a/gnu/usr.bin/gdb/gdb/coffread.c b/gnu/usr.bin/gdb/gdb/coffread.c
new file mode 100644
index 000000000000..eb0905b867ac
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coffread.c
@@ -0,0 +1,2071 @@
+/* Read coff symbol tables and convert to internal format, for GDB.
+ Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu).
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "breakpoint.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include <obstack.h>
+
+#include <string.h>
+
+#include <time.h> /* For time_t in libbfd.h. */
+#include <sys/types.h> /* For time_t, if not in time.h. */
+#include "libbfd.h" /* FIXME secret internal data from BFD */
+#include "coff/internal.h" /* Internal format of COFF symbols in BFD */
+#include "libcoff.h" /* FIXME secret internal data from BFD */
+
+struct coff_symfile_info {
+ file_ptr min_lineno_offset; /* Where in file lowest line#s are */
+ file_ptr max_lineno_offset; /* 1+last byte of line#s in file */
+
+ asection *stabsect; /* Section pointer for .stab section */
+ asection *stabstrsect; /* Section pointer for .stab section */
+ asection *stabindexsect; /* Section pointer for .stab.index section */
+ char *stabstrdata;
+};
+
+/* Translate an external name string into a user-visible name. */
+#define EXTERNAL_NAME(string, abfd) \
+ (string[0] == bfd_get_symbol_leading_char(abfd)? string+1: string)
+
+/* To be an sdb debug type, type must have at least a basic or primary
+ derived type. Using this rather than checking against T_NULL is
+ said to prevent core dumps if we try to operate on Michael Bloom
+ dbx-in-coff file. */
+
+#define SDB_TYPE(type) (BTYPE(type) | (type & N_TMASK))
+
+/*
+ * Convert from an sdb register number to an internal gdb register number.
+ * This should be defined in tm.h, if REGISTER_NAMES is not set up
+ * to map one to one onto the sdb register numbers.
+ */
+#ifndef SDB_REG_TO_REGNUM
+# define SDB_REG_TO_REGNUM(value) (value)
+#endif
+
+/* Core address of start and end of text of current source file.
+ This comes from a ".text" symbol where x_nlinno > 0. */
+
+static CORE_ADDR cur_src_start_addr;
+static CORE_ADDR cur_src_end_addr;
+
+/* Core address of the end of the first object file. */
+static CORE_ADDR first_object_file_end;
+
+/* The addresses of the symbol table stream and number of symbols
+ of the object file we are reading (as copied into core). */
+
+static FILE *nlist_stream_global;
+static int nlist_nsyms_global;
+
+/* Vector of line number information. */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index. */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector. */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently. */
+
+static int line_vector_length;
+
+/* Pointers to scratch storage, used for reading raw symbols and auxents. */
+
+static char *temp_sym;
+static char *temp_aux;
+
+/* Local variables that hold the shift and mask values for the
+ COFF file that we are currently reading. These come back to us
+ from BFD, and are referenced by their macro names, as well as
+ internally to the BTYPE, ISPTR, ISFCN, ISARY, ISTAG, and DECREF
+ macros from ../internalcoff.h . */
+
+static unsigned local_n_btmask;
+static unsigned local_n_btshft;
+static unsigned local_n_tmask;
+static unsigned local_n_tshift;
+
+#define N_BTMASK local_n_btmask
+#define N_BTSHFT local_n_btshft
+#define N_TMASK local_n_tmask
+#define N_TSHIFT local_n_tshift
+
+/* Local variables that hold the sizes in the file of various COFF structures.
+ (We only need to know this to read them from the file -- BFD will then
+ translate the data in them, into `internal_xxx' structs in the right
+ byte order, alignment, etc.) */
+
+static unsigned local_linesz;
+static unsigned local_symesz;
+static unsigned local_auxesz;
+
+
+/* Chain of typedefs of pointers to empty struct/union types.
+ They are chained thru the SYMBOL_VALUE_CHAIN. */
+
+static struct symbol *opaque_type_chain[HASHSIZE];
+
+#if 0
+/* The type of the function we are currently reading in. This is
+ used by define_symbol to record the type of arguments to a function. */
+
+struct type *in_function_type;
+#endif
+
+struct pending_block *pending_blocks;
+
+/* Complaints about various problems in the file being read */
+
+struct complaint ef_complaint =
+ {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0};
+
+struct complaint bf_no_aux_complaint =
+ {"`.bf' symbol %d has no aux entry", 0, 0};
+
+struct complaint ef_no_aux_complaint =
+ {"`.ef' symbol %d has no aux entry", 0, 0};
+
+struct complaint lineno_complaint =
+ {"Line number pointer %d lower than start of line numbers", 0, 0};
+
+struct complaint unexpected_type_complaint =
+ {"Unexpected type for symbol %s", 0, 0};
+
+struct complaint bad_sclass_complaint =
+ {"Bad n_sclass for symbol %s", 0, 0};
+
+struct complaint misordered_blocks_complaint =
+ {"Blocks out of order at address %x", 0, 0};
+
+struct complaint tagndx_bad_complaint =
+ {"Symbol table entry for %s has bad tagndx value", 0, 0};
+
+struct complaint eb_complaint =
+ {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0};
+
+/* Simplified internal version of coff symbol table information */
+
+struct coff_symbol {
+ char *c_name;
+ int c_symnum; /* symbol number of this entry */
+ int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */
+ long c_value;
+ int c_sclass;
+ int c_secnum;
+ unsigned int c_type;
+};
+
+static struct type *
+coff_read_struct_type PARAMS ((int, int, int));
+
+static struct type *
+decode_base_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+decode_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+decode_function_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+coff_read_enum_type PARAMS ((int, int, int));
+
+static struct symbol *
+process_coff_symbol PARAMS ((struct coff_symbol *, union internal_auxent *,
+ struct objfile *));
+
+static void
+patch_opaque_types PARAMS ((struct symtab *));
+
+static void
+patch_type PARAMS ((struct type *, struct type *));
+
+static void
+enter_linenos PARAMS ((long, int, int));
+
+static void
+free_linetab PARAMS ((void));
+
+static int
+init_lineno PARAMS ((int, long, int));
+
+static char *
+getfilename PARAMS ((union internal_auxent *));
+
+static char *
+getsymname PARAMS ((struct internal_syment *));
+
+static void
+free_stringtab PARAMS ((void));
+
+static int
+init_stringtab PARAMS ((int, long));
+
+static void
+read_one_sym PARAMS ((struct coff_symbol *, struct internal_syment *,
+ union internal_auxent *));
+
+static void
+read_coff_symtab PARAMS ((long, int, struct objfile *));
+
+static void
+find_linenos PARAMS ((bfd *, sec_ptr, PTR));
+
+static void
+coff_symfile_init PARAMS ((struct objfile *));
+
+static void
+coff_new_init PARAMS ((struct objfile *));
+
+static void
+coff_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+coff_symfile_finish PARAMS ((struct objfile *));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type));
+
+static void
+coff_end_symtab PARAMS ((struct objfile *));
+
+static void
+complete_symtab PARAMS ((char *, CORE_ADDR, unsigned int));
+
+static void
+coff_start_symtab PARAMS ((void));
+
+static void
+coff_record_line PARAMS ((int, CORE_ADDR));
+
+static struct type *
+coff_alloc_type PARAMS ((int));
+
+static struct type **
+coff_lookup_type PARAMS ((int));
+
+
+static void
+coff_locate_sections PARAMS ((bfd *, asection *, PTR));
+
+/* We are called once per section from coff_symfile_read. We
+ need to examine each section we are passed, check to see
+ if it is something we are interested in processing, and
+ if so, stash away some access information for the section.
+
+ FIXME: The section names should not be hardwired strings (what
+ should they be? I don't think most object file formats have enough
+ section flags to specify what kind of debug section it is
+ -kingdon). */
+
+static void
+coff_locate_sections (ignore_abfd, sectp, csip)
+ bfd *ignore_abfd;
+ asection *sectp;
+ PTR csip;
+{
+ register struct coff_symfile_info *csi;
+
+ csi = (struct coff_symfile_info *) csip;
+ if (STREQ (sectp->name, ".stab"))
+ {
+ csi->stabsect = sectp;
+ }
+ else if (STREQ (sectp->name, ".stabstr"))
+ {
+ csi->stabstrsect = sectp;
+ }
+ else if (STREQ (sectp->name, ".stab.index"))
+ {
+ csi->stabindexsect = sectp;
+ }
+}
+
+/* Look up a coff type-number index. Return the address of the slot
+ where the type for that index is stored.
+ The type-number is in INDEX.
+
+ This can be used for finding the type associated with that index
+ or for associating a new type with the index. */
+
+static struct type **
+coff_lookup_type (index)
+ register int index;
+{
+ if (index >= type_vector_length)
+ {
+ int old_vector_length = type_vector_length;
+
+ type_vector_length *= 2;
+ if (index /* is still */ >= type_vector_length) {
+ type_vector_length = index * 2;
+ }
+ type_vector = (struct type **)
+ xrealloc ((char *) type_vector,
+ type_vector_length * sizeof (struct type *));
+ memset (&type_vector[old_vector_length], 0,
+ (type_vector_length - old_vector_length) * sizeof(struct type *));
+ }
+ return &type_vector[index];
+}
+
+/* Make sure there is a type allocated for type number index
+ and return the type object.
+ This can create an empty (zeroed) type object. */
+
+static struct type *
+coff_alloc_type (index)
+ int index;
+{
+ register struct type **type_addr = coff_lookup_type (index);
+ register struct type *type = *type_addr;
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (type == NULL)
+ {
+ type = alloc_type (current_objfile);
+ *type_addr = type;
+ }
+ return type;
+}
+
+/* Record a line number entry for line LINE at address PC.
+ FIXME: Use record_line instead. */
+
+static void
+coff_record_line (line, pc)
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Make sure line vector is big enough. */
+
+ if (line_vector_index + 2 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc ((char *) line_vector, sizeof (struct linetable)
+ + (line_vector_length
+ * sizeof (struct linetable_entry)));
+ }
+
+ e = line_vector->item + line_vector_index++;
+ e->line = line; e->pc = pc;
+}
+
+/* Start a new symtab for a new source file.
+ This is called when a COFF ".file" symbol is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+coff_start_symtab ()
+{
+ start_symtab (
+ /* We fill in the filename later. start_symtab
+ puts this pointer into last_source file and in
+ coff_end_symtab we assume we can free() it.
+ FIXME: leaks memory. */
+ savestring ("", 0),
+ /* We never know the directory name for COFF. */
+ NULL,
+ /* The start address is irrelevant, since we set
+ last_source_start_addr in coff_end_symtab. */
+ 0);
+
+ /* Initialize the source file line number information for this file. */
+
+ if (line_vector) /* Unlikely, but maybe possible? */
+ free ((PTR)line_vector);
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+}
+
+/* Save the vital information from when starting to read a file,
+ for use when closing off the current file.
+ NAME is the file name the symbols came from, START_ADDR is the first
+ text address for the file, and SIZE is the number of bytes of text. */
+
+static void
+complete_symtab (name, start_addr, size)
+ char *name;
+ CORE_ADDR start_addr;
+ unsigned int size;
+{
+ last_source_file = savestring (name, strlen (name));
+ cur_src_start_addr = start_addr;
+ cur_src_end_addr = start_addr + size;
+
+ if (current_objfile -> ei.entry_point >= cur_src_start_addr &&
+ current_objfile -> ei.entry_point < cur_src_end_addr)
+ {
+ current_objfile -> ei.entry_file_lowpc = cur_src_start_addr;
+ current_objfile -> ei.entry_file_highpc = cur_src_end_addr;
+ }
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the
+ struct symtab for that file and put it in the list of all such. */
+
+static void
+coff_end_symtab (objfile)
+ struct objfile *objfile;
+{
+ struct symtab *symtab;
+
+ last_source_start_addr = cur_src_start_addr;
+
+ /* For no good reason, this file stores the number of entries in a
+ separate variable instead of in line_vector->nitems. Fix it. */
+ if (line_vector)
+ line_vector->nitems = line_vector_index;
+
+ /* For COFF, we only have one subfile, so we can just look at
+ subfiles and not worry about there being other elements in the
+ chain. We fill in various fields now because we didn't know them
+ before (or because doing it now is simply an artifact of how this
+ file used to be written). */
+ subfiles->line_vector = line_vector;
+ subfiles->name = last_source_file;
+
+ /* sort_pending is needed for amdcoff, at least.
+ sort_linevec is needed for the SCO compiler. */
+ symtab = end_symtab (cur_src_end_addr, 1, 1, objfile, 0);
+
+ if (symtab != NULL)
+ free_named_symtabs (symtab->filename);
+
+ /* Reinitialize for beginning of new file. */
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = NULL;
+}
+
+static void
+record_minimal_symbol (name, address, type)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type type;
+{
+ /* We don't want TDESC entry points in the minimal symbol table */
+ if (name[0] == '@') return;
+
+ prim_record_minimal_symbol (savestring (name, strlen (name)), address, type);
+}
+
+/* coff_symfile_init ()
+ is the coff-specific initialization routine for reading symbols.
+ It is passed a struct objfile which contains, among other things,
+ the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we fill with cookies and other
+ treats for coff_symfile_read ().
+
+ We will only be called if this is a COFF or COFF-like file.
+ BFD handles figuring out the format of the file, and code in symtab.c
+ uses BFD's determination to vector to us.
+
+ The ultimate result is a new symtab (or, FIXME, eventually a psymtab). */
+
+static int text_bfd_scnum;
+
+static void
+coff_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ asection *section, *strsection;
+ bfd *abfd = objfile->obfd;
+
+ /* Allocate struct to keep track of stab reading. */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+
+ memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+
+ /* Allocate struct to keep track of the symfile */
+ objfile -> sym_private = xmmalloc (objfile -> md,
+ sizeof (struct coff_symfile_info));
+
+ memset (objfile->sym_private, 0, sizeof (struct coff_symfile_info));
+
+ init_entry_point_info (objfile);
+
+ /* Save the section number for the text section */
+ section = bfd_get_section_by_name (abfd, ".text");
+ if (section)
+ text_bfd_scnum = section->index;
+ else
+ text_bfd_scnum = -1;
+}
+
+/* This function is called for every section; it finds the outer limits
+ of the line table (minimum and maximum file offset) so that the
+ mainline code can read the whole thing for efficiency. */
+
+/* ARGSUSED */
+static void
+find_linenos (abfd, asect, vpinfo)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR vpinfo;
+{
+ struct coff_symfile_info *info;
+ int size, count;
+ file_ptr offset, maxoff;
+
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ count = asect->lineno_count;
+/* End of warning */
+
+ if (count == 0)
+ return;
+ size = count * local_linesz;
+
+ info = (struct coff_symfile_info *)vpinfo;
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ offset = asect->line_filepos;
+/* End of warning */
+
+ if (offset < info->min_lineno_offset || info->min_lineno_offset == 0)
+ info->min_lineno_offset = offset;
+
+ maxoff = offset + size;
+ if (maxoff > info->max_lineno_offset)
+ info->max_lineno_offset = maxoff;
+}
+
+
+/* The BFD for this file -- only good while we're actively reading
+ symbols into a psymtab or a symtab. */
+
+static bfd *symfile_bfd;
+
+/* Read a symbol file, after initialization by coff_symfile_init. */
+/* FIXME! Addr and Mainline are not used yet -- this will not work for
+ shared libraries or add_file! */
+
+/* ARGSUSED */
+static void
+coff_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ struct coff_symfile_info *info;
+ struct dbx_symfile_info *dbxinfo;
+ bfd *abfd = objfile->obfd;
+ coff_data_type *cdata = coff_data (abfd);
+ char *name = bfd_get_filename (abfd);
+ int desc;
+ register int val;
+ int num_symbols;
+ int symtab_offset;
+ int stringtab_offset;
+ struct cleanup *back_to;
+ int stabsize, stabstrsize;
+
+ info = (struct coff_symfile_info *) objfile -> sym_private;
+ dbxinfo = (struct dbx_symfile_info *) objfile->sym_stab_info;
+ symfile_bfd = abfd; /* Kludge for swap routines */
+
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ desc = fileno ((FILE *)(abfd->iostream)); /* File descriptor */
+ num_symbols = bfd_get_symcount (abfd); /* How many syms */
+ symtab_offset = cdata->sym_filepos; /* Symbol table file offset */
+ stringtab_offset = symtab_offset + /* String table file offset */
+ num_symbols * cdata->local_symesz;
+
+ /* Set a few file-statics that give us specific information about
+ the particular COFF file format we're reading. */
+ local_linesz = cdata->local_linesz;
+ local_n_btmask = cdata->local_n_btmask;
+ local_n_btshft = cdata->local_n_btshft;
+ local_n_tmask = cdata->local_n_tmask;
+ local_n_tshift = cdata->local_n_tshift;
+ local_linesz = cdata->local_linesz;
+ local_symesz = cdata->local_symesz;
+ local_auxesz = cdata->local_auxesz;
+
+ /* Allocate space for raw symbol and aux entries, based on their
+ space requirements as reported by BFD. */
+ temp_sym = (char *) xmalloc
+ (cdata->local_symesz + cdata->local_auxesz);
+ temp_aux = temp_sym + cdata->local_symesz;
+ back_to = make_cleanup (free_current_contents, &temp_sym);
+/* End of warning */
+
+ /* Read the line number table, all at once. */
+ info->min_lineno_offset = 0;
+ info->max_lineno_offset = 0;
+ bfd_map_over_sections (abfd, find_linenos, (PTR) info);
+
+ make_cleanup (free_linetab, 0);
+ val = init_lineno (desc, info->min_lineno_offset,
+ info->max_lineno_offset - info->min_lineno_offset);
+ if (val < 0)
+ error ("\"%s\": error reading line numbers\n", name);
+
+ /* Now read the string table, all at once. */
+
+ make_cleanup (free_stringtab, 0);
+ val = init_stringtab (desc, stringtab_offset);
+ if (val < 0)
+ error ("\"%s\": can't get string table", name);
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ read_coff_symtab ((long)symtab_offset, num_symbols, objfile);
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_all_symtab_syms ();
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ bfd_map_over_sections (abfd, coff_locate_sections, (PTR) info);
+
+ if (info->stabsect)
+ {
+ /* FIXME: dubious. Why can't we use something normal like
+ bfd_get_section_contents? */
+ fseek ((FILE *) abfd->iostream, abfd->where, 0);
+
+ stabsize = bfd_section_size (abfd, info->stabsect);
+ stabstrsize = bfd_section_size (abfd, info->stabstrsect);
+
+ coffstab_build_psymtabs (objfile,
+ section_offsets,
+ mainline,
+ info->stabsect->filepos, stabsize,
+ info->stabstrsect->filepos, stabstrsize);
+ }
+
+ do_cleanups (back_to);
+}
+
+static void
+coff_new_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+coff_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_private != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_private);
+ }
+}
+
+
+/* Given pointers to a symbol table in coff style exec file,
+ analyze them and create struct symtab's describing the symbols.
+ NSYMS is the number of symbols in the symbol table.
+ We read them one at a time using read_one_sym (). */
+
+static void
+read_coff_symtab (symtab_offset, nsyms, objfile)
+ long symtab_offset;
+ int nsyms;
+ struct objfile *objfile;
+{
+ FILE *stream;
+ register struct context_stack *new;
+ struct coff_symbol coff_symbol;
+ register struct coff_symbol *cs = &coff_symbol;
+ static struct internal_syment main_sym;
+ static union internal_auxent main_aux;
+ struct coff_symbol fcn_cs_saved;
+ static struct internal_syment fcn_sym_saved;
+ static union internal_auxent fcn_aux_saved;
+ struct symtab *s;
+
+ /* A .file is open. */
+ int in_source_file = 0;
+ int num_object_files = 0;
+ int next_file_symnum = -1;
+
+ /* Name of the current file. */
+ char *filestring = "";
+ int depth = 0;
+ int fcn_first_line = 0;
+ int fcn_last_line = 0;
+ int fcn_start_addr = 0;
+ long fcn_line_ptr = 0;
+ int val;
+
+ stream = bfd_cache_lookup(objfile->obfd);
+ if (!stream)
+ perror_with_name(objfile->name);
+
+ /* Work around a stdio bug in SunOS4.1.1 (this makes me nervous....
+ it's hard to know I've really worked around it. The fix should be
+ harmless, anyway). The symptom of the bug is that the first
+ fread (in read_one_sym), will (in my example) actually get data
+ from file offset 268, when the fseek was to 264 (and ftell shows
+ 264). This causes all hell to break loose. I was unable to
+ reproduce this on a short test program which operated on the same
+ file, performing (I think) the same sequence of operations.
+
+ It stopped happening when I put in this rewind().
+
+ FIXME: Find out if this has been reported to Sun, whether it has
+ been fixed in a later release, etc. */
+
+ rewind (stream);
+
+ /* Position to read the symbol table. */
+ val = fseek (stream, (long)symtab_offset, 0);
+ if (val < 0)
+ perror_with_name (objfile->name);
+
+ current_objfile = objfile;
+ nlist_stream_global = stream;
+ nlist_nsyms_global = nsyms;
+ last_source_file = NULL;
+ memset (opaque_type_chain, 0, sizeof opaque_type_chain);
+
+ if (type_vector) /* Get rid of previous one */
+ free ((PTR)type_vector);
+ type_vector_length = 160;
+ type_vector = (struct type **)
+ xmalloc (type_vector_length * sizeof (struct type *));
+ memset (type_vector, 0, type_vector_length * sizeof (struct type *));
+
+ coff_start_symtab ();
+
+ symnum = 0;
+ while (symnum < nsyms)
+ {
+ QUIT; /* Make this command interruptable. */
+ read_one_sym (cs, &main_sym, &main_aux);
+
+#ifdef SEM
+ temp_sem_val = cs->c_name[0] << 24 | cs->c_name[1] << 16 |
+ cs->c_name[2] << 8 | cs->c_name[3];
+ if (int_sem_val == temp_sem_val)
+ last_coffsem = (int) strtol (cs->c_name+4, (char **) NULL, 10);
+#endif
+
+ if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE)
+ {
+ if (last_source_file)
+ coff_end_symtab (objfile);
+
+ coff_start_symtab ();
+ complete_symtab ("_globals_", 0, first_object_file_end);
+ /* done with all files, everything from here on out is globals */
+ }
+
+ /* Special case for file with type declarations only, no text. */
+ if (!last_source_file && SDB_TYPE (cs->c_type)
+ && cs->c_secnum == N_DEBUG)
+ complete_symtab (filestring, 0, 0);
+
+ /* Typedefs should not be treated as symbol definitions. */
+ if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF)
+ {
+ /* Record all functions -- external and static -- in minsyms. */
+ record_minimal_symbol (cs->c_name, cs->c_value, mst_text);
+
+ fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr;
+ fcn_start_addr = cs->c_value;
+ fcn_cs_saved = *cs;
+ fcn_sym_saved = main_sym;
+ fcn_aux_saved = main_aux;
+ continue;
+ }
+
+ switch (cs->c_sclass)
+ {
+ case C_EFCN:
+ case C_EXTDEF:
+ case C_ULABEL:
+ case C_USTATIC:
+ case C_LINE:
+ case C_ALIAS:
+ case C_HIDDEN:
+ complain (&bad_sclass_complaint, cs->c_name);
+ break;
+
+ case C_FILE:
+ /*
+ * c_value field contains symnum of next .file entry in table
+ * or symnum of first global after last .file.
+ */
+ next_file_symnum = cs->c_value;
+ if (cs->c_naux > 0)
+ filestring = getfilename (&main_aux);
+ else
+ filestring = "";
+
+ /*
+ * Complete symbol table for last object file
+ * containing debugging information.
+ */
+ if (last_source_file)
+ {
+ coff_end_symtab (objfile);
+ coff_start_symtab ();
+ }
+ in_source_file = 1;
+ break;
+
+ case C_STAT:
+ if (cs->c_name[0] == '.') {
+ if (STREQ (cs->c_name, ".text")) {
+ /* FIXME: don't wire in ".text" as section name
+ or symbol name! */
+ if (++num_object_files == 1) {
+ /* last address of startup file */
+ first_object_file_end = cs->c_value +
+ main_aux.x_scn.x_scnlen;
+ }
+ /* Check for in_source_file deals with case of
+ a file with debugging symbols
+ followed by a later file with no symbols. */
+ if (in_source_file)
+ complete_symtab (filestring, cs->c_value,
+ main_aux.x_scn.x_scnlen);
+ in_source_file = 0;
+ }
+ /* flush rest of '.' symbols */
+ break;
+ }
+ else if (!SDB_TYPE (cs->c_type)
+ && cs->c_name[0] == 'L'
+ && (strncmp (cs->c_name, "LI%", 3) == 0
+ || strncmp (cs->c_name, "LF%", 3) == 0
+ || strncmp (cs->c_name,"LC%",3) == 0
+ || strncmp (cs->c_name,"LP%",3) == 0
+ || strncmp (cs->c_name,"LPB%",4) == 0
+ || strncmp (cs->c_name,"LBB%",4) == 0
+ || strncmp (cs->c_name,"LBE%",4) == 0
+ || strncmp (cs->c_name,"LPBX%",5) == 0))
+ /* At least on a 3b1, gcc generates swbeg and string labels
+ that look like this. Ignore them. */
+ break;
+ /* fall in for static symbols that don't start with '.' */
+ case C_EXT:
+ /* Record external symbols in minsyms if we don't have debug
+ info for them. FIXME, this is probably the wrong thing
+ to do. Why don't we record them even if we do have
+ debug symbol info? What really belongs in the minsyms
+ anyway? Fred!?? */
+ if (!SDB_TYPE (cs->c_type)) {
+ /* FIXME: This is BOGUS Will Robinson!
+ Coff should provide the SEC_CODE flag for executable sections,
+ then if we could look up sections by section number we
+ could see if the flags indicate SEC_CODE. If so, then
+ record this symbol as a function in the minimal symbol table.
+ But why are absolute syms recorded as functions, anyway? */
+ if (cs->c_secnum <= text_bfd_scnum+1) {/* text or abs */
+ record_minimal_symbol (cs->c_name, cs->c_value,
+ mst_text);
+ break;
+ } else {
+ record_minimal_symbol (cs->c_name, cs->c_value,
+ mst_data);
+ break;
+ }
+ }
+ process_coff_symbol (cs, &main_aux, objfile);
+ break;
+
+ case C_FCN:
+ if (STREQ (cs->c_name, ".bf"))
+ {
+ within_function = 1;
+
+ /* value contains address of first non-init type code */
+ /* main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains line number of '{' } */
+ if (cs->c_naux != 1)
+ complain (&bf_no_aux_complaint, cs->c_symnum);
+ fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+
+ /* Might want to check that locals are 0 and
+ context_stack_depth is zero, and complain if not. */
+
+ depth = 0;
+ new = push_context (depth, fcn_start_addr);
+ fcn_cs_saved.c_name = getsymname (&fcn_sym_saved);
+ new->name = process_coff_symbol (&fcn_cs_saved,
+ &fcn_aux_saved, objfile);
+ }
+ else if (STREQ (cs->c_name, ".ef"))
+ {
+ /* the value of .ef is the address of epilogue code;
+ not useful for gdb. */
+ /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains number of lines to '}' */
+ new = pop_context ();
+ /* Stack must be empty now. */
+ if (context_stack_depth > 0 || new == NULL)
+ {
+ complain (&ef_complaint, cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+ if (cs->c_naux != 1)
+ {
+ complain (&ef_no_aux_complaint, cs->c_symnum);
+ fcn_last_line = 0x7FFFFFFF;
+ }
+ else
+ {
+ fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+ }
+ enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line);
+
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr,
+#if defined (FUNCTION_EPILOGUE_SIZE)
+ /* This macro should be defined only on
+ machines where the
+ fcn_aux_saved.x_sym.x_misc.x_fsize
+ field is always zero.
+ So use the .bf record information that
+ points to the epilogue and add the size
+ of the epilogue. */
+ cs->c_value + FUNCTION_EPILOGUE_SIZE,
+#else
+ fcn_cs_saved.c_value +
+ fcn_aux_saved.x_sym.x_misc.x_fsize,
+#endif
+ objfile
+ );
+ within_function = 0;
+ }
+ break;
+
+ case C_BLOCK:
+ if (STREQ (cs->c_name, ".bb"))
+ {
+ push_context (++depth, cs->c_value);
+ }
+ else if (STREQ (cs->c_name, ".eb"))
+ {
+ new = pop_context ();
+ if (depth-- != new->depth)
+ {
+ complain (&eb_complaint, symnum);
+ break;
+ }
+ if (local_symbols && context_stack_depth > 0)
+ {
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, cs->c_value, objfile);
+ }
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ }
+ break;
+
+ default:
+ process_coff_symbol (cs, &main_aux, objfile);
+ break;
+ }
+ }
+
+ if (last_source_file)
+ coff_end_symtab (objfile);
+
+ /* Patch up any opaque types (references to types that are not defined
+ in the file where they are referenced, e.g. "struct foo *bar"). */
+ ALL_OBJFILE_SYMTABS (objfile, s)
+ patch_opaque_types (s);
+
+ current_objfile = NULL;
+}
+
+/* Routines for reading headers and symbols from executable. */
+
+#ifdef FIXME
+/* Move these XXXMAGIC symbol defns into BFD! */
+
+/* Read COFF file header, check magic number,
+ and return number of symbols. */
+read_file_hdr (chan, file_hdr)
+ int chan;
+ FILHDR *file_hdr;
+{
+ lseek (chan, 0L, 0);
+ if (myread (chan, (char *)file_hdr, FILHSZ) < 0)
+ return -1;
+
+ switch (file_hdr->f_magic)
+ {
+#ifdef MC68MAGIC
+ case MC68MAGIC:
+#endif
+#ifdef NS32GMAGIC
+ case NS32GMAGIC:
+ case NS32SMAGIC:
+#endif
+#ifdef I386MAGIC
+ case I386MAGIC:
+#endif
+#ifdef CLIPPERMAGIC
+ case CLIPPERMAGIC:
+#endif
+#if defined (MC68KWRMAGIC) \
+ && (!defined (MC68MAGIC) || MC68KWRMAGIC != MC68MAGIC)
+ case MC68KWRMAGIC:
+#endif
+#ifdef MC68KROMAGIC
+ case MC68KROMAGIC:
+ case MC68KPGMAGIC:
+#endif
+#ifdef MC88DGMAGIC
+ case MC88DGMAGIC:
+#endif
+#ifdef MC88MAGIC
+ case MC88MAGIC:
+#endif
+#ifdef I960ROMAGIC
+ case I960ROMAGIC: /* Intel 960 */
+#endif
+#ifdef I960RWMAGIC
+ case I960RWMAGIC: /* Intel 960 */
+#endif
+ return file_hdr->f_nsyms;
+
+ default:
+#ifdef BADMAG
+ if (BADMAG(file_hdr))
+ return -1;
+ else
+ return file_hdr->f_nsyms;
+#else
+ return -1;
+#endif
+ }
+}
+#endif
+
+/* Read the next symbol, swap it, and return it in both internal_syment
+ form, and coff_symbol form. Also return its first auxent, if any,
+ in internal_auxent form, and skip any other auxents. */
+
+static void
+read_one_sym (cs, sym, aux)
+ register struct coff_symbol *cs;
+ register struct internal_syment *sym;
+ register union internal_auxent *aux;
+{
+ int i;
+
+ cs->c_symnum = symnum;
+ fread (temp_sym, local_symesz, 1, nlist_stream_global);
+ bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *)sym);
+ cs->c_naux = sym->n_numaux & 0xff;
+ if (cs->c_naux >= 1)
+ {
+ fread (temp_aux, local_auxesz, 1, nlist_stream_global);
+ bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass,
+ (char *)aux);
+ /* If more than one aux entry, read past it (only the first aux
+ is important). */
+ for (i = 1; i < cs->c_naux; i++)
+ fread (temp_aux, local_auxesz, 1, nlist_stream_global);
+ }
+ cs->c_name = getsymname (sym);
+ cs->c_value = sym->n_value;
+ cs->c_sclass = (sym->n_sclass & 0xff);
+ cs->c_secnum = sym->n_scnum;
+ cs->c_type = (unsigned) sym->n_type;
+ if (!SDB_TYPE (cs->c_type))
+ cs->c_type = 0;
+
+ symnum += 1 + cs->c_naux;
+}
+
+/* Support for string table handling */
+
+static char *stringtab = NULL;
+
+static int
+init_stringtab (chan, offset)
+ int chan;
+ long offset;
+{
+ long length;
+ int val;
+ unsigned char lengthbuf[4];
+
+ free_stringtab ();
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ val = myread (chan, (char *)lengthbuf, sizeof lengthbuf);
+ length = bfd_h_get_32 (symfile_bfd, lengthbuf);
+
+ /* If no string table is needed, then the file may end immediately
+ after the symbols. Just return with `stringtab' set to null. */
+ if (val != sizeof lengthbuf || length < sizeof lengthbuf)
+ return 0;
+
+ stringtab = (char *) xmalloc (length);
+ memcpy (stringtab, &length, sizeof length);
+ if (length == sizeof length) /* Empty table -- just the count */
+ return 0;
+
+ val = myread (chan, stringtab + sizeof lengthbuf, length - sizeof lengthbuf);
+ if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0')
+ return -1;
+
+ return 0;
+}
+
+static void
+free_stringtab ()
+{
+ if (stringtab)
+ free (stringtab);
+ stringtab = NULL;
+}
+
+static char *
+getsymname (symbol_entry)
+ struct internal_syment *symbol_entry;
+{
+ static char buffer[SYMNMLEN+1];
+ char *result;
+
+ if (symbol_entry->_n._n_n._n_zeroes == 0)
+ {
+ result = stringtab + symbol_entry->_n._n_n._n_offset;
+ }
+ else
+ {
+ strncpy (buffer, symbol_entry->_n._n_name, SYMNMLEN);
+ buffer[SYMNMLEN] = '\0';
+ result = buffer;
+ }
+ return result;
+}
+
+/* Extract the file name from the aux entry of a C_FILE symbol. Return
+ only the last component of the name. Result is in static storage and
+ is only good for temporary use. */
+
+static char *
+getfilename (aux_entry)
+ union internal_auxent *aux_entry;
+{
+ static char buffer[BUFSIZ];
+ register char *temp;
+ char *result;
+
+ if (aux_entry->x_file.x_n.x_zeroes == 0)
+ strcpy (buffer, stringtab + aux_entry->x_file.x_n.x_offset);
+ else
+ {
+ strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN);
+ buffer[FILNMLEN] = '\0';
+ }
+ result = buffer;
+ if ((temp = strrchr (result, '/')) != NULL)
+ result = temp + 1;
+ return (result);
+}
+
+/* Support for line number handling */
+static char *linetab = NULL;
+static long linetab_offset;
+static unsigned long linetab_size;
+
+/* Read in all the line numbers for fast lookups later. Leave them in
+ external (unswapped) format in memory; we'll swap them as we enter
+ them into GDB's data structures. */
+
+static int
+init_lineno (chan, offset, size)
+ int chan;
+ long offset;
+ int size;
+{
+ int val;
+
+ linetab_offset = offset;
+ linetab_size = size;
+
+ free_linetab();
+
+ if (size == 0)
+ return 0;
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ /* Allocate the desired table, plus a sentinel */
+ linetab = (char *) xmalloc (size + local_linesz);
+
+ val = myread (chan, linetab, size);
+ if (val != size)
+ return -1;
+
+ /* Terminate it with an all-zero sentinel record */
+ memset (linetab + size, 0, local_linesz);
+
+ return 0;
+}
+
+static void
+free_linetab ()
+{
+ if (linetab)
+ free (linetab);
+ linetab = NULL;
+}
+
+#if !defined (L_LNNO32)
+#define L_LNNO32(lp) ((lp)->l_lnno)
+#endif
+
+static void
+enter_linenos (file_offset, first_line, last_line)
+ long file_offset;
+ register int first_line;
+ register int last_line;
+{
+ register char *rawptr;
+ struct internal_lineno lptr;
+
+ if (file_offset < linetab_offset)
+ {
+ complain (&lineno_complaint, file_offset);
+ if (file_offset > linetab_size) /* Too big to be an offset? */
+ return;
+ file_offset += linetab_offset; /* Try reading at that linetab offset */
+ }
+
+ rawptr = &linetab[file_offset - linetab_offset];
+
+ /* skip first line entry for each function */
+ rawptr += local_linesz;
+ /* line numbers start at one for the first line of the function */
+ first_line--;
+
+ for (;;) {
+ bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr);
+ rawptr += local_linesz;
+ /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */
+ if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line)
+ coff_record_line (first_line + L_LNNO32 (&lptr), lptr.l_addr.l_paddr);
+ else
+ break;
+ }
+}
+
+static void
+patch_type (type, real_type)
+ struct type *type;
+ struct type *real_type;
+{
+ register struct type *target = TYPE_TARGET_TYPE (type);
+ register struct type *real_target = TYPE_TARGET_TYPE (real_type);
+ int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field);
+
+ TYPE_LENGTH (target) = TYPE_LENGTH (real_target);
+ TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target);
+ TYPE_FIELDS (target) = (struct field *) TYPE_ALLOC (target, field_size);
+
+ memcpy (TYPE_FIELDS (target), TYPE_FIELDS (real_target), field_size);
+
+ if (TYPE_NAME (real_target))
+ {
+ if (TYPE_NAME (target))
+ free (TYPE_NAME (target));
+ TYPE_NAME (target) = concat (TYPE_NAME (real_target), NULL);
+ }
+}
+
+/* Patch up all appropriate typedef symbols in the opaque_type_chains
+ so that they can be used to print out opaque data structures properly. */
+
+static void
+patch_opaque_types (s)
+ struct symtab *s;
+{
+ register struct block *b;
+ register int i;
+ register struct symbol *real_sym;
+
+ /* Go through the per-file symbols only */
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ /* Find completed typedefs to use to fix opaque ones.
+ Remove syms from the chain when their types are stored,
+ but search the whole chain, as there may be several syms
+ from different files with the same name. */
+ real_sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
+ SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE &&
+ TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0)
+ {
+ register char *name = SYMBOL_NAME (real_sym);
+ register int hash = hashname (name);
+ register struct symbol *sym, *prev;
+
+ prev = 0;
+ for (sym = opaque_type_chain[hash]; sym;)
+ {
+ if (name[0] == SYMBOL_NAME (sym)[0] &&
+ STREQ (name + 1, SYMBOL_NAME (sym) + 1))
+ {
+ if (prev)
+ {
+ SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+ }
+ else
+ {
+ opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+ }
+
+ patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym));
+
+ if (prev)
+ {
+ sym = SYMBOL_VALUE_CHAIN (prev);
+ }
+ else
+ {
+ sym = opaque_type_chain[hash];
+ }
+ }
+ else
+ {
+ prev = sym;
+ sym = SYMBOL_VALUE_CHAIN (sym);
+ }
+ }
+ }
+ }
+}
+
+static struct symbol *
+process_coff_symbol (cs, aux, objfile)
+ register struct coff_symbol *cs;
+ register union internal_auxent *aux;
+ struct objfile *objfile;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+ char *name;
+ struct type *temptype;
+
+ memset (sym, 0, sizeof (struct symbol));
+ name = cs->c_name;
+ name = EXTERNAL_NAME (name, objfile->obfd);
+ SYMBOL_NAME (sym) = obstack_copy0 (&objfile->symbol_obstack, name,
+ strlen (name));
+
+ /* default assumptions */
+ SYMBOL_VALUE (sym) = cs->c_value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ if (ISFCN (cs->c_type))
+ {
+#if 0
+ /* FIXME: This has NOT been tested. The DBX version has.. */
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ struct type *new = (struct type *)
+ obstack_alloc (&objfile->symbol_obstack, sizeof (struct type));
+
+ memcpy (new, lookup_function_type (decode_function_type (cs, cs->c_type, aux)),
+ sizeof(struct type));
+ SYMBOL_TYPE (sym) = new;
+ in_function_type = SYMBOL_TYPE(sym);
+#else
+ SYMBOL_TYPE(sym) =
+ lookup_function_type (decode_function_type (cs, cs->c_type, aux));
+#endif
+
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ if (cs->c_sclass == C_STAT)
+ add_symbol_to_list (sym, &file_symbols);
+ else if (cs->c_sclass == C_EXT)
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux);
+ switch (cs->c_sclass)
+ {
+ case C_NULL:
+ break;
+
+ case C_AUTO:
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_EXT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case C_STAT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ if (within_function) {
+ /* Static symbol of local scope */
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else {
+ /* Static symbol at top level of file */
+ add_symbol_to_list (sym, &file_symbols);
+ }
+ break;
+
+#ifdef C_GLBLREG /* AMD coff */
+ case C_GLBLREG:
+#endif
+ case C_REG:
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value);
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_LABEL:
+ break;
+
+ case C_ARG:
+ SYMBOL_CLASS (sym) = LOC_ARG;
+#if 0
+ /* FIXME: This has not been tested. */
+ /* Add parameter to function. */
+ add_param_to_type(&in_function_type,sym);
+#endif
+ add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION) && (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ /* If PCC says a parameter is a short or a char,
+ aligned on an int boundary, realign it to the "little end"
+ of the int. */
+ temptype = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT
+ && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype))
+ {
+ SYMBOL_VALUE (sym) += TYPE_LENGTH (temptype)
+ - TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+#endif
+ break;
+
+ case C_REGPARM:
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value);
+ add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION)
+ /* FIXME: This should retain the current type, since it's just
+ a register value. gnu@adobe, 26Feb93 */
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ temptype = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT)
+ {
+ SYMBOL_TYPE (sym) = TYPE_UNSIGNED (SYMBOL_TYPE (sym))
+ ? lookup_fundamental_type (current_objfile,
+ FT_UNSIGNED_INTEGER)
+ : temptype;
+ }
+#endif
+ break;
+
+ case C_TPDEF:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ /* If type has no name, give it one */
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym)) = concat (SYMBOL_NAME (sym), NULL);
+
+ /* Keep track of any type which points to empty structured type,
+ so it can be filled from a definition from another file. A
+ simple forward reference (TYPE_CODE_UNDEF) is not an
+ empty structured type, though; the forward references
+ work themselves out via the magic of coff_lookup_type. */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 &&
+ TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) !=
+ TYPE_CODE_UNDEF)
+ {
+ register int i = hashname (SYMBOL_NAME (sym));
+
+ SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i];
+ opaque_type_chain[i] = sym;
+ }
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case C_STRTAG:
+ case C_UNTAG:
+ case C_ENTAG:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+
+ /* Some compilers try to be helpful by inventing "fake"
+ names for anonymous enums, structures, and unions, like
+ "~0fake" or ".0fake". Thanks, but no thanks... */
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ if (SYMBOL_NAME(sym) != NULL
+ && *SYMBOL_NAME(sym) != '~'
+ && *SYMBOL_NAME(sym) != '.')
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym)) =
+ concat (SYMBOL_NAME (sym), NULL);
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return sym;
+}
+
+/* Decode a coff type specifier;
+ return the type that is meant. */
+
+static
+struct type *
+decode_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ register struct type *type = 0;
+ unsigned int new_c_type;
+
+ if (c_type & ~N_BTMASK)
+ {
+ new_c_type = DECREF (c_type);
+ if (ISPTR (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_pointer_type (type);
+ }
+ else if (ISFCN (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_function_type (type);
+ }
+ else if (ISARY (c_type))
+ {
+ int i, n;
+ register unsigned short *dim;
+ struct type *base_type, *index_type, *range_type;
+
+ /* Define an array type. */
+ /* auxent refers to array, not base type */
+ if (aux->x_sym.x_tagndx.l == 0)
+ cs->c_naux = 0;
+
+ /* shift the indices down */
+ dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0];
+ i = 1;
+ n = dim[0];
+ for (i = 0; *dim && i < DIMNUM - 1; i++, dim++)
+ *dim = *(dim + 1);
+ *dim = 0;
+
+ base_type = decode_type (cs, new_c_type, aux);
+ index_type = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ range_type =
+ create_range_type ((struct type *) NULL, index_type, 0, n - 1);
+ type =
+ create_array_type ((struct type *) NULL, base_type, range_type);
+ }
+ return type;
+ }
+
+ /* Reference to existing type. This only occurs with the
+ struct, union, and enum types. EPI a29k coff
+ fakes us out by producing aux entries with a nonzero
+ x_tagndx for definitions of structs, unions, and enums, so we
+ have to check the c_sclass field. SCO 3.2v4 cc gets confused
+ with pointers to pointers to defined structs, and generates
+ negative x_tagndx fields. */
+ if (cs->c_naux > 0 && aux->x_sym.x_tagndx.l != 0)
+ {
+ if (cs->c_sclass != C_STRTAG
+ && cs->c_sclass != C_UNTAG
+ && cs->c_sclass != C_ENTAG
+ && aux->x_sym.x_tagndx.l >= 0)
+ {
+ type = coff_alloc_type (aux->x_sym.x_tagndx.l);
+ return type;
+ } else {
+ complain (&tagndx_bad_complaint, cs->c_name);
+ /* And fall through to decode_base_type... */
+ }
+ }
+
+ return decode_base_type (cs, BTYPE (c_type), aux);
+}
+
+/* Decode a coff type specifier for function definition;
+ return the type that the function returns. */
+
+static
+struct type *
+decode_function_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ if (aux->x_sym.x_tagndx.l == 0)
+ cs->c_naux = 0; /* auxent refers to function, not base type */
+
+ return decode_type (cs, DECREF (c_type), aux);
+}
+
+/* basic C types */
+
+static
+struct type *
+decode_base_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ struct type *type;
+
+ switch (c_type)
+ {
+ case T_NULL:
+ /* shows up with "void (*foo)();" structure members */
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+
+#if 0
+/* DGUX actually defines both T_ARG and T_VOID to the same value. */
+#ifdef T_ARG
+ case T_ARG:
+ /* Shows up in DGUX, I think. Not sure where. */
+ return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */
+#endif
+#endif /* 0 */
+
+#ifdef T_VOID
+ case T_VOID:
+ /* Intel 960 COFF has this symbol and meaning. */
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+#endif
+
+ case T_CHAR:
+ return lookup_fundamental_type (current_objfile, FT_CHAR);
+
+ case T_SHORT:
+ return lookup_fundamental_type (current_objfile, FT_SHORT);
+
+ case T_INT:
+ return lookup_fundamental_type (current_objfile, FT_INTEGER);
+
+ case T_LONG:
+ return lookup_fundamental_type (current_objfile, FT_LONG);
+
+ case T_FLOAT:
+ return lookup_fundamental_type (current_objfile, FT_FLOAT);
+
+ case T_DOUBLE:
+ return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+
+ case T_STRUCT:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous structure type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "struct {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = coff_read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ return type;
+
+ case T_UNION:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous union type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "union {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = coff_read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ return type;
+
+ case T_ENUM:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous enum type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "enum {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS(type) = 0;
+ }
+ else
+ {
+ type = coff_read_enum_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ return type;
+
+ case T_MOE:
+ /* shouldn't show up here */
+ break;
+
+ case T_UCHAR:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+
+ case T_USHORT:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+
+ case T_UINT:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+
+ case T_ULONG:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ }
+ complain (&unexpected_type_complaint, cs->c_name);
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+}
+
+/* This page contains subroutines of read_type. */
+
+/* Read the description of a structure (or union type)
+ and return an object describing the type. */
+
+static struct type *
+coff_read_struct_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ struct field field;
+ };
+
+ register struct type *type;
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int nfields = 0;
+ register int n;
+ char *name;
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ struct internal_syment sub_sym;
+ union internal_auxent sub_aux;
+ int done = 0;
+
+ type = coff_alloc_type (index);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = length;
+
+ while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = EXTERNAL_NAME (name, current_objfile->obfd);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOS:
+ case C_MOU:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = 8 * ms->c_value;
+ list->field.bitsize = 0;
+ nfields++;
+ break;
+
+ case C_FIELD:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = ms->c_value;
+ list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size;
+ nfields++;
+ break;
+
+ case C_EOS:
+ done = 1;
+ break;
+ }
+ }
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ TYPE_FIELD (type, --n) = list->field;
+
+ return type;
+}
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+/* ARGSUSED */
+static struct type *
+coff_read_enum_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ register struct symbol *sym;
+ register struct type *type;
+ int nsyms = 0;
+ int done = 0;
+ struct pending **symlist;
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ struct internal_syment sub_sym;
+ union internal_auxent sub_aux;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+ register int n;
+ char *name;
+
+ type = coff_alloc_type (index);
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = EXTERNAL_NAME (name, current_objfile->obfd);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOE:
+ sym = (struct symbol *) xmalloc (sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ SYMBOL_NAME (sym) = savestring (name, strlen (name));
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = ms->c_value;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ break;
+
+ case C_EOS:
+ /* Sometimes the linker (on 386/ix 2.0.2 at least) screws
+ up the count of how many symbols to read. So stop
+ on .eos. */
+ done = 1;
+ break;
+ }
+ }
+
+ /* Now fill in the fields of the type-structure. */
+
+ if (length > 0)
+ TYPE_LENGTH (type) = length;
+ else
+ TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+ /* Note that we preserve the order of the enum constants, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ for (syms = *symlist, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++,n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ SYMBOL_TYPE (xsym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+#if 0
+ /* This screws up perfectly good C programs with enums. FIXME. */
+ /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */
+ if(TYPE_NFIELDS(type) == 2 &&
+ ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) ||
+ (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,0),"FALSE"))))
+ TYPE_CODE(type) = TYPE_CODE_BOOL;
+#endif
+ return type;
+}
+
+struct section_offsets *
+coff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* Register our ability to parse symbols for coff BFD files */
+
+static struct sym_fns coff_sym_fns =
+{
+ "coff", /* sym_name: name or name prefix of BFD target type */
+ 4, /* sym_namelen: number of significant sym_name chars */
+ coff_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ coff_symfile_read, /* sym_read: read a symbol file into symtab */
+ coff_symfile_finish, /* sym_finish: finished with file, cleanup */
+ coff_symfile_offsets, /* sym_offsets: xlate external to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_coffread ()
+{
+ add_symtab_fns(&coff_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/command.c b/gnu/usr.bin/gdb/gdb/command.c
new file mode 100644
index 000000000000..abc2d84499c0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.c
@@ -0,0 +1,1310 @@
+/* Handle lists of commands, their decoding and documentation, for GDB.
+ Copyright 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "value.h"
+#include <ctype.h>
+#include <string.h>
+
+/* Prototypes for local functions */
+
+static void
+undef_cmd_error PARAMS ((char *, char *));
+
+static void
+show_user PARAMS ((char *, int));
+
+static void
+show_user_1 PARAMS ((struct cmd_list_element *, FILE *));
+
+static void
+make_command PARAMS ((char *, int));
+
+static void
+shell_escape PARAMS ((char *, int));
+
+static int
+parse_binary_operation PARAMS ((char *));
+
+static void
+print_doc_line PARAMS ((FILE *, char *));
+
+/* Add element named NAME.
+ CLASS is the top level category into which commands are broken down
+ for "help" purposes.
+ FUN should be the function to execute the command;
+ it will get a character string as argument, with leading
+ and trailing blanks already eliminated.
+
+ DOC is a documentation string for the command.
+ Its first line should be a complete sentence.
+ It should start with ? for a command that is an abbreviation
+ or with * for a command that most users don't need to know about.
+
+ Add this command to command list *LIST. */
+
+struct cmd_list_element *
+add_cmd (name, class, fun, doc, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c
+ = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
+
+ delete_cmd (name, list);
+ c->next = *list;
+ c->name = name;
+ c->class = class;
+ c->function.cfunc = fun;
+ c->doc = doc;
+ c->prefixlist = 0;
+ c->prefixname = (char *)NULL;
+ c->allow_unknown = 0;
+ c->hook = 0;
+ c->hookee = 0;
+ c->cmd_pointer = 0;
+ c->abbrev_flag = 0;
+ c->type = not_set_cmd;
+ c->completer = make_symbol_completion_list;
+ c->var = 0;
+ c->var_type = var_boolean;
+ c->user_commands = 0;
+ *list = c;
+ return c;
+}
+
+/* Same as above, except that the abbrev_flag is set. */
+
+#if 0 /* Currently unused */
+
+struct cmd_list_element *
+add_abbrev_cmd (name, class, fun, doc, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c
+ = add_cmd (name, class, fun, doc, list);
+
+ c->abbrev_flag = 1;
+ return c;
+}
+
+#endif
+
+struct cmd_list_element *
+add_alias_cmd (name, oldname, class, abbrev_flag, list)
+ char *name;
+ char *oldname;
+ enum command_class class;
+ int abbrev_flag;
+ struct cmd_list_element **list;
+{
+ /* Must do this since lookup_cmd tries to side-effect its first arg */
+ char *copied_name;
+ register struct cmd_list_element *old;
+ register struct cmd_list_element *c;
+ copied_name = (char *) alloca (strlen (oldname) + 1);
+ strcpy (copied_name, oldname);
+ old = lookup_cmd (&copied_name, *list, "", 1, 1);
+
+ if (old == 0)
+ {
+ delete_cmd (name, list);
+ return 0;
+ }
+
+ c = add_cmd (name, class, old->function.cfunc, old->doc, list);
+ c->prefixlist = old->prefixlist;
+ c->prefixname = old->prefixname;
+ c->allow_unknown = old->allow_unknown;
+ c->abbrev_flag = abbrev_flag;
+ c->cmd_pointer = old;
+ return c;
+}
+
+/* Like add_cmd but adds an element for a command prefix:
+ a name that should be followed by a subcommand to be looked up
+ in another command list. PREFIXLIST should be the address
+ of the variable containing that list. */
+
+struct cmd_list_element *
+add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
+ allow_unknown, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **prefixlist;
+ char *prefixname;
+ int allow_unknown;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
+ c->prefixlist = prefixlist;
+ c->prefixname = prefixname;
+ c->allow_unknown = allow_unknown;
+ return c;
+}
+
+/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */
+
+struct cmd_list_element *
+add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
+ allow_unknown, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **prefixlist;
+ char *prefixname;
+ int allow_unknown;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
+ c->prefixlist = prefixlist;
+ c->prefixname = prefixname;
+ c->allow_unknown = allow_unknown;
+ c->abbrev_flag = 1;
+ return c;
+}
+
+/* ARGSUSED */
+void
+not_just_help_class_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+}
+
+/* Add element named NAME to command list LIST (the list for set
+ or some sublist thereof).
+ CLASS is as in add_cmd.
+ VAR_TYPE is the kind of thing we are setting.
+ VAR is address of the variable being controlled by this command.
+ DOC is the documentation string. */
+
+struct cmd_list_element *
+add_set_cmd (name, class, var_type, var, doc, list)
+ char *name;
+ enum command_class class;
+ var_types var_type;
+ char *var;
+ char *doc;
+ struct cmd_list_element **list;
+{
+ /* For set/show, we have to call do_setshow_command
+ differently than an ordinary function (take commandlist as
+ well as arg), so the function field isn't helpful. However,
+ function == NULL means that it's a help class, so set the function
+ to not_just_help_class_command. */
+ struct cmd_list_element *c
+ = add_cmd (name, class, not_just_help_class_command, doc, list);
+
+ c->type = set_cmd;
+ c->var_type = var_type;
+ c->var = var;
+ return c;
+}
+
+/* Where SETCMD has already been added, add the corresponding show
+ command to LIST and return a pointer to it. */
+struct cmd_list_element *
+add_show_from_set (setcmd, list)
+ struct cmd_list_element *setcmd;
+ struct cmd_list_element **list;
+{
+ struct cmd_list_element *showcmd =
+ (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
+
+ memcpy (showcmd, setcmd, sizeof (struct cmd_list_element));
+ delete_cmd (showcmd->name, list);
+ showcmd->type = show_cmd;
+
+ /* Replace "set " at start of docstring with "show ". */
+ if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e'
+ && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ')
+ showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL);
+ else
+ fprintf (stderr, "GDB internal error: Bad docstring for set command\n");
+
+ showcmd->next = *list;
+ *list = showcmd;
+ return showcmd;
+}
+
+/* Remove the command named NAME from the command list. */
+
+void
+delete_cmd (name, list)
+ char *name;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c;
+ struct cmd_list_element *p;
+
+ while (*list && STREQ ((*list)->name, name))
+ {
+ if ((*list)->hookee)
+ (*list)->hookee->hook = 0; /* Hook slips out of its mouth */
+ p = (*list)->next;
+ free ((PTR)*list);
+ *list = p;
+ }
+
+ if (*list)
+ for (c = *list; c->next;)
+ {
+ if (STREQ (c->next->name, name))
+ {
+ if (c->next->hookee)
+ c->next->hookee->hook = 0; /* hooked cmd gets away. */
+ p = c->next->next;
+ free ((PTR)c->next);
+ c->next = p;
+ }
+ else
+ c = c->next;
+ }
+}
+
+/* This command really has to deal with two things:
+ * 1) I want documentation on *this string* (usually called by
+ * "help commandname").
+ * 2) I want documentation on *this list* (usually called by
+ * giving a command that requires subcommands. Also called by saying
+ * just "help".)
+ *
+ * I am going to split this into two seperate comamnds, help_cmd and
+ * help_list.
+ */
+
+void
+help_cmd (command, stream)
+ char *command;
+ FILE *stream;
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (!command)
+ {
+ help_list (cmdlist, "", all_classes, stream);
+ return;
+ }
+
+ c = lookup_cmd (&command, cmdlist, "", 0, 0);
+
+ if (c == 0)
+ return;
+
+ /* There are three cases here.
+ If c->prefixlist is nonzero, we have a prefix command.
+ Print its documentation, then list its subcommands.
+
+ If c->function is nonzero, we really have a command.
+ Print its documentation and return.
+
+ If c->function is zero, we have a class name.
+ Print its documentation (as if it were a command)
+ and then set class to the number of this class
+ so that the commands in the class will be listed. */
+
+ fputs_filtered (c->doc, stream);
+ fputs_filtered ("\n", stream);
+
+ if (c->prefixlist == 0 && c->function.cfunc != NULL)
+ return;
+ fprintf_filtered (stream, "\n");
+
+ /* If this is a prefix command, print it's subcommands */
+ if (c->prefixlist)
+ help_list (*c->prefixlist, c->prefixname, all_commands, stream);
+
+ /* If this is a class name, print all of the commands in the class */
+ if (c->function.cfunc == NULL)
+ help_list (cmdlist, "", c->class, stream);
+
+ if (c->hook)
+ fprintf_filtered (stream, "\nThis command has a hook defined: %s\n",
+ c->hook->name);
+}
+
+/*
+ * Get a specific kind of help on a command list.
+ *
+ * LIST is the list.
+ * CMDTYPE is the prefix to use in the title string.
+ * CLASS is the class with which to list the nodes of this list (see
+ * documentation for help_cmd_list below), As usual, ALL_COMMANDS for
+ * everything, ALL_CLASSES for just classes, and non-negative for only things
+ * in a specific class.
+ * and STREAM is the output stream on which to print things.
+ * If you call this routine with a class >= 0, it recurses.
+ */
+void
+help_list (list, cmdtype, class, stream)
+ struct cmd_list_element *list;
+ char *cmdtype;
+ enum command_class class;
+ FILE *stream;
+{
+ int len;
+ char *cmdtype1, *cmdtype2;
+
+ /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */
+ len = strlen (cmdtype);
+ cmdtype1 = (char *) alloca (len + 1);
+ cmdtype1[0] = 0;
+ cmdtype2 = (char *) alloca (len + 4);
+ cmdtype2[0] = 0;
+ if (len)
+ {
+ cmdtype1[0] = ' ';
+ strncpy (cmdtype1 + 1, cmdtype, len - 1);
+ cmdtype1[len] = 0;
+ strncpy (cmdtype2, cmdtype, len - 1);
+ strcpy (cmdtype2 + len - 1, " sub");
+ }
+
+ if (class == all_classes)
+ fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2);
+ else
+ fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2);
+
+ help_cmd_list (list, class, cmdtype, (int)class >= 0, stream);
+
+ if (class == all_classes)
+ fprintf_filtered (stream, "\n\
+Type \"help%s\" followed by a class name for a list of commands in that class.",
+ cmdtype1);
+
+ fprintf_filtered (stream, "\n\
+Type \"help%s\" followed by %scommand name for full documentation.\n\
+Command name abbreviations are allowed if unambiguous.\n",
+ cmdtype1, cmdtype2);
+}
+
+/* Print only the first line of STR on STREAM. */
+static void
+print_doc_line (stream, str)
+ FILE *stream;
+ char *str;
+{
+ static char *line_buffer = 0;
+ static int line_size;
+ register char *p;
+
+ if (!line_buffer)
+ {
+ line_size = 80;
+ line_buffer = (char *) xmalloc (line_size);
+ }
+
+ p = str;
+ while (*p && *p != '\n' && *p != '.' && *p != ',')
+ p++;
+ if (p - str > line_size - 1)
+ {
+ line_size = p - str + 1;
+ free ((PTR)line_buffer);
+ line_buffer = (char *) xmalloc (line_size);
+ }
+ strncpy (line_buffer, str, p - str);
+ line_buffer[p - str] = '\0';
+ if (islower (line_buffer[0]))
+ line_buffer[0] = toupper (line_buffer[0]);
+ fputs_filtered (line_buffer, stream);
+}
+
+/*
+ * Implement a help command on command list LIST.
+ * RECURSE should be non-zero if this should be done recursively on
+ * all sublists of LIST.
+ * PREFIX is the prefix to print before each command name.
+ * STREAM is the stream upon which the output should be written.
+ * CLASS should be:
+ * A non-negative class number to list only commands in that
+ * class.
+ * ALL_COMMANDS to list all commands in list.
+ * ALL_CLASSES to list all classes in list.
+ *
+ * Note that RECURSE will be active on *all* sublists, not just the
+ * ones selected by the criteria above (ie. the selection mechanism
+ * is at the low level, not the high-level).
+ */
+void
+help_cmd_list (list, class, prefix, recurse, stream)
+ struct cmd_list_element *list;
+ enum command_class class;
+ char *prefix;
+ int recurse;
+ FILE *stream;
+{
+ register struct cmd_list_element *c;
+
+ for (c = list; c; c = c->next)
+ {
+ if (c->abbrev_flag == 0 &&
+ (class == all_commands
+ || (class == all_classes && c->function.cfunc == NULL)
+ || (class == c->class && c->function.cfunc != NULL)))
+ {
+ fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
+ print_doc_line (stream, c->doc);
+ fputs_filtered ("\n", stream);
+ }
+ if (recurse
+ && c->prefixlist != 0
+ && c->abbrev_flag == 0)
+ help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream);
+ }
+}
+
+/* This routine takes a line of TEXT and a CLIST in which to start the
+ lookup. When it returns it will have incremented the text pointer past
+ the section of text it matched, set *RESULT_LIST to point to the list in
+ which the last word was matched, and will return a pointer to the cmd
+ list element which the text matches. It will return NULL if no match at
+ all was possible. It will return -1 (cast appropriately, ick) if ambigous
+ matches are possible; in this case *RESULT_LIST will be set to point to
+ the list in which there are ambiguous choices (and *TEXT will be set to
+ the ambiguous text string).
+
+ If the located command was an abbreviation, this routine returns the base
+ command of the abbreviation.
+
+ It does no error reporting whatsoever; control will always return
+ to the superior routine.
+
+ In the case of an ambiguous return (-1), *RESULT_LIST will be set to point
+ at the prefix_command (ie. the best match) *or* (special case) will be NULL
+ if no prefix command was ever found. For example, in the case of "info a",
+ "info" matches without ambiguity, but "a" could be "args" or "address", so
+ *RESULT_LIST is set to the cmd_list_element for "info". So in this case
+ RESULT_LIST should not be interpeted as a pointer to the beginning of a
+ list; it simply points to a specific command. In the case of an ambiguous
+ return *TEXT is advanced past the last non-ambiguous prefix (e.g.
+ "info t" can be "info types" or "info target"; upon return *TEXT has been
+ advanced past "info ").
+
+ If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise
+ affect the operation).
+
+ This routine does *not* modify the text pointed to by TEXT.
+
+ If IGNORE_HELP_CLASSES is nonzero, ignore any command list elements which
+ are actually help classes rather than commands (i.e. the function field of
+ the struct cmd_list_element is NULL). */
+
+struct cmd_list_element *
+lookup_cmd_1 (text, clist, result_list, ignore_help_classes)
+ char **text;
+ struct cmd_list_element *clist, **result_list;
+ int ignore_help_classes;
+{
+ char *p, *command;
+ int len, tmp, nfound;
+ struct cmd_list_element *found, *c;
+
+ while (**text == ' ' || **text == '\t')
+ (*text)++;
+
+ /* Treating underscores as part of command words is important
+ so that "set args_foo()" doesn't get interpreted as
+ "set args _foo()". */
+ for (p = *text;
+ *p && (isalnum(*p) || *p == '-' || *p == '_');
+ p++)
+ ;
+
+ /* If nothing but whitespace, return 0. */
+ if (p == *text)
+ return 0;
+
+ len = p - *text;
+
+ /* *text and p now bracket the first command word to lookup (and
+ it's length is len). We copy this into a local temporary,
+ converting to lower case as we go. */
+
+ command = (char *) alloca (len + 1);
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = (*text)[tmp];
+ command[tmp] = isupper(x) ? tolower(x) : x;
+ }
+ command[len] = '\0';
+
+ /* Look it up. */
+ found = 0;
+ nfound = 0;
+ for (c = clist; c; c = c->next)
+ if (!strncmp (command, c->name, len)
+ && (!ignore_help_classes || c->function.cfunc))
+ {
+ found = c;
+ nfound++;
+ if (c->name[len] == '\0')
+ {
+ nfound = 1;
+ break;
+ }
+ }
+
+ /* If nothing matches, we have a simple failure. */
+ if (nfound == 0)
+ return 0;
+
+ if (nfound > 1)
+ {
+ if (result_list != NULL)
+ /* Will be modified in calling routine
+ if we know what the prefix command is. */
+ *result_list = 0;
+ return (struct cmd_list_element *) -1; /* Ambiguous. */
+ }
+
+ /* We've matched something on this list. Move text pointer forward. */
+
+ *text = p;
+
+ /* If this was an abbreviation, use the base command instead. */
+
+ if (found->cmd_pointer)
+ found = found->cmd_pointer;
+
+ /* If we found a prefix command, keep looking. */
+
+ if (found->prefixlist)
+ {
+ c = lookup_cmd_1 (text, *found->prefixlist, result_list,
+ ignore_help_classes);
+ if (!c)
+ {
+ /* Didn't find anything; this is as far as we got. */
+ if (result_list != NULL)
+ *result_list = clist;
+ return found;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ /* We've gotten this far properley, but the next step
+ is ambiguous. We need to set the result list to the best
+ we've found (if an inferior hasn't already set it). */
+ if (result_list != NULL)
+ if (!*result_list)
+ /* This used to say *result_list = *found->prefixlist
+ If that was correct, need to modify the documentation
+ at the top of this function to clarify what is supposed
+ to be going on. */
+ *result_list = found;
+ return c;
+ }
+ else
+ {
+ /* We matched! */
+ return c;
+ }
+ }
+ else
+ {
+ if (result_list != NULL)
+ *result_list = clist;
+ return found;
+ }
+}
+
+/* All this hair to move the space to the front of cmdtype */
+
+static void
+undef_cmd_error (cmdtype, q)
+ char *cmdtype, *q;
+{
+ error ("Undefined %scommand: \"%s\". Try \"help%s%.*s\".",
+ cmdtype,
+ q,
+ *cmdtype? " ": "",
+ strlen(cmdtype)-1,
+ cmdtype);
+}
+
+/* Look up the contents of *LINE as a command in the command list LIST.
+ LIST is a chain of struct cmd_list_element's.
+ If it is found, return the struct cmd_list_element for that command
+ and update *LINE to point after the command name, at the first argument.
+ If not found, call error if ALLOW_UNKNOWN is zero
+ otherwise (or if error returns) return zero.
+ Call error if specified command is ambiguous,
+ unless ALLOW_UNKNOWN is negative.
+ CMDTYPE precedes the word "command" in the error message.
+
+ If INGNORE_HELP_CLASSES is nonzero, ignore any command list
+ elements which are actually help classes rather than commands (i.e.
+ the function field of the struct cmd_list_element is 0). */
+
+struct cmd_list_element *
+lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes)
+ char **line;
+ struct cmd_list_element *list;
+ char *cmdtype;
+ int allow_unknown;
+ int ignore_help_classes;
+{
+ struct cmd_list_element *last_list = 0;
+ struct cmd_list_element *c =
+ lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+ char *ptr = (*line) + strlen (*line) - 1;
+
+ /* Clear off trailing whitespace. */
+ while (ptr >= *line && (*ptr == ' ' || *ptr == '\t'))
+ ptr--;
+ *(ptr + 1) = '\0';
+
+ if (!c)
+ {
+ if (!allow_unknown)
+ {
+ if (!*line)
+ error ("Lack of needed %scommand", cmdtype);
+ else
+ {
+ char *p = *line, *q;
+
+ while (isalnum(*p) || *p == '-')
+ p++;
+
+ q = (char *) alloca (p - *line + 1);
+ strncpy (q, *line, p - *line);
+ q[p-*line] = '\0';
+ undef_cmd_error (cmdtype, q);
+ }
+ }
+ else
+ return 0;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ /* Ambigous. Local values should be off prefixlist or called
+ values. */
+ int local_allow_unknown = (last_list ? last_list->allow_unknown :
+ allow_unknown);
+ char *local_cmdtype = last_list ? last_list->prefixname : cmdtype;
+ struct cmd_list_element *local_list =
+ (last_list ? *(last_list->prefixlist) : list);
+
+ if (local_allow_unknown < 0)
+ {
+ if (last_list)
+ return last_list; /* Found something. */
+ else
+ return 0; /* Found nothing. */
+ }
+ else
+ {
+ /* Report as error. */
+ int amb_len;
+ char ambbuf[100];
+
+ for (amb_len = 0;
+ ((*line)[amb_len] && (*line)[amb_len] != ' '
+ && (*line)[amb_len] != '\t');
+ amb_len++)
+ ;
+
+ ambbuf[0] = 0;
+ for (c = local_list; c; c = c->next)
+ if (!strncmp (*line, c->name, amb_len))
+ {
+ if (strlen (ambbuf) + strlen (c->name) + 6 < (int)sizeof ambbuf)
+ {
+ if (strlen (ambbuf))
+ strcat (ambbuf, ", ");
+ strcat (ambbuf, c->name);
+ }
+ else
+ {
+ strcat (ambbuf, "..");
+ break;
+ }
+ }
+ error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype,
+ *line, ambbuf);
+ return 0; /* lint */
+ }
+ }
+ else
+ {
+ /* We've got something. It may still not be what the caller
+ wants (if this command *needs* a subcommand). */
+ while (**line == ' ' || **line == '\t')
+ (*line)++;
+
+ if (c->prefixlist && **line && !c->allow_unknown)
+ undef_cmd_error (c->prefixname, *line);
+
+ /* Seems to be what he wants. Return it. */
+ return c;
+ }
+ return 0;
+}
+
+#if 0
+/* Look up the contents of *LINE as a command in the command list LIST.
+ LIST is a chain of struct cmd_list_element's.
+ If it is found, return the struct cmd_list_element for that command
+ and update *LINE to point after the command name, at the first argument.
+ If not found, call error if ALLOW_UNKNOWN is zero
+ otherwise (or if error returns) return zero.
+ Call error if specified command is ambiguous,
+ unless ALLOW_UNKNOWN is negative.
+ CMDTYPE precedes the word "command" in the error message. */
+
+struct cmd_list_element *
+lookup_cmd (line, list, cmdtype, allow_unknown)
+ char **line;
+ struct cmd_list_element *list;
+ char *cmdtype;
+ int allow_unknown;
+{
+ register char *p;
+ register struct cmd_list_element *c, *found;
+ int nfound;
+ char ambbuf[100];
+ char *processed_cmd;
+ int i, cmd_len;
+
+ /* Skip leading whitespace. */
+
+ while (**line == ' ' || **line == '\t')
+ (*line)++;
+
+ /* Clear out trailing whitespace. */
+
+ p = *line + strlen (*line);
+ while (p != *line && (p[-1] == ' ' || p[-1] == '\t'))
+ p--;
+ *p = 0;
+
+ /* Find end of command name. */
+
+ p = *line;
+ while (*p == '-' || isalnum(*p))
+ p++;
+
+ /* Look up the command name.
+ If exact match, keep that.
+ Otherwise, take command abbreviated, if unique. Note that (in my
+ opinion) a null string does *not* indicate ambiguity; simply the
+ end of the argument. */
+
+ if (p == *line)
+ {
+ if (!allow_unknown)
+ error ("Lack of needed %scommand", cmdtype);
+ return 0;
+ }
+
+ /* Copy over to a local buffer, converting to lowercase on the way.
+ This is in case the command being parsed is a subcommand which
+ doesn't match anything, and that's ok. We want the original
+ untouched for the routine of the original command. */
+
+ processed_cmd = (char *) alloca (p - *line + 1);
+ for (cmd_len = 0; cmd_len < p - *line; cmd_len++)
+ {
+ char x = (*line)[cmd_len];
+ if (isupper(x))
+ processed_cmd[cmd_len] = tolower(x);
+ else
+ processed_cmd[cmd_len] = x;
+ }
+ processed_cmd[cmd_len] = '\0';
+
+ /* Check all possibilities in the current command list. */
+ found = 0;
+ nfound = 0;
+ for (c = list; c; c = c->next)
+ {
+ if (!strncmp (processed_cmd, c->name, cmd_len))
+ {
+ found = c;
+ nfound++;
+ if (c->name[cmd_len] == 0)
+ {
+ nfound = 1;
+ break;
+ }
+ }
+ }
+
+ /* Report error for undefined command name. */
+
+ if (nfound != 1)
+ {
+ if (nfound > 1 && allow_unknown >= 0)
+ {
+ ambbuf[0] = 0;
+ for (c = list; c; c = c->next)
+ if (!strncmp (processed_cmd, c->name, cmd_len))
+ {
+ if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf)
+ {
+ if (strlen (ambbuf))
+ strcat (ambbuf, ", ");
+ strcat (ambbuf, c->name);
+ }
+ else
+ {
+ strcat (ambbuf, "..");
+ break;
+ }
+ }
+ error ("Ambiguous %scommand \"%s\": %s.", cmdtype,
+ processed_cmd, ambbuf);
+ }
+ else if (!allow_unknown)
+ error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd);
+ return 0;
+ }
+
+ /* Skip whitespace before the argument. */
+
+ while (*p == ' ' || *p == '\t') p++;
+ *line = p;
+
+ if (found->prefixlist && *p)
+ {
+ c = lookup_cmd (line, *found->prefixlist, found->prefixname,
+ found->allow_unknown);
+ if (c)
+ return c;
+ }
+
+ return found;
+}
+#endif
+
+/* Helper function for SYMBOL_COMPLETION_FUNCTION. */
+
+/* Return a vector of char pointers which point to the different
+ possible completions in LIST of TEXT.
+
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
+
+char **
+complete_on_cmdlist (list, text, word)
+ struct cmd_list_element *list;
+ char *text;
+ char *word;
+{
+ struct cmd_list_element *ptr;
+ char **matchlist;
+ int sizeof_matchlist;
+ int matches;
+ int textlen = strlen (text);
+
+ sizeof_matchlist = 10;
+ matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *));
+ matches = 0;
+
+ for (ptr = list; ptr; ptr = ptr->next)
+ if (!strncmp (ptr->name, text, textlen)
+ && !ptr->abbrev_flag
+ && (ptr->function.cfunc
+ || ptr->prefixlist))
+ {
+ if (matches == sizeof_matchlist)
+ {
+ sizeof_matchlist *= 2;
+ matchlist = (char **) xrealloc ((char *)matchlist,
+ (sizeof_matchlist
+ * sizeof (char *)));
+ }
+
+ matchlist[matches] = (char *)
+ xmalloc (strlen (word) + strlen (ptr->name) + 1);
+ if (word == text)
+ strcpy (matchlist[matches], ptr->name);
+ else if (word > text)
+ {
+ /* Return some portion of ptr->name. */
+ strcpy (matchlist[matches], ptr->name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus ptr->name. */
+ strncpy (matchlist[matches], word, text - word);
+ matchlist[matches][text - word] = '\0';
+ strcat (matchlist[matches], ptr->name);
+ }
+ ++matches;
+ }
+
+ if (matches == 0)
+ {
+ free ((PTR)matchlist);
+ matchlist = 0;
+ }
+ else
+ {
+ matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1)
+ * sizeof (char *)));
+ matchlist[matches] = (char *) 0;
+ }
+
+ return matchlist;
+}
+
+static int
+parse_binary_operation (arg)
+ char *arg;
+{
+ int length;
+
+ if (!arg || !*arg)
+ return 1;
+
+ length = strlen (arg);
+
+ while (arg[length - 1] == ' ' || arg[length - 1] == '\t')
+ length--;
+
+ if (!strncmp (arg, "on", length)
+ || !strncmp (arg, "1", length)
+ || !strncmp (arg, "yes", length))
+ return 1;
+ else
+ if (!strncmp (arg, "off", length)
+ || !strncmp (arg, "0", length)
+ || !strncmp (arg, "no", length))
+ return 0;
+ else
+ {
+ error ("\"on\" or \"off\" expected.");
+ return 0;
+ }
+}
+
+/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
+ of the argument, and FROM_TTY is nonzero if this command is being entered
+ directly by the user (i.e. these are just like any other
+ command). C is the command list element for the command. */
+void
+do_setshow_command (arg, from_tty, c)
+ char *arg;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (c->type == set_cmd)
+ {
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ char *new;
+ char *p;
+ char *q;
+ int ch;
+
+ if (arg == NULL)
+ arg = "";
+ new = (char *) xmalloc (strlen (arg) + 2);
+ p = arg; q = new;
+ while ((ch = *p++) != '\000')
+ {
+ if (ch == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ break;
+ ch = parse_escape (&p);
+ if (ch == 0)
+ break; /* C loses */
+ else if (ch > 0)
+ *q++ = ch;
+ }
+ else
+ *q++ = ch;
+ }
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+ *q++ = '\0';
+ new = (char *) xrealloc (new, q - new);
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **) c->var = new;
+ }
+ break;
+ case var_string_noescape:
+ if (arg == NULL)
+ arg = "";
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **) c->var = savestring (arg, strlen (arg));
+ break;
+ case var_filename:
+ if (arg == NULL)
+ error_no_arg ("filename to set it to.");
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **)c->var = tilde_expand (arg);
+ break;
+ case var_boolean:
+ *(int *) c->var = parse_binary_operation (arg);
+ break;
+ case var_uinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(unsigned int *) c->var = parse_and_eval_address (arg);
+ if (*(unsigned int *) c->var == 0)
+ *(unsigned int *) c->var = UINT_MAX;
+ break;
+ case var_integer:
+ {
+ unsigned int val;
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ val = parse_and_eval_address (arg);
+ if (val == 0)
+ *(int *) c->var = INT_MAX;
+ else if (val >= INT_MAX)
+ error ("integer %u out of range", val);
+ else
+ *(int *) c->var = val;
+ break;
+ }
+ case var_zinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(int *) c->var = parse_and_eval_address (arg);
+ break;
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ }
+ else if (c->type == show_cmd)
+ {
+ /* Print doc minus "show" at start. */
+ print_doc_line (stdout, c->doc + 5);
+
+ fputs_filtered (" is ", stdout);
+ wrap_here (" ");
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ unsigned char *p;
+ fputs_filtered ("\"", stdout);
+ for (p = *(unsigned char **) c->var; *p != '\0'; p++)
+ gdb_printchar (*p, stdout, '"');
+ fputs_filtered ("\"", stdout);
+ }
+ break;
+ case var_string_noescape:
+ case var_filename:
+ fputs_filtered ("\"", stdout);
+ fputs_filtered (*(char **) c->var, stdout);
+ fputs_filtered ("\"", stdout);
+ break;
+ case var_boolean:
+ fputs_filtered (*(int *) c->var ? "on" : "off", stdout);
+ break;
+ case var_uinteger:
+ if (*(unsigned int *) c->var == UINT_MAX) {
+ fputs_filtered ("unlimited", stdout);
+ break;
+ }
+ /* else fall through */
+ case var_zinteger:
+ fprintf_filtered (stdout, "%u", *(unsigned int *) c->var);
+ break;
+ case var_integer:
+ if (*(int *) c->var == INT_MAX)
+ {
+ fputs_filtered ("unlimited", stdout);
+ }
+ else
+ fprintf_filtered (stdout, "%d", *(int *) c->var);
+ break;
+
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ fputs_filtered (".\n", stdout);
+ }
+ else
+ error ("gdb internal error: bad cmd_type in do_setshow_command");
+ (*c->function.sfunc) (NULL, from_tty, c);
+}
+
+/* Show all the settings in a list of show commands. */
+
+void
+cmd_show_list (list, from_tty, prefix)
+ struct cmd_list_element *list;
+ int from_tty;
+ char *prefix;
+{
+ for (; list != NULL; list = list->next) {
+ /* If we find a prefix, run its list, prefixing our output by its
+ prefix (with "show " skipped). */
+ if (list->prefixlist && !list->abbrev_flag)
+ cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5);
+ if (list->type == show_cmd)
+ {
+ fputs_filtered (prefix, stdout);
+ fputs_filtered (list->name, stdout);
+ fputs_filtered (": ", stdout);
+ do_setshow_command ((char *)NULL, from_tty, list);
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+shell_escape (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+#ifdef CANT_FORK
+ /* FIXME: what about errors (I don't know how GO32 system() handles
+ them)? */
+ system (arg);
+#else /* Can fork. */
+ int rc, status, pid;
+ char *p, *user_shell;
+
+ if ((user_shell = (char *) getenv ("SHELL")) == NULL)
+ user_shell = "/bin/sh";
+
+ /* Get the name of the shell for arg0 */
+ if ((p = strrchr (user_shell, '/')) == NULL)
+ p = user_shell;
+ else
+ p++; /* Get past '/' */
+
+ if ((pid = fork()) == 0)
+ {
+ if (!arg)
+ execl (user_shell, p, 0);
+ else
+ execl (user_shell, p, "-c", arg, 0);
+
+ fprintf (stderr, "Exec of shell failed\n");
+ exit (0);
+ }
+
+ if (pid != -1)
+ while ((rc = wait (&status)) != pid && rc != -1)
+ ;
+ else
+ error ("Fork failed");
+#endif /* Can fork. */
+}
+
+static void
+make_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *p;
+
+ if (arg == 0)
+ p = "make";
+ else
+ {
+ p = xmalloc (sizeof("make ") + strlen(arg));
+ strcpy (p, "make ");
+ strcpy (p + sizeof("make ")-1, arg);
+ }
+
+ shell_escape (p, from_tty);
+}
+
+static void
+show_user_1 (c, stream)
+ struct cmd_list_element *c;
+ FILE *stream;
+{
+ register struct command_line *cmdlines;
+
+ cmdlines = c->user_commands;
+ if (!cmdlines)
+ return;
+ fputs_filtered ("User command ", stream);
+ fputs_filtered (c->name, stream);
+ fputs_filtered (":\n", stream);
+ while (cmdlines)
+ {
+ fputs_filtered (cmdlines->line, stream);
+ fputs_filtered ("\n", stream);
+ cmdlines = cmdlines->next;
+ }
+ fputs_filtered ("\n", stream);
+}
+
+/* ARGSUSED */
+static void
+show_user (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (args)
+ {
+ c = lookup_cmd (&args, cmdlist, "", 0, 1);
+ if (c->class != class_user)
+ error ("Not a user command.");
+ show_user_1 (c, stdout);
+ }
+ else
+ {
+ for (c = cmdlist; c; c = c->next)
+ {
+ if (c->class == class_user)
+ show_user_1 (c, stdout);
+ }
+ }
+}
+
+void
+_initialize_command ()
+{
+ add_com ("shell", class_support, shell_escape,
+ "Execute the rest of the line as a shell command. \n\
+With no arguments, run an inferior shell.");
+ add_com ("make", class_support, make_command,
+ "Run the ``make'' program using the rest of the line as arguments.");
+ add_cmd ("user", no_class, show_user,
+ "Show definitions of user defined commands.\n\
+Argument is the name of the user defined command.\n\
+With no argument, show definitions of all user defined commands.", &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/command.h b/gnu/usr.bin/gdb/gdb/command.h
new file mode 100644
index 000000000000..ee587c30659d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.h
@@ -0,0 +1,241 @@
+/* Header file for command-reading library command.c.
+ Copyright (C) 1986, 1989, 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (COMMAND_H)
+#define COMMAND_H 1
+
+/* Not a set/show command. Note that some commands which begin with
+ "set" or "show" might be in this category, if their syntax does
+ not fall into one of the following categories. */
+typedef enum cmd_types {
+ not_set_cmd,
+ set_cmd,
+ show_cmd
+} cmd_types;
+
+/* Types of "set" or "show" command. */
+typedef enum var_types {
+ /* "on" or "off". *VAR is an integer which is nonzero for on,
+ zero for off. */
+ var_boolean,
+ /* Unsigned Integer. *VAR is an unsigned int. The user can type 0
+ to mean "unlimited", which is stored in *VAR as UINT_MAX. */
+ var_uinteger,
+
+ /* Like var_uinteger but signed. *VAR is an int. The user can type 0
+ to mean "unlimited", which is stored in *VAR as INT_MAX. */
+ var_integer,
+
+ /* String which the user enters with escapes (e.g. the user types \n and
+ it is a real newline in the stored string).
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_string,
+ /* String which stores what the user types verbatim.
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_string_noescape,
+ /* String which stores a filename.
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_filename,
+ /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except
+ that zero really means zero. */
+ var_zinteger
+} var_types;
+
+/* This structure records one command'd definition. */
+
+struct cmd_list_element
+ {
+ /* Points to next command in this list. */
+ struct cmd_list_element *next;
+
+ /* Name of this command. */
+ char *name;
+
+ /* Command class; class values are chosen by application program. */
+ enum command_class class;
+
+ /* Function definition of this command.
+ Zero for command class names and for help topics that
+ are not really commands. */
+ union {
+ void (*cfunc) PARAMS ((char *args, int from_tty));
+ void (*sfunc) PARAMS ((char *args, int from_tty,
+ struct cmd_list_element *c));
+ } function;
+# define NO_FUNCTION ((void (*) PARAMS((char *args, int from_tty))) 0)
+
+ /* Documentation of this command (or help topic).
+ First line is brief documentation; remaining lines form, with it,
+ the full documentation. First line should end with a period.
+ Entire string should also end with a period, not a newline. */
+ char *doc;
+
+ /* Hook for another command to be executed before this command. */
+ struct cmd_list_element *hook;
+
+ /* Nonzero identifies a prefix command. For them, the address
+ of the variable containing the list of subcommands. */
+ struct cmd_list_element **prefixlist;
+
+ /* For prefix commands only:
+ String containing prefix commands to get here: this one
+ plus any others needed to get to it. Should end in a space.
+ It is used before the word "command" in describing the
+ commands reached through this prefix. */
+ char *prefixname;
+
+ /* For prefix commands only:
+ nonzero means do not get an error if subcommand is not
+ recognized; call the prefix's own function in that case. */
+ char allow_unknown;
+
+ /* Nonzero says this is an abbreviation, and should not
+ be mentioned in lists of commands.
+ This allows "br<tab>" to complete to "break", which it
+ otherwise wouldn't. */
+ char abbrev_flag;
+
+ /* Completion routine for this command. TEXT is the text beyond
+ what was matched for the command itself (leading whitespace is
+ skipped). It stops where we are supposed to stop completing
+ (rl_point) and is '\0' terminated.
+
+ Return value is a malloc'd vector of pointers to possible completions
+ terminated with NULL. If there are no completions, returning a pointer
+ to a NULL would work but returning NULL itself is also valid.
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
+ char ** (*completer) PARAMS ((char *text, char *word));
+
+ /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
+ or "show"). */
+ cmd_types type;
+
+ /* Pointer to variable affected by "set" and "show". Doesn't matter
+ if type is not_set. */
+ char *var;
+
+ /* What kind of variable is *VAR? */
+ var_types var_type;
+
+ /* Pointer to command strings of user-defined commands */
+ struct command_line *user_commands;
+
+ /* Pointer to command that is hooked by this one,
+ so the hook can be removed when this one is deleted. */
+ struct cmd_list_element *hookee;
+
+ /* Pointer to command that is aliased by this one, so the
+ aliased command can be located in case it has been hooked. */
+ struct cmd_list_element *cmd_pointer;
+ };
+
+/* Forward-declarations of the entry-points of command.c. */
+
+extern struct cmd_list_element *
+add_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int),
+ char *, struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_alias_cmd PARAMS ((char *, char *, enum command_class, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_prefix_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int),
+ char *, struct cmd_list_element **, char *, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_abbrev_prefix_cmd PARAMS ((char *, enum command_class,
+ void (*fun) (char *, int), char *,
+ struct cmd_list_element **, char *, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+lookup_cmd PARAMS ((char **, struct cmd_list_element *, char *, int, int));
+
+extern struct cmd_list_element *
+lookup_cmd_1 PARAMS ((char **, struct cmd_list_element *,
+ struct cmd_list_element **, int));
+
+extern void
+add_com PARAMS ((char *, enum command_class, void (*fun)(char *, int),
+ char *));
+
+extern void
+add_com_alias PARAMS ((char *, char *, enum command_class, int));
+
+extern void
+add_info PARAMS ((char *, void (*fun) (char *, int), char *));
+
+extern void
+add_info_alias PARAMS ((char *, char *, int));
+
+extern char **complete_on_cmdlist PARAMS ((struct cmd_list_element *,
+ char *, char *));
+
+extern void
+delete_cmd PARAMS ((char *, struct cmd_list_element **));
+
+extern void
+help_cmd PARAMS ((char *, FILE *));
+
+extern void
+help_list PARAMS ((struct cmd_list_element *, char *, enum command_class,
+ FILE *));
+
+extern void
+help_cmd_list PARAMS ((struct cmd_list_element *, enum command_class, char *,
+ int, FILE *));
+
+extern struct cmd_list_element *
+add_set_cmd PARAMS ((char *, enum command_class, var_types, char *, char *,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_show_from_set PARAMS ((struct cmd_list_element *,
+ struct cmd_list_element **));
+
+/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
+ of the argument, and FROM_TTY is nonzero if this command is being entered
+ directly by the user (i.e. these are just like any other
+ command). C is the command list element for the command. */
+
+extern void
+do_setshow_command PARAMS ((char *, int, struct cmd_list_element *));
+
+/* Do a "show" command for each thing on a command list. */
+
+extern void
+cmd_show_list PARAMS ((struct cmd_list_element *, int, char *));
+
+extern void
+error_no_arg PARAMS ((char *));
+
+extern void
+dont_repeat PARAMS ((void));
+
+/* Used to mark commands that don't do anything. If we just leave the
+ function field NULL, the command is interpreted as a help topic, or
+ as a class of commands. */
+
+extern void
+not_just_help_class_command PARAMS ((char *, int));
+
+#endif /* !defined (COMMAND_H) */
diff --git a/gnu/usr.bin/gdb/gdb/complaints.c b/gnu/usr.bin/gdb/gdb/complaints.c
new file mode 100644
index 000000000000..079ca5adc643
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/complaints.c
@@ -0,0 +1,158 @@
+/* Support for complaint handling during symbol reading in GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "complaints.h"
+#include "gdbcmd.h"
+#include <varargs.h>
+
+/* Structure to manage complaints about symbol file contents. */
+
+struct complaint complaint_root[1] = {
+ {
+ (char *) NULL, /* Complaint message */
+ 0, /* Complaint counter */
+ complaint_root /* Next complaint. */
+ }
+};
+
+/* How many complaints about a particular thing should be printed before
+ we stop whining about it? Default is no whining at all, since so many
+ systems have ill-constructed symbol files. */
+
+static unsigned int stop_whining = 0;
+
+/* Should each complaint be self explanatory, or should we assume that
+ a series of complaints is being produced?
+ case 0: self explanatory message.
+ case 1: First message of a series that must start off with explanation.
+ case 2: Subsequent message, when user already knows we are reading
+ symbols and we can just state our piece. */
+
+static int complaint_series = 0;
+
+/* External variables and functions referenced. */
+
+extern int info_verbose;
+
+
+/* Functions to handle complaints during symbol reading. */
+
+/* Print a complaint about the input symbols, and link the complaint block
+ into a chain for later handling. */
+
+/* VARARGS */
+void
+complain (va_alist)
+ va_dcl
+{
+ va_list args;
+ struct complaint *complaint;
+
+ va_start (args);
+ complaint = va_arg (args, struct complaint *);
+ complaint -> counter++;
+ if (complaint -> next == NULL)
+ {
+ complaint -> next = complaint_root -> next;
+ complaint_root -> next = complaint;
+ }
+ if (complaint -> counter > stop_whining)
+ {
+ return;
+ }
+ wrap_here ("");
+
+ switch (complaint_series + (info_verbose << 1))
+ {
+
+ /* Isolated messages, must be self-explanatory. */
+ case 0:
+ begin_line ();
+ puts_filtered ("During symbol reading, ");
+ wrap_here ("");
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered (".\n");
+ break;
+
+ /* First of a series, without `set verbose'. */
+ case 1:
+ begin_line ();
+ puts_filtered ("During symbol reading...");
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered ("...");
+ wrap_here ("");
+ complaint_series++;
+ break;
+
+ /* Subsequent messages of a series, or messages under `set verbose'.
+ (We'll already have produced a "Reading in symbols for XXX..."
+ message and will clean up at the end with a newline.) */
+ default:
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered ("...");
+ wrap_here ("");
+ }
+ /* If GDB dumps core, we'd like to see the complaints first. Presumably
+ GDB will not be sending so many complaints that this becomes a
+ performance hog. */
+ fflush (stdout);
+ va_end (args);
+}
+
+/* Clear out all complaint counters that have ever been incremented.
+ If sym_reading is 1, be less verbose about successive complaints,
+ since the messages are appearing all together during a command that
+ reads symbols (rather than scattered around as psymtabs get fleshed
+ out into symtabs at random times). If noisy is 1, we are in a
+ noisy symbol reading command, and our caller will print enough
+ context for the user to figure it out. */
+
+void
+clear_complaints (sym_reading, noisy)
+ int sym_reading;
+ int noisy;
+{
+ struct complaint *p;
+
+ for (p = complaint_root -> next; p != complaint_root; p = p -> next)
+ {
+ p -> counter = 0;
+ }
+
+ if (!sym_reading && !noisy && complaint_series > 1)
+ {
+ /* Terminate previous series, since caller won't. */
+ puts_filtered ("\n");
+ }
+
+ complaint_series = sym_reading ? 1 + noisy : 0;
+}
+
+void
+_initialize_complaints ()
+{
+ add_show_from_set
+ (add_set_cmd ("complaints", class_support, var_zinteger,
+ (char *) &stop_whining,
+ "Set max number of complaints about incorrect symbols.",
+ &setlist),
+ &showlist);
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/complaints.h b/gnu/usr.bin/gdb/gdb/complaints.h
new file mode 100644
index 000000000000..f7ff5a568142
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/complaints.h
@@ -0,0 +1,46 @@
+/* Definitions for complaint handling during symbol reading in GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Support for complaining about things in the symbol file that aren't
+ catastrophic.
+
+ Each such thing gets a counter. The first time we have the problem,
+ during a symbol read, we report it. At the end of symbol reading,
+ if verbose, we report how many of each problem we had. */
+
+struct complaint
+{
+ char *message;
+ unsigned counter;
+ struct complaint *next;
+};
+
+/* Root of the chain of complaints that have at some point been issued.
+ This is used to reset the counters, and/or report the total counts. */
+
+extern struct complaint complaint_root[1];
+
+/* Functions that handle complaints. (in complaints.c) */
+
+extern void
+complain ();
+
+extern void
+clear_complaints PARAMS ((int, int));
diff --git a/gnu/usr.bin/gdb/gdb/copying.c b/gnu/usr.bin/gdb/gdb/copying.c
new file mode 100644
index 000000000000..ffc884a67140
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/copying.c
@@ -0,0 +1,327 @@
+/* ==> Do not modify this file!! It is created automatically
+ by copying.awk. Modify copying.awk instead. <== */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+static void
+show_copying_command PARAMS ((char *, int));
+
+static void
+show_warranty_command PARAMS ((char *, int));
+
+extern int immediate_quit;
+static void
+show_copying_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ immediate_quit++;
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" Version 2, June 1991\n");
+ printf_filtered ("\n");
+ printf_filtered (" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n");
+ printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n");
+ printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n");
+ printf_filtered (" of this license document, but changing it is not allowed.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Preamble\n");
+ printf_filtered ("\n");
+ printf_filtered (" The licenses for most software are designed to take away your\n");
+ printf_filtered ("freedom to share and change it. By contrast, the GNU General Public\n");
+ printf_filtered ("License is intended to guarantee your freedom to share and change free\n");
+ printf_filtered ("software--to make sure the software is free for all its users. This\n");
+ printf_filtered ("General Public License applies to most of the Free Software\n");
+ printf_filtered ("Foundation's software and to any other program whose authors commit to\n");
+ printf_filtered ("using it. (Some other Free Software Foundation software is covered by\n");
+ printf_filtered ("the GNU Library General Public License instead.) You can apply it to\n");
+ printf_filtered ("your programs, too.\n");
+ printf_filtered ("\n");
+ printf_filtered (" When we speak of free software, we are referring to freedom, not\n");
+ printf_filtered ("price. Our General Public Licenses are designed to make sure that you\n");
+ printf_filtered ("have the freedom to distribute copies of free software (and charge for\n");
+ printf_filtered ("this service if you wish), that you receive source code or can get it\n");
+ printf_filtered ("if you want it, that you can change the software or use pieces of it\n");
+ printf_filtered ("in new free programs; and that you know you can do these things.\n");
+ printf_filtered ("\n");
+ printf_filtered (" To protect your rights, we need to make restrictions that forbid\n");
+ printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n");
+ printf_filtered ("These restrictions translate to certain responsibilities for you if you\n");
+ printf_filtered ("distribute copies of the software, or if you modify it.\n");
+ printf_filtered ("\n");
+ printf_filtered (" For example, if you distribute copies of such a program, whether\n");
+ printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n");
+ printf_filtered ("you have. You must make sure that they, too, receive or can get the\n");
+ printf_filtered ("source code. And you must show them these terms so they know their\n");
+ printf_filtered ("rights.\n");
+ printf_filtered ("\n");
+ printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n");
+ printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n");
+ printf_filtered ("distribute and/or modify the software.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Also, for each author's protection and ours, we want to make certain\n");
+ printf_filtered ("that everyone understands that there is no warranty for this free\n");
+ printf_filtered ("software. If the software is modified by someone else and passed on, we\n");
+ printf_filtered ("want its recipients to know that what they have is not the original, so\n");
+ printf_filtered ("that any problems introduced by others will not reflect on the original\n");
+ printf_filtered ("authors' reputations.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Finally, any free program is threatened constantly by software\n");
+ printf_filtered ("patents. We wish to avoid the danger that redistributors of a free\n");
+ printf_filtered ("program will individually obtain patent licenses, in effect making the\n");
+ printf_filtered ("program proprietary. To prevent this, we have made it clear that any\n");
+ printf_filtered ("patent must be licensed for everyone's free use or not licensed at all.\n");
+ printf_filtered ("\n");
+ printf_filtered (" The precise terms and conditions for copying, distribution and\n");
+ printf_filtered ("modification follow.\n");
+ printf_filtered ("\n");
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n");
+ printf_filtered ("\n");
+ printf_filtered (" 0. This License applies to any program or other work which contains\n");
+ printf_filtered ("a notice placed by the copyright holder saying it may be distributed\n");
+ printf_filtered ("under the terms of this General Public License. The \"Program\", below,\n");
+ printf_filtered ("refers to any such program or work, and a \"work based on the Program\"\n");
+ printf_filtered ("means either the Program or any derivative work under copyright law:\n");
+ printf_filtered ("that is to say, a work containing the Program or a portion of it,\n");
+ printf_filtered ("either verbatim or with modifications and/or translated into another\n");
+ printf_filtered ("language. (Hereinafter, translation is included without limitation in\n");
+ printf_filtered ("the term \"modification\".) Each licensee is addressed as \"you\".\n");
+ printf_filtered ("\n");
+ printf_filtered ("Activities other than copying, distribution and modification are not\n");
+ printf_filtered ("covered by this License; they are outside its scope. The act of\n");
+ printf_filtered ("running the Program is not restricted, and the output from the Program\n");
+ printf_filtered ("is covered only if its contents constitute a work based on the\n");
+ printf_filtered ("Program (independent of having been made by running the Program).\n");
+ printf_filtered ("Whether that is true depends on what the Program does.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's\n");
+ printf_filtered ("source code as you receive it, in any medium, provided that you\n");
+ printf_filtered ("conspicuously and appropriately publish on each copy an appropriate\n");
+ printf_filtered ("copyright notice and disclaimer of warranty; keep intact all the\n");
+ printf_filtered ("notices that refer to this License and to the absence of any warranty;\n");
+ printf_filtered ("and give any other recipients of the Program a copy of this License\n");
+ printf_filtered ("along with the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("You may charge a fee for the physical act of transferring a copy, and\n");
+ printf_filtered ("you may at your option offer warranty protection in exchange for a fee.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 2. You may modify your copy or copies of the Program or any portion\n");
+ printf_filtered ("of it, thus forming a work based on the Program, and copy and\n");
+ printf_filtered ("distribute such modifications or work under the terms of Section 1\n");
+ printf_filtered ("above, provided that you also meet all of these conditions:\n");
+ printf_filtered ("\n");
+ printf_filtered (" a) You must cause the modified files to carry prominent notices\n");
+ printf_filtered (" stating that you changed the files and the date of any change.\n");
+ printf_filtered ("\n");
+ printf_filtered (" b) You must cause any work that you distribute or publish, that in\n");
+ printf_filtered (" whole or in part contains or is derived from the Program or any\n");
+ printf_filtered (" part thereof, to be licensed as a whole at no charge to all third\n");
+ printf_filtered (" parties under the terms of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) If the modified program normally reads commands interactively\n");
+ printf_filtered (" when run, you must cause it, when started running for such\n");
+ printf_filtered (" interactive use in the most ordinary way, to print or display an\n");
+ printf_filtered (" announcement including an appropriate copyright notice and a\n");
+ printf_filtered (" notice that there is no warranty (or else, saying that you provide\n");
+ printf_filtered (" a warranty) and that users may redistribute the program under\n");
+ printf_filtered (" these conditions, and telling the user how to view a copy of this\n");
+ printf_filtered (" License. (Exception: if the Program itself is interactive but\n");
+ printf_filtered (" does not normally print such an announcement, your work based on\n");
+ printf_filtered (" the Program is not required to print an announcement.)\n");
+ printf_filtered ("\n");
+ printf_filtered ("These requirements apply to the modified work as a whole. If\n");
+ printf_filtered ("identifiable sections of that work are not derived from the Program,\n");
+ printf_filtered ("and can be reasonably considered independent and separate works in\n");
+ printf_filtered ("themselves, then this License, and its terms, do not apply to those\n");
+ printf_filtered ("sections when you distribute them as separate works. But when you\n");
+ printf_filtered ("distribute the same sections as part of a whole which is a work based\n");
+ printf_filtered ("on the Program, the distribution of the whole must be on the terms of\n");
+ printf_filtered ("this License, whose permissions for other licensees extend to the\n");
+ printf_filtered ("entire whole, and thus to each and every part regardless of who wrote it.\n");
+ printf_filtered ("\n");
+ printf_filtered ("Thus, it is not the intent of this section to claim rights or contest\n");
+ printf_filtered ("your rights to work written entirely by you; rather, the intent is to\n");
+ printf_filtered ("exercise the right to control the distribution of derivative or\n");
+ printf_filtered ("collective works based on the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("In addition, mere aggregation of another work not based on the Program\n");
+ printf_filtered ("with the Program (or with a work based on the Program) on a volume of\n");
+ printf_filtered ("a storage or distribution medium does not bring the other work under\n");
+ printf_filtered ("the scope of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 3. You may copy and distribute the Program (or a work based on it,\n");
+ printf_filtered ("under Section 2) in object code or executable form under the terms of\n");
+ printf_filtered ("Sections 1 and 2 above provided that you also do one of the following:\n");
+ printf_filtered ("\n");
+ printf_filtered (" a) Accompany it with the complete corresponding machine-readable\n");
+ printf_filtered (" source code, which must be distributed under the terms of Sections\n");
+ printf_filtered (" 1 and 2 above on a medium customarily used for software interchange; or,\n");
+ printf_filtered ("\n");
+ printf_filtered (" b) Accompany it with a written offer, valid for at least three\n");
+ printf_filtered (" years, to give any third party, for a charge no more than your\n");
+ printf_filtered (" cost of physically performing source distribution, a complete\n");
+ printf_filtered (" machine-readable copy of the corresponding source code, to be\n");
+ printf_filtered (" distributed under the terms of Sections 1 and 2 above on a medium\n");
+ printf_filtered (" customarily used for software interchange; or,\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) Accompany it with the information you received as to the offer\n");
+ printf_filtered (" to distribute corresponding source code. (This alternative is\n");
+ printf_filtered (" allowed only for noncommercial distribution and only if you\n");
+ printf_filtered (" received the program in object code or executable form with such\n");
+ printf_filtered (" an offer, in accord with Subsection b above.)\n");
+ printf_filtered ("\n");
+ printf_filtered ("The source code for a work means the preferred form of the work for\n");
+ printf_filtered ("making modifications to it. For an executable work, complete source\n");
+ printf_filtered ("code means all the source code for all modules it contains, plus any\n");
+ printf_filtered ("associated interface definition files, plus the scripts used to\n");
+ printf_filtered ("control compilation and installation of the executable. However, as a\n");
+ printf_filtered ("special exception, the source code distributed need not include\n");
+ printf_filtered ("anything that is normally distributed (in either source or binary\n");
+ printf_filtered ("form) with the major components (compiler, kernel, and so on) of the\n");
+ printf_filtered ("operating system on which the executable runs, unless that component\n");
+ printf_filtered ("itself accompanies the executable.\n");
+ printf_filtered ("\n");
+ printf_filtered ("If distribution of executable or object code is made by offering\n");
+ printf_filtered ("access to copy from a designated place, then offering equivalent\n");
+ printf_filtered ("access to copy the source code from the same place counts as\n");
+ printf_filtered ("distribution of the source code, even though third parties are not\n");
+ printf_filtered ("compelled to copy the source along with the object code.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 4. You may not copy, modify, sublicense, or distribute the Program\n");
+ printf_filtered ("except as expressly provided under this License. Any attempt\n");
+ printf_filtered ("otherwise to copy, modify, sublicense or distribute the Program is\n");
+ printf_filtered ("void, and will automatically terminate your rights under this License.\n");
+ printf_filtered ("However, parties who have received copies, or rights, from you under\n");
+ printf_filtered ("this License will not have their licenses terminated so long as such\n");
+ printf_filtered ("parties remain in full compliance.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 5. You are not required to accept this License, since you have not\n");
+ printf_filtered ("signed it. However, nothing else grants you permission to modify or\n");
+ printf_filtered ("distribute the Program or its derivative works. These actions are\n");
+ printf_filtered ("prohibited by law if you do not accept this License. Therefore, by\n");
+ printf_filtered ("modifying or distributing the Program (or any work based on the\n");
+ printf_filtered ("Program), you indicate your acceptance of this License to do so, and\n");
+ printf_filtered ("all its terms and conditions for copying, distributing or modifying\n");
+ printf_filtered ("the Program or works based on it.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 6. Each time you redistribute the Program (or any work based on the\n");
+ printf_filtered ("Program), the recipient automatically receives a license from the\n");
+ printf_filtered ("original licensor to copy, distribute or modify the Program subject to\n");
+ printf_filtered ("these terms and conditions. You may not impose any further\n");
+ printf_filtered ("restrictions on the recipients' exercise of the rights granted herein.\n");
+ printf_filtered ("You are not responsible for enforcing compliance by third parties to\n");
+ printf_filtered ("this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 7. If, as a consequence of a court judgment or allegation of patent\n");
+ printf_filtered ("infringement or for any other reason (not limited to patent issues),\n");
+ printf_filtered ("conditions are imposed on you (whether by court order, agreement or\n");
+ printf_filtered ("otherwise) that contradict the conditions of this License, they do not\n");
+ printf_filtered ("excuse you from the conditions of this License. If you cannot\n");
+ printf_filtered ("distribute so as to satisfy simultaneously your obligations under this\n");
+ printf_filtered ("License and any other pertinent obligations, then as a consequence you\n");
+ printf_filtered ("may not distribute the Program at all. For example, if a patent\n");
+ printf_filtered ("license would not permit royalty-free redistribution of the Program by\n");
+ printf_filtered ("all those who receive copies directly or indirectly through you, then\n");
+ printf_filtered ("the only way you could satisfy both it and this License would be to\n");
+ printf_filtered ("refrain entirely from distribution of the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("If any portion of this section is held invalid or unenforceable under\n");
+ printf_filtered ("any particular circumstance, the balance of the section is intended to\n");
+ printf_filtered ("apply and the section as a whole is intended to apply in other\n");
+ printf_filtered ("circumstances.\n");
+ printf_filtered ("\n");
+ printf_filtered ("It is not the purpose of this section to induce you to infringe any\n");
+ printf_filtered ("patents or other property right claims or to contest validity of any\n");
+ printf_filtered ("such claims; this section has the sole purpose of protecting the\n");
+ printf_filtered ("integrity of the free software distribution system, which is\n");
+ printf_filtered ("implemented by public license practices. Many people have made\n");
+ printf_filtered ("generous contributions to the wide range of software distributed\n");
+ printf_filtered ("through that system in reliance on consistent application of that\n");
+ printf_filtered ("system; it is up to the author/donor to decide if he or she is willing\n");
+ printf_filtered ("to distribute software through any other system and a licensee cannot\n");
+ printf_filtered ("impose that choice.\n");
+ printf_filtered ("\n");
+ printf_filtered ("This section is intended to make thoroughly clear what is believed to\n");
+ printf_filtered ("be a consequence of the rest of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 8. If the distribution and/or use of the Program is restricted in\n");
+ printf_filtered ("certain countries either by patents or by copyrighted interfaces, the\n");
+ printf_filtered ("original copyright holder who places the Program under this License\n");
+ printf_filtered ("may add an explicit geographical distribution limitation excluding\n");
+ printf_filtered ("those countries, so that distribution is permitted only in or among\n");
+ printf_filtered ("countries not thus excluded. In such case, this License incorporates\n");
+ printf_filtered ("the limitation as if written in the body of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 9. The Free Software Foundation may publish revised and/or new versions\n");
+ printf_filtered ("of the General Public License from time to time. Such new versions will\n");
+ printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n");
+ printf_filtered ("address new problems or concerns.\n");
+ printf_filtered ("\n");
+ printf_filtered ("Each version is given a distinguishing version number. If the Program\n");
+ printf_filtered ("specifies a version number of this License which applies to it and \"any\n");
+ printf_filtered ("later version\", you have the option of following the terms and conditions\n");
+ printf_filtered ("either of that version or of any later version published by the Free\n");
+ printf_filtered ("Software Foundation. If the Program does not specify a version number of\n");
+ printf_filtered ("this License, you may choose any version ever published by the Free Software\n");
+ printf_filtered ("Foundation.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 10. If you wish to incorporate parts of the Program into other free\n");
+ printf_filtered ("programs whose distribution conditions are different, write to the author\n");
+ printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n");
+ printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n");
+ printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n");
+ printf_filtered ("of preserving the free status of all derivatives of our free software and\n");
+ printf_filtered ("of promoting the sharing and reuse of software generally.\n");
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+static void
+show_warranty_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ immediate_quit++;
+ printf_filtered (" NO WARRANTY\n");
+ printf_filtered ("\n");
+ printf_filtered (" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n");
+ printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n");
+ printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n");
+ printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n");
+ printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n");
+ printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n");
+ printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n");
+ printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n");
+ printf_filtered ("REPAIR OR CORRECTION.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n");
+ printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n");
+ printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n");
+ printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n");
+ printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n");
+ printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n");
+ printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n");
+ printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n");
+ printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n");
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+void
+_initialize_copying ()
+{
+ add_cmd ("copying", no_class, show_copying_command,
+ "Conditions for redistributing copies of GDB.",
+ &showlist);
+ add_cmd ("warranty", no_class, show_warranty_command,
+ "Various kinds of warranty you do not have.",
+ &showlist);
+
+ /* For old-timers, allow "info copying", etc. */
+ add_info ("copying", show_copying_command,
+ "Conditions for redistributing copies of GDB.");
+ add_info ("warranty", show_warranty_command,
+ "Various kinds of warranty you do not have.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/core.c b/gnu/usr.bin/gdb/gdb/core.c
new file mode 100644
index 000000000000..36c9ab5e75a0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/core.c
@@ -0,0 +1,291 @@
+/* Core dump and executable file functions above target vector, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "symtab.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "bfd.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "dis-asm.h"
+
+extern char registers[];
+
+/* Hook for `exec_file_command' command to call. */
+
+void (*exec_file_display_hook) PARAMS ((char *)) = NULL;
+
+/* Binary file diddling handle for the core file. */
+
+bfd *core_bfd = NULL;
+
+
+/* Backward compatability with old way of specifying core files. */
+
+void
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ struct target_ops *t;
+
+ dont_repeat (); /* Either way, seems bogus. */
+
+ t = find_core_target ();
+ if (t != NULL)
+ if (!filename)
+ (t->to_detach) (filename, from_tty);
+ else
+ (t->to_open) (filename, from_tty);
+ else
+ error ("GDB can't read core files on this machine.");
+}
+
+
+/* Call this to specify the hook for exec_file_command to call back.
+ This is called from the x-window display code. */
+
+void
+specify_exec_file_hook (hook)
+ void (*hook) PARAMS ((char *));
+{
+ exec_file_display_hook = hook;
+}
+
+/* The exec file must be closed before running an inferior.
+ If it is needed again after the inferior dies, it must
+ be reopened. */
+
+void
+close_exec_file ()
+{
+#ifdef FIXME
+ if (exec_bfd)
+ bfd_tempclose (exec_bfd);
+#endif
+}
+
+void
+reopen_exec_file ()
+{
+#ifdef FIXME
+ if (exec_bfd)
+ bfd_reopen (exec_bfd);
+#endif
+}
+
+/* If we have both a core file and an exec file,
+ print a warning if they don't go together. */
+
+void
+validate_files ()
+{
+ if (exec_bfd && core_bfd)
+ {
+ if (!core_file_matches_executable_p (core_bfd, exec_bfd))
+ warning ("core file may not match specified executable file.");
+ else if (bfd_get_mtime(exec_bfd) > bfd_get_mtime(core_bfd))
+ warning ("exec file is newer than core file.");
+ }
+}
+
+/* Return the name of the executable file as a string.
+ ERR nonzero means get error if there is none specified;
+ otherwise return 0 in that case. */
+
+char *
+get_exec_file (err)
+ int err;
+{
+ if (exec_bfd) return bfd_get_filename(exec_bfd);
+ if (!err) return NULL;
+
+ error ("No executable file specified.\n\
+Use the \"file\" or \"exec-file\" command.");
+ return NULL;
+}
+
+
+/* Report a memory error with error(). */
+
+void
+memory_error (status, memaddr)
+ int status;
+ CORE_ADDR memaddr;
+{
+
+ if (status == EIO)
+ {
+ /* Actually, address between memaddr and memaddr + len
+ was out of bounds. */
+ error ("Cannot access memory at address %s.",
+ local_hex_string((unsigned long) memaddr));
+ }
+ else
+ {
+ error ("Error accessing memory address %s: %s.",
+ local_hex_string ((unsigned long) memaddr),
+ safe_strerror (status));
+ }
+}
+
+/* Same as target_read_memory, but report an error if can't read. */
+void
+read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int status;
+ status = target_read_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Like target_read_memory, but slightly different parameters. */
+
+int
+dis_asm_read_memory (memaddr, myaddr, len, info)
+ bfd_vma memaddr;
+ bfd_byte *myaddr;
+ int len;
+ disassemble_info *info;
+{
+ return target_read_memory (memaddr, (char *) myaddr, len);
+}
+
+/* Like memory_error with slightly different parameters. */
+void
+dis_asm_memory_error (status, memaddr, info)
+ int status;
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ memory_error (status, memaddr);
+}
+
+/* Like print_address with slightly different parameters. */
+void
+dis_asm_print_address (addr, info)
+ bfd_vma addr;
+ struct disassemble_info *info;
+{
+ print_address (addr, info->stream);
+}
+
+/* Same as target_write_memory, but report an error if can't write. */
+void
+write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int status;
+
+ status = target_write_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+LONGEST
+read_memory_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char buf[sizeof (LONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_signed_integer (buf, len);
+}
+
+unsigned LONGEST
+read_memory_unsigned_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char buf[sizeof (unsigned LONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_unsigned_integer (buf, len);
+}
+
+/* The current default bfd target. Points to storage allocated for
+ gnutarget_string. */
+char *gnutarget;
+
+/* Same thing, except it is "auto" not NULL for the default case. */
+static char *gnutarget_string;
+
+static void set_gnutarget_command
+ PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_gnutarget_command (ignore, from_tty, c)
+ char *ignore;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (STREQ (gnutarget_string, "auto"))
+ gnutarget = NULL;
+ else
+ gnutarget = gnutarget_string;
+}
+
+/* Set the gnutarget. */
+void
+set_gnutarget (newtarget)
+ char *newtarget;
+{
+ if (gnutarget_string != NULL)
+ free (gnutarget_string);
+ gnutarget_string = savestring (newtarget, strlen (newtarget));
+ set_gnutarget_command (NULL, 0, NULL);
+}
+
+void
+_initialize_core()
+{
+ struct cmd_list_element *c;
+ c = add_cmd ("core-file", class_files, core_file_command,
+ "Use FILE as core dump for examining memory and registers.\n\
+No arg means have no core file. This command has been superseded by the\n\
+`target core' and `detach' commands.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_set_cmd ("gnutarget", class_files, var_string_noescape,
+ (char *) &gnutarget_string,
+ "Set the current BFD target.\n\
+Use `set gnutarget auto' to specify automatic detection.",
+ &setlist);
+ c->function.sfunc = set_gnutarget_command;
+ add_show_from_set (c, &showlist);
+
+ if (getenv ("GNUTARGET"))
+ set_gnutarget (getenv ("GNUTARGET"));
+ else
+ set_gnutarget ("auto");
+}
diff --git a/gnu/usr.bin/gdb/gdb/coredep.c b/gnu/usr.bin/gdb/gdb/coredep.c
new file mode 100644
index 000000000000..d94fd9820c9d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coredep.c
@@ -0,0 +1,118 @@
+/* Extract registers from a "standard" core file, for GDB.
+ Copyright (C) 1988-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* core.c is supposed to be the more machine-independent aspects of this;
+ this file is more machine-specific. */
+
+#include "defs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include "gdbcore.h"
+
+/* These are needed on various systems to expand REGISTER_U_ADDR. */
+#ifndef USG
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#ifndef NO_PTRACE_H
+# ifdef PTRACE_IN_WRONG_PLACE
+# include <ptrace.h>
+# else /* !PTRACE_IN_WRONG_PLACE */
+# include <sys/ptrace.h>
+# endif /* !PTRACE_IN_WRONG_PLACE */
+#endif /* NO_PTRACE_H */
+#endif
+
+#ifdef NEED_SYS_CORE_H
+#include <sys/core.h>
+#endif
+
+/* Extract the register values out of the core file and store
+ them where `read_register' will find them.
+
+ CORE_REG_SECT points to the register values themselves, read into memory.
+ CORE_REG_SIZE is the size of that area.
+ WHICH says which set of registers we are handling (0 = int, 2 = float
+ on machines where they are discontiguous).
+ REG_ADDR is the offset from u.u_ar0 to the register values relative to
+ core_reg_sect. This is used with old-fashioned core files to
+ locate the registers in a large upage-plus-stack ".reg" section.
+ Original upage address X is at location core_reg_sect+x+reg_addr.
+ */
+
+void
+fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
+ char *core_reg_sect;
+ unsigned core_reg_size;
+ int which;
+ unsigned reg_addr;
+{
+ register int regno;
+ register unsigned int addr;
+ int bad_reg = -1;
+ register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */
+
+ /* If u.u_ar0 was an absolute address in the core file, relativize it now,
+ so we can use it as an offset into core_reg_sect. When we're done,
+ "register 0" will be at core_reg_sect+reg_ptr, and we can use
+ register_addr to offset to the other registers. If this is a modern
+ core file without a upage, reg_ptr will be zero and this is all a big
+ NOP. */
+ if (reg_ptr > core_reg_size)
+ reg_ptr -= KERNEL_U_ADDR;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ addr = register_addr (regno, reg_ptr);
+ if (addr >= core_reg_size) {
+ if (bad_reg < 0)
+ bad_reg = regno;
+ } else {
+ supply_register (regno, core_reg_sect + addr);
+ }
+ }
+ if (bad_reg >= 0)
+ {
+ error ("Register %s not found in core file.", reg_names[bad_reg]);
+ }
+}
+
+
+#ifdef REGISTER_U_ADDR
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+unsigned int
+register_addr (regno, blockend)
+ int regno;
+ int blockend;
+{
+ int addr;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+#endif /* REGISTER_U_ADDR */
diff --git a/gnu/usr.bin/gdb/gdb/corelow.c b/gnu/usr.bin/gdb/gdb/corelow.c
new file mode 100644
index 000000000000..1cebc48985ec
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/corelow.c
@@ -0,0 +1,328 @@
+/* Core dump and executable file functions below target vector, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "symtab.h"
+#include "command.h"
+#include "bfd.h"
+#include "target.h"
+#include "gdbcore.h"
+
+static void
+core_files_info PARAMS ((struct target_ops *));
+
+#ifdef SOLIB_ADD
+static int
+solib_add_stub PARAMS ((char *));
+#endif
+
+static void
+core_close PARAMS ((int));
+
+static void
+get_core_registers PARAMS ((int));
+
+/* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+/* ARGSUSED */
+static void
+core_close (quitting)
+ int quitting;
+{
+ inferior_pid = 0; /* Avoid confusion from thread stuff */
+
+ if (core_bfd) {
+ free (bfd_get_filename (core_bfd));
+ bfd_close (core_bfd);
+ core_bfd = NULL;
+#ifdef CLEAR_SOLIB
+ CLEAR_SOLIB ();
+#endif
+ if (core_ops.to_sections) {
+ free ((PTR)core_ops.to_sections);
+ core_ops.to_sections = NULL;
+ core_ops.to_sections_end = NULL;
+ }
+ }
+}
+
+#ifdef SOLIB_ADD
+/* Stub function for catch_errors around shared library hacking. */
+
+static int
+solib_add_stub (from_tty)
+ char *from_tty;
+{
+ SOLIB_ADD (NULL, (int)from_tty, &core_ops);
+ return 0;
+}
+#endif /* SOLIB_ADD */
+
+/* Look for sections whose names start with `.reg/' so that we can extract the
+ list of threads in a core file. */
+
+static void
+add_to_thread_list (abfd, asect, reg_sect_arg)
+ bfd *abfd;
+ asection *asect;
+ PTR reg_sect_arg;
+{
+ int thread_id;
+ asection *reg_sect = (asection *) reg_sect_arg;
+
+ if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0)
+ return;
+
+ thread_id = atoi (bfd_section_name (abfd, asect) + 5);
+
+ add_thread (thread_id);
+
+/* Warning, Will Robinson, looking at BFD private data! */
+
+ if (asect->filepos == reg_sect->filepos) /* Did we find .reg? */
+ inferior_pid = thread_id; /* Yes, make it current */
+}
+
+/* This routine opens and sets up the core file bfd */
+
+void
+core_open (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ const char *p;
+ int siggy;
+ struct cleanup *old_chain;
+ char *temp;
+ bfd *temp_bfd;
+ int ontop;
+ int scratch_chan;
+
+ target_preopen (from_tty);
+ if (!filename)
+ {
+ error (core_bfd?
+ "No core file specified. (Use `detach' to stop debugging a core file.)"
+ : "No core file specified.");
+ }
+
+ filename = tilde_expand (filename);
+ if (filename[0] != '/') {
+ temp = concat (current_directory, "/", filename, NULL);
+ free (filename);
+ filename = temp;
+ }
+
+ old_chain = make_cleanup (free, filename);
+
+ scratch_chan = open (filename, write_files? O_RDWR: O_RDONLY, 0);
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+
+ temp_bfd = bfd_fdopenr (filename, gnutarget, scratch_chan);
+ if (temp_bfd == NULL)
+ {
+ perror_with_name (filename);
+ }
+
+ if (!bfd_check_format (temp_bfd, bfd_core))
+ {
+ /* Do it after the err msg */
+ make_cleanup (bfd_close, temp_bfd);
+ error ("\"%s\" is not a core dump: %s", filename, bfd_errmsg(bfd_error));
+ }
+
+ /* Looks semi-reasonable. Toss the old core file and work on the new. */
+
+ discard_cleanups (old_chain); /* Don't free filename any more */
+ unpush_target (&core_ops);
+ core_bfd = temp_bfd;
+ old_chain = make_cleanup (core_close, core_bfd);
+
+ validate_files ();
+
+ /* Find the data section */
+ if (build_section_table (core_bfd, &core_ops.to_sections,
+ &core_ops.to_sections_end))
+ error ("Can't find sections in `%s': %s", bfd_get_filename(core_bfd),
+ bfd_errmsg (bfd_error));
+
+ ontop = !push_target (&core_ops);
+ discard_cleanups (old_chain);
+
+ p = bfd_core_file_failing_command (core_bfd);
+ if (p)
+ printf_filtered ("Core was generated by `%s'.\n", p);
+
+ siggy = bfd_core_file_failing_signal (core_bfd);
+ if (siggy > 0)
+ printf_filtered ("Program terminated with signal %d, %s.\n", siggy,
+ safe_strsignal (siggy));
+
+ /* Build up thread list from BFD sections. */
+
+ init_thread_list ();
+ bfd_map_over_sections (core_bfd, add_to_thread_list,
+ bfd_get_section_by_name (core_bfd, ".reg"));
+
+ if (ontop) {
+ /* Fetch all registers from core file */
+ target_fetch_registers (-1);
+
+ /* Add symbols and section mappings for any shared libraries */
+#ifdef SOLIB_ADD
+ catch_errors (solib_add_stub, (char *)from_tty, (char *)0,
+ RETURN_MASK_ALL);
+#endif
+
+ /* Now, set up the frame cache, and print the top of stack */
+ set_current_frame (create_new_frame (read_fp (),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ } else {
+ warning (
+"you won't be able to access this core file until you terminate\n\
+your %s; do ``info files''", current_target->to_longname);
+ }
+}
+
+void
+core_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Too many arguments");
+ unpush_target (&core_ops);
+ reinit_frame_cache ();
+ if (from_tty)
+ printf_filtered ("No core file now.\n");
+}
+
+/* Get the registers out of a core file. This is the machine-
+ independent part. Fetch_core_registers is the machine-dependent
+ part, typically implemented in the xm-file for each architecture. */
+
+/* We just get all the registers, so we don't use regno. */
+/* ARGSUSED */
+static void
+get_core_registers (regno)
+ int regno;
+{
+ sec_ptr reg_sec;
+ unsigned size;
+ char *the_regs;
+ char secname[10];
+
+ /* Thread support. If inferior_pid is non-zero, then we have found a core
+ file with threads (or multiple processes). In that case, we need to
+ use the appropriate register section, else we just use `.reg'. */
+
+ /* XXX - same thing needs to be done for floating-point (.reg2) sections. */
+
+ if (inferior_pid)
+ sprintf (secname, ".reg/%d", inferior_pid);
+ else
+ strcpy (secname, ".reg");
+
+ reg_sec = bfd_get_section_by_name (core_bfd, secname);
+ if (!reg_sec) goto cant;
+ size = bfd_section_size (core_bfd, reg_sec);
+ the_regs = alloca (size);
+ if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, size))
+ {
+ fetch_core_registers (the_regs, size, 0,
+ (unsigned) bfd_section_vma (abfd,reg_sec));
+ }
+ else
+ {
+cant:
+ fprintf_filtered (stderr, "Couldn't fetch registers from core file: %s\n",
+ bfd_errmsg (bfd_error));
+ }
+
+ /* Now do it again for the float registers, if they exist. */
+ reg_sec = bfd_get_section_by_name (core_bfd, ".reg2");
+ if (reg_sec) {
+ size = bfd_section_size (core_bfd, reg_sec);
+ the_regs = alloca (size);
+ if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0,
+ size))
+ {
+ fetch_core_registers (the_regs, size, 2,
+ (unsigned) bfd_section_vma (abfd,reg_sec));
+ }
+ else
+ {
+ fprintf_filtered (stderr, "Couldn't fetch register set 2 from core file: %s\n",
+ bfd_errmsg (bfd_error));
+ }
+ }
+ registers_fetched();
+}
+
+static void
+core_files_info (t)
+ struct target_ops *t;
+{
+ print_section_info (t, core_bfd);
+}
+
+/* If mourn is being called in all the right places, this could be say
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
+
+static int
+ignore (addr, contents)
+ CORE_ADDR addr;
+ char *contents;
+{
+}
+
+struct target_ops core_ops = {
+ "core", "Local core dump file",
+ "Use a core file as a target. Specify the filename of the core file.",
+ core_open, core_close,
+ find_default_attach, core_detach, 0, 0, /* resume, wait */
+ get_core_registers,
+ 0, 0, /* store_regs, prepare_to_store */
+ xfer_memory, core_files_info,
+ ignore, ignore, /* core_insert_breakpoint, core_remove_breakpoint, */
+ 0, 0, 0, 0, 0, /* terminal stuff */
+ 0, 0, 0, /* kill, load, lookup sym */
+ find_default_create_inferior, 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ core_stratum, 0, /* next */
+ 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_corelow()
+{
+ add_target (&core_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/cp-valprint.c b/gnu/usr.bin/gdb/gdb/cp-valprint.c
new file mode 100644
index 000000000000..47b38f803d9b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/cp-valprint.c
@@ -0,0 +1,484 @@
+/* Support for printing C++ values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "demangle.h"
+
+int vtblprint; /* Controls printing of vtbl's */
+int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+struct obstack dont_print_obstack;
+
+static void
+cplus_print_value PARAMS ((struct type *, char *, FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+/* BEGIN-FIXME: Hooks into typeprint.c, find a better home for prototypes. */
+
+extern void
+c_type_print_base PARAMS ((struct type *, FILE *, int, int));
+
+extern void
+c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ FILE *));
+
+extern struct obstack dont_print_obstack;
+
+/* END-FIXME */
+
+
+/* BEGIN-FIXME: Hooks into c-valprint.c */
+
+extern int
+c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, int,
+ enum val_prettyprint));
+/* END-FIXME */
+
+
+void
+cp_print_class_method (valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ FILE *stream;
+{
+ struct type *domain;
+ struct fn_field *f = NULL;
+ int j = 0;
+ int len2;
+ int offset;
+ char *kind = "";
+ CORE_ADDR addr;
+ struct symbol *sym;
+ unsigned len;
+ unsigned int i;
+
+ check_stub_type (TYPE_TARGET_TYPE (type));
+ domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+ if (domain == (struct type *)NULL)
+ {
+ fprintf_filtered (stream, "<unknown>");
+ return;
+ }
+ addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
+ if (METHOD_PTR_IS_VIRTUAL (addr))
+ {
+ offset = METHOD_PTR_TO_VOFFSET (addr);
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
+ {
+ kind = "virtual ";
+ goto common;
+ }
+ }
+ }
+ }
+ else
+ {
+ sym = find_pc_function (addr);
+ if (sym == 0)
+ {
+ error ("invalid pointer to member function");
+ }
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (domain, i, j);
+ if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+ {
+ goto common;
+ }
+ }
+ }
+ }
+ common:
+ if (i < len)
+ {
+ fprintf_filtered (stream, "&");
+ c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
+ fprintf (stream, kind);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+ {
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (domain, i),
+ 0, stream);
+ }
+ else
+ {
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (domain, i),
+ 0, stream);
+ }
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") %d", (int) addr >> 3);
+ }
+}
+
+/* Return truth value for assertion that TYPE is of the type
+ "pointer to virtual function". */
+
+int
+cp_is_vtbl_ptr_type(type)
+ struct type *type;
+{
+ char *typename = type_name_no_tag (type);
+ /* This was what it was for gcc 2.4.5 and earlier. */
+ static const char vtbl_ptr_name_old[] =
+ { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+ /* It was changed to this after 2.4.5. */
+ static const char vtbl_ptr_name[] =
+ { '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+
+ return (typename != NULL
+ && (STREQ (typename, vtbl_ptr_name)
+ || STREQ (typename, vtbl_ptr_name_old)));
+}
+
+/* Return truth value for the assertion that TYPE is of the type
+ "pointer to virtual function table". */
+
+int
+cp_is_vtbl_member(type)
+ struct type *type;
+{
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ type = TYPE_TARGET_TYPE (type);
+ else
+ return 0;
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT)
+ /* Virtual functions tables are full of pointers to virtual functions. */
+ return cp_is_vtbl_ptr_type (TYPE_TARGET_TYPE (type));
+ return 0;
+}
+
+/* Mutually recursive subroutines of cplus_print_value and c_val_print to
+ print out a structure's fields: cp_print_value_fields and cplus_print_value.
+
+ TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
+ same meanings as in cplus_print_value and c_val_print.
+
+ DONT_PRINT is an array of baseclass types that we
+ should not print, or zero if called from top level. */
+
+void
+cp_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ dont_print)
+ struct type *type;
+ char *valaddr;
+ FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ int i, len, n_baseclasses;
+
+ check_stub_type (type);
+
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* Print out baseclasses such that we don't print
+ duplicates of virtual baseclasses. */
+ if (n_baseclasses > 0)
+ cplus_print_value (type, valaddr, stream, format, recurse+1, pretty,
+ dont_print);
+
+ if (!len && n_baseclasses == 1)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ extern int inspect_it;
+ int fields_seen = 0;
+
+ for (i = n_baseclasses; i < len; i++)
+ {
+ /* Check if static field */
+ if (TYPE_FIELD_STATIC (type, i))
+ continue;
+ if (fields_seen)
+ fprintf_filtered (stream, ", ");
+ else if (n_baseclasses > 0)
+ {
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ fputs_filtered ("members of ", stream);
+ fputs_filtered (type_name_no_tag (type), stream);
+ fputs_filtered (": ", stream);
+ }
+ }
+ fields_seen = 1;
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ wrap_here (n_spaces (2 + 2 * recurse));
+ }
+ if (inspect_it)
+ {
+ if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
+ fputs_filtered ("\"( ptr \"", stream);
+ else
+ fputs_filtered ("\"( nodef \"", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered ("\" \"", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered ("\") \"", stream);
+ }
+ else
+ {
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered (" = ", stream);
+ }
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ value v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ v = value_from_longest (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr, i));
+
+ c_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ else
+ {
+ c_val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "}");
+}
+
+/* Special val_print routine to avoid printing multiple copies of virtual
+ baseclasses. */
+
+static void
+cplus_print_value (type, valaddr, stream, format, recurse, pretty, dont_print)
+ struct type *type;
+ char *valaddr;
+ FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ struct obstack tmp_obstack;
+ struct type **last_dont_print
+ = (struct type **)obstack_next_free (&dont_print_obstack);
+ int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ if (dont_print == 0)
+ {
+ /* If we're at top level, carve out a completely fresh
+ chunk of the obstack and use that until this particular
+ invocation returns. */
+ tmp_obstack = dont_print_obstack;
+ /* Bump up the high-water mark. Now alpha is omega. */
+ obstack_finish (&dont_print_obstack);
+ }
+
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ char *baddr;
+ int err;
+ char *basename = TYPE_NAME (TYPE_BASECLASS (type, i));
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ struct type **first_dont_print
+ = (struct type **)obstack_base (&dont_print_obstack);
+
+ int j = (struct type **)obstack_next_free (&dont_print_obstack)
+ - first_dont_print;
+
+ while (--j >= 0)
+ if (TYPE_BASECLASS (type, i) == first_dont_print[j])
+ goto flush_it;
+
+ obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i));
+ }
+
+ /* Fix to use baseclass_offset instead. FIXME */
+ baddr = baseclass_addr (type, i, valaddr, 0, &err);
+ if (err == 0 && baddr == 0)
+ error ("could not find virtual baseclass %s\n",
+ basename ? basename : "");
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ fputs_filtered ("<", stream);
+ /* Not sure what the best notation is in the case where there is no
+ baseclass name. */
+ fputs_filtered (basename ? basename : "", stream);
+ fputs_filtered ("> = ", stream);
+ if (err != 0)
+ fprintf_filtered (stream,
+ "<invalid address 0x%lx>", (unsigned long) baddr);
+ else
+ cp_print_value_fields (TYPE_BASECLASS (type, i), baddr, stream, format,
+ recurse, pretty,
+ (struct type **) obstack_base (&dont_print_obstack));
+ fputs_filtered (", ", stream);
+
+ flush_it:
+ ;
+ }
+
+ if (dont_print == 0)
+ {
+ /* Free the space used to deal with the printing
+ of this type from top level. */
+ obstack_free (&dont_print_obstack, last_dont_print);
+ /* Reset watermark so that we can continue protecting
+ ourselves from whatever we were protecting ourselves. */
+ dont_print_obstack = tmp_obstack;
+ }
+}
+
+void
+cp_print_class_member (valaddr, domain, stream, prefix)
+ char *valaddr;
+ struct type *domain;
+ FILE *stream;
+ char *prefix;
+{
+
+ /* VAL is a byte offset into the structure type DOMAIN.
+ Find the name of the field for that offset and
+ print it. */
+ int extra = 0;
+ int bits = 0;
+ register unsigned int i;
+ unsigned len = TYPE_NFIELDS (domain);
+ /* @@ Make VAL into bit offset */
+ LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
+ for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ {
+ int bitpos = TYPE_FIELD_BITPOS (domain, i);
+ QUIT;
+ if (val == bitpos)
+ break;
+ if (val < bitpos && i != 0)
+ {
+ /* Somehow pointing into a field. */
+ i -= 1;
+ extra = (val - TYPE_FIELD_BITPOS (domain, i));
+ if (extra & 0x7)
+ bits = 1;
+ else
+ extra >>= 3;
+ break;
+ }
+ }
+ if (i < len)
+ {
+ char *name;
+ fprintf_filtered (stream, prefix);
+ name = type_name_no_tag (domain);
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (domain, stream, 0, 0);
+ fprintf_filtered (stream, "::");
+ fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
+ if (extra)
+ fprintf_filtered (stream, " + %d bytes", extra);
+ if (bits)
+ fprintf_filtered (stream, " (offset in bits)");
+ }
+ else
+ fprintf_filtered (stream, "%d", val >> 3);
+}
+
+void
+_initialize_cp_valprint ()
+{
+ add_show_from_set
+ (add_set_cmd ("vtbl", class_support, var_boolean, (char *)&vtblprint,
+ "Set printing of C++ virtual function tables.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("object", class_support, var_boolean, (char *)&objectprint,
+ "Set printing of object's derived type based on vtable info.",
+ &setprintlist),
+ &showprintlist);
+
+ /* Give people the defaults which they are used to. */
+ objectprint = 0;
+ vtblprint = 0;
+ obstack_begin (&dont_print_obstack, 32 * sizeof (struct type *));
+}
diff --git a/gnu/usr.bin/gdb/gdb/dbxread.c b/gnu/usr.bin/gdb/gdb/dbxread.c
new file mode 100644
index 000000000000..7f4ef2632abb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dbxread.c
@@ -0,0 +1,2234 @@
+/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides three functions: dbx_symfile_init,
+ which initializes to read a symbol file; dbx_new_init, which
+ discards existing cached information when all symbols are being
+ discarded; and dbx_symfile_read, which reads a symbol table
+ from a file.
+
+ dbx_symfile_read only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real. dbx_psymtab_to_symtab() is the function that does this */
+
+#include "defs.h"
+#include <string.h>
+
+#if defined(USG) || defined(__CYGNUSCLIB__)
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <obstack.h>
+#include <sys/param.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "target.h"
+#include "gdbcore.h" /* for bfd stuff */
+#include "libbfd.h" /* FIXME Secret internal BFD stuff (bfd_read) */
+#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "demangle.h"
+#include "language.h" /* Needed inside partial-stab.h */
+#include "complaints.h"
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now */
+
+#if !defined (SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+/* Each partial symbol table entry contains a pointer to private data for the
+ read_symtab() function to use when expanding a partial symbol table entry
+ to a full symbol table entry.
+
+ For dbxread this structure contains the offset within the file symbol table
+ of first local symbol for this file, and length (in bytes) of the section
+ of the symbol table devoted to this file's symbols (actually, the section
+ bracketed may contain more than just this file's symbols). It also contains
+ further information needed to locate the symbols if they are in an ELF file.
+
+ If ldsymlen is 0, the only reason for this thing's existence is the
+ dependency list. Nothing else will happen when it is read in. */
+
+#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff)
+#define LDSYMLEN(p) (((struct symloc *)((p)->read_symtab_private))->ldsymlen)
+#define SYMLOC(p) ((struct symloc *)((p)->read_symtab_private))
+#define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size)
+#define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset)
+#define STRING_OFFSET(p) (SYMLOC(p)->string_offset)
+#define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset)
+
+struct symloc {
+ int ldsymoff;
+ int ldsymlen;
+ int symbol_size;
+ int symbol_offset;
+ int string_offset;
+ int file_string_offset;
+};
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+ of a file. Some machines override this definition. */
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems. Ignore it */
+#define IGNORE_SYMBOL(type) (type == (int)N_NSYMS)
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc. */
+#ifndef GCC_COMPILED_FLAG_SYMBOL
+#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc2. */
+#ifndef GCC2_COMPILED_FLAG_SYMBOL
+#define GCC2_COMPILED_FLAG_SYMBOL "gcc2_compiled."
+#endif
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+ gives the correct address. Otherwise assume pcc gives the
+ address of the corresponding int, which is not the same on a
+ big-endian machine. */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+/* Remember what we deduced to be the source language of this psymtab. */
+
+static enum language psymtab_language = language_unknown;
+
+/* Nonzero means give verbose info on gdb action. From main.c. */
+extern int info_verbose;
+
+/* The BFD for this file -- implicit parameter to next_symbol_text. */
+
+static bfd *symfile_bfd;
+
+/* The size of each symbol in the symbol file (in external form).
+ This is set by dbx_symfile_read when building psymtabs, and by
+ dbx_psymtab_to_symtab when building symtabs. */
+
+static unsigned symbol_size;
+
+/* This is the offset of the symbol table in the executable file */
+static unsigned symbol_table_offset;
+
+/* This is the offset of the string table in the executable file */
+static unsigned string_table_offset;
+
+/* For elf+stab executables, the n_strx field is not a simple index
+ into the string table. Instead, each .o file has a base offset
+ in the string table, and the associated symbols contain offsets
+ from this base. The following two variables contain the base
+ offset for the current and next .o files. */
+static unsigned int file_string_table_offset;
+static unsigned int next_file_string_table_offset;
+
+/* Complaints about the symbols we have encountered. */
+
+struct complaint lbrac_complaint =
+ {"bad block start address patched", 0, 0};
+
+struct complaint string_table_offset_complaint =
+ {"bad string table offset in symbol %d", 0, 0};
+
+struct complaint unknown_symtype_complaint =
+ {"unknown symbol type %s", 0, 0};
+
+struct complaint unknown_symchar_complaint =
+ {"unknown symbol type character `%c'", 0, 0};
+
+struct complaint lbrac_rbrac_complaint =
+ {"block start larger than block end", 0, 0};
+
+struct complaint lbrac_unmatched_complaint =
+ {"unmatched N_LBRAC before symtab pos %d", 0, 0};
+
+struct complaint lbrac_mismatch_complaint =
+ {"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0};
+
+struct complaint repeated_header_complaint =
+ {"\"repeated\" header file not previously seen, at symtab pos %d", 0, 0};
+
+struct complaint repeated_header_name_complaint =
+ {"\"repeated\" header file not previously seen, named %s", 0, 0};
+
+/* During initial symbol readin, we need to have a structure to keep
+ track of which psymtabs have which bincls in them. This structure
+ is used during readin to setup the list of dependencies within each
+ partial symbol table. */
+
+struct header_file_location
+{
+ char *name; /* Name of header file */
+ int instance; /* See above */
+ struct partial_symtab *pst; /* Partial symtab that has the
+ BINCL/EINCL defs for this file */
+};
+
+/* The actual list and controling variables */
+static struct header_file_location *bincl_list, *next_bincl;
+static int bincls_allocated;
+
+/* Local function prototypes */
+
+static void
+free_header_files PARAMS ((void));
+
+static void
+init_header_files PARAMS ((void));
+
+static void
+read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+dbx_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+dbx_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_dbx_symtab PARAMS ((struct section_offsets *, struct objfile *,
+ CORE_ADDR, int));
+
+static void
+free_bincl_list PARAMS ((struct objfile *));
+
+static struct partial_symtab *
+find_corresponding_bincl_psymtab PARAMS ((char *, int));
+
+static void
+add_bincl_to_list PARAMS ((struct partial_symtab *, char *, int));
+
+static void
+init_bincl_list PARAMS ((int, struct objfile *));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *));
+
+static char *
+dbx_next_symbol_text PARAMS ((void));
+
+static void
+fill_symbuf PARAMS ((bfd *));
+
+static void
+dbx_symfile_init PARAMS ((struct objfile *));
+
+static void
+dbx_new_init PARAMS ((struct objfile *));
+
+static void
+dbx_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+dbx_symfile_finish PARAMS ((struct objfile *));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *));
+
+static void
+add_new_header_file PARAMS ((char *, int));
+
+static void
+add_old_header_file PARAMS ((char *, int));
+
+static void
+add_this_object_header_file PARAMS ((int));
+
+/* Free up old header file tables */
+
+static void
+free_header_files ()
+{
+ register int i;
+
+ if (header_files != NULL)
+ {
+ for (i = 0; i < n_header_files; i++)
+ {
+ free (header_files[i].name);
+ }
+ free ((PTR)header_files);
+ header_files = NULL;
+ n_header_files = 0;
+ }
+ if (this_object_header_files)
+ {
+ free ((PTR)this_object_header_files);
+ this_object_header_files = NULL;
+ }
+ n_allocated_header_files = 0;
+ n_allocated_this_object_header_files = 0;
+}
+
+/* Allocate new header file tables */
+
+static void
+init_header_files ()
+{
+ n_header_files = 0;
+ n_allocated_header_files = 10;
+ header_files = (struct header_file *)
+ xmalloc (10 * sizeof (struct header_file));
+
+ n_allocated_this_object_header_files = 10;
+ this_object_header_files = (int *) xmalloc (10 * sizeof (int));
+}
+
+/* Add header file number I for this object file
+ at the next successive FILENUM. */
+
+static void
+add_this_object_header_file (i)
+ int i;
+{
+ if (n_this_object_header_files == n_allocated_this_object_header_files)
+ {
+ n_allocated_this_object_header_files *= 2;
+ this_object_header_files
+ = (int *) xrealloc ((char *) this_object_header_files,
+ n_allocated_this_object_header_files * sizeof (int));
+ }
+
+ this_object_header_files[n_this_object_header_files++] = i;
+}
+
+/* Add to this file an "old" header file, one already seen in
+ a previous object file. NAME is the header file's name.
+ INSTANCE is its instance code, to select among multiple
+ symbol tables for the same header file. */
+
+static void
+add_old_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register struct header_file *p = header_files;
+ register int i;
+
+ for (i = 0; i < n_header_files; i++)
+ if (STREQ (p[i].name, name) && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ complain (&repeated_header_complaint, symnum);
+ complain (&repeated_header_name_complaint, name);
+}
+
+/* Add to this file a "new" header file: definitions for its types follow.
+ NAME is the header file's name.
+ Most often this happens only once for each distinct header file,
+ but not necessarily. If it happens more than once, INSTANCE has
+ a different value each time, and references to the header file
+ use INSTANCE values to select among them.
+
+ dbx output contains "begin" and "end" markers for each new header file,
+ but at this level we just need to know which files there have been;
+ so we record the file when its "begin" is seen and ignore the "end". */
+
+static void
+add_new_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register int i;
+
+ /* Make sure there is room for one more header file. */
+
+ if (n_header_files == n_allocated_header_files)
+ {
+ n_allocated_header_files *= 2;
+ header_files = (struct header_file *)
+ xrealloc ((char *) header_files,
+ (n_allocated_header_files * sizeof (struct header_file)));
+ }
+
+ /* Create an entry for this header file. */
+
+ i = n_header_files++;
+ header_files[i].name = savestring (name, strlen(name));
+ header_files[i].instance = instance;
+ header_files[i].length = 10;
+ header_files[i].vector
+ = (struct type **) xmalloc (10 * sizeof (struct type *));
+ memset (header_files[i].vector, 0, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (i);
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (real_filenum, index)
+ int real_filenum, index;
+{
+ register struct header_file *f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ memset (&f->vector[f->length / 2],
+ '\0', f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+}
+#endif
+
+static void
+record_minimal_symbol (name, address, type, objfile)
+ char *name;
+ CORE_ADDR address;
+ int type;
+ struct objfile *objfile;
+{
+ enum minimal_symbol_type ms_type;
+
+ switch (type)
+ {
+ case N_TEXT | N_EXT: ms_type = mst_text; break;
+ case N_DATA | N_EXT: ms_type = mst_data; break;
+ case N_BSS | N_EXT: ms_type = mst_bss; break;
+ case N_ABS | N_EXT: ms_type = mst_abs; break;
+#ifdef N_SETV
+ case N_SETV | N_EXT: ms_type = mst_data; break;
+ case N_SETV:
+ /* I don't think this type actually exists; since a N_SETV is the result
+ of going over many .o files, it doesn't make sense to have one
+ file local. */
+ ms_type = mst_file_data;
+ break;
+#endif
+ case N_TEXT:
+ /* Don't put gcc_compiled, __gnu_compiled_cplus, and friends into
+ the minimal symbols, because if there is also another symbol
+ at the same address (e.g. the first function of the file),
+ lookup_minimal_symbol_by_pc would have no way of getting the
+ right one. */
+ if (name[0] == 'g'
+ && (strcmp (name, GCC_COMPILED_FLAG_SYMBOL) == 0
+ || strcmp (name, GCC2_COMPILED_FLAG_SYMBOL) == 0))
+ return;
+
+ {
+ char *tempstring = name;
+ if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ ++tempstring;
+ if (STREQN (tempstring, "__gnu_compiled", 14))
+ return;
+ }
+
+ case N_NBTEXT:
+ case N_FN:
+ case N_FN_SEQ:
+ ms_type = mst_file_text;
+ break;
+
+ case N_DATA:
+ ms_type = mst_file_data;
+
+ /* Check for __DYNAMIC, which is used by Sun shared libraries.
+ Record it as global even if it's local, not global, so
+ lookup_minimal_symbol can find it. We don't check symbol_leading_char
+ because for SunOS4 it always is '_'. */
+ if (name[8] == 'C' && STREQ ("__DYNAMIC", name))
+ ms_type = mst_data;
+
+ /* Same with virtual function tables, both global and static. */
+ {
+ char *tempstring = name;
+ if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ ++tempstring;
+ if (VTBL_PREFIX_P ((tempstring)))
+ ms_type = mst_data;
+ }
+ break;
+
+ case N_BSS:
+ ms_type = mst_file_bss;
+ break;
+
+ default: ms_type = mst_unknown; break;
+ }
+
+ prim_record_minimal_symbol
+ (obsavestring (name, strlen (name), &objfile -> symbol_obstack),
+ address,
+ ms_type);
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to dbx_symfile_init, which
+ put all the relevant info into a "struct dbx_symfile_info",
+ hung off the objfile structure.
+
+ SECTION_OFFSETS contains offsets relative to which the symbols in the
+ various sections are (depending where the sections were actually loaded).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file). */
+
+static void
+dbx_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline; /* FIXME comments above */
+{
+ bfd *sym_bfd;
+ int val;
+ struct cleanup *back_to;
+
+ sym_bfd = objfile->obfd;
+ val = bfd_seek (objfile->obfd, DBX_SYMTAB_OFFSET (objfile), SEEK_SET);
+ if (val < 0)
+ perror_with_name (objfile->name);
+
+ /* If we are reinitializing, or if we have never loaded syms yet, init */
+ if (mainline || objfile->global_psymbols.size == 0 || objfile->static_psymbols.size == 0)
+ init_psymbol_list (objfile);
+
+ symbol_size = DBX_SYMBOL_SIZE (objfile);
+ symbol_table_offset = DBX_SYMTAB_OFFSET (objfile);
+
+ pending_blocks = 0;
+ back_to = make_cleanup (really_free_pendings, 0);
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. */
+
+ read_dbx_symtab (section_offsets, objfile,
+ bfd_section_vma (sym_bfd, DBX_TEXT_SECT (objfile)),
+ bfd_section_size (sym_bfd, DBX_TEXT_SECT (objfile)));
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ if (!have_partial_symbols ()) {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+static void
+dbx_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+ init_header_files ();
+}
+
+
+/* dbx_symfile_init ()
+ is the dbx-specific initialization routine for reading symbols.
+ It is passed a struct objfile which contains, among other things,
+ the BFD for the file whose symbols are being read, and a slot for a pointer
+ to "private data" which we fill with goodies.
+
+ We read the string table into malloc'd space and stash a pointer to it.
+
+ Since BFD doesn't know how to read debug symbols in a format-independent
+ way (and may never do so...), we have to do it ourselves. We will never
+ be called unless this is an a.out (or very similar) file.
+ FIXME, there should be a cleaner peephole into the BFD environment here. */
+
+#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */
+
+static void
+dbx_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE];
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+
+ /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd))
+#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd))
+
+ /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+
+ DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL;
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+ DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd);
+ DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd);
+ DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET;
+
+ /* Read the string table and stash it away in the psymbol_obstack. It is
+ only needed as long as we need to expand psymbols into full symbols,
+ so when we blow away the psymbol the string table goes away as well.
+ Note that gdb used to use the results of attempting to malloc the
+ string table, based on the size it read, as a form of sanity check
+ for botched byte swapping, on the theory that a byte swapped string
+ table size would be so totally bogus that the malloc would fail. Now
+ that we put in on the psymbol_obstack, we can't do this since gdb gets
+ a fatal error (out of virtual memory) if the size is bogus. We can
+ however at least check to see if the size is less than the size of
+ the size field itself, or larger than the size of the entire file.
+ Note that all valid string tables have a size greater than zero, since
+ the bytes used to hold the size are included in the count. */
+
+ if (STRING_TABLE_OFFSET == 0)
+ {
+ /* It appears that with the existing bfd code, STRING_TABLE_OFFSET
+ will never be zero, even when there is no string table. This
+ would appear to be a bug in bfd. */
+ DBX_STRINGTAB_SIZE (objfile) = 0;
+ DBX_STRINGTAB (objfile) = NULL;
+ }
+ else
+ {
+ val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+
+ memset ((PTR) size_temp, 0, sizeof (size_temp));
+ val = bfd_read ((PTR) size_temp, sizeof (size_temp), 1, sym_bfd);
+ if (val < 0)
+ {
+ perror_with_name (name);
+ }
+ else if (val == 0)
+ {
+ /* With the existing bfd code, STRING_TABLE_OFFSET will be set to
+ EOF if there is no string table, and attempting to read the size
+ from EOF will read zero bytes. */
+ DBX_STRINGTAB_SIZE (objfile) = 0;
+ DBX_STRINGTAB (objfile) = NULL;
+ }
+ else
+ {
+ /* Read some data that would appear to be the string table size.
+ If there really is a string table, then it is probably the right
+ size. Byteswap if necessary and validate the size. Note that
+ the minimum is DBX_STRINGTAB_SIZE_SIZE. If we just read some
+ random data that happened to be at STRING_TABLE_OFFSET, because
+ bfd can't tell us there is no string table, the sanity checks may
+ or may not catch this. */
+ DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp);
+
+ if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp)
+ || DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size (%d bytes).",
+ DBX_STRINGTAB_SIZE (objfile));
+
+ DBX_STRINGTAB (objfile) =
+ (char *) obstack_alloc (&objfile -> psymbol_obstack,
+ DBX_STRINGTAB_SIZE (objfile));
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), DBX_STRINGTAB_SIZE (objfile), 1,
+ sym_bfd);
+ if (val != DBX_STRINGTAB_SIZE (objfile))
+ perror_with_name (name);
+ }
+ }
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+dbx_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ mfree (objfile -> md, objfile->sym_stab_info);
+ }
+ free_header_files ();
+}
+
+
+/* Buffer for reading the symbol table entries. */
+static struct internal_nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* Name of last function encountered. Used in Solaris to approximate
+ object file boundaries. */
+static char *last_function_name;
+
+/* The address in memory of the string table of the object file we are
+ reading (which might not be the "main" object file, but might be a
+ shared library or some other dynamically loaded thing). This is set
+ by read_dbx_symtab when building psymtabs, and by read_ofile_symtab
+ when building symtabs, and is used only by next_symbol_text. */
+static char *stringtab_global;
+
+/* Refill the symbol table input buffer
+ and set the variables that control fetching entries from it.
+ Reports an error if no data available.
+ This function can read past the end of the symbol table
+ (into the string table) but this does no harm. */
+
+static void
+fill_symbuf (sym_bfd)
+ bfd *sym_bfd;
+{
+ int nbytes = bfd_read ((PTR)symbuf, sizeof (symbuf), 1, sym_bfd);
+ if (nbytes < 0)
+ perror_with_name (bfd_get_filename (sym_bfd));
+ else if (nbytes == 0)
+ error ("Premature end of file reading symbol table");
+ symbuf_end = nbytes / symbol_size;
+ symbuf_idx = 0;
+}
+
+#define SWAP_SYMBOL(symp, abfd) \
+ { \
+ (symp)->n_strx = bfd_h_get_32(abfd, \
+ (unsigned char *)&(symp)->n_strx); \
+ (symp)->n_desc = bfd_h_get_16 (abfd, \
+ (unsigned char *)&(symp)->n_desc); \
+ (symp)->n_value = bfd_h_get_32 (abfd, \
+ (unsigned char *)&(symp)->n_value); \
+ }
+
+/* Invariant: The symbol pointed to by symbuf_idx is the first one
+ that hasn't been swapped. Swap the symbol at the same time
+ that symbuf_idx is incremented. */
+
+/* dbx allows the text of a symbol name to be continued into the
+ next symbol name! When such a continuation is encountered
+ (a \ at the end of the text of a name)
+ call this function to get the continuation. */
+
+static char *
+dbx_next_symbol_text ()
+{
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (symfile_bfd);
+ symnum++;
+ SWAP_SYMBOL(&symbuf[symbuf_idx], symfile_bfd);
+ return symbuf[symbuf_idx++].n_strx + stringtab_global
+ + file_string_table_offset;
+}
+
+/* Initializes storage for all of the partial symbols that will be
+ created by read_dbx_symtab and subsidiaries. */
+
+static void
+init_psymbol_list (objfile)
+ struct objfile *objfile;
+{
+ /* Free any previously allocated psymbol lists. */
+ if (objfile -> global_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+ if (objfile -> static_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol));
+ objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> static_psymbols.size * sizeof (struct partial_symbol));
+}
+
+/* Initialize the list of bincls to contain none and have some
+ allocated. */
+
+static void
+init_bincl_list (number, objfile)
+ int number;
+ struct objfile *objfile;
+{
+ bincls_allocated = number;
+ next_bincl = bincl_list = (struct header_file_location *)
+ xmmalloc (objfile -> md, bincls_allocated * sizeof(struct header_file_location));
+}
+
+/* Add a bincl to the list. */
+
+static void
+add_bincl_to_list (pst, name, instance)
+ struct partial_symtab *pst;
+ char *name;
+ int instance;
+{
+ if (next_bincl >= bincl_list + bincls_allocated)
+ {
+ int offset = next_bincl - bincl_list;
+ bincls_allocated *= 2;
+ bincl_list = (struct header_file_location *)
+ xmrealloc (pst->objfile->md, (char *)bincl_list,
+ bincls_allocated * sizeof (struct header_file_location));
+ next_bincl = bincl_list + offset;
+ }
+ next_bincl->pst = pst;
+ next_bincl->instance = instance;
+ next_bincl++->name = name;
+}
+
+/* Given a name, value pair, find the corresponding
+ bincl in the list. Return the partial symtab associated
+ with that header_file_location. */
+
+static struct partial_symtab *
+find_corresponding_bincl_psymtab (name, instance)
+ char *name;
+ int instance;
+{
+ struct header_file_location *bincl;
+
+ for (bincl = bincl_list; bincl < next_bincl; bincl++)
+ if (bincl->instance == instance
+ && STREQ (name, bincl->name))
+ return bincl->pst;
+
+ return (struct partial_symtab *) 0;
+}
+
+/* Free the storage allocated for the bincl list. */
+
+static void
+free_bincl_list (objfile)
+ struct objfile *objfile;
+{
+ mfree (objfile -> md, (PTR)bincl_list);
+ bincls_allocated = 0;
+}
+
+/* Given pointers to an a.out symbol table in core containing dbx
+ style data, setup partial_symtab's describing each source file for
+ which debugging information is available.
+ SYMFILE_NAME is the name of the file we are reading from
+ and SECTION_OFFSETS is the set of offsets for the various sections
+ of the file (a set of zeros if the mainline program). */
+
+static void
+read_dbx_symtab (section_offsets, objfile, text_addr, text_size)
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+ CORE_ADDR text_addr;
+ int text_size;
+{
+ register struct internal_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */
+ register char *namestring;
+ int nsl;
+ int past_first_source_file = 0;
+ CORE_ADDR last_o_file_start = 0;
+ struct cleanup *back_to;
+ bfd *abfd;
+
+ /* End of the text segment of the executable file. */
+ CORE_ADDR end_of_text_addr;
+
+ /* Current partial symtab */
+ struct partial_symtab *pst;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ /* FIXME. We probably want to change stringtab_global rather than add this
+ while processing every symbol entry. FIXME. */
+ file_string_table_offset = 0;
+ next_file_string_table_offset = 0;
+
+ stringtab_global = DBX_STRINGTAB (objfile);
+
+ pst = (struct partial_symtab *) 0;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ /* Init bincl list */
+ init_bincl_list (20, objfile);
+ back_to = make_cleanup (free_bincl_list, objfile);
+
+ last_source_file = NULL;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+ end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT]
+ + text_size; /* Relocate */
+#endif
+
+ symfile_bfd = objfile->obfd; /* For next_text_symbol */
+ abfd = objfile->obfd;
+ symbuf_end = symbuf_idx = 0;
+ next_symbol_text_func = dbx_next_symbol_text;
+
+ for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++)
+ {
+ /* Get the symbol for this run and pull out some info */
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx++];
+
+ /*
+ * Special case to speed up readin.
+ */
+ if (bufp->n_type == (unsigned char)N_SLINE) continue;
+
+ SWAP_SYMBOL (bufp, abfd);
+
+ /* Ok. There is a lot of code duplicated in the rest of this
+ switch statement (for efficiency reasons). Since I don't
+ like duplicating code, I will do my penance here, and
+ describe the code which is duplicated:
+
+ *) The assignment to namestring.
+ *) The call to strchr.
+ *) The addition of a partial symbol the the two partial
+ symbol lists. This last is a large section of code, so
+ I've imbedded it in the following macro.
+ */
+
+/* Set namestring based on bufp. If the string table index is invalid,
+ give a fake name, and print a single error message per symbol file read,
+ rather than abort the symbol reading or flood the user with messages. */
+
+/*FIXME: Too many adds and indirections in here for the inner loop. */
+#define SET_NAMESTRING()\
+ if (((unsigned)bufp->n_strx + file_string_table_offset) >= \
+ DBX_STRINGTAB_SIZE (objfile)) { \
+ complain (&string_table_offset_complaint, symnum); \
+ namestring = "foo"; \
+ } else \
+ namestring = bufp->n_strx + file_string_table_offset + \
+ DBX_STRINGTAB (objfile)
+
+#define CUR_SYMBOL_TYPE bufp->n_type
+#define CUR_SYMBOL_VALUE bufp->n_value
+#define DBXREAD_ONLY
+#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\
+ start_psymtab(ofile, secoff, fname, low, symoff, global_syms, static_syms)
+#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)\
+ end_psymtab(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)
+
+#include "partial-stab.h"
+ }
+
+ /* If there's stuff to be cleaned up, clean it up. */
+ if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */
+/*FIXME, does this have a bug at start address 0? */
+ && last_o_file_start
+ && objfile -> ei.entry_point < bufp->n_value
+ && objfile -> ei.entry_point >= last_o_file_start)
+ {
+ objfile -> ei.entry_file_lowpc = last_o_file_start;
+ objfile -> ei.entry_file_highpc = bufp->n_value;
+ }
+
+ if (pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size, end_of_text_addr,
+ dependency_list, dependencies_used);
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Allocate and partially fill a partial symtab. It will be
+ completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal). */
+
+
+struct partial_symtab *
+start_psymtab (objfile, section_offsets,
+ filename, textlow, ldsymoff, global_syms, static_syms)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ char *filename;
+ CORE_ADDR textlow;
+ int ldsymoff;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ start_psymtab_common(objfile, section_offsets,
+ filename, textlow, global_syms, static_syms);
+
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc));
+ LDSYMOFF(result) = ldsymoff;
+ result->read_symtab = dbx_psymtab_to_symtab;
+ SYMBOL_SIZE(result) = symbol_size;
+ SYMBOL_OFFSET(result) = symbol_table_offset;
+ STRING_OFFSET(result) = string_table_offset;
+ FILE_STRING_OFFSET(result) = file_string_table_offset;
+
+ /* If we're handling an ELF file, drag some section-relocation info
+ for this source file out of the ELF symbol table, to compensate for
+ Sun brain death. This replaces the section_offsets in this psymtab,
+ if successful. */
+ elfstab_offset_sections (objfile, result);
+
+ /* Deduce the source language from the filename for this psymtab. */
+ psymtab_language = deduce_language_from_filename (filename);
+
+ return result;
+}
+
+/* Close off the current usage of PST.
+ Returns PST or NULL if the partial symtab was empty and thrown away.
+
+ FIXME: List variables and peculiarities of same. */
+
+struct partial_symtab *
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+ capping_text, dependency_list, number_dependencies)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_offset;
+ CORE_ADDR capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+/* struct partial_symbol *capping_global, *capping_static;*/
+{
+ int i;
+ struct partial_symtab *p1;
+ struct objfile *objfile = pst -> objfile;
+
+ if (capping_symbol_offset != -1)
+ LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst);
+ pst->texthigh = capping_text;
+
+ /* Under Solaris, the N_SO symbols always have a value of 0,
+ instead of the usual address of the .o file. Therefore,
+ we have to do some tricks to fill in texthigh and textlow.
+ The first trick is in partial-stab.h: if we see a static
+ or global function, and the textlow for the current pst
+ is still 0, then we use that function's address for
+ the textlow of the pst.
+
+ Now, to fill in texthigh, we remember the last function seen
+ in the .o file (also in partial-stab.h). Also, there's a hack in
+ bfd/elf.c and gdb/elfread.c to pass the ELF st_size field
+ to here via the misc_info field. Therefore, we can fill in
+ a reliable texthigh by taking the address plus size of the
+ last function in the file.
+
+ Unfortunately, that does not cover the case where the last function
+ in the file is static. See the paragraph below for more comments
+ on this situation.
+
+ Finally, if we have a valid textlow for the current file, we run
+ down the partial_symtab_list filling in previous texthighs that
+ are still unknown. */
+
+ if (pst->texthigh == 0 && last_function_name) {
+ char *p;
+ int n;
+ struct minimal_symbol *minsym;
+
+ p = strchr (last_function_name, ':');
+ if (p == NULL)
+ p = last_function_name;
+ n = p - last_function_name;
+ p = alloca (n + 1);
+ strncpy (p, last_function_name, n);
+ p[n] = 0;
+
+ minsym = lookup_minimal_symbol (p, objfile);
+
+ if (minsym) {
+ pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) +
+ (long) MSYMBOL_INFO (minsym);
+ } else {
+ /* This file ends with a static function, and it's
+ difficult to imagine how hard it would be to track down
+ the elf symbol. Luckily, most of the time no one will notice,
+ since the next file will likely be compiled with -g, so
+ the code below will copy the first fuction's start address
+ back to our texthigh variable. (Also, if this file is the
+ last one in a dynamically linked program, texthigh already
+ has the right value.) If the next file isn't compiled
+ with -g, then the last function in this file winds up owning
+ all of the text space up to the next -g file, or the end (minus
+ shared libraries). This only matters for single stepping,
+ and even then it will still work, except that it will single
+ step through all of the covered functions, instead of setting
+ breakpoints around them as it usualy does. This makes it
+ pretty slow, but at least it doesn't fail.
+
+ We can fix this with a fairly big change to bfd, but we need
+ to coordinate better with Cygnus if we want to do that. FIXME. */
+ }
+ last_function_name = NULL;
+ }
+
+ /* this test will be true if the last .o file is only data */
+ if (pst->textlow == 0)
+ pst->textlow = pst->texthigh;
+
+ /* If we know our own starting text address, then walk through all other
+ psymtabs for this objfile, and if any didn't know their ending text
+ address, set it to our starting address. Take care to not set our
+ own ending address to our starting address, nor to set addresses on
+ `dependency' files that have both textlow and texthigh zero. */
+ if (pst->textlow) {
+ ALL_OBJFILE_PSYMTABS (objfile, p1) {
+ if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) {
+ p1->texthigh = pst->textlow;
+ /* if this file has only data, then make textlow match texthigh */
+ if (p1->textlow == 0)
+ p1->textlow = p1->texthigh;
+ }
+ }
+ }
+
+ /* End of kludge for patching Solaris textlow and texthigh. */
+
+
+ pst->n_global_syms =
+ objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset);
+ pst->n_static_syms =
+ objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset);
+
+ pst->number_of_dependencies = number_dependencies;
+ if (number_dependencies)
+ {
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ memcpy (pst->dependencies, dependency_list,
+ number_dependencies * sizeof (struct partial_symtab *));
+ }
+ else
+ pst->dependencies = 0;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ struct partial_symtab *subpst =
+ allocate_psymtab (include_list[i], objfile);
+
+ subpst->section_offsets = pst->section_offsets;
+ subpst->read_symtab_private =
+ (char *) obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc));
+ LDSYMOFF(subpst) =
+ LDSYMLEN(subpst) =
+ subpst->textlow =
+ subpst->texthigh = 0;
+
+ /* We could save slight bits of space by only making one of these,
+ shared by the entire set of include files. FIXME-someday. */
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset =
+ subpst->n_global_syms =
+ subpst->statics_offset =
+ subpst->n_static_syms = 0;
+
+ subpst->readin = 0;
+ subpst->symtab = 0;
+ subpst->read_symtab = pst->read_symtab;
+ }
+
+ sort_pst_symbols (pst);
+
+ /* If there is already a psymtab or symtab for a file of this name, remove it.
+ (If there is a symtab, more drastic things also happen.)
+ This happens in VxWorks. */
+ free_named_symtabs (pst->filename);
+
+ if (num_includes == 0
+ && number_dependencies == 0
+ && pst->n_global_syms == 0
+ && pst->n_static_syms == 0) {
+ /* Throw away this psymtab, it's empty. We can't deallocate it, since
+ it is on the obstack, but we can forget to chain it on the list. */
+ struct partial_symtab *prev_pst;
+
+ /* First, snip it out of the psymtab chain */
+
+ if (pst->objfile->psymtabs == pst)
+ pst->objfile->psymtabs = pst->next;
+ else
+ for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next)
+ if (prev_pst->next == pst)
+ prev_pst->next = pst->next;
+
+ /* Next, put it on a free list for recycling */
+
+ pst->next = pst->objfile->free_psymtabs;
+ pst->objfile->free_psymtabs = pst;
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *)NULL;
+ }
+ return pst;
+}
+
+static void
+dbx_psymtab_to_symtab_1 (pst)
+ struct partial_symtab *pst;
+{
+ struct cleanup *old_chain;
+ int i;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ /* Read in all partial symtabs on which this one is dependent */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...", pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ fflush (stdout);
+ }
+ dbx_psymtab_to_symtab_1 (pst->dependencies[i]);
+ }
+
+ if (LDSYMLEN(pst)) /* Otherwise it's a dummy */
+ {
+ /* Init stuff necessary for reading in symbols */
+ stabsread_init ();
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+ file_string_table_offset = FILE_STRING_OFFSET (pst);
+ symbol_size = SYMBOL_SIZE (pst);
+
+ /* Read in this file's symbols */
+ bfd_seek (pst->objfile->obfd, SYMBOL_OFFSET (pst), SEEK_SET);
+ read_ofile_symtab (pst);
+ sort_symtab_syms (pst->symtab);
+
+ do_cleanups (old_chain);
+ }
+
+ pst->readin = 1;
+}
+
+/* Read in all of the symbols for a given psymtab for real.
+ Be verbose about it if the user wants that. */
+
+static void
+dbx_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+ bfd *sym_bfd;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ if (LDSYMLEN(pst) || pst->number_of_dependencies)
+ {
+ /* Print the message now, before reading the string table,
+ to avoid disconcerting pauses. */
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ fflush (stdout);
+ }
+
+ sym_bfd = pst->objfile->obfd;
+
+ next_symbol_text_func = dbx_next_symbol_text;
+
+ dbx_psymtab_to_symtab_1 (pst);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered ("done.\n");
+ }
+}
+
+/* Read in a defined section of a specific object file's symbols. */
+
+static void
+read_ofile_symtab (pst)
+ struct partial_symtab *pst;
+{
+ register char *namestring;
+ register struct internal_nlist *bufp;
+ unsigned char type;
+ unsigned max_symnum;
+ register bfd *abfd;
+ struct objfile *objfile;
+ int sym_offset; /* Offset to start of symbols to read */
+ int sym_size; /* Size of symbols to read */
+ CORE_ADDR text_offset; /* Start of text segment for symbols */
+ int text_size; /* Size of text segment for symbols */
+ struct section_offsets *section_offsets;
+
+ objfile = pst->objfile;
+ sym_offset = LDSYMOFF(pst);
+ sym_size = LDSYMLEN(pst);
+ text_offset = pst->textlow;
+ text_size = pst->texthigh - pst->textlow;
+ section_offsets = pst->section_offsets;
+
+ current_objfile = objfile;
+ subfile_stack = NULL;
+
+ stringtab_global = DBX_STRINGTAB (objfile);
+ last_source_file = NULL;
+
+ abfd = objfile->obfd;
+ symfile_bfd = objfile->obfd; /* Implicit param to next_text_symbol */
+ symbuf_end = symbuf_idx = 0;
+
+ /* It is necessary to actually read one symbol *before* the start
+ of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL
+ occurs before the N_SO symbol.
+
+ Detecting this in read_dbx_symtab
+ would slow down initial readin, so we look for it here instead. */
+ if (!processing_acc_compilation && sym_offset >= (int)symbol_size)
+ {
+ bfd_seek (symfile_bfd, sym_offset - symbol_size, SEEK_CUR);
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx++];
+ SWAP_SYMBOL (bufp, abfd);
+
+ SET_NAMESTRING ();
+
+ processing_gcc_compilation = 0;
+ if (bufp->n_type == N_TEXT)
+ {
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+ }
+
+ /* Try to select a C++ demangling based on the compilation unit
+ producer. */
+
+ if (processing_gcc_compilation)
+ {
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ }
+ else
+ {
+ /* The N_SO starting this symtab is the first symbol, so we
+ better not check the symbol before it. I'm not this can
+ happen, but it doesn't hurt to check for it. */
+ bfd_seek (symfile_bfd, sym_offset, SEEK_CUR);
+ processing_gcc_compilation = 0;
+ }
+
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx];
+ if (bufp->n_type != (unsigned char)N_SO)
+ error("First symbol in segment of executable not a source symbol");
+
+ max_symnum = sym_size / symbol_size;
+
+ for (symnum = 0;
+ symnum < max_symnum;
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf(abfd);
+ bufp = &symbuf[symbuf_idx++];
+ SWAP_SYMBOL (bufp, abfd);
+
+ type = bufp->n_type;
+
+ SET_NAMESTRING ();
+
+ if (type & N_STAB) {
+ process_one_symbol (type, bufp->n_desc, bufp->n_value,
+ namestring, section_offsets, objfile);
+ }
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+ else if (type == N_TEXT)
+ {
+ /* I don't think this code will ever be executed, because
+ the GCC_COMPILED_FLAG_SYMBOL usually is right before
+ the N_SO symbol which starts this source file.
+ However, there is no reason not to accept
+ the GCC_COMPILED_FLAG_SYMBOL anywhere. */
+
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ else if (type & N_EXT || type == (unsigned char)N_TEXT
+ || type == (unsigned char)N_NBTEXT
+ ) {
+ /* Global symbol: see if we came across a dbx defintion for
+ a corresponding symbol. If so, store the value. Remove
+ syms from the chain when their values are stored, but
+ search the whole chain, as there may be several syms from
+ different files with the same name. */
+ /* This is probably not true. Since the files will be read
+ in one at a time, each reference to a global symbol will
+ be satisfied in each file as it appears. So we skip this
+ section. */
+ ;
+ }
+ }
+
+ current_objfile = NULL;
+
+ /* In a Solaris elf file, this variable, which comes from the
+ value of the N_SO symbol, will still be 0. Luckily, text_offset,
+ which comes from pst->textlow is correct. */
+ if (last_source_start_addr == 0)
+ last_source_start_addr = text_offset;
+
+ pst->symtab = end_symtab (text_offset + text_size, 0, 0, objfile,
+ SECT_OFF_TEXT);
+ end_stabs ();
+}
+
+
+/* This handles a single symbol from the symbol-file, building symbols
+ into a GDB symtab. It takes these arguments and an implicit argument.
+
+ TYPE is the type field of the ".stab" symbol entry.
+ DESC is the desc field of the ".stab" entry.
+ VALU is the value field of the ".stab" entry.
+ NAME is the symbol name, in our address space.
+ SECTION_OFFSETS is a set of amounts by which the sections of this object
+ file were relocated when it was loaded into memory.
+ All symbols that refer
+ to memory locations need to be offset by these amounts.
+ OBJFILE is the object file from which we are reading symbols.
+ It is used in end_symtab. */
+
+void
+process_one_symbol (type, desc, valu, name, section_offsets, objfile)
+ int type, desc;
+ CORE_ADDR valu;
+ char *name;
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+{
+#ifdef SUN_FIXED_LBRAC_BUG
+ /* If SUN_FIXED_LBRAC_BUG is defined, then it tells us whether we need
+ to correct the address of N_LBRAC's. If it is not defined, then
+ we never need to correct the addresses. */
+
+ /* This records the last pc address we've seen. We depend on there being
+ an SLINE or FUN or SO before the first LBRAC, since the variable does
+ not get reset in between reads of different symbol files. */
+ static CORE_ADDR last_pc_address;
+#endif
+
+ register struct context_stack *new;
+ /* This remembers the address of the start of a function. It is used
+ because in Solaris 2, N_LBRAC, N_RBRAC, and N_SLINE entries are
+ relative to the current function's start address. On systems
+ other than Solaris 2, this just holds the SECT_OFF_TEXT value, and is
+ used to relocate these symbol types rather than SECTION_OFFSETS. */
+ static CORE_ADDR function_start_offset;
+
+ /* If this is nonzero, N_LBRAC, N_RBRAC, and N_SLINE entries are relative
+ to the function start address. */
+ int block_address_function_relative;
+
+ /* If this is nonzero, we've seen a non-gcc N_OPT symbol for this source
+ file. Used to detect the SunPRO solaris compiler. */
+ static int n_opt_found;
+
+ /* The stab type used for the definition of the last function.
+ N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */
+ static int function_stab_type = 0;
+
+ /* This is true for Solaris (and all other stabs-in-elf systems, hopefully,
+ since it would be silly to do things differently from Solaris), and
+ false for SunOS4 and other a.out file formats. */
+ block_address_function_relative =
+ 0 == strncmp (bfd_get_target (objfile->obfd), "elf", 3);
+
+ if (!block_address_function_relative)
+ /* N_LBRAC, N_RBRAC and N_SLINE entries are not relative to the
+ function start address, so just use the text offset. */
+ function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+
+ if (last_source_file == NULL && type != (unsigned char)N_SO)
+ {
+ /* Ignore any symbols which appear before an N_SO symbol. Currently
+ no one puts symbols there, but we should deal gracefully with the
+ case. A complain()t might be in order (if !IGNORE_SYMBOL (type)),
+ but this should not be an error (). */
+ return;
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto define_a_symbol;
+
+ case N_LBRAC:
+ /* This "symbol" just indicates the start of an inner lexical
+ context within a function. */
+
+#if defined(BLOCK_ADDRESS_ABSOLUTE)
+ /* Relocate for dynamic loading (?). */
+ valu += function_start_offset;
+#else
+ if (block_address_function_relative)
+ /* Relocate for Sun ELF acc fn-relative syms. */
+ valu += function_start_offset;
+ else
+ /* On most machines, the block addresses are relative to the
+ N_SO, the linker did not relocate them (sigh). */
+ valu += last_source_start_addr;
+#endif
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) {
+ /* Patch current LBRAC pc value to match last handy pc value */
+ complain (&lbrac_complaint);
+ valu = last_pc_address;
+ }
+#endif
+ new = push_context (desc, valu);
+ break;
+
+ case N_RBRAC:
+ /* This "symbol" just indicates the end of an inner lexical
+ context that was started with N_LBRAC. */
+
+#if defined(BLOCK_ADDRESS_ABSOLUTE)
+ /* Relocate for dynamic loading (?). */
+ valu += function_start_offset;
+#else
+ if (block_address_function_relative)
+ /* Relocate for Sun ELF acc fn-relative syms. */
+ valu += function_start_offset;
+ else
+ /* On most machines, the block addresses are relative to the
+ N_SO, the linker did not relocate them (sigh). */
+ valu += last_source_start_addr;
+#endif
+
+ new = pop_context();
+ if (desc != new->depth)
+ complain (&lbrac_mismatch_complaint, symnum);
+
+ /* Some compilers put the variable decls inside of an
+ LBRAC/RBRAC block. This macro should be nonzero if this
+ is true. DESC is N_DESC from the N_RBRAC symbol.
+ GCC_P is true if we've detected the GCC_COMPILED_SYMBOL
+ or the GCC2_COMPILED_SYMBOL. */
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0
+#endif
+
+ /* Can only use new->locals as local symbols here if we're in
+ gcc or on a machine that puts them before the lbrack. */
+ if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ local_symbols = new->locals;
+
+ /* If this is not the outermost LBRAC...RBRAC pair in the
+ function, its local symbols preceded it, and are the ones
+ just recovered from the context stack. Defined the block for them.
+
+ If this is the outermost LBRAC...RBRAC pair, there is no
+ need to do anything; leave the symbols that preceded it
+ to be attached to the function's own block. However, if
+ it is so, we need to indicate that we just moved outside
+ of the function. */
+ if (local_symbols
+ && (context_stack_depth
+ > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)))
+ {
+ /* FIXME Muzzle a compiler bug that makes end < start. */
+ if (new->start_addr > valu)
+ {
+ complain (&lbrac_rbrac_complaint);
+ new->start_addr = valu;
+ }
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ else
+ {
+ within_function = 0;
+ }
+ if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ break;
+
+ case N_FN:
+ case N_FN_SEQ:
+ /* This kind of symbol indicates the start of an object file. */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+
+ case N_SO:
+ /* This type of symbol indicates the start of data
+ for one source file.
+ Finish the symbol table of the previous source file
+ (if any) and start accumulating a new symbol table. */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ n_opt_found = 0;
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+
+#ifdef PCC_SOL_BROKEN
+ /* pcc bug, occasionally puts out SO for SOL. */
+ if (context_stack_depth > 0)
+ {
+ start_subfile (name, NULL);
+ break;
+ }
+#endif
+ if (last_source_file)
+ {
+ /* Check if previous symbol was also an N_SO (with some
+ sanity checks). If so, that one was actually the directory
+ name, and the current one is the real file name.
+ Patch things up. */
+ if (previous_stab_code == (unsigned char) N_SO)
+ {
+ patch_subfile_names (current_subfile, name);
+ break; /* Ignore repeated SOs */
+ }
+ end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT);
+ end_stabs ();
+ }
+ start_stabs ();
+ start_symtab (name, NULL, valu);
+ break;
+
+
+ case N_SOL:
+ /* This type of symbol indicates the start of data for
+ a sub-source-file, one whose contents were copied or
+ included in the compilation of the main source file
+ (whose name was given in the N_SO symbol.) */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ start_subfile (name, current_subfile->dirname);
+ break;
+
+ case N_BINCL:
+ push_subfile ();
+ add_new_header_file (name, valu);
+ start_subfile (name, current_subfile->dirname);
+ break;
+
+ case N_EINCL:
+ start_subfile (pop_subfile (), current_subfile->dirname);
+ break;
+
+ case N_EXCL:
+ add_old_header_file (name, valu);
+ break;
+
+ case N_SLINE:
+ /* This type of "symbol" really just records
+ one line-number -- core-address correspondence.
+ Enter it in the line list for this symbol table. */
+ /* Relocate for dynamic loading and for ELF acc fn-relative syms. */
+ valu += function_start_offset;
+#ifdef SUN_FIXED_LBRAC_BUG
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+ record_line (current_subfile, desc, valu);
+ break;
+
+ case N_BCOMM:
+ common_block_start (name, objfile);
+ break;
+
+ case N_ECOMM:
+ common_block_end (objfile);
+ break;
+
+ /* The following symbol types need to have the appropriate offset added
+ to their value; then we process symbol definitions in the name. */
+
+ case N_STSYM: /* Static symbol in data seg */
+ case N_LCSYM: /* Static symbol in BSS seg */
+ case N_ROSYM: /* Static symbol in Read-only data seg */
+ /* HORRID HACK DEPT. However, it's Sun's furgin' fault.
+ Solaris2's stabs-in-elf makes *most* symbols relative
+ but leaves a few absolute (at least for Solaris 2.1 and version
+ 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence.
+ .stab "foo:S...",N_STSYM is absolute (ld relocates it)
+ .stab "foo:V...",N_STSYM is relative (section base subtracted).
+ This leaves us no choice but to search for the 'S' or 'V'...
+ (or pass the whole section_offsets stuff down ONE MORE function
+ call level, which we really don't want to do). */
+ {
+ char *p;
+ p = strchr (name, ':');
+ if (p != 0 && p[1] == 'S')
+ {
+ /* The linker relocated it. There used to be a kludge here
+ to add the text offset, but that will break if we ever
+ start using the text offset (currently it is always zero). */
+ goto define_a_symbol;
+ }
+ /* Since it's not the kludge case, re-dispatch to the right handler. */
+ switch (type) {
+ case N_STSYM: goto case_N_STSYM;
+ case N_LCSYM: goto case_N_LCSYM;
+ case N_ROSYM: goto case_N_ROSYM;
+ default: abort();
+ }
+ }
+
+ case_N_STSYM: /* Static symbol in data seg */
+ case N_DSLINE: /* Source line number, data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto define_a_symbol;
+
+ case_N_LCSYM: /* Static symbol in BSS seg */
+ case N_BSLINE: /* Source line number, bss seg */
+ /* N_BROWS: overlaps with N_BSLINE */
+ valu += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ goto define_a_symbol;
+
+ case_N_ROSYM: /* Static symbol in Read-only data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_RODATA);
+ goto define_a_symbol;
+
+ case N_ENTRY: /* Alternate entry point */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto define_a_symbol;
+
+ /* The following symbol types we don't know how to process. Handle
+ them in a "default" way, but complain to people who care. */
+ default:
+ case N_CATCH: /* Exception handler catcher */
+ case N_EHDECL: /* Exception handler name */
+ case N_PC: /* Global symbol in Pascal */
+ case N_M2C: /* Modula-2 compilation unit */
+ /* N_MOD2: overlaps with N_EHDECL */
+ case N_SCOPE: /* Modula-2 scope information */
+ case N_ECOML: /* End common (local name) */
+ case N_NBTEXT: /* Gould Non-Base-Register symbols??? */
+ case N_NBDATA:
+ case N_NBBSS:
+ case N_NBSTS:
+ case N_NBLCS:
+ complain (&unknown_symtype_complaint,
+ local_hex_string((unsigned long) type));
+ /* FALLTHROUGH */
+
+ /* The following symbol types don't need the address field relocated,
+ since it is either unused, or is absolute. */
+ define_a_symbol:
+ case N_GSYM: /* Global variable */
+ case N_NSYMS: /* Number of symbols (ultrix) */
+ case N_NOMAP: /* No map? (ultrix) */
+ case N_RSYM: /* Register variable */
+ case N_DEFD: /* Modula-2 GNU module dependency */
+ case N_SSYM: /* Struct or union element */
+ case N_LSYM: /* Local symbol in stack */
+ case N_PSYM: /* Parameter variable */
+ case N_LENG: /* Length of preceding symbol type */
+ if (name)
+ {
+ int deftype;
+ char *colon_pos = strchr (name, ':');
+ if (colon_pos == NULL)
+ deftype = '\0';
+ else
+ deftype = colon_pos[1];
+
+ switch (deftype)
+ {
+ case 'f':
+ case 'F':
+ function_stab_type = type;
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ /* The Sun acc compiler, under SunOS4, puts out
+ functions with N_GSYM or N_STSYM. The problem is
+ that the address of the symbol is no good (for N_GSYM
+ it doesn't even attept an address; for N_STSYM it
+ puts out an address but then it gets relocated
+ relative to the data segment, not the text segment).
+ Currently we can't fix this up later as we do for
+ some types of symbol in scan_file_globals.
+ Fortunately we do have a way of finding the address -
+ we know that the value in last_pc_address is either
+ the one we want (if we're dealing with the first
+ function in an object file), or somewhere in the
+ previous function. This means that we can use the
+ minimal symbol table to get the address. */
+
+ /* On solaris up to 2.2, the N_FUN stab gets relocated.
+ On Solaris 2.3, ld no longer relocates stabs (which
+ is good), and the N_FUN's value is now always zero.
+ The following code can't deal with this, because
+ last_pc_address depends on getting the address from a
+ N_SLINE or some such and in Solaris those are function
+ relative. Best fix is probably to create a Ttext.text symbol
+ and handle this like Ddata.data and so on. */
+
+ if (type == N_GSYM || type == N_STSYM)
+ {
+ struct minimal_symbol *m;
+ int l = colon_pos - name;
+
+ m = lookup_minimal_symbol_by_pc (last_pc_address);
+ if (m && STREQN (SYMBOL_NAME (m), name, l))
+ /* last_pc_address was in this function */
+ valu = SYMBOL_VALUE (m);
+ else if (m && STREQN (SYMBOL_NAME (m+1), name, l))
+ /* last_pc_address was in last function */
+ valu = SYMBOL_VALUE (m+1);
+ else
+ /* Not found - use last_pc_address (for finish_block) */
+ valu = last_pc_address;
+ }
+
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+
+ if (block_address_function_relative)
+ /* For Solaris 2.0 compilers, the block addresses and
+ N_SLINE's are relative to the start of the
+ function. On normal systems, and when using gcc on
+ Solaris 2.0, these addresses are just absolute, or
+ relative to the N_SO, depending on
+ BLOCK_ADDRESS_ABSOLUTE. */
+ function_start_offset = valu;
+
+ within_function = 1;
+ if (context_stack_depth > 0)
+ {
+ new = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ complain (&lbrac_unmatched_complaint, symnum);
+
+ new = push_context (0, valu);
+ new->name = define_symbol (valu, name, desc, type, objfile);
+ break;
+
+ default:
+ define_symbol (valu, name, desc, type, objfile);
+ break;
+ }
+ }
+ break;
+
+ /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it
+ for a bunch of other flags, too. Someday we may parse their
+ flags; for now we ignore theirs and hope they'll ignore ours. */
+ case N_OPT: /* Solaris 2: Compiler options */
+ if (name)
+ {
+ if (STREQ (name, GCC2_COMPILED_FLAG_SYMBOL))
+ {
+ processing_gcc_compilation = 2;
+#if 1 /* Works, but is experimental. -fnf */
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+#endif
+ }
+ else
+ n_opt_found = 1;
+ }
+ break;
+
+ /* The following symbol types can be ignored. */
+ case N_OBJ: /* Solaris 2: Object file dir and name */
+ /* N_UNDF: Solaris 2: file separator mark */
+ /* N_UNDF: -- we will never encounter it, since we only process one
+ file's symbols at once. */
+ case N_ENDM: /* Solaris 2: End of module */
+ case N_MAIN: /* Name of main routine. */
+ break;
+ }
+
+ previous_stab_code = type;
+}
+
+/* FIXME: The only difference between this and elfstab_build_psymtabs is
+ the call to install_minimal_symbols for elf. If the differences are
+ really that small, the code should be shared. */
+
+/* Scan and build partial symbols for an coff symbol file.
+ The coff file has already been processed to get its minimal symbols.
+
+ This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
+ rolled into one.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g.
+ the base address of the text segment).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+ STABOFFSET and STABSIZE define the location in OBJFILE where the .stab
+ section exists.
+ STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the
+ .stabstr section exists.
+
+ This routine is mostly copied from dbx_symfile_init and dbx_symfile_read,
+ adjusted for coff details. */
+
+void
+coffstab_build_psymtabs (objfile, section_offsets, mainline,
+ staboffset, stabsize,
+ stabstroffset, stabstrsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr staboffset;
+ unsigned int stabsize;
+ file_ptr stabstroffset;
+ unsigned int stabstrsize;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ struct dbx_symfile_info *info;
+
+ /* There is already a dbx_symfile_info allocated by our caller.
+ It might even contain some info from the coff symtab to help us. */
+ info = (struct dbx_symfile_info *) objfile->sym_stab_info;
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+#define COFF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */
+ DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE;
+ DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = stabstrsize;
+ DBX_SYMTAB_OFFSET (objfile) = staboffset;
+
+ if (stabstrsize > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", stabstrsize);
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1);
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd);
+ if (val != stabstrsize)
+ perror_with_name (name);
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+
+ processing_acc_compilation = 1;
+
+ /* In a coff file, we've already installed the minimal symbols that came
+ from the coff (non-stab) symbol table, so always act like an
+ incremental load here. */
+ dbx_symfile_read (objfile, section_offsets, 0);
+}
+
+/* Scan and build partial symbols for an ELF symbol file.
+ This ELF file has already been processed to get its minimal symbols,
+ and any DWARF symbols that were in it.
+
+ This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
+ rolled into one.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g.
+ the base address of the text segment).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+ STABOFFSET and STABSIZE define the location in OBJFILE where the .stab
+ section exists.
+ STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the
+ .stabstr section exists.
+
+ This routine is mostly copied from dbx_symfile_init and dbx_symfile_read,
+ adjusted for elf details. */
+
+void
+elfstab_build_psymtabs (objfile, section_offsets, mainline,
+ staboffset, stabsize,
+ stabstroffset, stabstrsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr staboffset;
+ unsigned int stabsize;
+ file_ptr stabstroffset;
+ unsigned int stabstrsize;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ struct dbx_symfile_info *info;
+
+ /* There is already a dbx_symfile_info allocated by our caller.
+ It might even contain some info from the ELF symtab to help us. */
+ info = (struct dbx_symfile_info *) objfile->sym_stab_info;
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+#define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */
+ DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE;
+ DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = stabstrsize;
+ DBX_SYMTAB_OFFSET (objfile) = staboffset;
+
+ if (stabstrsize > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", stabstrsize);
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1);
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd);
+ if (val != stabstrsize)
+ perror_with_name (name);
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+ install_minimal_symbols (objfile);
+
+ processing_acc_compilation = 1;
+
+ /* In an elf file, we've already installed the minimal symbols that came
+ from the elf (non-stab) symbol table, so always act like an
+ incremental load here. */
+ dbx_symfile_read (objfile, section_offsets, 0);
+}
+
+/* Scan and build partial symbols for a PA symbol file.
+ This PA file has already been processed to get its minimal symbols.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g.
+ the base address of the text segment).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ */
+
+void
+pastab_build_psymtabs (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ free_header_files ();
+ init_header_files ();
+
+ /* In a PA file, we've already installed the minimal symbols that came
+ from the PA (non-stab) symbol table, so always act like an
+ incremental load here. */
+
+ dbx_symfile_read (objfile, section_offsets, mainline);
+}
+
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+ of how to represent it for fast symbol reading. */
+
+static struct section_offsets *
+dbx_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* Register our willingness to decode symbols for SunOS and a.out and
+ NetBSD and b.out files handled by BFD... */
+static struct sym_fns sunos_sym_fns =
+{
+ "sunOs", /* sym_name: name or name prefix of BFD target type */
+ 6, /* sym_namelen: number of significant sym_name chars */
+ dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ dbx_symfile_read, /* sym_read: read a symbol file into symtab */
+ dbx_symfile_finish, /* sym_finish: finished with file, cleanup */
+ dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+static struct sym_fns aout_sym_fns =
+{
+ "a.out", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ dbx_symfile_read, /* sym_read: read a symbol file into symtab */
+ dbx_symfile_finish, /* sym_finish: finished with file, cleanup */
+ dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+static struct sym_fns bout_sym_fns =
+{
+ "b.out", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ dbx_symfile_read, /* sym_read: read a symbol file into symtab */
+ dbx_symfile_finish, /* sym_finish: finished with file, cleanup */
+ dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_dbxread ()
+{
+ add_symtab_fns(&sunos_sym_fns);
+ add_symtab_fns(&aout_sym_fns);
+ add_symtab_fns(&bout_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/dcache.c b/gnu/usr.bin/gdb/gdb/dcache.c
new file mode 100644
index 000000000000..aaa01d0fe227
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dcache.c
@@ -0,0 +1,236 @@
+/* Caching code. Typically used by remote back ends for
+ caching remote memory.
+
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "dcache.h"
+#include "gdbcmd.h"
+
+extern int insque();
+extern int remque();
+
+int remote_dcache = 0;
+
+/* The data cache records all the data read from the remote machine
+ since the last time it stopped.
+
+ Each cache block holds LINE_SIZE bytes of data
+ starting at a multiple-of-LINE_SIZE address. */
+
+#define LINE_SIZE_MASK ((LINE_SIZE - 1)) /* eg 7*2+1= 111*/
+#define XFORM(x) (((x) & LINE_SIZE_MASK) >> 2)
+
+/* Free all the data cache blocks, thus discarding all cached data. */
+void
+dcache_flush (dcache)
+ DCACHE *dcache;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache > 0)
+ while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
+ {
+ remque (db);
+ insque (db, &dcache->dcache_free);
+ }
+
+ return;
+}
+
+/*
+ * If addr is present in the dcache, return the address of the block
+ * containing it.
+ */
+static
+struct dcache_block *
+dcache_hit (dcache, addr)
+ DCACHE *dcache;
+ unsigned int addr;
+{
+ register struct dcache_block *db;
+
+ if (addr & 3
+ || remote_dcache == 0)
+ abort ();
+
+ /* Search all cache blocks for one that is at this address. */
+ db = dcache->dcache_valid.next;
+ while (db != &dcache->dcache_valid)
+ {
+ if ((addr & ~LINE_SIZE_MASK) == db->addr)
+ return db;
+ db = db->next;
+ }
+
+ return NULL;
+}
+
+/* Return the int data at address ADDR in dcache block DC. */
+static
+int
+dcache_value (db, addr)
+ struct dcache_block *db;
+ unsigned int addr;
+{
+ if (addr & 3
+ || remote_dcache == 0)
+ abort ();
+ return (db->data[XFORM (addr)]);
+}
+
+/* Get a free cache block, put or keep it on the valid list,
+ and return its address. The caller should store into the block
+ the address and data that it describes, then remque it from the
+ free list and insert it into the valid list. This procedure
+ prevents errors from creeping in if a memory retrieval is
+ interrupted (which used to put garbage blocks in the valid
+ list...). */
+static
+struct dcache_block *
+dcache_alloc (dcache)
+ DCACHE *dcache;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ abort();
+
+ if ((db = dcache->dcache_free.next) == &dcache->dcache_free)
+ {
+ /* If we can't get one from the free list, take last valid and put
+ it on the free list. */
+ db = dcache->dcache_valid.last;
+ remque (db);
+ insque (db, &dcache->dcache_free);
+ }
+
+ remque (db);
+ insque (db, &dcache->dcache_valid);
+ return (db);
+}
+
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine. */
+int
+dcache_fetch (dcache, addr)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ {
+ int i;
+
+ (*dcache->read_memory) (addr, (unsigned char *) &i, 4);
+ return(i);
+ }
+
+ db = dcache_hit (dcache, addr);
+ if (db == 0)
+ {
+ db = dcache_alloc (dcache);
+ immediate_quit++;
+ (*dcache->read_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+ immediate_quit--;
+ db->addr = addr & ~LINE_SIZE_MASK;
+ remque (db); /* Off the free list */
+ insque (db, &dcache->dcache_valid); /* On the valid list */
+ }
+ return (dcache_value (db, addr));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+void
+dcache_poke (dcache, addr, data)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+ int data;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ {
+ (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
+ return;
+ }
+
+ /* First make sure the word is IN the cache. DB is its cache block. */
+ db = dcache_hit (dcache, addr);
+ if (db == 0)
+ {
+ db = dcache_alloc (dcache);
+ immediate_quit++;
+ (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+ immediate_quit--;
+ db->addr = addr & ~LINE_SIZE_MASK;
+ remque (db); /* Off the free list */
+ insque (db, &dcache->dcache_valid); /* On the valid list */
+ }
+
+ /* Modify the word in the cache. */
+ db->data[XFORM (addr)] = data;
+
+ /* Send the changed word. */
+ immediate_quit++;
+ (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
+ immediate_quit--;
+}
+
+/* Initialize the data cache. */
+DCACHE *
+dcache_init (reading, writing)
+ memxferfunc reading;
+ memxferfunc writing;
+{
+ register i;
+ register struct dcache_block *db;
+ DCACHE *dcache;
+
+ dcache = (DCACHE *) xmalloc (sizeof (*dcache));
+ dcache->read_memory = reading;
+ dcache->write_memory = writing;
+ dcache->the_cache = (struct dcache_block *)
+ xmalloc (sizeof (*dcache->the_cache) * DCACHE_SIZE);
+
+ dcache->dcache_free.next = dcache->dcache_free.last = &dcache->dcache_free;
+ dcache->dcache_valid.next = dcache->dcache_valid.last = &dcache->dcache_valid;
+ for (db = dcache->the_cache, i = 0; i < DCACHE_SIZE; i++, db++)
+ insque (db, &dcache->dcache_free);
+
+ return(dcache);
+}
+
+void
+_initialitize_dcache ()
+{
+ add_show_from_set
+ (add_set_cmd ("remotecache", class_support, var_boolean,
+ (char *) &remote_dcache,
+ "\
+Set cache use for remote targets.\n\
+When on, use data caching for remote targets. For many remote targets\n\
+this option can offer better throughput for reading target memory.\n\
+Unfortunately, gdb does not currently know anything about volatile\n\
+registers and thus data caching will produce incorrect results with\n\
+volatile registers are in use. By default, this option is off.",
+ &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/dcache.h b/gnu/usr.bin/gdb/gdb/dcache.h
new file mode 100644
index 000000000000..bfc0dd7a1e3c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dcache.h
@@ -0,0 +1,83 @@
+/* Declarations for caching. Typically used by remote back ends for
+ caching remote memory.
+
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef DCACHE_H
+#define DCACHE_H
+
+/* The data cache leads to incorrect results because it doesn't know about
+ volatile variables, thus making it impossible to debug functions which
+ use hardware registers. Therefore it is #if 0'd out. Effect on
+ performance is some, for backtraces of functions with a few
+ arguments each. For functions with many arguments, the stack
+ frames don't fit in the cache blocks, which makes the cache less
+ helpful. Disabling the cache is a big performance win for fetching
+ large structures, because the cache code fetched data in 16-byte
+ chunks. */
+
+#define LINE_SIZE_POWER (4)
+/* eg 1<<3 == 8 */
+#define LINE_SIZE (1 << LINE_SIZE_POWER)
+/* Number of cache blocks */
+#define DCACHE_SIZE (64)
+
+struct dcache_block
+{
+ struct dcache_block *next, *last;
+ unsigned int addr; /* Address for which data is recorded. */
+ int data[LINE_SIZE / sizeof (int)];
+};
+
+typedef int (*memxferfunc) PARAMS((CORE_ADDR memaddr,
+ unsigned char *myaddr,
+ int len));
+
+typedef struct {
+ /* Function to actually read the target memory. */
+ memxferfunc read_memory;
+
+ /* Function to actually write the target memory */
+ memxferfunc write_memory;
+
+ /* free list */
+ struct dcache_block dcache_free;
+
+ /* in use list */
+ struct dcache_block dcache_valid;
+
+ /* The cache itself. */
+ struct dcache_block *the_cache;
+
+} DCACHE;
+
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine. */
+int dcache_fetch PARAMS((DCACHE *dcache, CORE_ADDR addr));
+
+/* Flush DCACHE. */
+void dcache_flush PARAMS((DCACHE *dcache));
+
+/* Initialize DCACHE. */
+DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing));
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+void dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data));
+
+#endif /* DCACHE_H */
diff --git a/gnu/usr.bin/gdb/gdb/defs.h b/gnu/usr.bin/gdb/gdb/defs.h
new file mode 100644
index 000000000000..f65d56ac5878
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/defs.h
@@ -0,0 +1,901 @@
+/* Basic, host-specific, and target-specific definitions for GDB.
+ Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (DEFS_H)
+#define DEFS_H 1
+
+#include <stdio.h>
+
+/* First include ansidecl.h so we can use the various macro definitions
+ here and in all subsequent file inclusions. */
+
+#include "ansidecl.h"
+
+/* An address in the program being debugged. Host byte order. */
+#ifndef CORE_ADDR_TYPE
+typedef unsigned int CORE_ADDR;
+#else
+typedef CORE_ADDR_TYPE CORE_ADDR;
+#endif
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/* Gdb does *lots* of string compares. Use macros to speed them up by
+ avoiding function calls if the first characters are not the same. */
+
+#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b))
+#define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0)
+#define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0)
+
+/* The character GNU C++ uses to build identifiers that must be unique from
+ the program's identifiers (such as $this and $$vptr). */
+#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */
+
+#include <errno.h> /* System call error return status */
+
+extern int quit_flag;
+extern int immediate_quit;
+extern int sevenbit_strings;
+
+extern void
+quit PARAMS ((void));
+
+#define QUIT { if (quit_flag) quit (); }
+
+/* Command classes are top-level categories into which commands are broken
+ down for "help" purposes.
+ Notes on classes: class_alias is for alias commands which are not
+ abbreviations of the original command. class-pseudo is for commands
+ which are not really commands nor help topics ("stop"). */
+
+enum command_class
+{
+ /* Special args to help_list */
+ all_classes = -2, all_commands = -1,
+ /* Classes of commands */
+ no_class = -1, class_run = 0, class_vars, class_stack,
+ class_files, class_support, class_info, class_breakpoint,
+ class_alias, class_obscure, class_user, class_maintenance,
+ class_pseudo
+};
+
+/* Languages represented in the symbol table and elsewhere.
+ This should probably be in language.h, but since enum's can't
+ be forward declared to satisfy opaque references before their
+ actual definition, needs to be here. */
+
+enum language
+{
+ language_unknown, /* Language not known */
+ language_auto, /* Placeholder for automatic setting */
+ language_c, /* C */
+ language_cplus, /* C++ */
+ language_chill, /* Chill */
+ language_m2 /* Modula-2 */
+};
+
+/* the cleanup list records things that have to be undone
+ if an error happens (descriptors to be closed, memory to be freed, etc.)
+ Each link in the chain records a function to call and an
+ argument to give it.
+
+ Use make_cleanup to add an element to the cleanup chain.
+ Use do_cleanups to do all cleanup actions back to a given
+ point in the chain. Use discard_cleanups to remove cleanups
+ from the chain back to a given point, not doing them. */
+
+struct cleanup
+{
+ struct cleanup *next;
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+};
+
+/* From blockframe.c */
+
+extern int
+inside_entry_func PARAMS ((CORE_ADDR));
+
+extern int
+inside_entry_file PARAMS ((CORE_ADDR addr));
+
+extern int
+inside_main_func PARAMS ((CORE_ADDR pc));
+
+/* From ch-lang.c, for the moment. (FIXME) */
+
+extern char *
+chill_demangle PARAMS ((const char *));
+
+/* From libiberty.a */
+
+extern char *
+cplus_demangle PARAMS ((const char *, int));
+
+extern char *
+cplus_mangle_opname PARAMS ((char *, int));
+
+/* From libmmalloc.a (memory mapped malloc library) */
+
+extern PTR
+mmalloc_attach PARAMS ((int, PTR));
+
+extern PTR
+mmalloc_detach PARAMS ((PTR));
+
+extern PTR
+mmalloc PARAMS ((PTR, long));
+
+extern PTR
+mrealloc PARAMS ((PTR, PTR, long));
+
+extern void
+mfree PARAMS ((PTR, PTR));
+
+extern int
+mmalloc_setkey PARAMS ((PTR, int, PTR));
+
+extern PTR
+mmalloc_getkey PARAMS ((PTR, int));
+
+/* From utils.c */
+
+extern int
+strcmp_iw PARAMS ((const char *, const char *));
+
+extern char *
+safe_strerror PARAMS ((int));
+
+extern char *
+safe_strsignal PARAMS ((int));
+
+extern void
+init_malloc PARAMS ((void *));
+
+extern void
+request_quit PARAMS ((int));
+
+extern void
+do_cleanups PARAMS ((struct cleanup *));
+
+extern void
+discard_cleanups PARAMS ((struct cleanup *));
+
+/* The bare make_cleanup function is one of those rare beasts that
+ takes almost any type of function as the first arg and anything that
+ will fit in a "void *" as the second arg.
+
+ Should be, once all calls and called-functions are cleaned up:
+extern struct cleanup *
+make_cleanup PARAMS ((void (*function) (void *), void *));
+
+ Until then, lint and/or various type-checking compiler options will
+ complain about make_cleanup calls. It'd be wrong to just cast things,
+ since the type actually passed when the function is called would be
+ wrong. */
+
+extern struct cleanup *
+make_cleanup ();
+
+extern struct cleanup *
+save_cleanups PARAMS ((void));
+
+extern void
+restore_cleanups PARAMS ((struct cleanup *));
+
+extern void
+free_current_contents PARAMS ((char **));
+
+extern void
+null_cleanup PARAMS ((char **));
+
+extern int
+myread PARAMS ((int, char *, int));
+
+extern int
+query ();
+
+extern void
+begin_line PARAMS ((void));
+
+extern void
+wrap_here PARAMS ((char *));
+
+extern void
+reinitialize_more_filter PARAMS ((void));
+
+extern int
+print_insn PARAMS ((CORE_ADDR, FILE *));
+
+extern void
+fputs_filtered PARAMS ((const char *, FILE *));
+
+extern void
+puts_filtered PARAMS ((char *));
+
+extern void
+vprintf_filtered ();
+
+extern void
+vfprintf_filtered ();
+
+extern void
+fprintf_filtered ();
+
+extern void
+fprintfi_filtered ();
+
+extern void
+printf_filtered ();
+
+extern void
+printfi_filtered ();
+
+extern void
+print_spaces PARAMS ((int, FILE *));
+
+extern void
+print_spaces_filtered PARAMS ((int, FILE *));
+
+extern char *
+n_spaces PARAMS ((int));
+
+extern void
+gdb_printchar PARAMS ((int, FILE *, int));
+
+extern void
+fprintf_symbol_filtered PARAMS ((FILE *, char *, enum language, int));
+
+extern void
+perror_with_name PARAMS ((char *));
+
+extern void
+print_sys_errmsg PARAMS ((char *, int));
+
+/* From regex.c or libc. BSD 4.4 declares this with the argument type as
+ "const char *" in unistd.h, so we can't declare the argument
+ as "char *". */
+
+extern char *
+re_comp PARAMS ((const char *));
+
+/* From symfile.c */
+
+extern void
+symbol_file_command PARAMS ((char *, int));
+
+/* From main.c */
+
+extern char *
+skip_quoted PARAMS ((char *));
+
+extern char *
+gdb_readline PARAMS ((char *));
+
+extern char *
+command_line_input PARAMS ((char *, int));
+
+extern void
+print_prompt PARAMS ((void));
+
+extern int
+batch_mode PARAMS ((void));
+
+extern int
+input_from_terminal_p PARAMS ((void));
+
+/* From printcmd.c */
+
+extern void
+set_next_address PARAMS ((CORE_ADDR));
+
+extern void
+print_address_symbolic PARAMS ((CORE_ADDR, FILE *, int, char *));
+
+extern void
+print_address PARAMS ((CORE_ADDR, FILE *));
+
+/* From source.c */
+
+extern int
+openp PARAMS ((char *, int, char *, int, int, char **));
+
+extern void
+mod_path PARAMS ((char *, char **));
+
+extern void
+directory_command PARAMS ((char *, int));
+
+extern void
+init_source_path PARAMS ((void));
+
+/* From findvar.c */
+
+extern int
+read_relative_register_raw_bytes PARAMS ((int, char *));
+
+/* From readline (but not in any readline .h files). */
+
+extern char *
+tilde_expand PARAMS ((char *));
+
+/* Structure for saved commands lines
+ (for breakpoints, defined commands, etc). */
+
+struct command_line
+{
+ struct command_line *next;
+ char *line;
+};
+
+extern struct command_line *
+read_command_lines PARAMS ((void));
+
+extern void
+free_command_lines PARAMS ((struct command_line **));
+
+/* String containing the current directory (what getwd would return). */
+
+extern char *current_directory;
+
+/* Default radixes for input and output. Only some values supported. */
+extern unsigned input_radix;
+extern unsigned output_radix;
+
+/* Possibilities for prettyprint parameters to routines which print
+ things. Like enum language, this should be in value.h, but needs
+ to be here for the same reason. FIXME: If we can eliminate this
+ as an arg to LA_VAL_PRINT, then we can probably move it back to
+ value.h. */
+
+enum val_prettyprint
+{
+ Val_no_prettyprint = 0,
+ Val_prettyprint,
+ /* Use the default setting which the user has specified. */
+ Val_pretty_default
+};
+
+
+/* Host machine definition. This will be a symlink to one of the
+ xm-*.h files, built by the `configure' script. */
+
+#include "xm.h"
+
+/* Native machine support. This will be a symlink to one of the
+ nm-*.h files, built by the `configure' script. */
+
+#include "nm.h"
+
+/* If the xm.h file did not define the mode string used to open the
+ files, assume that binary files are opened the same way as text
+ files */
+#ifndef FOPEN_RB
+#include "fopen-same.h"
+#endif
+
+/*
+ * Allow things in gdb to be declared "const". If compiling ANSI, it
+ * just works. If compiling with gcc but non-ansi, redefine to __const__.
+ * If non-ansi, non-gcc, then eliminate "const" entirely, making those
+ * objects be read-write rather than read-only.
+ */
+
+#ifndef const
+#ifndef __STDC__
+# ifdef __GNUC__
+# define const __const__
+# else
+# define const /*nothing*/
+# endif /* GNUC */
+#endif /* STDC */
+#endif /* const */
+
+#ifndef volatile
+#ifndef __STDC__
+# ifdef __GNUC__
+# define volatile __volatile__
+# else
+# define volatile /*nothing*/
+# endif /* GNUC */
+#endif /* STDC */
+#endif /* volatile */
+
+#if 1
+#define NORETURN /*nothing*/
+#else /* not 1 */
+/* FIXME: This is bogus. Having "volatile void" mean a function doesn't
+ return is a gcc extension and should be based on #ifdef __GNUC__.
+ Also, as of Sep 93 I'm told gcc is changing the syntax for ansi
+ reasons (so declaring exit here as "volatile void" and as "void" in
+ a system header loses). Using the new "__attributes__ ((noreturn));"
+ syntax would lose for old versions of gcc; using
+ typedef void exit_fn_type PARAMS ((int));
+ volatile exit_fn_type exit;
+ would win. */
+/* Some compilers (many AT&T SVR4 compilers for instance), do not accept
+ declarations of functions that never return (exit for instance) as
+ "volatile void". For such compilers "NORETURN" can be defined away
+ to keep them happy */
+
+#ifndef NORETURN
+# ifdef __lucid
+# define NORETURN /*nothing*/
+# else
+# define NORETURN volatile
+# endif
+#endif
+#endif /* not 1 */
+
+/* Defaults for system-wide constants (if not defined by xm.h, we fake it). */
+
+#if !defined (UINT_MAX)
+#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (INT_MAX)
+#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */
+#endif
+
+#if !defined (INT_MIN)
+#define INT_MIN (-INT_MAX - 1) /* 0x80000000 for 32-bits */
+#endif
+
+#if !defined (ULONG_MAX)
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (LONG_MAX)
+#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */
+#endif
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* Number of bits in a short or unsigned short for the target machine. */
+#if !defined (TARGET_SHORT_BIT)
+#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in an int or unsigned int for the target machine. */
+#if !defined (TARGET_INT_BIT)
+#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long or unsigned long for the target machine. */
+#if !defined (TARGET_LONG_BIT)
+#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long long or unsigned long long for the target machine. */
+#if !defined (TARGET_LONG_LONG_BIT)
+#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT)
+#endif
+
+/* Number of bits in a float for the target machine. */
+#if !defined (TARGET_FLOAT_BIT)
+#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a double for the target machine. */
+#if !defined (TARGET_DOUBLE_BIT)
+#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long double for the target machine. */
+#if !defined (TARGET_LONG_DOUBLE_BIT)
+#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT)
+#endif
+
+/* Number of bits in a "complex" for the target machine. */
+#if !defined (TARGET_COMPLEX_BIT)
+#define TARGET_COMPLEX_BIT (2 * TARGET_FLOAT_BIT)
+#endif
+
+/* Number of bits in a "double complex" for the target machine. */
+#if !defined (TARGET_DOUBLE_COMPLEX_BIT)
+#define TARGET_DOUBLE_COMPLEX_BIT (2 * TARGET_DOUBLE_BIT)
+#endif
+
+/* Number of bits in a pointer for the target machine */
+#if !defined (TARGET_PTR_BIT)
+#define TARGET_PTR_BIT TARGET_INT_BIT
+#endif
+
+/* Default to support for "long long" if the host compiler being used is gcc.
+ Config files must define CC_HAS_LONG_LONG to use other host compilers
+ that are capable of supporting "long long", and to cause gdb to use that
+ support. Not defining CC_HAS_LONG_LONG will suppress use of "long long"
+ regardless of what compiler is used.
+
+ FIXME: For now, automatic selection of "long long" as the default when
+ gcc is used is disabled, pending further testing. Concerns include the
+ impact on gdb performance and the universality of bugfree long long
+ support on platforms that do have gcc. Compiling with FORCE_LONG_LONG
+ will select "long long" use for testing purposes. -fnf */
+
+#ifndef CC_HAS_LONG_LONG
+# if defined (__GNUC__) && defined (FORCE_LONG_LONG) /* See FIXME above */
+# define CC_HAS_LONG_LONG 1
+# endif
+#endif
+
+/* LONGEST should not be a typedef, because "unsigned LONGEST" needs to work.
+ CC_HAS_LONG_LONG is defined if the host compiler supports "long long"
+ variables and we wish to make use of that support. */
+
+#ifndef LONGEST
+# ifdef CC_HAS_LONG_LONG
+# define LONGEST long long
+# else
+# define LONGEST long
+# endif
+#endif
+
+/* Convert a LONGEST to an int. This is used in contexts (e.g. number of
+ arguments to a function, number in a value history, register number, etc.)
+ where the value must not be larger than can fit in an int. */
+
+#ifndef longest_to_int
+# ifdef CC_HAS_LONG_LONG
+# define longest_to_int(x) (((x) > INT_MAX || (x) < INT_MIN) \
+ ? (error ("Value out of range."),0) : (int) (x))
+# else
+ /* Assume sizeof (int) == sizeof (long). */
+# define longest_to_int(x) ((int) (x))
+# endif
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
+/* Assorted functions we can declare, now that const and volatile are
+ defined. */
+
+extern char *
+savestring PARAMS ((const char *, int));
+
+extern char *
+msavestring PARAMS ((void *, const char *, int));
+
+extern char *
+strsave PARAMS ((const char *));
+
+extern char *
+mstrsave PARAMS ((void *, const char *));
+
+extern char *
+concat PARAMS ((char *, ...));
+
+extern PTR
+xmalloc PARAMS ((long));
+
+extern PTR
+xrealloc PARAMS ((PTR, long));
+
+extern PTR
+xmmalloc PARAMS ((PTR, long));
+
+extern PTR
+xmrealloc PARAMS ((PTR, PTR, long));
+
+extern PTR
+mmalloc PARAMS ((PTR, long));
+
+extern PTR
+mrealloc PARAMS ((PTR, PTR, long));
+
+extern void
+mfree PARAMS ((PTR, PTR));
+
+extern int
+mmcheck PARAMS ((PTR, void (*) (void)));
+
+extern int
+mmtrace PARAMS ((void));
+
+extern int
+parse_escape PARAMS ((char **));
+
+extern const char * const reg_names[];
+
+extern NORETURN void /* Does not return to the caller. */
+error ();
+
+extern NORETURN void /* Does not return to the caller. */
+fatal ();
+
+extern NORETURN void /* Not specified as volatile in ... */
+exit PARAMS ((int)); /* 4.10.4.3 */
+
+extern NORETURN void /* Does not return to the caller. */
+nomem PARAMS ((long));
+
+/* Reasons for calling return_to_top_level. */
+enum return_reason {
+ /* User interrupt. */
+ RETURN_QUIT,
+
+ /* Any other error. */
+ RETURN_ERROR
+};
+
+#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT)
+#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR)
+#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
+typedef int return_mask;
+
+extern NORETURN void /* Does not return to the caller. */
+return_to_top_level PARAMS ((enum return_reason));
+
+extern int catch_errors PARAMS ((int (*) (char *), void *, char *,
+ return_mask));
+
+extern void
+warning_setup PARAMS ((void));
+
+extern void
+warning ();
+
+/* Global functions from other, non-gdb GNU thingies (libiberty for
+ instance) */
+
+extern char *
+basename PARAMS ((char *));
+
+extern char *
+getenv PARAMS ((const char *));
+
+extern char **
+buildargv PARAMS ((char *));
+
+extern void
+freeargv PARAMS ((char **));
+
+extern char *
+strerrno PARAMS ((int));
+
+extern char *
+strsigno PARAMS ((int));
+
+extern int
+errno_max PARAMS ((void));
+
+extern int
+signo_max PARAMS ((void));
+
+extern int
+strtoerrno PARAMS ((char *));
+
+extern int
+strtosigno PARAMS ((char *));
+
+extern char *
+strsignal PARAMS ((int));
+
+/* From other system libraries */
+
+#ifndef PSIGNAL_IN_SIGNAL_H
+extern void
+psignal PARAMS ((unsigned, const char *));
+#endif
+
+/* For now, we can't include <stdlib.h> because it conflicts with
+ "../include/getopt.h". (FIXME)
+
+ However, if a function is defined in the ANSI C standard and a prototype
+ for that function is defined and visible in any header file in an ANSI
+ conforming environment, then that prototype must match the definition in
+ the ANSI standard. So we can just duplicate them here without conflict,
+ since they must be the same in all conforming ANSI environments. If
+ these cause problems, then the environment is not ANSI conformant. */
+
+#ifdef __STDC__
+#include <stddef.h>
+#endif
+
+extern int
+fclose PARAMS ((FILE *stream)); /* 4.9.5.1 */
+
+extern void
+perror PARAMS ((const char *)); /* 4.9.10.4 */
+
+extern double
+atof PARAMS ((const char *nptr)); /* 4.10.1.1 */
+
+extern int
+atoi PARAMS ((const char *)); /* 4.10.1.2 */
+
+#ifndef MALLOC_INCOMPATIBLE
+
+extern PTR
+malloc PARAMS ((size_t size)); /* 4.10.3.3 */
+
+extern PTR
+realloc PARAMS ((void *ptr, size_t size)); /* 4.10.3.4 */
+
+extern void
+free PARAMS ((void *)); /* 4.10.3.2 */
+
+#endif /* MALLOC_INCOMPATIBLE */
+
+extern void
+qsort PARAMS ((void *base, size_t nmemb, /* 4.10.5.2 */
+ size_t size,
+ int (*comp)(const void *, const void *)));
+
+#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */
+extern PTR
+memcpy PARAMS ((void *, const void *, size_t)); /* 4.11.2.1 */
+
+extern int
+memcmp PARAMS ((const void *, const void *, size_t)); /* 4.11.4.1 */
+#endif
+
+extern char *
+strchr PARAMS ((const char *, int)); /* 4.11.5.2 */
+
+extern char *
+strrchr PARAMS ((const char *, int)); /* 4.11.5.5 */
+
+extern char *
+strstr PARAMS ((const char *, const char *)); /* 4.11.5.7 */
+
+extern char *
+strtok PARAMS ((char *, const char *)); /* 4.11.5.8 */
+
+#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */
+extern PTR
+memset PARAMS ((void *, int, size_t)); /* 4.11.6.1 */
+#endif
+
+extern char *
+strerror PARAMS ((int)); /* 4.11.6.2 */
+
+/* Various possibilities for alloca. */
+#ifndef alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# else
+# ifdef sparc
+# include <alloca.h> /* NOTE: Doesn't declare alloca() */
+# endif
+# ifdef __STDC__
+ extern void *alloca (size_t);
+# else /* __STDC__ */
+ extern char *alloca ();
+# endif
+# endif
+#endif
+
+/* TARGET_BYTE_ORDER and HOST_BYTE_ORDER must be defined to one of these. */
+
+#if !defined (BIG_ENDIAN)
+#define BIG_ENDIAN 4321
+#endif
+
+#if !defined (LITTLE_ENDIAN)
+#define LITTLE_ENDIAN 1234
+#endif
+
+/* Target-system-dependent parameters for GDB. */
+
+/* Target machine definition. This will be a symlink to one of the
+ tm-*.h files, built by the `configure' script. */
+
+#include "tm.h"
+
+/* The bit byte-order has to do just with numbering of bits in
+ debugging symbols and such. Conceptually, it's quite separate
+ from byte/word byte order. */
+
+#if !defined (BITS_BIG_ENDIAN)
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+#define BITS_BIG_ENDIAN 1
+#endif /* Big endian. */
+
+#if TARGET_BYTE_ORDER == LITTLE_ENDIAN
+#define BITS_BIG_ENDIAN 0
+#endif /* Little endian. */
+#endif /* BITS_BIG_ENDIAN not defined. */
+
+/* Swap LEN bytes at BUFFER between target and host byte-order. This is
+ the wrong way to do byte-swapping because it assumes that you have a way
+ to have a host variable of exactly the right size.
+ extract_* are the right way. */
+#if TARGET_BYTE_ORDER == HOST_BYTE_ORDER
+#define SWAP_TARGET_AND_HOST(buffer,len)
+#else /* Target and host byte order differ. */
+#define SWAP_TARGET_AND_HOST(buffer,len) \
+ { \
+ char tmp; \
+ char *p = (char *)(buffer); \
+ char *q = ((char *)(buffer)) + len - 1; \
+ for (; p < q; p++, q--) \
+ { \
+ tmp = *q; \
+ *q = *p; \
+ *p = tmp; \
+ } \
+ }
+#endif /* Target and host byte order differ. */
+
+/* In findvar.c. */
+LONGEST extract_signed_integer PARAMS ((void *, int));
+unsigned LONGEST extract_unsigned_integer PARAMS ((void *, int));
+CORE_ADDR extract_address PARAMS ((void *, int));
+
+void store_signed_integer PARAMS ((void *, int, LONGEST));
+void store_unsigned_integer PARAMS ((void *, int, unsigned LONGEST));
+void store_address PARAMS ((void *, int, CORE_ADDR));
+
+/* On some machines there are bits in addresses which are not really
+ part of the address, but are used by the kernel, the hardware, etc.
+ for special purposes. ADDR_BITS_REMOVE takes out any such bits
+ so we get a "real" address such as one would find in a symbol
+ table. This is used only for addresses of instructions, and even then
+ I'm not sure it's used in all contexts. It exists to deal with there
+ being a few stray bits in the PC which would mislead us, not as some sort
+ of generic thing to handle alignment or segmentation (it's possible it
+ should be in TARGET_READ_PC instead). */
+#if !defined (ADDR_BITS_REMOVE)
+#define ADDR_BITS_REMOVE(addr) (addr)
+#endif /* No ADDR_BITS_REMOVE. */
+
+/* From valops.c */
+
+extern CORE_ADDR
+push_bytes PARAMS ((CORE_ADDR, char *, int));
+
+/* In some modules, we don't have a definition of REGISTER_TYPE yet, so we
+ must avoid prototyping this function for now. FIXME. Should be:
+extern CORE_ADDR
+push_word PARAMS ((CORE_ADDR, REGISTER_TYPE));
+ */
+extern CORE_ADDR
+push_word ();
+
+/* Some parts of gdb might be considered optional, in the sense that they
+ are not essential for being able to build a working, usable debugger
+ for a specific environment. For example, the maintenance commands
+ are there for the benefit of gdb maintainers. As another example,
+ some environments really don't need gdb's that are able to read N
+ different object file formats. In order to make it possible (but
+ not necessarily recommended) to build "stripped down" versions of
+ gdb, the following defines control selective compilation of those
+ parts of gdb which can be safely left out when necessary. Note that
+ the default is to include everything. */
+
+#ifndef MAINTENANCE_CMDS
+#define MAINTENANCE_CMDS 1
+#endif
+
+#endif /* !defined (DEFS_H) */
diff --git a/gnu/usr.bin/gdb/gdb/demangle.c b/gnu/usr.bin/gdb/gdb/demangle.c
new file mode 100644
index 000000000000..a134bb70ad98
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.c
@@ -0,0 +1,190 @@
+/* Basic C++ demangling support for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file contains support code for C++ demangling that is common
+ to a styles of demangling, and GDB specific. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "demangle.h"
+#include <string.h>
+
+/* Select the default C++ demangling style to use. The default is "auto",
+ which allows gdb to attempt to pick an appropriate demangling style for
+ the executable it has loaded. It can be set to a specific style ("gnu",
+ "lucid", "arm", etc.) in which case gdb will never attempt to do auto
+ selection of the style unless you do an explicit "set demangle auto".
+ To select one of these as the default, set DEFAULT_DEMANGLING_STYLE in
+ the appropriate target configuration file. */
+
+#ifndef DEFAULT_DEMANGLING_STYLE
+# define DEFAULT_DEMANGLING_STYLE AUTO_DEMANGLING_STYLE_STRING
+#endif
+
+/* String name for the current demangling style. Set by the "set demangling"
+ command, printed as part of the output by the "show demangling" command. */
+
+static char *current_demangling_style_string;
+
+/* List of supported demangling styles. Contains the name of the style as
+ seen by the user, and the enum value that corresponds to that style. */
+
+static const struct demangler
+{
+ char *demangling_style_name;
+ enum demangling_styles demangling_style;
+ char *demangling_style_doc;
+} demanglers [] =
+{
+ {AUTO_DEMANGLING_STYLE_STRING,
+ auto_demangling,
+ "Automatic selection based on executable"},
+ {GNU_DEMANGLING_STYLE_STRING,
+ gnu_demangling,
+ "GNU (g++) style demangling"},
+ {LUCID_DEMANGLING_STYLE_STRING,
+ lucid_demangling,
+ "Lucid (lcc) style demangling"},
+ {ARM_DEMANGLING_STYLE_STRING,
+ arm_demangling,
+ "ARM style demangling"},
+ {NULL, unknown_demangling, NULL}
+};
+
+/* show current demangling style. */
+
+static void
+show_demangling_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ /* done automatically by show command. */
+}
+
+
+/* set current demangling style. called by the "set demangling" command
+ after it has updated the current_demangling_style_string to match
+ what the user has entered.
+
+ if the user has entered a string that matches a known demangling style
+ name in the demanglers[] array then just leave the string alone and update
+ the current_demangling_style enum value to match.
+
+ if the user has entered a string that doesn't match, including an empty
+ string, then print a list of the currently known styles and restore
+ the current_demangling_style_string to match the current_demangling_style
+ enum value.
+
+ Note: Assumes that current_demangling_style_string always points to
+ a malloc'd string, even if it is a null-string. */
+
+static void
+set_demangling_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ const struct demangler *dem;
+
+ /* First just try to match whatever style name the user supplied with
+ one of the known ones. Don't bother special casing for an empty
+ name, we just treat it as any other style name that doesn't match.
+ If we match, update the current demangling style enum. */
+
+ for (dem = demanglers; dem -> demangling_style_name != NULL; dem++)
+ {
+ if (STREQ (current_demangling_style_string,
+ dem -> demangling_style_name))
+ {
+ current_demangling_style = dem -> demangling_style;
+ break;
+ }
+ }
+
+ /* Check to see if we found a match. If not, gripe about any non-empty
+ style name and supply a list of valid ones. FIXME: This should
+ probably be done with some sort of completion and with help. */
+
+ if (dem -> demangling_style_name == NULL)
+ {
+ if (*current_demangling_style_string != '\0')
+ {
+ printf ("Unknown demangling style `%s'.\n",
+ current_demangling_style_string);
+ }
+ printf ("The currently understood settings are:\n\n");
+ for (dem = demanglers; dem -> demangling_style_name != NULL; dem++)
+ {
+ printf ("%-10s %s\n", dem -> demangling_style_name,
+ dem -> demangling_style_doc);
+ if (dem -> demangling_style == current_demangling_style)
+ {
+ free (current_demangling_style_string);
+ current_demangling_style_string =
+ strdup (dem -> demangling_style_name);
+ }
+ }
+ if (current_demangling_style == unknown_demangling)
+ {
+ /* This can happen during initialization if gdb is compiled with
+ a DEMANGLING_STYLE value that is unknown, so pick the first
+ one as the default. */
+ current_demangling_style = demanglers[0].demangling_style;
+ current_demangling_style_string =
+ strdup (demanglers[0].demangling_style_name);
+ warning ("`%s' style demangling chosen as the default.\n",
+ current_demangling_style_string);
+ }
+ }
+}
+
+/* Fake a "set demangling" command. */
+
+void
+set_demangling_style (style)
+ char *style;
+{
+ if (current_demangling_style_string != NULL)
+ {
+ free (current_demangling_style_string);
+ }
+ current_demangling_style_string = strdup (style);
+ set_demangling_command ((char *) NULL, 0);
+}
+
+void
+_initialize_demangler ()
+{
+ struct cmd_list_element *set, *show;
+
+ set = add_set_cmd ("demangle-style", class_support, var_string_noescape,
+ (char *) &current_demangling_style_string,
+ "Set the current C++ demangling style.\n\
+Use `set demangle-style' without arguments for a list of demangling styles.",
+ &setlist);
+ show = add_show_from_set (set, &showlist);
+ set -> function.cfunc = set_demangling_command;
+ show -> function.cfunc = show_demangling_command;
+
+ /* Set the default demangling style chosen at compilation time. */
+ set_demangling_style (DEFAULT_DEMANGLING_STYLE);
+ set_cplus_marker_for_demangling (CPLUS_MARKER);
+}
diff --git a/gnu/usr.bin/gdb/gdb/demangle.h b/gnu/usr.bin/gdb/gdb/demangle.h
new file mode 100644
index 000000000000..4f191a2e1ade
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.h
@@ -0,0 +1,77 @@
+/* Defs for interface to demanglers.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#include <ansidecl.h>
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM)
+
+extern char *
+cplus_demangle PARAMS ((CONST char *mangled, int options));
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling PARAMS ((int ch));
+
+#endif /* DEMANGLE_H */
diff --git a/gnu/usr.bin/gdb/gdb/dis-asm.h b/gnu/usr.bin/gdb/gdb/dis-asm.h
new file mode 100644
index 000000000000..e7f106c318cb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-asm.h
@@ -0,0 +1,176 @@
+/* Interface between the opcode library and its callers.
+ Written by Cygnus Support, 1993.
+
+ The opcode library (libopcodes.a) provides instruction decoders for
+ a large variety of instruction sets, callable with an identical
+ interface, for making instruction-processing programs more independent
+ of the instruction set being processed. */
+
+#include <stdio.h>
+#include "bfd.h"
+
+typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
+
+enum dis_insn_type {
+ dis_noninsn, /* Not a valid instruction */
+ dis_nonbranch, /* Not a branch instruction */
+ dis_branch, /* Unconditional branch */
+ dis_condbranch, /* Conditional branch */
+ dis_jsr, /* Jump to subroutine */
+ dis_condjsr, /* Conditional jump to subroutine */
+ dis_dref, /* Data reference instruction */
+ dis_dref2, /* Two data references in instruction */
+};
+
+/* This struct is passed into the instruction decoding routine,
+ and is passed back out into each callback. The various fields are used
+ for conveying information from your main routine into your callbacks,
+ for passing information into the instruction decoders (such as the
+ addresses of the callback functions), or for passing information
+ back from the instruction decoders to their callers.
+
+ It must be initialized before it is first passed; this can be done
+ by hand, or using one of the initialization macros below. */
+
+typedef struct disassemble_info {
+ fprintf_ftype fprintf_func;
+ FILE *stream;
+ PTR application_data;
+
+ /* For use by the disassembler. */
+ int flags;
+ PTR private_data;
+
+ /* Function used to get bytes to disassemble. MEMADDR is the
+ address of the stuff to be disassembled, MYADDR is the address to
+ put the bytes in, and LENGTH is the number of bytes to read.
+ INFO is a pointer to this struct.
+ Returns an errno value or 0 for success. */
+ int (*read_memory_func)
+ PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
+ struct disassemble_info *info));
+
+ /* Function which should be called if we get an error that we can't
+ recover from. STATUS is the errno value from read_memory_func and
+ MEMADDR is the address that we were trying to read. INFO is a
+ pointer to this struct. */
+ void (*memory_error_func)
+ PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
+
+ /* Function called to print ADDR. */
+ void (*print_address_func)
+ PARAMS ((bfd_vma addr, struct disassemble_info *info));
+
+ /* These are for buffer_read_memory. */
+ bfd_byte *buffer;
+ bfd_vma buffer_vma;
+ int buffer_length;
+
+ /* Results from instruction decoders. Not all decoders yet support
+ this information. This info is set each time an instruction is
+ decoded, and is only valid for the last such instruction.
+
+ To determine whether this decoder supports this information, set
+ insn_info_valid to 0, decode an instruction, then check it. */
+
+ char insn_info_valid; /* Branch info has been set. */
+ char branch_delay_insns; /* How many sequential insn's will run before
+ a branch takes effect. (0 = normal) */
+ char data_size; /* Size of data reference in insn, in bytes */
+ enum dis_insn_type insn_type; /* Type of instruction */
+ bfd_vma target; /* Target address of branch or dref, if known;
+ zero if unknown. */
+ bfd_vma target2; /* Second target address for dref2 */
+
+} disassemble_info;
+
+
+
+
+
+
+/* Standard disassemblers. Disassemble one instruction at the given
+ target address. Return number of bytes processed. */
+typedef int (*disassembler_ftype)
+ PARAMS((bfd_vma, disassemble_info *));
+
+extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
+
+
+
+
+
+
+/* This block of definitions is for particular callers who read instructions
+ into a buffer before calling the instruction decoder. */
+
+/* Here is a function which callers may wish to use for read_memory_func.
+ It gets bytes from a buffer. */
+extern int buffer_read_memory
+ PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
+
+/* This function goes with buffer_read_memory.
+ It prints a message using info->fprintf_func and info->stream. */
+extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
+
+
+/* Just print the address is hex. This is included for completeness even
+ though both GDB and objdump provide their own (to print symbolic
+ addresses). */
+extern void generic_print_address
+ PARAMS ((bfd_vma, struct disassemble_info *));
+
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \
+ (INFO).fprintf_func = (fprintf_ftype)fprintf, \
+ (INFO).stream = (STREAM), \
+ (INFO).buffer = NULL, \
+ (INFO).buffer_vma = 0, \
+ (INFO).buffer_length = 0, \
+ (INFO).read_memory_func = buffer_read_memory, \
+ (INFO).memory_error_func = perror_memory, \
+ (INFO).print_address_func = generic_print_address, \
+ (INFO).insn_info_valid = 0
+
+
+
+
+/* This block of definitions is for calling the instruction decoders
+ from GDB. */
+
+/* GDB--Like target_read_memory, but slightly different parameters. */
+extern int
+dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int len,
+ disassemble_info *info));
+
+/* GDB--Like memory_error with slightly different parameters. */
+extern void
+dis_asm_memory_error
+ PARAMS ((int status, bfd_vma memaddr, disassemble_info *info));
+
+/* GDB--Like print_address with slightly different parameters. */
+extern void
+dis_asm_print_address PARAMS ((bfd_vma addr, disassemble_info *info));
+
+#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \
+ (INFO).fprintf_func = (fprintf_ftype)fprintf_filtered, \
+ (INFO).stream = (STREAM), \
+ (INFO).read_memory_func = dis_asm_read_memory, \
+ (INFO).memory_error_func = dis_asm_memory_error, \
+ (INFO).print_address_func = dis_asm_print_address, \
+ (INFO).insn_info_valid = 0
diff --git a/gnu/usr.bin/gdb/gdb/dis-buf.c b/gnu/usr.bin/gdb/gdb/dis-buf.c
new file mode 100644
index 000000000000..d07da6fcff31
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-buf.c
@@ -0,0 +1,69 @@
+/* Disassemble from a buffer, for GNU.
+ 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "dis-asm.h"
+#include <errno.h>
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+ Transfer them to myaddr. */
+int
+buffer_read_memory (memaddr, myaddr, length, info)
+ bfd_vma memaddr;
+ bfd_byte *myaddr;
+ int length;
+ struct disassemble_info *info;
+{
+ if (memaddr < info->buffer_vma
+ || memaddr + length > info->buffer_vma + info->buffer_length)
+ /* Out of bounds. Use EIO because GDB uses it. */
+ return EIO;
+ memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
+ return 0;
+}
+
+/* Print an error message. We can assume that this is in response to
+ an error return from buffer_read_memory. */
+void
+perror_memory (status, memaddr, info)
+ int status;
+ bfd_vma memaddr;
+ struct disassemble_info *info;
+{
+ if (status != EIO)
+ /* Can't happen. */
+ (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
+ else
+ /* Actually, address between memaddr and memaddr + len was
+ out of bounds. */
+ (*info->fprintf_func) (info->stream,
+ "Address 0x%x is out of bounds.\n", memaddr);
+}
+
+/* This could be in a separate file, to save miniscule amounts of space
+ in statically linked executables. */
+
+/* Just print the address is hex. This is included for completeness even
+ though both GDB and objdump provide their own (to print symbolic
+ addresses). */
+
+void
+generic_print_address (addr, info)
+ bfd_vma addr;
+ struct disassemble_info *info;
+{
+ (*info->fprintf_func) (info->stream, "0x%x", addr);
+}
diff --git a/gnu/usr.bin/gdb/gdb/dwarfread.c b/gnu/usr.bin/gdb/gdb/dwarfread.c
new file mode 100644
index 000000000000..5d19bf8d0b07
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dwarfread.c
@@ -0,0 +1,3866 @@
+/* DWARF debugging format support for GDB.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support. Portions based on dbxread.c,
+ mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+FIXME: Do we need to generate dependencies in partial symtabs?
+(Perhaps we don't need to).
+
+FIXME: Resolve minor differences between what information we put in the
+partial symbol table and what dbxread puts in. For example, we don't yet
+put enum constants there. And dbxread seems to invent a lot of typedefs
+we never see. Use the new printpsym command to see the partial symbol table
+contents.
+
+FIXME: Figure out a better way to tell gdb about the name of the function
+contain the user's entry point (I.E. main())
+
+FIXME: See other FIXME's and "ifdef 0" scattered throughout the code for
+other things to work on, if you get bored. :-)
+
+*/
+
+#include "defs.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include <time.h> /* For time_t in libbfd.h. */
+#include <sys/types.h> /* For time_t, if not in time.h. */
+#include "libbfd.h" /* FIXME Secret Internal BFD stuff (bfd_read) */
+#include "elf/dwarf.h"
+#include "buildsym.h"
+#include "demangle.h"
+#include "expression.h" /* Needed for enum exp_opcode in language.h, sigh... */
+#include "language.h"
+#include "complaints.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+
+/* FIXME -- convert this to SEEK_SET a la POSIX, move to config files. */
+#ifndef L_SET
+#define L_SET 0
+#endif
+
+/* Some macros to provide DIE info for complaints. */
+
+#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0)
+#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : ""
+
+/* Complaints that can be issued during DWARF debug info reading. */
+
+struct complaint no_bfd_get_N =
+{
+ "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0
+};
+
+struct complaint malformed_die =
+{
+ "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0
+};
+
+struct complaint bad_die_ref =
+{
+ "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0
+};
+
+struct complaint unknown_attribute_form =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0
+};
+
+struct complaint unknown_attribute_length =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0
+};
+
+struct complaint unexpected_fund_type =
+{
+ "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0
+};
+
+struct complaint unknown_type_modifier =
+{
+ "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0
+};
+
+struct complaint volatile_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0
+};
+
+struct complaint const_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0
+};
+
+struct complaint botched_modified_type =
+{
+ "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0
+};
+
+struct complaint op_deref2 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0
+};
+
+struct complaint op_deref4 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0
+};
+
+struct complaint basereg_not_handled =
+{
+ "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0
+};
+
+struct complaint dup_user_type_allocation =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0
+};
+
+struct complaint dup_user_type_definition =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0
+};
+
+struct complaint missing_tag =
+{
+ "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0
+};
+
+struct complaint bad_array_element_type =
+{
+ "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0
+};
+
+struct complaint subscript_data_items =
+{
+ "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0
+};
+
+struct complaint unhandled_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0
+};
+
+struct complaint unknown_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0
+};
+
+struct complaint not_row_major =
+{
+ "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0
+};
+
+typedef unsigned int DIE_REF; /* Reference to a DIE */
+
+#ifndef GCC_PRODUCER
+#define GCC_PRODUCER "GNU C "
+#endif
+
+#ifndef GPLUS_PRODUCER
+#define GPLUS_PRODUCER "GNU C++ "
+#endif
+
+#ifndef LCC_PRODUCER
+#define LCC_PRODUCER "NCR C/C++"
+#endif
+
+#ifndef CHILL_PRODUCER
+#define CHILL_PRODUCER "GNU Chill "
+#endif
+
+/* Flags to target_to_host() that tell whether or not the data object is
+ expected to be signed. Used, for example, when fetching a signed
+ integer in the target environment which is used as a signed integer
+ in the host environment, and the two environments have different sized
+ ints. In this case, *somebody* has to sign extend the smaller sized
+ int. */
+
+#define GET_UNSIGNED 0 /* No sign extension required */
+#define GET_SIGNED 1 /* Sign extension required */
+
+/* Defines for things which are specified in the document "DWARF Debugging
+ Information Format" published by UNIX International, Programming Languages
+ SIG. These defines are based on revision 1.0.0, Jan 20, 1992. */
+
+#define SIZEOF_DIE_LENGTH 4
+#define SIZEOF_DIE_TAG 2
+#define SIZEOF_ATTRIBUTE 2
+#define SIZEOF_FORMAT_SPECIFIER 1
+#define SIZEOF_FMT_FT 2
+#define SIZEOF_LINETBL_LENGTH 4
+#define SIZEOF_LINETBL_LINENO 4
+#define SIZEOF_LINETBL_STMT 2
+#define SIZEOF_LINETBL_DELTA 4
+#define SIZEOF_LOC_ATOM_CODE 1
+
+#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified */
+
+/* Macros that return the sizes of various types of data in the target
+ environment.
+
+ FIXME: Currently these are just compile time constants (as they are in
+ other parts of gdb as well). They need to be able to get the right size
+ either from the bfd or possibly from the DWARF info. It would be nice if
+ the DWARF producer inserted DIES that describe the fundamental types in
+ the target environment into the DWARF info, similar to the way dbx stabs
+ producers produce information about their fundamental types. */
+
+#define TARGET_FT_POINTER_SIZE(objfile) (TARGET_PTR_BIT / TARGET_CHAR_BIT)
+#define TARGET_FT_LONG_SIZE(objfile) (TARGET_LONG_BIT / TARGET_CHAR_BIT)
+
+/* The Amiga SVR4 header file <dwarf.h> defines AT_element_list as a
+ FORM_BLOCK2, and this is the value emitted by the AT&T compiler.
+ However, the Issue 2 DWARF specification from AT&T defines it as
+ a FORM_BLOCK4, as does the latest specification from UI/PLSIG.
+ For backwards compatibility with the AT&T compiler produced executables
+ we define AT_short_element_list for this variant. */
+
+#define AT_short_element_list (0x00f0|FORM_BLOCK2)
+
+/* External variables referenced. */
+
+extern int info_verbose; /* From main.c; nonzero => verbose */
+extern char *warning_pre_print; /* From utils.c */
+
+/* The DWARF debugging information consists of two major pieces,
+ one is a block of DWARF Information Entries (DIE's) and the other
+ is a line number table. The "struct dieinfo" structure contains
+ the information for a single DIE, the one currently being processed.
+
+ In order to make it easier to randomly access the attribute fields
+ of the current DIE, which are specifically unordered within the DIE,
+ each DIE is scanned and an instance of the "struct dieinfo"
+ structure is initialized.
+
+ Initialization is done in two levels. The first, done by basicdieinfo(),
+ just initializes those fields that are vital to deciding whether or not
+ to use this DIE, how to skip past it, etc. The second, done by the
+ function completedieinfo(), fills in the rest of the information.
+
+ Attributes which have block forms are not interpreted at the time
+ the DIE is scanned, instead we just save pointers to the start
+ of their value fields.
+
+ Some fields have a flag <name>_p that is set when the value of the
+ field is valid (I.E. we found a matching attribute in the DIE). Since
+ we may want to test for the presence of some attributes in the DIE,
+ such as AT_low_pc, without restricting the values of the field,
+ we need someway to note that we found such an attribute.
+
+ */
+
+typedef char BLOCK;
+
+struct dieinfo {
+ char * die; /* Pointer to the raw DIE data */
+ unsigned long die_length; /* Length of the raw DIE data */
+ DIE_REF die_ref; /* Offset of this DIE */
+ unsigned short die_tag; /* Tag for this DIE */
+ unsigned long at_padding;
+ unsigned long at_sibling;
+ BLOCK * at_location;
+ char * at_name;
+ unsigned short at_fund_type;
+ BLOCK * at_mod_fund_type;
+ unsigned long at_user_def_type;
+ BLOCK * at_mod_u_d_type;
+ unsigned short at_ordering;
+ BLOCK * at_subscr_data;
+ unsigned long at_byte_size;
+ unsigned short at_bit_offset;
+ unsigned long at_bit_size;
+ BLOCK * at_element_list;
+ unsigned long at_stmt_list;
+ unsigned long at_low_pc;
+ unsigned long at_high_pc;
+ unsigned long at_language;
+ unsigned long at_member;
+ unsigned long at_discr;
+ BLOCK * at_discr_value;
+ BLOCK * at_string_length;
+ char * at_comp_dir;
+ char * at_producer;
+ unsigned long at_start_scope;
+ unsigned long at_stride_size;
+ unsigned long at_src_info;
+ char * at_prototyped;
+ unsigned int has_at_low_pc:1;
+ unsigned int has_at_stmt_list:1;
+ unsigned int has_at_byte_size:1;
+ unsigned int short_element_list:1;
+};
+
+static int diecount; /* Approximate count of dies for compilation unit */
+static struct dieinfo *curdie; /* For warnings and such */
+
+static char *dbbase; /* Base pointer to dwarf info */
+static int dbsize; /* Size of dwarf info in bytes */
+static int dbroff; /* Relative offset from start of .debug section */
+static char *lnbase; /* Base pointer to line section */
+static int isreg; /* Kludge to identify register variables */
+/* Kludge to identify basereg references. Nonzero if we have an offset
+ relative to a basereg. */
+static int offreg;
+/* Which base register is it relative to? */
+static int basereg;
+
+/* This value is added to each symbol value. FIXME: Generalize to
+ the section_offsets structure used by dbxread (once this is done,
+ pass the appropriate section number to end_symtab). */
+static CORE_ADDR baseaddr; /* Add to each symbol value */
+
+/* The section offsets used in the current psymtab or symtab. FIXME,
+ only used to pass one value (baseaddr) at the moment. */
+static struct section_offsets *base_section_offsets;
+
+/* Each partial symbol table entry contains a pointer to private data for the
+ read_symtab() function to use when expanding a partial symbol table entry
+ to a full symbol table entry. For DWARF debugging info, this data is
+ contained in the following structure and macros are provided for easy
+ access to the members given a pointer to a partial symbol table entry.
+
+ dbfoff Always the absolute file offset to the start of the ".debug"
+ section for the file containing the DIE's being accessed.
+
+ dbroff Relative offset from the start of the ".debug" access to the
+ first DIE to be accessed. When building the partial symbol
+ table, this value will be zero since we are accessing the
+ entire ".debug" section. When expanding a partial symbol
+ table entry, this value will be the offset to the first
+ DIE for the compilation unit containing the symbol that
+ triggers the expansion.
+
+ dblength The size of the chunk of DIE's being examined, in bytes.
+
+ lnfoff The absolute file offset to the line table fragment. Ignored
+ when building partial symbol tables, but used when expanding
+ them, and contains the absolute file offset to the fragment
+ of the ".line" section containing the line numbers for the
+ current compilation unit.
+ */
+
+struct dwfinfo {
+ file_ptr dbfoff; /* Absolute file offset to start of .debug section */
+ int dbroff; /* Relative offset from start of .debug section */
+ int dblength; /* Size of the chunk of DIE's being examined */
+ file_ptr lnfoff; /* Absolute file offset to line table fragment */
+};
+
+#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff)
+#define DBROFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbroff)
+#define DBLENGTH(p) (((struct dwfinfo *)((p)->read_symtab_private))->dblength)
+#define LNFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->lnfoff)
+
+/* The generic symbol table building routines have separate lists for
+ file scope symbols and all all other scopes (local scopes). So
+ we need to select the right one to pass to add_symbol_to_list().
+ We do it by keeping a pointer to the correct list in list_in_scope.
+
+ FIXME: The original dwarf code just treated the file scope as the first
+ local scope, and all other local scopes as nested local scopes, and worked
+ fine. Check to see if we really need to distinguish these in buildsym.c */
+
+struct pending **list_in_scope = &file_symbols;
+
+/* DIES which have user defined types or modified user defined types refer to
+ other DIES for the type information. Thus we need to associate the offset
+ of a DIE for a user defined type with a pointer to the type information.
+
+ Originally this was done using a simple but expensive algorithm, with an
+ array of unsorted structures, each containing an offset/type-pointer pair.
+ This array was scanned linearly each time a lookup was done. The result
+ was that gdb was spending over half it's startup time munging through this
+ array of pointers looking for a structure that had the right offset member.
+
+ The second attempt used the same array of structures, but the array was
+ sorted using qsort each time a new offset/type was recorded, and a binary
+ search was used to find the type pointer for a given DIE offset. This was
+ even slower, due to the overhead of sorting the array each time a new
+ offset/type pair was entered.
+
+ The third attempt uses a fixed size array of type pointers, indexed by a
+ value derived from the DIE offset. Since the minimum DIE size is 4 bytes,
+ we can divide any DIE offset by 4 to obtain a unique index into this fixed
+ size array. Since each element is a 4 byte pointer, it takes exactly as
+ much memory to hold this array as to hold the DWARF info for a given
+ compilation unit. But it gets freed as soon as we are done with it.
+ This has worked well in practice, as a reasonable tradeoff between memory
+ consumption and speed, without having to resort to much more complicated
+ algorithms. */
+
+static struct type **utypes; /* Pointer to array of user type pointers */
+static int numutypes; /* Max number of user type pointers */
+
+/* Maintain an array of referenced fundamental types for the current
+ compilation unit being read. For DWARF version 1, we have to construct
+ the fundamental types on the fly, since no information about the
+ fundamental types is supplied. Each such fundamental type is created by
+ calling a language dependent routine to create the type, and then a
+ pointer to that type is then placed in the array at the index specified
+ by it's FT_<TYPENAME> value. The array has a fixed size set by the
+ FT_NUM_MEMBERS compile time constant, which is the number of predefined
+ fundamental types gdb knows how to construct. */
+
+static struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */
+
+/* Record the language for the compilation unit which is currently being
+ processed. We know it once we have seen the TAG_compile_unit DIE,
+ and we need it while processing the DIE's for that compilation unit.
+ It is eventually saved in the symtab structure, but we don't finalize
+ the symtab struct until we have processed all the DIE's for the
+ compilation unit. We also need to get and save a pointer to the
+ language struct for this language, so we can call the language
+ dependent routines for doing things such as creating fundamental
+ types. */
+
+static enum language cu_language;
+static const struct language_defn *cu_language_defn;
+
+/* Forward declarations of static functions so we don't have to worry
+ about ordering within this file. */
+
+static int
+attribute_size PARAMS ((unsigned int));
+
+static unsigned long
+target_to_host PARAMS ((char *, int, int, struct objfile *));
+
+static void
+add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+handle_producer PARAMS ((char *));
+
+static void
+read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static void
+read_func_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static void
+read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *,
+ struct objfile *));
+
+static void
+scan_partial_symbols PARAMS ((char *, char *, struct objfile *));
+
+static void
+scan_compilation_units PARAMS ((char *, char *, file_ptr,
+ file_ptr, struct objfile *));
+
+static void
+add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *, int));
+
+static void
+basicdieinfo PARAMS ((struct dieinfo *, char *, struct objfile *));
+
+static void
+completedieinfo PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+dwarf_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+process_dies PARAMS ((char *, char *, struct objfile *));
+
+static void
+read_structure_scope PARAMS ((struct dieinfo *, char *, char *,
+ struct objfile *));
+
+static struct type *
+decode_array_element_type PARAMS ((char *));
+
+static struct type *
+decode_subscript_data_item PARAMS ((char *, char *));
+
+static void
+dwarf_read_array_type PARAMS ((struct dieinfo *));
+
+static void
+read_tag_pointer_type PARAMS ((struct dieinfo *dip));
+
+static void
+read_tag_string_type PARAMS ((struct dieinfo *dip));
+
+static void
+read_subroutine_type PARAMS ((struct dieinfo *, char *, char *));
+
+static void
+read_enumeration PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static struct type *
+struct_type PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static struct type *
+enum_type PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+decode_line_numbers PARAMS ((char *));
+
+static struct type *
+decode_die_type PARAMS ((struct dieinfo *));
+
+static struct type *
+decode_mod_fund_type PARAMS ((char *));
+
+static struct type *
+decode_mod_u_d_type PARAMS ((char *));
+
+static struct type *
+decode_modified_type PARAMS ((char *, unsigned int, int));
+
+static struct type *
+decode_fund_type PARAMS ((unsigned int));
+
+static char *
+create_name PARAMS ((char *, struct obstack *));
+
+static struct type *
+lookup_utype PARAMS ((DIE_REF));
+
+static struct type *
+alloc_utype PARAMS ((DIE_REF, struct type *));
+
+static struct symbol *
+new_symbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *,
+ struct type *));
+
+static int
+locval PARAMS ((char *));
+
+static void
+set_cu_language PARAMS ((struct dieinfo *));
+
+static struct type *
+dwarf_fundamental_type PARAMS ((struct objfile *, int));
+
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_fundamental_type -- lookup or create a fundamental type
+
+SYNOPSIS
+
+ struct type *
+ dwarf_fundamental_type (struct objfile *objfile, int typeid)
+
+DESCRIPTION
+
+ DWARF version 1 doesn't supply any fundamental type information,
+ so gdb has to construct such types. It has a fixed number of
+ fundamental types that it knows how to construct, which is the
+ union of all types that it knows how to construct for all languages
+ that it knows about. These are enumerated in gdbtypes.h.
+
+ As an example, assume we find a DIE that references a DWARF
+ fundamental type of FT_integer. We first look in the ftypes
+ array to see if we already have such a type, indexed by the
+ gdb internal value of FT_INTEGER. If so, we simply return a
+ pointer to that type. If not, then we ask an appropriate
+ language dependent routine to create a type FT_INTEGER, using
+ defaults reasonable for the current target machine, and install
+ that type in ftypes for future reference.
+
+RETURNS
+
+ Pointer to a fundamental type.
+
+*/
+
+static struct type *
+dwarf_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("internal error - invalid fundamental type id %d", typeid);
+ }
+
+ /* Look for this particular type in the fundamental type vector. If one is
+ not found, create and install one appropriate for the current language
+ and the current target machine. */
+
+ if (ftypes[typeid] == NULL)
+ {
+ ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid);
+ }
+
+ return (ftypes[typeid]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ set_cu_language -- set local copy of language for compilation unit
+
+SYNOPSIS
+
+ void
+ set_cu_language (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Decode the language attribute for a compilation unit DIE and
+ remember what the language was. We use this at various times
+ when processing DIE's for a given compilation unit.
+
+RETURNS
+
+ No return value.
+
+ */
+
+static void
+set_cu_language (dip)
+ struct dieinfo *dip;
+{
+ switch (dip -> at_language)
+ {
+ case LANG_C89:
+ case LANG_C:
+ cu_language = language_c;
+ break;
+ case LANG_C_PLUS_PLUS:
+ cu_language = language_cplus;
+ break;
+ case LANG_CHILL:
+ cu_language = language_chill;
+ break;
+ case LANG_MODULA2:
+ cu_language = language_m2;
+ break;
+ case LANG_ADA83:
+ case LANG_COBOL74:
+ case LANG_COBOL85:
+ case LANG_FORTRAN77:
+ case LANG_FORTRAN90:
+ case LANG_PASCAL83:
+ /* We don't know anything special about these yet. */
+ cu_language = language_unknown;
+ break;
+ default:
+ /* If no at_language, try to deduce one from the filename */
+ cu_language = deduce_language_from_filename (dip -> at_name);
+ break;
+ }
+ cu_language_defn = language_def (cu_language);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ dwarf_build_psymtabs -- build partial symtabs from DWARF debug info
+
+SYNOPSIS
+
+ void dwarf_build_psymtabs (struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline, file_ptr dbfoff, unsigned int dbfsize,
+ file_ptr lnoffset, unsigned int lnsize)
+
+DESCRIPTION
+
+ This function is called upon to build partial symtabs from files
+ containing DIE's (Dwarf Information Entries) and DWARF line numbers.
+
+ It is passed a bfd* containing the DIES
+ and line number information, the corresponding filename for that
+ file, a base address for relocating the symbols, a flag indicating
+ whether or not this debugging information is from a "main symbol
+ table" rather than a shared library or dynamically linked file,
+ and file offset/size pairs for the DIE information and line number
+ information.
+
+RETURNS
+
+ No return value.
+
+ */
+
+void
+dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize,
+ lnoffset, lnsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr dbfoff;
+ unsigned int dbfsize;
+ file_ptr lnoffset;
+ unsigned int lnsize;
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+
+ current_objfile = objfile;
+ dbsize = dbfsize;
+ dbbase = xmalloc (dbsize);
+ dbroff = 0;
+ if ((bfd_seek (abfd, dbfoff, L_SET) != 0) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
+ {
+ free (dbbase);
+ error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
+ }
+ back_to = make_cleanup (free, dbbase);
+
+ /* If we are reinitializing, or if we have never loaded syms yet, init.
+ Since we have no idea how many DIES we are looking at, we just guess
+ some arbitrary value. */
+
+ if (mainline || objfile -> global_psymbols.size == 0 ||
+ objfile -> static_psymbols.size == 0)
+ {
+ init_psymbol_list (objfile, 1024);
+ }
+
+ /* Save the relocation factor where everybody can see it. */
+
+ base_section_offsets = section_offsets;
+ baseaddr = ANOFFSET (section_offsets, 0);
+
+ /* Follow the compilation unit sibling chain, building a partial symbol
+ table entry for each one. Save enough information about each compilation
+ unit to locate the full DWARF information later. */
+
+ scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile);
+
+ do_cleanups (back_to);
+ current_objfile = NULL;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_lexical_block_scope -- process all dies in a lexical block
+
+SYNOPSIS
+
+ static void read_lexical_block_scope (struct dieinfo *dip,
+ char *thisdie, char *enddie)
+
+DESCRIPTION
+
+ Process all the DIES contained within a lexical block scope.
+ Start a new scope, process the dies, and then close the scope.
+
+ */
+
+static void
+read_lexical_block_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ register struct context_stack *new;
+
+ push_context (0, dip -> at_low_pc);
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+ new = pop_context ();
+ if (local_symbols != NULL)
+ {
+ finish_block (0, &local_symbols, new -> old_blocks, new -> start_addr,
+ dip -> at_high_pc, objfile);
+ }
+ local_symbols = new -> locals;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ lookup_utype -- look up a user defined type from die reference
+
+SYNOPSIS
+
+ static type *lookup_utype (DIE_REF die_ref)
+
+DESCRIPTION
+
+ Given a DIE reference, lookup the user defined type associated with
+ that DIE, if it has been registered already. If not registered, then
+ return NULL. Alloc_utype() can be called to register an empty
+ type for this reference, which will be filled in later when the
+ actual referenced DIE is processed.
+ */
+
+static struct type *
+lookup_utype (die_ref)
+ DIE_REF die_ref;
+{
+ struct type *type = NULL;
+ int utypeidx;
+
+ utypeidx = (die_ref - dbroff) / 4;
+ if ((utypeidx < 0) || (utypeidx >= numutypes))
+ {
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
+ }
+ else
+ {
+ type = *(utypes + utypeidx);
+ }
+ return (type);
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ alloc_utype -- add a user defined type for die reference
+
+SYNOPSIS
+
+ static type *alloc_utype (DIE_REF die_ref, struct type *utypep)
+
+DESCRIPTION
+
+ Given a die reference DIE_REF, and a possible pointer to a user
+ defined type UTYPEP, register that this reference has a user
+ defined type and either use the specified type in UTYPEP or
+ make a new empty type that will be filled in later.
+
+ We should only be called after calling lookup_utype() to verify that
+ there is not currently a type registered for DIE_REF.
+ */
+
+static struct type *
+alloc_utype (die_ref, utypep)
+ DIE_REF die_ref;
+ struct type *utypep;
+{
+ struct type **typep;
+ int utypeidx;
+
+ utypeidx = (die_ref - dbroff) / 4;
+ typep = utypes + utypeidx;
+ if ((utypeidx < 0) || (utypeidx >= numutypes))
+ {
+ utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
+ }
+ else if (*typep != NULL)
+ {
+ utypep = *typep;
+ complain (&dup_user_type_allocation, DIE_ID, DIE_NAME);
+ }
+ else
+ {
+ if (utypep == NULL)
+ {
+ utypep = alloc_type (current_objfile);
+ }
+ *typep = utypep;
+ }
+ return (utypep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_die_type -- return a type for a specified die
+
+SYNOPSIS
+
+ static struct type *decode_die_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Given a pointer to a die information structure DIP, decode the
+ type of the die and return a pointer to the decoded type. All
+ dies without specific types default to type int.
+ */
+
+static struct type *
+decode_die_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type = NULL;
+
+ if (dip -> at_fund_type != 0)
+ {
+ type = decode_fund_type (dip -> at_fund_type);
+ }
+ else if (dip -> at_mod_fund_type != NULL)
+ {
+ type = decode_mod_fund_type (dip -> at_mod_fund_type);
+ }
+ else if (dip -> at_user_def_type)
+ {
+ if ((type = lookup_utype (dip -> at_user_def_type)) == NULL)
+ {
+ type = alloc_utype (dip -> at_user_def_type, NULL);
+ }
+ }
+ else if (dip -> at_mod_u_d_type)
+ {
+ type = decode_mod_u_d_type (dip -> at_mod_u_d_type);
+ }
+ else
+ {
+ type = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ struct_type -- compute and return the type for a struct or union
+
+SYNOPSIS
+
+ static struct type *struct_type (struct dieinfo *dip, char *thisdie,
+ char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given pointer to a die information structure for a die which
+ defines a union or structure (and MUST define one or the other),
+ and pointers to the raw die data that define the range of dies which
+ define the members, compute and return the user defined type for the
+ structure or union.
+ */
+
+static struct type *
+struct_type (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct nextfield {
+ struct nextfield *next;
+ struct field field;
+ };
+ struct nextfield *list = NULL;
+ struct nextfield *new;
+ int nfields = 0;
+ int n;
+ struct dieinfo mbr;
+ char *nextdie;
+#if !BITS_BIG_ENDIAN
+ int anonymous_size;
+#endif
+
+ if ((type = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* No forward references created an empty type, so install one now */
+ type = alloc_utype (dip -> die_ref, NULL);
+ }
+ INIT_CPLUS_SPECIFIC(type);
+ switch (dip -> die_tag)
+ {
+ case TAG_class_type:
+ TYPE_CODE (type) = TYPE_CODE_CLASS;
+ break;
+ case TAG_structure_type:
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case TAG_union_type:
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ default:
+ /* Should never happen */
+ TYPE_CODE (type) = TYPE_CODE_UNDEF;
+ complain (&missing_tag, DIE_ID, DIE_NAME);
+ break;
+ }
+ /* Some compilers try to be helpful by inventing "fake" names for
+ anonymous enums, structures, and unions, like "~0fake" or ".0fake".
+ Thanks, but no thanks... */
+ if (dip -> at_name != NULL
+ && *dip -> at_name != '~'
+ && *dip -> at_name != '.')
+ {
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
+ }
+ /* Use whatever size is known. Zero is a valid size. We might however
+ wish to check has_at_byte_size to make sure that some byte size was
+ given explicitly, but DWARF doesn't specify that explicit sizes of
+ zero have to present, so complaining about missing sizes should
+ probably not be the default. */
+ TYPE_LENGTH (type) = dip -> at_byte_size;
+ thisdie += dip -> die_length;
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&mbr, thisdie, objfile);
+ completedieinfo (&mbr, objfile);
+ if (mbr.die_length <= SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (mbr.at_sibling != 0)
+ {
+ nextdie = dbbase + mbr.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + mbr.die_length;
+ }
+ switch (mbr.die_tag)
+ {
+ case TAG_member:
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new -> next = list;
+ list = new;
+ /* Save the data. */
+ list -> field.name =
+ obsavestring (mbr.at_name, strlen (mbr.at_name),
+ &objfile -> type_obstack);
+ list -> field.type = decode_die_type (&mbr);
+ list -> field.bitpos = 8 * locval (mbr.at_location);
+ /* Handle bit fields. */
+ list -> field.bitsize = mbr.at_bit_size;
+#if BITS_BIG_ENDIAN
+ /* For big endian bits, the at_bit_offset gives the additional
+ bit offset from the MSB of the containing anonymous object to
+ the MSB of the field. We don't have to do anything special
+ since we don't need to know the size of the anonymous object. */
+ list -> field.bitpos += mbr.at_bit_offset;
+#else
+ /* For little endian bits, we need to have a non-zero at_bit_size,
+ so that we know we are in fact dealing with a bitfield. Compute
+ the bit offset to the MSB of the anonymous object, subtract off
+ the number of bits from the MSB of the field to the MSB of the
+ object, and then subtract off the number of bits of the field
+ itself. The result is the bit offset of the LSB of the field. */
+ if (mbr.at_bit_size > 0)
+ {
+ if (mbr.has_at_byte_size)
+ {
+ /* The size of the anonymous object containing the bit field
+ is explicit, so use the indicated size (in bytes). */
+ anonymous_size = mbr.at_byte_size;
+ }
+ else
+ {
+ /* The size of the anonymous object containing the bit field
+ matches the size of an object of the bit field's type.
+ DWARF allows at_byte_size to be left out in such cases,
+ as a debug information size optimization. */
+ anonymous_size = TYPE_LENGTH (list -> field.type);
+ }
+ list -> field.bitpos +=
+ anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
+ }
+#endif
+ nfields++;
+ break;
+ default:
+ process_dies (thisdie, nextdie, objfile);
+ break;
+ }
+ thisdie = nextdie;
+ }
+ /* Now create the vector of fields, and record how big it is. We may
+ not even have any fields, if this DIE was generated due to a reference
+ to an anonymous structure or union. In this case, TYPE_FLAG_STUB is
+ set, which clues gdb in to the fact that it needs to search elsewhere
+ for the full structure definition. */
+ if (nfields == 0)
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+ }
+ else
+ {
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+ /* Copy the saved-up fields into the field vector. */
+ for (n = nfields; list; list = list -> next)
+ {
+ TYPE_FIELD (type, --n) = list -> field;
+ }
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_structure_scope -- process all dies within struct or union
+
+SYNOPSIS
+
+ static void read_structure_scope (struct dieinfo *dip,
+ char *thisdie, char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Called when we find the DIE that starts a structure or union
+ scope (definition) to process all dies that define the members
+ of the structure or union. DIP is a pointer to the die info
+ struct for the DIE that names the structure or union.
+
+NOTES
+
+ Note that we need to call struct_type regardless of whether or not
+ the DIE has an at_name attribute, since it might be an anonymous
+ structure or union. This gets the type entered into our set of
+ user defined types.
+
+ However, if the structure is incomplete (an opaque struct/union)
+ then suppress creating a symbol table entry for it since gdb only
+ wants to find the one with the complete definition. Note that if
+ it is complete, we just call new_symbol, which does it's own
+ checking about whether the struct/union is anonymous or not (and
+ suppresses creating a symbol table entry itself).
+
+ */
+
+static void
+read_structure_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct symbol *sym;
+
+ type = struct_type (dip, thisdie, enddie, objfile);
+ if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB))
+ {
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
+ {
+ SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_array_element_type -- decode type of the array elements
+
+SYNOPSIS
+
+ static struct type *decode_array_element_type (char *scan, char *end)
+
+DESCRIPTION
+
+ As the last step in decoding the array subscript information for an
+ array DIE, we need to decode the type of the array elements. We are
+ passed a pointer to this last part of the subscript information and
+ must return the appropriate type. If the type attribute is not
+ recognized, just warn about the problem and return type int.
+ */
+
+static struct type *
+decode_array_element_type (scan)
+ char *scan;
+{
+ struct type *typep;
+ DIE_REF die_ref;
+ unsigned short attribute;
+ unsigned short fundtype;
+ int nbytes;
+
+ attribute = target_to_host (scan, SIZEOF_ATTRIBUTE, GET_UNSIGNED,
+ current_objfile);
+ scan += SIZEOF_ATTRIBUTE;
+ if ((nbytes = attribute_size (attribute)) == -1)
+ {
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ else
+ {
+ switch (attribute)
+ {
+ case AT_fund_type:
+ fundtype = target_to_host (scan, nbytes, GET_UNSIGNED,
+ current_objfile);
+ typep = decode_fund_type (fundtype);
+ break;
+ case AT_mod_fund_type:
+ typep = decode_mod_fund_type (scan);
+ break;
+ case AT_user_def_type:
+ die_ref = target_to_host (scan, nbytes, GET_UNSIGNED,
+ current_objfile);
+ if ((typep = lookup_utype (die_ref)) == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ case AT_mod_u_d_type:
+ typep = decode_mod_u_d_type (scan);
+ break;
+ default:
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+ }
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_subscript_data_item -- decode array subscript item
+
+SYNOPSIS
+
+ static struct type *
+ decode_subscript_data_item (char *scan, char *end)
+
+DESCRIPTION
+
+ The array subscripts and the data type of the elements of an
+ array are described by a list of data items, stored as a block
+ of contiguous bytes. There is a data item describing each array
+ dimension, and a final data item describing the element type.
+ The data items are ordered the same as their appearance in the
+ source (I.E. leftmost dimension first, next to leftmost second,
+ etc).
+
+ The data items describing each array dimension consist of four
+ parts: (1) a format specifier, (2) type type of the subscript
+ index, (3) a description of the low bound of the array dimension,
+ and (4) a description of the high bound of the array dimension.
+
+ The last data item is the description of the type of each of
+ the array elements.
+
+ We are passed a pointer to the start of the block of bytes
+ containing the remaining data items, and a pointer to the first
+ byte past the data. This function recursively decodes the
+ remaining data items and returns a type.
+
+ If we somehow fail to decode some data, we complain about it
+ and return a type "array of int".
+
+BUGS
+ FIXME: This code only implements the forms currently used
+ by the AT&T and GNU C compilers.
+
+ The end pointer is supplied for error checking, maybe we should
+ use it for that...
+ */
+
+static struct type *
+decode_subscript_data_item (scan, end)
+ char *scan;
+ char *end;
+{
+ struct type *typep = NULL; /* Array type we are building */
+ struct type *nexttype; /* Type of each element (may be array) */
+ struct type *indextype; /* Type of this index */
+ struct type *rangetype;
+ unsigned int format;
+ unsigned short fundtype;
+ unsigned long lowbound;
+ unsigned long highbound;
+ int nbytes;
+
+ format = target_to_host (scan, SIZEOF_FORMAT_SPECIFIER, GET_UNSIGNED,
+ current_objfile);
+ scan += SIZEOF_FORMAT_SPECIFIER;
+ switch (format)
+ {
+ case FMT_ET:
+ typep = decode_array_element_type (scan);
+ break;
+ case FMT_FT_C_C:
+ fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED,
+ current_objfile);
+ indextype = decode_fund_type (fundtype);
+ scan += SIZEOF_FMT_FT;
+ nbytes = TARGET_FT_LONG_SIZE (current_objfile);
+ lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ nexttype = decode_subscript_data_item (scan, end);
+ if (nexttype == NULL)
+ {
+ /* Munged subscript data or other problem, fake it. */
+ complain (&subscript_data_items, DIE_ID, DIE_NAME);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ rangetype = create_range_type ((struct type *) NULL, indextype,
+ lowbound, highbound);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ case FMT_FT_C_X:
+ case FMT_FT_X_C:
+ case FMT_FT_X_X:
+ case FMT_UT_C_C:
+ case FMT_UT_C_X:
+ case FMT_UT_X_C:
+ case FMT_UT_X_X:
+ complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ default:
+ complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_read_array_type -- read TAG_array_type DIE
+
+SYNOPSIS
+
+ static void dwarf_read_array_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_array_type DIE and add to
+ the user defined type vector.
+ */
+
+static void
+dwarf_read_array_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type;
+ struct type *utype;
+ char *sub;
+ char *subend;
+ unsigned short blocksz;
+ int nbytes;
+
+ if (dip -> at_ordering != ORD_row_major)
+ {
+ /* FIXME: Can gdb even handle column major arrays? */
+ complain (&not_row_major, DIE_ID, DIE_NAME);
+ }
+ if ((sub = dip -> at_subscr_data) != NULL)
+ {
+ nbytes = attribute_size (AT_subscr_data);
+ blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile);
+ subend = sub + nbytes + blocksz;
+ sub += nbytes;
+ type = decode_subscript_data_item (sub, subend);
+ if ((utype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* Install user defined type that has not been referenced yet. */
+ alloc_utype (dip -> die_ref, type);
+ }
+ else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF)
+ {
+ /* Ick! A forward ref has already generated a blank type in our
+ slot, and this type probably already has things pointing to it
+ (which is what caused it to be created in the first place).
+ If it's just a place holder we can plop our fully defined type
+ on top of it. We can't recover the space allocated for our
+ new type since it might be on an obstack, but we could reuse
+ it if we kept a list of them, but it might not be worth it
+ (FIXME). */
+ *utype = *type;
+ }
+ else
+ {
+ /* Double ick! Not only is a type already in our slot, but
+ someone has decorated it. Complain and leave it alone. */
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_tag_pointer_type -- read TAG_pointer_type DIE
+
+SYNOPSIS
+
+ static void read_tag_pointer_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_pointer_type DIE and add to
+ the user defined type vector.
+ */
+
+static void
+read_tag_pointer_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type;
+ struct type *utype;
+
+ type = decode_die_type (dip);
+ if ((utype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ utype = lookup_pointer_type (type);
+ alloc_utype (dip -> die_ref, utype);
+ }
+ else
+ {
+ TYPE_TARGET_TYPE (utype) = type;
+ TYPE_POINTER_TYPE (type) = utype;
+
+ /* We assume the machine has only one representation for pointers! */
+ /* FIXME: This confuses host<->target data representations, and is a
+ poor assumption besides. */
+
+ TYPE_LENGTH (utype) = sizeof (char *);
+ TYPE_CODE (utype) = TYPE_CODE_PTR;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_tag_string_type -- read TAG_string_type DIE
+
+SYNOPSIS
+
+ static void read_tag_string_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_string_type DIE and add to
+ the user defined type vector. It isn't really a user defined
+ type, but it behaves like one, with other DIE's using an
+ AT_user_def_type attribute to reference it.
+ */
+
+static void
+read_tag_string_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *utype;
+ struct type *indextype;
+ struct type *rangetype;
+ unsigned long lowbound = 0;
+ unsigned long highbound;
+
+ if (dip -> has_at_byte_size)
+ {
+ /* A fixed bounds string */
+ highbound = dip -> at_byte_size - 1;
+ }
+ else
+ {
+ /* A varying length string. Stub for now. (FIXME) */
+ highbound = 1;
+ }
+ indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, indextype, lowbound,
+ highbound);
+
+ utype = lookup_utype (dip -> die_ref);
+ if (utype == NULL)
+ {
+ /* No type defined, go ahead and create a blank one to use. */
+ utype = alloc_utype (dip -> die_ref, (struct type *) NULL);
+ }
+ else
+ {
+ /* Already a type in our slot due to a forward reference. Make sure it
+ is a blank one. If not, complain and leave it alone. */
+ if (TYPE_CODE (utype) != TYPE_CODE_UNDEF)
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ return;
+ }
+ }
+
+ /* Create the string type using the blank type we either found or created. */
+ utype = create_string_type (utype, rangetype);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_subroutine_type -- process TAG_subroutine_type dies
+
+SYNOPSIS
+
+ static void read_subroutine_type (struct dieinfo *dip, char thisdie,
+ char *enddie)
+
+DESCRIPTION
+
+ Handle DIES due to C code like:
+
+ struct foo {
+ int (*funcp)(int a, long l); (Generates TAG_subroutine_type DIE)
+ int b;
+ };
+
+NOTES
+
+ The parameter DIES are currently ignored. See if gdb has a way to
+ include this info in it's type system, and decode them if so. Is
+ this what the type structure's "arg_types" field is for? (FIXME)
+ */
+
+static void
+read_subroutine_type (dip, thisdie, enddie)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+{
+ struct type *type; /* Type that this function returns */
+ struct type *ftype; /* Function that returns above type */
+
+ /* Decode the type that this subroutine returns */
+
+ type = decode_die_type (dip);
+
+ /* Check to see if we already have a partially constructed user
+ defined type for this DIE, from a forward reference. */
+
+ if ((ftype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* This is the first reference to one of these types. Make
+ a new one and place it in the user defined types. */
+ ftype = lookup_function_type (type);
+ alloc_utype (dip -> die_ref, ftype);
+ }
+ else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF)
+ {
+ /* We have an existing partially constructed type, so bash it
+ into the correct type. */
+ TYPE_TARGET_TYPE (ftype) = type;
+ TYPE_FUNCTION_TYPE (type) = ftype;
+ TYPE_LENGTH (ftype) = 1;
+ TYPE_CODE (ftype) = TYPE_CODE_FUNC;
+ }
+ else
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_enumeration -- process dies which define an enumeration
+
+SYNOPSIS
+
+ static void read_enumeration (struct dieinfo *dip, char *thisdie,
+ char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a die which begins an enumeration, process all
+ the dies that define the members of the enumeration.
+
+NOTES
+
+ Note that we need to call enum_type regardless of whether or not we
+ have a symbol, since we might have an enum without a tag name (thus
+ no symbol for the tagname).
+ */
+
+static void
+read_enumeration (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct symbol *sym;
+
+ type = enum_type (dip, objfile);
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
+ {
+ SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ enum_type -- decode and return a type for an enumeration
+
+SYNOPSIS
+
+ static type *enum_type (struct dieinfo *dip, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a die information structure for the die which
+ starts an enumeration, process all the dies that define the members
+ of the enumeration and return a type pointer for the enumeration.
+
+ At the same time, for each member of the enumeration, create a
+ symbol for it with namespace VAR_NAMESPACE and class LOC_CONST,
+ and give it the type of the enumeration itself.
+
+NOTES
+
+ Note that the DWARF specification explicitly mandates that enum
+ constants occur in reverse order from the source program order,
+ for "consistency" and because this ordering is easier for many
+ compilers to generate. (Draft 6, sec 3.8.5, Enumeration type
+ Entries). Because gdb wants to see the enum members in program
+ source order, we have to ensure that the order gets reversed while
+ we are processing them.
+ */
+
+static struct type *
+enum_type (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct nextfield {
+ struct nextfield *next;
+ struct field field;
+ };
+ struct nextfield *list = NULL;
+ struct nextfield *new;
+ int nfields = 0;
+ int n;
+ char *scan;
+ char *listend;
+ unsigned short blocksz;
+ struct symbol *sym;
+ int nbytes;
+
+ if ((type = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* No forward references created an empty type, so install one now */
+ type = alloc_utype (dip -> die_ref, NULL);
+ }
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ /* Some compilers try to be helpful by inventing "fake" names for
+ anonymous enums, structures, and unions, like "~0fake" or ".0fake".
+ Thanks, but no thanks... */
+ if (dip -> at_name != NULL
+ && *dip -> at_name != '~'
+ && *dip -> at_name != '.')
+ {
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
+ }
+ if (dip -> at_byte_size != 0)
+ {
+ TYPE_LENGTH (type) = dip -> at_byte_size;
+ }
+ if ((scan = dip -> at_element_list) != NULL)
+ {
+ if (dip -> short_element_list)
+ {
+ nbytes = attribute_size (AT_short_element_list);
+ }
+ else
+ {
+ nbytes = attribute_size (AT_element_list);
+ }
+ blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
+ listend = scan + nbytes + blocksz;
+ scan += nbytes;
+ while (scan < listend)
+ {
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new -> next = list;
+ list = new;
+ list -> field.type = NULL;
+ list -> field.bitsize = 0;
+ list -> field.bitpos =
+ target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED,
+ objfile);
+ scan += TARGET_FT_LONG_SIZE (objfile);
+ list -> field.name = obsavestring (scan, strlen (scan),
+ &objfile -> type_obstack);
+ scan += strlen (scan) + 1;
+ nfields++;
+ /* Handcraft a new symbol for this enum member. */
+ sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (list -> field.name,
+ &objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_VALUE (sym) = list -> field.bitpos;
+ add_symbol_to_list (sym, list_in_scope);
+ }
+ /* Now create the vector of fields, and record how big it is. This is
+ where we reverse the order, by pulling the members off the list in
+ reverse order from how they were inserted. If we have no fields
+ (this is apparently possible in C++) then skip building a field
+ vector. */
+ if (nfields > 0)
+ {
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields);
+ /* Copy the saved-up fields into the field vector. */
+ for (n = 0; (n < nfields) && (list != NULL); list = list -> next)
+ {
+ TYPE_FIELD (type, n++) = list -> field;
+ }
+ }
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_func_scope -- process all dies within a function scope
+
+DESCRIPTION
+
+ Process all dies within a given function scope. We are passed
+ a die information structure pointer DIP for the die which
+ starts the function scope, and pointers into the raw die data
+ that define the dies within the function scope.
+
+ For now, we ignore lexical block scopes within the function.
+ The problem is that AT&T cc does not define a DWARF lexical
+ block scope for the function itself, while gcc defines a
+ lexical block scope for the function. We need to think about
+ how to handle this difference, or if it is even a problem.
+ (FIXME)
+ */
+
+static void
+read_func_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ register struct context_stack *new;
+
+ if (objfile -> ei.entry_point >= dip -> at_low_pc &&
+ objfile -> ei.entry_point < dip -> at_high_pc)
+ {
+ objfile -> ei.entry_func_lowpc = dip -> at_low_pc;
+ objfile -> ei.entry_func_highpc = dip -> at_high_pc;
+ }
+ if (STREQ (dip -> at_name, "main")) /* FIXME: hardwired name */
+ {
+ objfile -> ei.main_func_lowpc = dip -> at_low_pc;
+ objfile -> ei.main_func_highpc = dip -> at_high_pc;
+ }
+ new = push_context (0, dip -> at_low_pc);
+ new -> name = new_symbol (dip, objfile);
+ list_in_scope = &local_symbols;
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+ new = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (new -> name, &local_symbols, new -> old_blocks,
+ new -> start_addr, dip -> at_high_pc, objfile);
+ list_in_scope = &file_symbols;
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ handle_producer -- process the AT_producer attribute
+
+DESCRIPTION
+
+ Perform any operations that depend on finding a particular
+ AT_producer attribute.
+
+ */
+
+static void
+handle_producer (producer)
+ char *producer;
+{
+
+ /* If this compilation unit was compiled with g++ or gcc, then set the
+ processing_gcc_compilation flag. */
+
+ processing_gcc_compilation =
+ STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))
+ || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER))
+ || STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER));
+
+ /* Select a demangling style if we can identify the producer and if
+ the current style is auto. We leave the current style alone if it
+ is not auto. We also leave the demangling style alone if we find a
+ gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */
+
+ if (AUTO_DEMANGLING)
+ {
+ if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER)))
+ {
+ set_demangling_style (LUCID_DEMANGLING_STYLE_STRING);
+ }
+ }
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ read_file_scope -- process all dies within a file scope
+
+DESCRIPTION
+
+ Process all dies within a given file scope. We are passed a
+ pointer to the die information structure for the die which
+ starts the file scope, and pointers into the raw die data which
+ mark the range of dies within the file scope.
+
+ When the partial symbol table is built, the file offset for the line
+ number table for each compilation unit is saved in the partial symbol
+ table entry for that compilation unit. As the symbols for each
+ compilation unit are read, the line number table is read into memory
+ and the variable lnbase is set to point to it. Thus all we have to
+ do is use lnbase to access the line number table for the current
+ compilation unit.
+ */
+
+static void
+read_file_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct cleanup *back_to;
+ struct symtab *symtab;
+
+ if (objfile -> ei.entry_point >= dip -> at_low_pc &&
+ objfile -> ei.entry_point < dip -> at_high_pc)
+ {
+ objfile -> ei.entry_file_lowpc = dip -> at_low_pc;
+ objfile -> ei.entry_file_highpc = dip -> at_high_pc;
+ }
+ set_cu_language (dip);
+ if (dip -> at_producer != NULL)
+ {
+ handle_producer (dip -> at_producer);
+ }
+ numutypes = (enddie - thisdie) / 4;
+ utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
+ back_to = make_cleanup (free, utypes);
+ memset (utypes, 0, numutypes * sizeof (struct type *));
+ memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *));
+ start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc);
+ decode_line_numbers (lnbase);
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+
+ symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile, 0);
+ if (symtab != NULL)
+ {
+ symtab -> language = cu_language;
+ }
+ do_cleanups (back_to);
+ utypes = NULL;
+ numutypes = 0;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ process_dies -- process a range of DWARF Information Entries
+
+SYNOPSIS
+
+ static void process_dies (char *thisdie, char *enddie,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Process all DIE's in a specified range. May be (and almost
+ certainly will be) called recursively.
+ */
+
+static void
+process_dies (thisdie, enddie, objfile)
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ struct dieinfo di;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (di.die_tag == TAG_padding)
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ else
+ {
+ completedieinfo (&di, objfile);
+ if (di.at_sibling != 0)
+ {
+ nextdie = dbbase + di.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ switch (di.die_tag)
+ {
+ case TAG_compile_unit:
+ read_file_scope (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ if (di.has_at_low_pc)
+ {
+ read_func_scope (&di, thisdie, nextdie, objfile);
+ }
+ break;
+ case TAG_lexical_block:
+ read_lexical_block_scope (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ read_structure_scope (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_enumeration_type:
+ read_enumeration (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_subroutine_type:
+ read_subroutine_type (&di, thisdie, nextdie);
+ break;
+ case TAG_array_type:
+ dwarf_read_array_type (&di);
+ break;
+ case TAG_pointer_type:
+ read_tag_pointer_type (&di);
+ break;
+ case TAG_string_type:
+ read_tag_string_type (&di);
+ break;
+ default:
+ new_symbol (&di, objfile);
+ break;
+ }
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_line_numbers -- decode a line number table fragment
+
+SYNOPSIS
+
+ static void decode_line_numbers (char *tblscan, char *tblend,
+ long length, long base, long line, long pc)
+
+DESCRIPTION
+
+ Translate the DWARF line number information to gdb form.
+
+ The ".line" section contains one or more line number tables, one for
+ each ".line" section from the objects that were linked.
+
+ The AT_stmt_list attribute for each TAG_source_file entry in the
+ ".debug" section contains the offset into the ".line" section for the
+ start of the table for that file.
+
+ The table itself has the following structure:
+
+ <table length><base address><source statement entry>
+ 4 bytes 4 bytes 10 bytes
+
+ The table length is the total size of the table, including the 4 bytes
+ for the length information.
+
+ The base address is the address of the first instruction generated
+ for the source file.
+
+ Each source statement entry has the following structure:
+
+ <line number><statement position><address delta>
+ 4 bytes 2 bytes 4 bytes
+
+ The line number is relative to the start of the file, starting with
+ line 1.
+
+ The statement position either -1 (0xFFFF) or the number of characters
+ from the beginning of the line to the beginning of the statement.
+
+ The address delta is the difference between the base address and
+ the address of the first instruction for the statement.
+
+ Note that we must copy the bytes from the packed table to our local
+ variables before attempting to use them, to avoid alignment problems
+ on some machines, particularly RISC processors.
+
+BUGS
+
+ Does gdb expect the line numbers to be sorted? They are now by
+ chance/luck, but are not required to be. (FIXME)
+
+ The line with number 0 is unused, gdb apparently can discover the
+ span of the last line some other way. How? (FIXME)
+ */
+
+static void
+decode_line_numbers (linetable)
+ char *linetable;
+{
+ char *tblscan;
+ char *tblend;
+ unsigned long length;
+ unsigned long base;
+ unsigned long line;
+ unsigned long pc;
+
+ if (linetable != NULL)
+ {
+ tblscan = tblend = linetable;
+ length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_LENGTH;
+ tblend += length;
+ base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile),
+ GET_UNSIGNED, current_objfile);
+ tblscan += TARGET_FT_POINTER_SIZE (objfile);
+ base += baseaddr;
+ while (tblscan < tblend)
+ {
+ line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT;
+ pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_DELTA;
+ pc += base;
+ if (line != 0)
+ {
+ record_line (current_subfile, line, pc);
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ locval -- compute the value of a location attribute
+
+SYNOPSIS
+
+ static int locval (char *loc)
+
+DESCRIPTION
+
+ Given pointer to a string of bytes that define a location, compute
+ the location and return the value.
+
+ When computing values involving the current value of the frame pointer,
+ the value zero is used, which results in a value relative to the frame
+ pointer, rather than the absolute value. This is what GDB wants
+ anyway.
+
+ When the result is a register number, the global isreg flag is set,
+ otherwise it is cleared. This is a kludge until we figure out a better
+ way to handle the problem. Gdb's design does not mesh well with the
+ DWARF notion of a location computing interpreter, which is a shame
+ because the flexibility goes unused.
+
+NOTES
+
+ Note that stack[0] is unused except as a default error return.
+ Note that stack overflow is not yet handled.
+ */
+
+static int
+locval (loc)
+ char *loc;
+{
+ unsigned short nbytes;
+ unsigned short locsize;
+ auto long stack[64];
+ int stacki;
+ char *end;
+ int loc_atom_code;
+ int loc_value_size;
+
+ nbytes = attribute_size (AT_location);
+ locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile);
+ loc += nbytes;
+ end = loc + locsize;
+ stacki = 0;
+ stack[stacki] = 0;
+ isreg = 0;
+ offreg = 0;
+ loc_value_size = TARGET_FT_LONG_SIZE (current_objfile);
+ while (loc < end)
+ {
+ loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED,
+ current_objfile);
+ loc += SIZEOF_LOC_ATOM_CODE;
+ switch (loc_atom_code)
+ {
+ case 0:
+ /* error */
+ loc = end;
+ break;
+ case OP_REG:
+ /* push register (number) */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_UNSIGNED, current_objfile);
+ loc += loc_value_size;
+ isreg = 1;
+ break;
+ case OP_BASEREG:
+ /* push value of register (number) */
+ /* Actually, we compute the value as if register has 0, so the
+ value ends up being the offset from that register. */
+ offreg = 1;
+ basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
+ current_objfile);
+ loc += loc_value_size;
+ stack[++stacki] = 0;
+ break;
+ case OP_ADDR:
+ /* push address (relocated address) */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_UNSIGNED, current_objfile);
+ loc += loc_value_size;
+ break;
+ case OP_CONST:
+ /* push constant (number) FIXME: signed or unsigned! */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_SIGNED, current_objfile);
+ loc += loc_value_size;
+ break;
+ case OP_DEREF2:
+ /* pop, deref and push 2 bytes (as a long) */
+ complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]);
+ break;
+ case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */
+ complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]);
+ break;
+ case OP_ADD: /* pop top 2 items, add, push result */
+ stack[stacki - 1] += stack[stacki];
+ stacki--;
+ break;
+ }
+ }
+ return (stack[stacki]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_ofile_symtab -- build a full symtab entry from chunk of DIE's
+
+SYNOPSIS
+
+ static void read_ofile_symtab (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ When expanding a partial symbol table entry to a full symbol table
+ entry, this is the function that gets called to read in the symbols
+ for the compilation unit. A pointer to the newly constructed symtab,
+ which is now the new first one on the objfile's symtab list, is
+ stashed in the partial symbol table entry.
+ */
+
+static void
+read_ofile_symtab (pst)
+ struct partial_symtab *pst;
+{
+ struct cleanup *back_to;
+ unsigned long lnsize;
+ file_ptr foffset;
+ bfd *abfd;
+ char lnsizedata[SIZEOF_LINETBL_LENGTH];
+
+ abfd = pst -> objfile -> obfd;
+ current_objfile = pst -> objfile;
+
+ /* Allocate a buffer for the entire chunk of DIE's for this compilation
+ unit, seek to the location in the file, and read in all the DIE's. */
+
+ diecount = 0;
+ dbsize = DBLENGTH (pst);
+ dbbase = xmalloc (dbsize);
+ dbroff = DBROFF(pst);
+ foffset = DBFOFF(pst) + dbroff;
+ base_section_offsets = pst->section_offsets;
+ baseaddr = ANOFFSET (pst->section_offsets, 0);
+ if (bfd_seek (abfd, foffset, L_SET) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
+ {
+ free (dbbase);
+ error ("can't read DWARF data");
+ }
+ back_to = make_cleanup (free, dbbase);
+
+ /* If there is a line number table associated with this compilation unit
+ then read the size of this fragment in bytes, from the fragment itself.
+ Allocate a buffer for the fragment and read it in for future
+ processing. */
+
+ lnbase = NULL;
+ if (LNFOFF (pst))
+ {
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
+ (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) !=
+ sizeof (lnsizedata)))
+ {
+ error ("can't read DWARF line number table size");
+ }
+ lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH,
+ GET_UNSIGNED, pst -> objfile);
+ lnbase = xmalloc (lnsize);
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
+ (bfd_read (lnbase, lnsize, 1, abfd) != lnsize))
+ {
+ free (lnbase);
+ error ("can't read DWARF line numbers");
+ }
+ make_cleanup (free, lnbase);
+ }
+
+ process_dies (dbbase, dbbase + dbsize, pst -> objfile);
+ do_cleanups (back_to);
+ current_objfile = NULL;
+ pst -> symtab = pst -> objfile -> symtabs;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ psymtab_to_symtab_1 -- do grunt work for building a full symtab entry
+
+SYNOPSIS
+
+ static void psymtab_to_symtab_1 (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ Called once for each partial symbol table entry that needs to be
+ expanded into a full symbol table entry.
+
+*/
+
+static void
+psymtab_to_symtab_1 (pst)
+ struct partial_symtab *pst;
+{
+ int i;
+ struct cleanup *old_chain;
+
+ if (pst != NULL)
+ {
+ if (pst->readin)
+ {
+ warning ("psymtab for %s already read in. Shouldn't happen.",
+ pst -> filename);
+ }
+ else
+ {
+ /* Read in all partial symtabs on which this one is dependent */
+ for (i = 0; i < pst -> number_of_dependencies; i++)
+ {
+ if (!pst -> dependencies[i] -> readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst -> dependencies[i] -> filename);
+ wrap_here ("");
+ fflush (stdout); /* Flush output */
+ }
+ psymtab_to_symtab_1 (pst -> dependencies[i]);
+ }
+ }
+ if (DBLENGTH (pst)) /* Otherwise it's a dummy */
+ {
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+ read_ofile_symtab (pst);
+ if (info_verbose)
+ {
+ printf_filtered ("%d DIE's, sorting...", diecount);
+ wrap_here ("");
+ fflush (stdout);
+ }
+ sort_symtab_syms (pst -> symtab);
+ do_cleanups (old_chain);
+ }
+ pst -> readin = 1;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_psymtab_to_symtab -- build a full symtab entry from partial one
+
+SYNOPSIS
+
+ static void dwarf_psymtab_to_symtab (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ This is the DWARF support entry point for building a full symbol
+ table entry from a partial symbol table entry. We are passed a
+ pointer to the partial symbol table entry that needs to be expanded.
+
+*/
+
+static void
+dwarf_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+
+ if (pst != NULL)
+ {
+ if (pst -> readin)
+ {
+ warning ("psymtab for %s already read in. Shouldn't happen.",
+ pst -> filename);
+ }
+ else
+ {
+ if (DBLENGTH (pst) || pst -> number_of_dependencies)
+ {
+ /* Print the message now, before starting serious work, to avoid
+ disconcerting pauses. */
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...",
+ pst -> filename);
+ fflush (stdout);
+ }
+
+ psymtab_to_symtab_1 (pst);
+
+#if 0 /* FIXME: Check to see what dbxread is doing here and see if
+ we need to do an equivalent or is this something peculiar to
+ stabs/a.out format.
+ Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in.
+ */
+ scan_file_globals (pst -> objfile);
+#endif
+
+ /* Finish up the verbose info message. */
+ if (info_verbose)
+ {
+ printf_filtered ("done.\n");
+ fflush (stdout);
+ }
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ init_psymbol_list -- initialize storage for partial symbols
+
+SYNOPSIS
+
+ static void init_psymbol_list (struct objfile *objfile, int total_symbols)
+
+DESCRIPTION
+
+ Initializes storage for all of the partial symbols that will be
+ created by dwarf_build_psymtabs and subsidiaries.
+ */
+
+static void
+init_psymbol_list (objfile, total_symbols)
+ struct objfile *objfile;
+ int total_symbols;
+{
+ /* Free any previously allocated psymbol lists. */
+
+ if (objfile -> global_psymbols.list)
+ {
+ mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+ }
+ if (objfile -> static_psymbols.list)
+ {
+ mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+ }
+
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+
+ objfile -> global_psymbols.size = total_symbols / 10;
+ objfile -> static_psymbols.size = total_symbols / 10;
+ objfile -> global_psymbols.next =
+ objfile -> global_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> global_psymbols.size
+ * sizeof (struct partial_symbol));
+ objfile -> static_psymbols.next =
+ objfile -> static_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> static_psymbols.size
+ * sizeof (struct partial_symbol));
+}
+
+/*
+
+LOCAL FUNCTION
+
+ add_enum_psymbol -- add enumeration members to partial symbol table
+
+DESCRIPTION
+
+ Given pointer to a DIE that is known to be for an enumeration,
+ extract the symbolic names of the enumeration members and add
+ partial symbols for them.
+*/
+
+static void
+add_enum_psymbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ char *scan;
+ char *listend;
+ unsigned short blocksz;
+ int nbytes;
+
+ if ((scan = dip -> at_element_list) != NULL)
+ {
+ if (dip -> short_element_list)
+ {
+ nbytes = attribute_size (AT_short_element_list);
+ }
+ else
+ {
+ nbytes = attribute_size (AT_element_list);
+ }
+ blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
+ scan += nbytes;
+ listend = scan + blocksz;
+ while (scan < listend)
+ {
+ scan += TARGET_FT_LONG_SIZE (objfile);
+ ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
+ objfile -> static_psymbols, 0, cu_language,
+ objfile);
+ scan += strlen (scan) + 1;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ add_partial_symbol -- add symbol to partial symbol table
+
+DESCRIPTION
+
+ Given a DIE, if it is one of the types that we want to
+ add to a partial symbol table, finish filling in the die info
+ and then add a partial symbol table entry for it.
+
+NOTES
+
+ The caller must ensure that the DIE has a valid name attribute.
+*/
+
+static void
+add_partial_symbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ switch (dip -> die_tag)
+ {
+ case TAG_global_subroutine:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile -> global_psymbols,
+ dip -> at_low_pc, cu_language, objfile);
+ break;
+ case TAG_global_variable:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile -> global_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_subroutine:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile -> static_psymbols,
+ dip -> at_low_pc, cu_language, objfile);
+ break;
+ case TAG_local_variable:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_typedef:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ case TAG_enumeration_type:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ if (cu_language == language_cplus)
+ {
+ /* For C++, these implicitly act as typedefs as well. */
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ }
+ break;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ scan_partial_symbols -- scan DIE's within a single compilation unit
+
+DESCRIPTION
+
+ Process the DIE's within a single compilation unit, looking for
+ interesting DIE's that contribute to the partial symbol table entry
+ for this compilation unit.
+
+NOTES
+
+ There are some DIE's that may appear both at file scope and within
+ the scope of a function. We are only interested in the ones at file
+ scope, and the only way to tell them apart is to keep track of the
+ scope. For example, consider the test case:
+
+ static int i;
+ main () { int j; }
+
+ for which the relevant DWARF segment has the structure:
+
+ 0x51:
+ 0x23 global subrtn sibling 0x9b
+ name main
+ fund_type FT_integer
+ low_pc 0x800004cc
+ high_pc 0x800004d4
+
+ 0x74:
+ 0x23 local var sibling 0x97
+ name j
+ fund_type FT_integer
+ location OP_BASEREG 0xe
+ OP_CONST 0xfffffffc
+ OP_ADD
+ 0x97:
+ 0x4
+
+ 0x9b:
+ 0x1d local var sibling 0xb8
+ name i
+ fund_type FT_integer
+ location OP_ADDR 0x800025dc
+
+ 0xb8:
+ 0x4
+
+ We want to include the symbol 'i' in the partial symbol table, but
+ not the symbol 'j'. In essence, we want to skip all the dies within
+ the scope of a TAG_global_subroutine DIE.
+
+ Don't attempt to add anonymous structures or unions since they have
+ no name. Anonymous enumerations however are processed, because we
+ want to extract their member names (the check for a tag name is
+ done later).
+
+ Also, for variables and subroutines, check that this is the place
+ where the actual definition occurs, rather than just a reference
+ to an external.
+ */
+
+static void
+scan_partial_symbols (thisdie, enddie, objfile)
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ char *temp;
+ struct dieinfo di;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ /* To avoid getting complete die information for every die, we
+ only do it (below) for the cases we are interested in. */
+ switch (di.die_tag)
+ {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ completedieinfo (&di, objfile);
+ if (di.at_name && (di.has_at_low_pc || di.at_location))
+ {
+ add_partial_symbol (&di, objfile);
+ /* If there is a sibling attribute, adjust the nextdie
+ pointer to skip the entire scope of the subroutine.
+ Apply some sanity checking to make sure we don't
+ overrun or underrun the range of remaining DIE's */
+ if (di.at_sibling != 0)
+ {
+ temp = dbbase + di.at_sibling - dbroff;
+ if ((temp < thisdie) || (temp >= enddie))
+ {
+ complain (&bad_die_ref, DIE_ID, DIE_NAME,
+ di.at_sibling);
+ }
+ else
+ {
+ nextdie = temp;
+ }
+ }
+ }
+ break;
+ case TAG_global_variable:
+ case TAG_local_variable:
+ completedieinfo (&di, objfile);
+ if (di.at_name && (di.has_at_low_pc || di.at_location))
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ break;
+ case TAG_typedef:
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ completedieinfo (&di, objfile);
+ if (di.at_name)
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ break;
+ case TAG_enumeration_type:
+ completedieinfo (&di, objfile);
+ if (di.at_name)
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ add_enum_psymbol (&di, objfile);
+ break;
+ }
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ scan_compilation_units -- build a psymtab entry for each compilation
+
+DESCRIPTION
+
+ This is the top level dwarf parsing routine for building partial
+ symbol tables.
+
+ It scans from the beginning of the DWARF table looking for the first
+ TAG_compile_unit DIE, and then follows the sibling chain to locate
+ each additional TAG_compile_unit DIE.
+
+ For each TAG_compile_unit DIE it creates a partial symtab structure,
+ calls a subordinate routine to collect all the compilation unit's
+ global DIE's, file scope DIEs, typedef DIEs, etc, and then links the
+ new partial symtab structure into the partial symbol table. It also
+ records the appropriate information in the partial symbol table entry
+ to allow the chunk of DIE's and line number table for this compilation
+ unit to be located and re-read later, to generate a complete symbol
+ table entry for the compilation unit.
+
+ Thus it effectively partitions up a chunk of DIE's for multiple
+ compilation units into smaller DIE chunks and line number tables,
+ and associates them with a partial symbol table entry.
+
+NOTES
+
+ If any compilation unit has no line number table associated with
+ it for some reason (a missing at_stmt_list attribute, rather than
+ just one with a value of zero, which is valid) then we ensure that
+ the recorded file offset is zero so that the routine which later
+ reads line number table fragments knows that there is no fragment
+ to read.
+
+RETURNS
+
+ Returns no value.
+
+ */
+
+static void
+scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile)
+ char *thisdie;
+ char *enddie;
+ file_ptr dbfoff;
+ file_ptr lnoffset;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ struct dieinfo di;
+ struct partial_symtab *pst;
+ int culength;
+ int curoff;
+ file_ptr curlnoffset;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (di.die_tag != TAG_compile_unit)
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ else
+ {
+ completedieinfo (&di, objfile);
+ set_cu_language (&di);
+ if (di.at_sibling != 0)
+ {
+ nextdie = dbbase + di.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ curoff = thisdie - dbbase;
+ culength = nextdie - thisdie;
+ curlnoffset = di.has_at_stmt_list ? lnoffset + di.at_stmt_list : 0;
+
+ /* First allocate a new partial symbol table structure */
+
+ pst = start_psymtab_common (objfile, base_section_offsets,
+ di.at_name, di.at_low_pc,
+ objfile -> global_psymbols.next,
+ objfile -> static_psymbols.next);
+
+ pst -> texthigh = di.at_high_pc;
+ pst -> read_symtab_private = (char *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct dwfinfo));
+ DBFOFF (pst) = dbfoff;
+ DBROFF (pst) = curoff;
+ DBLENGTH (pst) = culength;
+ LNFOFF (pst) = curlnoffset;
+ pst -> read_symtab = dwarf_psymtab_to_symtab;
+
+ /* Now look for partial symbols */
+
+ scan_partial_symbols (thisdie + di.die_length, nextdie, objfile);
+
+ pst -> n_global_syms = objfile -> global_psymbols.next -
+ (objfile -> global_psymbols.list + pst -> globals_offset);
+ pst -> n_static_syms = objfile -> static_psymbols.next -
+ (objfile -> static_psymbols.list + pst -> statics_offset);
+ sort_pst_symbols (pst);
+ /* If there is already a psymtab or symtab for a file of this name,
+ remove it. (If there is a symtab, more drastic things also
+ happen.) This happens in VxWorks. */
+ free_named_symtabs (pst -> filename);
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ new_symbol -- make a symbol table entry for a new symbol
+
+SYNOPSIS
+
+ static struct symbol *new_symbol (struct dieinfo *dip,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a DWARF information entry, figure out if we need
+ to make a symbol table entry for it, and if so, create a new entry
+ and return a pointer to it.
+ */
+
+static struct symbol *
+new_symbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ struct symbol *sym = NULL;
+
+ if (dip -> at_name != NULL)
+ {
+ sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
+ /* default assumptions */
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_TYPE (sym) = decode_die_type (dip);
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_LANGUAGE (sym) = cu_language;
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack);
+ switch (dip -> die_tag)
+ {
+ case TAG_label:
+ SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ break;
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ if (dip -> die_tag == TAG_global_subroutine)
+ {
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ add_symbol_to_list (sym, list_in_scope);
+ }
+ break;
+ case TAG_global_variable:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ add_symbol_to_list (sym, &global_symbols);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) += baseaddr;
+ }
+ break;
+ case TAG_local_variable:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ add_symbol_to_list (sym, list_in_scope);
+ if (isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ }
+ else if (offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG;
+ SYMBOL_BASEREG (sym) = basereg;
+ }
+ else
+ {
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) += baseaddr;
+ }
+ }
+ break;
+ case TAG_formal_parameter:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ }
+ add_symbol_to_list (sym, list_in_scope);
+ if (isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ }
+ else if (offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
+ SYMBOL_BASEREG (sym) = basereg;
+ }
+ else
+ {
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ }
+ break;
+ case TAG_unspecified_parameters:
+ /* From varargs functions; gdb doesn't seem to have any interest in
+ this information, so just ignore it for now. (FIXME?) */
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ case TAG_enumeration_type:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ break;
+ case TAG_typedef:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ break;
+ default:
+ /* Not a tag we recognize. Hopefully we aren't processing trash
+ data, but since we must specifically ignore things we don't
+ recognize, there is nothing else we should do at this point. */
+ break;
+ }
+ }
+ return (sym);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ synthesize_typedef -- make a symbol table entry for a "fake" typedef
+
+SYNOPSIS
+
+ static void synthesize_typedef (struct dieinfo *dip,
+ struct objfile *objfile,
+ struct type *type);
+
+DESCRIPTION
+
+ Given a pointer to a DWARF information entry, synthesize a typedef
+ for the name in the DIE, using the specified type.
+
+ This is used for C++ class, structs, unions, and enumerations to
+ set up the tag name as a type.
+
+ */
+
+static void
+synthesize_typedef (dip, objfile, type)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+ struct type *type;
+{
+ struct symbol *sym = NULL;
+
+ if (dip -> at_name != NULL)
+ {
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_mod_fund_type -- decode a modified fundamental type
+
+SYNOPSIS
+
+ static struct type *decode_mod_fund_type (char *typedata)
+
+DESCRIPTION
+
+ Decode a block of data containing a modified fundamental
+ type specification. TYPEDATA is a pointer to the block,
+ which starts with a length containing the size of the rest
+ of the block. At the end of the block is a fundmental type
+ code value that gives the fundamental type. Everything
+ in between are type modifiers.
+
+ We simply compute the number of modifiers and call the general
+ function decode_modified_type to do the actual work.
+*/
+
+static struct type *
+decode_mod_fund_type (typedata)
+ char *typedata;
+{
+ struct type *typep = NULL;
+ unsigned short modcount;
+ int nbytes;
+
+ /* Get the total size of the block, exclusive of the size itself */
+
+ nbytes = attribute_size (AT_mod_fund_type);
+ modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
+ typedata += nbytes;
+
+ /* Deduct the size of the fundamental type bytes at the end of the block. */
+
+ modcount -= attribute_size (AT_fund_type);
+
+ /* Now do the actual decoding */
+
+ typep = decode_modified_type (typedata, modcount, AT_mod_fund_type);
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_mod_u_d_type -- decode a modified user defined type
+
+SYNOPSIS
+
+ static struct type *decode_mod_u_d_type (char *typedata)
+
+DESCRIPTION
+
+ Decode a block of data containing a modified user defined
+ type specification. TYPEDATA is a pointer to the block,
+ which consists of a two byte length, containing the size
+ of the rest of the block. At the end of the block is a
+ four byte value that gives a reference to a user defined type.
+ Everything in between are type modifiers.
+
+ We simply compute the number of modifiers and call the general
+ function decode_modified_type to do the actual work.
+*/
+
+static struct type *
+decode_mod_u_d_type (typedata)
+ char *typedata;
+{
+ struct type *typep = NULL;
+ unsigned short modcount;
+ int nbytes;
+
+ /* Get the total size of the block, exclusive of the size itself */
+
+ nbytes = attribute_size (AT_mod_u_d_type);
+ modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
+ typedata += nbytes;
+
+ /* Deduct the size of the reference type bytes at the end of the block. */
+
+ modcount -= attribute_size (AT_user_def_type);
+
+ /* Now do the actual decoding */
+
+ typep = decode_modified_type (typedata, modcount, AT_mod_u_d_type);
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_modified_type -- decode modified user or fundamental type
+
+SYNOPSIS
+
+ static struct type *decode_modified_type (char *modifiers,
+ unsigned short modcount, int mtype)
+
+DESCRIPTION
+
+ Decode a modified type, either a modified fundamental type or
+ a modified user defined type. MODIFIERS is a pointer to the
+ block of bytes that define MODCOUNT modifiers. Immediately
+ following the last modifier is a short containing the fundamental
+ type or a long containing the reference to the user defined
+ type. Which one is determined by MTYPE, which is either
+ AT_mod_fund_type or AT_mod_u_d_type to indicate what modified
+ type we are generating.
+
+ We call ourself recursively to generate each modified type,`
+ until MODCOUNT reaches zero, at which point we have consumed
+ all the modifiers and generate either the fundamental type or
+ user defined type. When the recursion unwinds, each modifier
+ is applied in turn to generate the full modified type.
+
+NOTES
+
+ If we find a modifier that we don't recognize, and it is not one
+ of those reserved for application specific use, then we issue a
+ warning and simply ignore the modifier.
+
+BUGS
+
+ We currently ignore MOD_const and MOD_volatile. (FIXME)
+
+ */
+
+static struct type *
+decode_modified_type (modifiers, modcount, mtype)
+ char *modifiers;
+ unsigned int modcount;
+ int mtype;
+{
+ struct type *typep = NULL;
+ unsigned short fundtype;
+ DIE_REF die_ref;
+ char modifier;
+ int nbytes;
+
+ if (modcount == 0)
+ {
+ switch (mtype)
+ {
+ case AT_mod_fund_type:
+ nbytes = attribute_size (AT_fund_type);
+ fundtype = target_to_host (modifiers, nbytes, GET_UNSIGNED,
+ current_objfile);
+ typep = decode_fund_type (fundtype);
+ break;
+ case AT_mod_u_d_type:
+ nbytes = attribute_size (AT_user_def_type);
+ die_ref = target_to_host (modifiers, nbytes, GET_UNSIGNED,
+ current_objfile);
+ if ((typep = lookup_utype (die_ref)) == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ default:
+ complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+ }
+ }
+ else
+ {
+ modifier = *modifiers++;
+ typep = decode_modified_type (modifiers, --modcount, mtype);
+ switch (modifier)
+ {
+ case MOD_pointer_to:
+ typep = lookup_pointer_type (typep);
+ break;
+ case MOD_reference_to:
+ typep = lookup_reference_type (typep);
+ break;
+ case MOD_const:
+ complain (&const_ignored, DIE_ID, DIE_NAME); /* FIXME */
+ break;
+ case MOD_volatile:
+ complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */
+ break;
+ default:
+ if (!(MOD_lo_user <= (unsigned char) modifier
+ && (unsigned char) modifier <= MOD_hi_user))
+ {
+ complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier);
+ }
+ break;
+ }
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_fund_type -- translate basic DWARF type to gdb base type
+
+DESCRIPTION
+
+ Given an integer that is one of the fundamental DWARF types,
+ translate it to one of the basic internal gdb types and return
+ a pointer to the appropriate gdb type (a "struct type *").
+
+NOTES
+
+ For robustness, if we are asked to translate a fundamental
+ type that we are unprepared to deal with, we return int so
+ callers can always depend upon a valid type being returned,
+ and so gdb may at least do something reasonable by default.
+ If the type is not in the range of those types defined as
+ application specific types, we also issue a warning.
+*/
+
+static struct type *
+decode_fund_type (fundtype)
+ unsigned int fundtype;
+{
+ struct type *typep = NULL;
+
+ switch (fundtype)
+ {
+
+ case FT_void:
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
+ break;
+
+ case FT_boolean: /* Was FT_set in AT&T version */
+ typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN);
+ break;
+
+ case FT_pointer: /* (void *) */
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
+ typep = lookup_pointer_type (typep);
+ break;
+
+ case FT_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_CHAR);
+ break;
+
+ case FT_signed_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+ break;
+
+ case FT_unsigned_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+ break;
+
+ case FT_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_SHORT);
+ break;
+
+ case FT_signed_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+ break;
+
+ case FT_unsigned_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+ break;
+
+ case FT_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+
+ case FT_signed_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+ break;
+
+ case FT_unsigned_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+ break;
+
+ case FT_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG);
+ break;
+
+ case FT_signed_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG);
+ break;
+
+ case FT_unsigned_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ break;
+
+ case FT_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG);
+ break;
+
+ case FT_signed_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
+ break;
+
+ case FT_unsigned_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
+ break;
+
+ case FT_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_FLOAT);
+ break;
+
+ case FT_dbl_prec_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+ break;
+
+ case FT_ext_prec_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
+ break;
+
+ case FT_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX);
+ break;
+
+ case FT_dbl_prec_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
+ break;
+
+ case FT_ext_prec_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
+ break;
+
+ }
+
+ if (typep == NULL)
+ {
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+ {
+ complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype);
+ }
+ }
+
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ create_name -- allocate a fresh copy of a string on an obstack
+
+DESCRIPTION
+
+ Given a pointer to a string and a pointer to an obstack, allocates
+ a fresh copy of the string on the specified obstack.
+
+*/
+
+static char *
+create_name (name, obstackp)
+ char *name;
+ struct obstack *obstackp;
+{
+ int length;
+ char *newname;
+
+ length = strlen (name) + 1;
+ newname = (char *) obstack_alloc (obstackp, length);
+ strcpy (newname, name);
+ return (newname);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ basicdieinfo -- extract the minimal die info from raw die data
+
+SYNOPSIS
+
+ void basicdieinfo (char *diep, struct dieinfo *dip,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to raw DIE data, and a pointer to an instance of a
+ die info structure, this function extracts the basic information
+ from the DIE data required to continue processing this DIE, along
+ with some bookkeeping information about the DIE.
+
+ The information we absolutely must have includes the DIE tag,
+ and the DIE length. If we need the sibling reference, then we
+ will have to call completedieinfo() to process all the remaining
+ DIE information.
+
+ Note that since there is no guarantee that the data is properly
+ aligned in memory for the type of access required (indirection
+ through anything other than a char pointer), and there is no
+ guarantee that it is in the same byte order as the gdb host,
+ we call a function which deals with both alignment and byte
+ swapping issues. Possibly inefficient, but quite portable.
+
+ We also take care of some other basic things at this point, such
+ as ensuring that the instance of the die info structure starts
+ out completely zero'd and that curdie is initialized for use
+ in error reporting if we have a problem with the current die.
+
+NOTES
+
+ All DIE's must have at least a valid length, thus the minimum
+ DIE size is SIZEOF_DIE_LENGTH. In order to have a valid tag, the
+ DIE size must be at least SIZEOF_DIE_TAG larger, otherwise they
+ are forced to be TAG_padding DIES.
+
+ Padding DIES must be at least SIZEOF_DIE_LENGTH in length, implying
+ that if a padding DIE is used for alignment and the amount needed is
+ less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big
+ enough to align to the next alignment boundry.
+
+ We do some basic sanity checking here, such as verifying that the
+ length of the die would not cause it to overrun the recorded end of
+ the buffer holding the DIE info. If we find a DIE that is either
+ too small or too large, we force it's length to zero which should
+ cause the caller to take appropriate action.
+ */
+
+static void
+basicdieinfo (dip, diep, objfile)
+ struct dieinfo *dip;
+ char *diep;
+ struct objfile *objfile;
+{
+ curdie = dip;
+ memset (dip, 0, sizeof (struct dieinfo));
+ dip -> die = diep;
+ dip -> die_ref = dbroff + (diep - dbbase);
+ dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED,
+ objfile);
+ if ((dip -> die_length < SIZEOF_DIE_LENGTH) ||
+ ((diep + dip -> die_length) > (dbbase + dbsize)))
+ {
+ complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length);
+ dip -> die_length = 0;
+ }
+ else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG))
+ {
+ dip -> die_tag = TAG_padding;
+ }
+ else
+ {
+ diep += SIZEOF_DIE_LENGTH;
+ dip -> die_tag = target_to_host (diep, SIZEOF_DIE_TAG, GET_UNSIGNED,
+ objfile);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ completedieinfo -- finish reading the information for a given DIE
+
+SYNOPSIS
+
+ void completedieinfo (struct dieinfo *dip, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to an already partially initialized die info structure,
+ scan the raw DIE data and finish filling in the die info structure
+ from the various attributes found.
+
+ Note that since there is no guarantee that the data is properly
+ aligned in memory for the type of access required (indirection
+ through anything other than a char pointer), and there is no
+ guarantee that it is in the same byte order as the gdb host,
+ we call a function which deals with both alignment and byte
+ swapping issues. Possibly inefficient, but quite portable.
+
+NOTES
+
+ Each time we are called, we increment the diecount variable, which
+ keeps an approximate count of the number of dies processed for
+ each compilation unit. This information is presented to the user
+ if the info_verbose flag is set.
+
+ */
+
+static void
+completedieinfo (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ char *diep; /* Current pointer into raw DIE data */
+ char *end; /* Terminate DIE scan here */
+ unsigned short attr; /* Current attribute being scanned */
+ unsigned short form; /* Form of the attribute */
+ int nbytes; /* Size of next field to read */
+
+ diecount++;
+ diep = dip -> die;
+ end = diep + dip -> die_length;
+ diep += SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG;
+ while (diep < end)
+ {
+ attr = target_to_host (diep, SIZEOF_ATTRIBUTE, GET_UNSIGNED, objfile);
+ diep += SIZEOF_ATTRIBUTE;
+ if ((nbytes = attribute_size (attr)) == -1)
+ {
+ complain (&unknown_attribute_length, DIE_ID, DIE_NAME);
+ diep = end;
+ continue;
+ }
+ switch (attr)
+ {
+ case AT_fund_type:
+ dip -> at_fund_type = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_ordering:
+ dip -> at_ordering = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_bit_offset:
+ dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_sibling:
+ dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_stmt_list:
+ dip -> at_stmt_list = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> has_at_stmt_list = 1;
+ break;
+ case AT_low_pc:
+ dip -> at_low_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> at_low_pc += baseaddr;
+ dip -> has_at_low_pc = 1;
+ break;
+ case AT_high_pc:
+ dip -> at_high_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> at_high_pc += baseaddr;
+ break;
+ case AT_language:
+ dip -> at_language = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_user_def_type:
+ dip -> at_user_def_type = target_to_host (diep, nbytes,
+ GET_UNSIGNED, objfile);
+ break;
+ case AT_byte_size:
+ dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> has_at_byte_size = 1;
+ break;
+ case AT_bit_size:
+ dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_member:
+ dip -> at_member = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_discr:
+ dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_location:
+ dip -> at_location = diep;
+ break;
+ case AT_mod_fund_type:
+ dip -> at_mod_fund_type = diep;
+ break;
+ case AT_subscr_data:
+ dip -> at_subscr_data = diep;
+ break;
+ case AT_mod_u_d_type:
+ dip -> at_mod_u_d_type = diep;
+ break;
+ case AT_element_list:
+ dip -> at_element_list = diep;
+ dip -> short_element_list = 0;
+ break;
+ case AT_short_element_list:
+ dip -> at_element_list = diep;
+ dip -> short_element_list = 1;
+ break;
+ case AT_discr_value:
+ dip -> at_discr_value = diep;
+ break;
+ case AT_string_length:
+ dip -> at_string_length = diep;
+ break;
+ case AT_name:
+ dip -> at_name = diep;
+ break;
+ case AT_comp_dir:
+ /* For now, ignore any "hostname:" portion, since gdb doesn't
+ know how to deal with it. (FIXME). */
+ dip -> at_comp_dir = strrchr (diep, ':');
+ if (dip -> at_comp_dir != NULL)
+ {
+ dip -> at_comp_dir++;
+ }
+ else
+ {
+ dip -> at_comp_dir = diep;
+ }
+ break;
+ case AT_producer:
+ dip -> at_producer = diep;
+ break;
+ case AT_start_scope:
+ dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_stride_size:
+ dip -> at_stride_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_src_info:
+ dip -> at_src_info = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_prototyped:
+ dip -> at_prototyped = diep;
+ break;
+ default:
+ /* Found an attribute that we are unprepared to handle. However
+ it is specifically one of the design goals of DWARF that
+ consumers should ignore unknown attributes. As long as the
+ form is one that we recognize (so we know how to skip it),
+ we can just ignore the unknown attribute. */
+ break;
+ }
+ form = FORM_FROM_ATTR (attr);
+ switch (form)
+ {
+ case FORM_DATA2:
+ diep += 2;
+ break;
+ case FORM_DATA4:
+ case FORM_REF:
+ diep += 4;
+ break;
+ case FORM_DATA8:
+ diep += 8;
+ break;
+ case FORM_ADDR:
+ diep += TARGET_FT_POINTER_SIZE (objfile);
+ break;
+ case FORM_BLOCK2:
+ diep += 2 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
+ break;
+ case FORM_BLOCK4:
+ diep += 4 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
+ break;
+ case FORM_STRING:
+ diep += strlen (diep) + 1;
+ break;
+ default:
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
+ diep = end;
+ break;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ target_to_host -- swap in target data to host
+
+SYNOPSIS
+
+ target_to_host (char *from, int nbytes, int signextend,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given pointer to data in target format in FROM, a byte count for
+ the size of the data in NBYTES, a flag indicating whether or not
+ the data is signed in SIGNEXTEND, and a pointer to the current
+ objfile in OBJFILE, convert the data to host format and return
+ the converted value.
+
+NOTES
+
+ FIXME: If we read data that is known to be signed, and expect to
+ use it as signed data, then we need to explicitly sign extend the
+ result until the bfd library is able to do this for us.
+
+ */
+
+static unsigned long
+target_to_host (from, nbytes, signextend, objfile)
+ char *from;
+ int nbytes;
+ int signextend; /* FIXME: Unused */
+ struct objfile *objfile;
+{
+ unsigned long rtnval;
+
+ switch (nbytes)
+ {
+ case 8:
+ rtnval = bfd_get_64 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 4:
+ rtnval = bfd_get_32 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 2:
+ rtnval = bfd_get_16 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 1:
+ rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ default:
+ complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes);
+ rtnval = 0;
+ break;
+ }
+ return (rtnval);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ attribute_size -- compute size of data for a DWARF attribute
+
+SYNOPSIS
+
+ static int attribute_size (unsigned int attr)
+
+DESCRIPTION
+
+ Given a DWARF attribute in ATTR, compute the size of the first
+ piece of data associated with this attribute and return that
+ size.
+
+ Returns -1 for unrecognized attributes.
+
+ */
+
+static int
+attribute_size (attr)
+ unsigned int attr;
+{
+ int nbytes; /* Size of next data for this attribute */
+ unsigned short form; /* Form of the attribute */
+
+ form = FORM_FROM_ATTR (attr);
+ switch (form)
+ {
+ case FORM_STRING: /* A variable length field is next */
+ nbytes = 0;
+ break;
+ case FORM_DATA2: /* Next 2 byte field is the data itself */
+ case FORM_BLOCK2: /* Next 2 byte field is a block length */
+ nbytes = 2;
+ break;
+ case FORM_DATA4: /* Next 4 byte field is the data itself */
+ case FORM_BLOCK4: /* Next 4 byte field is a block length */
+ case FORM_REF: /* Next 4 byte field is a DIE offset */
+ nbytes = 4;
+ break;
+ case FORM_DATA8: /* Next 8 byte field is the data itself */
+ nbytes = 8;
+ break;
+ case FORM_ADDR: /* Next field size is target sizeof(void *) */
+ nbytes = TARGET_FT_POINTER_SIZE (objfile);
+ break;
+ default:
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
+ nbytes = -1;
+ break;
+ }
+ return (nbytes);
+}
diff --git a/gnu/usr.bin/gdb/gdb/elf/common.h b/gnu/usr.bin/gdb/gdb/elf/common.h
new file mode 100644
index 000000000000..cd708f1489cf
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/common.h
@@ -0,0 +1,216 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that are common to both the internal and external representations.
+ For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory)
+ and external (in-file) representations. */
+
+
+/* Fields in e_ident[] */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7F /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+#define EI_CLASS 4 /* File class */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+
+#define EI_DATA 5 /* Data encoding */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
+#define EI_VERSION 6 /* File version */
+
+#define EI_PAD 7 /* Start of padding bytes */
+
+
+/* Values for e_type, which identifies the object file type */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_LOPROC 0xFF00 /* Processor-specific */
+#define ET_HIPROC 0xFFFF /* Processor-specific */
+
+/* Values for e_machine, which identifies the architecture */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 */
+#define EM_HPPA 9 /* HP PA-RISC */
+
+
+/* Values for e_version */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+
+/* Values for program header, p_type field */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved, unspecified semantics */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_LOPROC 0x70000000 /* Processor-specific */
+#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */
+
+/* Program segment permissions, in program header p_flags field */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */
+
+/* Values for section header, sh_type field */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program specific (private) data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
+#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* A symbol hash table */
+#define SHT_DYNAMIC 6 /* Information for dynamic linking */
+#define SHT_NOTE 7 /* Information that marks file */
+#define SHT_NOBITS 8 /* Section occupies no space in file */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved, unspecified semantics */
+#define SHT_DYNSYM 11 /* Dynamic linking symbol table */
+#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */
+#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */
+#define SHT_LOUSER 0x80000000 /* Application-specific semantics */
+#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */
+
+/* Values for section header, sh_flags field */
+
+#define SHF_WRITE (1 << 0) /* Writable data during execution */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */
+#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */
+
+/* Values of note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+
+/* Values of note segment descriptor types for object files. */
+/* (Only for hppa right now. Should this be moved elsewhere?) */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+/* These three macros disassemble and assemble a symbol table st_info field,
+ which contains the symbol binding and symbol type. The STB_ and STT_
+ defines identify the binding and type. */
+
+#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xF)
+#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF))
+
+#define STN_UNDEF 0 /* undefined symbol index */
+
+#define STB_LOCAL 0 /* Symbol not visible outside obj */
+#define STB_GLOBAL 1 /* Symbol visible outside obj */
+#define STB_WEAK 2 /* Like globals, lower precedence */
+#define STB_LOPROC 13 /* Application-specific semantics */
+#define STB_HIPROC 15 /* Application-specific semantics */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol gives a file name */
+#define STT_LOPROC 13 /* Application-specific semantics */
+#define STT_HIPROC 15 /* Application-specific semantics */
+
+/* Special section indices, which may show up in st_shndx fields, among
+ other places. */
+
+#define SHN_UNDEF 0 /* Undefined section reference */
+#define SHN_LORESERV 0xFF00 /* Begin range of reserved indices */
+#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */
+#define SHN_HIPROC 0xFF1F /* End range of appl-specific */
+#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
+#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */
+
+/* relocation info handling macros */
+
+#define ELF32_R_SYM(i) ((i)>>8)
+#define ELF32_R_TYPE(i) ((unsigned char)(i))
+#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
+
+#define ELF64_R_SYM(i) ((i)>>32)
+#define ELF64_R_TYPE(i) ((Elf64_Word)(i))
+#define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+(Elf64_Xword)(t))
+
+/* Dynamic section tags */
+
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
diff --git a/gnu/usr.bin/gdb/gdb/elf/dwarf.h b/gnu/usr.bin/gdb/gdb/elf/dwarf.h
new file mode 100644
index 000000000000..bc9723ae04a0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/dwarf.h
@@ -0,0 +1,314 @@
+/* Declarations and definitions of codes relating to the DWARF symbolic
+ debugging information format.
+
+ Written by Ron Guilmette (rfg@ncd.com)
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the 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 CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is derived from the DWARF specification (a public document)
+ Revision 1.0.1 (April 8, 1992) developed by the UNIX International
+ Programming Languages Special Interest Group (UI/PLSIG) and distributed
+ by UNIX International. Copies of this specification are available from
+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+*/
+
+/* Tag names and codes. */
+
+enum dwarf_tag {
+ TAG_padding = 0x0000,
+ TAG_array_type = 0x0001,
+ TAG_class_type = 0x0002,
+ TAG_entry_point = 0x0003,
+ TAG_enumeration_type = 0x0004,
+ TAG_formal_parameter = 0x0005,
+ TAG_global_subroutine = 0x0006,
+ TAG_global_variable = 0x0007,
+ /* 0x0008 -- reserved */
+ /* 0x0009 -- reserved */
+ TAG_label = 0x000a,
+ TAG_lexical_block = 0x000b,
+ TAG_local_variable = 0x000c,
+ TAG_member = 0x000d,
+ /* 0x000e -- reserved */
+ TAG_pointer_type = 0x000f,
+ TAG_reference_type = 0x0010,
+ TAG_compile_unit = 0x0011,
+ TAG_string_type = 0x0012,
+ TAG_structure_type = 0x0013,
+ TAG_subroutine = 0x0014,
+ TAG_subroutine_type = 0x0015,
+ TAG_typedef = 0x0016,
+ TAG_union_type = 0x0017,
+ TAG_unspecified_parameters = 0x0018,
+ TAG_variant = 0x0019,
+ TAG_common_block = 0x001a,
+ TAG_common_inclusion = 0x001b,
+ TAG_inheritance = 0x001c,
+ TAG_inlined_subroutine = 0x001d,
+ TAG_module = 0x001e,
+ TAG_ptr_to_member_type = 0x001f,
+ TAG_set_type = 0x0020,
+ TAG_subrange_type = 0x0021,
+ TAG_with_stmt = 0x0022,
+
+ /* GNU extensions */
+
+ TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */
+ TAG_namelist = 0x8001, /* For Fortran 90 */
+ TAG_function_template = 0x8002, /* for C++ */
+ TAG_class_template = 0x8003 /* for C++ */
+};
+
+#define TAG_lo_user 0x8000 /* implementation-defined range start */
+#define TAG_hi_user 0xffff /* implementation-defined range end */
+#define TAG_source_file TAG_compile_unit /* for backward compatibility */
+
+/* Form names and codes. */
+
+enum dwarf_form {
+ FORM_ADDR = 0x1,
+ FORM_REF = 0x2,
+ FORM_BLOCK2 = 0x3,
+ FORM_BLOCK4 = 0x4,
+ FORM_DATA2 = 0x5,
+ FORM_DATA4 = 0x6,
+ FORM_DATA8 = 0x7,
+ FORM_STRING = 0x8
+};
+
+/* Attribute names and codes. */
+
+enum dwarf_attribute {
+ AT_sibling = (0x0010|FORM_REF),
+ AT_location = (0x0020|FORM_BLOCK2),
+ AT_name = (0x0030|FORM_STRING),
+ AT_fund_type = (0x0050|FORM_DATA2),
+ AT_mod_fund_type = (0x0060|FORM_BLOCK2),
+ AT_user_def_type = (0x0070|FORM_REF),
+ AT_mod_u_d_type = (0x0080|FORM_BLOCK2),
+ AT_ordering = (0x0090|FORM_DATA2),
+ AT_subscr_data = (0x00a0|FORM_BLOCK2),
+ AT_byte_size = (0x00b0|FORM_DATA4),
+ AT_bit_offset = (0x00c0|FORM_DATA2),
+ AT_bit_size = (0x00d0|FORM_DATA4),
+ /* (0x00e0|FORM_xxxx) -- reserved */
+ AT_element_list = (0x00f0|FORM_BLOCK4),
+ AT_stmt_list = (0x0100|FORM_DATA4),
+ AT_low_pc = (0x0110|FORM_ADDR),
+ AT_high_pc = (0x0120|FORM_ADDR),
+ AT_language = (0x0130|FORM_DATA4),
+ AT_member = (0x0140|FORM_REF),
+ AT_discr = (0x0150|FORM_REF),
+ AT_discr_value = (0x0160|FORM_BLOCK2),
+ /* (0x0170|FORM_xxxx) -- reserved */
+ /* (0x0180|FORM_xxxx) -- reserved */
+ AT_string_length = (0x0190|FORM_BLOCK2),
+ AT_common_reference = (0x01a0|FORM_REF),
+ AT_comp_dir = (0x01b0|FORM_STRING),
+ AT_const_value_string = (0x01c0|FORM_STRING),
+ AT_const_value_data2 = (0x01c0|FORM_DATA2),
+ AT_const_value_data4 = (0x01c0|FORM_DATA4),
+ AT_const_value_data8 = (0x01c0|FORM_DATA8),
+ AT_const_value_block2 = (0x01c0|FORM_BLOCK2),
+ AT_const_value_block4 = (0x01c0|FORM_BLOCK4),
+ AT_containing_type = (0x01d0|FORM_REF),
+ AT_default_value_addr = (0x01e0|FORM_ADDR),
+ AT_default_value_data2 = (0x01e0|FORM_DATA2),
+ AT_default_value_data4 = (0x01e0|FORM_DATA4),
+ AT_default_value_data8 = (0x01e0|FORM_DATA8),
+ AT_default_value_string = (0x01e0|FORM_STRING),
+ AT_friends = (0x01f0|FORM_BLOCK2),
+ AT_inline = (0x0200|FORM_STRING),
+ AT_is_optional = (0x0210|FORM_STRING),
+ AT_lower_bound_ref = (0x0220|FORM_REF),
+ AT_lower_bound_data2 = (0x0220|FORM_DATA2),
+ AT_lower_bound_data4 = (0x0220|FORM_DATA4),
+ AT_lower_bound_data8 = (0x0220|FORM_DATA8),
+ AT_private = (0x0240|FORM_STRING),
+ AT_producer = (0x0250|FORM_STRING),
+ AT_program = (0x0230|FORM_STRING),
+ AT_protected = (0x0260|FORM_STRING),
+ AT_prototyped = (0x0270|FORM_STRING),
+ AT_public = (0x0280|FORM_STRING),
+ AT_pure_virtual = (0x0290|FORM_STRING),
+ AT_return_addr = (0x02a0|FORM_BLOCK2),
+ AT_abstract_origin = (0x02b0|FORM_REF),
+ AT_start_scope = (0x02c0|FORM_DATA4),
+ AT_stride_size = (0x02e0|FORM_DATA4),
+ AT_upper_bound_ref = (0x02f0|FORM_REF),
+ AT_upper_bound_data2 = (0x02f0|FORM_DATA2),
+ AT_upper_bound_data4 = (0x02f0|FORM_DATA4),
+ AT_upper_bound_data8 = (0x02f0|FORM_DATA8),
+ AT_virtual = (0x0300|FORM_STRING),
+
+ /* GNU extensions. */
+
+ AT_sf_names = (0x8000|FORM_DATA4),
+ AT_src_info = (0x8010|FORM_DATA4),
+ AT_mac_info = (0x8020|FORM_DATA4),
+ AT_src_coords = (0x8030|FORM_DATA4),
+ AT_body_begin = (0x8040|FORM_ADDR),
+ AT_body_end = (0x8050|FORM_ADDR)
+};
+
+#define AT_lo_user 0x8000 /* implementation-defined range start */
+#define AT_hi_user 0xffff /* implementation-defined range end */
+
+/* Location atom names and codes. */
+
+enum dwarf_location_atom {
+ OP_REG = 0x01,
+ OP_BASEREG = 0x02,
+ OP_ADDR = 0x03,
+ OP_CONST = 0x04,
+ OP_DEREF2 = 0x05,
+ OP_DEREF4 = 0x06,
+ OP_ADD = 0x07
+};
+
+#define OP_LO_USER 0x80 /* implementation-defined range start */
+#define OP_HI_USER 0xff /* implementation-defined range end */
+
+/* Fundamental type names and codes. */
+
+enum dwarf_fundamental_type {
+ FT_char = 0x0001,
+ FT_signed_char = 0x0002,
+ FT_unsigned_char = 0x0003,
+ FT_short = 0x0004,
+ FT_signed_short = 0x0005,
+ FT_unsigned_short = 0x0006,
+ FT_integer = 0x0007,
+ FT_signed_integer = 0x0008,
+ FT_unsigned_integer = 0x0009,
+ FT_long = 0x000a,
+ FT_signed_long = 0x000b,
+ FT_unsigned_long = 0x000c,
+ FT_pointer = 0x000d, /* an alias for (void *) */
+ FT_float = 0x000e,
+ FT_dbl_prec_float = 0x000f,
+ FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */
+ FT_complex = 0x0011, /* breaks "classic" svr4 SDB */
+ FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */
+ /* 0x0013 -- reserved */
+ FT_void = 0x0014,
+ FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */
+ FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */
+ FT_label = 0x0017,
+
+ /* GNU extensions
+ The low order byte must indicate the size (in bytes) for the type.
+ All of these types will probably break "classic" svr4 SDB */
+
+ FT_long_long = 0x8008,
+ FT_signed_long_long = 0x8108,
+ FT_unsigned_long_long = 0x8208,
+
+ FT_int8 = 0x9001,
+ FT_signed_int8 = 0x9101,
+ FT_unsigned_int8 = 0x9201,
+ FT_int16 = 0x9302,
+ FT_signed_int16 = 0x9402,
+ FT_unsigned_int16 = 0x9502,
+ FT_int32 = 0x9604,
+ FT_signed_int32 = 0x9704,
+ FT_unsigned_int32 = 0x9804,
+ FT_int64 = 0x9908,
+ FT_signed_int64 = 0x9a08,
+ FT_unsigned_int64 = 0x9b08,
+
+ FT_real32 = 0xa004,
+ FT_real64 = 0xa108,
+ FT_real96 = 0xa20c,
+ FT_real128 = 0xa310
+};
+
+#define FT_lo_user 0x8000 /* implementation-defined range start */
+#define FT_hi_user 0xffff /* implementation defined range end */
+
+/* Type modifier names and codes. */
+
+enum dwarf_type_modifier {
+ MOD_pointer_to = 0x01,
+ MOD_reference_to = 0x02,
+ MOD_const = 0x03,
+ MOD_volatile = 0x04
+};
+
+#define MOD_lo_user 0x80 /* implementation-defined range start */
+#define MOD_hi_user 0xff /* implementation-defined range end */
+
+/* Array ordering names and codes. */
+
+enum dwarf_array_dim_ordering {
+ ORD_row_major = 0,
+ ORD_col_major = 1
+};
+
+/* Array subscript format names and codes. */
+
+enum dwarf_subscr_data_formats {
+ FMT_FT_C_C = 0x0,
+ FMT_FT_C_X = 0x1,
+ FMT_FT_X_C = 0x2,
+ FMT_FT_X_X = 0x3,
+ FMT_UT_C_C = 0x4,
+ FMT_UT_C_X = 0x5,
+ FMT_UT_X_C = 0x6,
+ FMT_UT_X_X = 0x7,
+ FMT_ET = 0x8
+};
+
+/* Derived from above for ease of use. */
+
+#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \
+ (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \
+ | ((_UB_CONST_P) ? 0 : 2) \
+ | ((_LB_CONST_P) ? 0 : 1))
+
+/* Source language names and codes. */
+
+enum dwarf_source_language {
+ LANG_C89 = 0x00000001,
+ LANG_C = 0x00000002,
+ LANG_ADA83 = 0x00000003,
+ LANG_C_PLUS_PLUS = 0x00000004,
+ LANG_COBOL74 = 0x00000005,
+ LANG_COBOL85 = 0x00000006,
+ LANG_FORTRAN77 = 0x00000007,
+ LANG_FORTRAN90 = 0x00000008,
+ LANG_PASCAL83 = 0x00000009,
+ LANG_MODULA2 = 0x0000000a,
+
+ /* GNU extensions */
+
+ LANG_CHILL = 0x00009af3 /* random value for GNU Chill */
+};
+
+#define LANG_lo_user 0x00008000 /* implementation-defined range start */
+#define LANG_hi_user 0x0000ffff /* implementation-defined range end */
+
+/* Names and codes for GNU "macinfo" extension. */
+
+enum dwarf_macinfo_record_type {
+ MACINFO_start = 's',
+ MACINFO_resume = 'r',
+ MACINFO_define = 'd',
+ MACINFO_undef = 'u'
+};
diff --git a/gnu/usr.bin/gdb/gdb/elf/external.h b/gnu/usr.bin/gdb/gdb/elf/external.h
new file mode 100644
index 000000000000..f2ab63e1ede4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/external.h
@@ -0,0 +1,190 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented externally by the BFD library.
+ I.E. it describes the in-file representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+/* The 64-bit stuff is kind of random. Perhaps someone will publish a
+ spec someday. */
+
+/* ELF Header (32-bit implementations) */
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[4]; /* Entry point virtual address */
+ unsigned char e_phoff[4]; /* Program header table file offset */
+ unsigned char e_shoff[4]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf32_External_Ehdr;
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[8]; /* Entry point virtual address */
+ unsigned char e_phoff[8]; /* Program header table file offset */
+ unsigned char e_shoff[8]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf64_External_Ehdr;
+
+/* Program header */
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_offset[4]; /* Segment file offset */
+ unsigned char p_vaddr[4]; /* Segment virtual address */
+ unsigned char p_paddr[4]; /* Segment physical address */
+ unsigned char p_filesz[4]; /* Segment size in file */
+ unsigned char p_memsz[4]; /* Segment size in memory */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_align[4]; /* Segment alignment, file & memory */
+} Elf32_External_Phdr;
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_offset[8]; /* Segment file offset */
+ unsigned char p_vaddr[8]; /* Segment virtual address */
+ unsigned char p_paddr[8]; /* Segment physical address */
+ unsigned char p_filesz[8]; /* Segment size in file */
+ unsigned char p_memsz[8]; /* Segment size in memory */
+ unsigned char p_align[8]; /* Segment alignment, file & memory */
+} Elf64_External_Phdr;
+
+/* Section header */
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[4]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[4]; /* Section virtual addr at execution */
+ unsigned char sh_offset[4]; /* Section file offset */
+ unsigned char sh_size[4]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[4]; /* Section alignment */
+ unsigned char sh_entsize[4]; /* Entry size if section holds table */
+} Elf32_External_Shdr;
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[8]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[8]; /* Section virtual addr at execution */
+ unsigned char sh_offset[8]; /* Section file offset */
+ unsigned char sh_size[8]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[8]; /* Section alignment */
+ unsigned char sh_entsize[8]; /* Entry size if section holds table */
+} Elf64_External_Shdr;
+
+/* Symbol table entry */
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_value[4]; /* Value of the symbol */
+ unsigned char st_size[4]; /* Associated symbol size */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+} Elf32_External_Sym;
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+ unsigned char st_value[8]; /* Value of the symbol */
+ unsigned char st_size[8]; /* Associated symbol size */
+} Elf64_External_Sym;
+
+/* Note segments */
+
+typedef struct {
+ unsigned char namesz[4]; /* Size of entry's owner string */
+ unsigned char descsz[4]; /* Size of the note descriptor */
+ unsigned char type[4]; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_External_Note;
+
+/* Relocation Entries */
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+} Elf32_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+ unsigned char r_addend[4]; /* Constant addend used to compute value */
+} Elf32_External_Rela;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+} Elf64_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+ unsigned char r_addend[8]; /* Constant addend used to compute value */
+} Elf64_External_Rela;
+
+/* dynamic section structure */
+
+typedef struct {
+ unsigned char d_tag[4]; /* entry tag value */
+ union {
+ unsigned char d_val[4];
+ unsigned char d_ptr[4];
+ } d_un;
+} Elf32_External_Dyn;
+
+typedef struct {
+ unsigned char d_tag[8]; /* entry tag value */
+ union {
+ unsigned char d_val[8];
+ unsigned char d_ptr[8];
+ } d_un;
+} Elf64_External_Dyn;
diff --git a/gnu/usr.bin/gdb/gdb/elf/internal.h b/gnu/usr.bin/gdb/gdb/elf/internal.h
new file mode 100644
index 000000000000..ae4bdada5ea9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/internal.h
@@ -0,0 +1,195 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented internally in the BFD library.
+ I.E. it describes the in-memory representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+/* Types used by various structures, functions, etc. */
+
+typedef unsigned long Elf32_Addr; /* Unsigned program address */
+typedef unsigned long Elf32_Off; /* Unsigned file offset */
+typedef long Elf32_Sword; /* Signed large integer */
+typedef unsigned long Elf32_Word; /* Unsigned large integer */
+typedef unsigned short Elf32_Half; /* Unsigned medium integer */
+typedef unsigned char Elf32_Char; /* Unsigned tiny integer */
+
+#ifdef HOST_64_BIT
+typedef unsigned HOST_64_BIT Elf64_Addr;
+typedef unsigned HOST_64_BIT Elf64_Off;
+typedef HOST_64_BIT Elf64_Sxword;
+typedef unsigned HOST_64_BIT Elf64_Xword;
+#endif
+typedef long Elf64_Sword;
+typedef unsigned long Elf64_Word;
+typedef unsigned short Elf64_Half;
+
+/* NOTE that these structures are not kept in the same order as they appear
+ in the object file. In some cases they've been reordered for more optimal
+ packing under various circumstances. */
+
+/* ELF Header */
+
+#define EI_NIDENT 16 /* Size of e_ident[] */
+
+typedef struct elf_internal_ehdr {
+ unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
+ bfd_vma e_entry; /* Entry point virtual address */
+ bfd_signed_vma e_phoff; /* Program header table file offset */
+ bfd_signed_vma e_shoff; /* Section header table file offset */
+ unsigned long e_version; /* Identifies object file version */
+ unsigned long e_flags; /* Processor-specific flags */
+ unsigned short e_type; /* Identifies object file type */
+ unsigned short e_machine; /* Specifies required architecture */
+ unsigned short e_ehsize; /* ELF header size in bytes */
+ unsigned short e_phentsize; /* Program header table entry size */
+ unsigned short e_phnum; /* Program header table entry count */
+ unsigned short e_shentsize; /* Section header table entry size */
+ unsigned short e_shnum; /* Section header table entry count */
+ unsigned short e_shstrndx; /* Section header string table index */
+} Elf_Internal_Ehdr;
+
+#define elf32_internal_ehdr elf_internal_ehdr
+#define Elf32_Internal_Ehdr Elf_Internal_Ehdr
+#define elf64_internal_ehdr elf_internal_ehdr
+#define Elf64_Internal_Ehdr Elf_Internal_Ehdr
+
+/* Program header */
+
+struct elf_internal_phdr {
+ unsigned long p_type; /* Identifies program segment type */
+ unsigned long p_flags; /* Segment flags */
+ bfd_vma p_offset; /* Segment file offset */
+ bfd_vma p_vaddr; /* Segment virtual address */
+ bfd_vma p_paddr; /* Segment physical address */
+ bfd_vma p_filesz; /* Segment size in file */
+ bfd_vma p_memsz; /* Segment size in memory */
+ bfd_vma p_align; /* Segment alignment, file & memory */
+};
+
+typedef struct elf_internal_phdr Elf_Internal_Phdr;
+#define elf32_internal_phdr elf_internal_phdr
+#define Elf32_Internal_Phdr Elf_Internal_Phdr
+#define elf64_internal_phdr elf_internal_phdr
+#define Elf64_Internal_Phdr Elf_Internal_Phdr
+
+/* Section header */
+
+typedef struct elf_internal_shdr {
+ unsigned int sh_name; /* Section name, index in string tbl */
+ unsigned int sh_type; /* Type of section */
+ bfd_vma sh_flags; /* Miscellaneous section attributes */
+ bfd_vma sh_addr; /* Section virtual addr at execution */
+ bfd_size_type sh_size; /* Size of section in bytes */
+ bfd_size_type sh_entsize; /* Entry size if section holds table */
+ unsigned long sh_link; /* Index of another section */
+ unsigned long sh_info; /* Additional section information */
+ file_ptr sh_offset; /* Section file offset */
+ unsigned int sh_addralign; /* Section alignment */
+
+ /* The internal rep also has some cached info associated with it. */
+ void *rawdata; /* null if unused... */
+ void *contents; /* null if unused... */
+ bfd_vma size; /* size of contents (0 if unused) */
+} Elf_Internal_Shdr;
+
+#define elf32_internal_shdr elf_internal_shdr
+#define Elf32_Internal_Shdr Elf_Internal_Shdr
+#define elf64_internal_shdr elf_internal_shdr
+#define Elf64_Internal_Shdr Elf_Internal_Shdr
+
+/* Symbol table entry */
+
+struct elf_internal_sym {
+ bfd_vma st_value; /* Value of the symbol */
+ bfd_vma st_size; /* Associated symbol size */
+ unsigned long st_name; /* Symbol name, index in string tbl */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ unsigned short st_shndx; /* Associated section index */
+};
+
+typedef struct elf_internal_sym Elf_Internal_Sym;
+
+#define elf32_internal_sym elf_internal_sym
+#define elf64_internal_sym elf_internal_sym
+#define Elf32_Internal_Sym Elf_Internal_Sym
+#define Elf64_Internal_Sym Elf_Internal_Sym
+
+/* Note segments */
+
+typedef struct elf_internal_note {
+ unsigned long namesz; /* Size of entry's owner string */
+ unsigned long descsz; /* Size of the note descriptor */
+ unsigned long type; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_Internal_Note;
+#define Elf32_Internal_Note Elf_Internal_Note
+#define elf32_internal_note elf_internal_note
+
+/* Relocation Entries */
+
+typedef struct elf_internal_rel {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma r_info; /* index and type of relocation */
+} Elf_Internal_Rel;
+
+#define elf32_internal_rel elf_internal_rel
+#define Elf32_Internal_Rel Elf_Internal_Rel
+#define elf64_internal_rel elf_internal_rel
+#define Elf64_Internal_Rel Elf_Internal_Rel
+
+typedef struct elf_internal_rela {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ bfd_vma r_info; /* Index and Type of relocation */
+ bfd_signed_vma r_addend; /* Constant addend used to compute value */
+} Elf_Internal_Rela;
+
+#define elf32_internal_rela elf_internal_rela
+#define elf64_internal_rela elf_internal_rela
+#define Elf32_Internal_Rela Elf_Internal_Rela
+#define Elf64_Internal_Rela Elf_Internal_Rela
+
+/* dynamic section structure */
+
+typedef struct {
+ Elf32_Sword d_tag; /* entry tag value */
+ union {
+ Elf32_Word d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Internal_Dyn;
+
+#ifdef HOST_64_BIT
+typedef struct {
+ Elf64_Xword d_tag; /* entry tag value */
+ union {
+ Elf64_Xword d_val;
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Internal_Dyn;
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/elfread.c b/gnu/usr.bin/gdb/gdb/elfread.c
new file mode 100644
index 000000000000..230afecefb2e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elfread.c
@@ -0,0 +1,729 @@
+/* Read ELF (Executable and Linking Format) object files for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "bfd.h"
+#include <time.h> /* For time_t in libbfd.h. */
+#include <sys/types.h> /* For time_t, if not in time.h. */
+#include "libbfd.h" /* For bfd_elf_find_section */
+#include "libelf.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include <string.h>
+#include "demangle.h"
+
+/* The struct elfinfo is available only during ELF symbol table and
+ psymtab reading. It is destroyed at the complation of psymtab-reading.
+ It's local to elf_symfile_read. */
+
+struct elfinfo {
+ file_ptr dboffset; /* Offset to dwarf debug section */
+ unsigned int dbsize; /* Size of dwarf debug section */
+ file_ptr lnoffset; /* Offset to dwarf line number section */
+ unsigned int lnsize; /* Size of dwarf line number section */
+ asection *stabsect; /* Section pointer for .stab section */
+ asection *stabindexsect; /* Section pointer for .stab.index section */
+};
+
+/* Various things we might complain about... */
+
+struct complaint section_info_complaint =
+ {"elf/stab section information %s without a preceding file symbol", 0, 0};
+
+struct complaint section_info_dup_complaint =
+ {"duplicated elf/stab section information for %s", 0, 0};
+
+struct complaint stab_info_mismatch_complaint =
+ {"elf/stab section information missing for %s", 0, 0};
+
+struct complaint stab_info_questionable_complaint =
+ {"elf/stab section information questionable for %s", 0, 0};
+
+static void
+elf_symfile_init PARAMS ((struct objfile *));
+
+static void
+elf_new_init PARAMS ((struct objfile *));
+
+static void
+elf_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+elf_symfile_finish PARAMS ((struct objfile *));
+
+static void
+elf_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *));
+
+static void
+free_elfinfo PARAMS ((void *));
+
+static struct section_offsets *
+elf_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
+
+static void
+record_minimal_symbol_and_info PARAMS ((char *, CORE_ADDR,
+ enum minimal_symbol_type, char *,
+ struct objfile *));
+
+static void
+elf_locate_sections PARAMS ((bfd *, asection *, void *));
+
+/* We are called once per section from elf_symfile_read. We
+ need to examine each section we are passed, check to see
+ if it is something we are interested in processing, and
+ if so, stash away some access information for the section.
+
+ For now we recognize the dwarf debug information sections and
+ line number sections from matching their section names. The
+ ELF definition is no real help here since it has no direct
+ knowledge of DWARF (by design, so any debugging format can be
+ used).
+
+ We also recognize the ".stab" sections used by the Sun compilers
+ released with Solaris 2.
+
+ FIXME: The section names should not be hardwired strings (what
+ should they be? I don't think most object file formats have enough
+ section flags to specify what kind of debug section it is
+ -kingdon). */
+
+static void
+elf_locate_sections (ignore_abfd, sectp, eip)
+ bfd *ignore_abfd;
+ asection *sectp;
+ PTR eip;
+{
+ register struct elfinfo *ei;
+
+ ei = (struct elfinfo *) eip;
+ if (STREQ (sectp -> name, ".debug"))
+ {
+ ei -> dboffset = sectp -> filepos;
+ ei -> dbsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (STREQ (sectp -> name, ".line"))
+ {
+ ei -> lnoffset = sectp -> filepos;
+ ei -> lnsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (STREQ (sectp -> name, ".stab"))
+ {
+ ei -> stabsect = sectp;
+ }
+ else if (STREQ (sectp -> name, ".stab.index"))
+ {
+ ei -> stabindexsect = sectp;
+ }
+}
+
+#if 0 /* Currently unused */
+
+char *
+elf_interpreter (abfd)
+ bfd *abfd;
+{
+ sec_ptr interp_sec;
+ unsigned size;
+ char *interp = NULL;
+
+ interp_sec = bfd_get_section_by_name (abfd, ".interp");
+ if (interp_sec)
+ {
+ size = bfd_section_size (abfd, interp_sec);
+ interp = alloca (size);
+ if (bfd_get_section_contents (abfd, interp_sec, interp, (file_ptr)0,
+ size))
+ {
+ interp = savestring (interp, size - 1);
+ }
+ else
+ {
+ interp = NULL;
+ }
+ }
+ return (interp);
+}
+
+#endif
+
+static void
+record_minimal_symbol_and_info (name, address, ms_type, info, objfile)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ char *info; /* FIXME, is this really char *? */
+ struct objfile *objfile;
+{
+ int section;
+
+ /* Guess the section from the type. This is likely to be wrong in
+ some cases. */
+ switch (ms_type)
+ {
+ case mst_text:
+ case mst_file_text:
+ section = SECT_OFF_TEXT;
+ break;
+ case mst_data:
+ case mst_file_data:
+ section = SECT_OFF_DATA;
+ break;
+ case mst_bss:
+ case mst_file_bss:
+ section = SECT_OFF_BSS;
+ break;
+ default:
+ section = -1;
+ break;
+ }
+
+ name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
+ prim_record_minimal_symbol_and_info (name, address, ms_type, info, section);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ elf_symtab_read -- read the symbol table of an ELF file
+
+SYNOPSIS
+
+ void elf_symtab_read (bfd *abfd, CORE_ADDR addr,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given an open bfd, a base address to relocate symbols to, and a
+ flag that specifies whether or not this bfd is for an executable
+ or not (may be shared library for example), add all the global
+ function and data symbols to the minimal symbol table.
+
+ In stabs-in-ELF, as implemented by Sun, there are some local symbols
+ defined in the ELF symbol table, which can be used to locate
+ the beginnings of sections from each ".o" file that was linked to
+ form the executable objfile. We gather any such info and record it
+ in data structures hung off the objfile's private data.
+
+*/
+
+static void
+elf_symtab_read (abfd, addr, objfile)
+ bfd *abfd;
+ CORE_ADDR addr;
+ struct objfile *objfile;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ int index;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ enum minimal_symbol_type ms_type;
+ /* If sectinfo is nonNULL, it contains section info that should end up
+ filed in the objfile. */
+ struct stab_section_info *sectinfo = NULL;
+ /* If filesym is nonzero, it points to a file symbol, but we haven't
+ seen any section info for it yet. */
+ asymbol *filesym = 0;
+ struct dbx_symfile_info *dbx = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ unsigned long size;
+
+ storage_needed = get_symtab_upper_bound (abfd);
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = symbol_table[i];
+ if (sym -> name == NULL || *sym -> name == '\0')
+ {
+ /* Skip names that don't exist (shouldn't happen), or names
+ that are null strings (may happen). */
+ continue;
+ }
+ if (sym -> flags & BSF_FILE)
+ {
+ /* STT_FILE debugging symbol that helps stabs-in-elf debugging.
+ Chain any old one onto the objfile; remember new sym. */
+ if (sectinfo != NULL)
+ {
+ sectinfo -> next = dbx -> stab_section_info;
+ dbx -> stab_section_info = sectinfo;
+ sectinfo = NULL;
+ }
+ filesym = sym;
+ }
+ else if (sym -> flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK))
+ {
+ /* Select global/local/weak symbols. Note that bfd puts abs
+ symbols in their own section, so all symbols we are
+ interested in will have a section. */
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate all non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ {
+ symaddr += addr;
+ }
+ /* For non-absolute symbols, use the type of the section
+ they are relative to, to intuit text/data. Bfd provides
+ no way of figuring this out for absolute symbols. */
+ if (sym -> section == &bfd_abs_section)
+ {
+ ms_type = mst_abs;
+ }
+ else if (sym -> section -> flags & SEC_CODE)
+ {
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ ms_type = mst_text;
+ }
+ else if (sym->name[0] == '.' && sym->name[1] == 'L')
+ /* Looks like a compiler-generated label. Skip it.
+ The assembler should be skipping these (to keep
+ executables small), but apparently with gcc on the
+ delta m88k SVR4, it loses. So to have us check too
+ should be harmless (but I encourage people to fix this
+ in the assembler instead of adding checks here). */
+ continue;
+ else
+ {
+ ms_type = mst_file_text;
+ }
+ }
+ else if (sym -> section -> flags & SEC_ALLOC)
+ {
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ if (sym -> section -> flags & SEC_LOAD)
+ {
+ ms_type = mst_data;
+ }
+ else
+ {
+ ms_type = mst_bss;
+ }
+ }
+ else if (sym -> flags & BSF_LOCAL)
+ {
+ /* Named Local variable in a Data section. Check its
+ name for stabs-in-elf. The STREQ macro checks the
+ first character inline, so we only actually do a
+ strcmp function call on names that start with 'B'
+ or 'D' */
+ index = SECT_OFF_MAX;
+ if (STREQ ("Bbss.bss", sym -> name))
+ {
+ index = SECT_OFF_BSS;
+ }
+ else if (STREQ ("Ddata.data", sym -> name))
+ {
+ index = SECT_OFF_DATA;
+ }
+ else if (STREQ ("Drodata.rodata", sym -> name))
+ {
+ index = SECT_OFF_RODATA;
+ }
+ if (index != SECT_OFF_MAX)
+ {
+ /* Found a special local symbol. Allocate a
+ sectinfo, if needed, and fill it in. */
+ if (sectinfo == NULL)
+ {
+ sectinfo = (struct stab_section_info *)
+ xmmalloc (objfile -> md, sizeof (*sectinfo));
+ memset ((PTR) sectinfo, 0, sizeof (*sectinfo));
+ if (filesym == NULL)
+ {
+ complain (&section_info_complaint,
+ sym -> name);
+ }
+ else
+ {
+ sectinfo -> filename =
+ (char *) filesym -> name;
+ }
+ }
+ if (sectinfo -> sections[index] != 0)
+ {
+ complain (&section_info_dup_complaint,
+ sectinfo -> filename);
+ }
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ {
+ symaddr += addr;
+ }
+ sectinfo -> sections[index] = symaddr;
+ /* The special local symbols don't go in the
+ minimal symbol table, so ignore this one. */
+ continue;
+ }
+ /* Not a special stabs-in-elf symbol, do regular
+ symbol processing. */
+ if (sym -> section -> flags & SEC_LOAD)
+ {
+ ms_type = mst_file_data;
+ }
+ else
+ {
+ ms_type = mst_file_bss;
+ }
+ }
+ else
+ {
+ ms_type = mst_unknown;
+ }
+ }
+ else
+ {
+ /* FIXME: Solaris2 shared libraries include lots of
+ odd "absolute" and "undefined" symbols, that play
+ hob with actions like finding what function the PC
+ is in. Ignore them if they aren't text, data, or bss. */
+ /* ms_type = mst_unknown; */
+ continue; /* Skip this symbol. */
+ }
+ /* Pass symbol size field in via BFD. FIXME!!! */
+ size = ((elf_symbol_type *) sym) -> internal_elf_sym.st_size;
+ record_minimal_symbol_and_info ((char *) sym -> name, symaddr,
+ ms_type, (PTR) size, objfile);
+ }
+ }
+ do_cleanups (back_to);
+ }
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to elf_symfile_init, which
+ currently does nothing.
+
+ SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
+ in each section. We simplify it down to a single offset for all
+ symbols. FIXME.
+
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ This function only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real.
+
+ We look for sections with specific names, to tell us what debug
+ format to look for: FIXME!!!
+
+ dwarf_build_psymtabs() builds psymtabs for DWARF symbols;
+ elfstab_build_psymtabs() handles STABS symbols.
+
+ Note that ELF files have a "minimal" symbol table, which looks a lot
+ like a COFF symbol table, but has only the minimal information necessary
+ for linking. We process this also, and use the information to
+ build gdb's minimal symbol table. This gives us some minimal debugging
+ capability even for files compiled without -g. */
+
+static void
+elf_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ bfd *abfd = objfile->obfd;
+ struct elfinfo ei;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ memset ((char *) &ei, 0, sizeof (ei));
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+ memset ((char *) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+ make_cleanup (free_elfinfo, (PTR) objfile);
+
+ /* Process the normal ELF symbol table first. This may write some
+ chain of info into the dbx_symfile_info in objfile->sym_stab_info,
+ which can later be used by elfstab_offset_sections. */
+
+ /* FIXME, should take a section_offsets param, not just an offset. */
+ offset = ANOFFSET (section_offsets, 0);
+ elf_symtab_read (abfd, offset, objfile);
+
+ /* Now process debugging information, which is contained in
+ special ELF sections. We first have to find them... */
+
+ bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei);
+ if (ei.dboffset && ei.lnoffset)
+ {
+ /* DWARF sections */
+ dwarf_build_psymtabs (objfile,
+ section_offsets, mainline,
+ ei.dboffset, ei.dbsize,
+ ei.lnoffset, ei.lnsize);
+ }
+ if (ei.stabsect)
+ {
+ /* STABS sections */
+
+ /* FIXME: Sun didn't really know how to implement this well.
+ They made .stab sections that don't point to the .stabstr
+ section with the sh_link field. BFD doesn't make string table
+ sections visible to the caller. So we have to search the
+ ELF section table, not the BFD section table, for the string
+ table. */
+ struct elf32_internal_shdr *elf_sect;
+
+ elf_sect = bfd_elf_find_section (abfd, ".stabstr");
+ if (elf_sect)
+ elfstab_build_psymtabs (objfile,
+ section_offsets,
+ mainline,
+ ei.stabsect->filepos, /* .stab offset */
+ bfd_get_section_size_before_reloc (ei.stabsect),/* .stab size */
+ (file_ptr) elf_sect->sh_offset, /* .stabstr offset */
+ elf_sect->sh_size); /* .stabstr size */
+ }
+
+ if (!have_partial_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+/* This cleans up the objfile's sym_stab_info pointer, and the chain of
+ stab_section_info's, that might be dangling from it. */
+
+static void
+free_elfinfo (objp)
+ PTR objp;
+{
+ struct objfile *objfile = (struct objfile *)objp;
+ struct dbx_symfile_info *dbxinfo = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ struct stab_section_info *ssi, *nssi;
+
+ ssi = dbxinfo->stab_section_info;
+ while (ssi)
+ {
+ nssi = ssi->next;
+ mfree (objfile->md, ssi);
+ ssi = nssi;
+ }
+
+ dbxinfo->stab_section_info = 0; /* Just say No mo info about this. */
+}
+
+
+/* Initialize anything that needs initializing when a completely new symbol
+ file is specified (not just adding some symbols from another file, e.g. a
+ shared library).
+
+ We reinitialize buildsym, since we may be reading stabs from an ELF file. */
+
+static void
+elf_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+elf_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_stab_info != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_stab_info);
+ }
+}
+
+/* ELF specific initialization routine for reading symbols.
+
+ It is passed a pointer to a struct sym_fns which contains, among other
+ things, the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we can fill with goodies.
+
+ For now at least, we have nothing in particular to do, so this function is
+ just a stub. */
+
+static void
+elf_symfile_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+/* ELF specific parsing routine for section offsets.
+
+ Plain and simple for now. */
+
+static
+struct section_offsets *
+elf_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* When handling an ELF file that contains Sun STABS debug info,
+ some of the debug info is relative to the particular chunk of the
+ section that was generated in its individual .o file. E.g.
+ offsets to static variables are relative to the start of the data
+ segment *for that module before linking*. This information is
+ painfully squirreled away in the ELF symbol table as local symbols
+ with wierd names. Go get 'em when needed. */
+
+void
+elfstab_offset_sections (objfile, pst)
+ struct objfile *objfile;
+ struct partial_symtab *pst;
+{
+ char *filename = pst->filename;
+ struct dbx_symfile_info *dbx = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ struct stab_section_info *maybe = dbx->stab_section_info;
+ struct stab_section_info *questionable = 0;
+ int i;
+ char *p;
+
+ /* The ELF symbol info doesn't include path names, so strip the path
+ (if any) from the psymtab filename. */
+ while (0 != (p = strchr (filename, '/')))
+ filename = p+1;
+
+ /* FIXME: This linear search could speed up significantly
+ if it was chained in the right order to match how we search it,
+ and if we unchained when we found a match. */
+ for (; maybe; maybe = maybe->next)
+ {
+ if (filename[0] == maybe->filename[0]
+ && STREQ (filename, maybe->filename))
+ {
+ /* We found a match. But there might be several source files
+ (from different directories) with the same name. */
+ if (0 == maybe->found)
+ break;
+ questionable = maybe; /* Might use it later. */
+ }
+ }
+
+ if (maybe == 0 && questionable != 0)
+ {
+ complain (&stab_info_questionable_complaint, filename);
+ maybe = questionable;
+ }
+
+ if (maybe)
+ {
+ /* Found it! Allocate a new psymtab struct, and fill it in. */
+ maybe->found++;
+ pst->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (pst->section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (pst->section_offsets, i) = maybe->sections[i];
+ return;
+ }
+
+ /* We were unable to find any offsets for this file. Complain. */
+ if (dbx->stab_section_info) /* If there *is* any info, */
+ complain (&stab_info_mismatch_complaint, filename);
+}
+
+/* Register that we are able to handle ELF object file formats and DWARF
+ debugging formats.
+
+ Unlike other object file formats, where the debugging information format
+ is implied by the object file format, the ELF object file format and the
+ DWARF debugging information format are two distinct, and potentially
+ separate entities. I.E. it is perfectly possible to have ELF objects
+ with debugging formats other than DWARF. And it is conceivable that the
+ DWARF debugging format might be used with another object file format,
+ like COFF, by simply using COFF's custom section feature.
+
+ GDB, and to a lesser extent BFD, should support the notion of separate
+ object file formats and debugging information formats. For now, we just
+ use "elf" in the same sense as "a.out" or "coff", to imply both the ELF
+ object file format and the DWARF debugging format. */
+
+static struct sym_fns elf_sym_fns =
+{
+ "elf", /* sym_name: name or name prefix of BFD target type */
+ 3, /* sym_namelen: number of significant sym_name chars */
+ elf_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ elf_symfile_read, /* sym_read: read a symbol file into symtab */
+ elf_symfile_finish, /* sym_finish: finished with file, cleanup */
+ elf_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_elfread ()
+{
+ add_symtab_fns (&elf_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/environ.c b/gnu/usr.bin/gdb/gdb/environ.c
new file mode 100644
index 000000000000..4089212e5add
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/environ.c
@@ -0,0 +1,198 @@
+/* environ.c -- library for manipulating environments for GNU.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+#include "defs.h"
+#include "environ.h"
+#include <string.h>
+#include "defs.h" /* For strsave(). */
+
+
+/* Return a new environment object. */
+
+struct environ *
+make_environ ()
+{
+ register struct environ *e;
+
+ e = (struct environ *) xmalloc (sizeof (struct environ));
+
+ e->allocated = 10;
+ e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
+ e->vector[0] = 0;
+ return e;
+}
+
+/* Free an environment and all the strings in it. */
+
+void
+free_environ (e)
+ register struct environ *e;
+{
+ register char **vector = e->vector;
+
+ while (*vector)
+ free (*vector++);
+
+ free (e);
+}
+
+/* Copy the environment given to this process into E.
+ Also copies all the strings in it, so we can be sure
+ that all strings in these environments are safe to free. */
+
+void
+init_environ (e)
+ register struct environ *e;
+{
+ extern char **environ;
+ register int i;
+
+ for (i = 0; environ[i]; i++) /*EMPTY*/;
+
+ if (e->allocated < i)
+ {
+ e->allocated = max (i, e->allocated + 10);
+ e->vector = (char **) xrealloc ((char *)e->vector,
+ (e->allocated + 1) * sizeof (char *));
+ }
+
+ memcpy (e->vector, environ, (i + 1) * sizeof (char *));
+
+ while (--i >= 0)
+ {
+ register int len = strlen (e->vector[i]);
+ register char *new = (char *) xmalloc (len + 1);
+ memcpy (new, e->vector[i], len + 1);
+ e->vector[i] = new;
+ }
+}
+
+/* Return the vector of environment E.
+ This is used to get something to pass to execve. */
+
+char **
+environ_vector (e)
+ struct environ *e;
+{
+ return e->vector;
+}
+
+/* Return the value in environment E of variable VAR. */
+
+char *
+get_in_environ (e, var)
+ const struct environ *e;
+ const char *var;
+{
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ if (STREQN (s, var, len) && s[len] == '=')
+ return &s[len + 1];
+
+ return 0;
+}
+
+/* Store the value in E of VAR as VALUE. */
+
+void
+set_in_environ (e, var, value)
+ struct environ *e;
+ const char *var;
+ const char *value;
+{
+ register int i;
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (i = 0; (s = vector[i]) != NULL; i++)
+ if (STREQN (s, var, len) && s[len] == '=')
+ break;
+
+ if (s == 0)
+ {
+ if (i == e->allocated)
+ {
+ e->allocated += 10;
+ vector = (char **) xrealloc ((char *)vector,
+ (e->allocated + 1) * sizeof (char *));
+ e->vector = vector;
+ }
+ vector[i + 1] = 0;
+ }
+ else
+ free (s);
+
+ s = (char *) xmalloc (len + strlen (value) + 2);
+ strcpy (s, var);
+ strcat (s, "=");
+ strcat (s, value);
+ vector[i] = s;
+
+ /* Certain variables get exported back to the parent (e.g. our)
+ environment, too. FIXME: this is a hideous hack and should not be
+ allowed to live. What if we want to change the environment we pass to
+ the program without affecting GDB's behavior? */
+ if (STREQ(var, "PATH")) /* Object file location */
+ {
+ putenv (strsave (s));
+ }
+
+ /* This is a compatibility hack, since GDB 4.10 and older didn't have
+ `set gnutarget'. Eventually it should go away, so that (for example)
+ you can debug objdump's handling of GNUTARGET without affecting GDB's
+ behavior. */
+ if (STREQ (var, "GNUTARGET"))
+ {
+ set_gnutarget (value);
+ }
+ return;
+}
+
+/* Remove the setting for variable VAR from environment E. */
+
+void
+unset_in_environ (e, var)
+ struct environ *e;
+ char *var;
+{
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ {
+ if (STREQN (s, var, len) && s[len] == '=')
+ {
+ free (s);
+ /* Walk through the vector, shuffling args down by one, including
+ the NULL terminator. Can't use memcpy() here since the regions
+ overlap, and memmove() might not be available. */
+ while ((vector[0] = vector[1]) != NULL)
+ {
+ vector++;
+ }
+ break;
+ }
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/environ.h b/gnu/usr.bin/gdb/gdb/environ.h
new file mode 100644
index 000000000000..6c9fd03e3620
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/environ.h
@@ -0,0 +1,58 @@
+/* Header for environment manipulation library.
+ Copyright 1989, 1992 Free Software Foundation.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (ENVIRON_H)
+#define ENVIRON_H 1
+
+/* We manipulate environments represented as these structures. */
+
+struct environ
+{
+ /* Number of usable slots allocated in VECTOR.
+ VECTOR always has one slot not counted here,
+ to hold the terminating zero. */
+ int allocated;
+ /* A vector of slots, ALLOCATED + 1 of them.
+ The first few slots contain strings "VAR=VALUE"
+ and the next one contains zero.
+ Then come some unused slots. */
+ char **vector;
+};
+
+extern struct environ *
+make_environ PARAMS ((void));
+
+extern void
+free_environ PARAMS ((struct environ *));
+
+extern void
+init_environ PARAMS ((struct environ *));
+
+extern char *
+get_in_environ PARAMS ((const struct environ *, const char *));
+
+extern void
+set_in_environ PARAMS ((struct environ *, const char *,
+ const char *));
+
+extern void
+unset_in_environ PARAMS ((struct environ *, char *));
+
+extern char **
+environ_vector PARAMS ((struct environ *));
+
+#endif /* defined (ENVIRON_H) */
diff --git a/gnu/usr.bin/gdb/gdb/eval.c b/gnu/usr.bin/gdb/gdb/eval.c
new file mode 100644
index 000000000000..f641a65f95a4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/eval.c
@@ -0,0 +1,1213 @@
+/* Evaluate expressions for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "expression.h"
+#include "target.h"
+#include "frame.h"
+#include "language.h" /* For CAST_IS_CONVERSION */
+
+/* Values of NOSIDE argument to eval_subexp. */
+enum noside
+{ EVAL_NORMAL,
+ EVAL_SKIP, /* Only effect is to increment pos. */
+ EVAL_AVOID_SIDE_EFFECTS /* Don't modify any variables or
+ call any functions. The value
+ returned will have the correct
+ type, and will have an
+ approximately correct lvalue
+ type (inaccuracy: anything that is
+ listed as being in a register in
+ the function in which it was
+ declared will be lval_register). */
+};
+
+/* Prototypes for local functions. */
+
+static value
+evaluate_subexp_for_sizeof PARAMS ((struct expression *, int *));
+
+static value
+evaluate_subexp_with_coercion PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value
+evaluate_subexp_for_address PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value
+evaluate_subexp PARAMS ((struct type *, struct expression *, int *,
+ enum noside));
+
+
+/* Parse the string EXP as a C expression, evaluate it,
+ and return the result as a number. */
+
+CORE_ADDR
+parse_and_eval_address (exp)
+ char *exp;
+{
+ struct expression *expr = parse_expression (exp);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_pointer (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+/* Like parse_and_eval_address but takes a pointer to a char * variable
+ and advanced that variable across the characters parsed. */
+
+CORE_ADDR
+parse_and_eval_address_1 (expptr)
+ char **expptr;
+{
+ struct expression *expr = parse_exp_1 (expptr, (struct block *)0, 0);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_pointer (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+value
+parse_and_eval (exp)
+ char *exp;
+{
+ struct expression *expr = parse_expression (exp);
+ register value val;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return val;
+}
+
+/* Parse up to a comma (or to a closeparen)
+ in the string EXPP as an expression, evaluate it, and return the value.
+ EXPP is advanced to point to the comma. */
+
+value
+parse_to_comma_and_eval (expp)
+ char **expp;
+{
+ struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1);
+ register value val;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return val;
+}
+
+/* Evaluate an expression in internal prefix form
+ such as is constructed by parse.y.
+
+ See expression.h for info on the format of an expression. */
+
+static value evaluate_subexp ();
+static value evaluate_subexp_for_address ();
+static value evaluate_subexp_for_sizeof ();
+static value evaluate_subexp_with_coercion ();
+
+value
+evaluate_expression (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+}
+
+/* Evaluate an expression, avoiding all memory references
+ and getting a value whose type alone is correct. */
+
+value
+evaluate_type (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value
+evaluate_subexp (expect_type, exp, pos, noside)
+ struct type *expect_type;
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ int tem, tem2, tem3;
+ register int pc, pc2 = 0, oldpos;
+ register value arg1 = NULL, arg2 = NULL, arg3;
+ struct type *type;
+ int nargs;
+ value *argvec;
+
+ pc = (*pos)++;
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_SCOPE:
+ tem = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type,
+ 0,
+ exp->elts[pc + 1].type,
+ &exp->elts[pc + 3].string,
+ expect_type);
+ if (arg1 == NULL)
+ error ("There is no field named %s", &exp->elts[pc + 3].string);
+ return arg1;
+
+ case OP_LONG:
+ (*pos) += 3;
+ return value_from_longest (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].longconst);
+
+ case OP_DOUBLE:
+ (*pos) += 3;
+ return value_from_double (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].doubleconst);
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct symbol * sym = exp->elts[pc + 2].symbol;
+ enum lval_type lv;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_LABEL:
+ case LOC_CONST_BYTES:
+ lv = not_lval;
+ break;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ lv = lval_register;
+ break;
+
+ default:
+ lv = lval_memory;
+ break;
+ }
+
+ return value_zero (SYMBOL_TYPE (sym), lv);
+ }
+ else
+ return value_of_variable (exp->elts[pc + 2].symbol,
+ exp->elts[pc + 1].block);
+
+ case OP_LAST:
+ (*pos) += 2;
+ return
+ access_value_history (longest_to_int (exp->elts[pc + 1].longconst));
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ return value_of_register (longest_to_int (exp->elts[pc + 1].longconst));
+
+ case OP_BOOL:
+ (*pos) += 2;
+ return value_from_longest (builtin_type_chill_bool,
+ exp->elts[pc + 1].longconst);
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ return value_of_internalvar (exp->elts[pc + 1].internalvar);
+
+ case OP_STRING:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_string (&exp->elts[pc + 2].string, tem);
+
+ case OP_BITSTRING:
+ error ("support for OP_BITSTRING unimplemented");
+ break;
+
+ case OP_ARRAY:
+ (*pos) += 3;
+ tem2 = longest_to_int (exp->elts[pc + 1].longconst);
+ tem3 = longest_to_int (exp->elts[pc + 2].longconst);
+ nargs = tem3 - tem2 + 1;
+ argvec = (value *) alloca (sizeof (value) * nargs);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ /* Ensure that array expressions are coerced into pointer objects. */
+ argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+ }
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return (value_array (tem2, tem3, argvec));
+ break;
+
+ case TERNOP_COND:
+ /* Skip third and second args to evaluate the first one. */
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (value_logical_not (arg1))
+ {
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ return arg2;
+ }
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ op = exp->elts[*pos].opcode;
+ if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ int fnptr;
+
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ /* First, evaluate the structure into arg2 */
+ pc2 = (*pos)++;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (op == STRUCTOP_MEMBER)
+ {
+ arg2 = evaluate_subexp_for_address (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+
+ /* If the function is a virtual function, then the
+ aggregate value (providing the structure) plays
+ its part by providing the vtable. Otherwise,
+ it is just along for the ride: call the function
+ directly. */
+
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ fnptr = longest_to_int (value_as_long (arg1));
+
+ if (METHOD_PTR_IS_VIRTUAL(fnptr))
+ {
+ int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr);
+ struct type *basetype;
+ struct type *domain_type =
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)));
+ int i, j;
+ basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if (domain_type != basetype)
+ arg2 = value_cast(lookup_pointer_type (domain_type), arg2);
+ basetype = TYPE_VPTR_BASETYPE (domain_type);
+ for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i);
+ /* If one is virtual, then all are virtual. */
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, 0))
+ for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j)
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset)
+ {
+ value temp = value_ind (arg2);
+ arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0);
+ arg2 = value_addr (temp);
+ goto got_it;
+ }
+ }
+ if (i < 0)
+ error ("virtual function at index %d not found", fnoffset);
+ }
+ else
+ {
+ VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)));
+ }
+ got_it:
+
+ /* Now, say which argument to start evaluating from */
+ tem = 2;
+ }
+ else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+ {
+ /* Hair for method invocations */
+ int tem2;
+
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ /* First, evaluate the structure into arg2 */
+ pc2 = (*pos)++;
+ tem2 = longest_to_int (exp->elts[pc2 + 1].longconst);
+ *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (op == STRUCTOP_STRUCT)
+ {
+ /* If v is a variable in a register, and the user types
+ v.method (), this will produce an error, because v has
+ no address.
+
+ A possible way around this would be to allocate a
+ copy of the variable on the stack, copy in the
+ contents, call the function, and copy out the
+ contents. I.e. convert this from call by reference
+ to call by copy-return (or whatever it's called).
+ However, this does not work because it is not the
+ same: the method being called could stash a copy of
+ the address, and then future uses through that address
+ (after the method returns) would be expected to
+ use the variable itself, not some copy of it. */
+ arg2 = evaluate_subexp_for_address (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+ /* Now, say which argument to start evaluating from */
+ tem = 2;
+ }
+ else
+ {
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ tem = 0;
+ }
+ /* Allocate arg vector, including space for the function to be
+ called in argvec[0] and a terminating NULL */
+ argvec = (value *) alloca (sizeof (value) * (nargs + 2));
+ for (; tem <= nargs; tem++)
+ /* Ensure that array expressions are coerced into pointer objects. */
+ argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+
+ /* signal end of arglist */
+ argvec[tem] = 0;
+
+ if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+ {
+ int static_memfuncp;
+ value temp = arg2;
+
+ argvec[1] = arg2;
+ argvec[0] =
+ value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 2].string,
+ &static_memfuncp,
+ op == STRUCTOP_STRUCT
+ ? "structure" : "structure pointer");
+ arg2 = value_from_longest (lookup_pointer_type (VALUE_TYPE (temp)),
+ VALUE_ADDRESS (temp)+VALUE_OFFSET (temp));
+ argvec[1] = arg2;
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ nargs--;
+ argvec++;
+ }
+ }
+ else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ argvec[1] = arg2;
+ argvec[0] = arg1;
+ }
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the return type doesn't look like a function type, call an
+ error. This can happen if somebody tries to turn a variable into
+ a function call. This is here because people often want to
+ call, eg, strcmp, which gdb doesn't know is a function. If
+ gdb isn't asked for it's opinion (ie. through "whatis"),
+ it won't offer it. */
+
+ struct type *ftype =
+ TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
+
+ if (ftype)
+ return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+ else
+ error ("Expression of type other than \"Function returning ...\" used as function");
+ }
+ return call_function_by_hand (argvec[0], nargs, argvec + 1);
+
+ case STRUCTOP_STRUCT:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc + 2].string,
+ 0),
+ lval_memory);
+ else
+ {
+ value temp = arg1;
+ return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string,
+ (int *) 0, "structure");
+ }
+
+ case STRUCTOP_PTR:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc + 2].string,
+ 0),
+ lval_memory);
+ else
+ {
+ value temp = arg1;
+ return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string,
+ (int *) 0, "structure pointer");
+ }
+
+ case STRUCTOP_MEMBER:
+ arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ goto handle_pointer_to_member;
+ case STRUCTOP_MPTR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ handle_pointer_to_member:
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR)
+ goto bad_pointer_to_member;
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if (TYPE_CODE (type) == TYPE_CODE_METHOD)
+ error ("not implemented: pointer-to-method in pointer-to-member construct");
+ if (TYPE_CODE (type) != TYPE_CODE_MEMBER)
+ goto bad_pointer_to_member;
+ /* Now, convert these values to an address. */
+ arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
+ arg1);
+ arg3 = value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_as_long (arg1) + value_as_long (arg2));
+ return value_ind (arg3);
+ bad_pointer_to_member:
+ error("non-pointer-to-member value used in pointer-to-member construct");
+
+ case BINOP_CONCAT:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_concat (arg1, arg2);
+
+ case BINOP_ASSIGN:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_assign (arg1, arg2);
+
+ case BINOP_ASSIGN_MODIFY:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ op = exp->elts[pc + 1].opcode;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op);
+ else if (op == BINOP_ADD)
+ arg2 = value_add (arg1, arg2);
+ else if (op == BINOP_SUB)
+ arg2 = value_sub (arg1, arg2);
+ else
+ arg2 = value_binop (arg1, arg2, op);
+ return value_assign (arg1, arg2);
+
+ case BINOP_ADD:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_add (arg1, arg2);
+
+ case BINOP_SUB:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_sub (arg1, arg2);
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ if (noside == EVAL_AVOID_SIDE_EFFECTS
+ && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD))
+ return value_zero (VALUE_TYPE (arg1), not_lval);
+ else
+ return value_binop (arg1, arg2, op);
+
+ case BINOP_SUBSCRIPT:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the user attempts to subscript something that has no target
+ type (like a plain int variable for example), then report this
+ as an error. */
+
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ if (type)
+ return value_zero (type, VALUE_LVAL (arg1));
+ else
+ error ("cannot subscript something of type `%s'",
+ TYPE_NAME (VALUE_TYPE (arg1)));
+ }
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_subscript (arg1, arg2);
+
+ case MULTI_SUBSCRIPT:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ while (nargs-- > 0)
+ {
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ /* FIXME: EVAL_SKIP handling may not be correct. */
+ if (noside == EVAL_SKIP)
+ {
+ if (nargs > 0)
+ {
+ continue;
+ }
+ else
+ {
+ goto nosideret;
+ }
+ }
+ /* FIXME: EVAL_AVOID_SIDE_EFFECTS handling may not be correct. */
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the user attempts to subscript something that has no target
+ type (like a plain int variable for example), then report this
+ as an error. */
+
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ if (type != NULL)
+ {
+ arg1 = value_zero (type, VALUE_LVAL (arg1));
+ noside = EVAL_SKIP;
+ continue;
+ }
+ else
+ {
+ error ("cannot subscript something of type `%s'",
+ TYPE_NAME (VALUE_TYPE (arg1)));
+ }
+ }
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg1 = value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ arg1 = value_subscript (arg1, arg2);
+ }
+ }
+ return (arg1);
+
+ case BINOP_LOGICAL_AND:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_logical_not (arg1);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+ (tem ? EVAL_SKIP : noside));
+ return value_from_longest (builtin_type_int,
+ (LONGEST) (!tem && !value_logical_not (arg2)));
+ }
+
+ case BINOP_LOGICAL_OR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_logical_not (arg1);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+ (!tem ? EVAL_SKIP : noside));
+ return value_from_longest (builtin_type_int,
+ (LONGEST) (!tem || !value_logical_not (arg2)));
+ }
+
+ case BINOP_EQUAL:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_NOTEQUAL:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) ! tem);
+ }
+
+ case BINOP_LESS:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GTR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GEQ:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1) || value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_LEQ:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2) || value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_REPEAT:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT)
+ error ("Non-integral right operand for \"@\" operator.");
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_repeat_value (VALUE_TYPE (arg1),
+ longest_to_int (value_as_long (arg2)));
+ else
+ return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
+
+ case BINOP_COMMA:
+ evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ case UNOP_NEG:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return value_x_unop (arg1, op);
+ else
+ return value_neg (arg1);
+
+ case UNOP_COMPLEMENT:
+ /* C++: check for and handle destructor names. */
+ op = exp->elts[*pos].opcode;
+
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
+ return value_x_unop (arg1, UNOP_COMPLEMENT);
+ else
+ return value_complement (arg1);
+
+ case UNOP_LOGICAL_NOT:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return value_x_unop (arg1, op);
+ else
+ return value_from_longest (builtin_type_int,
+ (LONGEST) value_logical_not (arg1));
+
+ case UNOP_IND:
+ if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
+ expect_type = TYPE_TARGET_TYPE (expect_type);
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ /* In C you can dereference an array to get the 1st elt. */
+ || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY
+ )
+ return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ lval_memory);
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+ /* GDB allows dereferencing an int. */
+ return value_zero (builtin_type_int, lval_memory);
+ else
+ error ("Attempt to take contents of a non-pointer value.");
+ }
+ return value_ind (arg1);
+
+ case UNOP_ADDR:
+ /* C++: check for and handle pointer to members. */
+
+ op = exp->elts[*pos].opcode;
+
+ if (noside == EVAL_SKIP)
+ {
+ if (op == OP_SCOPE)
+ {
+ int temm = longest_to_int (exp->elts[pc+3].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1);
+ }
+ else
+ evaluate_subexp (expect_type, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+
+ return evaluate_subexp_for_address (exp, pos, noside);
+
+ case UNOP_SIZEOF:
+ if (noside == EVAL_SKIP)
+ {
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+ return evaluate_subexp_for_sizeof (exp, pos);
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_cast (exp->elts[pc + 1].type, arg1);
+
+ case UNOP_MEMVAL:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (exp->elts[pc + 1].type, lval_memory);
+ else
+ return value_at_lazy (exp->elts[pc + 1].type,
+ value_as_pointer (arg1));
+
+ case UNOP_PREINCREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_add (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ return value_assign (arg1, arg2);
+ }
+
+ case UNOP_PREDECREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_sub (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ return value_assign (arg1, arg2);
+ }
+
+ case UNOP_POSTINCREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_add (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ case UNOP_POSTDECREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_sub (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ case OP_THIS:
+ (*pos) += 1;
+ return value_of_this (1);
+
+ case OP_TYPE:
+ error ("Attempt to use a type name as an expression");
+
+ default:
+ /* Removing this case and compiling with gcc -Wall reveals that
+ a lot of cases are hitting this case. Some of these should
+ probably be removed from expression.h (e.g. do we need a BINOP_SCOPE
+ and an OP_SCOPE?); others are legitimate expressions which are
+ (apparently) not fully implemented.
+
+ If there are any cases landing here which mean a user error,
+ then they should be separate cases, with more descriptive
+ error messages. */
+
+ error ("\
+GDB does not (yet) know how to evaluated that kind of expression");
+ }
+
+ nosideret:
+ return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+/* Evaluate a subexpression of EXP, at index *POS,
+ and return the address of that subexpression.
+ Advance *POS over the subexpression.
+ If the subexpression isn't an lvalue, get an error.
+ NOSIDE may be EVAL_AVOID_SIDE_EFFECTS;
+ then only the type of the result need be correct. */
+
+static value
+evaluate_subexp_for_address (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ register int pc;
+ struct symbol *var;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case UNOP_IND:
+ (*pos)++;
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
+ evaluate_subexp (NULL_TYPE, exp, pos, noside));
+
+ case OP_VAR_VALUE:
+ var = exp->elts[pc + 2].symbol;
+
+ /* C++: The "address" of a reference should yield the address
+ * of the object pointed to. Let value_addr() deal with it. */
+ if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_REF)
+ goto default_case;
+
+ (*pos) += 4;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *type =
+ lookup_pointer_type (SYMBOL_TYPE (var));
+ enum address_class sym_class = SYMBOL_CLASS (var);
+
+ if (sym_class == LOC_CONST
+ || sym_class == LOC_CONST_BYTES
+ || sym_class == LOC_REGISTER
+ || sym_class == LOC_REGPARM)
+ error ("Attempt to take address of register or constant.");
+
+ return
+ value_zero (type, not_lval);
+ }
+ else
+ return
+ locate_var_value
+ (var,
+ block_innermost_frame (exp->elts[pc + 1].block));
+
+ default:
+ default_case:
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ value x = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (VALUE_LVAL (x) == lval_memory)
+ return value_zero (lookup_pointer_type (VALUE_TYPE (x)),
+ not_lval);
+ else
+ error ("Attempt to take address of non-lval");
+ }
+ return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ }
+}
+
+/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
+ When used in contexts where arrays will be coerced anyway, this is
+ equivalent to `evaluate_subexp' but much faster because it avoids
+ actually fetching array contents (perhaps obsolete now that we have
+ VALUE_LAZY).
+
+ Note that we currently only do the coercion for C expressions, where
+ arrays are zero based and the coercion is correct. For other languages,
+ with nonzero based arrays, coercion loses. Use CAST_IS_CONVERSION
+ to decide if coercion is appropriate.
+
+ */
+
+static value
+evaluate_subexp_with_coercion (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ register enum exp_opcode op;
+ register int pc;
+ register value val;
+ struct symbol *var;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_VAR_VALUE:
+ var = exp->elts[pc + 2].symbol;
+ if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_ARRAY
+ && CAST_IS_CONVERSION)
+ {
+ (*pos) += 4;
+ val =
+ locate_var_value
+ (var, block_innermost_frame (exp->elts[pc + 1].block));
+ return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (var))),
+ val);
+ }
+ /* FALLTHROUGH */
+
+ default:
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+}
+
+/* Evaluate a subexpression of EXP, at index *POS,
+ and return a value for the size of that subexpression.
+ Advance *POS over the subexpression. */
+
+static value
+evaluate_subexp_for_sizeof (exp, pos)
+ register struct expression *exp;
+ register int *pos;
+{
+ enum exp_opcode op;
+ register int pc;
+ value val;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ /* This case is handled specially
+ so that we avoid creating a value for the result type.
+ If the result type is very big, it's desirable not to
+ create a value unnecessarily. */
+ case UNOP_IND:
+ (*pos)++;
+ val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_longest (builtin_type_int, (LONGEST)
+ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type));
+
+ case OP_VAR_VALUE:
+ (*pos) += 4;
+ return
+ value_from_longest
+ (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 2].symbol)));
+
+ default:
+ val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+}
+
+/* Parse a type expression in the string [P..P+LENGTH). */
+
+struct type *
+parse_and_eval_type (p, length)
+ char *p;
+ int length;
+{
+ char *tmp = (char *)alloca (length + 4);
+ struct expression *expr;
+ tmp[0] = '(';
+ memcpy (tmp+1, p, length);
+ tmp[length+1] = ')';
+ tmp[length+2] = '0';
+ tmp[length+3] = '\0';
+ expr = parse_expression (tmp);
+ if (expr->elts[0].opcode != UNOP_CAST)
+ error ("Internal error in eval_type.");
+ return expr->elts[1].type;
+}
diff --git a/gnu/usr.bin/gdb/gdb/exec.c b/gnu/usr.bin/gdb/gdb/exec.c
new file mode 100644
index 000000000000..f66a33c2cdc5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/exec.c
@@ -0,0 +1,489 @@
+/* Work with executable files, for GDB.
+ Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcmd.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "gdbcore.h"
+
+#include <ctype.h>
+#include <sys/stat.h>
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Prototypes for local functions */
+
+static void
+add_to_section_table PARAMS ((bfd *, sec_ptr, PTR));
+
+static void
+exec_close PARAMS ((int));
+
+static void
+file_command PARAMS ((char *, int));
+
+static void
+set_section_command PARAMS ((char *, int));
+
+static void
+exec_files_info PARAMS ((struct target_ops *));
+
+extern int info_verbose;
+
+/* The Binary File Descriptor handle for the executable file. */
+
+bfd *exec_bfd = NULL;
+
+/* Whether to open exec and core files read-only or read-write. */
+
+int write_files = 0;
+
+/* Text start and end addresses (KLUDGE) if needed */
+
+#ifdef NEED_TEXT_START_END
+CORE_ADDR text_start = 0;
+CORE_ADDR text_end = 0;
+#endif
+
+/* Forward decl */
+
+extern struct target_ops exec_ops;
+
+/* ARGSUSED */
+static void
+exec_close (quitting)
+ int quitting;
+{
+ if (exec_bfd) {
+ char *name = bfd_get_filename (exec_bfd);
+ bfd_close (exec_bfd);
+ free (name);
+ exec_bfd = NULL;
+ }
+ if (exec_ops.to_sections) {
+ free ((PTR)exec_ops.to_sections);
+ exec_ops.to_sections = NULL;
+ exec_ops.to_sections_end = NULL;
+ }
+}
+
+/* Process the first arg in ARGS as the new exec file.
+
+ Note that we have to explicitly ignore additional args, since we can
+ be called from file_command(), which also calls symbol_file_command()
+ which can take multiple args. */
+
+void
+exec_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *filename;
+
+ target_preopen (from_tty);
+
+ /* Remove any previous exec file. */
+ unpush_target (&exec_ops);
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (args)
+ {
+ char *scratch_pathname;
+ int scratch_chan;
+
+ /* Scan through the args and pick up the first non option arg
+ as the filename. */
+
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ make_cleanup (freeargv, (char *) argv);
+
+ for (; (*argv != NULL) && (**argv == '-'); argv++) {;}
+ if (*argv == NULL)
+ {
+ error ("no exec file name was specified");
+ }
+
+ filename = tilde_expand (*argv);
+ make_cleanup (free, filename);
+
+ scratch_chan = openp (getenv ("PATH"), 1, filename,
+ write_files? O_RDWR|O_BINARY: O_RDONLY|O_BINARY, 0,
+ &scratch_pathname);
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+
+ exec_bfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
+ if (!exec_bfd)
+ error ("Could not open `%s' as an executable file: %s",
+ scratch_pathname, bfd_errmsg (bfd_error));
+ if (!bfd_check_format (exec_bfd, bfd_object))
+ error ("\"%s\": not in executable format: %s.",
+ scratch_pathname, bfd_errmsg (bfd_error));
+
+ if (build_section_table (exec_bfd, &exec_ops.to_sections,
+ &exec_ops.to_sections_end))
+ error ("Can't find the file sections in `%s': %s",
+ exec_bfd->filename, bfd_errmsg (bfd_error));
+
+#ifdef NEED_TEXT_START_END
+
+ /* text_end is sometimes used for where to put call dummies. A
+ few ports use these for other purposes too. */
+
+ {
+ struct section_table *p;
+
+ /* Set text_start to the lowest address of the start of any
+ readonly code section and set text_end to the highest
+ address of the end of any readonly code section. */
+
+ text_start = ~(CORE_ADDR)0;
+ text_end = (CORE_ADDR)0;
+ for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++)
+ if (bfd_get_section_flags (p->bfd, p->sec_ptr)
+ & (SEC_CODE | SEC_READONLY))
+ {
+ if (text_start > p->addr)
+ text_start = p->addr;
+ if (text_end < p->endaddr)
+ text_end = p->endaddr;
+ }
+ }
+#endif
+
+ validate_files ();
+
+ push_target (&exec_ops);
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+ }
+ else if (from_tty)
+ printf ("No exec file now.\n");
+}
+
+/* Set both the exec file and the symbol file, in one command.
+ What a novelty. Why did GDB go through four major releases before this
+ command was added? */
+
+static void
+file_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* FIXME, if we lose on reading the symbol file, we should revert
+ the exec file, but that's rough. */
+ exec_file_command (arg, from_tty);
+ symbol_file_command (arg, from_tty);
+}
+
+
+/* Locate all mappable sections of a BFD file.
+ table_pp_char is a char * to get it through bfd_map_over_sections;
+ we cast it back to its proper type. */
+
+static void
+add_to_section_table (abfd, asect, table_pp_char)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR table_pp_char;
+{
+ struct section_table **table_pp = (struct section_table **)table_pp_char;
+ flagword aflag;
+
+ aflag = bfd_get_section_flags (abfd, asect);
+ /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+ if (!(aflag & SEC_LOAD))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ (*table_pp)->bfd = abfd;
+ (*table_pp)->sec_ptr = asect;
+ (*table_pp)->addr = bfd_section_vma (abfd, asect);
+ (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
+ (*table_pp)++;
+}
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+ Returns 0 if OK, 1 on error. */
+
+int
+build_section_table (some_bfd, start, end)
+ bfd *some_bfd;
+ struct section_table **start, **end;
+{
+ unsigned count;
+
+ count = bfd_count_sections (some_bfd);
+ if (*start)
+ free ((PTR)*start);
+ *start = (struct section_table *) xmalloc (count * sizeof (**start));
+ *end = *start;
+ bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end);
+ if (*end > *start + count)
+ abort();
+ /* We could realloc the table, but it probably loses for most files. */
+ return 0;
+}
+
+/* Read or write the exec file.
+
+ Args are address within a BFD file, address within gdb address-space,
+ length, and a flag indicating whether to read or write.
+
+ Result is a length:
+
+ 0: We cannot handle this address and length.
+ > 0: We have handled N bytes starting at this address.
+ (If N == length, we did it all.) We might be able
+ to handle more bytes beyond this length, but no
+ promises.
+ < 0: We cannot handle this address, but if somebody
+ else handles (-N) bytes, we can start from there.
+
+ The same routine is used to handle both core and exec files;
+ we just tail-call it with more arguments to select between them. */
+
+int
+xfer_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target;
+{
+ boolean res;
+ struct section_table *p;
+ CORE_ADDR nextsectaddr, memend;
+ boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type));
+
+ if (len <= 0)
+ abort();
+
+ memend = memaddr + len;
+ xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents;
+ nextsectaddr = memend;
+
+ for (p = target->to_sections; p < target->to_sections_end; p++)
+ {
+ if (p->addr <= memaddr)
+ if (p->endaddr >= memend)
+ {
+ /* Entire transfer is within this section. */
+ res = xfer_fn (p->bfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+ return (res != false)? len: 0;
+ }
+ else if (p->endaddr <= memaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ res = xfer_fn (p->bfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+ return (res != false)? len: 0;
+ }
+ else if (p->addr < nextsectaddr)
+ nextsectaddr = p->addr;
+ }
+
+ if (nextsectaddr >= memend)
+ return 0; /* We can't help */
+ else
+ return - (nextsectaddr - memaddr); /* Next boundary where we can help */
+}
+
+#ifdef FIXME
+#ifdef REG_STACK_SEGMENT
+/* MOVE TO BFD... */
+ /* Pyramids and AM29000s have an extra segment in the virtual address space
+ for the (control) stack of register-window frames. The AM29000 folk
+ call it the "register stack" rather than the "memory stack". */
+ else if (memaddr >= reg_stack_start && memaddr < reg_stack_end)
+ {
+ i = min (len, reg_stack_end - memaddr);
+ fileptr = memaddr - reg_stack_start + reg_stack_offset;
+ wanna_xfer = coredata;
+ }
+#endif /* REG_STACK_SEGMENT */
+#endif /* FIXME */
+
+void
+print_section_info (t, abfd)
+ struct target_ops *t;
+ bfd *abfd;
+{
+ struct section_table *p;
+
+ printf_filtered ("\t`%s', ", bfd_get_filename(abfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(abfd));
+ printf_filtered ("\tEntry point: %s\n",
+ local_hex_string ((unsigned long) bfd_get_start_address (exec_bfd)));
+ for (p = t->to_sections; p < t->to_sections_end; p++) {
+ printf_filtered ("\t%s", local_hex_string_custom ((unsigned long) p->addr, "08l"));
+ printf_filtered (" - %s", local_hex_string_custom ((unsigned long) p->endaddr, "08l"));
+ if (info_verbose)
+ printf_filtered (" @ %s",
+ local_hex_string_custom ((unsigned long) p->sec_ptr->filepos, "08l"));
+ printf_filtered (" is %s", bfd_section_name (p->bfd, p->sec_ptr));
+ if (p->bfd != abfd) {
+ printf_filtered (" in %s", bfd_get_filename (p->bfd));
+ }
+ printf_filtered ("\n");
+ }
+}
+
+static void
+exec_files_info (t)
+ struct target_ops *t;
+{
+ print_section_info (t, exec_bfd);
+}
+
+static void
+set_section_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct section_table *p;
+ char *secname;
+ unsigned seclen;
+ unsigned long secaddr;
+ char secprint[100];
+ long offset;
+
+ if (args == 0)
+ error ("Must specify section name and its virtual address");
+
+ /* Parse out section name */
+ for (secname = args; !isspace(*args); args++) ;
+ seclen = args - secname;
+
+ /* Parse out new virtual address */
+ secaddr = parse_and_eval_address (args);
+
+ for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) {
+ if (!strncmp (secname, bfd_section_name (exec_bfd, p->sec_ptr), seclen)
+ && bfd_section_name (exec_bfd, p->sec_ptr)[seclen] == '\0') {
+ offset = secaddr - p->addr;
+ p->addr += offset;
+ p->endaddr += offset;
+ if (from_tty)
+ exec_files_info(&exec_ops);
+ return;
+ }
+ }
+ if (seclen >= sizeof (secprint))
+ seclen = sizeof (secprint) - 1;
+ strncpy (secprint, secname, seclen);
+ secprint[seclen] = '\0';
+ error ("Section %s not found", secprint);
+}
+
+/* If mourn is being called in all the right places, this could be say
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
+
+static int
+ignore (addr, contents)
+ CORE_ADDR addr;
+ char *contents;
+{
+ return 0;
+}
+
+struct target_ops exec_ops = {
+ "exec", "Local exec file",
+ "Use an executable file as a target.\n\
+Specify the filename of the executable file.",
+ exec_file_command, exec_close, /* open, close */
+ find_default_attach, 0, 0, 0, /* attach, detach, resume, wait, */
+ 0, 0, /* fetch_registers, store_registers, */
+ 0, /* prepare_to_store, */
+ xfer_memory, exec_files_info,
+ ignore, ignore, /* insert_breakpoint, remove_breakpoint, */
+ 0, 0, 0, 0, 0, /* terminal stuff */
+ 0, 0, /* kill, load */
+ 0, /* lookup sym */
+ find_default_create_inferior,
+ 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ file_stratum, 0, /* next */
+ 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_exec()
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("file", class_files, file_command,
+ "Use FILE as program to be debugged.\n\
+It is read for its symbols, for getting the contents of pure memory,\n\
+and it is the program executed when you use the `run' command.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+($PATH) is searched for a command of that name.\n\
+No arg means to have no executable file and no symbols.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("exec-file", class_files, exec_file_command,
+ "Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name.\n\
+No arg means have no executable file.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_com ("section", class_files, set_section_command,
+ "Change the base address of section SECTION of the exec file to ADDR.\n\
+This can be used if the exec file does not contain section addresses,\n\
+(such as in the a.out format), or when the addresses specified in the\n\
+file itself are wrong. Each section must be changed separately. The\n\
+``info files'' command lists all the sections and their addresses.");
+
+ add_show_from_set
+ (add_set_cmd ("write", class_support, var_boolean, (char *)&write_files,
+ "Set writing into executable and core files.",
+ &setlist),
+ &showlist);
+
+ add_target (&exec_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/expprint.c b/gnu/usr.bin/gdb/gdb/expprint.c
new file mode 100644
index 000000000000..607b3df7037a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expprint.c
@@ -0,0 +1,623 @@
+/* Print in infix form a struct expression.
+ Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "language.h"
+#include "parser-defs.h"
+
+/* Prototypes for local functions */
+
+static void
+print_subexp PARAMS ((struct expression *, int *, FILE *, enum precedence));
+
+static void
+print_simple_m2_func PARAMS ((char *, struct expression *, int *, FILE *));
+
+void
+print_expression (exp, stream)
+ struct expression *exp;
+ FILE *stream;
+{
+ int pc = 0;
+ print_subexp (exp, &pc, stream, PREC_NULL);
+}
+
+/* Print the subexpression of EXP that starts in position POS, on STREAM.
+ PREC is the precedence of the surrounding operator;
+ if the precedence of the main operator of this subexpression is less,
+ parentheses are needed here. */
+
+static void
+print_subexp (exp, pos, stream, prec)
+ register struct expression *exp;
+ register int *pos;
+ FILE *stream;
+ enum precedence prec;
+{
+ register unsigned tem;
+ register const struct op_print *op_print_tab;
+ register int pc;
+ unsigned nargs;
+ register char *op_str;
+ int assign_modify = 0;
+ enum exp_opcode opcode;
+ enum precedence myprec = PREC_NULL;
+ /* Set to 1 for a right-associative operator. */
+ int assoc = 0;
+ value val;
+ char *tempstr = NULL;
+
+ op_print_tab = exp->language_defn->la_op_print_tab;
+ pc = (*pos)++;
+ opcode = exp->elts[pc].opcode;
+ switch (opcode)
+ {
+ /* Common ops */
+
+ case OP_SCOPE:
+ myprec = PREC_PREFIX;
+ assoc = 0;
+ fputs_filtered (type_name_no_tag (exp->elts[pc + 1].type), stream);
+ fputs_filtered ("::", stream);
+ nargs = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1);
+ fputs_filtered (&exp->elts[pc + 3].string, stream);
+ return;
+
+ case OP_LONG:
+ (*pos) += 3;
+ value_print (value_from_longest (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].longconst),
+ stream, 0, Val_no_prettyprint);
+ return;
+
+ case OP_DOUBLE:
+ (*pos) += 3;
+ value_print (value_from_double (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].doubleconst),
+ stream, 0, Val_no_prettyprint);
+ return;
+
+ case OP_VAR_VALUE:
+ {
+ struct block *b;
+ (*pos) += 3;
+ b = exp->elts[pc + 1].block;
+ if (b != NULL
+ && BLOCK_FUNCTION (b) != NULL
+ && SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fputs_filtered (SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)), stream);
+ fputs_filtered ("::", stream);
+ }
+ fputs_filtered (SYMBOL_SOURCE_NAME (exp->elts[pc + 2].symbol), stream);
+ }
+ return;
+
+ case OP_LAST:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%d",
+ longest_to_int (exp->elts[pc + 1].longconst));
+ return;
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%s",
+ reg_names[longest_to_int (exp->elts[pc + 1].longconst)]);
+ return;
+
+ case OP_BOOL:
+ (*pos) += 2;
+ fprintf_filtered (stream, "%s",
+ longest_to_int (exp->elts[pc + 1].longconst)
+ ? "TRUE" : "FALSE");
+ return;
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%s",
+ internalvar_name (exp->elts[pc + 1].internalvar));
+ return;
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered (" (", stream);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ fputs_filtered (", ", stream);
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fputs_filtered (")", stream);
+ return;
+
+ case OP_STRING:
+ nargs = longest_to_int (exp -> elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
+ /* LA_PRINT_STRING will print using the current repeat count threshold.
+ If necessary, we can temporarily set it to zero, or pass it as an
+ additional parameter to LA_PRINT_STRING. -fnf */
+ LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 0);
+ return;
+
+ case OP_BITSTRING:
+ error ("support for OP_BITSTRING unimplemented");
+ break;
+
+ case OP_ARRAY:
+ (*pos) += 3;
+ nargs = longest_to_int (exp->elts[pc + 2].longconst);
+ nargs -= longest_to_int (exp->elts[pc + 1].longconst);
+ nargs++;
+ tem = 0;
+ if (exp->elts[pc + 4].opcode == OP_LONG
+ && exp->elts[pc + 5].type == builtin_type_char
+ && exp->language_defn->la_language == language_c)
+ {
+ /* Attempt to print C character arrays using string syntax.
+ Walk through the args, picking up one character from each
+ of the OP_LONG expression elements. If any array element
+ does not match our expection of what we should find for
+ a simple string, revert back to array printing. Note that
+ the last expression element is an explicit null terminator
+ byte, which doesn't get printed. */
+ tempstr = alloca (nargs);
+ pc += 4;
+ while (tem < nargs)
+ {
+ if (exp->elts[pc].opcode != OP_LONG
+ || exp->elts[pc + 1].type != builtin_type_char)
+ {
+ /* Not a simple array of char, use regular array printing. */
+ tem = 0;
+ break;
+ }
+ else
+ {
+ tempstr[tem++] =
+ longest_to_int (exp->elts[pc + 2].longconst);
+ pc += 4;
+ }
+ }
+ }
+ if (tem > 0)
+ {
+ LA_PRINT_STRING (stream, tempstr, nargs - 1, 0);
+ (*pos) = pc;
+ }
+ else
+ {
+ fputs_filtered (" {", stream);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ {
+ fputs_filtered (", ", stream);
+ }
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fputs_filtered ("}", stream);
+ }
+ return;
+
+ case TERNOP_COND:
+ if ((int) prec > (int) PREC_COMMA)
+ fputs_filtered ("(", stream);
+ /* Print the subexpressions, forcing parentheses
+ around any binary operations within them.
+ This is more parentheses than are strictly necessary,
+ but it looks clearer. */
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ fputs_filtered (" ? ", stream);
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ fputs_filtered (" : ", stream);
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ if ((int) prec > (int) PREC_COMMA)
+ fputs_filtered (")", stream);
+ return;
+
+ case STRUCTOP_STRUCT:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered (".", stream);
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ return;
+
+ /* Will not occur for Modula-2 */
+ case STRUCTOP_PTR:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("->", stream);
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ return;
+
+ case BINOP_SUBSCRIPT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("[", stream);
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ fputs_filtered ("]", stream);
+ return;
+
+ case UNOP_POSTINCREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("++", stream);
+ return;
+
+ case UNOP_POSTDECREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("--", stream);
+ return;
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered ("(", stream);
+ fputs_filtered ("(", stream);
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fputs_filtered (") ", stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered (")", stream);
+ return;
+
+ case UNOP_MEMVAL:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered ("(", stream);
+ if (exp->elts[pc + 1].type->code == TYPE_CODE_FUNC &&
+ exp->elts[pc + 3].opcode == OP_LONG) {
+ /* We have a minimal symbol fn, probably. It's encoded
+ as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
+ Swallow the OP_LONG (including both its opcodes); ignore
+ its type; print the value in the type of the MEMVAL. */
+ (*pos) += 4;
+ val = value_at_lazy (exp->elts[pc + 1].type,
+ (CORE_ADDR) exp->elts[pc + 5].longconst);
+ value_print (val, stream, 0, Val_no_prettyprint);
+ } else {
+ fputs_filtered ("{", stream);
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fputs_filtered ("} ", stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ }
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered (")", stream);
+ return;
+
+ case BINOP_ASSIGN_MODIFY:
+ opcode = exp->elts[pc + 1].opcode;
+ (*pos) += 2;
+ myprec = PREC_ASSIGN;
+ assoc = 1;
+ assign_modify = 1;
+ op_str = "???";
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == opcode)
+ {
+ op_str = op_print_tab[tem].string;
+ break;
+ }
+ if (op_print_tab[tem].opcode != opcode)
+ /* Not found; don't try to keep going because we don't know how
+ to interpret further elements. */
+ error ("Invalid expression");
+ break;
+
+ /* C++ ops */
+
+ case OP_THIS:
+ ++(*pos);
+ fputs_filtered ("this", stream);
+ return;
+
+ /* Modula-2 ops */
+
+ case MULTI_SUBSCRIPT:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, " [");
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ fprintf (stream, ", ");
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fprintf (stream, "]");
+ return;
+
+ case BINOP_VAL:
+ (*pos)+=2;
+ fprintf(stream,"VAL(");
+ type_print(exp->elts[pc+1].type,"",stream,0);
+ fprintf(stream,",");
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf(stream,")");
+ return;
+
+ case UNOP_CAP:
+ print_simple_m2_func("CAP",exp,pos,stream);
+ return;
+
+ case UNOP_CHR:
+ print_simple_m2_func("CHR",exp,pos,stream);
+ return;
+
+ case UNOP_ORD:
+ print_simple_m2_func("ORD",exp,pos,stream);
+ return;
+
+ case UNOP_ABS:
+ print_simple_m2_func("ABS",exp,pos,stream);
+ return;
+
+ case UNOP_FLOAT:
+ print_simple_m2_func("FLOAT",exp,pos,stream);
+ return;
+
+ case UNOP_HIGH:
+ print_simple_m2_func("HIGH",exp,pos,stream);
+ return;
+
+ case UNOP_MAX:
+ print_simple_m2_func("MAX",exp,pos,stream);
+ return;
+
+ case UNOP_MIN:
+ print_simple_m2_func("MIN",exp,pos,stream);
+ return;
+
+ case UNOP_ODD:
+ print_simple_m2_func("ODD",exp,pos,stream);
+ return;
+
+ case UNOP_TRUNC:
+ print_simple_m2_func("TRUNC",exp,pos,stream);
+ return;
+
+ case BINOP_INCL:
+ case BINOP_EXCL:
+ error("print_subexp: Not implemented.");
+
+ /* Default ops */
+
+ default:
+ op_str = "???";
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == opcode)
+ {
+ op_str = op_print_tab[tem].string;
+ myprec = op_print_tab[tem].precedence;
+ assoc = op_print_tab[tem].right_assoc;
+ break;
+ }
+ if (op_print_tab[tem].opcode != opcode)
+ /* Not found; don't try to keep going because we don't know how
+ to interpret further elements. For example, this happens
+ if opcode is OP_TYPE. */
+ error ("Invalid expression");
+ }
+
+ if ((int) myprec < (int) prec)
+ fputs_filtered ("(", stream);
+ if ((int) opcode > (int) BINOP_END)
+ {
+ /* Unary prefix operator. */
+ fputs_filtered (op_str, stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ }
+ else
+ {
+ /* Binary operator. */
+ /* Print left operand.
+ If operator is right-associative,
+ increment precedence for this operand. */
+ print_subexp (exp, pos, stream,
+ (enum precedence) ((int) myprec + assoc));
+ /* Print the operator itself. */
+ if (assign_modify)
+ fprintf_filtered (stream, " %s= ", op_str);
+ else if (op_str[0] == ',')
+ fprintf_filtered (stream, "%s ", op_str);
+ else
+ fprintf_filtered (stream, " %s ", op_str);
+ /* Print right operand.
+ If operator is left-associative,
+ increment precedence for this operand. */
+ print_subexp (exp, pos, stream,
+ (enum precedence) ((int) myprec + !assoc));
+ }
+
+ if ((int) myprec < (int) prec)
+ fputs_filtered (")", stream);
+}
+
+/* Print out something of the form <s>(<arg>).
+ This is used to print out some builtin Modula-2
+ functions.
+ FIXME: There is probably some way to get the precedence
+ rules to do this (print a unary operand with parens around it). */
+static void
+print_simple_m2_func(s,exp,pos,stream)
+ char *s;
+ register struct expression *exp;
+ register int *pos;
+ FILE *stream;
+{
+ fprintf(stream,"%s(",s);
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf(stream,")");
+}
+
+/* Return the operator corresponding to opcode OP as
+ a string. NULL indicates that the opcode was not found in the
+ current language table. */
+char *
+op_string(op)
+ enum exp_opcode op;
+{
+ int tem;
+ register const struct op_print *op_print_tab;
+
+ op_print_tab = current_language->la_op_print_tab;
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == op)
+ return op_print_tab[tem].string;
+ return NULL;
+}
+
+#ifdef DEBUG_EXPRESSIONS
+
+/* Support for dumping the raw data from expressions in a human readable
+ form. */
+
+void
+dump_expression (exp, stream, note)
+ struct expression *exp;
+ FILE *stream;
+ char *note;
+{
+ int elt;
+ char *opcode_name;
+ char *eltscan;
+ int eltsize;
+
+ fprintf_filtered (stream, "Dump of expression @ 0x%lx, %s:\n",
+ (unsigned long) exp, note);
+ fprintf_filtered (stream, "\tLanguage %s, %d elements, %d bytes each.\n",
+ exp->language_defn->la_name, exp -> nelts,
+ sizeof (union exp_element));
+ fprintf_filtered (stream, "\t%5s %20s %16s %s\n", "Index", "Opcode",
+ "Hex Value", "String Value");
+ for (elt = 0; elt < exp -> nelts; elt++)
+ {
+ fprintf_filtered (stream, "\t%5d ", elt);
+ switch (exp -> elts[elt].opcode)
+ {
+ default: opcode_name = "<unknown>"; break;
+ case OP_NULL: opcode_name = "OP_NULL"; break;
+ case BINOP_ADD: opcode_name = "BINOP_ADD"; break;
+ case BINOP_SUB: opcode_name = "BINOP_SUB"; break;
+ case BINOP_MUL: opcode_name = "BINOP_MUL"; break;
+ case BINOP_DIV: opcode_name = "BINOP_DIV"; break;
+ case BINOP_REM: opcode_name = "BINOP_REM"; break;
+ case BINOP_MOD: opcode_name = "BINOP_MOD"; break;
+ case BINOP_LSH: opcode_name = "BINOP_LSH"; break;
+ case BINOP_RSH: opcode_name = "BINOP_RSH"; break;
+ case BINOP_LOGICAL_AND: opcode_name = "BINOP_LOGICAL_AND"; break;
+ case BINOP_LOGICAL_OR: opcode_name = "BINOP_LOGICAL_OR"; break;
+ case BINOP_BITWISE_AND: opcode_name = "BINOP_BITWISE_AND"; break;
+ case BINOP_BITWISE_IOR: opcode_name = "BINOP_BITWISE_IOR"; break;
+ case BINOP_BITWISE_XOR: opcode_name = "BINOP_BITWISE_XOR"; break;
+ case BINOP_EQUAL: opcode_name = "BINOP_EQUAL"; break;
+ case BINOP_NOTEQUAL: opcode_name = "BINOP_NOTEQUAL"; break;
+ case BINOP_LESS: opcode_name = "BINOP_LESS"; break;
+ case BINOP_GTR: opcode_name = "BINOP_GTR"; break;
+ case BINOP_LEQ: opcode_name = "BINOP_LEQ"; break;
+ case BINOP_GEQ: opcode_name = "BINOP_GEQ"; break;
+ case BINOP_REPEAT: opcode_name = "BINOP_REPEAT"; break;
+ case BINOP_ASSIGN: opcode_name = "BINOP_ASSIGN"; break;
+ case BINOP_COMMA: opcode_name = "BINOP_COMMA"; break;
+ case BINOP_SUBSCRIPT: opcode_name = "BINOP_SUBSCRIPT"; break;
+ case MULTI_SUBSCRIPT: opcode_name = "MULTI_SUBSCRIPT"; break;
+ case BINOP_EXP: opcode_name = "BINOP_EXP"; break;
+ case BINOP_MIN: opcode_name = "BINOP_MIN"; break;
+ case BINOP_MAX: opcode_name = "BINOP_MAX"; break;
+ case BINOP_SCOPE: opcode_name = "BINOP_SCOPE"; break;
+ case STRUCTOP_MEMBER: opcode_name = "STRUCTOP_MEMBER"; break;
+ case STRUCTOP_MPTR: opcode_name = "STRUCTOP_MPTR"; break;
+ case BINOP_INTDIV: opcode_name = "BINOP_INTDIV"; break;
+ case BINOP_ASSIGN_MODIFY: opcode_name = "BINOP_ASSIGN_MODIFY"; break;
+ case BINOP_VAL: opcode_name = "BINOP_VAL"; break;
+ case BINOP_INCL: opcode_name = "BINOP_INCL"; break;
+ case BINOP_EXCL: opcode_name = "BINOP_EXCL"; break;
+ case BINOP_CONCAT: opcode_name = "BINOP_CONCAT"; break;
+ case BINOP_END: opcode_name = "BINOP_END"; break;
+ case TERNOP_COND: opcode_name = "TERNOP_COND"; break;
+ case OP_LONG: opcode_name = "OP_LONG"; break;
+ case OP_DOUBLE: opcode_name = "OP_DOUBLE"; break;
+ case OP_VAR_VALUE: opcode_name = "OP_VAR_VALUE"; break;
+ case OP_LAST: opcode_name = "OP_LAST"; break;
+ case OP_REGISTER: opcode_name = "OP_REGISTER"; break;
+ case OP_INTERNALVAR: opcode_name = "OP_INTERNALVAR"; break;
+ case OP_FUNCALL: opcode_name = "OP_FUNCALL"; break;
+ case OP_STRING: opcode_name = "OP_STRING"; break;
+ case OP_BITSTRING: opcode_name = "OP_BITSTRING"; break;
+ case OP_ARRAY: opcode_name = "OP_ARRAY"; break;
+ case UNOP_CAST: opcode_name = "UNOP_CAST"; break;
+ case UNOP_MEMVAL: opcode_name = "UNOP_MEMVAL"; break;
+ case UNOP_NEG: opcode_name = "UNOP_NEG"; break;
+ case UNOP_LOGICAL_NOT: opcode_name = "UNOP_LOGICAL_NOT"; break;
+ case UNOP_COMPLEMENT: opcode_name = "UNOP_COMPLEMENT"; break;
+ case UNOP_IND: opcode_name = "UNOP_IND"; break;
+ case UNOP_ADDR: opcode_name = "UNOP_ADDR"; break;
+ case UNOP_PREINCREMENT: opcode_name = "UNOP_PREINCREMENT"; break;
+ case UNOP_POSTINCREMENT: opcode_name = "UNOP_POSTINCREMENT"; break;
+ case UNOP_PREDECREMENT: opcode_name = "UNOP_PREDECREMENT"; break;
+ case UNOP_POSTDECREMENT: opcode_name = "UNOP_POSTDECREMENT"; break;
+ case UNOP_SIZEOF: opcode_name = "UNOP_SIZEOF"; break;
+ case UNOP_PLUS: opcode_name = "UNOP_PLUS"; break;
+ case UNOP_CAP: opcode_name = "UNOP_CAP"; break;
+ case UNOP_CHR: opcode_name = "UNOP_CHR"; break;
+ case UNOP_ORD: opcode_name = "UNOP_ORD"; break;
+ case UNOP_ABS: opcode_name = "UNOP_ABS"; break;
+ case UNOP_FLOAT: opcode_name = "UNOP_FLOAT"; break;
+ case UNOP_HIGH: opcode_name = "UNOP_HIGH"; break;
+ case UNOP_MAX: opcode_name = "UNOP_MAX"; break;
+ case UNOP_MIN: opcode_name = "UNOP_MIN"; break;
+ case UNOP_ODD: opcode_name = "UNOP_ODD"; break;
+ case UNOP_TRUNC: opcode_name = "UNOP_TRUNC"; break;
+ case OP_BOOL: opcode_name = "OP_BOOL"; break;
+ case OP_M2_STRING: opcode_name = "OP_M2_STRING"; break;
+ case STRUCTOP_STRUCT: opcode_name = "STRUCTOP_STRUCT"; break;
+ case STRUCTOP_PTR: opcode_name = "STRUCTOP_PTR"; break;
+ case OP_THIS: opcode_name = "OP_THIS"; break;
+ case OP_SCOPE: opcode_name = "OP_SCOPE"; break;
+ case OP_TYPE: opcode_name = "OP_TYPE"; break;
+ }
+ fprintf_filtered (stream, "%20s ", opcode_name);
+ fprintf_filtered (stream,
+#if defined (PRINTF_HAS_LONG_LONG)
+ "%ll16x ",
+#else
+ "%l16x ",
+#endif
+ exp -> elts[elt].longconst);
+
+ for (eltscan = (char *) &exp->elts[elt],
+ eltsize = sizeof (union exp_element) ;
+ eltsize-- > 0;
+ eltscan++)
+ {
+ fprintf_filtered (stream, "%c",
+ isprint (*eltscan) ? (*eltscan & 0xFF) : '.');
+ }
+ fprintf_filtered (stream, "\n");
+ }
+}
+
+#endif /* DEBUG_EXPRESSIONS */
diff --git a/gnu/usr.bin/gdb/gdb/expression.h b/gnu/usr.bin/gdb/gdb/expression.h
new file mode 100644
index 000000000000..521c25cb45a4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expression.h
@@ -0,0 +1,313 @@
+/* Definitions for expressions stored in reversed prefix form, for GDB.
+ Copyright 1986, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (EXPRESSION_H)
+#define EXPRESSION_H 1
+
+#ifdef __STDC__
+struct block; /* Forward declaration for prototypes */
+#endif
+
+/* Definitions for saved C expressions. */
+
+/* An expression is represented as a vector of union exp_element's.
+ Each exp_element is an opcode, except that some opcodes cause
+ the following exp_element to be treated as a long or double constant
+ or as a variable. The opcodes are obeyed, using a stack for temporaries.
+ The value is left on the temporary stack at the end. */
+
+/* When it is necessary to include a string,
+ it can occupy as many exp_elements as it needs.
+ We find the length of the string using strlen,
+ divide to find out how many exp_elements are used up,
+ and skip that many. Strings, like numbers, are indicated
+ by the preceding opcode. */
+
+enum exp_opcode
+{
+ /* Used when it's necessary to pass an opcode which will be ignored,
+ or to catch uninitialized values. */
+ OP_NULL,
+
+/* BINOP_... operate on two values computed by following subexpressions,
+ replacing them by one result value. They take no immediate arguments. */
+ BINOP_ADD, /* + */
+ BINOP_SUB, /* - */
+ BINOP_MUL, /* * */
+ BINOP_DIV, /* / */
+ BINOP_REM, /* % */
+ BINOP_MOD, /* mod (Knuth 1.2.4) */
+ BINOP_LSH, /* << */
+ BINOP_RSH, /* >> */
+ BINOP_LOGICAL_AND, /* && */
+ BINOP_LOGICAL_OR, /* || */
+ BINOP_BITWISE_AND, /* & */
+ BINOP_BITWISE_IOR, /* | */
+ BINOP_BITWISE_XOR, /* ^ */
+ BINOP_EQUAL, /* == */
+ BINOP_NOTEQUAL, /* != */
+ BINOP_LESS, /* < */
+ BINOP_GTR, /* > */
+ BINOP_LEQ, /* <= */
+ BINOP_GEQ, /* >= */
+ BINOP_REPEAT, /* @ */
+ BINOP_ASSIGN, /* = */
+ BINOP_COMMA, /* , */
+ BINOP_SUBSCRIPT, /* x[y] */
+ BINOP_EXP, /* Exponentiation */
+
+/* C++. */
+ BINOP_MIN, /* <? */
+ BINOP_MAX, /* >? */
+ BINOP_SCOPE, /* :: */
+
+ /* STRUCTOP_MEMBER is used for pointer-to-member constructs.
+ X . * Y translates into X STRUCTOP_MEMBER Y. */
+ STRUCTOP_MEMBER,
+ /* STRUCTOP_MPTR is used for pointer-to-member constructs
+ when X is a pointer instead of an aggregate. */
+ STRUCTOP_MPTR,
+/* end of C++. */
+
+ /* For Modula-2 integer division DIV */
+ BINOP_INTDIV,
+
+ BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on.
+ The following exp_element is another opcode,
+ a BINOP_, saying how to modify.
+ Then comes another BINOP_ASSIGN_MODIFY,
+ making three exp_elements in total. */
+
+ /* Modula-2 standard (binary) procedures*/
+ BINOP_VAL,
+ BINOP_INCL,
+ BINOP_EXCL,
+
+ /* Concatenate two operands, such as character strings or bitstrings.
+ If the first operand is a integer expression, then it means concatenate
+ the second operand with itself that many times. */
+ BINOP_CONCAT,
+
+ /* This must be the highest BINOP_ value, for expprint.c. */
+ BINOP_END,
+
+/* Operates on three values computed by following subexpressions. */
+ TERNOP_COND, /* ?: */
+
+/* Multidimensional subscript operator, such as Modula-2 x[a,b,...].
+ The dimensionality is encoded in the operator, like the number of
+ function arguments in OP_FUNCALL, I.E. <OP><dimension><OP>.
+ The value of the first following subexpression is subscripted
+ by each of the next following subexpressions, one per dimension. */
+
+ MULTI_SUBSCRIPT,
+
+/* The OP_... series take immediate following arguments.
+ After the arguments come another OP_... (the same one)
+ so that the grouping can be recognized from the end. */
+
+/* OP_LONG is followed by a type pointer in the next exp_element
+ and the long constant value in the following exp_element.
+ Then comes another OP_LONG.
+ Thus, the operation occupies four exp_elements. */
+
+ OP_LONG,
+/* OP_DOUBLE is similar but takes a double constant instead of a long one. */
+ OP_DOUBLE,
+
+ /* OP_VAR_VALUE takes one struct block * in the following element,
+ and one struct symbol * in the following exp_element, followed by
+ another OP_VAR_VALUE, making four exp_elements. If the block is
+ non-NULL, evaluate the symbol relative to the innermost frame
+ executing in that block; if the block is NULL use the selected frame. */
+
+ OP_VAR_VALUE,
+
+/* OP_LAST is followed by an integer in the next exp_element.
+ The integer is zero for the last value printed,
+ or it is the absolute number of a history element.
+ With another OP_LAST at the end, this makes three exp_elements. */
+ OP_LAST,
+/* OP_REGISTER is followed by an integer in the next exp_element.
+ This is the number of a register to fetch (as an int).
+ With another OP_REGISTER at the end, this makes three exp_elements. */
+ OP_REGISTER,
+/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element.
+ With another OP_INTERNALVAR at the end, this makes three exp_elements. */
+ OP_INTERNALVAR,
+/* OP_FUNCALL is followed by an integer in the next exp_element.
+ The integer is the number of args to the function call.
+ That many plus one values from following subexpressions
+ are used, the first one being the function.
+ The integer is followed by a repeat of OP_FUNCALL,
+ making three exp_elements. */
+ OP_FUNCALL,
+/* OP_STRING represents a string constant.
+ Its format is the same as that of a STRUCTOP, but the string
+ data is just made into a string constant when the operation
+ is executed. */
+ OP_STRING,
+/* OP_BITSTRING represents a packed bitstring constant.
+ Its format is the same as that of a STRUCTOP, but the bitstring
+ data is just made into a bitstring constant when the operation
+ is executed. */
+ OP_BITSTRING,
+/* OP_ARRAY creates an array constant out of the following subexpressions.
+ It is followed by two exp_elements, the first containing an integer
+ that is the lower bound of the array and the second containing another
+ integer that is the upper bound of the array. The second integer is
+ followed by a repeat of OP_ARRAY, making four exp_elements total.
+ The bounds are used to compute the number of following subexpressions
+ to consume, as well as setting the bounds in the created array constant.
+ The type of the elements is taken from the type of the first subexp,
+ and they must all match. */
+ OP_ARRAY,
+
+/* UNOP_CAST is followed by a type pointer in the next exp_element.
+ With another UNOP_CAST at the end, this makes three exp_elements.
+ It casts the value of the following subexpression. */
+ UNOP_CAST,
+/* UNOP_MEMVAL is followed by a type pointer in the next exp_element
+ With another UNOP_MEMVAL at the end, this makes three exp_elements.
+ It casts the contents of the word addressed by the value of the
+ following subexpression. */
+ UNOP_MEMVAL,
+/* UNOP_... operate on one value from a following subexpression
+ and replace it with a result. They take no immediate arguments. */
+ UNOP_NEG, /* Unary - */
+ UNOP_LOGICAL_NOT, /* Unary ! */
+ UNOP_COMPLEMENT, /* Unary ~ */
+ UNOP_IND, /* Unary * */
+ UNOP_ADDR, /* Unary & */
+ UNOP_PREINCREMENT, /* ++ before an expression */
+ UNOP_POSTINCREMENT, /* ++ after an expression */
+ UNOP_PREDECREMENT, /* -- before an expression */
+ UNOP_POSTDECREMENT, /* -- after an expression */
+ UNOP_SIZEOF, /* Unary sizeof (followed by expression) */
+
+ UNOP_PLUS, /* Unary plus */
+
+ UNOP_CAP, /* Modula-2 standard (unary) procedures */
+ UNOP_CHR,
+ UNOP_ORD,
+ UNOP_ABS,
+ UNOP_FLOAT,
+ UNOP_HIGH,
+ UNOP_MAX,
+ UNOP_MIN,
+ UNOP_ODD,
+ UNOP_TRUNC,
+
+ OP_BOOL, /* Modula-2 builtin BOOLEAN type */
+ OP_M2_STRING, /* Modula-2 string constants */
+
+/* STRUCTOP_... operate on a value from a following subexpression
+ by extracting a structure component specified by a string
+ that appears in the following exp_elements (as many as needed).
+ STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->".
+ They differ only in the error message given in case the value is
+ not suitable or the structure component specified is not found.
+
+ The length of the string follows the opcode, followed by
+ BYTES_TO_EXP_ELEM(length) elements containing the data of the
+ string, followed by the length again and the opcode again. */
+
+ STRUCTOP_STRUCT,
+ STRUCTOP_PTR,
+
+/* C++ */
+ /* OP_THIS is just a placeholder for the class instance variable.
+ It just comes in a tight (OP_THIS, OP_THIS) pair. */
+ OP_THIS,
+
+ /* OP_SCOPE surrounds a type name and a field name. The type
+ name is encoded as one element, but the field name stays as
+ a string, which, of course, is variable length. */
+ OP_SCOPE,
+
+ /* OP_TYPE is for parsing types, and used with the "ptype" command
+ so we can look up types that are qualified by scope, either with
+ the GDB "::" operator, or the Modula-2 '.' operator. */
+ OP_TYPE
+};
+
+union exp_element
+{
+ enum exp_opcode opcode;
+ struct symbol *symbol;
+ LONGEST longconst;
+ double doubleconst;
+ /* Really sizeof (union exp_element) characters (or less for the last
+ element of a string). */
+ char string;
+ struct type *type;
+ struct internalvar *internalvar;
+ struct block *block;
+};
+
+struct expression
+{
+ const struct language_defn *language_defn; /* language it was entered in */
+ int nelts;
+ union exp_element elts[1];
+};
+
+/* Macros for converting between number of expression elements and bytes
+ to store that many expression elements. */
+
+#define EXP_ELEM_TO_BYTES(elements) \
+ ((elements) * sizeof (union exp_element))
+#define BYTES_TO_EXP_ELEM(bytes) \
+ (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element))
+
+/* From parse.c */
+
+extern struct expression *
+parse_expression PARAMS ((char *));
+
+extern struct expression *
+parse_exp_1 PARAMS ((char **, struct block *, int));
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. To use this, set it to NULL, then call
+ parse_<whatever>, then look at it. */
+extern struct block *innermost_block;
+
+/* From expprint.c */
+
+extern void
+print_expression PARAMS ((struct expression *, FILE *));
+
+extern char *
+op_string PARAMS ((enum exp_opcode));
+
+/* To enable dumping of all parsed expressions in a human readable
+ form, define DEBUG_EXPRESSIONS. This is a compile time constant
+ at the moment, since it's not clear that this feature is important
+ enough to include by default. */
+
+#ifdef DEBUG_EXPRESSIONS
+extern void
+dump_expression PARAMS ((struct expression *, FILE *, char *));
+#define DUMP_EXPRESSION(exp,file,note) dump_expression ((exp), (file), (note))
+#else
+#define DUMP_EXPRESSION(exp,file,note) /* Null expansion */
+#endif /* DEBUG_EXPRESSIONS */
+
+#endif /* !defined (EXPRESSION_H) */
diff --git a/gnu/usr.bin/gdb/gdb/findvar.c b/gnu/usr.bin/gdb/gdb/findvar.c
new file mode 100644
index 000000000000..bf50e1f04541
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/findvar.c
@@ -0,0 +1,971 @@
+/* Find a variable's value in memory, for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "target.h"
+
+/* Basic byte-swapping routines. GDB has needed these for a long time...
+ All extract a target-format integer at ADDR which is LEN bytes long. */
+
+#if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8
+ /* 8 bit characters are a pretty safe assumption these days, so we
+ assume it throughout all these swapping routines. If we had to deal with
+ 9 bit characters, we would need to make len be in bits and would have
+ to re-write these routines... */
+ you lose
+#endif
+
+LONGEST
+extract_signed_integer (addr, len)
+ PTR addr;
+ int len;
+{
+ LONGEST retval;
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ if (len > sizeof (LONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ sizeof (LONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ p = startaddr;
+#else
+ p = endaddr - 1;
+#endif
+ /* Do the sign extension once at the start. */
+ retval = ((LONGEST)*p ^ 0x80) - 0x80;
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (++p; p < endaddr; ++p)
+#else
+ for (--p; p >= startaddr; --p)
+#endif
+ {
+ retval = (retval << 8) | *p;
+ }
+ return retval;
+}
+
+unsigned LONGEST
+extract_unsigned_integer (addr, len)
+ PTR addr;
+ int len;
+{
+ unsigned LONGEST retval;
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ if (len > sizeof (unsigned LONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ sizeof (unsigned LONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+ retval = 0;
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = startaddr; p < endaddr; ++p)
+#else
+ for (p = endaddr - 1; p >= startaddr; --p)
+#endif
+ {
+ retval = (retval << 8) | *p;
+ }
+ return retval;
+}
+
+CORE_ADDR
+extract_address (addr, len)
+ PTR addr;
+ int len;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ return extract_unsigned_integer (addr, len);
+}
+
+void
+store_signed_integer (addr, len, val)
+ PTR addr;
+ int len;
+ LONGEST val;
+{
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ /* Start at the least significant end of the integer, and work towards
+ the most significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = endaddr - 1; p >= startaddr; --p)
+#else
+ for (p = startaddr; p < endaddr; ++p)
+#endif
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+}
+
+void
+store_unsigned_integer (addr, len, val)
+ PTR addr;
+ int len;
+ unsigned LONGEST val;
+{
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ /* Start at the least significant end of the integer, and work towards
+ the most significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = endaddr - 1; p >= startaddr; --p)
+#else
+ for (p = startaddr; p < endaddr; ++p)
+#endif
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+}
+
+void
+store_address (addr, len, val)
+ PTR addr;
+ int len;
+ CORE_ADDR val;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ store_unsigned_integer (addr, len, (LONGEST)val);
+}
+
+#if !defined (GET_SAVED_REGISTER)
+
+/* Return the address in which frame FRAME's value of register REGNUM
+ has been saved in memory. Or return zero if it has not been saved.
+ If REGNUM specifies the SP, the value we return is actually
+ the SP value, not an address where it was saved. */
+
+CORE_ADDR
+find_saved_register (frame, regnum)
+ FRAME frame;
+ int regnum;
+{
+ struct frame_info *fi;
+ struct frame_saved_regs saved_regs;
+
+ register FRAME frame1 = 0;
+ register CORE_ADDR addr = 0;
+
+ if (frame == 0) /* No regs saved if want current frame */
+ return 0;
+
+#ifdef HAVE_REGISTER_WINDOWS
+ /* We assume that a register in a register window will only be saved
+ in one place (since the name changes and/or disappears as you go
+ towards inner frames), so we only call get_frame_saved_regs on
+ the current frame. This is directly in contradiction to the
+ usage below, which assumes that registers used in a frame must be
+ saved in a lower (more interior) frame. This change is a result
+ of working on a register window machine; get_frame_saved_regs
+ always returns the registers saved within a frame, within the
+ context (register namespace) of that frame. */
+
+ /* However, note that we don't want this to return anything if
+ nothing is saved (if there's a frame inside of this one). Also,
+ callers to this routine asking for the stack pointer want the
+ stack pointer saved for *this* frame; this is returned from the
+ next frame. */
+
+
+ if (REGISTER_IN_WINDOW_P(regnum))
+ {
+ frame1 = get_next_frame (frame);
+ if (!frame1) return 0; /* Registers of this frame are
+ active. */
+
+ /* Get the SP from the next frame in; it will be this
+ current frame. */
+ if (regnum != SP_REGNUM)
+ frame1 = frame;
+
+ fi = get_frame_info (frame1);
+ get_frame_saved_regs (fi, &saved_regs);
+ return saved_regs.regs[regnum]; /* ... which might be zero */
+ }
+#endif /* HAVE_REGISTER_WINDOWS */
+
+ /* Note that this next routine assumes that registers used in
+ frame x will be saved only in the frame that x calls and
+ frames interior to it. This is not true on the sparc, but the
+ above macro takes care of it, so we should be all right. */
+ while (1)
+ {
+ QUIT;
+ frame1 = get_prev_frame (frame1);
+ if (frame1 == 0 || frame1 == frame)
+ break;
+ fi = get_frame_info (frame1);
+ get_frame_saved_regs (fi, &saved_regs);
+ if (saved_regs.regs[regnum])
+ addr = saved_regs.regs[regnum];
+ }
+
+ return addr;
+}
+
+/* Find register number REGNUM relative to FRAME and put its (raw,
+ target format) contents in *RAW_BUFFER. Set *OPTIMIZED if the
+ variable was optimized out (and thus can't be fetched). Set *LVAL
+ to lval_memory, lval_register, or not_lval, depending on whether
+ the value was fetched from memory, from a register, or in a strange
+ and non-modifiable way (e.g. a frame pointer which was calculated
+ rather than fetched). Set *ADDRP to the address, either in memory
+ on as a REGISTER_BYTE offset into the registers array.
+
+ Note that this implementation never sets *LVAL to not_lval. But
+ it can be replaced by defining GET_SAVED_REGISTER and supplying
+ your own.
+
+ The argument RAW_BUFFER must point to aligned memory. */
+
+void
+get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+ char *raw_buffer;
+ int *optimized;
+ CORE_ADDR *addrp;
+ FRAME frame;
+ int regnum;
+ enum lval_type *lval;
+{
+ CORE_ADDR addr;
+ /* Normal systems don't optimize out things with register numbers. */
+ if (optimized != NULL)
+ *optimized = 0;
+ addr = find_saved_register (frame, regnum);
+ if (addr != 0)
+ {
+ if (lval != NULL)
+ *lval = lval_memory;
+ if (regnum == SP_REGNUM)
+ {
+ if (raw_buffer != NULL)
+ {
+ /* Put it back in target format. */
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr);
+ }
+ if (addrp != NULL)
+ *addrp = 0;
+ return;
+ }
+ if (raw_buffer != NULL)
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ {
+ if (lval != NULL)
+ *lval = lval_register;
+ addr = REGISTER_BYTE (regnum);
+ if (raw_buffer != NULL)
+ read_register_gen (regnum, raw_buffer);
+ }
+ if (addrp != NULL)
+ *addrp = addr;
+}
+#endif /* GET_SAVED_REGISTER. */
+
+/* Copy the bytes of register REGNUM, relative to the current stack frame,
+ into our memory at MYADDR, in target byte order.
+ The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
+
+ Returns 1 if could not be read, 0 if could. */
+
+int
+read_relative_register_raw_bytes (regnum, myaddr)
+ int regnum;
+ char *myaddr;
+{
+ int optim;
+ if (regnum == FP_REGNUM && selected_frame)
+ {
+ /* Put it back in target format. */
+ store_address (myaddr, REGISTER_RAW_SIZE(FP_REGNUM),
+ FRAME_FP(selected_frame));
+ return 0;
+ }
+
+ get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, selected_frame,
+ regnum, (enum lval_type *)NULL);
+ return optim;
+}
+
+/* Return a `value' with the contents of register REGNUM
+ in its virtual format, with the type specified by
+ REGISTER_VIRTUAL_TYPE. */
+
+value
+value_of_register (regnum)
+ int regnum;
+{
+ CORE_ADDR addr;
+ int optim;
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ enum lval_type lval;
+
+ get_saved_register (raw_buffer, &optim, &addr,
+ selected_frame, regnum, &lval);
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+ val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ memcpy (VALUE_CONTENTS_RAW (val), virtual_buffer,
+ REGISTER_VIRTUAL_SIZE (regnum));
+ VALUE_LVAL (val) = lval;
+ VALUE_ADDRESS (val) = addr;
+ VALUE_REGNO (val) = regnum;
+ VALUE_OPTIMIZED_OUT (val) = optim;
+ return val;
+}
+
+/* Low level examining and depositing of registers.
+
+ The caller is responsible for making
+ sure that the inferior is stopped before calling the fetching routines,
+ or it will get garbage. (a change from GDB version 3, in which
+ the caller got the value from the last stop). */
+
+/* Contents of the registers in target byte order.
+ We allocate some extra slop since we do a lot of memcpy's around `registers',
+ and failing-soft is better than failing hard. */
+char registers[REGISTER_BYTES + /* SLOP */ 256];
+
+/* Nonzero if that register has been fetched. */
+char register_valid[NUM_REGS];
+
+/* Indicate that registers may have changed, so invalidate the cache. */
+void
+registers_changed ()
+{
+ int i;
+ for (i = 0; i < NUM_REGS; i++)
+ register_valid[i] = 0;
+}
+
+/* Indicate that all registers have been fetched, so mark them all valid. */
+void
+registers_fetched ()
+{
+ int i;
+ for (i = 0; i < NUM_REGS; i++)
+ register_valid[i] = 1;
+}
+
+/* Copy LEN bytes of consecutive data from registers
+ starting with the REGBYTE'th byte of register data
+ into memory at MYADDR. */
+
+void
+read_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ /* Fetch all registers. */
+ int i;
+ for (i = 0; i < NUM_REGS; i++)
+ if (!register_valid[i])
+ {
+ target_fetch_registers (-1);
+ break;
+ }
+ if (myaddr != NULL)
+ memcpy (myaddr, &registers[regbyte], len);
+}
+
+/* Read register REGNO into memory at MYADDR, which must be large enough
+ for REGISTER_RAW_BYTES (REGNO). Target byte-order.
+ If the register is known to be the size of a CORE_ADDR or smaller,
+ read_register can be used instead. */
+void
+read_register_gen (regno, myaddr)
+ int regno;
+ char *myaddr;
+{
+ if (!register_valid[regno])
+ target_fetch_registers (regno);
+ memcpy (myaddr, &registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE (regno));
+}
+
+/* Copy LEN bytes of consecutive data from memory at MYADDR
+ into registers starting with the REGBYTE'th byte of register data. */
+
+void
+write_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ /* Make sure the entire registers array is valid. */
+ read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+ memcpy (&registers[regbyte], myaddr, len);
+ target_store_registers (-1);
+}
+
+/* Return the raw contents of register REGNO, regarding it as an integer. */
+/* This probably should be returning LONGEST rather than CORE_ADDR. */
+
+CORE_ADDR
+read_register (regno)
+ int regno;
+{
+ if (!register_valid[regno])
+ target_fetch_registers (regno);
+
+ return extract_address (&registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE(regno));
+}
+
+/* Registers we shouldn't try to store. */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* Store VALUE, into the raw contents of register number REGNO. */
+/* FIXME: The val arg should probably be a LONGEST. */
+
+void
+write_register (regno, val)
+ int regno;
+ LONGEST val;
+{
+ PTR buf;
+ int size;
+
+ /* On the sparc, writing %g0 is a no-op, so we don't even want to change
+ the registers array if something writes to this register. */
+ if (CANNOT_STORE_REGISTER (regno))
+ return;
+
+ size = REGISTER_RAW_SIZE(regno);
+ buf = alloca (size);
+ store_signed_integer (buf, size, (LONGEST) val);
+
+ /* If we have a valid copy of the register, and new value == old value,
+ then don't bother doing the actual store. */
+
+ if (register_valid [regno])
+ {
+ if (memcmp (&registers[REGISTER_BYTE (regno)], buf, size) == 0)
+ return;
+ }
+
+ target_prepare_to_store ();
+
+ memcpy (&registers[REGISTER_BYTE (regno)], buf, size);
+
+ register_valid [regno] = 1;
+
+ target_store_registers (regno);
+}
+
+/* Record that register REGNO contains VAL.
+ This is used when the value is obtained from the inferior or core dump,
+ so there is no need to store the value there. */
+
+void
+supply_register (regno, val)
+ int regno;
+ char *val;
+{
+ register_valid[regno] = 1;
+ memcpy (&registers[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno));
+
+ /* On some architectures, e.g. HPPA, there are a few stray bits in some
+ registers, that the rest of the code would like to ignore. */
+#ifdef CLEAN_UP_REGISTER_VALUE
+ CLEAN_UP_REGISTER_VALUE(regno, &registers[REGISTER_BYTE(regno)]);
+#endif
+}
+
+/* Will calling read_var_value or locate_var_value on SYM end
+ up caring what frame it is being evaluated relative to? SYM must
+ be non-NULL. */
+int
+symbol_read_needs_frame (sym)
+ struct symbol *sym;
+{
+ switch (SYMBOL_CLASS (sym))
+ {
+ /* All cases listed explicitly so that gcc -Wall will detect it if
+ we failed to consider one. */
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ return 1;
+
+ case LOC_UNDEF:
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_TYPEDEF:
+
+ case LOC_LABEL:
+ /* Getting the address of a label can be done independently of the block,
+ even if some *uses* of that address wouldn't work so well without
+ the right frame. */
+
+ case LOC_BLOCK:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ return 0;
+ }
+}
+
+/* Given a struct symbol for a variable,
+ and a stack frame id, read the value of the variable
+ and return a (pointer to a) struct value containing the value.
+ If the variable cannot be found, return a zero pointer.
+ If FRAME is NULL, use the selected_frame. */
+
+value
+read_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register value v;
+ struct frame_info *fi;
+ struct type *type = SYMBOL_TYPE (var);
+ CORE_ADDR addr;
+ register int len;
+
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
+ len = TYPE_LENGTH (type);
+
+ if (frame == 0) frame = selected_frame;
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ /* Put the constant back in target format. */
+ store_signed_integer (VALUE_CONTENTS_RAW (v), len,
+ (LONGEST) SYMBOL_VALUE (var));
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_LABEL:
+ /* Put the constant back in target format. */
+ store_address (VALUE_CONTENTS_RAW (v), len, SYMBOL_VALUE_ADDRESS (var));
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_CONST_BYTES:
+ {
+ char *bytes_addr;
+ bytes_addr = SYMBOL_VALUE_BYTES (var);
+ memcpy (VALUE_CONTENTS_RAW (v), bytes_addr, len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+ }
+
+ case LOC_STATIC:
+ addr = SYMBOL_VALUE_ADDRESS (var);
+ break;
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_ARGS_ADDRESS (fi);
+ if (!addr)
+ {
+ return 0;
+ }
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_REF_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_ARGS_ADDRESS (fi);
+ if (!addr)
+ {
+ return 0;
+ }
+ addr += SYMBOL_VALUE (var);
+ addr = read_memory_unsigned_integer
+ (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ break;
+
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_LOCALS_ADDRESS (fi);
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+ get_saved_register (buf, NULL, NULL, frame, SYMBOL_BASEREG (var),
+ NULL);
+ addr = extract_address (buf, REGISTER_RAW_SIZE (SYMBOL_BASEREG (var)));
+ addr += SYMBOL_VALUE (var);
+ break;
+ }
+
+ case LOC_TYPEDEF:
+ error ("Cannot look up value of a typedef");
+ break;
+
+ case LOC_BLOCK:
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ return v;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ {
+ struct block *b;
+
+ if (frame == NULL)
+ return 0;
+ b = get_frame_block (frame);
+
+ v = value_from_register (type, SYMBOL_VALUE (var), frame);
+
+ if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
+ {
+ addr = *(CORE_ADDR *)VALUE_CONTENTS (v);
+ VALUE_LVAL (v) = lval_memory;
+ }
+ else
+ return v;
+ }
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ VALUE_LVAL (v) = not_lval;
+ VALUE_OPTIMIZED_OUT (v) = 1;
+ return v;
+
+ default:
+ error ("Cannot look up value of a botched symbol.");
+ break;
+ }
+
+ VALUE_ADDRESS (v) = addr;
+ VALUE_LAZY (v) = 1;
+ return v;
+}
+
+/* Return a value of type TYPE, stored in register REGNUM, in frame
+ FRAME. */
+
+value
+value_from_register (type, regnum, frame)
+ struct type *type;
+ int regnum;
+ FRAME frame;
+{
+ char raw_buffer [MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ CORE_ADDR addr;
+ int optim;
+ value v = allocate_value (type);
+ int len = TYPE_LENGTH (type);
+ char *value_bytes = 0;
+ int value_bytes_copied = 0;
+ int num_storage_locs;
+ enum lval_type lval;
+
+ VALUE_REGNO (v) = regnum;
+
+ num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
+ ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
+ 1);
+
+ if (num_storage_locs > 1
+#ifdef GDB_TARGET_IS_H8500
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+#endif
+ )
+ {
+ /* Value spread across multiple storage locations. */
+
+ int local_regnum;
+ int mem_stor = 0, reg_stor = 0;
+ int mem_tracking = 1;
+ CORE_ADDR last_addr = 0;
+ CORE_ADDR first_addr = 0;
+
+ value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
+
+ /* Copy all of the data out, whereever it may be. */
+
+#ifdef GDB_TARGET_IS_H8500
+/* This piece of hideosity is required because the H8500 treats registers
+ differently depending upon whether they are used as pointers or not. As a
+ pointer, a register needs to have a page register tacked onto the front.
+ An alternate way to do this would be to have gcc output different register
+ numbers for the pointer & non-pointer form of the register. But, it
+ doesn't, so we're stuck with this. */
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ && len > 2)
+ {
+ int page_regnum;
+
+ switch (regnum)
+ {
+ case R0_REGNUM: case R1_REGNUM: case R2_REGNUM: case R3_REGNUM:
+ page_regnum = SEG_D_REGNUM;
+ break;
+ case R4_REGNUM: case R5_REGNUM:
+ page_regnum = SEG_E_REGNUM;
+ break;
+ case R6_REGNUM: case R7_REGNUM:
+ page_regnum = SEG_T_REGNUM;
+ break;
+ }
+
+ value_bytes[0] = 0;
+ get_saved_register (value_bytes + 1,
+ &optim,
+ &addr,
+ frame,
+ page_regnum,
+ &lval);
+
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ mem_stor++;
+ first_addr = addr;
+ last_addr = addr;
+
+ get_saved_register (value_bytes + 2,
+ &optim,
+ &addr,
+ frame,
+ regnum,
+ &lval);
+
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ {
+ mem_stor++;
+ mem_tracking = mem_tracking && (addr == last_addr);
+ }
+ last_addr = addr;
+ }
+ else
+#endif /* GDB_TARGET_IS_H8500 */
+ for (local_regnum = regnum;
+ value_bytes_copied < len;
+ (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+ ++local_regnum))
+ {
+ get_saved_register (value_bytes + value_bytes_copied,
+ &optim,
+ &addr,
+ frame,
+ local_regnum,
+ &lval);
+
+ if (regnum == local_regnum)
+ first_addr = addr;
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ {
+ mem_stor++;
+
+ mem_tracking =
+ (mem_tracking
+ && (regnum == local_regnum
+ || addr == last_addr));
+ }
+ last_addr = addr;
+ }
+
+ if ((reg_stor && mem_stor)
+ || (mem_stor && !mem_tracking))
+ /* Mixed storage; all of the hassle we just went through was
+ for some good purpose. */
+ {
+ VALUE_LVAL (v) = lval_reg_frame_relative;
+ VALUE_FRAME (v) = FRAME_FP (frame);
+ VALUE_FRAME_REGNUM (v) = regnum;
+ }
+ else if (mem_stor)
+ {
+ VALUE_LVAL (v) = lval_memory;
+ VALUE_ADDRESS (v) = first_addr;
+ }
+ else if (reg_stor)
+ {
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = first_addr;
+ }
+ else
+ fatal ("value_from_register: Value not stored anywhere!");
+
+ VALUE_OPTIMIZED_OUT (v) = optim;
+
+ /* Any structure stored in more than one register will always be
+ an integral number of registers. Otherwise, you'd need to do
+ some fiddling with the last register copied here for little
+ endian machines. */
+
+ /* Copy into the contents section of the value. */
+ memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len);
+
+ /* Finally do any conversion necessary when extracting this
+ type from more than one register. */
+#ifdef REGISTER_CONVERT_TO_TYPE
+ REGISTER_CONVERT_TO_TYPE(regnum, type, VALUE_CONTENTS_RAW(v));
+#endif
+ return v;
+ }
+
+ /* Data is completely contained within a single register. Locate the
+ register's contents in a real register or in core;
+ read the data in raw format. */
+
+ get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval);
+ VALUE_OPTIMIZED_OUT (v) = optim;
+ VALUE_LVAL (v) = lval;
+ VALUE_ADDRESS (v) = addr;
+
+ /* Convert the raw contents to virtual contents.
+ (Just copy them if the formats are the same.) */
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ /* When the raw and virtual formats differ, the virtual format
+ corresponds to a specific data type. If we want that type,
+ copy the data into the value.
+ Otherwise, do a type-conversion. */
+
+ if (type != REGISTER_VIRTUAL_TYPE (regnum))
+ {
+ /* eg a variable of type `float' in a 68881 register
+ with raw type `extended' and virtual type `double'.
+ Fetch it as a `double' and then convert to `float'. */
+ /* FIXME: This value will be not_lval, which means we can't assign
+ to it. Probably the right fix is to do the cast on a temporary
+ value, and just copy the VALUE_CONTENTS over. */
+ v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer,
+ REGISTER_VIRTUAL_SIZE (regnum));
+ v = value_cast (type, v);
+ }
+ else
+ memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, len);
+ }
+ else
+ {
+ /* Raw and virtual formats are the same for this register. */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ if (len < REGISTER_RAW_SIZE (regnum))
+ {
+ /* Big-endian, and we want less than full size. */
+ VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
+ }
+#endif
+
+ memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer + VALUE_OFFSET (v), len);
+ }
+
+ return v;
+}
+
+/* Given a struct symbol for a variable or function,
+ and a stack frame id,
+ return a (pointer to a) struct value containing the properly typed
+ address. */
+
+value
+locate_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ CORE_ADDR addr = 0;
+ struct type *type = SYMBOL_TYPE (var);
+ value lazy_value;
+
+ /* Evaluate it first; if the result is a memory address, we're fine.
+ Lazy evaluation pays off here. */
+
+ lazy_value = read_var_value (var, frame);
+ if (lazy_value == 0)
+ error ("Address of \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var));
+
+ if (VALUE_LAZY (lazy_value)
+ || TYPE_CODE (type) == TYPE_CODE_FUNC)
+ {
+ addr = VALUE_ADDRESS (lazy_value);
+ return value_from_longest (lookup_pointer_type (type), (LONGEST) addr);
+ }
+
+ /* Not a memory address; check what the problem was. */
+ switch (VALUE_LVAL (lazy_value))
+ {
+ case lval_register:
+ case lval_reg_frame_relative:
+ error ("Address requested for identifier \"%s\" which is in a register.",
+ SYMBOL_SOURCE_NAME (var));
+ break;
+
+ default:
+ error ("Can't take address of \"%s\" which isn't an lvalue.",
+ SYMBOL_SOURCE_NAME (var));
+ break;
+ }
+ return 0; /* For lint -- never reached */
+}
diff --git a/gnu/usr.bin/gdb/gdb/fopen-same.h b/gnu/usr.bin/gdb/gdb/fopen-same.h
new file mode 100644
index 000000000000..0f37529d33e0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fopen-same.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for "same" systems, where text and binary files are
+ the same. An example is Unix. Many Unix systems could also add a
+ "b" to the string, indicating binary files, but some reject this
+ (and thereby don't conform to ANSI C, but what else is new?).
+
+ This file is designed for inclusion by host-dependent .h files. No
+ user application should include it directly, since that would make
+ the application unable to be configured for both "same" and "binary"
+ variant systems. */
+
+#define FOPEN_RB "r"
+#define FOPEN_WB "w"
+#define FOPEN_AB "a"
+#define FOPEN_RUB "r+"
+#define FOPEN_WUB "w+"
+#define FOPEN_AUB "a+"
+
+#define FOPEN_RT "r"
+#define FOPEN_WT "w"
+#define FOPEN_AT "a"
+#define FOPEN_RUT "r+"
+#define FOPEN_WUT "w+"
+#define FOPEN_AUT "a+"
diff --git a/gnu/usr.bin/gdb/gdb/fork-child.c b/gnu/usr.bin/gdb/gdb/fork-child.c
new file mode 100644
index 000000000000..3c01b6021eb5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fork-child.c
@@ -0,0 +1,310 @@
+/* Fork a Unix child process, and set up to debug it, for GDB.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "terminal.h"
+
+#include <signal.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+extern int original_stack_limit;
+#endif /* SET_STACK_LIMIT_HUGE */
+
+extern char **environ;
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+void
+fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun)
+ char *exec_file;
+ char *allargs;
+ char **env;
+ void (*traceme_fun) PARAMS ((void));
+ void (*init_trace_fun) PARAMS ((int));
+{
+ int pid;
+ char *shell_command;
+ char *shell_file;
+ static char default_shell_file[] = SHELL_FILE;
+ int len;
+ int pending_execs;
+ int terminal_initted;
+ /* Set debug_fork then attach to the child while it sleeps, to debug. */
+ static int debug_fork = 0;
+ /* This is set to the result of setpgrp, which if vforked, will be visible
+ to you in the parent process. It's only used by humans for debugging. */
+ static int debug_setpgrp = 657473;
+ char **save_our_env;
+
+ /* If no exec file handed to us, get it from the exec-file command -- with
+ a good, common error message if none is specified. */
+ if (exec_file == 0)
+ exec_file = get_exec_file(1);
+
+ /* The user might want tilde-expansion, and in general probably wants
+ the program to behave the same way as if run from
+ his/her favorite shell. So we let the shell run it for us.
+ FIXME, this should probably search the local environment (as
+ modified by the setenv command), not the env gdb inherited. */
+ shell_file = getenv ("SHELL");
+ if (shell_file == NULL)
+ shell_file = default_shell_file;
+
+ /* Multiplying the length of exec_file by 4 is to account for the fact
+ that it may expand when quoted; it is a worst-case number based on
+ every character being '. */
+ len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 12;
+ /* If desired, concat something onto the front of ALLARGS.
+ SHELL_COMMAND is the result. */
+#ifdef SHELL_COMMAND_CONCAT
+ shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len);
+ strcpy (shell_command, SHELL_COMMAND_CONCAT);
+#else
+ shell_command = (char *) alloca (len);
+ shell_command[0] = '\0';
+#endif
+ strcat (shell_command, "exec ");
+
+ /* Now add exec_file, quoting as necessary. */
+ {
+ char *p;
+ int need_to_quote;
+
+ /* Quoting in this style is said to work with all shells. But csh
+ on IRIX 4.0.1 can't deal with it. So we only quote it if we need
+ to. */
+ p = exec_file;
+ while (1)
+ {
+ switch (*p)
+ {
+ case '\'':
+ case '"':
+ case '(':
+ case ')':
+ case '$':
+ case '&':
+ case ';':
+ case '<':
+ case '>':
+ case ' ':
+ case '\n':
+ case '\t':
+ need_to_quote = 1;
+ goto end_scan;
+
+ case '\0':
+ need_to_quote = 0;
+ goto end_scan;
+
+ default:
+ break;
+ }
+ ++p;
+ }
+ end_scan:
+ if (need_to_quote)
+ {
+ strcat (shell_command, "'");
+ for (p = exec_file; *p != '\0'; ++p)
+ {
+ if (*p == '\'')
+ strcat (shell_command, "'\\''");
+ else
+ strncat (shell_command, p, 1);
+ }
+ strcat (shell_command, "'");
+ }
+ else
+ strcat (shell_command, exec_file);
+ }
+
+ strcat (shell_command, " ");
+ strcat (shell_command, allargs);
+
+ /* exec is said to fail if the executable is open. */
+ close_exec_file ();
+
+ /* Retain a copy of our environment variables, since the child will
+ replace the value of environ and if we're vforked, we have to
+ restore it. */
+ save_our_env = environ;
+
+ /* Tell the terminal handling subsystem what tty we plan to run on;
+ it will just record the information for later. */
+
+ new_tty_prefork (inferior_io_terminal);
+
+ /* It is generally good practice to flush any possible pending stdio
+ output prior to doing a fork, to avoid the possibility of both the
+ parent and child flushing the same data after the fork. */
+
+ fflush (stdout);
+ fflush (stderr);
+
+#if defined(USG) && !defined(HAVE_VFORK)
+ pid = fork ();
+#else
+ if (debug_fork)
+ pid = fork ();
+ else
+ pid = vfork ();
+#endif
+
+ if (pid < 0)
+ perror_with_name ("vfork");
+
+ if (pid == 0)
+ {
+ if (debug_fork)
+ sleep (debug_fork);
+
+ /* Run inferior in a separate process group. */
+ debug_setpgrp = gdb_setpgid ();
+ if (debug_setpgrp == -1)
+ perror("setpgrp failed in child");
+
+#ifdef SET_STACK_LIMIT_HUGE
+ /* Reset the stack limit back to what it was. */
+ {
+ struct rlimit rlim;
+
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = original_stack_limit;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* Ask the tty subsystem to switch to the one we specified earlier
+ (or to share the current terminal, if none was specified). */
+
+ new_tty ();
+
+ /* Changing the signal handlers for the inferior after
+ a vfork can also change them for the superior, so we don't mess
+ with signals here. See comments in
+ initialize_signals for how we get the right signal handlers
+ for the inferior. */
+
+ /* "Trace me, Dr. Memory!" */
+ (*traceme_fun) ();
+
+ /* There is no execlpe call, so we have to set the environment
+ for our child in the global variable. If we've vforked, this
+ clobbers the parent, but environ is restored a few lines down
+ in the parent. By the way, yes we do need to look down the
+ path to find $SHELL. Rich Pixley says so, and I agree. */
+ environ = env;
+ execlp (shell_file, shell_file, "-c", shell_command, (char *)0);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", shell_file,
+ safe_strerror (errno));
+ fflush (stderr);
+ _exit (0177);
+ }
+
+ /* Restore our environment in case a vforked child clob'd it. */
+ environ = save_our_env;
+
+ init_thread_list();
+
+ /* Now that we have a child process, make it our target, and
+ initialize anything target-vector-specific that needs initializing. */
+ (*init_trace_fun)(pid);
+
+ /* The process was started by the fork that created it,
+ but it will have stopped one instruction after execing the shell.
+ Here we must get it up to actual execution of the real program. */
+
+ inferior_pid = pid; /* Needed for wait_for_inferior stuff below */
+
+ clear_proceed_status ();
+
+ /* We will get a trace trap after one instruction.
+ Continue it automatically. Eventually (after shell does an exec)
+ it will get another trace trap. Then insert breakpoints and continue. */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ pending_execs = START_INFERIOR_TRAPS_EXPECTED;
+#else
+ pending_execs = 2;
+#endif
+
+ init_wait_for_inferior ();
+
+ terminal_initted = 0;
+
+ while (1)
+ {
+ stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */
+ wait_for_inferior ();
+ if (stop_signal != SIGTRAP)
+ {
+ /* Let shell child handle its own signals in its own way */
+ /* FIXME, what if child has exit()ed? Must exit loop somehow */
+ resume (0, stop_signal);
+ }
+ else
+ {
+ /* We handle SIGTRAP, however; it means child did an exec. */
+ if (!terminal_initted)
+ {
+ /* Now that the child has exec'd we know it has already set its
+ process group. On POSIX systems, tcsetpgrp will fail with
+ EPERM if we try it before the child's setpgid. */
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ terminal_initted = 1;
+ }
+ if (0 == --pending_execs)
+ break;
+ resume (0, 0); /* Just make it go on */
+ }
+ }
+ stop_soon_quietly = 0;
+
+ /* We are now in the child process of interest, having exec'd the
+ correct program, and are poised at the first instruction of the
+ new program. */
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ SOLIB_CREATE_INFERIOR_HOOK (pid);
+#endif
+}
diff --git a/gnu/usr.bin/gdb/gdb/frame.h b/gnu/usr.bin/gdb/gdb/frame.h
new file mode 100644
index 000000000000..1fe6fb6a49b3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/frame.h
@@ -0,0 +1,238 @@
+/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (FRAME_H)
+#define FRAME_H 1
+
+/* A FRAME identifies a specific stack frame. It is not constant over
+ calls to the inferior (frame addresses are, see below).
+
+ This is implemented as a "struct frame_info *". This file and
+ blockframe.c are the only places which are allowed to use the
+ equivalence between FRAME and struct frame_info *. Exception:
+ Prototypes in other files use "struct frame_info *" because this
+ file might not be included.
+
+ The distinction between a FRAME and a "struct frame_info *" is made
+ with the idea of maybe someday changing a FRAME to be something else,
+ but seems to me that a "struct frame_info *" is fully general (since
+ any necessarily fields can be added; changing the meaning of existing
+ fields is not helped by the FRAME distinction), and this distinction
+ merely creates unnecessary hair. -kingdon, 18 May 93. */
+typedef struct frame_info *FRAME;
+
+/* Convert from a "struct frame_info *" into a FRAME. */
+#define FRAME_INFO_ID(f) (f)
+
+/* Convert from a FRAME into a "struct frame_info *". */
+extern struct frame_info *
+get_frame_info PARAMS ((FRAME));
+
+/* Type of the address of a frame. It is widely assumed (at least in
+ prototypes in headers which might not include this header) that
+ this is the same as CORE_ADDR, and no one can think of a case in
+ which it wouldn't be, so it might be best to remove this typedef. */
+typedef CORE_ADDR FRAME_ADDR;
+
+/* Convert from a FRAME into a frame address. Except in the
+ machine-dependent *FRAME* macros, a frame address has no defined
+ meaning other than as a magic cookie which identifies a frame over
+ calls to the inferior. The only known exception is inferior.h
+ (PC_IN_CALL_DUMMY) [ON_STACK]; see comments there. You cannot
+ assume that a frame address contains enough information to
+ reconstruct the frame; if you want more than just to identify the
+ frame (e.g. be able to fetch variables relative to that frame),
+ then save the whole struct frame_info (and the next struct
+ frame_info, since the latter is used for fetching variables on some
+ machines). */
+
+#define FRAME_FP(fr) ((fr)->frame)
+
+/* We keep a cache of stack frames, each of which is a "struct
+ frame_info". The innermost one gets allocated (in
+ wait_for_inferior) each time the inferior stops; current_frame
+ points to it. Additional frames get allocated (in
+ get_prev_frame_info) as needed, and are chained through the next
+ and prev fields. Any time that the frame cache becomes invalid
+ (most notably when we execute something, but also if we change how
+ we interpret the frames (e.g. "set heuristic-fence-post" in
+ mips-tdep.c, or anything which reads new symbols)), we should call
+ reinit_frame_cache. */
+
+struct frame_info
+ {
+ /* Nominal address of the frame described. See comments at FRAME_FP
+ about what this means outside the *FRAME* macros; in the *FRAME*
+ macros, it can mean whatever makes most sense for this machine. */
+ FRAME_ADDR frame;
+
+ /* Address at which execution is occurring in this frame.
+ For the innermost frame, it's the current pc.
+ For other frames, it is a pc saved in the next frame. */
+ CORE_ADDR pc;
+
+ /* Nonzero if this is a frame associated with calling a signal handler.
+
+ Set by machine-dependent code. On some machines, if
+ the machine-dependent code fails to check for this, the backtrace
+ will look relatively normal. For example, on the i386
+ #3 0x158728 in sighold ()
+ On other machines (e.g. rs6000), the machine-dependent code better
+ set this to prevent us from trying to print it like a normal frame. */
+ int signal_handler_caller;
+
+ /* Anything extra for this structure that may have been defined
+ in the machine dependent files. */
+#ifdef EXTRA_FRAME_INFO
+ EXTRA_FRAME_INFO
+#endif
+
+ /* We should probably also store a "struct frame_saved_regs" here.
+ This is already done by some machines (e.g. config/m88k/tm-m88k.h)
+ but there is no reason it couldn't be general. */
+
+ /* Pointers to the next and previous frame_info's in the frame cache. */
+ FRAME next, prev;
+ };
+
+/* Describe the saved registers of a frame. */
+
+struct frame_saved_regs
+ {
+
+ /* For each register, address of where it was saved on entry to
+ the frame, or zero if it was not saved on entry to this frame.
+ This includes special registers such as pc and fp saved in
+ special ways in the stack frame. The SP_REGNUM is even more
+ special, the address here is the sp for the next frame, not the
+ address where the sp was saved. */
+
+ CORE_ADDR regs[NUM_REGS];
+ };
+
+/* Define a default FRAME_CHAIN_VALID, in the form that is suitable for most
+ targets. If FRAME_CHAIN_VALID returns zero it means that the given frame
+ is the outermost one and has no caller.
+
+ If a particular target needs a different definition, then it can override
+ the definition here by providing one in the tm file. */
+
+#if !defined (FRAME_CHAIN_VALID)
+
+#if defined (FRAME_CHAIN_VALID_ALTERNATE)
+
+/* Use the alternate method of avoiding running up off the end of the frame
+ chain or following frames back into the startup code. See the comments
+ in objfiles.h. */
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ ((chain) != 0 \
+ && !inside_main_func ((thisframe) -> pc) \
+ && !inside_entry_func ((thisframe) -> pc))
+
+#else
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ ((chain) != 0 \
+ && !inside_entry_file (FRAME_SAVED_PC (thisframe)))
+
+#endif /* FRAME_CHAIN_VALID_ALTERNATE */
+
+#endif /* FRAME_CHAIN_VALID */
+
+/* The stack frame that the user has specified for commands to act on.
+ Note that one cannot assume this is the address of valid data. */
+
+extern FRAME selected_frame;
+
+/* Level of the selected frame:
+ 0 for innermost, 1 for its caller, ...
+ or -1 for frame specified by address with no defined level. */
+
+extern int selected_frame_level;
+
+extern struct frame_info *
+get_prev_frame_info PARAMS ((FRAME));
+
+extern FRAME
+create_new_frame PARAMS ((FRAME_ADDR, CORE_ADDR));
+
+extern void
+flush_cached_frames PARAMS ((void));
+
+extern void
+reinit_frame_cache PARAMS ((void));
+
+extern void
+get_frame_saved_regs PARAMS ((struct frame_info *, struct frame_saved_regs *));
+
+extern void
+set_current_frame PARAMS ((FRAME));
+
+extern FRAME
+get_prev_frame PARAMS ((FRAME));
+
+extern FRAME
+get_current_frame PARAMS ((void));
+
+extern FRAME
+get_next_frame PARAMS ((FRAME));
+
+extern struct block *
+get_frame_block PARAMS ((FRAME));
+
+extern struct block *
+get_current_block PARAMS ((void));
+
+extern struct block *
+get_selected_block PARAMS ((void));
+
+extern struct symbol *
+get_frame_function PARAMS ((FRAME));
+
+extern CORE_ADDR
+get_frame_pc PARAMS ((FRAME));
+
+extern CORE_ADDR
+get_pc_function_start PARAMS ((CORE_ADDR));
+
+extern struct block * block_for_pc PARAMS ((CORE_ADDR));
+
+extern int frameless_look_for_prologue PARAMS ((FRAME));
+
+extern void print_frame_args PARAMS ((struct symbol *, struct frame_info *,
+ int, FILE *));
+
+extern FRAME find_relative_frame PARAMS ((FRAME, int*));
+
+extern void print_stack_frame PARAMS ((FRAME, int, int));
+
+extern void select_frame PARAMS ((FRAME, int));
+
+extern void record_selected_frame PARAMS ((FRAME_ADDR *, int *));
+
+extern void print_frame_info PARAMS ((struct frame_info *, int, int, int));
+
+extern CORE_ADDR find_saved_register PARAMS ((FRAME, int));
+
+extern FRAME block_innermost_frame PARAMS ((struct block *));
+
+extern CORE_ADDR sigtramp_saved_pc PARAMS ((FRAME));
+
+#endif /* !defined (FRAME_H) */
diff --git a/gnu/usr.bin/gdb/gdb/freebsd-nat.c b/gnu/usr.bin/gdb/gdb/freebsd-nat.c
new file mode 100644
index 000000000000..deb68ebb9453
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/freebsd-nat.c
@@ -0,0 +1,323 @@
+/* Native-dependent code for BSD Unix running on i386's, for GDB.
+ Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <machine/reg.h>
+
+/* this table must line up with REGISTER_NAMES in tm-i386.h */
+/* symbols like 'tEAX' come from <machine/reg.h> */
+static int tregmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS
+};
+#ifdef sEAX
+static int sregmap[] =
+{
+ sEAX, sECX, sEDX, sEBX,
+ sESP, sEBP, sESI, sEDI,
+ sEIP, sEFLAGS, sCS, sSS
+};
+#endif
+/* blockend is the value of u.u_ar0, and points to the
+ place where ES is stored. */
+
+int
+i386_register_u_addr (blockend, regnum)
+ int blockend;
+ int regnum;
+{
+ /* The following condition is a kludge to get at the proper register map
+ depending upon the state of pcb_flag.
+ The proper condition would be
+ if (u.u_pcb.pcb_flag & FM_TRAP)
+ but that would require a ptrace call here and wouldn't work
+ for corefiles. */
+
+#ifdef sEAX
+ if (blockend < 0x1fcc)
+ return (blockend + 4 * tregmap[regnum]);
+ else
+ return (blockend + 4 * sregmap[regnum]);
+#else
+ return (blockend + 4 * tregmap[regnum]);
+#endif
+}
+
+#ifdef FLOAT_INFO
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <a.out.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
+#include <sys/user.h>
+#undef curpcb
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+
+i387_to_double (from, to)
+ char *from;
+ char *to;
+{
+ long *lp;
+ /* push extended mode on 387 stack, then pop in double mode
+ *
+ * first, set exception masks so no error is generated -
+ * number will be rounded to inf or 0, if necessary
+ */
+ asm ("pushl %eax"); /* grab a stack slot */
+ asm ("fstcw (%esp)"); /* get 387 control word */
+ asm ("movl (%esp),%eax"); /* save old value */
+ asm ("orl $0x3f,%eax"); /* mask all exceptions */
+ asm ("pushl %eax");
+ asm ("fldcw (%esp)"); /* load new value into 387 */
+
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldt (%eax)"); /* push extended number on 387 stack */
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpl (%eax)"); /* pop double */
+ asm ("fwait");
+
+ asm ("popl %eax"); /* flush modified control word */
+ asm ("fnclex"); /* clear exceptions */
+ asm ("fldcw (%esp)"); /* restore original control word */
+ asm ("popl %eax"); /* flush saved copy */
+}
+
+double_to_i387 (from, to)
+ char *from;
+ char *to;
+{
+ /* push double mode on 387 stack, then pop in extended mode
+ * no errors are possible because every 64-bit pattern
+ * can be converted to an extended
+ */
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldl (%eax)");
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpt (%eax)");
+ asm ("fwait");
+}
+
+struct env387
+{
+ unsigned short control;
+ unsigned short r0;
+ unsigned short status;
+ unsigned short r1;
+ unsigned short tag;
+ unsigned short r2;
+ unsigned long eip;
+ unsigned short code_seg;
+ unsigned short opcode;
+ unsigned long operand;
+ unsigned short operand_seg;
+ unsigned short r3;
+ unsigned char regs[8][10];
+};
+
+void
+print_387_control_word (control)
+unsigned int control;
+{
+ printf ("control 0x%04x: ", control);
+ printf ("compute to ");
+ switch ((control >> 8) & 3)
+ {
+ case 0: printf ("24 bits; "); break;
+ case 1: printf ("(bad); "); break;
+ case 2: printf ("53 bits; "); break;
+ case 3: printf ("64 bits; "); break;
+ }
+ printf ("round ");
+ switch ((control >> 10) & 3)
+ {
+ case 0: printf ("NEAREST; "); break;
+ case 1: printf ("DOWN; "); break;
+ case 2: printf ("UP; "); break;
+ case 3: printf ("CHOP; "); break;
+ }
+ if (control & 0x3f)
+ {
+ printf ("mask:");
+ if (control & 0x0001) printf (" INVALID");
+ if (control & 0x0002) printf (" DENORM");
+ if (control & 0x0004) printf (" DIVZ");
+ if (control & 0x0008) printf (" OVERF");
+ if (control & 0x0010) printf (" UNDERF");
+ if (control & 0x0020) printf (" LOS");
+ printf (";");
+ }
+ printf ("\n");
+ if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
+ control & 0xe080);
+}
+
+void
+print_387_status_word (status)
+ unsigned int status;
+{
+ printf ("status 0x%04x: ", status);
+ if (status & 0xff)
+ {
+ printf ("exceptions:");
+ if (status & 0x0001) printf (" INVALID");
+ if (status & 0x0002) printf (" DENORM");
+ if (status & 0x0004) printf (" DIVZ");
+ if (status & 0x0008) printf (" OVERF");
+ if (status & 0x0010) printf (" UNDERF");
+ if (status & 0x0020) printf (" LOS");
+ if (status & 0x0040) printf (" FPSTACK");
+ printf ("; ");
+ }
+ printf ("flags: %d%d%d%d; ",
+ (status & 0x4000) != 0,
+ (status & 0x0400) != 0,
+ (status & 0x0200) != 0,
+ (status & 0x0100) != 0);
+
+ printf ("top %d\n", (status >> 11) & 7);
+}
+
+static
+print_387_status (status, ep)
+ unsigned short status;
+ struct env387 *ep;
+{
+ int i;
+ int bothstatus;
+ int top;
+ int fpreg;
+ unsigned char *p;
+
+ bothstatus = ((status != 0) && (ep->status != 0));
+ if (status != 0)
+ {
+ if (bothstatus)
+ printf ("u: ");
+ print_387_status_word ((unsigned int)status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word ((unsigned int)ep->status);
+ }
+
+ print_387_control_word ((unsigned int)ep->control);
+ printf ("last exception: ");
+ printf ("opcode 0x%x; ", ep->opcode);
+ printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
+ printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
+
+ top = (ep->status >> 11) & 7;
+
+ printf (" regno tag msb lsb value\n");
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int st_regno;
+ double val;
+
+ /* The physical regno `fpreg' is only relevant as an index into the
+ * tag word. Logical `%st' numbers are required for indexing `p->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 0x7;
+
+ printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
+
+ switch ((ep->tag >> (fpreg * 2)) & 3)
+ {
+ case 0: printf ("valid "); break;
+ case 1: printf ("zero "); break;
+ case 2: printf ("trap "); break;
+ case 3: printf ("empty "); break;
+ }
+ for (i = 9; i >= 0; i--)
+ printf ("%02x", ep->regs[st_regno][i]);
+
+ i387_to_double (ep->regs[st_regno], (char *)&val);
+ printf (" %g\n", val);
+ }
+}
+
+i386_float_info ()
+{
+ struct user u; /* just for address computations */
+ int i;
+ /* fpstate defined in <sys/user.h> */
+ struct fpstate *fpstatep;
+ char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
+ unsigned int uaddr;
+ char fpvalid;
+ unsigned int rounded_addr;
+ unsigned int rounded_size;
+ /*extern int corechan;*/
+ int skip;
+ extern int inferior_pid;
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (inferior_pid)
+ {
+ int *ip;
+
+ rounded_addr = uaddr & -sizeof (int);
+ rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
+ sizeof (int) - 1) / sizeof (int);
+ skip = uaddr - rounded_addr;
+
+ ip = (int *)buf;
+ for (i = 0; i < rounded_size; i++)
+ {
+ *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ rounded_addr += sizeof (int);
+ }
+ }
+ else
+ {
+ printf("float info: can't do a core file (yet)\n");
+
+ return;
+#if 0
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror_with_name ("seek on core file");
+ if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
+ perror_with_name ("read from core file");
+ skip = 0;
+#endif
+ }
+
+ print_387_status (0, (struct env387 *)buf);
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/freebsd-solib.c b/gnu/usr.bin/gdb/gdb/freebsd-solib.c
new file mode 100644
index 000000000000..5b6e4c07309d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/freebsd-solib.c
@@ -0,0 +1,1469 @@
+/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* modified for FreeBSD, since the names in link.h are totally different!
+ 6.1.94 */
+
+#include "defs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+#ifndef SVR4_SHARED_LIBS
+ /* SunOS shared libs need the nlist structure. */
+#include <a.out.h>
+#endif
+#include <link.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "target.h"
+#include "frame.h"
+#include "regex.h"
+#include "inferior.h"
+#include "language.h"
+
+#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */
+
+/* On SVR4 systems, for the initial implementation, use some runtime startup
+ symbol as the "startup mapping complete" breakpoint address. The models
+ for SunOS and SVR4 dynamic linking debugger support are different in that
+ SunOS hits one breakpoint when all mapping is complete while using the SVR4
+ debugger support takes two breakpoint hits for each file mapped, and
+ there is no way to know when the "last" one is hit. Both these
+ mechanisms should be tied to a "breakpoint service routine" that
+ gets automatically executed whenever one of the breakpoints indicating
+ a change in mapping is hit. This is a future enhancement. (FIXME) */
+
+#define BKPT_AT_SYMBOL 1
+
+#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS)
+static char *bkpt_names[] = {
+#ifdef SOLIB_BKPT_NAME
+ SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */
+#endif
+ "_start",
+ "main",
+ NULL
+};
+#endif
+
+/* local data declarations */
+
+#ifndef SVR4_SHARED_LIBS
+
+#define DEBUG_BASE "_DYNAMIC"
+#ifdef OLD_FreeBSD_LD
+#define LM_ADDR(so) ((so) -> lm.lm_addr)
+#define LM_NEXT(so) ((so) -> lm.lm_next)
+#define LM_NAME(so) ((so) -> lm.lm_name)
+static struct link_dynamic dynamic_copy;
+static struct link_dynamic_2 ld_2_copy;
+static struct ld_debug debug_copy;
+#else
+#define LM_ADDR(so) ((so) -> lm.som_addr)
+#define LM_NEXT(so) ((so) -> lm.som_next)
+#define LM_NAME(so) ((so) -> lm.som_path)
+static struct _dynamic dynamic_copy;
+static struct section_dispatch_table ld_2_copy;
+static struct so_debug debug_copy;
+#endif
+static CORE_ADDR debug_addr;
+static CORE_ADDR flag_addr;
+
+#else /* SVR4_SHARED_LIBS */
+
+#define DEBUG_BASE "_r_debug"
+#define LM_ADDR(so) ((so) -> lm.l_addr)
+#define LM_NEXT(so) ((so) -> lm.l_next)
+#define LM_NAME(so) ((so) -> lm.l_name)
+static struct r_debug debug_copy;
+char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */
+
+#endif /* !SVR4_SHARED_LIBS */
+
+struct so_list {
+ struct so_list *next; /* next structure in linked list */
+#ifdef OLD_FreeBSD_LD
+ struct link_map lm; /* copy of link map from inferior */
+ struct link_map *lmaddr; /* addr in inferior lm was read from */
+#else
+ struct so_map lm; /* copy of link map from inferior */
+ struct so_map *lmaddr; /* addr in inferior lm was read from */
+#endif
+ CORE_ADDR lmend; /* upper addr bound of mapped object */
+ char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */
+ char symbols_loaded; /* flag: symbols read in yet? */
+ char from_tty; /* flag: print msgs? */
+ struct objfile *objfile; /* objfile for loaded lib */
+ struct section_table *sections;
+ struct section_table *sections_end;
+ struct section_table *textsection;
+ bfd *abfd;
+};
+
+static struct so_list *so_list_head; /* List of known shared objects */
+static CORE_ADDR debug_base; /* Base of dynamic linker structures */
+static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
+
+extern int
+fdmatch PARAMS ((int, int)); /* In libiberty */
+
+/* Local function prototypes */
+
+static void
+special_symbol_handling PARAMS ((struct so_list *));
+
+static void
+sharedlibrary_command PARAMS ((char *, int));
+
+static int
+enable_break PARAMS ((void));
+
+static int
+disable_break PARAMS ((void));
+
+static void
+info_sharedlibrary_command PARAMS ((char *, int));
+
+static int
+symbol_add_stub PARAMS ((char *));
+
+static struct so_list *
+find_solib PARAMS ((struct so_list *));
+
+#ifdef OLD_FreeBSD_LD
+static struct link_map *
+#else
+static struct so_map *
+#endif
+first_link_map_member PARAMS ((void));
+
+static CORE_ADDR
+locate_base PARAMS ((void));
+
+static void
+solib_map_sections PARAMS ((struct so_list *));
+
+#ifdef SVR4_SHARED_LIBS
+
+static int
+look_for_base PARAMS ((int, CORE_ADDR));
+
+static CORE_ADDR
+bfd_lookup_symbol PARAMS ((bfd *, char *));
+
+#else
+
+static void
+solib_add_common_symbols PARAMS ((struct rt_symbol *, struct objfile *));
+
+#endif
+
+/*
+
+LOCAL FUNCTION
+
+ solib_map_sections -- open bfd and build sections for shared lib
+
+SYNOPSIS
+
+ static void solib_map_sections (struct so_list *so)
+
+DESCRIPTION
+
+ Given a pointer to one of the shared objects in our list
+ of mapped objects, use the recorded name to open a bfd
+ descriptor for the object, build a section table, and then
+ relocate all the section addresses by the base address at
+ which the shared object was mapped.
+
+FIXMES
+
+ In most (all?) cases the shared object file name recorded in the
+ dynamic linkage tables will be a fully qualified pathname. For
+ cases where it isn't, do we really mimic the systems search
+ mechanism correctly in the below code (particularly the tilde
+ expansion stuff?).
+ */
+
+static void
+solib_map_sections (so)
+ struct so_list *so;
+{
+ char *filename;
+ char *scratch_pathname;
+ int scratch_chan;
+ struct section_table *p;
+ struct cleanup *old_chain;
+ bfd *abfd;
+
+ filename = tilde_expand (so -> so_name);
+ old_chain = make_cleanup (free, filename);
+
+ scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &scratch_pathname);
+ if (scratch_chan < 0)
+ {
+ scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename,
+ O_RDONLY, 0, &scratch_pathname);
+ }
+ if (scratch_chan < 0)
+ {
+ perror_with_name (filename);
+ }
+ /* Leave scratch_pathname allocated. abfd->name will point to it. */
+
+ abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
+ if (!abfd)
+ {
+ close (scratch_chan);
+ error ("Could not open `%s' as an executable file: %s",
+ scratch_pathname, bfd_errmsg (bfd_error));
+ }
+ /* Leave bfd open, core_xfer_memory and "info files" need it. */
+ so -> abfd = abfd;
+ abfd -> cacheable = true;
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ error ("\"%s\": not in executable format: %s.",
+ scratch_pathname, bfd_errmsg (bfd_error));
+ }
+ if (build_section_table (abfd, &so -> sections, &so -> sections_end))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ bfd_get_filename (exec_bfd), bfd_errmsg (bfd_error));
+ }
+
+ for (p = so -> sections; p < so -> sections_end; p++)
+ {
+ /* Relocate the section binding addresses as recorded in the shared
+ object's file by the base address to which the object was actually
+ mapped. */
+ p -> addr += (CORE_ADDR) LM_ADDR (so);
+ p -> endaddr += (CORE_ADDR) LM_ADDR (so);
+ so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend);
+ if (STREQ (p -> sec_ptr -> name, ".text"))
+ {
+ so -> textsection = p;
+ }
+ }
+
+ /* Free the file names, close the file now. */
+ do_cleanups (old_chain);
+}
+
+/* Read all dynamically loaded common symbol definitions from the inferior
+ and add them to the minimal symbol table for the shared library objfile. */
+
+#ifndef SVR4_SHARED_LIBS
+
+/* In GDB 4.9 this routine was a real performance hog. According to
+ some gprof data which mtranle@paris.IntelliCorp.COM (Minh Tran-Le)
+ sent, almost all the time spend in solib_add (up to 20 minutes with
+ 35 shared libraries) was spent here, with 5/6 in
+ lookup_minimal_symbol and 1/6 in read_memory.
+
+ To fix this, we moved the call to special_symbol_handling out of the
+ loop in solib_add, so this only gets called once, rather than once
+ for every shared library, and also removed the call to lookup_minimal_symbol
+ in this routine. */
+
+static void
+solib_add_common_symbols (rtc_symp, objfile)
+ struct rt_symbol *rtc_symp;
+ struct objfile *objfile;
+{
+ struct rt_symbol inferior_rtc_symb;
+ struct nzlist inferior_rtc_nzlist;
+ int len;
+ char *name;
+ char *origname;
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ while (rtc_symp)
+ {
+ read_memory ((CORE_ADDR) rtc_symp,
+ (char *) &inferior_rtc_symb,
+ sizeof (inferior_rtc_symb));
+ read_memory ((CORE_ADDR) inferior_rtc_symb.rt_sp,
+ (char *) &inferior_rtc_nzlist,
+ sizeof(inferior_rtc_nzlist));
+ if (inferior_rtc_nzlist.nz_type == N_COMM)
+ {
+ /* FIXME: The length of the symbol name is not available, but in the
+ current implementation the common symbol is allocated immediately
+ behind the name of the symbol. */
+ len = inferior_rtc_nzlist.nz_value - inferior_rtc_nzlist.nz_strx;
+
+ origname = name = xmalloc (len);
+ read_memory ((CORE_ADDR) inferior_rtc_nzlist.nz_name, name, len);
+
+ /* Don't enter the symbol twice if the target is re-run. */
+
+ if (name[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ {
+ name++;
+ }
+
+#if 0
+ /* I think this is unnecessary, GDB can probably deal with
+ duplicate minimal symbols, more or less. And the duplication
+ which used to happen because this was called for each shared
+ library is gone now that we are just called once. */
+ /* FIXME: Do we really want to exclude symbols which happen
+ to match symbols for other locations in the inferior's
+ address space, even when they are in different linkage units? */
+ if (lookup_minimal_symbol (name, (struct objfile *) NULL) == NULL)
+#endif
+ {
+ name = obsavestring (name, strlen (name),
+ &objfile -> symbol_obstack);
+ prim_record_minimal_symbol (name, inferior_rtc_nzlist.nz_value,
+ mst_bss);
+ }
+ free (origname);
+ }
+ rtc_symp = inferior_rtc_symb.rt_next;
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+}
+
+#endif /* SVR4_SHARED_LIBS */
+
+#ifdef SVR4_SHARED_LIBS
+
+/*
+
+LOCAL FUNCTION
+
+ bfd_lookup_symbol -- lookup the value for a specific symbol
+
+SYNOPSIS
+
+ CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
+
+DESCRIPTION
+
+ An expensive way to lookup the value of a single symbol for
+ bfd's that are only temporary anyway. This is used by the
+ shared library support to find the address of the debugger
+ interface structures in the shared library.
+
+ Note that 0 is specifically allowed as an error return (no
+ such symbol).
+
+ FIXME: See if there is a less "expensive" way of doing this.
+ Also see if there is already another bfd or gdb function
+ that specifically does this, and if so, use it.
+*/
+
+static CORE_ADDR
+bfd_lookup_symbol (abfd, symname)
+ bfd *abfd;
+ char *symname;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr = 0;
+
+ storage_needed = get_symtab_upper_bound (abfd);
+
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, (PTR)symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+ if (STREQ (sym -> name, symname))
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+ return (symaddr);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ look_for_base -- examine file for each mapped address segment
+
+SYNOPSYS
+
+ static int look_for_base (int fd, CORE_ADDR baseaddr)
+
+DESCRIPTION
+
+ This function is passed to proc_iterate_over_mappings, which
+ causes it to get called once for each mapped address space, with
+ an open file descriptor for the file mapped to that space, and the
+ base address of that mapped space.
+
+ Our job is to find the symbol DEBUG_BASE in the file that this
+ fd is open on, if it exists, and if so, initialize the dynamic
+ linker structure base address debug_base.
+
+ Note that this is a computationally expensive proposition, since
+ we basically have to open a bfd on every call, so we specifically
+ avoid opening the exec file.
+ */
+
+static int
+look_for_base (fd, baseaddr)
+ int fd;
+ CORE_ADDR baseaddr;
+{
+ bfd *interp_bfd;
+ CORE_ADDR address;
+
+ /* If the fd is -1, then there is no file that corresponds to this
+ mapped memory segment, so skip it. Also, if the fd corresponds
+ to the exec file, skip it as well. */
+
+ if ((fd == -1) || fdmatch (fileno ((FILE *)(exec_bfd -> iostream)), fd))
+ {
+ return (0);
+ }
+
+ /* Try to open whatever random file this fd corresponds to. Note that
+ we have no way currently to find the filename. Don't gripe about
+ any problems we might have, just fail. */
+
+ if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL)
+ {
+ return (0);
+ }
+ if (!bfd_check_format (interp_bfd, bfd_object))
+ {
+ bfd_close (interp_bfd);
+ return (0);
+ }
+
+ /* Now try to find our DEBUG_BASE symbol in this file, which we at
+ least know to be a valid ELF executable or shared library. */
+
+ if ((address = bfd_lookup_symbol (interp_bfd, DEBUG_BASE)) == 0)
+ {
+ bfd_close (interp_bfd);
+ return (0);
+ }
+
+ /* Eureka! We found the symbol. But now we may need to relocate it
+ by the base address. If the symbol's value is less than the base
+ address of the shared library, then it hasn't yet been relocated
+ by the dynamic linker, and we have to do it ourself. FIXME: Note
+ that we make the assumption that the first segment that corresponds
+ to the shared library has the base address to which the library
+ was relocated. */
+
+ if (address < baseaddr)
+ {
+ address += baseaddr;
+ }
+ debug_base = address;
+ bfd_close (interp_bfd);
+ return (1);
+}
+
+#endif
+
+/*
+
+LOCAL FUNCTION
+
+ locate_base -- locate the base address of dynamic linker structs
+
+SYNOPSIS
+
+ CORE_ADDR locate_base (void)
+
+DESCRIPTION
+
+ For both the SunOS and SVR4 shared library implementations, if the
+ inferior executable has been linked dynamically, there is a single
+ address somewhere in the inferior's data space which is the key to
+ locating all of the dynamic linker's runtime structures. This
+ address is the value of the symbol defined by the macro DEBUG_BASE.
+ The job of this function is to find and return that address, or to
+ return 0 if there is no such address (the executable is statically
+ linked for example).
+
+ For SunOS, the job is almost trivial, since the dynamic linker and
+ all of it's structures are statically linked to the executable at
+ link time. Thus the symbol for the address we are looking for has
+ already been added to the minimal symbol table for the executable's
+ objfile at the time the symbol file's symbols were read, and all we
+ have to do is look it up there. Note that we explicitly do NOT want
+ to find the copies in the shared library.
+
+ The SVR4 version is much more complicated because the dynamic linker
+ and it's structures are located in the shared C library, which gets
+ run as the executable's "interpreter" by the kernel. We have to go
+ to a lot more work to discover the address of DEBUG_BASE. Because
+ of this complexity, we cache the value we find and return that value
+ on subsequent invocations. Note there is no copy in the executable
+ symbol tables.
+
+ Note that we can assume nothing about the process state at the time
+ we need to find this address. We may be stopped on the first instruc-
+ tion of the interpreter (C shared library), the first instruction of
+ the executable itself, or somewhere else entirely (if we attached
+ to the process for example).
+
+ */
+
+static CORE_ADDR
+locate_base ()
+{
+
+#ifndef SVR4_SHARED_LIBS
+
+ struct minimal_symbol *msymbol;
+ CORE_ADDR address = 0;
+
+ /* For SunOS, we want to limit the search for DEBUG_BASE to the executable
+ being debugged, since there is a duplicate named symbol in the shared
+ library. We don't want the shared library versions. */
+
+ msymbol = lookup_minimal_symbol (DEBUG_BASE, symfile_objfile);
+ if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ {
+ address = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ return (address);
+
+#else /* SVR4_SHARED_LIBS */
+
+ /* Check to see if we have a currently valid address, and if so, avoid
+ doing all this work again and just return the cached address. If
+ we have no cached address, ask the /proc support interface to iterate
+ over the list of mapped address segments, calling look_for_base() for
+ each segment. When we are done, we will have either found the base
+ address or not. */
+
+ if (debug_base == 0)
+ {
+ proc_iterate_over_mappings (look_for_base);
+ }
+ return (debug_base);
+
+#endif /* !SVR4_SHARED_LIBS */
+
+}
+
+/*
+
+LOCAL FUNCTION
+
+ first_link_map_member -- locate first member in dynamic linker's map
+
+SYNOPSIS
+
+ static struct link_map *first_link_map_member (void)
+
+DESCRIPTION
+
+ Read in a copy of the first member in the inferior's dynamic
+ link map from the inferior's dynamic linker structures, and return
+ a pointer to the copy in our address space.
+*/
+
+#ifdef OLD_FreeBSD_LD
+static struct link_map *
+#else
+static struct so_map *
+#endif
+first_link_map_member ()
+{
+#ifdef OLD_FreeBSD_LD
+ struct link_map *lm = NULL;
+#else
+ struct so_map *lm = NULL;
+#endif
+
+#ifndef SVR4_SHARED_LIBS
+
+ read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy));
+#ifdef OLD_FreeBSD_LD
+ if (dynamic_copy.ld_version >= 2)
+ {
+ /* It is a version that we can deal with, so read in the secondary
+ structure and find the address of the link map list from it. */
+ read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy,
+ sizeof (struct link_dynamic_2));
+ lm = ld_2_copy.ld_loaded;
+ }
+#else
+ if (dynamic_copy.d_version >= 2)
+ {
+ /* It is a version that we can deal with, so read in the secondary
+ structure and find the address of the link map list from it. */
+ read_memory ((CORE_ADDR) dynamic_copy.d_un.d_sdt, (char *) &ld_2_copy,
+ sizeof (struct section_dispatch_table));
+ lm = ld_2_copy.sdt_loaded;
+ }
+#endif
+#else /* SVR4_SHARED_LIBS */
+
+ read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug));
+ /* FIXME: Perhaps we should validate the info somehow, perhaps by
+ checking r_version for a known version number, or r_state for
+ RT_CONSISTENT. */
+ lm = debug_copy.r_map;
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ return (lm);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ find_solib -- step through list of shared objects
+
+SYNOPSIS
+
+ struct so_list *find_solib (struct so_list *so_list_ptr)
+
+DESCRIPTION
+
+ This module contains the routine which finds the names of any
+ loaded "images" in the current process. The argument in must be
+ NULL on the first call, and then the returned value must be passed
+ in on subsequent calls. This provides the capability to "step" down
+ the list of loaded objects. On the last object, a NULL value is
+ returned.
+
+ The arg and return value are "struct link_map" pointers, as defined
+ in <link.h>.
+ */
+
+static struct so_list *
+find_solib (so_list_ptr)
+ struct so_list *so_list_ptr; /* Last lm or NULL for first one */
+{
+ struct so_list *so_list_next = NULL;
+#ifdef OLD_FreeBSD_LD
+ struct link_map *lm = NULL;
+#else
+ struct so_map *lm = NULL;
+#endif
+ struct so_list *new;
+
+ if (so_list_ptr == NULL)
+ {
+ /* We are setting up for a new scan through the loaded images. */
+ if ((so_list_next = so_list_head) == NULL)
+ {
+ /* We have not already read in the dynamic linking structures
+ from the inferior, lookup the address of the base structure. */
+ debug_base = locate_base ();
+ if (debug_base != 0)
+ {
+ /* Read the base structure in and find the address of the first
+ link map list member. */
+ lm = first_link_map_member ();
+ }
+ }
+ }
+ else
+ {
+ /* We have been called before, and are in the process of walking
+ the shared library list. Advance to the next shared object. */
+ if ((lm = LM_NEXT (so_list_ptr)) == NULL)
+ {
+ /* We have hit the end of the list, so check to see if any were
+ added, but be quiet if we can't read from the target any more. */
+ int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr,
+ (char *) &(so_list_ptr -> lm),
+#ifdef OLD_FreeBSD_LD
+ sizeof (struct link_map));
+#else
+ sizeof (struct so_map));
+#endif
+ if (status == 0)
+ {
+ lm = LM_NEXT (so_list_ptr);
+ }
+ else
+ {
+ lm = NULL;
+ }
+ }
+ so_list_next = so_list_ptr -> next;
+ }
+ if ((so_list_next == NULL) && (lm != NULL))
+ {
+ /* Get next link map structure from inferior image and build a local
+ abbreviated load_map structure */
+ new = (struct so_list *) xmalloc (sizeof (struct so_list));
+ memset ((char *) new, 0, sizeof (struct so_list));
+ new -> lmaddr = lm;
+ /* Add the new node as the next node in the list, or as the root
+ node if this is the first one. */
+ if (so_list_ptr != NULL)
+ {
+ so_list_ptr -> next = new;
+ }
+ else
+ {
+ so_list_head = new;
+ }
+ so_list_next = new;
+ read_memory ((CORE_ADDR) lm, (char *) &(new -> lm),
+#ifdef OLD_FreeBSD_LD
+ sizeof (struct link_map));
+#else
+ sizeof (struct so_map));
+#endif
+ /* For the SVR4 version, there is one entry that has no name
+ (for the inferior executable) since it is not a shared object. */
+ if (LM_NAME (new) != 0)
+ {
+ if (!target_read_string((CORE_ADDR) LM_NAME (new), new -> so_name,
+ MAX_PATH_SIZE - 1))
+ error ("find_solib: Can't read pathname for load map\n");
+ new -> so_name[MAX_PATH_SIZE - 1] = 0;
+ solib_map_sections (new);
+ }
+ }
+ return (so_list_next);
+}
+
+/* A small stub to get us past the arg-passing pinhole of catch_errors. */
+
+static int
+symbol_add_stub (arg)
+ char *arg;
+{
+ register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
+
+ so -> objfile = symbol_file_add (so -> so_name, so -> from_tty,
+ (unsigned int) so -> textsection -> addr,
+ 0, 0, 0);
+ return (1);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_add -- add a shared library file to the symtab and section list
+
+SYNOPSIS
+
+ void solib_add (char *arg_string, int from_tty,
+ struct target_ops *target)
+
+DESCRIPTION
+
+*/
+
+void
+solib_add (arg_string, from_tty, target)
+ char *arg_string;
+ int from_tty;
+ struct target_ops *target;
+{
+ register struct so_list *so = NULL; /* link map state variable */
+
+ /* Last shared library that we read. */
+ struct so_list *so_last = NULL;
+
+ char *re_err;
+ int count;
+ int old;
+
+ if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
+ {
+ error ("Invalid regexp: %s", re_err);
+ }
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0] && re_exec (so -> so_name))
+ {
+ so -> from_tty = from_tty;
+ if (so -> symbols_loaded)
+ {
+ if (from_tty)
+ {
+ printf ("Symbols already loaded for %s\n", so -> so_name);
+ }
+ }
+ else if (catch_errors
+ (symbol_add_stub, (char *) so,
+ "Error while reading shared library symbols:\n",
+ RETURN_MASK_ALL))
+ {
+ so_last = so;
+ so -> symbols_loaded = 1;
+ }
+ }
+ }
+
+ /* Now add the shared library sections to the section table of the
+ specified target, if any. */
+ if (target)
+ {
+ /* Count how many new section_table entries there are. */
+ so = NULL;
+ count = 0;
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ count += so -> sections_end - so -> sections;
+ }
+ }
+
+ if (count)
+ {
+ /* Reallocate the target's section table including the new size. */
+ if (target -> to_sections)
+ {
+ old = target -> to_sections_end - target -> to_sections;
+ target -> to_sections = (struct section_table *)
+ xrealloc ((char *)target -> to_sections,
+ (sizeof (struct section_table)) * (count + old));
+ }
+ else
+ {
+ old = 0;
+ target -> to_sections = (struct section_table *)
+ xmalloc ((sizeof (struct section_table)) * count);
+ }
+ target -> to_sections_end = target -> to_sections + (count + old);
+
+ /* Add these section table entries to the target's table. */
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ count = so -> sections_end - so -> sections;
+ memcpy ((char *) (target -> to_sections + old),
+ so -> sections,
+ (sizeof (struct section_table)) * count);
+ old += count;
+ }
+ }
+ }
+ }
+
+ /* Calling this once at the end means that we put all the minimal
+ symbols for commons into the objfile for the last shared library.
+ Since they are in common, this should not be a problem. If we
+ delete the objfile with the minimal symbols, we can put all the
+ symbols into a new objfile (and will on the next call to solib_add).
+
+ An alternate approach would be to create an objfile just for
+ common minsyms, thus not needing any objfile argument to
+ solib_add_common_symbols. */
+
+ if (so_last)
+ special_symbol_handling (so_last);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ info_sharedlibrary_command -- code for "info sharedlibrary"
+
+SYNOPSIS
+
+ static void info_sharedlibrary_command ()
+
+DESCRIPTION
+
+ Walk through the shared library list and print information
+ about each attached library.
+*/
+
+static void
+info_sharedlibrary_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct so_list *so = NULL; /* link map state variable */
+ int header_done = 0;
+
+ if (exec_bfd == NULL)
+ {
+ printf ("No exec file.\n");
+ return;
+ }
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ if (!header_done)
+ {
+ printf("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read",
+ "Shared Object Library");
+ header_done++;
+ }
+ printf ("%-12s",
+ local_hex_string_custom ((unsigned long) LM_ADDR (so),
+ "08l"));
+ printf ("%-12s",
+ local_hex_string_custom ((unsigned long) so -> lmend,
+ "08l"));
+ printf ("%-12s", so -> symbols_loaded ? "Yes" : "No");
+ printf ("%s\n", so -> so_name);
+ }
+ }
+ if (so_list_head == NULL)
+ {
+ printf ("No shared libraries loaded at this time.\n");
+ }
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_address -- check to see if an address is in a shared lib
+
+SYNOPSIS
+
+ int solib_address (CORE_ADDR address)
+
+DESCRIPTION
+
+ Provides a hook for other gdb routines to discover whether or
+ not a particular address is within the mapped address space of
+ a shared library. Any address between the base mapping address
+ and the first address beyond the end of the last mapping, is
+ considered to be within the shared library address space, for
+ our purposes.
+
+ For example, this routine is called at one point to disable
+ breakpoints which are in shared libraries that are not currently
+ mapped in.
+ */
+
+int
+solib_address (address)
+ CORE_ADDR address;
+{
+ register struct so_list *so = 0; /* link map state variable */
+
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ if ((address >= (CORE_ADDR) LM_ADDR (so)) &&
+ (address < (CORE_ADDR) so -> lmend))
+ {
+ return (1);
+ }
+ }
+ }
+ return (0);
+}
+
+/* Called by free_all_symtabs */
+
+void
+clear_solib()
+{
+ struct so_list *next;
+ char *bfd_filename;
+
+ while (so_list_head)
+ {
+ if (so_list_head -> sections)
+ {
+ free ((PTR)so_list_head -> sections);
+ }
+ if (so_list_head -> abfd)
+ {
+ bfd_filename = bfd_get_filename (so_list_head -> abfd);
+ bfd_close (so_list_head -> abfd);
+ }
+ else
+ /* This happens for the executable on SVR4. */
+ bfd_filename = NULL;
+
+ next = so_list_head -> next;
+ if (bfd_filename)
+ free ((PTR)bfd_filename);
+ free ((PTR)so_list_head);
+ so_list_head = next;
+ }
+ debug_base = 0;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ disable_break -- remove the "mapping changed" breakpoint
+
+SYNOPSIS
+
+ static int disable_break ()
+
+DESCRIPTION
+
+ Removes the breakpoint that gets hit when the dynamic linker
+ completes a mapping change.
+
+*/
+
+static int
+disable_break ()
+{
+ int status = 1;
+
+#ifndef SVR4_SHARED_LIBS
+
+ int in_debugger = 0;
+
+ /* Read the debugger structure from the inferior to retrieve the
+ address of the breakpoint and the original contents of the
+ breakpoint address. Remove the breakpoint by writing the original
+ contents back. */
+
+ read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy));
+
+ /* Set `in_debugger' to zero now. */
+
+ write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger));
+
+#ifdef OLD_FreeBSD_LD
+ breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr;
+ write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst,
+ sizeof (debug_copy.ldd_bp_inst));
+#else
+ breakpoint_addr = (CORE_ADDR) debug_copy.dd_bpt_addr;
+ write_memory (breakpoint_addr, (char *) &debug_copy.dd_bpt_shadow,
+ sizeof (debug_copy.dd_bpt_shadow));
+#endif
+
+#else /* SVR4_SHARED_LIBS */
+
+ /* Note that breakpoint address and original contents are in our address
+ space, so we just need to write the original contents back. */
+
+ if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0)
+ {
+ status = 0;
+ }
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ /* For the SVR4 version, we always know the breakpoint address. For the
+ SunOS version we don't know it until the above code is executed.
+ Grumble if we are stopped anywhere besides the breakpoint address. */
+
+ if (stop_pc != breakpoint_addr)
+ {
+ warning ("stopped at unknown breakpoint while handling shared libraries");
+ }
+
+ return (status);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ enable_break -- arrange for dynamic linker to hit breakpoint
+
+SYNOPSIS
+
+ int enable_break (void)
+
+DESCRIPTION
+
+ Both the SunOS and the SVR4 dynamic linkers have, as part of their
+ debugger interface, support for arranging for the inferior to hit
+ a breakpoint after mapping in the shared libraries. This function
+ enables that breakpoint.
+
+ For SunOS, there is a special flag location (in_debugger) which we
+ set to 1. When the dynamic linker sees this flag set, it will set
+ a breakpoint at a location known only to itself, after saving the
+ original contents of that place and the breakpoint address itself,
+ in it's own internal structures. When we resume the inferior, it
+ will eventually take a SIGTRAP when it runs into the breakpoint.
+ We handle this (in a different place) by restoring the contents of
+ the breakpointed location (which is only known after it stops),
+ chasing around to locate the shared libraries that have been
+ loaded, then resuming.
+
+ For SVR4, the debugger interface structure contains a member (r_brk)
+ which is statically initialized at the time the shared library is
+ built, to the offset of a function (_r_debug_state) which is guaran-
+ teed to be called once before mapping in a library, and again when
+ the mapping is complete. At the time we are examining this member,
+ it contains only the unrelocated offset of the function, so we have
+ to do our own relocation. Later, when the dynamic linker actually
+ runs, it relocates r_brk to be the actual address of _r_debug_state().
+
+ The debugger interface structure also contains an enumeration which
+ is set to either RT_ADD or RT_DELETE prior to changing the mapping,
+ depending upon whether or not the library is being mapped or unmapped,
+ and then set to RT_CONSISTENT after the library is mapped/unmapped.
+*/
+
+static int
+enable_break ()
+{
+ int success = 0;
+
+#ifndef SVR4_SHARED_LIBS
+
+ int j;
+ int in_debugger;
+
+ /* Get link_dynamic structure */
+
+ j = target_read_memory (debug_base, (char *) &dynamic_copy,
+ sizeof (dynamic_copy));
+ if (j)
+ {
+ /* unreadable */
+ return (0);
+ }
+
+ /* Calc address of debugger interface structure */
+
+#ifdef OLD_FreeBSD_LD
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+#else
+ debug_addr = (CORE_ADDR) dynamic_copy.d_debug;
+#endif
+
+ /* Calc address of `in_debugger' member of debugger interface structure */
+
+#ifdef OLD_FreeBSD_LD
+ flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger -
+ (char *) &debug_copy);
+#else
+ flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.dd_in_debugger -
+ (char *) &debug_copy);
+#endif
+
+ /* Write a value of 1 to this member. */
+
+ in_debugger = 1;
+ write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger));
+ success = 1;
+
+#else /* SVR4_SHARED_LIBS */
+
+#ifdef BKPT_AT_SYMBOL
+
+ struct minimal_symbol *msymbol;
+ char **bkpt_namep;
+ CORE_ADDR bkpt_addr;
+
+ /* Scan through the list of symbols, trying to look up the symbol and
+ set a breakpoint there. Terminate loop when we/if we succeed. */
+
+ breakpoint_addr = 0;
+ for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++)
+ {
+ msymbol = lookup_minimal_symbol (*bkpt_namep, symfile_objfile);
+ if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ {
+ bkpt_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (target_insert_breakpoint (bkpt_addr, shadow_contents) == 0)
+ {
+ breakpoint_addr = bkpt_addr;
+ success = 1;
+ break;
+ }
+ }
+ }
+
+#else /* !BKPT_AT_SYMBOL */
+
+ struct symtab_and_line sal;
+
+ /* Read the debugger interface structure directly. */
+
+ read_memory (debug_base, (char *) &debug_copy, sizeof (debug_copy));
+
+ /* Set breakpoint at the debugger interface stub routine that will
+ be called just prior to each mapping change and again after the
+ mapping change is complete. Set up the (nonexistent) handler to
+ deal with hitting these breakpoints. (FIXME). */
+
+ warning ("'%s': line %d: missing SVR4 support code", __FILE__, __LINE__);
+ success = 1;
+
+#endif /* BKPT_AT_SYMBOL */
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ return (success);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_create_inferior_hook -- shared library startup support
+
+SYNOPSIS
+
+ void solib_create_inferior_hook()
+
+DESCRIPTION
+
+ When gdb starts up the inferior, it nurses it along (through the
+ shell) until it is ready to execute it's first instruction. At this
+ point, this function gets called via expansion of the macro
+ SOLIB_CREATE_INFERIOR_HOOK.
+
+ For SunOS executables, this first instruction is typically the
+ one at "_start", or a similar text label, regardless of whether
+ the executable is statically or dynamically linked. The runtime
+ startup code takes care of dynamically linking in any shared
+ libraries, once gdb allows the inferior to continue.
+
+ For SVR4 executables, this first instruction is either the first
+ instruction in the dynamic linker (for dynamically linked
+ executables) or the instruction at "start" for statically linked
+ executables. For dynamically linked executables, the system
+ first exec's /lib/libc.so.N, which contains the dynamic linker,
+ and starts it running. The dynamic linker maps in any needed
+ shared libraries, maps in the actual user executable, and then
+ jumps to "start" in the user executable.
+
+ For both SunOS shared libraries, and SVR4 shared libraries, we
+ can arrange to cooperate with the dynamic linker to discover the
+ names of shared libraries that are dynamically linked, and the
+ base addresses to which they are linked.
+
+ This function is responsible for discovering those names and
+ addresses, and saving sufficient information about them to allow
+ their symbols to be read at a later time.
+
+FIXME
+
+ Between enable_break() and disable_break(), this code does not
+ properly handle hitting breakpoints which the user might have
+ set in the startup code or in the dynamic linker itself. Proper
+ handling will probably have to wait until the implementation is
+ changed to use the "breakpoint handler function" method.
+
+ Also, what if child has exit()ed? Must exit loop somehow.
+ */
+
+void
+solib_create_inferior_hook()
+{
+ /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base
+ yet. In fact, in the case of a SunOS4 executable being run on
+ Solaris, we can't get it yet. find_solib will get it when it needs
+ it. */
+#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL))
+ if ((debug_base = locate_base ()) == 0)
+ {
+ /* Can't find the symbol or the executable is statically linked. */
+ return;
+ }
+#endif
+
+ if (!enable_break ())
+ {
+ warning ("shared library handler failed to enable breakpoint");
+ return;
+ }
+
+ /* Now run the target. It will eventually hit the breakpoint, at
+ which point all of the libraries will have been mapped in and we
+ can go groveling around in the dynamic linker structures to find
+ out what we need to know about them. */
+
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+ stop_signal = 0;
+ do
+ {
+ target_resume (-1, 0, stop_signal);
+ wait_for_inferior ();
+ }
+ while (stop_signal != SIGTRAP);
+ stop_soon_quietly = 0;
+
+ /* We are now either at the "mapping complete" breakpoint (or somewhere
+ else, a condition we aren't prepared to deal with anyway), so adjust
+ the PC as necessary after a breakpoint, disable the breakpoint, and
+ add any shared libraries that were mapped in. */
+
+ if (DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+ }
+
+ if (!disable_break ())
+ {
+ warning ("shared library handler failed to disable breakpoint");
+ }
+
+ solib_add ((char *) 0, 0, (struct target_ops *) 0);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ special_symbol_handling -- additional shared library symbol handling
+
+SYNOPSIS
+
+ void special_symbol_handling (struct so_list *so)
+
+DESCRIPTION
+
+ Once the symbols from a shared object have been loaded in the usual
+ way, we are called to do any system specific symbol handling that
+ is needed.
+
+ For Suns, this consists of grunging around in the dynamic linkers
+ structures to find symbol definitions for "common" symbols and
+ adding them to the minimal symbol table for the corresponding
+ objfile.
+
+*/
+
+static void
+special_symbol_handling (so)
+struct so_list *so;
+{
+#ifndef SVR4_SHARED_LIBS
+ int j;
+
+ if (debug_addr == 0)
+ {
+ /* Get link_dynamic structure */
+
+ j = target_read_memory (debug_base, (char *) &dynamic_copy,
+ sizeof (dynamic_copy));
+ if (j)
+ {
+ /* unreadable */
+ return;
+ }
+
+ /* Calc address of debugger interface structure */
+ /* FIXME, this needs work for cross-debugging of core files
+ (byteorder, size, alignment, etc). */
+
+#ifdef OLD_FreeBSD_LD
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+#else
+ debug_addr = (CORE_ADDR) dynamic_copy.d_debug;
+#endif
+ }
+
+ /* Read the debugger structure from the inferior, just to make sure
+ we have a current copy. */
+
+ j = target_read_memory (debug_addr, (char *) &debug_copy,
+ sizeof (debug_copy));
+ if (j)
+ return; /* unreadable */
+
+ /* Get common symbol definitions for the loaded object. */
+
+#ifdef OLD_FreeBSD_LD
+ if (debug_copy.ldd_cp)
+ {
+ solib_add_common_symbols (debug_copy.ldd_cp, so -> objfile);
+ }
+#else
+ if (debug_copy.dd_cc)
+ {
+ solib_add_common_symbols (debug_copy.dd_cc, so -> objfile);
+ }
+#endif
+
+#endif /* !SVR4_SHARED_LIBS */
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ sharedlibrary_command -- handle command to explicitly add library
+
+SYNOPSIS
+
+ static void sharedlibrary_command (char *args, int from_tty)
+
+DESCRIPTION
+
+*/
+
+static void
+sharedlibrary_command (args, from_tty)
+char *args;
+int from_tty;
+{
+ dont_repeat ();
+ solib_add (args, from_tty, (struct target_ops *) 0);
+}
+
+void
+_initialize_solib()
+{
+
+ add_com ("sharedlibrary", class_files, sharedlibrary_command,
+ "Load shared object library symbols for files matching REGEXP.");
+ add_info ("sharedlibrary", info_sharedlibrary_command,
+ "Status of loaded shared object libraries.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/gdb-stabs.h b/gnu/usr.bin/gdb/gdb/gdb-stabs.h
new file mode 100644
index 000000000000..c1e0253842ed
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdb-stabs.h
@@ -0,0 +1,76 @@
+/* Definitions for symbol-reading containing "stabs", for GDB.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file exists to hold the common definitions required of most of
+ the symbol-readers that end up using stabs. The common use of
+ these `symbol-type-specific' customizations of the generic data
+ structures makes the stabs-oriented symbol readers able to call
+ each others' functions as required. */
+
+#if !defined (GDBSTABS_H)
+#define GDBSTABS_H
+
+/* Offsets in the psymtab's section_offsets array for various kinds of
+ stabs symbols. Every psymtab built from stabs will have these offsets
+ filled in by these guidelines, so that when actually reading symbols, the
+ proper offset can simply be selected and added to the symbol value. */
+
+#define SECT_OFF_TEXT 0
+#define SECT_OFF_DATA 1
+#define SECT_OFF_BSS 2
+#define SECT_OFF_RODATA 3
+#define SECT_OFF_MAX 4 /* Count of possible values */
+
+/* The stab_section_info chain remembers info from the ELF symbol table,
+ while psymtabs are being built for the other symbol tables in the
+ objfile. It is destroyed at the complation of psymtab-reading.
+ Any info that was used from it has been copied into psymtabs. */
+
+struct stab_section_info {
+ char *filename;
+ CORE_ADDR sections[SECT_OFF_MAX];
+ struct stab_section_info *next;
+ int found; /* Count of times it's found in searching */
+};
+
+/* Information is passed among various dbxread routines for accessing
+ symbol files. A pointer to this structure is kept in the sym_stab_info
+ field of the objfile struct. */
+
+struct dbx_symfile_info {
+ asection *text_sect; /* Text section accessor */
+ int symcount; /* How many symbols are there in the file */
+ char *stringtab; /* The actual string table */
+ int stringtab_size; /* Its size */
+ file_ptr symtab_offset; /* Offset in file to symbol table */
+ int symbol_size; /* Bytes in a single symbol */
+ struct stab_section_info *stab_section_info; /* section starting points
+ of the original .o files before linking. */
+};
+
+#define DBX_SYMFILE_INFO(o) ((struct dbx_symfile_info *)((o)->sym_stab_info))
+#define DBX_TEXT_SECT(o) (DBX_SYMFILE_INFO(o)->text_sect)
+#define DBX_SYMCOUNT(o) (DBX_SYMFILE_INFO(o)->symcount)
+#define DBX_STRINGTAB(o) (DBX_SYMFILE_INFO(o)->stringtab)
+#define DBX_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->stringtab_size)
+#define DBX_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->symtab_offset)
+#define DBX_SYMBOL_SIZE(o) (DBX_SYMFILE_INFO(o)->symbol_size)
+
+#endif /* GDBSTABS_H */
diff --git a/gnu/usr.bin/gdb/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb/gdb.1
new file mode 100644
index 000000000000..c6219de9c907
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdb.1
@@ -0,0 +1,371 @@
+.\" Copyright (c) 1991 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.1 1994/06/10 13:37:34 paul Exp $
+.TH gdb 1 "4nov1991" "GNU Tools" "GNU Tools"
+.SH NAME
+gdb \- The GNU Debugger
+.SH SYNOPSIS
+.na
+.TP
+.B gdb
+.RB "[\|" \-help "\|]"
+.RB "[\|" \-nx "\|]"
+.RB "[\|" \-q "\|]"
+.RB "[\|" \-batch "\|]"
+.RB "[\|" \-cd=\c
+.I dir\c
+\|]
+.RB "[\|" \-f "\|]"
+.RB "[\|" "\-b\ "\c
+.IR bps "\|]"
+.RB "[\|" "\-tty="\c
+.IR dev "\|]"
+.RB "[\|" "\-s "\c
+.I symfile\c
+\&\|]
+.RB "[\|" "\-e "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-se "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-c "\c
+.I core\c
+\&\|]
+.RB "[\|" "\-x "\c
+.I cmds\c
+\&\|]
+.RB "[\|" "\-d "\c
+.I dir\c
+\&\|]
+.RB "[\|" \c
+.I prog\c
+.RB "[\|" \c
+.IR core \||\| procID\c
+\&\|]\&\|]
+.ad b
+.SH DESCRIPTION
+The purpose of a debugger such as GDB is to allow you to see what is
+going on ``inside'' another program while it executes\(em\&or what another
+program was doing at the moment it crashed.
+
+GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+.TP
+\ \ \ \(bu
+Start your program, specifying anything that might affect its behavior.
+
+.TP
+\ \ \ \(bu
+Make your program stop on specified conditions.
+
+.TP
+\ \ \ \(bu
+Examine what has happened, when your program has stopped.
+
+.TP
+\ \ \ \(bu
+Change things in your program, so you can experiment with correcting the
+effects of one bug and go on to learn about another.
+.PP
+
+You can use GDB to debug programs written in C, C++, and Modula-2.
+Fortran support will be added when a GNU Fortran compiler is ready.
+
+GDB is invoked with the shell command \c
+.B gdb\c
+\&. Once started, it reads
+commands from the terminal until you tell it to exit with the GDB
+command \c
+.B quit\c
+\&. You can get online help from \c
+.B gdb\c
+\& itself
+by using the command \c
+.B help\c
+\&.
+
+You can run \c
+.B gdb\c
+\& with no arguments or options; but the most
+usual way to start GDB is with one argument or two, specifying an
+executable program as the argument:
+.sp
+.br
+gdb\ program
+.br
+.sp
+
+You can also start with both an executable program and a core file specified:
+.sp
+.br
+gdb\ program\ core
+.br
+.sp
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+.sp
+.br
+gdb\ program\ 1234
+.br
+.sp
+
+would attach GDB to process \c
+.B 1234\c
+\& (unless you also have a file
+named `\|\c
+.B 1234\c
+\&\|'; GDB does check for a core file first).
+
+Here are some of the most frequently needed GDB commands:
+.TP
+.B break \fR[\|\fIfile\fB:\fR\|]\fIfunction
+\&
+Set a breakpoint at \c
+.I function\c
+\& (in \c
+.I file\c
+\&).
+.TP
+.B run \fR[\|\fIarglist\fR\|]
+Start your program (with \c
+.I arglist\c
+\&, if specified).
+.TP
+.B bt
+Backtrace: display the program stack.
+.TP
+.BI print " expr"\c
+\&
+Display the value of an expression.
+.TP
+.B c
+Continue running your program (after stopping, e.g. at a breakpoint).
+.TP
+.B next
+Execute next program line (after stopping); step \c
+.I over\c
+\& any
+function calls in the line.
+.TP
+.B step
+Execute next program line (after stopping); step \c
+.I into\c
+\& any
+function calls in the line.
+.TP
+.B help \fR[\|\fIname\fR\|]
+Show information about GDB command \c
+.I name\c
+\&, or general information
+about using GDB.
+.TP
+.B quit
+Exit from GDB.
+.PP
+For full details on GDB, see \c
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+\&, by Richard M. Stallman and Roland H. Pesch. The same text is available online
+as the \c
+.B gdb\c
+\& entry in the \c
+.B info\c
+\& program.
+.SH OPTIONS
+Any arguments other than options specify an executable
+file and core file (or process ID); that is, the first argument
+encountered with no
+associated option flag is equivalent to a `\|\c
+.B \-se\c
+\&\|' option, and the
+second, if any, is equivalent to a `\|\c
+.B \-c\c
+\&\|' option if it's the name of a file. Many options have
+both long and short forms; both are shown here. The long forms are also
+recognized if you truncate them, so long as enough of the option is
+present to be unambiguous. (If you prefer, you can flag option
+arguments with `\|\c
+.B +\c
+\&\|' rather than `\|\c
+.B \-\c
+\&\|', though we illustrate the
+more usual convention.)
+
+All the options and command line arguments you give are processed
+in sequential order. The order makes a difference when the
+`\|\c
+.B \-x\c
+\&\|' option is used.
+
+.TP
+.B \-help
+.TP
+.B \-h
+List all options, with brief explanations.
+
+.TP
+.BI "\-symbols=" "file"\c
+.TP
+.BI "\-s " "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-exec=" "file"\c
+.TP
+.BI "\-e " "file"\c
+\&
+Use file \c
+.I file\c
+\& as the executable file to execute when
+appropriate, and for examining pure data in conjunction with a core
+dump.
+
+.TP
+.BI "\-se=" "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\& and use it as the executable
+file.
+
+.TP
+.BI "\-core=" "file"\c
+.TP
+.BI "\-c " "file"\c
+\&
+Use file \c
+.I file\c
+\& as a core dump to examine.
+
+.TP
+.BI "\-command=" "file"\c
+.TP
+.BI "\-x " "file"\c
+\&
+Execute GDB commands from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-directory=" "directory"\c
+.TP
+.BI "\-d " "directory"\c
+\&
+Add \c
+.I directory\c
+\& to the path to search for source files.
+.PP
+
+.TP
+.B \-nx
+.TP
+.B \-n
+Do not execute commands from any `\|\c
+.B .gdbinit\c
+\&\|' initialization files.
+Normally, the commands in these files are executed after all the
+command options and arguments have been processed.
+
+
+.TP
+.B \-quiet
+.TP
+.B \-q
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+.TP
+.B \-batch
+Run in batch mode. Exit with status \c
+.B 0\c
+\& after processing all the command
+files specified with `\|\c
+.B \-x\c
+\&\|' (and `\|\c
+.B .gdbinit\c
+\&\|', if not inhibited).
+Exit with nonzero status if an error occurs in executing the GDB
+commands in the command files.
+
+Batch mode may be useful for running GDB as a filter, for example to
+download and run a program on another computer; in order to make this
+more useful, the message
+.sp
+.br
+Program\ exited\ normally.
+.br
+.sp
+
+(which is ordinarily issued whenever a program running under GDB control
+terminates) is not issued when running in batch mode.
+
+.TP
+.BI "\-cd=" "directory"\c
+\&
+Run GDB using \c
+.I directory\c
+\& as its working directory,
+instead of the current directory.
+
+.TP
+.B \-fullname
+.TP
+.B \-f
+Emacs sets this option when it runs GDB as a subprocess. It tells GDB
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time the program stops). This recognizable format looks
+like two `\|\c
+.B \032\c
+\&\|' characters, followed by the file name, line number
+and character position separated by colons, and a newline. The
+Emacs-to-GDB interface program uses the two `\|\c
+.B \032\c
+\&\|' characters as
+a signal to display the source code for the frame.
+
+.TP
+.BI "\-b " "bps"\c
+\&
+Set the line speed (baud rate or bits per second) of any serial
+interface used by GDB for remote debugging.
+
+.TP
+.BI "\-tty=" "device"\c
+\&
+Run using \c
+.I device\c
+\& for your program's standard input and output.
+.PP
+
+.SH "SEE ALSO"
+.RB "`\|" gdb "\|'"
+entry in
+.B info\c
+\&;
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+, Richard M. Stallman and Roland H. Pesch, July 1991.
+.SH COPYING
+Copyright (c) 1991 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/gnu/usr.bin/gdb/gdb/gdbcmd.h b/gnu/usr.bin/gdb/gdb/gdbcmd.h
new file mode 100644
index 000000000000..88f323c73602
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbcmd.h
@@ -0,0 +1,101 @@
+/* Header file for GDB-specific command-line stuff.
+ Copyright 1986, 1989, 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (GDBCMD_H)
+#define GDBCMD_H 1
+
+#include "command.h"
+
+/* Chain containing all defined commands. */
+
+extern struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+extern struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+extern struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+extern struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+extern struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+extern struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+extern struct cmd_list_element *setlist;
+
+/* Chain containing all defined unset subcommands */
+
+extern struct cmd_list_element *unsetlist;
+
+/* Chain containing all defined show subcommands. */
+
+extern struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\". */
+
+extern struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\". */
+
+extern struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+extern struct cmd_list_element *unsethistlist;
+
+/* Chain containing all defined maintenance subcommands. */
+
+extern struct cmd_list_element *maintenancelist;
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+extern struct cmd_list_element *maintenanceinfolist;
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+extern struct cmd_list_element *maintenanceprintlist;
+
+extern struct cmd_list_element *setprintlist;
+
+extern struct cmd_list_element *showprintlist;
+
+extern struct cmd_list_element *setchecklist;
+
+extern struct cmd_list_element *showchecklist;
+
+extern void
+execute_user_command PARAMS ((struct cmd_list_element *, char *));
+
+extern void
+execute_command PARAMS ((char *, int));
+
+extern char **noop_completer PARAMS ((char *, char *));
+
+extern char **filename_completer PARAMS ((char *, char *));
+
+#endif /* !defined (GDBCMD_H) */
diff --git a/gnu/usr.bin/gdb/gdb/gdbcore.h b/gnu/usr.bin/gdb/gdb/gdbcore.h
new file mode 100644
index 000000000000..ec0f1b5a950a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbcore.h
@@ -0,0 +1,129 @@
+/* Machine independent variables that describe the core file under GDB.
+ Copyright 1986, 1987, 1989, 1990, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Interface routines for core, executable, etc. */
+
+#if !defined (GDBCORE_H)
+#define GDBCORE_H 1
+
+#include "bfd.h" /* Binary File Description */
+
+/* Return the name of the executable file as a string.
+ ERR nonzero means get error if there is none specified;
+ otherwise return 0 in that case. */
+
+extern char *
+get_exec_file PARAMS ((int err));
+
+/* Nonzero if there is a core file. */
+
+extern int
+have_core_file_p PARAMS ((void));
+
+/* Read "memory data" from whatever target or inferior we have.
+ Returns zero if successful, errno value if not. EIO is used
+ for address out of bounds. If breakpoints are inserted, returns
+ shadow contents, not the breakpoints themselves. From breakpoint.c. */
+
+extern int
+read_memory_nobpt PARAMS ((CORE_ADDR memaddr, char *myaddr, unsigned len));
+
+/* Report a memory error with error(). */
+
+extern void
+memory_error PARAMS ((int status, CORE_ADDR memaddr));
+
+/* Like target_read_memory, but report an error if can't read. */
+
+extern void
+read_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+extern LONGEST
+read_memory_integer PARAMS ((CORE_ADDR memaddr, int len));
+
+/* Read an unsigned integer from debugged memory, given address and number of bytes. */
+
+extern unsigned LONGEST
+read_memory_unsigned_integer PARAMS ((CORE_ADDR memaddr, int len));
+
+/* If this is prototyped, need to deal with void* vs. char*. */
+
+extern void
+write_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) PARAMS ((char *filename));
+
+extern void
+specify_exec_file_hook PARAMS ((void (*hook) (char *filename)));
+
+/* Binary File Diddlers for the exec and core files */
+extern bfd *core_bfd;
+extern bfd *exec_bfd;
+
+/* Whether to open exec and core files read-only or read-write. */
+
+extern int write_files;
+
+extern void
+core_file_command PARAMS ((char *filename, int from_tty));
+
+extern void
+exec_file_command PARAMS ((char *filename, int from_tty));
+
+extern void
+validate_files PARAMS ((void));
+
+extern unsigned int
+register_addr PARAMS ((int regno, int blockend));
+
+extern int
+xfer_core_file PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+extern void
+fetch_core_registers PARAMS ((char *core_reg_sect, unsigned core_reg_size,
+ int which, unsigned int reg_addr));
+
+extern void
+registers_fetched PARAMS ((void));
+
+#if !defined (KERNEL_U_ADDR)
+extern CORE_ADDR kernel_u_addr;
+#define KERNEL_U_ADDR kernel_u_addr
+#endif
+
+/* The target vector for core files */
+extern struct target_ops core_ops;
+
+ /* target vector functions called directly from elsewhere */
+void
+core_open PARAMS ((char *, int));
+
+void
+core_detach PARAMS ((char *, int));
+
+/* The current default bfd target. */
+extern char *gnutarget;
+
+extern void set_gnutarget PARAMS ((char *));
+
+#endif /* !defined (GDBCORE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.c b/gnu/usr.bin/gdb/gdb/gdbtypes.c
new file mode 100644
index 000000000000..f34646935aa5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.c
@@ -0,0 +1,1440 @@
+/* Support routines for manipulating internal types for GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "target.h"
+#include "value.h"
+#include "demangle.h"
+#include "complaints.h"
+
+/* These variables point to the objects
+ representing the predefined C data types. */
+
+struct type *builtin_type_void;
+struct type *builtin_type_char;
+struct type *builtin_type_short;
+struct type *builtin_type_int;
+struct type *builtin_type_long;
+struct type *builtin_type_long_long;
+struct type *builtin_type_signed_char;
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+struct type *builtin_type_unsigned_long_long;
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+struct type *builtin_type_long_double;
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_string;
+
+/* Alloc a new type structure and fill it with some defaults. If
+ OBJFILE is non-NULL, then allocate the space for the type structure
+ in that objfile's type_obstack. */
+
+struct type *
+alloc_type (objfile)
+ struct objfile *objfile;
+{
+ register struct type *type;
+
+ /* Alloc the structure and start off with all fields zeroed. */
+
+ if (objfile == NULL)
+ {
+ type = (struct type *) xmalloc (sizeof (struct type));
+ }
+ else
+ {
+ type = (struct type *) obstack_alloc (&objfile -> type_obstack,
+ sizeof (struct type));
+ }
+ memset ((char *) type, 0, sizeof (struct type));
+
+ /* Initialize the fields that might not be zero. */
+
+ TYPE_CODE (type) = TYPE_CODE_UNDEF;
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_VPTR_FIELDNO (type) = -1;
+
+ return (type);
+}
+
+/* Lookup a pointer to a type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the pointer type should be stored.
+ If *TYPEPTR is zero, update it to point to the pointer type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_pointer_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_POINTER_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_POINTER_TYPE (type) = ntype;
+
+ /* FIXME! Assume the machine has only one representation for pointers! */
+
+ TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (ntype) = TYPE_CODE_PTR;
+
+ /* pointers are unsigned */
+ TYPE_FLAGS (ntype) |= TYPE_FLAG_UNSIGNED;
+
+ if (!TYPE_POINTER_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_POINTER_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+/* Given a type TYPE, return a type of pointers to that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_pointer_type (type)
+ struct type *type;
+{
+ return make_pointer_type (type, (struct type **)0);
+}
+
+/* Lookup a C++ `reference' to a type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the reference type should be stored.
+ If *TYPEPTR is zero, update it to point to the reference type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_reference_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_REFERENCE_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_REFERENCE_TYPE (type) = ntype;
+
+ /* FIXME! Assume the machine has only one representation for references,
+ and that it matches the (only) representation for pointers! */
+
+ TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (ntype) = TYPE_CODE_REF;
+
+ if (!TYPE_REFERENCE_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_REFERENCE_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+/* Same as above, but caller doesn't care about memory allocation details. */
+
+struct type *
+lookup_reference_type (type)
+ struct type *type;
+{
+ return make_reference_type (type, (struct type **)0);
+}
+
+/* Lookup a function type that returns type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the function type should be stored.
+ If *TYPEPTR is zero, update it to point to the function type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_function_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_FUNCTION_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_FUNCTION_TYPE (type) = ntype;
+
+ TYPE_LENGTH (ntype) = 1;
+ TYPE_CODE (ntype) = TYPE_CODE_FUNC;
+
+ if (!TYPE_FUNCTION_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_FUNCTION_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+
+/* Given a type TYPE, return a type of functions that return that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_function_type (type)
+ struct type *type;
+{
+ return make_function_type (type, (struct type **)0);
+}
+
+/* Implement direct support for MEMBER_TYPE in GNU C++.
+ May need to construct such a type if this is the first use.
+ The TYPE is the type of the member. The DOMAIN is the type
+ of the aggregate that the member belongs to. */
+
+struct type *
+lookup_member_type (type, domain)
+ struct type *type;
+ struct type *domain;
+{
+ register struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (type));
+ smash_to_member_type (mtype, domain, type);
+ return (mtype);
+}
+
+/* Allocate a stub method whose return type is TYPE.
+ This apparently happens for speed of symbol reading, since parsing
+ out the arguments to the method is cpu-intensive, the way we are doing
+ it. So, we will fill in arguments later.
+ This always returns a fresh type. */
+
+struct type *
+allocate_stub_method (type)
+ struct type *type;
+{
+ struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (type));
+ TYPE_TARGET_TYPE (mtype) = type;
+ /* _DOMAIN_TYPE (mtype) = unknown yet */
+ /* _ARG_TYPES (mtype) = unknown yet */
+ TYPE_FLAGS (mtype) = TYPE_FLAG_STUB;
+ TYPE_CODE (mtype) = TYPE_CODE_METHOD;
+ TYPE_LENGTH (mtype) = 1;
+ return (mtype);
+}
+
+/* Create a range type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type, inheriting the objfile from INDEX_TYPE.
+
+ Indices will be of type INDEX_TYPE, and will range from LOW_BOUND to
+ HIGH_BOUND, inclusive.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into a range type? */
+
+struct type *
+create_range_type (result_type, index_type, low_bound, high_bound)
+ struct type *result_type;
+ struct type *index_type;
+ int low_bound;
+ int high_bound;
+{
+ if (result_type == NULL)
+ {
+ result_type = alloc_type (TYPE_OBJFILE (index_type));
+ }
+ TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+ TYPE_TARGET_TYPE (result_type) = index_type;
+ TYPE_LENGTH (result_type) = TYPE_LENGTH (index_type);
+ TYPE_NFIELDS (result_type) = 2;
+ TYPE_FIELDS (result_type) = (struct field *)
+ TYPE_ALLOC (result_type, 2 * sizeof (struct field));
+ memset (TYPE_FIELDS (result_type), 0, 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (result_type, 0) = low_bound;
+ TYPE_FIELD_BITPOS (result_type, 1) = high_bound;
+ TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int; /* FIXME */
+ TYPE_FIELD_TYPE (result_type, 1) = builtin_type_int; /* FIXME */
+
+ return (result_type);
+}
+
+
+/* Create an array type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type, inheriting the objfile from RANGE_TYPE.
+
+ Elements will be of type ELEMENT_TYPE, the indices will be of type
+ RANGE_TYPE.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into an array type? */
+
+struct type *
+create_array_type (result_type, element_type, range_type)
+ struct type *result_type;
+ struct type *element_type;
+ struct type *range_type;
+{
+ int low_bound;
+ int high_bound;
+
+ if (TYPE_CODE (range_type) != TYPE_CODE_RANGE)
+ {
+ /* FIXME: We only handle range types at the moment. Complain and
+ create a dummy range type to use. */
+ warning ("internal error: array index type must be a range type");
+ range_type = lookup_fundamental_type (TYPE_OBJFILE (range_type),
+ FT_INTEGER);
+ range_type = create_range_type ((struct type *) NULL, range_type, 0, 0);
+ }
+ if (result_type == NULL)
+ {
+ result_type = alloc_type (TYPE_OBJFILE (range_type));
+ }
+ TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (result_type) = element_type;
+ low_bound = TYPE_FIELD_BITPOS (range_type, 0);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ TYPE_LENGTH (result_type) =
+ TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
+ TYPE_NFIELDS (result_type) = 1;
+ TYPE_FIELDS (result_type) =
+ (struct field *) TYPE_ALLOC (result_type, sizeof (struct field));
+ memset (TYPE_FIELDS (result_type), 0, sizeof (struct field));
+ TYPE_FIELD_TYPE (result_type, 0) = range_type;
+ TYPE_VPTR_FIELDNO (result_type) = -1;
+
+ return (result_type);
+}
+
+/* Create a string type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type. String types are similar enough to array of
+ char types that we can use create_array_type to build the basic type
+ and then bash it into a string type.
+
+ For fixed length strings, the range type contains 0 as the lower
+ bound and the length of the string minus one as the upper bound.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into a string type? */
+
+struct type *
+create_string_type (result_type, range_type)
+ struct type *result_type;
+ struct type *range_type;
+{
+ result_type = create_array_type (result_type, builtin_type_char, range_type);
+ TYPE_CODE (result_type) = TYPE_CODE_STRING;
+ return (result_type);
+}
+
+/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE.
+ A MEMBER is a wierd thing -- it amounts to a typed offset into
+ a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't
+ include the offset (that's the value of the MEMBER itself), but does
+ include the structure type into which it points (for some reason).
+
+ When "smashing" the type, we preserve the objfile that the
+ old type pointed to, since we aren't changing where the type is actually
+ allocated. */
+
+void
+smash_to_member_type (type, domain, to_type)
+ struct type *type;
+ struct type *domain;
+ struct type *to_type;
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ memset ((char *) type, 0, sizeof (struct type));
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
+ TYPE_CODE (type) = TYPE_CODE_MEMBER;
+}
+
+/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.
+ METHOD just means `function that gets an extra "this" argument'.
+
+ When "smashing" the type, we preserve the objfile that the
+ old type pointed to, since we aren't changing where the type is actually
+ allocated. */
+
+void
+smash_to_method_type (type, domain, to_type, args)
+ struct type *type;
+ struct type *domain;
+ struct type *to_type;
+ struct type **args;
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ memset ((char *) type, 0, sizeof (struct type));
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_ARG_TYPES (type) = args;
+ TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
+ TYPE_CODE (type) = TYPE_CODE_METHOD;
+}
+
+/* Return a typename for a struct/union/enum type without "struct ",
+ "union ", or "enum ". If the type has a NULL name, return NULL. */
+
+char *
+type_name_no_tag (type)
+ register const struct type *type;
+{
+ if (TYPE_TAG_NAME (type) != NULL)
+ return TYPE_TAG_NAME (type);
+
+ /* Is there code which expects this to return the name if there is no
+ tag name? My guess is that this is mainly used for C++ in cases where
+ the two will always be the same. */
+ return TYPE_NAME (type);
+}
+
+/* Lookup a primitive type named NAME.
+ Return zero if NAME is not a primitive type.*/
+
+struct type *
+lookup_primitive_typename (name)
+ char *name;
+{
+ struct type ** const *p;
+
+ for (p = current_language -> la_builtin_type_vector; *p != NULL; p++)
+ {
+ if (STREQ ((**p) -> name, name))
+ {
+ return (**p);
+ }
+ }
+ return (NULL);
+}
+
+/* Lookup a typedef or primitive type named NAME,
+ visible in lexical block BLOCK.
+ If NOERR is nonzero, return zero if NAME is not suitably defined. */
+
+struct type *
+lookup_typename (name, block, noerr)
+ char *name;
+ struct block *block;
+ int noerr;
+{
+ register struct symbol *sym;
+ register struct type *tmp;
+
+ sym = lookup_symbol (name, block, VAR_NAMESPACE, 0, (struct symtab **) NULL);
+ if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ tmp = lookup_primitive_typename (name);
+ if (tmp)
+ {
+ return (tmp);
+ }
+ else if (!tmp && noerr)
+ {
+ return (NULL);
+ }
+ else
+ {
+ error ("No type named %s.", name);
+ }
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+struct type *
+lookup_unsigned_typename (name)
+ char *name;
+{
+ char *uns = alloca (strlen (name) + 10);
+
+ strcpy (uns, "unsigned ");
+ strcpy (uns + 9, name);
+ return (lookup_typename (uns, (struct block *) NULL, 0));
+}
+
+struct type *
+lookup_signed_typename (name)
+ char *name;
+{
+ struct type *t;
+ char *uns = alloca (strlen (name) + 8);
+
+ strcpy (uns, "signed ");
+ strcpy (uns + 7, name);
+ t = lookup_typename (uns, (struct block *) NULL, 1);
+ /* If we don't find "signed FOO" just try again with plain "FOO". */
+ if (t != NULL)
+ return t;
+ return lookup_typename (name, (struct block *) NULL, 0);
+}
+
+/* Lookup a structure type named "struct NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_struct (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ {
+ error ("No struct type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ {
+ error ("This context has class, union or enum %s, not a struct.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup a union type named "union NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_union (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ {
+ error ("No union type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION)
+ {
+ error ("This context has class, struct or enum %s, not a union.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup an enum type named "enum NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_enum (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+ if (sym == NULL)
+ {
+ error ("No enum type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM)
+ {
+ error ("This context has class, struct or union %s, not an enum.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup a template type named "template NAME<TYPE>",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_template_type (name, type, block)
+ char *name;
+ struct type *type;
+ struct block *block;
+{
+ struct symbol *sym;
+ char *nam = (char*) alloca(strlen(name) + strlen(type->name) + 4);
+ strcpy (nam, name);
+ strcat (nam, "<");
+ strcat (nam, type->name);
+ strcat (nam, " >"); /* FIXME, extra space still introduced in gcc? */
+
+ sym = lookup_symbol (nam, block, VAR_NAMESPACE, 0, (struct symtab **)NULL);
+
+ if (sym == NULL)
+ {
+ error ("No template type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ {
+ error ("This context has class, union or enum %s, not a struct.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Given a type TYPE, lookup the type of the component of type named NAME.
+
+ TYPE can be either a struct or union, or a pointer or reference to a struct or
+ union. If it is a pointer or reference, its target type is automatically used.
+ Thus '.' and '->' are interchangable, as specified for the definitions of the
+ expression element types STRUCTOP_STRUCT and STRUCTOP_PTR.
+
+ If NOERR is nonzero, return zero if NAME is not suitably defined.
+ If NAME is the name of a baseclass type, return that type. */
+
+struct type *
+lookup_struct_elt_type (type, name, noerr)
+ struct type *type;
+ char *name;
+ int noerr;
+{
+ int i;
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR ||
+ TYPE_CODE (type) == TYPE_CODE_REF)
+ type = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT &&
+ TYPE_CODE (type) != TYPE_CODE_UNION)
+ {
+ target_terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ error (" is not a structure or union type.");
+ }
+
+ check_stub_type (type);
+
+#if 0
+ /* FIXME: This change put in by Michael seems incorrect for the case where
+ the structure tag name is the same as the member name. I.E. when doing
+ "ptype bell->bar" for "struct foo { int bar; int foo; } bell;"
+ Disabled by fnf. */
+ {
+ char *typename;
+
+ typename = type_name_no_tag (type);
+ if (typename != NULL && STREQ (typename, name))
+ return type;
+ }
+#endif
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ return TYPE_FIELD_TYPE (type, i);
+ }
+ }
+
+ /* OK, it's not in this class. Recursively check the baseclasses. */
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ struct type *t;
+
+ t = lookup_struct_elt_type (TYPE_BASECLASS (type, i), name, noerr);
+ if (t != NULL)
+ {
+ return t;
+ }
+ }
+
+ if (noerr)
+ {
+ return NULL;
+ }
+
+ target_terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " has no component named ");
+ fputs_filtered (name, stderr);
+ error (".");
+ return (struct type *)-1; /* For lint */
+}
+
+/* If possible, make the vptr_fieldno and vptr_basetype fields of TYPE
+ valid. Callers should be aware that in some cases (for example,
+ the type or one of its baseclasses is a stub type and we are
+ debugging a .o file), this function will not be able to find the virtual
+ function table pointer, and vptr_fieldno will remain -1 and vptr_basetype
+ will remain NULL. */
+
+void
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ check_stub_type (type);
+
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ {
+ int i;
+
+ /* We must start at zero in case the first (and only) baseclass is
+ virtual (and hence we cannot share the table pointer). */
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, i));
+ if (TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)) >= 0)
+ {
+ TYPE_VPTR_FIELDNO (type)
+ = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i));
+ TYPE_VPTR_BASETYPE (type)
+ = TYPE_VPTR_BASETYPE (TYPE_BASECLASS (type, i));
+ break;
+ }
+ }
+ }
+}
+
+/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989.
+
+ If this is a stubbed struct (i.e. declared as struct foo *), see if
+ we can find a full definition in some other file. If so, copy this
+ definition, so we can use it in future. If not, set a flag so we
+ don't waste too much time in future. (FIXME, this doesn't seem
+ to be happening...)
+
+ This used to be coded as a macro, but I don't think it is called
+ often enough to merit such treatment.
+*/
+
+struct complaint stub_noname_complaint =
+ {"stub type has NULL name", 0, 0};
+
+void
+check_stub_type (type)
+ struct type *type;
+{
+ if (TYPE_FLAGS(type) & TYPE_FLAG_STUB)
+ {
+ char* name = type_name_no_tag (type);
+ /* FIXME: shouldn't we separately check the TYPE_NAME and the
+ TYPE_TAG_NAME, and look in STRUCT_NAMESPACE and/or VAR_NAMESPACE
+ as appropriate? (this code was written before TYPE_NAME and
+ TYPE_TAG_NAME were separate). */
+ struct symbol *sym;
+ if (name == NULL)
+ {
+ complain (&stub_noname_complaint);
+ return;
+ }
+ sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+ if (sym)
+ {
+ memcpy ((char *)type, (char *)SYMBOL_TYPE(sym), sizeof (struct type));
+ }
+ }
+}
+
+/* Ugly hack to convert method stubs into method types.
+
+ He ain't kiddin'. This demangles the name of the method into a string
+ including argument types, parses out each argument type, generates
+ a string casting a zero to that type, evaluates the string, and stuffs
+ the resulting type into an argtype vector!!! Then it knows the type
+ of the whole function (including argument types for overloading),
+ which info used to be in the stab's but was removed to hack back
+ the space required for them. */
+
+void
+check_stub_method (type, i, j)
+ struct type *type;
+ int i;
+ int j;
+{
+ struct fn_field *f;
+ char *mangled_name = gdb_mangle_name (type, i, j);
+ char *demangled_name = cplus_demangle (mangled_name,
+ DMGL_PARAMS | DMGL_ANSI);
+ char *argtypetext, *p;
+ int depth = 0, argcount = 1;
+ struct type **argtypes;
+ struct type *mtype;
+
+ if (demangled_name == NULL)
+ {
+ error ("Internal: Cannot demangle mangled name `%s'.", mangled_name);
+ }
+
+ /* Now, read in the parameters that define this type. */
+ argtypetext = strchr (demangled_name, '(') + 1;
+ p = argtypetext;
+ while (*p)
+ {
+ if (*p == '(')
+ {
+ depth += 1;
+ }
+ else if (*p == ')')
+ {
+ depth -= 1;
+ }
+ else if (*p == ',' && depth == 0)
+ {
+ argcount += 1;
+ }
+
+ p += 1;
+ }
+
+ /* We need two more slots: one for the THIS pointer, and one for the
+ NULL [...] or void [end of arglist]. */
+
+ argtypes = (struct type **)
+ TYPE_ALLOC (type, (argcount + 2) * sizeof (struct type *));
+ p = argtypetext;
+ argtypes[0] = lookup_pointer_type (type);
+ argcount = 1;
+
+ if (*p != ')') /* () means no args, skip while */
+ {
+ depth = 0;
+ while (*p)
+ {
+ if (depth <= 0 && (*p == ',' || *p == ')'))
+ {
+ argtypes[argcount] =
+ parse_and_eval_type (argtypetext, p - argtypetext);
+ argcount += 1;
+ argtypetext = p + 1;
+ }
+
+ if (*p == '(')
+ {
+ depth += 1;
+ }
+ else if (*p == ')')
+ {
+ depth -= 1;
+ }
+
+ p += 1;
+ }
+ }
+
+ if (p[-2] != '.') /* Not '...' */
+ {
+ argtypes[argcount] = builtin_type_void; /* List terminator */
+ }
+ else
+ {
+ argtypes[argcount] = NULL; /* Ellist terminator */
+ }
+
+ free (demangled_name);
+
+ f = TYPE_FN_FIELDLIST1 (type, i);
+ TYPE_FN_FIELD_PHYSNAME (f, j) = mangled_name;
+
+ /* Now update the old "stub" type into a real type. */
+ mtype = TYPE_FN_FIELD_TYPE (f, j);
+ TYPE_DOMAIN_TYPE (mtype) = type;
+ TYPE_ARG_TYPES (mtype) = argtypes;
+ TYPE_FLAGS (mtype) &= ~TYPE_FLAG_STUB;
+ TYPE_FN_FIELD_STUB (f, j) = 0;
+}
+
+const struct cplus_struct_type cplus_struct_default;
+
+void
+allocate_cplus_struct_type (type)
+ struct type *type;
+{
+ if (!HAVE_CPLUS_STRUCT (type))
+ {
+ TYPE_CPLUS_SPECIFIC (type) = (struct cplus_struct_type *)
+ TYPE_ALLOC (type, sizeof (struct cplus_struct_type));
+ *(TYPE_CPLUS_SPECIFIC(type)) = cplus_struct_default;
+ }
+}
+
+/* Helper function to initialize the standard scalar types.
+
+ If NAME is non-NULL and OBJFILE is non-NULL, then we make a copy
+ of the string pointed to by name in the type_obstack for that objfile,
+ and initialize the type name to that copy. There are places (mipsread.c
+ in particular, where init_type is called with a NULL value for NAME). */
+
+struct type *
+init_type (code, length, flags, name, objfile)
+ enum type_code code;
+ int length;
+ int flags;
+ char *name;
+ struct objfile *objfile;
+{
+ register struct type *type;
+
+ type = alloc_type (objfile);
+ TYPE_CODE (type) = code;
+ TYPE_LENGTH (type) = length;
+ TYPE_FLAGS (type) |= flags;
+ if ((name != NULL) && (objfile != NULL))
+ {
+ TYPE_NAME (type) =
+ obsavestring (name, strlen (name), &objfile -> type_obstack);
+ }
+ else
+ {
+ TYPE_NAME (type) = name;
+ }
+
+ /* C++ fancies. */
+
+ if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
+ {
+ INIT_CPLUS_SPECIFIC (type);
+ }
+ return (type);
+}
+
+/* Look up a fundamental type for the specified objfile.
+ May need to construct such a type if this is the first use.
+
+ Some object file formats (ELF, COFF, etc) do not define fundamental
+ types such as "int" or "double". Others (stabs for example), do
+ define fundamental types.
+
+ For the formats which don't provide fundamental types, gdb can create
+ such types, using defaults reasonable for the current language and
+ the current target machine.
+
+ NOTE: This routine is obsolescent. Each debugging format reader
+ should manage it's own fundamental types, either creating them from
+ suitable defaults or reading them from the debugging information,
+ whichever is appropriate. The DWARF reader has already been
+ fixed to do this. Once the other readers are fixed, this routine
+ will go away. Also note that fundamental types should be managed
+ on a compilation unit basis in a multi-language environment, not
+ on a linkage unit basis as is done here. */
+
+
+struct type *
+lookup_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type **typep;
+ register int nbytes;
+
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("internal error - invalid fundamental type id %d", typeid);
+ }
+
+ /* If this is the first time we need a fundamental type for this objfile
+ then we need to initialize the vector of type pointers. */
+
+ if (objfile -> fundamental_types == NULL)
+ {
+ nbytes = FT_NUM_MEMBERS * sizeof (struct type *);
+ objfile -> fundamental_types = (struct type **)
+ obstack_alloc (&objfile -> type_obstack, nbytes);
+ memset ((char *) objfile -> fundamental_types, 0, nbytes);
+ }
+
+ /* Look for this particular type in the fundamental type vector. If one is
+ not found, create and install one appropriate for the current language. */
+
+ typep = objfile -> fundamental_types + typeid;
+ if (*typep == NULL)
+ {
+ *typep = create_fundamental_type (objfile, typeid);
+ }
+
+ return (*typep);
+}
+
+#if MAINTENANCE_CMDS
+
+static void
+print_bit_vector (bits, nbits)
+ B_TYPE *bits;
+ int nbits;
+{
+ int bitno;
+
+ for (bitno = 0; bitno < nbits; bitno++)
+ {
+ if ((bitno % 8) == 0)
+ {
+ puts_filtered (" ");
+ }
+ if (B_TST (bits, bitno))
+ {
+ printf_filtered ("1");
+ }
+ else
+ {
+ printf_filtered ("0");
+ }
+ }
+}
+
+/* The args list is a strange beast. It is either terminated by a NULL
+ pointer for varargs functions, or by a pointer to a TYPE_CODE_VOID
+ type for normal fixed argcount functions. (FIXME someday)
+ Also note the first arg should be the "this" pointer, we may not want to
+ include it since we may get into a infinitely recursive situation. */
+
+static void
+print_arg_types (args, spaces)
+ struct type **args;
+ int spaces;
+{
+ if (args != NULL)
+ {
+ while (*args != NULL)
+ {
+ recursive_dump_type (*args, spaces + 2);
+ if ((*args++) -> code == TYPE_CODE_VOID)
+ {
+ break;
+ }
+ }
+ }
+}
+
+static void
+dump_fn_fieldlists (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ int method_idx;
+ int overload_idx;
+ struct fn_field *f;
+
+ printfi_filtered (spaces, "fn_fieldlists 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELDLISTS (type));
+ for (method_idx = 0; method_idx < TYPE_NFN_FIELDS (type); method_idx++)
+ {
+ f = TYPE_FN_FIELDLIST1 (type, method_idx);
+ printfi_filtered (spaces + 2, "[%d] name '%s' (0x%lx) length %d\n",
+ method_idx,
+ TYPE_FN_FIELDLIST_NAME (type, method_idx),
+ (unsigned long) TYPE_FN_FIELDLIST_NAME (type, method_idx),
+ TYPE_FN_FIELDLIST_LENGTH (type, method_idx));
+ for (overload_idx = 0;
+ overload_idx < TYPE_FN_FIELDLIST_LENGTH (type, method_idx);
+ overload_idx++)
+ {
+ printfi_filtered (spaces + 4, "[%d] physname '%s' (0x%lx)\n",
+ overload_idx,
+ TYPE_FN_FIELD_PHYSNAME (f, overload_idx),
+ (unsigned long) TYPE_FN_FIELD_PHYSNAME (f, overload_idx));
+ printfi_filtered (spaces + 8, "type 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_TYPE (f, overload_idx));
+ recursive_dump_type (TYPE_FN_FIELD_TYPE (f, overload_idx),
+ spaces + 8 + 2);
+ printfi_filtered (spaces + 8, "args 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_ARGS (f, overload_idx));
+ print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx), spaces);
+ printfi_filtered (spaces + 8, "fcontext 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_FCONTEXT (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_const %d\n",
+ TYPE_FN_FIELD_CONST (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_volatile %d\n",
+ TYPE_FN_FIELD_VOLATILE (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_private %d\n",
+ TYPE_FN_FIELD_PRIVATE (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_protected %d\n",
+ TYPE_FN_FIELD_PROTECTED (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_stub %d\n",
+ TYPE_FN_FIELD_STUB (f, overload_idx));
+ printfi_filtered (spaces + 8, "voffset %u\n",
+ TYPE_FN_FIELD_VOFFSET (f, overload_idx));
+ }
+ }
+}
+
+static void
+print_cplus_stuff (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ printfi_filtered (spaces, "n_baseclasses %d\n",
+ TYPE_N_BASECLASSES (type));
+ printfi_filtered (spaces, "nfn_fields %d\n",
+ TYPE_NFN_FIELDS (type));
+ printfi_filtered (spaces, "nfn_fields_total %d\n",
+ TYPE_NFN_FIELDS_TOTAL (type));
+ if (TYPE_N_BASECLASSES (type) > 0)
+ {
+ printfi_filtered (spaces, "virtual_field_bits (%d bits at *0x%lx)",
+ TYPE_N_BASECLASSES (type),
+ (unsigned long) TYPE_FIELD_VIRTUAL_BITS (type));
+ print_bit_vector (TYPE_FIELD_VIRTUAL_BITS (type),
+ TYPE_N_BASECLASSES (type));
+ puts_filtered ("\n");
+ }
+ if (TYPE_NFIELDS (type) > 0)
+ {
+ if (TYPE_FIELD_PRIVATE_BITS (type) != NULL)
+ {
+ printfi_filtered (spaces, "private_field_bits (%d bits at *0x%lx)",
+ TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELD_PRIVATE_BITS (type));
+ print_bit_vector (TYPE_FIELD_PRIVATE_BITS (type),
+ TYPE_NFIELDS (type));
+ puts_filtered ("\n");
+ }
+ if (TYPE_FIELD_PROTECTED_BITS (type) != NULL)
+ {
+ printfi_filtered (spaces, "protected_field_bits (%d bits at *0x%lx)",
+ TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELD_PROTECTED_BITS (type));
+ print_bit_vector (TYPE_FIELD_PROTECTED_BITS (type),
+ TYPE_NFIELDS (type));
+ puts_filtered ("\n");
+ }
+ }
+ if (TYPE_NFN_FIELDS (type) > 0)
+ {
+ dump_fn_fieldlists (type, spaces);
+ }
+}
+
+void
+recursive_dump_type (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ int idx;
+
+ printfi_filtered (spaces, "type node 0x%lx\n", (unsigned long)type);
+ printfi_filtered (spaces, "name '%s' (0x%lx)\n",
+ TYPE_NAME (type) ? TYPE_NAME (type) : "<NULL>",
+ (unsigned long)TYPE_NAME (type));
+ if (TYPE_TAG_NAME (type) != NULL)
+ printfi_filtered (spaces, "tagname '%s' (0x%lx)\n",
+ TYPE_TAG_NAME (type),
+ (unsigned long)TYPE_TAG_NAME (type));
+ printfi_filtered (spaces, "code 0x%x ", TYPE_CODE (type));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_UNDEF:
+ printf_filtered ("(TYPE_CODE_UNDEF)");
+ break;
+ case TYPE_CODE_PTR:
+ printf_filtered ("(TYPE_CODE_PTR)");
+ break;
+ case TYPE_CODE_ARRAY:
+ printf_filtered ("(TYPE_CODE_ARRAY)");
+ break;
+ case TYPE_CODE_STRUCT:
+ printf_filtered ("(TYPE_CODE_STRUCT)");
+ break;
+ case TYPE_CODE_UNION:
+ printf_filtered ("(TYPE_CODE_UNION)");
+ break;
+ case TYPE_CODE_ENUM:
+ printf_filtered ("(TYPE_CODE_ENUM)");
+ break;
+ case TYPE_CODE_FUNC:
+ printf_filtered ("(TYPE_CODE_FUNC)");
+ break;
+ case TYPE_CODE_INT:
+ printf_filtered ("(TYPE_CODE_INT)");
+ break;
+ case TYPE_CODE_FLT:
+ printf_filtered ("(TYPE_CODE_FLT)");
+ break;
+ case TYPE_CODE_VOID:
+ printf_filtered ("(TYPE_CODE_VOID)");
+ break;
+ case TYPE_CODE_SET:
+ printf_filtered ("(TYPE_CODE_SET)");
+ break;
+ case TYPE_CODE_RANGE:
+ printf_filtered ("(TYPE_CODE_RANGE)");
+ break;
+ case TYPE_CODE_STRING:
+ printf_filtered ("(TYPE_CODE_STRING)");
+ break;
+ case TYPE_CODE_ERROR:
+ printf_filtered ("(TYPE_CODE_ERROR)");
+ break;
+ case TYPE_CODE_MEMBER:
+ printf_filtered ("(TYPE_CODE_MEMBER)");
+ break;
+ case TYPE_CODE_METHOD:
+ printf_filtered ("(TYPE_CODE_METHOD)");
+ break;
+ case TYPE_CODE_REF:
+ printf_filtered ("(TYPE_CODE_REF)");
+ break;
+ case TYPE_CODE_CHAR:
+ printf_filtered ("(TYPE_CODE_CHAR)");
+ break;
+ case TYPE_CODE_BOOL:
+ printf_filtered ("(TYPE_CODE_BOOL)");
+ break;
+ default:
+ printf_filtered ("(UNKNOWN TYPE CODE)");
+ break;
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "length %d\n", TYPE_LENGTH (type));
+ printfi_filtered (spaces, "objfile 0x%lx\n",
+ (unsigned long) TYPE_OBJFILE (type));
+ printfi_filtered (spaces, "target_type 0x%lx\n",
+ (unsigned long) TYPE_TARGET_TYPE (type));
+ if (TYPE_TARGET_TYPE (type) != NULL)
+ {
+ recursive_dump_type (TYPE_TARGET_TYPE (type), spaces + 2);
+ }
+ printfi_filtered (spaces, "pointer_type 0x%lx\n",
+ (unsigned long) TYPE_POINTER_TYPE (type));
+ printfi_filtered (spaces, "reference_type 0x%lx\n",
+ (unsigned long) TYPE_REFERENCE_TYPE (type));
+ printfi_filtered (spaces, "function_type 0x%lx\n",
+ (unsigned long) TYPE_FUNCTION_TYPE (type));
+ printfi_filtered (spaces, "flags 0x%x", TYPE_FLAGS (type));
+ if (TYPE_FLAGS (type) & TYPE_FLAG_UNSIGNED)
+ {
+ puts_filtered (" TYPE_FLAG_UNSIGNED");
+ }
+ if (TYPE_FLAGS (type) & TYPE_FLAG_SIGNED)
+ {
+ puts_filtered (" TYPE_FLAG_SIGNED");
+ }
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ puts_filtered (" TYPE_FLAG_STUB");
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "nfields %d 0x%lx\n", TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELDS (type));
+ for (idx = 0; idx < TYPE_NFIELDS (type); idx++)
+ {
+ printfi_filtered (spaces + 2,
+ "[%d] bitpos %d bitsize %d type 0x%lx name '%s' (0x%lx)\n",
+ idx, TYPE_FIELD_BITPOS (type, idx),
+ TYPE_FIELD_BITSIZE (type, idx),
+ (unsigned long) TYPE_FIELD_TYPE (type, idx),
+ TYPE_FIELD_NAME (type, idx) != NULL
+ ? TYPE_FIELD_NAME (type, idx)
+ : "<NULL>",
+ (unsigned long) TYPE_FIELD_NAME (type, idx));
+ if (TYPE_FIELD_TYPE (type, idx) != NULL)
+ {
+ recursive_dump_type (TYPE_FIELD_TYPE (type, idx), spaces + 4);
+ }
+ }
+ printfi_filtered (spaces, "vptr_basetype 0x%lx\n",
+ (unsigned long) TYPE_VPTR_BASETYPE (type));
+ if (TYPE_VPTR_BASETYPE (type) != NULL)
+ {
+ recursive_dump_type (TYPE_VPTR_BASETYPE (type), spaces + 2);
+ }
+ printfi_filtered (spaces, "vptr_fieldno %d\n", TYPE_VPTR_FIELDNO (type));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_METHOD:
+ case TYPE_CODE_FUNC:
+ printfi_filtered (spaces, "arg_types 0x%lx\n",
+ (unsigned long) TYPE_ARG_TYPES (type));
+ print_arg_types (TYPE_ARG_TYPES (type), spaces);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ printfi_filtered (spaces, "cplus_stuff 0x%lx\n",
+ (unsigned long) TYPE_CPLUS_SPECIFIC (type));
+ print_cplus_stuff (type, spaces);
+ break;
+
+ default:
+ /* We have to pick one of the union types to be able print and test
+ the value. Pick cplus_struct_type, even though we know it isn't
+ any particular one. */
+ printfi_filtered (spaces, "type_specific 0x%lx",
+ (unsigned long) TYPE_CPLUS_SPECIFIC (type));
+ if (TYPE_CPLUS_SPECIFIC (type) != NULL)
+ {
+ printf_filtered (" (unknown data form)");
+ }
+ printf_filtered ("\n");
+ break;
+
+ }
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+void
+_initialize_gdbtypes ()
+{
+ builtin_type_void =
+ init_type (TYPE_CODE_VOID, 1,
+ 0,
+ "void", (struct objfile *) NULL);
+ builtin_type_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "char", (struct objfile *) NULL);
+ builtin_type_signed_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED,
+ "signed char", (struct objfile *) NULL);
+ builtin_type_unsigned_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned char", (struct objfile *) NULL);
+ builtin_type_short =
+ init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "short", (struct objfile *) NULL);
+ builtin_type_unsigned_short =
+ init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned short", (struct objfile *) NULL);
+ builtin_type_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "int", (struct objfile *) NULL);
+ builtin_type_unsigned_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned int", (struct objfile *) NULL);
+ builtin_type_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long", (struct objfile *) NULL);
+ builtin_type_unsigned_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned long", (struct objfile *) NULL);
+ builtin_type_long_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long long", (struct objfile *) NULL);
+ builtin_type_unsigned_long_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned long long", (struct objfile *) NULL);
+ builtin_type_float =
+ init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "float", (struct objfile *) NULL);
+ builtin_type_double =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "double", (struct objfile *) NULL);
+ builtin_type_long_double =
+ init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long double", (struct objfile *) NULL);
+ builtin_type_complex =
+ init_type (TYPE_CODE_FLT, TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0,
+ "complex", (struct objfile *) NULL);
+ builtin_type_double_complex =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0,
+ "double complex", (struct objfile *) NULL);
+ builtin_type_string =
+ init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "string", (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.h b/gnu/usr.bin/gdb/gdb/gdbtypes.h
new file mode 100644
index 000000000000..89cad6cbbe5d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.h
@@ -0,0 +1,704 @@
+/* Internal type definitions for GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (GDBTYPES_H)
+#define GDBTYPES_H 1
+
+/* When gdb creates fundamental types, it uses one of the following
+ type identifiers. The identifiers are used to index a vector of
+ pointers to any types that are created. */
+
+#define FT_VOID 0
+#define FT_BOOLEAN 1
+#define FT_CHAR 2
+#define FT_SIGNED_CHAR 3
+#define FT_UNSIGNED_CHAR 4
+#define FT_SHORT 5
+#define FT_SIGNED_SHORT 6
+#define FT_UNSIGNED_SHORT 7
+#define FT_INTEGER 8
+#define FT_SIGNED_INTEGER 9
+#define FT_UNSIGNED_INTEGER 10
+#define FT_LONG 11
+#define FT_SIGNED_LONG 12
+#define FT_UNSIGNED_LONG 13
+#define FT_LONG_LONG 14
+#define FT_SIGNED_LONG_LONG 15
+#define FT_UNSIGNED_LONG_LONG 16
+#define FT_FLOAT 17
+#define FT_DBL_PREC_FLOAT 18
+#define FT_EXT_PREC_FLOAT 19
+#define FT_COMPLEX 20
+#define FT_DBL_PREC_COMPLEX 21
+#define FT_EXT_PREC_COMPLEX 22
+#define FT_STRING 23
+#define FT_FIXED_DECIMAL 24
+#define FT_FLOAT_DECIMAL 25
+#define FT_BYTE 26
+#define FT_UNSIGNED_BYTE 27
+
+#define FT_NUM_MEMBERS 28 /* Highest FT_* above, plus one. */
+
+/* Some macros for char-based bitfields. */
+
+#define B_SET(a,x) ((a)[(x)>>3] |= (1 << ((x)&7)))
+#define B_CLR(a,x) ((a)[(x)>>3] &= ~(1 << ((x)&7)))
+#define B_TST(a,x) ((a)[(x)>>3] & (1 << ((x)&7)))
+#define B_TYPE unsigned char
+#define B_BYTES(x) ( 1 + ((x)>>3) )
+#define B_CLRALL(a,x) memset ((a), 0, B_BYTES(x))
+
+/* Different kinds of data types are distinguished by the `code' field. */
+
+enum type_code
+{
+ TYPE_CODE_UNDEF, /* Not used; catches errors */
+ TYPE_CODE_PTR, /* Pointer type */
+ TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */
+ TYPE_CODE_STRUCT, /* C struct or Pascal record */
+ TYPE_CODE_UNION, /* C union or Pascal variant part */
+ TYPE_CODE_ENUM, /* Enumeration type */
+ TYPE_CODE_FUNC, /* Function type */
+ TYPE_CODE_INT, /* Integer type */
+
+ /* Floating type. This is *NOT* a complex type. Complex types, when
+ we have them, will have their own type code (or TYPE_CODE_ERROR if
+ we can parse a complex type but not manipulate it). There are parts
+ of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */
+ TYPE_CODE_FLT,
+
+ /* Void type (values zero length; the length field is ignored). */
+ TYPE_CODE_VOID,
+
+ TYPE_CODE_SET, /* Pascal sets */
+ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
+ TYPE_CODE_STRING, /* String types, distinct from array of char */
+ TYPE_CODE_BITSTRING, /* String of bits, distinct from bool array */
+
+ /* Unknown type. The length field is valid if we were able to
+ deduce that much about the type, or 0 if we don't even know that. */
+ TYPE_CODE_ERROR,
+
+ /* C++ */
+ TYPE_CODE_MEMBER, /* Member type */
+ TYPE_CODE_METHOD, /* Method type */
+ TYPE_CODE_REF, /* C++ Reference types */
+
+ /* Modula-2 */
+ TYPE_CODE_CHAR, /* *real* character type */
+ TYPE_CODE_BOOL /* BOOLEAN type */
+};
+
+/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
+ alias for TYPE_CODE_STRUCT. Eventually these should probably be
+ officially distinct types within gdb. */
+
+#define TYPE_CODE_CLASS TYPE_CODE_STRUCT
+
+/* Some bits for the type's flags word. */
+
+/* Explicitly unsigned integer type */
+
+#define TYPE_FLAG_UNSIGNED (1 << 0)
+
+/* Explicitly signed integer type */
+
+#define TYPE_FLAG_SIGNED (1 << 1)
+
+/* This appears in a type's flags word if it is a stub type (e.g., if
+ someone referenced a type that wasn't defined in a source file
+ via (struct sir_not_appearing_in_this_film *)). */
+
+#define TYPE_FLAG_STUB (1 << 2)
+
+
+struct type
+{
+
+ /* Code for kind of type */
+
+ enum type_code code;
+
+ /* Name of this type, or NULL if none.
+
+ This is used for printing only, except by poorly designed C++ code.
+ For looking up a name, look for a symbol in the VAR_NAMESPACE. */
+
+ char *name;
+
+ /* Tag name for this type, or NULL if none. This means that the
+ name of the type consists of a keyword followed by the tag name.
+ Which keyword is determined by the type code ("struct" for
+ TYPE_CODE_STRUCT, etc.). As far as I know C/C++ are the only languages
+ with this feature.
+
+ This is used for printing only, except by poorly designed C++ code.
+ For looking up a name, look for a symbol in the STRUCT_NAMESPACE.
+ One more legitimate use is that if TYPE_FLAG_STUB is set, this is
+ the name to use to look for definitions in other files. */
+
+ char *tag_name;
+
+ /* Length, in units of TARGET_CHAR_BIT bits,
+ of storage for a value of this type */
+
+ unsigned length;
+
+ /* Every type is now associated with a particular objfile, and the
+ type is allocated on the type_obstack for that objfile. One problem
+ however, is that there are times when gdb allocates new types while
+ it is not in the process of reading symbols from a particular objfile.
+ Fortunately, these happen when the type being created is a derived
+ type of an existing type, such as in lookup_pointer_type(). So
+ we can just allocate the new type using the same objfile as the
+ existing type, but to do this we need a backpointer to the objfile
+ from the existing type. Yes this is somewhat ugly, but without
+ major overhaul of the internal type system, it can't be avoided
+ for now. */
+
+ struct objfile *objfile;
+
+ /* For a pointer type, describes the type of object pointed to.
+ For an array type, describes the type of the elements.
+ For a function or method type, describes the type of the return value.
+ For a range type, describes the type of the full range.
+ Unused otherwise. */
+
+ struct type *target_type;
+
+ /* Type that is a pointer to this type.
+ NULL if no such pointer-to type is known yet.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+
+ struct type *pointer_type;
+
+ /* C++: also need a reference type. */
+
+ struct type *reference_type;
+
+ /* Type that is a function returning this type.
+ NULL if no such function type is known here.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+
+ struct type *function_type;
+
+ /* Flags about this type. */
+
+ short flags;
+
+ /* Number of fields described for this type */
+
+ short nfields;
+
+ /* For structure and union types, a description of each field.
+ For set and pascal array types, there is one "field",
+ whose type is the domain type of the set or array.
+ For range types, there are two "fields",
+ the minimum and maximum values (both inclusive).
+ For enum types, each possible value is described by one "field".
+ For C++ classes, there is one field for each base class (if it is
+ a derived class) plus one field for each class data member. Member
+ functions are recorded elsewhere.
+
+ Using a pointer to a separate array of fields
+ allows all types to have the same size, which is useful
+ because we can allocate the space for a type before
+ we know what to put in it. */
+
+ struct field
+ {
+
+ /* Position of this field, counting in bits from start of
+ containing structure. For a function type, this is the
+ position in the argument list of this argument.
+ For a range bound or enum value, this is the value itself.
+ (FIXME: What about ranges larger than host int size?)
+ For BITS_BIG_ENDIAN=1 targets, it is the bit offset to the MSB.
+ For BITS_BIG_ENDIAN=0 targets, it is the bit offset to the LSB. */
+
+ int bitpos;
+
+ /* Size of this field, in bits, or zero if not packed.
+ For an unpacked field, the field's type's length
+ says how many bytes the field occupies. */
+ /* FIXME: This is abused by TYPE_FIELD_STATIC_PHYSNAME to contain
+ a pointer, so it has to be long. */
+
+ long bitsize;
+
+ /* In a struct or enum type, type of this field.
+ In a function type, type of this argument.
+ In an array type, the domain-type of the array. */
+
+ struct type *type;
+
+ /* Name of field, value or argument.
+ NULL for range bounds and array domains. */
+
+ char *name;
+
+ } *fields;
+
+ /* For types with virtual functions, VPTR_BASETYPE is the base class which
+ defined the virtual function table pointer.
+
+ For types that are pointer to member types, VPTR_BASETYPE
+ is the type that this pointer is a member of.
+
+ Unused otherwise. */
+
+ struct type *vptr_basetype;
+
+ /* Field number of the virtual function table pointer in
+ VPTR_BASETYPE. If -1, we were unable to find the virtual
+ function table pointer in initial symbol reading, and
+ fill_in_vptr_fieldno should be called to find it if possible.
+
+ Unused if this type does not have virtual functions. */
+
+ int vptr_fieldno;
+
+ /* Slot to point to additional language-specific fields of this type. */
+
+ union type_specific
+ {
+
+ /* ARG_TYPES is for TYPE_CODE_METHOD and TYPE_CODE_FUNC. */
+
+ struct type **arg_types;
+
+ /* CPLUS_STUFF is for TYPE_CODE_STRUCT. It is initialized to point to
+ cplus_struct_default, a default static instance of a struct
+ cplus_struct_type. */
+
+ struct cplus_struct_type *cplus_stuff;
+
+ } type_specific;
+};
+
+#define NULL_TYPE ((struct type *) 0)
+
+/* C++ language-specific information for TYPE_CODE_STRUCT and TYPE_CODE_UNION
+ nodes. */
+
+struct cplus_struct_type
+{
+ /* Number of base classes this type derives from. The baseclasses are
+ stored in the first N_BASECLASSES fields (i.e. the `fields' field of
+ the struct type). I think only the `type' field of such a field has
+ any meaning. */
+
+ short n_baseclasses;
+
+ /* Number of methods with unique names. All overloaded methods with
+ the same name count only once. */
+
+ short nfn_fields;
+
+ /* Number of methods described for this type plus all the
+ methods that it derives from. */
+
+ int nfn_fields_total;
+
+ /* For derived classes, the number of base classes is given by n_baseclasses
+ and virtual_field_bits is a bit vector containing one bit per base class.
+ If the base class is virtual, the corresponding bit will be set.
+ I.E, given:
+
+ class A{};
+ class B{};
+ class C : public B, public virtual A {};
+
+ B is a baseclass of C; A is a virtual baseclass for C.
+ This is a C++ 2.0 language feature. */
+
+ B_TYPE *virtual_field_bits;
+
+ /* For classes with private fields, the number of fields is given by
+ nfields and private_field_bits is a bit vector containing one bit
+ per field.
+ If the field is private, the corresponding bit will be set. */
+
+ B_TYPE *private_field_bits;
+
+ /* For classes with protected fields, the number of fields is given by
+ nfields and protected_field_bits is a bit vector containing one bit
+ per field.
+ If the field is private, the corresponding bit will be set. */
+
+ B_TYPE *protected_field_bits;
+
+ /* For classes, structures, and unions, a description of each field,
+ which consists of an overloaded name, followed by the types of
+ arguments that the method expects, and then the name after it
+ has been renamed to make it distinct.
+
+ fn_fieldlists points to an array of nfn_fields of these. */
+
+ struct fn_fieldlist
+ {
+
+ /* The overloaded name. */
+
+ char *name;
+
+ /* The number of methods with this name. */
+
+ int length;
+
+ /* The list of methods. */
+
+ struct fn_field
+ {
+
+ /* If is_stub is clear, this is the mangled name which we can
+ look up to find the address of the method (FIXME: it would
+ be cleaner to have a pointer to the struct symbol here
+ instead). */
+
+ /* If is_stub is set, this is the portion of the mangled
+ name which specifies the arguments. For example, "ii",
+ if there are two int arguments, or "" if there are no
+ arguments. See gdb_mangle_name for the conversion from this
+ format to the one used if is_stub is clear. */
+
+ char *physname;
+
+ /* The return value of the method */
+
+ struct type *type;
+
+ /* The argument list. Only valid if is_stub is clear. Contains
+ the type of each argument, including `this', and ending with
+ a NULL pointer after the last argument. */
+
+ struct type **args;
+
+ /* For virtual functions.
+ First baseclass that defines this virtual function. */
+
+ struct type *fcontext;
+
+ /* Attributes. */
+
+ unsigned int is_const : 1;
+ unsigned int is_volatile : 1;
+ unsigned int is_private : 1;
+ unsigned int is_protected : 1;
+
+ /* A stub method only has some fields valid (but they are enough
+ to reconstruct the rest of the fields). */
+ unsigned int is_stub : 1;
+
+ /* Unused. */
+ unsigned int dummy : 3;
+
+ /* Index into that baseclass's virtual function table,
+ minus 2; else if static: VOFFSET_STATIC; else: 0. */
+
+ unsigned int voffset : 24;
+
+# define VOFFSET_STATIC 1
+
+ } *fn_fields;
+
+ } *fn_fieldlists;
+
+};
+
+/* The default value of TYPE_CPLUS_SPECIFIC(T) points to the
+ this shared static structure. */
+
+extern const struct cplus_struct_type cplus_struct_default;
+
+extern void
+allocate_cplus_struct_type PARAMS ((struct type *));
+
+#define INIT_CPLUS_SPECIFIC(type) \
+ (TYPE_CPLUS_SPECIFIC(type)=(struct cplus_struct_type*)&cplus_struct_default)
+#define ALLOCATE_CPLUS_STRUCT_TYPE(type) allocate_cplus_struct_type (type)
+#define HAVE_CPLUS_STRUCT(type) \
+ (TYPE_CPLUS_SPECIFIC(type) != &cplus_struct_default)
+
+#define TYPE_NAME(thistype) (thistype)->name
+#define TYPE_TAG_NAME(type) ((type)->tag_name)
+#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type
+#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
+#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
+#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type
+#define TYPE_LENGTH(thistype) (thistype)->length
+#define TYPE_OBJFILE(thistype) (thistype)->objfile
+#define TYPE_FLAGS(thistype) (thistype)->flags
+#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED)
+#define TYPE_CODE(thistype) (thistype)->code
+#define TYPE_NFIELDS(thistype) (thistype)->nfields
+#define TYPE_FIELDS(thistype) (thistype)->fields
+
+/* C++ */
+
+#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno
+#define TYPE_FN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fields
+#define TYPE_NFN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields
+#define TYPE_NFN_FIELDS_TOTAL(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields_total
+#define TYPE_TYPE_SPECIFIC(thistype) (thistype)->type_specific
+#define TYPE_ARG_TYPES(thistype) (thistype)->type_specific.arg_types
+#define TYPE_CPLUS_SPECIFIC(thistype) (thistype)->type_specific.cplus_stuff
+#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type
+#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
+#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name
+#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos
+#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index))
+#define BASETYPE_VIA_VIRTUAL(thistype, index) \
+ B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index))
+
+#define TYPE_FIELD(thistype, n) (thistype)->fields[n]
+#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type
+#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name
+#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type)
+#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos
+#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize
+#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize
+
+#define TYPE_FIELD_PRIVATE_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits
+#define TYPE_FIELD_PROTECTED_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits
+#define TYPE_FIELD_VIRTUAL_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits
+#define SET_TYPE_FIELD_PRIVATE(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n))
+#define SET_TYPE_FIELD_PROTECTED(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n))
+#define SET_TYPE_FIELD_VIRTUAL(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n))
+#define TYPE_FIELD_PRIVATE(thistype, n) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n)))
+#define TYPE_FIELD_PROTECTED(thistype, n) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n)))
+#define TYPE_FIELD_VIRTUAL(thistype, n) \
+ B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n))
+
+#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1)
+#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize)
+
+#define TYPE_FN_FIELDLISTS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists
+#define TYPE_FN_FIELDLIST(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n]
+#define TYPE_FN_FIELDLIST1(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].fn_fields
+#define TYPE_FN_FIELDLIST_NAME(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].name
+#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].length
+
+#define TYPE_FN_FIELD(thisfn, n) (thisfn)[n]
+#define TYPE_FN_FIELD_PHYSNAME(thisfn, n) (thisfn)[n].physname
+#define TYPE_FN_FIELD_TYPE(thisfn, n) (thisfn)[n].type
+#define TYPE_FN_FIELD_ARGS(thisfn, n) TYPE_ARG_TYPES ((thisfn)[n].type)
+#define TYPE_FN_FIELD_CONST(thisfn, n) ((thisfn)[n].is_const)
+#define TYPE_FN_FIELD_VOLATILE(thisfn, n) ((thisfn)[n].is_volatile)
+#define TYPE_FN_FIELD_PRIVATE(thisfn, n) ((thisfn)[n].is_private)
+#define TYPE_FN_FIELD_PROTECTED(thisfn, n) ((thisfn)[n].is_protected)
+#define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub)
+#define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext)
+#define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2)
+#define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
+#define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC)
+
+extern struct type *builtin_type_void;
+extern struct type *builtin_type_char;
+extern struct type *builtin_type_short;
+extern struct type *builtin_type_int;
+extern struct type *builtin_type_long;
+extern struct type *builtin_type_signed_char;
+extern struct type *builtin_type_unsigned_char;
+extern struct type *builtin_type_unsigned_short;
+extern struct type *builtin_type_unsigned_int;
+extern struct type *builtin_type_unsigned_long;
+extern struct type *builtin_type_float;
+extern struct type *builtin_type_double;
+extern struct type *builtin_type_long_double;
+extern struct type *builtin_type_complex;
+extern struct type *builtin_type_double_complex;
+extern struct type *builtin_type_string;
+
+/* This type represents a type that was unrecognized in symbol
+ read-in. */
+
+extern struct type *builtin_type_error;
+
+extern struct type *builtin_type_long_long;
+extern struct type *builtin_type_unsigned_long_long;
+
+/* Modula-2 types */
+
+extern struct type *builtin_type_m2_char;
+extern struct type *builtin_type_m2_int;
+extern struct type *builtin_type_m2_card;
+extern struct type *builtin_type_m2_real;
+extern struct type *builtin_type_m2_bool;
+
+/* Chill types */
+
+extern struct type *builtin_type_chill_bool;
+extern struct type *builtin_type_chill_char;
+extern struct type *builtin_type_chill_long;
+extern struct type *builtin_type_chill_ulong;
+extern struct type *builtin_type_chill_real;
+
+/* CC_HAS_LONG_LONG is defined if the host has "long long". */
+
+#ifdef CC_HAS_LONG_LONG
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long
+
+#else /* not CC_HAS_LONG_LONG. */
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long
+
+#endif /* not CC_HAS_LONG_LONG. */
+
+/* Maximum and minimum values of built-in types */
+
+#define MAX_OF_TYPE(t) \
+ TYPE_UNSIGNED(t) ? UMAX_OF_SIZE(TYPE_LENGTH(t)) \
+ : MAX_OF_SIZE(TYPE_LENGTH(t))
+
+#define MIN_OF_TYPE(t) \
+ TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \
+ : MIN_OF_SIZE(TYPE_LENGTH(t))
+
+/* Allocate space for storing data associated with a particular type.
+ We ensure that the space is allocated using the same mechanism that
+ was used to allocate the space for the type structure itself. I.E.
+ if the type is on an objfile's type_obstack, then the space for data
+ associated with that type will also be allocated on the type_obstack.
+ If the type is not associated with any particular objfile (such as
+ builtin types), then the data space will be allocated with xmalloc,
+ the same as for the type structure. */
+
+#define TYPE_ALLOC(t,size) \
+ (TYPE_OBJFILE (t) != NULL \
+ ? obstack_alloc (&TYPE_OBJFILE (t) -> type_obstack, size) \
+ : xmalloc (size))
+
+extern struct type *
+alloc_type PARAMS ((struct objfile *));
+
+extern struct type *
+init_type PARAMS ((enum type_code, int, int, char *, struct objfile *));
+
+extern struct type *
+lookup_reference_type PARAMS ((struct type *));
+
+extern struct type *
+make_reference_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_member_type PARAMS ((struct type *, struct type *));
+
+extern void
+smash_to_method_type PARAMS ((struct type *, struct type *, struct type *,
+ struct type **));
+
+extern void
+smash_to_member_type PARAMS ((struct type *, struct type *, struct type *));
+
+extern struct type *
+allocate_stub_method PARAMS ((struct type *));
+
+extern char *
+type_name_no_tag PARAMS ((const struct type *));
+
+extern struct type *
+lookup_struct_elt_type PARAMS ((struct type *, char *, int));
+
+extern struct type *
+make_pointer_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_pointer_type PARAMS ((struct type *));
+
+extern struct type *
+make_function_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_function_type PARAMS ((struct type *));
+
+extern struct type *
+create_range_type PARAMS ((struct type *, struct type *, int, int));
+
+extern struct type *
+create_array_type PARAMS ((struct type *, struct type *, struct type *));
+
+extern struct type *
+create_string_type PARAMS ((struct type *, struct type *));
+
+extern struct type *
+lookup_unsigned_typename PARAMS ((char *));
+
+extern struct type *
+lookup_signed_typename PARAMS ((char *));
+
+extern void
+check_stub_type PARAMS ((struct type *));
+
+extern void
+check_stub_method PARAMS ((struct type *, int, int));
+
+extern struct type *
+lookup_primitive_typename PARAMS ((char *));
+
+extern char *
+gdb_mangle_name PARAMS ((struct type *, int, int));
+
+extern struct type *
+builtin_type PARAMS ((char **));
+
+extern struct type *
+lookup_typename PARAMS ((char *, struct block *, int));
+
+extern struct type *
+lookup_template_type PARAMS ((char *, struct type *, struct block *));
+
+extern struct type *
+lookup_fundamental_type PARAMS ((struct objfile *, int));
+
+extern void
+fill_in_vptr_fieldno PARAMS ((struct type *));
+
+#if MAINTENANCE_CMDS
+extern void recursive_dump_type PARAMS ((struct type *, int));
+#endif
+
+/* printcmd.c */
+
+extern void
+print_scalar_formatted PARAMS ((char *, struct type *, int, int, FILE *));
+
+#if MAINTENANCE_CMDS
+extern void maintenance_print_type PARAMS ((char *, int));
+#endif
+
+#endif /* GDBTYPES_H */
diff --git a/gnu/usr.bin/gdb/gdb/getopt.h b/gnu/usr.bin/gdb/gdb/getopt.h
new file mode 100644
index 000000000000..1b546b2e330c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/gdb/gdb/i386-dis.c b/gnu/usr.bin/gdb/gdb/i386-dis.c
new file mode 100644
index 000000000000..3e4bbb225e63
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-dis.c
@@ -0,0 +1,1952 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ * modified by John Hassey (hassey@dg-rtp.dg.com)
+ */
+
+/*
+ * The main tables describing the instructions is essentially a copy
+ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+ * Programmers Manual. Usually, there is a capital letter, followed
+ * by a small letter. The capital letter tell the addressing mode,
+ * and the small letter tells about the operand size. Refer to
+ * the Intel manual for details.
+ */
+
+#include "dis-asm.h"
+
+#define MAXLEN 20
+
+#include <setjmp.h>
+
+struct private
+{
+ /* Points to first byte not fetched. */
+ bfd_byte *max_fetched;
+ bfd_byte the_buffer[MAXLEN];
+ bfd_vma insn_start;
+ jmp_buf bailout;
+};
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+ to ADDR (exclusive) are valid. Returns 1 for success, longjmps
+ on error. */
+#define FETCH_DATA(info, addr) \
+ ((addr) <= ((struct private *)(info->private_data))->max_fetched \
+ ? 1 : fetch_data ((info), (addr)))
+
+static int
+fetch_data (info, addr)
+ struct disassemble_info *info;
+ bfd_byte *addr;
+{
+ int status;
+ struct private *priv = (struct private *)info->private_data;
+ bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+ status = (*info->read_memory_func) (start,
+ priv->max_fetched,
+ addr - priv->max_fetched,
+ info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, start, info);
+ longjmp (priv->bailout, 1);
+ }
+ else
+ priv->max_fetched = addr;
+ return 1;
+}
+
+#define Eb OP_E, b_mode
+#define indirEb OP_indirE, b_mode
+#define Gb OP_G, b_mode
+#define Ev OP_E, v_mode
+#define indirEv OP_indirE, v_mode
+#define Ew OP_E, w_mode
+#define Ma OP_E, v_mode
+#define M OP_E, 0
+#define Mp OP_E, 0 /* ? */
+#define Gv OP_G, v_mode
+#define Gw OP_G, w_mode
+#define Rw OP_rm, w_mode
+#define Rd OP_rm, d_mode
+#define Ib OP_I, b_mode
+#define sIb OP_sI, b_mode /* sign extened byte */
+#define Iv OP_I, v_mode
+#define Iw OP_I, w_mode
+#define Jb OP_J, b_mode
+#define Jv OP_J, v_mode
+#define ONE OP_ONE, 0
+#define Cd OP_C, d_mode
+#define Dd OP_D, d_mode
+#define Td OP_T, d_mode
+
+#define eAX OP_REG, eAX_reg
+#define eBX OP_REG, eBX_reg
+#define eCX OP_REG, eCX_reg
+#define eDX OP_REG, eDX_reg
+#define eSP OP_REG, eSP_reg
+#define eBP OP_REG, eBP_reg
+#define eSI OP_REG, eSI_reg
+#define eDI OP_REG, eDI_reg
+#define AL OP_REG, al_reg
+#define CL OP_REG, cl_reg
+#define DL OP_REG, dl_reg
+#define BL OP_REG, bl_reg
+#define AH OP_REG, ah_reg
+#define CH OP_REG, ch_reg
+#define DH OP_REG, dh_reg
+#define BH OP_REG, bh_reg
+#define AX OP_REG, ax_reg
+#define DX OP_REG, dx_reg
+#define indirDX OP_REG, indir_dx_reg
+
+#define Sw OP_SEG, w_mode
+#define Ap OP_DIR, lptr
+#define Av OP_DIR, v_mode
+#define Ob OP_OFF, b_mode
+#define Ov OP_OFF, v_mode
+#define Xb OP_DSSI, b_mode
+#define Xv OP_DSSI, v_mode
+#define Yb OP_ESDI, b_mode
+#define Yv OP_ESDI, v_mode
+
+#define es OP_REG, es_reg
+#define ss OP_REG, ss_reg
+#define cs OP_REG, cs_reg
+#define ds OP_REG, ds_reg
+#define fs OP_REG, fs_reg
+#define gs OP_REG, gs_reg
+
+int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG();
+int OP_J(), OP_SEG();
+int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C();
+int OP_D(), OP_T(), OP_rm();
+
+static void dofloat (), putop (), append_prefix (), set_op ();
+static int get16 (), get32 ();
+
+#define b_mode 1
+#define v_mode 2
+#define w_mode 3
+#define d_mode 4
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+#define eAX_reg 107
+#define eCX_reg 108
+#define eDX_reg 109
+#define eBX_reg 110
+#define eSP_reg 111
+#define eBP_reg 112
+#define eSI_reg 113
+#define eDI_reg 114
+
+#define lptr 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define indir_dx_reg 150
+
+#define GRP1b NULL, NULL, 0
+#define GRP1S NULL, NULL, 1
+#define GRP1Ss NULL, NULL, 2
+#define GRP2b NULL, NULL, 3
+#define GRP2S NULL, NULL, 4
+#define GRP2b_one NULL, NULL, 5
+#define GRP2S_one NULL, NULL, 6
+#define GRP2b_cl NULL, NULL, 7
+#define GRP2S_cl NULL, NULL, 8
+#define GRP3b NULL, NULL, 9
+#define GRP3S NULL, NULL, 10
+#define GRP4 NULL, NULL, 11
+#define GRP5 NULL, NULL, 12
+#define GRP6 NULL, NULL, 13
+#define GRP7 NULL, NULL, 14
+#define GRP8 NULL, NULL, 15
+
+#define FLOATCODE 50
+#define FLOAT NULL, NULL, FLOATCODE
+
+struct dis386 {
+ char *name;
+ int (*op1)();
+ int bytemode1;
+ int (*op2)();
+ int bytemode2;
+ int (*op3)();
+ int bytemode3;
+};
+
+struct dis386 dis386[] = {
+ /* 00 */
+ { "addb", Eb, Gb },
+ { "addS", Ev, Gv },
+ { "addb", Gb, Eb },
+ { "addS", Gv, Ev },
+ { "addb", AL, Ib },
+ { "addS", eAX, Iv },
+ { "pushl", es },
+ { "popl", es },
+ /* 08 */
+ { "orb", Eb, Gb },
+ { "orS", Ev, Gv },
+ { "orb", Gb, Eb },
+ { "orS", Gv, Ev },
+ { "orb", AL, Ib },
+ { "orS", eAX, Iv },
+ { "pushl", cs },
+ { "(bad)" }, /* 0x0f extended opcode escape */
+ /* 10 */
+ { "adcb", Eb, Gb },
+ { "adcS", Ev, Gv },
+ { "adcb", Gb, Eb },
+ { "adcS", Gv, Ev },
+ { "adcb", AL, Ib },
+ { "adcS", eAX, Iv },
+ { "pushl", ss },
+ { "popl", ss },
+ /* 18 */
+ { "sbbb", Eb, Gb },
+ { "sbbS", Ev, Gv },
+ { "sbbb", Gb, Eb },
+ { "sbbS", Gv, Ev },
+ { "sbbb", AL, Ib },
+ { "sbbS", eAX, Iv },
+ { "pushl", ds },
+ { "popl", ds },
+ /* 20 */
+ { "andb", Eb, Gb },
+ { "andS", Ev, Gv },
+ { "andb", Gb, Eb },
+ { "andS", Gv, Ev },
+ { "andb", AL, Ib },
+ { "andS", eAX, Iv },
+ { "(bad)" }, /* SEG ES prefix */
+ { "daa" },
+ /* 28 */
+ { "subb", Eb, Gb },
+ { "subS", Ev, Gv },
+ { "subb", Gb, Eb },
+ { "subS", Gv, Ev },
+ { "subb", AL, Ib },
+ { "subS", eAX, Iv },
+ { "(bad)" }, /* SEG CS prefix */
+ { "das" },
+ /* 30 */
+ { "xorb", Eb, Gb },
+ { "xorS", Ev, Gv },
+ { "xorb", Gb, Eb },
+ { "xorS", Gv, Ev },
+ { "xorb", AL, Ib },
+ { "xorS", eAX, Iv },
+ { "(bad)" }, /* SEG SS prefix */
+ { "aaa" },
+ /* 38 */
+ { "cmpb", Eb, Gb },
+ { "cmpS", Ev, Gv },
+ { "cmpb", Gb, Eb },
+ { "cmpS", Gv, Ev },
+ { "cmpb", AL, Ib },
+ { "cmpS", eAX, Iv },
+ { "(bad)" }, /* SEG DS prefix */
+ { "aas" },
+ /* 40 */
+ { "incS", eAX },
+ { "incS", eCX },
+ { "incS", eDX },
+ { "incS", eBX },
+ { "incS", eSP },
+ { "incS", eBP },
+ { "incS", eSI },
+ { "incS", eDI },
+ /* 48 */
+ { "decS", eAX },
+ { "decS", eCX },
+ { "decS", eDX },
+ { "decS", eBX },
+ { "decS", eSP },
+ { "decS", eBP },
+ { "decS", eSI },
+ { "decS", eDI },
+ /* 50 */
+ { "pushS", eAX },
+ { "pushS", eCX },
+ { "pushS", eDX },
+ { "pushS", eBX },
+ { "pushS", eSP },
+ { "pushS", eBP },
+ { "pushS", eSI },
+ { "pushS", eDI },
+ /* 58 */
+ { "popS", eAX },
+ { "popS", eCX },
+ { "popS", eDX },
+ { "popS", eBX },
+ { "popS", eSP },
+ { "popS", eBP },
+ { "popS", eSI },
+ { "popS", eDI },
+ /* 60 */
+ { "pusha" },
+ { "popa" },
+ { "boundS", Gv, Ma },
+ { "arpl", Ew, Gw },
+ { "(bad)" }, /* seg fs */
+ { "(bad)" }, /* seg gs */
+ { "(bad)" }, /* op size prefix */
+ { "(bad)" }, /* adr size prefix */
+ /* 68 */
+ { "pushS", Iv }, /* 386 book wrong */
+ { "imulS", Gv, Ev, Iv },
+ { "pushl", sIb }, /* push of byte really pushes 4 bytes */
+ { "imulS", Gv, Ev, Ib },
+ { "insb", Yb, indirDX },
+ { "insS", Yv, indirDX },
+ { "outsb", indirDX, Xb },
+ { "outsS", indirDX, Xv },
+ /* 70 */
+ { "jo", Jb },
+ { "jno", Jb },
+ { "jb", Jb },
+ { "jae", Jb },
+ { "je", Jb },
+ { "jne", Jb },
+ { "jbe", Jb },
+ { "ja", Jb },
+ /* 78 */
+ { "js", Jb },
+ { "jns", Jb },
+ { "jp", Jb },
+ { "jnp", Jb },
+ { "jl", Jb },
+ { "jnl", Jb },
+ { "jle", Jb },
+ { "jg", Jb },
+ /* 80 */
+ { GRP1b },
+ { GRP1S },
+ { "(bad)" },
+ { GRP1Ss },
+ { "testb", Eb, Gb },
+ { "testS", Ev, Gv },
+ { "xchgb", Eb, Gb },
+ { "xchgS", Ev, Gv },
+ /* 88 */
+ { "movb", Eb, Gb },
+ { "movS", Ev, Gv },
+ { "movb", Gb, Eb },
+ { "movS", Gv, Ev },
+ { "movw", Ew, Sw },
+ { "leaS", Gv, M },
+ { "movw", Sw, Ew },
+ { "popS", Ev },
+ /* 90 */
+ { "nop" },
+ { "xchgS", eCX, eAX },
+ { "xchgS", eDX, eAX },
+ { "xchgS", eBX, eAX },
+ { "xchgS", eSP, eAX },
+ { "xchgS", eBP, eAX },
+ { "xchgS", eSI, eAX },
+ { "xchgS", eDI, eAX },
+ /* 98 */
+ { "cwtl" },
+ { "cltd" },
+ { "lcall", Ap },
+ { "(bad)" }, /* fwait */
+ { "pushf" },
+ { "popf" },
+ { "sahf" },
+ { "lahf" },
+ /* a0 */
+ { "movb", AL, Ob },
+ { "movS", eAX, Ov },
+ { "movb", Ob, AL },
+ { "movS", Ov, eAX },
+ { "movsb", Yb, Xb },
+ { "movsS", Yv, Xv },
+ { "cmpsb", Yb, Xb },
+ { "cmpsS", Yv, Xv },
+ /* a8 */
+ { "testb", AL, Ib },
+ { "testS", eAX, Iv },
+ { "stosb", Yb, AL },
+ { "stosS", Yv, eAX },
+ { "lodsb", AL, Xb },
+ { "lodsS", eAX, Xv },
+ { "scasb", AL, Xb },
+ { "scasS", eAX, Xv },
+ /* b0 */
+ { "movb", AL, Ib },
+ { "movb", CL, Ib },
+ { "movb", DL, Ib },
+ { "movb", BL, Ib },
+ { "movb", AH, Ib },
+ { "movb", CH, Ib },
+ { "movb", DH, Ib },
+ { "movb", BH, Ib },
+ /* b8 */
+ { "movS", eAX, Iv },
+ { "movS", eCX, Iv },
+ { "movS", eDX, Iv },
+ { "movS", eBX, Iv },
+ { "movS", eSP, Iv },
+ { "movS", eBP, Iv },
+ { "movS", eSI, Iv },
+ { "movS", eDI, Iv },
+ /* c0 */
+ { GRP2b },
+ { GRP2S },
+ { "ret", Iw },
+ { "ret" },
+ { "lesS", Gv, Mp },
+ { "ldsS", Gv, Mp },
+ { "movb", Eb, Ib },
+ { "movS", Ev, Iv },
+ /* c8 */
+ { "enter", Iw, Ib },
+ { "leave" },
+ { "lret", Iw },
+ { "lret" },
+ { "int3" },
+ { "int", Ib },
+ { "into" },
+ { "iret" },
+ /* d0 */
+ { GRP2b_one },
+ { GRP2S_one },
+ { GRP2b_cl },
+ { GRP2S_cl },
+ { "aam", Ib },
+ { "aad", Ib },
+ { "(bad)" },
+ { "xlat" },
+ /* d8 */
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ /* e0 */
+ { "loopne", Jb },
+ { "loope", Jb },
+ { "loop", Jb },
+ { "jCcxz", Jb },
+ { "inb", AL, Ib },
+ { "inS", eAX, Ib },
+ { "outb", Ib, AL },
+ { "outS", Ib, eAX },
+ /* e8 */
+ { "call", Av },
+ { "jmp", Jv },
+ { "ljmp", Ap },
+ { "jmp", Jb },
+ { "inb", AL, indirDX },
+ { "inS", eAX, indirDX },
+ { "outb", indirDX, AL },
+ { "outS", indirDX, eAX },
+ /* f0 */
+ { "(bad)" }, /* lock prefix */
+ { "(bad)" },
+ { "(bad)" }, /* repne */
+ { "(bad)" }, /* repz */
+ { "hlt" },
+ { "cmc" },
+ { GRP3b },
+ { GRP3S },
+ /* f8 */
+ { "clc" },
+ { "stc" },
+ { "cli" },
+ { "sti" },
+ { "cld" },
+ { "std" },
+ { GRP4 },
+ { GRP5 },
+};
+
+struct dis386 dis386_twobyte[] = {
+ /* 00 */
+ { GRP6 },
+ { GRP7 },
+ { "larS", Gv, Ew },
+ { "lslS", Gv, Ew },
+ { "(bad)" },
+ { "(bad)" },
+ { "clts" },
+ { "(bad)" },
+ /* 08 */
+ { "invd" },
+ { "wbinvd" },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 10 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 18 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 20 */
+ /* these are all backward in appendix A of the intel book */
+ { "movl", Rd, Cd },
+ { "movl", Rd, Dd },
+ { "movl", Cd, Rd },
+ { "movl", Dd, Rd },
+ { "movl", Rd, Td },
+ { "(bad)" },
+ { "movl", Td, Rd },
+ { "(bad)" },
+ /* 28 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 30 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 38 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 40 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 48 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 50 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 58 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 60 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 68 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 70 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 78 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 80 */
+ { "jo", Jv },
+ { "jno", Jv },
+ { "jb", Jv },
+ { "jae", Jv },
+ { "je", Jv },
+ { "jne", Jv },
+ { "jbe", Jv },
+ { "ja", Jv },
+ /* 88 */
+ { "js", Jv },
+ { "jns", Jv },
+ { "jp", Jv },
+ { "jnp", Jv },
+ { "jl", Jv },
+ { "jge", Jv },
+ { "jle", Jv },
+ { "jg", Jv },
+ /* 90 */
+ { "seto", Eb },
+ { "setno", Eb },
+ { "setb", Eb },
+ { "setae", Eb },
+ { "sete", Eb },
+ { "setne", Eb },
+ { "setbe", Eb },
+ { "seta", Eb },
+ /* 98 */
+ { "sets", Eb },
+ { "setns", Eb },
+ { "setp", Eb },
+ { "setnp", Eb },
+ { "setl", Eb },
+ { "setge", Eb },
+ { "setle", Eb },
+ { "setg", Eb },
+ /* a0 */
+ { "pushl", fs },
+ { "popl", fs },
+ { "(bad)" },
+ { "btS", Ev, Gv },
+ { "shldS", Ev, Gv, Ib },
+ { "shldS", Ev, Gv, CL },
+ { "(bad)" },
+ { "(bad)" },
+ /* a8 */
+ { "pushl", gs },
+ { "popl", gs },
+ { "(bad)" },
+ { "btsS", Ev, Gv },
+ { "shrdS", Ev, Gv, Ib },
+ { "shrdS", Ev, Gv, CL },
+ { "(bad)" },
+ { "imulS", Gv, Ev },
+ /* b0 */
+ { "cmpxchgb", Eb, Gb },
+ { "cmpxchgS", Ev, Gv },
+ { "lssS", Gv, Mp }, /* 386 lists only Mp */
+ { "btrS", Ev, Gv },
+ { "lfsS", Gv, Mp }, /* 386 lists only Mp */
+ { "lgsS", Gv, Mp }, /* 386 lists only Mp */
+ { "movzbS", Gv, Eb },
+ { "movzwS", Gv, Ew },
+ /* b8 */
+ { "(bad)" },
+ { "(bad)" },
+ { GRP8 },
+ { "btcS", Ev, Gv },
+ { "bsfS", Gv, Ev },
+ { "bsrS", Gv, Ev },
+ { "movsbS", Gv, Eb },
+ { "movswS", Gv, Ew },
+ /* c0 */
+ { "xaddb", Eb, Gb },
+ { "xaddS", Ev, Gv },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* c8 */
+ { "bswap", eAX },
+ { "bswap", eCX },
+ { "bswap", eDX },
+ { "bswap", eBX },
+ { "bswap", eSP },
+ { "bswap", eBP },
+ { "bswap", eSI },
+ { "bswap", eDI },
+ /* d0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* d8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *codep;
+static disassemble_info *the_info;
+static int mod;
+static int rm;
+static int reg;
+static void oappend ();
+
+static char *names32[]={
+ "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi",
+};
+static char *names16[] = {
+ "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
+};
+static char *names8[] = {
+ "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
+};
+static char *names_seg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+};
+
+struct dis386 grps[][8] = {
+ /* GRP1b */
+ {
+ { "addb", Eb, Ib },
+ { "orb", Eb, Ib },
+ { "adcb", Eb, Ib },
+ { "sbbb", Eb, Ib },
+ { "andb", Eb, Ib },
+ { "subb", Eb, Ib },
+ { "xorb", Eb, Ib },
+ { "cmpb", Eb, Ib }
+ },
+ /* GRP1S */
+ {
+ { "addS", Ev, Iv },
+ { "orS", Ev, Iv },
+ { "adcS", Ev, Iv },
+ { "sbbS", Ev, Iv },
+ { "andS", Ev, Iv },
+ { "subS", Ev, Iv },
+ { "xorS", Ev, Iv },
+ { "cmpS", Ev, Iv }
+ },
+ /* GRP1Ss */
+ {
+ { "addS", Ev, sIb },
+ { "orS", Ev, sIb },
+ { "adcS", Ev, sIb },
+ { "sbbS", Ev, sIb },
+ { "andS", Ev, sIb },
+ { "subS", Ev, sIb },
+ { "xorS", Ev, sIb },
+ { "cmpS", Ev, sIb }
+ },
+ /* GRP2b */
+ {
+ { "rolb", Eb, Ib },
+ { "rorb", Eb, Ib },
+ { "rclb", Eb, Ib },
+ { "rcrb", Eb, Ib },
+ { "shlb", Eb, Ib },
+ { "shrb", Eb, Ib },
+ { "(bad)" },
+ { "sarb", Eb, Ib },
+ },
+ /* GRP2S */
+ {
+ { "rolS", Ev, Ib },
+ { "rorS", Ev, Ib },
+ { "rclS", Ev, Ib },
+ { "rcrS", Ev, Ib },
+ { "shlS", Ev, Ib },
+ { "shrS", Ev, Ib },
+ { "(bad)" },
+ { "sarS", Ev, Ib },
+ },
+ /* GRP2b_one */
+ {
+ { "rolb", Eb },
+ { "rorb", Eb },
+ { "rclb", Eb },
+ { "rcrb", Eb },
+ { "shlb", Eb },
+ { "shrb", Eb },
+ { "(bad)" },
+ { "sarb", Eb },
+ },
+ /* GRP2S_one */
+ {
+ { "rolS", Ev },
+ { "rorS", Ev },
+ { "rclS", Ev },
+ { "rcrS", Ev },
+ { "shlS", Ev },
+ { "shrS", Ev },
+ { "(bad)" },
+ { "sarS", Ev },
+ },
+ /* GRP2b_cl */
+ {
+ { "rolb", Eb, CL },
+ { "rorb", Eb, CL },
+ { "rclb", Eb, CL },
+ { "rcrb", Eb, CL },
+ { "shlb", Eb, CL },
+ { "shrb", Eb, CL },
+ { "(bad)" },
+ { "sarb", Eb, CL },
+ },
+ /* GRP2S_cl */
+ {
+ { "rolS", Ev, CL },
+ { "rorS", Ev, CL },
+ { "rclS", Ev, CL },
+ { "rcrS", Ev, CL },
+ { "shlS", Ev, CL },
+ { "shrS", Ev, CL },
+ { "(bad)" },
+ { "sarS", Ev, CL }
+ },
+ /* GRP3b */
+ {
+ { "testb", Eb, Ib },
+ { "(bad)", Eb },
+ { "notb", Eb },
+ { "negb", Eb },
+ { "mulb", AL, Eb },
+ { "imulb", AL, Eb },
+ { "divb", AL, Eb },
+ { "idivb", AL, Eb }
+ },
+ /* GRP3S */
+ {
+ { "testS", Ev, Iv },
+ { "(bad)" },
+ { "notS", Ev },
+ { "negS", Ev },
+ { "mulS", eAX, Ev },
+ { "imulS", eAX, Ev },
+ { "divS", eAX, Ev },
+ { "idivS", eAX, Ev },
+ },
+ /* GRP4 */
+ {
+ { "incb", Eb },
+ { "decb", Eb },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* GRP5 */
+ {
+ { "incS", Ev },
+ { "decS", Ev },
+ { "call", indirEv },
+ { "lcall", indirEv },
+ { "jmp", indirEv },
+ { "ljmp", indirEv },
+ { "pushS", Ev },
+ { "(bad)" },
+ },
+ /* GRP6 */
+ {
+ { "sldt", Ew },
+ { "str", Ew },
+ { "lldt", Ew },
+ { "ltr", Ew },
+ { "verr", Ew },
+ { "verw", Ew },
+ { "(bad)" },
+ { "(bad)" }
+ },
+ /* GRP7 */
+ {
+ { "sgdt", Ew },
+ { "sidt", Ew },
+ { "lgdt", Ew },
+ { "lidt", Ew },
+ { "smsw", Ew },
+ { "(bad)" },
+ { "lmsw", Ew },
+ { "invlpg", Ew },
+ },
+ /* GRP8 */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "btS", Ev, Ib },
+ { "btsS", Ev, Ib },
+ { "btrS", Ev, Ib },
+ { "btcS", Ev, Ib },
+ }
+};
+
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+static int prefixes;
+
+static void
+ckprefix ()
+{
+ prefixes = 0;
+ while (1)
+ {
+ FETCH_DATA (the_info, codep + 1);
+ switch (*codep)
+ {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ break;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ break;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ break;
+ case 0x2e:
+ prefixes |= PREFIX_CS;
+ break;
+ case 0x36:
+ prefixes |= PREFIX_SS;
+ break;
+ case 0x3e:
+ prefixes |= PREFIX_DS;
+ break;
+ case 0x26:
+ prefixes |= PREFIX_ES;
+ break;
+ case 0x64:
+ prefixes |= PREFIX_FS;
+ break;
+ case 0x65:
+ prefixes |= PREFIX_GS;
+ break;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ break;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ break;
+ case 0x9b:
+ prefixes |= PREFIX_FWAIT;
+ break;
+ default:
+ return;
+ }
+ codep++;
+ }
+}
+
+static int dflag;
+static int aflag;
+
+static char op1out[100], op2out[100], op3out[100];
+static int op_address[3], op_ad, op_index[3];
+static int start_pc;
+
+
+/*
+ * On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ * (see topic "Redundant prefixes" in the "Differences from 8086"
+ * section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ * be used to print the target address if this is a relative jump or call
+ * The function returns the length of this instruction in bytes.
+ */
+
+int
+print_insn_i386 (pc, info)
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ struct dis386 *dp;
+ int i;
+ int enter_instruction;
+ char *first, *second, *third;
+ int needcomma;
+
+ struct private priv;
+ bfd_byte *inbuf = priv.the_buffer;
+
+ info->private_data = (PTR) &priv;
+ priv.max_fetched = priv.the_buffer;
+ priv.insn_start = pc;
+ if (setjmp (priv.bailout) != 0)
+ /* Error return. */
+ return -1;
+
+ obuf[0] = 0;
+ op1out[0] = 0;
+ op2out[0] = 0;
+ op3out[0] = 0;
+
+ op_index[0] = op_index[1] = op_index[2] = -1;
+
+ the_info = info;
+ start_pc = pc;
+ start_codep = inbuf;
+ codep = inbuf;
+
+ ckprefix ();
+
+ FETCH_DATA (info, codep + 1);
+ if (*codep == 0xc8)
+ enter_instruction = 1;
+ else
+ enter_instruction = 0;
+
+ obufp = obuf;
+
+ if (prefixes & PREFIX_REPZ)
+ oappend ("repz ");
+ if (prefixes & PREFIX_REPNZ)
+ oappend ("repnz ");
+ if (prefixes & PREFIX_LOCK)
+ oappend ("lock ");
+
+ if ((prefixes & PREFIX_FWAIT)
+ && ((*codep < 0xd8) || (*codep > 0xdf)))
+ {
+ /* fwait not followed by floating point instruction */
+ (*info->fprintf_func) (info->stream, "fwait");
+ return (1);
+ }
+
+ /* these would be initialized to 0 if disassembling for 8086 or 286 */
+ dflag = 1;
+ aflag = 1;
+
+ if (prefixes & PREFIX_DATA)
+ dflag ^= 1;
+
+ if (prefixes & PREFIX_ADR)
+ {
+ aflag ^= 1;
+ oappend ("addr16 ");
+ }
+
+ if (*codep == 0x0f)
+ {
+ FETCH_DATA (info, codep + 2);
+ dp = &dis386_twobyte[*++codep];
+ }
+ else
+ dp = &dis386[*codep];
+ codep++;
+ FETCH_DATA (info, codep + 1);
+ mod = (*codep >> 6) & 3;
+ reg = (*codep >> 3) & 7;
+ rm = *codep & 7;
+
+ if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+ {
+ dofloat ();
+ }
+ else
+ {
+ if (dp->name == NULL)
+ dp = &grps[dp->bytemode1][reg];
+
+ putop (dp->name);
+
+ obufp = op1out;
+ op_ad = 2;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+
+ obufp = op2out;
+ op_ad = 1;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+
+ obufp = op3out;
+ op_ad = 0;
+ if (dp->op3)
+ (*dp->op3)(dp->bytemode3);
+ }
+
+ obufp = obuf + strlen (obuf);
+ for (i = strlen (obuf); i < 6; i++)
+ oappend (" ");
+ oappend (" ");
+ (*info->fprintf_func) (info->stream, "%s", obuf);
+
+ /* enter instruction is printed with operands in the
+ * same order as the intel book; everything else
+ * is printed in reverse order
+ */
+ if (enter_instruction)
+ {
+ first = op1out;
+ second = op2out;
+ third = op3out;
+ op_ad = op_index[0];
+ op_index[0] = op_index[2];
+ op_index[2] = op_ad;
+ }
+ else
+ {
+ first = op3out;
+ second = op2out;
+ third = op1out;
+ }
+ needcomma = 0;
+ if (*first)
+ {
+ if (op_index[0] != -1)
+ (*info->print_address_func) (op_address[op_index[0]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", first);
+ needcomma = 1;
+ }
+ if (*second)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[1] != -1)
+ (*info->print_address_func) (op_address[op_index[1]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", second);
+ needcomma = 1;
+ }
+ if (*third)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[2] != -1)
+ (*info->print_address_func) (op_address[op_index[2]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", third);
+ }
+ return (codep - inbuf);
+}
+
+char *float_mem[] = {
+ /* d8 */
+ "fadds",
+ "fmuls",
+ "fcoms",
+ "fcomps",
+ "fsubs",
+ "fsubrs",
+ "fdivs",
+ "fdivrs",
+ /* d9 */
+ "flds",
+ "(bad)",
+ "fsts",
+ "fstps",
+ "fldenv",
+ "fldcw",
+ "fNstenv",
+ "fNstcw",
+ /* da */
+ "fiaddl",
+ "fimull",
+ "ficoml",
+ "ficompl",
+ "fisubl",
+ "fisubrl",
+ "fidivl",
+ "fidivrl",
+ /* db */
+ "fildl",
+ "(bad)",
+ "fistl",
+ "fistpl",
+ "(bad)",
+ "fldt",
+ "(bad)",
+ "fstpt",
+ /* dc */
+ "faddl",
+ "fmull",
+ "fcoml",
+ "fcompl",
+ "fsubl",
+ "fsubrl",
+ "fdivl",
+ "fdivrl",
+ /* dd */
+ "fldl",
+ "(bad)",
+ "fstl",
+ "fstpl",
+ "frstor",
+ "(bad)",
+ "fNsave",
+ "fNstsw",
+ /* de */
+ "fiadd",
+ "fimul",
+ "ficom",
+ "ficomp",
+ "fisub",
+ "fisubr",
+ "fidiv",
+ "fidivr",
+ /* df */
+ "fild",
+ "(bad)",
+ "fist",
+ "fistp",
+ "fbld",
+ "fildll",
+ "fbstp",
+ "fistpll",
+};
+
+#define ST OP_ST, 0
+#define STi OP_STi, 0
+int OP_ST(), OP_STi();
+
+#define FGRPd9_2 NULL, NULL, 0
+#define FGRPd9_4 NULL, NULL, 1
+#define FGRPd9_5 NULL, NULL, 2
+#define FGRPd9_6 NULL, NULL, 3
+#define FGRPd9_7 NULL, NULL, 4
+#define FGRPda_5 NULL, NULL, 5
+#define FGRPdb_4 NULL, NULL, 6
+#define FGRPde_3 NULL, NULL, 7
+#define FGRPdf_4 NULL, NULL, 8
+
+struct dis386 float_reg[][8] = {
+ /* d8 */
+ {
+ { "fadd", ST, STi },
+ { "fmul", ST, STi },
+ { "fcom", STi },
+ { "fcomp", STi },
+ { "fsub", ST, STi },
+ { "fsubr", ST, STi },
+ { "fdiv", ST, STi },
+ { "fdivr", ST, STi },
+ },
+ /* d9 */
+ {
+ { "fld", STi },
+ { "fxch", STi },
+ { FGRPd9_2 },
+ { "(bad)" },
+ { FGRPd9_4 },
+ { FGRPd9_5 },
+ { FGRPd9_6 },
+ { FGRPd9_7 },
+ },
+ /* da */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPda_5 },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* db */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdb_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* dc */
+ {
+ { "fadd", STi, ST },
+ { "fmul", STi, ST },
+ { "(bad)" },
+ { "(bad)" },
+ { "fsub", STi, ST },
+ { "fsubr", STi, ST },
+ { "fdiv", STi, ST },
+ { "fdivr", STi, ST },
+ },
+ /* dd */
+ {
+ { "ffree", STi },
+ { "(bad)" },
+ { "fst", STi },
+ { "fstp", STi },
+ { "fucom", STi },
+ { "fucomp", STi },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* de */
+ {
+ { "faddp", STi, ST },
+ { "fmulp", STi, ST },
+ { "(bad)" },
+ { FGRPde_3 },
+ { "fsubp", STi, ST },
+ { "fsubrp", STi, ST },
+ { "fdivp", STi, ST },
+ { "fdivrp", STi, ST },
+ },
+ /* df */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdf_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+};
+
+
+char *fgrps[][8] = {
+ /* d9_2 0 */
+ {
+ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* d9_4 1 */
+ {
+ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+ },
+
+ /* d9_5 2 */
+ {
+ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+ },
+
+ /* d9_6 3 */
+ {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+ },
+
+ /* d9_7 4 */
+ {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+ },
+
+ /* da_5 5 */
+ {
+ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* db_4 6 */
+ {
+ "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+ "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+ },
+
+ /* de_3 7 */
+ {
+ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* df_4 8 */
+ {
+ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+};
+
+static void
+dofloat ()
+{
+ struct dis386 *dp;
+ unsigned char floatop;
+
+ floatop = codep[-1];
+
+ if (mod != 3)
+ {
+ putop (float_mem[(floatop - 0xd8) * 8 + reg]);
+ obufp = op1out;
+ OP_E (v_mode);
+ return;
+ }
+ codep++;
+
+ dp = &float_reg[floatop - 0xd8][reg];
+ if (dp->name == NULL)
+ {
+ putop (fgrps[dp->bytemode1][rm]);
+ /* instruction fnstsw is only one with strange arg */
+ if (floatop == 0xdf
+ && FETCH_DATA (the_info, codep + 1)
+ && *codep == 0xe0)
+ strcpy (op1out, "%eax");
+ }
+ else
+ {
+ putop (dp->name);
+ obufp = op1out;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+ }
+}
+
+/* ARGSUSED */
+int
+OP_ST (ignore)
+ int ignore;
+{
+ oappend ("%st");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_STi (ignore)
+ int ignore;
+{
+ sprintf (scratchbuf, "%%st(%d)", rm);
+ oappend (scratchbuf);
+ return (0);
+}
+
+
+/* capital letters in template are macros */
+static void
+putop (template)
+ char *template;
+{
+ char *p;
+
+ for (p = template; *p; p++)
+ {
+ switch (*p)
+ {
+ default:
+ *obufp++ = *p;
+ break;
+ case 'C': /* For jcxz/jecxz */
+ if (aflag == 0)
+ *obufp++ = 'e';
+ break;
+ case 'N':
+ if ((prefixes & PREFIX_FWAIT) == 0)
+ *obufp++ = 'n';
+ break;
+ case 'S':
+ /* operand size flag */
+ if (dflag)
+ *obufp++ = 'l';
+ else
+ *obufp++ = 'w';
+ break;
+ }
+ }
+ *obufp = 0;
+}
+
+static void
+oappend (s)
+ char *s;
+{
+ strcpy (obufp, s);
+ obufp += strlen (s);
+ *obufp = 0;
+}
+
+static void
+append_prefix ()
+{
+ if (prefixes & PREFIX_CS)
+ oappend ("%cs:");
+ if (prefixes & PREFIX_DS)
+ oappend ("%ds:");
+ if (prefixes & PREFIX_SS)
+ oappend ("%ss:");
+ if (prefixes & PREFIX_ES)
+ oappend ("%es:");
+ if (prefixes & PREFIX_FS)
+ oappend ("%fs:");
+ if (prefixes & PREFIX_GS)
+ oappend ("%gs:");
+}
+
+int
+OP_indirE (bytemode)
+ int bytemode;
+{
+ oappend ("*");
+ OP_E (bytemode);
+ return (0);
+}
+
+int
+OP_E (bytemode)
+ int bytemode;
+{
+ int disp;
+ int havesib;
+ int base;
+ int index;
+ int scale;
+ int havebase;
+
+ /* skip mod/rm byte */
+ codep++;
+
+ havesib = 0;
+ havebase = 0;
+ disp = 0;
+
+ if (mod == 3)
+ {
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[rm]);
+ else
+ oappend (names16[rm]);
+ break;
+ default:
+ oappend ("<bad dis table>");
+ break;
+ }
+ return (0);
+ }
+
+ append_prefix ();
+ if (rm == 4)
+ {
+ havesib = 1;
+ havebase = 1;
+ FETCH_DATA (the_info, codep + 1);
+ scale = (*codep >> 6) & 3;
+ index = (*codep >> 3) & 7;
+ base = *codep & 7;
+ codep++;
+ }
+
+ switch (mod)
+ {
+ case 0:
+ switch (rm)
+ {
+ case 4:
+ /* implies havesib and havebase */
+ if (base == 5) {
+ havebase = 0;
+ disp = get32 ();
+ }
+ break;
+ case 5:
+ disp = get32 ();
+ break;
+ default:
+ havebase = 1;
+ base = rm;
+ break;
+ }
+ break;
+ case 1:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ case 2:
+ disp = get32 ();
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ }
+
+ if (mod != 0 || rm == 5 || (havesib && base == 5))
+ {
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ }
+
+ if (havebase || havesib)
+ {
+ oappend ("(");
+ if (havebase)
+ oappend (names32[base]);
+ if (havesib)
+ {
+ if (index != 4)
+ {
+ sprintf (scratchbuf, ",%s", names32[index]);
+ oappend (scratchbuf);
+ }
+ sprintf (scratchbuf, ",%d", 1 << scale);
+ oappend (scratchbuf);
+ }
+ oappend (")");
+ }
+ return (0);
+}
+
+int
+OP_G (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[reg]);
+ break;
+ case w_mode:
+ oappend (names16[reg]);
+ break;
+ case d_mode:
+ oappend (names32[reg]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[reg]);
+ else
+ oappend (names16[reg]);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+static int
+get32 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 4);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ x |= (*codep++ & 0xff) << 16;
+ x |= (*codep++ & 0xff) << 24;
+ return (x);
+}
+
+static int
+get16 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 2);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ return (x);
+}
+
+static void
+set_op (op)
+ int op;
+{
+ op_index[op_ad] = op_ad;
+ op_address[op_ad] = op;
+}
+
+int
+OP_REG (code)
+ int code;
+{
+ char *s;
+
+ switch (code)
+ {
+ case indir_dx_reg: s = "(%dx)"; break;
+ case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+ case sp_reg: case bp_reg: case si_reg: case di_reg:
+ s = names16[code - ax_reg];
+ break;
+ case es_reg: case ss_reg: case cs_reg:
+ case ds_reg: case fs_reg: case gs_reg:
+ s = names_seg[code - es_reg];
+ break;
+ case al_reg: case ah_reg: case cl_reg: case ch_reg:
+ case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+ s = names8[code - al_reg];
+ break;
+ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+ if (dflag)
+ s = names32[code - eAX_reg];
+ else
+ s = names16[code - eAX_reg];
+ break;
+ default:
+ s = "<internal disassembler error>";
+ break;
+ }
+ oappend (s);
+ return (0);
+}
+
+int
+OP_I (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *codep++ & 0xff;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = get16 ();
+ break;
+ case w_mode:
+ op = get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_sI (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = (short)get16();
+ break;
+ case w_mode:
+ op = (short)get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_J (bytemode)
+ int bytemode;
+{
+ int disp;
+ int mask = -1;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ disp = get32 ();
+ else
+ {
+ disp = (short)get16 ();
+ /* for some reason, a data16 prefix on a jump instruction
+ means that the pc is masked to 16 bits after the
+ displacement is added! */
+ mask = 0xffff;
+ }
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ disp = (start_pc + codep - start_codep + disp) & mask;
+ set_op (disp);
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_SEG (dummy)
+ int dummy;
+{
+ static char *sreg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+ };
+
+ oappend (sreg[reg]);
+ return (0);
+}
+
+int
+OP_DIR (size)
+ int size;
+{
+ int seg, offset;
+
+ switch (size)
+ {
+ case lptr:
+ if (aflag)
+ {
+ offset = get32 ();
+ seg = get16 ();
+ }
+ else
+ {
+ offset = get16 ();
+ seg = get16 ();
+ }
+ sprintf (scratchbuf, "0x%x,0x%x", seg, offset);
+ oappend (scratchbuf);
+ break;
+ case v_mode:
+ if (aflag)
+ offset = get32 ();
+ else
+ offset = (short)get16 ();
+
+ offset = start_pc + codep - start_codep + offset;
+ set_op (offset);
+ sprintf (scratchbuf, "0x%x", offset);
+ oappend (scratchbuf);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_OFF (bytemode)
+ int bytemode;
+{
+ int off;
+
+ if (aflag)
+ off = get32 ();
+ else
+ off = get16 ();
+
+ sprintf (scratchbuf, "0x%x", off);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ESDI (dummy)
+ int dummy;
+{
+ oappend ("%es:(");
+ oappend (aflag ? "%edi" : "%di");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_DSSI (dummy)
+ int dummy;
+{
+ oappend ("%ds:(");
+ oappend (aflag ? "%esi" : "%si");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ONE (dummy)
+ int dummy;
+{
+ oappend ("1");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_C (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%cr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_D (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%db%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_T (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%tr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_rm (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case d_mode:
+ oappend (names32[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ }
+ return (0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/i386-pinsn.c b/gnu/usr.bin/gdb/gdb/i386-pinsn.c
new file mode 100644
index 000000000000..b6d7fe91e39f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-pinsn.c
@@ -0,0 +1,37 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "dis-asm.h"
+
+
+/* Print the instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ FILE *stream;
+{
+ disassemble_info info;
+
+ GDB_INIT_DISASSEMBLE_INFO(info, stream);
+
+ return print_insn_i386 (memaddr, &info);
+}
diff --git a/gnu/usr.bin/gdb/gdb/i386-tdep.c b/gnu/usr.bin/gdb/gdb/i386-tdep.c
new file mode 100644
index 000000000000..3c64d7224cf0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-tdep.c
@@ -0,0 +1,595 @@
+/* Intel 386 target-dependent stuff.
+ Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+
+static long
+i386_get_frame_setup PARAMS ((int));
+
+static void
+i386_follow_jump PARAMS ((void));
+
+static void
+codestream_read PARAMS ((unsigned char *, int));
+
+static void
+codestream_seek PARAMS ((int));
+
+static unsigned char
+codestream_fill PARAMS ((int));
+
+/* helper functions for tm-i386.h */
+
+/* Stdio style buffering was used to minimize calls to ptrace, but this
+ buffering did not take into account that the code section being accessed
+ may not be an even number of buffers long (even if the buffer is only
+ sizeof(int) long). In cases where the code section size happened to
+ be a non-integral number of buffers long, attempting to read the last
+ buffer would fail. Simply using target_read_memory and ignoring errors,
+ rather than read_memory, is not the correct solution, since legitimate
+ access errors would then be totally ignored. To properly handle this
+ situation and continue to use buffering would require that this code
+ be able to determine the minimum code section size granularity (not the
+ alignment of the section itself, since the actual failing case that
+ pointed out this problem had a section alignment of 4 but was not a
+ multiple of 4 bytes long), on a target by target basis, and then
+ adjust it's buffer size accordingly. This is messy, but potentially
+ feasible. It probably needs the bfd library's help and support. For
+ now, the buffer size is set to 1. (FIXME -fnf) */
+
+#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[CODESTREAM_BUFSIZ];
+static int codestream_off;
+static int codestream_cnt;
+
+#define codestream_tell() (codestream_addr + codestream_off)
+#define codestream_peek() (codestream_cnt == 0 ? \
+ codestream_fill(1): codestream_buf[codestream_off])
+#define codestream_get() (codestream_cnt-- == 0 ? \
+ codestream_fill(0) : codestream_buf[codestream_off++])
+
+static unsigned char
+codestream_fill (peek_flag)
+ int peek_flag;
+{
+ codestream_addr = codestream_next_addr;
+ codestream_next_addr += CODESTREAM_BUFSIZ;
+ codestream_off = 0;
+ codestream_cnt = CODESTREAM_BUFSIZ;
+ read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
+
+ if (peek_flag)
+ return (codestream_peek());
+ else
+ return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+ int place;
+{
+ codestream_next_addr = place / CODESTREAM_BUFSIZ;
+ codestream_next_addr *= CODESTREAM_BUFSIZ;
+ codestream_cnt = 0;
+ codestream_fill (1);
+ while (codestream_tell() != place)
+ codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+ unsigned char *buf;
+ int count;
+{
+ unsigned char *p;
+ int i;
+ p = buf;
+ for (i = 0; i < count; i++)
+ *p++ = codestream_get ();
+}
+
+/* next instruction is a jump, move to target */
+
+static void
+i386_follow_jump ()
+{
+ unsigned char buf[4];
+ long delta;
+
+ int data16;
+ CORE_ADDR pos;
+
+ pos = codestream_tell ();
+
+ data16 = 0;
+ if (codestream_peek () == 0x66)
+ {
+ codestream_get ();
+ data16 = 1;
+ }
+
+ switch (codestream_get ())
+ {
+ case 0xe9:
+ /* relative jump: if data16 == 0, disp32, else disp16 */
+ if (data16)
+ {
+ codestream_read (buf, 2);
+ delta = extract_signed_integer (buf, 2);
+
+ /* include size of jmp inst (including the 0x66 prefix). */
+ pos += delta + 4;
+ }
+ else
+ {
+ codestream_read (buf, 4);
+ delta = extract_signed_integer (buf, 4);
+
+ pos += delta + 5;
+ }
+ break;
+ case 0xeb:
+ /* relative jump, disp8 (ignore data16) */
+ codestream_read (buf, 1);
+ /* Sign-extend it. */
+ delta = extract_signed_integer (buf, 1);
+
+ pos += delta + 2;
+ break;
+ }
+ codestream_seek (pos);
+}
+
+/*
+ * find & return amound a local space allocated, and advance codestream to
+ * first register push (if any)
+ *
+ * if entry sequence doesn't make sense, return -1, and leave
+ * codestream pointer random
+ */
+
+static long
+i386_get_frame_setup (pc)
+ int pc;
+{
+ unsigned char op;
+
+ codestream_seek (pc);
+
+ i386_follow_jump ();
+
+ op = codestream_get ();
+
+ if (op == 0x58) /* popl %eax */
+ {
+ /*
+ * this function must start with
+ *
+ * popl %eax 0x58
+ * xchgl %eax, (%esp) 0x87 0x04 0x24
+ * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
+ *
+ * (the system 5 compiler puts out the second xchg
+ * inst, and the assembler doesn't try to optimize it,
+ * so the 'sib' form gets generated)
+ *
+ * this sequence is used to get the address of the return
+ * buffer for a function that returns a structure
+ */
+ int pos;
+ unsigned char buf[4];
+ static unsigned char proto1[3] = { 0x87,0x04,0x24 };
+ static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
+ pos = codestream_tell ();
+ codestream_read (buf, 4);
+ if (memcmp (buf, proto1, 3) == 0)
+ pos += 3;
+ else if (memcmp (buf, proto2, 4) == 0)
+ pos += 4;
+
+ codestream_seek (pos);
+ op = codestream_get (); /* update next opcode */
+ }
+
+ if (op == 0x55) /* pushl %ebp */
+ {
+ /* check for movl %esp, %ebp - can be written two ways */
+ switch (codestream_get ())
+ {
+ case 0x8b:
+ if (codestream_get () != 0xec)
+ return (-1);
+ break;
+ case 0x89:
+ if (codestream_get () != 0xe5)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ /* check for stack adjustment
+ *
+ * subl $XXX, %esp
+ *
+ * note: you can't subtract a 16 bit immediate
+ * from a 32 bit reg, so we don't have to worry
+ * about a data16 prefix
+ */
+ op = codestream_peek ();
+ if (op == 0x83)
+ {
+ /* subl with 8 bit immed */
+ codestream_get ();
+ if (codestream_get () != 0xec)
+ /* Some instruction starting with 0x83 other than subl. */
+ {
+ codestream_seek (codestream_tell () - 2);
+ return 0;
+ }
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ return (codestream_get());
+ }
+ else if (op == 0x81)
+ {
+ char buf[4];
+ /* Maybe it is subl with 32 bit immedediate. */
+ codestream_get();
+ if (codestream_get () != 0xec)
+ /* Some instruction starting with 0x81 other than subl. */
+ {
+ codestream_seek (codestream_tell () - 2);
+ return 0;
+ }
+ /* It is subl with 32 bit immediate. */
+ codestream_read ((unsigned char *)buf, 4);
+ return extract_signed_integer (buf, 4);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+ else if (op == 0xc8)
+ {
+ char buf[2];
+ /* enter instruction: arg is 16 bit unsigned immed */
+ codestream_read ((unsigned char *)buf, 2);
+ codestream_get (); /* flush final byte of enter instruction */
+ return extract_unsigned_integer (buf, 2);
+ }
+ return (-1);
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+int
+i386_frame_num_args (fi)
+ struct frame_info *fi;
+{
+#if 1
+ return -1;
+#else
+ /* This loses because not only might the compiler not be popping the
+ args right after the function call, it might be popping args from both
+ this call and a previous one, and we would say there are more args
+ than there really are. */
+
+ int retpc;
+ unsigned char op;
+ struct frame_info *pfi;
+
+ /* on the 386, the instruction following the call could be:
+ popl %ecx - one arg
+ addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
+ anything else - zero args */
+
+ int frameless;
+
+ FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
+ if (frameless)
+ /* In the absence of a frame pointer, GDB doesn't get correct values
+ for nameless arguments. Return -1, so it doesn't print any
+ nameless arguments. */
+ return -1;
+
+ pfi = get_prev_frame_info (fi);
+ if (pfi == 0)
+ {
+ /* Note: this can happen if we are looking at the frame for
+ main, because FRAME_CHAIN_VALID won't let us go into
+ start. If we have debugging symbols, that's not really
+ a big deal; it just means it will only show as many arguments
+ to main as are declared. */
+ return -1;
+ }
+ else
+ {
+ retpc = pfi->pc;
+ op = read_memory_integer (retpc, 1);
+ if (op == 0x59)
+ /* pop %ecx */
+ return 1;
+ else if (op == 0x83)
+ {
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<signed imm 8 bits>, %esp */
+ return (read_memory_integer (retpc+2,1)&0xff)/4;
+ else
+ return 0;
+ }
+ else if (op == 0x81)
+ { /* add with 32 bit immediate */
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<imm 32>, %esp */
+ return read_memory_integer (retpc+2, 4) / 4;
+ else
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+#endif
+}
+
+/*
+ * parse the first few instructions of the function to see
+ * what registers were stored.
+ *
+ * We handle these cases:
+ *
+ * The startup sequence can be at the start of the function,
+ * or the function can start with a branch to startup code at the end.
+ *
+ * %ebp can be set up with either the 'enter' instruction, or
+ * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
+ * but was once used in the sys5 compiler)
+ *
+ * Local space is allocated just below the saved %ebp by either the
+ * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
+ * a 16 bit unsigned argument for space to allocate, and the
+ * 'addl' instruction could have either a signed byte, or
+ * 32 bit immediate.
+ *
+ * Next, the registers used by this function are pushed. In
+ * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
+ * (and sometimes a harmless bug causes it to also save but not restore %eax);
+ * however, the code below is willing to see the pushes in any order,
+ * and will handle up to 8 of them.
+ *
+ * If the setup sequence is at the end of the function, then the
+ * next instruction will be a branch back to the start.
+ */
+
+void
+i386_frame_find_saved_regs (fip, fsrp)
+ struct frame_info *fip;
+ struct frame_saved_regs *fsrp;
+{
+ long locals;
+ unsigned char op;
+ CORE_ADDR dummy_bottom;
+ CORE_ADDR adr;
+ int i;
+
+ memset (fsrp, 0, sizeof *fsrp);
+
+ /* if frame is the end of a dummy, compute where the
+ * beginning would be
+ */
+ dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
+
+ /* check if the PC is in the stack, in a dummy frame */
+ if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
+ {
+ /* all regs were saved by push_call_dummy () */
+ adr = fip->frame;
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ adr -= REGISTER_RAW_SIZE (i);
+ fsrp->regs[i] = adr;
+ }
+ return;
+ }
+
+ locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
+
+ if (locals >= 0)
+ {
+ adr = fip->frame - 4 - locals;
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_get ();
+ if (op < 0x50 || op > 0x57)
+ break;
+ fsrp->regs[op - 0x50] = adr;
+ adr -= 4;
+ }
+ }
+
+ fsrp->regs[PC_REGNUM] = fip->frame + 4;
+ fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+
+int
+i386_skip_prologue (pc)
+ int pc;
+{
+ unsigned char op;
+ int i;
+
+ if (i386_get_frame_setup (pc) < 0)
+ return (pc);
+
+ /* found valid frame setup - codestream now points to
+ * start of push instructions for saving registers
+ */
+
+ /* skip over register saves */
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_peek ();
+ /* break if not pushl inst */
+ if (op < 0x50 || op > 0x57)
+ break;
+ codestream_get ();
+ }
+
+ i386_follow_jump ();
+
+ return (codestream_tell ());
+}
+
+void
+i386_push_dummy_frame ()
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ int regnum;
+ char regbuf[MAX_REGISTER_RAW_SIZE];
+
+ sp = push_word (sp, read_register (PC_REGNUM));
+ sp = push_word (sp, read_register (FP_REGNUM));
+ write_register (FP_REGNUM, sp);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ {
+ read_register_gen (regnum, regbuf);
+ sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
+ }
+ write_register (SP_REGNUM, sp);
+}
+
+void
+i386_pop_frame ()
+{
+ FRAME frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+ struct frame_saved_regs fsr;
+ struct frame_info *fi;
+ char regbuf[MAX_REGISTER_RAW_SIZE];
+
+ fi = get_frame_info (frame);
+ fp = fi->frame;
+ get_frame_saved_regs (fi, &fsr);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ {
+ CORE_ADDR adr;
+ adr = fsr.regs[regnum];
+ if (adr)
+ {
+ read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
+ write_register_bytes (REGISTER_BYTE (regnum), regbuf,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
+ write_register (FP_REGNUM, read_memory_integer (fp, 4));
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+ write_register (SP_REGNUM, fp + 8);
+ flush_cached_frames ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+}
+
+#ifdef GET_LONGJMP_TARGET
+
+/* Figure out where the longjmp will land. Slurp the args out of the stack.
+ We expect the first arg to be a pointer to the jmp_buf structure from which
+ we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
+ This routine returns true on success. */
+
+int
+get_longjmp_target(pc)
+ CORE_ADDR *pc;
+{
+ char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+ CORE_ADDR sp, jb_addr;
+
+ sp = read_register (SP_REGNUM);
+
+ if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
+ buf,
+ TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ return 0;
+
+ jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
+ TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ return 0;
+
+ *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ return 1;
+}
+
+#endif /* GET_LONGJMP_TARGET */
+
+#ifdef I386_AIX_TARGET
+/* On AIX, floating point values are returned in floating point registers. */
+
+void
+i386_extract_return_value(type, regbuf, valbuf)
+ struct type *type;
+ char regbuf[REGISTER_BYTES];
+ char *valbuf;
+{
+ if (TYPE_CODE_FLT == TYPE_CODE(type))
+ {
+ extern struct ext_format ext_format_i387;
+ double d;
+ /* 387 %st(0), gcc uses this */
+ ieee_extended_to_double (&ext_format_i387,
+ &regbuf[REGISTER_BYTE(FP0_REGNUM)],
+ &d);
+ switch (TYPE_LENGTH(type))
+ {
+ case 4: /* float */
+ {
+ float f = (float) d;
+ memcpy (valbuf, &f, 4);
+ break;
+ }
+ case 8: /* double */
+ memcpy (valbuf, &d, 8);
+ break;
+ default:
+ error("Unknown floating point size");
+ break;
+ }
+ }
+ else
+ {
+ memcpy (valbuf, regbuf, TYPE_LENGTH (type));
+ }
+}
+#endif /* I386_AIX_TARGET */
diff --git a/gnu/usr.bin/gdb/gdb/infcmd.c b/gnu/usr.bin/gdb/gdb/infcmd.c
new file mode 100644
index 000000000000..5859ed269f85
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infcmd.c
@@ -0,0 +1,1423 @@
+/* Memory-access and commands for "inferior" (child) process, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <signal.h>
+#include <sys/param.h>
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+
+static void
+continue_command PARAMS ((char *, int));
+
+static void
+until_next_command PARAMS ((int));
+
+static void
+until_command PARAMS ((char *, int));
+
+static void
+path_info PARAMS ((char *, int));
+
+static void
+path_command PARAMS ((char *, int));
+
+static void
+unset_command PARAMS ((char *, int));
+
+static void
+float_info PARAMS ((char *, int));
+
+static void
+detach_command PARAMS ((char *, int));
+
+static void
+nofp_registers_info PARAMS ((char *, int));
+
+static void
+all_registers_info PARAMS ((char *, int));
+
+static void
+registers_info PARAMS ((char *, int));
+
+static void
+do_registers_info PARAMS ((int, int));
+
+static void
+unset_environment_command PARAMS ((char *, int));
+
+static void
+set_environment_command PARAMS ((char *, int));
+
+static void
+environment_info PARAMS ((char *, int));
+
+static void
+program_info PARAMS ((char *, int));
+
+static void
+finish_command PARAMS ((char *, int));
+
+static void
+signal_command PARAMS ((char *, int));
+
+static void
+jump_command PARAMS ((char *, int));
+
+static void
+step_1 PARAMS ((int, int, char *));
+
+static void
+nexti_command PARAMS ((char *, int));
+
+static void
+stepi_command PARAMS ((char *, int));
+
+static void
+next_command PARAMS ((char *, int));
+
+static void
+step_command PARAMS ((char *, int));
+
+static void
+run_command PARAMS ((char *, int));
+
+#define ERROR_NO_INFERIOR \
+ if (!target_has_execution) error ("The program is not being run.");
+
+/* String containing arguments to give to the program, separated by spaces.
+ Empty string (pointer to '\0') means no args. */
+
+static char *inferior_args;
+
+/* File name for default use for standard in/out in the inferior. */
+
+char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now.
+ Since various parts of infrun.c test this to see whether there is a program
+ being debugged it should be nonzero (currently 3 is used) for remote
+ debugging. */
+
+int inferior_pid;
+
+/* Last signal that the inferior received (why it stopped). */
+
+int stop_signal;
+
+/* Address at which inferior stopped. */
+
+CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at. */
+
+bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+ current breakpoint. */
+
+int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command. */
+
+int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine. */
+
+int stop_stack_dummy;
+
+/* Nonzero if stopped due to a random (unexpected) signal in inferior
+ process. */
+
+int stopped_by_random_signal;
+
+/* Range to single step within.
+ If this is nonzero, respond to a single-step signal
+ by continuing to step if the pc is in this range. */
+
+CORE_ADDR step_range_start; /* Inclusive */
+CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call,
+ and how to set the frame for the breakpoint used to step out. */
+
+FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+ 0 means don't step over calls (used by stepi).
+ -1 means step over calls to undebuggable functions. */
+
+int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+ so don't print frame next time inferior stops
+ if it stops due to stepping. */
+
+int step_multi;
+
+/* Environment to use for running inferior,
+ in format described in environ.h. */
+
+struct environ *inferior_environ;
+
+
+/* ARGSUSED */
+void
+tty_command (file, from_tty)
+ char *file;
+ int from_tty;
+{
+ if (file == 0)
+ error_no_arg ("terminal name for running target process");
+
+ inferior_io_terminal = savestring (file, strlen (file));
+}
+
+static void
+run_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+
+ dont_repeat ();
+
+ /* Shouldn't this be target_has_execution? FIXME. */
+ if (inferior_pid)
+ {
+ if (
+ !query ("The program being debugged has been started already.\n\
+Start it from the beginning? "))
+ error ("Program not restarted.");
+ target_kill ();
+ }
+
+ exec_file = (char *) get_exec_file (0);
+
+ /* The exec file is re-read every time we do a generic_mourn_inferior, so
+ we just have to worry about the symbol file. */
+ reread_symbols ();
+
+ if (args)
+ {
+ char *cmd;
+ cmd = concat ("set args ", args, NULL);
+ make_cleanup (free, cmd);
+ execute_command (cmd, from_tty);
+ }
+
+ if (from_tty)
+ {
+ puts_filtered("Starting program: ");
+ if (exec_file)
+ puts_filtered(exec_file);
+ puts_filtered(" ");
+ puts_filtered(inferior_args);
+ puts_filtered("\n");
+ fflush (stdout);
+ }
+
+ target_create_inferior (exec_file, inferior_args,
+ environ_vector (inferior_environ));
+}
+
+static void
+continue_command (proc_count_exp, from_tty)
+ char *proc_count_exp;
+ int from_tty;
+{
+ ERROR_NO_INFERIOR;
+
+ /* If have argument, set proceed count of breakpoint we stopped at. */
+
+ if (proc_count_exp != NULL)
+ {
+ bpstat bs = stop_bpstat;
+ int num = bpstat_num (&bs);
+ if (num == 0 && from_tty)
+ {
+ printf_filtered
+ ("Not stopped at any breakpoint; argument ignored.\n");
+ }
+ while (num != 0)
+ {
+ set_ignore_count (num,
+ parse_and_eval_address (proc_count_exp) - 1,
+ from_tty);
+ /* set_ignore_count prints a message ending with a period.
+ So print two spaces before "Continuing.". */
+ if (from_tty)
+ printf_filtered (" ");
+ num = bpstat_num (&bs);
+ }
+ }
+
+ if (from_tty)
+ printf_filtered ("Continuing.\n");
+
+ clear_proceed_status ();
+
+ proceed ((CORE_ADDR) -1, -1, 0);
+}
+
+/* Step until outside of current statement. */
+
+/* ARGSUSED */
+static void
+step_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions. */
+
+/* ARGSUSED */
+static void
+next_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction. */
+
+/* ARGSUSED */
+static void
+stepi_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (0, 1, count_string);
+}
+
+/* ARGSUSED */
+static void
+nexti_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (1, 1, count_string);
+}
+
+static void
+step_1 (skip_subroutines, single_inst, count_string)
+ int skip_subroutines;
+ int single_inst;
+ char *count_string;
+{
+ register int count = 1;
+ FRAME fr;
+ struct cleanup *cleanups = 0;
+
+ ERROR_NO_INFERIOR;
+ count = count_string ? parse_and_eval_address (count_string) : 1;
+
+ if (!single_inst || skip_subroutines) /* leave si command alone */
+ {
+ enable_longjmp_breakpoint();
+ cleanups = make_cleanup(disable_longjmp_breakpoint, 0);
+ }
+
+ for (; count > 0; count--)
+ {
+ clear_proceed_status ();
+
+ fr = get_current_frame ();
+ if (!fr) /* Avoid coredump here. Why tho? */
+ error ("No current frame");
+ step_frame_address = FRAME_FP (fr);
+
+ if (! single_inst)
+ {
+ find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+ if (step_range_end == 0)
+ {
+ char *name;
+ if (find_pc_partial_function (stop_pc, &name, &step_range_start,
+ &step_range_end) == 0)
+ error ("Cannot find bounds of current function");
+
+ target_terminal_ours ();
+ printf_filtered ("\
+Single stepping until exit from function %s, \n\
+which has no line number information.\n", name);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ /* Say we are stepping, but stop after one insn whatever it does. */
+ step_range_start = step_range_end = 1;
+ if (!skip_subroutines)
+ /* It is stepi.
+ Don't step over function calls, not even to functions lacking
+ line numbers. */
+ step_over_calls = 0;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = 1;
+
+ step_multi = (count > 1);
+ proceed ((CORE_ADDR) -1, -1, 1);
+ if (! stop_step)
+ break;
+
+ /* FIXME: On nexti, this may have already been done (when we hit the
+ step resume break, I think). Probably this should be moved to
+ wait_for_inferior (near the top). */
+#if defined (SHIFT_INST_REGS)
+ SHIFT_INST_REGS();
+#endif
+ }
+
+ if (!single_inst || skip_subroutines)
+ do_cleanups(cleanups);
+}
+
+/* Continue program at specified address. */
+
+static void
+jump_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register CORE_ADDR addr;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *fn;
+ struct symbol *sfn;
+
+ ERROR_NO_INFERIOR;
+
+ if (!arg)
+ error_no_arg ("starting address");
+
+ sals = decode_line_spec_1 (arg, 1);
+ if (sals.nelts != 1)
+ {
+ error ("Unreasonable jump request");
+ }
+
+ sal = sals.sals[0];
+ free ((PTR)sals.sals);
+
+ if (sal.symtab == 0 && sal.pc == 0)
+ error ("No source file has been specified.");
+
+ resolve_sal_pc (&sal); /* May error out */
+
+ /* See if we are trying to jump to another function. */
+ fn = get_frame_function (get_current_frame ());
+ sfn = find_pc_function (sal.pc);
+ if (fn != NULL && sfn != fn)
+ {
+ if (!query ("Line %d is not in `%s'. Jump anyway? ", sal.line,
+ SYMBOL_SOURCE_NAME (fn)))
+ {
+ error ("Not confirmed.");
+ /* NOTREACHED */
+ }
+ }
+
+ addr = sal.pc;
+
+ if (from_tty)
+ printf_filtered ("Continuing at %s.\n",
+ local_hex_string((unsigned long) addr));
+
+ clear_proceed_status ();
+ proceed (addr, 0, 0);
+}
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int signum;
+
+ dont_repeat (); /* Too dangerous. */
+ ERROR_NO_INFERIOR;
+
+ if (!signum_exp)
+ error_no_arg ("signal number");
+
+ /* It would be even slicker to make signal names be valid expressions,
+ (the type could be "enum $signal" or some such), then the user could
+ assign them to convenience variables. */
+ signum = strtosigno (signum_exp);
+
+ if (signum == 0)
+ /* Not found as a name, try it as an expression. */
+ signum = parse_and_eval_address (signum_exp);
+
+ if (from_tty)
+ {
+ char *signame = strsigno (signum);
+ printf_filtered ("Continuing with signal ");
+ if (signame == NULL || signum == 0)
+ printf_filtered ("%d.\n", signum);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d).\n", signame, signum);
+ }
+
+ clear_proceed_status ();
+ proceed (stop_pc, signum, 0);
+}
+
+/* Call breakpoint_auto_delete on the current contents of the bpstat
+ pointed to by arg (which is really a bpstat *). */
+void
+breakpoint_auto_delete_contents (arg)
+ PTR arg;
+{
+ breakpoint_auto_delete (*(bpstat *)arg);
+}
+
+/* Execute a "stack dummy", a piece of code stored in the stack
+ by the debugger to be executed in the inferior.
+
+ To call: first, do PUSH_DUMMY_FRAME.
+ Then push the contents of the dummy. It should end with a breakpoint insn.
+ Then call here, passing address at which to start the dummy.
+
+ The contents of all registers are saved before the dummy frame is popped
+ and copied into the buffer BUFFER.
+
+ The dummy's frame is automatically popped whenever that break is hit.
+ If that is the first time the program stops, run_stack_dummy
+ returns to its caller with that frame already gone and returns 0.
+ Otherwise, run_stack-dummy returns 1 (the frame will eventually be popped
+ when we do hit that breakpoint). */
+
+/* DEBUG HOOK: 4 => return instead of letting the stack dummy run. */
+
+static int stack_dummy_testing = 0;
+
+int
+run_stack_dummy (addr, buffer)
+ CORE_ADDR addr;
+ char buffer[REGISTER_BYTES];
+{
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
+
+ /* Now proceed, having reached the desired place. */
+ clear_proceed_status ();
+ if (stack_dummy_testing & 4)
+ {
+ POP_FRAME;
+ return(0);
+ }
+#ifdef CALL_DUMMY_BREAKPOINT_OFFSET
+ {
+ struct breakpoint *bpt;
+ struct symtab_and_line sal;
+
+#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT
+ sal.pc = addr - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET;
+#else
+ sal.pc = entry_point_address ();
+#endif
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ /* Set up a FRAME for the dummy frame so we can pass it to
+ set_momentary_breakpoint. We need to give the breakpoint a
+ frame in case there is only one copy of the dummy (e.g.
+ CALL_DUMMY_LOCATION == AFTER_TEXT_END). */
+ flush_cached_frames ();
+ set_current_frame (create_new_frame (read_fp (), sal.pc));
+
+ /* If defined, CALL_DUMMY_BREAKPOINT_OFFSET is where we need to put
+ a breakpoint instruction. If not, the call dummy already has the
+ breakpoint instruction in it.
+
+ addr is the address of the call dummy plus the CALL_DUMMY_START_OFFSET,
+ so we need to subtract the CALL_DUMMY_START_OFFSET. */
+ bpt = set_momentary_breakpoint (sal,
+ get_current_frame (),
+ bp_call_dummy);
+ bpt->disposition = delete;
+
+ /* If all error()s out of proceed ended up calling normal_stop (and
+ perhaps they should; it already does in the special case of error
+ out of resume()), then we wouldn't need this. */
+ make_cleanup (breakpoint_auto_delete_contents, &stop_bpstat);
+ }
+#endif /* CALL_DUMMY_BREAKPOINT_OFFSET. */
+
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+ proceed (addr, 0, 0);
+
+ discard_cleanups (old_cleanups);
+
+ if (!stop_stack_dummy)
+ return 1;
+
+ /* On return, the stack dummy has been popped already. */
+
+ memcpy (buffer, stop_registers, sizeof stop_registers);
+ return 0;
+}
+
+/* Proceed until we reach a different source line with pc greater than
+ our current one or exit the function. We skip calls in both cases.
+
+ Note that eventually this command should probably be changed so
+ that only source lines are printed out when we hit the breakpoint
+ we set. I'm going to postpone this until after a hopeful rewrite
+ of wait_for_inferior and the proceed status code. -- randy */
+
+/* ARGSUSED */
+static void
+until_next_command (from_tty)
+ int from_tty;
+{
+ FRAME frame;
+ CORE_ADDR pc;
+ struct symbol *func;
+ struct symtab_and_line sal;
+
+ clear_proceed_status ();
+
+ frame = get_current_frame ();
+
+ /* Step until either exited from this function or greater
+ than the current line (if in symbolic section) or pc (if
+ not). */
+
+ pc = read_pc ();
+ func = find_pc_function (pc);
+
+ if (!func)
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ if (msymbol == NULL)
+ error ("Execution is not within a known function.");
+
+ step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
+ step_range_end = pc;
+ }
+ else
+ {
+ sal = find_pc_line (pc, 0);
+
+ step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
+ step_range_end = sal.end;
+ }
+
+ step_over_calls = 1;
+ step_frame_address = FRAME_FP (frame);
+
+ step_multi = 0; /* Only one call to proceed */
+
+ proceed ((CORE_ADDR) -1, -1, 1);
+}
+
+static void
+until_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!target_has_execution)
+ error ("The program is not running.");
+ if (arg)
+ until_break_command (arg, from_tty);
+ else
+ until_next_command (from_tty);
+}
+
+/* "finish": Set a temporary breakpoint at the place
+ the selected frame will return to, then continue. */
+
+static void
+finish_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtab_and_line sal;
+ register FRAME frame;
+ struct frame_info *fi;
+ register struct symbol *function;
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+
+ if (arg)
+ error ("The \"finish\" command does not take any arguments.");
+ if (!target_has_execution)
+ error ("The program is not running.");
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+
+ frame = get_prev_frame (selected_frame);
+ if (frame == 0)
+ error ("\"finish\" not meaningful in the outermost frame.");
+
+ clear_proceed_status ();
+
+ fi = get_frame_info (frame);
+ sal = find_pc_line (fi->pc, 0);
+ sal.pc = fi->pc;
+
+ breakpoint = set_momentary_breakpoint (sal, frame, bp_finish);
+
+ old_chain = make_cleanup(delete_breakpoint, breakpoint);
+
+ /* Find the function we will return from. */
+
+ fi = get_frame_info (selected_frame);
+ function = find_pc_function (fi->pc);
+
+ /* Print info on the selected frame, including level number
+ but not source. */
+ if (from_tty)
+ {
+ printf_filtered ("Run till exit from ");
+ print_stack_frame (selected_frame, selected_frame_level, 0);
+ }
+
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+ proceed ((CORE_ADDR) -1, -1, 0);
+
+ /* Did we stop at our breakpoint? */
+ if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL
+ && function != 0)
+ {
+ struct type *value_type;
+ register value val;
+ CORE_ADDR funcaddr;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+ if (!value_type)
+ fatal ("internal: finish_command: function has no target type");
+
+ if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
+ return;
+
+ funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
+
+ val = value_being_returned (value_type, stop_registers,
+ using_struct_return (value_of_variable (function, NULL),
+ funcaddr,
+ value_type,
+ BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))));
+
+ printf_filtered ("Value returned is $%d = ", record_latest_value (val));
+ value_print (val, stdout, 0, Val_no_prettyprint);
+ printf_filtered ("\n");
+ }
+ do_cleanups(old_chain);
+}
+
+/* ARGSUSED */
+static void
+program_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ bpstat bs = stop_bpstat;
+ int num = bpstat_num (&bs);
+
+ if (!target_has_execution)
+ {
+ printf_filtered ("The program being debugged is not being run.\n");
+ return;
+ }
+
+ target_files_info ();
+ printf_filtered ("Program stopped at %s.\n",
+ local_hex_string((unsigned long) stop_pc));
+ if (stop_step)
+ printf_filtered ("It stopped after being stepped.\n");
+ else if (num != 0)
+ {
+ /* There may be several breakpoints in the same place, so this
+ isn't as strange as it seems. */
+ while (num != 0)
+ {
+ if (num < 0)
+ printf_filtered ("It stopped at a breakpoint that has since been deleted.\n");
+ else
+ printf_filtered ("It stopped at breakpoint %d.\n", num);
+ num = bpstat_num (&bs);
+ }
+ }
+ else if (stop_signal)
+ {
+#ifdef PRINT_RANDOM_SIGNAL
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ char *signame = strsigno (stop_signal);
+ printf_filtered ("It stopped with signal ");
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s.\n", safe_strsignal (stop_signal));
+#endif
+ }
+
+ if (!from_tty)
+ printf_filtered ("Type \"info stack\" or \"info registers\" for more information.\n");
+}
+
+static void
+environment_info (var, from_tty)
+ char *var;
+ int from_tty;
+{
+ if (var)
+ {
+ register char *val = get_in_environ (inferior_environ, var);
+ if (val)
+ {
+ puts_filtered (var);
+ puts_filtered (" = ");
+ puts_filtered (val);
+ puts_filtered ("\n");
+ }
+ else
+ {
+ puts_filtered ("Environment variable \"");
+ puts_filtered (var);
+ puts_filtered ("\" not defined.\n");
+ }
+ }
+ else
+ {
+ register char **vector = environ_vector (inferior_environ);
+ while (*vector)
+ {
+ puts_filtered (*vector++);
+ puts_filtered ("\n");
+ }
+ }
+}
+
+static void
+set_environment_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register char *p, *val, *var;
+ int nullset = 0;
+
+ if (arg == 0)
+ error_no_arg ("environment variable and value");
+
+ /* Find seperation between variable name and value */
+ p = (char *) strchr (arg, '=');
+ val = (char *) strchr (arg, ' ');
+
+ if (p != 0 && val != 0)
+ {
+ /* We have both a space and an equals. If the space is before the
+ equals, walk forward over the spaces til we see a nonspace
+ (possibly the equals). */
+ if (p > val)
+ while (*val == ' ')
+ val++;
+
+ /* Now if the = is after the char following the spaces,
+ take the char following the spaces. */
+ if (p > val)
+ p = val - 1;
+ }
+ else if (val != 0 && p == 0)
+ p = val;
+
+ if (p == arg)
+ error_no_arg ("environment variable to set");
+
+ if (p == 0 || p[1] == 0)
+ {
+ nullset = 1;
+ if (p == 0)
+ p = arg + strlen (arg); /* So that savestring below will work */
+ }
+ else
+ {
+ /* Not setting variable value to null */
+ val = p + 1;
+ while (*val == ' ' || *val == '\t')
+ val++;
+ }
+
+ while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--;
+
+ var = savestring (arg, p - arg);
+ if (nullset)
+ {
+ printf_filtered ("Setting environment variable \"%s\" to null value.\n", var);
+ set_in_environ (inferior_environ, var, "");
+ }
+ else
+ set_in_environ (inferior_environ, var, val);
+ free (var);
+}
+
+static void
+unset_environment_command (var, from_tty)
+ char *var;
+ int from_tty;
+{
+ if (var == 0)
+ {
+ /* If there is no argument, delete all environment variables.
+ Ask for confirmation if reading from the terminal. */
+ if (!from_tty || query ("Delete all environment variables? "))
+ {
+ free_environ (inferior_environ);
+ inferior_environ = make_environ ();
+ }
+ }
+ else
+ unset_in_environ (inferior_environ, var);
+}
+
+/* Handle the execution path (PATH variable) */
+
+static const char path_var_name[] = "PATH";
+
+/* ARGSUSED */
+static void
+path_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ puts_filtered ("Executable and object file path: ");
+ puts_filtered (get_in_environ (inferior_environ, path_var_name));
+ puts_filtered ("\n");
+}
+
+/* Add zero or more directories to the front of the execution path. */
+
+static void
+path_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ char *exec_path;
+
+ dont_repeat ();
+ exec_path = strsave (get_in_environ (inferior_environ, path_var_name));
+ mod_path (dirname, &exec_path);
+ set_in_environ (inferior_environ, path_var_name, exec_path);
+ free (exec_path);
+ if (from_tty)
+ path_info ((char *)NULL, from_tty);
+}
+
+/* This routine is getting awfully cluttered with #if's. It's probably
+ time to turn this into READ_PC and define it in the tm.h file.
+ Ditto for write_pc. */
+
+CORE_ADDR
+read_pc ()
+{
+#ifdef TARGET_READ_PC
+ return TARGET_READ_PC ();
+#else
+ return ADDR_BITS_REMOVE ((CORE_ADDR) read_register (PC_REGNUM));
+#endif
+}
+
+void
+write_pc (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_PC
+ TARGET_WRITE_PC (val);
+#else
+ write_register (PC_REGNUM, (long) val);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, (long) val + 4);
+#ifdef NNPC_REGNUM
+ write_register (NNPC_REGNUM, (long) val + 8);
+#endif
+#endif
+#endif
+}
+
+/* Cope with strage ways of getting to the stack and frame pointers */
+
+CORE_ADDR
+read_sp ()
+{
+#ifdef TARGET_READ_SP
+ return TARGET_READ_SP ();
+#else
+ return read_register (SP_REGNUM);
+#endif
+}
+
+void
+write_sp (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_SP
+ TARGET_WRITE_SP (val);
+#else
+ write_register (SP_REGNUM, val);
+#endif
+}
+
+
+CORE_ADDR
+read_fp ()
+{
+#ifdef TARGET_READ_FP
+ return TARGET_READ_FP ();
+#else
+ return read_register (FP_REGNUM);
+#endif
+}
+
+void
+write_fp (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_FP
+ TARGET_WRITE_FP (val);
+#else
+ write_register (FP_REGNUM, val);
+#endif
+}
+
+const char * const reg_names[] = REGISTER_NAMES;
+
+/* Print out the machine register regnum. If regnum is -1,
+ print all registers (fpregs == 1) or all non-float registers
+ (fpregs == 0).
+
+ For most machines, having all_registers_info() print the
+ register(s) one per line is good enough. If a different format
+ is required, (eg, for MIPS or Pyramid 90x, which both have
+ lots of regs), or there is an existing convention for showing
+ all the registers, define the macro DO_REGISTERS_INFO(regnum, fp)
+ to provide that format. */
+
+#if !defined (DO_REGISTERS_INFO)
+#define DO_REGISTERS_INFO(regnum, fp) do_registers_info(regnum, fp)
+static void
+do_registers_info (regnum, fpregs)
+ int regnum;
+ int fpregs;
+{
+ register int i;
+
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+
+ /* Decide between printing all regs, nonfloat regs, or specific reg. */
+ if (regnum == -1) {
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT && !fpregs)
+ continue;
+ } else {
+ if (i != regnum)
+ continue;
+ }
+
+ fputs_filtered (reg_names[i], stdout);
+ print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
+
+ /* Get the data in raw format, then convert also to virtual format. */
+ if (read_relative_register_raw_bytes (i, raw_buffer))
+ {
+ printf_filtered ("Invalid register contents\n");
+ continue;
+ }
+
+ REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
+
+ /* If virtual format is floating, print it that way, and in raw hex. */
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT
+ && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i)))
+ {
+ register int j;
+
+ val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0,
+ stdout, 0, 1, 0, Val_pretty_default);
+
+ printf_filtered ("\t(raw 0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (i); j++)
+ printf_filtered ("%02x", (unsigned char)raw_buffer[j]);
+ printf_filtered (")");
+ }
+
+/* FIXME! val_print probably can handle all of these cases now... */
+
+ /* Else if virtual format is too long for printf,
+ print in hex a byte at a time. */
+ else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long))
+ {
+ register int j;
+ printf_filtered ("0x");
+ for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++)
+ printf_filtered ("%02x", (unsigned char)virtual_buffer[j]);
+ }
+ /* Else print as integer in hex and in decimal. */
+ else
+ {
+ val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+ stdout, 'x', 1, 0, Val_pretty_default);
+ printf_filtered ("\t");
+ val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+ stdout, 0, 1, 0, Val_pretty_default);
+ }
+
+ /* The SPARC wants to print even-numbered float regs as doubles
+ in addition to printing them as floats. */
+#ifdef PRINT_REGISTER_HOOK
+ PRINT_REGISTER_HOOK (i);
+#endif
+
+ printf_filtered ("\n");
+ }
+}
+#endif /* no DO_REGISTERS_INFO. */
+
+static void
+registers_info (addr_exp, fpregs)
+ char *addr_exp;
+ int fpregs;
+{
+ int regnum;
+ register char *end;
+
+ if (!target_has_registers)
+ error ("The program has no registers now.");
+
+ if (!addr_exp)
+ {
+ DO_REGISTERS_INFO(-1, fpregs);
+ return;
+ }
+
+ do
+ {
+ if (addr_exp[0] == '$')
+ addr_exp++;
+ end = addr_exp;
+ while (*end != '\0' && *end != ' ' && *end != '\t')
+ ++end;
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (!strncmp (addr_exp, reg_names[regnum], end - addr_exp)
+ && strlen (reg_names[regnum]) == end - addr_exp)
+ goto found;
+ if (*addr_exp >= '0' && *addr_exp <= '9')
+ regnum = atoi (addr_exp); /* Take a number */
+ if (regnum >= NUM_REGS) /* Bad name, or bad number */
+ error ("%.*s: invalid register", end - addr_exp, addr_exp);
+
+found:
+ DO_REGISTERS_INFO(regnum, fpregs);
+
+ addr_exp = end;
+ while (*addr_exp == ' ' || *addr_exp == '\t')
+ ++addr_exp;
+ } while (*addr_exp != '\0');
+}
+
+static void
+all_registers_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ registers_info (addr_exp, 1);
+}
+
+static void
+nofp_registers_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ registers_info (addr_exp, 0);
+}
+
+/*
+ * TODO:
+ * Should save/restore the tty state since it might be that the
+ * program to be debugged was started on this tty and it wants
+ * the tty in some state other than what we want. If it's running
+ * on another terminal or without a terminal, then saving and
+ * restoring the tty state is a harmless no-op.
+ * This only needs to be done if we are attaching to a process.
+ */
+
+/*
+ attach_command --
+ takes a program started up outside of gdb and ``attaches'' to it.
+ This stops it cold in its tracks and allows us to start debugging it.
+ and wait for the trace-trap that results from attaching. */
+
+void
+attach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ dont_repeat (); /* Not for the faint of heart */
+
+ if (target_has_execution)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ target_kill ();
+ else
+ error ("Not killed.");
+ }
+
+ target_attach (args, from_tty);
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ /* Set up execution context to know that we should return from
+ wait_for_inferior as soon as the target reports a stop. */
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+
+ wait_for_inferior ();
+
+#ifdef SOLIB_ADD
+ /* Add shared library symbols from the newly attached process, if any. */
+ SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0);
+#endif
+
+ normal_stop ();
+}
+
+/*
+ * detach_command --
+ * takes a program previously attached to and detaches it.
+ * The program resumes execution and will no longer stop
+ * on signals, etc. We better not have left any breakpoints
+ * in the program or it'll die when it hits one. For this
+ * to work, it may be necessary for the process to have been
+ * previously attached. It *might* work if the program was
+ * started via the normal ptrace (PTRACE_TRACEME).
+ */
+
+static void
+detach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ dont_repeat (); /* Not for the faint of heart */
+ target_detach (args, from_tty);
+}
+
+/* ARGSUSED */
+static void
+float_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+#ifdef FLOAT_INFO
+ FLOAT_INFO;
+#else
+ printf_filtered ("No floating point info available for this processor.\n");
+#endif
+}
+
+/* ARGSUSED */
+static void
+unset_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf_filtered ("\"unset\" must be followed by the name of an unset subcommand.\n");
+ help_list (unsetlist, "unset ", -1, stdout);
+}
+
+void
+_initialize_infcmd ()
+{
+ struct cmd_list_element *c;
+
+ add_com ("tty", class_run, tty_command,
+ "Set terminal for future runs of program being debugged.");
+
+ add_show_from_set
+ (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args,
+
+"Set arguments to give program being debugged when it is started.\n\
+Follow this command with any number of args, to be passed to the program.",
+ &setlist),
+ &showlist);
+
+ c = add_cmd
+ ("environment", no_class, environment_info,
+ "The environment to give the program, or one variable's value.\n\
+With an argument VAR, prints the value of environment variable VAR to\n\
+give the program being debugged. With no arguments, prints the entire\n\
+environment to be given to the program.", &showlist);
+ c->completer = noop_completer;
+
+ add_prefix_cmd ("unset", no_class, unset_command,
+ "Complement to certain \"set\" commands",
+ &unsetlist, "unset ", 0, &cmdlist);
+
+ c = add_cmd ("environment", class_run, unset_environment_command,
+ "Cancel environment variable VAR for the program.\n\
+This does not affect the program until the next \"run\" command.",
+ &unsetlist);
+ c->completer = noop_completer;
+
+ c = add_cmd ("environment", class_run, set_environment_command,
+ "Set environment variable value to give the program.\n\
+Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
+VALUES of environment variables are uninterpreted strings.\n\
+This does not affect the program until the next \"run\" command.",
+ &setlist);
+ c->completer = noop_completer;
+
+ add_com ("path", class_files, path_command,
+ "Add directory DIR(s) to beginning of search path for object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable. It is a list of\n\
+directories, separated by colons. These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.");
+
+ c = add_cmd ("paths", no_class, path_info,
+ "Current search path for finding object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable. It is a list of\n\
+directories, separated by colons. These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.", &showlist);
+ c->completer = noop_completer;
+
+ add_com ("attach", class_run, attach_command,
+ "Attach to a process or file outside of GDB.\n\
+This command attaches to another target, of the same type as your last\n\
+`target' command (`info files' will show your target stack).\n\
+The command may take as argument a process id or a device file.\n\
+For a process id, you must have permission to send the process a signal,\n\
+and it must have the same effective uid as the debugger.\n\
+When using \"attach\", you should use the \"file\" command to specify\n\
+the program running in the process, and to load its symbol table.");
+
+ add_com ("detach", class_run, detach_command,
+ "Detach a process or file previously attached.\n\
+If a process, it is no longer traced, and it continues its execution. If you\n\
+were debugging a file, the file is closed and gdb no longer accesses it.");
+
+ add_com ("signal", class_run, signal_command,
+ "Continue program giving it signal number SIGNUMBER.");
+
+ add_com ("stepi", class_run, stepi_command,
+ "Step one instruction exactly.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("si", "stepi", class_alias, 0);
+
+ add_com ("nexti", class_run, nexti_command,
+ "Step one instruction, but proceed through subroutine calls.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("ni", "nexti", class_alias, 0);
+
+ add_com ("finish", class_run, finish_command,
+ "Execute until selected stack frame returns.\n\
+Upon return, the value returned is printed and put in the value history.");
+
+ add_com ("next", class_run, next_command,
+ "Step program, proceeding through subroutine calls.\n\
+Like the \"step\" command as long as subroutine calls do not happen;\n\
+when they do, the call is treated as one instruction.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("n", "next", class_run, 1);
+
+ add_com ("step", class_run, step_command,
+ "Step program until it reaches a different source line.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("s", "step", class_run, 1);
+
+ add_com ("until", class_run, until_command,
+ "Execute until the program reaches a source line greater than the current\n\
+or a specified line or address or function (same args as break command).\n\
+Execution will also stop upon exit from the current stack frame.");
+ add_com_alias ("u", "until", class_run, 1);
+
+ add_com ("jump", class_run, jump_command,
+ "Continue program being debugged at specified line or address.\n\
+Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
+for an address to start at.");
+
+ add_com ("continue", class_run, continue_command,
+ "Continue program being debugged, after signal or breakpoint.\n\
+If proceeding from breakpoint, a number N may be used as an argument,\n\
+which means to set the ignore count of that breakpoint to N - 1 (so that\n\
+the breakpoint won't break until the Nth time it is reached).");
+ add_com_alias ("c", "cont", class_run, 1);
+ add_com_alias ("fg", "cont", class_run, 1);
+
+ add_com ("run", class_run, run_command,
+ "Start debugged program. You may specify arguments to give it.\n\
+Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\
+Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\
+With no arguments, uses arguments last specified (with \"run\" or \"set args\").\n\
+To cancel previous arguments and run with no arguments,\n\
+use \"set args\" without arguments.");
+ add_com_alias ("r", "run", class_run, 1);
+
+ add_info ("registers", nofp_registers_info,
+ "List of integer registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+ add_info ("all-registers", all_registers_info,
+"List of all registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+ add_info ("program", program_info,
+ "Execution status of the program.");
+
+ add_info ("float", float_info,
+ "Print the status of the floating point unit\n");
+
+ inferior_args = savestring ("", 1); /* Initially no args */
+ inferior_environ = make_environ ();
+ init_environ (inferior_environ);
+}
diff --git a/gnu/usr.bin/gdb/gdb/inferior.h b/gnu/usr.bin/gdb/gdb/inferior.h
new file mode 100644
index 000000000000..0f5499a3c6ba
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inferior.h
@@ -0,0 +1,401 @@
+/* Variables that describe the inferior process running under GDB:
+ Where it is, why it stopped, and how to step it.
+ Copyright 1986, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (INFERIOR_H)
+#define INFERIOR_H 1
+
+/* For bpstat. */
+#include "breakpoint.h"
+
+/* For FRAME_ADDR. */
+#include "frame.h"
+
+/*
+ * Structure in which to save the status of the inferior. Save
+ * through "save_inferior_status", restore through
+ * "restore_inferior_status".
+ * This pair of routines should be called around any transfer of
+ * control to the inferior which you don't want showing up in your
+ * control variables.
+ */
+struct inferior_status {
+ int stop_signal;
+ CORE_ADDR stop_pc;
+ FRAME_ADDR stop_frame_address;
+ bpstat stop_bpstat;
+ int stop_step;
+ int stop_stack_dummy;
+ int stopped_by_random_signal;
+ int trap_expected;
+ CORE_ADDR step_range_start;
+ CORE_ADDR step_range_end;
+ FRAME_ADDR step_frame_address;
+ int step_over_calls;
+ CORE_ADDR step_resume_break_address;
+ int stop_after_trap;
+ int stop_soon_quietly;
+ FRAME_ADDR selected_frame_address;
+ int selected_level;
+ char stop_registers[REGISTER_BYTES];
+
+ /* These are here because if call_function_by_hand has written some
+ registers and then decides to call error(), we better not have changed
+ any registers. */
+ char registers[REGISTER_BYTES];
+
+ int breakpoint_proceeded;
+ int restore_stack_info;
+ int proceed_to_finish;
+};
+
+extern void
+save_inferior_status PARAMS ((struct inferior_status *, int));
+
+extern void
+restore_inferior_status PARAMS ((struct inferior_status *));
+
+/* File name for default use for standard in/out in the inferior. */
+
+extern char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now. */
+
+extern int inferior_pid;
+
+/* Character array containing an image of the inferior programs' registers. */
+
+extern char registers[];
+
+/* Array of validity bits (one per register). Nonzero at position XXX_REGNUM
+ means that `registers' contains a valid copy of inferior register XXX. */
+
+extern char register_valid[NUM_REGS];
+
+extern void
+clear_proceed_status PARAMS ((void));
+
+extern void
+proceed PARAMS ((CORE_ADDR, int, int));
+
+extern void
+kill_inferior PARAMS ((void));
+
+extern void
+generic_mourn_inferior PARAMS ((void));
+
+extern void
+terminal_ours PARAMS ((void));
+
+extern int run_stack_dummy PARAMS ((CORE_ADDR, char [REGISTER_BYTES]));
+
+extern CORE_ADDR
+read_pc PARAMS ((void));
+
+extern void
+write_pc PARAMS ((CORE_ADDR));
+
+extern CORE_ADDR
+read_sp PARAMS ((void));
+
+extern void
+write_sp PARAMS ((CORE_ADDR));
+
+extern CORE_ADDR
+read_fp PARAMS ((void));
+
+extern void
+write_fp PARAMS ((CORE_ADDR));
+
+extern void
+wait_for_inferior PARAMS ((void));
+
+extern void
+init_wait_for_inferior PARAMS ((void));
+
+extern void
+close_exec_file PARAMS ((void));
+
+extern void
+reopen_exec_file PARAMS ((void));
+
+/* The `resume' routine should only be called in special circumstances.
+ Normally, use `proceed', which handles a lot of bookkeeping. */
+extern void
+resume PARAMS ((int, int));
+
+/* From misc files */
+
+extern void
+store_inferior_registers PARAMS ((int));
+
+extern void
+fetch_inferior_registers PARAMS ((int));
+
+extern void
+solib_create_inferior_hook PARAMS ((void));
+
+extern void
+child_terminal_info PARAMS ((char *, int));
+
+extern void
+term_info PARAMS ((char *, int));
+
+extern void
+terminal_ours_for_output PARAMS ((void));
+
+extern void
+terminal_inferior PARAMS ((void));
+
+extern void
+terminal_init_inferior PARAMS ((void));
+
+/* From infptrace.c */
+
+extern int
+attach PARAMS ((int));
+
+void
+detach PARAMS ((int));
+
+extern void
+child_resume PARAMS ((int, int, int));
+
+#ifndef PTRACE_ARG3_TYPE
+#define PTRACE_ARG3_TYPE int /* Correct definition for most systems. */
+#endif
+
+extern int
+call_ptrace PARAMS ((int, int, PTRACE_ARG3_TYPE, int));
+
+/* From procfs.c */
+
+extern int
+proc_iterate_over_mappings PARAMS ((int (*) (int, CORE_ADDR)));
+
+/* From fork-child.c */
+
+extern void
+fork_inferior PARAMS ((char *, char *, char **,
+ void (*) (void),
+ void (*) (int)));
+
+/* From inflow.c */
+
+extern void
+new_tty_prefork PARAMS ((char *));
+
+extern int gdb_has_a_terminal PARAMS ((void));
+
+/* From infrun.c */
+
+extern void
+start_remote PARAMS ((void));
+
+extern void
+normal_stop PARAMS ((void));
+
+extern int
+signal_stop_state PARAMS ((int));
+
+extern int
+signal_print_state PARAMS ((int));
+
+extern int
+signal_pass_state PARAMS ((int));
+
+/* From infcmd.c */
+
+extern void
+tty_command PARAMS ((char *, int));
+
+extern void
+attach_command PARAMS ((char *, int));
+
+/* Last signal that the inferior received (why it stopped). */
+
+extern int stop_signal;
+
+/* Address at which inferior stopped. */
+
+extern CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+extern FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at. */
+
+extern bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+ current breakpoint. */
+
+extern int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command. */
+
+extern int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine. */
+
+extern int stop_stack_dummy;
+
+/* Nonzero if program stopped due to a random (unexpected) signal in
+ inferior process. */
+
+extern int stopped_by_random_signal;
+
+/* Range to single step within.
+ If this is nonzero, respond to a single-step signal
+ by continuing to step if the pc is in this range.
+
+ If step_range_start and step_range_end are both 1, it means to step for
+ a single instruction (FIXME: it might clean up wait_for_inferior in a
+ minor way if this were changed to the address of the instruction and
+ that address plus one. But maybe not.). */
+
+extern CORE_ADDR step_range_start; /* Inclusive */
+extern CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call,
+ and how to set the frame for the breakpoint used to step out. */
+
+extern FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+ -1 means step over calls to undebuggable functions. */
+
+extern int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+ so don't print frame next time inferior stops
+ if it stops due to stepping. */
+
+extern int step_multi;
+
+/* Nonzero means expecting a trap and caller will handle it themselves.
+ It is used after attach, due to attaching to a process;
+ when running in the shell before the child program has been exec'd;
+ and when running some kinds of remote stuff (FIXME?). */
+
+extern int stop_soon_quietly;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+ situation when stop_registers should be saved. */
+
+extern int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+ if-and-only-if proceed_to_finish is set.
+ Thus this contains the return value from the called function (assuming
+ values are returned in a register). */
+
+extern char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if the child process in inferior_pid was attached rather
+ than forked. */
+
+extern int attach_flag;
+
+/* Sigtramp is a routine that the kernel calls (which then calls the
+ signal handler). On most machines it is a library routine that
+ is linked into the executable.
+
+ This macro, given a program counter value and the name of the
+ function in which that PC resides (which can be null if the
+ name is not known), returns nonzero if the PC and name show
+ that we are in sigtramp.
+
+ On most machines just see if the name is sigtramp (and if we have
+ no name, assume we are not in sigtramp). */
+#if !defined (IN_SIGTRAMP)
+# if defined (SIGTRAMP_START)
+# define IN_SIGTRAMP(pc, name) \
+ ((pc) >= SIGTRAMP_START \
+ && (pc) < SIGTRAMP_END \
+ )
+# else
+# define IN_SIGTRAMP(pc, name) \
+ (name && STREQ ("_sigtramp", name))
+# endif
+#endif
+
+/* Possible values for CALL_DUMMY_LOCATION. */
+#define ON_STACK 1
+#define BEFORE_TEXT_END 2
+#define AFTER_TEXT_END 3
+#define AT_ENTRY_POINT 4
+
+#if !defined (CALL_DUMMY_LOCATION)
+#define CALL_DUMMY_LOCATION ON_STACK
+#endif /* No CALL_DUMMY_LOCATION. */
+
+/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK
+ below is for infrun.c, which may give the macro a pc without that
+ subtracted out. */
+#if !defined (PC_IN_CALL_DUMMY)
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+extern CORE_ADDR text_end;
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= text_end - CALL_DUMMY_LENGTH \
+ && (pc) <= text_end + DECR_PC_AFTER_BREAK)
+#endif /* Before text_end. */
+
+#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
+extern CORE_ADDR text_end;
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= text_end \
+ && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK)
+#endif /* After text_end. */
+
+#if CALL_DUMMY_LOCATION == ON_STACK
+/* Is the PC in a call dummy? SP and FRAME_ADDRESS are the bottom and
+ top of the stack frame which we are checking, where "bottom" and
+ "top" refer to some section of memory which contains the code for
+ the call dummy. Calls to this macro assume that the contents of
+ SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively,
+ are the things to pass.
+
+ This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't
+ have that meaning, but the 29k doesn't use ON_STACK. This could be
+ fixed by generalizing this scheme, perhaps by passing in a frame
+ and adding a few fields, at least on machines which need them for
+ PC_IN_CALL_DUMMY.
+
+ Something simpler, like checking for the stack segment, doesn't work,
+ since various programs (threads implementations, gcc nested function
+ stubs, etc) may either allocate stack frames in another segment, or
+ allocate other kinds of code on the stack. */
+
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((sp) INNER_THAN (pc) && (frame_address != 0) && (pc) INNER_THAN (frame_address))
+#endif /* On stack. */
+
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+extern CORE_ADDR
+entry_point_address PARAMS ((void));
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= entry_point_address () \
+ && (pc) <= (entry_point_address () + DECR_PC_AFTER_BREAK))
+#endif /* At entry point. */
+#endif /* No PC_IN_CALL_DUMMY. */
+
+#endif /* !defined (INFERIOR_H) */
diff --git a/gnu/usr.bin/gdb/gdb/inflow.c b/gnu/usr.bin/gdb/gdb/inflow.c
new file mode 100644
index 000000000000..be0b43ba672e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inflow.c
@@ -0,0 +1,662 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "command.h"
+#include "signals.h"
+#include "serial.h"
+#include "terminal.h"
+#include "target.h"
+
+#include <signal.h>
+#include <fcntl.h>
+
+#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) && !defined (__GO32__)
+#define HAVE_SGTTY
+#endif
+
+#if defined (HAVE_TERMIOS)
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_TERMIOS
+#define PROCESS_GROUP_TYPE pid_t
+#endif
+
+#ifdef HAVE_SGTTY
+#ifdef SHORT_PGRP
+/* This is only used for the ultra. Does it have pid_t? */
+#define PROCESS_GROUP_TYPE short
+#else
+#define PROCESS_GROUP_TYPE int
+#endif
+#endif /* sgtty */
+
+static void
+kill_command PARAMS ((char *, int));
+
+static void
+terminal_ours_1 PARAMS ((int));
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+int attach_flag;
+
+
+/* Record terminal status separately for debugger and inferior. */
+
+static serial_t stdin_serial;
+
+/* TTY state for the inferior. We save it whenever the inferior stops, and
+ restore it when it resumes. */
+static serial_ttystate inferior_ttystate;
+
+/* Our own tty state, which we restore every time we need to deal with the
+ terminal. We only set it once, when GDB first starts. The settings of
+ flags which readline saves and restores and unimportant. */
+static serial_ttystate our_ttystate;
+
+/* fcntl flags for us and the inferior. Saved and restored just like
+ {our,inferior}_ttystate. */
+static int tflags_inferior;
+static int tflags_ours;
+
+#ifdef PROCESS_GROUP_TYPE
+/* Process group for us and the inferior. Saved and restored just like
+ {our,inferior}_ttystate. */
+PROCESS_GROUP_TYPE our_process_group;
+PROCESS_GROUP_TYPE inferior_process_group;
+#endif
+
+/* While the inferior is running, we want SIGINT and SIGQUIT to go to the
+ inferior only. If we have job control, that takes care of it. If not,
+ we save our handlers in these two variables and set SIGINT and SIGQUIT
+ to SIG_IGN. */
+static void (*sigint_ours) ();
+static void (*sigquit_ours) ();
+
+/* The name of the tty (from the `tty' command) that we gave to the inferior
+ when it was last started. */
+
+static char *inferior_thisrun_terminal;
+
+/* Nonzero if our terminal settings are in effect. Zero if the
+ inferior's settings are in effect. Ignored if !gdb_has_a_terminal
+ (). */
+
+static int terminal_is_ours;
+
+enum {yes, no, have_not_checked} gdb_has_a_terminal_flag = have_not_checked;
+
+/* Does GDB have a terminal (on stdin)? */
+int
+gdb_has_a_terminal ()
+{
+ switch (gdb_has_a_terminal_flag)
+ {
+ case yes:
+ return 1;
+ case no:
+ return 0;
+ case have_not_checked:
+ /* Get all the current tty settings (including whether we have a tty at
+ all!). Can't do this in _initialize_inflow because SERIAL_FDOPEN
+ won't work until the serial_ops_list is initialized. */
+
+#ifdef F_GETFL
+ tflags_ours = fcntl (0, F_GETFL, 0);
+#endif
+
+ gdb_has_a_terminal_flag = no;
+ stdin_serial = SERIAL_FDOPEN (0);
+ if (stdin_serial != NULL)
+ {
+ our_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+
+ if (our_ttystate != NULL)
+ {
+ gdb_has_a_terminal_flag = yes;
+#ifdef HAVE_TERMIOS
+ our_process_group = tcgetpgrp (0);
+#endif
+#ifdef HAVE_SGTTY
+ ioctl (0, TIOCGPGRP, &our_process_group);
+#endif
+ }
+ }
+
+ return gdb_has_a_terminal_flag == yes;
+ }
+}
+
+/* Macro for printing errors from ioctl operations */
+
+#define OOPSY(what) \
+ if (result == -1) \
+ fprintf(stderr, "[%s failed in terminal_inferior: %s]\n", \
+ what, strerror (errno))
+
+static void terminal_ours_1 PARAMS ((int));
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+void
+terminal_init_inferior ()
+{
+ if (gdb_has_a_terminal ())
+ {
+ /* We could just as well copy our_ttystate (if we felt like adding
+ a new function SERIAL_COPY_TTY_STATE). */
+ if (inferior_ttystate)
+ free (inferior_ttystate);
+ inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+#ifdef PROCESS_GROUP_TYPE
+ inferior_process_group = inferior_pid;
+#endif
+
+ /* Make sure that next time we call terminal_inferior (which will be
+ before the program runs, as it needs to be), we install the new
+ process group. */
+ terminal_is_ours = 1;
+ }
+}
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+void
+terminal_inferior ()
+{
+ if (gdb_has_a_terminal () && terminal_is_ours
+ && inferior_thisrun_terminal == 0)
+ {
+ int result;
+
+#ifdef F_GETFL
+ /* Is there a reason this is being done twice? It happens both
+ places we use F_SETFL, so I'm inclined to think perhaps there
+ is some reason, however perverse. Perhaps not though... */
+ result = fcntl (0, F_SETFL, tflags_inferior);
+ result = fcntl (0, F_SETFL, tflags_inferior);
+ OOPSY ("fcntl F_SETFL");
+#endif
+
+ /* Because we were careful to not change in or out of raw mode in
+ terminal_ours, we will not change in our out of raw mode with
+ this call, so we don't flush any input. */
+ result = SERIAL_SET_TTY_STATE (stdin_serial, inferior_ttystate);
+ OOPSY ("setting tty state");
+
+ if (!job_control)
+ {
+ sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN);
+ sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN);
+ }
+
+ /* If attach_flag is set, we don't know whether we are sharing a
+ terminal with the inferior or not. (attaching a process
+ without a terminal is one case where we do not; attaching a
+ process which we ran from the same shell as GDB via `&' is
+ one case where we do, I think (but perhaps this is not
+ `sharing' in the sense that we need to save and restore tty
+ state)). I don't know if there is any way to tell whether we
+ are sharing a terminal. So what we do is to go through all
+ the saving and restoring of the tty state, but ignore errors
+ setting the process group, which will happen if we are not
+ sharing a terminal). */
+
+ if (job_control)
+ {
+#ifdef HAVE_TERMIOS
+ result = tcsetpgrp (0, inferior_process_group);
+ if (!attach_flag)
+ OOPSY ("tcsetpgrp");
+#endif
+
+#ifdef HAVE_SGTTY
+ result = ioctl (0, TIOCSPGRP, &inferior_process_group);
+ if (!attach_flag)
+ OOPSY ("TIOCSPGRP");
+#endif
+ }
+
+ }
+ terminal_is_ours = 0;
+}
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+void
+terminal_ours_for_output ()
+{
+ terminal_ours_1 (1);
+}
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+void
+terminal_ours ()
+{
+ terminal_ours_1 (0);
+}
+
+/* output_only is not used, and should not be used unless we introduce
+ separate terminal_is_ours and terminal_is_ours_for_output
+ flags. */
+
+static void
+terminal_ours_1 (output_only)
+ int output_only;
+{
+ /* Checking inferior_thisrun_terminal is necessary so that
+ if GDB is running in the background, it won't block trying
+ to do the ioctl()'s below. Checking gdb_has_a_terminal
+ avoids attempting all the ioctl's when running in batch. */
+ if (inferior_thisrun_terminal != 0 || gdb_has_a_terminal () == 0)
+ return;
+
+ if (!terminal_is_ours)
+ {
+ /* Ignore this signal since it will happen when we try to set the
+ pgrp. */
+ void (*osigttou) ();
+ int result;
+
+ terminal_is_ours = 1;
+
+#ifdef SIGTTOU
+ if (job_control)
+ osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN);
+#endif
+
+ if (inferior_ttystate)
+ free (inferior_ttystate);
+ inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+#ifdef HAVE_TERMIOS
+ inferior_process_group = tcgetpgrp (0);
+#endif
+#ifdef HAVE_SGTTY
+ ioctl (0, TIOCGPGRP, &inferior_process_group);
+#endif
+
+ /* Here we used to set ICANON in our ttystate, but I believe this
+ was an artifact from before when we used readline. Readline sets
+ the tty state when it needs to. */
+
+ /* Set tty state to our_ttystate. We don't change in our out of raw
+ mode, to avoid flushing input. We need to do the same thing
+ regardless of output_only, because we don't have separate
+ terminal_is_ours and terminal_is_ours_for_output flags. It's OK,
+ though, since readline will deal with raw mode when/if it needs to.
+ */
+ SERIAL_NOFLUSH_SET_TTY_STATE (stdin_serial, our_ttystate,
+ inferior_ttystate);
+
+ if (job_control)
+ {
+#ifdef HAVE_TERMIOS
+ result = tcsetpgrp (0, our_process_group);
+#if 0
+ /* This fails on Ultrix with EINVAL if you run the testsuite
+ in the background with nohup, and then log out. GDB never
+ used to check for an error here, so perhaps there are other
+ such situations as well. */
+ if (result == -1)
+ fprintf (stderr, "[tcsetpgrp failed in terminal_ours: %s]\n",
+ strerror (errno));
+#endif
+#endif /* termios */
+
+#ifdef HAVE_SGTTY
+ result = ioctl (0, TIOCSPGRP, &our_process_group);
+#endif
+ }
+
+#ifdef SIGTTOU
+ if (job_control)
+ signal (SIGTTOU, osigttou);
+#endif
+
+ if (!job_control)
+ {
+ signal (SIGINT, sigint_ours);
+ signal (SIGQUIT, sigquit_ours);
+ }
+
+#ifdef F_GETFL
+ tflags_inferior = fcntl (0, F_GETFL, 0);
+
+ /* Is there a reason this is being done twice? It happens both
+ places we use F_SETFL, so I'm inclined to think perhaps there
+ is some reason, however perverse. Perhaps not though... */
+ result = fcntl (0, F_SETFL, tflags_ours);
+ result = fcntl (0, F_SETFL, tflags_ours);
+#endif
+
+ result = result; /* lint */
+ }
+}
+
+/* ARGSUSED */
+void
+term_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ target_terminal_info (arg, from_tty);
+}
+
+/* ARGSUSED */
+void
+child_terminal_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!gdb_has_a_terminal ())
+ {
+ printf_filtered ("This GDB does not control a terminal.\n");
+ return;
+ }
+
+ printf_filtered ("Inferior's terminal status (currently saved by GDB):\n");
+
+ /* First the fcntl flags. */
+ {
+ int flags;
+
+ flags = tflags_inferior;
+
+ printf_filtered ("File descriptor flags = ");
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (flags & (O_ACCMODE))
+ {
+ case O_RDONLY: printf_filtered ("O_RDONLY"); break;
+ case O_WRONLY: printf_filtered ("O_WRONLY"); break;
+ case O_RDWR: printf_filtered ("O_RDWR"); break;
+ }
+ flags &= ~(O_ACCMODE);
+
+#ifdef O_NONBLOCK
+ if (flags & O_NONBLOCK)
+ printf_filtered (" | O_NONBLOCK");
+ flags &= ~O_NONBLOCK;
+#endif
+
+#if defined (O_NDELAY)
+ /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will
+ print it as O_NONBLOCK, which is good cause that is what POSIX
+ has, and the flag will already be cleared by the time we get here. */
+ if (flags & O_NDELAY)
+ printf_filtered (" | O_NDELAY");
+ flags &= ~O_NDELAY;
+#endif
+
+ if (flags & O_APPEND)
+ printf_filtered (" | O_APPEND");
+ flags &= ~O_APPEND;
+
+#if defined (O_BINARY)
+ if (flags & O_BINARY)
+ printf_filtered (" | O_BINARY");
+ flags &= ~O_BINARY;
+#endif
+
+ if (flags)
+ printf_filtered (" | 0x%x", flags);
+ printf_filtered ("\n");
+ }
+
+#ifdef PROCESS_GROUP_TYPE
+ printf_filtered ("Process group = %d\n", inferior_process_group);
+#endif
+
+ SERIAL_PRINT_TTY_STATE (stdin_serial, inferior_ttystate);
+}
+
+/* NEW_TTY_PREFORK is called before forking a new child process,
+ so we can record the state of ttys in the child to be formed.
+ TTYNAME is null if we are to share the terminal with gdb;
+ or points to a string containing the name of the desired tty.
+
+ NEW_TTY is called in new child processes under Unix, which will
+ become debugger target processes. This actually switches to
+ the terminal specified in the NEW_TTY_PREFORK call. */
+
+void
+new_tty_prefork (ttyname)
+ char *ttyname;
+{
+ /* Save the name for later, for determining whether we and the child
+ are sharing a tty. */
+ inferior_thisrun_terminal = ttyname;
+}
+
+void
+new_tty ()
+{
+ register int tty;
+
+ if (inferior_thisrun_terminal == 0)
+ return;
+#if !defined(__GO32__)
+#ifdef TIOCNOTTY
+ /* Disconnect the child process from our controlling terminal. On some
+ systems (SVR4 for example), this may cause a SIGTTOU, so temporarily
+ ignore SIGTTOU. */
+ tty = open("/dev/tty", O_RDWR);
+ if (tty > 0)
+ {
+ void (*osigttou) ();
+
+ osigttou = (void (*)()) signal(SIGTTOU, SIG_IGN);
+ ioctl(tty, TIOCNOTTY, 0);
+ close(tty);
+ signal(SIGTTOU, osigttou);
+ }
+#endif
+
+ /* Now open the specified new terminal. */
+
+#ifdef USE_O_NOCTTY
+ tty = open(inferior_thisrun_terminal, O_RDWR | O_NOCTTY);
+#else
+ tty = open(inferior_thisrun_terminal, O_RDWR);
+#endif
+ if (tty == -1)
+ {
+ print_sys_errmsg (inferior_thisrun_terminal, errno);
+ _exit(1);
+ }
+
+ /* Avoid use of dup2; doesn't exist on all systems. */
+ if (tty != 0)
+ { close (0); dup (tty); }
+ if (tty != 1)
+ { close (1); dup (tty); }
+ if (tty != 2)
+ { close (2); dup (tty); }
+ if (tty > 2)
+ close(tty);
+#endif /* !go32 */
+}
+
+/* Kill the inferior process. Make us have no inferior. */
+
+/* ARGSUSED */
+static void
+kill_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* Shouldn't this be target_has_execution? FIXME. */
+ if (inferior_pid == 0)
+ error ("The program is not being run.");
+ if (!query ("Kill the program being debugged? "))
+ error ("Not confirmed.");
+ target_kill ();
+
+ init_thread_list(); /* Destroy thread info */
+
+ /* Killing off the inferior can leave us with a core file. If so,
+ print the state we are left in. */
+ if (target_has_stack) {
+ printf_filtered ("In %s,\n", current_target->to_longname);
+ if (selected_frame == NULL)
+ fputs_filtered ("No selected stack frame.\n", stdout);
+ else
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ }
+}
+
+/* The inferior process has died. Long live the inferior! */
+
+void
+generic_mourn_inferior ()
+{
+ inferior_pid = 0;
+ attach_flag = 0;
+ breakpoint_init_inferior ();
+ registers_changed ();
+
+#ifdef CLEAR_DEFERRED_STORES
+ /* Delete any pending stores to the inferior... */
+ CLEAR_DEFERRED_STORES;
+#endif
+
+ reopen_exec_file ();
+ reinit_frame_cache ();
+
+ /* It is confusing to the user for ignore counts to stick around
+ from previous runs of the inferior. So clear them. */
+ breakpoint_clear_ignore_counts ();
+}
+
+/* Call set_sigint_trap when you need to pass a signal on to an attached
+ process when handling SIGINT */
+
+/* ARGSUSED */
+static void
+pass_signal (signo)
+ int signo;
+{
+ kill (inferior_pid, SIGINT);
+}
+
+static void (*osig)();
+
+void
+set_sigint_trap()
+{
+ osig = (void (*) ()) signal (SIGINT, pass_signal);
+}
+
+void
+clear_sigint_trap()
+{
+ signal (SIGINT, osig);
+}
+
+
+int job_control;
+
+/* This is here because this is where we figure out whether we (probably)
+ have job control. Just using job_control only does part of it because
+ setpgid or setpgrp might not exist on a system without job control.
+ It might be considered misplaced (on the other hand, process groups and
+ job control are closely related to ttys).
+
+ For a more clean implementation, in libiberty, put a setpgid which merely
+ calls setpgrp and a setpgrp which does nothing (any system with job control
+ will have one or the other). */
+int
+gdb_setpgid ()
+{
+ int retval = 0;
+ if (job_control)
+ {
+#if defined (NEED_POSIX_SETPGID) || defined (HAVE_TERMIOS)
+ /* Do all systems with termios have setpgid? I hope so. */
+ /* setpgid (0, 0) is supposed to work and mean the same thing as
+ this, but on Ultrix 4.2A it fails with EPERM (and
+ setpgid (getpid (), getpid ()) succeeds). */
+ retval = setpgid (getpid (), getpid ());
+#else
+#if defined (TIOCGPGRP)
+#if defined(USG) && !defined(SETPGRP_ARGS)
+ retval = setpgrp ();
+#else
+ retval = setpgrp (getpid (), getpid ());
+#endif /* USG */
+#endif /* TIOCGPGRP. */
+#endif /* NEED_POSIX_SETPGID */
+ }
+ return retval;
+}
+
+void
+_initialize_inflow ()
+{
+ add_info ("terminal", term_info,
+ "Print inferior's saved terminal status.");
+
+ add_com ("kill", class_run, kill_command,
+ "Kill execution of program being debugged.");
+
+ inferior_pid = 0;
+
+ terminal_is_ours = 1;
+
+ /* OK, figure out whether we have job control. If neither termios nor
+ sgtty (i.e. termio or go32), leave job_control 0. */
+
+#if defined (HAVE_TERMIOS)
+ /* Do all systems with termios have the POSIX way of identifying job
+ control? I hope so. */
+#ifdef _POSIX_JOB_CONTROL
+ job_control = 1;
+#else
+ job_control = sysconf (_SC_JOB_CONTROL);
+#endif
+#endif /* termios */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+ job_control = 1;
+#else
+ job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gnu/usr.bin/gdb/gdb/infptrace.c b/gnu/usr.bin/gdb/gdb/infptrace.c
new file mode 100644
index 000000000000..a152d673a5df
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infptrace.c
@@ -0,0 +1,436 @@
+/* Low level Unix child interface to ptrace, for GDB when running under Unix.
+ Copyright 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#ifndef NO_PTRACE_H
+#ifdef PTRACE_IN_WRONG_PLACE
+#include <ptrace.h>
+#else
+#include <sys/ptrace.h>
+#endif
+#endif /* NO_PTRACE_H */
+
+#if !defined (PT_KILL)
+#define PT_KILL 8
+#endif
+
+#if !defined (PT_STEP)
+#define PT_STEP 9
+#define PT_CONTINUE 7
+#define PT_READ_U 3
+#define PT_WRITE_U 6
+#define PT_READ_I 1
+#define PT_READ_D 2
+#define PT_WRITE_I 4
+#define PT_WRITE_D 5
+#endif /* No PT_STEP. */
+
+#ifndef PT_ATTACH
+#define PT_ATTACH PTRACE_ATTACH
+#endif
+#ifndef PT_DETACH
+#define PT_DETACH PTRACE_DETACH
+#endif
+
+#include "gdbcore.h"
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#if 0
+/* Don't think this is used anymore. On the sequent (not sure whether it's
+ dynix or ptx or both), it is included unconditionally by sys/user.h and
+ not protected against multiple inclusion. */
+#include <sys/stat.h>
+#endif
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+#include <sys/user.h> /* Probably need to poke the user structure */
+#if defined (KERNEL_U_ADDR_BSD)
+#include <a.out.h> /* For struct nlist */
+#endif /* KERNEL_U_ADDR_BSD. */
+#endif /* !FETCH_INFERIOR_REGISTERS */
+
+
+/* This function simply calls ptrace with the given arguments.
+ It exists so that all calls to ptrace are isolated in this
+ machine-dependent file. */
+int
+call_ptrace (request, pid, addr, data)
+ int request, pid;
+ PTRACE_ARG3_TYPE addr;
+ int data;
+{
+ return ptrace (request, pid, addr, data
+#if defined (FIVE_ARG_PTRACE)
+ /* Deal with HPUX 8.0 braindamage. We never use the
+ calls which require the fifth argument. */
+ , 0
+#endif
+ );
+}
+
+#if defined (DEBUG_PTRACE) || defined (FIVE_ARG_PTRACE)
+/* For the rest of the file, use an extra level of indirection */
+/* This lets us breakpoint usefully on call_ptrace. */
+#define ptrace call_ptrace
+#endif
+
+void
+kill_inferior ()
+{
+ if (inferior_pid == 0)
+ return;
+ /* ptrace PT_KILL only works if process is stopped!!! So stop it with
+ a real signal first, if we can. */
+ kill (inferior_pid, SIGKILL);
+ ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
+ wait ((int *)0);
+ target_mourn_inferior ();
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+child_resume (pid, step, signal)
+ int pid;
+ int step;
+ int signal;
+{
+ errno = 0;
+
+ if (pid == -1)
+ pid = inferior_pid;
+
+ /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
+ it was. (If GDB wanted it to start some other way, we have already
+ written a new PC value to the child.)
+
+ If this system does not support PT_STEP, a higher level function will
+ have called single_step() to transmute the step request into a
+ continue request (by setting breakpoints on all possible successor
+ instructions), so we don't have to worry about that here. */
+
+ if (step)
+ ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, signal);
+ else
+ ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, signal);
+
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+#ifdef ATTACH_DETACH
+/* Start debugging the process whose number is PID. */
+int
+attach (pid)
+ int pid;
+{
+ errno = 0;
+ ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0);
+ if (errno)
+ perror_with_name ("ptrace");
+ attach_flag = 1;
+ return pid;
+}
+
+/* Stop debugging the process whose number is PID
+ and continue it with signal number SIGNAL.
+ SIGNAL = 0 means just continue it. */
+
+void
+detach (signal)
+ int signal;
+{
+ errno = 0;
+ ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+
+/* Default the type of the ptrace transfer to int. */
+#ifndef PTRACE_XFER_TYPE
+#define PTRACE_XFER_TYPE int
+#endif
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+
+/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+#if defined (KERNEL_U_ADDR_BSD)
+/* Get kernel_u_addr using BSD-style nlist(). */
+CORE_ADDR kernel_u_addr;
+
+void
+_initialize_kernel_u_addr ()
+{
+ struct nlist names[2];
+
+ names[0].n_un.n_name = "_u";
+ names[1].n_un.n_name = NULL;
+ if (nlist ("/vmunix", names) == 0)
+ kernel_u_addr = names[0].n_value;
+ else
+ fatal ("Unable to get kernel u area address.");
+}
+#endif /* KERNEL_U_ADDR_BSD. */
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* U_REGS_OFFSET is the offset of the registers within the u area. */
+#if !defined (U_REGS_OFFSET)
+#define U_REGS_OFFSET \
+ ptrace (PT_READ_U, inferior_pid, \
+ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
+ - KERNEL_U_ADDR
+#endif
+
+/* Registers we shouldn't try to fetch. */
+#if !defined (CANNOT_FETCH_REGISTER)
+#define CANNOT_FETCH_REGISTER(regno) 0
+#endif
+
+/* Fetch one register. */
+
+static void
+fetch_register (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ char mess[128]; /* For messages */
+ register int i;
+
+ /* Offset of registers within the u area. */
+ unsigned int offset;
+
+ if (CANNOT_FETCH_REGISTER (regno))
+ {
+ memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */
+ supply_register (regno, buf);
+ return;
+ }
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid,
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
+ {
+ sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno);
+ perror_with_name (mess);
+ }
+ }
+ supply_register (regno, buf);
+}
+
+
+/* Fetch all registers, or just one, from the child process. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+ if (regno == -1)
+ for (regno = 0; regno < NUM_REGS; regno++)
+ fetch_register (regno);
+ else
+ fetch_register (regno);
+}
+
+/* Registers we shouldn't try to store. */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+ register int i;
+
+ unsigned int offset = U_REGS_OFFSET;
+
+ if (regno >= 0)
+ {
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i]);
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d(%d)", regno, i);
+ perror_with_name (buf);
+ }
+ regaddr += sizeof(PTRACE_XFER_TYPE);
+ }
+ }
+ else
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (CANNOT_STORE_REGISTER (regno))
+ continue;
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i]);
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d(%d)", regno, i);
+ perror_with_name (buf);
+ }
+ regaddr += sizeof(PTRACE_XFER_TYPE);
+ }
+ }
+ }
+}
+#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
+
+/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
+ in the NEW_SUN_PTRACE case.
+ It ought to be straightforward. But it appears that writing did
+ not write the data that I specified. I cannot understand where
+ it got the data that it actually did write. */
+
+/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR. Copy to inferior if
+ WRITE is nonzero.
+
+ Returns the length copied, which is either the LEN argument or zero.
+ This xfer function does not do partial moves, since child_ops
+ doesn't allow memory operations to cross below us in the target stack
+ anyway. */
+
+int
+child_xfer_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target; /* ignored */
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ / sizeof (PTRACE_XFER_TYPE);
+ /* Allocate buffer of that many longwords. */
+ register PTRACE_XFER_TYPE *buffer
+ = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+
+ if (write)
+ {
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) {
+ /* Need part of initial word -- fetch it. */
+ buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ 0);
+ }
+
+ if (count > 1) /* FIXME, avoid if even boundary */
+ {
+ buffer[count - 1]
+ = ptrace (PT_READ_I, inferior_pid,
+ ((PTRACE_ARG3_TYPE)
+ (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))),
+ 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ myaddr,
+ len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ buffer[i]);
+ if (errno)
+ {
+ /* Using the appropriate one (I or D) is necessary for
+ Gould NP1, at least. */
+ errno = 0;
+ ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ buffer[i]);
+ }
+ if (errno)
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ buffer[i] = ptrace (PT_READ_I, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr, 0);
+ if (errno)
+ return 0;
+ QUIT;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr,
+ (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ len);
+ }
+ return len;
+}
diff --git a/gnu/usr.bin/gdb/gdb/infrun.c b/gnu/usr.bin/gdb/gdb/infrun.c
new file mode 100644
index 000000000000..9266c31caf15
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infrun.c
@@ -0,0 +1,1848 @@
+/* Target-struct-independent code to start (run) and stop an inferior process.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "breakpoint.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+
+#include <signal.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+/* Prototypes for local functions */
+
+static void
+signals_info PARAMS ((char *, int));
+
+static void
+handle_command PARAMS ((char *, int));
+
+static void
+sig_print_info PARAMS ((int));
+
+static void
+sig_print_header PARAMS ((void));
+
+static void
+resume_cleanups PARAMS ((int));
+
+static int
+hook_stop_stub PARAMS ((char *));
+
+/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the
+ program. It needs to examine the jmp_buf argument and extract the PC
+ from it. The return value is non-zero on success, zero otherwise. */
+#ifndef GET_LONGJMP_TARGET
+#define GET_LONGJMP_TARGET(PC_ADDR) 0
+#endif
+
+
+/* Some machines have trampoline code that sits between function callers
+ and the actual functions themselves. If this machine doesn't have
+ such things, disable their processing. */
+#ifndef SKIP_TRAMPOLINE_CODE
+#define SKIP_TRAMPOLINE_CODE(pc) 0
+#endif
+
+/* For SVR4 shared libraries, each call goes through a small piece of
+ trampoline code in the ".init" section. IN_SOLIB_TRAMPOLINE evaluates
+ to nonzero if we are current stopped in one of these. */
+#ifndef IN_SOLIB_TRAMPOLINE
+#define IN_SOLIB_TRAMPOLINE(pc,name) 0
+#endif
+
+/* On some systems, the PC may be left pointing at an instruction that won't
+ actually be executed. This is usually indicated by a bit in the PSW. If
+ we find ourselves in such a state, then we step the target beyond the
+ nullified instruction before returning control to the user so as to avoid
+ confusion. */
+
+#ifndef INSTRUCTION_NULLIFIED
+#define INSTRUCTION_NULLIFIED 0
+#endif
+
+/* Tables of how to react to signals; the user sets them. */
+
+static unsigned char *signal_stop;
+static unsigned char *signal_print;
+static unsigned char *signal_program;
+
+#define SET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 1; \
+ } while (0)
+
+#define UNSET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 0; \
+ } while (0)
+
+
+/* Command list pointer for the "stop" placeholder. */
+
+static struct cmd_list_element *stop_command;
+
+/* Nonzero if breakpoints are now inserted in the inferior. */
+
+static int breakpoints_inserted;
+
+/* Function inferior was in as of last step command. */
+
+static struct symbol *step_start_function;
+
+/* Nonzero if we are expecting a trace trap and should proceed from it. */
+
+static int trap_expected;
+
+/* Nonzero if the next time we try to continue the inferior, it will
+ step one instruction and generate a spurious trace trap.
+ This is used to compensate for a bug in HP-UX. */
+
+static int trap_expected_after_continue;
+
+/* Nonzero means expecting a trace trap
+ and should stop the inferior and return silently when it happens. */
+
+int stop_after_trap;
+
+/* Nonzero means expecting a trap and caller will handle it themselves.
+ It is used after attach, due to attaching to a process;
+ when running in the shell before the child program has been exec'd;
+ and when running some kinds of remote stuff (FIXME?). */
+
+int stop_soon_quietly;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+ situation when stop_registers should be saved. */
+
+int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+ if-and-only-if proceed_to_finish is set.
+ Thus this contains the return value from the called function (assuming
+ values are returned in a register). */
+
+char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if program stopped due to error trying to insert breakpoints. */
+
+static int breakpoints_failed;
+
+/* Nonzero after stop if current stack frame should be printed. */
+
+static int stop_print_frame;
+
+#ifdef NO_SINGLE_STEP
+extern int one_stepped; /* From machine dependent code */
+extern void single_step (); /* Same. */
+#endif /* NO_SINGLE_STEP */
+
+
+/* Things to clean up if we QUIT out of resume (). */
+/* ARGSUSED */
+static void
+resume_cleanups (arg)
+ int arg;
+{
+ normal_stop ();
+}
+
+/* Resume the inferior, but allow a QUIT. This is useful if the user
+ wants to interrupt some lengthy single-stepping operation
+ (for child processes, the SIGINT goes to the inferior, and so
+ we get a SIGINT random_signal, but for remote debugging and perhaps
+ other targets, that's not true).
+
+ STEP nonzero if we should step (zero to continue instead).
+ SIG is the signal to give the inferior (zero for none). */
+void
+resume (step, sig)
+ int step;
+ int sig;
+{
+ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
+ QUIT;
+
+#ifdef CANNOT_STEP_BREAKPOINT
+ /* Most targets can step a breakpoint instruction, thus executing it
+ normally. But if this one cannot, just continue and we will hit
+ it anyway. */
+ if (step && breakpoints_inserted && breakpoint_here_p (read_pc ()))
+ step = 0;
+#endif
+
+#ifdef NO_SINGLE_STEP
+ if (step) {
+ single_step(sig); /* Do it the hard way, w/temp breakpoints */
+ step = 0; /* ...and don't ask hardware to do it. */
+ }
+#endif
+
+ /* Handle any optimized stores to the inferior NOW... */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ target_resume (-1, step, sig);
+ discard_cleanups (old_cleanups);
+}
+
+
+/* Clear out all variables saying what to do when inferior is continued.
+ First do this, then set the ones you want, then call `proceed'. */
+
+void
+clear_proceed_status ()
+{
+ trap_expected = 0;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ step_over_calls = -1;
+ stop_after_trap = 0;
+ stop_soon_quietly = 0;
+ proceed_to_finish = 0;
+ breakpoint_proceeded = 1; /* We're about to proceed... */
+
+ /* Discard any remaining commands or status from previous stop. */
+ bpstat_clear (&stop_bpstat);
+}
+
+/* Basic routine for continuing the program in various fashions.
+
+ ADDR is the address to resume at, or -1 for resume where stopped.
+ SIGGNAL is the signal to give it, or 0 for none,
+ or -1 for act according to how it stopped.
+ STEP is nonzero if should trap after one instruction.
+ -1 means return after that and print nothing.
+ You should probably set various step_... variables
+ before calling here, if you are stepping.
+
+ You should call clear_proceed_status before calling proceed. */
+
+void
+proceed (addr, siggnal, step)
+ CORE_ADDR addr;
+ int siggnal;
+ int step;
+{
+ int oneproc = 0;
+
+ if (step > 0)
+ step_start_function = find_pc_function (read_pc ());
+ if (step < 0)
+ stop_after_trap = 1;
+
+ if (addr == (CORE_ADDR)-1)
+ {
+ /* If there is a breakpoint at the address we will resume at,
+ step one instruction before inserting breakpoints
+ so that we do not stop right away. */
+
+ if (breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+ }
+ else
+ write_pc (addr);
+
+ if (trap_expected_after_continue)
+ {
+ /* If (step == 0), a trap will be automatically generated after
+ the first instruction is executed. Force step one
+ instruction to clear this condition. This should not occur
+ if step is nonzero, but it is harmless in that case. */
+ oneproc = 1;
+ trap_expected_after_continue = 0;
+ }
+
+ if (oneproc)
+ /* We will get a trace trap after one instruction.
+ Continue it automatically and insert breakpoints then. */
+ trap_expected = 1;
+ else
+ {
+ int temp = insert_breakpoints ();
+ if (temp)
+ {
+ print_sys_errmsg ("ptrace", temp);
+ error ("Cannot insert breakpoints.\n\
+The same program may be running in another process.");
+ }
+ breakpoints_inserted = 1;
+ }
+
+ if (siggnal >= 0)
+ stop_signal = siggnal;
+ /* If this signal should not be seen by program,
+ give it zero. Used for debugging signals. */
+ else if (stop_signal < NSIG && !signal_program[stop_signal])
+ stop_signal= 0;
+
+ /* Resume inferior. */
+ resume (oneproc || step || bpstat_should_step (), stop_signal);
+
+ /* Wait for it to stop (if not standalone)
+ and in any case decode why it stopped, and act accordingly. */
+
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Record the pc and sp of the program the last time it stopped.
+ These are just used internally by wait_for_inferior, but need
+ to be preserved over calls to it and cleared when the inferior
+ is started. */
+static CORE_ADDR prev_pc;
+static CORE_ADDR prev_sp;
+static CORE_ADDR prev_func_start;
+static char *prev_func_name;
+
+
+/* Start remote-debugging of a machine over a serial link. */
+
+void
+start_remote ()
+{
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+ trap_expected = 0;
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Initialize static vars when a new inferior begins. */
+
+void
+init_wait_for_inferior ()
+{
+ /* These are meaningless until the first time through wait_for_inferior. */
+ prev_pc = 0;
+ prev_sp = 0;
+ prev_func_start = 0;
+ prev_func_name = NULL;
+
+ trap_expected_after_continue = 0;
+ breakpoints_inserted = 0;
+ breakpoint_init_inferior ();
+ stop_signal = 0; /* Don't confuse first call to proceed(). */
+}
+
+static void
+delete_breakpoint_current_contents (arg)
+ PTR arg;
+{
+ struct breakpoint **breakpointp = (struct breakpoint **)arg;
+ if (*breakpointp != NULL)
+ delete_breakpoint (*breakpointp);
+}
+
+/* Wait for control to return from inferior to debugger.
+ If inferior gets a signal, we may decide to start it up again
+ instead of returning. That is why there is a loop in this function.
+ When this function actually returns it means the inferior
+ should be left stopped and GDB should read more commands. */
+
+void
+wait_for_inferior ()
+{
+ struct cleanup *old_cleanups;
+ WAITTYPE w;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_sp = 0;
+ CORE_ADDR stop_func_start;
+ char *stop_func_name;
+ CORE_ADDR prologue_pc = 0, tmp;
+ struct symtab_and_line sal;
+ int remove_breakpoints_on_following_step = 0;
+ int current_line;
+ int handling_longjmp = 0; /* FIXME */
+ struct breakpoint *step_resume_breakpoint = NULL;
+ int pid;
+
+ old_cleanups = make_cleanup (delete_breakpoint_current_contents,
+ &step_resume_breakpoint);
+ sal = find_pc_line(prev_pc, 0);
+ current_line = sal.line;
+
+ /* Are we stepping? */
+#define CURRENTLY_STEPPING() ((step_resume_breakpoint == NULL \
+ && !handling_longjmp \
+ && (step_range_end \
+ || trap_expected)) \
+ || bpstat_should_step ())
+
+ while (1)
+ {
+ /* Clean up saved state that will become invalid. */
+ flush_cached_frames ();
+ registers_changed ();
+
+ pid = target_wait (-1, &w);
+
+#ifdef SIGTRAP_STOP_AFTER_LOAD
+
+ /* Somebody called load(2), and it gave us a "trap signal after load".
+ Ignore it gracefully. */
+
+ SIGTRAP_STOP_AFTER_LOAD (w);
+#endif
+
+ /* See if the process still exists; clean up if it doesn't. */
+ if (WIFEXITED (w))
+ {
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ if (WEXITSTATUS (w))
+ printf_filtered ("\nProgram exited with code 0%o.\n",
+ (unsigned int)WEXITSTATUS (w));
+ else
+ if (!batch_mode())
+ printf_filtered ("\nProgram exited normally.\n");
+ fflush (stdout);
+ target_mourn_inferior ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ stop_print_frame = 0;
+ break;
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ char *signame;
+
+ stop_print_frame = 0;
+ stop_signal = WTERMSIG (w);
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ target_kill (); /* kill mourns as well */
+#ifdef PRINT_RANDOM_SIGNAL
+ printf_filtered ("\nProgram terminated: ");
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ printf_filtered ("\nProgram terminated with signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number in addition to the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+#endif
+ printf_filtered ("The program no longer exists.\n");
+ fflush (stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ break;
+ }
+
+ stop_signal = WSTOPSIG (w);
+
+ if (pid != inferior_pid)
+ {
+ int save_pid = inferior_pid;
+
+ inferior_pid = pid; /* Setup for target memory/regs */
+ registers_changed ();
+ stop_pc = read_pc ();
+ inferior_pid = save_pid;
+ registers_changed ();
+ }
+ else
+ stop_pc = read_pc ();
+
+ if (stop_signal == SIGTRAP
+ && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK))
+ if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid))
+ {
+ /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */
+ if (breakpoints_inserted)
+ {
+ remove_breakpoints ();
+ target_resume (pid, 1, 0); /* Single step */
+ /* FIXME: What if a signal arrives instead of the single-step
+ happening? */
+ target_wait (pid, NULL);
+ insert_breakpoints ();
+ }
+ target_resume (-1, 0, 0);
+ continue;
+ }
+ else
+ if (pid != inferior_pid)
+ goto switch_thread;
+
+ if (pid != inferior_pid)
+ {
+ int printed = 0;
+
+ if (!in_thread_list (pid))
+ {
+ fprintf (stderr, "[New %s]\n", target_pid_to_str (pid));
+ add_thread (pid);
+
+ target_resume (-1, 0, 0);
+ continue;
+ }
+ else
+ {
+ if (stop_signal >= NSIG || signal_print[stop_signal])
+ {
+ char *signame;
+
+ printed = 1;
+ target_terminal_ours_for_output ();
+ printf_filtered ("\nProgram received signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+
+ fflush (stdout);
+ }
+
+ if (stop_signal == SIGTRAP
+ || stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ {
+switch_thread:
+ inferior_pid = pid;
+ printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid));
+
+ flush_cached_frames ();
+ registers_changed ();
+ trap_expected = 0;
+ if (step_resume_breakpoint)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+ }
+ prev_pc = 0;
+ prev_sp = 0;
+ prev_func_name = NULL;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ handling_longjmp = 0;
+ another_trap = 0;
+ }
+ else
+ {
+ if (printed)
+ target_terminal_inferior ();
+
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = 0;
+
+ target_resume (-1, 0, stop_signal);
+ continue;
+ }
+ }
+ }
+
+same_pid:
+
+#ifdef NO_SINGLE_STEP
+ if (one_stepped)
+ single_step (0); /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+
+/* If PC is pointing at a nullified instruction, then step beyond it so that
+ the user won't be confused when GDB appears to be ready to execute it. */
+
+ if (INSTRUCTION_NULLIFIED)
+ {
+ resume (1, 0);
+ continue;
+ }
+
+ set_current_frame ( create_new_frame (read_fp (), stop_pc));
+
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ stop_sp = read_sp ();
+ stop_func_start = 0;
+ stop_func_name = 0;
+ /* Don't care about return value; stop_func_start and stop_func_name
+ will both be 0 if it doesn't work. */
+ find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start,
+ NULL);
+ stop_func_start += FUNCTION_START_OFFSET;
+ another_trap = 0;
+ bpstat_clear (&stop_bpstat);
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ random_signal = 0;
+ stopped_by_random_signal = 0;
+ breakpoints_failed = 0;
+
+ /* Look at the cause of the stop, and decide what to do.
+ The alternatives are:
+ 1) break; to really stop and return to the debugger,
+ 2) drop through to start up again
+ (set another_trap to 1 to single step once)
+ 3) set random_signal to 1, and the decision between 1 and 2
+ will be made according to the signal handling tables. */
+
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions.
+ Note that breakpoint insns may cause SIGTRAP or SIGILL
+ or SIGEMT, depending on the operating system version.
+ Here we detect when a SIGILL or SIGEMT is really a breakpoint
+ and change it to SIGTRAP. */
+
+ if (stop_signal == SIGTRAP
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+#ifdef SIGEMT
+ || stop_signal == SIGEMT
+#endif
+ ))
+ || stop_soon_quietly)
+ {
+ if (stop_signal == SIGTRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_soon_quietly)
+ break;
+
+ /* Don't even think about breakpoints
+ if just proceeded over a breakpoint.
+
+ However, if we are trying to proceed over a breakpoint
+ and end up in sigtramp, then step_resume_breakpoint
+ will be set and we should check whether we've hit the
+ step breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected
+ && step_resume_breakpoint == NULL)
+ bpstat_clear (&stop_bpstat);
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
+ stop_bpstat = bpstat_stop_status
+ (&stop_pc, stop_frame_address,
+#if DECR_PC_AFTER_BREAK
+ /* Notice the case of stepping through a jump
+ that lands just after a breakpoint.
+ Don't confuse that with hitting the breakpoint.
+ What we check for is that 1) stepping is going on
+ and 2) the pc before the last insn does not match
+ the address of the breakpoint before the current pc. */
+ (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && CURRENTLY_STEPPING ())
+#else /* DECR_PC_AFTER_BREAK zero */
+ 0
+#endif /* DECR_PC_AFTER_BREAK zero */
+ );
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ }
+
+ if (stop_signal == SIGTRAP)
+ random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ || trap_expected
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+ || (step_range_end && step_resume_breakpoint == NULL));
+ else
+ {
+ random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ /* End of a stack dummy. Some systems (e.g. Sony
+ news) give another signal besides SIGTRAP,
+ so check here as well as above. */
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+ );
+ if (!random_signal)
+ stop_signal = SIGTRAP;
+ }
+ }
+ else
+ random_signal = 1;
+
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+
+ if (random_signal)
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
+
+ stopped_by_random_signal = 1;
+
+ if (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ char *signame;
+ printed = 1;
+ target_terminal_ours_for_output ();
+#ifdef PRINT_RANDOM_SIGNAL
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ printf_filtered ("\nProgram received signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+#endif /* PRINT_RANDOM_SIGNAL */
+ fflush (stdout);
+ }
+ if (stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ target_terminal_inferior ();
+
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = 0;
+
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ goto check_sigtramp2;
+ }
+
+ /* Handle cases caused by hitting a breakpoint. */
+ {
+ CORE_ADDR jmp_buf_pc;
+ struct bpstat_what what;
+
+ what = bpstat_what (stop_bpstat);
+
+ if (what.call_dummy)
+ {
+ stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 1;
+#endif
+ }
+
+ switch (what.main_action)
+ {
+ case BPSTAT_WHAT_SET_LONGJMP_RESUME:
+ /* If we hit the breakpoint at longjmp, disable it for the
+ duration of this command. Then, install a temporary
+ breakpoint at the target of the jmp_buf. */
+ disable_longjmp_breakpoint();
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going;
+
+ /* Need to blow away step-resume breakpoint, as it
+ interferes with us */
+ if (step_resume_breakpoint != NULL)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+ what.step_resume = 0;
+ }
+
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls > 0)
+ set_longjmp_resume_breakpoint(jmp_buf_pc,
+ get_current_frame());
+ else
+#endif /* 0 */
+ set_longjmp_resume_breakpoint(jmp_buf_pc, NULL);
+ handling_longjmp = 1; /* FIXME */
+ goto keep_going;
+
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls
+ && (stop_frame_address
+ INNER_THAN step_frame_address))
+ {
+ another_trap = 1;
+ goto keep_going;
+ }
+#endif /* 0 */
+ disable_longjmp_breakpoint();
+ handling_longjmp = 0; /* FIXME */
+ if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME)
+ break;
+ /* else fallthrough */
+
+ case BPSTAT_WHAT_SINGLE:
+ if (breakpoints_inserted)
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ /* Still need to check other stuff, at least the case
+ where we are stepping and step out of the right range. */
+ break;
+
+ case BPSTAT_WHAT_STOP_NOISY:
+ stop_print_frame = 1;
+ /* We are about to nuke the step_resume_breakpoint via the
+ cleanup chain, so no need to worry about it here. */
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_STOP_SILENT:
+ stop_print_frame = 0;
+ /* We are about to nuke the step_resume_breakpoint via the
+ cleanup chain, so no need to worry about it here. */
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_KEEP_CHECKING:
+ break;
+ }
+
+ if (what.step_resume)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+
+ /* If were waiting for a trap, hitting the step_resume_break
+ doesn't count as getting it. */
+ if (trap_expected)
+ another_trap = 1;
+ }
+ }
+
+ /* We come here if we hit a breakpoint but should not
+ stop for it. Possibly we also were stepping
+ and should stop for that. So fall through and
+ test for stepping. But, if not stepping,
+ do not stop. */
+
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ /* This is the old way of detecting the end of the stack dummy.
+ An architecture which defines CALL_DUMMY_BREAKPOINT_OFFSET gets
+ handled above. As soon as we can test it on all of them, all
+ architectures should define it. */
+
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently, unless the user was doing an si/ni, in which
+ case she'd better know what she's doing. */
+
+ if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+ && !step_range_end)
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 1;
+#endif
+ break;
+ }
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+
+ if (step_resume_breakpoint)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ /* I suspect this could/should be keep_going, because if the
+ check_sigtramp2 check succeeds, then it will put in another
+ step_resume_breakpoint, and we aren't (yet) prepared to nest
+ them. */
+ goto check_sigtramp2;
+
+ if (step_range_end == 0)
+ /* Likewise if we aren't even stepping. */
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ goto check_sigtramp2;
+
+ /* If stepping through a line, keep going if still within it. */
+ if (stop_pc >= step_range_start
+ && stop_pc < step_range_end
+ /* The step range might include the start of the
+ function, so if we are at the start of the
+ step range and either the stack or frame pointers
+ just changed, we've stepped outside */
+ && !(stop_pc == step_range_start
+ && stop_frame_address
+ && (stop_sp INNER_THAN prev_sp
+ || stop_frame_address != step_frame_address)))
+ {
+ /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
+ So definately need to check for sigtramp here. */
+ goto check_sigtramp2;
+ }
+
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+
+ /* Did we just take a signal? */
+ if (IN_SIGTRAMP (stop_pc, stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name))
+ {
+ /* This code is needed at least in the following case:
+ The user types "next" and then a signal arrives (before
+ the "next" is done). */
+ /* We've just taken a signal; go until we are back to
+ the point where we took it and one more. */
+ {
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = prev_pc;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+
+ /* If this is stepi or nexti, make sure that the stepping range
+ gets us past that instruction. */
+ if (step_range_end == 1)
+ /* FIXME: Does this run afoul of the code below which, if
+ we step into the middle of a line, resets the stepping
+ range? */
+ step_range_end = (step_range_start = prev_pc) + 1;
+
+ remove_breakpoints_on_following_step = 1;
+ goto keep_going;
+ }
+
+ if (stop_func_start)
+ {
+ /* Do this after the IN_SIGTRAMP check; it might give
+ an error. */
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
+ if ((/* Might be a non-recursive call. If the symbols are missing
+ enough that stop_func_start == prev_func_start even though
+ they are really two functions, we will treat some calls as
+ jumps. */
+ stop_func_start != prev_func_start
+
+ /* Might be a recursive call if either we have a prologue
+ or the call instruction itself saves the PC on the stack. */
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp)
+ && (/* PC is completely out of bounds of any known objfiles. Treat
+ like a subroutine call. */
+ !stop_func_start
+
+ /* If we do a call, we will be at the start of a function. */
+ || stop_pc == stop_func_start
+
+#if 0
+ /* Not conservative enough for 4.11. FIXME: enable this
+ after 4.11. */
+ /* Except on the Alpha with -O (and perhaps other machines
+ with similar calling conventions), in which we might
+ call the address after the load of gp. Since prologues
+ don't contain calls, we can't return to within one, and
+ we don't jump back into them, so this check is OK. */
+ || stop_pc < prologue_pc
+#endif
+
+ /* If we end up in certain places, it means we did a subroutine
+ call. I'm not completely sure this is necessary now that we
+ have the above checks with stop_func_start (and now that
+ find_pc_partial_function is pickier). */
+ || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name)
+
+ /* If none of the above apply, it is a jump within a function,
+ or a return from a subroutine. The other case is longjmp,
+ which can no longer happen here as long as the
+ handling_longjmp stuff is working. */
+ ))
+ {
+ /* It's a subroutine call. */
+
+ if (step_over_calls == 0)
+ {
+ /* I presume that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly language level
+ ("stepi"). Just stop. */
+ stop_step = 1;
+ break;
+ }
+
+ if (step_over_calls > 0)
+ /* We're doing a "next". */
+ goto step_over_function;
+
+ /* If we are in a function call trampoline (a stub between
+ the calling routine and the real function), locate the real
+ function. That's what tells us (a) whether we want to step
+ into it at all, and (b) what prologue we want to run to
+ the end of, if we do step into it. */
+ tmp = SKIP_TRAMPOLINE_CODE (stop_pc);
+ if (tmp != 0)
+ stop_func_start = tmp;
+
+ /* If we have line number information for the function we
+ are thinking of stepping into, step into it.
+
+ If there are several symtabs at that PC (e.g. with include
+ files), just want to know whether *any* of them have line
+ numbers. find_pc_line handles this. */
+ {
+ struct symtab_and_line tmp_sal;
+
+ tmp_sal = find_pc_line (stop_func_start, 0);
+ if (tmp_sal.line != 0)
+ goto step_into_function;
+ }
+
+step_over_function:
+ /* A subroutine call has happened. */
+ {
+ /* Set a special breakpoint after the return */
+ struct symtab_and_line sr_sal;
+ sr_sal.pc =
+ ADDR_BITS_REMOVE
+ (SAVED_PC_AFTER_CALL (get_current_frame ()));
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+ goto keep_going;
+
+step_into_function:
+ /* Subroutine call with source code we should not step over.
+ Do step to the first line of code in it. */
+ SKIP_PROLOGUE (stop_func_start);
+ sal = find_pc_line (stop_func_start, 0);
+ /* Use the step_resume_break to step until
+ the end of the prologue, even if that involves jumps
+ (as it seems to on the vax under 4.2). */
+ /* If the prologue ends in the middle of a source line,
+ continue to the end of that source line.
+ Otherwise, just go to end of prologue. */
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* no, don't either. It skips any code that's
+ legitimately on the first line. */
+#else
+ if (sal.end && sal.pc != stop_func_start)
+ stop_func_start = sal.end;
+#endif
+
+ if (stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ break;
+ }
+ else
+ /* Put the step-breakpoint there and go until there. */
+ {
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = stop_func_start;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ /* Do not specify what the fp should be when we stop
+ since on some machines the prologue
+ is where the new fp value is established. */
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ goto keep_going;
+ }
+
+ /* We've wandered out of the step range (but haven't done a
+ subroutine call or return). (Is that true? I think we get
+ here if we did a return and maybe a longjmp). */
+
+ sal = find_pc_line(stop_pc, 0);
+
+ if (step_range_end == 1)
+ {
+ /* It is stepi or nexti. We always want to stop stepping after
+ one instruction. */
+ stop_step = 1;
+ break;
+ }
+
+ if (sal.line == 0)
+ {
+ /* We have no line number information. That means to stop
+ stepping (does this always happen right after one instruction,
+ when we do "s" in a function with no line numbers,
+ or can this happen as a result of a return or longjmp?). */
+ stop_step = 1;
+ break;
+ }
+
+ if (stop_pc == sal.pc && current_line != sal.line)
+ {
+ /* We are at the start of a different line. So stop. Note that
+ we don't stop if we step into the middle of a different line.
+ That is said to make things like for (;;) statements work
+ better. */
+ stop_step = 1;
+ break;
+ }
+
+ /* We aren't done stepping.
+
+ Optimize by setting the stepping range to the line.
+ (We might not be in the original line, but if we entered a
+ new line in mid-statement, we continue stepping. This makes
+ things like for(;;) statements work better.) */
+ step_range_start = sal.pc;
+ step_range_end = sal.end;
+ goto keep_going;
+
+ check_sigtramp2:
+ if (trap_expected
+ && IN_SIGTRAMP (stop_pc, stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name))
+ {
+ /* What has happened here is that we have just stepped the inferior
+ with a signal (because it is a signal which shouldn't make
+ us stop), thus stepping into sigtramp.
+
+ So we need to set a step_resume_break_address breakpoint
+ and continue until we hit it, and then step. FIXME: This should
+ be more enduring than a step_resume breakpoint; we should know
+ that we will later need to keep going rather than re-hitting
+ the breakpoint here (see testsuite/gdb.t06/signals.exp where
+ it says "exceedingly difficult"). */
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = prev_pc;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ remove_breakpoints_on_following_step = 1;
+ another_trap = 1;
+ }
+
+ keep_going:
+ /* Come to this label when you need to resume the inferior.
+ It's really much cleaner to do a goto than a maze of if-else
+ conditions. */
+
+ /* Save the pc before execution, to compare with pc after stop. */
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER
+ BREAK is defined, the
+ original pc would not have
+ been at the start of a
+ function. */
+
+ prev_func_name = stop_func_name;
+ prev_sp = stop_sp;
+
+ /* If we did not do break;, it means we should keep
+ running the inferior and not return to debugger. */
+
+ if (trap_expected && stop_signal != SIGTRAP)
+ {
+ /* We took a signal (which we are supposed to pass through to
+ the inferior, else we'd have done a break above) and we
+ haven't yet gotten our trap. Simply continue. */
+ resume (CURRENTLY_STEPPING (), stop_signal);
+ }
+ else
+ {
+ /* Either the trap was not expected, but we are continuing
+ anyway (the user asked that this signal be passed to the
+ child)
+ -- or --
+ The signal was SIGTRAP, e.g. it was our signal, but we
+ decided we should resume from it.
+
+ We're going to run this baby now!
+
+ Insert breakpoints now, unless we are trying
+ to one-proceed past a breakpoint. */
+ /* If we've just finished a special step resume and we don't
+ want to hit a breakpoint, pull em out. */
+ if (step_resume_breakpoint == NULL &&
+ remove_breakpoints_on_following_step)
+ {
+ remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted &&
+ (step_resume_breakpoint != NULL || !another_trap))
+ {
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ break;
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = another_trap;
+
+ if (stop_signal == SIGTRAP)
+ stop_signal = 0;
+
+#ifdef SHIFT_INST_REGS
+ /* I'm not sure when this following segment applies. I do know, now,
+ that we shouldn't rewrite the regs when we were stopped by a
+ random signal from the inferior process. */
+ /* FIXME: Shouldn't this be based on the valid bit of the SXIP?
+ (this is only used on the 88k). */
+
+ if (!bpstat_explains_signal (stop_bpstat)
+ && (stop_signal != SIGCLD)
+ && !stopped_by_random_signal)
+ SHIFT_INST_REGS();
+#endif /* SHIFT_INST_REGS */
+
+ resume (CURRENTLY_STEPPING (), stop_signal);
+ }
+ }
+
+ stop_stepping:
+ if (target_has_execution)
+ {
+ /* Assuming the inferior still exists, set these up for next
+ time, just like we did above if we didn't break out of the
+ loop. */
+ prev_pc = read_pc ();
+ prev_func_start = stop_func_start;
+ prev_func_name = stop_func_name;
+ prev_sp = stop_sp;
+ }
+ do_cleanups (old_cleanups);
+}
+
+/* Here to return control to GDB when the inferior stops for real.
+ Print appropriate messages, remove breakpoints, give terminal our modes.
+
+ STOP_PRINT_FRAME nonzero means print the executing frame
+ (pc, function, args, file, line number and line text).
+ BREAKPOINTS_FAILED nonzero means stop was due to error
+ attempting to insert breakpoints. */
+
+void
+normal_stop ()
+{
+ /* Make sure that the current_frame's pc is correct. This
+ is a correction for setting up the frame info before doing
+ DECR_PC_AFTER_BREAK */
+ if (target_has_execution && get_current_frame())
+ (get_current_frame ())->pc = read_pc ();
+
+ if (breakpoints_failed)
+ {
+ target_terminal_ours_for_output ();
+ print_sys_errmsg ("ptrace", breakpoints_failed);
+ printf_filtered ("Stopped; cannot insert breakpoints.\n\
+The same program may be running in another process.\n");
+ }
+
+ if (target_has_execution && breakpoints_inserted)
+ if (remove_breakpoints ())
+ {
+ target_terminal_ours_for_output ();
+ printf_filtered ("Cannot remove breakpoints because program is no longer writable.\n\
+It might be running in another process.\n\
+Further execution is probably impossible.\n");
+ }
+
+ breakpoints_inserted = 0;
+
+ /* Delete the breakpoint we stopped at, if it wants to be deleted.
+ Delete any breakpoint that is to be deleted at the next stop. */
+
+ breakpoint_auto_delete (stop_bpstat);
+
+ /* If an auto-display called a function and that got a signal,
+ delete that auto-display to avoid an infinite recursion. */
+
+ if (stopped_by_random_signal)
+ disable_current_display ();
+
+ if (step_multi && stop_step)
+ return;
+
+ target_terminal_ours ();
+
+ /* Look up the hook_stop and run it if it exists. */
+
+ if (stop_command->hook)
+ {
+ catch_errors (hook_stop_stub, (char *)stop_command->hook,
+ "Error while running hook_stop:\n", RETURN_MASK_ALL);
+ }
+
+ if (!target_has_stack)
+ return;
+
+ /* Select innermost stack frame except on return from a stack dummy routine,
+ or if the program has exited. Print it without a level number if
+ we have changed functions or hit a breakpoint. Print source line
+ if we have one. */
+ if (!stop_stack_dummy)
+ {
+ select_frame (get_current_frame (), 0);
+
+ if (stop_print_frame)
+ {
+ int source_only;
+
+ source_only = bpstat_print (stop_bpstat);
+ source_only = source_only ||
+ ( stop_step
+ && step_frame_address == stop_frame_address
+ && step_start_function == find_pc_function (stop_pc));
+
+ print_stack_frame (selected_frame, -1, source_only? -1: 1);
+
+ /* Display the auto-display expressions. */
+ do_displays ();
+ }
+ }
+
+ /* Save the function value return registers, if we care.
+ We might be about to restore their previous contents. */
+ if (proceed_to_finish)
+ read_register_bytes (0, stop_registers, REGISTER_BYTES);
+
+ if (stop_stack_dummy)
+ {
+ /* Pop the empty frame that contains the stack dummy.
+ POP_FRAME ends with a setting of the current frame, so we
+ can use that next. */
+ POP_FRAME;
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+static int
+hook_stop_stub (cmd)
+ char *cmd;
+{
+ execute_user_command ((struct cmd_list_element *)cmd, 0);
+ return (0);
+}
+
+int signal_stop_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_stop[signo] : 0);
+}
+
+int signal_print_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_print[signo] : 0);
+}
+
+int signal_pass_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_program[signo] : 0);
+}
+
+static void
+sig_print_header ()
+{
+ printf_filtered ("Signal\t\tStop\tPrint\tPass to program\tDescription\n");
+}
+
+static void
+sig_print_info (number)
+ int number;
+{
+ char *name;
+
+ if ((name = strsigno (number)) == NULL)
+ printf_filtered ("%d\t\t", number);
+ else
+ printf_filtered ("%s (%d)\t", name, number);
+ printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No");
+ printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No");
+ printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No");
+ printf_filtered ("%s\n", safe_strsignal (number));
+}
+
+/* Specify how various signals in the inferior should be handled. */
+
+static void
+handle_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ int digits, wordlen;
+ int sigfirst, signum, siglast;
+ int allsigs;
+ int nsigs;
+ unsigned char *sigs;
+ struct cleanup *old_chain;
+
+ if (args == NULL)
+ {
+ error_no_arg ("signal to handle");
+ }
+
+ /* Allocate and zero an array of flags for which signals to handle. */
+
+ nsigs = signo_max () + 1;
+ sigs = (unsigned char *) alloca (nsigs);
+ memset (sigs, 0, nsigs);
+
+ /* Break the command line up into args. */
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ {
+ nomem (0);
+ }
+ old_chain = make_cleanup (freeargv, (char *) argv);
+
+ /* Walk through the args, looking for signal numbers, signal names, and
+ actions. Signal numbers and signal names may be interspersed with
+ actions, with the actions being performed for all signals cumulatively
+ specified. Signal ranges can be specified as <LOW>-<HIGH>. */
+
+ while (*argv != NULL)
+ {
+ wordlen = strlen (*argv);
+ for (digits = 0; isdigit ((*argv)[digits]); digits++) {;}
+ allsigs = 0;
+ sigfirst = siglast = -1;
+
+ if (wordlen >= 1 && !strncmp (*argv, "all", wordlen))
+ {
+ /* Apply action to all signals except those used by the
+ debugger. Silently skip those. */
+ allsigs = 1;
+ sigfirst = 0;
+ siglast = nsigs - 1;
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_stop);
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_print);
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (digits > 0)
+ {
+ sigfirst = siglast = atoi (*argv);
+ if ((*argv)[digits] == '-')
+ {
+ siglast = atoi ((*argv) + digits + 1);
+ }
+ if (sigfirst > siglast)
+ {
+ /* Bet he didn't figure we'd think of this case... */
+ signum = sigfirst;
+ sigfirst = siglast;
+ siglast = signum;
+ }
+ if (sigfirst < 0 || sigfirst >= nsigs)
+ {
+ error ("Signal %d not in range 0-%d", sigfirst, nsigs - 1);
+ }
+ if (siglast < 0 || siglast >= nsigs)
+ {
+ error ("Signal %d not in range 0-%d", siglast, nsigs - 1);
+ }
+ }
+ else if ((signum = strtosigno (*argv)) != 0)
+ {
+ sigfirst = siglast = signum;
+ }
+ else
+ {
+ /* Not a number and not a recognized flag word => complain. */
+ error ("Unrecognized or ambiguous flag word: \"%s\".", *argv);
+ }
+
+ /* If any signal numbers or symbol names were found, set flags for
+ which signals to apply actions to. */
+
+ for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
+ {
+ switch (signum)
+ {
+ case SIGTRAP:
+ case SIGINT:
+ if (!allsigs && !sigs[signum])
+ {
+ if (query ("%s is used by the debugger.\nAre you sure you want to change it? ", strsigno (signum)))
+ {
+ sigs[signum] = 1;
+ }
+ else
+ {
+ printf ("Not confirmed, unchanged.\n");
+ fflush (stdout);
+ }
+ }
+ break;
+ default:
+ sigs[signum] = 1;
+ break;
+ }
+ }
+
+ argv++;
+ }
+
+ target_notice_signals(inferior_pid);
+
+ if (from_tty)
+ {
+ /* Show the results. */
+ sig_print_header ();
+ for (signum = 0; signum < nsigs; signum++)
+ {
+ if (sigs[signum])
+ {
+ sig_print_info (signum);
+ }
+ }
+ }
+
+ do_cleanups (old_chain);
+}
+
+/* Print current contents of the tables set by the handle command. */
+
+static void
+signals_info (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int i;
+ sig_print_header ();
+
+ if (signum_exp)
+ {
+ /* First see if this is a symbol name. */
+ i = strtosigno (signum_exp);
+ if (i == 0)
+ {
+ /* Nope, maybe it's an address which evaluates to a signal
+ number. */
+ i = parse_and_eval_address (signum_exp);
+ if (i >= NSIG || i < 0)
+ error ("Signal number out of bounds.");
+ }
+ sig_print_info (i);
+ return;
+ }
+
+ printf_filtered ("\n");
+ for (i = 0; i < NSIG; i++)
+ {
+ QUIT;
+
+ sig_print_info (i);
+ }
+
+ printf_filtered ("\nUse the \"handle\" command to change these tables.\n");
+}
+
+/* Save all of the information associated with the inferior<==>gdb
+ connection. INF_STATUS is a pointer to a "struct inferior_status"
+ (defined in inferior.h). */
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+ struct inferior_status *inf_status;
+ int restore_stack_info;
+{
+ inf_status->stop_signal = stop_signal;
+ inf_status->stop_pc = stop_pc;
+ inf_status->stop_frame_address = stop_frame_address;
+ inf_status->stop_step = stop_step;
+ inf_status->stop_stack_dummy = stop_stack_dummy;
+ inf_status->stopped_by_random_signal = stopped_by_random_signal;
+ inf_status->trap_expected = trap_expected;
+ inf_status->step_range_start = step_range_start;
+ inf_status->step_range_end = step_range_end;
+ inf_status->step_frame_address = step_frame_address;
+ inf_status->step_over_calls = step_over_calls;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_soon_quietly = stop_soon_quietly;
+ /* Save original bpstat chain here; replace it with copy of chain.
+ If caller's caller is walking the chain, they'll be happier if we
+ hand them back the original chain when restore_i_s is called. */
+ inf_status->stop_bpstat = stop_bpstat;
+ stop_bpstat = bpstat_copy (stop_bpstat);
+ inf_status->breakpoint_proceeded = breakpoint_proceeded;
+ inf_status->restore_stack_info = restore_stack_info;
+ inf_status->proceed_to_finish = proceed_to_finish;
+
+ memcpy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+
+ read_register_bytes (0, inf_status->registers, REGISTER_BYTES);
+
+ record_selected_frame (&(inf_status->selected_frame_address),
+ &(inf_status->selected_level));
+ return;
+}
+
+struct restore_selected_frame_args {
+ FRAME_ADDR frame_address;
+ int level;
+};
+
+static int restore_selected_frame PARAMS ((char *));
+
+/* Restore the selected frame. args is really a struct
+ restore_selected_frame_args * (declared as char * for catch_errors)
+ telling us what frame to restore. Returns 1 for success, or 0 for
+ failure. An error message will have been printed on error. */
+static int
+restore_selected_frame (args)
+ char *args;
+{
+ struct restore_selected_frame_args *fr =
+ (struct restore_selected_frame_args *) args;
+ FRAME fid;
+ int level = fr->level;
+
+ fid = find_relative_frame (get_current_frame (), &level);
+
+ /* If inf_status->selected_frame_address is NULL, there was no
+ previously selected frame. */
+ if (fid == 0 ||
+ FRAME_FP (fid) != fr->frame_address ||
+ level != 0)
+ {
+ warning ("Unable to restore previously selected frame.\n");
+ return 0;
+ }
+ select_frame (fid, fr->level);
+ return(1);
+}
+
+void
+restore_inferior_status (inf_status)
+ struct inferior_status *inf_status;
+{
+ stop_signal = inf_status->stop_signal;
+ stop_pc = inf_status->stop_pc;
+ stop_frame_address = inf_status->stop_frame_address;
+ stop_step = inf_status->stop_step;
+ stop_stack_dummy = inf_status->stop_stack_dummy;
+ stopped_by_random_signal = inf_status->stopped_by_random_signal;
+ trap_expected = inf_status->trap_expected;
+ step_range_start = inf_status->step_range_start;
+ step_range_end = inf_status->step_range_end;
+ step_frame_address = inf_status->step_frame_address;
+ step_over_calls = inf_status->step_over_calls;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_soon_quietly = inf_status->stop_soon_quietly;
+ bpstat_clear (&stop_bpstat);
+ stop_bpstat = inf_status->stop_bpstat;
+ breakpoint_proceeded = inf_status->breakpoint_proceeded;
+ proceed_to_finish = inf_status->proceed_to_finish;
+
+ memcpy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ write_register_bytes (0, inf_status->registers, REGISTER_BYTES);
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+
+ /* FIXME: If we are being called after stopping in a function which
+ is called from gdb, we should not be trying to restore the
+ selected frame; it just prints a spurious error message (The
+ message is useful, however, in detecting bugs in gdb (like if gdb
+ clobbers the stack)). In fact, should we be restoring the
+ inferior status at all in that case? . */
+
+ if (target_has_stack && inf_status->restore_stack_info)
+ {
+ struct restore_selected_frame_args fr;
+ fr.level = inf_status->selected_level;
+ fr.frame_address = inf_status->selected_frame_address;
+ /* The point of catch_errors is that if the stack is clobbered,
+ walking the stack might encounter a garbage pointer and error()
+ trying to dereference it. */
+ if (catch_errors (restore_selected_frame, &fr,
+ "Unable to restore previously selected frame:\n",
+ RETURN_MASK_ERROR) == 0)
+ /* Error in restoring the selected frame. Select the innermost
+ frame. */
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+
+void
+_initialize_infrun ()
+{
+ register int i;
+ register int numsigs;
+
+ add_info ("signals", signals_info,
+ "What debugger does when program gets various signals.\n\
+Specify a signal number as argument to print info on that signal only.");
+ add_info_alias ("handle", "signals", 0);
+
+ add_com ("handle", class_run, handle_command,
+ "Specify how to handle a signal.\n\
+Args are signal numbers and actions to apply to those signals.\n\
+Signal numbers may be numeric (ex. 11) or symbolic (ex. SIGSEGV).\n\
+Numeric ranges may be specified with the form LOW-HIGH (ex. 14-21).\n\
+The special arg \"all\" is recognized to mean all signals except those\n\
+used by the debugger, typically SIGTRAP and SIGINT.\n\
+Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\
+\"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\
+Stop means reenter debugger if this signal happens (implies print).\n\
+Print means print a message if this signal happens.\n\
+Pass means let program see this signal; otherwise program doesn't know.\n\
+Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
+Pass and Stop may be combined.");
+
+ stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command,
+ "There is no `stop' command, but you can set a hook on `stop'.\n\
+This allows you to set a list of commands to be run each time execution\n\
+of the program stops.", &cmdlist);
+
+ numsigs = signo_max () + 1;
+ signal_stop = (unsigned char *)
+ xmalloc (sizeof (signal_stop[0]) * numsigs);
+ signal_print = (unsigned char *)
+ xmalloc (sizeof (signal_print[0]) * numsigs);
+ signal_program = (unsigned char *)
+ xmalloc (sizeof (signal_program[0]) * numsigs);
+ for (i = 0; i < numsigs; i++)
+ {
+ signal_stop[i] = 1;
+ signal_print[i] = 1;
+ signal_program[i] = 1;
+ }
+
+ /* Signals caused by debugger's own actions
+ should not be given to the program afterwards. */
+ signal_program[SIGTRAP] = 0;
+ signal_program[SIGINT] = 0;
+
+ /* Signals that are not errors should not normally enter the debugger. */
+#ifdef SIGALRM
+ signal_stop[SIGALRM] = 0;
+ signal_print[SIGALRM] = 0;
+#endif /* SIGALRM */
+#ifdef SIGVTALRM
+ signal_stop[SIGVTALRM] = 0;
+ signal_print[SIGVTALRM] = 0;
+#endif /* SIGVTALRM */
+#ifdef SIGPROF
+ signal_stop[SIGPROF] = 0;
+ signal_print[SIGPROF] = 0;
+#endif /* SIGPROF */
+#ifdef SIGCHLD
+ signal_stop[SIGCHLD] = 0;
+ signal_print[SIGCHLD] = 0;
+#endif /* SIGCHLD */
+#ifdef SIGCLD
+ signal_stop[SIGCLD] = 0;
+ signal_print[SIGCLD] = 0;
+#endif /* SIGCLD */
+#ifdef SIGIO
+ signal_stop[SIGIO] = 0;
+ signal_print[SIGIO] = 0;
+#endif /* SIGIO */
+#ifdef SIGURG
+ signal_stop[SIGURG] = 0;
+ signal_print[SIGURG] = 0;
+#endif /* SIGURG */
+}
diff --git a/gnu/usr.bin/gdb/gdb/inftarg.c b/gnu/usr.bin/gdb/gdb/inftarg.c
new file mode 100644
index 000000000000..f937be4ea6e1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inftarg.c
@@ -0,0 +1,310 @@
+/* Target-vector operations for controlling Unix child processes, for GDB.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "gdbcore.h"
+
+#include <signal.h>
+
+static void
+child_prepare_to_store PARAMS ((void));
+
+#ifndef CHILD_WAIT
+static int
+child_wait PARAMS ((int, int *));
+#endif /* CHILD_WAIT */
+
+static void
+child_open PARAMS ((char *, int));
+
+static void
+child_files_info PARAMS ((struct target_ops *));
+
+static void
+child_detach PARAMS ((char *, int));
+
+static void
+child_attach PARAMS ((char *, int));
+
+static void
+ptrace_me PARAMS ((void));
+
+static void
+ptrace_him PARAMS ((int));
+
+static void
+child_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+child_mourn_inferior PARAMS ((void));
+
+static int
+child_can_run PARAMS ((void));
+
+extern char **environ;
+
+/* Forward declaration */
+extern struct target_ops child_ops;
+
+#ifndef CHILD_WAIT
+
+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer STATUS. */
+
+static int
+child_wait (pid, status)
+ int pid;
+ int *status;
+{
+ int save_errno;
+
+ do {
+ if (attach_flag)
+ set_sigint_trap(); /* Causes SIGINT to be passed on to the
+ attached process. */
+ pid = wait (status);
+ save_errno = errno;
+
+ if (attach_flag)
+ clear_sigint_trap();
+
+ if (pid == -1)
+ {
+ if (save_errno == EINTR)
+ continue;
+ fprintf (stderr, "Child process unexpectedly missing: %s.\n",
+ safe_strerror (save_errno));
+ *status = 42; /* Claim it exited with signal 42 */
+ return -1;
+ }
+ } while (pid != inferior_pid); /* Some other child died or stopped */
+ return pid;
+}
+#endif /* CHILD_WAIT */
+
+/* Attach to process PID, then initialize for debugging it. */
+
+static void
+child_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+ int pid;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+#ifndef ATTACH_DETACH
+ error ("Can't attach to a process on this machine.");
+#else
+ pid = atoi (args);
+
+ if (pid == getpid()) /* Trying to masturbate? */
+ error ("I refuse to debug myself!");
+
+ if (from_tty)
+ {
+ exec_file = (char *) get_exec_file (0);
+
+ if (exec_file)
+ printf ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
+ else
+ printf ("Attaching to %s\n", target_pid_to_str (pid));
+
+ fflush (stdout);
+ }
+
+ attach (pid);
+ inferior_pid = pid;
+ push_target (&child_ops);
+#endif /* ATTACH_DETACH */
+}
+
+
+/* Take a program previously attached to and detaches it.
+ The program resumes execution and will no longer stop
+ on signals, etc. We'd better not have left any breakpoints
+ in the program or it'll die when it hits one. For this
+ to work, it may be necessary for the process to have been
+ previously attached. It *might* work if the program was
+ started via the normal ptrace (PTRACE_TRACEME). */
+
+static void
+child_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ int siggnal = 0;
+
+#ifdef ATTACH_DETACH
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf ("Detaching from program: %s %s\n", exec_file,
+ target_pid_to_str (inferior_pid));
+ fflush (stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&child_ops); /* Pop out of handling an inferior */
+#else
+ error ("This version of Unix does not support detaching a process.");
+#endif
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+child_prepare_to_store ()
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+child_files_info (ignore)
+ struct target_ops *ignore;
+{
+ printf ("\tUsing the running image of %s %s.\n",
+ attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
+}
+
+/* ARGSUSED */
+static void
+child_open (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+/* Stub function which causes the inferior that runs it, to be ptrace-able
+ by its parent process. */
+
+static void
+ptrace_me ()
+{
+ /* "Trace me, Dr. Memory!" */
+ call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0);
+}
+
+/* Stub function which causes the GDB that runs it, to start ptrace-ing
+ the child process. */
+
+static void
+ptrace_him (pid)
+ int pid;
+{
+ push_target (&child_ops);
+}
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+
+static void
+child_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, 0, 0);
+}
+
+static void
+child_mourn_inferior ()
+{
+ unpush_target (&child_ops);
+ generic_mourn_inferior ();
+}
+
+static int
+child_can_run ()
+{
+ return(1);
+}
+
+struct target_ops child_ops = {
+ "child", /* to_shortname */
+ "Unix child process", /* to_longname */
+ "Unix child process (started by the \"run\" command).", /* to_doc */
+ child_open, /* to_open */
+ 0, /* to_close */
+ child_attach, /* to_attach */
+ child_detach, /* to_detach */
+ child_resume, /* to_resume */
+ child_wait, /* to_wait */
+ fetch_inferior_registers, /* to_fetch_registers */
+ store_inferior_registers, /* to_store_registers */
+ child_prepare_to_store, /* to_prepare_to_store */
+ child_xfer_memory, /* to_xfer_memory */
+ child_files_info, /* to_files_info */
+ memory_insert_breakpoint, /* to_insert_breakpoint */
+ memory_remove_breakpoint, /* to_remove_breakpoint */
+ terminal_init_inferior, /* to_terminal_init */
+ terminal_inferior, /* to_terminal_inferior */
+ terminal_ours_for_output, /* to_terminal_ours_for_output */
+ terminal_ours, /* to_terminal_ours */
+ child_terminal_info, /* to_terminal_info */
+ kill_inferior, /* to_kill */
+ 0, /* to_load */
+ 0, /* to_lookup_symbol */
+ child_create_inferior, /* to_create_inferior */
+ child_mourn_inferior, /* to_mourn_inferior */
+ child_can_run, /* to_can_run */
+ 0, /* to_notice_signals */
+ process_stratum, /* to_stratum */
+ 0, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ 0, /* sections */
+ 0, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+
+void
+_initialize_inftarg ()
+{
+ add_target (&child_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/init.c b/gnu/usr.bin/gdb/gdb/init.c
new file mode 100644
index 000000000000..26afe1d761eb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/init.c
@@ -0,0 +1,47 @@
+/* Do not modify this file. It is created automatically by "munch". */
+void initialize_all_files () {
+ {extern void _initialize_blockframe (); _initialize_blockframe ();}
+ {extern void _initialize_breakpoint (); _initialize_breakpoint ();}
+ {extern void _initialize_buildsym (); _initialize_buildsym ();}
+ {extern void _initialize_c_language (); _initialize_c_language ();}
+ {extern void _initialize_chill_language (); _initialize_chill_language ();}
+ {extern void _initialize_coffread (); _initialize_coffread ();}
+ {extern void _initialize_command (); _initialize_command ();}
+ {extern void _initialize_complaints (); _initialize_complaints ();}
+ {extern void _initialize_copying (); _initialize_copying ();}
+ {extern void _initialize_core (); _initialize_core ();}
+ {extern void _initialize_corelow (); _initialize_corelow ();}
+ {extern void _initialize_cp_valprint (); _initialize_cp_valprint ();}
+ {extern void _initialize_dbxread (); _initialize_dbxread ();}
+ {extern void _initialize_demangler (); _initialize_demangler ();}
+ {extern void _initialize_elfread (); _initialize_elfread ();}
+ {extern void _initialize_exec (); _initialize_exec ();}
+ {extern void _initialize_gdbtypes (); _initialize_gdbtypes ();}
+ {extern void _initialize_infcmd (); _initialize_infcmd ();}
+ {extern void _initialize_inflow (); _initialize_inflow ();}
+ {extern void _initialize_infrun (); _initialize_infrun ();}
+ {extern void _initialize_inftarg (); _initialize_inftarg ();}
+ {extern void _initialize_language (); _initialize_language ();}
+ {extern void _initialize_m2_language (); _initialize_m2_language ();}
+ {extern void _initialize_maint_cmds (); _initialize_maint_cmds ();}
+ {extern void _initialize_mipsread (); _initialize_mipsread ();}
+ {extern void _initialize_nlmread (); _initialize_nlmread ();}
+ {extern void _initialize_parse (); _initialize_parse ();}
+ {extern void _initialize_printcmd (); _initialize_printcmd ();}
+ {extern void _initialize_remote (); _initialize_remote ();}
+ {extern void _initialize_ser_hardwire (); _initialize_ser_hardwire ();}
+ {extern void _initialize_solib (); _initialize_solib ();}
+ {extern void _initialize_source (); _initialize_source ();}
+ {extern void _initialize_sr_support (); _initialize_sr_support ();}
+ {extern void _initialize_stabsread (); _initialize_stabsread ();}
+ {extern void _initialize_stack (); _initialize_stack ();}
+ {extern void _initialize_symfile (); _initialize_symfile ();}
+ {extern void _initialize_symmisc (); _initialize_symmisc ();}
+ {extern void _initialize_symtab (); _initialize_symtab ();}
+ {extern void _initialize_targets (); _initialize_targets ();}
+ {extern void _initialize_thread (); _initialize_thread ();}
+ {extern void _initialize_typeprint (); _initialize_typeprint ();}
+ {extern void _initialize_utils (); _initialize_utils ();}
+ {extern void _initialize_valprint (); _initialize_valprint ();}
+ {extern void _initialize_values (); _initialize_values ();}
+}
diff --git a/gnu/usr.bin/gdb/gdb/language.c b/gnu/usr.bin/gdb/gdb/language.c
new file mode 100644
index 000000000000..be519532caf3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/language.c
@@ -0,0 +1,1332 @@
+/* Multiple source language support for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Contributed by the Department of Computer Science at the State University
+ of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file contains functions that return things that are specific
+ to languages. Each function should examine current_language if necessary,
+ and return the appropriate result. */
+
+/* FIXME: Most of these would be better organized as macros which
+ return data out of a "language-specific" struct pointer that is set
+ whenever the working language changes. That would be a lot faster. */
+
+#include "defs.h"
+#include <string.h>
+#include <varargs.h>
+
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "expression.h"
+#include "language.h"
+#include "target.h"
+#include "parser-defs.h"
+
+static void
+show_language_command PARAMS ((char *, int));
+
+static void
+set_language_command PARAMS ((char *, int));
+
+static void
+show_type_command PARAMS ((char *, int));
+
+static void
+set_type_command PARAMS ((char *, int));
+
+static void
+show_range_command PARAMS ((char *, int));
+
+static void
+set_range_command PARAMS ((char *, int));
+
+static void
+set_range_str PARAMS ((void));
+
+static void
+set_type_str PARAMS ((void));
+
+static void
+set_lang_str PARAMS ((void));
+
+static void
+unk_lang_error PARAMS ((char *));
+
+static int
+unk_lang_parser PARAMS ((void));
+
+static void
+show_check PARAMS ((char *, int));
+
+static void
+set_check PARAMS ((char *, int));
+
+static void
+set_type_range PARAMS ((void));
+
+/* Forward declaration */
+extern const struct language_defn unknown_language_defn;
+extern char *warning_pre_print;
+
+/* The current (default at startup) state of type and range checking.
+ (If the modes are set to "auto", though, these are changed based
+ on the default language at startup, and then again based on the
+ language of the first source file. */
+
+enum range_mode range_mode = range_mode_auto;
+enum range_check range_check = range_check_off;
+enum type_mode type_mode = type_mode_auto;
+enum type_check type_check = type_check_off;
+
+/* The current language and language_mode (see language.h) */
+
+const struct language_defn *current_language = &unknown_language_defn;
+enum language_mode language_mode = language_mode_auto;
+
+/* The language that the user expects to be typing in (the language
+ of main(), or the last language we notified them about, or C). */
+
+const struct language_defn *expected_language;
+
+/* The list of supported languages. The list itself is malloc'd. */
+
+static const struct language_defn **languages;
+static unsigned languages_size;
+static unsigned languages_allocsize;
+#define DEFAULT_ALLOCSIZE 4
+
+/* The "set language/type/range" commands all put stuff in these
+ buffers. This is to make them work as set/show commands. The
+ user's string is copied here, then the set_* commands look at
+ them and update them to something that looks nice when it is
+ printed out. */
+
+static char *language;
+static char *type;
+static char *range;
+
+/* Warning issued when current_language and the language of the current
+ frame do not match. */
+char lang_frame_mismatch_warn[] =
+ "Warning: the current language does not match this frame.";
+
+
+/* This page contains the functions corresponding to GDB commands
+ and their helpers. */
+
+/* Show command. Display a warning if the language set
+ does not match the frame. */
+static void
+show_language_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ enum language flang; /* The language of the current frame */
+
+ flang = get_frame_language();
+ if (flang != language_unknown &&
+ language_mode == language_mode_manual &&
+ current_language->la_language != flang)
+ printf_filtered("%s\n",lang_frame_mismatch_warn);
+}
+
+/* Set command. Change the current working language. */
+static void
+set_language_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ int i;
+ enum language flang;
+ char *err_lang;
+
+ /* FIXME -- do this from the list, with HELP. */
+ if (!language || !language[0]) {
+ printf("The currently understood settings are:\n\n");
+ printf ("local or auto Automatic setting based on source file\n");
+ printf ("c Use the C language\n");
+ printf ("c++ Use the C++ language\n");
+ printf ("chill Use the Chill language\n");
+ printf ("modula-2 Use the Modula-2 language\n");
+ /* Restore the silly string. */
+ set_language(current_language->la_language);
+ return;
+ }
+
+ /* Search the list of languages for a match. */
+ for (i = 0; i < languages_size; i++) {
+ if (STREQ (languages[i]->la_name, language)) {
+ /* Found it! Go into manual mode, and use this language. */
+ if (languages[i]->la_language == language_auto) {
+ /* Enter auto mode. Set to the current frame's language, if known. */
+ language_mode = language_mode_auto;
+ flang = get_frame_language();
+ if (flang!=language_unknown)
+ set_language(flang);
+ expected_language = current_language;
+ return;
+ } else {
+ /* Enter manual mode. Set the specified language. */
+ language_mode = language_mode_manual;
+ current_language = languages[i];
+ set_type_range ();
+ set_lang_str();
+ expected_language = current_language;
+ return;
+ }
+ }
+ }
+
+ /* Reset the language (esp. the global string "language") to the
+ correct values. */
+ err_lang=savestring(language,strlen(language));
+ make_cleanup (free, err_lang); /* Free it after error */
+ set_language(current_language->la_language);
+ error ("Unknown language `%s'.",err_lang);
+}
+
+/* Show command. Display a warning if the type setting does
+ not match the current language. */
+static void
+show_type_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (type_check != current_language->la_type_check)
+ printf(
+"Warning: the current type check setting does not match the language.\n");
+}
+
+/* Set command. Change the setting for type checking. */
+static void
+set_type_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (STREQ(type,"on"))
+ {
+ type_check = type_check_on;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"warn"))
+ {
+ type_check = type_check_warn;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"off"))
+ {
+ type_check = type_check_off;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"auto"))
+ {
+ type_mode = type_mode_auto;
+ set_type_range();
+ /* Avoid hitting the set_type_str call below. We
+ did it in set_type_range. */
+ return;
+ }
+ set_type_str();
+ show_type_command((char *)NULL, from_tty);
+}
+
+/* Show command. Display a warning if the range setting does
+ not match the current language. */
+static void
+show_range_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+
+ if (range_check != current_language->la_range_check)
+ printf(
+"Warning: the current range check setting does not match the language.\n");
+}
+
+/* Set command. Change the setting for range checking. */
+static void
+set_range_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (STREQ(range,"on"))
+ {
+ range_check = range_check_on;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"warn"))
+ {
+ range_check = range_check_warn;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"off"))
+ {
+ range_check = range_check_off;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"auto"))
+ {
+ range_mode = range_mode_auto;
+ set_type_range();
+ /* Avoid hitting the set_range_str call below. We
+ did it in set_type_range. */
+ return;
+ }
+ set_range_str();
+ show_range_command((char *)0, from_tty);
+}
+
+/* Set the status of range and type checking based on
+ the current modes and the current language.
+ If SHOW is non-zero, then print out the current language,
+ type and range checking status. */
+static void
+set_type_range()
+{
+
+ if (range_mode == range_mode_auto)
+ range_check = current_language->la_range_check;
+
+ if (type_mode == type_mode_auto)
+ type_check = current_language->la_type_check;
+
+ set_type_str();
+ set_range_str();
+}
+
+/* Set current language to (enum language) LANG. */
+
+void
+set_language(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ current_language = languages[i];
+ set_type_range ();
+ set_lang_str();
+ break;
+ }
+ }
+}
+
+/* This page contains functions that update the global vars
+ language, type and range. */
+static void
+set_lang_str()
+{
+ char *prefix = "";
+
+ free (language);
+ if (language_mode == language_mode_auto)
+ prefix = "auto; currently ";
+
+ language = concat(prefix, current_language->la_name, NULL);
+}
+
+static void
+set_type_str()
+{
+ char *tmp, *prefix = "";
+
+ free (type);
+ if (type_mode==type_mode_auto)
+ prefix = "auto; currently ";
+
+ switch(type_check)
+ {
+ case type_check_on:
+ tmp = "on";
+ break;
+ case type_check_off:
+ tmp = "off";
+ break;
+ case type_check_warn:
+ tmp = "warn";
+ break;
+ default:
+ error ("Unrecognized type check setting.");
+ }
+
+ type = concat(prefix,tmp,NULL);
+}
+
+static void
+set_range_str()
+{
+ char *tmp, *pref = "";
+
+ free (range);
+ if (range_mode==range_mode_auto)
+ pref = "auto; currently ";
+
+ switch(range_check)
+ {
+ case range_check_on:
+ tmp = "on";
+ break;
+ case range_check_off:
+ tmp = "off";
+ break;
+ case range_check_warn:
+ tmp = "warn";
+ break;
+ default:
+ error ("Unrecognized range check setting.");
+ }
+
+ range = concat(pref,tmp,NULL);
+}
+
+
+/* Print out the current language settings: language, range and
+ type checking. If QUIETLY, print only what has changed. */
+
+void
+language_info (quietly)
+ int quietly;
+{
+ if (quietly && expected_language == current_language)
+ return;
+
+ expected_language = current_language;
+ printf("Current language: %s\n",language);
+ show_language_command((char *)0, 1);
+
+ if (!quietly)
+ {
+ printf("Type checking: %s\n",type);
+ show_type_command((char *)0, 1);
+ printf("Range checking: %s\n",range);
+ show_range_command((char *)0, 1);
+ }
+}
+
+/* Return the result of a binary operation. */
+
+#if 0 /* Currently unused */
+
+struct type *
+binop_result_type(v1,v2)
+ value v1,v2;
+{
+ int l1,l2,size,uns;
+
+ l1 = TYPE_LENGTH(VALUE_TYPE(v1));
+ l2 = TYPE_LENGTH(VALUE_TYPE(v2));
+
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ if (TYPE_CODE(VALUE_TYPE(v1))==TYPE_CODE_FLT)
+ return TYPE_CODE(VALUE_TYPE(v2)) == TYPE_CODE_FLT && l2 > l1 ?
+ VALUE_TYPE(v2) : VALUE_TYPE(v1);
+ else if (TYPE_CODE(VALUE_TYPE(v2))==TYPE_CODE_FLT)
+ return TYPE_CODE(VALUE_TYPE(v1)) == TYPE_CODE_FLT && l1 > l2 ?
+ VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ else if (TYPE_UNSIGNED(VALUE_TYPE(v1)) && l1 > l2)
+ return VALUE_TYPE(v1);
+ else if (TYPE_UNSIGNED(VALUE_TYPE(v2)) && l2 > l1)
+ return VALUE_TYPE(v2);
+ else /* Both are signed. Result is the longer type */
+ return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ break;
+ case language_m2:
+ /* If we are doing type-checking, l1 should equal l2, so this is
+ not needed. */
+ return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ break;
+ case language_chill:
+ error ("Missing Chill support in function binop_result_check.");/*FIXME*/
+ }
+ abort();
+ return (struct type *)0; /* For lint */
+}
+
+#endif /* 0 */
+
+
+/* This page contains functions that return format strings for
+ printf for printing out numbers in different formats */
+
+/* Returns the appropriate printf format for hexadecimal
+ numbers. */
+char *
+local_hex_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_hex_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_hex_format_specifier ());
+ strcat (form, local_hex_format_suffix ());
+ return form;
+}
+
+/* Converts a number to hexadecimal and stores it in a static
+ string. Returns a pointer to this string. */
+char *
+local_hex_string (num)
+ unsigned long num;
+{
+ static char res[50];
+
+ sprintf (res, local_hex_format(), num);
+ return res;
+}
+
+/* Converts a number to custom hexadecimal and stores it in a static
+ string. Returns a pointer to this string. */
+char *
+local_hex_string_custom(num,pre)
+ unsigned long num;
+ char *pre;
+{
+ static char res[50];
+
+ sprintf (res, local_hex_format_custom(pre), num);
+ return res;
+}
+
+/* Returns the appropriate printf format for octal
+ numbers. */
+char *
+local_octal_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_octal_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_octal_format_specifier ());
+ strcat (form, local_octal_format_suffix ());
+ return form;
+}
+
+/* Returns the appropriate printf format for decimal numbers. */
+char *
+local_decimal_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_decimal_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_decimal_format_specifier ());
+ strcat (form, local_decimal_format_suffix ());
+ return form;
+}
+
+/* This page contains functions that are used in type/range checking.
+ They all return zero if the type/range check fails.
+
+ It is hoped that these will make extending GDB to parse different
+ languages a little easier. These are primarily used in eval.c when
+ evaluating expressions and making sure that their types are correct.
+ Instead of having a mess of conjucted/disjuncted expressions in an "if",
+ the ideas of type can be wrapped up in the following functions.
+
+ Note that some of them are not currently dependent upon which language
+ is currently being parsed. For example, floats are the same in
+ C and Modula-2 (ie. the only floating point type has TYPE_CODE of
+ TYPE_CODE_FLT), while booleans are different. */
+
+/* Returns non-zero if its argument is a simple type. This is the same for
+ both Modula-2 and for C. In the C case, TYPE_CODE_CHAR will never occur,
+ and thus will never cause the failure of the test. */
+int
+simple_type(type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if its argument is of an ordered type.
+ An ordered type is one in which the elements can be tested for the
+ properties of "greater than", "less than", etc, or for which the
+ operations "increment" or "decrement" make sense. */
+int
+ordered_type (type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_RANGE:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if the two types are the same */
+int
+same_type (arg1, arg2)
+ struct type *arg1, *arg2;
+{
+ if (structured_type(arg1) ? !structured_type(arg2) : structured_type(arg2))
+ /* One is structured and one isn't */
+ return 0;
+ else if (structured_type(arg1) && structured_type(arg2))
+ return arg1 == arg2;
+ else if (numeric_type(arg1) && numeric_type(arg2))
+ return (TYPE_CODE(arg2) == TYPE_CODE(arg1)) &&
+ (TYPE_UNSIGNED(arg1) == TYPE_UNSIGNED(arg2))
+ ? 1 : 0;
+ else
+ return arg1==arg2;
+}
+
+/* Returns non-zero if the type is integral */
+int
+integral_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) != TYPE_CODE_INT) &&
+ (TYPE_CODE(type) != TYPE_CODE_ENUM) ? 0 : 1;
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1;
+ case language_chill:
+ error ("Missing Chill support in function integral_type."); /*FIXME*/
+ default:
+ error ("Language not supported.");
+ }
+}
+
+/* Returns non-zero if the value is numeric */
+int
+numeric_type (type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if the value is a character type */
+int
+character_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_CHAR ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) == TYPE_CODE_INT) &&
+ TYPE_LENGTH(type) == sizeof(char)
+ ? 1 : 0;
+ default:
+ return (0);
+ }
+}
+
+/* Returns non-zero if the value is a string type */
+int
+string_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_STRING ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ /* C does not have distinct string type. */
+ return (0);
+ default:
+ return (0);
+ }
+}
+
+/* Returns non-zero if the value is a boolean type */
+int
+boolean_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_BOOL ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1;
+ default:
+ return (0);
+ }
+}
+
+/* Returns non-zero if the value is a floating-point type */
+int
+float_type (type)
+ struct type *type;
+{
+ return TYPE_CODE(type) == TYPE_CODE_FLT;
+}
+
+/* Returns non-zero if the value is a pointer type */
+int
+pointer_type(type)
+ struct type *type;
+{
+ return TYPE_CODE(type) == TYPE_CODE_PTR ||
+ TYPE_CODE(type) == TYPE_CODE_REF;
+}
+
+/* Returns non-zero if the value is a structured type */
+int
+structured_type(type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE(type) == TYPE_CODE_UNION) ||
+ (TYPE_CODE(type) == TYPE_CODE_ARRAY);
+ case language_m2:
+ return (TYPE_CODE(type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE(type) == TYPE_CODE_SET) ||
+ (TYPE_CODE(type) == TYPE_CODE_ARRAY);
+ case language_chill:
+ error ("Missing Chill support in function structured_type."); /*FIXME*/
+ default:
+ return (0);
+ }
+}
+
+/* This page contains functions that return info about
+ (struct value) values used in GDB. */
+
+/* Returns non-zero if the value VAL represents a true value. */
+int
+value_true(val)
+ value val;
+{
+ int len, i;
+ struct type *type;
+ LONGEST v;
+
+ switch (current_language->la_language) {
+
+ case language_c:
+ case language_cplus:
+ return !value_logical_not (val);
+
+ case language_m2:
+ type = VALUE_TYPE(val);
+ if (TYPE_CODE (type) != TYPE_CODE_BOOL)
+ return 0; /* Not a BOOLEAN at all */
+ /* Search the fields for one that matches the current value. */
+ len = TYPE_NFIELDS (type);
+ v = value_as_long (val);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (v == TYPE_FIELD_BITPOS (type, i))
+ break;
+ }
+ if (i >= len)
+ return 0; /* Not a valid BOOLEAN value */
+ if (STREQ ("TRUE", TYPE_FIELD_NAME(VALUE_TYPE(val), i)))
+ return 1; /* BOOLEAN with value TRUE */
+ else
+ return 0; /* BOOLEAN with value FALSE */
+ break;
+
+ case language_chill:
+ error ("Missing Chill support in function value_type."); /*FIXME*/
+
+ default:
+ error ("Language not supported.");
+ }
+}
+
+/* Returns non-zero if the operator OP is defined on
+ the values ARG1 and ARG2. */
+
+#if 0 /* Currently unused */
+
+void
+binop_type_check(arg1,arg2,op)
+ value arg1,arg2;
+ int op;
+{
+ struct type *t1, *t2;
+
+ /* If we're not checking types, always return success. */
+ if (!STRICT_TYPE)
+ return;
+
+ t1=VALUE_TYPE(arg1);
+ if (arg2!=(value)NULL)
+ t2=VALUE_TYPE(arg2);
+ else
+ t2=NULL;
+
+ switch(op)
+ {
+ case BINOP_ADD:
+ case BINOP_SUB:
+ if ((numeric_type(t1) && pointer_type(t2)) ||
+ (pointer_type(t1) && numeric_type(t2)))
+ {
+ warning ("combining pointer and integer.\n");
+ break;
+ }
+ case BINOP_MUL:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ if (!numeric_type(t1) || !numeric_type(t2))
+ type_op_error ("Arguments to %s must be numbers.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ if (!boolean_type(t1) || !boolean_type(t2))
+ type_op_error ("Arguments to %s must be of boolean type.",op);
+ break;
+
+ case BINOP_EQUAL:
+ if ((pointer_type(t1) && !(pointer_type(t2) || integral_type(t2))) ||
+ (pointer_type(t2) && !(pointer_type(t1) || integral_type(t1))))
+ type_op_error ("A pointer can only be compared to an integer or pointer.",op);
+ else if ((pointer_type(t1) && integral_type(t2)) ||
+ (integral_type(t1) && pointer_type(t2)))
+ {
+ warning ("combining integer and pointer.\n");
+ break;
+ }
+ else if (!simple_type(t1) || !simple_type(t2))
+ type_op_error ("Arguments to %s must be of simple type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_REM:
+ case BINOP_MOD:
+ if (!integral_type(t1) || !integral_type(t2))
+ type_op_error ("Arguments to %s must be of integral type.",op);
+ break;
+
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ if (!ordered_type(t1) || !ordered_type(t2))
+ type_op_error ("Arguments to %s must be of ordered type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_ASSIGN:
+ if (pointer_type(t1) && !integral_type(t2))
+ type_op_error ("A pointer can only be assigned an integer.",op);
+ else if (pointer_type(t1) && integral_type(t2))
+ {
+ warning ("combining integer and pointer.");
+ break;
+ }
+ else if (!simple_type(t1) || !simple_type(t2))
+ type_op_error ("Arguments to %s must be of simple type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_CONCAT:
+ /* FIXME: Needs to handle bitstrings as well. */
+ if (!(string_type(t1) || character_type(t1) || integral_type(t1))
+ || !(string_type(t2) || character_type(t2) || integral_type(t2)))
+ type_op_error ("Arguments to %s must be strings or characters.", op);
+ break;
+
+ /* Unary checks -- arg2 is null */
+
+ case UNOP_LOGICAL_NOT:
+ if (!boolean_type(t1))
+ type_op_error ("Argument to %s must be of boolean type.",op);
+ break;
+
+ case UNOP_PLUS:
+ case UNOP_NEG:
+ if (!numeric_type(t1))
+ type_op_error ("Argument to %s must be of numeric type.",op);
+ break;
+
+ case UNOP_IND:
+ if (integral_type(t1))
+ {
+ warning ("combining pointer and integer.\n");
+ break;
+ }
+ else if (!pointer_type(t1))
+ type_op_error ("Argument to %s must be a pointer.",op);
+ break;
+
+ case UNOP_PREINCREMENT:
+ case UNOP_POSTINCREMENT:
+ case UNOP_PREDECREMENT:
+ case UNOP_POSTDECREMENT:
+ if (!ordered_type(t1))
+ type_op_error ("Argument to %s must be of an ordered type.",op);
+ break;
+
+ default:
+ /* Ok. The following operators have different meanings in
+ different languages. */
+ switch(current_language->la_language)
+ {
+#ifdef _LANG_c
+ case language_c:
+ case language_cplus:
+ switch(op)
+ {
+ case BINOP_DIV:
+ if (!numeric_type(t1) || !numeric_type(t2))
+ type_op_error ("Arguments to %s must be numbers.",op);
+ break;
+ }
+ break;
+#endif
+
+#ifdef _LANG_m2
+ case language_m2:
+ switch(op)
+ {
+ case BINOP_DIV:
+ if (!float_type(t1) || !float_type(t2))
+ type_op_error ("Arguments to %s must be floating point numbers.",op);
+ break;
+ case BINOP_INTDIV:
+ if (!integral_type(t1) || !integral_type(t2))
+ type_op_error ("Arguments to %s must be of integral type.",op);
+ break;
+ }
+#endif
+
+#ifdef _LANG_chill
+ case language_chill:
+ error ("Missing Chill support in function binop_type_check.");/*FIXME*/
+#endif
+
+ }
+ }
+}
+
+#endif /* 0 */
+
+
+/* This page contains functions for the printing out of
+ error messages that occur during type- and range-
+ checking. */
+
+/* Prints the format string FMT with the operator as a string
+ corresponding to the opcode OP. If FATAL is non-zero, then
+ this is an error and error () is called. Otherwise, it is
+ a warning and printf() is called. */
+void
+op_error (fmt,op,fatal)
+ char *fmt;
+ enum exp_opcode op;
+ int fatal;
+{
+ if (fatal)
+ error (fmt,op_string(op));
+ else
+ {
+ warning (fmt,op_string(op));
+ }
+}
+
+/* These are called when a language fails a type- or range-check.
+ The first argument should be a printf()-style format string, and
+ the rest of the arguments should be its arguments. If
+ [type|range]_check is [type|range]_check_on, then return_to_top_level()
+ is called in the style of error (). Otherwise, the message is prefixed
+ by the value of warning_pre_print and we do not return to the top level. */
+
+void
+type_error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ if (type_check==type_check_warn)
+ fprintf(stderr,warning_pre_print);
+ else
+ target_terminal_ours();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+ if (type_check==type_check_on)
+ return_to_top_level (RETURN_ERROR);
+}
+
+void
+range_error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ if (range_check==range_check_warn)
+ fprintf(stderr,warning_pre_print);
+ else
+ target_terminal_ours();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+ if (range_check==range_check_on)
+ return_to_top_level (RETURN_ERROR);
+}
+
+
+/* This page contains miscellaneous functions */
+
+/* Return the language struct for a given language enum. */
+
+const struct language_defn *
+language_def(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ return languages[i];
+ }
+ }
+ return NULL;
+}
+
+/* Return the language as a string */
+char *
+language_str(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ return languages[i]->la_name;
+ }
+ }
+ return "Unknown";
+}
+
+static void
+set_check (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ printf(
+"\"set check\" must be followed by the name of a check subcommand.\n");
+ help_list(setchecklist, "set check ", -1, stdout);
+}
+
+static void
+show_check (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ cmd_show_list(showchecklist, from_tty, "");
+}
+
+/* Add a language to the set of known languages. */
+
+void
+add_language (lang)
+ const struct language_defn *lang;
+{
+ if (lang->la_magic != LANG_MAGIC)
+ {
+ fprintf(stderr, "Magic number of %s language struct wrong\n",
+ lang->la_name);
+ abort();
+ }
+
+ if (!languages)
+ {
+ languages_allocsize = DEFAULT_ALLOCSIZE;
+ languages = (const struct language_defn **) xmalloc
+ (languages_allocsize * sizeof (*languages));
+ }
+ if (languages_size >= languages_allocsize)
+ {
+ languages_allocsize *= 2;
+ languages = (const struct language_defn **) xrealloc ((char *) languages,
+ languages_allocsize * sizeof (*languages));
+ }
+ languages[languages_size++] = lang;
+}
+
+/* Define the language that is no language. */
+
+static int
+unk_lang_parser ()
+{
+ return 1;
+}
+
+static void
+unk_lang_error (msg)
+ char *msg;
+{
+ error ("Attempted to parse an expression with unknown language");
+}
+
+static void
+unk_lang_printchar (c, stream)
+ register int c;
+ FILE *stream;
+{
+ error ("internal error - unimplemented function unk_lang_printchar called.");
+}
+
+static void
+unk_lang_printstr (stream, string, length, force_ellipses)
+ FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ error ("internal error - unimplemented function unk_lang_printstr called.");
+}
+
+static struct type *
+unk_lang_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ error ("internal error - unimplemented function unk_lang_create_fundamental_type called.");
+}
+
+void
+unk_lang_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ error ("internal error - unimplemented function unk_lang_print_type called.");
+}
+
+int
+unk_lang_val_print (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ error ("internal error - unimplemented function unk_lang_val_print called.");
+}
+
+static struct type ** const (unknown_builtin_types[]) = { 0 };
+static const struct op_print unk_op_print_tab[] = {
+ {NULL, OP_NULL, PREC_NULL, 0}
+};
+
+const struct language_defn unknown_language_defn = {
+ "unknown",
+ language_unknown,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* These two structs define fake entries for the "local" and "auto" options. */
+const struct language_defn auto_language_defn = {
+ "auto",
+ language_auto,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+const struct language_defn local_language_defn = {
+ "local",
+ language_auto,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialize the language routines */
+
+void
+_initialize_language()
+{
+ struct cmd_list_element *set, *show;
+
+ /* GDB commands for language specific stuff */
+
+ set = add_set_cmd ("language", class_support, var_string_noescape,
+ (char *)&language,
+ "Set the current source language.",
+ &setlist);
+ show = add_show_from_set (set, &showlist);
+ set->function.cfunc = set_language_command;
+ show->function.cfunc = show_language_command;
+
+ add_prefix_cmd ("check", no_class, set_check,
+ "Set the status of the type/range checker",
+ &setchecklist, "set check ", 0, &setlist);
+ add_alias_cmd ("c", "check", no_class, 1, &setlist);
+ add_alias_cmd ("ch", "check", no_class, 1, &setlist);
+
+ add_prefix_cmd ("check", no_class, show_check,
+ "Show the status of the type/range checker",
+ &showchecklist, "show check ", 0, &showlist);
+ add_alias_cmd ("c", "check", no_class, 1, &showlist);
+ add_alias_cmd ("ch", "check", no_class, 1, &showlist);
+
+ set = add_set_cmd ("type", class_support, var_string_noescape,
+ (char *)&type,
+ "Set type checking. (on/warn/off/auto)",
+ &setchecklist);
+ show = add_show_from_set (set, &showchecklist);
+ set->function.cfunc = set_type_command;
+ show->function.cfunc = show_type_command;
+
+ set = add_set_cmd ("range", class_support, var_string_noescape,
+ (char *)&range,
+ "Set range checking. (on/warn/off/auto)",
+ &setchecklist);
+ show = add_show_from_set (set, &showchecklist);
+ set->function.cfunc = set_range_command;
+ show->function.cfunc = show_range_command;
+
+ add_language (&unknown_language_defn);
+ add_language (&local_language_defn);
+ add_language (&auto_language_defn);
+
+ language = savestring ("auto",strlen("auto"));
+ range = savestring ("auto",strlen("auto"));
+ type = savestring ("auto",strlen("auto"));
+
+ /* Have the above take effect */
+
+ set_language_command (language, 0);
+ set_type_command (NULL, 0);
+ set_range_command (NULL, 0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/language.h b/gnu/usr.bin/gdb/gdb/language.h
new file mode 100644
index 000000000000..9df5345c9301
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/language.h
@@ -0,0 +1,413 @@
+/* Source-language-related definitions for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Contributed by the Department of Computer Science at the State University
+ of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (LANGUAGE_H)
+#define LANGUAGE_H 1
+
+#ifdef __STDC__ /* Forward decls for prototypes */
+struct value;
+struct objfile;
+/* enum exp_opcode; ANSI's `wisdom' didn't include forward enum decls. */
+#endif
+
+/* This used to be included to configure GDB for one or more specific
+ languages. Now it is shortcutted to configure for all of them. FIXME. */
+/* #include "lang_def.h" */
+#define _LANG_c
+#define _LANG_m2
+#define _LANG_chill
+
+/* range_mode ==
+ range_mode_auto: range_check set automatically to default of language.
+ range_mode_manual: range_check set manually by user. */
+
+extern enum range_mode {range_mode_auto, range_mode_manual} range_mode;
+
+/* range_check ==
+ range_check_on: Ranges are checked in GDB expressions, producing errors.
+ range_check_warn: Ranges are checked, producing warnings.
+ range_check_off: Ranges are not checked in GDB expressions. */
+
+extern enum range_check
+ {range_check_off, range_check_warn, range_check_on} range_check;
+
+/* type_mode ==
+ type_mode_auto: type_check set automatically to default of language
+ type_mode_manual: type_check set manually by user. */
+
+extern enum type_mode {type_mode_auto, type_mode_manual} type_mode;
+
+/* type_check ==
+ type_check_on: Types are checked in GDB expressions, producing errors.
+ type_check_warn: Types are checked, producing warnings.
+ type_check_off: Types are not checked in GDB expressions. */
+
+extern enum type_check
+ {type_check_off, type_check_warn, type_check_on} type_check;
+
+/* Information for doing language dependent formatting of printed values. */
+
+struct language_format_info
+{
+ /* The format that can be passed directly to standard C printf functions
+ to generate a completely formatted value in the format appropriate for
+ the language. */
+
+ char *la_format;
+
+ /* The prefix to be used when directly printing a value, or constructing
+ a standard C printf format. This generally is everything up to the
+ conversion specification (the part introduced by the '%' character
+ and terminated by the conversion specifier character). */
+
+ char *la_format_prefix;
+
+ /* The conversion specifier. This is generally everything after the
+ field width and precision, typically only a single character such
+ as 'o' for octal format or 'x' for hexadecimal format. */
+
+ char *la_format_specifier;
+
+ /* The suffix to be used when directly printing a value, or constructing
+ a standard C printf format. This generally is everything after the
+ conversion specification (the part introduced by the '%' character
+ and terminated by the conversion specifier character). */
+
+ char *la_format_suffix; /* Suffix for custom format string */
+};
+
+/* Structure tying together assorted information about a language. */
+
+struct language_defn
+{
+ /* Name of the language */
+
+ char *la_name;
+
+ /* its symtab language-enum (defs.h) */
+
+ enum language la_language;
+
+ /* Its builtin types */
+
+ struct type ** const *la_builtin_type_vector;
+
+ /* Default range checking */
+
+ enum range_check la_range_check;
+
+ /* Default type checking */
+
+ enum type_check la_type_check;
+
+ /* Parser function. */
+
+ int (*la_parser) PARAMS((void));
+
+ /* Parser error function */
+
+ void (*la_error) PARAMS ((char *));
+
+ void (*la_printchar) PARAMS ((int, FILE *));
+
+ void (*la_printstr) PARAMS ((FILE *, char *, unsigned int, int));
+
+ struct type *(*la_fund_type) PARAMS ((struct objfile *, int));
+
+ /* Print a type using syntax appropriate for this language. */
+
+ void (*la_print_type) PARAMS ((struct type *, char *, FILE *, int, int));
+
+ /* Print a value using syntax appropriate for this language. */
+
+ int (*la_val_print) PARAMS ((struct type *, char *, CORE_ADDR, FILE *,
+ int, int, int, enum val_prettyprint));
+
+ /* Longest signed integral type */
+
+ struct type **la_longest_int;
+
+ /* Longest unsigned integral type */
+
+ struct type **la_longest_unsigned_int;
+
+ /* Longest floating point type */
+
+ struct type **la_longest_float;
+
+ /* Base 2 (binary) formats. */
+
+ struct language_format_info la_binary_format;
+
+ /* Base 8 (octal) formats. */
+
+ struct language_format_info la_octal_format;
+
+ /* Base 10 (decimal) formats */
+
+ struct language_format_info la_decimal_format;
+
+ /* Base 16 (hexadecimal) formats */
+
+ struct language_format_info la_hex_format;
+
+
+ /* Table for printing expressions */
+
+ const struct op_print *la_op_print_tab;
+
+ /* Add fields above this point, so the magic number is always last. */
+ /* Magic number for compat checking */
+
+ long la_magic;
+
+};
+
+#define LANG_MAGIC 910823L
+
+/* Pointer to the language_defn for our current language. This pointer
+ always points to *some* valid struct; it can be used without checking
+ it for validity.
+
+ The current language affects expression parsing and evaluation
+ (FIXME: it might be cleaner to make the evaluation-related stuff
+ separate exp_opcodes for each different set of semantics. We
+ should at least think this through more clearly with respect to
+ what happens if the language is changed between parsing and
+ evaluation) and printing of things like types and arrays. It does
+ *not* affect symbol-reading-- each source file in a symbol-file has
+ its own language and we should keep track of that regardless of the
+ language when symbols are read. If we want some manual setting for
+ the language of symbol files (e.g. detecting when ".c" files are
+ C++), it should be a seprate setting from the current_language. */
+
+extern const struct language_defn *current_language;
+
+/* Pointer to the language_defn expected by the user, e.g. the language
+ of main(), or the language we last mentioned in a message, or C. */
+
+extern const struct language_defn *expected_language;
+
+/* language_mode ==
+ language_mode_auto: current_language automatically set upon selection
+ of scope (e.g. stack frame)
+ language_mode_manual: current_language set only by user. */
+
+extern enum language_mode
+ {language_mode_auto, language_mode_manual} language_mode;
+
+/* These macros define the behaviour of the expression
+ evaluator. */
+
+/* Should we strictly type check expressions? */
+#define STRICT_TYPE (type_check != type_check_off)
+
+/* Should we range check values against the domain of their type? */
+#define RANGE_CHECK (range_check != range_check_off)
+
+/* "cast" really means conversion */
+/* FIXME -- should be a setting in language_defn */
+#define CAST_IS_CONVERSION (current_language->la_language == language_c || \
+ current_language->la_language == language_cplus)
+
+extern void
+language_info PARAMS ((int));
+
+extern void
+set_language PARAMS ((enum language));
+
+
+/* This page contains functions that return things that are
+ specific to languages. Each of these functions is based on
+ the current setting of working_lang, which the user sets
+ with the "set language" command. */
+
+/* Returns some built-in types */
+#define longest_int() (*current_language->la_longest_int)
+#define longest_unsigned_int() (*current_language->la_longest_unsigned_int)
+#define longest_float() (*current_language->la_longest_float)
+
+#define create_fundamental_type(objfile,typeid) \
+ (current_language->la_fund_type(objfile, typeid))
+
+#define LA_PRINT_TYPE(type,varstring,stream,show,level) \
+ (current_language->la_print_type(type,varstring,stream,show,level))
+
+#define LA_VAL_PRINT(type,valaddr,addr,stream,fmt,deref,recurse,pretty) \
+ (current_language->la_val_print(type,valaddr,addr,stream,fmt,deref, \
+ recurse,pretty))
+
+/* Return a format string for printf that will print a number in one of
+ the local (language-specific) formats. Result is static and is
+ overwritten by the next call. Takes printf options like "08" or "l"
+ (to produce e.g. %08x or %lx). */
+
+#define local_binary_format() \
+ (current_language->la_binary_format.la_format)
+#define local_binary_format_prefix() \
+ (current_language->la_binary_format.la_format_prefix)
+#define local_binary_format_specifier() \
+ (current_language->la_binary_format.la_format_specifier)
+#define local_binary_format_suffix() \
+ (current_language->la_binary_format.la_format_suffix)
+
+#define local_octal_format() \
+ (current_language->la_octal_format.la_format)
+#define local_octal_format_prefix() \
+ (current_language->la_octal_format.la_format_prefix)
+#define local_octal_format_specifier() \
+ (current_language->la_octal_format.la_format_specifier)
+#define local_octal_format_suffix() \
+ (current_language->la_octal_format.la_format_suffix)
+
+#define local_decimal_format() \
+ (current_language->la_decimal_format.la_format)
+#define local_decimal_format_prefix() \
+ (current_language->la_decimal_format.la_format_prefix)
+#define local_decimal_format_specifier() \
+ (current_language->la_decimal_format.la_format_specifier)
+#define local_decimal_format_suffix() \
+ (current_language->la_decimal_format.la_format_suffix)
+
+#define local_hex_format() \
+ (current_language->la_hex_format.la_format)
+#define local_hex_format_prefix() \
+ (current_language->la_hex_format.la_format_prefix)
+#define local_hex_format_specifier() \
+ (current_language->la_hex_format.la_format_specifier)
+#define local_hex_format_suffix() \
+ (current_language->la_hex_format.la_format_suffix)
+
+#define LA_PRINT_CHAR(ch, stream) \
+ (current_language->la_printchar(ch, stream))
+#define LA_PRINT_STRING(stream, string, length, force_ellipses) \
+ (current_language->la_printstr(stream, string, length, force_ellipses))
+
+/* Test a character to decide whether it can be printed in literal form
+ or needs to be printed in another representation. For example,
+ in C the literal form of the character with octal value 141 is 'a'
+ and the "other representation" is '\141'. The "other representation"
+ is program language dependent. */
+
+#define PRINT_LITERAL_FORM(c) \
+ ((c)>=0x20 && ((c)<0x7F || (c)>=0xA0) && (!sevenbit_strings || (c)<0x80))
+
+/* Return a format string for printf that will print a number in one of
+ the local (language-specific) formats. Result is static and is
+ overwritten by the next call. Takes printf options like "08" or "l"
+ (to produce e.g. %08x or %lx). */
+
+extern char *
+local_decimal_format_custom PARAMS ((char *)); /* language.c */
+
+extern char *
+local_octal_format_custom PARAMS ((char *)); /* language.c */
+
+extern char *
+local_hex_format_custom PARAMS ((char *)); /* language.c */
+
+/* Return a string that contains a number formatted in one of the local
+ (language-specific) formats. Result is static and is overwritten by
+ the next call. Takes printf options like "08" or "l". */
+
+extern char *
+local_hex_string PARAMS ((unsigned long)); /* language.c */
+
+extern char *
+local_hex_string_custom PARAMS ((unsigned long, char *)); /* language.c */
+
+/* Type predicates */
+
+extern int
+simple_type PARAMS ((struct type *));
+
+extern int
+ordered_type PARAMS ((struct type *));
+
+extern int
+same_type PARAMS ((struct type *, struct type *));
+
+extern int
+integral_type PARAMS ((struct type *));
+
+extern int
+numeric_type PARAMS ((struct type *));
+
+extern int
+character_type PARAMS ((struct type *));
+
+extern int
+boolean_type PARAMS ((struct type *));
+
+extern int
+float_type PARAMS ((struct type *));
+
+extern int
+pointer_type PARAMS ((struct type *));
+
+extern int
+structured_type PARAMS ((struct type *));
+
+/* Checks Binary and Unary operations for semantic type correctness */
+/* FIXME: Does not appear to be used */
+#define unop_type_check(v,o) binop_type_check((v),NULL,(o))
+
+extern void
+binop_type_check PARAMS ((struct value *, struct value *, int));
+
+/* Error messages */
+
+extern void
+op_error PARAMS ((char *fmt, enum exp_opcode, int));
+
+#define type_op_error(f,o) \
+ op_error((f),(o),type_check==type_check_on ? 1 : 0)
+#define range_op_error(f,o) \
+ op_error((f),(o),range_check==range_check_on ? 1 : 0)
+
+extern void
+type_error ();
+
+void
+range_error ();
+
+/* Data: Does this value represent "truth" to the current language? */
+
+extern int
+value_true PARAMS ((struct value *));
+
+/* Misc: The string representing a particular enum language. */
+
+extern const struct language_defn *
+language_def PARAMS ((enum language));
+
+extern char *
+language_str PARAMS ((enum language));
+
+/* Add a language to the set known by GDB (at initialization time). */
+
+extern void
+add_language PARAMS ((const struct language_defn *));
+
+extern enum language
+get_frame_language PARAMS ((void)); /* In stack.c */
+
+#endif /* defined (LANGUAGE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/m2-exp.y b/gnu/usr.bin/gdb/gdb/m2-exp.y
new file mode 100644
index 000000000000..cc4001fa984c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-exp.y
@@ -0,0 +1,1169 @@
+/* YACC grammar for Modula-2 expressions, for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Generated from expread.y (now c-exp.y) and contributed by the Department
+ of Computer Science at the State University of New York at Buffalo, 1991.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a Modula-2 expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include "defs.h"
+#include "expression.h"
+#include "language.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "m2-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth m2_maxdepth
+#define yyparse m2_parse
+#define yylex m2_lex
+#define yyerror m2_error
+#define yylval m2_lval
+#define yychar m2_char
+#define yydebug m2_debug
+#define yypact m2_pact
+#define yyr1 m2_r1
+#define yyr2 m2_r2
+#define yydef m2_def
+#define yychk m2_chk
+#define yypgo m2_pgo
+#define yyact m2_act
+#define yyexca m2_exca
+#define yyerrflag m2_errflag
+#define yynerrs m2_nerrs
+#define yyps m2_ps
+#define yypv m2_pv
+#define yys m2_s
+#define yy_yys m2_yys
+#define yystate m2_state
+#define yytmp m2_tmp
+#define yyv m2_v
+#define yy_yyv m2_yyv
+#define yyval m2_val
+#define yylloc m2_lloc
+#define yyreds m2_reds /* With YYDEBUG defined */
+#define yytoks m2_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+#if 0
+static char *
+make_qualname PARAMS ((char *, char *));
+#endif
+
+static int
+parse_number PARAMS ((int));
+
+/* The sign of the number being parsed. */
+static int number_sign = 1;
+
+/* The block that the module specified by the qualifer on an identifer is
+ contained in, */
+#if 0
+static struct block *modblock=0;
+#endif
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ unsigned LONGEST ulval;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%type <voidval> exp type_exp start set
+%type <voidval> variable
+%type <tval> type
+%type <bval> block
+%type <sym> fblock
+
+%token <lval> INT HEX ERROR
+%token <ulval> UINT M2_TRUE M2_FALSE CHAR
+%token <dval> FLOAT
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+ and both convey their data as strings.
+ But a TYPENAME is a string that happens to be defined as a typedef
+ or builtin type name (such as int or char)
+ and a NAME is any other symbol.
+
+ Contexts where this distinction is not important can use the
+ nonterminal "name", which matches either NAME or TYPENAME. */
+
+%token <sval> STRING
+%token <sval> NAME BLOCKNAME IDENT VARNAME
+%token <sval> TYPENAME
+
+%token SIZE CAP ORD HIGH ABS MIN_FUNC MAX_FUNC FLOAT_FUNC VAL CHR ODD TRUNC
+%token INC DEC INCL EXCL
+
+/* The GDB scope operator */
+%token COLONCOLON
+
+%token <lval> LAST REGNAME
+
+%token <ivar> INTERNAL_VAR
+
+/* M2 tokens */
+%left ','
+%left ABOVE_COMMA
+%nonassoc ASSIGN
+%left '<' '>' LEQ GEQ '=' NOTEQUAL '#' IN
+%left OROR
+%left LOGICAL_AND '&'
+%left '@'
+%left '+' '-'
+%left '*' '/' DIV MOD
+%right UNARY
+%right '^' DOT '[' '('
+%right NOT '~'
+%left COLONCOLON QID
+/* This is not an actual token ; it is used for precedence.
+%right QID
+*/
+
+
+%%
+
+start : exp
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ ;
+
+/* Expressions */
+
+exp : exp '^' %prec UNARY
+ { write_exp_elt_opcode (UNOP_IND); }
+
+exp : '-'
+ { number_sign = -1; }
+ exp %prec UNARY
+ { number_sign = 1;
+ write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '+' exp %prec UNARY
+ { write_exp_elt_opcode(UNOP_PLUS); }
+ ;
+
+exp : not_exp exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+not_exp : NOT
+ | '~'
+ ;
+
+exp : CAP '(' exp ')'
+ { write_exp_elt_opcode (UNOP_CAP); }
+ ;
+
+exp : ORD '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ORD); }
+ ;
+
+exp : ABS '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ABS); }
+ ;
+
+exp : HIGH '(' exp ')'
+ { write_exp_elt_opcode (UNOP_HIGH); }
+ ;
+
+exp : MIN_FUNC '(' type ')'
+ { write_exp_elt_opcode (UNOP_MIN);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (UNOP_MIN); }
+ ;
+
+exp : MAX_FUNC '(' type ')'
+ { write_exp_elt_opcode (UNOP_MAX);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (UNOP_MIN); }
+ ;
+
+exp : FLOAT_FUNC '(' exp ')'
+ { write_exp_elt_opcode (UNOP_FLOAT); }
+ ;
+
+exp : VAL '(' type ',' exp ')'
+ { write_exp_elt_opcode (BINOP_VAL);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (BINOP_VAL); }
+ ;
+
+exp : CHR '(' exp ')'
+ { write_exp_elt_opcode (UNOP_CHR); }
+ ;
+
+exp : ODD '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ODD); }
+ ;
+
+exp : TRUNC '(' exp ')'
+ { write_exp_elt_opcode (UNOP_TRUNC); }
+ ;
+
+exp : SIZE exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ ;
+
+
+exp : INC '(' exp ')'
+ { write_exp_elt_opcode(UNOP_PREINCREMENT); }
+ ;
+
+exp : INC '(' exp ',' exp ')'
+ { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_ADD);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : DEC '(' exp ')'
+ { write_exp_elt_opcode(UNOP_PREDECREMENT);}
+ ;
+
+exp : DEC '(' exp ',' exp ')'
+ { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_SUB);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : exp DOT NAME
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+exp : set
+ ;
+
+exp : exp IN set
+ { error("Sets are not implemented.");}
+ ;
+
+exp : INCL '(' exp ',' exp ')'
+ { error("Sets are not implemented.");}
+ ;
+
+exp : EXCL '(' exp ',' exp ')'
+ { error("Sets are not implemented.");}
+
+set : '{' arglist '}'
+ { error("Sets are not implemented.");}
+ | type '{' arglist '}'
+ { error("Sets are not implemented.");}
+ ;
+
+
+/* Modula-2 array subscript notation [a,b,c...] */
+exp : exp '['
+ /* This function just saves the number of arguments
+ that follow in the list. It is *not* specific to
+ function types */
+ { start_arglist(); }
+ non_empty_arglist ']' %prec DOT
+ { write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { start_arglist (); }
+ arglist ')' %prec DOT
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+non_empty_arglist
+ : exp
+ { arglist_len = 1; }
+ ;
+
+non_empty_arglist
+ : non_empty_arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+/* GDB construct */
+exp : '{' type '}' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ ;
+
+exp : type '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (UNOP_CAST); }
+ ;
+
+exp : '(' exp ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. Note that some
+ of these operators are overloaded! (ie. sets) */
+
+/* GDB construct */
+exp : exp '@' exp
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp DIV exp
+ { write_exp_elt_opcode (BINOP_INTDIV); }
+ ;
+
+exp : exp MOD exp
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '-' exp
+ { write_exp_elt_opcode (BINOP_SUB); }
+ ;
+
+exp : exp '=' exp
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ | exp '#' exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ ;
+
+exp : exp LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp GEQ exp
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ ;
+
+exp : exp '<' exp
+ { write_exp_elt_opcode (BINOP_LESS); }
+ ;
+
+exp : exp '>' exp
+ { write_exp_elt_opcode (BINOP_GTR); }
+ ;
+
+exp : exp LOGICAL_AND exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OROR exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp ASSIGN exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+
+/* Constants */
+
+exp : M2_TRUE
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL); }
+ ;
+
+exp : M2_FALSE
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL); }
+ ;
+
+exp : INT
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_int);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : UINT
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_card);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+exp : CHAR
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_char);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+
+exp : FLOAT
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_m2_real);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE); }
+ ;
+
+exp : variable
+ ;
+
+/* The GDB internal variable $$, et al. */
+exp : LAST
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LAST); }
+ ;
+
+exp : REGNAME
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_REGISTER); }
+ ;
+
+exp : SIZE '(' type ')' %prec UNARY
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : STRING
+ { write_exp_elt_opcode (OP_M2_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_M2_STRING); }
+ ;
+
+/* This will be used for extensions later. Like adding modules. */
+block : fblock
+ { $$ = SYMBOL_BLOCK_VALUE($1); }
+ ;
+
+fblock : BLOCKNAME
+ { struct symbol *sym
+ = lookup_symbol (copy_name ($1), expression_context_block,
+ VAR_NAMESPACE, 0, NULL);
+ $$ = sym;}
+ ;
+
+
+/* GDB scope operator */
+fblock : block COLONCOLON BLOCKNAME
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, 0, NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name ($3));
+ $$ = tem;
+ }
+ ;
+
+/* Useful for assigning to PROCEDURE variables */
+variable: fblock
+ { write_exp_elt_opcode(OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+/* GDB internal ($foo) variable */
+variable: INTERNAL_VAR
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+ ;
+
+/* GDB scope operator */
+variable: block COLONCOLON NAME
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, 0, NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name ($3));
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* block_found is set by lookup_symbol. */
+ write_exp_elt_block (block_found);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+/* Base case for variables. */
+variable: NAME
+ { struct symbol *sym;
+ int is_a_field_of_this;
+
+ sym = lookup_symbol (copy_name ($1),
+ expression_context_block,
+ VAR_NAMESPACE,
+ &is_a_field_of_this,
+ NULL);
+ if (sym)
+ {
+ if (symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* We want to use the selected frame, not
+ another more inner frame which happens to
+ be in the same block. */
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ register char *arg = copy_name ($1);
+
+ msymbol = lookup_minimal_symbol (arg,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.",
+ copy_name ($1));
+ }
+ }
+ ;
+
+type
+ : TYPENAME
+ { $$ = lookup_typename (copy_name ($1),
+ expression_context_block, 0); }
+
+ ;
+
+%%
+
+#if 0 /* FIXME! */
+int
+overflow(a,b)
+ long a,b;
+{
+ return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a;
+}
+
+int
+uoverflow(a,b)
+ unsigned long a,b;
+{
+ return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a;
+}
+#endif /* FIXME */
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register LONGEST n = 0;
+ register LONGEST prevn = 0;
+ register int c,i,ischar=0;
+ register int base = input_radix;
+ register int len = olen;
+ int unsigned_p = number_sign == 1 ? 1 : 0;
+
+ if(p[len-1] == 'H')
+ {
+ base = 16;
+ len--;
+ }
+ else if(p[len-1] == 'C' || p[len-1] == 'B')
+ {
+ base = 8;
+ ischar = p[len-1] == 'C';
+ len--;
+ }
+
+ /* Scan the number */
+ for (c = 0; c < len; c++)
+ {
+ if (p[c] == '.' && base == 10)
+ {
+ /* It's a float since it contains a point. */
+ yylval.dval = atof (p);
+ lexptr += len;
+ return FLOAT;
+ }
+ if (p[c] == '.' && base != 10)
+ error("Floating point numbers must be base 10.");
+ if (base == 10 && (p[c] < '0' || p[c] > '9'))
+ error("Invalid digit \'%c\' in number.",p[c]);
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ n *= base;
+ if( base == 8 && (c == '8' || c == '9'))
+ error("Invalid digit \'%c\' in octal number.",c);
+ if (c >= '0' && c <= '9')
+ i = c - '0';
+ else
+ {
+ if (base == 16 && c >= 'A' && c <= 'F')
+ i = c - 'A' + 10;
+ else
+ return ERROR;
+ }
+ n+=i;
+ if(i >= base)
+ return ERROR;
+ if(!unsigned_p && number_sign == 1 && (prevn >= n))
+ unsigned_p=1; /* Try something unsigned */
+ /* Don't do the range check if n==i and i==0, since that special
+ case will give an overflow error. */
+ if(RANGE_CHECK && n!=i && i)
+ {
+ if((unsigned_p && (unsigned)prevn >= (unsigned)n) ||
+ ((!unsigned_p && number_sign==-1) && -prevn <= -n))
+ range_error("Overflow on numeric constant.");
+ }
+ prevn=n;
+ }
+
+ lexptr = p;
+ if(*p == 'B' || *p == 'C' || *p == 'H')
+ lexptr++; /* Advance past B,C or H */
+
+ if (ischar)
+ {
+ yylval.ulval = n;
+ return CHAR;
+ }
+ else if ( unsigned_p && number_sign == 1)
+ {
+ yylval.ulval = n;
+ return UINT;
+ }
+ else if((unsigned_p && (n<0))) {
+ range_error("Overflow on numeric constant -- number too large.");
+ /* But, this can return if range_check == range_warn. */
+ }
+ yylval.lval = n;
+ return INT;
+}
+
+
+/* Some tokens */
+
+static struct
+{
+ char name[2];
+ int token;
+} tokentab2[] =
+{
+ { {'<', '>'}, NOTEQUAL },
+ { {':', '='}, ASSIGN },
+ { {'<', '='}, LEQ },
+ { {'>', '='}, GEQ },
+ { {':', ':'}, COLONCOLON },
+
+};
+
+/* Some specific keywords */
+
+struct keyword {
+ char keyw[10];
+ int token;
+};
+
+static struct keyword keytab[] =
+{
+ {"OR" , OROR },
+ {"IN", IN },/* Note space after IN */
+ {"AND", LOGICAL_AND},
+ {"ABS", ABS },
+ {"CHR", CHR },
+ {"DEC", DEC },
+ {"NOT", NOT },
+ {"DIV", DIV },
+ {"INC", INC },
+ {"MAX", MAX_FUNC },
+ {"MIN", MIN_FUNC },
+ {"MOD", MOD },
+ {"ODD", ODD },
+ {"CAP", CAP },
+ {"ORD", ORD },
+ {"VAL", VAL },
+ {"EXCL", EXCL },
+ {"HIGH", HIGH },
+ {"INCL", INCL },
+ {"SIZE", SIZE },
+ {"FLOAT", FLOAT_FUNC },
+ {"TRUNC", TRUNC },
+};
+
+
+/* Read one token, getting characters through lexptr. */
+
+/* This is where we will check to make sure that the language and the operators used are
+ compatible */
+
+static int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register int i;
+ register char *tokstart;
+ register char quote;
+
+ retry:
+
+ tokstart = lexptr;
+
+
+ /* See if it is a special token of length 2 */
+ for( i = 0 ; i < sizeof tokentab2 / sizeof tokentab2[0] ; i++)
+ if(STREQN(tokentab2[i].name, tokstart, 2))
+ {
+ lexptr += 2;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '(':
+ paren_depth++;
+ lexptr++;
+ return c;
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return c;
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return c;
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] >= '0' && lexptr[1] <= '9')
+ break; /* Falls into number code. */
+ else
+ {
+ lexptr++;
+ return DOT;
+ }
+
+/* These are character tokens that appear as-is in the YACC grammar */
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '^':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '=':
+ case '{':
+ case '}':
+ case '#':
+ case '@':
+ case '~':
+ case '&':
+ lexptr++;
+ return c;
+
+ case '\'' :
+ case '"':
+ quote = c;
+ for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++)
+ if (c == '\\')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ c = tokstart[++namelen];
+ }
+ }
+ if(c != quote)
+ error("Unterminated string or character constant.");
+ yylval.sval.ptr = tokstart + 1;
+ yylval.sval.length = namelen - 1;
+ lexptr += namelen + 1;
+
+ if(namelen == 2) /* Single character */
+ {
+ yylval.ulval = tokstart[1];
+ return CHAR;
+ }
+ else
+ return STRING;
+ }
+
+ /* Is it a number? */
+ /* Note: We have already dealt with the case of the token '.'.
+ See case '.' above. */
+ if ((c >= '0' && c <= '9'))
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0;
+ register char *p = tokstart;
+ int toktype;
+
+ for (++p ;; ++p)
+ {
+ if (!got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ else if (!got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ else if ((*p < '0' || *p > '9') &&
+ (*p < 'A' || *p > 'F') &&
+ (*p != 'H')) /* Modula-2 hexadecimal number */
+ break;
+ }
+ toktype = parse_number (p - tokstart);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ if (!(c == '_' || c == '$'
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+ c = tokstart[++namelen])
+ ;
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+ and $$digits (equivalent to $<-digits> if you could type that).
+ Make token type LAST, and put the number (the digits) in yylval. */
+
+ if (*tokstart == '$')
+ {
+ register int negate = 0;
+ c = 1;
+ /* Double dollar means negate the number and add -1 as well.
+ Thus $$ alone means -1. */
+ if (namelen >= 2 && tokstart[1] == '$')
+ {
+ negate = 1;
+ c = 2;
+ }
+ if (c == namelen)
+ {
+ /* Just dollars (one or two) */
+ yylval.lval = - negate;
+ return LAST;
+ }
+ /* Is the rest of the token digits? */
+ for (; c < namelen; c++)
+ if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
+ break;
+ if (c == namelen)
+ {
+ yylval.lval = atoi (tokstart + 1 + negate);
+ if (negate)
+ yylval.lval = - yylval.lval;
+ return LAST;
+ }
+ }
+
+ /* Handle tokens that refer to machine registers:
+ $ followed by a register name. */
+
+ if (*tokstart == '$') {
+ for (c = 0; c < NUM_REGS; c++)
+ if (namelen - 1 == strlen (reg_names[c])
+ && STREQN (tokstart + 1, reg_names[c], namelen - 1))
+ {
+ yylval.lval = c;
+ return REGNAME;
+ }
+ for (c = 0; c < num_std_regs; c++)
+ if (namelen - 1 == strlen (std_regs[c].name)
+ && STREQN (tokstart + 1, std_regs[c].name, namelen - 1))
+ {
+ yylval.lval = std_regs[c].regnum;
+ return REGNAME;
+ }
+ }
+
+
+ /* Lookup special keywords */
+ for(i = 0 ; i < sizeof(keytab) / sizeof(keytab[0]) ; i++)
+ if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen))
+ return keytab[i].token;
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ /* Any other names starting in $ are debugger internal variables. */
+
+ if (*tokstart == '$')
+ {
+ yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1);
+ return INTERNAL_VAR;
+ }
+
+
+ /* Use token-type BLOCKNAME for symbols that happen to be defined as
+ functions. If this is not so, then ...
+ Use token-type TYPENAME for symbols that happen to be defined
+ currently as names of types; NAME for other symbols.
+ The caller is not constrained to care about the distinction. */
+ {
+
+
+ char *tmp = copy_name (yylval.sval);
+ struct symbol *sym;
+
+ if (lookup_partial_symtab (tmp))
+ return BLOCKNAME;
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, 0, NULL);
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ return BLOCKNAME;
+ if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
+ return TYPENAME;
+
+ if(sym)
+ {
+ switch(sym->class)
+ {
+ case LOC_STATIC:
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ return NAME;
+
+ case LOC_TYPEDEF:
+ return TYPENAME;
+
+ case LOC_BLOCK:
+ return BLOCKNAME;
+
+ case LOC_UNDEF:
+ error("internal: Undefined class in m2lex()");
+
+ case LOC_LABEL:
+ error("internal: Unforseen case in m2lex()");
+ }
+ }
+ else
+ {
+ /* Built-in BOOLEAN type. This is sort of a hack. */
+ if(STREQN(tokstart,"TRUE",4))
+ {
+ yylval.ulval = 1;
+ return M2_TRUE;
+ }
+ else if(STREQN(tokstart,"FALSE",5))
+ {
+ yylval.ulval = 0;
+ return M2_FALSE;
+ }
+ }
+
+ /* Must be another type of name... */
+ return NAME;
+ }
+}
+
+#if 0 /* Unused */
+static char *
+make_qualname(mod,ident)
+ char *mod, *ident;
+{
+ char *new = malloc(strlen(mod)+strlen(ident)+2);
+
+ strcpy(new,mod);
+ strcat(new,".");
+ strcat(new,ident);
+ return new;
+}
+#endif /* 0 */
+
+void
+yyerror(msg)
+ char *msg; /* unused */
+{
+ printf("Parsing: %s\n",lexptr);
+ if (yychar < 256)
+ error("Invalid syntax in expression near character '%c'.",yychar);
+ else
+ error("Invalid syntax in expression");
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.c b/gnu/usr.bin/gdb/gdb/m2-lang.c
new file mode 100644
index 000000000000..0b678fd9c3c1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-lang.c
@@ -0,0 +1,457 @@
+/* Modula 2 language support routines for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "m2-lang.h"
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific.
+ FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version.
+ */
+
+static void
+emit_char (c, stream, quoter)
+ register int c;
+ FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+/* FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version. */
+
+static void
+m2_printchar (c, stream)
+ int c;
+ FILE *stream;
+{
+ fputs_filtered ("'", stream);
+ emit_char (c, stream, '\'');
+ fputs_filtered ("'", stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version. */
+
+static void
+m2_printstr (stream, string, length, force_ellipses)
+ FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+ extern int inspect_it;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stdout);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ fputs_filtered (", ", stream);
+ need_comma = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ m2_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ if (!in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ in_quotes = 1;
+ }
+ emit_char (string[i], stream, '"');
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ }
+
+ if (force_ellipses || i < length)
+ fputs_filtered ("...", stream);
+}
+
+/* FIXME: This is a copy of c_create_fundamental_type(), before
+ all the non-C types were stripped from it. Needs to be fixed
+ by an experienced Modula programmer. */
+
+static struct type *
+m2_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "<?type?>", objfile);
+ warning ("internal error: no Modula fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ type = init_type (TYPE_CODE_VOID,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "void", objfile);
+ break;
+ case FT_BOOLEAN:
+ type = init_type (TYPE_CODE_BOOL,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "boolean", objfile);
+ break;
+ case FT_STRING:
+ type = init_type (TYPE_CODE_STRING,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "string", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "char", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "signed char", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
+ break;
+ case FT_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "short", objfile); /* FIXME-fnf */
+ break;
+ case FT_UNSIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
+ break;
+ case FT_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile);
+ break;
+ case FT_SIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "int", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
+ break;
+ case FT_FIXED_DECIMAL:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "fixed decimal", objfile);
+ break;
+ case FT_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile);
+ break;
+ case FT_SIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "long", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
+ break;
+ case FT_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long long", objfile);
+ break;
+ case FT_SIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_SIGNED, "signed long long", objfile);
+ break;
+ case FT_UNSIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "double", objfile);
+ break;
+ case FT_FLOAT_DECIMAL:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "floating decimal", objfile);
+ break;
+ case FT_EXT_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long double", objfile);
+ break;
+ case FT_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "complex", objfile);
+ break;
+ case FT_DBL_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "double complex", objfile);
+ break;
+ case FT_EXT_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "long double complex", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table of operators and their precedences for printing expressions. */
+
+static const struct op_print m2_op_print_tab[] = {
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"+", UNOP_PLUS, PREC_PREFIX, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"DIV", BINOP_INTDIV, PREC_MUL, 0},
+ {"MOD", BINOP_REM, PREC_MUL, 0},
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"=", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {"^", UNOP_IND, PREC_PREFIX, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {NULL, 0, 0, 0}
+};
+
+/* The built-in types of Modula-2. */
+
+struct type *builtin_type_m2_char;
+struct type *builtin_type_m2_int;
+struct type *builtin_type_m2_card;
+struct type *builtin_type_m2_real;
+struct type *builtin_type_m2_bool;
+
+struct type ** const (m2_builtin_types[]) =
+{
+ &builtin_type_m2_char,
+ &builtin_type_m2_int,
+ &builtin_type_m2_card,
+ &builtin_type_m2_real,
+ &builtin_type_m2_bool,
+ 0
+};
+
+const struct language_defn m2_language_defn = {
+ "modula-2",
+ language_m2,
+ m2_builtin_types,
+ range_check_on,
+ type_check_on,
+ m2_parse, /* parser */
+ m2_error, /* parser error function */
+ m2_printchar, /* Print character constant */
+ m2_printstr, /* function to print string constant */
+ m2_create_fundamental_type, /* Create fundamental type in this language */
+ m2_print_type, /* Print a type using appropriate syntax */
+ m2_val_print, /* Print a value using appropriate syntax */
+ &builtin_type_m2_int, /* longest signed integral type */
+ &builtin_type_m2_card, /* longest unsigned integral type */
+ &builtin_type_m2_real, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"%loB", "", "o", "B"}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0%lXH", "0", "X", "H"}, /* Hex format info */
+ m2_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialization for Modula-2 */
+
+void
+_initialize_m2_language ()
+{
+ /* Modula-2 "pervasive" types. NOTE: these can be redefined!!! */
+ builtin_type_m2_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "INTEGER", (struct objfile *) NULL);
+ builtin_type_m2_card =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CARDINAL", (struct objfile *) NULL);
+ builtin_type_m2_real =
+ init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "REAL", (struct objfile *) NULL);
+ builtin_type_m2_char =
+ init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CHAR", (struct objfile *) NULL);
+ builtin_type_m2_bool =
+ init_type (TYPE_CODE_BOOL, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "BOOLEAN", (struct objfile *) NULL);
+
+ TYPE_NFIELDS(builtin_type_m2_bool) = 2;
+ TYPE_FIELDS(builtin_type_m2_bool) =
+ (struct field *) xmalloc (sizeof (struct field) * 2);
+ TYPE_FIELD_BITPOS(builtin_type_m2_bool,0) = 0;
+ TYPE_FIELD_NAME(builtin_type_m2_bool,0) = (char *)xmalloc(6);
+ strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,0),"FALSE");
+ TYPE_FIELD_BITPOS(builtin_type_m2_bool,1) = 1;
+ TYPE_FIELD_NAME(builtin_type_m2_bool,1) = (char *)xmalloc(5);
+ strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,1),"TRUE");
+
+ add_language (&m2_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.h b/gnu/usr.bin/gdb/gdb/m2-lang.h
new file mode 100644
index 000000000000..4bc57f5c2943
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-lang.h
@@ -0,0 +1,31 @@
+/* Modula 2 language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern int
+m2_parse PARAMS ((void)); /* Defined in m2-exp.y */
+
+extern void
+m2_error PARAMS ((char *)); /* Defined in m2-exp.y */
+
+extern void /* Defined in m2-typeprint.c */
+m2_print_type PARAMS ((struct type *, char *, FILE *, int, int));
+
+extern int
+m2_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ int, enum val_prettyprint));
diff --git a/gnu/usr.bin/gdb/gdb/m2-typeprint.c b/gnu/usr.bin/gdb/gdb/m2-typeprint.c
new file mode 100644
index 000000000000..ef66a80a8b90
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-typeprint.c
@@ -0,0 +1,49 @@
+/* Support for printing Modula 2 types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "m2-lang.h"
+
+#include <string.h>
+#include <errno.h>
+
+void
+m2_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ extern void c_print_type PARAMS ((struct type *, char *, FILE *, int, int));
+
+ c_print_type (type, varstring, stream, show, level); /* FIXME */
+}
diff --git a/gnu/usr.bin/gdb/gdb/m2-valprint.c b/gnu/usr.bin/gdb/gdb/m2-valprint.c
new file mode 100644
index 000000000000..fc17ea50c9a3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-valprint.c
@@ -0,0 +1,45 @@
+/* Support for printing Modula 2 values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "valprint.h"
+
+/* FIXME: For now, just explicitly declare c_val_print and use it instead */
+
+int
+m2_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ extern int
+ c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ int, enum val_prettyprint));
+ return (c_val_print (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty));
+}
diff --git a/gnu/usr.bin/gdb/gdb/main.c b/gnu/usr.bin/gdb/gdb/main.c
new file mode 100644
index 000000000000..deaf6240ef98
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/main.c
@@ -0,0 +1,2799 @@
+/* Top level `main' program for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "call-cmds.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "signals.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "terminal.h" /* For job_control. */
+
+#include "getopt.h"
+
+/* readline include files */
+#include "readline.h"
+#include "history.h"
+
+/* readline defines this. */
+#undef savestring
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int original_stack_limit;
+#endif
+
+/* Prototypes for local functions */
+
+static char *
+symbol_completion_function PARAMS ((char *, int));
+
+static void
+command_loop PARAMS ((void));
+
+static void
+command_loop_marker PARAMS ((int));
+
+static void
+print_gdb_version PARAMS ((FILE *));
+
+static void
+quit_command PARAMS ((char *, int));
+
+static void
+init_main PARAMS ((void));
+
+static void
+init_history PARAMS ((void));
+
+static void
+init_cmd_lists PARAMS ((void));
+
+static void
+float_handler PARAMS ((int));
+
+static void
+source_command PARAMS ((char *, int));
+
+static void cd_command PARAMS ((char *, int));
+
+static void
+print_gnu_advertisement PARAMS ((void));
+
+static void
+init_signals PARAMS ((void));
+
+static void
+read_command_file PARAMS ((FILE *));
+
+static void
+set_verbose PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_history PARAMS ((char *, int));
+
+static void
+set_history PARAMS ((char *, int));
+
+static void
+set_history_size_command PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_commands PARAMS ((char *, int));
+
+static void
+echo_command PARAMS ((char *, int));
+
+static void
+pwd_command PARAMS ((char *, int));
+
+static void
+show_version PARAMS ((char *, int));
+
+static void
+document_command PARAMS ((char *, int));
+
+static void
+define_command PARAMS ((char *, int));
+
+static void
+validate_comname PARAMS ((char *));
+
+static void
+help_command PARAMS ((char *, int));
+
+static void
+show_command PARAMS ((char *, int));
+
+static void
+info_command PARAMS ((char *, int));
+
+static void
+do_nothing PARAMS ((int));
+
+static int
+quit_cover PARAMS ((char *));
+
+static void
+disconnect PARAMS ((int));
+
+static void
+source_cleanup PARAMS ((FILE *));
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+/* Initialization file name for gdb. This is overridden in some configs. */
+
+#ifndef GDBINIT_FILENAME
+#define GDBINIT_FILENAME ".gdbinit"
+#endif
+static char gdbinit[] = GDBINIT_FILENAME;
+static int inhibit_gdbinit = 0;
+
+#define ALL_CLEANUPS ((struct cleanup *)0)
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/* Canonical host name as a string. */
+
+extern char *host_canonical;
+
+/* Canonical target name as a string. */
+
+extern char *target_canonical;
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Message to be printed before the warning message, when a warning occurs. */
+
+extern char *warning_pre_print;
+
+extern char lang_frame_mismatch_warn[]; /* language.c */
+
+/* Flag for whether we want all the "from_tty" gubbish printed. */
+
+int caution = 1; /* Default is yes, sigh. */
+
+/*
+ * Define all cmd_list_element's
+ */
+
+/* Chain containing all defined commands. */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+struct cmd_list_element *setlist;
+
+/* Chain containing all defined unset subcommands */
+
+struct cmd_list_element *unsetlist;
+
+/* Chain containing all defined show subcommands. */
+
+struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\". */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\". */
+
+struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+struct cmd_list_element *unsethistlist;
+
+/* Chain containing all defined maintenance subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenancelist;
+#endif
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceinfolist;
+#endif
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceprintlist;
+#endif
+
+struct cmd_list_element *setprintlist;
+
+struct cmd_list_element *showprintlist;
+
+struct cmd_list_element *setchecklist;
+
+struct cmd_list_element *showchecklist;
+
+/* stdio stream that command input is being read from. Set to stdin normally.
+ Set by source_command to the file we are sourcing. Set to NULL if we are
+ executing a user-defined command. */
+
+FILE *instream;
+
+/* Current working directory. */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually). */
+static char dirbuf[1024];
+
+/* Function to call before reading a command, if nonzero.
+ The function receives two args: an input stream,
+ and a prompt string. */
+
+void (*window_hook) PARAMS ((FILE *, char *));
+
+extern int mapped_symbol_files;
+extern int readnow_symbol_files;
+
+int epoch_interface;
+int xgdb_verbose;
+
+/* gdb prints this when reading a command interactively */
+static char *prompt;
+
+/* Buffer used for reading command lines, and the size
+ allocated for it so far. */
+
+char *line;
+int linesize = 100;
+
+/* Baud rate specified for talking to serial target systems. Default
+ is left as -1, so targets can choose their own defaults. */
+
+int baud_rate = -1;
+
+/* Non-zero tells remote* modules to output debugging info. */
+
+int remote_debug = 0;
+
+/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
+
+#ifndef STOP_SIGNAL
+#ifdef SIGTSTP
+#define STOP_SIGNAL SIGTSTP
+static void stop_sig PARAMS ((int));
+#endif
+#endif
+
+/* Some System V have job control but not sigsetmask(). */
+#if !defined (HAVE_SIGSETMASK)
+#define HAVE_SIGSETMASK !defined (USG)
+#endif
+
+#if 0 == (HAVE_SIGSETMASK)
+#define sigsetmask(n)
+#endif
+
+/* Where to go for return_to_top_level (RETURN_ERROR). */
+static jmp_buf error_return;
+/* Where to go for return_to_top_level (RETURN_QUIT). */
+static jmp_buf quit_return;
+
+/* Temporary variable for SET_TOP_LEVEL. */
+static int top_level_val;
+
+/* Do a setjmp on error_return and quit_return. catch_errors is
+ generally a cleaner way to do this, but main() would look pretty
+ ugly if it had to use catch_errors each time. */
+
+#define SET_TOP_LEVEL() \
+ (((top_level_val = setjmp (error_return)) \
+ ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \
+ , top_level_val)
+
+/* Return for reason REASON. This generally gets back to the command
+ loop, but can be caught via catch_errors. */
+
+NORETURN void
+return_to_top_level (reason)
+ enum return_reason reason;
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+
+ /* Perhaps it would be cleaner to do this via the cleanup chain (not sure
+ I can think of a reason why that is vital, though). */
+ bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */
+
+ disable_current_display ();
+ do_cleanups (ALL_CLEANUPS);
+ (NORETURN void) longjmp
+ (reason == RETURN_ERROR ? error_return : quit_return, 1);
+}
+
+/* Call FUNC with arg ARGS, catching any errors. If there is no
+ error, return the value returned by FUNC. If there is an error,
+ print ERRSTRING, print the specific error message, then return
+ zero.
+
+ Must not be called with immediate_quit in effect (bad things might
+ happen, say we got a signal in the middle of a memcpy to quit_return).
+ This is an OK restriction; with very few exceptions immediate_quit can
+ be replaced by judicious use of QUIT.
+
+ MASK specifies what to catch; it is normally set to
+ RETURN_MASK_ALL, if for no other reason than that the code which
+ calls catch_errors might not be set up to deal with a quit which
+ isn't caught. But if the code can deal with it, it generally
+ should be RETURN_MASK_ERROR, unless for some reason it is more
+ useful to abort only the portion of the operation inside the
+ catch_errors. Note that quit should return to the command line
+ fairly quickly, even if some further processing is being done. */
+
+int
+catch_errors (func, args, errstring, mask)
+ int (*func) PARAMS ((char *));
+ PTR args;
+ char *errstring;
+ return_mask mask;
+{
+ jmp_buf saved_error;
+ jmp_buf saved_quit;
+ jmp_buf tmp_jmp;
+ int val;
+ struct cleanup *saved_cleanup_chain;
+ char *saved_error_pre_print;
+
+ saved_cleanup_chain = save_cleanups ();
+ saved_error_pre_print = error_pre_print;
+
+ if (mask & RETURN_MASK_ERROR)
+ memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (saved_quit, quit_return, sizeof (jmp_buf));
+ error_pre_print = errstring;
+
+ if (setjmp (tmp_jmp) == 0)
+ {
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
+ val = (*func) (args);
+ }
+ else
+ val = 0;
+
+ restore_cleanups (saved_cleanup_chain);
+
+ error_pre_print = saved_error_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, saved_error, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, saved_quit, sizeof (jmp_buf));
+ return val;
+}
+
+/* Handler for SIGHUP. */
+
+static void
+disconnect (signo)
+int signo;
+{
+ catch_errors (quit_cover, NULL,
+ "Could not kill the program being debugged", RETURN_MASK_ALL);
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+
+/* Just a little helper function for disconnect(). */
+
+static int
+quit_cover (s)
+char *s;
+{
+ caution = 0; /* Throw caution to the wind -- we're exiting.
+ This prevents asking the user dumb questions. */
+ quit_command((char *)0, 0);
+ return 0;
+}
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command). */
+
+static void
+source_cleanup (stream)
+ FILE *stream;
+{
+ /* Restore the previous input stream. */
+ instream = stream;
+}
+
+/* Read commands from STREAM. */
+static void
+read_command_file (stream)
+ FILE *stream;
+{
+ struct cleanup *cleanups;
+
+ cleanups = make_cleanup (source_cleanup, instream);
+ instream = stream;
+ command_loop ();
+ do_cleanups (cleanups);
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int count;
+ static int quiet = 0;
+ static int batch = 0;
+
+ /* Pointers to various arguments from command line. */
+ char *symarg = NULL;
+ char *execarg = NULL;
+ char *corearg = NULL;
+ char *cdarg = NULL;
+ char *ttyarg = NULL;
+
+ /* These are static so that we can take their address in an initializer. */
+ static int print_help;
+ static int print_version;
+
+ /* Pointers to all arguments of --command option. */
+ char **cmdarg;
+ /* Allocated size of cmdarg. */
+ int cmdsize;
+ /* Number of elements of cmdarg used. */
+ int ncmd;
+
+ /* Indices of all arguments of --directory option. */
+ char **dirarg;
+ /* Allocated size. */
+ int dirsize;
+ /* Number of elements used. */
+ int ndir;
+
+ struct stat homebuf, cwdbuf;
+ char *homedir, *homeinit;
+
+ register int i;
+
+ /* This needs to happen before the first use of malloc. */
+ init_malloc ((PTR) NULL);
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+ i = (int) &count & 0x3;
+ if (i != 0)
+ alloca (4 - i);
+#endif
+
+ /* If error() is called from initialization code, just exit */
+ if (SET_TOP_LEVEL ()) {
+ exit(1);
+ }
+
+ cmdsize = 1;
+ cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg));
+ ncmd = 0;
+ dirsize = 1;
+ dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
+ ndir = 0;
+
+ quit_flag = 0;
+ line = (char *) xmalloc (linesize);
+ line[0] = '\0'; /* Terminate saved (now empty) cmd line */
+ instream = stdin;
+
+ getcwd (dirbuf, sizeof (dirbuf));
+ current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ original_stack_limit = rlim.rlim_cur;
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* Parse arguments and options. */
+ {
+ int c;
+ /* When var field is 0, use flag field to record the equivalent
+ short option (or arbitrary numbers starting at 10 for those
+ with no equivalent). */
+ static struct option long_options[] =
+ {
+ {"readnow", no_argument, &readnow_symbol_files, 1},
+ {"r", no_argument, &readnow_symbol_files, 1},
+ {"mapped", no_argument, &mapped_symbol_files, 1},
+ {"m", no_argument, &mapped_symbol_files, 1},
+ {"quiet", no_argument, &quiet, 1},
+ {"q", no_argument, &quiet, 1},
+ {"silent", no_argument, &quiet, 1},
+ {"nx", no_argument, &inhibit_gdbinit, 1},
+ {"n", no_argument, &inhibit_gdbinit, 1},
+ {"batch", no_argument, &batch, 1},
+ {"epoch", no_argument, &epoch_interface, 1},
+ {"fullname", no_argument, &frame_file_full_name, 1},
+ {"f", no_argument, &frame_file_full_name, 1},
+ {"help", no_argument, &print_help, 1},
+ {"se", required_argument, 0, 10},
+ {"symbols", required_argument, 0, 's'},
+ {"s", required_argument, 0, 's'},
+ {"exec", required_argument, 0, 'e'},
+ {"e", required_argument, 0, 'e'},
+ {"core", required_argument, 0, 'c'},
+ {"c", required_argument, 0, 'c'},
+ {"command", required_argument, 0, 'x'},
+ {"version", no_argument, &print_version, 1},
+ {"x", required_argument, 0, 'x'},
+ {"directory", required_argument, 0, 'd'},
+ {"cd", required_argument, 0, 11},
+ {"tty", required_argument, 0, 't'},
+ {"baud", required_argument, 0, 'b'},
+ {"b", required_argument, 0, 'b'},
+/* Allow machine descriptions to add more options... */
+#ifdef ADDITIONAL_OPTIONS
+ ADDITIONAL_OPTIONS
+#endif
+ {0, no_argument, 0, 0},
+ };
+
+ while (1)
+ {
+ int option_index;
+
+ c = getopt_long_only (argc, argv, "",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ /* Long option that takes an argument. */
+ if (c == 0 && long_options[option_index].flag == 0)
+ c = long_options[option_index].val;
+
+ switch (c)
+ {
+ case 0:
+ /* Long option that just sets a flag. */
+ break;
+ case 10:
+ symarg = optarg;
+ execarg = optarg;
+ break;
+ case 11:
+ cdarg = optarg;
+ break;
+ case 's':
+ symarg = optarg;
+ break;
+ case 'e':
+ execarg = optarg;
+ break;
+ case 'c':
+ corearg = optarg;
+ break;
+ case 'x':
+ cmdarg[ncmd++] = optarg;
+ if (ncmd >= cmdsize)
+ {
+ cmdsize *= 2;
+ cmdarg = (char **) xrealloc ((char *)cmdarg,
+ cmdsize * sizeof (*cmdarg));
+ }
+ break;
+ case 'd':
+ dirarg[ndir++] = optarg;
+ if (ndir >= dirsize)
+ {
+ dirsize *= 2;
+ dirarg = (char **) xrealloc ((char *)dirarg,
+ dirsize * sizeof (*dirarg));
+ }
+ break;
+ case 't':
+ ttyarg = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'b':
+ {
+ int i;
+ char *p;
+
+ i = strtol (optarg, &p, 0);
+ if (i == 0 && p == optarg)
+ warning ("Could not set baud rate to `%s'.\n", optarg);
+ else
+ baud_rate = i;
+ }
+ break;
+
+#ifdef ADDITIONAL_OPTION_CASES
+ ADDITIONAL_OPTION_CASES
+#endif
+ case '?':
+ fprintf (stderr,
+ "Use `%s --help' for a complete list of options.\n",
+ argv[0]);
+ exit (1);
+ }
+ }
+
+ /* OK, that's all the options. The other arguments are filenames. */
+ count = 0;
+ for (; optind < argc; optind++)
+ switch (++count)
+ {
+ case 1:
+ symarg = argv[optind];
+ execarg = argv[optind];
+ break;
+ case 2:
+ corearg = argv[optind];
+ break;
+ case 3:
+ fprintf (stderr,
+ "Excess command line arguments ignored. (%s%s)\n",
+ argv[optind], (optind == argc - 1) ? "" : " ...");
+ break;
+ }
+ if (batch)
+ quiet = 1;
+ }
+
+ /* Run the init function of each source file */
+
+ init_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ init_main (); /* But that omits this file! Do it now */
+ init_signals ();
+
+ /* Do these (and anything which might call wrap_here or *_filtered)
+ after initialize_all_files. */
+ if (print_version)
+ {
+ print_gdb_version (stdout);
+ wrap_here ("");
+ printf_filtered ("\n");
+ exit (0);
+ }
+
+ if (print_help)
+ {
+ /* --version is intentionally not documented here, because we
+ are printing the version here, and the help is long enough
+ already. */
+
+ print_gdb_version (stdout);
+ /* Make sure the output gets printed. */
+ wrap_here ("");
+ printf_filtered ("\n");
+
+ /* But don't use *_filtered here. We don't want to prompt for continue
+ no matter how small the screen or how much we're going to print. */
+ fputs ("\
+This is the GNU debugger. Usage:\n\
+ gdb [options] [executable-file [core-file or process-id]]\n\
+Options:\n\
+ --help Print this message.\n\
+ --quiet Do not print version number on startup.\n\
+ --fullname Output information used by emacs-GDB interface.\n\
+ --epoch Output information used by epoch emacs-GDB interface.\n\
+ --batch Exit after processing options.\n\
+ --nx Do not read .gdbinit file.\n\
+ --tty=TTY Use TTY for input/output by the program being debugged.\n\
+ --cd=DIR Change current directory to DIR.\n\
+ --directory=DIR Search for source files in DIR.\n\
+ --command=FILE Execute GDB commands from FILE.\n\
+ --symbols=SYMFILE Read symbols from SYMFILE.\n\
+ --exec=EXECFILE Use EXECFILE as the executable.\n\
+ --se=FILE Use FILE as symbol file and executable file.\n\
+ --core=COREFILE Analyze the core dump COREFILE.\n\
+ -b BAUDRATE Set serial port baud rate used for remote debugging.\n\
+ --mapped Use mapped symbol files if supported on this system.\n\
+ --readnow Fully read symbol files on first access.\n\
+", stdout);
+#ifdef ADDITIONAL_OPTION_HELP
+ fputs (ADDITIONAL_OPTION_HELP, stdout);
+#endif
+ fputs ("\n\
+For more information, type \"help\" from within GDB, or consult the\n\
+GDB manual (available as on-line info or a printed manual).\n", stdout);
+ exit (0);
+ }
+
+ if (!quiet)
+ {
+ /* Print all the junk at the top, with trailing "..." if we are about
+ to read a symbol file (possibly slowly). */
+ print_gnu_advertisement ();
+ print_gdb_version (stdout);
+ if (symarg)
+ printf_filtered ("..");
+ wrap_here("");
+ fflush (stdout); /* Force to screen during slow operations */
+ }
+
+ error_pre_print = "\n\n";
+ /* We may get more than one warning, don't double space all of them... */
+ warning_pre_print = "\nwarning: ";
+
+ /* We need a default language for parsing expressions, so simple things like
+ "set width 0" won't fail if no language is explicitly set in a config file
+ or implicitly set by reading an executable during startup. */
+ set_language (language_c);
+ expected_language = current_language; /* don't warn about the change. */
+
+ /* Read and execute $HOME/.gdbinit file, if it exists. This is done
+ *before* all the command line arguments are processed; it sets
+ global parameters, which are independent of what file you are
+ debugging or what directory you are in. */
+ homedir = getenv ("HOME");
+ if (homedir)
+ {
+ homeinit = (char *) alloca (strlen (getenv ("HOME")) +
+ strlen (gdbinit) + 10);
+ strcpy (homeinit, getenv ("HOME"));
+ strcat (homeinit, "/");
+ strcat (homeinit, gdbinit);
+ if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+ {
+ if (!SET_TOP_LEVEL ())
+ source_command (homeinit, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ /* Do stats; no need to do them elsewhere since we'll only
+ need them if homedir is set. Make sure that they are
+ zero in case one of them fails (this guarantees that they
+ won't match if either exists). */
+
+ memset (&homebuf, 0, sizeof (struct stat));
+ memset (&cwdbuf, 0, sizeof (struct stat));
+
+ stat (homeinit, &homebuf);
+ stat (gdbinit, &cwdbuf); /* We'll only need this if
+ homedir was set. */
+ }
+
+ /* Now perform all the actions indicated by the arguments. */
+ if (cdarg != NULL)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ cd_command (cdarg, 0);
+ init_source_path ();
+ }
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ for (i = 0; i < ndir; i++)
+ if (!SET_TOP_LEVEL ())
+ directory_command (dirarg[i], 0);
+ free ((PTR)dirarg);
+ do_cleanups (ALL_CLEANUPS);
+
+ if (execarg != NULL
+ && symarg != NULL
+ && STREQ (execarg, symarg))
+ {
+ /* The exec file and the symbol-file are the same. If we can't open
+ it, better only print one error message. */
+ if (!SET_TOP_LEVEL ())
+ {
+ exec_file_command (execarg, !batch);
+ symbol_file_command (symarg, 0);
+ }
+ }
+ else
+ {
+ if (execarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ exec_file_command (execarg, !batch);
+ if (symarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ symbol_file_command (symarg, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ /* After the symbol file has been read, print a newline to get us
+ beyond the copyright line... But errors should still set off
+ the error message with a (single) blank line. */
+ if (!quiet)
+ printf_filtered ("\n");
+ error_pre_print = "\n";
+ warning_pre_print = "\nwarning: ";
+
+ if (corearg != NULL)
+ if (!SET_TOP_LEVEL ())
+ core_file_command (corearg, !batch);
+ else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ())
+ attach_command (corearg, !batch);
+ do_cleanups (ALL_CLEANUPS);
+
+ if (ttyarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ tty_command (ttyarg, !batch);
+ do_cleanups (ALL_CLEANUPS);
+
+#ifdef ADDITIONAL_OPTION_HANDLER
+ ADDITIONAL_OPTION_HANDLER;
+#endif
+
+ /* Error messages should no longer be distinguished with extra output. */
+ error_pre_print = 0;
+ warning_pre_print = "warning: ";
+
+ /* Read the .gdbinit file in the current directory, *if* it isn't
+ the same as the $HOME/.gdbinit file (it should exist, also). */
+
+ if (!homedir
+ || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
+ if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
+ {
+ if (!SET_TOP_LEVEL ())
+ source_command (gdbinit, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ for (i = 0; i < ncmd; i++)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+ read_command_file (stdin);
+ else
+ source_command (cmdarg[i], !batch);
+ do_cleanups (ALL_CLEANUPS);
+ }
+ }
+ free ((PTR)cmdarg);
+
+ /* Read in the old history after all the command files have been read. */
+ init_history();
+
+ if (batch)
+ {
+ /* We have hit the end of the batch file. */
+ exit (0);
+ }
+
+ /* Do any host- or target-specific hacks. This is used for i960 targets
+ to force the user to set a nindy target and spec its parameters. */
+
+#ifdef BEFORE_MAIN_LOOP_HOOK
+ BEFORE_MAIN_LOOP_HOOK;
+#endif
+
+ /* The command loop. */
+
+ while (1)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */
+ command_loop ();
+ quit_command ((char *)0, instream == stdin);
+ }
+ }
+ /* No exit -- exit is through quit_command. */
+}
+
+void
+execute_user_command (c, args)
+ struct cmd_list_element *c;
+ char *args;
+{
+ register struct command_line *cmdlines;
+ struct cleanup *old_chain;
+
+ if (args)
+ error ("User-defined commands cannot take arguments.");
+
+ cmdlines = c->user_commands;
+ if (cmdlines == 0)
+ /* Null command */
+ return;
+
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ old_chain = make_cleanup (source_cleanup, instream);
+ instream = (FILE *) 0;
+ while (cmdlines)
+ {
+ execute_command (cmdlines->line, 0);
+ cmdlines = cmdlines->next;
+ }
+ do_cleanups (old_chain);
+}
+
+/* Execute the line P as a command.
+ Pass FROM_TTY as second argument to the defining function. */
+
+void
+execute_command (p, from_tty)
+ char *p;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register enum language flang;
+ static int warned = 0;
+
+ free_all_values ();
+
+ /* This can happen when command_line_input hits end of file. */
+ if (p == NULL)
+ return;
+
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p)
+ {
+ char *arg;
+
+ c = lookup_cmd (&p, cmdlist, "", 0, 1);
+ /* Pass null arg rather than an empty one. */
+ arg = *p ? p : 0;
+
+ /* If this command has been hooked, run the hook first. */
+ if (c->hook)
+ execute_user_command (c->hook, (char *)0);
+
+ if (c->class == class_user)
+ execute_user_command (c, arg);
+ else if (c->type == set_cmd || c->type == show_cmd)
+ do_setshow_command (arg, from_tty & caution, c);
+ else if (c->function.cfunc == NO_FUNCTION)
+ error ("That is not a command, just a help topic.");
+ else
+ (*c->function.cfunc) (arg, from_tty & caution);
+ }
+
+ /* Tell the user if the language has changed (except first time). */
+ if (current_language != expected_language)
+ {
+ if (language_mode == language_mode_auto) {
+ language_info (1); /* Print what changed. */
+ }
+ warned = 0;
+ }
+
+ /* Warn the user if the working language does not match the
+ language of the current frame. Only warn the user if we are
+ actually running the program, i.e. there is a stack. */
+ /* FIXME: This should be cacheing the frame and only running when
+ the frame changes. */
+ if (target_has_stack)
+ {
+ flang = get_frame_language ();
+ if (!warned
+ && flang != language_unknown
+ && flang != current_language->la_language)
+ {
+ printf_filtered ("%s\n", lang_frame_mismatch_warn);
+ warned = 1;
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+command_loop_marker (foo)
+ int foo;
+{
+}
+
+/* Read commands from `instream' and execute them
+ until end of file or error reading instream. */
+static void
+command_loop ()
+{
+ struct cleanup *old_chain;
+ char *command;
+ int stdin_is_tty = ISATTY (stdin);
+
+ while (!feof (instream))
+ {
+ if (window_hook && instream == stdin)
+ (*window_hook) (instream, prompt);
+
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (command_loop_marker, 0);
+ command = command_line_input (instream == stdin ? prompt : (char *) NULL,
+ instream == stdin);
+ if (command == 0)
+ return;
+ execute_command (command, instream == stdin);
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions (&stop_bpstat);
+ do_cleanups (old_chain);
+ }
+}
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ /* If we aren't reading from standard input, we are saving the last
+ thing read from stdin in line and don't want to delete it. Null lines
+ won't repeat here in any case. */
+ if (instream == stdin)
+ *line = 0;
+}
+
+/* Read a line from the stream "instream" without command line editing.
+
+ It prints PRROMPT once at the start.
+ Action is compatible with "readline", e.g. space for the result is
+ malloc'd and should be freed by the caller.
+
+ A NULL return means end of file. */
+char *
+gdb_readline (prrompt)
+ char *prrompt;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prrompt)
+ {
+ /* Don't use a _filtered function here. It causes the assumed
+ character position to be off, since the newline we read from
+ the user is not accounted for. */
+ fputs (prrompt, stdout);
+ fflush (stdout);
+ }
+
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ /* Read from stdin if we are executing a user defined command.
+ This is the right thing for prompt_for_continue, at least. */
+ c = fgetc (instream ? instream : stdin);
+
+ if (c == EOF)
+ {
+ if (input_index > 0)
+ /* The last line does not end with a newline. Return it, and
+ if we are called again fgetc will still return EOF and
+ we'll return NULL then. */
+ break;
+ free (result);
+ return NULL;
+ }
+
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
+ }
+
+ result[input_index++] = '\0';
+ return result;
+}
+
+/* Variables which control command line editing and history
+ substitution. These variables are given default values at the end
+ of this file. */
+static int command_editing_p;
+static int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* readline uses the word breaks for two things:
+ (1) In figuring out where to point the TEXT parameter to the
+ rl_completion_entry_function. Since we don't use TEXT for much,
+ it doesn't matter a lot what the word breaks are for this purpose, but
+ it does affect how much stuff M-? lists.
+ (2) If one of the matches contains a word break character, readline
+ will quote it. That's why we switch between
+ gdb_completer_word_break_characters and
+ gdb_completer_command_word_break_characters. I'm not sure when
+ we need this behavior (perhaps for funky characters in C++ symbols?). */
+
+/* Variables which are necessary for fancy command line editing. */
+char *gdb_completer_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
+
+/* When completing on command names, we remove '-' from the list of
+ word break characters, since we use it in command names. If the
+ readline library sees one in any of the current completion strings,
+ it thinks that the string needs to be quoted and automatically supplies
+ a leading quote. */
+char *gdb_completer_command_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+
+/* Characters that can be used to quote completion strings. Note that we
+ can't include '"' because the gdb C parser treats such quoted sequences
+ as strings. */
+char *gdb_completer_quote_characters =
+ "'";
+
+/* Functions that are used as part of the fancy command line editing. */
+
+/* This can be used for functions which don't want to complete on symbols
+ but don't want to complete on anything else either. */
+/* ARGSUSED */
+char **
+noop_completer (text, prefix)
+ char *text;
+ char *prefix;
+{
+ return NULL;
+}
+
+/* Complete on filenames. */
+char **
+filename_completer (text, word)
+ char *text;
+ char *word;
+{
+ /* From readline. */
+ extern char *filename_completion_function ();
+ int subsequent_name;
+ char **return_val;
+ int return_val_used;
+ int return_val_alloced;
+
+ return_val_used = 0;
+ /* Small for testing. */
+ return_val_alloced = 1;
+ return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
+
+ subsequent_name = 0;
+ while (1)
+ {
+ char *p;
+ p = filename_completion_function (text, subsequent_name);
+ if (return_val_used >= return_val_alloced)
+ {
+ return_val_alloced *= 2;
+ return_val =
+ (char **) xrealloc (return_val,
+ return_val_alloced * sizeof (char *));
+ }
+ if (p == NULL)
+ {
+ return_val[return_val_used++] = p;
+ break;
+ }
+ /* Like emacs, don't complete on old versions. Especially useful
+ in the "source" command. */
+ if (p[strlen (p) - 1] == '~')
+ continue;
+
+ {
+ char *q;
+ if (word == text)
+ /* Return exactly p. */
+ return_val[return_val_used++] = p;
+ else if (word > text)
+ {
+ /* Return some portion of p. */
+ q = xmalloc (strlen (p) + 5);
+ strcpy (q, p + (word - text));
+ return_val[return_val_used++] = q;
+ free (p);
+ }
+ else
+ {
+ /* Return some of TEXT plus p. */
+ q = xmalloc (strlen (p) + (text - word) + 5);
+ strncpy (q, word, text - word);
+ q[text - word] = '\0';
+ strcat (q, p);
+ return_val[return_val_used++] = q;
+ free (p);
+ }
+ }
+ subsequent_name = 1;
+ }
+#if 0
+ /* There is no way to do this just long enough to affect quote inserting
+ without also affecting the next completion. This should be fixed in
+ readline. FIXME. */
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters = "";
+#endif
+ return return_val;
+}
+
+/* Here are some useful test cases for completion. FIXME: These should
+ be put in the test suite. They should be tested with both M-? and TAB.
+
+ "show output-" "radix"
+ "show output" "-radix"
+ "p" ambiguous (commands starting with p--path, print, printf, etc.)
+ "p " ambiguous (all symbols)
+ "info t foo" no completions
+ "info t " no completions
+ "info t" ambiguous ("info target", "info terminal", etc.)
+ "info ajksdlfk" no completions
+ "info ajksdlfk " no completions
+ "info" " "
+ "info " ambiguous (all info commands)
+ "p \"a" no completions (string constant)
+ "p 'a" ambiguous (all symbols starting with a)
+ "p b-a" ambiguous (all symbols starting with a)
+ "p b-" ambiguous (all symbols)
+ "file Make" "file" (word break hard to screw up here)
+ "file ../gdb.stabs/wi" "erd" (needs to not break word at slash)
+ */
+
+/* Generate completions one by one for the completer. Each time we are
+ called return another potential completion to the caller. The function
+ is misnamed; it just completes on commands or passes the buck to the
+ command's completer function; the stuff specific to symbol completion
+ is in make_symbol_completion_list.
+
+ TEXT is readline's idea of the "word" we are looking at; we don't really
+ like readline's ideas about word breaking so we ignore it.
+
+ MATCHES is the number of matches that have currently been collected from
+ calling this completion function. When zero, then we need to initialize,
+ otherwise the initialization has already taken place and we can just
+ return the next potential completion string.
+
+ Returns NULL if there are no more completions, else a pointer to a string
+ which is a possible completion.
+
+ RL_LINE_BUFFER is available to be looked at; it contains the entire text
+ of the line. RL_POINT is the offset in that line of the cursor. You
+ should pretend that the line ends at RL_POINT. */
+
+static char *
+symbol_completion_function (text, matches)
+ char *text;
+ int matches;
+{
+ static char **list = (char **)NULL; /* Cache of completions */
+ static int index; /* Next cached completion */
+ char *output = NULL;
+ char *tmp_command, *p;
+ /* Pointer within tmp_command which corresponds to text. */
+ char *word;
+ struct cmd_list_element *c, *result_list;
+ extern char *rl_line_buffer;
+ extern int rl_point;
+
+ if (matches == 0)
+ {
+ /* The caller is beginning to accumulate a new set of completions, so
+ we need to find all of them now, and cache them for returning one at
+ a time on future calls. */
+
+ if (list)
+ {
+ /* Free the storage used by LIST, but not by the strings inside.
+ This is because rl_complete_internal () frees the strings. */
+ free ((PTR)list);
+ }
+ list = 0;
+ index = 0;
+
+ /* Choose the default set of word break characters to break completions.
+ If we later find out that we are doing completions on command strings
+ (as opposed to strings supplied by the individual command completer
+ functions, which can be any string) then we will switch to the
+ special word break set for command strings, which leaves out the
+ '-' character used in some commands. */
+
+ rl_completer_word_break_characters =
+ gdb_completer_word_break_characters;
+
+ /* Decide whether to complete on a list of gdb commands or on symbols. */
+ tmp_command = (char *) alloca (rl_point + 1);
+ p = tmp_command;
+
+ strncpy (tmp_command, rl_line_buffer, rl_point);
+ tmp_command[rl_point] = '\0';
+ /* Since text always contains some number of characters leading up
+ to rl_point, we can find the equivalent position in tmp_command
+ by subtracting that many characters from the end of tmp_command. */
+ word = tmp_command + rl_point - strlen (text);
+
+ if (rl_point == 0)
+ {
+ /* An empty line we want to consider ambiguous; that is, it
+ could be any command. */
+ c = (struct cmd_list_element *) -1;
+ result_list = 0;
+ }
+ else
+ {
+ c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+ }
+
+ /* Move p up to the next interesting thing. */
+ while (*p == ' ' || *p == '\t')
+ {
+ p++;
+ }
+
+ if (!c)
+ {
+ /* It is an unrecognized command. So there are no
+ possible completions. */
+ list = NULL;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ char *q;
+
+ /* lookup_cmd_1 advances p up to the first ambiguous thing, but
+ doesn't advance over that thing itself. Do so now. */
+ q = p;
+ while (*q && (isalnum (*q) || *q == '-' || *q == '_'))
+ ++q;
+ if (q != tmp_command + rl_point)
+ {
+ /* There is something beyond the ambiguous
+ command, so there are no possible completions. For
+ example, "info t " or "info t foo" does not complete
+ to anything, because "info t" can be "info target" or
+ "info terminal". */
+ list = NULL;
+ }
+ else
+ {
+ /* We're trying to complete on the command which was ambiguous.
+ This we can deal with. */
+ if (result_list)
+ {
+ list = complete_on_cmdlist (*result_list->prefixlist, p,
+ word);
+ }
+ else
+ {
+ list = complete_on_cmdlist (cmdlist, p, word);
+ }
+ /* Insure that readline does the right thing with respect to
+ inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ }
+ else
+ {
+ /* We've recognized a full command. */
+
+ if (p == tmp_command + rl_point)
+ {
+ /* There is no non-whitespace in the line beyond the command. */
+
+ if (p[-1] == ' ' || p[-1] == '\t')
+ {
+ /* The command is followed by whitespace; we need to complete
+ on whatever comes after command. */
+ if (c->prefixlist)
+ {
+ /* It is a prefix command; what comes after it is
+ a subcommand (e.g. "info "). */
+ list = complete_on_cmdlist (*c->prefixlist, p, word);
+
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ else
+ {
+ /* It is a normal command; what comes after it is
+ completed by the command's completer function. */
+ list = (*c->completer) (p, word);
+ }
+ }
+ else
+ {
+ /* The command is not followed by whitespace; we need to
+ complete on the command itself. e.g. "p" which is a
+ command itself but also can complete to "print", "ptype"
+ etc. */
+ char *q;
+
+ /* Find the command we are completing on. */
+ q = p;
+ while (q > tmp_command)
+ {
+ if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_')
+ --q;
+ else
+ break;
+ }
+
+ list = complete_on_cmdlist (result_list, q, word);
+
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ }
+ else
+ {
+ /* There is non-whitespace beyond the command. */
+
+ if (c->prefixlist && !c->allow_unknown)
+ {
+ /* It is an unrecognized subcommand of a prefix command,
+ e.g. "info adsfkdj". */
+ list = NULL;
+ }
+ else
+ {
+ /* It is a normal command. */
+ list = (*c->completer) (p, word);
+ }
+ }
+ }
+ }
+
+ /* If we found a list of potential completions during initialization then
+ dole them out one at a time. The vector of completions is NULL
+ terminated, so after returning the last one, return NULL (and continue
+ to do so) each time we are called after that, until a new list is
+ available. */
+
+ if (list)
+ {
+ output = list[index];
+ if (output)
+ {
+ index++;
+ }
+ }
+
+#if 0
+ /* Can't do this because readline hasn't yet checked the word breaks
+ for figuring out whether to insert a quote. */
+ if (output == NULL)
+ /* Make sure the word break characters are set back to normal for the
+ next time that readline tries to complete something. */
+ rl_completer_word_break_characters =
+ gdb_completer_word_break_characters;
+#endif
+
+ return (output);
+}
+
+/* Skip over a possibly quoted word (as defined by the quote characters
+ and word break characters the completer uses). Returns pointer to the
+ location after the "word". */
+
+char *
+skip_quoted (str)
+ char *str;
+{
+ char quote_char = '\0';
+ char *scan;
+
+ for (scan = str; *scan != '\0'; scan++)
+ {
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char */
+ if (*scan == quote_char)
+ {
+ /* Found matching close quote. */
+ scan++;
+ break;
+ }
+ }
+ else if (strchr (gdb_completer_quote_characters, *scan))
+ {
+ /* Found start of a quoted string. */
+ quote_char = *scan;
+ }
+ else if (strchr (gdb_completer_word_break_characters, *scan))
+ {
+ break;
+ }
+ }
+ return (scan);
+}
+
+
+#ifdef STOP_SIGNAL
+static void
+stop_sig (signo)
+int signo;
+{
+#if STOP_SIGNAL == SIGTSTP
+ signal (SIGTSTP, SIG_DFL);
+ sigsetmask (0);
+ kill (getpid (), SIGTSTP);
+ signal (SIGTSTP, stop_sig);
+#else
+ signal (STOP_SIGNAL, stop_sig);
+#endif
+ printf ("%s", prompt);
+ fflush (stdout);
+
+ /* Forget about any previous command -- null line now will do nothing. */
+ dont_repeat ();
+}
+#endif /* STOP_SIGNAL */
+
+/* Initialize signal handlers. */
+static void
+do_nothing (signo)
+int signo;
+{
+}
+
+static void
+init_signals ()
+{
+ signal (SIGINT, request_quit);
+
+ /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
+ passed to the inferior, which we don't want. It would be
+ possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
+ on BSD4.3 systems using vfork, that can affect the
+ GDB process as well as the inferior (the signal handling tables
+ might be in memory, shared between the two). Since we establish
+ a handler for SIGQUIT, when we call exec it will set the signal
+ to SIG_DFL for us. */
+ signal (SIGQUIT, do_nothing);
+ if (signal (SIGHUP, do_nothing) != SIG_IGN)
+ signal (SIGHUP, disconnect);
+ signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
+}
+
+/* Read one line from the command input stream `instream'
+ into the local static buffer `linebuffer' (whose current length
+ is `linelength').
+ The buffer is made bigger as necessary.
+ Returns the address of the start of the line.
+
+ NULL is returned for end of file.
+
+ *If* the instream == stdin & stdin is a terminal, the line read
+ is copied into the file line saver (global var char *line,
+ length linesize) so that it can be duplicated.
+
+ This routine either uses fancy command line editing or
+ simple input as the user has requested. */
+
+char *
+command_line_input (prrompt, repeat)
+ char *prrompt;
+ int repeat;
+{
+ static char *linebuffer = 0;
+ static unsigned linelength = 0;
+ register char *p;
+ char *p1;
+ char *rl;
+ char *local_prompt = prrompt;
+ register int c;
+ char *nline;
+ char got_eof = 0;
+
+ if (linebuffer == 0)
+ {
+ linelength = 80;
+ linebuffer = (char *) xmalloc (linelength);
+ }
+
+ p = linebuffer;
+
+ /* Control-C quits instantly if typed while in this loop
+ since it should not wait until the user types a newline. */
+ immediate_quit++;
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, stop_sig);
+#endif
+
+ while (1)
+ {
+ /* Reports are that some Sys V's don't flush stdout/err on reads
+ from stdin, when stdin/out are sockets rather than ttys. So we
+ have to do it ourselves, to make emacs-gdb and xxgdb work.
+ On other machines, doing this once per input should be a cheap nop. */
+ fflush (stdout);
+ fflush (stderr);
+
+ /* Don't use fancy stuff if not talking to stdin. */
+ if (command_editing_p && instream == stdin
+ && ISATTY (instream))
+ rl = readline (local_prompt);
+ else
+ rl = gdb_readline (local_prompt);
+
+ if (!rl || rl == (char *) EOF)
+ {
+ got_eof = 1;
+ break;
+ }
+ if (strlen(rl) + 1 + (p - linebuffer) > linelength)
+ {
+ linelength = strlen(rl) + 1 + (p - linebuffer);
+ nline = (char *) xrealloc (linebuffer, linelength);
+ p += nline - linebuffer;
+ linebuffer = nline;
+ }
+ p1 = rl;
+ /* Copy line. Don't copy null at end. (Leaves line alone
+ if this was just a newline) */
+ while (*p1)
+ *p++ = *p1++;
+
+ free (rl); /* Allocated in readline. */
+
+ if (p == linebuffer || *(p - 1) != '\\')
+ break;
+
+ p--; /* Put on top of '\'. */
+ local_prompt = (char *) 0;
+ }
+
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, SIG_DFL);
+#endif
+ immediate_quit--;
+
+ if (got_eof)
+ return NULL;
+
+ /* Do history expansion if that is wished. */
+ if (history_expansion_p && instream == stdin
+ && ISATTY (instream))
+ {
+ char *history_value;
+ int expanded;
+
+ *p = '\0'; /* Insert null now. */
+ expanded = history_expand (linebuffer, &history_value);
+ if (expanded)
+ {
+ /* Print the changes. */
+ printf ("%s\n", history_value);
+
+ /* If there was an error, call this function again. */
+ if (expanded < 0)
+ {
+ free (history_value);
+ return command_line_input (prrompt, repeat);
+ }
+ if (strlen (history_value) > linelength)
+ {
+ linelength = strlen (history_value) + 1;
+ linebuffer = (char *) xrealloc (linebuffer, linelength);
+ }
+ strcpy (linebuffer, history_value);
+ p = linebuffer + strlen(linebuffer);
+ free (history_value);
+ }
+ }
+
+ /* If we just got an empty line, and that is supposed
+ to repeat the previous command, return the value in the
+ global buffer. */
+ if (repeat)
+ {
+ if (p == linebuffer)
+ return line;
+ p1 = linebuffer;
+ while (*p1 == ' ' || *p1 == '\t')
+ p1++;
+ if (!*p1)
+ return line;
+ }
+
+ *p = 0;
+
+ /* Add line to history if appropriate. */
+ if (instream == stdin
+ && ISATTY (stdin) && *linebuffer)
+ add_history (linebuffer);
+
+ /* Note: lines consisting soley of comments are added to the command
+ history. This is useful when you type a command, and then
+ realize you don't want to execute it quite yet. You can comment
+ out the command and then later fetch it from the value history
+ and remove the '#'. The kill ring is probably better, but some
+ people are in the habit of commenting things out. */
+ p1 = linebuffer;
+ while ((c = *p1++) != '\0')
+ {
+ if (c == '"')
+ while ((c = *p1++) != '"')
+ {
+ /* Make sure an escaped '"' doesn't make us think the string
+ is ended. */
+ if (c == '\\')
+ parse_escape (&p1);
+ if (c == '\0')
+ break;
+ }
+ else if (c == '\'')
+ while ((c = *p1++) != '\'')
+ {
+ /* Make sure an escaped '\'' doesn't make us think the string
+ is ended. */
+ if (c == '\\')
+ parse_escape (&p1);
+ if (c == '\0')
+ break;
+ }
+ else if (c == '#')
+ {
+ /* Found a comment. */
+ p1[-1] = '\0';
+ break;
+ }
+ }
+
+ /* Save into global buffer if appropriate. */
+ if (repeat)
+ {
+ if (linelength > linesize)
+ {
+ line = xrealloc (line, linelength);
+ linesize = linelength;
+ }
+ strcpy (line, linebuffer);
+ return line;
+ }
+
+ return linebuffer;
+}
+
+/* Read lines from the input stream
+ and accumulate them in a chain of struct command_line's
+ which is then returned. */
+
+struct command_line *
+read_command_lines ()
+{
+ struct command_line *first = 0;
+ register struct command_line *next, *tail = 0;
+ register char *p, *p1;
+ struct cleanup *old_chain = 0;
+
+ while (1)
+ {
+ dont_repeat ();
+ p = command_line_input ((char *) NULL, instream == stdin);
+ if (p == NULL)
+ /* Treat end of file like "end". */
+ break;
+
+ /* Remove leading and trailing blanks. */
+ while (*p == ' ' || *p == '\t') p++;
+ p1 = p + strlen (p);
+ while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--;
+
+ /* Is this "end"? */
+ if (p1 - p == 3 && !strncmp (p, "end", 3))
+ break;
+
+ /* No => add this line to the chain of command lines. */
+ next = (struct command_line *) xmalloc (sizeof (struct command_line));
+ next->line = savestring (p, p1 - p);
+ next->next = 0;
+ if (tail)
+ {
+ tail->next = next;
+ }
+ else
+ {
+ /* We just read the first line.
+ From now on, arrange to throw away the lines we have
+ if we quit or get an error while inside this function. */
+ first = next;
+ old_chain = make_cleanup (free_command_lines, &first);
+ }
+ tail = next;
+ }
+
+ dont_repeat ();
+
+ /* Now we are about to return the chain to our caller,
+ so freeing it becomes his responsibility. */
+ if (first)
+ discard_cleanups (old_chain);
+ return first;
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines (lptr)
+ struct command_line **lptr;
+{
+ register struct command_line *l = *lptr;
+ register struct command_line *next;
+
+ while (l)
+ {
+ next = l->next;
+ free (l->line);
+ free ((PTR)l);
+ l = next;
+ }
+}
+
+/* Add an element to the list of info subcommands. */
+
+void
+add_info (name, fun, doc)
+ char *name;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+{
+ add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands. */
+
+void
+add_info_alias (name, oldname, abbrev_flag)
+ char *name;
+ char *oldname;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+ Therefore, its own definition is called only for "info" with no args. */
+
+/* ARGSUSED */
+static void
+info_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, stdout);
+}
+
+/* The "show" command with no arguments shows all the settings. */
+
+/* ARGSUSED */
+static void
+show_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ cmd_show_list (showlist, from_tty, "");
+}
+
+/* Add an element to the list of commands. */
+
+void
+add_com (name, class, fun, doc)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+{
+ add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands. */
+
+void
+add_com_alias (name, oldname, class, abbrev_flag)
+ char *name;
+ char *oldname;
+ enum command_class class;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+void
+error_no_arg (why)
+ char *why;
+{
+ error ("Argument required (%s).", why);
+}
+
+/* ARGSUSED */
+static void
+help_command (command, from_tty)
+ char *command;
+ int from_tty; /* Ignored */
+{
+ help_cmd (command, stdout);
+}
+
+static void
+validate_comname (comname)
+ char *comname;
+{
+ register char *p;
+
+ if (comname == 0)
+ error_no_arg ("name of command to define");
+
+ p = comname;
+ while (*p)
+ {
+ if (!isalnum(*p) && *p != '-')
+ error ("Junk in argument list: \"%s\"", p);
+ p++;
+ }
+}
+
+/* This is just a placeholder in the command data structures. */
+static void
+user_defined_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+}
+
+static void
+define_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct command_line *cmds;
+ register struct cmd_list_element *c, *newc, *hookc = 0;
+ char *tem = comname;
+#define HOOK_STRING "hook-"
+#define HOOK_LEN 5
+
+ validate_comname (comname);
+
+ /* Look it up, and verify that we got an exact match. */
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c && !STREQ (comname, c->name))
+ c = 0;
+
+ if (c)
+ {
+ if (c->class == class_user || c->class == class_alias)
+ tem = "Redefine command \"%s\"? ";
+ else
+ tem = "Really redefine built-in command \"%s\"? ";
+ if (!query (tem, c->name))
+ error ("Command \"%s\" not redefined.", c->name);
+ }
+
+ /* If this new command is a hook, then mark the command which it
+ is hooking. Note that we allow hooking `help' commands, so that
+ we can hook the `stop' pseudo-command. */
+
+ if (!strncmp (comname, HOOK_STRING, HOOK_LEN))
+ {
+ /* Look up cmd it hooks, and verify that we got an exact match. */
+ tem = comname+HOOK_LEN;
+ hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+ if (hookc && !STREQ (comname+HOOK_LEN, hookc->name))
+ hookc = 0;
+ if (!hookc)
+ {
+ warning ("Your new `%s' command does not hook any existing command.",
+ comname);
+ if (!query ("Proceed? ", (char *)0))
+ error ("Not confirmed.");
+ }
+ }
+
+ comname = savestring (comname, strlen (comname));
+
+ /* If the rest of the commands will be case insensitive, this one
+ should behave in the same manner. */
+ for (tem = comname; *tem; tem++)
+ if (isupper(*tem)) *tem = tolower(*tem);
+
+ if (from_tty)
+ {
+ printf ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ fflush (stdout);
+ }
+
+ cmds = read_command_lines ();
+
+ if (c && c->class == class_user)
+ free_command_lines (&c->user_commands);
+
+ newc = add_cmd (comname, class_user, user_defined_command,
+ (c && c->class == class_user)
+ ? c->doc : savestring ("User-defined.", 13), &cmdlist);
+ newc->user_commands = cmds;
+
+ /* If this new command is a hook, then mark both commands as being
+ tied. */
+ if (hookc)
+ {
+ hookc->hook = newc; /* Target gets hooked. */
+ newc->hookee = hookc; /* We are marked as hooking target cmd. */
+ }
+}
+
+static void
+document_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ struct command_line *doclines;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+
+ if (c->class != class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ if (from_tty)
+ printf ("Type documentation for \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+
+ doclines = read_command_lines ();
+
+ if (c->doc) free (c->doc);
+
+ {
+ register struct command_line *cl1;
+ register int len = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ len += strlen (cl1->line) + 1;
+
+ c->doc = (char *) xmalloc (len + 1);
+ *c->doc = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ {
+ strcat (c->doc, cl1->line);
+ if (cl1->next)
+ strcat (c->doc, "\n");
+ }
+ }
+
+ free_command_lines (&doclines);
+}
+
+static void
+print_gnu_advertisement()
+{
+ printf ("\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"show copying\" to see the conditions.\n\
+There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\
+");
+}
+
+static void
+print_gdb_version (stream)
+ FILE *stream;
+{
+ fprintf_filtered (stream, "\
+GDB %s (%s", version, host_canonical);
+
+ if (strcmp(host_canonical, target_canonical))
+ fprintf_filtered (stream, " --target %s", target_canonical);
+
+ fprintf_filtered (stream, "), ");
+ wrap_here("");
+ fprintf_filtered (stream, "Copyright 1993 Free Software Foundation, Inc.");
+}
+
+/* ARGSUSED */
+static void
+show_version (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ immediate_quit++;
+ print_gnu_advertisement ();
+ print_gdb_version (stdout);
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+/* xgdb calls this to reprint the usual GDB prompt. */
+
+void
+print_prompt ()
+{
+ printf ("%s", prompt);
+ fflush (stdout);
+}
+
+static void
+quit_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (inferior_pid != 0 && target_has_execution)
+ {
+ if (attach_flag)
+ {
+ if (query ("The program is running. Quit anyway (and detach it)? "))
+ target_detach (args, from_tty);
+ else
+ error ("Not confirmed.");
+ }
+ else
+ {
+ if (query ("The program is running. Quit anyway (and kill it)? "))
+ target_kill ();
+ else
+ error ("Not confirmed.");
+ }
+ }
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
+ exit (0);
+}
+
+/* Returns whether GDB is running on a terminal and whether the user
+ desires that questions be asked of them on that terminal. */
+
+int
+input_from_terminal_p ()
+{
+ return gdb_has_a_terminal () && (instream == stdin) & caution;
+}
+
+/* ARGSUSED */
+static void
+pwd_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args) error ("The \"pwd\" command does not take an argument: %s", args);
+ getcwd (dirbuf, sizeof (dirbuf));
+
+ if (!STREQ (dirbuf, current_directory))
+ printf ("Working directory %s\n (canonically %s).\n",
+ current_directory, dirbuf);
+ else
+ printf ("Working directory %s.\n", current_directory);
+}
+
+static void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ int len;
+ /* Found something other than leading repetitions of "/..". */
+ int found_real_path;
+ char *p;
+
+ /* If the new directory is absolute, repeat is a no-op; if relative,
+ repeat might be useful but is more likely to be a mistake. */
+ dont_repeat ();
+
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ dir = tilde_expand (dir);
+ make_cleanup (free, dir);
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+ len = strlen (dir);
+ dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+ if (dir[0] == '/')
+ current_directory = dir;
+ else
+ {
+ if (current_directory[0] == '/' && current_directory[1] == '\0')
+ current_directory = concat (current_directory, dir, NULL);
+ else
+ current_directory = concat (current_directory, "/", dir, NULL);
+ free (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ found_real_path = 0;
+ for (p = current_directory; *p;)
+ {
+ if (p[0] == '/' && p[1] == '.' && (p[2] == 0 || p[2] == '/'))
+ strcpy (p, p + 2);
+ else if (p[0] == '/' && p[1] == '.' && p[2] == '.'
+ && (p[3] == 0 || p[3] == '/'))
+ {
+ if (found_real_path)
+ {
+ /* Search backwards for the directory just before the "/.."
+ and obliterate it and the "/..". */
+ char *q = p;
+ while (q != current_directory && q[-1] != '/')
+ --q;
+
+ if (q == current_directory)
+ /* current_directory is
+ a relative pathname ("can't happen"--leave it alone). */
+ ++p;
+ else
+ {
+ strcpy (q - 1, p + 3);
+ p = q - 1;
+ }
+ }
+ else
+ /* We are dealing with leading repetitions of "/..", for example
+ "/../..", which is the Mach super-root. */
+ p += 3;
+ }
+ else
+ {
+ found_real_path = 1;
+ ++p;
+ }
+ }
+
+ forget_cached_source_info ();
+
+ if (from_tty)
+ pwd_command ((char *) 0, 1);
+}
+
+/* ARGSUSED */
+static void
+source_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ FILE *stream;
+ struct cleanup *cleanups;
+ char *file = args;
+
+ if (file == NULL)
+ {
+ error ("source command requires pathname of file to source.");
+ }
+
+ file = tilde_expand (file);
+ make_cleanup (free, file);
+
+ stream = fopen (file, FOPEN_RT);
+ if (stream == 0)
+ perror_with_name (file);
+
+ cleanups = make_cleanup (fclose, stream);
+
+ read_command_file (stream);
+
+ do_cleanups (cleanups);
+}
+
+/* ARGSUSED */
+static void
+echo_command (text, from_tty)
+ char *text;
+ int from_tty;
+{
+ char *p = text;
+ register int c;
+
+ if (text)
+ while ((c = *p++) != '\0')
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ return;
+
+ c = parse_escape (&p);
+ if (c >= 0)
+ printf_filtered ("%c", c);
+ }
+ else
+ printf_filtered ("%c", c);
+ }
+
+ /* Force this output to appear now. */
+ wrap_here ("");
+ fflush (stdout);
+}
+
+
+/* Functions to manipulate command line editing control variables. */
+
+/* Number of commands to print in each call to show_commands. */
+#define Hist_print 10
+static void
+show_commands (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ /* Index for history commands. Relative to history_base. */
+ int offset;
+
+ /* Number of the history entry which we are planning to display next.
+ Relative to history_base. */
+ static int num = 0;
+
+ /* The first command in the history which doesn't exist (i.e. one more
+ than the number of the last command). Relative to history_base. */
+ int hist_len;
+
+ extern struct _hist_entry *history_get PARAMS ((int));
+ extern int history_base;
+
+ /* Print out some of the commands from the command history. */
+ /* First determine the length of the history list. */
+ hist_len = history_size;
+ for (offset = 0; offset < history_size; offset++)
+ {
+ if (!history_get (history_base + offset))
+ {
+ hist_len = offset;
+ break;
+ }
+ }
+
+ if (args)
+ {
+ if (args[0] == '+' && args[1] == '\0')
+ /* "info editing +" should print from the stored position. */
+ ;
+ else
+ /* "info editing <exp>" should print around command number <exp>. */
+ num = (parse_and_eval_address (args) - history_base) - Hist_print / 2;
+ }
+ /* "show commands" means print the last Hist_print commands. */
+ else
+ {
+ num = hist_len - Hist_print;
+ }
+
+ if (num < 0)
+ num = 0;
+
+ /* If there are at least Hist_print commands, we want to display the last
+ Hist_print rather than, say, the last 6. */
+ if (hist_len - num < Hist_print)
+ {
+ num = hist_len - Hist_print;
+ if (num < 0)
+ num = 0;
+ }
+
+ for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
+ {
+ printf_filtered ("%5d %s\n", history_base + offset,
+ (history_get (history_base + offset))->line);
+ }
+
+ /* The next command we want to display is the next one that we haven't
+ displayed yet. */
+ num += Hist_print;
+
+ /* If the user repeats this command with return, it should do what
+ "show commands +" does. This is unnecessary if arg is null,
+ because "show commands +" is not useful after "show commands". */
+ if (from_tty && args)
+ {
+ args[0] = '+';
+ args[1] = '\0';
+ }
+}
+
+/* Called by do_setshow_command. */
+/* ARGSUSED */
+static void
+set_history_size_command (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (history_size == INT_MAX)
+ unstifle_history ();
+ else if (history_size >= 0)
+ stifle_history (history_size);
+ else
+ {
+ history_size = INT_MAX;
+ error ("History size must be non-negative");
+ }
+}
+
+/* ARGSUSED */
+static void
+set_history (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, stdout);
+}
+
+/* ARGSUSED */
+static void
+show_history (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ cmd_show_list (showhistlist, from_tty, "");
+}
+
+int info_verbose = 0; /* Default verbose msgs off */
+
+/* Called by do_setshow_command. An elaborate joke. */
+/* ARGSUSED */
+static void
+set_verbose (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ char *cmdname = "verbose";
+ struct cmd_list_element *showcmd;
+
+ showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+
+ if (info_verbose)
+ {
+ c->doc = "Set verbose printing of informational messages.";
+ showcmd->doc = "Show verbose printing of informational messages.";
+ }
+ else
+ {
+ c->doc = "Set verbosity.";
+ showcmd->doc = "Show verbosity.";
+ }
+}
+
+static void
+float_handler (signo)
+int signo;
+{
+ /* This message is based on ANSI C, section 4.7. Note that integer
+ divide by zero causes this, so "float" is a misnomer. */
+ signal (SIGFPE, float_handler);
+ error ("Erroneous arithmetic operation.");
+}
+
+/* Return whether we are running a batch file or from terminal. */
+int
+batch_mode ()
+{
+ return !(instream == stdin && ISATTY (stdin));
+}
+
+
+static void
+init_cmd_lists ()
+{
+ cmdlist = NULL;
+ infolist = NULL;
+ enablelist = NULL;
+ disablelist = NULL;
+ deletelist = NULL;
+ enablebreaklist = NULL;
+ setlist = NULL;
+ unsetlist = NULL;
+ showlist = NULL;
+ sethistlist = NULL;
+ showhistlist = NULL;
+ unsethistlist = NULL;
+#if MAINTENANCE_CMDS
+ maintenancelist = NULL;
+ maintenanceinfolist = NULL;
+ maintenanceprintlist = NULL;
+#endif
+ setprintlist = NULL;
+ showprintlist = NULL;
+ setchecklist = NULL;
+ showchecklist = NULL;
+}
+
+/* Init the history buffer. Note that we are called after the init file(s)
+ * have been read so that the user can change the history file via his
+ * .gdbinit file (for instance). The GDBHISTFILE environment variable
+ * overrides all of this.
+ */
+
+static void
+init_history()
+{
+ char *tmpenv;
+
+ tmpenv = getenv ("HISTSIZE");
+ if (tmpenv)
+ history_size = atoi (tmpenv);
+ else if (!history_size)
+ history_size = 256;
+
+ stifle_history (history_size);
+
+ tmpenv = getenv ("GDBHISTFILE");
+ if (tmpenv)
+ history_filename = savestring (tmpenv, strlen(tmpenv));
+ else if (!history_filename) {
+ /* We include the current directory so that if the user changes
+ directories the file written will be the same as the one
+ that was read. */
+ history_filename = concat (current_directory, "/.gdb_history", NULL);
+ }
+ read_history (history_filename);
+}
+
+static void
+init_main ()
+{
+ struct cmd_list_element *c;
+
+#ifdef DEFAULT_PROMPT
+ prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
+#else
+ prompt = savestring ("(gdb) ", 6);
+#endif
+
+ /* Set the important stuff up for command editing. */
+ command_editing_p = 1;
+ history_expansion_p = 0;
+ write_history_p = 0;
+
+ /* Setup important stuff for command line editing. */
+ rl_completion_entry_function = (int (*)()) symbol_completion_function;
+ rl_completer_word_break_characters = gdb_completer_word_break_characters;
+ rl_completer_quote_characters = gdb_completer_quote_characters;
+ rl_readline_name = "gdb";
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("internals", class_maintenance, NO_FUNCTION,
+ "Maintenance commands.\n\
+Some gdb commands are provided just for use by gdb maintainers.\n\
+These commands are subject to frequent change, and may not be as\n\
+well documented as user commands.",
+ &cmdlist);
+ add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist);
+ add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\
+The commands in this class are those defined by the user.\n\
+Use the \"define\" command to define a command.", &cmdlist);
+ add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist);
+ add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\
+The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
+counting from zero for the innermost (currently executing) frame.\n\n\
+At any time gdb identifies one frame as the \"selected\" frame.\n\
+Variable lookups are done with respect to the selected frame.\n\
+When the program being debugged stops, gdb selects the innermost frame.\n\
+The commands below can be used to select other frames by number or address.",
+ &cmdlist);
+ add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist);
+
+ add_com ("pwd", class_files, pwd_command,
+ "Print working directory. This is used for your program as well.");
+ c = add_cmd ("cd", class_files, cd_command,
+ "Set working directory to DIR for debugger and program being debugged.\n\
+The change does not take effect for the program being debugged\n\
+until the next time it is started.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_show_from_set
+ (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt,
+ "Set gdb's prompt",
+ &setlist),
+ &showlist);
+
+ add_com ("echo", class_support, echo_command,
+ "Print a constant string. Give string as argument.\n\
+C escape sequences may be used in the argument.\n\
+No newline is added at the end of the argument;\n\
+use \"\\n\" if you want a newline to be printed.\n\
+Since leading and trailing whitespace are ignored in command arguments,\n\
+if you want to print some you must use \"\\\" before leading whitespace\n\
+to be printed or after trailing whitespace.");
+ add_com ("document", class_support, document_command,
+ "Document a user-defined command.\n\
+Give command name as argument. Give documentation on following lines.\n\
+End with a line of just \"end\".");
+ add_com ("define", class_support, define_command,
+ "Define a new command name. Command name is argument.\n\
+Definition appears on following lines, one command per line.\n\
+End with a line of just \"end\".\n\
+Use the \"document\" command to give documentation for the new command.\n\
+Commands defined in this way do not take arguments.");
+
+#ifdef __STDC__
+ c = add_cmd ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
+when gdb is started.", &cmdlist);
+#else
+ /* Punt file name, we can't help it easily. */
+ c = add_cmd ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \".gdbinit\" is read automatically in this way\n\
+when gdb is started.", &cmdlist);
+#endif
+ c->completer = filename_completer;
+
+ add_com ("quit", class_support, quit_command, "Exit gdb.");
+ add_com ("help", class_support, help_command, "Print list of commands.");
+ add_com_alias ("q", "quit", class_support, 1);
+ add_com_alias ("h", "help", class_support, 1);
+
+
+ c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose,
+ "Set ",
+ &setlist),
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_verbose;
+ set_verbose (NULL, 0, c);
+
+ add_show_from_set
+ (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
+ "Set editing of command lines as they are typed.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled. To edit, use\n\
+EMACS-like or VI-like commands like control-P or ESC.", &setlist),
+ &showlist);
+
+ add_prefix_cmd ("history", class_support, set_history,
+ "Generic command for setting command history parameters.",
+ &sethistlist, "set history ", 0, &setlist);
+ add_prefix_cmd ("history", class_support, show_history,
+ "Generic command for showing command history parameters.",
+ &showhistlist, "show history ", 0, &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p,
+ "Set history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist),
+ &showhistlist);
+
+ add_show_from_set
+ (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p,
+ "Set saving of the history record on exit.\n\
+Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
+Without an argument, saving is enabled.", &sethistlist),
+ &showhistlist);
+
+ c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size,
+ "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+ add_show_from_set (c, &showhistlist);
+ c->function.sfunc = set_history_size_command;
+
+ add_show_from_set
+ (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename,
+ "Set the filename in which to record the command history\n\
+ (the list of previous commands of which a record is kept).", &sethistlist),
+ &showhistlist);
+
+ add_show_from_set
+ (add_set_cmd ("confirm", class_support, var_boolean,
+ (char *)&caution,
+ "Set whether to confirm potentially dangerous operations.",
+ &setlist),
+ &showlist);
+
+ add_prefix_cmd ("info", class_info, info_command,
+ "Generic command for showing things about the program being debugged.",
+ &infolist, "info ", 0, &cmdlist);
+ add_com_alias ("i", "info", class_info, 1);
+
+ add_prefix_cmd ("show", class_info, show_command,
+ "Generic command for showing things about the debugger.",
+ &showlist, "show ", 0, &cmdlist);
+ /* Another way to get at the same thing. */
+ add_info ("set", show_command, "Show all GDB settings.");
+
+ add_cmd ("commands", no_class, show_commands,
+ "Show the the history of commands you typed.\n\
+You can supply a command number to start with, or a `+' to start after\n\
+the previous command number shown.",
+ &showlist);
+
+ add_cmd ("version", no_class, show_version,
+ "Show what version of GDB this is.", &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("remotedebug", no_class, var_boolean, (char *)&remote_debug,
+ "Set debugging of remote protocol.\n\
+When enabled, each packet sent or received with the remote target\n\
+is displayed.", &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/maint.c b/gnu/usr.bin/gdb/gdb/maint.c
new file mode 100644
index 000000000000..b5334512ab48
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/maint.c
@@ -0,0 +1,305 @@
+/* Support for GDB maintenance commands.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "defs.h"
+
+#if MAINTENANCE_CMDS /* Entire file goes away if not including maint cmds */
+
+#include <signal.h>
+#include "command.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "demangle.h"
+#include "gdbcore.h"
+
+static void
+maintenance_command PARAMS ((char *, int));
+
+static void
+maintenance_dump_me PARAMS ((char *, int));
+
+static void
+maintenance_demangle PARAMS ((char *, int));
+
+/*
+
+LOCAL FUNCTION
+
+ maintenance_command -- access the maintenance subcommands
+
+SYNOPSIS
+
+ void maintenance_command (char *args, int from_tty)
+
+DESCRIPTION
+
+*/
+
+static void
+maintenance_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf ("\"maintenance\" must be followed by the name of a maintenance command.\n");
+ help_list (maintenancelist, "maintenance ", -1, stdout);
+}
+
+
+/* ARGSUSED */
+static void
+maintenance_dump_me (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (query ("Should GDB dump core? "))
+ {
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ }
+}
+
+/* Someday we should allow demangling for things other than just
+ explicit strings. For example, we might want to be able to
+ specify the address of a string in either GDB's process space
+ or the debuggee's process space, and have gdb fetch and demangle
+ that string. If we have a char* pointer "ptr" that points to
+ a string, we might want to be able to given just the name and
+ have GDB demangle and print what it points to, etc. (FIXME) */
+
+static void
+maintenance_demangle (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *demangled;
+
+ if (args == NULL || *args == '\0')
+ {
+ printf ("\"maintenance demangle\" takes an argument to demangle.\n");
+ }
+ else
+ {
+ demangled = cplus_demangle (args, DMGL_ANSI | DMGL_PARAMS);
+ if (demangled != NULL)
+ {
+ printf ("%s\n", demangled);
+ free (demangled);
+ }
+ else
+ {
+ printf ("Can't demangle \"%s\"\n", args);
+ }
+ }
+}
+
+/* The "maintenance info" command is defined as a prefix, with allow_unknown 0.
+ Therefore, its own definition is called only for "maintenance info" with
+ no args. */
+
+/* ARGSUSED */
+static void
+maintenance_info_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"maintenance info\" must be followed by the name of an info command.\n");
+ help_list (maintenanceinfolist, "maintenance info ", -1, stdout);
+}
+
+static void
+print_section_table (abfd, asect, ignore)
+ bfd *abfd;
+ asection *asect;
+ PTR ignore;
+{
+ flagword flags;
+
+ flags = bfd_get_section_flags (abfd, asect);
+
+ printf_filtered (" %s",
+ local_hex_string_custom
+ ((unsigned long) bfd_section_vma (abfd, asect), "08l"));
+ printf_filtered ("->%s",
+ local_hex_string_custom
+ ((unsigned long) (bfd_section_vma (abfd, asect)
+ + bfd_section_size (abfd, asect)),
+ "08l"));
+ printf_filtered (" at %s",
+ local_hex_string_custom
+ ((unsigned long) asect->filepos, "08l"));
+ printf_filtered (": %s", bfd_section_name (abfd, asect));
+
+ if (flags & SEC_ALLOC)
+ printf_filtered (" ALLOC");
+ if (flags & SEC_LOAD)
+ printf_filtered (" LOAD");
+ if (flags & SEC_RELOC)
+ printf_filtered (" RELOC");
+ if (flags & SEC_READONLY)
+ printf_filtered (" READONLY");
+ if (flags & SEC_CODE)
+ printf_filtered (" CODE");
+ if (flags & SEC_DATA)
+ printf_filtered (" DATA");
+ if (flags & SEC_ROM)
+ printf_filtered (" ROM");
+ if (flags & SEC_CONSTRUCTOR)
+ printf_filtered (" CONSTRUCTOR");
+ if (flags & SEC_HAS_CONTENTS)
+ printf_filtered (" HAS_CONTENTS");
+ if (flags & SEC_NEVER_LOAD)
+ printf_filtered (" NEVER_LOAD");
+ if (flags & SEC_SHARED_LIBRARY)
+ printf_filtered (" SHARED_LIBRARY");
+ if (flags & SEC_IS_COMMON)
+ printf_filtered (" IS_COMMON");
+
+ printf_filtered ("\n");
+}
+
+/* ARGSUSED */
+static void
+maintenance_info_sections (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (exec_bfd)
+ {
+ printf_filtered ("Exec file:\n");
+ printf_filtered (" `%s', ", bfd_get_filename(exec_bfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(exec_bfd));
+ bfd_map_over_sections(exec_bfd, print_section_table, 0);
+ }
+
+ if (core_bfd)
+ {
+ printf_filtered ("Core file:\n");
+ printf_filtered (" `%s', ", bfd_get_filename(core_bfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(core_bfd));
+ bfd_map_over_sections(core_bfd, print_section_table, 0);
+ }
+}
+
+/* The "maintenance print" command is defined as a prefix, with allow_unknown
+ 0. Therefore, its own definition is called only for "maintenance print"
+ with no args. */
+
+/* ARGSUSED */
+static void
+maintenance_print_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"maintenance print\" must be followed by the name of a print command.\n");
+ help_list (maintenanceprintlist, "maintenance print ", -1, stdout);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ _initialize_maint_cmds -- initialize the process file system stuff
+
+SYNOPSIS
+
+ void _initialize_maint_cmds (void)
+
+DESCRIPTION
+
+ Do required initializations during gdb startup for using the
+ /proc file system interface.
+
+*/
+
+
+void
+_initialize_maint_cmds ()
+{
+ add_prefix_cmd ("maintenance", class_maintenance, maintenance_command,
+ "Commands for use by GDB maintainers.\n\
+Includes commands to dump specific internal GDB structures in\n\
+a human readable form, to cause GDB to deliberately dump core,\n\
+to test internal functions such as the C++ demangler, etc.",
+ &maintenancelist, "maintenance ", 0,
+ &cmdlist);
+
+ add_com_alias ("mt", "maintenance", class_maintenance, 1);
+
+ add_prefix_cmd ("info", class_maintenance, maintenance_info_command,
+ "Commands for showing internal info about the program being debugged.",
+ &maintenanceinfolist, "maintenance info ", 0,
+ &maintenancelist);
+
+ add_cmd ("sections", class_maintenance, maintenance_info_sections,
+ "List the BFD sections of the exec and core files.",
+ &maintenanceinfolist);
+
+ add_prefix_cmd ("print", class_maintenance, maintenance_print_command,
+ "Maintenance command for printing GDB internal state.",
+ &maintenanceprintlist, "maintenance print ", 0,
+ &maintenancelist);
+
+ add_cmd ("dump-me", class_maintenance, maintenance_dump_me,
+ "Get fatal error; make debugger dump its core.\n\
+GDB sets it's handling of SIGQUIT back to SIG_DFL and then sends\n\
+itself a SIGQUIT signal.",
+ &maintenancelist);
+
+ add_cmd ("demangle", class_maintenance, maintenance_demangle,
+ "Demangle a C++ mangled name.\n\
+Call internal GDB demangler routine to demangle a C++ link name\n\
+and prints the result.",
+ &maintenancelist);
+
+ add_cmd ("type", class_maintenance, maintenance_print_type,
+ "Print a type chain for a given symbol.\n\
+For each node in a type chain, print the raw data for each member of\n\
+the type structure, and the interpretation of the data.",
+ &maintenanceprintlist);
+
+ add_cmd ("symbols", class_maintenance, maintenance_print_symbols,
+ "Print dump of current symbol definitions.\n\
+Entries in the full symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("msymbols", class_maintenance, maintenance_print_msymbols,
+ "Print dump of current minimal symbol definitions.\n\
+Entries in the minimal symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's minimal symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("psymbols", class_maintenance, maintenance_print_psymbols,
+ "Print dump of current partial symbol definitions.\n\
+Entries in the partial symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's partial symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("objfiles", class_maintenance, maintenance_print_objfiles,
+ "Print dump of current object file definitions.",
+ &maintenanceprintlist);
+
+}
+
+#endif /* MAINTENANCE_CMDS */
diff --git a/gnu/usr.bin/gdb/gdb/mem-break.c b/gnu/usr.bin/gdb/gdb/mem-break.c
new file mode 100644
index 000000000000..74dfaa147501
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mem-break.c
@@ -0,0 +1,104 @@
+/* Simulate breakpoints by patching locations in the target system, for GDB.
+ Copyright 1990, 1991 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+
+#ifdef BREAKPOINT
+/* This file is only useful if BREAKPOINT is set. If not, we punt. */
+
+#include "symtab.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "target.h"
+
+/* This is the sequence of bytes we insert for a breakpoint. On some
+ machines, breakpoints are handled by the target environment and we
+ don't have to worry about them here. */
+
+static unsigned char break_insn[] = BREAKPOINT;
+
+/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes. */
+
+static unsigned char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT;
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+ support. We read the contents of the target location and stash it,
+ then overwrite it with a breakpoint instruction. ADDR is the target
+ location in the target machine. CONTENTS_CACHE is a pointer to
+ memory allocated for saving the target contents. It is guaranteed
+ by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+ is accomplished via BREAKPOINT_MAX). */
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ int val;
+
+ val = target_read_memory (addr, contents_cache, sizeof break_insn);
+
+ if (val == 0)
+ val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+
+ return val;
+}
+
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ return target_write_memory (addr, contents_cache, sizeof break_insn);
+}
+
+
+/* FIXME: This is a hack and should depend on the debugging target.
+ See comment in breakpoint.c where this is used. */
+
+int memory_breakpoint_size = sizeof (break_insn);
+
+
+#else /* BREAKPOINT */
+
+char nogo[] = "Breakpoints not implemented for this target.";
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ error (nogo);
+ return 0; /* lint */
+}
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ error (nogo);
+ return 0; /* lint */
+}
+
+int memory_breakpoint_size = -1;
+
+#endif /* BREAKPOINT */
diff --git a/gnu/usr.bin/gdb/gdb/minsyms.c b/gnu/usr.bin/gdb/gdb/minsyms.c
new file mode 100644
index 000000000000..dbb4e797d970
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/minsyms.c
@@ -0,0 +1,597 @@
+/* GDB routines for manipulating the minimal symbol tables.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file contains support routines for creating, manipulating, and
+ destroying minimal symbol tables.
+
+ Minimal symbol tables are used to hold some very basic information about
+ all defined global symbols (text, data, bss, abs, etc). The only two
+ required pieces of information are the symbol's name and the address
+ associated with that symbol.
+
+ In many cases, even if a file was compiled with no special options for
+ debugging at all, as long as was not stripped it will contain sufficient
+ information to build useful minimal symbol tables using this structure.
+
+ Even when a file contains enough debugging information to build a full
+ symbol table, these minimal symbols are still useful for quickly mapping
+ between names and addresses, and vice versa. They are also sometimes used
+ to figure out what full symbol table entries need to be read in. */
+
+
+#include "defs.h"
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "demangle.h"
+
+/* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE.
+ At the end, copy them all into one newly allocated location on an objfile's
+ symbol obstack. */
+
+#define BUNCH_SIZE 127
+
+struct msym_bunch
+{
+ struct msym_bunch *next;
+ struct minimal_symbol contents[BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct msym_bunch *msym_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int msym_bunch_index;
+
+/* Total number of minimal symbols recorded so far for the objfile. */
+
+static int msym_count;
+
+/* Prototypes for local functions. */
+
+static int
+compare_minimal_symbols PARAMS ((const void *, const void *));
+
+static int
+compact_minimal_symbols PARAMS ((struct minimal_symbol *, int));
+
+/* Look through all the current minimal symbol tables and find the first
+ minimal symbol that matches NAME. If OBJF is non-NULL, it specifies a
+ particular objfile and the search is limited to that objfile. Returns
+ a pointer to the minimal symbol that matches, or NULL if no match is found.
+
+ Note: One instance where there may be duplicate minimal symbols with
+ the same name is when the symbol tables for a shared library and the
+ symbol tables for an executable contain global symbols with the same
+ names (the dynamic linker deals with the duplication). */
+
+struct minimal_symbol *
+lookup_minimal_symbol (name, objf)
+ register const char *name;
+ struct objfile *objf;
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *found_symbol = NULL;
+ struct minimal_symbol *found_file_symbol = NULL;
+#ifdef IBM6000_TARGET
+ struct minimal_symbol *trampoline_symbol = NULL;
+#endif
+
+ for (objfile = object_files;
+ objfile != NULL && found_symbol == NULL;
+ objfile = objfile -> next)
+ {
+ if (objf == NULL || objf == objfile)
+ {
+ for (msymbol = objfile -> msymbols;
+ msymbol != NULL && SYMBOL_NAME (msymbol) != NULL &&
+ found_symbol == NULL;
+ msymbol++)
+ {
+ if (SYMBOL_MATCHES_NAME (msymbol, name))
+ {
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_file_text:
+ case mst_file_data:
+ case mst_file_bss:
+ /* It is file-local. If we find more than one, just
+ return the latest one (the user can't expect
+ useful behavior in that case). */
+ found_file_symbol = msymbol;
+ break;
+
+ case mst_unknown:
+#ifdef IBM6000_TARGET
+ /* I *think* all platforms using shared
+ libraries (and trampoline code) will suffer
+ this problem. Consider a case where there are
+ 5 shared libraries, each referencing `foo'
+ with a trampoline entry. When someone wants
+ to put a breakpoint on `foo' and the only
+ info we have is minimal symbol vector, we
+ want to use the real `foo', rather than one
+ of those trampoline entries. MGO */
+
+ /* If a trampoline symbol is found, we prefer to
+ keep looking for the *real* symbol. If the
+ actual symbol not found, then we'll use the
+ trampoline entry. Sorry for the machine
+ dependent code here, but I hope this will
+ benefit other platforms as well. For
+ trampoline entries, we used mst_unknown
+ earlier. Perhaps we should define a
+ `mst_trampoline' type?? */
+
+ if (trampoline_symbol == NULL)
+ trampoline_symbol = msymbol;
+ break;
+#else
+ /* FALLTHROUGH */
+#endif
+ default:
+ found_symbol = msymbol;
+ break;
+ }
+ }
+ }
+ }
+ }
+ /* External symbols are best. */
+ if (found_symbol)
+ return found_symbol;
+
+ /* File-local symbols are next best. */
+ if (found_file_symbol)
+ return found_file_symbol;
+
+ /* Symbols for IBM shared library trampolines are next best. */
+#ifdef IBM6000_TARGET
+ if (trampoline_symbol)
+ return trampoline_symbol;
+#endif
+
+ return NULL;
+}
+
+
+/* Search through the minimal symbol table for each objfile and find the
+ symbol whose address is the largest address that is still less than or
+ equal to PC. Returns a pointer to the minimal symbol if such a symbol
+ is found, or NULL if PC is not in a suitable range. Note that we need
+ to look through ALL the minimal symbol tables before deciding on the
+ symbol that comes closest to the specified PC. This is because objfiles
+ can overlap, for example objfile A has .text at 0x100 and .data at 0x40000
+ and objfile B has .text at 0x234 and .data at 0x40048. */
+
+struct minimal_symbol *
+lookup_minimal_symbol_by_pc (pc)
+ register CORE_ADDR pc;
+{
+ register int lo;
+ register int hi;
+ register int new;
+ register struct objfile *objfile;
+ register struct minimal_symbol *msymbol;
+ register struct minimal_symbol *best_symbol = NULL;
+
+ for (objfile = object_files;
+ objfile != NULL;
+ objfile = objfile -> next)
+ {
+ /* If this objfile has a minimal symbol table, go search it using
+ a binary search. Note that a minimal symbol table always consists
+ of at least two symbols, a "real" symbol and the terminating
+ "null symbol". If there are no real symbols, then there is no
+ minimal symbol table at all. */
+
+ if ((msymbol = objfile -> msymbols) != NULL)
+ {
+ lo = 0;
+ hi = objfile -> minimal_symbol_count - 1;
+
+ /* This code assumes that the minimal symbols are sorted by
+ ascending address values. If the pc value is greater than or
+ equal to the first symbol's address, then some symbol in this
+ minimal symbol table is a suitable candidate for being the
+ "best" symbol. This includes the last real symbol, for cases
+ where the pc value is larger than any address in this vector.
+
+ By iterating until the address associated with the current
+ hi index (the endpoint of the test interval) is less than
+ or equal to the desired pc value, we accomplish two things:
+ (1) the case where the pc value is larger than any minimal
+ symbol address is trivially solved, (2) the address associated
+ with the hi index is always the one we want when the interation
+ terminates. In essence, we are iterating the test interval
+ down until the pc value is pushed out of it from the high end.
+
+ Warning: this code is trickier than it would appear at first. */
+
+ /* Should also requires that pc is <= end of objfile. FIXME! */
+ if (pc >= SYMBOL_VALUE_ADDRESS (&msymbol[lo]))
+ {
+ while (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) > pc)
+ {
+ /* pc is still strictly less than highest address */
+ /* Note "new" will always be >= lo */
+ new = (lo + hi) / 2;
+ if ((SYMBOL_VALUE_ADDRESS (&msymbol[new]) >= pc) ||
+ (lo == new))
+ {
+ hi = new;
+ }
+ else
+ {
+ lo = new;
+ }
+ }
+ /* The minimal symbol indexed by hi now is the best one in this
+ objfile's minimal symbol table. See if it is the best one
+ overall. */
+
+ /* Skip any absolute symbols. This is apparently what adb
+ and dbx do, and is needed for the CM-5. There are two
+ known possible problems: (1) on ELF, apparently end, edata,
+ etc. are absolute. Not sure ignoring them here is a big
+ deal, but if we want to use them, the fix would go in
+ elfread.c. (2) I think shared library entry points on the
+ NeXT are absolute. If we want special handling for this
+ it probably should be triggered by a special
+ mst_abs_or_lib or some such. */
+ while (hi >= 0
+ && msymbol[hi].type == mst_abs)
+ --hi;
+
+ if (hi >= 0
+ && ((best_symbol == NULL) ||
+ (SYMBOL_VALUE_ADDRESS (best_symbol) <
+ SYMBOL_VALUE_ADDRESS (&msymbol[hi]))))
+ {
+ best_symbol = &msymbol[hi];
+ }
+ }
+ }
+ }
+ return (best_symbol);
+}
+
+/* Prepare to start collecting minimal symbols. Note that presetting
+ msym_bunch_index to BUNCH_SIZE causes the first call to save a minimal
+ symbol to allocate the memory for the first bunch. */
+
+void
+init_minimal_symbol_collection ()
+{
+ msym_count = 0;
+ msym_bunch = NULL;
+ msym_bunch_index = BUNCH_SIZE;
+}
+
+void
+prim_record_minimal_symbol (name, address, ms_type)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+{
+ register struct msym_bunch *new;
+ register struct minimal_symbol *msymbol;
+
+ if (msym_bunch_index == BUNCH_SIZE)
+ {
+ new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch));
+ msym_bunch_index = 0;
+ new -> next = msym_bunch;
+ msym_bunch = new;
+ }
+ msymbol = &msym_bunch -> contents[msym_bunch_index];
+ SYMBOL_NAME (msymbol) = (char *) name;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown);
+ SYMBOL_VALUE_ADDRESS (msymbol) = address;
+ SYMBOL_SECTION (msymbol) = -1;
+ MSYMBOL_TYPE (msymbol) = ms_type;
+ /* FIXME: This info, if it remains, needs its own field. */
+ MSYMBOL_INFO (msymbol) = NULL; /* FIXME! */
+ msym_bunch_index++;
+ msym_count++;
+}
+
+/* FIXME: Why don't we just combine this function with the one above
+ and pass it a NULL info pointer value if info is not needed? */
+
+void
+prim_record_minimal_symbol_and_info (name, address, ms_type, info, section)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ char *info;
+ int section;
+{
+ register struct msym_bunch *new;
+ register struct minimal_symbol *msymbol;
+
+ if (msym_bunch_index == BUNCH_SIZE)
+ {
+ new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch));
+ msym_bunch_index = 0;
+ new -> next = msym_bunch;
+ msym_bunch = new;
+ }
+ msymbol = &msym_bunch -> contents[msym_bunch_index];
+ SYMBOL_NAME (msymbol) = (char *) name;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown);
+ SYMBOL_VALUE_ADDRESS (msymbol) = address;
+ SYMBOL_SECTION (msymbol) = section;
+ MSYMBOL_TYPE (msymbol) = ms_type;
+ /* FIXME: This info, if it remains, needs its own field. */
+ MSYMBOL_INFO (msymbol) = info; /* FIXME! */
+ msym_bunch_index++;
+ msym_count++;
+}
+
+/* Compare two minimal symbols by address and return a signed result based
+ on unsigned comparisons, so that we sort into unsigned numeric order. */
+
+static int
+compare_minimal_symbols (fn1p, fn2p)
+ const PTR fn1p;
+ const PTR fn2p;
+{
+ register const struct minimal_symbol *fn1;
+ register const struct minimal_symbol *fn2;
+
+ fn1 = (const struct minimal_symbol *) fn1p;
+ fn2 = (const struct minimal_symbol *) fn2p;
+
+ if (SYMBOL_VALUE_ADDRESS (fn1) < SYMBOL_VALUE_ADDRESS (fn2))
+ {
+ return (-1);
+ }
+ else if (SYMBOL_VALUE_ADDRESS (fn1) > SYMBOL_VALUE_ADDRESS (fn2))
+ {
+ return (1);
+ }
+ else
+ {
+ return (0);
+ }
+}
+
+/* Discard the currently collected minimal symbols, if any. If we wish
+ to save them for later use, we must have already copied them somewhere
+ else before calling this function.
+
+ FIXME: We could allocate the minimal symbol bunches on their own
+ obstack and then simply blow the obstack away when we are done with
+ it. Is it worth the extra trouble though? */
+
+/* ARGSUSED */
+void
+discard_minimal_symbols (foo)
+ int foo;
+{
+ register struct msym_bunch *next;
+
+ while (msym_bunch != NULL)
+ {
+ next = msym_bunch -> next;
+ free ((PTR)msym_bunch);
+ msym_bunch = next;
+ }
+}
+
+/* Compact duplicate entries out of a minimal symbol table by walking
+ through the table and compacting out entries with duplicate addresses
+ and matching names. Return the number of entries remaining.
+
+ On entry, the table resides between msymbol[0] and msymbol[mcount].
+ On exit, it resides between msymbol[0] and msymbol[result_count].
+
+ When files contain multiple sources of symbol information, it is
+ possible for the minimal symbol table to contain many duplicate entries.
+ As an example, SVR4 systems use ELF formatted object files, which
+ usually contain at least two different types of symbol tables (a
+ standard ELF one and a smaller dynamic linking table), as well as
+ DWARF debugging information for files compiled with -g.
+
+ Without compacting, the minimal symbol table for gdb itself contains
+ over a 1000 duplicates, about a third of the total table size. Aside
+ from the potential trap of not noticing that two successive entries
+ identify the same location, this duplication impacts the time required
+ to linearly scan the table, which is done in a number of places. So we
+ just do one linear scan here and toss out the duplicates.
+
+ Note that we are not concerned here about recovering the space that
+ is potentially freed up, because the strings themselves are allocated
+ on the symbol_obstack, and will get automatically freed when the symbol
+ table is freed. The caller can free up the unused minimal symbols at
+ the end of the compacted region if their allocation strategy allows it.
+
+ Also note we only go up to the next to last entry within the loop
+ and then copy the last entry explicitly after the loop terminates.
+
+ Since the different sources of information for each symbol may
+ have different levels of "completeness", we may have duplicates
+ that have one entry with type "mst_unknown" and the other with a
+ known type. So if the one we are leaving alone has type mst_unknown,
+ overwrite its type with the type from the one we are compacting out. */
+
+static int
+compact_minimal_symbols (msymbol, mcount)
+ struct minimal_symbol *msymbol;
+ int mcount;
+{
+ struct minimal_symbol *copyfrom;
+ struct minimal_symbol *copyto;
+
+ if (mcount > 0)
+ {
+ copyfrom = copyto = msymbol;
+ while (copyfrom < msymbol + mcount - 1)
+ {
+ if (SYMBOL_VALUE_ADDRESS (copyfrom) ==
+ SYMBOL_VALUE_ADDRESS ((copyfrom + 1)) &&
+ (STREQ (SYMBOL_NAME (copyfrom), SYMBOL_NAME ((copyfrom + 1)))))
+ {
+ if (MSYMBOL_TYPE((copyfrom + 1)) == mst_unknown)
+ {
+ MSYMBOL_TYPE ((copyfrom + 1)) = MSYMBOL_TYPE (copyfrom);
+ }
+ copyfrom++;
+ }
+ else
+ {
+ *copyto++ = *copyfrom++;
+ }
+ }
+ *copyto++ = *copyfrom++;
+ mcount = copyto - msymbol;
+ }
+ return (mcount);
+}
+
+/* Add the minimal symbols in the existing bunches to the objfile's official
+ minimal symbol table. In most cases there is no minimal symbol table yet
+ for this objfile, and the existing bunches are used to create one. Once
+ in a while (for shared libraries for example), we add symbols (e.g. common
+ symbols) to an existing objfile.
+
+ Because of the way minimal symbols are collected, we generally have no way
+ of knowing what source language applies to any particular minimal symbol.
+ Specifically, we have no way of knowing if the minimal symbol comes from a
+ C++ compilation unit or not. So for the sake of supporting cached
+ demangled C++ names, we have no choice but to try and demangle each new one
+ that comes in. If the demangling succeeds, then we assume it is a C++
+ symbol and set the symbol's language and demangled name fields
+ appropriately. Note that in order to avoid unnecessary demanglings, and
+ allocating obstack space that subsequently can't be freed for the demangled
+ names, we mark all newly added symbols with language_auto. After
+ compaction of the minimal symbols, we go back and scan the entire minimal
+ symbol table looking for these new symbols. For each new symbol we attempt
+ to demangle it, and if successful, record it as a language_cplus symbol
+ and cache the demangled form on the symbol obstack. Symbols which don't
+ demangle are marked as language_unknown symbols, which inhibits future
+ attempts to demangle them if we later add more minimal symbols. */
+
+void
+install_minimal_symbols (objfile)
+ struct objfile *objfile;
+{
+ register int bindex;
+ register int mcount;
+ register struct msym_bunch *bunch;
+ register struct minimal_symbol *msymbols;
+ int alloc_count;
+ register char leading_char;
+
+ if (msym_count > 0)
+ {
+ /* Allocate enough space in the obstack, into which we will gather the
+ bunches of new and existing minimal symbols, sort them, and then
+ compact out the duplicate entries. Once we have a final table,
+ we will give back the excess space. */
+
+ alloc_count = msym_count + objfile->minimal_symbol_count + 1;
+ obstack_blank (&objfile->symbol_obstack,
+ alloc_count * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_base (&objfile->symbol_obstack);
+
+ /* Copy in the existing minimal symbols, if there are any. */
+
+ if (objfile->minimal_symbol_count)
+ memcpy ((char *)msymbols, (char *)objfile->msymbols,
+ objfile->minimal_symbol_count * sizeof (struct minimal_symbol));
+
+ /* Walk through the list of minimal symbol bunches, adding each symbol
+ to the new contiguous array of symbols. Note that we start with the
+ current, possibly partially filled bunch (thus we use the current
+ msym_bunch_index for the first bunch we copy over), and thereafter
+ each bunch is full. */
+
+ mcount = objfile->minimal_symbol_count;
+ leading_char = bfd_get_symbol_leading_char (objfile->obfd);
+
+ for (bunch = msym_bunch; bunch != NULL; bunch = bunch -> next)
+ {
+ for (bindex = 0; bindex < msym_bunch_index; bindex++, mcount++)
+ {
+ msymbols[mcount] = bunch -> contents[bindex];
+ SYMBOL_LANGUAGE (&msymbols[mcount]) = language_auto;
+ if (SYMBOL_NAME (&msymbols[mcount])[0] == leading_char)
+ {
+ SYMBOL_NAME(&msymbols[mcount])++;
+ }
+ }
+ msym_bunch_index = BUNCH_SIZE;
+ }
+
+ /* Sort the minimal symbols by address. */
+
+ qsort (msymbols, mcount, sizeof (struct minimal_symbol),
+ compare_minimal_symbols);
+
+ /* Compact out any duplicates, and free up whatever space we are
+ no longer using. */
+
+ mcount = compact_minimal_symbols (msymbols, mcount);
+
+ obstack_blank (&objfile->symbol_obstack,
+ (mcount + 1 - alloc_count) * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_finish (&objfile->symbol_obstack);
+
+ /* We also terminate the minimal symbol table with a "null symbol",
+ which is *not* included in the size of the table. This makes it
+ easier to find the end of the table when we are handed a pointer
+ to some symbol in the middle of it. Zero out the fields in the
+ "null symbol" allocated at the end of the array. Note that the
+ symbol count does *not* include this null symbol, which is why it
+ is indexed by mcount and not mcount-1. */
+
+ SYMBOL_NAME (&msymbols[mcount]) = NULL;
+ SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0;
+ MSYMBOL_INFO (&msymbols[mcount]) = NULL;
+ MSYMBOL_TYPE (&msymbols[mcount]) = mst_unknown;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (&msymbols[mcount], language_unknown);
+
+ /* Attach the minimal symbol table to the specified objfile.
+ The strings themselves are also located in the symbol_obstack
+ of this objfile. */
+
+ objfile -> minimal_symbol_count = mcount;
+ objfile -> msymbols = msymbols;
+
+ /* Now walk through all the minimal symbols, selecting the newly added
+ ones and attempting to cache their C++ demangled names. */
+
+ for ( ; mcount-- > 0 ; msymbols++)
+ {
+ SYMBOL_INIT_DEMANGLED_NAME (msymbols, &objfile->symbol_obstack);
+ }
+ }
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/mipsread.c b/gnu/usr.bin/gdb/gdb/mipsread.c
new file mode 100644
index 000000000000..199092bb5c39
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mipsread.c
@@ -0,0 +1,3653 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+ Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU. Major work
+ by Per Bothner, John Gilmore and Ian Lance Taylor at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides three functions: mipscoff_symfile_init,
+ which initializes to read a symbol file; mipscoff_new_init, which
+ discards existing cached information when all symbols are being
+ discarded; and mipscoff_symfile_read, which reads a symbol table
+ from a file.
+
+ mipscoff_symfile_read only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real. mipscoff_psymtab_to_symtab() is called indirectly through
+ a pointer in the psymtab to do this.
+
+ ECOFF symbol tables are mostly written in the byte order of the
+ target machine. However, one section of the table (the auxiliary
+ symbol information) is written in the host byte order. There is a
+ bit in the other symbol info which describes which host byte order
+ was used. ECOFF thereby takes the trophy from Intel `b.out' for
+ the most brain-dead adaptation of a file format to byte order.
+
+ This module can read all four of the known byte-order combinations,
+ on any type of host. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "obstack.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "complaints.h"
+
+/* These are needed if the tm.h file does not contain the necessary
+ mips specific definitions. */
+
+#ifndef MIPS_EFI_SYMBOL_NAME
+#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+typedef struct mips_extra_func_info {
+ long numargs;
+ PDR pdr;
+} *mips_extra_func_info_t;
+#ifndef RA_REGNUM
+#define RA_REGNUM 0
+#endif
+#endif
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "gdb-stabs.h"
+
+#include "bfd.h"
+
+#include "coff/internal.h"
+#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */
+
+/* FIXME: coff/internal.h and aout/aout64.h both define N_ABS. We
+ want the definition from aout/aout64.h. */
+#undef N_ABS
+
+#include "libaout.h" /* Private BFD a.out information. */
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h" /* STABS information */
+
+/* FIXME: libcoff.h and libaout.h both define a couple of macros. We
+ don't use them. */
+#undef exec_hdr
+#undef obj_sym_filepos
+
+#include "libcoff.h" /* Private BFD COFF information. */
+#include "libecoff.h" /* Private BFD ECOFF information. */
+
+#include "expression.h"
+#include "language.h" /* Needed inside partial-stab.h */
+
+/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */
+#ifndef ECOFF_REG_TO_REGNUM
+#define ECOFF_REG_TO_REGNUM(num) (num)
+#endif
+
+/* Information is passed among various mipsread routines for accessing
+ symbol files. A pointer to this structure is kept in the sym_private
+ field of the objfile struct. */
+
+struct ecoff_symfile_info {
+ struct mips_pending **pending_list;
+};
+#define ECOFF_SYMFILE_INFO(o) ((struct ecoff_symfile_info *)((o)->sym_private))
+#define ECOFF_PENDING_LIST(o) (ECOFF_SYMFILE_INFO(o)->pending_list)
+
+
+/* Each partial symbol table entry contains a pointer to private data
+ for the read_symtab() function to use when expanding a partial
+ symbol table entry to a full symbol table entry.
+
+ For mipsread this structure contains the index of the FDR that this
+ psymtab represents and a pointer to the BFD that the psymtab was
+ created from. */
+
+#define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private)
+#define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx)
+#define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd)
+
+struct symloc
+{
+ int fdr_idx;
+ bfd *cur_bfd;
+ EXTR *extern_tab; /* Pointer to external symbols for this file. */
+ int extern_count; /* Size of extern_tab. */
+ enum language pst_language;
+};
+
+/* Things we import explicitly from other modules */
+
+extern int info_verbose;
+
+/* Various complaints about symbol reading that don't abort the process */
+
+struct complaint bad_file_number_complaint =
+{"bad file number %d", 0, 0};
+
+struct complaint index_complaint =
+{"bad aux index at symbol %s", 0, 0};
+
+struct complaint aux_index_complaint =
+{"bad proc end in aux found from symbol %s", 0, 0};
+
+struct complaint block_index_complaint =
+{"bad aux index at block symbol %s", 0, 0};
+
+struct complaint unknown_ext_complaint =
+{"unknown external symbol %s", 0, 0};
+
+struct complaint unknown_sym_complaint =
+{"unknown local symbol %s", 0, 0};
+
+struct complaint unknown_st_complaint =
+{"with type %d", 0, 0};
+
+struct complaint block_overflow_complaint =
+{"block containing %s overfilled", 0, 0};
+
+struct complaint basic_type_complaint =
+{"cannot map MIPS basic type 0x%x for %s", 0, 0};
+
+struct complaint unknown_type_qual_complaint =
+{"unknown type qualifier 0x%x", 0, 0};
+
+struct complaint array_index_type_complaint =
+{"illegal array index type for %s, assuming int", 0, 0};
+
+struct complaint bad_tag_guess_complaint =
+{"guessed tag type of %s incorrectly", 0, 0};
+
+struct complaint block_member_complaint =
+{"declaration block contains unhandled symbol type %d", 0, 0};
+
+struct complaint stEnd_complaint =
+{"stEnd with storage class %d not handled", 0, 0};
+
+struct complaint unknown_mips_symtype_complaint =
+{"unknown symbol type 0x%x", 0, 0};
+
+struct complaint stab_unknown_complaint =
+{"unknown stabs symbol %s", 0, 0};
+
+struct complaint pdr_for_nonsymbol_complaint =
+{"PDR for %s, but no symbol", 0, 0};
+
+struct complaint pdr_static_symbol_complaint =
+{"can't handle PDR for static proc at 0x%lx", 0, 0};
+
+struct complaint bad_setjmp_pdr_complaint =
+{"fixing bad setjmp PDR from libc", 0, 0};
+
+struct complaint bad_fbitfield_complaint =
+{"can't handle TIR fBitfield for %s", 0, 0};
+
+struct complaint bad_continued_complaint =
+{"illegal TIR continued for %s", 0, 0};
+
+struct complaint bad_rfd_entry_complaint =
+{"bad rfd entry for %s: file %d, index %d", 0, 0};
+
+struct complaint unexpected_type_code_complaint =
+{"unexpected type code for %s", 0, 0};
+
+struct complaint unable_to_cross_ref_complaint =
+{"unable to cross ref btTypedef for %s", 0, 0};
+
+struct complaint illegal_forward_tq0_complaint =
+{"illegal tq0 in forward typedef for %s", 0, 0};
+
+struct complaint illegal_forward_bt_complaint =
+{"illegal bt %d in forward typedef for %s", 0, 0};
+
+struct complaint bad_linetable_guess_complaint =
+{"guessed size of linetable for %s incorrectly", 0, 0};
+
+/* Macros and extra defs */
+
+/* Puns: hard to find whether -g was used and how */
+
+#define MIN_GLEVEL GLEVEL_0
+#define compare_glevel(a,b) \
+ (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \
+ ((b) == GLEVEL_3) ? -1 : (int)((b) - (a)))
+
+/* Things that really are local to this module */
+
+/* Remember what we deduced to be the source language of this psymtab. */
+
+static enum language psymtab_language = language_unknown;
+
+/* Current BFD. */
+
+static bfd *cur_bfd;
+
+/* Pointer to current file decriptor record, and its index */
+
+static FDR *cur_fdr;
+static int cur_fd;
+
+/* Index of current symbol */
+
+static int cur_sdx;
+
+/* Note how much "debuggable" this image is. We would like
+ to see at least one FDR with full symbols */
+
+static max_gdbinfo;
+static max_glevel;
+
+/* When examining .o files, report on undefined symbols */
+
+static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs;
+
+/* Pseudo symbol to use when putting stabs into the symbol table. */
+
+static char stabs_symbol[] = STABS_SYMBOL;
+
+/* Extra builtin types */
+
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_fixed_dec;
+struct type *builtin_type_float_dec;
+struct type *builtin_type_string;
+
+/* Forward declarations */
+
+static void
+read_mips_symtab PARAMS ((struct objfile *, struct section_offsets *));
+
+static void
+read_the_mips_symtab PARAMS ((bfd *));
+
+static int
+upgrade_type PARAMS ((int, struct type **, int, union aux_ext *, int, char *));
+
+static void
+parse_partial_symbols PARAMS ((struct objfile *,
+ struct section_offsets *));
+
+static int
+cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code,
+ char **, int, char *));
+
+static void
+fixup_sigtramp PARAMS ((void));
+
+static struct symbol *
+new_symbol PARAMS ((char *));
+
+static struct type *
+new_type PARAMS ((char *));
+
+static struct block *
+new_block PARAMS ((int));
+
+static struct symtab *
+new_symtab PARAMS ((char *, int, int, struct objfile *));
+
+static struct linetable *
+new_linetable PARAMS ((int));
+
+static struct blockvector *
+new_bvect PARAMS ((int));
+
+static int
+parse_symbol PARAMS ((SYMR *, union aux_ext *, char *, int));
+
+static struct type *
+parse_type PARAMS ((int, union aux_ext *, unsigned int, int *, int, char *));
+
+static struct symbol *
+mylookup_symbol PARAMS ((char *, struct block *, enum namespace,
+ enum address_class));
+
+static struct block *
+shrink_block PARAMS ((struct block *, struct symtab *));
+
+static PTR
+xzalloc PARAMS ((unsigned int));
+
+static void
+sort_blocks PARAMS ((struct symtab *));
+
+static int
+compare_blocks PARAMS ((const void *, const void *));
+
+static struct partial_symtab *
+new_psymtab PARAMS ((char *, struct objfile *));
+
+static void
+psymtab_to_symtab_1 PARAMS ((struct partial_symtab *, char *));
+
+static void
+add_block PARAMS ((struct block *, struct symtab *));
+
+static void
+add_symbol PARAMS ((struct symbol *, struct block *));
+
+static int
+add_line PARAMS ((struct linetable *, int, CORE_ADDR, int));
+
+static struct linetable *
+shrink_linetable PARAMS ((struct linetable *));
+
+static char *
+mips_next_symbol_text PARAMS ((void));
+
+/* Things we export to other modules */
+
+/* Address bounds for the signal trampoline in inferior, if any */
+/* FIXME: Nothing really seems to use this. Why is it here? */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+static void
+mipscoff_new_init (ignore)
+ struct objfile *ignore;
+{
+ sigtramp_address = 0;
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+static void
+mipscoff_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_private != NULL)
+ {
+ mfree (objfile->md, objfile->sym_private);
+ }
+ objfile->sym_private = (PTR)
+ xmmalloc (objfile->md, sizeof (struct ecoff_symfile_info));
+}
+
+static void
+mipscoff_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ struct cleanup * back_to;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ read_mips_symtab (objfile, section_offsets);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+mipscoff_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_private != NULL)
+ {
+ mfree (objfile->md, objfile->sym_private);
+ }
+
+ cur_bfd = 0;
+}
+
+/* Allocate zeroed memory */
+
+static PTR
+xzalloc (size)
+ unsigned int size;
+{
+ PTR p = xmalloc (size);
+
+ memset (p, 0, size);
+ return p;
+}
+
+/* Exported procedure: Builds a symtab from the PST partial one.
+ Restores the environment in effect when PST was created, delegates
+ most of the work to an ancillary procedure, and sorts
+ and reorders the symtab list at the end */
+
+static void
+mipscoff_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+
+ if (!pst)
+ return;
+
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ fflush (stdout);
+ }
+
+ next_symbol_text_func = mips_next_symbol_text;
+
+ psymtab_to_symtab_1 (pst, pst->filename);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ if (info_verbose)
+ printf_filtered ("done.\n");
+}
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int
+in_sigtramp (pc, ignore)
+ CORE_ADDR pc;
+ char *ignore; /* function name */
+{
+ if (sigtramp_address == 0)
+ fixup_sigtramp ();
+ return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+/* File-level interface functions */
+
+/* Read the symtab information from file ABFD into memory. */
+
+static void
+read_the_mips_symtab (abfd)
+ bfd *abfd;
+{
+ if (ecoff_slurp_symbolic_info (abfd) == false)
+ error ("Error reading symbol table: %s", bfd_errmsg (bfd_error));
+}
+
+/* Find a file descriptor given its index RF relative to a file CF */
+
+static FDR *
+get_rfd (cf, rf)
+ int cf, rf;
+{
+ FDR *fdrs;
+ register FDR *f;
+ RFDT rfd;
+
+ fdrs = ecoff_data (cur_bfd)->fdr;
+ f = fdrs + cf;
+ /* Object files do not have the RFD table, all refs are absolute */
+ if (f->rfdBase == 0)
+ return fdrs + rf;
+ (*ecoff_backend (cur_bfd)->swap_rfd_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_rfd
+ + (f->rfdBase + rf) * ecoff_backend (cur_bfd)->external_rfd_size),
+ &rfd);
+ return fdrs + rfd;
+}
+
+/* Return a safer print NAME for a file descriptor */
+
+static char *
+fdr_name (f)
+ FDR *f;
+{
+ if (f->rss == -1)
+ return "<stripped file>";
+ if (f->rss == 0)
+ return "<NFY>";
+ return ecoff_data (cur_bfd)->ss + f->issBase + f->rss;
+}
+
+
+/* Read in and parse the symtab of the file OBJFILE. Symbols from
+ different sections are relocated via the SECTION_OFFSETS. */
+
+static void
+read_mips_symtab (objfile, section_offsets)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+{
+ cur_bfd = objfile->obfd;
+
+ read_the_mips_symtab (objfile->obfd);
+
+ parse_partial_symbols (objfile, section_offsets);
+
+#if 0
+ /* Check to make sure file was compiled with -g. If not, warn the
+ user of this limitation. */
+ if (compare_glevel (max_glevel, GLEVEL_2) < 0)
+ {
+ if (max_gdbinfo == 0)
+ printf ("\n%s not compiled with -g, debugging support is limited.\n",
+ objfile->name);
+ printf ("You should compile with -g2 or -g3 for best debugging support.\n");
+ fflush (stdout);
+ }
+#endif
+}
+
+/* Local utilities */
+
+/* Map of FDR indexes to partial symtabs */
+
+struct pst_map
+{
+ struct partial_symtab *pst; /* the psymtab proper */
+ long n_globals; /* exported globals (external symbols) */
+ long globals_offset; /* cumulative */
+};
+
+
+/* Utility stack, used to nest procedures and blocks properly.
+ It is a doubly linked list, to avoid too many alloc/free.
+ Since we might need it quite a few times it is NOT deallocated
+ after use. */
+
+static struct parse_stack
+{
+ struct parse_stack *next, *prev;
+ struct symtab *cur_st; /* Current symtab. */
+ struct block *cur_block; /* Block in it. */
+ int blocktype; /* What are we parsing. */
+ int maxsyms; /* Max symbols in this block. */
+ struct type *cur_type; /* Type we parse fields for. */
+ int cur_field; /* Field number in cur_type. */
+ CORE_ADDR procadr; /* Start addres of this procedure */
+ int numargs; /* Its argument count */
+}
+
+ *top_stack; /* Top stack ptr */
+
+
+/* Enter a new lexical context */
+
+static void
+push_parse_stack ()
+{
+ struct parse_stack *new;
+
+ /* Reuse frames if possible */
+ if (top_stack && top_stack->prev)
+ new = top_stack->prev;
+ else
+ new = (struct parse_stack *) xzalloc (sizeof (struct parse_stack));
+ /* Initialize new frame with previous content */
+ if (top_stack)
+ {
+ register struct parse_stack *prev = new->prev;
+
+ *new = *top_stack;
+ top_stack->prev = new;
+ new->prev = prev;
+ new->next = top_stack;
+ }
+ top_stack = new;
+}
+
+/* Exit a lexical context */
+
+static void
+pop_parse_stack ()
+{
+ if (!top_stack)
+ return;
+ if (top_stack->next)
+ top_stack = top_stack->next;
+}
+
+
+/* Cross-references might be to things we haven't looked at
+ yet, e.g. type references. To avoid too many type
+ duplications we keep a quick fixup table, an array
+ of lists of references indexed by file descriptor */
+
+struct mips_pending
+{
+ struct mips_pending *next; /* link */
+ char *s; /* the unswapped symbol */
+ struct type *t; /* its partial type descriptor */
+};
+
+
+/* Check whether we already saw symbol SH in file FH */
+
+static struct mips_pending *
+is_pending_symbol (fh, sh)
+ FDR *fh;
+ char *sh;
+{
+ int f_idx = fh - ecoff_data (cur_bfd)->fdr;
+ register struct mips_pending *p;
+ struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile);
+
+ /* Linear search is ok, list is typically no more than 10 deep */
+ for (p = pending_list[f_idx]; p; p = p->next)
+ if (p->s == sh)
+ break;
+ return p;
+}
+
+/* Add a new symbol SH of type T */
+
+static void
+add_pending (fh, sh, t)
+ FDR *fh;
+ char *sh;
+ struct type *t;
+{
+ int f_idx = fh - ecoff_data (cur_bfd)->fdr;
+ struct mips_pending *p = is_pending_symbol (fh, sh);
+
+ /* Make sure we do not make duplicates */
+ if (!p)
+ {
+ struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile);
+
+ p = ((struct mips_pending *)
+ obstack_alloc (&current_objfile->psymbol_obstack,
+ sizeof (struct mips_pending)));
+ p->s = sh;
+ p->t = t;
+ p->next = pending_list[f_idx];
+ pending_list[f_idx] = p;
+ }
+}
+
+
+/* Parsing Routines proper. */
+
+/* Parse a single symbol. Mostly just make up a GDB symbol for it.
+ For blocks, procedures and types we open a new lexical context.
+ This is basically just a big switch on the symbol's type. Argument
+ AX is the base pointer of aux symbols for this file (fh->iauxBase).
+ EXT_SH points to the unswapped symbol, which is needed for struct,
+ union, etc., types; it is NULL for an EXTR. BIGEND says whether
+ aux symbols are big-endian or little-endian. Return count of
+ SYMR's handled (normally one). */
+
+static int
+parse_symbol (sh, ax, ext_sh, bigend)
+ SYMR *sh;
+ union aux_ext *ax;
+ char *ext_sh;
+ int bigend;
+{
+ const bfd_size_type external_sym_size
+ = ecoff_backend (cur_bfd)->external_sym_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) =
+ ecoff_backend (cur_bfd)->swap_sym_in;
+ char *name;
+ struct symbol *s;
+ struct block *b;
+ struct mips_pending *pend;
+ struct type *t;
+ struct field *f;
+ int count = 1;
+ enum address_class class;
+ TIR tir;
+ long svalue = sh->value;
+ int bitsize;
+
+ if (ext_sh == (char *) NULL)
+ name = ecoff_data (cur_bfd)->ssext + sh->iss;
+ else
+ name = ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh->iss;
+
+ switch (sh->st)
+ {
+ case stNil:
+ break;
+
+ case stGlobal: /* external symbol, goes into global block */
+ class = LOC_STATIC;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st),
+ GLOBAL_BLOCK);
+ s = new_symbol (name);
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ goto data;
+
+ case stStatic: /* static data, goes into current block. */
+ class = LOC_STATIC;
+ b = top_stack->cur_block;
+ s = new_symbol (name);
+ if (sh->sc == scCommon)
+ {
+ /* It is a FORTRAN common block. At least for SGI Fortran the
+ address is not in the symbol; we need to fix it later in
+ scan_file_globals. */
+ int bucket = hashname (SYMBOL_NAME (s));
+ SYMBOL_VALUE_CHAIN (s) = global_sym_chain[bucket];
+ global_sym_chain[bucket] = s;
+ }
+ else
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ goto data;
+
+ case stLocal: /* local variable, goes into current block */
+ if (sh->sc == scRegister)
+ {
+ class = LOC_REGISTER;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ }
+ else
+ class = LOC_LOCAL;
+ b = top_stack->cur_block;
+ s = new_symbol (name);
+ SYMBOL_VALUE (s) = svalue;
+
+ data: /* Common code for symbols describing data */
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = class;
+ add_symbol (s, b);
+
+ /* Type could be missing in a number of cases */
+ if (sh->sc == scUndefined || sh->sc == scNil ||
+ sh->index == 0xfffff)
+ SYMBOL_TYPE (s) = builtin_type_int; /* undefined? */
+ else
+ SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name);
+ /* Value of a data symbol is its memory address */
+ break;
+
+ case stParam: /* arg to procedure, goes into current block */
+ max_gdbinfo++;
+ top_stack->numargs++;
+
+ /* Special GNU C++ name. */
+ if (name[0] == CPLUS_MARKER && name[1] == 't' && name[2] == 0)
+ name = "this"; /* FIXME, not alloc'd in obstack */
+ s = new_symbol (name);
+
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ switch (sh->sc)
+ {
+ case scRegister:
+ /* Pass by value in register. */
+ SYMBOL_CLASS(s) = LOC_REGPARM;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ break;
+ case scVar:
+ /* Pass by reference on stack. */
+ SYMBOL_CLASS(s) = LOC_REF_ARG;
+ break;
+ case scVarRegister:
+ /* Pass by reference in register. */
+ SYMBOL_CLASS(s) = LOC_REGPARM_ADDR;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ break;
+ default:
+ /* Pass by value on stack. */
+ SYMBOL_CLASS(s) = LOC_ARG;
+ break;
+ }
+ SYMBOL_VALUE (s) = svalue;
+ SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name);
+ add_symbol (s, top_stack->cur_block);
+#if 0
+ /* FIXME: This has not been tested. See dbxread.c */
+ /* Add the type of this parameter to the function/procedure
+ type of this block. */
+ add_param_to_type (&top_stack->cur_block->function->type, s);
+#endif
+ break;
+
+ case stLabel: /* label, goes into current block */
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; /* so that it can be used */
+ SYMBOL_CLASS (s) = LOC_LABEL; /* but not misused */
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ SYMBOL_TYPE (s) = builtin_type_int;
+ add_symbol (s, top_stack->cur_block);
+ break;
+
+ case stProc: /* Procedure, usually goes into global block */
+ case stStaticProc: /* Static procedure, goes into current block */
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ /* Type of the return value */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ t = builtin_type_int;
+ else
+ t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name);
+ b = top_stack->cur_block;
+ if (sh->st == stProc)
+ {
+ struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st);
+ /* The next test should normally be true,
+ but provides a hook for nested functions
+ (which we don't want to make global). */
+ if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ }
+ add_symbol (s, b);
+
+ /* Make a type for the procedure itself */
+#if 0
+ /* FIXME: This has not been tested yet! See dbxread.c */
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ memcpy (lookup_function_type (t), SYMBOL_TYPE (s), sizeof (struct type));
+#else
+ SYMBOL_TYPE (s) = lookup_function_type (t);
+#endif
+
+ /* Create and enter a new lexical context */
+ b = new_block (top_stack->maxsyms);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_START (b) = BLOCK_END (b) = sh->value;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ add_block (b, top_stack->cur_st);
+
+ /* Not if we only have partial info */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ break;
+
+ push_parse_stack ();
+ top_stack->cur_block = b;
+ top_stack->blocktype = sh->st;
+ top_stack->cur_type = SYMBOL_TYPE (s);
+ top_stack->cur_field = -1;
+ top_stack->procadr = sh->value;
+ top_stack->numargs = 0;
+ break;
+
+ /* Beginning of code for structure, union, and enum definitions.
+ They all share a common set of local variables, defined here. */
+ {
+ enum type_code type_code;
+ char *ext_tsym;
+ int nfields;
+ long max_value;
+ struct field *f;
+
+ case stStruct: /* Start a block defining a struct type */
+ type_code = TYPE_CODE_STRUCT;
+ goto structured_common;
+
+ case stUnion: /* Start a block defining a union type */
+ type_code = TYPE_CODE_UNION;
+ goto structured_common;
+
+ case stEnum: /* Start a block defining an enum type */
+ type_code = TYPE_CODE_ENUM;
+ goto structured_common;
+
+ case stBlock: /* Either a lexical block, or some type */
+ if (sh->sc != scInfo && sh->sc != scCommon)
+ goto case_stBlock_code; /* Lexical block */
+
+ type_code = TYPE_CODE_UNDEF; /* We have a type. */
+
+ /* Common code for handling struct, union, enum, and/or as-yet-
+ unknown-type blocks of info about structured data. `type_code'
+ has been set to the proper TYPE_CODE, if we know it. */
+ structured_common:
+ push_parse_stack ();
+ top_stack->blocktype = stBlock;
+
+ /* First count the number of fields and the highest value. */
+ nfields = 0;
+ max_value = 0;
+ for (ext_tsym = ext_sh + external_sym_size;
+ ;
+ ext_tsym += external_sym_size)
+ {
+ SYMR tsym;
+
+ (*swap_sym_in) (cur_bfd, ext_tsym, &tsym);
+
+ switch (tsym.st)
+ {
+ case stEnd:
+ goto end_of_fields;
+
+ case stMember:
+ if (nfields == 0 && type_code == TYPE_CODE_UNDEF)
+ /* If the type of the member is Nil (or Void),
+ without qualifiers, assume the tag is an
+ enumeration. */
+ if (tsym.index == indexNil)
+ type_code = TYPE_CODE_ENUM;
+ else
+ {
+ ecoff_swap_tir_in (bigend,
+ &ax[tsym.index].a_ti,
+ &tir);
+ if ((tir.bt == btNil || tir.bt == btVoid)
+ && tir.tq0 == tqNil)
+ type_code = TYPE_CODE_ENUM;
+ }
+ nfields++;
+ if (tsym.value > max_value)
+ max_value = tsym.value;
+ break;
+
+ case stBlock:
+ case stUnion:
+ case stEnum:
+ case stStruct:
+ {
+#if 0
+ /* This is a no-op; is it trying to tell us something
+ we should be checking? */
+ if (tsym.sc == scVariant); /*UNIMPLEMENTED*/
+#endif
+ if (tsym.index != 0)
+ {
+ /* This is something like a struct within a
+ struct. Skip over the fields of the inner
+ struct. The -1 is because the for loop will
+ increment ext_tsym. */
+ ext_tsym = ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((cur_fdr->isymBase + tsym.index - 1)
+ * external_sym_size));
+ }
+ }
+ break;
+
+ case stTypedef:
+ /* mips cc puts out a typedef for struct x if it is not yet
+ defined when it encounters
+ struct y { struct x *xp; };
+ Just ignore it. */
+ break;
+
+ default:
+ complain (&block_member_complaint, tsym.st);
+ }
+ }
+ end_of_fields:;
+
+ /* In an stBlock, there is no way to distinguish structs,
+ unions, and enums at this point. This is a bug in the
+ original design (that has been fixed with the recent
+ addition of the stStruct, stUnion, and stEnum symbol
+ types.) The way you can tell is if/when you see a variable
+ or field of that type. In that case the variable's type
+ (in the AUX table) says if the type is struct, union, or
+ enum, and points back to the stBlock here. So you can
+ patch the tag kind up later - but only if there actually is
+ a variable or field of that type.
+
+ So until we know for sure, we will guess at this point.
+ The heuristic is:
+ If the first member has index==indexNil or a void type,
+ assume we have an enumeration.
+ Otherwise, if there is more than one member, and all
+ the members have offset 0, assume we have a union.
+ Otherwise, assume we have a struct.
+
+ The heuristic could guess wrong in the case of of an
+ enumeration with no members or a union with one (or zero)
+ members, or when all except the last field of a struct have
+ width zero. These are uncommon and/or illegal situations,
+ and in any case guessing wrong probably doesn't matter
+ much.
+
+ But if we later do find out we were wrong, we fixup the tag
+ kind. Members of an enumeration must be handled
+ differently from struct/union fields, and that is harder to
+ patch up, but luckily we shouldn't need to. (If there are
+ any enumeration members, we can tell for sure it's an enum
+ here.) */
+
+ if (type_code == TYPE_CODE_UNDEF)
+ if (nfields > 1 && max_value == 0)
+ type_code = TYPE_CODE_UNION;
+ else
+ type_code = TYPE_CODE_STRUCT;
+
+ /* Create a new type or use the pending type. */
+ pend = is_pending_symbol (cur_fdr, ext_sh);
+ if (pend == (struct mips_pending *) NULL)
+ {
+ t = new_type (NULL);
+ add_pending (cur_fdr, ext_sh, t);
+ }
+ else
+ t = pend->t;
+
+ /* Alpha cc unnamed structs do not get a tag name. */
+ if (sh->iss == 0)
+ TYPE_TAG_NAME (t) = NULL;
+ else
+ TYPE_TAG_NAME (t) = obconcat (&current_objfile->symbol_obstack,
+ "", "", name);
+
+ TYPE_CODE (t) = type_code;
+ TYPE_LENGTH (t) = sh->value;
+ TYPE_NFIELDS (t) = nfields;
+ TYPE_FIELDS (t) = f = ((struct field *)
+ TYPE_ALLOC (t,
+ nfields * sizeof (struct field)));
+
+ if (type_code == TYPE_CODE_ENUM)
+ {
+ /* This is a non-empty enum. */
+ for (ext_tsym = ext_sh + external_sym_size;
+ ;
+ ext_tsym += external_sym_size)
+ {
+ SYMR tsym;
+ struct symbol *enum_sym;
+
+ (*swap_sym_in) (cur_bfd, ext_tsym, &tsym);
+
+ if (tsym.st != stMember)
+ break;
+
+ f->bitpos = tsym.value;
+ f->type = t;
+ f->name = (ecoff_data (cur_bfd)->ss
+ + cur_fdr->issBase
+ + tsym.iss);
+ f->bitsize = 0;
+
+ enum_sym = ((struct symbol *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct symbol)));
+ memset ((PTR) enum_sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (enum_sym) = f->name;
+ SYMBOL_CLASS (enum_sym) = LOC_CONST;
+ SYMBOL_TYPE (enum_sym) = t;
+ SYMBOL_NAMESPACE (enum_sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (enum_sym) = tsym.value;
+ add_symbol (enum_sym, top_stack->cur_block);
+
+ /* Skip the stMembers that we've handled. */
+ count++;
+ f++;
+ }
+ }
+ /* make this the current type */
+ top_stack->cur_type = t;
+ top_stack->cur_field = 0;
+
+ /* Do not create a symbol for alpha cc unnamed structs. */
+ if (sh->iss == 0)
+ break;
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_TYPEDEF;
+ SYMBOL_VALUE (s) = 0;
+ SYMBOL_TYPE (s) = t;
+
+ /* gcc puts out an empty struct for an opaque struct definitions. */
+ if (TYPE_NFIELDS (t) == 0)
+ {
+ TYPE_FLAGS (t) |= TYPE_FLAG_STUB;
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ }
+ add_symbol (s, top_stack->cur_block);
+ break;
+
+ /* End of local variables shared by struct, union, enum, and
+ block (as yet unknown struct/union/enum) processing. */
+ }
+
+ case_stBlock_code:
+ /* beginnning of (code) block. Value of symbol
+ is the displacement from procedure start */
+ push_parse_stack ();
+ top_stack->blocktype = stBlock;
+ b = new_block (top_stack->maxsyms);
+ BLOCK_START (b) = sh->value + top_stack->procadr;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ top_stack->cur_block = b;
+ add_block (b, top_stack->cur_st);
+ break;
+
+ case stEnd: /* end (of anything) */
+ if (sh->sc == scInfo || sh->sc == scCommon)
+ {
+ /* Finished with type */
+ top_stack->cur_type = 0;
+ }
+ else if (sh->sc == scText &&
+ (top_stack->blocktype == stProc ||
+ top_stack->blocktype == stStaticProc))
+ {
+ /* Finished with procedure */
+ struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st);
+ struct mips_extra_func_info *e;
+ struct block *b;
+ int i;
+
+ BLOCK_END (top_stack->cur_block) += sh->value; /* size */
+
+ /* Make up special symbol to contain procedure specific info */
+ s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ e = ((struct mips_extra_func_info *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct mips_extra_func_info)));
+ SYMBOL_VALUE (s) = (long) e;
+ e->numargs = top_stack->numargs;
+ add_symbol (s, top_stack->cur_block);
+
+ /* Reallocate symbols, saving memory */
+ b = shrink_block (top_stack->cur_block, top_stack->cur_st);
+
+ /* f77 emits proc-level with address bounds==[0,0],
+ So look for such child blocks, and patch them. */
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++)
+ {
+ struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SUPERBLOCK (b_bad) == b
+ && BLOCK_START (b_bad) == top_stack->procadr
+ && BLOCK_END (b_bad) == top_stack->procadr)
+ {
+ BLOCK_START (b_bad) = BLOCK_START (b);
+ BLOCK_END (b_bad) = BLOCK_END (b);
+ }
+ }
+ }
+ else if (sh->sc == scText && top_stack->blocktype == stBlock)
+ {
+ /* End of (code) block. The value of the symbol is the
+ displacement from the procedure`s start address of the
+ end of this block. */
+ BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr;
+ shrink_block (top_stack->cur_block, top_stack->cur_st);
+ }
+ else if (sh->sc == scText && top_stack->blocktype == stFile)
+ {
+ /* End of file. Pop parse stack and ignore. Higher
+ level code deals with this. */
+ ;
+ }
+ else
+ complain (&stEnd_complaint, sh->sc);
+
+ pop_parse_stack (); /* restore previous lexical context */
+ break;
+
+ case stMember: /* member of struct or union */
+ f = &TYPE_FIELDS (top_stack->cur_type)[top_stack->cur_field++];
+ f->name = name;
+ f->bitpos = sh->value;
+ bitsize = 0;
+ f->type = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name);
+ f->bitsize = bitsize;
+ break;
+
+ case stTypedef: /* type definition */
+ /* Typedefs for forward declarations and opaque structs from alpha cc
+ are handled by cross_ref, skip them. */
+ if (sh->iss == 0)
+ break;
+
+ /* Parse the type or use the pending type. */
+ pend = is_pending_symbol (cur_fdr, ext_sh);
+ if (pend == (struct mips_pending *) NULL)
+ {
+ t = parse_type (cur_fd, ax, sh->index, (int *)NULL, bigend, name);
+ add_pending (cur_fdr, ext_sh, t);
+ }
+ else
+ t = pend->t;
+
+ /* mips cc puts out a typedef with the name of the struct for forward
+ declarations. These should not go into the symbol table and
+ TYPE_NAME should not be set for them.
+ They can't be distinguished from an intentional typedef to
+ the same name however:
+ x.h:
+ struct x { int ix; int jx; };
+ struct xx;
+ x.c:
+ typedef struct x x;
+ struct xx {int ixx; int jxx; };
+ generates a cross referencing stTypedef for x and xx.
+ The user visible effect of this is that the type of a pointer
+ to struct foo sometimes is given as `foo *' instead of `struct foo *'.
+ The problem is fixed with alpha cc. */
+
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_TYPEDEF;
+ SYMBOL_BLOCK_VALUE (s) = top_stack->cur_block;
+ SYMBOL_TYPE (s) = t;
+ add_symbol (s, top_stack->cur_block);
+
+ /* Incomplete definitions of structs should not get a name. */
+ if (TYPE_NAME (SYMBOL_TYPE (s)) == NULL
+ && (TYPE_NFIELDS (SYMBOL_TYPE (s)) != 0
+ || (TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_STRUCT
+ && TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_UNION)))
+ {
+ if (TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_PTR
+ || TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; CC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type
+ refering to the stTypedef symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (s)) = SYMBOL_NAME (s);
+ }
+ break;
+
+ case stFile: /* file name */
+ push_parse_stack ();
+ top_stack->blocktype = sh->st;
+ break;
+
+ /* I`ve never seen these for C */
+ case stRegReloc:
+ break; /* register relocation */
+ case stForward:
+ break; /* forwarding address */
+ case stConstant:
+ break; /* constant */
+ default:
+ complain (&unknown_mips_symtype_complaint, sh->st);
+ break;
+ }
+
+ return count;
+}
+
+/* Parse the type information provided in the raw AX entries for
+ the symbol SH. Return the bitfield size in BS, in case.
+ We must byte-swap the AX entries before we use them; BIGEND says whether
+ they are big-endian or little-endian (from fh->fBigendian). */
+
+static struct type *
+parse_type (fd, ax, aux_index, bs, bigend, sym_name)
+ int fd;
+ union aux_ext *ax;
+ unsigned int aux_index;
+ int *bs;
+ int bigend;
+ char *sym_name;
+{
+ /* Null entries in this map are treated specially */
+ static struct type **map_bt[] =
+ {
+ &builtin_type_void, /* btNil */
+ 0, /* btAdr */
+ &builtin_type_char, /* btChar */
+ &builtin_type_unsigned_char,/* btUChar */
+ &builtin_type_short, /* btShort */
+ &builtin_type_unsigned_short, /* btUShort */
+ &builtin_type_int, /* btInt */
+ &builtin_type_unsigned_int, /* btUInt */
+ &builtin_type_long, /* btLong */
+ &builtin_type_unsigned_long,/* btULong */
+ &builtin_type_float, /* btFloat */
+ &builtin_type_double, /* btDouble */
+ 0, /* btStruct */
+ 0, /* btUnion */
+ 0, /* btEnum */
+ 0, /* btTypedef */
+ 0, /* btRange */
+ 0, /* btSet */
+ &builtin_type_complex, /* btComplex */
+ &builtin_type_double_complex, /* btDComplex */
+ 0, /* btIndirect */
+ &builtin_type_fixed_dec, /* btFixedDec */
+ &builtin_type_float_dec, /* btFloatDec */
+ &builtin_type_string, /* btString */
+ 0, /* btBit */
+ 0, /* btPicture */
+ &builtin_type_void, /* btVoid */
+ 0, /* DEC C++: Pointer to member */
+ 0, /* DEC C++: Virtual function table */
+ 0, /* DEC C++: Class (Record) */
+ &builtin_type_long, /* btLong64 */
+ &builtin_type_unsigned_long, /* btULong64 */
+ &builtin_type_long_long, /* btLongLong64 */
+ &builtin_type_unsigned_long_long, /* btULongLong64 */
+ &builtin_type_unsigned_long, /* btAdr64 */
+ &builtin_type_long, /* btInt64 */
+ &builtin_type_unsigned_long, /* btUInt64 */
+ };
+
+ TIR t[1];
+ struct type *tp = 0;
+ enum type_code type_code = TYPE_CODE_UNDEF;
+
+ /* Handle corrupt aux indices. */
+ if (aux_index >= (ecoff_data (cur_bfd)->fdr + fd)->caux)
+ {
+ complain (&index_complaint, sym_name);
+ return builtin_type_int;
+ }
+ ax += aux_index;
+
+ /* Use aux as a type information record, map its basic type. */
+ ecoff_swap_tir_in (bigend, &ax->a_ti, t);
+ if (t->bt >= (sizeof (map_bt) / sizeof (*map_bt)))
+ {
+ complain (&basic_type_complaint, t->bt, sym_name);
+ return builtin_type_int;
+ }
+ if (map_bt[t->bt])
+ {
+ tp = *map_bt[t->bt];
+ }
+ else
+ {
+ tp = NULL;
+ /* Cannot use builtin types -- build our own */
+ switch (t->bt)
+ {
+ case btAdr:
+ tp = lookup_pointer_type (builtin_type_void);
+ break;
+ case btStruct:
+ type_code = TYPE_CODE_STRUCT;
+ break;
+ case btUnion:
+ type_code = TYPE_CODE_UNION;
+ break;
+ case btEnum:
+ type_code = TYPE_CODE_ENUM;
+ break;
+ case btRange:
+ type_code = TYPE_CODE_RANGE;
+ break;
+ case btSet:
+ type_code = TYPE_CODE_SET;
+ break;
+ case btTypedef:
+ /* alpha cc uses this for typedefs. The true type will be
+ obtained by crossreferencing below. */
+ type_code = TYPE_CODE_ERROR;
+ break;
+ default:
+ complain (&basic_type_complaint, t->bt, sym_name);
+ return builtin_type_int;
+ }
+ }
+
+ /* Move on to next aux */
+ ax++;
+
+ if (t->fBitfield)
+ {
+ /* Inhibit core dumps with some cfront generated objects that
+ corrupt the TIR. */
+ if (bs == (int *)NULL)
+ {
+ complain (&bad_fbitfield_complaint, sym_name);
+ return builtin_type_int;
+ }
+ *bs = AUX_GET_WIDTH (bigend, ax);
+ ax++;
+ }
+
+ /* All these types really point to some (common) MIPS type
+ definition, and only the type-qualifiers fully identify
+ them. We'll make the same effort at sharing. */
+ if (t->bt == btStruct ||
+ t->bt == btUnion ||
+ t->bt == btEnum ||
+
+ /* btSet (I think) implies that the name is a tag name, not a typedef
+ name. This apparently is a MIPS extension for C sets. */
+ t->bt == btSet)
+ {
+ char *name;
+
+ /* Try to cross reference this type, build new type on failure. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+
+ /* Make sure that TYPE_CODE(tp) has an expected type code.
+ Any type may be returned from cross_ref if file indirect entries
+ are corrupted. */
+ if (TYPE_CODE (tp) != TYPE_CODE_STRUCT
+ && TYPE_CODE (tp) != TYPE_CODE_UNION
+ && TYPE_CODE (tp) != TYPE_CODE_ENUM)
+ {
+ complain (&unexpected_type_code_complaint, sym_name);
+ }
+ else
+ {
+
+ /* Usually, TYPE_CODE(tp) is already type_code. The main
+ exception is if we guessed wrong re struct/union/enum.
+ But for struct vs. union a wrong guess is harmless, so
+ don't complain(). */
+ if ((TYPE_CODE (tp) == TYPE_CODE_ENUM
+ && type_code != TYPE_CODE_ENUM)
+ || (TYPE_CODE (tp) != TYPE_CODE_ENUM
+ && type_code == TYPE_CODE_ENUM))
+ {
+ complain (&bad_tag_guess_complaint, sym_name);
+ }
+
+ if (TYPE_CODE (tp) != type_code)
+ {
+ TYPE_CODE (tp) = type_code;
+ }
+
+ /* Do not set the tag name if it is a compiler generated tag name
+ (.Fxx or .xxfake or empty) for unnamed struct/union/enums. */
+ if (name[0] == '.' || name[0] == '\0')
+ TYPE_TAG_NAME (tp) = NULL;
+ else if (TYPE_TAG_NAME (tp) == NULL
+ || !STREQ (TYPE_TAG_NAME (tp), name))
+ TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->type_obstack);
+ }
+ }
+
+ /* All these types really point to some (common) MIPS type
+ definition, and only the type-qualifiers fully identify
+ them. We'll make the same effort at sharing.
+ FIXME: btIndirect cannot happen here as it is handled by the
+ switch t->bt above. And we are not doing any guessing on range types. */
+ if (t->bt == btIndirect ||
+ t->bt == btRange)
+ {
+ char *name;
+
+ /* Try to cross reference this type, build new type on failure. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+
+ /* Make sure that TYPE_CODE(tp) has an expected type code.
+ Any type may be returned from cross_ref if file indirect entries
+ are corrupted. */
+ if (TYPE_CODE (tp) != TYPE_CODE_RANGE)
+ {
+ complain (&unexpected_type_code_complaint, sym_name);
+ }
+ else
+ {
+ /* Usually, TYPE_CODE(tp) is already type_code. The main
+ exception is if we guessed wrong re struct/union/enum. */
+ if (TYPE_CODE (tp) != type_code)
+ {
+ complain (&bad_tag_guess_complaint, sym_name);
+ TYPE_CODE (tp) = type_code;
+ }
+ if (TYPE_NAME (tp) == NULL || !STREQ (TYPE_NAME (tp), name))
+ TYPE_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->type_obstack);
+ }
+ }
+ if (t->bt == btTypedef)
+ {
+ char *name;
+
+ /* Try to cross reference this type, it should succeed. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ {
+ complain (&unable_to_cross_ref_complaint, sym_name);
+ tp = builtin_type_int;
+ }
+ }
+
+ /* Deal with range types */
+ if (t->bt == btRange)
+ {
+ TYPE_NFIELDS (tp) = 2;
+ TYPE_FIELDS (tp) = ((struct field *)
+ TYPE_ALLOC (tp, 2 * sizeof (struct field)));
+ TYPE_FIELD_NAME (tp, 0) = obsavestring ("Low", strlen ("Low"),
+ &current_objfile->type_obstack);
+ TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax);
+ ax++;
+ TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"),
+ &current_objfile->type_obstack);
+ TYPE_FIELD_BITPOS (tp, 1) = AUX_GET_DNHIGH (bigend, ax);
+ ax++;
+ }
+
+ /* Parse all the type qualifiers now. If there are more
+ than 6 the game will continue in the next aux */
+
+ while (1)
+ {
+#define PARSE_TQ(tq) \
+ if (t->tq != tqNil) \
+ ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \
+ else \
+ break;
+
+ PARSE_TQ (tq0);
+ PARSE_TQ (tq1);
+ PARSE_TQ (tq2);
+ PARSE_TQ (tq3);
+ PARSE_TQ (tq4);
+ PARSE_TQ (tq5);
+#undef PARSE_TQ
+
+ /* mips cc 2.x and gcc never put out continued aux entries. */
+ if (!t->continued)
+ break;
+
+ ecoff_swap_tir_in (bigend, &ax->a_ti, t);
+ ax++;
+ }
+
+ /* Complain for illegal continuations due to corrupt aux entries. */
+ if (t->continued)
+ complain (&bad_continued_complaint, sym_name);
+
+ return tp;
+}
+
+/* Make up a complex type from a basic one. Type is passed by
+ reference in TPP and side-effected as necessary. The type
+ qualifier TQ says how to handle the aux symbols at AX for
+ the symbol SX we are currently analyzing. BIGEND says whether
+ aux symbols are big-endian or little-endian.
+ Returns the number of aux symbols we parsed. */
+
+static int
+upgrade_type (fd, tpp, tq, ax, bigend, sym_name)
+ int fd;
+ struct type **tpp;
+ int tq;
+ union aux_ext *ax;
+ int bigend;
+ char *sym_name;
+{
+ int off;
+ struct type *t;
+
+ /* Used in array processing */
+ int rf, id;
+ FDR *fh;
+ struct type *range;
+ struct type *indx;
+ int lower, upper;
+ RNDXR rndx;
+
+ switch (tq)
+ {
+ case tqPtr:
+ t = lookup_pointer_type (*tpp);
+ *tpp = t;
+ return 0;
+
+ case tqProc:
+ t = lookup_function_type (*tpp);
+ *tpp = t;
+ return 0;
+
+ case tqArray:
+ off = 0;
+
+ /* Determine and record the domain type (type of index) */
+ ecoff_swap_rndx_in (bigend, &ax->a_rndx, &rndx);
+ id = rndx.index;
+ rf = rndx.rfd;
+ if (rf == 0xfff)
+ {
+ ax++;
+ rf = AUX_GET_ISYM (bigend, ax);
+ off++;
+ }
+ fh = get_rfd (fd, rf);
+
+ indx = parse_type (fd,
+ ecoff_data (cur_bfd)->external_aux + fh->iauxBase,
+ id, (int *) NULL, bigend, sym_name);
+
+ /* The bounds type should be an integer type, but might be anything
+ else due to corrupt aux entries. */
+ if (TYPE_CODE (indx) != TYPE_CODE_INT)
+ {
+ complain (&array_index_type_complaint, sym_name);
+ indx = builtin_type_int;
+ }
+
+ /* Get the bounds, and create the array type. */
+ ax++;
+ lower = AUX_GET_DNLOW (bigend, ax);
+ ax++;
+ upper = AUX_GET_DNHIGH (bigend, ax);
+ ax++;
+ rf = AUX_GET_WIDTH (bigend, ax); /* bit size of array element */
+
+ range = create_range_type ((struct type *) NULL, indx,
+ lower, upper);
+
+ t = create_array_type ((struct type *) NULL, *tpp, range);
+
+ /* We used to fill in the supplied array element bitsize
+ here if the TYPE_LENGTH of the target type was zero.
+ This happens for a `pointer to an array of anonymous structs',
+ but in this case the array element bitsize is also zero,
+ so nothing is gained.
+ And we used to check the TYPE_LENGTH of the target type against
+ the supplied array element bitsize.
+ gcc causes a mismatch for `pointer to array of object',
+ since the sdb directives it uses do not have a way of
+ specifying the bitsize, but it does no harm (the
+ TYPE_LENGTH should be correct) and we should be able to
+ ignore the erroneous bitsize from the auxiliary entry safely.
+ dbx seems to ignore it too. */
+
+ *tpp = t;
+ return 4 + off;
+
+ case tqVol:
+ /* Volatile -- currently ignored */
+ return 0;
+
+ case tqConst:
+ /* Const -- currently ignored */
+ return 0;
+
+ default:
+ complain (&unknown_type_qual_complaint, tq);
+ return 0;
+ }
+}
+
+
+/* Parse a procedure descriptor record PR. Note that the procedure is
+ parsed _after_ the local symbols, now we just insert the extra
+ information we need into a MIPS_EFI_SYMBOL_NAME symbol that has
+ already been placed in the procedure's main block. Note also that
+ images that have been partially stripped (ld -x) have been deprived
+ of local symbols, and we have to cope with them here. FIRST_OFF is
+ the offset of the first procedure for this FDR; we adjust the
+ address by this amount, but I don't know why. SEARCH_SYMTAB is the symtab
+ to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol
+ in question, or NULL to use top_stack->cur_block. */
+
+static void parse_procedure PARAMS ((PDR *, struct symtab *, unsigned long));
+
+static void
+parse_procedure (pr, search_symtab, first_off)
+ PDR *pr;
+ struct symtab *search_symtab;
+ unsigned long first_off;
+{
+ struct symbol *s, *i;
+ struct block *b;
+ struct mips_extra_func_info *e;
+ char *sh_name;
+
+ /* Simple rule to find files linked "-x" */
+ if (cur_fdr->rss == -1)
+ {
+ if (pr->isym == -1)
+ {
+ /* Static procedure at address pr->adr. Sigh. */
+ complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr);
+ return;
+ }
+ else
+ {
+ /* external */
+ EXTR she;
+
+ (*ecoff_backend (cur_bfd)->swap_ext_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_ext
+ + pr->isym * ecoff_backend (cur_bfd)->external_ext_size),
+ &she);
+ sh_name = ecoff_data (cur_bfd)->ssext + she.asym.iss;
+ }
+ }
+ else
+ {
+ /* Full symbols */
+ SYMR sh;
+
+ (*ecoff_backend (cur_bfd)->swap_sym_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((cur_fdr->isymBase + pr->isym)
+ * ecoff_backend (cur_bfd)->external_sym_size)),
+ &sh);
+ sh_name = ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh.iss;
+ }
+
+ if (search_symtab != NULL)
+ {
+#if 0
+ /* This loses both in the case mentioned (want a static, find a global),
+ but also if we are looking up a non-mangled name which happens to
+ match the name of a mangled function. */
+ /* We have to save the cur_fdr across the call to lookup_symbol.
+ If the pdr is for a static function and if a global function with
+ the same name exists, lookup_symbol will eventually read in the symtab
+ for the global function and clobber cur_fdr. */
+ FDR *save_cur_fdr = cur_fdr;
+ s = lookup_symbol (sh_name, NULL, VAR_NAMESPACE, 0, NULL);
+ cur_fdr = save_cur_fdr;
+#else
+ s = mylookup_symbol
+ (sh_name,
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK),
+ VAR_NAMESPACE,
+ LOC_BLOCK);
+#endif
+ }
+ else
+ s = mylookup_symbol (sh_name, top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK);
+
+ if (s != 0)
+ {
+ b = SYMBOL_BLOCK_VALUE (s);
+ }
+ else
+ {
+ complain (&pdr_for_nonsymbol_complaint, sh_name);
+#if 1
+ return;
+#else
+/* FIXME -- delete. We can't do symbol allocation now; it's all done. */
+ s = new_symbol (sh_name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ /* Donno its type, hope int is ok */
+ SYMBOL_TYPE (s) = lookup_function_type (builtin_type_int);
+ add_symbol (s, top_stack->cur_block);
+ /* Wont have symbols for this one */
+ b = new_block (2);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_START (b) = pr->adr;
+ /* BOUND used to be the end of procedure's text, but the
+ argument is no longer passed in. */
+ BLOCK_END (b) = bound;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ add_block (b, top_stack->cur_st);
+#endif
+ }
+
+ i = mylookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, LOC_CONST);
+
+ if (i)
+ {
+ e = (struct mips_extra_func_info *) SYMBOL_VALUE (i);
+ e->pdr = *pr;
+ e->pdr.isym = (long) s;
+ e->pdr.adr += cur_fdr->adr - first_off;
+
+ /* Correct incorrect setjmp procedure descriptor from the library
+ to make backtrace through setjmp work. */
+ if (e->pdr.pcreg == 0 && STREQ (sh_name, "setjmp"))
+ {
+ complain (&bad_setjmp_pdr_complaint, 0);
+ e->pdr.pcreg = RA_REGNUM;
+ e->pdr.regmask = 0x80000000;
+ e->pdr.regoffset = -4;
+ }
+
+ /* Fake PC_REGNUM for alpha __sigtramp so that read_next_frame_reg
+ will use the saved user pc from the sigcontext. */
+ if (STREQ (sh_name, "__sigtramp"))
+ e->pdr.pcreg = PC_REGNUM;
+ }
+}
+
+/* Parse the external symbol ES. Just call parse_symbol() after
+ making sure we know where the aux are for it. For procedures,
+ parsing of the PDRs has already provided all the needed
+ information, we only parse them if SKIP_PROCEDURES is false,
+ and only if this causes no symbol duplication.
+ BIGEND says whether aux entries are big-endian or little-endian.
+
+ This routine clobbers top_stack->cur_block and ->cur_st. */
+
+static void
+parse_external (es, skip_procedures, bigend)
+ EXTR *es;
+ int skip_procedures;
+ int bigend;
+{
+ union aux_ext *ax;
+
+ if (es->ifd != ifdNil)
+ {
+ cur_fd = es->ifd;
+ cur_fdr = ecoff_data (cur_bfd)->fdr + cur_fd;
+ ax = ecoff_data (cur_bfd)->external_aux + cur_fdr->iauxBase;
+ }
+ else
+ {
+ cur_fdr = ecoff_data (cur_bfd)->fdr;
+ ax = 0;
+ }
+
+ /* Reading .o files */
+ if (es->asym.sc == scUndefined || es->asym.sc == scNil)
+ {
+ char *what;
+ switch (es->asym.st)
+ {
+ case stNil:
+ /* These are generated for static symbols in .o files,
+ ignore them. */
+ return;
+ case stStaticProc:
+ case stProc:
+ what = "procedure";
+ n_undef_procs++;
+ break;
+ case stGlobal:
+ what = "variable";
+ n_undef_vars++;
+ break;
+ case stLabel:
+ what = "label";
+ n_undef_labels++;
+ break;
+ default:
+ what = "symbol";
+ break;
+ }
+ n_undef_symbols++;
+ /* FIXME: Turn this into a complaint? */
+ if (info_verbose)
+ printf_filtered ("Warning: %s `%s' is undefined (in %s)\n",
+ what,
+ ecoff_data (cur_bfd)->ssext + es->asym.iss,
+ fdr_name (cur_fdr));
+ return;
+ }
+
+ switch (es->asym.st)
+ {
+ case stProc:
+ /* If we have full symbols we do not need more */
+ if (skip_procedures)
+ return;
+ if (mylookup_symbol (ecoff_data (cur_bfd)->ssext + es->asym.iss,
+ top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK))
+ break;
+ /* fall through */
+ case stGlobal:
+ case stLabel:
+ /* Note that the case of a symbol with indexNil must be handled
+ anyways by parse_symbol(). */
+ parse_symbol (&es->asym, ax, (char *) NULL, bigend);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Parse the line number info for file descriptor FH into
+ GDB's linetable LT. MIPS' encoding requires a little bit
+ of magic to get things out. Note also that MIPS' line
+ numbers can go back and forth, apparently we can live
+ with that and do not need to reorder our linetables */
+
+static void
+parse_lines (fh, pr, lt, maxlines)
+ FDR *fh;
+ PDR *pr;
+ struct linetable *lt;
+ int maxlines;
+{
+ unsigned char *base;
+ int j, k;
+ int delta, count, lineno = 0;
+ unsigned long first_off = pr->adr;
+
+ if (fh->cbLine == 0)
+ return;
+
+ base = ecoff_data (cur_bfd)->line + fh->cbLineOffset;
+
+ /* Scan by procedure descriptors */
+ k = 0;
+ for (j = 0; j < fh->cpd; j++, pr++)
+ {
+ long l;
+ unsigned long adr;
+ unsigned char *halt;
+
+ /* No code for this one */
+ if (pr->iline == ilineNil ||
+ pr->lnLow == -1 || pr->lnHigh == -1)
+ continue;
+
+ /* Determine start and end address of compressed line bytes for
+ this procedure. */
+ base = ecoff_data (cur_bfd)->line + fh->cbLineOffset;
+ if (j != (fh->cpd - 1))
+ halt = base + pr[1].cbLineOffset;
+ else
+ halt = base + fh->cbLine;
+ base += pr->cbLineOffset;
+
+ adr = fh->adr + pr->adr - first_off;
+ l = adr >> 2; /* in words */
+ for (lineno = pr->lnLow; base < halt; )
+ {
+ count = *base & 0x0f;
+ delta = *base++ >> 4;
+ if (delta >= 8)
+ delta -= 16;
+ if (delta == -8)
+ {
+ delta = (base[0] << 8) | base[1];
+ if (delta >= 0x8000)
+ delta -= 0x10000;
+ base += 2;
+ }
+ lineno += delta; /* first delta is 0 */
+
+ /* Complain if the line table overflows. Could happen
+ with corrupt binaries. */
+ if (lt->nitems >= maxlines)
+ {
+ complain (&bad_linetable_guess_complaint, fdr_name (fh));
+ break;
+ }
+ k = add_line (lt, lineno, l, k);
+ l += count + 1;
+ }
+ }
+}
+
+/* Master parsing procedure for first-pass reading of file symbols
+ into a partial_symtab. */
+
+static void
+parse_partial_symbols (objfile, section_offsets)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (cur_bfd);
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ const bfd_size_type external_rfd_size = backend->external_rfd_size;
+ const bfd_size_type external_ext_size = backend->external_ext_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->swap_sym_in;
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = backend->swap_rfd_in;
+ int f_idx, s_idx;
+ HDRR *hdr = &ecoff_data (cur_bfd)->symbolic_header;
+ /* Running pointers */
+ FDR *fh;
+ char *ext_out;
+ char *ext_out_end;
+ EXTR *ext_block;
+ register EXTR *ext_in;
+ EXTR *ext_in_end;
+ SYMR sh;
+ struct partial_symtab *pst;
+
+ int past_first_source_file = 0;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+ EXTR *extern_tab;
+ struct pst_map *fdr_to_pst;
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+ struct cleanup *old_chain;
+ char *name;
+ enum language prev_language;
+
+ extern_tab = (EXTR *) obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (EXTR) * hdr->iextMax);
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+ next_symbol_text_func = mips_next_symbol_text;
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ last_source_file = NULL;
+
+ /*
+ * Big plan:
+ *
+ * Only parse the Local and External symbols, and the Relative FDR.
+ * Fixup enough of the loader symtab to be able to use it.
+ * Allocate space only for the file's portions we need to
+ * look at. (XXX)
+ */
+
+ max_gdbinfo = 0;
+ max_glevel = MIN_GLEVEL;
+
+ /* Allocate the map FDR -> PST.
+ Minor hack: -O3 images might claim some global data belongs
+ to FDR -1. We`ll go along with that */
+ fdr_to_pst = (struct pst_map *) xzalloc ((hdr->ifdMax + 1) * sizeof *fdr_to_pst);
+ old_chain = make_cleanup (free, fdr_to_pst);
+ fdr_to_pst++;
+ {
+ struct partial_symtab *pst = new_psymtab ("", objfile);
+ fdr_to_pst[-1].pst = pst;
+ FDR_IDX (pst) = -1;
+ }
+
+ /* Allocate the global pending list. */
+ ECOFF_PENDING_LIST (objfile) =
+ ((struct mips_pending **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ hdr->ifdMax * sizeof (struct mips_pending *)));
+ memset ((PTR) ECOFF_PENDING_LIST (objfile), 0,
+ hdr->ifdMax * sizeof (struct mips_pending *));
+
+ /* Pass 0 over external syms: swap them in. */
+ ext_block = (EXTR *) xmalloc (hdr->iextMax * sizeof (EXTR));
+ make_cleanup (free, ext_block);
+
+ ext_out = (char *) ecoff_data (cur_bfd)->external_ext;
+ ext_out_end = ext_out + hdr->iextMax * external_ext_size;
+ ext_in = ext_block;
+ for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++)
+ (*swap_ext_in) (cur_bfd, ext_out, ext_in);
+
+ /* Pass 1 over external syms: Presize and partition the list */
+ ext_in = ext_block;
+ ext_in_end = ext_in + hdr->iextMax;
+ for (; ext_in < ext_in_end; ext_in++)
+ fdr_to_pst[ext_in->ifd].n_globals++;
+
+ /* Pass 1.5 over files: partition out global symbol space */
+ s_idx = 0;
+ for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++)
+ {
+ fdr_to_pst[f_idx].globals_offset = s_idx;
+ s_idx += fdr_to_pst[f_idx].n_globals;
+ fdr_to_pst[f_idx].n_globals = 0;
+ }
+
+ /* Pass 2 over external syms: fill in external symbols */
+ ext_in = ext_block;
+ ext_in_end = ext_in + hdr->iextMax;
+ for (; ext_in < ext_in_end; ext_in++)
+ {
+ enum minimal_symbol_type ms_type = mst_text;
+
+ extern_tab[fdr_to_pst[ext_in->ifd].globals_offset
+ + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in;
+
+ if (ext_in->asym.sc == scUndefined || ext_in->asym.sc == scNil)
+ continue;
+
+ name = ecoff_data (cur_bfd)->ssext + ext_in->asym.iss;
+ switch (ext_in->asym.st)
+ {
+ case stProc:
+ break;
+ case stStaticProc:
+ ms_type = mst_file_text;
+ break;
+ case stGlobal:
+ if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData)
+ ms_type = mst_data;
+ else
+ ms_type = mst_bss;
+ break;
+ case stLabel:
+ if (ext_in->asym.sc == scAbs)
+ ms_type = mst_abs;
+ else if (ext_in->asym.sc == scText)
+ ms_type = mst_text;
+ else if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData)
+ ms_type = mst_data;
+ else
+ ms_type = mst_bss;
+ break;
+ case stLocal:
+ /* The alpha has the section start addresses in stLocal symbols
+ whose name starts with a `.'. Skip those but complain for all
+ other stLocal symbols. */
+ if (name[0] == '.')
+ continue;
+ /* Fall through. */
+ default:
+ ms_type = mst_unknown;
+ complain (&unknown_ext_complaint, name);
+ }
+ prim_record_minimal_symbol (name, ext_in->asym.value, ms_type);
+ }
+
+ /* Pass 3 over files, over local syms: fill in static symbols */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+ {
+ struct partial_symtab *save_pst;
+ EXTR *ext_ptr;
+
+ cur_fdr = fh = ecoff_data (cur_bfd)->fdr + f_idx;
+
+ if (fh->csym == 0)
+ {
+ fdr_to_pst[f_idx].pst = NULL;
+ continue;
+ }
+ pst = start_psymtab_common (objfile, section_offsets,
+ fdr_name (fh),
+ fh->cpd ? fh->adr : 0,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ pst->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc)));
+ memset ((PTR) pst->read_symtab_private, 0, sizeof (struct symloc));
+
+ save_pst = pst;
+ FDR_IDX (pst) = f_idx;
+ CUR_BFD (pst) = cur_bfd;
+
+ /* The way to turn this into a symtab is to call... */
+ pst->read_symtab = mipscoff_psymtab_to_symtab;
+
+ /* Set up language for the pst.
+ The language from the FDR is used if it is unambigious (e.g. cfront
+ with native cc and g++ will set the language to C).
+ Otherwise we have to deduce the language from the filename.
+ Native ecoff has every header file in a separate FDR, so
+ deduce_language_from_filename will return language_unknown for
+ a header file, which is not what we want.
+ But the FDRs for the header files are after the FDR for the source
+ file, so we can assign the language of the source file to the
+ following header files. Then we save the language in the private
+ pst data so that we can reuse it when building symtabs. */
+ prev_language = psymtab_language;
+
+ switch (fh->lang)
+ {
+ case langCplusplusV2:
+ psymtab_language = language_cplus;
+ break;
+ default:
+ psymtab_language = deduce_language_from_filename (fdr_name (fh));
+ break;
+ }
+ if (psymtab_language == language_unknown)
+ psymtab_language = prev_language;
+ PST_PRIVATE (pst)->pst_language = psymtab_language;
+
+ pst->texthigh = pst->textlow;
+
+ /* For stabs-in-ecoff files, the second symbol must be @stab.
+ This symbol is emitted by mips-tfile to signal that the
+ current object file uses encapsulated stabs instead of mips
+ ecoff for local symbols. (It is the second symbol because
+ the first symbol is the stFile used to signal the start of a
+ file). */
+ processing_gcc_compilation = 0;
+ if (fh->csym >= 2)
+ {
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss,
+ stabs_symbol))
+ processing_gcc_compilation = 2;
+ }
+
+ if (processing_gcc_compilation != 0)
+ {
+ for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++)
+ {
+ int type_code;
+ char *namestring;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + cur_sdx) * external_sym_size),
+ &sh);
+ type_code = ECOFF_UNMARK_STAB (sh.index);
+ if (!ECOFF_IS_STAB (&sh))
+ {
+ if (sh.st == stProc || sh.st == stStaticProc)
+ {
+ long procaddr = sh.value;
+ long isym;
+
+
+ isym = AUX_GET_ISYM (fh->fBigendian,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase
+ + sh.index));
+ (*swap_sym_in) (cur_bfd,
+ (((char *)
+ ecoff_data (cur_bfd)->external_sym)
+ + ((fh->isymBase + isym - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st == stEnd)
+ {
+ long high = procaddr + sh.value;
+ if (high > pst->texthigh)
+ pst->texthigh = high;
+ }
+ }
+ continue;
+ }
+#define SET_NAMESTRING() \
+ namestring = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss
+#define CUR_SYMBOL_TYPE type_code
+#define CUR_SYMBOL_VALUE sh.value
+#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\
+ pst = save_pst
+#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) (void)0
+#define HANDLE_RBRAC(val) \
+ if ((val) > save_pst->texthigh) save_pst->texthigh = (val);
+#include "partial-stab.h"
+ }
+ }
+ else
+ {
+ for (cur_sdx = 0; cur_sdx < fh->csym;)
+ {
+ char *name;
+ enum address_class class;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((fh->isymBase + cur_sdx)
+ * external_sym_size)),
+ &sh);
+
+ if (ECOFF_IS_STAB (&sh))
+ {
+ cur_sdx++;
+ continue;
+ }
+
+ /* Non absolute static symbols go into the minimal table. */
+ if (sh.sc == scUndefined || sh.sc == scNil
+ || (sh.index == indexNil
+ && (sh.st != stStatic || sh.sc == scAbs)))
+ {
+ /* FIXME, premature? */
+ cur_sdx++;
+ continue;
+ }
+
+ name = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss;
+
+ switch (sh.st)
+ {
+ long high;
+ long procaddr;
+ int new_sdx;
+
+ case stStaticProc: /* Function */
+ /* I believe this is used only for file-local functions.
+ The comment in symconst.h ("load time only static procs")
+ isn't particularly clear on this point. */
+ prim_record_minimal_symbol (name, sh.value, mst_file_text);
+ /* FALLTHROUGH */
+
+ case stProc: /* Asm labels apparently */
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->static_psymbols, sh.value,
+ psymtab_language, objfile);
+ /* Skip over procedure to next one. */
+ if (sh.index >= hdr->iauxMax)
+ {
+ /* Should not happen, but does when cross-compiling
+ with the MIPS compiler. FIXME -- pull later. */
+ complain (&index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip at all */
+ }
+ else
+ new_sdx = AUX_GET_ISYM (fh->fBigendian,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase
+ + sh.index));
+ procaddr = sh.value;
+
+ if (new_sdx <= cur_sdx)
+ {
+ /* This should not happen either... FIXME. */
+ complain (&aux_index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip backward */
+ }
+
+ cur_sdx = new_sdx;
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((fh->isymBase + cur_sdx - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st != stEnd)
+ continue;
+ high = procaddr + sh.value;
+ if (high > pst->texthigh)
+ pst->texthigh = high;
+ continue;
+
+ case stStatic: /* Variable */
+ if (sh.sc == scData || sh.sc == scSData || sh.sc == scRData)
+ prim_record_minimal_symbol (name, sh.value, mst_file_data);
+ else
+ prim_record_minimal_symbol (name, sh.value, mst_file_bss);
+ class = LOC_STATIC;
+ break;
+
+ case stTypedef:/* Typedef */
+ class = LOC_TYPEDEF;
+ break;
+
+ case stConstant: /* Constant decl */
+ class = LOC_CONST;
+ break;
+
+ case stUnion:
+ case stStruct:
+ case stEnum:
+ case stBlock: /* { }, str, un, enum*/
+ if (sh.sc == scInfo || sh.sc == scCommon)
+ {
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ sh.value,
+ psymtab_language, objfile);
+ }
+ /* Skip over the block */
+ new_sdx = sh.index;
+ if (new_sdx <= cur_sdx)
+ {
+ /* This happens with the Ultrix kernel. */
+ complain (&block_index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip backward */
+ }
+ cur_sdx = new_sdx;
+ continue;
+
+ case stFile: /* File headers */
+ case stLabel: /* Labels */
+ case stEnd: /* Ends of files */
+ goto skip;
+
+ case stLocal: /* Local variables */
+ /* Normally these are skipped because we skip over
+ all blocks we see. However, these can occur
+ as visible symbols in a .h file that contains code. */
+ goto skip;
+
+ default:
+ /* Both complaints are valid: one gives symbol name,
+ the other the offending symbol type. */
+ complain (&unknown_sym_complaint, name);
+ complain (&unknown_st_complaint, sh.st);
+ cur_sdx++;
+ continue;
+ }
+ /* Use this gdb symbol */
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, class,
+ objfile->static_psymbols, sh.value,
+ psymtab_language, objfile);
+ skip:
+ cur_sdx++; /* Go to next file symbol */
+ }
+
+ /* Now do enter the external symbols. */
+ ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset];
+ cur_sdx = fdr_to_pst[f_idx].n_globals;
+ PST_PRIVATE (save_pst)->extern_count = cur_sdx;
+ PST_PRIVATE (save_pst)->extern_tab = ext_ptr;
+ for (; --cur_sdx >= 0; ext_ptr++)
+ {
+ enum address_class class;
+ SYMR *psh;
+ char *name;
+
+ if (ext_ptr->ifd != f_idx)
+ abort ();
+ psh = &ext_ptr->asym;
+
+ /* Do not add undefined symbols to the partial symbol table. */
+ if (psh->sc == scUndefined || psh->sc == scNil)
+ continue;
+
+ switch (psh->st)
+ {
+ case stNil:
+ /* These are generated for static symbols in .o files,
+ ignore them. */
+ continue;
+ case stProc:
+ case stStaticProc:
+ class = LOC_BLOCK;
+ break;
+ case stLabel:
+ class = LOC_LABEL;
+ break;
+ default:
+ complain (&unknown_ext_complaint,
+ ecoff_data (cur_bfd)->ssext + psh->iss);
+ /* Fall through, pretend it's global. */
+ case stGlobal:
+ class = LOC_STATIC;
+ break;
+ }
+ name = ecoff_data (cur_bfd)->ssext + psh->iss;
+ ADD_PSYMBOL_ADDR_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, class,
+ objfile->global_psymbols, (CORE_ADDR) psh->value,
+ psymtab_language, objfile);
+ }
+ }
+
+ /* Link pst to FDR. end_psymtab returns NULL if the psymtab was
+ empty and put on the free list. */
+ fdr_to_pst[f_idx].pst = end_psymtab (save_pst,
+ psymtab_include_list, includes_used,
+ -1, save_pst->texthigh,
+ dependency_list, dependencies_used);
+ if (objfile->ei.entry_point >= save_pst->textlow &&
+ objfile->ei.entry_point < save_pst->texthigh)
+ {
+ objfile->ei.entry_file_lowpc = save_pst->textlow;
+ objfile->ei.entry_file_highpc = save_pst->texthigh;
+ }
+ }
+
+ /* Now scan the FDRs for dependencies */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+ {
+ fh = f_idx + ecoff_data (cur_bfd)->fdr;
+ pst = fdr_to_pst[f_idx].pst;
+
+ if (pst == (struct partial_symtab *)NULL)
+ continue;
+
+ /* This should catch stabs-in-ecoff. */
+ if (fh->crfd <= 1)
+ continue;
+
+ /* Skip the first file indirect entry as it is a self dependency
+ for source files or a reverse .h -> .c dependency for header files. */
+ pst->number_of_dependencies = 0;
+ pst->dependencies =
+ ((struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ ((fh->crfd - 1)
+ * sizeof (struct partial_symtab *))));
+ for (s_idx = 1; s_idx < fh->crfd; s_idx++)
+ {
+ RFDT rh;
+
+ (*swap_rfd_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_rfd
+ + (fh->rfdBase + s_idx) * external_rfd_size),
+ &rh);
+ if (rh < 0 || rh >= hdr->ifdMax)
+ {
+ complain (&bad_file_number_complaint, rh);
+ continue;
+ }
+
+ /* Skip self dependencies of header files. */
+ if (rh == f_idx)
+ continue;
+
+ /* Do not add to dependeny list if psymtab was empty. */
+ if (fdr_to_pst[rh].pst == (struct partial_symtab *)NULL)
+ continue;
+ pst->dependencies[pst->number_of_dependencies++] = fdr_to_pst[rh].pst;
+ }
+ }
+ do_cleanups (old_chain);
+}
+
+
+static char *
+mips_next_symbol_text ()
+{
+ SYMR sh;
+
+ cur_sdx++;
+ (*ecoff_backend (cur_bfd)->swap_sym_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((cur_fdr->isymBase + cur_sdx)
+ * ecoff_backend (cur_bfd)->external_sym_size)),
+ &sh);
+ return ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh.iss;
+}
+
+/* Ancillary function to psymtab_to_symtab(). Does all the work
+ for turning the partial symtab PST into a symtab, recurring
+ first on all dependent psymtabs. The argument FILENAME is
+ only passed so we can see in debug stack traces what file
+ is being read.
+
+ This function has a split personality, based on whether the
+ symbol table contains ordinary ecoff symbols, or stabs-in-ecoff.
+ The flow of control and even the memory allocation differs. FIXME. */
+
+static void
+psymtab_to_symtab_1 (pst, filename)
+ struct partial_symtab *pst;
+ char *filename;
+{
+ const bfd_size_type external_sym_size
+ = ecoff_backend (cur_bfd)->external_sym_size;
+ const bfd_size_type external_pdr_size
+ = ecoff_backend (cur_bfd)->external_pdr_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = ecoff_backend (cur_bfd)->swap_sym_in;
+ void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *))
+ = ecoff_backend (cur_bfd)->swap_pdr_in;
+ int i;
+ struct symtab *st;
+ FDR *fh;
+ struct linetable *lines;
+
+ if (pst->readin)
+ return;
+ pst->readin = 1;
+
+ /* Read in all partial symbtabs on which this one is dependent.
+ NOTE that we do have circular dependencies, sigh. We solved
+ that by setting pst->readin before this point. */
+
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ fflush (stdout);
+ }
+ /* We only pass the filename for debug purposes */
+ psymtab_to_symtab_1 (pst->dependencies[i],
+ pst->dependencies[i]->filename);
+ }
+
+ /* Do nothing if this is a dummy psymtab. */
+
+ if (pst->n_global_syms == 0 && pst->n_static_syms == 0
+ && pst->textlow == 0 && pst->texthigh == 0)
+ return;
+
+ /* Now read the symbols for this symtab */
+
+ cur_bfd = CUR_BFD (pst);
+ current_objfile = pst->objfile;
+ cur_fd = FDR_IDX (pst);
+ fh = (cur_fd == -1) ? (FDR *) NULL : ecoff_data (cur_bfd)->fdr + cur_fd;
+ cur_fdr = fh;
+
+ /* See comment in parse_partial_symbols about the @stabs sentinel. */
+ processing_gcc_compilation = 0;
+ if (fh != (FDR *) NULL && fh->csym >= 2)
+ {
+ SYMR sh;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss,
+ stabs_symbol))
+ {
+ /* We indicate that this is a GCC compilation so that certain
+ features will be enabled in stabsread/dbxread. */
+ processing_gcc_compilation = 2;
+ }
+ }
+
+ if (processing_gcc_compilation != 0)
+ {
+ char *pdr_ptr;
+ char *pdr_end;
+ int first_pdr;
+ unsigned long first_off = 0;
+
+ /* This symbol table contains stabs-in-ecoff entries. */
+
+ /* Parse local symbols first */
+
+ if (fh->csym <= 2) /* FIXME, this blows psymtab->symtab ptr */
+ {
+ current_objfile = NULL;
+ return;
+ }
+ for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++)
+ {
+ SYMR sh;
+ char *name;
+ CORE_ADDR valu;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + cur_sdx) * external_sym_size),
+ &sh);
+ name = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss;
+ valu = sh.value;
+ if (ECOFF_IS_STAB (&sh))
+ {
+ int type_code = ECOFF_UNMARK_STAB (sh.index);
+ process_one_symbol (type_code, 0, valu, name,
+ pst->section_offsets, pst->objfile);
+ if (type_code == N_FUN)
+ {
+ /* Make up special symbol to contain
+ procedure specific info */
+ struct mips_extra_func_info *e =
+ ((struct mips_extra_func_info *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct mips_extra_func_info)));
+ struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ SYMBOL_VALUE (s) = (long) e;
+ add_symbol_to_list (s, &local_symbols);
+ }
+ }
+ else if (sh.st == stLabel && sh.index != indexNil)
+ {
+ /* Handle encoded stab line number. */
+ record_line (current_subfile, sh.index, valu);
+ }
+ else if (sh.st == stProc || sh.st == stStaticProc || sh.st == stEnd)
+ /* These are generated by gcc-2.x, do not complain */
+ ;
+ else
+ complain (&stab_unknown_complaint, name);
+ }
+ st = end_symtab (pst->texthigh, 0, 0, pst->objfile, SECT_OFF_TEXT);
+ end_stabs ();
+
+ /* Sort the symbol table now, we are done adding symbols to it.
+ We must do this before parse_procedure calls lookup_symbol. */
+ sort_symtab_syms (st);
+
+ /* This may not be necessary for stabs symtabs. FIXME. */
+ sort_blocks (st);
+
+ /* Fill in procedure info next. */
+ first_pdr = 1;
+ pdr_ptr = ((char *) ecoff_data (cur_bfd)->external_pdr
+ + fh->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fh->cpd * external_pdr_size;
+ for (; pdr_ptr < pdr_end; pdr_ptr += external_pdr_size)
+ {
+ PDR pr;
+
+ (*swap_pdr_in) (cur_bfd, pdr_ptr, &pr);
+ if (first_pdr)
+ {
+ first_off = pr.adr;
+ first_pdr = 0;
+ }
+ parse_procedure (&pr, st, first_off);
+ }
+ }
+ else
+ {
+ /* This symbol table contains ordinary ecoff entries. */
+
+ /* FIXME: doesn't use pst->section_offsets. */
+
+ int f_max;
+ int maxlines;
+ EXTR *ext_ptr;
+
+ /* How many symbols will we need */
+ /* FIXME, this does not count enum values. */
+ f_max = pst->n_global_syms + pst->n_static_syms;
+ if (fh == 0)
+ {
+ maxlines = 0;
+ st = new_symtab ("unknown", f_max, 0, pst->objfile);
+ }
+ else
+ {
+ f_max += fh->csym + fh->cpd;
+ maxlines = 2 * fh->cline;
+ st = new_symtab (pst->filename, 2 * f_max, maxlines, pst->objfile);
+
+ /* The proper language was already determined when building
+ the psymtab, use it. */
+ st->language = PST_PRIVATE (pst)->pst_language;
+ }
+
+ psymtab_language = st->language;
+
+ lines = LINETABLE (st);
+
+ /* Get a new lexical context */
+
+ push_parse_stack ();
+ top_stack->cur_st = st;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (st),
+ STATIC_BLOCK);
+ BLOCK_START (top_stack->cur_block) = fh ? fh->adr : 0;
+ BLOCK_END (top_stack->cur_block) = 0;
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms = 2 * f_max;
+ top_stack->cur_type = 0;
+ top_stack->procadr = 0;
+ top_stack->numargs = 0;
+
+ if (fh)
+ {
+ char *sym_ptr;
+ char *sym_end;
+
+ /* Parse local symbols first */
+ sym_ptr = ((char *) ecoff_data (cur_bfd)->external_sym
+ + fh->isymBase * external_sym_size);
+ sym_end = sym_ptr + fh->csym * external_sym_size;
+ while (sym_ptr < sym_end)
+ {
+ SYMR sh;
+ int c;
+
+ (*swap_sym_in) (cur_bfd, sym_ptr, &sh);
+ c = parse_symbol (&sh,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase),
+ sym_ptr, fh->fBigendian);
+ sym_ptr += c * external_sym_size;
+ }
+
+ /* Linenumbers. At the end, check if we can save memory.
+ parse_lines has to look ahead an arbitrary number of PDR
+ structures, so we swap them all first. */
+ if (fh->cpd > 0)
+ {
+ PDR *pr_block;
+ struct cleanup *old_chain;
+ char *pdr_ptr;
+ char *pdr_end;
+ PDR *pdr_in;
+ PDR *pdr_in_end;
+
+ pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR));
+
+ old_chain = make_cleanup (free, pr_block);
+
+ pdr_ptr = ((char *) ecoff_data (cur_bfd)->external_pdr
+ + fh->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fh->cpd * external_pdr_size;
+ pdr_in = pr_block;
+ for (;
+ pdr_ptr < pdr_end;
+ pdr_ptr += external_pdr_size, pdr_in++)
+ (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in);
+
+ parse_lines (fh, pr_block, lines, maxlines);
+ if (lines->nitems < fh->cline)
+ lines = shrink_linetable (lines);
+
+ /* Fill in procedure info next. */
+ pdr_in = pr_block;
+ pdr_in_end = pdr_in + fh->cpd;
+ for (; pdr_in < pdr_in_end; pdr_in++)
+ parse_procedure (pdr_in, 0, pr_block->adr);
+
+ do_cleanups (old_chain);
+ }
+ }
+
+ LINETABLE (st) = lines;
+
+ /* .. and our share of externals.
+ XXX use the global list to speed up things here. how?
+ FIXME, Maybe quit once we have found the right number of ext's? */
+ top_stack->cur_st = st;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st),
+ GLOBAL_BLOCK);
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms = (ecoff_data (cur_bfd)->symbolic_header.isymMax
+ + ecoff_data (cur_bfd)->symbolic_header.ipdMax
+ + ecoff_data (cur_bfd)->symbolic_header.iextMax);
+
+ ext_ptr = PST_PRIVATE (pst)->extern_tab;
+ for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++)
+ parse_external (ext_ptr, 1, fh->fBigendian);
+
+ /* If there are undefined symbols, tell the user.
+ The alpha has an undefined symbol for every symbol that is
+ from a shared library, so tell the user only if verbose is on. */
+ if (info_verbose && n_undef_symbols)
+ {
+ printf_filtered ("File %s contains %d unresolved references:",
+ st->filename, n_undef_symbols);
+ printf_filtered ("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n",
+ n_undef_vars, n_undef_procs, n_undef_labels);
+ n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0;
+
+ }
+ pop_parse_stack ();
+
+ /* Sort the symbol table now, we are done adding symbols to it.*/
+ sort_symtab_syms (st);
+
+ sort_blocks (st);
+ }
+
+ /* Now link the psymtab and the symtab. */
+ pst->symtab = st;
+
+ current_objfile = NULL;
+}
+
+/* Ancillary parsing procedures. */
+
+/* Lookup the type at relative index RN. Return it in TPP
+ if found and in any event come up with its name PNAME.
+ BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian).
+ Return value says how many aux symbols we ate. */
+
+static int
+cross_ref (fd, ax, tpp, type_code, pname, bigend, sym_name)
+ int fd;
+ union aux_ext *ax;
+ struct type **tpp;
+ enum type_code type_code; /* Use to alloc new type if none is found. */
+ char **pname;
+ int bigend;
+ char *sym_name;
+{
+ RNDXR rn[1];
+ unsigned int rf;
+ int result = 1;
+ FDR *fh;
+ char *esh;
+ SYMR sh;
+ int xref_fd;
+ struct mips_pending *pend;
+
+ *tpp = (struct type *)NULL;
+
+ ecoff_swap_rndx_in (bigend, &ax->a_rndx, rn);
+
+ /* Escape index means 'the next one' */
+ if (rn->rfd == 0xfff)
+ {
+ result++;
+ rf = AUX_GET_ISYM (bigend, ax + 1);
+ }
+ else
+ {
+ rf = rn->rfd;
+ }
+
+ /* mips cc uses a rf of -1 for opaque struct definitions.
+ Set TYPE_FLAG_STUB for these types so that check_stub_type will
+ resolve them if the struct gets defined in another compilation unit. */
+ if (rf == -1)
+ {
+ *pname = "<undefined>";
+ *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+ TYPE_FLAGS (*tpp) |= TYPE_FLAG_STUB;
+ return result;
+ }
+
+ /* mips cc uses an escaped rn->index of 0 for struct return types
+ of procedures that were compiled without -g. These will always remain
+ undefined. */
+ if (rn->rfd == 0xfff && rn->index == 0)
+ {
+ *pname = "<undefined>";
+ return result;
+ }
+
+ /* Find the relative file descriptor and the symbol in it. */
+ fh = get_rfd (fd, rf);
+ xref_fd = fh - ecoff_data (cur_bfd)->fdr;
+
+ if (rn->index >= fh->csym)
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ complain (&bad_rfd_entry_complaint,
+ sym_name, xref_fd, rn->index);
+ return result;
+ }
+
+ /* If we have processed this symbol then we left a forwarding
+ pointer to the type in the pending list. If not, we`ll put
+ it in a list of pending types, to be processed later when
+ the file will be. In any event, we collect the name for the
+ type here. */
+
+ esh = ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((fh->isymBase + rn->index)
+ * ecoff_backend (cur_bfd)->external_sym_size));
+ (*ecoff_backend (cur_bfd)->swap_sym_in) (cur_bfd, esh, &sh);
+
+ /* Make sure that this type of cross reference can be handled. */
+ if (sh.sc != scInfo
+ || (sh.st != stBlock && sh.st != stTypedef
+ && sh.st != stStruct && sh.st != stUnion
+ && sh.st != stEnum))
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ complain (&bad_rfd_entry_complaint,
+ sym_name, xref_fd, rn->index);
+ return result;
+ }
+
+ *pname = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss;
+
+ pend = is_pending_symbol (fh, esh);
+ if (pend)
+ *tpp = pend->t;
+ else
+ {
+ /* We have not yet seen this type. */
+
+ if (sh.iss == 0 && sh.st == stTypedef)
+ {
+ TIR tir;
+
+ /* alpha cc puts out a stTypedef with a sh.iss of zero for
+ two cases:
+ a) forward declarations of structs/unions/enums which are not
+ defined in this compilation unit.
+ For these the type will be void. This is a bad design decision
+ as cross referencing across compilation units is impossible
+ due to the missing name.
+ b) forward declarations of structs/unions/enums which are defined
+ later in this file or in another file in the same compilation
+ unit. Simply cross reference those again to get the
+ true type.
+ The forward references are not entered in the pending list and
+ in the symbol table. */
+
+ ecoff_swap_tir_in (bigend,
+ &(ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase + sh.index)->a_ti,
+ &tir);
+ if (tir.tq0 != tqNil)
+ complain (&illegal_forward_tq0_complaint, sym_name);
+ switch (tir.bt)
+ {
+ case btVoid:
+ *tpp = init_type (type_code, 0, 0, (char *) NULL,
+ current_objfile);
+ *pname = "<undefined>";
+ break;
+
+ case btStruct:
+ case btUnion:
+ case btEnum:
+ cross_ref (xref_fd,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase + sh.index + 1),
+ tpp, type_code, pname,
+ fh->fBigendian, sym_name);
+ break;
+
+ default:
+ complain (&illegal_forward_bt_complaint, tir.bt, sym_name);
+ *tpp = init_type (type_code, 0, 0, (char *) NULL,
+ current_objfile);
+ break;
+ }
+ return result;
+ }
+ else if (sh.st == stTypedef)
+ {
+ /* Parse the type for a normal typedef. This might recursively call
+ cross_ref till we get a non typedef'ed type.
+ FIXME: This is not correct behaviour, but gdb currently
+ cannot handle typedefs without type copying. But type copying is
+ impossible as we might have mutual forward references between
+ two files and the copied type would not get filled in when
+ we later parse its definition. */
+ *tpp = parse_type (xref_fd,
+ ecoff_data (cur_bfd)->external_aux + fh->iauxBase,
+ sh.index,
+ (int *)NULL,
+ fh->fBigendian,
+ (ecoff_data (cur_bfd)->ss
+ + fh->issBase + sh.iss));
+ }
+ else
+ {
+ /* Cross reference to a struct/union/enum which is defined
+ in another file in the same compilation unit but that file
+ has not been parsed yet.
+ Initialize the type only, it will be filled in when
+ it's definition is parsed. */
+ *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+ }
+ add_pending (fh, esh, *tpp);
+ }
+
+ /* We used one auxent normally, two if we got a "next one" rf. */
+ return result;
+}
+
+
+/* Quick&dirty lookup procedure, to avoid the MI ones that require
+ keeping the symtab sorted */
+
+static struct symbol *
+mylookup_symbol (name, block, namespace, class)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+ enum address_class class;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+
+ bot = 0;
+ top = BLOCK_NSYMS (block);
+ inc = name[0];
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAME (sym)[0] == inc
+ && SYMBOL_NAMESPACE (sym) == namespace
+ && SYMBOL_CLASS (sym) == class
+ && strcmp (SYMBOL_NAME (sym), name) == 0)
+ return sym;
+ bot++;
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ if (block)
+ return mylookup_symbol (name, block, namespace, class);
+ return 0;
+}
+
+
+/* Add a new symbol S to a block B.
+ Infrequently, we will need to reallocate the block to make it bigger.
+ We only detect this case when adding to top_stack->cur_block, since
+ that's the only time we know how big the block is. FIXME. */
+
+static void
+add_symbol (s, b)
+ struct symbol *s;
+ struct block *b;
+{
+ int nsyms = BLOCK_NSYMS (b)++;
+ struct block *origb;
+ struct parse_stack *stackp;
+
+ if (b == top_stack->cur_block &&
+ nsyms >= top_stack->maxsyms)
+ {
+ complain (&block_overflow_complaint, SYMBOL_NAME (s));
+ /* In this case shrink_block is actually grow_block, since
+ BLOCK_NSYMS(b) is larger than its current size. */
+ origb = b;
+ b = shrink_block (top_stack->cur_block, top_stack->cur_st);
+
+ /* Now run through the stack replacing pointers to the
+ original block. shrink_block has already done this
+ for the blockvector and BLOCK_FUNCTION. */
+ for (stackp = top_stack; stackp; stackp = stackp->next)
+ {
+ if (stackp->cur_block == origb)
+ {
+ stackp->cur_block = b;
+ stackp->maxsyms = BLOCK_NSYMS (b);
+ }
+ }
+ }
+ BLOCK_SYM (b, nsyms) = s;
+}
+
+/* Add a new block B to a symtab S */
+
+static void
+add_block (b, s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR (s);
+
+ bv = (struct blockvector *) xrealloc ((PTR) bv,
+ (sizeof (struct blockvector)
+ + BLOCKVECTOR_NBLOCKS (bv)
+ * sizeof (bv->block)));
+ if (bv != BLOCKVECTOR (s))
+ BLOCKVECTOR (s) = bv;
+
+ BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b;
+}
+
+/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
+ MIPS' linenumber encoding might need more than one byte
+ to describe it, LAST is used to detect these continuation lines.
+
+ Combining lines with the same line number seems like a bad idea.
+ E.g: There could be a line number entry with the same line number after the
+ prologue and GDB should not ignore it (this is a better way to find
+ a prologue than mips_skip_prologue).
+ But due to the compressed line table format there are line number entries
+ for the same line which are needed to bridge the gap to the next
+ line number entry. These entries have a bogus address info with them
+ and we are unable to tell them from intended duplicate line number
+ entries.
+ This is another reason why -ggdb debugging format is preferable. */
+
+static int
+add_line (lt, lineno, adr, last)
+ struct linetable *lt;
+ int lineno;
+ CORE_ADDR adr;
+ int last;
+{
+ if (last == 0)
+ last = -2; /* make sure we record first line */
+
+ if (last == lineno) /* skip continuation lines */
+ return lineno;
+
+ lt->item[lt->nitems].line = lineno;
+ lt->item[lt->nitems++].pc = adr << 2;
+ return lineno;
+}
+
+/* Sorting and reordering procedures */
+
+/* Blocks with a smaller low bound should come first */
+
+static int
+compare_blocks (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
+{
+ register int addr_diff;
+ struct block **b1 = (struct block **) arg1;
+ struct block **b2 = (struct block **) arg2;
+
+ addr_diff = (BLOCK_START ((*b1))) - (BLOCK_START ((*b2)));
+ if (addr_diff == 0)
+ return (BLOCK_END ((*b2))) - (BLOCK_END ((*b1)));
+ return addr_diff;
+}
+
+/* Sort the blocks of a symtab S.
+ Reorder the blocks in the blockvector by code-address,
+ as required by some MI search routines */
+
+static void
+sort_blocks (s)
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR (s);
+
+ if (BLOCKVECTOR_NBLOCKS (bv) <= 2)
+ {
+ /* Cosmetic */
+ if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0)
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0;
+ if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0)
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0;
+ return;
+ }
+ /*
+ * This is very unfortunate: normally all functions are compiled in
+ * the order they are found, but if the file is compiled -O3 things
+ * are very different. It would be nice to find a reliable test
+ * to detect -O3 images in advance.
+ */
+ if (BLOCKVECTOR_NBLOCKS (bv) > 3)
+ qsort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK),
+ BLOCKVECTOR_NBLOCKS (bv) - FIRST_LOCAL_BLOCK,
+ sizeof (struct block *),
+ compare_blocks);
+
+ {
+ register CORE_ADDR high = 0;
+ register int i, j = BLOCKVECTOR_NBLOCKS (bv);
+
+ for (i = FIRST_LOCAL_BLOCK; i < j; i++)
+ if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)))
+ high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i));
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high;
+ }
+
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) =
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK));
+
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) =
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) =
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+}
+
+
+/* Constructor/restructor/destructor procedures */
+
+/* Allocate a new symtab for NAME. Needs an estimate of how many symbols
+ MAXSYMS and linenumbers MAXLINES we'll put in it */
+
+static struct symtab *
+new_symtab (name, maxsyms, maxlines, objfile)
+ char *name;
+ int maxsyms;
+ int maxlines;
+ struct objfile *objfile;
+{
+ struct symtab *s = allocate_symtab (name, objfile);
+
+ LINETABLE (s) = new_linetable (maxlines);
+
+ /* All symtabs must have at least two blocks */
+ BLOCKVECTOR (s) = new_bvect (2);
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK) = new_block (maxsyms);
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) = new_block (maxsyms);
+ BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) =
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+
+ s->free_code = free_linetable;
+
+ return (s);
+}
+
+/* Allocate a new partial_symtab NAME */
+
+static struct partial_symtab *
+new_psymtab (name, objfile)
+ char *name;
+ struct objfile *objfile;
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (name, objfile);
+
+ /* Keep a backpointer to the file's symbols */
+
+ psymtab->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc)));
+ memset ((PTR) psymtab->read_symtab_private, 0, sizeof (struct symloc));
+ CUR_BFD (psymtab) = cur_bfd;
+
+ /* The way to turn this into a symtab is to call... */
+ psymtab->read_symtab = mipscoff_psymtab_to_symtab;
+ return (psymtab);
+}
+
+
+/* Allocate a linetable array of the given SIZE. Since the struct
+ already includes one item, we subtract one when calculating the
+ proper size to allocate. */
+
+static struct linetable *
+new_linetable (size)
+ int size;
+{
+ struct linetable *l;
+
+ size = (size - 1) * sizeof (l->item) + sizeof (struct linetable);
+ l = (struct linetable *) xmalloc (size);
+ l->nitems = 0;
+ return l;
+}
+
+/* Oops, too big. Shrink it. This was important with the 2.4 linetables,
+ I am not so sure about the 3.4 ones.
+
+ Since the struct linetable already includes one item, we subtract one when
+ calculating the proper size to allocate. */
+
+static struct linetable *
+shrink_linetable (lt)
+ struct linetable *lt;
+{
+
+ return (struct linetable *) xrealloc ((PTR) lt,
+ (sizeof (struct linetable)
+ + ((lt->nitems - 1)
+ * sizeof (lt->item))));
+}
+
+/* Allocate and zero a new blockvector of NBLOCKS blocks. */
+
+static struct blockvector *
+new_bvect (nblocks)
+ int nblocks;
+{
+ struct blockvector *bv;
+ int size;
+
+ size = sizeof (struct blockvector) + nblocks * sizeof (struct block *);
+ bv = (struct blockvector *) xzalloc (size);
+
+ BLOCKVECTOR_NBLOCKS (bv) = nblocks;
+
+ return bv;
+}
+
+/* Allocate and zero a new block of MAXSYMS symbols */
+
+static struct block *
+new_block (maxsyms)
+ int maxsyms;
+{
+ int size = sizeof (struct block) + (maxsyms - 1) * sizeof (struct symbol *);
+
+ return (struct block *) xzalloc (size);
+}
+
+/* Ooops, too big. Shrink block B in symtab S to its minimal size.
+ Shrink_block can also be used by add_symbol to grow a block. */
+
+static struct block *
+shrink_block (b, s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct block *new;
+ struct blockvector *bv = BLOCKVECTOR (s);
+ int i;
+
+ /* Just reallocate it and fix references to the old one */
+
+ new = (struct block *) xrealloc ((PTR) b,
+ (sizeof (struct block)
+ + ((BLOCK_NSYMS (b) - 1)
+ * sizeof (struct symbol *))));
+
+ /* Should chase pointers to old one. Fortunately, that`s just
+ the block`s function and inferior blocks */
+ if (BLOCK_FUNCTION (new) && SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) == b)
+ SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) = new;
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++)
+ if (BLOCKVECTOR_BLOCK (bv, i) == b)
+ BLOCKVECTOR_BLOCK (bv, i) = new;
+ else if (BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) == b)
+ BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) = new;
+ return new;
+}
+
+/* Create a new symbol with printname NAME */
+
+static struct symbol *
+new_symbol (name)
+ char *name;
+{
+ struct symbol *s = ((struct symbol *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct symbol)));
+
+ memset ((PTR) s, 0, sizeof (*s));
+ SYMBOL_NAME (s) = name;
+ SYMBOL_LANGUAGE (s) = psymtab_language;
+ SYMBOL_INIT_DEMANGLED_NAME (s, &current_objfile->symbol_obstack);
+ return s;
+}
+
+/* Create a new type with printname NAME */
+
+static struct type *
+new_type (name)
+ char *name;
+{
+ struct type *t;
+
+ t = alloc_type (current_objfile);
+ TYPE_NAME (t) = name;
+ TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default;
+ return t;
+}
+
+
+/* Things used for calling functions in the inferior.
+ These functions are exported to our companion
+ mips-tdep.c file and are here because they play
+ with the symbol-table explicitly. */
+
+/* Sigtramp: make sure we have all the necessary information
+ about the signal trampoline code. Since the official code
+ from MIPS does not do so, we make up that information ourselves.
+ If they fix the library (unlikely) this code will neutralize itself. */
+
+static void
+fixup_sigtramp ()
+{
+ struct symbol *s;
+ struct symtab *st;
+ struct block *b, *b0 = NULL;
+
+ sigtramp_address = -1;
+
+ /* We have to handle the following cases here:
+ a) The Mips library has a sigtramp label within sigvec.
+ b) Irix has a _sigtramp which we want to use, but it also has sigvec. */
+ s = lookup_symbol ("sigvec", 0, VAR_NAMESPACE, 0, NULL);
+ if (s != 0)
+ {
+ b0 = SYMBOL_BLOCK_VALUE (s);
+ s = lookup_symbol ("sigtramp", b0, VAR_NAMESPACE, 0, NULL);
+ }
+ if (s == 0)
+ {
+ /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */
+ s = lookup_symbol ("_sigtramp", 0, VAR_NAMESPACE, 0, NULL);
+ }
+
+ /* But maybe this program uses its own version of sigvec */
+ if (s == 0)
+ return;
+
+ /* Did we or MIPSco fix the library ? */
+ if (SYMBOL_CLASS (s) == LOC_BLOCK)
+ {
+ sigtramp_address = BLOCK_START (SYMBOL_BLOCK_VALUE (s));
+ sigtramp_end = BLOCK_END (SYMBOL_BLOCK_VALUE (s));
+ return;
+ }
+
+ sigtramp_address = SYMBOL_VALUE (s);
+ sigtramp_end = sigtramp_address + 0x88; /* black magic */
+
+ /* But what symtab does it live in ? */
+ st = find_pc_symtab (SYMBOL_VALUE (s));
+
+ /*
+ * Ok, there goes the fix: turn it into a procedure, with all the
+ * needed info. Note we make it a nested procedure of sigvec,
+ * which is the way the (assembly) code is actually written.
+ */
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ SYMBOL_TYPE (s) = init_type (TYPE_CODE_FUNC, 4, 0, (char *) NULL,
+ st->objfile);
+ TYPE_TARGET_TYPE (SYMBOL_TYPE (s)) = builtin_type_void;
+
+ /* Need a block to allocate MIPS_EFI_SYMBOL_NAME in */
+ b = new_block (1);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_START (b) = sigtramp_address;
+ BLOCK_END (b) = sigtramp_end;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_SUPERBLOCK (b) = BLOCK_SUPERBLOCK (b0);
+ add_block (b, st);
+ sort_blocks (st);
+
+ /* Make a MIPS_EFI_SYMBOL_NAME entry for it */
+ {
+ struct mips_extra_func_info *e =
+ ((struct mips_extra_func_info *)
+ xzalloc (sizeof (struct mips_extra_func_info)));
+
+ e->numargs = 0; /* the kernel thinks otherwise */
+ /* align_longword(sigcontext + SIGFRAME) */
+ e->pdr.frameoffset = 0x150;
+ e->pdr.framereg = SP_REGNUM;
+ /* read_next_frame_reg provides the true pc at the time of signal */
+ e->pdr.pcreg = PC_REGNUM;
+ e->pdr.regmask = -2;
+ e->pdr.regoffset = -(41 * sizeof (int));
+ e->pdr.fregmask = -1;
+ e->pdr.fregoffset = -(7 * sizeof (int));
+ e->pdr.isym = (long) s;
+ e->pdr.adr = sigtramp_address;
+
+ current_objfile = st->objfile; /* Keep new_symbol happy */
+ s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_VALUE (s) = (long) e;
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ current_objfile = NULL;
+ }
+
+ BLOCK_SYM (b, BLOCK_NSYMS (b)++) = s;
+}
+
+
+/* Fake up identical offsets for all sections. */
+
+struct section_offsets *
+mipscoff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ section_offsets = ((struct section_offsets *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ (sizeof (struct section_offsets)
+ + (sizeof (section_offsets->offsets)
+ * (SECT_OFF_MAX - 1)))));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* Initialization */
+
+static struct sym_fns ecoff_sym_fns =
+{
+ "ecoff", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */
+ mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */
+ mipscoff_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+
+void
+_initialize_mipsread ()
+{
+ add_symtab_fns (&ecoff_sym_fns);
+
+ /* Missing basic types */
+
+ builtin_type_string =
+ init_type (TYPE_CODE_STRING,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "string",
+ (struct objfile *) NULL);
+ builtin_type_complex =
+ init_type (TYPE_CODE_FLT,
+ TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "complex",
+ (struct objfile *) NULL);
+ builtin_type_double_complex =
+ init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "double complex",
+ (struct objfile *) NULL);
+ builtin_type_fixed_dec =
+ init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "fixed decimal",
+ (struct objfile *) NULL);
+ builtin_type_float_dec =
+ init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "floating decimal",
+ (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/nlmread.c b/gnu/usr.bin/gdb/gdb/nlmread.c
new file mode 100644
index 000000000000..fde3af249328
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nlmread.c
@@ -0,0 +1,300 @@
+/* Read NLM (NetWare Loadable Module) format executable files for GDB.
+ Copyright 1993 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+
+static void
+nlm_new_init PARAMS ((struct objfile *));
+
+static void
+nlm_symfile_init PARAMS ((struct objfile *));
+
+static void
+nlm_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+nlm_symfile_finish PARAMS ((struct objfile *));
+
+static void
+nlm_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *));
+
+static struct section_offsets *
+nlm_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type,
+ struct objfile *));
+
+
+/* Initialize anything that needs initializing when a completely new symbol
+ file is specified (not just adding some symbols from another file, e.g. a
+ shared library).
+
+ We reinitialize buildsym, since gdb will be able to read stabs from an NLM
+ file at some point in the near future. */
+
+static void
+nlm_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+
+/* NLM specific initialization routine for reading symbols.
+
+ It is passed a pointer to a struct sym_fns which contains, among other
+ things, the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we can fill with goodies.
+
+ For now at least, we have nothing in particular to do, so this function is
+ just a stub. */
+
+static void
+nlm_symfile_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+static void
+record_minimal_symbol (name, address, ms_type, objfile)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ struct objfile *objfile;
+{
+ name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
+ prim_record_minimal_symbol (name, address, ms_type);
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ nlm_symtab_read -- read the symbol table of an NLM file
+
+SYNOPSIS
+
+ void nlm_symtab_read (bfd *abfd, CORE_ADDR addr,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given an open bfd, a base address to relocate symbols to, and a
+ flag that specifies whether or not this bfd is for an executable
+ or not (may be shared library for example), add all the global
+ function and data symbols to the minimal symbol table.
+*/
+
+static void
+nlm_symtab_read (abfd, addr, objfile)
+ bfd *abfd;
+ CORE_ADDR addr;
+ struct objfile *objfile;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ enum minimal_symbol_type ms_type;
+
+ storage_needed = get_symtab_upper_bound (abfd);
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = symbol_table[i];
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate all non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ {
+ symaddr += addr;
+ }
+
+ /* For non-absolute symbols, use the type of the section
+ they are relative to, to intuit text/data. Bfd provides
+ no way of figuring this out for absolute symbols. */
+ if (sym -> section -> flags & SEC_CODE)
+ {
+ ms_type = mst_text;
+ }
+ else if (sym -> section -> flags & SEC_DATA)
+ {
+ ms_type = mst_data;
+ }
+ else
+ {
+ ms_type = mst_unknown;
+ }
+ record_minimal_symbol ((char *) sym -> name, symaddr, ms_type,
+ objfile);
+ }
+ }
+ do_cleanups (back_to);
+ }
+}
+
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to nlm_symfile_init, which
+ currently does nothing.
+
+ SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
+ in each section. We simplify it down to a single offset for all
+ symbols. FIXME.
+
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ This function only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real.
+
+ Note that NLM files have two sets of information that is potentially
+ useful for building gdb's minimal symbol table. The first is a list
+ of the publically exported symbols, and is currently used to build
+ bfd's canonical symbol table. The second is an optional native debugging
+ format which contains additional symbols (and possibly duplicates of
+ the publically exported symbols). The optional native debugging format
+ is not currently used. */
+
+static void
+nlm_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ bfd *abfd = objfile -> obfd;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ /* FIXME, should take a section_offsets param, not just an offset. */
+
+ offset = ANOFFSET (section_offsets, 0);
+
+ /* Process the NLM export records, which become the bfd's canonical symbol
+ table. */
+
+ nlm_symtab_read (abfd, offset, objfile);
+
+ /* FIXME: We could locate and read the optional native debugging format
+ here and add the symbols to the minimal symbol table. */
+
+ if (!have_partial_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+nlm_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_private != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_private);
+ }
+}
+
+/* NLM specific parsing routine for section offsets.
+ FIXME: This may or may not be necessary. All the symbol readers seem
+ to have similar code. See if it can be generalized and moved elsewhere. */
+
+static
+struct section_offsets *
+nlm_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ {
+ ANOFFSET (section_offsets, i) = addr;
+ }
+
+ return (section_offsets);
+}
+
+
+/* Register that we are able to handle NLM file format. */
+
+static struct sym_fns nlm_sym_fns =
+{
+ "nlm", /* sym_name: name or name prefix of BFD target type */
+ 3, /* sym_namelen: number of significant sym_name chars */
+ nlm_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ nlm_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ nlm_symfile_read, /* sym_read: read a symbol file into symtab */
+ nlm_symfile_finish, /* sym_finish: finished with file, cleanup */
+ nlm_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_nlmread ()
+{
+ add_symtab_fns (&nlm_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/nm.h b/gnu/usr.bin/gdb/gdb/nm.h
new file mode 100644
index 000000000000..a7af00f33d87
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nm.h
@@ -0,0 +1,44 @@
+/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef NM_FREEBSD_H
+#define NM_FREEBSD_H
+
+/* Be shared lib aware */
+#include "solib.h"
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+
+/* #undef FLOAT_INFO /* No float info yet */
+#define FLOAT_INFO extern i386_float_info (); \
+ i386_float_info ()
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = i386_register_u_addr ((blockend),(regno));
+
+extern int
+i386_register_u_addr PARAMS ((int, int));
+
+#define PTRACE_ARG3_TYPE char*
+
+#endif /* NM_FREEBSD_H */
diff --git a/gnu/usr.bin/gdb/gdb/objfiles.c b/gnu/usr.bin/gdb/gdb/objfiles.c
new file mode 100644
index 000000000000..b111f005c05d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.c
@@ -0,0 +1,773 @@
+/* GDB routines for manipulating objfiles.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file contains support routines for creating, manipulating, and
+ destroying objfile structures. */
+
+#include "defs.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "target.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <obstack.h>
+
+/* Prototypes for local functions */
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+static int
+open_existing_mapped_file PARAMS ((char *, long, int));
+
+static int
+open_mapped_file PARAMS ((char *filename, long mtime, int mapped));
+
+static CORE_ADDR
+map_to_address PARAMS ((void));
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Externally visible variables that are owned by this module.
+ See declarations in objfile.h for more info. */
+
+struct objfile *object_files; /* Linked list of all objfiles */
+struct objfile *current_objfile; /* For symbol file being read in */
+struct objfile *symfile_objfile; /* Main symbol table loaded from */
+
+int mapped_symbol_files; /* Try to use mapped symbol files */
+
+/* Locate all mappable sections of a BFD file.
+ objfile_p_char is a char * to get it through
+ bfd_map_over_sections; we cast it back to its proper type. */
+
+static void
+add_to_objfile_sections (abfd, asect, objfile_p_char)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR objfile_p_char;
+{
+ struct objfile *objfile = (struct objfile *) objfile_p_char;
+ struct obj_section section;
+ flagword aflag;
+
+ aflag = bfd_get_section_flags (abfd, asect);
+ /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+ if (!(aflag & SEC_LOAD))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ section.offset = 0;
+ section.objfile = objfile;
+ section.sec_ptr = asect;
+ section.addr = bfd_section_vma (abfd, asect);
+ section.endaddr = section.addr + bfd_section_size (abfd, asect);
+ obstack_grow (&objfile->psymbol_obstack, &section, sizeof(section));
+ objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1);
+}
+
+/* Builds a section table for OBJFILE.
+ Returns 0 if OK, 1 on error. */
+
+static int
+build_objfile_section_table (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sections)
+ abort();
+
+ objfile->sections_end = 0;
+ bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *)objfile);
+ objfile->sections = (struct obj_section *)
+ obstack_finish (&objfile->psymbol_obstack);
+ objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end;
+ return(0);
+}
+
+/* Given a pointer to an initialized bfd (ABFD) and a flag that indicates
+ whether or not an objfile is to be mapped (MAPPED), allocate a new objfile
+ struct, fill it in as best we can, link it into the list of all known
+ objfiles, and return a pointer to the new objfile struct. */
+
+struct objfile *
+allocate_objfile (abfd, mapped)
+ bfd *abfd;
+ int mapped;
+{
+ struct objfile *objfile = NULL;
+ int fd;
+ PTR md;
+ CORE_ADDR mapto;
+
+ mapped |= mapped_symbol_files;
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+ /* If we can support mapped symbol files, try to open/reopen the mapped file
+ that corresponds to the file from which we wish to read symbols. If the
+ objfile is to be mapped, we must malloc the structure itself using the
+ mmap version, and arrange that all memory allocation for the objfile uses
+ the mmap routines. If we are reusing an existing mapped file, from which
+ we get our objfile pointer, we have to make sure that we update the
+ pointers to the alloc/free functions in the obstack, in case these
+ functions have moved within the current gdb. */
+
+ fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd),
+ mapped);
+ if (fd >= 0)
+ {
+ if (((mapto = map_to_address ()) == 0) ||
+ ((md = mmalloc_attach (fd, (PTR) mapto)) == NULL))
+ {
+ close (fd);
+ }
+ else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL)
+ {
+ /* Update memory corruption handler function addresses. */
+ init_malloc (md);
+ objfile -> md = md;
+ objfile -> mmfd = fd;
+ /* Update pointers to functions to *our* copies */
+ obstack_chunkfun (&objfile -> psymbol_obstack, xmmalloc);
+ obstack_freefun (&objfile -> psymbol_obstack, mfree);
+ obstack_chunkfun (&objfile -> symbol_obstack, xmmalloc);
+ obstack_freefun (&objfile -> symbol_obstack, mfree);
+ obstack_chunkfun (&objfile -> type_obstack, xmmalloc);
+ obstack_freefun (&objfile -> type_obstack, mfree);
+ /* If already in objfile list, unlink it. */
+ unlink_objfile (objfile);
+ /* Forget things specific to a particular gdb, may have changed. */
+ objfile -> sf = NULL;
+ }
+ else
+ {
+ /* Set up to detect internal memory corruption. MUST be done before
+ the first malloc. See comments in init_malloc() and mmcheck(). */
+ init_malloc (md);
+ objfile = (struct objfile *) xmmalloc (md, sizeof (struct objfile));
+ memset (objfile, 0, sizeof (struct objfile));
+ objfile -> md = md;
+ objfile -> mmfd = fd;
+ objfile -> flags |= OBJF_MAPPED;
+ mmalloc_setkey (objfile -> md, 0, objfile);
+ obstack_specify_allocation_with_arg (&objfile -> psymbol_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ obstack_specify_allocation_with_arg (&objfile -> symbol_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ obstack_specify_allocation_with_arg (&objfile -> type_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ }
+ }
+
+ if (mapped && (objfile == NULL))
+ {
+ warning ("symbol table for '%s' will not be mapped",
+ bfd_get_filename (abfd));
+ }
+
+#else /* defined(NO_MMALLOC) || !defined(HAVE_MMAP) */
+
+ if (mapped)
+ {
+ warning ("this version of gdb does not support mapped symbol tables.");
+
+ /* Turn off the global flag so we don't try to do mapped symbol tables
+ any more, which shuts up gdb unless the user specifically gives the
+ "mapped" keyword again. */
+
+ mapped_symbol_files = 0;
+ }
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+ /* If we don't support mapped symbol files, didn't ask for the file to be
+ mapped, or failed to open the mapped file for some reason, then revert
+ back to an unmapped objfile. */
+
+ if (objfile == NULL)
+ {
+ objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
+ memset (objfile, 0, sizeof (struct objfile));
+ objfile -> md = NULL;
+ obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc,
+ free);
+ obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc,
+ free);
+ obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc,
+ free);
+ }
+
+ /* Update the per-objfile information that comes from the bfd, ensuring
+ that any data that is reference is saved in the per-objfile data
+ region. */
+
+ objfile -> obfd = abfd;
+ if (objfile -> name != NULL)
+ {
+ mfree (objfile -> md, objfile -> name);
+ }
+ objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd));
+ objfile -> mtime = bfd_get_mtime (abfd);
+
+ /* Build section table. */
+
+ if (build_objfile_section_table (objfile))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ objfile -> name, bfd_errmsg (bfd_error));
+ }
+
+ /* Push this file onto the head of the linked list of other such files. */
+
+ objfile -> next = object_files;
+ object_files = objfile;
+
+ return (objfile);
+}
+
+/* Unlink OBJFILE from the list of known objfiles, if it is found in the
+ list.
+
+ It is not a bug, or error, to call this function if OBJFILE is not known
+ to be in the current list. This is done in the case of mapped objfiles,
+ for example, just to ensure that the mapped objfile doesn't appear twice
+ in the list. Since the list is threaded, linking in a mapped objfile
+ twice would create a circular list.
+
+ If OBJFILE turns out to be in the list, we zap it's NEXT pointer after
+ unlinking it, just to ensure that we have completely severed any linkages
+ between the OBJFILE and the list. */
+
+void
+unlink_objfile (objfile)
+ struct objfile *objfile;
+{
+ struct objfile** objpp;
+
+ for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp) -> next))
+ {
+ if (*objpp == objfile)
+ {
+ *objpp = (*objpp) -> next;
+ objfile -> next = NULL;
+ break;
+ }
+ }
+}
+
+
+/* Destroy an objfile and all the symtabs and psymtabs under it. Note
+ that as much as possible is allocated on the symbol_obstack and
+ psymbol_obstack, so that the memory can be efficiently freed.
+
+ Things which we do NOT free because they are not in malloc'd memory
+ or not in memory specific to the objfile include:
+
+ objfile -> sf
+
+ FIXME: If the objfile is using reusable symbol information (via mmalloc),
+ then we need to take into account the fact that more than one process
+ may be using the symbol information at the same time (when mmalloc is
+ extended to support cooperative locking). When more than one process
+ is using the mapped symbol info, we need to be more careful about when
+ we free objects in the reusable area. */
+
+void
+free_objfile (objfile)
+ struct objfile *objfile;
+{
+ int mmfd;
+
+ /* First do any symbol file specific actions required when we are
+ finished with a particular symbol file. Note that if the objfile
+ is using reusable symbol information (via mmalloc) then each of
+ these routines is responsible for doing the correct thing, either
+ freeing things which are valid only during this particular gdb
+ execution, or leaving them to be reused during the next one. */
+
+ if (objfile -> sf != NULL)
+ {
+ (*objfile -> sf -> sym_finish) (objfile);
+ }
+
+ /* We always close the bfd. */
+
+ if (objfile -> obfd != NULL)
+ {
+ char *name = bfd_get_filename (objfile->obfd);
+ bfd_close (objfile -> obfd);
+ free (name);
+ }
+
+ /* Remove it from the chain of all objfiles. */
+
+ unlink_objfile (objfile);
+
+ /* Before the symbol table code was redone to make it easier to
+ selectively load and remove information particular to a specific
+ linkage unit, gdb used to do these things whenever the monolithic
+ symbol table was blown away. How much still needs to be done
+ is unknown, but we play it safe for now and keep each action until
+ it is shown to be no longer needed. */
+
+#if defined (CLEAR_SOLIB)
+ CLEAR_SOLIB ();
+ /* CLEAR_SOLIB closes the bfd's for any shared libraries. But
+ the to_sections for a core file might refer to those bfd's. So
+ detach any core file. */
+ {
+ struct target_ops *t = find_core_target ();
+ if (t != NULL)
+ (t->to_detach) (NULL, 0);
+ }
+#endif
+ clear_pc_function_cache ();
+
+ /* The last thing we do is free the objfile struct itself for the
+ non-reusable case, or detach from the mapped file for the reusable
+ case. Note that the mmalloc_detach or the mfree is the last thing
+ we can do with this objfile. */
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+ if (objfile -> flags & OBJF_MAPPED)
+ {
+ /* Remember the fd so we can close it. We can't close it before
+ doing the detach, and after the detach the objfile is gone. */
+ mmfd = objfile -> mmfd;
+ mmalloc_detach (objfile -> md);
+ objfile = NULL;
+ close (mmfd);
+ }
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+ /* If we still have an objfile, then either we don't support reusable
+ objfiles or this one was not reusable. So free it normally. */
+
+ if (objfile != NULL)
+ {
+ if (objfile -> name != NULL)
+ {
+ mfree (objfile -> md, objfile -> name);
+ }
+ if (objfile->global_psymbols.list)
+ mfree (objfile->md, objfile->global_psymbols.list);
+ if (objfile->static_psymbols.list)
+ mfree (objfile->md, objfile->static_psymbols.list);
+ /* Free the obstacks for non-reusable objfiles */
+ obstack_free (&objfile -> psymbol_obstack, 0);
+ obstack_free (&objfile -> symbol_obstack, 0);
+ obstack_free (&objfile -> type_obstack, 0);
+ mfree (objfile -> md, objfile);
+ objfile = NULL;
+ }
+}
+
+
+/* Free all the object files at once and clean up their users. */
+
+void
+free_all_objfiles ()
+{
+ struct objfile *objfile, *temp;
+
+ ALL_OBJFILES_SAFE (objfile, temp)
+ {
+ free_objfile (objfile);
+ }
+ clear_symtab_users ();
+}
+
+/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
+ entries in new_offsets. */
+void
+objfile_relocate (objfile, new_offsets)
+ struct objfile *objfile;
+ struct section_offsets *new_offsets;
+{
+ struct section_offsets *delta = (struct section_offsets *) alloca
+ (sizeof (struct section_offsets)
+ + objfile->num_sections * sizeof (delta->offsets));
+
+ {
+ int i;
+ int something_changed = 0;
+ for (i = 0; i < objfile->num_sections; ++i)
+ {
+ ANOFFSET (delta, i) =
+ ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i);
+ if (ANOFFSET (delta, i) != 0)
+ something_changed = 1;
+ }
+ if (!something_changed)
+ return;
+ }
+
+ /* OK, get all the symtabs. */
+ {
+ struct symtab *s;
+
+ for (s = objfile->symtabs; s; s = s->next)
+ {
+ struct linetable *l;
+ struct blockvector *bv;
+ int i;
+
+ /* First the line table. */
+ l = LINETABLE (s);
+ if (l)
+ {
+ for (i = 0; i < l->nitems; ++i)
+ l->item[i].pc += ANOFFSET (delta, s->block_line_section);
+ }
+
+ /* Don't relocate a shared blockvector more than once. */
+ if (!s->primary)
+ continue;
+
+ bv = BLOCKVECTOR (s);
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
+ {
+ struct block *b;
+ int j;
+
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+ BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+ for (j = 0; j < BLOCK_NSYMS (b); ++j)
+ {
+ struct symbol *sym = BLOCK_SYM (b, j);
+ /* The RS6000 code from which this was taken skipped
+ any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE.
+ But I'm leaving out that test, on the theory that
+ they can't possibly pass the tests below. */
+ if ((SYMBOL_CLASS (sym) == LOC_LABEL
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ && SYMBOL_SECTION (sym) >= 0)
+ {
+ SYMBOL_VALUE_ADDRESS (sym) +=
+ ANOFFSET (delta, SYMBOL_SECTION (sym));
+ }
+ }
+ }
+ }
+ }
+
+ {
+ struct partial_symtab *p;
+
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+ {
+ /* FIXME: specific to symbol readers which use gdb-stabs.h.
+ We can only get away with it since objfile_relocate is only
+ used on XCOFF, which lacks psymtabs, and for gdb-stabs.h
+ targets. */
+ p->textlow += ANOFFSET (delta, SECT_OFF_TEXT);
+ p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+ }
+
+ {
+ struct partial_symbol *psym;
+
+ for (psym = objfile->global_psymbols.list;
+ psym < objfile->global_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ for (psym = objfile->static_psymbols.list;
+ psym < objfile->static_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ }
+
+ {
+ struct minimal_symbol *msym;
+ ALL_OBJFILE_MSYMBOLS (objfile, msym)
+ if (SYMBOL_SECTION (msym) >= 0)
+ SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
+ }
+
+ {
+ int i;
+ for (i = 0; i < objfile->num_sections; ++i)
+ ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i);
+ }
+}
+
+/* Many places in gdb want to test just to see if we have any partial
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_partial_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> psymtabs != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Many places in gdb want to test just to see if we have any full
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_full_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> symtabs != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Many places in gdb want to test just to see if we have any minimal
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_minimal_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> msymbols != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+/* Given the name of a mapped symbol file in SYMSFILENAME, and the timestamp
+ of the corresponding symbol file in MTIME, try to open an existing file
+ with the name SYMSFILENAME and verify it is more recent than the base
+ file by checking it's timestamp against MTIME.
+
+ If SYMSFILENAME does not exist (or can't be stat'd), simply returns -1.
+
+ If SYMSFILENAME does exist, but is out of date, we check to see if the
+ user has specified creation of a mapped file. If so, we don't issue
+ any warning message because we will be creating a new mapped file anyway,
+ overwriting the old one. If not, then we issue a warning message so that
+ the user will know why we aren't using this existing mapped symbol file.
+ In either case, we return -1.
+
+ If SYMSFILENAME does exist and is not out of date, but can't be opened for
+ some reason, then prints an appropriate system error message and returns -1.
+
+ Otherwise, returns the open file descriptor. */
+
+static int
+open_existing_mapped_file (symsfilename, mtime, mapped)
+ char *symsfilename;
+ long mtime;
+ int mapped;
+{
+ int fd = -1;
+ struct stat sbuf;
+
+ if (stat (symsfilename, &sbuf) == 0)
+ {
+ if (sbuf.st_mtime < mtime)
+ {
+ if (!mapped)
+ {
+ warning ("mapped symbol file `%s' is out of date, ignored it",
+ symsfilename);
+ }
+ }
+ else if ((fd = open (symsfilename, O_RDWR)) < 0)
+ {
+ if (error_pre_print)
+ {
+ printf (error_pre_print);
+ }
+ print_sys_errmsg (symsfilename, errno);
+ }
+ }
+ return (fd);
+}
+
+/* Look for a mapped symbol file that corresponds to FILENAME and is more
+ recent than MTIME. If MAPPED is nonzero, the user has asked that gdb
+ use a mapped symbol file for this file, so create a new one if one does
+ not currently exist.
+
+ If found, then return an open file descriptor for the file, otherwise
+ return -1.
+
+ This routine is responsible for implementing the policy that generates
+ the name of the mapped symbol file from the name of a file containing
+ symbols that gdb would like to read. Currently this policy is to append
+ ".syms" to the name of the file.
+
+ This routine is also responsible for implementing the policy that
+ determines where the mapped symbol file is found (the search path).
+ This policy is that when reading an existing mapped file, a file of
+ the correct name in the current directory takes precedence over a
+ file of the correct name in the same directory as the symbol file.
+ When creating a new mapped file, it is always created in the current
+ directory. This helps to minimize the chances of a user unknowingly
+ creating big mapped files in places like /bin and /usr/local/bin, and
+ allows a local copy to override a manually installed global copy (in
+ /bin for example). */
+
+static int
+open_mapped_file (filename, mtime, mapped)
+ char *filename;
+ long mtime;
+ int mapped;
+{
+ int fd;
+ char *symsfilename;
+
+ /* First try to open an existing file in the current directory, and
+ then try the directory where the symbol file is located. */
+
+ symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL);
+ if ((fd = open_existing_mapped_file (symsfilename, mtime, mapped)) < 0)
+ {
+ free (symsfilename);
+ symsfilename = concat (filename, ".syms", (char *) NULL);
+ fd = open_existing_mapped_file (symsfilename, mtime, mapped);
+ }
+
+ /* If we don't have an open file by now, then either the file does not
+ already exist, or the base file has changed since it was created. In
+ either case, if the user has specified use of a mapped file, then
+ create a new mapped file, truncating any existing one. If we can't
+ create one, print a system error message saying why we can't.
+
+ By default the file is rw for everyone, with the user's umask taking
+ care of turning off the permissions the user wants off. */
+
+ if ((fd < 0) && mapped)
+ {
+ free (symsfilename);
+ symsfilename = concat ("./", basename (filename), ".syms",
+ (char *) NULL);
+ if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
+ {
+ if (error_pre_print)
+ {
+ printf (error_pre_print);
+ }
+ print_sys_errmsg (symsfilename, errno);
+ }
+ }
+
+ free (symsfilename);
+ return (fd);
+}
+
+/* Return the base address at which we would like the next objfile's
+ mapped data to start.
+
+ For now, we use the kludge that the configuration specifies a base
+ address to which it is safe to map the first mmalloc heap, and an
+ increment to add to this address for each successive heap. There are
+ a lot of issues to deal with here to make this work reasonably, including:
+
+ Avoid memory collisions with existing mapped address spaces
+
+ Reclaim address spaces when their mmalloc heaps are unmapped
+
+ When mmalloc heaps are shared between processes they have to be
+ mapped at the same addresses in each
+
+ Once created, a mmalloc heap that is to be mapped back in must be
+ mapped at the original address. I.E. each objfile will expect to
+ be remapped at it's original address. This becomes a problem if
+ the desired address is already in use.
+
+ etc, etc, etc.
+
+ */
+
+
+static CORE_ADDR
+map_to_address ()
+{
+
+#if defined(MMAP_BASE_ADDRESS) && defined (MMAP_INCREMENT)
+
+ static CORE_ADDR next = MMAP_BASE_ADDRESS;
+ CORE_ADDR mapto = next;
+
+ next += MMAP_INCREMENT;
+ return (mapto);
+
+#else
+
+ return (0);
+
+#endif
+
+}
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+/* Returns a section whose range includes PC or NULL if none found. */
+
+struct obj_section *
+find_pc_section(pc)
+ CORE_ADDR pc;
+{
+ struct obj_section *s;
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ for (s = objfile->sections; s < objfile->sections_end; ++s)
+ if (s->addr <= pc
+ && pc < s->endaddr)
+ return(s);
+
+ return(NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/objfiles.h b/gnu/usr.bin/gdb/gdb/objfiles.h
new file mode 100644
index 000000000000..50226ff47e77
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.h
@@ -0,0 +1,437 @@
+/* Definitions for symbol file management in GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (OBJFILES_H)
+#define OBJFILES_H
+
+/* This structure maintains information on a per-objfile basis about the
+ "entry point" of the objfile, and the scope within which the entry point
+ exists. It is possible that gdb will see more than one objfile that is
+ executable, each with it's own entry point.
+
+ For example, for dynamically linked executables in SVR4, the dynamic linker
+ code is contained within the shared C library, which is actually executable
+ and is run by the kernel first when an exec is done of a user executable
+ that is dynamically linked. The dynamic linker within the shared C library
+ then maps in the various program segments in the user executable and jumps
+ to the user executable's recorded entry point, as if the call had been made
+ directly by the kernel.
+
+ The traditional gdb method of using this info is to use the recorded entry
+ point to set the variables entry_file_lowpc and entry_file_highpc from
+ the debugging information, where these values are the starting address
+ (inclusive) and ending address (exclusive) of the instruction space in the
+ executable which correspond to the "startup file", I.E. crt0.o in most
+ cases. This file is assumed to be a startup file and frames with pc's
+ inside it are treated as nonexistent. Setting these variables is necessary
+ so that backtraces do not fly off the bottom of the stack (or top, depending
+ upon your stack orientation).
+
+ Gdb also supports an alternate method to avoid running off the top/bottom
+ of the stack.
+
+ There are two frames that are "special", the frame for the function
+ containing the process entry point, since it has no predecessor frame,
+ and the frame for the function containing the user code entry point
+ (the main() function), since all the predecessor frames are for the
+ process startup code. Since we have no guarantee that the linked
+ in startup modules have any debugging information that gdb can use,
+ we need to avoid following frame pointers back into frames that might
+ have been built in the startup code, as we might get hopelessly
+ confused. However, we almost always have debugging information
+ available for main().
+
+ These variables are used to save the range of PC values which are valid
+ within the main() function and within the function containing the process
+ entry point. If we always consider the frame for main() as the outermost
+ frame when debugging user code, and the frame for the process entry
+ point function as the outermost frame when debugging startup code, then
+ all we have to do is have FRAME_CHAIN_VALID return false whenever a
+ frame's current PC is within the range specified by these variables.
+ In essence, we set "ceilings" in the frame chain beyond which we will
+ not proceed when following the frame chain back up the stack.
+
+ A nice side effect is that we can still debug startup code without
+ running off the end of the frame chain, assuming that we have usable
+ debugging information in the startup modules, and if we choose to not
+ use the block at main, or can't find it for some reason, everything
+ still works as before. And if we have no startup code debugging
+ information but we do have usable information for main(), backtraces
+ from user code don't go wandering off into the startup code.
+
+ To use this method, define your FRAME_CHAIN_VALID macro like:
+
+ #define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 \
+ && !(inside_main_func ((thisframe)->pc)) \
+ && !(inside_entry_func ((thisframe)->pc)))
+
+ and add initializations of the four scope controlling variables inside
+ the object file / debugging information processing modules. */
+
+struct entry_info
+{
+
+ /* The value we should use for this objects entry point.
+ The illegal/unknown value needs to be something other than 0, ~0
+ for instance, which is much less likely than 0. */
+
+ CORE_ADDR entry_point;
+
+ /* Start (inclusive) and end (exclusive) of function containing the
+ entry point. */
+
+ CORE_ADDR entry_func_lowpc;
+ CORE_ADDR entry_func_highpc;
+
+ /* Start (inclusive) and end (exclusive) of object file containing the
+ entry point. */
+
+ CORE_ADDR entry_file_lowpc;
+ CORE_ADDR entry_file_highpc;
+
+ /* Start (inclusive) and end (exclusive) of the user code main() function. */
+
+ CORE_ADDR main_func_lowpc;
+ CORE_ADDR main_func_highpc;
+
+};
+
+
+/* Sections in an objfile.
+
+ It is strange that we have both this notion of "sections"
+ and the one used by section_offsets. Section as used
+ here, (currently at least) means a BFD section, and the sections
+ are set up from the BFD sections in allocate_objfile.
+
+ The sections in section_offsets have their meaning determined by
+ the symbol format, and they are set up by the sym_offsets function
+ for that symbol file format.
+
+ I'm not sure this could or should be changed, however. */
+
+struct obj_section {
+ CORE_ADDR addr; /* lowest address in section */
+ CORE_ADDR endaddr; /* 1+highest address in section */
+
+ /* This field is being used for nefarious purposes by syms_from_objfile.
+ It is said to be redundant with section_offsets; it's not really being
+ used that way, however, it's some sort of hack I don't understand
+ and am not going to try to eliminate (yet, anyway). FIXME.
+
+ It was documented as "offset between (end)addr and actual memory
+ addresses", but that's not true; addr & endaddr are actual memory
+ addresses. */
+ CORE_ADDR offset;
+
+ sec_ptr sec_ptr; /* BFD section pointer */
+
+ /* Objfile this section is part of. Not currently used, but I'm sure
+ that someone will want the bfd that the sec_ptr goes with or something
+ like that before long. */
+ struct objfile *objfile;
+};
+
+/* Master structure for keeping track of each input file from which
+ gdb reads symbols. One of these is allocated for each such file we
+ access, e.g. the exec_file, symbol_file, and any shared library object
+ files. */
+
+struct objfile
+{
+
+ /* All struct objfile's are chained together by their next pointers.
+ The global variable "object_files" points to the first link in this
+ chain.
+
+ FIXME: There is a problem here if the objfile is reusable, and if
+ multiple users are to be supported. The problem is that the objfile
+ list is linked through a member of the objfile struct itself, which
+ is only valid for one gdb process. The list implementation needs to
+ be changed to something like:
+
+ struct list {struct list *next; struct objfile *objfile};
+
+ where the list structure is completely maintained separately within
+ each gdb process. */
+
+ struct objfile *next;
+
+ /* The object file's name. Malloc'd; free it if you free this struct. */
+
+ char *name;
+
+ /* Some flag bits for this objfile. */
+
+ unsigned short flags;
+
+ /* Each objfile points to a linked list of symtabs derived from this file,
+ one symtab structure for each compilation unit (source file). Each link
+ in the symtab list contains a backpointer to this objfile. */
+
+ struct symtab *symtabs;
+
+ /* Each objfile points to a linked list of partial symtabs derived from
+ this file, one partial symtab structure for each compilation unit
+ (source file). */
+
+ struct partial_symtab *psymtabs;
+
+ /* List of freed partial symtabs, available for re-use */
+
+ struct partial_symtab *free_psymtabs;
+
+ /* The object file's BFD. Can be null, in which case bfd_open (name) and
+ put the result here. */
+
+ bfd *obfd;
+
+ /* The modification timestamp of the object file, as of the last time
+ we read its symbols. */
+
+ long mtime;
+
+ /* Obstacks to hold objects that should be freed when we load a new symbol
+ table from this object file. */
+
+ struct obstack psymbol_obstack; /* Partial symbols */
+ struct obstack symbol_obstack; /* Full symbols */
+ struct obstack type_obstack; /* Types */
+
+ /* Vectors of all partial symbols read in from file. The actual data
+ is stored in the psymbol_obstack. */
+
+ struct psymbol_allocation_list global_psymbols;
+ struct psymbol_allocation_list static_psymbols;
+
+ /* Each file contains a pointer to an array of minimal symbols for all
+ global symbols that are defined within the file. The array is terminated
+ by a "null symbol", one that has a NULL pointer for the name and a zero
+ value for the address. This makes it easy to walk through the array
+ when passed a pointer to somewhere in the middle of it. There is also
+ a count of the number of symbols, which does include the terminating
+ null symbol. The array itself, as well as all the data that it points
+ to, should be allocated on the symbol_obstack for this file. */
+
+ struct minimal_symbol *msymbols;
+ int minimal_symbol_count;
+
+ /* For object file formats which don't specify fundamental types, gdb
+ can create such types. For now, it maintains a vector of pointers
+ to these internally created fundamental types on a per objfile basis,
+ however it really should ultimately keep them on a per-compilation-unit
+ basis, to account for linkage-units that consist of a number of
+ compilation units that may have different fundamental types, such as
+ linking C modules with ADA modules, or linking C modules that are
+ compiled with 32-bit ints with C modules that are compiled with 64-bit
+ ints (not inherently evil with a smarter linker). */
+
+ struct type **fundamental_types;
+
+ /* The mmalloc() malloc-descriptor for this objfile if we are using
+ the memory mapped malloc() package to manage storage for this objfile's
+ data. NULL if we are not. */
+
+ PTR md;
+
+ /* The file descriptor that was used to obtain the mmalloc descriptor
+ for this objfile. If we call mmalloc_detach with the malloc descriptor
+ we should then close this file descriptor. */
+
+ int mmfd;
+
+ /* Structure which keeps track of functions that manipulate objfile's
+ of the same type as this objfile. I.E. the function to read partial
+ symbols for example. Note that this structure is in statically
+ allocated memory, and is shared by all objfiles that use the
+ object module reader of this type. */
+
+ struct sym_fns *sf;
+
+ /* The per-objfile information about the entry point, the scope (file/func)
+ containing the entry point, and the scope of the user's main() func. */
+
+ struct entry_info ei;
+
+ /* Information about stabs. Will be filled in with a dbx_symfile_info
+ struct by those readers that need it. */
+
+ PTR sym_stab_info;
+
+ /* Hook for information for use by the symbol reader (currently used
+ for information shared by sym_init and sym_read). It is
+ typically a pointer to malloc'd memory. The symbol reader's finish
+ function is responsible for freeing the memory thusly allocated. */
+
+ PTR sym_private;
+
+ /* Hook for target-architecture-specific information. This must
+ point to memory allocated on one of the obstacks in this objfile,
+ so that it gets freed automatically when reading a new object
+ file. */
+
+ PTR obj_private;
+
+ /* Set of relocation offsets to apply to each section.
+ Currently on the psymbol_obstack (which makes no sense, but I'm
+ not sure it's harming anything).
+
+ These offsets indicate that all symbols (including partial and
+ minimal symbols) which have been read have been relocated by this
+ much. Symbols which are yet to be read need to be relocated by
+ it. */
+
+ struct section_offsets *section_offsets;
+ int num_sections;
+
+ /* set of section begin and end addresses used to map pc addresses
+ into sections. Currently on the psymbol_obstack (which makes no
+ sense, but I'm not sure it's harming anything). */
+
+ struct obj_section
+ *sections,
+ *sections_end;
+};
+
+/* Defines for the objfile flag word. */
+
+/* Gdb can arrange to allocate storage for all objects related to a
+ particular objfile in a designated section of it's address space,
+ managed at a low level by mmap() and using a special version of
+ malloc that handles malloc/free/realloc on top of the mmap() interface.
+ This allows the "internal gdb state" for a particular objfile to be
+ dumped to a gdb state file and subsequently reloaded at a later time. */
+
+#define OBJF_MAPPED (1 << 0) /* Objfile data is mmap'd */
+
+/* When using mapped/remapped predigested gdb symbol information, we need
+ a flag that indicates that we have previously done an initial symbol
+ table read from this particular objfile. We can't just look for the
+ absence of any of the three symbol tables (msymbols, psymtab, symtab)
+ because if the file has no symbols for example, none of these will
+ exist. */
+
+#define OBJF_SYMS (1 << 1) /* Have tried to read symbols */
+
+/* The object file that the main symbol table was loaded from (e.g. the
+ argument to the "symbol-file" or "file" command). */
+
+extern struct objfile *symfile_objfile;
+
+/* When we need to allocate a new type, we need to know which type_obstack
+ to allocate the type on, since there is one for each objfile. The places
+ where types are allocated are deeply buried in function call hierarchies
+ which know nothing about objfiles, so rather than trying to pass a
+ particular objfile down to them, we just do an end run around them and
+ set current_objfile to be whatever objfile we expect to be using at the
+ time types are being allocated. For instance, when we start reading
+ symbols for a particular objfile, we set current_objfile to point to that
+ objfile, and when we are done, we set it back to NULL, to ensure that we
+ never put a type someplace other than where we are expecting to put it.
+ FIXME: Maybe we should review the entire type handling system and
+ see if there is a better way to avoid this problem. */
+
+extern struct objfile *current_objfile;
+
+/* All known objfiles are kept in a linked list. This points to the
+ root of this list. */
+
+extern struct objfile *object_files;
+
+/* Declarations for functions defined in objfiles.c */
+
+extern struct objfile *
+allocate_objfile PARAMS ((bfd *, int));
+
+extern void
+unlink_objfile PARAMS ((struct objfile *));
+
+extern void
+free_objfile PARAMS ((struct objfile *));
+
+extern void
+free_all_objfiles PARAMS ((void));
+
+extern void
+objfile_relocate PARAMS ((struct objfile *, struct section_offsets *));
+
+extern int
+have_partial_symbols PARAMS ((void));
+
+extern int
+have_full_symbols PARAMS ((void));
+
+/* Functions for dealing with the minimal symbol table, really a misc
+ address<->symbol mapping for things we don't have debug symbols for. */
+
+extern int
+have_minimal_symbols PARAMS ((void));
+
+extern struct obj_section *
+find_pc_section PARAMS((CORE_ADDR pc));
+
+/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete
+ the objfile during the traversal. */
+
+#define ALL_OBJFILES(obj) \
+ for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next)
+
+#define ALL_OBJFILES_SAFE(obj,nxt) \
+ for ((obj) = object_files; \
+ (obj) != NULL? ((nxt)=(obj)->next,1) :0; \
+ (obj) = (nxt))
+
+
+/* Traverse all symtabs in one objfile. */
+
+#define ALL_OBJFILE_SYMTABS(objfile, s) \
+ for ((s) = (objfile) -> symtabs; (s) != NULL; (s) = (s) -> next)
+
+/* Traverse all psymtabs in one objfile. */
+
+#define ALL_OBJFILE_PSYMTABS(objfile, p) \
+ for ((p) = (objfile) -> psymtabs; (p) != NULL; (p) = (p) -> next)
+
+/* Traverse all minimal symbols in one objfile. */
+
+#define ALL_OBJFILE_MSYMBOLS(objfile, m) \
+ for ((m) = (objfile) -> msymbols; SYMBOL_NAME(m) != NULL; (m)++)
+
+
+/* Traverse all symtabs in all objfiles. */
+
+#define ALL_SYMTABS(objfile, s) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s)
+
+/* Traverse all psymtabs in all objfiles. */
+
+#define ALL_PSYMTABS(objfile, p) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+
+/* Traverse all minimal symbols in all objfiles. */
+
+#define ALL_MSYMBOLS(objfile, m) \
+ ALL_OBJFILES (objfile) \
+ if ((objfile)->msymbols) \
+ ALL_OBJFILE_MSYMBOLS (objfile, m)
+
+#endif /* !defined (OBJFILES_H) */
diff --git a/gnu/usr.bin/gdb/gdb/obstack.h b/gnu/usr.bin/gdb/gdb/obstack.h
new file mode 100644
index 000000000000..689f14855fed
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/obstack.h
@@ -0,0 +1,490 @@
+/* obstack.h - object stack macros
+ Copyright (C) 1988, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' an obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef __OBSTACKS__
+#define __OBSTACKS__
+
+/* We use subtraction of (char *)0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+#define __PTR_TO_INT(P) ((P) - (char *)0)
+#endif
+
+#ifndef __INT_TO_PTR
+#define __INT_TO_PTR(P) ((P) + (char *)0)
+#endif
+
+/* We need the type of the resulting object. In ANSI C it is ptrdiff_t
+ but in traditional C it is usually long. If we are in ANSI C and
+ don't already have ptrdiff_t get it. */
+
+#if defined (__STDC__) && ! defined (offsetof)
+#if defined (__GNUC__) && defined (IN_GCC)
+/* On Next machine, the system's stddef.h screws up if included
+ after we have defined just ptrdiff_t, so include all of gstddef.h.
+ Otherwise, define just ptrdiff_t, which is all we need. */
+#ifndef __NeXT__
+#define __need_ptrdiff_t
+#endif
+
+/* While building GCC, the stddef.h that goes with GCC has this name. */
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+#endif
+
+#ifdef __STDC__
+#define PTR_INT_TYPE ptrdiff_t
+#else
+#define PTR_INT_TYPE long
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ PTR_INT_TYPE temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+ unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
+ unsigned maybe_empty_object:1;/* There is a possibility that the current
+ chunk contains a zero-length object. This
+ prevents freeing the chunk if we allocate
+ a bigger chunk to replace it. */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#ifdef __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern void _obstack_begin (struct obstack *, int, int,
+ void *(*) (), void (*) ());
+extern void _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (), void (*) (), void *);
+#else
+extern void _obstack_newchunk ();
+extern void _obstack_free ();
+extern void _obstack_begin ();
+extern void _obstack_begin_1 ();
+#endif
+
+#ifdef __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+#define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
+
+#define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun))
+
+#define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)()) (newfreefun))
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#if defined (__GNUC__) && defined (__STDC__)
+#if __GNUC__ < 2
+#define __extension__
+#endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+#define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+#define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ bcopy (where, __o->next_free, __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \
+ bcopy (where, __o->next_free, __len), \
+ __o->next_free += __len, \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, 1), 0) : 0), \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+#define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0), \
+ *((void **)__o->next_free)++ = ((void *)datum); \
+ (void) 0; })
+
+#define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (int) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0), \
+ *((int *)__o->next_free)++ = ((int)datum); \
+ (void) 0; })
+
+#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->chunk_limit - __o->next_free < __len) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+#define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ ((__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ ? (__o1->next_free = __o1->chunk_limit) : 0); \
+ __o1->object_base = __o1->next_free; \
+ value; })
+
+#define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+#define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+#define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+#define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)
+
+#define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ *((h)->next_free)++ = (datum))
+
+#define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum))
+
+#define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ *((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum))
+
+#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+#define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *)(h)->chunk \
+ > (h)->chunk_limit - (char *)(h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp))
+
+#ifdef __STDC__
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+#else
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACKS__ */
diff --git a/gnu/usr.bin/gdb/gdb/parse.c b/gnu/usr.bin/gdb/gdb/parse.c
new file mode 100644
index 000000000000..08f2b7e67484
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parse.c
@@ -0,0 +1,827 @@
+/* Parse expressions for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Modified from expread.y by the Department of Computer Science at the
+ State University of New York at Buffalo, 1991.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse an expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "language.h"
+#include "parser-defs.h"
+
+static void
+free_funcalls PARAMS ((void));
+
+static void
+prefixify_expression PARAMS ((struct expression *));
+
+static int
+length_of_subexp PARAMS ((struct expression *, int));
+
+static void
+prefixify_subexp PARAMS ((struct expression *, struct expression *, int, int));
+
+/* Data structure for saving values of arglist_len for function calls whose
+ arguments contain other function calls. */
+
+struct funcall
+ {
+ struct funcall *next;
+ int arglist_len;
+ };
+
+static struct funcall *funcall_chain;
+
+/* Assign machine-independent names to certain registers
+ (unless overridden by the REGISTER_NAMES table) */
+
+#ifdef NO_STD_REGS
+unsigned num_std_regs = 0;
+struct std_regs std_regs[1];
+#else
+struct std_regs std_regs[] = {
+
+#ifdef PC_REGNUM
+ { "pc", PC_REGNUM },
+#endif
+#ifdef FP_REGNUM
+ { "fp", FP_REGNUM },
+#endif
+#ifdef SP_REGNUM
+ { "sp", SP_REGNUM },
+#endif
+#ifdef PS_REGNUM
+ { "ps", PS_REGNUM },
+#endif
+
+};
+
+unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]);
+
+#endif
+
+
+/* Begin counting arguments for a function call,
+ saving the data about any containing call. */
+
+void
+start_arglist ()
+{
+ register struct funcall *new;
+
+ new = (struct funcall *) xmalloc (sizeof (struct funcall));
+ new->next = funcall_chain;
+ new->arglist_len = arglist_len;
+ arglist_len = 0;
+ funcall_chain = new;
+}
+
+/* Return the number of arguments in a function call just terminated,
+ and restore the data for the containing function call. */
+
+int
+end_arglist ()
+{
+ register int val = arglist_len;
+ register struct funcall *call = funcall_chain;
+ funcall_chain = call->next;
+ arglist_len = call->arglist_len;
+ free ((PTR)call);
+ return val;
+}
+
+/* Free everything in the funcall chain.
+ Used when there is an error inside parsing. */
+
+static void
+free_funcalls ()
+{
+ register struct funcall *call, *next;
+
+ for (call = funcall_chain; call; call = next)
+ {
+ next = call->next;
+ free ((PTR)call);
+ }
+}
+
+/* This page contains the functions for adding data to the struct expression
+ being constructed. */
+
+/* Add one element to the end of the expression. */
+
+/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
+ a register through here */
+
+void
+write_exp_elt (expelt)
+ union exp_element expelt;
+{
+ if (expout_ptr >= expout_size)
+ {
+ expout_size *= 2;
+ expout = (struct expression *)
+ xrealloc ((char *) expout, sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size));
+ }
+ expout->elts[expout_ptr++] = expelt;
+}
+
+void
+write_exp_elt_opcode (expelt)
+ enum exp_opcode expelt;
+{
+ union exp_element tmp;
+
+ tmp.opcode = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_sym (expelt)
+ struct symbol *expelt;
+{
+ union exp_element tmp;
+
+ tmp.symbol = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_block (b)
+ struct block *b;
+{
+ union exp_element tmp;
+ tmp.block = b;
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_longcst (expelt)
+ LONGEST expelt;
+{
+ union exp_element tmp;
+
+ tmp.longconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_dblcst (expelt)
+ double expelt;
+{
+ union exp_element tmp;
+
+ tmp.doubleconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_type (expelt)
+ struct type *expelt;
+{
+ union exp_element tmp;
+
+ tmp.type = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_intern (expelt)
+ struct internalvar *expelt;
+{
+ union exp_element tmp;
+
+ tmp.internalvar = expelt;
+
+ write_exp_elt (tmp);
+}
+
+/* Add a string constant to the end of the expression.
+
+ String constants are stored by first writing an expression element
+ that contains the length of the string, then stuffing the string
+ constant itself into however many expression elements are needed
+ to hold it, and then writing another expression element that contains
+ the length of the string. I.E. an expression element at each end of
+ the string records the string length, so you can skip over the
+ expression elements containing the actual string bytes from either
+ end of the string. Note that this also allows gdb to handle
+ strings with embedded null bytes, as is required for some languages.
+
+ Don't be fooled by the fact that the string is null byte terminated,
+ this is strictly for the convenience of debugging gdb itself. Gdb
+ Gdb does not depend up the string being null terminated, since the
+ actual length is recorded in expression elements at each end of the
+ string. The null byte is taken into consideration when computing how
+ many expression elements are required to hold the string constant, of
+ course. */
+
+
+void
+write_exp_string (str)
+ struct stoken str;
+{
+ register int len = str.length;
+ register int lenelt;
+ register char *strdata;
+
+ /* Compute the number of expression elements required to hold the string
+ (including a null byte terminator), along with one expression element
+ at each end to record the actual string length (not including the
+ null byte terminator). */
+
+ lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1);
+
+ /* Ensure that we have enough available expression elements to store
+ everything. */
+
+ if ((expout_ptr + lenelt) >= expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
+ expout = (struct expression *)
+ xrealloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ /* Write the leading length expression element (which advances the current
+ expression element index), then write the string constant followed by a
+ terminating null byte, and then write the trailing length expression
+ element. */
+
+ write_exp_elt_longcst ((LONGEST) len);
+ strdata = (char *) &expout->elts[expout_ptr];
+ memcpy (strdata, str.ptr, len);
+ *(strdata + len) = '\0';
+ expout_ptr += lenelt - 2;
+ write_exp_elt_longcst ((LONGEST) len);
+}
+
+/* Add a bitstring constant to the end of the expression.
+
+ Bitstring constants are stored by first writing an expression element
+ that contains the length of the bitstring (in bits), then stuffing the
+ bitstring constant itself into however many expression elements are
+ needed to hold it, and then writing another expression element that
+ contains the length of the bitstring. I.E. an expression element at
+ each end of the bitstring records the bitstring length, so you can skip
+ over the expression elements containing the actual bitstring bytes from
+ either end of the bitstring. */
+
+void
+write_exp_bitstring (str)
+ struct stoken str;
+{
+ register int bits = str.length; /* length in bits */
+ register int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ register int lenelt;
+ register char *strdata;
+
+ /* Compute the number of expression elements required to hold the bitstring,
+ along with one expression element at each end to record the actual
+ bitstring length in bits. */
+
+ lenelt = 2 + BYTES_TO_EXP_ELEM (len);
+
+ /* Ensure that we have enough available expression elements to store
+ everything. */
+
+ if ((expout_ptr + lenelt) >= expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
+ expout = (struct expression *)
+ xrealloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ /* Write the leading length expression element (which advances the current
+ expression element index), then write the bitstring constant, and then
+ write the trailing length expression element. */
+
+ write_exp_elt_longcst ((LONGEST) bits);
+ strdata = (char *) &expout->elts[expout_ptr];
+ memcpy (strdata, str.ptr, len);
+ expout_ptr += lenelt - 2;
+ write_exp_elt_longcst ((LONGEST) bits);
+}
+
+/* Return a null-terminated temporary copy of the name
+ of a string token. */
+
+char *
+copy_name (token)
+ struct stoken token;
+{
+ memcpy (namecopy, token.ptr, token.length);
+ namecopy[token.length] = 0;
+ return namecopy;
+}
+
+/* Reverse an expression from suffix form (in which it is constructed)
+ to prefix form (in which we can conveniently print or execute it). */
+
+static void
+prefixify_expression (expr)
+ register struct expression *expr;
+{
+ register int len =
+ sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
+ register struct expression *temp;
+ register int inpos = expr->nelts, outpos = 0;
+
+ temp = (struct expression *) alloca (len);
+
+ /* Copy the original expression into temp. */
+ memcpy (temp, expr, len);
+
+ prefixify_subexp (temp, expr, inpos, outpos);
+}
+
+/* Return the number of exp_elements in the subexpression of EXPR
+ whose last exp_element is at index ENDPOS - 1 in EXPR. */
+
+static int
+length_of_subexp (expr, endpos)
+ register struct expression *expr;
+ register int endpos;
+{
+ register int oplen = 1;
+ register int args = 0;
+ register int i;
+
+ if (endpos < 1)
+ error ("?error in length_of_subexp");
+
+ i = (int) expr->elts[endpos - 1].opcode;
+
+ switch (i)
+ {
+ /* C++ */
+ case OP_SCOPE:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_VAR_VALUE:
+ oplen = 4;
+ break;
+
+ case OP_TYPE:
+ case OP_BOOL:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
+ break;
+
+ case UNOP_MAX:
+ case UNOP_MIN:
+ oplen = 3;
+ break;
+
+ case BINOP_VAL:
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case UNOP_ABS:
+ case UNOP_CAP:
+ case UNOP_CHR:
+ case UNOP_FLOAT:
+ case UNOP_HIGH:
+ case UNOP_ODD:
+ case UNOP_ORD:
+ case UNOP_TRUNC:
+ oplen = 1;
+ args = 1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ /* fall through */
+ case OP_M2_STRING:
+ case OP_STRING:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_BITSTRING:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen);
+ break;
+
+ case OP_ARRAY:
+ oplen = 4;
+ args = longest_to_int (expr->elts[endpos - 2].longconst);
+ args -= longest_to_int (expr->elts[endpos - 3].longconst);
+ args += 1;
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ break;
+
+ /* Modula-2 */
+ case MULTI_SUBSCRIPT:
+ oplen=3;
+ args = 1 + longest_to_int (expr->elts[endpos- 2].longconst);
+ break;
+
+ case BINOP_ASSIGN_MODIFY:
+ oplen = 3;
+ args = 2;
+ break;
+
+ /* C++ */
+ case OP_THIS:
+ oplen = 2;
+ break;
+
+ default:
+ args = 1 + (i < (int) BINOP_END);
+ }
+
+ while (args > 0)
+ {
+ oplen += length_of_subexp (expr, endpos - oplen);
+ args--;
+ }
+
+ return oplen;
+}
+
+/* Copy the subexpression ending just before index INEND in INEXPR
+ into OUTEXPR, starting at index OUTBEG.
+ In the process, convert it from suffix to prefix form. */
+
+static void
+prefixify_subexp (inexpr, outexpr, inend, outbeg)
+ register struct expression *inexpr;
+ struct expression *outexpr;
+ register int inend;
+ int outbeg;
+{
+ register int oplen = 1;
+ register int args = 0;
+ register int i;
+ int *arglens;
+ enum exp_opcode opcode;
+
+ /* Compute how long the last operation is (in OPLEN),
+ and also how many preceding subexpressions serve as
+ arguments for it (in ARGS). */
+
+ opcode = inexpr->elts[inend - 1].opcode;
+ switch (opcode)
+ {
+ /* C++ */
+ case OP_SCOPE:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_VAR_VALUE:
+ oplen = 4;
+ break;
+
+ case OP_TYPE:
+ case OP_BOOL:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
+ break;
+
+ case UNOP_MIN:
+ case UNOP_MAX:
+ oplen = 3;
+ break;
+
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case UNOP_ABS:
+ case UNOP_CAP:
+ case UNOP_CHR:
+ case UNOP_FLOAT:
+ case UNOP_HIGH:
+ case UNOP_ODD:
+ case UNOP_ORD:
+ case UNOP_TRUNC:
+ oplen=1;
+ args=1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ /* fall through */
+ case OP_M2_STRING:
+ case OP_STRING:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_BITSTRING:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen);
+ break;
+
+ case OP_ARRAY:
+ oplen = 4;
+ args = longest_to_int (inexpr->elts[inend - 2].longconst);
+ args -= longest_to_int (inexpr->elts[inend - 3].longconst);
+ args += 1;
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ break;
+
+ case BINOP_ASSIGN_MODIFY:
+ oplen = 3;
+ args = 2;
+ break;
+
+ /* Modula-2 */
+ case MULTI_SUBSCRIPT:
+ oplen=3;
+ args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
+ break;
+
+ /* C++ */
+ case OP_THIS:
+ oplen = 2;
+ break;
+
+ default:
+ args = 1 + ((int) opcode < (int) BINOP_END);
+ }
+
+ /* Copy the final operator itself, from the end of the input
+ to the beginning of the output. */
+ inend -= oplen;
+ memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend],
+ EXP_ELEM_TO_BYTES (oplen));
+ outbeg += oplen;
+
+ /* Find the lengths of the arg subexpressions. */
+ arglens = (int *) alloca (args * sizeof (int));
+ for (i = args - 1; i >= 0; i--)
+ {
+ oplen = length_of_subexp (inexpr, inend);
+ arglens[i] = oplen;
+ inend -= oplen;
+ }
+
+ /* Now copy each subexpression, preserving the order of
+ the subexpressions, but prefixifying each one.
+ In this loop, inend starts at the beginning of
+ the expression this level is working on
+ and marches forward over the arguments.
+ outbeg does similarly in the output. */
+ for (i = 0; i < args; i++)
+ {
+ oplen = arglens[i];
+ inend += oplen;
+ prefixify_subexp (inexpr, outexpr, inend, outbeg);
+ outbeg += oplen;
+ }
+}
+
+/* This page contains the two entry points to this file. */
+
+/* Read an expression from the string *STRINGPTR points to,
+ parse it, and return a pointer to a struct expression that we malloc.
+ Use block BLOCK as the lexical context for variable names;
+ if BLOCK is zero, use the block of the selected stack frame.
+ Meanwhile, advance *STRINGPTR to point after the expression,
+ at the first nonwhite character that is not part of the expression
+ (possibly a null character).
+
+ If COMMA is nonzero, stop if a comma is reached. */
+
+struct expression *
+parse_exp_1 (stringptr, block, comma)
+ char **stringptr;
+ struct block *block;
+ int comma;
+{
+ struct cleanup *old_chain;
+
+ lexptr = *stringptr;
+
+ paren_depth = 0;
+ type_stack_depth = 0;
+
+ comma_terminates = comma;
+
+ if (lexptr == 0 || *lexptr == 0)
+ error_no_arg ("expression to compute");
+
+ old_chain = make_cleanup (free_funcalls, 0);
+ funcall_chain = 0;
+
+ expression_context_block = block ? block : get_selected_block ();
+
+ namecopy = (char *) alloca (strlen (lexptr) + 1);
+ expout_size = 10;
+ expout_ptr = 0;
+ expout = (struct expression *)
+ xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size));
+ expout->language_defn = current_language;
+ make_cleanup (free_current_contents, &expout);
+
+ if (current_language->la_parser ())
+ current_language->la_error (NULL);
+
+ discard_cleanups (old_chain);
+
+ /* Record the actual number of expression elements, and then
+ reallocate the expression memory so that we free up any
+ excess elements. */
+
+ expout->nelts = expout_ptr;
+ expout = (struct expression *)
+ xrealloc ((char *) expout,
+ sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_ptr));;
+
+ /* Convert expression from postfix form as generated by yacc
+ parser, to a prefix form. */
+
+ DUMP_EXPRESSION (expout, stdout, "before conversion to prefix form");
+ prefixify_expression (expout);
+ DUMP_EXPRESSION (expout, stdout, "after conversion to prefix form");
+
+ *stringptr = lexptr;
+ return expout;
+}
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+
+struct expression *
+parse_expression (string)
+ char *string;
+{
+ register struct expression *exp;
+ exp = parse_exp_1 (&string, 0, 0);
+ if (*string)
+ error ("Junk after end of expression.");
+ return exp;
+}
+
+/* Stuff for maintaining a stack of types. Currently just used by C, but
+ probably useful for any language which declares its types "backwards". */
+
+void
+push_type (tp)
+ enum type_pieces tp;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (union type_stack_elt *)
+ xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack));
+ }
+ type_stack[type_stack_depth++].piece = tp;
+}
+
+void
+push_type_int (n)
+ int n;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (union type_stack_elt *)
+ xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack));
+ }
+ type_stack[type_stack_depth++].int_val = n;
+}
+
+enum type_pieces
+pop_type ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth].piece;
+ return tp_end;
+}
+
+int
+pop_type_int ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth].int_val;
+ /* "Can't happen". */
+ return 0;
+}
+
+/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
+ as modified by all the stuff on the stack. */
+struct type *
+follow_types (follow_type)
+ struct type *follow_type;
+{
+ int done = 0;
+ int array_size;
+ struct type *range_type;
+
+ while (!done)
+ switch (pop_type ())
+ {
+ case tp_end:
+ done = 1;
+ break;
+ case tp_pointer:
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_reference:
+ follow_type = lookup_reference_type (follow_type);
+ break;
+ case tp_array:
+ array_size = pop_type_int ();
+ if (array_size != -1)
+ {
+ range_type =
+ create_range_type ((struct type *) NULL,
+ builtin_type_int, 0,
+ array_size - 1);
+ follow_type =
+ create_array_type ((struct type *) NULL,
+ follow_type, range_type);
+ }
+ else
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_function:
+ follow_type = lookup_function_type (follow_type);
+ break;
+ }
+ return follow_type;
+}
+
+void
+_initialize_parse ()
+{
+ type_stack_size = 80;
+ type_stack_depth = 0;
+ type_stack = (union type_stack_elt *)
+ xmalloc (type_stack_size * sizeof (*type_stack));
+}
diff --git a/gnu/usr.bin/gdb/gdb/parser-defs.h b/gnu/usr.bin/gdb/gdb/parser-defs.h
new file mode 100644
index 000000000000..5c8710e4e6e2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parser-defs.h
@@ -0,0 +1,188 @@
+/* Parser definitions for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Modified from expread.y by the Department of Computer Science at the
+ State University of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (PARSER_DEFS_H)
+#define PARSER_DEFS_H 1
+
+struct std_regs {
+ char *name;
+ int regnum;
+};
+
+extern struct std_regs std_regs[];
+extern unsigned num_std_regs;
+
+struct expression *expout;
+int expout_size;
+int expout_ptr;
+
+/* If this is nonzero, this block is used as the lexical context
+ for symbol names. */
+
+struct block *expression_context_block;
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. */
+struct block *innermost_block;
+
+/* The block in which the most recently discovered symbol was found. */
+struct block *block_found;
+
+/* Number of arguments seen so far in innermost function call. */
+int arglist_len;
+
+/* A string token, either a char-string or bit-string. Char-strings are
+ used, for example, for the names of symbols. */
+
+struct stoken
+ {
+ /* Pointer to first byte of char-string or first bit of bit-string */
+ char *ptr;
+ /* Length of string in bytes for char-string or bits for bit-string */
+ int length;
+ };
+
+struct ttype
+ {
+ struct stoken stoken;
+ struct type *type;
+ };
+
+struct symtoken
+ {
+ struct stoken stoken;
+ struct symbol *sym;
+ int is_a_field_of_this;
+ };
+
+/* For parsing of complicated types.
+ An array should be preceded in the list by the size of the array. */
+enum type_pieces
+ {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function};
+/* The stack can contain either an enum type_pieces or an int. */
+union type_stack_elt {
+ enum type_pieces piece;
+ int int_val;
+};
+union type_stack_elt *type_stack;
+int type_stack_depth, type_stack_size;
+
+extern void
+write_exp_elt PARAMS ((union exp_element));
+
+extern void
+write_exp_elt_opcode PARAMS ((enum exp_opcode));
+
+extern void
+write_exp_elt_sym PARAMS ((struct symbol *));
+
+extern void
+write_exp_elt_longcst PARAMS ((LONGEST));
+
+extern void
+write_exp_elt_dblcst PARAMS ((double));
+
+extern void
+write_exp_elt_type PARAMS ((struct type *));
+
+extern void
+write_exp_elt_intern PARAMS ((struct internalvar *));
+
+extern void
+write_exp_string PARAMS ((struct stoken));
+
+extern void
+write_exp_bitstring PARAMS ((struct stoken));
+
+extern void
+start_arglist PARAMS ((void));
+
+extern int
+end_arglist PARAMS ((void));
+
+extern char *
+copy_name PARAMS ((struct stoken));
+
+extern void
+push_type PARAMS ((enum type_pieces));
+
+extern void
+push_type_int PARAMS ((int));
+
+extern enum type_pieces
+pop_type PARAMS ((void));
+
+extern int
+pop_type_int PARAMS ((void));
+
+extern struct type *follow_types PARAMS ((struct type *));
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+char *lexptr;
+
+/* Tokens that refer to names do so with explicit pointer and length,
+ so they can share the storage that lexptr is parsing.
+
+ When it is necessary to pass a name to a function that expects
+ a null-terminated string, the substring is copied out
+ into a block of storage that namecopy points to.
+
+ namecopy is allocated once, guaranteed big enough, for each parsing. */
+
+char *namecopy;
+
+/* Current depth in parentheses within the expression. */
+
+int paren_depth;
+
+/* Nonzero means stop parsing on first comma (if not within parentheses). */
+
+int comma_terminates;
+
+/* These codes indicate operator precedences for expression printing,
+ least tightly binding first. */
+/* Adding 1 to a precedence value is done for binary operators,
+ on the operand which is more tightly bound, so that operators
+ of equal precedence within that operand will get parentheses. */
+/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
+ they are used as the "surrounding precedence" to force
+ various kinds of things to be parenthesized. */
+enum precedence
+{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR,
+ PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR,
+ PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
+ PREC_HYPER, PREC_PREFIX, PREC_SUFFIX };
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+struct op_print
+{
+ char *string;
+ enum exp_opcode opcode;
+ /* Precedence of operator. These values are used only by comparisons. */
+ enum precedence precedence;
+ int right_assoc;
+};
+
+#endif /* PARSER_DEFS_H */
diff --git a/gnu/usr.bin/gdb/gdb/partial-stab.h b/gnu/usr.bin/gdb/gdb/partial-stab.h
new file mode 100644
index 000000000000..3be0be618873
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/partial-stab.h
@@ -0,0 +1,618 @@
+/* Shared code to pre-read a stab (dbx-style), when building a psymtab.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The following need to be defined:
+ SET_NAMESTRING() --Set namestring to name of symbol.
+ CUR_SYMBOL_TYPE --Type code of current symbol.
+ CUR_SYMBOL_VALUE --Value field of current symbol. May be adjusted here.
+ */
+
+/* End of macro definitions, now let's handle them symbols! */
+
+ switch (CUR_SYMBOL_TYPE)
+ {
+ char *p;
+ /*
+ * Standard, external, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ case N_NBTEXT | N_EXT:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto record_it;
+
+ case N_DATA | N_EXT:
+ case N_NBDATA | N_EXT:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto record_it;
+
+ case N_BSS:
+ case N_BSS | N_EXT:
+ case N_NBBSS | N_EXT:
+ case N_SETV | N_EXT: /* FIXME, is this in BSS? */
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ goto record_it;
+
+ case N_ABS | N_EXT:
+ record_it:
+#ifdef DBXREAD_ONLY
+ SET_NAMESTRING();
+
+ bss_ext_symbol:
+ record_minimal_symbol (namestring, CUR_SYMBOL_VALUE,
+ CUR_SYMBOL_TYPE, objfile); /* Always */
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ /* Standard, local, non-debugger, symbols */
+
+ case N_NBTEXT:
+
+ /* We need to be able to deal with both N_FN or N_TEXT,
+ because we have no way of knowing whether the sys-supplied ld
+ or GNU ld was used to make the executable. Sequents throw
+ in another wrinkle -- they renumbered N_FN. */
+
+ case N_FN:
+ case N_FN_SEQ:
+ case N_TEXT:
+#ifdef DBXREAD_ONLY
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ SET_NAMESTRING();
+ if ((namestring[0] == '-' && namestring[1] == 'l')
+ || (namestring [(nsl = strlen (namestring)) - 1] == 'o'
+ && namestring [nsl - 2] == '.')
+#ifdef GDB_TARGET_IS_HPPA
+ /* some cooperation from gcc to get around ld stupidity */
+ || (namestring[0] == 'e' && STREQ (namestring, "end_file."))
+#endif
+ )
+ {
+#ifndef GDB_TARGET_IS_HPPA
+ if (objfile -> ei.entry_point < CUR_SYMBOL_VALUE &&
+ objfile -> ei.entry_point >= last_o_file_start)
+ {
+ objfile -> ei.entry_file_lowpc = last_o_file_start;
+ objfile -> ei.entry_file_highpc = CUR_SYMBOL_VALUE;
+ }
+#endif
+ if (past_first_source_file && pst
+ /* The gould NP1 uses low values for .o and -l symbols
+ which are not the address. */
+ && CUR_SYMBOL_VALUE >= pst->textlow)
+ {
+ END_PSYMTAB (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size, CUR_SYMBOL_VALUE,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ last_o_file_start = CUR_SYMBOL_VALUE;
+ }
+ else
+ goto record_it;
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ case N_DATA:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto record_it;
+
+ case N_UNDF | N_EXT:
+#ifdef DBXREAD_ONLY
+ if (CUR_SYMBOL_VALUE != 0) {
+ /* This is a "Fortran COMMON" symbol. See if the target
+ environment knows where it has been relocated to. */
+
+ CORE_ADDR reladdr;
+
+ SET_NAMESTRING();
+ if (target_lookup_symbol (namestring, &reladdr)) {
+ continue; /* Error in lookup; ignore symbol for now. */
+ }
+ CUR_SYMBOL_TYPE ^= (N_BSS^N_UNDF); /* Define it as a bss-symbol */
+ CUR_SYMBOL_VALUE = reladdr;
+ goto bss_ext_symbol;
+ }
+#endif /* DBXREAD_ONLY */
+ continue; /* Just undefined, not COMMON */
+
+ case N_UNDF:
+#ifdef DBXREAD_ONLY
+ if (processing_acc_compilation && bufp->n_strx == 1) {
+ /* Deal with relative offsets in the string table
+ used in ELF+STAB under Solaris. If we want to use the
+ n_strx field, which contains the name of the file,
+ we must adjust file_string_table_offset *before* calling
+ SET_NAMESTRING(). */
+ past_first_source_file = 1;
+ file_string_table_offset = next_file_string_table_offset;
+ next_file_string_table_offset =
+ file_string_table_offset + bufp->n_value;
+ if (next_file_string_table_offset < file_string_table_offset)
+ error ("string table offset backs up at %d", symnum);
+ /* FIXME -- replace error() with complaint. */
+ continue;
+ }
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ /* Lots of symbol types we can just ignore. */
+
+ case N_ABS:
+ case N_NBDATA:
+ case N_NBBSS:
+ continue;
+
+ /* Keep going . . .*/
+
+ /*
+ * Special symbol types for GNU
+ */
+ case N_INDR:
+ case N_INDR | N_EXT:
+ case N_SETA:
+ case N_SETA | N_EXT:
+ case N_SETT:
+ case N_SETT | N_EXT:
+ case N_SETD:
+ case N_SETD | N_EXT:
+ case N_SETB:
+ case N_SETB | N_EXT:
+ case N_SETV:
+ continue;
+
+ /*
+ * Debugger symbols
+ */
+
+ case N_SO: {
+ unsigned long valu;
+ static int prev_so_symnum = -10;
+ static int first_so_symnum;
+ char *p;
+
+ valu = CUR_SYMBOL_VALUE + ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ past_first_source_file = 1;
+
+ if (prev_so_symnum != symnum - 1)
+ { /* Here if prev stab wasn't N_SO */
+ first_so_symnum = symnum;
+
+ if (pst)
+ {
+ END_PSYMTAB (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size, valu,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ }
+
+ prev_so_symnum = symnum;
+
+ /* End the current partial symtab and start a new one */
+
+ SET_NAMESTRING();
+
+ /* Some compilers (including gcc) emit a pair of initial N_SOs.
+ The first one is a directory name; the second the file name.
+ If pst exists, is empty, and has a filename ending in '/',
+ we assume the previous N_SO was a directory name. */
+
+ p = strrchr (namestring, '/');
+ if (p && *(p+1) == '\000')
+ continue; /* Simply ignore directory name SOs */
+
+ /* Some other compilers (C++ ones in particular) emit useless
+ SOs for non-existant .c files. We ignore all subsequent SOs that
+ immediately follow the first. */
+
+ if (!pst)
+ pst = START_PSYMTAB (objfile, section_offsets,
+ namestring, valu,
+ first_so_symnum * symbol_size,
+ objfile -> global_psymbols.next,
+ objfile -> static_psymbols.next);
+ continue;
+ }
+
+ case N_BINCL:
+#ifdef DBXREAD_ONLY
+ /* Add this bincl to the bincl_list for future EXCLs. No
+ need to save the string; it'll be around until
+ read_dbx_symtab function returns */
+
+ SET_NAMESTRING();
+
+ add_bincl_to_list (pst, namestring, CUR_SYMBOL_VALUE);
+
+ /* Mark down an include file in the current psymtab */
+
+ goto record_include_file;
+
+#else /* DBXREAD_ONLY */
+ continue;
+#endif
+
+ case N_SOL:
+ /* Mark down an include file in the current psymtab */
+
+ SET_NAMESTRING();
+
+ /* In C++, one may expect the same filename to come round many
+ times, when code is coming alternately from the main file
+ and from inline functions in other files. So I check to see
+ if this is a file we've seen before -- either the main
+ source file, or a previously included file.
+
+ This seems to be a lot of time to be spending on N_SOL, but
+ things like "break c-exp.y:435" need to work (I
+ suppose the psymtab_include_list could be hashed or put
+ in a binary tree, if profiling shows this is a major hog). */
+ if (pst && STREQ (namestring, pst->filename))
+ continue;
+ {
+ register int i;
+ for (i = 0; i < includes_used; i++)
+ if (STREQ (namestring, psymtab_include_list[i]))
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+
+#ifdef DBXREAD_ONLY
+ record_include_file:
+#endif
+
+ psymtab_include_list[includes_used++] = namestring;
+ if (includes_used >= includes_allocated)
+ {
+ char **orig = psymtab_include_list;
+
+ psymtab_include_list = (char **)
+ alloca ((includes_allocated *= 2) *
+ sizeof (char *));
+ memcpy ((PTR)psymtab_include_list, (PTR)orig,
+ includes_used * sizeof (char *));
+ }
+ continue;
+
+ case N_LSYM: /* Typedef or automatic variable. */
+ case N_STSYM: /* Data seg var -- static */
+ case N_LCSYM: /* BSS " */
+ case N_ROSYM: /* Read-only data seg var -- static. */
+ case N_NBSTS: /* Gould nobase. */
+ case N_NBLCS: /* symbols. */
+ case N_FUN:
+ case N_GSYM: /* Global (extern) variable; can be
+ data or bss (sigh FIXME). */
+
+ /* Following may probably be ignored; I'll leave them here
+ for now (until I do Pascal and Modula 2 extensions). */
+
+ case N_PC: /* I may or may not need this; I
+ suspect not. */
+ case N_M2C: /* I suspect that I can ignore this here. */
+ case N_SCOPE: /* Same. */
+
+ SET_NAMESTRING();
+
+ p = (char *) strchr (namestring, ':');
+ if (!p)
+ continue; /* Not a debugging symbol. */
+
+
+
+ /* Main processing section for debugging symbols which
+ the initial read through the symbol tables needs to worry
+ about. If we reach this point, the symbol which we are
+ considering is definitely one we are interested in.
+ p must also contain the (valid) index into the namestring
+ which indicates the debugging type symbol. */
+
+ switch (p[1])
+ {
+ case 'S':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+ case 'G':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ /* The addresses in these entries are reported to be
+ wrong. See the code that reads 'G's for symtabs. */
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->global_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE, psymtab_language,
+ objfile);
+ p += 1;
+ }
+ }
+ goto check_enum;
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ }
+ check_enum:
+ /* If this is an enumerated type, we need to
+ add all the enum constants to the partial symbol
+ table. This does not cover enums without names, e.g.
+ "enum {a, b} c;" in C, but fortunately those are
+ rare. There is no way for GDB to find those from the
+ enum type without spending too much time on it. Thus
+ to solve this problem, the compiler needs to put out the
+ enum in a nameless type. GCC2 does this. */
+
+ /* We are looking for something of the form
+ <name> ":" ("t" | "T") [<number> "="] "e"
+ {<constant> ":" <value> ","} ";". */
+
+ /* Skip over the colon and the 't' or 'T'. */
+ p += 2;
+ /* This type may be given a number. Also, numbers can come
+ in pairs like (0,26). Skip over it. */
+ while ((*p >= '0' && *p <= '9')
+ || *p == '(' || *p == ',' || *p == ')'
+ || *p == '=')
+ p++;
+
+ if (*p++ == 'e')
+ {
+ /* We have found an enumerated type. */
+ /* According to comments in read_enum_type
+ a comma could end it instead of a semicolon.
+ I don't know where that happens.
+ Accept either. */
+ while (*p && *p != ';' && *p != ',')
+ {
+ char *q;
+
+ /* Check for and handle cretinous dbx symbol name
+ continuation! */
+ if (*p == '\\')
+ p = next_symbol_text ();
+
+ /* Point to the character after the name
+ of the enum constant. */
+ for (q = p; *q && *q != ':'; q++)
+ ;
+ /* Note that the value doesn't matter for
+ enum constants in psymtabs, just in symtabs. */
+ ADD_PSYMBOL_TO_LIST (p, q - p,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, 0,
+ psymtab_language, objfile);
+ /* Point past the name. */
+ p = q;
+ /* Skip over the value. */
+ while (*p && *p != ',')
+ p++;
+ /* Advance past the comma. */
+ if (*p)
+ p++;
+ }
+ }
+ continue;
+ case 'c':
+ /* Constant, e.g. from "const" in Pascal. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'f':
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ if (pst && pst->textlow == 0)
+ pst->textlow = CUR_SYMBOL_VALUE;
+#if 0
+ if (startup_file_end == 0)
+ startup_file_end = CUR_SYMBOL_VALUE;
+#endif
+ /* End kludge. */
+#endif /* DBXREAD_ONLY */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ /* Global functions were ignored here, but now they
+ are put into the global psymtab like one would expect.
+ They're also in the minimal symbol table. */
+ case 'F':
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ if (pst && pst->textlow == 0)
+ pst->textlow = CUR_SYMBOL_VALUE;
+#if 0
+ if (startup_file_end == 0)
+ startup_file_end = CUR_SYMBOL_VALUE;
+#endif
+ /* End kludge. */
+#endif /* DBXREAD_ONLY */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->global_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ /* Two things show up here (hopefully); static symbols of
+ local scope (static used inside braces) or extensions
+ of structure symbols. We can ignore both. */
+ case 'V':
+ case '(':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ continue;
+
+ default:
+ /* Unexpected symbol. Ignore it; perhaps it is an extension
+ that we don't know about.
+
+ Someone says sun cc puts out symbols like
+ /foo/baz/maclib::/usr/local/bin/maclib,
+ which would get here with a symbol type of ':'. */
+ complain (&unknown_symchar_complaint, p[1]);
+ continue;
+ }
+
+ case N_EXCL:
+#ifdef DBXREAD_ONLY
+
+ SET_NAMESTRING();
+
+ /* Find the corresponding bincl and mark that psymtab on the
+ psymtab dependency list */
+ {
+ struct partial_symtab *needed_pst =
+ find_corresponding_bincl_psymtab (namestring, CUR_SYMBOL_VALUE);
+
+ /* If this include file was defined earlier in this file,
+ leave it alone. */
+ if (needed_pst == pst) continue;
+
+ if (needed_pst)
+ {
+ int i;
+ int found = 0;
+
+ for (i = 0; i < dependencies_used; i++)
+ if (dependency_list[i] == needed_pst)
+ {
+ found = 1;
+ break;
+ }
+
+ /* If it's already in the list, skip the rest. */
+ if (found) continue;
+
+ dependency_list[dependencies_used++] = needed_pst;
+ if (dependencies_used >= dependencies_allocated)
+ {
+ struct partial_symtab **orig = dependency_list;
+ dependency_list =
+ (struct partial_symtab **)
+ alloca ((dependencies_allocated *= 2)
+ * sizeof (struct partial_symtab *));
+ memcpy ((PTR)dependency_list, (PTR)orig,
+ (dependencies_used
+ * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to reallocate dependency list.\n");
+ fprintf (stderr, "New dependencies allocated: %d\n",
+ dependencies_allocated);
+#endif
+ }
+ }
+ else
+ error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.",
+ symnum);
+ }
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ case N_RBRAC:
+#ifdef HANDLE_RBRAC
+ HANDLE_RBRAC(CUR_SYMBOL_VALUE);
+ continue;
+#endif
+ case N_EINCL:
+ case N_DSLINE:
+ case N_BSLINE:
+ case N_SSYM: /* Claim: Structure or union element.
+ Hopefully, I can ignore this. */
+ case N_ENTRY: /* Alternate entry point; can ignore. */
+ case N_MAIN: /* Can definitely ignore this. */
+ case N_CATCH: /* These are GNU C++ extensions */
+ case N_EHDECL: /* that can safely be ignored here. */
+ case N_LENG:
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_FNAME:
+ case N_SLINE:
+ case N_RSYM:
+ case N_PSYM:
+ case N_LBRAC:
+ case N_NSYMS: /* Ultrix 4.0: symbol count */
+ case N_DEFD: /* GNU Modula-2 */
+
+ case N_OBJ: /* useless types from Solaris */
+ case N_OPT:
+ case N_ENDM:
+ /* These symbols aren't interesting; don't worry about them */
+
+ continue;
+
+ default:
+ /* If we haven't found it yet, ignore it. It's probably some
+ new type we don't know about yet. */
+ complain (&unknown_symtype_complaint,
+ local_hex_string ((unsigned long) CUR_SYMBOL_TYPE));
+ continue;
+ }
diff --git a/gnu/usr.bin/gdb/gdb/printcmd.c b/gnu/usr.bin/gdb/gdb/printcmd.c
new file mode 100644
index 000000000000..3530ac2f32f0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/printcmd.c
@@ -0,0 +1,2078 @@
+/* Print values for GNU debugger GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <varargs.h>
+#include "frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "language.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "demangle.h"
+
+extern int asm_demangle; /* Whether to demangle syms in asm printouts */
+extern int addressprint; /* Whether to print hex addresses in HLL " */
+
+struct format_data
+{
+ int count;
+ char format;
+ char size;
+};
+
+/* Last specified output format. */
+
+static char last_format = 'x';
+
+/* Last specified examination size. 'b', 'h', 'w' or `q'. */
+
+static char last_size = 'w';
+
+/* Default address to examine next. */
+
+static CORE_ADDR next_address;
+
+/* Last address examined. */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+ This is not valid past the end of the `x' command! */
+
+static value last_examine_value;
+
+/* Largest offset between a symbolic value and an address, that will be
+ printed as `0x1234 <symbol+offset>'. */
+
+static unsigned int max_symbolic_offset = UINT_MAX;
+
+/* Append the source filename and linenumber of the symbol when
+ printing a symbolic value as `<symbol at filename:linenum>' if set. */
+static int print_symbol_filename = 0;
+
+/* Number of auto-display expression currently being displayed.
+ So that we can disable it if we get an error or a signal within it.
+ -1 when not doing one. */
+
+int current_display_number;
+
+/* Flag to low-level print routines that this value is being printed
+ in an epoch window. We'd like to pass this as a parameter, but
+ every routine would need to take it. Perhaps we can encapsulate
+ this in the I/O stream once we have GNU stdio. */
+
+int inspect_it = 0;
+
+struct display
+{
+ /* Chain link to next auto-display item. */
+ struct display *next;
+ /* Expression to be evaluated and displayed. */
+ struct expression *exp;
+ /* Item number of this auto-display item. */
+ int number;
+ /* Display format specified. */
+ struct format_data format;
+ /* Innermost block required by this expression when evaluated */
+ struct block *block;
+ /* Status of this display (enabled or disabled) */
+ enum enable status;
+};
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Prototypes for local functions */
+
+static void
+delete_display PARAMS ((int));
+
+static void
+enable_display PARAMS ((char *, int));
+
+static void
+disable_display_command PARAMS ((char *, int));
+
+static void
+disassemble_command PARAMS ((char *, int));
+
+static void
+printf_command PARAMS ((char *, int));
+
+static void
+print_frame_nameless_args PARAMS ((struct frame_info *, long, int, int,
+ FILE *));
+
+static void
+display_info PARAMS ((char *, int));
+
+static void
+do_one_display PARAMS ((struct display *));
+
+static void
+undisplay_command PARAMS ((char *, int));
+
+static void
+free_display PARAMS ((struct display *));
+
+static void
+display_command PARAMS ((char *, int));
+
+static void
+x_command PARAMS ((char *, int));
+
+static void
+address_info PARAMS ((char *, int));
+
+static void
+set_command PARAMS ((char *, int));
+
+static void
+output_command PARAMS ((char *, int));
+
+static void
+call_command PARAMS ((char *, int));
+
+static void
+inspect_command PARAMS ((char *, int));
+
+static void
+print_command PARAMS ((char *, int));
+
+static void
+print_command_1 PARAMS ((char *, int, int));
+
+static void
+validate_format PARAMS ((struct format_data, char *));
+
+static void
+do_examine PARAMS ((struct format_data, CORE_ADDR));
+
+static void
+print_formatted PARAMS ((value, int, int));
+
+static struct format_data
+decode_format PARAMS ((char **, int, int));
+
+
+/* Decode a format specification. *STRING_PTR should point to it.
+ OFORMAT and OSIZE are used as defaults for the format and size
+ if none are given in the format specification.
+ If OSIZE is zero, then the size field of the returned value
+ should be set only if a size is explicitly specified by the
+ user.
+ The structure returned describes all the data
+ found in the specification. In addition, *STRING_PTR is advanced
+ past the specification and past all whitespace following it. */
+
+static struct format_data
+decode_format (string_ptr, oformat, osize)
+ char **string_ptr;
+ int oformat;
+ int osize;
+{
+ struct format_data val;
+ register char *p = *string_ptr;
+
+ val.format = '?';
+ val.size = '?';
+ val.count = 1;
+
+ if (*p >= '0' && *p <= '9')
+ val.count = atoi (p);
+ while (*p >= '0' && *p <= '9') p++;
+
+ /* Now process size or format letters that follow. */
+
+ while (1)
+ {
+ if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+ val.size = *p++;
+ else if (*p >= 'a' && *p <= 'z')
+ val.format = *p++;
+ else
+ break;
+ }
+
+#ifndef CC_HAS_LONG_LONG
+ /* Make sure 'g' size is not used on integer types.
+ Well, actually, we can handle hex. */
+ if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+ val.size = 'w';
+#endif
+
+ while (*p == ' ' || *p == '\t') p++;
+ *string_ptr = p;
+
+ /* Set defaults for format and size if not specified. */
+ if (val.format == '?')
+ {
+ if (val.size == '?')
+ {
+ /* Neither has been specified. */
+ val.format = oformat;
+ val.size = osize;
+ }
+ else
+ /* If a size is specified, any format makes a reasonable
+ default except 'i'. */
+ val.format = oformat == 'i' ? 'x' : oformat;
+ }
+ else if (val.size == '?')
+ switch (val.format)
+ {
+ case 'a':
+ case 's':
+ /* Addresses must be words. */
+ val.size = osize ? 'w' : osize;
+ break;
+ case 'f':
+ /* Floating point has to be word or giantword. */
+ if (osize == 'w' || osize == 'g')
+ val.size = osize;
+ else
+ /* Default it to giantword if the last used size is not
+ appropriate. */
+ val.size = osize ? 'g' : osize;
+ break;
+ case 'c':
+ /* Characters default to one byte. */
+ val.size = osize ? 'b' : osize;
+ break;
+ default:
+ /* The default is the size most recently specified. */
+ val.size = osize;
+ }
+
+ return val;
+}
+
+/* Print value VAL on stdout according to FORMAT, a letter or 0.
+ Do not end with a newline.
+ 0 means print VAL according to its own type.
+ SIZE is the letter for the size of datum being printed.
+ This is used to pad hex numbers so they line up. */
+
+static void
+print_formatted (val, format, size)
+ register value val;
+ register int format;
+ int size;
+{
+ int len = TYPE_LENGTH (VALUE_TYPE (val));
+
+ if (VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val) + len;
+
+ switch (format)
+ {
+ case 's':
+ next_address = VALUE_ADDRESS (val)
+ + value_print (value_addr (val), stdout, format, Val_pretty_default);
+ break;
+
+ case 'i':
+ /* The old comment says
+ "Force output out, print_insn not using _filtered".
+ I'm not completely sure what that means, I suspect most print_insn
+ now do use _filtered, so I guess it's obsolete. */
+ /* We often wrap here if there are long symbolic names. */
+ wrap_here (" ");
+ next_address = VALUE_ADDRESS (val)
+ + print_insn (VALUE_ADDRESS (val), stdout);
+ break;
+
+ default:
+ if (format == 0
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+ || VALUE_REPEATED (val))
+ value_print (val, stdout, format, Val_pretty_default);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, stdout);
+ }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+ according to letters FORMAT and SIZE on STREAM.
+ FORMAT may not be zero. Formats s and i are not supported at this level.
+
+ This is how the elements of an array or structure are printed
+ with a format. */
+
+void
+print_scalar_formatted (valaddr, type, format, size, stream)
+ char *valaddr;
+ struct type *type;
+ int format;
+ int size;
+ FILE *stream;
+{
+ LONGEST val_long;
+ int len = TYPE_LENGTH (type);
+
+ if (len > sizeof (LONGEST)
+ && (format == 't'
+ || format == 'c'
+ || format == 'o'
+ || format == 'u'
+ || format == 'd'
+ || format == 'x'))
+ {
+ /* We can't print it normally, but we can print it in hex.
+ Printing it in the wrong radix is more useful than saying
+ "use /x, you dummy". */
+ /* FIXME: we could also do octal or binary if that was the
+ desired format. */
+ /* FIXME: we should be using the size field to give us a minimum
+ field width to print. */
+ val_print_type_code_int (type, valaddr, stream);
+ return;
+ }
+
+ val_long = unpack_long (type, valaddr);
+
+ /* If we are printing it as unsigned, truncate it in case it is actually
+ a negative signed value (e.g. "print/u (short)-1" should print 65535
+ (if shorts are 16 bits) instead of 4294967295). */
+ if (format != 'd')
+ {
+ if (len < sizeof (LONGEST))
+ val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
+ }
+
+ switch (format)
+ {
+ case 'x':
+ if (!size)
+ {
+ /* no size specified, like in print. Print varying # of digits. */
+ print_longest (stream, 'x', 1, val_long);
+ }
+ else
+ switch (size)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ print_longest (stream, size, 1, val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+ break;
+
+ case 'd':
+ print_longest (stream, 'd', 1, val_long);
+ break;
+
+ case 'u':
+ print_longest (stream, 'u', 0, val_long);
+ break;
+
+ case 'o':
+ if (val_long)
+ print_longest (stream, 'o', 1, val_long);
+ else
+ fprintf_filtered (stream, "0");
+ break;
+
+ case 'a':
+ print_address (unpack_pointer (type, valaddr), stream);
+ break;
+
+ case 'c':
+ value_print (value_from_longest (builtin_type_char, val_long), stream, 0,
+ Val_pretty_default);
+ break;
+
+ case 'f':
+ if (len == sizeof (float))
+ type = builtin_type_float;
+ else if (len == sizeof (double))
+ type = builtin_type_double;
+ print_floating (valaddr, type, stream);
+ break;
+
+ case 0:
+ abort ();
+
+ case 't':
+ /* Binary; 't' stands for "two". */
+ {
+ char bits[8*(sizeof val_long) + 1];
+ char *cp = bits;
+ int width;
+
+ if (!size)
+ width = 8*(sizeof val_long);
+ else
+ switch (size)
+ {
+ case 'b':
+ width = 8;
+ break;
+ case 'h':
+ width = 16;
+ break;
+ case 'w':
+ width = 32;
+ break;
+ case 'g':
+ width = 64;
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+
+ bits[width] = '\0';
+ while (width-- > 0)
+ {
+ bits[width] = (val_long & 1) ? '1' : '0';
+ val_long >>= 1;
+ }
+ if (!size)
+ {
+ while (*cp && *cp == '0')
+ cp++;
+ if (*cp == '\0')
+ cp--;
+ }
+ fprintf_filtered (stream, local_binary_format_prefix());
+ fprintf_filtered (stream, cp);
+ fprintf_filtered (stream, local_binary_format_suffix());
+ }
+ break;
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* Specify default address for `x' command.
+ `info lines' uses this. */
+
+void
+set_next_address (addr)
+ CORE_ADDR addr;
+{
+ next_address = addr;
+
+ /* Make address available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (lookup_pointer_type (builtin_type_void),
+ (LONGEST) addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM,
+ after LEADIN. Print nothing if no symbolic name is found nearby.
+ DO_DEMANGLE controls whether to print a symbol in its native "raw" form,
+ or to interpret it as a possible C++ name and convert it back to source
+ form. However note that DO_DEMANGLE can be overridden by the specific
+ settings of the demangle and asm_demangle variables. */
+
+void
+print_address_symbolic (addr, stream, do_demangle, leadin)
+ CORE_ADDR addr;
+ FILE *stream;
+ int do_demangle;
+ char *leadin;
+{
+ CORE_ADDR name_location;
+ register struct symbol *symbol;
+ char *name;
+
+ /* First try to find the address in the symbol tables to find
+ static functions. If that doesn't succeed we try the minimal symbol
+ vector for symbols in non-text space.
+ FIXME: Should find a way to get at the static non-text symbols too. */
+
+ symbol = find_pc_function (addr);
+ if (symbol)
+ {
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (symbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (symbol);
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (addr);
+
+ /* If nothing comes out, don't print anything symbolic. */
+ if (msymbol == NULL)
+ return;
+ name_location = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (msymbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (msymbol);
+ }
+
+ /* If the nearest symbol is too far away, don't print anything symbolic. */
+
+ /* For when CORE_ADDR is larger than unsigned int, we do math in
+ CORE_ADDR. But when we detect unsigned wraparound in the
+ CORE_ADDR math, we ignore this test and print the offset,
+ because addr+max_symbolic_offset has wrapped through the end
+ of the address space back to the beginning, giving bogus comparison. */
+ if (addr > name_location + max_symbolic_offset
+ && name_location + max_symbolic_offset > name_location)
+ return;
+
+ fputs_filtered (leadin, stream);
+ fputs_filtered ("<", stream);
+ fputs_filtered (name, stream);
+ if (addr != name_location)
+ fprintf_filtered (stream, "+%u", (unsigned int)(addr - name_location));
+
+ /* Append source filename and line number if desired. */
+ if (symbol && print_symbol_filename)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.symtab)
+ fprintf_filtered (stream, " at %s:%d", sal.symtab->filename, sal.line);
+ }
+ fputs_filtered (">", stream);
+}
+
+/* Print address ADDR symbolically on STREAM.
+ First print it as a number. Then perhaps print
+ <SYMBOL + OFFSET> after the number. */
+
+void
+print_address (addr, stream)
+ CORE_ADDR addr;
+ FILE *stream;
+{
+#if 0 && defined (ADDR_BITS_REMOVE)
+ /* This is wrong for pointer to char, in which we do want to print
+ the low bits. */
+ fprintf_filtered (stream, local_hex_format(),
+ (unsigned long) ADDR_BITS_REMOVE(addr));
+#else
+ fprintf_filtered (stream, local_hex_format(), (unsigned long) addr);
+#endif
+ print_address_symbolic (addr, stream, asm_demangle, " ");
+}
+
+/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE
+ controls whether to print the symbolic name "raw" or demangled.
+ Global setting "addressprint" controls whether to print hex address
+ or not. */
+
+void
+print_address_demangle (addr, stream, do_demangle)
+ CORE_ADDR addr;
+ FILE *stream;
+ int do_demangle;
+{
+ if (addr == 0) {
+ fprintf_filtered (stream, "0");
+ } else if (addressprint) {
+ fprintf_filtered (stream, local_hex_format(), (unsigned long) addr);
+ print_address_symbolic (addr, stream, do_demangle, " ");
+ } else {
+ print_address_symbolic (addr, stream, do_demangle, "");
+ }
+}
+
+
+/* These are the types that $__ will get after an examine command of one
+ of these sizes. */
+
+static struct type *examine_b_type;
+static struct type *examine_h_type;
+static struct type *examine_w_type;
+static struct type *examine_g_type;
+
+/* Examine data at address ADDR in format FMT.
+ Fetch it from memory and print on stdout. */
+
+static void
+do_examine (fmt, addr)
+ struct format_data fmt;
+ CORE_ADDR addr;
+{
+ register char format = 0;
+ register char size;
+ register int count = 1;
+ struct type *val_type = NULL;
+ register int i;
+ register int maxelts;
+
+ format = fmt.format;
+ size = fmt.size;
+ count = fmt.count;
+ next_address = addr;
+
+ /* String or instruction format implies fetch single bytes
+ regardless of the specified size. */
+ if (format == 's' || format == 'i')
+ size = 'b';
+
+ if (size == 'b')
+ val_type = examine_b_type;
+ else if (size == 'h')
+ val_type = examine_h_type;
+ else if (size == 'w')
+ val_type = examine_w_type;
+ else if (size == 'g')
+ val_type = examine_g_type;
+
+ maxelts = 8;
+ if (size == 'w')
+ maxelts = 4;
+ if (size == 'g')
+ maxelts = 2;
+ if (format == 's' || format == 'i')
+ maxelts = 1;
+
+ /* Print as many objects as specified in COUNT, at most maxelts per line,
+ with the address of the next one at the start of each line. */
+
+ while (count > 0)
+ {
+ print_address (next_address, stdout);
+ printf_filtered (":");
+ for (i = maxelts;
+ i > 0 && count > 0;
+ i--, count--)
+ {
+ printf_filtered ("\t");
+ /* Note that print_formatted sets next_address for the next
+ object. */
+ last_examine_address = next_address;
+ last_examine_value = value_at (val_type, next_address);
+ print_formatted (last_examine_value, format, size);
+ }
+ printf_filtered ("\n");
+ fflush (stdout);
+ }
+}
+
+static void
+validate_format (fmt, cmdname)
+ struct format_data fmt;
+ char *cmdname;
+{
+ if (fmt.size != 0)
+ error ("Size letters are meaningless in \"%s\" command.", cmdname);
+ if (fmt.count != 1)
+ error ("Item count other than 1 is meaningless in \"%s\" command.",
+ cmdname);
+ if (fmt.format == 'i' || fmt.format == 's')
+ error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+ fmt.format, cmdname);
+}
+
+/* Evaluate string EXP as an expression in the current language and
+ print the resulting value. EXP may contain a format specifier as the
+ first argument ("/x myvar" for example, to print myvar in hex).
+ */
+
+static void
+print_command_1 (exp, inspect, voidprint)
+ char *exp;
+ int inspect;
+ int voidprint;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain = 0;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+ int cleanup = 0;
+
+ /* Pass inspect flag to the rest of the print routines in a global (sigh). */
+ inspect_it = inspect;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, 0);
+ validate_format (fmt, "print");
+ last_format = format = fmt.format;
+ }
+ else
+ {
+ fmt.count = 1;
+ fmt.format = 0;
+ fmt.size = 0;
+ }
+
+ if (exp && *exp)
+ {
+ extern int objectprint;
+ struct type *type;
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+
+ /* C++: figure out what type we actually want to print it as. */
+ type = VALUE_TYPE (val);
+
+ if (objectprint
+ && ( TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF)
+ && ( TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_UNION))
+ {
+ value v;
+
+ v = value_from_vtable_info (val, TYPE_TARGET_TYPE (type));
+ if (v != 0)
+ {
+ val = v;
+ type = VALUE_TYPE (val);
+ }
+ }
+ }
+ else
+ val = access_value_history (0);
+
+ if (voidprint || (val && VALUE_TYPE (val) &&
+ TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID))
+ {
+ int histindex = record_latest_value (val);
+
+ if (inspect)
+ printf ("\031(gdb-makebuffer \"%s\" %d '(\"", exp, histindex);
+ else
+ if (histindex >= 0) printf_filtered ("$%d = ", histindex);
+
+ print_formatted (val, format, fmt.size);
+ printf_filtered ("\n");
+ if (inspect)
+ printf("\") )\030");
+ }
+
+ if (cleanup)
+ do_cleanups (old_chain);
+ inspect_it = 0; /* Reset print routines to normal */
+}
+
+/* ARGSUSED */
+static void
+print_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ print_command_1 (exp, 0, 1);
+}
+
+/* Same as print, except in epoch, it gets its own window */
+/* ARGSUSED */
+static void
+inspect_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ extern int epoch_interface;
+
+ print_command_1 (exp, epoch_interface, 1);
+}
+
+/* Same as print, except it doesn't print void results. */
+/* ARGSUSED */
+static void
+call_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ print_command_1 (exp, 0, 0);
+}
+
+/* ARGSUSED */
+static void
+output_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ validate_format (fmt, "output");
+ format = fmt.format;
+ }
+
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ print_formatted (val, format, fmt.size);
+
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+set_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr = parse_expression (exp);
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+address_info (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ register struct symbol *sym;
+ register struct minimal_symbol *msymbol;
+ register long val;
+ register long basereg;
+ int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero
+ if exp is a field of `this'. */
+
+ if (exp == 0)
+ error ("Argument required.");
+
+ sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE,
+ &is_a_field_of_this, (struct symtab **)NULL);
+ if (sym == NULL)
+ {
+ if (is_a_field_of_this)
+ {
+ printf ("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+ return;
+ }
+
+ msymbol = lookup_minimal_symbol (exp, (struct objfile *) NULL);
+
+ if (msymbol != NULL)
+ printf ("Symbol \"%s\" is at %s in a file compiled without debugging.\n",
+ exp,
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (msymbol)));
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+ basereg = SYMBOL_BASEREG (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf ("a label at address %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+
+ case LOC_REGISTER:
+ printf ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf ("static storage at address %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+
+ case LOC_REGPARM:
+ printf ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_REGPARM_ADDR:
+ printf ("address of an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf ("an argument at offset %ld", val);
+ break;
+
+ case LOC_LOCAL_ARG:
+ printf ("an argument at frame offset %ld", val);
+ break;
+
+ case LOC_LOCAL:
+ printf ("a local variable at frame offset %ld", val);
+ break;
+
+ case LOC_REF_ARG:
+ printf ("a reference argument at offset %ld", val);
+ break;
+
+ case LOC_BASEREG:
+ printf ("a variable at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_BASEREG_ARG:
+ printf ("an argument at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_TYPEDEF:
+ printf ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf ("a function at address %s",
+ local_hex_string((unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (sym))));
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("optimized out");
+ break;
+
+ default:
+ printf ("of unknown (botched) type");
+ break;
+ }
+ printf (".\n");
+}
+
+static void
+x_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ struct format_data fmt;
+ struct cleanup *old_chain;
+ struct value *val;
+
+ fmt.format = last_format;
+ fmt.size = last_size;
+ fmt.count = 1;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, last_size);
+ }
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ {
+ expr = parse_expression (exp);
+ /* Cause expression not to be there any more
+ if this command is repeated with Newline.
+ But don't clobber a user-defined command's definition. */
+ if (from_tty)
+ *exp = 0;
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_expression (expr);
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+ val = value_ind (val);
+ /* In rvalue contexts, such as this, functions are coerced into
+ pointers to functions. This makes "x/i main" work. */
+ if (/* last_format == 'i'
+ && */ TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC
+ && VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val);
+ else
+ next_address = value_as_pointer (val);
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address);
+
+ /* If the examine succeeds, we remember its size and format for next time. */
+ last_size = fmt.size;
+ last_format = fmt.format;
+
+ /* Set a couple of internal variables if appropriate. */
+ if (last_examine_value)
+ {
+ /* Make last address examined available to the user as $_. Use
+ the correct pointer type. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (
+ lookup_pointer_type (VALUE_TYPE (last_examine_value)),
+ (LONGEST) last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__.*/
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+
+/* Add an expression to the auto-display chain.
+ Specify the expression. */
+
+static void
+display_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct format_data fmt;
+ register struct expression *expr;
+ register struct display *new;
+
+ if (exp == 0)
+ {
+ do_displays ();
+ return;
+ }
+
+ if (*exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ if (fmt.size && fmt.format == 0)
+ fmt.format = 'x';
+ if (fmt.format == 'i' || fmt.format == 's')
+ fmt.size = 'b';
+ }
+ else
+ {
+ fmt.format = 0;
+ fmt.size = 0;
+ fmt.count = 0;
+ }
+
+ innermost_block = 0;
+ expr = parse_expression (exp);
+
+ new = (struct display *) xmalloc (sizeof (struct display));
+
+ new->exp = expr;
+ new->block = innermost_block;
+ new->next = display_chain;
+ new->number = ++display_number;
+ new->format = fmt;
+ new->status = enabled;
+ display_chain = new;
+
+ if (from_tty && target_has_execution)
+ do_one_display (new);
+
+ dont_repeat ();
+}
+
+static void
+free_display (d)
+ struct display *d;
+{
+ free ((PTR)d->exp);
+ free ((PTR)d);
+}
+
+/* Clear out the display_chain.
+ Done when new symtabs are loaded, since this invalidates
+ the types stored in many expressions. */
+
+void
+clear_displays ()
+{
+ register struct display *d;
+
+ while ((d = display_chain) != NULL)
+ {
+ free ((PTR)d->exp);
+ display_chain = d->next;
+ free ((PTR)d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+static void
+delete_display (num)
+ int num;
+{
+ register struct display *d1, *d;
+
+ if (!display_chain)
+ error ("No display number %d.", num);
+
+ if (display_chain->number == num)
+ {
+ d1 = display_chain;
+ display_chain = d1->next;
+ free_display (d1);
+ }
+ else
+ for (d = display_chain; ; d = d->next)
+ {
+ if (d->next == 0)
+ error ("No display number %d.", num);
+ if (d->next->number == num)
+ {
+ d1 = d->next;
+ d->next = d1->next;
+ free_display (d1);
+ break;
+ }
+ }
+}
+
+/* Delete some values from the auto-display chain.
+ Specify the element numbers. */
+
+static void
+undisplay_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+
+ if (args == 0)
+ {
+ if (query ("Delete all auto-display expressions? "))
+ clear_displays ();
+ dont_repeat ();
+ return;
+ }
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9') p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ delete_display (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+ dont_repeat ();
+}
+
+/* Display a single auto-display.
+ Do nothing if the display cannot be printed in the current context,
+ or if the display is disabled. */
+
+static void
+do_one_display (d)
+ struct display *d;
+{
+ int within_current_scope;
+
+ if (d->status == disabled)
+ return;
+
+ if (d->block)
+ within_current_scope = contained_in (get_selected_block (), d->block);
+ else
+ within_current_scope = 1;
+ if (!within_current_scope)
+ return;
+
+ current_display_number = d->number;
+
+ printf_filtered ("%d: ", d->number);
+ if (d->format.size)
+ {
+ CORE_ADDR addr;
+
+ printf_filtered ("x/");
+ if (d->format.count != 1)
+ printf_filtered ("%d", d->format.count);
+ printf_filtered ("%c", d->format.format);
+ if (d->format.format != 'i' && d->format.format != 's')
+ printf_filtered ("%c", d->format.size);
+ printf_filtered (" ");
+ print_expression (d->exp, stdout);
+ if (d->format.count != 1)
+ printf_filtered ("\n");
+ else
+ printf_filtered (" ");
+
+ addr = value_as_pointer (evaluate_expression (d->exp));
+ if (d->format.format == 'i')
+ addr = ADDR_BITS_REMOVE (addr);
+
+ do_examine (d->format, addr);
+ }
+ else
+ {
+ if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ printf_filtered (" = ");
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf_filtered ("\n");
+ }
+
+ fflush (stdout);
+ current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+ evaluated in the current scope. */
+
+void
+do_displays ()
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+ This is done when there is an error or a signal. */
+
+void
+disable_display (num)
+ int num;
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = disabled;
+ return;
+ }
+ printf ("No display number %d.\n", num);
+}
+
+void
+disable_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ disable_display (current_display_number);
+ fprintf (stderr, "Disabling display %d to avoid infinite recursion.\n",
+ current_display_number);
+ }
+ current_display_number = -1;
+}
+
+static void
+display_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct display *d;
+
+ if (!display_chain)
+ printf ("There are no auto-display expressions now.\n");
+ else
+ printf_filtered ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+ for (d = display_chain; d; d = d->next)
+ {
+ printf_filtered ("%d: %c ", d->number, "ny"[(int)d->status]);
+ if (d->format.size)
+ printf_filtered ("/%d%c%c ", d->format.count, d->format.size,
+ d->format.format);
+ else if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf_filtered (" (cannot be evaluated in the current context)");
+ printf_filtered ("\n");
+ fflush (stdout);
+ }
+}
+
+static void
+enable_display (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->status = enabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = enabled;
+ goto win;
+ }
+ printf ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+/* ARGSUSED */
+static void
+disable_display_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->status = disabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ disable_display (atoi (p));
+
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+
+/* Print the value in stack frame FRAME of a variable
+ specified by a struct symbol. */
+
+void
+print_variable_value (var, frame, stream)
+ struct symbol *var;
+ FRAME frame;
+ FILE *stream;
+{
+ value val = read_var_value (var, frame);
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+ running in that frame (as a symbol), the info on the frame,
+ and the number of args according to the stack frame (or -1 if unknown). */
+
+/* References here and elsewhere to "number of args according to the
+ stack frame" appear in all cases to refer to "number of ints of args
+ according to the stack frame". At least for VAX, i386, isi. */
+
+void
+print_frame_args (func, fi, num, stream)
+ struct symbol *func;
+ struct frame_info *fi;
+ int num;
+ FILE *stream;
+{
+ struct block *b = NULL;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register struct symbol *sym;
+ register value val;
+ /* Offset of next stack argument beyond the one we have seen that is
+ at the highest offset.
+ -1 if we haven't come to a stack argument yet. */
+ long highest_offset = -1;
+ int arg_size;
+ /* Number of ints of arguments that we have printed so far. */
+ int args_printed = 0;
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+ }
+
+ for (i = 0; i < nsyms; i++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, i);
+
+ /* Keep track of the highest stack argument offset seen, and
+ skip over any kinds of symbols we don't care about. */
+
+ switch (SYMBOL_CLASS (sym)) {
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ {
+ long current_offset = SYMBOL_VALUE (sym);
+
+ arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+
+ /* Compute address of next argument by adding the size of
+ this argument and rounding to an int boundary. */
+ current_offset
+ = ((current_offset + arg_size + sizeof (int) - 1)
+ & ~(sizeof (int) - 1));
+
+ /* If this is the highest offset seen yet, set highest_offset. */
+ if (highest_offset == -1
+ || (current_offset > highest_offset))
+ highest_offset = current_offset;
+
+ /* Add the number of ints we're about to print to args_printed. */
+ args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
+ }
+
+ /* We care about types of symbols, but don't need to keep track of
+ stack offsets in them. */
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG_ARG:
+ break;
+
+ /* Other types of symbols we just skip over. */
+ default:
+ continue;
+ }
+
+ /* We have to look up the symbol because arguments can have
+ two entries (one a parameter, one a local) and the one we
+ want is the local, which lookup_symbol will find for us.
+ This includes gcc1 (not gcc2) on the sparc when passing a
+ small structure and gcc2 when the argument type is float
+ and it is passed as a double and converted to float by
+ the prologue (in the latter case the type of the LOC_ARG
+ symbol is double and the type of the LOC_LOCAL symbol is
+ float). There are also LOC_ARG/LOC_REGISTER pairs which
+ are not combined in symbol-reading. */
+ /* But if the parameter name is null, don't try it.
+ Null parameter names occur on the RS/6000, for traceback tables.
+ FIXME, should we even print them? */
+
+ if (*SYMBOL_NAME (sym))
+ sym = lookup_symbol
+ (SYMBOL_NAME (sym),
+ b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+
+ /* Print the current arg. */
+ if (! first)
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym),
+ SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered ("=", stream);
+
+ /* Avoid value_print because it will deref ref parameters. We just
+ want to print their addresses. Print ??? for args whose address
+ we do not know. We pass 2 as "recurse" to val_print because our
+ standard indentation here is 4 spaces, and val_print indents
+ 2 for each recurse. */
+ val = read_var_value (sym, FRAME_INFO_ID (fi));
+ if (val)
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val),
+ stream, 0, 0, 2, Val_no_prettyprint);
+ else
+ fputs_filtered ("???", stream);
+ first = 0;
+ }
+
+ /* Don't print nameless args in situations where we don't know
+ enough about the stack to find them. */
+ if (num != -1)
+ {
+ long start;
+
+ if (highest_offset == -1)
+ start = FRAME_ARGS_SKIP;
+ else
+ start = highest_offset;
+
+ print_frame_nameless_args (fi, start, num - args_printed,
+ first, stream);
+ }
+}
+
+/* Print nameless args on STREAM.
+ FI is the frameinfo for this frame, START is the offset
+ of the first nameless arg, and NUM is the number of nameless args to
+ print. FIRST is nonzero if this is the first argument (not just
+ the first nameless arg). */
+static void
+print_frame_nameless_args (fi, start, num, first, stream)
+ struct frame_info *fi;
+ long start;
+ int num;
+ int first;
+ FILE *stream;
+{
+ int i;
+ CORE_ADDR argsaddr;
+ long arg_value;
+
+ for (i = 0; i < num; i++)
+ {
+ QUIT;
+#ifdef NAMELESS_ARG_VALUE
+ NAMELESS_ARG_VALUE (fi, start, &arg_value);
+#else
+ argsaddr = FRAME_ARGS_ADDRESS (fi);
+ if (!argsaddr)
+ return;
+
+ arg_value = read_memory_integer (argsaddr + start, sizeof (int));
+#endif
+
+ if (!first)
+ fprintf_filtered (stream, ", ");
+
+#ifdef PRINT_NAMELESS_INTEGER
+ PRINT_NAMELESS_INTEGER (stream, arg_value);
+#else
+#ifdef PRINT_TYPELESS_INTEGER
+ PRINT_TYPELESS_INTEGER (stream, builtin_type_int, (LONGEST) arg_value);
+#else
+ fprintf_filtered (stream, "%d", arg_value);
+#endif /* PRINT_TYPELESS_INTEGER */
+#endif /* PRINT_NAMELESS_INTEGER */
+ first = 0;
+ start += sizeof (int);
+ }
+}
+
+/* ARGSUSED */
+static void
+printf_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register char *f;
+ register char *s = arg;
+ char *string;
+ value *val_args;
+ char *substrings;
+ char *current_substring;
+ int nargs = 0;
+ int allocated_args = 20;
+ va_list args_to_vprintf;
+ struct cleanup *old_cleanups;
+
+ val_args = (value *) xmalloc (allocated_args * sizeof (value));
+ old_cleanups = make_cleanup (free_current_contents, &val_args);
+
+ if (s == 0)
+ error_no_arg ("format-control string and values to print");
+
+ /* Skip white space before format string */
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* A format string should follow, enveloped in double quotes */
+ if (*s++ != '"')
+ error ("Bad format string, missing '\"'.");
+
+ /* Parse the format-control string and copy it into the string STRING,
+ processing some kinds of escape sequence. */
+
+ f = string = (char *) alloca (strlen (s) + 1);
+
+ while (*s != '"')
+ {
+ int c = *s++;
+ switch (c)
+ {
+ case '\0':
+ error ("Bad format string, non-terminated '\"'.");
+
+ case '\\':
+ switch (c = *s++)
+ {
+ case '\\':
+ *f++ = '\\';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized \\ escape character in format string.");
+ }
+ break;
+
+ default:
+ *f++ = c;
+ }
+ }
+
+ /* Skip over " and following space and comma. */
+ s++;
+ *f++ = '\0';
+ while (*s == ' ' || *s == '\t') s++;
+
+ if (*s != ',' && *s != 0)
+ error ("Invalid argument syntax");
+
+ if (*s == ',') s++;
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* Need extra space for the '\0's. Doubling the size is sufficient. */
+ substrings = alloca (strlen (string) * 2);
+ current_substring = substrings;
+
+ {
+ /* Now scan the string for %-specs and see what kinds of args they want.
+ argclass[I] classifies the %-specs so we can give vprintf something
+ of the right size. */
+
+ enum argclass {no_arg, int_arg, string_arg, double_arg, long_long_arg};
+ enum argclass *argclass;
+ enum argclass this_argclass;
+ char *last_arg;
+ int nargs_wanted;
+ int lcount;
+ int i;
+
+ argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
+ nargs_wanted = 0;
+ f = string;
+ last_arg = string;
+ while (*f)
+ if (*f++ == '%')
+ {
+ lcount = 0;
+ while (strchr ("0123456789.hlL-+ #", *f))
+ {
+ if (*f == 'l' || *f == 'L')
+ lcount++;
+ f++;
+ }
+ switch (*f)
+ {
+ case 's':
+ this_argclass = string_arg;
+ break;
+
+ case 'e':
+ case 'f':
+ case 'g':
+ this_argclass = double_arg;
+ break;
+
+ case '*':
+ error ("`*' not supported for precision or width in printf");
+
+ case 'n':
+ error ("Format specifier `n' not supported in printf");
+
+ case '%':
+ this_argclass = no_arg;
+ break;
+
+ default:
+ if (lcount > 1)
+ this_argclass = long_long_arg;
+ else
+ this_argclass = int_arg;
+ break;
+ }
+ f++;
+ if (this_argclass != no_arg)
+ {
+ strncpy (current_substring, last_arg, f - last_arg);
+ current_substring += f - last_arg;
+ *current_substring++ = '\0';
+ last_arg = f;
+ argclass[nargs_wanted++] = this_argclass;
+ }
+ }
+
+ /* Now, parse all arguments and evaluate them.
+ Store the VALUEs in VAL_ARGS. */
+
+ while (*s != '\0')
+ {
+ char *s1;
+ if (nargs == allocated_args)
+ val_args = (value *) xrealloc ((char *) val_args,
+ (allocated_args *= 2)
+ * sizeof (value));
+ s1 = s;
+ val_args[nargs] = parse_to_comma_and_eval (&s1);
+
+ /* If format string wants a float, unchecked-convert the value to
+ floating point of the same size */
+
+ if (argclass[nargs] == double_arg)
+ {
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+ }
+ nargs++;
+ s = s1;
+ if (*s == ',')
+ s++;
+ }
+
+ if (nargs != nargs_wanted)
+ error ("Wrong number of arguments for specified format-string");
+
+ /* FIXME: We should be using vprintf_filtered, but as long as it
+ has an arbitrary limit that is unacceptable. Correct fix is
+ for vprintf_filtered to scan down the format string so it knows
+ how big a buffer it needs (perhaps by putting a vasprintf (see
+ GNU C library) in libiberty).
+
+ But for now, just force out any pending output, so at least the output
+ appears in the correct order. */
+ wrap_here ((char *)NULL);
+
+ /* Now actually print them. */
+ current_substring = substrings;
+ for (i = 0; i < nargs; i++)
+ {
+ switch (argclass[i])
+ {
+ case string_arg:
+ {
+ char *str;
+ CORE_ADDR tem;
+ int j;
+ tem = value_as_pointer (val_args[i]);
+
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0; ; j++)
+ {
+ char c;
+ QUIT;
+ read_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
+
+ /* Copy the string contents into a string inside GDB. */
+ str = (char *) alloca (j + 1);
+ read_memory (tem, str, j);
+ str[j] = 0;
+
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (current_substring, str);
+ }
+ break;
+ case double_arg:
+ {
+ double val = value_as_double (val_args[i]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (current_substring, val);
+ break;
+ }
+ case long_long_arg:
+#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+ {
+ long long val = value_as_long (val_args[i]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (current_substring, val);
+ break;
+ }
+#else
+ error ("long long not supported in printf");
+#endif
+ case int_arg:
+ {
+ /* FIXME: there should be separate int_arg and long_arg. */
+ long val = value_as_long (val_args[i]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (current_substring, val);
+ break;
+ }
+ default:
+ error ("internal error in printf_command");
+ }
+ /* Skip to the next substring. */
+ current_substring += strlen (current_substring) + 1;
+ }
+ /* Print the portion of the format string after the last argument. */
+ /* It would be OK to use printf_filtered here. */
+ printf (last_arg);
+ }
+ do_cleanups (old_cleanups);
+}
+
+/* Dump a specified section of assembly code. With no command line
+ arguments, this command will dump the assembly code for the
+ function surrounding the pc value in the selected frame. With one
+ argument, it will dump the assembly code surrounding that pc value.
+ Two arguments are interpeted as bounds within which to dump
+ assembly. */
+
+/* ARGSUSED */
+static void
+disassemble_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ CORE_ADDR low, high;
+ char *name;
+ CORE_ADDR pc;
+ char *space_index;
+
+ name = NULL;
+ if (!arg)
+ {
+ if (!selected_frame)
+ error ("No frame selected.\n");
+
+ pc = get_frame_pc (selected_frame);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains program counter for selected frame.\n");
+ }
+ else if (!(space_index = (char *) strchr (arg, ' ')))
+ {
+ /* One argument. */
+ pc = parse_and_eval_address (arg);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains specified address.\n");
+ }
+ else
+ {
+ /* Two arguments. */
+ *space_index = '\0';
+ low = parse_and_eval_address (arg);
+ high = parse_and_eval_address (space_index + 1);
+ }
+
+ printf_filtered ("Dump of assembler code ");
+ if (name != NULL)
+ {
+ printf_filtered ("for function %s:\n", name);
+ }
+ else
+ {
+ printf_filtered ("from %s ", local_hex_string((unsigned long) low));
+ printf_filtered ("to %s:\n", local_hex_string((unsigned long) high));
+ }
+
+ /* Dump the specified range. */
+ for (pc = low; pc < high; )
+ {
+ QUIT;
+ print_address (pc, stdout);
+ printf_filtered (":\t");
+ pc += print_insn (pc, stdout);
+ printf_filtered ("\n");
+ }
+ printf_filtered ("End of assembler dump.\n");
+ fflush (stdout);
+}
+
+
+void
+_initialize_printcmd ()
+{
+ current_display_number = -1;
+
+ add_info ("address", address_info,
+ "Describe where variable VAR is stored.");
+
+ add_com ("x", class_vars, x_command,
+ "Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+ t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n\
+Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1. Default address is following last thing printed\n\
+with this command or \"print\".");
+
+ add_com ("disassemble", class_vars, disassemble_command,
+ "Disassemble a specified section of memory.\n\
+Default is the function surrounding the pc of the selected frame.\n\
+With a single argument, the function surrounding that address is dumped.\n\
+Two arguments are taken as a range of memory to dump.");
+
+#if 0
+ add_com ("whereis", class_vars, whereis_command,
+ "Print line number and file of definition of variable.");
+#endif
+
+ add_info ("display", display_info,
+ "Expressions to display when program stops, with code numbers.");
+
+ add_cmd ("undisplay", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+ &cmdlist);
+
+ add_com ("display", class_vars, display_command,
+ "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made.");
+
+ add_cmd ("display", class_vars, enable_display,
+ "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+ add_cmd ("display", class_vars, disable_display_command,
+ "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+ add_cmd ("display", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+ add_com ("printf", class_vars, printf_command,
+ "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+ add_com ("output", class_vars, output_command,
+ "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+ add_prefix_cmd ("set", class_vars, set_command,
+"Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example). VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged. EXP is any valid expression.\n\
+Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment.\n\
+You can see these environment settings with the \"show\" command.",
+ &setlist, "set ", 1, &cmdlist);
+
+ /* "call" is the same as "set", but handy for dbx users to call fns. */
+ add_com ("call", class_vars, call_command,
+ "Call a function in the program.\n\
+The argument is the function name and arguments, in the notation of the\n\
+current working language. The result is printed and saved in the value\n\
+history, if it is not void.");
+
+ add_cmd ("variable", class_vars, set_command,
+"Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example). VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged. EXP is any valid expression.\n\
+This may usually be abbreviated to simply \"set\".",
+ &setlist);
+
+ add_com ("print", class_vars, print_command,
+ concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM. $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n\
+if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+ "\n\
+{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array. FOO@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc. FOO must be an expression whose value\n\
+resides in memory.\n",
+ "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command).", NULL));
+ add_com_alias ("p", "print", class_vars, 1);
+
+ add_com ("inspect", class_vars, inspect_command,
+"Same as \"print\" command, except that if you are running in the epoch\n\
+environment, the value is printed in its own window.");
+
+ add_show_from_set (
+ add_set_cmd ("max-symbolic-offset", no_class, var_uinteger,
+ (char *)&max_symbolic_offset,
+ "Set the largest offset that will be printed in <symbol+1234> form.",
+ &setprintlist),
+ &showprintlist);
+ add_show_from_set (
+ add_set_cmd ("symbol-filename", no_class, var_boolean,
+ (char *)&print_symbol_filename,
+ "Set printing of source filename and line number with <symbol>.",
+ &setprintlist),
+ &showprintlist);
+
+ examine_b_type = init_type (TYPE_CODE_INT, 1, 0, NULL, NULL);
+ examine_h_type = init_type (TYPE_CODE_INT, 2, 0, NULL, NULL);
+ examine_w_type = init_type (TYPE_CODE_INT, 4, 0, NULL, NULL);
+ examine_g_type = init_type (TYPE_CODE_INT, 8, 0, NULL, NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/putenv.c b/gnu/usr.bin/gdb/gdb/putenv.c
new file mode 100644
index 000000000000..e2ea3572d91d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/putenv.c
@@ -0,0 +1,111 @@
+/****************************************************************/
+/* */
+/* putenv(3) */
+/* */
+/* Change or add an environment entry */
+/* */
+/****************************************************************/
+/* origination 1987-Oct-7 T. Holm */
+/****************************************************************/
+
+/*
+Path: hoptoad!pacbell!ames!ll-xn!mit-eddie!uw-beaver!ssc-vax!uvicctr!tholm
+From: tholm@uvicctr.UUCP (Terrence W. Holm)
+Newsgroups: comp.os.minix
+Subject: putenv(3)
+Message-ID: <395@uvicctr.UUCP>
+Date: 5 May 88 06:40:52 GMT
+Organization: University of Victoria, Victoria B.C. Canada
+
+EFTH Minix report #2 - May 1988 - putenv(3)
+
+This is an implementation of putenv(3) that we
+wrote for Minix. Please consider this a public
+domain program.
+*/
+
+#include <stdio.h>
+
+#define PSIZE sizeof(char *)
+
+extern char **environ;
+
+char *strchr();
+char *malloc();
+
+/****************************************************************/
+/* */
+/* int */
+/* putenv( entry ) */
+/* */
+/* The "entry" should follow the form */
+/* "NAME=VALUE". This routine will search the */
+/* user environment for "NAME" and replace its */
+/* value with "VALUE". */
+/* */
+/* Note that "entry" is not copied, it is used */
+/* as the environment entry. This means that it */
+/* must not be unallocated or otherwise modifed */
+/* by the caller, unless it is replaced by a */
+/* subsequent putenv(). */
+/* */
+/* If the name is not found in the environment, */
+/* then a new vector of pointers is allocated, */
+/* "entry" is put at the end and the global */
+/* variable "environ" is updated. */
+/* */
+/* This function normally returns NULL, but -1 */
+/* is returned if it can not allocate enough */
+/* space using malloc(3), or "entry" does not */
+/* contain a '='. */
+/* */
+/****************************************************************/
+
+
+int
+putenv( entry )
+ char *entry;
+{
+ unsigned length;
+ unsigned size;
+ char *temp;
+ char **p;
+ char **new_environ;
+
+ /* Find the length of the "NAME=" */
+
+ temp = strchr(entry,'=');
+ if ( temp == 0 )
+ return( -1 );
+
+ length = (unsigned) (temp - entry + 1);
+
+
+ /* Scan through the environment looking for "NAME=" */
+
+ for ( p=environ; *p != 0 ; p++ )
+ if ( strncmp( entry, *p, length ) == 0 )
+ {
+ *p = entry;
+ return( 0 );
+ }
+
+
+ /* The name was not found, build a bigger environment */
+
+ size = p - environ;
+
+ new_environ = (char **) malloc( (size+2)*PSIZE );
+
+ if ( new_environ == (char **) NULL )
+ return( -1 );
+
+ memcpy ((char *) new_environ, (char *) environ, size*PSIZE );
+
+ new_environ[size] = entry;
+ new_environ[size+1] = NULL;
+
+ environ = new_environ;
+
+ return(0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/regex.c b/gnu/usr.bin/gdb/gdb/regex.c
new file mode 100644
index 000000000000..75bf4e9fc234
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/regex.c
@@ -0,0 +1,1725 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 1985, 1989 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To test, compile with -Dtest.
+ This Dtestable feature turns this into a self-contained program
+ which reads a pattern, describes how it compiles,
+ then reads a string and searches for it. */
+
+#ifdef emacs
+
+/* The `emacs' switch turns on certain special matching commands
+ that make sense only in emacs. */
+
+#include "config.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else /* not emacs */
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#endif
+#endif
+
+/*
+ * Define the syntax stuff, so we can do the \<...\> things.
+ */
+
+#ifndef Sword /* must be non-zero in some of the tests below... */
+#define Sword 1
+#endif
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#ifdef SYNTAX_TABLE
+
+char *re_syntax_table;
+
+#else
+
+static char re_syntax_table[256];
+
+static void
+init_syntax_once ()
+{
+ register int c;
+ static int done = 0;
+
+ if (done)
+ return;
+
+ memset (re_syntax_table, '\0', sizeof re_syntax_table);
+
+ for (c = 'a'; c <= 'z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = '0'; c <= '9'; c++)
+ re_syntax_table[c] = Sword;
+
+ done = 1;
+}
+
+#endif /* SYNTAX_TABLE */
+#endif /* not emacs */
+
+#include "regex.h"
+
+/* Number of failure points to allocate space for initially,
+ when matching. If this number is exceeded, more space is allocated,
+ so it is not a hard limit. */
+
+#ifndef NFAILURES
+#define NFAILURES 80
+#endif /* NFAILURES */
+
+/* width of a byte in bits */
+
+#define BYTEWIDTH 8
+
+#ifndef SIGN_EXTEND_CHAR
+#define SIGN_EXTEND_CHAR(x) (x)
+#endif
+
+static int obscure_syntax = 0;
+
+/* Specify the precise syntax of regexp for compilation.
+ This provides for compatibility for various utilities
+ which historically have different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit-mask containing the two bits
+ RE_NO_BK_PARENS and RE_NO_BK_VBAR. */
+
+int
+re_set_syntax (syntax)
+ int syntax;
+{
+ int ret;
+
+ ret = obscure_syntax;
+ obscure_syntax = syntax;
+ return ret;
+}
+
+/* re_compile_pattern takes a regular-expression string
+ and converts it into a buffer full of byte commands for matching.
+
+ PATTERN is the address of the pattern string
+ SIZE is the length of it.
+ BUFP is a struct re_pattern_buffer * which points to the info
+ on where to store the byte commands.
+ This structure contains a char * which points to the
+ actual space, which should have been obtained with malloc.
+ re_compile_pattern may use realloc to grow the buffer space.
+
+ The number of bytes of commands can be found out by looking in
+ the struct re_pattern_buffer that bufp pointed to,
+ after re_compile_pattern returns.
+*/
+
+#define PATPUSH(ch) (*b++ = (char) (ch))
+
+#define PATFETCH(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; \
+ if (translate) c = translate[c]; }
+
+#define PATFETCH_RAW(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; }
+
+#define PATUNFETCH p--
+
+#define EXTEND_BUFFER \
+ { char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == (1<<16)) goto too_big; \
+ bufp->allocated *= 2; \
+ if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \
+ if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
+ goto memory_exhausted; \
+ c = bufp->buffer - old_buffer; \
+ b += c; \
+ if (fixup_jump) \
+ fixup_jump += c; \
+ if (laststart) \
+ laststart += c; \
+ begalt += c; \
+ if (pending_exact) \
+ pending_exact += c; \
+ }
+
+static void store_jump (), insert_jump ();
+
+char *
+re_compile_pattern (pattern, size, bufp)
+ char *pattern;
+ int size;
+ struct re_pattern_buffer *bufp;
+{
+ register char *b = bufp->buffer;
+ register char *p = pattern;
+ char *pend = pattern + size;
+ register unsigned c, c1;
+ char *p1;
+ unsigned char *translate = (unsigned char *) bufp->translate;
+
+ /* address of the count-byte of the most recently inserted "exactn" command.
+ This makes it possible to tell whether a new exact-match character
+ can be added to that command or requires a new "exactn" command. */
+
+ char *pending_exact = 0;
+
+ /* address of the place where a forward-jump should go
+ to the end of the containing expression.
+ Each alternative of an "or", except the last, ends with a forward-jump
+ of this sort. */
+
+ char *fixup_jump = 0;
+
+ /* address of start of the most recently finished expression.
+ This tells postfix * where to find the start of its operand. */
+
+ char *laststart = 0;
+
+ /* In processing a repeat, 1 means zero matches is allowed */
+
+ char zero_times_ok;
+
+ /* In processing a repeat, 1 means many matches is allowed */
+
+ char many_times_ok;
+
+ /* address of beginning of regexp, or inside of last \( */
+
+ char *begalt = b;
+
+ /* Stack of information saved by \( and restored by \).
+ Four stack elements are pushed by each \(:
+ First, the value of b.
+ Second, the value of fixup_jump.
+ Third, the value of regnum.
+ Fourth, the value of begalt. */
+
+ int stackb[40];
+ int *stackp = stackb;
+ int *stacke = stackb + 40;
+ int *stackt;
+
+ /* Counts \('s as they are encountered. Remembered for the matching \),
+ where it becomes the "register number" to put in the stop_memory command */
+
+ int regnum = 1;
+
+ bufp->fastmap_accurate = 0;
+
+#ifndef emacs
+#ifndef SYNTAX_TABLE
+ /*
+ * Initialize the syntax table.
+ */
+ init_syntax_once();
+#endif
+#endif
+
+ if (bufp->allocated == 0)
+ {
+ bufp->allocated = 28;
+ if (bufp->buffer)
+ /* EXTEND_BUFFER loses when bufp->allocated is 0 */
+ bufp->buffer = (char *) realloc (bufp->buffer, 28);
+ else
+ /* Caller did not allocate a buffer. Do it for him */
+ bufp->buffer = (char *) malloc (28);
+ if (!bufp->buffer) goto memory_exhausted;
+ begalt = b = bufp->buffer;
+ }
+
+ while (p != pend)
+ {
+ if (b - bufp->buffer > bufp->allocated - 10)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '$':
+ if (obscure_syntax & RE_TIGHT_VBAR)
+ {
+ if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
+ goto normal_char;
+ /* Make operand of last vbar end before this `$'. */
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = 0;
+ PATPUSH (endline);
+ break;
+ }
+
+ /* $ means succeed if at end of line, but only in special contexts.
+ If randomly in the middle of a pattern, it is a normal character. */
+ if (p == pend || *p == '\n'
+ || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
+ || (obscure_syntax & RE_NO_BK_PARENS
+ ? *p == ')'
+ : *p == '\\' && p[1] == ')')
+ || (obscure_syntax & RE_NO_BK_VBAR
+ ? *p == '|'
+ : *p == '\\' && p[1] == '|'))
+ {
+ PATPUSH (endline);
+ break;
+ }
+ goto normal_char;
+
+ case '^':
+ /* ^ means succeed if at beg of line, but only if no preceding pattern. */
+
+ if (laststart && p[-2] != '\n'
+ && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ if (obscure_syntax & RE_TIGHT_VBAR)
+ {
+ if (p != pattern + 1
+ && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ PATPUSH (begline);
+ begalt = b;
+ }
+ else
+ PATPUSH (begline);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern, char not special. */
+ if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ /* If there is a sequence of repetition chars,
+ collapse it down to equivalent to just one. */
+ zero_times_ok = 0;
+ many_times_ok = 0;
+ while (1)
+ {
+ zero_times_ok |= c != '+';
+ many_times_ok |= c != '?';
+ if (p == pend)
+ break;
+ PATFETCH (c);
+ if (c == '*')
+ ;
+ else if (!(obscure_syntax & RE_BK_PLUS_QM)
+ && (c == '+' || c == '?'))
+ ;
+ else if ((obscure_syntax & RE_BK_PLUS_QM)
+ && c == '\\')
+ {
+ int c1;
+ PATFETCH (c1);
+ if (!(c1 == '+' || c1 == '?'))
+ {
+ PATUNFETCH;
+ PATUNFETCH;
+ break;
+ }
+ c = c1;
+ }
+ else
+ {
+ PATUNFETCH;
+ break;
+ }
+ }
+
+ /* Star, etc. applied to an empty pattern is equivalent
+ to an empty pattern. */
+ if (!laststart)
+ break;
+
+ /* Now we know whether 0 matches is allowed,
+ and whether 2 or more matches is allowed. */
+ if (many_times_ok)
+ {
+ /* If more than one repetition is allowed,
+ put in a backward jump at the end. */
+ store_jump (b, maybe_finalize_jump, laststart - 3);
+ b += 3;
+ }
+ insert_jump (on_failure_jump, laststart, b + 3, b);
+ pending_exact = 0;
+ b += 3;
+ if (!zero_times_ok)
+ {
+ /* At least one repetition required: insert before the loop
+ a skip over the initial on-failure-jump instruction */
+ insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
+ b += 3;
+ }
+ break;
+
+ case '.':
+ laststart = b;
+ PATPUSH (anychar);
+ break;
+
+ case '[':
+ while (b - bufp->buffer
+ > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ laststart = b;
+ if (*p == '^')
+ PATPUSH (charset_not), p++;
+ else
+ PATPUSH (charset);
+ p1 = p;
+
+ PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Clear the whole map */
+ memset (b, '\0', (1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Read in characters and ranges, setting map bits */
+ while (1)
+ {
+ PATFETCH (c);
+ if (c == ']' && p != p1 + 1) break;
+ if (*p == '-' && p[1] != ']')
+ {
+ PATFETCH (c1);
+ PATFETCH (c1);
+ while (c <= c1)
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
+ }
+ else
+ {
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
+ }
+ }
+ /* Discard any bitmap bytes that are all 0 at the end of the map.
+ Decrement the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+ break;
+
+ case '(':
+ if (! (obscure_syntax & RE_NO_BK_PARENS))
+ goto normal_char;
+ else
+ goto handle_open;
+
+ case ')':
+ if (! (obscure_syntax & RE_NO_BK_PARENS))
+ goto normal_char;
+ else
+ goto handle_close;
+
+ case '\n':
+ if (! (obscure_syntax & RE_NEWLINE_OR))
+ goto normal_char;
+ else
+ goto handle_bar;
+
+ case '|':
+ if (! (obscure_syntax & RE_NO_BK_VBAR))
+ goto normal_char;
+ else
+ goto handle_bar;
+
+ case '\\':
+ if (p == pend) goto invalid_pattern;
+ PATFETCH_RAW (c);
+ switch (c)
+ {
+ case '(':
+ if (obscure_syntax & RE_NO_BK_PARENS)
+ goto normal_backsl;
+ handle_open:
+ if (stackp == stacke) goto nesting_too_deep;
+ if (regnum < RE_NREGS)
+ {
+ PATPUSH (start_memory);
+ PATPUSH (regnum);
+ }
+ *stackp++ = b - bufp->buffer;
+ *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
+ *stackp++ = regnum++;
+ *stackp++ = begalt - bufp->buffer;
+ fixup_jump = 0;
+ laststart = 0;
+ begalt = b;
+ break;
+
+ case ')':
+ if (obscure_syntax & RE_NO_BK_PARENS)
+ goto normal_backsl;
+ handle_close:
+ if (stackp == stackb) goto unmatched_close;
+ begalt = *--stackp + bufp->buffer;
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ if (stackp[-1] < RE_NREGS)
+ {
+ PATPUSH (stop_memory);
+ PATPUSH (stackp[-1]);
+ }
+ stackp -= 2;
+ fixup_jump = 0;
+ if (*stackp)
+ fixup_jump = *stackp + bufp->buffer - 1;
+ laststart = *--stackp + bufp->buffer;
+ break;
+
+ case '|':
+ if (obscure_syntax & RE_NO_BK_VBAR)
+ goto normal_backsl;
+ handle_bar:
+ insert_jump (on_failure_jump, begalt, b + 6, b);
+ pending_exact = 0;
+ b += 3;
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = b;
+ b += 3;
+ laststart = 0;
+ begalt = b;
+ break;
+
+#ifdef emacs
+ case '=':
+ PATPUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATPUSH (syntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATPUSH (notsyntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+ case 'w':
+ laststart = b;
+ PATPUSH (wordchar);
+ break;
+
+ case 'W':
+ laststart = b;
+ PATPUSH (notwordchar);
+ break;
+
+ case '<':
+ PATPUSH (wordbeg);
+ break;
+
+ case '>':
+ PATPUSH (wordend);
+ break;
+
+ case 'b':
+ PATPUSH (wordbound);
+ break;
+
+ case 'B':
+ PATPUSH (notwordbound);
+ break;
+
+ case '`':
+ PATPUSH (begbuf);
+ break;
+
+ case '\'':
+ PATPUSH (endbuf);
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c - '0';
+ if (c1 >= regnum)
+ goto normal_char;
+ for (stackt = stackp - 2; stackt > stackb; stackt -= 4)
+ if (*stackt == c1)
+ goto normal_char;
+ laststart = b;
+ PATPUSH (duplicate);
+ PATPUSH (c1);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+
+ default:
+ normal_backsl:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ if (translate) c = translate[c];
+ goto normal_char;
+ }
+ break;
+
+ default:
+ normal_char:
+ if (!pending_exact || pending_exact + *pending_exact + 1 != b
+ || *pending_exact == 0177 || *p == '*' || *p == '^'
+ || ((obscure_syntax & RE_BK_PLUS_QM)
+ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ : (*p == '+' || *p == '?')))
+ {
+ laststart = b;
+ PATPUSH (exactn);
+ pending_exact = b;
+ PATPUSH (0);
+ }
+ PATPUSH (c);
+ (*pending_exact)++;
+ }
+ }
+
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+
+ if (stackp != stackb) goto unmatched_open;
+
+ bufp->used = b - bufp->buffer;
+ return 0;
+
+ invalid_pattern:
+ return "Invalid regular expression";
+
+ unmatched_open:
+ return "Unmatched \\(";
+
+ unmatched_close:
+ return "Unmatched \\)";
+
+ end_of_pattern:
+ return "Premature end of regular expression";
+
+ nesting_too_deep:
+ return "Nesting too deep";
+
+ too_big:
+ return "Regular expression too big";
+
+ memory_exhausted:
+ return "Memory exhausted";
+}
+
+/* Store where `from' points a jump operation to jump to where `to' points.
+ `opcode' is the opcode to store. */
+
+static void
+store_jump (from, opcode, to)
+ char *from, *to;
+ char opcode;
+{
+ from[0] = opcode;
+ from[1] = (to - (from + 3)) & 0377;
+ from[2] = (to - (from + 3)) >> 8;
+}
+
+/* Open up space at char FROM, and insert there a jump to TO.
+ CURRENT_END gives te end of the storage no in use,
+ so we know how much data to copy up.
+ OP is the opcode of the jump to insert.
+
+ If you call this function, you must zero out pending_exact. */
+
+static void
+insert_jump (op, from, to, current_end)
+ char op;
+ char *from, *to, *current_end;
+{
+ register char *pto = current_end + 3;
+ register char *pfrom = current_end;
+ while (pfrom != from)
+ *--pto = *--pfrom;
+ store_jump (from, op, to);
+}
+
+/* Given a pattern, compute a fastmap from it.
+ The fastmap records which of the (1 << BYTEWIDTH) possible characters
+ can start a string that matches the pattern.
+ This fastmap is used by re_search to skip quickly over totally implausible text.
+
+ The caller must supply the address of a (1 << BYTEWIDTH)-byte data area
+ as bufp->fastmap.
+ The other components of bufp describe the pattern to be used. */
+
+void
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *pattern = (unsigned char *) bufp->buffer;
+ int size = bufp->used;
+ register char *fastmap = bufp->fastmap;
+ register unsigned char *p = pattern;
+ register unsigned char *pend = pattern + size;
+ register int j;
+ unsigned char *translate = (unsigned char *) bufp->translate;
+
+ unsigned char *stackb[NFAILURES];
+ unsigned char **stackp = stackb;
+
+ memset (fastmap, '\0', (1 << BYTEWIDTH));
+ bufp->fastmap_accurate = 1;
+ bufp->can_be_null = 0;
+
+ while (p)
+ {
+ if (p == pend)
+ {
+ bufp->can_be_null = 1;
+ break;
+ }
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((enum regexpcode) *p++))
+#else
+ switch ((enum regexpcode) *p++)
+#endif
+ {
+ case exactn:
+ if (translate)
+ fastmap[translate[p[1]]] = 1;
+ else
+ fastmap[p[1]] = 1;
+ break;
+
+ case begline:
+ case before_dot:
+ case at_dot:
+ case after_dot:
+ case begbuf:
+ case endbuf:
+ case wordbound:
+ case notwordbound:
+ case wordbeg:
+ case wordend:
+ continue;
+
+ case endline:
+ if (translate)
+ fastmap[translate['\n']] = 1;
+ else
+ fastmap['\n'] = 1;
+ if (bufp->can_be_null != 1)
+ bufp->can_be_null = 2;
+ break;
+
+ case finalize_jump:
+ case maybe_finalize_jump:
+ case jump:
+ case dummy_failure_jump:
+ bufp->can_be_null = 1;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ if (j > 0)
+ continue;
+ /* Jump backward reached implies we just went through
+ the body of a loop and matched nothing.
+ Opcode jumped to should be an on_failure_jump.
+ Just treat it like an ordinary jump.
+ For a * loop, it has pushed its failure point already;
+ if so, discard that as redundant. */
+ if ((enum regexpcode) *p != on_failure_jump)
+ continue;
+ p++;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ if (stackp != stackb && *stackp == p)
+ stackp--;
+ continue;
+
+ case on_failure_jump:
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *++stackp = p + j;
+ continue;
+
+ case start_memory:
+ case stop_memory:
+ p++;
+ continue;
+
+ case duplicate:
+ bufp->can_be_null = 1;
+ fastmap['\n'] = 1;
+ case anychar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (j != '\n')
+ fastmap[j] = 1;
+ if (bufp->can_be_null)
+ return;
+ /* Don't return; check the alternative paths
+ so we can set can_be_null if appropriate. */
+ break;
+
+ case wordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == Sword)
+ fastmap[j] = 1;
+ break;
+
+ case notwordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != Sword)
+ fastmap[j] = 1;
+ break;
+
+#ifdef emacs
+ case syntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+ case notsyntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+#endif /* emacs */
+
+ case charset:
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ {
+ if (translate)
+ fastmap[translate[j]] = 1;
+ else
+ fastmap[j] = 1;
+ }
+ break;
+
+ case charset_not:
+ /* Chars beyond end of map must be allowed */
+ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ if (translate)
+ fastmap[translate[j]] = 1;
+ else
+ fastmap[j] = 1;
+
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ {
+ if (translate)
+ fastmap[translate[j]] = 1;
+ else
+ fastmap[j] = 1;
+ }
+ break;
+ }
+
+ /* Get here means we have successfully found the possible starting characters
+ of one path of the pattern. We need not follow this path any farther.
+ Instead, look at the next alternative remembered in the stack. */
+ if (stackp != stackb)
+ p = *stackp--;
+ else
+ break;
+ }
+}
+
+/* Like re_search_2, below, but only one string is specified. */
+
+int
+re_search (pbufp, string, size, startpos, range, regs)
+ struct re_pattern_buffer *pbufp;
+ char *string;
+ int size, startpos, range;
+ struct re_registers *regs;
+{
+ return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size);
+}
+
+/* Like re_match_2 but tries first a match starting at index STARTPOS,
+ then at STARTPOS + 1, and so on.
+ RANGE is the number of places to try before giving up.
+ If RANGE is negative, the starting positions tried are
+ STARTPOS, STARTPOS - 1, etc.
+ It is up to the caller to make sure that range is not so large
+ as to take the starting position outside of the input strings.
+
+The value returned is the position at which the match was found,
+ or -1 if no match was found,
+ or -2 if error (such as failure stack overflow). */
+
+int
+re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop)
+ struct re_pattern_buffer *pbufp;
+ char *string1, *string2;
+ int size1, size2;
+ int startpos;
+ register int range;
+ struct re_registers *regs;
+ int mstop;
+{
+ register char *fastmap = pbufp->fastmap;
+ register unsigned char *translate = (unsigned char *) pbufp->translate;
+ int total = size1 + size2;
+ int val;
+
+ /* Update the fastmap now if not correct already */
+ if (fastmap && !pbufp->fastmap_accurate)
+ re_compile_fastmap (pbufp);
+
+ /* Don't waste time in a long search for a pattern
+ that says it is anchored. */
+ if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
+ && range > 0)
+ {
+ if (startpos > 0)
+ return -1;
+ else
+ range = 1;
+ }
+
+ while (1)
+ {
+ /* If a fastmap is supplied, skip quickly over characters
+ that cannot possibly be the start of a match.
+ Note, however, that if the pattern can possibly match
+ the null string, we must test it at each starting point
+ so that we take the first null string we get. */
+
+ if (fastmap && startpos < total && pbufp->can_be_null != 1)
+ {
+ if (range > 0)
+ {
+ register int lim = 0;
+ register unsigned char *p;
+ int irange = range;
+ if (startpos < size1 && startpos + range >= size1)
+ lim = range - (size1 - startpos);
+
+ p = ((unsigned char *)
+ &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
+
+ if (translate)
+ {
+ while (range > lim && !fastmap[translate[*p++]])
+ range--;
+ }
+ else
+ {
+ while (range > lim && !fastmap[*p++])
+ range--;
+ }
+ startpos += irange - range;
+ }
+ else
+ {
+ register unsigned char c;
+ if (startpos >= size1)
+ c = string2[startpos - size1];
+ else
+ c = string1[startpos];
+ c &= 0xff;
+ if (translate ? !fastmap[translate[c]] : !fastmap[c])
+ goto advance;
+ }
+ }
+
+ if (range >= 0 && startpos == total
+ && fastmap && pbufp->can_be_null == 0)
+ return -1;
+
+ val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop);
+ if (0 <= val)
+ {
+ if (val == -2)
+ return -2;
+ return startpos;
+ }
+
+#ifdef C_ALLOCA
+ alloca (0);
+#endif /* C_ALLOCA */
+
+ advance:
+ if (!range) break;
+ if (range > 0) range--, startpos++; else range++, startpos--;
+ }
+ return -1;
+}
+
+#ifndef emacs /* emacs never uses this */
+int
+re_match (pbufp, string, size, pos, regs)
+ struct re_pattern_buffer *pbufp;
+ char *string;
+ int size, pos;
+ struct re_registers *regs;
+{
+ return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size);
+}
+#endif /* emacs */
+
+/* Maximum size of failure stack. Beyond this, overflow is an error. */
+
+int re_max_failures = 2000;
+
+static int memcmp_translate();
+/* Match the pattern described by PBUFP
+ against data which is the virtual concatenation of STRING1 and STRING2.
+ SIZE1 and SIZE2 are the sizes of the two data strings.
+ Start the match at position POS.
+ Do not consider matching past the position MSTOP.
+
+ If pbufp->fastmap is nonzero, then it had better be up to date.
+
+ The reason that the data to match are specified as two components
+ which are to be regarded as concatenated
+ is so this function can be used directly on the contents of an Emacs buffer.
+
+ -1 is returned if there is no match. -2 is returned if there is
+ an error (such as match stack overflow). Otherwise the value is the length
+ of the substring which was matched. */
+
+int
+re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop)
+ struct re_pattern_buffer *pbufp;
+ unsigned char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int mstop;
+{
+ register unsigned char *p = (unsigned char *) pbufp->buffer;
+ register unsigned char *pend = p + pbufp->used;
+ /* End of first string */
+ unsigned char *end1;
+ /* End of second string */
+ unsigned char *end2;
+ /* Pointer just past last char to consider matching */
+ unsigned char *end_match_1, *end_match_2;
+ register unsigned char *d, *dend;
+ register int mcnt;
+ unsigned char *translate = (unsigned char *) pbufp->translate;
+
+ /* Failure point stack. Each place that can handle a failure further down the line
+ pushes a failure point on this stack. It consists of two char *'s.
+ The first one pushed is where to resume scanning the pattern;
+ the second pushed is where to resume scanning the strings.
+ If the latter is zero, the failure point is a "dummy".
+ If a failure happens and the innermost failure point is dormant,
+ it discards that failure point and tries the next one. */
+
+ unsigned char *initial_stack[2 * NFAILURES];
+ unsigned char **stackb = initial_stack;
+ unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
+
+ /* Information on the "contents" of registers.
+ These are pointers into the input strings; they record
+ just what was matched (on this attempt) by some part of the pattern.
+ The start_memory command stores the start of a register's contents
+ and the stop_memory command stores the end.
+
+ At that point, regstart[regnum] points to the first character in the register,
+ regend[regnum] points to the first character beyond the end of the register,
+ regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
+ and regend_seg1[regnum] is true iff regend[regnum] points into string1. */
+
+ unsigned char *regstart[RE_NREGS];
+ unsigned char *regend[RE_NREGS];
+ unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
+
+ /* Set up pointers to ends of strings.
+ Don't allow the second string to be empty unless both are empty. */
+ if (!size2)
+ {
+ string2 = string1;
+ size2 = size1;
+ string1 = 0;
+ size1 = 0;
+ }
+ end1 = string1 + size1;
+ end2 = string2 + size2;
+
+ /* Compute where to stop matching, within the two strings */
+ if (mstop <= size1)
+ {
+ end_match_1 = string1 + mstop;
+ end_match_2 = string2;
+ }
+ else
+ {
+ end_match_1 = end1;
+ end_match_2 = string2 + mstop - size1;
+ }
+
+ /* Initialize \) text positions to -1
+ to mark ones that no \( or \) has been seen for. */
+
+ for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
+ regend[mcnt] = (unsigned char *) -1;
+
+ /* `p' scans through the pattern as `d' scans through the data.
+ `dend' is the end of the input string that `d' points within.
+ `d' is advanced into the following input string whenever necessary,
+ but this happens before fetching;
+ therefore, at the beginning of the loop,
+ `d' can be pointing at the end of a string,
+ but it cannot equal string2. */
+
+ if (pos <= size1)
+ d = string1 + pos, dend = end_match_1;
+ else
+ d = string2 + pos - size1, dend = end_match_2;
+
+/* Write PREFETCH; just before fetching a character with *d. */
+#define PREFETCH \
+ while (d == dend) \
+ { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \
+ d = string2; /* end of string1 => advance to string2. */ \
+ dend = end_match_2; }
+
+ /* This loop loops over pattern commands.
+ It exits by returning from the function if match is complete,
+ or it drops through if match fails at this starting point in the input data. */
+
+ while (1)
+ {
+ if (p == pend)
+ /* End of pattern means we have succeeded! */
+ {
+ /* If caller wants register contents data back, convert it to indices */
+ if (regs)
+ {
+ regs->start[0] = pos;
+ if (dend == end_match_1)
+ regs->end[0] = d - string1;
+ else
+ regs->end[0] = d - string2 + size1;
+ for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ {
+ if (regend[mcnt] == (unsigned char *) -1)
+ {
+ regs->start[mcnt] = -1;
+ regs->end[mcnt] = -1;
+ continue;
+ }
+ if (regstart_seg1[mcnt])
+ regs->start[mcnt] = regstart[mcnt] - string1;
+ else
+ regs->start[mcnt] = regstart[mcnt] - string2 + size1;
+ if (regend_seg1[mcnt])
+ regs->end[mcnt] = regend[mcnt] - string1;
+ else
+ regs->end[mcnt] = regend[mcnt] - string2 + size1;
+ }
+ }
+ if (dend == end_match_1)
+ return (d - string1 - pos);
+ else
+ return d - string2 + size1 - pos;
+ }
+
+ /* Otherwise match next pattern command */
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((enum regexpcode) *p++))
+#else
+ switch ((enum regexpcode) *p++)
+#endif
+ {
+
+ /* \( is represented by a start_memory, \) by a stop_memory.
+ Both of those commands contain a "register number" argument.
+ The text matched within the \( and \) is recorded under that number.
+ Then, \<digit> turns into a `duplicate' command which
+ is followed by the numeric value of <digit> as the register number. */
+
+ case start_memory:
+ regstart[*p] = d;
+ regstart_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case stop_memory:
+ regend[*p] = d;
+ regend_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case duplicate:
+ {
+ int regno = *p++; /* Get which register to match against */
+ register unsigned char *d2, *dend2;
+
+ d2 = regstart[regno];
+ dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
+ ? regend[regno] : end_match_1);
+ while (1)
+ {
+ /* Advance to next segment in register contents, if necessary */
+ while (d2 == dend2)
+ {
+ if (dend2 == end_match_2) break;
+ if (dend2 == regend[regno]) break;
+ d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */
+ }
+ /* At end of register contents => success */
+ if (d2 == dend2) break;
+
+ /* Advance to next segment in data being matched, if necessary */
+ PREFETCH;
+
+ /* mcnt gets # consecutive chars to compare */
+ mcnt = dend - d;
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+ /* Compare that many; failure if mismatch, else skip them. */
+ if (translate ? memcmp_translate (d, d2, mcnt, translate) : memcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+ }
+ }
+ break;
+
+ case anychar:
+ /* fetch a data character */
+ PREFETCH;
+ /* Match anything but a newline. */
+ if ((translate ? translate[*d++] : *d++) == '\n')
+ goto fail;
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ /* Nonzero for charset_not */
+ int not = 0;
+ register int c;
+ if (*(p - 1) == (unsigned char) charset_not)
+ not = 1;
+
+ /* fetch a data character */
+ PREFETCH;
+
+ if (translate)
+ c = translate [*d];
+ else
+ c = *d;
+
+ if (c < *p * BYTEWIDTH
+ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) goto fail;
+ d++;
+ break;
+ }
+
+ case begline:
+ if (d == string1 || d[-1] == '\n')
+ break;
+ goto fail;
+
+ case endline:
+ if (d == end2
+ || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
+ break;
+ goto fail;
+
+ /* "or" constructs ("|") are handled by starting each alternative
+ with an on_failure_jump that points to the start of the next alternative.
+ Each alternative except the last ends with a jump to the joining point.
+ (Actually, each jump except for the last one really jumps
+ to the following jump, because tensioning the jumps is a hassle.) */
+
+ /* The start of a stupid repeat has an on_failure_jump that points
+ past the end of the repeat text.
+ This makes a failure point so that, on failure to match a repetition,
+ matching restarts past as many repetitions have been found
+ with no way to fail and look for another one. */
+
+ /* A smart repeat is similar but loops back to the on_failure_jump
+ so that each repetition makes another failure point. */
+
+ case on_failure_jump:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx;
+ if (stacke - stackb > re_max_failures * 2)
+ return -2;
+ stackx = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *stackp++ = mcnt + p;
+ *stackp++ = d;
+ break;
+
+ /* The end of a smart repeat has an maybe_finalize_jump back.
+ Change it either to a finalize_jump or an ordinary jump. */
+
+ case maybe_finalize_jump:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ {
+ register unsigned char *p2 = p;
+ /* Compare what follows with the begining of the repeat.
+ If we can establish that there is nothing that they would
+ both match, we can change to finalize_jump */
+ while (p2 != pend
+ && (*p2 == (unsigned char) stop_memory
+ || *p2 == (unsigned char) start_memory))
+ p2++;
+ if (p2 == pend)
+ p[-3] = (unsigned char) finalize_jump;
+ else if (*p2 == (unsigned char) exactn
+ || *p2 == (unsigned char) endline)
+ {
+ register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
+ register unsigned char *p1 = p + mcnt;
+ /* p1[0] ... p1[2] are an on_failure_jump.
+ Examine what follows that */
+ if (p1[3] == (unsigned char) exactn && p1[5] != c)
+ p[-3] = (unsigned char) finalize_jump;
+ else if (p1[3] == (unsigned char) charset
+ || p1[3] == (unsigned char) charset_not)
+ {
+ int not = p1[3] == (unsigned char) charset_not;
+ if (c < p1[4] * BYTEWIDTH
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+ /* not is 1 if c would match */
+ /* That means it is not safe to finalize */
+ if (!not)
+ p[-3] = (unsigned char) finalize_jump;
+ }
+ }
+ }
+ p -= 2;
+ if (p[-1] != (unsigned char) finalize_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ goto nofinalize;
+ }
+
+ /* The end of a stupid repeat has a finalize-jump
+ back to the start, where another failure point will be made
+ which will point after all the repetitions found so far. */
+
+ case finalize_jump:
+ stackp -= 2;
+
+ case jump:
+ nofinalize:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += mcnt + 1; /* The 1 compensates for missing ++ above */
+ break;
+
+ case dummy_failure_jump:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx
+ = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ *stackp++ = 0;
+ *stackp++ = 0;
+ goto nofinalize;
+
+ case wordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ break;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ break;
+ goto fail;
+
+ case notwordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ goto fail;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ goto fail;
+ break;
+
+ case wordbeg:
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
+ goto fail;
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ break;
+ goto fail;
+
+ case wordend:
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ goto fail;
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ <= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ == point)
+ goto fail;
+ break;
+
+ case after_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ >= point)
+ goto fail;
+ break;
+
+ case wordchar:
+ mcnt = (int) Sword;
+ goto matchsyntax;
+
+ case syntaxspec:
+ mcnt = *p++;
+ matchsyntax:
+ PREFETCH;
+ if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
+ break;
+
+ case notwordchar:
+ mcnt = (int) Sword;
+ goto matchnotsyntax;
+
+ case notsyntaxspec:
+ mcnt = *p++;
+ matchnotsyntax:
+ PREFETCH;
+ if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
+ break;
+#else
+ case wordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) == 0) goto fail;
+ break;
+
+ case notwordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) != 0) goto fail;
+ break;
+#endif /* not emacs */
+
+ case begbuf:
+ if (d == string1) /* Note, d cannot equal string2 */
+ break; /* unless string1 == string2. */
+ goto fail;
+
+ case endbuf:
+ if (d == end2 || (d == end1 && size2 == 0))
+ break;
+ goto fail;
+
+ case exactn:
+ /* Match the next few pattern characters exactly.
+ mcnt is how many characters to match. */
+ mcnt = *p++;
+ if (translate)
+ {
+ do
+ {
+ PREFETCH;
+ if (translate[*d++] != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH;
+ if (*d++ != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ break;
+ }
+ continue; /* Successfully matched one pattern command; keep matching */
+
+ /* Jump here if any matching operation fails. */
+ fail:
+ if (stackp != stackb)
+ /* A restart point is known. Restart there and pop it. */
+ {
+ if (!stackp[-2])
+ { /* If innermost failure point is dormant, flush it and keep looking */
+ stackp -= 2;
+ goto fail;
+ }
+ d = *--stackp;
+ p = *--stackp;
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else break; /* Matching at this starting point really fails! */
+ }
+ return -1; /* Failure to match */
+}
+
+static int
+memcmp_translate (s1, s2, len, translate)
+ unsigned char *s1, *s2;
+ register int len;
+ unsigned char *translate;
+{
+ register unsigned char *p1 = s1, *p2 = s2;
+ while (len)
+ {
+ if (translate [*p1++] != translate [*p2++]) return 1;
+ len--;
+ }
+ return 0;
+}
+
+/* Entry points compatible with bsd4.2 regex library */
+
+#ifndef emacs
+
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+ char *s;
+{
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return "No previous regular expression";
+ return 0;
+ }
+
+ if (!re_comp_buf.buffer)
+ {
+ if (!(re_comp_buf.buffer = (char *) malloc (200)))
+ return "Memory exhausted";
+ re_comp_buf.allocated = 200;
+ if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
+ return "Memory exhausted";
+ }
+ return re_compile_pattern (s, strlen (s), &re_comp_buf);
+}
+
+int
+re_exec (s)
+ char *s;
+{
+ int len = strlen (s);
+ return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0);
+}
+
+#endif /* emacs */
+
+#ifdef test
+
+#include <stdio.h>
+
+/* Indexed by a character, gives the upper case equivalent of the character */
+
+static char upcase[0400] =
+ { 000, 001, 002, 003, 004, 005, 006, 007,
+ 010, 011, 012, 013, 014, 015, 016, 017,
+ 020, 021, 022, 023, 024, 025, 026, 027,
+ 030, 031, 032, 033, 034, 035, 036, 037,
+ 040, 041, 042, 043, 044, 045, 046, 047,
+ 050, 051, 052, 053, 054, 055, 056, 057,
+ 060, 061, 062, 063, 064, 065, 066, 067,
+ 070, 071, 072, 073, 074, 075, 076, 077,
+ 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
+ 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
+ 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
+ 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
+ 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
+ 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
+ 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
+ 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
+ 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+ 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+ 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+ 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
+ };
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char pat[80];
+ struct re_pattern_buffer buf;
+ int i;
+ char c;
+ char fastmap[(1 << BYTEWIDTH)];
+
+ /* Allow a command argument to specify the style of syntax. */
+ if (argc > 1)
+ obscure_syntax = atoi (argv[1]);
+
+ buf.allocated = 40;
+ buf.buffer = (char *) malloc (buf.allocated);
+ buf.fastmap = fastmap;
+ buf.translate = upcase;
+
+ while (1)
+ {
+ gets (pat);
+
+ if (*pat)
+ {
+ re_compile_pattern (pat, strlen(pat), &buf);
+
+ for (i = 0; i < buf.used; i++)
+ printchar (buf.buffer[i]);
+
+ putchar ('\n');
+
+ printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
+
+ re_compile_fastmap (&buf);
+ printf ("Allowed by fastmap: ");
+ for (i = 0; i < (1 << BYTEWIDTH); i++)
+ if (fastmap[i]) printchar (i);
+ putchar ('\n');
+ }
+
+ gets (pat); /* Now read the string to match against */
+
+ i = re_match (&buf, pat, strlen (pat), 0, 0);
+ printf ("Match value %d.\n", i);
+ }
+}
+
+#ifdef NOTDEF
+print_buf (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ int i;
+
+ printf ("buf is :\n----------------\n");
+ for (i = 0; i < bufp->used; i++)
+ printchar (bufp->buffer[i]);
+
+ printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
+
+ printf ("Allowed by fastmap: ");
+ for (i = 0; i < (1 << BYTEWIDTH); i++)
+ if (bufp->fastmap[i])
+ printchar (i);
+ printf ("\nAllowed by translate: ");
+ if (bufp->translate)
+ for (i = 0; i < (1 << BYTEWIDTH); i++)
+ if (bufp->translate[i])
+ printchar (i);
+ printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
+ printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
+}
+#endif
+
+printchar (c)
+ char c;
+{
+ if (c < 041 || c >= 0177)
+ {
+ putchar ('\\');
+ putchar (((c >> 6) & 3) + '0');
+ putchar (((c >> 3) & 7) + '0');
+ putchar ((c & 7) + '0');
+ }
+ else
+ putchar (c);
+}
+
+error (string)
+ char *string;
+{
+ puts (string);
+ exit (1);
+}
+
+#endif /* test */
diff --git a/gnu/usr.bin/gdb/gdb/regex.h b/gnu/usr.bin/gdb/gdb/regex.h
new file mode 100644
index 000000000000..6348c3eb6e45
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/regex.h
@@ -0,0 +1,179 @@
+/* Definitions for data structures callers pass the regex library.
+ Copyright (C) 1985, 1989 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Define number of parens for which we record the beginnings and ends.
+ This affects how much space the `struct re_registers' type takes up. */
+#ifndef RE_NREGS
+#define RE_NREGS 10
+#endif
+
+/* These bits are used in the obscure_syntax variable to choose among
+ alternative regexp syntaxes. */
+
+/* 1 means plain parentheses serve as grouping, and backslash
+ parentheses are needed for literal searching.
+ 0 means backslash-parentheses are grouping, and plain parentheses
+ are for literal searching. */
+#define RE_NO_BK_PARENS 1
+
+/* 1 means plain | serves as the "or"-operator, and \| is a literal.
+ 0 means \| serves as the "or"-operator, and | is a literal. */
+#define RE_NO_BK_VBAR 2
+
+/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
+ 1 means \+, \? are operators and plain +, ? are literals. */
+#define RE_BK_PLUS_QM 4
+
+/* 1 means | binds tighter than ^ or $.
+ 0 means the contrary. */
+#define RE_TIGHT_VBAR 8
+
+/* 1 means treat \n as an _OR operator
+ 0 means treat it as a normal character */
+#define RE_NEWLINE_OR 16
+
+/* 0 means that a special characters (such as *, ^, and $) always have
+ their special meaning regardless of the surrounding context.
+ 1 means that special characters may act as normal characters in some
+ contexts. Specifically, this applies to:
+ ^ - only special at the beginning, or after ( or |
+ $ - only special at the end, or before ) or |
+ *, +, ? - only special when not after the beginning, (, or | */
+#define RE_CONTEXT_INDEP_OPS 32
+
+/* Now define combinations of bits for the standard possibilities. */
+#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
+#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR)
+#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
+#define RE_SYNTAX_EMACS 0
+
+/* This data structure is used to represent a compiled pattern. */
+
+struct re_pattern_buffer
+ {
+ char *buffer; /* Space holding the compiled pattern commands. */
+ int allocated; /* Size of space that buffer points to */
+ int used; /* Length of portion of buffer actually occupied */
+ char *fastmap; /* Pointer to fastmap, if any, or zero if none. */
+ /* re_search uses the fastmap, if there is one,
+ to skip quickly over totally implausible characters */
+ char *translate; /* Translate table to apply to all characters before comparing.
+ Or zero for no translation.
+ The translation is applied to a pattern when it is compiled
+ and to data when it is matched. */
+ char fastmap_accurate;
+ /* Set to zero when a new pattern is stored,
+ set to one when the fastmap is updated from it. */
+ char can_be_null; /* Set to one by compiling fastmap
+ if this pattern might match the null string.
+ It does not necessarily match the null string
+ in that case, but if this is zero, it cannot.
+ 2 as value means can match null string
+ but at end of range or before a character
+ listed in the fastmap. */
+ };
+
+/* Structure to store "register" contents data in.
+
+ Pass the address of such a structure as an argument to re_match, etc.,
+ if you want this information back.
+
+ start[i] and end[i] record the string matched by \( ... \) grouping i,
+ for i from 1 to RE_NREGS - 1.
+ start[0] and end[0] record the entire string matched. */
+
+struct re_registers
+ {
+ int start[RE_NREGS];
+ int end[RE_NREGS];
+ };
+
+/* These are the command codes that appear in compiled regular expressions, one per byte.
+ Some command codes are followed by argument bytes.
+ A command code can specify any interpretation whatever for its arguments.
+ Zero-bytes may appear in the compiled regular expression. */
+
+enum regexpcode
+ {
+ unused,
+ exactn, /* followed by one byte giving n, and then by n literal bytes */
+ begline, /* fails unless at beginning of line */
+ endline, /* fails unless at end of line */
+ jump, /* followed by two bytes giving relative address to jump to */
+ on_failure_jump, /* followed by two bytes giving relative address of place
+ to resume at in case of failure. */
+ finalize_jump, /* Throw away latest failure point and then jump to address. */
+ maybe_finalize_jump, /* Like jump but finalize if safe to do so.
+ This is used to jump back to the beginning
+ of a repeat. If the command that follows
+ this jump is clearly incompatible with the
+ one at the beginning of the repeat, such that
+ we can be sure that there is no use backtracking
+ out of repetitions already completed,
+ then we finalize. */
+ dummy_failure_jump, /* jump, and push a dummy failure point.
+ This failure point will be thrown away
+ if an attempt is made to use it for a failure.
+ A + construct makes this before the first repeat. */
+ anychar, /* matches any one character */
+ charset, /* matches any one char belonging to specified set.
+ First following byte is # bitmap bytes.
+ Then come bytes for a bit-map saying which chars are in.
+ Bits in each byte are ordered low-bit-first.
+ A character is in the set if its bit is 1.
+ A character too large to have a bit in the map
+ is automatically not in the set */
+ charset_not, /* similar but match any character that is NOT one of those specified */
+ start_memory, /* starts remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ stop_memory, /* stops remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ duplicate, /* match a duplicate of something remembered.
+ Followed by one byte containing the index of the memory register. */
+ before_dot, /* Succeeds if before dot */
+ at_dot, /* Succeeds if at dot */
+ after_dot, /* Succeeds if after dot */
+ begbuf, /* Succeeds if at beginning of buffer */
+ endbuf, /* Succeeds if at end of buffer */
+ wordchar, /* Matches any word-constituent character */
+ notwordchar, /* Matches any char that is not a word-constituent */
+ wordbeg, /* Succeeds if at word beginning */
+ wordend, /* Succeeds if at word end */
+ wordbound, /* Succeeds if at a word boundary */
+ notwordbound, /* Succeeds if not at a word boundary */
+ syntaxspec, /* Matches any character whose syntax is specified.
+ followed by a byte which contains a syntax code, Sword or such like */
+ notsyntaxspec /* Matches any character whose syntax differs from the specified. */
+ };
+
+extern char *re_compile_pattern ();
+/* Is this really advertised? */
+extern void re_compile_fastmap ();
+extern int re_search (), re_search_2 ();
+extern int re_match (), re_match_2 ();
+
+/* 4.2 bsd compatibility (yuck) */
+extern char *re_comp ();
+extern int re_exec ();
+
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.c b/gnu/usr.bin/gdb/gdb/remote-utils.c
new file mode 100644
index 000000000000..f4f25e4c490c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.c
@@ -0,0 +1,645 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file actually contains two distinct logical "packages". They
+ are packaged together in this one file because they are typically
+ used together.
+
+ The first package is an addition to the serial package. The
+ addition provides reading and writing with debugging output and
+ timeouts based on user settable variables. These routines are
+ intended to support serial port based remote backends. These
+ functions are prefixed with sr_.
+
+ The second package is a collection of more or less generic
+ functions for use by remote backends. They support user settable
+ variables for debugging, retries, and the like.
+
+ Todo:
+
+ * a pass through mode a la kermit or telnet.
+ * autobaud.
+ * ask remote to change his baud rate.
+ * put generic load here.
+
+ */
+
+#include <ctype.h>
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "serial.h"
+#include "gdbcore.h" /* for exec_bfd */
+#include "inferior.h" /* for generic_mourn_inferior */
+#include "remote-utils.h"
+
+struct _sr_settings sr_settings = {
+ 4, /* timeout:
+ remote-hms.c had 2
+ remote-bug.c had "with a timeout of 2, we time out waiting for
+ the prompt after an s-record dump."
+
+ remote.c had (2): This was 5 seconds, which is a long time to
+ sit and wait. Unless this is going though some terminal server
+ or multiplexer or other form of hairy serial connection, I
+ would think 2 seconds would be plenty.
+*/
+
+ 10, /* retries */
+ NULL, /* device */
+ NULL, /* descriptor */
+};
+
+struct gr_settings *gr_settings = NULL;
+
+static void
+usage(proto, junk)
+ char *proto;
+ char *junk;
+{
+ if (junk != NULL)
+ fprintf(stderr, "Unrecognized arguments: `%s'.\n", junk);
+
+ /* FIXME-now: service@host? */
+
+ error("Usage: target %s <device <speed <debug>>>\n\
+or target %s <host> <port>\n", proto, proto);
+
+ return;
+}
+
+#define CHECKDONE(p, q) \
+{ \
+ if (q == p) \
+ { \
+ if (*p == '\0') \
+ return; \
+ else \
+ usage(proto, p); \
+ } \
+}
+
+void
+sr_scan_args(proto, args)
+ char *proto;
+ char *args;
+{
+ int n;
+ char *p, *q;
+
+ extern int strtol();
+
+ /* if no args, then nothing to do. */
+ if (args == NULL || *args == '\0')
+ return;
+
+ /* scan off white space. */
+ for (p = args; isspace(*p); ++p) ;;
+
+ /* find end of device name. */
+ for (q = p; *q != '\0' && !isspace(*q); ++q) ;;
+
+ /* check for missing or empty device name. */
+ CHECKDONE(p, q);
+ sr_set_device(savestring(p, q - p));
+
+ /* look for baud rate. */
+ n = strtol(q, &p, 10);
+
+ /* check for missing or empty baud rate. */
+ CHECKDONE(p, q);
+ sr_set_baud_rate(n);
+
+ /* look for debug value. */
+ n = strtol(p, &q, 10);
+
+ /* check for missing or empty debug value. */
+ CHECKDONE(p, q);
+ sr_set_debug(n);
+
+ /* scan off remaining white space. */
+ for (p = q; isspace(*p); ++p) ;;
+
+ /* if not end of string, then there's unrecognized junk. */
+ if (*p != '\0')
+ usage(proto, p);
+
+ return;
+}
+
+void
+gr_generic_checkin()
+{
+ sr_write_cr("");
+ gr_expect_prompt();
+}
+
+void
+gr_open(args, from_tty, gr)
+ char *args;
+ int from_tty;
+ struct gr_settings *gr;
+{
+ target_preopen(from_tty);
+ sr_scan_args(gr->ops->to_shortname, args);
+ unpush_target(gr->ops);
+
+ gr_settings = gr;
+
+ gr_set_dcache(dcache_init(gr->readfunc, gr->writefunc));
+
+ if (sr_get_desc() != NULL)
+ gr_close (0);
+
+ sr_set_desc(SERIAL_OPEN (sr_get_device()));
+ if (!sr_get_desc())
+ perror_with_name((char *) sr_get_device());
+
+ if (SERIAL_SETBAUDRATE(sr_get_desc(), sr_get_baud_rate()) != 0)
+ {
+ SERIAL_CLOSE(sr_get_desc());
+ perror_with_name(sr_get_device());
+ }
+
+ SERIAL_RAW (sr_get_desc());
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (sr_get_desc ());
+
+ /* default retries */
+ if (sr_get_retries() == 0)
+ sr_set_retries(1);
+
+ /* default clear breakpoint function */
+ if (gr_settings->clear_all_breakpoints == NULL)
+ gr_settings->clear_all_breakpoints = remove_breakpoints;
+
+ if (from_tty)
+ printf_filtered ("Remote debugging using `%s' at baud rate of %d\n",
+ sr_get_device(), sr_get_baud_rate());
+
+ push_target(gr->ops);
+ gr_checkin();
+ gr_clear_all_breakpoints ();
+ return;
+}
+
+/* Read a character from the remote system masking it down to 7 bits
+ and doing all the fancy timeout stuff. */
+
+int
+sr_readchar ()
+{
+ int buf;
+
+ buf = SERIAL_READCHAR (sr_get_desc(), sr_get_timeout());
+
+ if (buf == SERIAL_TIMEOUT)
+ error ("Timeout reading from remote system.");
+
+ if (sr_get_debug() > 0)
+ printf ("%c", buf);
+
+ return buf & 0x7f;
+}
+
+int
+sr_pollchar()
+{
+ int buf;
+
+ buf = SERIAL_READCHAR (sr_get_desc(), 0);
+ if (buf == SERIAL_TIMEOUT)
+ buf = 0;
+ if (sr_get_debug() > 0)
+ if (buf)
+ printf ("%c", buf);
+ else
+ printf ("<empty character poll>");
+
+ return buf & 0x7f;
+}
+
+/* Keep discarding input from the remote system, until STRING is found.
+ Let the user break out immediately. */
+void
+sr_expect (string)
+ char *string;
+{
+ char *p = string;
+
+ immediate_quit = 1;
+ while (1)
+ {
+ if (sr_readchar () == *p)
+ {
+ p++;
+ if (*p == '\0')
+ {
+ immediate_quit = 0;
+ return;
+ }
+ }
+ else
+ p = string;
+ }
+}
+
+void
+sr_write (a, l)
+ char *a;
+ int l;
+{
+ int i;
+
+ if (SERIAL_WRITE (sr_get_desc(), a, l) != 0)
+ perror_with_name ("sr_write: Error writing to remote");
+
+ if (sr_get_debug() > 0)
+ for (i = 0; i < l; i++)
+ printf ("%c", a[i]);
+
+ return;
+}
+
+void
+sr_write_cr (s)
+ char *s;
+{
+ sr_write (s, strlen (s));
+ sr_write ("\r", 1);
+ return;
+}
+
+int
+sr_timed_read (buf, n)
+ char *buf;
+ int n;
+{
+ int i;
+ char c;
+
+ i = 0;
+ while (i < n)
+ {
+ c = sr_readchar ();
+
+ if (c == 0)
+ return i;
+ buf[i] = c;
+ i++;
+
+ }
+ return i;
+}
+
+/* Get a hex digit from the remote system & return its value. If
+ ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
+
+int
+sr_get_hex_digit (ignore_space)
+ int ignore_space;
+{
+ int ch;
+
+ while (1)
+ {
+ ch = sr_readchar ();
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ else if (ch != ' ' || !ignore_space)
+ {
+ gr_expect_prompt ();
+ error ("Invalid hex digit from remote system.");
+ }
+ }
+}
+
+/* Get a byte from the remote and put it in *BYT. Accept any number
+ leading spaces. */
+void
+sr_get_hex_byte (byt)
+ char *byt;
+{
+ int val;
+
+ val = sr_get_hex_digit (1) << 4;
+ val |= sr_get_hex_digit (0);
+ *byt = val;
+}
+
+/* Read a 32-bit hex word from the remote, preceded by a space */
+long
+sr_get_hex_word ()
+{
+ long val;
+ int j;
+
+ val = 0;
+ for (j = 0; j < 8; j++)
+ val = (val << 4) + sr_get_hex_digit (j == 0);
+ return val;
+}
+
+/* Put a command string, in args, out to the remote. The remote is assumed to
+ be in raw mode, all writing/reading done through desc.
+ Ouput from the remote is placed on the users terminal until the
+ prompt from the remote is seen.
+ FIXME: Can't handle commands that take input. */
+
+void
+sr_com (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ sr_check_open ();
+
+ if (!args)
+ return;
+
+ /* Clear all input so only command relative output is displayed */
+
+ sr_write_cr (args);
+ sr_write ("\030", 1);
+ gr_expect_prompt ();
+}
+
+void
+gr_close(quitting)
+ int quitting;
+{
+ gr_clear_all_breakpoints();
+
+ if (sr_is_open())
+ {
+ SERIAL_CLOSE (sr_get_desc());
+ sr_set_desc(NULL);
+ }
+
+ return;
+}
+
+/* gr_detach()
+ takes a program previously attached to and detaches it.
+ We better not have left any breakpoints
+ in the program or it'll die when it hits one.
+ Close the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+
+void
+gr_detach(args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ if (sr_is_open())
+ gr_clear_all_breakpoints ();
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+
+ return;
+}
+
+void
+gr_files_info (ops)
+ struct target_ops *ops;
+{
+ char *file = "nothing";
+
+ if (exec_bfd)
+ file = bfd_get_filename (exec_bfd);
+
+ if (exec_bfd)
+ {
+#ifdef __GO32__
+ printf_filtered ("\tAttached to DOS asynctsr\n");
+#else
+ printf_filtered ("\tAttached to %s at %d baud\n",
+ sr_get_device(), sr_get_baud_rate());
+#endif
+ }
+
+ printf_filtered ("\tand running program %s\n", file);
+ printf_filtered ("\tusing the %s protocol.\n", ops->to_shortname);
+}
+
+void
+gr_mourn ()
+{
+ gr_clear_all_breakpoints ();
+ unpush_target (gr_get_ops());
+ generic_mourn_inferior ();
+}
+
+void
+gr_kill ()
+{
+ return;
+}
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+void
+gr_create_inferior (execfile, args, env)
+ char *execfile;
+ char *args;
+ char **env;
+{
+ int entry_pt;
+
+ if (args && *args)
+ error ("Can't pass arguments to remote process.");
+
+ if (execfile == 0 || exec_bfd == 0)
+ error ("No exec file specified");
+
+ entry_pt = (int) bfd_get_start_address (exec_bfd);
+ sr_check_open ();
+
+ gr_kill ();
+ gr_clear_all_breakpoints ();
+
+ init_wait_for_inferior ();
+ gr_checkin();
+
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+ proceed (entry_pt, -1, 0);
+}
+
+/* Given a null terminated list of strings LIST, read the input until we find one of
+ them. Return the index of the string found or -1 on error. '?' means match
+ any single character. Note that with the algorithm we use, the initial
+ character of the string cannot recur in the string, or we will not find some
+ cases of the string in the input. If PASSTHROUGH is non-zero, then
+ pass non-matching data on. */
+
+int
+gr_multi_scan (list, passthrough)
+ char *list[];
+ int passthrough;
+{
+ char *swallowed = NULL; /* holding area */
+ char *swallowed_p = swallowed; /* Current position in swallowed. */
+ int ch;
+ int ch_handled;
+ int i;
+ int string_count;
+ int max_length;
+ char **plist;
+
+ /* Look through the strings. Count them. Find the largest one so we can
+ allocate a holding area. */
+
+ for (max_length = string_count = i = 0;
+ list[i] != NULL;
+ ++i, ++string_count)
+ {
+ int length = strlen(list[i]);
+
+ if (length > max_length)
+ max_length = length;
+ }
+
+ /* if we have no strings, then something is wrong. */
+ if (string_count == 0)
+ return(-1);
+
+ /* otherwise, we will need a holding area big enough to hold almost two
+ copies of our largest string. */
+ swallowed_p = swallowed = alloca(max_length << 1);
+
+ /* and a list of pointers to current scan points. */
+ plist = (char **) alloca (string_count * sizeof(*plist));
+
+ /* and initialize */
+ for (i = 0; i < string_count; ++i)
+ plist[i] = list[i];
+
+ for (ch = sr_readchar(); /* loop forever */ ; ch = sr_readchar())
+ {
+ QUIT; /* Let user quit and leave process running */
+ ch_handled = 0;
+
+ for (i = 0; i < string_count; ++i)
+ {
+ if (ch == *plist[i] || *plist[i] == '?')
+ {
+ ++plist[i];
+ if (*plist[i] == '\0')
+ return(i);
+
+ if (!ch_handled)
+ *swallowed_p++ = ch;
+
+ ch_handled = 1;
+ }
+ else
+ plist[i] = list[i];
+ }
+
+ if (!ch_handled)
+ {
+ char *p;
+
+ /* Print out any characters which have been swallowed. */
+ if (passthrough)
+ {
+ for (p = swallowed; p < swallowed_p; ++p)
+ putc (*p, stdout);
+
+ putc (ch, stdout);
+ }
+
+ swallowed_p = swallowed;
+ }
+ }
+#if 0
+ /* Never reached. */
+ return(-1);
+#endif
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+void
+gr_prepare_to_store ()
+{
+ /* Do nothing, since we assume we can store individual regs */
+}
+
+/* Read a word from remote address ADDR and return it.
+ * This goes through the data cache.
+ */
+int
+gr_fetch_word (addr)
+ CORE_ADDR addr;
+{
+ return dcache_fetch (gr_get_dcache(), addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+void
+gr_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (gr_get_dcache(), addr, word);
+}
+
+void
+_initialize_sr_support ()
+{
+/* FIXME-now: if target is open when baud changes... */
+ add_show_from_set (add_set_cmd ("remotebaud", no_class,
+ var_zinteger, (char *)&baud_rate,
+ "Set baud rate for remote serial I/O.\n\
+This value is used to set the speed of the serial port when debugging\n\
+using remote targets.", &setlist),
+ &showlist);
+
+/* FIXME-now: if target is open... */
+ add_show_from_set (add_set_cmd ("remotedevice", no_class,
+ var_filename, (char *)&sr_settings.device,
+ "Set device for remote serial I/O.\n\
+This device is used as the serial port when debugging using remote\n\
+targets.", &setlist),
+ &showlist);
+
+ add_com ("remote <command>", class_obscure, sr_com,
+ "Send a command to the remote monitor.");
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.h b/gnu/usr.bin/gdb/gdb/remote-utils.h
new file mode 100644
index 000000000000..59f4d3b3706f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.h
@@ -0,0 +1,149 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef REMOTE_UTILS_H
+#define REMOTE_UTILS_H
+
+#include "serial.h"
+#include "target.h"
+#include "dcache.h"
+
+/* Stuff that should be shared (and handled consistently) among the various
+ remote targets. */
+
+struct _sr_settings {
+ unsigned int timeout;
+
+ int retries;
+
+ char *device;
+ serial_t desc;
+
+};
+
+extern struct _sr_settings sr_settings;
+extern int remote_debug;
+extern int baud_rate;
+
+/* get and set debug value. */
+#define sr_get_debug() (remote_debug)
+#define sr_set_debug(newval) (remote_debug = (newval))
+
+/* get and set baud rate. */
+#define sr_get_baud_rate() (baud_rate)
+#define sr_set_baud_rate(newval) (baud_rate = (newval))
+
+/* get and set timeout. */
+#define sr_get_timeout() (sr_settings.timeout)
+#define sr_set_timeout(newval) (sr_settings.timeout = (newval))
+
+/* get and set device. */
+#define sr_get_device() (sr_settings.device)
+#define sr_set_device(newval) \
+{ \
+ if (sr_settings.device) free(sr_settings.device); \
+ sr_settings.device = (newval); \
+}
+
+/* get and set descriptor value. */
+#define sr_get_desc() (sr_settings.desc)
+#define sr_set_desc(newval) (sr_settings.desc = (newval))
+
+/* get and set retries. */
+#define sr_get_retries() (sr_settings.retries)
+#define sr_set_retries(newval) (sr_settings.retries = (newval))
+
+#define sr_is_open() (sr_settings.desc != NULL)
+
+#define sr_check_open() { if (!sr_is_open()) \
+ error ("Remote device not open"); }
+
+struct gr_settings {
+ /* This is our data cache. */
+ DCACHE *dcache;
+ char *prompt;
+ struct target_ops *ops;
+ int (*clear_all_breakpoints)PARAMS((void));
+ memxferfunc readfunc;
+ memxferfunc writefunc;
+ void (*checkin)PARAMS((void));
+};
+
+extern struct gr_settings *gr_settings;
+
+/* get and set dcache. */
+#define gr_get_dcache() (gr_settings->dcache)
+#define gr_set_dcache(newval) (gr_settings->dcache = (newval))
+
+/* get and set prompt. */
+#define gr_get_prompt() (gr_settings->prompt)
+#define gr_set_prompt(newval) (gr_settings->prompt = (newval))
+
+/* get and set ops. */
+#define gr_get_ops() (gr_settings->ops)
+#define gr_set_ops(newval) (gr_settings->ops = (newval))
+
+#define gr_clear_all_breakpoints() ((gr_settings->clear_all_breakpoints)())
+#define gr_checkin() ((gr_settings->checkin)())
+
+/* Keep discarding input until we see the prompt.
+
+ The convention for dealing with the prompt is that you
+ o give your command
+ o *then* wait for the prompt.
+
+ Thus the last thing that a procedure does with the serial line
+ will be an gr_expect_prompt(). Exception: resume does not
+ wait for the prompt, because the terminal is being handed over
+ to the inferior. However, the next thing which happens after that
+ is a bug_wait which does wait for the prompt.
+ Note that this includes abnormal exit, e.g. error(). This is
+ necessary to prevent getting into states from which we can't
+ recover. */
+
+#define gr_expect_prompt() sr_expect(gr_get_prompt())
+
+int gr_fetch_word PARAMS((CORE_ADDR addr));
+int gr_multi_scan PARAMS((char *list[], int passthrough));
+int sr_get_hex_digit PARAMS((int ignore_space));
+int sr_pollchar PARAMS((void));
+int sr_readchar PARAMS((void));
+int sr_timed_read PARAMS((char *buf, int n));
+long sr_get_hex_word PARAMS((void));
+void gr_close PARAMS((int quitting));
+void gr_create_inferior PARAMS((char *execfile, char *args, char **env));
+void gr_detach PARAMS((char *args, int from_tty));
+void gr_files_info PARAMS((struct target_ops *ops));
+void gr_generic_checkin PARAMS((void));
+void gr_kill PARAMS((void));
+void gr_mourn PARAMS((void));
+void gr_prepare_to_store PARAMS((void));
+void gr_store_word PARAMS((CORE_ADDR addr, int word));
+void sr_expect PARAMS((char *string));
+void sr_get_hex_byte PARAMS((char *byt));
+void sr_scan_args PARAMS((char *proto, char *args));
+void sr_write PARAMS((char *a, int l));
+void sr_write_cr PARAMS((char *s));
+
+void gr_open PARAMS((char *args, int from_tty,
+ struct gr_settings *gr_settings));
+
+
+#endif /* REMOTE_UTILS_H */
diff --git a/gnu/usr.bin/gdb/gdb/remote.c b/gnu/usr.bin/gdb/gdb/remote.c
new file mode 100644
index 000000000000..266d5f389def
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote.c
@@ -0,0 +1,1272 @@
+/* Remote target communications for serial-line targets in custom GDB protocol
+ Copyright 1988, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Remote communication protocol.
+
+ A debug packet whose contents are <data>
+ is encapsulated for transmission in the form:
+
+ $ <data> # CSUM1 CSUM2
+
+ <data> must be ASCII alphanumeric and cannot include characters
+ '$' or '#'
+
+ CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ checksum of <data>, the most significant nibble is sent first.
+ the hex digits 0-9,a-f are used.
+
+ Receiver responds with:
+
+ + - if CSUM is correct and ready for next packet
+ - - if CSUM is incorrect
+
+ <data> is as follows:
+ All values are encoded in ascii hex digits.
+
+ Request Packet
+
+ read registers g
+ reply XX....X Each byte of register data
+ is described by two hex digits.
+ Registers are in the internal order
+ for GDB, and the bytes in a register
+ are in the same order the machine uses.
+ or ENN for an error.
+
+ write regs GXX..XX Each byte of register data
+ is described by two hex digits.
+ reply OK for success
+ ENN for an error
+
+ read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
+ reply XX..XX XX..XX is mem contents
+ Can be fewer bytes than requested
+ if able to read only part of the data.
+ or ENN NN is errno
+
+ write mem MAA..AA,LLLL:XX..XX
+ AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is data
+ reply OK for success
+ ENN for an error (this includes the case
+ where only part of the data was
+ written).
+
+ cont cAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ step sAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ last signal ? Reply the current reason for stopping.
+ This is the same reply as is generated
+ for step or cont : SAA where AA is the
+ signal number.
+
+ There is no immediate reply to step or cont.
+ The reply comes when the machine stops.
+ It is SAA AA is the "signal number"
+
+ or... TAAn...:r...;n:r...;n...:r...;
+ AA = signal number
+ n... = register number
+ r... = register contents
+ or... WAA The process extited, and AA is
+ the exit status. This is only
+ applicable for certains sorts of
+ targets.
+ or... NAATT;DD;BB Relocate the object file.
+ AA = signal number
+ TT = text address
+ DD = data address
+ BB = bss address
+ This is used by the NLM stub,
+ which is why it only has three
+ addresses rather than one per
+ section: the NLM stub always
+ sees only three sections, even
+ though gdb may see more.
+
+ kill request k
+
+ toggle debug d toggle debug flag (see 386 & 68k stubs)
+ reset r reset -- see sparc stub.
+ reserved <other> On other requests, the stub should
+ ignore the request and send an empty
+ response ($#<checksum>). This way
+ we can extend the protocol and GDB
+ can tell whether the stub it is
+ talking to uses the old or the new.
+*/
+
+#include "defs.h"
+#include <string.h>
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "wait.h"
+#include "terminal.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+
+#include "dcache.h"
+
+#if !defined(DONT_USE_REMOTE)
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+#include "serial.h"
+
+/* Prototypes for local functions */
+
+static int
+remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+
+static int
+remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+
+static void
+remote_files_info PARAMS ((struct target_ops *ignore));
+
+static int
+remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
+ int should_write, struct target_ops *target));
+
+static void
+remote_prepare_to_store PARAMS ((void));
+
+static void
+remote_fetch_registers PARAMS ((int regno));
+
+static void
+remote_resume PARAMS ((int pid, int step, int siggnal));
+
+static int
+remote_start_remote PARAMS ((char *dummy));
+
+static void
+remote_open PARAMS ((char *name, int from_tty));
+
+static void
+remote_close PARAMS ((int quitting));
+
+static void
+remote_store_registers PARAMS ((int regno));
+
+static void
+getpkt PARAMS ((char *buf, int forever));
+
+static void
+putpkt PARAMS ((char *buf));
+
+static void
+remote_send PARAMS ((char *buf));
+
+static int
+readchar PARAMS ((void));
+
+static int
+remote_wait PARAMS ((int pid, WAITTYPE *status));
+
+static int
+tohex PARAMS ((int nib));
+
+static int
+fromhex PARAMS ((int a));
+
+static void
+remote_detach PARAMS ((char *args, int from_tty));
+
+static void
+remote_interrupt PARAMS ((int signo));
+
+static void
+remote_interrupt_twice PARAMS ((int signo));
+
+static void
+interrupt_query PARAMS ((void));
+
+extern struct target_ops remote_ops; /* Forward decl */
+
+extern int baud_rate;
+
+extern int remote_debug;
+
+/* This was 5 seconds, which is a long time to sit and wait.
+ Unless this is going though some terminal server or multiplexer or
+ other form of hairy serial connection, I would think 2 seconds would
+ be plenty. */
+static int timeout = 2;
+
+#if 0
+int icache;
+#endif
+
+/* Descriptor for I/O to remote machine. Initialize it to NULL so that
+ remote_open knows that we don't have a file open when the program
+ starts. */
+serial_t remote_desc = NULL;
+
+#define PBUFSIZ 1024
+
+/* Maximum number of bytes to read/write at once. The value here
+ is chosen to fill up a packet (the headers account for the 32). */
+#define MAXBUFBYTES ((PBUFSIZ-32)/2)
+
+/* Round up PBUFSIZ to hold all the registers, at least. */
+#if REGISTER_BYTES > MAXBUFBYTES
+#undef PBUFSIZ
+#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
+#endif
+
+/* Clean up connection to a remote debugger. */
+
+/* ARGSUSED */
+static void
+remote_close (quitting)
+ int quitting;
+{
+ if (remote_desc)
+ SERIAL_CLOSE (remote_desc);
+ remote_desc = NULL;
+}
+
+/* Stub for catch_errors. */
+
+static int
+remote_start_remote (dummy)
+ char *dummy;
+{
+ immediate_quit = 1; /* Allow user to interrupt it */
+
+ /* Ack any packet which the remote side has already sent. */
+ /* I'm not sure this \r is needed; we don't use it any other time we
+ send an ack. */
+ SERIAL_WRITE (remote_desc, "+\r", 2);
+ putpkt ("?"); /* initiate a query from remote machine */
+ immediate_quit = 0;
+
+ start_remote (); /* Initialize gdb process mechanisms */
+ return 1;
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static DCACHE *remote_dcache;
+
+static void
+remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ if (name == 0)
+ error (
+"To open a remote debug connection, you need to specify what serial\n\
+device is attached to the remote system (e.g. /dev/ttya).");
+
+ target_preopen (from_tty);
+
+ unpush_target (&remote_ops);
+
+ remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
+
+ remote_desc = SERIAL_OPEN (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
+
+ SERIAL_RAW (remote_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (remote_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (&remote_ops); /* Switch to using remote target now */
+
+ /* Start the remote connection; if error (0), discard this target.
+ In particular, if the user quits, be sure to discard it
+ (we'd be in an inconsistent state otherwise). */
+ if (!catch_errors (remote_start_remote, (char *)0,
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ pop_target();
+}
+
+/* remote_detach()
+ takes a program previously attached to and detaches it.
+ We better not have left any breakpoints
+ in the program or it'll die when it hits one.
+ Close the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+
+static void
+remote_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (a)
+ int a;
+{
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ error ("Reply contains invalid hex digit");
+ return -1;
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (nib)
+ int nib;
+{
+ if (nib < 10)
+ return '0'+nib;
+ else
+ return 'a'+nib-10;
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+remote_resume (pid, step, siggnal)
+ int pid, step, siggnal;
+{
+ char buf[PBUFSIZ];
+
+ if (siggnal)
+ {
+ char *name;
+ target_terminal_ours_for_output ();
+ printf_filtered ("Can't send signals to a remote system. ");
+ name = strsigno (siggnal);
+ if (name)
+ printf_filtered (name);
+ else
+ printf_filtered ("Signal %d", siggnal);
+ printf_filtered (" not sent.\n");
+ target_terminal_inferior ();
+ }
+
+ dcache_flush (remote_dcache);
+
+ strcpy (buf, step ? "s": "c");
+
+ putpkt (buf);
+}
+
+/* Send ^C to target to halt it. Target will respond, and send us a
+ packet. */
+
+static void
+remote_interrupt (signo)
+ int signo;
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, remote_interrupt_twice);
+
+ if (remote_debug)
+ printf ("remote_interrupt called\n");
+
+ SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */
+}
+
+static void (*ofunc)();
+
+/* The user typed ^C twice. */
+static void
+remote_interrupt_twice (signo)
+ int signo;
+{
+ signal (signo, ofunc);
+
+ interrupt_query ();
+
+ signal (signo, remote_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query ()
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ return_to_top_level (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would.
+ Returns "pid" (though it's not clear what, if anything, that
+ means in the case of this target). */
+
+static int
+remote_wait (pid, status)
+ int pid;
+ WAITTYPE *status;
+{
+ unsigned char buf[PBUFSIZ];
+
+ WSETEXIT ((*status), 0);
+
+ while (1)
+ {
+ unsigned char *p;
+
+ ofunc = (void (*)()) signal (SIGINT, remote_interrupt);
+ getpkt ((char *) buf, 1);
+ signal (SIGINT, ofunc);
+
+ if (buf[0] == 'E')
+ warning ("Remote failure reply: %s", buf);
+ else if (buf[0] == 'T')
+ {
+ int i;
+ long regno;
+ char regs[MAX_REGISTER_RAW_SIZE];
+
+ /* Expedited reply, containing Signal, {regno, reg} repeat */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
+
+ p = &buf[3]; /* after Txx */
+
+ while (*p)
+ {
+ unsigned char *p1;
+
+ regno = strtol (p, &p1, 16); /* Read the register number */
+
+ if (p1 == p)
+ warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
+ p1, buf);
+
+ p = p1;
+
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
+
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
+ regno, p, buf);
+
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ warning ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+
+ if (*p++ != ';')
+ warning ("Remote register badly formatted: %s", buf);
+
+ supply_register (regno, regs);
+ }
+ break;
+ }
+ else if (buf[0] == 'N')
+ {
+ unsigned char *p1;
+ bfd_vma text_addr, data_addr, bss_addr;
+
+ /* Relocate object file. Format is NAATT;DD;BB where AA is
+ the signal number, TT is the new text address, DD is the
+ new data address, and BB is the new bss address. This is
+ used by the NLM stub; gdb may see more sections. */
+ p = &buf[3];
+ text_addr = strtoul (p, &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ data_addr = strtoul (p, &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ bss_addr = strtoul (p, &p1, 16);
+ if (p1 == p)
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+
+ if (symfile_objfile != NULL
+ && (ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_TEXT) != text_addr
+ || ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_DATA) != data_addr
+ || ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_BSS) != bss_addr))
+ {
+ struct section_offsets *offs;
+
+ /* FIXME: This code assumes gdb-stabs.h is being used;
+ it's broken for xcoff, dwarf, sdb-coff, etc. But
+ there is no simple canonical representation for this
+ stuff. (Just what does "text" as seen by the stub
+ mean, anyway?). */
+
+ /* FIXME: Why don't the various symfile_offsets routines
+ in the sym_fns vectors set this?
+ (no good reason -kingdon). */
+ if (symfile_objfile->num_sections == 0)
+ symfile_objfile->num_sections = SECT_OFF_MAX;
+
+ offs = ((struct section_offsets *)
+ alloca (sizeof (struct section_offsets)
+ + (symfile_objfile->num_sections
+ * sizeof (offs->offsets))));
+ memcpy (offs, symfile_objfile->section_offsets,
+ (sizeof (struct section_offsets)
+ + (symfile_objfile->num_sections
+ * sizeof (offs->offsets))));
+ ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
+ ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
+ ANOFFSET (offs, SECT_OFF_BSS) = bss_addr;
+
+ objfile_relocate (symfile_objfile, offs);
+ {
+ struct obj_section *s;
+ bfd *abfd;
+
+ abfd = symfile_objfile->obfd;
+
+ for (s = symfile_objfile->sections;
+ s < symfile_objfile->sections_end; ++s)
+ {
+ flagword flags;
+
+ flags = bfd_get_section_flags (abfd, s->sec_ptr);
+
+ if (flags & SEC_CODE)
+ {
+ s->addr += text_addr;
+ s->endaddr += text_addr;
+ }
+ else if (flags & (SEC_DATA | SEC_LOAD))
+ {
+ s->addr += data_addr;
+ s->endaddr += data_addr;
+ }
+ else if (flags & SEC_ALLOC)
+ {
+ s->addr += bss_addr;
+ s->endaddr += bss_addr;
+ }
+ }
+ }
+ }
+ break;
+ }
+ else if (buf[0] == 'W')
+ {
+ /* The remote process exited. */
+ WSETEXIT (*status, (fromhex (buf[1]) << 4) + fromhex (buf[2]));
+ return 0;
+ }
+ else if (buf[0] == 'S')
+ break;
+ else
+ warning ("Invalid remote reply: %s", buf);
+ }
+
+ WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
+
+ return 0;
+}
+
+/* Number of bytes of registers this stub implements. */
+static int register_bytes_found;
+
+/* Read the remote registers into the block REGS. */
+/* Currently we just read all the registers, so we don't use regno. */
+/* ARGSUSED */
+static void
+remote_fetch_registers (regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+ char regs[REGISTER_BYTES];
+
+ sprintf (buf, "g");
+ remote_send (buf);
+
+ /* Unimplemented registers read as all bits zero. */
+ memset (regs, 0, REGISTER_BYTES);
+
+ /* We can get out of synch in various cases. If the first character
+ in the buffer is not a hex character, assume that has happened
+ and try to fetch another packet to read. */
+ while ((buf[0] < '0' || buf[0] > '9')
+ && (buf[0] < 'a' || buf[0] > 'f'))
+ {
+ if (remote_debug)
+ printf ("Bad register packet; fetching a new packet\n");
+ getpkt (buf, 0);
+ }
+
+ /* Reply describes registers byte by byte, each byte encoded as two
+ hex characters. Suck them all up, then supply them to the
+ register cacheing/storage mechanism. */
+
+ p = buf;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ if (p[0] == 0)
+ break;
+ if (p[1] == 0)
+ {
+ warning ("Remote reply is of odd length: %s", buf);
+ /* Don't change register_bytes_found in this case, and don't
+ print a second warning. */
+ goto supply_them;
+ }
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+
+ if (i != register_bytes_found)
+ {
+ register_bytes_found = i;
+#ifdef REGISTER_BYTES_OK
+ if (!REGISTER_BYTES_OK (i))
+ warning ("Remote reply is too short: %s", buf);
+#endif
+ }
+
+ supply_them:
+ for (i = 0; i < NUM_REGS; i++)
+ supply_register (i, &regs[REGISTER_BYTE(i)]);
+}
+
+/* Prepare to store registers. Since we send them all, we have to
+ read out the ones we don't want to change first. */
+
+static void
+remote_prepare_to_store ()
+{
+ /* Make sure the entire registers array is valid. */
+ read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+}
+
+/* Store the remote registers from the contents of the block REGISTERS.
+ FIXME, eventually just store one register if that's all that is needed. */
+
+/* ARGSUSED */
+static void
+remote_store_registers (regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ buf[0] = 'G';
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + 1;
+ /* remote_prepare_to_store insures that register_bytes_found gets set. */
+ for (i = 0; i < register_bytes_found; i++)
+ {
+ *p++ = tohex ((registers[i] >> 4) & 0xf);
+ *p++ = tohex (registers[i] & 0xf);
+ }
+ *p = '\0';
+
+ remote_send (buf);
+}
+
+#if 0
+
+/* Use of the data cache is disabled because it loses for looking at
+ and changing hardware I/O ports and the like. Accepting `volatile'
+ would perhaps be one way to fix it, but a better way which would
+ win for more cases would be to use the executable file for the text
+ segment, like the `icache' code below but done cleanly (in some
+ target-independent place, perhaps in target_xfer_memory, perhaps
+ based on assigning each target a speed or perhaps by some simpler
+ mechanism). */
+
+/* Read a word from remote address ADDR and return it.
+ This goes through the data cache. */
+
+static int
+remote_fetch_word (addr)
+ CORE_ADDR addr;
+{
+#if 0
+ if (icache)
+ {
+ extern CORE_ADDR text_start, text_end;
+
+ if (addr >= text_start && addr < text_end)
+ {
+ int buffer;
+ xfer_core_file (addr, &buffer, sizeof (int));
+ return buffer;
+ }
+ }
+#endif
+ return dcache_fetch (remote_dcache, addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+static void
+remote_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (remote_dcache, addr, word);
+}
+#endif /* 0 */
+
+/* Write memory data directly to the remote machine.
+ This does not inform the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+remote_write_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 20)
+ abort ();
+
+ sprintf (buf, "M%x,%x:", memaddr, len);
+
+ /* We send target system values byte by byte, in increasing byte addresses,
+ each byte encoded as two hex characters. */
+
+ p = buf + strlen (buf);
+ for (i = 0; i < len; i++)
+ {
+ *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
+ }
+ *p = '\0';
+
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+ return len;
+}
+
+/* Read memory data directly from the remote machine.
+ This does not use the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+remote_read_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 1)
+ abort ();
+
+ sprintf (buf, "m%x,%x", memaddr, len);
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+
+ /* Reply describes memory byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < len; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ /* Reply is short. This means that we were able to read only part
+ of what we wanted to. */
+ break;
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+ return i;
+}
+
+/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
+ to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
+ nonzero. Returns length of data written or read; 0 for error. */
+
+/* ARGSUSED */
+static int
+remote_xfer_memory(memaddr, myaddr, len, should_write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int should_write;
+ struct target_ops *target; /* ignored */
+{
+ int xfersize;
+ int bytes_xferred;
+ int total_xferred = 0;
+
+ while (len > 0)
+ {
+ if (len > MAXBUFBYTES)
+ xfersize = MAXBUFBYTES;
+ else
+ xfersize = len;
+
+ if (should_write)
+ bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize);
+ else
+ bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize);
+
+ /* If we get an error, we are done xferring. */
+ if (bytes_xferred == 0)
+ break;
+
+ memaddr += bytes_xferred;
+ myaddr += bytes_xferred;
+ len -= bytes_xferred;
+ total_xferred += bytes_xferred;
+ }
+ return total_xferred;
+}
+
+static void
+remote_files_info (ignore)
+ struct target_ops *ignore;
+{
+ puts_filtered ("Debugging a target over a serial line.\n");
+}
+
+/* Stuff for dealing with the packets which are part of this protocol.
+ See comment at top of file for details. */
+
+/* Read a single character from the remote end, masking it down to 7 bits. */
+
+static int
+readchar ()
+{
+ int ch;
+
+ ch = SERIAL_READCHAR (remote_desc, timeout);
+
+ if (ch < 0)
+ return ch;
+
+ return ch & 0x7f;
+}
+
+/* Send the command in BUF to the remote machine,
+ and read the reply into BUF.
+ Report an error if we get an error reply. */
+
+static void
+remote_send (buf)
+ char *buf;
+{
+
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+}
+
+/* Send a packet to the remote machine, with error checking.
+ The data of the packet is in BUF. */
+
+static void
+putpkt (buf)
+ char *buf;
+{
+ int i;
+ unsigned char csum = 0;
+ char buf2[PBUFSIZ];
+ int cnt = strlen (buf);
+ int ch;
+ char *p;
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ if (cnt > sizeof(buf2) - 5) /* Prosanity check */
+ abort();
+
+ p = buf2;
+ *p++ = '$';
+
+ for (i = 0; i < cnt; i++)
+ {
+ csum += buf[i];
+ *p++ = buf[i];
+ }
+ *p++ = '#';
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+
+ /* Send it over and over until we get a positive ack. */
+
+ while (1)
+ {
+ if (remote_debug)
+ {
+ *p = '\0';
+ printf ("Sending packet: %s...", buf2); fflush(stdout);
+ }
+ if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
+ perror_with_name ("putpkt: write failed");
+
+ /* read until either a timeout occurs (-2) or '+' is read */
+ while (1)
+ {
+ ch = readchar ();
+
+ switch (ch)
+ {
+ case '+':
+ if (remote_debug)
+ printf("Ack\n");
+ return;
+ case SERIAL_TIMEOUT:
+ break; /* Retransmit buffer */
+ case SERIAL_ERROR:
+ perror_with_name ("putpkt: couldn't read ACK");
+ case SERIAL_EOF:
+ error ("putpkt: EOF while trying to read ACK");
+ default:
+ if (remote_debug)
+ printf ("%02X %c ", ch&0xFF, ch);
+ continue;
+ }
+ break; /* Here to retransmit */
+ }
+
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+ }
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. BUF is expected to be of size PBUFSIZ.
+ If FOREVER, wait forever rather than timing out; this is used
+ while the target is executing user code. */
+
+static void
+getpkt (buf, forever)
+ char *buf;
+ int forever;
+{
+ char *bp;
+ unsigned char csum;
+ int c = 0;
+ unsigned char c1, c2;
+ int retries = 0;
+#define MAX_RETRIES 10
+
+ while (1)
+ {
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+
+ /* This can loop forever if the remote side sends us characters
+ continuously, but if it pauses, we'll get a zero from readchar
+ because of timeout. Then we'll count that as a retry. */
+
+ c = readchar();
+ if (c > 0 && c != '$')
+ continue;
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (forever)
+ continue;
+ if (++retries >= MAX_RETRIES)
+ if (remote_debug) puts_filtered ("Timed out.\n");
+ goto out;
+ }
+
+ if (c == SERIAL_EOF)
+ error ("Remote connection closed");
+ if (c == SERIAL_ERROR)
+ perror_with_name ("Remote communication error");
+
+ /* Force csum to be zero here because of possible error retry. */
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar ();
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ puts_filtered ("Timeout in mid-packet, retrying\n");
+ goto whole; /* Start a new packet, count retries */
+ }
+ if (c == '$')
+ {
+ if (remote_debug)
+ puts_filtered ("Saw new packet start in middle of old one\n");
+ goto whole; /* Start a new packet, count retries */
+ }
+ if (c == '#')
+ break;
+ if (bp >= buf+PBUFSIZ-1)
+ {
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ goto whole;
+ }
+ *bp++ = c;
+ csum += c;
+ }
+ *bp = 0;
+
+ c1 = fromhex (readchar ());
+ c2 = fromhex (readchar ());
+ if ((csum & 0xff) == (c1 << 4) + c2)
+ break;
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ (c1 << 4) + c2, csum & 0xff);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ /* Try the whole thing again. */
+whole:
+ if (++retries < MAX_RETRIES)
+ {
+ SERIAL_WRITE (remote_desc, "-", 1);
+ }
+ else
+ {
+ printf ("Ignoring packet error, continuing...\n");
+ break;
+ }
+ }
+
+out:
+
+ SERIAL_WRITE (remote_desc, "+", 1);
+
+ if (remote_debug)
+ fprintf (stderr,"Packet received: %s\n", buf);
+}
+
+static void
+remote_kill ()
+{
+ putpkt ("k");
+ /* Don't wait for it to die. I'm not really sure it matters whether
+ we do or not. For the existing stubs, kill is a noop. */
+ target_mourn_inferior ();
+}
+
+static void
+remote_mourn ()
+{
+ unpush_target (&remote_ops);
+ generic_mourn_inferior ();
+}
+
+#ifdef REMOTE_BREAKPOINT
+
+/* On some machines, e.g. 68k, we may use a different breakpoint instruction
+ than other targets. */
+static unsigned char break_insn[] = REMOTE_BREAKPOINT;
+
+/* Check that it fits in BREAKPOINT_MAX bytes. */
+static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT;
+
+#else /* No REMOTE_BREAKPOINT. */
+
+/* Same old breakpoint instruction. This code does nothing different
+ than mem-break.c. */
+static unsigned char break_insn[] = BREAKPOINT;
+
+#endif /* No REMOTE_BREAKPOINT. */
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+ support. We read the contents of the target location and stash it,
+ then overwrite it with a breakpoint instruction. ADDR is the target
+ location in the target machine. CONTENTS_CACHE is a pointer to
+ memory allocated for saving the target contents. It is guaranteed
+ by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+ is accomplished via BREAKPOINT_MAX). */
+
+static int
+remote_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ int val;
+
+ val = target_read_memory (addr, contents_cache, sizeof break_insn);
+
+ if (val == 0)
+ val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+
+ return val;
+}
+
+static int
+remote_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ return target_write_memory (addr, contents_cache, sizeof break_insn);
+}
+
+/* Define the target subroutine names */
+
+struct target_ops remote_ops = {
+ "remote", /* to_shortname */
+ "Remote serial target in gdb-specific protocol", /* to_longname */
+ "Use a remote computer via a serial line, using a gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */
+ remote_open, /* to_open */
+ remote_close, /* to_close */
+ NULL, /* to_attach */
+ remote_detach, /* to_detach */
+ remote_resume, /* to_resume */
+ remote_wait, /* to_wait */
+ remote_fetch_registers, /* to_fetch_registers */
+ remote_store_registers, /* to_store_registers */
+ remote_prepare_to_store, /* to_prepare_to_store */
+ remote_xfer_memory, /* to_xfer_memory */
+ remote_files_info, /* to_files_info */
+
+ remote_insert_breakpoint, /* to_insert_breakpoint */
+ remote_remove_breakpoint, /* to_remove_breakpoint */
+
+ NULL, /* to_terminal_init */
+ NULL, /* to_terminal_inferior */
+ NULL, /* to_terminal_ours_for_output */
+ NULL, /* to_terminal_ours */
+ NULL, /* to_terminal_info */
+ remote_kill, /* to_kill */
+ generic_load, /* to_load */
+ NULL, /* to_lookup_symbol */
+ NULL, /* to_create_inferior */
+ remote_mourn, /* to_mourn_inferior */
+ 0, /* to_can_run */
+ 0, /* to_notice_signals */
+ process_stratum, /* to_stratum */
+ NULL, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ NULL, /* sections */
+ NULL, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+
+void
+_initialize_remote ()
+{
+ add_target (&remote_ops);
+}
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/ser-unix.c b/gnu/usr.bin/gdb/gdb/ser-unix.c
new file mode 100644
index 000000000000..b306e8ace5b2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ser-unix.c
@@ -0,0 +1,633 @@
+/* Serial interface for local (hardwired) serial ports on Un*x like systems
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "serial.h"
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
+#define HAVE_SGTTY
+#endif
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#include <unistd.h>
+
+struct hardwire_ttystate
+{
+ struct termios termios;
+};
+#endif /* termios */
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+
+/* It is believed that all systems which have added job control to SVR3
+ (e.g. sco) have also added termios. Even if not, trying to figure out
+ all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty
+ bewildering. So we don't attempt it. */
+
+struct hardwire_ttystate
+{
+ struct termio termio;
+};
+#endif /* termio */
+
+#ifdef HAVE_SGTTY
+/* Needed for the code which uses select(). We would include <sys/select.h>
+ too if it existed on all systems. */
+#include <sys/time.h>
+
+#include <sgtty.h>
+
+struct hardwire_ttystate
+{
+ struct sgttyb sgttyb;
+ struct tchars tc;
+ struct ltchars ltc;
+ /* Line discipline flags. */
+ int lmode;
+};
+#endif /* sgtty */
+
+static int hardwire_open PARAMS ((serial_t scb, const char *name));
+static void hardwire_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int hardwire_readchar PARAMS ((serial_t scb, int timeout));
+static int rate_to_code PARAMS ((int rate));
+static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate));
+static int hardwire_write PARAMS ((serial_t scb, const char *str, int len));
+/* FIXME: static void hardwire_restore PARAMS ((serial_t scb)); */
+static void hardwire_close PARAMS ((serial_t scb));
+static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb));
+static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
+/* Open up a real live device for serial I/O */
+
+static int
+hardwire_open(scb, name)
+ serial_t scb;
+ const char *name;
+{
+ scb->fd = open (name, O_RDWR);
+ if (scb->fd < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+get_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+#ifdef HAVE_TERMIOS
+ extern int errno;
+
+ if (tcgetattr(scb->fd, &state->termios) < 0)
+ return -1;
+
+ return 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ if (ioctl (scb->fd, TCGETA, &state->termio) < 0)
+ return -1;
+ return 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
+ return -1;
+
+ return 0;
+#endif
+}
+
+static int
+set_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+#ifdef HAVE_TERMIOS
+ if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0)
+ return -1;
+
+ return 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ if (ioctl (scb->fd, TCSETA, &state->termio) < 0)
+ return -1;
+ return 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0)
+ return -1;
+
+ return 0;
+#endif
+}
+
+static serial_ttystate
+hardwire_get_tty_state(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate *state;
+
+ state = (struct hardwire_ttystate *)xmalloc(sizeof *state);
+
+ if (get_tty_state(scb, state))
+ return NULL;
+
+ return (serial_ttystate)state;
+}
+
+static int
+hardwire_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state;
+
+ state = (struct hardwire_ttystate *)ttystate;
+
+ return set_tty_state(scb, state);
+}
+
+static int
+hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
+ serial_t scb;
+ serial_ttystate new_ttystate;
+ serial_ttystate old_ttystate;
+{
+ struct hardwire_ttystate new_state;
+ struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate;
+
+ new_state = *(struct hardwire_ttystate *)new_ttystate;
+
+#ifdef HAVE_TERMIOS
+ /* I'm not sure whether this is necessary; the manpage makes no mention
+ of discarding input when switching to/from ICANON. */
+ if (state->termios.c_lflag & ICANON)
+ new_state.termios.c_lflag |= ICANON;
+ else
+ new_state.termios.c_lflag &= ~ICANON;
+#endif
+
+#ifdef HAVE_TERMIO
+ /* I'm not sure whether this is necessary; the manpage makes no mention
+ of discarding input when switching to/from ICANON. */
+ if (state->termio.c_lflag & ICANON)
+ new_state.termio.c_lflag |= ICANON;
+ else
+ new_state.termio.c_lflag &= ~ICANON;
+#endif
+
+#ifdef HAVE_SGTTY
+ if (state->sgttyb.sg_flags & RAW)
+ new_state.sgttyb.sg_flags |= RAW;
+ else
+ new_state.sgttyb.sg_flags &= ~RAW;
+
+ /* I'm not sure whether this is necessary; the manpage just mentions
+ RAW not CBREAK. */
+ if (state->sgttyb.sg_flags & CBREAK)
+ new_state.sgttyb.sg_flags |= CBREAK;
+ else
+ new_state.sgttyb.sg_flags &= ~CBREAK;
+#endif
+
+ return set_tty_state (scb, &new_state);
+}
+
+static void
+hardwire_print_tty_state (scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
+ int i;
+
+#ifdef HAVE_TERMIOS
+ printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ state->termios.c_iflag, state->termios.c_oflag);
+ printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n",
+ state->termios.c_cflag, state->termios.c_lflag);
+#if 0
+ /* This not in POSIX, and is not really documented by those systems
+ which have it (at least not Sun). */
+ printf_filtered ("c_line = 0x%x.\n", state->termios.c_line);
+#endif
+ printf_filtered ("c_cc: ");
+ for (i = 0; i < NCCS; i += 1)
+ printf_filtered ("0x%x ", state->termios.c_cc[i]);
+ printf_filtered ("\n");
+#endif
+
+#ifdef HAVE_TERMIO
+ printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ state->termio.c_iflag, state->termio.c_oflag);
+ printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
+ state->termio.c_cflag, state->termio.c_lflag,
+ state->termio.c_line);
+ printf_filtered ("c_cc: ");
+ for (i = 0; i < NCC; i += 1)
+ printf_filtered ("0x%x ", state->termio.c_cc[i]);
+ printf_filtered ("\n");
+#endif
+
+#ifdef HAVE_SGTTY
+ printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags);
+
+ printf_filtered ("tchars: ");
+ for (i = 0; i < (int)sizeof (struct tchars); i++)
+ printf_filtered ("0x%x ", ((unsigned char *)&state->tc)[i]);
+ printf_filtered ("\n");
+
+ printf_filtered ("ltchars: ");
+ for (i = 0; i < (int)sizeof (struct ltchars); i++)
+ printf_filtered ("0x%x ", ((unsigned char *)&state->ltc)[i]);
+ printf_filtered ("\n");
+
+ printf_filtered ("lmode: 0x%x\n", state->lmode);
+#endif
+}
+
+static int
+hardwire_flush_output (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcflush (scb->fd, TCOFLUSH);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCFLSH, 1);
+#endif
+
+#ifdef HAVE_SGTTY
+ /* This flushes both input and output, but we can't do better. */
+ return ioctl (scb->fd, TIOCFLUSH, 0);
+#endif
+}
+
+static int
+hardwire_flush_input (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcflush (scb->fd, TCIFLUSH);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCFLSH, 0);
+#endif
+
+#ifdef HAVE_SGTTY
+ /* This flushes both input and output, but we can't do better. */
+ return ioctl (scb->fd, TIOCFLUSH, 0);
+#endif
+}
+
+static int
+hardwire_send_break (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcsendbreak (scb->fd, 0);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCSBRK, 0);
+#endif
+
+#ifdef HAVE_SGTTY
+ {
+ int status;
+ struct timeval timeout;
+
+ status = ioctl (scb->fd, TIOCSBRK, 0);
+
+ /* Can't use usleep; it doesn't exist in BSD 4.2. */
+ /* Note that if this select() is interrupted by a signal it will not wait
+ the full length of time. I think that is OK. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 250000;
+ select (0, 0, 0, 0, &timeout);
+ status = ioctl (scb->fd, TIOCCBRK, 0);
+ return status;
+ }
+#endif
+}
+
+static void
+hardwire_raw(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_iflag = 0;
+ state.termios.c_oflag = 0;
+ state.termios.c_lflag = 0;
+ state.termios.c_cflag &= ~(CSIZE|PARENB);
+ state.termios.c_cflag |= CS8;
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_iflag = 0;
+ state.termio.c_oflag = 0;
+ state.termio.c_lflag = 0;
+ state.termio.c_cflag &= ~(CSIZE|PARENB);
+ state.termio.c_cflag |= CS8;
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_flags |= RAW | ANYP;
+ state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
+#endif
+
+ scb->current_timeout = 0;
+
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+}
+
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+ For termio{s}, we actually just setup VTIME if necessary, and let the
+ timeout occur in the read() in hardwire_read().
+ */
+
+static int
+wait_for(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+#ifdef HAVE_SGTTY
+ struct timeval tv;
+ fd_set readfds;
+
+ FD_ZERO (&readfds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_SET(scb->fd, &readfds);
+
+ while (1)
+ {
+ int numfds;
+
+ if (timeout >= 0)
+ numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+
+ if (numfds <= 0)
+ if (numfds == 0)
+ return SERIAL_TIMEOUT;
+ else if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from select or poll */
+
+ return 0;
+ }
+
+#endif /* HAVE_SGTTY */
+
+#if defined HAVE_TERMIO || defined HAVE_TERMIOS
+ if (timeout == scb->current_timeout)
+ return 0;
+
+ {
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_cc[VTIME] = timeout * 10;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_cc[VTIME] = timeout * 10;
+#endif
+
+ scb->current_timeout = timeout;
+
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+
+ return 0;
+ }
+#endif /* HAVE_TERMIO || HAVE_TERMIOS */
+}
+
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns SERIAL_TIMEOUT if timeout expired, EOF if line
+ dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */
+
+static int
+hardwire_readchar(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ int status;
+
+ if (scb->bufcnt-- > 0)
+ return *scb->bufp++;
+
+ status = wait_for(scb, timeout);
+
+ if (status < 0)
+ return status;
+
+ scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
+
+ if (scb->bufcnt <= 0)
+ if (scb->bufcnt == 0)
+ return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to
+ distinguish between EOF & timeouts
+ someday] */
+ else
+ return SERIAL_ERROR; /* Got an error from read */
+
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+}
+
+#ifndef B19200
+#define B19200 EXTA
+#endif
+
+#ifndef B38400
+#define B38400 EXTB
+#endif
+
+/* Translate baud rates from integers to damn B_codes. Unix should
+ have outgrown this crap years ago, but even POSIX wouldn't buck it. */
+
+static struct
+{
+ int rate;
+ int code;
+}
+baudtab[] =
+{
+ {50, B50},
+ {75, B75},
+ {110, B110},
+ {134, B134},
+ {150, B150},
+ {200, B200},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {1800, B1800},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+ {-1, -1},
+};
+
+static int
+rate_to_code(rate)
+ int rate;
+{
+ int i;
+
+ for (i = 0; baudtab[i].rate != -1; i++)
+ if (rate == baudtab[i].rate)
+ return baudtab[i].code;
+
+ return -1;
+}
+
+static int
+hardwire_setbaudrate(scb, rate)
+ serial_t scb;
+ int rate;
+{
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ return -1;
+
+#ifdef HAVE_TERMIOS
+ cfsetospeed (&state.termios, rate_to_code (rate));
+ cfsetispeed (&state.termios, rate_to_code (rate));
+#endif
+
+#ifdef HAVE_TERMIO
+#ifndef CIBAUD
+#define CIBAUD CBAUD
+#endif
+
+ state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+ state.termio.c_cflag |= rate_to_code (rate);
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_ispeed = rate_to_code (rate);
+ state.sgttyb.sg_ospeed = rate_to_code (rate);
+#endif
+
+ return set_tty_state (scb, &state);
+}
+
+static int
+hardwire_write(scb, str, len)
+ serial_t scb;
+ const char *str;
+ int len;
+{
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(scb->fd, str, len);
+
+ if (cc < 0)
+ return 1;
+ len -= cc;
+ str += cc;
+ }
+ return 0;
+}
+
+static void
+hardwire_close(scb)
+ serial_t scb;
+{
+ if (scb->fd < 0)
+ return;
+
+ close(scb->fd);
+ scb->fd = -1;
+}
+
+static struct serial_ops hardwire_ops =
+{
+ "hardwire",
+ 0,
+ hardwire_open,
+ hardwire_close,
+ hardwire_readchar,
+ hardwire_write,
+ hardwire_flush_output,
+ hardwire_flush_input,
+ hardwire_send_break,
+ hardwire_raw,
+ hardwire_get_tty_state,
+ hardwire_set_tty_state,
+ hardwire_print_tty_state,
+ hardwire_noflush_set_tty_state,
+ hardwire_setbaudrate,
+};
+
+void
+_initialize_ser_hardwire ()
+{
+ serial_add_interface (&hardwire_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/serial.c b/gnu/usr.bin/gdb/gdb/serial.c
new file mode 100644
index 000000000000..6913fd6e2398
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.c
@@ -0,0 +1,261 @@
+/* Generic serial interface routines
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "serial.h"
+
+/* Linked list of serial I/O handlers */
+
+static struct serial_ops *serial_ops_list = NULL;
+
+/* This is the last serial stream opened. Used by connect command. */
+
+static serial_t last_serial_opened = NULL;
+
+static struct serial_ops *
+serial_interface_lookup (name)
+ char *name;
+{
+ struct serial_ops *ops;
+
+ for (ops = serial_ops_list; ops; ops = ops->next)
+ if (strcmp (name, ops->name) == 0)
+ return ops;
+
+ return NULL;
+}
+
+void
+serial_add_interface(optable)
+ struct serial_ops *optable;
+{
+ optable->next = serial_ops_list;
+ serial_ops_list = optable;
+}
+
+/* Open up a device or a network socket, depending upon the syntax of NAME. */
+
+serial_t
+serial_open(name)
+ const char *name;
+{
+ serial_t scb;
+ struct serial_ops *ops;
+
+ if (strchr (name, ':'))
+ ops = serial_interface_lookup ("tcp");
+ else
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ if (scb->ops->open(scb, name))
+ {
+ free (scb);
+ return NULL;
+ }
+
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+serial_t
+serial_fdopen(fd)
+ const int fd;
+{
+ serial_t scb;
+ struct serial_ops *ops;
+
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ scb->fd = fd;
+
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+void
+serial_close(scb)
+ serial_t scb;
+{
+ last_serial_opened = NULL;
+
+/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
+ should fix your code instead. */
+
+ if (!scb)
+ return;
+
+ scb->ops->close(scb);
+ free(scb);
+}
+
+#if 0
+/*
+The connect command is #if 0 because I hadn't thought of an elegant
+way to wait for I/O on two serial_t's simultaneously. Two solutions
+came to mind:
+
+ 1) Fork, and have have one fork handle the to user direction,
+ and have the other hand the to target direction. This
+ obviously won't cut it for MSDOS.
+
+ 2) Use something like select. This assumes that stdin and
+ the target side can both be waited on via the same
+ mechanism. This may not be true for DOS, if GDB is
+ talking to the target via a TCP socket.
+-grossman, 8 Jun 93
+*/
+
+/* Connect the user directly to the remote system. This command acts just like
+ the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+
+static serial_t tty_desc; /* Controlling terminal */
+
+static void
+cleanup_tty(ttystate)
+ serial_ttystate ttystate;
+{
+ printf ("\r\n[Exiting connect mode]\r\n");
+ SERIAL_SET_TTY_STATE (tty_desc, ttystate);
+ free (ttystate);
+ SERIAL_CLOSE (tty_desc);
+}
+
+static void
+connect_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ int c;
+ char cur_esc = 0;
+ serial_ttystate ttystate;
+ serial_t port_desc; /* TTY port */
+
+ dont_repeat();
+
+ if (args)
+ fprintf(stderr, "This command takes no args. They have been ignored.\n");
+
+ printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
+
+ tty_desc = SERIAL_FDOPEN (0);
+ port_desc = last_serial_opened;
+
+ ttystate = SERIAL_GET_TTY_STATE (tty_desc);
+
+ SERIAL_RAW (tty_desc);
+ SERIAL_RAW (port_desc);
+
+ make_cleanup (cleanup_tty, ttystate);
+
+ while (1)
+ {
+ int mask;
+
+ mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
+
+ if (mask & 2)
+ { /* tty input */
+ char cx;
+
+ while (1)
+ {
+ c = SERIAL_READCHAR(tty_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name("connect");
+
+ cx = c;
+ SERIAL_WRITE(port_desc, &cx, 1);
+
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
+ }
+ }
+
+ if (mask & 1)
+ { /* Port input */
+ char cx;
+
+ while (1)
+ {
+ c = SERIAL_READCHAR(port_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name("connect");
+
+ cx = c;
+
+ SERIAL_WRITE(tty_desc, &cx, 1);
+ }
+ }
+ }
+}
+
+void
+_initialize_serial ()
+{
+ add_com ("connect", class_obscure, connect_command,
+ "Connect the terminal directly up to the command monitor.\n\
+Use <CR>~. or <CR>~^D to break out.");
+}
+#endif /* 0 */
diff --git a/gnu/usr.bin/gdb/gdb/serial.h b/gnu/usr.bin/gdb/gdb/serial.h
new file mode 100644
index 000000000000..7e7e53066864
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.h
@@ -0,0 +1,153 @@
+/* Remote serial support interface definitions for GDB, the GNU Debugger.
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SERIAL_H
+#define SERIAL_H
+
+/* Terminal state pointer. This is specific to each type of interface. */
+
+typedef PTR serial_ttystate;
+
+struct _serial_t
+{
+ int fd; /* File descriptor */
+ struct serial_ops *ops; /* Function vector */
+ serial_ttystate ttystate; /* Not used (yet) */
+ int bufcnt; /* Amount of data in receive buffer */
+ unsigned char *bufp; /* Current byte */
+ unsigned char buf[BUFSIZ]; /* Da buffer itself */
+ int current_timeout; /* (termio{s} only), last value of VTIME */
+};
+
+typedef struct _serial_t *serial_t;
+
+struct serial_ops {
+ char *name;
+ struct serial_ops *next;
+ int (*open) PARAMS ((serial_t, const char *name));
+ void (*close) PARAMS ((serial_t));
+ int (*readchar) PARAMS ((serial_t, int timeout));
+ int (*write) PARAMS ((serial_t, const char *str, int len));
+ int (*flush_output) PARAMS ((serial_t));
+ int (*flush_input) PARAMS ((serial_t));
+ int (*send_break) PARAMS ((serial_t));
+ void (*go_raw) PARAMS ((serial_t));
+ serial_ttystate (*get_tty_state) PARAMS ((serial_t));
+ int (*set_tty_state) PARAMS ((serial_t, serial_ttystate));
+ void (*print_tty_state) PARAMS ((serial_t, serial_ttystate));
+ int (*noflush_set_tty_state)
+ PARAMS ((serial_t, serial_ttystate, serial_ttystate));
+ int (*setbaudrate) PARAMS ((serial_t, int rate));
+};
+
+/* Add a new serial interface to the interface list */
+
+void serial_add_interface PARAMS ((struct serial_ops *optable));
+
+serial_t serial_open PARAMS ((const char *name));
+
+serial_t serial_fdopen PARAMS ((int fd));
+
+/* For most routines, if a failure is indicated, then errno should be
+ examined. */
+
+/* Try to open NAME. Returns a new serial_t on success, NULL on failure.
+ */
+
+#define SERIAL_OPEN(NAME) serial_open(NAME)
+
+/* Open a new serial stream using a file handle. */
+
+#define SERIAL_FDOPEN(FD) serial_fdopen(FD)
+
+/* Flush pending output. Might also flush input (if this system can't flush
+ only output). */
+
+#define SERIAL_FLUSH_OUTPUT(SERIAL_T) \
+ ((SERIAL_T)->ops->flush_output((SERIAL_T)))
+
+/* Flush pending input. Might also flush output (if this system can't flush
+ only input). */
+
+#define SERIAL_FLUSH_INPUT(SERIAL_T)\
+ ((*(SERIAL_T)->ops->flush_input) ((SERIAL_T)))
+
+/* Send a break between 0.25 and 0.5 seconds long. */
+
+#define SERIAL_SEND_BREAK(SERIAL_T) \
+ ((*(SERIAL_T)->ops->send_break) (SERIAL_T))
+
+/* Turn the port into raw mode. */
+
+#define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T))
+
+/* Return a pointer to a newly malloc'd ttystate containing the state
+ of the tty. */
+#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T))
+
+/* Set the state of the tty to TTYSTATE. The change is immediate.
+ When changing to or from raw mode, input might be discarded. */
+#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE))
+
+/* printf_filtered a user-comprehensible description of ttystate. */
+#define SERIAL_PRINT_TTY_STATE(SERIAL_T, TTYSTATE) \
+ ((*((SERIAL_T)->ops->print_tty_state)) ((SERIAL_T), (TTYSTATE)))
+
+/* Set the tty state to NEW_TTYSTATE, where OLD_TTYSTATE is the
+ current state (generally obtained from a recent call to
+ SERIAL_GET_TTY_STATE), but be careful not to discard any input.
+ This means that we never switch in or out of raw mode, even
+ if NEW_TTYSTATE specifies a switch. */
+#define SERIAL_NOFLUSH_SET_TTY_STATE(SERIAL_T, NEW_TTYSTATE, OLD_TTYSTATE) \
+ ((*((SERIAL_T)->ops->noflush_set_tty_state)) \
+ ((SERIAL_T), (NEW_TTYSTATE), (OLD_TTYSTATE)))
+
+/* Read one char from the serial device with TIMEOUT seconds to wait
+ or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if ok, else one of the following codes. Note that all error
+ codes are guaranteed to be < 0. */
+
+#define SERIAL_ERROR -1 /* General error, see errno for details */
+#define SERIAL_TIMEOUT -2
+#define SERIAL_EOF -3
+
+#define SERIAL_READCHAR(SERIAL_T, TIMEOUT) ((SERIAL_T)->ops->readchar((SERIAL_T), TIMEOUT))
+
+/* Set the baudrate to the decimal value supplied. Returns 0 for success,
+ -1 for failure. */
+
+#define SERIAL_SETBAUDRATE(SERIAL_T, RATE) ((SERIAL_T)->ops->setbaudrate((SERIAL_T), RATE))
+
+/* Write LEN chars from STRING to the port SERIAL_T. Returns 0 for
+ success, non-zero for failure. */
+
+#define SERIAL_WRITE(SERIAL_T, STRING, LEN) ((SERIAL_T)->ops->write((SERIAL_T), STRING, LEN))
+
+/* Push out all buffers, close the device and destroy SERIAL_T. */
+
+void serial_close PARAMS ((serial_t));
+
+#define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T)
+
+/* Destroy SERIAL_T without doing the rest of the stuff that SERIAL_CLOSE
+ does. */
+
+#define SERIAL_UN_FDOPEN(SERIAL_T) (free (SERIAL_T))
+
+#endif /* SERIAL_H */
diff --git a/gnu/usr.bin/gdb/gdb/signals.h b/gnu/usr.bin/gdb/gdb/signals.h
new file mode 100644
index 000000000000..08fa606ef097
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/signals.h
@@ -0,0 +1,27 @@
+/* Signal handler definitions for GDB, the GNU Debugger.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is almost the same as including <signal.h> except that it
+ eliminates certain signal names when job control is not supported,
+ (or, on some systems, when job control is there but doesn't work
+ the way GDB expects it to work). */
+/* This has been superceded by the job_control variable in serial.h. */
+
+#include <signal.h>
diff --git a/gnu/usr.bin/gdb/gdb/solib.h b/gnu/usr.bin/gdb/gdb/solib.h
new file mode 100644
index 000000000000..ddabf7460bc1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/solib.h
@@ -0,0 +1,56 @@
+/* Shared library declarations for GDB, the GNU Debugger.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__ /* Forward decl's for prototypes */
+struct target_ops;
+#endif
+
+/* Called when we free all symtabs, to free the shared library information
+ as well. */
+
+#define CLEAR_SOLIB clear_solib
+
+extern void
+clear_solib PARAMS ((void));
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ) \
+ solib_add (filename, from_tty, targ)
+
+extern void
+solib_add PARAMS ((char *, int, struct target_ops *));
+
+/* Function to be called when the inferior starts up, to discover the names
+ of shared libraries that are dynamically linked, the base addresses to
+ which they are linked, and sufficient information to read in their symbols
+ at a later time. */
+
+#define SOLIB_CREATE_INFERIOR_HOOK(PID) solib_create_inferior_hook()
+
+extern void
+solib_create_inferior_hook PARAMS((void)); /* solib.c */
+
+/* If we can't set a breakpoint, and it's in a shared library, just
+ disable it. */
+
+#define DISABLE_UNSETTABLE_BREAK(addr) solib_address(addr)
+
+extern int
+solib_address PARAMS ((CORE_ADDR)); /* solib.c */
diff --git a/gnu/usr.bin/gdb/gdb/source.c b/gnu/usr.bin/gdb/gdb/source.c
new file mode 100644
index 000000000000..88781d7cbc91
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/source.c
@@ -0,0 +1,1398 @@
+/* List lines of source files for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "expression.h"
+#include "language.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "frame.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "gdbcore.h"
+#include "regex.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+/* Prototypes for local functions. */
+
+static int
+open_source_file PARAMS ((struct symtab *));
+
+static int
+get_filename_and_charpos PARAMS ((struct symtab *, char **));
+
+static void
+reverse_search_command PARAMS ((char *, int));
+
+static void
+forward_search_command PARAMS ((char *, int));
+
+static void
+line_info PARAMS ((char *, int));
+
+static void
+list_command PARAMS ((char *, int));
+
+static void
+ambiguous_line_spec PARAMS ((struct symtabs_and_lines *));
+
+static void
+source_info PARAMS ((char *, int));
+
+static void
+show_directories PARAMS ((char *, int));
+
+static void
+find_source_lines PARAMS ((struct symtab *, int));
+
+/* If we use this declaration, it breaks because of fucking ANSI "const" stuff
+ on some systems. We just have to not declare it at all, have it default
+ to int, and possibly botch on a few systems. Thanks, ANSIholes... */
+/* extern char *strstr(); */
+
+/* Path of directories to search for source files.
+ Same format as the PATH environment variable's value. */
+
+char *source_path;
+
+/* Symtab of default file for listing lines of. */
+
+struct symtab *current_source_symtab;
+
+/* Default next line to list. */
+
+int current_source_line;
+
+/* Default number of lines to print with commands like "list".
+ This is based on guessing how many long (i.e. more than chars_per_line
+ characters) lines there will be. To be completely correct, "list"
+ and friends should be rewritten to count characters and see where
+ things are wrapping, but that would be a fair amount of work. */
+
+int lines_to_list = 10;
+
+/* Line number of last line printed. Default for various commands.
+ current_source_line is usually, but not always, the same as this. */
+
+static int last_line_listed;
+
+/* First line number listed by last listing command. */
+
+static int first_line_listed;
+
+
+/* Set the source file default for the "list" command to be S.
+
+ If S is NULL, and we don't have a default, find one. This
+ should only be called when the user actually tries to use the
+ default, since we produce an error if we can't find a reasonable
+ default. Also, since this can cause symbols to be read, doing it
+ before we need to would make things slower than necessary. */
+
+void
+select_source_symtab (s)
+ register struct symtab *s;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct partial_symtab *ps;
+ struct partial_symtab *cs_pst = 0;
+ struct objfile *ofp;
+
+ if (s)
+ {
+ current_source_symtab = s;
+ current_source_line = 1;
+ return;
+ }
+
+ if (current_source_symtab)
+ return;
+
+ /* Make the default place to list be the function `main'
+ if one exists. */
+ if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0, NULL))
+ {
+ sals = decode_line_spec ("main", 1);
+ sal = sals.sals[0];
+ free (sals.sals);
+ current_source_symtab = sal.symtab;
+ current_source_line = max (sal.line - (lines_to_list - 1), 1);
+ if (current_source_symtab)
+ return;
+ }
+
+ /* All right; find the last file in the symtab list (ignoring .h's). */
+
+ current_source_line = 1;
+
+ for (ofp = object_files; ofp != NULL; ofp = ofp -> next)
+ {
+ for (s = ofp -> symtabs; s; s = s->next)
+ {
+ char *name = s -> filename;
+ int len = strlen (name);
+ if (! (len > 2 && (STREQ (&name[len - 2], ".h"))))
+ {
+ current_source_symtab = s;
+ }
+ }
+ }
+ if (current_source_symtab)
+ return;
+
+ /* Howabout the partial symbol tables? */
+
+ for (ofp = object_files; ofp != NULL; ofp = ofp -> next)
+ {
+ for (ps = ofp -> psymtabs; ps != NULL; ps = ps -> next)
+ {
+ char *name = ps -> filename;
+ int len = strlen (name);
+ if (! (len > 2 && (STREQ (&name[len - 2], ".h"))))
+ {
+ cs_pst = ps;
+ }
+ }
+ }
+ if (cs_pst)
+ {
+ if (cs_pst -> readin)
+ {
+ fatal ("Internal: select_source_symtab: readin pst found and no symtabs.");
+ }
+ else
+ {
+ current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
+ }
+ }
+
+ error ("Can't find a default source file");
+}
+
+static void
+show_directories (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ puts_filtered ("Source directories searched: ");
+ puts_filtered (source_path);
+ puts_filtered ("\n");
+}
+
+/* Forget what we learned about line positions in source files,
+ and which directories contain them;
+ must check again now since files may be found in
+ a different directory now. */
+
+void
+forget_cached_source_info ()
+{
+ register struct symtab *s;
+ register struct objfile *objfile;
+
+ for (objfile = object_files; objfile != NULL; objfile = objfile -> next)
+ {
+ for (s = objfile -> symtabs; s != NULL; s = s -> next)
+ {
+ if (s -> line_charpos != NULL)
+ {
+ mfree (objfile -> md, s -> line_charpos);
+ s -> line_charpos = NULL;
+ }
+ if (s -> fullname != NULL)
+ {
+ mfree (objfile -> md, s -> fullname);
+ s -> fullname = NULL;
+ }
+ }
+ }
+}
+
+void
+init_source_path ()
+{
+ source_path = savestring ("$cdir:$cwd", /* strlen of it */ 10);
+ forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of the source path. */
+
+void
+directory_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ dont_repeat ();
+ /* FIXME, this goes to "delete dir"... */
+ if (dirname == 0)
+ {
+ if (query ("Reinitialize source path to empty? ", ""))
+ {
+ free (source_path);
+ init_source_path ();
+ }
+ }
+ else
+ mod_path (dirname, &source_path);
+ if (from_tty)
+ show_directories ((char *)0, from_tty);
+ forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of an arbitrary path. */
+
+void
+mod_path (dirname, which_path)
+ char *dirname;
+ char **which_path;
+{
+ char *old = *which_path;
+ int prefix = 0;
+
+ if (dirname == 0)
+ return;
+
+ dirname = strsave (dirname);
+ make_cleanup (free, dirname);
+
+ do
+ {
+ char *name = dirname;
+ register char *p;
+ struct stat st;
+
+ {
+ char *colon = strchr (name, ':');
+ char *space = strchr (name, ' ');
+ char *tab = strchr (name, '\t');
+ if (colon == 0 && space == 0 && tab == 0)
+ p = dirname = name + strlen (name);
+ else
+ {
+ p = 0;
+ if (colon != 0 && (p == 0 || colon < p))
+ p = colon;
+ if (space != 0 && (p == 0 || space < p))
+ p = space;
+ if (tab != 0 && (p == 0 || tab < p))
+ p = tab;
+ dirname = p + 1;
+ while (*dirname == ':' || *dirname == ' ' || *dirname == '\t')
+ ++dirname;
+ }
+ }
+
+ if (p[-1] == '/')
+ /* Sigh. "foo/" => "foo" */
+ --p;
+ *p = '\0';
+
+ while (p[-1] == '.')
+ {
+ if (p - name == 1)
+ {
+ /* "." => getwd (). */
+ name = current_directory;
+ goto append;
+ }
+ else if (p[-2] == '/')
+ {
+ if (p - name == 2)
+ {
+ /* "/." => "/". */
+ *--p = '\0';
+ goto append;
+ }
+ else
+ {
+ /* "...foo/." => "...foo". */
+ p -= 2;
+ *p = '\0';
+ continue;
+ }
+ }
+ else
+ break;
+ }
+
+ if (name[0] == '~')
+ name = tilde_expand (name);
+ else if (name[0] != '/' && name[0] != '$')
+ name = concat (current_directory, "/", name, NULL);
+ else
+ name = savestring (name, p - name);
+ make_cleanup (free, name);
+
+ /* Unless it's a variable, check existence. */
+ if (name[0] != '$') {
+ /* These are warnings, not errors, since we don't want a
+ non-existent directory in a .gdbinit file to stop processing
+ of the .gdbinit file.
+
+ Whether they get added to the path is more debatable. Current
+ answer is yes, in case the user wants to go make the directory
+ or whatever. If the directory continues to not exist/not be
+ a directory/etc, then having them in the path should be
+ harmless. */
+ if (stat (name, &st) < 0)
+ {
+ int save_errno = errno;
+ fprintf (stderr, "Warning: ");
+ print_sys_errmsg (name, save_errno);
+ }
+ else if ((st.st_mode & S_IFMT) != S_IFDIR)
+ warning ("%s is not a directory.", name);
+ }
+
+ append:
+ {
+ register unsigned int len = strlen (name);
+
+ p = *which_path;
+ while (1)
+ {
+ if (!strncmp (p, name, len)
+ && (p[len] == '\0' || p[len] == ':'))
+ {
+ /* Found it in the search path, remove old copy */
+ if (p > *which_path)
+ p--; /* Back over leading colon */
+ if (prefix > p - *which_path)
+ goto skip_dup; /* Same dir twice in one cmd */
+ strcpy (p, &p[len+1]); /* Copy from next \0 or : */
+ }
+ p = strchr (p, ':');
+ if (p != 0)
+ ++p;
+ else
+ break;
+ }
+ if (p == 0)
+ {
+ /* If we have already tacked on a name(s) in this command, be sure they stay on the front as we tack on some more. */
+ if (prefix)
+ {
+ char *temp, c;
+
+ c = old[prefix];
+ old[prefix] = '\0';
+ temp = concat (old, ":", name, NULL);
+ old[prefix] = c;
+ *which_path = concat (temp, "", &old[prefix], NULL);
+ prefix = strlen (temp);
+ free (temp);
+ }
+ else
+ {
+ *which_path = concat (name, (old[0]? ":" : old), old, NULL);
+ prefix = strlen (name);
+ }
+ free (old);
+ old = *which_path;
+ }
+ }
+ skip_dup: ;
+ } while (*dirname != '\0');
+}
+
+
+static void
+source_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct symtab *s = current_source_symtab;
+
+ if (!s)
+ {
+ printf_filtered("No current source file.\n");
+ return;
+ }
+ printf_filtered ("Current source file is %s\n", s->filename);
+ if (s->dirname)
+ printf_filtered ("Compilation directory is %s\n", s->dirname);
+ if (s->fullname)
+ printf_filtered ("Located in %s\n", s->fullname);
+ if (s->nlines)
+ printf_filtered ("Contains %d line%s.\n", s->nlines,
+ s->nlines == 1 ? "" : "s");
+
+ printf_filtered("Source language is %s.\n", language_str (s->language));
+}
+
+
+
+/* Open a file named STRING, searching path PATH (dir names sep by colons)
+ using mode MODE and protection bits PROT in the calls to open.
+
+ If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
+ (ie pretend the first element of PATH is "."). This also indicates
+ that a slash in STRING disables searching of the path (this is
+ so that "exec-file ./foo" or "symbol-file ./foo" insures that you
+ get that particular version of foo or an error message).
+
+ If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
+ the actual file opened (this string will always start with a "/". We
+ have to take special pains to avoid doubling the "/" between the directory
+ and the file, sigh! Emacs gets confuzzed by this when we print the
+ source file name!!!
+
+ If a file is found, return the descriptor.
+ Otherwise, return -1, with errno set for the last name we tried to open. */
+
+/* >>>> This should only allow files of certain types,
+ >>>> eg executable, non-directory */
+int
+openp (path, try_cwd_first, string, mode, prot, filename_opened)
+ char *path;
+ int try_cwd_first;
+ char *string;
+ int mode;
+ int prot;
+ char **filename_opened;
+{
+ register int fd;
+ register char *filename;
+ register char *p, *p1;
+ register int len;
+ int alloclen;
+
+ if (!path)
+ path = ".";
+
+ if (try_cwd_first || string[0] == '/')
+ {
+ filename = string;
+ fd = open (filename, mode, prot);
+ if (fd >= 0 || string[0] == '/' || strchr (string, '/'))
+ goto done;
+ }
+
+ /* ./foo => foo */
+ while (string[0] == '.' && string[1] == '/')
+ string += 2;
+
+ alloclen = strlen (path) + strlen (string) + 2;
+ filename = (char *) alloca (alloclen);
+ fd = -1;
+ for (p = path; p; p = p1 ? p1 + 1 : 0)
+ {
+ p1 = (char *) strchr (p, ':');
+ if (p1)
+ len = p1 - p;
+ else
+ len = strlen (p);
+
+ if (len == 4 && p[0] == '$' && p[1] == 'c'
+ && p[2] == 'w' && p[3] == 'd') {
+ /* Name is $cwd -- insert current directory name instead. */
+ int newlen;
+
+ /* First, realloc the filename buffer if too short. */
+ len = strlen (current_directory);
+ newlen = len + strlen (string) + 2;
+ if (newlen > alloclen) {
+ alloclen = newlen;
+ filename = (char *) alloca (alloclen);
+ }
+ strcpy (filename, current_directory);
+ } else {
+ /* Normal file name in path -- just use it. */
+ strncpy (filename, p, len);
+ filename[len] = 0;
+ }
+
+ /* Remove trailing slashes */
+ while (len > 0 && filename[len-1] == '/')
+ filename[--len] = 0;
+
+ strcat (filename+len, "/");
+ strcat (filename, string);
+
+ fd = open (filename, mode, prot);
+ if (fd >= 0) break;
+ }
+
+ done:
+ if (filename_opened)
+ if (fd < 0)
+ *filename_opened = (char *) 0;
+ else if (filename[0] == '/')
+ *filename_opened = savestring (filename, strlen (filename));
+ else
+ {
+ /* Beware the // my son, the Emacs barfs, the botch that catch... */
+
+ *filename_opened = concat (current_directory,
+ '/' == current_directory[strlen(current_directory)-1]? "": "/",
+ filename, NULL);
+ }
+
+ return fd;
+}
+
+/* Open a source file given a symtab S. Returns a file descriptor
+ or negative number for error. */
+
+static int
+open_source_file (s)
+ struct symtab *s;
+{
+ char *path = source_path;
+ char *p;
+ int result;
+ char *fullname;
+
+ /* Quick way out if we already know its full name */
+ if (s->fullname)
+ {
+ result = open (s->fullname, O_RDONLY);
+ if (result >= 0)
+ return result;
+ /* Didn't work -- free old one, try again. */
+ mfree (s->objfile->md, s->fullname);
+ s->fullname = NULL;
+ }
+
+ if (s->dirname != NULL)
+ {
+ /* Replace a path entry of $cdir with the compilation directory name */
+#define cdir_len 5
+ /* We cast strstr's result in case an ANSIhole has made it const,
+ which produces a "required warning" when assigned to a nonconst. */
+ p = (char *)strstr (source_path, "$cdir");
+ if (p && (p == path || p[-1] == ':')
+ && (p[cdir_len] == ':' || p[cdir_len] == '\0')) {
+ int len;
+
+ path = (char *)
+ alloca (strlen (source_path) + 1 + strlen (s->dirname) + 1);
+ len = p - source_path;
+ strncpy (path, source_path, len); /* Before $cdir */
+ strcpy (path + len, s->dirname); /* new stuff */
+ strcat (path + len, source_path + len + cdir_len); /* After $cdir */
+ }
+ }
+
+ result = openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ if (result < 0)
+ {
+ /* Didn't work. Try using just the basename. */
+ p = basename (s->filename);
+ if (p != s->filename)
+ result = openp(path, 0, p, O_RDONLY,0, &s->fullname);
+ }
+ if (result >= 0)
+ {
+ fullname = s -> fullname;
+ s -> fullname = mstrsave (s -> objfile -> md, s -> fullname);
+ free (fullname);
+ }
+ return result;
+}
+
+
+/* Create and initialize the table S->line_charpos that records
+ the positions of the lines in the source file, which is assumed
+ to be open on descriptor DESC.
+ All set S->nlines to the number of such lines. */
+
+static void
+find_source_lines (s, desc)
+ struct symtab *s;
+ int desc;
+{
+ struct stat st;
+ register char *data, *p, *end;
+ int nlines = 0;
+ int lines_allocated = 1000;
+ int *line_charpos;
+ long exec_mtime;
+ int size;
+#ifdef LSEEK_NOT_LINEAR
+ char c;
+#endif
+
+ line_charpos = (int *) xmmalloc (s -> objfile -> md,
+ lines_allocated * sizeof (int));
+ if (fstat (desc, &st) < 0)
+ perror_with_name (s->filename);
+
+ if (exec_bfd) {
+ exec_mtime = bfd_get_mtime(exec_bfd);
+ if (exec_mtime && exec_mtime < st.st_mtime)
+ printf_filtered ("Source file is more recent than executable.\n");
+ }
+
+#ifdef LSEEK_NOT_LINEAR
+ /* Have to read it byte by byte to find out where the chars live */
+
+ line_charpos[0] = tell(desc);
+ nlines = 1;
+ while (myread(desc, &c, 1)>0)
+ {
+ if (c == '\n')
+ {
+ if (nlines == lines_allocated)
+ {
+ lines_allocated *= 2;
+ line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = tell(desc);
+ }
+ }
+
+#else
+ /* st_size might be a large type, but we only support source files whose
+ size fits in an int. FIXME. */
+ size = (int) st.st_size;
+
+#ifdef BROKEN_LARGE_ALLOCA
+ data = (char *) xmalloc (size);
+ make_cleanup (free, data);
+#else
+ data = (char *) alloca (size);
+#endif
+ if (myread (desc, data, size) < 0)
+ perror_with_name (s->filename);
+ end = data + size;
+ p = data;
+ line_charpos[0] = 0;
+ nlines = 1;
+ while (p != end)
+ {
+ if (*p++ == '\n'
+ /* A newline at the end does not start a new line. */
+ && p != end)
+ {
+ if (nlines == lines_allocated)
+ {
+ lines_allocated *= 2;
+ line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = p - data;
+ }
+ }
+#endif
+ s->nlines = nlines;
+ s->line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ nlines * sizeof (int));
+
+}
+
+/* Return the character position of a line LINE in symtab S.
+ Return 0 if anything is invalid. */
+
+#if 0 /* Currently unused */
+
+int
+source_line_charpos (s, line)
+ struct symtab *s;
+ int line;
+{
+ if (!s) return 0;
+ if (!s->line_charpos || line <= 0) return 0;
+ if (line > s->nlines)
+ line = s->nlines;
+ return s->line_charpos[line - 1];
+}
+
+/* Return the line number of character position POS in symtab S. */
+
+int
+source_charpos_line (s, chr)
+ register struct symtab *s;
+ register int chr;
+{
+ register int line = 0;
+ register int *lnp;
+
+ if (s == 0 || s->line_charpos == 0) return 0;
+ lnp = s->line_charpos;
+ /* Files are usually short, so sequential search is Ok */
+ while (line < s->nlines && *lnp <= chr)
+ {
+ line++;
+ lnp++;
+ }
+ if (line >= s->nlines)
+ line = s->nlines;
+ return line;
+}
+
+#endif /* 0 */
+
+
+/* Get full pathname and line number positions for a symtab.
+ Return nonzero if line numbers may have changed.
+ Set *FULLNAME to actual name of the file as found by `openp',
+ or to 0 if the file is not found. */
+
+static int
+get_filename_and_charpos (s, fullname)
+ struct symtab *s;
+ char **fullname;
+{
+ register int desc, linenums_changed = 0;
+
+ desc = open_source_file (s);
+ if (desc < 0)
+ {
+ if (fullname)
+ *fullname = NULL;
+ return 0;
+ }
+ if (fullname)
+ *fullname = s->fullname;
+ if (s->line_charpos == 0) linenums_changed = 1;
+ if (linenums_changed) find_source_lines (s, desc);
+ close (desc);
+ return linenums_changed;
+}
+
+/* Print text describing the full name of the source file S
+ and the line number LINE and its corresponding character position.
+ The text starts with two Ctrl-z so that the Emacs-GDB interface
+ can easily find it.
+
+ MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
+
+ Return 1 if successful, 0 if could not find the file. */
+
+int
+identify_source_line (s, line, mid_statement, pc)
+ struct symtab *s;
+ int line;
+ int mid_statement;
+ CORE_ADDR pc;
+{
+ if (s->line_charpos == 0)
+ get_filename_and_charpos (s, (char **)NULL);
+ if (s->fullname == 0)
+ return 0;
+ if (line > s->nlines)
+ /* Don't index off the end of the line_charpos array. */
+ return 0;
+ printf ("\032\032%s:%d:%d:%s:0x%lx\n", s->fullname,
+ line, s->line_charpos[line - 1],
+ mid_statement ? "middle" : "beg",
+ (unsigned long) pc);
+ current_source_line = line;
+ first_line_listed = line;
+ last_line_listed = line;
+ current_source_symtab = s;
+ return 1;
+}
+
+/* Print source lines from the file of symtab S,
+ starting with line number LINE and stopping before line number STOPLINE. */
+
+void
+print_source_lines (s, line, stopline, noerror)
+ struct symtab *s;
+ int line, stopline;
+ int noerror;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int nlines = stopline - line;
+
+ /* Regardless of whether we can open the file, set current_source_symtab. */
+ current_source_symtab = s;
+ current_source_line = line;
+ first_line_listed = line;
+
+ desc = open_source_file (s);
+ if (desc < 0)
+ {
+ if (! noerror) {
+ char *name = alloca (strlen (s->filename) + 100);
+ sprintf (name, "%s:%d", s->filename, line);
+ print_sys_errmsg (name, errno);
+ }
+ return;
+ }
+
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc);
+
+ if (line < 1 || line > s->nlines)
+ {
+ close (desc);
+ error ("Line number %d out of range; %s has %d lines.",
+ line, s->filename, s->nlines);
+ }
+
+ if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (s->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+
+ while (nlines-- > 0)
+ {
+ c = fgetc (stream);
+ if (c == EOF) break;
+ last_line_listed = current_source_line;
+ printf_filtered ("%d\t", current_source_line++);
+ do
+ {
+ if (c < 040 && c != '\t' && c != '\n' && c != '\r')
+ printf_filtered ("^%c", c + 0100);
+ else if (c == 0177)
+ printf_filtered ("^?");
+ else
+ printf_filtered ("%c", c);
+ } while (c != '\n' && (c = fgetc (stream)) >= 0);
+ }
+
+ fclose (stream);
+}
+
+
+
+/*
+ C++
+ Print a list of files and line numbers which a user may choose from
+ in order to list a function which was specified ambiguously
+ (as with `list classname::overloadedfuncname', for example).
+ The vector in SALS provides the filenames and line numbers.
+ */
+static void
+ambiguous_line_spec (sals)
+ struct symtabs_and_lines *sals;
+{
+ int i;
+
+ for (i = 0; i < sals->nelts; ++i)
+ printf_filtered("file: \"%s\", line number: %d\n",
+ sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
+
+static void
+list_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals, sals_end;
+ struct symtab_and_line sal, sal_end;
+ struct symbol *sym;
+ char *arg1;
+ int no_end = 1;
+ int dummy_end = 0;
+ int dummy_beg = 0;
+ int linenum_beg = 0;
+ char *p;
+
+ if (!have_full_symbols () && !have_partial_symbols())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ /* Pull in a current source symtab if necessary */
+ if (current_source_symtab == 0 &&
+ (arg == 0 || arg[0] == '+' || arg[0] == '-'))
+ select_source_symtab (0);
+
+ /* "l" or "l +" lists next ten lines. */
+
+ if (arg == 0 || STREQ (arg, "+"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab, current_source_line,
+ current_source_line + lines_to_list, 0);
+ return;
+ }
+
+ /* "l -" lists previous ten lines, the ones before the ten just listed. */
+ if (STREQ (arg, "-"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab,
+ max (first_line_listed - lines_to_list, 1),
+ first_line_listed, 0);
+ return;
+ }
+
+ /* Now if there is only one argument, decode it in SAL
+ and set NO_END.
+ If there are two arguments, decode them in SAL and SAL_END
+ and clear NO_END; however, if one of the arguments is blank,
+ set DUMMY_BEG or DUMMY_END to record that fact. */
+
+ arg1 = arg;
+ if (*arg1 == ',')
+ dummy_beg = 1;
+ else
+ {
+ sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+
+ if (! sals.nelts) return; /* C++ */
+ if (sals.nelts > 1)
+ {
+ ambiguous_line_spec (&sals);
+ free (sals.sals);
+ return;
+ }
+
+ sal = sals.sals[0];
+ free (sals.sals);
+ }
+
+ /* Record whether the BEG arg is all digits. */
+
+ for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
+ linenum_beg = (p == arg1);
+
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == ',')
+ {
+ no_end = 0;
+ arg1++;
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == 0)
+ dummy_end = 1;
+ else
+ {
+ if (dummy_beg)
+ sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ else
+ sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ if (sals_end.nelts == 0)
+ return;
+ if (sals_end.nelts > 1)
+ {
+ ambiguous_line_spec (&sals_end);
+ free (sals_end.sals);
+ return;
+ }
+ sal_end = sals_end.sals[0];
+ free (sals_end.sals);
+ }
+ }
+
+ if (*arg1)
+ error ("Junk at end of line specification.");
+
+ if (!no_end && !dummy_beg && !dummy_end
+ && sal.symtab != sal_end.symtab)
+ error ("Specified start and end are in different files.");
+ if (dummy_beg && dummy_end)
+ error ("Two empty args do not say what lines to list.");
+
+ /* if line was specified by address,
+ first print exactly which line, and which file.
+ In this case, sal.symtab == 0 means address is outside
+ of all known source files, not that user failed to give a filename. */
+ if (*arg == '*')
+ {
+ if (sal.symtab == 0)
+ error ("No source file for address %s.",
+ local_hex_string((unsigned long) sal.pc));
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ {
+ printf_filtered ("%s is in ",
+ local_hex_string((unsigned long) sal.pc));
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout);
+ printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
+ }
+ else
+ printf_filtered ("%s is at %s:%d.\n",
+ local_hex_string((unsigned long) sal.pc),
+ sal.symtab->filename, sal.line);
+ }
+
+ /* If line was not specified by just a line number,
+ and it does not imply a symtab, it must be an undebuggable symbol
+ which means no source code. */
+
+ if (! linenum_beg && sal.symtab == 0)
+ error ("No line number known for %s.", arg);
+
+ /* If this command is repeated with RET,
+ turn it into the no-arg variant. */
+
+ if (from_tty)
+ *arg = 0;
+
+ if (dummy_beg && sal_end.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ if (dummy_beg)
+ print_source_lines (sal_end.symtab,
+ max (sal_end.line - (lines_to_list - 1), 1),
+ sal_end.line + 1, 0);
+ else if (sal.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ else if (no_end)
+ print_source_lines (sal.symtab,
+ max (sal.line - (lines_to_list / 2), 1),
+ sal.line + (lines_to_list / 2), 0);
+ else
+ print_source_lines (sal.symtab, sal.line,
+ (dummy_end
+ ? sal.line + lines_to_list
+ : sal_end.line + 1),
+ 0);
+}
+
+/* Print info on range of pc's in a specified line. */
+
+static void
+line_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ CORE_ADDR start_pc, end_pc;
+ int i;
+
+ if (arg == 0)
+ {
+ sal.symtab = current_source_symtab;
+ sal.line = last_line_listed;
+ sals.nelts = 1;
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sals.sals[0] = sal;
+ }
+ else
+ {
+ sals = decode_line_spec_1 (arg, 0);
+
+ dont_repeat ();
+ }
+
+ /* C++ More than one line may have been specified, as when the user
+ specifies an overloaded function name. Print info on them all. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (sal.symtab == 0)
+ {
+ printf_filtered ("No line number information available");
+ if (sal.pc != 0)
+ {
+ /* This is useful for "info line *0x7f34". If we can't tell the
+ user about a source line, at least let them have the symbolic
+ address. */
+ printf_filtered (" for address ");
+ wrap_here (" ");
+ print_address (sal.pc, stdout);
+ }
+ else
+ printf_filtered (".");
+ printf_filtered ("\n");
+ }
+ else if (sal.line > 0
+ && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
+ {
+ if (start_pc == end_pc)
+ {
+ printf_filtered ("Line %d of \"%s\"",
+ sal.line, sal.symtab->filename);
+ wrap_here (" ");
+ printf_filtered (" is at address ");
+ print_address (start_pc, stdout);
+ wrap_here (" ");
+ printf_filtered (" but contains no code.\n");
+ }
+ else
+ {
+ printf_filtered ("Line %d of \"%s\"",
+ sal.line, sal.symtab->filename);
+ wrap_here (" ");
+ printf_filtered (" starts at address ");
+ print_address (start_pc, stdout);
+ wrap_here (" ");
+ printf_filtered (" and ends at ");
+ print_address (end_pc, stdout);
+ printf_filtered (".\n");
+ }
+
+ /* x/i should display this line's code. */
+ set_next_address (start_pc);
+
+ /* Repeating "info line" should do the following line. */
+ last_line_listed = sal.line + 1;
+
+ /* If this is the only line, show the source code. If it could
+ not find the file, don't do anything special. */
+ if (frame_file_full_name && sals.nelts == 1)
+ identify_source_line (sal.symtab, sal.line, 0, start_pc);
+ }
+ else
+ /* Is there any case in which we get here, and have an address
+ which the user would want to see? If we have debugging symbols
+ and no line numbers? */
+ printf_filtered ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+ }
+ free (sals.sals);
+}
+
+/* Commands to search the source file for a regexp. */
+
+/* ARGSUSED */
+static void
+forward_search_command (regex, from_tty)
+ char *regex;
+ int from_tty;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed + 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ /* Search from last_line_listed+1 in current_source_symtab */
+
+ desc = open_source_file (current_source_symtab);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+ while (1) {
+/* FIXME!!! We walk right off the end of buf if we get a long line!!! */
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = getc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = getc (stream)) >= 0);
+
+ /* we now have a source line in buf, null terminate and match */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - lines_to_list / 2, 1);
+ return;
+ }
+ line++;
+ }
+
+ printf_filtered ("Expression not found\n");
+ fclose (stream);
+}
+
+/* ARGSUSED */
+static void
+reverse_search_command (regex, from_tty)
+ char *regex;
+ int from_tty;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed - 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ /* Search from last_line_listed-1 in current_source_symtab */
+
+ desc = open_source_file (current_source_symtab);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+ while (line > 1)
+ {
+/* FIXME!!! We walk right off the end of buf if we get a long line!!! */
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = getc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = getc (stream)) >= 0);
+
+ /* We now have a source line in buf; null terminate and match. */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - lines_to_list / 2, 1);
+ return;
+ }
+ line--;
+ if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ fclose (stream);
+ perror_with_name (current_source_symtab->filename);
+ }
+ }
+
+ printf_filtered ("Expression not found\n");
+ fclose (stream);
+ return;
+}
+
+void
+_initialize_source ()
+{
+ struct cmd_list_element *c;
+ current_source_symtab = 0;
+ init_source_path ();
+
+ /* The intention is to use POSIX Basic Regular Expressions.
+ Always use the GNU regex routine for consistency across all hosts.
+ Our current GNU regex.c does not have all the POSIX features, so this is
+ just an approximation. */
+ re_set_syntax (RE_SYNTAX_GREP);
+
+ c = add_cmd ("directory", class_files, directory_command,
+ "Add directory DIR to beginning of search path for source files.\n\
+Forget cached info on source file locations and line positions.\n\
+DIR can also be $cwd for the current working directory, or $cdir for the\n\
+directory in which the source file was compiled into object code.\n\
+With no argument, reset the search path to $cdir:$cwd, the default.",
+ &cmdlist);
+ c->completer = filename_completer;
+
+ add_cmd ("directories", no_class, show_directories,
+ "Current search path for finding source files.\n\
+$cwd in the path means the current working directory.\n\
+$cdir in the path means the compilation directory of the source file.",
+ &showlist);
+
+ add_info ("source", source_info,
+ "Information about the current source file.");
+
+ add_info ("line", line_info,
+ "Core addresses of the code for a source line.\n\
+Line can be specified as\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+Default is to describe the last source line that was listed.\n\n\
+This sets the default address for \"x\" to the line's first instruction\n\
+so that \"x/i\" suffices to start examining the machine code.\n\
+The address is also stored as the value of \"$_\".");
+
+ add_com ("forward-search", class_files, forward_search_command,
+ "Search for regular expression (see regex(3)) from last line listed.");
+ add_com_alias ("search", "forward-search", class_files, 0);
+
+ add_com ("reverse-search", class_files, reverse_search_command,
+ "Search backward for regular expression (see regex(3)) from last line listed.");
+
+ add_com ("list", class_files, list_command,
+ "List specified function or line.\n\
+With no argument, lists ten more lines after or around previous listing.\n\
+\"list -\" lists the ten lines before a previous ten-line listing.\n\
+One argument specifies a line, and ten lines are listed around that line.\n\
+Two arguments with comma between specify starting and ending lines to list.\n\
+Lines can be specified in these ways:\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, to list around the line containing that address.\n\
+With two args if one is empty it stands for ten lines away from the other arg.");
+ add_com_alias ("l", "list", class_files, 1);
+
+ add_show_from_set
+ (add_set_cmd ("listsize", class_support, var_uinteger,
+ (char *)&lines_to_list,
+ "Set number of source lines gdb will list by default.",
+ &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/stabsread.c b/gnu/usr.bin/gdb/gdb/stabsread.c
new file mode 100644
index 000000000000..e81c314b6def
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.c
@@ -0,0 +1,3770 @@
+/* Support routines for decoding "stabs" debugging information format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Support routines for reading and decoding debugging information in
+ the "stabs" format. This format is used with many systems that use
+ the a.out object file format, as well as some systems that use
+ COFF or ELF where the stabs data is placed in a special section.
+ Avoid placing any object file format specific code in this file. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "aout/stab_gnu.h" /* We always use GNU stabs, not native */
+#include "buildsym.h"
+#include "complaints.h"
+#include "demangle.h"
+
+#include <ctype.h>
+
+/* Ask stabsread.h to define the vars it normally declares `extern'. */
+#define EXTERN /**/
+#include "stabsread.h" /* Our own declarations */
+#undef EXTERN
+
+/* The routines that read and process a complete stabs for a C struct or
+ C++ class pass lists of data member fields and lists of member function
+ fields in an instance of a field_info structure, as defined below.
+ This is part of some reorganization of low level C++ support and is
+ expected to eventually go away... (FIXME) */
+
+struct field_info
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ int visibility;
+ struct field field;
+ } *list;
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ } *fnlist;
+};
+
+static struct type *
+dbx_alloc_type PARAMS ((int [2], struct objfile *));
+
+static long read_huge_number PARAMS ((char **, int, int *));
+
+static struct type *error_type PARAMS ((char **));
+
+static void
+patch_block_stabs PARAMS ((struct pending *, struct pending_stabs *,
+ struct objfile *));
+
+static void
+fix_common_block PARAMS ((struct symbol *, int));
+
+static int
+read_type_number PARAMS ((char **, int *));
+
+static struct type *
+read_range_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_sun_builtin_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_sun_floating_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_enum_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type *
+rs6000_builtin_type PARAMS ((int));
+
+static int
+read_member_functions PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_struct_fields PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_baseclasses PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_tilde_fields PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+attach_fn_fields_to_type PARAMS ((struct field_info *, struct type *));
+
+static int
+attach_fields_to_type PARAMS ((struct field_info *, struct type *,
+ struct objfile *));
+
+static struct type *
+read_struct_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type *
+read_array_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type **
+read_args PARAMS ((char **, int, struct objfile *));
+
+static int
+read_cpp_abbrev PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' };
+static const char vb_name[] = { '_','v','b',CPLUS_MARKER,'\0' };
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+ gives the correct address. Otherwise assume pcc gives the
+ address of the corresponding int, which is not the same on a
+ big-endian machine. */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+#if 0
+/* I think this can go away, all current uses have been removed.
+ GCC emits a few crazy types which can only be distinguished by the
+ name (complex, long long on some machines), but I'd say fix GCC. */
+
+/* During some calls to read_type (and thus to read_range_type), this
+ contains the name of the type being defined. Range types are only
+ used in C as basic types. We use the name to distinguish the otherwise
+ identical basic types "int" and "long" and their unsigned versions.
+ FIXME, this should disappear with better type management. */
+
+static char *long_kludge_name;
+#endif
+
+#if 0
+struct complaint dbx_class_complaint =
+{
+ "encountered DBX-style class variable debugging information.\n\
+You seem to have compiled your program with \
+\"g++ -g0\" instead of \"g++ -g\".\n\
+Therefore GDB will not know about your class variables", 0, 0
+};
+#endif
+
+struct complaint invalid_cpp_abbrev_complaint =
+ {"invalid C++ abbreviation `%s'", 0, 0};
+
+struct complaint invalid_cpp_type_complaint =
+ {"C++ abbreviated type name unknown at symtab pos %d", 0, 0};
+
+struct complaint member_fn_complaint =
+ {"member function type missing, got '%c'", 0, 0};
+
+struct complaint const_vol_complaint =
+ {"const/volatile indicator missing, got '%c'", 0, 0};
+
+struct complaint error_type_complaint =
+ {"debug info mismatch between compiler and debugger", 0, 0};
+
+struct complaint invalid_member_complaint =
+ {"invalid (minimal) member type data format at symtab pos %d.", 0, 0};
+
+struct complaint range_type_base_complaint =
+ {"base type %d of range type is not defined", 0, 0};
+
+struct complaint reg_value_complaint =
+ {"register number too large in symbol %s", 0, 0};
+
+struct complaint vtbl_notfound_complaint =
+ {"virtual function table pointer not found when defining class `%s'", 0, 0};
+
+struct complaint unrecognized_cplus_name_complaint =
+ {"Unknown C++ symbol name `%s'", 0, 0};
+
+struct complaint rs6000_builtin_complaint =
+ {"Unknown builtin type %d", 0, 0};
+
+struct complaint stabs_general_complaint =
+ {"%s", 0, 0};
+
+/* Make a list of forward references which haven't been defined. */
+
+static struct type **undef_types;
+static int undef_types_allocated;
+static int undef_types_length;
+
+/* Check for and handle cretinous stabs symbol name continuation! */
+#define STABS_CONTINUE(pp) \
+ do { \
+ if (**(pp) == '\\') *(pp) = next_symbol_text (); \
+ } while (0)
+
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0];
+ register int index = typenums[1];
+ unsigned old_len;
+ register int real_filenum;
+ register struct header_file *f;
+ int f_orig_length;
+
+ if (filenum == -1) /* -1,-1 is for temporary types. */
+ return 0;
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ {
+ static struct complaint msg = {"\
+Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ 0, 0};
+ complain (&msg, filenum, index, symnum);
+ goto error_return;
+ }
+
+ if (filenum == 0)
+ {
+ if (index < 0)
+ {
+ /* Caller wants address of address of type. We think
+ that negative (rs6k builtin) types will never appear as
+ "lvalues", (nor should they), so we stuff the real type
+ pointer into a temp, and return its address. If referenced,
+ this will do the right thing. */
+ static struct type *temp_type;
+
+ temp_type = rs6000_builtin_type(index);
+ return &temp_type;
+ }
+
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ old_len = type_vector_length;
+ if (old_len == 0)
+ {
+ type_vector_length = INITIAL_TYPE_VECTOR_LENGTH;
+ type_vector = (struct type **)
+ malloc (type_vector_length * sizeof (struct type *));
+ }
+ while (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ }
+ type_vector = (struct type **)
+ xrealloc ((char *) type_vector,
+ (type_vector_length * sizeof (struct type *)));
+ memset (&type_vector[old_len], 0,
+ (type_vector_length - old_len) * sizeof (struct type *));
+ }
+ return (&type_vector[index]);
+ }
+ else
+ {
+ real_filenum = this_object_header_files[filenum];
+
+ if (real_filenum >= n_header_files)
+ {
+ struct type *temp_type;
+ struct type **temp_type_p;
+
+ warning ("GDB internal error: bad real_filenum");
+
+ error_return:
+ temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL);
+ temp_type_p = (struct type **) xmalloc (sizeof (struct type *));
+ *temp_type_p = temp_type;
+ return temp_type_p;
+ }
+
+ f = &header_files[real_filenum];
+
+ f_orig_length = f->length;
+ if (index >= f_orig_length)
+ {
+ while (index >= f->length)
+ {
+ f->length *= 2;
+ }
+ f->vector = (struct type **)
+ xrealloc ((char *) f->vector, f->length * sizeof (struct type *));
+ memset (&f->vector[f_orig_length], 0,
+ (f->length - f_orig_length) * sizeof (struct type *));
+ }
+ return (&f->vector[index]);
+ }
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+ and return the type object.
+ This can create an empty (zeroed) type object.
+ TYPENUMS may be (-1, -1) to return a new type object that is not
+ put into the type vector, and so may not be referred to by number. */
+
+static struct type *
+dbx_alloc_type (typenums, objfile)
+ int typenums[2];
+ struct objfile *objfile;
+{
+ register struct type **type_addr;
+
+ if (typenums[0] == -1)
+ {
+ return (alloc_type (objfile));
+ }
+
+ type_addr = dbx_lookup_type (typenums);
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (*type_addr == 0)
+ {
+ *type_addr = alloc_type (objfile);
+ }
+
+ return (*type_addr);
+}
+
+/* for all the stabs in a given stab vector, build appropriate types
+ and fix their symbols in given symbol vector. */
+
+static void
+patch_block_stabs (symbols, stabs, objfile)
+ struct pending *symbols;
+ struct pending_stabs *stabs;
+ struct objfile *objfile;
+{
+ int ii;
+ char *name;
+ char *pp;
+ struct symbol *sym;
+
+ if (stabs)
+ {
+
+ /* for all the stab entries, find their corresponding symbols and
+ patch their types! */
+
+ for (ii = 0; ii < stabs->count; ++ii)
+ {
+ name = stabs->stab[ii];
+ pp = (char*) strchr (name, ':');
+ sym = find_symbol_in_list (symbols, name, pp-name);
+ if (!sym)
+ {
+ /* On xcoff, if a global is defined and never referenced,
+ ld will remove it from the executable. There is then
+ a N_GSYM stab for it, but no regular (C_EXT) symbol. */
+ sym = (struct symbol *)
+ obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ SYMBOL_NAME (sym) =
+ obstack_copy0 (&objfile->symbol_obstack, name, pp - name);
+ pp += 2;
+ if (*(pp-1) == 'F' || *(pp-1) == 'f')
+ {
+ /* I don't think the linker does this with functions,
+ so as far as I know this is never executed.
+ But it doesn't hurt to check. */
+ SYMBOL_TYPE (sym) =
+ lookup_function_type (read_type (&pp, objfile));
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = read_type (&pp, objfile);
+ }
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ pp += 2;
+ if (*(pp-1) == 'F' || *(pp-1) == 'f')
+ {
+ SYMBOL_TYPE (sym) =
+ lookup_function_type (read_type (&pp, objfile));
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = read_type (&pp, objfile);
+ }
+ }
+ }
+ }
+}
+
+
+/* Read a number by which a type is referred to in dbx data,
+ or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+ Just a single number N is equivalent to (0,N).
+ Return the two numbers by storing them in the vector TYPENUMS.
+ TYPENUMS will then be used as an argument to dbx_lookup_type.
+
+ Returns 0 for success, -1 for error. */
+
+static int
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ int nbits;
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0) return -1;
+ typenums[1] = read_huge_number (pp, ')', &nbits);
+ if (nbits != 0) return -1;
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0) return -1;
+ }
+ return 0;
+}
+
+
+/* To handle GNU C++ typename abbreviation, we need to be able to
+ fill in a type's name as soon as space for that type is allocated.
+ `type_synonym_name' is the name of the type being allocated.
+ It is cleared as soon as it is used (lest all allocated types
+ get this name). */
+
+static char *type_synonym_name;
+
+/* ARGSUSED */
+struct symbol *
+define_symbol (valu, string, desc, type, objfile)
+ CORE_ADDR valu;
+ char *string;
+ int desc;
+ int type;
+ struct objfile *objfile;
+{
+ register struct symbol *sym;
+ char *p = (char *) strchr (string, ':');
+ int deftype;
+ int synonym = 0;
+ register int i;
+
+ /* We would like to eliminate nameless symbols, but keep their types.
+ E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer
+ to type 2, but, should not create a symbol to address that type. Since
+ the symbol will be nameless, there is no way any user can refer to it. */
+
+ int nameless;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ /* Ignore old-style symbols from cc -go */
+ if (p == 0)
+ return 0;
+
+ /* If a nameless stab entry, all we need is the type, not the symbol.
+ e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */
+ nameless = (p == string || ((string[0] == ' ') && (string[1] == ':')));
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ if (processing_gcc_compilation)
+ {
+ /* GCC 2.x puts the line number in desc. SunOS apparently puts in the
+ number of bytes occupied by a type or object, which we ignore. */
+ SYMBOL_LINE(sym) = desc;
+ }
+ else
+ {
+ SYMBOL_LINE(sym) = 0; /* unknown */
+ }
+
+ if (string[0] == CPLUS_MARKER)
+ {
+ /* Special GNU C++ names. */
+ switch (string[1])
+ {
+ case 't':
+ SYMBOL_NAME (sym) = obsavestring ("this", strlen ("this"),
+ &objfile -> symbol_obstack);
+ break;
+
+ case 'v': /* $vtbl_ptr_type */
+ /* Was: SYMBOL_NAME (sym) = "vptr"; */
+ goto normal;
+
+ case 'e':
+ SYMBOL_NAME (sym) = obsavestring ("eh_throw", strlen ("eh_throw"),
+ &objfile -> symbol_obstack);
+ break;
+
+ case '_':
+ /* This was an anonymous type that was never fixed up. */
+ goto normal;
+
+ default:
+ complain (&unrecognized_cplus_name_complaint, string);
+ goto normal; /* Do *something* with it */
+ }
+ }
+ else
+ {
+ normal:
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_NAME (sym) = (char *)
+ obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1));
+ /* Open-coded memcpy--saves function call time. */
+ /* FIXME: Does it really? Try replacing with simple strcpy and
+ try it on an executable with a large symbol table. */
+ /* FIXME: considering that gcc can open code memcpy anyway, I
+ doubt it. xoxorich. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ {
+ *p2++ = *p1++;
+ }
+ *p2++ = '\0';
+ }
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
+ }
+ p++;
+
+ /* Determine the type of name being defined. */
+#if 0
+ /* Getting GDB to correctly skip the symbol on an undefined symbol
+ descriptor and not ever dump core is a very dodgy proposition if
+ we do things this way. I say the acorn RISC machine can just
+ fix their compiler. */
+ /* The Acorn RISC machine's compiler can put out locals that don't
+ start with "234=" or "(3,4)=", so assume anything other than the
+ deftypes we know how to handle is a local. */
+ if (!strchr ("cfFGpPrStTvVXCR", *p))
+#else
+ if (isdigit (*p) || *p == '(' || *p == '-')
+#endif
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ switch (deftype)
+ {
+ case 'c':
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol.
+ SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ if (*p != '=')
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+ ++p;
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *dbl_valu;
+
+ /* FIXME: lookup_fundamental_type is a hack. We should be
+ creating a type especially for the type of float constants.
+ Problem is, what type should it be? We currently have to
+ read this in host floating point format, but what type
+ represents a host format "double"?
+
+ Also, what should the name of this type be? Should we
+ be using 'S' constants (see stabs.texinfo) instead? */
+
+ SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile,
+ FT_DBL_PREC_FLOAT);
+ dbl_valu = (char *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (double));
+ memcpy (dbl_valu, &d, sizeof (double));
+ /* Put it in target byte order, but it's still in host
+ floating point format. */
+ SWAP_TARGET_AND_HOST (dbl_valu, sizeof (double));
+ SYMBOL_VALUE_BYTES (sym) = dbl_valu;
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ case 'i':
+ {
+ /* Defining integer constants this way is kind of silly,
+ since 'e' constants allows the compiler to give not
+ only the value, but the type as well. C has at least
+ int, long, unsigned int, and long long as constant
+ types; other languages probably should have at least
+ unsigned as well as signed constants. */
+
+ /* We just need one int constant type for all objfiles.
+ It doesn't depend on languages or anything (arguably its
+ name should be a language-specific name for a type of
+ that size, but I'm inclined to say that if the compiler
+ wants a nice name for the type, it can use 'e'). */
+ static struct type *int_const_type;
+
+ /* Yes, this is as long as a *host* int. That is because we
+ use atoi. */
+ if (int_const_type == NULL)
+ int_const_type =
+ init_type (TYPE_CODE_INT,
+ sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0,
+ "integer constant",
+ (struct objfile *)NULL);
+ SYMBOL_TYPE (sym) = int_const_type;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'e':
+ /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+ can be represented as integral.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ if (*p != ',')
+ {
+ SYMBOL_TYPE (sym) = error_type (&p);
+ break;
+ }
+ ++p;
+
+ /* If the value is too big to fit in an int (perhaps because
+ it is unsigned), or something like that, we silently get
+ a bogus value. The type and everything else about it is
+ correct. Ideally, we should be using whatever we have
+ available for parsing unsigned and long long values,
+ however. */
+ SYMBOL_VALUE (sym) = atoi (p);
+ }
+ break;
+ default:
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ }
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+
+ case 'C':
+ /* The name of a caught exception. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'f':
+ /* A static function definition. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ /* fall into process_function_types. */
+
+ process_function_types:
+ /* Function result types are described as the result type in stabs.
+ We need to convert this to the function-returning-type-X type
+ in GDB. E.g. "int" is converted to "function returning int". */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC)
+ {
+#if 0
+ /* This code doesn't work -- it needs to realloc and can't. */
+ /* Attempt to set up to record a function prototype... */
+ struct type *new = alloc_type (objfile);
+
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ *new = *lookup_function_type (SYMBOL_TYPE(sym));
+ SYMBOL_TYPE(sym) = new;
+ TYPE_OBJFILE (new) = objfile;
+ in_function_type = new;
+#else
+ SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+#endif
+ }
+ /* fall into process_prototype_types */
+
+ process_prototype_types:
+ /* Sun acc puts declared types of arguments here. We don't care
+ about their actual types (FIXME -- we should remember the whole
+ function prototype), but the list may define some new types
+ that we have to remember, so we must scan it now. */
+ while (*p == ';') {
+ p++;
+ read_type (&p, objfile);
+ }
+ break;
+
+ case 'F':
+ /* A global function definition. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ goto process_function_types;
+
+ case 'G':
+ /* For a class G (global) symbol, it appears that the
+ value is not correct. It is necessary to search for the
+ corresponding linker definition to find the value.
+ These definitions appear at the end of the namelist. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ /* This case is faked by a conditional above,
+ when there is no code letter in the dbx data.
+ Dbx data never actually contains 'l'. */
+ case 'l':
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ if (*p == 'F')
+ /* pF is a two-letter code that means a function parameter in Fortran.
+ The type-number specifies the type of the return value.
+ Translate it into a pointer-to-function type. */
+ {
+ p++;
+ SYMBOL_TYPE (sym)
+ = lookup_pointer_type
+ (lookup_function_type (read_type (&p, objfile)));
+ }
+ else
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* Normally this is a parameter, a LOC_ARG. On the i960, it
+ can also be a LOC_LOCAL_ARG depending on symbol type. */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define DBX_PARM_SYMBOL_CLASS(type) LOC_ARG
+#endif
+
+ SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+#if 0
+ /* This doesn't work yet. */
+ add_param_to_type (&in_function_type, sym);
+#endif
+ add_symbol_to_list (sym, &local_symbols);
+
+#if TARGET_BYTE_ORDER == LITTLE_ENDIAN
+ /* On little-endian machines, this crud is never necessary, and,
+ if the extra bytes contain garbage, is harmful. */
+ break;
+#else /* Big endian. */
+ /* If it's gcc-compiled, if it says `short', believe it. */
+ if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION)
+ break;
+
+#if !BELIEVE_PCC_PROMOTION
+ {
+ /* This is the signed type which arguments get promoted to. */
+ static struct type *pcc_promotion_type;
+ /* This is the unsigned type which arguments get promoted to. */
+ static struct type *pcc_unsigned_promotion_type;
+
+ /* Call it "int" because this is mainly C lossage. */
+ if (pcc_promotion_type == NULL)
+ pcc_promotion_type =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", NULL);
+
+ if (pcc_unsigned_promotion_type == NULL)
+ pcc_unsigned_promotion_type =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", NULL);
+
+#if defined(BELIEVE_PCC_PROMOTION_TYPE)
+ /* This macro is defined on machines (e.g. sparc) where
+ we should believe the type of a PCC 'short' argument,
+ but shouldn't believe the address (the address is
+ the address of the corresponding int). Note that
+ this is only different from the BELIEVE_PCC_PROMOTION
+ case on big-endian machines.
+
+ My guess is that this correction, as opposed to changing
+ the parameter to an 'int' (as done below, for PCC
+ on most machines), is the right thing to do
+ on all machines, but I don't want to risk breaking
+ something that already works. On most PCC machines,
+ the sparc problem doesn't come up because the calling
+ function has to zero the top bytes (not knowing whether
+ the called function wants an int or a short), so there
+ is no practical difference between an int and a short
+ (except perhaps what happens when the GDB user types
+ "print short_arg = 0x10000;").
+
+ Hacked for SunOS 4.1 by gnu@cygnus.com. In 4.1, the compiler
+ actually produces the correct address (we don't need to fix it
+ up). I made this code adapt so that it will offset the symbol
+ if it was pointing at an int-aligned location and not
+ otherwise. This way you can use the same gdb for 4.0.x and
+ 4.1 systems.
+
+ If the parameter is shorter than an int, and is integral
+ (e.g. char, short, or unsigned equivalent), and is claimed to
+ be passed on an integer boundary, don't believe it! Offset the
+ parameter's address to the tail-end of that integer. */
+
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT
+ && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (pcc_promotion_type))
+ {
+ SYMBOL_VALUE (sym) += TYPE_LENGTH (pcc_promotion_type)
+ - TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+ break;
+
+#else /* no BELIEVE_PCC_PROMOTION_TYPE. */
+
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT)
+ {
+ SYMBOL_TYPE (sym) =
+ TYPE_UNSIGNED (SYMBOL_TYPE (sym))
+ ? pcc_unsigned_promotion_type
+ : pcc_promotion_type;
+ }
+ break;
+
+#endif /* no BELIEVE_PCC_PROMOTION_TYPE. */
+ }
+#endif /* !BELIEVE_PCC_PROMOTION. */
+#endif /* Big endian. */
+
+ case 'P':
+ /* acc seems to use P to delare the prototypes of functions that
+ are referenced by this file. gdb is not prepared to deal
+ with this extra information. FIXME, it ought to. */
+ if (type == N_FUN)
+ {
+ read_type (&p, objfile);
+ goto process_prototype_types;
+ }
+ /*FALLTHROUGH*/
+
+ case 'R':
+ /* Parameter which is in a register. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'r':
+ /* Register variable (either global or local). */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (within_function)
+ {
+ /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same
+ name to represent an argument passed in a register.
+ GCC uses 'P' for the same case. So if we find such a symbol pair
+ we combine it into one 'P' symbol.
+ Note that this code illegally combines
+ main(argc) int argc; { register int argc = 1; }
+ but this case is considered pathological and causes a warning
+ from a decent compiler. */
+ if (local_symbols
+ && local_symbols->nsyms > 0)
+ {
+ struct symbol *prev_sym;
+ prev_sym = local_symbols->symbol[local_symbols->nsyms - 1];
+ if (SYMBOL_CLASS (prev_sym) == LOC_ARG
+ && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym)))
+ {
+ SYMBOL_CLASS (prev_sym) = LOC_REGPARM;
+ SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym);
+ sym = prev_sym;
+ break;
+ }
+ }
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+#if 0
+ /* See comment where long_kludge_name is declared. */
+ /* Here we save the name of the symbol for read_range_type, which
+ ends up reading in the basic types. In stabs, unfortunately there
+ is no distinction between "int" and "long" types except their
+ names. Until we work out a saner type policy (eliminating most
+ builtin types and using the names specified in the files), we
+ save away the name so that far away from here in read_range_type,
+ we can examine it to decide between "int" and "long". FIXME. */
+ long_kludge_name = SYMBOL_NAME (sym);
+#endif
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ /* C++ vagaries: we may have a type which is derived from
+ a base type which did not have its name defined when the
+ derived class was output. We fill in the derived class's
+ base part member's name here in that case. */
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) != NULL)
+ if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+ && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+ {
+ int j;
+ for (j = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; j >= 0; j--)
+ if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) == 0)
+ TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) =
+ type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), j));
+ }
+
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL)
+ {
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; PCC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type number
+ defined in the 't' symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym);
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ by 't' which means we are typedef'ing it as well. */
+ synonym = *p == 't';
+
+ if (synonym)
+ {
+ p++;
+ type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)),
+ &objfile -> symbol_obstack);
+ }
+
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+
+ if (synonym)
+ {
+ /* Clone the sym and then modify it. */
+ register struct symbol *typedef_sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ *typedef_sym = *sym;
+ SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (typedef_sym) = valu;
+ SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (typedef_sym, &file_symbols);
+ }
+ break;
+
+ case 'V':
+ /* Static symbol of local scope */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'v':
+ /* Reference parameter */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'X':
+ /* This is used by Sun FORTRAN for "function result value".
+ Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+ that Pascal uses it too, but when I tried it Pascal used
+ "x:3" (local symbol) instead. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ default:
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_VALUE (sym) = 0;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+ }
+
+ /* When passing structures to a function, some systems sometimes pass
+ the address in a register, not the structure itself.
+
+ If REG_STRUCT_HAS_ADDR yields non-zero we have to convert LOC_REGPARM
+ to LOC_REGPARM_ADDR for structures and unions. */
+
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+ && ( (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+
+ return sym;
+}
+
+
+/* Skip rest of this symbol and return an error type.
+
+ General notes on error recovery: error_type always skips to the
+ end of the symbol (modulo cretinous dbx symbol name continuation).
+ Thus code like this:
+
+ if (*(*pp)++ != ';')
+ return error_type (pp);
+
+ is wrong because if *pp starts out pointing at '\0' (typically as the
+ result of an earlier error), it will be incremented to point to the
+ start of the next symbol, which might produce strange results, at least
+ if you run off the end of the string table. Instead use
+
+ if (**pp != ';')
+ return error_type (pp);
+ ++*pp;
+
+ or
+
+ if (**pp != ';')
+ foo = error_type (pp);
+ else
+ ++*pp;
+
+ And in case it isn't obvious, the point of all this hair is so the compiler
+ can define new types and new syntaxes, and old versions of the
+ debugger will be able to read the new symbol tables. */
+
+static struct type *
+error_type (pp)
+ char **pp;
+{
+ complain (&error_type_complaint);
+ while (1)
+ {
+ /* Skip to end of symbol. */
+ while (**pp != '\0')
+ {
+ (*pp)++;
+ }
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if ((*pp)[-1] == '\\')
+ {
+ *pp = next_symbol_text ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ return (builtin_type_error);
+}
+
+
+/* Read type information or a type definition; return the type. Even
+ though this routine accepts either type information or a type
+ definition, the distinction is relevant--some parts of stabsread.c
+ assume that type information starts with a digit, '-', or '(' in
+ deciding whether to call read_type. */
+
+struct type *
+read_type (pp, objfile)
+ register char **pp;
+ struct objfile *objfile;
+{
+ register struct type *type = 0;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+ char type_descriptor;
+
+ /* Size in bits of type if specified by a type attribute, or -1 if
+ there is no size attribute. */
+ int type_size = -1;
+
+ /* Read type number if present. The type number may be omitted.
+ for instance in a two-dimensional array declared with type
+ "ar1;1;10;ar1;1;10;4". */
+ if ((**pp >= '0' && **pp <= '9')
+ || **pp == '('
+ || **pp == '-')
+ {
+ if (read_type_number (pp, typenums) != 0)
+ return error_type (pp);
+
+ /* Type is not being defined here. Either it already exists,
+ or this is a forward reference to it. dbx_alloc_type handles
+ both cases. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums, objfile);
+
+ /* Type is being defined here. */
+ /* Skip the '='. */
+ ++(*pp);
+
+ while (**pp == '@')
+ {
+ char *p = *pp + 1;
+ /* It might be a type attribute or a member type. */
+ if (isdigit (*p) || *p == '(' || *p == '-')
+ /* Member type. */
+ break;
+ else
+ {
+ /* Type attributes. */
+ char *attr = p;
+
+ /* Skip to the semicolon. */
+ while (*p != ';' && *p != '\0')
+ ++p;
+ *pp = p;
+ if (*p == '\0')
+ return error_type (pp);
+ else
+ /* Skip the semicolon. */
+ ++*pp;
+
+ switch (*attr)
+ {
+ case 's':
+ type_size = atoi (attr + 1);
+ if (type_size <= 0)
+ type_size = -1;
+ break;
+ default:
+ /* Ignore unrecognized type attributes, so future compilers
+ can invent new ones. */
+ break;
+ }
+ }
+ }
+ /* Skip the type descriptor, we get it below with (*pp)[-1]. */
+ ++(*pp);
+ }
+ else
+ {
+ /* 'typenums=' not present, type is anonymous. Read and return
+ the definition, but don't put it in the type vector. */
+ typenums[0] = typenums[1] = -1;
+ (*pp)++;
+ }
+
+ type_descriptor = (*pp)[-1];
+ switch (type_descriptor)
+ {
+ case 'x':
+ {
+ enum type_code code;
+
+ /* Used to index through file_symbols. */
+ struct pending *ppt;
+ int i;
+
+ /* Name including "struct", etc. */
+ char *type_name;
+
+ {
+ char *from, *to;
+
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ code = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ code = TYPE_CODE_UNION;
+ break;
+ case 'e':
+ code = TYPE_CODE_ENUM;
+ break;
+ default:
+ return error_type (pp);
+ }
+
+ to = type_name = (char *)
+ obstack_alloc (&objfile -> type_obstack,
+ (((char *) strchr (*pp, ':') - (*pp)) + 1));
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while ((*to++ = *from++) != ':')
+ ;
+ *--to = '\0';
+
+ /* Set the pointer ahead of the name which we just read. */
+ *pp = from;
+ }
+
+ /* Now check to see whether the type has already been declared. */
+ /* This is necessary at least in the case where the
+ program says something like
+ struct foo bar[5];
+ The compiler puts out a cross-reference; we better find
+ set the length of the structure correctly so we can
+ set the length of the array. */
+ for (ppt = file_symbols; ppt; ppt = ppt->next)
+ for (i = 0; i < ppt->nsyms; i++)
+ {
+ struct symbol *sym = ppt->symbol[i];
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+ && STREQ (SYMBOL_NAME (sym), type_name))
+ {
+ obstack_free (&objfile -> type_obstack, type_name);
+ type = SYMBOL_TYPE (sym);
+ return type;
+ }
+ }
+
+ /* Didn't find the type to which this refers, so we must
+ be dealing with a forward reference. Allocate a type
+ structure for it, and keep track of it so we can
+ fill in the rest of the fields when we get the full
+ type. */
+ type = dbx_alloc_type (typenums, objfile);
+ TYPE_CODE (type) = code;
+ TYPE_TAG_NAME (type) = type_name;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+ add_undefined_type (type);
+ return type;
+ }
+
+ case '-': /* RS/6000 built-in type */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+
+ (*pp)--;
+ if (read_type_number (pp, xtypenums) != 0)
+ return error_type (pp);
+
+ if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+ /* It's being defined as itself. That means it is "void". */
+ type = init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+ else
+ {
+ struct type *xtype = *dbx_lookup_type (xtypenums);
+
+ /* This can happen if we had '-' followed by a garbage character,
+ for example. */
+ if (xtype == NULL)
+ return error_type (pp);
+
+ /* The type is being defined to another type. So we copy the type.
+ This loses if we copy a C++ class and so we lose track of how
+ the names are mangled (but g++ doesn't output stabs like this
+ now anyway). */
+
+ type = alloc_type (objfile);
+ memcpy (type, xtype, sizeof (struct type));
+
+ /* The idea behind clearing the names is that the only purpose
+ for defining a type to another type is so that the name of
+ one can be different. So we probably don't need to worry much
+ about the case where the compiler doesn't give a name to the
+ new type. */
+ TYPE_NAME (type) = NULL;
+ TYPE_TAG_NAME (type) = NULL;
+ }
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ /* In the following types, we must be sure to overwrite any existing
+ type that the typenums refer to, rather than allocating a new one
+ and making the typenums point to the new one. This is because there
+ may already be pointers to the existing type (if it had been
+ forward-referenced), and we must change it to a pointer, function,
+ reference, or whatever, *in-place*. */
+
+ case '*':
+ type1 = read_type (pp, objfile);
+ type = make_pointer_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case '&': /* Reference to another type */
+ type1 = read_type (pp, objfile);
+ type = make_reference_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'f': /* Function returning another type */
+ type1 = read_type (pp, objfile);
+ type = make_function_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'k': /* Const qualifier on some type (Sun) */
+ type = read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+ case 'B': /* Volatile qual on some type (Sun) */
+ type = read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+/* FIXME -- we should be doing smash_to_XXX types here. */
+ case '@': /* Member (class & variable) type */
+ {
+ struct type *domain = read_type (pp, objfile);
+ struct type *memtype;
+
+ if (**pp != ',')
+ /* Invalid member type data format. */
+ return error_type (pp);
+ ++*pp;
+
+ memtype = read_type (pp, objfile);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case '#': /* Method (class & fn) type */
+ if ((*pp)[0] == '#')
+ {
+ /* We'll get the parameter types from the name. */
+ struct type *return_type;
+
+ (*pp)++;
+ return_type = read_type (pp, objfile);
+ if (*(*pp)++ != ';')
+ complain (&invalid_member_complaint, symnum);
+ type = allocate_stub_method (return_type);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ struct type *domain = read_type (pp, objfile);
+ struct type *return_type;
+ struct type **args;
+
+ if (**pp != ',')
+ /* Invalid member type data format. */
+ return error_type (pp);
+ else
+ ++(*pp);
+
+ return_type = read_type (pp, objfile);
+ args = read_args (pp, ';', objfile);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_method_type (type, domain, return_type, args);
+ }
+ break;
+
+ case 'r': /* Range type */
+ type = read_range_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'b': /* Sun ACC builtin int type */
+ type = read_sun_builtin_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'R': /* Sun ACC builtin float type */
+ type = read_sun_floating_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e': /* Enumeration type */
+ type = dbx_alloc_type (typenums, objfile);
+ type = read_enum_type (pp, type, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's': /* Struct type */
+ case 'u': /* Union type */
+ type = dbx_alloc_type (typenums, objfile);
+ if (!TYPE_NAME (type))
+ {
+ TYPE_NAME (type) = type_synonym_name;
+ }
+ type_synonym_name = NULL;
+ switch (type_descriptor)
+ {
+ case 's':
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ }
+ type = read_struct_type (pp, type, objfile);
+ break;
+
+ case 'a': /* Array type */
+ if (**pp != 'r')
+ return error_type (pp);
+ ++*pp;
+
+ type = dbx_alloc_type (typenums, objfile);
+ type = read_array_type (pp, type, objfile);
+ break;
+
+ default:
+ --*pp; /* Go back to the symbol in error */
+ /* Particularly important if it was \0! */
+ return error_type (pp);
+ }
+
+ if (type == 0)
+ {
+ warning ("GDB internal error, type is NULL in stabsread.c\n");
+ return error_type (pp);
+ }
+
+ /* Size specified in a type attribute overrides any other size. */
+ if (type_size != -1)
+ TYPE_LENGTH (type) = type_size / TARGET_CHAR_BIT;
+
+ return type;
+}
+
+/* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
+ Return the proper type node for a given builtin type number. */
+
+static struct type *
+rs6000_builtin_type (typenum)
+ int typenum;
+{
+ /* We recognize types numbered from -NUMBER_RECOGNIZED to -1. */
+#define NUMBER_RECOGNIZED 30
+ /* This includes an empty slot for type number -0. */
+ static struct type *negative_types[NUMBER_RECOGNIZED + 1];
+ struct type *rettype = NULL;
+
+ if (typenum >= 0 || typenum < -NUMBER_RECOGNIZED)
+ {
+ complain (&rs6000_builtin_complaint, typenum);
+ return builtin_type_error;
+ }
+ if (negative_types[-typenum] != NULL)
+ return negative_types[-typenum];
+
+#if TARGET_CHAR_BIT != 8
+ #error This code wrong for TARGET_CHAR_BIT not 8
+ /* These definitions all assume that TARGET_CHAR_BIT is 8. I think
+ that if that ever becomes not true, the correct fix will be to
+ make the size in the struct type to be in bits, not in units of
+ TARGET_CHAR_BIT. */
+#endif
+
+ switch (-typenum)
+ {
+ case 1:
+ /* The size of this and all the other types are fixed, defined
+ by the debugging format. If there is a type called "int" which
+ is other than 32 bits, then it should use a new negative type
+ number (or avoid negative type numbers for that case).
+ See stabs.texinfo. */
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "int", NULL);
+ break;
+ case 2:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "char", NULL);
+ break;
+ case 3:
+ rettype = init_type (TYPE_CODE_INT, 2, 0, "short", NULL);
+ break;
+ case 4:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "long", NULL);
+ break;
+ case 5:
+ rettype = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED,
+ "unsigned char", NULL);
+ break;
+ case 6:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "signed char", NULL);
+ break;
+ case 7:
+ rettype = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED,
+ "unsigned short", NULL);
+ break;
+ case 8:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned int", NULL);
+ break;
+ case 9:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned", NULL);
+ case 10:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned long", NULL);
+ break;
+ case 11:
+ rettype = init_type (TYPE_CODE_VOID, 0, 0, "void", NULL);
+ break;
+ case 12:
+ /* IEEE single precision (32 bit). */
+ rettype = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL);
+ break;
+ case 13:
+ /* IEEE double precision (64 bit). */
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL);
+ break;
+ case 14:
+ /* This is an IEEE double on the RS/6000, and different machines with
+ different sizes for "long double" should use different negative
+ type numbers. See stabs.texinfo. */
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "long double", NULL);
+ break;
+ case 15:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "integer", NULL);
+ break;
+ case 16:
+ rettype = init_type (TYPE_CODE_BOOL, 4, 0, "boolean", NULL);
+ break;
+ case 17:
+ rettype = init_type (TYPE_CODE_FLT, 4, 0, "short real", NULL);
+ break;
+ case 18:
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "real", NULL);
+ break;
+ case 19:
+ rettype = init_type (TYPE_CODE_ERROR, 0, 0, "stringptr", NULL);
+ break;
+ case 20:
+ rettype = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED,
+ "character", NULL);
+ break;
+ case 21:
+ rettype = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED,
+ "logical*1", NULL);
+ break;
+ case 22:
+ rettype = init_type (TYPE_CODE_BOOL, 2, TYPE_FLAG_UNSIGNED,
+ "logical*2", NULL);
+ break;
+ case 23:
+ rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED,
+ "logical*4", NULL);
+ break;
+ case 24:
+ rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED,
+ "logical", NULL);
+ break;
+ case 25:
+ /* Complex type consisting of two IEEE single precision values. */
+ rettype = init_type (TYPE_CODE_ERROR, 8, 0, "complex", NULL);
+ break;
+ case 26:
+ /* Complex type consisting of two IEEE double precision values. */
+ rettype = init_type (TYPE_CODE_ERROR, 16, 0, "double complex", NULL);
+ break;
+ case 27:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "integer*1", NULL);
+ break;
+ case 28:
+ rettype = init_type (TYPE_CODE_INT, 2, 0, "integer*2", NULL);
+ break;
+ case 29:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "integer*4", NULL);
+ break;
+ case 30:
+ rettype = init_type (TYPE_CODE_CHAR, 2, 0, "wchar", NULL);
+ break;
+ }
+ negative_types[-typenum] = rettype;
+ return rettype;
+}
+
+/* This page contains subroutines of read_type. */
+
+#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */
+#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */
+
+/* Read member function stabs info for C++ classes. The form of each member
+ function data is:
+
+ NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
+
+ An example with two member functions is:
+
+ afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
+
+ For the case of overloaded operators, the format is op$::*.funcs, where
+ $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
+ name (such as `+=') and `.' marks the end of the operator name.
+
+ Returns 1 for success, 0 for failure. */
+
+static int
+read_member_functions (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ int nfn_fields = 0;
+ int length = 0;
+ /* Total number of member functions defined in this class. If the class
+ defines two `f' functions, and one `g' function, then this will have
+ the value 3. */
+ int total_length = 0;
+ int i;
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ struct fn_field fn_field;
+ } *sublist;
+ struct type *look_ahead_type;
+ struct next_fnfieldlist *new_fnlist;
+ struct next_fnfield *new_sublist;
+ char *main_fn_name;
+ register char *p;
+
+ /* Process each list until we find something that is not a member function
+ or find the end of the functions. */
+
+ while (**pp != ';')
+ {
+ /* We should be positioned at the start of the function name.
+ Scan forward to find the first ':' and if it is not the
+ first of a "::" delimiter, then this is not a member function. */
+ p = *pp;
+ while (*p != ':')
+ {
+ p++;
+ }
+ if (p[1] != ':')
+ {
+ break;
+ }
+
+ sublist = NULL;
+ look_ahead_type = NULL;
+ length = 0;
+
+ new_fnlist = (struct next_fnfieldlist *)
+ xmalloc (sizeof (struct next_fnfieldlist));
+ make_cleanup (free, new_fnlist);
+ memset (new_fnlist, 0, sizeof (struct next_fnfieldlist));
+
+ if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
+ {
+ /* This is a completely wierd case. In order to stuff in the
+ names that might contain colons (the usual name delimiter),
+ Mike Tiemann defined a different name format which is
+ signalled if the identifier is "op$". In that case, the
+ format is "op$::XXXX." where XXXX is the name. This is
+ used for names like "+" or "=". YUUUUUUUK! FIXME! */
+ /* This lets the user type "break operator+".
+ We could just put in "+" as the name, but that wouldn't
+ work for "*". */
+ static char opname[32] = {'o', 'p', CPLUS_MARKER};
+ char *o = opname + 3;
+
+ /* Skip past '::'. */
+ *pp = p + 2;
+
+ STABS_CONTINUE (pp);
+ p = *pp;
+ while (*p != '.')
+ {
+ *o++ = *p++;
+ }
+ main_fn_name = savestring (opname, o - opname);
+ /* Skip past '.' */
+ *pp = p + 1;
+ }
+ else
+ {
+ main_fn_name = savestring (*pp, p - *pp);
+ /* Skip past '::'. */
+ *pp = p + 2;
+ }
+ new_fnlist -> fn_fieldlist.name = main_fn_name;
+
+ do
+ {
+ new_sublist =
+ (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield));
+ make_cleanup (free, new_sublist);
+ memset (new_sublist, 0, sizeof (struct next_fnfield));
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (look_ahead_type == NULL)
+ {
+ /* Normal case. */
+ STABS_CONTINUE (pp);
+
+ new_sublist -> fn_field.type = read_type (pp, objfile);
+ if (**pp != ':')
+ {
+ /* Invalid symtab info for member function. */
+ return 0;
+ }
+ }
+ else
+ {
+ /* g++ version 1 kludge */
+ new_sublist -> fn_field.type = look_ahead_type;
+ look_ahead_type = NULL;
+ }
+
+ (*pp)++;
+ p = *pp;
+ while (*p != ';')
+ {
+ p++;
+ }
+
+ /* If this is just a stub, then we don't have the real name here. */
+
+ if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB)
+ {
+ if (!TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type))
+ TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type) = type;
+ new_sublist -> fn_field.is_stub = 1;
+ }
+ new_sublist -> fn_field.physname = savestring (*pp, p - *pp);
+ *pp = p + 1;
+
+ /* Set this member function's visibility fields. */
+ switch (*(*pp)++)
+ {
+ case VISIBILITY_PRIVATE:
+ new_sublist -> fn_field.is_private = 1;
+ break;
+ case VISIBILITY_PROTECTED:
+ new_sublist -> fn_field.is_protected = 1;
+ break;
+ }
+
+ STABS_CONTINUE (pp);
+ switch (**pp)
+ {
+ case 'A': /* Normal functions. */
+ new_sublist -> fn_field.is_const = 0;
+ new_sublist -> fn_field.is_volatile = 0;
+ (*pp)++;
+ break;
+ case 'B': /* `const' member functions. */
+ new_sublist -> fn_field.is_const = 1;
+ new_sublist -> fn_field.is_volatile = 0;
+ (*pp)++;
+ break;
+ case 'C': /* `volatile' member function. */
+ new_sublist -> fn_field.is_const = 0;
+ new_sublist -> fn_field.is_volatile = 1;
+ (*pp)++;
+ break;
+ case 'D': /* `const volatile' member function. */
+ new_sublist -> fn_field.is_const = 1;
+ new_sublist -> fn_field.is_volatile = 1;
+ (*pp)++;
+ break;
+ case '*': /* File compiled with g++ version 1 -- no info */
+ case '?':
+ case '.':
+ break;
+ default:
+ complain (&const_vol_complaint, **pp);
+ break;
+ }
+
+ switch (*(*pp)++)
+ {
+ case '*':
+ {
+ int nbits;
+ /* virtual member function, followed by index.
+ The sign bit is set to distinguish pointers-to-methods
+ from virtual function indicies. Since the array is
+ in words, the quantity must be shifted left by 1
+ on 16 bit machine, and by 2 on 32 bit machine, forcing
+ the sign bit out, and usable as a valid index into
+ the array. Remove the sign bit here. */
+ new_sublist -> fn_field.voffset =
+ (0x7fffffff & read_huge_number (pp, ';', &nbits)) + 2;
+ if (nbits != 0)
+ return 0;
+
+ STABS_CONTINUE (pp);
+ if (**pp == ';' || **pp == '\0')
+ {
+ /* Must be g++ version 1. */
+ new_sublist -> fn_field.fcontext = 0;
+ }
+ else
+ {
+ /* Figure out from whence this virtual function came.
+ It may belong to virtual function table of
+ one of its baseclasses. */
+ look_ahead_type = read_type (pp, objfile);
+ if (**pp == ':')
+ {
+ /* g++ version 1 overloaded methods. */
+ }
+ else
+ {
+ new_sublist -> fn_field.fcontext = look_ahead_type;
+ if (**pp != ';')
+ {
+ return 0;
+ }
+ else
+ {
+ ++*pp;
+ }
+ look_ahead_type = NULL;
+ }
+ }
+ break;
+ }
+ case '?':
+ /* static member function. */
+ new_sublist -> fn_field.voffset = VOFFSET_STATIC;
+ if (strncmp (new_sublist -> fn_field.physname,
+ main_fn_name, strlen (main_fn_name)))
+ {
+ new_sublist -> fn_field.is_stub = 1;
+ }
+ break;
+
+ default:
+ /* error */
+ complain (&member_fn_complaint, (*pp)[-1]);
+ /* Fall through into normal member function. */
+
+ case '.':
+ /* normal member function. */
+ new_sublist -> fn_field.voffset = 0;
+ new_sublist -> fn_field.fcontext = 0;
+ break;
+ }
+
+ new_sublist -> next = sublist;
+ sublist = new_sublist;
+ length++;
+ STABS_CONTINUE (pp);
+ }
+ while (**pp != ';' && **pp != '\0');
+
+ (*pp)++;
+
+ new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile -> type_obstack,
+ sizeof (struct fn_field) * length);
+ memset (new_fnlist -> fn_fieldlist.fn_fields, 0,
+ sizeof (struct fn_field) * length);
+ for (i = length; (i--, sublist); sublist = sublist -> next)
+ {
+ new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field;
+ }
+
+ new_fnlist -> fn_fieldlist.length = length;
+ new_fnlist -> next = fip -> fnlist;
+ fip -> fnlist = new_fnlist;
+ nfn_fields++;
+ total_length += length;
+ STABS_CONTINUE (pp);
+ }
+
+ if (nfn_fields)
+ {
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields);
+ memset (TYPE_FN_FIELDLISTS (type), 0,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+ }
+
+ return 1;
+}
+
+/* Special GNU C++ name.
+
+ Returns 1 for success, 0 for failure. "failure" means that we can't
+ keep parsing and it's time for error_type(). */
+
+static int
+read_cpp_abbrev (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ char *name;
+ char cpp_abbrev;
+ struct type *context;
+
+ p = *pp;
+ if (*++p == 'v')
+ {
+ name = NULL;
+ cpp_abbrev = *++p;
+
+ *pp = p + 1;
+
+ /* At this point, *pp points to something like "22:23=*22...",
+ where the type number before the ':' is the "context" and
+ everything after is a regular type definition. Lookup the
+ type, find it's name, and construct the field name. */
+
+ context = read_type (pp, objfile);
+
+ switch (cpp_abbrev)
+ {
+ case 'f': /* $vf -- a virtual function table pointer */
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack, vptr_name, "", "");
+ break;
+
+ case 'b': /* $vb -- a virtual bsomethingorother */
+ name = type_name_no_tag (context);
+ if (name == NULL)
+ {
+ complain (&invalid_cpp_type_complaint, symnum);
+ name = "FOO";
+ }
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack, vb_name, name, "");
+ break;
+
+ default:
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack,
+ "INVALID_CPLUSPLUS_ABBREV", "", "");
+ break;
+ }
+
+ /* At this point, *pp points to the ':'. Skip it and read the
+ field type. */
+
+ p = ++(*pp);
+ if (p[-1] != ':')
+ {
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ return 0;
+ }
+ fip->list->field.type = read_type (pp, objfile);
+ if (**pp == ',')
+ (*pp)++; /* Skip the comma. */
+ else
+ return 0;
+
+ {
+ int nbits;
+ fip->list->field.bitpos = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+ /* This field is unpacked. */
+ fip->list->field.bitsize = 0;
+ fip->list->visibility = VISIBILITY_PRIVATE;
+ }
+ else
+ {
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ /* We have no idea what syntax an unrecognized abbrev would have, so
+ better return 0. If we returned 1, we would need to at least advance
+ *pp to avoid an infinite loop. */
+ return 0;
+ }
+ return 1;
+}
+
+static void
+read_one_struct_field (fip, pp, p, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ char *p;
+ struct type *type;
+ struct objfile *objfile;
+{
+ fip -> list -> field.name =
+ obsavestring (*pp, p - *pp, &objfile -> type_obstack);
+ *pp = p + 1;
+
+ /* This means we have a visibility for a field coming. */
+ if (**pp == '/')
+ {
+ (*pp)++;
+ fip -> list -> visibility = *(*pp)++;
+ switch (fip -> list -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ case VISIBILITY_PROTECTED:
+ break;
+
+ case VISIBILITY_PUBLIC:
+ /* Nothing to do */
+ break;
+
+ default:
+ /* Unknown visibility specifier. */
+ complain (&stabs_general_complaint,
+ "unknown visibility specifier");
+ return;
+ break;
+ }
+ }
+ else
+ {
+ /* normal dbx-style format, no explicit visibility */
+ fip -> list -> visibility = VISIBILITY_PUBLIC;
+ }
+
+ fip -> list -> field.type = read_type (pp, objfile);
+ if (**pp == ':')
+ {
+ p = ++(*pp);
+#if 0
+ /* Possible future hook for nested types. */
+ if (**pp == '!')
+ {
+ fip -> list -> field.bitpos = (long)-2; /* nested type */
+ p = ++(*pp);
+ }
+ else
+#endif
+ {
+ /* Static class member. */
+ fip -> list -> field.bitpos = (long) -1;
+ }
+ while (*p != ';')
+ {
+ p++;
+ }
+ fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ return;
+ }
+ else if (**pp != ',')
+ {
+ /* Bad structure-type format. */
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+
+ (*pp)++; /* Skip the comma. */
+
+ {
+ int nbits;
+ fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ }
+#if 0
+ /* FIXME-tiemann: Can't the compiler put out something which
+ lets us distinguish these? (or maybe just not put out anything
+ for the field). What is the story here? What does the compiler
+ really do? Also, patch gdb.texinfo for this case; I document
+ it as a possible problem there. Search for "DBX-style". */
+
+ /* This is wrong because this is identical to the symbols
+ produced for GCC 0-size arrays. For example:
+ typedef union {
+ int num;
+ char str[0];
+ } foo;
+ The code which dumped core in such circumstances should be
+ fixed not to dump core. */
+
+ /* g++ -g0 can put out bitpos & bitsize zero for a static
+ field. This does not give us any way of getting its
+ class, so we can't know its name. But we can just
+ ignore the field so we don't dump core and other nasty
+ stuff. */
+ if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+ {
+ complain (&dbx_class_complaint);
+ /* Ignore this field. */
+ fip -> list = fip -> list -> next;
+ }
+ else
+#endif /* 0 */
+ {
+ /* Detect an unpacked field and mark it as such.
+ dbx gives a bit size for all fields.
+ Note that forward refs cannot be packed,
+ and treat enums as if they had the width of ints. */
+
+ if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT
+ && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ if ((fip -> list -> field.bitsize
+ == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type)
+ || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM
+ && (fip -> list -> field.bitsize
+ == TARGET_INT_BIT)
+ )
+ )
+ &&
+ fip -> list -> field.bitpos % 8 == 0)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ }
+}
+
+
+/* Read struct or class data fields. They have the form:
+
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The optional VISIBILITY is one of:
+
+ '/0' (VISIBILITY_PRIVATE)
+ '/1' (VISIBILITY_PROTECTED)
+ '/2' (VISIBILITY_PUBLIC)
+
+ or nothing, for C style fields with public visibility.
+
+ Returns 1 for success, 0 for failure. */
+
+static int
+read_struct_fields (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ struct nextfield *new;
+
+ /* We better set p right now, in case there are no fields at all... */
+
+ p = *pp;
+
+ /* Read each data member type until we find the terminating ';' at the end of
+ the data member list, or break for some other reason such as finding the
+ start of the member function list. */
+
+ while (**pp != ';')
+ {
+ STABS_CONTINUE (pp);
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+
+ /* Get the field name. */
+ p = *pp;
+ /* If is starts with CPLUS_MARKER it is a special abbreviation, unless
+ the CPLUS_MARKER is followed by an underscore, in which case it is
+ just the name of an anonymous type, which we should handle like any
+ other type name. */
+ if (*p == CPLUS_MARKER && p[1] != '_')
+ {
+ if (!read_cpp_abbrev (fip, pp, type, objfile))
+ return 0;
+ continue;
+ }
+
+ /* Look for the ':' that separates the field name from the field
+ values. Data members are delimited by a single ':', while member
+ functions are delimited by a pair of ':'s. When we hit the member
+ functions (if any), terminate scan loop and return. */
+
+ while (*p != ':' && *p != '\0')
+ {
+ p++;
+ }
+ if (*p == '\0')
+ return 0;
+
+ /* Check to see if we have hit the member functions yet. */
+ if (p[1] == ':')
+ {
+ break;
+ }
+ read_one_struct_field (fip, pp, p, type, objfile);
+ }
+ if (p[1] == ':')
+ {
+ /* chill the list of fields: the last entry (at the head) is a
+ partially constructed entry which we now scrub. */
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* The stabs for C++ derived classes contain baseclass information which
+ is marked by a '!' character after the total size. This function is
+ called when we encounter the baseclass marker, and slurps up all the
+ baseclass information.
+
+ Immediately following the '!' marker is the number of base classes that
+ the class is derived from, followed by information for each base class.
+ For each base class, there are two visibility specifiers, a bit offset
+ to the base class information within the derived class, a reference to
+ the type for the base class, and a terminating semicolon.
+
+ A typical example, with two base classes, would be "!2,020,19;0264,21;".
+ ^^ ^ ^ ^ ^ ^ ^
+ Baseclass information marker __________________|| | | | | | |
+ Number of baseclasses __________________________| | | | | | |
+ Visibility specifiers (2) ________________________| | | | | |
+ Offset in bits from start of class _________________| | | | |
+ Type number for base class ___________________________| | | |
+ Visibility specifiers (2) _______________________________| | |
+ Offset in bits from start of class ________________________| |
+ Type number of base class ____________________________________|
+
+ Return 1 for success, 0 for (error-type-inducing) failure. */
+
+static int
+read_baseclasses (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ int i;
+ struct nextfield *new;
+
+ if (**pp != '!')
+ {
+ return 1;
+ }
+ else
+ {
+ /* Skip the '!' baseclass information marker. */
+ (*pp)++;
+ }
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ {
+ int nbits;
+ TYPE_N_BASECLASSES (type) = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+
+#if 0
+ /* Some stupid compilers have trouble with the following, so break
+ it up into simpler expressions. */
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+ TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+#else
+ {
+ int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type));
+ char *pointer;
+
+ pointer = (char *) TYPE_ALLOC (type, num_bytes);
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer;
+ }
+#endif /* 0 */
+
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+ new -> field.bitsize = 0; /* this should be an unpacked field! */
+
+ STABS_CONTINUE (pp);
+ switch (*(*pp)++)
+ {
+ case '0':
+ /* Nothing to do. */
+ break;
+ case '1':
+ SET_TYPE_FIELD_VIRTUAL (type, i);
+ break;
+ default:
+ /* Bad visibility format. */
+ return 0;
+ }
+
+ new -> visibility = *(*pp)++;
+ switch (new -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ case VISIBILITY_PROTECTED:
+ case VISIBILITY_PUBLIC:
+ break;
+ default:
+ /* Bad visibility format. */
+ return 0;
+ }
+
+ {
+ int nbits;
+
+ /* The remaining value is the bit offset of the portion of the object
+ corresponding to this baseclass. Always zero in the absence of
+ multiple inheritance. */
+
+ new -> field.bitpos = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+
+ /* The last piece of baseclass information is the type of the
+ base class. Read it, and remember it's type name as this
+ field's name. */
+
+ new -> field.type = read_type (pp, objfile);
+ new -> field.name = type_name_no_tag (new -> field.type);
+
+ /* skip trailing ';' and bump count of number of fields seen */
+ if (**pp == ';')
+ (*pp)++;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+/* The tail end of stabs for C++ classes that contain a virtual function
+ pointer contains a tilde, a %, and a type number.
+ The type number refers to the base class (possibly this class itself) which
+ contains the vtable pointer for the current class.
+
+ This function is called when we have parsed all the method declarations,
+ so we can look for the vptr base class info. */
+
+static int
+read_tilde_fields (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+
+ STABS_CONTINUE (pp);
+
+ /* If we are positioned at a ';', then skip it. */
+ if (**pp == ';')
+ {
+ (*pp)++;
+ }
+
+ if (**pp == '~')
+ {
+ (*pp)++;
+
+ if (**pp == '=' || **pp == '+' || **pp == '-')
+ {
+ /* Obsolete flags that used to indicate the presence
+ of constructors and/or destructors. */
+ (*pp)++;
+ }
+
+ /* Read either a '%' or the final ';'. */
+ if (*(*pp)++ == '%')
+ {
+ /* The next number is the type number of the base class
+ (possibly our own class) which supplies the vtable for
+ this class. Parse it out, and search that class to find
+ its vtable pointer, and install those into TYPE_VPTR_BASETYPE
+ and TYPE_VPTR_FIELDNO. */
+
+ struct type *t;
+ int i;
+
+ t = read_type (pp, objfile);
+ p = (*pp)++;
+ while (*p != '\0' && *p != ';')
+ {
+ p++;
+ }
+ if (*p == '\0')
+ {
+ /* Premature end of symbol. */
+ return 0;
+ }
+
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t) /* Our own class provides vtbl ptr */
+ {
+ for (i = TYPE_NFIELDS (t) - 1;
+ i >= TYPE_N_BASECLASSES (t);
+ --i)
+ {
+ if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name,
+ sizeof (vptr_name) - 1))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ goto gotit;
+ }
+ }
+ /* Virtual function table field not found. */
+ complain (&vtbl_notfound_complaint, TYPE_NAME (type));
+ return 0;
+ }
+ else
+ {
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+ }
+
+ gotit:
+ *pp = p + 1;
+ }
+ }
+ return 1;
+}
+
+static int
+attach_fn_fields_to_type (fip, type)
+ struct field_info *fip;
+ register struct type *type;
+{
+ register int n;
+
+ for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
+ {
+ if (TYPE_CODE (TYPE_BASECLASS (type, n)) == TYPE_CODE_UNDEF)
+ {
+ /* @@ Memory leak on objfile -> type_obstack? */
+ return 0;
+ }
+ TYPE_NFN_FIELDS_TOTAL (type) +=
+ TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, n));
+ }
+
+ for (n = TYPE_NFN_FIELDS (type);
+ fip -> fnlist != NULL;
+ fip -> fnlist = fip -> fnlist -> next)
+ {
+ --n; /* Circumvent Sun3 compiler bug */
+ TYPE_FN_FIELDLISTS (type)[n] = fip -> fnlist -> fn_fieldlist;
+ }
+ return 1;
+}
+
+/* Create the vector of fields, and record how big it is.
+ We need this info to record proper virtual function table information
+ for this class's virtual functions. */
+
+static int
+attach_fields_to_type (fip, type, objfile)
+ struct field_info *fip;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register int nfields = 0;
+ register int non_public_fields = 0;
+ register struct nextfield *scan;
+
+ /* Count up the number of fields that we have, as well as taking note of
+ whether or not there are any non-public fields, which requires us to
+ allocate and build the private_field_bits and protected_field_bits
+ bitfields. */
+
+ for (scan = fip -> list; scan != NULL; scan = scan -> next)
+ {
+ nfields++;
+ if (scan -> visibility != VISIBILITY_PUBLIC)
+ {
+ non_public_fields++;
+ }
+ }
+
+ /* Now we know how many fields there are, and whether or not there are any
+ non-public fields. Record the field count, allocate space for the
+ array of fields, and create blank visibility bitfields if necessary. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+ if (non_public_fields)
+ {
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+
+ TYPE_FIELD_PRIVATE_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+ TYPE_FIELD_PROTECTED_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+ }
+
+ /* Copy the saved-up fields into the field vector. Start from the head
+ of the list, adding to the tail of the field array, so that they end
+ up in the same order in the array in which they were added to the list. */
+
+ while (nfields-- > 0)
+ {
+ TYPE_FIELD (type, nfields) = fip -> list -> field;
+ switch (fip -> list -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ SET_TYPE_FIELD_PRIVATE (type, nfields);
+ break;
+
+ case VISIBILITY_PROTECTED:
+ SET_TYPE_FIELD_PROTECTED (type, nfields);
+ break;
+
+ case VISIBILITY_PUBLIC:
+ break;
+
+ default:
+ /* Should warn about this unknown visibility? */
+ break;
+ }
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* Read the description of a structure (or union type) and return an object
+ describing the type.
+
+ PP points to a character pointer that points to the next unconsumed token
+ in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ *PP will point to "4a:1,0,32;;".
+
+ TYPE points to an incomplete type that needs to be filled in.
+
+ OBJFILE points to the current objfile from which the stabs information is
+ being read. (Note that it is redundant in that TYPE also contains a pointer
+ to this same objfile, so it might be a good idea to eliminate it. FIXME).
+ */
+
+static struct type *
+read_struct_type (pp, type, objfile)
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ struct cleanup *back_to;
+ struct field_info fi;
+
+ fi.list = NULL;
+ fi.fnlist = NULL;
+
+ back_to = make_cleanup (null_cleanup, 0);
+
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+ /* First comes the total size in bytes. */
+
+ {
+ int nbits;
+ TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ }
+
+ /* Now read the baseclasses, if any, read the regular C struct or C++
+ class member fields, attach the fields to the type, read the C++
+ member functions, attach them to the type, and then read any tilde
+ field (baseclass specifier for the class holding the main vtable). */
+
+ if (!read_baseclasses (&fi, pp, type, objfile)
+ || !read_struct_fields (&fi, pp, type, objfile)
+ || !attach_fields_to_type (&fi, type, objfile)
+ || !read_member_functions (&fi, pp, type, objfile)
+ || !attach_fn_fields_to_type (&fi, type)
+ || !read_tilde_fields (&fi, pp, type, objfile))
+ {
+ do_cleanups (back_to);
+ return (error_type (pp));
+ }
+
+ do_cleanups (back_to);
+ return (type);
+}
+
+/* Read a definition of an array type,
+ and create and return a suitable type object.
+ Also creates a range type which represents the bounds of that
+ array. */
+
+static struct type *
+read_array_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+ int adjustable = 0;
+ int nbits;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code in
+ to handle this.
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ index_type = read_type (pp, objfile);
+ if (**pp != ';')
+ /* Improper format of array type decl. */
+ return error_type (pp);
+ ++*pp;
+
+ if (!(**pp >= '0' && **pp <= '9'))
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ lower = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (!(**pp >= '0' && **pp <= '9'))
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ upper = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ element_type = read_type (pp, objfile);
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ range_type =
+ create_range_type ((struct type *) NULL, index_type, lower, upper);
+ type = create_array_type (type, element_type, range_type);
+
+ /* If we have an array whose element type is not yet known, but whose
+ bounds *are* known, record it to be adjusted at the end of the file. */
+
+ if (TYPE_LENGTH (element_type) == 0 && !adjustable)
+ {
+ add_undefined_type (type);
+ }
+
+ return type;
+}
+
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+read_enum_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ char *name;
+ register long n;
+ register struct symbol *sym;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+
+#if 0
+ /* FIXME! The stabs produced by Sun CC merrily define things that ought
+ to be file-scope, between N_FN entries, using N_LSYM. What's a mother
+ to do? For now, force all enum values to file scope. */
+ if (within_function)
+ symlist = &local_symbols;
+ else
+#endif
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comma instead of a NAME means the end. */
+ while (**pp && **pp != ';' && **pp != ',')
+ {
+ int nbits;
+ STABS_CONTINUE (pp);
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack);
+ *pp = p + 1;
+ n = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = n;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ }
+
+ if (**pp == ';')
+ (*pp)++; /* Skip the semicolon. */
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = sizeof (int);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+ /* Note that we preserve the order of the enum constants, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ for (syms = *symlist, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++,n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ SYMBOL_TYPE (xsym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+#if 0
+ /* This screws up perfectly good C programs with enums. FIXME. */
+ /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */
+ if(TYPE_NFIELDS(type) == 2 &&
+ ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) ||
+ (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,0),"FALSE"))))
+ TYPE_CODE(type) = TYPE_CODE_BOOL;
+#endif
+
+ return type;
+}
+
+/* Sun's ACC uses a somewhat saner method for specifying the builtin
+ typedefs in every file (for int, long, etc):
+
+ type = b <signed> <width>; <offset>; <nbits>
+ signed = u or s. Possible c in addition to u or s (for char?).
+ offset = offset from high order bit to start bit of type.
+ width is # bytes in object of this type, nbits is # bits in type.
+
+ The width/offset stuff appears to be for small objects stored in
+ larger ones (e.g. `shorts' in `int' registers). We ignore it for now,
+ FIXME. */
+
+static struct type *
+read_sun_builtin_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int type_bits;
+ int nbits;
+ int signed_type;
+
+ switch (**pp)
+ {
+ case 's':
+ signed_type = 1;
+ break;
+ case 'u':
+ signed_type = 0;
+ break;
+ default:
+ return error_type (pp);
+ }
+ (*pp)++;
+
+ /* For some odd reason, all forms of char put a c here. This is strange
+ because no other type has this honor. We can safely ignore this because
+ we actually determine 'char'acterness by the number of bits specified in
+ the descriptor. */
+
+ if (**pp == 'c')
+ (*pp)++;
+
+ /* The first number appears to be the number of bytes occupied
+ by this type, except that unsigned short is 4 instead of 2.
+ Since this information is redundant with the third number,
+ we will ignore it. */
+ read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The second number is always 0, so ignore it too. */
+ read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The third number is the number of bits for this type. */
+ type_bits = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+#if 0
+ /* FIXME. Here we should just be able to make a type of the right
+ number of bits and signedness. FIXME. */
+
+ if (type_bits == TARGET_LONG_LONG_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_LONG_LONG: FT_UNSIGNED_LONG_LONG));
+
+ if (type_bits == TARGET_INT_BIT)
+ {
+ /* FIXME -- the only way to distinguish `int' from `long'
+ is to look at its name! */
+ if (signed_type)
+ {
+ if (long_kludge_name && long_kludge_name[0] == 'l' /* long */)
+ return lookup_fundamental_type (objfile, FT_LONG);
+ else
+ return lookup_fundamental_type (objfile, FT_INTEGER);
+ }
+ else
+ {
+ if (long_kludge_name
+ && ((long_kludge_name[0] == 'u' /* unsigned */ &&
+ long_kludge_name[9] == 'l' /* long */)
+ || (long_kludge_name[0] == 'l' /* long unsigned */)))
+ return lookup_fundamental_type (objfile, FT_UNSIGNED_LONG);
+ else
+ return lookup_fundamental_type (objfile, FT_UNSIGNED_INTEGER);
+ }
+ }
+
+ if (type_bits == TARGET_SHORT_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_SHORT: FT_UNSIGNED_SHORT));
+
+ if (type_bits == TARGET_CHAR_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_CHAR: FT_UNSIGNED_CHAR));
+
+ if (type_bits == 0)
+ return lookup_fundamental_type (objfile, FT_VOID);
+
+ return error_type (pp);
+#else
+ return init_type (type_bits == 0 ? TYPE_CODE_VOID : TYPE_CODE_INT,
+ type_bits / TARGET_CHAR_BIT,
+ signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL,
+ objfile);
+#endif
+}
+
+static struct type *
+read_sun_floating_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int nbits;
+ int details;
+ int nbytes;
+
+ /* The first number has more details about the type, for example
+ FN_COMPLEX. */
+ details = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The second number is the number of bytes occupied by this type */
+ nbytes = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (details == NF_COMPLEX || details == NF_COMPLEX16
+ || details == NF_COMPLEX32)
+ /* This is a type we can't handle, but we do know the size.
+ We also will be able to give it a name. */
+ return init_type (TYPE_CODE_ERROR, nbytes, 0, NULL, objfile);
+
+ return init_type (TYPE_CODE_FLT, nbytes, 0, NULL, objfile);
+}
+
+/* Read a number from the string pointed to by *PP.
+ The value of *PP is advanced over the number.
+ If END is nonzero, the character that ends the
+ number must match END, or an error happens;
+ and that character is skipped if it does match.
+ If END is zero, *PP is left pointing to that character.
+
+ If the number fits in a long, set *BITS to 0 and return the value.
+ If not, set *BITS to be the number of bits in the number and return 0.
+
+ If encounter garbage, set *BITS to -1 and return 0. */
+
+static long
+read_huge_number (pp, end, bits)
+ char **pp;
+ int end;
+ int *bits;
+{
+ char *p = *pp;
+ int sign = 1;
+ long n = 0;
+ int radix = 10;
+ char overflow = 0;
+ int nbits = 0;
+ int c;
+ long upper_limit;
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Leading zero means octal. GCC uses this to output values larger
+ than an int (because that would be hard in decimal). */
+ if (*p == '0')
+ {
+ radix = 8;
+ p++;
+ }
+
+ upper_limit = LONG_MAX / radix;
+ while ((c = *p++) >= '0' && c < ('0' + radix))
+ {
+ if (n <= upper_limit)
+ {
+ n *= radix;
+ n += c - '0'; /* FIXME this overflows anyway */
+ }
+ else
+ overflow = 1;
+
+ /* This depends on large values being output in octal, which is
+ what GCC does. */
+ if (radix == 8)
+ {
+ if (nbits == 0)
+ {
+ if (c == '0')
+ /* Ignore leading zeroes. */
+ ;
+ else if (c == '1')
+ nbits = 1;
+ else if (c == '2' || c == '3')
+ nbits = 2;
+ else
+ nbits = 3;
+ }
+ else
+ nbits += 3;
+ }
+ }
+ if (end)
+ {
+ if (c && c != end)
+ {
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+ }
+ else
+ --p;
+
+ *pp = p;
+ if (overflow)
+ {
+ if (nbits == 0)
+ {
+ /* Large decimal constants are an error (because it is hard to
+ count how many bits are in them). */
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+
+ /* -0x7f is the same as 0x80. So deal with it by adding one to
+ the number of bits. */
+ if (sign == -1)
+ ++nbits;
+ if (bits)
+ *bits = nbits;
+ }
+ else
+ {
+ if (bits)
+ *bits = 0;
+ return n * sign;
+ }
+ /* It's *BITS which has the interesting information. */
+ return 0;
+}
+
+static struct type *
+read_range_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int rangenums[2];
+ long n2, n3;
+ int n2bits, n3bits;
+ int self_subrange;
+ struct type *result_type;
+ struct type *index_type;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ /* FIXME: according to stabs.texinfo and AIX doc, this can be a type-id
+ not just a type number. */
+ if (read_type_number (pp, rangenums) != 0)
+ return error_type (pp);
+ self_subrange = (rangenums[0] == typenums[0] &&
+ rangenums[1] == typenums[1]);
+
+ /* A semicolon should now follow; skip it. */
+ if (**pp == ';')
+ (*pp)++;
+
+ /* The remaining two operands are usually lower and upper bounds
+ of the range. But in some special cases they mean something else. */
+ n2 = read_huge_number (pp, ';', &n2bits);
+ n3 = read_huge_number (pp, ';', &n3bits);
+
+ if (n2bits == -1 || n3bits == -1)
+ return error_type (pp);
+
+ /* If limits are huge, must be large integral type. */
+ if (n2bits != 0 || n3bits != 0)
+ {
+ char got_signed = 0;
+ char got_unsigned = 0;
+ /* Number of bits in the type. */
+ int nbits = 0;
+
+ /* Range from 0 to <large number> is an unsigned large integral type. */
+ if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+ {
+ got_unsigned = 1;
+ nbits = n3bits;
+ }
+ /* Range from <large number> to <large number>-1 is a large signed
+ integral type. Take care of the case where <large number> doesn't
+ fit in a long but <large number>-1 does. */
+ else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+ || (n2bits != 0 && n3bits == 0
+ && (n2bits == sizeof (long) * HOST_CHAR_BIT)
+ && n3 == LONG_MAX))
+ {
+ got_signed = 1;
+ nbits = n2bits;
+ }
+
+ if (got_signed || got_unsigned)
+ {
+ return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT,
+ got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL,
+ objfile);
+ }
+ else
+ return error_type (pp);
+ }
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+
+ /* If n3 is zero and n2 is not, we want a floating type,
+ and n2 is the width in bytes.
+
+ Fortran programs appear to use this for complex types also,
+ and they give no way to distinguish between double and single-complex!
+
+ GDB does not have complex types.
+
+ Just return the complex as a float of that size. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile);
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ /* It is unsigned int or unsigned long. */
+ /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5
+ compatibility hack. */
+ return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, NULL, objfile);
+ }
+
+ /* Special case: char is defined (Who knows why) as a subrange of
+ itself with range 0-127. */
+ else if (self_subrange && n2 == 0 && n3 == 127)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+
+ /* We used to do this only for subrange of self or subrange of int. */
+ else if (n2 == 0)
+ {
+ if (n3 < 0)
+ /* n3 actually gives the size. */
+ return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED,
+ NULL, objfile);
+ if (n3 == 0xff)
+ return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile);
+ if (n3 == 0xffff)
+ return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile);
+
+ /* -1 is used for the upper bound of (4 byte) "unsigned int" and
+ "unsigned long", and we already checked for that,
+ so don't need to test for it here. */
+ }
+ /* I think this is for Convex "long long". Since I don't know whether
+ Convex sets self_subrange, I also accept that particular size regardless
+ of self_subrange. */
+ else if (n3 == 0 && n2 < 0
+ && (self_subrange
+ || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT))
+ return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile);
+ else if (n2 == -n3 -1)
+ {
+ if (n3 == 0x7f)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+ if (n3 == 0x7fff)
+ return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile);
+ if (n3 == 0x7fffffff)
+ return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile);
+ }
+
+ /* We have a real range type on our hands. Allocate space and
+ return a real pointer. */
+
+ /* At this point I don't have the faintest idea how to deal with
+ a self_subrange type; I'm going to assume that this is used
+ as an idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ return error_type (pp);
+
+ index_type = *dbx_lookup_type (rangenums);
+ if (index_type == NULL)
+ {
+ /* Does this actually ever happen? Is that why we are worrying
+ about dealing with it rather than just calling error_type? */
+
+ static struct type *range_type_index;
+
+ complain (&range_type_base_complaint, rangenums[1]);
+ if (range_type_index == NULL)
+ range_type_index =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "range type index type", NULL);
+ index_type = range_type_index;
+ }
+
+ result_type = create_range_type ((struct type *) NULL, index_type, n2, n3);
+ return (result_type);
+}
+
+/* Read in an argument list. This is a list of types, separated by commas
+ and terminated with END. Return the list of types read in, or (struct type
+ **)-1 if there is an error. */
+
+static struct type **
+read_args (pp, end, objfile)
+ char **pp;
+ int end;
+ struct objfile *objfile;
+{
+ /* FIXME! Remove this arbitrary limit! */
+ struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+ int n = 0;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ /* Invalid argument list: no ','. */
+ return (struct type **)-1;
+ (*pp)++;
+ STABS_CONTINUE (pp);
+ types[n++] = read_type (pp, objfile);
+ }
+ (*pp)++; /* get past `end' (the ':' character) */
+
+ if (n == 1)
+ {
+ rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+ }
+ else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+ {
+ rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+ memset (rval + n, 0, sizeof (struct type *));
+ }
+ else
+ {
+ rval = (struct type **) xmalloc (n * sizeof (struct type *));
+ }
+ memcpy (rval, types, n * sizeof (struct type *));
+ return rval;
+}
+
+/* Common block handling. */
+
+/* List of symbols declared since the last BCOMM. This list is a tail
+ of local_symbols. When ECOMM is seen, the symbols on the list
+ are noted so their proper addresses can be filled in later,
+ using the common block base address gotten from the assembler
+ stabs. */
+
+static struct pending *common_block;
+static int common_block_i;
+
+/* Name of the current common block. We get it from the BCOMM instead of the
+ ECOMM to match IBM documentation (even though IBM puts the name both places
+ like everyone else). */
+static char *common_block_name;
+
+/* Process a N_BCOMM symbol. The storage for NAME is not guaranteed
+ to remain after this function returns. */
+
+void
+common_block_start (name, objfile)
+ char *name;
+ struct objfile *objfile;
+{
+ if (common_block_name != NULL)
+ {
+ static struct complaint msg = {
+ "Invalid symbol data: common block within common block",
+ 0, 0};
+ complain (&msg);
+ }
+ common_block = local_symbols;
+ common_block_i = local_symbols ? local_symbols->nsyms : 0;
+ common_block_name = obsavestring (name, strlen (name),
+ &objfile -> symbol_obstack);
+}
+
+/* Process a N_ECOMM symbol. */
+
+void
+common_block_end (objfile)
+ struct objfile *objfile;
+{
+ /* Symbols declared since the BCOMM are to have the common block
+ start address added in when we know it. common_block and
+ common_block_i point to the first symbol after the BCOMM in
+ the local_symbols list; copy the list and hang it off the
+ symbol for the common block name for later fixup. */
+ int i;
+ struct symbol *sym;
+ struct pending *new = 0;
+ struct pending *next;
+ int j;
+
+ if (common_block_name == NULL)
+ {
+ static struct complaint msg = {"ECOMM symbol unmatched by BCOMM", 0, 0};
+ complain (&msg);
+ return;
+ }
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = common_block_name;
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+
+ /* Now we copy all the symbols which have been defined since the BCOMM. */
+
+ /* Copy all the struct pendings before common_block. */
+ for (next = local_symbols;
+ next != NULL && next != common_block;
+ next = next->next)
+ {
+ for (j = 0; j < next->nsyms; j++)
+ add_symbol_to_list (next->symbol[j], &new);
+ }
+
+ /* Copy however much of COMMON_BLOCK we need. If COMMON_BLOCK is
+ NULL, it means copy all the local symbols (which we already did
+ above). */
+
+ if (common_block != NULL)
+ for (j = common_block_i; j < common_block->nsyms; j++)
+ add_symbol_to_list (common_block->symbol[j], &new);
+
+ SYMBOL_NAMESPACE (sym) = (enum namespace)((long) new);
+
+ /* Should we be putting local_symbols back to what it was?
+ Does it matter? */
+
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ common_block_name = NULL;
+}
+
+/* Add a common block's start address to the offset of each symbol
+ declared to be in it (by being between a BCOMM/ECOMM pair that uses
+ the common block name). */
+
+static void
+fix_common_block (sym, valu)
+ struct symbol *sym;
+ int valu;
+{
+ struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym);
+ for ( ; next; next = next->next)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu;
+ }
+}
+
+
+
+/* What about types defined as forward references inside of a small lexical
+ scope? */
+/* Add a type to the list of undefined types to be checked through
+ once this file has been read in. */
+
+void
+add_undefined_type (type)
+ struct type *type;
+{
+ if (undef_types_length == undef_types_allocated)
+ {
+ undef_types_allocated *= 2;
+ undef_types = (struct type **)
+ xrealloc ((char *) undef_types,
+ undef_types_allocated * sizeof (struct type *));
+ }
+ undef_types[undef_types_length++] = type;
+}
+
+/* Go through each undefined type, see if it's still undefined, and fix it
+ up if possible. We have two kinds of undefined types:
+
+ TYPE_CODE_ARRAY: Array whose target type wasn't defined yet.
+ Fix: update array length using the element bounds
+ and the target type's length.
+ TYPE_CODE_STRUCT, TYPE_CODE_UNION: Structure whose fields were not
+ yet defined at the time a pointer to it was made.
+ Fix: Do a full lookup on the struct/union tag. */
+void
+cleanup_undefined_types ()
+{
+ struct type **type;
+
+ for (type = undef_types; type < undef_types + undef_types_length; type++)
+ {
+ switch (TYPE_CODE (*type))
+ {
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ {
+ /* Check if it has been defined since. */
+ if (TYPE_FLAGS (*type) & TYPE_FLAG_STUB)
+ {
+ struct pending *ppt;
+ int i;
+ /* Name of the type, without "struct" or "union" */
+ char *typename = TYPE_TAG_NAME (*type);
+
+ if (typename == NULL)
+ {
+ static struct complaint msg = {"need a type name", 0, 0};
+ complain (&msg);
+ break;
+ }
+ for (ppt = file_symbols; ppt; ppt = ppt->next)
+ {
+ for (i = 0; i < ppt->nsyms; i++)
+ {
+ struct symbol *sym = ppt->symbol[i];
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
+ TYPE_CODE (*type))
+ && STREQ (SYMBOL_NAME (sym), typename))
+ {
+ memcpy (*type, SYMBOL_TYPE (sym),
+ sizeof (struct type));
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case TYPE_CODE_ARRAY:
+ {
+ struct type *range_type;
+ int lower, upper;
+
+ if (TYPE_LENGTH (*type) != 0) /* Better be unknown */
+ goto badtype;
+ if (TYPE_NFIELDS (*type) != 1)
+ goto badtype;
+ range_type = TYPE_FIELD_TYPE (*type, 0);
+ if (TYPE_CODE (range_type) != TYPE_CODE_RANGE)
+ goto badtype;
+
+ /* Now recompute the length of the array type, based on its
+ number of elements and the target type's length. */
+ lower = TYPE_FIELD_BITPOS (range_type, 0);
+ upper = TYPE_FIELD_BITPOS (range_type, 1);
+ TYPE_LENGTH (*type) = (upper - lower + 1)
+ * TYPE_LENGTH (TYPE_TARGET_TYPE (*type));
+ }
+ break;
+
+ default:
+ badtype:
+ {
+ static struct complaint msg = {"\
+GDB internal error. cleanup_undefined_types with bad type %d.", 0, 0};
+ complain (&msg, TYPE_CODE (*type));
+ }
+ break;
+ }
+ }
+ undef_types_length = 0;
+}
+
+/* Scan through all of the global symbols defined in the object file,
+ assigning values to the debugging symbols that need to be assigned
+ to. Get these symbols from the minimal symbol table. */
+
+void
+scan_file_globals (objfile)
+ struct objfile *objfile;
+{
+ int hash;
+ struct minimal_symbol *msymbol;
+ struct symbol *sym, *prev;
+
+ if (objfile->msymbols == 0) /* Beware the null file. */
+ return;
+
+ for (msymbol = objfile -> msymbols; SYMBOL_NAME (msymbol) != NULL; msymbol++)
+ {
+ QUIT;
+
+ prev = NULL;
+
+ /* Get the hash index and check all the symbols
+ under that hash index. */
+
+ hash = hashname (SYMBOL_NAME (msymbol));
+
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (SYMBOL_NAME (msymbol)[0] == SYMBOL_NAME (sym)[0] &&
+ STREQ(SYMBOL_NAME (msymbol) + 1, SYMBOL_NAME (sym) + 1))
+ {
+ /* Splice this symbol out of the hash chain and
+ assign the value we have to it. */
+ if (prev)
+ {
+ SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+ }
+ else
+ {
+ global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+ }
+
+ /* Check to see whether we need to fix up a common block. */
+ /* Note: this code might be executed several times for
+ the same symbol if there are multiple references. */
+
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ fix_common_block (sym, SYMBOL_VALUE_ADDRESS (msymbol));
+ }
+ else
+ {
+ SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+
+ if (prev)
+ {
+ sym = SYMBOL_VALUE_CHAIN (prev);
+ }
+ else
+ {
+ sym = global_sym_chain[hash];
+ }
+ }
+ else
+ {
+ prev = sym;
+ sym = SYMBOL_VALUE_CHAIN (sym);
+ }
+ }
+ }
+}
+
+/* Initialize anything that needs initializing when starting to read
+ a fresh piece of a symbol file, e.g. reading in the stuff corresponding
+ to a psymtab. */
+
+void
+stabsread_init ()
+{
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+void
+stabsread_new_init ()
+{
+ /* Empty the hash table of global syms looking for values. */
+ memset (global_sym_chain, 0, sizeof (global_sym_chain));
+}
+
+/* Initialize anything that needs initializing at the same time as
+ start_symtab() is called. */
+
+void start_stabs ()
+{
+ global_stabs = NULL; /* AIX COFF */
+ /* Leave FILENUM of 0 free for builtin types and this file's types. */
+ n_this_object_header_files = 1;
+ type_vector_length = 0;
+ type_vector = (struct type **) 0;
+
+ /* FIXME: If common_block_name is not already NULL, we should complain(). */
+ common_block_name = NULL;
+}
+
+/* Call after end_symtab() */
+
+void end_stabs ()
+{
+ if (type_vector)
+ {
+ free ((char *) type_vector);
+ }
+ type_vector = 0;
+ type_vector_length = 0;
+ previous_stab_code = 0;
+}
+
+void
+finish_global_stabs (objfile)
+ struct objfile *objfile;
+{
+ if (global_stabs)
+ {
+ patch_block_stabs (global_symbols, global_stabs, objfile);
+ free ((PTR) global_stabs);
+ global_stabs = NULL;
+ }
+}
+
+/* Initializer for this module */
+
+void
+_initialize_stabsread ()
+{
+ undef_types_allocated = 20;
+ undef_types_length = 0;
+ undef_types = (struct type **)
+ xmalloc (undef_types_allocated * sizeof (struct type *));
+}
diff --git a/gnu/usr.bin/gdb/gdb/stabsread.h b/gnu/usr.bin/gdb/gdb/stabsread.h
new file mode 100644
index 000000000000..3b890d805840
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.h
@@ -0,0 +1,194 @@
+/* Include file for stabs debugging format support functions.
+ Copyright 1986-1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Definitions, prototypes, etc for stabs debugging format support
+ functions.
+
+ Variables declared in this file can be defined by #define-ing
+ the name EXTERN to null. It is used to declare variables that
+ are normally extern, but which get defined in a single module
+ using this technique. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */
+
+#ifndef STAB_REG_TO_REGNUM
+#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
+#endif
+
+/* Hash table of global symbols whose values are not known yet.
+ They are chained thru the SYMBOL_VALUE_CHAIN, since we don't
+ have the correct data for that slot yet.
+
+ The use of the LOC_BLOCK code in this chain is nonstandard--
+ it refers to a FORTRAN common block rather than the usual meaning. */
+
+EXTERN struct symbol *global_sym_chain[HASHSIZE];
+
+extern void common_block_start PARAMS ((char *, struct objfile *));
+extern void common_block_end PARAMS ((struct objfile *));
+
+/* Kludge for xcoffread.c */
+
+struct pending_stabs
+{
+ int count;
+ int length;
+ char *stab[1];
+};
+
+EXTERN struct pending_stabs *global_stabs;
+
+/* The type code that process_one_symbol saw on its previous invocation.
+ Used to detect pairs of N_SO symbols. */
+
+EXTERN int previous_stab_code;
+
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+ in that header file.
+
+ header_files maps header file names to their type tables.
+ It is a vector of n_header_files elements.
+ Each element describes one header file.
+ It contains a vector of types.
+
+ Sometimes it can happen that the same header file produces
+ different results when included in different places.
+ This can result from conditionals or from different
+ things done before including the file.
+ When this happens, there are multiple entries for the file in this table,
+ one entry for each distinct set of results.
+ The entries are distinguished by the INSTANCE field.
+ The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+ used to match header-file references to their corresponding data. */
+
+struct header_file
+{
+
+ /* Name of header file */
+
+ char *name;
+
+ /* Numeric code distinguishing instances of one header file that produced
+ different results when included. It comes from the N_BINCL or N_EXCL. */
+
+ int instance;
+
+ /* Pointer to vector of types */
+
+ struct type **vector;
+
+ /* Allocated length (# elts) of that vector */
+
+ int length;
+
+};
+
+EXTERN struct header_file *header_files;
+
+EXTERN int n_header_files;
+
+EXTERN int n_allocated_header_files;
+
+/* Within each object file, various header files are assigned numbers.
+ A type is defined or referred to with a pair of numbers
+ (FILENUM,TYPENUM) where FILENUM is the number of the header file
+ and TYPENUM is the number within that header file.
+ TYPENUM is the index within the vector of types for that header file.
+
+ FILENUM == 1 is special; it refers to the main source of the object file,
+ and not to any header file. FILENUM != 1 is interpreted by looking it up
+ in the following table, which contains indices in header_files. */
+
+EXTERN int *this_object_header_files;
+
+EXTERN int n_this_object_header_files;
+
+EXTERN int n_allocated_this_object_header_files;
+
+extern struct complaint unknown_symtype_complaint;
+extern struct complaint unknown_symchar_complaint;
+
+extern struct type *
+read_type PARAMS ((char **, struct objfile *));
+
+extern void
+cleanup_undefined_types PARAMS ((void));
+
+extern struct type **
+dbx_lookup_type PARAMS ((int [2]));
+
+extern long
+read_number PARAMS ((char **, int));
+
+extern void
+add_undefined_type PARAMS ((struct type *));
+
+extern struct symbol *
+define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *));
+
+extern void
+stabsread_init PARAMS ((void));
+
+extern void
+stabsread_new_init PARAMS ((void));
+
+extern void
+start_stabs PARAMS ((void));
+
+extern void
+end_stabs PARAMS ((void));
+
+extern void
+finish_global_stabs PARAMS ((struct objfile *objfile));
+
+/* Functions exported by dbxread.c. These are not in stabsread.h because
+ they are only used by some stabs readers. */
+
+extern struct partial_symtab *
+start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *,
+ CORE_ADDR, int, struct partial_symbol *,
+ struct partial_symbol *));
+
+extern struct partial_symtab *
+end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR,
+ struct partial_symtab **, int));
+
+extern void
+process_one_symbol PARAMS ((int, int, CORE_ADDR, char *,
+ struct section_offsets *, struct objfile *));
+
+extern void
+elfstab_build_psymtabs PARAMS ((struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline,
+ file_ptr staboff, unsigned int stabsize,
+ file_ptr stabstroffset,
+ unsigned int stabstrsize));
+
+extern void
+pastab_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *,
+ int));
+
+#undef EXTERN
diff --git a/gnu/usr.bin/gdb/gdb/stack.c b/gnu/usr.bin/gdb/gdb/stack.c
new file mode 100644
index 000000000000..6fdd8c181245
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stack.c
@@ -0,0 +1,1379 @@
+/* Print and select stack frames for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "value.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "frame.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "inferior.h"
+
+static void
+return_command PARAMS ((char *, int));
+
+static void
+down_command PARAMS ((char *, int));
+
+static void
+down_silently_command PARAMS ((char *, int));
+
+static void
+up_command PARAMS ((char *, int));
+
+static void
+up_silently_command PARAMS ((char *, int));
+
+static void
+frame_command PARAMS ((char *, int));
+
+static void
+select_frame_command PARAMS ((char *, int));
+
+static void
+args_info PARAMS ((char *, int));
+
+static void
+print_frame_arg_vars PARAMS ((FRAME, FILE *));
+
+static void
+catch_info PARAMS ((char *, int));
+
+static void
+locals_info PARAMS ((char *, int));
+
+static void
+print_frame_label_vars PARAMS ((FRAME, int, FILE *));
+
+static void
+print_frame_local_vars PARAMS ((FRAME, FILE *));
+
+static int
+print_block_frame_labels PARAMS ((struct block *, int *, FILE *));
+
+static int
+print_block_frame_locals PARAMS ((struct block *, FRAME, FILE *));
+
+static void
+backtrace_command PARAMS ((char *, int));
+
+static FRAME
+parse_frame_specification PARAMS ((char *));
+
+static void
+frame_info PARAMS ((char *, int));
+
+
+extern int addressprint; /* Print addresses, or stay symbolic only? */
+extern int info_verbose; /* Verbosity of symbol reading msgs */
+extern int lines_to_list; /* # of lines "list" command shows by default */
+
+/* The "selected" stack frame is used by default for local and arg access.
+ May be zero, for no selected frame. */
+
+FRAME selected_frame;
+
+/* Level of the selected frame:
+ 0 for innermost, 1 for its caller, ...
+ or -1 for frame specified by address with no defined level. */
+
+int selected_frame_level;
+
+/* Nonzero means print the full filename and linenumber
+ when a frame is printed, and do so in a format programs can parse. */
+
+int frame_file_full_name = 0;
+
+
+struct print_stack_frame_args {
+ struct frame_info *fi;
+ int level;
+ int source;
+ int args;
+};
+
+static int print_stack_frame_stub PARAMS ((char *));
+
+/* Pass the args the way catch_errors wants them. */
+static int
+print_stack_frame_stub (args)
+ char *args;
+{
+ struct print_stack_frame_args *p = (struct print_stack_frame_args *)args;
+ print_frame_info (p->fi, p->level, p->source, p->args);
+ return 0;
+}
+
+/* Print a stack frame briefly. FRAME should be the frame id
+ and LEVEL should be its level in the stack (or -1 for level not defined).
+ This prints the level, the function executing, the arguments,
+ and the file name and line number.
+ If the pc is not at the beginning of the source line,
+ the actual pc is printed at the beginning.
+
+ If SOURCE is 1, print the source line as well.
+ If SOURCE is -1, print ONLY the source line. */
+
+void
+print_stack_frame (frame, level, source)
+ FRAME frame;
+ int level;
+ int source;
+{
+ struct print_stack_frame_args args;
+
+ args.fi = get_frame_info (frame);
+ args.level = level;
+ args.source = source;
+ args.args = 1;
+
+ catch_errors (print_stack_frame_stub, (char *)&args, "", RETURN_MASK_ERROR);
+}
+
+struct print_args_args {
+ struct symbol *func;
+ struct frame_info *fi;
+};
+
+static int print_args_stub PARAMS ((char *));
+
+/* Pass the args the way catch_errors wants them. */
+static int
+print_args_stub (args)
+ char *args;
+{
+ int numargs;
+ struct print_args_args *p = (struct print_args_args *)args;
+ FRAME_NUM_ARGS (numargs, (p->fi));
+ print_frame_args (p->func, p->fi, numargs, stdout);
+ return 0;
+}
+
+void
+print_frame_info (fi, level, source, args)
+ struct frame_info *fi;
+ register int level;
+ int source;
+ int args;
+{
+ struct symtab_and_line sal;
+ struct symbol *func;
+ register char *funname = 0;
+ enum language funlang = language_unknown;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ CORE_ADDR sp;
+
+ /* Get the value of SP_REGNUM relative to the frame. */
+ get_saved_register (buf, (int *)NULL, (CORE_ADDR *)NULL,
+ FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *)NULL);
+ sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM));
+
+ /* This is not a perfect test, because if a function alloca's some
+ memory, puts some code there, and then jumps into it, then the test
+ will succeed even though there is no call dummy. Probably best is
+ to check for a bp_call_dummy breakpoint. */
+ if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
+ {
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ printf_filtered ("<function called from gdb>\n");
+ return;
+ }
+ if (fi->signal_handler_caller)
+ {
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ printf_filtered ("<signal handler called>\n");
+ return;
+ }
+
+ /* If fi is not the innermost frame, that normally means that fi->pc
+ points to *after* the call instruction, and we want to get the line
+ containing the call, never the next line. But if the next frame is
+ a signal_handler_caller frame, then the next frame was not entered
+ as the result of a call, and we want to get the line containing
+ fi->pc. */
+ sal =
+ find_pc_line (fi->pc,
+ fi->next != NULL && fi->next->signal_handler_caller == 0);
+
+ func = find_pc_function (fi->pc);
+ if (func)
+ {
+ /* In certain pathological cases, the symtabs give the wrong
+ function (when we are in the first function in a file which
+ is compiled without debugging symbols, the previous function
+ is compiled with debugging symbols, and the "foo.o" symbol
+ that is supposed to tell us where the file with debugging symbols
+ ends has been truncated by ar because it is longer than 15
+ characters). This also occurs if the user uses asm() to create
+ a function but not stabs for it (in a file compiled -g).
+
+ So look in the minimal symbol tables as well, and if it comes
+ up with a larger address for the function use that instead.
+ I don't think this can ever cause any problems; there shouldn't
+ be any minimal symbols in the middle of a function; if this is
+ ever changed many parts of GDB will need to be changed (and we'll
+ create a find_pc_minimal_function or some such). */
+
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL
+ && (SYMBOL_VALUE_ADDRESS (msymbol)
+ > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ {
+ /* In this case we have no way of knowing the source file
+ and line number, so don't print them. */
+ sal.symtab = 0;
+ /* We also don't know anything about the function besides
+ its address and name. */
+ func = 0;
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ else
+ {
+ funname = SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ }
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL)
+ {
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+
+ if (source >= 0 || !sal.symtab)
+ {
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ if (addressprint)
+ if (fi->pc != sal.pc || !sal.symtab)
+ printf_filtered ("%s in ", local_hex_string((unsigned long) fi->pc));
+ fprintf_symbol_filtered (stdout, funname ? funname : "??", funlang,
+ DMGL_NO_OPTS);
+ wrap_here (" ");
+ fputs_filtered (" (", stdout);
+ if (args)
+ {
+ struct print_args_args args;
+ args.fi = fi;
+ args.func = func;
+ catch_errors (print_args_stub, (char *)&args, "", RETURN_MASK_ERROR);
+ }
+ printf_filtered (")");
+ if (sal.symtab && sal.symtab->filename)
+ {
+ wrap_here (" ");
+ printf_filtered (" at %s:%d", sal.symtab->filename, sal.line);
+ }
+
+#ifdef PC_LOAD_SEGMENT
+ /* If we couldn't print out function name but if can figure out what
+ load segment this pc value is from, at least print out some info
+ about its load segment. */
+ if (!funname) {
+ wrap_here (" ");
+ printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc));
+ }
+#endif
+ printf_filtered ("\n");
+ }
+
+ if ((source != 0) && sal.symtab)
+ {
+ int done = 0;
+ int mid_statement = source < 0 && fi->pc != sal.pc;
+ if (frame_file_full_name)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement,
+ fi->pc);
+ if (!done)
+ {
+ if (addressprint && mid_statement)
+ printf_filtered ("%s\t", local_hex_string((unsigned long) fi->pc));
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+ }
+ current_source_line = max (sal.line - lines_to_list/2, 1);
+ }
+ if (source != 0)
+ set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+ fflush (stdout);
+}
+
+/*
+ * Read a frame specification in whatever the appropriate format is.
+ * Call error() if the specification is in any way invalid (i.e.
+ * this function never returns NULL).
+ */
+static FRAME
+parse_frame_specification (frame_exp)
+ char *frame_exp;
+{
+ int numargs = 0;
+#define MAXARGS 4
+ CORE_ADDR args[MAXARGS];
+
+ if (frame_exp)
+ {
+ char *addr_string, *p;
+ struct cleanup *tmp_cleanup;
+
+ while (*frame_exp == ' ') frame_exp++;
+
+ while (*frame_exp)
+ {
+ if (numargs > MAXARGS)
+ error ("Too many args in frame specification");
+ /* Parse an argument. */
+ for (p = frame_exp; *p && *p != ' '; p++)
+ ;
+ addr_string = savestring(frame_exp, p - frame_exp);
+
+ {
+ tmp_cleanup = make_cleanup (free, addr_string);
+ args[numargs++] = parse_and_eval_address (addr_string);
+ do_cleanups (tmp_cleanup);
+ }
+
+ /* Skip spaces, move to possible next arg. */
+ while (*p == ' ') p++;
+ frame_exp = p;
+ }
+ }
+
+ switch (numargs)
+ {
+ case 0:
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ return selected_frame;
+ /* NOTREACHED */
+ case 1:
+ {
+ int level = args[0];
+ FRAME fid = find_relative_frame (get_current_frame (), &level);
+ FRAME tfid;
+
+ if (level == 0)
+ /* find_relative_frame was successful */
+ return fid;
+
+ /* If (s)he specifies the frame with an address, he deserves what
+ (s)he gets. Still, give the highest one that matches. */
+
+ for (fid = get_current_frame ();
+ fid && FRAME_FP (fid) != args[0];
+ fid = get_prev_frame (fid))
+ ;
+
+ if (fid)
+ while ((tfid = get_prev_frame (fid)) &&
+ (FRAME_FP (tfid) == args[0]))
+ fid = tfid;
+
+ /* We couldn't identify the frame as an existing frame, but
+ perhaps we can create one with a single argument.
+ Fall through to default case; it's up to SETUP_ARBITRARY_FRAME
+ to complain if it doesn't like a single arg. */
+ }
+
+ default:
+#ifdef SETUP_ARBITRARY_FRAME
+ return SETUP_ARBITRARY_FRAME (numargs, args);
+#else
+ /* Usual case. Do it here rather than have everyone supply
+ a SETUP_ARBITRARY_FRAME that does this. */
+ if (numargs == 1)
+ return create_new_frame (args[0], 0);
+ error ("Too many args in frame specification");
+#endif
+ /* NOTREACHED */
+ }
+ /* NOTREACHED */
+}
+
+/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except
+ that if it is unsure about the answer, it returns 0
+ instead of guessing (this happens on the VAX and i960, for example).
+
+ On most machines, we never have to guess about the args address,
+ so FRAME_ARGS_ADDRESS{,_CORRECT} are the same. */
+#if !defined (FRAME_ARGS_ADDRESS_CORRECT)
+#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS
+#endif
+
+/* Print verbosely the selected frame or the frame at address ADDR.
+ This means absolutely all information in the frame is printed. */
+
+static void
+frame_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ FRAME frame;
+ struct frame_info *fi;
+ struct frame_saved_regs fsr;
+ struct symtab_and_line sal;
+ struct symbol *func;
+ struct symtab *s;
+ FRAME calling_frame;
+ int i, count;
+ char *funname = 0;
+ enum language funlang = language_unknown;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ frame = parse_frame_specification (addr_exp);
+ if (!frame)
+ error ("Invalid frame specified.");
+
+ fi = get_frame_info (frame);
+ sal = find_pc_line (fi->pc,
+ fi->next != NULL && fi->next->signal_handler_caller == 0);
+ func = get_frame_function (frame);
+ s = find_pc_symtab(fi->pc);
+ if (func)
+ {
+ funname = SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL)
+ {
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+ calling_frame = get_prev_frame (frame);
+
+ if (!addr_exp && selected_frame_level >= 0) {
+ printf_filtered ("Stack level %d, frame at %s:\n",
+ selected_frame_level,
+ local_hex_string((unsigned long) FRAME_FP(frame)));
+ } else {
+ printf_filtered ("Stack frame at %s:\n",
+ local_hex_string((unsigned long) FRAME_FP(frame)));
+ }
+ printf_filtered (" %s = %s",
+ reg_names[PC_REGNUM],
+ local_hex_string((unsigned long) fi->pc));
+
+ wrap_here (" ");
+ if (funname)
+ {
+ printf_filtered (" in ");
+ fprintf_symbol_filtered (stdout, funname, funlang,
+ DMGL_ANSI | DMGL_PARAMS);
+ }
+ wrap_here (" ");
+ if (sal.symtab)
+ printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line);
+ puts_filtered ("; ");
+ wrap_here (" ");
+ printf_filtered ("saved %s %s\n", reg_names[PC_REGNUM],
+ local_hex_string((unsigned long) FRAME_SAVED_PC (frame)));
+
+ {
+ int frameless = 0;
+#ifdef FRAMELESS_FUNCTION_INVOCATION
+ FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
+#endif
+ if (frameless)
+ printf_filtered (" (FRAMELESS),");
+ }
+
+ if (calling_frame)
+ printf_filtered (" called by frame at %s",
+ local_hex_string((unsigned long) FRAME_FP (calling_frame)));
+ if (fi->next && calling_frame)
+ puts_filtered (",");
+ wrap_here (" ");
+ if (fi->next)
+ printf_filtered (" caller of frame at %s",
+ local_hex_string ((unsigned long) fi->next->frame));
+ if (fi->next || calling_frame)
+ puts_filtered ("\n");
+ if (s)
+ printf_filtered(" source language %s.\n", language_str(s->language));
+
+#ifdef PRINT_EXTRA_FRAME_INFO
+ PRINT_EXTRA_FRAME_INFO (fi);
+#endif
+
+ {
+ /* Address of the argument list for this frame, or 0. */
+ CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
+ /* Number of args for this frame, or -1 if unknown. */
+ int numargs;
+
+ if (arg_list == 0)
+ printf_filtered (" Arglist at unknown address.\n");
+ else
+ {
+ printf_filtered (" Arglist at %s,",
+ local_hex_string((unsigned long) arg_list));
+
+ FRAME_NUM_ARGS (numargs, fi);
+ if (numargs < 0)
+ puts_filtered (" args: ");
+ else if (numargs == 0)
+ puts_filtered (" no args.");
+ else if (numargs == 1)
+ puts_filtered (" 1 arg: ");
+ else
+ printf_filtered (" %d args: ", numargs);
+ print_frame_args (func, fi, numargs, stdout);
+ puts_filtered ("\n");
+ }
+ }
+ {
+ /* Address of the local variables for this frame, or 0. */
+ CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi);
+
+ if (arg_list == 0)
+ printf_filtered (" Locals at unknown address,");
+ else
+ printf_filtered (" Locals at %s,",
+ local_hex_string((unsigned long) arg_list));
+ }
+
+#if defined (FRAME_FIND_SAVED_REGS)
+ get_frame_saved_regs (fi, &fsr);
+ /* The sp is special; what's returned isn't the save address, but
+ actually the value of the previous frame's sp. */
+ printf_filtered (" Previous frame's sp is %s\n",
+ local_hex_string((unsigned long) fsr.regs[SP_REGNUM]));
+ count = 0;
+ for (i = 0; i < NUM_REGS; i++)
+ if (fsr.regs[i] && i != SP_REGNUM)
+ {
+ if (count == 0)
+ puts_filtered (" Saved registers:\n ");
+ else
+ puts_filtered (",");
+ wrap_here (" ");
+ printf_filtered (" %s at %s", reg_names[i],
+ local_hex_string((unsigned long) fsr.regs[i]));
+ count++;
+ }
+ if (count)
+ puts_filtered ("\n");
+#endif /* Have FRAME_FIND_SAVED_REGS. */
+}
+
+#if 0
+/* Set a limit on the number of frames printed by default in a
+ backtrace. */
+
+static int backtrace_limit;
+
+static void
+set_backtrace_limit_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ int count = parse_and_eval_address (count_exp);
+
+ if (count < 0)
+ error ("Negative argument not meaningful as backtrace limit.");
+
+ backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"Info backtrace-limit\" takes no arguments.");
+
+ printf ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames. */
+
+static void
+backtrace_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ struct frame_info *fi;
+ register int count;
+ register FRAME frame;
+ register int i;
+ register FRAME trailing;
+ register int trailing_level;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ /* The following code must do two things. First, it must
+ set the variable TRAILING to the frame from which we should start
+ printing. Second, it must set the variable count to the number
+ of frames which we should print, or -1 if all of them. */
+ trailing = get_current_frame ();
+ trailing_level = 0;
+ if (count_exp)
+ {
+ count = parse_and_eval_address (count_exp);
+ if (count < 0)
+ {
+ FRAME current;
+
+ count = -count;
+
+ current = trailing;
+ while (current && count--)
+ {
+ QUIT;
+ current = get_prev_frame (current);
+ }
+
+ /* Will stop when CURRENT reaches the top of the stack. TRAILING
+ will be COUNT below it. */
+ while (current)
+ {
+ QUIT;
+ trailing = get_prev_frame (trailing);
+ current = get_prev_frame (current);
+ trailing_level++;
+ }
+
+ count = -1;
+ }
+ }
+ else
+ count = -1;
+
+ if (info_verbose)
+ {
+ struct partial_symtab *ps;
+
+ /* Read in symbols for all of the frames. Need to do this in
+ a separate pass so that "Reading in symbols for xxx" messages
+ don't screw up the appearance of the backtrace. Also
+ if people have strong opinions against reading symbols for
+ backtrace this may have to be an option. */
+ i = count;
+ for (frame = trailing;
+ frame != NULL && i--;
+ frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+ ps = find_pc_psymtab (fi->pc);
+ if (ps)
+ PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in */
+ }
+ }
+
+ for (i = 0, frame = trailing;
+ frame && count--;
+ i++, frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+
+ /* Don't use print_stack_frame; if an error() occurs it probably
+ means further attempts to backtrace would fail (on the other
+ hand, perhaps the code does or could be fixed to make sure
+ the frame->prev field gets set to NULL in that case). */
+ print_frame_info (fi, trailing_level + i, 0, 1);
+ }
+
+ /* If we've stopped before the end, mention that. */
+ if (frame && from_tty)
+ printf_filtered ("(More stack frames follow...)\n");
+}
+
+/* Print the local variables of a block B active in FRAME.
+ Return 1 if any variables were printed; 0 otherwise. */
+
+static int
+print_block_frame_locals (b, frame, stream)
+ struct block *b;
+ register FRAME frame;
+ register FILE *stream;
+{
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+ register int values_printed = 0;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_LOCAL
+ || SYMBOL_CLASS (sym) == LOC_REGISTER
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+ print_variable_value (sym, frame, stream);
+ fprintf_filtered (stream, "\n");
+ }
+ }
+ return values_printed;
+}
+
+/* Same, but print labels. */
+
+static int
+print_block_frame_labels (b, have_default, stream)
+ struct block *b;
+ int *have_default;
+ register FILE *stream;
+{
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+ register int values_printed = 0;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (STREQ (SYMBOL_NAME (sym), "default"))
+ {
+ if (*have_default)
+ continue;
+ *have_default = 1;
+ }
+ if (SYMBOL_CLASS (sym) == LOC_LABEL)
+ {
+ struct symtab_and_line sal;
+ sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ if (addressprint)
+ fprintf_filtered (stream, " %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ fprintf_filtered (stream, " in file %s, line %d\n",
+ sal.symtab->filename, sal.line);
+ }
+ }
+ return values_printed;
+}
+
+/* Print on STREAM all the local variables in frame FRAME,
+ including all the blocks active in that frame
+ at its current pc.
+
+ Returns 1 if the job was done,
+ or 0 if nothing was printed because we have no info
+ on the function running in FRAME. */
+
+static void
+print_frame_local_vars (frame, stream)
+ register FRAME frame;
+ register FILE *stream;
+{
+ register struct block *block = get_frame_block (frame);
+ register int values_printed = 0;
+
+ if (block == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ while (block != 0)
+ {
+ if (print_block_frame_locals (block, frame, stream))
+ values_printed = 1;
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (!values_printed)
+ {
+ fprintf_filtered (stream, "No locals.\n");
+ }
+}
+
+/* Same, but print labels. */
+
+static void
+print_frame_label_vars (frame, this_level_only, stream)
+ register FRAME frame;
+ int this_level_only;
+ register FILE *stream;
+{
+ register struct blockvector *bl;
+ register struct block *block = get_frame_block (frame);
+ register int values_printed = 0;
+ int index, have_default = 0;
+ char *blocks_printed;
+ struct frame_info *fi = get_frame_info (frame);
+ CORE_ADDR pc = fi->pc;
+
+ if (block == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+ blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+ memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+ while (block != 0)
+ {
+ CORE_ADDR end = BLOCK_END (block) - 4;
+ int last_index;
+
+ if (bl != blockvector_for_pc (end, &index))
+ error ("blockvector blotch");
+ if (BLOCKVECTOR_BLOCK (bl, index) != block)
+ error ("blockvector botch");
+ last_index = BLOCKVECTOR_NBLOCKS (bl);
+ index += 1;
+
+ /* Don't print out blocks that have gone by. */
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+ index++;
+
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+ {
+ if (blocks_printed[index] == 0)
+ {
+ if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), &have_default, stream))
+ values_printed = 1;
+ blocks_printed[index] = 1;
+ }
+ index++;
+ }
+ if (have_default)
+ return;
+ if (values_printed && this_level_only)
+ return;
+
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (!values_printed && !this_level_only)
+ {
+ fprintf_filtered (stream, "No catches.\n");
+ }
+}
+
+/* ARGSUSED */
+static void
+locals_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_local_vars (selected_frame, stdout);
+}
+
+static void
+catch_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_label_vars (selected_frame, 0, stdout);
+}
+
+static void
+print_frame_arg_vars (frame, stream)
+ register FRAME frame;
+ register FILE *stream;
+{
+ struct symbol *func = get_frame_function (frame);
+ register struct block *b;
+ int nsyms;
+ register int i;
+ register struct symbol *sym, *sym2;
+ register int values_printed = 0;
+
+ if (func == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_ARG:
+ case LOC_LOCAL_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_BASEREG_ARG:
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+
+ /* We have to look up the symbol because arguments can have
+ two entries (one a parameter, one a local) and the one we
+ want is the local, which lookup_symbol will find for us.
+ This includes gcc1 (not gcc2) on the sparc when passing a
+ small structure and gcc2 when the argument type is float
+ and it is passed as a double and converted to float by
+ the prologue (in the latter case the type of the LOC_ARG
+ symbol is double and the type of the LOC_LOCAL symbol is
+ float). There are also LOC_ARG/LOC_REGISTER pairs which
+ are not combined in symbol-reading. */
+
+ sym2 = lookup_symbol (SYMBOL_NAME (sym),
+ b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+ print_variable_value (sym2, frame, stream);
+ fprintf_filtered (stream, "\n");
+ break;
+
+ default:
+ /* Don't worry about things which aren't arguments. */
+ break;
+ }
+ }
+
+ if (!values_printed)
+ {
+ fprintf_filtered (stream, "No arguments.\n");
+ }
+}
+
+static void
+args_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_arg_vars (selected_frame, stdout);
+}
+
+/* Select frame FRAME, and note that its stack level is LEVEL.
+ LEVEL may be -1 if an actual level number is not known. */
+
+void
+select_frame (frame, level)
+ FRAME frame;
+ int level;
+{
+ register struct symtab *s;
+
+ selected_frame = frame;
+ selected_frame_level = level;
+
+ /* Ensure that symbols for this frame are read in. Also, determine the
+ source language of this frame, and switch to it if desired. */
+ if (frame)
+ {
+ s = find_pc_symtab (get_frame_info (frame)->pc);
+ if (s
+ && s->language != current_language->la_language
+ && s->language != language_unknown
+ && language_mode == language_mode_auto) {
+ set_language(s->language);
+ }
+ }
+}
+
+/* Store the selected frame and its level into *FRAMEP and *LEVELP.
+ If there is no selected frame, *FRAMEP is set to NULL. */
+
+void
+record_selected_frame (frameaddrp, levelp)
+ FRAME_ADDR *frameaddrp;
+ int *levelp;
+{
+ *frameaddrp = selected_frame ? FRAME_FP (selected_frame) : 0;
+ *levelp = selected_frame_level;
+}
+
+/* Return the symbol-block in which the selected frame is executing.
+ Can return zero under various legitimate circumstances. */
+
+struct block *
+get_selected_block ()
+{
+ if (!target_has_stack)
+ return 0;
+
+ if (!selected_frame)
+ return get_current_block ();
+ return get_frame_block (selected_frame);
+}
+
+/* Find a frame a certain number of levels away from FRAME.
+ LEVEL_OFFSET_PTR points to an int containing the number of levels.
+ Positive means go to earlier frames (up); negative, the reverse.
+ The int that contains the number of levels is counted toward
+ zero as the frames for those levels are found.
+ If the top or bottom frame is reached, that frame is returned,
+ but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
+ how much farther the original request asked to go. */
+
+FRAME
+find_relative_frame (frame, level_offset_ptr)
+ register FRAME frame;
+ register int* level_offset_ptr;
+{
+ register FRAME prev;
+ register FRAME frame1;
+
+ /* Going up is simple: just do get_prev_frame enough times
+ or until initial frame is reached. */
+ while (*level_offset_ptr > 0)
+ {
+ prev = get_prev_frame (frame);
+ if (prev == 0)
+ break;
+ (*level_offset_ptr)--;
+ frame = prev;
+ }
+ /* Going down is just as simple. */
+ if (*level_offset_ptr < 0)
+ {
+ while (*level_offset_ptr < 0) {
+ frame1 = get_next_frame (frame);
+ if (!frame1)
+ break;
+ frame = frame1;
+ (*level_offset_ptr)++;
+ }
+ }
+ return frame;
+}
+
+/* The "select_frame" command. With no arg, NOP.
+ With arg LEVEL_EXP, select the frame at level LEVEL if it is a
+ valid level. Otherwise, treat level_exp as an address expression
+ and select it. See parse_frame_specification for more info on proper
+ frame expressions. */
+
+/* ARGSUSED */
+static void
+select_frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ register FRAME frame, frame1;
+ unsigned int level = 0;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ frame = parse_frame_specification (level_exp);
+
+ /* Try to figure out what level this frame is. But if there is
+ no current stack, don't error out -- let the user set one. */
+ frame1 = 0;
+ if (get_current_frame()) {
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+ }
+
+ if (!frame1)
+ level = 0;
+
+ select_frame (frame, level);
+}
+
+/* The "frame" command. With no arg, print selected frame briefly.
+ With arg, behaves like select_frame and then prints the selected
+ frame. */
+
+static void
+frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ select_frame_command (level_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+/* ARGSUSED */
+static void
+up_silently_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ register FRAME frame;
+ int count = 1, count1;
+ if (count_exp)
+ count = parse_and_eval_address (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || selected_frame == 0)
+ error ("No stack.");
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Initial frame selected; you cannot go up.");
+ select_frame (frame, selected_frame_level + count - count1);
+}
+
+static void
+up_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ up_silently_command (count_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+/* ARGSUSED */
+static void
+down_silently_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ register FRAME frame;
+ int count = -1, count1;
+ if (count_exp)
+ count = - parse_and_eval_address (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || selected_frame == 0)
+ error ("No stack.");
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+ select_frame (frame, selected_frame_level + count - count1);
+}
+
+
+static void
+down_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ down_silently_command (count_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+static void
+return_command (retval_exp, from_tty)
+ char *retval_exp;
+ int from_tty;
+{
+ struct symbol *thisfun;
+ FRAME_ADDR selected_frame_addr;
+ CORE_ADDR selected_frame_pc;
+ FRAME frame;
+ value return_value = NULL;
+
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ thisfun = get_frame_function (selected_frame);
+ selected_frame_addr = FRAME_FP (selected_frame);
+ selected_frame_pc = (get_frame_info (selected_frame))->pc;
+
+ /* Compute the return value (if any -- possibly getting errors here). */
+
+ if (retval_exp)
+ {
+ return_value = parse_and_eval (retval_exp);
+
+ /* Make sure we have fully evaluated it, since
+ it might live in the stack frame we're about to pop. */
+ if (VALUE_LAZY (return_value))
+ value_fetch_lazy (return_value);
+ }
+
+ /* If interactive, require confirmation. */
+
+ if (from_tty)
+ {
+ if (thisfun != 0)
+ {
+ if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun)))
+ {
+ error ("Not confirmed.");
+ /* NOTREACHED */
+ }
+ }
+ else
+ if (!query ("Make selected stack frame return now? "))
+ error ("Not confirmed.");
+ }
+
+ /* Do the real work. Pop until the specified frame is current. We
+ use this method because the selected_frame is not valid after
+ a POP_FRAME. The pc comparison makes this work even if the
+ selected frame shares its fp with another frame. */
+
+ while ( selected_frame_addr != FRAME_FP (frame = get_current_frame())
+ || selected_frame_pc != (get_frame_info (frame))->pc )
+ POP_FRAME;
+
+ /* Then pop that frame. */
+
+ POP_FRAME;
+
+ /* Compute the return value (if any) and store in the place
+ for return values. */
+
+ if (retval_exp)
+ set_return_value (return_value);
+
+ /* If interactive, print the frame that is now current. */
+
+ if (from_tty)
+ frame_command ("0", 1);
+}
+
+/* Gets the language of the current frame. */
+enum language
+get_frame_language()
+{
+ register struct symtab *s;
+ FRAME fr;
+ enum language flang; /* The language of the current frame */
+
+ fr = get_frame_info(selected_frame);
+ if(fr)
+ {
+ s = find_pc_symtab(fr->pc);
+ if(s)
+ flang = s->language;
+ else
+ flang = language_unknown;
+ }
+ else
+ flang = language_unknown;
+
+ return flang;
+}
+
+void
+_initialize_stack ()
+{
+#if 0
+ backtrace_limit = 30;
+#endif
+
+ add_com ("return", class_stack, return_command,
+ "Make selected stack frame return to its caller.\n\
+Control remains in the debugger, but when you continue\n\
+execution will resume in the frame above the one now selected.\n\
+If an argument is given, it is an expression for the value to return.");
+
+ add_com ("up", class_stack, up_command,
+ "Select and print stack frame that called this one.\n\
+An argument says how many frames up to go.");
+ add_com ("up-silently", class_support, up_silently_command,
+ "Same as the `up' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+ add_com ("down", class_stack, down_command,
+ "Select and print stack frame called by this one.\n\
+An argument says how many frames down to go.");
+ add_com_alias ("do", "down", class_stack, 1);
+ add_com_alias ("dow", "down", class_stack, 1);
+ add_com ("down-silently", class_support, down_silently_command,
+ "Same as the `down' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+ add_com ("frame", class_stack, frame_command,
+ "Select and print a stack frame.\n\
+With no argument, print the selected stack frame. (See also \"info frame\").\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n\
+With argument, nothing is printed if input is coming from\n\
+a command file or a user-defined command.");
+
+ add_com_alias ("f", "frame", class_stack, 1);
+
+ add_com ("select-frame", class_stack, select_frame_command,
+ "Select a stack frame without printing anything.\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n");
+
+ add_com ("backtrace", class_stack, backtrace_command,
+ "Print backtrace of all stack frames, or innermost COUNT frames.\n\
+With a negative argument, print outermost -COUNT frames.");
+ add_com_alias ("bt", "backtrace", class_stack, 0);
+ add_com_alias ("where", "backtrace", class_alias, 0);
+ add_info ("stack", backtrace_command,
+ "Backtrace of the stack, or innermost COUNT frames.");
+ add_info_alias ("s", "stack", 1);
+ add_info ("frame", frame_info,
+ "All about selected stack frame, or frame at ADDR.");
+ add_info_alias ("f", "frame", 1);
+ add_info ("locals", locals_info,
+ "Local variables of current stack frame.");
+ add_info ("args", args_info,
+ "Argument variables of current stack frame.");
+ add_info ("catch", catch_info,
+ "Exceptions that can be caught in the current stack frame.");
+
+#if 0
+ add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
+ "Specify maximum number of frames for \"backtrace\" to print by default.",
+ &setlist);
+ add_info ("backtrace-limit", backtrace_limit_info,
+ "The maximum number of frames for \"backtrace\" to print by default.");
+#endif
+}
diff --git a/gnu/usr.bin/gdb/gdb/symfile.c b/gnu/usr.bin/gdb/gdb/symfile.c
new file mode 100644
index 000000000000..197c0c3a6221
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.c
@@ -0,0 +1,1489 @@
+/* Generic symbol file reading for the GNU debugger, GDB.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+#include "language.h"
+#include "complaints.h"
+#include "demangle.h"
+#include "inferior.h" /* for write_pc */
+
+#include <obstack.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Global variables owned by this file */
+
+int readnow_symbol_files; /* Read full symbols immediately */
+
+struct complaint oldsyms_complaint = {
+ "Replacing old symbols for `%s'", 0, 0
+};
+
+struct complaint empty_symtab_complaint = {
+ "Empty symbol table found for `%s'", 0, 0
+};
+
+/* External variables and functions referenced. */
+
+extern int info_verbose;
+
+/* Functions this file defines */
+
+static void
+set_initial_language PARAMS ((void));
+
+static void
+load_command PARAMS ((char *, int));
+
+static void
+add_symbol_file_command PARAMS ((char *, int));
+
+static void
+cashier_psymtab PARAMS ((struct partial_symtab *));
+
+static int
+compare_psymbols PARAMS ((const void *, const void *));
+
+static int
+compare_symbols PARAMS ((const void *, const void *));
+
+static bfd *
+symfile_bfd_open PARAMS ((char *));
+
+static void
+find_sym_fns PARAMS ((struct objfile *));
+
+/* List of all available sym_fns. On gdb startup, each object file reader
+ calls add_symtab_fns() to register information on each format it is
+ prepared to read. */
+
+static struct sym_fns *symtab_fns = NULL;
+
+/* Structures with which to manage partial symbol allocation. */
+
+struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0};
+
+/* Flag for whether user will be reloading symbols multiple times.
+ Defaults to ON for VxWorks, otherwise OFF. */
+
+#ifdef SYMBOL_RELOADING_DEFAULT
+int symbol_reloading = SYMBOL_RELOADING_DEFAULT;
+#else
+int symbol_reloading = 0;
+#endif
+
+
+/* Since this function is called from within qsort, in an ANSI environment
+ it must conform to the prototype for qsort, which specifies that the
+ comparison function takes two "void *" pointers. */
+
+static int
+compare_symbols (s1p, s2p)
+ const PTR s1p;
+ const PTR s2p;
+{
+ register struct symbol **s1, **s2;
+
+ s1 = (struct symbol **) s1p;
+ s2 = (struct symbol **) s2p;
+
+ return (STRCMP (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)));
+}
+
+/*
+
+LOCAL FUNCTION
+
+ compare_psymbols -- compare two partial symbols by name
+
+DESCRIPTION
+
+ Given pointer to two partial symbol table entries, compare
+ them by name and return -N, 0, or +N (ala strcmp). Typically
+ used by sorting routines like qsort().
+
+NOTES
+
+ Does direct compare of first two characters before punting
+ and passing to strcmp for longer compares. Note that the
+ original version had a bug whereby two null strings or two
+ identically named one character strings would return the
+ comparison of memory following the null byte.
+
+ */
+
+static int
+compare_psymbols (s1p, s2p)
+ const PTR s1p;
+ const PTR s2p;
+{
+ register char *st1 = SYMBOL_NAME ((struct partial_symbol *) s1p);
+ register char *st2 = SYMBOL_NAME ((struct partial_symbol *) s2p);
+
+ if ((st1[0] - st2[0]) || !st1[0])
+ {
+ return (st1[0] - st2[0]);
+ }
+ else if ((st1[1] - st2[1]) || !st1[1])
+ {
+ return (st1[1] - st2[1]);
+ }
+ else
+ {
+ return (STRCMP (st1 + 2, st2 + 2));
+ }
+}
+
+void
+sort_pst_symbols (pst)
+ struct partial_symtab *pst;
+{
+ /* Sort the global list; don't sort the static list */
+
+ qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset,
+ pst -> n_global_syms, sizeof (struct partial_symbol),
+ compare_psymbols);
+}
+
+/* Call sort_block_syms to sort alphabetically the symbols of one block. */
+
+void
+sort_block_syms (b)
+ register struct block *b;
+{
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+}
+
+/* Call sort_symtab_syms to sort alphabetically
+ the symbols of each block of one symtab. */
+
+void
+sort_symtab_syms (s)
+ register struct symtab *s;
+{
+ register struct blockvector *bv;
+ int nbl;
+ int i;
+ register struct block *b;
+
+ if (s == 0)
+ return;
+ bv = BLOCKVECTOR (s);
+ nbl = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ }
+}
+
+void
+sort_all_symtab_syms ()
+{
+ register struct symtab *s;
+ register struct objfile *objfile;
+
+ for (objfile = object_files; objfile != NULL; objfile = objfile -> next)
+ {
+ for (s = objfile -> symtabs; s != NULL; s = s -> next)
+ {
+ sort_symtab_syms (s);
+ }
+ }
+}
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+char *
+obsavestring (ptr, size, obstackp)
+ char *ptr;
+ int size;
+ struct obstack *obstackp;
+{
+ register char *p = (char *) obstack_alloc (obstackp, size + 1);
+ /* Open-coded memcpy--saves function call time.
+ These strings are usually short. */
+ {
+ register char *p1 = ptr;
+ register char *p2 = p;
+ char *end = ptr + size;
+ while (p1 != end)
+ *p2++ = *p1++;
+ }
+ p[size] = 0;
+ return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+char *
+obconcat (obstackp, s1, s2, s3)
+ struct obstack *obstackp;
+ const char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) obstack_alloc (obstackp, len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+/* Get the symbol table that corresponds to a partial_symtab.
+ This is fast after the first time you do it. In fact, there
+ is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
+ case inline. */
+
+struct symtab *
+psymtab_to_symtab (pst)
+ register struct partial_symtab *pst;
+{
+ /* If it's been looked up before, return it. */
+ if (pst->symtab)
+ return pst->symtab;
+
+ /* If it has not yet been read in, read it. */
+ if (!pst->readin)
+ {
+ (*pst->read_symtab) (pst);
+ }
+
+ return pst->symtab;
+}
+
+/* Initialize entry point information for this objfile. */
+
+void
+init_entry_point_info (objfile)
+ struct objfile *objfile;
+{
+ /* Save startup file's range of PC addresses to help blockframe.c
+ decide where the bottom of the stack is. */
+
+ if (bfd_get_file_flags (objfile -> obfd) & EXEC_P)
+ {
+ /* Executable file -- record its entry point so we'll recognize
+ the startup file because it contains the entry point. */
+ objfile -> ei.entry_point = bfd_get_start_address (objfile -> obfd);
+ }
+ else
+ {
+ /* Examination of non-executable.o files. Short-circuit this stuff. */
+ /* ~0 will not be in any file, we hope. */
+ objfile -> ei.entry_point = ~0;
+ /* set the startup file to be an empty range. */
+ objfile -> ei.entry_file_lowpc = 0;
+ objfile -> ei.entry_file_highpc = 0;
+ }
+}
+
+/* Get current entry point address. */
+
+CORE_ADDR
+entry_point_address()
+{
+ return symfile_objfile ? symfile_objfile->ei.entry_point : 0;
+}
+
+/* Remember the lowest-addressed loadable section we've seen.
+ This function is called via bfd_map_over_sections. */
+
+#if 0 /* Not used yet */
+static void
+find_lowest_section (abfd, sect, obj)
+ bfd *abfd;
+ asection *sect;
+ PTR obj;
+{
+ asection **lowest = (asection **)obj;
+
+ if (0 == (bfd_get_section_flags (abfd, sect) & SEC_LOAD))
+ return;
+ if (!*lowest)
+ *lowest = sect; /* First loadable section */
+ else if (bfd_section_vma (abfd, *lowest) >= bfd_section_vma (abfd, sect))
+ *lowest = sect; /* A lower loadable section */
+}
+#endif
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file.
+
+ NAME is the file name (which will be tilde-expanded and made
+ absolute herein) (but we don't free or modify NAME itself).
+ FROM_TTY says how verbose to be. MAINLINE specifies whether this
+ is the main symbol file, or whether it's an extra symbol file such
+ as dynamically loaded code. If !mainline, ADDR is the address
+ where the text segment was loaded. If VERBO, the caller has printed
+ a verbose message about the symbol reading (and complaints can be
+ more terse about it). */
+
+void
+syms_from_objfile (objfile, addr, mainline, verbo)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+ int mainline;
+ int verbo;
+{
+ struct section_offsets *section_offsets;
+ asection *lowest_sect;
+ struct cleanup *old_chain;
+
+ init_entry_point_info (objfile);
+ find_sym_fns (objfile);
+
+ /* Make sure that partially constructed symbol tables will be cleaned up
+ if an error occurs during symbol reading. */
+ old_chain = make_cleanup (free_objfile, objfile);
+
+ if (mainline)
+ {
+ /* We will modify the main symbol table, make sure that all its users
+ will be cleaned up if an error occurs during symbol reading. */
+ make_cleanup (clear_symtab_users, 0);
+
+ /* Since no error yet, throw away the old symbol table. */
+
+ if (symfile_objfile != NULL)
+ {
+ free_objfile (symfile_objfile);
+ symfile_objfile = NULL;
+ }
+
+ (*objfile -> sf -> sym_new_init) (objfile);
+ }
+
+ /* Convert addr into an offset rather than an absolute address.
+ We find the lowest address of a loaded segment in the objfile,
+ and assume that <addr> is where that got loaded. Due to historical
+ precedent, we warn if that doesn't happen to be the ".text"
+ segment. */
+
+ if (mainline)
+ {
+ addr = 0; /* No offset from objfile addresses. */
+ }
+ else
+ {
+ lowest_sect = bfd_get_section_by_name (objfile->obfd, ".text");
+#if 0
+ lowest_sect = 0;
+ bfd_map_over_sections (objfile->obfd, find_lowest_section,
+ (PTR) &lowest_sect);
+#endif
+
+ if (lowest_sect == 0)
+ warning ("no loadable sections found in added symbol-file %s",
+ objfile->name);
+ else if (0 == bfd_get_section_name (objfile->obfd, lowest_sect)
+ || !STREQ (".text",
+ bfd_get_section_name (objfile->obfd, lowest_sect)))
+ warning ("Lowest section in %s is %s at 0x%lx",
+ objfile->name,
+ bfd_section_name (objfile->obfd, lowest_sect),
+ (unsigned long) bfd_section_vma (objfile->obfd, lowest_sect));
+
+ if (lowest_sect)
+ addr -= bfd_section_vma (objfile->obfd, lowest_sect);
+ }
+
+ /* Initialize symbol reading routines for this objfile, allow complaints to
+ appear for this new file, and record how verbose to be, then do the
+ initial symbol reading for this file. */
+
+ (*objfile -> sf -> sym_init) (objfile);
+ clear_complaints (1, verbo);
+
+ /* If objfile->sf->sym_offsets doesn't set this, we don't care
+ (currently). */
+ objfile->num_sections = 0; /* krp-FIXME: why zero? */
+ section_offsets = (*objfile -> sf -> sym_offsets) (objfile, addr);
+ objfile->section_offsets = section_offsets;
+
+#ifndef IBM6000_TARGET
+ /* This is a SVR4/SunOS specific hack, I think. In any event, it
+ screws RS/6000. sym_offsets should be doing this sort of thing,
+ because it knows the mapping between bfd sections and
+ section_offsets. */
+ /* This is a hack. As far as I can tell, section offsets are not
+ target dependent. They are all set to addr with a couple of
+ exceptions. The exceptions are sysvr4 shared libraries, whose
+ offsets are kept in solib structures anyway and rs6000 xcoff
+ which handles shared libraries in a completely unique way.
+
+ Section offsets are built similarly, except that they are built
+ by adding addr in all cases because there is no clear mapping
+ from section_offsets into actual sections. Note that solib.c
+ has a different algorythm for finding section offsets.
+
+ These should probably all be collapsed into some target
+ independent form of shared library support. FIXME. */
+
+ if (addr)
+ {
+ struct obj_section *s;
+
+ for (s = objfile->sections; s < objfile->sections_end; ++s)
+ {
+ s->addr -= s->offset;
+ s->addr += addr;
+ s->endaddr -= s->offset;
+ s->endaddr += addr;
+ s->offset += addr;
+ }
+ }
+#endif /* not IBM6000_TARGET */
+
+ (*objfile -> sf -> sym_read) (objfile, section_offsets, mainline);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+ /* Ditto void *. FIXME should do this for all the builtin types. */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+ TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0;
+
+ /* Mark the objfile has having had initial symbol read attempted. Note
+ that this does not mean we found any symbols... */
+
+ objfile -> flags |= OBJF_SYMS;
+
+ /* Discard cleanups as symbol reading was successful. */
+
+ discard_cleanups (old_chain);
+}
+
+/* Perform required actions after either reading in the initial
+ symbols for a new objfile, or mapping in the symbols from a reusable
+ objfile. */
+
+void
+new_symfile_objfile (objfile, mainline, verbo)
+ struct objfile *objfile;
+ int mainline;
+ int verbo;
+{
+
+ /* If this is the main symbol file we have to clean up all users of the
+ old main symbol file. Otherwise it is sufficient to fixup all the
+ breakpoints that may have been redefined by this symbol file. */
+ if (mainline)
+ {
+ /* OK, make it the "real" symbol file. */
+ symfile_objfile = objfile;
+
+ clear_symtab_users ();
+ }
+ else
+ {
+ breakpoint_re_set ();
+ }
+
+ /* We're done reading the symbol file; finish off complaints. */
+ clear_complaints (0, verbo);
+}
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file.
+
+ NAME is the file name (which will be tilde-expanded and made
+ absolute herein) (but we don't free or modify NAME itself).
+ FROM_TTY says how verbose to be. MAINLINE specifies whether this
+ is the main symbol file, or whether it's an extra symbol file such
+ as dynamically loaded code. If !mainline, ADDR is the address
+ where the text segment was loaded.
+
+ Upon success, returns a pointer to the objfile that was added.
+ Upon failure, jumps back to command level (never returns). */
+
+struct objfile *
+symbol_file_add (name, from_tty, addr, mainline, mapped, readnow)
+ char *name;
+ int from_tty;
+ CORE_ADDR addr;
+ int mainline;
+ int mapped;
+ int readnow;
+{
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+ bfd *abfd;
+
+ /* Open a bfd for the file, and give user a chance to burp if we'd be
+ interactively wiping out any existing symbols. */
+
+ abfd = symfile_bfd_open (name);
+
+ if ((have_full_symbols () || have_partial_symbols ())
+ && mainline
+ && from_tty
+ && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ objfile = allocate_objfile (abfd, mapped);
+
+ /* If the objfile uses a mapped symbol file, and we have a psymtab for
+ it, then skip reading any symbols at this time. */
+
+ if ((objfile -> flags & OBJF_MAPPED) && (objfile -> flags & OBJF_SYMS))
+ {
+ /* We mapped in an existing symbol table file that already has had
+ initial symbol reading performed, so we can skip that part. Notify
+ the user that instead of reading the symbols, they have been mapped.
+ */
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("Mapped symbols for %s...", name);
+ wrap_here ("");
+ fflush (stdout);
+ }
+ init_entry_point_info (objfile);
+ find_sym_fns (objfile);
+ }
+ else
+ {
+ /* We either created a new mapped symbol table, mapped an existing
+ symbol table file which has not had initial symbol reading
+ performed, or need to read an unmapped symbol table. */
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("Reading symbols from %s...", name);
+ wrap_here ("");
+ fflush (stdout);
+ }
+ syms_from_objfile (objfile, addr, mainline, from_tty);
+ }
+
+ /* We now have at least a partial symbol table. Check to see if the
+ user requested that all symbols be read on initial access via either
+ the gdb startup command line or on a per symbol file basis. Expand
+ all partial symbol tables for this objfile if so. */
+
+ if (readnow || readnow_symbol_files)
+ {
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("expanding to full symbols...");
+ wrap_here ("");
+ fflush (stdout);
+ }
+
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ psymtab_to_symtab (psymtab);
+ }
+ }
+
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("done.\n");
+ fflush (stdout);
+ }
+
+ new_symfile_objfile (objfile, mainline, from_tty);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+
+ reinit_frame_cache ();
+
+ return (objfile);
+}
+
+/* This is the symbol-file command. Read the file, analyze its symbols,
+ and add a struct symtab to a symtab list. */
+
+void
+symbol_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *name = NULL;
+ struct cleanup *cleanups;
+ int mapped = 0;
+ int readnow = 0;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ if ((have_full_symbols () || have_partial_symbols ())
+ && from_tty
+ && !query ("Discard symbol table from `%s'? ",
+ symfile_objfile -> name))
+ error ("Not confirmed.");
+ free_all_objfiles ();
+ symfile_objfile = NULL;
+ if (from_tty)
+ {
+ printf ("No symbol file now.\n");
+ }
+ }
+ else
+ {
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+ while (*argv != NULL)
+ {
+ if (STREQ (*argv, "-mapped"))
+ {
+ mapped = 1;
+ }
+ else if (STREQ (*argv, "-readnow"))
+ {
+ readnow = 1;
+ }
+ else if (**argv == '-')
+ {
+ error ("unknown option `%s'", *argv);
+ }
+ else
+ {
+ name = *argv;
+ }
+ argv++;
+ }
+
+ if (name == NULL)
+ {
+ error ("no symbol file name was specified");
+ }
+ else
+ {
+ symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
+ set_initial_language ();
+ }
+ do_cleanups (cleanups);
+ }
+}
+
+/* Set the initial language.
+
+ A better solution would be to record the language in the psymtab when reading
+ partial symbols, and then use it (if known) to set the language. This would
+ be a win for formats that encode the language in an easily discoverable place,
+ such as DWARF. For stabs, we can jump through hoops looking for specially
+ named symbols or try to intuit the language from the specific type of stabs
+ we find, but we can't do that until later when we read in full symbols.
+ FIXME. */
+
+static void
+set_initial_language ()
+{
+ struct partial_symtab *pst;
+ enum language lang = language_unknown;
+
+ pst = find_main_psymtab ();
+ if (pst != NULL)
+ {
+ if (pst -> filename != NULL)
+ {
+ lang = deduce_language_from_filename (pst -> filename);
+ }
+ if (lang == language_unknown)
+ {
+ /* Make C the default language */
+ lang = language_c;
+ }
+ set_language (lang);
+ expected_language = current_language; /* Don't warn the user */
+ }
+}
+
+/* Open file specified by NAME and hand it off to BFD for preliminary
+ analysis. Result is a newly initialized bfd *, which includes a newly
+ malloc'd` copy of NAME (tilde-expanded and made absolute).
+ In case of trouble, error() is called. */
+
+static bfd *
+symfile_bfd_open (name)
+ char *name;
+{
+ bfd *sym_bfd;
+ int desc;
+ char *absolute_name;
+
+ name = tilde_expand (name); /* Returns 1st new malloc'd copy */
+
+ /* Look down path for it, allocate 2nd new malloc'd copy. */
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY | O_BINARY, 0, &absolute_name);
+ if (desc < 0)
+ {
+ make_cleanup (free, name);
+ perror_with_name (name);
+ }
+ free (name); /* Free 1st new malloc'd copy */
+ name = absolute_name; /* Keep 2nd malloc'd copy in bfd */
+ /* It'll be freed in free_objfile(). */
+
+ sym_bfd = bfd_fdopenr (name, gnutarget, desc);
+ if (!sym_bfd)
+ {
+ close (desc);
+ make_cleanup (free, name);
+ error ("\"%s\": can't open to read symbols: %s.", name,
+ bfd_errmsg (bfd_error));
+ }
+ sym_bfd->cacheable = true;
+
+ if (!bfd_check_format (sym_bfd, bfd_object))
+ {
+ bfd_close (sym_bfd); /* This also closes desc */
+ make_cleanup (free, name);
+ error ("\"%s\": can't read symbols: %s.", name,
+ bfd_errmsg (bfd_error));
+ }
+
+ return (sym_bfd);
+}
+
+/* Link a new symtab_fns into the global symtab_fns list. Called on gdb
+ startup by the _initialize routine in each object file format reader,
+ to register information about each format the the reader is prepared
+ to handle. */
+
+void
+add_symtab_fns (sf)
+ struct sym_fns *sf;
+{
+ sf->next = symtab_fns;
+ symtab_fns = sf;
+}
+
+
+/* Initialize to read symbols from the symbol file sym_bfd. It either
+ returns or calls error(). The result is an initialized struct sym_fns
+ in the objfile structure, that contains cached information about the
+ symbol file. */
+
+static void
+find_sym_fns (objfile)
+ struct objfile *objfile;
+{
+ struct sym_fns *sf;
+
+ for (sf = symtab_fns; sf != NULL; sf = sf -> next)
+ {
+ if (strncmp (bfd_get_target (objfile -> obfd),
+ sf -> sym_name, sf -> sym_namelen) == 0)
+ {
+ objfile -> sf = sf;
+ return;
+ }
+ }
+ error ("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown.",
+ bfd_get_target (objfile -> obfd));
+}
+
+/* This function runs the load command of our current target. */
+
+static void
+load_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ target_load (arg, from_tty);
+}
+
+/* This version of "load" should be usable for any target. Currently
+ it is just used for remote targets, not inftarg.c or core files,
+ on the theory that only in that case is it useful.
+
+ Avoiding xmodem and the like seems like a win (a) because we don't have
+ to worry about finding it, and (b) On VMS, fork() is very slow and so
+ we don't want to run a subprocess. On the other hand, I'm not sure how
+ performance compares. */
+void
+generic_load (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ struct cleanup *old_cleanups;
+ asection *s;
+ bfd *loadfile_bfd = bfd_openr (filename, gnutarget);
+ if (loadfile_bfd == NULL)
+ {
+ perror_with_name (filename);
+ return;
+ }
+ old_cleanups = make_cleanup (bfd_close, loadfile_bfd);
+
+ if (!bfd_check_format (loadfile_bfd, bfd_object))
+ {
+ error ("\"%s\" is not an object file: %s", filename,
+ bfd_errmsg (bfd_error));
+ }
+
+ for (s = loadfile_bfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ bfd_size_type size;
+
+ size = bfd_get_section_size_before_reloc (s);
+ if (size > 0)
+ {
+ char *buffer;
+ struct cleanup *old_chain;
+ bfd_vma vma;
+
+ buffer = xmalloc (size);
+ old_chain = make_cleanup (free, buffer);
+
+ vma = bfd_get_section_vma (loadfile_bfd, s);
+
+ /* Is this really necessary? I guess it gives the user something
+ to look at during a long download. */
+ printf_filtered ("Loading section %s, size 0x%lx vma 0x%lx\n",
+ bfd_get_section_name (loadfile_bfd, s),
+ (unsigned long) size, (unsigned long) vma);
+
+ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size);
+
+ target_write_memory (vma, buffer, size);
+
+ do_cleanups (old_chain);
+ }
+ }
+ }
+
+ /* We were doing this in remote-mips.c, I suspect it is right
+ for other targets too. */
+ write_pc (loadfile_bfd->start_address);
+
+ /* FIXME: are we supposed to call symbol_file_add or not? According to
+ a comment from remote-mips.c (where a call to symbol_file_add was
+ commented out), making the call confuses GDB if more than one file is
+ loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c
+ does. */
+
+ do_cleanups (old_cleanups);
+}
+
+/* This function allows the addition of incrementally linked object files.
+ It does not modify any state in the target, only in the debugger. */
+
+/* ARGSUSED */
+static void
+add_symbol_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *name = NULL;
+ CORE_ADDR text_addr;
+ char *arg;
+ int readnow = 0;
+ int mapped = 0;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("add-symbol-file takes a file name and an address");
+ }
+
+ /* Make a copy of the string that we can safely write into. */
+
+ args = strdup (args);
+ make_cleanup (free, args);
+
+ /* Pick off any -option args and the file name. */
+
+ while ((*args != '\000') && (name == NULL))
+ {
+ while (isspace (*args)) {args++;}
+ arg = args;
+ while ((*args != '\000') && !isspace (*args)) {args++;}
+ if (*args != '\000')
+ {
+ *args++ = '\000';
+ }
+ if (*arg != '-')
+ {
+ name = arg;
+ }
+ else if (STREQ (arg, "-mapped"))
+ {
+ mapped = 1;
+ }
+ else if (STREQ (arg, "-readnow"))
+ {
+ readnow = 1;
+ }
+ else
+ {
+ error ("unknown option `%s'", arg);
+ }
+ }
+
+ /* After picking off any options and the file name, args should be
+ left pointing at the remainder of the command line, which should
+ be the address expression to evaluate. */
+
+ if ((name == NULL) || (*args == '\000') )
+ {
+ error ("add-symbol-file takes a file name and an address");
+ }
+ name = tilde_expand (name);
+ make_cleanup (free, name);
+
+ text_addr = parse_and_eval_address (args);
+
+ if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n",
+ name, local_hex_string ((unsigned long)text_addr)))
+ error ("Not confirmed.");
+
+ symbol_file_add (name, 0, text_addr, 0, mapped, readnow);
+}
+
+/* Re-read symbols if a symbol-file has changed. */
+void
+reread_symbols ()
+{
+ struct objfile *objfile;
+ long new_modtime;
+ int reread_one = 0;
+ struct stat new_statbuf;
+ int res;
+
+ /* With the addition of shared libraries, this should be modified,
+ the load time should be saved in the partial symbol tables, since
+ different tables may come from different source files. FIXME.
+ This routine should then walk down each partial symbol table
+ and see if the symbol table that it originates from has been changed */
+
+the_big_top:
+ for (objfile = object_files; objfile; objfile = objfile->next) {
+ if (objfile->obfd) {
+#ifdef IBM6000_TARGET
+ /* If this object is from a shared library, then you should
+ stat on the library name, not member name. */
+
+ if (objfile->obfd->my_archive)
+ res = stat (objfile->obfd->my_archive->filename, &new_statbuf);
+ else
+#endif
+ res = stat (objfile->name, &new_statbuf);
+ if (res != 0) {
+ /* FIXME, should use print_sys_errmsg but it's not filtered. */
+ printf_filtered ("`%s' has disappeared; keeping its symbols.\n",
+ objfile->name);
+ continue;
+ }
+ new_modtime = new_statbuf.st_mtime;
+ if (new_modtime != objfile->mtime) {
+ printf_filtered ("`%s' has changed; re-reading symbols.\n",
+ objfile->name);
+ /* FIXME, this should use a different command...that would only
+ affect this objfile's symbols, and would reset objfile->mtime.
+ (objfile->mtime = new_modtime;)
+ HOWEVER, that command isn't written yet -- so call symbol_file_
+ command, and restart the scan from the top, because it munges
+ the object_files list. */
+ symbol_file_command (objfile->name, 0);
+ reread_one = 1;
+ goto the_big_top; /* Start over. */
+ }
+ }
+ }
+
+ if (reread_one)
+ breakpoint_re_set ();
+}
+
+
+enum language
+deduce_language_from_filename (filename)
+ char *filename;
+{
+ char *c;
+
+ if (0 == filename)
+ ; /* Get default */
+ else if (0 == (c = strrchr (filename, '.')))
+ ; /* Get default. */
+ else if (STREQ(c,".mod"))
+ return language_m2;
+ else if (STREQ(c,".c"))
+ return language_c;
+ else if (STREQ (c,".cc") || STREQ (c,".C") || STREQ (c, ".cxx"))
+ return language_cplus;
+ else if (STREQ (c,".ch") || STREQ (c,".c186") || STREQ (c,".c286"))
+ return language_chill;
+
+ return language_unknown; /* default */
+}
+
+/* allocate_symtab:
+
+ Allocate and partly initialize a new symbol table. Return a pointer
+ to it. error() if no space.
+
+ Caller must set these fields:
+ LINETABLE(symtab)
+ symtab->blockvector
+ symtab->dirname
+ symtab->free_code
+ symtab->free_ptr
+ initialize any EXTRA_SYMTAB_INFO
+ possibly free_named_symtabs (symtab->filename);
+ */
+
+struct symtab *
+allocate_symtab (filename, objfile)
+ char *filename;
+ struct objfile *objfile;
+{
+ register struct symtab *symtab;
+
+ symtab = (struct symtab *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symtab));
+ memset (symtab, 0, sizeof (*symtab));
+ symtab -> filename = obsavestring (filename, strlen (filename),
+ &objfile -> symbol_obstack);
+ symtab -> fullname = NULL;
+ symtab -> language = deduce_language_from_filename (filename);
+
+ /* Hook it to the objfile it comes from */
+
+ symtab -> objfile = objfile;
+ symtab -> next = objfile -> symtabs;
+ objfile -> symtabs = symtab;
+
+#ifdef INIT_EXTRA_SYMTAB_INFO
+ INIT_EXTRA_SYMTAB_INFO (symtab);
+#endif
+
+ return (symtab);
+}
+
+struct partial_symtab *
+allocate_psymtab (filename, objfile)
+ char *filename;
+ struct objfile *objfile;
+{
+ struct partial_symtab *psymtab;
+
+ if (objfile -> free_psymtabs)
+ {
+ psymtab = objfile -> free_psymtabs;
+ objfile -> free_psymtabs = psymtab -> next;
+ }
+ else
+ psymtab = (struct partial_symtab *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ memset (psymtab, 0, sizeof (struct partial_symtab));
+ psymtab -> filename = obsavestring (filename, strlen (filename),
+ &objfile -> psymbol_obstack);
+ psymtab -> symtab = NULL;
+
+ /* Hook it to the objfile it comes from */
+
+ psymtab -> objfile = objfile;
+ psymtab -> next = objfile -> psymtabs;
+ objfile -> psymtabs = psymtab;
+
+ return (psymtab);
+}
+
+
+/* Reset all data structures in gdb which may contain references to symbol
+ table date. */
+
+void
+clear_symtab_users ()
+{
+ /* Someday, we should do better than this, by only blowing away
+ the things that really need to be blown. */
+ clear_value_history ();
+ clear_displays ();
+ clear_internalvars ();
+ breakpoint_re_set ();
+ set_default_breakpoint (0, 0, 0, 0);
+ current_source_symtab = 0;
+ current_source_line = 0;
+}
+
+/* clear_symtab_users_once:
+
+ This function is run after symbol reading, or from a cleanup.
+ If an old symbol table was obsoleted, the old symbol table
+ has been blown away, but the other GDB data structures that may
+ reference it have not yet been cleared or re-directed. (The old
+ symtab was zapped, and the cleanup queued, in free_named_symtab()
+ below.)
+
+ This function can be queued N times as a cleanup, or called
+ directly; it will do all the work the first time, and then will be a
+ no-op until the next time it is queued. This works by bumping a
+ counter at queueing time. Much later when the cleanup is run, or at
+ the end of symbol processing (in case the cleanup is discarded), if
+ the queued count is greater than the "done-count", we do the work
+ and set the done-count to the queued count. If the queued count is
+ less than or equal to the done-count, we just ignore the call. This
+ is needed because reading a single .o file will often replace many
+ symtabs (one per .h file, for example), and we don't want to reset
+ the breakpoints N times in the user's face.
+
+ The reason we both queue a cleanup, and call it directly after symbol
+ reading, is because the cleanup protects us in case of errors, but is
+ discarded if symbol reading is successful. */
+
+#if 0
+/* FIXME: As free_named_symtabs is currently a big noop this function
+ is no longer needed. */
+static void
+clear_symtab_users_once PARAMS ((void));
+
+static int clear_symtab_users_queued;
+static int clear_symtab_users_done;
+
+static void
+clear_symtab_users_once ()
+{
+ /* Enforce once-per-`do_cleanups'-semantics */
+ if (clear_symtab_users_queued <= clear_symtab_users_done)
+ return;
+ clear_symtab_users_done = clear_symtab_users_queued;
+
+ clear_symtab_users ();
+}
+#endif
+
+/* Delete the specified psymtab, and any others that reference it. */
+
+static void
+cashier_psymtab (pst)
+ struct partial_symtab *pst;
+{
+ struct partial_symtab *ps, *pprev = NULL;
+ int i;
+
+ /* Find its previous psymtab in the chain */
+ for (ps = pst->objfile->psymtabs; ps; ps = ps->next) {
+ if (ps == pst)
+ break;
+ pprev = ps;
+ }
+
+ if (ps) {
+ /* Unhook it from the chain. */
+ if (ps == pst->objfile->psymtabs)
+ pst->objfile->psymtabs = ps->next;
+ else
+ pprev->next = ps->next;
+
+ /* FIXME, we can't conveniently deallocate the entries in the
+ partial_symbol lists (global_psymbols/static_psymbols) that
+ this psymtab points to. These just take up space until all
+ the psymtabs are reclaimed. Ditto the dependencies list and
+ filename, which are all in the psymbol_obstack. */
+
+ /* We need to cashier any psymtab that has this one as a dependency... */
+again:
+ for (ps = pst->objfile->psymtabs; ps; ps = ps->next) {
+ for (i = 0; i < ps->number_of_dependencies; i++) {
+ if (ps->dependencies[i] == pst) {
+ cashier_psymtab (ps);
+ goto again; /* Must restart, chain has been munged. */
+ }
+ }
+ }
+ }
+}
+
+/* If a symtab or psymtab for filename NAME is found, free it along
+ with any dependent breakpoints, displays, etc.
+ Used when loading new versions of object modules with the "add-file"
+ command. This is only called on the top-level symtab or psymtab's name;
+ it is not called for subsidiary files such as .h files.
+
+ Return value is 1 if we blew away the environment, 0 if not.
+ FIXME. The return valu appears to never be used.
+
+ FIXME. I think this is not the best way to do this. We should
+ work on being gentler to the environment while still cleaning up
+ all stray pointers into the freed symtab. */
+
+int
+free_named_symtabs (name)
+ char *name;
+{
+#if 0
+ /* FIXME: With the new method of each objfile having it's own
+ psymtab list, this function needs serious rethinking. In particular,
+ why was it ever necessary to toss psymtabs with specific compilation
+ unit filenames, as opposed to all psymtabs from a particular symbol
+ file? -- fnf
+ Well, the answer is that some systems permit reloading of particular
+ compilation units. We want to blow away any old info about these
+ compilation units, regardless of which objfiles they arrived in. --gnu. */
+
+ register struct symtab *s;
+ register struct symtab *prev;
+ register struct partial_symtab *ps;
+ struct blockvector *bv;
+ int blewit = 0;
+
+ /* We only wack things if the symbol-reload switch is set. */
+ if (!symbol_reloading)
+ return 0;
+
+ /* Some symbol formats have trouble providing file names... */
+ if (name == 0 || *name == '\0')
+ return 0;
+
+ /* Look for a psymtab with the specified name. */
+
+again2:
+ for (ps = partial_symtab_list; ps; ps = ps->next) {
+ if (STREQ (name, ps->filename)) {
+ cashier_psymtab (ps); /* Blow it away...and its little dog, too. */
+ goto again2; /* Must restart, chain has been munged */
+ }
+ }
+
+ /* Look for a symtab with the specified name. */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ if (STREQ (name, s->filename))
+ break;
+ prev = s;
+ }
+
+ if (s)
+ {
+ if (s == symtab_list)
+ symtab_list = s->next;
+ else
+ prev->next = s->next;
+
+ /* For now, queue a delete for all breakpoints, displays, etc., whether
+ or not they depend on the symtab being freed. This should be
+ changed so that only those data structures affected are deleted. */
+
+ /* But don't delete anything if the symtab is empty.
+ This test is necessary due to a bug in "dbxread.c" that
+ causes empty symtabs to be created for N_SO symbols that
+ contain the pathname of the object file. (This problem
+ has been fixed in GDB 3.9x). */
+
+ bv = BLOCKVECTOR (s);
+ if (BLOCKVECTOR_NBLOCKS (bv) > 2
+ || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK))
+ || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)))
+ {
+ complain (&oldsyms_complaint, name);
+
+ clear_symtab_users_queued++;
+ make_cleanup (clear_symtab_users_once, 0);
+ blewit = 1;
+ } else {
+ complain (&empty_symtab_complaint, name);
+ }
+
+ free_symtab (s);
+ }
+ else
+ {
+ /* It is still possible that some breakpoints will be affected
+ even though no symtab was found, since the file might have
+ been compiled without debugging, and hence not be associated
+ with a symtab. In order to handle this correctly, we would need
+ to keep a list of text address ranges for undebuggable files.
+ For now, we do nothing, since this is a fairly obscure case. */
+ ;
+ }
+
+ /* FIXME, what about the minimal symbol table? */
+ return blewit;
+#else
+ return (0);
+#endif
+}
+
+/* Allocate and partially fill a partial symtab. It will be
+ completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal). */
+
+
+struct partial_symtab *
+start_psymtab_common (objfile, section_offsets,
+ filename, textlow, global_syms, static_syms)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ char *filename;
+ CORE_ADDR textlow;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (filename, objfile);
+ psymtab -> section_offsets = section_offsets;
+ psymtab -> textlow = textlow;
+ psymtab -> texthigh = psymtab -> textlow; /* default */
+ psymtab -> globals_offset = global_syms - objfile -> global_psymbols.list;
+ psymtab -> statics_offset = static_syms - objfile -> static_psymbols.list;
+ return (psymtab);
+}
+
+/* Debugging versions of functions that are usually inline macros
+ (see symfile.h). */
+
+#if !INLINE_ADD_PSYMBOL
+
+/* Add a symbol with a long value to a psymtab.
+ Since one arg is a struct, we pass in a ptr and deref it (sigh). */
+
+void
+add_psymbol_to_list (name, namelength, namespace, class, list, val, language,
+ objfile)
+ char *name;
+ int namelength;
+ enum namespace namespace;
+ enum address_class class;
+ struct psymbol_allocation_list *list;
+ long val;
+ enum language language;
+ struct objfile *objfile;
+{
+ register struct partial_symbol *psym;
+ register char *demangled_name;
+
+ if (list->next >= list->list + list->size)
+ {
+ extend_psymbol_list (list,objfile);
+ }
+ psym = list->next++;
+
+ SYMBOL_NAME (psym) =
+ (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
+ memcpy (SYMBOL_NAME (psym), name, namelength);
+ SYMBOL_NAME (psym)[namelength] = '\0';
+ SYMBOL_VALUE (psym) = val;
+ SYMBOL_LANGUAGE (psym) = language;
+ PSYMBOL_NAMESPACE (psym) = namespace;
+ PSYMBOL_CLASS (psym) = class;
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack);
+}
+
+/* Add a symbol with a CORE_ADDR value to a psymtab. */
+
+void
+add_psymbol_addr_to_list (name, namelength, namespace, class, list, val,
+ language, objfile)
+ char *name;
+ int namelength;
+ enum namespace namespace;
+ enum address_class class;
+ struct psymbol_allocation_list *list;
+ CORE_ADDR val;
+ enum language language;
+ struct objfile *objfile;
+{
+ register struct partial_symbol *psym;
+ register char *demangled_name;
+
+ if (list->next >= list->list + list->size)
+ {
+ extend_psymbol_list (list,objfile);
+ }
+ psym = list->next++;
+
+ SYMBOL_NAME (psym) =
+ (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
+ memcpy (SYMBOL_NAME (psym), name, namelength);
+ SYMBOL_NAME (psym)[namelength] = '\0';
+ SYMBOL_VALUE_ADDRESS (psym) = val;
+ SYMBOL_LANGUAGE (psym) = language;
+ PSYMBOL_NAMESPACE (psym) = namespace;
+ PSYMBOL_CLASS (psym) = class;
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack);
+}
+
+#endif /* !INLINE_ADD_PSYMBOL */
+
+
+void
+_initialize_symfile ()
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table from executable file FILE.\n\
+The `file' command can also load symbol tables, as well as setting the file\n\
+to execute.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command,
+ "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
+The second argument provides the starting address of the file's text.",
+ &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("load", class_files, load_command,
+ "Dynamically load FILE into the running program, and record its symbols\n\
+for access from GDB.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_show_from_set
+ (add_set_cmd ("symbol-reloading", class_support, var_boolean,
+ (char *)&symbol_reloading,
+ "Set dynamic symbol table reloading multiple times in one run.",
+ &setlist),
+ &showlist);
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/symfile.h b/gnu/usr.bin/gdb/gdb/symfile.h
new file mode 100644
index 000000000000..70bc73db4b00
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.h
@@ -0,0 +1,228 @@
+/* Definitions for reading symbol files into GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (SYMFILE_H)
+#define SYMFILE_H
+
+/* This file requires that you first include "bfd.h". */
+
+struct psymbol_allocation_list {
+ struct partial_symbol *list;
+ struct partial_symbol *next;
+ int size;
+};
+
+/* Structure to keep track of symbol reading functions for various
+ object file types. */
+
+struct sym_fns {
+
+ /* is the name, or name prefix, of the BFD "target type" that this
+ set of functions handles. E.g. "a.out" or "sunOs" or "coff" or "elf". */
+
+ char *sym_name;
+
+ /* counts how many bytes of sym_name should be checked against the
+ BFD target type of the file being read. If an exact match is
+ desired, specify the number of characters in sym_name plus 1 for
+ the '\0'. If a prefix match is desired, specify the number of
+ characters in sym_name. */
+
+ int sym_namelen;
+
+ /* Initializes anything that is global to the entire symbol table. It is
+ called during symbol_file_add, when we begin debugging an entirely new
+ program. */
+
+ void (*sym_new_init) PARAMS ((struct objfile *));
+
+ /* Reads any initial information from a symbol file, and initializes the
+ struct sym_fns SF in preparation for sym_read(). It is called every
+ time we read a symbol file for any reason. */
+
+ void (*sym_init) PARAMS ((struct objfile *));
+
+ /* sym_read (objfile, addr, mainline)
+ Reads a symbol file into a psymtab (or possibly a symtab).
+ OBJFILE is the objfile struct for the file we are reading.
+ SECTION_OFFSETS
+ are the offset between the file's specified section addresses and
+ their true addresses in memory.
+ MAINLINE is 1 if this is the
+ main symbol table being read, and 0 if a secondary
+ symbol file (e.g. shared library or dynamically loaded file)
+ is being read. */
+
+ void (*sym_read) PARAMS ((struct objfile *, struct section_offsets *, int));
+
+ /* Called when we are finished with an objfile. Should do all cleanup
+ that is specific to the object file format for the particular objfile. */
+
+ void (*sym_finish) PARAMS ((struct objfile *));
+
+ /* This function produces a file-dependent section_offsets structure,
+ allocated in the objfile's storage, and based on the parameter.
+ The parameter is currently a CORE_ADDR (FIXME!) for backward compatibility
+ with the higher levels of GDB. It should probably be changed to
+ a string, where NULL means the default, and others are parsed in a file
+ dependent way. The result of this function is handed in to sym_read. */
+
+ struct section_offsets *(*sym_offsets) PARAMS ((struct objfile *, CORE_ADDR));
+
+ /* Finds the next struct sym_fns. They are allocated and initialized
+ in whatever module implements the functions pointed to; an
+ initializer calls add_symtab_fns to add them to the global chain. */
+
+ struct sym_fns *next;
+
+};
+
+extern void
+extend_psymbol_list PARAMS ((struct psymbol_allocation_list *,
+ struct objfile *));
+
+/* Add any kind of symbol to a psymbol_allocation_list. */
+
+#ifndef INLINE_ADD_PSYMBOL
+#define INLINE_ADD_PSYMBOL 1
+#endif
+
+#if !INLINE_ADD_PSYMBOL
+
+/* Since one arg is a struct, we have to pass in a ptr and deref it (sigh) */
+
+#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ add_psymbol_to_list (name, namelength, namespace, class, &list, value, language, objfile)
+
+#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ add_psymbol_addr_to_list (name, namelength, namespace, class, &list, value, language, objfile)
+
+#else /* !INLINE_ADD_PSYMBOL */
+
+#include "demangle.h"
+
+#define ADD_PSYMBOL_VT_TO_LIST(NAME,NAMELENGTH,NAMESPACE,CLASS,LIST,VALUE,VT,LANGUAGE, OBJFILE) \
+ do { \
+ register struct partial_symbol *psym; \
+ if ((LIST).next >= (LIST).list + (LIST).size) \
+ extend_psymbol_list (&(LIST),(OBJFILE)); \
+ psym = (LIST).next++; \
+ SYMBOL_NAME (psym) = \
+ (char *) obstack_alloc (&objfile->psymbol_obstack, \
+ (NAMELENGTH) + 1); \
+ memcpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH)); \
+ SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0'; \
+ SYMBOL_NAMESPACE (psym) = (NAMESPACE); \
+ PSYMBOL_CLASS (psym) = (CLASS); \
+ VT (psym) = (VALUE); \
+ SYMBOL_LANGUAGE (psym) = (LANGUAGE); \
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack); \
+ } while (0);
+
+/* Add a symbol with an integer value to a psymtab. */
+
+#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE, language, objfile)
+
+/* Add a symbol with a CORE_ADDR value to a psymtab. */
+
+#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile)\
+ ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE_ADDRESS, language, objfile)
+
+#endif /* INLINE_ADD_PSYMBOL */
+
+ /* Functions */
+
+extern void
+sort_pst_symbols PARAMS ((struct partial_symtab *));
+
+extern struct symtab *
+allocate_symtab PARAMS ((char *, struct objfile *));
+
+extern int
+free_named_symtabs PARAMS ((char *));
+
+extern void
+fill_in_vptr_fieldno PARAMS ((struct type *));
+
+extern void
+add_symtab_fns PARAMS ((struct sym_fns *));
+
+extern void
+init_entry_point_info PARAMS ((struct objfile *));
+
+extern void
+syms_from_objfile PARAMS ((struct objfile *, CORE_ADDR, int, int));
+
+extern void
+new_symfile_objfile PARAMS ((struct objfile *, int, int));
+
+extern struct partial_symtab *
+start_psymtab_common PARAMS ((struct objfile *, struct section_offsets *,
+ char *, CORE_ADDR,
+ struct partial_symbol *,
+ struct partial_symbol *));
+
+/* Sorting your symbols for fast lookup or alphabetical printing. */
+
+extern void
+sort_block_syms PARAMS ((struct block *));
+
+extern void
+sort_symtab_syms PARAMS ((struct symtab *));
+
+extern void
+sort_all_symtab_syms PARAMS ((void));
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+extern char *
+obsavestring PARAMS ((char *, int, struct obstack *));
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+extern char *
+obconcat PARAMS ((struct obstack *obstackp, const char *, const char *,
+ const char *));
+
+ /* Variables */
+
+/* From symfile.c */
+
+extern struct partial_symtab *
+allocate_psymtab PARAMS ((char *, struct objfile *));
+
+/* Remote targets may wish to use this as their load function. */
+extern void generic_load PARAMS ((char *name, int from_tty));
+
+/* From dwarfread.c */
+
+extern void
+dwarf_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, int,
+ file_ptr, unsigned int, file_ptr, unsigned int));
+
+/* From demangle.c */
+
+extern void
+set_demangling_style PARAMS ((char *));
+
+#endif /* !defined(SYMFILE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/symmisc.c b/gnu/usr.bin/gdb/gdb/symmisc.c
new file mode 100644
index 000000000000..411a53bef96a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symmisc.c
@@ -0,0 +1,857 @@
+/* Do various things to symbol tables (other than lookup), for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "obstack.h"
+#include "language.h"
+
+#include <string.h>
+
+#ifndef DEV_TTY
+#define DEV_TTY "/dev/tty"
+#endif
+
+/* Unfortunately for debugging, stderr is usually a macro. This is painful
+ when calling functions that take FILE *'s from the debugger.
+ So we make a variable which has the same value and which is accessible when
+ debugging GDB with itself. Because stdin et al need not be constants,
+ we initialize them in the _initialize_symmisc function at the bottom
+ of the file. */
+FILE *std_in;
+FILE *std_out;
+FILE *std_err;
+
+/* Prototypes for local functions */
+
+static void
+dump_symtab PARAMS ((struct objfile *, struct symtab *, FILE *));
+
+static void
+dump_psymtab PARAMS ((struct objfile *, struct partial_symtab *, FILE *));
+
+static void
+dump_msymbols PARAMS ((struct objfile *, FILE *));
+
+static void
+dump_objfile PARAMS ((struct objfile *));
+
+static int
+block_depth PARAMS ((struct block *));
+
+static void
+print_partial_symbol PARAMS ((struct partial_symbol *, int, char *, FILE *));
+
+struct print_symbol_args {
+ struct symbol *symbol;
+ int depth;
+ FILE *outfile;
+};
+
+static int print_symbol PARAMS ((char *));
+
+static void
+free_symtab_block PARAMS ((struct objfile *, struct block *));
+
+
+/* Free a struct block <- B and all the symbols defined in that block. */
+
+static void
+free_symtab_block (objfile, b)
+ struct objfile *objfile;
+ struct block *b;
+{
+ register int i, n;
+ n = BLOCK_NSYMS (b);
+ for (i = 0; i < n; i++)
+ {
+ mfree (objfile -> md, SYMBOL_NAME (BLOCK_SYM (b, i)));
+ mfree (objfile -> md, (PTR) BLOCK_SYM (b, i));
+ }
+ mfree (objfile -> md, (PTR) b);
+}
+
+/* Free all the storage associated with the struct symtab <- S.
+ Note that some symtabs have contents malloc'ed structure by structure,
+ while some have contents that all live inside one big block of memory,
+ and some share the contents of another symbol table and so you should
+ not free the contents on their behalf (except sometimes the linetable,
+ which maybe per symtab even when the rest is not).
+ It is s->free_code that says which alternative to use. */
+
+void
+free_symtab (s)
+ register struct symtab *s;
+{
+ register int i, n;
+ register struct blockvector *bv;
+
+ switch (s->free_code)
+ {
+ case free_nothing:
+ /* All the contents are part of a big block of memory (an obstack),
+ and some other symtab is in charge of freeing that block.
+ Therefore, do nothing. */
+ break;
+
+ case free_contents:
+ /* Here all the contents were malloc'ed structure by structure
+ and must be freed that way. */
+ /* First free the blocks (and their symbols. */
+ bv = BLOCKVECTOR (s);
+ n = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < n; i++)
+ free_symtab_block (s -> objfile, BLOCKVECTOR_BLOCK (bv, i));
+ /* Free the blockvector itself. */
+ mfree (s -> objfile -> md, (PTR) bv);
+ /* Also free the linetable. */
+
+ case free_linetable:
+ /* Everything will be freed either by our `free_ptr'
+ or by some other symtab, except for our linetable.
+ Free that now. */
+ if (LINETABLE (s))
+ mfree (s -> objfile -> md, (PTR) LINETABLE (s));
+ break;
+ }
+
+ /* If there is a single block of memory to free, free it. */
+ if (s -> free_ptr != NULL)
+ mfree (s -> objfile -> md, s -> free_ptr);
+
+ /* Free source-related stuff */
+ if (s -> line_charpos != NULL)
+ mfree (s -> objfile -> md, (PTR) s -> line_charpos);
+ if (s -> fullname != NULL)
+ mfree (s -> objfile -> md, s -> fullname);
+ mfree (s -> objfile -> md, (PTR) s);
+}
+
+#if MAINTENANCE_CMDS
+
+static void
+dump_objfile (objfile)
+ struct objfile *objfile;
+{
+ struct symtab *symtab;
+ struct partial_symtab *psymtab;
+
+ printf_filtered ("\nObject file %s: ", objfile -> name);
+ printf_filtered ("Objfile at %lx, bfd at %lx, %d minsyms\n\n",
+ (unsigned long) objfile,
+ (unsigned long) objfile -> obfd,
+ objfile->minimal_symbol_count);
+
+ if (objfile -> psymtabs)
+ {
+ printf_filtered ("Psymtabs:\n");
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ printf_filtered ("%s at %lx, ",
+ psymtab -> filename, (unsigned long) psymtab);
+ if (psymtab -> objfile != objfile)
+ {
+ printf_filtered ("NOT ON CHAIN! ");
+ }
+ wrap_here (" ");
+ }
+ printf_filtered ("\n\n");
+ }
+
+ if (objfile -> symtabs)
+ {
+ printf_filtered ("Symtabs:\n");
+ for (symtab = objfile -> symtabs;
+ symtab != NULL;
+ symtab = symtab->next)
+ {
+ printf_filtered ("%s at %lx, ",
+ symtab -> filename, (unsigned long) symtab);
+ if (symtab -> objfile != objfile)
+ {
+ printf_filtered ("NOT ON CHAIN! ");
+ }
+ wrap_here (" ");
+ }
+ printf_filtered ("\n\n");
+ }
+}
+
+/* Print minimal symbols from this objfile. */
+
+static void
+dump_msymbols (objfile, outfile)
+ struct objfile *objfile;
+ FILE *outfile;
+{
+ struct minimal_symbol *msymbol;
+ int index;
+ char ms_type;
+
+ fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile -> name);
+ if (objfile -> minimal_symbol_count == 0)
+ {
+ fprintf_filtered (outfile, "No minimal symbols found.\n");
+ return;
+ }
+ for (index = 0, msymbol = objfile -> msymbols;
+ SYMBOL_NAME (msymbol) != NULL; msymbol++, index++)
+ {
+ switch (msymbol -> type)
+ {
+ case mst_unknown:
+ ms_type = 'u';
+ break;
+ case mst_text:
+ ms_type = 'T';
+ break;
+ case mst_data:
+ ms_type = 'D';
+ break;
+ case mst_bss:
+ ms_type = 'B';
+ break;
+ case mst_abs:
+ ms_type = 'A';
+ break;
+ case mst_file_text:
+ ms_type = 't';
+ break;
+ case mst_file_data:
+ ms_type = 'd';
+ break;
+ case mst_file_bss:
+ ms_type = 'b';
+ break;
+ default:
+ ms_type = '?';
+ break;
+ }
+ fprintf_filtered (outfile, "[%2d] %c %#10lx %s", index, ms_type,
+ SYMBOL_VALUE_ADDRESS (msymbol), SYMBOL_NAME (msymbol));
+ if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL)
+ {
+ fprintf_filtered (outfile, " %s", SYMBOL_DEMANGLED_NAME (msymbol));
+ }
+ fputs_filtered ("\n", outfile);
+ }
+ if (objfile -> minimal_symbol_count != index)
+ {
+ warning ("internal error: minimal symbol count %d != %d",
+ objfile -> minimal_symbol_count, index);
+ }
+ fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_psymtab (objfile, psymtab, outfile)
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+ FILE *outfile;
+{
+ int i;
+
+ fprintf_filtered (outfile, "\nPartial symtab for source file %s ",
+ psymtab -> filename);
+ fprintf_filtered (outfile, "(object 0x%lx)\n\n", (unsigned long) psymtab);
+ fprintf (outfile, " Read from object file %s (0x%lx)\n",
+ objfile -> name, (unsigned long) objfile);
+
+ if (psymtab -> readin)
+ {
+ fprintf_filtered (outfile,
+ " Full symtab was read (at 0x%lx by function at 0x%lx)\n",
+ (unsigned long) psymtab -> symtab,
+ (unsigned long) psymtab -> read_symtab);
+ }
+
+ /* FIXME, we need to be able to print the relocation stuff. */
+ /* This prints some garbage for anything but stabs right now. FIXME. */
+ if (psymtab->section_offsets)
+ fprintf_filtered (outfile,
+ " Relocate symbols by 0x%lx, 0x%lx, 0x%lx, 0x%lx.\n",
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 0),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 1),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 2),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 3));
+
+ fprintf_filtered (outfile, " Symbols cover text addresses 0x%lx-0x%lx\n",
+ (unsigned long) psymtab -> textlow,
+ (unsigned long) psymtab -> texthigh);
+ fprintf_filtered (outfile, " Depends on %d other partial symtabs.\n",
+ psymtab -> number_of_dependencies);
+ for (i = 0; i < psymtab -> number_of_dependencies; i++)
+ {
+ fprintf_filtered (outfile, " %d 0x%lx %s\n", i,
+ (unsigned long) psymtab -> dependencies[i],
+ psymtab -> dependencies[i] -> filename);
+ }
+ if (psymtab -> n_global_syms > 0)
+ {
+ print_partial_symbol (objfile -> global_psymbols.list
+ + psymtab -> globals_offset,
+ psymtab -> n_global_syms, "Global", outfile);
+ }
+ if (psymtab -> n_static_syms > 0)
+ {
+ print_partial_symbol (objfile -> static_psymbols.list
+ + psymtab -> statics_offset,
+ psymtab -> n_static_syms, "Static", outfile);
+ }
+ fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_symtab (objfile, symtab, outfile)
+ struct objfile *objfile;
+ struct symtab *symtab;
+ FILE *outfile;
+{
+ register int i, j;
+ int len, blen;
+ register struct linetable *l;
+ struct blockvector *bv;
+ register struct block *b;
+ int depth;
+
+ fprintf (outfile, "\nSymtab for file %s\n", symtab->filename);
+ fprintf (outfile, "Read from object file %s (%lx)\n", objfile->name,
+ (unsigned long) objfile);
+ fprintf (outfile, "Language: %s\n", language_str (symtab -> language));
+
+ /* First print the line table. */
+ l = LINETABLE (symtab);
+ if (l) {
+ fprintf (outfile, "\nLine table:\n\n");
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ fprintf (outfile, " line %ld at %lx\n", l->item[i].line,
+ (unsigned long) l->item[i].pc);
+ }
+ /* Now print the block info. */
+ fprintf (outfile, "\nBlockvector:\n\n");
+ bv = BLOCKVECTOR (symtab);
+ len = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < len; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ depth = block_depth (b) * 2;
+ print_spaces (depth, outfile);
+ fprintf (outfile, "block #%03d (object 0x%lx) ", i, (unsigned long) b);
+ fprintf (outfile, "[0x%lx..0x%lx]",
+ (unsigned long) BLOCK_START (b),
+ (unsigned long) BLOCK_END (b));
+ if (BLOCK_SUPERBLOCK (b))
+ fprintf (outfile, " (under 0x%lx)",
+ (unsigned long) BLOCK_SUPERBLOCK (b));
+ if (BLOCK_FUNCTION (b))
+ {
+ fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fprintf (outfile, " %s",
+ SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)));
+ }
+ }
+ if (BLOCK_GCC_COMPILED(b))
+ fprintf (outfile, " gcc%d compiled", BLOCK_GCC_COMPILED(b));
+ fputc ('\n', outfile);
+ blen = BLOCK_NSYMS (b);
+ for (j = 0; j < blen; j++)
+ {
+ struct print_symbol_args s;
+ s.symbol = BLOCK_SYM (b, j);
+ s.depth = depth + 1;
+ s.outfile = outfile;
+ catch_errors (print_symbol, &s, "Error printing symbol:\n",
+ RETURN_MASK_ERROR);
+ }
+ }
+ fprintf (outfile, "\n");
+}
+
+void
+maintenance_print_symbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ FILE *outfile;
+ struct cleanup *cleanups;
+ char *symname = NULL;
+ char *filename = DEV_TTY;
+ struct objfile *objfile;
+ struct symtab *s;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-symbols takes an output file name and optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, (char *) outfile);
+
+ immediate_quit++;
+ ALL_SYMTABS (objfile, s)
+ if (symname == NULL || (STREQ (symname, s -> filename)))
+ dump_symtab (objfile, s, outfile);
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE. ARGS->DEPTH says how
+ far to indent. ARGS is really a struct print_symbol_args *, but is
+ declared as char * to get it past catch_errors. Returns 0 for error,
+ 1 for success. */
+
+static int
+print_symbol (args)
+ char *args;
+{
+ struct symbol *symbol = ((struct print_symbol_args *)args)->symbol;
+ int depth = ((struct print_symbol_args *)args)->depth;
+ FILE *outfile = ((struct print_symbol_args *)args)->outfile;
+
+ print_spaces (depth, outfile);
+ if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+ {
+ fprintf (outfile, "label %s at 0x%lx\n", SYMBOL_SOURCE_NAME (symbol),
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ return 1;
+ }
+ if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+ {
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol)))
+ {
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ else
+ {
+ fprintf (outfile, "%s %s = ",
+ (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
+ ? "enum"
+ : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
+ ? "struct" : "union")),
+ SYMBOL_NAME (symbol));
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ fprintf (outfile, ";\n");
+ }
+ else
+ {
+ if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+ fprintf (outfile, "typedef ");
+ if (SYMBOL_TYPE (symbol))
+ {
+ /* Print details of types, except for enums where it's clutter. */
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol),
+ outfile,
+ TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM,
+ depth);
+ fprintf (outfile, "; ");
+ }
+ else
+ fprintf (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol));
+
+ switch (SYMBOL_CLASS (symbol))
+ {
+ case LOC_CONST:
+ fprintf (outfile, "const %ld (0x%lx),",
+ SYMBOL_VALUE (symbol),
+ (unsigned long) SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_CONST_BYTES:
+ fprintf (outfile, "const %u hex bytes:",
+ TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+ {
+ unsigned i;
+ for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+ fprintf (outfile, " %02x",
+ (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]);
+ fprintf (outfile, ",");
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf (outfile, "static at 0x%lx,",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ break;
+
+ case LOC_REGISTER:
+ fprintf (outfile, "register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_ARG:
+ fprintf (outfile, "arg at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL_ARG:
+ fprintf (outfile, "arg at offset 0x%lx from fp,",
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REF_ARG:
+ fprintf (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM:
+ fprintf (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM_ADDR:
+ fprintf (outfile, "address parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL:
+ fprintf (outfile, "local at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_BASEREG:
+ fprintf (outfile, "local at 0x%lx from register %d",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_BASEREG_ARG:
+ fprintf (outfile, "arg at 0x%lx from register %d,",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_TYPEDEF:
+ break;
+
+ case LOC_LABEL:
+ fprintf (outfile, "label at 0x%lx",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ break;
+
+ case LOC_BLOCK:
+ fprintf (outfile, "block (object 0x%lx) starting at 0x%lx,",
+ (unsigned long) SYMBOL_BLOCK_VALUE (symbol),
+ (unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ fprintf (outfile, "optimized out");
+ break;
+
+ default:
+ fprintf (outfile, "botched symbol class %x", SYMBOL_CLASS (symbol));
+ break;
+ }
+ }
+ fprintf (outfile, "\n");
+ return 1;
+}
+
+void
+maintenance_print_psymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ FILE *outfile;
+ struct cleanup *cleanups;
+ char *symname = NULL;
+ char *filename = DEV_TTY;
+ struct objfile *objfile;
+ struct partial_symtab *ps;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-psymbols takes an output file name and optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, outfile);
+
+ immediate_quit++;
+ ALL_PSYMTABS (objfile, ps)
+ if (symname == NULL || (STREQ (symname, ps -> filename)))
+ dump_psymtab (objfile, ps, outfile);
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+static void
+print_partial_symbol (p, count, what, outfile)
+ struct partial_symbol *p;
+ int count;
+ char *what;
+ FILE *outfile;
+{
+
+ fprintf_filtered (outfile, " %s partial symbols:\n", what);
+ while (count-- > 0)
+ {
+ fprintf_filtered (outfile, " `%s'", SYMBOL_NAME(p));
+ if (SYMBOL_DEMANGLED_NAME (p) != NULL)
+ {
+ fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (p));
+ }
+ fputs_filtered (", ", outfile);
+ switch (SYMBOL_NAMESPACE (p))
+ {
+ case UNDEF_NAMESPACE:
+ fputs_filtered ("undefined namespace, ", outfile);
+ break;
+ case VAR_NAMESPACE:
+ /* This is the usual thing -- don't print it */
+ break;
+ case STRUCT_NAMESPACE:
+ fputs_filtered ("struct namespace, ", outfile);
+ break;
+ case LABEL_NAMESPACE:
+ fputs_filtered ("label namespace, ", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid namespace>, ", outfile);
+ break;
+ }
+ switch (SYMBOL_CLASS (p))
+ {
+ case LOC_UNDEF:
+ fputs_filtered ("undefined", outfile);
+ break;
+ case LOC_CONST:
+ fputs_filtered ("constant int", outfile);
+ break;
+ case LOC_STATIC:
+ fputs_filtered ("static", outfile);
+ break;
+ case LOC_REGISTER:
+ fputs_filtered ("register", outfile);
+ break;
+ case LOC_ARG:
+ fputs_filtered ("pass by value", outfile);
+ break;
+ case LOC_REF_ARG:
+ fputs_filtered ("pass by reference", outfile);
+ break;
+ case LOC_REGPARM:
+ fputs_filtered ("register parameter", outfile);
+ break;
+ case LOC_REGPARM_ADDR:
+ fputs_filtered ("register address parameter", outfile);
+ break;
+ case LOC_LOCAL:
+ fputs_filtered ("stack parameter", outfile);
+ break;
+ case LOC_TYPEDEF:
+ fputs_filtered ("type", outfile);
+ break;
+ case LOC_LABEL:
+ fputs_filtered ("label", outfile);
+ break;
+ case LOC_BLOCK:
+ fputs_filtered ("function", outfile);
+ break;
+ case LOC_CONST_BYTES:
+ fputs_filtered ("constant bytes", outfile);
+ break;
+ case LOC_LOCAL_ARG:
+ fputs_filtered ("shuffled arg", outfile);
+ break;
+ case LOC_OPTIMIZED_OUT:
+ fputs_filtered ("optimized out", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid location>", outfile);
+ break;
+ }
+ fputs_filtered (", ", outfile);
+ fprintf_filtered (outfile, "0x%lx\n", SYMBOL_VALUE (p));
+ p++;
+ }
+}
+
+void
+maintenance_print_msymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ FILE *outfile;
+ struct cleanup *cleanups;
+ char *filename = DEV_TTY;
+ char *symname = NULL;
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-msymbols takes an output file name and optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, outfile);
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ if (symname == NULL || (STREQ (symname, objfile -> name)))
+ dump_msymbols (objfile, outfile);
+ immediate_quit--;
+ fprintf_filtered (outfile, "\n\n");
+ do_cleanups (cleanups);
+}
+
+void
+maintenance_print_objfiles (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ dump_objfile (objfile);
+ immediate_quit--;
+}
+
+
+/* Return the nexting depth of a block within other blocks in its symtab. */
+
+static int
+block_depth (block)
+ struct block *block;
+{
+ register int i = 0;
+ while ((block = BLOCK_SUPERBLOCK (block)) != NULL)
+ {
+ i++;
+ }
+ return i;
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+
+/* Increase the space allocated for LISTP, which is probably
+ global_psymbol_list or static_psymbol_list. This space will eventually
+ be freed in free_objfile(). */
+
+void
+extend_psymbol_list (listp, objfile)
+ register struct psymbol_allocation_list *listp;
+ struct objfile *objfile;
+{
+ int new_size;
+ if (listp->size == 0)
+ {
+ new_size = 255;
+ listp->list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, new_size * sizeof (struct partial_symbol));
+ }
+ else
+ {
+ new_size = listp->size * 2;
+ listp->list = (struct partial_symbol *)
+ xmrealloc (objfile -> md, (char *) listp->list,
+ new_size * sizeof (struct partial_symbol));
+ }
+ /* Next assumes we only went one over. Should be good if
+ program works correctly */
+ listp->next = listp->list + listp->size;
+ listp->size = new_size;
+}
+
+
+/* Do early runtime initializations. */
+void
+_initialize_symmisc ()
+{
+ std_in = stdin;
+ std_out = stdout;
+ std_err = stderr;
+}
diff --git a/gnu/usr.bin/gdb/gdb/symtab.c b/gnu/usr.bin/gdb/gdb/symtab.c
new file mode 100644
index 000000000000..0d0255c73175
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.c
@@ -0,0 +1,3035 @@
+/* Symbol table lookup for the GNU debugger, GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+#include "call-cmds.h"
+#include "regex.h"
+#include "expression.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <obstack.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+/* Prototypes for local functions */
+
+extern int
+find_methods PARAMS ((struct type *, char *, struct symbol **));
+
+static void
+completion_list_add_name PARAMS ((char *, char *, int, char *, char *));
+
+static void
+build_canonical_line_spec PARAMS ((struct symtab_and_line *, char *, char ***));
+
+static struct symtabs_and_lines
+decode_line_2 PARAMS ((struct symbol *[], int, int, char ***));
+
+static void
+rbreak_command PARAMS ((char *, int));
+
+static void
+types_info PARAMS ((char *, int));
+
+static void
+functions_info PARAMS ((char *, int));
+
+static void
+variables_info PARAMS ((char *, int));
+
+static void
+sources_info PARAMS ((char *, int));
+
+static void
+list_symbols PARAMS ((char *, int, int));
+
+static void
+output_source_filename PARAMS ((char *, int *));
+
+static char *
+operator_chars PARAMS ((char *, char **));
+
+static int find_line_common PARAMS ((struct linetable *, int, int *));
+
+static struct partial_symbol *
+lookup_partial_symbol PARAMS ((struct partial_symtab *, const char *,
+ int, enum namespace));
+
+static struct symtab *
+lookup_symtab_1 PARAMS ((char *));
+
+/* */
+
+/* The single non-language-specific builtin type */
+struct type *builtin_type_error;
+
+/* Block in which the most recently searched-for symbol was found.
+ Might be better to make this a parameter to lookup_symbol and
+ value_of_this. */
+
+const struct block *block_found;
+
+char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command.";
+
+/* While the C++ support is still in flux, issue a possibly helpful hint on
+ using the new command completion feature on single quoted demangled C++
+ symbols. Remove when loose ends are cleaned up. FIXME -fnf */
+
+void
+cplusplus_hint (name)
+ char *name;
+{
+ printf ("Hint: try '%s<TAB> or '%s<ESC-?>\n", name, name);
+ printf ("(Note leading single quote.)\n");
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work. */
+
+static struct symtab *
+lookup_symtab_1 (name)
+ char *name;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register char *slash;
+ register struct objfile *objfile;
+
+ got_symtab:
+
+ /* First, search for an exact match */
+
+ ALL_SYMTABS (objfile, s)
+ if (STREQ (name, s->filename))
+ return s;
+
+ slash = strchr (name, '/');
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (!slash)
+ ALL_SYMTABS (objfile, s)
+ {
+ char *p = s -> filename;
+ char *tail = strrchr (p, '/');
+
+ if (tail)
+ p = tail + 1;
+
+ if (STREQ (p, name))
+ return s;
+ }
+
+ /* Same search rules as above apply here, but now we look thru the
+ psymtabs. */
+
+ ps = lookup_partial_symtab (name);
+ if (!ps)
+ return (NULL);
+
+ if (ps -> readin)
+ error ("Internal: readin %s pst for `%s' found when no symtab found.",
+ ps -> filename, name);
+
+ s = PSYMTAB_TO_SYMTAB (ps);
+
+ if (s)
+ return s;
+
+ /* At this point, we have located the psymtab for this file, but
+ the conversion to a symtab has failed. This usually happens
+ when we are looking up an include file. In this case,
+ PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
+ been created. So, we need to run through the symtabs again in
+ order to find the file.
+ XXX - This is a crock, and should be fixed inside of the the
+ symbol parsing routines. */
+ goto got_symtab;
+}
+
+/* Lookup the symbol table of a source file named NAME. Try a couple
+ of variations if the first lookup doesn't work. */
+
+struct symtab *
+lookup_symtab (name)
+ char *name;
+{
+ register struct symtab *s;
+ register char *copy;
+
+ s = lookup_symtab_1 (name);
+ if (s) return s;
+
+ /* If name not found as specified, see if adding ".c" helps. */
+ /* Why is this? Is it just a user convenience? (If so, it's pretty
+ questionable in the presence of C++, FORTRAN, etc.). It's not in
+ the GDB manual. */
+
+ copy = (char *) alloca (strlen (name) + 3);
+ strcpy (copy, name);
+ strcat (copy, ".c");
+ s = lookup_symtab_1 (copy);
+ if (s) return s;
+
+ /* We didn't find anything; die. */
+ return 0;
+}
+
+/* Lookup the partial symbol table of a source file named NAME.
+ *If* there is no '/' in the name, a match after a '/'
+ in the psymtab filename will also work. */
+
+struct partial_symtab *
+lookup_partial_symtab (name)
+char *name;
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (STREQ (name, pst -> filename))
+ {
+ return (pst);
+ }
+ }
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (!strchr (name, '/'))
+ ALL_PSYMTABS (objfile, pst)
+ {
+ char *p = pst -> filename;
+ char *tail = strrchr (p, '/');
+
+ if (tail)
+ p = tail + 1;
+
+ if (STREQ (p, name))
+ return (pst);
+ }
+
+ return (NULL);
+}
+
+/* Demangle a GDB method stub type.
+ Note that this function is g++ specific. */
+
+char *
+gdb_mangle_name (type, i, j)
+ struct type *type;
+ int i, j;
+{
+ int mangled_name_len;
+ char *mangled_name;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ struct fn_field *method = &f[j];
+ char *field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+ char *newname = type_name_no_tag (type);
+ int is_constructor;
+ int is_destructor = DESTRUCTOR_PREFIX_P (physname);
+ /* Need a new type prefix. */
+ char *const_prefix = method->is_const ? "C" : "";
+ char *volatile_prefix = method->is_volatile ? "V" : "";
+ char buf[20];
+ int len = (newname == NULL ? 0 : strlen (newname));
+ char *opname;
+
+ is_constructor = newname && STREQ(field_name, newname);
+ if (!is_constructor)
+ is_constructor = (physname[0]=='_' && physname[1]=='_' &&
+ (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t'));
+ if (!is_constructor)
+ is_constructor = (strncmp(physname, "__ct", 4) == 0);
+ if (!is_destructor)
+ is_destructor = (strncmp(physname, "__dt", 4) == 0);
+
+#ifndef GCC_MANGLE_BUG
+ if (is_destructor)
+ {
+ mangled_name = (char*) xmalloc(strlen(physname)+1);
+ strcpy(mangled_name, physname);
+ return mangled_name;
+ }
+
+ if (len == 0)
+ {
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ if (strcmp(buf, "__") == 0)
+ buf[0] = '\0';
+ }
+ else
+ {
+ sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
+ }
+ mangled_name_len = ((is_constructor ? 0 : strlen (field_name))
+ + strlen (buf) + len
+ + strlen (physname)
+ + 1);
+
+ /* Only needed for GNU-mangled names. ANSI-mangled names
+ work with the normal mechanisms. */
+ if (OPNAME_PREFIX_P (field_name))
+ {
+ char *opname = cplus_mangle_opname (field_name + 3, 0);
+ if (opname == NULL)
+ error ("No mangling for \"%s\"", field_name);
+ mangled_name_len += strlen (opname);
+ mangled_name = (char *)xmalloc (mangled_name_len);
+
+ strncpy (mangled_name, field_name, 3);
+ mangled_name[3] = '\0';
+ strcat (mangled_name, opname);
+ }
+ else
+ {
+ mangled_name = (char *)xmalloc (mangled_name_len);
+ if (is_constructor)
+ mangled_name[0] = '\0';
+ else
+ strcpy (mangled_name, field_name);
+ }
+ strcat (mangled_name, buf);
+ /* If the class doesn't have a name, i.e. newname NULL, then we just
+ mangle it using 0 for the length of the class. Thus it gets mangled
+ as something starting with `::' rather than `classname::'. */
+ if (newname != NULL)
+ strcat (mangled_name, newname);
+
+#else
+
+ if (is_constructor)
+ {
+ buf[0] = '\0';
+ }
+ else
+ {
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ }
+
+ mangled_name_len = ((is_constructor ? 0 : strlen (field_name))
+ + strlen (buf) + strlen (physname) + 1);
+
+ /* Only needed for GNU-mangled names. ANSI-mangled names
+ work with the normal mechanisms. */
+ if (OPNAME_PREFIX_P (field_name))
+ {
+ opname = cplus_mangle_opname (field_name + 3, 0);
+ if (opname == NULL)
+ {
+ error ("No mangling for \"%s\"", field_name);
+ }
+ mangled_name_len += strlen (opname);
+ mangled_name = (char *) xmalloc (mangled_name_len);
+
+ strncpy (mangled_name, field_name, 3);
+ strcpy (mangled_name + 3, opname);
+ }
+ else
+ {
+ mangled_name = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ {
+ mangled_name[0] = '\0';
+ }
+ else
+ {
+ strcpy (mangled_name, field_name);
+ }
+ }
+ strcat (mangled_name, buf);
+
+#endif
+ strcat (mangled_name, physname);
+ return (mangled_name);
+}
+
+
+/* Find which partial symtab on contains PC. Return 0 if none. */
+
+struct partial_symtab *
+find_pc_psymtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (pc >= pst->textlow && pc < pst->texthigh)
+ return (pst);
+ }
+ return (NULL);
+}
+
+/* Find which partial symbol within a psymtab contains PC. Return 0
+ if none. Check all psymtabs if PSYMTAB is 0. */
+struct partial_symbol *
+find_pc_psymbol (psymtab, pc)
+ struct partial_symtab *psymtab;
+ CORE_ADDR pc;
+{
+ struct partial_symbol *best = NULL, *p;
+ CORE_ADDR best_pc;
+
+ if (!psymtab)
+ psymtab = find_pc_psymtab (pc);
+ if (!psymtab)
+ return 0;
+
+ best_pc = psymtab->textlow - 1;
+
+ for (p = psymtab->objfile->static_psymbols.list + psymtab->statics_offset;
+ (p - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset)
+ < psymtab->n_static_syms);
+ p++)
+ if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE_ADDRESS (p)
+ && SYMBOL_VALUE_ADDRESS (p) > best_pc)
+ {
+ best_pc = SYMBOL_VALUE_ADDRESS (p);
+ best = p;
+ }
+ if (best_pc == psymtab->textlow - 1)
+ return 0;
+ return best;
+}
+
+
+/* Find the definition for a specified symbol name NAME
+ in namespace NAMESPACE, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ If SYMTAB is non-NULL, store the symbol table in which the
+ symbol was found there, or NULL if not found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+struct symbol *
+lookup_symbol (name, block, namespace, is_a_field_of_this, symtab)
+ const char *name;
+ register const struct block *block;
+ const enum namespace namespace;
+ int *is_a_field_of_this;
+ struct symtab **symtab;
+{
+ register struct symbol *sym;
+ register struct symtab *s = NULL;
+ register struct partial_symtab *ps;
+ struct blockvector *bv;
+ register struct objfile *objfile;
+ register struct block *b;
+ register struct minimal_symbol *msymbol;
+
+ /* Search specified block and its superiors. */
+
+ while (block != 0)
+ {
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ {
+ /* Search the list of symtabs for one which contains the
+ address of the start of this block. */
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+ goto found;
+ }
+found:
+ *symtab = s;
+ }
+
+ return (sym);
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* FIXME: this code is never executed--block is always NULL at this
+ point. What is it trying to do, anyway? We already should have
+ checked the STATIC_BLOCK above (it is the superblock of top-level
+ blocks). Why is VAR_NAMESPACE special-cased? */
+ /* Don't need to mess with the psymtabs; if we have a block,
+ that file is read in. If we don't, then we deal later with
+ all the psymtab stuff that needs checking. */
+ if (namespace == VAR_NAMESPACE && block != NULL)
+ {
+ struct block *b;
+ /* Find the right symtab. */
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+ {
+ sym = lookup_block_symbol (b, name, VAR_NAMESPACE);
+ if (sym)
+ {
+ block_found = b;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+ }
+
+
+ /* C++: If requested to do so by the caller,
+ check to see if NAME is a field of `this'. */
+ if (is_a_field_of_this)
+ {
+ struct value *v = value_of_this (0);
+
+ *is_a_field_of_this = 0;
+ if (v && check_field (v, name))
+ {
+ *is_a_field_of_this = 1;
+ if (symtab != NULL)
+ *symtab = NULL;
+ return 0;
+ }
+ }
+
+ /* Now search all global blocks. Do the symtab's first, then
+ check the psymtab's */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Check for the possibility of the symbol being a global function
+ that is stored in one of the minimal symbol tables. Eventually, all
+ global symbols might be resolved in this way. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol));
+ /* If S is NULL, there are no debug symbols for this file.
+ Skip this stuff and check for matching static symbols below. */
+ if (s != NULL)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol),
+ namespace);
+ /* We kept static functions in minimal symbol table as well as
+ in static scope. We want to find them in the symbol table. */
+ if (!sym) {
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol),
+ namespace);
+ }
+
+ /* sym == 0 if symbol was found in the minimal symbol table
+ but not in the symtab.
+ Return 0 to use the msymbol definition of "foo_".
+
+ This happens for Fortran "foo_" symbols,
+ which are "foo" in the symtab.
+
+ This can also happen if "asm" is used to make a
+ regular symbol but not a debugging symbol, e.g.
+ asm(".globl _main");
+ asm("_main:");
+ */
+
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ error ("Internal: global symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Now search all per-file blocks.
+ Not strictly correct, but more useful than an error.
+ Do the symtabs first, then check the psymtabs */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ error ("Internal: static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Now search all per-file blocks for static mangled symbols.
+ Do the symtabs first, then check the psymtabs. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, VAR_NAMESPACE);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 0, VAR_NAMESPACE))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, VAR_NAMESPACE);
+ if (!sym)
+ error ("Internal: mangled static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+
+ if (symtab != NULL)
+ *symtab = NULL;
+ return 0;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME. Check the global
+ symbols if GLOBAL, the static symbols if not */
+
+static struct partial_symbol *
+lookup_partial_symbol (pst, name, global, namespace)
+ struct partial_symtab *pst;
+ const char *name;
+ int global;
+ enum namespace namespace;
+{
+ struct partial_symbol *start, *psym;
+ struct partial_symbol *top, *bottom, *center;
+ int length = (global ? pst->n_global_syms : pst->n_static_syms);
+ int do_linear_search = 1;
+
+ if (length == 0)
+ {
+ return (NULL);
+ }
+
+ start = (global ?
+ pst->objfile->global_psymbols.list + pst->globals_offset :
+ pst->objfile->static_psymbols.list + pst->statics_offset );
+
+ if (global) /* This means we can use a binary search. */
+ {
+ do_linear_search = 0;
+
+ /* Binary search. This search is guaranteed to end with center
+ pointing at the earliest partial symbol with the correct
+ name. At that point *all* partial symbols with that name
+ will be checked against the correct namespace. */
+
+ bottom = start;
+ top = start + length - 1;
+ while (top > bottom)
+ {
+ center = bottom + (top - bottom) / 2;
+ assert (center < top);
+ if (!do_linear_search && SYMBOL_LANGUAGE (center) == language_cplus)
+ {
+ do_linear_search = 1;
+ }
+ if (STRCMP (SYMBOL_NAME (center), name) >= 0)
+ {
+ top = center;
+ }
+ else
+ {
+ bottom = center + 1;
+ }
+ }
+ assert (top == bottom);
+ while (STREQ (SYMBOL_NAME (top), name))
+ {
+ if (SYMBOL_NAMESPACE (top) == namespace)
+ {
+ return top;
+ }
+ top ++;
+ }
+ }
+
+ /* Can't use a binary search or else we found during the binary search that
+ we should also do a linear search. */
+
+ if (do_linear_search)
+ {
+ for (psym = start; psym < start + length; psym++)
+ {
+ if (namespace == SYMBOL_NAMESPACE (psym))
+ {
+ if (SYMBOL_MATCHES_NAME (psym, name))
+ {
+ return (psym);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* Find the psymtab containing main(). */
+/* FIXME: What about languages without main() or specially linked
+ executables that have no main() ? */
+
+struct partial_symtab *
+find_main_psymtab ()
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (lookup_partial_symbol (pst, "main", 1, VAR_NAMESPACE))
+ {
+ return (pst);
+ }
+ }
+ return (NULL);
+}
+
+/* Search BLOCK for symbol NAME in NAMESPACE.
+
+ Note that if NAME is the demangled form of a C++ symbol, we will fail
+ to find a match during the binary search of the non-encoded names, but
+ for now we don't worry about the slight inefficiency of looking for
+ a match we'll never find, since it will go pretty quick. Once the
+ binary search terminates, we drop through and do a straight linear
+ search on the symbols. Each symbol which is marked as being a C++
+ symbol (language_cplus set) has both the encoded and non-encoded names
+ tested for a match. */
+
+struct symbol *
+lookup_block_symbol (block, name, namespace)
+ register const struct block *block;
+ const char *name;
+ const enum namespace namespace;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+ register struct symbol *sym_found = NULL;
+ register int do_linear_search = 1;
+
+ /* If the blocks's symbols were sorted, start with a binary search. */
+
+ if (BLOCK_SHOULD_SORT (block))
+ {
+ /* Reset the linear search flag so if the binary search fails, we
+ won't do the linear search once unless we find some reason to
+ do so, such as finding a C++ symbol during the binary search.
+ Note that for C++ modules, ALL the symbols in a block should
+ end up marked as C++ symbols. */
+
+ do_linear_search = 0;
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+
+ /* Advance BOT to not far before the first symbol whose name is NAME. */
+
+ while (1)
+ {
+ inc = (top - bot + 1);
+ /* No need to keep binary searching for the last few bits worth. */
+ if (inc < 4)
+ {
+ break;
+ }
+ inc = (inc >> 1) + bot;
+ sym = BLOCK_SYM (block, inc);
+ if (!do_linear_search && SYMBOL_LANGUAGE (sym) == language_cplus)
+ {
+ do_linear_search = 1;
+ }
+ if (SYMBOL_NAME (sym)[0] < name[0])
+ {
+ bot = inc;
+ }
+ else if (SYMBOL_NAME (sym)[0] > name[0])
+ {
+ top = inc;
+ }
+ else if (STRCMP (SYMBOL_NAME (sym), name) < 0)
+ {
+ bot = inc;
+ }
+ else
+ {
+ top = inc;
+ }
+ }
+
+ /* Now scan forward until we run out of symbols, find one whose
+ name is greater than NAME, or find one we want. If there is
+ more than one symbol with the right name and namespace, we
+ return the first one; I believe it is now impossible for us
+ to encounter two symbols with the same name and namespace
+ here, because blocks containing argument symbols are no
+ longer sorted. */
+
+ top = BLOCK_NSYMS (block);
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ inc = SYMBOL_NAME (sym)[0] - name[0];
+ if (inc == 0)
+ {
+ inc = STRCMP (SYMBOL_NAME (sym), name);
+ }
+ if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
+ {
+ return (sym);
+ }
+ if (inc > 0)
+ {
+ break;
+ }
+ bot++;
+ }
+ }
+
+ /* Here if block isn't sorted, or we fail to find a match during the
+ binary search above. If during the binary search above, we find a
+ symbol which is a C++ symbol, then we have re-enabled the linear
+ search flag which was reset when starting the binary search.
+
+ This loop is equivalent to the loop above, but hacked greatly for speed.
+
+ Note that parameter symbols do not always show up last in the
+ list; this loop makes sure to take anything else other than
+ parameter symbols first; it only uses parameter symbols as a
+ last resort. Note that this only takes up extra computation
+ time on a match. */
+
+ if (do_linear_search)
+ {
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAMESPACE (sym) == namespace &&
+ SYMBOL_MATCHES_NAME (sym, name))
+ {
+ sym_found = sym;
+ if (SYMBOL_CLASS (sym) != LOC_ARG &&
+ SYMBOL_CLASS (sym) != LOC_LOCAL_ARG &&
+ SYMBOL_CLASS (sym) != LOC_REF_ARG &&
+ SYMBOL_CLASS (sym) != LOC_REGPARM &&
+ SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR &&
+ SYMBOL_CLASS (sym) != LOC_BASEREG_ARG)
+ {
+ break;
+ }
+ }
+ bot++;
+ }
+ }
+ return (sym_found); /* Will be NULL if not found. */
+}
+
+
+/* Return the symbol for the function which contains a specified
+ lexical block, described by a struct block BL. */
+
+struct symbol *
+block_function (bl)
+ struct block *bl;
+{
+ while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
+/* Find the symtab associated with PC. Look through the psymtabs and read in
+ another symtab if necessary. */
+
+struct symtab *
+find_pc_symtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ struct blockvector *bv;
+ register struct symtab *s = NULL;
+ register struct symtab *best_s = NULL;
+ register struct partial_symtab *ps;
+ register struct objfile *objfile;
+ int distance = 0;
+
+ /* Search all symtabs for the one whose file contains our address, and which
+ is the smallest of all the ones containing the address. This is designed
+ to deal with a case like symtab a is at 0x1000-0x2000 and 0x3000-0x4000
+ and symtab b is at 0x2000-0x3000. So the GLOBAL_BLOCK for a is from
+ 0x1000-0x4000, but for address 0x2345 we want to return symtab b.
+ This is said to happen for the mips; it might be swifter to create
+ several symtabs with the same name like xcoff does (I'm not sure). */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc
+ && (distance == 0
+ || BLOCK_END (b) - BLOCK_START (b) < distance))
+ {
+ distance = BLOCK_END (b) - BLOCK_START (b);
+ best_s = s;
+ }
+ }
+
+ if (best_s != NULL)
+ return(best_s);
+
+ s = NULL;
+ ps = find_pc_psymtab (pc);
+ if (ps)
+ {
+ if (ps->readin)
+ /* Might want to error() here (in case symtab is corrupt and
+ will cause a core dump), but maybe we can successfully
+ continue, so let's not. */
+ warning ("\
+(Internal error: pc 0x%lx in read in psymtab, but not in symtab.)\n",
+ (unsigned long) pc);
+ s = PSYMTAB_TO_SYMTAB (ps);
+ }
+ return (s);
+}
+
+/* Find the source file and line number for a given PC value.
+ Return a structure containing a symtab pointer, a line number,
+ and a pc range for the entire source line.
+ The value's .pc field is NOT the specified pc.
+ NOTCURRENT nonzero means, if specified pc is on a line boundary,
+ use the line that ends there. Otherwise, in that case, the line
+ that begins there is used. */
+
+/* The big complication here is that a line may start in one file, and end just
+ before the start of another file. This usually occurs when you #include
+ code in the middle of a subroutine. To properly find the end of a line's PC
+ range, we must search all symtabs associated with this compilation unit, and
+ find the one whose first PC is closer than that of the next line in this
+ symtab. */
+
+/* If it's worth the effort, we could be using a binary search. */
+
+struct symtab_and_line
+find_pc_line (pc, notcurrent)
+ CORE_ADDR pc;
+ int notcurrent;
+{
+ struct symtab *s;
+ register struct linetable *l;
+ register int len;
+ register int i;
+ register struct linetable_entry *item;
+ struct symtab_and_line val;
+ struct blockvector *bv;
+
+ /* Info on best line seen so far, and where it starts, and its file. */
+
+ struct linetable_entry *best = NULL;
+ CORE_ADDR best_end = 0;
+ struct symtab *best_symtab = 0;
+
+ /* Store here the first line number
+ of a file which contains the line at the smallest pc after PC.
+ If we don't find a line whose range contains PC,
+ we will use a line one less than this,
+ with a range from the start of that file to the first line's pc. */
+ struct linetable_entry *alt = NULL;
+ struct symtab *alt_symtab = 0;
+
+ /* Info on best line seen in this file. */
+
+ struct linetable_entry *prev;
+
+ /* If this pc is not from the current frame,
+ it is the address of the end of a call instruction.
+ Quite likely that is the start of the following statement.
+ But what we want is the statement containing the instruction.
+ Fudge the pc to make sure we get that. */
+
+ if (notcurrent) pc -= 1;
+
+ s = find_pc_symtab (pc);
+ if (!s)
+ {
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = pc;
+ val.end = 0;
+ return val;
+ }
+
+ bv = BLOCKVECTOR (s);
+
+ /* Look at all the symtabs that share this blockvector.
+ They all have the same apriori range, that we found was right;
+ but they have different line tables. */
+
+ for (; s && BLOCKVECTOR (s) == bv; s = s->next)
+ {
+ /* Find the best line in this symtab. */
+ l = LINETABLE (s);
+ if (!l)
+ continue;
+ len = l->nitems;
+ if (len <= 0)
+ {
+ /* I think len can be zero if the symtab lacks line numbers
+ (e.g. gcc -g1). (Either that or the LINETABLE is NULL;
+ I'm not sure which, and maybe it depends on the symbol
+ reader). */
+ continue;
+ }
+
+ prev = NULL;
+ item = l->item; /* Get first line info */
+
+ /* Is this file's first line closer than the first lines of other files?
+ If so, record this file, and its first line, as best alternate. */
+ if (item->pc > pc && (!alt || item->pc < alt->pc))
+ {
+ alt = item;
+ alt_symtab = s;
+ }
+
+ for (i = 0; i < len; i++, item++)
+ {
+ /* Return the last line that did not start after PC. */
+ if (item->pc > pc)
+ break;
+
+ prev = item;
+ }
+
+ /* At this point, prev points at the line whose start addr is <= pc, and
+ item points at the next line. If we ran off the end of the linetable
+ (pc >= start of the last line), then prev == item. If pc < start of
+ the first line, prev will not be set. */
+
+ /* Is this file's best line closer than the best in the other files?
+ If so, record this file, and its best line, as best so far. */
+
+ if (prev && (!best || prev->pc > best->pc))
+ {
+ best = prev;
+ best_symtab = s;
+ /* If another line is in the linetable, and its PC is closer
+ than the best_end we currently have, take it as best_end. */
+ if (i < len && (best_end == 0 || best_end > item->pc))
+ best_end = item->pc;
+ }
+ }
+
+ if (!best_symtab)
+ {
+ if (!alt_symtab)
+ { /* If we didn't find any line # info, just
+ return zeros. */
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = pc;
+ val.end = 0;
+ }
+ else
+ {
+ val.symtab = alt_symtab;
+ val.line = alt->line - 1;
+ val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ val.end = alt->pc;
+ }
+ }
+ else
+ {
+ val.symtab = best_symtab;
+ val.line = best->line;
+ val.pc = best->pc;
+ if (best_end && (!alt || best_end < alt->pc))
+ val.end = best_end;
+ else if (alt)
+ val.end = alt->pc;
+ else
+ val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ }
+ return val;
+}
+
+static int find_line_symtab PARAMS ((struct symtab *, int, struct linetable **,
+ int *, int *));
+
+/* Find line number LINE in any symtab whose name is the same as
+ SYMTAB.
+
+ If found, return 1, set *LINETABLE to the linetable in which it was
+ found, set *INDEX to the index in the linetable of the best entry
+ found, and set *EXACT_MATCH nonzero if the value returned is an
+ exact match.
+
+ If not found, return 0. */
+
+static int
+find_line_symtab (symtab, line, linetable, index, exact_match)
+ struct symtab *symtab;
+ int line;
+ struct linetable **linetable;
+ int *index;
+ int *exact_match;
+{
+ int exact;
+
+ /* BEST_INDEX and BEST_LINETABLE identify the smallest linenumber > LINE
+ so far seen. */
+
+ int best_index;
+ struct linetable *best_linetable;
+
+ /* First try looking it up in the given symtab. */
+ best_linetable = LINETABLE (symtab);
+ best_index = find_line_common (best_linetable, line, &exact);
+ if (best_index < 0 || !exact)
+ {
+ /* Didn't find an exact match. So we better keep looking for
+ another symtab with the same name. In the case of xcoff,
+ multiple csects for one source file (produced by IBM's FORTRAN
+ compiler) produce multiple symtabs (this is unavoidable
+ assuming csects can be at arbitrary places in memory and that
+ the GLOBAL_BLOCK of a symtab has a begin and end address). */
+
+ /* BEST is the smallest linenumber > LINE so far seen,
+ or 0 if none has been seen so far.
+ BEST_INDEX and BEST_LINETABLE identify the item for it. */
+ int best;
+
+ struct objfile *objfile;
+ struct symtab *s;
+
+ if (best_index >= 0)
+ best = best_linetable->item[best_index].line;
+ else
+ best = 0;
+
+ ALL_SYMTABS (objfile, s)
+ {
+ struct linetable *l;
+ int ind;
+
+ if (!STREQ (symtab->filename, s->filename))
+ continue;
+ l = LINETABLE (s);
+ ind = find_line_common (l, line, &exact);
+ if (ind >= 0)
+ {
+ if (exact)
+ {
+ best_index = ind;
+ best_linetable = l;
+ goto done;
+ }
+ if (best == 0 || l->item[ind].line < best)
+ {
+ best = l->item[ind].line;
+ best_index = ind;
+ best_linetable = l;
+ }
+ }
+ }
+ }
+ done:
+ if (best_index < 0)
+ return 0;
+
+ if (index)
+ *index = best_index;
+ if (linetable)
+ *linetable = best_linetable;
+ if (exact_match)
+ *exact_match = exact;
+ return 1;
+}
+
+/* Find the PC value for a given source file and line number.
+ Returns zero for invalid line number.
+ The source file is specified with a struct symtab. */
+
+CORE_ADDR
+find_line_pc (symtab, line)
+ struct symtab *symtab;
+ int line;
+{
+ struct linetable *l;
+ int ind;
+
+ if (symtab == 0)
+ return 0;
+ if (find_line_symtab (symtab, line, &l, &ind, NULL))
+ return l->item[ind].pc;
+ else
+ return 0;
+}
+
+/* Find the range of pc values in a line.
+ Store the starting pc of the line into *STARTPTR
+ and the ending pc (start of next line) into *ENDPTR.
+ Returns 1 to indicate success.
+ Returns 0 if could not find the specified line. */
+
+int
+find_line_pc_range (symtab, thisline, startptr, endptr)
+ struct symtab *symtab;
+ int thisline;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct linetable *l;
+ int ind;
+ int exact_match; /* did we get an exact linenumber match */
+
+ if (symtab == 0)
+ return 0;
+
+ if (find_line_symtab (symtab, thisline, &l, &ind, &exact_match))
+ {
+ *startptr = l->item[ind].pc;
+ /* If we have not seen an entry for the specified line,
+ assume that means the specified line has zero bytes. */
+ if (!exact_match || ind == l->nitems-1)
+ *endptr = *startptr;
+ else
+ /* Perhaps the following entry is for the following line.
+ It's worth a try. */
+ if (ind+1 < l->nitems
+ && l->item[ind+1].line == thisline + 1)
+ *endptr = l->item[ind+1].pc;
+ else
+ *endptr = find_line_pc (symtab, thisline+1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Given a line table and a line number, return the index into the line
+ table for the pc of the nearest line whose number is >= the specified one.
+ Return -1 if none is found. The value is >= 0 if it is an index.
+
+ Set *EXACT_MATCH nonzero if the value returned is an exact match. */
+
+static int
+find_line_common (l, lineno, exact_match)
+ register struct linetable *l;
+ register int lineno;
+ int *exact_match;
+{
+ register int i;
+ register int len;
+
+ /* BEST is the smallest linenumber > LINENO so far seen,
+ or 0 if none has been seen so far.
+ BEST_INDEX identifies the item for it. */
+
+ int best_index = -1;
+ int best = 0;
+
+ if (lineno <= 0)
+ return -1;
+ if (l == 0)
+ return -1;
+
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ register struct linetable_entry *item = &(l->item[i]);
+
+ if (item->line == lineno)
+ {
+ /* Return the first (lowest address) entry which matches. */
+ *exact_match = 1;
+ return i;
+ }
+
+ if (item->line > lineno && (best == 0 || item->line < best))
+ {
+ best = item->line;
+ best_index = i;
+ }
+ }
+
+ /* If we got here, we didn't get an exact match. */
+
+ *exact_match = 0;
+ return best_index;
+}
+
+int
+find_pc_line_pc_range (pc, startptr, endptr)
+ CORE_ADDR pc;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct symtab_and_line sal;
+ sal = find_pc_line (pc, 0);
+ *startptr = sal.pc;
+ *endptr = sal.end;
+ return sal.symtab != 0;
+}
+
+/* If P is of the form "operator[ \t]+..." where `...' is
+ some legitimate operator text, return a pointer to the
+ beginning of the substring of the operator text.
+ Otherwise, return "". */
+static char *
+operator_chars (p, end)
+ char *p;
+ char **end;
+{
+ *end = "";
+ if (strncmp (p, "operator", 8))
+ return *end;
+ p += 8;
+
+ /* Don't get faked out by `operator' being part of a longer
+ identifier. */
+ if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0')
+ return *end;
+
+ /* Allow some whitespace between `operator' and the operator symbol. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* Recognize 'operator TYPENAME'. */
+
+ if (isalpha(*p) || *p == '_' || *p == '$')
+ {
+ register char *q = p+1;
+ while (isalnum(*q) || *q == '_' || *q == '$')
+ q++;
+ *end = q;
+ return p;
+ }
+
+ switch (*p)
+ {
+ case '!':
+ case '=':
+ case '*':
+ case '/':
+ case '%':
+ case '^':
+ if (p[1] == '=')
+ *end = p+2;
+ else
+ *end = p+1;
+ return p;
+ case '<':
+ case '>':
+ case '+':
+ case '-':
+ case '&':
+ case '|':
+ if (p[1] == '=' || p[1] == p[0])
+ *end = p+2;
+ else
+ *end = p+1;
+ return p;
+ case '~':
+ case ',':
+ *end = p+1;
+ return p;
+ case '(':
+ if (p[1] != ')')
+ error ("`operator ()' must be specified without whitespace in `()'");
+ *end = p+2;
+ return p;
+ case '?':
+ if (p[1] != ':')
+ error ("`operator ?:' must be specified without whitespace in `?:'");
+ *end = p+2;
+ return p;
+ case '[':
+ if (p[1] != ']')
+ error ("`operator []' must be specified without whitespace in `[]'");
+ *end = p+2;
+ return p;
+ default:
+ error ("`operator %s' not supported", p);
+ break;
+ }
+ *end = "";
+ return *end;
+}
+
+/* Recursive helper function for decode_line_1.
+ * Look for methods named NAME in type T.
+ * Return number of matches.
+ * Put matches in SYM_ARR (which better be big enough!).
+ * These allocations seem to define "big enough":
+ * sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+ * Note that this function is g++ specific.
+ */
+
+int
+find_methods (t, name, sym_arr)
+ struct type *t;
+ char *name;
+ struct symbol **sym_arr;
+{
+ int i1 = 0;
+ int ibase;
+ struct symbol *sym_class;
+ char *class_name = type_name_no_tag (t);
+ /* Ignore this class if it doesn't have a name. This is ugly, but
+ unless we figure out how to get the physname without the name of
+ the class, then the loop can't do any good. */
+ if (class_name
+ && (sym_class = lookup_symbol (class_name,
+ (struct block *)NULL,
+ STRUCT_NAMESPACE,
+ (int *)NULL,
+ (struct symtab **)NULL)))
+ {
+ int method_counter;
+ /* FIXME: Shouldn't this just be check_stub_type (t)? */
+ t = SYMBOL_TYPE (sym_class);
+ for (method_counter = TYPE_NFN_FIELDS (t) - 1;
+ method_counter >= 0;
+ --method_counter)
+ {
+ int field_counter;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter);
+
+ char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
+ if (STREQ (name, method_name))
+ /* Find all the fields with that name. */
+ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ char *phys_name;
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ check_stub_method (t, method_counter, field_counter);
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ /* Destructor is handled by caller, dont add it to the list */
+ if (DESTRUCTOR_PREFIX_P (phys_name))
+ continue;
+
+ /* FIXME: Why are we looking this up in the
+ SYMBOL_BLOCK_VALUE (sym_class)? It is intended as a hook
+ for nested types? If so, it should probably hook to the
+ type, not the symbol. mipsread.c is the only symbol
+ reader which sets the SYMBOL_BLOCK_VALUE for types, and
+ this is not documented in symtab.h. -26Aug93. */
+
+ sym_arr[i1] = lookup_symbol (phys_name,
+ SYMBOL_BLOCK_VALUE (sym_class),
+ VAR_NAMESPACE,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1]) i1++;
+ else
+ {
+ fputs_filtered("(Cannot find method ", stdout);
+ fprintf_symbol_filtered (stdout, phys_name,
+ language_cplus, DMGL_PARAMS);
+ fputs_filtered(" - possibly inlined.)\n", stdout);
+ }
+ }
+ }
+ }
+
+ /* Only search baseclasses if there is no match yet, since names in
+ derived classes override those in baseclasses.
+
+ FIXME: The above is not true; it is only true of member functions
+ if they have the same number of arguments (??? - section 13.1 of the
+ ARM says the function members are not in the same scope but doesn't
+ really spell out the rules in a way I understand. In any case, if
+ the number of arguments differ this is a case in which we can overload
+ rather than hiding without any problem, and gcc 2.4.5 does overload
+ rather than hiding in this case). */
+
+ if (i1)
+ return i1;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ i1 += find_methods(TYPE_BASECLASS(t, ibase), name,
+ sym_arr + i1);
+ return i1;
+}
+
+/* Helper function for decode_line_1.
+ Build a canonical line spec in CANONICAL if it is non-NULL and if
+ the SAL has a symtab.
+ If SYMNAME is non-NULL the canonical line spec is `filename:symname'.
+ If SYMNAME is NULL the line number from SAL is used and the canonical
+ line spec is `filename:linenum'. */
+
+static void
+build_canonical_line_spec (sal, symname, canonical)
+ struct symtab_and_line *sal;
+ char *symname;
+ char ***canonical;
+{
+ char **canonical_arr;
+ char *canonical_name;
+ char *filename;
+ struct symtab *s = sal->symtab;
+
+ if (s == (struct symtab *)NULL
+ || s->filename == (char *)NULL
+ || canonical == (char ***)NULL)
+ return;
+
+ canonical_arr = (char **) xmalloc (sizeof (char *));
+ *canonical = canonical_arr;
+
+ filename = s->filename;
+ if (symname != NULL)
+ {
+ canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
+ sprintf (canonical_name, "%s:%s", filename, symname);
+ }
+ else
+ {
+ canonical_name = xmalloc (strlen (filename) + 30);
+ sprintf (canonical_name, "%s:%d", filename, sal->line);
+ }
+ canonical_arr[0] = canonical_name;
+}
+
+/* Parse a string that specifies a line number.
+ Pass the address of a char * variable; that variable will be
+ advanced over the characters actually parsed.
+
+ The string can be:
+
+ LINENUM -- that line number in current file. PC returned is 0.
+ FILE:LINENUM -- that line in that file. PC returned is 0.
+ FUNCTION -- line number of openbrace of that function.
+ PC returned is the start of the function.
+ VARIABLE -- line number of definition of that variable.
+ PC returned is 0.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in minimal symbol table.
+
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside a function when a function is specified.
+
+ DEFAULT_SYMTAB specifies the file to use if none is specified.
+ It defaults to current_source_symtab.
+ DEFAULT_LINE specifies the line number to use for relative
+ line numbers (that start with signs). Defaults to current_source_line.
+ If CANONICAL is non-NULL, store an array of strings containing the canonical
+ line specs there if necessary. Currently overloaded member functions and
+ line numbers or static functions without a filename yield a canonical
+ line spec. The array and the line spec strings are allocated on the heap,
+ it is the callers responsibility to free them.
+
+ Note that it is possible to return zero for the symtab
+ if no file is validly specified. Callers must check that.
+ Also, the line number returned may be invalid. */
+
+struct symtabs_and_lines
+decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical)
+ char **argptr;
+ int funfirstline;
+ struct symtab *default_symtab;
+ int default_line;
+ char ***canonical;
+{
+ struct symtabs_and_lines values;
+#ifdef HPPA_COMPILER_BUG
+ /* FIXME: The native HP 9000/700 compiler has a bug which appears
+ when optimizing this file with target i960-vxworks. I haven't
+ been able to construct a simple test case. The problem is that
+ in the second call to SKIP_PROLOGUE below, the compiler somehow
+ does not realize that the statement val = find_pc_line (...) will
+ change the values of the fields of val. It extracts the elements
+ into registers at the top of the block, and does not update the
+ registers after the call to find_pc_line. You can check this by
+ inserting a printf at the end of find_pc_line to show what values
+ it is returning for val.pc and val.end and another printf after
+ the call to see what values the function actually got (remember,
+ this is compiling with cc -O, with this patch removed). You can
+ also examine the assembly listing: search for the second call to
+ skip_prologue; the LDO statement before the next call to
+ find_pc_line loads the address of the structure which
+ find_pc_line will return; if there is a LDW just before the LDO,
+ which fetches an element of the structure, then the compiler
+ still has the bug.
+
+ Setting val to volatile avoids the problem. We must undef
+ volatile, because the HPPA native compiler does not define
+ __STDC__, although it does understand volatile, and so volatile
+ will have been defined away in defs.h. */
+#undef volatile
+ volatile struct symtab_and_line val;
+#define volatile /*nothing*/
+#else
+ struct symtab_and_line val;
+#endif
+ register char *p, *p1;
+ char *q, *q1;
+ register struct symtab *s;
+
+ register struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+
+ register CORE_ADDR pc;
+ register struct minimal_symbol *msymbol;
+ char *copy;
+ struct symbol *sym_class;
+ int i1;
+ int is_quoted;
+ struct symbol **sym_arr;
+ struct type *t;
+ char *saved_arg = *argptr;
+ extern char *gdb_completer_quote_characters;
+
+ /* Defaults have defaults. */
+
+ if (default_symtab == 0)
+ {
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ /* See if arg is *PC */
+
+ if (**argptr == '*')
+ {
+ if (**argptr == '*')
+ {
+ (*argptr)++;
+ }
+ pc = parse_and_eval_address_1 (argptr);
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = pc;
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+ s = NULL;
+ is_quoted = (strchr (gdb_completer_quote_characters, **argptr) != NULL);
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if ((p[0] == ':') && !is_quoted)
+ {
+
+ /* C++ */
+ if (p[1] ==':')
+ {
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Discard the class name from the arg. */
+ p = p1 + 2;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0,
+ (struct symtab **)NULL);
+
+ if (sym_class &&
+ ( TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION))
+ {
+ /* Arg token is not digits => try it as a function name
+ Find the next token (everything up to end or next whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++;
+ q = operator_chars (*argptr, &q1);
+
+ if (q1 - q)
+ {
+ char *opname;
+ char *tmp = alloca (q1 - q + 1);
+ memcpy (tmp, q, q1 - q);
+ tmp[q1 - q] = '\0';
+ opname = cplus_mangle_opname (tmp, DMGL_ANSI);
+ if (opname == NULL)
+ {
+ warning ("no mangling for \"%s\"", tmp);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ copy = (char*) alloca (3 + strlen(opname));
+ sprintf (copy, "__%s", opname);
+ p = q1;
+ }
+ else
+ {
+ copy = (char *) alloca (p - *argptr + 1 + (q1 - q));
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ }
+
+ /* no line number may be specified */
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym = 0;
+ i1 = 0; /* counter for the symbol array */
+ t = SYMBOL_TYPE (sym_class);
+ sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+
+ /* Cfront objects don't have fieldlists. */
+ if (destructor_name_p (copy, t) && TYPE_FN_FIELDLISTS (t) != NULL)
+ {
+ /* destructors are a special case. */
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
+ int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
+ /* gcc 1.x puts destructor in last field,
+ gcc 2.x puts destructor in first field. */
+ char *phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
+ if (!DESTRUCTOR_PREFIX_P (phys_name))
+ {
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, 0);
+ if (!DESTRUCTOR_PREFIX_P (phys_name))
+ phys_name = "";
+ }
+ sym_arr[i1] =
+ lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class),
+ VAR_NAMESPACE, 0, (struct symtab **)NULL);
+ if (sym_arr[i1]) i1++;
+ }
+ else
+ i1 = find_methods (t, copy, sym_arr);
+ if (i1 == 1)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
+ }
+ else
+ {
+ values.nelts = 0;
+ }
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* There is more than one field with that name
+ (overloaded). Ask the user which one to use. */
+ return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ }
+ else
+ {
+ char *tmp;
+
+ if (OPNAME_PREFIX_P (copy))
+ {
+ tmp = (char *)alloca (strlen (copy+3) + 9);
+ strcpy (tmp, "operator ");
+ strcat (tmp, copy+3);
+ }
+ else
+ tmp = copy;
+ if (tmp[0] == '~')
+ warning ("the class `%s' does not have destructor defined",
+ SYMBOL_SOURCE_NAME(sym_class));
+ else
+ warning ("the class %s does not have any method named %s",
+ SYMBOL_SOURCE_NAME(sym_class), tmp);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
+ else
+ {
+ /* The quotes are important if copy is empty. */
+ warning ("can't find class, struct, or union named \"%s\"",
+ copy);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
+ /* end of C++ */
+
+
+ /* Extract the file name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ s = lookup_symtab (copy);
+ if (s == 0)
+ {
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error (no_symtab_msg);
+ error ("No source file named %s.", copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ }
+
+ /* S is specified file's symtab, or 0 if no file specified.
+ arg no longer contains the file name. */
+
+ /* Check whether arg is all digits (and sign) */
+
+ p = *argptr;
+ if (*p == '-' || *p == '+') p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+ {
+ /* We found a token consisting of all digits -- at least one digit. */
+ enum sign {none, plus, minus} sign = none;
+
+ /* We might need a canonical line spec if no file was specified. */
+ int need_canonical = (s == 0) ? 1 : 0;
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarantee that this section of code is never executed
+ when we are called with just a function name, since
+ select_source_symtab calls us with such an argument */
+
+ if (s == 0 && default_symtab == 0)
+ {
+ select_source_symtab (0);
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ val.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (p == *argptr)
+ val.line = 5;
+ if (s == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (p == *argptr)
+ val.line = 15;
+ if (s == 0)
+ val.line = default_line - val.line;
+ else
+ val.line = 1;
+ break;
+ case none:
+ break; /* No need to adjust val.line. */
+ }
+
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ if (s == 0)
+ s = default_symtab;
+ val.symtab = s;
+ val.pc = 0;
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+ }
+
+ /* Arg token is not digits => try it as a variable name
+ Find the next token (everything up to end or next whitespace). */
+
+ p = skip_quoted (*argptr);
+ if (is_quoted && p[-1] != '\'')
+ error ("Unmatched single quote.");
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if ((copy[0] == copy [p - *argptr - 1])
+ && strchr (gdb_completer_quote_characters, copy[0]) != NULL)
+ {
+ copy [p - *argptr - 1] = '\0';
+ copy++;
+ }
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ /* Look up that token as a variable.
+ If file specified, use that file's per-file block to start with. */
+
+ sym = lookup_symbol (copy,
+ (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
+ : get_selected_block ()),
+ VAR_NAMESPACE, 0, &sym_symtab);
+
+ if (sym != NULL)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ val = find_pc_line (pc, 0);
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* Convex: no need to suppress code on first line, if any */
+ val.pc = pc;
+#else
+ /* Check if SKIP_PROLOGUE left us in mid-line, and the next
+ line is still part of the same function. */
+ if (val.pc != pc
+ && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= val.end
+ && val.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym)))
+ {
+ /* First pc of next line */
+ pc = val.end;
+ /* Recalculate the line number (might not be N+1). */
+ val = find_pc_line (pc, 0);
+ }
+ val.pc = pc;
+#endif
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+
+ /* I think this is always the same as the line that
+ we calculate above, but the general principle is
+ "trust the symbols more than stuff like
+ SKIP_PROLOGUE". */
+ if (SYMBOL_LINE (sym) != 0)
+ values.sals[0].line = SYMBOL_LINE (sym);
+
+ /* We might need a canonical line spec if it is a static function. */
+ if (s == 0)
+ {
+ struct blockvector *bv = BLOCKVECTOR (sym_symtab);
+ struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL)
+ build_canonical_line_spec (values.sals, copy, canonical);
+ }
+ return values;
+ }
+ else if (SYMBOL_LINE (sym) != 0)
+ {
+ /* We know its line number. */
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ memset (&values.sals[0], 0, sizeof (values.sals[0]));
+ values.sals[0].symtab = sym_symtab;
+ values.sals[0].line = SYMBOL_LINE (sym);
+ return values;
+ }
+ else
+ /* This can happen if it is compiled with a compiler which doesn't
+ put out line numbers for variables. */
+ /* FIXME: Shouldn't we just set .line and .symtab to zero and
+ return? For example, "info line foo" could print the address. */
+ error ("Line number not known for symbol \"%s\"", copy);
+ }
+
+ msymbol = lookup_minimal_symbol (copy, (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = SYMBOL_VALUE_ADDRESS (msymbol) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (val.pc);
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ return values;
+ }
+
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error (no_symtab_msg);
+
+ error ("Function \"%s\" not defined.", copy);
+ return values; /* for lint */
+}
+
+struct symtabs_and_lines
+decode_line_spec (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtabs_and_lines sals;
+ if (string == 0)
+ error ("Empty line specification.");
+ sals = decode_line_1 (&string, funfirstline,
+ current_source_symtab, current_source_line,
+ (char ***)NULL);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to
+ operate on (ask user if necessary).
+ If CANONICAL is non-NULL return a corresponding array of mangled names
+ as canonical line specs there. */
+
+static struct symtabs_and_lines
+decode_line_2 (sym_arr, nelts, funfirstline, canonical)
+ struct symbol *sym_arr[];
+ int nelts;
+ int funfirstline;
+ char ***canonical;
+{
+ struct symtabs_and_lines values, return_values;
+ register CORE_ADDR pc;
+ char *args, *arg1;
+ int i;
+ char *prompt;
+ char *symname;
+ struct cleanup *old_chain;
+ char **canonical_arr = (char **)NULL;
+
+ values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
+ return_values.sals = (struct symtab_and_line *) xmalloc (nelts * sizeof(struct symtab_and_line));
+ old_chain = make_cleanup (free, return_values.sals);
+
+ if (canonical)
+ {
+ canonical_arr = (char **) xmalloc (nelts * sizeof (char *));
+ make_cleanup (free, canonical_arr);
+ memset (canonical_arr, 0, nelts * sizeof (char *));
+ *canonical = canonical_arr;
+ }
+
+ i = 0;
+ printf("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i]))
+ + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals[i] = find_pc_line (pc, 0);
+ values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ?
+ values.sals[i].end : pc;
+ printf("[%d] %s at %s:%d\n", (i+2), SYMBOL_SOURCE_NAME (sym_arr[i]),
+ values.sals[i].symtab->filename, values.sals[i].line);
+ }
+ else printf ("?HERE\n");
+ i++;
+ }
+
+ if ((prompt = getenv ("PS2")) == NULL)
+ {
+ prompt = ">";
+ }
+ printf("%s ",prompt);
+ fflush(stdout);
+
+ args = command_line_input ((char *) NULL, 0);
+
+ if (args == 0 || *args == 0)
+ error_no_arg ("one or more choice numbers");
+
+ i = 0;
+ while (*args)
+ {
+ int num;
+
+ arg1 = args;
+ while (*arg1 >= '0' && *arg1 <= '9') arg1++;
+ if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
+ error ("Arguments must be choice numbers.");
+
+ num = atoi (args);
+
+ if (num == 0)
+ error ("cancelled");
+ else if (num == 1)
+ {
+ if (canonical_arr)
+ {
+ for (i = 0; i < nelts; i++)
+ {
+ if (canonical_arr[i] == NULL)
+ {
+ symname = SYMBOL_NAME (sym_arr[i]);
+ canonical_arr[i] = savestring (symname, strlen (symname));
+ }
+ }
+ }
+ memcpy (return_values.sals, values.sals,
+ (nelts * sizeof(struct symtab_and_line)));
+ return_values.nelts = nelts;
+ discard_cleanups (old_chain);
+ return return_values;
+ }
+
+ if (num > nelts + 2)
+ {
+ printf ("No choice number %d.\n", num);
+ }
+ else
+ {
+ num -= 2;
+ if (values.sals[num].pc)
+ {
+ if (canonical_arr)
+ {
+ symname = SYMBOL_NAME (sym_arr[num]);
+ make_cleanup (free, symname);
+ canonical_arr[i] = savestring (symname, strlen (symname));
+ }
+ return_values.sals[i++] = values.sals[num];
+ values.sals[num].pc = 0;
+ }
+ else
+ {
+ printf ("duplicate request for %d ignored.\n", num);
+ }
+ }
+
+ args = arg1;
+ while (*args == ' ' || *args == '\t') args++;
+ }
+ return_values.nelts = i;
+ discard_cleanups (old_chain);
+ return return_values;
+}
+
+
+/* Slave routine for sources_info. Force line breaks at ,'s.
+ NAME is the name to print and *FIRST is nonzero if this is the first
+ name printed. Set *FIRST to zero. */
+static void
+output_source_filename (name, first)
+ char *name;
+ int *first;
+{
+ /* Table of files printed so far. Since a single source file can
+ result in several partial symbol tables, we need to avoid printing
+ it more than once. Note: if some of the psymtabs are read in and
+ some are not, it gets printed both under "Source files for which
+ symbols have been read" and "Source files for which symbols will
+ be read in on demand". I consider this a reasonable way to deal
+ with the situation. I'm not sure whether this can also happen for
+ symtabs; it doesn't hurt to check. */
+ static char **tab = NULL;
+ /* Allocated size of tab in elements.
+ Start with one 256-byte block (when using GNU malloc.c).
+ 24 is the malloc overhead when range checking is in effect. */
+ static int tab_alloc_size = (256 - 24) / sizeof (char *);
+ /* Current size of tab in elements. */
+ static int tab_cur_size;
+
+ char **p;
+
+ if (*first)
+ {
+ if (tab == NULL)
+ tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab));
+ tab_cur_size = 0;
+ }
+
+ /* Is NAME in tab? */
+ for (p = tab; p < tab + tab_cur_size; p++)
+ if (STREQ (*p, name))
+ /* Yes; don't print it again. */
+ return;
+ /* No; add it to tab. */
+ if (tab_cur_size == tab_alloc_size)
+ {
+ tab_alloc_size *= 2;
+ tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab));
+ }
+ tab[tab_cur_size++] = name;
+
+ if (*first)
+ {
+ *first = 0;
+ }
+ else
+ {
+ printf_filtered (", ");
+ }
+
+ wrap_here ("");
+ fputs_filtered (name, stdout);
+}
+
+static void
+sources_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct objfile *objfile;
+ int first;
+
+ if (!have_full_symbols () && !have_partial_symbols ())
+ {
+ error (no_symtab_msg);
+ }
+
+ printf_filtered ("Source files for which symbols have been read in:\n\n");
+
+ first = 1;
+ ALL_SYMTABS (objfile, s)
+ {
+ output_source_filename (s -> filename, &first);
+ }
+ printf_filtered ("\n\n");
+
+ printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
+
+ first = 1;
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin)
+ {
+ output_source_filename (ps -> filename, &first);
+ }
+ }
+ printf_filtered ("\n");
+}
+
+/* List all symbols (if REGEXP is NULL) or all symbols matching REGEXP.
+ If CLASS is zero, list all symbols except functions, type names, and
+ constants (enums).
+ If CLASS is 1, list only functions.
+ If CLASS is 2, list only type names.
+ If CLASS is 3, list only method names.
+
+ BPT is non-zero if we should set a breakpoint at the functions
+ we find. */
+
+static void
+list_symbols (regexp, class, bpt)
+ char *regexp;
+ int class;
+ int bpt;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b;
+ register int i, j;
+ register struct symbol *sym;
+ struct partial_symbol *psym;
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ char *val;
+ static char *classnames[]
+ = {"variable", "function", "type", "method"};
+ int found_in_file = 0;
+ int found_misc = 0;
+ static enum minimal_symbol_type types[]
+ = {mst_data, mst_text, mst_abs, mst_unknown};
+ static enum minimal_symbol_type types2[]
+ = {mst_bss, mst_text, mst_abs, mst_unknown};
+ enum minimal_symbol_type ourtype = types[class];
+ enum minimal_symbol_type ourtype2 = types2[class];
+
+ if (regexp != NULL)
+ {
+ /* Make sure spacing is right for C++ operators.
+ This is just a courtesy to make the matching less sensitive
+ to how many spaces the user leaves between 'operator'
+ and <TYPENAME> or <OPERATOR>. */
+ char *opend;
+ char *opname = operator_chars (regexp, &opend);
+ if (*opname)
+ {
+ int fix = -1; /* -1 means ok; otherwise number of spaces needed. */
+ if (isalpha(*opname) || *opname == '_' || *opname == '$')
+ {
+ /* There should 1 space between 'operator' and 'TYPENAME'. */
+ if (opname[-1] != ' ' || opname[-2] == ' ')
+ fix = 1;
+ }
+ else
+ {
+ /* There should 0 spaces between 'operator' and 'OPERATOR'. */
+ if (opname[-1] == ' ')
+ fix = 0;
+ }
+ /* If wrong number of spaces, fix it. */
+ if (fix >= 0)
+ {
+ char *tmp = (char*) alloca(opend-opname+10);
+ sprintf(tmp, "operator%.*s%s", fix, " ", opname);
+ regexp = tmp;
+ }
+ }
+
+ if (0 != (val = re_comp (regexp)))
+ error ("Invalid regexp (%s): %s", val, regexp);
+ }
+
+ /* Search through the partial symtabs *first* for all symbols
+ matching the regexp. That way we don't have to reproduce all of
+ the machinery below. */
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ struct partial_symbol *bound, *gbound, *sbound;
+ int keep_going = 1;
+
+ if (ps->readin) continue;
+
+ gbound = objfile->global_psymbols.list + ps->globals_offset + ps->n_global_syms;
+ sbound = objfile->static_psymbols.list + ps->statics_offset + ps->n_static_syms;
+ bound = gbound;
+
+ /* Go through all of the symbols stored in a partial
+ symtab in one loop. */
+ psym = objfile->global_psymbols.list + ps->globals_offset;
+ while (keep_going)
+ {
+ if (psym >= bound)
+ {
+ if (bound == gbound && ps->n_static_syms != 0)
+ {
+ psym = objfile->static_psymbols.list + ps->statics_offset;
+ bound = sbound;
+ }
+ else
+ keep_going = 0;
+ continue;
+ }
+ else
+ {
+ QUIT;
+
+ /* If it would match (logic taken from loop below)
+ load the file and go on to the next one */
+ if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (psym))
+ && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (psym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK)))
+ {
+ PSYMTAB_TO_SYMTAB(ps);
+ keep_going = 0;
+ }
+ }
+ psym++;
+ }
+ }
+
+ /* Here, we search through the minimal symbol tables for functions that
+ match, and call find_pc_symtab on them to force their symbols to
+ be read. The symbol will then be found during the scan of symtabs
+ below. If find_pc_symtab fails, set found_misc so that we will
+ rescan to print any matching symbols without debug info. */
+
+ if (class == 1)
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2)
+ {
+ if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol))
+ {
+ if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))
+ {
+ found_misc = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* Printout here so as to get after the "Reading in symbols"
+ messages which will be generated above. */
+ if (!bpt)
+ printf_filtered (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[class],
+ regexp);
+
+ ALL_SYMTABS (objfile, s)
+ {
+ found_in_file = 0;
+ bv = BLOCKVECTOR (s);
+ /* Often many files share a blockvector.
+ Scan each blockvector only once so that
+ we don't get every symbol many times.
+ It happens that the first symtab in the list
+ for any given blockvector is the main file. */
+ if (bv != prev_bv)
+ for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ /* Skip the sort if this block is always sorted. */
+ if (!BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ for (j = 0; j < BLOCK_NSYMS (b); j++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, j);
+ if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym))
+ && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ && SYMBOL_CLASS (sym) != LOC_CONST)
+ || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
+ {
+ if (bpt)
+ {
+ /* Set a breakpoint here, if it's a function */
+ if (class == 1)
+ {
+ /* There may be more than one function with the
+ same name but in different files. In order to
+ set breakpoints on all of them, we must give
+ both the file name and the function name to
+ break_command. */
+ char *string =
+ (char *) alloca (strlen (s->filename)
+ + strlen (SYMBOL_NAME(sym))
+ + 2);
+ strcpy (string, s->filename);
+ strcat (string, ":");
+ strcat (string, SYMBOL_NAME(sym));
+ break_command (string, 0);
+ }
+ }
+ else if (!found_in_file)
+ {
+ fputs_filtered ("\nFile ", stdout);
+ fputs_filtered (s->filename, stdout);
+ fputs_filtered (":\n", stdout);
+ }
+ found_in_file = 1;
+
+ if (class != 2 && i == STATIC_BLOCK)
+ printf_filtered ("static ");
+
+ /* Typedef that is not a C++ class */
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+ c_typedef_print (SYMBOL_TYPE(sym), sym, stdout);
+ /* variable, func, or typedef-that-is-c++-class */
+ else if (class < 2 ||
+ (class == 2 &&
+ SYMBOL_NAMESPACE(sym) == STRUCT_NAMESPACE))
+ {
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_SOURCE_NAME (sym)),
+ stdout, 0);
+
+ printf_filtered (";\n");
+ }
+ else
+ {
+# if 0 /* FIXME, why is this zapped out? */
+ char buf[1024];
+ c_type_print_base (TYPE_FN_FIELD_TYPE(t, i),
+ stdout, 0, 0);
+ c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i),
+ stdout, 0);
+ sprintf (buf, " %s::", type_name_no_tag (t));
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (t, i),
+ buf, name, stdout);
+# endif
+ }
+ }
+ }
+ }
+ prev_bv = bv;
+ }
+
+ /* If there are no eyes, avoid all contact. I mean, if there are
+ no debug symbols, then print directly from the msymbol_vector. */
+
+ if (found_misc || class != 1)
+ {
+ found_in_file = 0;
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2)
+ {
+ if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol))
+ {
+ /* Functions: Look up by address. */
+ if (class != 1 ||
+ (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ /* Variables/Absolutes: Look up by name */
+ if (lookup_symbol (SYMBOL_NAME (msymbol),
+ (struct block *) NULL, VAR_NAMESPACE,
+ 0, (struct symtab **) NULL) == NULL)
+ {
+ if (!found_in_file)
+ {
+ printf_filtered ("\nNon-debugging symbols:\n");
+ found_in_file = 1;
+ }
+ printf_filtered (" %08lx %s\n",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (msymbol),
+ SYMBOL_SOURCE_NAME (msymbol));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+variables_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 0, 0);
+}
+
+static void
+functions_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 1, 0);
+}
+
+static void
+types_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 2, 0);
+}
+
+#if 0
+/* Tiemann says: "info methods was never implemented." */
+static void
+methods_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 3, 0);
+}
+#endif /* 0 */
+
+/* Breakpoint all functions matching regular expression. */
+static void
+rbreak_command (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 1, 1);
+}
+
+
+/* Return Nonzero if block a is lexically nested within block b,
+ or if a and b have the same pc range.
+ Return zero otherwise. */
+int
+contained_in (a, b)
+ struct block *a, *b;
+{
+ if (!a || !b)
+ return 0;
+ return BLOCK_START (a) >= BLOCK_START (b)
+ && BLOCK_END (a) <= BLOCK_END (b);
+}
+
+
+/* Helper routine for make_symbol_completion_list. */
+
+static int return_val_size;
+static int return_val_index;
+static char **return_val;
+
+#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
+ do { \
+ if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) \
+ /* Put only the mangled name on the list. */ \
+ /* Advantage: "b foo<TAB>" completes to "b foo(int, int)" */ \
+ /* Disadvantage: "b foo__i<TAB>" doesn't complete. */ \
+ completion_list_add_name \
+ (SYMBOL_DEMANGLED_NAME (symbol), (sym_text), (len), (text), (word)); \
+ else \
+ completion_list_add_name \
+ (SYMBOL_NAME (symbol), (sym_text), (len), (text), (word)); \
+ } while (0)
+
+/* Test to see if the symbol specified by SYMNAME (which is already
+ demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
+ characters. If so, add it to the current completion list. */
+
+static void
+completion_list_add_name (symname, sym_text, sym_text_len, text, word)
+ char *symname;
+ char *sym_text;
+ int sym_text_len;
+ char *text;
+ char *word;
+{
+ int newsize;
+ int i;
+
+ /* clip symbols that cannot match */
+
+ if (strncmp (symname, sym_text, sym_text_len) != 0)
+ {
+ return;
+ }
+
+ /* Clip any symbol names that we've already considered. (This is a
+ time optimization) */
+
+ for (i = 0; i < return_val_index; ++i)
+ {
+ if (STREQ (symname, return_val[i]))
+ {
+ return;
+ }
+ }
+
+ /* We have a match for a completion, so add SYMNAME to the current list
+ of matches. Note that the name is moved to freshly malloc'd space. */
+
+ {
+ char *new;
+ if (word == sym_text)
+ {
+ new = xmalloc (strlen (symname) + 5);
+ strcpy (new, symname);
+ }
+ else if (word > sym_text)
+ {
+ /* Return some portion of symname. */
+ new = xmalloc (strlen (symname) + 5);
+ strcpy (new, symname + (word - sym_text));
+ }
+ else
+ {
+ /* Return some of SYM_TEXT plus symname. */
+ new = xmalloc (strlen (symname) + (sym_text - word) + 5);
+ strncpy (new, word, sym_text - word);
+ new[sym_text - word] = '\0';
+ strcat (new, symname);
+ }
+
+ if (return_val_index + 3 > return_val_size)
+ {
+ newsize = (return_val_size *= 2) * sizeof (char *);
+ return_val = (char **) xrealloc ((char *) return_val, newsize);
+ }
+ return_val[return_val_index++] = new;
+ return_val[return_val_index] = NULL;
+ }
+}
+
+/* Return a NULL terminated array of all symbols (regardless of class) which
+ begin by matching TEXT. If the answer is no symbols, then the return value
+ is an array which contains only a NULL pointer.
+
+ Problem: All of the symbols have to be copied because readline frees them.
+ I'm not going to worry about this; hopefully there won't be that many. */
+
+char **
+make_symbol_completion_list (text, word)
+ char *text;
+ char *word;
+{
+ register struct symbol *sym;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct minimal_symbol *msymbol;
+ register struct objfile *objfile;
+ register struct block *b, *surrounding_static_block = 0;
+ register int i, j;
+ struct partial_symbol *psym;
+ /* The symbol we are completing on. Points in same buffer as text. */
+ char *sym_text;
+ /* Length of sym_text. */
+ int sym_text_len;
+
+ /* Now look for the symbol we are supposed to complete on.
+ FIXME: This should be language-specific. */
+ {
+ char *p;
+ char quote_found;
+ char *quote_pos = NULL;
+
+ /* First see if this is a quoted string. */
+ quote_found = '\0';
+ for (p = text; *p != '\0'; ++p)
+ {
+ if (quote_found != '\0')
+ {
+ if (*p == quote_found)
+ /* Found close quote. */
+ quote_found = '\0';
+ else if (*p == '\\' && p[1] == quote_found)
+ /* A backslash followed by the quote character
+ doesn't end the string. */
+ ++p;
+ }
+ else if (*p == '\'' || *p == '"')
+ {
+ quote_found = *p;
+ quote_pos = p;
+ }
+ }
+ if (quote_found == '\'')
+ /* A string within single quotes can be a symbol, so complete on it. */
+ sym_text = quote_pos + 1;
+ else if (quote_found == '"')
+ /* A double-quoted string is never a symbol, nor does it make sense
+ to complete it any other way. */
+ return NULL;
+ else
+ {
+ /* It is not a quoted string. Break it based on the characters
+ which are in symbols. */
+ while (p > text)
+ {
+ if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
+ --p;
+ else
+ break;
+ }
+ sym_text = p;
+ }
+ }
+
+ sym_text_len = strlen (sym_text);
+
+ return_val_size = 100;
+ return_val_index = 0;
+ return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *));
+ return_val[0] = NULL;
+
+ /* Look through the partial symtabs for all symbols which begin
+ by matching SYM_TEXT. Add each one that you find to the list. */
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ /* If the psymtab's been read in we'll get it when we search
+ through the blockvector. */
+ if (ps->readin) continue;
+
+ for (psym = objfile->global_psymbols.list + ps->globals_offset;
+ psym < (objfile->global_psymbols.list + ps->globals_offset
+ + ps->n_global_syms);
+ psym++)
+ {
+ /* If interrupted, then quit. */
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word);
+ }
+
+ for (psym = objfile->static_psymbols.list + ps->statics_offset;
+ psym < (objfile->static_psymbols.list + ps->statics_offset
+ + ps->n_static_syms);
+ psym++)
+ {
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ /* At this point scan through the misc symbol vectors and add each
+ symbol you find to the list. Eventually we want to ignore
+ anything that isn't a text symbol (everything else will be
+ handled by the psymtab code above). */
+
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word);
+ }
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+
+ for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b))
+ {
+ if (!BLOCK_SUPERBLOCK (b))
+ {
+ surrounding_static_block = b; /* For elmin of dups */
+ }
+
+ /* Also catch fields of types defined in this places which match our
+ text string. Only complete on types visible from current context. */
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ struct type *t = SYMBOL_TYPE (sym);
+ enum type_code c = TYPE_CODE (t);
+
+ if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
+ {
+ for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
+ {
+ if (TYPE_FIELD_NAME (t, j))
+ {
+ completion_list_add_name (TYPE_FIELD_NAME (t, j),
+ sym_text, sym_text_len, text, word);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Go through the symtabs and check the externs and statics for
+ symbols which match. */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block) continue;
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ return (return_val);
+}
+
+
+#if 0
+/* Add the type of the symbol sym to the type of the current
+ function whose block we are in (assumed). The type of
+ this current function is contained in *TYPE.
+
+ This basically works as follows: When we find a function
+ symbol (N_FUNC with a 'f' or 'F' in the symbol name), we record
+ a pointer to its type in the global in_function_type. Every
+ time we come across a parameter symbol ('p' in its name), then
+ this procedure adds the name and type of that parameter
+ to the function type pointed to by *TYPE. (Which should correspond
+ to in_function_type if it was called correctly).
+
+ Note that since we are modifying a type, the result of
+ lookup_function_type() should be memcpy()ed before calling
+ this. When not in strict typing mode, the expression
+ evaluator can choose to ignore this.
+
+ Assumption: All of a function's parameter symbols will
+ appear before another function symbol is found. The parameters
+ appear in the same order in the argument list as they do in the
+ symbol table. */
+
+void
+add_param_to_type (type,sym)
+ struct type **type;
+ struct symbol *sym;
+{
+ int num = ++(TYPE_NFIELDS(*type));
+
+ if(TYPE_NFIELDS(*type)-1)
+ TYPE_FIELDS(*type) = (struct field *)
+ (*current_objfile->xrealloc) ((char *)(TYPE_FIELDS(*type)),
+ num*sizeof(struct field));
+ else
+ TYPE_FIELDS(*type) = (struct field *)
+ (*current_objfile->xmalloc) (num*sizeof(struct field));
+
+ TYPE_FIELD_BITPOS(*type,num-1) = num-1;
+ TYPE_FIELD_BITSIZE(*type,num-1) = 0;
+ TYPE_FIELD_TYPE(*type,num-1) = SYMBOL_TYPE(sym);
+ TYPE_FIELD_NAME(*type,num-1) = SYMBOL_NAME(sym);
+}
+#endif
+
+void
+_initialize_symtab ()
+{
+ add_info ("variables", variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ add_info ("functions", functions_info,
+ "All function names, or those matching REGEXP.");
+
+ /* FIXME: This command has at least the following problems:
+ 1. It prints builtin types (in a very strange and confusing fashion).
+ 2. It doesn't print right, e.g. with
+ typedef struct foo *FOO
+ type_print prints "FOO" when we want to make it (in this situation)
+ print "struct foo *".
+ I also think "ptype" or "whatis" is more likely to be useful (but if
+ there is much disagreement "info types" can be fixed). */
+ add_info ("types", types_info,
+ "All type names, or those matching REGEXP.");
+
+#if 0
+ add_info ("methods", methods_info,
+ "All method names, or those matching REGEXP::REGEXP.\n\
+If the class qualifier is omitted, it is assumed to be the current scope.\n\
+If the first REGEXP is omitted, then all methods matching the second REGEXP\n\
+are listed.");
+#endif
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ add_com ("rbreak", no_class, rbreak_command,
+ "Set a breakpoint for all functions matching REGEXP.");
+
+ /* Initialize the one built-in type that isn't language dependent... */
+ builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0,
+ "<unknown type>", (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/symtab.h b/gnu/usr.bin/gdb/gdb/symtab.h
new file mode 100644
index 000000000000..9570b393adbf
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.h
@@ -0,0 +1,1124 @@
+/* Symbol table definitions for GDB.
+ Copyright (C) 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (SYMTAB_H)
+#define SYMTAB_H 1
+
+/* Some definitions and declarations to go with use of obstacks. */
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* Define a structure for the information that is common to all symbol types,
+ including minimal symbols, partial symbols, and full symbols. In a
+ multilanguage environment, some language specific information may need to
+ be recorded along with each symbol. */
+
+struct general_symbol_info
+{
+ /* Name of the symbol. This is a required field. Storage for the name is
+ allocated on the psymbol_obstack or symbol_obstack for the associated
+ objfile. */
+
+ char *name;
+
+ /* Value of the symbol. Which member of this union to use, and what
+ it means, depends on what kind of symbol this is and its
+ SYMBOL_CLASS. See comments there for more details. All of these
+ are in host byte order (though what they point to might be in
+ target byte order, e.g. LOC_CONST_BYTES). */
+
+ union
+ {
+ long value;
+
+ struct block *block;
+
+ char *bytes;
+
+ CORE_ADDR address;
+
+ /* for opaque typedef struct chain */
+
+ struct symbol *chain;
+ }
+ value;
+
+ /* Record the source code language that applies to this symbol.
+ This is used to select one of the fields from the language specific
+ union below. */
+
+ enum language language;
+
+ /* Since one and only one language can apply, wrap the language specific
+ information inside a union. */
+
+ union
+ {
+ struct cplus_specific /* For C++ */
+ {
+ char *demangled_name;
+ } cplus_specific;
+ struct chill_specific /* For Chill */
+ {
+ char *demangled_name;
+ } chill_specific;
+ } language_specific;
+
+ /* Which section is this symbol in? This is an index into
+ section_offsets for this objfile. Negative means that the symbol
+ does not get relocated relative to a section.
+ Disclaimer: currently this is just used for xcoff, so don't
+ expect all symbol-reading code to set it correctly (the ELF code
+ also tries to set it correctly). */
+
+ int section;
+};
+
+#define SYMBOL_NAME(symbol) (symbol)->ginfo.name
+#define SYMBOL_VALUE(symbol) (symbol)->ginfo.value.value
+#define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->ginfo.value.address
+#define SYMBOL_VALUE_BYTES(symbol) (symbol)->ginfo.value.bytes
+#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->ginfo.value.block
+#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain
+#define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language
+#define SYMBOL_SECTION(symbol) (symbol)->ginfo.section
+
+#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \
+ (symbol)->ginfo.language_specific.cplus_specific.demangled_name
+
+
+extern int demangle; /* We reference it, so go ahead and declare it. */
+
+/* Macro that initializes the language dependent portion of a symbol
+ depending upon the language for the symbol. */
+
+#define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \
+ do { \
+ SYMBOL_LANGUAGE (symbol) = language; \
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus) \
+ { \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ else if (SYMBOL_LANGUAGE (symbol) == language_chill) \
+ { \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ else \
+ { \
+ memset (&(symbol)->ginfo.language_specific, 0, \
+ sizeof ((symbol)->ginfo.language_specific)); \
+ } \
+ } while (0)
+
+/* Macro that attempts to initialize the demangled name for a symbol,
+ based on the language of that symbol. If the language is set to
+ language_auto, it will attempt to find any demangling algorithm
+ that works and then set the language appropriately. If no demangling
+ of any kind is found, the language is set back to language_unknown,
+ so we can avoid doing this work again the next time we encounter
+ the symbol. Any required space to store the name is obtained from the
+ specified obstack. */
+
+#define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack) \
+ do { \
+ char *demangled = NULL; \
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus \
+ || SYMBOL_LANGUAGE (symbol) == language_auto) \
+ { \
+ demangled = \
+ cplus_demangle (SYMBOL_NAME (symbol), DMGL_PARAMS | DMGL_ANSI);\
+ if (demangled != NULL) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_cplus; \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = \
+ obsavestring (demangled, strlen (demangled), (obstack)); \
+ free (demangled); \
+ } \
+ else \
+ { \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ } \
+ if (demangled == NULL \
+ && (SYMBOL_LANGUAGE (symbol) == language_chill \
+ || SYMBOL_LANGUAGE (symbol) == language_auto)) \
+ { \
+ demangled = \
+ chill_demangle (SYMBOL_NAME (symbol)); \
+ if (demangled != NULL) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_chill; \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = \
+ obsavestring (demangled, strlen (demangled), (obstack)); \
+ free (demangled); \
+ } \
+ else \
+ { \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ } \
+ if (SYMBOL_LANGUAGE (symbol) == language_auto) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_unknown; \
+ } \
+ } while (0)
+
+/* Macro that returns the demangled name for a symbol based on the language
+ for that symbol. If no demangled name exists, returns NULL. */
+
+#define SYMBOL_DEMANGLED_NAME(symbol) \
+ (SYMBOL_LANGUAGE (symbol) == language_cplus \
+ ? SYMBOL_CPLUS_DEMANGLED_NAME (symbol) \
+ : (SYMBOL_LANGUAGE (symbol) == language_chill \
+ ? SYMBOL_CHILL_DEMANGLED_NAME (symbol) \
+ : NULL))
+
+#define SYMBOL_CHILL_DEMANGLED_NAME(symbol) \
+ (symbol)->ginfo.language_specific.chill_specific.demangled_name
+
+/* Macro that returns the "natural source name" of a symbol. In C++ this is
+ the "demangled" form of the name if demangle is on and the "mangled" form
+ of the name if demangle is off. In other languages this is just the
+ symbol name. The result should never be NULL. */
+
+#define SYMBOL_SOURCE_NAME(symbol) \
+ (demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ ? SYMBOL_DEMANGLED_NAME (symbol) \
+ : SYMBOL_NAME (symbol))
+
+/* Macro that returns the "natural assembly name" of a symbol. In C++ this is
+ the "mangled" form of the name if demangle is off, or if demangle is on and
+ asm_demangle is off. Otherwise if asm_demangle is on it is the "demangled"
+ form. In other languages this is just the symbol name. The result should
+ never be NULL. */
+
+#define SYMBOL_LINKAGE_NAME(symbol) \
+ (demangle && asm_demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ ? SYMBOL_DEMANGLED_NAME (symbol) \
+ : SYMBOL_NAME (symbol))
+
+/* From utils.c. */
+extern int demangle;
+extern int asm_demangle;
+
+/* Macro that tests a symbol for a match against a specified name string.
+ First test the unencoded name, then looks for and test a C++ encoded
+ name if it exists. Note that whitespace is ignored while attempting to
+ match a C++ encoded name, so that "foo::bar(int,long)" is the same as
+ "foo :: bar (int, long)".
+ Evaluates to zero if the match fails, or nonzero if it succeeds. */
+
+#define SYMBOL_MATCHES_NAME(symbol, name) \
+ (STREQ (SYMBOL_NAME (symbol), (name)) \
+ || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ && strcmp_iw (SYMBOL_DEMANGLED_NAME (symbol), (name)) == 0))
+
+/* Macro that tests a symbol for an re-match against the last compiled regular
+ expression. First test the unencoded name, then look for and test a C++
+ encoded name if it exists.
+ Evaluates to zero if the match fails, or nonzero if it succeeds. */
+
+#define SYMBOL_MATCHES_REGEXP(symbol) \
+ (re_exec (SYMBOL_NAME (symbol)) != 0 \
+ || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ && re_exec (SYMBOL_DEMANGLED_NAME (symbol)) != 0))
+
+/* Define a simple structure used to hold some very basic information about
+ all defined global symbols (text, data, bss, abs, etc). The only required
+ information is the general_symbol_info.
+
+ In many cases, even if a file was compiled with no special options for
+ debugging at all, as long as was not stripped it will contain sufficient
+ information to build a useful minimal symbol table using this structure.
+ Even when a file contains enough debugging information to build a full
+ symbol table, these minimal symbols are still useful for quickly mapping
+ between names and addresses, and vice versa. They are also sometimes
+ used to figure out what full symbol table entries need to be read in. */
+
+struct minimal_symbol
+{
+
+ /* The general symbol info required for all types of symbols.
+
+ The SYMBOL_VALUE_ADDRESS contains the address that this symbol
+ corresponds to. */
+
+ struct general_symbol_info ginfo;
+
+ /* The info field is available for caching machine-specific information that
+ The AMD 29000 tdep.c uses it to remember things it has decoded from the
+ instructions in the function header, so it doesn't have to rederive the
+ info constantly (over a serial line). It is initialized to zero and
+ stays that way until target-dependent code sets it. Storage for any data
+ pointed to by this field should be allocated on the symbol_obstack for
+ the associated objfile. The type would be "void *" except for reasons
+ of compatibility with older compilers. This field is optional. */
+
+ char *info;
+
+ /* Classification types for this symbol. These should be taken as "advisory
+ only", since if gdb can't easily figure out a classification it simply
+ selects mst_unknown. It may also have to guess when it can't figure out
+ which is a better match between two types (mst_data versus mst_bss) for
+ example. Since the minimal symbol info is sometimes derived from the
+ BFD library's view of a file, we need to live with what information bfd
+ supplies. */
+
+ enum minimal_symbol_type
+ {
+ mst_unknown = 0, /* Unknown type, the default */
+ mst_text, /* Generally executable instructions */
+ mst_data, /* Generally initialized data */
+ mst_bss, /* Generally uninitialized data */
+ mst_abs, /* Generally absolute (nonrelocatable) */
+ /* For the mst_file* types, the names are only guaranteed to be unique
+ within a given .o file. */
+ mst_file_text, /* Static version of mst_text */
+ mst_file_data, /* Static version of mst_data */
+ mst_file_bss /* Static version of mst_bss */
+ } type;
+
+};
+
+#define MSYMBOL_INFO(msymbol) (msymbol)->info
+#define MSYMBOL_TYPE(msymbol) (msymbol)->type
+
+
+/* All of the name-scope contours of the program
+ are represented by `struct block' objects.
+ All of these objects are pointed to by the blockvector.
+
+ Each block represents one name scope.
+ Each lexical context has its own block.
+
+ The blockvector begins with some special blocks.
+ The GLOBAL_BLOCK contains all the symbols defined in this compilation
+ whose scope is the entire program linked together.
+ The STATIC_BLOCK contains all the symbols whose scope is the
+ entire compilation excluding other separate compilations.
+ Blocks starting with the FIRST_LOCAL_BLOCK are not special.
+
+ Each block records a range of core addresses for the code that
+ is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK
+ give, for the range of code, the entire range of code produced
+ by the compilation that the symbol segment belongs to.
+
+ The blocks appear in the blockvector
+ in order of increasing starting-address,
+ and, within that, in order of decreasing ending-address.
+
+ This implies that within the body of one function
+ the blocks appear in the order of a depth-first tree walk. */
+
+struct blockvector
+{
+ /* Number of blocks in the list. */
+ int nblocks;
+ /* The blocks themselves. */
+ struct block *block[1];
+};
+
+#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
+
+/* Special block numbers */
+
+#define GLOBAL_BLOCK 0
+#define STATIC_BLOCK 1
+#define FIRST_LOCAL_BLOCK 2
+
+struct block
+{
+
+ /* Addresses in the executable code that are in this block. */
+
+ CORE_ADDR startaddr;
+ CORE_ADDR endaddr;
+
+ /* The symbol that names this block, if the block is the body of a
+ function; otherwise, zero. */
+
+ struct symbol *function;
+
+ /* The `struct block' for the containing block, or 0 if none.
+
+ The superblock of a top-level local block (i.e. a function in the
+ case of C) is the STATIC_BLOCK. The superblock of the
+ STATIC_BLOCK is the GLOBAL_BLOCK. */
+
+ struct block *superblock;
+
+ /* Version of GCC used to compile the function corresponding
+ to this block, or 0 if not compiled with GCC. When possible,
+ GCC should be compatible with the native compiler, or if that
+ is not feasible, the differences should be fixed during symbol
+ reading. As of 16 Apr 93, this flag is never used to distinguish
+ between gcc2 and the native compiler.
+
+ If there is no function corresponding to this block, this meaning
+ of this flag is undefined. */
+
+ unsigned char gcc_compile_flag;
+
+ /* Number of local symbols. */
+
+ int nsyms;
+
+ /* The symbols. If some of them are arguments, then they must be
+ in the order in which we would like to print them. */
+
+ struct symbol *sym[1];
+};
+
+#define BLOCK_START(bl) (bl)->startaddr
+#define BLOCK_END(bl) (bl)->endaddr
+#define BLOCK_NSYMS(bl) (bl)->nsyms
+#define BLOCK_SYM(bl, n) (bl)->sym[n]
+#define BLOCK_FUNCTION(bl) (bl)->function
+#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
+#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
+
+/* Nonzero if symbols of block BL should be sorted alphabetically.
+ Don't sort a block which corresponds to a function. If we did the
+ sorting would have to preserve the order of the symbols for the
+ arguments. */
+
+#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40 && BLOCK_FUNCTION (bl) == NULL)
+
+
+/* Represent one symbol name; a variable, constant, function or typedef. */
+
+/* Different name spaces for symbols. Looking up a symbol specifies a
+ namespace and ignores symbol definitions in other name spaces. */
+
+enum namespace
+{
+ /* UNDEF_NAMESPACE is used when a namespace has not been discovered or
+ none of the following apply. This usually indicates an error either
+ in the symbol information or in gdb's handling of symbols. */
+
+ UNDEF_NAMESPACE,
+
+ /* VAR_NAMESPACE is the usual namespace. In C, this contains variables,
+ function names, typedef names and enum type values. */
+
+ VAR_NAMESPACE,
+
+ /* STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
+ Thus, if `struct foo' is used in a C program, it produces a symbol named
+ `foo' in the STRUCT_NAMESPACE. */
+
+ STRUCT_NAMESPACE,
+
+ /* LABEL_NAMESPACE may be used for names of labels (for gotos);
+ currently it is not used and labels are not recorded at all. */
+
+ LABEL_NAMESPACE
+};
+
+/* An address-class says where to find the value of a symbol. */
+
+enum address_class
+{
+ /* Not used; catches errors */
+
+ LOC_UNDEF,
+
+ /* Value is constant int SYMBOL_VALUE, host byteorder */
+
+ LOC_CONST,
+
+ /* Value is at fixed address SYMBOL_VALUE_ADDRESS */
+
+ LOC_STATIC,
+
+ /* Value is in register. SYMBOL_VALUE is the register number. */
+
+ LOC_REGISTER,
+
+ /* It's an argument; the value is at SYMBOL_VALUE offset in arglist. */
+
+ LOC_ARG,
+
+ /* Value address is at SYMBOL_VALUE offset in arglist. */
+
+ LOC_REF_ARG,
+
+ /* Value is in register number SYMBOL_VALUE. Just like LOC_REGISTER
+ except this is an argument. Probably the cleaner way to handle
+ this would be to separate address_class (which would include
+ separate ARG and LOCAL to deal with FRAME_ARGS_ADDRESS versus
+ FRAME_LOCALS_ADDRESS), and an is_argument flag.
+
+ For some symbol formats (stabs, for some compilers at least),
+ the compiler generates two symbols, an argument and a register.
+ In some cases we combine them to a single LOC_REGPARM in symbol
+ reading, but currently not for all cases (e.g. it's passed on the
+ stack and then loaded into a register). */
+
+ LOC_REGPARM,
+
+ /* Value is in specified register. Just like LOC_REGPARM except the
+ register holds the address of the argument instead of the argument
+ itself. This is currently used for the passing of structs and unions
+ on sparc and hppa. It is also used for call by reference where the
+ address is in a register, at least by mipsread.c. */
+
+ LOC_REGPARM_ADDR,
+
+ /* Value is a local variable at SYMBOL_VALUE offset in stack frame. */
+
+ LOC_LOCAL,
+
+ /* Value not used; definition in SYMBOL_TYPE. Symbols in the namespace
+ STRUCT_NAMESPACE all have this class. */
+
+ LOC_TYPEDEF,
+
+ /* Value is address SYMBOL_VALUE_ADDRESS in the code */
+
+ LOC_LABEL,
+
+ /* In a symbol table, value is SYMBOL_BLOCK_VALUE of a `struct block'.
+ In a partial symbol table, SYMBOL_VALUE_ADDRESS is the start address
+ of the block. Function names have this class. */
+
+ LOC_BLOCK,
+
+ /* Value is a constant byte-sequence pointed to by SYMBOL_VALUE_BYTES, in
+ target byte order. */
+
+ LOC_CONST_BYTES,
+
+ /* Value is arg at SYMBOL_VALUE offset in stack frame. Differs from
+ LOC_LOCAL in that symbol is an argument; differs from LOC_ARG in
+ that we find it in the frame (FRAME_LOCALS_ADDRESS), not in the
+ arglist (FRAME_ARGS_ADDRESS). Added for i960, which passes args
+ in regs then copies to frame. */
+
+ LOC_LOCAL_ARG,
+
+ /* Value is at SYMBOL_VALUE offset from the current value of
+ register number SYMBOL_BASEREG. This exists mainly for the same
+ things that LOC_LOCAL and LOC_ARG do; but we need to do this
+ instead because on 88k DWARF gives us the offset from the
+ frame/stack pointer, rather than the offset from the "canonical
+ frame address" used by COFF, stabs, etc., and we don't know how
+ to convert between these until we start examining prologues.
+
+ Note that LOC_BASEREG is much less general than a DWARF expression.
+ We don't need the generality (at least not yet), and storing a general
+ DWARF expression would presumably take up more space than the existing
+ scheme. */
+
+ LOC_BASEREG,
+
+ /* Same as LOC_BASEREG but it is an argument. */
+
+ LOC_BASEREG_ARG,
+
+ /* The variable does not actually exist in the program.
+ The value is ignored. */
+
+ LOC_OPTIMIZED_OUT
+};
+
+struct symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Name space code. */
+
+ enum namespace namespace;
+
+ /* Address class */
+
+ enum address_class class;
+
+ /* Data type of value */
+
+ struct type *type;
+
+ /* Line number of definition. FIXME: Should we really make the assumption
+ that nobody will try to debug files longer than 64K lines? What about
+ machine generated programs? */
+
+ unsigned short line;
+
+ /* Some symbols require an additional value to be recorded on a per-
+ symbol basis. Stash those values here. */
+
+ union
+ {
+ /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */
+ short basereg;
+ }
+ aux_value;
+
+};
+
+#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace
+#define SYMBOL_CLASS(symbol) (symbol)->class
+#define SYMBOL_TYPE(symbol) (symbol)->type
+#define SYMBOL_LINE(symbol) (symbol)->line
+#define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg
+
+/* A partial_symbol records the name, namespace, and address class of
+ symbols whose types we have not parsed yet. For functions, it also
+ contains their memory address, so we can find them from a PC value.
+ Each partial_symbol sits in a partial_symtab, all of which are chained
+ on a partial symtab list and which points to the corresponding
+ normal symtab once the partial_symtab has been referenced. */
+
+struct partial_symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Name space code. */
+
+ enum namespace namespace;
+
+ /* Address class (for info_symbols) */
+
+ enum address_class class;
+
+};
+
+#define PSYMBOL_NAMESPACE(psymbol) (psymbol)->namespace
+#define PSYMBOL_CLASS(psymbol) (psymbol)->class
+
+
+/* Source-file information. This describes the relation between source files,
+ ine numbers and addresses in the program text. */
+
+struct sourcevector
+{
+ int length; /* Number of source files described */
+ struct source *source[1]; /* Descriptions of the files */
+};
+
+/* Each item represents a line-->pc (or the reverse) mapping. This is
+ somewhat more wasteful of space than one might wish, but since only
+ the files which are actually debugged are read in to core, we don't
+ waste much space. */
+
+struct linetable_entry
+{
+ int line;
+ CORE_ADDR pc;
+};
+
+/* The order of entries in the linetable is significant. They should
+ be sorted by increasing values of the pc field. If there is more than
+ one entry for a given pc, then I'm not sure what should happen (and
+ I not sure whether we currently handle it the best way).
+
+ Example: a C for statement generally looks like this
+
+ 10 0x100 - for the init/test part of a for stmt.
+ 20 0x200
+ 30 0x300
+ 10 0x400 - for the increment part of a for stmt.
+
+ */
+
+struct linetable
+{
+ int nitems;
+
+ /* Actually NITEMS elements. If you don't like this use of the
+ `struct hack', you can shove it up your ANSI (seriously, if the
+ committee tells us how to do it, we can probably go along). */
+ struct linetable_entry item[1];
+};
+
+/* All the information on one source file. */
+
+struct source
+{
+ char *name; /* Name of file */
+ struct linetable contents;
+};
+
+/* How to relocate the symbols from each section in a symbol file.
+ Each struct contains an array of offsets.
+ The ordering and meaning of the offsets is file-type-dependent;
+ typically it is indexed by section numbers or symbol types or
+ something like that.
+
+ To give us flexibility in changing the internal representation
+ of these offsets, the ANOFFSET macro must be used to insert and
+ extract offset values in the struct. */
+
+struct section_offsets
+ {
+ CORE_ADDR offsets[1]; /* As many as needed. */
+ };
+
+#define ANOFFSET(secoff, whichone) (secoff->offsets[whichone])
+
+/* Each source file or header is represented by a struct symtab.
+ These objects are chained through the `next' field. */
+
+struct symtab
+ {
+
+ /* Chain of all existing symtabs. */
+
+ struct symtab *next;
+
+ /* List of all symbol scope blocks for this symtab. May be shared
+ between different symtabs (and normally is for all the symtabs
+ in a given compilation unit). */
+
+ struct blockvector *blockvector;
+
+ /* Table mapping core addresses to line numbers for this file.
+ Can be NULL if none. Never shared between different symtabs. */
+
+ struct linetable *linetable;
+
+ /* Section in objfile->section_offsets for the blockvector and
+ the linetable. */
+
+ int block_line_section;
+
+ /* If several symtabs share a blockvector, exactly one of them
+ should be designed the primary, so that the blockvector
+ is relocated exactly once by objfile_relocate. */
+
+ int primary;
+
+ /* Name of this source file. */
+
+ char *filename;
+
+ /* Directory in which it was compiled, or NULL if we don't know. */
+
+ char *dirname;
+
+ /* This component says how to free the data we point to:
+ free_contents => do a tree walk and free each object.
+ free_nothing => do nothing; some other symtab will free
+ the data this one uses.
+ free_linetable => free just the linetable. FIXME: Is this redundant
+ with the primary field? */
+
+ enum free_code
+ {
+ free_nothing, free_contents, free_linetable
+ }
+ free_code;
+
+ /* Pointer to one block of storage to be freed, if nonzero. */
+ /* This is IN ADDITION to the action indicated by free_code. */
+
+ char *free_ptr;
+
+ /* Total number of lines found in source file. */
+
+ int nlines;
+
+ /* line_charpos[N] is the position of the (N-1)th line of the
+ source file. "position" means something we can lseek() to; it
+ is not guaranteed to be useful any other way. */
+
+ int *line_charpos;
+
+ /* Language of this source file. */
+
+ enum language language;
+
+ /* String of version information. May be zero. */
+
+ char *version;
+
+ /* Full name of file as found by searching the source path.
+ NULL if not yet known. */
+
+ char *fullname;
+
+ /* Object file from which this symbol information was read. */
+
+ struct objfile *objfile;
+
+ /* Anything extra for this symtab. This is for target machines
+ with special debugging info of some sort (which cannot just
+ be represented in a normal symtab). */
+
+#if defined (EXTRA_SYMTAB_INFO)
+ EXTRA_SYMTAB_INFO
+#endif
+
+ };
+
+#define BLOCKVECTOR(symtab) (symtab)->blockvector
+#define LINETABLE(symtab) (symtab)->linetable
+
+
+/* Each source file that has not been fully read in is represented by
+ a partial_symtab. This contains the information on where in the
+ executable the debugging symbols for a specific file are, and a
+ list of names of global symbols which are located in this file.
+ They are all chained on partial symtab lists.
+
+ Even after the source file has been read into a symtab, the
+ partial_symtab remains around. They are allocated on an obstack,
+ psymbol_obstack. FIXME, this is bad for dynamic linking or VxWorks-
+ style execution of a bunch of .o's. */
+
+struct partial_symtab
+{
+
+ /* Chain of all existing partial symtabs. */
+
+ struct partial_symtab *next;
+
+ /* Name of the source file which this partial_symtab defines */
+
+ char *filename;
+
+ /* Information about the object file from which symbols should be read. */
+
+ struct objfile *objfile;
+
+ /* Set of relocation offsets to apply to each section. */
+
+ struct section_offsets *section_offsets;
+
+ /* Range of text addresses covered by this file; texthigh is the
+ beginning of the next section. */
+
+ CORE_ADDR textlow;
+ CORE_ADDR texthigh;
+
+ /* Array of pointers to all of the partial_symtab's which this one
+ depends on. Since this array can only be set to previous or
+ the current (?) psymtab, this dependency tree is guaranteed not
+ to have any loops. "depends on" means that symbols must be read
+ for the dependencies before being read for this psymtab; this is
+ for type references in stabs, where if foo.c includes foo.h, declarations
+ in foo.h may use type numbers defined in foo.c. For other debugging
+ formats there may be no need to use dependencies. */
+
+ struct partial_symtab **dependencies;
+
+ int number_of_dependencies;
+
+ /* Global symbol list. This list will be sorted after readin to
+ improve access. Binary search will be the usual method of
+ finding a symbol within it. globals_offset is an integer offset
+ within global_psymbols[]. */
+
+ int globals_offset;
+ int n_global_syms;
+
+ /* Static symbol list. This list will *not* be sorted after readin;
+ to find a symbol in it, exhaustive search must be used. This is
+ reasonable because searches through this list will eventually
+ lead to either the read in of a files symbols for real (assumed
+ to take a *lot* of time; check) or an error (and we don't care
+ how long errors take). This is an offset and size within
+ static_psymbols[]. */
+
+ int statics_offset;
+ int n_static_syms;
+
+ /* Pointer to symtab eventually allocated for this source file, 0 if
+ !readin or if we haven't looked for the symtab after it was readin. */
+
+ struct symtab *symtab;
+
+ /* Pointer to function which will read in the symtab corresponding to
+ this psymtab. */
+
+ void (*read_symtab) PARAMS ((struct partial_symtab *));
+
+ /* Information that lets read_symtab() locate the part of the symbol table
+ that this psymtab corresponds to. This information is private to the
+ format-dependent symbol reading routines. For further detail examine
+ the various symbol reading modules. Should really be (void *) but is
+ (char *) as with other such gdb variables. (FIXME) */
+
+ char *read_symtab_private;
+
+ /* Non-zero if the symtab corresponding to this psymtab has been readin */
+
+ unsigned char readin;
+};
+
+/* A fast way to get from a psymtab to its symtab (after the first time). */
+#define PSYMTAB_TO_SYMTAB(pst) \
+ ((pst) -> symtab != NULL ? (pst) -> symtab : psymtab_to_symtab (pst))
+
+
+/* The virtual function table is now an array of structures which have the
+ form { int16 offset, delta; void *pfn; }.
+
+ In normal virtual function tables, OFFSET is unused.
+ DELTA is the amount which is added to the apparent object's base
+ address in order to point to the actual object to which the
+ virtual function should be applied.
+ PFN is a pointer to the virtual function.
+
+ Note that this macro is g++ specific (FIXME). */
+
+#define VTBL_FNADDR_OFFSET 2
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ operator
+ names. If you leave out the parenthesis here you will lose!
+ Currently 'o' 'p' CPLUS_MARKER is used for both the symbol in the
+ symbol-file and the names in gdb's symbol table.
+ Note that this macro is g++ specific (FIXME). */
+
+#define OPNAME_PREFIX_P(NAME) \
+ ((NAME)[0] == 'o' && (NAME)[1] == 'p' && (NAME)[2] == CPLUS_MARKER)
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl
+ names. Note that this macro is g++ specific (FIXME). */
+
+#define VTBL_PREFIX_P(NAME) \
+ ((NAME)[3] == CPLUS_MARKER && !strncmp ((NAME), "_vt", 3))
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ destructor
+ names. Note that this macro is g++ specific (FIXME). */
+
+#define DESTRUCTOR_PREFIX_P(NAME) \
+ ((NAME)[0] == '_' && (NAME)[1] == CPLUS_MARKER && (NAME)[2] == '_')
+
+
+/* External variables and functions for the objects described above. */
+
+/* This symtab variable specifies the current file for printing source lines */
+
+extern struct symtab *current_source_symtab;
+
+/* This is the next line to print for listing source lines. */
+
+extern int current_source_line;
+
+/* See the comment in symfile.c about how current_objfile is used. */
+
+extern struct objfile *current_objfile;
+
+extern struct symtab *
+lookup_symtab PARAMS ((char *));
+
+extern struct symbol *
+lookup_symbol PARAMS ((const char *, const struct block *,
+ const enum namespace, int *, struct symtab **));
+
+extern struct symbol *
+lookup_block_symbol PARAMS ((const struct block *, const char *,
+ const enum namespace));
+
+extern struct type *
+lookup_struct PARAMS ((char *, struct block *));
+
+extern struct type *
+lookup_union PARAMS ((char *, struct block *));
+
+extern struct type *
+lookup_enum PARAMS ((char *, struct block *));
+
+extern struct symbol *
+block_function PARAMS ((struct block *));
+
+extern struct symbol *
+find_pc_function PARAMS ((CORE_ADDR));
+
+extern int find_pc_partial_function
+ PARAMS ((CORE_ADDR, char **, CORE_ADDR *, CORE_ADDR *));
+
+extern void
+clear_pc_function_cache PARAMS ((void));
+
+extern struct partial_symtab *
+lookup_partial_symtab PARAMS ((char *));
+
+extern struct partial_symtab *
+find_pc_psymtab PARAMS ((CORE_ADDR));
+
+extern struct symtab *
+find_pc_symtab PARAMS ((CORE_ADDR));
+
+extern struct partial_symbol *
+find_pc_psymbol PARAMS ((struct partial_symtab *, CORE_ADDR));
+
+extern int
+find_pc_line_pc_range PARAMS ((CORE_ADDR, CORE_ADDR *, CORE_ADDR *));
+
+extern int
+contained_in PARAMS ((struct block *, struct block *));
+
+extern void
+reread_symbols PARAMS ((void));
+
+/* Functions for dealing with the minimal symbol table, really a misc
+ address<->symbol mapping for things we don't have debug symbols for. */
+
+extern void
+prim_record_minimal_symbol PARAMS ((const char *, CORE_ADDR,
+ enum minimal_symbol_type));
+
+extern void
+prim_record_minimal_symbol_and_info PARAMS ((const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ char *info, int section));
+
+extern struct minimal_symbol *
+lookup_minimal_symbol PARAMS ((const char *, struct objfile *));
+
+extern struct minimal_symbol *
+lookup_minimal_symbol_by_pc PARAMS ((CORE_ADDR));
+
+extern void
+init_minimal_symbol_collection PARAMS ((void));
+
+extern void
+discard_minimal_symbols PARAMS ((int));
+
+extern void
+install_minimal_symbols PARAMS ((struct objfile *));
+
+struct symtab_and_line
+{
+ struct symtab *symtab;
+
+ /* Line number. Line numbers start at 1 and proceed through symtab->nlines.
+ 0 is never a valid line number; it is used to indicate that line number
+ information is not available. */
+ int line;
+
+ CORE_ADDR pc;
+ CORE_ADDR end;
+};
+
+struct symtabs_and_lines
+{
+ struct symtab_and_line *sals;
+ int nelts;
+};
+
+/* Given a pc value, return line number it is in. Second arg nonzero means
+ if pc is on the boundary use the previous statement's line number. */
+
+extern struct symtab_and_line
+find_pc_line PARAMS ((CORE_ADDR, int));
+
+/* Given a symtab and line number, return the pc there. */
+
+extern CORE_ADDR
+find_line_pc PARAMS ((struct symtab *, int));
+
+extern int
+find_line_pc_range PARAMS ((struct symtab *, int, CORE_ADDR *, CORE_ADDR *));
+
+extern void
+resolve_sal_pc PARAMS ((struct symtab_and_line *));
+
+/* Given a string, return the line specified by it. For commands like "list"
+ and "breakpoint". */
+
+extern struct symtabs_and_lines
+decode_line_spec PARAMS ((char *, int));
+
+extern struct symtabs_and_lines
+decode_line_spec_1 PARAMS ((char *, int));
+
+extern struct symtabs_and_lines
+decode_line_1 PARAMS ((char **, int, struct symtab *, int, char ***));
+
+/* Symmisc.c */
+
+#if MAINTENANCE_CMDS
+
+void
+maintenance_print_symbols PARAMS ((char *, int));
+
+void
+maintenance_print_psymbols PARAMS ((char *, int));
+
+void
+maintenance_print_msymbols PARAMS ((char *, int));
+
+void
+maintenance_print_objfiles PARAMS ((char *, int));
+
+#endif
+
+extern void
+free_symtab PARAMS ((struct symtab *));
+
+/* Symbol-reading stuff in symfile.c and solib.c. */
+
+extern struct symtab *
+psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+extern void
+clear_solib PARAMS ((void));
+
+extern struct objfile *
+symbol_file_add PARAMS ((char *, int, CORE_ADDR, int, int, int));
+
+/* source.c */
+
+extern int frame_file_full_name; /* in stack.c */
+
+extern int
+identify_source_line PARAMS ((struct symtab *, int, int, CORE_ADDR));
+
+extern void
+print_source_lines PARAMS ((struct symtab *, int, int, int));
+
+extern void
+forget_cached_source_info PARAMS ((void));
+
+extern void
+select_source_symtab PARAMS ((struct symtab *));
+
+extern char **make_symbol_completion_list PARAMS ((char *, char *));
+
+/* symtab.c */
+
+extern struct partial_symtab *
+find_main_psymtab PARAMS ((void));
+
+/* blockframe.c */
+
+extern struct blockvector *
+blockvector_for_pc PARAMS ((CORE_ADDR, int *));
+
+/* symfile.c */
+
+extern void
+clear_symtab_users PARAMS ((void));
+
+extern enum language
+deduce_language_from_filename PARAMS ((char *));
+
+#endif /* !defined(SYMTAB_H) */
diff --git a/gnu/usr.bin/gdb/gdb/target.c b/gnu/usr.bin/gdb/gdb/target.c
new file mode 100644
index 000000000000..ea1bd93ca3b6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.c
@@ -0,0 +1,789 @@
+/* Select target systems and architectures at runtime for GDB.
+ Copyright 1990, 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <errno.h>
+#include <ctype.h>
+#include "target.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+extern int errno;
+
+static void
+target_info PARAMS ((char *, int));
+
+static void
+cleanup_target PARAMS ((struct target_ops *));
+
+static void
+maybe_kill_then_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+maybe_kill_then_attach PARAMS ((char *, int));
+
+static void
+kill_or_be_killed PARAMS ((int));
+
+static void
+default_terminal_info PARAMS ((char *, int));
+
+static int
+nosymbol PARAMS ((char *, CORE_ADDR *));
+
+static void
+tcomplain PARAMS ((void));
+
+static int
+nomemory PARAMS ((CORE_ADDR, char *, int, int));
+
+static int
+return_zero PARAMS ((void));
+
+static void
+ignore PARAMS ((void));
+
+static void
+target_command PARAMS ((char *, int));
+
+static struct target_ops *
+find_default_run_target PARAMS ((char *));
+
+/* Pointer to array of target architecture structures; the size of the
+ array; the current index into the array; the allocated size of the
+ array. */
+struct target_ops **target_structs;
+unsigned target_struct_size;
+unsigned target_struct_index;
+unsigned target_struct_allocsize;
+#define DEFAULT_ALLOCSIZE 10
+
+/* The initial current target, so that there is always a semi-valid
+ current target. */
+
+struct target_ops dummy_target = {"None", "None", "",
+ 0, 0, /* open, close */
+ find_default_attach, 0, /* attach, detach */
+ 0, 0, /* resume, wait */
+ 0, 0, 0, /* registers */
+ 0, 0, /* memory */
+ 0, 0, /* bkpts */
+ 0, 0, 0, 0, 0, /* terminal */
+ 0, 0, /* kill, load */
+ 0, /* lookup_symbol */
+ find_default_create_inferior, /* create_inferior */
+ 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ dummy_stratum, 0, /* stratum, next */
+ 0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC,
+};
+
+/* The target structure we are currently using to talk to a process
+ or file or whatever "inferior" we have. */
+
+struct target_ops *current_target;
+
+/* The stack of target structures that have been pushed. */
+
+struct target_ops **current_target_stack;
+
+/* Command list for target. */
+
+static struct cmd_list_element *targetlist = NULL;
+
+/* The user just typed 'target' without the name of a target. */
+
+/* ARGSUSED */
+static void
+target_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ fputs_filtered ("Argument required (target name). Try `help target'\n",
+ stdout);
+}
+
+/* Add a possible target architecture to the list. */
+
+void
+add_target (t)
+ struct target_ops *t;
+{
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf(stderr, "Magic number of %s target struct wrong\n",
+ t->to_shortname);
+ abort();
+ }
+
+ if (!target_structs)
+ {
+ target_struct_allocsize = DEFAULT_ALLOCSIZE;
+ target_structs = (struct target_ops **) xmalloc
+ (target_struct_allocsize * sizeof (*target_structs));
+ }
+ if (target_struct_size >= target_struct_allocsize)
+ {
+ target_struct_allocsize *= 2;
+ target_structs = (struct target_ops **)
+ xrealloc ((char *) target_structs,
+ target_struct_allocsize * sizeof (*target_structs));
+ }
+ target_structs[target_struct_size++] = t;
+ cleanup_target (t);
+
+ if (targetlist == NULL)
+ add_prefix_cmd ("target", class_run, target_command,
+ "Connect to a target machine or process.\n\
+The first argument is the type or protocol of the target machine.\n\
+Remaining arguments are interpreted by the target protocol. For more\n\
+information on the arguments for a particular protocol, type\n\
+`help target ' followed by the protocol name.",
+ &targetlist, "target ", 0, &cmdlist);
+ add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist);
+}
+
+/* Stub functions */
+
+static void
+ignore ()
+{
+}
+
+/* ARGSUSED */
+static int
+nomemory (memaddr, myaddr, len, write)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+{
+ errno = EIO; /* Can't read/write this location */
+ return 0; /* No bytes handled */
+}
+
+static void
+tcomplain ()
+{
+ error ("You can't do that when your target is `%s'",
+ current_target->to_shortname);
+}
+
+void
+noprocess ()
+{
+ error ("You can't do that without a process to debug");
+}
+
+/* ARGSUSED */
+static int
+nosymbol (name, addrp)
+ char *name;
+ CORE_ADDR *addrp;
+{
+ return 1; /* Symbol does not exist in target env */
+}
+
+/* ARGSUSED */
+static void
+default_terminal_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf("No saved terminal information.\n");
+}
+
+#if 0
+/* With strata, this function is no longer needed. FIXME. */
+/* This is the default target_create_inferior function. It looks up
+ the stack for some target that cares to create inferiors, then
+ calls it -- or complains if not found. */
+
+static void
+upstack_create_inferior (exec, args, env)
+ char *exec;
+ char *args;
+ char **env;
+{
+ struct target_ops *t;
+
+ for (t = current_target;
+ t;
+ t = t->to_next)
+ {
+ if (t->to_create_inferior != upstack_create_inferior)
+ {
+ t->to_create_inferior (exec, args, env);
+ return;
+ }
+
+ }
+ tcomplain();
+}
+#endif
+
+/* This is the default target_create_inferior and target_attach function.
+ If the current target is executing, it asks whether to kill it off.
+ If this function returns without calling error(), it has killed off
+ the target, and the operation should be attempted. */
+
+static void
+kill_or_be_killed (from_tty)
+ int from_tty;
+{
+ if (target_has_execution)
+ {
+ printf ("You are already running a program:\n");
+ target_files_info ();
+ if (query ("Kill it? ")) {
+ target_kill ();
+ if (target_has_execution)
+ error ("Killing the program did not help.");
+ return;
+ } else {
+ error ("Program not killed.");
+ }
+ }
+ tcomplain();
+}
+
+static void
+maybe_kill_then_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ kill_or_be_killed (from_tty);
+ target_attach (args, from_tty);
+}
+
+static void
+maybe_kill_then_create_inferior (exec, args, env)
+ char *exec;
+ char *args;
+ char **env;
+{
+ kill_or_be_killed (0);
+ target_create_inferior (exec, args, env);
+}
+
+/* Clean up a target struct so it no longer has any zero pointers in it.
+ We default entries, at least to stubs that print error messages. */
+
+static void
+cleanup_target (t)
+ struct target_ops *t;
+{
+
+ /* Check magic number. If wrong, it probably means someone changed
+ the struct definition, but not all the places that initialize one. */
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf(stderr, "Magic number of %s target struct wrong\n",
+ t->to_shortname);
+ abort();
+ }
+
+#define de_fault(field, value) \
+ if (!t->field) t->field = value
+
+ /* FIELD DEFAULT VALUE */
+
+ de_fault (to_open, (void (*)())tcomplain);
+ de_fault (to_close, (void (*)())ignore);
+ de_fault (to_attach, maybe_kill_then_attach);
+ de_fault (to_detach, (void (*)())ignore);
+ de_fault (to_resume, (void (*)())noprocess);
+ de_fault (to_wait, (int (*)())noprocess);
+ de_fault (to_fetch_registers, (void (*)())ignore);
+ de_fault (to_store_registers, (void (*)())noprocess);
+ de_fault (to_prepare_to_store, (void (*)())noprocess);
+ de_fault (to_xfer_memory, (int (*)())nomemory);
+ de_fault (to_files_info, (void (*)())ignore);
+ de_fault (to_insert_breakpoint, memory_insert_breakpoint);
+ de_fault (to_remove_breakpoint, memory_remove_breakpoint);
+ de_fault (to_terminal_init, ignore);
+ de_fault (to_terminal_inferior, ignore);
+ de_fault (to_terminal_ours_for_output,ignore);
+ de_fault (to_terminal_ours, ignore);
+ de_fault (to_terminal_info, default_terminal_info);
+ de_fault (to_kill, (void (*)())noprocess);
+ de_fault (to_load, (void (*)())tcomplain);
+ de_fault (to_lookup_symbol, nosymbol);
+ de_fault (to_create_inferior, maybe_kill_then_create_inferior);
+ de_fault (to_mourn_inferior, (void (*)())noprocess);
+ de_fault (to_can_run, return_zero);
+ de_fault (to_notice_signals, (void (*)())ignore);
+ de_fault (to_next, 0);
+ de_fault (to_has_all_memory, 0);
+ de_fault (to_has_memory, 0);
+ de_fault (to_has_stack, 0);
+ de_fault (to_has_registers, 0);
+ de_fault (to_has_execution, 0);
+
+#undef de_fault
+}
+
+/* Push a new target type into the stack of the existing target accessors,
+ possibly superseding some of the existing accessors.
+
+ Result is zero if the pushed target ended up on top of the stack,
+ nonzero if at least one target is on top of it.
+
+ Rather than allow an empty stack, we always have the dummy target at
+ the bottom stratum, so we can call the function vectors without
+ checking them. */
+
+int
+push_target (t)
+ struct target_ops *t;
+{
+ struct target_ops *st, *prev;
+
+ for (prev = 0, st = current_target;
+ st;
+ prev = st, st = st->to_next) {
+ if ((int)(t->to_stratum) >= (int)(st->to_stratum))
+ break;
+ }
+
+ while (t->to_stratum == st->to_stratum) {
+ /* There's already something on this stratum. Close it off. */
+ (st->to_close) (0);
+ if (prev)
+ prev->to_next = st->to_next; /* Unchain old target_ops */
+ else
+ current_target = st->to_next; /* Unchain first on list */
+ st = st->to_next;
+ }
+
+ /* We have removed all targets in our stratum, now add ourself. */
+ t->to_next = st;
+ if (prev)
+ prev->to_next = t;
+ else
+ current_target = t;
+
+ cleanup_target (current_target);
+ return prev != 0;
+}
+
+/* Remove a target_ops vector from the stack, wherever it may be.
+ Return how many times it was removed (0 or 1 unless bug). */
+
+int
+unpush_target (t)
+ struct target_ops *t;
+{
+ struct target_ops *u, *v;
+ int result = 0;
+
+ for (u = current_target, v = 0;
+ u;
+ v = u, u = u->to_next)
+ if (u == t)
+ {
+ if (v == 0)
+ pop_target(); /* unchain top copy */
+ else {
+ (t->to_close)(0); /* Let it clean up */
+ v->to_next = t->to_next; /* unchain middle copy */
+ }
+ result++;
+ }
+ return result;
+}
+
+void
+pop_target ()
+{
+ (current_target->to_close)(0); /* Let it clean up */
+ current_target = current_target->to_next;
+#if 0
+ /* This will dump core if ever called--push_target expects current_target
+ to be non-NULL. But I don't think it's needed; I don't see how the
+ dummy_target could ever be removed from the stack. */
+ if (!current_target) /* At bottom, push dummy. */
+ push_target (&dummy_target);
+#endif
+}
+
+#undef MIN
+#define MIN(A, B) (((A) <= (B)) ? (A) : (B))
+
+/* target_read_string -- read a null terminated string from MEMADDR in target.
+ The read may also be terminated early by getting an error from target_xfer_
+ memory.
+ LEN is the size of the buffer pointed to by MYADDR. Note that a terminating
+ null will only be written if there is sufficient room. The return value is
+ is the number of bytes (including the null) actually transferred.
+*/
+
+int
+target_read_string (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int tlen, origlen, offset, i;
+ char buf[4];
+
+ origlen = len;
+
+ while (len > 0)
+ {
+ tlen = MIN (len, 4 - (memaddr & 3));
+ offset = memaddr & 3;
+
+ if (target_xfer_memory (memaddr & ~3, buf, 4, 0))
+ return origlen - len;
+
+ for (i = 0; i < tlen; i++)
+ {
+ *myaddr++ = buf[i + offset];
+ if (buf[i + offset] == '\000')
+ return (origlen - len) + i + 1;
+ }
+
+ memaddr += tlen;
+ len -= tlen;
+ }
+ return origlen;
+}
+
+/* Read LEN bytes of target memory at address MEMADDR, placing the results in
+ GDB's memory at MYADDR. Returns either 0 for success or an errno value
+ if any error occurs.
+
+ If an error occurs, no guarantee is made about the contents of the data at
+ MYADDR. In particular, the caller should not depend upon partial reads
+ filling the buffer with good data. There is no way for the caller to know
+ how much good data might have been transfered anyway. Callers that can
+ deal with partial reads should call target_read_memory_partial. */
+
+int
+target_read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ return target_xfer_memory (memaddr, myaddr, len, 0);
+}
+
+/* Read LEN bytes of target memory at address MEMADDR, placing the results
+ in GDB's memory at MYADDR. Returns a count of the bytes actually read,
+ and optionally an errno value in the location pointed to by ERRNOPTR
+ if ERRNOPTR is non-null. */
+
+int
+target_read_memory_partial (memaddr, myaddr, len, errnoptr)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int *errnoptr;
+{
+ int nread; /* Number of bytes actually read. */
+ int errcode; /* Error from last read. */
+
+ /* First try a complete read. */
+ errcode = target_xfer_memory (memaddr, myaddr, len, 0);
+ if (errcode == 0)
+ {
+ /* Got it all. */
+ nread = len;
+ }
+ else
+ {
+ /* Loop, reading one byte at a time until we get as much as we can. */
+ for (errcode = 0, nread = 0; len > 0 && errcode == 0; nread++, len--)
+ {
+ errcode = target_xfer_memory (memaddr++, myaddr++, 1, 0);
+ }
+ /* If an error, the last read was unsuccessful, so adjust count. */
+ if (errcode != 0)
+ {
+ nread--;
+ }
+ }
+ if (errnoptr != NULL)
+ {
+ *errnoptr = errcode;
+ }
+ return (nread);
+}
+
+int
+target_write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ return target_xfer_memory (memaddr, myaddr, len, 1);
+}
+
+/* Move memory to or from the targets. Iterate until all of it has
+ been moved, if necessary. The top target gets priority; anything
+ it doesn't want, is offered to the next one down, etc. Note the
+ business with curlen: if an early target says "no, but I have a
+ boundary overlapping this xfer" then we shorten what we offer to
+ the subsequent targets so the early guy will get a chance at the
+ tail before the subsequent ones do.
+
+ Result is 0 or errno value. */
+
+int
+target_xfer_memory (memaddr, myaddr, len, write)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+{
+ int curlen;
+ int res;
+ struct target_ops *t;
+
+ /* to_xfer_memory is not guaranteed to set errno, even when it returns
+ 0. */
+ errno = 0;
+
+ /* The quick case is that the top target does it all. */
+ res = current_target->to_xfer_memory
+ (memaddr, myaddr, len, write, current_target);
+ if (res == len)
+ return 0;
+
+ if (res > 0)
+ goto bump;
+ /* If res <= 0 then we call it again in the loop. Ah well. */
+
+ for (; len > 0;)
+ {
+ curlen = len; /* Want to do it all */
+ for (t = current_target;
+ t;
+ t = t->to_has_all_memory? 0: t->to_next)
+ {
+ res = t->to_xfer_memory(memaddr, myaddr, curlen, write, t);
+ if (res > 0) break; /* Handled all or part of xfer */
+ if (res == 0) continue; /* Handled none */
+ curlen = -res; /* Could handle once we get past res bytes */
+ }
+ if (res <= 0)
+ {
+ /* If this address is for nonexistent memory,
+ read zeros if reading, or do nothing if writing. Return error. */
+ if (!write)
+ memset (myaddr, 0, len);
+ if (errno == 0)
+ return EIO;
+ else
+ return errno;
+ }
+bump:
+ memaddr += res;
+ myaddr += res;
+ len -= res;
+ }
+ return 0; /* We managed to cover it all somehow. */
+}
+
+
+/* ARGSUSED */
+static void
+target_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct target_ops *t;
+ int has_all_mem = 0;
+
+ if (symfile_objfile != NULL)
+ printf ("Symbols from \"%s\".\n", symfile_objfile->name);
+
+#ifdef FILES_INFO_HOOK
+ if (FILES_INFO_HOOK ())
+ return;
+#endif
+
+ for (t = current_target;
+ t;
+ t = t->to_next)
+ {
+ if ((int)(t->to_stratum) <= (int)dummy_stratum)
+ continue;
+ if (has_all_mem)
+ printf("\tWhile running this, gdb does not access memory from...\n");
+ printf("%s:\n", t->to_longname);
+ (t->to_files_info)(t);
+ has_all_mem = t->to_has_all_memory;
+ }
+}
+
+/* This is to be called by the open routine before it does
+ anything. */
+
+void
+target_preopen (from_tty)
+ int from_tty;
+{
+ dont_repeat();
+
+ if (target_has_execution)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ target_kill ();
+ else
+ error ("Program not killed.");
+ }
+}
+
+/* Detach a target after doing deferred register stores. */
+
+void
+target_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ /* Handle any optimized stores to the inferior. */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+ (current_target->to_detach) (args, from_tty);
+}
+
+/* Look through the list of possible targets for a target that can
+ execute a run or attach command without any other data. This is
+ used to locate the default process stratum.
+
+ Result is always valid (error() is called for errors). */
+
+static struct target_ops *
+find_default_run_target (do_mesg)
+ char *do_mesg;
+{
+ struct target_ops **t;
+ struct target_ops *runable = NULL;
+ int count;
+
+ count = 0;
+
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+ if (target_can_run(*t))
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ if (count != 1)
+ error ("Don't know how to %s. Try \"help target\".", do_mesg);
+
+ return runable;
+}
+
+void
+find_default_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct target_ops *t;
+
+ t = find_default_run_target("attach");
+ (t->to_attach) (args, from_tty);
+ return;
+}
+
+void
+find_default_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ struct target_ops *t;
+
+ t = find_default_run_target("run");
+ (t->to_create_inferior) (exec_file, allargs, env);
+ return;
+}
+
+static int
+return_zero ()
+{
+ return 0;
+}
+
+struct target_ops *
+find_core_target ()
+{
+ struct target_ops **t;
+ struct target_ops *runable = NULL;
+ int count;
+
+ count = 0;
+
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+ if ((*t)->to_stratum == core_stratum)
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ return(count == 1 ? runable : NULL);
+}
+
+/* Convert a normal process ID to a string. Returns the string in a static
+ buffer. */
+
+char *
+normal_pid_to_str (pid)
+ int pid;
+{
+ static char buf[30];
+
+ sprintf (buf, "process %d", pid);
+
+ return buf;
+}
+
+static char targ_desc[] =
+ "Names of targets and files being debugged.\n\
+Shows the entire stack of targets currently in use (including the exec-file,\n\
+core-file, and process, if any), as well as the symbol file name.";
+
+void
+_initialize_targets ()
+{
+ current_target = &dummy_target;
+ cleanup_target (current_target);
+
+ add_info ("target", target_info, targ_desc);
+ add_info ("files", target_info, targ_desc);
+}
diff --git a/gnu/usr.bin/gdb/gdb/target.h b/gnu/usr.bin/gdb/gdb/target.h
new file mode 100644
index 000000000000..c112b4ac122f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.h
@@ -0,0 +1,465 @@
+/* Interface between GDB and target environments, including files and processes
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TARGET_H)
+#define TARGET_H
+
+/* This include file defines the interface between the main part
+ of the debugger, and the part which is target-specific, or
+ specific to the communications interface between us and the
+ target.
+
+ A TARGET is an interface between the debugger and a particular
+ kind of file or process. Targets can be STACKED in STRATA,
+ so that more than one target can potentially respond to a request.
+ In particular, memory accesses will walk down the stack of targets
+ until they find a target that is interested in handling that particular
+ address. STRATA are artificial boundaries on the stack, within
+ which particular kinds of targets live. Strata exist so that
+ people don't get confused by pushing e.g. a process target and then
+ a file target, and wondering why they can't see the current values
+ of variables any more (the file target is handling them and they
+ never get to the process target). So when you push a file target,
+ it goes into the file stratum, which is always below the process
+ stratum. */
+
+#include "bfd.h"
+
+enum strata {
+ dummy_stratum, /* The lowest of the low */
+ file_stratum, /* Executable files, etc */
+ core_stratum, /* Core dump files */
+ process_stratum /* Executing processes */
+};
+
+struct target_ops
+{
+ char *to_shortname; /* Name this target type */
+ char *to_longname; /* Name for printing */
+ char *to_doc; /* Documentation. Does not include trailing
+ newline, and starts with a one-line descrip-
+ tion (probably similar to to_longname). */
+ void (*to_open) PARAMS ((char *, int));
+ void (*to_close) PARAMS ((int));
+ void (*to_attach) PARAMS ((char *, int));
+ void (*to_detach) PARAMS ((char *, int));
+ void (*to_resume) PARAMS ((int, int, int));
+ int (*to_wait) PARAMS ((int, int *));
+ void (*to_fetch_registers) PARAMS ((int));
+ void (*to_store_registers) PARAMS ((int));
+ void (*to_prepare_to_store) PARAMS ((void));
+
+ /* Transfer LEN bytes of memory between GDB address MYADDR and
+ target address MEMADDR. If WRITE, transfer them to the target, else
+ transfer them from the target. TARGET is the target from which we
+ get this function.
+
+ Return value, N, is one of the following:
+
+ 0 means that we can't handle this. If errno has been set, it is the
+ error which prevented us from doing it (FIXME: What about bfd_error?).
+
+ positive (call it N) means that we have transferred N bytes
+ starting at MEMADDR. We might be able to handle more bytes
+ beyond this length, but no promises.
+
+ negative (call its absolute value N) means that we cannot
+ transfer right at MEMADDR, but we could transfer at least
+ something at MEMADDR + N. */
+
+ int (*to_xfer_memory) PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int write,
+ struct target_ops * target));
+
+ void (*to_files_info) PARAMS ((struct target_ops *));
+ int (*to_insert_breakpoint) PARAMS ((CORE_ADDR, char *));
+ int (*to_remove_breakpoint) PARAMS ((CORE_ADDR, char *));
+ void (*to_terminal_init) PARAMS ((void));
+ void (*to_terminal_inferior) PARAMS ((void));
+ void (*to_terminal_ours_for_output) PARAMS ((void));
+ void (*to_terminal_ours) PARAMS ((void));
+ void (*to_terminal_info) PARAMS ((char *, int));
+ void (*to_kill) PARAMS ((void));
+ void (*to_load) PARAMS ((char *, int));
+ int (*to_lookup_symbol) PARAMS ((char *, CORE_ADDR *));
+ void (*to_create_inferior) PARAMS ((char *, char *, char **));
+ void (*to_mourn_inferior) PARAMS ((void));
+ int (*to_can_run) PARAMS ((void));
+ void (*to_notice_signals) PARAMS ((int pid));
+ enum strata to_stratum;
+ struct target_ops
+ *to_next;
+ int to_has_all_memory;
+ int to_has_memory;
+ int to_has_stack;
+ int to_has_registers;
+ int to_has_execution;
+ struct section_table
+ *to_sections;
+ struct section_table
+ *to_sections_end;
+ int to_magic;
+ /* Need sub-structure for target machine related rather than comm related? */
+};
+
+/* Magic number for checking ops size. If a struct doesn't end with this
+ number, somebody changed the declaration but didn't change all the
+ places that initialize one. */
+
+#define OPS_MAGIC 3840
+
+/* The ops structure for our "current" target process. This should
+ never be NULL. If there is no target, it points to the dummy_target. */
+
+extern struct target_ops *current_target;
+
+/* Define easy words for doing these operations on our current target. */
+
+#define target_shortname (current_target->to_shortname)
+#define target_longname (current_target->to_longname)
+
+/* The open routine takes the rest of the parameters from the command,
+ and (if successful) pushes a new target onto the stack.
+ Targets should supply this routine, if only to provide an error message. */
+#define target_open(name, from_tty) \
+ (*current_target->to_open) (name, from_tty)
+
+/* Does whatever cleanup is required for a target that we are no longer
+ going to be calling. Argument says whether we are quitting gdb and
+ should not get hung in case of errors, or whether we want a clean
+ termination even if it takes a while. This routine is automatically
+ always called just before a routine is popped off the target stack.
+ Closing file descriptors and freeing memory are typical things it should
+ do. */
+
+#define target_close(quitting) \
+ (*current_target->to_close) (quitting)
+
+/* Attaches to a process on the target side. Arguments are as passed
+ to the `attach' command by the user. This routine can be called
+ when the target is not on the target-stack, if the target_can_run
+ routine returns 1; in that case, it must push itself onto the stack.
+ Upon exit, the target should be ready for normal operations, and
+ should be ready to deliver the status of the process immediately
+ (without waiting) to an upcoming target_wait call. */
+
+#define target_attach(args, from_tty) \
+ (*current_target->to_attach) (args, from_tty)
+
+/* Takes a program previously attached to and detaches it.
+ The program may resume execution (some targets do, some don't) and will
+ no longer stop on signals, etc. We better not have left any breakpoints
+ in the program or it'll die when it hits one. ARGS is arguments
+ typed by the user (e.g. a signal to send the process). FROM_TTY
+ says whether to be verbose or not. */
+
+extern void
+target_detach PARAMS ((char *, int));
+
+/* Resume execution of the target process PID. STEP says whether to
+ single-step or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be
+ given to the target, or zero for no signal. */
+
+#define target_resume(pid, step, siggnal) \
+ (*current_target->to_resume) (pid, step, siggnal)
+
+/* Wait for process pid to do something. Pid = -1 to wait for any pid to do
+ something. Return pid of child, or -1 in case of error; store status
+ through argument pointer STATUS. */
+
+#define target_wait(pid, status) \
+ (*current_target->to_wait) (pid, status)
+
+/* Fetch register REGNO, or all regs if regno == -1. No result. */
+
+#define target_fetch_registers(regno) \
+ (*current_target->to_fetch_registers) (regno)
+
+/* Store at least register REGNO, or all regs if REGNO == -1.
+ It can store as many registers as it wants to, so target_prepare_to_store
+ must have been previously called. Calls error() if there are problems. */
+
+#define target_store_registers(regs) \
+ (*current_target->to_store_registers) (regs)
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that REGISTERS contains all the registers from the program being
+ debugged. */
+
+#define target_prepare_to_store() \
+ (*current_target->to_prepare_to_store) ()
+
+extern int
+target_read_string PARAMS ((CORE_ADDR, char *, int));
+
+extern int
+target_read_memory PARAMS ((CORE_ADDR, char *, int));
+
+extern int
+target_read_memory_partial PARAMS ((CORE_ADDR, char *, int, int *));
+
+extern int
+target_write_memory PARAMS ((CORE_ADDR, char *, int));
+
+extern int
+xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+extern int
+child_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+/* Transfer LEN bytes between target address MEMADDR and GDB address MYADDR.
+ Returns 0 for success, errno code for failure (which includes partial
+ transfers--if you want a more useful response to partial transfers, try
+ target_read_memory_partial). */
+
+extern int target_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int write));
+
+/* From exec.c */
+
+extern void
+print_section_info PARAMS ((struct target_ops *, bfd *));
+
+/* Print a line about the current target. */
+
+#define target_files_info() \
+ (*current_target->to_files_info) (current_target)
+
+/* Insert a breakpoint at address ADDR in the target machine.
+ SAVE is a pointer to memory allocated for saving the
+ target contents. It is guaranteed by the caller to be long enough
+ to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or
+ an errno value. */
+
+#define target_insert_breakpoint(addr, save) \
+ (*current_target->to_insert_breakpoint) (addr, save)
+
+/* Remove a breakpoint at address ADDR in the target machine.
+ SAVE is a pointer to the same save area
+ that was previously passed to target_insert_breakpoint.
+ Result is 0 for success, or an errno value. */
+
+#define target_remove_breakpoint(addr, save) \
+ (*current_target->to_remove_breakpoint) (addr, save)
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+#define target_terminal_init() \
+ (*current_target->to_terminal_init) ()
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+#define target_terminal_inferior() \
+ (*current_target->to_terminal_inferior) ()
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+#define target_terminal_ours_for_output() \
+ (*current_target->to_terminal_ours_for_output) ()
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+#define target_terminal_ours() \
+ (*current_target->to_terminal_ours) ()
+
+/* Print useful information about our terminal status, if such a thing
+ exists. */
+
+#define target_terminal_info(arg, from_tty) \
+ (*current_target->to_terminal_info) (arg, from_tty)
+
+/* Kill the inferior process. Make it go away. */
+
+#define target_kill() \
+ (*current_target->to_kill) ()
+
+/* Load an executable file into the target process. This is expected to
+ not only bring new code into the target process, but also to update
+ GDB's symbol tables to match. */
+
+#define target_load(arg, from_tty) \
+ (*current_target->to_load) (arg, from_tty)
+
+/* Look up a symbol in the target's symbol table. NAME is the symbol
+ name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol
+ should be returned. The result is 0 if successful, nonzero if the
+ symbol does not exist in the target environment. This function should
+ not call error() if communication with the target is interrupted, since
+ it is called from symbol reading, but should return nonzero, possibly
+ doing a complain(). */
+
+#define target_lookup_symbol(name, addrp) \
+ (*current_target->to_lookup_symbol) (name, addrp)
+
+/* Start an inferior process and set inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error().
+ On VxWorks and various standalone systems, we ignore exec_file. */
+
+#define target_create_inferior(exec_file, args, env) \
+ (*current_target->to_create_inferior) (exec_file, args, env)
+
+/* The inferior process has died. Do what is right. */
+
+#define target_mourn_inferior() \
+ (*current_target->to_mourn_inferior) ()
+
+/* Does target have enough data to do a run or attach command? */
+
+#define target_can_run(t) \
+ ((t)->to_can_run) ()
+
+/* post process changes to signal handling in the inferior. */
+
+#define target_notice_signals(pid) \
+ (*current_target->to_notice_signals) (pid)
+
+/* Pointer to next target in the chain, e.g. a core file and an exec file. */
+
+#define target_next \
+ (current_target->to_next)
+
+/* Does the target include all of memory, or only part of it? This
+ determines whether we look up the target chain for other parts of
+ memory if this target can't satisfy a request. */
+
+#define target_has_all_memory \
+ (current_target->to_has_all_memory)
+
+/* Does the target include memory? (Dummy targets don't.) */
+
+#define target_has_memory \
+ (current_target->to_has_memory)
+
+/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until
+ we start a process.) */
+
+#define target_has_stack \
+ (current_target->to_has_stack)
+
+/* Does the target have registers? (Exec files don't.) */
+
+#define target_has_registers \
+ (current_target->to_has_registers)
+
+/* Does the target have execution? Can we make it jump (through
+ hoops), or pop its stack a few times? FIXME: If this is to work that
+ way, it needs to check whether an inferior actually exists.
+ remote-udi.c and probably other targets can be the current target
+ when the inferior doesn't actually exist at the moment. Right now
+ this just tells us whether this target is *capable* of execution. */
+
+#define target_has_execution \
+ (current_target->to_has_execution)
+
+/* Converts a process id to a string. Usually, the string just contains
+ `process xyz', but on some systems it may contain
+ `process xyz thread abc'. */
+
+#ifndef target_pid_to_str
+#define target_pid_to_str(PID) \
+ normal_pid_to_str (PID)
+extern char *normal_pid_to_str PARAMS ((int pid));
+#endif
+
+/* Routines for maintenance of the target structures...
+
+ add_target: Add a target to the list of all possible targets.
+
+ push_target: Make this target the top of the stack of currently used
+ targets, within its particular stratum of the stack. Result
+ is 0 if now atop the stack, nonzero if not on top (maybe
+ should warn user).
+
+ unpush_target: Remove this from the stack of currently used targets,
+ no matter where it is on the list. Returns 0 if no
+ change, 1 if removed from stack.
+
+ pop_target: Remove the top thing on the stack of current targets. */
+
+extern void
+add_target PARAMS ((struct target_ops *));
+
+extern int
+push_target PARAMS ((struct target_ops *));
+
+extern int
+unpush_target PARAMS ((struct target_ops *));
+
+extern void
+target_preopen PARAMS ((int));
+
+extern void
+pop_target PARAMS ((void));
+
+/* Struct section_table maps address ranges to file sections. It is
+ mostly used with BFD files, but can be used without (e.g. for handling
+ raw disks, or files not in formats handled by BFD). */
+
+struct section_table {
+ CORE_ADDR addr; /* Lowest address in section */
+ CORE_ADDR endaddr; /* 1+highest address in section */
+ sec_ptr sec_ptr; /* BFD section pointer */
+ bfd *bfd; /* BFD file pointer */
+};
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+ Returns 0 if OK, 1 on error. */
+
+extern int
+build_section_table PARAMS ((bfd *, struct section_table **,
+ struct section_table **));
+
+/* From mem-break.c */
+
+extern int
+memory_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+
+extern int
+memory_insert_breakpoint PARAMS ((CORE_ADDR, char *));
+
+/* From target.c */
+
+void
+noprocess PARAMS ((void));
+
+void
+find_default_attach PARAMS ((char *, int));
+
+void
+find_default_create_inferior PARAMS ((char *, char *, char **));
+
+struct target_ops *
+find_core_target PARAMS ((void));
+
+#endif /* !defined (TARGET_H) */
diff --git a/gnu/usr.bin/gdb/gdb/terminal.h b/gnu/usr.bin/gdb/gdb/terminal.h
new file mode 100644
index 000000000000..f76fa9031336
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/terminal.h
@@ -0,0 +1,62 @@
+/* Terminal interface definitions for GDB, the GNU Debugger.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TERMINAL_H)
+#define TERMINAL_H 1
+
+#if !defined(__GO32__) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+ the system offers to make it look like that. FIXME: serial.h and
+ ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+ is converted to use them, can get rid of this crap. */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif /* termio or sgtty */
+
+extern void new_tty PARAMS ((void));
+
+/* Do we have job control? Can be assumed to always be the same within
+ a given run of GDB. In inflow.c. */
+extern int job_control;
+
+/* Set the process group of the caller to its own pid, or do nothing if
+ we lack job control. */
+extern int gdb_setpgid PARAMS ((void));
+
+#endif /* !defined (TERMINAL_H) */
diff --git a/gnu/usr.bin/gdb/gdb/thread.c b/gnu/usr.bin/gdb/gdb/thread.c
new file mode 100644
index 000000000000..f14b41fc041c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/thread.c
@@ -0,0 +1,248 @@
+/* Multi-process/thread control for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1993
+
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+#include "target.h"
+#include "thread.h"
+#include "command.h"
+
+#include <sys/types.h>
+#include <signal.h>
+
+/*#include "lynxos-core.h"*/
+
+struct thread_info
+{
+ struct thread_info *next;
+ int pid; /* Actual process id */
+ int num; /* Convenient handle */
+};
+
+static struct thread_info *thread_list = NULL;
+static int highest_thread_num;
+
+static void thread_command PARAMS ((char * tidstr, int from_tty));
+
+static void prune_threads PARAMS ((void));
+
+static void thread_switch PARAMS ((int pid));
+
+static struct thread_info * find_thread_id PARAMS ((int num));
+
+void
+init_thread_list ()
+{
+ struct thread_info *tp, *tpnext;
+
+ if (!thread_list)
+ return;
+
+ for (tp = thread_list; tp; tp = tpnext)
+ {
+ tpnext = tp->next;
+ free (tp);
+ }
+
+ thread_list = NULL;
+ highest_thread_num = 0;
+}
+
+void
+add_thread (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ tp = (struct thread_info *) xmalloc (sizeof (struct thread_info));
+
+ tp->pid = pid;
+ tp->num = ++highest_thread_num;
+ tp->next = thread_list;
+ thread_list = tp;
+}
+
+static struct thread_info *
+find_thread_id (num)
+ int num;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->num == num)
+ return tp;
+
+ return NULL;
+}
+
+int
+valid_thread_id (num)
+ int num;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->num == num)
+ return 1;
+
+ return 0;
+}
+
+int
+pid_to_thread_id (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == pid)
+ return tp->num;
+
+ return 0;
+}
+
+int
+in_thread_list (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == pid)
+ return 1;
+
+ return 0; /* Never heard of 'im */
+}
+
+static void
+prune_threads ()
+{
+ struct thread_info *tp, *tpprev;
+
+ tpprev = 0;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == -1)
+ {
+ if (tpprev)
+ tpprev->next = tp->next;
+ else
+ thread_list = NULL;
+
+ free (tp);
+ }
+ else
+ tpprev = tp;
+}
+
+/* Print information about currently known threads */
+
+static void
+info_threads_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct thread_info *tp;
+ int current_pid = inferior_pid;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ {
+ if (target_has_execution
+ && kill (tp->pid, 0) == -1)
+ {
+ tp->pid = -1; /* Mark it as dead */
+ continue;
+ }
+
+ if (tp->pid == current_pid)
+ printf_filtered ("* ");
+ else
+ printf_filtered (" ");
+
+ printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid));
+
+ thread_switch (tp->pid);
+ print_stack_frame (selected_frame, -1, 0);
+ }
+
+ thread_switch (current_pid);
+ prune_threads ();
+}
+
+/* Switch from one thread to another. */
+
+static void
+thread_switch (pid)
+ int pid;
+{
+ if (pid == inferior_pid)
+ return;
+
+ inferior_pid = pid;
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc();
+ set_current_frame (create_new_frame (read_fp (), stop_pc));
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ select_frame (get_current_frame (), 0);
+}
+
+static void
+thread_command (tidstr, from_tty)
+ char *tidstr;
+ int from_tty;
+{
+ int num;
+ struct thread_info *tp;
+
+ if (!tidstr)
+ error ("Please specify a thread ID. Use the \"info threads\" command to\n\
+see the IDs of currently known threads.");
+
+
+ num = atoi (tidstr);
+
+ tp = find_thread_id (num);
+
+ if (!tp)
+ error ("Thread ID %d not known. Use the \"info threads\" command to\n\
+see the IDs of currently known threads.", num);
+
+ thread_switch (tp->pid);
+
+ printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+void
+_initialize_thread ()
+{
+ add_info ("threads", info_threads_command,
+ "IDs of currently known threads.");
+ add_com ("thread", class_info, thread_command,
+ "Use this command to switch between threads.\n\
+The new thread ID must be currently known.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/thread.h b/gnu/usr.bin/gdb/gdb/thread.h
new file mode 100644
index 000000000000..2ec94fc5c5e4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/thread.h
@@ -0,0 +1,36 @@
+/* Multi-process/thread control defs for GDB, the GNU debugger.
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993
+
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef THREAD_H
+#define THREAD_H
+
+extern void init_thread_list PARAMS ((void));
+
+extern void add_thread PARAMS ((int pid));
+
+extern int in_thread_list PARAMS ((int pid));
+
+extern int pid_to_thread_id PARAMS ((int pid));
+
+extern int valid_thread_id PARAMS ((int thread));
+
+#endif /* THREAD_H */
diff --git a/gnu/usr.bin/gdb/gdb/tm-i386v.h b/gnu/usr.bin/gdb/gdb/tm-i386v.h
new file mode 100644
index 000000000000..f80f51921488
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm-i386v.h
@@ -0,0 +1,309 @@
+/* Macro definitions for i386, Unix System V.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TM_I386V_H)
+#define TM_I386V_H 1
+
+/*
+ * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ */
+
+#define TARGET_BYTE_ORDER LITTLE_ENDIAN
+
+/* turn this on when rest of gdb is ready */
+#define IEEE_FLOAT
+
+/* number of traps that happen between exec'ing the shell
+ * to run an inferior, and when we finally get to
+ * the inferior code. This is 2 on most implementations.
+ */
+#ifndef START_INFERIOR_TRAPS_EXPECTED
+#define START_INFERIOR_TRAPS_EXPECTED 4
+#endif
+
+/* Offset from address of function to start of its code.
+ Zero on most machines. */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));}
+
+extern int
+i386_skip_prologue PARAMS ((int));
+
+/* Immediately after a function call, return the saved pc.
+ Can't always go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+#define SAVED_PC_AFTER_CALL(frame) \
+ (read_memory_integer (read_register (SP_REGNUM), 4))
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Sequence of bytes for breakpoint instruction. */
+
+#define BREAKPOINT {0xcc}
+
+/* Amount PC must be decremented by after a breakpoint.
+ This is often the number of bytes in BREAKPOINT
+ but not always. */
+
+#ifndef DECR_PC_AFTER_BREAK
+#define DECR_PC_AFTER_BREAK 1
+#endif
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3)
+
+/* Return 1 if P points to an invalid floating point value.
+ LEN is the length in bytes -- not relevant on the 386. */
+
+#define INVALID_FLOAT(p, len) (0)
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* Number of machine registers */
+
+#define NUM_REGS 16
+
+/* Initializer for an array of names of registers.
+ There should be NUM_REGS strings in this initializer. */
+
+/* the order of the first 8 registers must match the compiler's
+ * numbering scheme (which is the same as the 386 scheme)
+ * also, this table must match regmap in i386-pinsn.c.
+ */
+#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \
+ "esp", "ebp", "esi", "edi", \
+ "eip", "ps", "cs", "ss", \
+ "ds", "es", "fs", "gs", \
+ }
+
+/* Register numbers of various important registers.
+ Note that some of these values are "real" register numbers,
+ and correspond to the general registers of the machine,
+ and some are "phony" register numbers which are too large
+ to be actual register numbers as far as the user is concerned
+ but do serve to get the desired values when passed to read_register. */
+
+#define FP_REGNUM 5 /* Contains address of executing stack frame */
+#define SP_REGNUM 4 /* Contains address of top of stack */
+
+#define PC_REGNUM 8
+#define PS_REGNUM 9
+
+/* Total amount of space needed to store our copies of the machine's
+ register state, the array `registers'. */
+#define REGISTER_BYTES (NUM_REGS * 4)
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+#define REGISTER_BYTE(N) ((N)*4)
+
+/* Number of bytes of storage in the actual machine representation
+ for register N. */
+
+#define REGISTER_RAW_SIZE(N) (4)
+
+/* Number of bytes of storage in the program's representation
+ for register N. */
+
+#define REGISTER_VIRTUAL_SIZE(N) (4)
+
+/* Largest value REGISTER_RAW_SIZE can have. */
+
+#define MAX_REGISTER_RAW_SIZE 4
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have. */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 4
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (0)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
+ {memcpy ((TO), (FROM), 4);}
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
+ {memcpy ((TO), (FROM), 4);}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+/* Perhaps si and di should go here, but potentially they could be
+ used for things other than address. */
+#define REGISTER_VIRTUAL_TYPE(N) \
+ ((N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM ? \
+ lookup_pointer_type (builtin_type_void) : builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+#define STORE_STRUCT_RETURN(ADDR, SP) \
+ { (SP) -= sizeof (ADDR); \
+ write_memory ((SP), (char *) &(ADDR), sizeof (ADDR)); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+ a function return value of type TYPE, and copy that, in virtual format,
+ into VALBUF. */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+ memcpy ((VALBUF), (REGBUF), TYPE_LENGTH (TYPE))
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+ write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR (or an expression that can be used as one). */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
+
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+
+/* FRAME_CHAIN takes a frame's nominal address
+ and produces the frame's chain-pointer. */
+
+#define FRAME_CHAIN(thisframe) \
+ (!inside_entry_file ((thisframe)->pc) ? \
+ read_memory_integer ((thisframe)->frame, 4) :\
+ 0)
+
+/* Define other aspects of the stack frame. */
+
+/* A macro that tells us whether the function invocation represented
+ by FI does not have a frame on the stack associated with it. If it
+ does not, FRAMELESS is set to 1, else 0. */
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+ (FRAMELESS) = frameless_look_for_prologue(FI)
+
+#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
+
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+#define FRAME_NUM_ARGS(numargs, fi) (numargs) = -1
+
+#ifdef __STDC__ /* Forward decl's for prototypes */
+struct frame_info;
+struct frame_saved_regs;
+#endif
+
+extern int
+i386_frame_num_args PARAMS ((struct frame_info *));
+
+/* Return number of bytes at start of arglist that are not really args. */
+
+#define FRAME_ARGS_SKIP 8
+
+/* Put here the code to store, into a struct frame_saved_regs,
+ the addresses of the saved registers of frame described by FRAME_INFO.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame. */
+
+#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
+{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
+
+extern void
+i386_frame_find_saved_regs PARAMS ((struct frame_info *,
+ struct frame_saved_regs *));
+
+
+/* Things needed for making the inferior call functions. */
+
+/* Push an empty stack frame, to record the current PC, etc. */
+
+#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); }
+
+extern void
+i386_push_dummy_frame PARAMS ((void));
+
+/* Discard from the stack the innermost frame, restoring all registers. */
+
+#define POP_FRAME { i386_pop_frame (); }
+
+extern void
+i386_pop_frame PARAMS ((void));
+
+/* this is
+ * call 11223344 (32 bit relative)
+ * int3
+ */
+
+#define CALL_DUMMY { 0x223344e8, 0xcc11 }
+
+#define CALL_DUMMY_LENGTH 8
+
+#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */
+
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME. */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \
+{ \
+ int from, to, delta, loc; \
+ loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \
+ from = loc + 5; \
+ to = (int)(fun); \
+ delta = to - from; \
+ *((char *)(dummyname) + 1) = (delta & 0xff); \
+ *((char *)(dummyname) + 2) = ((delta >> 8) & 0xff); \
+ *((char *)(dummyname) + 3) = ((delta >> 16) & 0xff); \
+ *((char *)(dummyname) + 4) = ((delta >> 24) & 0xff); \
+}
+
+extern void
+print_387_control_word PARAMS ((unsigned int));
+
+extern void
+print_387_status_word PARAMS ((unsigned int));
+
+/* Offset from SP to first arg on stack at first instruction of a function */
+
+#define SP_ARG0 (1 * 4)
+
+#endif /* !defined (TM_I386V_H) */
diff --git a/gnu/usr.bin/gdb/gdb/tm.h b/gnu/usr.bin/gdb/gdb/tm.h
new file mode 100644
index 000000000000..25b66c709dee
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm.h
@@ -0,0 +1,76 @@
+/* Macro definitions for i386 running under BSD Unix.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Override number of expected traps from sysv. */
+#define START_INFERIOR_TRAPS_EXPECTED 2
+
+/* Most definitions from sysv could be used. */
+#include "tm-i386v.h"
+
+/* 386BSD cannot handle the segment registers. */
+/* BSDI can't handle them either. */
+#undef NUM_REGS
+#define NUM_REGS 10
+
+/* On 386 bsd, sigtramp is above the user stack and immediately below
+ the user area. Using constants here allows for cross debugging.
+ These are tested for BSDI but should work on 386BSD. */
+#define SIGTRAMP_START 0xfdbfdfc0
+#define SIGTRAMP_END 0xfdbfe000
+
+/* The following redefines make backtracing through sigtramp work.
+ They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp
+ from the sigcontext structure which is pushed by the kernel on the
+ user stack, along with a pointer to it. */
+
+/* FRAME_CHAIN takes a frame's nominal address and produces the frame's
+ chain-pointer.
+ In the case of the i386, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+#undef FRAME_CHAIN
+#define FRAME_CHAIN(thisframe) \
+ (thisframe->signal_handler_caller \
+ ? thisframe->frame \
+ : (!inside_entry_file ((thisframe)->pc) \
+ ? read_memory_integer ((thisframe)->frame, 4) \
+ : 0))
+
+/* A macro that tells us whether the function invocation represented
+ by FI does not have a frame on the stack associated with it. If it
+ does not, FRAMELESS is set to 1, else 0. */
+#undef FRAMELESS_FUNCTION_INVOCATION
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+ do { \
+ if ((FI)->signal_handler_caller) \
+ (FRAMELESS) = 0; \
+ else \
+ (FRAMELESS) = frameless_look_for_prologue(FI); \
+ } while (0)
+
+/* Saved Pc. Get it from sigcontext if within sigtramp. */
+
+/* Offset to saved PC in sigcontext, from <sys/signal.h>. */
+#define SIGCONTEXT_PC_OFFSET 20
+
+#undef FRAME_SAVED_PC(FRAME)
+#define FRAME_SAVED_PC(FRAME) \
+ (((FRAME)->signal_handler_caller \
+ ? sigtramp_saved_pc (FRAME) \
+ : read_memory_integer ((FRAME)->frame + 4, 4)) \
+ )
diff --git a/gnu/usr.bin/gdb/gdb/typeprint.c b/gnu/usr.bin/gdb/gdb/typeprint.c
new file mode 100644
index 000000000000..5e13e07fb4d9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/typeprint.c
@@ -0,0 +1,297 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <string.h>
+#include <errno.h>
+
+static void
+ptype_command PARAMS ((char *, int));
+
+static struct type *
+ptype_eval PARAMS ((struct expression *));
+
+static void
+whatis_command PARAMS ((char *, int));
+
+static void
+whatis_exp PARAMS ((char *, int));
+
+/* Print a description of a type TYPE in the form of a declaration of a
+ variable named VARSTRING. (VARSTRING is demangled if necessary.)
+ Output goes to STREAM (via stdio).
+ If SHOW is positive, we show the contents of the outermost level
+ of structure even if there is a type name that could be used instead.
+ If SHOW is negative, we never show the details of elements' types. */
+
+void
+type_print (type, varstring, stream, show)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+{
+ LA_PRINT_TYPE (type, varstring, stream, show, 0);
+}
+
+/* Print type of EXP, or last thing in value history if EXP == NULL.
+ show is passed to type_print. */
+
+static void
+whatis_exp (exp, show)
+ char *exp;
+ int show;
+{
+ struct expression *expr;
+ register value val;
+ register struct cleanup *old_chain = NULL;
+
+ if (exp)
+ {
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ printf_filtered ("type = ");
+ type_print (VALUE_TYPE (val), "", stdout, show);
+ printf_filtered ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+whatis_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ /* Most of the time users do not want to see all the fields
+ in a structure. If they do they can use the "ptype" command.
+ Hence the "-1" below. */
+ whatis_exp (exp, -1);
+}
+
+/* Simple subroutine for ptype_command. */
+
+static struct type *
+ptype_eval (exp)
+ struct expression *exp;
+{
+ if (exp->elts[0].opcode == OP_TYPE)
+ {
+ return (exp->elts[1].type);
+ }
+ else
+ {
+ return (NULL);
+ }
+}
+
+/* TYPENAME is either the name of a type, or an expression. */
+
+/* ARGSUSED */
+static void
+ptype_command (typename, from_tty)
+ char *typename;
+ int from_tty;
+{
+ register struct type *type;
+ struct expression *expr;
+ register struct cleanup *old_chain;
+
+ if (typename == NULL)
+ {
+ /* Print type of last thing in value history. */
+ whatis_exp (typename, 1);
+ }
+ else
+ {
+ expr = parse_expression (typename);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ type = ptype_eval (expr);
+ if (type != NULL)
+ {
+ /* User did "ptype <typename>" */
+ printf_filtered ("type = ");
+ type_print (type, "", stdout, 1);
+ printf_filtered ("\n");
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ /* User did "ptype <symbolname>" */
+ do_cleanups (old_chain);
+ whatis_exp (typename, 1);
+ }
+ }
+}
+
+/* Print integral scalar data VAL, of type TYPE, onto stdio stream STREAM.
+ Used to print data from type structures in a specified type. For example,
+ array bounds may be characters or booleans in some languages, and this
+ allows the ranges to be printed in their "natural" form rather than as
+ decimal integer values.
+
+ FIXME: This is here simply because only the type printing routines
+ currently use it, and it wasn't clear if it really belonged somewhere
+ else (like printcmd.c). There are a lot of other gdb routines that do
+ something similar, but they are generally concerned with printing values
+ that come from the inferior in target byte order and target size. */
+
+void
+print_type_scalar (type, val, stream)
+ struct type *type;
+ LONGEST val;
+ FILE *stream;
+{
+ unsigned int i;
+ unsigned len;
+
+ switch (TYPE_CODE (type))
+ {
+
+ case TYPE_CODE_ENUM:
+ len = TYPE_NFIELDS (type);
+ for (i = 0; i < len; i++)
+ {
+ if (TYPE_FIELD_BITPOS (type, i) == val)
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_INT:
+ print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val);
+ break;
+
+ case TYPE_CODE_CHAR:
+ LA_PRINT_CHAR ((unsigned char) val, stream);
+ break;
+
+ case TYPE_CODE_BOOL:
+ fprintf_filtered (stream, val ? "TRUE" : "FALSE");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_METHOD:
+ case TYPE_CODE_REF:
+ error ("internal error: unhandled type in print_type_scalar");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ fflush (stream);
+}
+
+#if MAINTENANCE_CMDS
+
+/* Dump details of a type specified either directly or indirectly.
+ Uses the same sort of type lookup mechanism as ptype_command()
+ and whatis_command(). */
+
+void
+maintenance_print_type (typename, from_tty)
+ char *typename;
+ int from_tty;
+{
+ register value val;
+ register struct type *type;
+ register struct cleanup *old_chain;
+ struct expression *expr;
+
+ if (typename != NULL)
+ {
+ expr = parse_expression (typename);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ if (expr -> elts[0].opcode == OP_TYPE)
+ {
+ /* The user expression names a type directly, just use that type. */
+ type = expr -> elts[1].type;
+ }
+ else
+ {
+ /* The user expression may name a type indirectly by naming an
+ object of that type. Find that indirectly named type. */
+ val = evaluate_type (expr);
+ type = VALUE_TYPE (val);
+ }
+ if (type != NULL)
+ {
+ recursive_dump_type (type, 0);
+ }
+ do_cleanups (old_chain);
+ }
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+
+void
+_initialize_typeprint ()
+{
+
+ add_com ("ptype", class_vars, ptype_command,
+ "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\
+The selected stack frame's lexical context is used to look up the name.");
+
+ add_com ("whatis", class_vars, whatis_command,
+ "Print data type of expression EXP.");
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/typeprint.h b/gnu/usr.bin/gdb/gdb/typeprint.h
new file mode 100644
index 000000000000..e6740db7c298
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/typeprint.h
@@ -0,0 +1,21 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+void
+print_type_scalar PARAMS ((struct type *type, LONGEST, FILE *));
diff --git a/gnu/usr.bin/gdb/gdb/utils.c b/gnu/usr.bin/gdb/gdb/utils.c
new file mode 100644
index 000000000000..38010e323e6f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/utils.c
@@ -0,0 +1,1547 @@
+/* General utility routines for GDB, the GNU debugger.
+ Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#if !defined(__GO32__)
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <pwd.h>
+#endif
+#include <varargs.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "signals.h"
+#include "gdbcmd.h"
+#include "serial.h"
+#include "terminal.h" /* For job_control */
+#include "bfd.h"
+#include "target.h"
+#include "demangle.h"
+#include "expression.h"
+#include "language.h"
+
+/* Prototypes for local functions */
+
+#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK)
+#else
+
+static void
+malloc_botch PARAMS ((void));
+
+#endif /* NO_MMALLOC, etc */
+
+static void
+fatal_dump_core (); /* Can't prototype with <varargs.h> usage... */
+
+static void
+prompt_for_continue PARAMS ((void));
+
+static void
+set_width_command PARAMS ((char *, int, struct cmd_list_element *));
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero means a quit has been requested. */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now, rather
+ than waiting until QUIT is executed. Be careful in setting this;
+ code which executes with immediate_quit set has to be very careful
+ about being able to deal with being interrupted at any time. It is
+ almost always better to use QUIT; the only exception I can think of
+ is being able to quit out of a system call (using EINTR loses if
+ the SIGINT happens between the previous QUIT and the system call).
+ To immediately quit in the case in which a SIGINT happens between
+ the previous QUIT and setting immediate_quit (desirable anytime we
+ expect to block), call QUIT after setting immediate_quit. */
+
+int immediate_quit;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+ C++ form rather than raw. */
+
+int demangle = 1;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+ C++ form even in assembler language displays. If this is set, but
+ DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls. */
+
+int asm_demangle = 0;
+
+/* Nonzero means that strings with character values >0x7F should be printed
+ as octal escapes. Zero means just print the value (e.g. it's an
+ international character, and the terminal or window can cope.) */
+
+int sevenbit_strings = 0;
+
+/* String to be printed before error messages, if any. */
+
+char *error_pre_print;
+char *warning_pre_print = "\nwarning: ";
+
+/* Add a new cleanup to the cleanup_chain,
+ and return the previous chain pointer
+ to be passed later to do_cleanups or discard_cleanups.
+ Args are FUNCTION to clean up with, and ARG to pass to it. */
+
+struct cleanup *
+make_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ register struct cleanup *new
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ register struct cleanup *old_chain = cleanup_chain;
+
+ new->next = cleanup_chain;
+ new->function = function;
+ new->arg = arg;
+ cleanup_chain = new;
+
+ return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+do_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next; /* Do this first incase recursion */
+ (*ptr->function) (ptr->arg);
+ free (ptr);
+ }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+discard_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next;
+ free ((PTR)ptr);
+ }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain. */
+struct cleanup *
+save_cleanups ()
+{
+ struct cleanup *old_chain = cleanup_chain;
+
+ cleanup_chain = 0;
+ return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain. */
+void
+restore_cleanups (chain)
+ struct cleanup *chain;
+{
+ cleanup_chain = chain;
+}
+
+/* This function is useful for cleanups.
+ Do
+
+ foo = xmalloc (...);
+ old_chain = make_cleanup (free_current_contents, &foo);
+
+ to arrange to free the object thus allocated. */
+
+void
+free_current_contents (location)
+ char **location;
+{
+ free (*location);
+}
+
+/* Provide a known function that does nothing, to use as a base for
+ for a possibly long chain of cleanups. This is useful where we
+ use the cleanup chain for handling normal cleanups as well as dealing
+ with cleanups that need to be done as a result of a call to error().
+ In such cases, we may not be certain where the first cleanup is, unless
+ we have a do-nothing one to always use as the base. */
+
+/* ARGSUSED */
+void
+null_cleanup (arg)
+ char **arg;
+{
+}
+
+
+/* Provide a hook for modules wishing to print their own warning messages
+ to set up the terminal state in a compatible way, without them having
+ to import all the target_<...> macros. */
+
+void
+warning_setup ()
+{
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ fflush (stdout);
+}
+
+/* Print a warning message.
+ The first argument STRING is the warning message, used as a fprintf string,
+ and the remaining args are passed as arguments to it.
+ The primary difference between warnings and errors is that a warning
+ does not force the return to command level. */
+
+/* VARARGS */
+void
+warning (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ fflush (stdout);
+ if (warning_pre_print)
+ fprintf (stderr, warning_pre_print);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+/* Print an error message and return to command level.
+ The first argument STRING is the error message, used as a fprintf string,
+ and the remaining args are passed as arguments to it. */
+
+/* VARARGS */
+NORETURN void
+error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ fflush (stdout);
+ if (error_pre_print)
+ fprintf_filtered (stderr, error_pre_print);
+ string = va_arg (args, char *);
+ vfprintf_filtered (stderr, string, args);
+ fprintf_filtered (stderr, "\n");
+ va_end (args);
+ return_to_top_level (RETURN_ERROR);
+}
+
+/* Print an error message and exit reporting failure.
+ This is for a error that we cannot continue from.
+ The arguments are printed a la printf.
+
+ This function cannot be declared volatile (NORETURN) in an
+ ANSI environment because exit() is not declared volatile. */
+
+/* VARARGS */
+NORETURN void
+fatal (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ string = va_arg (args, char *);
+ fprintf (stderr, "\ngdb: ");
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+ exit (1);
+}
+
+/* Print an error message and exit, dumping core.
+ The arguments are printed a la printf (). */
+
+/* VARARGS */
+static void
+fatal_dump_core (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ string = va_arg (args, char *);
+ /* "internal error" is always correct, since GDB should never dump
+ core, no matter what the input. */
+ fprintf (stderr, "\ngdb internal error: ");
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ /* We should never get here, but just in case... */
+ exit (1);
+}
+
+/* The strerror() function can return NULL for errno values that are
+ out of range. Provide a "safe" version that always returns a
+ printable string. */
+
+char *
+safe_strerror (errnum)
+ int errnum;
+{
+ char *msg;
+ static char buf[32];
+
+ if ((msg = strerror (errnum)) == NULL)
+ {
+ sprintf (buf, "(undocumented errno %d)", errnum);
+ msg = buf;
+ }
+ return (msg);
+}
+
+/* The strsignal() function can return NULL for signal values that are
+ out of range. Provide a "safe" version that always returns a
+ printable string. */
+
+char *
+safe_strsignal (signo)
+ int signo;
+{
+ char *msg;
+ static char buf[32];
+
+ if ((msg = strsignal (signo)) == NULL)
+ {
+ sprintf (buf, "(undocumented signal %d)", signo);
+ msg = buf;
+ }
+ return (msg);
+}
+
+
+/* Print the system error message for errno, and also mention STRING
+ as the file name for which the error was encountered.
+ Then return to command level. */
+
+void
+perror_with_name (string)
+ char *string;
+{
+ char *err;
+ char *combined;
+
+ err = safe_strerror (errno);
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ /* I understand setting these is a matter of taste. Still, some people
+ may clear errno but not know about bfd_error. Doing this here is not
+ unreasonable. */
+ bfd_error = no_error;
+ errno = 0;
+
+ error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+ as the file name for which the error was encountered. */
+
+void
+print_sys_errmsg (string, errcode)
+ char *string;
+ int errcode;
+{
+ char *err;
+ char *combined;
+
+ err = safe_strerror (errcode);
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ fprintf (stderr, "%s.\n", combined);
+}
+
+/* Control C eventually causes this to be called, at a convenient time. */
+
+void
+quit ()
+{
+ serial_t stdout_serial = serial_fdopen (1);
+
+ target_terminal_ours ();
+ wrap_here ((char *)0); /* Force out any pending output */
+
+ SERIAL_FLUSH_OUTPUT (stdout_serial);
+
+ SERIAL_UN_FDOPEN (stdout_serial);
+
+ /* Don't use *_filtered; we don't want to prompt the user to continue. */
+ if (error_pre_print)
+ fprintf (stderr, error_pre_print);
+
+ if (job_control
+ /* If there is no terminal switching for this target, then we can't
+ possibly get screwed by the lack of job control. */
+ || current_target->to_terminal_ours == NULL)
+ fprintf (stderr, "Quit\n");
+ else
+ fprintf (stderr,
+ "Quit (expect signal SIGINT when the program is resumed)\n");
+ return_to_top_level (RETURN_QUIT);
+}
+
+
+#ifdef __GO32__
+
+/* In the absence of signals, poll keyboard for a quit.
+ Called from #define QUIT pollquit() in xm-go32.h. */
+
+void
+pollquit()
+{
+ if (kbhit ())
+ {
+ int k = getkey ();
+ if (k == 1)
+ quit_flag = 1;
+ else if (k == 2)
+ immediate_quit = 1;
+ quit ();
+ }
+}
+
+#endif
+
+/* Control C comes here */
+
+void
+request_quit (signo)
+ int signo;
+{
+ quit_flag = 1;
+
+#ifdef USG
+ /* Restore the signal handler. */
+ signal (signo, request_quit);
+#endif
+
+ if (immediate_quit)
+ quit ();
+}
+
+
+/* Memory management stuff (malloc friends). */
+
+#if defined (NO_MMALLOC)
+
+PTR
+mmalloc (md, size)
+ PTR md;
+ long size;
+{
+ return (malloc (size));
+}
+
+PTR
+mrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ long size;
+{
+ if (ptr == 0) /* Guard against old realloc's */
+ return malloc (size);
+ else
+ return realloc (ptr, size);
+}
+
+void
+mfree (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ free (ptr);
+}
+
+#endif /* NO_MMALLOC */
+
+#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK)
+
+void
+init_malloc (md)
+ PTR md;
+{
+}
+
+#else /* have mmalloc and want corruption checking */
+
+static void
+malloc_botch ()
+{
+ fatal_dump_core ("Memory corruption");
+}
+
+/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified
+ by MD, to detect memory corruption. Note that MD may be NULL to specify
+ the default heap that grows via sbrk.
+
+ Note that for freshly created regions, we must call mmcheck prior to any
+ mallocs in the region. Otherwise, any region which was allocated prior to
+ installing the checking hooks, which is later reallocated or freed, will
+ fail the checks! The mmcheck function only allows initial hooks to be
+ installed before the first mmalloc. However, anytime after we have called
+ mmcheck the first time to install the checking hooks, we can call it again
+ to update the function pointer to the memory corruption handler.
+
+ Returns zero on failure, non-zero on success. */
+
+void
+init_malloc (md)
+ PTR md;
+{
+ if (!mmcheck (md, malloc_botch))
+ {
+ warning ("internal error: failed to install memory consistency checks");
+ }
+
+ mmtrace ();
+}
+
+#endif /* Have mmalloc and want corruption checking */
+
+/* Called when a memory allocation fails, with the number of bytes of
+ memory requested in SIZE. */
+
+NORETURN void
+nomem (size)
+ long size;
+{
+ if (size > 0)
+ {
+ fatal ("virtual memory exhausted: can't allocate %ld bytes.", size);
+ }
+ else
+ {
+ fatal ("virtual memory exhausted.");
+ }
+}
+
+/* Like mmalloc but get error if no storage available, and protect against
+ the caller wanting to allocate zero bytes. Whether to return NULL for
+ a zero byte request, or translate the request into a request for one
+ byte of zero'd storage, is a religious issue. */
+
+PTR
+xmmalloc (md, size)
+ PTR md;
+ long size;
+{
+ register PTR val;
+
+ if (size == 0)
+ {
+ val = NULL;
+ }
+ else if ((val = mmalloc (md, size)) == NULL)
+ {
+ nomem (size);
+ }
+ return (val);
+}
+
+/* Like mrealloc but get error if no storage available. */
+
+PTR
+xmrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ long size;
+{
+ register PTR val;
+
+ if (ptr != NULL)
+ {
+ val = mrealloc (md, ptr, size);
+ }
+ else
+ {
+ val = mmalloc (md, size);
+ }
+ if (val == NULL)
+ {
+ nomem (size);
+ }
+ return (val);
+}
+
+/* Like malloc but get error if no storage available, and protect against
+ the caller wanting to allocate zero bytes. */
+
+PTR
+xmalloc (size)
+ long size;
+{
+ return (xmmalloc ((PTR) NULL, size));
+}
+
+/* Like mrealloc but get error if no storage available. */
+
+PTR
+xrealloc (ptr, size)
+ PTR ptr;
+ long size;
+{
+ return (xmrealloc ((PTR) NULL, ptr, size));
+}
+
+
+/* My replacement for the read system call.
+ Used like `read' but keeps going if `read' returns too soon. */
+
+int
+myread (desc, addr, len)
+ int desc;
+ char *addr;
+ int len;
+{
+ register int val;
+ int orglen = len;
+
+ while (len > 0)
+ {
+ val = read (desc, addr, len);
+ if (val < 0)
+ return val;
+ if (val == 0)
+ return orglen - len;
+ len -= val;
+ addr += val;
+ }
+ return orglen;
+}
+
+/* Make a copy of the string at PTR with SIZE characters
+ (and add a null character at the end in the copy).
+ Uses malloc to get the space. Returns the address of the copy. */
+
+char *
+savestring (ptr, size)
+ const char *ptr;
+ int size;
+{
+ register char *p = (char *) xmalloc (size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+msavestring (md, ptr, size)
+ PTR md;
+ const char *ptr;
+ int size;
+{
+ register char *p = (char *) xmmalloc (md, size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+/* The "const" is so it compiles under DGUX (which prototypes strsave
+ in <string.h>. FIXME: This should be named "xstrsave", shouldn't it?
+ Doesn't real strsave return NULL if out of memory? */
+char *
+strsave (ptr)
+ const char *ptr;
+{
+ return savestring (ptr, strlen (ptr));
+}
+
+char *
+mstrsave (md, ptr)
+ PTR md;
+ const char *ptr;
+{
+ return (msavestring (md, ptr, strlen (ptr)));
+}
+
+void
+print_spaces (n, file)
+ register int n;
+ register FILE *file;
+{
+ while (n-- > 0)
+ fputc (' ', file);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+ Takes three args which are given to printf to print the question.
+ The first, a control string, should end in "? ".
+ It should not say how to answer, because we do that. */
+
+/* VARARGS */
+int
+query (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *ctlstr;
+ register int answer;
+ register int ans2;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ while (1)
+ {
+ wrap_here (""); /* Flush any buffered output */
+ fflush (stdout);
+ va_start (args);
+ ctlstr = va_arg (args, char *);
+ vfprintf_filtered (stdout, ctlstr, args);
+ va_end (args);
+ printf_filtered ("(y or n) ");
+ fflush (stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ return 1;
+ if (answer != '\n') /* Eat rest of input line, to EOF or newline */
+ do
+ {
+ ans2 = fgetc (stdin);
+ clearerr (stdin);
+ }
+ while (ans2 != EOF && ans2 != '\n');
+ if (answer >= 'a')
+ answer -= 040;
+ if (answer == 'Y')
+ return 1;
+ if (answer == 'N')
+ return 0;
+ printf_filtered ("Please answer y or n.\n");
+ }
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ should point to the character after the \. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return 007; /* Bell (alert) char */
+ case 'b':
+ return '\b';
+ case 'e': /* Escape character */
+ return 033;
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+ {
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that this routine should only
+ be call for printing things which are independent of the language
+ of the program being debugged. */
+
+void
+gdb_printchar (c, stream, quoter)
+ register int c;
+ FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if ( c < 0x20 || /* Low control chars */
+ (c >= 0x7F && c < 0xA0) || /* DEL, High controls */
+ (sevenbit_strings && c >= 0x80)) { /* high order bit set */
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ } else {
+ if (c == '\\' || c == quoter)
+ fputs_filtered ("\\", stream);
+ fprintf_filtered (stream, "%c", c);
+ }
+}
+
+/* Number of lines per page or UINT_MAX if paging is disabled. */
+static unsigned int lines_per_page;
+/* Number of chars per line or UNIT_MAX is line folding is disabled. */
+static unsigned int chars_per_line;
+/* Current count of lines printed on this page, chars on this line. */
+static unsigned int lines_printed, chars_printed;
+
+/* Buffer and start column of buffered text, for doing smarter word-
+ wrapping. When someone calls wrap_here(), we start buffering output
+ that comes through fputs_filtered(). If we see a newline, we just
+ spit it out and forget about the wrap_here(). If we see another
+ wrap_here(), we spit it out and remember the newer one. If we see
+ the end of the line, we spit out a newline, the indent, and then
+ the buffered output. */
+
+/* Malloc'd buffer with chars_per_line+2 bytes. Contains characters which
+ are waiting to be output (they have already been counted in chars_printed).
+ When wrap_buffer[0] is null, the buffer is empty. */
+static char *wrap_buffer;
+
+/* Pointer in wrap_buffer to the next character to fill. */
+static char *wrap_pointer;
+
+/* String to indent by if the wrap occurs. Must not be NULL if wrap_column
+ is non-zero. */
+static char *wrap_indent;
+
+/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
+ is not in effect. */
+static int wrap_column;
+
+/* ARGSUSED */
+static void
+set_width_command (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (!wrap_buffer)
+ {
+ wrap_buffer = (char *) xmalloc (chars_per_line + 2);
+ wrap_buffer[0] = '\0';
+ }
+ else
+ wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2);
+ wrap_pointer = wrap_buffer; /* Start it at the beginning */
+}
+
+/* Wait, so the user can read what's on the screen. Prompt the user
+ to continue by pressing RETURN. */
+
+static void
+prompt_for_continue ()
+{
+ char *ignore;
+
+ /* We must do this *before* we call gdb_readline, else it will eventually
+ call us -- thinking that we're trying to print beyond the end of the
+ screen. */
+ reinitialize_more_filter ();
+
+ immediate_quit++;
+ /* On a real operating system, the user can quit with SIGINT.
+ But not on GO32.
+
+ 'q' is provided on all systems so users don't have to change habits
+ from system to system, and because telling them what to do in
+ the prompt is more user-friendly than expecting them to think of
+ SIGINT. */
+ ignore =
+ gdb_readline ("---Type <return> to continue, or q <return> to quit---");
+ if (ignore)
+ {
+ char *p = ignore;
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ if (p[0] == 'q')
+ request_quit (SIGINT);
+ free (ignore);
+ }
+ immediate_quit--;
+
+ /* Now we have to do this again, so that GDB will know that it doesn't
+ need to save the ---Type <return>--- line at the top of the screen. */
+ reinitialize_more_filter ();
+
+ dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
+}
+
+/* Reinitialize filter; ie. tell it to reset to original values. */
+
+void
+reinitialize_more_filter ()
+{
+ lines_printed = 0;
+ chars_printed = 0;
+}
+
+/* Indicate that if the next sequence of characters overflows the line,
+ a newline should be inserted here rather than when it hits the end.
+ If INDENT is non-null, it is a string to be printed to indent the
+ wrapped part on the next line. INDENT must remain accessible until
+ the next call to wrap_here() or until a newline is printed through
+ fputs_filtered().
+
+ If the line is already overfull, we immediately print a newline and
+ the indentation, and disable further wrapping.
+
+ If we don't know the width of lines, but we know the page height,
+ we must not wrap words, but should still keep track of newlines
+ that were explicitly printed.
+
+ INDENT should not contain tabs, as that will mess up the char count
+ on the next line. FIXME.
+
+ This routine is guaranteed to force out any output which has been
+ squirreled away in the wrap_buffer, so wrap_here ((char *)0) can be
+ used to force out output from the wrap_buffer. */
+
+void
+wrap_here(indent)
+ char *indent;
+{
+ if (wrap_buffer[0])
+ {
+ *wrap_pointer = '\0';
+ fputs (wrap_buffer, stdout);
+ }
+ wrap_pointer = wrap_buffer;
+ wrap_buffer[0] = '\0';
+ if (chars_per_line == UINT_MAX) /* No line overflow checking */
+ {
+ wrap_column = 0;
+ }
+ else if (chars_printed >= chars_per_line)
+ {
+ puts_filtered ("\n");
+ if (indent != NULL)
+ puts_filtered (indent);
+ wrap_column = 0;
+ }
+ else
+ {
+ wrap_column = chars_printed;
+ if (indent == NULL)
+ wrap_indent = "";
+ else
+ wrap_indent = indent;
+ }
+}
+
+/* Ensure that whatever gets printed next, using the filtered output
+ commands, starts at the beginning of the line. I.E. if there is
+ any pending output for the current line, flush it and start a new
+ line. Otherwise do nothing. */
+
+void
+begin_line ()
+{
+ if (chars_printed > 0)
+ {
+ puts_filtered ("\n");
+ }
+}
+
+/* Like fputs but pause after every screenful, and can wrap at points
+ other than the final character of a line.
+ Unlike fputs, fputs_filtered does not return a value.
+ It is OK for LINEBUFFER to be NULL, in which case just don't print
+ anything.
+
+ Note that a longjmp to top level may occur in this routine
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+void
+fputs_filtered (linebuffer, stream)
+ const char *linebuffer;
+ FILE *stream;
+{
+ const char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if (stream != stdout
+ || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+ {
+ fputs (linebuffer, stream);
+ return;
+ }
+
+ /* Go through and output each character. Show line extension
+ when this is necessary; prompt user for new page when this is
+ necessary. */
+
+ lineptr = linebuffer;
+ while (*lineptr)
+ {
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ while (*lineptr && *lineptr != '\n')
+ {
+ /* Print a single line. */
+ if (*lineptr == '\t')
+ {
+ if (wrap_column)
+ *wrap_pointer++ = '\t';
+ else
+ putc ('\t', stream);
+ /* Shifting right by 3 produces the number of tab stops
+ we have already passed, and then adding one and
+ shifting left 3 advances to the next tab stop. */
+ chars_printed = ((chars_printed >> 3) + 1) << 3;
+ lineptr++;
+ }
+ else
+ {
+ if (wrap_column)
+ *wrap_pointer++ = *lineptr;
+ else
+ putc (*lineptr, stream);
+ chars_printed++;
+ lineptr++;
+ }
+
+ if (chars_printed >= chars_per_line)
+ {
+ unsigned int save_chars = chars_printed;
+
+ chars_printed = 0;
+ lines_printed++;
+ /* If we aren't actually wrapping, don't output newline --
+ if chars_per_line is right, we probably just overflowed
+ anyway; if it's wrong, let us keep going. */
+ if (wrap_column)
+ putc ('\n', stream);
+
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ /* Now output indentation and wrapped string */
+ if (wrap_column)
+ {
+ fputs (wrap_indent, stream);
+ *wrap_pointer = '\0'; /* Null-terminate saved stuff */
+ fputs (wrap_buffer, stream); /* and eject it */
+ /* FIXME, this strlen is what prevents wrap_indent from
+ containing tabs. However, if we recurse to print it
+ and count its chars, we risk trouble if wrap_indent is
+ longer than (the user settable) chars_per_line.
+ Note also that this can set chars_printed > chars_per_line
+ if we are printing a long string. */
+ chars_printed = strlen (wrap_indent)
+ + (save_chars - wrap_column);
+ wrap_pointer = wrap_buffer; /* Reset buffer */
+ wrap_buffer[0] = '\0';
+ wrap_column = 0; /* And disable fancy wrap */
+ }
+ }
+ }
+
+ if (*lineptr == '\n')
+ {
+ chars_printed = 0;
+ wrap_here ((char *)0); /* Spit out chars, cancel further wraps */
+ lines_printed++;
+ putc ('\n', stream);
+ lineptr++;
+ }
+ }
+}
+
+/* Print a variable number of ARGS using format FORMAT. If this
+ information is going to put the amount written (since the last call
+ to REINITIALIZE_MORE_FILTER or the last page break) over the page size,
+ print out a pause message and do a gdb_readline to get the users
+ permision to continue.
+
+ Unlike fprintf, this function does not return a value.
+
+ We implement three variants, vfprintf (takes a vararg list and stream),
+ fprintf (takes a stream to write on), and printf (the usual).
+
+ Note that this routine has a restriction that the length of the
+ final output line must be less than 255 characters *or* it must be
+ less than twice the size of the format string. This is a very
+ arbitrary restriction, but it is an internal restriction, so I'll
+ put it in. This means that the %s format specifier is almost
+ useless; unless the caller can GUARANTEE that the string is short
+ enough, fputs_filtered should be used instead.
+
+ Note also that a longjmp to top level may occur in this routine
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+#define MIN_LINEBUF 255
+
+void
+vfprintf_filtered (stream, format, args)
+ FILE *stream;
+ char *format;
+ va_list args;
+{
+ char line_buf[MIN_LINEBUF+10];
+ char *linebuffer = line_buf;
+ int format_length;
+
+ format_length = strlen (format);
+
+ /* Reallocate buffer to a larger size if this is necessary. */
+ if (format_length * 2 > MIN_LINEBUF)
+ {
+ linebuffer = alloca (10 + format_length * 2);
+ }
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ vsprintf (linebuffer, format, args);
+
+ fputs_filtered (linebuffer, stream);
+}
+
+void
+vprintf_filtered (format, args)
+ char *format;
+ va_list args;
+{
+ vfprintf_filtered (stdout, format, args);
+}
+
+/* VARARGS */
+void
+fprintf_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ FILE *stream;
+ char *format;
+
+ va_start (args);
+ stream = va_arg (args, FILE *);
+ format = va_arg (args, char *);
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+/* Like fprintf_filtered, but prints it's result indent.
+ Called as fprintfi_filtered (spaces, stream, format, ...); */
+
+/* VARARGS */
+void
+fprintfi_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ int spaces;
+ FILE *stream;
+ char *format;
+
+ va_start (args);
+ spaces = va_arg (args, int);
+ stream = va_arg (args, FILE *);
+ format = va_arg (args, char *);
+ print_spaces_filtered (spaces, stream);
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+/* VARARGS */
+void
+printf_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *format;
+
+ va_start (args);
+ format = va_arg (args, char *);
+
+ vfprintf_filtered (stdout, format, args);
+ va_end (args);
+}
+
+/* Like printf_filtered, but prints it's result indented.
+ Called as printfi_filtered (spaces, format, ...); */
+
+/* VARARGS */
+void
+printfi_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ int spaces;
+ char *format;
+
+ va_start (args);
+ spaces = va_arg (args, int);
+ format = va_arg (args, char *);
+ print_spaces_filtered (spaces, stdout);
+ vfprintf_filtered (stdout, format, args);
+ va_end (args);
+}
+
+/* Easy -- but watch out!
+
+ This routine is *not* a replacement for puts()! puts() appends a newline.
+ This one doesn't, and had better not! */
+
+void
+puts_filtered (string)
+ char *string;
+{
+ fputs_filtered (string, stdout);
+}
+
+/* Return a pointer to N spaces and a null. The pointer is good
+ until the next call to here. */
+char *
+n_spaces (n)
+ int n;
+{
+ register char *t;
+ static char *spaces;
+ static int max_spaces;
+
+ if (n > max_spaces)
+ {
+ if (spaces)
+ free (spaces);
+ spaces = (char *) xmalloc (n+1);
+ for (t = spaces+n; t != spaces;)
+ *--t = ' ';
+ spaces[n] = '\0';
+ max_spaces = n;
+ }
+
+ return spaces + max_spaces - n;
+}
+
+/* Print N spaces. */
+void
+print_spaces_filtered (n, stream)
+ int n;
+ FILE *stream;
+{
+ fputs_filtered (n_spaces (n), stream);
+}
+
+/* C++ demangler stuff. */
+
+/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language
+ LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
+ If the name is not mangled, or the language for the name is unknown, or
+ demangling is off, the name is printed in its "raw" form. */
+
+void
+fprintf_symbol_filtered (stream, name, lang, arg_mode)
+ FILE *stream;
+ char *name;
+ enum language lang;
+ int arg_mode;
+{
+ char *demangled;
+
+ if (name != NULL)
+ {
+ /* If user wants to see raw output, no problem. */
+ if (!demangle)
+ {
+ fputs_filtered (name, stream);
+ }
+ else
+ {
+ switch (lang)
+ {
+ case language_cplus:
+ demangled = cplus_demangle (name, arg_mode);
+ break;
+ case language_chill:
+ demangled = chill_demangle (name);
+ break;
+ default:
+ demangled = NULL;
+ break;
+ }
+ fputs_filtered (demangled ? demangled : name, stream);
+ if (demangled != NULL)
+ {
+ free (demangled);
+ }
+ }
+ }
+}
+
+/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any
+ differences in whitespace. Returns 0 if they match, non-zero if they
+ don't (slightly different than strcmp()'s range of return values).
+
+ As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO".
+ This "feature" is useful when searching for matching C++ function names
+ (such as if the user types 'break FOO', where FOO is a mangled C++
+ function). */
+
+int
+strcmp_iw (string1, string2)
+ const char *string1;
+ const char *string2;
+{
+ while ((*string1 != '\0') && (*string2 != '\0'))
+ {
+ while (isspace (*string1))
+ {
+ string1++;
+ }
+ while (isspace (*string2))
+ {
+ string2++;
+ }
+ if (*string1 != *string2)
+ {
+ break;
+ }
+ if (*string1 != '\0')
+ {
+ string1++;
+ string2++;
+ }
+ }
+ return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0');
+}
+
+
+void
+_initialize_utils ()
+{
+ struct cmd_list_element *c;
+
+ c = add_set_cmd ("width", class_support, var_uinteger,
+ (char *)&chars_per_line,
+ "Set number of characters gdb thinks are in a line.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_width_command;
+
+ add_show_from_set
+ (add_set_cmd ("height", class_support,
+ var_uinteger, (char *)&lines_per_page,
+ "Set number of lines gdb thinks are in a page.", &setlist),
+ &showlist);
+
+ /* These defaults will be used if we are unable to get the correct
+ values from termcap. */
+#if defined(__GO32__)
+ lines_per_page = ScreenRows();
+ chars_per_line = ScreenCols();
+#else
+ lines_per_page = 24;
+ chars_per_line = 80;
+ /* Initialize the screen height and width from termcap. */
+ {
+ char *termtype = getenv ("TERM");
+
+ /* Positive means success, nonpositive means failure. */
+ int status;
+
+ /* 2048 is large enough for all known terminals, according to the
+ GNU termcap manual. */
+ char term_buffer[2048];
+
+ if (termtype)
+ {
+ status = tgetent (term_buffer, termtype);
+ if (status > 0)
+ {
+ int val;
+
+ val = tgetnum ("li");
+ if (val >= 0)
+ lines_per_page = val;
+ else
+ /* The number of lines per page is not mentioned
+ in the terminal description. This probably means
+ that paging is not useful (e.g. emacs shell window),
+ so disable paging. */
+ lines_per_page = UINT_MAX;
+
+ val = tgetnum ("co");
+ if (val >= 0)
+ chars_per_line = val;
+ }
+ }
+ }
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+
+ /* If there is a better way to determine the window size, use it. */
+ SIGWINCH_HANDLER ();
+#endif
+#endif
+ /* If the output is not a terminal, don't paginate it. */
+ if (!ISATTY (stdout))
+ lines_per_page = UINT_MAX;
+
+ set_width_command ((char *)NULL, 0, c);
+
+ add_show_from_set
+ (add_set_cmd ("demangle", class_support, var_boolean,
+ (char *)&demangle,
+ "Set demangling of encoded C++ names when displaying symbols.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("sevenbit-strings", class_support, var_boolean,
+ (char *)&sevenbit_strings,
+ "Set printing of 8-bit characters in strings as \\nnn.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("asm-demangle", class_support, var_boolean,
+ (char *)&asm_demangle,
+ "Set demangling of C++ names in disassembly listings.",
+ &setprintlist),
+ &showprintlist);
+}
+
+/* Machine specific function to handle SIGWINCH signal. */
+
+#ifdef SIGWINCH_HANDLER_BODY
+ SIGWINCH_HANDLER_BODY
+#endif
+
diff --git a/gnu/usr.bin/gdb/gdb/valarith.c b/gnu/usr.bin/gdb/gdb/valarith.c
new file mode 100644
index 000000000000..3711a150d28c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valarith.c
@@ -0,0 +1,969 @@
+/* Perform arithmetic and other operations on values, for GDB.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "value.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "target.h"
+#include "language.h"
+#include <string.h>
+
+/* Define whether or not the C operator '/' truncates towards zero for
+ differently signed operands (truncation direction is undefined in C). */
+
+#ifndef TRUNCATION_TOWARDS_ZERO
+#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2)
+#endif
+
+static value
+value_subscripted_rvalue PARAMS ((value, value));
+
+
+value
+value_add (arg1, arg2)
+ value arg1, arg2;
+{
+ register value valint, valptr;
+ register int len;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR)
+ &&
+ (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT))
+ /* Exactly one argument is a pointer, and one is an integer. */
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ {
+ valptr = arg1;
+ valint = arg2;
+ }
+ else
+ {
+ valptr = arg2;
+ valint = arg1;
+ }
+ len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr)));
+ if (len == 0) len = 1; /* For (void *) */
+ return value_from_longest (VALUE_TYPE (valptr),
+ value_as_long (valptr)
+ + (len * value_as_long (valint)));
+ }
+
+ return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+value
+value_sub (arg1, arg2)
+ value arg1, arg2;
+{
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ /* pointer - integer. */
+ return value_from_longest
+ (VALUE_TYPE (arg1),
+ value_as_long (arg1)
+ - (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))
+ * value_as_long (arg2)));
+ }
+ else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2))
+ {
+ /* pointer to <type x> - pointer to <type x>. */
+ return value_from_longest
+ (builtin_type_long, /* FIXME -- should be ptrdiff_t */
+ (value_as_long (arg1) - value_as_long (arg2))
+ / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))));
+ }
+ else
+ {
+ error ("\
+First argument of `-' is a pointer and second argument is neither\n\
+an integer nor a pointer of the same type.");
+ }
+ }
+
+ return value_binop (arg1, arg2, BINOP_SUB);
+}
+
+/* Return the value of ARRAY[IDX].
+ See comments in value_coerce_array() for rationale for reason for
+ doing lower bounds adjustment here rather than there.
+ FIXME: Perhaps we should validate that the index is valid and if
+ verbosity is set, warn about invalid indices (but still use them). */
+
+value
+value_subscript (array, idx)
+ value array, idx;
+{
+ int lowerbound;
+ value bound;
+ struct type *range_type;
+
+ COERCE_REF (array);
+
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY)
+ {
+ range_type = TYPE_FIELD_TYPE (VALUE_TYPE (array), 0);
+ lowerbound = TYPE_FIELD_BITPOS (range_type, 0);
+ if (lowerbound != 0)
+ {
+ bound = value_from_longest (builtin_type_int, (LONGEST) lowerbound);
+ idx = value_sub (idx, bound);
+ }
+ if (VALUE_LVAL (array) != lval_memory)
+ {
+ return value_subscripted_rvalue (array, idx);
+ }
+ }
+ return value_ind (value_add (array, idx));
+}
+
+/* Return the value of EXPR[IDX], expr an aggregate rvalue
+ (eg, a vector register). This routine used to promote floats
+ to doubles, but no longer does. */
+
+static value
+value_subscripted_rvalue (array, idx)
+ value array, idx;
+{
+ struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array));
+ int elt_size = TYPE_LENGTH (elt_type);
+ int elt_offs = elt_size * longest_to_int (value_as_long (idx));
+ value v;
+
+ if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array)))
+ error ("no such vector element");
+
+ v = allocate_value (elt_type);
+ memcpy (VALUE_CONTENTS (v), VALUE_CONTENTS (array) + elt_offs, elt_size);
+
+ if (VALUE_LVAL (array) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ else
+ VALUE_LVAL (v) = not_lval;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (array);
+ VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs;
+ VALUE_BITSIZE (v) = elt_size * 8;
+ return v;
+}
+
+/* Check to see if either argument is a structure. This is called so
+ we know whether to go ahead with the normal binop or look for a
+ user defined function instead.
+
+ For now, we do not overload the `=' operator. */
+
+int
+binop_user_defined_p (op, arg1, arg2)
+ enum exp_opcode op;
+ value arg1, arg2;
+{
+ if (op == BINOP_ASSIGN)
+ return 0;
+ return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_STRUCT
+ || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_STRUCT));
+}
+
+/* Check to see if argument is a structure. This is called so
+ we know whether to go ahead with the normal unop or look for a
+ user defined function instead.
+
+ For now, we do not overload the `&' operator. */
+
+int unop_user_defined_p (op, arg1)
+ enum exp_opcode op;
+ value arg1;
+{
+ if (op == UNOP_ADDR)
+ return 0;
+ return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+ || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT));
+}
+
+/* We know either arg1 or arg2 is a structure, so try to find the right
+ user defined function. Create an argument vector that calls
+ arg1.operator @ (arg1,arg2) and return that value (where '@' is any
+ binary operator which is legal for GNU C++).
+
+ OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP
+ is the opcode saying how to modify it. Otherwise, OTHEROP is
+ unused. */
+
+value
+value_x_binop (arg1, arg2, op, otherop)
+ value arg1, arg2;
+ enum exp_opcode op, otherop;
+{
+ value * argvec;
+ char *ptr;
+ char tstr[13];
+ int static_memfuncp;
+
+ COERCE_REF (arg1);
+ COERCE_REF (arg2);
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ /* now we know that what we have to do is construct our
+ arg vector and find the right function to call it with. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+ error ("Can't do that binary op on that type"); /* FIXME be explicit */
+
+ argvec = (value *) alloca (sizeof (value) * 4);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = arg2;
+ argvec[3] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr, "operator__");
+ ptr = tstr+8;
+ switch (op)
+ {
+ case BINOP_ADD: strcpy(ptr,"+"); break;
+ case BINOP_SUB: strcpy(ptr,"-"); break;
+ case BINOP_MUL: strcpy(ptr,"*"); break;
+ case BINOP_DIV: strcpy(ptr,"/"); break;
+ case BINOP_REM: strcpy(ptr,"%"); break;
+ case BINOP_LSH: strcpy(ptr,"<<"); break;
+ case BINOP_RSH: strcpy(ptr,">>"); break;
+ case BINOP_BITWISE_AND: strcpy(ptr,"&"); break;
+ case BINOP_BITWISE_IOR: strcpy(ptr,"|"); break;
+ case BINOP_BITWISE_XOR: strcpy(ptr,"^"); break;
+ case BINOP_LOGICAL_AND: strcpy(ptr,"&&"); break;
+ case BINOP_LOGICAL_OR: strcpy(ptr,"||"); break;
+ case BINOP_MIN: strcpy(ptr,"<?"); break;
+ case BINOP_MAX: strcpy(ptr,">?"); break;
+ case BINOP_ASSIGN: strcpy(ptr,"="); break;
+ case BINOP_ASSIGN_MODIFY:
+ switch (otherop)
+ {
+ case BINOP_ADD: strcpy(ptr,"+="); break;
+ case BINOP_SUB: strcpy(ptr,"-="); break;
+ case BINOP_MUL: strcpy(ptr,"*="); break;
+ case BINOP_DIV: strcpy(ptr,"/="); break;
+ case BINOP_REM: strcpy(ptr,"%="); break;
+ case BINOP_BITWISE_AND: strcpy(ptr,"&="); break;
+ case BINOP_BITWISE_IOR: strcpy(ptr,"|="); break;
+ case BINOP_BITWISE_XOR: strcpy(ptr,"^="); break;
+ case BINOP_MOD: /* invalid */
+ default:
+ error ("Invalid binary operation specified.");
+ }
+ break;
+ case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break;
+ case BINOP_EQUAL: strcpy(ptr,"=="); break;
+ case BINOP_NOTEQUAL: strcpy(ptr,"!="); break;
+ case BINOP_LESS: strcpy(ptr,"<"); break;
+ case BINOP_GTR: strcpy(ptr,">"); break;
+ case BINOP_GEQ: strcpy(ptr,">="); break;
+ case BINOP_LEQ: strcpy(ptr,"<="); break;
+ case BINOP_MOD: /* invalid */
+ default:
+ error ("Invalid binary operation specified.");
+ }
+ argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+ if (argvec[0])
+ {
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ argvec++;
+ }
+ return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+#ifdef lint
+ return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
+#endif
+}
+
+/* We know that arg1 is a structure, so try to find a unary user
+ defined operator that matches the operator in question.
+ Create an argument vector that calls arg1.operator @ (arg1)
+ and return that value (where '@' is (almost) any unary operator which
+ is legal for GNU C++). */
+
+value
+value_x_unop (arg1, op)
+ value arg1;
+ enum exp_opcode op;
+{
+ value * argvec;
+ char *ptr;
+ char tstr[13];
+ int static_memfuncp;
+
+ COERCE_ENUM (arg1);
+
+ /* now we know that what we have to do is construct our
+ arg vector and find the right function to call it with. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+ error ("Can't do that unary op on that type"); /* FIXME be explicit */
+
+ argvec = (value *) alloca (sizeof (value) * 3);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr,"operator__");
+ ptr = tstr+8;
+ switch (op)
+ {
+ case UNOP_PREINCREMENT: strcpy(ptr,"++"); break;
+ case UNOP_PREDECREMENT: strcpy(ptr,"++"); break;
+ case UNOP_POSTINCREMENT: strcpy(ptr,"++"); break;
+ case UNOP_POSTDECREMENT: strcpy(ptr,"++"); break;
+ case UNOP_LOGICAL_NOT: strcpy(ptr,"!"); break;
+ case UNOP_COMPLEMENT: strcpy(ptr,"~"); break;
+ case UNOP_NEG: strcpy(ptr,"-"); break;
+ default:
+ error ("Invalid binary operation specified.");
+ }
+ argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+ if (argvec[0])
+ {
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ argvec++;
+ }
+ return call_function_by_hand (argvec[0], 1 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+ return 0; /* For lint -- never reached */
+}
+
+
+/* Concatenate two values with the following conditions:
+
+ (1) Both values must be either bitstring values or character string
+ values and the resulting value consists of the concatenation of
+ ARG1 followed by ARG2.
+
+ or
+
+ One value must be an integer value and the other value must be
+ either a bitstring value or character string value, which is
+ to be repeated by the number of times specified by the integer
+ value.
+
+
+ (2) Boolean values are also allowed and are treated as bit string
+ values of length 1.
+
+ (3) Character values are also allowed and are treated as character
+ string values of length 1.
+*/
+
+value
+value_concat (arg1, arg2)
+ value arg1, arg2;
+{
+ register value inval1, inval2, outval;
+ int inval1len, inval2len;
+ int count, idx;
+ char *ptr;
+ char inchar;
+
+ /* First figure out if we are dealing with two values to be concatenated
+ or a repeat count and a value to be repeated. INVAL1 is set to the
+ first of two concatenated values, or the repeat count. INVAL2 is set
+ to the second of the two concatenated values or the value to be
+ repeated. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ inval1 = arg2;
+ inval2 = arg1;
+ }
+ else
+ {
+ inval1 = arg1;
+ inval2 = arg2;
+ }
+
+ /* Now process the input values. */
+
+ if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_INT)
+ {
+ /* We have a repeat count. Validate the second value and then
+ construct a value repeated that many times. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ count = longest_to_int (value_as_long (inval1));
+ inval2len = TYPE_LENGTH (VALUE_TYPE (inval2));
+ ptr = (char *) alloca (count * inval2len);
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ inchar = (char) unpack_long (VALUE_TYPE (inval2),
+ VALUE_CONTENTS (inval2));
+ for (idx = 0; idx < count; idx++)
+ {
+ *(ptr + idx) = inchar;
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < count; idx++)
+ {
+ memcpy (ptr + (idx * inval2len), VALUE_CONTENTS (inval2),
+ inval2len);
+ }
+ }
+ outval = value_string (ptr, count * inval2len);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BITSTRING
+ || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BOOL)
+ {
+ error ("unimplemented support for bitstring/boolean repeats");
+ }
+ else
+ {
+ error ("can't repeat values of that type");
+ }
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR)
+ {
+ /* We have two character strings to concatenate. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_STRING
+ && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_CHAR)
+ {
+ error ("Strings can only be concatenated with other strings.");
+ }
+ inval1len = TYPE_LENGTH (VALUE_TYPE (inval1));
+ inval2len = TYPE_LENGTH (VALUE_TYPE (inval2));
+ ptr = (char *) alloca (inval1len + inval2len);
+ if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR)
+ {
+ *ptr = (char) unpack_long (VALUE_TYPE (inval1), VALUE_CONTENTS (inval1));
+ }
+ else
+ {
+ memcpy (ptr, VALUE_CONTENTS (inval1), inval1len);
+ }
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ *(ptr + inval1len) =
+ (char) unpack_long (VALUE_TYPE (inval2), VALUE_CONTENTS (inval2));
+ }
+ else
+ {
+ memcpy (ptr + inval1len, VALUE_CONTENTS (inval2), inval2len);
+ }
+ outval = value_string (ptr, inval1len + inval2len);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BITSTRING
+ || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BOOL)
+ {
+ /* We have two bitstrings to concatenate. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BITSTRING
+ && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BOOL)
+ {
+ error ("Bitstrings or booleans can only be concatenated with other bitstrings or booleans.");
+ }
+ error ("unimplemented support for bitstring/boolean concatenation.");
+ }
+ else
+ {
+ /* We don't know how to concatenate these operands. */
+ error ("illegal operands for concatenation.");
+ }
+ return (outval);
+}
+
+
+/* Perform a binary operation on two operands which have reasonable
+ representations as integers or floats. This includes booleans,
+ characters, integers, or floats.
+ Does not support addition and subtraction on pointers;
+ use value_add or value_sub if you want to handle those possibilities. */
+
+value
+value_binop (arg1, arg2, op)
+ value arg1, arg2;
+ enum exp_opcode op;
+{
+ register value val;
+
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_CHAR
+ &&
+ TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_BOOL)
+ ||
+ (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_CHAR
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_BOOL))
+ error ("Argument to arithmetic operation not a number or boolean.");
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT
+ ||
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT)
+ {
+ double v1, v2, v;
+ v1 = value_as_double (arg1);
+ v2 = value_as_double (arg2);
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ default:
+ error ("Integer-only operation on floating point number.");
+ }
+
+ val = allocate_value (builtin_type_double);
+ SWAP_TARGET_AND_HOST (&v, sizeof (v));
+ *(double *) VALUE_CONTENTS_RAW (val) = v;
+ }
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_BOOL
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_BOOL)
+ {
+ LONGEST v1, v2, v;
+ v1 = value_as_long (arg1);
+ v2 = value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ default:
+ error ("Invalid operation on booleans.");
+ }
+
+ val = allocate_value (builtin_type_chill_bool);
+ store_signed_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ else
+ /* Integral operations here. */
+ /* FIXME: Also mixed integral/booleans, with result an integer. */
+ {
+ /* Should we promote to unsigned longest? */
+ if ((TYPE_UNSIGNED (VALUE_TYPE (arg1))
+ || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+ && (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)
+ || TYPE_LENGTH (VALUE_TYPE (arg2)) >= sizeof (unsigned LONGEST)))
+ {
+ unsigned LONGEST v1, v2, v;
+ v1 = (unsigned LONGEST) value_as_long (arg1);
+ v2 = (unsigned LONGEST) value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ case BINOP_REM:
+ v = v1 % v2;
+ break;
+
+ case BINOP_MOD:
+ /* Knuth 1.2.4, integer only. Note that unlike the C '%' op,
+ v1 mod 0 has a defined value, v1. */
+ /* Chill specifies that v2 must be > 0, so check for that. */
+ if (current_language -> la_language == language_chill
+ && value_as_long (arg2) <= 0)
+ {
+ error ("Second operand of MOD must be greater than zero.");
+ }
+ if (v2 == 0)
+ {
+ v = v1;
+ }
+ else
+ {
+ v = v1/v2;
+ /* Note floor(v1/v2) == v1/v2 for unsigned. */
+ v = v1 - (v2 * v);
+ }
+ break;
+
+ case BINOP_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_LOGICAL_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_LOGICAL_OR:
+ v = v1 || v2;
+ break;
+
+ case BINOP_MIN:
+ v = v1 < v2 ? v1 : v2;
+ break;
+
+ case BINOP_MAX:
+ v = v1 > v2 ? v1 : v2;
+ break;
+
+ default:
+ error ("Invalid binary operation on numbers.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST);
+ store_unsigned_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ else
+ {
+ LONGEST v1, v2, v;
+ v1 = value_as_long (arg1);
+ v2 = value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ case BINOP_REM:
+ v = v1 % v2;
+ break;
+
+ case BINOP_MOD:
+ /* Knuth 1.2.4, integer only. Note that unlike the C '%' op,
+ X mod 0 has a defined value, X. */
+ /* Chill specifies that v2 must be > 0, so check for that. */
+ if (current_language -> la_language == language_chill
+ && v2 <= 0)
+ {
+ error ("Second operand of MOD must be greater than zero.");
+ }
+ if (v2 == 0)
+ {
+ v = v1;
+ }
+ else
+ {
+ v = v1/v2;
+ /* Compute floor. */
+ if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0))
+ {
+ v--;
+ }
+ v = v1 - (v2 * v);
+ }
+ break;
+
+ case BINOP_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_LOGICAL_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_LOGICAL_OR:
+ v = v1 || v2;
+ break;
+
+ case BINOP_MIN:
+ v = v1 < v2 ? v1 : v2;
+ break;
+
+ case BINOP_MAX:
+ v = v1 > v2 ? v1 : v2;
+ break;
+
+ default:
+ error ("Invalid binary operation on numbers.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_LONGEST);
+ store_signed_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ }
+
+ return val;
+}
+
+/* Simulate the C operator ! -- return 1 if ARG1 contains zero. */
+
+int
+value_logical_not (arg1)
+ value arg1;
+{
+ register int len;
+ register char *p;
+
+ COERCE_ARRAY (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT)
+ return 0 == value_as_double (arg1);
+
+ len = TYPE_LENGTH (VALUE_TYPE (arg1));
+ p = VALUE_CONTENTS (arg1);
+
+ while (--len >= 0)
+ {
+ if (*p++)
+ break;
+ }
+
+ return len < 0;
+}
+
+/* Simulate the C operator == by returning a 1
+ iff ARG1 and ARG2 have equal contents. */
+
+int
+value_equal (arg1, arg2)
+ register value arg1, arg2;
+
+{
+ register int len;
+ register char *p1, *p2;
+ enum type_code code1;
+ enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (VALUE_TYPE (arg1));
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+ if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+ return value_as_long (arg1) == value_as_long (arg2);
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+ return value_as_double (arg1) == value_as_double (arg2);
+
+ /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
+ is bigger. */
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+ return value_as_pointer (arg1) == (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT)
+ return (CORE_ADDR) value_as_long (arg1) == value_as_pointer (arg2);
+
+ else if (code1 == code2
+ && ((len = TYPE_LENGTH (VALUE_TYPE (arg1)))
+ == TYPE_LENGTH (VALUE_TYPE (arg2))))
+ {
+ p1 = VALUE_CONTENTS (arg1);
+ p2 = VALUE_CONTENTS (arg2);
+ while (--len >= 0)
+ {
+ if (*p1++ != *p2++)
+ break;
+ }
+ return len < 0;
+ }
+ else
+ {
+ error ("Invalid type combination in equality test.");
+ return 0; /* For lint -- never reached */
+ }
+}
+
+/* Simulate the C operator < by returning 1
+ iff ARG1's contents are less than ARG2's. */
+
+int
+value_less (arg1, arg2)
+ register value arg1, arg2;
+{
+ register enum type_code code1;
+ register enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (VALUE_TYPE (arg1));
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+ if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+ {
+ if (TYPE_UNSIGNED (VALUE_TYPE (arg1))
+ || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+ return ((unsigned LONGEST) value_as_long (arg1)
+ < (unsigned LONGEST) value_as_long (arg2));
+ else
+ return value_as_long (arg1) < value_as_long (arg2);
+ }
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+ return value_as_double (arg1) < value_as_double (arg2);
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ return value_as_pointer (arg1) < value_as_pointer (arg2);
+
+ /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
+ is bigger. */
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+ return value_as_pointer (arg1) < (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT)
+ return (CORE_ADDR) value_as_long (arg1) < value_as_pointer (arg2);
+
+ else
+ {
+ error ("Invalid type combination in ordering comparison.");
+ return 0;
+ }
+}
+
+/* The unary operators - and ~. Both free the argument ARG1. */
+
+value
+value_neg (arg1)
+ register value arg1;
+{
+ register struct type *type;
+
+ COERCE_ENUM (arg1);
+
+ type = VALUE_TYPE (arg1);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return value_from_double (type, - value_as_double (arg1));
+ else if (TYPE_CODE (type) == TYPE_CODE_INT)
+ return value_from_longest (type, - value_as_long (arg1));
+ else {
+ error ("Argument to negate operation not a number.");
+ return 0; /* For lint -- never reached */
+ }
+}
+
+value
+value_complement (arg1)
+ register value arg1;
+{
+ COERCE_ENUM (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+ error ("Argument to complement operation not an integer.");
+
+ return value_from_longest (VALUE_TYPE (arg1), ~ value_as_long (arg1));
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/valops.c b/gnu/usr.bin/gdb/gdb/valops.c
new file mode 100644
index 000000000000..dc4d82a8651c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valops.c
@@ -0,0 +1,1819 @@
+/* Perform non-arithmetic operations on values, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "demangle.h"
+#include "language.h"
+
+#include <errno.h>
+
+/* Local functions. */
+
+static int
+typecmp PARAMS ((int staticp, struct type *t1[], value t2[]));
+
+static CORE_ADDR
+find_function_addr PARAMS ((value, struct type **));
+
+static CORE_ADDR
+value_push PARAMS ((CORE_ADDR, value));
+
+static CORE_ADDR
+value_arg_push PARAMS ((CORE_ADDR, value));
+
+static value
+search_struct_field PARAMS ((char *, value, int, struct type *, int));
+
+static value
+search_struct_method PARAMS ((char *, value *, value *, int, int *,
+ struct type *));
+
+static int
+check_field_in PARAMS ((struct type *, const char *));
+
+static CORE_ADDR
+allocate_space_in_inferior PARAMS ((int));
+
+
+/* Allocate NBYTES of space in the inferior using the inferior's malloc
+ and return a value that is a pointer to the allocated space. */
+
+static CORE_ADDR
+allocate_space_in_inferior (len)
+ int len;
+{
+ register value val;
+ register struct symbol *sym;
+ struct minimal_symbol *msymbol;
+ struct type *type;
+ value blocklen;
+ LONGEST maddr;
+
+ /* Find the address of malloc in the inferior. */
+
+ sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0, NULL);
+ if (sym != NULL)
+ {
+ if (SYMBOL_CLASS (sym) != LOC_BLOCK)
+ {
+ error ("\"malloc\" exists in this program but is not a function.");
+ }
+ val = value_of_variable (sym, NULL);
+ }
+ else
+ {
+ msymbol = lookup_minimal_symbol ("malloc", (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ type = lookup_pointer_type (builtin_type_char);
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+ maddr = (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol);
+ val = value_from_longest (type, maddr);
+ }
+ else
+ {
+ error ("evaluation of this expression requires the program to have a function \"malloc\".");
+ }
+ }
+
+ blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
+ val = call_function_by_hand (val, 1, &blocklen);
+ if (value_logical_not (val))
+ {
+ error ("No memory available to program.");
+ }
+ return (value_as_long (val));
+}
+
+/* Cast value ARG2 to type TYPE and return as a value.
+ More general than a C cast: accepts any two types of the same length,
+ and if ARG2 is an lvalue it can be cast into anything at all. */
+/* In C++, casts may change pointer or object representations. */
+
+value
+value_cast (type, arg2)
+ struct type *type;
+ register value arg2;
+{
+ register enum type_code code1;
+ register enum type_code code2;
+ register int scalar;
+
+ /* Coerce arrays but not enums. Enums will work as-is
+ and coercing them would cause an infinite recursion. */
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM)
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (type);
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+ scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
+ || code2 == TYPE_CODE_ENUM);
+
+ if ( code1 == TYPE_CODE_STRUCT
+ && code2 == TYPE_CODE_STRUCT
+ && TYPE_NAME (type) != 0)
+ {
+ /* Look in the type of the source to see if it contains the
+ type of the target as a superclass. If so, we'll need to
+ offset the object in addition to changing its type. */
+ value v = search_struct_field (type_name_no_tag (type),
+ arg2, 0, VALUE_TYPE (arg2), 1);
+ if (v)
+ {
+ VALUE_TYPE (v) = type;
+ return v;
+ }
+ }
+ if (code1 == TYPE_CODE_FLT && scalar)
+ return value_from_double (type, value_as_double (arg2));
+ else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM)
+ && (scalar || code2 == TYPE_CODE_PTR))
+ return value_from_longest (type, value_as_long (arg2));
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2)))
+ {
+ if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ {
+ /* Look in the type of the source to see if it contains the
+ type of the target as a superclass. If so, we'll need to
+ offset the pointer rather than just change its type. */
+ struct type *t1 = TYPE_TARGET_TYPE (type);
+ struct type *t2 = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if ( TYPE_CODE (t1) == TYPE_CODE_STRUCT
+ && TYPE_CODE (t2) == TYPE_CODE_STRUCT
+ && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */
+ {
+ value v = search_struct_field (type_name_no_tag (t1),
+ value_ind (arg2), 0, t2, 1);
+ if (v)
+ {
+ v = value_addr (v);
+ VALUE_TYPE (v) = type;
+ return v;
+ }
+ }
+ /* No superclass found, just fall through to change ptr type. */
+ }
+ VALUE_TYPE (arg2) = type;
+ return arg2;
+ }
+ else if (VALUE_LVAL (arg2) == lval_memory)
+ {
+ return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+ }
+ else if (code1 == TYPE_CODE_VOID)
+ {
+ return value_zero (builtin_type_void, not_lval);
+ }
+ else
+ {
+ error ("Invalid cast.");
+ return 0;
+ }
+}
+
+/* Create a value of type TYPE that is zero, and return it. */
+
+value
+value_zero (type, lv)
+ struct type *type;
+ enum lval_type lv;
+{
+ register value val = allocate_value (type);
+
+ memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (type));
+ VALUE_LVAL (val) = lv;
+
+ return val;
+}
+
+/* Return a value with type TYPE located at ADDR.
+
+ Call value_at only if the data needs to be fetched immediately;
+ if we can be 'lazy' and defer the fetch, perhaps indefinately, call
+ value_at_lazy instead. value_at_lazy simply records the address of
+ the data and sets the lazy-evaluation-required flag. The lazy flag
+ is tested in the VALUE_CONTENTS macro, which is used if and when
+ the contents are actually required. */
+
+value
+value_at (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value val = allocate_value (type);
+
+ read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type));
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+
+ return val;
+}
+
+/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */
+
+value
+value_at_lazy (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value val = allocate_value (type);
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+ VALUE_LAZY (val) = 1;
+
+ return val;
+}
+
+/* Called only from the VALUE_CONTENTS macro, if the current data for
+ a variable needs to be loaded into VALUE_CONTENTS(VAL). Fetches the
+ data from the user's process, and clears the lazy flag to indicate
+ that the data in the buffer is valid.
+
+ If the value is zero-length, we avoid calling read_memory, which would
+ abort. We mark the value as fetched anyway -- all 0 bytes of it.
+
+ This function returns a value because it is used in the VALUE_CONTENTS
+ macro as part of an expression, where a void would not work. The
+ value is ignored. */
+
+int
+value_fetch_lazy (val)
+ register value val;
+{
+ CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+
+ if (TYPE_LENGTH (VALUE_TYPE (val)))
+ read_memory (addr, VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)));
+ VALUE_LAZY (val) = 0;
+ return 0;
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+ Return a new value with the location of TOVAL and contents of FROMVAL. */
+
+value
+value_assign (toval, fromval)
+ register value toval, fromval;
+{
+ register struct type *type = VALUE_TYPE (toval);
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ int use_buffer = 0;
+
+ COERCE_ARRAY (fromval);
+ COERCE_REF (toval);
+
+ if (VALUE_LVAL (toval) != lval_internalvar)
+ fromval = value_cast (type, fromval);
+
+ /* If TOVAL is a special machine register requiring conversion
+ of program values to a special raw format,
+ convert FROMVAL's contents now, with result in `raw_buffer',
+ and set USE_BUFFER to the number of bytes to write. */
+
+ if (VALUE_REGNO (toval) >= 0
+ && REGISTER_CONVERTIBLE (VALUE_REGNO (toval)))
+ {
+ int regno = VALUE_REGNO (toval);
+ if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno))
+ fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval);
+ memcpy (virtual_buffer, VALUE_CONTENTS (fromval),
+ REGISTER_VIRTUAL_SIZE (regno));
+ REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer);
+ use_buffer = REGISTER_RAW_SIZE (regno);
+ }
+
+ switch (VALUE_LVAL (toval))
+ {
+ case lval_internalvar:
+ set_internalvar (VALUE_INTERNALVAR (toval), fromval);
+ break;
+
+ case lval_internalvar_component:
+ set_internalvar_component (VALUE_INTERNALVAR (toval),
+ VALUE_OFFSET (toval),
+ VALUE_BITPOS (toval),
+ VALUE_BITSIZE (toval),
+ fromval);
+ break;
+
+ case lval_memory:
+ if (VALUE_BITSIZE (toval))
+ {
+ int v; /* FIXME, this won't work for large bitfields */
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ modify_field ((char *) &v, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *)&v, sizeof v);
+ }
+ else if (use_buffer)
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, use_buffer);
+ else
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+ break;
+
+ case lval_register:
+ if (VALUE_BITSIZE (toval))
+ {
+ int v;
+
+ read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ modify_field ((char *) &v, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ }
+ else if (use_buffer)
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, use_buffer);
+ else
+ {
+ /* Do any conversion necessary when storing this type to more
+ than one register. */
+#ifdef REGISTER_CONVERT_FROM_TYPE
+ memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+ REGISTER_CONVERT_FROM_TYPE(VALUE_REGNO (toval), type, raw_buffer);
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, TYPE_LENGTH (type));
+#else
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+#endif
+ }
+ break;
+
+ case lval_reg_frame_relative:
+ {
+ /* value is stored in a series of registers in the frame
+ specified by the structure. Copy that value out, modify
+ it, and copy it back in. */
+ int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type));
+ int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval));
+ int byte_offset = VALUE_OFFSET (toval) % reg_size;
+ int reg_offset = VALUE_OFFSET (toval) / reg_size;
+ int amount_copied;
+ char *buffer = (char *) alloca (amount_to_copy);
+ int regno;
+ FRAME frame;
+
+ /* Figure out which frame this is in currently. */
+ for (frame = get_current_frame ();
+ frame && FRAME_FP (frame) != VALUE_FRAME (toval);
+ frame = get_prev_frame (frame))
+ ;
+
+ if (!frame)
+ error ("Value being assigned to is no longer active.");
+
+ amount_to_copy += (reg_size - amount_to_copy % reg_size);
+
+ /* Copy it out. */
+ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+ amount_copied = 0);
+ amount_copied < amount_to_copy;
+ amount_copied += reg_size, regno++)
+ {
+ get_saved_register (buffer + amount_copied,
+ (int *)NULL, (CORE_ADDR *)NULL,
+ frame, regno, (enum lval_type *)NULL);
+ }
+
+ /* Modify what needs to be modified. */
+ if (VALUE_BITSIZE (toval))
+ modify_field (buffer + byte_offset,
+ value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ else if (use_buffer)
+ memcpy (buffer + byte_offset, raw_buffer, use_buffer);
+ else
+ memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+
+ /* Copy it back. */
+ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+ amount_copied = 0);
+ amount_copied < amount_to_copy;
+ amount_copied += reg_size, regno++)
+ {
+ enum lval_type lval;
+ CORE_ADDR addr;
+ int optim;
+
+ /* Just find out where to put it. */
+ get_saved_register ((char *)NULL,
+ &optim, &addr, frame, regno, &lval);
+
+ if (optim)
+ error ("Attempt to assign to a value that was optimized out.");
+ if (lval == lval_memory)
+ write_memory (addr, buffer + amount_copied, reg_size);
+ else if (lval == lval_register)
+ write_register_bytes (addr, buffer + amount_copied, reg_size);
+ else
+ error ("Attempt to assign to an unmodifiable value.");
+ }
+ }
+ break;
+
+
+ default:
+ error ("Left side of = operation is not an lvalue.");
+ }
+
+ /* Return a value just like TOVAL except with the contents of FROMVAL
+ (except in the case of the type if TOVAL is an internalvar). */
+
+ if (VALUE_LVAL (toval) == lval_internalvar
+ || VALUE_LVAL (toval) == lval_internalvar_component)
+ {
+ type = VALUE_TYPE (fromval);
+ }
+
+ /* FIXME: This loses if fromval is a different size than toval, for
+ example because fromval got cast in the REGISTER_CONVERTIBLE case
+ above. */
+ val = allocate_value (type);
+ memcpy (val, toval, VALUE_CONTENTS_RAW (val) - (char *) val);
+ memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+ VALUE_TYPE (val) = type;
+
+ return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type. */
+
+value
+value_repeat (arg1, count)
+ value arg1;
+ int count;
+{
+ register value val;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Only values in memory can be extended with '@'.");
+ if (count < 1)
+ error ("Invalid number %d of repetitions.", count);
+
+ val = allocate_repeat_value (VALUE_TYPE (arg1), count);
+
+ read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1),
+ VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)) * count);
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+ return val;
+}
+
+value
+value_of_variable (var, b)
+ struct symbol *var;
+ struct block *b;
+{
+ value val;
+ FRAME fr;
+
+ if (b == NULL)
+ /* Use selected frame. */
+ fr = NULL;
+ else
+ {
+ fr = block_innermost_frame (b);
+ if (fr == NULL && symbol_read_needs_frame (var))
+ {
+ if (BLOCK_FUNCTION (b) != NULL
+ && SYMBOL_NAME (BLOCK_FUNCTION (b)) != NULL)
+ error ("No frame is currently executing in block %s.",
+ SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ else
+ error ("No frame is currently executing in specified block");
+ }
+ }
+ val = read_var_value (var, fr);
+ if (val == 0)
+ error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var));
+ return val;
+}
+
+/* Given a value which is an array, return a value which is a pointer to its
+ first element, regardless of whether or not the array has a nonzero lower
+ bound.
+
+ FIXME: A previous comment here indicated that this routine should be
+ substracting the array's lower bound. It's not clear to me that this
+ is correct. Given an array subscripting operation, it would certainly
+ work to do the adjustment here, essentially computing:
+
+ (&array[0] - (lowerbound * sizeof array[0])) + (index * sizeof array[0])
+
+ However I believe a more appropriate and logical place to account for
+ the lower bound is to do so in value_subscript, essentially computing:
+
+ (&array[0] + ((index - lowerbound) * sizeof array[0]))
+
+ As further evidence consider what would happen with operations other
+ than array subscripting, where the caller would get back a value that
+ had an address somewhere before the actual first element of the array,
+ and the information about the lower bound would be lost because of
+ the coercion to pointer type.
+ */
+
+value
+value_coerce_array (arg1)
+ value arg1;
+{
+ register struct type *type;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ /* Get type of elements. */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY)
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ else
+ /* A phony array made by value_repeat.
+ Its type is the type of the elements, not an array type. */
+ type = VALUE_TYPE (arg1);
+
+ return value_from_longest (lookup_pointer_type (type),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value which is a function, return a value which is a pointer
+ to it. */
+
+value
+value_coerce_function (arg1)
+ value arg1;
+{
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ return value_from_longest (lookup_pointer_type (VALUE_TYPE (arg1)),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Return a pointer value for the object for which ARG1 is the contents. */
+
+value
+value_addr (arg1)
+ value arg1;
+{
+ struct type *type = VALUE_TYPE (arg1);
+ if (TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ /* Copy the value, but change the type from (T&) to (T*).
+ We keep the same location information, which is efficient,
+ and allows &(&X) to get the location containing the reference. */
+ value arg2 = value_copy (arg1);
+ VALUE_TYPE (arg2) = lookup_pointer_type (TYPE_TARGET_TYPE (type));
+ return arg2;
+ }
+ if (VALUE_REPEATED (arg1)
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ return value_coerce_array (arg1);
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ return value_coerce_function (arg1);
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ return value_from_longest (lookup_pointer_type (type),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it. */
+
+value
+value_ind (arg1)
+ value arg1;
+{
+ COERCE_ARRAY (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in value_ind");
+
+ /* Allow * on an integer so we can cast it to whatever we want.
+ This returns an int, which seems like the most C-like thing
+ to do. "long long" variables are rare enough that
+ BUILTIN_TYPE_LONGEST would seem to be a mistake. */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+ return value_at (builtin_type_int,
+ (CORE_ADDR) value_as_long (arg1));
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ return value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ value_as_pointer (arg1));
+ error ("Attempt to take contents of a non-pointer value.");
+ return 0; /* For lint -- never reached */
+}
+
+/* Pushing small parts of stack frames. */
+
+/* Push one word (the size of object that a register holds). */
+
+CORE_ADDR
+push_word (sp, word)
+ CORE_ADDR sp;
+ REGISTER_TYPE word;
+{
+ register int len = sizeof (REGISTER_TYPE);
+ char buffer[MAX_REGISTER_RAW_SIZE];
+
+ store_unsigned_integer (buffer, len, word);
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, buffer, len);
+#else /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Push LEN bytes with data at BUFFER. */
+
+CORE_ADDR
+push_bytes (sp, buffer, len)
+ CORE_ADDR sp;
+ char *buffer;
+ int len;
+{
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, buffer, len);
+#else /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Push onto the stack the specified value VALUE. */
+
+static CORE_ADDR
+value_push (sp, arg)
+ register CORE_ADDR sp;
+ value arg;
+{
+ register int len = TYPE_LENGTH (VALUE_TYPE (arg));
+
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, VALUE_CONTENTS (arg), len);
+#else /* stack grows upward */
+ write_memory (sp, VALUE_CONTENTS (arg), len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Perform the standard coercions that are specified
+ for arguments to be passed to C functions. */
+
+value
+value_arg_coerce (arg)
+ value arg;
+{
+ register struct type *type;
+
+ /* FIXME: We should coerce this according to the prototype (if we have
+ one). Right now we do a little bit of this in typecmp(), but that
+ doesn't always get called. For example, if passing a ref to a function
+ without a prototype, we probably should de-reference it. Currently
+ we don't. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM)
+ arg = value_cast (builtin_type_unsigned_int, arg);
+
+#if 1 /* FIXME: This is only a temporary patch. -fnf */
+ if (VALUE_REPEATED (arg)
+ || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY)
+ arg = value_coerce_array (arg);
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC)
+ arg = value_coerce_function (arg);
+#endif
+
+ type = VALUE_TYPE (arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_INT
+ && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ return value_cast (builtin_type_int, arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double))
+ return value_cast (builtin_type_double, arg);
+
+ return arg;
+}
+
+/* Push the value ARG, first coercing it as an argument
+ to a C function. */
+
+static CORE_ADDR
+value_arg_push (sp, arg)
+ register CORE_ADDR sp;
+ value arg;
+{
+ return value_push (sp, value_arg_coerce (arg));
+}
+
+/* Determine a function's address and its return type from its value.
+ Calls error() if the function is not valid for calling. */
+
+static CORE_ADDR
+find_function_addr (function, retval_type)
+ value function;
+ struct type **retval_type;
+{
+ register struct type *ftype = VALUE_TYPE (function);
+ register enum type_code code = TYPE_CODE (ftype);
+ struct type *value_type;
+ CORE_ADDR funaddr;
+
+ /* If it's a member function, just look at the function
+ part of it. */
+
+ /* Determine address to call. */
+ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+ {
+ funaddr = VALUE_ADDRESS (function);
+ value_type = TYPE_TARGET_TYPE (ftype);
+ }
+ else if (code == TYPE_CODE_PTR)
+ {
+ funaddr = value_as_pointer (function);
+ if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC
+ || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD)
+ value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype));
+ else
+ value_type = builtin_type_int;
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ /* Handle the case of functions lacking debugging info.
+ Their values are characters since their addresses are char */
+ if (TYPE_LENGTH (ftype) == 1)
+ funaddr = value_as_pointer (value_addr (function));
+ else
+ /* Handle integer used as address of a function. */
+ funaddr = (CORE_ADDR) value_as_long (function);
+
+ value_type = builtin_type_int;
+ }
+ else
+ error ("Invalid data type for function to be called.");
+
+ *retval_type = value_type;
+ return funaddr;
+}
+
+#if defined (CALL_DUMMY)
+/* All this stuff with a dummy frame may seem unnecessarily complicated
+ (why not just save registers in GDB?). The purpose of pushing a dummy
+ frame which looks just like a real frame is so that if you call a
+ function and then hit a breakpoint (get a signal, etc), "backtrace"
+ will look right. Whether the backtrace needs to actually show the
+ stack at the time the inferior function was called is debatable, but
+ it certainly needs to not display garbage. So if you are contemplating
+ making dummy frames be different from normal frames, consider that. */
+
+/* Perform a function call in the inferior.
+ ARGS is a vector of values of arguments (NARGS of them).
+ FUNCTION is a value, the function to be called.
+ Returns a value representing what the function returned.
+ May fail to return, if a breakpoint or signal is hit
+ during the execution of the function. */
+
+value
+call_function_by_hand (function, nargs, args)
+ value function;
+ int nargs;
+ value *args;
+{
+ register CORE_ADDR sp;
+ register int i;
+ CORE_ADDR start_sp;
+ /* CALL_DUMMY is an array of words (REGISTER_TYPE), but each word
+ is in host byte order. It is switched to target byte order before calling
+ FIX_CALL_DUMMY. */
+ static REGISTER_TYPE dummy[] = CALL_DUMMY;
+ REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)];
+ CORE_ADDR old_sp;
+ struct type *value_type;
+ unsigned char struct_return;
+ CORE_ADDR struct_addr;
+ struct inferior_status inf_status;
+ struct cleanup *old_chain;
+ CORE_ADDR funaddr;
+ int using_gcc;
+ CORE_ADDR real_pc;
+
+ if (!target_has_execution)
+ noprocess();
+
+ save_inferior_status (&inf_status, 1);
+ old_chain = make_cleanup (restore_inferior_status, &inf_status);
+
+ /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
+ (and POP_FRAME for restoring them). (At least on most machines)
+ they are saved on the stack in the inferior. */
+ PUSH_DUMMY_FRAME;
+
+ old_sp = sp = read_sp ();
+
+#if 1 INNER_THAN 2 /* Stack grows down */
+ sp -= sizeof dummy;
+ start_sp = sp;
+#else /* Stack grows up */
+ start_sp = sp;
+ sp += sizeof dummy;
+#endif
+
+ funaddr = find_function_addr (function, &value_type);
+
+ {
+ struct block *b = block_for_pc (funaddr);
+ /* If compiled without -g, assume GCC. */
+ using_gcc = b == NULL || BLOCK_GCC_COMPILED (b);
+ }
+
+ /* Are we returning a value using a structure return or a normal
+ value return? */
+
+ struct_return = using_struct_return (function, funaddr, value_type,
+ using_gcc);
+
+ /* Create a call sequence customized for this function
+ and the number of arguments for it. */
+ for (i = 0; i < sizeof dummy / sizeof (REGISTER_TYPE); i++)
+ store_unsigned_integer (&dummy1[i], sizeof (REGISTER_TYPE),
+ (unsigned LONGEST)dummy[i]);
+
+#ifdef GDB_TARGET_IS_HPPA
+ real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+ value_type, using_gcc);
+#else
+ FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+ value_type, using_gcc);
+ real_pc = start_sp;
+#endif
+
+#if CALL_DUMMY_LOCATION == ON_STACK
+ write_memory (start_sp, (char *)dummy1, sizeof dummy);
+#endif /* On stack. */
+
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+ /* Convex Unix prohibits executing in the stack segment. */
+ /* Hope there is empty room at the top of the text segment. */
+ {
+ extern CORE_ADDR text_end;
+ static checked = 0;
+ if (!checked)
+ for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp)
+ if (read_memory_integer (start_sp, 1) != 0)
+ error ("text segment full -- no place to put call");
+ checked = 1;
+ sp = old_sp;
+ real_pc = text_end - sizeof dummy;
+ write_memory (real_pc, (char *)dummy1, sizeof dummy);
+ }
+#endif /* Before text_end. */
+
+#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
+ {
+ extern CORE_ADDR text_end;
+ int errcode;
+ sp = old_sp;
+ real_pc = text_end;
+ errcode = target_write_memory (real_pc, (char *)dummy1, sizeof dummy);
+ if (errcode != 0)
+ error ("Cannot write text segment -- call_function failed");
+ }
+#endif /* After text_end. */
+
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ real_pc = funaddr;
+#endif /* At entry point. */
+
+#ifdef lint
+ sp = old_sp; /* It really is used, for some ifdef's... */
+#endif
+
+#ifdef STACK_ALIGN
+ /* If stack grows down, we must leave a hole at the top. */
+ {
+ int len = 0;
+
+ /* Reserve space for the return structure to be written on the
+ stack, if necessary */
+
+ if (struct_return)
+ len += TYPE_LENGTH (value_type);
+
+ for (i = nargs - 1; i >= 0; i--)
+ len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i])));
+#ifdef CALL_DUMMY_STACK_ADJUST
+ len += CALL_DUMMY_STACK_ADJUST;
+#endif
+#if 1 INNER_THAN 2
+ sp -= STACK_ALIGN (len) - len;
+#else
+ sp += STACK_ALIGN (len) - len;
+#endif
+ }
+#endif /* STACK_ALIGN */
+
+ /* Reserve space for the return structure to be written on the
+ stack, if necessary */
+
+ if (struct_return)
+ {
+#if 1 INNER_THAN 2
+ sp -= TYPE_LENGTH (value_type);
+ struct_addr = sp;
+#else
+ struct_addr = sp;
+ sp += TYPE_LENGTH (value_type);
+#endif
+ }
+
+#if defined (REG_STRUCT_HAS_ADDR)
+ {
+ /* This is a machine like the sparc, where we need to pass a pointer
+ to the structure, not the structure itself. */
+ if (REG_STRUCT_HAS_ADDR (using_gcc))
+ for (i = nargs - 1; i >= 0; i--)
+ if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT)
+ {
+ CORE_ADDR addr;
+#if !(1 INNER_THAN 2)
+ /* The stack grows up, so the address of the thing we push
+ is the stack pointer before we push it. */
+ addr = sp;
+#endif
+ /* Push the structure. */
+ sp = value_push (sp, args[i]);
+#if 1 INNER_THAN 2
+ /* The stack grows down, so the address of the thing we push
+ is the stack pointer after we push it. */
+ addr = sp;
+#endif
+ /* The value we're going to pass is the address of the thing
+ we just pushed. */
+ args[i] = value_from_longest (lookup_pointer_type (value_type),
+ (LONGEST) addr);
+ }
+ }
+#endif /* REG_STRUCT_HAS_ADDR. */
+
+#ifdef PUSH_ARGUMENTS
+ PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr);
+#else /* !PUSH_ARGUMENTS */
+ for (i = nargs - 1; i >= 0; i--)
+ sp = value_arg_push (sp, args[i]);
+#endif /* !PUSH_ARGUMENTS */
+
+#ifdef CALL_DUMMY_STACK_ADJUST
+#if 1 INNER_THAN 2
+ sp -= CALL_DUMMY_STACK_ADJUST;
+#else
+ sp += CALL_DUMMY_STACK_ADJUST;
+#endif
+#endif /* CALL_DUMMY_STACK_ADJUST */
+
+ /* Store the address at which the structure is supposed to be
+ written. Note that this (and the code which reserved the space
+ above) assumes that gcc was used to compile this function. Since
+ it doesn't cost us anything but space and if the function is pcc
+ it will ignore this value, we will make that assumption.
+
+ Also note that on some machines (like the sparc) pcc uses a
+ convention like gcc's. */
+
+ if (struct_return)
+ STORE_STRUCT_RETURN (struct_addr, sp);
+
+ /* Write the stack pointer. This is here because the statements above
+ might fool with it. On SPARC, this write also stores the register
+ window into the right place in the new stack frame, which otherwise
+ wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */
+ write_sp (sp);
+
+ {
+ char retbuf[REGISTER_BYTES];
+ char *name;
+ struct symbol *symbol;
+
+ name = NULL;
+ symbol = find_pc_function (funaddr);
+ if (symbol)
+ {
+ name = SYMBOL_SOURCE_NAME (symbol);
+ }
+ else
+ {
+ /* Try the minimal symbols. */
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+
+ if (msymbol)
+ {
+ name = SYMBOL_SOURCE_NAME (msymbol);
+ }
+ }
+ if (name == NULL)
+ {
+ char format[80];
+ sprintf (format, "at %s", local_hex_format ());
+ name = alloca (80);
+ sprintf (name, format, (unsigned long) funaddr);
+ }
+
+ /* Execute the stack dummy routine, calling FUNCTION.
+ When it is done, discard the empty frame
+ after storing the contents of all regs into retbuf. */
+ if (run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf))
+ {
+ /* We stopped somewhere besides the call dummy. */
+
+ /* If we did the cleanups, we would print a spurious error message
+ (Unable to restore previously selected frame), would write the
+ registers from the inf_status (which is wrong), and would do other
+ wrong things (like set stop_bpstat to the wrong thing). */
+ discard_cleanups (old_chain);
+ /* Prevent memory leak. */
+ bpstat_clear (&inf_status.stop_bpstat);
+
+ /* The following error message used to say "The expression
+ which contained the function call has been discarded." It
+ is a hard concept to explain in a few words. Ideally, GDB
+ would be able to resume evaluation of the expression when
+ the function finally is done executing. Perhaps someday
+ this will be implemented (it would not be easy). */
+
+ /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+ a C++ name with arguments and stuff. */
+ error ("\
+The program being debugged stopped while in a function called from GDB.\n\
+When the function (%s) is done executing, GDB will silently\n\
+stop (instead of continuing to evaluate the expression containing\n\
+the function call).", name);
+ }
+
+ do_cleanups (old_chain);
+
+ /* Figure out the value returned by the function. */
+ return value_being_returned (value_type, retbuf, struct_return);
+ }
+}
+#else /* no CALL_DUMMY. */
+value
+call_function_by_hand (function, nargs, args)
+ value function;
+ int nargs;
+ value *args;
+{
+ error ("Cannot invoke functions on this machine.");
+}
+#endif /* no CALL_DUMMY. */
+
+
+/* Create a value for an array by allocating space in the inferior, copying
+ the data into that space, and then setting up an array value.
+
+ The array bounds are set from LOWBOUND and HIGHBOUND, and the array is
+ populated from the values passed in ELEMVEC.
+
+ The element type of the array is inherited from the type of the
+ first element, and all elements must have the same size (though we
+ don't currently enforce any restriction on their types). */
+
+value
+value_array (lowbound, highbound, elemvec)
+ int lowbound;
+ int highbound;
+ value *elemvec;
+{
+ int nelem;
+ int idx;
+ int typelength;
+ value val;
+ struct type *rangetype;
+ struct type *arraytype;
+ CORE_ADDR addr;
+
+ /* Validate that the bounds are reasonable and that each of the elements
+ have the same size. */
+
+ nelem = highbound - lowbound + 1;
+ if (nelem <= 0)
+ {
+ error ("bad array bounds (%d, %d)", lowbound, highbound);
+ }
+ typelength = TYPE_LENGTH (VALUE_TYPE (elemvec[0]));
+ for (idx = 0; idx < nelem; idx++)
+ {
+ if (TYPE_LENGTH (VALUE_TYPE (elemvec[idx])) != typelength)
+ {
+ error ("array elements must all be the same size");
+ }
+ }
+
+ /* Allocate space to store the array in the inferior, and then initialize
+ it by copying in each element. FIXME: Is it worth it to create a
+ local buffer in which to collect each value and then write all the
+ bytes in one operation? */
+
+ addr = allocate_space_in_inferior (nelem * typelength);
+ for (idx = 0; idx < nelem; idx++)
+ {
+ write_memory (addr + (idx * typelength), VALUE_CONTENTS (elemvec[idx]),
+ typelength);
+ }
+
+ /* Create the array type and set up an array value to be evaluated lazily. */
+
+ rangetype = create_range_type ((struct type *) NULL, builtin_type_int,
+ lowbound, highbound);
+ arraytype = create_array_type ((struct type *) NULL,
+ VALUE_TYPE (elemvec[0]), rangetype);
+ val = value_at_lazy (arraytype, addr);
+ return (val);
+}
+
+/* Create a value for a string constant by allocating space in the inferior,
+ copying the data into that space, and returning the address with type
+ TYPE_CODE_STRING. PTR points to the string constant data; LEN is number
+ of characters.
+ Note that string types are like array of char types with a lower bound of
+ zero and an upper bound of LEN - 1. Also note that the string may contain
+ embedded null bytes. */
+
+value
+value_string (ptr, len)
+ char *ptr;
+ int len;
+{
+ value val;
+ struct type *rangetype;
+ struct type *stringtype;
+ CORE_ADDR addr;
+
+ /* Allocate space to store the string in the inferior, and then
+ copy LEN bytes from PTR in gdb to that address in the inferior. */
+
+ addr = allocate_space_in_inferior (len);
+ write_memory (addr, ptr, len);
+
+ /* Create the string type and set up a string value to be evaluated
+ lazily. */
+
+ rangetype = create_range_type ((struct type *) NULL, builtin_type_int,
+ 0, len - 1);
+ stringtype = create_string_type ((struct type *) NULL, rangetype);
+ val = value_at_lazy (stringtype, addr);
+ return (val);
+}
+
+/* See if we can pass arguments in T2 to a function which takes arguments
+ of types T1. Both t1 and t2 are NULL-terminated vectors. If some
+ arguments need coercion of some sort, then the coerced values are written
+ into T2. Return value is 0 if the arguments could be matched, or the
+ position at which they differ if not.
+
+ STATICP is nonzero if the T1 argument list came from a
+ static member function.
+
+ For non-static member functions, we ignore the first argument,
+ which is the type of the instance variable. This is because we want
+ to handle calls with objects from derived classes. This is not
+ entirely correct: we should actually check to make sure that a
+ requested operation is type secure, shouldn't we? FIXME. */
+
+static int
+typecmp (staticp, t1, t2)
+ int staticp;
+ struct type *t1[];
+ value t2[];
+{
+ int i;
+
+ if (t2 == 0)
+ return 1;
+ if (staticp && t1 == 0)
+ return t2[1] != 0;
+ if (t1 == 0)
+ return 1;
+ if (TYPE_CODE (t1[0]) == TYPE_CODE_VOID) return 0;
+ if (t1[!staticp] == 0) return 0;
+ for (i = !staticp; t1[i] && TYPE_CODE (t1[i]) != TYPE_CODE_VOID; i++)
+ {
+ if (! t2[i])
+ return i+1;
+ if (TYPE_CODE (t1[i]) == TYPE_CODE_REF
+ /* We should be doing hairy argument matching, as below. */
+ && (TYPE_CODE (TYPE_TARGET_TYPE (t1[i]))
+ == TYPE_CODE (VALUE_TYPE (t2[i]))))
+ {
+ t2[i] = value_addr (t2[i]);
+ continue;
+ }
+
+ if (TYPE_CODE (t1[i]) == TYPE_CODE_PTR
+ && TYPE_CODE (VALUE_TYPE (t2[i])) == TYPE_CODE_ARRAY)
+ /* Array to pointer is a `trivial conversion' according to the ARM. */
+ continue;
+
+ /* We should be doing much hairier argument matching (see section 13.2
+ of the ARM), but as a quick kludge, just check for the same type
+ code. */
+ if (TYPE_CODE (t1[i]) != TYPE_CODE (VALUE_TYPE (t2[i])))
+ return i+1;
+ }
+ if (!t1[i]) return 0;
+ return t2[i] ? i+1 : 0;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+ Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+ and search in it assuming it has (class) type TYPE.
+ If found, return value, else return NULL.
+
+ If LOOKING_FOR_BASECLASS, then instead of looking for struct fields,
+ look for a baseclass named NAME. */
+
+static value
+search_struct_field (name, arg1, offset, type, looking_for_baseclass)
+ char *name;
+ register value arg1;
+ int offset;
+ register struct type *type;
+ int looking_for_baseclass;
+{
+ int i;
+
+ check_stub_type (type);
+
+ if (! looking_for_baseclass)
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ value v;
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i);
+ struct symbol *sym =
+ lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
+ if (sym == NULL)
+ error ("Internal error: could not find physical static variable named %s",
+ phys_name);
+ v = value_at (TYPE_FIELD_TYPE (type, i),
+ (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ }
+ else
+ v = value_primitive_field (arg1, offset, i, type);
+ if (v == 0)
+ error("there is no field named %s", name);
+ return v;
+ }
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ value v;
+ /* If we are looking for baseclasses, this is what we get when we
+ hit them. But it could happen that the base part's member name
+ is not yet filled in. */
+ int found_baseclass = (looking_for_baseclass
+ && TYPE_BASECLASS_NAME (type, i) != NULL
+ && STREQ (name, TYPE_BASECLASS_NAME (type, i)));
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ value v2;
+ /* Fix to use baseclass_offset instead. FIXME */
+ baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset,
+ &v2, (int *)NULL);
+ if (v2 == 0)
+ error ("virtual baseclass botch");
+ if (found_baseclass)
+ return v2;
+ v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i),
+ looking_for_baseclass);
+ }
+ else if (found_baseclass)
+ v = value_primitive_field (arg1, offset, i, type);
+ else
+ v = search_struct_field (name, arg1,
+ offset + TYPE_BASECLASS_BITPOS (type, i) / 8,
+ TYPE_BASECLASS (type, i),
+ looking_for_baseclass);
+ if (v) return v;
+ }
+ return NULL;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+ Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+ and search in it assuming it has (class) type TYPE.
+ If found, return value, else if name matched and args not return (value)-1,
+ else return NULL. */
+
+static value
+search_struct_method (name, arg1p, args, offset, static_memfuncp, type)
+ char *name;
+ register value *arg1p, *args;
+ int offset, *static_memfuncp;
+ register struct type *type;
+{
+ int i;
+ static int name_matched = 0;
+
+ check_stub_type (type);
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+ {
+ char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ name_matched = 1;
+
+ if (j > 0 && args == 0)
+ error ("cannot resolve overloaded method `%s'", name);
+ while (j >= 0)
+ {
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (type, i, j);
+ if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
+ TYPE_FN_FIELD_ARGS (f, j), args))
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ return (value)value_virtual_fn_field (arg1p, f, j, type, offset);
+ if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+ *static_memfuncp = 1;
+ return (value)value_fn_field (arg1p, f, j, type, offset);
+ }
+ j--;
+ }
+ }
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ value v;
+ int base_offset;
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ base_offset = baseclass_offset (type, i, *arg1p, offset);
+ if (base_offset == -1)
+ error ("virtual baseclass botch");
+ }
+ else
+ {
+ base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
+ }
+ v = search_struct_method (name, arg1p, args, base_offset + offset,
+ static_memfuncp, TYPE_BASECLASS (type, i));
+ if (v == (value) -1)
+ {
+ name_matched = 1;
+ }
+ else if (v)
+ {
+/* FIXME-bothner: Why is this commented out? Why is it here? */
+/* *arg1p = arg1_tmp;*/
+ return v;
+ }
+ }
+ if (name_matched) return (value) -1;
+ else return NULL;
+}
+
+/* Given *ARGP, a value of type (pointer to a)* structure/union,
+ extract the component named NAME from the ultimate target structure/union
+ and return it as a value with its appropriate type.
+ ERR is used in the error message if *ARGP's type is wrong.
+
+ C++: ARGS is a list of argument types to aid in the selection of
+ an appropriate method. Also, handle derived types.
+
+ STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location
+ where the truthvalue of whether the function that was resolved was
+ a static member function or not is stored.
+
+ ERR is an error message to be printed in case the field is not found. */
+
+value
+value_struct_elt (argp, args, name, static_memfuncp, err)
+ register value *argp, *args;
+ char *name;
+ int *static_memfuncp;
+ char *err;
+{
+ register struct type *t;
+ value v;
+
+ COERCE_ARRAY (*argp);
+
+ t = VALUE_TYPE (*argp);
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ *argp = value_ind (*argp);
+ /* Don't coerce fn pointer to fn and then back again! */
+ if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC)
+ COERCE_ARRAY (*argp);
+ t = VALUE_TYPE (*argp);
+ }
+
+ if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+ error ("not implemented: member type in value_struct_elt");
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Attempt to extract a component of a value that is not a %s.", err);
+
+ /* Assume it's not, unless we see that it is. */
+ if (static_memfuncp)
+ *static_memfuncp =0;
+
+ if (!args)
+ {
+ /* if there are no arguments ...do this... */
+
+ /* Try as a field first, because if we succeed, there
+ is less work to be done. */
+ v = search_struct_field (name, *argp, 0, t, 0);
+ if (v)
+ return v;
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ if (destructor_name_p (name, t))
+ error ("Cannot get value of destructor");
+
+ v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+ if (v == 0)
+ {
+ if (TYPE_NFN_FIELDS (t))
+ error ("There is no member or method named %s.", name);
+ else
+ error ("There is no member named %s.", name);
+ }
+ return v;
+ }
+
+ if (destructor_name_p (name, t))
+ {
+ if (!args[1])
+ {
+ /* destructors are a special case. */
+ return (value)value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0),
+ TYPE_FN_FIELDLIST_LENGTH (t, 0),
+ 0, 0);
+ }
+ else
+ {
+ error ("destructor should not have any argument");
+ }
+ }
+ else
+ v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+ if (v == (value) -1)
+ {
+ error("Argument list of %s mismatch with component in the structure.", name);
+ }
+ else if (v == 0)
+ {
+ /* See if user tried to invoke data as function. If so,
+ hand it back. If it's not callable (i.e., a pointer to function),
+ gdb should give an error. */
+ v = search_struct_field (name, *argp, 0, t, 0);
+ }
+
+ if (!v)
+ error ("Structure has no component named %s.", name);
+ return v;
+}
+
+/* C++: return 1 is NAME is a legitimate name for the destructor
+ of type TYPE. If TYPE does not have a destructor, or
+ if NAME is inappropriate for TYPE, an error is signaled. */
+int
+destructor_name_p (name, type)
+ const char *name;
+ const struct type *type;
+{
+ /* destructors are a special case. */
+
+ if (name[0] == '~')
+ {
+ char *dname = type_name_no_tag (type);
+ if (!STREQ (dname, name+1))
+ error ("name of destructor must equal name of class");
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/* Helper function for check_field: Given TYPE, a structure/union,
+ return 1 if the component named NAME from the ultimate
+ target structure/union is defined, otherwise, return 0. */
+
+static int
+check_field_in (type, name)
+ register struct type *type;
+ const char *name;
+{
+ register int i;
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+ if (t_field_name && STREQ (t_field_name, name))
+ return 1;
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, type))
+ return 1;
+
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+ {
+ if (STREQ (TYPE_FN_FIELDLIST_NAME (type, i), name))
+ return 1;
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ if (check_field_in (TYPE_BASECLASS (type, i), name))
+ return 1;
+
+ return 0;
+}
+
+
+/* C++: Given ARG1, a value of type (pointer to a)* structure/union,
+ return 1 if the component named NAME from the ultimate
+ target structure/union is defined, otherwise, return 0. */
+
+int
+check_field (arg1, name)
+ register value arg1;
+ const char *name;
+{
+ register struct type *t;
+
+ COERCE_ARRAY (arg1);
+
+ t = VALUE_TYPE (arg1);
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ t = TYPE_TARGET_TYPE (t);
+
+ if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+ error ("not implemented: member type in check_field");
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: `this' is not an aggregate");
+
+ return check_field_in (t, name);
+}
+
+/* C++: Given an aggregate type CURTYPE, and a member name NAME,
+ return the address of this member as a "pointer to member"
+ type. If INTYPE is non-null, then it will be the type
+ of the member we are looking for. This will help us resolve
+ "pointers to member functions". This function is used
+ to resolve user expressions of the form "DOMAIN::NAME". */
+
+value
+value_struct_elt_for_reference (domain, offset, curtype, name, intype)
+ struct type *domain, *curtype, *intype;
+ int offset;
+ char *name;
+{
+ register struct type *t = curtype;
+ register int i;
+ value v;
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: non-aggregate type to value_struct_elt_for_reference");
+
+ for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (t, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ if (TYPE_FIELD_STATIC (t, i))
+ {
+ char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i);
+ struct symbol *sym =
+ lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
+ if (sym == NULL)
+ error ("Internal error: could not find physical static variable named %s",
+ phys_name);
+ return value_at (SYMBOL_TYPE (sym),
+ (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ }
+ if (TYPE_FIELD_PACKED (t, i))
+ error ("pointers to bitfield members not allowed");
+
+ return value_from_longest
+ (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i),
+ domain)),
+ offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ }
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ {
+ error ("member pointers to destructors not implemented yet");
+ }
+
+ /* Perform all necessary dereferencing. */
+ while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR)
+ intype = TYPE_TARGET_TYPE (intype);
+
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (STREQ (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ if (intype == 0 && j > 1)
+ error ("non-unique member `%s' requires type instantiation", name);
+ if (intype)
+ {
+ while (j--)
+ if (TYPE_FN_FIELD_TYPE (f, j) == intype)
+ break;
+ if (j < 0)
+ error ("no member function matches that type instantiation");
+ }
+ else
+ j = 0;
+
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (t, i, j);
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ {
+ return value_from_longest
+ (lookup_reference_type
+ (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+ domain)),
+ (LONGEST) METHOD_PTR_FROM_VOFFSET
+ (TYPE_FN_FIELD_VOFFSET (f, j)));
+ }
+ else
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE, 0, NULL);
+ if (s == NULL)
+ {
+ v = 0;
+ }
+ else
+ {
+ v = read_var_value (s, 0);
+#if 0
+ VALUE_TYPE (v) = lookup_reference_type
+ (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+ domain));
+#endif
+ }
+ return v;
+ }
+ }
+ }
+ for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--)
+ {
+ value v;
+ int base_offset;
+
+ if (BASETYPE_VIA_VIRTUAL (t, i))
+ base_offset = 0;
+ else
+ base_offset = TYPE_BASECLASS_BITPOS (t, i) / 8;
+ v = value_struct_elt_for_reference (domain,
+ offset + base_offset,
+ TYPE_BASECLASS (t, i),
+ name,
+ intype);
+ if (v)
+ return v;
+ }
+ return 0;
+}
+
+/* C++: return the value of the class instance variable, if one exists.
+ Flag COMPLAIN signals an error if the request is made in an
+ inappropriate context. */
+value
+value_of_this (complain)
+ int complain;
+{
+ extern FRAME selected_frame;
+ struct symbol *func, *sym;
+ struct block *b;
+ int i;
+ static const char funny_this[] = "this";
+ value this;
+
+ if (selected_frame == 0)
+ if (complain)
+ error ("no frame selected");
+ else return 0;
+
+ func = get_frame_function (selected_frame);
+ if (!func)
+ {
+ if (complain)
+ error ("no `this' in nameless context");
+ else return 0;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ i = BLOCK_NSYMS (b);
+ if (i <= 0)
+ if (complain)
+ error ("no args, no `this'");
+ else return 0;
+
+ /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
+ symbol instead of the LOC_ARG one (if both exist). */
+ sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE);
+ if (sym == NULL)
+ {
+ if (complain)
+ error ("current stack frame not in method");
+ else
+ return NULL;
+ }
+
+ this = read_var_value (sym, selected_frame);
+ if (this == 0 && complain)
+ error ("`this' argument at unknown address");
+ return this;
+}
diff --git a/gnu/usr.bin/gdb/gdb/valprint.c b/gnu/usr.bin/gdb/gdb/valprint.c
new file mode 100644
index 000000000000..b805645a4ce2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.c
@@ -0,0 +1,1063 @@
+/* Print values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "obstack.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <errno.h>
+
+/* Prototypes for local functions */
+
+static void
+print_hex_chars PARAMS ((FILE *, unsigned char *, unsigned int));
+
+static void
+show_print PARAMS ((char *, int));
+
+static void
+set_print PARAMS ((char *, int));
+
+static void
+set_radix PARAMS ((char *, int));
+
+static void
+show_radix PARAMS ((char *, int));
+
+static void
+set_input_radix PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_input_radix_1 PARAMS ((int, unsigned));
+
+static void
+set_output_radix PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_output_radix_1 PARAMS ((int, unsigned));
+
+static void
+value_print_array_elements PARAMS ((value, FILE *, int, enum val_prettyprint));
+
+/* Maximum number of chars to print for a string pointer value or vector
+ contents, or UINT_MAX for no limit. Note that "set print elements 0"
+ stores UINT_MAX in print_max, which displays in a show command as
+ "unlimited". */
+
+unsigned int print_max;
+#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */
+
+/* Default input and output radixes, and output format letter. */
+
+unsigned input_radix = 10;
+unsigned output_radix = 10;
+int output_format = 0;
+
+/* Print repeat counts if there are more than this many repetitions of an
+ element in an array. Referenced by the low level language dependent
+ print routines. */
+
+unsigned int repeat_count_threshold = 10;
+
+int prettyprint_structs; /* Controls pretty printing of structures */
+int prettyprint_arrays; /* Controls pretty printing of arrays. */
+
+/* If nonzero, causes unions inside structures or other unions to be
+ printed. */
+
+int unionprint; /* Controls printing of nested unions. */
+
+/* If nonzero, causes machine addresses to be printed in certain contexts. */
+
+int addressprint; /* Controls printing of machine addresses */
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter, or 0 for natural format using TYPE).
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ FIXME: The data at VALADDR is in target byte order. If gdb is ever
+ enhanced to be able to debug more than the single target it was compiled
+ for (specific CPU type and thus specific target byte ordering), then
+ either the print routines are going to have to take this into account,
+ or the data is going to have to be passed into here already converted
+ to the host byte ordering, whichever is more convenient. */
+
+
+int
+val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ if (pretty == Val_pretty_default)
+ {
+ pretty = prettyprint_structs ? Val_prettyprint : Val_no_prettyprint;
+ }
+
+ QUIT;
+
+ /* Ensure that the type is complete and not just a stub. If the type is
+ only a stub and we can't find and substitute its complete type, then
+ print appropriate string and return. Typical types that my be stubs
+ are structs, unions, and C++ methods. */
+
+ check_stub_type (type);
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ fflush (stream);
+ return (0);
+ }
+
+ return (LA_VAL_PRINT (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty));
+}
+
+/* Print the value VAL in C-ish syntax on stream STREAM.
+ FORMAT is a format-letter, or 0 for print in natural format of data type.
+ If the object printed is a string pointer, returns
+ the number of string bytes printed. */
+
+int
+value_print (val, stream, format, pretty)
+ value val;
+ FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ register unsigned int n, typelen;
+
+ if (val == 0)
+ {
+ printf_filtered ("<address of value unknown>");
+ return 0;
+ }
+ if (VALUE_OPTIMIZED_OUT (val))
+ {
+ printf_filtered ("<value optimized out>");
+ return 0;
+ }
+
+ /* A "repeated" value really contains several values in a row.
+ They are made by the @ operator.
+ Print such values as if they were arrays. */
+
+ if (VALUE_REPEATED (val))
+ {
+ n = VALUE_REPETITIONS (val);
+ typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ fprintf_filtered (stream, "{");
+ /* Print arrays of characters using string syntax. */
+ if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
+ && format == 0)
+ LA_PRINT_STRING (stream, VALUE_CONTENTS (val), n, 0);
+ else
+ {
+ value_print_array_elements (val, stream, format, pretty);
+ }
+ fprintf_filtered (stream, "}");
+ return (n * typelen);
+ }
+ else
+ {
+ struct type *type = VALUE_TYPE (val);
+
+ /* If it is a pointer, indicate what it points to.
+
+ Print type also if it is a reference.
+
+ C++: if it is a member pointer, we will take care
+ of that when we print it. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR ||
+ TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ /* Hack: remove (char *) for char strings. Their
+ type is indicated by the quoted string anyway. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof(char) &&
+ TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT &&
+ !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type)))
+ {
+ /* Print nothing */
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ }
+ return (val_print (type, VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty));
+ }
+}
+
+/* Called by various <lang>_val_print routines to print TYPE_CODE_INT's */
+
+void
+val_print_type_code_int (type, valaddr, stream)
+ struct type *type;
+ char *valaddr;
+ FILE *stream;
+{
+ char *p;
+ /* Pointer to first (i.e. lowest address) nonzero character. */
+ char *first_addr;
+ unsigned int len;
+
+ if (TYPE_LENGTH (type) > sizeof (LONGEST))
+ {
+ if (TYPE_UNSIGNED (type))
+ {
+ /* First figure out whether the number in fact has zeros
+ in all its bytes more significant than least significant
+ sizeof (LONGEST) ones. */
+ len = TYPE_LENGTH (type);
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = valaddr;
+ len > sizeof (LONGEST) && p < valaddr + TYPE_LENGTH (type);
+ p++)
+#else /* Little endian. */
+ first_addr = valaddr;
+ for (p = valaddr + TYPE_LENGTH (type) - 1;
+ len > sizeof (LONGEST) && p >= valaddr;
+ p--)
+#endif /* Little endian. */
+ {
+ if (*p == 0)
+ {
+ len--;
+ }
+ else
+ {
+ break;
+ }
+ }
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ first_addr = p;
+#endif
+ if (len <= sizeof (LONGEST))
+ {
+ /* We can print it in decimal. */
+ print_longest (stream, 'u', 0,
+ unpack_long (BUILTIN_TYPE_LONGEST, first_addr));
+ }
+ else
+ {
+ /* It is big, so print it in hex. */
+ print_hex_chars (stream, (unsigned char *) first_addr, len);
+ }
+ }
+ else
+ {
+ /* Signed. One could assume two's complement (a reasonable
+ assumption, I think) and do better than this. */
+ print_hex_chars (stream, (unsigned char *) valaddr,
+ TYPE_LENGTH (type));
+ }
+ }
+ else
+ {
+#ifdef PRINT_TYPELESS_INTEGER
+ PRINT_TYPELESS_INTEGER (stream, type, unpack_long (type, valaddr));
+#else
+ print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0,
+ unpack_long (type, valaddr));
+#endif
+ }
+}
+
+/* Print a number according to FORMAT which is one of d,u,x,o,b,h,w,g.
+ The raison d'etre of this function is to consolidate printing of LONG_LONG's
+ into this one function. Some platforms have long longs but don't have a
+ printf() that supports "ll" in the format string. We handle these by seeing
+ if the number is actually a long, and if not we just bail out and print the
+ number in hex. The format chars b,h,w,g are from
+ print_scalar_formatted(). USE_LOCAL says whether or not to call the
+ local formatting routine to get the format. */
+
+void
+print_longest (stream, format, use_local, val_long)
+ FILE *stream;
+ int format;
+ int use_local;
+ LONGEST val_long;
+{
+#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG)
+ long vtop, vbot;
+
+ vtop = val_long >> (sizeof (long) * HOST_CHAR_BIT);
+ vbot = (long) val_long;
+
+ if ((format == 'd' && (val_long < INT_MIN || val_long > INT_MAX))
+ || ((format == 'u' || format == 'x') && val_long > UINT_MAX))
+ {
+ fprintf_filtered (stream, "0x%lx%08lx", vtop, vbot);
+ return;
+ }
+#endif
+
+#ifdef PRINTF_HAS_LONG_LONG
+ switch (format)
+ {
+ case 'd':
+ fprintf_filtered (stream,
+ use_local ? local_decimal_format_custom ("ll")
+ : "%lld",
+ val_long);
+ break;
+ case 'u':
+ fprintf_filtered (stream, "%llu", val_long);
+ break;
+ case 'x':
+ fprintf_filtered (stream,
+ use_local ? local_hex_format_custom ("ll")
+ : "%llx",
+ val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("ll")
+ : "%llo",
+ break;
+ case 'b':
+ fprintf_filtered (stream, local_hex_format_custom ("02ll"), val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, local_hex_format_custom ("04ll"), val_long);
+ break;
+ case 'w':
+ fprintf_filtered (stream, local_hex_format_custom ("08ll"), val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, local_hex_format_custom ("016ll"), val_long);
+ break;
+ default:
+ abort ();
+ }
+#else /* !PRINTF_HAS_LONG_LONG */
+ /* In the following it is important to coerce (val_long) to a long. It does
+ nothing if !LONG_LONG, but it will chop off the top half (which we know
+ we can ignore) if the host supports long longs. */
+
+ switch (format)
+ {
+ case 'd':
+ fprintf_filtered (stream,
+ use_local ? local_decimal_format_custom ("l")
+ : "%ld",
+ (long) val_long);
+ break;
+ case 'u':
+ fprintf_filtered (stream, "%lu", (unsigned long) val_long);
+ break;
+ case 'x':
+ fprintf_filtered (stream,
+ use_local ? local_hex_format_custom ("l")
+ : "%lx",
+ (long) val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("l")
+ : "%lo",
+ (long) val_long);
+ break;
+ case 'b':
+ fprintf_filtered (stream, local_hex_format_custom ("02l"),
+ (long) val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, local_hex_format_custom ("04l"),
+ (long) val_long);
+ break;
+ case 'w':
+ fprintf_filtered (stream, local_hex_format_custom ("08l"),
+ (long) val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, local_hex_format_custom ("016l"),
+ (long) val_long);
+ break;
+ default:
+ abort ();
+ }
+#endif /* !PRINTF_HAS_LONG_LONG */
+}
+
+/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR,
+ on STREAM. */
+
+void
+print_floating (valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ FILE *stream;
+{
+ double doub;
+ int inv;
+ unsigned len = TYPE_LENGTH (type);
+
+#if defined (IEEE_FLOAT)
+
+ /* Check for NaN's. Note that this code does not depend on us being
+ on an IEEE conforming system. It only depends on the target
+ machine using IEEE representation. This means (a)
+ cross-debugging works right, and (2) IEEE_FLOAT can (and should)
+ be defined for systems like the 68881, which uses IEEE
+ representation, but is not IEEE conforming. */
+
+ {
+ long low, high;
+ /* Is the sign bit 0? */
+ int nonnegative;
+ /* Is it is a NaN (i.e. the exponent is all ones and
+ the fraction is nonzero)? */
+ int is_nan;
+
+ if (len == sizeof (float))
+ {
+ /* It's single precision. */
+ memcpy ((char *) &low, valaddr, sizeof (low));
+ /* target -> host. */
+ SWAP_TARGET_AND_HOST (&low, sizeof (float));
+ nonnegative = low >= 0;
+ is_nan = ((((low >> 23) & 0xFF) == 0xFF)
+ && 0 != (low & 0x7FFFFF));
+ low &= 0x7fffff;
+ high = 0;
+ }
+ else
+ {
+ /* It's double precision. Get the high and low words. */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ memcpy (&low, valaddr+4, sizeof (low));
+ memcpy (&high, valaddr+0, sizeof (high));
+#else
+ memcpy (&low, valaddr+0, sizeof (low));
+ memcpy (&high, valaddr+4, sizeof (high));
+#endif
+ SWAP_TARGET_AND_HOST (&low, sizeof (low));
+ SWAP_TARGET_AND_HOST (&high, sizeof (high));
+ nonnegative = high >= 0;
+ is_nan = (((high >> 20) & 0x7ff) == 0x7ff
+ && ! ((((high & 0xfffff) == 0)) && (low == 0)));
+ high &= 0xfffff;
+ }
+
+ if (is_nan)
+ {
+ /* The meaning of the sign and fraction is not defined by IEEE.
+ But the user might know what they mean. For example, they
+ (in an implementation-defined manner) distinguish between
+ signaling and quiet NaN's. */
+ if (high)
+ fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonnegative,
+ high, low);
+ else
+ fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low);
+ return;
+ }
+ }
+#endif /* IEEE_FLOAT. */
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf_filtered (stream, "<invalid float value>");
+ else
+ fprintf_filtered (stream, len <= sizeof(float) ? "%.9g" : "%.17g", doub);
+}
+
+/* VALADDR points to an integer of LEN bytes. Print it in hex on stream. */
+
+static void
+print_hex_chars (stream, valaddr, len)
+ FILE *stream;
+ unsigned char *valaddr;
+ unsigned len;
+{
+ unsigned char *p;
+
+ /* FIXME: We should be not printing leading zeroes in most cases. */
+
+ fprintf_filtered (stream, local_hex_format_prefix ());
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = valaddr;
+ p < valaddr + len;
+ p++)
+#else /* Little endian. */
+ for (p = valaddr + len - 1;
+ p >= valaddr;
+ p--)
+#endif
+ {
+ fprintf_filtered (stream, "%02x", *p);
+ }
+ fprintf_filtered (stream, local_hex_format_suffix ());
+}
+
+/* Called by various <lang>_val_print routines to print elements of an
+ array in the form "<elem1>, <elem2>, <elem3>, ...".
+
+ (FIXME?) Assumes array element separator is a comma, which is correct
+ for all languages currently handled.
+ (FIXME?) Some languages have a notation for repeated array elements,
+ perhaps we should try to use that notation when appropriate.
+ */
+
+void
+val_print_array_elements (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty, i)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+ unsigned int i;
+{
+ unsigned int things_printed = 0;
+ unsigned len;
+ struct type *elttype;
+ unsigned eltlen;
+ /* Position of the array element we are examining to see
+ whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+
+ for (; i < len && things_printed < print_max; i++)
+ {
+ if (i != 0)
+ {
+ if (prettyprint_arrays)
+ {
+ fprintf_filtered (stream, ",\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ }
+ wrap_here (n_spaces (2 + 2 * recurse));
+
+ rep1 = i + 1;
+ reps = 1;
+ while ((rep1 < len) &&
+ !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen))
+ {
+ ++reps;
+ ++rep1;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ things_printed++;
+ }
+ }
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+static void
+value_print_array_elements (val, stream, format, pretty)
+ value val;
+ FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ unsigned int things_printed = 0;
+ register unsigned int i, n, typelen;
+ /* Position of the array elem we are examining to see if it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ n = VALUE_REPETITIONS (val);
+ typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ for (i = 0; i < n && things_printed < print_max; i++)
+ {
+ if (i != 0)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ wrap_here ("");
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < n && !memcmp (VALUE_CONTENTS (val) + typelen * i,
+ VALUE_CONTENTS (val) + typelen * rep1,
+ typelen))
+ {
+ ++reps;
+ ++rep1;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i,
+ VALUE_ADDRESS (val) + typelen * i, stream, format, 1,
+ 0, pretty);
+ fprintf (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i,
+ VALUE_ADDRESS (val) + typelen * i, stream, format, 1,
+ 0, pretty);
+ things_printed++;
+ }
+ }
+ if (i < n)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+/* Print a string from the inferior, starting at ADDR and printing up to LEN
+ characters, to STREAM. If LEN is zero, printing stops at the first null
+ byte, otherwise printing proceeds (including null bytes) until either
+ print_max or LEN characters have been printed, whichever is smaller. */
+
+int
+val_print_string (addr, len, stream)
+ CORE_ADDR addr;
+ unsigned int len;
+ FILE *stream;
+{
+ int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */
+ int errcode; /* Errno returned from bad reads. */
+ unsigned int fetchlimit; /* Maximum number of bytes to fetch. */
+ unsigned int nfetch; /* Bytes to fetch / bytes fetched. */
+ unsigned int chunksize; /* Size of each fetch, in bytes. */
+ int bufsize; /* Size of current fetch buffer. */
+ char *buffer = NULL; /* Dynamically growable fetch buffer. */
+ char *bufptr; /* Pointer to next available byte in buffer. */
+ char *limit; /* First location past end of fetch buffer. */
+ struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */
+ char peekchar; /* Place into which we can read one char. */
+
+ /* First we need to figure out the limit on the number of characters we are
+ going to attempt to fetch and print. This is actually pretty simple. If
+ LEN is nonzero, then the limit is the minimum of LEN and print_max. If
+ LEN is zero, then the limit is print_max. This is true regardless of
+ whether print_max is zero, UINT_MAX (unlimited), or something in between,
+ because finding the null byte (or available memory) is what actually
+ limits the fetch. */
+
+ fetchlimit = (len == 0 ? print_max : min (len, print_max));
+
+ /* Now decide how large of chunks to try to read in one operation. This
+ is also pretty simple. If LEN is nonzero, then we want fetchlimit bytes,
+ so we might as well read them all in one operation. If LEN is zero, we
+ are looking for a null terminator to end the fetching, so we might as
+ well read in blocks that are large enough to be efficient, but not so
+ large as to be slow if fetchlimit happens to be large. So we choose the
+ minimum of DEFAULT_PRINT_MAX and fetchlimit. */
+
+ chunksize = (len == 0 ? min (PRINT_MAX_DEFAULT, fetchlimit) : fetchlimit);
+
+ /* Loop until we either have all the characters to print, or we encounter
+ some error, such as bumping into the end of the address space. */
+
+ bufsize = 0;
+ do {
+ QUIT;
+ /* Figure out how much to fetch this time, and grow the buffer to fit. */
+ nfetch = min (chunksize, fetchlimit - bufsize);
+ bufsize += nfetch;
+ if (buffer == NULL)
+ {
+ buffer = (char *) xmalloc (bufsize);
+ bufptr = buffer;
+ }
+ else
+ {
+ discard_cleanups (old_chain);
+ buffer = (char *) xrealloc (buffer, bufsize);
+ bufptr = buffer + bufsize - nfetch;
+ }
+ old_chain = make_cleanup (free, buffer);
+
+ /* Read as much as we can. */
+ nfetch = target_read_memory_partial (addr, bufptr, nfetch, &errcode);
+ if (len != 0)
+ {
+ addr += nfetch;
+ bufptr += nfetch;
+ }
+ else
+ {
+ /* Scan this chunk for the null byte that terminates the string
+ to print. If found, we don't need to fetch any more. Note
+ that bufptr is explicitly left pointing at the next character
+ after the null byte, or at the next character after the end of
+ the buffer. */
+ limit = bufptr + nfetch;
+ do {
+ addr++;
+ bufptr++;
+ } while (bufptr < limit && *(bufptr - 1) != '\0');
+ }
+ } while (errcode == 0 /* no error */
+ && bufptr < buffer + fetchlimit /* no overrun */
+ && !(len == 0 && *(bufptr - 1) == '\0')); /* no null term */
+
+ /* We now have either successfully filled the buffer to fetchlimit, or
+ terminated early due to an error or finding a null byte when LEN is
+ zero. */
+
+ if (len == 0 && *(bufptr - 1) != '\0')
+ {
+ /* We didn't find a null terminator we were looking for. Attempt
+ to peek at the next character. If not successful, or it is not
+ a null byte, then force ellipsis to be printed. */
+ if (target_read_memory (addr, &peekchar, 1) != 0 || peekchar != '\0')
+ {
+ force_ellipsis = 1;
+ }
+ }
+ else if ((len != 0 && errcode != 0) || (len > bufptr - buffer))
+ {
+ /* Getting an error when we have a requested length, or fetching less
+ than the number of characters actually requested, always make us
+ print ellipsis. */
+ force_ellipsis = 1;
+ }
+
+ QUIT;
+
+ if (addressprint)
+ {
+ fputs_filtered (" ", stream);
+ }
+ LA_PRINT_STRING (stream, buffer, bufptr - buffer, force_ellipsis);
+
+ if (errcode != 0 && force_ellipsis)
+ {
+ if (errcode == EIO)
+ {
+ fprintf_filtered (stream,
+ " <Address 0x%lx out of bounds>",
+ (unsigned long) addr);
+ }
+ else
+ {
+ error ("Error reading memory address 0x%lx: %s.",
+ (unsigned long) addr,
+ safe_strerror (errcode));
+ }
+ }
+ fflush (stream);
+ do_cleanups (old_chain);
+ return (bufptr - buffer);
+}
+
+
+/* Validate an input or output radix setting, and make sure the user
+ knows what they really did here. Radix setting is confusing, e.g.
+ setting the input radix to "10" never changes it! */
+
+/* ARGSUSED */
+static void
+set_input_radix (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ set_input_radix_1 (from_tty, *(unsigned *)c->var);
+}
+
+/* ARGSUSED */
+static void
+set_input_radix_1 (from_tty, radix)
+ int from_tty;
+ unsigned radix;
+{
+ /* We don't currently disallow any input radix except 0 or 1, which don't
+ make any mathematical sense. In theory, we can deal with any input
+ radix greater than 1, even if we don't have unique digits for every
+ value from 0 to radix-1, but in practice we lose on large radix values.
+ We should either fix the lossage or restrict the radix range more.
+ (FIXME). */
+
+ if (radix < 2)
+ {
+ error ("Nonsense input radix ``decimal %u''; input radix unchanged.",
+ radix);
+ }
+ input_radix = radix;
+ if (from_tty)
+ {
+ printf_filtered ("Input radix now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* ARGSUSED */
+static void
+set_output_radix (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ set_output_radix_1 (from_tty, *(unsigned *)c->var);
+}
+
+static void
+set_output_radix_1 (from_tty, radix)
+ int from_tty;
+ unsigned radix;
+{
+ /* Validate the radix and disallow ones that we aren't prepared to
+ handle correctly, leaving the radix unchanged. */
+ switch (radix)
+ {
+ case 16:
+ output_format = 'x'; /* hex */
+ break;
+ case 10:
+ output_format = 0; /* decimal */
+ break;
+ case 8:
+ output_format = 'o'; /* octal */
+ break;
+ default:
+ error ("Unsupported output radix ``decimal %u''; output radix unchanged.",
+ radix);
+ }
+ output_radix = radix;
+ if (from_tty)
+ {
+ printf_filtered ("Output radix now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* Set both the input and output radix at once. Try to set the output radix
+ first, since it has the most restrictive range. An radix that is valid as
+ an output radix is also valid as an input radix.
+
+ It may be useful to have an unusual input radix. If the user wishes to
+ set an input radix that is not valid as an output radix, he needs to use
+ the 'set input-radix' command. */
+
+static void
+set_radix (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ unsigned radix;
+
+ radix = (arg == NULL) ? 10 : parse_and_eval_address (arg);
+ set_output_radix_1 (0, radix);
+ set_input_radix_1 (0, radix);
+ if (from_tty)
+ {
+ printf_filtered ("Input and output radices now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* Show both the input and output radices. */
+
+/*ARGSUSED*/
+static void
+show_radix (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (from_tty)
+ {
+ if (input_radix == output_radix)
+ {
+ printf_filtered ("Input and output radices set to decimal %u, hex %x, octal %o.\n",
+ input_radix, input_radix, input_radix);
+ }
+ else
+ {
+ printf_filtered ("Input radix set to decimal %u, hex %x, octal %o.\n",
+ input_radix, input_radix, input_radix);
+ printf_filtered ("Output radix set to decimal %u, hex %x, octal %o.\n",
+ output_radix, output_radix, output_radix);
+ }
+ }
+}
+
+
+/*ARGSUSED*/
+static void
+set_print (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf (
+"\"set print\" must be followed by the name of a print subcommand.\n");
+ help_list (setprintlist, "set print ", -1, stdout);
+}
+
+/*ARGSUSED*/
+static void
+show_print (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ cmd_show_list (showprintlist, from_tty, "");
+}
+
+void
+_initialize_valprint ()
+{
+ struct cmd_list_element *c;
+
+ add_prefix_cmd ("print", no_class, set_print,
+ "Generic command for setting how things print.",
+ &setprintlist, "set print ", 0, &setlist);
+ add_alias_cmd ("p", "print", no_class, 1, &setlist);
+ /* prefer set print to set prompt */
+ add_alias_cmd ("pr", "print", no_class, 1, &setlist);
+
+ add_prefix_cmd ("print", no_class, show_print,
+ "Generic command for showing print settings.",
+ &showprintlist, "show print ", 0, &showlist);
+ add_alias_cmd ("p", "print", no_class, 1, &showlist);
+ add_alias_cmd ("pr", "print", no_class, 1, &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("elements", no_class, var_uinteger, (char *)&print_max,
+ "Set limit on string chars or array elements to print.\n\
+\"set print elements 0\" causes there to be no limit.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("repeats", no_class, var_uinteger,
+ (char *)&repeat_count_threshold,
+ "Set threshold for repeated print elements.\n\
+\"set print repeats 0\" causes all elements to be individually printed.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("pretty", class_support, var_boolean,
+ (char *)&prettyprint_structs,
+ "Set prettyprinting of structures.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("union", class_support, var_boolean, (char *)&unionprint,
+ "Set printing of unions interior to structures.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("array", class_support, var_boolean,
+ (char *)&prettyprint_arrays,
+ "Set prettyprinting of arrays.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("address", class_support, var_boolean, (char *)&addressprint,
+ "Set printing of addresses.",
+ &setprintlist),
+ &showprintlist);
+
+ c = add_set_cmd ("input-radix", class_support, var_uinteger,
+ (char *)&input_radix,
+ "Set default input radix for entering numbers.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_input_radix;
+
+ c = add_set_cmd ("output-radix", class_support, var_uinteger,
+ (char *)&output_radix,
+ "Set default output radix for printing of values.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_output_radix;
+
+ /* The "set radix" and "show radix" commands are special in that they are
+ like normal set and show commands but allow two normally independent
+ variables to be either set or shown with a single command. So the
+ usual add_set_cmd() and add_show_from_set() commands aren't really
+ appropriate. */
+ add_cmd ("radix", class_support, set_radix,
+ "Set default input and output number radices.\n\
+Use 'set input-radix' or 'set output-radix' to independently set each.\n\
+Without an argument, sets both radices back to the default value of 10.",
+ &setlist);
+ add_cmd ("radix", class_support, show_radix,
+ "Show the default input and output number radices.\n\
+Use 'show input-radix' or 'show output-radix' to independently show each.",
+ &showlist);
+
+ /* Give people the defaults which they are used to. */
+ prettyprint_structs = 0;
+ prettyprint_arrays = 0;
+ unionprint = 1;
+ addressprint = 1;
+ print_max = PRINT_MAX_DEFAULT;
+}
diff --git a/gnu/usr.bin/gdb/gdb/valprint.h b/gnu/usr.bin/gdb/gdb/valprint.h
new file mode 100644
index 000000000000..5918def07e68
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.h
@@ -0,0 +1,40 @@
+/* Declarations for value printing routines for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+extern int prettyprint_arrays; /* Controls pretty printing of arrays. */
+extern int prettyprint_structs; /* Controls pretty printing of structures */
+extern int prettyprint_arrays; /* Controls pretty printing of arrays. */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+extern int unionprint; /* Controls printing of nested unions. */
+extern int addressprint; /* Controls pretty printing of addresses. */
+extern int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+
+extern unsigned int print_max; /* Max # of chars for strings/vectors */
+extern int output_format;
+
+extern void
+val_print_array_elements PARAMS ((struct type *, char *, CORE_ADDR, FILE *,
+ int, int, int, enum val_prettyprint, int));
+
+extern void
+val_print_type_code_int PARAMS ((struct type *, char *, FILE *));
+
diff --git a/gnu/usr.bin/gdb/gdb/value.h b/gnu/usr.bin/gdb/gdb/value.h
new file mode 100644
index 000000000000..b8e16761e5d6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/value.h
@@ -0,0 +1,502 @@
+/* Definitions for values of C expressions, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (VALUE_H)
+#define VALUE_H 1
+
+/*
+ * The structure which defines the type of a value. It should never
+ * be possible for a program lval value to survive over a call to the inferior
+ * (ie to be put into the history list or an internal variable).
+ */
+enum lval_type {
+ /* Not an lval. */
+ not_lval,
+ /* In memory. Could be a saved register. */
+ lval_memory,
+ /* In a register. */
+ lval_register,
+ /* In a gdb internal variable. */
+ lval_internalvar,
+ /* Part of a gdb internal variable (structure field). */
+ lval_internalvar_component,
+ /* In a register series in a frame not the current one, which may have been
+ partially saved or saved in different places (otherwise would be
+ lval_register or lval_memory). */
+ lval_reg_frame_relative
+};
+
+struct value
+ {
+ /* Type of value; either not an lval, or one of the various
+ different possible kinds of lval. */
+ enum lval_type lval;
+ /* Location of value (if lval). */
+ union
+ {
+ /* Address in inferior or byte of registers structure. */
+ CORE_ADDR address;
+ /* Pointer to internal variable. */
+ struct internalvar *internalvar;
+ /* Number of register. Only used with
+ lval_reg_frame_relative. */
+ int regnum;
+ } location;
+ /* Describes offset of a value within lval a structure in bytes. */
+ int offset;
+ /* Only used for bitfields; number of bits contained in them. */
+ int bitsize;
+ /* Only used for bitfields; position of start of field.
+ For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB.
+ For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */
+ int bitpos;
+ /* Frame value is relative to. In practice, this address is only
+ used if the value is stored in several registers in other than
+ the current frame, and these registers have not all been saved
+ at the same place in memory. This will be described in the
+ lval enum above as "lval_reg_frame_relative". */
+ CORE_ADDR frame_addr;
+ /* Type of the value. */
+ struct type *type;
+ /* Values are stored in a chain, so that they can be deleted
+ easily over calls to the inferior. Values assigned to internal
+ variables or put into the value history are taken off this
+ list. */
+ struct value *next;
+ /* If an lval is forced to repeat, a new value is created with
+ these fields set. The new value is not an lval. */
+ short repeated;
+ short repetitions;
+ /* Register number if the value is from a register. Is not kept
+ if you take a field of a structure that is stored in a
+ register. Shouldn't it be? */
+ short regno;
+ /* If zero, contents of this value are in the contents field.
+ If nonzero, contents are in inferior memory at address
+ in the location.address field plus the offset field
+ (and the lval field should be lval_memory). */
+ char lazy;
+ /* If nonzero, this is the value of a variable which does not
+ actually exist in the program. */
+ char optimized_out;
+ /* Actual contents of the value. For use of this value; setting
+ it uses the stuff above. Not valid if lazy is nonzero.
+ Target byte-order. We force it to be aligned properly for any
+ possible value. */
+ union {
+ long contents[1];
+ double force_double_align;
+#ifdef CC_HAS_LONG_LONG
+ long long force_longlong_align;
+#endif
+ } aligner;
+
+ };
+
+typedef struct value *value;
+
+#define VALUE_TYPE(val) (val)->type
+#define VALUE_LAZY(val) (val)->lazy
+/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of
+ the gdb buffer used to hold a copy of the contents of the lval.
+ VALUE_CONTENTS is used when the contents of the buffer are needed --
+ it uses value_fetch_lazy() to load the buffer from the process being
+ debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is
+ used when data is being stored into the buffer, or when it is
+ certain that the contents of the buffer are valid. */
+#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents)
+#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\
+ VALUE_CONTENTS_RAW(val))
+extern int
+value_fetch_lazy PARAMS ((value val));
+
+#define VALUE_LVAL(val) (val)->lval
+#define VALUE_ADDRESS(val) (val)->location.address
+#define VALUE_INTERNALVAR(val) (val)->location.internalvar
+#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum)
+#define VALUE_FRAME(val) ((val)->frame_addr)
+#define VALUE_OFFSET(val) (val)->offset
+#define VALUE_BITSIZE(val) (val)->bitsize
+#define VALUE_BITPOS(val) (val)->bitpos
+#define VALUE_NEXT(val) (val)->next
+#define VALUE_REPEATED(val) (val)->repeated
+#define VALUE_REPETITIONS(val) (val)->repetitions
+#define VALUE_REGNO(val) (val)->regno
+#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out)
+
+/* Convert a REF to the object referenced. */
+
+#define COERCE_REF(arg) \
+{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \
+ arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \
+ unpack_long (VALUE_TYPE (arg), \
+ VALUE_CONTENTS (arg)));}
+
+/* If ARG is an array, convert it to a pointer.
+ If ARG is an enum, convert it to an integer.
+ If ARG is a function, convert it to a function pointer.
+
+ References are dereferenced. */
+
+#define COERCE_ARRAY(arg) \
+{ COERCE_REF(arg); \
+ if (VALUE_REPEATED (arg) \
+ || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \
+ arg = value_coerce_array (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \
+ arg = value_coerce_function (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+}
+
+/* If ARG is an enum, convert it to an integer. */
+
+#define COERCE_ENUM(arg) \
+{ COERCE_REF (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+}
+
+/* Internal variables (variables for convenience of use of debugger)
+ are recorded as a chain of these structures. */
+
+struct internalvar
+{
+ struct internalvar *next;
+ char *name;
+ value value;
+};
+
+/* Pointer to member function. Depends on compiler implementation. */
+
+#define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000)
+#define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET))
+#define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR))
+
+
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+
+#ifdef __STDC__
+struct frame_info;
+struct fn_field;
+#endif
+
+extern void
+print_address_demangle PARAMS ((CORE_ADDR, FILE *, int));
+
+extern LONGEST
+value_as_long PARAMS ((value val));
+
+extern double
+value_as_double PARAMS ((value val));
+
+extern CORE_ADDR
+value_as_pointer PARAMS ((value val));
+
+extern LONGEST
+unpack_long PARAMS ((struct type *type, char *valaddr));
+
+extern double
+unpack_double PARAMS ((struct type *type, char *valaddr, int *invp));
+
+extern CORE_ADDR unpack_pointer PARAMS ((struct type *type, char *valaddr));
+
+extern LONGEST unpack_field_as_long PARAMS ((struct type *type, char *valaddr,
+ int fieldno));
+
+extern value value_from_longest PARAMS ((struct type *type, LONGEST num));
+
+extern value value_from_double PARAMS ((struct type *type, double num));
+
+extern value value_at PARAMS ((struct type *type, CORE_ADDR addr));
+
+extern value value_at_lazy PARAMS ((struct type *type, CORE_ADDR addr));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value value_from_register PARAMS ((struct type *type, int regnum,
+ struct frame_info * frame));
+
+extern value value_of_variable PARAMS ((struct symbol *var, struct block *b));
+
+extern value value_of_register PARAMS ((int regnum));
+
+extern int symbol_read_needs_frame PARAMS ((struct symbol *));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value read_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value locate_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+extern value allocate_value PARAMS ((struct type *type));
+
+extern value allocate_repeat_value PARAMS ((struct type *type, int count));
+
+extern value value_mark PARAMS ((void));
+
+extern void value_free_to_mark PARAMS ((value mark));
+
+extern value value_string PARAMS ((char *ptr, int len));
+
+extern value value_array PARAMS ((int lowbound, int highbound,
+ value *elemvec));
+
+extern value value_concat PARAMS ((value arg1, value arg2));
+
+extern value value_binop PARAMS ((value arg1, value arg2, enum exp_opcode op));
+
+extern value value_add PARAMS ((value arg1, value arg2));
+
+extern value value_sub PARAMS ((value arg1, value arg2));
+
+extern value value_coerce_array PARAMS ((value arg1));
+
+extern value value_coerce_function PARAMS ((value arg1));
+
+extern value value_ind PARAMS ((value arg1));
+
+extern value value_addr PARAMS ((value arg1));
+
+extern value value_assign PARAMS ((value toval, value fromval));
+
+extern value value_neg PARAMS ((value arg1));
+
+extern value value_complement PARAMS ((value arg1));
+
+extern value value_struct_elt PARAMS ((value *argp, value *args, char *name,
+ int *static_memfuncp, char *err));
+
+extern value value_struct_elt_for_reference PARAMS ((struct type *domain,
+ int offset,
+ struct type *curtype,
+ char *name,
+ struct type *intype));
+
+extern value value_field PARAMS ((value arg1, int fieldno));
+
+extern value value_primitive_field PARAMS ((value arg1, int offset,
+ int fieldno,
+ struct type *arg_type));
+
+extern value value_cast PARAMS ((struct type *type, value arg2));
+
+extern value value_zero PARAMS ((struct type *type, enum lval_type lv));
+
+extern value value_repeat PARAMS ((value arg1, int count));
+
+extern value value_subscript PARAMS ((value array, value idx));
+
+extern value value_from_vtable_info PARAMS ((value arg, struct type *type));
+
+extern value value_being_returned PARAMS ((struct type *valtype,
+ char retbuf[REGISTER_BYTES],
+ int struct_return));
+
+extern int
+using_struct_return PARAMS ((value function, CORE_ADDR funcaddr,
+ struct type *value_type, int gcc_p));
+
+extern void
+set_return_value PARAMS ((value val));
+
+extern value
+evaluate_expression PARAMS ((struct expression *exp));
+
+extern value
+evaluate_type PARAMS ((struct expression *exp));
+
+extern value
+parse_and_eval PARAMS ((char *exp));
+
+extern value
+parse_to_comma_and_eval PARAMS ((char **expp));
+
+extern struct type *
+parse_and_eval_type PARAMS ((char *p, int length));
+
+extern CORE_ADDR
+parse_and_eval_address PARAMS ((char *exp));
+
+extern CORE_ADDR
+parse_and_eval_address_1 PARAMS ((char **expptr));
+
+extern value
+access_value_history PARAMS ((int num));
+
+extern value
+value_of_internalvar PARAMS ((struct internalvar *var));
+
+extern void
+set_internalvar PARAMS ((struct internalvar *var, value val));
+
+extern void
+set_internalvar_component PARAMS ((struct internalvar *var, int offset,
+ int bitpos, int bitsize,
+ value newvalue));
+
+extern struct internalvar *
+lookup_internalvar PARAMS ((char *name));
+
+extern int
+value_equal PARAMS ((value arg1, value arg2));
+
+extern int
+value_less PARAMS ((value arg1, value arg2));
+
+extern int
+value_logical_not PARAMS ((value arg1));
+
+/* C++ */
+
+extern value
+value_of_this PARAMS ((int complain));
+
+extern value
+value_x_binop PARAMS ((value arg1, value arg2, enum exp_opcode op,
+ enum exp_opcode otherop));
+
+extern value
+value_x_unop PARAMS ((value arg1, enum exp_opcode op));
+
+extern value
+value_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j,
+ struct type* type, int offset));
+
+extern value
+value_virtual_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j,
+ struct type *type, int offset));
+
+extern int
+binop_user_defined_p PARAMS ((enum exp_opcode op, value arg1, value arg2));
+
+extern int
+unop_user_defined_p PARAMS ((enum exp_opcode op, value arg1));
+
+extern int
+destructor_name_p PARAMS ((const char *name, const struct type *type));
+
+#define value_free(val) free ((PTR)val)
+
+extern void
+free_all_values PARAMS ((void));
+
+extern void
+release_value PARAMS ((value val));
+
+extern int
+record_latest_value PARAMS ((value val));
+
+extern void
+registers_changed PARAMS ((void));
+
+extern void
+read_register_bytes PARAMS ((int regbyte, char *myaddr, int len));
+
+extern void
+write_register_bytes PARAMS ((int regbyte, char *myaddr, int len));
+
+extern void
+read_register_gen PARAMS ((int regno, char *myaddr));
+
+extern CORE_ADDR
+read_register PARAMS ((int regno));
+
+extern void
+write_register PARAMS ((int regno, LONGEST val));
+
+extern void
+supply_register PARAMS ((int regno, char *val));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern void
+get_saved_register PARAMS ((char *raw_buffer, int *optimized,
+ CORE_ADDR *addrp, struct frame_info *frame,
+ int regnum, enum lval_type *lval));
+
+extern void
+modify_field PARAMS ((char *addr, LONGEST fieldval, int bitpos, int bitsize));
+
+extern void
+type_print PARAMS ((struct type *type, char *varstring, FILE *stream,
+ int show));
+
+extern char *
+baseclass_addr PARAMS ((struct type *type, int index, char *valaddr,
+ value *valuep, int *errp));
+
+extern void
+print_longest PARAMS ((FILE *stream, int format, int use_local,
+ LONGEST value));
+
+extern void
+print_floating PARAMS ((char *valaddr, struct type *type, FILE *stream));
+
+extern int
+value_print PARAMS ((value val, FILE *stream, int format,
+ enum val_prettyprint pretty));
+
+extern int
+val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address,
+ FILE *stream, int format, int deref_ref,
+ int recurse, enum val_prettyprint pretty));
+
+extern int
+val_print_string PARAMS ((CORE_ADDR addr, unsigned int len, FILE *stream));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern void
+print_variable_value PARAMS ((struct symbol *var, struct frame_info *frame,
+ FILE *stream));
+
+extern value
+value_arg_coerce PARAMS ((value));
+
+extern int
+check_field PARAMS ((value, const char *));
+
+extern void
+c_typedef_print PARAMS ((struct type *type, struct symbol *new, FILE *stream));
+
+extern char *
+internalvar_name PARAMS ((struct internalvar *var));
+
+extern void
+clear_value_history PARAMS ((void));
+
+extern void
+clear_internalvars PARAMS ((void));
+
+/* From values.c */
+
+extern value
+value_copy PARAMS ((value));
+
+extern int
+baseclass_offset PARAMS ((struct type *, int, value, int));
+
+/* From valops.c */
+
+extern value
+call_function_by_hand PARAMS ((value, int, value *));
+
+#endif /* !defined (VALUE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/values.c b/gnu/usr.bin/gdb/gdb/values.c
new file mode 100644
index 000000000000..a592f9eeca98
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/values.c
@@ -0,0 +1,1502 @@
+/* Low level packing and unpacking of values for GDB, the GNU Debugger.
+ Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "demangle.h"
+
+/* Local function prototypes. */
+
+static value
+value_headof PARAMS ((value, struct type *, struct type *));
+
+static void
+show_values PARAMS ((char *, int));
+
+static void
+show_convenience PARAMS ((char *, int));
+
+/* The value-history records all the values printed
+ by print commands during this session. Each chunk
+ records 60 consecutive values. The first chunk on
+ the chain records the most recent values.
+ The total number of values is in value_history_count. */
+
+#define VALUE_HISTORY_CHUNK 60
+
+struct value_history_chunk
+{
+ struct value_history_chunk *next;
+ value values[VALUE_HISTORY_CHUNK];
+};
+
+/* Chain of chunks now in use. */
+
+static struct value_history_chunk *value_history_chain;
+
+static int value_history_count; /* Abs number of last entry stored */
+
+/* List of all value objects currently allocated
+ (except for those released by calls to release_value)
+ This is so they can be freed after each command. */
+
+static value all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+value
+allocate_value (type)
+ struct type *type;
+{
+ register value val;
+
+ check_stub_type (type);
+
+ val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type));
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 0;
+ VALUE_REPETITIONS (val) = 0;
+ VALUE_REGNO (val) = -1;
+ VALUE_LAZY (val) = 0;
+ VALUE_OPTIMIZED_OUT (val) = 0;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+value
+allocate_repeat_value (type, count)
+ struct type *type;
+ int count;
+{
+ register value val;
+
+ val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count);
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 1;
+ VALUE_REPETITIONS (val) = count;
+ VALUE_REGNO (val) = -1;
+ VALUE_LAZY (val) = 0;
+ VALUE_OPTIMIZED_OUT (val) = 0;
+ return val;
+}
+
+/* Return a mark in the value chain. All values allocated after the
+ mark is obtained (except for those released) are subject to being freed
+ if a subsequent value_free_to_mark is passed the mark. */
+value
+value_mark ()
+{
+ return all_values;
+}
+
+/* Free all values allocated since MARK was obtained by value_mark
+ (except for those released). */
+void
+value_free_to_mark (mark)
+ value mark;
+{
+ value val, next;
+
+ for (val = all_values; val && val != mark; val = next)
+ {
+ next = VALUE_NEXT (val);
+ value_free (val);
+ }
+ all_values = val;
+}
+
+/* Free all the values that have been allocated (except for those released).
+ Called after each command, successful or not. */
+
+void
+free_all_values ()
+{
+ register value val, next;
+
+ for (val = all_values; val; val = next)
+ {
+ next = VALUE_NEXT (val);
+ value_free (val);
+ }
+
+ all_values = 0;
+}
+
+/* Remove VAL from the chain all_values
+ so it will not be freed automatically. */
+
+void
+release_value (val)
+ register value val;
+{
+ register value v;
+
+ if (all_values == val)
+ {
+ all_values = val->next;
+ return;
+ }
+
+ for (v = all_values; v; v = v->next)
+ {
+ if (v->next == val)
+ {
+ v->next = val->next;
+ break;
+ }
+ }
+}
+
+/* Return a copy of the value ARG.
+ It contains the same contents, for same memory address,
+ but it's a different block of storage. */
+
+value
+value_copy (arg)
+ value arg;
+{
+ register value val;
+ register struct type *type = VALUE_TYPE (arg);
+ if (VALUE_REPEATED (arg))
+ val = allocate_repeat_value (type, VALUE_REPETITIONS (arg));
+ else
+ val = allocate_value (type);
+ VALUE_LVAL (val) = VALUE_LVAL (arg);
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg);
+ VALUE_OFFSET (val) = VALUE_OFFSET (arg);
+ VALUE_BITPOS (val) = VALUE_BITPOS (arg);
+ VALUE_BITSIZE (val) = VALUE_BITSIZE (arg);
+ VALUE_REGNO (val) = VALUE_REGNO (arg);
+ VALUE_LAZY (val) = VALUE_LAZY (arg);
+ if (!VALUE_LAZY (val))
+ {
+ memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS_RAW (arg),
+ TYPE_LENGTH (VALUE_TYPE (arg))
+ * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1));
+ }
+ return val;
+}
+
+/* Access to the value history. */
+
+/* Record a new value in the value history.
+ Returns the absolute history index of the entry.
+ Result of -1 indicates the value was not saved; otherwise it is the
+ value history index of this new item. */
+
+int
+record_latest_value (val)
+ value val;
+{
+ int i;
+
+ /* Check error now if about to store an invalid float. We return -1
+ to the caller, but allow them to continue, e.g. to print it as "Nan". */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT)
+ {
+ unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i);
+ if (i) return -1; /* Indicate value not saved in history */
+ }
+
+ /* Here we treat value_history_count as origin-zero
+ and applying to the value being stored now. */
+
+ i = value_history_count % VALUE_HISTORY_CHUNK;
+ if (i == 0)
+ {
+ register struct value_history_chunk *new
+ = (struct value_history_chunk *)
+ xmalloc (sizeof (struct value_history_chunk));
+ memset (new->values, 0, sizeof new->values);
+ new->next = value_history_chain;
+ value_history_chain = new;
+ }
+
+ value_history_chain->values[i] = val;
+
+ /* We don't want this value to have anything to do with the inferior anymore.
+ In particular, "set $1 = 50" should not affect the variable from which
+ the value was taken, and fast watchpoints should be able to assume that
+ a value on the value history never changes. */
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+ VALUE_LVAL (val) = not_lval;
+ release_value (val);
+
+ /* Now we regard value_history_count as origin-one
+ and applying to the value just stored. */
+
+ return ++value_history_count;
+}
+
+/* Return a copy of the value in the history with sequence number NUM. */
+
+value
+access_value_history (num)
+ int num;
+{
+ register struct value_history_chunk *chunk;
+ register int i;
+ register int absnum = num;
+
+ if (absnum <= 0)
+ absnum += value_history_count;
+
+ if (absnum <= 0)
+ {
+ if (num == 0)
+ error ("The history is empty.");
+ else if (num == 1)
+ error ("There is only one value in the history.");
+ else
+ error ("History does not go back to $$%d.", -num);
+ }
+ if (absnum > value_history_count)
+ error ("History has not yet reached $%d.", absnum);
+
+ absnum--;
+
+ /* Now absnum is always absolute and origin zero. */
+
+ chunk = value_history_chain;
+ for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK;
+ i > 0; i--)
+ chunk = chunk->next;
+
+ return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);
+}
+
+/* Clear the value history entirely.
+ Must be done when new symbol tables are loaded,
+ because the type pointers become invalid. */
+
+void
+clear_value_history ()
+{
+ register struct value_history_chunk *next;
+ register int i;
+ register value val;
+
+ while (value_history_chain)
+ {
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if ((val = value_history_chain->values[i]) != NULL)
+ free ((PTR)val);
+ next = value_history_chain->next;
+ free ((PTR)value_history_chain);
+ value_history_chain = next;
+ }
+ value_history_count = 0;
+}
+
+static void
+show_values (num_exp, from_tty)
+ char *num_exp;
+ int from_tty;
+{
+ register int i;
+ register value val;
+ static int num = 1;
+
+ if (num_exp)
+ {
+ /* "info history +" should print from the stored position.
+ "info history <exp>" should print around value number <exp>. */
+ if (num_exp[0] != '+' || num_exp[1] != '\0')
+ num = parse_and_eval_address (num_exp) - 5;
+ }
+ else
+ {
+ /* "info history" means print the last 10 values. */
+ num = value_history_count - 9;
+ }
+
+ if (num <= 0)
+ num = 1;
+
+ for (i = num; i < num + 10 && i <= value_history_count; i++)
+ {
+ val = access_value_history (i);
+ printf_filtered ("$%d = ", i);
+ value_print (val, stdout, 0, Val_pretty_default);
+ printf_filtered ("\n");
+ }
+
+ /* The next "info history +" should start after what we just printed. */
+ num += 10;
+
+ /* Hitting just return after this command should do the same thing as
+ "info history +". If num_exp is null, this is unnecessary, since
+ "info history +" is not useful after "info history". */
+ if (from_tty && num_exp)
+ {
+ num_exp[0] = '+';
+ num_exp[1] = '\0';
+ }
+}
+
+/* Internal variables. These are variables within the debugger
+ that hold values assigned by debugger commands.
+ The user refers to them with a '$' prefix
+ that does not appear in the variable names stored internally. */
+
+static struct internalvar *internalvars;
+
+/* Look up an internal variable with name NAME. NAME should not
+ normally include a dollar sign.
+
+ If the specified internal variable does not exist,
+ one is created, with a void value. */
+
+struct internalvar *
+lookup_internalvar (name)
+ char *name;
+{
+ register struct internalvar *var;
+
+ for (var = internalvars; var; var = var->next)
+ if (STREQ (var->name, name))
+ return var;
+
+ var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
+ var->name = concat (name, NULL);
+ var->value = allocate_value (builtin_type_void);
+ release_value (var->value);
+ var->next = internalvars;
+ internalvars = var;
+ return var;
+}
+
+value
+value_of_internalvar (var)
+ struct internalvar *var;
+{
+ register value val;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ return VALUE_OF_TRAPPED_INTERNALVAR (var);
+#endif
+
+ val = value_copy (var->value);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+ VALUE_LVAL (val) = lval_internalvar;
+ VALUE_INTERNALVAR (val) = var;
+ return val;
+}
+
+void
+set_internalvar_component (var, offset, bitpos, bitsize, newval)
+ struct internalvar *var;
+ int offset, bitpos, bitsize;
+ value newval;
+{
+ register char *addr = VALUE_CONTENTS (var->value) + offset;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset);
+#endif
+
+ if (bitsize)
+ modify_field (addr, value_as_long (newval),
+ bitpos, bitsize);
+ else
+ memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval)));
+}
+
+void
+set_internalvar (var, val)
+ struct internalvar *var;
+ value val;
+{
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0);
+#endif
+
+ free ((PTR)var->value);
+ var->value = value_copy (val);
+ /* Force the value to be fetched from the target now, to avoid problems
+ later when this internalvar is referenced and the target is gone or
+ has changed. */
+ if (VALUE_LAZY (var->value))
+ value_fetch_lazy (var->value);
+ release_value (var->value);
+}
+
+char *
+internalvar_name (var)
+ struct internalvar *var;
+{
+ return var->name;
+}
+
+/* Free all internalvars. Done when new symtabs are loaded,
+ because that makes the values invalid. */
+
+void
+clear_internalvars ()
+{
+ register struct internalvar *var;
+
+ while (internalvars)
+ {
+ var = internalvars;
+ internalvars = var->next;
+ free ((PTR)var->name);
+ free ((PTR)var->value);
+ free ((PTR)var);
+ }
+}
+
+static void
+show_convenience (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct internalvar *var;
+ int varseen = 0;
+
+ for (var = internalvars; var; var = var->next)
+ {
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ continue;
+#endif
+ if (!varseen)
+ {
+ varseen = 1;
+ }
+ printf_filtered ("$%s = ", var->name);
+ value_print (var->value, stdout, 0, Val_pretty_default);
+ printf_filtered ("\n");
+ }
+ if (!varseen)
+ printf ("No debugger convenience variables now defined.\n\
+Convenience variables have names starting with \"$\";\n\
+use \"set\" as in \"set $foo = 5\" to define them.\n");
+}
+
+/* Extract a value as a C number (either long or double).
+ Knows how to convert fixed values to double, or
+ floating values to long.
+ Does not deallocate the value. */
+
+LONGEST
+value_as_long (val)
+ register value val;
+{
+ /* This coerces arrays and functions, which is necessary (e.g.
+ in disassemble_command). It also dereferences references, which
+ I suspect is the most logical thing to do. */
+ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_ENUM)
+ COERCE_ARRAY (val);
+ return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val));
+}
+
+double
+value_as_double (val)
+ register value val;
+{
+ double foo;
+ int inv;
+
+ foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv);
+ if (inv)
+ error ("Invalid floating value found in program.");
+ return foo;
+}
+/* Extract a value as a C pointer.
+ Does not deallocate the value. */
+CORE_ADDR
+value_as_pointer (val)
+ value val;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+#if 0
+ /* ADDR_BITS_REMOVE is wrong if we are being called for a
+ non-address (e.g. argument to "signal", "info break", etc.), or
+ for pointers to char, in which the low bits *are* significant. */
+ return ADDR_BITS_REMOVE(value_as_long (val));
+#else
+ return value_as_long (val);
+#endif
+}
+
+/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+ as a long, or as a double, assuming the raw data is described
+ by type TYPE. Knows how to convert different sizes of values
+ and can convert between fixed and floating point. We don't assume
+ any alignment for the raw data. Return value is in host byte order.
+
+ If you want functions and arrays to be coerced to pointers, and
+ references to be dereferenced, call value_as_long() instead.
+
+ C++: It is assumed that the front-end has taken care of
+ all matters concerning pointers to members. A pointer
+ to member which reaches here is considered to be equivalent
+ to an INT (or some size). After all, it is only an offset. */
+
+/* FIXME: This should be rewritten as a switch statement for speed and
+ ease of comprehension. */
+
+LONGEST
+unpack_long (type, valaddr)
+ struct type *type;
+ char *valaddr;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ if (code == TYPE_CODE_ENUM || code == TYPE_CODE_BOOL)
+ code = TYPE_CODE_INT;
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ {
+ float retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+
+ if (len == sizeof (double))
+ {
+ double retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else
+ {
+ error ("Unexpected type of floating point number.");
+ }
+ }
+ else if ((code == TYPE_CODE_INT || code == TYPE_CODE_CHAR) && nosign)
+ {
+ return extract_unsigned_integer (valaddr, len);
+ }
+ else if (code == TYPE_CODE_INT || code == TYPE_CODE_CHAR)
+ {
+ return extract_signed_integer (valaddr, len);
+ }
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ else if (code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ {
+ return extract_address (valaddr, len);
+ }
+ else if (code == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in unpack_long");
+
+ error ("Value not integer or pointer.");
+ return 0; /* For lint -- never reached */
+}
+
+/* Return a double value from the specified type and address.
+ INVP points to an int which is set to 0 for valid value,
+ 1 for invalid value (bad float format). In either case,
+ the returned double is OK to use. Argument is in target
+ format, result is in host format. */
+
+double
+unpack_double (type, valaddr, invp)
+ struct type *type;
+ char *valaddr;
+ int *invp;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ *invp = 0; /* Assume valid. */
+ if (code == TYPE_CODE_FLT)
+ {
+ if (INVALID_FLOAT (valaddr, len))
+ {
+ *invp = 1;
+ return 1.234567891011121314;
+ }
+
+ if (len == sizeof (float))
+ {
+ float retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+
+ if (len == sizeof (double))
+ {
+ double retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else
+ {
+ error ("Unexpected type of floating point number.");
+ return 0; /* Placate lint. */
+ }
+ }
+ else if (nosign) {
+ /* Unsigned -- be sure we compensate for signed LONGEST. */
+ return (unsigned LONGEST) unpack_long (type, valaddr);
+ } else {
+ /* Signed -- we are OK with unpack_long. */
+ return unpack_long (type, valaddr);
+ }
+}
+
+/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+ as a CORE_ADDR, assuming the raw data is described by type TYPE.
+ We don't assume any alignment for the raw data. Return value is in
+ host byte order.
+
+ If you want functions and arrays to be coerced to pointers, and
+ references to be dereferenced, call value_as_pointer() instead.
+
+ C++: It is assumed that the front-end has taken care of
+ all matters concerning pointers to members. A pointer
+ to member which reaches here is considered to be equivalent
+ to an INT (or some size). After all, it is only an offset. */
+
+CORE_ADDR
+unpack_pointer (type, valaddr)
+ struct type *type;
+ char *valaddr;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ return unpack_long (type, valaddr);
+}
+
+/* Given a value ARG1 (offset by OFFSET bytes)
+ of a struct or union type ARG_TYPE,
+ extract and return the value of one of its fields.
+ FIELDNO says which field.
+
+ For C++, must also be able to return values from static fields */
+
+value
+value_primitive_field (arg1, offset, fieldno, arg_type)
+ register value arg1;
+ int offset;
+ register int fieldno;
+ register struct type *arg_type;
+{
+ register value v;
+ register struct type *type;
+
+ check_stub_type (arg_type);
+ type = TYPE_FIELD_TYPE (arg_type, fieldno);
+
+ /* Handle packed fields */
+
+ offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+ if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
+ {
+ v = value_from_longest (type,
+ unpack_field_as_long (arg_type,
+ VALUE_CONTENTS (arg1),
+ fieldno));
+ VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8;
+ VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+ }
+ else
+ {
+ v = allocate_value (type);
+ if (VALUE_LAZY (arg1))
+ VALUE_LAZY (v) = 1;
+ else
+ memcpy (VALUE_CONTENTS_RAW (v), VALUE_CONTENTS_RAW (arg1) + offset,
+ TYPE_LENGTH (type));
+ }
+ VALUE_LVAL (v) = VALUE_LVAL (arg1);
+ if (VALUE_LVAL (arg1) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1);
+ VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1);
+ return v;
+}
+
+/* Given a value ARG1 of a struct or union type,
+ extract and return the value of one of its fields.
+ FIELDNO says which field.
+
+ For C++, must also be able to return values from static fields */
+
+value
+value_field (arg1, fieldno)
+ register value arg1;
+ register int fieldno;
+{
+ return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1));
+}
+
+/* Return a non-virtual function as a value.
+ F is the list of member functions which contains the desired method.
+ J is an index into F which provides the desired method. */
+
+value
+value_fn_field (arg1p, f, j, type, offset)
+ value *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ register value v;
+ register struct type *ftype = TYPE_FN_FIELD_TYPE (f, j);
+ struct symbol *sym;
+
+ sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE, 0, NULL);
+ if (! sym) error ("Internal error: could not find physical method named %s",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+
+ v = allocate_value (ftype);
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ VALUE_TYPE (v) = ftype;
+
+ if (arg1p)
+ {
+ if (type != VALUE_TYPE (*arg1p))
+ *arg1p = value_ind (value_cast (lookup_pointer_type (type),
+ value_addr (*arg1p)));
+
+ /* Move the `this' pointer according to the offset.
+ VALUE_OFFSET (*arg1p) += offset;
+ */
+ }
+
+ return v;
+}
+
+/* Return a virtual function as a value.
+ ARG1 is the object which provides the virtual function
+ table pointer. *ARG1P is side-effected in calling this function.
+ F is the list of member functions which contains the desired virtual
+ function.
+ J is an index into F which provides the desired virtual function.
+
+ TYPE is the type in which F is located. */
+value
+value_virtual_fn_field (arg1p, f, j, type, offset)
+ value *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ value arg1 = *arg1p;
+ /* First, get the virtual function table pointer. That comes
+ with a strange type, so cast it to type `pointer to long' (which
+ should serve just fine as a function type). Then, index into
+ the table, and convert final value to appropriate function type. */
+ value entry, vfn, vtbl;
+ value vi = value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+ struct type *fcontext = TYPE_FN_FIELD_FCONTEXT (f, j);
+ struct type *context;
+ if (fcontext == NULL)
+ /* We don't have an fcontext (e.g. the program was compiled with
+ g++ version 1). Try to get the vtbl from the TYPE_VPTR_BASETYPE.
+ This won't work right for multiple inheritance, but at least we
+ should do as well as GDB 3.x did. */
+ fcontext = TYPE_VPTR_BASETYPE (type);
+ context = lookup_pointer_type (fcontext);
+ /* Now context is a pointer to the basetype containing the vtbl. */
+ if (TYPE_TARGET_TYPE (context) != VALUE_TYPE (arg1))
+ arg1 = value_ind (value_cast (context, value_addr (arg1)));
+
+ context = VALUE_TYPE (arg1);
+ /* Now context is the basetype containing the vtbl. */
+
+ /* This type may have been defined before its virtual function table
+ was. If so, fill in the virtual function table entry for the
+ type now. */
+ if (TYPE_VPTR_FIELDNO (context) < 0)
+ fill_in_vptr_fieldno (context);
+
+ /* The virtual function table is now an array of structures
+ which have the form { int16 offset, delta; void *pfn; }. */
+ vtbl = value_ind (value_primitive_field (arg1, 0,
+ TYPE_VPTR_FIELDNO (context),
+ TYPE_VPTR_BASETYPE (context)));
+
+ /* Index into the virtual function table. This is hard-coded because
+ looking up a field is not cheap, and it may be important to save
+ time, e.g. if the user has set a conditional breakpoint calling
+ a virtual function. */
+ entry = value_subscript (vtbl, vi);
+
+ /* Move the `this' pointer according to the virtual function table. */
+ VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0))/* + offset*/;
+
+ if (! VALUE_LAZY (arg1))
+ {
+ VALUE_LAZY (arg1) = 1;
+ value_fetch_lazy (arg1);
+ }
+
+ vfn = value_field (entry, 2);
+ /* Reinstantiate the function pointer with the correct type. */
+ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+
+ *arg1p = arg1;
+ return vfn;
+}
+
+/* ARG is a pointer to an object we know to be at least
+ a DTYPE. BTYPE is the most derived basetype that has
+ already been searched (and need not be searched again).
+ After looking at the vtables between BTYPE and DTYPE,
+ return the most derived type we find. The caller must
+ be satisfied when the return value == DTYPE.
+
+ FIXME-tiemann: should work with dossier entries as well. */
+
+static value
+value_headof (in_arg, btype, dtype)
+ value in_arg;
+ struct type *btype, *dtype;
+{
+ /* First collect the vtables we must look at for this object. */
+ /* FIXME-tiemann: right now, just look at top-most vtable. */
+ value arg, vtbl, entry, best_entry = 0;
+ int i, nelems;
+ int offset, best_offset = 0;
+ struct symbol *sym;
+ CORE_ADDR pc_for_sym;
+ char *demangled_name;
+ struct minimal_symbol *msymbol;
+
+ btype = TYPE_VPTR_BASETYPE (dtype);
+ check_stub_type (btype);
+ arg = in_arg;
+ if (btype != dtype)
+ arg = value_cast (lookup_pointer_type (btype), arg);
+ vtbl = value_ind (value_field (value_ind (arg), TYPE_VPTR_FIELDNO (btype)));
+
+ /* Check that VTBL looks like it points to a virtual function table. */
+ msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl));
+ if (msymbol == NULL
+ || !VTBL_PREFIX_P (demangled_name = SYMBOL_NAME (msymbol)))
+ {
+ /* If we expected to find a vtable, but did not, let the user
+ know that we aren't happy, but don't throw an error.
+ FIXME: there has to be a better way to do this. */
+ struct type *error_type = (struct type *)xmalloc (sizeof (struct type));
+ memcpy (error_type, VALUE_TYPE (in_arg), sizeof (struct type));
+ TYPE_NAME (error_type) = savestring ("suspicious *", sizeof ("suspicious *"));
+ VALUE_TYPE (in_arg) = error_type;
+ return in_arg;
+ }
+
+ /* Now search through the virtual function table. */
+ entry = value_ind (vtbl);
+ nelems = longest_to_int (value_as_long (value_field (entry, 2)));
+ for (i = 1; i <= nelems; i++)
+ {
+ entry = value_subscript (vtbl, value_from_longest (builtin_type_int,
+ (LONGEST) i));
+ offset = longest_to_int (value_as_long (value_field (entry, 0)));
+ /* If we use '<=' we can handle single inheritance
+ * where all offsets are zero - just use the first entry found. */
+ if (offset <= best_offset)
+ {
+ best_offset = offset;
+ best_entry = entry;
+ }
+ }
+ /* Move the pointer according to BEST_ENTRY's offset, and figure
+ out what type we should return as the new pointer. */
+ if (best_entry == 0)
+ {
+ /* An alternative method (which should no longer be necessary).
+ * But we leave it in for future use, when we will hopefully
+ * have optimizes the vtable to use thunks instead of offsets. */
+ /* Use the name of vtable itself to extract a base type. */
+ demangled_name += 4; /* Skip _vt$ prefix. */
+ }
+ else
+ {
+ pc_for_sym = value_as_pointer (value_field (best_entry, 2));
+ sym = find_pc_function (pc_for_sym);
+ demangled_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ANSI);
+ *(strchr (demangled_name, ':')) = '\0';
+ }
+ sym = lookup_symbol (demangled_name, 0, VAR_NAMESPACE, 0, 0);
+ if (sym == NULL)
+ error ("could not find type declaration for `%s'", demangled_name);
+ if (best_entry)
+ {
+ free (demangled_name);
+ arg = value_add (value_cast (builtin_type_int, arg),
+ value_field (best_entry, 0));
+ }
+ else arg = in_arg;
+ VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym));
+ return arg;
+}
+
+/* ARG is a pointer object of type TYPE. If TYPE has virtual
+ function tables, probe ARG's tables (including the vtables
+ of its baseclasses) to figure out the most derived type that ARG
+ could actually be a pointer to. */
+
+value
+value_from_vtable_info (arg, type)
+ value arg;
+ struct type *type;
+{
+ /* Take care of preliminaries. */
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ fill_in_vptr_fieldno (type);
+ if (TYPE_VPTR_FIELDNO (type) < 0 || VALUE_REPEATED (arg))
+ return 0;
+
+ return value_headof (arg, 0, type);
+}
+
+/* Return true if the INDEXth field of TYPE is a virtual baseclass
+ pointer which is for the base class whose type is BASECLASS. */
+
+static int
+vb_match (type, index, basetype)
+ struct type *type;
+ int index;
+ struct type *basetype;
+{
+ struct type *fieldtype;
+ char *name = TYPE_FIELD_NAME (type, index);
+ char *field_class_name = NULL;
+
+ if (*name != '_')
+ return 0;
+ /* gcc 2.4 uses _vb$. */
+ if (name[1] == 'v' && name[2] == 'b' && name[3] == CPLUS_MARKER)
+ field_class_name = name + 4;
+ /* gcc 2.5 will use __vb_. */
+ if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_')
+ field_class_name = name + 5;
+
+ if (field_class_name == NULL)
+ /* This field is not a virtual base class pointer. */
+ return 0;
+
+ /* It's a virtual baseclass pointer, now we just need to find out whether
+ it is for this baseclass. */
+ fieldtype = TYPE_FIELD_TYPE (type, index);
+ if (fieldtype == NULL
+ || TYPE_CODE (fieldtype) != TYPE_CODE_PTR)
+ /* "Can't happen". */
+ return 0;
+
+ /* What we check for is that either the types are equal (needed for
+ nameless types) or have the same name. This is ugly, and a more
+ elegant solution should be devised (which would probably just push
+ the ugliness into symbol reading unless we change the stabs format). */
+ if (TYPE_TARGET_TYPE (fieldtype) == basetype)
+ return 1;
+
+ if (TYPE_NAME (basetype) != NULL
+ && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL
+ && STREQ (TYPE_NAME (basetype),
+ TYPE_NAME (TYPE_TARGET_TYPE (fieldtype))))
+ return 1;
+ return 0;
+}
+
+/* Compute the offset of the baseclass which is
+ the INDEXth baseclass of class TYPE, for a value ARG,
+ wih extra offset of OFFSET.
+ The result is the offste of the baseclass value relative
+ to (the address of)(ARG) + OFFSET.
+
+ -1 is returned on error. */
+
+int
+baseclass_offset (type, index, arg, offset)
+ struct type *type;
+ int index;
+ value arg;
+ int offset;
+{
+ struct type *basetype = TYPE_BASECLASS (type, index);
+
+ if (BASETYPE_VIA_VIRTUAL (type, index))
+ {
+ /* Must hunt for the pointer to this virtual baseclass. */
+ register int i, len = TYPE_NFIELDS (type);
+ register int n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* First look for the virtual baseclass pointer
+ in the fields. */
+ for (i = n_baseclasses; i < len; i++)
+ {
+ if (vb_match (type, i, basetype))
+ {
+ CORE_ADDR addr
+ = unpack_pointer (TYPE_FIELD_TYPE (type, i),
+ VALUE_CONTENTS (arg) + VALUE_OFFSET (arg)
+ + offset
+ + (TYPE_FIELD_BITPOS (type, i) / 8));
+
+ if (VALUE_LVAL (arg) != lval_memory)
+ return -1;
+
+ return addr -
+ (LONGEST) (VALUE_ADDRESS (arg) + VALUE_OFFSET (arg) + offset);
+ }
+ }
+ /* Not in the fields, so try looking through the baseclasses. */
+ for (i = index+1; i < n_baseclasses; i++)
+ {
+ int boffset =
+ baseclass_offset (type, i, arg, offset);
+ if (boffset)
+ return boffset;
+ }
+ /* Not found. */
+ return -1;
+ }
+
+ /* Baseclass is easily computed. */
+ return TYPE_BASECLASS_BITPOS (type, index) / 8;
+}
+
+/* Compute the address of the baseclass which is
+ the INDEXth baseclass of class TYPE. The TYPE base
+ of the object is at VALADDR.
+
+ If ERRP is non-NULL, set *ERRP to be the errno code of any error,
+ or 0 if no error. In that case the return value is not the address
+ of the baseclasss, but the address which could not be read
+ successfully. */
+
+/* FIXME Fix remaining uses of baseclass_addr to use baseclass_offset */
+
+char *
+baseclass_addr (type, index, valaddr, valuep, errp)
+ struct type *type;
+ int index;
+ char *valaddr;
+ value *valuep;
+ int *errp;
+{
+ struct type *basetype = TYPE_BASECLASS (type, index);
+
+ if (errp)
+ *errp = 0;
+
+ if (BASETYPE_VIA_VIRTUAL (type, index))
+ {
+ /* Must hunt for the pointer to this virtual baseclass. */
+ register int i, len = TYPE_NFIELDS (type);
+ register int n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* First look for the virtual baseclass pointer
+ in the fields. */
+ for (i = n_baseclasses; i < len; i++)
+ {
+ if (vb_match (type, i, basetype))
+ {
+ value val = allocate_value (basetype);
+ CORE_ADDR addr;
+ int status;
+
+ addr
+ = unpack_pointer (TYPE_FIELD_TYPE (type, i),
+ valaddr + (TYPE_FIELD_BITPOS (type, i) / 8));
+
+ status = target_read_memory (addr,
+ VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (basetype));
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+
+ if (status != 0)
+ {
+ if (valuep)
+ *valuep = NULL;
+ release_value (val);
+ value_free (val);
+ if (errp)
+ *errp = status;
+ return (char *)addr;
+ }
+ else
+ {
+ if (valuep)
+ *valuep = val;
+ return (char *) VALUE_CONTENTS (val);
+ }
+ }
+ }
+ /* Not in the fields, so try looking through the baseclasses. */
+ for (i = index+1; i < n_baseclasses; i++)
+ {
+ char *baddr;
+
+ baddr = baseclass_addr (type, i, valaddr, valuep, errp);
+ if (baddr)
+ return baddr;
+ }
+ /* Not found. */
+ if (valuep)
+ *valuep = 0;
+ return 0;
+ }
+
+ /* Baseclass is easily computed. */
+ if (valuep)
+ *valuep = 0;
+ return valaddr + TYPE_BASECLASS_BITPOS (type, index) / 8;
+}
+
+/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at
+ VALADDR.
+
+ Extracting bits depends on endianness of the machine. Compute the
+ number of least significant bits to discard. For big endian machines,
+ we compute the total number of bits in the anonymous object, subtract
+ off the bit count from the MSB of the object to the MSB of the
+ bitfield, then the size of the bitfield, which leaves the LSB discard
+ count. For little endian machines, the discard count is simply the
+ number of bits from the LSB of the anonymous object to the LSB of the
+ bitfield.
+
+ If the field is signed, we also do sign extension. */
+
+LONGEST
+unpack_field_as_long (type, valaddr, fieldno)
+ struct type *type;
+ char *valaddr;
+ int fieldno;
+{
+ unsigned LONGEST val;
+ unsigned LONGEST valmask;
+ int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
+ int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
+ int lsbcount;
+
+ val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val));
+
+ /* Extract bits. See comment above. */
+
+#if BITS_BIG_ENDIAN
+ lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize);
+#else
+ lsbcount = (bitpos % 8);
+#endif
+ val >>= lsbcount;
+
+ /* If the field does not entirely fill a LONGEST, then zero the sign bits.
+ If the field is signed, and is negative, then sign extend. */
+
+ if ((bitsize > 0) && (bitsize < 8 * sizeof (val)))
+ {
+ valmask = (((unsigned LONGEST) 1) << bitsize) - 1;
+ val &= valmask;
+ if (!TYPE_UNSIGNED (TYPE_FIELD_TYPE (type, fieldno)))
+ {
+ if (val & (valmask ^ (valmask >> 1)))
+ {
+ val |= ~valmask;
+ }
+ }
+ }
+ return (val);
+}
+
+/* Modify the value of a bitfield. ADDR points to a block of memory in
+ target byte order; the bitfield starts in the byte pointed to. FIELDVAL
+ is the desired value of the field, in host byte order. BITPOS and BITSIZE
+ indicate which bits (in target bit order) comprise the bitfield. */
+
+void
+modify_field (addr, fieldval, bitpos, bitsize)
+ char *addr;
+ LONGEST fieldval;
+ int bitpos, bitsize;
+{
+ LONGEST oword;
+
+ /* Reject values too big to fit in the field in question,
+ otherwise adjoining fields may be corrupted. */
+ if (bitsize < (8 * sizeof (fieldval))
+ && 0 != (fieldval & ~((1<<bitsize)-1)))
+ {
+ /* FIXME: would like to include fieldval in the message, but
+ we don't have a sprintf_longest. */
+ error ("Value does not fit in %d bits.", bitsize);
+ }
+
+ oword = extract_signed_integer (addr, sizeof oword);
+
+ /* Shifting for bit field depends on endianness of the target machine. */
+#if BITS_BIG_ENDIAN
+ bitpos = sizeof (oword) * 8 - bitpos - bitsize;
+#endif
+
+ /* Mask out old value, while avoiding shifts >= size of oword */
+ if (bitsize < 8 * sizeof (oword))
+ oword &= ~(((((unsigned LONGEST)1) << bitsize) - 1) << bitpos);
+ else
+ oword &= ~((~(unsigned LONGEST)0) << bitpos);
+ oword |= fieldval << bitpos;
+
+ store_signed_integer (addr, sizeof oword, oword);
+}
+
+/* Convert C numbers into newly allocated values */
+
+value
+value_from_longest (type, num)
+ struct type *type;
+ register LONGEST num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ switch (code)
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
+ store_signed_integer (VALUE_CONTENTS_RAW (val), len, num);
+ break;
+
+ case TYPE_CODE_REF:
+ case TYPE_CODE_PTR:
+ /* This assumes that all pointers of a given length
+ have the same form. */
+ store_address (VALUE_CONTENTS_RAW (val), len, (CORE_ADDR) num);
+ break;
+
+ default:
+ error ("Unexpected type encountered for integer constant.");
+ }
+ return val;
+}
+
+value
+value_from_double (type, num)
+ struct type *type;
+ double num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ * (float *) VALUE_CONTENTS_RAW (val) = num;
+ else if (len == sizeof (double))
+ * (double *) VALUE_CONTENTS_RAW (val) = num;
+ else
+ error ("Floating type encountered with unexpected data length.");
+ }
+ else
+ error ("Unexpected type encountered for floating constant.");
+
+ /* num was in host byte order. So now put the value's contents
+ into target byte order. */
+ SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (val), len);
+
+ return val;
+}
+
+/* Deal with the value that is "about to be returned". */
+
+/* Return the value that a function returning now
+ would be returning to its caller, assuming its type is VALTYPE.
+ RETBUF is where we look for what ought to be the contents
+ of the registers (in raw form). This is because it is often
+ desirable to restore old values to those registers
+ after saving the contents of interest, and then call
+ this function using the saved values.
+ struct_return is non-zero when the function in question is
+ using the structure return conventions on the machine in question;
+ 0 when it is using the value returning conventions (this often
+ means returning pointer to where structure is vs. returning value). */
+
+value
+value_being_returned (valtype, retbuf, struct_return)
+ register struct type *valtype;
+ char retbuf[REGISTER_BYTES];
+ int struct_return;
+ /*ARGSUSED*/
+{
+ register value val;
+ CORE_ADDR addr;
+
+#if defined (EXTRACT_STRUCT_VALUE_ADDRESS)
+ /* If this is not defined, just use EXTRACT_RETURN_VALUE instead. */
+ if (struct_return) {
+ addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf);
+ if (!addr)
+ error ("Function return value unknown");
+ return value_at (valtype, addr);
+ }
+#endif
+
+ val = allocate_value (valtype);
+ EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val));
+
+ return val;
+}
+
+/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
+ EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
+ and TYPE is the type (which is known to be struct, union or array).
+
+ On most machines, the struct convention is used unless we are
+ using gcc and the type is of a special size. */
+/* As of about 31 Mar 93, GCC was changed to be compatible with the
+ native compiler. GCC 2.3.3 was the last release that did it the
+ old way. Since gcc2_compiled was not changed, we have no
+ way to correctly win in all cases, so we just do the right thing
+ for gcc1 and for gcc2 after this change. Thus it loses for gcc
+ 2.0-2.3.3. This is somewhat unfortunate, but changing gcc2_compiled
+ would cause more chaos than dealing with some struct returns being
+ handled wrong. */
+#if !defined (USE_STRUCT_CONVENTION)
+#define USE_STRUCT_CONVENTION(gcc_p, type)\
+ (!((gcc_p == 1) && (TYPE_LENGTH (value_type) == 1 \
+ || TYPE_LENGTH (value_type) == 2 \
+ || TYPE_LENGTH (value_type) == 4 \
+ || TYPE_LENGTH (value_type) == 8 \
+ ) \
+ ))
+#endif
+
+/* Return true if the function specified is using the structure returning
+ convention on this machine to return arguments, or 0 if it is using
+ the value returning convention. FUNCTION is the value representing
+ the function, FUNCADDR is the address of the function, and VALUE_TYPE
+ is the type returned by the function. GCC_P is nonzero if compiled
+ with GCC. */
+
+int
+using_struct_return (function, funcaddr, value_type, gcc_p)
+ value function;
+ CORE_ADDR funcaddr;
+ struct type *value_type;
+ int gcc_p;
+ /*ARGSUSED*/
+{
+ register enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_ERROR)
+ error ("Function return type unknown.");
+
+ if (code == TYPE_CODE_STRUCT ||
+ code == TYPE_CODE_UNION ||
+ code == TYPE_CODE_ARRAY)
+ return USE_STRUCT_CONVENTION (gcc_p, value_type);
+
+ return 0;
+}
+
+/* Store VAL so it will be returned if a function returns now.
+ Does not verify that VAL's type matches what the current
+ function wants to return. */
+
+void
+set_return_value (val)
+ value val;
+{
+ register enum type_code code = TYPE_CODE (VALUE_TYPE (val));
+ double dbuf;
+ LONGEST lbuf;
+
+ if (code == TYPE_CODE_ERROR)
+ error ("Function return type unknown.");
+
+ if ( code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION) /* FIXME, implement struct return. */
+ error ("GDB does not support specifying a struct or union return value.");
+
+ /* FIXME, this is bogus. We don't know what the return conventions
+ are, or how values should be promoted.... */
+ if (code == TYPE_CODE_FLT)
+ {
+ dbuf = value_as_double (val);
+
+ STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&dbuf);
+ }
+ else
+ {
+ lbuf = value_as_long (val);
+ STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&lbuf);
+ }
+}
+
+void
+_initialize_values ()
+{
+ add_cmd ("convenience", no_class, show_convenience,
+ "Debugger convenience (\"$foo\") variables.\n\
+These variables are created when you assign them values;\n\
+thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\
+A few convenience variables are given values automatically:\n\
+\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\
+\"$__\" holds the contents of the last address examined with \"x\".",
+ &showlist);
+
+ add_cmd ("values", no_class, show_values,
+ "Elements of value history around item number IDX (or last ten).",
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/version.c b/gnu/usr.bin/gdb/gdb/version.c
new file mode 100644
index 000000000000..d32e958a2dd1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/version.c
@@ -0,0 +1,3 @@
+char *version = "4.11";
+char *host_canonical = "i386-unknown-freebsd";
+char *target_canonical = "i386-unknown-freebsd";
diff --git a/gnu/usr.bin/gdb/gdb/wait.h b/gnu/usr.bin/gdb/gdb/wait.h
new file mode 100644
index 000000000000..a72943cd9ee0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/wait.h
@@ -0,0 +1,38 @@
+/* Define how to access the int that the wait system call stores.
+ This has been compatible in all Unix systems since time immemorial,
+ but various well-meaning people have defined various different
+ words for the same old bits in the same old int (sometimes claimed
+ to be a struct). We just know it's an int and we use these macros
+ to access the bits. */
+
+/* The following macros are defined equivalently to their definitions
+ in POSIX.1. We fail to define WNOHANG and WUNTRACED, which POSIX.1
+ <sys/wait.h> defines, since our code does not use waitpid(). We
+ also fail to declare wait() and waitpid(). */
+
+#define WIFEXITED(w) (((w)&0377) == 0)
+#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
+#ifdef IBM6000
+
+/* Unfortunately, the above comment (about being compatible in all Unix
+ systems) is not quite correct for AIX, sigh. And AIX 3.2 can generate
+ status words like 0x57c (sigtrap received after load), and gdb would
+ choke on it. */
+
+#define WIFSTOPPED(w) ((w)&0x40)
+
+#else
+#define WIFSTOPPED(w) (((w)&0377) == 0177)
+#endif
+
+#define WEXITSTATUS(w) (((w) >> 8) & 0377) /* same as WRETCODE */
+#define WTERMSIG(w) ((w) & 0177)
+#define WSTOPSIG WEXITSTATUS
+
+/* These are not defined in POSIX, but are used by our programs. */
+
+#define WAITTYPE int
+
+#define WCOREDUMP(w) (((w)&0200) != 0)
+#define WSETEXIT(w,status) ((w) = (0 | ((status) << 8)))
+#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
diff --git a/gnu/usr.bin/gdb/gdb/xm.h b/gnu/usr.bin/gdb/gdb/xm.h
new file mode 100644
index 000000000000..8d28df0b713f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/xm.h
@@ -0,0 +1,31 @@
+/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HOST_BYTE_ORDER LITTLE_ENDIAN
+
+#include <machine/limits.h> /* for INT_MIN, to avoid "INT_MIN
+ redefined" warnings from defs.h */
+
+/* psignal() is in <signal.h>. */
+
+#define PSIGNAL_IN_SIGNAL_H
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#define SET_STACK_LIMIT_HUGE
diff --git a/gnu/usr.bin/gdb/kgdb_proto.h b/gnu/usr.bin/gdb/kgdb_proto.h
deleted file mode 100644
index 9da8d2b4eba3..000000000000
--- a/gnu/usr.bin/gdb/kgdb_proto.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Steven McCanne of Lawrence Berkeley Laboratory.
- *
- * 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.
- *
- * @(#)kgdb_proto.h 6.3 (Berkeley) 5/8/91
- *
- *
- * $Header: /home/cvs/386BSD/src/gnu/usr.bin/gdb/kgdb_proto.h,v 1.1 1993/06/29 09:47:25 nate Exp $ (LBL)
- */
-
-/*
- * Message types.
- */
-#define KGDB_MEM_R 0x01
-#define KGDB_MEM_W 0x02
-#define KGDB_REG_R 0x03
-#define KGDB_REG_W 0x04
-#define KGDB_CONT 0x05
-#define KGDB_STEP 0x06
-#define KGDB_KILL 0x07
-#define KGDB_SIGNAL 0x08
-#define KGDB_EXEC 0x09
-
-#define KGDB_CMD(x) ((x) & 0x0f)
-
-/*
- * Message flags.
- */
-#define KGDB_ACK 0x80
-#define KGDB_DELTA 0x40
-#define KGDB_MORE 0x20
-#define KGDB_SEQ 0x10
diff --git a/gnu/usr.bin/gdb/libiberty/COPYING.LIB b/gnu/usr.bin/gdb/libiberty/COPYING.LIB
new file mode 100644
index 000000000000..eb685a5ec981
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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/gnu/usr.bin/gdb/libiberty/Makefile b/gnu/usr.bin/gdb/libiberty/Makefile
new file mode 100644
index 000000000000..838781295e82
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/Makefile
@@ -0,0 +1,13 @@
+LIB= iberty
+SRCS= argv.c basename.c concat.c cplus-dem.c fdmatch.c getopt.c \
+ getopt1.c ieee-float.c obstack.c spaces.c strerror.c strsignal.c \
+ xmalloc.c
+
+CFLAGS+= -I$(.CURDIR)/../gdb/.
+NOPROFILE=no
+NOPIC=no
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/libiberty/README.FreeBSD b/gnu/usr.bin/gdb/libiberty/README.FreeBSD
new file mode 100644
index 000000000000..573fa0a9a809
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libiberty directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libiberty will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/libiberty/alloca-conf.h b/gnu/usr.bin/gdb/libiberty/alloca-conf.h
new file mode 100644
index 000000000000..e1d9177893a1
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/alloca-conf.h
@@ -0,0 +1,11 @@
+/* "Normal" configuration for alloca. */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+#else
+char *alloca ();
+#endif /* sparc */
+#endif /* not __GNUC__ */
diff --git a/gnu/usr.bin/gdb/libiberty/argv.c b/gnu/usr.bin/gdb/libiberty/argv.c
new file mode 100644
index 000000000000..fed46e7d797b
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/argv.c
@@ -0,0 +1,332 @@
+/* Create and destroy argument vectors (argv's)
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/* Create and destroy argument vectors. An argument vector is simply an
+ array of string pointers, terminated by a NULL pointer. */
+
+/* AIX requires this to be the first thing in the file. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+extern char *__builtin_alloca(); /* Stupid include file doesn't declare it */
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif /* sparc */
+#endif /* not __GNUC__ */
+
+#define isspace(ch) ((ch) == ' ' || (ch) == '\t')
+
+#include "alloca-conf.h"
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+
+#include <stddef.h>
+extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
+extern size_t strlen (const char *s); /* 4.11.6.3 */
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
+extern void free (void *ptr); /* 4.10.3.2 */
+extern char *strdup (const char *s); /* Non-ANSI */
+
+#else /* !__STDC__ */
+
+extern char *memcpy (); /* Copy memory region */
+extern int strlen (); /* Count length of string */
+extern char *malloc (); /* Standard memory allocater */
+extern char *realloc (); /* Standard memory reallocator */
+extern void free (); /* Free malloc'd memory */
+extern char *strdup (); /* Duplicate a string */
+
+#endif /* __STDC__ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EOS
+#define EOS '\0'
+#endif
+
+#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
+
+
+/*
+
+NAME
+
+ freeargv -- free an argument vector
+
+SYNOPSIS
+
+ void freeargv (vector)
+ char **vector;
+
+DESCRIPTION
+
+ Free an argument vector that was built using buildargv. Simply scans
+ through the vector, freeing the memory for each argument until the
+ terminating NULL is found, and then frees the vector itself.
+
+RETURNS
+
+ No value.
+
+*/
+
+void freeargv (vector)
+char **vector;
+{
+ register char **scan;
+
+ if (vector != NULL)
+ {
+ for (scan = vector; *scan != NULL; scan++)
+ {
+ free (*scan);
+ }
+ free (vector);
+ }
+}
+
+/*
+
+NAME
+
+ buildargv -- build an argument vector from a string
+
+SYNOPSIS
+
+ char **buildargv (sp)
+ char *sp;
+
+DESCRIPTION
+
+ Given a pointer to a string, parse the string extracting fields
+ separated by whitespace and optionally enclosed within either single
+ or double quotes (which are stripped off), and build a vector of
+ pointers to copies of the string for each field. The input string
+ remains unchanged.
+
+ All of the memory for the pointer array and copies of the string
+ is obtained from malloc. All of the memory can be returned to the
+ system with the single function call freeargv, which takes the
+ returned result of buildargv, as it's argument.
+
+ The memory for the argv array is dynamically expanded as necessary.
+
+RETURNS
+
+ Returns a pointer to the argument vector if successful. Returns NULL
+ if the input string pointer is NULL or if there is insufficient
+ memory to complete building the argument vector.
+
+NOTES
+
+ In order to provide a working buffer for extracting arguments into,
+ with appropriate stripping of quotes and translation of backslash
+ sequences, we allocate a working buffer at least as long as the input
+ string. This ensures that we always have enough space in which to
+ work, since the extracted arg is never larger than the input string.
+
+ If the input is a null string (as opposed to a NULL pointer), then
+ buildarg returns an argv that has one arg, a null string.
+
+ Argv is always kept terminated with a NULL arg pointer, so it can
+ be passed to freeargv at any time, or returned, as appropriate.
+*/
+
+char **buildargv (input)
+char *input;
+{
+ char *arg;
+ char *copybuf;
+ int squote = 0;
+ int dquote = 0;
+ int bsquote = 0;
+ int argc = 0;
+ int maxargc = 0;
+ char **argv = NULL;
+ char **nargv;
+
+ if (input != NULL)
+ {
+ copybuf = alloca (strlen (input) + 1);
+ /* Is a do{}while to always execute the loop once. Always return an
+ argv, even for null strings. See NOTES above, test case below. */
+ do
+ {
+ /* Pick off argv[argc] */
+ while (isspace (*input))
+ {
+ input++;
+ }
+ if ((maxargc == 0) || (argc >= (maxargc - 1)))
+ {
+ /* argv needs initialization, or expansion */
+ if (argv == NULL)
+ {
+ maxargc = INITIAL_MAXARGC;
+ nargv = (char **) malloc (maxargc * sizeof (char *));
+ }
+ else
+ {
+ maxargc *= 2;
+ nargv = (char **) realloc (argv, maxargc * sizeof (char *));
+ }
+ if (nargv == NULL)
+ {
+ if (argv != NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ }
+ break;
+ }
+ argv = nargv;
+ argv[argc] = NULL;
+ }
+ /* Begin scanning arg */
+ arg = copybuf;
+ while (*input != EOS)
+ {
+ if (isspace (*input) && !squote && !dquote && !bsquote)
+ {
+ break;
+ }
+ else
+ {
+ if (bsquote)
+ {
+ bsquote = 0;
+ *arg++ = *input;
+ }
+ else if (*input == '\\')
+ {
+ bsquote = 1;
+ }
+ else if (squote)
+ {
+ if (*input == '\'')
+ {
+ squote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else if (dquote)
+ {
+ if (*input == '"')
+ {
+ dquote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else
+ {
+ if (*input == '\'')
+ {
+ squote = 1;
+ }
+ else if (*input == '"')
+ {
+ dquote = 1;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ input++;
+ }
+ }
+ *arg = EOS;
+ argv[argc] = strdup (copybuf);
+ if (argv[argc] == NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ break;
+ }
+ argc++;
+ argv[argc] = NULL;
+ }
+ while (*input != EOS);
+ }
+ return (argv);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+static char *tests[] =
+{
+ "a simple command line",
+ "arg 'foo' is single quoted",
+ "arg \"bar\" is double quoted",
+ "arg \"foo bar\" has embedded whitespace",
+ "arg 'Jack said \\'hi\\'' has single quotes",
+ "arg 'Jack said \\\"hi\\\"' has double quotes",
+ "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
+ "",
+ NULL
+};
+
+main ()
+{
+ char **argv;
+ char **test;
+ char **targs;
+
+ for (test = tests; *test != NULL; test++)
+ {
+ printf ("buildargv(\"%s\")\n", *test);
+ if ((argv = buildargv (*test)) == NULL)
+ {
+ printf ("failed!\n\n");
+ }
+ else
+ {
+ for (targs = argv; *targs != NULL; targs++)
+ {
+ printf ("\t\"%s\"\n", *targs);
+ }
+ printf ("\n");
+ }
+ freeargv (argv);
+ }
+
+}
+
+#endif /* MAIN */
diff --git a/gnu/usr.bin/gdb/libiberty/basename.c b/gnu/usr.bin/gdb/libiberty/basename.c
new file mode 100644
index 000000000000..f61a308e9b53
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/basename.c
@@ -0,0 +1,56 @@
+/* Return the basename of a pathname.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+
+NAME
+
+ basename -- return pointer to last component of a pathname
+
+SYNOPSIS
+
+ char *basename (char *name)
+
+DESCRIPTION
+
+ Given a pointer to a string containing a typical pathname
+ (/usr/src/cmd/ls/ls.c for example), returns a pointer to the
+ last component of the pathname ("ls.c" in this case).
+
+BUGS
+
+ Presumes a UNIX style path with UNIX style separators.
+*/
+
+
+char *
+basename (name)
+ char *name;
+{
+ char *base = name;
+
+ while (*name)
+ {
+ if (*name++ == '/')
+ {
+ base = name;
+ }
+ }
+ return (base);
+}
diff --git a/gnu/usr.bin/gdb/libiberty/concat.c b/gnu/usr.bin/gdb/libiberty/concat.c
new file mode 100644
index 000000000000..61f7d97481ce
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/concat.c
@@ -0,0 +1,118 @@
+/* Concatenate variable number of strings.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/*
+
+NAME
+
+ concat -- concatenate a variable number of strings
+
+SYNOPSIS
+
+ #include <varargs.h>
+
+ char *concat (s1, s2, s3, ..., NULL)
+
+DESCRIPTION
+
+ Concatenate a variable number of strings and return the result
+ in freshly malloc'd memory.
+
+ Returns NULL if insufficient memory is available. The argument
+ list is terminated by the first NULL pointer encountered. Pointers
+ to empty strings are ignored.
+
+NOTES
+
+ This function uses xmalloc() which is expected to be a front end
+ function to malloc() that deals with low memory situations. In
+ typical use, if malloc() returns NULL then xmalloc() diverts to an
+ error handler routine which never returns, and thus xmalloc will
+ never return a NULL pointer. If the client application wishes to
+ deal with low memory situations itself, it should supply an xmalloc
+ that just directly invokes malloc and blindly returns whatever
+ malloc returns.
+*/
+
+
+#include <varargs.h>
+
+#define NULLP (char *)0
+
+extern char *xmalloc ();
+
+/* VARARGS */
+char *
+concat (va_alist)
+ va_dcl
+{
+ register int length = 0;
+ register char *newstr;
+ register char *end;
+ register char *arg;
+ va_list args;
+
+ /* First compute the size of the result and get sufficient memory. */
+
+ va_start (args);
+ while ((arg = va_arg (args, char *)) != NULLP)
+ {
+ length += strlen (arg);
+ }
+ newstr = (char *) xmalloc (length + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+
+ if (newstr != NULLP)
+ {
+ va_start (args);
+ end = newstr;
+ while ((arg = va_arg (args, char *)) != NULLP)
+ {
+ while (*arg)
+ {
+ *end++ = *arg++;
+ }
+ }
+ *end = '\000';
+ va_end (args);
+ }
+
+ return (newstr);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+main ()
+{
+ printf ("\"\" = \"%s\"\n", concat (NULLP));
+ printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));
+ printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP));
+ printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP));
+ printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP));
+ printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP));
+ printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP));
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/config.h b/gnu/usr.bin/gdb/libiberty/config.h
new file mode 100644
index 000000000000..b37ee84a78ab
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/config.h
@@ -0,0 +1 @@
+/* !Automatically generated from ./functions.def - DO NOT EDIT! */
diff --git a/gnu/usr.bin/gdb/libiberty/cplus-dem.c b/gnu/usr.bin/gdb/libiberty/cplus-dem.c
new file mode 100644
index 000000000000..2ad0e971487b
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/cplus-dem.c
@@ -0,0 +1,2669 @@
+/* Demangler for GNU C++
+ Copyright 1989, 1991 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.uucp)
+ Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+#include <demangle.h>
+#undef CURRENT_DEMANGLING_STYLE
+#define CURRENT_DEMANGLING_STYLE work->options
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+extern char *xmalloc PARAMS((long));
+extern char *xrealloc PARAMS((PTR, long));
+extern char *strstr PARAMS ((const char *, const char *));
+extern void free PARAMS((PTR));
+
+/* In order to allow a single demangler executable to demangle strings
+ using various common values of CPLUS_MARKER, as well as any specific
+ one set at compile time, we maintain a string containing all the
+ commonly used ones, and check to see if the marker we are looking for
+ is in that string. CPLUS_MARKER is usually '$' on systems where the
+ assembler can deal with that. Where the assembler can't, it's usually
+ '.' (but on many systems '.' is used for other things). We put the
+ current defined CPLUS_MARKER first (which defaults to '$'), followed
+ by the next most common value, followed by an explicit '$' in case
+ the value of CPLUS_MARKER is not '$'.
+
+ We could avoid this if we could just get g++ to tell us what the actual
+ cplus marker character is as part of the debug information, perhaps by
+ ensuring that it is the character that terminates the gcc<n>_compiled
+ marker symbol (FIXME). */
+
+#if !defined (CPLUS_MARKER)
+#define CPLUS_MARKER '$'
+#endif
+
+enum demangling_styles current_demangling_style = gnu_demangling;
+
+static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
+
+void
+set_cplus_marker_for_demangling (ch)
+ int ch;
+{
+ cplus_markers[0] = ch;
+}
+
+/* Stuff that is shared between sub-routines.
+ * Using a shared structure allows cplus_demangle to be reentrant. */
+
+struct work_stuff
+{
+ int options;
+ char **typevec;
+ int ntypes;
+ int typevec_size;
+ int constructor;
+ int destructor;
+ int static_type; /* A static member function */
+ int const_type; /* A const member function */
+};
+
+#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
+#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS)
+
+static CONST struct optable
+{
+ CONST char *in;
+ CONST char *out;
+ int flags;
+} optable[] = {
+ {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"new", " new", 0}, /* old (1.91, and 1.x) */
+ {"delete", " delete", 0}, /* old (1.91, and 1.x) */
+ {"as", "=", DMGL_ANSI}, /* ansi */
+ {"ne", "!=", DMGL_ANSI}, /* old, ansi */
+ {"eq", "==", DMGL_ANSI}, /* old, ansi */
+ {"ge", ">=", DMGL_ANSI}, /* old, ansi */
+ {"gt", ">", DMGL_ANSI}, /* old, ansi */
+ {"le", "<=", DMGL_ANSI}, /* old, ansi */
+ {"lt", "<", DMGL_ANSI}, /* old, ansi */
+ {"plus", "+", 0}, /* old */
+ {"pl", "+", DMGL_ANSI}, /* ansi */
+ {"apl", "+=", DMGL_ANSI}, /* ansi */
+ {"minus", "-", 0}, /* old */
+ {"mi", "-", DMGL_ANSI}, /* ansi */
+ {"ami", "-=", DMGL_ANSI}, /* ansi */
+ {"mult", "*", 0}, /* old */
+ {"ml", "*", DMGL_ANSI}, /* ansi */
+ {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */
+ {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */
+ {"convert", "+", 0}, /* old (unary +) */
+ {"negate", "-", 0}, /* old (unary -) */
+ {"trunc_mod", "%", 0}, /* old */
+ {"md", "%", DMGL_ANSI}, /* ansi */
+ {"amd", "%=", DMGL_ANSI}, /* ansi */
+ {"trunc_div", "/", 0}, /* old */
+ {"dv", "/", DMGL_ANSI}, /* ansi */
+ {"adv", "/=", DMGL_ANSI}, /* ansi */
+ {"truth_andif", "&&", 0}, /* old */
+ {"aa", "&&", DMGL_ANSI}, /* ansi */
+ {"truth_orif", "||", 0}, /* old */
+ {"oo", "||", DMGL_ANSI}, /* ansi */
+ {"truth_not", "!", 0}, /* old */
+ {"nt", "!", DMGL_ANSI}, /* ansi */
+ {"postincrement","++", 0}, /* old */
+ {"pp", "++", DMGL_ANSI}, /* ansi */
+ {"postdecrement","--", 0}, /* old */
+ {"mm", "--", DMGL_ANSI}, /* ansi */
+ {"bit_ior", "|", 0}, /* old */
+ {"or", "|", DMGL_ANSI}, /* ansi */
+ {"aor", "|=", DMGL_ANSI}, /* ansi */
+ {"bit_xor", "^", 0}, /* old */
+ {"er", "^", DMGL_ANSI}, /* ansi */
+ {"aer", "^=", DMGL_ANSI}, /* ansi */
+ {"bit_and", "&", 0}, /* old */
+ {"ad", "&", DMGL_ANSI}, /* ansi */
+ {"aad", "&=", DMGL_ANSI}, /* ansi */
+ {"bit_not", "~", 0}, /* old */
+ {"co", "~", DMGL_ANSI}, /* ansi */
+ {"call", "()", 0}, /* old */
+ {"cl", "()", DMGL_ANSI}, /* ansi */
+ {"alshift", "<<", 0}, /* old */
+ {"ls", "<<", DMGL_ANSI}, /* ansi */
+ {"als", "<<=", DMGL_ANSI}, /* ansi */
+ {"arshift", ">>", 0}, /* old */
+ {"rs", ">>", DMGL_ANSI}, /* ansi */
+ {"ars", ">>=", DMGL_ANSI}, /* ansi */
+ {"component", "->", 0}, /* old */
+ {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */
+ {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */
+ {"indirect", "*", 0}, /* old */
+ {"method_call", "->()", 0}, /* old */
+ {"addr", "&", 0}, /* old (unary &) */
+ {"array", "[]", 0}, /* old */
+ {"vc", "[]", DMGL_ANSI}, /* ansi */
+ {"compound", ", ", 0}, /* old */
+ {"cm", ", ", DMGL_ANSI}, /* ansi */
+ {"cond", "?:", 0}, /* old */
+ {"cn", "?:", DMGL_ANSI}, /* psuedo-ansi */
+ {"max", ">?", 0}, /* old */
+ {"mx", ">?", DMGL_ANSI}, /* psuedo-ansi */
+ {"min", "<?", 0}, /* old */
+ {"mn", "<?", DMGL_ANSI}, /* psuedo-ansi */
+ {"nop", "", 0}, /* old (for operator=) */
+ {"rm", "->*", DMGL_ANSI} /* ansi */
+};
+
+
+typedef struct string /* Beware: these aren't required to be */
+{ /* '\0' terminated. */
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#define STRING_EMPTY(str) ((str) -> b == (str) -> p)
+#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
+ string_prepend(str, " ");}
+#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
+ string_append(str, " ");}
+
+#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */
+#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */
+
+/* Prototypes for local functions */
+
+static char *
+mop_up PARAMS ((struct work_stuff *, string *, int));
+
+#if 0
+static int
+demangle_method_args PARAMS ((struct work_stuff *work, CONST char **, string *));
+#endif
+
+static int
+demangle_template PARAMS ((struct work_stuff *work, CONST char **, string *,
+ string *));
+
+static int
+demangle_qualified PARAMS ((struct work_stuff *, CONST char **, string *,
+ int, int));
+
+static int
+demangle_class PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_fund_type PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_signature PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_prefix PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+gnu_special PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+arm_special PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static void
+string_need PARAMS ((string *, int));
+
+static void
+string_delete PARAMS ((string *));
+
+static void
+string_init PARAMS ((string *));
+
+static void
+string_clear PARAMS ((string *));
+
+#if 0
+static int
+string_empty PARAMS ((string *));
+#endif
+
+static void
+string_append PARAMS ((string *, CONST char *));
+
+static void
+string_appends PARAMS ((string *, string *));
+
+static void
+string_appendn PARAMS ((string *, CONST char *, int));
+
+static void
+string_prepend PARAMS ((string *, CONST char *));
+
+static void
+string_prependn PARAMS ((string *, CONST char *, int));
+
+static int
+get_count PARAMS ((CONST char **, int *));
+
+static int
+consume_count PARAMS ((CONST char **));
+
+static int
+demangle_args PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+do_type PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+do_arg PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static void
+demangle_function_name PARAMS ((struct work_stuff *, CONST char **, string *,
+ CONST char *));
+
+static void
+remember_type PARAMS ((struct work_stuff *, CONST char *, int));
+
+static void
+forget_types PARAMS ((struct work_stuff *));
+
+static void
+string_prepends PARAMS ((string *, string *));
+
+/* Translate count to integer, consuming tokens in the process.
+ Conversion terminates on the first non-digit character.
+ Trying to consume something that isn't a count results in
+ no consumption of input and a return of 0. */
+
+static int
+consume_count (type)
+ CONST char **type;
+{
+ int count = 0;
+
+ while (isdigit (**type))
+ {
+ count *= 10;
+ count += **type - '0';
+ (*type)++;
+ }
+ return (count);
+}
+
+/* Takes operator name as e.g. "++" and returns mangled
+ operator name (e.g. "postincrement_expr"), or NULL if not found.
+
+ If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
+ if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */
+
+char *
+cplus_mangle_opname (opname, options)
+ char *opname;
+ int options;
+{
+ int i;
+ int len;
+
+ len = strlen (opname);
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].out) == len
+ && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
+ && memcmp (optable[i].out, opname, len) == 0)
+ return ((char *)optable[i].in);
+ }
+ return (0);
+}
+
+/* check to see whether MANGLED can match TEXT in the first TEXT_LEN
+ characters. */
+
+int cplus_match (mangled, text, text_len)
+ CONST char *mangled;
+ char *text;
+ int text_len;
+{
+ if (strncmp (mangled, text, text_len) != 0) {
+ return(0); /* cannot match either */
+ } else {
+ return(1); /* matches mangled, may match demangled */
+ }
+}
+
+/* char *cplus_demangle (const char *name, int options)
+
+ If NAME is a mangled function name produced by GNU C++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ The OPTIONS arg may contain one or more of the following bits:
+
+ DMGL_ANSI ANSI qualifiers such as `const' and `void' are
+ included.
+ DMGL_PARAMS Function parameters are included.
+
+ For example,
+
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", 0) => "A::foo"
+
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", 0) => "A::foo"
+
+ Note that any leading underscores, or other such characters prepended by
+ the compilation system, are presumed to have already been stripped from
+ TYPE. */
+
+char *
+cplus_demangle (mangled, options)
+ CONST char *mangled;
+ int options;
+{
+ string decl;
+ int success = 0;
+ struct work_stuff work[1];
+ char *demangled = NULL;
+
+ if ((mangled != NULL) && (*mangled != '\0'))
+ {
+ memset ((char *) work, 0, sizeof (work));
+ work -> options = options;
+ if ((work->options & DMGL_STYLE_MASK) == 0)
+ work->options |= (int)current_demangling_style & DMGL_STYLE_MASK;
+
+ string_init (&decl);
+
+ /* First check to see if gnu style demangling is active and if the
+ string to be demangled contains a CPLUS_MARKER. If so, attempt to
+ recognize one of the gnu special forms rather than looking for a
+ standard prefix. In particular, don't worry about whether there
+ is a "__" string in the mangled string. Consider "_$_5__foo" for
+ example. */
+
+ if ((AUTO_DEMANGLING || GNU_DEMANGLING))
+ {
+ success = gnu_special (work, &mangled, &decl);
+ }
+ if (!success)
+ {
+ success = demangle_prefix (work, &mangled, &decl);
+ }
+ if (success && (*mangled != '\0'))
+ {
+ success = demangle_signature (work, &mangled, &decl);
+ }
+ if (work->constructor == 2)
+ {
+ string_prepend(&decl, "global constructors keyed to ");
+ work->constructor = 0;
+ }
+ else if (work->destructor == 2)
+ {
+ string_prepend(&decl, "global destructors keyed to ");
+ work->destructor = 0;
+ }
+ demangled = mop_up (work, &decl, success);
+ }
+ return (demangled);
+}
+
+static char *
+mop_up (work, declp, success)
+ struct work_stuff *work;
+ string *declp;
+ int success;
+{
+ char *demangled = NULL;
+
+ /* Discard the remembered types, if any. */
+
+ forget_types (work);
+ if (work -> typevec != NULL)
+ {
+ free ((char *) work -> typevec);
+ }
+
+ /* If demangling was successful, ensure that the demangled string is null
+ terminated and return it. Otherwise, free the demangling decl. */
+
+ if (!success)
+ {
+ string_delete (declp);
+ }
+ else
+ {
+ string_appendn (declp, "", 1);
+ demangled = declp -> b;
+ }
+ return (demangled);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_signature -- demangle the signature part of a mangled name
+
+SYNOPSIS
+
+ static int
+ demangle_signature (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the signature portion of the mangled name.
+
+ DECLP is the string where demangled output is being built. At
+ entry it contains the demangled root name from the mangled name
+ prefix. I.E. either a demangled operator name or the root function
+ name. In some special cases, it may contain nothing.
+
+ *MANGLED points to the current unconsumed location in the mangled
+ name. As tokens are consumed and demangling is performed, the
+ pointer is updated to continuously point at the next token to
+ be consumed.
+
+ Demangling GNU style mangled names is nasty because there is no
+ explicit token that marks the start of the outermost function
+ argument list.
+*/
+
+static int
+demangle_signature (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 1;
+ int func_done = 0;
+ int expect_func = 0;
+ CONST char *oldmangled = NULL;
+ string trawname;
+ string tname;
+
+ while (success && (**mangled != '\0'))
+ {
+ switch (**mangled)
+ {
+ case 'Q':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'S':
+ /* Static member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> static_type = 1;
+ break;
+
+ case 'C':
+ /* a const member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> const_type = 1;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_class (work, mangled, declp);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'F':
+ /* Function */
+ /* ARM style demangling includes a specific 'F' character after
+ the class name. For GNU style, it is just implied. So we can
+ safely just consume any 'F' at this point and be compatible
+ with either style. */
+
+ oldmangled = NULL;
+ func_done = 1;
+ (*mangled)++;
+
+ /* For lucid/ARM style we have to forget any types we might
+ have remembered up to this point, since they were not argument
+ types. GNU style considers all types seen as available for
+ back references. See comment in demangle_args() */
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+ forget_types (work);
+ }
+ success = demangle_args (work, mangled, declp);
+ break;
+
+ case 't':
+ /* G++ Template */
+ string_init(&trawname);
+ string_init(&tname);
+ success = demangle_template (work, mangled, &tname, &trawname);
+ string_append(&tname, "::");
+ string_prepends(declp, &tname);
+ if (work -> destructor & 1)
+ {
+ string_prepend (&trawname, "~");
+ string_appends (declp, &trawname);
+ work->destructor -= 1;
+ }
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_appends (declp, &trawname);
+ work->constructor -= 1;
+ }
+ string_delete(&trawname);
+ string_delete(&tname);
+ expect_func = 1;
+ break;
+
+ case '_':
+ /* At the outermost level, we cannot have a return type specified,
+ so if we run into another '_' at this point we are dealing with
+ a mangled name that is either bogus, or has been mangled by
+ some algorithm we don't know how to deal with. So just
+ reject the entire demangling. */
+ success = 0;
+ break;
+
+ default:
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ }
+ else
+ {
+ /* Non-GNU demanglers use a specific token to mark the start
+ of the outermost function argument tokens. Typically 'F',
+ for ARM-demangling, for example. So if we find something
+ we are not prepared for, it must be an error. */
+ success = 0;
+ }
+ break;
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ if (success && expect_func)
+ {
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ }
+ if (success && !func_done)
+ {
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added to
+ the current declp. Note that with ARM, the first case
+ represents the name of a static data member 'foo::bar',
+ which is in the current declp, so we leave it alone. */
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ if (success && work -> static_type && PRINT_ARG_TYPES)
+ {
+ string_append (declp, " static");
+ }
+ if (success && work -> const_type && PRINT_ARG_TYPES)
+ {
+ string_append (declp, " const");
+ }
+ return (success);
+}
+
+#if 0
+
+static int
+demangle_method_args (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 0;
+
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ return (success);
+}
+
+#endif
+
+static int
+demangle_template (work, mangled, tname, trawname)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *tname;
+ string *trawname;
+{
+ int i;
+ int is_pointer;
+ int is_real;
+ int is_integral;
+ int r;
+ int need_comma = 0;
+ int success = 0;
+ int done;
+ CONST char *old_p;
+ CONST char *start;
+ int symbol_len;
+ string temp;
+
+ (*mangled)++;
+ start = *mangled;
+ /* get template name */
+ if ((r = consume_count (mangled)) == 0)
+ {
+ return (0);
+ }
+ if (trawname)
+ string_appendn (trawname, *mangled, r);
+ string_appendn (tname, *mangled, r);
+ *mangled += r;
+ string_append (tname, "<");
+ /* get size of template parameter list */
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ for (i = 0; i < r; i++)
+ {
+ if (need_comma)
+ {
+ string_append (tname, ", ");
+ }
+ /* Z for type parameters */
+ if (**mangled == 'Z')
+ {
+ (*mangled)++;
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* otherwise, value parameter */
+ old_p = *mangled;
+ is_pointer = 0;
+ is_real = 0;
+ is_integral = 0;
+ done = 0;
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ string_append (tname, "=");
+ while (*old_p && !done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'R':
+ done = is_pointer = 1;
+ break;
+ case 'C': /* const */
+ case 'S': /* explicitly signed [char] */
+ case 'U': /* unsigned */
+ case 'V': /* volatile */
+ case 'F': /* function */
+ case 'M': /* member function */
+ case 'O': /* ??? */
+ old_p++;
+ continue;
+ case 'Q': /* repetition of following */
+ case 'T': /* remembered type */
+ abort ();
+ break;
+ case 'v': /* void */
+ abort ();
+ break;
+ case 'x': /* long long */
+ case 'l': /* long */
+ case 'i': /* int */
+ case 's': /* short */
+ case 'c': /* char */
+ case 'w': /* wchar_t */
+ done = is_integral = 1;
+ break;
+ case 'r': /* long double */
+ case 'd': /* double */
+ case 'f': /* float */
+ done = is_real = 1;
+ break;
+ default:
+ abort ();
+ }
+ }
+ if (is_integral)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (tname, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ else if (is_real)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (tname, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ if (**mangled == '.') /* fraction */
+ {
+ string_appendn (tname, ".", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ if (**mangled == 'e') /* exponent */
+ {
+ string_appendn (tname, "e", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ }
+ else if (is_pointer)
+ {
+ if (!get_count (mangled, &symbol_len))
+ {
+ success = 0;
+ break;
+ }
+ string_appendn (tname, *mangled, symbol_len);
+ *mangled += symbol_len;
+ }
+ }
+ need_comma = 1;
+ }
+ string_append (tname, ">");
+
+/*
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+*/
+ return (success);
+}
+
+static int
+arm_pt (work, mangled, n, anchor, args)
+ struct work_stuff *work;
+ CONST char *mangled;
+ int n;
+ CONST char **anchor, **args;
+{
+ /* ARM template? */
+ if (ARM_DEMANGLING && (*anchor = strstr(mangled, "__pt__")))
+ {
+ int len;
+ *args = *anchor + 6;
+ len = consume_count (args);
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+demangle_class_name (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 0;
+
+ n = consume_count (mangled);
+ if (strlen (*mangled) >= n)
+ {
+ CONST char *p;
+ CONST char *args;
+ CONST char *e = *mangled + n;
+ /* ARM template? */
+ if (arm_pt (work, *mangled, n, &p, &args))
+ {
+ string arg;
+ string_init (&arg);
+ string_appendn (declp, *mangled, p - *mangled);
+ string_append (declp, "<");
+ /* should do error checking here */
+ while (args < e) {
+ string_clear (&arg);
+ do_type (work, &args, &arg);
+ string_appends (declp, &arg);
+ string_append (declp, ",");
+ }
+ string_delete (&arg);
+ --declp->p;
+ string_append (declp, ">");
+ }
+ else
+ {
+ string_appendn (declp, *mangled, n);
+ }
+ *mangled += n;
+ success = 1;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_class -- demangle a mangled class sequence
+
+SYNOPSIS
+
+ static int
+ demangle_class (struct work_stuff *work, const char **mangled,
+ strint *declp)
+
+DESCRIPTION
+
+ DECLP points to the buffer into which demangling is being done.
+
+ *MANGLED points to the current token to be demangled. On input,
+ it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
+ On exit, it points to the next token after the mangled class on
+ success, or the first unconsumed token on failure.
+
+ If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
+ we are demangling a constructor or destructor. In this case
+ we prepend "class::class" or "class::~class" to DECLP.
+
+ Otherwise, we prepend "class::" to the current DECLP.
+
+ Reset the constructor/destructor flags once they have been
+ "consumed". This allows demangle_class to be called later during
+ the same demangling, to do normal class demangling.
+
+ Returns 1 if demangling is successful, 0 otherwise.
+
+*/
+
+static int
+demangle_class (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 0;
+ string class_name;
+
+ string_init (&class_name);
+ if (demangle_class_name (work, mangled, &class_name))
+ {
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_prepends (declp, &class_name);
+ if (work -> destructor & 1)
+ {
+ string_prepend (declp, "~");
+ work -> destructor -= 1;
+ }
+ else
+ {
+ work -> constructor -= 1;
+ }
+ }
+ string_prepend (declp, "::");
+ string_prepends (declp, &class_name);
+ success = 1;
+ }
+ string_delete (&class_name);
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_prefix -- consume the mangled name prefix and find signature
+
+SYNOPSIS
+
+ static int
+ demangle_prefix (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the prefix of the mangled name.
+
+ DECLP points to the string buffer into which demangled output is
+ placed. On entry, the buffer is empty. On exit it contains
+ the root function name, the demangled operator name, or in some
+ special cases either nothing or the completely demangled result.
+
+ MANGLED points to the current pointer into the mangled name. As each
+ token of the mangled name is consumed, it is updated. Upon entry
+ the current mangled name pointer points to the first character of
+ the mangled name. Upon exit, it should point to the first character
+ of the signature if demangling was successful, or to the first
+ unconsumed character if demangling of the prefix was unsuccessful.
+
+ Returns 1 on success, 0 otherwise.
+ */
+
+static int
+demangle_prefix (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 1;
+ CONST char *scan;
+ int i;
+
+ if (strncmp(*mangled, "_GLOBAL_$D$", 11) == 0)
+ {
+ /* it's a GNU global destructor to be executed at program exit */
+ (*mangled) += 11;
+ work->destructor = 2;
+ }
+ else if (strncmp(*mangled, "_GLOBAL_$I$", 11) == 0)
+ {
+ /* it's a GNU global constructor to be executed at program initial */
+ (*mangled) += 11;
+ work->constructor = 2;
+ }
+ else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0)
+ {
+ /* it's a ARM global destructor to be executed at program exit */
+ (*mangled) += 7;
+ work->destructor = 2;
+ }
+ else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0)
+ {
+ /* it's a ARM global constructor to be executed at program initial */
+ (*mangled) += 7;
+ work->constructor = 2;
+ }
+
+/* This block of code is a reduction in strength time optimization
+ of:
+ scan = strstr (*mangled, "__"); */
+
+ {
+ scan = *mangled;
+
+ do {
+ scan = strchr (scan, '_');
+ } while (scan != NULL && *++scan != '_');
+
+ if (scan != NULL) --scan;
+ }
+
+ if (scan != NULL)
+ {
+ /* We found a sequence of two or more '_', ensure that we start at
+ the last pair in the sequence. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ {
+ scan += (i - 2);
+ }
+ }
+
+ if (scan == NULL)
+ {
+ success = 0;
+ }
+ else if (work -> static_type)
+ {
+ if (!isdigit (scan[0]) && (scan[0] != 't'))
+ {
+ success = 0;
+ }
+ }
+ else if ((scan == *mangled) &&
+ (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
+ {
+ /* The ARM says nothing about the mangling of local variables.
+ But cfront mangles local variables by prepending __<nesting_level>
+ to them. As an extension to ARM demangling we handle this case. */
+ if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2]))
+ {
+ *mangled = scan + 2;
+ consume_count (mangled);
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ /* A GNU style constructor starts with "__[0-9Qt]. */
+ work -> constructor += 1;
+ *mangled = scan + 2;
+ }
+ }
+ else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't'))
+ {
+ /* Mangled name starts with "__". Skip over any leading '_' characters,
+ then find the next "__" that separates the prefix from the signature.
+ */
+ if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
+ || (arm_special (work, mangled, declp) == 0))
+ {
+ while (*scan == '_')
+ {
+ scan++;
+ }
+ if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
+ {
+ /* No separator (I.E. "__not_mangled"), or empty signature
+ (I.E. "__not_mangled_either__") */
+ success = 0;
+ }
+ else
+ {
+ demangle_function_name (work, mangled, declp, scan);
+ }
+ }
+ }
+ else if (*(scan + 2) != '\0')
+ {
+ /* Mangled name does not start with "__" but does have one somewhere
+ in there with non empty stuff after it. Looks like a global
+ function name. */
+ demangle_function_name (work, mangled, declp, scan);
+ }
+ else
+ {
+ /* Doesn't look like a mangled name */
+ success = 0;
+ }
+
+ if (!success && (work->constructor == 2 || work->destructor == 2))
+ {
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ gnu_special -- special handling of gnu mangled strings
+
+SYNOPSIS
+
+ static int
+ gnu_special (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special GNU style mangling forms that don't fit
+ the normal pattern. For example:
+
+ _$_3foo (destructor for class foo)
+ _vt$foo (foo virtual table)
+ _vt$foo$bar (foo::bar virtual table)
+ _3foo$varname (static data member)
+ _Q22rs2tu$vw (static data member)
+ __t6vector1Zii (constructor with template)
+ */
+
+static int
+gnu_special (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 1;
+ CONST char *p;
+
+ if ((*mangled)[0] == '_'
+ && strchr (cplus_markers, (*mangled)[1]) != NULL
+ && (*mangled)[2] == '_')
+ {
+ /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
+ (*mangled) += 3;
+ work -> destructor += 1;
+ }
+ else if ((*mangled)[0] == '_'
+ && (*mangled)[1] == 'v'
+ && (*mangled)[2] == 't'
+ && strchr (cplus_markers, (*mangled)[3]) != NULL)
+ {
+ /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ (*mangled) += 4;
+ while (**mangled != '\0')
+ {
+ if (isdigit(*mangled[0]))
+ {
+ n = consume_count(mangled);
+ }
+ else
+ {
+ n = strcspn (*mangled, cplus_markers);
+ }
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+
+ if (**mangled != '\0')
+ {
+ string_append (declp, "::");
+ (*mangled)++;
+ }
+ }
+ string_append (declp, " virtual table");
+ }
+ else if ((*mangled)[0] == '_'
+ && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
+ && (p = strpbrk (*mangled, cplus_markers)) != NULL)
+ {
+ /* static data member, "_3foo$varname" for example */
+ (*mangled)++;
+ switch (**mangled)
+ {
+ case 'Q':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0);
+ break;
+ default:
+ n = consume_count (mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ if (success && (p == *mangled))
+ {
+ /* Consumed everything up to the cplus_marker, append the
+ variable name. */
+ (*mangled)++;
+ string_append (declp, "::");
+ n = strlen (*mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ else
+ {
+ success = 0;
+ }
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ arm_special -- special handling of ARM/lucid mangled strings
+
+SYNOPSIS
+
+ static int
+ arm_special (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special ARM style mangling forms that don't fit
+ the normal pattern. For example:
+
+ __vtbl__3foo (foo virtual table)
+ __vtbl__3foo__3bar (bar::foo virtual table)
+
+ */
+
+static int
+arm_special (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 1;
+ CONST char *scan;
+
+ if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
+ {
+ /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ scan = *mangled + ARM_VTABLE_STRLEN;
+ while (*scan != '\0') /* first check it can be demangled */
+ {
+ n = consume_count (&scan);
+ if (n==0)
+ {
+ return (0); /* no good */
+ }
+ scan += n;
+ if (scan[0] == '_' && scan[1] == '_')
+ {
+ scan += 2;
+ }
+ }
+ (*mangled) += ARM_VTABLE_STRLEN;
+ while (**mangled != '\0')
+ {
+ n = consume_count (mangled);
+ string_prependn (declp, *mangled, n);
+ (*mangled) += n;
+ if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
+ {
+ string_prepend (declp, "::");
+ (*mangled) += 2;
+ }
+ }
+ string_append (declp, " virtual table");
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_qualified -- demangle 'Q' qualified name strings
+
+SYNOPSIS
+
+ static int
+ demangle_qualified (struct work_stuff *, const char *mangled,
+ string *result, int isfuncname, int append);
+
+DESCRIPTION
+
+ Demangle a qualified name, such as "Q25Outer5Inner" which is
+ the mangled form of "Outer::Inner". The demangled output is
+ prepended or appended to the result string according to the
+ state of the append flag.
+
+ If isfuncname is nonzero, then the qualified name we are building
+ is going to be used as a member function name, so if it is a
+ constructor or destructor function, append an appropriate
+ constructor or destructor name. I.E. for the above example,
+ the result for use as a constructor is "Outer::Inner::Inner"
+ and the result for use as a destructor is "Outer::Inner::~Inner".
+
+BUGS
+
+ Numeric conversion is ASCII dependent (FIXME).
+
+ */
+
+static int
+demangle_qualified (work, mangled, result, isfuncname, append)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+ int isfuncname;
+ int append;
+{
+ int qualifiers;
+ int namelength;
+ int success = 1;
+ CONST char *p;
+ char num[2];
+ string temp;
+
+ string_init (&temp);
+ switch ((*mangled)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is preceded
+ by an underscore (to distinguish it from the <= 9 case) and followed
+ by an underscore. */
+ p = *mangled + 2;
+ qualifiers = atoi (p);
+ if (!isdigit (*p) || *p == '0')
+ success = 0;
+
+ /* Skip the digits. */
+ while (isdigit (*p))
+ ++p;
+
+ if (*p != '_')
+ success = 0;
+
+ *mangled = p + 1;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* The count is in a single digit. */
+ num[0] = (*mangled)[1];
+ num[1] = '\0';
+ qualifiers = atoi (num);
+
+ /* If there is an underscore after the digit, skip it. This is
+ said to be for ARM-qualified names, but the ARM makes no
+ mention of such an underscore. Perhaps cfront uses one. */
+ if ((*mangled)[2] == '_')
+ {
+ (*mangled)++;
+ }
+ (*mangled) += 2;
+ break;
+
+ case '0':
+ default:
+ success = 0;
+ }
+
+ if (!success)
+ return success;
+
+ /* Pick off the names and collect them in the temp buffer in the order
+ in which they are found, separated by '::'. */
+
+ while (qualifiers-- > 0)
+ {
+ if (*mangled[0] == 't')
+ {
+ success = demangle_template(work, mangled, &temp, 0);
+ if (!success) break;
+ }
+ else
+ {
+ namelength = consume_count (mangled);
+ if (strlen (*mangled) < namelength)
+ {
+ /* Simple sanity check failed */
+ success = 0;
+ break;
+ }
+ string_appendn (&temp, *mangled, namelength);
+ *mangled += namelength;
+ }
+ if (qualifiers > 0)
+ {
+ string_appendn (&temp, "::", 2);
+ }
+ }
+
+ /* If we are using the result as a function name, we need to append
+ the appropriate '::' separated constructor or destructor name.
+ We do this here because this is the most convenient place, where
+ we already have a pointer to the name and the length of the name. */
+
+ if (isfuncname && (work->constructor & 1 || work->destructor & 1))
+ {
+ string_appendn (&temp, "::", 2);
+ if (work -> destructor & 1)
+ {
+ string_append (&temp, "~");
+ }
+ string_appendn (&temp, (*mangled) - namelength, namelength);
+ }
+
+ /* Now either prepend the temp buffer to the result, or append it,
+ depending upon the state of the append flag. */
+
+ if (append)
+ {
+ string_appends (result, &temp);
+ }
+ else
+ {
+ if (!STRING_EMPTY (result))
+ {
+ string_appendn (&temp, "::", 2);
+ }
+ string_prepends (result, &temp);
+ }
+
+ string_delete (&temp);
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ get_count -- convert an ascii count to integer, consuming tokens
+
+SYNOPSIS
+
+ static int
+ get_count (const char **type, int *count)
+
+DESCRIPTION
+
+ Return 0 if no conversion is performed, 1 if a string is converted.
+*/
+
+static int
+get_count (type, count)
+ CONST char **type;
+ int *count;
+{
+ CONST char *p;
+ int n;
+
+ if (!isdigit (**type))
+ {
+ return (0);
+ }
+ else
+ {
+ *count = **type - '0';
+ (*type)++;
+ if (isdigit (**type))
+ {
+ p = *type;
+ n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p++;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ }
+ return (1);
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ int n;
+ int done;
+ int success;
+ string decl;
+ CONST char *remembered_type;
+ int constp;
+ int volatilep;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**mangled)
+ {
+
+ /* A pointer type */
+ case 'P':
+ (*mangled)++;
+ string_prepend (&decl, "*");
+ break;
+
+ /* A reference type */
+ case 'R':
+ (*mangled)++;
+ string_prepend (&decl, "&");
+ break;
+
+ /* An array */
+ case 'A':
+ {
+ CONST char *p = ++(*mangled);
+
+ string_prepend (&decl, "(");
+ string_append (&decl, ")[");
+ /* Copy anything up until the next underscore (the size of the
+ array). */
+ while (**mangled && **mangled != '_')
+ ++(*mangled);
+ if (**mangled == '_')
+ {
+ string_appendn (&decl, p, *mangled - p);
+ string_append (&decl, "]");
+ *mangled += 1;
+ }
+ else
+ success = 0;
+ break;
+ }
+
+ /* A back reference to a previously seen type */
+ case 'T':
+ (*mangled)++;
+ if (!get_count (mangled, &n) || n >= work -> ntypes)
+ {
+ success = 0;
+ }
+ else
+ {
+ remembered_type = work -> typevec[n];
+ mangled = &remembered_type;
+ }
+ break;
+
+ /* A function */
+ case 'F':
+ (*mangled)++;
+ if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ /* After picking off the function args, we expect to either find the
+ function return type (preceded by an '_') or the end of the
+ string. */
+ if (!demangle_args (work, mangled, &decl)
+ || (**mangled != '_' && **mangled != '\0'))
+ {
+ success = 0;
+ }
+ if (success && (**mangled == '_'))
+ {
+ (*mangled)++;
+ }
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ constp = 0;
+ volatilep = 0;
+
+ member = **mangled == 'M';
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ {
+ success = 0;
+ break;
+ }
+ n = consume_count (mangled);
+ if (strlen (*mangled) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *mangled, n);
+ string_prepend (&decl, "(");
+ *mangled += n;
+ if (member)
+ {
+ if (**mangled == 'C')
+ {
+ (*mangled)++;
+ constp = 1;
+ }
+ if (**mangled == 'V')
+ {
+ (*mangled)++;
+ volatilep = 1;
+ }
+ if (*(*mangled)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !demangle_args (work, mangled, &decl))
+ || **mangled != '_')
+ {
+ success = 0;
+ break;
+ }
+ (*mangled)++;
+ if (! PRINT_ANSI_QUALIFIERS)
+ {
+ break;
+ }
+ if (constp)
+ {
+ APPEND_BLANK (&decl);
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ APPEND_BLANK (&decl);
+ string_append (&decl, "volatile");
+ }
+ break;
+ }
+ case 'G':
+ (*mangled)++;
+ break;
+
+ case 'C':
+ (*mangled)++;
+/*
+ if ((*mangled)[1] == 'P')
+ {
+*/
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ if (!STRING_EMPTY (&decl))
+ {
+ string_prepend (&decl, " ");
+ }
+ string_prepend (&decl, "const");
+ }
+ break;
+/*
+ }
+*/
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ switch (**mangled)
+ {
+ /* A qualified name, such as "Outer::Inner". */
+ case 'Q':
+ success = demangle_qualified (work, mangled, result, 0, 1);
+ break;
+
+ default:
+ success = demangle_fund_type (work, mangled, result);
+ break;
+ }
+
+ if (success)
+ {
+ if (!STRING_EMPTY (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ }
+ else
+ {
+ string_delete (result);
+ }
+ string_delete (&decl);
+ return (success);
+}
+
+/* Given a pointer to a type string that represents a fundamental type
+ argument (int, long, unsigned int, etc) in TYPE, a pointer to the
+ string in which the demangled output is being built in RESULT, and
+ the WORK structure, decode the types and add them to the result.
+
+ For example:
+
+ "Ci" => "const int"
+ "Sl" => "signed long"
+ "CUs" => "const unsigned short"
+
+ */
+
+static int
+demangle_fund_type (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ int done = 0;
+ int success = 1;
+
+ /* First pick off any type qualifiers. There can be more than one. */
+
+ while (!done)
+ {
+ switch (**mangled)
+ {
+ case 'C':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "const");
+ }
+ break;
+ case 'U':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "unsigned");
+ break;
+ case 'S': /* signed char only */
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "signed");
+ break;
+ case 'V':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "volatile");
+ }
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ /* Now pick off the fundamental type. There can be only one. */
+
+ switch (**mangled)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "void");
+ break;
+ case 'x':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long long");
+ break;
+ case 'l':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long");
+ break;
+ case 'i':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "int");
+ break;
+ case 's':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "short");
+ break;
+ case 'c':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "char");
+ break;
+ case 'w':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "wchar_t");
+ break;
+ case 'r':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long double");
+ break;
+ case 'd':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "double");
+ break;
+ case 'f':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "float");
+ break;
+ case 'G':
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ /* An explicit type, such as "6mytype" or "7integer" */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ APPEND_BLANK (result);
+ if (!demangle_class_name (work, mangled, result)) {
+ --result->p;
+ success = 0;
+ }
+ break;
+ case 't':
+ success = demangle_template(work,mangled, result, 0);
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ return (success);
+}
+
+/* `result' will be initialized in do_type; it will be freed on failure */
+
+static int
+do_arg (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ CONST char *start = *mangled;
+
+ if (!do_type (work, mangled, result))
+ {
+ return (0);
+ }
+ else
+ {
+ remember_type (work, start, *mangled - start);
+ return (1);
+ }
+}
+
+static void
+remember_type (work, start, len)
+ struct work_stuff *work;
+ CONST char *start;
+ int len;
+{
+ char *tem;
+
+ if (work -> ntypes >= work -> typevec_size)
+ {
+ if (work -> typevec_size == 0)
+ {
+ work -> typevec_size = 3;
+ work -> typevec =
+ (char **) xmalloc (sizeof (char *) * work -> typevec_size);
+ }
+ else
+ {
+ work -> typevec_size *= 2;
+ work -> typevec =
+ (char **) xrealloc ((char *)work -> typevec,
+ sizeof (char *) * work -> typevec_size);
+ }
+ }
+ tem = xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> typevec[work -> ntypes++] = tem;
+}
+
+/* Forget the remembered types, but not the type vector itself. */
+
+static void
+forget_types (work)
+ struct work_stuff *work;
+{
+ int i;
+
+ while (work -> ntypes > 0)
+ {
+ i = --(work -> ntypes);
+ if (work -> typevec[i] != NULL)
+ {
+ free (work -> typevec[i]);
+ work -> typevec[i] = NULL;
+ }
+ }
+}
+
+/* Process the argument list part of the signature, after any class spec
+ has been consumed, as well as the first 'F' character (if any). For
+ example:
+
+ "__als__3fooRT0" => process "RT0"
+ "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i"
+
+ DECLP must be already initialised, usually non-empty. It won't be freed
+ on failure.
+
+ Note that g++ differs significantly from ARM and lucid style mangling
+ with regards to references to previously seen types. For example, given
+ the source fragment:
+
+ class foo {
+ public:
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
+ };
+
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+ void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+
+ g++ produces the names:
+
+ __3fooiRT0iT2iT2
+ foo__FiR3fooiT1iT1
+
+ while lcc (and presumably other ARM style compilers as well) produces:
+
+ foo__FiR3fooT1T2T1T2
+ __ct__3fooFiR3fooT1T2T1T2
+
+ Note that g++ bases it's type numbers starting at zero and counts all
+ previously seen types, while lucid/ARM bases it's type numbers starting
+ at one and only considers types after it has seen the 'F' character
+ indicating the start of the function args. For lucid/ARM style, we
+ account for this difference by discarding any previously seen types when
+ we see the 'F' character, and subtracting one from the type number
+ reference.
+
+ */
+
+static int
+demangle_args (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ string arg;
+ int need_comma = 0;
+ int r;
+ int t;
+ CONST char *tem;
+ char temptype;
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, "(");
+ if (**mangled == '\0')
+ {
+ string_append (declp, "void");
+ }
+ }
+
+ while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+ {
+ if ((**mangled == 'N') || (**mangled == 'T'))
+ {
+ temptype = *(*mangled)++;
+
+ if (temptype == 'N')
+ {
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ r = 1;
+ }
+ if (!get_count (mangled, &t))
+ {
+ return (0);
+ }
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+ t--;
+ }
+ /* Validate the type index. Protect against illegal indices from
+ malformed type strings. */
+ if ((t < 0) || (t >= work -> ntypes))
+ {
+ return (0);
+ }
+ while (--r >= 0)
+ {
+ tem = work -> typevec[t];
+ if (need_comma && PRINT_ARG_TYPES)
+ {
+ string_append (declp, ", ");
+ }
+ if (!do_arg (work, &tem, &arg))
+ {
+ return (0);
+ }
+ if (PRINT_ARG_TYPES)
+ {
+ string_appends (declp, &arg);
+ }
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma & PRINT_ARG_TYPES)
+ {
+ string_append (declp, ", ");
+ }
+ if (!do_arg (work, mangled, &arg))
+ {
+ return (0);
+ }
+ if (PRINT_ARG_TYPES)
+ {
+ string_appends (declp, &arg);
+ }
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**mangled == 'e')
+ {
+ (*mangled)++;
+ if (PRINT_ARG_TYPES)
+ {
+ if (need_comma)
+ {
+ string_append (declp, ",");
+ }
+ string_append (declp, "...");
+ }
+ }
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, ")");
+ }
+ return (1);
+}
+
+static void
+demangle_function_name (work, mangled, declp, scan)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+ CONST char *scan;
+{
+ int i;
+ int len;
+ string type;
+ CONST char *tem;
+
+ string_appendn (declp, (*mangled), scan - (*mangled));
+ string_need (declp, 1);
+ *(declp -> p) = '\0';
+
+ /* Consume the function name, including the "__" separating the name
+ from the signature. We are guaranteed that SCAN points to the
+ separator. */
+
+ (*mangled) = scan + 2;
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+
+ /* See if we have an ARM style constructor or destructor operator.
+ If so, then just record it, clear the decl, and return.
+ We can't build the actual constructor/destructor decl until later,
+ when we recover the class name from the signature. */
+
+ if (strcmp (declp -> b, "__ct") == 0)
+ {
+ work -> constructor += 1;
+ string_clear (declp);
+ return;
+ }
+ else if (strcmp (declp -> b, "__dt") == 0)
+ {
+ work -> destructor += 1;
+ string_clear (declp);
+ return;
+ }
+ }
+
+ if (declp->p - declp->b >= 3
+ && declp->b[0] == 'o'
+ && declp->b[1] == 'p'
+ && strchr (cplus_markers, declp->b[2]) != NULL)
+ {
+ /* see if it's an assignment expression */
+ if (declp->p - declp->b >= 10 /* op$assign_ */
+ && memcmp (declp->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ len = declp->p - declp->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 10, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ string_append (declp, "=");
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ int len = declp->p - declp->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 3, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type$", 5) == 0)
+ {
+ /* type conversion operator */
+ tem = declp->b + 5;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && declp->b[2] == 'o' && declp->b[3] == 'p')
+ {
+ /* ANSI. */
+ /* type conversion operator. */
+ tem = declp->b + 4;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && declp->b[2] >= 'a' && declp->b[2] <= 'z'
+ && declp->b[3] >= 'a' && declp->b[3] <= 'z')
+ {
+ if (declp->b[4] == '\0')
+ {
+ /* Operator. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 2
+ && memcmp (optable[i].in, declp->b + 2, 2) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (declp->b[2] == 'a' && declp->b[5] == '\0')
+ {
+ /* Assignment. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 3
+ && memcmp (optable[i].in, declp->b + 2, 3) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+ string *s;
+ int n;
+{
+ int tem;
+
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ {
+ n = 32;
+ }
+ s->p = s->b = xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (s)
+ string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (s)
+ string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (s)
+ string *s;
+{
+ s->p = s->b;
+}
+
+#if 0
+
+static int
+string_empty (s)
+ string *s;
+{
+ return (s->b == s->p);
+}
+
+#endif
+
+static void
+string_append (p, s)
+ string *p;
+ CONST char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (p, s)
+ string *p, *s;
+{
+ int n;
+
+ if (s->b != s->p)
+ {
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+ }
+}
+
+static void
+string_appendn (p, s, n)
+ string *p;
+ CONST char *s;
+ int n;
+{
+ if (n != 0)
+ {
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_prepend (p, s)
+ string *p;
+ CONST char *s;
+{
+ if (s != NULL && *s != '\0')
+ {
+ string_prependn (p, s, strlen (s));
+ }
+}
+
+static void
+string_prepends (p, s)
+ string *p, *s;
+{
+ if (s->b != s->p)
+ {
+ string_prependn (p, s->b, s->p - s->b);
+ }
+}
+
+static void
+string_prependn (p, s, n)
+ string *p;
+ CONST char *s;
+ int n;
+{
+ char *q;
+
+ if (n != 0)
+ {
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ {
+ q[n] = q[0];
+ }
+ memcpy (p->b, s, n);
+ p->p += n;
+ }
+}
+
+/* To generate a standalone demangler program for testing purposes, just
+ compile and link this file with -DMAIN. When run, it demangles each
+ command line arg, or each stdin string, and prints the result on stdout. */
+
+#ifdef MAIN
+
+static void
+demangle_it (mangled_name)
+ char *mangled_name;
+{
+ char *result;
+
+ result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
+ if (result == NULL)
+ {
+ printf ("%s\n", mangled_name);
+ }
+ else
+ {
+ printf ("%s\n", result);
+ free (result);
+ }
+}
+
+char *
+xmalloc (size)
+ long size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) malloc ((int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't allocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+char *
+xrealloc (oldmem, size)
+ PTR oldmem;
+ long size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't reallocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+#include "getopt.h"
+
+static char *program_name;
+extern char *program_version;
+
+static void
+usage (stream, status)
+ FILE *stream;
+ int status;
+{
+ fprintf (stream, "\
+Usage: %s [-_] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
+ [--format={gnu,lucid,arm}] [--help] [--version] [arg...]\n",
+ program_name);
+ exit (status);
+}
+
+#define MBUF_SIZE 512
+char mbuffer[MBUF_SIZE];
+
+/* Defined in the automatically-generated ../binutils/underscore.c. */
+extern int prepends_underscore;
+
+int strip_underscore = 0;
+
+static struct option long_options[] = {
+ {"strip-underscores", no_argument, 0, '_'},
+ {"format", required_argument, 0, 's'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, no_argument, 0, 0}
+};
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *result;
+ int c;
+
+ program_name = argv[0];
+ strip_underscore = prepends_underscore;
+
+ while ((c = getopt_long (argc, argv, "_s:", long_options, (int *) 0)) != EOF)
+ {
+ switch (c)
+ {
+ case '?':
+ usage (stderr, 1);
+ break;
+ case 'h':
+ usage (stdout, 0);
+ case 'v':
+ printf ("GNU %s version %s\n", program_name, program_version);
+ exit (0);
+ case '_':
+ strip_underscore = 1;
+ break;
+ case 's':
+ if (strcmp (optarg, "gnu") == 0)
+ {
+ current_demangling_style = gnu_demangling;
+ }
+ else if (strcmp (optarg, "lucid") == 0)
+ {
+ current_demangling_style = lucid_demangling;
+ }
+ else if (strcmp (optarg, "arm") == 0)
+ {
+ current_demangling_style = arm_demangling;
+ }
+ else
+ {
+ fprintf (stderr, "%s: unknown demangling style `%s'\n",
+ program_name, optarg);
+ exit (1);
+ }
+ break;
+ }
+ }
+
+ if (optind < argc)
+ {
+ for ( ; optind < argc; optind++)
+ {
+ demangle_it (argv[optind]);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ int i = 0;
+ c = getchar ();
+ /* Try to read a label. */
+ while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
+ {
+ if (i >= MBUF_SIZE-1)
+ break;
+ mbuffer[i++] = c;
+ c = getchar ();
+ }
+ if (i > 0)
+ {
+ int skip_first = strip_underscore && i > 1 && mbuffer[0] == '_';
+ mbuffer[i] = 0;
+
+ result = cplus_demangle (mbuffer+skip_first,
+ DMGL_PARAMS | DMGL_ANSI);
+ if (result)
+ {
+ fputs (result, stdout);
+ free (result);
+ }
+ else
+ fputs (mbuffer + skip_first, stdout);
+ }
+ if (c == EOF)
+ break;
+ putchar (c);
+ }
+ }
+
+ exit (0);
+}
+
+#endif /* main */
diff --git a/gnu/usr.bin/gdb/libiberty/fdmatch.c b/gnu/usr.bin/gdb/libiberty/fdmatch.c
new file mode 100644
index 000000000000..0a6de2af0fd0
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/fdmatch.c
@@ -0,0 +1,71 @@
+/* Compare two open file descriptors to see if they refer to the same file.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/*
+
+NAME
+
+ fdmatch -- see if two file descriptors refer to same file
+
+SYNOPSIS
+
+ int fdmatch (int fd1, int fd2)
+
+DESCRIPTION
+
+ Check to see if two open file descriptors refer to the same file.
+ This is useful, for example, when we have an open file descriptor
+ for an unnamed file, and the name of a file that we believe to
+ correspond to that fd. This can happen when we are exec'd with
+ an already open file (stdout for example) or from the SVR4 /proc
+ calls that return open file descriptors for mapped address spaces.
+ All we have to do is open the file by name and check the two file
+ descriptors for a match, which is done by comparing major&minor
+ device numbers and inode numbers.
+
+BUGS
+
+ (FIXME: does this work for networks?)
+ It works for NFS, which assigns a device number to each mount.
+
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int fdmatch (fd1, fd2)
+ int fd1;
+ int fd2;
+{
+ struct stat sbuf1;
+ struct stat sbuf2;
+
+ if ((fstat (fd1, &sbuf1) == 0) &&
+ (fstat (fd2, &sbuf2) == 0) &&
+ (sbuf1.st_dev == sbuf2.st_dev) &&
+ (sbuf1.st_ino == sbuf2.st_ino))
+ {
+ return (1);
+ }
+ else
+ {
+ return (0);
+ }
+}
diff --git a/gnu/usr.bin/gdb/libiberty/getopt.c b/gnu/usr.bin/gdb/libiberty/getopt.c
new file mode 100644
index 000000000000..c7a8b0326418
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/getopt.c
@@ -0,0 +1,750 @@
+/* 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 roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* 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>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* 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 EOF, 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. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it.
+ (Supposedly there are some machines where it might get a warning,
+ but changing this conditional to __STDC__ is too risky.) */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* 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 (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ 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;
+ }
+ /* 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;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* 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 `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ 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. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* 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 ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - 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 nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ 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/gnu/usr.bin/gdb/libiberty/getopt1.c b/gnu/usr.bin/gdb/libiberty/getopt1.c
new file mode 100644
index 000000000000..6806da5f983f
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/getopt1.c
@@ -0,0 +1,180 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ 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/gnu/usr.bin/gdb/libiberty/ieee-float.c b/gnu/usr.bin/gdb/libiberty/ieee-float.c
new file mode 100644
index 000000000000..b50eb859a1c1
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/ieee-float.c
@@ -0,0 +1,150 @@
+/* IEEE floating point support routines, for GDB, the GNU Debugger.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ieee-float.h"
+#include <math.h> /* ldexp */
+
+/* Convert an IEEE extended float to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+void
+ieee_extended_to_double (ext_format, from, to)
+ CONST struct ext_format *ext_format;
+ char *from;
+ double *to;
+{
+ unsigned char *ufrom = (unsigned char *)from;
+ double dto;
+ unsigned long mant0, mant1, exponent;
+
+ memcpy (&mant0, &from[MANBYTE_H], 4);
+ memcpy (&mant1, &from[MANBYTE_L], 4);
+ exponent = ((ufrom[EXPBYTE_H] & (unsigned char)~SIGNMASK) << 8) | ufrom[EXPBYTE_L];
+
+#if 0
+ /* We can't do anything useful with a NaN anyway, so ignore its
+ difference. It will end up as Infinity or something close. */
+ if (exponent == EXT_EXP_NAN) {
+ /* We have a NaN source. */
+ dto = 0.123456789; /* Not much else useful to do -- we don't know if
+ the host system even *has* NaNs, nor how to
+ generate an innocuous one if it does. */
+ } else
+#endif
+ if (exponent == 0 && mant0 == 0 && mant1 == 0) {
+ dto = 0;
+ } else {
+ /* Build the result algebraically. Might go infinite, underflow, etc;
+ who cares. */
+ mant0 |= 0x80000000;
+ dto = ldexp ((double)mant0, exponent - EXT_EXP_BIAS - 31);
+ dto += ldexp ((double)mant1, exponent - EXT_EXP_BIAS - 31 - 32);
+ if (ufrom[EXPBYTE_H] & SIGNMASK) /* If negative... */
+ dto = -dto; /* ...negate. */
+ }
+ memcpy (to, &dto, sizeof (dto));
+}
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. Neither FROM nor TO have any alignment
+ restrictions. */
+
+void
+double_to_ieee_extended (ext_format, from, to)
+ CONST struct ext_format *ext_format;
+ double *from;
+ char *to;
+{
+ double dfrom;
+ unsigned long twolongs[2];
+ unsigned long mant0, mant1, exponent;
+ unsigned char tobytes[8];
+
+ memcpy (&dfrom, from, sizeof (dfrom));
+ memset (to, 0, TOTALSIZE);
+ if (dfrom == 0)
+ return; /* Result is zero */
+ if (dfrom != dfrom) {
+ /* From is NaN */
+ to[EXPBYTE_H] = (unsigned char)(EXT_EXP_NAN >> 8);
+ to[EXPBYTE_L] = (unsigned char)EXT_EXP_NAN;
+ to[MANBYTE_H] = 1; /* Be sure it's not infinity, but NaN value is irrel */
+ return; /* Result is NaN */
+ }
+ if (dfrom < 0)
+ to[SIGNBYTE] |= SIGNMASK; /* Set negative sign */
+ /* How to tell an infinity from an ordinary number? FIXME-someday */
+
+ /* The following code assumes that the host has IEEE doubles. FIXME-someday.
+ It also assumes longs are 32 bits! FIXME-someday. */
+ memcpy (twolongs, from, 8);
+ memcpy (tobytes, from, 8);
+#if HOST_BYTE_ORDER == BIG_ENDIAN
+ exponent = ((tobytes[1] & 0xF0) >> 4) | (tobytes[0] & 0x7F) << 4;
+ mant0 = (twolongs[0] << 11) | twolongs[1] >> 21;
+ mant1 = (twolongs[1] << 11);
+#else
+ exponent = ((tobytes[6] & 0xF0) >> 4) | (tobytes[7] & 0x7F) << 4;
+ mant0 = (twolongs[1] << 11) | twolongs[0] >> 21;
+ mant1 = (twolongs[0] << 11);
+#endif
+
+ /* Fiddle with leading 1-bit, implied in double, explicit in extended. */
+ if (exponent == 0)
+ mant0 &= 0x7FFFFFFF;
+ else
+ mant0 |= 0x80000000;
+
+ exponent -= DBL_EXP_BIAS; /* Get integer exp */
+ exponent += EXT_EXP_BIAS; /* Offset for extended */
+
+ /* OK, now store it in extended format. */
+ to[EXPBYTE_H] |= (unsigned char)(exponent >> 8); /* Retain sign */
+ to[EXPBYTE_L] = (unsigned char) exponent;
+
+ memcpy (&to[MANBYTE_H], &mant0, 4);
+ memcpy (&to[MANBYTE_L], &mant1, 4);
+}
+
+
+#ifdef IEEE_DEBUG
+
+/* Test some numbers to see that extended/double conversion works for them. */
+
+ieee_test (n)
+ int n;
+{
+ union { double d; int i[2]; } di;
+ double result;
+ int i;
+ char exten[16];
+ extern struct ext_format ext_format_68881;
+
+ for (i = 0; i < n; i++) {
+ di.i[0] = (random() << 16) | (random() & 0xffff);
+ di.i[1] = (random() << 16) | (random() & 0xffff);
+ double_to_ieee_extended (&ext_format_68881, &di.d, exten);
+ ieee_extended_to_double (&ext_format_68881, exten, &result);
+ if (di.d != result)
+ printf ("Differ: %x %x %g => %x %x %g\n", di.d, di.d, result, result);
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/ieee-float.h b/gnu/usr.bin/gdb/libiberty/ieee-float.h
new file mode 100644
index 000000000000..68ef23b40fd9
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/ieee-float.h
@@ -0,0 +1,65 @@
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (IEEE_FLOAT_H)
+#define IEEE_FLOAT_H 1
+
+#include "ansidecl.h"
+
+/* Parameters for extended float format: */
+
+struct ext_format {
+ unsigned totalsize; /* Total size of extended number */
+ unsigned signbyte; /* Byte number of sign bit */
+ unsigned char signmask; /* Mask for sign bit */
+ unsigned expbyte_h; /* High byte of exponent */
+ unsigned expbyte_l; /* Low byte of exponent */
+ unsigned manbyte_h; /* High byte of mantissa */
+ unsigned manbyte_l; /* Low byte of mantissa */
+};
+
+#define TOTALSIZE ext_format->totalsize
+#define SIGNBYTE ext_format->signbyte
+#define SIGNMASK ext_format->signmask
+#define EXPBYTE_H ext_format->expbyte_h
+#define EXPBYTE_L ext_format->expbyte_l
+#define MANBYTE_H ext_format->manbyte_h
+#define MANBYTE_L ext_format->manbyte_l
+
+/* Actual ext_format structs for various machines are in the *-tdep.c file
+ for each machine. */
+
+#define EXT_EXP_NAN 0x7FFF /* Exponent value that indicates NaN */
+#define EXT_EXP_BIAS 0x3FFF /* Amount added to "true" exponent for ext */
+#define DBL_EXP_BIAS 0x3FF /* Ditto, for doubles */
+
+/* Convert an IEEE extended float to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+extern void
+ieee_extended_to_double PARAMS ((const struct ext_format *, char *, double *));
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. */
+
+extern void
+double_to_ieee_extended PARAMS ((const struct ext_format *, double *, char *));
+
+#endif /* defined (IEEE_FLOAT_H) */
diff --git a/gnu/usr.bin/gdb/libiberty/obstack.c b/gnu/usr.bin/gdb/libiberty/obstack.c
new file mode 100644
index 000000000000..4297bbbd51f1
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/obstack.c
@@ -0,0 +1,460 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988, 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "obstack.h"
+
+/* This is just to get __GNU_LIBRARY__ defined. */
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+#ifdef __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment. */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT \
+ ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+/* The non-GNU-C macros copy the obstack into this global variable
+ to avoid multiple evaluation. */
+
+struct obstack *_obstack;
+
+/* Define a macro that either calls functions with the traditional malloc/free
+ calling interface, or calls functions with the mmalloc/mfree interface
+ (that adds an extra first argument), based on the state of use_extra_arg.
+ For free, do not use ?:, since some compilers, like the MIPS compilers,
+ do not allow (expr) ? void : void. */
+
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(h)->freefun) ((old_chunk)); \
+ } while (0)
+
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them. */
+
+void
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->use_extra_arg = 0;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+}
+
+void
+_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+ POINTER arg;
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->extra_arg = arg;
+ h->use_extra_arg = 1;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (h, length)
+ struct obstack *h;
+ int length;
+{
+ register struct _obstack_chunk* old_chunk = h->chunk;
+ register struct _obstack_chunk* new_chunk;
+ register long new_size;
+ register int obj_size = h->next_free - h->object_base;
+ register int i;
+ int already;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = h->chunk = CALL_CHUNKFUN (h, new_size);
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ new_chunk->contents[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
+ {
+ new_chunk->prev = old_chunk->prev;
+ CALL_FREEFUN (h, old_chunk);
+ }
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+#ifdef __STDC__
+/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
+ obstack.h because it is just for debugging. */
+int _obstack_allocated_p (struct obstack *h, POINTER obj);
+#endif
+
+int
+_obstack_allocated_p (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+#undef obstack_free
+
+/* This function has two names with identical definitions.
+ This is the first one, called from non-ANSI code. */
+
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+/* This function is used from ANSI code. */
+
+void
+obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+#if 0
+/* These are now turned off because the applications do not use it
+ and it uses bcopy via obstack_grow, which causes trouble on sysV. */
+
+/* Now define the functional versions of the obstack macros.
+ Define them to simply use the corresponding macros to do the job. */
+
+#ifdef __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+ they won't pass through the macro names in parentheses. */
+
+/* The function names appear in parentheses in order to prevent
+ the macro-definitions of the names from being expanded there. */
+
+POINTER (obstack_base) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_room (obstack);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/gnu/usr.bin/gdb/libiberty/sigsetmask.c b/gnu/usr.bin/gdb/libiberty/sigsetmask.c
new file mode 100644
index 000000000000..545b12e57b3f
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/sigsetmask.c
@@ -0,0 +1,44 @@
+/* Version of sigsetmask.c
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Written by Steve Chamberlain (sac@cygnus.com).
+ Contributed by Cygnus Support.
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* Set the current signal mask to the set provided, and return the
+ previous value */
+
+#define _POSIX_SOURCE
+#include <ansidecl.h>
+#include <signal.h>
+
+#ifdef SIG_SETMASK
+int
+DEFUN(sigsetmask,(set),
+ int set)
+{
+ sigset_t new;
+ sigset_t old;
+
+ sigemptyset (&new);
+ if (set != 0) {
+ abort(); /* FIXME, we don't know how to translate old mask to new */
+ }
+ sigprocmask(SIG_SETMASK, &new, &old);
+ return 1; /* FIXME, we always return 1 as old value. */
+}
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/spaces.c b/gnu/usr.bin/gdb/libiberty/spaces.c
new file mode 100644
index 000000000000..28f07462d372
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/spaces.c
@@ -0,0 +1,67 @@
+/* Allocate memory region filled with spaces.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+
+NAME
+
+ spaces -- return a pointer to a buffer full of spaces
+
+SYNOPSIS
+
+ char *spaces (int count)
+
+DESCRIPTION
+
+ Returns a pointer to a memory region filled with the specified
+ number of spaces and null terminated. The returned pointer is
+ valid until at least the next call.
+
+BUGS
+
+*/
+
+
+char *
+spaces (count)
+ int count;
+{
+ register char *t;
+ static char *buf;
+ static int maxsize;
+ extern char *malloc ();
+ extern void free ();
+
+ if (count > maxsize)
+ {
+ if (buf)
+ {
+ free (buf);
+ }
+ buf = malloc (count + 1);
+ for (t = buf + count ; t != buf ; )
+ {
+ *--t = ' ';
+ }
+ maxsize = count;
+ buf[count] = '\0';
+ }
+ return (buf + maxsize - count);
+}
+
diff --git a/gnu/usr.bin/gdb/libiberty/strerror.c b/gnu/usr.bin/gdb/libiberty/strerror.c
new file mode 100644
index 000000000000..f377311a4f56
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strerror.c
@@ -0,0 +1,811 @@
+/* Extended support for using errno values.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish. fnf@cygnus.com
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#ifndef NEED_sys_errlist
+/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least)
+ might declare sys_errlist in a way that the compiler might consider
+ incompatible with our later declaration, perhaps by using const
+ attributes. So we hide the declaration in errno.h (if any) using a
+ macro. */
+#define sys_errlist sys_errlist__
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef NEED_sys_errlist
+#undef sys_errlist
+#endif
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+#include <stddef.h>
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */
+#else /* !__STDC__ */
+#ifndef const
+#define const
+#endif
+extern char *malloc (); /* Standard memory allocater */
+extern char *memset ();
+#endif /* __STDC__ */
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Translation table for errno values. See intro(2) in most UNIX systems
+ Programmers Reference Manuals.
+
+ Note that this table is generally only accessed when it is used at runtime
+ to initialize errno name and message tables that are indexed by errno
+ value.
+
+ Not all of these errnos will exist on all systems. This table is the only
+ thing that should have to be updated as new error numbers are introduced.
+ It's sort of ugly, but at least its portable. */
+
+struct error_info
+{
+ int value; /* The numeric value from <errno.h> */
+ char *name; /* The equivalent symbolic value */
+ char *msg; /* Short message about this value */
+};
+
+static const struct error_info error_table[] =
+{
+#if defined (EPERM)
+ {EPERM, "EPERM", "Not owner"},
+#endif
+#if defined (ENOENT)
+ {ENOENT, "ENOENT", "No such file or directory"},
+#endif
+#if defined (ESRCH)
+ {ESRCH, "ESRCH", "No such process"},
+#endif
+#if defined (EINTR)
+ {EINTR, "EINTR", "Interrupted system call"},
+#endif
+#if defined (EIO)
+ {EIO, "EIO", "I/O error"},
+#endif
+#if defined (ENXIO)
+ {ENXIO, "ENXIO", "No such device or address"},
+#endif
+#if defined (E2BIG)
+ {E2BIG, "E2BIG", "Arg list too long"},
+#endif
+#if defined (ENOEXEC)
+ {ENOEXEC, "ENOEXEC", "Exec format error"},
+#endif
+#if defined (EBADF)
+ {EBADF, "EBADF", "Bad file number"},
+#endif
+#if defined (ECHILD)
+ {ECHILD, "ECHILD", "No child processes"},
+#endif
+#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */
+ {EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"},
+#endif
+#if defined (EAGAIN)
+ {EAGAIN, "EAGAIN", "No more processes"},
+#endif
+#if defined (ENOMEM)
+ {ENOMEM, "ENOMEM", "Not enough space"},
+#endif
+#if defined (EACCES)
+ {EACCES, "EACCES", "Permission denied"},
+#endif
+#if defined (EFAULT)
+ {EFAULT, "EFAULT", "Bad address"},
+#endif
+#if defined (ENOTBLK)
+ {ENOTBLK, "ENOTBLK", "Block device required"},
+#endif
+#if defined (EBUSY)
+ {EBUSY, "EBUSY", "Device busy"},
+#endif
+#if defined (EEXIST)
+ {EEXIST, "EEXIST", "File exists"},
+#endif
+#if defined (EXDEV)
+ {EXDEV, "EXDEV", "Cross-device link"},
+#endif
+#if defined (ENODEV)
+ {ENODEV, "ENODEV", "No such device"},
+#endif
+#if defined (ENOTDIR)
+ {ENOTDIR, "ENOTDIR", "Not a directory"},
+#endif
+#if defined (EISDIR)
+ {EISDIR, "EISDIR", "Is a directory"},
+#endif
+#if defined (EINVAL)
+ {EINVAL, "EINVAL", "Invalid argument"},
+#endif
+#if defined (ENFILE)
+ {ENFILE, "ENFILE", "File table overflow"},
+#endif
+#if defined (EMFILE)
+ {EMFILE, "EMFILE", "Too many open files"},
+#endif
+#if defined (ENOTTY)
+ {ENOTTY, "ENOTTY", "Not a typewriter"},
+#endif
+#if defined (ETXTBSY)
+ {ETXTBSY, "ETXTBSY", "Text file busy"},
+#endif
+#if defined (EFBIG)
+ {EFBIG, "EFBIG", "File too large"},
+#endif
+#if defined (ENOSPC)
+ {ENOSPC, "ENOSPC", "No space left on device"},
+#endif
+#if defined (ESPIPE)
+ {ESPIPE, "ESPIPE", "Illegal seek"},
+#endif
+#if defined (EROFS)
+ {EROFS, "EROFS", "Read-only file system"},
+#endif
+#if defined (EMLINK)
+ {EMLINK, "EMLINK", "Too many links"},
+#endif
+#if defined (EPIPE)
+ {EPIPE, "EPIPE", "Broken pipe"},
+#endif
+#if defined (EDOM)
+ {EDOM, "EDOM", "Math argument out of domain of func"},
+#endif
+#if defined (ERANGE)
+ {ERANGE, "ERANGE", "Math result not representable"},
+#endif
+#if defined (ENOMSG)
+ {ENOMSG, "ENOMSG", "No message of desired type"},
+#endif
+#if defined (EIDRM)
+ {EIDRM, "EIDRM", "Identifier removed"},
+#endif
+#if defined (ECHRNG)
+ {ECHRNG, "ECHRNG", "Channel number out of range"},
+#endif
+#if defined (EL2NSYNC)
+ {EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"},
+#endif
+#if defined (EL3HLT)
+ {EL3HLT, "EL3HLT", "Level 3 halted"},
+#endif
+#if defined (EL3RST)
+ {EL3RST, "EL3RST", "Level 3 reset"},
+#endif
+#if defined (ELNRNG)
+ {ELNRNG, "ELNRNG", "Link number out of range"},
+#endif
+#if defined (EUNATCH)
+ {EUNATCH, "EUNATCH", "Protocol driver not attached"},
+#endif
+#if defined (ENOCSI)
+ {ENOCSI, "ENOCSI", "No CSI structure available"},
+#endif
+#if defined (EL2HLT)
+ {EL2HLT, "EL2HLT", "Level 2 halted"},
+#endif
+#if defined (EDEADLK)
+ {EDEADLK, "EDEADLK", "Deadlock condition"},
+#endif
+#if defined (ENOLCK)
+ {ENOLCK, "ENOLCK", "No record locks available"},
+#endif
+#if defined (EBADE)
+ {EBADE, "EBADE", "Invalid exchange"},
+#endif
+#if defined (EBADR)
+ {EBADR, "EBADR", "Invalid request descriptor"},
+#endif
+#if defined (EXFULL)
+ {EXFULL, "EXFULL", "Exchange full"},
+#endif
+#if defined (ENOANO)
+ {ENOANO, "ENOANO", "No anode"},
+#endif
+#if defined (EBADRQC)
+ {EBADRQC, "EBADRQC", "Invalid request code"},
+#endif
+#if defined (EBADSLT)
+ {EBADSLT, "EBADSLT", "Invalid slot"},
+#endif
+#if defined (EDEADLOCK)
+ {EDEADLOCK, "EDEADLOCK", "File locking deadlock error"},
+#endif
+#if defined (EBFONT)
+ {EBFONT, "EBFONT", "Bad font file format"},
+#endif
+#if defined (ENOSTR)
+ {ENOSTR, "ENOSTR", "Device not a stream"},
+#endif
+#if defined (ENODATA)
+ {ENODATA, "ENODATA", "No data available"},
+#endif
+#if defined (ETIME)
+ {ETIME, "ETIME", "Timer expired"},
+#endif
+#if defined (ENOSR)
+ {ENOSR, "ENOSR", "Out of streams resources"},
+#endif
+#if defined (ENONET)
+ {ENONET, "ENONET", "Machine is not on the network"},
+#endif
+#if defined (ENOPKG)
+ {ENOPKG, "ENOPKG", "Package not installed"},
+#endif
+#if defined (EREMOTE)
+ {EREMOTE, "EREMOTE", "Object is remote"},
+#endif
+#if defined (ENOLINK)
+ {ENOLINK, "ENOLINK", "Link has been severed"},
+#endif
+#if defined (EADV)
+ {EADV, "EADV", "Advertise error"},
+#endif
+#if defined (ESRMNT)
+ {ESRMNT, "ESRMNT", "Srmount error"},
+#endif
+#if defined (ECOMM)
+ {ECOMM, "ECOMM", "Communication error on send"},
+#endif
+#if defined (EPROTO)
+ {EPROTO, "EPROTO", "Protocol error"},
+#endif
+#if defined (EMULTIHOP)
+ {EMULTIHOP, "EMULTIHOP", "Multihop attempted"},
+#endif
+#if defined (EDOTDOT)
+ {EDOTDOT, "EDOTDOT", "RFS specific error"},
+#endif
+#if defined (EBADMSG)
+ {EBADMSG, "EBADMSG", "Not a data message"},
+#endif
+#if defined (ENAMETOOLONG)
+ {ENAMETOOLONG, "ENAMETOOLONG", "File name too long"},
+#endif
+#if defined (EOVERFLOW)
+ {EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"},
+#endif
+#if defined (ENOTUNIQ)
+ {ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"},
+#endif
+#if defined (EBADFD)
+ {EBADFD, "EBADFD", "File descriptor in bad state"},
+#endif
+#if defined (EREMCHG)
+ {EREMCHG, "EREMCHG", "Remote address changed"},
+#endif
+#if defined (ELIBACC)
+ {ELIBACC, "ELIBACC", "Can not access a needed shared library"},
+#endif
+#if defined (ELIBBAD)
+ {ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"},
+#endif
+#if defined (ELIBSCN)
+ {ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"},
+#endif
+#if defined (ELIBMAX)
+ {ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"},
+#endif
+#if defined (ELIBEXEC)
+ {ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"},
+#endif
+#if defined (EILSEQ)
+ {EILSEQ, "EILSEQ", "Illegal byte sequence"},
+#endif
+#if defined (ENOSYS)
+ {ENOSYS, "ENOSYS", "Operation not applicable"},
+#endif
+#if defined (ELOOP)
+ {ELOOP, "ELOOP", "Too many symbolic links encountered"},
+#endif
+#if defined (ERESTART)
+ {ERESTART, "ERESTART", "Interrupted system call should be restarted"},
+#endif
+#if defined (ESTRPIPE)
+ {ESTRPIPE, "ESTRPIPE", "Streams pipe error"},
+#endif
+#if defined (ENOTEMPTY)
+ {ENOTEMPTY, "ENOTEMPTY", "Directory not empty"},
+#endif
+#if defined (EUSERS)
+ {EUSERS, "EUSERS", "Too many users"},
+#endif
+#if defined (ENOTSOCK)
+ {ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"},
+#endif
+#if defined (EDESTADDRREQ)
+ {EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"},
+#endif
+#if defined (EMSGSIZE)
+ {EMSGSIZE, "EMSGSIZE", "Message too long"},
+#endif
+#if defined (EPROTOTYPE)
+ {EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"},
+#endif
+#if defined (ENOPROTOOPT)
+ {ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"},
+#endif
+#if defined (EPROTONOSUPPORT)
+ {EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"},
+#endif
+#if defined (ESOCKTNOSUPPORT)
+ {ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"},
+#endif
+#if defined (EOPNOTSUPP)
+ {EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"},
+#endif
+#if defined (EPFNOSUPPORT)
+ {EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"},
+#endif
+#if defined (EAFNOSUPPORT)
+ {EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"},
+#endif
+#if defined (EADDRINUSE)
+ {EADDRINUSE, "EADDRINUSE", "Address already in use"},
+#endif
+#if defined (EADDRNOTAVAIL)
+ {EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"},
+#endif
+#if defined (ENETDOWN)
+ {ENETDOWN, "ENETDOWN", "Network is down"},
+#endif
+#if defined (ENETUNREACH)
+ {ENETUNREACH, "ENETUNREACH", "Network is unreachable"},
+#endif
+#if defined (ENETRESET)
+ {ENETRESET, "ENETRESET", "Network dropped connection because of reset"},
+#endif
+#if defined (ECONNABORTED)
+ {ECONNABORTED, "ECONNABORTED", "Software caused connection abort"},
+#endif
+#if defined (ECONNRESET)
+ {ECONNRESET, "ECONNRESET", "Connection reset by peer"},
+#endif
+#if defined (ENOBUFS)
+ {ENOBUFS, "ENOBUFS", "No buffer space available"},
+#endif
+#if defined (EISCONN)
+ {EISCONN, "EISCONN", "Transport endpoint is already connected"},
+#endif
+#if defined (ENOTCONN)
+ {ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"},
+#endif
+#if defined (ESHUTDOWN)
+ {ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"},
+#endif
+#if defined (ETOOMANYREFS)
+ {ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"},
+#endif
+#if defined (ETIMEDOUT)
+ {ETIMEDOUT, "ETIMEDOUT", "Connection timed out"},
+#endif
+#if defined (ECONNREFUSED)
+ {ECONNREFUSED, "ECONNREFUSED", "Connection refused"},
+#endif
+#if defined (EHOSTDOWN)
+ {EHOSTDOWN, "EHOSTDOWN", "Host is down"},
+#endif
+#if defined (EHOSTUNREACH)
+ {EHOSTUNREACH, "EHOSTUNREACH", "No route to host"},
+#endif
+#if defined (EALREADY)
+ {EALREADY, "EALREADY", "Operation already in progress"},
+#endif
+#if defined (EINPROGRESS)
+ {EINPROGRESS, "EINPROGRESS", "Operation now in progress"},
+#endif
+#if defined (ESTALE)
+ {ESTALE, "ESTALE", "Stale NFS file handle"},
+#endif
+#if defined (EUCLEAN)
+ {EUCLEAN, "EUCLEAN", "Structure needs cleaning"},
+#endif
+#if defined (ENOTNAM)
+ {ENOTNAM, "ENOTNAM", "Not a XENIX named type file"},
+#endif
+#if defined (ENAVAIL)
+ {ENAVAIL, "ENAVAIL", "No XENIX semaphores available"},
+#endif
+#if defined (EISNAM)
+ {EISNAM, "EISNAM", "Is a named type file"},
+#endif
+#if defined (EREMOTEIO)
+ {EREMOTEIO, "EREMOTEIO", "Remote I/O error"},
+#endif
+ {0, NULL, NULL}
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ errno value to find the equivalent symbolic value. */
+
+static char **error_names;
+static int num_error_names = 0;
+
+/* Translation table allocated and initialized at runtime, if it does not
+ already exist in the host environment. Indexed by the errno value to find
+ the descriptive string.
+
+ We don't export it for use in other modules because even though it has the
+ same name, it differs from other implementations in that it is dynamically
+ initialized rather than statically initialized. */
+
+#ifdef NEED_sys_errlist
+
+static int sys_nerr;
+static char **sys_errlist;
+
+#else
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#endif
+
+
+/*
+
+NAME
+
+ init_error_tables -- initialize the name and message tables
+
+SYNOPSIS
+
+ static void init_error_tables ();
+
+DESCRIPTION
+
+ Using the error_table, which is initialized at compile time, generate
+ the error_names and the sys_errlist (if needed) tables, which are
+ indexed at runtime by a specific errno value.
+
+BUGS
+
+ The initialization of the tables may fail under low memory conditions,
+ in which case we don't do anything particularly useful, but we don't
+ bomb either. Who knows, it might succeed at a later point if we free
+ some memory in the meantime. In any case, the other routines know
+ how to deal with lack of a table after trying to initialize it. This
+ may or may not be considered to be a bug, that we don't specifically
+ warn about this particular failure mode.
+
+*/
+
+static void
+init_error_tables ()
+{
+ const struct error_info *eip;
+ int nbytes;
+
+ /* If we haven't already scanned the error_table once to find the maximum
+ errno value, then go find it now. */
+
+ if (num_error_names == 0)
+ {
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ if (eip -> value >= num_error_names)
+ {
+ num_error_names = eip -> value + 1;
+ }
+ }
+ }
+
+ /* Now attempt to allocate the error_names table, zero it out, and then
+ initialize it from the statically initialized error_table. */
+
+ if (error_names == NULL)
+ {
+ nbytes = num_error_names * sizeof (char *);
+ if ((error_names = (char **) malloc (nbytes)) != NULL)
+ {
+ memset (error_names, 0, nbytes);
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ error_names[eip -> value] = eip -> name;
+ }
+ }
+ }
+
+#ifdef NEED_sys_errlist
+
+ /* Now attempt to allocate the sys_errlist table, zero it out, and then
+ initialize it from the statically initialized error_table. */
+
+ if (sys_errlist == NULL)
+ {
+ nbytes = num_error_names * sizeof (char *);
+ if ((sys_errlist = (char **) malloc (nbytes)) != NULL)
+ {
+ memset (sys_errlist, 0, nbytes);
+ sys_nerr = num_error_names;
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ sys_errlist[eip -> value] = eip -> msg;
+ }
+ }
+ }
+
+#endif
+
+}
+
+/*
+
+NAME
+
+ errno_max -- return the max errno value
+
+SYNOPSIS
+
+ int errno_max ();
+
+DESCRIPTION
+
+ Returns the maximum errno value for which a corresponding symbolic
+ name or message is available. Note that in the case where
+ we use the sys_errlist supplied by the system, it is possible for
+ there to be more symbolic names than messages, or vice versa.
+ In fact, the manual page for perror(3C) explicitly warns that one
+ should check the size of the table (sys_nerr) before indexing it,
+ since new error codes may be added to the system before they are
+ added to the table. Thus sys_nerr might be smaller than value
+ implied by the largest errno value defined in <errno.h>.
+
+ We return the maximum value that can be used to obtain a meaningful
+ symbolic name or message.
+
+*/
+
+int
+errno_max ()
+{
+ int maxsize;
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+ maxsize = MAX (sys_nerr, num_error_names);
+ return (maxsize - 1);
+}
+
+#ifdef NEED_strerror
+
+/*
+
+NAME
+
+ strerror -- map an error number to an error message string
+
+SYNOPSIS
+
+ char *strerror (int errnoval)
+
+DESCRIPTION
+
+ Maps an errno number to an error message string, the contents of
+ which are implementation defined. On systems which have the external
+ variables sys_nerr and sys_errlist, these strings will be the same
+ as the ones used by perror().
+
+ If the supplied error number is within the valid range of indices
+ for the sys_errlist, but no message is available for the particular
+ error number, then returns the string "Error NUM", where NUM is the
+ error number.
+
+ If the supplied error number is not a valid index into sys_errlist,
+ returns NULL.
+
+ The returned string is only guaranteed to be valid only until the
+ next call to strerror.
+
+*/
+
+char *
+strerror (errnoval)
+ int errnoval;
+{
+ char *msg;
+ static char buf[32];
+
+#ifdef NEED_sys_errlist
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+
+#endif
+
+ if ((errnoval < 0) || (errnoval >= sys_nerr))
+ {
+ /* Out of range, just return NULL */
+ msg = NULL;
+ }
+ else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
+ {
+ /* In range, but no sys_errlist or no entry at this index. */
+ sprintf (buf, "Error %d", errnoval);
+ msg = buf;
+ }
+ else
+ {
+ /* In range, and a valid message. Just return the message. */
+ msg = sys_errlist[errnoval];
+ }
+
+ return (msg);
+}
+
+#endif /* NEED_strerror */
+
+
+/*
+
+NAME
+
+ strerrno -- map an error number to a symbolic name string
+
+SYNOPSIS
+
+ char *strerrno (int errnoval)
+
+DESCRIPTION
+
+ Given an error number returned from a system call (typically
+ returned in errno), returns a pointer to a string containing the
+ symbolic name of that error number, as found in <errno.h>.
+
+ If the supplied error number is within the valid range of indices
+ for symbolic names, but no name is available for the particular
+ error number, then returns the string "Error NUM", where NUM is
+ the error number.
+
+ If the supplied error number is not within the range of valid
+ indices, then returns NULL.
+
+BUGS
+
+ The contents of the location pointed to are only guaranteed to be
+ valid until the next call to strerrno.
+
+*/
+
+char *
+strerrno (errnoval)
+ int errnoval;
+{
+ char *name;
+ static char buf[32];
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+
+ if ((errnoval < 0) || (errnoval >= num_error_names))
+ {
+ /* Out of range, just return NULL */
+ name = NULL;
+ }
+ else if ((error_names == NULL) || (error_names[errnoval] == NULL))
+ {
+ /* In range, but no error_names or no entry at this index. */
+ sprintf (buf, "Error %d", errnoval);
+ name = buf;
+ }
+ else
+ {
+ /* In range, and a valid name. Just return the name. */
+ name = error_names[errnoval];
+ }
+
+ return (name);
+}
+
+/*
+
+NAME
+
+ strtoerrno -- map a symbolic errno name to a numeric value
+
+SYNOPSIS
+
+ int strtoerrno (char *name)
+
+DESCRIPTION
+
+ Given the symbolic name of a error number, map it to an errno value.
+ If no translation is found, returns 0.
+
+*/
+
+int
+strtoerrno (name)
+ char *name;
+{
+ int errnoval = 0;
+
+ if (name != NULL)
+ {
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+ for (errnoval = 0; errnoval < num_error_names; errnoval++)
+ {
+ if ((error_names[errnoval] != NULL) &&
+ (strcmp (name, error_names[errnoval]) == 0))
+ {
+ break;
+ }
+ }
+ if (errnoval == num_error_names)
+ {
+ errnoval = 0;
+ }
+ }
+ return (errnoval);
+}
+
+
+/* A simple little main that does nothing but print all the errno translations
+ if MAIN is defined and this file is compiled and linked. */
+
+#ifdef MAIN
+
+main ()
+{
+ int errn;
+ int errnmax;
+ char *name;
+ char *msg;
+ char *strerrno ();
+ char *strerror ();
+
+ errnmax = errno_max ();
+ printf ("%d entries in names table.\n", num_error_names);
+ printf ("%d entries in messages table.\n", sys_nerr);
+ printf ("%d is max useful index.\n", errnmax);
+
+ /* Keep printing values until we get to the end of *both* tables, not
+ *either* table. Note that knowing the maximum useful index does *not*
+ relieve us of the responsibility of testing the return pointer for
+ NULL. */
+
+ for (errn = 0; errn <= errnmax; errn++)
+ {
+ name = strerrno (errn);
+ name = (name == NULL) ? "<NULL>" : name;
+ msg = strerror (errn);
+ msg = (msg == NULL) ? "<NULL>" : msg;
+ printf ("%-4d%-18s%s\n", errn, name, msg);
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/strsignal.c b/gnu/usr.bin/gdb/libiberty/strsignal.c
new file mode 100644
index 000000000000..15411ff496c6
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strsignal.c
@@ -0,0 +1,634 @@
+/* Extended support for using signal values.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish. fnf@cygnus.com
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <ansidecl.h>
+
+#include "config.h"
+
+#ifdef LOSING_SYS_SIGLIST
+#define sys_siglist no_such_symbol
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+#include <stddef.h>
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */
+#else /* !__STDC__ */
+#ifndef const
+#define const
+#endif
+extern char *malloc (); /* Standard memory allocater */
+extern char *memset ();
+#endif /* __STDC__ */
+
+#ifdef LOSING_SYS_SIGLIST
+#undef sys_siglist
+#endif
+
+
+#ifndef NULL
+# ifdef __STDC__
+# define NULL (void *) 0
+# else
+# define NULL 0
+# endif
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Translation table for signal values.
+
+ Note that this table is generally only accessed when it is used at runtime
+ to initialize signal name and message tables that are indexed by signal
+ value.
+
+ Not all of these signals will exist on all systems. This table is the only
+ thing that should have to be updated as new signal numbers are introduced.
+ It's sort of ugly, but at least its portable. */
+
+struct signal_info
+{
+ int value; /* The numeric value from <signal.h> */
+ char *name; /* The equivalent symbolic value */
+ char *msg; /* Short message about this value */
+};
+
+static const struct signal_info signal_table[] =
+{
+#if defined (SIGHUP)
+ {SIGHUP, "SIGHUP", "Hangup"},
+#endif
+#if defined (SIGINT)
+ {SIGINT, "SIGINT", "Interrupt"},
+#endif
+#if defined (SIGQUIT)
+ {SIGQUIT, "SIGQUIT", "Quit"},
+#endif
+#if defined (SIGILL)
+ {SIGILL, "SIGILL", "Illegal instruction"},
+#endif
+#if defined (SIGTRAP)
+ {SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"},
+#endif
+/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT
+ overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */
+#if defined (SIGIOT)
+ {SIGIOT, "SIGIOT", "IOT trap"},
+#endif
+#if defined (SIGABRT)
+ {SIGABRT, "SIGABRT", "Aborted"},
+#endif
+#if defined (SIGEMT)
+ {SIGEMT, "SIGEMT", "Emulation trap"},
+#endif
+#if defined (SIGFPE)
+ {SIGFPE, "SIGFPE", "Arithmetic exception"},
+#endif
+#if defined (SIGKILL)
+ {SIGKILL, "SIGKILL", "Killed"},
+#endif
+#if defined (SIGBUS)
+ {SIGBUS, "SIGBUS", "Bus error"},
+#endif
+#if defined (SIGSEGV)
+ {SIGSEGV, "SIGSEGV", "Segmentation fault"},
+#endif
+#if defined (SIGSYS)
+ {SIGSYS, "SIGSYS", "Bad system call"},
+#endif
+#if defined (SIGPIPE)
+ {SIGPIPE, "SIGPIPE", "Broken pipe"},
+#endif
+#if defined (SIGALRM)
+ {SIGALRM, "SIGALRM", "Alarm clock"},
+#endif
+#if defined (SIGTERM)
+ {SIGTERM, "SIGTERM", "Terminated"},
+#endif
+#if defined (SIGUSR1)
+ {SIGUSR1, "SIGUSR1", "User defined signal 1"},
+#endif
+#if defined (SIGUSR2)
+ {SIGUSR2, "SIGUSR2", "User defined signal 2"},
+#endif
+/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
+ overrides SIGCLD. SIGCHLD is in POXIX.1 */
+#if defined (SIGCLD)
+ {SIGCLD, "SIGCLD", "Child status changed"},
+#endif
+#if defined (SIGCHLD)
+ {SIGCHLD, "SIGCHLD", "Child status changed"},
+#endif
+#if defined (SIGPWR)
+ {SIGPWR, "SIGPWR", "Power fail/restart"},
+#endif
+#if defined (SIGWINCH)
+ {SIGWINCH, "SIGWINCH", "Window size changed"},
+#endif
+#if defined (SIGURG)
+ {SIGURG, "SIGURG", "Urgent I/O condition"},
+#endif
+#if defined (SIGIO)
+ /* "I/O pending" has also been suggested, but is misleading since the
+ signal only happens when the process has asked for it, not everytime
+ I/O is pending. */
+ {SIGIO, "SIGIO", "I/O possible"},
+#endif
+#if defined (SIGPOLL)
+ {SIGPOLL, "SIGPOLL", "Pollable event occurred"},
+#endif
+#if defined (SIGSTOP)
+ {SIGSTOP, "SIGSTOP", "Stopped (signal)"},
+#endif
+#if defined (SIGTSTP)
+ {SIGTSTP, "SIGTSTP", "Stopped (user)"},
+#endif
+#if defined (SIGCONT)
+ {SIGCONT, "SIGCONT", "Continued"},
+#endif
+#if defined (SIGTTIN)
+ {SIGTTIN, "SIGTTIN", "Stopped (tty input)"},
+#endif
+#if defined (SIGTTOU)
+ {SIGTTOU, "SIGTTOU", "Stopped (tty output)"},
+#endif
+#if defined (SIGVTALRM)
+ {SIGVTALRM, "SIGVTALRM", "Virtual timer expired"},
+#endif
+#if defined (SIGPROF)
+ {SIGPROF, "SIGPROF", "Profiling timer expired"},
+#endif
+#if defined (SIGXCPU)
+ {SIGXCPU, "SIGXCPU", "CPU time limit exceeded"},
+#endif
+#if defined (SIGXFSZ)
+ {SIGXFSZ, "SIGXFSZ", "File size limit exceeded"},
+#endif
+#if defined (SIGWIND)
+ {SIGWIND, "SIGWIND", "SIGWIND"},
+#endif
+#if defined (SIGPHONE)
+ {SIGPHONE, "SIGPHONE", "SIGPHONE"},
+#endif
+#if defined (SIGLOST)
+ {SIGLOST, "SIGLOST", "Resource lost"},
+#endif
+#if defined (SIGWAITING)
+ {SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"},
+#endif
+#if defined (SIGLWP)
+ {SIGLWP, "SIGLWP", "Signal LWP"},
+#endif
+#if defined (SIGDANGER)
+ {SIGDANGER, "SIGDANGER", "Swap space dangerously low"},
+#endif
+#if defined (SIGGRANT)
+ {SIGGRANT, "SIGGRANT", "Monitor mode granted"},
+#endif
+#if defined (SIGRETRACT)
+ {SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"},
+#endif
+#if defined (SIGMSG)
+ {SIGMSG, "SIGMSG", "Monitor mode data available"},
+#endif
+#if defined (SIGSOUND)
+ {SIGSOUND, "SIGSOUND", "Sound completed"},
+#endif
+#if defined (SIGSAK)
+ {SIGSAK, "SIGSAK", "Secure attention"},
+#endif
+ {0, NULL, NULL}
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ signal value to find the equivalent symbolic value. */
+
+static char **signal_names;
+static int num_signal_names = 0;
+
+/* Translation table allocated and initialized at runtime, if it does not
+ already exist in the host environment. Indexed by the signal value to find
+ the descriptive string.
+
+ We don't export it for use in other modules because even though it has the
+ same name, it differs from other implementations in that it is dynamically
+ initialized rather than statically initialized. */
+
+#ifdef NEED_sys_siglist
+
+static int sys_nsig;
+static char **sys_siglist;
+
+#else
+
+static int sys_nsig = NSIG;
+extern const char * const sys_siglist[];
+
+#endif
+
+
+/*
+
+NAME
+
+ init_signal_tables -- initialize the name and message tables
+
+SYNOPSIS
+
+ static void init_signal_tables ();
+
+DESCRIPTION
+
+ Using the signal_table, which is initialized at compile time, generate
+ the signal_names and the sys_siglist (if needed) tables, which are
+ indexed at runtime by a specific signal value.
+
+BUGS
+
+ The initialization of the tables may fail under low memory conditions,
+ in which case we don't do anything particularly useful, but we don't
+ bomb either. Who knows, it might succeed at a later point if we free
+ some memory in the meantime. In any case, the other routines know
+ how to deal with lack of a table after trying to initialize it. This
+ may or may not be considered to be a bug, that we don't specifically
+ warn about this particular failure mode.
+
+*/
+
+static void
+init_signal_tables ()
+{
+ const struct signal_info *eip;
+ int nbytes;
+
+ /* If we haven't already scanned the signal_table once to find the maximum
+ signal value, then go find it now. */
+
+ if (num_signal_names == 0)
+ {
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ if (eip -> value >= num_signal_names)
+ {
+ num_signal_names = eip -> value + 1;
+ }
+ }
+ }
+
+ /* Now attempt to allocate the signal_names table, zero it out, and then
+ initialize it from the statically initialized signal_table. */
+
+ if (signal_names == NULL)
+ {
+ nbytes = num_signal_names * sizeof (char *);
+ if ((signal_names = (char **) malloc (nbytes)) != NULL)
+ {
+ memset (signal_names, 0, nbytes);
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ signal_names[eip -> value] = eip -> name;
+ }
+ }
+ }
+
+#ifdef NEED_sys_siglist
+
+ /* Now attempt to allocate the sys_siglist table, zero it out, and then
+ initialize it from the statically initialized signal_table. */
+
+ if (sys_siglist == NULL)
+ {
+ nbytes = num_signal_names * sizeof (char *);
+ if ((sys_siglist = (char **) malloc (nbytes)) != NULL)
+ {
+ memset (sys_siglist, 0, nbytes);
+ sys_nsig = num_signal_names;
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ sys_siglist[eip -> value] = eip -> msg;
+ }
+ }
+ }
+
+#endif
+
+}
+
+
+/*
+
+NAME
+
+ signo_max -- return the max signo value
+
+SYNOPSIS
+
+ int signo_max ();
+
+DESCRIPTION
+
+ Returns the maximum signo value for which a corresponding symbolic
+ name or message is available. Note that in the case where
+ we use the sys_siglist supplied by the system, it is possible for
+ there to be more symbolic names than messages, or vice versa.
+ In fact, the manual page for psignal(3b) explicitly warns that one
+ should check the size of the table (NSIG) before indexing it,
+ since new signal codes may be added to the system before they are
+ added to the table. Thus NSIG might be smaller than value
+ implied by the largest signo value defined in <signal.h>.
+
+ We return the maximum value that can be used to obtain a meaningful
+ symbolic name or message.
+
+*/
+
+int
+signo_max ()
+{
+ int maxsize;
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ maxsize = MAX (sys_nsig, num_signal_names);
+ return (maxsize - 1);
+}
+
+
+/*
+
+NAME
+
+ strsignal -- map a signal number to a signal message string
+
+SYNOPSIS
+
+ char *strsignal (int signo)
+
+DESCRIPTION
+
+ Maps an signal number to an signal message string, the contents of
+ which are implementation defined. On systems which have the external
+ variable sys_siglist, these strings will be the same as the ones used
+ by psignal().
+
+ If the supplied signal number is within the valid range of indices
+ for the sys_siglist, but no message is available for the particular
+ signal number, then returns the string "Signal NUM", where NUM is the
+ signal number.
+
+ If the supplied signal number is not a valid index into sys_siglist,
+ returns NULL.
+
+ The returned string is only guaranteed to be valid only until the
+ next call to strsignal.
+
+*/
+
+char *
+strsignal (signo)
+ int signo;
+{
+ char *msg;
+ static char buf[32];
+
+#ifdef NEED_sys_siglist
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+
+#endif
+
+ if ((signo < 0) || (signo >= sys_nsig))
+ {
+ /* Out of range, just return NULL */
+ msg = NULL;
+ }
+ else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
+ {
+ /* In range, but no sys_siglist or no entry at this index. */
+ sprintf (buf, "Signal %d", signo);
+ msg = buf;
+ }
+ else
+ {
+ /* In range, and a valid message. Just return the message. */
+ msg = (char*)sys_siglist[signo];
+ }
+
+ return (msg);
+}
+
+
+/*
+
+NAME
+
+ strsigno -- map an signal number to a symbolic name string
+
+SYNOPSIS
+
+ char *strsigno (int signo)
+
+DESCRIPTION
+
+ Given an signal number, returns a pointer to a string containing
+ the symbolic name of that signal number, as found in <signal.h>.
+
+ If the supplied signal number is within the valid range of indices
+ for symbolic names, but no name is available for the particular
+ signal number, then returns the string "Signal NUM", where NUM is
+ the signal number.
+
+ If the supplied signal number is not within the range of valid
+ indices, then returns NULL.
+
+BUGS
+
+ The contents of the location pointed to are only guaranteed to be
+ valid until the next call to strsigno.
+
+*/
+
+char *
+strsigno (signo)
+ int signo;
+{
+ char *name;
+ static char buf[32];
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+
+ if ((signo < 0) || (signo >= num_signal_names))
+ {
+ /* Out of range, just return NULL */
+ name = NULL;
+ }
+ else if ((signal_names == NULL) || (signal_names[signo] == NULL))
+ {
+ /* In range, but no signal_names or no entry at this index. */
+ sprintf (buf, "Signal %d", signo);
+ name = buf;
+ }
+ else
+ {
+ /* In range, and a valid name. Just return the name. */
+ name = signal_names[signo];
+ }
+
+ return (name);
+}
+
+
+/*
+
+NAME
+
+ strtosigno -- map a symbolic signal name to a numeric value
+
+SYNOPSIS
+
+ int strtosigno (char *name)
+
+DESCRIPTION
+
+ Given the symbolic name of a signal, map it to a signal number.
+ If no translation is found, returns 0.
+
+*/
+
+int
+strtosigno (name)
+ char *name;
+{
+ int signo = 0;
+
+ if (name != NULL)
+ {
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ for (signo = 0; signo < num_signal_names; signo++)
+ {
+ if ((signal_names[signo] != NULL) &&
+ (strcmp (name, signal_names[signo]) == 0))
+ {
+ break;
+ }
+ }
+ if (signo == num_signal_names)
+ {
+ signo = 0;
+ }
+ }
+ return (signo);
+}
+
+
+/*
+
+NAME
+
+ psignal -- print message about signal to stderr
+
+SYNOPSIS
+
+ void psignal (unsigned signo, char *message);
+
+DESCRIPTION
+
+ Print to the standard error the message, followed by a colon,
+ followed by the description of the signal specified by signo,
+ followed by a newline.
+*/
+
+#ifdef NEED_psignal
+
+void
+psignal (signo, message)
+ unsigned signo;
+ char *message;
+{
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ if ((signo <= 0) || (signo >= sys_nsig))
+ {
+ fprintf (stderr, "%s: unknown signal\n", message);
+ }
+ else
+ {
+ fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
+ }
+}
+
+#endif /* NEED_psignal */
+
+
+/* A simple little main that does nothing but print all the signal translations
+ if MAIN is defined and this file is compiled and linked. */
+
+#ifdef MAIN
+
+main ()
+{
+ int signo;
+ int maxsigno;
+ char *name;
+ char *msg;
+ char *strsigno ();
+ char *strsignal ();
+
+ maxsigno = signo_max ();
+ printf ("%d entries in names table.\n", num_signal_names);
+ printf ("%d entries in messages table.\n", sys_nsig);
+ printf ("%d is max useful index.\n", maxsigno);
+
+ /* Keep printing values until we get to the end of *both* tables, not
+ *either* table. Note that knowing the maximum useful index does *not*
+ relieve us of the responsibility of testing the return pointer for
+ NULL. */
+
+ for (signo = 0; signo <= maxsigno; signo++)
+ {
+ name = strsigno (signo);
+ name = (name == NULL) ? "<NULL>" : name;
+ msg = strsignal (signo);
+ msg = (msg == NULL) ? "<NULL>" : msg;
+ printf ("%-4d%-18s%s\n", signo, name, msg);
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/xmalloc.c b/gnu/usr.bin/gdb/libiberty/xmalloc.c
new file mode 100644
index 000000000000..be0c7aa9319c
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/xmalloc.c
@@ -0,0 +1,58 @@
+/* memory allocation routines with error checking.
+ Copyright 1989, 1991, 1993 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty 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.
+
+Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <ansidecl.h>
+
+#include <stdio.h>
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#define size_t unsigned long
+#endif
+
+
+PTR
+xmalloc (size)
+ size_t size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) malloc ((int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't allocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+PTR
+xrealloc (oldmem, size)
+ PTR oldmem;
+ size_t size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't reallocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
diff --git a/gnu/usr.bin/gdb/main.c b/gnu/usr.bin/gdb/main.c
deleted file mode 100644
index 323de87975ad..000000000000
--- a/gnu/usr.bin/gdb/main.c
+++ /dev/null
@@ -1,2241 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)main.c 6.6 (Berkeley) 5/13/91";
-#endif /* not lint */
-
-/* Top level for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-GDB is free software; you can 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.
-
-GDB is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdio.h>
-#include "defs.h"
-#include "command.h"
-#include "param.h"
-#include "expression.h"
-
-#ifdef USG
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include <sys/file.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <ctype.h>
-
-#ifdef SET_STACK_LIMIT_HUGE
-#include <sys/time.h>
-#include <sys/resource.h>
-
-int original_stack_limit;
-#endif
-
-/* If this definition isn't overridden by the header files, assume
- that isatty and fileno exist on this system. */
-#ifndef ISATTY
-#define ISATTY(FP) (isatty (fileno (FP)))
-#endif
-
-extern void free ();
-
-/* Version number of GDB, as a string. */
-
-extern char *version;
-
-/*
- * Declare all cmd_list_element's
- */
-
-/* Chain containing all defined commands. */
-
-struct cmd_list_element *cmdlist;
-
-/* Chain containing all defined info subcommands. */
-
-struct cmd_list_element *infolist;
-
-/* Chain containing all defined enable subcommands. */
-
-struct cmd_list_element *enablelist;
-
-/* Chain containing all defined disable subcommands. */
-
-struct cmd_list_element *disablelist;
-
-/* Chain containing all defined delete subcommands. */
-
-struct cmd_list_element *deletelist;
-
-/* Chain containing all defined "enable breakpoint" subcommands. */
-
-struct cmd_list_element *enablebreaklist;
-
-/* Chain containing all defined set subcommands */
-
-struct cmd_list_element *setlist;
-
-/* Chain containing all defined \"set history\". */
-
-struct cmd_list_element *sethistlist;
-
-/* Chain containing all defined \"unset history\". */
-
-struct cmd_list_element *unsethistlist;
-
-/* stdio stream that command input is being read from. */
-
-FILE *instream;
-
-/* Current working directory. */
-
-char *current_directory;
-
-/* The directory name is actually stored here (usually). */
-static char dirbuf[MAXPATHLEN];
-
-#ifdef KERNELDEBUG
-/* Nonzero if we're debugging /dev/mem or a kernel crash dump */
-
-int kernel_debugging;
-#endif
-
-/* Nonzero to inhibit confirmation of quitting or restarting
- a stopped inferior. */
-int inhibit_confirm;
-
-/* Nonzero if we can write in text or core file */
-
-int writeable_text;
-
-/* The number of lines on a page, and the number of spaces
- in a line. */
-int linesize, pagesize;
-
-/* Nonzero if we should refrain from using an X window. */
-
-int inhibit_windows = 0;
-
-/* Function to call before reading a command, if nonzero.
- The function receives two args: an input stream,
- and a prompt string. */
-
-void (*window_hook) ();
-
-extern int frame_file_full_name;
-int xgdb_verbose;
-
-void execute_command();
-void free_command_lines ();
-char *gdb_readline ();
-char *command_line_input ();
-static void initialize_main ();
-static void initialize_cmd_lists ();
-void command_loop ();
-static void source_command ();
-static void print_gdb_version ();
-static void float_handler ();
-static void cd_command ();
-
-char *getenv ();
-
-/* gdb prints this when reading a command interactively */
-static char *prompt;
-
-/* Buffer used for reading command lines, and the size
- allocated for it so far. */
-
-char *line;
-int linesize;
-
-
-/* This is how `error' returns to command level. */
-
-jmp_buf to_top_level;
-
-void
-return_to_top_level ()
-{
- quit_flag = 0;
- immediate_quit = 0;
- clear_breakpoint_commands ();
- clear_momentary_breakpoints ();
- disable_current_display ();
- do_cleanups (0);
- longjmp (to_top_level, 1);
-}
-
-/* Call FUNC with arg ARG, catching any errors.
- If there is no error, return the value returned by FUNC.
- If there is an error, return zero after printing ERRSTRING
- (which is in addition to the specific error message already printed). */
-
-int
-catch_errors (func, arg, errstring)
- int (*func) ();
- int arg;
- char *errstring;
-{
- jmp_buf saved;
- int val;
- struct cleanup *saved_cleanup_chain;
-
- saved_cleanup_chain = save_cleanups ();
-
- bcopy (to_top_level, saved, sizeof (jmp_buf));
-
- if (setjmp (to_top_level) == 0)
- val = (*func) (arg);
- else
- {
- fprintf (stderr, "%s\n", errstring);
- val = 0;
- }
-
- restore_cleanups (saved_cleanup_chain);
-
- bcopy (saved, to_top_level, sizeof (jmp_buf));
- return val;
-}
-
-/* Handler for SIGHUP. */
-
-static void
-disconnect ()
-{
- kill_inferior_fast ();
- signal (SIGHUP, SIG_DFL);
- kill (getpid (), SIGHUP);
-}
-
-/* Clean up on error during a "source" command (or execution of a
- user-defined command).
- Close the file opened by the command
- and restore the previous input stream. */
-
-static void
-source_cleanup (stream)
- FILE *stream;
-{
- /* Instream may be 0; set to it when executing user-defined command. */
- if (instream)
- fclose (instream);
- instream = stream;
-}
-
-/*
- * Source $HOME/.gdbinit and $cwd/.gdbinit.
- * If X is enabled, also $HOME/.xgdbinit and $cwd/.xgdbinit.source
- */
-void
-source_init_files()
-{
- char *homedir, initfile[256];
- int samedir = 0;
-
- /* Read init file, if it exists in home directory */
- homedir = getenv ("HOME");
- if (homedir) {
- struct stat homebuf, cwdbuf;
-
- sprintf(initfile, "%s/.gdbinit", homedir);
- if (access (initfile, R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (initfile);
- if (!inhibit_windows) {
- sprintf(initfile, "%s/.xgdbinit", homedir);
- if (access (initfile, R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (initfile);
- }
- /* Determine if current directory is the same as the home
- directory, so we don't source the same file twice. */
-
- bzero (&homebuf, sizeof (struct stat));
- bzero (&cwdbuf, sizeof (struct stat));
-
- stat(homedir, &homebuf);
- stat(".", &cwdbuf);
-
- samedir = bcmp(&homebuf, &cwdbuf, sizeof(struct stat)) == 0;
- }
- /* Read the input file in the current directory, *if* it isn't
- the same file (it should exist, also). */
- if (!samedir) {
- if (access (".gdbinit", R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (".gdbinit");
- if (access (".xgdbinit", R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (".xgdbinit");
- }
-}
-
-
-int
-main (argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
-{
- int count;
- int inhibit_gdbinit = 0;
- int quiet = 1;
- int batch = 0;
- register int i;
- char *cp;
-
- /* XXX Windows only for xgdb. */
- char *strrchr();
- if (cp = strrchr(argv[0], '/'))
- ++cp;
- else
- cp = argv[0];
- if (*cp != 'x')
- inhibit_windows = 1;
-
-#if defined (ALIGN_STACK_ON_STARTUP)
- i = (int) &count & 0x3;
- if (i != 0)
- alloca (4 - i);
-#endif
-
- quit_flag = 0;
- linesize = 100;
- line = (char *) xmalloc (linesize);
- *line = 0;
- instream = stdin;
-
- getwd (dirbuf);
- current_directory = dirbuf;
-
-#ifdef SET_STACK_LIMIT_HUGE
- {
- struct rlimit rlim;
-
- /* Set the stack limit huge so that alloca (particularly stringtab
- * in dbxread.c) does not fail. */
- getrlimit (RLIMIT_STACK, &rlim);
- original_stack_limit = rlim.rlim_cur;
- rlim.rlim_cur = rlim.rlim_max;
- setrlimit (RLIMIT_STACK, &rlim);
- }
-#endif /* SET_STACK_LIMIT_HUGE */
-
- /* Look for flag arguments. */
-
- for (i = 1; i < argc; i++)
- {
- if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet"))
- quiet = 1;
- else if (!strcmp (argv[i], "-nx"))
- inhibit_gdbinit = 1;
- else if (!strcmp (argv[i], "-nw"))
- inhibit_windows = 1;
- else if (!strcmp (argv[i], "-batch"))
- batch = 1, quiet = 1;
- else if (!strcmp (argv[i], "-fullname"))
- frame_file_full_name = 1;
- else if (!strcmp (argv[i], "-xgdb_verbose"))
- xgdb_verbose = 1;
- /* -help: print a summary of command line switches. */
- else if (!strcmp (argv[i], "-help"))
- {
- fputs ("\
-This is GDB, the GNU debugger. Use the command\n\
- gdb [options] [executable [core-file]]\n\
-to enter the debugger.\n\
-\n\
-Options available are:\n\
- -help Print this message.\n\
- -quiet Do not print version number on startup.\n\
- -fullname Output information used by emacs-GDB interface.\n\
- -batch Exit after processing options.\n\
- -nx Do not read .gdbinit file.\n\
- -tty TTY Use TTY for input/output by the program being debugged.\n\
- -cd DIR Change current directory to DIR.\n\
- -directory DIR Search for source files in DIR.\n\
- -command FILE Execute GDB commands from FILE.\n\
- -symbols SYMFILE Read symbols from SYMFILE.\n\
- -exec EXECFILE Use EXECFILE as the executable.\n\
- -se FILE Use FILE as symbol file and executable file.\n\
- -core COREFILE Analyze the core dump COREFILE.\n\
- -k Kernel debugging.\n\
- -w Writeable text.\n\
- -v Print GNU message and version number on startup.\n\
- -nc Don't confirm quit or run commands.\n\
-\n\
-For more information, type \"help\" from within GDB, or consult the\n\
-GDB manual (available as on-line info or a printed manual).\n", stderr);
- /* Exiting after printing this message seems like
- the most useful thing to do. */
- exit (0);
- }
-#ifdef KERNELDEBUG
- else if (!strcmp (argv[i], "-k"))
- kernel_debugging = 1;
-#endif
- else if (!strcmp (argv[i], "-w"))
- writeable_text = 1;
- else if (!strcmp (argv[i], "-v"))
- quiet = 0;
- else if (!strcmp (argv[i], "-nc"))
- inhibit_confirm = 1;
- else if (argv[i][0] == '-')
- /* Other options take arguments, so don't confuse an
- argument with an option. */
- i++;
- }
-
- /* Run the init function of each source file */
-
- initialize_cmd_lists (); /* This needs to be done first */
- initialize_all_files ();
- initialize_main (); /* But that omits this file! Do it now */
- initialize_signals ();
-
- if (!quiet)
- print_gdb_version ();
-
- /* Process the command line arguments. */
-
- count = 0;
- for (i = 1; i < argc; i++)
- {
- extern void exec_file_command (), symbol_file_command ();
- extern void core_file_command ();
- register char *arg = argv[i];
- /* Args starting with - say what to do with the following arg
- as a filename. */
- if (arg[0] == '-')
- {
- extern void tty_command (), directory_command ();
-
- if (!strcmp (arg, "-q") || !strcmp (arg, "-nx")
- || !strcmp (arg, "-quiet") || !strcmp (arg, "-batch")
- || !strcmp (arg, "-fullname") || !strcmp (arg, "-nw")
- || !strcmp (arg, "-xgdb_verbose")
- || !strcmp (arg, "-help")
- || !strcmp (arg, "-k")
- || !strcmp (arg, "-w")
- || !strcmp (arg, "-v")
- || !strcmp (arg, "-nc"))
- /* Already processed above */
- continue;
-
- if (++i == argc)
- fprintf (stderr, "No argument follows \"%s\".\n", arg);
- if (!setjmp (to_top_level))
- {
- /* -s foo: get syms from foo. -e foo: execute foo.
- -se foo: do both with foo. -c foo: use foo as core dump. */
- if (!strcmp (arg, "-se"))
- {
- exec_file_command (argv[i], !batch);
- symbol_file_command (argv[i], !batch);
- }
- else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols"))
- symbol_file_command (argv[i], !batch);
- else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec"))
- exec_file_command (argv[i], !batch);
- else if (!strcmp (arg, "-c") || !strcmp (arg, "-core"))
- core_file_command (argv[i], !batch);
- /* -x foo: execute commands from foo. */
- else if (!strcmp (arg, "-x") || !strcmp (arg, "-command")
- || !strcmp (arg, "-commands"))
- source_command (argv[i]);
- /* -d foo: add directory `foo' to source-file directory
- search-list */
- else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir")
- || !strcmp (arg, "-directory"))
- directory_command (argv[i], 0);
- /* -cd FOO: specify current directory as FOO.
- GDB remembers the precise string FOO as the dirname. */
- else if (!strcmp (arg, "-cd"))
- {
- cd_command (argv[i], 0);
- init_source_path ();
- }
- /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */
- else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty"))
- tty_command (argv[i], 0);
-
- else
- error ("Unknown command-line switch: \"%s\"\n", arg);
- }
- }
- else
- {
- /* Args not thus accounted for
- are treated as, first, the symbol/executable file
- and, second, the core dump file. */
- count++;
- if (!setjmp (to_top_level))
- switch (count)
- {
- case 1:
- exec_file_command (arg, !batch);
- symbol_file_command (arg, !batch);
- break;
-
- case 2:
- core_file_command (arg, !batch);
- break;
-
- case 3:
- fprintf (stderr, "Excess command line args ignored. (%s%s)\n",
- arg, (i == argc - 1) ? "" : " ...");
- }
- }
- }
-
- if (!inhibit_gdbinit)
- source_init_files();
-
- if (batch)
- {
-#if 0
- fatal ("Attempt to read commands from stdin in batch mode.");
-#endif
- /* We have hit the end of the batch file. */
- exit (0);
- }
-
- if (!quiet)
- printf ("Type \"help\" for a list of commands.\n");
-
- /* The command loop. */
-
- while (1)
- {
- if (!setjmp (to_top_level))
- command_loop ();
- if (ISATTY(stdin))
- clearerr (stdin); /* Don't get hung if C-d is typed. */
- else if (feof(instream)) /* Avoid endless loops for redirected stdin */
- break;
- }
- exit (0);
-}
-
-
-static void
-do_nothing ()
-{
-}
-
-/* Read commands from `instream' and execute them
- until end of file. */
-void
-command_loop ()
-{
- struct cleanup *old_chain;
- register int toplevel = (instream == stdin);
- register int interactive = (toplevel && ISATTY(stdin));
-
- while (!feof (instream))
- {
- register char *cmd_line;
-
- quit_flag = 0;
- if (interactive)
- reinitialize_more_filter ();
- old_chain = make_cleanup (do_nothing, 0);
- cmd_line = command_line_input (prompt, toplevel);
- execute_command (cmd_line, toplevel);
- /* Do any commands attached to breakpoint we stopped at. */
- do_breakpoint_commands ();
- do_cleanups (old_chain);
- }
-}
-
-/* Commands call this if they do not want to be repeated by null lines. */
-
-void
-dont_repeat ()
-{
- /* If we aren't reading from standard input, we are saving the last
- thing read from stdin in line and don't want to delete it. Null lines
- won't repeat here in any case. */
- if (instream == stdin)
- *line = 0;
-}
-
-/* Read a line from the stream "instream" without command line editing.
-
- It prints PROMPT once at the start.
- Action is compatible with "readline" (i.e., space for typing is
- malloced & should be freed by caller). */
-char *
-gdb_readline (prompt)
- char *prompt;
-{
- int c;
- char *result;
- int input_index = 0;
- int result_size = 80;
-
- if (prompt)
- {
- printf (prompt);
- fflush (stdout);
- }
-
- result = (char *) xmalloc (result_size);
-
- while (1)
- {
- c = fgetc (instream ? instream : stdin);
- if (c == EOF)
- {
- free(result);
- return ((char *)0);
- }
- if (c == '\n')
- break;
-
- result[input_index++] = c;
- if (input_index >= result_size)
- {
- result_size <= 1;
- result = (char *)xrealloc(result, result_size);
- }
- }
- result[input_index++] = '\0';
- return result;
-}
-
-/* Declaration for fancy readline with command line editing. */
-char *readline ();
-
-/* Variables which control command line editing and history
- substitution. These variables are given default values at the end
- of this file. */
-static int command_editing_p;
-static int history_expansion_p;
-static int write_history_p;
-static int history_size;
-static char *history_filename;
-
-/* Variables which are necessary for fancy command line editing. */
-char *gdb_completer_word_break_characters =
- " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
-
-/* Functions that are used as part of the fancy command line editing. */
-
-/* Generate symbol names one by one for the completer. If STATE is
- zero, then we need to initialize, otherwise the initialization has
- already taken place. TEXT is what we expect the symbol to start
- with. RL_LINE_BUFFER is available to be looked at; it contains the
- entire text of the line. RL_POINT is the offset in that line of
- the cursor. You should pretend that the line ends at RL_POINT. */
-char *
-symbol_completion_function (text, state)
- char *text;
- int state;
-{
- char **make_symbol_completion_list ();
- static char **list = (char **)NULL;
- static int index;
- char *output;
- extern char *rl_line_buffer;
- extern int rl_point;
- char *tmp_command, *p;
- struct cmd_list_element *c, *result_list;
-
- if (!state)
- {
- /* Free the storage used by LIST, but not by the strings inside. This is
- because rl_complete_internal () frees the strings. */
- if (list)
- free (list);
- list = 0;
- index = 0;
-
- /* Decide whether to complete on a list of gdb commands or on
- symbols. */
- tmp_command = (char *) alloca (rl_point + 1);
- p = tmp_command;
-
- strncpy (tmp_command, rl_line_buffer, rl_point);
- tmp_command[rl_point] = '\0';
-
- if (rl_point == 0)
- {
- /* An empty line we want to consider ambiguous; that is,
- it could be any command. */
- c = (struct cmd_list_element *) -1;
- result_list = 0;
- }
- else
- c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
-
- /* Move p up to the next interesting thing. */
- while (*p == ' ' || *p == '\t')
- p++;
-
- if (!c)
- /* He's typed something unrecognizable. Sigh. */
- list = (char **) 0;
- else if (c == (struct cmd_list_element *) -1)
- {
- if (p + strlen(text) != tmp_command + rl_point)
- error ("Unrecognized command.");
-
- /* He's typed something ambiguous. This is easier. */
- if (result_list)
- list = complete_on_cmdlist (*result_list->prefixlist, text);
- else
- list = complete_on_cmdlist (cmdlist, text);
- }
- else
- {
- /* If we've gotten this far, gdb has recognized a full
- command. There are several possibilities:
-
- 1) We need to complete on the command.
- 2) We need to complete on the possibilities coming after
- the command.
- 2) We need to complete the text of what comes after the
- command. */
-
- if (!*p && *text)
- /* Always (might be longer versions of thie command). */
- list = complete_on_cmdlist (result_list, text);
- else if (!*p && !*text)
- {
- if (c->prefixlist)
- list = complete_on_cmdlist (*c->prefixlist, "");
- else
- list = make_symbol_completion_list ("");
- }
- else
- {
- if (c->prefixlist && !c->allow_unknown)
- {
- *p = '\0';
- error ("\"%s\" command requires a subcommand.",
- tmp_command);
- }
- else
- list = make_symbol_completion_list (text);
- }
- }
- }
-
- /* If the debugged program wasn't compiled with symbols, or if we're
- clearly completing on a command and no command matches, return
- NULL. */
- if (!list)
- return ((char *)NULL);
-
- output = list[index];
- if (output)
- index++;
-
- return (output);
-}
-
-
-void
-print_prompt ()
-{
- if (prompt)
- {
- printf ("%s", prompt);
- fflush (stdout);
- }
-}
-
-
-#ifdef HAVE_TERMIO
-#include <termio.h>
-static struct termio norm_tty;
-
-static void
-suspend_sig()
-{
- int tty = fileno(stdin);
- struct termio cur_tty;
-
- ioctl(tty, TCGETA, &cur_tty);
- ioctl(tty, TCSETAW, &norm_tty);
-
- (void) sigsetmask(0);
- signal(SIGTSTP, SIG_DFL);
- kill(0, SIGTSTP);
-
- /*
- * we've just been resumed -- current tty params become new
- * 'normal' params (in case tset/stty was done while we were
- * suspended). Merge values that readline might have changed
- * into new params, then restore term mode.
- */
- ioctl(tty, TCGETA, &norm_tty);
- cur_tty.c_lflag = (cur_tty.c_lflag & (ICANON|ECHO|ISIG)) |
- (norm_tty.c_lflag &~ (ICANON|ECHO|ISIG));
- cur_tty.c_iflag = (cur_tty.c_iflag & (IXON|ISTRIP|INPCK)) |
- (norm_tty.c_iflag &~ (IXON|ISTRIP|INPCK));
- ioctl(tty, TCSETAW, &cur_tty);
-
- signal(SIGTSTP, suspend_sig);
- print_prompt();
-
- /*
- * Forget about any previous command -- null line now will do
- * nothing.
- */
- dont_repeat();
-}
-
-#else
-
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <sgtty.h>
-
-static struct sgttyb norm_tty;
-static struct tchars norm_tchars;
-static struct ltchars norm_ltchars;
-static int norm_lflags;
-
-#ifdef PASS8
-#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK|PASS8)
-#else
-#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK)
-#endif
-
-static void
-suspend_sig()
-{
- int tty = fileno(stdin);
- struct sgttyb cur_tty;
- struct tchars cur_tchars;
- struct ltchars cur_ltchars;
- int cur_lflags;
- int cur_flags;
-
- ioctl(tty, TIOCGETP, &cur_tty);
- ioctl(tty, TIOCGETC, &cur_tchars);
- ioctl(tty, TIOCLGET, &cur_lflags);
- ioctl(tty, TIOCGLTC, &cur_ltchars);
-
- ioctl(tty, TIOCSETP, &norm_tty);
- ioctl(tty, TIOCSETC, &norm_tchars);
- ioctl(tty, TIOCLSET, &norm_lflags);
- ioctl(tty, TIOCSLTC, &norm_ltchars);
-
- (void) sigsetmask(0);
- signal(SIGTSTP, SIG_DFL);
- kill(0, SIGTSTP);
-
- /*
- * we've just been resumed -- current tty params become new
- * 'normal' params (in case tset/stty was done while we were
- * suspended). Merge values that readline might have changed
- * into new params, then restore term mode.
- */
- ioctl(tty, TIOCGETP, &norm_tty);
- cur_flags = cur_tty.sg_flags;
- cur_tty = norm_tty;
- cur_tty.sg_flags = (cur_tty.sg_flags &~ RL_TFLAGS)
- | (cur_flags & RL_TFLAGS);
-
- ioctl(tty, TIOCLGET, &norm_lflags);
-#ifdef LPASS8
- cur_lflags = (cur_lflags &~ LPASS8) | (cur_flags & LPASS8);
-#endif
- ioctl(tty, TIOCGETC, &norm_tchars);
- ioctl(tty, TIOCGLTC, &norm_ltchars);
-
- ioctl(tty, TIOCSETP, &cur_tty);
- ioctl(tty, TIOCSETC, &cur_tchars);
- ioctl(tty, TIOCLSET, &cur_lflags);
- ioctl(tty, TIOCSLTC, &cur_ltchars);
-
- signal(SIGTSTP, suspend_sig);
- print_prompt();
-
- /*
- * Forget about any previous command -- null line now will do
- * nothing.
- */
- dont_repeat();
-}
-#endif /* HAVE_TERMIO */
-
-/* Initialize signal handlers. */
-initialize_signals ()
-{
- extern void request_quit ();
- int tty = fileno(stdin);
-
- signal (SIGINT, request_quit);
-
- /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
- passed to the inferior, which we don't want. It would be
- possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
- on BSD4.3 systems using vfork, that will (apparently) affect the
- GDB process as well as the inferior (the signal handling tables
- being shared between the two, apparently). Since we establish
- a handler for SIGQUIT, when we call exec it will set the signal
- to SIG_DFL for us. */
- signal (SIGQUIT, do_nothing);
- if (signal (SIGHUP, do_nothing) != SIG_IGN)
- signal (SIGHUP, disconnect);
- signal (SIGFPE, float_handler);
-
- ioctl(tty, TIOCGETP, &norm_tty);
- ioctl(tty, TIOCLGET, &norm_lflags);
- ioctl(tty, TIOCGETC, &norm_tchars);
- ioctl(tty, TIOCGLTC, &norm_ltchars);
- signal(SIGTSTP, suspend_sig);
-}
-
-char *
-finish_command_input(inputline, repeat, interactive)
- register char *inputline;
- int repeat;
- int interactive;
-{
- static char *do_free;
-
- if (do_free) {
- free(do_free);
- do_free = NULL;
- }
-
- /* Do history expansion if that is wished. */
- if (interactive && history_expansion_p) {
- int expanded;
-
- expanded = history_expand(inputline, &do_free);
- if (expanded) {
- /* Print the changes. */
- puts(do_free);
-
- /* An error acts like no input. */
- if (expanded < 0) {
- *do_free = 0;
- return (do_free);
- }
- }
- inputline = do_free;
- }
- /* get rid of any leading whitespace */
- while (isspace(*inputline))
- ++inputline;
- /*
- * If we just got an empty line, and that is supposed to repeat the
- * previous command, return the value in the global buffer.
- */
- if (*inputline == 0) {
- if (repeat)
- return (line);
- } else if (interactive)
- add_history(inputline);
-
- /*
- * If line is a comment, clear it out.
- * Note: comments are added to the command history. This is useful
- * when you type a command, and then realize you don't want to
- * execute it quite yet. You can comment out the command and then
- * later fetch it from the value history and remove the '#'.
- */
- if (*inputline == '#')
- *inputline = 0;
- else if (repeat) {
- /* Save into global buffer. */
- register int i = strlen(inputline) + 1;
-
- if (i > linesize) {
- line = xrealloc(line, i);
- linesize = i;
- }
- strcpy(line, inputline);
- }
- return (inputline);
-}
-
-static char *
-get_a_cmd_line(prompt, interactive)
- char *prompt;
- int interactive;
-{
- register char *cp;
-
- /* Control-C quits instantly if typed while reading input. */
- immediate_quit++;
- if (interactive && command_editing_p) {
- extern void (*rl_event_hook)();
-
- rl_event_hook = window_hook;
- cp = readline(prompt);
- } else {
- if (interactive) {
- if (window_hook) {
- print_prompt();
- (*window_hook)();
- }
- } else
- prompt = NULL;
- cp = gdb_readline(prompt);
- }
- --immediate_quit;
- return (cp);
-}
-
-/* Read one line from the command input stream `instream'
- Returns the address of the start of the line.
-
- *If* the instream == stdin & stdin is a terminal, the line read
- is copied into the file line saver (global var char *line,
- length linesize) so that it can be duplicated.
-
- This routine either uses fancy command line editing or
- simple input as the user has requested. */
-
-char *
-command_line_input(prompt, repeat)
- char *prompt;
- int repeat;
-{
- static char *do_free;
- register int interactive = (instream == stdin && ISATTY(instream));
- register char *cp;
- register int i;
-
- if (do_free) {
- free(do_free);
- do_free = NULL;
- }
- cp = get_a_cmd_line(prompt, interactive);
-
- /*
- * handle continued lines (this loop is not particularly
- * efficient because it's rare).
- */
- while (cp && cp[i = strlen(cp) - 1] == '\\') {
- register char *np = get_a_cmd_line(prompt, interactive);
- register int j;
-
- if (np == NULL) {
- cp[i] = 0;
- break;
- }
- j = strlen(np);
- cp = xrealloc(cp, i + j + 1);
- strcpy(cp + i, np);
- free(np);
- }
- if (cp == NULL)
- return ("");
- do_free = cp;
- return (finish_command_input(cp, repeat, interactive));
-}
-
-
-#define MAX_USER_ARGS 32
-
-static struct user_args {
- struct {
- char *arg;
- int len;
- } a[10];
-} uargs[MAX_USER_ARGS];
-
-static struct user_args *user_arg = uargs;
-
-static void
-arg_cleanup(ap)
- struct user_args *ap;
-{
- user_arg = ap;
-}
-
-/* Bind arguments $arg0, $arg1, ..., for a user defined command. */
-struct cleanup *
-setup_user_args(p)
- char *p;
-{
- register int i;
- struct cleanup *old_chain = make_cleanup(arg_cleanup, user_arg);
-
- if (++user_arg >= &uargs[MAX_USER_ARGS])
- error("user defined functions nested too deeply\n");
-
- bzero(user_arg, sizeof(*user_arg));
-
- i = 0;
- while (*p) {
- while (isspace(*p))
- ++p;
- user_arg->a[i].arg = p;
- while (*p && ! isspace(*p))
- ++p;
- user_arg->a[i].len = p - user_arg->a[i].arg;
- ++i;
- }
- return (old_chain);
-}
-
-static char *
-findarg(str)
- register char *str;
-{
- register char *cp = str;
- extern char *index();
-
- while (cp = index(cp, '$')) {
- if (strncmp(cp, "$arg", 4) == 0 && isdigit(cp[4]))
- return (cp);
- ++cp;
- }
- return (char *)0;
-}
-
-/* expand arguments from "line" into "new" */
-static void
-expand_args(line, new)
- register char *line, *new;
-{
- register char *cp = findarg(line);
-
- while (cp = findarg(line)) {
- int i, len;
-
- bcopy(line, new, cp - line);
- new += cp - line;
- i = cp[4] - '0';
- if (len = user_arg->a[i].len) {
- bcopy(user_arg->a[i].arg, new, len);
- new += len;
- }
- line = cp + 5;
- }
- strcpy(new, line);
-}
-
-/* expand any arguments in "line" then execute the result */
-static void
-expand_and_execute(line, from_tty)
- char *line;
- int from_tty;
-{
- void execute_command();
- char new[1024];
-
- if (! findarg(line)) {
- execute_command(line, from_tty);
- return;
- }
- expand_args(line, new);
- execute_command(new, from_tty);
-}
-
-char *
-read_one_command_line(prompt, from_tty)
- char *prompt;
-{
- register char *p, *p1;
-
- dont_repeat();
- p = command_line_input(prompt, from_tty);
-
- /* Remove trailing blanks. */
- p1 = p + strlen(p);
- while (--p1 > p && (*p1 == ' ' || *p1 == '\t'))
- ;
- *++p1 = 0;
- return (p);
-}
-
-static char cmd_prompt[] = " > ";
-
-int
-parse_control_structure(rootcmd, from_tty, level)
- struct command_line *rootcmd;
- int from_tty;
-{
- struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
- char *prompt;
-
- ++level;
- prompt = from_tty? &cmd_prompt[sizeof(cmd_prompt) - 1 - 2*level] :
- (char *)0;
- bzero(cmd, sizeof(*cmd));
- rootcmd->body = cmd;
- while (1) {
- char *p = read_one_command_line(prompt, from_tty);
-
- p = savestring(p, strlen(p));
- cmd->line = p;
- if (!strncmp(p, "while ", 6)) {
- cmd->type = CL_WHILE;
- if (parse_control_structure(cmd, from_tty, level))
- return (1);
- } else if (!strncmp(p, "if ", 3)) {
- cmd->type = CL_IF;
- if (parse_control_structure(cmd, from_tty, level)) {
- struct command_line *tmp;
- int stat;
-
- cmd->elsebody = cmd->body;
- stat = parse_control_structure(cmd, from_tty,
- level);
- tmp = cmd->elsebody;
- cmd->elsebody = cmd->body;
- cmd->body = tmp;
- if (stat)
- return (1);
- }
- } else if (!strcmp(p, "else")) {
- cmd->type = CL_END;
- return (1);
- } else if (!strcmp(p, "end")) {
- cmd->type = CL_END;
- return (0);
- } else if (!strcmp(p, "exitloop")) {
- cmd->type = CL_EXITLOOP;
- } else {
- cmd->type = CL_NORMAL;
- }
- cmd->next = (struct command_line *)xmalloc(sizeof(*cmd));
- cmd = cmd->next;
- bzero(cmd, sizeof(*cmd));
- }
- /* NOTREACHED */
-}
-
-int
-execute_control_structure(cmd)
- register struct command_line *cmd;
-{
- char expn[1024];
- struct expression *cond;
- int stat;
-
- while (cmd) {
- QUIT;
- switch (cmd->type) {
- case CL_END:
- return (0);
- case CL_NORMAL:
- expand_and_execute(cmd->line, 0);
- break;
- case CL_WHILE:
- expand_args(cmd->line + 6, expn);
- cond = parse_c_expression(expn);
- while (breakpoint_cond_eval(cond) == 0)
- if (execute_control_structure(cmd->body))
- break;
- free(cond);
- break;
- case CL_IF:
- expand_args(cmd->line + 3, expn);
- cond = parse_c_expression(expn);
- stat = breakpoint_cond_eval(cond);
- free(cond);
- if (stat == 0) {
- if (execute_control_structure(cmd->body))
- return (1);
- } else if (cmd->elsebody) {
- if (execute_control_structure(cmd->elsebody))
- return (1);
- }
- break;
- case CL_EXITLOOP:
- return (1);
- }
- cmd = cmd->next;
- }
- free_all_values();
-}
-
-execute_command_lines(cmd)
- struct command_line *cmd;
-{
- struct cleanup *old_chain = make_cleanup(source_cleanup, instream);
-
- /*
- * Set the instream to 0, indicating execution of a user-defined
- * function.
- */
- ++immediate_quit;
- instream = (FILE *) 0;
- (void)execute_control_structure(cmd);
- --immediate_quit;
- do_cleanups(old_chain);
-}
-
-/* do following command lines if expression true */
-if_command(p, from_tty)
- char *p;
- int from_tty;
-{
- struct cleanup *old_chain;
- struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
- char buf[128];
-
- sprintf(buf, "if %s", p);
-
- bzero(cmd, sizeof(*cmd));
- old_chain = make_cleanup(free_command_lines, cmd);
- cmd->type = CL_IF;
- cmd->line = savestring(buf, strlen(buf));
- /* XXX cmd->line? */
- if (parse_control_structure(cmd, from_tty, 0)) {
- struct command_line *tmp;
-
- cmd->elsebody = cmd->body;
- (void) parse_control_structure(cmd, from_tty, 0);
- tmp = cmd->elsebody;
- cmd->elsebody = cmd->body;
- cmd->body = tmp;
- }
- (void) execute_command_lines(cmd);
- do_cleanups(old_chain);
-}
-
-/* do following command lines while expression true */
-while_command(p, from_tty)
- char *p;
- int from_tty;
-{
- struct cleanup *old_chain;
- struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
- char buf[128];
-
- sprintf(buf, "while %s", p);
-
- bzero(cmd, sizeof(*cmd));
- old_chain = make_cleanup(free_command_lines, cmd);
- cmd->type = CL_WHILE;
- cmd->line = savestring(buf, strlen(buf));
- (void)parse_control_structure(cmd, from_tty, 0);
- (void)execute_command_lines(cmd);
- do_cleanups(old_chain);
-}
-
-/*
- * Execute the line P as a command.
- * Pass FROM_TTY as second argument to the defining function.
- */
-void
-execute_command (p, from_tty)
- char *p;
- int from_tty;
-{
- register struct cmd_list_element *c;
- register struct command_line *cmdlines;
-
- free_all_values();
- if (*p) {
- c = lookup_cmd(&p, cmdlist, "", 0, 1);
- if (c->function == 0)
- error("That is not a command, just a help topic.");
- else if (c->class == (int) class_user) {
- struct cleanup *old_chain = setup_user_args(p);
-
- cmdlines = (struct command_line *) c->function;
- if (cmdlines)
- (void)execute_command_lines(cmdlines);
-
- do_cleanups(old_chain);
- } else
- /* Pass null arg rather than an empty one. */
- (*c->function) (*p ? p : 0, from_tty);
- }
-}
-
-/*
- * Read lines from the input stream and accumulate them in a chain of struct
- * command_line's which is then returned.
- */
-struct command_line *
-read_command_lines(from_tty)
- int from_tty;
-{
- struct cleanup *old_chain;
- struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
- struct command_line *next;
-
- bzero(cmd, sizeof(*cmd));
- old_chain = make_cleanup(free_command_lines, cmd);
- cmd->type = CL_NOP;
- (void)parse_control_structure(cmd, from_tty, 0);
- dont_repeat();
- discard_cleanups(old_chain);
- next = cmd->body;
- free(cmd);
- return (next);
-}
-
-/* Free a chain of struct command_line's. */
-
-void
-free_command_lines(cmds)
- struct command_line *cmds;
-{
- struct command_line *next;
-
- while (cmds) {
- if (cmds->body)
- free(cmds->body);
- if (cmds->elsebody)
- free(cmds->elsebody);
- if (cmds->line)
- free(cmds->line);
- next = cmds->next;
- free(cmds);
- cmds = next;
- }
-}
-
-/* Add an element to the list of info subcommands. */
-
-void
-add_info (name, fun, doc)
- char *name;
- void (*fun) ();
- char *doc;
-{
- add_cmd (name, no_class, fun, doc, &infolist);
-}
-
-/* Add an alias to the list of info subcommands. */
-
-void
-add_info_alias (name, oldname, abbrev_flag)
- char *name;
- char *oldname;
- int abbrev_flag;
-{
- add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
-}
-
-/* The "info" command is defined as a prefix, with allow_unknown = 0.
- Therefore, its own definition is called only for "info" with no args. */
-
-static void
-info_command ()
-{
- printf ("\"info\" must be followed by the name of an info command.\n");
- help_list (infolist, "info ", -1, stdout);
-}
-
-/* Add an element to the list of commands. */
-
-void
-add_com (name, class, fun, doc)
- char *name;
- int class;
- void (*fun) ();
- char *doc;
-{
- add_cmd (name, class, fun, doc, &cmdlist);
-}
-
-/* Add an alias or abbreviation command to the list of commands. */
-
-void
-add_com_alias (name, oldname, class, abbrev_flag)
- char *name;
- char *oldname;
- int class;
- int abbrev_flag;
-{
- add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
-}
-
-void
-error_no_arg (why)
- char *why;
-{
- error ("Argument required (%s).", why);
-}
-
-static void
-help_command (command, from_tty)
- char *command;
- int from_tty; /* Ignored */
-{
- help_cmd (command, stdout);
-}
-
-static void
-validate_comname (comname)
- char *comname;
-{
- register char *p;
-
- if (comname == 0)
- error_no_arg ("name of command to define");
-
- p = comname;
- while (*p)
- {
- if (!(*p >= 'A' && *p <= 'Z')
- && !(*p >= 'a' && *p <= 'z')
- && !(*p >= '0' && *p <= '9')
- && *p != '-')
- error ("Junk in argument list: \"%s\"", p);
- p++;
- }
-}
-
-static void
-define_command (comname, from_tty)
- char *comname;
- int from_tty;
-{
- register struct command_line *cmds;
- register struct cmd_list_element *c;
- char *tem = comname;
-
- validate_comname (comname);
-
- c = lookup_cmd (&tem, cmdlist, "", -1, 1);
- if (c)
- {
- if (c->class == (int) class_user || c->class == (int) class_alias)
- tem = "Redefine command \"%s\"? ";
- else
- tem = "Really redefine built-in command \"%s\"? ";
- if (!query (tem, comname))
- error ("Command \"%s\" not redefined.", comname);
- }
-
- if (from_tty)
- {
- printf ("Type commands for definition of \"%s\".\n\
-End with a line saying just \"end\".\n", comname);
- fflush (stdout);
- }
- comname = savestring (comname, strlen (comname));
-
- cmds = read_command_lines (from_tty);
-
- if (c && c->class == (int) class_user)
- free_command_lines (c->function);
-
- add_com (comname, class_user, cmds,
- (c && c->class == (int) class_user)
- ? c->doc : savestring ("User-defined.", 13));
-}
-
-static void
-document_command (comname, from_tty)
- char *comname;
- int from_tty;
-{
- register struct cmd_list_element *c;
- register char *p;
- register char *cp;
- register char *doc = 0;
- register int len;
- char *tmp = comname;
-
- validate_comname (comname);
- c = lookup_cmd (&tmp, cmdlist, "", 0, 1);
- if (c->class != (int) class_user)
- error ("Command \"%s\" is built-in.", comname);
-
- if (from_tty)
- printf ("Type documentation for \"%s\". \
-End with a line saying just \"end\".\n", comname);
-
- while (p = read_one_command_line(from_tty? "> " : 0, from_tty))
- {
- if (strcmp(p, "end") == 0)
- break;
- len = strlen(p) + 1;
- if (! doc)
- {
- doc = xmalloc(len);
- cp = doc;
- }
- else
- {
- int i = cp - doc;
- doc = xrealloc(doc, i + len);
- cp = doc + i;
- }
- strcpy(cp, p);
- cp += len;
- cp[-1] = '\n';
- }
- if (doc && cp > doc)
- cp[-1] = 0;
- if (c->doc)
- free (c->doc);
- c->doc = doc;
-}
-
-static void
-print_gdb_version ()
-{
- printf ("GDB %s, Copyright (C) 1989 Free Software Foundation, Inc.\n\
-There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
-GDB is free software and you are welcome to distribute copies of it\n\
- under certain conditions; type \"info copying\" to see the conditions.\n",
- version);
-}
-
-static void
-version_info ()
-{
- immediate_quit++;
- print_gdb_version ();
- immediate_quit--;
-}
-
-
-/* Command to specify a prompt string instead of "(gdb) ". */
-
-void
-set_prompt_command (text)
- char *text;
-{
- char *p, *q;
- register int c;
- char *new;
-
- if (text == 0)
- error_no_arg ("string to which to set prompt");
-
- new = (char *) xmalloc (strlen (text) + 2);
- p = text; q = new;
- while (c = *p++)
- {
- if (c == '\\')
- {
- /* \ at end of argument is used after spaces
- so they won't be lost. */
- if (*p == 0)
- break;
- c = parse_escape (&p);
- if (c == 0)
- break; /* C loses */
- else if (c > 0)
- *q++ = c;
- }
- else
- *q++ = c;
- }
- if (*(p - 1) != '\\')
- *q++ = ' ';
- *q++ = '\0';
- new = (char *) xrealloc (new, q - new);
- free (prompt);
- prompt = new;
-}
-
-static void
-quit_command ()
-{
- extern void exec_file_command ();
- if (have_inferior_p ())
- {
- if (inhibit_confirm || query ("The program is running. Quit anyway? "))
- {
- /* Prevent any warning message from reopen_exec_file, in case
- we have a core file that's inconsistent with the exec file. */
- exec_file_command (0, 0);
- kill_inferior ();
- }
- else
- error ("Not confirmed.");
- }
- /* Save the history information if it is appropriate to do so. */
- if (write_history_p && history_filename)
- write_history (history_filename);
- exit (0);
-}
-
-int
-input_from_terminal_p ()
-{
- return instream == stdin;
-}
-
-static void
-pwd_command (arg, from_tty)
- char *arg;
- int from_tty;
-{
- if (arg) error ("The \"pwd\" command does not take an argument: %s", arg);
- getwd (dirbuf);
-
- if (strcmp (dirbuf, current_directory))
- printf ("Working directory %s\n (canonically %s).\n",
- current_directory, dirbuf);
- else
- printf ("Working directory %s.\n", current_directory);
-}
-
-static void
-cd_command (dir, from_tty)
- char *dir;
- int from_tty;
-{
- int len;
- int change;
-
- if (dir == 0)
- error_no_arg ("new working directory");
-
- dir = tilde_expand (dir);
- make_cleanup (free, dir);
-
- len = strlen (dir);
- dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
- if (dir[0] == '/')
- current_directory = dir;
- else
- {
- current_directory = concat (current_directory, "/", dir);
- free (dir);
- }
-
- /* Now simplify any occurrences of `.' and `..' in the pathname. */
-
- change = 1;
- while (change)
- {
- char *p;
- change = 0;
-
- for (p = current_directory; *p;)
- {
- if (!strncmp (p, "/./", 2)
- && (p[2] == 0 || p[2] == '/'))
- strcpy (p, p + 2);
- else if (!strncmp (p, "/..", 3)
- && (p[3] == 0 || p[3] == '/')
- && p != current_directory)
- {
- char *q = p;
- while (q != current_directory && q[-1] != '/') q--;
- if (q != current_directory)
- {
- strcpy (q-1, p+3);
- p = q-1;
- }
- }
- else p++;
- }
- }
-
- if (chdir (dir) < 0)
- perror_with_name (dir);
-
- if (from_tty)
- pwd_command ((char *) 0, 1);
-}
-
-static void
-source_command (arg, from_tty)
- char *arg;
- int from_tty;
-{
- FILE *stream;
- struct cleanup *cleanups;
- char *file = arg;
- char *path;
-
- if (file == 0)
- /* Let source without arguments read .gdbinit. */
- file = ".gdbinit";
-
- file = tilde_expand (file);
- make_cleanup (free, file);
-
-#ifdef KERNELDEBUG
- if (path = getenv(kernel_debugging? "KGDBPATH" : "GDBPATH"))
-#else
- if (path = getenv("GDBPATH"))
-#endif
- {
- int fd = openp(path, 1, file, O_RDONLY, 0, 0);
-
- if (fd == -1)
- stream = 0;
- else
- stream = fdopen(fd, "r");
- }
- else
- stream = fopen (file, "r");
-
- if (stream == 0)
- perror_with_name (file);
-
- cleanups = make_cleanup (source_cleanup, instream);
-
- instream = stream;
-
- command_loop ();
-
- do_cleanups (cleanups);
-}
-
-static void
-echo_command (text)
- char *text;
-{
- char *p = text;
- register int c;
-
- if (text)
- while (c = *p++)
- {
- if (c == '\\')
- {
- /* \ at end of argument is used after spaces
- so they won't be lost. */
- if (*p == 0)
- return;
-
- c = parse_escape (&p);
- if (c >= 0)
- fputc (c, stdout);
- }
- else
- fputc (c, stdout);
- }
- fflush(stdout);
-}
-
-static void
-dump_me_command ()
-{
- if (query ("Should GDB dump core? "))
- {
- signal (SIGQUIT, SIG_DFL);
- kill (getpid (), SIGQUIT);
- }
-}
-
-int
-parse_binary_operation (caller, arg)
- char *caller, *arg;
-{
- int length;
-
- if (!arg || !*arg)
- return 1;
-
- length = strlen (arg);
-
- while (arg[length - 1] == ' ' || arg[length - 1] == '\t')
- length--;
-
- if (!strncmp (arg, "on", length)
- || !strncmp (arg, "1", length)
- || !strncmp (arg, "yes", length))
- return 1;
- else
- if (!strncmp (arg, "off", length)
- || !strncmp (arg, "0", length)
- || !strncmp (arg, "no", length))
- return 0;
- else
- error ("\"%s\" not given a binary valued argument.", caller);
-}
-
-/* Functions to manipulate command line editing control variables. */
-
-static void
-set_editing (arg, from_tty)
- char *arg;
- int from_tty;
-{
- command_editing_p = parse_binary_operation ("set command-editing", arg);
-}
-
-/* Number of commands to print in each call to editing_info. */
-#define Hist_print 10
-static void
-editing_info (arg, from_tty)
- char *arg;
- int from_tty;
-{
- /* Index for history commands. Relative to history_base. */
- int offset;
-
- /* Number of the history entry which we are planning to display next.
- Relative to history_base. */
- static int num = 0;
-
- /* The first command in the history which doesn't exist (i.e. one more
- than the number of the last command). Relative to history_base. */
- int hist_len;
-
- struct _hist_entry {
- char *line;
- char *data;
- } *history_get();
- extern int history_base;
-
- printf_filtered ("Interactive command editing is %s.\n",
- command_editing_p ? "on" : "off");
-
- printf_filtered ("History expansion of command input is %s.\n",
- history_expansion_p ? "on" : "off");
- printf_filtered ("Writing of a history record upon exit is %s.\n",
- write_history_p ? "enabled" : "disabled");
- printf_filtered ("The size of the history list (number of stored commands) is %d.\n",
- history_size);
- printf_filtered ("The name of the history record is \"%s\".\n\n",
- history_filename ? history_filename : "");
-
- /* Print out some of the commands from the command history. */
- /* First determine the length of the history list. */
- hist_len = history_size;
- for (offset = 0; offset < history_size; offset++)
- {
- if (!history_get (history_base + offset))
- {
- hist_len = offset;
- break;
- }
- }
-
- if (arg)
- {
- if (arg[0] == '+' && arg[1] == '\0')
- /* "info editing +" should print from the stored position. */
- ;
- else
- /* "info editing <exp>" should print around command number <exp>. */
- num = (parse_and_eval_address (arg) - history_base) - Hist_print / 2;
- }
- /* "info editing" means print the last Hist_print commands. */
- else
- {
- num = hist_len - Hist_print;
- }
-
- if (num < 0)
- num = 0;
-
- /* If there are at least Hist_print commands, we want to display the last
- Hist_print rather than, say, the last 6. */
- if (hist_len - num < Hist_print)
- {
- num = hist_len - Hist_print;
- if (num < 0)
- num = 0;
- }
-
- if (num == hist_len - Hist_print)
- printf_filtered ("The list of the last %d commands is:\n\n", Hist_print);
- else
- printf_filtered ("Some of the stored commands are:\n\n");
-
- for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
- {
- printf_filtered ("%5d %s\n", history_base + offset,
- (history_get (history_base + offset))->line);
- }
-
- /* The next command we want to display is the next one that we haven't
- displayed yet. */
- num += Hist_print;
-
- /* If the user repeats this command with return, it should do what
- "info editing +" does. This is unnecessary if arg is null,
- because "info editing +" is not useful after "info editing". */
- if (from_tty && arg)
- {
- arg[0] = '+';
- arg[1] = '\0';
- }
-}
-
-static void
-set_history_expansion (arg, from_tty)
- char *arg;
- int from_tty;
-{
- history_expansion_p = parse_binary_operation ("set history expansion", arg);
-}
-
-static void
-set_history_write (arg, from_tty)
- char *arg;
- int from_tty;
-{
- write_history_p = parse_binary_operation ("set history write", arg);
-}
-
-static void
-set_history (arg, from_tty)
- char *arg;
- int from_tty;
-{
- printf ("\"set history\" must be followed by the name of a history subcommand.\n");
- help_list (sethistlist, "set history ", -1, stdout);
-}
-
-static void
-set_history_size (arg, from_tty)
- char *arg;
- int from_tty;
-{
- if (!*arg)
- error_no_arg ("set history size");
-
- history_size = atoi (arg);
-}
-
-static void
-set_history_filename (arg, from_tty)
- char *arg;
- int from_tty;
-{
- int i;
-
- if (!arg)
- error_no_arg ("history file name");
-
- arg = tilde_expand (arg);
- make_cleanup (free, arg);
-
- i = strlen (arg) - 1;
-
- free (history_filename);
-
- while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
- i--;
- ++i;
-
- if (!*arg)
- history_filename = (char *) 0;
- else
- history_filename = savestring (arg, i + 1);
- history_filename[i] = '\0';
-}
-
-int info_verbose;
-
-static void
-set_verbose_command (arg, from_tty)
- char *arg;
- int from_tty;
-{
- info_verbose = parse_binary_operation ("set verbose", arg);
-}
-
-static void
-verbose_info (arg, from_tty)
- char *arg;
- int from_tty;
-{
- if (arg)
- error ("\"info verbose\" does not take any arguments.\n");
-
- printf ("Verbose printing of information is %s.\n",
- info_verbose ? "on" : "off");
-}
-
-static void
-float_handler ()
-{
- error ("Invalid floating value encountered or computed.");
-}
-
-
-static void
-initialize_cmd_lists ()
-{
- cmdlist = (struct cmd_list_element *) 0;
- infolist = (struct cmd_list_element *) 0;
- enablelist = (struct cmd_list_element *) 0;
- disablelist = (struct cmd_list_element *) 0;
- deletelist = (struct cmd_list_element *) 0;
- enablebreaklist = (struct cmd_list_element *) 0;
- setlist = (struct cmd_list_element *) 0;
- sethistlist = (struct cmd_list_element *) 0;
- unsethistlist = (struct cmd_list_element *) 0;
-}
-
-static void
-initialize_main ()
-{
- char *tmpenv;
- /* Command line editing externals. */
- extern int (*rl_completion_entry_function)();
- extern char *rl_completer_word_break_characters;
- extern char *rl_readline_name;
-
- /* Set default verbose mode on. */
- info_verbose = 1;
-
-#ifdef KERNELDEBUG
- if (kernel_debugging)
- prompt = savestring ("(kgdb) ", 7);
- else
-#endif
- prompt = savestring ("(gdb) ", 6);
-
- /* Set the important stuff up for command editing. */
- command_editing_p = 1;
- history_expansion_p = 0;
- write_history_p = 0;
-
- if (tmpenv = getenv ("HISTSIZE"))
- history_size = atoi (tmpenv);
- else
- history_size = 256;
-
- stifle_history (history_size);
-
- if (tmpenv = getenv ("GDBHISTFILE"))
- history_filename = savestring (tmpenv, strlen(tmpenv));
- else
- /* We include the current directory so that if the user changes
- directories the file written will be the same as the one
- that was read. */
- history_filename = concat (current_directory, "/.gdb_history", "");
-
- read_history (history_filename);
-
- /* Setup important stuff for command line editing. */
- rl_completion_entry_function = (int (*)()) symbol_completion_function;
- rl_completer_word_break_characters = gdb_completer_word_break_characters;
- rl_readline_name = "gdb";
-
- /* Define the classes of commands.
- They will appear in the help list in the reverse of this order. */
-
- add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist);
- add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist);
- add_cmd ("user", class_user, 0, "User-defined commands.\n\
-The commands in this class are those defined by the user.\n\
-Use the \"define\" command to define a command.", &cmdlist);
- add_cmd ("support", class_support, 0, "Support facilities.", &cmdlist);
- add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist);
- add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist);
- add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist);
- add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist);
- add_cmd ("stack", class_stack, 0, "Examining the stack.\n\
-The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
-counting from zero for the innermost (currently executing) frame.\n\n\
-At any time gdb identifies one frame as the \"selected\" frame.\n\
-Variable lookups are done with respect to the selected frame.\n\
-When the program being debugged stops, gdb selects the innermost frame.\n\
-The commands below can be used to select other frames by number or address.",
- &cmdlist);
- add_cmd ("running", class_run, 0, "Running the program.", &cmdlist);
-
- add_com ("pwd", class_files, pwd_command,
- "Print working directory. This is used for your program as well.");
- add_com ("cd", class_files, cd_command,
- "Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started.");
-
- add_cmd ("prompt", class_support, set_prompt_command,
- "Change gdb's prompt from the default of \"(gdb)\"",
- &setlist);
- add_com ("echo", class_support, echo_command,
- "Print a constant string. Give string as argument.\n\
-C escape sequences may be used in the argument.\n\
-No newline is added at the end of the argument;\n\
-use \"\\n\" if you want a newline to be printed.\n\
-Since leading and trailing whitespace are ignored in command arguments,\n\
-if you want to print some you must use \"\\\" before leading whitespace\n\
-to be printed or after trailing whitespace.");
- add_com ("document", class_support, document_command,
- "Document a user-defined command.\n\
-Give command name as argument. Give documentation on following lines.\n\
-End with a line of just \"end\".");
- add_com ("define", class_support, define_command,
- "Define a new command name. Command name is argument.\n\
-Definition appears on following lines, one command per line.\n\
-End with a line of just \"end\".\n\
-Use the \"document\" command to give documentation for the new command.\n\
-Commands defined in this way do not take arguments.");
-
- add_com ("source", class_support, source_command,
- "Read commands from a file named FILE.\n\
-Note that the file \".gdbinit\" is read automatically in this way\n\
-when gdb is started.");
- add_com ("quit", class_support, quit_command, "Exit gdb.");
- add_com ("help", class_support, help_command, "Print list of commands.");
- add_com_alias ("q", "quit", class_support, 1);
- add_com_alias ("h", "help", class_support, 1);
- add_com ("while", class_support, while_command,
- "execute following commands while condition is true.\n\
-Expression for condition follows \"while\" keyword.");
- add_com ("if", class_support, if_command,
- "execute following commands if condition is true.\n\
-Expression for condition follows \"if\" keyword.");
- add_cmd ("verbose", class_support, set_verbose_command,
- "Change the number of informational messages gdb prints.",
- &setlist);
- add_info ("verbose", verbose_info,
- "Status of gdb's verbose printing option.\n");
-
- add_com ("dump-me", class_obscure, dump_me_command,
- "Get fatal error; make debugger dump its core.");
-
- add_cmd ("editing", class_support, set_editing,
- "Enable or disable command line editing.\n\
-Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
-Without an argument, command line editing is enabled.", &setlist);
-
- add_prefix_cmd ("history", class_support, set_history,
- "Generic command for setting command history parameters.",
- &sethistlist, "set history ", 0, &setlist);
-
- add_cmd ("expansion", no_class, set_history_expansion,
- "Enable or disable history expansion on command input.\n\
-Without an argument, history expansion is enabled.", &sethistlist);
-
- add_cmd ("write", no_class, set_history_write,
- "Enable or disable saving of the history record on exit.\n\
-Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
-Without an argument, saving is enabled.", &sethistlist);
-
- add_cmd ("size", no_class, set_history_size,
- "Set the size of the command history, \n\
-ie. the number of previous commands to keep a record of.", &sethistlist);
-
- add_cmd ("filename", no_class, set_history_filename,
- "Set the filename in which to record the command history\n\
- (the list of previous commands of which a record is kept).", &sethistlist);
-
- add_prefix_cmd ("info", class_info, info_command,
- "Generic command for printing status.",
- &infolist, "info ", 0, &cmdlist);
- add_com_alias ("i", "info", class_info, 1);
-
- add_info ("editing", editing_info, "Status of command editor.");
-
- add_info ("version", version_info, "Report what version of GDB this is.");
-}
diff --git a/gnu/usr.bin/gdb/mmalloc/Makefile b/gnu/usr.bin/gdb/mmalloc/Makefile
new file mode 100644
index 000000000000..1ef0d1dd0e37
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/Makefile
@@ -0,0 +1,10 @@
+LIB= mmalloc
+SRCS= mcalloc.c mfree.c mmalloc.c mmcheck.c mmemalign.c mmstats.c \
+ mmtrace.c mrealloc.c mvalloc.c mmap-sup.c attach.c detach.c keys.c \
+ sbrk-sup.c
+
+NOPROFILE=no
+NOPIC=no
+install:
+ @echo -n
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/mmalloc/README.FreeBSD b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD
new file mode 100644
index 000000000000..338400ffa885
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libmmalloc directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libmmalloc will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/mmalloc/attach.c b/gnu/usr.bin/gdb/mmalloc/attach.c
new file mode 100644
index 000000000000..6737fca38723
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/attach.c
@@ -0,0 +1,218 @@
+/* Initialization for access to a mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <fcntl.h> /* After sys/types.h, at least for dpx/2. */
+#include <sys/stat.h>
+#include <string.h>
+#include "mmalloc.h"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+
+#if defined(HAVE_MMAP)
+
+/* Forward declarations/prototypes for local functions */
+
+static struct mdesc *reuse PARAMS ((int));
+
+/* Initialize access to a mmalloc managed region.
+
+ If FD is a valid file descriptor for an open file then data for the
+ mmalloc managed region is mapped to that file, otherwise "/dev/zero"
+ is used and the data will not exist in any filesystem object.
+
+ If the open file corresponding to FD is from a previous use of
+ mmalloc and passes some basic sanity checks to ensure that it is
+ compatible with the current mmalloc package, then it's data is
+ mapped in and is immediately accessible at the same addresses in
+ the current process as the process that created the file.
+
+ If BASEADDR is not NULL, the mapping is established starting at the
+ specified address in the process address space. If BASEADDR is NULL,
+ the mmalloc package chooses a suitable address at which to start the
+ mapped region, which will be the value of the previous mapping if
+ opening an existing file which was previously built by mmalloc, or
+ for new files will be a value chosen by mmap.
+
+ Specifying BASEADDR provides more control over where the regions
+ start and how big they can be before bumping into existing mapped
+ regions or future mapped regions.
+
+ On success, returns a "malloc descriptor" which is used in subsequent
+ calls to other mmalloc package functions. It is explicitly "void *"
+ ("char *" for systems that don't fully support void) so that users
+ of the package don't have to worry about the actual implementation
+ details.
+
+ On failure returns NULL. */
+
+PTR
+mmalloc_attach (fd, baseaddr)
+ int fd;
+ PTR baseaddr;
+{
+ struct mdesc mtemp;
+ struct mdesc *mdp;
+ PTR mbase;
+ struct stat sbuf;
+
+ /* First check to see if FD is a valid file descriptor, and if so, see
+ if the file has any current contents (size > 0). If it does, then
+ attempt to reuse the file. If we can't reuse the file, either
+ because it isn't a valid mmalloc produced file, was produced by an
+ obsolete version, or any other reason, then we fail to attach to
+ this file. */
+
+ if (fd >= 0)
+ {
+ if (fstat (fd, &sbuf) < 0)
+ {
+ return (NULL);
+ }
+ else if (sbuf.st_size > 0)
+ {
+ return ((PTR) reuse (fd));
+ }
+ }
+
+ /* We start off with the malloc descriptor allocated on the stack, until
+ we build it up enough to call _mmalloc_mmap_morecore() to allocate the
+ first page of the region and copy it there. Ensure that it is zero'd and
+ then initialize the fields that we know values for. */
+
+ mdp = &mtemp;
+ memset ((char *) mdp, 0, sizeof (mtemp));
+ strncpy (mdp -> magic, MMALLOC_MAGIC, MMALLOC_MAGIC_SIZE);
+ mdp -> headersize = sizeof (mtemp);
+ mdp -> version = MMALLOC_VERSION;
+ mdp -> morecore = __mmalloc_mmap_morecore;
+ mdp -> fd = fd;
+ mdp -> base = mdp -> breakval = mdp -> top = baseaddr;
+
+ /* If we have not been passed a valid open file descriptor for the file
+ to map to, then open /dev/zero and use that to map to. */
+
+ if (mdp -> fd < 0)
+ {
+ if ((mdp -> fd = open ("/dev/zero", O_RDWR)) < 0)
+ {
+ return (NULL);
+ }
+ else
+ {
+ mdp -> flags |= MMALLOC_DEVZERO;
+ }
+ }
+
+ /* Now try to map in the first page, copy the malloc descriptor structure
+ there, and arrange to return a pointer to this new copy. If the mapping
+ fails, then close the file descriptor if it was opened by us, and arrange
+ to return a NULL. */
+
+ if ((mbase = mdp -> morecore (mdp, sizeof (mtemp))) != NULL)
+ {
+ memcpy (mbase, mdp, sizeof (mtemp));
+ mdp = (struct mdesc *) mbase;
+ }
+ else
+ {
+ if (mdp -> flags & MMALLOC_DEVZERO)
+ {
+ close (mdp -> fd);
+ }
+ mdp = NULL;
+ }
+
+ return ((PTR) mdp);
+}
+
+/* Given an valid file descriptor on an open file, test to see if that file
+ is a valid mmalloc produced file, and if so, attempt to remap it into the
+ current process at the same address to which it was previously mapped.
+
+ Note that we have to update the file descriptor number in the malloc-
+ descriptor read from the file to match the current valid one, before
+ trying to map the file in, and again after a successful mapping and
+ after we've switched over to using the mapped in malloc descriptor
+ rather than the temporary one on the stack.
+
+ Once we've switched over to using the mapped in malloc descriptor, we
+ have to update the pointer to the morecore function, since it almost
+ certainly will be at a different address if the process reusing the
+ mapped region is from a different executable.
+
+ Also note that if the heap being remapped previously used the mmcheck()
+ routines, we need to update the hooks since their target functions
+ will have certainly moved if the executable has changed in any way.
+ We do this by calling mmcheck() internally.
+
+ Returns a pointer to the malloc descriptor if successful, or NULL if
+ unsuccessful for some reason. */
+
+static struct mdesc *
+reuse (fd)
+ int fd;
+{
+ struct mdesc mtemp;
+ struct mdesc *mdp = NULL;
+
+ if ((lseek (fd, 0L, SEEK_SET) == 0) &&
+ (read (fd, (char *) &mtemp, sizeof (mtemp)) == sizeof (mtemp)) &&
+ (mtemp.headersize == sizeof (mtemp)) &&
+ (strcmp (mtemp.magic, MMALLOC_MAGIC) == 0) &&
+ (mtemp.version <= MMALLOC_VERSION))
+ {
+ mtemp.fd = fd;
+ if (__mmalloc_remap_core (&mtemp) == mtemp.base)
+ {
+ mdp = (struct mdesc *) mtemp.base;
+ mdp -> fd = fd;
+ mdp -> morecore = __mmalloc_mmap_morecore;
+ if (mdp -> mfree_hook != NULL)
+ {
+ mmcheck ((PTR) mdp, (void (*) PARAMS ((void))) NULL);
+ }
+ }
+ }
+ return (mdp);
+}
+
+#else /* !defined (HAVE_MMAP) */
+
+/* For systems without mmap, the library still supplies an entry point
+ to link to, but trying to initialize access to an mmap'd managed region
+ always fails. */
+
+/* ARGSUSED */
+PTR
+mmalloc_attach (fd, baseaddr)
+ int fd;
+ PTR baseaddr;
+{
+ return (NULL);
+}
+
+#endif /* defined (HAVE_MMAP) */
+
diff --git a/gnu/usr.bin/gdb/mmalloc/detach.c b/gnu/usr.bin/gdb/mmalloc/detach.c
new file mode 100644
index 000000000000..03d632c20609
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/detach.c
@@ -0,0 +1,71 @@
+/* Finish access to a mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <fcntl.h> /* After sys/types.h, at least for dpx/2. */
+#include "mmalloc.h"
+
+/* Terminate access to a mmalloc managed region by unmapping all memory pages
+ associated with the region, and closing the file descriptor if it is one
+ that we opened.
+
+ Returns NULL on success.
+
+ Returns the malloc descriptor on failure, which can subsequently be used
+ for further action, such as obtaining more information about the nature of
+ the failure by examining the preserved errno value.
+
+ Note that the malloc descriptor that we are using is currently located in
+ region we are about to unmap, so we first make a local copy of it on the
+ stack and use the copy. */
+
+PTR
+mmalloc_detach (md)
+ PTR md;
+{
+ struct mdesc mtemp;
+
+ if (md != NULL)
+ {
+
+ mtemp = *(struct mdesc *) md;
+
+ /* Now unmap all the pages associated with this region by asking for a
+ negative increment equal to the current size of the region. */
+
+ if ((mtemp.morecore (&mtemp, mtemp.base - mtemp.top)) == NULL)
+ {
+ /* Update the original malloc descriptor with any changes */
+ *(struct mdesc *) md = mtemp;
+ }
+ else
+ {
+ if (mtemp.flags & MMALLOC_DEVZERO)
+ {
+ close (mtemp.fd);
+ }
+ md = NULL;
+ }
+ }
+
+ return (md);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/keys.c b/gnu/usr.bin/gdb/mmalloc/keys.c
new file mode 100644
index 000000000000..69d41b977395
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/keys.c
@@ -0,0 +1,66 @@
+/* Access for application keys in mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This module provides access to some keys that the application can use to
+ provide persistent access to locations in the mapped memory section.
+ The intent is that these keys are to be used sparingly as sort of
+ persistent global variables which the application can use to reinitialize
+ access to data in the mapped region.
+
+ For the moment, these keys are simply stored in the malloc descriptor
+ itself, in an array of fixed length. This should be fixed so that there
+ can be an unlimited number of keys, possibly using a multilevel access
+ scheme of some sort. */
+
+#include "mmalloc.h"
+
+int
+mmalloc_setkey (md, keynum, key)
+ PTR md;
+ int keynum;
+ PTR key;
+{
+ struct mdesc *mdp = (struct mdesc *) md;
+ int result = 0;
+
+ if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS))
+ {
+ mdp -> keys [keynum] = key;
+ result++;
+ }
+ return (result);
+}
+
+PTR
+mmalloc_getkey (md, keynum)
+ PTR md;
+ int keynum;
+{
+ struct mdesc *mdp = (struct mdesc *) md;
+ PTR keyval = NULL;
+
+ if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS))
+ {
+ keyval = mdp -> keys [keynum];
+ }
+ return (keyval);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mcalloc.c b/gnu/usr.bin/gdb/mmalloc/mcalloc.c
new file mode 100644
index 000000000000..08f07bfe1c79
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mcalloc.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+ The entire array is initialized to zeros. */
+
+PTR
+mcalloc (md, nmemb, size)
+ PTR md;
+ register size_t nmemb;
+ register size_t size;
+{
+ register PTR result;
+
+ if ((result = mmalloc (md, nmemb * size)) != NULL)
+ {
+ memset (result, 0, nmemb * size);
+ }
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+calloc (nmemb, size)
+ size_t nmemb;
+ size_t size;
+{
+ return (mcalloc ((PTR) NULL, nmemb, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mfree.c b/gnu/usr.bin/gdb/mmalloc/mfree.c
new file mode 100644
index 000000000000..aee43aad15bf
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mfree.c
@@ -0,0 +1,247 @@
+/* Free a block of memory allocated by `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* Return memory to the heap.
+ Like `mfree' but don't call a mfree_hook if there is one. */
+
+void
+__mmalloc_free (mdp, ptr)
+ struct mdesc *mdp;
+ PTR ptr;
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ block = BLOCK (ptr);
+
+ type = mdp -> heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -=
+ mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+ mdp -> heapstats.bytes_free +=
+ mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = mdp -> heapindex;
+ if (i > block)
+ {
+ while (i > block)
+ {
+ i = mdp -> heapinfo[i].free.prev;
+ }
+ }
+ else
+ {
+ do
+ {
+ i = mdp -> heapinfo[i].free.next;
+ }
+ while ((i != 0) && (i < block));
+ i = mdp -> heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + mdp -> heapinfo[i].free.size)
+ {
+ /* Coalesce this block with its predecessor. */
+ mdp -> heapinfo[i].free.size +=
+ mdp -> heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else
+ {
+ /* Really link this block back into the free list. */
+ mdp -> heapinfo[block].free.size =
+ mdp -> heapinfo[block].busy.info.size;
+ mdp -> heapinfo[block].free.next = mdp -> heapinfo[i].free.next;
+ mdp -> heapinfo[block].free.prev = i;
+ mdp -> heapinfo[i].free.next = block;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+ mdp -> heapstats.chunks_free++;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + mdp -> heapinfo[block].free.size ==
+ mdp -> heapinfo[block].free.next)
+ {
+ mdp -> heapinfo[block].free.size
+ += mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.size;
+ mdp -> heapinfo[block].free.next
+ = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.next;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+ mdp -> heapstats.chunks_free--;
+ }
+
+ /* Now see if we can return stuff to the system. */
+ blocks = mdp -> heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
+ && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ mdp -> heaplimit -= blocks;
+ mdp -> morecore (mdp, -bytes);
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapinfo[block].free.next;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ block = mdp -> heapinfo[block].free.prev;
+ mdp -> heapstats.chunks_free--;
+ mdp -> heapstats.bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ mdp -> heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -= 1 << type;
+ mdp -> heapstats.chunks_free++;
+ mdp -> heapstats.bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *)
+ ((char *) ADDRESS(block) +
+ (mdp -> heapinfo[block].busy.info.frag.first << type));
+
+ if (mdp -> heapinfo[block].busy.info.frag.nfree ==
+ (BLOCKSIZE >> type) - 1)
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+ next = prev;
+ for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+ {
+ next = next -> next;
+ }
+ prev -> prev -> next = next;
+ if (next != NULL)
+ {
+ next -> prev = prev -> prev;
+ }
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += BLOCKSIZE;
+ mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
+ mdp -> heapstats.bytes_free -= BLOCKSIZE;
+
+ mfree ((PTR) mdp, (PTR) ADDRESS(block));
+ }
+ else if (mdp -> heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next -> next = prev -> next;
+ next -> prev = prev;
+ prev -> next = next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next;
+ }
+ ++mdp -> heapinfo[block].busy.info.frag.nfree;
+ }
+ else
+ {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ mdp -> heapinfo[block].busy.info.frag.nfree = 1;
+ mdp -> heapinfo[block].busy.info.frag.first =
+ RESIDUAL (ptr, BLOCKSIZE) >> type;
+ prev -> next = mdp -> fraghead[type].next;
+ prev -> prev = &mdp -> fraghead[type];
+ prev -> prev -> next = prev;
+ if (prev -> next != NULL)
+ {
+ prev -> next -> prev = prev;
+ }
+ }
+ break;
+ }
+}
+
+/* Return memory to the heap. */
+
+void
+mfree (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct mdesc *mdp;
+ register struct alignlist *l;
+
+ if (ptr != NULL)
+ {
+ mdp = MD_TO_MDP (md);
+ for (l = mdp -> aligned_blocks; l != NULL; l = l -> next)
+ {
+ if (l -> aligned == ptr)
+ {
+ l -> aligned = NULL; /* Mark the slot in the list as free. */
+ ptr = l -> exact;
+ break;
+ }
+ }
+ if (mdp -> mfree_hook != NULL)
+ {
+ (*mdp -> mfree_hook) (md, ptr);
+ }
+ else
+ {
+ __mmalloc_free (mdp, ptr);
+ }
+ }
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+void
+free (ptr)
+ PTR ptr;
+{
+ mfree ((PTR) NULL, ptr);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.c b/gnu/usr.bin/gdb/mmalloc/mmalloc.c
new file mode 100644
index 000000000000..46b450e8513d
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.c
@@ -0,0 +1,334 @@
+/* Memory allocator `malloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish for mmap'd version.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Prototypes for local functions */
+
+static int initialize PARAMS ((struct mdesc *));
+static PTR morecore PARAMS ((struct mdesc *, size_t));
+static PTR align PARAMS ((struct mdesc *, size_t));
+
+/* Aligned allocation. */
+
+static PTR
+align (mdp, size)
+ struct mdesc *mdp;
+ size_t size;
+{
+ PTR result;
+ unsigned long int adj;
+
+ result = mdp -> morecore (mdp, size);
+ adj = RESIDUAL (result, BLOCKSIZE);
+ if (adj != 0)
+ {
+ adj = BLOCKSIZE - adj;
+ mdp -> morecore (mdp, adj);
+ result = (char *) result + adj;
+ }
+ return (result);
+}
+
+/* Set everything up and remember that we have. */
+
+static int
+initialize (mdp)
+ struct mdesc *mdp;
+{
+ mdp -> heapsize = HEAP / BLOCKSIZE;
+ mdp -> heapinfo = (malloc_info *)
+ align (mdp, mdp -> heapsize * sizeof (malloc_info));
+ if (mdp -> heapinfo == NULL)
+ {
+ return (0);
+ }
+ memset ((PTR)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (malloc_info));
+ mdp -> heapinfo[0].free.size = 0;
+ mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0;
+ mdp -> heapindex = 0;
+ mdp -> heapbase = (char *) mdp -> heapinfo;
+ mdp -> flags |= MMALLOC_INITIALIZED;
+ return (1);
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+
+static PTR
+morecore (mdp, size)
+ struct mdesc *mdp;
+ size_t size;
+{
+ PTR result;
+ malloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ result = align (mdp, size);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Check if we need to grow the info table. */
+ if ((size_t) BLOCK ((char *) result + size) > mdp -> heapsize)
+ {
+ newsize = mdp -> heapsize;
+ while ((size_t) BLOCK ((char *) result + size) > newsize)
+ {
+ newsize *= 2;
+ }
+ newinfo = (malloc_info *) align (mdp, newsize * sizeof (malloc_info));
+ if (newinfo == NULL)
+ {
+ mdp -> morecore (mdp, -size);
+ return (NULL);
+ }
+ memset ((PTR) newinfo, 0, newsize * sizeof (malloc_info));
+ memcpy ((PTR) newinfo, (PTR) mdp -> heapinfo,
+ mdp -> heapsize * sizeof (malloc_info));
+ oldinfo = mdp -> heapinfo;
+ newinfo[BLOCK (oldinfo)].busy.type = 0;
+ newinfo[BLOCK (oldinfo)].busy.info.size
+ = BLOCKIFY (mdp -> heapsize * sizeof (malloc_info));
+ mdp -> heapinfo = newinfo;
+ __mmalloc_free (mdp, (PTR)oldinfo);
+ mdp -> heapsize = newsize;
+ }
+
+ mdp -> heaplimit = BLOCK ((char *) result + size);
+ return (result);
+}
+
+/* Allocate memory from the heap. */
+
+PTR
+mmalloc (md, size)
+ PTR md;
+ size_t size;
+{
+ struct mdesc *mdp;
+ PTR result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+ register size_t log;
+
+ if (size == 0)
+ {
+ return (NULL);
+ }
+
+ mdp = MD_TO_MDP (md);
+
+ if (mdp -> mmalloc_hook != NULL)
+ {
+ return ((*mdp -> mmalloc_hook) (md, size));
+ }
+
+ if (!(mdp -> flags & MMALLOC_INITIALIZED))
+ {
+ if (!initialize (mdp))
+ {
+ return (NULL);
+ }
+ }
+
+ if (size < sizeof (struct list))
+ {
+ size = sizeof (struct list);
+ }
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ {
+ ++log;
+ }
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = mdp -> fraghead[log].next;
+ if (next != NULL)
+ {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (PTR) next;
+ next -> prev -> next = next -> next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next -> prev;
+ }
+ block = BLOCK (result);
+ if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ mdp -> heapinfo[block].busy.info.frag.first =
+ RESIDUAL (next -> next, BLOCKSIZE) >> log;
+ }
+
+ /* Update the statistics. */
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += 1 << log;
+ mdp -> heapstats.chunks_free--;
+ mdp -> heapstats.bytes_free -= 1 << log;
+ }
+ else
+ {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = mmalloc (md, BLOCKSIZE);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+ {
+ next = (struct list *) ((char *) result + (i << log));
+ next -> next = mdp -> fraghead[log].next;
+ next -> prev = &mdp -> fraghead[log];
+ next -> prev -> next = next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next;
+ }
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK (result);
+ mdp -> heapinfo[block].busy.type = log;
+ mdp -> heapinfo[block].busy.info.frag.nfree = i - 1;
+ mdp -> heapinfo[block].busy.info.frag.first = i - 1;
+
+ mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
+ mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
+ mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
+ }
+ }
+ else
+ {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY(size);
+ start = block = MALLOC_SEARCH_START;
+ while (mdp -> heapinfo[block].free.size < blocks)
+ {
+ block = mdp -> heapinfo[block].free.next;
+ if (block == start)
+ {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = mdp -> heapinfo[0].free.prev;
+ lastblocks = mdp -> heapinfo[block].free.size;
+ if (mdp -> heaplimit != 0 &&
+ block + lastblocks == mdp -> heaplimit &&
+ mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) &&
+ (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL)
+ {
+ /* Which block we are extending (the `final free
+ block' referred to above) might have changed, if
+ it got combined with a freed info table. */
+ block = mdp -> heapinfo[0].free.prev;
+
+ mdp -> heapinfo[block].free.size += (blocks - lastblocks);
+ mdp -> heapstats.bytes_free +=
+ (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore(mdp, blocks * BLOCKSIZE);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+ block = BLOCK (result);
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
+ return (result);
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS(block);
+ if (mdp -> heapinfo[block].free.size > blocks)
+ {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ mdp -> heapinfo[block + blocks].free.size
+ = mdp -> heapinfo[block].free.size - blocks;
+ mdp -> heapinfo[block + blocks].free.next
+ = mdp -> heapinfo[block].free.next;
+ mdp -> heapinfo[block + blocks].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapindex = block + blocks;
+ }
+ else
+ {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapindex = mdp -> heapinfo[block].free.next;
+ mdp -> heapstats.chunks_free--;
+ }
+
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
+ mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+malloc (size)
+ size_t size;
+{
+ return (mmalloc ((PTR) NULL, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.h b/gnu/usr.bin/gdb/mmalloc/mmalloc.h
new file mode 100644
index 000000000000..54b6ed654dcd
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.h
@@ -0,0 +1,390 @@
+/* Declarations for `mmalloc' and friends.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+
+#ifndef __MMALLOC_H
+#define __MMALLOC_H 1
+
+#ifdef __STDC__
+# include <stddef.h>
+# define PTR void *
+# define CONST const
+# define PARAMS(paramlist) paramlist
+# include <limits.h>
+# ifndef NULL
+# define NULL (void *) 0
+# endif
+#else
+# define PTR char *
+# define CONST /* nothing */
+# define PARAMS(paramlist) ()
+# ifndef size_t
+# define size_t unsigned int
+# endif
+# ifndef CHAR_BIT
+# define CHAR_BIT 8
+# endif
+# ifndef NULL
+# define NULL 0
+# endif
+#endif
+
+#ifndef MIN
+# define MIN(A, B) ((A) < (B) ? (A) : (B))
+#endif
+
+#define MMALLOC_MAGIC "mmalloc" /* Mapped file magic number */
+#define MMALLOC_MAGIC_SIZE 8 /* Size of magic number buf */
+#define MMALLOC_VERSION 1 /* Current mmalloc version */
+#define MMALLOC_KEYS 16 /* Keys for application use */
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE ((unsigned int) 1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* The difference between two pointers is a signed int. On machines where
+ the data addresses have the high bit set, we need to ensure that the
+ difference becomes an unsigned int when we are using the address as an
+ integral value. In addition, when using with the '%' operator, the
+ sign of the result is machine dependent for negative values, so force
+ it to be treated as an unsigned int. */
+
+#define ADDR2UINT(addr) ((unsigned int) ((char *) (addr) - (char *) NULL))
+#define RESIDUAL(addr,bsize) ((unsigned int) (ADDR2UINT (addr) % (bsize)))
+
+/* Determine the amount of memory spanned by the initial heap table
+ (not an absolute limit). */
+
+#define HEAP (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+
+#define FINAL_FREE_BLOCKS 8
+
+/* Where to start searching the free list when looking for new memory.
+ The two possible values are 0 and heapindex. Starting at 0 seems
+ to reduce total memory usage, while starting at heapindex seems to
+ run faster. */
+
+#define MALLOC_SEARCH_START mdp -> heapindex
+
+/* Address to block number and vice versa. */
+
+#define BLOCK(A) (((char *) (A) - mdp -> heapbase) / BLOCKSIZE + 1)
+
+#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + mdp -> heapbase))
+
+/* Data structure giving per-block information. */
+
+typedef union
+ {
+ /* Heap information for a busy block. */
+ struct
+ {
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+ union
+ {
+ struct
+ {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+ /* Heap information for a free block (that may be the first of
+ a free cluster). */
+ struct
+ {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+ } malloc_info;
+
+/* List of blocks allocated with `mmemalign' (or `mvalloc'). */
+
+struct alignlist
+ {
+ struct alignlist *next;
+ PTR aligned; /* The address that mmemaligned returned. */
+ PTR exact; /* The address that malloc returned. */
+ };
+
+/* Doubly linked lists of free fragments. */
+
+struct list
+ {
+ struct list *next;
+ struct list *prev;
+ };
+
+/* Statistics available to the user.
+ FIXME: By design, the internals of the malloc package are no longer
+ exported to the user via an include file, so access to this data needs
+ to be via some other mechanism, such as mmstat_<something> where the
+ return value is the <something> the user is interested in. */
+
+struct mstats
+ {
+ size_t bytes_total; /* Total size of the heap. */
+ size_t chunks_used; /* Chunks allocated by the user. */
+ size_t bytes_used; /* Byte total of user-allocated chunks. */
+ size_t chunks_free; /* Chunks in the free list. */
+ size_t bytes_free; /* Byte total of chunks in the free list. */
+ };
+
+/* Internal structure that defines the format of the malloc-descriptor.
+ This gets written to the base address of the region that mmalloc is
+ managing, and thus also becomes the file header for the mapped file,
+ if such a file exists. */
+
+struct mdesc
+{
+ /* The "magic number" for an mmalloc file. */
+
+ char magic[MMALLOC_MAGIC_SIZE];
+
+ /* The size in bytes of this structure, used as a sanity check when reusing
+ a previously created mapped file. */
+
+ unsigned int headersize;
+
+ /* The version number of the mmalloc package that created this file. */
+
+ unsigned char version;
+
+ /* Some flag bits to keep track of various internal things. */
+
+ unsigned int flags;
+
+ /* If a system call made by the mmalloc package fails, the errno is
+ preserved for future examination. */
+
+ int saved_errno;
+
+ /* Pointer to the function that is used to get more core, or return core
+ to the system, for requests using this malloc descriptor. For memory
+ mapped regions, this is the mmap() based routine. There may also be
+ a single malloc descriptor that points to an sbrk() based routine
+ for systems without mmap() or for applications that call the mmalloc()
+ package with a NULL malloc descriptor.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*morecore) PARAMS ((struct mdesc *, int));
+
+ /* Pointer to the function that causes an abort when the memory checking
+ features are activated. By default this is set to abort(), but can
+ be set to another function by the application using mmalloc().
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ void (*abortfunc) PARAMS ((void));
+
+ /* Debugging hook for free.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ void (*mfree_hook) PARAMS ((PTR, PTR));
+
+ /* Debugging hook for `malloc'.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*mmalloc_hook) PARAMS ((PTR, size_t));
+
+ /* Debugging hook for realloc.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+ /* Number of info entries. */
+
+ size_t heapsize;
+
+ /* Pointer to first block of the heap (base of the first block). */
+
+ char *heapbase;
+
+ /* Current search index for the heap table. */
+ /* Search index in the info table. */
+
+ size_t heapindex;
+
+ /* Limit of valid info table indices. */
+
+ size_t heaplimit;
+
+ /* Block information table.
+ Allocated with malign/__mmalloc_free (not mmalloc/mfree). */
+ /* Table indexed by block number giving per-block information. */
+
+ malloc_info *heapinfo;
+
+ /* Instrumentation. */
+
+ struct mstats heapstats;
+
+ /* Free list headers for each fragment size. */
+ /* Free lists for each fragment size. */
+
+ struct list fraghead[BLOCKLOG];
+
+ /* List of blocks allocated by memalign. */
+
+ struct alignlist *aligned_blocks;
+
+ /* The base address of the memory region for this malloc heap. This
+ is the location where the bookkeeping data for mmap and for malloc
+ begins. */
+
+ char *base;
+
+ /* The current location in the memory region for this malloc heap which
+ represents the end of memory in use. */
+
+ char *breakval;
+
+ /* The end of the current memory region for this malloc heap. This is
+ the first location past the end of mapped memory. */
+
+ char *top;
+
+ /* Open file descriptor for the file to which this malloc heap is mapped.
+ This will always be a valid file descriptor, since /dev/zero is used
+ by default if no open file is supplied by the client. Also note that
+ it may change each time the region is mapped and unmapped. */
+
+ int fd;
+
+ /* An array of keys to data within the mapped region, for use by the
+ application. */
+
+ PTR keys[MMALLOC_KEYS];
+
+};
+
+/* Bits to look at in the malloc descriptor flags word */
+
+#define MMALLOC_DEVZERO (1 << 0) /* Have mapped to /dev/zero */
+#define MMALLOC_INITIALIZED (1 << 1) /* Initialized mmalloc */
+#define MMALLOC_MMCHECK_USED (1 << 2) /* mmcheck() called already */
+
+/* Allocate SIZE bytes of memory. */
+
+extern PTR mmalloc PARAMS ((PTR, size_t));
+
+/* Re-allocate the previously allocated block in PTR, making the new block
+ SIZE bytes long. */
+
+extern PTR mrealloc PARAMS ((PTR, PTR, size_t));
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+
+extern PTR mcalloc PARAMS ((PTR, size_t, size_t));
+
+/* Free a block allocated by `mmalloc', `mrealloc' or `mcalloc'. */
+
+extern void mfree PARAMS ((PTR, PTR));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */
+
+extern PTR mmemalign PARAMS ((PTR, size_t, size_t));
+
+/* Allocate SIZE bytes on a page boundary. */
+
+extern PTR mvalloc PARAMS ((PTR, size_t));
+
+/* Activate a standard collection of debugging hooks. */
+
+extern int mmcheck PARAMS ((PTR, void (*) (void)));
+
+/* Pick up the current statistics. (see FIXME elsewhere) */
+
+extern struct mstats mmstats PARAMS ((PTR));
+
+/* Internal version of `mfree' used in `morecore'. */
+
+extern void __mmalloc_free PARAMS ((struct mdesc *, PTR));
+
+/* Hooks for debugging versions. */
+
+extern void (*__mfree_hook) PARAMS ((PTR, PTR));
+extern PTR (*__mmalloc_hook) PARAMS ((PTR, size_t));
+extern PTR (*__mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+/* A default malloc descriptor for the single sbrk() managed region. */
+
+extern struct mdesc *__mmalloc_default_mdp;
+
+/* Initialize the first use of the default malloc descriptor, which uses
+ an sbrk() region. */
+
+extern struct mdesc *__mmalloc_sbrk_init PARAMS ((void));
+
+/* Grow or shrink a contiguous mapped region using mmap().
+ Works much like sbrk() */
+
+#if defined(HAVE_MMAP)
+
+extern PTR __mmalloc_mmap_morecore PARAMS ((struct mdesc *, int));
+
+#endif
+
+/* Remap a mmalloc region that was previously mapped. */
+
+extern PTR __mmalloc_remap_core PARAMS ((struct mdesc *));
+
+/* Macro to convert from a user supplied malloc descriptor to pointer to the
+ internal malloc descriptor. If the user supplied descriptor is NULL, then
+ use the default internal version, initializing it if necessary. Otherwise
+ just cast the user supplied version (which is void *) to the proper type
+ (struct mdesc *). */
+
+#define MD_TO_MDP(md) \
+ ((md) == NULL \
+ ? (__mmalloc_default_mdp == NULL \
+ ? __mmalloc_sbrk_init () \
+ : __mmalloc_default_mdp) \
+ : (struct mdesc *) (md))
+
+#endif /* __MMALLOC_H */
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.texi b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi
new file mode 100644
index 000000000000..f70ae68621ee
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi
@@ -0,0 +1,258 @@
+\input texinfo @c -*- Texinfo -*-
+@setfilename mmalloc.info
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Mmalloc: (mmalloc). The GNU mapped-malloc package.
+END-INFO-DIR-ENTRY
+@end format
+
+This file documents the GNU mmalloc (mapped-malloc) package, written by
+fnf@@cygnus.com, based on GNU malloc written by mike@@ai.mit.edu.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+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.
+
+@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 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.
+@end ifinfo
+@iftex
+@c @finalout
+@setchapternewpage odd
+@settitle MMALLOC, the GNU memory-mapped malloc package
+@titlepage
+@title mmalloc
+@subtitle The GNU memory-mapped malloc package
+@author Fred Fish
+@author Cygnus Support
+@author Mike Haertel
+@author Free Software Foundation
+@page
+
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.1 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill fnf\@cygnus.com\par
+\hfill {\it MMALLOC, the GNU memory-mapped malloc package}, \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 Free Software Foundation, Inc.
+
+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.
+@end titlepage
+@end iftex
+
+@ifinfo
+@node Top, Overview, (dir), (dir)
+@top mmalloc
+This file documents the GNU memory-mapped malloc package mmalloc.
+
+@menu
+* Overview:: Overall Description
+* Implementation:: Implementation
+
+ --- The Detailed Node Listing ---
+
+Implementation
+
+* Compatibility:: Backwards Compatibility
+* Functions:: Function Descriptions
+@end menu
+
+@end ifinfo
+
+@node Overview, Implementation, Top, Top
+@chapter Overall Description
+
+This is a heavily modified version of GNU @code{malloc}. It uses
+@code{mmap} as the basic mechanism for for obtaining memory from the
+system, rather than @code{sbrk}. This gives it several advantages over the
+more traditional malloc:
+
+@itemize @bullet
+@item
+Several different heaps can be used, each of them growing
+or shinking under control of @code{mmap}, with the @code{mmalloc} functions
+using a specific heap on a call by call basis.
+
+@item
+By using @code{mmap}, it is easy to create heaps which are intended to
+be persistent and exist as a filesystem object after the creating
+process has gone away.
+
+@item
+Because multiple heaps can be managed, data used for a
+specific purpose can be allocated into its own heap, making
+it easier to allow applications to ``dump'' and ``restore'' initialized
+malloc-managed memory regions. For example, the ``unexec'' hack popularized
+by GNU Emacs could potentially go away.
+@end itemize
+
+@node Implementation, , Overview, Top
+@chapter Implementation
+
+The @code{mmalloc} functions contain no internal static state. All
+@code{mmalloc} internal data is allocated in the mapped in region, along
+with the user data that it manages. This allows it to manage multiple
+such regions and to ``pick up where it left off'' when such regions are
+later dynamically mapped back in.
+
+In some sense, malloc has been ``purified'' to contain no internal state
+information and generalized to use multiple memory regions rather than a
+single region managed by @code{sbrk}. However the new routines now need an
+extra parameter which informs @code{mmalloc} which memory region it is dealing
+with (along with other information). This parameter is called the
+@dfn{malloc descriptor}.
+
+The functions initially provided by @code{mmalloc} are:
+
+@example
+void *mmalloc_attach (int fd, void *baseaddr);
+void *mmalloc_detach (void *md);
+int mmalloc_errno (void *md);
+int mmalloc_setkey (void *md, int keynum, void *key);
+void *mmalloc_getkey (void *md, int keynum);
+
+void *mmalloc (void *md, size_t size);
+void *mrealloc (void *md, void *ptr, size_t size);
+void *mvalloc (void *md, size_t size);
+void mfree (void *md, void *ptr);
+@end example
+
+@menu
+* Compatibility:: Backwards Compatibility
+* Functions:: Function Descriptions
+@end menu
+
+@node Compatibility, Functions, Implementation, Implementation
+@section Backwards Compatibility
+
+To allow a single malloc package to be used in a given application,
+provision is made for the traditional @code{malloc}, @code{realloc}, and
+@code{free} functions to be implemented as special cases of the
+@code{mmalloc} functions. In particular, if any of the functions that
+expect malloc descriptors are called with a @code{NULL} pointer rather than a
+valid malloc descriptor, then they default to using an @code{sbrk} managed
+region.
+The @code{mmalloc} package provides compatible @code{malloc}, @code{realloc},
+and @code{free} functions using this mechanism internally.
+Applications can avoid this extra interface layer by simply including the
+following defines:
+
+@example
+#define malloc(size) mmalloc ((void *)0, (size))
+#define realloc(ptr,size) mrealloc ((void *)0, (ptr), (size));
+#define free(ptr) mfree ((void *)0, (ptr))
+@end example
+
+@noindent
+or replace the existing @code{malloc}, @code{realloc}, and @code{free}
+calls with the above patterns if using @code{#define} causes problems.
+
+@node Functions, , Compatibility, Implementation
+@section Function Descriptions
+
+These are the details on the functions that make up the @code{mmalloc}
+package.
+
+@table @code
+@item void *mmalloc_attach (int @var{fd}, void *@var{baseaddr});
+Initialize access to a @code{mmalloc} managed region.
+
+If @var{fd} is a valid file descriptor for an open file, then data for the
+@code{mmalloc} managed region is mapped to that file. Otherwise
+@file{/dev/zero} is used and the data will not exist in any filesystem object.
+
+If the open file corresponding to @var{fd} is from a previous use of
+@code{mmalloc} and passes some basic sanity checks to ensure that it is
+compatible with the current @code{mmalloc} package, then its data is
+mapped in and is immediately accessible at the same addresses in
+the current process as the process that created the file.
+
+If @var{baseaddr} is not @code{NULL}, the mapping is established
+starting at the specified address in the process address space. If
+@var{baseaddr} is @code{NULL}, the @code{mmalloc} package chooses a
+suitable address at which to start the mapped region, which will be the
+value of the previous mapping if opening an existing file which was
+previously built by @code{mmalloc}, or for new files will be a value
+chosen by @code{mmap}.
+
+Specifying @var{baseaddr} provides more control over where the regions
+start and how big they can be before bumping into existing mapped
+regions or future mapped regions.
+
+On success, returns a malloc descriptor which is used in subsequent
+calls to other @code{mmalloc} package functions. It is explicitly
+@samp{void *} (@samp{char *} for systems that don't fully support
+@code{void}) so that users of the package don't have to worry about the
+actual implementation details.
+
+On failure returns @code{NULL}.
+
+@item void *mmalloc_detach (void *@var{md});
+Terminate access to a @code{mmalloc} managed region identified by the
+descriptor @var{md}, by closing the base file and unmapping all memory
+pages associated with the region.
+
+Returns @code{NULL} on success.
+
+Returns the malloc descriptor on failure, which can subsequently
+be used for further action (such as obtaining more information about
+the nature of the failure).
+
+@item void *mmalloc (void *@var{md}, size_t @var{size});
+Given an @code{mmalloc} descriptor @var{md}, allocate additional memory of
+@var{size} bytes in the associated mapped region.
+
+@item *mrealloc (void *@var{md}, void *@var{ptr}, size_t @var{size});
+Given an @code{mmalloc} descriptor @var{md} and a pointer to memory
+previously allocated by @code{mmalloc} in @var{ptr}, reallocate the
+memory to be @var{size} bytes long, possibly moving the existing
+contents of memory if necessary.
+
+@item void *mvalloc (void *@var{md}, size_t @var{size});
+Like @code{mmalloc} but the resulting memory is aligned on a page boundary.
+
+@item void mfree (void *@var{md}, void *@var{ptr});
+Given an @code{mmalloc} descriptor @var{md} and a pointer to memory previously
+allocated by @code{mmalloc} in @var{ptr}, free the previously allocated memory.
+
+@item int mmalloc_errno (void *@var{md});
+Given a @code{mmalloc} descriptor, if the last @code{mmalloc} operation
+failed for some reason due to a system call failure, then
+returns the associated @code{errno}. Returns 0 otherwise.
+(This function is not yet implemented).
+@end table
+
+@bye
diff --git a/gnu/usr.bin/gdb/mmalloc/mmap-sup.c b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c
new file mode 100644
index 000000000000..37b307905c5b
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c
@@ -0,0 +1,144 @@
+/* Support for an sbrk-like function that uses mmap.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#if defined(HAVE_MMAP)
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#include "mmalloc.h"
+
+extern int munmap PARAMS ((caddr_t, size_t)); /* Not in any header file */
+
+/* Cache the pagesize for the current host machine. Note that if the host
+ does not readily provide a getpagesize() function, we need to emulate it
+ elsewhere, not clutter up this file with lots of kluges to try to figure
+ it out. */
+
+static size_t pagesize;
+extern int getpagesize PARAMS ((void));
+
+#define PAGE_ALIGN(addr) (caddr_t) (((long)(addr) + pagesize - 1) & \
+ ~(pagesize - 1))
+
+/* Get core for the memory region specified by MDP, using SIZE as the
+ amount to either add to or subtract from the existing region. Works
+ like sbrk(), but using mmap(). */
+
+PTR
+__mmalloc_mmap_morecore (mdp, size)
+ struct mdesc *mdp;
+ int size;
+{
+ PTR result = NULL;
+ off_t foffset; /* File offset at which new mapping will start */
+ size_t mapbytes; /* Number of bytes to map */
+ caddr_t moveto; /* Address where we wish to move "break value" to */
+ caddr_t mapto; /* Address we actually mapped to */
+ char buf = 0; /* Single byte to write to extend mapped file */
+
+ if (pagesize == 0)
+ {
+ pagesize = getpagesize ();
+ }
+ if (size == 0)
+ {
+ /* Just return the current "break" value. */
+ result = mdp -> breakval;
+ }
+ else if (size < 0)
+ {
+ /* We are deallocating memory. If the amount requested would cause
+ us to try to deallocate back past the base of the mmap'd region
+ then do nothing, and return NULL. Otherwise, deallocate the
+ memory and return the old break value. */
+ if (mdp -> breakval + size >= mdp -> base)
+ {
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ moveto = PAGE_ALIGN (mdp -> breakval);
+ munmap (moveto, (size_t) (mdp -> top - moveto));
+ mdp -> top = moveto;
+ }
+ }
+ else
+ {
+ /* We are allocating memory. Make sure we have an open file
+ descriptor and then go on to get the memory. */
+ if (mdp -> fd < 0)
+ {
+ result = NULL;
+ }
+ else if (mdp -> breakval + size > mdp -> top)
+ {
+ /* The request would move us past the end of the currently
+ mapped memory, so map in enough more memory to satisfy
+ the request. This means we also have to grow the mapped-to
+ file by an appropriate amount, since mmap cannot be used
+ to extend a file. */
+ moveto = PAGE_ALIGN (mdp -> breakval + size);
+ mapbytes = moveto - mdp -> top;
+ foffset = mdp -> top - mdp -> base;
+ /* FIXME: Test results of lseek() and write() */
+ lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET);
+ write (mdp -> fd, &buf, 1);
+ mapto = mmap (mdp -> top, mapbytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, mdp -> fd, foffset);
+ if (mapto == mdp -> top)
+ {
+ mdp -> top = moveto;
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ }
+ }
+ else
+ {
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ }
+ }
+ return (result);
+}
+
+PTR
+__mmalloc_remap_core (mdp)
+ struct mdesc *mdp;
+{
+ caddr_t base;
+
+ /* FIXME: Quick hack, needs error checking and other attention. */
+
+ base = mmap (mdp -> base, mdp -> top - mdp -> base,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
+ mdp -> fd, 0);
+ return ((PTR) base);
+}
+
+#else /* defined(HAVE_MMAP) */
+/* Prevent "empty translation unit" warnings from the idiots at X3J11. */
+static char ansi_c_idiots = 69;
+#endif /* defined(HAVE_MMAP) */
diff --git a/gnu/usr.bin/gdb/mmalloc/mmcheck.c b/gnu/usr.bin/gdb/mmalloc/mmcheck.c
new file mode 100644
index 000000000000..c3e29d3b3d75
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmcheck.c
@@ -0,0 +1,196 @@
+/* Standard debugging hooks for `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* Default function to call when something awful happens. The application
+ can specify an alternate function to be called instead (and probably will
+ want to). */
+
+extern void abort PARAMS ((void));
+
+/* Arbitrary magical numbers. */
+
+#define MAGICWORD (unsigned int) 0xfedabeeb /* Active chunk */
+#define MAGICWORDFREE (unsigned int) 0xdeadbeef /* Inactive chunk */
+#define MAGICBYTE ((char) 0xd7)
+
+/* Each memory allocation is bounded by a header structure and a trailer
+ byte. I.E.
+
+ <size><magicword><user's allocation><magicbyte>
+
+ The pointer returned to the user points to the first byte in the
+ user's allocation area. The magic word can be tested to detect
+ buffer underruns and the magic byte can be tested to detect overruns. */
+
+struct hdr
+ {
+ size_t size; /* Exact size requested by user. */
+ unsigned long int magic; /* Magic number to check header integrity. */
+ };
+
+/* Check the magicword and magicbyte, and if either is corrupted then
+ call the emergency abort function specified for the heap in use. */
+
+static void
+checkhdr (mdp, hdr)
+ struct mdesc *mdp;
+ CONST struct hdr *hdr;
+{
+ if (hdr -> magic != MAGICWORD ||
+ ((char *) &hdr[1])[hdr -> size] != MAGICBYTE)
+ {
+ (*mdp -> abortfunc)();
+ }
+}
+
+static void
+mfree_check (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ checkhdr (mdp, hdr);
+ hdr -> magic = MAGICWORDFREE;
+ mdp -> mfree_hook = NULL;
+ mfree (md, (PTR)hdr);
+ mdp -> mfree_hook = mfree_check;
+}
+
+static PTR
+mmalloc_check (md, size)
+ PTR md;
+ size_t size;
+{
+ struct hdr *hdr;
+ struct mdesc *mdp;
+ size_t nbytes;
+
+ mdp = MD_TO_MDP (md);
+ mdp -> mmalloc_hook = NULL;
+ nbytes = sizeof (struct hdr) + size + 1;
+ hdr = (struct hdr *) mmalloc (md, nbytes);
+ mdp -> mmalloc_hook = mmalloc_check;
+ if (hdr != NULL)
+ {
+ hdr -> size = size;
+ hdr -> magic = MAGICWORD;
+ hdr++;
+ *((char *) hdr + size) = MAGICBYTE;
+ }
+ return ((PTR) hdr);
+}
+
+static PTR
+mrealloc_check (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ struct mdesc *mdp;
+ size_t nbytes;
+
+ mdp = MD_TO_MDP (md);
+ checkhdr (mdp, hdr);
+ mdp -> mfree_hook = NULL;
+ mdp -> mmalloc_hook = NULL;
+ mdp -> mrealloc_hook = NULL;
+ nbytes = sizeof (struct hdr) + size + 1;
+ hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes);
+ mdp -> mfree_hook = mfree_check;
+ mdp -> mmalloc_hook = mmalloc_check;
+ mdp -> mrealloc_hook = mrealloc_check;
+ if (hdr != NULL)
+ {
+ hdr -> size = size;
+ hdr++;
+ *((char *) hdr + size) = MAGICBYTE;
+ }
+ return ((PTR) hdr);
+}
+
+/* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified
+ by MD. If FUNC is non-NULL, it is a pointer to the function to call
+ to abort whenever memory corruption is detected. By default, this is the
+ standard library function abort().
+
+ Note that we disallow installation of initial checking hooks if mmalloc
+ has been called at any time for this particular heap, since if any region
+ that is allocated prior to installation of the hooks is subsequently
+ reallocated or freed after installation of the hooks, it is guaranteed
+ to trigger a memory corruption error. We do this by checking the state
+ of the MMALLOC_INITIALIZED flag.
+
+ However, we can call this function at any time after the initial call,
+ to update the function pointers to the checking routines and to the
+ user defined corruption handler routine, as long as these function pointers
+ have been previously extablished by the initial call. Note that we
+ do this automatically when remapping an previously used heap, to ensure
+ that the hooks get updated to the correct values, although the corruption
+ handler pointer gets set back to the default. The application can then
+ call mmcheck to use a different corruption handler if desired.
+
+ Returns non-zero if checking is successfully enabled, zero otherwise. */
+
+int
+mmcheck (md, func)
+ PTR md;
+ void (*func) PARAMS ((void));
+{
+ struct mdesc *mdp;
+ int rtnval;
+
+ mdp = MD_TO_MDP (md);
+
+ /* We can safely set or update the abort function at any time, regardless
+ of whether or not we successfully do anything else. */
+
+ mdp -> abortfunc = (func != NULL ? func : abort);
+
+ /* If we haven't yet called mmalloc the first time for this heap, or if we
+ have hooks that were previously installed, then allow the hooks to be
+ initialized or updated. */
+
+ if (1 /* FIXME: Always allow installation for now. */ ||
+ !(mdp -> flags & MMALLOC_INITIALIZED) ||
+ (mdp -> mfree_hook != NULL))
+ {
+ mdp -> mfree_hook = mfree_check;
+ mdp -> mmalloc_hook = mmalloc_check;
+ mdp -> mrealloc_hook = mrealloc_check;
+ mdp -> flags |= MMALLOC_MMCHECK_USED;
+ rtnval = 1;
+ }
+ else
+ {
+ rtnval = 0;
+ }
+
+ return (rtnval);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmemalign.c b/gnu/usr.bin/gdb/mmalloc/mmemalign.c
new file mode 100644
index 000000000000..63350a215cd3
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmemalign.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "mmalloc.h"
+
+PTR
+mmemalign (md, alignment, size)
+ PTR md;
+ size_t alignment;
+ size_t size;
+{
+ PTR result;
+ unsigned long int adj;
+ struct alignlist *l;
+ struct mdesc *mdp;
+
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ if ((result = mmalloc (md, size)) != NULL)
+ {
+ adj = RESIDUAL (result, alignment);
+ if (adj != 0)
+ {
+ mdp = MD_TO_MDP (md);
+ for (l = mdp -> aligned_blocks; l != NULL; l = l -> next)
+ {
+ if (l -> aligned == NULL)
+ {
+ /* This slot is free. Use it. */
+ break;
+ }
+ }
+ if (l == NULL)
+ {
+ l = (struct alignlist *) mmalloc (md, sizeof (struct alignlist));
+ if (l == NULL)
+ {
+ mfree (md, result);
+ return (NULL);
+ }
+ }
+ l -> exact = result;
+ result = l -> aligned = (char *) result + alignment - adj;
+ l -> next = mdp -> aligned_blocks;
+ mdp -> aligned_blocks = l;
+ }
+ }
+ return (result);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmstats.c b/gnu/usr.bin/gdb/mmalloc/mmstats.c
new file mode 100644
index 000000000000..d3846eb2dbe5
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmstats.c
@@ -0,0 +1,46 @@
+/* Access the statistics maintained by `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* FIXME: See the comment in mmalloc.h where struct mstats is defined.
+ None of the internal mmalloc structures should be externally visible
+ outside the library. */
+
+struct mstats
+mmstats (md)
+ PTR md;
+{
+ struct mstats result;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ result.bytes_total =
+ (char *) mdp -> morecore (mdp, 0) - mdp -> heapbase;
+ result.chunks_used = mdp -> heapstats.chunks_used;
+ result.bytes_used = mdp -> heapstats.bytes_used;
+ result.chunks_free = mdp -> heapstats.chunks_free;
+ result.bytes_free = mdp -> heapstats.bytes_free;
+ return (result);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmtrace.c b/gnu/usr.bin/gdb/mmalloc/mmtrace.c
new file mode 100644
index 000000000000..73368a1b57aa
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmtrace.c
@@ -0,0 +1,166 @@
+/* More debugging hooks for `mmalloc'.
+ Copyright 1991, 1992 Free Software Foundation
+
+ Written April 2, 1991 by John Gilmore of Cygnus Support
+ Based on mcheck.c by Mike Haertel.
+ Modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "mmalloc.h"
+
+#ifndef __GNU_LIBRARY__
+extern char *getenv ();
+#endif
+
+static FILE *mallstream;
+
+#if 0 /* FIXME: Disabled for now. */
+static char mallenv[] = "MALLOC_TRACE";
+static char mallbuf[BUFSIZ]; /* Buffer for the output. */
+#endif
+
+/* Address to breakpoint on accesses to... */
+static PTR mallwatch;
+
+/* Old hook values. */
+
+static void (*old_mfree_hook) PARAMS ((PTR, PTR));
+static PTR (*old_mmalloc_hook) PARAMS ((PTR, size_t));
+static PTR (*old_mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ freed has an address matching the variable "mallwatch". In a debugger,
+ set "mallwatch" to the address of interest, then put a breakpoint on
+ tr_break. */
+
+static void
+tr_break ()
+{
+}
+
+static void
+tr_freehook (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ /* Be sure to print it first. */
+ fprintf (mallstream, "- %08x\n", (unsigned int) ptr);
+ if (ptr == mallwatch)
+ tr_break ();
+ mdp -> mfree_hook = old_mfree_hook;
+ mfree (md, ptr);
+ mdp -> mfree_hook = tr_freehook;
+}
+
+static PTR
+tr_mallochook (md, size)
+ PTR md;
+ size_t size;
+{
+ PTR hdr;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ mdp -> mmalloc_hook = old_mmalloc_hook;
+ hdr = (PTR) mmalloc (md, size);
+ mdp -> mmalloc_hook = tr_mallochook;
+
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %08x %x\n", (unsigned int) hdr, size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return (hdr);
+}
+
+static PTR
+tr_reallochook (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ PTR hdr;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ mdp -> mfree_hook = old_mfree_hook;
+ mdp -> mmalloc_hook = old_mmalloc_hook;
+ mdp -> mrealloc_hook = old_mrealloc_hook;
+ hdr = (PTR) mrealloc (md, ptr, size);
+ mdp -> mfree_hook = tr_freehook;
+ mdp -> mmalloc_hook = tr_mallochook;
+ mdp -> mrealloc_hook = tr_reallochook;
+ if (hdr == NULL)
+ /* Failed realloc. */
+ fprintf (mallstream, "! %08x %x\n", (unsigned int) ptr, size);
+ else
+ fprintf (mallstream, "< %08x\n> %08x %x\n", (unsigned int) ptr,
+ (unsigned int) hdr, size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+ is set, or if the variable mallwatch has been patched to an address
+ that the debugging user wants us to stop on. When patching mallwatch,
+ don't forget to set a breakpoint on tr_break! */
+
+int
+mmtrace ()
+{
+#if 0 /* FIXME! This is disabled for now until we figure out how to
+ maintain a stack of hooks per heap, since we might have other
+ hooks (such as set by mmcheck) active also. */
+ char *mallfile;
+
+ mallfile = getenv (mallenv);
+ if (mallfile != NULL || mallwatch != NULL)
+ {
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+ if (mallstream != NULL)
+ {
+ /* Be sure it doesn't mmalloc its buffer! */
+ setbuf (mallstream, mallbuf);
+ fprintf (mallstream, "= Start\n");
+ old_mfree_hook = mdp -> mfree_hook;
+ mdp -> mfree_hook = tr_freehook;
+ old_mmalloc_hook = mdp -> mmalloc_hook;
+ mdp -> mmalloc_hook = tr_mallochook;
+ old_mrealloc_hook = mdp -> mrealloc_hook;
+ mdp -> mrealloc_hook = tr_reallochook;
+ }
+ }
+
+#endif /* 0 */
+
+ return (1);
+}
+
diff --git a/gnu/usr.bin/gdb/mmalloc/mrealloc.c b/gnu/usr.bin/gdb/mmalloc/mrealloc.c
new file mode 100644
index 000000000000..85bec565dadb
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mrealloc.c
@@ -0,0 +1,160 @@
+/* Change the size of a block allocated by `mmalloc'.
+ Copyright 1990, 1991 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both mfree and mmalloc. */
+
+PTR
+mrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ struct mdesc *mdp;
+ PTR result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ if (size == 0)
+ {
+ mfree (md, ptr);
+ return (mmalloc (md, 0));
+ }
+ else if (ptr == NULL)
+ {
+ return (mmalloc (md, size));
+ }
+
+ mdp = MD_TO_MDP (md);
+
+ if (mdp -> mrealloc_hook != NULL)
+ {
+ return ((*mdp -> mrealloc_hook) (md, ptr, size));
+ }
+
+ block = BLOCK (ptr);
+
+ type = mdp -> heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ result = mmalloc (md, size);
+ if (result != NULL)
+ {
+ memcpy (result, ptr, size);
+ mfree (md, ptr);
+ return (result);
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY (size);
+ if (blocks < mdp -> heapinfo[block].busy.info.size)
+ {
+ /* The new size is smaller; return excess memory to the free list. */
+ mdp -> heapinfo[block + blocks].busy.type = 0;
+ mdp -> heapinfo[block + blocks].busy.info.size
+ = mdp -> heapinfo[block].busy.info.size - blocks;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mfree (md, ADDRESS (block + blocks));
+ result = ptr;
+ }
+ else if (blocks == mdp -> heapinfo[block].busy.info.size)
+ {
+ /* No size change necessary. */
+ result = ptr;
+ }
+ else
+ {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = mdp -> heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = mdp -> heaplimit;
+ mdp -> heaplimit = 0;
+ mfree (md, ptr);
+ mdp -> heaplimit = oldlimit;
+ result = mmalloc (md, size);
+ if (result == NULL)
+ {
+ mmalloc (md, blocks * BLOCKSIZE);
+ return (NULL);
+ }
+ if (ptr != result)
+ {
+ memmove (result, ptr, blocks * BLOCKSIZE);
+ }
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+ {
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ }
+ else
+ {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = mmalloc (md, size);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+ memcpy (result, ptr, MIN (size, (size_t) 1 << type));
+ mfree (md, ptr);
+ }
+ break;
+ }
+
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+realloc (ptr, size)
+ PTR ptr;
+ size_t size;
+{
+ return (mrealloc ((PTR) NULL, ptr, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mvalloc.c b/gnu/usr.bin/gdb/mmalloc/mvalloc.c
new file mode 100644
index 000000000000..1ffba7865cf7
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mvalloc.c
@@ -0,0 +1,40 @@
+/* Allocate memory on a page boundary.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "mmalloc.h"
+
+/* Cache the pagesize for the current host machine. Note that if the host
+ does not readily provide a getpagesize() function, we need to emulate it
+ elsewhere, not clutter up this file with lots of kluges to try to figure
+ it out. */
+
+static size_t pagesize;
+extern int getpagesize PARAMS ((void));
+
+PTR
+mvalloc (md, size)
+ PTR md;
+ size_t size;
+{
+ if (pagesize == 0)
+ {
+ pagesize = getpagesize ();
+ }
+
+ return (mmemalign (md, pagesize, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c
new file mode 100644
index 000000000000..e6a57d6ccad2
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c
@@ -0,0 +1,96 @@
+/* Support for sbrk() regions.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+extern PTR sbrk ();
+
+/* The mmalloc() package can use a single implicit malloc descriptor
+ for mmalloc/mrealloc/mfree operations which do not supply an explicit
+ descriptor. For these operations, sbrk() is used to obtain more core
+ from the system, or return core. This allows mmalloc() to provide
+ backwards compatibility with the non-mmap'd version. */
+
+struct mdesc *__mmalloc_default_mdp;
+
+/* Use sbrk() to get more core. */
+
+static PTR
+sbrk_morecore (mdp, size)
+ struct mdesc *mdp;
+ int size;
+{
+ PTR result;
+
+ if ((result = sbrk (size)) == (PTR) -1)
+ {
+ result = NULL;
+ }
+ else
+ {
+ mdp -> breakval += size;
+ mdp -> top += size;
+ }
+ return (result);
+}
+
+/* Initialize the default malloc descriptor if this is the first time
+ a request has been made to use the default sbrk'd region.
+
+ Since no alignment guarantees are made about the initial value returned
+ by sbrk, test the initial value and (if necessary) sbrk enough additional
+ memory to start off with alignment to BLOCKSIZE. We actually only need
+ it aligned to an alignment suitable for any object, so this is overkill.
+ But at most it wastes just part of one BLOCKSIZE chunk of memory and
+ minimizes portability problems by avoiding us having to figure out
+ what the actual minimal alignment is. The rest of the malloc code
+ avoids this as well, by always aligning to the minimum of the requested
+ size rounded up to a power of two, or to BLOCKSIZE.
+
+ Note that we are going to use some memory starting at this initial sbrk
+ address for the sbrk region malloc descriptor, which is a struct, so the
+ base address must be suitably aligned. */
+
+struct mdesc *
+__mmalloc_sbrk_init ()
+{
+ PTR base;
+ unsigned int adj;
+
+ base = sbrk (0);
+ adj = RESIDUAL (base, BLOCKSIZE);
+ if (adj != 0)
+ {
+ sbrk (BLOCKSIZE - adj);
+ base = sbrk (0);
+ }
+ __mmalloc_default_mdp = (struct mdesc *) sbrk (sizeof (struct mdesc));
+ memset ((char *) __mmalloc_default_mdp, 0, sizeof (struct mdesc));
+ __mmalloc_default_mdp -> morecore = sbrk_morecore;
+ __mmalloc_default_mdp -> base = base;
+ __mmalloc_default_mdp -> breakval = __mmalloc_default_mdp -> top = sbrk (0);
+ __mmalloc_default_mdp -> fd = -1;
+ return (__mmalloc_default_mdp);
+}
+
+
diff --git a/gnu/usr.bin/gdb/readline/ChangeLog b/gnu/usr.bin/gdb/readline/ChangeLog
deleted file mode 100644
index b72a59daed03..000000000000
--- a/gnu/usr.bin/gdb/readline/ChangeLog
+++ /dev/null
@@ -1,98 +0,0 @@
-Thu Feb 8 01:04:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
-
- * Makefile (the *other* libreadline.a): Uncomment out ranlib line.
-
-Thu Feb 1 17:50:22 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
-
- * Makefile (libreadline.a): Uncomment out ranlib line.
-
-Sun Nov 26 16:29:11 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
-
- * readline.c (rl_deprep_terminal): Only restore local_mode_flags
- if they had been set.
-
-Thu Oct 19 17:18:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
-
- * Move vi_doing_insert from vi_mode.c to readline.c
-
- * readline.c: Move compare_strings before its use.
- Remove declarations.
-
- * readline.c: Move defining_kbd_macro above rl_dispatch.
- (rl_dispatch): Remove "extern int defining_kbd_macro".
-
-Mon Oct 16 11:56:03 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
-
- * readline.c (rl_set_signals): Remove unnecessary "static int
- rl_signal_handler()".
-
-Sat Sep 30 14:51:56 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
-
- * readline.c (rl_initialize): Change parsing_conditionalized_out
- to static.
- (rl_dispatch): Change defining_kbd_macro to static.
- (rl_newline): Change vi_doing_insert to static.
-
-Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel)
-
- * readline.c: rl_prep_terminal (). Only turn on 8th bit
- as meta-bit iff the terminal is not using parity.
-
-Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel)
-
- * readline.c: start_insert (). Uses multiple
- insertion call in cases where that makes sense.
-
- rl_insert (). Read type-ahead buffer for additional
- keys that are bound to rl_insert, and insert them
- all at once. Make insertion of single keys given
- with an argument much more efficient.
-
-Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel)
-
- * readline.c: Changed handling of EOF. readline () returns
- (char *)EOF or consed string. The EOF character is read from the
- tty, or if the tty doesn't have one, defaults to C-d.
-
- * readline.c: Added support for event driven programs.
- rl_event_hook is the address of a function you want called
- while Readline is waiting for input.
-
- * readline.c: Cleanup time. Functions without type declarations
- do not use return with a value.
-
- * history.c: history_expand () has new variable which is the
- characters to ignore immediately following history_expansion_char.
-
-Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel)
-
- * rl_prep_terminal ()
- BSD version turns off C-s, C-q, C-y, C-v.
-
- * readline.c -- rl_prep_terminal ()
- SYSV version hacks readline_echoing_p.
- BSD version turns on passing of the 8th bit for the duration
- of reading the line.
-
-Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel)
-
- * readline.c: new variable rl_tilde_expander.
- If non-null, this contains the address of a function to call if
- the standard meaning for expanding a tilde fails. The function is
- called with the text sans tilde (as in "foo"), and returns a
- malloc()'ed string which is the expansion, or a NULL pointer if
- there is no expansion.
-
- * readline.h - new file chardefs.h
- Separates things that only readline.c needs from the standard
- header file publishing interesting things about readline.
-
- * readline.c:
- readline_default_bindings () now looks at terminal chararacters
- and binds those as well.
-
-Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel)
-
- * Made readline and history into independent libraries.
-
-
diff --git a/gnu/usr.bin/gdb/readline/Makefile.gnu b/gnu/usr.bin/gdb/readline/Makefile.gnu
deleted file mode 100644
index dc1153984e86..000000000000
--- a/gnu/usr.bin/gdb/readline/Makefile.gnu
+++ /dev/null
@@ -1,114 +0,0 @@
-## -*- text -*- ####################################################
-# #
-# Makefile for readline and history libraries. #
-# #
-####################################################################
-
-# Here is a rule for making .o files from .c files that doesn't force
-# the type of the machine (like -sun3) into the flags.
-.c.o:
- $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $*.c
-
-# Destination installation directory. The libraries are copied to DESTDIR
-# when you do a `make install', and the header files to INCDIR/readline/*.h.
-DESTDIR = /usr/gnu/lib
-INCDIR = /usr/gnu/include
-
-# Define TYPES as -DVOID_SIGHANDLER if your operating system uses
-# a return type of "void" for signal handlers.
-TYPES = -DVOID_SIGHANDLER
-
-# Define SYSV as -DSYSV if you are using a System V operating system.
-#SYSV = -DSYSV
-
-# HP-UX compilation requires the BSD library.
-#LOCAL_LIBS = -lBSD
-
-# Xenix compilation requires -ldir -lx
-#LOCAL_LIBS = -ldir -lx
-
-# Comment this out if you don't think that anyone will ever desire
-# the vi line editing mode and features.
-READLINE_DEFINES = -DVI_MODE
-
-DEBUG_FLAGS = -g
-LDFLAGS = $(DEBUG_FLAGS)
-CFLAGS = $(DEBUG_FLAGS) $(TYPE) $(SYSV) -I.
-
-# A good alternative is gcc -traditional.
-#CC = gcc -traditional
-CC = cc
-RANLIB = /usr/bin/ranlib
-AR = ar
-RM = rm
-CP = cp
-
-LOCAL_INCLUDES = -I../
-
-CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \
- emacs_keymap.c vi_keymap.c keymaps.c
-
-HSOURCES = readline.h chardefs.h history.h keymaps.h
-SOURCES = $(CSOURCES) $(HSOURCES)
-
-DOCUMENTATION = readline.texinfo inc-readline.texinfo \
- history.texinfo inc-history.texinfo
-
-SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog
-
-THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
-
-##########################################################################
-
-all: libreadline.a
-
-libreadline.a: readline.o history.o funmap.o keymaps.o
- $(RM) -f libreadline.a
- $(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o
- if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi
-
-readline.o: readline.h chardefs.h keymaps.h history.h readline.c vi_mode.c
- $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
- $(LOCAL_INCLUDES) $*.c
-
-history.o: history.c history.h
- $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
- $(LOCAL_INCLUDES) $*.c
-
-funmap.o: readline.h
- $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
- $(LOCAL_INCLUDES) $*.c
-
-keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c
- $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
- $(LOCAL_INCLUDES) $*.c
-
-libtest: libreadline.a libtest.c
- $(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap
-
-readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h
- $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
- $(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \
- keymaps.o history.o -L. -ltermcap
-
-readline.tar: $(THINGS_TO_TAR)
- tar -cf readline.tar $(THINGS_TO_TAR)
-
-readline.tar.Z: readline.tar
- compress -f readline.tar
-
-install: $(DESTDIR)/libreadline.a includes
-
-includes:
- if [ ! -r $(INCDIR)/readline ]; then\
- mkdir $(INCDIR)/readline;\
- chmod a+r $(INCDIR)/readline;\
- fi
- $(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/
-clean:
- rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc
-
-$(DESTDIR)/libreadline.a: libreadline.a
- -mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old
- cp libreadline.a $(DESTDIR)/libreadline.a
- $(RANLIB) -t $(DESTDIR)/libreadline.a
diff --git a/gnu/usr.bin/gdb/readline/chardefs.h b/gnu/usr.bin/gdb/readline/chardefs.h
deleted file mode 100644
index 9749ae489f46..000000000000
--- a/gnu/usr.bin/gdb/readline/chardefs.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* chardefs.h -- Character definitions for readline. */
-#ifndef _CHARDEFS_
-
-#ifndef savestring
-#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
-#endif
-
-#ifndef whitespace
-#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
-#endif
-
-#ifdef CTRL
-#undef CTRL
-#endif
-
-/* Some character stuff. */
-#define control_character_threshold 0x020 /* smaller than this is control */
-#define meta_character_threshold 0x07f /* larger than this is Meta. */
-#define control_character_bit 0x40 /* 0x000000, must be off. */
-#define meta_character_bit 0x080 /* x0000000, must be on. */
-
-#define CTRL(c) ((c) & (~control_character_bit))
-#define META(c) ((c) | meta_character_bit)
-
-#define UNMETA(c) ((c) & (~meta_character_bit))
-#define UNCTRL(c) to_upper(((c)|control_character_bit))
-
-#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1)))
-#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1)))
-
-#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c))
-
-#ifndef to_upper
-#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c))
-#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c))
-#endif
-
-#define CTRL_P(c) ((c) < control_character_threshold)
-#define META_P(c) ((c) > meta_character_threshold)
-
-#define NEWLINE '\n'
-#define RETURN CTRL('M')
-#define RUBOUT 0x07f
-#define TAB '\t'
-#define ABORT_CHAR CTRL('G')
-#define PAGE CTRL('L')
-#define SPACE 0x020
-#define ESC CTRL('[')
-
-#endif /* _CHARDEFS_ */
diff --git a/gnu/usr.bin/gdb/readline/emacs_keymap.c b/gnu/usr.bin/gdb/readline/emacs_keymap.c
deleted file mode 100644
index 7030e69f6b7c..000000000000
--- a/gnu/usr.bin/gdb/readline/emacs_keymap.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
-
-/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
-
- This file is part of GNU Readline, a library for reading lines
- of text with interactive input and history editing.
-
- Readline is free software; you can 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.
-
- Readline is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Readline; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef FILE
-#include <stdio.h>
-#endif /* FILE */
-
-#include "readline.h"
-
-/* An array of function pointers, one for each possible key.
- If the type byte is ISKMAP, then the pointer is the address of
- a keymap. */
-
-KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
-
- /* Control keys. */
- { ISFUNC, (Function *)0x0 }, /* Control-@ */
- { ISFUNC, rl_beg_of_line }, /* Control-a */
- { ISFUNC, rl_backward }, /* Control-b */
- { ISFUNC, (Function *)0x0 }, /* Control-c */
- { ISFUNC, rl_delete }, /* Control-d */
- { ISFUNC, rl_end_of_line }, /* Control-e */
- { ISFUNC, rl_forward }, /* Control-f */
- { ISFUNC, rl_abort }, /* Control-g */
- { ISFUNC, rl_backward }, /* Control-h */
- { ISFUNC, rl_complete }, /* Control-i */
- { ISFUNC, rl_newline }, /* Control-j */
- { ISFUNC, rl_kill_line }, /* Control-k */
- { ISFUNC, rl_clear_screen }, /* Control-l */
- { ISFUNC, rl_newline }, /* Control-m */
- { ISFUNC, rl_get_next_history }, /* Control-n */
- { ISFUNC, (Function *)0x0 }, /* Control-o */
- { ISFUNC, rl_get_previous_history }, /* Control-p */
- { ISFUNC, rl_quoted_insert }, /* Control-q */
- { ISFUNC, rl_reverse_search_history }, /* Control-r */
- { ISFUNC, rl_forward_search_history }, /* Control-s */
- { ISFUNC, rl_transpose_chars }, /* Control-t */
- { ISFUNC, rl_unix_line_discard }, /* Control-u */
- { ISFUNC, rl_quoted_insert }, /* Control-v */
- { ISFUNC, rl_unix_word_rubout }, /* Control-w */
- { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */
- { ISFUNC, rl_yank }, /* Control-y */
- { ISFUNC, (Function *)0x0 }, /* Control-z */
- { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
- { ISFUNC, (Function *)0x0 }, /* Control-\ */
- { ISFUNC, (Function *)0x0 }, /* Control-] */
- { ISFUNC, (Function *)0x0 }, /* Control-^ */
- { ISFUNC, rl_undo_command }, /* Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, rl_insert }, /* SPACE */
- { ISFUNC, rl_insert }, /* ! */
- { ISFUNC, rl_insert }, /* " */
- { ISFUNC, rl_insert }, /* # */
- { ISFUNC, rl_insert }, /* $ */
- { ISFUNC, rl_insert }, /* % */
- { ISFUNC, rl_insert }, /* & */
- { ISFUNC, rl_insert }, /* ' */
- { ISFUNC, rl_insert }, /* ( */
- { ISFUNC, rl_insert }, /* ) */
- { ISFUNC, rl_insert }, /* * */
- { ISFUNC, rl_insert }, /* + */
- { ISFUNC, rl_insert }, /* , */
- { ISFUNC, rl_insert }, /* - */
- { ISFUNC, rl_insert }, /* . */
- { ISFUNC, rl_insert }, /* / */
-
- /* Regular digits. */
- { ISFUNC, rl_insert }, /* 0 */
- { ISFUNC, rl_insert }, /* 1 */
- { ISFUNC, rl_insert }, /* 2 */
- { ISFUNC, rl_insert }, /* 3 */
- { ISFUNC, rl_insert }, /* 4 */
- { ISFUNC, rl_insert }, /* 5 */
- { ISFUNC, rl_insert }, /* 6 */
- { ISFUNC, rl_insert }, /* 7 */
- { ISFUNC, rl_insert }, /* 8 */
- { ISFUNC, rl_insert }, /* 9 */
-
- /* A little more punctuation. */
- { ISFUNC, rl_insert }, /* : */
- { ISFUNC, rl_insert }, /* ; */
- { ISFUNC, rl_insert }, /* < */
- { ISFUNC, rl_insert }, /* = */
- { ISFUNC, rl_insert }, /* > */
- { ISFUNC, rl_insert }, /* ? */
- { ISFUNC, rl_insert }, /* @ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_insert }, /* A */
- { ISFUNC, rl_insert }, /* B */
- { ISFUNC, rl_insert }, /* C */
- { ISFUNC, rl_insert }, /* D */
- { ISFUNC, rl_insert }, /* E */
- { ISFUNC, rl_insert }, /* F */
- { ISFUNC, rl_insert }, /* G */
- { ISFUNC, rl_insert }, /* H */
- { ISFUNC, rl_insert }, /* I */
- { ISFUNC, rl_insert }, /* J */
- { ISFUNC, rl_insert }, /* K */
- { ISFUNC, rl_insert }, /* L */
- { ISFUNC, rl_insert }, /* M */
- { ISFUNC, rl_insert }, /* N */
- { ISFUNC, rl_insert }, /* O */
- { ISFUNC, rl_insert }, /* P */
- { ISFUNC, rl_insert }, /* Q */
- { ISFUNC, rl_insert }, /* R */
- { ISFUNC, rl_insert }, /* S */
- { ISFUNC, rl_insert }, /* T */
- { ISFUNC, rl_insert }, /* U */
- { ISFUNC, rl_insert }, /* V */
- { ISFUNC, rl_insert }, /* W */
- { ISFUNC, rl_insert }, /* X */
- { ISFUNC, rl_insert }, /* Y */
- { ISFUNC, rl_insert }, /* Z */
-
- /* Some more punctuation. */
- { ISFUNC, rl_insert }, /* [ */
- { ISFUNC, rl_insert }, /* \ */
- { ISFUNC, rl_insert }, /* ] */
- { ISFUNC, rl_insert }, /* ^ */
- { ISFUNC, rl_insert }, /* _ */
- { ISFUNC, rl_insert }, /* ` */
-
- /* Lowercase alphabet. */
- { ISFUNC, rl_insert }, /* a */
- { ISFUNC, rl_insert }, /* b */
- { ISFUNC, rl_insert }, /* c */
- { ISFUNC, rl_insert }, /* d */
- { ISFUNC, rl_insert }, /* e */
- { ISFUNC, rl_insert }, /* f */
- { ISFUNC, rl_insert }, /* g */
- { ISFUNC, rl_insert }, /* h */
- { ISFUNC, rl_insert }, /* i */
- { ISFUNC, rl_insert }, /* j */
- { ISFUNC, rl_insert }, /* k */
- { ISFUNC, rl_insert }, /* l */
- { ISFUNC, rl_insert }, /* m */
- { ISFUNC, rl_insert }, /* n */
- { ISFUNC, rl_insert }, /* o */
- { ISFUNC, rl_insert }, /* p */
- { ISFUNC, rl_insert }, /* q */
- { ISFUNC, rl_insert }, /* r */
- { ISFUNC, rl_insert }, /* s */
- { ISFUNC, rl_insert }, /* t */
- { ISFUNC, rl_insert }, /* u */
- { ISFUNC, rl_insert }, /* v */
- { ISFUNC, rl_insert }, /* w */
- { ISFUNC, rl_insert }, /* x */
- { ISFUNC, rl_insert }, /* y */
- { ISFUNC, rl_insert }, /* z */
-
- /* Final punctuation. */
- { ISFUNC, rl_insert }, /* { */
- { ISFUNC, rl_insert }, /* | */
- { ISFUNC, rl_insert }, /* } */
- { ISFUNC, rl_insert }, /* ~ */
- { ISFUNC, rl_rubout } /* RUBOUT */
-};
-
-KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
-
- /* Meta keys. Just like above, but the high bit is set. */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
- { ISFUNC, rl_abort }, /* Meta-Control-g */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */
- { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
- { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
- { ISFUNC, rl_revert_line }, /* Meta-Control-r */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
- { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
-
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
- { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */
- { ISFUNC, (Function *)0x0 }, /* Meta-! */
- { ISFUNC, (Function *)0x0 }, /* Meta-" */
- { ISFUNC, (Function *)0x0 }, /* Meta-# */
- { ISFUNC, (Function *)0x0 }, /* Meta-$ */
- { ISFUNC, (Function *)0x0 }, /* Meta-% */
- { ISFUNC, (Function *)0x0 }, /* Meta-& */
- { ISFUNC, (Function *)0x0 }, /* Meta-' */
- { ISFUNC, (Function *)0x0 }, /* Meta-( */
- { ISFUNC, (Function *)0x0 }, /* Meta-) */
- { ISFUNC, (Function *)0x0 }, /* Meta-* */
- { ISFUNC, (Function *)0x0 }, /* Meta-+ */
- { ISFUNC, (Function *)0x0 }, /* Meta-, */
- { ISFUNC, rl_digit_argument }, /* Meta-- */
- { ISFUNC, (Function *)0x0 }, /* Meta-. */
- { ISFUNC, (Function *)0x0 }, /* Meta-/ */
-
- /* Regular digits. */
- { ISFUNC, rl_digit_argument }, /* Meta-0 */
- { ISFUNC, rl_digit_argument }, /* Meta-1 */
- { ISFUNC, rl_digit_argument }, /* Meta-2 */
- { ISFUNC, rl_digit_argument }, /* Meta-3 */
- { ISFUNC, rl_digit_argument }, /* Meta-4 */
- { ISFUNC, rl_digit_argument }, /* Meta-5 */
- { ISFUNC, rl_digit_argument }, /* Meta-6 */
- { ISFUNC, rl_digit_argument }, /* Meta-7 */
- { ISFUNC, rl_digit_argument }, /* Meta-8 */
- { ISFUNC, rl_digit_argument }, /* Meta-9 */
-
- /* A little more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* Meta-: */
- { ISFUNC, (Function *)0x0 }, /* Meta-; */
- { ISFUNC, rl_beginning_of_history }, /* Meta-< */
- { ISFUNC, (Function *)0x0 }, /* Meta-= */
- { ISFUNC, rl_end_of_history }, /* Meta-> */
- { ISFUNC, rl_possible_completions }, /* Meta-? */
- { ISFUNC, (Function *)0x0 }, /* Meta-@ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-A */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-B */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-C */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-D */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-E */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-F */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-G */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-H */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-I */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-J */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-K */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-L */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-M */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-N */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-O */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-P */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-R */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-S */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-T */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-U */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-V */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-W */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-X */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
- { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
-
- /* Some more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* Meta-[ */
- { ISFUNC, (Function *)0x0 }, /* Meta-\ */
- { ISFUNC, (Function *)0x0 }, /* Meta-] */
- { ISFUNC, (Function *)0x0 }, /* Meta-^ */
- { ISFUNC, (Function *)0x0 }, /* Meta-_ */
- { ISFUNC, (Function *)0x0 }, /* Meta-` */
-
- /* Lowercase alphabet. */
- { ISFUNC, (Function *)0x0 }, /* Meta-a */
- { ISFUNC, rl_backward_word }, /* Meta-b */
- { ISFUNC, rl_capitalize_word }, /* Meta-c */
- { ISFUNC, rl_kill_word }, /* Meta-d */
- { ISFUNC, (Function *)0x0 }, /* Meta-e */
- { ISFUNC, rl_forward_word }, /* Meta-f */
- { ISFUNC, (Function *)0x0 }, /* Meta-g */
- { ISFUNC, (Function *)0x0 }, /* Meta-h */
- { ISFUNC, (Function *)0x0 }, /* Meta-i */
- { ISFUNC, (Function *)0x0 }, /* Meta-j */
- { ISFUNC, (Function *)0x0 }, /* Meta-k */
- { ISFUNC, rl_downcase_word }, /* Meta-l */
- { ISFUNC, (Function *)0x0 }, /* Meta-m */
- { ISFUNC, (Function *)0x0 }, /* Meta-n */
- { ISFUNC, (Function *)0x0 }, /* Meta-o */
- { ISFUNC, (Function *)0x0 }, /* Meta-p */
- { ISFUNC, (Function *)0x0 }, /* Meta-q */
- { ISFUNC, rl_revert_line }, /* Meta-r */
- { ISFUNC, (Function *)0x0 }, /* Meta-s */
- { ISFUNC, rl_transpose_words }, /* Meta-t */
- { ISFUNC, rl_upcase_word }, /* Meta-u */
- { ISFUNC, (Function *)0x0 }, /* Meta-v */
- { ISFUNC, (Function *)0x0 }, /* Meta-w */
- { ISFUNC, (Function *)0x0 }, /* Meta-x */
- { ISFUNC, rl_yank_pop }, /* Meta-y */
- { ISFUNC, (Function *)0x0 }, /* Meta-z */
-
- /* Final punctuation. */
- { ISFUNC, (Function *)0x0 }, /* Meta-{ */
- { ISFUNC, (Function *)0x0 }, /* Meta-| */
- { ISFUNC, (Function *)0x0 }, /* Meta-} */
- { ISFUNC, (Function *)0x0 }, /* Meta-~ */
- { ISFUNC, rl_backward_kill_word } /* Meta-rubout */
-};
-
-KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
-
- /* Control keys. */
- { ISFUNC, (Function *)0x0 }, /* Control-@ */
- { ISFUNC, (Function *)0x0 }, /* Control-a */
- { ISFUNC, (Function *)0x0 }, /* Control-b */
- { ISFUNC, (Function *)0x0 }, /* Control-c */
- { ISFUNC, (Function *)0x0 }, /* Control-d */
- { ISFUNC, (Function *)0x0 }, /* Control-e */
- { ISFUNC, (Function *)0x0 }, /* Control-f */
- { ISFUNC, rl_abort }, /* Control-g */
- { ISFUNC, (Function *)0x0 }, /* Control-h */
- { ISFUNC, (Function *)0x0 }, /* Control-i */
- { ISFUNC, (Function *)0x0 }, /* Control-j */
- { ISFUNC, (Function *)0x0 }, /* Control-k */
- { ISFUNC, (Function *)0x0 }, /* Control-l */
- { ISFUNC, (Function *)0x0 }, /* Control-m */
- { ISFUNC, (Function *)0x0 }, /* Control-n */
- { ISFUNC, (Function *)0x0 }, /* Control-o */
- { ISFUNC, (Function *)0x0 }, /* Control-p */
- { ISFUNC, (Function *)0x0 }, /* Control-q */
- { ISFUNC, rl_re_read_init_file }, /* Control-r */
- { ISFUNC, (Function *)0x0 }, /* Control-s */
- { ISFUNC, (Function *)0x0 }, /* Control-t */
- { ISFUNC, rl_undo_command }, /* Control-u */
- { ISFUNC, (Function *)0x0 }, /* Control-v */
- { ISFUNC, (Function *)0x0 }, /* Control-w */
- { ISFUNC, (Function *)0x0 }, /* Control-x */
- { ISFUNC, (Function *)0x0 }, /* Control-y */
- { ISFUNC, (Function *)0x0 }, /* Control-z */
- { ISFUNC, (Function *)0x0 }, /* Control-[ */
- { ISFUNC, (Function *)0x0 }, /* Control-\ */
- { ISFUNC, (Function *)0x0 }, /* Control-] */
- { ISFUNC, (Function *)0x0 }, /* Control-^ */
- { ISFUNC, (Function *)0x0 }, /* Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, (Function *)0x0 }, /* SPACE */
- { ISFUNC, (Function *)0x0 }, /* ! */
- { ISFUNC, (Function *)0x0 }, /* " */
- { ISFUNC, (Function *)0x0 }, /* # */
- { ISFUNC, (Function *)0x0 }, /* $ */
- { ISFUNC, (Function *)0x0 }, /* % */
- { ISFUNC, (Function *)0x0 }, /* & */
- { ISFUNC, (Function *)0x0 }, /* ' */
- { ISFUNC, rl_start_kbd_macro }, /* ( */
- { ISFUNC, rl_end_kbd_macro }, /* ) */
- { ISFUNC, (Function *)0x0 }, /* * */
- { ISFUNC, (Function *)0x0 }, /* + */
- { ISFUNC, (Function *)0x0 }, /* , */
- { ISFUNC, (Function *)0x0 }, /* - */
- { ISFUNC, (Function *)0x0 }, /* . */
- { ISFUNC, (Function *)0x0 }, /* / */
-
- /* Regular digits. */
- { ISFUNC, (Function *)0x0 }, /* 0 */
- { ISFUNC, (Function *)0x0 }, /* 1 */
- { ISFUNC, (Function *)0x0 }, /* 2 */
- { ISFUNC, (Function *)0x0 }, /* 3 */
- { ISFUNC, (Function *)0x0 }, /* 4 */
- { ISFUNC, (Function *)0x0 }, /* 5 */
- { ISFUNC, (Function *)0x0 }, /* 6 */
- { ISFUNC, (Function *)0x0 }, /* 7 */
- { ISFUNC, (Function *)0x0 }, /* 8 */
- { ISFUNC, (Function *)0x0 }, /* 9 */
-
- /* A little more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* : */
- { ISFUNC, (Function *)0x0 }, /* ; */
- { ISFUNC, (Function *)0x0 }, /* < */
- { ISFUNC, (Function *)0x0 }, /* = */
- { ISFUNC, (Function *)0x0 }, /* > */
- { ISFUNC, (Function *)0x0 }, /* ? */
- { ISFUNC, (Function *)0x0 }, /* @ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_do_lowercase_version }, /* A */
- { ISFUNC, rl_do_lowercase_version }, /* B */
- { ISFUNC, rl_do_lowercase_version }, /* C */
- { ISFUNC, rl_do_lowercase_version }, /* D */
- { ISFUNC, rl_do_lowercase_version }, /* E */
- { ISFUNC, rl_do_lowercase_version }, /* F */
- { ISFUNC, rl_do_lowercase_version }, /* G */
- { ISFUNC, rl_do_lowercase_version }, /* H */
- { ISFUNC, rl_do_lowercase_version }, /* I */
- { ISFUNC, rl_do_lowercase_version }, /* J */
- { ISFUNC, rl_do_lowercase_version }, /* K */
- { ISFUNC, rl_do_lowercase_version }, /* L */
- { ISFUNC, rl_do_lowercase_version }, /* M */
- { ISFUNC, rl_do_lowercase_version }, /* N */
- { ISFUNC, rl_do_lowercase_version }, /* O */
- { ISFUNC, rl_do_lowercase_version }, /* P */
- { ISFUNC, rl_do_lowercase_version }, /* Q */
- { ISFUNC, rl_do_lowercase_version }, /* R */
- { ISFUNC, rl_do_lowercase_version }, /* S */
- { ISFUNC, rl_do_lowercase_version }, /* T */
- { ISFUNC, rl_do_lowercase_version }, /* U */
- { ISFUNC, rl_do_lowercase_version }, /* V */
- { ISFUNC, rl_do_lowercase_version }, /* W */
- { ISFUNC, rl_do_lowercase_version }, /* X */
- { ISFUNC, rl_do_lowercase_version }, /* Y */
- { ISFUNC, rl_do_lowercase_version }, /* Z */
-
- /* Some more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* [ */
- { ISFUNC, (Function *)0x0 }, /* \ */
- { ISFUNC, (Function *)0x0 }, /* ] */
- { ISFUNC, (Function *)0x0 }, /* ^ */
- { ISFUNC, (Function *)0x0 }, /* _ */
- { ISFUNC, (Function *)0x0 }, /* ` */
-
- /* Lowercase alphabet. */
- { ISFUNC, (Function *)0x0 }, /* a */
- { ISFUNC, (Function *)0x0 }, /* b */
- { ISFUNC, (Function *)0x0 }, /* c */
- { ISFUNC, (Function *)0x0 }, /* d */
- { ISFUNC, rl_call_last_kbd_macro }, /* e */
- { ISFUNC, (Function *)0x0 }, /* f */
- { ISFUNC, (Function *)0x0 }, /* g */
- { ISFUNC, (Function *)0x0 }, /* h */
- { ISFUNC, (Function *)0x0 }, /* i */
- { ISFUNC, (Function *)0x0 }, /* j */
- { ISFUNC, (Function *)0x0 }, /* k */
- { ISFUNC, (Function *)0x0 }, /* l */
- { ISFUNC, (Function *)0x0 }, /* m */
- { ISFUNC, (Function *)0x0 }, /* n */
- { ISFUNC, (Function *)0x0 }, /* o */
- { ISFUNC, (Function *)0x0 }, /* p */
- { ISFUNC, (Function *)0x0 }, /* q */
- { ISFUNC, rl_re_read_init_file }, /* r */
- { ISFUNC, (Function *)0x0 }, /* s */
- { ISFUNC, (Function *)0x0 }, /* t */
- { ISFUNC, (Function *)0x0 }, /* u */
- { ISFUNC, (Function *)0x0 }, /* v */
- { ISFUNC, (Function *)0x0 }, /* w */
- { ISFUNC, (Function *)0x0 }, /* x */
- { ISFUNC, (Function *)0x0 }, /* y */
- { ISFUNC, (Function *)0x0 }, /* z */
-
- /* Final punctuation. */
- { ISFUNC, (Function *)0x0 }, /* { */
- { ISFUNC, (Function *)0x0 }, /* | */
- { ISFUNC, (Function *)0x0 }, /* } */
- { ISFUNC, (Function *)0x0 }, /* ~ */
- { ISFUNC, rl_backward_kill_line } /* RUBOUT */
-};
diff --git a/gnu/usr.bin/gdb/readline/funmap.c b/gnu/usr.bin/gdb/readline/funmap.c
deleted file mode 100644
index 357e716f2003..000000000000
--- a/gnu/usr.bin/gdb/readline/funmap.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* funmap.c -- attach names to functions. */
-
-/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
-
- This file is part of GNU Readline, a library for reading lines
- of text with interactive input and history editing.
-
- Readline is free software; you can 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.
-
- Readline is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Readline; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#define STATIC_MALLOC
-#ifndef STATIC_MALLOC
-extern char *xmalloc (), *xrealloc ();
-#else
-static char *xmalloc (), *xrealloc ();
-#endif
-
-#ifndef FILE
-#include <stdio.h>
-#endif /* FILE */
-
-#include "readline.h"
-
-FUNMAP **funmap = (FUNMAP **)NULL;
-static int funmap_size = 0;
-
-static int just_testing_ar_tmp = 0;
-static int just_testing_ar_tmp_2 = 5;
-int foo_testing_ar;
-
-static int funmap_entry = 0;
-
-static FUNMAP default_funmap[] = {
- { "beginning-of-line", rl_beg_of_line },
- { "backward-char", rl_backward },
- { "delete-char", rl_delete },
- { "end-of-line", rl_end_of_line },
- { "forward-char", rl_forward },
- { "accept-line", rl_newline },
- { "kill-line", rl_kill_line },
- { "clear-screen", rl_clear_screen },
- { "next-history", rl_get_next_history },
- { "previous-history", rl_get_previous_history },
- { "quoted-insert", rl_quoted_insert },
- { "reverse-search-history", rl_reverse_search_history },
- { "forward-search-history", rl_forward_search_history },
- { "transpose-chars", rl_transpose_chars },
- { "unix-line-discard", rl_unix_line_discard },
- { "unix-word-rubout", rl_unix_word_rubout },
- { "yank", rl_yank },
- { "yank-pop", rl_yank_pop },
- { "yank-nth-arg", rl_yank_nth_arg },
- { "backward-delete-char", rl_rubout },
- { "backward-word", rl_backward_word },
- { "kill-word", rl_kill_word },
- { "forward-word", rl_forward_word },
- { "tab-insert", rl_tab_insert },
- { "backward-kill-word", rl_backward_kill_word },
- { "backward-kill-line", rl_backward_kill_line },
- { "transpose-words", rl_transpose_words },
- { "digit-argument", rl_digit_argument },
- { "complete", rl_complete },
- { "possible-completions", rl_possible_completions },
- { "do-lowercase-version", rl_do_lowercase_version },
- { "digit-argument", rl_digit_argument },
- { "universal-argument", rl_universal_argument },
- { "abort", rl_abort },
- { "undo", rl_undo_command },
- { "upcase-word", rl_upcase_word },
- { "downcase-word", rl_downcase_word },
- { "capitalize-word", rl_capitalize_word },
- { "revert-line", rl_revert_line },
- { "beginning-of-history", rl_beginning_of_history },
- { "end-of-history", rl_end_of_history },
- { "self-insert", rl_insert },
- { "start-kbd-macro", rl_start_kbd_macro },
- { "end-kbd-macro", rl_end_kbd_macro },
- { "re-read-init-file", rl_re_read_init_file },
-#ifdef VI_MODE
- { "vi-movement-mode", rl_vi_movement_mode },
- { "vi-insertion-mode", rl_vi_insertion_mode },
- { "vi-arg-digit", rl_vi_arg_digit },
- { "vi-prev-word", rl_vi_prev_word },
- { "vi-next-word", rl_vi_next_word },
- { "vi-char-search", rl_vi_char_search },
- { "vi-editing-mode", rl_vi_editing_mode },
- { "vi-eof-maybe", rl_vi_eof_maybe },
- { "vi-append-mode", rl_vi_append_mode },
- { "vi-put", rl_vi_put },
- { "vi-append-eol", rl_vi_append_eol },
- { "vi-insert-beg", rl_vi_insert_beg },
- { "vi-delete", rl_vi_delete },
- { "vi-comment", rl_vi_comment },
- { "vi-first-print", rl_vi_first_print },
- { "vi-fword", rl_vi_fword },
- { "vi-fWord", rl_vi_fWord },
- { "vi-bword", rl_vi_bword },
- { "vi-bWord", rl_vi_bWord },
- { "vi-eword", rl_vi_eword },
- { "vi-eWord", rl_vi_eWord },
- { "vi-end-word", rl_vi_end_word },
- { "vi-change-case", rl_vi_change_case },
- { "vi-match", rl_vi_match },
- { "vi-bracktype", rl_vi_bracktype },
- { "vi-change-char", rl_vi_change_char },
- { "vi-yank-arg", rl_vi_yank_arg },
- { "vi-search", rl_vi_search },
- { "vi-search-again", rl_vi_search_again },
- { "vi-dosearch", rl_vi_dosearch },
- { "vi-subst", rl_vi_subst },
- { "vi-overstrike", rl_vi_overstrike },
- { "vi-overstrike-delete", rl_vi_overstrike_delete },
- { "vi-replace, ", rl_vi_replace },
- { "vi-column", rl_vi_column },
- { "vi-delete-to", rl_vi_delete_to },
- { "vi-change-to", rl_vi_change_to },
- { "vi-yank-to", rl_vi_yank_to },
- { "vi-complete", rl_vi_complete },
-#endif /* VI_MODE */
-
- {(char *)NULL, (Function *)NULL }
-};
-
-rl_add_funmap_entry (name, function)
- char *name;
- Function *function;
-{
- if (funmap_entry + 2 >= funmap_size)
- if (!funmap)
- funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *));
- else
- funmap =
- (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *));
-
- funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
- funmap[funmap_entry]->name = name;
- funmap[funmap_entry]->function = function;
-
- funmap[++funmap_entry] = (FUNMAP *)NULL;
-}
-
-static int funmap_initialized = 0;
-
-/* Make the funmap contain all of the default entries. */
-rl_initialize_funmap ()
-{
- register int i;
-
- if (funmap_initialized)
- return;
-
- for (i = 0; default_funmap[i].name; i++)
- rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
-
- funmap_initialized = 1;
-}
-
-/* Things that mean `Control'. */
-char *possible_control_prefixes[] = {
- "Control-", "C-", "CTRL-", (char *)NULL
-};
-
-char *possible_meta_prefixes[] = {
- "Meta", "M-", (char *)NULL
-};
-
-#ifdef STATIC_MALLOC
-
-/* **************************************************************** */
-/* */
-/* xmalloc and xrealloc () */
-/* */
-/* **************************************************************** */
-
-static char *
-xmalloc (bytes)
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)malloc (bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static char *
-xrealloc (pointer, bytes)
- char *pointer;
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)realloc (pointer, bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static
-memory_error_and_abort ()
-{
- fprintf (stderr, "history: Out of virtual memory!\n");
- abort ();
-}
-#endif /* STATIC_MALLOC */
diff --git a/gnu/usr.bin/gdb/readline/history.c b/gnu/usr.bin/gdb/readline/history.c
deleted file mode 100644
index 7087718edc30..000000000000
--- a/gnu/usr.bin/gdb/readline/history.c
+++ /dev/null
@@ -1,1462 +0,0 @@
-/* History.c -- standalone history library */
-
-/* Copyright (C) 1989 Free Software Foundation, Inc.
-
- This file contains the GNU History Library (the Library), a set of
- routines for managing the text of previously typed lines.
-
- The 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 1, or (at your option)
- any later version.
-
- The 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.
-
- The GNU General Public License is often shipped with GNU software, and
- is generally kept in a file called COPYING or LICENSE. If you do not
- have a copy of the license, write to the Free Software Foundation,
- 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* The goal is to make the implementation transparent, so that you
- don't have to know what data types are used, just what functions
- you can call. I think I have done that. */
-
-/* Remove these declarations when we have a complete libgnu.a. */
-#define STATIC_MALLOC
-#ifndef STATIC_MALLOC
-extern char *xmalloc (), *xrealloc ();
-#else
-static char *xmalloc (), *xrealloc ();
-#endif
-
-#include <stdio.h>
-
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else
-#if defined (sparc) && defined (sun)
-#include <alloca.h>
-#else
-extern char *alloca ();
-#endif
-#endif
-
-#include "history.h"
-
-#ifndef savestring
-#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
-#endif
-
-#ifndef whitespace
-#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
-#endif
-
-#ifndef digit
-#define digit(c) ((c) >= '0' && (c) <= '9')
-#endif
-
-#ifndef member
-#define member(c, s) ((c) ? index ((s), (c)) : 0)
-#endif
-
-/* **************************************************************** */
-/* */
-/* History functions */
-/* */
-/* **************************************************************** */
-
-/* An array of HIST_ENTRY. This is where we store the history. */
-static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
-
-/* Non-zero means that we have enforced a limit on the amount of
- history that we save. */
-static int history_stifled = 0;
-
-/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
- entries to remember. */
-static int max_input_history;
-
-/* The current location of the interactive history pointer. Just makes
- life easier for outside callers. */
-static int history_offset = 0;
-
-/* The number of strings currently stored in the input_history list. */
-static int history_length = 0;
-
-/* The current number of slots allocated to the input_history. */
-static int history_size = 0;
-
-/* The number of slots to increase the_history by. */
-#define DEFAULT_HISTORY_GROW_SIZE 50
-
-/* The character that represents the start of a history expansion
- request. This is usually `!'. */
-char history_expansion_char = '!';
-
-/* The character that invokes word substitution if found at the start of
- a line. This is usually `^'. */
-char history_subst_char = '^';
-
-/* During tokenization, if this character is seen as the first character
- of a word, then it, and all subsequent characters upto a newline are
- ignored. For a Bourne shell, this should be '#'. Bash special cases
- the interactive comment character to not be a comment delimiter. */
-char history_comment_char = '\0';
-
-/* The list of characters which inhibit the expansion of text if found
- immediately following history_expansion_char. */
-char *history_no_expand_chars = " \t\n\r=";
-
-/* The logical `base' of the history array. It defaults to 1. */
-int history_base = 1;
-
-/* Begin a session in which the history functions might be used. This
- initializes interactive variables. */
-void
-using_history ()
-{
- history_offset = history_length;
-}
-
-/* Place STRING at the end of the history list. The data field
- is set to NULL. */
-void
-add_history (string)
- char *string;
-{
- HIST_ENTRY *temp;
-
- if (history_stifled && (history_length == max_input_history)) {
- register int i;
-
- /* If the history is stifled, and history_length is zero,
- and it equals max_input_history, we don't save items. */
- if (!history_length)
- return;
-
- /* If there is something in the slot, then remove it. */
- if (the_history[0]) {
- free (the_history[0]->line);
- free (the_history[0]);
- }
-
- for (i = 0; i < history_length; i++)
- the_history[i] = the_history[i + 1];
-
- history_base++;
-
- } else {
-
- if (!history_size) {
- the_history =
- (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
- * sizeof (HIST_ENTRY *));
- history_length = 1;
-
- } else {
- if (history_length == (history_size - 1)) {
- the_history =
- (HIST_ENTRY **)xrealloc (the_history,
- ((history_size += DEFAULT_HISTORY_GROW_SIZE)
- * sizeof (HIST_ENTRY *)));
- }
- history_length++;
- }
- }
-
- temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
- temp->line = savestring (string);
- temp->data = (char *)NULL;
-
- the_history[history_length] = (HIST_ENTRY *)NULL;
- the_history[history_length - 1] = temp;
-}
-
-/* Make the history entry at WHICH have LINE and DATA. This returns
- the old entry so you can dispose of the data. In the case of an
- invalid WHICH, a NULL pointer is returned. */
-HIST_ENTRY *
-replace_history_entry (which, line, data)
- int which;
- char *line;
- char *data;
-{
- HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
- HIST_ENTRY *old_value;
-
- if (which >= history_length)
- return ((HIST_ENTRY *)NULL);
-
- old_value = the_history[which];
-
- temp->line = savestring (line);
- temp->data = data;
- the_history[which] = temp;
-
- return (old_value);
-}
-
-/* Returns the magic number which says what history element we are
- looking at now. In this implementation, it returns history_offset. */
-int
-where_history ()
-{
- return (history_offset);
-}
-
-/* Search the history for STRING, starting at history_offset.
- If DIRECTION < 0, then the search is through previous entries,
- else through subsequent. If the string is found, then
- current_history () is the history entry, and the value of this function
- is the offset in the line of that history entry that the string was
- found in. Otherwise, nothing is changed, and a -1 is returned. */
-int
-history_search (string, direction)
- char *string;
- int direction;
-{
- register int i = history_offset;
- register int reverse = (direction < 0);
- register char *line;
- register int index;
- int string_len = strlen (string);
-
- /* Take care of trivial cases first. */
-
- if (!history_length || (i == history_length) && !reverse)
- return (-1);
-
- if (reverse && (i == history_length))
- i--;
-
- while (1)
- {
- /* Search each line in the history list for STRING. */
-
- /* At limit for direction? */
- if ((reverse && i < 0) ||
- (!reverse && i == history_length))
- return (-1);
-
- line = the_history[i]->line;
- index = strlen (line);
-
- /* If STRING is longer than line, no match. */
- if (string_len > index)
- goto next_line;
-
- /* Do the actual search. */
- if (reverse)
- {
- index -= string_len;
-
- while (index >= 0)
- {
- if (strncmp (string, line + index, string_len) == 0)
- {
- history_offset = i;
- return (index);
- }
- index--;
- }
- }
- else
- {
- register int limit = (string_len - index) + 1;
- index = 0;
-
- while (index < limit)
- {
- if (strncmp (string, line + index, string_len) == 0)
- {
- history_offset = i;
- return (index);
- }
- index++;
- }
- }
- next_line:
- if (reverse)
- i--;
- else
- i++;
- }
-}
-
-/* Remove history element WHICH from the history. The removed
- element is returned to you so you can free the line, data,
- and containing structure. */
-HIST_ENTRY *
-remove_history (which)
- int which;
-{
- HIST_ENTRY *return_value;
-
- if (which >= history_length || !history_length)
- return_value = (HIST_ENTRY *)NULL;
- else
- {
- register int i;
- return_value = the_history[which];
-
- for (i = which; i < history_length; i++)
- the_history[i] = the_history[i + 1];
-
- history_length--;
- }
- return (return_value);
-}
-
-/* Stifle the history list, remembering only MAX number of lines. */
-void
-stifle_history (max)
- int max;
-{
- if (history_length > max)
- {
- register int i, j;
-
- /* This loses because we cannot free the data. */
- for (i = 0; i < (history_length - max); i++)
- {
- free (the_history[i]->line);
- free (the_history[i]);
- }
- history_base = i;
- for (j = 0, i = history_length - max; j < max; i++, j++)
- the_history[j] = the_history[i];
- the_history[j] = (HIST_ENTRY *)NULL;
- history_length = j;
- }
- history_stifled = 1;
- max_input_history = max;
-}
-
-/* Stop stifling the history. This returns the previous amount the history
- was stifled by. The value is positive if the history was stifled, negative
- if it wasn't. */
-int
-unstifle_history ()
-{
- int result = max_input_history;
- if (history_stifled)
- {
- result = - result;
- history_stifled = 0;
- }
- return (result);
-}
-
-/* Return the string that should be used in the place of this
- filename. This only matters when you don't specify the
- filename to read_history (), or write_history (). */
-static char *
-history_filename (filename)
- char *filename;
-{
- char *return_val = filename ? savestring (filename) : (char *)NULL;
-
- if (!return_val)
- {
- char *home = (char *)getenv ("HOME");
- if (!home) home = ".";
- return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
- strcpy (return_val, home);
- strcat (return_val, "/");
- strcat (return_val, ".history");
- }
- return (return_val);
-}
-
-/* What to use until the line gets too big. */
-#define TYPICAL_LINE_SIZE 2048
-
-/* Add the contents of FILENAME to the history list, a line at a time.
- If FILENAME is NULL, then read from ~/.history. Returns 0 if
- successful, or errno if not. */
-int
-read_history (filename)
- char *filename;
-{
- char *input = history_filename (filename);
- FILE *file = fopen (input, "r");
- char *line = (char *)xmalloc (TYPICAL_LINE_SIZE);
- int line_size = TYPICAL_LINE_SIZE;
- int done = 0;
-
- if (!file)
- {
- extern int errno;
- free (line);
- return (errno);
- }
-
- while (!done)
- {
- int c;
- int i;
-
- i = 0;
- while (!(done = ((c = getc (file)) == EOF)))
- {
- if (c == '\n')
- break;
-
- line [i++] = c;
- if (i == line_size)
- line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE);
- }
- line[i] = '\0';
- if (line[0])
- add_history (line);
- }
- free (line);
- fclose (file);
- return (0);
-}
-
-/* Overwrite FILENAME with the current history. If FILENAME is NULL,
- then write the history list to ~/.history. Values returned
- are as in read_history ().*/
-int
-write_history (filename)
- char *filename;
-{
- extern int errno;
- char *output = history_filename (filename);
- FILE *file = fopen (output, "w");
- register int i;
-
- if (!file) return (errno);
- if (!history_length) return (0);
-
- for (i = 0; i < history_length; i++)
- fprintf (file, "%s\n", the_history[i]->line);
-
- fclose (file);
- return (0);
-}
-
-/* Return the history entry at the current position, as determined by
- history_offset. If there is no entry there, return a NULL pointer. */
-HIST_ENTRY *
-current_history ()
-{
- if ((history_offset == history_length) || !the_history)
- return ((HIST_ENTRY *)NULL);
- else
- return (the_history[history_offset]);
-}
-
-/* Back up history_offset to the previous history entry, and return
- a pointer to that entry. If there is no previous entry then return
- a NULL pointer. */
-HIST_ENTRY *
-previous_history ()
-{
- if (!history_offset)
- return ((HIST_ENTRY *)NULL);
- else
- return (the_history[--history_offset]);
-}
-
-/* Move history_offset forward to the next history entry, and return
- a pointer to that entry. If there is no next entry then return a
- NULL pointer. */
-HIST_ENTRY *
-next_history ()
-{
- if (history_offset == history_length)
- return ((HIST_ENTRY *)NULL);
- else
- return (the_history[++history_offset]);
-}
-
-/* Return the current history array. The caller has to be carefull, since this
- is the actual array of data, and could be bashed or made corrupt easily.
- The array is terminated with a NULL pointer. */
-HIST_ENTRY **
-history_list ()
-{
- return (the_history);
-}
-
-/* Return the history entry which is logically at OFFSET in the history array.
- OFFSET is relative to history_base. */
-HIST_ENTRY *
-history_get (offset)
- int offset;
-{
- int index = offset - history_base;
-
- if (index >= history_length ||
- index < 0 ||
- !the_history)
- return ((HIST_ENTRY *)NULL);
- return (the_history[index]);
-}
-
-/* Search for STRING in the history list. DIR is < 0 for searching
- backwards. POS is an absolute index into the history list at
- which point to begin searching. */
-int
-history_search_pos (string, dir, pos)
- char *string;
- int dir, pos;
-{
- int ret, old = where_history ();
- history_set_pos (pos);
- if (history_search (string, dir) == -1)
- {
- history_set_pos (old);
- return (-1);
- }
- ret = where_history ();
- history_set_pos (old);
- return ret;
-}
-
-/* Make the current history item be the one at POS, an absolute index.
- Returns zero if POS is out of range, else non-zero. */
-int
-history_set_pos (pos)
- int pos;
-{
- if (pos > history_length || pos < 0 || !the_history)
- return (0);
- history_offset = pos;
- return (1);
-}
-
-
-/* **************************************************************** */
-/* */
-/* History Expansion */
-/* */
-/* **************************************************************** */
-
-/* Hairy history expansion on text, not tokens. This is of general
- use, and thus belongs in this library. */
-
-/* The last string searched for in a !?string? search. */
-static char *search_string = (char *)NULL;
-
-/* Return the event specified at TEXT + OFFSET modifying OFFSET to
- point to after the event specifier. Just a pointer to the history
- line is returned; NULL is returned in the event of a bad specifier.
- You pass STRING with *INDEX equal to the history_expansion_char that
- begins this specification.
- DELIMITING_QUOTE is a character that is allowed to end the string
- specification for what to search for in addition to the normal
- characters `:', ` ', `\t', `\n', and sometimes `?'.
- So you might call this function like:
- line = get_history_event ("!echo:p", &index, 0); */
-char *
-get_history_event (string, caller_index, delimiting_quote)
- char *string;
- int *caller_index;
- int delimiting_quote;
-{
- register int i = *caller_index;
- int which, sign = 1;
- HIST_ENTRY *entry;
-
- /* The event can be specified in a number of ways.
-
- !! the previous command
- !n command line N
- !-n current command-line minus N
- !str the most recent command starting with STR
- !?str[?]
- the most recent command containing STR
-
- All values N are determined via HISTORY_BASE. */
-
- if (string[i] != history_expansion_char)
- return ((char *)NULL);
-
- /* Move on to the specification. */
- i++;
-
- /* Handle !! case. */
- if (string[i] == history_expansion_char)
- {
- i++;
- which = history_base + (history_length - 1);
- *caller_index = i;
- goto get_which;
- }
-
- /* Hack case of numeric line specification. */
- read_which:
- if (string[i] == '-')
- {
- sign = -1;
- i++;
- }
-
- if (digit (string[i]))
- {
- int start = i;
-
- /* Get the extent of the digits. */
- for (; digit (string[i]); i++);
-
- /* Get the digit value. */
- sscanf (string + start, "%d", &which);
-
- *caller_index = i;
-
- if (sign < 0)
- which = (history_length + history_base) - which;
-
- get_which:
- if (entry = history_get (which))
- return (entry->line);
-
- return ((char *)NULL);
- }
-
- /* This must be something to search for. If the spec begins with
- a '?', then the string may be anywhere on the line. Otherwise,
- the string must be found at the start of a line. */
- {
- int index;
- char *temp;
- int substring_okay = 0;
-
- if (string[i] == '?')
- {
- substring_okay++;
- i++;
- }
-
- for (index = i; string[i]; i++)
- if (whitespace (string[i]) ||
- string[i] == '\n' ||
- string[i] == ':' ||
- (substring_okay && string[i] == '?') ||
- string[i] == delimiting_quote)
- break;
-
- temp = (char *)alloca (1 + (i - index));
- strncpy (temp, &string[index], (i - index));
- temp[i - index] = '\0';
-
- if (string[i] == '?')
- i++;
-
- *caller_index = i;
-
- search_again:
-
- index = history_search (temp, -1);
-
- if (index < 0)
- search_lost:
- {
- history_offset = history_length;
- return ((char *)NULL);
- }
-
- if (index == 0 || substring_okay ||
- (strncmp (temp, the_history[history_offset]->line,
- strlen (temp)) == 0))
- {
- search_won:
- entry = current_history ();
- history_offset = history_length;
-
- /* If this was a substring search, then remember the string that
- we matched for word substitution. */
- if (substring_okay)
- {
- if (search_string)
- free (search_string);
- search_string = savestring (temp);
- }
-
- return (entry->line);
- }
-
- if (history_offset)
- history_offset--;
- else
- goto search_lost;
-
- goto search_again;
- }
-}
-
-/* Expand the string STRING, placing the result into OUTPUT, a pointer
- to a string. Returns:
-
- 0) If no expansions took place (or, if the only change in
- the text was the de-slashifying of the history expansion
- character)
- 1) If expansions did take place
- -1) If there was an error in expansion.
-
- If an error ocurred in expansion, then OUTPUT contains a descriptive
- error message. */
-int
-history_expand (string, output)
- char *string;
- char **output;
-{
- register int j, l = strlen (string);
- int i, word_spec_error = 0;
- int cc, modified = 0;
- char *word_spec, *event;
- int starting_index, only_printing = 0, substitute_globally = 0;
-
- char *get_history_word_specifier (), *rindex ();
-
- /* The output string, and its length. */
- int len = 0;
- char *result = (char *)NULL;
-
- /* Used in add_string; */
- char *temp, tt[2], tbl[3];
-
- /* Prepare the buffer for printing error messages. */
- result = (char *)xmalloc (len = 255);
-
- result[0] = tt[1] = tbl[2] = '\0';
- tbl[0] = '\\';
- tbl[1] = history_expansion_char;
-
- /* Grovel the string. Only backslash can quote the history escape
- character. We also handle arg specifiers. */
-
- /* Before we grovel forever, see if the history_expansion_char appears
- anywhere within the text. */
-
- /* The quick substitution character is a history expansion all right. That
- is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
- that is the substitution that we do. */
- if (string[0] == history_subst_char)
- {
- char *format_string = (char *)alloca (10 + strlen (string));
-
- sprintf (format_string, "%c%c:s%s",
- history_expansion_char, history_expansion_char,
- string);
- string = format_string;
- l += 4;
- goto grovel;
- }
-
- /* If not quick substitution, still maybe have to do expansion. */
-
- /* `!' followed by one of the characters in history_no_expand_chars
- is NOT an expansion. */
- for (i = 0; string[i]; i++)
- if (string[i] == history_expansion_char)
- if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
- continue;
- else
- goto grovel;
-
- free (result);
- *output = savestring (string);
- return (0);
-
- grovel:
-
- for (i = j = 0; i < l; i++)
- {
- int tchar = string[i];
- if (tchar == history_expansion_char)
- tchar = -3;
-
- switch (tchar)
- {
- case '\\':
- if (string[i + 1] == history_expansion_char)
- {
- i++;
- temp = tbl;
- goto do_add;
- }
- else
- goto add_char;
-
- /* case history_expansion_char: */
- case -3:
- starting_index = i + 1;
- cc = string[i + 1];
-
- /* If the history_expansion_char is followed by one of the
- characters in history_no_expand_chars, then it is not a
- candidate for expansion of any kind. */
- if (member (cc, history_no_expand_chars))
- goto add_char;
-
- /* There is something that is listed as a `word specifier' in csh
- documentation which means `the expanded text to this point'.
- That is not a word specifier, it is an event specifier. */
-
- if (cc == '#')
- goto hack_pound_sign;
-
- /* If it is followed by something that starts a word specifier,
- then !! is implied as the event specifier. */
-
- if (member (cc, ":$*%^"))
- {
- char fake_s[2];
- int fake_i = 0;
- i++;
- fake_s[0] = fake_s[1] = history_expansion_char;
- fake_s[2] = '\0';
- event = get_history_event (fake_s, &fake_i);
- }
- else
- {
- int quoted_search_delimiter = 0;
-
- /* If the character before this `!' is a double or single
- quote, then this expansion takes place inside of the
- quoted string. If we have to search for some text ("!foo"),
- allow the delimiter to end the search string. */
- if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
- quoted_search_delimiter = string[i - 1];
-
- event = get_history_event (string, &i, quoted_search_delimiter);
- }
-
- if (!event)
- event_not_found:
- {
- int l = 1 + (i - starting_index);
-
- temp = (char *)alloca (1 + l);
- strncpy (temp, string + starting_index, l);
- temp[l - 1] = 0;
- sprintf (result, "%s: %s.", temp,
- word_spec_error ? "Bad word specifier" : "Event not found");
- error_exit:
- *output = result;
- return (-1);
- }
-
- /* If a word specifier is found, then do what that requires. */
- starting_index = i;
-
- word_spec = get_history_word_specifier (string, event, &i);
-
- /* There is no such thing as a `malformed word specifier'. However,
- it is possible for a specifier that has no match. In that case,
- we complain. */
- if (word_spec == (char *)-1)
- bad_word_spec:
- {
- word_spec_error++;
- goto event_not_found;
- }
-
- /* If no word specifier, than the thing of interest was the event. */
- if (!word_spec)
- temp = event;
- else
- {
- temp = (char *)alloca (1 + strlen (word_spec));
- strcpy (temp, word_spec);
- free (word_spec);
- }
-
- /* Perhaps there are other modifiers involved. Do what they say. */
-
- hack_specials:
-
- if (string[i] == ':')
- {
- char *tstr;
-
- switch (string[i + 1])
- {
- /* :p means make this the last executed line. So we
- return an error state after adding this line to the
- history. */
- case 'p':
- only_printing++;
- goto next_special;
-
- /* :t discards all but the last part of the pathname. */
- case 't':
- tstr = rindex (temp, '/');
- if (tstr)
- temp = ++tstr;
- goto next_special;
-
- /* :h discards the last part of a pathname. */
- case 'h':
- tstr = rindex (temp, '/');
- if (tstr)
- *tstr = '\0';
- goto next_special;
-
- /* :r discards the suffix. */
- case 'r':
- tstr = rindex (temp, '.');
- if (tstr)
- *tstr = '\0';
- goto next_special;
-
- /* :e discards everything but the suffix. */
- case 'e':
- tstr = rindex (temp, '.');
- if (tstr)
- temp = tstr;
- goto next_special;
-
- /* :s/this/that substitutes `this' for `that'. */
- /* :gs/this/that substitutes `this' for `that' globally. */
- case 'g':
- if (string[i + 2] == 's')
- {
- i++;
- substitute_globally = 1;
- goto substitute;
- }
- else
-
- case 's':
- substitute:
- {
- char *this, *that, *new_event;
- int delimiter = 0;
- int si, l_this, l_that, l_temp = strlen (temp);
-
- if (i + 2 < strlen (string))
- delimiter = string[i + 2];
-
- if (!delimiter)
- break;
-
- i += 3;
-
- /* Get THIS. */
- for (si = i; string[si] && string[si] != delimiter; si++);
- l_this = (si - i);
- this = (char *)alloca (1 + l_this);
- strncpy (this, string + i, l_this);
- this[l_this] = '\0';
-
- i = si;
- if (string[si])
- i++;
-
- /* Get THAT. */
- for (si = i; string[si] && string[si] != delimiter; si++);
- l_that = (si - i);
- that = (char *)alloca (1 + l_that);
- strncpy (that, string + i, l_that);
- that[l_that] = '\0';
-
- i = si;
- if (string[si]) i++;
-
- /* Ignore impossible cases. */
- if (l_this > l_temp)
- goto cant_substitute;
-
- /* Find the first occurrence of THIS in TEMP. */
- si = 0;
- for (; (si + l_this) <= l_temp; si++)
- if (strncmp (temp + si, this, l_this) == 0)
- {
- new_event =
- (char *)alloca (1 + (l_that - l_this) + l_temp);
- strncpy (new_event, temp, si);
- strncpy (new_event + si, that, l_that);
- strncpy (new_event + si + l_that,
- temp + si + l_this,
- l_temp - (si + l_this));
- new_event[(l_that - l_this) + l_temp] = '\0';
- temp = new_event;
-
- if (substitute_globally)
- {
- si += l_that;
- l_temp = strlen (temp);
- substitute_globally++;
- continue;
- }
-
- goto hack_specials;
- }
-
- cant_substitute:
-
- if (substitute_globally > 1)
- {
- substitute_globally = 0;
- goto hack_specials;
- }
-
- goto event_not_found;
- }
-
- /* :# is the line so far. Note that we have to
- alloca () it since RESULT could be realloc ()'ed
- below in add_string. */
- case '#':
- hack_pound_sign:
- if (result)
- {
- temp = (char *)alloca (1 + strlen (result));
- strcpy (temp, result);
- }
- else
- temp = "";
-
- next_special:
- i += 2;
- goto hack_specials;
- }
-
- }
- /* Believe it or not, we have to back the pointer up by one. */
- --i;
- goto add_string;
-
- /* A regular character. Just add it to the output string. */
- default:
- add_char:
- tt[0] = string[i];
- temp = tt;
- goto do_add;
-
- add_string:
- modified++;
-
- do_add:
- j += strlen (temp);
- while (j > len)
- result = (char *)xrealloc (result, (len += 255));
-
- strcpy (result + (j - strlen (temp)), temp);
- }
- }
-
- *output = result;
-
- if (only_printing)
- {
- add_history (result);
- return (-1);
- }
-
- return (modified != 0);
-}
-
-/* Return a consed string which is the word specified in SPEC, and found
- in FROM. NULL is returned if there is no spec. -1 is returned if
- the word specified cannot be found. CALLER_INDEX is the offset in
- SPEC to start looking; it is updated to point to just after the last
- character parsed. */
-char *
-get_history_word_specifier (spec, from, caller_index)
- char *spec, *from;
- int *caller_index;
-{
- register int i = *caller_index;
- int first, last;
- int expecting_word_spec = 0;
- char *history_arg_extract ();
-
- /* The range of words to return doesn't exist yet. */
- first = last = 0;
-
- /* If we found a colon, then this *must* be a word specification. If
- it isn't, then it is an error. */
- if (spec[i] == ':')
- i++, expecting_word_spec++;
-
- /* Handle special cases first. */
-
- /* `%' is the word last searched for. */
- if (spec[i] == '%')
- {
- *caller_index = i + 1;
- if (search_string)
- return (savestring (search_string));
- else
- return (savestring (""));
- }
-
- /* `*' matches all of the arguments, but not the command. */
- if (spec[i] == '*')
- {
- *caller_index = i + 1;
- return (history_arg_extract (1, '$', from));
- }
-
- /* `$' is last arg. */
- if (spec[i] == '$')
- {
- *caller_index = i + 1;
- return (history_arg_extract ('$', '$', from));
- }
-
- /* Try to get FIRST and LAST figured out. */
- if (spec[i] == '-' || spec[i] == '^')
- {
- first = 1;
- goto get_last;
- }
-
- get_first:
- if (digit (spec[i]) && expecting_word_spec)
- {
- sscanf (spec + i, "%d", &first);
- for (; digit (spec[i]); i++);
- }
- else
- return ((char *)NULL);
-
- get_last:
- if (spec[i] == '^')
- {
- i++;
- last = 1;
- goto get_args;
- }
-
- if (spec[i] != '-')
- {
- last = first;
- goto get_args;
- }
-
- i++;
-
- if (digit (spec[i]))
- {
- sscanf (spec + i, "%d", &last);
- for (; digit (spec[i]); i++);
- }
- else
- if (spec[i] == '$')
- {
- i++;
- last = '$';
- }
-
- get_args:
- {
- char *result = (char *)NULL;
-
- *caller_index = i;
-
- if (last >= first)
- result = history_arg_extract (first, last, from);
-
- if (result)
- return (result);
- else
- return ((char *)-1);
- }
-}
-
-/* Extract the args specified, starting at FIRST, and ending at LAST.
- The args are taken from STRING. */
-char *
-history_arg_extract (first, last, string)
- int first, last;
- char *string;
-{
- register int i, len;
- char *result = (char *)NULL;
- int size = 0, offset = 0;
-
- char **history_tokenize (), **list;
-
- if (!(list = history_tokenize (string)))
- return ((char *)NULL);
-
- for (len = 0; list[len]; len++);
-
- if (last == '$')
- last = len - 1;
-
- if (first == '$')
- first = len - 1;
-
- last++;
-
- if (first > len || last > len)
- result = ((char *)NULL);
- else {
- for (i = first; i < last; i++)
- {
- int l = strlen (list[i]);
-
- if (!result)
- result = (char *)xmalloc ((size = (2 + l)));
- else
- result = (char *)xrealloc (result, (size += (2 + l)));
- strcpy (result + offset, list[i]);
- offset += l;
- if (i + 1 < last)
- {
- strcpy (result + offset, " ");
- offset++;
- }
- }
- }
-
- for (i = 0; i < len; i++)
- free (list[i]);
-
- free (list);
-
- return (result);
-}
-
-#define slashify_in_quotes "\\`\"$"
-
-/* Return an array of tokens, much as the shell might. The tokens are
- parsed out of STRING. */
-char **
-history_tokenize (string)
- char *string;
-{
- char **result = (char **)NULL;
- register int i, start, result_index, size;
- int len;
-
- i = result_index = size = 0;
-
- /* Get a token, and stuff it into RESULT. The tokens are split
- exactly where the shell would split them. */
- get_token:
-
- /* Skip leading whitespace. */
- for (; string[i] && whitespace(string[i]); i++);
-
- start = i;
-
- if (!string[i] || string[i] == history_comment_char)
- return (result);
-
- if (member (string[i], "()\n")) {
- i++;
- goto got_token;
- }
-
- if (member (string[i], "<>;&|")) {
- int peek = string[i + 1];
-
- if (peek == string[i]) {
- if (peek == '<') {
- if (string[1 + 2] == '-')
- i++;
- i += 2;
- goto got_token;
- }
-
- if (member (peek, ">:&|")) {
- i += 2;
- goto got_token;
- }
- } else {
- if ((peek == '&' &&
- (string[i] == '>' || string[i] == '<')) ||
- ((peek == '>') &&
- (string[i] == '&'))) {
- i += 2;
- goto got_token;
- }
- }
- i++;
- goto got_token;
- }
-
- /* Get word from string + i; */
- {
- int delimiter = 0;
-
- if (member (string[i], "\"'`"))
- delimiter = string[i++];
-
- for (;string[i]; i++) {
-
- if (string[i] == '\\') {
-
- if (string[i + 1] == '\n') {
- i++;
- continue;
- } else {
- if (delimiter != '\'')
- if ((delimiter != '"') ||
- (member (string[i], slashify_in_quotes))) {
- i++;
- continue;
- }
- }
- }
-
- if (delimiter && string[i] == delimiter) {
- delimiter = 0;
- continue;
- }
-
- if (!delimiter && (member (string[i], " \t\n;&()|<>")))
- goto got_token;
-
- if (!delimiter && member (string[i], "\"'`")) {
- delimiter = string[i];
- continue;
- }
- }
- got_token:
-
- len = i - start;
- if (result_index + 2 >= size) {
- if (!size)
- result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
- else
- result =
- (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
- }
- result[result_index] = (char *)xmalloc (1 + len);
- strncpy (result[result_index], string + start, len);
- result[result_index][len] = '\0';
- result_index++;
- result[result_index] = (char *)NULL;
- }
- if (string[i])
- goto get_token;
-
- return (result);
-}
-
-#ifdef STATIC_MALLOC
-
-/* **************************************************************** */
-/* */
-/* xmalloc and xrealloc () */
-/* */
-/* **************************************************************** */
-
-static char *
-xmalloc (bytes)
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)malloc (bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static char *
-xrealloc (pointer, bytes)
- char *pointer;
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)realloc (pointer, bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static
-memory_error_and_abort ()
-{
- fprintf (stderr, "history: Out of virtual memory!\n");
- abort ();
-}
-#endif /* STATIC_MALLOC */
-
-
-/* **************************************************************** */
-/* */
-/* Test Code */
-/* */
-/* **************************************************************** */
-#ifdef TEST
-main ()
-{
- char line[1024], *t;
- int done = 0;
-
- line[0] = 0;
-
- while (!done)
- {
- fprintf (stdout, "history%% ");
- t = gets (line);
-
- if (!t)
- strcpy (line, "quit");
-
- if (line[0])
- {
- char *expansion;
- int result;
-
- using_history ();
-
- result = history_expand (line, &expansion);
- strcpy (line, expansion);
- free (expansion);
- if (result)
- fprintf (stderr, "%s\n", line);
-
- if (result < 0)
- continue;
-
- add_history (line);
- }
-
- if (strcmp (line, "quit") == 0) done = 1;
- if (strcmp (line, "save") == 0) write_history (0);
- if (strcmp (line, "read") == 0) read_history (0);
- if (strcmp (line, "list") == 0)
- {
- register HIST_ENTRY **the_list = history_list ();
- register int i;
-
- if (the_list)
- for (i = 0; the_list[i]; i++)
- fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
- }
- if (strncmp (line, "delete", strlen ("delete")) == 0)
- {
- int which;
- if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
- {
- HIST_ENTRY *entry = remove_history (which);
- if (!entry)
- fprintf (stderr, "No such entry %d\n", which);
- else
- {
- free (entry->line);
- free (entry);
- }
- }
- else
- {
- fprintf (stderr, "non-numeric arg given to `delete'\n");
- }
- }
- }
-}
-
-#endif /* TEST */
-
-/*
-* Local variables:
-* compile-command: "gcc -g -DTEST -o history history.c"
-* end:
-*/
diff --git a/gnu/usr.bin/gdb/readline/history.h b/gnu/usr.bin/gdb/readline/history.h
deleted file mode 100644
index 0bac2092079e..000000000000
--- a/gnu/usr.bin/gdb/readline/history.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* History.h -- the names of functions that you can call in history. */
-
-typedef struct _hist_entry {
- char *line;
- char *data;
-} HIST_ENTRY;
-
-/* For convenience only. You set this when interpreting history commands.
- It is the logical offset of the first history element. */
-extern int history_base;
-
-/* Begin a session in which the history functions might be used. This
- just initializes the interactive variables. */
-extern void using_history ();
-
-/* Place STRING at the end of the history list.
- The associated data field (if any) is set to NULL. */
-extern void add_history ();
-
-/* Returns the number which says what history element we are now
- looking at. */
-extern int where_history ();
-
-/* Set the position in the history list to POS. */
-int history_set_pos ();
-
-/* Search for STRING in the history list, starting at POS, an
- absolute index into the list. DIR, if negative, says to search
- backwards from POS, else forwards.
- Returns the absolute index of the history element where STRING
- was found, or -1 otherwise. */
-extern int history_search_pos ();
-
-/* A reasonably useless function, only here for completeness. WHICH
- is the magic number that tells us which element to delete. The
- elements are numbered from 0. */
-extern HIST_ENTRY *remove_history ();
-
-/* Stifle the history list, remembering only MAX number of entries. */
-extern void stifle_history ();
-
-/* Stop stifling the history. This returns the previous amount the
- history was stifled by. The value is positive if the history was
- stifled, negative if it wasn't. */
-extern int unstifle_history ();
-
-/* Add the contents of FILENAME to the history list, a line at a time.
- If FILENAME is NULL, then read from ~/.history. Returns 0 if
- successful, or errno if not. */
-extern int read_history ();
-
-/* Append the current history to FILENAME. If FILENAME is NULL,
- then append the history list to ~/.history. Values returned
- are as in read_history (). */
-extern int write_history ();
-
-
-/* Make the history entry at WHICH have LINE and DATA. This returns
- the old entry so you can dispose of the data. In the case of an
- invalid WHICH, a NULL pointer is returned. */
-extern HIST_ENTRY *replace_history_entry ();
-
-/* Return the history entry at the current position, as determined by
- history_offset. If there is no entry there, return a NULL pointer. */
-HIST_ENTRY *current_history ();
-
-/* Back up history_offset to the previous history entry, and return
- a pointer to that entry. If there is no previous entry, return
- a NULL pointer. */
-extern HIST_ENTRY *previous_history ();
-
-/* Move history_offset forward to the next item in the input_history,
- and return the a pointer to that entry. If there is no next entry,
- return a NULL pointer. */
-extern HIST_ENTRY *next_history ();
-
-/* Return a NULL terminated array of HIST_ENTRY which is the current input
- history. Element 0 of this list is the beginning of time. If there
- is no history, return NULL. */
-extern HIST_ENTRY **history_list ();
-
-/* Search the history for STRING, starting at history_offset.
- If DIRECTION < 0, then the search is through previous entries,
- else through subsequent. If the string is found, then
- current_history () is the history entry, and the value of this function
- is the offset in the line of that history entry that the string was
- found in. Otherwise, nothing is changed, and a -1 is returned. */
-extern int history_search ();
-
-/* Expand the string STRING, placing the result into OUTPUT, a pointer
- to a string. Returns:
-
- 0) If no expansions took place (or, if the only change in
- the text was the de-slashifying of the history expansion
- character)
- 1) If expansions did take place
- -1) If there was an error in expansion.
-
- If an error ocurred in expansion, then OUTPUT contains a descriptive
- error message. */
-extern int history_expand ();
-
-/* Extract a string segment consisting of the FIRST through LAST
- arguments present in STRING. Arguments are broken up as in
- the shell. */
-extern char *history_arg_extract ();
-
-
diff --git a/gnu/usr.bin/gdb/readline/keymaps.c b/gnu/usr.bin/gdb/readline/keymaps.c
deleted file mode 100644
index e0c5e394a421..000000000000
--- a/gnu/usr.bin/gdb/readline/keymaps.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
-
-/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
-
- This file is part of GNU Readline, a library for reading lines
- of text with interactive input and history editing.
-
- Readline is free software; you can 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.
-
- Readline is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Readline; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "keymaps.h"
-#include "emacs_keymap.c"
-
-#ifdef VI_MODE
-#include "vi_keymap.c"
-#endif
-
-/* Remove these declarations when we have a complete libgnu.a. */
-#define STATIC_MALLOC
-#ifndef STATIC_MALLOC
-extern char *xmalloc (), *xrealloc ();
-#else
-static char *xmalloc (), *xrealloc ();
-#endif
-
-/* **************************************************************** */
-/* */
-/* Functions for manipulating Keymaps. */
-/* */
-/* **************************************************************** */
-
-
-/* Return a new, empty keymap.
- Free it with free() when you are done. */
-Keymap
-rl_make_bare_keymap ()
-{
- register int i;
- Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY));
-
- for (i = 0; i < 128; i++)
- {
- keymap[i].type = ISFUNC;
- keymap[i].function = (Function *)NULL;
- }
-
- for (i = 'A'; i < ('Z' + 1); i++)
- {
- keymap[i].type = ISFUNC;
- keymap[i].function = rl_do_lowercase_version;
- }
-
- return (keymap);
-}
-
-/* Return a new keymap which is a copy of MAP. */
-Keymap
-rl_copy_keymap (map)
- Keymap map;
-{
- register int i;
- Keymap temp = rl_make_bare_keymap ();
-
- for (i = 0; i < 128; i++)
- {
- temp[i].type = map[i].type;
- temp[i].function = map[i].function;
- }
- return (temp);
-}
-
-/* Return a new keymap with the printing characters bound to rl_insert,
- the uppercase Meta characters bound to run their lowercase equivalents,
- and the Meta digits bound to produce numeric arguments. */
-Keymap
-rl_make_keymap ()
-{
- extern rl_insert (), rl_rubout (), rl_do_lowercase_version ();
- extern rl_digit_argument ();
- register int i;
- Keymap newmap;
-
- newmap = rl_make_bare_keymap ();
-
- /* All printing characters are self-inserting. */
- for (i = ' '; i < 126; i++)
- newmap[i].function = rl_insert;
-
- newmap[TAB].function = rl_insert;
- newmap[RUBOUT].function = rl_rubout;
-
- return (newmap);
-}
-
-/* Free the storage associated with MAP. */
-rl_discard_keymap (map)
- Keymap (map);
-{
- int i;
-
- if (!map)
- return;
-
- for (i = 0; i < 128; i++)
- {
- switch (map[i].type)
- {
- case ISFUNC:
- break;
-
- case ISKMAP:
- rl_discard_keymap ((Keymap)map[i].function);
- break;
-
- case ISMACR:
- free ((char *)map[i].function);
- break;
- }
- }
-}
-
-#ifdef STATIC_MALLOC
-
-/* **************************************************************** */
-/* */
-/* xmalloc and xrealloc () */
-/* */
-/* **************************************************************** */
-
-static char *
-xmalloc (bytes)
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)malloc (bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static char *
-xrealloc (pointer, bytes)
- char *pointer;
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)realloc (pointer, bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static
-memory_error_and_abort ()
-{
- fprintf (stderr, "readline: Out of virtual memory!\n");
- abort ();
-}
-#endif /* STATIC_MALLOC */
diff --git a/gnu/usr.bin/gdb/readline/keymaps.h b/gnu/usr.bin/gdb/readline/keymaps.h
deleted file mode 100644
index 3c577b398f59..000000000000
--- a/gnu/usr.bin/gdb/readline/keymaps.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* keymaps.h -- Manipulation of readline keymaps. */
-
-#ifndef _KEYMAPS_H_
-#define _KEYMAPS_H_
-
-#include <readline/chardefs.h>
-
-#ifndef __FUNCTION_DEF
-typedef int Function ();
-#define __FUNCTION_DEF
-#endif
-
-/* A keymap contains one entry for each key in the ASCII set.
- Each entry consists of a type and a pointer.
- POINTER is the address of a function to run, or the
- address of a keymap to indirect through.
- TYPE says which kind of thing POINTER is. */
-typedef struct _keymap_entry {
- char type;
- Function *function;
-} KEYMAP_ENTRY;
-
-/* I wanted to make the above structure contain a union of:
- union { Function *function; struct _keymap_entry *keymap; } value;
- but this made it impossible for me to create a static array.
- Maybe I need C lessons. */
-
-typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128];
-typedef KEYMAP_ENTRY *Keymap;
-
-/* The values that TYPE can have in a keymap entry. */
-#define ISFUNC 0
-#define ISKMAP 1
-#define ISMACR 2
-
-extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
-extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
-
-/* Return a new, empty keymap.
- Free it with free() when you are done. */
-Keymap rl_make_bare_keymap ();
-
-/* Return a new keymap which is a copy of MAP. */
-Keymap rl_copy_keymap ();
-
-/* Return a new keymap with the printing characters bound to rl_insert,
- the lowercase Meta characters bound to run their equivalents, and
- the Meta digits bound to produce numeric arguments. */
-Keymap rl_make_keymap ();
-
-#endif /* _KEYMAPS_H_ */
-
-
diff --git a/gnu/usr.bin/gdb/readline/readline.c b/gnu/usr.bin/gdb/readline/readline.c
deleted file mode 100644
index 3e8f9a38a1d8..000000000000
--- a/gnu/usr.bin/gdb/readline/readline.c
+++ /dev/null
@@ -1,5557 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)readline.c 6.4 (Berkeley) 5/8/91";
-#endif /* not lint */
-
-/* readline.c -- a general facility for reading lines of input
- with emacs style editing and completion. */
-
-/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
-
- This file contains the Readline Library (the Library), a set of
- routines for providing Emacs style line input to programs that ask
- for it.
-
- The 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 1, or (at your option)
- any later version.
-
- The 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.
-
- The GNU General Public License is often shipped with GNU software, and
- is generally kept in a file called COPYING or LICENSE. If you do not
- have a copy of the license, write to the Free Software Foundation,
- 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Remove these declarations when we have a complete libgnu.a. */
-#define STATIC_MALLOC
-#ifndef STATIC_MALLOC
-extern char *xmalloc (), *xrealloc ();
-#else
-static char *xmalloc (), *xrealloc ();
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <signal.h>
-#include <string.h>
-
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else
-#if defined (sparc) && defined (sun)
-#include <alloca.h>
-#endif
-#endif
-
-#define NEW_TTY_DRIVER
-#if defined (SYSV) || defined (hpux)
-#undef NEW_TTY_DRIVER
-#include <termio.h>
-#else
-#include <sgtty.h>
-#endif
-
-#include <errno.h>
-extern int errno;
-
-#include <setjmp.h>
-
-/* These next are for filename completion. Perhaps this belongs
- in a different place. */
-#include <sys/stat.h>
-
-#include <pwd.h>
-#ifdef SYSV
-struct passwd *getpwuid (), *getpwent ();
-#endif
-
-#define HACK_TERMCAP_MOTION
-
-#ifndef SYSV
-#include <sys/dir.h>
-#else /* SYSV */
-#ifdef hpux
-#include <ndir.h>
-#else
-#include <dirent.h>
-#define direct dirent
-#define d_namlen d_reclen
-#endif /* hpux */
-#endif /* SYSV */
-
-/* Some standard library routines. */
-#include "readline.h"
-#include "history.h"
-
-#ifndef digit
-#define digit(c) ((c) >= '0' && (c) <= '9')
-#endif
-
-#ifndef isletter
-#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
-#endif
-
-#ifndef digit_value
-#define digit_value(c) ((c) - '0')
-#endif
-
-#ifndef member
-char *index ();
-#define member(c, s) ((c) ? index ((s), (c)) : 0)
-#endif
-
-#ifndef isident
-#define isident(c) ((isletter(c) || digit(c) || c == '_'))
-#endif
-
-#ifndef exchange
-#define exchange(x, y) {int temp = x; x = y; y = temp;}
-#endif
-
-static update_line ();
-static void output_character_function ();
-static delete_chars ();
-static start_insert ();
-static end_insert ();
-
-/* This typedef is equivalant to the one for Function; it allows us
- to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
-typedef void SigHandler ();
-
-#ifdef SIGWINCH
-static void rl_handle_sigwinch ();
-static SigHandler *old_sigwinch = (SigHandler *)NULL;
-#endif
-
-/* If on, then readline handles signals in a way that doesn't screw. */
-/* #define HANDLE_SIGNALS */
-
-#if defined (SYSV)
-#ifdef HANDLE_SIGNALS
-#undef HANDLE_SIGNALS
-#endif
-#endif
-
-/* Stupid comparison routine for qsort () ing strings. */
-static int
-compare_strings (s1, s2)
- char **s1, **s2;
-{
- return (strcmp (*s1, *s2));
-}
-
-
-/* **************************************************************** */
-/* */
-/* Line editing input utility */
-/* */
-/* **************************************************************** */
-
-/* A pointer to the keymap that is currently in use.
- By default, it is the standard emacs keymap. */
-Keymap keymap = emacs_standard_keymap;
-
-#define vi_mode 0
-#define emacs_mode 1
-
-/* The current style of editing. */
-int rl_editing_mode = emacs_mode;
-
-/* Non-zero if the previous command was a kill command. */
-static int last_command_was_kill = 0;
-
-/* The current value of the numeric argument specified by the user. */
-int rl_numeric_arg = 1;
-
-/* Non-zero if an argument was typed. */
-int rl_explicit_arg = 0;
-
-/* Temporary value used while generating the argument. */
-static int arg_sign = 1;
-
-/* Non-zero means we have been called at least once before. */
-static int rl_initialized = 0;
-
-/* If non-zero, this program is running in an EMACS buffer. */
-static char *running_in_emacs = (char *)NULL;
-
-/* The current offset in the current input line. */
-int rl_point;
-
-/* Mark in the current input line. */
-int rl_mark;
-
-/* Length of the current input line. */
-int rl_end;
-
-/* Make this non-zero to return the current input_line. */
-int rl_done;
-
-/* The last function executed by readline. */
-Function *rl_last_func = (Function *)NULL;
-
-/* Top level environment for readline_internal (). */
-static jmp_buf readline_top_level;
-
-/* The streams we interact with. */
-static FILE *in_stream, *out_stream;
-
-/* The names of the streams that we do input and output to. */
-FILE *rl_instream = stdin, *rl_outstream = stdout;
-
-/* Non-zero means echo characters as they are read. */
-int readline_echoing_p = 1;
-
-/* Current prompt. */
-char *rl_prompt;
-
-/* The number of characters read in order to type this complete command. */
-int rl_key_sequence_length = 0;
-
-/* If non-zero, then this is the address of a function to call just
- before readline_internal () prints the first prompt. */
-Function *rl_startup_hook = (Function *)NULL;
-
-/* What we use internally. You should always refer to RL_LINE_BUFFER. */
-static char *the_line;
-
-/* The character that can generate an EOF. Really read from
- the terminal driver... just defaulted here. */
-static int eof_char = CTRL ('D');
-
-/* Non-zero makes this the next keystroke to read. */
-int rl_pending_input = 0;
-
-/* Pointer to a useful terminal name. */
-char *rl_terminal_name = (char *)NULL;
-
-/* Line buffer and maintenence. */
-char *rl_line_buffer = (char *)NULL;
-static int rl_line_buffer_len = 0;
-#define DEFAULT_BUFFER_SIZE 256
-
-
-/* **************************************************************** */
-/* */
-/* Top Level Functions */
-/* */
-/* **************************************************************** */
-
-/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means
- none. A return value of NULL means that EOF was encountered. */
-char *
-readline (prompt)
- char *prompt;
-{
- static rl_prep_terminal (), rl_deprep_terminal ();
- char *readline_internal ();
- char *value;
-
- rl_prompt = prompt;
-
- /* If we are at EOF return a NULL string. */
- if (rl_pending_input == EOF)
- {
- rl_pending_input = 0;
- return ((char *)NULL);
- }
-
- rl_initialize ();
- rl_prep_terminal ();
-
-#ifdef SIGWINCH
- old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch);
-#endif
-
-#ifdef HANDLE_SIGNALS
- rl_set_signals ();
-#endif
-
- value = readline_internal ();
- rl_deprep_terminal ();
-
-#ifdef SIGWINCH
- signal (SIGWINCH, old_sigwinch);
-#endif
-
-#ifdef HANDLE_SIGNALS
- rl_clear_signals ();
-#endif
-
- return (value);
-}
-
-/* Read a line of input from the global rl_instream, doing output on
- the global rl_outstream.
- If rl_prompt is non-null, then that is our prompt. */
-char *
-readline_internal ()
-{
- int lastc, c, eof_found;
-
- in_stream = rl_instream; out_stream = rl_outstream;
- lastc = eof_found = 0;
-
- if (rl_startup_hook)
- (*rl_startup_hook) ();
-
- if (!readline_echoing_p)
- {
- if (rl_prompt) {
- fprintf (out_stream, "%s", rl_prompt);
- fflush(out_stream);
- }
- }
- else
- {
- rl_on_new_line ();
- rl_redisplay ();
-#ifdef VI_MODE
- if (rl_editing_mode == vi_mode)
- rl_vi_insertion_mode ();
-#endif /* VI_MODE */
- }
-
- while (!rl_done)
- {
- int lk = last_command_was_kill;
- int code = setjmp (readline_top_level);
-
- if (code)
- rl_redisplay ();
-
- if (!rl_pending_input)
- {
- /* Then initialize the argument and number of keys read. */
- rl_init_argument ();
- rl_key_sequence_length = 0;
- }
-
- c = rl_read_key ();
-
- /* EOF typed to a non-blank line is a <NL>. */
- if (c == EOF && rl_end)
- c = NEWLINE;
-
- /* The character eof_char typed to blank line, and not as the
- previous character is interpreted as EOF. */
- if (((c == eof_char && lastc != c) || c == EOF) && !rl_end)
- {
- eof_found = 1;
- break;
- }
-
- lastc = c;
- rl_dispatch (c, keymap);
-
- /* If there was no change in last_command_was_kill, then no kill
- has taken place. Note that if input is pending we are reading
- a prefix command, so nothing has changed yet. */
- if (!rl_pending_input)
- {
- if (lk == last_command_was_kill)
- last_command_was_kill = 0;
- }
-
-#ifdef VI_MODE
- /* In vi mode, when you exit insert mode, the cursor moves back
- over the previous character. We explicitly check for that here. */
- if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap)
- rl_vi_check ();
-#endif
-
- if (!rl_done)
- rl_redisplay ();
- }
-
- /* Restore the original of this history line, iff the line that we
- are editing was originally in the history, AND the line has changed. */
- {
- HIST_ENTRY *entry = current_history ();
-
- if (entry && rl_undo_list)
- {
- char *temp = savestring (the_line);
- rl_revert_line ();
- entry = replace_history_entry (where_history (), the_line,
- (HIST_ENTRY *)NULL);
- free_history_entry (entry);
-
- strcpy (the_line, temp);
- free (temp);
- }
- }
-
- /* At any rate, it is highly likely that this line has an undo list. Get
- rid of it now. */
- if (rl_undo_list)
- free_undo_list ();
-
- if (eof_found)
- return (char *)NULL;
- else
- return (savestring (the_line));
-}
-
-
-/* Variables for keyboard macros. */
-
-/* The currently executing macro string. If this is non-zero,
- then it is a malloc ()'ed string where input is coming from. */
-static char *executing_macro = (char *)NULL;
-
-/* The offset in the above string to the next character to be read. */
-static int executing_macro_index = 0;
-
-/* Non-zero means to save keys that we dispatch on in a kbd macro. */
-static int defining_kbd_macro = 0;
-
-/* The current macro string being built. Characters get stuffed
- in here by add_macro_char (). */
-static char *current_macro = (char *)NULL;
-
-/* The size of the buffer allocated to current_macro. */
-static int current_macro_size = 0;
-
-/* The index at which characters are being added to current_macro. */
-static int current_macro_index = 0;
-
-/* A structure used to save nested macro strings.
- It is a linked list of string/index for each saved macro. */
-struct saved_macro {
- struct saved_macro *next;
- char *string;
- int index;
-};
-
-/* The list of saved macros. */
-struct saved_macro *macro_list = (struct saved_macro *)NULL;
-
-
-/* **************************************************************** */
-/* */
-/* Signal Handling */
-/* */
-/* **************************************************************** */
-
-#ifdef SIGWINCH
-static void
-rl_handle_sigwinch (sig, code, scp)
- int sig, code;
- struct sigcontext *scp;
-{
- char *term = rl_terminal_name, *getenv ();
-
- if (readline_echoing_p)
- {
- if (!term)
- term = getenv ("TERM");
- if (!term)
- term = "dumb";
- rl_reset_terminal (term);
-#ifdef NEVER
- crlf ();
- rl_forced_update_display ();
-#endif
- }
-
- if (old_sigwinch &&
- old_sigwinch != (SigHandler *)SIG_IGN &&
- old_sigwinch != (SigHandler *)SIG_DFL)
- (*old_sigwinch)(sig, code, scp);
-}
-#endif /* SIGWINCH */
-
-#ifdef HANDLE_SIGNALS
-/* Interrupt handling. */
-static SigHandler *old_int = (SigHandler *)NULL,
- *old_tstp = (SigHandler *)NULL,
- *old_ttou = (SigHandler *)NULL,
- *old_ttin = (SigHandler *)NULL,
- *old_cont = (SigHandler *)NULL;
-
-/* Handle an interrupt character. */
-static void
-rl_signal_handler (sig, code, scp)
- int sig, code;
- struct sigcontext *scp;
-{
- static rl_prep_terminal (), rl_deprep_terminal ();
-
- switch (sig)
- {
- case SIGINT:
- free_undo_list ();
- rl_clear_message ();
- rl_init_argument ();
-#ifdef SIGWINCH
- signal (SIGWINCH, old_sigwinch);
-#endif
-
-#ifdef SIGTSTP
- case SIGTSTP:
- case SIGTTOU:
- case SIGTTIN:
-#endif
-
- rl_clean_up_for_exit ();
- rl_deprep_terminal ();
- rl_clear_signals ();
- rl_pending_input = 0;
-
- kill (getpid (), sig);
- sigsetmask (0);
-
- rl_prep_terminal ();
- rl_set_signals ();
- }
-}
-
-rl_set_signals ()
-{
- old_int = (SigHandler *)signal (SIGINT, rl_signal_handler);
-
- if (old_int == (SigHandler *)SIG_IGN)
- signal (SIGINT, SIG_IGN);
-
-#ifdef SIGTSTP
- old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler);
- if (old_tstp == (SigHandler *)SIG_IGN)
- signal (SIGTSTP, SIG_IGN);
-#endif
-#ifdef SIGTTOU
- old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler);
- old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler);
-#endif
-}
-
-rl_clear_signals ()
-{
- signal (SIGINT, old_int);
-
-#ifdef SIGTSTP
- signal (SIGTSTP, old_tstp);
-#endif
-#ifdef SIGTTOU
- signal (SIGTTOU, old_ttou);
- signal (SIGTTIN, old_ttin);
-#endif
-}
-#endif /* HANDLE_SIGNALS */
-
-
-
-/* **************************************************************** */
-/* */
-/* Character Input Buffering */
-/* */
-/* **************************************************************** */
-
-/* If the terminal was in xoff state when we got to it, then xon_char
- contains the character that is supposed to start it again. */
-static int xon_char, xoff_state;
-static int pop_index = 0, push_index = 0, ibuffer_len = 511;
-static unsigned char ibuffer[512];
-
-/* Non-null means it is a pointer to a function to run while waiting for
- character input. */
-Function *rl_event_hook = (Function *)NULL;
-
-#define any_typein (push_index != pop_index)
-
-/* Add KEY to the buffer of characters to be read. */
-rl_stuff_char (key)
- int key;
-{
- if (key == EOF)
- {
- key = NEWLINE;
- rl_pending_input = EOF;
- }
- ibuffer[push_index++] = key;
- if (push_index >= ibuffer_len)
- push_index = 0;
-}
-
-/* Return the amount of space available in the
- buffer for stuffing characters. */
-int
-ibuffer_space ()
-{
- if (pop_index > push_index)
- return (pop_index - push_index);
- else
- return (ibuffer_len - (push_index - pop_index));
-}
-
-/* Get a key from the buffer of characters to be read.
- Result is KEY if there was a key, or -2 if there wasn't. */
-int
-rl_get_char ()
-{
- int key;
-
- if (push_index == pop_index)
- return (-2);
-
- key = ibuffer[pop_index++];
-
- if (pop_index >= ibuffer_len)
- pop_index = 0;
-
- return (key);
-}
-
-/* Stuff KEY into the *front* of the input buffer.
- Returns non-zero if successful, zero if there is
- no space left in the buffer. */
-int
-rl_unget_char (key)
- int key;
-{
- if (ibuffer_space ())
- {
- pop_index--;
- if (pop_index < 0)
- pop_index = ibuffer_len - 1;
- ibuffer[pop_index] = key;
- return (1);
- }
- return (0);
-}
-
-
-
-static void
-rl_getc (stream)
- FILE *stream;
-{
- int result;
- int nchar;
- int tty = fileno(stream);
- char buf[512]; /* XXX - must be at least as large as ibuffer */
-
- while (1)
- {
- if (ioctl(tty, FIONREAD, &nchar) == -1)
- nchar = sizeof(buf);
- else if (nchar <= 0)
- nchar = 1;
- result = ibuffer_space();
- if (nchar > result)
- nchar = result;
- result = read(tty, buf, nchar);
- if (result > 0)
- {
- register char *cp = buf;
-
- while (--result >= 0)
- rl_stuff_char(*cp++);
- return;
- }
- if (errno != EINTR)
- {
- rl_stuff_char(EOF);
- return;
- }
- }
-}
-
-/* Read a key, including pending input. */
-int
-rl_read_key ()
-{
- int c;
-
- rl_key_sequence_length++;
-
- if (rl_pending_input)
- {
- c = rl_pending_input;
- rl_pending_input = 0;
- }
- else
- {
- static int next_macro_key ();
-
- /* If input is coming from a macro, then use that. */
- if (c = next_macro_key ())
- return (c);
-
- while ((c = rl_get_char()) == -2)
- {
- if (rl_event_hook)
- {
- (*rl_event_hook) ();
- if ((c = rl_get_char()) != -2)
- return (c);
- }
- rl_getc(in_stream);
- }
- }
-#ifdef TIOCSTART
- /* Ugh. But I can't think of a better way. */
- if (xoff_state && c == xon_char)
- {
- ioctl (fileno (in_stream), TIOCSTART, 0);
- xoff_state = 0;
- return rl_read_key ();
- }
-#endif /* TIOCSTART */
- return (c);
-}
-
-/* Do the command associated with KEY in MAP.
- If the associated command is really a keymap, then read
- another key, and dispatch into that map. */
-rl_dispatch (key, map)
- register int key;
- Keymap map;
-{
- if (defining_kbd_macro)
- {
- static add_macro_char ();
-
- add_macro_char (key);
- }
-
- if (key > 127 && key < 256)
- {
- if (map[ESC].type == ISKMAP)
- {
- map = (Keymap)map[ESC].function;
- key -= 128;
- rl_dispatch (key, map);
- }
- else
- ding ();
- return;
- }
-
- switch (map[key].type)
- {
- case ISFUNC:
- {
- Function *func = map[key].function;
-
- if (func != (Function *)NULL)
- {
- /* Special case rl_do_lowercase_version (). */
- if (func == rl_do_lowercase_version)
- {
- rl_dispatch (to_lower (key), map);
- return;
- }
-
- (*map[key].function)(rl_numeric_arg * arg_sign, key);
- }
- else
- {
- ding ();
- return;
- }
- }
- break;
-
- case ISKMAP:
- if (map[key].function != (Function *)NULL)
- {
- int newkey;
-
- rl_key_sequence_length++;
- newkey = rl_read_key ();
- rl_dispatch (newkey, (Keymap)map[key].function);
- }
- else
- {
- ding ();
- return;
- }
- break;
-
- case ISMACR:
- if (map[key].function != (Function *)NULL)
- {
- static with_macro_input ();
- char *macro = savestring ((char *)map[key].function);
-
- with_macro_input (macro);
- return;
- }
- break;
- }
-
- /* If we have input pending, then the last command was a prefix
- command. Don't change the state of rl_last_func. */
- if (!rl_pending_input)
- rl_last_func = map[key].function;
-}
-
-
-/* **************************************************************** */
-/* */
-/* Hacking Keyboard Macros */
-/* */
-/* **************************************************************** */
-
-/* Set up to read subsequent input from STRING.
- STRING is free ()'ed when we are done with it. */
-static
-with_macro_input (string)
- char *string;
-{
- static push_executing_macro ();
-
- push_executing_macro ();
- executing_macro = string;
- executing_macro_index = 0;
-}
-
-/* Return the next character available from a macro, or 0 if
- there are no macro characters. */
-static int
-next_macro_key ()
-{
- if (!executing_macro)
- return (0);
-
- if (!executing_macro[executing_macro_index])
- {
- static pop_executing_macro ();
-
- pop_executing_macro ();
- return (next_macro_key ());
- }
-
- return (executing_macro[executing_macro_index++]);
-}
-
-/* Save the currently executing macro on a stack of saved macros. */
-static
-push_executing_macro ()
-{
- struct saved_macro *saver;
-
- saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
- saver->next = macro_list;
- saver->index = executing_macro_index;
- saver->string = executing_macro;
-
- macro_list = saver;
-}
-
-/* Discard the current macro, replacing it with the one
- on the top of the stack of saved macros. */
-static
-pop_executing_macro ()
-{
- if (executing_macro)
- free (executing_macro);
-
- executing_macro = (char *)NULL;
- executing_macro_index = 0;
-
- if (macro_list)
- {
- struct saved_macro *disposer = macro_list;
- executing_macro = macro_list->string;
- executing_macro_index = macro_list->index;
- macro_list = macro_list->next;
- free (disposer);
- }
-}
-
-/* Add a character to the macro being built. */
-static
-add_macro_char (c)
- int c;
-{
- if (current_macro_index + 1 >= current_macro_size)
- {
- if (!current_macro)
- current_macro = (char *)xmalloc (current_macro_size = 25);
- else
- current_macro =
- (char *)xrealloc (current_macro, current_macro_size += 25);
- }
-
- current_macro[current_macro_index++] = c;
- current_macro[current_macro_index] = '\0';
-}
-
-/* Begin defining a keyboard macro.
- Keystrokes are recorded as they are executed.
- End the definition with rl_end_kbd_macro ().
- If a numeric argument was explicitly typed, then append this
- definition to the end of the existing macro, and start by
- re-executing the existing macro. */
-rl_start_kbd_macro (ignore1, ignore2)
- int ignore1, ignore2;
-{
- if (defining_kbd_macro)
- rl_abort ();
-
- if (rl_explicit_arg)
- {
- if (current_macro)
- with_macro_input (savestring (current_macro));
- }
- else
- current_macro_index = 0;
-
- defining_kbd_macro = 1;
-}
-
-/* Stop defining a keyboard macro.
- A numeric argument says to execute the macro right now,
- that many times, counting the definition as the first time. */
-rl_end_kbd_macro (count, ignore)
- int count, ignore;
-{
- if (!defining_kbd_macro)
- rl_abort ();
-
- current_macro_index -= (rl_key_sequence_length - 1);
- current_macro[current_macro_index] = '\0';
-
- defining_kbd_macro = 0;
-
- rl_call_last_kbd_macro (--count, 0);
-}
-
-/* Execute the most recently defined keyboard macro.
- COUNT says how many times to execute it. */
-rl_call_last_kbd_macro (count, ignore)
- int count, ignore;
-{
- if (!current_macro)
- rl_abort ();
-
- while (count--)
- with_macro_input (savestring (current_macro));
-}
-
-
-/* Non-zero means do not parse any lines other than comments and
- parser directives. */
-static unsigned char parsing_conditionalized_out = 0;
-
-/* **************************************************************** */
-/* */
-/* Initializations */
-/* */
-/* **************************************************************** */
-
-/* Initliaze readline (and terminal if not already). */
-rl_initialize ()
-{
- extern char *rl_display_prompt;
-
- /* If we have never been called before, initialize the
- terminal and data structures. */
- if (!rl_initialized)
- {
- readline_initialize_everything ();
- rl_initialized++;
- }
-
- /* Initalize the current line information. */
- rl_point = rl_end = 0;
- the_line = rl_line_buffer;
- the_line[0] = 0;
-
- /* We aren't done yet. We haven't even gotten started yet! */
- rl_done = 0;
-
- /* Tell the history routines what is going on. */
- start_using_history ();
-
- /* Make the display buffer match the state of the line. */
- {
- extern char *rl_display_prompt;
- extern int forced_display;
-
- rl_on_new_line ();
-
- rl_display_prompt = rl_prompt ? rl_prompt : "";
- forced_display = 1;
- }
-
- /* No such function typed yet. */
- rl_last_func = (Function *)NULL;
-
- /* Parsing of key-bindings begins in an enabled state. */
- {
- parsing_conditionalized_out = 0;
- }
-}
-
-/* Initialize the entire state of the world. */
-readline_initialize_everything ()
-{
- /* Find out if we are running in Emacs. */
- running_in_emacs = (char *)getenv ("EMACS");
-
- /* Allocate data structures. */
- if (!rl_line_buffer)
- rl_line_buffer =
- (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
-
- /* Initialize the terminal interface. */
- init_terminal_io ((char *)NULL);
-
- /* Bind tty characters to readline functions. */
- readline_default_bindings ();
-
- /* Initialize the function names. */
- rl_initialize_funmap ();
-
- /* Read in the init file. */
- rl_read_init_file ((char *)NULL);
-
- /* If the completion parser's default word break characters haven't
- been set yet, then do so now. */
- {
- extern char *rl_completer_word_break_characters;
- extern char *rl_basic_word_break_characters;
-
- if (rl_completer_word_break_characters == (char *)NULL)
- rl_completer_word_break_characters = rl_basic_word_break_characters;
- }
-}
-
-/* If this system allows us to look at the values of the regular
- input editing characters, then bind them to their readline
- equivalents. */
-readline_default_bindings ()
-{
-#ifdef TIOCGETP
- struct sgttyb ttybuff;
- int tty = fileno (rl_instream);
-
- if (ioctl (tty, TIOCGETP, &ttybuff) != -1)
- {
- int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill;
-
- if (erase != -1 && keymap[erase].type == ISFUNC)
- keymap[erase].function = rl_rubout;
-
- if (kill != -1 && keymap[kill].type == ISFUNC)
- keymap[kill].function = rl_unix_line_discard;
- }
-
-#ifdef TIOCGLTC
- {
- struct ltchars lt;
-
- if (ioctl (tty, TIOCGLTC, &lt) != -1)
- {
- int erase = lt.t_werasc, nextc = lt.t_lnextc;
-
- if (erase != -1 && keymap[erase].type == ISFUNC)
- keymap[erase].function = rl_unix_word_rubout;
-
- if (nextc != -1 && keymap[nextc].type == ISFUNC)
- keymap[nextc].function = rl_quoted_insert;
- }
- }
-#endif /* TIOCGLTC */
-#endif /* TIOCGETP */
-}
-
-
-/* **************************************************************** */
-/* */
-/* Numeric Arguments */
-/* */
-/* **************************************************************** */
-
-/* Handle C-u style numeric args, as well as M--, and M-digits. */
-
-/* Add the current digit to the argument in progress. */
-rl_digit_argument (ignore, key)
- int ignore, key;
-{
- rl_pending_input = key;
- rl_digit_loop ();
-}
-
-/* What to do when you abort reading an argument. */
-rl_discard_argument ()
-{
- ding ();
- rl_clear_message ();
- rl_init_argument ();
-}
-
-/* Create a default argument. */
-rl_init_argument ()
-{
- rl_numeric_arg = arg_sign = 1;
- rl_explicit_arg = 0;
-}
-
-/* C-u, universal argument. Multiply the current argument by 4.
- Read a key. If the key has nothing to do with arguments, then
- dispatch on it. If the key is the abort character then abort. */
-rl_universal_argument ()
-{
- rl_numeric_arg *= 4;
- rl_digit_loop ();
-}
-
-rl_digit_loop ()
-{
- int key, c;
- while (1)
- {
- rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
- key = c = rl_read_key ();
-
- if (keymap[c].type == ISFUNC &&
- keymap[c].function == rl_universal_argument)
- {
- rl_numeric_arg *= 4;
- continue;
- }
- c = UNMETA (c);
- if (numeric (c))
- {
- if (rl_explicit_arg)
- rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
- else
- rl_numeric_arg = (c - '0');
- rl_explicit_arg = 1;
- }
- else
- {
- if (c == '-' && !rl_explicit_arg)
- {
- rl_numeric_arg = 1;
- arg_sign = -1;
- }
- else
- {
- rl_clear_message ();
- rl_dispatch (key, keymap);
- return;
- }
- }
- }
-}
-
-
-/* **************************************************************** */
-/* */
-/* Display stuff */
-/* */
-/* **************************************************************** */
-
-/* This is the stuff that is hard for me. I never seem to write good
- display routines in C. Let's see how I do this time. */
-
-/* (PWP) Well... Good for a simple line updater, but totally ignores
- the problems of input lines longer than the screen width.
-
- update_line and the code that calls it makes a multiple line,
- automatically wrapping line update. Carefull attention needs
- to be paid to the vertical position variables.
-
- handling of terminals with autowrap on (incl. DEC braindamage)
- could be improved a bit. Right now I just cheat and decrement
- screenwidth by one. */
-
-/* Keep two buffers; one which reflects the current contents of the
- screen, and the other to draw what we think the new contents should
- be. Then compare the buffers, and make whatever changes to the
- screen itself that we should. Finally, make the buffer that we
- just drew into be the one which reflects the current contents of the
- screen, and place the cursor where it belongs.
-
- Commands that want to can fix the display themselves, and then let
- this function know that the display has been fixed by setting the
- RL_DISPLAY_FIXED variable. This is good for efficiency. */
-
-/* Termcap variables: */
-extern char *term_up, *term_dc, *term_cr;
-extern int screenheight, screenwidth, terminal_can_insert;
-
-/* What YOU turn on when you have handled all redisplay yourself. */
-int rl_display_fixed = 0;
-
-/* The visible cursor position. If you print some text, adjust this. */
-int last_c_pos = 0;
-int last_v_pos = 0;
-
-/* The last left edge of text that was displayed. This is used when
- doing horizontal scrolling. It shifts in thirds of a screenwidth. */
-static int last_lmargin = 0;
-
-/* The line display buffers. One is the line currently displayed on
- the screen. The other is the line about to be displayed. */
-static char *visible_line = (char *)NULL;
-static char *invisible_line = (char *)NULL;
-
-/* Number of lines currently on screen minus 1. */
-int vis_botlin = 0;
-
-/* A buffer for `modeline' messages. */
-char msg_buf[128];
-
-/* Non-zero forces the redisplay even if we thought it was unnecessary. */
-int forced_display = 0;
-
-/* The stuff that gets printed out before the actual text of the line.
- This is usually pointing to rl_prompt. */
-char *rl_display_prompt = (char *)NULL;
-
-/* Default and initial buffer size. Can grow. */
-static int line_size = 1024;
-
-/* Non-zero means to always use horizontal scrolling in line display. */
-int horizontal_scroll_mode = 0;
-
-/* I really disagree with this, but my boss (among others) insists that we
- support compilers that don't work. I don't think we are gaining by doing
- so; what is the advantage in producing better code if we can't use it? */
-/* The following two declarations belong inside the
- function block, not here. */
-static void move_cursor_relative ();
-static void output_some_chars ();
-
-/* Basic redisplay algorithm. */
-rl_redisplay ()
-{
- register int in, out, c, linenum;
- register char *line = invisible_line;
- int c_pos = 0;
- int inv_botlin = 0; /* Number of lines in newly drawn buffer. */
-
- extern int readline_echoing_p;
-
- if (!readline_echoing_p)
- return;
-
- if (!rl_display_prompt)
- rl_display_prompt = "";
-
- if (!invisible_line)
- {
- visible_line = (char *)xmalloc (line_size);
- invisible_line = (char *)xmalloc (line_size);
- line = invisible_line;
- for (in = 0; in < line_size; in++)
- {
- visible_line[in] = 0;
- invisible_line[in] = 1;
- }
- rl_on_new_line ();
- }
-
- /* Draw the line into the buffer. */
- c_pos = -1;
-
- /* Mark the line as modified or not. We only do this for history
- lines. */
- out = 0;
- if (current_history () && rl_undo_list)
- {
- line[out++] = '*';
- line[out] = '\0';
- }
-
- /* If someone thought that the redisplay was handled, but the currently
- visible line has a different modification state than the one about
- to become visible, then correct the callers misconception. */
- if (visible_line[0] != invisible_line[0])
- rl_display_fixed = 0;
-
- strncpy (line + out, rl_display_prompt, strlen (rl_display_prompt));
- out += strlen (rl_display_prompt);
- line[out] = '\0';
-
- for (in = 0; in < rl_end; in++)
- {
- c = the_line[in];
-
- if (out + 1 >= line_size)
- {
- line_size *= 2;
- visible_line = (char *)xrealloc (visible_line, line_size);
- invisible_line = (char *)xrealloc (invisible_line, line_size);
- line = invisible_line;
- }
-
- if (in == rl_point)
- c_pos = out;
-
- if (c > 127)
- {
- line[out++] = 'M';
- line[out++] = '-';
- line[out++] = c - 128;
- }
-#define DISPLAY_TABS
-#ifdef DISPLAY_TABS
- else if (c == '\t')
- {
- register int newout = (out | (int)7) + 1;
- while (out < newout)
- line[out++] = ' ';
- }
-#endif
- else if (c < 32)
- {
- line[out++] = 'C';
- line[out++] = '-';
- line[out++] = c + 64;
- }
- else
- line[out++] = c;
- }
- line[out] = '\0';
- if (c_pos < 0)
- c_pos = out;
-
- /* PWP: now is when things get a bit hairy. The visible and invisible
- line buffers are really multiple lines, which would wrap every
- (screenwidth - 1) characters. Go through each in turn, finding
- the changed region and updating it. The line order is top to bottom. */
-
- /* If we can move the cursor up and down, then use multiple lines,
- otherwise, let long lines display in a single terminal line, and
- horizontally scroll it. */
-
- if (!horizontal_scroll_mode && term_up && *term_up)
- {
- int total_screen_chars = (screenwidth * screenheight);
-
- if (!rl_display_fixed || forced_display)
- {
- forced_display = 0;
-
- /* If we have more than a screenful of material to display, then
- only display a screenful. We should display the last screen,
- not the first. I'll fix this in a minute. */
- if (out >= total_screen_chars)
- out = total_screen_chars - 1;
-
- /* Number of screen lines to display. */
- inv_botlin = out / screenwidth;
-
- /* For each line in the buffer, do the updating display. */
- for (linenum = 0; linenum <= inv_botlin; linenum++)
- update_line (linenum > vis_botlin ? ""
- : &visible_line[linenum * screenwidth],
- &invisible_line[linenum * screenwidth],
- linenum);
-
- /* We may have deleted some lines. If so, clear the left over
- blank ones at the bottom out. */
- if (vis_botlin > inv_botlin)
- {
- char *tt;
- for (; linenum <= vis_botlin; linenum++)
- {
- tt = &visible_line[linenum * screenwidth];
- move_vert (linenum);
- move_cursor_relative (0, tt);
- clear_to_eol ((linenum == vis_botlin)?
- strlen (tt) : screenwidth);
- }
- }
- vis_botlin = inv_botlin;
-
- /* Move the cursor where it should be. */
- move_vert (c_pos / screenwidth);
- move_cursor_relative (c_pos % screenwidth,
- &invisible_line[(c_pos / screenwidth) * screenwidth]);
- }
- }
- else /* Do horizontal scrolling. */
- {
- int lmargin;
-
- /* Always at top line. */
- last_v_pos = 0;
-
- /* If the display position of the cursor would be off the edge
- of the screen, start the display of this line at an offset that
- leaves the cursor on the screen. */
- if (c_pos - last_lmargin > screenwidth - 2)
- lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
- else if (c_pos - last_lmargin < 1)
- lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
- else
- lmargin = last_lmargin;
-
- /* If the first character on the screen isn't the first character
- in the display line, indicate this with a special character. */
- if (lmargin > 0)
- line[lmargin] = '<';
-
- if (lmargin + screenwidth < out)
- line[lmargin + screenwidth - 1] = '>';
-
- if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
- {
- forced_display = 0;
- update_line (&visible_line[last_lmargin],
- &invisible_line[lmargin], 0);
-
- move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
- last_lmargin = lmargin;
- }
- }
- fflush (out_stream);
-
- /* Swap visible and non-visible lines. */
- {
- char *temp = visible_line;
- visible_line = invisible_line;
- invisible_line = temp;
- rl_display_fixed = 0;
- }
-}
-
-/* PWP: update_line() is based on finding the middle difference of each
- line on the screen; vis:
-
- /old first difference
- /beginning of line | /old last same /old EOL
- v v v v
-old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
-new: eddie> Oh, my little buggy says to me, as lurgid as
- ^ ^ ^ ^
- \beginning of line | \new last same \new end of line
- \new first difference
-
- All are character pointers for the sake of speed. Special cases for
- no differences, as well as for end of line additions must be handeled.
-
- Could be made even smarter, but this works well enough */
-static
-update_line (old, new, current_line)
- register char *old, *new;
- int current_line;
-{
- register char *ofd, *ols, *oe, *nfd, *nls, *ne;
- int lendiff, wsatend;
-
- /* Find first difference. */
- for (ofd = old, nfd = new;
- (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
- ofd++, nfd++)
- ;
-
- /* Move to the end of the screen line. */
- for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
- for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
-
- /* If no difference, continue to next line. */
- if (ofd == oe && nfd == ne)
- return;
-
- wsatend = 1; /* flag for trailing whitespace */
- ols = oe - 1; /* find last same */
- nls = ne - 1;
- while ((*ols == *nls) && (ols > ofd) && (nls > nfd))
- {
- if (*ols != ' ')
- wsatend = 0;
- ols--;
- nls--;
- }
-
- if (wsatend)
- {
- ols = oe;
- nls = ne;
- }
- else if (*ols != *nls)
- {
- if (*ols) /* don't step past the NUL */
- ols++;
- if (*nls)
- nls++;
- }
-
- move_vert (current_line);
- move_cursor_relative (ofd - old, old);
-
- /* if (len (new) > len (old)) */
- lendiff = (nls - nfd) - (ols - ofd);
-
- /* Insert (diff(len(old),len(new)) ch */
- if (lendiff > 0)
- {
- if (terminal_can_insert)
- {
- extern char *term_IC;
-
- /* Sometimes it is cheaper to print the characters rather than
- use the terminal's capabilities. */
- if ((2 * (ne - nfd)) < lendiff && (!term_IC || !*term_IC))
- {
- output_some_chars (nfd, (ne - nfd));
- last_c_pos += (ne - nfd);
- }
- else
- {
- if (*ols)
- {
- start_insert (lendiff);
- output_some_chars (nfd, lendiff);
- last_c_pos += lendiff;
- end_insert ();
- }
- else
- {
- /* At the end of a line the characters do not have to
- be "inserted". They can just be placed on the screen. */
- output_some_chars (nfd, lendiff);
- last_c_pos += lendiff;
- }
- /* Copy (new) chars to screen from first diff to last match. */
- if (((nls - nfd) - lendiff) > 0)
- {
- output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
- last_c_pos += ((nls - nfd) - lendiff);
- }
- }
- }
- else
- { /* cannot insert chars, write to EOL */
- output_some_chars (nfd, (ne - nfd));
- last_c_pos += (ne - nfd);
- }
- }
- else /* Delete characters from line. */
- {
- /* If possible and inexpensive to use terminal deletion, then do so. */
- if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
- {
- if (lendiff)
- delete_chars (-lendiff); /* delete (diff) characters */
-
- /* Copy (new) chars to screen from first diff to last match */
- if ((nls - nfd) > 0)
- {
- output_some_chars (nfd, (nls - nfd));
- last_c_pos += (nls - nfd);
- }
- }
- /* Otherwise, print over the existing material. */
- else
- {
- output_some_chars (nfd, (ne - nfd));
- last_c_pos += (ne - nfd);
- clear_to_eol ((oe - old) - (ne - new));
- }
- }
-}
-
-/* (PWP) tell the update routines that we have moved onto a
- new (empty) line. */
-rl_on_new_line ()
-{
- if (visible_line)
- visible_line[0] = '\0';
-
- last_c_pos = last_v_pos = 0;
- vis_botlin = last_lmargin = 0;
-}
-
-/* Actually update the display, period. */
-rl_forced_update_display ()
-{
- if (visible_line)
- {
- register char *temp = visible_line;
-
- while (*temp) *temp++ = '\0';
- }
- rl_on_new_line ();
- forced_display++;
- rl_redisplay ();
-}
-
-/* Move the cursor from last_c_pos to NEW, which are buffer indices.
- DATA is the contents of the screen line of interest; i.e., where
- the movement is being done. */
-static void
-move_cursor_relative (new, data)
- int new;
- char *data;
-{
- register int i;
- static void output_character_function ();
-
- /* It may be faster to output a CR, and then move forwards instead
- of moving backwards. */
- if (new + 1 < last_c_pos - new)
- {
- tputs (term_cr, 1, output_character_function);
- last_c_pos = 0;
- }
-
- if (last_c_pos == new) return;
-
- if (last_c_pos < new)
- {
- /* Move the cursor forward. We do it by printing the command
- to move the cursor forward if there is one, else print that
- portion of the output buffer again. Which is cheaper? */
-
- /* The above comment is left here for posterity. It is faster
- to print one character (non-control) than to print a control
- sequence telling the terminal to move forward one character.
- That kind of control is for people who don't know what the
- data is underneath the cursor. */
-#ifdef HACK_TERMCAP_MOTION
- extern char *term_forward_char;
-
- if (term_forward_char)
- for (i = last_c_pos; i < new; i++)
- tputs (term_forward_char, 1, output_character_function);
- else
- for (i = last_c_pos; i < new; i++)
- putc (data[i], out_stream);
-#else
- for (i = last_c_pos; i < new; i++)
- putc (data[i], out_stream);
-#endif /* HACK_TERMCAP_MOTION */
- }
- else
- backspace (last_c_pos - new);
- last_c_pos = new;
-}
-
-/* PWP: move the cursor up or down. */
-move_vert (to)
- int to;
-{
- void output_character_function ();
- register int delta, i;
-
- if (last_v_pos == to) return;
-
- if (to > screenheight)
- return;
-
- if ((delta = to - last_v_pos) > 0)
- {
- for (i = 0; i < delta; i++)
- putc ('\n', out_stream);
- tputs (term_cr, 1, output_character_function);
- last_c_pos = 0; /* because crlf() will do \r\n */
- }
- else
- { /* delta < 0 */
- if (term_up && *term_up)
- for (i = 0; i < -delta; i++)
- tputs (term_up, 1, output_character_function);
- }
- last_v_pos = to; /* now to is here */
-}
-
-/* Physically print C on out_stream. This is for functions which know
- how to optimize the display. */
-rl_show_char (c)
- int c;
-{
- if (c > 127)
- {
- fprintf (out_stream, "M-");
- c -= 128;
- }
-
-#ifdef DISPLAY_TABS
- if (c < 32 && c != '\t')
-#else
- if (c < 32)
-#endif
- {
-
- c += 64;
- }
-
- putc (c, out_stream);
- fflush (out_stream);
-}
-
-#ifdef DISPLAY_TABS
-int
-rl_character_len (c, pos)
- register int c, pos;
-{
- if (c < ' ' || c > 126)
- {
- if (c == '\t')
- return (((pos | (int)7) + 1) - pos);
- else
- return (3);
- }
- else
- return (1);
-}
-#else
-int
-rl_character_len (c)
- int c;
-{
- if (c < ' ' || c > 126)
- return (3);
- else
- return (1);
-}
-#endif /* DISPLAY_TAB */
-
-/* How to print things in the "echo-area". The prompt is treated as a
- mini-modeline. */
-rl_message (string, arg1, arg2)
- char *string;
-{
- sprintf (msg_buf, string, arg1, arg2);
- rl_display_prompt = msg_buf;
- rl_redisplay ();
-}
-
-/* How to clear things from the "echo-area". */
-rl_clear_message ()
-{
- rl_display_prompt = rl_prompt;
- rl_redisplay ();
-}
-
-/* **************************************************************** */
-/* */
-/* Terminal and Termcap */
-/* */
-/* **************************************************************** */
-
-static char *term_buffer = (char *)NULL;
-static char *term_string_buffer = (char *)NULL;
-
-/* Non-zero means this terminal can't really do anything. */
-int dumb_term = 0;
-
-char PC;
-char *BC, *UP;
-
-/* Some strings to control terminal actions. These are output by tputs (). */
-char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
-
-int screenwidth, screenheight;
-
-/* Non-zero if we determine that the terminal can do character insertion. */
-int terminal_can_insert = 0;
-
-/* How to insert characters. */
-char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
-
-/* How to delete characters. */
-char *term_dc, *term_DC;
-
-#ifdef HACK_TERMCAP_MOTION
-char *term_forward_char;
-#endif /* HACK_TERMCAP_MOTION */
-
-/* How to go up a line. */
-char *term_up;
-
-/* Re-initialize the terminal considering that the TERM/TERMCAP variable
- has changed. */
-rl_reset_terminal (terminal_name)
- char *terminal_name;
-{
- init_terminal_io (terminal_name);
-}
-
-init_terminal_io (terminal_name)
- char *terminal_name;
-{
- char *term = (terminal_name? terminal_name : (char *)getenv ("TERM"));
- char *tgetstr (), *buffer;
-
-
- if (!term_string_buffer)
- term_string_buffer = (char *)xmalloc (2048);
-
- if (!term_buffer)
- term_buffer = (char *)xmalloc (2048);
-
- buffer = term_string_buffer;
-
- term_clrpag = term_cr = term_clreol = (char *)NULL;
-
- if (!term)
- term = "dumb";
-
- if (tgetent (term_buffer, term) < 0)
- {
- dumb_term = 1;
- return;
- }
-
- BC = tgetstr ("pc", &buffer);
- PC = buffer ? *buffer : 0;
-
- term_backspace = tgetstr ("le", &buffer);
-
- term_cr = tgetstr ("cr", &buffer);
- term_clreol = tgetstr ("ce", &buffer);
- term_clrpag = tgetstr ("cl", &buffer);
-
- if (!term_cr)
- term_cr = "\r";
-
-#ifdef HACK_TERMCAP_MOTION
- term_forward_char = tgetstr ("nd", &buffer);
-#endif /* HACK_TERMCAP_MOTION */
-
- screenwidth = tgetnum ("co");
- if (screenwidth <= 0)
- screenwidth = 80;
- screenwidth--; /* PWP: avoid autowrap bugs */
-
- screenheight = tgetnum ("li");
- if (screenheight <= 0)
- screenheight = 24;
-
- term_im = tgetstr ("im", &buffer);
- term_ei = tgetstr ("ei", &buffer);
- term_IC = tgetstr ("IC", &buffer);
- term_ic = tgetstr ("ic", &buffer);
- term_ip = tgetstr ("ip", &buffer);
- term_IC = tgetstr ("IC", &buffer);
-
- /* "An application program can assume that the terminal can do
- character insertion if *any one of* the capabilities `IC',
- `im', `ic' or `ip' is provided." */
-#ifdef notdef
- /* XXX Circumvent broken code. */
- terminal_can_insert = (term_IC || term_im || term_ic || term_ip);
-#endif
-
- term_up = tgetstr ("up", &buffer);
- term_dc = tgetstr ("dc", &buffer);
- term_DC = tgetstr ("DC", &buffer);
-}
-
-/* A function for the use of tputs () */
-static void
-output_character_function (c)
- int c;
-{
- putc (c, out_stream);
-}
-
-/* Write COUNT characters from STRING to the output stream. */
-static void
-output_some_chars (string, count)
- char *string;
- int count;
-{
- fwrite (string, 1, count, out_stream);
-}
-
-
-/* Delete COUNT characters from the display line. */
-static
-delete_chars (count)
- int count;
-{
- if (count > screenwidth)
- return;
-
- if (term_DC && *term_DC)
- {
- char *tgoto (), *buffer;
- buffer = tgoto (term_DC, 0, count);
- tputs (buffer, 1, output_character_function);
- }
- else
- {
- if (term_dc && *term_dc)
- while (count--)
- tputs (term_dc, 1, output_character_function);
- }
-}
-
-/* Prepare to insert by inserting COUNT blank spaces. */
-static
-start_insert (count)
- int count;
-{
- if (term_im && *term_im)
- tputs (term_im, 1, output_character_function);
-
- if (term_IC && *term_IC &&
- (count > 1 || !term_ic || !*term_ic))
- {
- char *tgoto (), *buffer;
- buffer = tgoto (term_IC, 0, count);
- tputs (buffer, 1, output_character_function);
- }
- else
- {
- if (term_ic && *term_ic)
- while (count--)
- tputs (term_ic, 1, output_character_function);
- }
-}
-
-/* We are finished doing our insertion. Send ending string. */
-static
-end_insert ()
-{
- if (term_ei && *term_ei)
- tputs (term_ei, 1, output_character_function);
-}
-
-/* Move the cursor back. */
-backspace (count)
- int count;
-{
- register int i;
-
- if (term_backspace)
- for (i = 0; i < count; i++)
- tputs (term_backspace, 1, output_character_function);
- else
- for (i = 0; i < count; i++)
- putc ('\b', out_stream);
-}
-
-/* Move to the start of the next line. */
-crlf ()
-{
- tputs (term_cr, 1, output_character_function);
- putc ('\n', out_stream);
-}
-
-/* Clear to the end of the line. COUNT is the minimum
- number of character spaces to clear, */
-clear_to_eol (count)
- int count;
-{
- if (term_clreol) {
- tputs (term_clreol, 1, output_character_function);
- } else {
- register int i;
- /* Do one more character space. */
- count++;
- for (i = 0; i < count; i++)
- putc (' ', out_stream);
- backspace (count);
- }
-}
-
-
-/* **************************************************************** */
-/* */
-/* Saving and Restoring the TTY */
-/* */
-/* **************************************************************** */
-
-#ifdef NEW_TTY_DRIVER
-
-/* Standard flags, including ECHO. */
-static int original_tty_flags = 0;
-
-/* Local mode flags, like LPASS8. */
-static int local_mode_flags = 0;
-
-/* Terminal characters. This has C-s and C-q in it. */
-static struct tchars original_tchars;
-
-/* Local special characters. This has the interrupt characters in it. */
-static struct ltchars original_ltchars;
-
-/* We use this to get and set the tty_flags. */
-static struct sgttyb the_ttybuff;
-
-/* Put the terminal in CBREAK mode so that we can detect key presses. */
-static
-rl_prep_terminal ()
-{
- int tty = fileno (rl_instream);
-
- /* We always get the latest tty values. Maybe stty changed them. */
-
- ioctl (tty, TIOCGETP, &the_ttybuff);
- original_tty_flags = the_ttybuff.sg_flags;
-
- readline_echoing_p = (original_tty_flags & ECHO);
-
- /* If this terminal doesn't care how the 8th bit is used,
- then we can use it for the meta-key.
- We check by seeing if BOTH odd and even parity are allowed. */
- if ((the_ttybuff.sg_flags & (ODDP | EVENP)) == (ODDP | EVENP))
- {
-#ifdef PASS8
- the_ttybuff.sg_flags |= PASS8;
-#endif
-
-#if defined (TIOCLGET) && defined (LPASS8)
- {
- int flags;
- ioctl (tty, TIOCLGET, &flags);
- local_mode_flags = flags;
- flags |= LPASS8;
- ioctl (tty, TIOCLSET, &flags);
- }
-#endif
- }
-
-#ifdef TIOCGETC
- {
- struct tchars temp;
-
- ioctl (tty, TIOCGETC, &original_tchars);
- bcopy (&original_tchars, &temp, sizeof (struct tchars));
-
- /* Get rid of C-s and C-q.
- We remember the value of startc (C-q) so that if the terminal is in
- xoff state, the user can xon it by pressing that character. */
- xon_char = temp.t_startc;
- temp.t_stopc = -1;
- temp.t_startc = -1;
-
- /* If there is an XON character, bind it to restart the output. */
- if (xon_char != -1)
- rl_bind_key (xon_char, rl_restart_output);
-
- /* If there is an EOF char, bind eof_char to it. */
- if (temp.t_eofc != -1)
- eof_char = temp.t_eofc;
-
-#ifdef NEVER
- /* Get rid of C-\ and C-c. */
- temp.t_intrc = temp.t_quitc = -1;
-#endif
-
- ioctl (tty, TIOCSETC, &temp);
- }
-#endif /* TIOCGETC */
-
-#ifdef TIOCGLTC
- {
- struct ltchars temp;
-
- ioctl (tty, TIOCGLTC, &original_ltchars);
- bcopy (&original_ltchars, &temp, sizeof (struct ltchars));
-
- /* Make the interrupt keys go away. Just enough to make people happy. */
- temp.t_dsuspc = -1; /* C-y */
- temp.t_lnextc = -1; /* C-v */
-
- ioctl (tty, TIOCSLTC, &temp);
- }
-#endif /* TIOCGLTC */
-
- the_ttybuff.sg_flags &= ~ECHO;
- the_ttybuff.sg_flags |= CBREAK;
- ioctl (tty, TIOCSETN, &the_ttybuff);
-}
-
-/* Restore the terminal to its original state. */
-static
-rl_deprep_terminal ()
-{
- int tty = fileno (rl_instream);
-
-#if defined (TIOCLGET) && defined (LPASS8)
- if ((the_ttybuff.sg_flags & (ODDP | EVENP)) == (ODDP | EVENP))
- ioctl (tty, TIOCLSET, &local_mode_flags);
-#endif
-
-#ifdef TIOCSLTC
- ioctl (tty, TIOCSLTC, &original_ltchars);
-#endif
-
-#ifdef TIOCSETC
- ioctl (tty, TIOCSETC, &original_tchars);
-#endif
-
- the_ttybuff.sg_flags = original_tty_flags;
- ioctl (tty, TIOCSETN, &the_ttybuff);
- readline_echoing_p = 1;
-}
-
-#else /* !defined (NEW_TTY_DRIVER) */
-static struct termio otio;
-
-static
-rl_prep_terminal ()
-{
- int tty = fileno (rl_instream);
- struct termio tio;
-
- ioctl (tty, TCGETA, &tio);
- ioctl (tty, TCGETA, &otio);
-
- readline_echoing_p = (tio.c_lflag & ECHO);
-
- tio.c_lflag &= ~(ICANON|ECHO);
- tio.c_iflag &= ~(IXON|ISTRIP|INPCK);
-
-#ifndef HANDLE_SIGNALS
- tio.c_lflag &= ~ISIG;
-#endif
-
- tio.c_cc[VEOF] = 1; /* really: MIN */
- tio.c_cc[VEOL] = 0; /* really: TIME */
- ioctl (tty, TCSETAW,&tio);
-}
-
-static
-rl_deprep_terminal ()
-{
- int tty = fileno (rl_instream);
- ioctl (tty, TCSETAW, &otio);
-}
-#endif /* NEW_TTY_DRIVER */
-
-
-/* **************************************************************** */
-/* */
-/* Utility Functions */
-/* */
-/* **************************************************************** */
-
-/* Return 0 if C is not a member of the class of characters that belong
- in words, or 1 if it is. */
-
-int allow_pathname_alphabetic_chars = 0;
-char *pathname_alphabetic_chars = "/-_=~.#$";
-
-int
-alphabetic (c)
- int c;
-{
- if (pure_alphabetic (c) || (numeric (c)))
- return (1);
-
- if (allow_pathname_alphabetic_chars)
- return ((int)rindex (pathname_alphabetic_chars, c));
- else
- return (0);
-}
-
-/* Return non-zero if C is a numeric character. */
-int
-numeric (c)
- int c;
-{
- return (c >= '0' && c <= '9');
-}
-
-/* Ring the terminal bell. */
-int
-ding ()
-{
- if (readline_echoing_p)
- {
- fprintf (stderr, "\007");
- fflush (stderr);
- }
- return (-1);
-}
-
-/* How to abort things. */
-rl_abort ()
-{
- ding ();
- rl_clear_message ();
- rl_init_argument ();
- rl_pending_input = 0;
-
- defining_kbd_macro = 0;
- while (executing_macro)
- pop_executing_macro ();
-
- longjmp (readline_top_level, 1);
-}
-
-/* Return a copy of the string between FROM and TO.
- FROM is inclusive, TO is not. */
-char *
-rl_copy (from, to)
- int from, to;
-{
- register int length;
- char *copy;
-
- /* Fix it if the caller is confused. */
- if (from > to) {
- int t = from;
- from = to;
- to = t;
- }
-
- length = to - from;
- copy = (char *)xmalloc (1 + length);
- strncpy (copy, the_line + from, length);
- copy[length] = '\0';
- return (copy);
-}
-
-
-/* **************************************************************** */
-/* */
-/* Insert and Delete */
-/* */
-/* **************************************************************** */
-
-
-/* Insert a string of text into the line at point. This is the only
- way that you should do insertion. rl_insert () calls this
- function. */
-rl_insert_text (string)
- char *string;
-{
- extern int doing_an_undo;
- register int i, l = strlen (string);
- while (rl_end + l >= rl_line_buffer_len)
- {
- rl_line_buffer =
- (char *)xrealloc (rl_line_buffer,
- rl_line_buffer_len += DEFAULT_BUFFER_SIZE);
- the_line = rl_line_buffer;
- }
-
- for (i = rl_end; i >= rl_point; i--)
- the_line[i + l] = the_line[i];
- strncpy (the_line + rl_point, string, l);
-
- /* Remember how to undo this if we aren't undoing something. */
- if (!doing_an_undo)
- {
- /* If possible and desirable, concatenate the undos. */
- if ((strlen (string) == 1) &&
- rl_undo_list &&
- (rl_undo_list->what == UNDO_INSERT) &&
- (rl_undo_list->end == rl_point) &&
- (rl_undo_list->end - rl_undo_list->start < 20))
- rl_undo_list->end++;
- else
- rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
- }
- rl_point += l;
- rl_end += l;
- the_line[rl_end] = '\0';
-}
-
-/* Delete the string between FROM and TO. FROM is
- inclusive, TO is not. */
-rl_delete_text (from, to)
- int from, to;
-{
- extern int doing_an_undo;
- register char *text;
-
- /* Fix it if the caller is confused. */
- if (from > to) {
- int t = from;
- from = to;
- to = t;
- }
- text = rl_copy (from, to);
- strncpy (the_line + from, the_line + to, rl_end - to);
-
- /* Remember how to undo this delete. */
- if (!doing_an_undo)
- rl_add_undo (UNDO_DELETE, from, to, text);
- else
- free (text);
-
- rl_end -= (to - from);
- the_line[rl_end] = '\0';
-}
-
-
-/* **************************************************************** */
-/* */
-/* Readline character functions */
-/* */
-/* **************************************************************** */
-
-/* This is not a gap editor, just a stupid line input routine. No hair
- is involved in writing any of the functions, and none should be. */
-
-/* Note that:
-
- rl_end is the place in the string that we would place '\0';
- i.e., it is always safe to place '\0' there.
-
- rl_point is the place in the string where the cursor is. Sometimes
- this is the same as rl_end.
-
- Any command that is called interactively receives two arguments.
- The first is a count: the numeric arg pased to this command.
- The second is the key which invoked this command.
-*/
-
-
-/* **************************************************************** */
-/* */
-/* Movement Commands */
-/* */
-/* **************************************************************** */
-
-/* Note that if you `optimize' the display for these functions, you cannot
- use said functions in other functions which do not do optimizing display.
- I.e., you will have to update the data base for rl_redisplay, and you
- might as well let rl_redisplay do that job. */
-
-/* Move forward COUNT characters. */
-rl_forward (count)
- int count;
-{
- if (count < 0)
- rl_backward (-count);
- else
- while (count)
- {
-#ifdef VI_MODE
- if (rl_point == (rl_end - (rl_editing_mode == vi_mode)))
-#else
- if (rl_point == rl_end)
-#endif
- {
- ding ();
- return;
- }
- else
- rl_point++;
- --count;
- }
-}
-
-/* Move backward COUNT characters. */
-rl_backward (count)
- int count;
-{
- if (count < 0)
- rl_forward (-count);
- else
- while (count)
- {
- if (!rl_point)
- {
- ding ();
- return;
- }
- else
- --rl_point;
- --count;
- }
-}
-
-/* Move to the beginning of the line. */
-rl_beg_of_line ()
-{
- rl_point = 0;
-}
-
-/* Move to the end of the line. */
-rl_end_of_line ()
-{
- rl_point = rl_end;
-}
-
-/* Move forward a word. We do what Emacs does. */
-rl_forward_word (count)
- int count;
-{
- int c;
-
- if (count < 0)
- {
- rl_backward_word (-count);
- return;
- }
-
- while (count)
- {
- if (rl_point == rl_end)
- return;
-
- /* If we are not in a word, move forward until we are in one.
- Then, move forward until we hit a non-alphabetic character. */
- c = the_line[rl_point];
- if (!alphabetic (c))
- {
- while (++rl_point < rl_end)
- {
- c = the_line[rl_point];
- if (alphabetic (c)) break;
- }
- }
- if (rl_point == rl_end) return;
- while (++rl_point < rl_end)
- {
- c = the_line[rl_point];
- if (!alphabetic (c)) break;
- }
- --count;
- }
-}
-
-/* Move backward a word. We do what Emacs does. */
-rl_backward_word (count)
- int count;
-{
- int c;
-
- if (count < 0)
- {
- rl_forward_word (-count);
- return;
- }
-
- while (count)
- {
- if (!rl_point)
- return;
-
- /* Like rl_forward_word (), except that we look at the characters
- just before point. */
-
- c = the_line[rl_point - 1];
- if (!alphabetic (c))
- {
- while (--rl_point)
- {
- c = the_line[rl_point - 1];
- if (alphabetic (c)) break;
- }
- }
-
- while (rl_point)
- {
- c = the_line[rl_point - 1];
- if (!alphabetic (c))
- break;
- else --rl_point;
- }
- --count;
- }
-}
-
-/* Clear the current line. Numeric argument to C-l does this. */
-rl_refresh_line ()
-{
- int curr_line = last_c_pos / screenwidth;
-
- move_vert(curr_line);
- move_cursor_relative (0, the_line); /* XXX is this right */
- rl_forced_update_display ();
- rl_display_fixed = 1;
-}
-
-/* C-l typed to a line without quoting clears the screen, and then reprints
- the prompt and the current input line. Given a numeric arg, redraw only
- the current line. */
-rl_clear_screen ()
-{
- extern char *term_clrpag;
- static void output_character_function ();
-
- if (rl_explicit_arg)
- {
- rl_refresh_line ();
- return;
- }
-
- if (term_clrpag)
- tputs (term_clrpag, 1, output_character_function);
- else
- crlf ();
-
- rl_forced_update_display ();
- rl_display_fixed = 1;
-}
-
-
-/* **************************************************************** */
-/* */
-/* Text commands */
-/* */
-/* **************************************************************** */
-
-/* Insert the character C at the current location, moving point forward. */
-rl_insert (count, c)
- int count, c;
-{
- register int i;
- char *string;
-
- if (count <= 0)
- return;
-
- /* If we can optimize, then do it. But don't let people crash
- readline because of extra large arguments. */
- if (count > 1 && count < 1024)
- {
- string = (char *)alloca (1 + count);
-
- for (i = 0; i < count; i++)
- string[i] = c;
-
- string[i] = '\0';
- rl_insert_text (string);
- return;
- }
-
- if (count > 1024)
- {
- int descreaser;
-
- string = (char *)alloca (1024 + 1);
-
- for (i = 0; i < 1024; i++)
- string[i] = c;
-
- while (count)
- {
- descreaser = (count > 1024 ? 1024 : count);
- string[descreaser] = '\0';
- rl_insert_text (string);
- count -= descreaser;
- }
- return;
- }
-
- /* We are inserting a single character.
- If there is pending input, then make a string of all of the
- pending characters that are bound to rl_insert, and insert
- them all. */
- if (any_typein)
- {
- int slen, key = 0, t;
-
- i = 0;
- string = (char *)alloca (ibuffer_len + 1);
- string[i++] = c;
-
- while ((key = rl_get_char()) != -2 &&
- (keymap[key].type == ISFUNC &&
- keymap[key].function == rl_insert))
- string[i++] = key;
-
- if (key != -2)
- rl_unget_char (key);
-
- string[i] = '\0';
- rl_insert_text (string);
- return;
- }
- else
- {
- /* Inserting a single character. */
- string = (char *)alloca (2);
-
- string[1] = '\0';
- string[0] = c;
- rl_insert_text (string);
- }
-}
-
-/* Insert the next typed character verbatim. */
-rl_quoted_insert (count)
- int count;
-{
- int c = rl_read_key (in_stream);
- rl_insert (count, c);
-}
-
-/* Insert a tab character. */
-rl_tab_insert (count)
- int count;
-{
- rl_insert (count, '\t');
-}
-
-#ifdef VI_MODE
-/* Non-zero means enter insertion mode. */
-static vi_doing_insert = 0;
-#endif
-
-/* What to do when a NEWLINE is pressed. We accept the whole line.
- KEY is the key that invoked this command. I guess it could have
- meaning in the future. */
-rl_newline (count, key)
- int count, key;
-{
-
- rl_done = 1;
-
-#ifdef VI_MODE
- {
- if (vi_doing_insert)
- {
- rl_end_undo_group ();
- vi_doing_insert = 0;
- }
- }
-#endif /* VI_MODE */
-
- if (readline_echoing_p)
- {
- move_vert (vis_botlin);
- vis_botlin = 0;
- crlf ();
- fflush (out_stream);
- rl_display_fixed++;
- }
-}
-
-rl_clean_up_for_exit ()
-{
- if (readline_echoing_p)
- {
- move_vert (vis_botlin);
- vis_botlin = 0;
- fflush (out_stream);
- rl_restart_output ();
- }
-}
-
-/* What to do for some uppercase characters, like meta characters,
- and some characters appearing in emacs_ctlx_keymap. This function
- is just a stub, you bind keys to it and the code in rl_dispatch ()
- is special cased. */
-rl_do_lowercase_version (ignore1, ignore2)
- int ignore1, ignore2;
-{
-}
-
-/* Rubout the character behind point. */
-rl_rubout (count)
- int count;
-{
- if (count < 0)
- {
- rl_delete (-count);
- return;
- }
-
- if (!rl_point)
- {
- ding ();
- return;
- }
-
- if (count > 1)
- {
- int orig_point = rl_point;
- rl_backward (count);
- rl_kill_text (orig_point, rl_point);
- }
- else
- {
- int c = the_line[--rl_point];
- rl_delete_text (rl_point, rl_point + 1);
-
- if (rl_point == rl_end && alphabetic (c) && last_c_pos)
- {
- backspace (1);
- putc (' ', out_stream);
- backspace (1);
- last_c_pos--;
- rl_display_fixed++;
- }
- }
-}
-
-/* Delete the character under the cursor. Given a numeric argument,
- kill that many characters instead. */
-rl_delete (count, invoking_key)
- int count;
-{
- if (count < 0)
- {
- rl_rubout (-count);
- return;
- }
-
- if (rl_point == rl_end)
- {
- ding ();
- return;
- }
-
-#ifdef VI_MODE
- if ((count > 1) || ((count == 1) && (rl_editing_mode == vi_mode)))
-#else
- if (count > 1)
-#endif
- {
- int orig_point = rl_point;
- while (count && (rl_point < rl_end))
- {
- rl_point++;
- count--;
- }
- rl_kill_text (orig_point, rl_point);
- rl_point = orig_point;
- }
- else
- rl_delete_text (rl_point, rl_point + 1);
-}
-
-
-/* **************************************************************** */
-/* */
-/* Kill commands */
-/* */
-/* **************************************************************** */
-
-/* The next two functions mimic unix line editing behaviour, except they
- save the deleted text on the kill ring. This is safer than not saving
- it, and since we have a ring, nobody should get screwed. */
-
-/* This does what C-w does in Unix. We can't prevent people from
- using behaviour that they expect. */
-rl_unix_word_rubout ()
-{
- if (!rl_point) ding ();
- else {
- int orig_point = rl_point;
- while (rl_point && whitespace (the_line[rl_point - 1]))
- rl_point--;
- while (rl_point && !whitespace (the_line[rl_point - 1]))
- rl_point--;
- rl_kill_text (rl_point, orig_point);
- }
-}
-
-/* Here is C-u doing what Unix does. You don't *have* to use these
- key-bindings. We have a choice of killing the entire line, or
- killing from where we are to the start of the line. We choose the
- latter, because if you are a Unix weenie, then you haven't backspaced
- into the line at all, and if you aren't, then you know what you are
- doing. */
-rl_unix_line_discard ()
-{
- if (!rl_point) ding ();
- else {
- rl_kill_text (rl_point, 0);
- rl_point = 0;
- }
-}
-
-
-
-/* **************************************************************** */
-/* */
-/* Commands For Typos */
-/* */
-/* **************************************************************** */
-
-/* Random and interesting things in here. */
-
-
-/* **************************************************************** */
-/* */
-/* Changing Case */
-/* */
-/* **************************************************************** */
-
-/* The three kinds of things that we know how to do. */
-#define UpCase 1
-#define DownCase 2
-#define CapCase 3
-
-/* Uppercase the word at point. */
-rl_upcase_word (count)
- int count;
-{
- rl_change_case (count, UpCase);
-}
-
-/* Lowercase the word at point. */
-rl_downcase_word (count)
- int count;
-{
- rl_change_case (count, DownCase);
-}
-
-/* Upcase the first letter, downcase the rest. */
-rl_capitalize_word (count)
- int count;
-{
- rl_change_case (count, CapCase);
-}
-
-/* The meaty function.
- Change the case of COUNT words, performing OP on them.
- OP is one of UpCase, DownCase, or CapCase.
- If a negative argument is given, leave point where it started,
- otherwise, leave it where it moves to. */
-rl_change_case (count, op)
- int count, op;
-{
- register int start = rl_point, end;
- int state = 0;
-
- rl_forward_word (count);
- end = rl_point;
-
- if (count < 0)
- {
- int temp = start;
- start = end;
- end = temp;
- }
-
- /* We are going to modify some text, so let's prepare to undo it. */
- rl_modifying (start, end);
-
- for (; start < end; start++)
- {
- switch (op)
- {
- case UpCase:
- the_line[start] = to_upper (the_line[start]);
- break;
-
- case DownCase:
- the_line[start] = to_lower (the_line[start]);
- break;
-
- case CapCase:
- if (state == 0)
- {
- the_line[start] = to_upper (the_line[start]);
- state = 1;
- }
- else
- {
- the_line[start] = to_lower (the_line[start]);
- }
- if (!pure_alphabetic (the_line[start]))
- state = 0;
- break;
-
- default:
- abort ();
- }
- }
- rl_point = end;
-}
-
-/* **************************************************************** */
-/* */
-/* Transposition */
-/* */
-/* **************************************************************** */
-
-/* Transpose the words at point. */
-rl_transpose_words (count)
- int count;
-{
- char *word1, *word2;
- int w1_beg, w1_end, w2_beg, w2_end;
- int orig_point = rl_point;
-
- if (!count) return;
-
- /* Find the two words. */
- rl_forward_word (count);
- w2_end = rl_point;
- rl_backward_word (1);
- w2_beg = rl_point;
- rl_backward_word (count);
- w1_beg = rl_point;
- rl_forward_word (1);
- w1_end = rl_point;
-
- /* Do some check to make sure that there really are two words. */
- if ((w1_beg == w2_beg) || (w2_beg < w1_end))
- {
- ding ();
- rl_point = orig_point;
- return;
- }
-
- /* Get the text of the words. */
- word1 = rl_copy (w1_beg, w1_end);
- word2 = rl_copy (w2_beg, w2_end);
-
- /* We are about to do many insertions and deletions. Remember them
- as one operation. */
- rl_begin_undo_group ();
-
- /* Do the stuff at word2 first, so that we don't have to worry
- about word1 moving. */
- rl_point = w2_beg;
- rl_delete_text (w2_beg, w2_end);
- rl_insert_text (word1);
-
- rl_point = w1_beg;
- rl_delete_text (w1_beg, w1_end);
- rl_insert_text (word2);
-
- /* This is exactly correct since the text before this point has not
- changed in length. */
- rl_point = w2_end;
-
- /* I think that does it. */
- rl_end_undo_group ();
- free (word1); free (word2);
-}
-
-/* Transpose the characters at point. If point is at the end of the line,
- then transpose the characters before point. */
-rl_transpose_chars (count)
- int count;
-{
- if (!count)
- return;
-
- if (!rl_point || rl_end < 2) {
- ding ();
- return;
- }
-
- while (count) {
- if (rl_point == rl_end) {
- int t = the_line[rl_point - 1];
- the_line[rl_point - 1] = the_line[rl_point - 2];
- the_line[rl_point - 2] = t;
- } else {
- int t = the_line[rl_point];
- the_line[rl_point] = the_line[rl_point - 1];
- the_line[rl_point - 1] = t;
- if (count < 0 && rl_point)
- rl_point--;
- else
- rl_point++;
- }
- if (count < 0)
- count++;
- else
- count--;
- }
-}
-
-
-/* **************************************************************** */
-/* */
-/* Bogus Flow Control */
-/* */
-/* **************************************************************** */
-
-rl_restart_output (count, key)
- int count, key;
-{
- int fildes = fileno (stdin);
-#ifdef TIOCSTART
- ioctl (fildes, TIOCSTART, 0);
-#endif /* TIOCSTART */
-}
-
-/* **************************************************************** */
-/* */
-/* Completion matching, from readline's point of view. */
-/* */
-/* **************************************************************** */
-
-/* Pointer to the generator function for completion_matches ().
- NULL means to use filename_entry_function (), the default filename
- completer. */
-Function *rl_completion_entry_function = (Function *)NULL;
-
-/* Pointer to alternative function to create matches.
- Function is called with TEXT, START, and END.
- START and END are indices in RL_LINE_BUFFER saying what the boundaries
- of TEXT are.
- If this function exists and returns NULL then call the value of
- rl_completion_entry_function to try to match, otherwise use the
- array of strings returned. */
-Function *rl_attempted_completion_function = (Function *)NULL;
-
-/* Complete the word at or before point. You have supplied the function
- that does the initial simple matching selection algorithm (see
- completion_matches ()). The default is to do filename completion. */
-rl_complete (ignore, invoking_key)
- int ignore, invoking_key;
-{
- rl_complete_internal (TAB);
- if (running_in_emacs)
- printf ("%s", the_line);
-}
-
-/* List the possible completions. See description of rl_complete (). */
-rl_possible_completions ()
-{
- rl_complete_internal ('?');
-}
-
-/* The user must press "y" or "n". Non-zero return means "y" pressed. */
-get_y_or_n ()
-{
- int c;
- loop:
- c = rl_read_key (in_stream);
- if (c == 'y' || c == 'Y') return (1);
- if (c == 'n' || c == 'N') return (0);
- if (c == ABORT_CHAR) rl_abort ();
- ding (); goto loop;
-}
-
-/* Up to this many items will be displayed in response to a
- possible-completions call. After that, we ask the user if
- she is sure she wants to see them all. */
-int rl_completion_query_items = 100;
-
-/* The basic list of characters that signal a break between words for the
- completer routine. The contents of this variable is what breaks words
- in the shell, i.e. " \t\n\"\\'`@$><=" */
-char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=";
-
-/* The list of characters that signal a break between words for
- rl_complete_internal. The default list is the contents of
- rl_basic_word_break_characters. */
-char *rl_completer_word_break_characters = (char *)NULL;
-
-/* List of characters that are word break characters, but should be left
- in TEXT when it is passed to the completion function. The shell uses
- this to help determine what kind of completing to do. */
-char *rl_special_prefixes = (char *)NULL;
-
-/* If non-zero, then disallow duplicates in the matches. */
-int rl_ignore_completion_duplicates = 1;
-
-/* Non-zero means that the results of the matches are to be treated
- as filenames. This is ALWAYS zero on entry, and can only be changed
- within a completion entry finder function. */
-int rl_filename_completion_desired = 0;
-
-/* Complete the word at or before point.
- WHAT_TO_DO says what to do with the completion.
- `?' means list the possible completions.
- TAB means do standard completion.
- `*' means insert all of the possible completions. */
-rl_complete_internal (what_to_do)
- int what_to_do;
-{
- char *filename_completion_function ();
- char **completion_matches (), **matches;
- Function *our_func;
- int start, end, delimiter = 0;
- char *text;
-
- if (rl_completion_entry_function)
- our_func = rl_completion_entry_function;
- else
- our_func = (int (*)())filename_completion_function;
-
- /* Only the completion entry function can change this. */
- rl_filename_completion_desired = 0;
-
- /* We now look backwards for the start of a filename/variable word. */
- end = rl_point;
- if (rl_point)
- {
- while (--rl_point &&
- !rindex (rl_completer_word_break_characters, the_line[rl_point]));
-
- /* If we are at a word break, then advance past it. */
- if (rindex (rl_completer_word_break_characters, (the_line[rl_point])))
- {
- /* If the character that caused the word break was a quoting
- character, then remember it as the delimiter. */
- if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1)
- delimiter = the_line[rl_point];
-
- /* If the character isn't needed to determine something special
- about what kind of completion to perform, then advance past it. */
-
- if (!rl_special_prefixes ||
- !rindex (rl_special_prefixes, the_line[rl_point]))
- rl_point++;
- }
- }
-
- start = rl_point;
- rl_point = end;
- text = rl_copy (start, end);
-
- /* If the user wants to TRY to complete, but then wants to give
- up and use the default completion function, they set the
- variable rl_attempted_completion_function. */
- if (rl_attempted_completion_function)
- {
- matches =
- (char **)(*rl_attempted_completion_function) (text, start, end);
-
- if (matches)
- goto after_usual_completion;
- }
-
- matches = completion_matches (text, our_func, start, end);
-
- after_usual_completion:
- free (text);
-
- if (!matches)
- ding ();
- else
- {
- register int i;
-
- some_matches:
-
- /* It seems to me that in all the cases we handle we would like
- to ignore duplicate possiblilities. Scan for the text to
- insert being identical to the other completions. */
- if (rl_ignore_completion_duplicates)
- {
- char *lowest_common;
- int j, newlen = 0;
-
- /* Sort the items. */
- /* It is safe to sort this array, because the lowest common
- denominator found in matches[0] will remain in place. */
- for (i = 0; matches[i]; i++);
- qsort (matches, i, sizeof (char *), compare_strings);
-
- /* Remember the lowest common denimator for it may be unique. */
- lowest_common = savestring (matches[0]);
-
- for (i = 0; matches[i + 1]; i++)
- {
- if (strcmp (matches[i], matches[i + 1]) == 0)
- {
- free (matches[i]);
- matches[i] = (char *)-1;
- }
- else
- newlen++;
- }
-
- /* We have marked all the dead slots with (char *)-1.
- Copy all the non-dead entries into a new array. */
- {
- char **temp_array =
- (char **)malloc ((3 + newlen) * sizeof (char *));
-
- for (i = 1, j = 1; matches[i]; i++)
- if (matches[i] != (char *)-1)
- temp_array[j++] = matches[i];
- temp_array[j] = (char *)NULL;
-
- if (matches[0] != (char *)-1)
- free (matches[0]);
- free (matches);
-
- matches = temp_array;
- }
-
- /* Place the lowest common denominator back in [0]. */
- matches[0] = lowest_common;
-
- /* If there is one string left, and it is identical to the
- lowest common denominator, then the LCD is the string to
- insert. */
- if (j == 2 && strcmp (matches[0], matches[1]) == 0)
- {
- free (matches[1]);
- matches[1] = (char *)NULL;
- }
- }
-
- switch (what_to_do)
- {
- case TAB:
- rl_delete_text (start, rl_point);
- rl_point = start;
- rl_insert_text (matches[0]);
-
- /* If there are more matches, ring the bell to indicate.
- If this was the only match, and we are hacking files,
- check the file to see if it was a directory. If so,
- add a '/' to the name. If not, and we are at the end
- of the line, then add a space. */
- if (matches[1])
- {
- ding (); /* There are other matches remaining. */
- }
- else
- {
- char temp_string[2];
-
- temp_string[0] = delimiter ? delimiter : ' ';
- temp_string[1] = '\0';
-
- if (rl_filename_completion_desired)
- {
- struct stat finfo;
- char *tilde_expand ();
- char *filename = tilde_expand (matches[0]);
-
- if ((stat (filename, &finfo) == 0) &&
- ((finfo.st_mode & S_IFMT) == S_IFDIR))
- {
- if (the_line[rl_point] != '/')
- rl_insert_text ("/");
- }
- else
- {
- if (rl_point == rl_end)
- rl_insert_text (temp_string);
- }
- free (filename);
- }
- else
- {
- if (rl_point == rl_end)
- rl_insert_text (temp_string);
- }
- }
- break;
-
- case '*':
- {
- int i = 1;
-
- rl_delete_text (start, rl_point);
- rl_point = start;
- rl_begin_undo_group ();
- if (matches[1])
- {
- while (matches[i])
- {
- rl_insert_text (matches[i++]);
- rl_insert_text (" ");
- }
- }
- else
- {
- rl_insert_text (matches[0]);
- rl_insert_text (" ");
- }
- rl_end_undo_group ();
- }
- break;
-
-
- case '?':
- {
- int len, count, limit, max = 0;
- int j, k, l;
-
- /* Handle simple case first. What if there is only one answer? */
- if (!matches[1])
- {
- char *temp;
-
- if (rl_filename_completion_desired)
- temp = rindex (matches[0], '/');
- else
- temp = (char *)NULL;
-
- if (!temp)
- temp = matches[0];
- else
- temp++;
-
- crlf ();
- fprintf (out_stream, "%s", temp);
- crlf ();
- goto restart;
- }
-
- /* There is more than one answer. Find out how many there are,
- and find out what the maximum printed length of a single entry
- is. */
- for (i = 1; matches[i]; i++)
- {
- char *temp = (char *)NULL;
-
- /* If we are hacking filenames, then only count the characters
- after the last slash in the pathname. */
- if (rl_filename_completion_desired)
- temp = rindex (matches[i], '/');
- else
- temp = (char *)NULL;
-
- if (!temp)
- temp = matches[i];
- else
- temp++;
-
- if (strlen (temp) > max)
- max = strlen (temp);
- }
-
- len = i;
-
- /* If there are many items, then ask the user if she
- really wants to see them all. */
- if (len >= rl_completion_query_items)
- {
- crlf ();
- fprintf (out_stream,
- "There are %d possibilities. Do you really", len);
- crlf ();
- fprintf (out_stream, "wish to see them all? (y or n)");
- fflush (out_stream);
- if (!get_y_or_n ())
- {
- crlf ();
- goto restart;
- }
- }
- /* How many items of MAX length can we fit in the screen window? */
- max += 2;
- limit = screenwidth / max;
- if (limit != 1 && (limit * max == screenwidth))
- limit--;
-
- /* How many iterations of the printing loop? */
- count = (len + (limit - 1)) / limit;
-
- /* Watch out for special case. If LEN is less than LIMIT, then
- just do the inner printing loop. */
- if (len < limit) count = 1;
-
- /* Sort the items if they are not already sorted. */
- if (!rl_ignore_completion_duplicates)
- {
- qsort (matches, len, sizeof (char *), compare_strings);
- }
-
- /* Print the sorted items, up-and-down alphabetically, like
- ls might. */
- crlf ();
-
- for (i = 1; i < count + 1; i++)
- {
- for (j = 0, l = i; j < limit; j++)
- {
- if (l > len || !matches[l])
- {
- break;
- }
- else
- {
- char *temp = (char *)NULL;
-
- if (rl_filename_completion_desired)
- temp = rindex (matches[l], '/');
- else
- temp = (char *)NULL;
-
- if (!temp)
- temp = matches[l];
- else
- temp++;
-
- fprintf (out_stream, "%s", temp);
- for (k = 0; k < max - strlen (temp); k++)
- putc (' ', out_stream);
- }
- l += count;
- }
- crlf ();
- }
- restart:
-
- rl_on_new_line ();
- }
- break;
-
- default:
- abort ();
- }
-
- for (i = 0; matches[i]; i++)
- free (matches[i]);
- free (matches);
- }
-}
-
-/* A completion function for usernames.
- TEXT contains a partial username preceded by a random
- character (usually `~'). */
-char *
-username_completion_function (text, state)
- int state;
- char *text;
-{
- static char *username = (char *)NULL;
- static struct passwd *entry;
- static int namelen;
-
- if (!state)
- {
- if (username)
- free (username);
- username = savestring (&text[1]);
- namelen = strlen (username);
- setpwent ();
- }
-
- while (entry = getpwent ())
- {
- if (strncmp (username, entry->pw_name, namelen) == 0)
- break;
- }
-
- if (!entry)
- {
- endpwent ();
- return ((char *)NULL);
- }
- else
- {
- char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
- *value = *text;
- strcpy (value + 1, entry->pw_name);
- rl_filename_completion_desired = 1;
- return (value);
- }
-}
-
-/* If non-null, this contains the address of a function to call if the
- standard meaning for expanding a tilde fails. The function is called
- with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
- which is the expansion, or a NULL pointer if there is no expansion. */
-Function *rl_tilde_expander = (Function *)NULL;
-
-/* Expand FILENAME if it begins with a tilde. This always returns
- a new string. */
-char *
-tilde_expand (filename)
- char *filename;
-{
- char *dirname = filename ? savestring (filename) : (char *)NULL;
-
- if (dirname && *dirname == '~')
- {
- char *temp_name;
- if (!dirname[1] || dirname[1] == '/')
- {
- /* Prepend $HOME to the rest of the string. */
- char *temp_home = (char *)getenv ("HOME");
-
- temp_name = (char *)alloca (1 + strlen (&dirname[1])
- + (temp_home? strlen (temp_home) : 0));
- temp_name[0] = '\0';
- if (temp_home)
- strcpy (temp_name, temp_home);
- strcat (temp_name, &dirname[1]);
- free (dirname);
- dirname = savestring (temp_name);
- }
- else
- {
- struct passwd *getpwnam (), *user_entry;
- char *username = (char *)alloca (257);
- int i, c;
-
- for (i = 1; c = dirname[i]; i++)
- {
- if (c == '/') break;
- else username[i - 1] = c;
- }
- username[i - 1] = '\0';
-
- if (!(user_entry = getpwnam (username)))
- {
- /* If the calling program has a special syntax for
- expanding tildes, and we couldn't find a standard
- expansion, then let them try. */
- if (rl_tilde_expander)
- {
- char *expansion;
-
- expansion = (char *)(*rl_tilde_expander) (username);
-
- if (expansion)
- {
- temp_name = (char *)alloca (1 + strlen (expansion)
- + strlen (&dirname[i]));
- strcpy (temp_name, expansion);
- strcat (temp_name, &dirname[i]);
- free (expansion);
- goto return_name;
- }
- }
- /*
- * We shouldn't report errors.
- */
- }
- else
- {
- temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir)
- + strlen (&dirname[i]));
- strcpy (temp_name, user_entry->pw_dir);
- strcat (temp_name, &dirname[i]);
- return_name:
- free (dirname);
- dirname = savestring (temp_name);
- }
- }
- }
- return (dirname);
-}
-
-
-/* **************************************************************** */
-/* */
-/* Undo, and Undoing */
-/* */
-/* **************************************************************** */
-
-/* Non-zero tells rl_delete_text and rl_insert_text to not add to
- the undo list. */
-int doing_an_undo = 0;
-
-/* The current undo list for THE_LINE. */
-UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
-
-/* Remember how to undo something. Concatenate some undos if that
- seems right. */
-rl_add_undo (what, start, end, text)
- enum undo_code what;
- int start, end;
- char *text;
-{
- UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
- temp->what = what;
- temp->start = start;
- temp->end = end;
- temp->text = text;
- temp->next = rl_undo_list;
- rl_undo_list = temp;
-}
-
-/* Free the existing undo list. */
-free_undo_list ()
-{
- while (rl_undo_list) {
- UNDO_LIST *release = rl_undo_list;
- rl_undo_list = rl_undo_list->next;
-
- if (release->what == UNDO_DELETE)
- free (release->text);
-
- free (release);
- }
-}
-
-/* Undo the next thing in the list. Return 0 if there
- is nothing to undo, or non-zero if there was. */
-int
-rl_do_undo ()
-{
- UNDO_LIST *release;
- int waiting_for_begin = 0;
-
-undo_thing:
- if (!rl_undo_list)
- return (0);
-
- doing_an_undo = 1;
-
- switch (rl_undo_list->what) {
-
- /* Undoing deletes means inserting some text. */
- case UNDO_DELETE:
- rl_point = rl_undo_list->start;
- rl_insert_text (rl_undo_list->text);
- free (rl_undo_list->text);
- break;
-
- /* Undoing inserts means deleting some text. */
- case UNDO_INSERT:
- rl_delete_text (rl_undo_list->start, rl_undo_list->end);
- rl_point = rl_undo_list->start;
- break;
-
- /* Undoing an END means undoing everything 'til we get to
- a BEGIN. */
- case UNDO_END:
- waiting_for_begin++;
- break;
-
- /* Undoing a BEGIN means that we are done with this group. */
- case UNDO_BEGIN:
- if (waiting_for_begin)
- waiting_for_begin--;
- else
- abort ();
- break;
- }
-
- doing_an_undo = 0;
-
- release = rl_undo_list;
- rl_undo_list = rl_undo_list->next;
- free (release);
-
- if (waiting_for_begin)
- goto undo_thing;
-
- return (1);
-}
-
-/* Begin a group. Subsequent undos are undone as an atomic operation. */
-rl_begin_undo_group ()
-{
- rl_add_undo (UNDO_BEGIN, 0, 0, 0);
-}
-
-/* End an undo group started with rl_begin_undo_group (). */
-rl_end_undo_group ()
-{
- rl_add_undo (UNDO_END, 0, 0, 0);
-}
-
-/* Save an undo entry for the text from START to END. */
-rl_modifying (start, end)
- int start, end;
-{
- if (start > end)
- {
- int t = start;
- start = end;
- end = t;
- }
-
- if (start != end)
- {
- char *temp = rl_copy (start, end);
- rl_begin_undo_group ();
- rl_add_undo (UNDO_DELETE, start, end, temp);
- rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
- rl_end_undo_group ();
- }
-}
-
-/* Revert the current line to its previous state. */
-rl_revert_line ()
-{
- if (!rl_undo_list) ding ();
- else {
- while (rl_undo_list)
- rl_do_undo ();
- }
-}
-
-/* Do some undoing of things that were done. */
-rl_undo_command (count)
-{
- if (count < 0) return; /* Nothing to do. */
-
- while (count)
- {
- if (rl_do_undo ())
- {
- count--;
- }
- else
- {
- ding ();
- break;
- }
- }
-}
-
-/* **************************************************************** */
-/* */
-/* History Utilities */
-/* */
-/* **************************************************************** */
-
-/* We already have a history library, and that is what we use to control
- the history features of readline. However, this is our local interface
- to the history mechanism. */
-
-/* While we are editing the history, this is the saved
- version of the original line. */
-HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL;
-
-/* Set the history pointer back to the last entry in the history. */
-start_using_history ()
-{
- using_history ();
- if (saved_line_for_history)
- free_history_entry (saved_line_for_history);
-
- saved_line_for_history = (HIST_ENTRY *)NULL;
-}
-
-/* Free the contents (and containing structure) of a HIST_ENTRY. */
-free_history_entry (entry)
- HIST_ENTRY *entry;
-{
- if (!entry) return;
- if (entry->line)
- free (entry->line);
- free (entry);
-}
-
-/* Perhaps put back the current line if it has changed. */
-maybe_replace_line ()
-{
- HIST_ENTRY *temp = current_history ();
-
- /* If the current line has changed, save the changes. */
- if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) {
- temp = replace_history_entry (where_history (), the_line, rl_undo_list);
- free (temp->line);
- free (temp);
- }
-}
-
-/* Put back the saved_line_for_history if there is one. */
-maybe_unsave_line ()
-{
- if (saved_line_for_history) {
- strcpy (the_line, saved_line_for_history->line);
- rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
- free_history_entry (saved_line_for_history);
- saved_line_for_history = (HIST_ENTRY *)NULL;
- rl_end = rl_point = strlen (the_line);
- } else {
- ding ();
- }
-}
-
-/* Save the current line in saved_line_for_history. */
-maybe_save_line ()
-{
- if (!saved_line_for_history) {
- saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
- saved_line_for_history->line = savestring (the_line);
- saved_line_for_history->data = (char *)rl_undo_list;
- }
-}
-
-
-
-/* **************************************************************** */
-/* */
-/* History Commands */
-/* */
-/* **************************************************************** */
-
-/* Meta-< goes to the start of the history. */
-rl_beginning_of_history ()
-{
- rl_get_previous_history (1 + where_history ());
-}
-
-/* Meta-> goes to the end of the history. (The current line). */
-rl_end_of_history ()
-{
- maybe_replace_line ();
- using_history ();
- maybe_unsave_line ();
-}
-
-/* Move down to the next history line. */
-rl_get_next_history (count)
- int count;
-{
- HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
-
- if (count < 0)
- {
- rl_get_previous_history (-count);
- return;
- }
-
- if (!count)
- return;
-
- maybe_replace_line ();
-
- while (count)
- {
- temp = next_history ();
- if (!temp)
- break;
- --count;
- }
-
- if (!temp)
- maybe_unsave_line ();
- else
- {
- strcpy (the_line, temp->line);
- rl_undo_list = (UNDO_LIST *)temp->data;
- rl_end = rl_point = strlen (the_line);
- }
-}
-
-/* Get the previous item out of our interactive history, making it the current
- line. If there is no previous history, just ding. */
-rl_get_previous_history (count)
- int count;
-{
- HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL;
- HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
-
- if (count < 0)
- {
- rl_get_next_history (-count);
- return;
- }
-
- if (!count)
- return;
-
- /* If we don't have a line saved, then save this one. */
- maybe_save_line ();
-
- /* If the current line has changed, save the changes. */
- maybe_replace_line ();
-
- while (count)
- {
- temp = previous_history ();
- if (!temp)
- break;
- else
- old_temp = temp;
- --count;
- }
-
- /* If there was a large argument, and we moved back to the start of the
- history, that is not an error. So use the last value found. */
- if (!temp && old_temp)
- temp = old_temp;
-
- if (!temp)
- ding ();
- else
- {
- strcpy (the_line, temp->line);
- rl_undo_list = (UNDO_LIST *)temp->data;
- rl_end = rl_point = strlen (the_line);
-#ifdef VI_MODE
- if (rl_editing_mode == vi_mode)
- rl_point = 0;
-#endif /* VI_MODE */
- }
-}
-
-/* There is a command in ksh which yanks into this line, the last word
- of the previous line. Here it is. We left it on M-. */
-rl_yank_previous_last_arg (ignore)
- int ignore;
-{
-}
-
-
-
-/* **************************************************************** */
-/* */
-/* I-Search and Searching */
-/* */
-/* **************************************************************** */
-
-/* Search backwards through the history looking for a string which is typed
- interactively. Start with the current line. */
-rl_reverse_search_history (sign, key)
- int sign;
- int key;
-{
- rl_search_history (-sign, key);
-}
-
-/* Search forwards through the history looking for a string which is typed
- interactively. Start with the current line. */
-rl_forward_search_history (sign, key)
- int sign;
- int key;
-{
- rl_search_history (sign, key);
-}
-
-/* Display the current state of the search in the echo-area.
- SEARCH_STRING contains the string that is being searched for,
- DIRECTION is zero for forward, or 1 for reverse,
- WHERE is the history list number of the current line. If it is
- -1, then this line is the starting one. */
-rl_display_search (search_string, reverse_p, where)
- char *search_string;
- int reverse_p, where;
-{
- char *message = (char *)NULL;
-
- message =
- (char *)alloca (1 + (search_string ? strlen (search_string) : 0) + 30);
-
- *message = '\0';
-
-#ifdef NEVER
- if (where != -1)
- sprintf (message, "[%d]", where + history_base);
-#endif
-
- strcat (message, "(");
-
- if (reverse_p)
- strcat (message, "reverse-");
-
- strcat (message, "i-search)`");
-
- if (search_string)
- strcat (message, search_string);
-
- strcat (message, "': ");
- rl_message (message, 0, 0);
- rl_redisplay ();
-}
-
-/* Search through the history looking for an interactively typed string.
- This is analogous to i-search. We start the search in the current line.
- DIRECTION is which direction to search; > 0 means forward, < 0 means
- backwards. */
-rl_search_history (direction, invoking_key)
- int direction;
- int invoking_key;
-{
- /* The string that the user types in to search for. */
- char *search_string = (char *)alloca (128);
-
- /* The current length of SEARCH_STRING. */
- int search_string_index;
-
- /* The list of lines to search through. */
- char **lines;
-
- /* The length of LINES. */
- int hlen;
-
- /* Where we get LINES from. */
- HIST_ENTRY **hlist = history_list ();
-
- int orig_point = rl_point;
- int orig_line = where_history ();
- int last_found_line = orig_line;
- int c, done = 0;
- register int i = 0;
-
-
- /* The line currently being searched. */
- char *sline;
-
- /* Offset in that line. */
- int index;
-
- /* Non-zero if we are doing a reverse search. */
- int reverse = (direction < 0);
-
- /* Create an arrary of pointers to the lines that we want to search. */
-
- maybe_replace_line ();
- if (hlist)
- for (i = 0; hlist[i]; i++);
-
- /* Allocate space for this many lines, +1 for the current input line,
- and remember those lines. */
- lines = (char **)alloca ((1 + (hlen = i)) * sizeof (char *));
- for (i = 0; i < hlen; i++)
- lines[i] = hlist[i]->line;
-
- if (saved_line_for_history)
- lines[i] = saved_line_for_history->line;
- else
- {
- /* So I have to type it in this way instead. */
- lines[i] = (char *)alloca (1 + strlen (the_line));
- strcpy (lines[i], &the_line[0]);
- }
-
- hlen++;
-
- /* The line where we start the search. */
- i = orig_line;
-
- /* Initialize search parameters. */
- *search_string = '\0';
- search_string_index = 0;
-
- rl_display_search (search_string, reverse, -1);
-
- sline = the_line;
- index = rl_point;
-
- while (!done)
- {
- c = rl_read_key (in_stream);
-
- /* Hack C to Do What I Mean. */
- {
- Function *f = (Function *)NULL;
-
- if (keymap[c].type == ISFUNC)
- f = keymap[c].function;
-
- if (f == rl_reverse_search_history)
- c = reverse ? -1 : -2;
- else if (f == rl_forward_search_history)
- c = !reverse ? -1 : -2;
- }
-
- switch (c)
- {
- case ESC:
- done = 1;
- continue;
-
- /* case invoking_key: */
- case -1:
- goto search_again;
-
- /* switch directions */
- case -2:
- direction = -direction;
- reverse = (direction < 0);
-
- goto do_search;
-
- case CTRL ('G'):
- strcpy (the_line, lines[orig_line]);
- rl_point = orig_point;
- rl_end = strlen (the_line);
- rl_clear_message ();
- return;
-
- default:
- if (c < 32 || c > 126)
- {
- rl_execute_next (c);
- done = 1;
- continue;
- }
- else
- {
- search_string[search_string_index++] = c;
- search_string[search_string_index] = '\0';
- goto do_search;
-
- search_again:
-
- if (!search_string_index)
- continue;
- else
- {
- if (reverse)
- --index;
- else
- if (index != strlen (sline))
- ++index;
- else
- ding ();
- }
- do_search:
-
- while (1)
- {
- if (reverse)
- {
- while (index >= 0)
- if (strncmp
- (search_string,
- sline + index,
- search_string_index) == 0)
- goto string_found;
- else
- index--;
- }
- else
- {
- register int limit =
- (strlen (sline) - search_string_index) + 1;
-
- while (index < limit)
- {
- if (strncmp (search_string,
- sline + index,
- search_string_index) == 0)
- goto string_found;
- index++;
- }
- }
-
- next_line:
- i += direction;
-
- /* At limit for direction? */
- if ((reverse && i < 0) ||
- (!reverse && i == hlen))
- goto search_failed;
-
- sline = lines[i];
- if (reverse)
- index = strlen (sline);
- else
- index = 0;
-
- /* If the search string is longer than the current
- line, no match. */
- if (search_string_index > strlen (sline))
- goto next_line;
-
- /* Start actually searching. */
- if (reverse)
- index -= search_string_index;
- }
-
- search_failed:
- /* We cannot find the search string. Ding the bell. */
- ding ();
- i = last_found_line;
- break;
-
- string_found:
- /* We have found the search string. Just display it. But don't
- actually move there in the history list until the user accepts
- the location. */
- strcpy (the_line, lines[i]);
- rl_point = index;
- rl_end = strlen (the_line);
- last_found_line = i;
- rl_display_search (search_string, reverse,
- (i == orig_line) ? -1 : i);
- }
- }
- continue;
- }
- /* The user has won. They found the string that they wanted. Now all
- we have to do is place them there. */
- {
- int now = last_found_line;
-
- /* First put back the original state. */
- strcpy (the_line, lines[orig_line]);
-
- if (now < orig_line)
- rl_get_previous_history (orig_line - now);
- else
- rl_get_next_history (now - orig_line);
-
- rl_point = index;
- rl_clear_message ();
- }
-}
-
-/* Make C be the next command to be executed. */
-rl_execute_next (c)
- int c;
-{
- rl_pending_input = c;
-}
-
-/* **************************************************************** */
-/* */
-/* Killing Mechanism */
-/* */
-/* **************************************************************** */
-
-/* What we assume for a max number of kills. */
-#define DEFAULT_MAX_KILLS 10
-
-/* The real variable to look at to find out when to flush kills. */
-int rl_max_kills = DEFAULT_MAX_KILLS;
-
-/* Where to store killed text. */
-char **rl_kill_ring = (char **)NULL;
-
-/* Where we are in the kill ring. */
-int rl_kill_index = 0;
-
-/* How many slots we have in the kill ring. */
-int rl_kill_ring_length = 0;
-
-/* How to say that you only want to save a certain amount
- of kill material. */
-rl_set_retained_kills (num)
- int num;
-{}
-
-/* The way to kill something. This appends or prepends to the last
- kill, if the last command was a kill command. if FROM is less
- than TO, then the text is appended, otherwise prepended. If the
- last command was not a kill command, then a new slot is made for
- this kill. */
-rl_kill_text (from, to)
- int from, to;
-{
- int slot;
- char *text = rl_copy (from, to);
-
- /* Is there anything to kill? */
- if (from == to) {
- free (text);
- last_command_was_kill++;
- return;
- }
-
- /* Delete the copied text from the line. */
- rl_delete_text (from, to);
-
- /* First, find the slot to work with. */
- if (!last_command_was_kill) {
-
- /* Get a new slot. */
- if (!rl_kill_ring) {
-
- /* If we don't have any defined, then make one. */
- rl_kill_ring =
- (char **)xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *));
- slot = 1;
-
- } else {
-
- /* We have to add a new slot on the end, unless we have exceeded
- the max limit for remembering kills. */
- slot = rl_kill_ring_length;
- if (slot == rl_max_kills) {
- register int i;
- free (rl_kill_ring[0]);
- for (i = 0; i < slot; i++)
- rl_kill_ring[i] = rl_kill_ring[i + 1];
- } else {
- rl_kill_ring =
- (char **)xrealloc (rl_kill_ring,
- ((slot = (rl_kill_ring_length += 1)) + 1)
- * sizeof (char *));
- }
- }
- slot--;
- } else {
- slot = rl_kill_ring_length - 1;
- }
-
- /* If the last command was a kill, prepend or append. */
- if (last_command_was_kill) {
- char *old = rl_kill_ring[slot];
- char *new = (char *)xmalloc (1 + strlen (old) + strlen (text));
-
- if (from < to) {
- strcpy (new, old);
- strcat (new, text);
- } else {
- strcpy (new, text);
- strcat (new, old);
- }
- free (old);
- free (text);
- rl_kill_ring[slot] = new;
- } else {
- rl_kill_ring[slot] = text;
- }
- rl_kill_index = slot;
- last_command_was_kill++;
-}
-
-/* Now REMEMBER! In order to do prepending or appending correctly, kill
- commands always make rl_point's original position be the FROM argument,
- and rl_point's extent be the TO argument. */
-
-
-/* **************************************************************** */
-/* */
-/* Killing Commands */
-/* */
-/* **************************************************************** */
-
-/* Delete the word at point, saving the text in the kill ring. */
-rl_kill_word (count)
- int count;
-{
- int orig_point = rl_point;
-
- if (count < 0)
- rl_backward_kill_word (-count);
- else
- {
- rl_forward_word (count);
-
- if (rl_point != orig_point)
- rl_kill_text (orig_point, rl_point);
-
- rl_point = orig_point;
- }
-}
-
-/* Rubout the word before point, placing it on the kill ring. */
-rl_backward_kill_word (count)
- int count;
-{
- int orig_point = rl_point;
-
- if (count < 0)
- rl_kill_word (-count);
- else
- {
- rl_backward_word (count);
-
- if (rl_point != orig_point)
- rl_kill_text (orig_point, rl_point);
- }
-}
-
-/* Kill from here to the end of the line. If DIRECTION is negative, kill
- back to the line start instead. */
-rl_kill_line (direction)
- int direction;
-{
- int orig_point = rl_point;
-
- if (direction < 0)
- rl_backward_kill_line (1);
- else
- {
- rl_end_of_line ();
- if (orig_point != rl_point)
- rl_kill_text (orig_point, rl_point);
- rl_point = orig_point;
- }
-}
-
-/* Kill backwards to the start of the line. If DIRECTION is negative, kill
- forwards to the line end instead. */
-rl_backward_kill_line (direction)
- int direction;
-{
- int orig_point = rl_point;
-
- if (direction < 0)
- rl_kill_line (1);
- else
- {
- if (!rl_point)
- ding ();
- else
- {
- rl_beg_of_line ();
- rl_kill_text (orig_point, rl_point);
- }
- }
-}
-
-/* Yank back the last killed text. This ignores arguments. */
-rl_yank ()
-{
- if (!rl_kill_ring) rl_abort ();
- rl_insert_text (rl_kill_ring[rl_kill_index]);
-}
-
-/* If the last command was yank, or yank_pop, and the text just
- before point is identical to the current kill item, then
- delete that text from the line, rotate the index down, and
- yank back some other text. */
-rl_yank_pop ()
-{
- int l;
-
- if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) ||
- !rl_kill_ring)
- {
- rl_abort ();
- }
-
- l = strlen (rl_kill_ring[rl_kill_index]);
- if (((rl_point - l) >= 0) &&
- (strncmp (the_line + (rl_point - l),
- rl_kill_ring[rl_kill_index], l) == 0))
- {
- rl_delete_text ((rl_point - l), rl_point);
- rl_point -= l;
- rl_kill_index--;
- if (rl_kill_index < 0)
- rl_kill_index = rl_kill_ring_length - 1;
- rl_yank ();
- }
- else
- rl_abort ();
-
-}
-
-/* Yank the COUNTth argument from the previous history line. */
-rl_yank_nth_arg (count, ignore)
- int count;
-{
- register HIST_ENTRY *entry = previous_history ();
- char *arg;
-
- if (entry)
- next_history ();
- else
- {
- ding ();
- return;
- }
-
- arg = history_arg_extract (count, count, entry->line);
- if (!arg || !*arg)
- {
- ding ();
- return;
- }
-
- rl_begin_undo_group ();
- if (rl_point && the_line[rl_point - 1] != ' ')
- rl_insert_text (" ");
- rl_insert_text (arg);
- free (arg);
- rl_end_undo_group ();
-}
-
-/* Vi Mode. */
-#ifdef VI_MODE
-#include "vi_mode.c"
-#endif /* VI_MODE */
-
-/* How to toggle back and forth between editing modes. */
-rl_vi_editing_mode ()
-{
-#ifdef VI_MODE
- rl_editing_mode = vi_mode;
- rl_vi_insertion_mode ();
-#endif /* VI_MODE */
-}
-
-rl_emacs_editing_mode ()
-{
- rl_editing_mode = emacs_mode;
- keymap = emacs_standard_keymap;
-}
-
-
-/* **************************************************************** */
-/* */
-/* Completion */
-/* */
-/* **************************************************************** */
-
-/* Non-zero means that case is not significant in completion. */
-int completion_case_fold = 0;
-
-/* Return an array of (char *) which is a list of completions for TEXT.
- If there are no completions, return a NULL pointer.
- The first entry in the returned array is the substitution for TEXT.
- The remaining entries are the possible completions.
- The array is terminated with a NULL pointer.
-
- ENTRY_FUNCTION is a function of two args, and returns a (char *).
- The first argument is TEXT.
- The second is a state argument; it should be zero on the first call, and
- non-zero on subsequent calls. It returns a NULL pointer to the caller
- when there are no more matches.
- */
-char **
-completion_matches (text, entry_function)
- char *text;
- char *(*entry_function) ();
-{
- /* Number of slots in match_list. */
- int match_list_size;
-
- /* The list of matches. */
- char **match_list =
- (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
-
- /* Number of matches actually found. */
- int matches = 0;
-
- /* Temporary string binder. */
- char *string;
-
- match_list[1] = (char *)NULL;
-
- while (string = (*entry_function) (text, matches))
- {
- if (matches + 1 == match_list_size)
- match_list =
- (char **)xrealloc (match_list,
- ((match_list_size += 10) + 1) * sizeof (char *));
-
- match_list[++matches] = string;
- match_list[matches + 1] = (char *)NULL;
- }
-
- /* If there were any matches, then look through them finding out the
- lowest common denominator. That then becomes match_list[0]. */
- if (matches)
- {
- register int i = 1;
- int low = 100000; /* Count of max-matched characters. */
-
- /* If only one match, just use that. */
- if (matches == 1)
- {
- match_list[0] = match_list[1];
- match_list[1] = (char *)NULL;
- }
- else
- {
- /* Otherwise, compare each member of the list with
- the next, finding out where they stop matching. */
-
- while (i < matches)
- {
- register int c1, c2, si;
-
- if (completion_case_fold)
- {
- for (si = 0;
- (c1 = to_lower(match_list[i][si])) &&
- (c2 = to_lower(match_list[i + 1][si]));
- si++)
- if (c1 != c2) break;
- }
- else
- {
- for (si = 0;
- (c1 = match_list[i][si]) &&
- (c2 = match_list[i + 1][si]);
- si++)
- if (c1 != c2) break;
- }
-
- if (low > si) low = si;
- i++;
- }
- match_list[0] = (char *)xmalloc (low + 1);
- strncpy (match_list[0], match_list[1], low);
- match_list[0][low] = '\0';
- }
- }
- else /* There were no matches. */
- {
- free (match_list);
- match_list = (char **)NULL;
- }
- return (match_list);
-}
-
-/* Okay, now we write the entry_function for filename completion. In the
- general case. Note that completion in the shell is a little different
- because of all the pathnames that must be followed when looking up the
- completion for a command. */
-char *
-filename_completion_function (text, state)
- int state;
- char *text;
-{
- static DIR *directory;
- static char *filename = (char *)NULL;
- static char *dirname = (char *)NULL;
- static char *users_dirname = (char *)NULL;
- static int filename_len;
-
- struct direct *entry = (struct direct *)NULL;
-
- /* If we don't have any state, then do some initialization. */
- if (!state)
- {
- char *temp;
-
- if (dirname) free (dirname);
- if (filename) free (filename);
- if (users_dirname) free (users_dirname);
-
- filename = savestring (text);
- if (!*text) text = ".";
- dirname = savestring (text);
-
- temp = rindex (dirname, '/');
-
- if (temp)
- {
- strcpy (filename, ++temp);
- *temp = '\0';
- }
- else
- strcpy (dirname, ".");
-
- /* We aren't done yet. We also support the "~user" syntax. */
-
- /* Save the version of the directory that the user typed. */
- users_dirname = savestring (dirname);
- {
- char *tilde_expand (), *temp_dirname = tilde_expand (dirname);
- free (dirname);
- dirname = temp_dirname;
-#ifdef SHELL
- {
- extern int follow_symbolic_links;
- char *make_absolute ();
-
- if (follow_symbolic_links && (strcmp (dirname, ".") != 0))
- {
- temp_dirname = make_absolute (dirname, get_working_directory (""));
-
- if (temp_dirname)
- {
- free (dirname);
- dirname = temp_dirname;
- }
- }
- }
-#endif /* SHELL */
- }
- directory = opendir (dirname);
- filename_len = strlen (filename);
-
- rl_filename_completion_desired = 1;
- }
-
- /* At this point we should entertain the possibility of hacking wildcarded
- filenames, like /usr/man*\/te<TAB>. If the directory name contains
- globbing characters, then build an array of directories to glob on, and
- glob on the first one. */
-
- /* Now that we have some state, we can read the directory. */
-
- while (directory && (entry = readdir (directory)))
- {
- /* Special case for no filename.
- All entries except "." and ".." match. */
- if (!filename_len)
- {
- if ((strcmp (entry->d_name, ".") != 0) &&
- (strcmp (entry->d_name, "..") != 0))
- break;
- }
- else
- {
- /* Otherwise, if these match upto the length of filename, then
- it is a match. */
-#ifdef TMB_SYSV
- if ((strlen (entry->d_name) >= filename_len) &&
- (strncmp (filename, entry->d_name, filename_len) == 0))
-#else
- if ((entry->d_namlen >= filename_len) &&
- (strncmp (filename, entry->d_name, filename_len) == 0))
-#endif /* TMB_SYSV */
- {
- break;
- }
- }
- }
-
- if (!entry)
- {
- if (directory)
- {
- closedir (directory);
- directory = (DIR *)NULL;
- }
- return (char *)NULL;
- }
- else
- {
- char *temp;
-
- if (dirname && (strcmp (dirname, ".") != 0))
- {
-#ifdef TMB_SYSV
- temp = (char *)xmalloc (1 + strlen (users_dirname)
- + strlen (entry->d_name));
-#else
- temp = (char *)xmalloc (1 + strlen (users_dirname)
- + entry->d_namlen);
-#endif /* TMB_SYSV */
- strcpy (temp, users_dirname);
- strcat (temp, entry->d_name);
- }
- else
- {
- temp = (savestring (entry->d_name));
- }
- return (temp);
- }
-}
-
-
-/* **************************************************************** */
-/* */
-/* Binding keys */
-/* */
-/* **************************************************************** */
-
-/* rl_add_defun (char *name, Function *function, int key)
- Add NAME to the list of named functions. Make FUNCTION
- be the function that gets called.
- If KEY is not -1, then bind it. */
-rl_add_defun (name, function, key)
- char *name;
- Function *function;
- int key;
-{
- if (key != -1)
- rl_bind_key (key, function);
- rl_add_funmap_entry (name, function);
-}
-
-/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
-int
-rl_bind_key (key, function)
- int key;
- Function *function;
-{
- if (key < 0)
- return (key);
-
- if (key > 127 && key < 256)
- {
- if (keymap[ESC].type == ISKMAP)
- {
- Keymap escmap = (Keymap)keymap[ESC].function;
-
- key -= 128;
- escmap[key].type = ISFUNC;
- escmap[key].function = function;
- return (0);
- }
- return (key);
- }
-
- keymap[key].type = ISFUNC;
- keymap[key].function = function;
- return (0);
-}
-
-/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid
- KEY. */
-int
-rl_bind_key_in_map (key, function, map)
- int key;
- Function *function;
- Keymap map;
-{
- int result;
- Keymap oldmap = keymap;
-
- keymap = map;
- result = rl_bind_key (key, function);
- keymap = oldmap;
- return (result);
-}
-
-/* Make KEY do nothing in the currently selected keymap.
- Returns non-zero in case of error. */
-int
-rl_unbind_key (key)
- int key;
-{
- return (rl_bind_key (key, (Function *)NULL));
-}
-
-/* Make KEY do nothing in MAP.
- Returns non-zero in case of error. */
-int
-rl_unbind_key_in_map (key, map)
- int key;
- Keymap map;
-{
- return (rl_bind_key_in_map (key, (Function *)NULL, map));
-}
-
-/* Bind the key sequence represented by the string KEYSEQ to
- FUNCTION. This makes new keymaps as necessary. The initial
- place to do bindings is in MAP. */
-rl_set_key (keyseq, function, map)
- char *keyseq;
- Function *function;
- Keymap map;
-{
- rl_generic_bind (ISFUNC, keyseq, function, map);
-}
-
-/* Bind the key sequence represented by the string KEYSEQ to
- the string of characters MACRO. This makes new keymaps as
- necessary. The initial place to do bindings is in MAP. */
-rl_macro_bind (keyseq, macro, map)
- char *keyseq, *macro;
- Keymap map;
-{
- char *macro_keys = (char *)xmalloc (2 * (strlen (macro)));
- int macro_keys_len;
-
- if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
- {
- free (macro_keys);
- return;
- }
- rl_generic_bind (ISMACR, keyseq, macro_keys, map);
-}
-
-/* Bind the key sequence represented by the string KEYSEQ to
- the arbitrary pointer DATA. TYPE says what kind of data is
- pointed to by DATA, right now this can be a function (ISFUNC),
- a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps
- as necessary. The initial place to do bindings is in MAP. */
-rl_generic_bind (type, keyseq, data, map)
- int type;
- char *keyseq, *data;
- Keymap map;
-{
- char *keys;
- int keys_len;
- register int i;
- int start;
-
- /* If no keys to bind to, exit right away. */
- if (!keyseq || !*keyseq)
- {
- if (type == ISMACR)
- free (data);
- return;
- }
-
- keys = (char *)alloca (1 + (2 * strlen (keyseq)));
-
- /* Translate the ASCII representation of KEYSEQ into an array
- of characters. Stuff the characters into ARRAY, and the
- length of ARRAY into LENGTH. */
- if (rl_translate_keyseq (keyseq, keys, &keys_len))
- return;
-
- /* Handle mapping of the ESC Key in vi mode */
- start = 0;
-#ifdef VI_MODE
- if ((rl_editing_mode == vi_mode) && (keys[0] == ESC))
- {
- start++;
- map = vi_movement_keymap;
- if(keys[1] == ESC)
- {
- extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
-
- start++;
- map = vi_escape_keymap;
- }
- }
-#endif
-
- /* Bind keys, making new keymaps as necessary. */
- for (i = start; i < keys_len; i++)
- {
- if (i + 1 < keys_len)
- {
- if (map[keys[i]].type != ISKMAP)
- {
- if (map[i].type == ISMACR)
- free ((char *)map[i].function);
-
- map[keys[i]].type = ISKMAP;
- map[keys[i]].function = (Function *)rl_make_bare_keymap ();
- }
- map = (Keymap)map[keys[i]].function;
- }
- else
- {
- if (map[keys[i]].type == ISMACR)
- free ((char *)map[keys[i]].function);
-
- map[keys[i]].function = (Function *)data;
- map[keys[i]].type = type;
- }
- }
-}
-
-/* Translate the ASCII representation of SEQ, stuffing the
- values into ARRAY, an array of characters. LEN gets the
- final length of ARRAY. Return non-zero if there was an
- error parsing SEQ. */
-rl_translate_keyseq (seq, array, len)
- char *seq, *array;
- int *len;
-{
- register int i, c, l = 0;
-
- for (i = 0; c = seq[i]; i++)
- {
- if (c == '\\')
- {
- c = seq[++i];
-
- if (!c)
- break;
-
- if (((c == 'C' || c == 'M') && seq[i + 1] == '-') ||
- (c == 'e'))
- {
- /* Handle special case of backwards define. */
- if (strncmp (&seq[i], "C-\\M-", 5) == 0)
- {
- array[l++] = ESC;
- i += 5;
- array[l++] = CTRL (to_upper (seq[i]));
- if (!seq[i])
- i--;
- continue;
- }
-
- switch (c)
- {
- case 'M':
- i++;
- array[l++] = ESC;
- break;
-
- case 'C':
- i += 2;
- array[l++] = CTRL (to_upper (seq[i]));
- break;
-
- case 'e':
- array[l++] = ESC;
- }
-
- continue;
- }
- }
- array[l++] = c;
- }
-
- array[l] = '\0';
- *len = l;
- return (0);
-}
-
-/* Return a pointer to the function that STRING represents.
- If STRING doesn't have a matching function, then a NULL pointer
- is returned. */
-Function *
-rl_named_function (string)
- char *string;
-{
- register int i;
- static int stricmp ();
-
- for (i = 0; funmap[i]; i++)
- if (stricmp (funmap[i]->name, string) == 0)
- return (funmap[i]->function);
- return ((Function *)NULL);
-}
-
-/* The last key bindings file read. */
-static char *last_readline_init_file = "~/.inputrc";
-
-/* Re-read the current keybindings file. */
-rl_re_read_init_file (count, ignore)
- int count, ignore;
-{
- rl_read_init_file (last_readline_init_file);
-}
-
-/* Do key bindings from a file. If FILENAME is NULL it defaults
- to `~/.inputrc'. If the file existed and could be opened and
- read, 0 is returned, otherwise errno is returned. */
-int
-rl_read_init_file (filename)
- char *filename;
-{
- int line_size, line_index;
- char *line = (char *)xmalloc (line_size = 100);
- char *openname;
- FILE *file;
-
- int c;
-
- /* Default the filename. */
- if (!filename)
- filename = "~/.inputrc";
-
- openname = tilde_expand (filename);
-
- /* Open the file. */
- file = fopen (openname, "r");
- free (openname);
-
- if (!file)
- return (errno);
-
- last_readline_init_file = filename;
-
- /* Loop reading lines from the file. Lines that start with `#' are
- comments, all other lines are commands for readline initialization. */
- while ((c = getc(file)) != EOF)
- {
- /* If comment, flush to EOL. */
- if (c == '#')
- {
- while ((c = getc(file)) != EOF && c != '\n');
- if (c == EOF)
- goto function_exit;
- continue;
- }
-
- /* Otherwise, this is the start of a line. Read the
- line from the file. */
- line_index = 0;
- while (c != EOF && c != '\n')
- {
- line[line_index++] = c;
- if (line_index == line_size)
- line = (char *)xrealloc (line, line_size += 100);
- c = getc (file);
- }
- line[line_index] = '\0';
-
- /* Parse the line. */
- rl_parse_and_bind (line);
- }
-
-function_exit:
-
- free (line);
- /* Close up the file and exit. */
- fclose (file);
- return (0);
-}
-
-
-/* **************************************************************** */
-/* */
-/* Parser Directives */
-/* */
-/* **************************************************************** */
-
-/* Conditionals. */
-
-/* Calling programs set this to have their argv[0]. */
-char *rl_readline_name = "other";
-
-/* Stack of previous values of parsing_conditionalized_out. */
-static unsigned char *if_stack = (unsigned char *)NULL;
-static int if_stack_depth = 0;
-static int if_stack_size = 0;
-
-/* Push parsing_conditionalized_out, and set parser state based on ARGS. */
-parser_if (args)
- char *args;
-{
- register int i;
- static int stricmp ();
-
- /* Push parser state. */
- if (if_stack_depth + 1 >= if_stack_size)
- {
- if (!if_stack)
- if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
- else
- if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
- }
- if_stack[if_stack_depth++] = parsing_conditionalized_out;
-
- /* We only check to see if the first word in ARGS is the same as the
- value stored in rl_readline_name. */
-
- /* Isolate first argument. */
- for (i = 0; args[i] && !whitespace (args[i]); i++);
-
- if (args[i])
- args[i++] = '\0';
-
- if (stricmp (args, rl_readline_name) == 0)
- parsing_conditionalized_out = 0;
- else
- parsing_conditionalized_out = 1;
-}
-
-/* Invert the current parser state if there is anything on the stack. */
-parser_else (args)
- char *args;
-{
- if (if_stack_depth)
- parsing_conditionalized_out = !parsing_conditionalized_out;
- else
- {
- /* *** What, no error message? *** */
- }
-}
-
-/* Terminate a conditional, popping the value of
- parsing_conditionalized_out from the stack. */
-parser_endif (args)
- char *args;
-{
- if (if_stack_depth)
- parsing_conditionalized_out = if_stack[--if_stack_depth];
- else
- {
- /* *** What, no error message? *** */
- }
-}
-
-/* Associate textual names with actual functions. */
-static struct {
- char *name;
- Function *function;
-} parser_directives [] = {
- { "if", parser_if },
- { "endif", parser_endif },
- { "else", parser_else },
- { (char *)0x0, (Function *)0x0 }
-};
-
-/* Handle a parser directive. STATEMENT is the line of the directive
- without any leading `$'. */
-static int
-handle_parser_directive (statement)
- char *statement;
-{
- register int i;
- char *directive, *args;
- static int stricmp ();
-
- /* Isolate the actual directive. */
-
- /* Skip whitespace. */
- for (i = 0; whitespace (statement[i]); i++);
-
- directive = &statement[i];
-
- for (; statement[i] && !whitespace (statement[i]); i++);
-
- if (statement[i])
- statement[i++] = '\0';
-
- for (; statement[i] && whitespace (statement[i]); i++);
-
- args = &statement[i];
-
- /* Lookup the command, and act on it. */
- for (i = 0; parser_directives[i].name; i++)
- if (stricmp (directive, parser_directives[i].name) == 0)
- {
- (*parser_directives[i].function) (args);
- return (0);
- }
-
- /* *** Should an error message be output? */
- return (1);
-}
-
-/* Read the binding command from STRING and perform it.
- A key binding command looks like: Keyname: function-name\0,
- a variable binding command looks like: set variable value.
- A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
-rl_parse_and_bind (string)
- char *string;
-{
- extern char *possible_control_prefixes[], *possible_meta_prefixes[];
- char *funname, *kname;
- static int substring_member_of_array (), stricmp ();
- register int c;
- int key, i;
-
- if (!string || !*string || *string == '#')
- return;
-
- /* If this is a parser directive, act on it. */
- if (*string == '$')
- {
- handle_parser_directive (&string[1]);
- return;
- }
-
- /* If we are supposed to be skipping parsing right now, then do it. */
- if (parsing_conditionalized_out)
- return;
-
- i = 0;
- /* If this keyname is a complex key expression surrounded by quotes,
- advance to after the matching close quote. */
- if (*string == '"')
- {
- for (i = 1; c = string[i]; i++)
- {
- if (c == '"' && string[i - 1] != '\\')
- break;
- }
- }
-
- /* Advance to the colon (:) or whitespace which separates the two objects. */
- for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
-
- /* Mark the end of the command (or keyname). */
- if (string[i])
- string[i++] = '\0';
-
- /* If this is a command to set a variable, then do that. */
- if (stricmp (string, "set") == 0)
- {
- char *var = string + i;
- char *value;
-
- /* Make VAR point to start of variable name. */
- while (*var && whitespace (*var)) var++;
-
- /* Make value point to start of value string. */
- value = var;
- while (*value && !whitespace (*value)) value++;
- if (*value)
- *value++ = '\0';
- while (*value && whitespace (*value)) value++;
-
- rl_variable_bind (var, value);
- return;
- }
-
- /* Skip any whitespace between keyname and funname. */
- for (; string[i] && whitespace (string[i]); i++);
- funname = &string[i];
-
- /* Now isolate funname.
- For straight function names just look for whitespace, since
- that will signify the end of the string. But this could be a
- macro definition. In that case, the string is quoted, so skip
- to the matching delimiter. */
- if (*funname == '\'' || *funname == '"')
- {
- int delimiter = string[i++];
-
- for (; c = string[i]; i++)
- {
- if (c == delimiter && string[i - 1] != '\\')
- break;
- }
- if (c)
- i++;
- }
-
- /* Advance to the end of the string. */
- for (; string[i] && !whitespace (string[i]); i++);
-
- /* No extra whitespace at the end of the string. */
- string[i] = '\0';
-
- /* If this is a new-style key-binding, then do the binding with
- rl_set_key (). Otherwise, let the older code deal with it. */
- if (*string == '"')
- {
- char *seq = (char *)alloca (1 + strlen (string));
- register int j, k = 0;
-
- for (j = 1; string[j]; j++)
- {
- if (string[j] == '"' && string[j - 1] != '\\')
- break;
-
- seq[k++] = string[j];
- }
- seq[k] = '\0';
-
- /* Binding macro? */
- if (*funname == '\'' || *funname == '"')
- {
- j = strlen (funname);
-
- if (j && funname[j - 1] == *funname)
- funname[j - 1] = '\0';
-
- rl_macro_bind (seq, &funname[1], keymap);
- }
- else
- rl_set_key (seq, rl_named_function (funname), keymap);
-
- return;
- }
-
- /* Get the actual character we want to deal with. */
- kname = rindex (string, '-');
- if (!kname)
- kname = string;
- else
- kname++;
-
- key = glean_key_from_name (kname);
-
- /* Add in control and meta bits. */
- if (substring_member_of_array (string, possible_control_prefixes))
- key = CTRL (to_upper (key));
-
- if (substring_member_of_array (string, possible_meta_prefixes))
- key = META (key);
-
- /* Temporary. Handle old-style keyname with macro-binding. */
- if (*funname == '\'' || *funname == '"')
- {
- char seq[2];
- int fl = strlen (funname);
-
- seq[0] = key; seq[1] = '\0';
- if (fl && funname[fl - 1] == *funname)
- funname[fl - 1] = '\0';
-
- rl_macro_bind (seq, &funname[1], keymap);
- }
- else
- rl_bind_key (key, rl_named_function (funname));
-}
-
-rl_variable_bind (name, value)
- char *name, *value;
-{
- static int strnicmp (), stricmp ();
-
- if (stricmp (name, "editing-mode") == 0)
- {
- if (strnicmp (value, "vi", 2) == 0)
- {
-#ifdef VI_MODE
- keymap = vi_insertion_keymap;
- rl_editing_mode = vi_mode;
-#endif /* VI_MODE */
- }
- else if (strnicmp (value, "emacs", 5) == 0)
- {
- keymap = emacs_standard_keymap;
- rl_editing_mode = emacs_mode;
- }
- }
- else if (stricmp (name, "horizontal-scroll-mode") == 0)
- {
- if (!*value || stricmp (value, "On") == 0)
- horizontal_scroll_mode = 1;
- else
- horizontal_scroll_mode = 0;
- }
-}
-
-/* Return the character which matches NAME.
- For example, `Space' returns ' '. */
-
-typedef struct {
- char *name;
- int value;
-} assoc_list;
-
-assoc_list name_key_alist[] = {
- { "Space", ' ' },
- { "SPC", ' ' },
- { "Rubout", 0x7f },
- { "DEL", 0x7f },
- { "Tab", 0x09 },
- { "Newline", '\n' },
- { "Return", '\r' },
- { "RET", '\r' },
- { "LFD", '\n' },
- { "Escape", '\033' },
- { "ESC", '\033' },
-
- { (char *)0x0, 0 }
-};
-
-int
-glean_key_from_name (name)
- char *name;
-{
- register int i;
- static int stricmp ();
-
- for (i = 0; name_key_alist[i].name; i++)
- if (stricmp (name, name_key_alist[i].name) == 0)
- return (name_key_alist[i].value);
-
- return (*name);
-}
-
-
-/* **************************************************************** */
-/* */
-/* String Utility Functions */
-/* */
-/* **************************************************************** */
-
-/* Return non-zero if any members of ARRAY are a substring in STRING. */
-static int
-substring_member_of_array (string, array)
- char *string, **array;
-{
- static char *strindex ();
-
- while (*array)
- {
- if (strindex (string, *array))
- return (1);
- array++;
- }
- return (0);
-}
-
-/* Whoops, Unix doesn't have strnicmp. */
-
-/* Compare at most COUNT characters from string1 to string2. Case
- doesn't matter. */
-static int
-strnicmp (string1, string2, count)
- char *string1, *string2;
-{
- register char ch1, ch2;
-
- while (count) {
- ch1 = *string1++;
- ch2 = *string2++;
- if (to_upper(ch1) == to_upper(ch2))
- count--;
- else break;
- }
- return (count);
-}
-
-/* strcmp (), but caseless. */
-static int
-stricmp (string1, string2)
- char *string1, *string2;
-{
- register char ch1, ch2;
-
- while (*string1 && *string2) {
- ch1 = *string1++;
- ch2 = *string2++;
- if (to_upper(ch1) != to_upper(ch2))
- return (1);
- }
- return (*string1 | *string2);
-}
-
-/* Determine if s2 occurs in s1. If so, return a pointer to the
- match in s1. The compare is case insensitive. */
-static char *
-strindex (s1, s2)
- register char *s1, *s2;
-{
- register int i, l = strlen (s2);
- register int len = strlen (s1);
-
- for (i = 0; (len - i) >= l; i++)
- if (strnicmp (&s1[i], s2, l) == 0)
- return (s1 + i);
- return ((char *)NULL);
-}
-
-
-#ifdef STATIC_MALLOC
-
-/* **************************************************************** */
-/* */
-/* xmalloc and xrealloc () */
-/* */
-/* **************************************************************** */
-
-static char *
-xmalloc (bytes)
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)malloc (bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static char *
-xrealloc (pointer, bytes)
- char *pointer;
- int bytes;
-{
- static memory_error_and_abort ();
- char *temp = (char *)realloc (pointer, bytes);
-
- if (!temp)
- memory_error_and_abort ();
- return (temp);
-}
-
-static
-memory_error_and_abort ()
-{
- fprintf (stderr, "readline: Out of virtual memory!\n");
- abort ();
-}
-#endif /* STATIC_MALLOC */
-
-
-/* **************************************************************** */
-/* */
-/* Testing Readline */
-/* */
-/* **************************************************************** */
-
-#ifdef TEST
-
-main ()
-{
- HIST_ENTRY **history_list ();
- char *temp = (char *)NULL;
- char *prompt = "readline% ";
- int done = 0;
-
- while (!done)
- {
- temp = readline (prompt);
-
- /* Test for EOF. */
- if (!temp)
- exit (1);
-
- /* If there is anything on the line, print it and remember it. */
- if (*temp)
- {
- fprintf (stderr, "%s\r\n", temp);
- add_history (temp);
- }
-
- /* Check for `command' that we handle. */
- if (strcmp (temp, "quit") == 0)
- done = 1;
-
- if (strcmp (temp, "list") == 0) {
- HIST_ENTRY **list = history_list ();
- register int i;
- if (list) {
- for (i = 0; list[i]; i++) {
- fprintf (stderr, "%d: %s\r\n", i, list[i]->line);
- free (list[i]->line);
- }
- free (list);
- }
- }
- free (temp);
- }
-}
-
-#endif /* TEST */
-
-
-/*
- * Local variables:
- * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap"
- * end:
- */
diff --git a/gnu/usr.bin/gdb/readline/readline.h b/gnu/usr.bin/gdb/readline/readline.h
deleted file mode 100644
index 7d7fbe7c3c79..000000000000
--- a/gnu/usr.bin/gdb/readline/readline.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/* Readline.h -- the names of functions callable from within readline. */
-
-#ifndef _READLINE_H_
-#define _READLINE_H_
-
-#include <readline/keymaps.h>
-
-#ifndef __FUNCTION_DEF
-typedef int Function ();
-#define __FUNCTION_DEF
-#endif
-
-/* The functions for manipulating the text of the line within readline.
-Most of these functions are bound to keys by default. */
-extern int
-rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (),
-rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (),
-rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (),
-rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars
-(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout
-(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (),
-rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (),
-rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words
-(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version
-(), rl_digit_argument (), rl_universal_argument (), rl_abort (),
-rl_undo_command (), rl_revert_line (), rl_beginning_of_history (),
-rl_end_of_history (), rl_forward_search_history (), rl_insert (),
-rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (),
-rl_restart_output (), rl_re_read_init_file ();
-
-/* These are *both* defined even when VI_MODE is not. */
-extern int rl_vi_editing_mode (), rl_emacs_editing_mode ();
-
-#ifdef VI_MODE
-/* Things for vi mode. */
-extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (),
-rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (),
-rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (),
-rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (),
-rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (),
-rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (),
-rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (),
-rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (),
-rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (),
-rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (),
-rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete ();
-#endif /* VI_MODE */
-
-/* Keyboard macro commands. */
-extern int
-rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro ();
-
-/* Maintaining the state of undo. We remember individual deletes and inserts
- on a chain of things to do. */
-
-/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
- to insert some text, and UNDO_INSERT means to delete some text. I.e.,
- the code tells undo what to undo, not how to undo it. */
-enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
-
-/* What an element of THE_UNDO_LIST looks like. */
-typedef struct undo_list {
- struct undo_list *next;
- int start, end; /* Where the change took place. */
- char *text; /* The text to insert, if undoing a delete. */
- enum undo_code what; /* Delete, Insert, Begin, End. */
-} UNDO_LIST;
-
-/* The current undo list for RL_LINE_BUFFER. */
-extern UNDO_LIST *rl_undo_list;
-
-/* The data structure for mapping textual names to code addresses. */
-typedef struct {
- char *name;
- Function *function;
-} FUNMAP;
-
-extern FUNMAP **funmap;
-
-/* **************************************************************** */
-/* */
-/* Well Published Variables */
-/* */
-/* **************************************************************** */
-
-/* The name of the calling program. You should initialize this to
- whatever was in argv[0]. It is used when parsing conditionals. */
-extern char *rl_readline_name;
-
-/* The line buffer that is in use. */
-extern char *rl_line_buffer;
-
-/* The location of point, and end. */
-extern int rl_point, rl_end;
-
-/* The name of the terminal to use. */
-extern char *rl_terminal_name;
-
-/* The input and output streams. */
-extern FILE *rl_instream, *rl_outstream;
-
-/* The basic list of characters that signal a break between words for the
- completer routine. The contents of this variable is what breaks words
- in the shell, i.e. "n\"\\'`@$>". */
-extern char *rl_basic_word_break_characters;
-
-/* The list of characters that signal a break between words for
- rl_complete_internal. The default list is the contents of
- rl_basic_word_break_characters. */
-extern char *rl_completer_word_break_characters;
-
-/* List of characters that are word break characters, but should be left
- in TEXT when it is passed to the completion function. The shell uses
- this to help determine what kind of completing to do. */
-extern char *rl_special_prefixes;
-
-/* Pointer to the generator function for completion_matches ().
- NULL means to use filename_entry_function (), the default filename
- completer. */
-extern Function *rl_completion_entry_function;
-
-/* Pointer to alternative function to create matches.
- Function is called with TEXT, START, and END.
- START and END are indices in RL_LINE_BUFFER saying what the boundaries
- of TEXT are.
- If this function exists and returns NULL then call the value of
- rl_completion_entry_function to try to match, otherwise use the
- array of strings returned. */
-extern Function *rl_attempted_completion_function;
-
-/* If non-null, this contains the address of a function to call if the
- standard meaning for expanding a tilde fails. The function is called
- with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
- which is the expansion, or a NULL pointer if there is no expansion. */
-extern Function *rl_tilde_expander;
-
-/* If non-zero, then this is the address of a function to call just
- before readline_internal () prints the first prompt. */
-extern Function *rl_startup_hook;
-
-/* **************************************************************** */
-/* */
-/* Well Published Functions */
-/* */
-/* **************************************************************** */
-
-/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
-extern char *readline ();
-
-/* Return an array of strings which are the result of repeatadly calling
- FUNC with TEXT. */
-extern char **completion_matches ();
-
-/* rl_add_defun (char *name, Function *function, int key)
- Add NAME to the list of named functions. Make FUNCTION
- be the function that gets called.
- If KEY is not -1, then bind it. */
-extern int rl_add_defun ();
-
-#endif /* _READLINE_H_ */
-
diff --git a/gnu/usr.bin/gdb/readline/vi_keymap.c b/gnu/usr.bin/gdb/readline/vi_keymap.c
deleted file mode 100644
index 71c7ec8506cc..000000000000
--- a/gnu/usr.bin/gdb/readline/vi_keymap.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * @(#)vi_keymap.c 6.4 (Berkeley) 5/8/91
- */
-
-/* vi_keymap.c -- the keymap for vi_mode in readline (). */
-
-/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
-
- This file is part of GNU Readline, a library for reading lines
- of text with interactive input and history editing.
-
- Readline is free software; you can 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.
-
- Readline is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Readline; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef FILE
-#include <stdio.h>
-#endif /* FILE */
-
-#include "readline.h"
-
-extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
-
-/* The keymap arrays for handling vi mode. */
-KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
-
- /* The regular control keys come first. */
- { ISFUNC, (Function *)0x0 }, /* Control-@ */
- { ISFUNC, (Function *)0x0 }, /* Control-a */
- { ISFUNC, (Function *)0x0 }, /* Control-b */
- { ISFUNC, (Function *)0x0 }, /* Control-c */
- { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
- { ISFUNC, rl_emacs_editing_mode }, /* Control-e */
- { ISFUNC, (Function *)0x0 }, /* Control-f */
- { ISFUNC, rl_abort }, /* Control-g */
- { ISFUNC, rl_backward }, /* Control-h */
- { ISFUNC, (Function *)0x0 }, /* Control-i */
- { ISFUNC, rl_newline }, /* Control-j */
- { ISFUNC, rl_kill_line }, /* Control-k */
- { ISFUNC, rl_clear_screen }, /* Control-l */
- { ISFUNC, rl_newline }, /* Control-m */
- { ISFUNC, rl_get_next_history }, /* Control-n */
- { ISFUNC, (Function *)0x0 }, /* Control-o */
- { ISFUNC, rl_get_previous_history }, /* Control-p */
- { ISFUNC, rl_quoted_insert }, /* Control-q */
- { ISFUNC, rl_reverse_search_history }, /* Control-r */
- { ISFUNC, rl_forward_search_history }, /* Control-s */
- { ISFUNC, rl_transpose_chars }, /* Control-t */
- { ISFUNC, rl_unix_line_discard }, /* Control-u */
- { ISFUNC, rl_quoted_insert }, /* Control-v */
- { ISFUNC, rl_unix_word_rubout }, /* Control-w */
- { ISFUNC, (Function *)0x0 }, /* Control-x */
- { ISFUNC, rl_yank }, /* Control-y */
- { ISFUNC, (Function *)0x0 }, /* Control-z */
-
- { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */
- { ISFUNC, (Function *)0x0 }, /* Control-\ */
- { ISFUNC, (Function *)0x0 }, /* Control-] */
- { ISFUNC, (Function *)0x0 }, /* Control-^ */
- { ISFUNC, rl_undo_command }, /* Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, rl_forward }, /* SPACE */
- { ISFUNC, (Function *)0x0 }, /* ! */
- { ISFUNC, (Function *)0x0 }, /* " */
- { ISFUNC, rl_vi_comment }, /* # */
- { ISFUNC, rl_end_of_line }, /* $ */
- { ISFUNC, rl_vi_match }, /* % */
- { ISFUNC, (Function *)0x0 }, /* & */
- { ISFUNC, (Function *)0x0 }, /* ' */
- { ISFUNC, (Function *)0x0 }, /* ( */
- { ISFUNC, (Function *)0x0 }, /* ) */
- { ISFUNC, rl_vi_complete }, /* * */
- { ISFUNC, rl_get_previous_history}, /* + */
- { ISFUNC, rl_vi_char_search }, /* , */
- { ISFUNC, rl_get_next_history }, /* - */
- { ISFUNC, (Function *)0x0 }, /* . */
- { ISFUNC, rl_vi_search }, /* / */
-
- /* Regular digits. */
- { ISFUNC, rl_vi_arg_digit }, /* 0 */
- { ISFUNC, rl_vi_arg_digit }, /* 1 */
- { ISFUNC, rl_vi_arg_digit }, /* 2 */
- { ISFUNC, rl_vi_arg_digit }, /* 3 */
- { ISFUNC, rl_vi_arg_digit }, /* 4 */
- { ISFUNC, rl_vi_arg_digit }, /* 5 */
- { ISFUNC, rl_vi_arg_digit }, /* 6 */
- { ISFUNC, rl_vi_arg_digit }, /* 7 */
- { ISFUNC, rl_vi_arg_digit }, /* 8 */
- { ISFUNC, rl_vi_arg_digit }, /* 9 */
-
- /* A little more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* : */
- { ISFUNC, rl_vi_char_search }, /* ; */
- { ISFUNC, (Function *)0x0 }, /* < */
- { ISFUNC, (Function *)0x0 }, /* = */
- { ISFUNC, (Function *)0x0 }, /* > */
- { ISFUNC, rl_vi_search }, /* ? */
- { ISFUNC, (Function *)0x0 }, /* @ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_vi_append_eol }, /* A */
- { ISFUNC, rl_vi_prev_word}, /* B */
- { ISFUNC, rl_vi_change_to }, /* C */
- { ISFUNC, rl_vi_delete_to }, /* D */
- { ISFUNC, rl_vi_end_word }, /* E */
- { ISFUNC, rl_vi_char_search }, /* F */
- { ISFUNC, (Function *)0x0 }, /* G */
- { ISFUNC, (Function *)0x0 }, /* H */
- { ISFUNC, rl_vi_insert_beg }, /* I */
- { ISFUNC, (Function *)0x0 }, /* J */
- { ISFUNC, (Function *)0x0 }, /* K */
- { ISFUNC, (Function *)0x0 }, /* L */
- { ISFUNC, (Function *)0x0 }, /* M */
- { ISFUNC, rl_vi_search_again }, /* N */
- { ISFUNC, (Function *)0x0 }, /* O */
- { ISFUNC, rl_vi_put }, /* P */
- { ISFUNC, (Function *)0x0 }, /* Q */
- { ISFUNC, rl_vi_replace }, /* R */
- { ISFUNC, rl_vi_subst }, /* S */
- { ISFUNC, rl_vi_char_search }, /* T */
- { ISFUNC, rl_revert_line }, /* U */
- { ISFUNC, (Function *)0x0 }, /* V */
- { ISFUNC, rl_vi_next_word }, /* W */
- { ISFUNC, rl_rubout }, /* X */
- { ISFUNC, rl_vi_yank_to }, /* Y */
- { ISFUNC, (Function *)0x0 }, /* Z */
-
- /* Some more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* [ */
- { ISFUNC, (Function *)0x0 }, /* \ */
- { ISFUNC, (Function *)0x0 }, /* ] */
- { ISFUNC, rl_vi_first_print }, /* ^ */
- { ISFUNC, rl_vi_yank_arg }, /* _ */
- { ISFUNC, (Function *)0x0 }, /* ` */
-
- /* Lowercase alphabet. */
- { ISFUNC, rl_vi_append_mode }, /* a */
- { ISFUNC, rl_vi_prev_word }, /* b */
- { ISFUNC, rl_vi_change_to }, /* c */
- { ISFUNC, rl_vi_delete_to }, /* d */
- { ISFUNC, rl_vi_end_word }, /* e */
- { ISFUNC, rl_vi_char_search }, /* f */
- { ISFUNC, (Function *)0x0 }, /* g */
- { ISFUNC, rl_backward }, /* h */
- { ISFUNC, rl_vi_insertion_mode }, /* i */
- { ISFUNC, rl_get_next_history }, /* j */
- { ISFUNC, rl_get_previous_history }, /* k */
- { ISFUNC, rl_forward }, /* l */
- { ISFUNC, (Function *)0x0 }, /* m */
- { ISFUNC, rl_vi_search_again }, /* n */
- { ISFUNC, (Function *)0x0 }, /* o */
- { ISFUNC, rl_vi_put }, /* p */
- { ISFUNC, (Function *)0x0 }, /* q */
- { ISFUNC, rl_vi_change_char }, /* r */
- { ISFUNC, rl_vi_subst }, /* s */
- { ISFUNC, rl_vi_char_search }, /* t */
- { ISFUNC, rl_undo_command }, /* u */
- { ISFUNC, (Function *)0x0 }, /* v */
- { ISFUNC, rl_vi_next_word }, /* w */
- { ISFUNC, rl_vi_delete }, /* x */
- { ISFUNC, rl_vi_yank_to }, /* y */
- { ISFUNC, (Function *)0x0 }, /* z */
-
- /* Final punctuation. */
- { ISFUNC, (Function *)0x0 }, /* { */
- { ISFUNC, rl_vi_column }, /* | */
- { ISFUNC, (Function *)0x0 }, /* } */
- { ISFUNC, rl_vi_change_case }, /* ~ */
- { ISFUNC, rl_backward } /* RUBOUT */
-};
-
-
-KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
-
- /* The regular control keys come first. */
- { ISFUNC, (Function *)0x0 }, /* Control-@ */
- { ISFUNC, rl_insert }, /* Control-a */
- { ISFUNC, rl_insert }, /* Control-b */
- { ISFUNC, rl_insert }, /* Control-c */
- { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
- { ISFUNC, rl_insert }, /* Control-e */
- { ISFUNC, rl_insert }, /* Control-f */
- { ISFUNC, rl_insert }, /* Control-g */
- { ISFUNC, rl_rubout }, /* Control-h */
- { ISFUNC, rl_complete }, /* Control-i */
- { ISFUNC, rl_newline }, /* Control-j */
- { ISFUNC, rl_insert }, /* Control-k */
- { ISFUNC, rl_insert }, /* Control-l */
- { ISFUNC, rl_newline }, /* Control-m */
- { ISFUNC, rl_insert }, /* Control-n */
- { ISFUNC, rl_insert }, /* Control-o */
- { ISFUNC, rl_insert }, /* Control-p */
- { ISFUNC, rl_insert }, /* Control-q */
- { ISFUNC, rl_reverse_search_history }, /* Control-r */
- { ISFUNC, rl_forward_search_history }, /* Control-s */
- { ISFUNC, rl_transpose_chars }, /* Control-t */
- { ISFUNC, rl_unix_line_discard }, /* Control-u */
- { ISFUNC, rl_quoted_insert }, /* Control-v */
- { ISFUNC, rl_unix_word_rubout }, /* Control-w */
- { ISFUNC, rl_insert }, /* Control-x */
- { ISFUNC, rl_yank }, /* Control-y */
- { ISFUNC, rl_insert }, /* Control-z */
-
- { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
- { ISFUNC, rl_insert }, /* Control-\ */
- { ISFUNC, rl_insert }, /* Control-] */
- { ISFUNC, rl_insert }, /* Control-^ */
- { ISFUNC, rl_undo_command }, /* Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, rl_insert }, /* SPACE */
- { ISFUNC, rl_insert }, /* ! */
- { ISFUNC, rl_insert }, /* " */
- { ISFUNC, rl_insert }, /* # */
- { ISFUNC, rl_insert }, /* $ */
- { ISFUNC, rl_insert }, /* % */
- { ISFUNC, rl_insert }, /* & */
- { ISFUNC, rl_insert }, /* ' */
- { ISFUNC, rl_insert }, /* ( */
- { ISFUNC, rl_insert }, /* ) */
- { ISFUNC, rl_insert }, /* * */
- { ISFUNC, rl_insert }, /* + */
- { ISFUNC, rl_insert }, /* , */
- { ISFUNC, rl_insert }, /* - */
- { ISFUNC, rl_insert }, /* . */
- { ISFUNC, rl_insert }, /* / */
-
- /* Regular digits. */
- { ISFUNC, rl_insert }, /* 0 */
- { ISFUNC, rl_insert }, /* 1 */
- { ISFUNC, rl_insert }, /* 2 */
- { ISFUNC, rl_insert }, /* 3 */
- { ISFUNC, rl_insert }, /* 4 */
- { ISFUNC, rl_insert }, /* 5 */
- { ISFUNC, rl_insert }, /* 6 */
- { ISFUNC, rl_insert }, /* 7 */
- { ISFUNC, rl_insert }, /* 8 */
- { ISFUNC, rl_insert }, /* 9 */
-
- /* A little more punctuation. */
- { ISFUNC, rl_insert }, /* : */
- { ISFUNC, rl_insert }, /* ; */
- { ISFUNC, rl_insert }, /* < */
- { ISFUNC, rl_insert }, /* = */
- { ISFUNC, rl_insert }, /* > */
- { ISFUNC, rl_insert }, /* ? */
- { ISFUNC, rl_insert }, /* @ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_insert }, /* A */
- { ISFUNC, rl_insert }, /* B */
- { ISFUNC, rl_insert }, /* C */
- { ISFUNC, rl_insert }, /* D */
- { ISFUNC, rl_insert }, /* E */
- { ISFUNC, rl_insert }, /* F */
- { ISFUNC, rl_insert }, /* G */
- { ISFUNC, rl_insert }, /* H */
- { ISFUNC, rl_insert }, /* I */
- { ISFUNC, rl_insert }, /* J */
- { ISFUNC, rl_insert }, /* K */
- { ISFUNC, rl_insert }, /* L */
- { ISFUNC, rl_insert }, /* M */
- { ISFUNC, rl_insert }, /* N */
- { ISFUNC, rl_insert }, /* O */
- { ISFUNC, rl_insert }, /* P */
- { ISFUNC, rl_insert }, /* Q */
- { ISFUNC, rl_insert }, /* R */
- { ISFUNC, rl_insert }, /* S */
- { ISFUNC, rl_insert }, /* T */
- { ISFUNC, rl_insert }, /* U */
- { ISFUNC, rl_insert }, /* V */
- { ISFUNC, rl_insert }, /* W */
- { ISFUNC, rl_insert }, /* X */
- { ISFUNC, rl_insert }, /* Y */
- { ISFUNC, rl_insert }, /* Z */
-
- /* Some more punctuation. */
- { ISFUNC, rl_insert }, /* [ */
- { ISFUNC, rl_insert }, /* \ */
- { ISFUNC, rl_insert }, /* ] */
- { ISFUNC, rl_insert }, /* ^ */
- { ISFUNC, rl_insert }, /* _ */
- { ISFUNC, rl_insert }, /* ` */
-
- /* Lowercase alphabet. */
- { ISFUNC, rl_insert }, /* a */
- { ISFUNC, rl_insert }, /* b */
- { ISFUNC, rl_insert }, /* c */
- { ISFUNC, rl_insert }, /* d */
- { ISFUNC, rl_insert }, /* e */
- { ISFUNC, rl_insert }, /* f */
- { ISFUNC, rl_insert }, /* g */
- { ISFUNC, rl_insert }, /* h */
- { ISFUNC, rl_insert }, /* i */
- { ISFUNC, rl_insert }, /* j */
- { ISFUNC, rl_insert }, /* k */
- { ISFUNC, rl_insert }, /* l */
- { ISFUNC, rl_insert }, /* m */
- { ISFUNC, rl_insert }, /* n */
- { ISFUNC, rl_insert }, /* o */
- { ISFUNC, rl_insert }, /* p */
- { ISFUNC, rl_insert }, /* q */
- { ISFUNC, rl_insert }, /* r */
- { ISFUNC, rl_insert }, /* s */
- { ISFUNC, rl_insert }, /* t */
- { ISFUNC, rl_insert }, /* u */
- { ISFUNC, rl_insert }, /* v */
- { ISFUNC, rl_insert }, /* w */
- { ISFUNC, rl_insert }, /* x */
- { ISFUNC, rl_insert }, /* y */
- { ISFUNC, rl_insert }, /* z */
-
- /* Final punctuation. */
- { ISFUNC, rl_insert }, /* { */
- { ISFUNC, rl_insert }, /* | */
- { ISFUNC, rl_insert }, /* } */
- { ISFUNC, rl_insert }, /* ~ */
- { ISFUNC, rl_rubout } /* RUBOUT */
-};
-
-KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
-
- /* The regular control keys come first. */
- { ISFUNC, (Function *)0x0 }, /* Control-@ */
- { ISFUNC, (Function *)0x0 }, /* Control-a */
- { ISFUNC, (Function *)0x0 }, /* Control-b */
- { ISFUNC, (Function *)0x0 }, /* Control-c */
- { ISFUNC, (Function *)0x0 }, /* Control-d */
- { ISFUNC, (Function *)0x0 }, /* Control-e */
- { ISFUNC, (Function *)0x0 }, /* Control-f */
- { ISFUNC, (Function *)0x0 }, /* Control-g */
- { ISFUNC, (Function *)0x0 }, /* Control-h */
- { ISFUNC, rl_tab_insert}, /* Control-i */
- { ISFUNC, rl_emacs_editing_mode}, /* Control-j */
- { ISFUNC, rl_kill_line }, /* Control-k */
- { ISFUNC, (Function *)0x0 }, /* Control-l */
- { ISFUNC, rl_emacs_editing_mode}, /* Control-m */
- { ISFUNC, (Function *)0x0 }, /* Control-n */
- { ISFUNC, (Function *)0x0 }, /* Control-o */
- { ISFUNC, (Function *)0x0 }, /* Control-p */
- { ISFUNC, (Function *)0x0 }, /* Control-q */
- { ISFUNC, (Function *)0x0 }, /* Control-r */
- { ISFUNC, (Function *)0x0 }, /* Control-s */
- { ISFUNC, (Function *)0x0 }, /* Control-t */
- { ISFUNC, (Function *)0x0 }, /* Control-u */
- { ISFUNC, (Function *)0x0 }, /* Control-v */
- { ISFUNC, (Function *)0x0 }, /* Control-w */
- { ISFUNC, (Function *)0x0 }, /* Control-x */
- { ISFUNC, (Function *)0x0 }, /* Control-y */
- { ISFUNC, (Function *)0x0 }, /* Control-z */
-
- { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
- { ISFUNC, (Function *)0x0 }, /* Control-\ */
- { ISFUNC, (Function *)0x0 }, /* Control-] */
- { ISFUNC, (Function *)0x0 }, /* Control-^ */
- { ISFUNC, rl_undo_command }, /* Control-_ */
-
- /* The start of printing characters. */
- { ISFUNC, (Function *)0x0 }, /* SPACE */
- { ISFUNC, (Function *)0x0 }, /* ! */
- { ISFUNC, (Function *)0x0 }, /* " */
- { ISFUNC, (Function *)0x0 }, /* # */
- { ISFUNC, (Function *)0x0 }, /* $ */
- { ISFUNC, (Function *)0x0 }, /* % */
- { ISFUNC, (Function *)0x0 }, /* & */
- { ISFUNC, (Function *)0x0 }, /* ' */
- { ISFUNC, (Function *)0x0 }, /* ( */
- { ISFUNC, (Function *)0x0 }, /* ) */
- { ISFUNC, (Function *)0x0 }, /* * */
- { ISFUNC, (Function *)0x0 }, /* + */
- { ISFUNC, (Function *)0x0 }, /* , */
- { ISFUNC, (Function *)0x0 }, /* - */
- { ISFUNC, (Function *)0x0 }, /* . */
- { ISFUNC, (Function *)0x0 }, /* / */
-
- /* Regular digits. */
- { ISFUNC, rl_vi_arg_digit }, /* 0 */
- { ISFUNC, rl_vi_arg_digit }, /* 1 */
- { ISFUNC, rl_vi_arg_digit }, /* 2 */
- { ISFUNC, rl_vi_arg_digit }, /* 3 */
- { ISFUNC, rl_vi_arg_digit }, /* 4 */
- { ISFUNC, rl_vi_arg_digit }, /* 5 */
- { ISFUNC, rl_vi_arg_digit }, /* 6 */
- { ISFUNC, rl_vi_arg_digit }, /* 7 */
- { ISFUNC, rl_vi_arg_digit }, /* 8 */
- { ISFUNC, rl_vi_arg_digit }, /* 9 */
-
- /* A little more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* : */
- { ISFUNC, (Function *)0x0 }, /* ; */
- { ISFUNC, (Function *)0x0 }, /* < */
- { ISFUNC, (Function *)0x0 }, /* = */
- { ISFUNC, (Function *)0x0 }, /* > */
- { ISFUNC, (Function *)0x0 }, /* ? */
- { ISFUNC, (Function *)0x0 }, /* @ */
-
- /* Uppercase alphabet. */
- { ISFUNC, rl_do_lowercase_version }, /* A */
- { ISFUNC, rl_do_lowercase_version }, /* B */
- { ISFUNC, rl_do_lowercase_version }, /* C */
- { ISFUNC, rl_do_lowercase_version }, /* D */
- { ISFUNC, rl_do_lowercase_version }, /* E */
- { ISFUNC, rl_do_lowercase_version }, /* F */
- { ISFUNC, rl_do_lowercase_version }, /* G */
- { ISFUNC, rl_do_lowercase_version }, /* H */
- { ISFUNC, rl_do_lowercase_version }, /* I */
- { ISFUNC, rl_do_lowercase_version }, /* J */
- { ISFUNC, rl_do_lowercase_version }, /* K */
- { ISFUNC, rl_do_lowercase_version }, /* L */
- { ISFUNC, rl_do_lowercase_version }, /* M */
- { ISFUNC, rl_do_lowercase_version }, /* N */
- { ISFUNC, rl_do_lowercase_version }, /* O */
- { ISFUNC, rl_do_lowercase_version }, /* P */
- { ISFUNC, rl_do_lowercase_version }, /* Q */
- { ISFUNC, rl_do_lowercase_version }, /* R */
- { ISFUNC, rl_do_lowercase_version }, /* S */
- { ISFUNC, rl_do_lowercase_version }, /* T */
- { ISFUNC, rl_do_lowercase_version }, /* U */
- { ISFUNC, rl_do_lowercase_version }, /* V */
- { ISFUNC, rl_do_lowercase_version }, /* W */
- { ISFUNC, rl_do_lowercase_version }, /* X */
- { ISFUNC, rl_do_lowercase_version }, /* Y */
- { ISFUNC, rl_do_lowercase_version }, /* Z */
-
- /* Some more punctuation. */
- { ISFUNC, (Function *)0x0 }, /* [ */
- { ISFUNC, (Function *)0x0 }, /* \ */
- { ISFUNC, (Function *)0x0 }, /* ] */
- { ISFUNC, (Function *)0x0 }, /* ^ */
- { ISFUNC, (Function *)0x0 }, /* _ */
- { ISFUNC, (Function *)0x0 }, /* ` */
-
- /* Lowercase alphabet. */
- { ISFUNC, (Function *)0x0 }, /* a */
- { ISFUNC, (Function *)0x0 }, /* b */
- { ISFUNC, (Function *)0x0 }, /* c */
- { ISFUNC, (Function *)0x0 }, /* d */
- { ISFUNC, (Function *)0x0 }, /* e */
- { ISFUNC, (Function *)0x0 }, /* f */
- { ISFUNC, (Function *)0x0 }, /* g */
- { ISFUNC, (Function *)0x0 }, /* h */
- { ISFUNC, (Function *)0x0 }, /* i */
- { ISFUNC, (Function *)0x0 }, /* j */
- { ISFUNC, (Function *)0x0 }, /* k */
- { ISFUNC, (Function *)0x0 }, /* l */
- { ISFUNC, (Function *)0x0 }, /* m */
- { ISFUNC, (Function *)0x0 }, /* n */
- { ISFUNC, (Function *)0x0 }, /* o */
- { ISFUNC, (Function *)0x0 }, /* p */
- { ISFUNC, (Function *)0x0 }, /* q */
- { ISFUNC, (Function *)0x0 }, /* r */
- { ISFUNC, (Function *)0x0 }, /* s */
- { ISFUNC, (Function *)0x0 }, /* t */
- { ISFUNC, (Function *)0x0 }, /* u */
- { ISFUNC, (Function *)0x0 }, /* v */
- { ISFUNC, (Function *)0x0 }, /* w */
- { ISFUNC, (Function *)0x0 }, /* x */
- { ISFUNC, (Function *)0x0 }, /* y */
- { ISFUNC, (Function *)0x0 }, /* z */
-
- /* Final punctuation. */
- { ISFUNC, (Function *)0x0 }, /* { */
- { ISFUNC, (Function *)0x0 }, /* | */
- { ISFUNC, (Function *)0x0 }, /* } */
- { ISFUNC, (Function *)0x0 }, /* ~ */
- { ISFUNC, rl_backward_kill_word } /* RUBOUT */
-};
diff --git a/gnu/usr.bin/gdb/readline/vi_mode.c b/gnu/usr.bin/gdb/readline/vi_mode.c
deleted file mode 100644
index 3a13cc6c862a..000000000000
--- a/gnu/usr.bin/gdb/readline/vi_mode.c
+++ /dev/null
@@ -1,875 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * @(#)vi_mode.c 6.4 (Berkeley) 5/8/91
- */
-
-/* vi_mode.c -- A vi emulation mode for Bash.
- Mostly written by Jeff Sparkes (jeff1@????).
- */
-
-
-/* **************************************************************** */
-/* */
-/* VI Emulation Mode */
-/* */
-/* **************************************************************** */
-
-/* Last string searched for from `/' or `?'. */
-static char *vi_last_search = (char *)NULL;
-static int vi_histpos;
-
-/* *** UNCLEAN *** */
-/* Command keys which do movement for xxx_to commands. */
-static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
-
-/* Keymap used for vi replace characters. Created dynamically since
- rarely used. */
-static Keymap vi_replace_map = (Keymap)NULL;
-
-/* The number of characters inserted in the last replace operation. */
-static vi_replace_count = 0;
-
-/* Yank the nth arg from the previous line into this line at point. */
-rl_vi_yank_arg (count)
- int count;
-{
- rl_yank_nth_arg (count);
-}
-
-/* Search again for the last thing searched for. */
-rl_vi_search_again (ignore, key)
- int ignore, key;
-{
- switch (key)
- {
- case 'n':
- rl_vi_dosearch (vi_last_search, -1);
- break;
-
- case 'N':
- rl_vi_dosearch (vi_last_search, 1);
- break;
- }
-}
-
-/* Do a vi style search. */
-rl_vi_search (count, key)
- int count, key;
-{
- int dir, c;
- char *p;
-
- switch (key)
- {
- case '?':
- dir = 1;
- break;
-
- case '/':
- dir = -1;
- break;
-
- default:
- ding ();
- return;
- }
-
- vi_histpos = where_history ();
- maybe_save_line ();
-
- /* Reuse the line input buffer to read the search string. */
- the_line[0] = 0;
- rl_end = rl_point = 0;
- p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
-
- sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
-
- rl_message (p);
-
- while (c = rl_read_key (in_stream))
- {
- switch (c)
- {
- case CTRL('W'):
- case CTRL('U'):
- case CTRL('H'):
- case RUBOUT:
- rl_dispatch (c, keymap);
- break;
-
- case ESC:
- case RETURN:
- case NEWLINE:
- goto dosearch;
- break;
-
- case CTRL('C'):
- maybe_unsave_line ();
- rl_clear_message ();
- rl_point = 0;
- ding ();
- return;
-
- default:
- rl_insert (1, c);
- break;
- }
- rl_redisplay ();
- }
- dosearch:
- if (vi_last_search)
- free (vi_last_search);
-
- vi_last_search = savestring (the_line);
- rl_vi_dosearch (the_line, dir);
-}
-
-rl_vi_dosearch (string, dir)
- char *string;
- int dir;
-{
- int old, save = vi_histpos;
- HIST_ENTRY *h;
-
- if (string == 0 || *string == 0 || vi_histpos < 0)
- {
- ding ();
- return;
- }
-
- if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
- {
- maybe_unsave_line ();
- rl_clear_message ();
- rl_point = 0;
- ding ();
- return;
- }
-
- vi_histpos = save;
-
- old = where_history ();
- history_set_pos (vi_histpos);
- h = current_history ();
- history_set_pos (old);
-
- strcpy (the_line, h->line);
- rl_undo_list = (UNDO_LIST *)h->data;
- rl_end = strlen (the_line);
- rl_point = 0;
- rl_clear_message ();
-}
-
-/* Completion, from vi's point of view. */
-rl_vi_complete (ignore, key)
- int ignore, key;
-{
- if (!whitespace (the_line[rl_point]))
- {
- rl_vi_end_word (1, 'E');
- rl_point++;
- }
- rl_complete_internal ('*');
- rl_vi_insertion_mode ();
-}
-
-/* Previous word in vi mode. */
-rl_vi_prev_word (count, key)
- int count, key;
-{
- if (count < 0)
- {
- rl_vi_next_word (-count, key);
- return;
- }
-
- if (uppercase_p (key))
- rl_vi_bWord (count);
- else
- rl_vi_bword (count);
-}
-
-/* Next word in vi mode. */
-rl_vi_next_word (count, key)
- int count;
-{
- if (count < 0)
- {
- rl_vi_prev_word (-count, key);
- return;
- }
-
- if (uppercase_p (key))
- rl_vi_fWord (count);
- else
- rl_vi_fword (count);
-}
-
-/* Move to the end of the ?next? word. */
-rl_vi_end_word (count, key)
- int count, key;
-{
- if (count < 0)
- {
- ding ();
- return;
- }
-
- if (uppercase_p (key))
- rl_vi_eWord (count);
- else
- rl_vi_eword (count);
-}
-
-/* Move forward a word the way that 'W' does. */
-rl_vi_fWord (count)
- int count;
-{
- while (count-- && rl_point < (rl_end - 1))
- {
- /* Skip until whitespace. */
- while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
- rl_point++;
-
- /* Now skip whitespace. */
- while (whitespace (the_line[rl_point]) && rl_point < rl_end)
- rl_point++;
- }
-}
-
-rl_vi_bWord (count)
- int count;
-{
- while (count-- && rl_point > 0)
- {
- while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
- while (rl_point >= 0 && !whitespace (the_line[rl_point]))
- rl_point--;
- rl_point++;
- }
-}
-
-rl_vi_eWord (count)
- int count;
-{
- while (count -- && rl_point < (rl_end - 1))
- {
- while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
- while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
- rl_point--;
- }
-}
-
-rl_vi_fword (count)
- int count;
-{
- while (count -- && rl_point < (rl_end - 1))
- {
- if (isident (the_line[rl_point]))
- {
- while (isident (the_line[rl_point]) && rl_point < rl_end)
- rl_point += 1;
- }
- else if (!whitespace (the_line[rl_point]))
- {
- while (!isident (the_line[rl_point]) &&
- !whitespace (the_line[rl_point]) && rl_point < rl_end)
- rl_point += 1;
- }
-
- while (whitespace (the_line[rl_point]) && rl_point < rl_end)
- rl_point++;
- }
-}
-
-rl_vi_bword (count)
- int count;
-{
- while (count -- && rl_point > 0)
- {
- while (--rl_point > 0 && whitespace (the_line[rl_point]));
- if (rl_point > 0)
- {
- if (isident (the_line[rl_point]))
- while (--rl_point >= 0 && isident (the_line[rl_point]));
- else
- while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
- !whitespace (the_line[rl_point]));
- rl_point++;
- }
- }
-}
-
-rl_vi_eword (count)
- int count;
-{
- while (count -- && rl_point < rl_end - 1)
- {
- while (++rl_point < rl_end && whitespace (the_line[rl_point]));
-
- if (rl_point < rl_end)
- {
- if (isident (the_line[rl_point]))
- while (++rl_point < rl_end && isident (the_line[rl_point]));
- else
- while (++rl_point < rl_end && !isident (the_line[rl_point])
- && !whitespace (the_line[rl_point]));
- rl_point--;
- }
- }
-}
-
-rl_vi_insert_beg ()
-{
- rl_beg_of_line ();
- rl_vi_insertion_mode ();
- return 0;
-}
-
-rl_vi_append_mode ()
-{
- if (rl_point < rl_end)
- rl_point += 1;
- rl_vi_insertion_mode ();
- return 0;
-}
-
-rl_vi_append_eol ()
-{
- rl_end_of_line ();
- rl_vi_append_mode ();
- return 0;
-}
-
-/* What to do in the case of C-d. */
-rl_vi_eof_maybe (count, c)
- int count, c;
-{
- rl_newline (1, '\n');
-}
-
-/* Insertion mode stuff. */
-
-/* Switching from one mode to the other really just involves
- switching keymaps. */
-rl_vi_insertion_mode ()
-{
- keymap = vi_insertion_keymap;
-}
-
-rl_vi_movement_mode ()
-{
- if (rl_point > 0)
- rl_backward (1);
-
- keymap = vi_movement_keymap;
- if (vi_doing_insert)
- {
- rl_end_undo_group ();
- vi_doing_insert = 0;
- }
-}
-
-rl_vi_arg_digit (count, c)
- int count, c;
-{
- if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
- rl_beg_of_line ();
- else
- rl_digit_argument (count, c);
-}
-
-/* Doesn't take an arg count in vi */
-rl_vi_change_case (ignore1, ignore2)
- int ignore1, ignore2;
-{
- char c = 0;
-
- if (uppercase_p (the_line[rl_point]))
- c = to_lower (the_line[rl_point]);
- else if (lowercase_p (the_line[rl_point]))
- c = to_upper (the_line[rl_point]);
-
- /* Vi is kind of strange here. */
- if (c)
- {
- rl_begin_undo_group ();
- rl_delete (1);
- rl_insert (1, c);
- rl_end_undo_group ();
- rl_vi_check ();
- }
- else
- rl_forward (1);
-}
-
-rl_vi_put (count, key)
- int count, key;
-{
- if (!uppercase_p (key))
- {
- if(rl_point != rl_end)
- rl_point++;
- }
-
- rl_yank ();
- rl_backward (1);
-}
-
-rl_vi_check ()
-{
- if (rl_point && rl_point == rl_end)
- rl_point--;
-}
-
-rl_vi_column (count)
-{
- if (count > rl_end)
- rl_end_of_line ();
- else
- rl_point = count - 1;
-}
-
-int
-rl_vi_domove ()
-{
- int c, save;
-
- rl_mark = rl_point;
- c = rl_read_key (in_stream);
-
- if (!member (c, vi_motion))
- {
- if (digit (c))
- {
- save = rl_numeric_arg;
- rl_digit_loop1 ();
- rl_numeric_arg *= save;
- }
- else
- return (-1);
- }
-
- rl_dispatch (c, keymap);
-
- /* No change in position means the command failed. */
- if (rl_mark == rl_point)
- return (-1);
-
- if ((c == 'w' || c == 'W') && rl_point < rl_end)
- {
- rl_point--;
- while((rl_point > 0) && whitespace (the_line[rl_point]))
- rl_point--;
- rl_point++;
- }
-
- if (rl_mark < rl_point)
- exchange (rl_point, rl_mark);
-
- return (0);
-}
-
-/* A simplified loop for vi. Don't dispatch key at end.
- Don't recognize minus sign? */
-rl_digit_loop1 ()
-{
- int key, c;
-
- while (1)
- {
- rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
- key = c = rl_read_key ();
-
- if (keymap[c].type == ISFUNC &&
- keymap[c].function == rl_universal_argument)
- {
- rl_numeric_arg *= 4;
- continue;
- }
- c = UNMETA (c);
- if (numeric (c))
- {
- if (rl_explicit_arg)
- rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
- else
- rl_numeric_arg = (c - '0');
- rl_explicit_arg = 1;
- }
- else
- {
- rl_clear_message ();
- rl_stuff_char (key);
- }
- }
-}
-
-rl_vi_delete_to (count, key)
- int count, key;
-{
- if (uppercase_p (key))
- rl_stuff_char ('$');
-
- if (rl_vi_domove ())
- {
- ding ();
- return;
- }
-
- rl_kill_text (rl_point, rl_mark);
-}
-
-rl_vi_change_to (count, key)
- int count, key;
-{
- if (uppercase_p (key))
- rl_stuff_char ('$');
-
- if (rl_vi_domove ())
- {
- ding ();
- return;
- }
-
- rl_begin_undo_group ();
- vi_doing_insert = 1;
- rl_kill_text (rl_point, rl_mark);
- rl_vi_insertion_mode ();
-}
-
-rl_vi_yank_to (count, key)
- int count, key;
-{
- int save = rl_point;
-
- if (uppercase_p (key))
- rl_stuff_char ('$');
-
- if (rl_vi_domove ())
- {
- ding ();
- return;
- }
-
- rl_begin_undo_group ();
- rl_kill_text (rl_point, rl_mark);
- rl_end_undo_group ();
- rl_do_undo ();
- rl_point = save;
-}
-
-rl_vi_delete (count)
-{
- if (rl_point >= rl_end - 1)
- {
- rl_delete (count);
- if (rl_point > 0)
- rl_backward (1);
- }
- else
- rl_delete (count);
-}
-
-/* Turn the current line into a comment in shell history. A ksh function */
-rl_vi_comment ()
-{
- rl_beg_of_line ();
- rl_insert_text (": "); /* # doesn't work in interactive mode */
- rl_redisplay ();
- rl_newline (1, '\010');
-}
-
-rl_vi_first_print ()
-{
- rl_back_to_indent ();
-}
-
-rl_back_to_indent (ignore1, ignore2)
- int ignore1, ignore2;
-{
- rl_beg_of_line ();
- while (rl_point < rl_end && whitespace (the_line[rl_point]))
- rl_point++;
-}
-
-/* NOTE: it is necessary that opposite directions are inverses */
-#define FTO 1 /* forward to */
-#define BTO -1 /* backward to */
-#define FFIND 2 /* forward find */
-#define BFIND -2 /* backward find */
-
-rl_vi_char_search (count, key)
- int count, key;
-{
- static char target;
- static int orig_dir, dir;
- int pos;
-
- if (key == ';' || key == ',')
- dir = (key == ';' ? orig_dir : -orig_dir);
- else
- {
- target = rl_read_key();
-
- switch (key)
- {
- case 't':
- orig_dir = dir = FTO;
- break;
-
- case 'T':
- orig_dir = dir = BTO;
- break;
-
- case 'f':
- orig_dir = dir = FFIND;
- break;
-
- case 'F':
- orig_dir = dir = BFIND;
- break;
- }
- }
-
- pos = rl_point;
-
- if (dir < 0)
- {
- pos--;
- do
- {
- if (the_line[pos] == target)
- {
- if (dir == BTO)
- rl_point = pos + 1;
- else
- rl_point = pos;
- return;
- }
- }
- while (pos--);
-
- if (pos < 0)
- {
- ding ();
- return;
- }
- }
- else
- { /* dir > 0 */
- pos++;
- do
- {
- if (the_line[pos] == target)
- {
- if (dir == FTO)
- rl_point = pos - 1;
- else
- rl_point = pos;
- return;
- }
- }
- while (++pos < rl_end);
-
- if (pos >= (rl_end - 1))
- ding ();
- }
-}
-
-/* Match brackets */
-rl_vi_match ()
-{
- int count = 1, brack, pos;
-
- pos = rl_point;
- if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
- {
- while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
- rl_point < rl_end - 1)
- rl_forward (1);
-
- if (brack <= 0)
- {
- rl_point = pos;
- ding ();
- return;
- }
- }
-
- pos = rl_point;
-
- if (brack < 0)
- {
- while (count)
- {
- if (--pos >= 0)
- {
- int b = rl_vi_bracktype (the_line[pos]);
- if (b == -brack)
- count--;
- else if (b == brack)
- count++;
- }
- else
- {
- ding ();
- return;
- }
- }
- }
- else
- { /* brack > 0 */
- while (count)
- {
- if (++pos < rl_end)
- {
- int b = rl_vi_bracktype (the_line[pos]);
- if (b == -brack)
- count--;
- else if (b == brack)
- count++;
- }
- else
- {
- ding ();
- return;
- }
- }
- }
- rl_point = pos;
-}
-
-int
-rl_vi_bracktype (c)
- int c;
-{
- switch (c)
- {
- case '(': return 1;
- case ')': return -1;
- case '[': return 2;
- case ']': return -2;
- case '{': return 3;
- case '}': return -3;
- default: return 0;
- }
-}
-
-rl_vi_change_char ()
-{
- int c;
-
- c = rl_read_key();
-
- switch (c)
- {
- case '\033':
- case CTRL('C'):
- return;
-
- default:
- rl_begin_undo_group ();
- rl_delete (1);
- rl_insert (1, c);
- rl_end_undo_group ();
- break;
- }
-}
-
-rl_vi_subst (count, key)
- int count, key;
-{
- rl_begin_undo_group ();
- vi_doing_insert = 1;
-
- if (uppercase_p (key))
- {
- rl_beg_of_line ();
- rl_kill_line (1);
- }
- else
- rl_delete (1);
-
- rl_vi_insertion_mode ();
-}
-
-rl_vi_overstrike (count, key)
- int count, key;
-{
- int i;
-
- if (vi_doing_insert == 0)
- {
- vi_doing_insert = 1;
- rl_begin_undo_group ();
- }
-
- for (i = 0; i < count; i++)
- {
- vi_replace_count++;
- rl_begin_undo_group ();
-
- if (rl_point < rl_end)
- {
- rl_delete (1);
- rl_insert (1, key);
- }
- else
- rl_insert (1, key);
-
- rl_end_undo_group ();
- }
-}
-
-rl_vi_overstrike_delete (count)
- int count;
-{
- int i, s;
-
- for (i = 0; i < count; i++)
- {
- if (vi_replace_count == 0)
- {
- ding ();
- break;
- }
- s = rl_point;
-
- if (rl_do_undo ())
- vi_replace_count--;
-
- if (rl_point == s)
- rl_backward (1);
- }
-
- if (vi_replace_count == 0 && vi_doing_insert)
- {
- rl_end_undo_group ();
- rl_do_undo ();
- vi_doing_insert = 0;
- }
-}
-
-rl_vi_replace ()
-{
- int i;
-
- vi_replace_count = 0;
-
- vi_replace_map = rl_make_bare_keymap ();
-
- for (i = ' '; i < 127; i++)
- vi_replace_map[i].function = rl_vi_overstrike;
-
- vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
- vi_replace_map[CTRL('H')].function = rl_vi_overstrike_delete;
- vi_replace_map[ESC].function = rl_vi_movement_mode;
- vi_replace_map[RETURN].function = rl_newline;
- vi_replace_map[NEWLINE].function = rl_newline;
- keymap = vi_replace_map;
-}
diff --git a/gnu/usr.bin/gdb/remote.c b/gnu/usr.bin/gdb/remote.c
deleted file mode 100644
index 8b65522d804d..000000000000
--- a/gnu/usr.bin/gdb/remote.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
- *
- * 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.
- *
- * $Header: /home/cvs/386BSD/src/gnu/usr.bin/gdb/remote.c,v 1.1 1993/06/29 09:47:34 nate Exp $;
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91";
-#endif /* not lint */
-
-#include "param.h"
-
-#include <stdio.h>
-#include <varargs.h>
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-
-#include "defs.h"
-#include "frame.h"
-#include "inferior.h"
-#include "wait.h"
-
-#include "kgdb_proto.h"
-
-static FILE *kiodebug;
-static int icache = 1;
-extern int kernel_debugging;
-
-static int remote_cache_valid;
-static int remote_instub;
-
-static void remote_signal();
-static void remote_debug();
-static void print_msg();
-
-static int remote_mtu;
-static int (*send_msg)();
-static int (*recv_msg)();
-static void (*closelink)();
-
-static u_char *inbuffer;
-static u_char *outbuffer;
-
-/*
- * Statistics.
- */
-static int remote_ierrs;
-static int remote_oerrs;
-static int remote_seqerrs;
-static int remote_spurious;
-
-#define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0)
-
-/*
- * Send an outbound message to the remote machine and read the reply.
- * Either or both message buffers may be NULL.
- */
-static int
-m_xchg(type, out, outlen, in, inlen)
- int type;
- u_char *out;
- int outlen;
- u_char *in;
- int *inlen;
-{
- register int err, (*send)() = send_msg, (*recv)() = recv_msg;
- int ack;
- static int seqbit = 0;
-
- if (!remote_instub) {
- remote_instub = 1;
- PUTCMD(KGDB_EXEC);
- }
-
- seqbit ^= KGDB_SEQ;
- while (1) {
- err = (*send)(type | seqbit, out, outlen);
- if (err) {
- ++remote_oerrs;
- if (kiodebug)
- remote_debug("send error %d\n", err);
- }
- if (kiodebug)
- print_msg(type | seqbit, out, outlen, 'O');
-
- recv:
- err = (*recv)(&ack, in, inlen);
- if (err) {
- ++remote_ierrs;
- if (kiodebug)
- remote_debug("recv error %d\n", err);
- remote_cache_valid = 0;
- } else if (kiodebug)
- print_msg(ack, in, inlen ? *inlen : 0, 'I');
-
- if (err)
- continue;
-
- if ((ack & KGDB_ACK) == 0 || KGDB_CMD(ack) != KGDB_CMD(type)) {
- ++remote_spurious;
- continue;
- }
- if ((ack & KGDB_SEQ) ^ seqbit) {
- ++remote_seqerrs;
- goto recv;
- }
- return ack;
- }
-}
-
-/*
- * Wait for the specified message type. Discard anything else.
- * (this is used by 'remote-signal' to help us resync with other side.)
- */
-static void
-m_recv(type, in, inlen)
- int type;
- u_char *in;
- int *inlen;
-{
- int reply, err;
-
- while (1) {
- err = (*recv_msg)(&reply, in, inlen);
- if (err) {
- ++remote_ierrs;
- if (kiodebug)
- remote_debug("recv error %d\n", err);
- } else if (kiodebug)
- print_msg(reply, in, inlen ? *inlen : 0, 'I');
-
- if (KGDB_CMD(reply) == type)
- return;
- ++remote_spurious;
- }
-}
-
-/*
- * Send a message. Do not wait for *any* response from the other side.
- * Some other thread of control will pick up the ack that will be generated.
- */
-static void
-m_send(type, buf, len)
- int type;
- u_char *buf;
- int len;
-{
- int err;
-
- if (!remote_instub) {
- remote_instub = 1;
- PUTCMD(KGDB_EXEC);
- }
-
- err = (*send_msg)(type, buf, len);
- if (err) {
- ++remote_ierrs;
- if (kiodebug)
- remote_debug("[send error %d] ", err);
- }
- if (kiodebug)
- print_msg(type, buf, len, 'O');
-}
-
-/*
- * Open a connection to a remote debugger.
- * NAME is the filename used for communication.
- */
-void
-remote_open(name, from_tty)
- char *name;
- int from_tty;
-{
- int bufsize;
-
- remote_debugging = 0;
- if (sl_open(name, &send_msg, &recv_msg, &closelink, &remote_mtu,
- &bufsize))
- return;
- if (from_tty)
- printf("Remote debugging using %s\n", name);
- remote_debugging = 1;
-
- remote_cache_valid = 0;
-
- inbuffer = (u_char *)malloc(bufsize);
- outbuffer = (u_char *)malloc(bufsize);
-
- remote_signal();
-
- remote_ierrs = 0;
- remote_oerrs = 0;
- remote_spurious = 0;
-}
-
-/*
- * Close the open connection to the remote debugger. Use this when you want
- * to detach and do something else with your gdb.
- */
-void
-remote_close(from_tty)
- int from_tty;
-{
- if (!remote_debugging)
- error("remote debugging not enabled");
-
- remote_debugging = 0;
- /*
- * Take remote machine out of debug mode.
- */
- (void)PUTCMD(KGDB_KILL);
- (*closelink)();
- if (from_tty)
- printf("Ending remote debugging\n");
-
- free((char *)inbuffer);
- free((char *)outbuffer);
-}
-
-/*
- * Tell the remote machine to resume.
- */
-int
-remote_resume(step, signal)
- int step, signal;
-{
- if (!step) {
- (void)PUTCMD(KGDB_CONT);
- remote_instub = 0;
- } else {
-#ifdef NO_SINGLE_STEP
- single_step(0);
-#else
- (void)PUTCMD(KGDB_STEP);
-#endif
- }
-}
-
-/*
- * Wait until the remote machine stops, then return, storing status in STATUS
- * just as `wait' would.
- */
-int
-remote_wait(status)
- WAITTYPE *status;
-{
- int len;
-
- WSETEXIT((*status), 0);
- /*
- * When the machine stops, it will send us a KGDB_SIGNAL message,
- * so we wait for one of these.
- */
- m_recv(KGDB_SIGNAL, inbuffer, &len);
- WSETSTOP((*status), inbuffer[0]);
-}
-
-/*
- * Register context as of last remote_fetch_registers().
- */
-static char reg_cache[REGISTER_BYTES];
-
-/*
- * Read the remote registers into the block REGS.
- */
-void
-remote_fetch_registers(regs)
- char *regs;
-{
- int regno, len, rlen, ack;
- u_char *cp, *ep;
-
- regno = -1;
- do {
- outbuffer[0] = regno + 1;
- ack = m_xchg(remote_cache_valid ?
- KGDB_REG_R|KGDB_DELTA : KGDB_REG_R,
- outbuffer, 1, inbuffer, &len);
- cp = inbuffer;
- ep = cp + len;
- while (cp < ep) {
- regno = *cp++;
- rlen = REGISTER_RAW_SIZE(regno);
- bcopy((char *)cp,
- &reg_cache[REGISTER_BYTE(regno)], rlen);
- cp += rlen;
- }
- } while (ack & KGDB_MORE);
-
- remote_cache_valid = 1;
- bcopy(reg_cache, regs, REGISTER_BYTES);
-}
-
-/*
- * Store the remote registers from the contents of the block REGS.
- */
-void
-remote_store_registers(regs)
- char *regs;
-{
- u_char *cp, *ep;
- int regno, off, rlen;
-
- cp = outbuffer;
- ep = cp + remote_mtu;
-
- for (regno = 0; regno < NUM_REGS; ++regno) {
- off = REGISTER_BYTE(regno);
- rlen = REGISTER_RAW_SIZE(regno);
- if (!remote_cache_valid ||
- bcmp(&regs[off], &reg_cache[off], rlen) != 0) {
- if (cp + rlen + 1 >= ep) {
- (void)m_xchg(KGDB_REG_W,
- outbuffer, cp - outbuffer,
- (u_char *)0, (int *)0);
- cp = outbuffer;
- }
- *cp++ = regno;
- bcopy(&regs[off], cp, rlen);
- cp += rlen;
- }
- }
- if (cp != outbuffer)
- (void)m_xchg(KGDB_REG_W, outbuffer, cp - outbuffer,
- (u_char *)0, (int *)0);
- bcopy(regs, reg_cache, REGISTER_BYTES);
-}
-
-/*
- * Store a chunk of memory into the remote host.
- * 'remote_addr' is the address in the remote memory space.
- * 'cp' is the address of the buffer in our space, and 'len' is
- * the number of bytes. Returns an errno status.
- */
-int
-remote_write_inferior_memory(remote_addr, cp, len)
- CORE_ADDR remote_addr;
- u_char *cp;
- int len;
-{
- int cnt;
-
- while (len > 0) {
- cnt = min(len, remote_mtu - 4);
- bcopy((char *)&remote_addr, outbuffer, 4);
- bcopy(cp, outbuffer + 4, cnt);
- (void)m_xchg(KGDB_MEM_W, outbuffer, cnt + 4, inbuffer, &len);
-
- if (inbuffer[0])
- return inbuffer[0];
-
- remote_addr += cnt;
- cp += cnt;
- len -= cnt;
- }
- return 0;
-}
-
-/*
- * Read memory data directly from the remote machine.
- * 'remote_addr' is the address in the remote memory space.
- * 'cp' is the address of the buffer in our space, and 'len' is
- * the number of bytes. Returns an errno status.
- */
-static int
-remote_read_memory(remote_addr, cp, len)
- CORE_ADDR remote_addr;
- u_char *cp;
- int len;
-{
- int cnt, inlen;
-
- while (len > 0) {
- cnt = min(len, remote_mtu - 1);
- outbuffer[0] = cnt;
- bcopy((char *)&remote_addr, (char *)&outbuffer[1], 4);
-
- (void)m_xchg(KGDB_MEM_R, outbuffer, 5, inbuffer, &inlen);
-
- if (inbuffer[0] != 0)
- return inbuffer[0];
-
- if (cnt != inlen - 1)
- /* XXX */
- error("remote_read_memory() request botched");
-
- bcopy((char *)&inbuffer[1], (char *)cp, cnt);
-
- remote_addr += cnt;
- cp += cnt;
- len -= cnt;
- }
- return 0;
-}
-
-int
-remote_read_inferior_memory(remote_addr, cp, len)
- CORE_ADDR remote_addr;
- char *cp;
- int len;
-{
- int stat = 0;
-
- if (icache) {
- extern CORE_ADDR text_start, text_end;
- CORE_ADDR xferend = remote_addr + len;
-
- if (remote_addr < text_end && text_start < xferend) {
- /*
- * at least part of this xfer is in the text
- * space -- xfer the overlap from the exec file.
- */
- if (remote_addr >= text_start && xferend < text_end)
- return (xfer_core_file(remote_addr, cp, len));
- if (remote_addr >= text_start) {
- int i = text_end - remote_addr;
-
- if (stat = xfer_core_file(remote_addr, cp, i))
- return (stat);
- remote_addr += i;
- cp += i;
- len -= i;
- } else if (xferend <= text_end) {
- int i = xferend - text_start;
-
- len = text_start - remote_addr;
- if (stat = xfer_core_file(text_start,
- cp + len, i))
- return (stat);
- }
- }
- }
- return remote_read_memory(remote_addr, cp, len);
-}
-
-/*
- * Signal the remote machine. The remote end might be idle or it might
- * already be in debug mode -- we need to handle both case. Thus, we use
- * the framing character as the wakeup byte, and send a SIGNAL packet.
- * If the remote host is idle, the framing character will wake it up.
- * If it is in the kgdb stub, then we will get a SIGNAL reply.
- */
-static void
-remote_signal()
-{
- if (!remote_debugging)
- printf("Remote debugging not enabled.\n");
- else {
- remote_instub = 0;
- m_send(KGDB_SIGNAL, (u_char *)0, 0);
- }
-}
-
-static void
-remote_signal_command()
-{
- extern int stop_after_attach;
-
- if (!remote_debugging)
- error("Not debugging remote.");
- remote_cache_valid = 0;
- remote_signal();
- restart_remote();
-}
-
-/*
- * Print a message for debugging.
- */
-static void
-print_msg(type, buf, len, dir)
- int type;
- u_char *buf;
- int len;
- int dir;
-{
- int i;
- char *s;
-
- switch (KGDB_CMD(type)) {
- case KGDB_MEM_R: s = "memr"; break;
- case KGDB_MEM_W: s = "memw"; break;
- case KGDB_REG_R: s = "regr"; break;
- case KGDB_REG_W: s = "regw"; break;
- case KGDB_CONT: s = "cont"; break;
- case KGDB_STEP: s = "step"; break;
- case KGDB_KILL: s = "kill"; break;
- case KGDB_SIGNAL: s = "sig "; break;
- case KGDB_EXEC: s = "exec"; break;
- default: s = "unk "; break;
- }
- remote_debug("%c %c%c%c%c %s (%02x): ", dir,
- (type & KGDB_ACK) ? 'A' : '.',
- (type & KGDB_DELTA) ? 'D' : '.',
- (type & KGDB_MORE) ? 'M' : '.',
- (type & KGDB_SEQ) ? '-' : '+',
- s, type);
- if (buf)
- for (i = 0; i < len; ++i)
- remote_debug("%02x", buf[i]);
- remote_debug("\n");
-}
-
-static void
-set_remote_text_refs_command(arg, from_tty)
- char *arg;
- int from_tty;
-{
- icache = !parse_binary_operation("set remote-text-refs", arg);
-}
-
-static void
-remote_debug_command(arg, from_tty)
- char *arg;
- int from_tty;
-{
- char *name;
-
- if (kiodebug != 0 && kiodebug != stderr)
- (void)fclose(kiodebug);
-
- if (arg == 0) {
- kiodebug = 0;
- printf("Remote debugging off.\n");
- return;
- }
- if (arg[0] == '-') {
- kiodebug = stderr;
- name = "stderr";
- } else {
- kiodebug = fopen(arg, "w");
- if (kiodebug == 0) {
- printf("Cannot open '%s'.\n", arg);
- return;
- }
- name = arg;
- }
- printf("Remote debugging output routed to %s.\n", name);
-}
-
-/* ARGSUSED */
-static void
-remote_info(arg, from_tty)
- char *arg;
- int from_tty;
-{
- printf("Using %s for text references.\n",
- icache? "local executable" : "remote");
- printf("Protocol debugging is %s.\n", kiodebug? "on" : "off");
- printf("%d spurious input messages.\n", remote_spurious);
- printf("%d input errors; %d output errors; %d sequence errors.\n",
- remote_ierrs, remote_oerrs, remote_seqerrs);
-}
-
-/* VARARGS */
-static void
-remote_debug(va_alist)
- va_dcl
-{
- register char *cp;
- va_list ap;
-
- va_start(ap);
- cp = va_arg(ap, char *);
- (void)vfprintf(kiodebug, cp, ap);
- va_end(ap);
- fflush(kiodebug);
-}
-
-extern struct cmd_list_element *setlist;
-
-void
-_initialize_remote()
-{
- add_com("remote-signal", class_run, remote_signal_command,
- "If remote debugging, send interrupt signal to remote.");
- add_cmd("remote-text-refs", class_support,
- set_remote_text_refs_command,
-"Enable/disable use of local executable for text segment references.\n\
-If on, all memory read/writes go to remote.\n\
-If off, text segment reads use the local executable.",
- &setlist);
-
- add_com("remote-debug", class_run, remote_debug_command,
-"With a file name argument, enables output of remote protocol debugging\n\
-messages to said file. If file is `-', stderr is used.\n\
-With no argument, remote debugging is disabled.");
-
- add_info("remote", remote_info,
- "Show current settings of remote debugging options.");
-}
-
diff --git a/gnu/usr.bin/gdb/symtab.c b/gnu/usr.bin/gdb/symtab.c
deleted file mode 100644
index 7b2dd7c93331..000000000000
--- a/gnu/usr.bin/gdb/symtab.c
+++ /dev/null
@@ -1,2473 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * $Header: /home/cvs/386BSD/src/gnu/usr.bin/gdb/symtab.c,v 1.2 1993/12/01 16:44:43 ats Exp $;
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)symtab.c 6.3 (Berkeley) 5/8/91";
-#endif /* not lint */
-
-/* Symbol table lookup for the GNU debugger, GDB.
- Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-GDB is free software; you can 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.
-
-GDB is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdio.h>
-#include "defs.h"
-#include "param.h"
-#include "symtab.h"
-
-#include <obstack.h>
-#include <assert.h>
-
-char *index ();
-extern char *cplus_demangle ();
-extern struct value * value_of_this ();
-
-/* Allocate an obstack to hold objects that should be freed
- when we load a new symbol table.
- This includes the symbols made by dbxread
- and the types that are not permanent. */
-
-struct obstack obstack1;
-
-struct obstack *symbol_obstack = &obstack1;
-
-/* This obstack will be used for partial_symbol objects. It can
- probably actually be the same as the symbol_obstack above, but I'd
- like to keep them seperate for now. If I want to later, I'll
- replace one with the other. */
-
-struct obstack obstack2;
-
-struct obstack *psymbol_obstack = &obstack2;
-
-/* These variables point to the objects
- representing the predefined C data types. */
-
-struct type *builtin_type_void;
-struct type *builtin_type_char;
-struct type *builtin_type_short;
-struct type *builtin_type_int;
-struct type *builtin_type_long;
-#ifdef LONG_LONG
-struct type *builtin_type_long_long;
-#endif
-struct type *builtin_type_unsigned_char;
-struct type *builtin_type_unsigned_short;
-struct type *builtin_type_unsigned_int;
-struct type *builtin_type_unsigned_long;
-#ifdef LONG_LONG
-struct type *builtin_type_unsigned_long_long;
-#endif
-struct type *builtin_type_float;
-struct type *builtin_type_double;
-
-/* Block in which the most recently searched-for symbol was found.
- Might be better to make this a parameter to lookup_symbol and
- value_of_this. */
-struct block *block_found;
-
-/* Functions */
-static int find_line_common ();
-int lookup_misc_func ();
-struct partial_symtab *lookup_partial_symtab ();
-struct symtab *psymtab_to_symtab ();
-static struct partial_symbol *lookup_partial_symbol ();
-
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
-
-static struct symtab *
-lookup_symtab_1 (name)
- char *name;
-{
- register struct symtab *s;
- register struct partial_symtab *ps;
- register char *slash = index (name, '/');
- register int len = strlen (name);
-
- for (s = symtab_list; s; s = s->next)
- if (!strcmp (name, s->filename))
- return s;
-
- for (ps = partial_symtab_list; ps; ps = ps->next)
- if (!strcmp (name, ps->filename))
- {
- if (ps->readin)
- fatal ("Internal: readin pst found when no symtab found.");
- s = psymtab_to_symtab (ps);
- return s;
- }
-
- if (!slash)
- {
- for (s = symtab_list; s; s = s->next)
- {
- int l = strlen (s->filename);
-
- if (s->filename[l - len -1] == '/'
- && !strcmp (s->filename + l - len, name))
- return s;
- }
-
- for (ps = partial_symtab_list; ps; ps = ps->next)
- {
- int l = strlen (ps->filename);
-
- if (ps->filename[l - len - 1] == '/'
- && !strcmp (ps->filename + l - len, name))
- {
- if (ps->readin)
- fatal ("Internal: readin pst found when no symtab found.");
- s = psymtab_to_symtab (ps);
- return s;
- }
- }
- }
- return 0;
-}
-
-/* Lookup the symbol table of a source file named NAME. Try a couple
- of variations if the first lookup doesn't work. */
-
-struct symtab *
-lookup_symtab (name)
- char *name;
-{
- register struct symtab *s;
- register char *copy;
-
- s = lookup_symtab_1 (name);
- if (s) return s;
-
- /* If name not found as specified, see if adding ".c" helps. */
-
- copy = (char *) alloca (strlen (name) + 3);
- strcpy (copy, name);
- strcat (copy, ".c");
- s = lookup_symtab_1 (copy);
- if (s) return s;
-
- /* We didn't find anything; die. */
- return 0;
-}
-
-/* Lookup the partial symbol table of a source file named NAME. This
- only returns true on an exact match (ie. this semantics are
- different from lookup_symtab. */
-
-struct partial_symtab *
-lookup_partial_symtab (name)
-char *name;
-{
- register struct partial_symtab *s;
- register char *copy;
-
- for (s = partial_symtab_list; s; s = s->next)
- if (!strcmp (name, s->filename))
- return s;
-
- return 0;
-}
-
-/* Lookup a typedef or primitive type named NAME,
- visible in lexical block BLOCK.
- If NOERR is nonzero, return zero if NAME is not suitably defined. */
-
-struct type *
-lookup_typename (name, block, noerr)
- char *name;
- struct block *block;
- int noerr;
-{
- register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE, 0);
- if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
- {
- if (!strcmp (name, "int"))
- return builtin_type_int;
- if (!strcmp (name, "long"))
- return builtin_type_long;
- if (!strcmp (name, "short"))
- return builtin_type_short;
- if (!strcmp (name, "char"))
- return builtin_type_char;
- if (!strcmp (name, "float"))
- return builtin_type_float;
- if (!strcmp (name, "double"))
- return builtin_type_double;
- if (!strcmp (name, "void"))
- return builtin_type_void;
-
- if (noerr)
- return 0;
- error ("No type named %s.", name);
- }
- return SYMBOL_TYPE (sym);
-}
-
-struct type *
-lookup_unsigned_typename (name)
- char *name;
-{
- if (!strcmp (name, "int"))
- return builtin_type_unsigned_int;
- if (!strcmp (name, "long"))
- return builtin_type_unsigned_long;
- if (!strcmp (name, "short"))
- return builtin_type_unsigned_short;
- if (!strcmp (name, "char"))
- return builtin_type_unsigned_char;
- error ("No type named unsigned %s.", name);
-}
-
-/* Lookup a structure type named "struct NAME",
- visible in lexical block BLOCK. */
-
-struct type *
-lookup_struct (name, block)
- char *name;
- struct block *block;
-{
- register struct symbol *sym
- = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
-
- if (sym == 0)
- error ("No struct type named %s.", name);
- if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
- error ("This context has class, union or enum %s, not a struct.", name);
- return SYMBOL_TYPE (sym);
-}
-
-/* Lookup a union type named "union NAME",
- visible in lexical block BLOCK. */
-
-struct type *
-lookup_union (name, block)
- char *name;
- struct block *block;
-{
- register struct symbol *sym
- = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
-
- if (sym == 0)
- error ("No union type named %s.", name);
- if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION)
- error ("This context has class, struct or enum %s, not a union.", name);
- return SYMBOL_TYPE (sym);
-}
-
-/* Lookup an enum type named "enum NAME",
- visible in lexical block BLOCK. */
-
-struct type *
-lookup_enum (name, block)
- char *name;
- struct block *block;
-{
- register struct symbol *sym
- = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
- if (sym == 0)
- error ("No enum type named %s.", name);
- if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM)
- error ("This context has class, struct or union %s, not an enum.", name);
- return SYMBOL_TYPE (sym);
-}
-
-/* Given a type TYPE, lookup the type of the component of type named
- NAME. */
-
-struct type *
-lookup_struct_elt_type (type, name)
- struct type *type;
- char *name;
-{
- struct type *t;
- int i;
- char *errmsg;
-
- if (TYPE_CODE (type) != TYPE_CODE_STRUCT
- && TYPE_CODE (type) != TYPE_CODE_UNION)
- {
- terminal_ours ();
- fflush (stdout);
- fprintf (stderr, "Type ");
- type_print (type, "", stderr, -1);
- fprintf (stderr, " is not a structure or union type.\n");
- return_to_top_level ();
- }
-
- for (i = TYPE_NFIELDS (type) - 1; i >= 0; i--)
- if (!strcmp (TYPE_FIELD_NAME (type, i), name))
- return TYPE_FIELD_TYPE (type, i);
-
- terminal_ours ();
- fflush (stdout);
- fprintf (stderr, "Type ");
- type_print (type, "", stderr, -1);
- fprintf (stderr, " has no component named %s\n", name);
- return_to_top_level ();
-}
-
-/* Given a type TYPE, return a type of pointers to that type.
- May need to construct such a type if this is the first use.
-
- C++: use TYPE_MAIN_VARIANT and TYPE_CHAIN to keep pointer
- to member types under control. */
-
-struct type *
-lookup_pointer_type (type)
- struct type *type;
-{
- register struct type *ptype = TYPE_POINTER_TYPE (type);
- if (ptype) return TYPE_MAIN_VARIANT (ptype);
-
- /* This is the first time anyone wanted a pointer to a TYPE. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- ptype = (struct type *) xmalloc (sizeof (struct type));
- else
- ptype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- bzero (ptype, sizeof (struct type));
- TYPE_MAIN_VARIANT (ptype) = ptype;
- TYPE_TARGET_TYPE (ptype) = type;
- TYPE_POINTER_TYPE (type) = ptype;
- /* New type is permanent if type pointed to is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
- /* We assume the machine has only one representation for pointers! */
- TYPE_LENGTH (ptype) = sizeof (char *);
- TYPE_CODE (ptype) = TYPE_CODE_PTR;
- return ptype;
-}
-
-struct type *
-lookup_reference_type (type)
- struct type *type;
-{
- register struct type *rtype = TYPE_REFERENCE_TYPE (type);
- if (rtype) return TYPE_MAIN_VARIANT (rtype);
-
- /* This is the first time anyone wanted a pointer to a TYPE. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- rtype = (struct type *) xmalloc (sizeof (struct type));
- else
- rtype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- bzero (rtype, sizeof (struct type));
- TYPE_MAIN_VARIANT (rtype) = rtype;
- TYPE_TARGET_TYPE (rtype) = type;
- TYPE_REFERENCE_TYPE (type) = rtype;
- /* New type is permanent if type pointed to is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (rtype) |= TYPE_FLAG_PERM;
- /* We assume the machine has only one representation for pointers! */
- TYPE_LENGTH (rtype) = sizeof (char *);
- TYPE_CODE (rtype) = TYPE_CODE_REF;
- return rtype;
-}
-
-
-/* Implement direct support for MEMBER_TYPE in GNU C++.
- May need to construct such a type if this is the first use.
- The TYPE is the type of the member. The DOMAIN is the type
- of the aggregate that the member belongs to. */
-
-struct type *
-lookup_member_type (type, domain)
- struct type *type, *domain;
-{
- register struct type *mtype = TYPE_MAIN_VARIANT (type);
- struct type *main_type;
-
- main_type = mtype;
- while (mtype)
- {
- if (TYPE_DOMAIN_TYPE (mtype) == domain)
- return mtype;
- mtype = TYPE_NEXT_VARIANT (mtype);
- }
-
- /* This is the first time anyone wanted this member type. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- mtype = (struct type *) xmalloc (sizeof (struct type));
- else
- mtype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- bzero (mtype, sizeof (struct type));
- if (main_type == 0)
- main_type = mtype;
- else
- {
- TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
- TYPE_NEXT_VARIANT (main_type) = mtype;
- }
- TYPE_MAIN_VARIANT (mtype) = main_type;
- TYPE_TARGET_TYPE (mtype) = type;
- TYPE_DOMAIN_TYPE (mtype) = domain;
- /* New type is permanent if type pointed to is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
-
- /* In practice, this is never used. */
- TYPE_LENGTH (mtype) = 1;
- TYPE_CODE (mtype) = TYPE_CODE_MEMBER;
-
-#if 0
- /* Now splice in the new member pointer type. */
- if (main_type)
- {
- /* This type was not "smashed". */
- TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
- TYPE_CHAIN (main_type) = mtype;
- }
-#endif
-
- return mtype;
-}
-
-struct type *
-lookup_method_type (type, domain, args)
- struct type *type, *domain, **args;
-{
- register struct type *mtype = TYPE_MAIN_VARIANT (type);
- struct type *main_type;
-
- main_type = mtype;
- while (mtype)
- {
- if (TYPE_DOMAIN_TYPE (mtype) == domain)
- {
- struct type **t1 = args;
- struct type **t2 = TYPE_ARG_TYPES (mtype);
- if (t2)
- {
- int i;
- for (i = 0; t1[i] != 0 && t1[i]->code != TYPE_CODE_VOID; i++)
- if (t1[i] != t2[i])
- break;
- if (t1[i] == t2[i])
- return mtype;
- }
- }
- mtype = TYPE_NEXT_VARIANT (mtype);
- }
-
- /* This is the first time anyone wanted this member type. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- mtype = (struct type *) xmalloc (sizeof (struct type));
- else
- mtype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- bzero (mtype, sizeof (struct type));
- if (main_type == 0)
- main_type = mtype;
- else
- {
- TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
- TYPE_NEXT_VARIANT (main_type) = mtype;
- }
- TYPE_MAIN_VARIANT (mtype) = main_type;
- TYPE_TARGET_TYPE (mtype) = type;
- TYPE_DOMAIN_TYPE (mtype) = domain;
- TYPE_ARG_TYPES (mtype) = args;
- /* New type is permanent if type pointed to is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
-
- /* In practice, this is never used. */
- TYPE_LENGTH (mtype) = 1;
- TYPE_CODE (mtype) = TYPE_CODE_METHOD;
-
-#if 0
- /* Now splice in the new member pointer type. */
- if (main_type)
- {
- /* This type was not "smashed". */
- TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
- TYPE_CHAIN (main_type) = mtype;
- }
-#endif
-
- return mtype;
-}
-
-/* Given a type TYPE, return a type which has offset OFFSET,
- via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC.
- May need to construct such a type if none exists. */
-struct type *
-lookup_basetype_type (type, offset, via_virtual, via_public)
- struct type *type;
- int offset;
- int via_virtual, via_public;
-{
- register struct type *btype = TYPE_MAIN_VARIANT (type);
- struct type *main_type;
-
- if (offset != 0)
- {
- printf ("Internal error: type offset non-zero in lookup_basetype_type");
- offset = 0;
- }
-
- main_type = btype;
- while (btype)
- {
- if (/* TYPE_OFFSET (btype) == offset
- && */ TYPE_VIA_PUBLIC (btype) == via_public
- && TYPE_VIA_VIRTUAL (btype) == via_virtual)
- return btype;
- btype = TYPE_NEXT_VARIANT (btype);
- }
-
- /* This is the first time anyone wanted this member type. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- btype = (struct type *) xmalloc (sizeof (struct type));
- else
- btype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- if (main_type == 0)
- {
- main_type = btype;
- bzero (btype, sizeof (struct type));
- TYPE_MAIN_VARIANT (btype) = main_type;
- }
- else
- {
- bcopy (main_type, btype, sizeof (struct type));
- TYPE_NEXT_VARIANT (main_type) = btype;
- }
-/* TYPE_OFFSET (btype) = offset; */
- if (via_public)
- TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_PUBLIC;
- if (via_virtual)
- TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_VIRTUAL;
- /* New type is permanent if type pointed to is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (btype) |= TYPE_FLAG_PERM;
-
- /* In practice, this is never used. */
- TYPE_LENGTH (btype) = 1;
- TYPE_CODE (btype) = TYPE_CODE_STRUCT;
-
- return btype;
-}
-
-/* Given a type TYPE, return a type of functions that return that type.
- May need to construct such a type if this is the first use. */
-
-struct type *
-lookup_function_type (type)
- struct type *type;
-{
- register struct type *ptype = TYPE_FUNCTION_TYPE (type);
- if (ptype) return ptype;
-
- /* This is the first time anyone wanted a function returning a TYPE. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- ptype = (struct type *) xmalloc (sizeof (struct type));
- else
- ptype = (struct type *) obstack_alloc (symbol_obstack,
- sizeof (struct type));
-
- bzero (ptype, sizeof (struct type));
- TYPE_TARGET_TYPE (ptype) = type;
- TYPE_FUNCTION_TYPE (type) = ptype;
- /* New type is permanent if type returned is permanent. */
- if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
- TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
- TYPE_LENGTH (ptype) = 1;
- TYPE_CODE (ptype) = TYPE_CODE_FUNC;
- TYPE_NFIELDS (ptype) = 0;
- return ptype;
-}
-
-/* Create an array type. Elements will be of type TYPE, and there will
- be NUM of them.
-
- Eventually this should be extended to take two more arguments which
- specify the bounds of the array and the type of the index.
- It should also be changed to be a "lookup" function, with the
- appropriate data structures added to the type field.
- Then read array type should call here. */
-
-struct type *
-create_array_type (element_type, number)
- struct type *element_type;
- int number;
-{
- struct type *result_type = (struct type *)
- obstack_alloc (symbol_obstack, sizeof (struct type));
-
- bzero (result_type, sizeof (struct type));
-
- TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
- TYPE_TARGET_TYPE (result_type) = element_type;
- TYPE_LENGTH (result_type) = number * TYPE_LENGTH (element_type);
- TYPE_NFIELDS (result_type) = 1;
- TYPE_FIELDS (result_type) =
- (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field));
- TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int;
- TYPE_VPTR_FIELDNO (result_type) = -1;
-
- return result_type;
-}
-
-
-/* Smash TYPE to be a type of pointers to TO_TYPE.
- If TO_TYPE is not permanent and has no pointer-type yet,
- record TYPE as its pointer-type. */
-
-void
-smash_to_pointer_type (type, to_type)
- struct type *type, *to_type;
-{
- int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
-
- bzero (type, sizeof (struct type));
- TYPE_TARGET_TYPE (type) = to_type;
- /* We assume the machine has only one representation for pointers! */
- TYPE_LENGTH (type) = sizeof (char *);
- TYPE_CODE (type) = TYPE_CODE_PTR;
-
- TYPE_MAIN_VARIANT (type) = type;
-
- if (type_permanent)
- TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
-
- if (TYPE_POINTER_TYPE (to_type) == 0
- && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
- || type_permanent))
- {
- TYPE_POINTER_TYPE (to_type) = type;
- }
-}
-
-/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE. */
-
-void
-smash_to_member_type (type, domain, to_type)
- struct type *type, *domain, *to_type;
-{
- bzero (type, sizeof (struct type));
- TYPE_TARGET_TYPE (type) = to_type;
- TYPE_DOMAIN_TYPE (type) = domain;
-
- /* In practice, this is never needed. */
- TYPE_LENGTH (type) = 1;
- TYPE_CODE (type) = TYPE_CODE_MEMBER;
-
- TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type);
-}
-
-/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. */
-
-void
-smash_to_method_type (type, domain, to_type, args)
- struct type *type, *domain, *to_type, **args;
-{
- bzero (type, sizeof (struct type));
- TYPE_TARGET_TYPE (type) = to_type;
- TYPE_DOMAIN_TYPE (type) = domain;
- TYPE_ARG_TYPES (type) = args;
-
- /* In practice, this is never needed. */
- TYPE_LENGTH (type) = 1;
- TYPE_CODE (type) = TYPE_CODE_METHOD;
-
- TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type, args);
-}
-
-/* Smash TYPE to be a type of reference to TO_TYPE.
- If TO_TYPE is not permanent and has no pointer-type yet,
- record TYPE as its pointer-type. */
-
-void
-smash_to_reference_type (type, to_type)
- struct type *type, *to_type;
-{
- int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
-
- bzero (type, sizeof (struct type));
- TYPE_TARGET_TYPE (type) = to_type;
- /* We assume the machine has only one representation for pointers! */
- TYPE_LENGTH (type) = sizeof (char *);
- TYPE_CODE (type) = TYPE_CODE_REF;
-
- TYPE_MAIN_VARIANT (type) = type;
-
- if (type_permanent)
- TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
-
- if (TYPE_REFERENCE_TYPE (to_type) == 0
- && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
- || type_permanent))
- {
- TYPE_REFERENCE_TYPE (to_type) = type;
- }
-}
-
-/* Smash TYPE to be a type of functions returning TO_TYPE.
- If TO_TYPE is not permanent and has no function-type yet,
- record TYPE as its function-type. */
-
-void
-smash_to_function_type (type, to_type)
- struct type *type, *to_type;
-{
- int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
-
- bzero (type, sizeof (struct type));
- TYPE_TARGET_TYPE (type) = to_type;
- TYPE_LENGTH (type) = 1;
- TYPE_CODE (type) = TYPE_CODE_FUNC;
- TYPE_NFIELDS (type) = 0;
-
- if (type_permanent)
- TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
-
- if (TYPE_FUNCTION_TYPE (to_type) == 0
- && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
- || type_permanent))
- {
- TYPE_FUNCTION_TYPE (to_type) = type;
- }
-}
-
-/* Find which partial symtab on the partial_symtab_list contains
- PC. Return 0 if none. */
-
-struct partial_symtab *
-find_pc_psymtab (pc)
- register CORE_ADDR pc;
-{
- register struct partial_symtab *ps;
-
- for (ps = partial_symtab_list; ps; ps = ps->next)
- if (pc >= ps->textlow && pc < ps->texthigh)
- return ps;
-
- return 0;
-}
-
-/* Find which partial symbol within a psymtab contains PC. Return 0
- if none. Check all psymtabs if PSYMTAB is 0. */
-struct partial_symbol *
-find_pc_psymbol (psymtab, pc)
- struct partial_symtab *psymtab;
- CORE_ADDR pc;
-{
- struct partial_symbol *best, *p;
- int best_pc;
-
- if (!psymtab)
- psymtab = find_pc_psymtab (pc);
- if (!psymtab)
- return 0;
-
- best_pc = psymtab->textlow - 1;
-
- for (p = static_psymbols.list + psymtab->statics_offset;
- (p - (static_psymbols.list + psymtab->statics_offset)
- < psymtab->n_static_syms);
- p++)
- if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
- && SYMBOL_CLASS (p) == LOC_BLOCK
- && pc >= SYMBOL_VALUE (p)
- && SYMBOL_VALUE (p) > best_pc)
- {
- best_pc = SYMBOL_VALUE (p);
- best = p;
- }
- if (best_pc == psymtab->textlow - 1)
- return 0;
- return best;
-}
-
-
-static struct symbol *lookup_block_symbol ();
-
-/* Find the definition for a specified symbol name NAME
- in namespace NAMESPACE, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-struct symbol *
-lookup_symbol (name, block, namespace, is_a_field_of_this)
- char *name;
- register struct block *block;
- enum namespace namespace;
- int *is_a_field_of_this;
-{
- register int i, n;
- register struct symbol *sym;
- register struct symtab *s;
- register struct partial_symtab *ps;
- register struct partial_symbol *psym;
- struct blockvector *bv;
-
- /* Search specified block and its superiors. */
-
- while (block != 0)
- {
- sym = lookup_block_symbol (block, name, namespace);
- if (sym)
- {
- block_found = block;
- return sym;
- }
- block = BLOCK_SUPERBLOCK (block);
- }
-
- /* C++: If requested to do so by the caller,
- check to see if NAME is a field of `this'. */
- if (is_a_field_of_this)
- {
- struct value *v = value_of_this (0);
-
- *is_a_field_of_this = 0;
- if (v && check_field (v, name))
- {
- *is_a_field_of_this = 1;
- return 0;
- }
- }
-
- /* Now search all global blocks. Do the symtab's first, then
- check the psymtab's */
-
- for (s = symtab_list; s; s = s->next)
- {
- bv = BLOCKVECTOR (s);
- block = BLOCKVECTOR_BLOCK (bv, 0);
- sym = lookup_block_symbol (block, name, namespace);
- if (sym)
- {
- block_found = block;
- return sym;
- }
- }
-
- /* Check for the possibility of the symbol being a global function
- that is stored on the misc function vector. Eventually, all
- global symbols might be resolved in this way. */
-
- if (namespace == VAR_NAMESPACE)
- {
- int index = lookup_misc_func (name);
-
- if (index == -1)
- { /* Look for a mangled C++ name for NAME. */
- int name_len = strlen (name);
- for (index = misc_function_count; --index >= 0; )
- /* Assume orginal name is prefix of mangled name. */
- if (!strncmp (misc_function_vector[index].name, name, name_len))
- {
- char *demangled =
- cplus_demangle(misc_function_vector[index].name, -1);
- if (demangled != NULL)
- {
- int cond = strcmp (demangled, name);
- free (demangled);
- if (!cond)
- break;
- }
- }
- /* Loop terminates on no match with index == -1. */
- }
-
- if (index != -1)
- {
- ps = find_pc_psymtab (misc_function_vector[index].address);
- if (ps && !ps->readin)
- {
- s = psymtab_to_symtab (ps);
- bv = BLOCKVECTOR (s);
- block = BLOCKVECTOR_BLOCK (bv, 0);
- sym = lookup_block_symbol (block, name, namespace);
- /* sym == 0 if symbol was found in the psymtab but not
- in the symtab.
- Return 0 to use the misc_function definition of "foo_".
-
- This happens for Fortran "foo_" symbols,
- which are "foo" in the symtab.
-
- This can also happen if "asm" is used to make a
- regular symbol but not a debugging symbol, e.g.
- asm(".globl _main");
- asm("_main:");
- */
-
- return sym;
- }
- }
- }
-
- if (psym = lookup_partial_symbol (name, 1, namespace))
- {
- ps = psym->pst;
- s = psymtab_to_symtab(ps);
- bv = BLOCKVECTOR (s);
- block = BLOCKVECTOR_BLOCK (bv, 0);
- sym = lookup_block_symbol (block, name, namespace);
- if (!sym)
- fatal ("Internal: global symbol found in psymtab but not in symtab");
- return sym;
- }
-
- /* Now search all per-file blocks.
- Not strictly correct, but more useful than an error.
- Do the symtabs first, then check the psymtabs */
-
- for (s = symtab_list; s; s = s->next)
- {
- bv = BLOCKVECTOR (s);
- block = BLOCKVECTOR_BLOCK (bv, 1);
- sym = lookup_block_symbol (block, name, namespace);
- if (sym)
- {
- block_found = block;
- return sym;
- }
- }
-
- if (psym = lookup_partial_symbol(name, 0, namespace))
- {
- ps = psym->pst;
- s = psymtab_to_symtab(ps);
- bv = BLOCKVECTOR (s);
- block = BLOCKVECTOR_BLOCK (bv, 1);
- sym = lookup_block_symbol (block, name, namespace);
- if (!sym)
- fatal ("Internal: static symbol found in psymtab but not in symtab");
- return sym;
- }
-
- return 0;
-}
-
-/* Look, in partial_symtab PST, for symbol NAME. Check the global
- symbols if GLOBAL, the static symbols if not */
-
-static struct partial_symbol *
-lookup_partial_symbol (name, global, namespace)
- register char *name;
- register int global;
- register enum namespace namespace;
-{
- register struct partial_symbol *start, *psym;
- register struct partial_symbol *top, *bottom, *center;
- register struct partial_symtab *pst;
- register int length;
-
- if (global)
- {
- start = global_psymbols.list;
- length = global_psymbols.next - start;
- }
- else
- {
- start = static_psymbols.list;
- length = static_psymbols.next - start;
- }
-
- if (!length)
- return (struct partial_symbol *) 0;
-
- /* Binary search. This search is guarranteed to end with center
- pointing at the earliest partial symbol with the correct
- name. At that point *all* partial symbols with that name
- will be checked against the correct namespace. */
- bottom = start;
- top = start + length - 1;
- while (top > bottom)
- {
- center = bottom + (top - bottom) / 2;
-
- assert (center < top);
-
- if (strcmp (SYMBOL_NAME (center), name) >= 0)
- top = center;
- else
- bottom = center + 1;
- }
- assert (top == bottom);
-
- while (strcmp (SYMBOL_NAME (top), name) == 0)
- {
- if (!top->pst->readin && SYMBOL_NAMESPACE (top) == namespace)
- return top;
- top ++;
- }
-
- return (struct partial_symbol *) 0;
-}
-
-/* Look for a symbol in block BLOCK. */
-
-static struct symbol *
-lookup_block_symbol (block, name, namespace)
- register struct block *block;
- char *name;
- enum namespace namespace;
-{
- register int bot, top, inc;
- register struct symbol *sym, *parameter_sym;
-
- top = BLOCK_NSYMS (block);
- bot = 0;
-
- /* If the blocks's symbols were sorted, start with a binary search. */
-
- if (BLOCK_SHOULD_SORT (block))
- {
- /* First, advance BOT to not far before
- the first symbol whose name is NAME. */
-
- while (1)
- {
- inc = (top - bot + 1);
- /* No need to keep binary searching for the last few bits worth. */
- if (inc < 4)
- break;
- inc = (inc >> 1) + bot;
- sym = BLOCK_SYM (block, inc);
- if (SYMBOL_NAME (sym)[0] < name[0])
- bot = inc;
- else if (SYMBOL_NAME (sym)[0] > name[0])
- top = inc;
- else if (strcmp (SYMBOL_NAME (sym), name) < 0)
- bot = inc;
- else
- top = inc;
- }
-
- /* Now scan forward until we run out of symbols,
- find one whose name is greater than NAME,
- or find one we want.
- If there is more than one symbol with the right name and namespace,
- we return the first one. dbxread.c is careful to make sure
- that if one is a register then it comes first. */
-
- top = BLOCK_NSYMS (block);
- while (bot < top)
- {
- sym = BLOCK_SYM (block, bot);
- inc = SYMBOL_NAME (sym)[0] - name[0];
- if (inc == 0)
- inc = strcmp (SYMBOL_NAME (sym), name);
- if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
- return sym;
- if (inc > 0)
- return 0;
- bot++;
- }
- return 0;
- }
-
- /* Here if block isn't sorted.
- This loop is equivalent to the loop above,
- but hacked greatly for speed.
-
- Note that parameter symbols do not always show up last in the
- list; this loop makes sure to take anything else other than
- parameter symbols first; it only uses parameter symbols as a
- last resort. Note that this only takes up extra computation
- time on a match. */
-
- parameter_sym = (struct symbol *) 0;
- top = BLOCK_NSYMS (block);
- inc = name[0];
- while (bot < top)
- {
- sym = BLOCK_SYM (block, bot);
- if (SYMBOL_NAME (sym)[0] == inc
- && !strcmp (SYMBOL_NAME (sym), name)
- && SYMBOL_NAMESPACE (sym) == namespace)
- {
- if (SYMBOL_CLASS (sym) == LOC_ARG
- || SYMBOL_CLASS (sym) == LOC_REF_ARG
- || SYMBOL_CLASS (sym) == LOC_REGPARM)
- parameter_sym = sym;
- else
- return sym;
- }
- bot++;
- }
- return parameter_sym; /* Will be 0 if not found. */
-}
-
-/* Return the symbol for the function which contains a specified
- lexical block, described by a struct block BL. */
-
-struct symbol *
-block_function (bl)
- struct block *bl;
-{
- while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
- bl = BLOCK_SUPERBLOCK (bl);
-
- return BLOCK_FUNCTION (bl);
-}
-
-/* Subroutine of find_pc_line */
-
-struct symtab *
-find_pc_symtab (pc)
- register CORE_ADDR pc;
-{
- register struct block *b;
- struct blockvector *bv;
- register struct symtab *s;
- register struct partial_symtab *ps;
-
- /* Search all symtabs for one whose file contains our pc */
-
- for (s = symtab_list; s; s = s->next)
- {
- bv = BLOCKVECTOR (s);
- b = BLOCKVECTOR_BLOCK (bv, 0);
- if (BLOCK_START (b) <= pc
- && BLOCK_END (b) > pc)
- break;
- }
-
- if (!s)
- {
- ps = find_pc_psymtab (pc);
- if (ps && ps->readin)
- fatal ("Internal error: pc in read in psymtab, but not in symtab.");
-
- if (ps)
- s = psymtab_to_symtab (ps);
- }
-
- return s;
-}
-
-/* Find the source file and line number for a given PC value.
- Return a structure containing a symtab pointer, a line number,
- and a pc range for the entire source line.
- The value's .pc field is NOT the specified pc.
- NOTCURRENT nonzero means, if specified pc is on a line boundary,
- use the line that ends there. Otherwise, in that case, the line
- that begins there is used. */
-
-struct symtab_and_line
-find_pc_line (pc, notcurrent)
- CORE_ADDR pc;
- int notcurrent;
-{
- struct symtab *s;
- register struct linetable *l;
- register int len;
- register int i;
- register struct linetable_entry *item;
- struct symtab_and_line value;
- struct blockvector *bv;
-
- /* Info on best line seen so far, and where it starts, and its file. */
-
- int best_line = 0;
- CORE_ADDR best_pc = 0;
- CORE_ADDR best_end = 0;
- struct symtab *best_symtab = 0;
-
- /* Store here the first line number
- of a file which contains the line at the smallest pc after PC.
- If we don't find a line whose range contains PC,
- we will use a line one less than this,
- with a range from the start of that file to the first line's pc. */
- int alt_line = 0;
- CORE_ADDR alt_pc = 0;
- struct symtab *alt_symtab = 0;
-
- /* Info on best line seen in this file. */
-
- int prev_line;
- CORE_ADDR prev_pc;
-
- /* Info on first line of this file. */
-
- int first_line;
- CORE_ADDR first_pc;
-
- /* If this pc is not from the current frame,
- it is the address of the end of a call instruction.
- Quite likely that is the start of the following statement.
- But what we want is the statement containing the instruction.
- Fudge the pc to make sure we get that. */
-
- if (notcurrent) pc -= 1;
-
- s = find_pc_symtab (pc);
- if (s == 0)
- {
- value.symtab = 0;
- value.line = 0;
- value.pc = pc;
- value.end = 0;
- return value;
- }
-
- bv = BLOCKVECTOR (s);
-
- /* Look at all the symtabs that share this blockvector.
- They all have the same apriori range, that we found was right;
- but they have different line tables. */
-
- for (; s && BLOCKVECTOR (s) == bv; s = s->next)
- {
- /* Find the best line in this symtab. */
- l = LINETABLE (s);
- len = l->nitems;
- prev_line = -1;
- first_line = -1;
- for (i = 0; i < len; i++)
- {
- item = &(l->item[i]);
-
- if (first_line < 0)
- {
- first_line = item->line;
- first_pc = item->pc;
- }
- /* Return the last line that did not start after PC. */
- if (pc >= item->pc)
- {
- prev_line = item->line;
- prev_pc = item->pc;
- }
- else
- break;
- }
-
- /* Is this file's best line closer than the best in the other files?
- If so, record this file, and its best line, as best so far. */
- if (prev_line >= 0 && prev_pc > best_pc)
- {
- best_pc = prev_pc;
- best_line = prev_line;
- best_symtab = s;
- if (i < len)
- best_end = item->pc;
- else
- best_end = 0;
- }
- /* Is this file's first line closer than the first lines of other files?
- If so, record this file, and its first line, as best alternate. */
- if (first_line >= 0 && first_pc > pc
- && (alt_pc == 0 || first_pc < alt_pc))
- {
- alt_pc = first_pc;
- alt_line = first_line;
- alt_symtab = s;
- }
- }
- if (best_symtab == 0)
- {
- value.symtab = alt_symtab;
- value.line = alt_line - 1;
- value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0));
- value.end = alt_pc;
- }
- else
- {
- value.symtab = best_symtab;
- value.line = best_line;
- value.pc = best_pc;
- value.end = (best_end ? best_end
- : (alt_pc ? alt_pc
- : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0))));
- }
- return value;
-}
-
-/* Find the PC value for a given source file and line number.
- Returns zero for invalid line number.
- The source file is specified with a struct symtab. */
-
-CORE_ADDR
-find_line_pc (symtab, line)
- struct symtab *symtab;
- int line;
-{
- register struct linetable *l;
- register int index;
- int dummy;
-
- if (symtab == 0)
- return 0;
- l = LINETABLE (symtab);
- index = find_line_common(l, line, &dummy);
- return index ? l->item[index].pc : 0;
-}
-
-/* Find the range of pc values in a line.
- Store the starting pc of the line into *STARTPTR
- and the ending pc (start of next line) into *ENDPTR.
- Returns 1 to indicate success.
- Returns 0 if could not find the specified line. */
-
-int
-find_line_pc_range (symtab, thisline, startptr, endptr)
- struct symtab *symtab;
- int thisline;
- CORE_ADDR *startptr, *endptr;
-{
- register struct linetable *l;
- register int index;
- int exact_match; /* did we get an exact linenumber match */
- register CORE_ADDR prev_pc;
- CORE_ADDR last_pc;
-
- if (symtab == 0)
- return 0;
-
- l = LINETABLE (symtab);
- index = find_line_common (l, thisline, &exact_match);
- if (index)
- {
- *startptr = l->item[index].pc;
- /* If we have not seen an entry for the specified line,
- assume that means the specified line has zero bytes. */
- if (!exact_match || index == l->nitems-1)
- *endptr = *startptr;
- else
- /* Perhaps the following entry is for the following line.
- It's worth a try. */
- if (l->item[index+1].line == thisline + 1)
- *endptr = l->item[index+1].pc;
- else
- *endptr = find_line_pc (symtab, thisline+1);
- return 1;
- }
-
- return 0;
-}
-
-/* Given a line table and a line number, return the index into the line
- table for the pc of the nearest line whose number is >= the specified one.
- Return 0 if none is found. The value is never zero is it is an index.
-
- Set *EXACT_MATCH nonzero if the value returned is an exact match. */
-
-static int
-find_line_common (l, lineno, exact_match)
- register struct linetable *l;
- register int lineno;
- int *exact_match;
-{
- register int i;
- register int len;
-
- /* BEST is the smallest linenumber > LINENO so far seen,
- or 0 if none has been seen so far.
- BEST_INDEX identifies the item for it. */
-
- int best_index = 0;
- int best = 0;
-
- int nextline = -1;
-
- if (lineno <= 0)
- return 0;
-
- len = l->nitems;
- for (i = 0; i < len; i++)
- {
- register struct linetable_entry *item = &(l->item[i]);
-
- if (item->line == lineno)
- {
- *exact_match = 1;
- return i;
- }
-
- if (item->line > lineno && (best == 0 || item->line < best))
- {
- best = item->line;
- best_index = i;
- }
- }
-
- /* If we got here, we didn't get an exact match. */
-
- *exact_match = 0;
- return best_index;
-}
-
-int
-find_pc_line_pc_range (pc, startptr, endptr)
- CORE_ADDR pc;
- CORE_ADDR *startptr, *endptr;
-{
- struct symtab_and_line sal;
- sal = find_pc_line (pc, 0);
- *startptr = sal.pc;
- *endptr = sal.end;
- return sal.symtab != 0;
-}
-
-/* Parse a string that specifies a line number.
- Pass the address of a char * variable; that variable will be
- advanced over the characters actually parsed.
-
- The string can be:
-
- LINENUM -- that line number in current file. PC returned is 0.
- FILE:LINENUM -- that line in that file. PC returned is 0.
- FUNCTION -- line number of openbrace of that function.
- PC returned is the start of the function.
- FILE:FUNCTION -- likewise, but prefer functions in that file.
- *EXPR -- line in which address EXPR appears.
-
- FUNCTION may be an undebuggable function found in misc_function_vector.
-
- If the argument FUNFIRSTLINE is nonzero, we want the first line
- of real code inside a function when a function is specified.
-
- DEFAULT_SYMTAB specifies the file to use if none is specified.
- It defaults to current_source_symtab.
- DEFAULT_LINE specifies the line number to use for relative
- line numbers (that start with signs). Defaults to current_source_line.
-
- Note that it is possible to return zero for the symtab
- if no file is validly specified. Callers must check that.
- Also, the line number returned may be invalid. */
-
-struct symtabs_and_lines
-decode_line_1 (argptr, funfirstline, default_symtab, default_line)
- char **argptr;
- int funfirstline;
- struct symtab *default_symtab;
- int default_line;
-{
- struct symtabs_and_lines decode_line_2 ();
- struct symtabs_and_lines values;
- struct symtab_and_line value;
- register char *p, *p1;
- register struct symtab *s;
- register struct symbol *sym;
- register CORE_ADDR pc;
- register int i;
- char *copy;
- struct symbol *sym_class;
- char *class_name, *method_name, *phys_name;
- int method_counter;
- int i1;
- struct symbol **sym_arr;
- struct type *t, *field;
- char **physnames;
-
- /* Defaults have defaults. */
-
- if (default_symtab == 0)
- {
- default_symtab = current_source_symtab;
- default_line = current_source_line;
- }
-
- /* See if arg is *PC */
-
- if (**argptr == '*')
- {
- (*argptr)++;
- pc = parse_and_eval_address_1 (argptr);
- values.sals = (struct symtab_and_line *)
- malloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- values.sals[0] = find_pc_line (pc, 0);
- values.sals[0].pc = pc;
- return values;
- }
-
- /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
-
- s = 0;
-
- for (p = *argptr; *p; p++)
- {
- if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
- break;
- }
- while (p[0] == ' ' || p[0] == '\t') p++;
-
- if (p[0] == ':')
- {
-
- /* C++ */
- if (p[1] ==':')
- {
- /* Extract the class name. */
- p1 = p;
- while (p != *argptr && p[-1] == ' ') --p;
- copy = (char *) alloca (p - *argptr + 1);
- bcopy (*argptr, copy, p - *argptr);
- copy[p - *argptr] = 0;
-
- /* Discard the class name from the arg. */
- p = p1 + 2;
- while (*p == ' ' || *p == '\t') p++;
- *argptr = p;
-
- sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0);
-
- if (sym_class &&
- (TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT
- || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION))
- {
- /* Arg token is not digits => try it as a function name
- Find the next token (everything up to end or next whitespace). */
- p = *argptr;
- while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++;
- copy = (char *) alloca (p - *argptr + 1);
- bcopy (*argptr, copy, p - *argptr);
- copy[p - *argptr] = '\0';
-
- /* no line number may be specified */
- while (*p == ' ' || *p == '\t') p++;
- *argptr = p;
-
- sym = 0;
- i1 = 0; /* counter for the symbol array */
- t = SYMBOL_TYPE (sym_class);
- sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
- physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*));
-
- if (destructor_name_p (copy, t))
- {
- /* destructors are a special case. */
- struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
- int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
- phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
- physnames[i1] = (char *)alloca (strlen (phys_name) + 1);
- strcpy (physnames[i1], phys_name);
- sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
- if (sym_arr[i1]) i1++;
- }
- else while (t)
- {
- class_name = TYPE_NAME (t);
- /* Ignore this class if it doesn't have a name.
- This prevents core dumps, but is just a workaround
- because we might not find the function in
- certain cases, such as
- struct D {virtual int f();}
- struct C : D {virtual int g();}
- (in this case g++ 1.35.1- does not put out a name
- for D as such, it defines type 19 (for example) in
- the same stab as C, and then does a
- .stabs "D:T19" and a .stabs "D:t19".
- Thus
- "break C::f" should not be looking for field f in
- the class named D,
- but just for the field f in the baseclasses of C
- (no matter what their names).
-
- However, I don't know how to replace the code below
- that depends on knowing the name of D. */
- if (class_name)
- {
- /* We just want the class name. In the context
- of C++, stripping off "struct " is always
- sensible. */
- if (strncmp("struct ", class_name, 7) == 0)
- class_name += 7;
- if (strncmp("union ", class_name, 6) == 0)
- class_name += 6;
-
- sym_class = lookup_symbol (class_name, 0, STRUCT_NAMESPACE, 0);
- for (method_counter = TYPE_NFN_FIELDS (SYMBOL_TYPE (sym_class)) - 1;
- method_counter >= 0;
- --method_counter)
- {
- int field_counter;
- struct fn_field *f =
- TYPE_FN_FIELDLIST1 (SYMBOL_TYPE (sym_class), method_counter);
-
- method_name = TYPE_FN_FIELDLIST_NAME (SYMBOL_TYPE (sym_class), method_counter);
- if (!strcmp (copy, method_name))
- /* Find all the fields with that name. */
- for (field_counter = TYPE_FN_FIELDLIST_LENGTH (SYMBOL_TYPE (sym_class), method_counter) - 1;
- field_counter >= 0;
- --field_counter)
- {
- phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
- physnames[i1] = (char*) alloca (strlen (phys_name) + 1);
- strcpy (physnames[i1], phys_name);
- sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
- if (sym_arr[i1]) i1++;
- }
- }
- }
- if (TYPE_N_BASECLASSES (t))
- t = TYPE_BASECLASS(t, 1);
- else
- break;
- }
-
- if (i1 == 1)
- {
- /* There is exactly one field with that name. */
- sym = sym_arr[0];
-
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- /* Arg is the name of a function */
- pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
- if (funfirstline)
- SKIP_PROLOGUE (pc);
- values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- values.sals[0] = find_pc_line (pc, 0);
- values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
- }
- else
- {
- values.nelts = 0;
- }
- return values;
- }
- if (i1 > 0)
- {
- /* There is more than one field with that name
- (overloaded). Ask the user which one to use. */
- return decode_line_2 (argptr, sym_arr, physnames,
- i1, funfirstline);
- }
- else
- error ("that class does not have any method named %s",copy);
- }
- else
- error("no class, struct, or union named %s", copy );
- }
- /* end of C++ */
-
-
- /* Extract the file name. */
- p1 = p;
- while (p != *argptr && p[-1] == ' ') --p;
- copy = (char *) alloca (p - *argptr + 1);
- bcopy (*argptr, copy, p - *argptr);
- copy[p - *argptr] = 0;
-
- /* Find that file's data. */
- s = lookup_symtab (copy);
- if (s == 0)
- {
- if (symtab_list == 0 && partial_symtab_list == 0)
- error ("No symbol table is loaded. Use the \"symbol-file\" command.");
- error ("No source file named %s.", copy);
- }
-
- /* Discard the file name from the arg. */
- p = p1 + 1;
- while (*p == ' ' || *p == '\t') p++;
- *argptr = p;
- }
-
- /* S is specified file's symtab, or 0 if no file specified.
- arg no longer contains the file name. */
-
- /* Check whether arg is all digits (and sign) */
-
- p = *argptr;
- if (*p == '-' || *p == '+') p++;
- while (*p >= '0' && *p <= '9')
- p++;
-
- if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
- {
- /* We found a token consisting of all digits -- at least one digit. */
- enum sign {none, plus, minus} sign = none;
-
- /* This is where we need to make sure that we have good defaults.
- We must guarrantee that this section of code is never executed
- when we are called with just a function name, since
- select_source_symtab calls us with such an argument */
-
- if (s == 0 && default_symtab == 0)
- {
- if (symtab_list == 0 && partial_symtab_list == 0)
- error ("No symbol table is loaded. Use the \"symbol-file\" command.");
- select_source_symtab (0);
- default_symtab = current_source_symtab;
- default_line = current_source_line;
- }
-
- if (**argptr == '+')
- sign = plus, (*argptr)++;
- else if (**argptr == '-')
- sign = minus, (*argptr)++;
- value.line = atoi (*argptr);
- switch (sign)
- {
- case plus:
- if (p == *argptr)
- value.line = 5;
- if (s == 0)
- value.line = default_line + value.line;
- break;
- case minus:
- if (p == *argptr)
- value.line = 15;
- if (s == 0)
- value.line = default_line - value.line;
- else
- value.line = 1;
- break;
- }
-
- while (*p == ' ' || *p == '\t') p++;
- *argptr = p;
- if (s == 0)
- s = default_symtab;
- value.symtab = s;
- value.pc = 0;
- values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
- values.sals[0] = value;
- values.nelts = 1;
- return values;
- }
-
- /* Arg token is not digits => try it as a function name
- Find the next token (everything up to end or next whitespace). */
- p = *argptr;
- while (*p && *p != ' ' && *p != '\t' && *p != ',') p++;
- copy = (char *) alloca (p - *argptr + 1);
- bcopy (*argptr, copy, p - *argptr);
- copy[p - *argptr] = 0;
- while (*p == ' ' || *p == '\t') p++;
- *argptr = p;
-
- /* Look up that token as a function.
- If file specified, use that file's per-file block to start with. */
-
- if (s == 0)
- /* use current file as default if none is specified. */
- s = default_symtab;
-
- sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0,
- VAR_NAMESPACE, 0);
-
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- /* Arg is the name of a function */
- pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
- if (funfirstline)
- SKIP_PROLOGUE (pc);
- value = find_pc_line (pc, 0);
-#ifdef PROLOGUE_FIRSTLINE_OVERLAP
- /* Convex: no need to suppress code on first line, if any */
- value.pc = pc;
-#else
- value.pc = (value.end && value.pc != pc) ? value.end : pc;
-#endif
- values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
- values.sals[0] = value;
- values.nelts = 1;
- return values;
- }
-
- if (sym)
- error ("%s is not a function.", copy);
-
- if (symtab_list == 0 && partial_symtab_list == 0)
- error ("No symbol table is loaded. Use the \"symbol-file\" command.");
-
- if ((i = lookup_misc_func (copy)) >= 0)
- {
- value.symtab = 0;
- value.line = 0;
- value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET;
- if (funfirstline)
- SKIP_PROLOGUE (value.pc);
- values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
- values.sals[0] = value;
- values.nelts = 1;
- return values;
- }
-
- error ("Function %s not defined.", copy);
-}
-
-struct symtabs_and_lines
-decode_line_spec (string, funfirstline)
- char *string;
- int funfirstline;
-{
- struct symtabs_and_lines sals;
- if (string == 0)
- error ("Empty line specification.");
- sals = decode_line_1 (&string, funfirstline,
- current_source_symtab, current_source_line);
- if (*string)
- error ("Junk at end of line specification: %s", string);
- return sals;
-}
-
-/* Given a list of NELTS symbols in sym_arr (with corresponding
- mangled names in physnames), return a list of lines to operate on
- (ask user if necessary). */
-struct symtabs_and_lines
-decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline)
- char **argptr;
- struct symbol *sym_arr[];
- char *physnames[];
- int nelts;
- int funfirstline;
-{
- char *getenv();
- struct symtabs_and_lines values, return_values;
- register CORE_ADDR pc;
- char *args, *arg1, *command_line_input ();
- int i;
- char *prompt;
-
- values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
- return_values.sals = (struct symtab_and_line *) malloc (nelts * sizeof(struct symtab_and_line));
-
- i = 0;
- printf("[0] cancel\n[1] all\n");
- while (i < nelts)
- {
- if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
- {
- /* Arg is the name of a function */
- pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i]))
- + FUNCTION_START_OFFSET;
- if (funfirstline)
- SKIP_PROLOGUE (pc);
- values.sals[i] = find_pc_line (pc, 0);
- values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ? values.sals[i].end : pc;
- printf("[%d] file:%s; line number:%d\n",
- (i+2), values.sals[i].symtab->filename, values.sals[i].line);
- }
- else printf ("?HERE\n");
- i++;
- }
-
- if ((prompt = getenv ("PS2")) == NULL)
- {
- prompt = ">";
- }
- printf("%s ",prompt);
- fflush(stdout);
-
- args = command_line_input (0, 0);
-
- if (args == 0)
- error_no_arg ("one or more choice numbers");
-
- i = 0;
- while (*args)
- {
- int num;
-
- arg1 = args;
- while (*arg1 >= '0' && *arg1 <= '9') arg1++;
- if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
- error ("Arguments must be choice numbers.");
-
- num = atoi (args);
-
- if (num == 0)
- error ("cancelled");
- else if (num == 1)
- {
- bcopy (values.sals, return_values.sals, (nelts * sizeof(struct symtab_and_line)));
- return_values.nelts = nelts;
- return return_values;
- }
-
- if (num > nelts + 2)
- {
- printf ("No choice number %d.\n", num);
- }
- else
- {
- num -= 2;
- if (values.sals[num].pc)
- {
- return_values.sals[i++] = values.sals[num];
- values.sals[num].pc = 0;
- }
- else
- {
- printf ("duplicate request for %d ignored.\n", num);
- }
- }
-
- args = arg1;
- while (*args == ' ' || *args == '\t') args++;
- }
- return_values.nelts = i;
- return return_values;
-}
-
-/* hash a symbol ("hashpjw" from Aho, Sethi & Ullman, p.436) */
-
-int
-hash_symbol(str)
- register char *str;
-{
- register unsigned int h = 0, g;
- register unsigned char c;
-
- while (c = *(unsigned char *)str++) {
- h = (h << 4) + c;
- if (g = h & 0xf0000000) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- }
- return ((int)h);
-}
-
-/* Return the index of misc function named NAME. */
-
-int
-lookup_misc_func (name)
- register char *name;
-{
- register int i = hash_symbol(name) & (MISC_FUNC_HASH_SIZE - 1);
-
- if (misc_function_vector == 0)
- error("No symbol file");
-
- i = misc_function_hash_tab[i];
- while (i >= 0)
- {
- if (strcmp(misc_function_vector[i].name, name) == 0)
- break;
- i = misc_function_vector[i].next;
- }
- return (i);
-}
-
-/*
- * Slave routine for sources_info. Force line breaks at ,'s.
- */
-static void
-output_source_filename (name, next)
-char *name;
-int next;
-{
- static int column = 0;
-
- if (column != 0 && column + strlen (name) >= 70)
- {
- printf_filtered ("\n");
- column = 0;
- }
- else if (column != 0)
- {
- printf_filtered (" ");
- column++;
- }
- printf_filtered ("%s", name);
- column += strlen (name);
- if (next)
- {
- printf_filtered (",");
- column++;
- }
-
- if (!next) column = 0;
-}
-
-static void
-sources_info ()
-{
- register struct symtab *s;
- register struct partial_symtab *ps;
- register int column = 0;
-
- if (symtab_list == 0 && partial_symtab_list == 0)
- {
- printf ("No symbol table is loaded.\n");
- return;
- }
-
- printf_filtered ("Source files for which symbols have been read in:\n\n");
-
- for (s = symtab_list; s; s = s->next)
- output_source_filename (s->filename, s->next);
- printf_filtered ("\n\n");
-
- printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
-
- for (ps = partial_symtab_list; ps; ps = ps->next)
- if (!ps->readin)
- output_source_filename (ps->filename, ps->next);
- printf_filtered ("\n");
-}
-
-/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP.
- If CLASS is zero, list all symbols except functions and type names.
- If CLASS is 1, list only functions.
- If CLASS is 2, list only type names. */
-
-static void sort_block_syms ();
-
-static void
-list_symbols (regexp, class)
- char *regexp;
- int class;
-{
- register struct symtab *s;
- register struct partial_symtab *ps;
- register struct blockvector *bv;
- struct blockvector *prev_bv = 0;
- register struct block *b;
- register int i, j;
- register struct symbol *sym;
- struct partial_symbol *psym, *bound;
- char *val;
- static char *classnames[]
- = {"variable", "function", "type", "method"};
- int print_count = 0;
- int found_in_file = 0;
-
- if (regexp)
- if (val = (char *) re_comp (regexp))
- error ("Invalid regexp: %s", val);
-
- /* Search through the partial_symtab_list *first* for all symbols
- matching the regexp. That way we don't have to reproduce all of
- the machinery below. */
- for (psym = global_psymbols.list, bound = global_psymbols.next; ;
- psym = static_psymbols.list, bound = static_psymbols.next)
- {
- for (; psym < bound; ++psym)
- {
- if (psym->pst->readin)
- continue;
-
- QUIT;
- /* If it would match (logic taken from loop below)
- load the file and go on to the next one */
- if ((regexp == 0 || re_exec (SYMBOL_NAME (psym)))
- && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF
- && SYMBOL_CLASS (psym) != LOC_BLOCK)
- || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK)
- || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF)
- || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK)))
- psymtab_to_symtab(psym->pst);
- }
- if (psym == static_psymbols.next)
- break;
- }
-
- /* Printout here so as to get after the "Reading in symbols"
- messages which will be generated above. */
- printf_filtered (regexp
- ? "All %ss matching regular expression \"%s\":\n"
- : "All defined %ss:\n",
- classnames[class],
- regexp);
-
- /* Here, *if* the class is correct (function only, right now), we
- should search through the misc function vector for symbols that
- match and call find_pc_psymtab on them. If find_pc_psymtab returns
- 0, don't worry about it (already read in or no debugging info). */
-
- if (class == 1)
- {
- for (i = 0; i < misc_function_count; i++)
- if (regexp == 0 || re_exec (misc_function_vector[i].name))
- {
- ps = find_pc_psymtab (misc_function_vector[i].address);
- if (ps && !ps->readin)
- psymtab_to_symtab (ps);
- }
- }
-
- for (s = symtab_list; s; s = s->next)
- {
- found_in_file = 0;
- bv = BLOCKVECTOR (s);
- /* Often many files share a blockvector.
- Scan each blockvector only once so that
- we don't get every symbol many times.
- It happens that the first symtab in the list
- for any given blockvector is the main file. */
- if (bv != prev_bv)
- for (i = 0; i < 2; i++)
- {
- b = BLOCKVECTOR_BLOCK (bv, i);
- /* Skip the sort if this block is always sorted. */
- if (!BLOCK_SHOULD_SORT (b))
- sort_block_syms (b);
- for (j = 0; j < BLOCK_NSYMS (b); j++)
- {
- QUIT;
- sym = BLOCK_SYM (b, j);
- if ((regexp == 0 || re_exec (SYMBOL_NAME (sym)))
- && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
- && SYMBOL_CLASS (sym) != LOC_BLOCK)
- || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
- || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
- || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
- {
- if (!found_in_file)
- {
- printf_filtered ("\nFile %s:\n", s->filename);
- print_count += 2;
- }
- found_in_file = 1;
- if (class != 2 && i == 1)
- printf_filtered ("static ");
- if (class == 2
- && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
- printf_filtered ("typedef ");
-
- if (class < 3)
- {
- type_print (SYMBOL_TYPE (sym),
- (SYMBOL_CLASS (sym) == LOC_TYPEDEF
- ? "" : SYMBOL_NAME (sym)),
- stdout, 0);
-
- if (class == 2
- && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE
- && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0
- || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))),
- SYMBOL_NAME (sym))))
- printf_filtered (" %s", SYMBOL_NAME (sym));
-
- printf_filtered (";\n");
- }
- else
- {
-# if 0
- char buf[1024];
- type_print_base (TYPE_FN_FIELD_TYPE(t, i), stdout, 0, 0);
- type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), stdout, 0);
- sprintf (buf, " %s::", TYPE_NAME (t));
- type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), buf, name, stdout);
-# endif
- }
- }
- }
- }
- prev_bv = bv;
- }
-}
-
-static void
-variables_info (regexp)
- char *regexp;
-{
- list_symbols (regexp, 0);
-}
-
-static void
-functions_info (regexp)
- char *regexp;
-{
- list_symbols (regexp, 1);
-}
-
-static void
-types_info (regexp)
- char *regexp;
-{
- list_symbols (regexp, 2);
-}
-
-#if 0
-/* Tiemann says: "info methods was never implemented." */
-static void
-methods_info (regexp)
- char *regexp;
-{
- list_symbols (regexp, 3);
-}
-#endif /* 0 */
-
-/* Call sort_block_syms to sort alphabetically the symbols of one block. */
-
-static int
-compare_symbols (s1, s2)
- struct symbol **s1, **s2;
-{
- /* Names that are less should come first. */
- register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
- if (namediff != 0) return namediff;
- /* For symbols of the same name, registers should come first. */
- return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
- - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
-}
-
-static void
-sort_block_syms (b)
- register struct block *b;
-{
- qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
- sizeof (struct symbol *), compare_symbols);
-}
-
-/* Initialize the standard C scalar types. */
-
-static
-struct type *
-init_type (code, length, uns, name)
- enum type_code code;
- int length, uns;
- char *name;
-{
- register struct type *type;
-
- type = (struct type *) xmalloc (sizeof (struct type));
- bzero (type, sizeof *type);
- TYPE_MAIN_VARIANT (type) = type;
- TYPE_CODE (type) = code;
- TYPE_LENGTH (type) = length;
- TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0;
- TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
- TYPE_NFIELDS (type) = 0;
- TYPE_NAME (type) = name;
-
- /* C++ fancies. */
- TYPE_NFN_FIELDS (type) = 0;
- TYPE_N_BASECLASSES (type) = 0;
- TYPE_BASECLASSES (type) = 0;
- return type;
-}
-
-/* Return Nonzero if block a is lexically nested within block b,
- or if a and b have the same pc range.
- Return zero otherwise. */
-int
-contained_in (a, b)
- struct block *a, *b;
-{
- if (!a || !b)
- return 0;
- return a->startaddr >= b->startaddr && a->endaddr <= b->endaddr;
-}
-
-
-/* Helper routine for make_symbol_completion_list. */
-
-int return_val_size, return_val_index;
-char **return_val;
-
-void
-completion_list_add_symbol (symname)
- char *symname;
-{
- if (return_val_index + 3 > return_val_size)
- return_val =
- (char **)xrealloc (return_val,
- (return_val_size *= 2) * sizeof (char *));
-
- return_val[return_val_index] =
- (char *)xmalloc (1 + strlen (symname));
-
- strcpy (return_val[return_val_index], symname);
-
- return_val[++return_val_index] = (char *)NULL;
-}
-
-/* Return a NULL terminated array of all symbols (regardless of class) which
- begin by matching TEXT. If the answer is no symbols, then the return value
- is an array which contains only a NULL pointer.
-
- Problem: All of the symbols have to be copied because readline
- frees them. I'm not going to worry about this; hopefully there
- won't be that many. */
-
-char **
-make_symbol_completion_list (text)
- char *text;
-{
- register struct symtab *s;
- register struct partial_symtab *ps;
- register struct blockvector *bv;
- struct blockvector *prev_bv = 0;
- register struct block *b, *surrounding_static_block;
- extern struct block *get_selected_block ();
- register int i, j;
- register struct symbol *sym;
- struct partial_symbol *psym;
-
- int text_len = strlen (text);
- return_val_size = 100;
- return_val_index = 0;
- return_val =
- (char **)xmalloc ((1 + return_val_size) *sizeof (char *));
- return_val[0] = (char *)NULL;
-
- /* Look through the partial symtabs for all symbols which begin
- by matching TEXT. Add each one that you find to the list. */
-
- for (ps = partial_symtab_list; ps; ps = ps->next)
- {
- /* If the psymtab's been read in we'll get it when we search
- through the blockvector. */
- if (ps->readin) continue;
-
- for (psym = global_psymbols.list + ps->globals_offset;
- psym < (global_psymbols.list + ps->globals_offset
- + ps->n_global_syms);
- psym++)
- {
- QUIT; /* If interrupted, then quit. */
- if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
- completion_list_add_symbol (SYMBOL_NAME (psym));
- }
-
- for (psym = static_psymbols.list + ps->statics_offset;
- psym < (static_psymbols.list + ps->statics_offset
- + ps->n_static_syms);
- psym++)
- {
- QUIT;
- if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
- completion_list_add_symbol (SYMBOL_NAME (psym));
- }
- }
-
- /* At this point scan through the misc function vector and add each
- symbol you find to the list. Eventually we want to ignore
- anything that isn't a text symbol (everything else will be
- handled by the psymtab code above). */
-
- for (i = 0; i < misc_function_count; i++)
- if (!strncmp (text, misc_function_vector[i].name, text_len))
- completion_list_add_symbol (misc_function_vector[i].name);
-
- /* Search upwards from currently selected frame (so that we can
- complete on local vars. */
- for (b = get_selected_block (); b; b = BLOCK_SUPERBLOCK (b))
- {
- if (!BLOCK_SUPERBLOCK (b))
- surrounding_static_block = b; /* For elmin of dups */
-
- /* Also catch fields of types defined in this places which
- match our text string. Only complete on types visible
- from current context. */
- for (i = 0; i < BLOCK_NSYMS (b); i++)
- {
- register struct symbol *sym = BLOCK_SYM (b, i);
-
- if (!strncmp (SYMBOL_NAME (sym), text, text_len))
- completion_list_add_symbol (SYMBOL_NAME (sym));
-
- if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
- {
- struct type *t = SYMBOL_TYPE (sym);
- enum type_code c = TYPE_CODE (t);
-
- if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
- for (j = 0; j < TYPE_NFIELDS (t); j++)
- if (TYPE_FIELD_NAME (t, j) &&
- !strncmp (TYPE_FIELD_NAME (t, j), text, text_len))
- completion_list_add_symbol (TYPE_FIELD_NAME (t, j));
- }
- }
- }
-
- /* Go through the symtabs and check the externs and statics for
- symbols which match. */
-
- for (s = symtab_list; s; s = s->next)
- {
- struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 0);
-
- for (i = 0; i < BLOCK_NSYMS (b); i++)
- if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
- completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
- }
-
- for (s = symtab_list; s; s = s->next)
- {
- struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
-
- /* Don't do this block twice. */
- if (b == surrounding_static_block) continue;
-
- for (i = 0; i < BLOCK_NSYMS (b); i++)
- if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
- completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
- }
-
- return (return_val);
-}
-
-void
-_initialize_symtab ()
-{
- add_info ("variables", variables_info,
- "All global and static variable names, or those matching REGEXP.");
- add_info ("functions", functions_info,
- "All function names, or those matching REGEXP.");
- add_info ("types", types_info,
- "All types names, or those matching REGEXP.");
-#if 0
- add_info ("methods", methods_info,
- "All method names, or those matching REGEXP::REGEXP.\n\
-If the class qualifier is ommited, it is assumed to be the current scope.\n\
-If the first REGEXP is ommited, then all methods matching the second REGEXP\n\
-are listed.");
-#endif
- add_info ("sources", sources_info,
- "Source files in the program.");
-
- obstack_init (symbol_obstack);
- obstack_init (psymbol_obstack);
-
- builtin_type_void = init_type (TYPE_CODE_VOID, 1, 0, "void");
-
- builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float");
- builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double");
-
- builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char");
- builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short");
- builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long");
- builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int");
-
- builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char");
- builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short");
- builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long");
- builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int");
-#ifdef LONG_LONG
- builtin_type_long_long =
- init_type (TYPE_CODE_INT, sizeof (long long), 0, "long long");
- builtin_type_unsigned_long_long =
- init_type (TYPE_CODE_INT, sizeof (long long), 1, "unsigned long long");
-#endif
-}
-
diff --git a/gnu/usr.bin/gdb/utils.c b/gnu/usr.bin/gdb/utils.c
deleted file mode 100644
index 782b345c9ba1..000000000000
--- a/gnu/usr.bin/gdb/utils.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * $Header: /home/cvs/386BSD/src/gnu/usr.bin/gdb/utils.c,v 1.1 1993/06/29 09:47:42 nate Exp $;
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)utils.c 6.4 (Berkeley) 5/8/91";
-#endif /* not lint */
-
-/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986, 1989 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-GDB is free software; you can 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.
-
-GDB is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "param.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <pwd.h>
-#include "defs.h"
-#ifdef HAVE_TERMIO
-#include <termio.h>
-#endif
-
-/* If this definition isn't overridden by the header files, assume
- that isatty and fileno exist on this system. */
-#ifndef ISATTY
-#define ISATTY(FP) (isatty (fileno (FP)))
-#endif
-
-extern FILE *instream;
-
-void error ();
-void fatal ();
-
-/* Chain of cleanup actions established with make_cleanup,
- to be executed if an error happens. */
-
-static struct cleanup *cleanup_chain;
-
-/* Nonzero means a quit has been requested. */
-
-int quit_flag;
-
-/* Nonzero means quit immediately if Control-C is typed now,
- rather than waiting until QUIT is executed. */
-
-int immediate_quit;
-
-/* Add a new cleanup to the cleanup_chain,
- and return the previous chain pointer
- to be passed later to do_cleanups or discard_cleanups.
- Args are FUNCTION to clean up with, and ARG to pass to it. */
-
-struct cleanup *
-make_cleanup (function, arg)
- void (*function) ();
- int arg;
-{
- register struct cleanup *new
- = (struct cleanup *) xmalloc (sizeof (struct cleanup));
- register struct cleanup *old_chain = cleanup_chain;
-
- new->next = cleanup_chain;
- new->function = function;
- new->arg = arg;
- cleanup_chain = new;
-
- return old_chain;
-}
-
-/* Discard cleanups and do the actions they describe
- until we get back to the point OLD_CHAIN in the cleanup_chain. */
-
-void
-do_cleanups (old_chain)
- register struct cleanup *old_chain;
-{
- register struct cleanup *ptr;
- while ((ptr = cleanup_chain) != old_chain)
- {
- (*ptr->function) (ptr->arg);
- cleanup_chain = ptr->next;
- free (ptr);
- }
-}
-
-/* Discard cleanups, not doing the actions they describe,
- until we get back to the point OLD_CHAIN in the cleanup_chain. */
-
-void
-discard_cleanups (old_chain)
- register struct cleanup *old_chain;
-{
- register struct cleanup *ptr;
- while ((ptr = cleanup_chain) != old_chain)
- {
- cleanup_chain = ptr->next;
- free (ptr);
- }
-}
-
-/* Set the cleanup_chain to 0, and return the old cleanup chain. */
-struct cleanup *
-save_cleanups ()
-{
- struct cleanup *old_chain = cleanup_chain;
-
- cleanup_chain = 0;
- return old_chain;
-}
-
-/* Restore the cleanup chain from a previously saved chain. */
-void
-restore_cleanups (chain)
- struct cleanup *chain;
-{
- cleanup_chain = chain;
-}
-
-/* This function is useful for cleanups.
- Do
-
- foo = xmalloc (...);
- old_chain = make_cleanup (free_current_contents, &foo);
-
- to arrange to free the object thus allocated. */
-
-void
-free_current_contents (location)
- char **location;
-{
- free (*location);
-}
-
-/* Generally useful subroutines used throughout the program. */
-
-/* Like malloc but get error if no storage available. */
-
-char *
-xmalloc (size)
- long size;
-{
- register char *val = (char *) malloc (size);
- if (!val)
- fatal ("virtual memory exhausted.", 0);
- return val;
-}
-
-/* Like realloc but get error if no storage available. */
-
-char *
-xrealloc (ptr, size)
- char *ptr;
- long size;
-{
- register char *val = (char *) realloc (ptr, size);
- if (!val)
- fatal ("virtual memory exhausted.", 0);
- return val;
-}
-
-/* Print the system error message for errno, and also mention STRING
- as the file name for which the error was encountered.
- Then return to command level. */
-
-void
-perror_with_name (string)
- char *string;
-{
- extern int sys_nerr;
- extern char *sys_errlist[];
- extern int errno;
- char *err;
- char *combined;
-
- if (errno < sys_nerr)
- err = sys_errlist[errno];
- else
- err = "unknown error";
-
- combined = (char *) alloca (strlen (err) + strlen (string) + 3);
- strcpy (combined, string);
- strcat (combined, ": ");
- strcat (combined, err);
-
- error ("%s.", combined);
-}
-
-/* Print the system error message for ERRCODE, and also mention STRING
- as the file name for which the error was encountered. */
-
-void
-print_sys_errmsg (string, errcode)
- char *string;
- int errcode;
-{
- extern int sys_nerr;
- extern char *sys_errlist[];
- char *err;
- char *combined;
-
- if (errcode < sys_nerr)
- err = sys_errlist[errcode];
- else
- err = "unknown error";
-
- combined = (char *) alloca (strlen (err) + strlen (string) + 3);
- strcpy (combined, string);
- strcat (combined, ": ");
- strcat (combined, err);
-
- printf ("%s.\n", combined);
-}
-
-void
-quit ()
-{
-#ifdef HAVE_TERMIO
- ioctl (fileno (stdout), TCFLSH, 1);
-#else /* not HAVE_TERMIO */
- ioctl (fileno (stdout), TIOCFLUSH, 0);
-#endif /* not HAVE_TERMIO */
-#ifdef TIOCGPGRP
- error ("Quit");
-#else
- error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
-#endif /* TIOCGPGRP */
-}
-
-/* Control C comes here */
-
-void
-request_quit ()
-{
- extern int remote_debugging;
-
- quit_flag = 1;
-
-#ifdef USG
- /* Restore the signal handler. */
- signal (SIGINT, request_quit);
-#endif
-
- if (immediate_quit)
- quit();
-}
-
-/* Print an error message and return to command level.
- STRING is the error message, used as a fprintf string,
- and ARG is passed as an argument to it. */
-
-void
-error (string, arg1, arg2, arg3)
- char *string;
- int arg1, arg2, arg3;
-{
- terminal_ours (); /* Should be ok even if no inf. */
- fflush (stdout);
- fprintf (stderr, string, arg1, arg2, arg3);
- fprintf (stderr, "\n");
- return_to_top_level ();
-}
-
-/* Print an error message and exit reporting failure.
- This is for a error that we cannot continue from.
- STRING and ARG are passed to fprintf. */
-
-void
-fatal (string, arg)
- char *string;
- int arg;
-{
- fprintf (stderr, "gdb: ");
- fprintf (stderr, string, arg);
- fprintf (stderr, "\n");
- exit (1);
-}
-
-/* Print an error message and exit, dumping core.
- STRING is a printf-style control string, and ARG is a corresponding
- argument. */
-void
-fatal_dump_core (string, arg)
- char *string;
- int arg;
-{
- /* "internal error" is always correct, since GDB should never dump
- core, no matter what the input. */
- fprintf (stderr, "gdb internal error: ");
- fprintf (stderr, string, arg);
- fprintf (stderr, "\n");
- signal (SIGQUIT, SIG_DFL);
- kill (getpid (), SIGQUIT);
- /* We should never get here, but just in case... */
- exit (1);
-}
-
-/* Make a copy of the string at PTR with SIZE characters
- (and add a null character at the end in the copy).
- Uses malloc to get the space. Returns the address of the copy. */
-
-char *
-savestring (ptr, size)
- char *ptr;
- int size;
-{
- register char *p = (char *) xmalloc (size + 1);
- bcopy (ptr, p, size);
- p[size] = 0;
- return p;
-}
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
- register char *val = (char *) xmalloc (len);
- strcpy (val, s1);
- strcat (val, s2);
- strcat (val, s3);
- return val;
-}
-
-void
-print_spaces (n, file)
- register int n;
- register FILE *file;
-{
- while (n-- > 0)
- fputc (' ', file);
-}
-
-/* Ask user a y-or-n question and return 1 iff answer is yes.
- Takes three args which are given to printf to print the question.
- The first, a control string, should end in "? ".
- It should not say how to answer, because we do that. */
-
-int
-query (ctlstr, arg1, arg2)
- char *ctlstr;
-{
- register int answer;
-
- /* Automatically answer "yes" if input is not from a terminal. */
- if (!input_from_terminal_p ())
- return 1;
-
- while (1)
- {
- printf (ctlstr, arg1, arg2);
- printf ("(y or n) ");
- fflush (stdout);
- answer = fgetc (stdin);
- clearerr (stdin); /* in case of C-d */
- if (answer != '\n')
- while (fgetc (stdin) != '\n') clearerr (stdin);
- if (answer >= 'a')
- answer -= 040;
- if (answer == 'Y')
- return 1;
- if (answer == 'N')
- return 0;
- printf ("Please answer y or n.\n");
- }
-}
-
-/* Parse a C escape sequence. STRING_PTR points to a variable
- containing a pointer to the string to parse. That pointer
- is updated past the characters we use. The value of the
- escape sequence is returned.
-
- A negative value means the sequence \ newline was seen,
- which is supposed to be equivalent to nothing at all.
-
- If \ is followed by a null character, we return a negative
- value and leave the string pointer pointing at the null character.
-
- If \ is followed by 000, we return 0 and leave the string pointer
- after the zeros. A value of 0 does not mean end of string. */
-
-int
-parse_escape (string_ptr)
- char **string_ptr;
-{
- register int c = *(*string_ptr)++;
- switch (c)
- {
- case 'a':
- return '\a';
- case 'b':
- return '\b';
- case 'e':
- return 033;
- case 'f':
- return '\f';
- case 'n':
- return '\n';
- case 'r':
- return '\r';
- case 't':
- return '\t';
- case 'v':
- return '\v';
- case '\n':
- return -2;
- case 0:
- (*string_ptr)--;
- return 0;
- case '^':
- c = *(*string_ptr)++;
- if (c == '\\')
- c = parse_escape (string_ptr);
- if (c == '?')
- return 0177;
- return (c & 0200) | (c & 037);
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- register int i = c - '0';
- register int count = 0;
- while (++count < 3)
- {
- if ((c = *(*string_ptr)++) >= '0' && c <= '7')
- {
- i *= 8;
- i += c - '0';
- }
- else
- {
- (*string_ptr)--;
- break;
- }
- }
- return i;
- }
- default:
- return c;
- }
-}
-
-/* Print the character CH on STREAM as part of the contents
- of a literal string whose delimiter is QUOTER. */
-
-void
-printchar (ch, stream, quoter)
- unsigned char ch;
- FILE *stream;
- int quoter;
-{
- register int c = ch;
- if (c < 040 || c >= 0177)
- switch (c)
- {
- case '\n':
- fputs_filtered ("\\n", stream);
- break;
- case '\b':
- fputs_filtered ("\\b", stream);
- break;
- case '\t':
- fputs_filtered ("\\t", stream);
- break;
- case '\f':
- fputs_filtered ("\\f", stream);
- break;
- case '\r':
- fputs_filtered ("\\r", stream);
- break;
- case '\033':
- fputs_filtered ("\\e", stream);
- break;
- case '\007':
- fputs_filtered ("\\a", stream);
- break;
- default:
- fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
- break;
- }
- else
- {
- if (c == '\\' || c == quoter)
- fputs_filtered ("\\", stream);
- fprintf_filtered (stream, "%c", c);
- }
-}
-
-static int lines_per_page, lines_printed, chars_per_line, chars_printed;
-
-/* Set values of page and line size. */
-static void
-set_screensize_command (arg, from_tty)
- char *arg;
- int from_tty;
-{
- char *p = arg;
- char *p1;
- int tolinesize = lines_per_page;
- int tocharsize = chars_per_line;
-
- if (p == 0)
- error_no_arg ("set screensize");
-
- while (*p >= '0' && *p <= '9')
- p++;
-
- if (*p && *p != ' ' && *p != '\t')
- error ("Non-integral argument given to \"set screensize\".");
-
- tolinesize = atoi (arg);
-
- while (*p == ' ' || *p == '\t')
- p++;
-
- if (*p)
- {
- p1 = p;
- while (*p1 >= '0' && *p1 <= '9')
- p1++;
-
- if (*p1)
- error ("Non-integral second argument given to \"set screensize\".");
-
- tocharsize = atoi (p);
- }
-
- lines_per_page = tolinesize;
- chars_per_line = tocharsize;
-}
-
-static void
-instream_cleanup(stream)
- FILE *stream;
-{
- instream = stream;
-}
-
-static void
-prompt_for_continue ()
-{
- if (ISATTY(stdin) && ISATTY(stdout))
- {
- struct cleanup *old_chain = make_cleanup(instream_cleanup, instream);
- char *cp, *gdb_readline();
-
- instream = stdin;
- immediate_quit++;
- if (cp = gdb_readline ("---Type <return> to continue---"))
- free(cp);
- chars_printed = lines_printed = 0;
- immediate_quit--;
- do_cleanups(old_chain);
- }
-}
-
-/* Reinitialize filter; ie. tell it to reset to original values. */
-
-void
-reinitialize_more_filter ()
-{
- lines_printed = 0;
- chars_printed = 0;
-}
-
-static void
-screensize_info (arg, from_tty)
- char *arg;
- int from_tty;
-{
- if (arg)
- error ("\"info screensize\" does not take any arguments.");
-
- if (!lines_per_page)
- printf ("Output more filtering is disabled.\n");
- else
- {
- printf ("Output more filtering is enabled with\n");
- printf ("%d lines per page and %d characters per line.\n",
- lines_per_page, chars_per_line);
- }
-}
-
-/* Like fputs but pause after every screenful.
- Unlike fputs, fputs_filtered does not return a value.
- It is OK for LINEBUFFER to be NULL, in which case just don't print
- anything.
-
- Note that a longjmp to top level may occur in this routine
- (since prompt_for_continue may do so) so this routine should not be
- called when cleanups are not in place. */
-
-void
-fputs_filtered (linebuffer, stream)
- char *linebuffer;
- FILE *stream;
-{
- char *lineptr;
-
- if (linebuffer == 0)
- return;
-
- /* Don't do any filtering if it is disabled. */
- if (stream != stdout || !ISATTY(stdout) || lines_per_page == 0)
- {
- fputs (linebuffer, stream);
- return;
- }
-
- /* Go through and output each character. Show line extension
- when this is necessary; prompt user for new page when this is
- necessary. */
-
- lineptr = linebuffer;
- while (*lineptr)
- {
- /* Possible new page. */
- if (lines_printed >= lines_per_page - 1)
- prompt_for_continue ();
-
- while (*lineptr && *lineptr != '\n')
- {
- /* Print a single line. */
- if (*lineptr == '\t')
- {
- putc ('\t', stream);
- /* Shifting right by 3 produces the number of tab stops
- we have already passed, and then adding one and
- shifting left 3 advances to the next tab stop. */
- chars_printed = ((chars_printed >> 3) + 1) << 3;
- lineptr++;
- }
- else
- {
- putc (*lineptr, stream);
- chars_printed++;
- lineptr++;
- }
-
- if (chars_printed >= chars_per_line)
- {
- chars_printed = 0;
- lines_printed++;
- /* Possible new page. */
- if (lines_printed >= lines_per_page - 1)
- prompt_for_continue ();
- }
- }
-
- if (*lineptr == '\n')
- {
- lines_printed++;
- putc ('\n', stream);
- lineptr++;
- chars_printed = 0;
- }
- }
-}
-
-/* fputs_demangled is a variant of fputs_filtered that
- demangles g++ names.*/
-
-void
-fputs_demangled (linebuffer, stream, arg_mode)
- char *linebuffer;
- FILE *stream;
-{
-#ifdef __STDC__
- extern char *cplus_demangle (const char *, int);
-#else
- extern char *cplus_demangle ();
-#endif
-#define SYMBOL_MAX 1024
-
-#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
-
- char buf[SYMBOL_MAX+1];
- char *p;
-
- if (linebuffer == NULL)
- return;
-
- p = linebuffer;
-
- while ( *p != (char) 0 ) {
- int i = 0;
-
- /* collect non-interesting characters into buf */
- while ( *p != (char) 0 && !SYMBOL_CHAR(*p) ) {
- buf[i++] = *p;
- p++;
- }
- if (i > 0) {
- /* output the non-interesting characters without demangling */
- buf[i] = (char) 0;
- fputs_filtered(buf, stream);
- i = 0; /* reset buf */
- }
-
- /* and now the interesting characters */
- while (i < SYMBOL_MAX && *p != (char) 0 && SYMBOL_CHAR(*p) ) {
- buf[i++] = *p;
- p++;
- }
- buf[i] = (char) 0;
- if (i > 0) {
- char * result;
-
- if ( (result = cplus_demangle(buf, arg_mode)) != NULL ) {
- fputs_filtered(result, stream);
- free(result);
- }
- else {
- fputs_filtered(buf, stream);
- }
- }
- }
-}
-
-/* Print ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this
- information is going to put the amount written since the last call
- to INIIALIZE_MORE_FILTER or the last page break over the page size,
- print out a pause message and do a gdb_readline to get the users
- permision to continue.
-
- Unlike fprintf, this function does not return a value.
-
- Note that this routine has a restriction that the length of the
- final output line must be less than 255 characters *or* it must be
- less than twice the size of the format string. This is a very
- arbitrary restriction, but it is an internal restriction, so I'll
- put it in. This means that the %s format specifier is almost
- useless; unless the caller can GUARANTEE that the string is short
- enough, fputs_filtered should be used instead.
-
- Note also that a longjmp to top level may occur in this routine
- (since prompt_for_continue may do so) so this routine should not be
- called when cleanups are not in place. */
-
-void
-fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6)
- FILE *stream;
- char *format;
- int arg1, arg2, arg3, arg4, arg5, arg6;
-{
- static char *linebuffer = (char *) 0;
- static int line_size;
- int format_length = strlen (format);
- int numchars;
-
- /* Allocated linebuffer for the first time. */
- if (!linebuffer)
- {
- linebuffer = (char *) xmalloc (255);
- line_size = 255;
- }
-
- /* Reallocate buffer to a larger size if this is necessary. */
- if (format_length * 2 > line_size)
- {
- line_size = format_length * 2;
-
- /* You don't have to copy. */
- free (linebuffer);
- linebuffer = (char *) xmalloc (line_size);
- }
-
- /* This won't blow up if the restrictions described above are
- followed. */
- (void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
-
- fputs_filtered (linebuffer, stream);
-}
-
-void
-printf_filtered (format, arg1, arg2, arg3, arg4, arg5, arg6)
- char *format;
- int arg1, arg2, arg3, arg4, arg5, arg6;
-{
- fprintf_filtered (stdout, format, arg1, arg2, arg3, arg4, arg5, arg6);
-}
-
-/* Print N spaces. */
-void
-print_spaces_filtered (n, stream)
- int n;
- FILE *stream;
-{
- register char *s = (char *) alloca (n + 1);
- register char *t = s;
-
- while (n--)
- *t++ = ' ';
- *t = '\0';
-
- fputs_filtered (s, stream);
-}
-
-
-#ifdef USG
-bcopy (from, to, count)
-char *from, *to;
-{
- memcpy (to, from, count);
-}
-
-bcmp (from, to, count)
-{
- return (memcmp (to, from, count));
-}
-
-bzero (to, count)
-char *to;
-{
- while (count--)
- *to++ = 0;
-}
-
-getwd (buf)
-char *buf;
-{
- getcwd (buf, MAXPATHLEN);
-}
-
-char *
-index (s, c)
- char *s;
-{
- char *strchr ();
- return strchr (s, c);
-}
-
-char *
-rindex (s, c)
- char *s;
-{
- char *strrchr ();
- return strrchr (s, c);
-}
-
-#ifndef USG
-char *sys_siglist[32] = {
- "SIG0",
- "SIGHUP",
- "SIGINT",
- "SIGQUIT",
- "SIGILL",
- "SIGTRAP",
- "SIGIOT",
- "SIGEMT",
- "SIGFPE",
- "SIGKILL",
- "SIGBUS",
- "SIGSEGV",
- "SIGSYS",
- "SIGPIPE",
- "SIGALRM",
- "SIGTERM",
- "SIGUSR1",
- "SIGUSR2",
- "SIGCLD",
- "SIGPWR",
- "SIGWIND",
- "SIGPHONE",
- "SIGPOLL",
-};
-#endif
-
-/* Queue routines */
-
-struct queue {
- struct queue *forw;
- struct queue *back;
-};
-
-insque (item, after)
-struct queue *item;
-struct queue *after;
-{
- item->forw = after->forw;
- after->forw->back = item;
-
- item->back = after;
- after->forw = item;
-}
-
-remque (item)
-struct queue *item;
-{
- item->forw->back = item->back;
- item->back->forw = item->forw;
-}
-#endif /* USG */
-
-#ifdef USG
-/* There is too much variation in Sys V signal numbers and names, so
- we must initialize them at runtime. */
-static char undoc[] = "(undocumented)";
-
-char *sys_siglist[NSIG];
-#endif /* USG */
-
-extern struct cmd_list_element *setlist;
-
-void
-_initialize_utils ()
-{
- int i;
- add_cmd ("screensize", class_support, set_screensize_command,
- "Change gdb's notion of the size of the output screen.\n\
-The first argument is the number of lines on a page.\n\
-The second argument (optional) is the number of characters on a line.",
- &setlist);
- add_info ("screensize", screensize_info,
- "Show gdb's current notion of the size of the output screen.");
-
- /* These defaults will be used if we are unable to get the correct
- values from termcap. */
- lines_per_page = 24;
- chars_per_line = 80;
- /* Initialize the screen height and width from termcap. */
- {
- int termtype = getenv ("TERM");
-
- /* Positive means success, nonpositive means failure. */
- int status;
-
- /* 2048 is large enough for all known terminals, according to the
- GNU termcap manual. */
- char term_buffer[2048];
-
- if (termtype)
- {
- status = tgetent (term_buffer, termtype);
- if (status > 0)
- {
- int val;
-
- val = tgetnum ("li");
- if (val >= 0)
- lines_per_page = val;
- else
- /* The number of lines per page is not mentioned
- in the terminal description. This probably means
- that paging is not useful (e.g. emacs shell window),
- so disable paging. */
- lines_per_page = 0;
-
- val = tgetnum ("co");
- if (val >= 0)
- chars_per_line = val;
- }
- }
- }
-
-#ifdef USG
- /* Initialize signal names. */
- for (i = 0; i < NSIG; i++)
- sys_siglist[i] = undoc;
-
-#ifdef SIGHUP
- sys_siglist[SIGHUP ] = "SIGHUP";
-#endif
-#ifdef SIGINT
- sys_siglist[SIGINT ] = "SIGINT";
-#endif
-#ifdef SIGQUIT
- sys_siglist[SIGQUIT ] = "SIGQUIT";
-#endif
-#ifdef SIGILL
- sys_siglist[SIGILL ] = "SIGILL";
-#endif
-#ifdef SIGTRAP
- sys_siglist[SIGTRAP ] = "SIGTRAP";
-#endif
-#ifdef SIGIOT
- sys_siglist[SIGIOT ] = "SIGIOT";
-#endif
-#ifdef SIGEMT
- sys_siglist[SIGEMT ] = "SIGEMT";
-#endif
-#ifdef SIGFPE
- sys_siglist[SIGFPE ] = "SIGFPE";
-#endif
-#ifdef SIGKILL
- sys_siglist[SIGKILL ] = "SIGKILL";
-#endif
-#ifdef SIGBUS
- sys_siglist[SIGBUS ] = "SIGBUS";
-#endif
-#ifdef SIGSEGV
- sys_siglist[SIGSEGV ] = "SIGSEGV";
-#endif
-#ifdef SIGSYS
- sys_siglist[SIGSYS ] = "SIGSYS";
-#endif
-#ifdef SIGPIPE
- sys_siglist[SIGPIPE ] = "SIGPIPE";
-#endif
-#ifdef SIGALRM
- sys_siglist[SIGALRM ] = "SIGALRM";
-#endif
-#ifdef SIGTERM
- sys_siglist[SIGTERM ] = "SIGTERM";
-#endif
-#ifdef SIGUSR1
- sys_siglist[SIGUSR1 ] = "SIGUSR1";
-#endif
-#ifdef SIGUSR2
- sys_siglist[SIGUSR2 ] = "SIGUSR2";
-#endif
-#ifdef SIGCLD
- sys_siglist[SIGCLD ] = "SIGCLD";
-#endif
-#ifdef SIGCHLD
- sys_siglist[SIGCHLD ] = "SIGCHLD";
-#endif
-#ifdef SIGPWR
- sys_siglist[SIGPWR ] = "SIGPWR";
-#endif
-#ifdef SIGTSTP
- sys_siglist[SIGTSTP ] = "SIGTSTP";
-#endif
-#ifdef SIGTTIN
- sys_siglist[SIGTTIN ] = "SIGTTIN";
-#endif
-#ifdef SIGTTOU
- sys_siglist[SIGTTOU ] = "SIGTTOU";
-#endif
-#ifdef SIGSTOP
- sys_siglist[SIGSTOP ] = "SIGSTOP";
-#endif
-#ifdef SIGXCPU
- sys_siglist[SIGXCPU ] = "SIGXCPU";
-#endif
-#ifdef SIGXFSZ
- sys_siglist[SIGXFSZ ] = "SIGXFSZ";
-#endif
-#ifdef SIGVTALRM
- sys_siglist[SIGVTALRM ] = "SIGVTALRM";
-#endif
-#ifdef SIGPROF
- sys_siglist[SIGPROF ] = "SIGPROF";
-#endif
-#ifdef SIGWINCH
- sys_siglist[SIGWINCH ] = "SIGWINCH";
-#endif
-#ifdef SIGCONT
- sys_siglist[SIGCONT ] = "SIGCONT";
-#endif
-#ifdef SIGURG
- sys_siglist[SIGURG ] = "SIGURG";
-#endif
-#ifdef SIGIO
- sys_siglist[SIGIO ] = "SIGIO";
-#endif
-#ifdef SIGWIND
- sys_siglist[SIGWIND ] = "SIGWIND";
-#endif
-#ifdef SIGPHONE
- sys_siglist[SIGPHONE ] = "SIGPHONE";
-#endif
-#ifdef SIGPOLL
- sys_siglist[SIGPOLL ] = "SIGPOLL";
-#endif
-#endif /* USG */
-}
diff --git a/gnu/usr.bin/gdb/xgdb/xgdb.c b/gnu/usr.bin/gdb/xgdb/xgdb.c
deleted file mode 100644
index c480f42b251e..000000000000
--- a/gnu/usr.bin/gdb/xgdb/xgdb.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * static char rcsid[] = "$Header: /home/cvs/386BSD/src/gnu/usr.bin/gdb/xgdb/xgdb.c,v 1.1 1993/06/29 09:48:26 nate Exp $";
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91";
-#endif /* not lint */
-
-/*
- * Interface from GDB to X windows. Copyright (C) 1987 Free Software
- * Foundation, Inc.
- *
- * GDB 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 GDB
- * General Public License for full details.
- *
- * Everyone is granted permission to copy, modify and redistribute GDB, but only
- * under the conditions described in the GDB General Public License. A copy
- * of this license is supposed to have been given to you along with GDB 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.
- *
- * In other words, go ahead and share GDB, but don't try to stop anyone else
- * from sharing it farther. Help stamp out software hoarding!
- */
-
-/*
- * Original version was contributed by Derek Beatty, 30 June 87.
- * This version is essentially a re-write of the original by Van
- * Jacobson (van@helios.ee.lbl.gov), Nov, 90.
- */
-
-#include "defs.h"
-#include "param.h"
-#include "symtab.h"
-#include "frame.h"
-
-extern int stop_breakpoint;
-
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/Xaw/AsciiSink.h>
-#include <X11/Xaw/AsciiText.h>
-#include <X11/Xaw/Box.h>
-#include <X11/Xaw/Command.h>
-#include <X11/Xaw/Label.h>
-#include <X11/Xaw/Paned.h>
-#include <X11/Xaw/Text.h>
-
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/file.h>
-#include <sys/errno.h>
-
-extern int errno;
-extern char *getenv();
-extern char *malloc();
-extern void bcopy();
-extern int select();
-
-extern int get_filename_and_charpos();
-extern int source_line_charpos();
-extern int source_charpos_line();
-extern void execute_command();
-extern void error_no_arg();
-extern void add_com();
-
-/* The X display where the window appears. */
-
-static char *displayname;
-static Display *display;
-
-static XtAppContext app_context;
-
-/* Windows manipulated by this package. */
-
-static Widget main_widget;
-static Widget containing_widget;
-static Widget source_name_widget;
-static Widget source_text_widget;
-static Widget button_box_widget;
-
-/* Source text display. */
-
-static struct frame_info *last_fi;
-static CORE_ADDR last_pc;
-static struct symtab *last_cur_symtab;
-static int last_cur_line;
-
-static int source_window_line;
-static char *source_window_file;
-static struct symtab *source_window_symtab;
-
-static char version_label[64];
-extern char *version;
-
-/* Forward declarations */
-
-static Widget create_text_widget();
-
-static int
-safe_strcmp(a, b)
- register char *a, *b;
-{
- register int i;
-
- if (a == b)
- return (0);
- if (!a && b)
- return (1);
- if (a && !b)
- return (-1);
- return (strcmp(a, b));
-}
-
-
-/* Display an appropriate piece of source code in the source window. */
-
-void
-xgdb_display_source()
-{
- char *filename = NULL;
- struct symtab_and_line get_selected_frame_sal();
- struct symtab_and_line sal;
- struct frame_info *fi;
-
- /* Do nothing if called before we are initialized */
-
- if (!containing_widget)
- return;
-
- /*
- * Figure out what to display (the appropriate hooks to tell
- * us don't exist so we guess): If there's a current frame
- * and it or its pc changed from the last time we were here,
- * display appropriate source line. Otherwise if the current
- * source symtab or line is different, display that line.
- * Otherwise nothing changed so leave the display alone.
- */
- fi = get_frame_info(selected_frame);
- if (fi && (fi != last_fi || fi->pc != last_pc)) {
- last_fi = fi;
- last_pc = fi->pc;
- sal = find_pc_line(fi->pc, fi->next_frame);
- if (sal.symtab == NULL) { /* XXX */
- sal.symtab = current_source_symtab;
- sal.line = current_source_line;
- }
- current_source_symtab = sal.symtab;
- current_source_line = sal.line;
- } else if (current_source_symtab != last_cur_symtab ||
- current_source_line != last_cur_line) {
- sal.symtab = last_cur_symtab = current_source_symtab;
- sal.line = last_cur_line = current_source_line;
- } else
- return;
- /*
- * Do a path search and get the exact filename of this source file.
- * Also scan it and find its source lines if not already done.
- */
- if (sal.symtab && filename == NULL) {
- if (get_filename_and_charpos(sal.symtab, sal.line, &filename))
- /* line numbers may have changed - force highlight */
- source_window_line = -1;
- }
-
- /*
- * If the source window is wrong, destroy it and make a new one.
- */
- if (safe_strcmp(filename, source_window_file)) {
- Arg args[1];
- Widget src = XawTextGetSource(source_text_widget);
-
- if (filename) {
- XtSetArg(args[0], XtNstring, filename);
- XtSetValues(src, args, XtNumber(args));
- args[0].name = XtNlabel;
- XtSetValues(source_name_widget, args, XtNumber(args));
- } else {
- XtSetArg(args[0], XtNstring, "/dev/null");
- XtSetValues(src, args, XtNumber(args));
- XtSetArg(args[0], XtNlabel, "");
- XtSetValues(source_name_widget, args, XtNumber(args));
- }
- if (source_window_file)
- free(source_window_file);
- source_window_file = filename;
- source_window_line = sal.line + 1; /* force highlight */
- }
- if (sal.symtab && source_window_line != sal.line) {
- /*
- * Update display and cursor positions as necessary.
- * Cursor should be placed on line sal.line.
- */
- XawTextPosition l, r;
-
- source_window_symtab = sal.symtab;
- source_window_line = sal.line;
- l = source_line_charpos(source_window_symtab, sal.line);
- r = source_line_charpos(source_window_symtab, sal.line + 1);
- if (r < l)
- r = l + 1;
- XawTextSetSelection(source_text_widget, l, r);
- XawTextScrollToLine(source_text_widget, l, 10, 3);
- XawTextSetInsertionPoint(source_text_widget, l);
- }
-}
-
-
-/*
- * Handlers for buttons.
- */
-
-static int
-current_lineno()
-{
- XawTextPosition start, finish;
-
- XawTextGetSelectionPos(source_text_widget, &start, &finish);
- if (start >= finish)
- start = XawTextGetInsertionPoint(source_text_widget);
-
- return (source_charpos_line(source_window_symtab, start));
-}
-
-static char *
-append_selection(cp)
- char *cp;
-{
- int len;
- XawTextPosition l, r;
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if ((len = r - l) > 0) {
- Widget src = XawTextGetSource(source_text_widget);
-
- while (len > 0) {
- XawTextBlock tb;
-
- XawTextSourceRead(src, l, &tb, len);
- bcopy(tb.ptr, cp, tb.length);
- cp += tb.length;
- len -= tb.length;
- }
- if (cp[-1] == 0)
- --cp;
- }
- return (cp);
-}
-
-static char *
-append_selection_word(cp)
- register char *cp;
-{
- register int len;
- XawTextPosition l, r;
- XawTextBlock tb;
- register char c;
- register Widget src = XawTextGetSource(source_text_widget);
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if ((len = r - l) <= 0) {
- l = XawTextGetInsertionPoint(source_text_widget);
- len = 128; /* XXX */
-
- /* might have clicked in middle of word -- back up to start */
- for ( ; l > 0; --l) {
- XawTextSourceRead(src, l - 1, &tb, 1);
- c = tb.ptr[0];
- if (! isalnum(c) && c != '_' && c != '$')
- break;
- }
- }
- while (len > 0) {
- char *sp;
- int i;
-
- XawTextSourceRead(src, l, &tb, len);
- for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
- c = *sp++;
- if (!isalnum(c) && c != '_' && c != '$')
- return (cp);
- *cp++ = c;
- }
- len -= tb.length;
- }
- return (cp);
-}
-
-static char *
-append_selection_expr(cp)
- char *cp;
-{
- int len;
- XawTextPosition l, r;
- Widget src = XawTextGetSource(source_text_widget);
- XawTextBlock tb;
- char *sp;
- char c;
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if (r > l)
- return (append_selection(cp));
-
- l = XawTextGetInsertionPoint(source_text_widget);
-
- /* might have clicked in middle of word -- back up to start */
- for ( ; l > 0; --l) {
- XawTextSourceRead(src, l - 1, &tb, 1);
- c = tb.ptr[0];
- if (! isalnum(c) && c != '_' && c != '$')
- break;
- }
-
- len = 128; /* XXX */
- while (len > 0) {
- int i;
- char pstack[64];
- int pcnt = 0;
-
- XawTextSourceRead(src, l, &tb, len);
- for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
- switch (c = *sp++) {
- case '\n':
- case ';':
- return (cp);
- case '=':
- if (cp[-1] != '=')
- return (cp - 1);
- if (len == 128)
- return (cp);
- break;
- case ',':
- if (pcnt <= 0)
- return (cp);
- break;
- case '(':
- pstack[pcnt] = ')';
- if (++pcnt >= sizeof(pstack))
- return (cp);
- break;
- case '[':
- pstack[pcnt] = ']';
- if (++pcnt >= sizeof(pstack))
- return (cp);
- break;
- case ')':
- case ']':
- if (--pcnt < 0 || pstack[pcnt] != c)
- return (cp);
- break;
- }
- *cp++ = c;
- }
- len -= tb.length;
- }
- return (cp);
-}
-
-static int input_avail; /* XXX kluge: do_command sets this when command
- * data from button is avaialble to force top level
- * to break out of its loop. */
-/*
- * Handle a button by running the command COMMAND.
- */
-static void
-do_command(w, command, call_data)
- Widget w;
- register char *command;
- caddr_t call_data;
-{
- char cmd_line[256];
- char buf[256];
- register char *out = cmd_line;
- char *cp;
- register char c;
- extern char *finish_command_input();
-
- while (c = *command++) {
- if (c == '%') {
- switch (*command++) {
- case 's': /* current selection */
- out = append_selection(out);
- break;
- case 'S': /* 1st selected "word" at curor */
- out = append_selection_word(out);
- break;
- case 'e': /* echo cmd before executing */
- break;
- case 'E': /* 1st selected expression at curor */
- out = append_selection_expr(out);
- break;
-
- case 'l': /* current line number */
- (void) sprintf(buf, "%d", current_lineno());
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- case 'L': /* line we're stopped at */
- (void) sprintf(buf, "%d", source_window_line);
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- case 'f': /* current file name */
- for (cp = source_window_symtab->filename;
- c = *cp++; *out++ = c)
- ;
- break;
- case 'b': /* break # we're stopped at */
- if (stop_breakpoint <= 0)
- /* if no breakpoint, don't do cmd */
- return;
-
- (void) sprintf(buf, "%d", stop_breakpoint);
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- }
- } else
- *out++ = c;
- }
- *out = 0;
- reinitialize_more_filter();
- /* have to exit via readline or tty modes stay messed up */
- for (cp = cmd_line; c = *cp++; )
- rl_stuff_char(c);
- rl_stuff_char('\n');
- input_avail = 1;
-}
-
-/*
- * Define and display all the buttons.
- */
-static void
-addbutton(parent, name, function, closure)
- Widget parent;
- char *name;
- void (*function) ();
- caddr_t closure;
-{
- static XtCallbackRec Callback[] = {
- {NULL, (caddr_t) NULL},
- {NULL, (caddr_t) NULL},
- };
- static Arg commandArgs[] = {
- {XtNlabel, (XtArgVal) NULL},
- {XtNcallback, (XtArgVal) Callback},
- };
- Widget w;
- char wname[128];
- register char *cp;
-
- strcpy(wname, name);
- while ((cp = index(wname, '*')) || (cp = index(wname, '.')))
- *cp -= 0x10;
-
- if (w = XtNameToWidget(parent, wname))
- XtDestroyWidget(w);
-
- Callback[0].callback = (XtCallbackProc) function;
- Callback[0].closure = (caddr_t) closure;
- commandArgs[0].value = (XtArgVal) name;
- XtCreateManagedWidget(wname, commandWidgetClass, parent,
- commandArgs, XtNumber(commandArgs));
-}
-
-/*
- * Create the button windows and store them in `buttons'.
- */
-static void
-create_buttons(parent)
- Widget parent;
-{
- addbutton(parent, "quit", do_command, "quit");
-}
-
-static void
-button_command(arg)
- char *arg;
-{
- char *label;
- unsigned int len;
-
- if (! arg)
- error_no_arg("button label and command");
-
- for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
- ;
- if (len == 0)
- error_no_arg("button label and command");
- arg[len] = 0;
-
- /* make a copy of button label & command for toolkit to use */
- label = malloc(len + 1);
- strcpy(label, arg);
-
- /* find the end of the label */
- if (*label == '"') {
- if ((arg = index(++label, '"')) == 0) {
- printf("button label missing closing quote\n");
- return;
- }
- *arg++ = 0;
- } else if (arg = index(label, ' '))
- *arg++ = 0;
- else
- arg = label;
-
- while (*arg && isspace(*arg))
- ++arg;
-
- addbutton(button_box_widget, label, do_command, arg);
-}
-
-static void
-button_delete_command(arg)
- char *arg;
-{
- unsigned int len;
- Widget w;
- register char *cp;
-
- if (! arg)
- error_no_arg("button name");
-
- for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
- ;
- if (len == 0)
- error_no_arg("button name");
- arg[len] = 0;
-
- /* find the end of the label */
- if (*arg == '"') {
- if ((cp = index(++arg, '"')) == 0) {
- printf("button label missing closing quote\n");
- return;
- }
- *cp++ = 0;
- }
- while ((cp = index(arg, '*')) || (cp = index(arg, '.')))
- *cp -= 0x10;
-
- if (w = XtNameToWidget(button_box_widget, arg))
- XtDestroyWidget(w);
-}
-
-/*
- * Create a "label window" that just displays the string LABEL.
- */
-static Widget
-create_label(name, label)
- char *name, *label;
-{
- Arg args[1];
- Widget w;
-
- XtSetArg(args[0], XtNlabel, label);
- w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget,
- args, XtNumber(args));
- return (w);
-}
-
-/*
- * Create a subwindow of PARENT that displays and scrolls the contents of
- * file FILENAME.
- */
-static Widget
-create_text_widget(parent, filename)
- Widget parent;
- char *filename;
-{
- static Arg arg[] = {
- {XtNstring, NULL},
- {XtNtype, XawAsciiFile},
- {XtNcursor, None},
- };
- Widget text_widget;
-
- arg[0].value = (XtArgVal)filename;
- text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass,
- parent, arg, XtNumber(arg));
- return (text_widget);
-}
-
-/*
- * Entry point to create the widgets representing our display.
- */
-void
-xgdb_create_window()
-{
- /* initialize toolkit, setup defaults */
-#ifdef notyet
- main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
- argcptr, argv, NULL, NULL, 0);
-#else
- char *dummy_argv[] = { "xgdb", 0 };
- int dummy_argc = 1;
- main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
- &dummy_argc, dummy_argv, NULL, NULL, 0);
-#endif
- display = XtDisplay(main_widget);
- containing_widget = XtCreateManagedWidget("frame", panedWidgetClass,
- main_widget, NULL, 0);
-
- sprintf(version_label, "XGDB %s", version);
- button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass,
- containing_widget, NULL, 0);
- create_buttons(button_box_widget);
- source_name_widget = create_label("srcLabel", "No source file yet.");
- source_text_widget = create_text_widget(containing_widget, "/dev/null");
-
- XtRealizeWidget(main_widget);
- XFlush(display);
-}
-
-/*
- * If we use an X window, the readline input loop is told to call
- * this function before reading a character from stdin.
- */
-/*ARGSUSED*/
-static void
-xgdb_window_hook()
-{
- register int inmask = 1 << fileno(stdin);
- register int xmask = 1 << ConnectionNumber(display);
- register int nfds, pend;
- int input_rfds;
- XEvent ev;
-
- /*
- * Display our current idea of the `interesting' source file then
- * loop, dispatching window events until data is available on
- * stdin. Then return so the input data can be processed.
- */
- input_avail = 0;
- xgdb_display_source();
-
- input_rfds = 0;
- while (input_avail == 0 && (input_rfds & inmask) == 0) {
- pend = XPending(display);
- if (!pend) {
- input_rfds = inmask | xmask;
- nfds = select(32, &input_rfds, 0, 0,
- (struct timeval *)0);
- if (nfds == -1 && errno == EINTR)
- continue;
- }
- if (pend || (input_rfds & xmask)) {
- XNextEvent(display, &ev);
- XtDispatchEvent(&ev);
- }
- }
-}
-
-void
-_initialize_xgdb()
-{
- extern void (*window_hook) ();
- extern int inhibit_windows;
- extern struct cmd_list_element *deletelist;
-
- if (inhibit_windows)
- return;
-
- if (! displayname) {
- displayname = getenv("DISPLAY");
- if (! displayname) {
- fprintf(stderr, "xgdb: no display name\n");
- inhibit_windows = 1;
- return;
- }
- }
- xgdb_create_window();
- window_hook = xgdb_window_hook;
- add_com("button", class_support, button_command,
-"Add command button to xgdb window. First argument is button\n\
-label, second is command associated with button. Command can\n\
-include printf-like escapes:\n\
- %s for current selection,\n\
- %S for first 'word' of current selection,\n\
- %e for current selection or expression at insertion pt,\n\
- %E for current selection or expression at insertion pt,\n\
- %l for current line number,\n\
- %L for line program stopped at,\n\
- %f for current file name,\n\
- %b for current breakpoint number.");
- add_cmd("button", class_support, button_delete_command,
-"Delete a button from the xgdb window.\n\
-Argument is name of button to be deleted.",
- &deletelist);
-}
diff --git a/gnu/usr.bin/groff/Makefile.cfg b/gnu/usr.bin/groff/Makefile.cfg
index ffeba9ce6dd6..6ef2ce2956e1 100644
--- a/gnu/usr.bin/groff/Makefile.cfg
+++ b/gnu/usr.bin/groff/Makefile.cfg
@@ -11,7 +11,7 @@ LIBDRIVER= $(.CURDIR)/../libdriver/libdriver.a
LIBBIB= $(.CURDIR)/../libbib/libbib.a
.endif
-CFLAGS+= -DHAVE_UNISTD_H=1\
+DEFINES= -DHAVE_UNISTD_H=1\
-DHAVE_DIRENT_H=1\
-DHAVE_LIMITS_H=1\
-DHAVE_STDLIB_H=1\
@@ -28,6 +28,9 @@ CFLAGS+= -DHAVE_UNISTD_H=1\
-DHAVE_SYS_SIGLIST=1\
-DARRAY_DELETE_NEEDS_SIZE=1
+CFLAGS+=$(DEFINES)
+CXXFLAGS+=$(DEFINES)
+
.y.o:
$(YACC) $(YFLAGS) $(.IMPSRC)
mv y.tab.c $(.PREFIX).cc
diff --git a/gnu/usr.bin/groff/addftinfo/Makefile b/gnu/usr.bin/groff/addftinfo/Makefile
index 6b93a8305696..873b7e8f2c73 100644
--- a/gnu/usr.bin/groff/addftinfo/Makefile
+++ b/gnu/usr.bin/groff/addftinfo/Makefile
@@ -3,6 +3,7 @@
PROG= addftinfo
SRCS= addftinfo.cc guess.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF)
DPADD+= $(LIBGROFF)
diff --git a/gnu/usr.bin/groff/devices/devascii/R.proto b/gnu/usr.bin/groff/devices/devascii/R.proto
index 876c74c4a6d8..9a8909e85b79 100644
--- a/gnu/usr.bin/groff/devices/devascii/R.proto
+++ b/gnu/usr.bin/groff/devices/devascii/R.proto
@@ -3,11 +3,15 @@ internalname 0
spacewidth 24
charset
! 24 0 0041
+r! "
+TP "
+Tp "
" 24 0 0042
lq "
rq "
# 24 0 0043
sh "
+sc "
$ 24 0 0044
Do "
% 24 0 0045
@@ -16,12 +20,20 @@ Do "
aa "
fm "
aq "
+ac "
( 24 0 0050
) 24 0 0051
* 24 0 0052
** "
+ho "
+ 24 0 0053
pl "
+dg "
+dd "
+ad "
+ah "
+-D "
+Sd "
, 24 0 0054
\- 24 0 0055
hy "
@@ -49,10 +61,12 @@ la "
fo "
= 24 0 0075
eq "
+ss "
> 24 0 0076
ra "
fc "
? 24 0 0077
+r? "
@ 24 0 0100
at "
A 24 0 0101
@@ -105,6 +119,8 @@ rB "
a^ 24 0 0136
^ "
ha "
+ua "
+de "
_ 24 0 0137
ru "
ul "
@@ -128,6 +144,8 @@ m 24 0 0155
n 24 0 0156
o 24 0 0157
*o "
+a- "
+ao "
p 24 0 0160
q 24 0 0161
r 24 0 0162
@@ -135,6 +153,7 @@ s 24 0 0163
t 24 0 0164
u 24 0 0165
v 24 0 0166
+da "
w 24 0 0167
x 24 0 0170
mu "
diff --git a/gnu/usr.bin/groff/eqn/Makefile b/gnu/usr.bin/groff/eqn/Makefile
index c3c162989caf..3049a6874add 100644
--- a/gnu/usr.bin/groff/eqn/Makefile
+++ b/gnu/usr.bin/groff/eqn/Makefile
@@ -5,6 +5,7 @@ SRCS= main.cc lex.cc box.cc limit.cc list.cc over.cc text.cc\
script.cc mark.cc other.cc delim.cc sqrt.cc pile.cc special.cc
OBJS= eqn.o
CFLAGS+= -I. -I$(.CURDIR)/../include
+CXXFLAGS+= -I. -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF)
DPADD+= $(LIBGROFF)
diff --git a/gnu/usr.bin/groff/grodvi/Makefile b/gnu/usr.bin/groff/grodvi/Makefile
index afa1b9cef5c1..2ceef51f7225 100644
--- a/gnu/usr.bin/groff/grodvi/Makefile
+++ b/gnu/usr.bin/groff/grodvi/Makefile
@@ -3,6 +3,7 @@
PROG= grodvi
SRCS= dvi.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm
DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/groff/Makefile b/gnu/usr.bin/groff/groff/Makefile
index 31b278637c72..b31f73d68e63 100644
--- a/gnu/usr.bin/groff/groff/Makefile
+++ b/gnu/usr.bin/groff/groff/Makefile
@@ -3,6 +3,7 @@
PROG= groff
SRCS= groff.cc pipeline.c
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF) -lm
DPADD+= $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/grops/Makefile b/gnu/usr.bin/groff/grops/Makefile
index 2877e49a2cee..eba9bc72f898 100644
--- a/gnu/usr.bin/groff/grops/Makefile
+++ b/gnu/usr.bin/groff/grops/Makefile
@@ -3,6 +3,7 @@
PROG= grops
SRCS= ps.cc psrm.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm
DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/grops/psrm.cc b/gnu/usr.bin/groff/grops/psrm.cc
index e26acf4b15c5..5abe683f7213 100644
--- a/gnu/usr.bin/groff/grops/psrm.cc
+++ b/gnu/usr.bin/groff/grops/psrm.cc
@@ -873,9 +873,10 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename,
const int NHEADER_COMMENTS = (sizeof(header_comment_table)
/ sizeof(header_comment_table[0]));
+ typedef (resource_manager::*resource_manager_mfp)(const char *, int, FILE *, FILE *);
struct comment_info {
const char *name;
- int (resource_manager::*proc)(const char *, int, FILE *, FILE *);
+ resource_manager_mfp proc;
};
static comment_info comment_table[] = {
diff --git a/gnu/usr.bin/groff/grotty/Makefile b/gnu/usr.bin/groff/grotty/Makefile
index a6e3e815aef4..585cd9bdd575 100644
--- a/gnu/usr.bin/groff/grotty/Makefile
+++ b/gnu/usr.bin/groff/grotty/Makefile
@@ -3,6 +3,7 @@
PROG= grotty
SRCS= tty.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm
DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/indxbib/Makefile b/gnu/usr.bin/groff/indxbib/Makefile
index 578f60efb834..a39aa4546286 100644
--- a/gnu/usr.bin/groff/indxbib/Makefile
+++ b/gnu/usr.bin/groff/indxbib/Makefile
@@ -3,6 +3,7 @@
PROG= indxbib
SRCS= indxbib.cc dirnamemax.c signal.c
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBBIB) $(LIBGROFF) -lm
DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/libbib/Makefile b/gnu/usr.bin/groff/libbib/Makefile
index 45b80e416903..a84c26866265 100644
--- a/gnu/usr.bin/groff/libbib/Makefile
+++ b/gnu/usr.bin/groff/libbib/Makefile
@@ -3,6 +3,7 @@
LIB= bib
SRCS= common.cc index.cc linear.cc search.cc map.c
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
NOMAN= noman
NOPROFILE= noprofile
diff --git a/gnu/usr.bin/groff/libdriver/Makefile b/gnu/usr.bin/groff/libdriver/Makefile
index aafc6fe3c3fb..3158982c8ba4 100644
--- a/gnu/usr.bin/groff/libdriver/Makefile
+++ b/gnu/usr.bin/groff/libdriver/Makefile
@@ -3,6 +3,7 @@
LIB= driver
SRCS= input.cc printer.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
NOMAN= noman
NOPROFILE= noprofile
diff --git a/gnu/usr.bin/groff/libgroff/Makefile b/gnu/usr.bin/groff/libgroff/Makefile
index 8cb9db360e0d..ab21f755f09e 100644
--- a/gnu/usr.bin/groff/libgroff/Makefile
+++ b/gnu/usr.bin/groff/libgroff/Makefile
@@ -8,6 +8,7 @@ SRCS= assert.cc change_lf.cc cmap.cc cset.cc device.cc errarg.cc\
tmpfile.cc illegal.cc version.cc
SRCS+= iftoa.c itoa.c matherr.c
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
NOMAN= noman
NOPROFILE= noprofile
diff --git a/gnu/usr.bin/groff/lkbib/Makefile b/gnu/usr.bin/groff/lkbib/Makefile
index 4551f973ce18..57fadd64aa72 100644
--- a/gnu/usr.bin/groff/lkbib/Makefile
+++ b/gnu/usr.bin/groff/lkbib/Makefile
@@ -3,6 +3,7 @@
PROG= lkbib
SRCS= lkbib.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBBIB) $(LIBGROFF) -lm
DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/lookbib/Makefile b/gnu/usr.bin/groff/lookbib/Makefile
index 685f2f35ce1f..94d832c0a2d8 100644
--- a/gnu/usr.bin/groff/lookbib/Makefile
+++ b/gnu/usr.bin/groff/lookbib/Makefile
@@ -3,6 +3,7 @@
PROG= lookbib
SRCS= lookbib.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBBIB) $(LIBGROFF) -lm
DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/pic/Makefile b/gnu/usr.bin/groff/pic/Makefile
index f7157213ea64..16a5ed39f56e 100644
--- a/gnu/usr.bin/groff/pic/Makefile
+++ b/gnu/usr.bin/groff/pic/Makefile
@@ -4,6 +4,7 @@ PROG= pic
SRCS= lex.cc main.cc object.cc common.cc troff.cc tex.cc
OBJS= pic.o
CFLAGS+= -I. -I$(.CURDIR)/../include
+CXXFLAGS+= -I. -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF) -lm
DPADD+= $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/refer/Makefile b/gnu/usr.bin/groff/refer/Makefile
index c6bb691b1588..7bbdd99f3f09 100644
--- a/gnu/usr.bin/groff/refer/Makefile
+++ b/gnu/usr.bin/groff/refer/Makefile
@@ -4,6 +4,7 @@ PROG= refer
SRCS= command.cc ref.cc refer.cc token.cc
OBJS= label.o
CFLAGS+= -I. -I$(.CURDIR)/../include
+CXXFLAGS+= -I. -I$(.CURDIR)/../include
LDADD+= $(LIBBIB) $(LIBGROFF) -lm
DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/soelim/Makefile b/gnu/usr.bin/groff/soelim/Makefile
index 76665627a6c8..aad2e1f0362a 100644
--- a/gnu/usr.bin/groff/soelim/Makefile
+++ b/gnu/usr.bin/groff/soelim/Makefile
@@ -3,6 +3,7 @@
PROG= soelim
SRCS= soelim.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF)
DPADD+= $(LIBGROFF)
diff --git a/gnu/usr.bin/groff/tbl/Makefile b/gnu/usr.bin/groff/tbl/Makefile
index 86b4b8c1a313..3000af7697b9 100644
--- a/gnu/usr.bin/groff/tbl/Makefile
+++ b/gnu/usr.bin/groff/tbl/Makefile
@@ -3,6 +3,7 @@
PROG= tbl
SRCS= main.cc table.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF) -lm
DPADD+= $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile b/gnu/usr.bin/groff/tfmtodit/Makefile
index ee28efe36159..6e81c27b4ab8 100644
--- a/gnu/usr.bin/groff/tfmtodit/Makefile
+++ b/gnu/usr.bin/groff/tfmtodit/Makefile
@@ -3,6 +3,7 @@
PROG= tfmtodit
SRCS= tfmtodit.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF) -lm
DPADD+= $(LIBGROFF) $(LIBMATH)
diff --git a/gnu/usr.bin/groff/troff/Makefile b/gnu/usr.bin/groff/troff/Makefile
index 5e8290b6f4b9..a7401a2646ec 100644
--- a/gnu/usr.bin/groff/troff/Makefile
+++ b/gnu/usr.bin/groff/troff/Makefile
@@ -4,6 +4,7 @@ PROG= troff
SRCS= env.cc node.cc input.cc div.cc symbol.cc dictionary.cc reg.cc \
number.cc majorminor.cc
CFLAGS+= -I$(.CURDIR)/../include
+CXXFLAGS+= -I$(.CURDIR)/../include
LDADD+= $(LIBGROFF) -lm
DPADD+= $(LIBGROFF) $(LIBMATH)
tmacdir?= /usr/share/tmac
diff --git a/gnu/usr.bin/groff/xditview/device.c b/gnu/usr.bin/groff/xditview/device.c
index 45cce4c6cf98..740f93f72b29 100644
--- a/gnu/usr.bin/groff/xditview/device.c
+++ b/gnu/usr.bin/groff/xditview/device.c
@@ -23,8 +23,14 @@ searching for device and font description files. */
#define WS " \t\r\n"
/* Minimum and maximum values a `signed int' can hold. */
+
+#ifndef INT_MIN
#define INT_MIN (-INT_MAX-1)
+#endif
+#ifndef INT_MAX
#define INT_MAX 2147483647
+#endif
+
#define CHAR_TABLE_SIZE 307
diff --git a/gnu/usr.bin/gzip/Makefile b/gnu/usr.bin/gzip/Makefile
index cd9ae24ebcce..e6f86523e47e 100644
--- a/gnu/usr.bin/gzip/Makefile
+++ b/gnu/usr.bin/gzip/Makefile
@@ -9,6 +9,7 @@ MLINKS= gzip.1 gunzip.1 gzip.1 zcat.1 gzip.1 gzcat.1
LINKS+= ${BINDIR}/gzip ${BINDIR}/gunzip
LINKS+= ${BINDIR}/gzip ${BINDIR}/gzcat
LINKS+= ${BINDIR}/gzip ${BINDIR}/zcat
+NOSHARED=yes
afterinstall:
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
diff --git a/gnu/usr.bin/kgdb/COPYING b/gnu/usr.bin/kgdb/COPYING
new file mode 100644
index 000000000000..9a1703758111
--- /dev/null
+++ b/gnu/usr.bin/kgdb/COPYING
@@ -0,0 +1,249 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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/gnu/usr.bin/gdb/ChangeLog b/gnu/usr.bin/kgdb/ChangeLog
index 1f2342b797a7..1f2342b797a7 100644
--- a/gnu/usr.bin/gdb/ChangeLog
+++ b/gnu/usr.bin/kgdb/ChangeLog
diff --git a/gnu/usr.bin/gdb/Gdbinit b/gnu/usr.bin/kgdb/Gdbinit
index bcacd5dc7e84..bcacd5dc7e84 100644
--- a/gnu/usr.bin/gdb/Gdbinit
+++ b/gnu/usr.bin/kgdb/Gdbinit
diff --git a/gnu/usr.bin/kgdb/Makefile b/gnu/usr.bin/kgdb/Makefile
new file mode 100644
index 000000000000..e32a4a05b6f6
--- /dev/null
+++ b/gnu/usr.bin/kgdb/Makefile
@@ -0,0 +1,36 @@
+# @(#)Makefile 6.4 (Berkley) 5/6/91
+
+PROG= kgdb
+GDBSRCS= blockframe.c breakpoint.c command.c copying.c core.c \
+ cplus-dem.c dbxread.c environ.c eval.c expprint.c \
+ expread.y findvar.c infcmd.c inflow.c infrun.c \
+ main.c obstack.c printcmd.c regex.c remote.c \
+ remote-sl.c source.c stack.c symmisc.c symtab.c \
+ utils.c valarith.c valops.c valprint.c values.c \
+ version.c
+SRCS= $(CONFIGSRCS) $(GDBSRCS) init.c
+CFLAGS+= -I. -I$(.CURDIR) -I$(.CURDIR)/config \
+ -DHAVE_VPRINTF -DKERNELDEBUG -DNEWVM
+DPADD+= $(LIBREADLINE) $(LIBTERM)
+LDADD+= -lreadline -ltermcap
+YFLAGS=
+.PATH: $(.CURDIR)/config
+
+depend:
+
+.include "config/Makefile.$(MACHINE)"
+.include <bsd.prog.mk>
+
+$(OBJS): param.h
+
+#
+# Generate the constructor
+#
+init.c: $(CONFIGSRCS) $(GDBSRCS) $(READLINESRCS)
+ -((cd $(.CURDIR)/config; \
+ egrep -h '^_initialize_[^ ]* *\(\)' $(CONFIGSRCS)); \
+ (cd $(.CURDIR); egrep -h '^_initialize_[^ ]* *\(\)' $(GDBSRCS))) | \
+ (echo 'void initialize_all_files () {'; sed -e 's/$$/;/'; echo '}') \
+ > init.c
+
+CLEANFILES+= init.c param.h
diff --git a/gnu/usr.bin/gdb/Makefile.dist b/gnu/usr.bin/kgdb/Makefile.dist
index 3cbc91f9786f..3cbc91f9786f 100644
--- a/gnu/usr.bin/gdb/Makefile.dist
+++ b/gnu/usr.bin/kgdb/Makefile.dist
diff --git a/gnu/usr.bin/gdb/Projects b/gnu/usr.bin/kgdb/Projects
index f38f6c74e959..f38f6c74e959 100644
--- a/gnu/usr.bin/gdb/Projects
+++ b/gnu/usr.bin/kgdb/Projects
diff --git a/gnu/usr.bin/gdb/README.gnu b/gnu/usr.bin/kgdb/README.gnu
index fa54dec236fd..fa54dec236fd 100644
--- a/gnu/usr.bin/gdb/README.gnu
+++ b/gnu/usr.bin/kgdb/README.gnu
diff --git a/gnu/usr.bin/gdb/XGdbinit.samp b/gnu/usr.bin/kgdb/XGdbinit.samp
index a99f10695606..a99f10695606 100644
--- a/gnu/usr.bin/gdb/XGdbinit.samp
+++ b/gnu/usr.bin/kgdb/XGdbinit.samp
diff --git a/gnu/usr.bin/gdb/Xgdb.ad b/gnu/usr.bin/kgdb/Xgdb.ad
index 5f9fe9920b49..5f9fe9920b49 100644
--- a/gnu/usr.bin/gdb/Xgdb.ad
+++ b/gnu/usr.bin/kgdb/Xgdb.ad
diff --git a/gnu/usr.bin/gdb/blockframe.c b/gnu/usr.bin/kgdb/blockframe.c
index 236d1cdccfec..236d1cdccfec 100644
--- a/gnu/usr.bin/gdb/blockframe.c
+++ b/gnu/usr.bin/kgdb/blockframe.c
diff --git a/gnu/usr.bin/gdb/breakpoint.c b/gnu/usr.bin/kgdb/breakpoint.c
index b515ed3f874f..b515ed3f874f 100644
--- a/gnu/usr.bin/gdb/breakpoint.c
+++ b/gnu/usr.bin/kgdb/breakpoint.c
diff --git a/gnu/usr.bin/gdb/command.c b/gnu/usr.bin/kgdb/command.c
index 79daea490383..79daea490383 100644
--- a/gnu/usr.bin/gdb/command.c
+++ b/gnu/usr.bin/kgdb/command.c
diff --git a/gnu/usr.bin/gdb/command.h b/gnu/usr.bin/kgdb/command.h
index fe28aef817ae..fe28aef817ae 100644
--- a/gnu/usr.bin/gdb/command.h
+++ b/gnu/usr.bin/kgdb/command.h
diff --git a/gnu/usr.bin/gdb/config/Makefile.i386 b/gnu/usr.bin/kgdb/config/Makefile.i386
index cc52aa3b13d4..cc52aa3b13d4 100644
--- a/gnu/usr.bin/gdb/config/Makefile.i386
+++ b/gnu/usr.bin/kgdb/config/Makefile.i386
diff --git a/gnu/usr.bin/gdb/config/default-dep.c b/gnu/usr.bin/kgdb/config/default-dep.c
index 13fe7b95a49e..13fe7b95a49e 100644
--- a/gnu/usr.bin/gdb/config/default-dep.c
+++ b/gnu/usr.bin/kgdb/config/default-dep.c
diff --git a/gnu/usr.bin/gdb/config/i386-dep.c b/gnu/usr.bin/kgdb/config/i386-dep.c
index c4630d0c07ac..c4630d0c07ac 100644
--- a/gnu/usr.bin/gdb/config/i386-dep.c
+++ b/gnu/usr.bin/kgdb/config/i386-dep.c
diff --git a/gnu/usr.bin/gdb/config/i386-pinsn.c b/gnu/usr.bin/kgdb/config/i386-pinsn.c
index 649baaf56bf6..649baaf56bf6 100644
--- a/gnu/usr.bin/gdb/config/i386-pinsn.c
+++ b/gnu/usr.bin/kgdb/config/i386-pinsn.c
diff --git a/gnu/usr.bin/kgdb/config/i386bsd-dep.c b/gnu/usr.bin/kgdb/config/i386bsd-dep.c
new file mode 100644
index 000000000000..16286eea2269
--- /dev/null
+++ b/gnu/usr.bin/kgdb/config/i386bsd-dep.c
@@ -0,0 +1,1889 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)i386bsd-dep.c 6.10 (Berkeley) 6/26/91";
+#endif /* not lint */
+
+/* Low level interface to ptrace, for GDB when running on the Intel 386.
+ Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can 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.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "value.h"
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <a.out.h>
+
+#ifndef N_SET_MAGIC
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
+#include <sys/user.h>
+#undef curpcb
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+
+#include <machine/reg.h>
+
+#ifdef KERNELDEBUG
+#ifndef NEWVM
+#include <sys/vmmac.h>
+#include <machine/pte.h>
+#else
+#include <sys/proc.h> /* for curproc */
+#endif
+#include <machine/vmparam.h>
+#include <machine/cpu.h>
+#include <ctype.h>
+#include "symtab.h" /* XXX */
+
+#undef vtophys /* XXX */
+
+extern int kernel_debugging;
+
+#define KERNOFF ((unsigned)KERNBASE)
+#ifndef NEWVM
+#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr))
+#define INUPAGE(x) \
+ ((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + NBPG)
+#else
+#define INKERNEL(x) ((x) >= KERNOFF)
+#endif
+
+#define PT_ADDR_ANY ((caddr_t) 1)
+
+/*
+ * Convert from sysmap pte index to system virtual address & vice-versa.
+ * (why aren't these in one of the system vm macro files???)
+ */
+#define smxtob(a) (sbr + (a) * sizeof(pte))
+#define btosmx(b) (((b) - sbr) / sizeof(pte))
+
+static int ok_to_cache();
+static int found_pcb;
+#ifdef NEWVM
+static CORE_ADDR curpcb;
+static CORE_ADDR kstack;
+#endif
+
+static void setregmap();
+
+extern int errno;
+
+/*
+ * This function simply calls ptrace with the given arguments. It exists so
+ * that all calls to ptrace are isolated in this machine-dependent file.
+ */
+int
+call_ptrace(request, pid, arg3, arg4)
+ int request;
+ pid_t pid;
+ caddr_t arg3;
+ int arg4;
+{
+ return(ptrace(request, pid, arg3, arg4));
+}
+
+kill_inferior()
+{
+ if (remote_debugging) {
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ /*
+ * It's a very, very bad idea to go away leaving
+ * breakpoints in a remote kernel or to leave it
+ * stopped at a breakpoint.
+ */
+ clear_breakpoints();
+#endif
+ remote_close(0);
+ inferior_died();
+ } else if (inferior_pid != 0) {
+ ptrace(PT_KILL, inferior_pid, 0, 0);
+ wait(0);
+ inferior_died();
+ }
+}
+
+/*
+ * This is used when GDB is exiting. It gives less chance of error.
+ */
+kill_inferior_fast()
+{
+ if (remote_debugging) {
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ clear_breakpoints();
+#endif
+ remote_close(0);
+ return;
+ }
+ if (inferior_pid == 0)
+ return;
+
+ ptrace(PT_KILL, inferior_pid, 0, 0);
+ wait(0);
+}
+
+/*
+ * Resume execution of the inferior process. If STEP is nonzero, single-step
+ * it. If SIGNAL is nonzero, give it that signal.
+ */
+void
+resume(step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume(step, signal);
+ else {
+ ptrace(step ? PT_STEP : PT_CONTINUE, inferior_pid,
+ PT_ADDR_ANY, signal);
+ if (errno)
+ perror_with_name("ptrace");
+ }
+}
+
+#ifdef ATTACH_DETACH
+extern int attach_flag;
+
+/*
+ * Start debugging the process whose number is PID.
+ */
+attach(pid)
+ int pid;
+{
+ errno = 0;
+ ptrace(PT_ATTACH, pid, 0, 0);
+ if (errno)
+ perror_with_name("ptrace");
+ attach_flag = 1;
+ return pid;
+}
+
+/*
+ * Stop debugging the process whose number is PID and continue it
+ * with signal number SIGNAL. SIGNAL = 0 means just continue it.
+ */
+void
+detach(signal)
+ int signal;
+{
+ errno = 0;
+ ptrace(PT_DETACH, inferior_pid, PT_ADDR_ANY, signal);
+ if (errno)
+ perror_with_name("ptrace");
+ attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+
+static unsigned int
+get_register_offset()
+{
+ unsigned int offset;
+ struct user u; /* XXX */
+ unsigned int flags = (char *) &u.u_pcb.pcb_flags - (char *) &u;
+
+ setregmap(ptrace(PT_READ_U, inferior_pid, (caddr_t)flags, 0));
+
+#ifdef NEWVM
+ offset = (char *) &u.u_kproc.kp_proc.p_regs - (char *) &u;
+ offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
+ USRSTACK;
+#else
+ offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
+ KERNEL_U_ADDR;
+#endif
+
+ return offset;
+}
+
+void
+fetch_inferior_registers()
+{
+ register int regno;
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+ unsigned int offset;
+
+ if (remote_debugging) {
+ extern char registers[];
+
+ remote_fetch_registers(registers);
+ return;
+ }
+
+ offset = get_register_offset();
+
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
+ *(int *)&buf[i] = ptrace(PT_READ_U, inferior_pid,
+ (caddr_t)regaddr, 0);
+ regaddr += sizeof(int);
+ }
+ supply_register(regno, buf);
+ }
+}
+
+/*
+ * Store our register values back into the inferior. If REGNO is -1, do this
+ * for all registers. Otherwise, REGNO specifies which register (so we can
+ * save time).
+ */
+store_inferior_registers(regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+ extern char registers[];
+ register int i;
+ unsigned int offset;
+
+ if (remote_debugging) {
+ extern char registers[];
+
+ remote_store_registers(registers);
+ return;
+ }
+
+ offset = get_register_offset();
+
+ if (regno >= 0) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
+ errno = 0;
+ ptrace(PT_WRITE_U, inferior_pid, (caddr_t)regaddr,
+ *(int *) &registers[REGISTER_BYTE(regno) + i]);
+ if (errno != 0) {
+ sprintf(buf, "writing register number %d(%d)",
+ regno, i);
+ perror_with_name(buf);
+ }
+ regaddr += sizeof(int);
+ }
+ } else
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno);
+ i += sizeof(int)) {
+ errno = 0;
+ ptrace(PT_WRITE_U, inferior_pid,
+ (caddr_t)regaddr,
+ *(int *) &registers[REGISTER_BYTE(regno) + i]);
+ if (errno != 0) {
+ sprintf(buf,
+ "writing register number %d(%d)",
+ regno, i);
+ perror_with_name(buf);
+ }
+ regaddr += sizeof(int);
+ }
+ }
+}
+
+/*
+ * Copy LEN bytes from inferior's memory starting at MEMADDR to debugger
+ * memory starting at MYADDR. On failure (cannot read from inferior, usually
+ * because address is out of bounds) returns the value of errno.
+ */
+int
+read_inferior_memory(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & -sizeof(int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
+ sizeof(int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca(count * sizeof(int));
+ extern int errno;
+
+ if (remote_debugging)
+ return (remote_read_inferior_memory(memaddr, myaddr, len));
+
+ /* Read all the longwords */
+ errno = 0;
+ for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
+ buffer[i] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy((char *) buffer + (memaddr & (sizeof(int) - 1)), myaddr, len);
+ return(errno);
+}
+
+/*
+ * Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory
+ * at MEMADDR. On failure (cannot write the inferior) returns the value of
+ * errno.
+ */
+
+int
+write_inferior_memory(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & -sizeof(int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
+ sizeof(int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca(count * sizeof(int));
+ extern int errno;
+
+ /*
+ * Fill start and end extra bytes of buffer with existing memory
+ * data.
+ */
+ if (remote_debugging)
+ return (remote_write_inferior_memory(memaddr, myaddr, len));
+
+ /*
+ * Fill start and end extra bytes of buffer with existing memory
+ * data.
+ */
+ buffer[0] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
+
+ if (count > 1)
+ buffer[count - 1] = ptrace(PT_READ_I, inferior_pid,
+ (caddr_t)addr + (count - 1) * sizeof(int), 0);
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy(myaddr, (char *) buffer + (memaddr & (sizeof(int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ errno = 0;
+ for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
+ ptrace(PT_WRITE_I, inferior_pid, (caddr_t)addr, buffer[i]);
+
+ return(errno);
+}
+
+
+/*
+ * Work with core dump and executable files, for GDB.
+ * This code would be in core.c if it weren't machine-dependent.
+ */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/*
+ * Make COFF and non-COFF names for things a little more compatible to reduce
+ * conditionals later.
+ */
+
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+
+extern char *sys_siglist[];
+
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+extern int (*core_file_hook)();
+
+#ifdef KERNELDEBUG
+/*
+ * Kernel debugging routines.
+ */
+
+#define IOTOP 0x100000 /* XXX should get this from include file */
+#define IOBASE 0xa0000 /* XXX should get this from include file */
+
+static CORE_ADDR file_offset;
+static CORE_ADDR lowram;
+static CORE_ADDR sbr;
+static CORE_ADDR slr;
+static struct pcb pcb;
+
+static CORE_ADDR
+ksym_lookup(name)
+ char *name;
+{
+ struct symbol *sym;
+ int i;
+
+ if ((i = lookup_misc_func(name)) < 0)
+ error("kernel symbol `%s' not found.", name);
+
+ return (misc_function_vector[i].address);
+}
+
+/*
+ * return true if 'len' bytes starting at 'addr' can be read out as
+ * longwords and/or locally cached (this is mostly for memory mapped
+ * i/o register access when debugging remote kernels).
+ *
+ * XXX the HP code does this differently with NEWVM
+ */
+static int
+ok_to_cache(addr, len)
+{
+ static CORE_ADDR atdevbase;
+
+ if (! atdevbase)
+ atdevbase = ksym_lookup("atdevbase");
+
+ if (addr >= atdevbase && addr < atdevbase + (IOTOP - IOBASE))
+ return (0);
+
+ return (1);
+}
+
+static
+physrd(addr, dat, len)
+ u_int addr;
+ char *dat;
+{
+ if (lseek(corechan, addr - file_offset, L_SET) == -1)
+ return (-1);
+ if (read(corechan, dat, len) != len)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * When looking at kernel data space through /dev/mem or with a core file, do
+ * virtual memory mapping.
+ */
+#ifdef NEWVM
+static CORE_ADDR
+vtophys(addr)
+ CORE_ADDR addr;
+{
+ CORE_ADDR v;
+ struct pte pte;
+ static CORE_ADDR PTD = -1;
+ CORE_ADDR current_ptd;
+
+ /*
+ * If we're looking at the kernel stack,
+ * munge the address to refer to the user space mapping instead;
+ * that way we get the requested process's kstack, not the running one.
+ */
+ if (addr >= kstack && addr < kstack + ctob(UPAGES))
+ addr = (addr - kstack) + curpcb;
+
+ /*
+ * We may no longer have a linear system page table...
+ *
+ * Here's the scoop. IdlePTD contains the physical address
+ * of a page table directory that always maps the kernel.
+ * IdlePTD is in memory that is mapped 1-to-1, so we can
+ * find it easily given its 'virtual' address from ksym_lookup().
+ * For hysterical reasons, the value of IdlePTD is stored in sbr.
+ *
+ * To look up a kernel address, we first convert it to a 1st-level
+ * address and look it up in IdlePTD. This gives us the physical
+ * address of a page table page; we extract the 2nd-level part of
+ * VA and read the 2nd-level pte. Finally, we add the offset part
+ * of the VA into the physical address from the pte and return it.
+ *
+ * User addresses are a little more complicated. If we don't have
+ * a current PCB from read_pcb(), we use PTD, which is the (fixed)
+ * virtual address of the current ptd. Since it's NOT in 1-to-1
+ * kernel space, we must look it up using IdlePTD. If we do have
+ * a pcb, we get the ptd from pcb_ptd.
+ */
+
+ if (INKERNEL(addr))
+ current_ptd = sbr;
+ else if (found_pcb == 0) {
+ if (PTD == -1)
+ PTD = vtophys(ksym_lookup("PTD"));
+ current_ptd = PTD;
+ } else
+ current_ptd = pcb.pcb_ptd;
+
+ /*
+ * Read the first-level page table (ptd).
+ */
+ v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte;
+ if (physrd(v, (char *)&pte, sizeof pte) || pte.pg_v == 0)
+ return (~0);
+
+ /*
+ * Read the second-level page table.
+ */
+ v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte;
+ if (physrd(v, (char *) &pte, sizeof(pte)) || pte.pg_v == 0)
+ return (~0);
+
+ addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET);
+#if 0
+ printf("vtophys(%x) -> %x\n", oldaddr, addr);
+#endif
+ return (addr);
+}
+#else
+static CORE_ADDR
+vtophys(addr)
+ CORE_ADDR addr;
+{
+ CORE_ADDR v;
+ struct pte pte;
+ CORE_ADDR oldaddr = addr;
+
+ if (found_pcb == 0 && INUPAGE(addr)) {
+ static CORE_ADDR pSwtchmap;
+
+ if (pSwtchmap == 0)
+ pSwtchmap = vtophys(ksym_lookup("Swtchmap"));
+ addr = pSwtchmap;
+ } else if (INKERNEL(addr)) {
+ /*
+ * In system space get system pte. If valid or reclaimable
+ * then physical address is combination of its page number
+ * and the page offset of the original address.
+ */
+ addr = smxtob(btop(addr - KERNOFF)) - KERNOFF;
+ } else {
+ v = btop(addr);
+ if (v < pcb.pcb_p0lr)
+ addr = (CORE_ADDR) pcb.pcb_p0br +
+ v * sizeof (struct pte);
+ else if (v >= pcb.pcb_p1lr && v < P1PAGES)
+ addr = (CORE_ADDR) pcb.pcb_p0br +
+ ((pcb.pcb_szpt * NPTEPG - HIGHPAGES) -
+ (BTOPUSRSTACK - v)) * sizeof (struct pte);
+ else
+ return (~0);
+
+ /*
+ * For p0/p1 address, user-level page table should be in
+ * kernel vm. Do second-level indirect by recursing.
+ */
+ if (!INKERNEL(addr))
+ return (~0);
+
+ addr = vtophys(addr);
+ }
+ /*
+ * Addr is now address of the pte of the page we are interested in;
+ * get the pte and paste up the physical address.
+ */
+ if (physrd(addr, (char *) &pte, sizeof(pte)))
+ return (~0);
+
+ if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
+ return (~0);
+
+ addr = (CORE_ADDR)ptob(pte.pg_pfnum) + (oldaddr & PGOFSET);
+#if 0
+ printf("vtophys(%x) -> %x\n", oldaddr, addr);
+#endif
+ return (addr);
+}
+
+#endif
+
+static
+kvread(addr)
+ CORE_ADDR addr;
+{
+ CORE_ADDR paddr = vtophys(addr);
+
+ if (paddr != ~0)
+ if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0);
+ return (addr);
+
+ return (~0);
+}
+
+static void
+read_pcb(uaddr)
+ u_int uaddr;
+{
+ int i;
+ int *pcb_regs = (int *)&pcb;
+
+#ifdef NEWVM
+ if (physrd(uaddr, (char *)&pcb, sizeof pcb))
+ error("cannot read pcb at %x\n", uaddr);
+ printf("current pcb at %x\n", uaddr);
+#else
+ if (physrd(uaddr, (char *)&pcb, sizeof pcb))
+ error("cannot read pcb at %x\n", uaddr);
+ printf("p0br %x p0lr %x p1br %x p1lr %x\n",
+ pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr);
+#endif
+
+ /*
+ * get the register values out of the sys pcb and
+ * store them where `read_register' will find them.
+ */
+ for (i = 0; i < 8; ++i)
+ supply_register(i, &pcb_regs[i+10]);
+ supply_register(8, &pcb_regs[8]); /* eip */
+ supply_register(9, &pcb_regs[9]); /* eflags */
+ for (i = 10; i < 13; ++i) /* cs, ss, ds */
+ supply_register(i, &pcb_regs[i+9]);
+ supply_register(13, &pcb_regs[18]); /* es */
+ for (i = 14; i < 16; ++i) /* fs, gs */
+ supply_register(i, &pcb_regs[i+8]);
+
+ /* XXX 80387 registers? */
+}
+
+static void
+setup_kernel_debugging()
+{
+ struct stat stb;
+ int devmem = 0;
+ CORE_ADDR addr;
+
+ fstat(corechan, &stb);
+ if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0))
+ devmem = 1;
+
+#ifdef NEWVM
+ physrd(ksym_lookup("IdlePTD") - KERNOFF, &sbr, sizeof sbr);
+ slr = 2 * NPTEPG; /* XXX temporary */
+ printf("IdlePTD %x\n", sbr);
+ curpcb = ksym_lookup("curpcb") - KERNOFF;
+ physrd(curpcb, &curpcb, sizeof curpcb);
+ kstack = ksym_lookup("kstack");
+#else
+ sbr = ksym_lookup("Sysmap");
+ slr = ksym_lookup("Syssize");
+ printf("sbr %x slr %x\n", sbr, slr);
+#endif
+
+ /*
+ * pcb where "panic" saved registers in first thing in current
+ * u area.
+ */
+#ifndef NEWVM
+ read_pcb(vtophys(ksym_lookup("u")));
+#endif
+ found_pcb = 1;
+ if (!devmem) {
+ /* find stack frame */
+ CORE_ADDR panicstr;
+ char buf[256];
+ register char *cp;
+
+ panicstr = kvread(ksym_lookup("panicstr"));
+ if (panicstr == ~0)
+ return;
+ (void) kernel_core_file_hook(panicstr, buf, sizeof(buf));
+ for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
+ if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
+ *cp = '?';
+ if (*cp)
+ *cp = '\0';
+ printf("panic: %s\n", buf);
+ read_pcb(ksym_lookup("dumppcb") - KERNOFF);
+ }
+#ifdef NEWVM
+ else
+ read_pcb(vtophys(kstack));
+#endif
+
+ stack_start = USRSTACK;
+ stack_end = USRSTACK + ctob(UPAGES);
+}
+
+set_paddr_command(arg)
+ char *arg;
+{
+ u_int uaddr;
+
+ if (!arg)
+ error_no_arg("ps-style address for new current process");
+ if (!kernel_debugging)
+ error("not debugging kernel");
+ uaddr = (u_int) parse_and_eval_address(arg);
+#ifndef NEWVM
+ read_pcb(ctob(uaddr));
+#else
+ /* p_addr is now a pcb virtual address */
+ read_pcb(vtophys(uaddr));
+ curpcb = uaddr;
+#endif
+
+ flush_cached_frames();
+ set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc()));
+ select_frame(get_current_frame(), 0);
+}
+
+/*
+ * read len bytes from kernel virtual address 'addr' into local
+ * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read
+ * errors, portion of buffer not read is zeroed.
+ */
+kernel_core_file_hook(addr, buf, len)
+ CORE_ADDR addr;
+ char *buf;
+ int len;
+{
+ int i;
+ CORE_ADDR paddr;
+
+ while (len > 0) {
+ paddr = vtophys(addr);
+ if (paddr == ~0) {
+ bzero(buf, len);
+ return (1);
+ }
+ /* we can't read across a page boundary */
+ i = min(len, NBPG - (addr & PGOFSET));
+ if (physrd(paddr, buf, i)) {
+ bzero(buf, len);
+ return (1);
+ }
+ buf += i;
+ addr += i;
+ len -= i;
+ }
+ return (0);
+}
+#endif
+
+core_file_command(filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+#ifdef KERNELDEBUG
+ struct stat stb;
+#endif
+
+ /*
+ * Discard all vestiges of any previous core file and mark data and
+ * stack spaces as empty.
+ */
+ if (corefile)
+ free(corefile);
+ corefile = 0;
+ core_file_hook = 0;
+
+ if (corechan >= 0)
+ close(corechan);
+ corechan = -1;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename == 0) {
+ if (from_tty)
+ printf("No core file now.\n");
+ return;
+ }
+ filename = tilde_expand(filename);
+ make_cleanup(free, filename);
+ if (have_inferior_p())
+ error("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open(filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name(filename);
+
+#ifdef KERNELDEBUG
+ fstat(corechan, &stb);
+
+ if (kernel_debugging) {
+ setup_kernel_debugging();
+ core_file_hook = kernel_core_file_hook;
+ } else if ((stb.st_mode & S_IFMT) == S_IFCHR &&
+ stb.st_rdev == makedev(2, 1)) {
+ /* looking at /dev/kmem */
+ data_offset = data_start = KERNOFF;
+ data_end = ~0; /* XXX */
+ stack_end = stack_start = data_end;
+ } else
+#endif
+ {
+ /*
+ * 4.2-style core dump file.
+ */
+ struct user u;
+ unsigned int reg_offset;
+
+ val = myread(corechan, &u, sizeof u);
+ if (val < 0)
+ perror_with_name("Not a core file: reading upage");
+ if (val != sizeof u)
+ error("Not a core file: could only read %d bytes", val);
+
+ /*
+ * We are depending on exec_file_command having been
+ * called previously to set exec_data_start. Since
+ * the executable and the core file share the same
+ * text segment, the address of the data segment will
+ * be the same in both.
+ */
+ data_start = exec_data_start;
+
+#ifndef NEWVM
+ data_end = data_start + NBPG * u.u_dsize;
+ stack_start = stack_end - NBPG * u.u_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG * (UPAGES + u.u_dsize);
+
+ /*
+ * Some machines put an absolute address in here and
+ * some put the offset in the upage of the regs.
+ */
+ reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
+#else
+ stack_end = (CORE_ADDR) u.u_kproc.kp_eproc.e_vm.vm_maxsaddr
+ + MAXSSIZ;
+
+ data_end = data_start +
+ NBPG * u.u_kproc.kp_eproc.e_vm.vm_dsize;
+ stack_start = stack_end -
+ NBPG * u.u_kproc.kp_eproc.e_vm.vm_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG *
+ (UPAGES + u.u_kproc.kp_eproc.e_vm.vm_dsize);
+
+ reg_offset = (int) u.u_kproc.kp_proc.p_regs - USRSTACK;
+#endif
+
+ setregmap(u.u_pcb.pcb_flags);
+
+ /*
+ * I don't know where to find this info. So, for now,
+ * mark it as not available.
+ */
+ /* N_SET_MAGIC (core_aouthdr, 0); */
+ bzero ((char *) &core_aouthdr, sizeof core_aouthdr);
+
+ /*
+ * Read the register values out of the core file and
+ * store them where `read_register' will find them.
+ */
+ {
+ register int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ val = lseek(corechan, register_addr(regno, reg_offset), 0);
+ if (val < 0
+ || (val = myread(corechan, buf, sizeof buf)) < 0) {
+ char *buffer = (char *) alloca(strlen(reg_names[regno]) + 30);
+ strcpy(buffer, "Reading register ");
+ strcat(buffer, reg_names[regno]);
+ perror_with_name(buffer);
+ }
+ supply_register(regno, buf);
+ }
+ }
+ }
+#endif
+ if (filename[0] == '/')
+ corefile = savestring(filename, strlen(filename));
+ else
+ corefile = concat(current_directory, "/", filename);
+
+ set_current_frame(create_new_frame(read_register(FP_REGNUM),
+ read_pc()));
+ select_frame(get_current_frame(), 0);
+ validate_files();
+}
+
+exec_file_command(filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /*
+ * Eliminate all traces of old exec file. Mark text segment as empty.
+ */
+
+ if (execfile)
+ free(execfile);
+ execfile = 0;
+ data_start = 0;
+ data_end = 0;
+ stack_start = 0;
+ stack_end = 0;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close(execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename) {
+ filename = tilde_expand(filename);
+ make_cleanup(free, filename);
+
+ execchan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name(filename);
+
+ {
+ struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD(execchan);
+#endif
+
+ val = myread(execchan, &exec_aouthdr, sizeof(AOUTHDR));
+
+ if (val < 0)
+ perror_with_name(filename);
+
+#ifdef KERNELDEBUG
+ if (kernel_debugging) {
+ /* Gross and disgusting XXX */
+ text_start = KERNTEXT_BASE;
+ exec_data_start = KERNTEXT_BASE +
+ (exec_aouthdr.a_text + 4095) & ~ 4095;
+ } else {
+#endif
+ text_start = N_TXTADDR(exec_aouthdr);
+ exec_data_start = N_DATADDR(exec_aouthdr);
+#ifdef KERNELDEBUG
+ }
+#endif
+
+ text_offset = N_TXTOFF(exec_aouthdr);
+ exec_data_offset = N_TXTOFF(exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+
+ fstat(execchan, &st_exec);
+ exec_mtime = st_exec.st_mtime;
+ }
+
+ validate_files();
+ } else if (from_tty)
+ printf("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
+
+int dummy_code[] = {
+ 0xb8909090, /* nop; nop; nop; movl $0x32323232,%eax */
+ 0x32323232,
+#define DUMMY_CALL_INDEX 1
+ 0x90ccd0ff, /* call %eax; int3; nop */
+};
+
+/*
+ * Build `dummy' call instructions on inferior's stack to cause
+ * it to call a subroutine.
+ *
+ * N.B. - code in wait_for_inferior requires that sp < pc < fp when
+ * we take the trap 2 above so it will recognize that we stopped
+ * at a `dummy' call. So, after the call sp is *not* decremented
+ * to clean the arguments, code & other stuff we lay on the stack.
+ * Since the regs are restored to saved values at the breakpoint,
+ * sp will get reset correctly. Also, this restore means we don't
+ * have to construct frame linkage info to save pc & fp. The lack
+ * of frame linkage means we can't do a backtrace, etc., if the
+ * called function gets a fault or hits a breakpoint but code in
+ * run_stack_dummy makes this impossible anyway.
+ */
+CORE_ADDR
+setup_dummy(sp, funaddr, nargs, args, struct_return_bytes, pushfn)
+ CORE_ADDR sp;
+ CORE_ADDR funaddr;
+ int nargs;
+ value *args;
+ int struct_return_bytes;
+ CORE_ADDR (*pushfn)();
+{
+ int padding, i;
+ CORE_ADDR top = sp, struct_addr, pc;
+
+ i = arg_stacklen(nargs, args) + struct_return_bytes
+ + sizeof(dummy_code);
+ if (i & 3)
+ padding = 4 - (i & 3);
+ else
+ padding = 0;
+ pc = sp - sizeof(dummy_code);
+ sp = pc - padding - struct_return_bytes;
+ struct_addr = sp;
+ while (--nargs >= 0)
+ sp = (*pushfn)(sp, *args++);
+ if (struct_return_bytes)
+ STORE_STRUCT_RETURN(struct_addr, sp);
+ write_register(SP_REGNUM, sp);
+
+ dummy_code[DUMMY_CALL_INDEX] = (int)funaddr;
+ write_memory(pc, (char *)dummy_code, sizeof(dummy_code));
+
+ return pc;
+}
+
+/* helper functions for m-i386.h */
+
+/* stdio style buffering to minimize calls to ptrace */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[sizeof (int)];
+static int codestream_off;
+static int codestream_cnt;
+
+#define codestream_tell() (codestream_addr + codestream_off)
+#define codestream_peek() (codestream_cnt == 0 ? \
+ codestream_fill(1): codestream_buf[codestream_off])
+#define codestream_get() (codestream_cnt-- == 0 ? \
+ codestream_fill(0) : codestream_buf[codestream_off++])
+
+static unsigned char
+codestream_fill (peek_flag)
+{
+ codestream_addr = codestream_next_addr;
+ codestream_next_addr += sizeof (int);
+ codestream_off = 0;
+ codestream_cnt = sizeof (int);
+ read_memory (codestream_addr,
+ (unsigned char *)codestream_buf,
+ sizeof (int));
+
+ if (peek_flag)
+ return (codestream_peek());
+ else
+ return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+{
+ codestream_next_addr = place & -sizeof (int);
+ codestream_cnt = 0;
+ codestream_fill (1);
+ while (codestream_tell() != place)
+ codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+ unsigned char *buf;
+{
+ unsigned char *p;
+ int i;
+ p = buf;
+ for (i = 0; i < count; i++)
+ *p++ = codestream_get ();
+}
+
+/* next instruction is a jump, move to target */
+static
+i386_follow_jump ()
+{
+ int long_delta;
+ short short_delta;
+ char byte_delta;
+ int data16;
+ int pos;
+
+ pos = codestream_tell ();
+
+ data16 = 0;
+ if (codestream_peek () == 0x66)
+ {
+ codestream_get ();
+ data16 = 1;
+ }
+
+ switch (codestream_get ())
+ {
+ case 0xe9:
+ /* relative jump: if data16 == 0, disp32, else disp16 */
+ if (data16)
+ {
+ codestream_read ((unsigned char *)&short_delta, 2);
+ pos += short_delta + 3; /* include size of jmp inst */
+ }
+ else
+ {
+ codestream_read ((unsigned char *)&long_delta, 4);
+ pos += long_delta + 5;
+ }
+ break;
+ case 0xeb:
+ /* relative jump, disp8 (ignore data16) */
+ codestream_read ((unsigned char *)&byte_delta, 1);
+ pos += byte_delta + 2;
+ break;
+ }
+ codestream_seek (pos + data16);
+}
+
+/*
+ * find & return amound a local space allocated, and advance codestream to
+ * first register push (if any)
+ *
+ * if entry sequence doesn't make sense, return -1, and leave
+ * codestream pointer random
+ */
+static long
+i386_get_frame_setup (pc)
+{
+ unsigned char op;
+
+ codestream_seek (pc);
+
+ i386_follow_jump ();
+
+ op = codestream_get ();
+
+ if (op == 0x58) /* popl %eax */
+ {
+ /*
+ * this function must start with
+ *
+ * popl %eax 0x58
+ * xchgl %eax, (%esp) 0x87 0x04 0x24
+ * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
+ *
+ * (the system 5 compiler puts out the second xchg
+ * inst, and the assembler doesn't try to optimize it,
+ * so the 'sib' form gets generated)
+ *
+ * this sequence is used to get the address of the return
+ * buffer for a function that returns a structure
+ */
+ int pos;
+ unsigned char buf[4];
+ static unsigned char proto1[3] = { 0x87,0x04,0x24 };
+ static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
+ pos = codestream_tell ();
+ codestream_read (buf, 4);
+ if (bcmp (buf, proto1, 3) == 0)
+ pos += 3;
+ else if (bcmp (buf, proto2, 4) == 0)
+ pos += 4;
+
+ codestream_seek (pos);
+ op = codestream_get (); /* update next opcode */
+ }
+
+ if (op == 0x55) /* pushl %esp */
+ {
+ /* check for movl %esp, %ebp - can be written two ways */
+ switch (codestream_get ())
+ {
+ case 0x8b:
+ if (codestream_get () != 0xec)
+ return (-1);
+ break;
+ case 0x89:
+ if (codestream_get () != 0xe5)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ /* check for stack adjustment
+ *
+ * subl $XXX, %esp
+ *
+ * note: you can't subtract a 16 bit immediate
+ * from a 32 bit reg, so we don't have to worry
+ * about a data16 prefix
+ */
+ op = codestream_peek ();
+ if (op == 0x83)
+ {
+ /* subl with 8 bit immed */
+ codestream_get ();
+ if (codestream_get () != 0xec)
+ return (-1);
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ return (codestream_get());
+ }
+ else if (op == 0x81)
+ {
+ /* subl with 32 bit immed */
+ int locals;
+ codestream_get();
+ if (codestream_get () != 0xec)
+ return (-1);
+ /* subl with 32 bit immediate */
+ codestream_read ((unsigned char *)&locals, 4);
+ return (locals);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+ else if (op == 0xc8)
+ {
+ /* enter instruction: arg is 16 bit unsigned immed */
+ unsigned short slocals;
+ codestream_read ((unsigned char *)&slocals, 2);
+ codestream_get (); /* flush final byte of enter instruction */
+ return (slocals);
+ }
+ return (-1);
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+/* on the 386, the instruction following the call could be:
+ * popl %ecx - one arg
+ * addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
+ * anything else - zero args
+ */
+
+int
+i386_frame_num_args (fi)
+ struct frame_info fi;
+{
+ int retpc;
+ unsigned char op;
+ struct frame_info *pfi;
+
+ pfi = get_prev_frame_info ((fi));
+ if (pfi == 0)
+ {
+ /* Note: this can happen if we are looking at the frame for
+ main, because FRAME_CHAIN_VALID won't let us go into
+ start. If we have debugging symbols, that's not really
+ a big deal; it just means it will only show as many arguments
+ to main as are declared. */
+ return -1;
+ }
+ else
+ {
+ retpc = pfi->pc;
+ op = read_memory_integer (retpc, 1);
+ if (op == 0x59)
+ /* pop %ecx */
+ return 1;
+ else if (op == 0x83)
+ {
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<signed imm 8 bits>, %esp */
+ return (read_memory_integer (retpc+2,1)&0xff)/4;
+ else
+ return 0;
+ }
+ else if (op == 0x81)
+ { /* add with 32 bit immediate */
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<imm 32>, %esp */
+ return read_memory_integer (retpc+2, 4) / 4;
+ else
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+
+/*
+ * parse the first few instructions of the function to see
+ * what registers were stored.
+ *
+ * We handle these cases:
+ *
+ * The startup sequence can be at the start of the function,
+ * or the function can start with a branch to startup code at the end.
+ *
+ * %ebp can be set up with either the 'enter' instruction, or
+ * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
+ * but was once used in the sys5 compiler)
+ *
+ * Local space is allocated just below the saved %ebp by either the
+ * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
+ * a 16 bit unsigned argument for space to allocate, and the
+ * 'addl' instruction could have either a signed byte, or
+ * 32 bit immediate.
+ *
+ * Next, the registers used by this function are pushed. In
+ * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
+ * (and sometimes a harmless bug causes it to also save but not restore %eax);
+ * however, the code below is willing to see the pushes in any order,
+ * and will handle up to 8 of them.
+ *
+ * If the setup sequence is at the end of the function, then the
+ * next instruction will be a branch back to the start.
+ */
+
+i386_frame_find_saved_regs (fip, fsrp)
+ struct frame_info *fip;
+ struct frame_saved_regs *fsrp;
+{
+ unsigned long locals;
+ unsigned char *p;
+ unsigned char op;
+ CORE_ADDR dummy_bottom;
+ CORE_ADDR adr;
+ int i;
+
+ bzero (fsrp, sizeof *fsrp);
+
+#if 0
+ /* if frame is the end of a dummy, compute where the
+ * beginning would be
+ */
+ dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH;
+
+ /* check if the PC is in the stack, in a dummy frame */
+ if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
+ {
+ /* all regs were saved by push_call_dummy () */
+ adr = fip->frame - 4;
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ fsrp->regs[i] = adr;
+ adr -= 4;
+ }
+ return;
+ }
+#endif
+
+ locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
+
+ if (locals >= 0)
+ {
+ adr = fip->frame - 4 - locals;
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_get ();
+ if (op < 0x50 || op > 0x57)
+ break;
+ fsrp->regs[op - 0x50] = adr;
+ adr -= 4;
+ }
+ }
+
+ fsrp->regs[PC_REGNUM] = fip->frame + 4;
+ fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+i386_skip_prologue (pc)
+{
+ unsigned char op;
+ int i;
+
+ if (i386_get_frame_setup (pc) < 0)
+ return (pc);
+
+ /* found valid frame setup - codestream now points to
+ * start of push instructions for saving registers
+ */
+
+ /* skip over register saves */
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_peek ();
+ /* break if not pushl inst */
+ if (op < 0x50 || op > 0x57)
+ break;
+ codestream_get ();
+ }
+
+ i386_follow_jump ();
+
+ return (codestream_tell ());
+}
+
+i386_pop_frame ()
+{
+ FRAME frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+ struct frame_saved_regs fsr;
+ struct frame_info *fi;
+
+ fi = get_frame_info (frame);
+ fp = fi->frame;
+ get_frame_saved_regs (fi, &fsr);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ {
+ CORE_ADDR adr;
+ adr = fsr.regs[regnum];
+ if (adr)
+ write_register (regnum, read_memory_integer (adr, 4));
+ }
+ write_register (FP_REGNUM, read_memory_integer (fp, 4));
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+ write_register (SP_REGNUM, fp + 8);
+ flush_cached_frames ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+}
+
+/* this table must line up with REGISTER_NAMES in m-i386.h */
+/* symbols like 'EAX' come from <sys/reg.h> */
+static int trapmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS,
+ tDS, tES, tES, tES /* lies: no fs or gs */
+};
+#if defined(FM_TRAP) || defined(EX_TRAPSTK)
+static int syscallmap[] =
+{
+ sEAX, sECX, sEDX, sEBX,
+ sESP, sEBP, sESI, sEDI,
+ sEIP, sEFLAGS, sCS, sSS,
+ sCS, sCS, sCS, sCS /* lies: no ds, es, fs or gs */
+};
+#endif
+static int *regmap;
+
+static void
+setregmap(flags)
+ int flags;
+{
+#ifdef FM_TRAP
+ regmap = flags & FM_TRAP ? trapmap: syscallmap;
+#elif EX_TRAPSTK
+ regmap = flags & EX_TRAPSTK ? trapmap : syscallmap;
+#else
+ regmap = trapmap; /* the lesser evil */
+#endif
+}
+
+/* blockend is the value of u.u_ar0, and points to the
+ * place where GS is stored
+ */
+i386_register_u_addr (blockend, regnum)
+{
+#if 0
+ /* this will be needed if fp registers are reinstated */
+ /* for now, you can look at them with 'info float'
+ * sys5 wont let you change them with ptrace anyway
+ */
+ if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
+ {
+ int ubase, fpstate;
+ struct user u;
+ ubase = blockend + 4 * (SS + 1) - KSTKSZ;
+ fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+ }
+ else
+#endif
+ return (blockend + 4 * regmap[regnum]);
+}
+
+i387_to_double (from, to)
+ char *from;
+ char *to;
+{
+ long *lp;
+ /* push extended mode on 387 stack, then pop in double mode
+ *
+ * first, set exception masks so no error is generated -
+ * number will be rounded to inf or 0, if necessary
+ */
+ asm ("pushl %eax"); /* grab a stack slot */
+ asm ("fstcw (%esp)"); /* get 387 control word */
+ asm ("movl (%esp),%eax"); /* save old value */
+ asm ("orl $0x3f,%eax"); /* mask all exceptions */
+ asm ("pushl %eax");
+ asm ("fldcw (%esp)"); /* load new value into 387 */
+
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldt (%eax)"); /* push extended number on 387 stack */
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpl (%eax)"); /* pop double */
+ asm ("fwait");
+
+ asm ("popl %eax"); /* flush modified control word */
+ asm ("fnclex"); /* clear exceptions */
+ asm ("fldcw (%esp)"); /* restore original control word */
+ asm ("popl %eax"); /* flush saved copy */
+}
+
+double_to_i387 (from, to)
+ char *from;
+ char *to;
+{
+ /* push double mode on 387 stack, then pop in extended mode
+ * no errors are possible because every 64-bit pattern
+ * can be converted to an extended
+ */
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldl (%eax)");
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpt (%eax)");
+ asm ("fwait");
+}
+
+struct env387
+{
+ unsigned short control;
+ unsigned short r0;
+ unsigned short status;
+ unsigned short r1;
+ unsigned short tag;
+ unsigned short r2;
+ unsigned long eip;
+ unsigned short code_seg;
+ unsigned short opcode;
+ unsigned long operand;
+ unsigned short operand_seg;
+ unsigned short r3;
+ unsigned char regs[8][10];
+};
+
+static
+print_387_control_word (control)
+unsigned short control;
+{
+ printf ("control 0x%04x: ", control);
+ printf ("compute to ");
+ switch ((control >> 8) & 3)
+ {
+ case 0: printf ("24 bits; "); break;
+ case 1: printf ("(bad); "); break;
+ case 2: printf ("53 bits; "); break;
+ case 3: printf ("64 bits; "); break;
+ }
+ printf ("round ");
+ switch ((control >> 10) & 3)
+ {
+ case 0: printf ("NEAREST; "); break;
+ case 1: printf ("DOWN; "); break;
+ case 2: printf ("UP; "); break;
+ case 3: printf ("CHOP; "); break;
+ }
+ if (control & 0x3f)
+ {
+ printf ("mask:");
+ if (control & 0x0001) printf (" INVALID");
+ if (control & 0x0002) printf (" DENORM");
+ if (control & 0x0004) printf (" DIVZ");
+ if (control & 0x0008) printf (" OVERF");
+ if (control & 0x0010) printf (" UNDERF");
+ if (control & 0x0020) printf (" LOS");
+ printf (";");
+ }
+ printf ("\n");
+ if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
+ control & 0xe080);
+}
+
+static
+print_387_status_word (status)
+ unsigned short status;
+{
+ printf ("status 0x%04x: ", status);
+ if (status & 0xff)
+ {
+ printf ("exceptions:");
+ if (status & 0x0001) printf (" INVALID");
+ if (status & 0x0002) printf (" DENORM");
+ if (status & 0x0004) printf (" DIVZ");
+ if (status & 0x0008) printf (" OVERF");
+ if (status & 0x0010) printf (" UNDERF");
+ if (status & 0x0020) printf (" LOS");
+ if (status & 0x0040) printf (" FPSTACK");
+ printf ("; ");
+ }
+ printf ("flags: %d%d%d%d; ",
+ (status & 0x4000) != 0,
+ (status & 0x0400) != 0,
+ (status & 0x0200) != 0,
+ (status & 0x0100) != 0);
+
+ printf ("top %d\n", (status >> 11) & 7);
+}
+
+static
+print_387_status (status, ep)
+ unsigned short status;
+ struct env387 *ep;
+{
+ int i;
+ int bothstatus;
+ int top;
+ int fpreg;
+ unsigned char *p;
+
+ bothstatus = ((status != 0) && (ep->status != 0));
+ if (status != 0)
+ {
+ if (bothstatus)
+ printf ("u: ");
+ print_387_status_word (status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word (ep->status);
+ }
+
+ print_387_control_word (ep->control);
+ printf ("last exception: ");
+ printf ("opcode 0x%x; ", ep->opcode);
+ printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
+ printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
+
+ top = (ep->status >> 11) & 7;
+
+ printf (" regno tag msb lsb value\n");
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int st_regno;
+ double val;
+
+ /* The physical regno `fpreg' is only relevant as an index into the
+ * tag word. Logical `%st' numbers are required for indexing `p->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 0x7;
+
+ printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
+
+ switch ((ep->tag >> (fpreg * 2)) & 3)
+ {
+ case 0: printf ("valid "); break;
+ case 1: printf ("zero "); break;
+ case 2: printf ("trap "); break;
+ case 3: printf ("empty "); break;
+ }
+ for (i = 9; i >= 0; i--)
+ printf ("%02x", ep->regs[st_regno][i]);
+
+ i387_to_double (ep->regs[st_regno], (char *)&val);
+ printf (" %g\n", val);
+ }
+#if 0 /* reserved fields are always 0xffff on 486's */
+ if (ep->r0)
+ printf ("warning: reserved0 is 0x%x\n", ep->r0);
+ if (ep->r1)
+ printf ("warning: reserved1 is 0x%x\n", ep->r1);
+ if (ep->r2)
+ printf ("warning: reserved2 is 0x%x\n", ep->r2);
+ if (ep->r3)
+ printf ("warning: reserved3 is 0x%x\n", ep->r3);
+#endif
+}
+
+#ifdef __386BSD__
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+#endif
+
+#ifndef U_FPSTATE
+#define U_FPSTATE(u) u.u_fpstate
+#endif
+
+i386_float_info ()
+{
+ struct user u; /* just for address computations */
+ int i;
+ /* fpstate defined in <sys/user.h> */
+ struct fpstate *fpstatep;
+ char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
+ unsigned int uaddr;
+ char fpvalid;
+ unsigned int rounded_addr;
+ unsigned int rounded_size;
+ extern int corechan;
+ int skip;
+
+#ifndef __386BSD__ /* XXX - look at pcb flags */
+ uaddr = (char *)&u.u_fpvalid - (char *)&u;
+ if (have_inferior_p())
+ {
+ unsigned int data;
+ unsigned int mask;
+
+ rounded_addr = uaddr & -sizeof (int);
+ data = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ mask = 0xff << ((uaddr - rounded_addr) * 8);
+
+ fpvalid = ((data & mask) != 0);
+ }
+ else
+ {
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror ("seek on core file");
+ if (myread (corechan, &fpvalid, 1) < 0)
+ perror ("read on core file");
+
+ }
+
+ if (fpvalid == 0)
+ {
+ printf ("no floating point status saved\n");
+ return;
+ }
+#endif /* not __386BSD__ */
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (have_inferior_p ())
+ {
+ int *ip;
+
+ rounded_addr = uaddr & -sizeof (int);
+ rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
+ sizeof (int) - 1) / sizeof (int);
+ skip = uaddr - rounded_addr;
+
+ ip = (int *)buf;
+ for (i = 0; i < rounded_size; i++)
+ {
+ *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ rounded_addr += sizeof (int);
+ }
+ }
+ else
+ {
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror_with_name ("seek on core file");
+ if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
+ perror_with_name ("read from core file");
+ skip = 0;
+ }
+
+#ifdef __386BSD__
+ print_387_status (0, (struct env387 *)buf);
+#else
+ fpstatep = (struct fpstate *)(buf + skip);
+ print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
+#endif
+}
+
+void
+_initialize_i386bsd_dep()
+{
+#ifdef KERNELDEBUG
+ add_com ("process-address", class_obscure, set_paddr_command,
+ "The process identified by (ps-style) ADDR becomes the\n\
+\"current\" process context for kernel debugging.");
+ add_com_alias ("paddr", "process-address", class_obscure, 0);
+#endif
+}
diff --git a/gnu/usr.bin/gdb/config/m-i386-sv32.h b/gnu/usr.bin/kgdb/config/m-i386-sv32.h
index 38fb4eb6d5b6..38fb4eb6d5b6 100644
--- a/gnu/usr.bin/gdb/config/m-i386-sv32.h
+++ b/gnu/usr.bin/kgdb/config/m-i386-sv32.h
diff --git a/gnu/usr.bin/gdb/config/m-i386.h b/gnu/usr.bin/kgdb/config/m-i386.h
index 5449ec454c95..5449ec454c95 100644
--- a/gnu/usr.bin/gdb/config/m-i386.h
+++ b/gnu/usr.bin/kgdb/config/m-i386.h
diff --git a/gnu/usr.bin/gdb/config/m-i386bsd.h b/gnu/usr.bin/kgdb/config/m-i386bsd.h
index 15d97b23d339..15d97b23d339 100644
--- a/gnu/usr.bin/gdb/config/m-i386bsd.h
+++ b/gnu/usr.bin/kgdb/config/m-i386bsd.h
diff --git a/gnu/usr.bin/gdb/config/m-i386g-sv32.h b/gnu/usr.bin/kgdb/config/m-i386g-sv32.h
index 3d69eea184e0..3d69eea184e0 100644
--- a/gnu/usr.bin/gdb/config/m-i386g-sv32.h
+++ b/gnu/usr.bin/kgdb/config/m-i386g-sv32.h
diff --git a/gnu/usr.bin/gdb/config/m-i386gas.h b/gnu/usr.bin/kgdb/config/m-i386gas.h
index fbd21385cc77..fbd21385cc77 100644
--- a/gnu/usr.bin/gdb/config/m-i386gas.h
+++ b/gnu/usr.bin/kgdb/config/m-i386gas.h
diff --git a/gnu/usr.bin/gdb/copying.c b/gnu/usr.bin/kgdb/copying.c
index b3d75198078e..b3d75198078e 100644
--- a/gnu/usr.bin/gdb/copying.c
+++ b/gnu/usr.bin/kgdb/copying.c
diff --git a/gnu/usr.bin/gdb/core.c b/gnu/usr.bin/kgdb/core.c
index 307addb54ae1..307addb54ae1 100644
--- a/gnu/usr.bin/gdb/core.c
+++ b/gnu/usr.bin/kgdb/core.c
diff --git a/gnu/usr.bin/gdb/cplus-dem.c b/gnu/usr.bin/kgdb/cplus-dem.c
index 8ea9c8bb55ac..8ea9c8bb55ac 100644
--- a/gnu/usr.bin/gdb/cplus-dem.c
+++ b/gnu/usr.bin/kgdb/cplus-dem.c
diff --git a/gnu/usr.bin/gdb/dbxread.c b/gnu/usr.bin/kgdb/dbxread.c
index 7a25665536a4..7a25665536a4 100644
--- a/gnu/usr.bin/gdb/dbxread.c
+++ b/gnu/usr.bin/kgdb/dbxread.c
diff --git a/gnu/usr.bin/gdb/defs.h b/gnu/usr.bin/kgdb/defs.h
index de744fce78a6..de744fce78a6 100644
--- a/gnu/usr.bin/gdb/defs.h
+++ b/gnu/usr.bin/kgdb/defs.h
diff --git a/gnu/usr.bin/gdb/environ.c b/gnu/usr.bin/kgdb/environ.c
index 022016631331..022016631331 100644
--- a/gnu/usr.bin/gdb/environ.c
+++ b/gnu/usr.bin/kgdb/environ.c
diff --git a/gnu/usr.bin/gdb/environ.h b/gnu/usr.bin/kgdb/environ.h
index 13f31f470a5e..13f31f470a5e 100644
--- a/gnu/usr.bin/gdb/environ.h
+++ b/gnu/usr.bin/kgdb/environ.h
diff --git a/gnu/usr.bin/gdb/eval.c b/gnu/usr.bin/kgdb/eval.c
index 60779e688ff4..60779e688ff4 100644
--- a/gnu/usr.bin/gdb/eval.c
+++ b/gnu/usr.bin/kgdb/eval.c
diff --git a/gnu/usr.bin/gdb/expprint.c b/gnu/usr.bin/kgdb/expprint.c
index 2c63cf8928cb..2c63cf8928cb 100644
--- a/gnu/usr.bin/gdb/expprint.c
+++ b/gnu/usr.bin/kgdb/expprint.c
diff --git a/gnu/usr.bin/gdb/expread.y b/gnu/usr.bin/kgdb/expread.y
index 96a12c48c064..96a12c48c064 100644
--- a/gnu/usr.bin/gdb/expread.y
+++ b/gnu/usr.bin/kgdb/expread.y
diff --git a/gnu/usr.bin/gdb/expression.h b/gnu/usr.bin/kgdb/expression.h
index 5a5e20e0606c..5a5e20e0606c 100644
--- a/gnu/usr.bin/gdb/expression.h
+++ b/gnu/usr.bin/kgdb/expression.h
diff --git a/gnu/usr.bin/gdb/findvar.c b/gnu/usr.bin/kgdb/findvar.c
index 0157d101e9a4..0157d101e9a4 100644
--- a/gnu/usr.bin/gdb/findvar.c
+++ b/gnu/usr.bin/kgdb/findvar.c
diff --git a/gnu/usr.bin/gdb/frame.h b/gnu/usr.bin/kgdb/frame.h
index 322ddbae04b9..322ddbae04b9 100644
--- a/gnu/usr.bin/gdb/frame.h
+++ b/gnu/usr.bin/kgdb/frame.h
diff --git a/gnu/usr.bin/gdb/getpagesize.h b/gnu/usr.bin/kgdb/getpagesize.h
index 32adae61efa2..32adae61efa2 100644
--- a/gnu/usr.bin/gdb/getpagesize.h
+++ b/gnu/usr.bin/kgdb/getpagesize.h
diff --git a/gnu/usr.bin/gdb/infcmd.c b/gnu/usr.bin/kgdb/infcmd.c
index 378784f22ba6..378784f22ba6 100644
--- a/gnu/usr.bin/gdb/infcmd.c
+++ b/gnu/usr.bin/kgdb/infcmd.c
diff --git a/gnu/usr.bin/gdb/inferior.h b/gnu/usr.bin/kgdb/inferior.h
index 04c662e4626c..04c662e4626c 100644
--- a/gnu/usr.bin/gdb/inferior.h
+++ b/gnu/usr.bin/kgdb/inferior.h
diff --git a/gnu/usr.bin/gdb/inflow.c b/gnu/usr.bin/kgdb/inflow.c
index 209fcf373458..209fcf373458 100644
--- a/gnu/usr.bin/gdb/inflow.c
+++ b/gnu/usr.bin/kgdb/inflow.c
diff --git a/gnu/usr.bin/gdb/infrun.c b/gnu/usr.bin/kgdb/infrun.c
index 887a0bb4e4cd..887a0bb4e4cd 100644
--- a/gnu/usr.bin/gdb/infrun.c
+++ b/gnu/usr.bin/kgdb/infrun.c
diff --git a/gnu/usr.bin/kgdb/kgdb.1 b/gnu/usr.bin/kgdb/kgdb.1
new file mode 100644
index 000000000000..3cc2dd9556a3
--- /dev/null
+++ b/gnu/usr.bin/kgdb/kgdb.1
@@ -0,0 +1,15 @@
+.\" Copyright (c) 1994 Paul Richards
+.TH kgdb 1 "10June94" "GNU Tools" "GNU Tools"
+.SH NAME
+kgdb \- The GDB Kernel Debugger
+.SH SYNOPSIS
+.na
+.TP
+.B kgdb
+.RB "[\|" \-help "\|]"
+.ad b
+.SH DESCRIPTION
+kgdb is the old gdb (GDB-3.5) used in FreeBSD 1.1 hardwired
+to run in kernel debugging mode since the installed gdb (GDB-4.11)
+does not support kernel debugging. For further details on gdb refer
+to the gdb man page.
diff --git a/gnu/usr.bin/kgdb/kgdb_proto.h b/gnu/usr.bin/kgdb/kgdb_proto.h
new file mode 100644
index 000000000000..ffb6e134a63d
--- /dev/null
+++ b/gnu/usr.bin/kgdb/kgdb_proto.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * @(#)kgdb_proto.h 6.3 (Berkeley) 5/8/91
+ *
+ *
+ * $Header: /home/cvs/386BSD/src/gnu/usr.bin/kgdb/kgdb_proto.h,v 1.1 1993/06/29 09:47:25 nate Exp $ (LBL)
+ */
+
+/*
+ * Message types.
+ */
+#define KGDB_MEM_R 0x01
+#define KGDB_MEM_W 0x02
+#define KGDB_REG_R 0x03
+#define KGDB_REG_W 0x04
+#define KGDB_CONT 0x05
+#define KGDB_STEP 0x06
+#define KGDB_KILL 0x07
+#define KGDB_SIGNAL 0x08
+#define KGDB_EXEC 0x09
+
+#define KGDB_CMD(x) ((x) & 0x0f)
+
+/*
+ * Message flags.
+ */
+#define KGDB_ACK 0x80
+#define KGDB_DELTA 0x40
+#define KGDB_MORE 0x20
+#define KGDB_SEQ 0x10
diff --git a/gnu/usr.bin/kgdb/main.c b/gnu/usr.bin/kgdb/main.c
new file mode 100644
index 000000000000..37b6c18ade57
--- /dev/null
+++ b/gnu/usr.bin/kgdb/main.c
@@ -0,0 +1,2236 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 6.6 (Berkeley) 5/13/91";
+#endif /* not lint */
+
+/* Top level for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can 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.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "command.h"
+#include "param.h"
+#include "expression.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <sys/file.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int original_stack_limit;
+#endif
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+extern void free ();
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/*
+ * Declare all cmd_list_element's
+ */
+
+/* Chain containing all defined commands. */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+struct cmd_list_element *setlist;
+
+/* Chain containing all defined \"set history\". */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+struct cmd_list_element *unsethistlist;
+
+/* stdio stream that command input is being read from. */
+
+FILE *instream;
+
+/* Current working directory. */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually). */
+static char dirbuf[MAXPATHLEN];
+
+#ifdef KERNELDEBUG
+/* Nonzero if we're debugging /dev/mem or a kernel crash dump */
+
+int kernel_debugging = 1;
+#endif
+
+/* Nonzero to inhibit confirmation of quitting or restarting
+ a stopped inferior. */
+int inhibit_confirm;
+
+/* Nonzero if we can write in text or core file */
+
+int writeable_text;
+
+/* The number of lines on a page, and the number of spaces
+ in a line. */
+int linesize, pagesize;
+
+/* Nonzero if we should refrain from using an X window. */
+
+int inhibit_windows = 0;
+
+/* Function to call before reading a command, if nonzero.
+ The function receives two args: an input stream,
+ and a prompt string. */
+
+void (*window_hook) ();
+
+extern int frame_file_full_name;
+int xgdb_verbose;
+
+void execute_command();
+void free_command_lines ();
+char *gdb_readline ();
+char *command_line_input ();
+static void initialize_main ();
+static void initialize_cmd_lists ();
+void command_loop ();
+static void source_command ();
+static void print_gdb_version ();
+static void float_handler ();
+static void cd_command ();
+
+char *getenv ();
+
+/* gdb prints this when reading a command interactively */
+static char *prompt;
+
+/* Buffer used for reading command lines, and the size
+ allocated for it so far. */
+
+char *line;
+int linesize;
+
+
+/* This is how `error' returns to command level. */
+
+jmp_buf to_top_level;
+
+void
+return_to_top_level ()
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+ clear_breakpoint_commands ();
+ clear_momentary_breakpoints ();
+ disable_current_display ();
+ do_cleanups (0);
+ longjmp (to_top_level, 1);
+}
+
+/* Call FUNC with arg ARG, catching any errors.
+ If there is no error, return the value returned by FUNC.
+ If there is an error, return zero after printing ERRSTRING
+ (which is in addition to the specific error message already printed). */
+
+int
+catch_errors (func, arg, errstring)
+ int (*func) ();
+ int arg;
+ char *errstring;
+{
+ jmp_buf saved;
+ int val;
+ struct cleanup *saved_cleanup_chain;
+
+ saved_cleanup_chain = save_cleanups ();
+
+ bcopy (to_top_level, saved, sizeof (jmp_buf));
+
+ if (setjmp (to_top_level) == 0)
+ val = (*func) (arg);
+ else
+ {
+ fprintf (stderr, "%s\n", errstring);
+ val = 0;
+ }
+
+ restore_cleanups (saved_cleanup_chain);
+
+ bcopy (saved, to_top_level, sizeof (jmp_buf));
+ return val;
+}
+
+/* Handler for SIGHUP. */
+
+static void
+disconnect ()
+{
+ kill_inferior_fast ();
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command).
+ Close the file opened by the command
+ and restore the previous input stream. */
+
+static void
+source_cleanup (stream)
+ FILE *stream;
+{
+ /* Instream may be 0; set to it when executing user-defined command. */
+ if (instream)
+ fclose (instream);
+ instream = stream;
+}
+
+/*
+ * Source $HOME/.gdbinit and $cwd/.gdbinit.
+ * If X is enabled, also $HOME/.xgdbinit and $cwd/.xgdbinit.source
+ */
+void
+source_init_files()
+{
+ char *homedir, initfile[256];
+ int samedir = 0;
+
+ /* Read init file, if it exists in home directory */
+ homedir = getenv ("HOME");
+ if (homedir) {
+ struct stat homebuf, cwdbuf;
+
+ sprintf(initfile, "%s/.gdbinit", homedir);
+ if (access (initfile, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (initfile);
+ if (!inhibit_windows) {
+ sprintf(initfile, "%s/.xgdbinit", homedir);
+ if (access (initfile, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (initfile);
+ }
+ /* Determine if current directory is the same as the home
+ directory, so we don't source the same file twice. */
+
+ bzero (&homebuf, sizeof (struct stat));
+ bzero (&cwdbuf, sizeof (struct stat));
+
+ stat(homedir, &homebuf);
+ stat(".", &cwdbuf);
+
+ samedir = bcmp(&homebuf, &cwdbuf, sizeof(struct stat)) == 0;
+ }
+ /* Read the input file in the current directory, *if* it isn't
+ the same file (it should exist, also). */
+ if (!samedir) {
+ if (access (".gdbinit", R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (".gdbinit");
+ if (access (".xgdbinit", R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (".xgdbinit");
+ }
+}
+
+
+int
+main (argc, argv, envp)
+ int argc;
+ char **argv;
+ char **envp;
+{
+ int count;
+ int inhibit_gdbinit = 0;
+ int quiet = 1;
+ int batch = 0;
+ register int i;
+ char *cp;
+
+ /* XXX Windows only for xgdb. */
+ char *strrchr();
+ if (cp = strrchr(argv[0], '/'))
+ ++cp;
+ else
+ cp = argv[0];
+ if (*cp != 'x')
+ inhibit_windows = 1;
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+ i = (int) &count & 0x3;
+ if (i != 0)
+ alloca (4 - i);
+#endif
+
+ quit_flag = 0;
+ linesize = 100;
+ line = (char *) xmalloc (linesize);
+ *line = 0;
+ instream = stdin;
+
+ getwd (dirbuf);
+ current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ original_stack_limit = rlim.rlim_cur;
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* Look for flag arguments. */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet"))
+ quiet = 1;
+ else if (!strcmp (argv[i], "-nx"))
+ inhibit_gdbinit = 1;
+ else if (!strcmp (argv[i], "-nw"))
+ inhibit_windows = 1;
+ else if (!strcmp (argv[i], "-batch"))
+ batch = 1, quiet = 1;
+ else if (!strcmp (argv[i], "-fullname"))
+ frame_file_full_name = 1;
+ else if (!strcmp (argv[i], "-xgdb_verbose"))
+ xgdb_verbose = 1;
+ /* -help: print a summary of command line switches. */
+ else if (!strcmp (argv[i], "-help"))
+ {
+ fputs ("\
+This is GDB, the GNU debugger. Use the command\n\
+ gdb [options] [executable [core-file]]\n\
+to enter the debugger.\n\
+\n\
+Options available are:\n\
+ -help Print this message.\n\
+ -quiet Do not print version number on startup.\n\
+ -fullname Output information used by emacs-GDB interface.\n\
+ -batch Exit after processing options.\n\
+ -nx Do not read .gdbinit file.\n\
+ -tty TTY Use TTY for input/output by the program being debugged.\n\
+ -cd DIR Change current directory to DIR.\n\
+ -directory DIR Search for source files in DIR.\n\
+ -command FILE Execute GDB commands from FILE.\n\
+ -symbols SYMFILE Read symbols from SYMFILE.\n\
+ -exec EXECFILE Use EXECFILE as the executable.\n\
+ -se FILE Use FILE as symbol file and executable file.\n\
+ -core COREFILE Analyze the core dump COREFILE.\n\
+ -w Writeable text.\n\
+ -v Print GNU message and version number on startup.\n\
+ -nc Don't confirm quit or run commands.\n\
+\n\
+For more information, type \"help\" from within GDB, or consult the\n\
+GDB manual (available as on-line info or a printed manual).\n", stderr);
+ /* Exiting after printing this message seems like
+ the most useful thing to do. */
+ exit (0);
+ }
+ else if (!strcmp (argv[i], "-w"))
+ writeable_text = 1;
+ else if (!strcmp (argv[i], "-v"))
+ quiet = 0;
+ else if (!strcmp (argv[i], "-nc"))
+ inhibit_confirm = 1;
+ else if (argv[i][0] == '-')
+ /* Other options take arguments, so don't confuse an
+ argument with an option. */
+ i++;
+ }
+
+ /* Run the init function of each source file */
+
+ initialize_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ initialize_main (); /* But that omits this file! Do it now */
+ initialize_signals ();
+
+ if (!quiet)
+ print_gdb_version ();
+
+ /* Process the command line arguments. */
+
+ count = 0;
+ for (i = 1; i < argc; i++)
+ {
+ extern void exec_file_command (), symbol_file_command ();
+ extern void core_file_command ();
+ register char *arg = argv[i];
+ /* Args starting with - say what to do with the following arg
+ as a filename. */
+ if (arg[0] == '-')
+ {
+ extern void tty_command (), directory_command ();
+
+ if (!strcmp (arg, "-q") || !strcmp (arg, "-nx")
+ || !strcmp (arg, "-quiet") || !strcmp (arg, "-batch")
+ || !strcmp (arg, "-fullname") || !strcmp (arg, "-nw")
+ || !strcmp (arg, "-xgdb_verbose")
+ || !strcmp (arg, "-help")
+ || !strcmp (arg, "-k")
+ || !strcmp (arg, "-w")
+ || !strcmp (arg, "-v")
+ || !strcmp (arg, "-nc"))
+ /* Already processed above */
+ continue;
+
+ if (++i == argc)
+ fprintf (stderr, "No argument follows \"%s\".\n", arg);
+ if (!setjmp (to_top_level))
+ {
+ /* -s foo: get syms from foo. -e foo: execute foo.
+ -se foo: do both with foo. -c foo: use foo as core dump. */
+ if (!strcmp (arg, "-se"))
+ {
+ exec_file_command (argv[i], !batch);
+ symbol_file_command (argv[i], !batch);
+ }
+ else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols"))
+ symbol_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec"))
+ exec_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-c") || !strcmp (arg, "-core"))
+ core_file_command (argv[i], !batch);
+ /* -x foo: execute commands from foo. */
+ else if (!strcmp (arg, "-x") || !strcmp (arg, "-command")
+ || !strcmp (arg, "-commands"))
+ source_command (argv[i]);
+ /* -d foo: add directory `foo' to source-file directory
+ search-list */
+ else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir")
+ || !strcmp (arg, "-directory"))
+ directory_command (argv[i], 0);
+ /* -cd FOO: specify current directory as FOO.
+ GDB remembers the precise string FOO as the dirname. */
+ else if (!strcmp (arg, "-cd"))
+ {
+ cd_command (argv[i], 0);
+ init_source_path ();
+ }
+ /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */
+ else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty"))
+ tty_command (argv[i], 0);
+
+ else
+ error ("Unknown command-line switch: \"%s\"\n", arg);
+ }
+ }
+ else
+ {
+ /* Args not thus accounted for
+ are treated as, first, the symbol/executable file
+ and, second, the core dump file. */
+ count++;
+ if (!setjmp (to_top_level))
+ switch (count)
+ {
+ case 1:
+ exec_file_command (arg, !batch);
+ symbol_file_command (arg, !batch);
+ break;
+
+ case 2:
+ core_file_command (arg, !batch);
+ break;
+
+ case 3:
+ fprintf (stderr, "Excess command line args ignored. (%s%s)\n",
+ arg, (i == argc - 1) ? "" : " ...");
+ }
+ }
+ }
+
+ if (!inhibit_gdbinit)
+ source_init_files();
+
+ if (batch)
+ {
+#if 0
+ fatal ("Attempt to read commands from stdin in batch mode.");
+#endif
+ /* We have hit the end of the batch file. */
+ exit (0);
+ }
+
+ if (!quiet)
+ printf ("Type \"help\" for a list of commands.\n");
+
+ /* The command loop. */
+
+ while (1)
+ {
+ if (!setjmp (to_top_level))
+ command_loop ();
+ if (ISATTY(stdin))
+ clearerr (stdin); /* Don't get hung if C-d is typed. */
+ else if (feof(instream)) /* Avoid endless loops for redirected stdin */
+ break;
+ }
+ exit (0);
+}
+
+
+static void
+do_nothing ()
+{
+}
+
+/* Read commands from `instream' and execute them
+ until end of file. */
+void
+command_loop ()
+{
+ struct cleanup *old_chain;
+ register int toplevel = (instream == stdin);
+ register int interactive = (toplevel && ISATTY(stdin));
+
+ while (!feof (instream))
+ {
+ register char *cmd_line;
+
+ quit_flag = 0;
+ if (interactive)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (do_nothing, 0);
+ cmd_line = command_line_input (prompt, toplevel);
+ execute_command (cmd_line, toplevel);
+ /* Do any commands attached to breakpoint we stopped at. */
+ do_breakpoint_commands ();
+ do_cleanups (old_chain);
+ }
+}
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ /* If we aren't reading from standard input, we are saving the last
+ thing read from stdin in line and don't want to delete it. Null lines
+ won't repeat here in any case. */
+ if (instream == stdin)
+ *line = 0;
+}
+
+/* Read a line from the stream "instream" without command line editing.
+
+ It prints PROMPT once at the start.
+ Action is compatible with "readline" (i.e., space for typing is
+ malloced & should be freed by caller). */
+char *
+gdb_readline (prompt)
+ char *prompt;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prompt)
+ {
+ printf (prompt);
+ fflush (stdout);
+ }
+
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ c = fgetc (instream ? instream : stdin);
+ if (c == EOF)
+ {
+ free(result);
+ return ((char *)0);
+ }
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ if (input_index >= result_size)
+ {
+ result_size <= 1;
+ result = (char *)xrealloc(result, result_size);
+ }
+ }
+ result[input_index++] = '\0';
+ return result;
+}
+
+/* Declaration for fancy readline with command line editing. */
+char *readline ();
+
+/* Variables which control command line editing and history
+ substitution. These variables are given default values at the end
+ of this file. */
+static int command_editing_p;
+static int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* Variables which are necessary for fancy command line editing. */
+char *gdb_completer_word_break_characters =
+ " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+
+/* Functions that are used as part of the fancy command line editing. */
+
+/* Generate symbol names one by one for the completer. If STATE is
+ zero, then we need to initialize, otherwise the initialization has
+ already taken place. TEXT is what we expect the symbol to start
+ with. RL_LINE_BUFFER is available to be looked at; it contains the
+ entire text of the line. RL_POINT is the offset in that line of
+ the cursor. You should pretend that the line ends at RL_POINT. */
+char *
+symbol_completion_function (text, state)
+ char *text;
+ int state;
+{
+ char **make_symbol_completion_list ();
+ static char **list = (char **)NULL;
+ static int index;
+ char *output;
+ extern char *rl_line_buffer;
+ extern int rl_point;
+ char *tmp_command, *p;
+ struct cmd_list_element *c, *result_list;
+
+ if (!state)
+ {
+ /* Free the storage used by LIST, but not by the strings inside. This is
+ because rl_complete_internal () frees the strings. */
+ if (list)
+ free (list);
+ list = 0;
+ index = 0;
+
+ /* Decide whether to complete on a list of gdb commands or on
+ symbols. */
+ tmp_command = (char *) alloca (rl_point + 1);
+ p = tmp_command;
+
+ strncpy (tmp_command, rl_line_buffer, rl_point);
+ tmp_command[rl_point] = '\0';
+
+ if (rl_point == 0)
+ {
+ /* An empty line we want to consider ambiguous; that is,
+ it could be any command. */
+ c = (struct cmd_list_element *) -1;
+ result_list = 0;
+ }
+ else
+ c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+
+ /* Move p up to the next interesting thing. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (!c)
+ /* He's typed something unrecognizable. Sigh. */
+ list = (char **) 0;
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ if (p + strlen(text) != tmp_command + rl_point)
+ error ("Unrecognized command.");
+
+ /* He's typed something ambiguous. This is easier. */
+ if (result_list)
+ list = complete_on_cmdlist (*result_list->prefixlist, text);
+ else
+ list = complete_on_cmdlist (cmdlist, text);
+ }
+ else
+ {
+ /* If we've gotten this far, gdb has recognized a full
+ command. There are several possibilities:
+
+ 1) We need to complete on the command.
+ 2) We need to complete on the possibilities coming after
+ the command.
+ 2) We need to complete the text of what comes after the
+ command. */
+
+ if (!*p && *text)
+ /* Always (might be longer versions of thie command). */
+ list = complete_on_cmdlist (result_list, text);
+ else if (!*p && !*text)
+ {
+ if (c->prefixlist)
+ list = complete_on_cmdlist (*c->prefixlist, "");
+ else
+ list = make_symbol_completion_list ("");
+ }
+ else
+ {
+ if (c->prefixlist && !c->allow_unknown)
+ {
+ *p = '\0';
+ error ("\"%s\" command requires a subcommand.",
+ tmp_command);
+ }
+ else
+ list = make_symbol_completion_list (text);
+ }
+ }
+ }
+
+ /* If the debugged program wasn't compiled with symbols, or if we're
+ clearly completing on a command and no command matches, return
+ NULL. */
+ if (!list)
+ return ((char *)NULL);
+
+ output = list[index];
+ if (output)
+ index++;
+
+ return (output);
+}
+
+
+void
+print_prompt ()
+{
+ if (prompt)
+ {
+ printf ("%s", prompt);
+ fflush (stdout);
+ }
+}
+
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+static struct termio norm_tty;
+
+static void
+suspend_sig()
+{
+ int tty = fileno(stdin);
+ struct termio cur_tty;
+
+ ioctl(tty, TCGETA, &cur_tty);
+ ioctl(tty, TCSETAW, &norm_tty);
+
+ (void) sigsetmask(0);
+ signal(SIGTSTP, SIG_DFL);
+ kill(0, SIGTSTP);
+
+ /*
+ * we've just been resumed -- current tty params become new
+ * 'normal' params (in case tset/stty was done while we were
+ * suspended). Merge values that readline might have changed
+ * into new params, then restore term mode.
+ */
+ ioctl(tty, TCGETA, &norm_tty);
+ cur_tty.c_lflag = (cur_tty.c_lflag & (ICANON|ECHO|ISIG)) |
+ (norm_tty.c_lflag &~ (ICANON|ECHO|ISIG));
+ cur_tty.c_iflag = (cur_tty.c_iflag & (IXON|ISTRIP|INPCK)) |
+ (norm_tty.c_iflag &~ (IXON|ISTRIP|INPCK));
+ ioctl(tty, TCSETAW, &cur_tty);
+
+ signal(SIGTSTP, suspend_sig);
+ print_prompt();
+
+ /*
+ * Forget about any previous command -- null line now will do
+ * nothing.
+ */
+ dont_repeat();
+}
+
+#else
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sgtty.h>
+
+static struct sgttyb norm_tty;
+static struct tchars norm_tchars;
+static struct ltchars norm_ltchars;
+static int norm_lflags;
+
+#ifdef PASS8
+#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK|PASS8)
+#else
+#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK)
+#endif
+
+static void
+suspend_sig()
+{
+ int tty = fileno(stdin);
+ struct sgttyb cur_tty;
+ struct tchars cur_tchars;
+ struct ltchars cur_ltchars;
+ int cur_lflags;
+ int cur_flags;
+
+ ioctl(tty, TIOCGETP, &cur_tty);
+ ioctl(tty, TIOCGETC, &cur_tchars);
+ ioctl(tty, TIOCLGET, &cur_lflags);
+ ioctl(tty, TIOCGLTC, &cur_ltchars);
+
+ ioctl(tty, TIOCSETP, &norm_tty);
+ ioctl(tty, TIOCSETC, &norm_tchars);
+ ioctl(tty, TIOCLSET, &norm_lflags);
+ ioctl(tty, TIOCSLTC, &norm_ltchars);
+
+ (void) sigsetmask(0);
+ signal(SIGTSTP, SIG_DFL);
+ kill(0, SIGTSTP);
+
+ /*
+ * we've just been resumed -- current tty params become new
+ * 'normal' params (in case tset/stty was done while we were
+ * suspended). Merge values that readline might have changed
+ * into new params, then restore term mode.
+ */
+ ioctl(tty, TIOCGETP, &norm_tty);
+ cur_flags = cur_tty.sg_flags;
+ cur_tty = norm_tty;
+ cur_tty.sg_flags = (cur_tty.sg_flags &~ RL_TFLAGS)
+ | (cur_flags & RL_TFLAGS);
+
+ ioctl(tty, TIOCLGET, &norm_lflags);
+#ifdef LPASS8
+ cur_lflags = (cur_lflags &~ LPASS8) | (cur_flags & LPASS8);
+#endif
+ ioctl(tty, TIOCGETC, &norm_tchars);
+ ioctl(tty, TIOCGLTC, &norm_ltchars);
+
+ ioctl(tty, TIOCSETP, &cur_tty);
+ ioctl(tty, TIOCSETC, &cur_tchars);
+ ioctl(tty, TIOCLSET, &cur_lflags);
+ ioctl(tty, TIOCSLTC, &cur_ltchars);
+
+ signal(SIGTSTP, suspend_sig);
+ print_prompt();
+
+ /*
+ * Forget about any previous command -- null line now will do
+ * nothing.
+ */
+ dont_repeat();
+}
+#endif /* HAVE_TERMIO */
+
+/* Initialize signal handlers. */
+initialize_signals ()
+{
+ extern void request_quit ();
+ int tty = fileno(stdin);
+
+ signal (SIGINT, request_quit);
+
+ /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
+ passed to the inferior, which we don't want. It would be
+ possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
+ on BSD4.3 systems using vfork, that will (apparently) affect the
+ GDB process as well as the inferior (the signal handling tables
+ being shared between the two, apparently). Since we establish
+ a handler for SIGQUIT, when we call exec it will set the signal
+ to SIG_DFL for us. */
+ signal (SIGQUIT, do_nothing);
+ if (signal (SIGHUP, do_nothing) != SIG_IGN)
+ signal (SIGHUP, disconnect);
+ signal (SIGFPE, float_handler);
+
+ ioctl(tty, TIOCGETP, &norm_tty);
+ ioctl(tty, TIOCLGET, &norm_lflags);
+ ioctl(tty, TIOCGETC, &norm_tchars);
+ ioctl(tty, TIOCGLTC, &norm_ltchars);
+ signal(SIGTSTP, suspend_sig);
+}
+
+char *
+finish_command_input(inputline, repeat, interactive)
+ register char *inputline;
+ int repeat;
+ int interactive;
+{
+ static char *do_free;
+
+ if (do_free) {
+ free(do_free);
+ do_free = NULL;
+ }
+
+ /* Do history expansion if that is wished. */
+ if (interactive && history_expansion_p) {
+ int expanded;
+
+ expanded = history_expand(inputline, &do_free);
+ if (expanded) {
+ /* Print the changes. */
+ puts(do_free);
+
+ /* An error acts like no input. */
+ if (expanded < 0) {
+ *do_free = 0;
+ return (do_free);
+ }
+ }
+ inputline = do_free;
+ }
+ /* get rid of any leading whitespace */
+ while (isspace(*inputline))
+ ++inputline;
+ /*
+ * If we just got an empty line, and that is supposed to repeat the
+ * previous command, return the value in the global buffer.
+ */
+ if (*inputline == 0) {
+ if (repeat)
+ return (line);
+ } else if (interactive)
+ add_history(inputline);
+
+ /*
+ * If line is a comment, clear it out.
+ * Note: comments are added to the command history. This is useful
+ * when you type a command, and then realize you don't want to
+ * execute it quite yet. You can comment out the command and then
+ * later fetch it from the value history and remove the '#'.
+ */
+ if (*inputline == '#')
+ *inputline = 0;
+ else if (repeat) {
+ /* Save into global buffer. */
+ register int i = strlen(inputline) + 1;
+
+ if (i > linesize) {
+ line = xrealloc(line, i);
+ linesize = i;
+ }
+ strcpy(line, inputline);
+ }
+ return (inputline);
+}
+
+static char *
+get_a_cmd_line(prompt, interactive)
+ char *prompt;
+ int interactive;
+{
+ register char *cp;
+
+ /* Control-C quits instantly if typed while reading input. */
+ immediate_quit++;
+ if (interactive && command_editing_p) {
+ extern void (*rl_event_hook)();
+
+ rl_event_hook = window_hook;
+ cp = readline(prompt);
+ } else {
+ if (interactive) {
+ if (window_hook) {
+ print_prompt();
+ (*window_hook)();
+ }
+ } else
+ prompt = NULL;
+ cp = gdb_readline(prompt);
+ }
+ --immediate_quit;
+ return (cp);
+}
+
+/* Read one line from the command input stream `instream'
+ Returns the address of the start of the line.
+
+ *If* the instream == stdin & stdin is a terminal, the line read
+ is copied into the file line saver (global var char *line,
+ length linesize) so that it can be duplicated.
+
+ This routine either uses fancy command line editing or
+ simple input as the user has requested. */
+
+char *
+command_line_input(prompt, repeat)
+ char *prompt;
+ int repeat;
+{
+ static char *do_free;
+ register int interactive = (instream == stdin && ISATTY(instream));
+ register char *cp;
+ register int i;
+
+ if (do_free) {
+ free(do_free);
+ do_free = NULL;
+ }
+ cp = get_a_cmd_line(prompt, interactive);
+
+ /*
+ * handle continued lines (this loop is not particularly
+ * efficient because it's rare).
+ */
+ while (cp && cp[i = strlen(cp) - 1] == '\\') {
+ register char *np = get_a_cmd_line(prompt, interactive);
+ register int j;
+
+ if (np == NULL) {
+ cp[i] = 0;
+ break;
+ }
+ j = strlen(np);
+ cp = xrealloc(cp, i + j + 1);
+ strcpy(cp + i, np);
+ free(np);
+ }
+ if (cp == NULL)
+ return ("");
+ do_free = cp;
+ return (finish_command_input(cp, repeat, interactive));
+}
+
+
+#define MAX_USER_ARGS 32
+
+static struct user_args {
+ struct {
+ char *arg;
+ int len;
+ } a[10];
+} uargs[MAX_USER_ARGS];
+
+static struct user_args *user_arg = uargs;
+
+static void
+arg_cleanup(ap)
+ struct user_args *ap;
+{
+ user_arg = ap;
+}
+
+/* Bind arguments $arg0, $arg1, ..., for a user defined command. */
+struct cleanup *
+setup_user_args(p)
+ char *p;
+{
+ register int i;
+ struct cleanup *old_chain = make_cleanup(arg_cleanup, user_arg);
+
+ if (++user_arg >= &uargs[MAX_USER_ARGS])
+ error("user defined functions nested too deeply\n");
+
+ bzero(user_arg, sizeof(*user_arg));
+
+ i = 0;
+ while (*p) {
+ while (isspace(*p))
+ ++p;
+ user_arg->a[i].arg = p;
+ while (*p && ! isspace(*p))
+ ++p;
+ user_arg->a[i].len = p - user_arg->a[i].arg;
+ ++i;
+ }
+ return (old_chain);
+}
+
+static char *
+findarg(str)
+ register char *str;
+{
+ register char *cp = str;
+ extern char *index();
+
+ while (cp = index(cp, '$')) {
+ if (strncmp(cp, "$arg", 4) == 0 && isdigit(cp[4]))
+ return (cp);
+ ++cp;
+ }
+ return (char *)0;
+}
+
+/* expand arguments from "line" into "new" */
+static void
+expand_args(line, new)
+ register char *line, *new;
+{
+ register char *cp = findarg(line);
+
+ while (cp = findarg(line)) {
+ int i, len;
+
+ bcopy(line, new, cp - line);
+ new += cp - line;
+ i = cp[4] - '0';
+ if (len = user_arg->a[i].len) {
+ bcopy(user_arg->a[i].arg, new, len);
+ new += len;
+ }
+ line = cp + 5;
+ }
+ strcpy(new, line);
+}
+
+/* expand any arguments in "line" then execute the result */
+static void
+expand_and_execute(line, from_tty)
+ char *line;
+ int from_tty;
+{
+ void execute_command();
+ char new[1024];
+
+ if (! findarg(line)) {
+ execute_command(line, from_tty);
+ return;
+ }
+ expand_args(line, new);
+ execute_command(new, from_tty);
+}
+
+char *
+read_one_command_line(prompt, from_tty)
+ char *prompt;
+{
+ register char *p, *p1;
+
+ dont_repeat();
+ p = command_line_input(prompt, from_tty);
+
+ /* Remove trailing blanks. */
+ p1 = p + strlen(p);
+ while (--p1 > p && (*p1 == ' ' || *p1 == '\t'))
+ ;
+ *++p1 = 0;
+ return (p);
+}
+
+static char cmd_prompt[] = " > ";
+
+int
+parse_control_structure(rootcmd, from_tty, level)
+ struct command_line *rootcmd;
+ int from_tty;
+{
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char *prompt;
+
+ ++level;
+ prompt = from_tty? &cmd_prompt[sizeof(cmd_prompt) - 1 - 2*level] :
+ (char *)0;
+ bzero(cmd, sizeof(*cmd));
+ rootcmd->body = cmd;
+ while (1) {
+ char *p = read_one_command_line(prompt, from_tty);
+
+ p = savestring(p, strlen(p));
+ cmd->line = p;
+ if (!strncmp(p, "while ", 6)) {
+ cmd->type = CL_WHILE;
+ if (parse_control_structure(cmd, from_tty, level))
+ return (1);
+ } else if (!strncmp(p, "if ", 3)) {
+ cmd->type = CL_IF;
+ if (parse_control_structure(cmd, from_tty, level)) {
+ struct command_line *tmp;
+ int stat;
+
+ cmd->elsebody = cmd->body;
+ stat = parse_control_structure(cmd, from_tty,
+ level);
+ tmp = cmd->elsebody;
+ cmd->elsebody = cmd->body;
+ cmd->body = tmp;
+ if (stat)
+ return (1);
+ }
+ } else if (!strcmp(p, "else")) {
+ cmd->type = CL_END;
+ return (1);
+ } else if (!strcmp(p, "end")) {
+ cmd->type = CL_END;
+ return (0);
+ } else if (!strcmp(p, "exitloop")) {
+ cmd->type = CL_EXITLOOP;
+ } else {
+ cmd->type = CL_NORMAL;
+ }
+ cmd->next = (struct command_line *)xmalloc(sizeof(*cmd));
+ cmd = cmd->next;
+ bzero(cmd, sizeof(*cmd));
+ }
+ /* NOTREACHED */
+}
+
+int
+execute_control_structure(cmd)
+ register struct command_line *cmd;
+{
+ char expn[1024];
+ struct expression *cond;
+ int stat;
+
+ while (cmd) {
+ QUIT;
+ switch (cmd->type) {
+ case CL_END:
+ return (0);
+ case CL_NORMAL:
+ expand_and_execute(cmd->line, 0);
+ break;
+ case CL_WHILE:
+ expand_args(cmd->line + 6, expn);
+ cond = parse_c_expression(expn);
+ while (breakpoint_cond_eval(cond) == 0)
+ if (execute_control_structure(cmd->body))
+ break;
+ free(cond);
+ break;
+ case CL_IF:
+ expand_args(cmd->line + 3, expn);
+ cond = parse_c_expression(expn);
+ stat = breakpoint_cond_eval(cond);
+ free(cond);
+ if (stat == 0) {
+ if (execute_control_structure(cmd->body))
+ return (1);
+ } else if (cmd->elsebody) {
+ if (execute_control_structure(cmd->elsebody))
+ return (1);
+ }
+ break;
+ case CL_EXITLOOP:
+ return (1);
+ }
+ cmd = cmd->next;
+ }
+ free_all_values();
+}
+
+execute_command_lines(cmd)
+ struct command_line *cmd;
+{
+ struct cleanup *old_chain = make_cleanup(source_cleanup, instream);
+
+ /*
+ * Set the instream to 0, indicating execution of a user-defined
+ * function.
+ */
+ ++immediate_quit;
+ instream = (FILE *) 0;
+ (void)execute_control_structure(cmd);
+ --immediate_quit;
+ do_cleanups(old_chain);
+}
+
+/* do following command lines if expression true */
+if_command(p, from_tty)
+ char *p;
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char buf[128];
+
+ sprintf(buf, "if %s", p);
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_IF;
+ cmd->line = savestring(buf, strlen(buf));
+ /* XXX cmd->line? */
+ if (parse_control_structure(cmd, from_tty, 0)) {
+ struct command_line *tmp;
+
+ cmd->elsebody = cmd->body;
+ (void) parse_control_structure(cmd, from_tty, 0);
+ tmp = cmd->elsebody;
+ cmd->elsebody = cmd->body;
+ cmd->body = tmp;
+ }
+ (void) execute_command_lines(cmd);
+ do_cleanups(old_chain);
+}
+
+/* do following command lines while expression true */
+while_command(p, from_tty)
+ char *p;
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char buf[128];
+
+ sprintf(buf, "while %s", p);
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_WHILE;
+ cmd->line = savestring(buf, strlen(buf));
+ (void)parse_control_structure(cmd, from_tty, 0);
+ (void)execute_command_lines(cmd);
+ do_cleanups(old_chain);
+}
+
+/*
+ * Execute the line P as a command.
+ * Pass FROM_TTY as second argument to the defining function.
+ */
+void
+execute_command (p, from_tty)
+ char *p;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register struct command_line *cmdlines;
+
+ free_all_values();
+ if (*p) {
+ c = lookup_cmd(&p, cmdlist, "", 0, 1);
+ if (c->function == 0)
+ error("That is not a command, just a help topic.");
+ else if (c->class == (int) class_user) {
+ struct cleanup *old_chain = setup_user_args(p);
+
+ cmdlines = (struct command_line *) c->function;
+ if (cmdlines)
+ (void)execute_command_lines(cmdlines);
+
+ do_cleanups(old_chain);
+ } else
+ /* Pass null arg rather than an empty one. */
+ (*c->function) (*p ? p : 0, from_tty);
+ }
+}
+
+/*
+ * Read lines from the input stream and accumulate them in a chain of struct
+ * command_line's which is then returned.
+ */
+struct command_line *
+read_command_lines(from_tty)
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ struct command_line *next;
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_NOP;
+ (void)parse_control_structure(cmd, from_tty, 0);
+ dont_repeat();
+ discard_cleanups(old_chain);
+ next = cmd->body;
+ free(cmd);
+ return (next);
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines(cmds)
+ struct command_line *cmds;
+{
+ struct command_line *next;
+
+ while (cmds) {
+ if (cmds->body)
+ free(cmds->body);
+ if (cmds->elsebody)
+ free(cmds->elsebody);
+ if (cmds->line)
+ free(cmds->line);
+ next = cmds->next;
+ free(cmds);
+ cmds = next;
+ }
+}
+
+/* Add an element to the list of info subcommands. */
+
+void
+add_info (name, fun, doc)
+ char *name;
+ void (*fun) ();
+ char *doc;
+{
+ add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands. */
+
+void
+add_info_alias (name, oldname, abbrev_flag)
+ char *name;
+ char *oldname;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+ Therefore, its own definition is called only for "info" with no args. */
+
+static void
+info_command ()
+{
+ printf ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, stdout);
+}
+
+/* Add an element to the list of commands. */
+
+void
+add_com (name, class, fun, doc)
+ char *name;
+ int class;
+ void (*fun) ();
+ char *doc;
+{
+ add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands. */
+
+void
+add_com_alias (name, oldname, class, abbrev_flag)
+ char *name;
+ char *oldname;
+ int class;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+void
+error_no_arg (why)
+ char *why;
+{
+ error ("Argument required (%s).", why);
+}
+
+static void
+help_command (command, from_tty)
+ char *command;
+ int from_tty; /* Ignored */
+{
+ help_cmd (command, stdout);
+}
+
+static void
+validate_comname (comname)
+ char *comname;
+{
+ register char *p;
+
+ if (comname == 0)
+ error_no_arg ("name of command to define");
+
+ p = comname;
+ while (*p)
+ {
+ if (!(*p >= 'A' && *p <= 'Z')
+ && !(*p >= 'a' && *p <= 'z')
+ && !(*p >= '0' && *p <= '9')
+ && *p != '-')
+ error ("Junk in argument list: \"%s\"", p);
+ p++;
+ }
+}
+
+static void
+define_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct command_line *cmds;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c)
+ {
+ if (c->class == (int) class_user || c->class == (int) class_alias)
+ tem = "Redefine command \"%s\"? ";
+ else
+ tem = "Really redefine built-in command \"%s\"? ";
+ if (!query (tem, comname))
+ error ("Command \"%s\" not redefined.", comname);
+ }
+
+ if (from_tty)
+ {
+ printf ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ fflush (stdout);
+ }
+ comname = savestring (comname, strlen (comname));
+
+ cmds = read_command_lines (from_tty);
+
+ if (c && c->class == (int) class_user)
+ free_command_lines (c->function);
+
+ add_com (comname, class_user, cmds,
+ (c && c->class == (int) class_user)
+ ? c->doc : savestring ("User-defined.", 13));
+}
+
+static void
+document_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register char *p;
+ register char *cp;
+ register char *doc = 0;
+ register int len;
+ char *tmp = comname;
+
+ validate_comname (comname);
+ c = lookup_cmd (&tmp, cmdlist, "", 0, 1);
+ if (c->class != (int) class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ if (from_tty)
+ printf ("Type documentation for \"%s\". \
+End with a line saying just \"end\".\n", comname);
+
+ while (p = read_one_command_line(from_tty? "> " : 0, from_tty))
+ {
+ if (strcmp(p, "end") == 0)
+ break;
+ len = strlen(p) + 1;
+ if (! doc)
+ {
+ doc = xmalloc(len);
+ cp = doc;
+ }
+ else
+ {
+ int i = cp - doc;
+ doc = xrealloc(doc, i + len);
+ cp = doc + i;
+ }
+ strcpy(cp, p);
+ cp += len;
+ cp[-1] = '\n';
+ }
+ if (doc && cp > doc)
+ cp[-1] = 0;
+ if (c->doc)
+ free (c->doc);
+ c->doc = doc;
+}
+
+static void
+print_gdb_version ()
+{
+ printf ("GDB %s, Copyright (C) 1989 Free Software Foundation, Inc.\n\
+There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"info copying\" to see the conditions.\n",
+ version);
+}
+
+static void
+version_info ()
+{
+ immediate_quit++;
+ print_gdb_version ();
+ immediate_quit--;
+}
+
+
+/* Command to specify a prompt string instead of "(gdb) ". */
+
+void
+set_prompt_command (text)
+ char *text;
+{
+ char *p, *q;
+ register int c;
+ char *new;
+
+ if (text == 0)
+ error_no_arg ("string to which to set prompt");
+
+ new = (char *) xmalloc (strlen (text) + 2);
+ p = text; q = new;
+ while (c = *p++)
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ break;
+ c = parse_escape (&p);
+ if (c == 0)
+ break; /* C loses */
+ else if (c > 0)
+ *q++ = c;
+ }
+ else
+ *q++ = c;
+ }
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+ *q++ = '\0';
+ new = (char *) xrealloc (new, q - new);
+ free (prompt);
+ prompt = new;
+}
+
+static void
+quit_command ()
+{
+ extern void exec_file_command ();
+ if (have_inferior_p ())
+ {
+ if (inhibit_confirm || query ("The program is running. Quit anyway? "))
+ {
+ /* Prevent any warning message from reopen_exec_file, in case
+ we have a core file that's inconsistent with the exec file. */
+ exec_file_command (0, 0);
+ kill_inferior ();
+ }
+ else
+ error ("Not confirmed.");
+ }
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
+ exit (0);
+}
+
+int
+input_from_terminal_p ()
+{
+ return instream == stdin;
+}
+
+static void
+pwd_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg) error ("The \"pwd\" command does not take an argument: %s", arg);
+ getwd (dirbuf);
+
+ if (strcmp (dirbuf, current_directory))
+ printf ("Working directory %s\n (canonically %s).\n",
+ current_directory, dirbuf);
+ else
+ printf ("Working directory %s.\n", current_directory);
+}
+
+static void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ int len;
+ int change;
+
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ dir = tilde_expand (dir);
+ make_cleanup (free, dir);
+
+ len = strlen (dir);
+ dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+ if (dir[0] == '/')
+ current_directory = dir;
+ else
+ {
+ current_directory = concat (current_directory, "/", dir);
+ free (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ change = 1;
+ while (change)
+ {
+ char *p;
+ change = 0;
+
+ for (p = current_directory; *p;)
+ {
+ if (!strncmp (p, "/./", 2)
+ && (p[2] == 0 || p[2] == '/'))
+ strcpy (p, p + 2);
+ else if (!strncmp (p, "/..", 3)
+ && (p[3] == 0 || p[3] == '/')
+ && p != current_directory)
+ {
+ char *q = p;
+ while (q != current_directory && q[-1] != '/') q--;
+ if (q != current_directory)
+ {
+ strcpy (q-1, p+3);
+ p = q-1;
+ }
+ }
+ else p++;
+ }
+ }
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+ if (from_tty)
+ pwd_command ((char *) 0, 1);
+}
+
+static void
+source_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ FILE *stream;
+ struct cleanup *cleanups;
+ char *file = arg;
+ char *path;
+
+ if (file == 0)
+ /* Let source without arguments read .gdbinit. */
+ file = ".gdbinit";
+
+ file = tilde_expand (file);
+ make_cleanup (free, file);
+
+#ifdef KERNELDEBUG
+ if (path = getenv(kernel_debugging? "KGDBPATH" : "GDBPATH"))
+#else
+ if (path = getenv("GDBPATH"))
+#endif
+ {
+ int fd = openp(path, 1, file, O_RDONLY, 0, 0);
+
+ if (fd == -1)
+ stream = 0;
+ else
+ stream = fdopen(fd, "r");
+ }
+ else
+ stream = fopen (file, "r");
+
+ if (stream == 0)
+ perror_with_name (file);
+
+ cleanups = make_cleanup (source_cleanup, instream);
+
+ instream = stream;
+
+ command_loop ();
+
+ do_cleanups (cleanups);
+}
+
+static void
+echo_command (text)
+ char *text;
+{
+ char *p = text;
+ register int c;
+
+ if (text)
+ while (c = *p++)
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ return;
+
+ c = parse_escape (&p);
+ if (c >= 0)
+ fputc (c, stdout);
+ }
+ else
+ fputc (c, stdout);
+ }
+ fflush(stdout);
+}
+
+static void
+dump_me_command ()
+{
+ if (query ("Should GDB dump core? "))
+ {
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ }
+}
+
+int
+parse_binary_operation (caller, arg)
+ char *caller, *arg;
+{
+ int length;
+
+ if (!arg || !*arg)
+ return 1;
+
+ length = strlen (arg);
+
+ while (arg[length - 1] == ' ' || arg[length - 1] == '\t')
+ length--;
+
+ if (!strncmp (arg, "on", length)
+ || !strncmp (arg, "1", length)
+ || !strncmp (arg, "yes", length))
+ return 1;
+ else
+ if (!strncmp (arg, "off", length)
+ || !strncmp (arg, "0", length)
+ || !strncmp (arg, "no", length))
+ return 0;
+ else
+ error ("\"%s\" not given a binary valued argument.", caller);
+}
+
+/* Functions to manipulate command line editing control variables. */
+
+static void
+set_editing (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ command_editing_p = parse_binary_operation ("set command-editing", arg);
+}
+
+/* Number of commands to print in each call to editing_info. */
+#define Hist_print 10
+static void
+editing_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* Index for history commands. Relative to history_base. */
+ int offset;
+
+ /* Number of the history entry which we are planning to display next.
+ Relative to history_base. */
+ static int num = 0;
+
+ /* The first command in the history which doesn't exist (i.e. one more
+ than the number of the last command). Relative to history_base. */
+ int hist_len;
+
+ struct _hist_entry {
+ char *line;
+ char *data;
+ } *history_get();
+ extern int history_base;
+
+ printf_filtered ("Interactive command editing is %s.\n",
+ command_editing_p ? "on" : "off");
+
+ printf_filtered ("History expansion of command input is %s.\n",
+ history_expansion_p ? "on" : "off");
+ printf_filtered ("Writing of a history record upon exit is %s.\n",
+ write_history_p ? "enabled" : "disabled");
+ printf_filtered ("The size of the history list (number of stored commands) is %d.\n",
+ history_size);
+ printf_filtered ("The name of the history record is \"%s\".\n\n",
+ history_filename ? history_filename : "");
+
+ /* Print out some of the commands from the command history. */
+ /* First determine the length of the history list. */
+ hist_len = history_size;
+ for (offset = 0; offset < history_size; offset++)
+ {
+ if (!history_get (history_base + offset))
+ {
+ hist_len = offset;
+ break;
+ }
+ }
+
+ if (arg)
+ {
+ if (arg[0] == '+' && arg[1] == '\0')
+ /* "info editing +" should print from the stored position. */
+ ;
+ else
+ /* "info editing <exp>" should print around command number <exp>. */
+ num = (parse_and_eval_address (arg) - history_base) - Hist_print / 2;
+ }
+ /* "info editing" means print the last Hist_print commands. */
+ else
+ {
+ num = hist_len - Hist_print;
+ }
+
+ if (num < 0)
+ num = 0;
+
+ /* If there are at least Hist_print commands, we want to display the last
+ Hist_print rather than, say, the last 6. */
+ if (hist_len - num < Hist_print)
+ {
+ num = hist_len - Hist_print;
+ if (num < 0)
+ num = 0;
+ }
+
+ if (num == hist_len - Hist_print)
+ printf_filtered ("The list of the last %d commands is:\n\n", Hist_print);
+ else
+ printf_filtered ("Some of the stored commands are:\n\n");
+
+ for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
+ {
+ printf_filtered ("%5d %s\n", history_base + offset,
+ (history_get (history_base + offset))->line);
+ }
+
+ /* The next command we want to display is the next one that we haven't
+ displayed yet. */
+ num += Hist_print;
+
+ /* If the user repeats this command with return, it should do what
+ "info editing +" does. This is unnecessary if arg is null,
+ because "info editing +" is not useful after "info editing". */
+ if (from_tty && arg)
+ {
+ arg[0] = '+';
+ arg[1] = '\0';
+ }
+}
+
+static void
+set_history_expansion (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ history_expansion_p = parse_binary_operation ("set history expansion", arg);
+}
+
+static void
+set_history_write (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ write_history_p = parse_binary_operation ("set history write", arg);
+}
+
+static void
+set_history (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, stdout);
+}
+
+static void
+set_history_size (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!*arg)
+ error_no_arg ("set history size");
+
+ history_size = atoi (arg);
+}
+
+static void
+set_history_filename (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ int i;
+
+ if (!arg)
+ error_no_arg ("history file name");
+
+ arg = tilde_expand (arg);
+ make_cleanup (free, arg);
+
+ i = strlen (arg) - 1;
+
+ free (history_filename);
+
+ while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
+ i--;
+ ++i;
+
+ if (!*arg)
+ history_filename = (char *) 0;
+ else
+ history_filename = savestring (arg, i + 1);
+ history_filename[i] = '\0';
+}
+
+int info_verbose;
+
+static void
+set_verbose_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ info_verbose = parse_binary_operation ("set verbose", arg);
+}
+
+static void
+verbose_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info verbose\" does not take any arguments.\n");
+
+ printf ("Verbose printing of information is %s.\n",
+ info_verbose ? "on" : "off");
+}
+
+static void
+float_handler ()
+{
+ error ("Invalid floating value encountered or computed.");
+}
+
+
+static void
+initialize_cmd_lists ()
+{
+ cmdlist = (struct cmd_list_element *) 0;
+ infolist = (struct cmd_list_element *) 0;
+ enablelist = (struct cmd_list_element *) 0;
+ disablelist = (struct cmd_list_element *) 0;
+ deletelist = (struct cmd_list_element *) 0;
+ enablebreaklist = (struct cmd_list_element *) 0;
+ setlist = (struct cmd_list_element *) 0;
+ sethistlist = (struct cmd_list_element *) 0;
+ unsethistlist = (struct cmd_list_element *) 0;
+}
+
+static void
+initialize_main ()
+{
+ char *tmpenv;
+ /* Command line editing externals. */
+ extern int (*rl_completion_entry_function)();
+ extern char *rl_completer_word_break_characters;
+ extern char *rl_readline_name;
+
+ /* Set default verbose mode on. */
+ info_verbose = 1;
+
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ prompt = savestring ("(kgdb) ", 7);
+ else
+#endif
+ prompt = savestring ("(gdb) ", 6);
+
+ /* Set the important stuff up for command editing. */
+ command_editing_p = 1;
+ history_expansion_p = 0;
+ write_history_p = 0;
+
+ if (tmpenv = getenv ("HISTSIZE"))
+ history_size = atoi (tmpenv);
+ else
+ history_size = 256;
+
+ stifle_history (history_size);
+
+ if (tmpenv = getenv ("GDBHISTFILE"))
+ history_filename = savestring (tmpenv, strlen(tmpenv));
+ else
+ /* We include the current directory so that if the user changes
+ directories the file written will be the same as the one
+ that was read. */
+ history_filename = concat (current_directory, "/.gdb_history", "");
+
+ read_history (history_filename);
+
+ /* Setup important stuff for command line editing. */
+ rl_completion_entry_function = (int (*)()) symbol_completion_function;
+ rl_completer_word_break_characters = gdb_completer_word_break_characters;
+ rl_readline_name = "gdb";
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist);
+ add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user", class_user, 0, "User-defined commands.\n\
+The commands in this class are those defined by the user.\n\
+Use the \"define\" command to define a command.", &cmdlist);
+ add_cmd ("support", class_support, 0, "Support facilities.", &cmdlist);
+ add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, 0, "Examining the stack.\n\
+The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
+counting from zero for the innermost (currently executing) frame.\n\n\
+At any time gdb identifies one frame as the \"selected\" frame.\n\
+Variable lookups are done with respect to the selected frame.\n\
+When the program being debugged stops, gdb selects the innermost frame.\n\
+The commands below can be used to select other frames by number or address.",
+ &cmdlist);
+ add_cmd ("running", class_run, 0, "Running the program.", &cmdlist);
+
+ add_com ("pwd", class_files, pwd_command,
+ "Print working directory. This is used for your program as well.");
+ add_com ("cd", class_files, cd_command,
+ "Set working directory to DIR for debugger and program being debugged.\n\
+The change does not take effect for the program being debugged\n\
+until the next time it is started.");
+
+ add_cmd ("prompt", class_support, set_prompt_command,
+ "Change gdb's prompt from the default of \"(gdb)\"",
+ &setlist);
+ add_com ("echo", class_support, echo_command,
+ "Print a constant string. Give string as argument.\n\
+C escape sequences may be used in the argument.\n\
+No newline is added at the end of the argument;\n\
+use \"\\n\" if you want a newline to be printed.\n\
+Since leading and trailing whitespace are ignored in command arguments,\n\
+if you want to print some you must use \"\\\" before leading whitespace\n\
+to be printed or after trailing whitespace.");
+ add_com ("document", class_support, document_command,
+ "Document a user-defined command.\n\
+Give command name as argument. Give documentation on following lines.\n\
+End with a line of just \"end\".");
+ add_com ("define", class_support, define_command,
+ "Define a new command name. Command name is argument.\n\
+Definition appears on following lines, one command per line.\n\
+End with a line of just \"end\".\n\
+Use the \"document\" command to give documentation for the new command.\n\
+Commands defined in this way do not take arguments.");
+
+ add_com ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \".gdbinit\" is read automatically in this way\n\
+when gdb is started.");
+ add_com ("quit", class_support, quit_command, "Exit gdb.");
+ add_com ("help", class_support, help_command, "Print list of commands.");
+ add_com_alias ("q", "quit", class_support, 1);
+ add_com_alias ("h", "help", class_support, 1);
+ add_com ("while", class_support, while_command,
+ "execute following commands while condition is true.\n\
+Expression for condition follows \"while\" keyword.");
+ add_com ("if", class_support, if_command,
+ "execute following commands if condition is true.\n\
+Expression for condition follows \"if\" keyword.");
+ add_cmd ("verbose", class_support, set_verbose_command,
+ "Change the number of informational messages gdb prints.",
+ &setlist);
+ add_info ("verbose", verbose_info,
+ "Status of gdb's verbose printing option.\n");
+
+ add_com ("dump-me", class_obscure, dump_me_command,
+ "Get fatal error; make debugger dump its core.");
+
+ add_cmd ("editing", class_support, set_editing,
+ "Enable or disable command line editing.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled.", &setlist);
+
+ add_prefix_cmd ("history", class_support, set_history,
+ "Generic command for setting command history parameters.",
+ &sethistlist, "set history ", 0, &setlist);
+
+ add_cmd ("expansion", no_class, set_history_expansion,
+ "Enable or disable history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist);
+
+ add_cmd ("write", no_class, set_history_write,
+ "Enable or disable saving of the history record on exit.\n\
+Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
+Without an argument, saving is enabled.", &sethistlist);
+
+ add_cmd ("size", no_class, set_history_size,
+ "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+
+ add_cmd ("filename", no_class, set_history_filename,
+ "Set the filename in which to record the command history\n\
+ (the list of previous commands of which a record is kept).", &sethistlist);
+
+ add_prefix_cmd ("info", class_info, info_command,
+ "Generic command for printing status.",
+ &infolist, "info ", 0, &cmdlist);
+ add_com_alias ("i", "info", class_info, 1);
+
+ add_info ("editing", editing_info, "Status of command editor.");
+
+ add_info ("version", version_info, "Report what version of GDB this is.");
+}
diff --git a/gnu/usr.bin/gdb/ngdb.i386/Makefile b/gnu/usr.bin/kgdb/ngdb.i386/Makefile
index 3bf4c6c94929..3bf4c6c94929 100644
--- a/gnu/usr.bin/gdb/ngdb.i386/Makefile
+++ b/gnu/usr.bin/kgdb/ngdb.i386/Makefile
diff --git a/gnu/usr.bin/gdb/obstack.c b/gnu/usr.bin/kgdb/obstack.c
index 6f4b282d1e7a..6f4b282d1e7a 100644
--- a/gnu/usr.bin/gdb/obstack.c
+++ b/gnu/usr.bin/kgdb/obstack.c
diff --git a/gnu/usr.bin/gdb/obstack.h b/gnu/usr.bin/kgdb/obstack.h
index 27c017e2f253..27c017e2f253 100644
--- a/gnu/usr.bin/gdb/obstack.h
+++ b/gnu/usr.bin/kgdb/obstack.h
diff --git a/gnu/usr.bin/gdb/printcmd.c b/gnu/usr.bin/kgdb/printcmd.c
index 6edd7bd2c2f3..6edd7bd2c2f3 100644
--- a/gnu/usr.bin/gdb/printcmd.c
+++ b/gnu/usr.bin/kgdb/printcmd.c
diff --git a/gnu/usr.bin/gdb/regex.c b/gnu/usr.bin/kgdb/regex.c
index 45c34780f6c2..45c34780f6c2 100644
--- a/gnu/usr.bin/gdb/regex.c
+++ b/gnu/usr.bin/kgdb/regex.c
diff --git a/gnu/usr.bin/gdb/regex.h b/gnu/usr.bin/kgdb/regex.h
index d0d8a82835b6..d0d8a82835b6 100644
--- a/gnu/usr.bin/gdb/regex.h
+++ b/gnu/usr.bin/kgdb/regex.h
diff --git a/gnu/usr.bin/gdb/remote-sl.c b/gnu/usr.bin/kgdb/remote-sl.c
index 4c72197f1ae1..4c72197f1ae1 100644
--- a/gnu/usr.bin/gdb/remote-sl.c
+++ b/gnu/usr.bin/kgdb/remote-sl.c
diff --git a/gnu/usr.bin/kgdb/remote.c b/gnu/usr.bin/kgdb/remote.c
new file mode 100644
index 000000000000..e8bc8c85b581
--- /dev/null
+++ b/gnu/usr.bin/kgdb/remote.c
@@ -0,0 +1,626 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * $Header: /home/cvs/386BSD/src/gnu/usr.bin/kgdb/remote.c,v 1.1 1993/06/29 09:47:34 nate Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+#include "param.h"
+
+#include <stdio.h>
+#include <varargs.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "wait.h"
+
+#include "kgdb_proto.h"
+
+static FILE *kiodebug;
+static int icache = 1;
+extern int kernel_debugging;
+
+static int remote_cache_valid;
+static int remote_instub;
+
+static void remote_signal();
+static void remote_debug();
+static void print_msg();
+
+static int remote_mtu;
+static int (*send_msg)();
+static int (*recv_msg)();
+static void (*closelink)();
+
+static u_char *inbuffer;
+static u_char *outbuffer;
+
+/*
+ * Statistics.
+ */
+static int remote_ierrs;
+static int remote_oerrs;
+static int remote_seqerrs;
+static int remote_spurious;
+
+#define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0)
+
+/*
+ * Send an outbound message to the remote machine and read the reply.
+ * Either or both message buffers may be NULL.
+ */
+static int
+m_xchg(type, out, outlen, in, inlen)
+ int type;
+ u_char *out;
+ int outlen;
+ u_char *in;
+ int *inlen;
+{
+ register int err, (*send)() = send_msg, (*recv)() = recv_msg;
+ int ack;
+ static int seqbit = 0;
+
+ if (!remote_instub) {
+ remote_instub = 1;
+ PUTCMD(KGDB_EXEC);
+ }
+
+ seqbit ^= KGDB_SEQ;
+ while (1) {
+ err = (*send)(type | seqbit, out, outlen);
+ if (err) {
+ ++remote_oerrs;
+ if (kiodebug)
+ remote_debug("send error %d\n", err);
+ }
+ if (kiodebug)
+ print_msg(type | seqbit, out, outlen, 'O');
+
+ recv:
+ err = (*recv)(&ack, in, inlen);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("recv error %d\n", err);
+ remote_cache_valid = 0;
+ } else if (kiodebug)
+ print_msg(ack, in, inlen ? *inlen : 0, 'I');
+
+ if (err)
+ continue;
+
+ if ((ack & KGDB_ACK) == 0 || KGDB_CMD(ack) != KGDB_CMD(type)) {
+ ++remote_spurious;
+ continue;
+ }
+ if ((ack & KGDB_SEQ) ^ seqbit) {
+ ++remote_seqerrs;
+ goto recv;
+ }
+ return ack;
+ }
+}
+
+/*
+ * Wait for the specified message type. Discard anything else.
+ * (this is used by 'remote-signal' to help us resync with other side.)
+ */
+static void
+m_recv(type, in, inlen)
+ int type;
+ u_char *in;
+ int *inlen;
+{
+ int reply, err;
+
+ while (1) {
+ err = (*recv_msg)(&reply, in, inlen);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("recv error %d\n", err);
+ } else if (kiodebug)
+ print_msg(reply, in, inlen ? *inlen : 0, 'I');
+
+ if (KGDB_CMD(reply) == type)
+ return;
+ ++remote_spurious;
+ }
+}
+
+/*
+ * Send a message. Do not wait for *any* response from the other side.
+ * Some other thread of control will pick up the ack that will be generated.
+ */
+static void
+m_send(type, buf, len)
+ int type;
+ u_char *buf;
+ int len;
+{
+ int err;
+
+ if (!remote_instub) {
+ remote_instub = 1;
+ PUTCMD(KGDB_EXEC);
+ }
+
+ err = (*send_msg)(type, buf, len);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("[send error %d] ", err);
+ }
+ if (kiodebug)
+ print_msg(type, buf, len, 'O');
+}
+
+/*
+ * Open a connection to a remote debugger.
+ * NAME is the filename used for communication.
+ */
+void
+remote_open(name, from_tty)
+ char *name;
+ int from_tty;
+{
+ int bufsize;
+
+ remote_debugging = 0;
+ if (sl_open(name, &send_msg, &recv_msg, &closelink, &remote_mtu,
+ &bufsize))
+ return;
+ if (from_tty)
+ printf("Remote debugging using %s\n", name);
+ remote_debugging = 1;
+
+ remote_cache_valid = 0;
+
+ inbuffer = (u_char *)malloc(bufsize);
+ outbuffer = (u_char *)malloc(bufsize);
+
+ remote_signal();
+
+ remote_ierrs = 0;
+ remote_oerrs = 0;
+ remote_spurious = 0;
+}
+
+/*
+ * Close the open connection to the remote debugger. Use this when you want
+ * to detach and do something else with your gdb.
+ */
+void
+remote_close(from_tty)
+ int from_tty;
+{
+ if (!remote_debugging)
+ error("remote debugging not enabled");
+
+ remote_debugging = 0;
+ /*
+ * Take remote machine out of debug mode.
+ */
+ (void)PUTCMD(KGDB_KILL);
+ (*closelink)();
+ if (from_tty)
+ printf("Ending remote debugging\n");
+
+ free((char *)inbuffer);
+ free((char *)outbuffer);
+}
+
+/*
+ * Tell the remote machine to resume.
+ */
+int
+remote_resume(step, signal)
+ int step, signal;
+{
+ if (!step) {
+ (void)PUTCMD(KGDB_CONT);
+ remote_instub = 0;
+ } else {
+#ifdef NO_SINGLE_STEP
+ single_step(0);
+#else
+ (void)PUTCMD(KGDB_STEP);
+#endif
+ }
+}
+
+/*
+ * Wait until the remote machine stops, then return, storing status in STATUS
+ * just as `wait' would.
+ */
+int
+remote_wait(status)
+ WAITTYPE *status;
+{
+ int len;
+
+ WSETEXIT((*status), 0);
+ /*
+ * When the machine stops, it will send us a KGDB_SIGNAL message,
+ * so we wait for one of these.
+ */
+ m_recv(KGDB_SIGNAL, inbuffer, &len);
+ WSETSTOP((*status), inbuffer[0]);
+}
+
+/*
+ * Register context as of last remote_fetch_registers().
+ */
+static char reg_cache[REGISTER_BYTES];
+
+/*
+ * Read the remote registers into the block REGS.
+ */
+void
+remote_fetch_registers(regs)
+ char *regs;
+{
+ int regno, len, rlen, ack;
+ u_char *cp, *ep;
+
+ regno = -1;
+ do {
+ outbuffer[0] = regno + 1;
+ ack = m_xchg(remote_cache_valid ?
+ KGDB_REG_R|KGDB_DELTA : KGDB_REG_R,
+ outbuffer, 1, inbuffer, &len);
+ cp = inbuffer;
+ ep = cp + len;
+ while (cp < ep) {
+ regno = *cp++;
+ rlen = REGISTER_RAW_SIZE(regno);
+ bcopy((char *)cp,
+ &reg_cache[REGISTER_BYTE(regno)], rlen);
+ cp += rlen;
+ }
+ } while (ack & KGDB_MORE);
+
+ remote_cache_valid = 1;
+ bcopy(reg_cache, regs, REGISTER_BYTES);
+}
+
+/*
+ * Store the remote registers from the contents of the block REGS.
+ */
+void
+remote_store_registers(regs)
+ char *regs;
+{
+ u_char *cp, *ep;
+ int regno, off, rlen;
+
+ cp = outbuffer;
+ ep = cp + remote_mtu;
+
+ for (regno = 0; regno < NUM_REGS; ++regno) {
+ off = REGISTER_BYTE(regno);
+ rlen = REGISTER_RAW_SIZE(regno);
+ if (!remote_cache_valid ||
+ bcmp(&regs[off], &reg_cache[off], rlen) != 0) {
+ if (cp + rlen + 1 >= ep) {
+ (void)m_xchg(KGDB_REG_W,
+ outbuffer, cp - outbuffer,
+ (u_char *)0, (int *)0);
+ cp = outbuffer;
+ }
+ *cp++ = regno;
+ bcopy(&regs[off], cp, rlen);
+ cp += rlen;
+ }
+ }
+ if (cp != outbuffer)
+ (void)m_xchg(KGDB_REG_W, outbuffer, cp - outbuffer,
+ (u_char *)0, (int *)0);
+ bcopy(regs, reg_cache, REGISTER_BYTES);
+}
+
+/*
+ * Store a chunk of memory into the remote host.
+ * 'remote_addr' is the address in the remote memory space.
+ * 'cp' is the address of the buffer in our space, and 'len' is
+ * the number of bytes. Returns an errno status.
+ */
+int
+remote_write_inferior_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ u_char *cp;
+ int len;
+{
+ int cnt;
+
+ while (len > 0) {
+ cnt = min(len, remote_mtu - 4);
+ bcopy((char *)&remote_addr, outbuffer, 4);
+ bcopy(cp, outbuffer + 4, cnt);
+ (void)m_xchg(KGDB_MEM_W, outbuffer, cnt + 4, inbuffer, &len);
+
+ if (inbuffer[0])
+ return inbuffer[0];
+
+ remote_addr += cnt;
+ cp += cnt;
+ len -= cnt;
+ }
+ return 0;
+}
+
+/*
+ * Read memory data directly from the remote machine.
+ * 'remote_addr' is the address in the remote memory space.
+ * 'cp' is the address of the buffer in our space, and 'len' is
+ * the number of bytes. Returns an errno status.
+ */
+static int
+remote_read_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ u_char *cp;
+ int len;
+{
+ int cnt, inlen;
+
+ while (len > 0) {
+ cnt = min(len, remote_mtu - 1);
+ outbuffer[0] = cnt;
+ bcopy((char *)&remote_addr, (char *)&outbuffer[1], 4);
+
+ (void)m_xchg(KGDB_MEM_R, outbuffer, 5, inbuffer, &inlen);
+
+ if (inbuffer[0] != 0)
+ return inbuffer[0];
+
+ if (cnt != inlen - 1)
+ /* XXX */
+ error("remote_read_memory() request botched");
+
+ bcopy((char *)&inbuffer[1], (char *)cp, cnt);
+
+ remote_addr += cnt;
+ cp += cnt;
+ len -= cnt;
+ }
+ return 0;
+}
+
+int
+remote_read_inferior_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ char *cp;
+ int len;
+{
+ int stat = 0;
+
+ if (icache) {
+ extern CORE_ADDR text_start, text_end;
+ CORE_ADDR xferend = remote_addr + len;
+
+ if (remote_addr < text_end && text_start < xferend) {
+ /*
+ * at least part of this xfer is in the text
+ * space -- xfer the overlap from the exec file.
+ */
+ if (remote_addr >= text_start && xferend < text_end)
+ return (xfer_core_file(remote_addr, cp, len));
+ if (remote_addr >= text_start) {
+ int i = text_end - remote_addr;
+
+ if (stat = xfer_core_file(remote_addr, cp, i))
+ return (stat);
+ remote_addr += i;
+ cp += i;
+ len -= i;
+ } else if (xferend <= text_end) {
+ int i = xferend - text_start;
+
+ len = text_start - remote_addr;
+ if (stat = xfer_core_file(text_start,
+ cp + len, i))
+ return (stat);
+ }
+ }
+ }
+ return remote_read_memory(remote_addr, cp, len);
+}
+
+/*
+ * Signal the remote machine. The remote end might be idle or it might
+ * already be in debug mode -- we need to handle both case. Thus, we use
+ * the framing character as the wakeup byte, and send a SIGNAL packet.
+ * If the remote host is idle, the framing character will wake it up.
+ * If it is in the kgdb stub, then we will get a SIGNAL reply.
+ */
+static void
+remote_signal()
+{
+ if (!remote_debugging)
+ printf("Remote debugging not enabled.\n");
+ else {
+ remote_instub = 0;
+ m_send(KGDB_SIGNAL, (u_char *)0, 0);
+ }
+}
+
+static void
+remote_signal_command()
+{
+ extern int stop_after_attach;
+
+ if (!remote_debugging)
+ error("Not debugging remote.");
+ remote_cache_valid = 0;
+ remote_signal();
+ restart_remote();
+}
+
+/*
+ * Print a message for debugging.
+ */
+static void
+print_msg(type, buf, len, dir)
+ int type;
+ u_char *buf;
+ int len;
+ int dir;
+{
+ int i;
+ char *s;
+
+ switch (KGDB_CMD(type)) {
+ case KGDB_MEM_R: s = "memr"; break;
+ case KGDB_MEM_W: s = "memw"; break;
+ case KGDB_REG_R: s = "regr"; break;
+ case KGDB_REG_W: s = "regw"; break;
+ case KGDB_CONT: s = "cont"; break;
+ case KGDB_STEP: s = "step"; break;
+ case KGDB_KILL: s = "kill"; break;
+ case KGDB_SIGNAL: s = "sig "; break;
+ case KGDB_EXEC: s = "exec"; break;
+ default: s = "unk "; break;
+ }
+ remote_debug("%c %c%c%c%c %s (%02x): ", dir,
+ (type & KGDB_ACK) ? 'A' : '.',
+ (type & KGDB_DELTA) ? 'D' : '.',
+ (type & KGDB_MORE) ? 'M' : '.',
+ (type & KGDB_SEQ) ? '-' : '+',
+ s, type);
+ if (buf)
+ for (i = 0; i < len; ++i)
+ remote_debug("%02x", buf[i]);
+ remote_debug("\n");
+}
+
+static void
+set_remote_text_refs_command(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ icache = !parse_binary_operation("set remote-text-refs", arg);
+}
+
+static void
+remote_debug_command(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *name;
+
+ if (kiodebug != 0 && kiodebug != stderr)
+ (void)fclose(kiodebug);
+
+ if (arg == 0) {
+ kiodebug = 0;
+ printf("Remote debugging off.\n");
+ return;
+ }
+ if (arg[0] == '-') {
+ kiodebug = stderr;
+ name = "stderr";
+ } else {
+ kiodebug = fopen(arg, "w");
+ if (kiodebug == 0) {
+ printf("Cannot open '%s'.\n", arg);
+ return;
+ }
+ name = arg;
+ }
+ printf("Remote debugging output routed to %s.\n", name);
+}
+
+/* ARGSUSED */
+static void
+remote_info(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf("Using %s for text references.\n",
+ icache? "local executable" : "remote");
+ printf("Protocol debugging is %s.\n", kiodebug? "on" : "off");
+ printf("%d spurious input messages.\n", remote_spurious);
+ printf("%d input errors; %d output errors; %d sequence errors.\n",
+ remote_ierrs, remote_oerrs, remote_seqerrs);
+}
+
+/* VARARGS */
+static void
+remote_debug(va_alist)
+ va_dcl
+{
+ register char *cp;
+ va_list ap;
+
+ va_start(ap);
+ cp = va_arg(ap, char *);
+ (void)vfprintf(kiodebug, cp, ap);
+ va_end(ap);
+ fflush(kiodebug);
+}
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_remote()
+{
+ add_com("remote-signal", class_run, remote_signal_command,
+ "If remote debugging, send interrupt signal to remote.");
+ add_cmd("remote-text-refs", class_support,
+ set_remote_text_refs_command,
+"Enable/disable use of local executable for text segment references.\n\
+If on, all memory read/writes go to remote.\n\
+If off, text segment reads use the local executable.",
+ &setlist);
+
+ add_com("remote-debug", class_run, remote_debug_command,
+"With a file name argument, enables output of remote protocol debugging\n\
+messages to said file. If file is `-', stderr is used.\n\
+With no argument, remote debugging is disabled.");
+
+ add_info("remote", remote_info,
+ "Show current settings of remote debugging options.");
+}
+
diff --git a/gnu/usr.bin/gdb/source.c b/gnu/usr.bin/kgdb/source.c
index bb65e1ca9483..bb65e1ca9483 100644
--- a/gnu/usr.bin/gdb/source.c
+++ b/gnu/usr.bin/kgdb/source.c
diff --git a/gnu/usr.bin/gdb/stab.def b/gnu/usr.bin/kgdb/stab.def
index b81cda4bdc31..b81cda4bdc31 100644
--- a/gnu/usr.bin/gdb/stab.def
+++ b/gnu/usr.bin/kgdb/stab.def
diff --git a/gnu/usr.bin/gdb/stack.c b/gnu/usr.bin/kgdb/stack.c
index 91218aae3656..91218aae3656 100644
--- a/gnu/usr.bin/gdb/stack.c
+++ b/gnu/usr.bin/kgdb/stack.c
diff --git a/gnu/usr.bin/gdb/symmisc.c b/gnu/usr.bin/kgdb/symmisc.c
index bb4eb50674d6..bb4eb50674d6 100644
--- a/gnu/usr.bin/gdb/symmisc.c
+++ b/gnu/usr.bin/kgdb/symmisc.c
diff --git a/gnu/usr.bin/gdb/symseg.h b/gnu/usr.bin/kgdb/symseg.h
index 6a61a1791a20..6a61a1791a20 100644
--- a/gnu/usr.bin/gdb/symseg.h
+++ b/gnu/usr.bin/kgdb/symseg.h
diff --git a/gnu/usr.bin/kgdb/symtab.c b/gnu/usr.bin/kgdb/symtab.c
new file mode 100644
index 000000000000..96b4beb84e6d
--- /dev/null
+++ b/gnu/usr.bin/kgdb/symtab.c
@@ -0,0 +1,2473 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * $Header: /home/cvs/386BSD/src/gnu/usr.bin/kgdb/symtab.c,v 1.2 1993/12/01 16:44:43 ats Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)symtab.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Symbol table lookup for the GNU debugger, GDB.
+ Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can 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.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+
+#include <obstack.h>
+#include <assert.h>
+
+char *index ();
+extern char *cplus_demangle ();
+extern struct value * value_of_this ();
+
+/* Allocate an obstack to hold objects that should be freed
+ when we load a new symbol table.
+ This includes the symbols made by dbxread
+ and the types that are not permanent. */
+
+struct obstack obstack1;
+
+struct obstack *symbol_obstack = &obstack1;
+
+/* This obstack will be used for partial_symbol objects. It can
+ probably actually be the same as the symbol_obstack above, but I'd
+ like to keep them seperate for now. If I want to later, I'll
+ replace one with the other. */
+
+struct obstack obstack2;
+
+struct obstack *psymbol_obstack = &obstack2;
+
+/* These variables point to the objects
+ representing the predefined C data types. */
+
+struct type *builtin_type_void;
+struct type *builtin_type_char;
+struct type *builtin_type_short;
+struct type *builtin_type_int;
+struct type *builtin_type_long;
+#ifdef LONG_LONG
+struct type *builtin_type_long_long;
+#endif
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+#ifdef LONG_LONG
+struct type *builtin_type_unsigned_long_long;
+#endif
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+
+/* Block in which the most recently searched-for symbol was found.
+ Might be better to make this a parameter to lookup_symbol and
+ value_of_this. */
+struct block *block_found;
+
+/* Functions */
+static int find_line_common ();
+int lookup_misc_func ();
+struct partial_symtab *lookup_partial_symtab ();
+struct symtab *psymtab_to_symtab ();
+static struct partial_symbol *lookup_partial_symbol ();
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work. */
+
+static struct symtab *
+lookup_symtab_1 (name)
+ char *name;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register char *slash = index (name, '/');
+ register int len = strlen (name);
+
+ for (s = symtab_list; s; s = s->next)
+ if (!strcmp (name, s->filename))
+ return s;
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (!strcmp (name, ps->filename))
+ {
+ if (ps->readin)
+ fatal ("Internal: readin pst found when no symtab found.");
+ s = psymtab_to_symtab (ps);
+ return s;
+ }
+
+ if (!slash)
+ {
+ for (s = symtab_list; s; s = s->next)
+ {
+ int l = strlen (s->filename);
+
+ if (s->filename[l - len -1] == '/'
+ && !strcmp (s->filename + l - len, name))
+ return s;
+ }
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ int l = strlen (ps->filename);
+
+ if (ps->filename[l - len - 1] == '/'
+ && !strcmp (ps->filename + l - len, name))
+ {
+ if (ps->readin)
+ fatal ("Internal: readin pst found when no symtab found.");
+ s = psymtab_to_symtab (ps);
+ return s;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Lookup the symbol table of a source file named NAME. Try a couple
+ of variations if the first lookup doesn't work. */
+
+struct symtab *
+lookup_symtab (name)
+ char *name;
+{
+ register struct symtab *s;
+ register char *copy;
+
+ s = lookup_symtab_1 (name);
+ if (s) return s;
+
+ /* If name not found as specified, see if adding ".c" helps. */
+
+ copy = (char *) alloca (strlen (name) + 3);
+ strcpy (copy, name);
+ strcat (copy, ".c");
+ s = lookup_symtab_1 (copy);
+ if (s) return s;
+
+ /* We didn't find anything; die. */
+ return 0;
+}
+
+/* Lookup the partial symbol table of a source file named NAME. This
+ only returns true on an exact match (ie. this semantics are
+ different from lookup_symtab. */
+
+struct partial_symtab *
+lookup_partial_symtab (name)
+char *name;
+{
+ register struct partial_symtab *s;
+ register char *copy;
+
+ for (s = partial_symtab_list; s; s = s->next)
+ if (!strcmp (name, s->filename))
+ return s;
+
+ return 0;
+}
+
+/* Lookup a typedef or primitive type named NAME,
+ visible in lexical block BLOCK.
+ If NOERR is nonzero, return zero if NAME is not suitably defined. */
+
+struct type *
+lookup_typename (name, block, noerr)
+ char *name;
+ struct block *block;
+ int noerr;
+{
+ register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE, 0);
+ if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ if (!strcmp (name, "int"))
+ return builtin_type_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_char;
+ if (!strcmp (name, "float"))
+ return builtin_type_float;
+ if (!strcmp (name, "double"))
+ return builtin_type_double;
+ if (!strcmp (name, "void"))
+ return builtin_type_void;
+
+ if (noerr)
+ return 0;
+ error ("No type named %s.", name);
+ }
+ return SYMBOL_TYPE (sym);
+}
+
+struct type *
+lookup_unsigned_typename (name)
+ char *name;
+{
+ if (!strcmp (name, "int"))
+ return builtin_type_unsigned_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_unsigned_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_unsigned_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_unsigned_char;
+ error ("No type named unsigned %s.", name);
+}
+
+/* Lookup a structure type named "struct NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_struct (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+
+ if (sym == 0)
+ error ("No struct type named %s.", name);
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ error ("This context has class, union or enum %s, not a struct.", name);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Lookup a union type named "union NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_union (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+
+ if (sym == 0)
+ error ("No union type named %s.", name);
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION)
+ error ("This context has class, struct or enum %s, not a union.", name);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Lookup an enum type named "enum NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_enum (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+ if (sym == 0)
+ error ("No enum type named %s.", name);
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM)
+ error ("This context has class, struct or union %s, not an enum.", name);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Given a type TYPE, lookup the type of the component of type named
+ NAME. */
+
+struct type *
+lookup_struct_elt_type (type, name)
+ struct type *type;
+ char *name;
+{
+ struct type *t;
+ int i;
+ char *errmsg;
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ {
+ terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " is not a structure or union type.\n");
+ return_to_top_level ();
+ }
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= 0; i--)
+ if (!strcmp (TYPE_FIELD_NAME (type, i), name))
+ return TYPE_FIELD_TYPE (type, i);
+
+ terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " has no component named %s\n", name);
+ return_to_top_level ();
+}
+
+/* Given a type TYPE, return a type of pointers to that type.
+ May need to construct such a type if this is the first use.
+
+ C++: use TYPE_MAIN_VARIANT and TYPE_CHAIN to keep pointer
+ to member types under control. */
+
+struct type *
+lookup_pointer_type (type)
+ struct type *type;
+{
+ register struct type *ptype = TYPE_POINTER_TYPE (type);
+ if (ptype) return TYPE_MAIN_VARIANT (ptype);
+
+ /* This is the first time anyone wanted a pointer to a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (ptype) = ptype;
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_POINTER_TYPE (type) = ptype;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (ptype) = sizeof (char *);
+ TYPE_CODE (ptype) = TYPE_CODE_PTR;
+ return ptype;
+}
+
+struct type *
+lookup_reference_type (type)
+ struct type *type;
+{
+ register struct type *rtype = TYPE_REFERENCE_TYPE (type);
+ if (rtype) return TYPE_MAIN_VARIANT (rtype);
+
+ /* This is the first time anyone wanted a pointer to a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ rtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ rtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (rtype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (rtype) = rtype;
+ TYPE_TARGET_TYPE (rtype) = type;
+ TYPE_REFERENCE_TYPE (type) = rtype;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (rtype) |= TYPE_FLAG_PERM;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (rtype) = sizeof (char *);
+ TYPE_CODE (rtype) = TYPE_CODE_REF;
+ return rtype;
+}
+
+
+/* Implement direct support for MEMBER_TYPE in GNU C++.
+ May need to construct such a type if this is the first use.
+ The TYPE is the type of the member. The DOMAIN is the type
+ of the aggregate that the member belongs to. */
+
+struct type *
+lookup_member_type (type, domain)
+ struct type *type, *domain;
+{
+ register struct type *mtype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ main_type = mtype;
+ while (mtype)
+ {
+ if (TYPE_DOMAIN_TYPE (mtype) == domain)
+ return mtype;
+ mtype = TYPE_NEXT_VARIANT (mtype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ mtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ mtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (mtype, sizeof (struct type));
+ if (main_type == 0)
+ main_type = mtype;
+ else
+ {
+ TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+ TYPE_NEXT_VARIANT (main_type) = mtype;
+ }
+ TYPE_MAIN_VARIANT (mtype) = main_type;
+ TYPE_TARGET_TYPE (mtype) = type;
+ TYPE_DOMAIN_TYPE (mtype) = domain;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (mtype) = 1;
+ TYPE_CODE (mtype) = TYPE_CODE_MEMBER;
+
+#if 0
+ /* Now splice in the new member pointer type. */
+ if (main_type)
+ {
+ /* This type was not "smashed". */
+ TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+ TYPE_CHAIN (main_type) = mtype;
+ }
+#endif
+
+ return mtype;
+}
+
+struct type *
+lookup_method_type (type, domain, args)
+ struct type *type, *domain, **args;
+{
+ register struct type *mtype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ main_type = mtype;
+ while (mtype)
+ {
+ if (TYPE_DOMAIN_TYPE (mtype) == domain)
+ {
+ struct type **t1 = args;
+ struct type **t2 = TYPE_ARG_TYPES (mtype);
+ if (t2)
+ {
+ int i;
+ for (i = 0; t1[i] != 0 && t1[i]->code != TYPE_CODE_VOID; i++)
+ if (t1[i] != t2[i])
+ break;
+ if (t1[i] == t2[i])
+ return mtype;
+ }
+ }
+ mtype = TYPE_NEXT_VARIANT (mtype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ mtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ mtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (mtype, sizeof (struct type));
+ if (main_type == 0)
+ main_type = mtype;
+ else
+ {
+ TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+ TYPE_NEXT_VARIANT (main_type) = mtype;
+ }
+ TYPE_MAIN_VARIANT (mtype) = main_type;
+ TYPE_TARGET_TYPE (mtype) = type;
+ TYPE_DOMAIN_TYPE (mtype) = domain;
+ TYPE_ARG_TYPES (mtype) = args;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (mtype) = 1;
+ TYPE_CODE (mtype) = TYPE_CODE_METHOD;
+
+#if 0
+ /* Now splice in the new member pointer type. */
+ if (main_type)
+ {
+ /* This type was not "smashed". */
+ TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+ TYPE_CHAIN (main_type) = mtype;
+ }
+#endif
+
+ return mtype;
+}
+
+/* Given a type TYPE, return a type which has offset OFFSET,
+ via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC.
+ May need to construct such a type if none exists. */
+struct type *
+lookup_basetype_type (type, offset, via_virtual, via_public)
+ struct type *type;
+ int offset;
+ int via_virtual, via_public;
+{
+ register struct type *btype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ if (offset != 0)
+ {
+ printf ("Internal error: type offset non-zero in lookup_basetype_type");
+ offset = 0;
+ }
+
+ main_type = btype;
+ while (btype)
+ {
+ if (/* TYPE_OFFSET (btype) == offset
+ && */ TYPE_VIA_PUBLIC (btype) == via_public
+ && TYPE_VIA_VIRTUAL (btype) == via_virtual)
+ return btype;
+ btype = TYPE_NEXT_VARIANT (btype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ btype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ btype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ if (main_type == 0)
+ {
+ main_type = btype;
+ bzero (btype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (btype) = main_type;
+ }
+ else
+ {
+ bcopy (main_type, btype, sizeof (struct type));
+ TYPE_NEXT_VARIANT (main_type) = btype;
+ }
+/* TYPE_OFFSET (btype) = offset; */
+ if (via_public)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_PUBLIC;
+ if (via_virtual)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_VIRTUAL;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (btype) = 1;
+ TYPE_CODE (btype) = TYPE_CODE_STRUCT;
+
+ return btype;
+}
+
+/* Given a type TYPE, return a type of functions that return that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_function_type (type)
+ struct type *type;
+{
+ register struct type *ptype = TYPE_FUNCTION_TYPE (type);
+ if (ptype) return ptype;
+
+ /* This is the first time anyone wanted a function returning a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_FUNCTION_TYPE (type) = ptype;
+ /* New type is permanent if type returned is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ TYPE_LENGTH (ptype) = 1;
+ TYPE_CODE (ptype) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (ptype) = 0;
+ return ptype;
+}
+
+/* Create an array type. Elements will be of type TYPE, and there will
+ be NUM of them.
+
+ Eventually this should be extended to take two more arguments which
+ specify the bounds of the array and the type of the index.
+ It should also be changed to be a "lookup" function, with the
+ appropriate data structures added to the type field.
+ Then read array type should call here. */
+
+struct type *
+create_array_type (element_type, number)
+ struct type *element_type;
+ int number;
+{
+ struct type *result_type = (struct type *)
+ obstack_alloc (symbol_obstack, sizeof (struct type));
+
+ bzero (result_type, sizeof (struct type));
+
+ TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (result_type) = element_type;
+ TYPE_LENGTH (result_type) = number * TYPE_LENGTH (element_type);
+ TYPE_NFIELDS (result_type) = 1;
+ TYPE_FIELDS (result_type) =
+ (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field));
+ TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int;
+ TYPE_VPTR_FIELDNO (result_type) = -1;
+
+ return result_type;
+}
+
+
+/* Smash TYPE to be a type of pointers to TO_TYPE.
+ If TO_TYPE is not permanent and has no pointer-type yet,
+ record TYPE as its pointer-type. */
+
+void
+smash_to_pointer_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (type) = sizeof (char *);
+ TYPE_CODE (type) = TYPE_CODE_PTR;
+
+ TYPE_MAIN_VARIANT (type) = type;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_POINTER_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_POINTER_TYPE (to_type) = type;
+ }
+}
+
+/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE. */
+
+void
+smash_to_member_type (type, domain, to_type)
+ struct type *type, *domain, *to_type;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+
+ /* In practice, this is never needed. */
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_MEMBER;
+
+ TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type);
+}
+
+/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. */
+
+void
+smash_to_method_type (type, domain, to_type, args)
+ struct type *type, *domain, *to_type, **args;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_ARG_TYPES (type) = args;
+
+ /* In practice, this is never needed. */
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_METHOD;
+
+ TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type, args);
+}
+
+/* Smash TYPE to be a type of reference to TO_TYPE.
+ If TO_TYPE is not permanent and has no pointer-type yet,
+ record TYPE as its pointer-type. */
+
+void
+smash_to_reference_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (type) = sizeof (char *);
+ TYPE_CODE (type) = TYPE_CODE_REF;
+
+ TYPE_MAIN_VARIANT (type) = type;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_REFERENCE_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_REFERENCE_TYPE (to_type) = type;
+ }
+}
+
+/* Smash TYPE to be a type of functions returning TO_TYPE.
+ If TO_TYPE is not permanent and has no function-type yet,
+ record TYPE as its function-type. */
+
+void
+smash_to_function_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (type) = 0;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_FUNCTION_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_FUNCTION_TYPE (to_type) = type;
+ }
+}
+
+/* Find which partial symtab on the partial_symtab_list contains
+ PC. Return 0 if none. */
+
+struct partial_symtab *
+find_pc_psymtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct partial_symtab *ps;
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (pc >= ps->textlow && pc < ps->texthigh)
+ return ps;
+
+ return 0;
+}
+
+/* Find which partial symbol within a psymtab contains PC. Return 0
+ if none. Check all psymtabs if PSYMTAB is 0. */
+struct partial_symbol *
+find_pc_psymbol (psymtab, pc)
+ struct partial_symtab *psymtab;
+ CORE_ADDR pc;
+{
+ struct partial_symbol *best, *p;
+ int best_pc;
+
+ if (!psymtab)
+ psymtab = find_pc_psymtab (pc);
+ if (!psymtab)
+ return 0;
+
+ best_pc = psymtab->textlow - 1;
+
+ for (p = static_psymbols.list + psymtab->statics_offset;
+ (p - (static_psymbols.list + psymtab->statics_offset)
+ < psymtab->n_static_syms);
+ p++)
+ if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE (p)
+ && SYMBOL_VALUE (p) > best_pc)
+ {
+ best_pc = SYMBOL_VALUE (p);
+ best = p;
+ }
+ if (best_pc == psymtab->textlow - 1)
+ return 0;
+ return best;
+}
+
+
+static struct symbol *lookup_block_symbol ();
+
+/* Find the definition for a specified symbol name NAME
+ in namespace NAMESPACE, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+struct symbol *
+lookup_symbol (name, block, namespace, is_a_field_of_this)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+ int *is_a_field_of_this;
+{
+ register int i, n;
+ register struct symbol *sym;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct partial_symbol *psym;
+ struct blockvector *bv;
+
+ /* Search specified block and its superiors. */
+
+ while (block != 0)
+ {
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* C++: If requested to do so by the caller,
+ check to see if NAME is a field of `this'. */
+ if (is_a_field_of_this)
+ {
+ struct value *v = value_of_this (0);
+
+ *is_a_field_of_this = 0;
+ if (v && check_field (v, name))
+ {
+ *is_a_field_of_this = 1;
+ return 0;
+ }
+ }
+
+ /* Now search all global blocks. Do the symtab's first, then
+ check the psymtab's */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ }
+
+ /* Check for the possibility of the symbol being a global function
+ that is stored on the misc function vector. Eventually, all
+ global symbols might be resolved in this way. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ int index = lookup_misc_func (name);
+
+ if (index == -1)
+ { /* Look for a mangled C++ name for NAME. */
+ int name_len = strlen (name);
+ for (index = misc_function_count; --index >= 0; )
+ /* Assume orginal name is prefix of mangled name. */
+ if (!strncmp (misc_function_vector[index].name, name, name_len))
+ {
+ char *demangled =
+ cplus_demangle(misc_function_vector[index].name, -1);
+ if (demangled != NULL)
+ {
+ int cond = strcmp (demangled, name);
+ free (demangled);
+ if (!cond)
+ break;
+ }
+ }
+ /* Loop terminates on no match with index == -1. */
+ }
+
+ if (index != -1)
+ {
+ ps = find_pc_psymtab (misc_function_vector[index].address);
+ if (ps && !ps->readin)
+ {
+ s = psymtab_to_symtab (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ /* sym == 0 if symbol was found in the psymtab but not
+ in the symtab.
+ Return 0 to use the misc_function definition of "foo_".
+
+ This happens for Fortran "foo_" symbols,
+ which are "foo" in the symtab.
+
+ This can also happen if "asm" is used to make a
+ regular symbol but not a debugging symbol, e.g.
+ asm(".globl _main");
+ asm("_main:");
+ */
+
+ return sym;
+ }
+ }
+ }
+
+ if (psym = lookup_partial_symbol (name, 1, namespace))
+ {
+ ps = psym->pst;
+ s = psymtab_to_symtab(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ fatal ("Internal: global symbol found in psymtab but not in symtab");
+ return sym;
+ }
+
+ /* Now search all per-file blocks.
+ Not strictly correct, but more useful than an error.
+ Do the symtabs first, then check the psymtabs */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 1);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ }
+
+ if (psym = lookup_partial_symbol(name, 0, namespace))
+ {
+ ps = psym->pst;
+ s = psymtab_to_symtab(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 1);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ fatal ("Internal: static symbol found in psymtab but not in symtab");
+ return sym;
+ }
+
+ return 0;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME. Check the global
+ symbols if GLOBAL, the static symbols if not */
+
+static struct partial_symbol *
+lookup_partial_symbol (name, global, namespace)
+ register char *name;
+ register int global;
+ register enum namespace namespace;
+{
+ register struct partial_symbol *start, *psym;
+ register struct partial_symbol *top, *bottom, *center;
+ register struct partial_symtab *pst;
+ register int length;
+
+ if (global)
+ {
+ start = global_psymbols.list;
+ length = global_psymbols.next - start;
+ }
+ else
+ {
+ start = static_psymbols.list;
+ length = static_psymbols.next - start;
+ }
+
+ if (!length)
+ return (struct partial_symbol *) 0;
+
+ /* Binary search. This search is guarranteed to end with center
+ pointing at the earliest partial symbol with the correct
+ name. At that point *all* partial symbols with that name
+ will be checked against the correct namespace. */
+ bottom = start;
+ top = start + length - 1;
+ while (top > bottom)
+ {
+ center = bottom + (top - bottom) / 2;
+
+ assert (center < top);
+
+ if (strcmp (SYMBOL_NAME (center), name) >= 0)
+ top = center;
+ else
+ bottom = center + 1;
+ }
+ assert (top == bottom);
+
+ while (strcmp (SYMBOL_NAME (top), name) == 0)
+ {
+ if (!top->pst->readin && SYMBOL_NAMESPACE (top) == namespace)
+ return top;
+ top ++;
+ }
+
+ return (struct partial_symbol *) 0;
+}
+
+/* Look for a symbol in block BLOCK. */
+
+static struct symbol *
+lookup_block_symbol (block, name, namespace)
+ register struct block *block;
+ char *name;
+ enum namespace namespace;
+{
+ register int bot, top, inc;
+ register struct symbol *sym, *parameter_sym;
+
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+
+ /* If the blocks's symbols were sorted, start with a binary search. */
+
+ if (BLOCK_SHOULD_SORT (block))
+ {
+ /* First, advance BOT to not far before
+ the first symbol whose name is NAME. */
+
+ while (1)
+ {
+ inc = (top - bot + 1);
+ /* No need to keep binary searching for the last few bits worth. */
+ if (inc < 4)
+ break;
+ inc = (inc >> 1) + bot;
+ sym = BLOCK_SYM (block, inc);
+ if (SYMBOL_NAME (sym)[0] < name[0])
+ bot = inc;
+ else if (SYMBOL_NAME (sym)[0] > name[0])
+ top = inc;
+ else if (strcmp (SYMBOL_NAME (sym), name) < 0)
+ bot = inc;
+ else
+ top = inc;
+ }
+
+ /* Now scan forward until we run out of symbols,
+ find one whose name is greater than NAME,
+ or find one we want.
+ If there is more than one symbol with the right name and namespace,
+ we return the first one. dbxread.c is careful to make sure
+ that if one is a register then it comes first. */
+
+ top = BLOCK_NSYMS (block);
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ inc = SYMBOL_NAME (sym)[0] - name[0];
+ if (inc == 0)
+ inc = strcmp (SYMBOL_NAME (sym), name);
+ if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
+ return sym;
+ if (inc > 0)
+ return 0;
+ bot++;
+ }
+ return 0;
+ }
+
+ /* Here if block isn't sorted.
+ This loop is equivalent to the loop above,
+ but hacked greatly for speed.
+
+ Note that parameter symbols do not always show up last in the
+ list; this loop makes sure to take anything else other than
+ parameter symbols first; it only uses parameter symbols as a
+ last resort. Note that this only takes up extra computation
+ time on a match. */
+
+ parameter_sym = (struct symbol *) 0;
+ top = BLOCK_NSYMS (block);
+ inc = name[0];
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAME (sym)[0] == inc
+ && !strcmp (SYMBOL_NAME (sym), name)
+ && SYMBOL_NAMESPACE (sym) == namespace)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ || SYMBOL_CLASS (sym) == LOC_REF_ARG
+ || SYMBOL_CLASS (sym) == LOC_REGPARM)
+ parameter_sym = sym;
+ else
+ return sym;
+ }
+ bot++;
+ }
+ return parameter_sym; /* Will be 0 if not found. */
+}
+
+/* Return the symbol for the function which contains a specified
+ lexical block, described by a struct block BL. */
+
+struct symbol *
+block_function (bl)
+ struct block *bl;
+{
+ while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
+/* Subroutine of find_pc_line */
+
+struct symtab *
+find_pc_symtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ struct blockvector *bv;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+
+ /* Search all symtabs for one whose file contains our pc */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, 0);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc)
+ break;
+ }
+
+ if (!s)
+ {
+ ps = find_pc_psymtab (pc);
+ if (ps && ps->readin)
+ fatal ("Internal error: pc in read in psymtab, but not in symtab.");
+
+ if (ps)
+ s = psymtab_to_symtab (ps);
+ }
+
+ return s;
+}
+
+/* Find the source file and line number for a given PC value.
+ Return a structure containing a symtab pointer, a line number,
+ and a pc range for the entire source line.
+ The value's .pc field is NOT the specified pc.
+ NOTCURRENT nonzero means, if specified pc is on a line boundary,
+ use the line that ends there. Otherwise, in that case, the line
+ that begins there is used. */
+
+struct symtab_and_line
+find_pc_line (pc, notcurrent)
+ CORE_ADDR pc;
+ int notcurrent;
+{
+ struct symtab *s;
+ register struct linetable *l;
+ register int len;
+ register int i;
+ register struct linetable_entry *item;
+ struct symtab_and_line value;
+ struct blockvector *bv;
+
+ /* Info on best line seen so far, and where it starts, and its file. */
+
+ int best_line = 0;
+ CORE_ADDR best_pc = 0;
+ CORE_ADDR best_end = 0;
+ struct symtab *best_symtab = 0;
+
+ /* Store here the first line number
+ of a file which contains the line at the smallest pc after PC.
+ If we don't find a line whose range contains PC,
+ we will use a line one less than this,
+ with a range from the start of that file to the first line's pc. */
+ int alt_line = 0;
+ CORE_ADDR alt_pc = 0;
+ struct symtab *alt_symtab = 0;
+
+ /* Info on best line seen in this file. */
+
+ int prev_line;
+ CORE_ADDR prev_pc;
+
+ /* Info on first line of this file. */
+
+ int first_line;
+ CORE_ADDR first_pc;
+
+ /* If this pc is not from the current frame,
+ it is the address of the end of a call instruction.
+ Quite likely that is the start of the following statement.
+ But what we want is the statement containing the instruction.
+ Fudge the pc to make sure we get that. */
+
+ if (notcurrent) pc -= 1;
+
+ s = find_pc_symtab (pc);
+ if (s == 0)
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = pc;
+ value.end = 0;
+ return value;
+ }
+
+ bv = BLOCKVECTOR (s);
+
+ /* Look at all the symtabs that share this blockvector.
+ They all have the same apriori range, that we found was right;
+ but they have different line tables. */
+
+ for (; s && BLOCKVECTOR (s) == bv; s = s->next)
+ {
+ /* Find the best line in this symtab. */
+ l = LINETABLE (s);
+ len = l->nitems;
+ prev_line = -1;
+ first_line = -1;
+ for (i = 0; i < len; i++)
+ {
+ item = &(l->item[i]);
+
+ if (first_line < 0)
+ {
+ first_line = item->line;
+ first_pc = item->pc;
+ }
+ /* Return the last line that did not start after PC. */
+ if (pc >= item->pc)
+ {
+ prev_line = item->line;
+ prev_pc = item->pc;
+ }
+ else
+ break;
+ }
+
+ /* Is this file's best line closer than the best in the other files?
+ If so, record this file, and its best line, as best so far. */
+ if (prev_line >= 0 && prev_pc > best_pc)
+ {
+ best_pc = prev_pc;
+ best_line = prev_line;
+ best_symtab = s;
+ if (i < len)
+ best_end = item->pc;
+ else
+ best_end = 0;
+ }
+ /* Is this file's first line closer than the first lines of other files?
+ If so, record this file, and its first line, as best alternate. */
+ if (first_line >= 0 && first_pc > pc
+ && (alt_pc == 0 || first_pc < alt_pc))
+ {
+ alt_pc = first_pc;
+ alt_line = first_line;
+ alt_symtab = s;
+ }
+ }
+ if (best_symtab == 0)
+ {
+ value.symtab = alt_symtab;
+ value.line = alt_line - 1;
+ value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0));
+ value.end = alt_pc;
+ }
+ else
+ {
+ value.symtab = best_symtab;
+ value.line = best_line;
+ value.pc = best_pc;
+ value.end = (best_end ? best_end
+ : (alt_pc ? alt_pc
+ : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0))));
+ }
+ return value;
+}
+
+/* Find the PC value for a given source file and line number.
+ Returns zero for invalid line number.
+ The source file is specified with a struct symtab. */
+
+CORE_ADDR
+find_line_pc (symtab, line)
+ struct symtab *symtab;
+ int line;
+{
+ register struct linetable *l;
+ register int index;
+ int dummy;
+
+ if (symtab == 0)
+ return 0;
+ l = LINETABLE (symtab);
+ index = find_line_common(l, line, &dummy);
+ return index ? l->item[index].pc : 0;
+}
+
+/* Find the range of pc values in a line.
+ Store the starting pc of the line into *STARTPTR
+ and the ending pc (start of next line) into *ENDPTR.
+ Returns 1 to indicate success.
+ Returns 0 if could not find the specified line. */
+
+int
+find_line_pc_range (symtab, thisline, startptr, endptr)
+ struct symtab *symtab;
+ int thisline;
+ CORE_ADDR *startptr, *endptr;
+{
+ register struct linetable *l;
+ register int index;
+ int exact_match; /* did we get an exact linenumber match */
+ register CORE_ADDR prev_pc;
+ CORE_ADDR last_pc;
+
+ if (symtab == 0)
+ return 0;
+
+ l = LINETABLE (symtab);
+ index = find_line_common (l, thisline, &exact_match);
+ if (index)
+ {
+ *startptr = l->item[index].pc;
+ /* If we have not seen an entry for the specified line,
+ assume that means the specified line has zero bytes. */
+ if (!exact_match || index == l->nitems-1)
+ *endptr = *startptr;
+ else
+ /* Perhaps the following entry is for the following line.
+ It's worth a try. */
+ if (l->item[index+1].line == thisline + 1)
+ *endptr = l->item[index+1].pc;
+ else
+ *endptr = find_line_pc (symtab, thisline+1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Given a line table and a line number, return the index into the line
+ table for the pc of the nearest line whose number is >= the specified one.
+ Return 0 if none is found. The value is never zero is it is an index.
+
+ Set *EXACT_MATCH nonzero if the value returned is an exact match. */
+
+static int
+find_line_common (l, lineno, exact_match)
+ register struct linetable *l;
+ register int lineno;
+ int *exact_match;
+{
+ register int i;
+ register int len;
+
+ /* BEST is the smallest linenumber > LINENO so far seen,
+ or 0 if none has been seen so far.
+ BEST_INDEX identifies the item for it. */
+
+ int best_index = 0;
+ int best = 0;
+
+ int nextline = -1;
+
+ if (lineno <= 0)
+ return 0;
+
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ register struct linetable_entry *item = &(l->item[i]);
+
+ if (item->line == lineno)
+ {
+ *exact_match = 1;
+ return i;
+ }
+
+ if (item->line > lineno && (best == 0 || item->line < best))
+ {
+ best = item->line;
+ best_index = i;
+ }
+ }
+
+ /* If we got here, we didn't get an exact match. */
+
+ *exact_match = 0;
+ return best_index;
+}
+
+int
+find_pc_line_pc_range (pc, startptr, endptr)
+ CORE_ADDR pc;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct symtab_and_line sal;
+ sal = find_pc_line (pc, 0);
+ *startptr = sal.pc;
+ *endptr = sal.end;
+ return sal.symtab != 0;
+}
+
+/* Parse a string that specifies a line number.
+ Pass the address of a char * variable; that variable will be
+ advanced over the characters actually parsed.
+
+ The string can be:
+
+ LINENUM -- that line number in current file. PC returned is 0.
+ FILE:LINENUM -- that line in that file. PC returned is 0.
+ FUNCTION -- line number of openbrace of that function.
+ PC returned is the start of the function.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in misc_function_vector.
+
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside a function when a function is specified.
+
+ DEFAULT_SYMTAB specifies the file to use if none is specified.
+ It defaults to current_source_symtab.
+ DEFAULT_LINE specifies the line number to use for relative
+ line numbers (that start with signs). Defaults to current_source_line.
+
+ Note that it is possible to return zero for the symtab
+ if no file is validly specified. Callers must check that.
+ Also, the line number returned may be invalid. */
+
+struct symtabs_and_lines
+decode_line_1 (argptr, funfirstline, default_symtab, default_line)
+ char **argptr;
+ int funfirstline;
+ struct symtab *default_symtab;
+ int default_line;
+{
+ struct symtabs_and_lines decode_line_2 ();
+ struct symtabs_and_lines values;
+ struct symtab_and_line value;
+ register char *p, *p1;
+ register struct symtab *s;
+ register struct symbol *sym;
+ register CORE_ADDR pc;
+ register int i;
+ char *copy;
+ struct symbol *sym_class;
+ char *class_name, *method_name, *phys_name;
+ int method_counter;
+ int i1;
+ struct symbol **sym_arr;
+ struct type *t, *field;
+ char **physnames;
+
+ /* Defaults have defaults. */
+
+ if (default_symtab == 0)
+ {
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ /* See if arg is *PC */
+
+ if (**argptr == '*')
+ {
+ (*argptr)++;
+ pc = parse_and_eval_address_1 (argptr);
+ values.sals = (struct symtab_and_line *)
+ malloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = pc;
+ return values;
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+ s = 0;
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if (p[0] == ':')
+ {
+
+ /* C++ */
+ if (p[1] ==':')
+ {
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Discard the class name from the arg. */
+ p = p1 + 2;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0);
+
+ if (sym_class &&
+ (TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION))
+ {
+ /* Arg token is not digits => try it as a function name
+ Find the next token (everything up to end or next whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = '\0';
+
+ /* no line number may be specified */
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym = 0;
+ i1 = 0; /* counter for the symbol array */
+ t = SYMBOL_TYPE (sym_class);
+ sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+ physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*));
+
+ if (destructor_name_p (copy, t))
+ {
+ /* destructors are a special case. */
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
+ int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
+ physnames[i1] = (char *)alloca (strlen (phys_name) + 1);
+ strcpy (physnames[i1], phys_name);
+ sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
+ if (sym_arr[i1]) i1++;
+ }
+ else while (t)
+ {
+ class_name = TYPE_NAME (t);
+ /* Ignore this class if it doesn't have a name.
+ This prevents core dumps, but is just a workaround
+ because we might not find the function in
+ certain cases, such as
+ struct D {virtual int f();}
+ struct C : D {virtual int g();}
+ (in this case g++ 1.35.1- does not put out a name
+ for D as such, it defines type 19 (for example) in
+ the same stab as C, and then does a
+ .stabs "D:T19" and a .stabs "D:t19".
+ Thus
+ "break C::f" should not be looking for field f in
+ the class named D,
+ but just for the field f in the baseclasses of C
+ (no matter what their names).
+
+ However, I don't know how to replace the code below
+ that depends on knowing the name of D. */
+ if (class_name)
+ {
+ /* We just want the class name. In the context
+ of C++, stripping off "struct " is always
+ sensible. */
+ if (strncmp("struct ", class_name, 7) == 0)
+ class_name += 7;
+ if (strncmp("union ", class_name, 6) == 0)
+ class_name += 6;
+
+ sym_class = lookup_symbol (class_name, 0, STRUCT_NAMESPACE, 0);
+ for (method_counter = TYPE_NFN_FIELDS (SYMBOL_TYPE (sym_class)) - 1;
+ method_counter >= 0;
+ --method_counter)
+ {
+ int field_counter;
+ struct fn_field *f =
+ TYPE_FN_FIELDLIST1 (SYMBOL_TYPE (sym_class), method_counter);
+
+ method_name = TYPE_FN_FIELDLIST_NAME (SYMBOL_TYPE (sym_class), method_counter);
+ if (!strcmp (copy, method_name))
+ /* Find all the fields with that name. */
+ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (SYMBOL_TYPE (sym_class), method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ physnames[i1] = (char*) alloca (strlen (phys_name) + 1);
+ strcpy (physnames[i1], phys_name);
+ sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
+ if (sym_arr[i1]) i1++;
+ }
+ }
+ }
+ if (TYPE_N_BASECLASSES (t))
+ t = TYPE_BASECLASS(t, 1);
+ else
+ break;
+ }
+
+ if (i1 == 1)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
+ }
+ else
+ {
+ values.nelts = 0;
+ }
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* There is more than one field with that name
+ (overloaded). Ask the user which one to use. */
+ return decode_line_2 (argptr, sym_arr, physnames,
+ i1, funfirstline);
+ }
+ else
+ error ("that class does not have any method named %s",copy);
+ }
+ else
+ error("no class, struct, or union named %s", copy );
+ }
+ /* end of C++ */
+
+
+ /* Extract the file name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ s = lookup_symtab (copy);
+ if (s == 0)
+ {
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ error ("No source file named %s.", copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ }
+
+ /* S is specified file's symtab, or 0 if no file specified.
+ arg no longer contains the file name. */
+
+ /* Check whether arg is all digits (and sign) */
+
+ p = *argptr;
+ if (*p == '-' || *p == '+') p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+ {
+ /* We found a token consisting of all digits -- at least one digit. */
+ enum sign {none, plus, minus} sign = none;
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarrantee that this section of code is never executed
+ when we are called with just a function name, since
+ select_source_symtab calls us with such an argument */
+
+ if (s == 0 && default_symtab == 0)
+ {
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ select_source_symtab (0);
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ value.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (p == *argptr)
+ value.line = 5;
+ if (s == 0)
+ value.line = default_line + value.line;
+ break;
+ case minus:
+ if (p == *argptr)
+ value.line = 15;
+ if (s == 0)
+ value.line = default_line - value.line;
+ else
+ value.line = 1;
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ if (s == 0)
+ s = default_symtab;
+ value.symtab = s;
+ value.pc = 0;
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ /* Arg token is not digits => try it as a function name
+ Find the next token (everything up to end or next whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',') p++;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ /* Look up that token as a function.
+ If file specified, use that file's per-file block to start with. */
+
+ if (s == 0)
+ /* use current file as default if none is specified. */
+ s = default_symtab;
+
+ sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0,
+ VAR_NAMESPACE, 0);
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ value = find_pc_line (pc, 0);
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* Convex: no need to suppress code on first line, if any */
+ value.pc = pc;
+#else
+ value.pc = (value.end && value.pc != pc) ? value.end : pc;
+#endif
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ if (sym)
+ error ("%s is not a function.", copy);
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+
+ if ((i = lookup_misc_func (copy)) >= 0)
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (value.pc);
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ error ("Function %s not defined.", copy);
+}
+
+struct symtabs_and_lines
+decode_line_spec (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtabs_and_lines sals;
+ if (string == 0)
+ error ("Empty line specification.");
+ sals = decode_line_1 (&string, funfirstline,
+ current_source_symtab, current_source_line);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+/* Given a list of NELTS symbols in sym_arr (with corresponding
+ mangled names in physnames), return a list of lines to operate on
+ (ask user if necessary). */
+struct symtabs_and_lines
+decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline)
+ char **argptr;
+ struct symbol *sym_arr[];
+ char *physnames[];
+ int nelts;
+ int funfirstline;
+{
+ char *getenv();
+ struct symtabs_and_lines values, return_values;
+ register CORE_ADDR pc;
+ char *args, *arg1, *command_line_input ();
+ int i;
+ char *prompt;
+
+ values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
+ return_values.sals = (struct symtab_and_line *) malloc (nelts * sizeof(struct symtab_and_line));
+
+ i = 0;
+ printf("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i]))
+ + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals[i] = find_pc_line (pc, 0);
+ values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ? values.sals[i].end : pc;
+ printf("[%d] file:%s; line number:%d\n",
+ (i+2), values.sals[i].symtab->filename, values.sals[i].line);
+ }
+ else printf ("?HERE\n");
+ i++;
+ }
+
+ if ((prompt = getenv ("PS2")) == NULL)
+ {
+ prompt = ">";
+ }
+ printf("%s ",prompt);
+ fflush(stdout);
+
+ args = command_line_input (0, 0);
+
+ if (args == 0)
+ error_no_arg ("one or more choice numbers");
+
+ i = 0;
+ while (*args)
+ {
+ int num;
+
+ arg1 = args;
+ while (*arg1 >= '0' && *arg1 <= '9') arg1++;
+ if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
+ error ("Arguments must be choice numbers.");
+
+ num = atoi (args);
+
+ if (num == 0)
+ error ("cancelled");
+ else if (num == 1)
+ {
+ bcopy (values.sals, return_values.sals, (nelts * sizeof(struct symtab_and_line)));
+ return_values.nelts = nelts;
+ return return_values;
+ }
+
+ if (num > nelts + 2)
+ {
+ printf ("No choice number %d.\n", num);
+ }
+ else
+ {
+ num -= 2;
+ if (values.sals[num].pc)
+ {
+ return_values.sals[i++] = values.sals[num];
+ values.sals[num].pc = 0;
+ }
+ else
+ {
+ printf ("duplicate request for %d ignored.\n", num);
+ }
+ }
+
+ args = arg1;
+ while (*args == ' ' || *args == '\t') args++;
+ }
+ return_values.nelts = i;
+ return return_values;
+}
+
+/* hash a symbol ("hashpjw" from Aho, Sethi & Ullman, p.436) */
+
+int
+hash_symbol(str)
+ register char *str;
+{
+ register unsigned int h = 0, g;
+ register unsigned char c;
+
+ while (c = *(unsigned char *)str++) {
+ h = (h << 4) + c;
+ if (g = h & 0xf0000000) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return ((int)h);
+}
+
+/* Return the index of misc function named NAME. */
+
+int
+lookup_misc_func (name)
+ register char *name;
+{
+ register int i = hash_symbol(name) & (MISC_FUNC_HASH_SIZE - 1);
+
+ if (misc_function_vector == 0)
+ error("No symbol file");
+
+ i = misc_function_hash_tab[i];
+ while (i >= 0)
+ {
+ if (strcmp(misc_function_vector[i].name, name) == 0)
+ break;
+ i = misc_function_vector[i].next;
+ }
+ return (i);
+}
+
+/*
+ * Slave routine for sources_info. Force line breaks at ,'s.
+ */
+static void
+output_source_filename (name, next)
+char *name;
+int next;
+{
+ static int column = 0;
+
+ if (column != 0 && column + strlen (name) >= 70)
+ {
+ printf_filtered ("\n");
+ column = 0;
+ }
+ else if (column != 0)
+ {
+ printf_filtered (" ");
+ column++;
+ }
+ printf_filtered ("%s", name);
+ column += strlen (name);
+ if (next)
+ {
+ printf_filtered (",");
+ column++;
+ }
+
+ if (!next) column = 0;
+}
+
+static void
+sources_info ()
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register int column = 0;
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ {
+ printf ("No symbol table is loaded.\n");
+ return;
+ }
+
+ printf_filtered ("Source files for which symbols have been read in:\n\n");
+
+ for (s = symtab_list; s; s = s->next)
+ output_source_filename (s->filename, s->next);
+ printf_filtered ("\n\n");
+
+ printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (!ps->readin)
+ output_source_filename (ps->filename, ps->next);
+ printf_filtered ("\n");
+}
+
+/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP.
+ If CLASS is zero, list all symbols except functions and type names.
+ If CLASS is 1, list only functions.
+ If CLASS is 2, list only type names. */
+
+static void sort_block_syms ();
+
+static void
+list_symbols (regexp, class)
+ char *regexp;
+ int class;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b;
+ register int i, j;
+ register struct symbol *sym;
+ struct partial_symbol *psym, *bound;
+ char *val;
+ static char *classnames[]
+ = {"variable", "function", "type", "method"};
+ int print_count = 0;
+ int found_in_file = 0;
+
+ if (regexp)
+ if (val = (char *) re_comp (regexp))
+ error ("Invalid regexp: %s", val);
+
+ /* Search through the partial_symtab_list *first* for all symbols
+ matching the regexp. That way we don't have to reproduce all of
+ the machinery below. */
+ for (psym = global_psymbols.list, bound = global_psymbols.next; ;
+ psym = static_psymbols.list, bound = static_psymbols.next)
+ {
+ for (; psym < bound; ++psym)
+ {
+ if (psym->pst->readin)
+ continue;
+
+ QUIT;
+ /* If it would match (logic taken from loop below)
+ load the file and go on to the next one */
+ if ((regexp == 0 || re_exec (SYMBOL_NAME (psym)))
+ && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (psym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK)))
+ psymtab_to_symtab(psym->pst);
+ }
+ if (psym == static_psymbols.next)
+ break;
+ }
+
+ /* Printout here so as to get after the "Reading in symbols"
+ messages which will be generated above. */
+ printf_filtered (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[class],
+ regexp);
+
+ /* Here, *if* the class is correct (function only, right now), we
+ should search through the misc function vector for symbols that
+ match and call find_pc_psymtab on them. If find_pc_psymtab returns
+ 0, don't worry about it (already read in or no debugging info). */
+
+ if (class == 1)
+ {
+ for (i = 0; i < misc_function_count; i++)
+ if (regexp == 0 || re_exec (misc_function_vector[i].name))
+ {
+ ps = find_pc_psymtab (misc_function_vector[i].address);
+ if (ps && !ps->readin)
+ psymtab_to_symtab (ps);
+ }
+ }
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ found_in_file = 0;
+ bv = BLOCKVECTOR (s);
+ /* Often many files share a blockvector.
+ Scan each blockvector only once so that
+ we don't get every symbol many times.
+ It happens that the first symtab in the list
+ for any given blockvector is the main file. */
+ if (bv != prev_bv)
+ for (i = 0; i < 2; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ /* Skip the sort if this block is always sorted. */
+ if (!BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ for (j = 0; j < BLOCK_NSYMS (b); j++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, j);
+ if ((regexp == 0 || re_exec (SYMBOL_NAME (sym)))
+ && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
+ {
+ if (!found_in_file)
+ {
+ printf_filtered ("\nFile %s:\n", s->filename);
+ print_count += 2;
+ }
+ found_in_file = 1;
+ if (class != 2 && i == 1)
+ printf_filtered ("static ");
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+ printf_filtered ("typedef ");
+
+ if (class < 3)
+ {
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_NAME (sym)),
+ stdout, 0);
+
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE
+ && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0
+ || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))),
+ SYMBOL_NAME (sym))))
+ printf_filtered (" %s", SYMBOL_NAME (sym));
+
+ printf_filtered (";\n");
+ }
+ else
+ {
+# if 0
+ char buf[1024];
+ type_print_base (TYPE_FN_FIELD_TYPE(t, i), stdout, 0, 0);
+ type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), stdout, 0);
+ sprintf (buf, " %s::", TYPE_NAME (t));
+ type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), buf, name, stdout);
+# endif
+ }
+ }
+ }
+ }
+ prev_bv = bv;
+ }
+}
+
+static void
+variables_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 0);
+}
+
+static void
+functions_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 1);
+}
+
+static void
+types_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 2);
+}
+
+#if 0
+/* Tiemann says: "info methods was never implemented." */
+static void
+methods_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 3);
+}
+#endif /* 0 */
+
+/* Call sort_block_syms to sort alphabetically the symbols of one block. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ /* Names that are less should come first. */
+ register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void
+sort_block_syms (b)
+ register struct block *b;
+{
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+}
+
+/* Initialize the standard C scalar types. */
+
+static
+struct type *
+init_type (code, length, uns, name)
+ enum type_code code;
+ int length, uns;
+ char *name;
+{
+ register struct type *type;
+
+ type = (struct type *) xmalloc (sizeof (struct type));
+ bzero (type, sizeof *type);
+ TYPE_MAIN_VARIANT (type) = type;
+ TYPE_CODE (type) = code;
+ TYPE_LENGTH (type) = length;
+ TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_NAME (type) = name;
+
+ /* C++ fancies. */
+ TYPE_NFN_FIELDS (type) = 0;
+ TYPE_N_BASECLASSES (type) = 0;
+ TYPE_BASECLASSES (type) = 0;
+ return type;
+}
+
+/* Return Nonzero if block a is lexically nested within block b,
+ or if a and b have the same pc range.
+ Return zero otherwise. */
+int
+contained_in (a, b)
+ struct block *a, *b;
+{
+ if (!a || !b)
+ return 0;
+ return a->startaddr >= b->startaddr && a->endaddr <= b->endaddr;
+}
+
+
+/* Helper routine for make_symbol_completion_list. */
+
+int return_val_size, return_val_index;
+char **return_val;
+
+void
+completion_list_add_symbol (symname)
+ char *symname;
+{
+ if (return_val_index + 3 > return_val_size)
+ return_val =
+ (char **)xrealloc (return_val,
+ (return_val_size *= 2) * sizeof (char *));
+
+ return_val[return_val_index] =
+ (char *)xmalloc (1 + strlen (symname));
+
+ strcpy (return_val[return_val_index], symname);
+
+ return_val[++return_val_index] = (char *)NULL;
+}
+
+/* Return a NULL terminated array of all symbols (regardless of class) which
+ begin by matching TEXT. If the answer is no symbols, then the return value
+ is an array which contains only a NULL pointer.
+
+ Problem: All of the symbols have to be copied because readline
+ frees them. I'm not going to worry about this; hopefully there
+ won't be that many. */
+
+char **
+make_symbol_completion_list (text)
+ char *text;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b, *surrounding_static_block;
+ extern struct block *get_selected_block ();
+ register int i, j;
+ register struct symbol *sym;
+ struct partial_symbol *psym;
+
+ int text_len = strlen (text);
+ return_val_size = 100;
+ return_val_index = 0;
+ return_val =
+ (char **)xmalloc ((1 + return_val_size) *sizeof (char *));
+ return_val[0] = (char *)NULL;
+
+ /* Look through the partial symtabs for all symbols which begin
+ by matching TEXT. Add each one that you find to the list. */
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ /* If the psymtab's been read in we'll get it when we search
+ through the blockvector. */
+ if (ps->readin) continue;
+
+ for (psym = global_psymbols.list + ps->globals_offset;
+ psym < (global_psymbols.list + ps->globals_offset
+ + ps->n_global_syms);
+ psym++)
+ {
+ QUIT; /* If interrupted, then quit. */
+ if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+ completion_list_add_symbol (SYMBOL_NAME (psym));
+ }
+
+ for (psym = static_psymbols.list + ps->statics_offset;
+ psym < (static_psymbols.list + ps->statics_offset
+ + ps->n_static_syms);
+ psym++)
+ {
+ QUIT;
+ if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+ completion_list_add_symbol (SYMBOL_NAME (psym));
+ }
+ }
+
+ /* At this point scan through the misc function vector and add each
+ symbol you find to the list. Eventually we want to ignore
+ anything that isn't a text symbol (everything else will be
+ handled by the psymtab code above). */
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strncmp (text, misc_function_vector[i].name, text_len))
+ completion_list_add_symbol (misc_function_vector[i].name);
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+ for (b = get_selected_block (); b; b = BLOCK_SUPERBLOCK (b))
+ {
+ if (!BLOCK_SUPERBLOCK (b))
+ surrounding_static_block = b; /* For elmin of dups */
+
+ /* Also catch fields of types defined in this places which
+ match our text string. Only complete on types visible
+ from current context. */
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ register struct symbol *sym = BLOCK_SYM (b, i);
+
+ if (!strncmp (SYMBOL_NAME (sym), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (sym));
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ struct type *t = SYMBOL_TYPE (sym);
+ enum type_code c = TYPE_CODE (t);
+
+ if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
+ for (j = 0; j < TYPE_NFIELDS (t); j++)
+ if (TYPE_FIELD_NAME (t, j) &&
+ !strncmp (TYPE_FIELD_NAME (t, j), text, text_len))
+ completion_list_add_symbol (TYPE_FIELD_NAME (t, j));
+ }
+ }
+ }
+
+ /* Go through the symtabs and check the externs and statics for
+ symbols which match. */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 0);
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ }
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
+
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block) continue;
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ }
+
+ return (return_val);
+}
+
+void
+_initialize_symtab ()
+{
+ add_info ("variables", variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ add_info ("functions", functions_info,
+ "All function names, or those matching REGEXP.");
+ add_info ("types", types_info,
+ "All types names, or those matching REGEXP.");
+#if 0
+ add_info ("methods", methods_info,
+ "All method names, or those matching REGEXP::REGEXP.\n\
+If the class qualifier is ommited, it is assumed to be the current scope.\n\
+If the first REGEXP is ommited, then all methods matching the second REGEXP\n\
+are listed.");
+#endif
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ obstack_init (symbol_obstack);
+ obstack_init (psymbol_obstack);
+
+ builtin_type_void = init_type (TYPE_CODE_VOID, 1, 0, "void");
+
+ builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float");
+ builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double");
+
+ builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char");
+ builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short");
+ builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long");
+ builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int");
+
+ builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char");
+ builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short");
+ builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long");
+ builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int");
+#ifdef LONG_LONG
+ builtin_type_long_long =
+ init_type (TYPE_CODE_INT, sizeof (long long), 0, "long long");
+ builtin_type_unsigned_long_long =
+ init_type (TYPE_CODE_INT, sizeof (long long), 1, "unsigned long long");
+#endif
+}
+
diff --git a/gnu/usr.bin/gdb/symtab.h b/gnu/usr.bin/kgdb/symtab.h
index fefed6001e5f..fefed6001e5f 100644
--- a/gnu/usr.bin/gdb/symtab.h
+++ b/gnu/usr.bin/kgdb/symtab.h
diff --git a/gnu/usr.bin/kgdb/utils.c b/gnu/usr.bin/kgdb/utils.c
new file mode 100644
index 000000000000..1a8a01442aad
--- /dev/null
+++ b/gnu/usr.bin/kgdb/utils.c
@@ -0,0 +1,1096 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * $Header: /home/cvs/386BSD/src/gnu/usr.bin/kgdb/utils.c,v 1.1 1993/06/29 09:47:42 nate Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)utils.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* General utility routines for GDB, the GNU debugger.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can 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.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "param.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include "defs.h"
+#ifdef HAVE_TERMIO
+#include <termio.h>
+#endif
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+extern FILE *instream;
+
+void error ();
+void fatal ();
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero means a quit has been requested. */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now,
+ rather than waiting until QUIT is executed. */
+
+int immediate_quit;
+
+/* Add a new cleanup to the cleanup_chain,
+ and return the previous chain pointer
+ to be passed later to do_cleanups or discard_cleanups.
+ Args are FUNCTION to clean up with, and ARG to pass to it. */
+
+struct cleanup *
+make_cleanup (function, arg)
+ void (*function) ();
+ int arg;
+{
+ register struct cleanup *new
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ register struct cleanup *old_chain = cleanup_chain;
+
+ new->next = cleanup_chain;
+ new->function = function;
+ new->arg = arg;
+ cleanup_chain = new;
+
+ return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+do_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ (*ptr->function) (ptr->arg);
+ cleanup_chain = ptr->next;
+ free (ptr);
+ }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+discard_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next;
+ free (ptr);
+ }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain. */
+struct cleanup *
+save_cleanups ()
+{
+ struct cleanup *old_chain = cleanup_chain;
+
+ cleanup_chain = 0;
+ return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain. */
+void
+restore_cleanups (chain)
+ struct cleanup *chain;
+{
+ cleanup_chain = chain;
+}
+
+/* This function is useful for cleanups.
+ Do
+
+ foo = xmalloc (...);
+ old_chain = make_cleanup (free_current_contents, &foo);
+
+ to arrange to free the object thus allocated. */
+
+void
+free_current_contents (location)
+ char **location;
+{
+ free (*location);
+}
+
+/* Generally useful subroutines used throughout the program. */
+
+/* Like malloc but get error if no storage available. */
+
+char *
+xmalloc (size)
+ long size;
+{
+ register char *val = (char *) malloc (size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* Like realloc but get error if no storage available. */
+
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ long size;
+{
+ register char *val = (char *) realloc (ptr, size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* Print the system error message for errno, and also mention STRING
+ as the file name for which the error was encountered.
+ Then return to command level. */
+
+void
+perror_with_name (string)
+ char *string;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+ char *err;
+ char *combined;
+
+ if (errno < sys_nerr)
+ err = sys_errlist[errno];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+ as the file name for which the error was encountered. */
+
+void
+print_sys_errmsg (string, errcode)
+ char *string;
+ int errcode;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ char *err;
+ char *combined;
+
+ if (errcode < sys_nerr)
+ err = sys_errlist[errcode];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ printf ("%s.\n", combined);
+}
+
+void
+quit ()
+{
+#ifdef HAVE_TERMIO
+ ioctl (fileno (stdout), TCFLSH, 1);
+#else /* not HAVE_TERMIO */
+ ioctl (fileno (stdout), TIOCFLUSH, 0);
+#endif /* not HAVE_TERMIO */
+#ifdef TIOCGPGRP
+ error ("Quit");
+#else
+ error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
+#endif /* TIOCGPGRP */
+}
+
+/* Control C comes here */
+
+void
+request_quit ()
+{
+ extern int remote_debugging;
+
+ quit_flag = 1;
+
+#ifdef USG
+ /* Restore the signal handler. */
+ signal (SIGINT, request_quit);
+#endif
+
+ if (immediate_quit)
+ quit();
+}
+
+/* Print an error message and return to command level.
+ STRING is the error message, used as a fprintf string,
+ and ARG is passed as an argument to it. */
+
+void
+error (string, arg1, arg2, arg3)
+ char *string;
+ int arg1, arg2, arg3;
+{
+ terminal_ours (); /* Should be ok even if no inf. */
+ fflush (stdout);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, "\n");
+ return_to_top_level ();
+}
+
+/* Print an error message and exit reporting failure.
+ This is for a error that we cannot continue from.
+ STRING and ARG are passed to fprintf. */
+
+void
+fatal (string, arg)
+ char *string;
+ int arg;
+{
+ fprintf (stderr, "gdb: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Print an error message and exit, dumping core.
+ STRING is a printf-style control string, and ARG is a corresponding
+ argument. */
+void
+fatal_dump_core (string, arg)
+ char *string;
+ int arg;
+{
+ /* "internal error" is always correct, since GDB should never dump
+ core, no matter what the input. */
+ fprintf (stderr, "gdb internal error: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ /* We should never get here, but just in case... */
+ exit (1);
+}
+
+/* Make a copy of the string at PTR with SIZE characters
+ (and add a null character at the end in the copy).
+ Uses malloc to get the space. Returns the address of the copy. */
+
+char *
+savestring (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) xmalloc (size + 1);
+ bcopy (ptr, p, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) xmalloc (len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+void
+print_spaces (n, file)
+ register int n;
+ register FILE *file;
+{
+ while (n-- > 0)
+ fputc (' ', file);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+ Takes three args which are given to printf to print the question.
+ The first, a control string, should end in "? ".
+ It should not say how to answer, because we do that. */
+
+int
+query (ctlstr, arg1, arg2)
+ char *ctlstr;
+{
+ register int answer;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ while (1)
+ {
+ printf (ctlstr, arg1, arg2);
+ printf ("(y or n) ");
+ fflush (stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer != '\n')
+ while (fgetc (stdin) != '\n') clearerr (stdin);
+ if (answer >= 'a')
+ answer -= 040;
+ if (answer == 'Y')
+ return 1;
+ if (answer == 'N')
+ return 0;
+ printf ("Please answer y or n.\n");
+ }
+}
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'e':
+ return 033;
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+ {
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+/* Print the character CH on STREAM as part of the contents
+ of a literal string whose delimiter is QUOTER. */
+
+void
+printchar (ch, stream, quoter)
+ unsigned char ch;
+ FILE *stream;
+ int quoter;
+{
+ register int c = ch;
+ if (c < 040 || c >= 0177)
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ else
+ {
+ if (c == '\\' || c == quoter)
+ fputs_filtered ("\\", stream);
+ fprintf_filtered (stream, "%c", c);
+ }
+}
+
+static int lines_per_page, lines_printed, chars_per_line, chars_printed;
+
+/* Set values of page and line size. */
+static void
+set_screensize_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *p = arg;
+ char *p1;
+ int tolinesize = lines_per_page;
+ int tocharsize = chars_per_line;
+
+ if (p == 0)
+ error_no_arg ("set screensize");
+
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (*p && *p != ' ' && *p != '\t')
+ error ("Non-integral argument given to \"set screensize\".");
+
+ tolinesize = atoi (arg);
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+
+ if (*p1)
+ error ("Non-integral second argument given to \"set screensize\".");
+
+ tocharsize = atoi (p);
+ }
+
+ lines_per_page = tolinesize;
+ chars_per_line = tocharsize;
+}
+
+static void
+instream_cleanup(stream)
+ FILE *stream;
+{
+ instream = stream;
+}
+
+static void
+prompt_for_continue ()
+{
+ if (ISATTY(stdin) && ISATTY(stdout))
+ {
+ struct cleanup *old_chain = make_cleanup(instream_cleanup, instream);
+ char *cp, *gdb_readline();
+
+ instream = stdin;
+ immediate_quit++;
+ if (cp = gdb_readline ("---Type <return> to continue---"))
+ free(cp);
+ chars_printed = lines_printed = 0;
+ immediate_quit--;
+ do_cleanups(old_chain);
+ }
+}
+
+/* Reinitialize filter; ie. tell it to reset to original values. */
+
+void
+reinitialize_more_filter ()
+{
+ lines_printed = 0;
+ chars_printed = 0;
+}
+
+static void
+screensize_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info screensize\" does not take any arguments.");
+
+ if (!lines_per_page)
+ printf ("Output more filtering is disabled.\n");
+ else
+ {
+ printf ("Output more filtering is enabled with\n");
+ printf ("%d lines per page and %d characters per line.\n",
+ lines_per_page, chars_per_line);
+ }
+}
+
+/* Like fputs but pause after every screenful.
+ Unlike fputs, fputs_filtered does not return a value.
+ It is OK for LINEBUFFER to be NULL, in which case just don't print
+ anything.
+
+ Note that a longjmp to top level may occur in this routine
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+void
+fputs_filtered (linebuffer, stream)
+ char *linebuffer;
+ FILE *stream;
+{
+ char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if (stream != stdout || !ISATTY(stdout) || lines_per_page == 0)
+ {
+ fputs (linebuffer, stream);
+ return;
+ }
+
+ /* Go through and output each character. Show line extension
+ when this is necessary; prompt user for new page when this is
+ necessary. */
+
+ lineptr = linebuffer;
+ while (*lineptr)
+ {
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ while (*lineptr && *lineptr != '\n')
+ {
+ /* Print a single line. */
+ if (*lineptr == '\t')
+ {
+ putc ('\t', stream);
+ /* Shifting right by 3 produces the number of tab stops
+ we have already passed, and then adding one and
+ shifting left 3 advances to the next tab stop. */
+ chars_printed = ((chars_printed >> 3) + 1) << 3;
+ lineptr++;
+ }
+ else
+ {
+ putc (*lineptr, stream);
+ chars_printed++;
+ lineptr++;
+ }
+
+ if (chars_printed >= chars_per_line)
+ {
+ chars_printed = 0;
+ lines_printed++;
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+ }
+ }
+
+ if (*lineptr == '\n')
+ {
+ lines_printed++;
+ putc ('\n', stream);
+ lineptr++;
+ chars_printed = 0;
+ }
+ }
+}
+
+/* fputs_demangled is a variant of fputs_filtered that
+ demangles g++ names.*/
+
+void
+fputs_demangled (linebuffer, stream, arg_mode)
+ char *linebuffer;
+ FILE *stream;
+{
+#ifdef __STDC__
+ extern char *cplus_demangle (const char *, int);
+#else
+ extern char *cplus_demangle ();
+#endif
+#define SYMBOL_MAX 1024
+
+#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
+
+ char buf[SYMBOL_MAX+1];
+ char *p;
+
+ if (linebuffer == NULL)
+ return;
+
+ p = linebuffer;
+
+ while ( *p != (char) 0 ) {
+ int i = 0;
+
+ /* collect non-interesting characters into buf */
+ while ( *p != (char) 0 && !SYMBOL_CHAR(*p) ) {
+ buf[i++] = *p;
+ p++;
+ }
+ if (i > 0) {
+ /* output the non-interesting characters without demangling */
+ buf[i] = (char) 0;
+ fputs_filtered(buf, stream);
+ i = 0; /* reset buf */
+ }
+
+ /* and now the interesting characters */
+ while (i < SYMBOL_MAX && *p != (char) 0 && SYMBOL_CHAR(*p) ) {
+ buf[i++] = *p;
+ p++;
+ }
+ buf[i] = (char) 0;
+ if (i > 0) {
+ char * result;
+
+ if ( (result = cplus_demangle(buf, arg_mode)) != NULL ) {
+ fputs_filtered(result, stream);
+ free(result);
+ }
+ else {
+ fputs_filtered(buf, stream);
+ }
+ }
+ }
+}
+
+/* Print ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this
+ information is going to put the amount written since the last call
+ to INIIALIZE_MORE_FILTER or the last page break over the page size,
+ print out a pause message and do a gdb_readline to get the users
+ permision to continue.
+
+ Unlike fprintf, this function does not return a value.
+
+ Note that this routine has a restriction that the length of the
+ final output line must be less than 255 characters *or* it must be
+ less than twice the size of the format string. This is a very
+ arbitrary restriction, but it is an internal restriction, so I'll
+ put it in. This means that the %s format specifier is almost
+ useless; unless the caller can GUARANTEE that the string is short
+ enough, fputs_filtered should be used instead.
+
+ Note also that a longjmp to top level may occur in this routine
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+void
+fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6)
+ FILE *stream;
+ char *format;
+ int arg1, arg2, arg3, arg4, arg5, arg6;
+{
+ static char *linebuffer = (char *) 0;
+ static int line_size;
+ int format_length = strlen (format);
+ int numchars;
+
+ /* Allocated linebuffer for the first time. */
+ if (!linebuffer)
+ {
+ linebuffer = (char *) xmalloc (255);
+ line_size = 255;
+ }
+
+ /* Reallocate buffer to a larger size if this is necessary. */
+ if (format_length * 2 > line_size)
+ {
+ line_size = format_length * 2;
+
+ /* You don't have to copy. */
+ free (linebuffer);
+ linebuffer = (char *) xmalloc (line_size);
+ }
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ (void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
+
+ fputs_filtered (linebuffer, stream);
+}
+
+void
+printf_filtered (format, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *format;
+ int arg1, arg2, arg3, arg4, arg5, arg6;
+{
+ fprintf_filtered (stdout, format, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+/* Print N spaces. */
+void
+print_spaces_filtered (n, stream)
+ int n;
+ FILE *stream;
+{
+ register char *s = (char *) alloca (n + 1);
+ register char *t = s;
+
+ while (n--)
+ *t++ = ' ';
+ *t = '\0';
+
+ fputs_filtered (s, stream);
+}
+
+
+#ifdef USG
+bcopy (from, to, count)
+char *from, *to;
+{
+ memcpy (to, from, count);
+}
+
+bcmp (from, to, count)
+{
+ return (memcmp (to, from, count));
+}
+
+bzero (to, count)
+char *to;
+{
+ while (count--)
+ *to++ = 0;
+}
+
+getwd (buf)
+char *buf;
+{
+ getcwd (buf, MAXPATHLEN);
+}
+
+char *
+index (s, c)
+ char *s;
+{
+ char *strchr ();
+ return strchr (s, c);
+}
+
+char *
+rindex (s, c)
+ char *s;
+{
+ char *strrchr ();
+ return strrchr (s, c);
+}
+
+#ifndef USG
+char *sys_siglist[32] = {
+ "SIG0",
+ "SIGHUP",
+ "SIGINT",
+ "SIGQUIT",
+ "SIGILL",
+ "SIGTRAP",
+ "SIGIOT",
+ "SIGEMT",
+ "SIGFPE",
+ "SIGKILL",
+ "SIGBUS",
+ "SIGSEGV",
+ "SIGSYS",
+ "SIGPIPE",
+ "SIGALRM",
+ "SIGTERM",
+ "SIGUSR1",
+ "SIGUSR2",
+ "SIGCLD",
+ "SIGPWR",
+ "SIGWIND",
+ "SIGPHONE",
+ "SIGPOLL",
+};
+#endif
+
+/* Queue routines */
+
+struct queue {
+ struct queue *forw;
+ struct queue *back;
+};
+
+insque (item, after)
+struct queue *item;
+struct queue *after;
+{
+ item->forw = after->forw;
+ after->forw->back = item;
+
+ item->back = after;
+ after->forw = item;
+}
+
+remque (item)
+struct queue *item;
+{
+ item->forw->back = item->back;
+ item->back->forw = item->forw;
+}
+#endif /* USG */
+
+#ifdef USG
+/* There is too much variation in Sys V signal numbers and names, so
+ we must initialize them at runtime. */
+static char undoc[] = "(undocumented)";
+
+char *sys_siglist[NSIG];
+#endif /* USG */
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_utils ()
+{
+ int i;
+ add_cmd ("screensize", class_support, set_screensize_command,
+ "Change gdb's notion of the size of the output screen.\n\
+The first argument is the number of lines on a page.\n\
+The second argument (optional) is the number of characters on a line.",
+ &setlist);
+ add_info ("screensize", screensize_info,
+ "Show gdb's current notion of the size of the output screen.");
+
+ /* These defaults will be used if we are unable to get the correct
+ values from termcap. */
+ lines_per_page = 24;
+ chars_per_line = 80;
+ /* Initialize the screen height and width from termcap. */
+ {
+ int termtype = getenv ("TERM");
+
+ /* Positive means success, nonpositive means failure. */
+ int status;
+
+ /* 2048 is large enough for all known terminals, according to the
+ GNU termcap manual. */
+ char term_buffer[2048];
+
+ if (termtype)
+ {
+ status = tgetent (term_buffer, termtype);
+ if (status > 0)
+ {
+ int val;
+
+ val = tgetnum ("li");
+ if (val >= 0)
+ lines_per_page = val;
+ else
+ /* The number of lines per page is not mentioned
+ in the terminal description. This probably means
+ that paging is not useful (e.g. emacs shell window),
+ so disable paging. */
+ lines_per_page = 0;
+
+ val = tgetnum ("co");
+ if (val >= 0)
+ chars_per_line = val;
+ }
+ }
+ }
+
+#ifdef USG
+ /* Initialize signal names. */
+ for (i = 0; i < NSIG; i++)
+ sys_siglist[i] = undoc;
+
+#ifdef SIGHUP
+ sys_siglist[SIGHUP ] = "SIGHUP";
+#endif
+#ifdef SIGINT
+ sys_siglist[SIGINT ] = "SIGINT";
+#endif
+#ifdef SIGQUIT
+ sys_siglist[SIGQUIT ] = "SIGQUIT";
+#endif
+#ifdef SIGILL
+ sys_siglist[SIGILL ] = "SIGILL";
+#endif
+#ifdef SIGTRAP
+ sys_siglist[SIGTRAP ] = "SIGTRAP";
+#endif
+#ifdef SIGIOT
+ sys_siglist[SIGIOT ] = "SIGIOT";
+#endif
+#ifdef SIGEMT
+ sys_siglist[SIGEMT ] = "SIGEMT";
+#endif
+#ifdef SIGFPE
+ sys_siglist[SIGFPE ] = "SIGFPE";
+#endif
+#ifdef SIGKILL
+ sys_siglist[SIGKILL ] = "SIGKILL";
+#endif
+#ifdef SIGBUS
+ sys_siglist[SIGBUS ] = "SIGBUS";
+#endif
+#ifdef SIGSEGV
+ sys_siglist[SIGSEGV ] = "SIGSEGV";
+#endif
+#ifdef SIGSYS
+ sys_siglist[SIGSYS ] = "SIGSYS";
+#endif
+#ifdef SIGPIPE
+ sys_siglist[SIGPIPE ] = "SIGPIPE";
+#endif
+#ifdef SIGALRM
+ sys_siglist[SIGALRM ] = "SIGALRM";
+#endif
+#ifdef SIGTERM
+ sys_siglist[SIGTERM ] = "SIGTERM";
+#endif
+#ifdef SIGUSR1
+ sys_siglist[SIGUSR1 ] = "SIGUSR1";
+#endif
+#ifdef SIGUSR2
+ sys_siglist[SIGUSR2 ] = "SIGUSR2";
+#endif
+#ifdef SIGCLD
+ sys_siglist[SIGCLD ] = "SIGCLD";
+#endif
+#ifdef SIGCHLD
+ sys_siglist[SIGCHLD ] = "SIGCHLD";
+#endif
+#ifdef SIGPWR
+ sys_siglist[SIGPWR ] = "SIGPWR";
+#endif
+#ifdef SIGTSTP
+ sys_siglist[SIGTSTP ] = "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+ sys_siglist[SIGTTIN ] = "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+ sys_siglist[SIGTTOU ] = "SIGTTOU";
+#endif
+#ifdef SIGSTOP
+ sys_siglist[SIGSTOP ] = "SIGSTOP";
+#endif
+#ifdef SIGXCPU
+ sys_siglist[SIGXCPU ] = "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+ sys_siglist[SIGXFSZ ] = "SIGXFSZ";
+#endif
+#ifdef SIGVTALRM
+ sys_siglist[SIGVTALRM ] = "SIGVTALRM";
+#endif
+#ifdef SIGPROF
+ sys_siglist[SIGPROF ] = "SIGPROF";
+#endif
+#ifdef SIGWINCH
+ sys_siglist[SIGWINCH ] = "SIGWINCH";
+#endif
+#ifdef SIGCONT
+ sys_siglist[SIGCONT ] = "SIGCONT";
+#endif
+#ifdef SIGURG
+ sys_siglist[SIGURG ] = "SIGURG";
+#endif
+#ifdef SIGIO
+ sys_siglist[SIGIO ] = "SIGIO";
+#endif
+#ifdef SIGWIND
+ sys_siglist[SIGWIND ] = "SIGWIND";
+#endif
+#ifdef SIGPHONE
+ sys_siglist[SIGPHONE ] = "SIGPHONE";
+#endif
+#ifdef SIGPOLL
+ sys_siglist[SIGPOLL ] = "SIGPOLL";
+#endif
+#endif /* USG */
+}
diff --git a/gnu/usr.bin/gdb/valarith.c b/gnu/usr.bin/kgdb/valarith.c
index 8e76899884b8..8e76899884b8 100644
--- a/gnu/usr.bin/gdb/valarith.c
+++ b/gnu/usr.bin/kgdb/valarith.c
diff --git a/gnu/usr.bin/gdb/valops.c b/gnu/usr.bin/kgdb/valops.c
index ab5652cc187a..ab5652cc187a 100644
--- a/gnu/usr.bin/gdb/valops.c
+++ b/gnu/usr.bin/kgdb/valops.c
diff --git a/gnu/usr.bin/gdb/valprint.c b/gnu/usr.bin/kgdb/valprint.c
index 781eb296d391..781eb296d391 100644
--- a/gnu/usr.bin/gdb/valprint.c
+++ b/gnu/usr.bin/kgdb/valprint.c
diff --git a/gnu/usr.bin/gdb/value.h b/gnu/usr.bin/kgdb/value.h
index 07dd8e840eb7..07dd8e840eb7 100644
--- a/gnu/usr.bin/gdb/value.h
+++ b/gnu/usr.bin/kgdb/value.h
diff --git a/gnu/usr.bin/gdb/values.c b/gnu/usr.bin/kgdb/values.c
index 93a291112a65..93a291112a65 100644
--- a/gnu/usr.bin/gdb/values.c
+++ b/gnu/usr.bin/kgdb/values.c
diff --git a/gnu/usr.bin/gdb/version.c b/gnu/usr.bin/kgdb/version.c
index 2f3dd8504301..2f3dd8504301 100644
--- a/gnu/usr.bin/gdb/version.c
+++ b/gnu/usr.bin/kgdb/version.c
diff --git a/gnu/usr.bin/gdb/wait.h b/gnu/usr.bin/kgdb/wait.h
index c431cb6a47a9..c431cb6a47a9 100644
--- a/gnu/usr.bin/gdb/wait.h
+++ b/gnu/usr.bin/kgdb/wait.h
diff --git a/gnu/usr.bin/gdb/xgdb/Makefile b/gnu/usr.bin/kgdb/xgdb/Makefile
index 72c53598dd27..72c53598dd27 100644
--- a/gnu/usr.bin/gdb/xgdb/Makefile
+++ b/gnu/usr.bin/kgdb/xgdb/Makefile
diff --git a/gnu/usr.bin/kgdb/xgdb/xgdb.c b/gnu/usr.bin/kgdb/xgdb/xgdb.c
new file mode 100644
index 000000000000..ceba5fdcc2d1
--- /dev/null
+++ b/gnu/usr.bin/kgdb/xgdb/xgdb.c
@@ -0,0 +1,700 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * static char rcsid[] = "$Header: /home/cvs/386BSD/src/gnu/usr.bin/kgdb/xgdb/xgdb.c,v 1.1 1993/06/29 09:48:26 nate Exp $";
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/*
+ * Interface from GDB to X windows. Copyright (C) 1987 Free Software
+ * Foundation, Inc.
+ *
+ * GDB 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 GDB
+ * General Public License for full details.
+ *
+ * Everyone is granted permission to copy, modify and redistribute GDB, but only
+ * under the conditions described in the GDB General Public License. A copy
+ * of this license is supposed to have been given to you along with GDB 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.
+ *
+ * In other words, go ahead and share GDB, but don't try to stop anyone else
+ * from sharing it farther. Help stamp out software hoarding!
+ */
+
+/*
+ * Original version was contributed by Derek Beatty, 30 June 87.
+ * This version is essentially a re-write of the original by Van
+ * Jacobson (van@helios.ee.lbl.gov), Nov, 90.
+ */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+extern int stop_breakpoint;
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/AsciiSink.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Text.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+
+extern int errno;
+extern char *getenv();
+extern char *malloc();
+extern void bcopy();
+extern int select();
+
+extern int get_filename_and_charpos();
+extern int source_line_charpos();
+extern int source_charpos_line();
+extern void execute_command();
+extern void error_no_arg();
+extern void add_com();
+
+/* The X display where the window appears. */
+
+static char *displayname;
+static Display *display;
+
+static XtAppContext app_context;
+
+/* Windows manipulated by this package. */
+
+static Widget main_widget;
+static Widget containing_widget;
+static Widget source_name_widget;
+static Widget source_text_widget;
+static Widget button_box_widget;
+
+/* Source text display. */
+
+static struct frame_info *last_fi;
+static CORE_ADDR last_pc;
+static struct symtab *last_cur_symtab;
+static int last_cur_line;
+
+static int source_window_line;
+static char *source_window_file;
+static struct symtab *source_window_symtab;
+
+static char version_label[64];
+extern char *version;
+
+/* Forward declarations */
+
+static Widget create_text_widget();
+
+static int
+safe_strcmp(a, b)
+ register char *a, *b;
+{
+ register int i;
+
+ if (a == b)
+ return (0);
+ if (!a && b)
+ return (1);
+ if (a && !b)
+ return (-1);
+ return (strcmp(a, b));
+}
+
+
+/* Display an appropriate piece of source code in the source window. */
+
+void
+xgdb_display_source()
+{
+ char *filename = NULL;
+ struct symtab_and_line get_selected_frame_sal();
+ struct symtab_and_line sal;
+ struct frame_info *fi;
+
+ /* Do nothing if called before we are initialized */
+
+ if (!containing_widget)
+ return;
+
+ /*
+ * Figure out what to display (the appropriate hooks to tell
+ * us don't exist so we guess): If there's a current frame
+ * and it or its pc changed from the last time we were here,
+ * display appropriate source line. Otherwise if the current
+ * source symtab or line is different, display that line.
+ * Otherwise nothing changed so leave the display alone.
+ */
+ fi = get_frame_info(selected_frame);
+ if (fi && (fi != last_fi || fi->pc != last_pc)) {
+ last_fi = fi;
+ last_pc = fi->pc;
+ sal = find_pc_line(fi->pc, fi->next_frame);
+ if (sal.symtab == NULL) { /* XXX */
+ sal.symtab = current_source_symtab;
+ sal.line = current_source_line;
+ }
+ current_source_symtab = sal.symtab;
+ current_source_line = sal.line;
+ } else if (current_source_symtab != last_cur_symtab ||
+ current_source_line != last_cur_line) {
+ sal.symtab = last_cur_symtab = current_source_symtab;
+ sal.line = last_cur_line = current_source_line;
+ } else
+ return;
+ /*
+ * Do a path search and get the exact filename of this source file.
+ * Also scan it and find its source lines if not already done.
+ */
+ if (sal.symtab && filename == NULL) {
+ if (get_filename_and_charpos(sal.symtab, sal.line, &filename))
+ /* line numbers may have changed - force highlight */
+ source_window_line = -1;
+ }
+
+ /*
+ * If the source window is wrong, destroy it and make a new one.
+ */
+ if (safe_strcmp(filename, source_window_file)) {
+ Arg args[1];
+ Widget src = XawTextGetSource(source_text_widget);
+
+ if (filename) {
+ XtSetArg(args[0], XtNstring, filename);
+ XtSetValues(src, args, XtNumber(args));
+ args[0].name = XtNlabel;
+ XtSetValues(source_name_widget, args, XtNumber(args));
+ } else {
+ XtSetArg(args[0], XtNstring, "/dev/null");
+ XtSetValues(src, args, XtNumber(args));
+ XtSetArg(args[0], XtNlabel, "");
+ XtSetValues(source_name_widget, args, XtNumber(args));
+ }
+ if (source_window_file)
+ free(source_window_file);
+ source_window_file = filename;
+ source_window_line = sal.line + 1; /* force highlight */
+ }
+ if (sal.symtab && source_window_line != sal.line) {
+ /*
+ * Update display and cursor positions as necessary.
+ * Cursor should be placed on line sal.line.
+ */
+ XawTextPosition l, r;
+
+ source_window_symtab = sal.symtab;
+ source_window_line = sal.line;
+ l = source_line_charpos(source_window_symtab, sal.line);
+ r = source_line_charpos(source_window_symtab, sal.line + 1);
+ if (r < l)
+ r = l + 1;
+ XawTextSetSelection(source_text_widget, l, r);
+ XawTextScrollToLine(source_text_widget, l, 10, 3);
+ XawTextSetInsertionPoint(source_text_widget, l);
+ }
+}
+
+
+/*
+ * Handlers for buttons.
+ */
+
+static int
+current_lineno()
+{
+ XawTextPosition start, finish;
+
+ XawTextGetSelectionPos(source_text_widget, &start, &finish);
+ if (start >= finish)
+ start = XawTextGetInsertionPoint(source_text_widget);
+
+ return (source_charpos_line(source_window_symtab, start));
+}
+
+static char *
+append_selection(cp)
+ char *cp;
+{
+ int len;
+ XawTextPosition l, r;
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if ((len = r - l) > 0) {
+ Widget src = XawTextGetSource(source_text_widget);
+
+ while (len > 0) {
+ XawTextBlock tb;
+
+ XawTextSourceRead(src, l, &tb, len);
+ bcopy(tb.ptr, cp, tb.length);
+ cp += tb.length;
+ len -= tb.length;
+ }
+ if (cp[-1] == 0)
+ --cp;
+ }
+ return (cp);
+}
+
+static char *
+append_selection_word(cp)
+ register char *cp;
+{
+ register int len;
+ XawTextPosition l, r;
+ XawTextBlock tb;
+ register char c;
+ register Widget src = XawTextGetSource(source_text_widget);
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if ((len = r - l) <= 0) {
+ l = XawTextGetInsertionPoint(source_text_widget);
+ len = 128; /* XXX */
+
+ /* might have clicked in middle of word -- back up to start */
+ for ( ; l > 0; --l) {
+ XawTextSourceRead(src, l - 1, &tb, 1);
+ c = tb.ptr[0];
+ if (! isalnum(c) && c != '_' && c != '$')
+ break;
+ }
+ }
+ while (len > 0) {
+ char *sp;
+ int i;
+
+ XawTextSourceRead(src, l, &tb, len);
+ for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
+ c = *sp++;
+ if (!isalnum(c) && c != '_' && c != '$')
+ return (cp);
+ *cp++ = c;
+ }
+ len -= tb.length;
+ }
+ return (cp);
+}
+
+static char *
+append_selection_expr(cp)
+ char *cp;
+{
+ int len;
+ XawTextPosition l, r;
+ Widget src = XawTextGetSource(source_text_widget);
+ XawTextBlock tb;
+ char *sp;
+ char c;
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if (r > l)
+ return (append_selection(cp));
+
+ l = XawTextGetInsertionPoint(source_text_widget);
+
+ /* might have clicked in middle of word -- back up to start */
+ for ( ; l > 0; --l) {
+ XawTextSourceRead(src, l - 1, &tb, 1);
+ c = tb.ptr[0];
+ if (! isalnum(c) && c != '_' && c != '$')
+ break;
+ }
+
+ len = 128; /* XXX */
+ while (len > 0) {
+ int i;
+ char pstack[64];
+ int pcnt = 0;
+
+ XawTextSourceRead(src, l, &tb, len);
+ for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
+ switch (c = *sp++) {
+ case '\n':
+ case ';':
+ return (cp);
+ case '=':
+ if (cp[-1] != '=')
+ return (cp - 1);
+ if (len == 128)
+ return (cp);
+ break;
+ case ',':
+ if (pcnt <= 0)
+ return (cp);
+ break;
+ case '(':
+ pstack[pcnt] = ')';
+ if (++pcnt >= sizeof(pstack))
+ return (cp);
+ break;
+ case '[':
+ pstack[pcnt] = ']';
+ if (++pcnt >= sizeof(pstack))
+ return (cp);
+ break;
+ case ')':
+ case ']':
+ if (--pcnt < 0 || pstack[pcnt] != c)
+ return (cp);
+ break;
+ }
+ *cp++ = c;
+ }
+ len -= tb.length;
+ }
+ return (cp);
+}
+
+static int input_avail; /* XXX kluge: do_command sets this when command
+ * data from button is avaialble to force top level
+ * to break out of its loop. */
+/*
+ * Handle a button by running the command COMMAND.
+ */
+static void
+do_command(w, command, call_data)
+ Widget w;
+ register char *command;
+ caddr_t call_data;
+{
+ char cmd_line[256];
+ char buf[256];
+ register char *out = cmd_line;
+ char *cp;
+ register char c;
+ extern char *finish_command_input();
+
+ while (c = *command++) {
+ if (c == '%') {
+ switch (*command++) {
+ case 's': /* current selection */
+ out = append_selection(out);
+ break;
+ case 'S': /* 1st selected "word" at curor */
+ out = append_selection_word(out);
+ break;
+ case 'e': /* echo cmd before executing */
+ break;
+ case 'E': /* 1st selected expression at curor */
+ out = append_selection_expr(out);
+ break;
+
+ case 'l': /* current line number */
+ (void) sprintf(buf, "%d", current_lineno());
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'L': /* line we're stopped at */
+ (void) sprintf(buf, "%d", source_window_line);
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'f': /* current file name */
+ for (cp = source_window_symtab->filename;
+ c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'b': /* break # we're stopped at */
+ if (stop_breakpoint <= 0)
+ /* if no breakpoint, don't do cmd */
+ return;
+
+ (void) sprintf(buf, "%d", stop_breakpoint);
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ }
+ } else
+ *out++ = c;
+ }
+ *out = 0;
+ reinitialize_more_filter();
+ /* have to exit via readline or tty modes stay messed up */
+ for (cp = cmd_line; c = *cp++; )
+ rl_stuff_char(c);
+ rl_stuff_char('\n');
+ input_avail = 1;
+}
+
+/*
+ * Define and display all the buttons.
+ */
+static void
+addbutton(parent, name, function, closure)
+ Widget parent;
+ char *name;
+ void (*function) ();
+ caddr_t closure;
+{
+ static XtCallbackRec Callback[] = {
+ {NULL, (caddr_t) NULL},
+ {NULL, (caddr_t) NULL},
+ };
+ static Arg commandArgs[] = {
+ {XtNlabel, (XtArgVal) NULL},
+ {XtNcallback, (XtArgVal) Callback},
+ };
+ Widget w;
+ char wname[128];
+ register char *cp;
+
+ strcpy(wname, name);
+ while ((cp = index(wname, '*')) || (cp = index(wname, '.')))
+ *cp -= 0x10;
+
+ if (w = XtNameToWidget(parent, wname))
+ XtDestroyWidget(w);
+
+ Callback[0].callback = (XtCallbackProc) function;
+ Callback[0].closure = (caddr_t) closure;
+ commandArgs[0].value = (XtArgVal) name;
+ XtCreateManagedWidget(wname, commandWidgetClass, parent,
+ commandArgs, XtNumber(commandArgs));
+}
+
+/*
+ * Create the button windows and store them in `buttons'.
+ */
+static void
+create_buttons(parent)
+ Widget parent;
+{
+ addbutton(parent, "quit", do_command, "quit");
+}
+
+static void
+button_command(arg)
+ char *arg;
+{
+ char *label;
+ unsigned int len;
+
+ if (! arg)
+ error_no_arg("button label and command");
+
+ for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
+ ;
+ if (len == 0)
+ error_no_arg("button label and command");
+ arg[len] = 0;
+
+ /* make a copy of button label & command for toolkit to use */
+ label = malloc(len + 1);
+ strcpy(label, arg);
+
+ /* find the end of the label */
+ if (*label == '"') {
+ if ((arg = index(++label, '"')) == 0) {
+ printf("button label missing closing quote\n");
+ return;
+ }
+ *arg++ = 0;
+ } else if (arg = index(label, ' '))
+ *arg++ = 0;
+ else
+ arg = label;
+
+ while (*arg && isspace(*arg))
+ ++arg;
+
+ addbutton(button_box_widget, label, do_command, arg);
+}
+
+static void
+button_delete_command(arg)
+ char *arg;
+{
+ unsigned int len;
+ Widget w;
+ register char *cp;
+
+ if (! arg)
+ error_no_arg("button name");
+
+ for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
+ ;
+ if (len == 0)
+ error_no_arg("button name");
+ arg[len] = 0;
+
+ /* find the end of the label */
+ if (*arg == '"') {
+ if ((cp = index(++arg, '"')) == 0) {
+ printf("button label missing closing quote\n");
+ return;
+ }
+ *cp++ = 0;
+ }
+ while ((cp = index(arg, '*')) || (cp = index(arg, '.')))
+ *cp -= 0x10;
+
+ if (w = XtNameToWidget(button_box_widget, arg))
+ XtDestroyWidget(w);
+}
+
+/*
+ * Create a "label window" that just displays the string LABEL.
+ */
+static Widget
+create_label(name, label)
+ char *name, *label;
+{
+ Arg args[1];
+ Widget w;
+
+ XtSetArg(args[0], XtNlabel, label);
+ w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget,
+ args, XtNumber(args));
+ return (w);
+}
+
+/*
+ * Create a subwindow of PARENT that displays and scrolls the contents of
+ * file FILENAME.
+ */
+static Widget
+create_text_widget(parent, filename)
+ Widget parent;
+ char *filename;
+{
+ static Arg arg[] = {
+ {XtNstring, NULL},
+ {XtNtype, XawAsciiFile},
+ {XtNcursor, None},
+ };
+ Widget text_widget;
+
+ arg[0].value = (XtArgVal)filename;
+ text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass,
+ parent, arg, XtNumber(arg));
+ return (text_widget);
+}
+
+/*
+ * Entry point to create the widgets representing our display.
+ */
+void
+xgdb_create_window()
+{
+ /* initialize toolkit, setup defaults */
+#ifdef notyet
+ main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
+ argcptr, argv, NULL, NULL, 0);
+#else
+ char *dummy_argv[] = { "xgdb", 0 };
+ int dummy_argc = 1;
+ main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
+ &dummy_argc, dummy_argv, NULL, NULL, 0);
+#endif
+ display = XtDisplay(main_widget);
+ containing_widget = XtCreateManagedWidget("frame", panedWidgetClass,
+ main_widget, NULL, 0);
+
+ sprintf(version_label, "XGDB %s", version);
+ button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass,
+ containing_widget, NULL, 0);
+ create_buttons(button_box_widget);
+ source_name_widget = create_label("srcLabel", "No source file yet.");
+ source_text_widget = create_text_widget(containing_widget, "/dev/null");
+
+ XtRealizeWidget(main_widget);
+ XFlush(display);
+}
+
+/*
+ * If we use an X window, the readline input loop is told to call
+ * this function before reading a character from stdin.
+ */
+/*ARGSUSED*/
+static void
+xgdb_window_hook()
+{
+ register int inmask = 1 << fileno(stdin);
+ register int xmask = 1 << ConnectionNumber(display);
+ register int nfds, pend;
+ int input_rfds;
+ XEvent ev;
+
+ /*
+ * Display our current idea of the `interesting' source file then
+ * loop, dispatching window events until data is available on
+ * stdin. Then return so the input data can be processed.
+ */
+ input_avail = 0;
+ xgdb_display_source();
+
+ input_rfds = 0;
+ while (input_avail == 0 && (input_rfds & inmask) == 0) {
+ pend = XPending(display);
+ if (!pend) {
+ input_rfds = inmask | xmask;
+ nfds = select(32, &input_rfds, 0, 0,
+ (struct timeval *)0);
+ if (nfds == -1 && errno == EINTR)
+ continue;
+ }
+ if (pend || (input_rfds & xmask)) {
+ XNextEvent(display, &ev);
+ XtDispatchEvent(&ev);
+ }
+ }
+}
+
+void
+_initialize_xgdb()
+{
+ extern void (*window_hook) ();
+ extern int inhibit_windows;
+ extern struct cmd_list_element *deletelist;
+
+ if (inhibit_windows)
+ return;
+
+ if (! displayname) {
+ displayname = getenv("DISPLAY");
+ if (! displayname) {
+ fprintf(stderr, "xgdb: no display name\n");
+ inhibit_windows = 1;
+ return;
+ }
+ }
+ xgdb_create_window();
+ window_hook = xgdb_window_hook;
+ add_com("button", class_support, button_command,
+"Add command button to xgdb window. First argument is button\n\
+label, second is command associated with button. Command can\n\
+include printf-like escapes:\n\
+ %s for current selection,\n\
+ %S for first 'word' of current selection,\n\
+ %e for current selection or expression at insertion pt,\n\
+ %E for current selection or expression at insertion pt,\n\
+ %l for current line number,\n\
+ %L for line program stopped at,\n\
+ %f for current file name,\n\
+ %b for current breakpoint number.");
+ add_cmd("button", class_support, button_delete_command,
+"Delete a button from the xgdb window.\n\
+Argument is name of button to be deleted.",
+ &deletelist);
+}
diff --git a/gnu/usr.bin/ld/etc.c b/gnu/usr.bin/ld/etc.c
index 27e2c5661895..b33db7618eda 100644
--- a/gnu/usr.bin/ld/etc.c
+++ b/gnu/usr.bin/ld/etc.c
@@ -1,151 +1,66 @@
/*
- * $Id: etc.c,v 1.7 1994/02/13 20:41:05 jkh Exp $
+ * $Id: etc.c,v 1.8 1994/06/15 22:39:32 rich Exp $
*/
-#include <sys/param.h>
-#include <stdio.h>
+#include <err.h>
#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <ar.h>
-#include <ranlib.h>
-#include <a.out.h>
-#include <stab.h>
#include <string.h>
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-#include "ld.h"
/*
- * Report a nonfatal error.
+ * Like malloc but get fatal error if memory is exhausted.
*/
-
-void
-#if __STDC__
-error(char *fmt, ...)
-#else
-error(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
+void *
+xmalloc(size)
+ size_t size;
{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "%s: ", progname);
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- va_end(ap);
+ register void *result = (void *)malloc(size);
+
+ if (!result)
+ errx(1, "virtual memory exhausted");
+
+ return result;
}
-void (*fatal_cleanup_hook)__P((void));
/*
- * Report a fatal error.
+ * Like realloc but get fatal error if memory is exhausted.
*/
-
-void
-#if __STDC__
-fatal(char *fmt, ...)
-#else
-fatal(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
+void *
+xrealloc(ptr, size)
+ void *ptr;
+ size_t size;
{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "%s: ", progname);
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- va_end(ap);
+ register void *result;
- if (fatal_cleanup_hook)
- (*fatal_cleanup_hook)();
- exit(1);
-}
+ if (ptr == NULL)
+ result = (void *)malloc(size);
+ else
+ result = (void *)realloc(ptr, size);
+ if (!result)
+ errx(1, "virtual memory exhausted");
+
+ return result;
+}
/*
* Return a newly-allocated string whose contents concatenate
* the strings S1, S2, S3.
*/
-
char *
concat(s1, s2, s3)
const char *s1, *s2, *s3;
{
- register int len1 = strlen (s1),
- len2 = strlen (s2),
- len3 = strlen (s3);
+ register int len1 = strlen(s1),
+ len2 = strlen(s2),
+ len3 = strlen(s3);
- register char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+ register char *result = (char *)xmalloc(len1 + len2 + len3 + 1);
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
+ strcpy(result, s1);
+ strcpy(result + len1, s2);
+ strcpy(result + len1 + len2, s3);
result[len1 + len2 + len3] = 0;
return result;
}
-/* Parse the string ARG using scanf format FORMAT, and return the result.
- If it does not parse, report fatal error
- generating the error message using format string ERROR and ARG as arg. */
-
-int
-parse(arg, format, error)
- char *arg, *format, *error;
-{
- int x;
- if (1 != sscanf (arg, format, &x))
- fatal (error, arg);
- return x;
-}
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-void *
-xmalloc(size)
- int size;
-{
- register void *result = (void *)malloc (size);
-
- if (!result)
- fatal ("virtual memory exhausted", 0);
-
- return result;
-}
-
-/* Like realloc but get fatal error if memory is exhausted. */
-
-void *
-xrealloc(ptr, size)
- void *ptr;
- int size;
-{
- register void *result;
-
- if (ptr == NULL)
- result = (void *)malloc (size);
- else
- result = (void *)realloc (ptr, size);
-
- if (!result)
- fatal ("virtual memory exhausted", 0);
-
- return result;
-}
diff --git a/gnu/usr.bin/ld/i386/md.c b/gnu/usr.bin/ld/i386/md.c
index 2e206a9eb25d..d0a7dad66b4a 100644
--- a/gnu/usr.bin/ld/i386/md.c
+++ b/gnu/usr.bin/ld/i386/md.c
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,13 +27,14 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: md.c,v 1.9 1994/02/13 20:42:09 jkh Exp $
+ * $Id: md.c,v 1.10 1994/06/15 22:40:44 rich Exp $
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <err.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
@@ -53,14 +54,13 @@ unsigned char *addr;
switch (RELOC_TARGET_SIZE(rp)) {
case 0:
return get_byte(addr);
- break;
case 1:
return get_short(addr);
- break;
case 2:
return get_long(addr);
- break;
}
+ errx(1, "Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
+ return 0;
}
/*
@@ -71,20 +71,20 @@ md_relocate(rp, relocation, addr, relocatable_output)
struct relocation_info *rp;
long relocation;
unsigned char *addr;
+int relocatable_output;
{
switch (RELOC_TARGET_SIZE(rp)) {
case 0:
put_byte(addr, relocation);
- break;
+ return;
case 1:
put_short(addr, relocation);
- break;
+ return;
case 2:
put_long(addr, relocation);
- break;
- default:
- fatal("Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
+ return;
}
+ errx(1, "Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
}
/*
diff --git a/gnu/usr.bin/ld/i386/md.h b/gnu/usr.bin/ld/i386/md.h
index f98bb5eef2a1..11ad91df591e 100644
--- a/gnu/usr.bin/ld/i386/md.h
+++ b/gnu/usr.bin/ld/i386/md.h
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: md.h,v 1.9 1994/02/13 20:42:11 jkh Exp $
+ * $Id: md.h,v 1.10 1994/06/15 22:40:46 rich Exp $
*/
diff --git a/gnu/usr.bin/ld/i386/mdprologue.S b/gnu/usr.bin/ld/i386/mdprologue.S
index b5f13520c15e..f64bb13345d5 100644
--- a/gnu/usr.bin/ld/i386/mdprologue.S
+++ b/gnu/usr.bin/ld/i386/mdprologue.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: mdprologue.S,v 1.3 1993/12/10 10:16:00 jkh Exp $
+ * $Id: mdprologue.S,v 1.4 1994/06/15 22:40:49 rich Exp $
*/
/*
diff --git a/gnu/usr.bin/ld/ld.1 b/gnu/usr.bin/ld/ld.1
index b181fd70f9cc..7642f05a717e 100644
--- a/gnu/usr.bin/ld/ld.1
+++ b/gnu/usr.bin/ld/ld.1
@@ -27,7 +27,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $Id: ld.1,v 1.5.2.1 1994/05/01 16:03:59 jkh Exp $
+.\" $Id: ld.1,v 1.7 1994/06/15 22:39:35 rich Exp $
.\"
.Dd October 14, 1993
.Dt LD 8
@@ -103,6 +103,11 @@ Force all members of archives to be loaded, whether or not such members
contribute a definition to any plain object files. Useful for making a
shared library from an archive of PIC objects without having to unpack
the archive.
+.It Fl B Ar silly
+Search for
+.Em \.sa
+silly archive companions of shared objects. Useful for compatibility with
+version 3 shared objects.
.It Fl D Ar data-size
Set the size of the data segment. For sanity's sake, this should be larger
than the cumulative data sizes of the input files.
diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c
index ac887511ebbf..f2787b6e3fc0 100644
--- a/gnu/usr.bin/ld/ld.c
+++ b/gnu/usr.bin/ld/ld.c
@@ -32,26 +32,27 @@ static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91";
Set, indirect, and warning symbol features added by Randy Smith. */
/*
- * $Id: ld.c,v 1.21 1994/02/17 03:57:00 davidg Exp $
+ * $Id: ld.c,v 1.22 1994/06/15 22:39:40 rich Exp $
*/
/* Define how to initialize system-dependent header fields. */
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
#include <fcntl.h>
#include <ar.h>
#include <ranlib.h>
#include <a.out.h>
#include <stab.h>
#include <string.h>
-#include <strings.h>
#include "ld.h"
@@ -88,6 +89,9 @@ int page_align_segments;
/* 1 => data segment must be page aligned, even if `-n' or `-N' */
int page_align_data;
+/* 1 => do not use standard library search path */
+int nostdlib;
+
/* Version number to put in __DYNAMIC (set by -V) */
int soversion;
@@ -137,15 +141,17 @@ int magic; /* Output file magic. */
int oldmagic;
int relocatable_output; /* `-r'-ed output */
-symbol *entry_symbol;
-int entry_offset;
+symbol *entry_symbol; /* specified by `-e' */
+int entry_offset; /* program entry if no `-e' given */
int page_size; /* Size of a page (machine dependent) */
-/* Keep a list of any symbols referenced from the command line (so
- that error messages for these guys can be generated). This list is
- zero terminated. */
-struct glosym **cmdline_references;
+/*
+ * Keep a list of any symbols referenced from the command line (so
+ * that error messages for these guys can be generated). This list is
+ * zero terminated.
+ */
+symbol **cmdline_references;
int cl_refs_allocated;
/*
@@ -246,20 +252,16 @@ static void write_data __P((void));
static void write_rel __P((void));
static void write_syms __P((void));
static void assign_symbolnums __P((struct file_entry *, int *));
-static void myfatal __P((void));
+static void cleanup __P((void));
+static int parse __P((char *, char *, char *));
int
main(argc, argv)
- char **argv;
int argc;
+ char *argv[];
{
- if ((progname = strrchr(argv[0], '/')) == NULL)
- progname = argv[0];
- else
- progname++;
-
/* Added this to stop ld core-dumping on very large .o files. */
#ifdef RLIMIT_STACK
/* Get rid of any avoidable limit on stack size. */
@@ -267,9 +269,13 @@ main(argc, argv)
struct rlimit rlim;
/* Set the stack limit huge so that alloca does not fail. */
- getrlimit(RLIMIT_STACK, &rlim);
+ if (getrlimit(RLIMIT_STACK, &rlim) != 0)
+ warn("getrlimit");
+ else {
rlim.rlim_cur = rlim.rlim_max;
- setrlimit(RLIMIT_STACK, &rlim);
+ if (setrlimit(RLIMIT_STACK, &rlim) != 0)
+ warn("setrlimit");
+ }
}
#endif /* RLIMIT_STACK */
@@ -321,9 +327,8 @@ main(argc, argv)
/* Keep a list of symbols referenced from the command line */
cl_refs_allocated = 10;
- cmdline_references
- = (struct glosym **) xmalloc(cl_refs_allocated
- * sizeof(struct glosym *));
+ cmdline_references = (symbol **)
+ xmalloc(cl_refs_allocated * sizeof(symbol *));
*cmdline_references = 0;
/* Completely decode ARGV. */
@@ -333,7 +338,7 @@ main(argc, argv)
(!relocatable_output && (link_mode & SHAREABLE));
if (building_shared_object && entry_symbol) {
- fatal("`-Bshareable' and `-e' options are mutually exclusive");
+ errx(1,"`-Bshareable' and `-e' options are mutually exclusive");
}
/* Create the symbols `etext', `edata' and `end'. */
@@ -347,6 +352,7 @@ main(argc, argv)
* and initialize the text size accordingly. This depends on the kind
* of system and on the output format selected.
*/
+
if (magic == ZMAGIC || magic == QMAGIC)
page_align_segments = 1;
@@ -454,7 +460,6 @@ decode_command(argc, argv)
{
register int i;
register struct file_entry *p;
- char *cp;
number_of_files = 0;
output_filename = "a.out";
@@ -469,7 +474,7 @@ decode_command(argc, argv)
register int code = classify_arg(argv[i]);
if (code) {
if (i + code > argc)
- fatal("no argument following %s\n", argv[i]);
+ errx(1, "no argument following %s", argv[i]);
decode_option(argv[i], argv[i + 1]);
@@ -482,7 +487,7 @@ decode_command(argc, argv)
}
if (!number_of_files)
- fatal("no input files");
+ errx(1, "no input files");
p = file_table = (struct file_entry *)
xmalloc(number_of_files * sizeof(struct file_entry));
@@ -526,10 +531,11 @@ decode_command(argc, argv)
}
if (argv[i][1] == 'A') {
if (p != file_table)
- fatal("-A specified before an input file other than the first");
+ errx(1, "-A specified before an input file other than the first");
p->filename = string;
p->local_sym_name = string;
p->flags |= E_JUST_SYMS;
+ link_mode &= ~DYNAMIC;
p++;
}
if (argv[i][1] == 'l') {
@@ -545,12 +551,14 @@ decode_command(argc, argv)
/* Now check some option settings for consistency. */
- if (page_align_segments
- && (text_start - text_start_alignment) & (page_size - 1))
- fatal("-T argument not multiple of page size, with sharable output");
+ if (page_align_segments &&
+ (text_start - text_start_alignment) & (page_size - 1))
+ errx(1, "-T argument not multiple of page size, with sharable output");
/* Append the standard search directories to the user-specified ones. */
- std_search_dirs(getenv("LD_LIBRARY_PATH"));
+ add_search_path(getenv("LD_LIBRARY_PATH"));
+ if (!nostdlib && getenv("LD_NOSTD_PATH") == NULL)
+ std_search_path();
}
void
@@ -567,13 +575,13 @@ add_cmdline_ref(sp)
int diff = ptr - cmdline_references;
cl_refs_allocated *= 2;
- cmdline_references = (struct glosym **)
+ cmdline_references = (symbol **)
xrealloc(cmdline_references,
- cl_refs_allocated * sizeof(struct glosym *));
+ cl_refs_allocated * sizeof(symbol *));
ptr = cmdline_references + diff;
}
*ptr++ = sp;
- *ptr = (symbol *) 0;
+ *ptr = (symbol *)0;
}
int
@@ -634,6 +642,10 @@ decode_option(swt, arg)
force_executable = 1;
return;
}
+ if (!strcmp(swt + 1, "nostdlib")) {
+ nostdlib = 1;
+ return;
+ }
if (swt[2] != 0)
arg = &swt[2];
@@ -646,12 +658,12 @@ decode_option(swt, arg)
return;
case 'd':
- if (*arg == 'c')
+ if (swt[2] == 0 || *arg == 'c')
force_common_definition = 1;
else if (*arg == 'p')
force_alias_definition = 1;
else
- fatal("-d option takes 'c' or 'p' argument");
+ errx(1, "-d option takes 'c' or 'p' argument");
return;
case 'e':
@@ -767,7 +779,7 @@ decode_option(swt, arg)
return;
default:
- fatal("invalid command option `%s'", swt);
+ errx(1, "invalid command option `%s'", swt);
}
}
@@ -783,8 +795,8 @@ decode_option(swt, arg)
void
each_file(function, arg)
- register void (*function) ();
- register int arg;
+ register void (*function)();
+ register void *arg;
{
register int i;
@@ -796,29 +808,29 @@ each_file(function, arg)
continue;
if (!(entry->flags & E_IS_LIBRARY))
- (*function) (entry, arg);
+ (*function)(entry, arg);
subentry = entry->subfiles;
for (; subentry; subentry = subentry->chain) {
if (subentry->flags & E_SCRAPPED)
continue;
- (*function) (subentry, arg);
+ (*function)(subentry, arg);
}
#ifdef SUN_COMPAT
if (entry->silly_archive) {
if (!(entry->flags & E_DYNAMIC))
- error("Silly");
+ warnx("Silly");
if (!(entry->silly_archive->flags & E_IS_LIBRARY))
- error("Sillier");
+ warnx("Sillier");
subentry = entry->silly_archive->subfiles;
for (; subentry; subentry = subentry->chain) {
if (subentry->flags & E_SCRAPPED)
continue;
- (*function) (subentry, arg);
+ (*function)(subentry, arg);
}
}
#endif
@@ -836,8 +848,8 @@ each_file(function, arg)
unsigned long
check_each_file(function, arg)
- register unsigned long (*function) ();
- register int arg;
+ register unsigned long (*function)();
+ register void *arg;
{
register int i;
register unsigned long return_val;
@@ -851,10 +863,10 @@ check_each_file(function, arg)
for (; subentry; subentry = subentry->chain) {
if (subentry->flags & E_SCRAPPED)
continue;
- if (return_val = (*function) (subentry, arg))
+ if (return_val = (*function)(subentry, arg))
return return_val;
}
- } else if (return_val = (*function) (entry, arg))
+ } else if (return_val = (*function)(entry, arg))
return return_val;
}
return 0;
@@ -864,8 +876,8 @@ check_each_file(function, arg)
void
each_full_file(function, arg)
- register void (*function) ();
- register int arg;
+ register void (*function)();
+ register void *arg;
{
register int i;
@@ -880,16 +892,16 @@ each_full_file(function, arg)
if (entry->silly_archive) {
if (!(entry->flags & E_DYNAMIC))
- error("Silly");
+ warnx("Silly");
if (!(entry->silly_archive->flags & E_IS_LIBRARY))
- error("Sillier");
+ warnx("Sillier");
subentry = entry->silly_archive->subfiles;
for (; subentry; subentry = subentry->chain) {
if (subentry->flags & E_SCRAPPED)
continue;
- (*function) (subentry, arg);
+ (*function)(subentry, arg);
}
}
#endif
@@ -897,13 +909,13 @@ each_full_file(function, arg)
continue;
if (!(entry->flags & E_IS_LIBRARY))
- (*function) (entry, arg);
+ (*function)(entry, arg);
subentry = entry->subfiles;
for (; subentry; subentry = subentry->chain) {
if (subentry->flags & E_SCRAPPED)
continue;
- (*function) (subentry, arg);
+ (*function)(subentry, arg);
}
}
@@ -925,36 +937,40 @@ file_close()
* open is not actually done.
*/
int
-file_open (entry)
+file_open(entry)
register struct file_entry *entry;
{
- register int desc;
+ register int fd;
if (entry->superfile && (entry->superfile->flags & E_IS_LIBRARY))
- return file_open (entry->superfile);
+ return file_open(entry->superfile);
if (entry == input_file)
return input_desc;
- if (input_file) file_close ();
+ if (input_file)
+ file_close();
if (entry->flags & E_SEARCH_DIRS) {
- desc = findlib(entry);
+ fd = findlib(entry);
} else
- desc = open (entry->filename, O_RDONLY, 0);
+ fd = open(entry->filename, O_RDONLY, 0);
- if (desc > 0) {
+ if (fd > 0) {
input_file = entry;
- input_desc = desc;
- return desc;
+ input_desc = fd;
+ return fd;
}
- perror_file (entry);
- /* NOTREACHED */
+ if (entry->flags & E_SEARCH_DIRS)
+ errx(1, "%s: no match", entry->local_sym_name);
+ else
+ err(1, "%s", entry->filename);
+ return fd;
}
int
-text_offset (entry)
+text_offset(entry)
struct file_entry *entry;
{
return entry->starting_offset + N_TXTOFF (entry->header);
@@ -963,64 +979,68 @@ text_offset (entry)
/*---------------------------------------------------------------------------*/
/*
- * Read a file's header into the proper place in the file_entry. DESC is the
+ * Read a file's header into the proper place in the file_entry. FD is the
* descriptor on which the file is open. ENTRY is the file's entry.
*/
void
-read_header (desc, entry)
- int desc;
- register struct file_entry *entry;
+read_header(fd, entry)
+ int fd;
+ struct file_entry *entry;
{
- register int len, mid;
+ register int len;
- if (lseek (desc, entry->starting_offset, L_SET) !=
+ if (lseek(fd, entry->starting_offset, L_SET) !=
entry->starting_offset)
- fatal_with_file("read_header: lseek failure ", entry);
+ err(1, "%s: read_header: lseek", get_file_name(entry));
- len = read (desc, &entry->header, sizeof (struct exec));
+ len = read(fd, &entry->header, sizeof(struct exec));
if (len != sizeof (struct exec))
- fatal_with_file ("failure reading header of ", entry);
+ err(1, "%s: read_header: read", get_file_name(entry));
md_swapin_exec_hdr(&entry->header);
if (N_BADMAG (entry->header))
- fatal_with_file ("bad magic number in ", entry);
+ errx(1, "%s: bad magic number", get_file_name(entry));
if (N_BADMID(entry->header))
- fatal_with_file ("non-native input file ", entry);
+ errx(1, "%s: non-native input file", get_file_name(entry));
entry->flags |= E_HEADER_VALID;
}
/*
* Read the symbols of file ENTRY into core. Assume it is already open, on
- * descriptor DESC. Also read the length of the string table, which follows
+ * descriptor FD. Also read the length of the string table, which follows
* the symbol table, but don't read the contents of the string table.
*/
void
-read_entry_symbols (desc, entry)
+read_entry_symbols(fd, entry)
struct file_entry *entry;
- int desc;
+ int fd;
{
int str_size;
struct nlist *np;
int i;
if (!(entry->flags & E_HEADER_VALID))
- read_header (desc, entry);
+ read_header(fd, entry);
- np = (struct nlist *) alloca (entry->header.a_syms);
+ np = (struct nlist *)alloca(entry->header.a_syms);
entry->nsymbols = entry->header.a_syms / sizeof(struct nlist);
+ if (entry->nsymbols == 0)
+ return;
+
entry->symbols = (struct localsymbol *)
xmalloc(entry->nsymbols * sizeof(struct localsymbol));
- if (lseek(desc, N_SYMOFF(entry->header) + entry->starting_offset, L_SET)
+ if (lseek(fd, N_SYMOFF(entry->header) + entry->starting_offset, L_SET)
!= N_SYMOFF(entry->header) + entry->starting_offset)
- fatal_with_file ("read_symbols(h): lseek failure ", entry);
+ err(1, "%s: read_symbols: lseek(syms) failed", get_file_name(entry));
- if (entry->header.a_syms != read (desc, np, entry->header.a_syms))
- fatal_with_file ("premature end of file in symbols of ", entry);
+ if (entry->header.a_syms != read(fd, np, entry->header.a_syms))
+ errx(1, "%s: read_symbols: premature end of file in symbols",
+ get_file_name(entry));
md_swapin_symbols(np, entry->header.a_syms / sizeof(struct nlist));
@@ -1036,35 +1056,41 @@ read_entry_symbols (desc, entry)
entry->strings_offset = N_STROFF(entry->header) +
entry->starting_offset;
- if (lseek(desc, entry->strings_offset, 0) == (off_t)-1)
- fatal_with_file ("read_symbols(s): lseek failure ", entry);
- if (sizeof str_size != read (desc, &str_size, sizeof str_size))
- fatal_with_file ("bad string table size in ", entry);
+ if (lseek(fd, entry->strings_offset, 0) == (off_t)-1)
+ err(1, "%s: read_symbols: lseek(strings) failed",
+ get_file_name(entry));
+ if (sizeof str_size != read(fd, &str_size, sizeof str_size))
+ errx(1, "%s: read_symbols: cannot read string table size",
+ get_file_name(entry));
entry->string_size = md_swap_long(str_size);
}
/*
- * Read the string table of file ENTRY into core. Assume it is already open,
- * on descriptor DESC.
+ * Read the string table of file ENTRY open on descriptor FD, into core.
*/
void
-read_entry_strings (desc, entry)
+read_entry_strings(fd, entry)
struct file_entry *entry;
- int desc;
+ int fd;
{
- int buffer;
+
+ if (entry->string_size == 0)
+ return;
if (!(entry->flags & E_HEADER_VALID) || !entry->strings_offset)
- fatal_with_file("internal error: cannot read string table for ",
- entry);
+ errx(1, "%s: read_strings: string table unavailable",
+ get_file_name(entry));
- if (lseek (desc, entry->strings_offset, L_SET) != entry->strings_offset)
- fatal_with_file ("read_strings: lseek failure ", entry);
+ if (lseek(fd, entry->strings_offset, L_SET) !=
+ entry->strings_offset)
+ err(1, "%s: read_strings: lseek",
+ get_file_name(entry));
- if (entry->string_size !=
- read (desc, entry->strings, entry->string_size))
- fatal_with_file ("premature end of file in strings of ", entry);
+ if (read(fd, entry->strings, entry->string_size) !=
+ entry->string_size)
+ errx(1, "%s: read_strings: premature end of file in strings",
+ get_file_name(entry));
return;
}
@@ -1072,8 +1098,8 @@ read_entry_strings (desc, entry)
/* Read in the relocation sections of ENTRY if necessary */
void
-read_entry_relocation (desc, entry)
- int desc;
+read_entry_relocation(fd, entry)
+ int fd;
struct file_entry *entry;
{
register struct relocation_info *reloc;
@@ -1087,14 +1113,15 @@ read_entry_relocation (desc, entry)
pos = text_offset(entry) +
entry->header.a_text + entry->header.a_data;
- if (lseek(desc, pos, L_SET) != pos)
- fatal_with_file("read_reloc(t): lseek failure ", entry);
+ if (lseek(fd, pos, L_SET) != pos)
+ err(1, "%s: read_reloc(text): lseek failed",
+ get_file_name(entry));
+
+ if (read(fd, reloc, entry->header.a_trsize) !=
+ entry->header.a_trsize)
+ errx(1, "%s: read_reloc(text): premature EOF",
+ get_file_name(entry));
- if (entry->header.a_trsize !=
- read(desc, reloc, entry->header.a_trsize)) {
- fatal_with_file (
- "premature eof in text relocation of ", entry);
- }
md_swapin_reloc(reloc, entry->header.a_trsize / sizeof(*reloc));
entry->textrel = reloc;
entry->ntextrel = entry->header.a_trsize / sizeof(*reloc);
@@ -1109,14 +1136,15 @@ read_entry_relocation (desc, entry)
pos = text_offset(entry) + entry->header.a_text +
entry->header.a_data + entry->header.a_trsize;
- if (lseek(desc, pos, L_SET) != pos)
- fatal_with_file("read_reloc(d): lseek failure ", entry);
+ if (lseek(fd, pos, L_SET) != pos)
+ err(1, "%s: read_reloc(data): lseek failed",
+ get_file_name(entry));
+
+ if (read(fd, reloc, entry->header.a_drsize) !=
+ entry->header.a_drsize)
+ errx(1, "%s: read_reloc(data): premature EOF",
+ get_file_name(entry));
- if (entry->header.a_drsize !=
- read (desc, reloc, entry->header.a_drsize)) {
- fatal_with_file (
- "premature eof in data relocation of ", entry);
- }
md_swapin_reloc(reloc, entry->header.a_drsize / sizeof(*reloc));
entry->datarel = reloc;
entry->ndatarel = entry->header.a_drsize / sizeof(*reloc);
@@ -1130,7 +1158,7 @@ read_entry_relocation (desc, entry)
* Read in the symbols of all input files.
*/
static void
-load_symbols ()
+load_symbols()
{
register int i;
@@ -1141,7 +1169,7 @@ load_symbols ()
read_file_symbols(&file_table[i]);
if (trace_files)
- fprintf (stderr, "\n");
+ fprintf(stderr, "\n");
}
/*
@@ -1151,55 +1179,57 @@ load_symbols ()
*/
void
-read_file_symbols (entry)
+read_file_symbols(entry)
register struct file_entry *entry;
{
- register int desc;
+ register int fd;
register int len;
struct exec hdr;
- desc = file_open (entry);
+ fd = file_open(entry);
- len = read (desc, &hdr, sizeof hdr);
+ len = read(fd, &hdr, sizeof hdr);
if (len != sizeof hdr)
- fatal_with_file ("failure reading header of ", entry);
+ errx(1, "%s: read_file_symbols(header): premature EOF",
+ get_file_name(entry));
md_swapin_exec_hdr(&hdr);
if (!N_BADMAG (hdr)) {
if (N_IS_DYNAMIC(hdr) && !(entry->flags & E_JUST_SYMS)) {
if (relocatable_output) {
- fatal_with_file(
- "-r and shared objects currently not supported ",
- entry);
+ errx(1,
+ "%s: -r and shared objects currently not supported ",
+ get_file_name(entry));
return;
}
entry->flags |= E_DYNAMIC;
if (entry->superfile || rrs_add_shobj(entry))
- read_shared_object(desc, entry);
+ read_shared_object(fd, entry);
else
entry->flags |= E_SCRAPPED;
} else {
- read_entry_symbols (desc, entry);
- entry->strings = (char *) alloca (entry->string_size);
- read_entry_strings (desc, entry);
- read_entry_relocation(desc, entry);
- enter_file_symbols (entry);
+ read_entry_symbols(fd, entry);
+ entry->strings = (char *)alloca (entry->string_size);
+ read_entry_strings(fd, entry);
+ read_entry_relocation(fd, entry);
+ enter_file_symbols(entry);
entry->strings = 0;
}
} else {
char armag[SARMAG];
- lseek (desc, 0, 0);
- if (SARMAG != read (desc, armag, SARMAG) ||
+ lseek (fd, 0, 0);
+ if (SARMAG != read(fd, armag, SARMAG) ||
strncmp (armag, ARMAG, SARMAG))
- fatal_with_file(
- "malformed input file (not rel or archive) ", entry);
+ errx(1,
+ "%s: malformed input file (not rel or archive)",
+ get_file_name(entry));
entry->flags |= E_IS_LIBRARY;
- search_library (desc, entry);
+ search_library(fd, entry);
}
- file_close ();
+ file_close();
}
@@ -1208,12 +1238,13 @@ read_file_symbols (entry)
*/
void
-enter_file_symbols (entry)
+enter_file_symbols(entry)
struct file_entry *entry;
{
struct localsymbol *lsp, *lspend;
- if (trace_files) prline_file_name (entry, stderr);
+ if (trace_files)
+ prline_file_name(entry, stderr);
lspend = entry->symbols + entry->nsymbols;
@@ -1242,7 +1273,8 @@ enter_file_symbols (entry)
/* Grab the next entry. */
p++;
if (p->n_type != (N_UNDF | N_EXT)) {
- error("Warning symbol found in %s without external reference following.",
+ warnx(
+ "%s: Warning symbol without external reference following.",
get_file_name(entry));
make_executable = 0;
p--; /* Process normally. */
@@ -1284,13 +1316,13 @@ enter_file_symbols (entry)
*/
static void
-enter_global_ref (lsp, name, entry)
+enter_global_ref(lsp, name, entry)
struct localsymbol *lsp;
char *name;
struct file_entry *entry;
{
register struct nzlist *nzp = &lsp->nzlist;
- register symbol *sp = getsym (name);
+ register symbol *sp = getsym(name);
register int type = nzp->nz_type;
int oldref = (sp->flags & GS_REFERENCED);
int olddef = sp->defined;
@@ -1299,7 +1331,7 @@ enter_global_ref (lsp, name, entry)
if (type == (N_INDR | N_EXT)) {
sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx);
if (sp == sp->alias) {
- error("%s: %s is alias for itself",
+ warnx("%s: %s is alias for itself",
get_file_name(entry), name);
/* Rewrite symbol as global text symbol with value 0 */
lsp->nzlist.nz_type = N_TEXT|N_EXT;
@@ -1356,7 +1388,7 @@ enter_global_ref (lsp, name, entry)
if (sp == dynamic_symbol || sp == got_symbol) {
if (type != (N_UNDF | N_EXT) && !(entry->flags & E_JUST_SYMS))
- fatal("Linker reserved symbol %s defined as type %x ",
+ errx(1,"Linker reserved symbol %s defined as type %x ",
name, type);
return;
}
@@ -1383,6 +1415,10 @@ enter_global_ref (lsp, name, entry)
* It used to be undefined and we're defining it.
*/
undefined_global_sym_count--;
+ if (undefined_global_sym_count < 0)
+ errx(1,
+ "internal error: enter_glob_ref: undefined_global_sym_count = %d",
+ undefined_global_sym_count);
if (!olddef && type == (N_UNDF | N_EXT) && nzp->nz_value) {
/*
@@ -1449,9 +1485,9 @@ enter_global_ref (lsp, name, entry)
break;
}
- fprintf (stderr, "symbol %s %s in ", sp->name, reftype);
+ fprintf(stderr, "symbol %s %s in ", sp->name, reftype);
print_file_name (entry, stderr);
- fprintf (stderr, "\n");
+ fprintf(stderr, "\n");
}
}
@@ -1462,7 +1498,7 @@ enter_global_ref (lsp, name, entry)
*/
unsigned long
-contains_symbol (entry, np)
+contains_symbol(entry, np)
struct file_entry *entry;
register struct nlist *np;
{
@@ -1505,7 +1541,7 @@ contains_symbol (entry, np)
*/
static void
-digest_symbols ()
+digest_symbols()
{
if (trace_files)
@@ -1528,10 +1564,10 @@ digest_symbols ()
defined_global_sym_count = 0;
digest_pass1();
- each_full_file(consider_relocation, 0); /* Text */
- each_full_file(consider_relocation, 1); /* Data */
+ each_full_file(consider_relocation, (void *)0); /* Text */
+ each_full_file(consider_relocation, (void *)1); /* Data */
- each_file(consider_local_symbols, 0);
+ each_file(consider_local_symbols, (void *)0);
/*
* Compute total size of sections.
@@ -1570,7 +1606,7 @@ digest_symbols ()
data_start = rrs_data_start + rrs_data_size;
if (!relocatable_output) {
set_sect_start = rrs_data_start + data_size;
- data_size += set_sect_size;
+ data_size += MALIGN(set_sect_size);
}
bss_start = rrs_data_start + data_size;
@@ -1581,6 +1617,8 @@ printf("datastart = %#x, datasize = %#x, rrs_data_start %#x, rrs_data_size %#x\n
data_start, data_size, rrs_data_start, rrs_data_size);
printf("bssstart = %#x, bsssize = %#x\n",
bss_start, bss_size);
+printf("set_sect_start = %#x, set_sect_size = %#x\n",
+ set_sect_start, set_sect_size);
#endif
/* Compute start addresses of each file's sections and symbols. */
@@ -1679,6 +1717,9 @@ digest_pass1()
/* Superfluous symbol from shared object */
continue;
}
+ if (sp->so_defined)
+ /* Already examined; must have been an alias */
+ continue;
if (sp == got_symbol || sp == dynamic_symbol)
continue;
@@ -1689,7 +1730,7 @@ digest_pass1()
if (SET_ELEMENT_P(type)) {
if (relocatable_output)
- fatal(
+ errx(1,
"internal error: global ref to set el %s with -r",
sp->name);
if (!defs++) {
@@ -1758,6 +1799,10 @@ digest_pass1()
if (building_shared_object) {
/* Just punt for now */
undefined_global_sym_count--;
+ if (undefined_global_sym_count < 0)
+ errx(1,
+ "internal error: digest_pass1,1: %s: undefined_global_sym_count = %d",
+ sp->name, undefined_global_sym_count);
continue;
}
@@ -1766,8 +1811,8 @@ digest_pass1()
register struct nlist *p = &lsp->nzlist.nlist;
register int type = p->n_type;
- if ((type & N_EXT) && type != (N_UNDF | N_EXT)
- && (type & N_TYPE) != N_FN) {
+ if ((type & N_EXT) && type != (N_UNDF | N_EXT) &&
+ (type & N_TYPE) != N_FN) {
/* non-common definition */
sp->def_nlist = p;
lsp->entry->flags |= E_SYMBOLS_USED;
@@ -1780,6 +1825,10 @@ digest_pass1()
#ifdef DEBUG
printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value);
#endif
+ if (undefined_global_sym_count < 0)
+ errx(1,
+ "internal error: digest_pass1,2: %s: undefined_global_sym_count = %d",
+ sp->name, undefined_global_sym_count);
if (sp->alias && !(sp->alias->flags & GS_REFERENCED)) {
sp = sp->alias;
goto again;
@@ -1790,7 +1839,7 @@ printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value);
} END_EACH_SYMBOL;
if (setv_fill_count != set_sect_size/sizeof(long))
- fatal("internal error: allocated set symbol space (%d) \
+ errx(1, "internal error: allocated set symbol space (%d) \
doesn't match actual (%d)",
set_sect_size/sizeof(long), setv_fill_count);
}
@@ -1801,7 +1850,7 @@ doesn't match actual (%d)",
* of the output file.
*/
static void
-consider_relocation (entry, dataseg)
+consider_relocation(entry, dataseg)
struct file_entry *entry;
int dataseg;
{
@@ -1863,6 +1912,10 @@ consider_relocation (entry, dataseg)
sp = lsp->symbol;
if (sp->alias)
sp = sp->alias;
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr, "symbol %s has jmpslot in %s\n",
+ sp->name, get_file_name(entry));
+ }
alloc_rrs_jmpslot(entry, sp);
} else if (RELOC_BASEREL_P(reloc)) {
@@ -1892,8 +1945,8 @@ consider_relocation (entry, dataseg)
lsp = &entry->symbols[reloc->r_symbolnum];
sp = lsp->symbol;
if (sp == NULL)
- fatal_with_file(
- "internal error, sp==NULL", entry);
+ errx(1, "%s: internal error, sp==NULL",
+ get_file_name(entry));
if (sp->alias)
sp = sp->alias;
@@ -1903,8 +1956,9 @@ consider_relocation (entry, dataseg)
*/
if (sp == got_symbol) {
if (!CHECK_GOT_RELOC(reloc))
- fatal_with_file(
- "Unexpected relocation type ", entry);
+ errx(1,
+ "%s: Unexpected relocation type for GOT symbol",
+ get_file_name(entry));
continue;
}
@@ -1913,6 +1967,11 @@ consider_relocation (entry, dataseg)
*/
if (building_shared_object) {
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s RRS entry in %s\n",
+ sp->name, get_file_name(entry));
+ }
alloc_rrs_reloc(entry, sp);
continue;
}
@@ -1939,7 +1998,7 @@ consider_relocation (entry, dataseg)
* Prepare an RRS relocation as these are load
* address dependent.
*/
- if (building_shared_object) {
+ if (building_shared_object && !RELOC_PCREL_P(reloc)) {
alloc_rrs_segment_reloc(entry, reloc);
}
}
@@ -2021,7 +2080,7 @@ consider_local_symbols(entry)
* the output file.
*/
static void
-consider_file_section_lengths (entry)
+consider_file_section_lengths(entry)
register struct file_entry *entry;
{
@@ -2043,7 +2102,7 @@ consider_file_section_lengths (entry)
* Also relocate the addresses of the file's local and debugger symbols.
*/
static void
-relocate_file_addresses (entry)
+relocate_file_addresses(entry)
register struct file_entry *entry;
{
register struct localsymbol *lsp, *lspend;
@@ -2092,8 +2151,9 @@ printf("%s: datastart: %#x, bss %#x\n", get_file_name(entry),
case N_BSS:
case N_SETB:
/* likewise for symbols with value in BSS. */
- p->n_value += entry->bss_start_address
- - entry->header.a_text - entry->header.a_data;
+ p->n_value += entry->bss_start_address -
+ (entry->header.a_text +
+ entry->header.a_data);
break;
}
@@ -2194,14 +2254,14 @@ digest_pass2()
* It's a common.
*/
if (sp->defined != (N_UNDF + N_EXT))
- fatal("%s: common isn't", sp->name);
+ errx(1, "%s: common isn't", sp->name);
} else if ((size = sp->size) != 0 && sp->defined == N_SIZE) {
/*
* It's data from shared object with size info.
*/
if (!sp->so_defined)
- fatal("%s: Bogus N_SIZE item", sp->name);
+ errx(1, "%s: Bogus N_SIZE item", sp->name);
} else
/*
@@ -2257,62 +2317,64 @@ digest_pass2()
/* Write the output file */
void
-write_output ()
+write_output()
{
struct stat statbuf;
int filemode;
- if (lstat(output_filename, &statbuf) != -1) {
- if (!S_ISDIR(statbuf.st_mode))
+ if (lstat(output_filename, &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode))
(void)unlink(output_filename);
}
- outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ outdesc = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (outdesc < 0)
- perror_name (output_filename);
+ err(1, "open: %s", output_filename);
- fatal_cleanup_hook = myfatal;
+ if (atexit(cleanup))
+ err(1, "atexit");
if (fstat (outdesc, &statbuf) < 0)
- perror_name (output_filename);
+ err(1, "fstat: %s", output_filename);
filemode = statbuf.st_mode;
chmod (output_filename, filemode & ~0111);
/* Output the a.out header. */
- write_header ();
+ write_header();
/* Output the text and data segments, relocating as we go. */
- write_text ();
- write_data ();
+ write_text();
+ write_data();
/* Output the merged relocation info, if requested with `-r'. */
if (relocatable_output)
- write_rel ();
+ write_rel();
/* Output the symbol table (both globals and locals). */
- write_syms ();
+ write_syms();
/* Output the RSS section */
- write_rrs ();
-
- close (outdesc);
+ write_rrs();
if (chmod (output_filename, filemode | 0111) == -1)
- perror_name (output_filename);
+ err(1, "chmod: %s", output_filename);
+
+ close(outdesc);
+ outdesc = 0;
}
/* Total number of symbols to be written in the output file. */
static int nsyms;
void
-write_header ()
+write_header()
{
int flags = (rrs_section_type == RRS_FULL) ? EX_DYNAMIC : 0;
if (oldmagic && (flags & EX_DYNAMIC))
- error("Cannot set flag in old magic headers\n");
+ warnx("Cannot set flag in old magic headers\n");
N_SET_FLAG (outheader, flags);
@@ -2341,7 +2403,7 @@ write_header ()
}
md_swapout_exec_hdr(&outheader);
- mywrite (&outheader, sizeof (struct exec), 1, outdesc);
+ mywrite(&outheader, sizeof (struct exec), 1, outdesc);
md_swapin_exec_hdr(&outheader);
/*
@@ -2350,27 +2412,28 @@ write_header ()
*/
#ifndef COFF_ENCAPSULATE
- padfile (N_TXTOFF(outheader) - sizeof outheader, outdesc);
+ padfile(N_TXTOFF(outheader) - sizeof outheader, outdesc);
#endif
}
-/* Relocate the text segment of each input file
- and write to the output file. */
-
+/*
+ * Relocate the text segment of each input file
+ * and write to the output file.
+ */
void
-write_text ()
+write_text()
{
if (trace_files)
- fprintf (stderr, "Copying and relocating text:\n\n");
+ fprintf(stderr, "Copying and relocating text:\n\n");
- each_full_file (copy_text, 0);
- file_close ();
+ each_full_file(copy_text, 0);
+ file_close();
if (trace_files)
- fprintf (stderr, "\n");
+ fprintf(stderr, "\n");
- padfile (text_pad, outdesc);
+ padfile(text_pad, outdesc);
}
/*
@@ -2379,55 +2442,57 @@ write_text ()
* reuse.
*/
void
-copy_text (entry)
+copy_text(entry)
struct file_entry *entry;
{
register char *bytes;
- register int desc;
+ register int fd;
if (trace_files)
- prline_file_name (entry, stderr);
+ prline_file_name(entry, stderr);
- desc = file_open (entry);
+ fd = file_open(entry);
/* Allocate space for the file's text section */
- bytes = (char *) alloca (entry->header.a_text);
+ bytes = (char *)alloca(entry->header.a_text);
/* Deal with relocation information however is appropriate */
if (entry->textrel == NULL)
- fatal_with_file("no text relocation of ", entry);
+ errx(1, "%s: no text relocation", get_file_name(entry));
/* Read the text section into core. */
- lseek (desc, text_offset (entry), 0);
- if (entry->header.a_text != read (desc, bytes, entry->header.a_text))
- fatal_with_file ("premature eof in text section of ", entry);
-
+ if (lseek(fd, text_offset(entry), L_SET) == (off_t)-1)
+ err(1, "%s: copy_text: lseek", get_file_name(entry));
+ if (entry->header.a_text != read(fd, bytes, entry->header.a_text))
+ errx(1, "%s: copy_text: premature EOF in text section", get_file_name(entry));
/* Relocate the text according to the text relocation. */
perform_relocation (bytes, entry->header.a_text,
entry->textrel, entry->ntextrel, entry, 0);
/* Write the relocated text to the output file. */
- mywrite (bytes, 1, entry->header.a_text, outdesc);
+ mywrite(bytes, 1, entry->header.a_text, outdesc);
}
-/* Relocate the data segment of each input file
- and write to the output file. */
+/*
+ * Relocate the data segment of each input file
+ * and write to the output file.
+ */
void
-write_data ()
+write_data()
{
- long pos;
+ off_t pos;
if (trace_files)
- fprintf (stderr, "Copying and relocating data:\n\n");
+ fprintf(stderr, "Copying and relocating data:\n\n");
pos = N_DATOFF(outheader) + data_start - rrs_data_start;
if (lseek(outdesc, pos, L_SET) != pos)
- fatal("write_data: lseek: cant position data offset");
+ errx(1, "write_data: failed to lseek to data offset");
- each_full_file (copy_data, 0);
- file_close ();
+ each_full_file(copy_data, 0);
+ file_close();
/*
* Write out the set element vectors. See digest symbols for
@@ -2436,14 +2501,14 @@ write_data ()
if (set_vector_count) {
swap_longs(set_vectors, set_symbol_count + 2*set_vector_count);
- mywrite (set_vectors, set_symbol_count + 2*set_vector_count,
+ mywrite(set_vectors, set_symbol_count + 2*set_vector_count,
sizeof (unsigned long), outdesc);
}
if (trace_files)
- fprintf (stderr, "\n");
+ fprintf(stderr, "\n");
- padfile (data_pad, outdesc);
+ padfile(data_pad, outdesc);
}
/*
@@ -2452,30 +2517,32 @@ write_data ()
* reuse. See comments in `copy_text'.
*/
void
-copy_data (entry)
+copy_data(entry)
struct file_entry *entry;
{
register char *bytes;
- register int desc;
+ register int fd;
if (trace_files)
prline_file_name (entry, stderr);
- desc = file_open (entry);
+ fd = file_open(entry);
bytes = (char *)alloca(entry->header.a_data);
if (entry->datarel == NULL)
- fatal_with_file("no data relocation of ", entry);
+ errx(1, "%s: no data relocation", get_file_name(entry));
- lseek (desc, text_offset (entry) + entry->header.a_text, 0);
- if (entry->header.a_data != read(desc, bytes, entry->header.a_data))
- fatal_with_file ("premature eof in data section of ", entry);
+ if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
+ (off_t)-1)
+ err(1, "%s: copy_data: lseek", get_file_name(entry));
+ if (entry->header.a_data != read(fd, bytes, entry->header.a_data))
+ errx(1, "%s: copy_data: premature EOF in data section", get_file_name(entry));
- perform_relocation (bytes, entry->header.a_data,
+ perform_relocation(bytes, entry->header.a_data,
entry->datarel, entry->ndatarel, entry, 1);
- mywrite (bytes, 1, entry->header.a_data, outdesc);
+ mywrite(bytes, 1, entry->header.a_data, outdesc);
}
/*
@@ -2522,8 +2589,8 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
*/
if (addr >= data_size)
- fatal_with_file(
- "relocation address out of range in ", entry);
+ errx(1, "%s: relocation address out of range",
+ get_file_name(entry));
if (RELOC_JMPTAB_P(r)) {
@@ -2532,8 +2599,8 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
symbol *sp;
if (symindex >= entry->nsymbols)
- fatal_with_file(
- "relocation symbolnum out of range in ", entry);
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
sp = lsp->symbol;
if (sp->alias)
@@ -2554,17 +2621,17 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
struct localsymbol *lsp = &entry->symbols[symindex];
if (symindex >= entry->nsymbols)
- fatal_with_file(
- "relocation symbolnum out of range in ", entry);
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
if (relocatable_output)
relocation = addend;
else if (!RELOC_EXTERN_P(r))
- relocation = claim_rrs_internal_gotslot(entry,
- r, lsp, addend);
+ relocation = claim_rrs_internal_gotslot(
+ entry, r, lsp, addend);
else
- relocation = claim_rrs_gotslot(entry,
- r, lsp, addend);
+ relocation = claim_rrs_gotslot(
+ entry, r, lsp, addend);
} else if (RELOC_EXTERN_P(r)) {
@@ -2572,8 +2639,8 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
symbol *sp;
if (symindex >= entry->nsymbols)
- fatal_with_file(
- "relocation symbolnum out of range in ", entry);
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
sp = entry->symbols[symindex].symbol;
if (sp->alias)
@@ -2588,6 +2655,12 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
if (!pic_code_seen)
relocation += sp->value;
} else if (sp->defined) {
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s defined as %x in %s\n",
+ sp->name, sp->defined,
+ get_file_name(entry) );
+ }
if (sp == got_symbol) {
/* Handle _GOT_ refs */
relocation = addend + sp->value
@@ -2602,8 +2675,8 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
entry->data_start_address:
entry->text_start_address;
relocation = addend;
- if (claim_rrs_reloc(entry, r,
- sp, &relocation))
+ if (claim_rrs_reloc(
+ entry, r, sp, &relocation))
continue;
} else if (sp->defined == N_SIZE) {
/*
@@ -2611,7 +2684,7 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
* run-time copy.
*/
if (!sp->size)
- fatal("Copy item isn't: %s",
+ errx(1, "Copy item isn't: %s",
sp->name);
relocation = addend + sp->value;
@@ -2628,48 +2701,35 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
* run-time. The r_address field is updated
* to reflect the changed position in the
* output file.
- *
- * In case the symbol is defined in a shared
- * object as N_TEXT or N_DATA, an appropriate
- * jmpslot or copy relocation is generated.
*/
- switch (sp->so_defined) {
-
- case N_TEXT+N_EXT:
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s claims RRS in %s%s\n",
+ sp->name, get_file_name(entry),
+ (sp->so_defined == (N_TEXT+N_EXT) &&
+ sp->jmpslot_offset != -1)?
+ " (JMPSLOT)":"");
+ }
+ if (sp->so_defined == (N_TEXT+N_EXT) &&
+ sp->jmpslot_offset != -1) {
/*
- * Claim a jmpslot if one was
- * allocated (dependent on
- * `force_alias_flag').
+ * Claim a jmpslot if one was allocated.
+ *
+ * At this point, a jmpslot can only
+ * result from a shared object reference
+ * while `force_alias' is in effect.
*/
-
- if (sp->jmpslot_offset == -1)
- goto undefined;
-
relocation = addend +
- claim_rrs_jmpslot(entry, r,
- sp, addend);
- break;
-
- case N_DATA+N_EXT:
- /*FALLTHROUGH*/
- case 0:
- undefined:
+ claim_rrs_jmpslot(
+ entry, r, sp, addend);
+ } else {
r->r_address += dataseg?
entry->data_start_address:
entry->text_start_address;
relocation = addend;
- if (claim_rrs_reloc(entry, r,
- sp, &relocation))
+ if (claim_rrs_reloc(
+ entry, r, sp, &relocation))
continue;
- break;
-
- case N_BSS+N_EXT:
-printf("%s: BSS found in so_defined\n", sp->name);
- /*break;*/
-
- default:
- fatal("%s: shobj symbol with unknown type %#x", sp->name, sp->so_defined);
- break;
}
}
@@ -2712,8 +2772,8 @@ printf("%s: BSS found in so_defined\n", sp->name);
break;
default:
- fatal_with_file(
- "nonexternal relocation code invalid in ", entry);
+ errx(1, "%s: nonexternal relocation invalid",
+ get_file_name(entry));
}
/*
@@ -2721,7 +2781,7 @@ printf("%s: BSS found in so_defined\n", sp->name);
* relocations need a "load address relative"
* RRS fixup.
*/
- if (building_shared_object) {
+ if (building_shared_object && !RELOC_PCREL_P(r)) {
r->r_address += dataseg?
entry->data_start_address:
entry->text_start_address;
@@ -2743,19 +2803,19 @@ printf("%s: BSS found in so_defined\n", sp->name);
*/
void
-write_rel ()
+write_rel()
{
int count = 0;
if (trace_files)
- fprintf (stderr, "Writing text relocation:\n\n");
+ fprintf(stderr, "Writing text relocation:\n\n");
/*
* Assign each global symbol a sequence number, giving the order
* in which `write_syms' will write it.
* This is so we can store the proper symbolnum fields
* in relocation entries we write.
- *
+ */
/* BLECH - Assign number 0 to __DYNAMIC (!! Sun compatibility) */
@@ -2772,20 +2832,20 @@ write_rel ()
} END_EACH_SYMBOL;
if (count != global_sym_count)
- fatal ("internal error: write_rel: count = %d", count);
+ errx(1, "internal error: write_rel: count = %d", count);
- each_full_file (assign_symbolnums, &count);
+ each_full_file(assign_symbolnums, &count);
/* Write out the relocations of all files, remembered from copy_text. */
- each_full_file (coptxtrel, 0);
+ each_full_file(coptxtrel, 0);
if (trace_files)
- fprintf (stderr, "\nWriting data relocation:\n\n");
+ fprintf(stderr, "\nWriting data relocation:\n\n");
- each_full_file (copdatrel, 0);
+ each_full_file(copdatrel, 0);
if (trace_files)
- fprintf (stderr, "\n");
+ fprintf(stderr, "\n");
}
@@ -2842,8 +2902,8 @@ coptxtrel(entry)
}
if (symindex >= entry->nsymbols)
- fatal_with_file(
- "relocation symbolnum out of range in ", entry);
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
sp = lsp->symbol;
@@ -2851,7 +2911,7 @@ coptxtrel(entry)
/* Resolve indirection. */
if ((sp->defined & ~N_EXT) == N_INDR) {
if (sp->alias == NULL)
- fatal("internal error: alias in hyperspace");
+ errx(1, "internal error: alias in hyperspace");
sp = sp->alias;
}
#endif
@@ -2914,9 +2974,8 @@ copdatrel(entry)
if (!RELOC_EXTERN_P(r)) {
if (RELOC_BASEREL_P(r))
- fatal_with_file(
- "Unsupported relocation type in ",
- entry);
+ errx(1, "%s: Unsupported relocation type",
+ get_file_name(entry));
continue;
}
@@ -2924,14 +2983,14 @@ copdatrel(entry)
sp = entry->symbols[symindex].symbol;
if (symindex >= entry->header.a_syms)
- fatal_with_file(
- "relocation symbolnum out of range in ", entry);
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
#ifdef N_INDR
/* Resolve indirection. */
if ((sp->defined & ~N_EXT) == N_INDR) {
if (sp->alias == NULL)
- fatal("internal error: alias in hyperspace");
+ errx(1, "internal error: alias in hyperspace");
sp = sp->alias;
}
#endif
@@ -3004,7 +3063,7 @@ assign_string_table_index(name)
return index;
}
-FILE *outstream = (FILE *) 0;
+FILE *outstream = (FILE *)0;
/*
* Write the contents of `strtab_vector' into the string table. This is done
@@ -3012,25 +3071,27 @@ FILE *outstream = (FILE *) 0;
* symbols.
*/
void
-write_string_table ()
+write_string_table()
{
register int i;
- lseek (outdesc, string_table_offset + string_table_len, 0);
+ if (lseek(outdesc, string_table_offset + string_table_len, 0) ==
+ (off_t)-1)
+ err(1, "write_string_table: %s: lseek", output_filename);
if (!outstream)
- outstream = fdopen (outdesc, "w");
+ outstream = fdopen(outdesc, "w");
for (i = 0; i < strtab_index; i++) {
fwrite (strtab_vector[i], 1, strtab_lens[i], outstream);
string_table_len += strtab_lens[i];
}
- fflush (outstream);
+ fflush(outstream);
/* Report I/O error such as disk full. */
- if (ferror (outstream))
- perror_name (output_filename);
+ if (ferror(outstream))
+ err(1, "write_string_table: %s", output_filename);
}
/* Write the symbol table and string table of the output file. */
@@ -3070,8 +3131,8 @@ write_syms()
* extra space for the references following indirect outputs.
*/
- strtab_vector = (char **) alloca((global_sym_count) * sizeof(char *));
- strtab_lens = (int *) alloca((global_sym_count) * sizeof(int));
+ strtab_vector = (char **)alloca((global_sym_count) * sizeof(char *));
+ strtab_lens = (int *)alloca((global_sym_count) * sizeof(int));
strtab_index = 0;
/*
@@ -3124,12 +3185,12 @@ write_syms()
* (they are in the RRS symbol table).
*/
if (!building_shared_object)
- error("symbol %s remains undefined", sp->name);
+ warnx("symbol %s remains undefined", sp->name);
continue;
}
if (syms_written >= global_sym_count)
- fatal(
+ errx(1,
"internal error: number of symbols exceeds alloc'd %d",
global_sym_count);
@@ -3161,7 +3222,7 @@ write_syms()
nl.n_type = sp->defined;
if (nl.n_type == (N_INDR|N_EXT) &&
sp->value != 0)
- fatal("%s: N_INDR has value %#x",
+ errx(1, "%s: N_INDR has value %#x",
sp->name, sp->value);
nl.n_value = sp->value;
nl.n_other = N_OTHER(0, sp->aux);
@@ -3184,7 +3245,7 @@ write_syms()
nl.n_type = N_UNDF | N_EXT;
nl.n_value = 0;
} else
- fatal(
+ errx(1,
"internal error: %s defined in mysterious way",
sp->name);
@@ -3204,7 +3265,7 @@ write_syms()
*/
if (nl.n_type == N_INDR + N_EXT) {
if (sp->alias == NULL)
- fatal("internal error: alias in hyperspace");
+ errx(1, "internal error: alias in hyperspace");
nl.n_type = N_UNDF + N_EXT;
nl.n_un.n_strx =
assign_string_table_index(sp->alias->name);
@@ -3234,13 +3295,15 @@ printf("writesym(#%d): %s, type %x\n", syms_written, sp->name, sp->defined);
} END_EACH_SYMBOL;
if (syms_written != strtab_index || strtab_index != global_sym_count)
- fatal("internal error:\
+ errx(1, "internal error:\
wrong number (%d) of global symbols written into output file, should be %d",
syms_written, global_sym_count);
/* Output the buffer full of `struct nlist's. */
- lseek(outdesc, symbol_table_offset + symbol_table_len, 0);
+ if (lseek(outdesc, symbol_table_offset + symbol_table_len, 0) ==
+ (off_t)-1)
+ err(1, "write_syms: lseek");
md_swapout_symbols(buf, bufp - buf);
mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc);
symbol_table_len += sizeof(struct nlist) * (bufp - buf);
@@ -3249,16 +3312,16 @@ wrong number (%d) of global symbols written into output file, should be %d",
write_string_table();
/* Write the local symbols defined by the various files. */
- each_file(write_file_syms, &syms_written);
+ each_file(write_file_syms, (void *)&syms_written);
file_close();
if (syms_written != nsyms)
- fatal("internal error:\
+ errx(1, "internal error:\
wrong number of symbols (%d) written into output file, should be %d",
syms_written, nsyms);
if (symbol_table_offset + symbol_table_len != string_table_offset)
- fatal(
+ errx(1,
"internal error: inconsistent symbol table length: %d vs %s",
symbol_table_offset + symbol_table_len, string_table_offset);
@@ -3304,8 +3367,8 @@ write_file_syms(entry, syms_written_addr)
* length. The elements are filled in by `assign_string_table_index'.
*/
- strtab_vector = (char **) alloca(max_syms * sizeof(char *));
- strtab_lens = (int *) alloca(max_syms * sizeof(int));
+ strtab_vector = (char **)alloca(max_syms * sizeof(char *));
+ strtab_lens = (int *)alloca(max_syms * sizeof(int));
strtab_index = 0;
/* Generate a local symbol for the start of this file's text. */
@@ -3314,7 +3377,8 @@ write_file_syms(entry, syms_written_addr)
struct nlist nl;
nl.n_type = N_FN | N_EXT;
- nl.n_un.n_strx = assign_string_table_index(entry->local_sym_name);
+ nl.n_un.n_strx =
+ assign_string_table_index(entry->local_sym_name);
nl.n_value = entry->text_start_address;
nl.n_desc = 0;
nl.n_other = 0;
@@ -3323,15 +3387,13 @@ write_file_syms(entry, syms_written_addr)
}
/* Read the file's string table. */
- entry->strings = (char *) alloca(entry->string_size);
+ entry->strings = (char *)alloca(entry->string_size);
read_entry_strings(file_open(entry), entry);
lspend = entry->symbols + entry->nsymbols;
for (lsp = entry->symbols; lsp < lspend; lsp++) {
register struct nlist *p = &lsp->nzlist.nlist;
- register int type = p->n_type;
- register int write = 0;
char *name;
if (!(lsp->flags & LS_WRITE))
@@ -3380,48 +3442,72 @@ write_file_syms(entry, syms_written_addr)
}
/*
- * Output COUNT*ELTSIZE bytes of data at BUF to the descriptor DESC.
+ * Parse the string ARG using scanf format FORMAT, and return the result.
+ * If it does not parse, report fatal error
+ * generating the error message using format string ERROR and ARG as arg.
+ */
+
+static int
+parse(arg, format, error)
+ char *arg, *format, *error;
+{
+ int x;
+
+ if (1 != sscanf(arg, format, &x))
+ errx(1, error, arg);
+ return x;
+}
+
+/*
+ * Output COUNT*ELTSIZE bytes of data at BUF to the descriptor FD.
*/
void
-mywrite (buf, count, eltsize, desc)
+mywrite(buf, count, eltsize, fd)
void *buf;
int count;
int eltsize;
- int desc;
+ int fd;
{
register int val;
register int bytes = count * eltsize;
while (bytes > 0) {
- val = write (desc, buf, bytes);
+ val = write(fd, buf, bytes);
if (val <= 0)
- perror(output_filename);
+ err(1, "write: %s", output_filename);
buf += val;
bytes -= val;
}
}
static void
-myfatal()
+cleanup()
{
- if (outdesc > 0)
- unlink(output_filename);
+ struct stat statbuf;
+
+ if (outdesc <= 0)
+ return;
+
+ if (fstat(outdesc, &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode))
+ (void)unlink(output_filename);
+ }
}
/*
- * Output PADDING zero-bytes to descriptor OUTDESC.
+ * Output PADDING zero-bytes to descriptor FD.
* PADDING may be negative; in that case, do nothing.
*/
void
-padfile (padding, outdesc)
+padfile(padding, fd)
int padding;
- int outdesc;
+ int fd;
{
register char *buf;
if (padding <= 0)
return;
- buf = (char *) alloca (padding);
- bzero (buf, padding);
- mywrite (buf, padding, 1, outdesc);
+ buf = (char *)alloca(padding);
+ bzero(buf, padding);
+ mywrite(buf, padding, 1, fd);
}
diff --git a/gnu/usr.bin/ld/ld.h b/gnu/usr.bin/ld/ld.h
index 27ff136708f0..0af50337276b 100644
--- a/gnu/usr.bin/ld/ld.h
+++ b/gnu/usr.bin/ld/ld.h
@@ -1,5 +1,5 @@
/*
- * $Id: ld.h,v 1.10 1994/02/13 20:41:34 jkh Exp $
+ * $Id: ld.h,v 1.11 1994/06/15 22:39:46 rich Exp $
*/
/*-
* This code is derived from software copyrighted by the Free Software
@@ -47,13 +47,7 @@
/* Align to machine dependent boundary */
#define MALIGN(x) PALIGN(x,MAX_ALIGNMENT)
-/* Name this program was invoked by. */
-char *progname;
-
-/* System dependencies */
-
/* Define this to specify the default executable format. */
-
#ifndef DEFAULT_MAGIC
#ifdef FreeBSD
#define DEFAULT_MAGIC QMAGIC
@@ -596,20 +590,24 @@ extern int n_search_dirs; /* Length of above. */
extern int write_map; /* write a load map (`-M') */
-extern void (*fatal_cleanup_hook)__P((void));
-
void read_header __P((int, struct file_entry *));
void read_entry_symbols __P((int, struct file_entry *));
void read_entry_strings __P((int, struct file_entry *));
void read_entry_relocation __P((int, struct file_entry *));
void enter_file_symbols __P((struct file_entry *));
void read_file_symbols __P((struct file_entry *));
+int set_element_prefixed_p __P((char *));
+int text_offset __P((struct file_entry *));
+int file_open __P((struct file_entry *));
+void each_file __P((void (*)(), void *));
+void each_full_file __P((void (*)(), void *));
+unsigned long check_each_file __P((unsigned long (*)(), void *));
void mywrite __P((void *, int, int, int));
+void padfile __P((int,int));
/* In warnings.c: */
void perror_name __P((char *));
void perror_file __P((struct file_entry *));
-void fatal_with_file __P((char *, struct file_entry *, ...));
void print_symbols __P((FILE *));
char *get_file_name __P((struct file_entry *));
void print_file_name __P((struct file_entry *, FILE *));
@@ -617,13 +615,9 @@ void prline_file_name __P((struct file_entry *, FILE *));
int do_warnings __P((FILE *));
/* In etc.c: */
-void *xmalloc __P((int));
-void *xrealloc __P((void *, int));
-void fatal __P((char *, ...));
-void error __P((char *, ...));
-void padfile __P((int,int));
+void *xmalloc __P((size_t));
+void *xrealloc __P((void *, size_t));
char *concat __P((const char *, const char *, const char *));
-int parse __P((char *, char *, char *));
/* In symbol.c: */
void symtab_init __P((int));
@@ -637,7 +631,10 @@ int findlib __P((struct file_entry *));
/* In shlib.c: */
char *findshlib __P((char *, int *, int *, int));
void add_search_dir __P((char *));
-void std_search_dirs __P((char *));
+void add_search_path __P((char *));
+void std_search_path __P((void));
+int getdewey __P((int[], char *));
+int cmpndewey __P((int[], int, int[], int));
/* In rrs.c: */
void init_rrs __P((void));
@@ -654,6 +651,9 @@ long claim_rrs_gotslot __P((struct file_entry *, struct relocation_info *, struc
long claim_rrs_internal_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
void claim_rrs_cpy_reloc __P((struct file_entry *, struct relocation_info *, symbol *));
void claim_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void consider_rrs_section_lengths __P((void));
+void relocate_rrs_addresses __P((void));
+void write_rrs __P((void));
/* In <md>.c */
void md_init_header __P((struct exec *, int, int));
@@ -665,6 +665,7 @@ int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int))
void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
#ifdef NEED_SWAP
void md_swapin_exec_hdr __P((struct exec *));
diff --git a/gnu/usr.bin/ld/ldconfig/Makefile b/gnu/usr.bin/ld/ldconfig/Makefile
index 04768a7c9b3c..08582c3a0044 100644
--- a/gnu/usr.bin/ld/ldconfig/Makefile
+++ b/gnu/usr.bin/ld/ldconfig/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.6 1994/02/13 20:42:18 jkh Exp $
+# $Id: Makefile,v 1.7 1994/04/13 20:49:42 ats Exp $
PROG= ldconfig
SRCS= ldconfig.c shlib.c etc.c
LDDIR?= $(.CURDIR)/..
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE)
-LDSTATIC=-static
+LDFLAGS+=-static
BINDIR= /sbin
MAN8= ldconfig.8
diff --git a/gnu/usr.bin/ld/ldconfig/ldconfig.8 b/gnu/usr.bin/ld/ldconfig/ldconfig.8
index 32c35afc8041..1ca25a429131 100644
--- a/gnu/usr.bin/ld/ldconfig/ldconfig.8
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.8
@@ -62,6 +62,8 @@ Do not scan
.Sq /usr/lib
,
.Sq /usr/X386/lib
+,
+.Sq /usr/X11R6/lib
and
.Sq /usr/local/lib
for shared libraries.
diff --git a/gnu/usr.bin/ld/ldconfig/ldconfig.c b/gnu/usr.bin/ld/ldconfig/ldconfig.c
index 4c840ffd3144..cd447bb627c1 100644
--- a/gnu/usr.bin/ld/ldconfig/ldconfig.c
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.c
@@ -27,26 +27,27 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: ldconfig.c,v 1.5 1994/02/13 20:42:30 jkh Exp $
+ * $Id: ldconfig.c,v 1.7 1994/06/15 22:40:56 rich Exp $
*/
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/resource.h>
-#include <fcntl.h>
+#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <ar.h>
#include <ranlib.h>
#include <a.out.h>
#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <dirent.h>
+#include <unistd.h>
#include "ld.h"
@@ -74,6 +75,7 @@ static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
static void enter __P((char *, char *, char *, int *, int));
static int dodir __P((char *, int));
static int build_hints __P((void));
+static int listhints __P((void));
int
main(argc, argv)
@@ -101,7 +103,7 @@ char *argv[];
justread = 1;
break;
default:
- fprintf(stderr, "Usage: %s [-v] [dir ...]\n", progname);
+ fprintf(stderr, "Usage: %s [-r] [-s] [-v] [dir ...]\n", progname);
exit(1);
break;
}
@@ -111,7 +113,7 @@ char *argv[];
return listhints();
if (!nostd)
- std_search_dirs(NULL);
+ std_search_path();
for (i = 0; i < n_search_dirs; i++)
rval |= dodir(search_dirs[i], 1);
@@ -349,7 +351,7 @@ build_hints()
return 0;
}
-int
+static int
listhints()
{
int fd;
@@ -375,7 +377,8 @@ listhints()
hdr = (struct hints_header *)addr;
if (HH_BADMAG(*hdr)) {
- fprintf(stderr, "%s: Bad magic: %d\n");
+ fprintf(stderr, "%s: Bad magic: %o\n",
+ _PATH_LD_HINTS, hdr->hh_magic);
return -1;
}
diff --git a/gnu/usr.bin/ld/ldd/ldd.1 b/gnu/usr.bin/ld/ldd/ldd.1
index f5a6abadcf49..13a13eeb8e37 100644
--- a/gnu/usr.bin/ld/ldd/ldd.1
+++ b/gnu/usr.bin/ld/ldd/ldd.1
@@ -16,7 +16,6 @@ depedencies that are the result of needed shared objects which themselves
depend on yet other shared objects.
.Sh SEE ALSO
.Xr ld 1 ,
-.Xr ld.so 1 ,
.Xr nm 1
.Sh HISTORY
A
diff --git a/gnu/usr.bin/ld/ldd/ldd.c b/gnu/usr.bin/ld/ldd/ldd.c
index 74e5de2ef82b..07ded46e945d 100644
--- a/gnu/usr.bin/ld/ldd/ldd.c
+++ b/gnu/usr.bin/ld/ldd/ldd.c
@@ -27,29 +27,30 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: ldd.c,v 1.3 1994/02/13 20:42:43 jkh Exp $
+ * $Id: ldd.c,v 1.4 1994/06/15 22:41:03 rich Exp $
*/
-#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
-#include <fcntl.h>
#include <sys/wait.h>
#include <a.out.h>
-
-static char *progname;
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
void
usage()
{
- fprintf(stderr, "Usage: %s <filename> ...\n", progname);
+ extern char *__progname;
+
+ fprintf(stderr, "Usage: %s <filename> ...\n", __progname);
+ exit(1);
}
int
@@ -57,20 +58,14 @@ main(argc, argv)
int argc;
char *argv[];
{
- int rval = 0;
+ int rval;
int c;
- extern int optind;
-
- if ((progname = strrchr(argv[0], '/')) == NULL)
- progname = argv[0];
- else
- progname++;
while ((c = getopt(argc, argv, "")) != EOF) {
switch (c) {
default:
usage();
- exit(1);
+ /*NOTREACHED*/
}
}
argc -= optind;
@@ -78,27 +73,29 @@ char *argv[];
if (argc <= 0) {
usage();
- exit(1);
+ /*NOTREACHED*/
}
/* ld.so magic */
setenv("LD_TRACE_LOADED_OBJECTS", "", 1);
+ rval = 0;
while (argc--) {
int fd;
struct exec hdr;
int status;
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
- perror(*argv);
+ warn("%s", *argv);
rval |= 1;
argv++;
continue;
}
if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
- !(N_GETFLAG(hdr) & EX_DYNAMIC)) {
- fprintf(stderr, "%s: not a dynamic executable\n",
- *argv);
+ !(N_GETFLAG(hdr) & EX_DYNAMIC) ||
+ hdr.a_entry < __LDPGSZ) {
+
+ warnx("%s: not a dynamic executable", *argv);
(void)close(fd);
rval |= 1;
argv++;
@@ -111,14 +108,13 @@ char *argv[];
switch (fork()) {
case -1:
- perror("fork");
- exit(1);
+ err(1, "fork");
break;
default:
- if (wait(&status) <= 0)
- perror("wait");
-
- if (WIFSIGNALED(status)) {
+ if (wait(&status) <= 0) {
+ warn("wait");
+ rval |= 1;
+ } else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s: signal %d\n",
*argv, WTERMSIG(status));
rval |= 1;
@@ -129,7 +125,7 @@ char *argv[];
}
break;
case 0:
- rval != execl(*argv, *argv, NULL) != 0;
+ rval |= execl(*argv, *argv, NULL) != 0;
perror(*argv);
_exit(1);
}
diff --git a/gnu/usr.bin/ld/lib.c b/gnu/usr.bin/ld/lib.c
index f9d8de0fbd7c..19959ef1bdf6 100644
--- a/gnu/usr.bin/ld/lib.c
+++ b/gnu/usr.bin/ld/lib.c
@@ -1,14 +1,16 @@
/*
- * $Id: lib.c,v 1.9 1994/02/13 20:41:37 jkh Exp $ - library routines
+ * $Id: lib.c,v 1.10 1994/06/15 22:39:49 rich Exp $ - library routines
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
+#include <err.h>
#include <fcntl.h>
#include <ar.h>
#include <ranlib.h>
@@ -16,6 +18,7 @@
#include <stab.h>
#include <string.h>
#include <dirent.h>
+#include <ctype.h>
#include "ld.h"
@@ -26,15 +29,15 @@ static struct file_entry *decode_library_subfile __P((int,
int, int *));
/*
- * Search the library ENTRY, already open on descriptor DESC. This means
+ * Search the library ENTRY, already open on descriptor FD. This means
* deciding which library members to load, making a chain of `struct
* file_entry' for those members, and entering their global symbols in the
* hash table.
*/
void
-search_library(desc, entry)
- int desc;
+search_library(fd, entry)
+ int fd;
struct file_entry *entry;
{
int member_length;
@@ -45,7 +48,7 @@ search_library(desc, entry)
return;
/* Examine its first member, which starts SARMAG bytes in. */
- subentry = decode_library_subfile(desc, entry, SARMAG, &member_length);
+ subentry = decode_library_subfile(fd, entry, SARMAG, &member_length);
if (!subentry)
return;
@@ -55,21 +58,21 @@ search_library(desc, entry)
/* Search via __.SYMDEF if that exists, else linearly. */
if (!strcmp(name, "__.SYMDEF"))
- symdef_library(desc, entry, member_length);
+ symdef_library(fd, entry, member_length);
else
- linear_library(desc, entry);
+ linear_library(fd, entry);
}
/*
* Construct and return a file_entry for a library member. The library's
- * file_entry is library_entry, and the library is open on DESC.
+ * file_entry is library_entry, and the library is open on FD.
* SUBFILE_OFFSET is the byte index in the library of this member's header.
* We store the length of the member into *LENGTH_LOC.
*/
static struct file_entry *
-decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
- int desc;
+decode_library_subfile(fd, library_entry, subfile_offset, length_loc)
+ int fd;
struct file_entry *library_entry;
int subfile_offset;
int *length_loc;
@@ -82,17 +85,20 @@ decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
struct ar_hdr hdr1;
register struct file_entry *subentry;
- lseek(desc, subfile_offset, 0);
+ lseek(fd, subfile_offset, 0);
- bytes_read = read(desc, &hdr1, sizeof hdr1);
+ bytes_read = read(fd, &hdr1, sizeof hdr1);
if (!bytes_read)
return 0; /* end of archive */
if (sizeof hdr1 != bytes_read)
- fatal_with_file("malformed library archive ", library_entry);
+ errx(1, "%s: malformed library archive",
+ get_file_name(library_entry));
if (sscanf(hdr1.ar_size, "%d", &member_length) != 1)
- fatal_with_file("malformatted header of archive member in ", library_entry);
+ errx(1, "%s: malformatted header of archive member: %.*s",
+ get_file_name(library_entry),
+ sizeof(hdr1.ar_name), hdr1.ar_name);
subentry = (struct file_entry *) xmalloc(sizeof(struct file_entry));
bzero(subentry, sizeof(struct file_entry));
@@ -116,10 +122,10 @@ decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
namelen = atoi(&hdr1.ar_name[sizeof(AR_EFMT1) - 1]);
name = (char *)xmalloc(namelen + 1);
- if (read(desc, name, namelen) != namelen)
- fatal_with_file(
- "malformatted header of archive member in ",
- library_entry);
+ if (read(fd, name, namelen) != namelen)
+ errx(1, "%s: malformatted archive member: %.*s",
+ get_file_name(library_entry),
+ sizeof(hdr1.ar_name), hdr1.ar_name);
name[namelen] = 0;
content_length -= namelen;
starting_offset += namelen;
@@ -134,14 +140,16 @@ decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
subentry->filename = name;
subentry->local_sym_name = name;
+ subentry->starting_offset = starting_offset;
+ subentry->superfile = library_entry;
+ subentry->total_size = content_length;
+#if 0
subentry->symbols = 0;
subentry->strings = 0;
subentry->subfiles = 0;
- subentry->starting_offset = starting_offset;
- subentry->superfile = library_entry;
subentry->chain = 0;
subentry->flags = 0;
- subentry->total_size = content_length;
+#endif
(*length_loc) = member_length;
@@ -151,15 +159,15 @@ decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
static int subfile_wanted_p __P((struct file_entry *));
/*
- * Search a library that has a __.SYMDEF member. DESC is a descriptor on
+ * Search a library that has a __.SYMDEF member. FD is a descriptor on
* which the library is open. The file pointer is assumed to point at the
* __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the
* length of the __.SYMDEF data.
*/
static void
-symdef_library(desc, entry, member_length)
- int desc;
+symdef_library(fd, entry, member_length)
+ int fd;
struct file_entry *entry;
int member_length;
{
@@ -174,14 +182,16 @@ symdef_library(desc, entry, member_length)
struct file_entry *prev = 0;
int prev_offset = 0;
- bytes_read = read(desc, symdef_data, member_length);
+ bytes_read = read(fd, symdef_data, member_length);
if (bytes_read != member_length)
- fatal_with_file("malformatted __.SYMDEF in ", entry);
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
nsymdefs = md_swap_long(*symdef_data) / sizeof(struct ranlib);
if (nsymdefs < 0 ||
nsymdefs * sizeof(struct ranlib) + 2 * sizeof(int) > member_length)
- fatal_with_file("malformatted __.SYMDEF in ", entry);
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
symdef_base = (struct ranlib *) (symdef_data + 1);
length_of_strings = md_swap_long(*(int *) (symdef_base + nsymdefs));
@@ -189,7 +199,8 @@ symdef_library(desc, entry, member_length)
if (length_of_strings < 0
|| nsymdefs * sizeof(struct ranlib) + length_of_strings
+ 2 * sizeof(int) > member_length)
- fatal_with_file("malformatted __.SYMDEF in ", entry);
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
sym_name_base = sizeof(int) + (char *) (symdef_base + nsymdefs);
@@ -199,7 +210,8 @@ symdef_library(desc, entry, member_length)
register int index = symdef_base[i].ran_un.ran_strx;
if (index < 0 || index >= length_of_strings
|| (index && *(sym_name_base + index - 1)))
- fatal_with_file("malformatted __.SYMDEF in ", entry);
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
}
/*
@@ -268,19 +280,19 @@ symdef_library(desc, entry, member_length)
* Read the symbol table of the archive member.
*/
- subentry = decode_library_subfile(desc,
+ subentry = decode_library_subfile(fd,
entry, offset, &junk);
if (subentry == 0)
- fatal(
+ errx(1,
"invalid offset for %s in symbol table of %s",
sym_name_base
+ symdef_base[i].ran_un.ran_strx,
entry->filename);
- read_entry_symbols(desc, subentry);
+ read_entry_symbols(fd, subentry);
subentry->strings = (char *)
- malloc(subentry->string_size);
- read_entry_strings(desc, subentry);
+ alloca(subentry->string_size);
+ read_entry_strings(fd, subentry);
/*
* Now scan the symbol table and decide whether to
@@ -289,6 +301,7 @@ symdef_library(desc, entry, member_length)
if (!(link_mode & FORCEARCHIVE) &&
!subfile_wanted_p(subentry)) {
+ if (subentry->symbols)
free(subentry->symbols);
free(subentry);
} else {
@@ -301,7 +314,7 @@ symdef_library(desc, entry, member_length)
not_finished = 1;
- read_entry_relocation(desc, subentry);
+ read_entry_relocation(fd, subentry);
enter_file_symbols(subentry);
if (prev)
@@ -320,28 +333,27 @@ symdef_library(desc, entry, member_length)
if (symdef_base[j].ran_off == offset)
symdef_base[j].ran_un.ran_strx = -1;
}
- }
/*
- * We'll read the strings again if we need them
- * again.
+ * We'll read the strings again
+ * if we need them.
*/
- free(subentry->strings);
subentry->strings = 0;
}
}
+ }
free(symdef_data);
}
/*
* Search a library that has no __.SYMDEF. ENTRY is the library's file_entry.
- * DESC is the descriptor it is open on.
+ * FD is the descriptor it is open on.
*/
static void
-linear_library(desc, entry)
- int desc;
+linear_library(fd, entry)
+ int fd;
struct file_entry *entry;
{
register struct file_entry *prev = 0;
@@ -353,22 +365,23 @@ linear_library(desc, entry)
int member_length;
register struct file_entry *subentry;
- subentry = decode_library_subfile(desc, entry,
+ subentry = decode_library_subfile(fd, entry,
this_subfile_offset, &member_length);
if (!subentry)
return;
- read_entry_symbols(desc, subentry);
- subentry->strings = (char *) alloca(subentry->string_size);
- read_entry_strings(desc, subentry);
+ read_entry_symbols(fd, subentry);
+ subentry->strings = (char *)alloca(subentry->string_size);
+ read_entry_strings(fd, subentry);
if (!(link_mode & FORCEARCHIVE) &&
!subfile_wanted_p(subentry)) {
+ if (subentry->symbols)
free(subentry->symbols);
free(subentry);
} else {
- read_entry_relocation(desc, subentry);
+ read_entry_relocation(fd, subentry);
enter_file_symbols(subentry);
if (prev)
@@ -527,6 +540,7 @@ subfile_wanted_p(entry)
/*
* But this member wants it to be
* a common; ignore it.
+ */
continue;
}
@@ -550,7 +564,9 @@ subfile_wanted_p(entry)
if (write_map) {
print_file_name(entry, stdout);
- fprintf(stdout, " needed due to shared lib ref %s\n", sp->name);
+ fprintf(stdout,
+ " needed due to shared lib ref %s\n",
+ sp->name);
}
return 1;
}
@@ -561,12 +577,12 @@ subfile_wanted_p(entry)
/*
* Read the symbols of dynamic entity ENTRY into core. Assume it is already
- * open, on descriptor DESC.
+ * open, on descriptor FD.
*/
void
-read_shared_object (desc, entry)
+read_shared_object(fd, entry)
struct file_entry *entry;
- int desc;
+ int fd;
{
struct _dynamic dyn;
struct section_dispatch_table sdt;
@@ -575,22 +591,23 @@ read_shared_object (desc, entry)
int n, i, has_nz = 0;
if (!(entry->flags & E_HEADER_VALID))
- read_header (desc, entry);
+ read_header(fd, entry);
/* Read DYNAMIC structure (first in data segment) */
- lseek (desc,
- text_offset (entry) + entry->header.a_text,
- L_SET);
- if (read(desc, &dyn, sizeof dyn) != sizeof dyn) {
- fatal_with_file (
- "premature eof in data segment of ", entry);
+ if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
+ (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &dyn, sizeof dyn) != sizeof dyn) {
+ errx(1, "%s: premature EOF reading _dynamic",
+ get_file_name(entry));
}
md_swapin__dynamic(&dyn);
/* Check version */
switch (dyn.d_version) {
default:
- fatal_with_file( "unsupported _DYNAMIC version ", entry);
+ errx(1, "%s: unsupported _DYNAMIC version: %d",
+ get_file_name(entry), dyn.d_version);
break;
case LD_VERSION_SUN:
break;
@@ -600,29 +617,33 @@ read_shared_object (desc, entry)
}
/* Read Section Dispatch Table (from data segment) */
- lseek (desc,
+ if (lseek(fd,
text_offset(entry) + (long)dyn.d_un.d_sdt -
(DATA_START(entry->header) - N_DATOFF(entry->header)),
- L_SET);
- if (read(desc, &sdt, sizeof sdt) != sizeof sdt) {
- fatal_with_file( "premature eof in data segment of ", entry);
- }
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &sdt, sizeof sdt) != sizeof sdt)
+ errx(1, "%s: premature EOF reading sdt",
+ get_file_name(entry));
md_swapin_section_dispatch_table(&sdt);
/* Read symbols (text segment) */
n = sdt.sdt_strings - sdt.sdt_nzlist;
entry->nsymbols = n /
(has_nz ? sizeof(struct nzlist) : sizeof(struct nlist));
- nzp = (struct nzlist *)(np = (struct nlist *) alloca (n));
+ nzp = (struct nzlist *)(np = (struct nlist *)alloca (n));
entry->symbols = (struct localsymbol *)
xmalloc(entry->nsymbols * sizeof(struct localsymbol));
- lseek(desc, text_offset(entry) + (long)sdt.sdt_nzlist -
+
+ if (lseek(fd,
+ text_offset(entry) + (long)sdt.sdt_nzlist -
(TEXT_START(entry->header) - N_TXTOFF(entry->header)),
- L_SET);
- if (read(desc, (char *)nzp, n) != n) {
- fatal_with_file(
- "premature eof while reading object symbols ", entry);
- }
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, (char *)nzp, n) != n)
+ errx(1, "%s: premature EOF reading symbols ",
+ get_file_name(entry));
+
if (has_nz)
md_swapin_zsymbols(nzp, entry->nsymbols);
else
@@ -645,15 +666,16 @@ read_shared_object (desc, entry)
/* Read strings (text segment) */
n = entry->string_size = sdt.sdt_str_sz;
- entry->strings = (char *) alloca(n);
+ entry->strings = (char *)alloca(n);
entry->strings_offset = text_offset(entry) + sdt.sdt_strings;
- lseek(desc, entry->strings_offset -
+ if (lseek(fd,
+ entry->strings_offset -
(TEXT_START(entry->header) - N_TXTOFF(entry->header)),
- L_SET);
- if (read(desc, entry->strings, n) != n) {
- fatal_with_file(
- "premature eof while reading object strings ", entry);
- }
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, entry->strings, n) != n)
+ errx(1, "%s: premature EOF reading strings",
+ get_file_name(entry));
enter_file_symbols (entry);
entry->strings = 0;
@@ -675,19 +697,21 @@ read_shared_object (desc, entry)
bzero(subentry, sizeof(struct file_entry));
subentry->superfile = entry;
- lseek(desc, offset -
- (TEXT_START(entry->header) - N_TXTOFF(entry->header)),
- L_SET);
- if (read(desc, &sod, sizeof(sod)) != sizeof(sod)) {
- fatal_with_file(
- "premature eof while reading sod ",
- entry);
- }
+ if (lseek(fd,
+ offset - (TEXT_START(entry->header) -
+ N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &sod, sizeof(sod)) != sizeof(sod))
+ errx(1, "%s: premature EOF reding sod",
+ get_file_name(entry));
md_swapin_sod(&sod, 1);
- (void)lseek(desc, (off_t)sod.sod_name -
- (TEXT_START(entry->header) - N_TXTOFF(entry->header)),
- L_SET);
- (void)read(desc, name, sizeof(name)); /*XXX*/
+ if (lseek(fd,
+ (off_t)sod.sod_name - (TEXT_START(entry->header) -
+ N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ (void)read(fd, name, sizeof(name)); /*XXX*/
if (sod.sod_library) {
int sod_major = sod.sod_major;
int sod_minor = sod.sod_minor;
@@ -695,7 +719,7 @@ read_shared_object (desc, entry)
libname = findshlib(name,
&sod_major, &sod_minor, 0);
if (libname == NULL)
- fatal("no shared -l%s.%d.%d available",
+ errx(1,"no shared -l%s.%d.%d available",
name, sod.sod_major, sod.sod_minor);
subentry->filename = libname;
subentry->local_sym_name = concat("-l", name, "");
@@ -710,7 +734,7 @@ read_shared_object (desc, entry)
else
entry->subfiles = subentry;
prev = subentry;
- desc = file_open(entry);
+ fd = file_open(entry);
if ((offset = (off_t)sod.sod_next) == 0)
break;
}
@@ -746,7 +770,7 @@ read_shared_object (desc, entry)
(void)read(fd, armag, SARMAG);
(void)close(fd);
if (strncmp(armag, ARMAG, SARMAG) != 0) {
- error("%s: malformed silly archive",
+ warnx("%s: malformed silly archive",
get_file_name(entry));
goto out;
}
@@ -774,9 +798,8 @@ int
findlib(p)
struct file_entry *p;
{
- int desc;
int i;
- int len;
+ int fd = -1;
int major = -1, minor = -1;
char *cp, *fname = NULL;
@@ -785,14 +808,14 @@ struct file_entry *p;
fname = findshlib(p->filename, &major, &minor, 1);
- if (fname && (desc = open (fname, O_RDONLY, 0)) > 0) {
+ if (fname && (fd = open(fname, O_RDONLY, 0)) > 0) {
p->filename = fname;
p->lib_major = major;
p->lib_minor = minor;
p->flags &= ~E_SEARCH_DIRS;
- return desc;
+ return fd;
}
- free (fname);
+ (void)free(fname);
dot_a:
p->flags &= ~E_SEARCH_DYNAMIC;
@@ -804,16 +827,17 @@ dot_a:
fname = concat("lib", p->filename, ".a");
for (i = 0; i < n_search_dirs; i++) {
- register char *string
- = concat (search_dirs[i], "/", fname);
- desc = open (string, O_RDONLY, 0);
- if (desc > 0) {
- p->filename = string;
+ register char *path
+ = concat(search_dirs[i], "/", fname);
+ fd = open(path, O_RDONLY, 0);
+ if (fd > 0) {
+ p->filename = path;
p->flags &= ~E_SEARCH_DIRS;
break;
}
- free (string);
+ (void)free(path);
}
- return desc;
+ (void)free(fname);
+ return fd;
}
diff --git a/gnu/usr.bin/ld/rrs.c b/gnu/usr.bin/ld/rrs.c
index 050fcd6552ea..ab950c7ef31b 100644
--- a/gnu/usr.bin/ld/rrs.c
+++ b/gnu/usr.bin/ld/rrs.c
@@ -27,24 +27,25 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: rrs.c,v 1.11 1994/02/13 20:41:40 jkh Exp $
+ * $Id: rrs.c,v 1.12 1994/06/15 22:39:52 rich Exp $
*/
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
#include <fcntl.h>
#include <ar.h>
#include <ranlib.h>
#include <a.out.h>
#include <stab.h>
#include <string.h>
-#include <strings.h>
#include "ld.h"
@@ -228,7 +229,7 @@ struct localsymbol *lsp;
if (!RELOC_EXTERN_P(r)) {
if (sp != NULL) {
- error("%s: relocation for internal symbol expected at %#x",
+ warnx("%s: relocation for internal symbol expected at %#x",
get_file_name(entry), RELOC_ADDRESS(r));
return;
}
@@ -253,7 +254,7 @@ struct localsymbol *lsp;
} else {
if (sp == NULL) {
- error("%s: relocation must refer to global symbol at %#x",
+ warnx("%s: relocation must refer to global symbol at %#x",
get_file_name(entry), RELOC_ADDRESS(r));
return;
}
@@ -296,7 +297,7 @@ rrs_next_reloc()
r = rrs_reloc + claimed_rrs_relocs++;
if (claimed_rrs_relocs > reserved_rrs_relocs)
- fatal("internal error: RRS relocs exceed allocation %d",
+ errx(1, "internal error: RRS relocs exceed allocation %d",
reserved_rrs_relocs);
return r;
}
@@ -319,7 +320,7 @@ long *relocation;
struct relocation_info *r = rrs_next_reloc();
if (rp->r_address < text_start + text_size)
- error("%s: RRS text relocation at %#x for \"%s\"",
+ warnx("%s: RRS text relocation at %#x for \"%s\"",
get_file_name(entry), rp->r_address, sp->name);
#ifdef DEBUG
@@ -330,7 +331,7 @@ printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
if (link_mode & SYMBOLIC) {
if (!sp->defined)
- error("Cannot reduce symbol \"%s\" in %s",
+ warnx("Cannot reduce symbol \"%s\" in %s",
sp->name, get_file_name(entry));
RELOC_EXTERN_P(r) = 0;
*relocation += sp->value;
@@ -358,20 +359,20 @@ long addend;
return rrs_sdt.sdt_plt + sp->jmpslot_offset;
#ifdef DEBUG
-printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x (textreloc %#x)\n",
+printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n",
get_file_name(entry),
- sp->name, sp->rrs_symbolnum, sp->jmpslot_offset, text_relocation);
+ sp->name, sp->rrs_symbolnum, sp->jmpslot_offset);
#endif
if (sp->jmpslot_offset == -1)
- fatal(
+ errx(1,
"internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
get_file_name(entry),
sp->name);
if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
if (!sp->defined)
- error("Cannot reduce symbol \"%s\" in %s",
+ warnx("Cannot reduce symbol \"%s\" in %s",
sp->name, get_file_name(entry));
md_fix_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
@@ -439,7 +440,7 @@ printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
sp->name, sp->rrs_symbolnum, sp->gotslot_offset, addend);
#endif
if (sp->gotslot_offset == -1)
- fatal(
+ errx(1,
"internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
get_file_name(entry), sp->name);
@@ -464,7 +465,7 @@ printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
* RRS_PARTIAL: we don't link against shared objects,
* so again all symbols must be known.
*/
- error("Cannot reduce symbol \"%s\" in %s",
+ warnx("Cannot reduce symbol \"%s\" in %s",
sp->name, get_file_name(entry));
} else {
@@ -483,7 +484,7 @@ printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
* NOTE: RRS_PARTIAL implies !SHAREABLE.
*/
if (!sp->defined)
- error("Cannot reduce symbol \"%s\" in %s",
+ warnx("Cannot reduce symbol \"%s\" in %s",
sp->name, get_file_name(entry));
return sp->gotslot_offset;
}
@@ -532,7 +533,7 @@ printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
#endif
if (lsp->gotslot_offset == -1)
- fatal(
+ errx(1,
"internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n",
get_file_name(entry), RELOC_ADDRESS(rp));
@@ -568,7 +569,8 @@ symbol *sp;
return;
if (!(sp->flags & GS_CPYRELOCRESERVED))
- fatal("internal error: %s: claim_cpy_reloc: %s: no reservation\n",
+ errx(1,
+ "internal error: %s: claim_cpy_reloc: %s: no reservation\n",
get_file_name(entry), sp->name);
#ifdef DEBUG
@@ -652,7 +654,6 @@ consider_rrs_section_lengths()
{
int n;
struct shobj *shp, **shpp;
- int symbolsize;
#ifdef notyet
/* We run into trouble with this as long as shared object symbols
@@ -663,7 +664,7 @@ consider_rrs_section_lengths()
for (shpp = &rrs_shobjs; *shpp; shpp = &(*shpp)->next) {
while (*shpp && !((*shpp)->entry->flags & E_SYMBOLS_USED)) {
if (--number_of_shobjs < 0)
- fatal("internal error: number_of_shobjs < 0");
+ errx(1, "internal error: number_of_shobjs < 0");
*shpp = (*shpp)->next;
}
if (*shpp == NULL)
@@ -703,7 +704,7 @@ consider_rrs_section_lengths()
*/
if (!(link_mode & SHAREABLE) &&
!(dynamic_symbol->flags & GS_REFERENCED))
- fatal("No reference to __DYNAMIC");
+ errx(1, "No reference to __DYNAMIC");
dynamic_symbol->flags |= GS_REFERENCED;
@@ -891,21 +892,21 @@ write_rrs_data()
pos = rrs_data_start + (N_DATOFF(outheader) - DATA_START(outheader));
if (lseek(outdesc, pos, L_SET) != pos)
- fatal("write_rrs_data: cant position in output file");
+ err(1, "write_rrs_data: lseek");
if (rrs_section_type == RRS_PARTIAL) {
/*
* Only a GOT and PLT are needed.
*/
if (number_of_gotslots <= 1)
- fatal("write_rrs_data: # gotslots <= 1");
+ errx(1, "write_rrs_data: # gotslots <= 1");
md_swapout_got(rrs_got, number_of_gotslots);
mywrite(rrs_got, number_of_gotslots,
sizeof(got_t), outdesc);
if (number_of_jmpslots <= 1)
- fatal("write_rrs_data: # jmpslots <= 1");
+ errx(1, "write_rrs_data: # jmpslots <= 1");
md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
mywrite(rrs_plt, number_of_jmpslots,
@@ -945,7 +946,7 @@ write_rrs_text()
pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
if (lseek(outdesc, pos, L_SET) != pos)
- fatal("write_rrs_text: cant position in output file");
+ err(1, "write_rrs_text: lseek");
/* Write relocation records */
md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
@@ -989,7 +990,7 @@ write_rrs_text()
if ((long)nlp - (long)rrs_symbols >=
number_of_rrs_symbols * rrs_symbol_size)
- fatal(
+ errx(1,
"internal error: rrs symbols exceed allocation %d ",
number_of_rrs_symbols);
@@ -1040,14 +1041,14 @@ write_rrs_text()
* Define a "weak" function symbol.
*/
if (sp->aux != AUX_FUNC)
- fatal("%s: non-function jmpslot",
+ errx(1, "%s: non-function jmpslot",
sp->name);
nlp->nz_other = N_OTHER(0, sp->aux);
nlp->nz_value =
rrs_sdt.sdt_plt + sp->jmpslot_offset;
}
} else
- fatal(
+ errx(1,
"internal error: %s defined in mysterious way",
sp->name);
@@ -1079,7 +1080,7 @@ write_rrs_text()
} END_EACH_SYMBOL;
if (MALIGN(offset) != rrs_strtab_size)
- fatal(
+ errx(1,
"internal error: inconsistent RRS string table length: %d, expected %d",
offset, rrs_strtab_size);
@@ -1103,7 +1104,7 @@ write_rrs_text()
char *name = shp->entry->local_sym_name;
if (i >= number_of_shobjs)
- fatal("internal error: # of link objects exceeds %d",
+ errx(1, "internal error: # of link objects exceeds %d",
number_of_shobjs);
sodp[i].sod_name = pos;
@@ -1122,7 +1123,8 @@ write_rrs_text()
}
if (i < number_of_shobjs)
- fatal("internal error: # of link objects less then expected %d",
+ errx(1,
+ "internal error: # of link objects less then expected %d",
number_of_shobjs);
md_swapout_sod(sodp, number_of_shobjs);
@@ -1148,7 +1150,7 @@ write_rrs()
*/
if (rrs_section_type == RRS_NONE) {
if (reserved_rrs_relocs > 1)
- fatal(
+ errx(1,
"internal error: RRS relocs in static program: %d",
reserved_rrs_relocs-1);
return;
@@ -1159,14 +1161,17 @@ printf("rrs_relocs %d, gotslots %d, jmpslots %d\n",
reserved_rrs_relocs, number_of_gotslots-1, number_of_jmpslots-1);
#endif
+#if 0
+ /* Must fix this check: misses out when linking PIC code but no
+ shared object involved: reserved relocs are never claimed!
+ */
if (claimed_rrs_relocs != reserved_rrs_relocs) {
-/*
- fatal("internal error: reserved relocs(%d) != claimed(%d)",
+ errx(1, "internal error: reserved relocs(%d) != claimed(%d)",
reserved_rrs_relocs, claimed_rrs_relocs);
-*/
printf("FIX:internal error: reserved relocs(%d) != claimed(%d)\n",
reserved_rrs_relocs, claimed_rrs_relocs);
}
+#endif
/* Write the RRS segments. */
write_rrs_text ();
diff --git a/gnu/usr.bin/ld/rtld/Makefile b/gnu/usr.bin/ld/rtld/Makefile
index 02a4437c2645..8cc208569541 100644
--- a/gnu/usr.bin/ld/rtld/Makefile
+++ b/gnu/usr.bin/ld/rtld/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 1994/02/13 20:42:48 jkh Exp $
+# $Id: Makefile,v 1.10 1994/03/10 23:19:54 ats Exp $
PROG= ld.so
SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c
@@ -9,7 +9,7 @@ PICFLAG=-fpic
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD
LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic
ASFLAGS+=-k
-LDADD+= -lc_pic
+LDADD+= -lc_pic -lgcc_pic
BINDIR= /usr/libexec
.SUFFIXES: .S
diff --git a/gnu/usr.bin/ld/rtld/malloc.c b/gnu/usr.bin/ld/rtld/malloc.c
index 4a9e7e65e9b3..42cf8d6318f2 100644
--- a/gnu/usr.bin/ld/rtld/malloc.c
+++ b/gnu/usr.bin/ld/rtld/malloc.c
@@ -33,7 +33,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/
-static char *rcsid = "$Id: malloc.c,v 1.1 1994/02/13 20:44:09 jkh Exp $";
+static char *rcsid = "$Id: malloc.c,v 1.2 1994/06/15 22:41:13 rich Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -48,6 +48,7 @@ static char *rcsid = "$Id: malloc.c,v 1.1 1994/02/13 20:44:09 jkh Exp $";
*/
#include <sys/types.h>
+#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -460,7 +461,7 @@ int n;
caddr_t addr = (caddr_t)
(((int)pagepool_start + pagesz - 1) & ~(pagesz - 1));
if (munmap(addr, pagepool_end - addr) != 0)
- perror("munmap");
+ warn("morepages: munmap %p", addr);
}
offset = (int)pagepool_start - ((int)pagepool_start & ~(pagesz - 1));
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c
index 8ed0f0683ce3..05c3e369fec3 100644
--- a/gnu/usr.bin/ld/rtld/rtld.c
+++ b/gnu/usr.bin/ld/rtld/rtld.c
@@ -27,13 +27,10 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: rtld.c,v 1.15 1994/02/13 20:42:53 jkh Exp $
+ * $Id: rtld.c,v 1.17 1994/06/15 22:41:15 rich Exp $
*/
-#include <machine/vmparam.h>
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
@@ -43,13 +40,16 @@
#include <sys/mman.h>
#ifndef BSD
#define MAP_COPY MAP_PRIVATE
-#define MAP_FILE 0
#define MAP_ANON 0
#endif
+#include <err.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#if __STDC__
#include <stdarg.h>
#else
@@ -123,34 +123,37 @@ struct somap_private {
#define LM_PARENT(smp) (LM_PRIVATE(smp)->spd_parent)
char **environ;
+char *__progname;
int errno;
+
static uid_t uid, euid;
static gid_t gid, egid;
static int careful;
-static char *main_progname = "main";
+static char __main_progname[] = "main";
+static char *main_progname = __main_progname;
+static char us[] = "/usr/libexec/ld.so";
struct so_map *link_map_head, *main_map;
struct so_map **link_map_tail = &link_map_head;
struct rt_symbol *rt_symbol_head;
-static void *dlopen __P((char *, int));
-static int dlclose __P((void *));
-static void *dlsym __P((void *, char *));
-static int dlctl __P((void *, int, void *));
+static void *__dlopen __P((char *, int));
+static int __dlclose __P((void *));
+static void *__dlsym __P((void *, char *));
+static int __dlctl __P((void *, int, void *));
static struct ld_entry ld_entry = {
- dlopen, dlclose, dlsym, dlctl
+ __dlopen, __dlclose, __dlsym, __dlctl
};
void xprintf __P((char *, ...));
-static void init_brk __P((void));
static void load_objects __P(( struct crt_ldso *,
struct _dynamic *));
static struct so_map *map_object __P((struct sod *, struct so_map *));
static struct so_map *alloc_link_map __P(( char *, struct sod *,
struct so_map *, caddr_t,
struct _dynamic *));
-static void inline check_text_reloc __P(( struct relocation_info *,
+static inline void check_text_reloc __P(( struct relocation_info *,
struct so_map *,
caddr_t));
static void reloc_map __P((struct so_map *));
@@ -188,7 +191,6 @@ struct _dynamic *dp;
int n;
int nreloc; /* # of ld.so relocations */
struct relocation_info *reloc;
- char **envp;
struct so_debug *ddp;
struct so_map *smp;
@@ -217,7 +219,7 @@ struct _dynamic *dp;
md_relocate_simple(reloc, crtp->crt_ba, addr);
}
- progname = "ld.so";
+ __progname = "ld.so";
if (version >= CRT_VERSION_BSD_3)
main_progname = crtp->crt_prog;
@@ -237,7 +239,10 @@ struct _dynamic *dp;
}
/* Setup directory search */
- std_search_dirs(getenv("LD_LIBRARY_PATH"));
+ add_search_path(getenv("LD_RUN_PATH"));
+ add_search_path(getenv("LD_LIBRARY_PATH"));
+ if (getenv("LD_NOSTD_PATH") == NULL)
+ std_search_path();
/* Load required objects into the process address space */
load_objects(crtp, dp);
@@ -275,12 +280,12 @@ struct _dynamic *dp;
/* Set breakpoint for the benefit of debuggers */
if (mprotect(addr, PAGSIZ,
PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
- perror("mprotect"),
- fatal("Cannot set breakpoint (%s)\n", main_progname);
+ err(1, "Cannot set breakpoint (%s)", main_progname);
}
- md_set_breakpoint(crtp->crt_bp, &ddp->dd_bpt_shadow);
+ md_set_breakpoint((long)crtp->crt_bp, (long *)&ddp->dd_bpt_shadow);
if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) {
- perror("mprotect");
+ err(1, "Cannot re-protect breakpoint (%s)",
+ main_progname);
}
ddp->dd_bpt_addr = crtp->crt_bp;
@@ -311,7 +316,7 @@ struct _dynamic *dp;
LM_PRIVATE(smp)->spd_flags |= RTLD_MAIN;
/* Make an entry for ourselves */
- smp = alloc_link_map("/usr/libexec/ld.so", (struct sod *)0, (struct so_map *)0,
+ smp = alloc_link_map(us, (struct sod *)0, (struct so_map *)0,
(caddr_t)crtp->crt_ba, dp);
LM_PRIVATE(smp)->spd_refcount++;
LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD;
@@ -335,12 +340,11 @@ struct _dynamic *dp;
char *name = (char *)
(sodp->sod_name + LM_LDBASE(smp));
char *fmt = sodp->sod_library ?
- "%s: lib%s.so.%d.%d: %s\n" :
- "%s: %s: %s\n";
- fatal(fmt, main_progname, name,
+ "%s: lib%s.so.%d.%d" :
+ "%s: %s";
+ err(1, fmt, main_progname, name,
sodp->sod_major,
- sodp->sod_minor,
- strerror(errno));
+ sodp->sod_minor);
}
newmap = alloc_link_map(NULL, sodp, smp, 0, 0);
}
@@ -364,17 +368,17 @@ struct _dynamic *dp;
path = "not found";
if (sodp->sod_library)
- printf("\t-l%s.%d => %s (%#x)\n", name,
+ printf("\t-l%s.%d => %s (%p)\n", name,
sodp->sod_major, path, smp->som_addr);
else
- printf("\t%s => %s (%#x)\n", name, path, smp->som_addr);
+ printf("\t%s => %s (%p)\n", name, path, smp->som_addr);
}
exit(0);
}
/*
- * Allocate a new link map for an shared object NAME loaded at ADDR as a
+ * Allocate a new link map for shared object NAME loaded at ADDR as a
* result of the presence of link object LOP in the link map PARENT.
*/
static struct so_map *
@@ -395,7 +399,7 @@ alloc_link_map(path, sodp, parent, addr, dp)
link_map_tail = &smp->som_next;
smp->som_addr = addr;
- smp->som_path = path;
+ smp->som_path = strdup(path);
smp->som_sod = sodp;
smp->som_dynamic = dp;
smp->som_spd = (caddr_t)smpp;
@@ -482,6 +486,7 @@ again:
return NULL;
}
+#if 0
if (mmap(addr + hdr.a_text, hdr.a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FILE|MAP_FIXED|MAP_COPY,
@@ -489,13 +494,19 @@ again:
(void)close(fd);
return NULL;
}
+#endif
+ if (mprotect(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
+ (void)close(fd);
+ return NULL;
+ }
(void)close(fd);
fd = -1;
#ifdef NEED_DEV_ZERO
if ((fd = open("/dev/zero", O_RDWR, 0)) == -1)
- perror("/dev/zero");
+ warn("open: %s", "/dev/zero");
#endif
if (hdr.a_bss && mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
@@ -516,7 +527,7 @@ again:
return alloc_link_map(path, sodp, smp, addr, dp);
}
-static void inline
+static inline void
check_text_reloc(r, smp, addr)
struct relocation_info *r;
struct so_map *smp;
@@ -543,8 +554,7 @@ caddr_t addr;
LD_TEXTSZ(smp->som_dynamic),
PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
- perror("mprotect"),
- fatal("Cannot enable writes to %s:%s\n",
+ err(1, "Cannot enable writes to %s:%s",
main_progname, smp->som_path);
}
@@ -592,7 +602,7 @@ reloc_map(smp)
np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/);
if (np == NULL)
- fatal("Undefined symbol \"%s\" in %s:%s\n",
+ errx(1, "Undefined symbol \"%s\" in %s:%s\n",
sym, main_progname, smp->som_path);
/*
@@ -636,8 +646,7 @@ reloc_map(smp)
LD_TEXTSZ(smp->som_dynamic),
PROT_READ|PROT_EXEC) == -1) {
- perror("mprotect"),
- fatal("Cannot disable writes to %s:%s\n",
+ err(1, "Cannot disable writes to %s:%s\n",
main_progname, smp->som_path);
}
smp->som_write = 0;
@@ -681,7 +690,7 @@ static struct rt_symbol *rt_symtab[RTC_TABSIZE];
/*
* Compute hash value for run-time symbol table
*/
- static int inline
+ static inline int
hash_string(key)
char *key;
{
@@ -784,7 +793,7 @@ lookup(name, src_map, strong)
*/
for (smp = link_map_head; smp; smp = smp->som_next) {
int buckets = LD_BUCKETS(smp->som_dynamic);
- long hashval = 0;
+ long hashval;
struct rrs_hash *hp;
char *cp;
struct nzlist *np;
@@ -801,10 +810,11 @@ lookup(name, src_map, strong)
if (*src_map && smp != *src_map)
continue;
+restart:
/*
* Compute bucket in which the symbol might be found.
*/
- for (cp = name; *cp; cp++)
+ for (hashval = 0, cp = name; *cp; cp++)
hashval = (hashval << 1) + *cp;
hashval = (hashval & 0x7fffffff) % buckets;
@@ -838,6 +848,15 @@ lookup(name, src_map, strong)
/*
* We have a symbol with the name we're looking for.
*/
+ if (np->nz_type == N_INDR+N_EXT) {
+ /*
+ * Next symbol gives the aliased name. Restart
+ * search with new name and confine to this map.
+ */
+ name = stringbase + (++np)->nz_strx;
+ *src_map = smp;
+ goto restart;
+ }
if (np->nz_value == 0)
/* It's not a definition */
@@ -902,7 +921,7 @@ binder(jsp)
}
if (smp == NULL)
- fatal("Call to binder from unknown location: %#x\n", jsp);
+ errx(1, "Call to binder from unknown location: %#x\n", jsp);
index = jsp->reloc_index & JMPSLOT_RELOC_MASK;
@@ -912,7 +931,7 @@ binder(jsp)
np = lookup(sym, &src_map, 1);
if (np == NULL)
- fatal("Undefined symbol \"%s\" called from %s:%s at %#x",
+ errx(1, "Undefined symbol \"%s\" called from %s:%s at %#x",
sym, main_progname, smp->som_path, jsp);
/* Fixup jmpslot so future calls transfer directly to target */
@@ -1074,13 +1093,17 @@ rtfindlib(name, major, minor, usehints)
if (hint)
return hint;
}
- } else {
- /* No LD_LIBRARY_PATH, check default */
- hint = findhint(name, major, minor, NULL);
+ /* Not found in hints, try directory search */
+ hint = (char *)findshlib(name, &major, &minor, 0);
if (hint)
return hint;
}
+ /* No LD_LIBRARY_PATH or lib not found in there; check default */
+ hint = findhint(name, major, minor, NULL);
+ if (hint)
+ return hint;
+
/* No hints available for name */
*usehints = 0;
return (char *)findshlib(name, &major, &minor, 0);
@@ -1108,7 +1131,7 @@ static struct so_map dlmap = {
static int dlerrno;
static void *
-dlopen(name, mode)
+__dlopen(name, mode)
char *name;
int mode;
{
@@ -1126,7 +1149,7 @@ dlopen(name, mode)
return NULL;
}
- sodp->sod_name = (long)name;
+ sodp->sod_name = (long)strdup(name);
sodp->sod_library = 0;
sodp->sod_major = sodp->sod_minor = 0;
@@ -1149,7 +1172,7 @@ xprintf("%s: %s\n", name, strerror(errno));
}
static int
-dlclose(fd)
+__dlclose(fd)
void *fd;
{
struct so_map *smp = (struct so_map *)fd;
@@ -1164,6 +1187,7 @@ xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refc
init_map(smp, "_fini");
#if 0
unmap_object(smp);
+ free(smp->som_sod->sod_name);
free(smp->som_sod);
free(smp);
#endif
@@ -1172,7 +1196,7 @@ xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refc
}
static void *
-dlsym(fd, sym)
+__dlsym(fd, sym)
void *fd;
char *sym;
{
@@ -1199,7 +1223,7 @@ dlsym(fd, sym)
}
static int
-dlctl(fd, cmd, arg)
+__dlctl(fd, cmd, arg)
void *fd, *arg;
int cmd;
{
diff --git a/gnu/usr.bin/ld/shlib.c b/gnu/usr.bin/ld/shlib.c
index a50d498dd6d5..467a007426fd 100644
--- a/gnu/usr.bin/ld/shlib.c
+++ b/gnu/usr.bin/ld/shlib.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: shlib.c,v 1.8 1994/02/13 20:41:43 jkh Exp $
+ * $Id: shlib.c,v 1.9 1994/06/15 22:39:54 rich Exp $
*/
#include <sys/param.h>
@@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
+#include <err.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
@@ -53,7 +54,7 @@ char *strsep();
* Standard directories to search for files specified by -l.
*/
#ifndef STANDARD_SEARCH_DIRS
-#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/X386/lib", "/usr/local/lib"
+#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/X11R6/lib", "/usr/X386/lib", "/usr/local/lib"
#endif
/*
@@ -73,25 +74,32 @@ add_search_dir(name)
char *name;
{
n_search_dirs++;
- search_dirs = (char **)xrealloc(search_dirs,
- n_search_dirs * sizeof(char *));
+ search_dirs = (char **)
+ xrealloc(search_dirs, n_search_dirs * sizeof(char *));
search_dirs[n_search_dirs - 1] = strdup(name);
}
void
-std_search_dirs(paths)
-char *paths;
+add_search_path(path)
+char *path;
{
- char *cp;
- int i, n;
+ register char *cp;
+
+ if (path == NULL)
+ return;
- if (paths != NULL)
/* Add search directories from `paths' */
- while ((cp = strsep(&paths, ":")) != NULL) {
+ while ((cp = strsep(&path, ":")) != NULL) {
add_search_dir(cp);
- if (paths)
- *(paths-1) = ':';
+ if (path)
+ *(path-1) = ':';
}
+}
+
+void
+std_search_path()
+{
+ int i, n;
/* Append standard search directories */
n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
@@ -137,7 +145,7 @@ cmpndewey(d1, n1, d2, n2)
int d1[], d2[];
int n1, n2;
{
- int i;
+ register int i;
for (i = 0; i < n1 && i < n2; i++) {
if (d1[i] < d2[i])
@@ -154,6 +162,9 @@ int n1, n2;
if (i == n2)
return 1;
+
+ errx(1, "cmpndewey: cant happen");
+ return 0;
}
/*
@@ -200,7 +211,7 @@ int do_dot_a;
continue;
while ((dp = readdir(dd)) != NULL) {
- int n, j, might_take_it = 0;
+ int n, might_take_it = 0;
if (do_dot_a && path == NULL &&
dp->d_namlen == len + 2 &&
diff --git a/gnu/usr.bin/ld/sparc/md.c b/gnu/usr.bin/ld/sparc/md.c
index 07de1c2df109..077f6853d851 100644
--- a/gnu/usr.bin/ld/sparc/md.c
+++ b/gnu/usr.bin/ld/sparc/md.c
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,15 +27,16 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: md.c,v 1.7 1994/02/13 20:43:03 jkh Exp $
+ * $Id: md.c,v 1.8 1994/06/15 22:41:19 rich Exp $
*/
#include <sys/param.h>
+#include <sys/types.h>
+#include <a.out.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/types.h>
+#include <err.h>
#include <fcntl.h>
-#include <a.out.h>
#include <stab.h>
#include <string.h>
@@ -165,7 +166,8 @@ int relocatable_output;
*(u_long *) (addr) |= relocation;
break;
default:
- fatal( "Unimplemented relocation field length in");
+ errx(1, "Unimplemented relocation field length: %d",
+ RELOC_TARGET_SIZE(r));
}
}
diff --git a/gnu/usr.bin/ld/symbol.c b/gnu/usr.bin/ld/symbol.c
index 495726565e58..3d77427db377 100644
--- a/gnu/usr.bin/ld/symbol.c
+++ b/gnu/usr.bin/ld/symbol.c
@@ -1,16 +1,16 @@
/*
- * $Id: symbol.c,v 1.4 1994/02/13 20:41:46 jkh Exp $ - symbol table routines
+ * $Id: symbol.c,v 1.5 1994/06/15 22:39:56 rich Exp $ - symbol table routines
*/
/* Create the symbol table entries for `etext', `edata' and `end'. */
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "ld.h"
@@ -25,8 +25,8 @@ symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
symbol *dynamic_symbol; /* the symbol __DYNAMIC */
void
-symtab_init (relocatable_output)
-int relocatable_output;
+symtab_init(relocatable_output)
+ int relocatable_output;
{
/*
* Put linker reserved symbols into symbol table.
@@ -45,18 +45,18 @@ int relocatable_output;
#define GOT_SYM "_GLOBAL_OFFSET_TABLE_"
#endif
- dynamic_symbol = getsym (DYN_SYM);
+ dynamic_symbol = getsym(DYN_SYM);
dynamic_symbol->defined = relocatable_output?N_UNDF:(N_DATA | N_EXT);
- got_symbol = getsym (GOT_SYM);
+ got_symbol = getsym(GOT_SYM);
got_symbol->defined = N_DATA | N_EXT;
if (relocatable_output)
return;
- etext_symbol = getsym (ETEXT_SYM);
- edata_symbol = getsym (EDATA_SYM);
- end_symbol = getsym (END_SYM);
+ etext_symbol = getsym(ETEXT_SYM);
+ edata_symbol = getsym(EDATA_SYM);
+ end_symbol = getsym(END_SYM);
etext_symbol->defined = N_TEXT | N_EXT;
edata_symbol->defined = N_DATA | N_EXT;
@@ -67,7 +67,9 @@ int relocatable_output;
end_symbol->flags |= GS_REFERENCED;
}
-/* Compute the hash code for symbol name KEY. */
+/*
+ * Compute the hash code for symbol name KEY.
+ */
int
hash_string (key)
@@ -84,8 +86,10 @@ hash_string (key)
return k;
}
-/* Get the symbol table entry for the global symbol named KEY.
- Create one if there is none. */
+/*
+ * Get the symbol table entry for the global symbol named KEY.
+ * Create one if there is none.
+ */
symbol *
getsym(key)
@@ -95,16 +99,16 @@ getsym(key)
register symbol *bp;
/* Determine the proper bucket. */
- hashval = hash_string (key) % SYMTABSIZE;
+ hashval = hash_string(key) % SYMTABSIZE;
/* Search the bucket. */
for (bp = symtab[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
+ if (strcmp(key, bp->name) == 0)
return bp;
/* Nothing was found; create a new symbol table entry. */
- bp = (symbol *) xmalloc (sizeof (symbol));
- bp->name = (char *) xmalloc (strlen (key) + 1);
+ bp = (symbol *)xmalloc(sizeof(symbol));
+ bp->name = (char *)xmalloc(strlen(key) + 1);
strcpy (bp->name, key);
bp->refs = 0;
bp->defined = 0;
@@ -146,13 +150,11 @@ getsym_soft (key)
register symbol *bp;
/* Determine which bucket. */
-
- hashval = hash_string (key) % SYMTABSIZE;
+ hashval = hash_string(key) % SYMTABSIZE;
/* Search the bucket. */
-
for (bp = symtab[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
+ if (strcmp(key, bp->name) == 0)
return bp;
return 0;
diff --git a/gnu/usr.bin/ld/warnings.c b/gnu/usr.bin/ld/warnings.c
index 9d2634f35f52..8306febafa77 100644
--- a/gnu/usr.bin/ld/warnings.c
+++ b/gnu/usr.bin/ld/warnings.c
@@ -1,15 +1,16 @@
/*
- * $Id: warnings.c,v 1.6 1994/02/13 20:41:48 jkh Exp $
+ * $Id: warnings.c,v 1.8 1994/06/15 22:40:00 rich Exp $
*/
#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <fcntl.h>
#include <ar.h>
#include <ranlib.h>
@@ -73,83 +74,19 @@ get_file_name (entry)
}
if (entry->superfile) {
- supfile = get_file_name (entry->superfile);
- result = (char *) xmalloc (strlen(supfile)
- + strlen(entry->filename) + 3);
- sprintf (result, "%s(%s)", supfile, entry->filename);
- free (supfile);
+ supfile = get_file_name(entry->superfile);
+ result = (char *)
+ xmalloc(strlen(supfile) + strlen(entry->filename) + 3);
+ (void)sprintf(result, "%s(%s)", supfile, entry->filename);
+ free(supfile);
} else {
- result = (char *) xmalloc (strlen (entry->filename) + 1);
- strcpy (result, entry->filename);
+ result = (char *)xmalloc(strlen(entry->filename) + 1);
+ strcpy(result, entry->filename);
}
return result;
}
-/*
- * Report a fatal error. The error message is STRING followed by the
- * filename of ENTRY.
- */
-void
-#if __STDC__
-fatal_with_file (char *fmt, struct file_entry *entry, ...)
-#else
-fatal_with_file (fmt, entry, va_alist)
- char *fmt;
- struct file_entry *entry;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "%s: ", progname);
- (void)vfprintf(stderr, fmt, ap);
- print_file_name (entry, stderr);
- (void)fprintf(stderr, "\n");
-
- va_end(ap);
- exit (1);
-}
-
-/*
- * Report a fatal error using the message for the last failed system call,
- * followed by the string NAME.
- */
-void
-perror_name (name)
- char *name;
-{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- fatal (s, name);
-}
-
-/*
- * Report a fatal error using the message for the last failed system call,
- * followed by the name of file ENTRY.
- */
-void
-perror_file (entry)
- struct file_entry *entry;
-{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for ");
- else
- s = "cannot open ";
- fatal_with_file (s, entry);
-}
-
-
/* Print a complete or partial map of the output file. */
static void describe_file_sections __P((struct file_entry *, FILE *));
@@ -160,7 +97,7 @@ print_symbols(outfile)
FILE *outfile;
{
fprintf(outfile, "\nFiles:\n\n");
- each_file(describe_file_sections, outfile);
+ each_file(describe_file_sections, (void *)outfile);
fprintf(outfile, "\nGlobal symbols:\n\n");
FOR_EACH_SYMBOL(i, sp) {
@@ -178,7 +115,7 @@ print_symbols(outfile)
sp->name, sp->value, sp->size);
} END_EACH_SYMBOL;
- each_file(list_file_locals, outfile);
+ each_file(list_file_locals, (void *)outfile);
}
static void
@@ -189,7 +126,7 @@ describe_file_sections(entry, outfile)
fprintf(outfile, " ");
print_file_name(entry, outfile);
if (entry->flags & (E_JUST_SYMS | E_DYNAMIC))
- fprintf(outfile, " symbols only\n", 0);
+ fprintf(outfile, " symbols only\n");
else
fprintf(outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
entry->text_start_address, entry->header.a_text,
@@ -255,7 +192,7 @@ struct line_debug_entry
relation between the two relocation entries. Used by qsort. */
static int
-relocation_entries_relation (rel1, rel2)
+relocation_entries_relation(rel1, rel2)
struct relocation_info *rel1, *rel2;
{
return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
@@ -269,7 +206,7 @@ relocation_entries_relation (rel1, rel2)
state_pointer[1].sym == 0, this routine should not be called. */
static int
-next_debug_entry (use_data_symbols, state_pointer)
+next_debug_entry(use_data_symbols, state_pointer)
register int use_data_symbols;
/* Next must be passed by reference! */
struct line_debug_entry state_pointer[3];
@@ -397,12 +334,12 @@ address_to_line(address, state_pointer)
/* Next must be passed by reference! */
struct line_debug_entry state_pointer[3];
{
- struct line_debug_entry
- *current = state_pointer, *next = state_pointer + 1;
- struct line_debug_entry *tmp_pointer;
-
+ struct line_debug_entry *current, *next, *tmp_pointer;
int use_data_symbols;
+ current = state_pointer;
+ next = state_pointer + 1;
+
if (next->sym)
use_data_symbols =
(next->sym->nzlist.nlist.n_type & N_TYPE) == N_DATA;
@@ -419,6 +356,7 @@ address_to_line(address, state_pointer)
state_pointer[2] = tmp_pointer[2];
free(tmp_pointer);
}
+
/* If we're still in a bad way, return -1, meaning invalid line. */
if (current->sym->nzlist.nlist.n_value > address)
return -1;
@@ -426,6 +364,7 @@ address_to_line(address, state_pointer)
while (next->sym
&& next->sym->nzlist.nlist.n_value <= address
&& next_debug_entry(use_data_symbols, state_pointer));
+
return current->line;
}
@@ -486,7 +425,7 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
for (reloc = reloc_start;
reloc < (reloc_start + reloc_size);
reloc++) {
- register struct localsymbol *s;
+ register struct localsymbol *lsp;
register symbol *g;
/*
@@ -496,7 +435,7 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
if (!RELOC_EXTERN_P(reloc))
continue;
- s = &entry->symbols[RELOC_SYMBOL(reloc)];
+ lsp = &entry->symbols[RELOC_SYMBOL(reloc)];
/*
* Local symbols shouldn't ever be used by relocation info,
@@ -507,17 +446,24 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
* assembler would have caught it otherwise), so we can
* ignore these cases.
*/
- if (!(s->nzlist.nz_type & N_EXT))
+
+ if ((g = lsp->symbol) == NULL)
continue;
- g = s->symbol;
+ if (!(lsp->nzlist.nz_type & N_EXT) &&
+ !SET_ELEMENT_P(lsp->nzlist.nz_type)) {
+ warnx("internal error: `%s' N_EXT not set", g->name);
+ continue;
+ }
+
errmsg = 0;
- if (!g->defined && !g->so_defined && list_unresolved_refs) { /* Reference */
+ if (!g->defined && !g->so_defined && list_unresolved_refs) {
/* Mark as being noted by relocation warning pass. */
- SET_BIT(nlist_bitvector, s - start_of_syms);
+ SET_BIT(nlist_bitvector, lsp - start_of_syms);
- if (g->undef_refs >= MAX_UREFS_PRINTED) /* Listed too many */
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ /* Listed too many */
continue;
/* Undefined symbol which we should mention */
@@ -526,7 +472,8 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
errfmt = "More undefined symbol %s refs follow";
invalidate_line_number = 1;
} else {
- errfmt = "Undefined symbol %s referenced from %s segment";
+ errfmt =
+ "Undefined symbol `%s' referenced from %s segment";
invalidate_line_number = 0;
}
} else { /* Defined */
@@ -535,7 +482,7 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
continue;
/* Mark as being noted by relocation warning pass. */
- SET_BIT(nlist_bitvector, s - start_of_syms);
+ SET_BIT(nlist_bitvector, lsp - start_of_syms);
errfmt = 0;
errmsg = g->warning;
@@ -548,8 +495,9 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
char *nm;
nm = g->name;
- errmsg = (char *) xmalloc(strlen(errfmt) + strlen(nm) + 1);
- sprintf(errmsg, errfmt, nm, data_segment ? "data" : "text");
+ errmsg = (char *)
+ xmalloc(strlen(errfmt) + strlen(nm) + 1);
+ sprintf(errmsg, errfmt, nm, data_segment?"data":"text");
if (nm != g->name)
free(nm);
}
@@ -595,24 +543,25 @@ do_file_warnings (entry, outfile)
if (!entry->strings) {
int desc;
- entry->strings = (char *) alloca (entry->string_size);
- desc = file_open (entry);
- read_entry_strings (desc, entry);
+ entry->strings = (char *)alloca(entry->string_size);
+ desc = file_open(entry);
+ read_entry_strings(desc, entry);
}
if (!(entry->flags & E_DYNAMIC)) {
- /* Do text warnings based on a scan through the relocation info. */
- do_relocation_warnings (entry, 0, outfile, nlist_bitvector);
+ /* Do text warnings based on a scan through the reloc info. */
+ do_relocation_warnings(entry, 0, outfile, nlist_bitvector);
- /* Do data warnings based on a scan through the relocation info. */
- do_relocation_warnings (entry, 1, outfile, nlist_bitvector);
+ /* Do data warnings based on a scan through the reloc info. */
+ do_relocation_warnings(entry, 1, outfile, nlist_bitvector);
}
- /* Scan through all of the nlist entries in this file and pick up
- anything that the scan through the relocation stuff didn't. */
-
- text_scan = init_debug_scan (0, entry);
- data_scan = init_debug_scan (1, entry);
+ /*
+ * Scan through all of the nlist entries in this file and pick up
+ * anything that the scan through the relocation stuff didn't.
+ */
+ text_scan = init_debug_scan(0, entry);
+ data_scan = init_debug_scan(1, entry);
for (i = 0; i < number_of_syms; i++) {
struct nlist *s;
@@ -621,9 +570,23 @@ do_file_warnings (entry, outfile)
g = entry->symbols[i].symbol;
s = &entry->symbols[i].nzlist.nlist;
- if (!(s->n_type & N_EXT))
+ /*
+ * XXX This is a temporary fence to correct an
+ * incorrect assumption made in the case of symbols
+ * which do not have entries in the (global)
+ * symbol table.
+ */
+ if(g == NULL)
continue;
+ if (g == NULL)
+ continue;
+
+ if (!(s->n_type & N_EXT) && !SET_ELEMENT_P(s->n_type)) {
+ warnx("internal error: `%s' N_EXT not set", g->name);
+ continue;
+ }
+
if (!(g->flags & GS_REFERENCED)) {
#if 0
/* Check for undefined shobj symbols */
@@ -650,16 +613,18 @@ do_file_warnings (entry, outfile)
dont_allow_symbol_name = 0;
if (list_multiple_defs && g->mult_defs) {
- errfmt = "Definition of symbol %s (multiply defined)";
+ errfmt = "Definition of symbol `%s' (multiply defined)";
switch (s->n_type) {
case N_TEXT | N_EXT:
- line_number = address_to_line (s->n_value, text_scan);
+ line_number =
+ address_to_line(s->n_value, text_scan);
file_name = text_scan[0].filename;
break;
case N_DATA | N_EXT:
- line_number = address_to_line (s->n_value, data_scan);
+ line_number =
+ address_to_line(s->n_value, data_scan);
file_name = data_scan[0].filename;
break;
@@ -669,7 +634,9 @@ do_file_warnings (entry, outfile)
case N_SETB | N_EXT:
if (g->mult_defs == 2)
continue;
- errfmt = "First set element definition of symbol %s (multiply defined)";
+ errfmt =
+ "First set element definition of symbol %s (multiply defined)";
+ line_number = -1;
break;
default:
@@ -678,9 +645,11 @@ printf("multiply defined: %s, type %#x\n", g->name, s->n_type);
continue;
}
- } else if (BIT_SET_P (nlist_bitvector, i)) {
+ } else if (BIT_SET_P(nlist_bitvector, i)) {
continue;
- } else if (list_unresolved_refs && !g->defined && !g->so_defined) {
+ } else if (list_unresolved_refs &&
+ !g->defined && !g->so_defined) {
+
if (g->undef_refs >= MAX_UREFS_PRINTED)
continue;
@@ -696,8 +665,8 @@ printf("multiply defined: %s, type %#x\n", g->name, s->n_type);
* do a reference. The second is if it's the reference
* used by the warning stabs itself.
*/
- if (s->n_type != (N_EXT | N_UNDF)
- || (i && (s-1)->n_type == N_WARNING))
+ if (s->n_type != (N_EXT | N_UNDF) ||
+ (i && (s-1)->n_type == N_WARNING))
continue;
errfmt = g->warning;
@@ -707,19 +676,19 @@ printf("multiply defined: %s, type %#x\n", g->name, s->n_type);
continue;
if (line_number == -1)
- fprintf (outfile, "%s: ", entry->filename);
+ fprintf(outfile, "%s: ", entry->filename);
else
- fprintf (outfile, "%s:%d: ", file_name, line_number);
+ fprintf(outfile, "%s:%d: ", file_name, line_number);
if (dont_allow_symbol_name)
- fprintf (outfile, "%s", errfmt);
+ fprintf(outfile, "%s", errfmt);
else
- fprintf (outfile, errfmt, g->name);
+ fprintf(outfile, errfmt, g->name);
- fputc ('\n', outfile);
+ fputc('\n', outfile);
}
- free (text_scan);
- free (data_scan);
+ free(text_scan);
+ free(data_scan);
entry->strings = 0; /* Since it will dissapear anyway. */
}
@@ -738,9 +707,9 @@ do_warnings(outfile)
return 1;
if (entry_symbol && !entry_symbol->defined)
- fprintf (outfile, "Undefined entry symbol %s\n",
+ fprintf(outfile, "Undefined entry symbol %s\n",
entry_symbol->name);
- each_file (do_file_warnings, outfile);
+ each_file(do_file_warnings, (void *)outfile);
if (list_unresolved_refs || list_multiple_defs)
return 0;
diff --git a/gnu/usr.bin/man/Makefile.inc b/gnu/usr.bin/man/Makefile.inc
index c0df250c0a23..b993e790e96f 100644
--- a/gnu/usr.bin/man/Makefile.inc
+++ b/gnu/usr.bin/man/Makefile.inc
@@ -19,6 +19,8 @@ refer= /usr/bin/refer
grap= # no grap
pic= /usr/bin/pic
zcat= /usr/bin/zcat
+compress= gzip -c
+compext= .gz
# For scripts.
.if !target(obj)
diff --git a/gnu/usr.bin/man/apropos/Makefile b/gnu/usr.bin/man/apropos/Makefile
index 6208d5e6ba5e..b2f855a0f12e 100644
--- a/gnu/usr.bin/man/apropos/Makefile
+++ b/gnu/usr.bin/man/apropos/Makefile
@@ -1,12 +1,16 @@
+# $Id: Makefile,v 1.7 1994/06/05 21:57:03 csgr Exp $
+
.if exists(${.CURDIR}/obj)
-MANP= ${.CURDIR}/obj/apropos.1
+MAN1= ${.CURDIR}/obj/apropos.1
TARG= ${.CURDIR}/obj/apropos
.else
-MANP= ${.CURDIR}/apropos.1
+MAN1= ${.CURDIR}/apropos.1
TARG= ${.CURDIR}/apropos
.endif
-all: ${TARG} ${MANP}
+MANDEPEND= ${MAN1}
+
+all: ${TARG} ${MAN1}
depend rcsfreeze tags all:
@echo -n
@@ -15,14 +19,14 @@ cleandir: clean
cd ${.CURDIR}; rm -rf obj;
clean:
- @rm -f ${TARG} ${MANP}
+ @rm -f ${TARG} ${MAN1}
${TARG}: ${.CURDIR}/apropos.sh
sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
-e 's,%pager%,${pager},' \
${.CURDIR}/apropos.sh > $@
-${MANP}: ${.CURDIR}/apropos.man
+${MAN1}: ${.CURDIR}/apropos.man
sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
-e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
-e 's,%manpath_config_file%,${manpath_config_file},' \
@@ -31,7 +35,13 @@ ${MANP}: ${.CURDIR}/apropos.man
install: ${TARG} maninstall
install -c -o bin -g bin -m 555 ${TARG} ${DESTDIR}/usr/bin
-maninstall: ${MANP}
- install -c -o bin -g bin -m 444 ${MANP} ${DESTDIR}/usr/share/man/man1
.include "../Makefile.inc"
+
+.if make(maninstall) || make(install)
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.elif !target(maninstall)
+maninstall:
+.endif
+.endif
diff --git a/gnu/usr.bin/man/catman/Makefile b/gnu/usr.bin/man/catman/Makefile
index de870e395a6b..f4bd03f7baec 100644
--- a/gnu/usr.bin/man/catman/Makefile
+++ b/gnu/usr.bin/man/catman/Makefile
@@ -1,8 +1,15 @@
-obj cleandir clean depend rcsfreeze tags all:
- @echo -n
+NOMAN= noman
+CLEANFILES= catman
-install:
- install -c -o bin -g bin -m 555 catman ${DESTDIR}/usr/bin
+beforeinstall: catman
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ catman ${DESTDIR}${BINDIR}
-.include "../Makefile.inc"
.include <bsd.prog.mk>
+
+catman: catman.sh
+ sed -e 's,%compress%,${compress},' \
+ -e 's,%compext%,${compext},' \
+ -e 's,%zcat%,${zcat},' \
+ ${.CURDIR}/catman.sh > catman
+
diff --git a/gnu/usr.bin/man/catman/catman b/gnu/usr.bin/man/catman/catman
deleted file mode 100644
index a2d16a11704c..000000000000
--- a/gnu/usr.bin/man/catman/catman
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-# usage: sh catman
-# put the section numbers here:
-SECTIONS="1 2 3 4 5 6 7 8"
-MANDIR=/usr/share/man
-
-formatman()
-{
- echo " "$1 "->" $*
- (cd cat$section; rm -f $*)
- nroff -man < man$section/$1 > cat$section/$1
- catfile=$1; shift
- while [ $# -gt 0 ]
- do
- ln cat$section/$catfile cat$section/$1
- shift
- done
-}
-
-cd $MANDIR
-for section in $SECTIONS
-do
- echo formatting section $section ...
-
- IFS=" "
- allfiles=`ls -i1 man$section | sort | awk '{if (inode ~ $1) printf "/" $2;
- else printf " " $2; inode = $1 } END {printf "\n"}'`
- for files in $allfiles
- do
- IFS="/"
- tfiles=`echo $files`
- IFS=" "
- formatman $tfiles
- done
-done
-exit 0
diff --git a/gnu/usr.bin/man/catman/catman.sh b/gnu/usr.bin/man/catman/catman.sh
new file mode 100644
index 000000000000..456cb576953d
--- /dev/null
+++ b/gnu/usr.bin/man/catman/catman.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# usage: sh catman
+# put the section numbers here:
+SECTIONS="1 2 3 4 5 6 7 8"
+MANDIR=/usr/share/man
+
+formatman()
+{
+ suffix=`echo $1 | sed -e 's/.*\\.//'`
+ (cd cat$section; rm -f $*)
+ if [ ".$suffix" = "%compext%" ]; then
+ adds=
+ %zcat% man$section/$1 | nroff -man | %compress% > cat$section/$1$adds
+ else
+ adds=%compext%
+ nroff -man < man$section/$1 | %compress% > cat$section/$1$adds
+ fi
+ echo " "$* "->" $1$adds
+ catfile=$1$adds; shift
+ while [ $# -gt 0 ]
+ do
+ ln cat$section/$catfile cat$section/$1$adds
+ shift
+ done
+}
+
+cd $MANDIR
+for section in $SECTIONS
+do
+ echo formatting section $section ...
+
+ IFS=" "
+ allfiles=`ls -i1 man$section | sort | awk '{if (inode ~ $1) printf "/" $2;
+ else printf " " $2; inode = $1 } END {printf "\n"}'`
+ for files in $allfiles
+ do
+ IFS="/"
+ tfiles=`echo $files`
+ IFS=" "
+ formatman $tfiles
+ done
+done
+exit 0
diff --git a/gnu/usr.bin/man/lib/Makefile b/gnu/usr.bin/man/lib/Makefile
index d364b32f4b7a..7134c86aa3a5 100644
--- a/gnu/usr.bin/man/lib/Makefile
+++ b/gnu/usr.bin/man/lib/Makefile
@@ -6,8 +6,9 @@ CONFH= ${.CURDIR}/obj/config.h
CONFH= ${.CURDIR}/config.h
.endif
+NOPROFILE= YES
-CFLAGS+= -I${.CURDIR} -DSTDC_HEADERS -DPOSIX -DHAS_TROFF -DDO_UNCOMPRESS -DALT_SYSTEMS
+CFLAGS+= -I${.CURDIR} -DSTDC_HEADERS -DPOSIX -DHAS_TROFF -DDO_COMPRESS -DALT_SYSTEMS
CLEANFILES+= ${CONFH}
SRCS = util.c gripes.c
@@ -25,6 +26,8 @@ depend ${CONFH}: ${.CURDIR}/config.h_dist ../Makefile.inc
-e 's,%vgrind%,${vgrind},' -e 's,%refer%,${refer},' \
-e 's,%grap%,${grap},' -e 's,%zcat%,${zcat},' \
-e 's,%manpath_config_file%,${manpath_config_file},' \
+ -e 's,%compress%,${compress},' \
+ -e 's,%compext%,${compext},' \
${.CURDIR}/config.h_dist > ${CONFH}
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/man/lib/config.h_dist b/gnu/usr.bin/man/lib/config.h_dist
index 74122df0370b..3438e6f0082a 100644
--- a/gnu/usr.bin/man/lib/config.h_dist
+++ b/gnu/usr.bin/man/lib/config.h_dist
@@ -22,11 +22,6 @@
* Austin, Texas 78712
*/
-#ifdef COMPRESS
-#define DO_COMPRESS
-#define DO_UNCOMPRESS
-#endif
-
/*
* This is the size of a number of internal buffers. It should
* probably not be less than 512.
@@ -132,27 +127,26 @@
/*
* Define the uncompression program(s) to use for those preformatted
* pages that end in the given character. If you add extras here, you
- * may need to change man.c.
+ * may need to change man.c. [I have no idea what FCAT and YCAT files
+ * are! - I will leave them in for now.. -jkh]
*/
-#ifdef DO_UNCOMPRESS
/* .F files */
#define FCAT ""
/* .Y files */
#define YCAT ""
/* .Z files */
#define ZCAT "%zcat%"
-#endif
/*
* This is the standard program to use on this system for compressing
* pages once they have been formatted, and the character to tack on
* to the end of those files. The program listed is expected to read
* from the standard input and write compressed output to the standard
- * output.
+ * output. These won't actually be used unless compression is enabled.
*/
#ifdef DO_COMPRESS
-#define COMPRESSOR ""
-#define COMPRESS_EXT ""
+#define COMPRESSOR "%compress%"
+#define COMPRESS_EXT "%compext%"
#endif
/*
diff --git a/gnu/usr.bin/man/makewhatis/Makefile b/gnu/usr.bin/man/makewhatis/Makefile
index f146c9d4da2d..bd14975c490a 100644
--- a/gnu/usr.bin/man/makewhatis/Makefile
+++ b/gnu/usr.bin/man/makewhatis/Makefile
@@ -5,11 +5,13 @@ CLEANFILES= makewhatis
beforeinstall: makewhatis
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/makewhatis.sh ${DESTDIR}${BINDIR}/makewhatis
+ makewhatis ${DESTDIR}${BINDIR}
.include <bsd.prog.mk>
makewhatis: makewhatis.sh
sed -e 's/%sections%/ "1", "n", "l", "6", "8", "2", "3", "4", "5", "7", "p", "o", NULL/' \
+ -e 's,%zcat%,${zcat},' \
+ -e 's,%compext%,${compext},' \
${.CURDIR}/makewhatis.sh > makewhatis
diff --git a/gnu/usr.bin/man/makewhatis/makewhatis.sh b/gnu/usr.bin/man/makewhatis/makewhatis.sh
index 1d86d1993946..28b871d22da8 100644
--- a/gnu/usr.bin/man/makewhatis/makewhatis.sh
+++ b/gnu/usr.bin/man/makewhatis/makewhatis.sh
@@ -30,9 +30,16 @@ do
then
for f in `find $subdir -type f -print`
do
+ suffix=`echo $f | sed -e 's/.*\\.//'`
+ if [ ".$suffix" = "%compext%" ]; then
+ output=%zcat%
+ else
+ output=cat
+ fi
+ $output $f | \
sed -n '/^\.TH.*$/p
/^\.Dt.*$/p
- /^\.S[hH][ ]*NAME/,/^\.S[hH]/p' $f |\
+ /^\.S[hH][ ]*NAME/,/^\.S[hH]/p'|\
sed -e 's/\\[ ]*\-/-/
s/^.P[Pp].*$//
s/\\(em//
diff --git a/gnu/usr.bin/man/man/Makefile b/gnu/usr.bin/man/man/Makefile
index 52903bfbd634..aaeb0868d8b2 100644
--- a/gnu/usr.bin/man/man/Makefile
+++ b/gnu/usr.bin/man/man/Makefile
@@ -18,13 +18,14 @@ MAN1= ${.CURDIR}/man.1
DPADD+= ${MAN1}
CFLAGS+= -I${.CURDIR}/../lib -DSTDC_HEADERS -DPOSIX -DHAS_TROFF
-CFLAGS+= -DDO_UNCOMPRESS -DALT_SYSTEMS -DSETREUID -DCATMODE=0664
+CFLAGS+= -DDO_COMPRESS -DALT_SYSTEMS -DSETREUID -DCATMODE=0664
CLEANFILES+= ${MAN1}
${MAN1}: ${.CURDIR}/man.man
sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
-e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
-e 's,%manpath_config_file%,${manpath_config_file},' \
+ -e 's,%compress%,${compress},' \
${.CURDIR}/man.man > ${MAN1}
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/man/man.c b/gnu/usr.bin/man/man/man.c
index c5b4ee0af0a4..262e3337f214 100644
--- a/gnu/usr.bin/man/man/man.c
+++ b/gnu/usr.bin/man/man/man.c
@@ -524,11 +524,15 @@ convert_name (name, to_cat)
if (to_cat)
{
int len = strlen (name) + 3;
+ int cextlen = strlen(COMPRESS_EXT);
+
to_name = (char *) malloc (len);
if (to_name == NULL)
gripe_alloc (len, "to_name");
strcpy (to_name, name);
- strcat (to_name, ".Z");
+ /* Avoid tacking it on twice */
+ if (strcmp(name + (len - (3 + cextlen)), COMPRESS_EXT))
+ strcat (to_name, COMPRESS_EXT);
}
else
to_name = strdup (name);
@@ -660,43 +664,30 @@ make_name (path, section, name, cat)
return &names[0];
}
-#ifdef DO_UNCOMPRESS
char *
get_expander (file)
char *file;
{
- char *expander = NULL;
- int len = strlen (file);
+ char *end = file + (strlen (file) - 1);
- if (file[len - 2] == '.')
- {
- switch (file[len - 1])
- {
+ while (end > file && end[-1] != '.')
+ --end;
+ if (end == file)
+ return NULL;
#ifdef FCAT
- case 'F':
- if (strcmp (FCAT, "") != 0)
- expander = strdup (FCAT);
- break;
-#endif
+ if (*end == 'F')
+ return FCAT;
+#endif /* FCAT */
#ifdef YCAT
- case 'Y':
- if (strcmp (YCAT, "") != 0)
- expander = strdup (YCAT);
- break;
-#endif
+ if (*end == 'Y')
+ return YCAT;
+#endif /* YCAT */
#ifdef ZCAT
- case 'Z':
- if (strcmp (ZCAT, "") != 0)
- expander = strdup (ZCAT);
- break;
-#endif
- default:
- break;
- }
- }
- return expander;
+ if (*end == 'Z' || !strcmp(end, "gz"))
+ return ZCAT;
+#endif /* ZCAT */
+ return NULL;
}
-#endif
/*
* Simply display the preformatted page.
@@ -712,16 +703,12 @@ display_cat_file (file)
if (access (file, R_OK) == 0)
{
-#ifdef DO_UNCOMPRESS
char *expander = get_expander (file);
if (expander != NULL)
sprintf (command, "%s %s | %s", expander, file, pager);
else
sprintf (command, "%s %s", pager, file);
-#else
- sprintf (command, "%s %s", pager, file);
-#endif
found = do_system_command (command);
}
@@ -911,7 +898,6 @@ parse_roff_directive (cp, file, buf)
strcat (buf, " | ");
strcat (buf, NROFF);
}
-
if (tbl_found && !troff && strcmp (COL, "") != 0)
{
strcat (buf, " | ");
@@ -992,22 +978,21 @@ make_roff_command (file)
if (debug)
fprintf (stderr, "using default preprocessor sequence\n");
+ if ((cp = get_expander(file)) == NULL)
+ cp = "cat";
+ sprintf(buf, "%s %s | ", cp, file);
#ifdef HAS_TROFF
if (troff)
{
if (strcmp (TBL, "") != 0)
{
- strcpy (buf, TBL);
- strcat (buf, " ");
- strcat (buf, file);
+ strcat (buf, TBL);
strcat (buf, " | ");
strcat (buf, TROFF);
}
else
{
- strcpy (buf, TROFF);
- strcat (buf, " ");
- strcat (buf, file);
+ strcat (buf, TROFF);
}
}
else
@@ -1015,17 +1000,13 @@ make_roff_command (file)
{
if (strcmp (TBL, "") != 0)
{
- strcpy (buf, TBL);
- strcat (buf, " ");
- strcat (buf, file);
+ strcat (buf, TBL);
strcat (buf, " | ");
strcat (buf, NROFF);
}
else
{
strcpy (buf, NROFF);
- strcat (buf, " ");
- strcat (buf, file);
}
if (strcmp (COL, "") != 0)
@@ -1073,7 +1054,7 @@ make_cat_file (path, man_file, cat_file)
#endif
/*
* Don't let the user interrupt the system () call and screw up
- * the formmatted man page if we're not done yet.
+ * the formatted man page if we're not done yet.
*/
fprintf (stderr, "Formatting page, please wait...");
fflush(stderr);
@@ -1383,7 +1364,7 @@ man (name)
if (debug)
fprintf (stderr, "\nsearching in %s\n", *mp);
- glob = 0;
+ glob = 1;
found += try_section (*mp, section, name, glob);
diff --git a/gnu/usr.bin/man/man/man.man b/gnu/usr.bin/man/man/man.man
index 2c034feee0a7..bddfc028b7f7 100644
--- a/gnu/usr.bin/man/man/man.man
+++ b/gnu/usr.bin/man/man/man.man
@@ -27,7 +27,9 @@ like to display the formatted pages. If section is specified, man
only looks in that section of the manual. You may also specify the
order to search the sections for entries and which preprocessors to
run on the source files via command line options or environment
-variables.
+variables. If enabled by the system administrator, formatted man
+pages will also be compressed with the `%compress%' command to save
+space.
.SH OPTIONS
.TP
.B \-\^M " path"
diff --git a/gnu/usr.bin/man/manpath/Makefile b/gnu/usr.bin/man/manpath/Makefile
index c86bf1be8463..6b6bfbbd85ed 100644
--- a/gnu/usr.bin/man/manpath/Makefile
+++ b/gnu/usr.bin/man/manpath/Makefile
@@ -25,6 +25,6 @@ ${MAN1}: ${.CURDIR}/manpath.man
${.CURDIR}/manpath.man > ${MAN1}
afterinstall:
- install -c -o bin -g bin -m 555 ${.CURDIR}/manpath.config ${DESTDIR}${manpath_config_file}
+ install -c -o bin -g bin -m 555 ${.CURDIR}/manpath.config ${DESTDIR}${manpath_config_file}.sample
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/manpath/manpath.config b/gnu/usr.bin/man/manpath/manpath.config
index b9c1171ae37e..677b1adec5e4 100644
--- a/gnu/usr.bin/man/manpath/manpath.config
+++ b/gnu/usr.bin/man/manpath/manpath.config
@@ -17,6 +17,7 @@
MANDATORY_MANPATH /usr/share/man
MANDATORY_MANPATH /usr/local/man
MANDATORY_MANPATH /usr/X386/man
+MANDATORY_MANPATH /usr/X11R6/man
MANDATORY_MANPATH /usr/gnu/man
#
# set up PATH to MANPATH mapping
@@ -27,4 +28,5 @@ MANPATH_MAP /usr/ucb /usr/share/man
MANPATH_MAP /usr/local/mh /usr/local/mh/man
MANPATH_MAP /usr/local/bin /usr/local/man
MANPATH_MAP /usr/gnu /usr/gnu/man
-MANPATH_MAP /usr/X386 /usr/X386/man
+MANPATH_MAP /usr/X386/bin /usr/X386/man
+MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
diff --git a/gnu/usr.bin/man/whatis/Makefile b/gnu/usr.bin/man/whatis/Makefile
index 94347e11eb31..b3cd6a8b34a1 100644
--- a/gnu/usr.bin/man/whatis/Makefile
+++ b/gnu/usr.bin/man/whatis/Makefile
@@ -1,12 +1,14 @@
.if exists(${.CURDIR}/obj)
-MANP= ${.CURDIR}/obj/whatis.1
+MAN1= ${.CURDIR}/obj/whatis.1
TARG= ${.CURDIR}/obj/whatis
.else
-MANP= ${.CURDIR}/whatis.1
+MAN1= ${.CURDIR}/whatis.1
TARG= ${.CURDIR}/whatis
.endif
-all: ${TARG} ${MANP}
+MANDEPEND= ${MAN1}
+
+all: ${TARG} ${MAN1}
depend rcsfreeze tags all:
@echo -n
@@ -15,23 +17,28 @@ cleandir: clean
cd ${.CURDIR}; rm -rf obj;
clean:
- @rm -f ${TARG} ${MANP}
+ @rm -f ${TARG} ${MAN1}
${TARG}: ${.CURDIR}/whatis.sh
sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
-e 's,%pager%,${pager},' \
${.CURDIR}/whatis.sh > ${TARG}
-${MANP}: ${.CURDIR}/whatis.man
+${MAN1}: ${.CURDIR}/whatis.man
sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
-e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
-e 's,%manpath_config_file%,${manpath_config_file},' \
- ${.CURDIR}/whatis.man > ${MANP}
+ ${.CURDIR}/whatis.man > ${MAN1}
install: ${TARG} maninstall
install -c -o bin -g bin -m 555 ${TARG} ${DESTDIR}/usr/bin
-maninstall: ${MANP}
- install -c -o bin -g bin -m 444 ${MANP} ${DESTDIR}/usr/share/man/man1
.include "../Makefile.inc"
+.if make(maninstall) || make(install)
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.else
+maninstall:
+.endif
+.endif
diff --git a/gnu/usr.bin/patch/patch.1 b/gnu/usr.bin/patch/patch.1
index a3353c99f57f..636ea2b4f044 100644
--- a/gnu/usr.bin/patch/patch.1
+++ b/gnu/usr.bin/patch/patch.1
@@ -1,12 +1,8 @@
.\" -*- nroff -*-
.rn '' }`
-'\" $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.1,v 1.3.2.1 1994/05/01 16:04:21 jkh Exp $
+'\" $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.1,v 1.4 1994/02/25 21:45:59 phk Exp $
'\"
'\" $Log: patch.1,v $
-.\" Revision 1.3.2.1 1994/05/01 16:04:21 jkh
-.\" Bring man page changes over from -current (correct various misspellings,
-.\" typos, etc).
-.\"
.\" Revision 1.4 1994/02/25 21:45:59 phk
.\" added the -C/-check again.
.\"
diff --git a/gnu/usr.bin/patch/patch.c b/gnu/usr.bin/patch/patch.c
index c315645ccc62..06fea2c8ad9e 100644
--- a/gnu/usr.bin/patch/patch.c
+++ b/gnu/usr.bin/patch/patch.c
@@ -1,5 +1,5 @@
char rcsid[] =
- "$Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.c,v 1.3 1994/02/17 22:20:34 jkh Exp $";
+ "$Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.c,v 1.4 1994/02/25 21:46:04 phk Exp $";
/* patch - a program to apply diffs to original files
*
@@ -9,6 +9,9 @@ char rcsid[] =
* money off of it, or pretend that you wrote it.
*
* $Log: patch.c,v $
+ * Revision 1.4 1994/02/25 21:46:04 phk
+ * added the -C/-check again.
+ *
* Revision 1.3 1994/02/17 22:20:34 jkh
* Put this back - I was somehow under the erroneous impression that patch was in
* ports, until I saw the the commit messages, that is! :-) All changed backed out.
@@ -134,6 +137,9 @@ static int remove_empty_files = FALSE;
/* TRUE if -R was specified on command line. */
static int reverse_flag_specified = FALSE;
+/* TRUE if -C was specified on command line. */
+static int check_patch = FALSE;
+
/* Apply a set of diffs as appropriate. */
int
@@ -363,7 +369,9 @@ char **argv;
struct stat statbuf;
char *realout = outname;
- if (move_file(TMPOUTNAME, outname) < 0) {
+ if (check_patch) {
+ ;
+ } else if (move_file(TMPOUTNAME, outname) < 0) {
toutkeep = TRUE;
realout = TMPOUTNAME;
chmod(TMPOUTNAME, filemode);
@@ -394,7 +402,9 @@ char **argv;
say4("%d out of %d hunks failed--saving rejects to %s\n",
failed, hunk, rejname);
}
- if (move_file(TMPREJNAME, rejname) < 0)
+ if (check_patch) {
+ ;
+ } else if (move_file(TMPREJNAME, rejname) < 0)
trejkeep = TRUE;
}
set_signals(1);
@@ -442,11 +452,12 @@ reinitialize_almost_everything()
fatal1("you may not change to a different patch file\n");
}
-static char *shortopts = "-b:B:cd:D:eEfF:lnNo:p::r:RsStuvV:x:";
+static char *shortopts = "-b:B:cCd:D:eEfF:lnNo:p::r:RsStuvV:x:";
static struct option longopts[] =
{
{"suffix", 1, NULL, 'b'},
{"prefix", 1, NULL, 'B'},
+ {"check", 0, NULL, 'C'},
{"context", 0, NULL, 'c'},
{"directory", 1, NULL, 'd'},
{"ifdef", 1, NULL, 'D'},
@@ -503,6 +514,9 @@ get_some_switches()
case 'c':
diff_type = CONTEXT_DIFF;
break;
+ case 'C':
+ check_patch = TRUE;
+ break;
case 'd':
if (chdir(optarg) < 0)
pfatal2("can't cd to %s", optarg);
@@ -583,9 +597,9 @@ Usage: %s [options] [origfile [patchfile]] [+ [options] [origfile]]...\n",
Argv[0]);
fprintf(stderr, "\
Options:\n\
- [-ceEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
+ [-cCeEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
[-D symbol] [-F max-fuzz] [-o out-file] [-p[strip-count]]\n\
- [-r rej-name] [-V {numbered,existing,simple}] [--context]\n\
+ [-r rej-name] [-V {numbered,existing,simple}] [--check] [--context]\n\
[--prefix=backup-prefix] [--suffix=backup-ext] [--ifdef=symbol]\n\
[--directory=directory] [--ed] [--fuzz=max-fuzz] [--force] [--batch]\n\
[--ignore-whitespace] [--forward] [--reverse] [--output=out-file]\n");
diff --git a/gnu/usr.bin/patch/pch.c b/gnu/usr.bin/patch/pch.c
index cb058f7266cf..2e6dc859a524 100644
--- a/gnu/usr.bin/patch/pch.c
+++ b/gnu/usr.bin/patch/pch.c
@@ -1,6 +1,9 @@
-/* $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/pch.c,v 1.3 1994/02/17 22:20:36 jkh Exp $
+/* $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/pch.c,v 1.4 1994/02/25 21:46:07 phk Exp $
*
* $Log: pch.c,v $
+ * Revision 1.4 1994/02/25 21:46:07 phk
+ * added the -C/-check again.
+ *
* Revision 1.3 1994/02/17 22:20:36 jkh
* Put this back - I was somehow under the erroneous impression that patch was in
* ports, until I saw the the commit messages, that is! :-) All changed backed out.
@@ -188,6 +191,7 @@ there_is_another_patch()
if (force || batch) {
say1("No file to patch. Skipping...\n");
filearg[0] = savestr(bestguess);
+ skip_rest_of_patch = TRUE;
return TRUE;
}
ask1("File to patch: ");
diff --git a/contrib/xntpd/compilers/.keep_me b/gnu/usr.bin/ptx/.stamp-h.in
index e69de29bb2d1..e69de29bb2d1 100644
--- a/contrib/xntpd/compilers/.keep_me
+++ b/gnu/usr.bin/ptx/.stamp-h.in
diff --git a/gnu/usr.bin/ptx/COPYING b/gnu/usr.bin/ptx/COPYING
new file mode 100644
index 000000000000..a43ea2126fb6
--- /dev/null
+++ b/gnu/usr.bin/ptx/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU 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. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, 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 software, or if you modify it.
+
+ For example, if you distribute copies of 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 show them these terms so they know 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.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ 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 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 derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 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 License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary 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
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing 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 for copying, distributing or modifying
+the Program or works based on it.
+
+ 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.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. 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 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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. 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 the public, 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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) 19yy 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 is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/ptx/ChangeLog b/gnu/usr.bin/ptx/ChangeLog
new file mode 100644
index 000000000000..fffb47f15e79
--- /dev/null
+++ b/gnu/usr.bin/ptx/ChangeLog
@@ -0,0 +1,546 @@
+Fri Nov 5 23:10:07 1993 Francois Pinard (pinard@icule)
+
+ * Version 0.3
+
+ * check-out: New name for check_out.
+ * Makefile.in: Change check_out for check-out everywhere.
+ Reported by Jim Meyering <meyering@comco.com>.
+
+ * Makefile.in (realclean): Do not remove .stamp-h.in and
+ config.h.in. One should not need Autoconf installed.
+ Reported by Nelson Beebe <beebe@math.utah.edu>.
+
+ * ptx.c: Add missing definition of isxdigit.
+ Reported by Nelson Beebe <beebe@math.utah.edu>.
+
+ * ptx.c: Define S_ISREG if not defined, then use it.
+ Reported by Karl Berry <karl@cs.umb.edu>.
+
+Wed Nov 3 15:53:00 1993 Francois Pinard (pinard@icule)
+
+ * mkinstalldirs: New, from elsewhere.
+ * Makefile.in: Use it.
+
+Mon Nov 1 00:48:34 1993 Francois Pinard (pinard@lagrande.IRO.UMontreal.CA)
+
+ * Makefile.in (clean): Delete ptx, not the obsolete $(PROGS).
+
+Sun Oct 31 15:04:57 1993 Francois Pinard (pinard@raptor.IRO.UMontreal.CA)
+
+ * ptx.c (alloc_and_compile_regex): Zero out the whole allocated
+ pattern, not just a few fields.
+
+ * ptx.c (alloc_and_compile_regex): Clarify error message.
+
+Thu Oct 28 08:29:29 1993 Francois Pinard (pinard@compy.IRO.UMontreal.CA)
+
+ * ptx.c (print_copyright): Deleted. Rather use a "copyright"
+ variable, print to standard output instead of standard error.
+
+ * ptx.c: Use error instead of fprintf (stderr, ...).
+
+ * ptx.c: Rename fold_lower_to_upper to ignore_case.
+
+Wed Oct 27 18:41:52 1993 Francois Pinard (pinard@lagrande.IRO.UMontreal.CA)
+
+ * ptx.c: Add option -M for using another macro name than "xx".
+ Reported by Thorsten Ohl <ohl@physics.harvard.edu>.
+
+ * examples/ignore/: New files.
+ * eign: Linked to examples/ignore/eign.
+ * Makefile.in: Install and uninstall $(datadir)/eign.
+ * configure.in: Remove testing of a default ignore file.
+ Reported by Nelson Beebe <beebe@math.utah.edu>.
+
+ * ptx.c (main): Add --help and --version processing.
+ (print_version): Deleted.
+
+ * ptx.c: Use -traditional instead of --no-gnu-extensions,
+ --ignore-case instead of --fold-letter-case, --format=<format>
+ instead of --tex-output and --roff-output.
+ * argmatch.c: New file. Taken from fileutils/lib.
+ Reported by Karl Berry <karl@cs.umb.edu>.
+
+Tue Oct 26 08:39:14 1993 Francois Pinard (pinard@icule)
+
+ * ptx.c (usage): New name for usage_and_exit. Accept an exit
+ status parameter. If zero, print full help on stdout. If
+ non-zero, print a one-line helper on stderr.
+
+ * ptx.c: Remove sizeof_occurs and OCCURS_ALIGNMENT complexity.
+ The memory savings did not justify the portability headaches.
+
+ * ptx.c (copy_unescaped_string): New function.
+ (main): Use it with options -F, -S and -W.
+ Reported by Dave Cottingham <dc@haiti.gsfc.nasa.gov>.
+
+ * ptx.c (fix_output_parameters): Force edit of '\f', because some
+ systems does not consider it to be whitespace.
+ Reported by Stephane Berube <berube@iro.umontreal.ca>.
+
+ * ptx.c (fix_output_parameters): For roff output, do not disallow
+ characters with 8th bit set.
+ Reported by James Clark <jjc@jclark.com>.
+
+ * Makefile.in (dist): Include examples/ in distribution.
+
+Mon Oct 25 15:46:16 1993 Francois Pinard (pinard@icule)
+
+ * ptx.c: Change --display-width to --width, for consistency with
+ other GNU programs.
+
+ * examples/ajay/: New files.
+ Reported by Ajay Shah <ajayshah@cmie.ernet.in>.
+ Reported by Rakesh Chauhan <rk@cmie.ernet.in>.
+
+ * examples/luke/: New files.
+ Reported by Luke Kendall <luke@research.canon.oz.au>.
+
+ * examples/latex/: New files.
+
+ * ptx.c (find_occurs_in_text): Assign 0 to refererence_length so
+ GNU C will not warn anymore against its unitialized use.
+ Reported by Loic Dachary <L.Dachary@cs.ucl.ac.uk>.
+
+ * lib/: Move routines in main directory first, then destroy.
+ * Makefile.in: Merge lib/Makefile.in, clean up.
+ * configure.in: Do not create lib/Makefile.in.
+
+ * acconfig.h: New file.
+ * .stamp-h.in: Used for timestamping autoheader.
+ * Makefile.in: Use acconfig.h and .stamp-h.in. Force
+ autoheader whenever acconfig.h is modified.
+
+Wed Jun 9 15:01:28 1993 Francois Pinard (pinard@icule)
+
+ * Makefile.in (dist): Replace "echo `pwd`" by a mere "pwd".
+ Create a gzip file.
+
+Sat May 22 20:18:31 1993 Francois Pinard (pinard@icule)
+
+ * Makefile.in: Replace $(PROGS) by ptx.
+
+ * diacrit.h: Change `c' to `chr', better protect it.
+
+ * lib/COPYING.LIB: Deleted.
+ * lib/Makefile.in: Adjust accordingly.
+
+Sat Feb 6 15:03:13 1993 Francois Pinard (pinard@icule)
+
+ * Makefile.in, lib/Makefile.in: In dist goals, ensure 777 mode for
+ directories, so older tar's will restore file modes properly.
+
+Sun Jan 17 15:42:35 1993 Francois Pinard (pinard@icule)
+
+ * Makefile.in, lib/Makefile.in: Put $(CFLAGS) after $(CPPFLAGS),
+ so the installer can override automatically configured choices.
+ Reported by Karl Berry <karl@cs.umb.edu>.
+
+Tue Jan 12 09:21:22 1993 Francois Pinard (pinard at icule)
+
+ * configure.in: Check for setchrclass().
+ * diacrit.[hc]: New file, extracted from my own ctype.[hc].
+ * ctype.[hc]: Deleted.
+ * Makefile.in: Distribute diacrit.[hc], but not ctype.[hc].
+ * ptx.c: Include "diacrit.h" rather than "ctype.h".
+ Include <ctype.h> for ANSI C, or else, use our own definitions.
+ (initialize_regex): Use ctype.h macros for making the folding
+ table and for making the \w+ fastmap. Previously, was reusing the
+ regex syntax table or looking at character bit structure.
+ (main): Execute setchrclass (NULL) if available and ANSI C.
+
+ * Spelling fixes in various files.
+ Reported by Jim Meyering <meyering@cs.utexas.edu>.
+
+Thu Jan 7 20:19:25 1993 Francois Pinard (pinard at icule)
+
+ * Makefile.in: Using autoheader, derive config.h.in from
+ configure.in. Distribute config.h.in.
+ Use config.status for reconstructing config.h from config.h.in.
+ Have all $(OBJECTS) depend upon config.h.
+ Always use -I. calling the C compiler, for config.h to be found.
+ Remove config.h in distclean-local.
+ * lib/Makefile.in: Always use -I.. calling the C compiler, for
+ config.h to be found. Also use $(DEFS).
+ Have all $(OBJECTS) depend upon ../config.h.
+ * configure.in: Create config.h from config.h.in.
+ * ptx.c, ctype.c: Conditionnaly include config.h.
+
+Fri Jan 1 19:52:49 1993 Francois Pinard (pinard at icule)
+
+ * Makefile.in, lib/Makefile.in: Reinstate $(CPPFLAGS), use it.
+ Richard wants it there. Remove $(ALLFLAGS) and reequilibrate.
+
+Sun Dec 27 05:57:55 1992 Francois Pinard (pinard at icule)
+
+ * ptx.c (find_occurs_in_text): Introduce word_start and word_end
+ variables, and use them instead of the word_regs structure. This
+ takes care of the fact newer regex.h does not allocate the arrays
+ any more, and these were used even when regexps were not compiled.
+
+ * Makefile, lib/Makefile.in: Define CHAR_SET_SIZE for SYNTAX_TABLE
+ to work correctly.
+
+ * configure.in: Replace AC_USG by AC_HAVE_HEADERS(string.h).
+ Cleanup and reorganize a little.
+
+ * ptx.c: Renamed from gptx.c. Add -G (--no-gnu-extensions)
+ and clarify some long option names by making them more
+ explicit. Remove all PTX_COMPATIBILITY conditionals.
+ Introduce gnu_extensions variable initialized to 1. Let -G
+ give it the value 0, but still allow and process GNU specific
+ options and long option names. The Ignore file is now the same
+ whatever the value of gnu_extensions.
+ * ptx.texinfo: Renamed from gptx.texinfo, adjusted.
+ * Makefile.in, configure.in: Adjusted accordingly. Now
+ installs only one program under the name $(binprefix)ptx.
+
+ * gptx.c (perror_and_exit): Deleted. Use error() directly.
+
+ * gptx.c: Remove unneeded prototypes for system library routines.
+
+ * gptx.c (compare_words, compare_occurs): #define first and second
+ instead of using an intermediate variable.
+
+ * configure.in: Use AC_CONST.
+ * gptx.h: Do not define const.
+ * Define volatile dependent on __GNUC__, not __STDC__, and define
+ it to __volatile__.
+
+ * gptx.h, version.c: Deleted, integrated into gptx.c.
+ * Remove src/ and doc/ subdirectories, merging them in main.
+ * Move lib/bumpalloc.h, lib/ctype.[ch] in main directory.
+ * Integrate all ChangeLogs in main ChangeLog.
+ * Integrate all Makefiles in main Makefile and lib/Makefile,
+ rewriting them all along the way.
+
+Fri Nov 13 00:10:31 1992 Francois Pinard (pinard at icule)
+
+ * Makefile.in (dist): chmod a+r before making the tar file.
+
+Tue Oct 6 12:47:00 1992 Francois Pinard (pinard at icule)
+
+ * {,doc/,lib/,src/}Makefile.in: Use exec_prefix. Add `uninstall'.
+
+Wed Aug 19 16:02:09 1992 Francois Pinard (pinard at icule)
+
+ * ansi2knr.c: New file, from Ghostscript distribution.
+ * gptx.c: Get rid of many __STDC__ tests.
+ * version.c: Idem.
+
+Fri Aug 14 22:53:05 1992 Francois Pinard (pinard at icule)
+
+ * gptx.c: Use HAVE_MCHECK instead of MCHECK_MISSING.
+ * configure.in: Use AC_HAVE_FUNCS instead of AC_MISSING_FUNCS.
+
+ * configure.in: Autoconfigure for mcheck and strerror.
+ Reported by Bernd Nordhausen <bernd@iss.nus.sg>.
+
+Thu Jun 18 09:15:12 1992 Francois Pinard (pinard at icule)
+
+ * configure.in, all Makefile's: Adapt to Autoconf 0.118.
+
+Sun Feb 2 16:23:47 1992 Francois Pinard (pinard at icule)
+
+ * gptx.c (main): Returns int.
+
+Tue Dec 10 09:53:21 1991 Francois Pinard (pinard at icule)
+
+ * gptx.c (usage_and_exit): Print --OPTION instead of +OPTION.
+
+Wed Dec 4 10:31:06 1991 Francois Pinard (pinard at icule)
+
+ * gptx.c (compare_occurs, compare_words): Change parameters to
+ (void *) to comply with qsort ANSI declaration, and cast the true
+ type inside the function, each time a parameter is used.
+ Reported by Byron Rakitzis <byron@archone.tamu.edu>.
+
+Mon Dec 2 10:41:43 1991 Francois Pinard (pinard at icule)
+
+ * gptx.c: Removed comma at end of enum.
+
+ * version.c: Add a few missing `const's.
+
+ * gptx.c: Add prototypes for close, fstat, open, perror and read
+ if __STDC__.
+
+ * gptx.c: Remove useless alloca declaration.
+
+Sat Nov 9 20:03:37 1991 Francois Pinard (pinard at icule)
+
+ * configure.in, all/Makefile.in: Directory reorganization,
+ including separate src and doc, in plus of lib. Ensure all
+ Makefile's can be used independently.
+
+Thu Nov 7 11:20:38 1991 Francois Pinard (pinard at icule)
+
+ * gptx.texinfo: Renamed from gptx.texi. Now `TeX'able.
+ * Makefile.in: Ensure distributing texinfo.tex.
+ Reported by Karl Berry <karl@cs.umb.edu>.
+
+ * configure.in: Take care of POSIXish ISC.
+ Reported by Karl Berry <karl@cs.umb.edu>.
+
+Tue Nov 5 09:42:58 1991 Francois Pinard (pinard at icule)
+
+ * configure.in, Makefile.in: Do not absolutize $(srcdir), because
+ this could create problems with automounters.
+
+ * configure.in, Makefile.in: Remove IF_* devices, they were
+ solving a problem caused only by non timestamping shars, and
+ gptx is now distributed in tar format.
+
+Mon Oct 28 14:39:36 1991 Francois Pinard (pinard at icule)
+
+ * configure.in: New file.
+ * configure: Automatically generated from file configure.in
+ and David MacKenzie's autoconf.
+
+Sat Oct 19 20:06:28 1991 Francois Pinard (pinard at icule)
+
+ * configure: Use ANSI header files if present, even with non ANSI
+ compilers.
+ Reported by David MacKenzie <djm@eng.umd.edu>.
+
+Tue Oct 15 08:43:13 1991 Francois Pinard (pinard at icule)
+
+ * Makefile.in: Install gptx and ptx separately. On DEC Ultrix
+ 4.1, install cannot install more than one file at a time.
+ Reported by Simon Leinen <simon@liasun1.epfl.ch>.
+
+Fri Oct 11 15:19:42 1991 Francois Pinard (pinard at icule)
+
+ * Makefile.in: `realclean' did not work, because lib/Makefile was
+ disappearing at `distclean' time. I tried separate doc and src
+ directories, but this is not worth the heaviness. Split some
+ goals instead, using _doc, _lib and _src suffixes.
+
+Fri Oct 10 18:04:21 1991 Francois Pinard (pinard at icule)
+
+ * Version 0.2
+
+Wed Oct 9 16:13:42 1991 Francois Pinard (pinard at icule)
+
+ * configure, Makefile.in: New files.
+ * Makefile, GNUmakefile, Depends: Deleted.
+
+ * gptx.c: Change -A output from `FILE(NN):' to `FILE:NN:'.
+
+ * gptx.c, gptx.h, version.c: Reinstate __STDC__ tests.
+
+Tue Jun 25 11:35:32 1991 Francois Pinard (pinard at icule)
+
+ * gptx.c: Something is wrong in -r reference allocation, I suspect
+ casting does not do what I expect. I relax the constraints so to
+ make it work for now. To be revisited.
+
+ * gptx.c: Call initialize_regex sooner, to ensure folded_chars is
+ properly initialized when -f and -i are simultaneously used.
+
+ * gptx.c: Remove -p option and rather compile two separate
+ programs, one by defining PTX_COMPATIBILITY, to conform a GNU
+ standard asking to not depend on the program installed name. This
+ also removes the -p option, so loosing the debatable advantage of
+ dynamically reverting to ptx compatibility mode.
+
+ * gptx.h: Cleanup. Don't duplicate stdlib.h.
+
+Wed Dec 5 18:00:23 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (usage_and_exit): Change -C explanation.
+
+Sun Oct 28 16:11:36 1990 Francois Pinard (pinard at icule)
+
+ * gptx.h: Remove the PROTO macros and usage.
+ * gptx.c: Remove all the #ifdef __STDC__ noise.
+ * version.c: Remove all the #ifdef __STDC__ noise.
+
+Wed Jul 25 12:20:45 1990 Francois Pinard (pinard at icule)
+
+ * ctype.[ch]: Linked from my library.
+
+Wed Jul 11 10:53:13 1990 Francois Pinard (pinard at icule)
+
+ * bumpalloc.h: Linked from my library.
+
+Sun Aug 5 13:17:25 1990 Francois Pinard (pinard at icule)
+
+ * Version 0.1
+
+ * gptx.c: Implement IGNORE and PIGNORE defines.
+
+ * gptx.c: Implement special character protection for roff and TeX
+ output, through the edited_flag array.
+
+Fri Aug 3 12:47:35 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Implement new -R option for automatic referencing, with
+ the possibility of multiple input files in normal mode. Now,
+ option -r implies ptx compatibility mode default for -S; exclude
+ reference from context whenever easy to do, and allow coselection
+ of both -r and -R.
+
+Wed Aug 1 12:00:07 1990 Francois Pinard (pinard at icule)
+
+ * gptx.[hc]: Define and use OCCURS_ALIGNMENT, to avoid those
+ `Bus error's on Sparcs.
+
+Fri Jul 27 12:04:40 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (initialize_regex): Use only isalpha and "ctype.h" to
+ initialize Sword syntax, getting rid of any other explicit ISO
+ 8859-1 references. This will make the MS-DOS port easier,
+ character set wise.
+
+ * gptx.c (swallow_file_in_memory): Revised along the lines of
+ io.c from GNU diff 1.14, so it could handle stin and fifos,
+ and work faster.
+
+ * gptx.c (perror_and_exit): New function, use it where convenient.
+
+Thu Jul 26 13:28:13 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (swallow_input_text): Remove white space compression even
+ if not in ptx compatibility mode. This being out of the way, use
+ swallow_file_in_memory instead of inputting characters one by one.
+
+Wed Jul 25 12:20:45 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (find_occurs_in_text): Include the sentence separator as
+ part of the right context, except for separator's suffix white
+ space. Formerly, it was excluded from all contexts.
+
+ * gptx.h: Check STDLIB_PROTO_ALREADY to conditionalize prototype
+ declarations for standard C library routines; check __GNUC__
+ before using `volatile' on function prototypes.
+
+ * gptx.c: (find_occurs_in_text): Maintain the maximum length of
+ all words read.
+ (define_all_fields): Optimize scanning longish left contexts by
+ sometimes doing a backward jump from the keyword instead of always
+ scanning forward from the left context boundary.
+
+Sun Jul 22 09:18:21 1990 Francois Pinard (pinard at icule)
+
+ * gptx (alloc_and_compile_regex): Realloc out all extra allocated
+ space.
+
+Mon Jul 16 09:07:25 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: In OCCURS structure, modify left, right and reference
+ pointers and make them displacements, to save some space. Define
+ DELTA typedef, use it, make all other necessary changes.
+
+ * gptx.c: Work on portability. Define const and volatile to
+ nothing if not __STDC__. On BSD, define str[r]chr to be [r]index.
+ Avoid writings specific to GNU C.
+
+Sun Jul 15 17:28:39 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Add a word_fastmap array and use it if -W has not been
+ specified, instead of using default regexps. Finish implementing
+ the Break files.
+
+Sat Jul 14 10:54:21 1990 Francois Pinard (pinard at icule)
+
+ * gptx.[ch], version.c: Use prototypes in all header
+ functions. Add some missing const declarations.
+
+Fri Jul 13 10:16:34 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Enforce ptx compatibility mode by disallowing normal
+ mode extensions. Disallow -p if extensions are used.
+
+ * gptx.c: Finish implementation of Ignore and Only files.
+
+Wed Jul 11 10:53:13 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Revise WORD typedef and use it in OCCURS typedef;
+ adjust all usages. Add BLOCK and WORD_ARRAY typedefs, revise in
+ various place to make better usage of these. Use BUMP_ALLOC.
+
+Tue Jul 10 09:02:26 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Add -L option, `latin1_charset' variable and support.
+
+ * gptx.c: Remove old generate_roff and generate_tex variables,
+ replace with output_format which is of enum type.
+
+Mon Jul 9 10:40:41 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (compare_words): Check word_regex.translate and do not
+ use the translation table if not computed. Also protect against
+ possible 8-bit problems.
+
+ * gptx.c (alloc_and_compile_regex): New function.
+
+Sun Jul 8 17:52:14 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Make a more systematic use of SKIP_* macros, to get rid
+ of explicit ' ' references when possible.
+
+ * gptx.c: Replace `head' field by `left' in the OCCURS structure,
+ delay the `before' computation from find_occurs_in_text to
+ define_all_fields, and make all necessary adjustments. Also
+ add a `right' field in the OCCURS structure, use it to get rid of
+ explicit '\n' references when possible.
+
+ * gptx.c (initialize_regex): New function. Compute the syntax
+ table for regex. Get rid of previous break_chars_init variable
+ and break_chars array, use word_regex and word_regex_string
+ instead.
+
+ * gptx.c: Use re_search to find words and re_match to skip over
+ them. Add -W option and support. Use re_search to find end of
+ lines or end of sentences, add -S option and support.
+
+Sat Jul 7 08:50:40 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Change PRINT_SPACES and PRINT_FIELD macros to
+ print_spaces and print_field routines, respectively.
+
+Fri Jul 6 09:44:39 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c (generate_output): Split into define_all_fields,
+ generate_all_output, output_one_roff_line, output_one_tex_line,
+ and output_one_tty_line.
+
+ * gptx.c: Move the inline code to reallocate the text buffer into
+ reallocate_text_buffer. Correct a small bug in this area.
+
+ * gptx.c: Modify -F to accept a STRING argument, modify output
+ routines to handle truncation marks having more than one
+ character.
+
+Thu Jul 5 11:08:59 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Add -F option and logic.
+
+ * gptx.c: Select ptx compatibility mode if program is
+ installed under the name `ptx'. Install both gptx and ptx.
+
+Thu Jun 7 17:21:25 1990 Francois Pinard (pinard at icule)
+
+ * gptx.c: Make each OCCURS a variable size thing, depending on
+ various options; mark occurs_found table size with an integer
+ counter instead of an end pointer.
+
+Sat Apr 14 20:01:09 1990 Francois Pinard (pinard at icule)
+
+ * Version 0.0
+
+ * gptx.c: Removed limitations on table sizes: it should now go
+ until an `Out of memory' error. Use xmalloc. Rename some
+ variables.
+
+ * version.c, gptx.c (usage_and_exit): Add -C option to print
+ Copyright.
+
+Mon Mar 12 17:59:42 1990 Francois Pinard (pinard at icule)
+
+ * ChangeLog initialisation. Previous experiments towards gptx
+ were done at the defunct site ora.odyssee.qc.ca, which was a
+ Sun-3/160 running SunOS 3.0. The files have been stocked for
+ a long time to kovic.iro archives, then imported to icule.
+
+ * gptx.c: GCC linted.
diff --git a/gnu/usr.bin/ptx/Makefile b/gnu/usr.bin/ptx/Makefile
new file mode 100644
index 000000000000..340c09afb7fd
--- /dev/null
+++ b/gnu/usr.bin/ptx/Makefile
@@ -0,0 +1,10 @@
+PROG= ptx
+SRCS= argmatch.c diacrit.c error.c getopt.c getopt1.c ptx.c xmalloc.c
+
+LDADD+= -lgnuregex
+DPADD+= ${GNUREGEX}
+CFLAGS+= -DHAVE_CONFIG_H -DDEFAULT_IGNORE_FILE=\"/usr/share/dict/eign\"
+
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ptx/NEWS b/gnu/usr.bin/ptx/NEWS
new file mode 100644
index 000000000000..6f97bf92852e
--- /dev/null
+++ b/gnu/usr.bin/ptx/NEWS
@@ -0,0 +1,53 @@
+GNU permuted indexer NEWS - User visible changes.
+Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
+Francois Pinard <pinard@iro.umontreal.ca>, 1992.
+
+Version 0.3 - 1993-10-??, by Franc,ois Pinard
+
+* GNU ptx installs as a single program, -G option dynamically reverts
+to the System V compatible behaviour, yet being liberal with options.
+
+* It should install more easily on more systems, source code is
+unprotoized on the fly for older C compilers.
+
+* A default ignore file is installed along with GNU ptx, ptx uses it.
+
+* Options -F, -S and -W interpret most \-escapes themselves.
+
+* Option -M can be use to change "xx" to another macro name.
+
+* CHRCLASS environment variable is obeyed for systems supporting it.
+
+* Long option names have been cleaned up a little.
+
+* Some examples are given in the example/ directory structure.
+
+
+Version 0.2 - 1991-10-10, by Franc,ois Pinard
+
+* Reference format (with -A) has been modified slightly to better
+comply with GNU standards for line reporting.
+
+* Option -p removed, rather compile two separate programs, one with
+GNU extensions, the other being strict on System V compatibility.
+
+
+Version 0.1 - 1990-08-05, by Franc,ois Pinard
+
+* Add many options: -L for Latin1, -R for automatic referencing, -W
+for regular expressions describing words, -S for regular expressions
+describing end of lines or sentences. Let -F specify the truncation
+strings.
+
+* Implementing Ignore files and Only files.
+
+* Option -p dynamically enforces strict System V compatibility.
+
+* Correct a few bugs and portability problems, have faster input,
+faster processing, and use less memory.
+
+
+Version 0.0 - 1990-04-14, by Franc,ois Pinard
+
+* Initial release.
+
diff --git a/gnu/usr.bin/ptx/README b/gnu/usr.bin/ptx/README
new file mode 100644
index 000000000000..240b7ee8891a
--- /dev/null
+++ b/gnu/usr.bin/ptx/README
@@ -0,0 +1,23 @@
+This is an beta release of GNU ptx, a permuted index generator. GNU
+ptx can handle multiple input files at once, produce TeX compatible
+output, or a readable KWIC (keywords in their context) without the
+need of nroff. This version does not handle huge input files, that
+is, those which do not fit in memory all at once.
+
+The command syntax is not the same as UNIX ptx: all given files are
+input files, the results are produced on standard output by default.
+GNU ptx manual is provided in Texinfo format. Calling `ptx --help'
+prints an option summary. Please note that an overall renaming of all
+options is foreseeable: GNU ptx specifications are not frozen yet.
+
+See the file COPYING for copying conditions.
+
+See the file THANKS for a list of contributors.
+
+See the file NEWS for a list of major changes in the current release.
+
+See the file INSTALL for compilation and installation instructions.
+
+Mail suggestions and bug reports (including documentation errors) for
+these programs to bug-gnu-utils@prep.ai.mit.edu.
+
diff --git a/gnu/usr.bin/ptx/THANKS b/gnu/usr.bin/ptx/THANKS
new file mode 100644
index 000000000000..e6a45cf9c77c
--- /dev/null
+++ b/gnu/usr.bin/ptx/THANKS
@@ -0,0 +1,23 @@
+GNU permuted indexer has originally been written by François Pinard.
+Other people contributed to the GNU permuted index by reporting
+problems, suggesting various improvements or submitting actual code.
+Here is a list of these people. Help me keep it complete and exempt
+of errors.
+
+Ajay Shah ajayshah@cmie.ernet.in
+Bernd Nordhausen bernd@iss.nus.sg
+Byron Rakitzis byron@archone.tamu.edu
+Dave Cottingham dc@haiti.gsfc.nasa.gov
+David J. MacKenzie djm@eng.umd.edu
+Francois Pinard pinard@iro.umontreal.ca
+Janne Himanka shem@syy.oulu.fi
+James Clark jjc@jclark.com
+Jim Meyering meyering@comco.com
+Karl Berry karl@cs.umb.edu
+Loic Dachary L.Dachary@cs.ucl.ac.uk
+Luke Kendall luke@research.canon.oz.au
+Nelson Beebe beebe@math.utah.edu
+Rakesh Chauhan rk@cmie.ernet.in
+Simon Leinen simon@liasun1.epfl.ch
+Stephane Berube berube@iro.umontreal.ca
+Thorsten Ohl ohl@physics.harvard.edu
diff --git a/gnu/usr.bin/ptx/TODO b/gnu/usr.bin/ptx/TODO
new file mode 100644
index 000000000000..6714313c5751
--- /dev/null
+++ b/gnu/usr.bin/ptx/TODO
@@ -0,0 +1,94 @@
+TODO file for GNU ptx - last revised 05 November 1993.
+Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+Francois Pinard <pinard@iro.umontreal.ca>, 1992.
+
+The following are more or less in decreasing order of priority.
+
+* Use rx instead of regex.
+
+* Correct the infinite loop using -S '$' or -S '^'.
+
+* Use mmap for swallowing files (maybe wrong when memory edited).
+
+* Understand and mimic `-t' option, if I can.
+
+* Sort keywords intelligently for Latin-1 code. See how to interface
+this character set with various output formats. Also, introduce
+options to inverse-sort and possibly to reverse-sort.
+
+* Improve speed for Ignore and Only tables. Consider hashing instead
+of sorting. Consider playing with obstacks to digest them.
+
+* Provide better handling of format effectors obtained from input, and
+also attempt white space compression on output which would still
+maximize full output width usage.
+
+* See how TeX mode could be made more useful, and if a texinfo mode
+would mean something to someone.
+
+* Provide multiple language support
+
+Most of the boosting work should go along the line of fast recognition
+of multiple and complex boundaries, which define various `languages'.
+Each such language has its own rules for words, sentences, paragraphs,
+and reporting requests. This is less difficult than I first thought:
+
+ . Recognize language modifiers with each option. At least -b, -i, -o,
+-W, -S, and also new language switcher options, will have such
+modifiers. Modifiers on language switchers will allow or disallow
+language transitions.
+
+ . Complete the transformation of underlying variables into arrays in
+the code.
+
+ . Implement a heap of positions in the input file. There is one entry
+in the heap for each compiled regexp; it is initialized by a re_search
+after each regexp compile. Regexps reschedule themselves in the heap
+when their position passes while scanning input. In this way, looking
+simultaneously for a lot of regexps should not be too inefficient,
+once the scanning starts. If this works ok, maybe consider accepting
+regexps in Only and Ignore tables.
+
+ . Merge with language processing boundary processing options, really
+integrating -S processing as a special case. Maybe, implement several
+level of boundaries. See how to implement a stack of languages, for
+handling quotations. See if more sophisticated references could be
+handled as another special case of a language.
+
+* Tackle other aspects, in a more long term view
+
+ . Add options for statistics, frequency lists, referencing, and all
+other prescreening tools and subsidiary tasks of concordance
+production.
+
+ . Develop an interactive mode. Even better, construct a GNU emacs
+interface. I'm looking at Gene Myers <gene@cs.arizona.edu> suffix
+arrays as a possible implementation along those ideas.
+
+ . Implement hooks so word classification and tagging should be merged
+in. See how to effectively hook in lemmatisation or other
+morphological features. It is far from being clear by now how to
+interface this correctly, so some experimentation is mandatory.
+
+ . Profile and speed up the whole thing.
+
+ . Make it work on small address space machines. Consider three levels
+of hugeness for files, and three corresponding algorithms to make
+optimal use of memory. The first case is when all the input files and
+all the word references fit in memory: this is the case currently
+implemented. The second case is when the files cannot fit all together
+in memory, but the word references do. The third case is when even
+the word references cannot fit in memory.
+
+ . There also are subsidiary developments for in-core incremental sort
+routines as well as for external sort packages. The need for more
+flexible sort packages comes partly from the fact that linguists use
+kinds of keys which compare in unusual and more sophisticated ways.
+GNU `sort' and `ptx' could evolve together.
+
+
+Local Variables:
+mode: outline
+outline-regexp: " *[-+*.] \\| "
+eval: (hide-body)
+End:
diff --git a/gnu/usr.bin/ptx/alloca.c b/gnu/usr.bin/ptx/alloca.c
new file mode 100644
index 000000000000..bd4932aa4453
--- /dev/null
+++ b/gnu/usr.bin/ptx/alloca.c
@@ -0,0 +1,484 @@
+/* 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
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#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
+#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
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define NULL 0
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
diff --git a/gnu/usr.bin/ptx/argmatch.c b/gnu/usr.bin/ptx/argmatch.c
new file mode 100644
index 000000000000..17e088b7e806
--- /dev/null
+++ b/gnu/usr.bin/ptx/argmatch.c
@@ -0,0 +1,94 @@
+/* argmatch.c -- find a match for a string in an array
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+#include <string.h>
+#endif
+
+extern char *program_name;
+
+/* If ARG is an unambiguous match for an element of the
+ null-terminated array OPTLIST, return the index in OPTLIST
+ of the matched element, else -1 if it does not match any element
+ or -2 if it is ambiguous (is a prefix of more than one element). */
+
+int
+argmatch (arg, optlist)
+ char *arg;
+ char **optlist;
+{
+ int i; /* Temporary index in OPTLIST. */
+ int arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++)
+ {
+ if (!strncmp (optlist[i], arg, arglen))
+ {
+ if (strlen (optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/* Error reporting for argmatch.
+ KIND is a description of the type of entity that was being matched.
+ VALUE is the invalid value that was given.
+ PROBLEM is the return value from argmatch. */
+
+void
+invalid_arg (kind, value, problem)
+ char *kind;
+ char *value;
+ int problem;
+{
+ fprintf (stderr, "%s: ", program_name);
+ if (problem == -1)
+ fprintf (stderr, "invalid");
+ else /* Assume -2. */
+ fprintf (stderr, "ambiguous");
+ fprintf (stderr, " %s `%s'\n", kind, value);
+}
diff --git a/gnu/usr.bin/ptx/bumpalloc.h b/gnu/usr.bin/ptx/bumpalloc.h
new file mode 100644
index 000000000000..bbf901fc1d47
--- /dev/null
+++ b/gnu/usr.bin/ptx/bumpalloc.h
@@ -0,0 +1,58 @@
+/* BUMP_ALLOC macro - increase table allocation by one element.
+ Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
+ Francois Pinard <pinard@iro.umontreal.ca>, 1990.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*-------------------------------------------------------------------------.
+| Bump the allocation of the array pointed to by TABLE whenever required. |
+| The table already has already COUNT elements in it, this macro ensure it |
+| has enough space to accommodate at least one more element. Space is |
+| allocated (2 ^ EXPONENT) elements at a time. Each element of the array |
+| is of type TYPE. |
+`-------------------------------------------------------------------------*/
+
+/* Routines `xmalloc' and `xrealloc' are called to do the actual memory
+ management. This implies that the program will abort with an `Virtual
+ Memory exhausted!' error if any problem arise.
+
+ To work correctly, at least EXPONENT and TYPE should always be the
+ same for all uses of this macro for any given TABLE. A secure way to
+ achieve this is to never use this macro directly, but use it to define
+ other macros, which would then be TABLE-specific.
+
+ The first time through, COUNT is usually zero. Note that COUNT is not
+ updated by this macro, but it should be update elsewhere, later. This
+ is convenient, because it allows TABLE[COUNT] to refer to the new
+ element at the end. Once its construction is completed, COUNT++ will
+ record it in the table. Calling this macro several times in a row
+ without updating COUNT is a bad thing to do. */
+
+#define BUMP_ALLOC(Table, Count, Exponent, Type) \
+ BUMP_ALLOC_WITH_SIZE ((Table), (Count), (Exponent), Type, sizeof (Type))
+
+/* In cases `sizeof TYPE' would not always yield the correct value for
+ the size of each element entry, this macro accepts a supplementary
+ SIZE argument. The EXPONENT, TYPE and SIZE parameters should still
+ have the same value for all macro calls related to a specific TABLE. */
+
+#define BUMP_ALLOC_WITH_SIZE(Table, Count, Exponent, Type, Size) \
+ if (((Count) & (~(~0 << (Exponent)))) == 0) \
+ if ((Count) == 0) \
+ (Table) = (Type *) xmalloc ((1 << (Exponent)) * (Size)); \
+ else \
+ (Table) = (Type *) \
+ xrealloc ((Table), ((Count) + (1 << (Exponent))) * (Size)); \
+ else
diff --git a/gnu/usr.bin/ptx/check-out b/gnu/usr.bin/ptx/check-out
new file mode 100644
index 000000000000..4d13c48bd337
--- /dev/null
+++ b/gnu/usr.bin/ptx/check-out
@@ -0,0 +1,65 @@
+:30: /ranslate to certain respons ibilities for you if you distr/
+:183: c/ These actions are proh ibited by law if you do not ac
+:278: AS BEEN ADVISED OF THE POSS IBILITY OF SUCH DAMAGES. /Y H
+:232: /his License may add an expl icit geographical distribution/
+:267: /COST OF ALL NECESSARY SERV ICING, REPAIR OR CORRECTION.
+:216: /ht claims or to contest val idity of any such claims; this/
+:45: e/ If the software is mod ified by someone else and pass
+:57: pying, distribution and mod ification follow. /for co
+:60: /PYING, DISTRIBUTION AND MOD IFICATION 0. This License a/
+:68: /either verbatim or with mod ifications and/or translated i/
+:70: limitation in the term "mod ification".) /ithout
+:72: /pying, distribution and mod ification are not covered by t/
+:92: /opy and distribute such mod ifications or work under the t/
+:95: /a) You must cause the mod ified files to carry prominent/
+:103: ommands in/ c) If the mod ified program normally reads c
+:114: quirements apply to the mod ified work as a whole. /se re
+:115: are not derived/ If ident ifiable sections of that work
+:156: of the work for making mod ifications to it. /ed form
+:243: Lice/ If the Program spec ifies a version number of this
+:46: /hat they have is not the or iginal, so that any problems i/
+:47: /will not reflect on the or iginal authors' reputations.
+:191: /eives a license from the or iginal licensor to copy, distr/
+:231: /yrighted interfaces, the or iginal copyright holder who pl/
+:265: /ED WARRANTIES OF MERCHANTAB ILITY AND FITNESS FOR A PARTIC/
+:274: /NG OUT OF THE USE OR INAB ILITY TO USE THE PROGRAM (INCL/
+:303: /warranty of MERCHANTAB ILITY or FITNESS FOR A PARTICU/
+:69: /ation is included without l imitation in the term "modific/
+:198: /for any other reason (not l imited to patent issues), cond/
+:232: /geographical distribution l imitation excluding those coun/
+:235: /License incorporates the l imitation as if written in the/
+:239: Such new versions will be s imilar in spirit to the presen/
+:264: /PLIED, INCLUDING, BUT NOT L IMITED TO, THE IMPLIED WARRANT/
+:274: /ROGRAM (INCLUDING BUT NOT L IMITED TO LOSS OF DATA OR DATA/
+:67: /hat is to say, a work conta ining the Program or a portion/
+:158: /ny associated interface def inition files, plus the script/
+:34: /fee, you must give the rec ipients all the rights that yo/
+:46: /passed on, we want its rec ipients to know that what they/
+:84: /nty; and give any other rec ipients of the Program a copy/
+:190: /ed on the Program), the rec ipient automatically receives/
+:193: /her restrictions on the rec ipients' exercise of the right/
+:239: /sions will be similar in sp irit to the present version, b/
+:254: o goals of prese/ Our dec ision will be guided by the tw
+:273: /OR CONSEQUENTIAL DAMAGES AR ISING OUT OF THE USE OR INAB/
+:315: /teractive mode: Gnomov ision version 69, Copyright (C/
+:316: /y name of author Gnomov ision comes with ABSOLUTELY NO/
+:330: /st in the program `Gnomov ision' (which makes passes at/
+:30: /late to certain responsibil ities for you if you distribut/
+:56: The precise terms and cond itions for copying, distributi/
+:60: /C LICENSE TERMS AND COND ITIONS FOR COPYING, DISTRIBUTI/
+:93: /also meet all of these cond itions: a) You must cause/
+:109: /rogram under these cond itions, and telling the user h/
+:129: ther work not bas/ In add ition, mere aggregation of ano
+:186: /and all its terms and cond itions for copying, distributi/
+:192: ect to these terms and cond itions. /am subj
+:199: /ted to patent issues), cond itions are imposed on you (whe/
+:200: /e) that contradict the cond itions of this License, they d/
+:201: ot excuse you from the cond itions of this License. /do n
+:244: /ollowing the terms and cond itions either of that version/
+:251: /ams whose distribution cond itions are different, write to/
+:262: /WHEN OTHERWISE STATED IN WR ITING THE COPYRIGHT HOLDERS AN/
+:270: /ABLE LAW OR AGREED TO IN WR ITING WILL ANY COPYRIGHT HOLDE/
+:280: ly/ END OF TERMS AND COND ITIONS Appendix: How to App
+:318: /e it under certain cond itions; type `show c' for deta/
+:52: /of a free program will ind ividually obtain patent licens/
+:72: stribution and mod/ Act ivities other than copying, di
diff --git a/gnu/usr.bin/ptx/config.h b/gnu/usr.bin/ptx/config.h
new file mode 100644
index 000000000000..93e7ed1fc688
--- /dev/null
+++ b/gnu/usr.bin/ptx/config.h
@@ -0,0 +1,57 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define if type char is unsigned and you are not using gcc. */
+/* #undef __CHAR_UNSIGNED__ */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* 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 you have alloca.h and it should be used (not Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* 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 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* In regex, request the capability of modifying the letter syntax. */
+#define SYNTAX_TABLE 1
+
+/* In regex, use 8 bits per character. */
+#define CHAR_SET_SIZE 256
+
+/* Define if you have mcheck. */
+/* #undef HAVE_MCHECK */
+
+/* Define if you have setchrclass. */
+/* #undef HAVE_SETCHRCLASS */
+
+/* Define if you have strerror. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
diff --git a/gnu/usr.bin/ptx/diacrit.c b/gnu/usr.bin/ptx/diacrit.c
new file mode 100644
index 000000000000..29e319bbdc49
--- /dev/null
+++ b/gnu/usr.bin/ptx/diacrit.c
@@ -0,0 +1,148 @@
+/* Diacritics processing for a few character codes.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Francois Pinard <pinard@iro.umontreal.ca>, 1988.
+
+ All this file is a temporary hack, waiting for locales in GNU.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "diacrit.h"
+
+/* ISO 8859-1 Latin-1 code is used as the underlying character set. If
+ MSDOS is defined, IBM-PC's character set code is used instead. */
+
+/*--------------------------------------------------------------------.
+| For each alphabetic character, returns what it would be without its |
+| possible diacritic symbol. |
+`--------------------------------------------------------------------*/
+
+const char diacrit_base[256] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
+ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0, 0, 0, 0, 0,
+
+#ifdef MSDOS
+
+ 'C', 'u', 'e', 'a', 'a', 'a', 'a', 'c',
+ 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A',
+ 'E', 'e', 'E', 'o', 'o', 'o', 'u', 'u',
+ 'y', 'O', 'U', 0, 0, 0, 0, 0,
+ 'a', 'i', 'o', 'u', 'n', 'N', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+#else /* not MSDOS */
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C',
+ 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+ 0, 'N', 'O', 'O', 'O', 'O', 'O', 0,
+ 'O', 'U', 'U', 'U', 'U', 'Y', 0, 0,
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
+ 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
+ 0, 'n', 'o', 'o', 'o', 'o', 'o', 0,
+ 'o', 'u', 'u', 'u', 'u', 'y', 0, 'y',
+
+#endif /* not MSDOS */
+};
+
+/*------------------------------------------------------------------------.
+| For each alphabetic character, returns a code of what its diacritic is, |
+| according to the following codes: 1 (eE) over aA for latin diphtongs; 2 |
+| (') acute accent; 3 (`) grave accent; 4 (^) circumflex accent; 5 (") |
+| umlaut or diaraesis; 6 (~) tilda; 7 (,) cedilla; 8 (o) covering degree |
+| symbol; 9 (|) slashed character. |
+`------------------------------------------------------------------------*/
+
+const char diacrit_diac[256] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 4, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 6, 0,
+
+#ifdef MSDOS
+
+ 7, 5, 2, 4, 5, 3, 8, 7,
+ 4, 5, 3, 5, 4, 3, 5, 8,
+ 2, 1, 1, 4, 5, 3, 4, 3,
+ 5, 5, 5, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+#else /* not MSDOS */
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 2, 4, 6, 5, 8, 1, 7,
+ 3, 2, 4, 5, 3, 2, 4, 5,
+ 0, 6, 3, 2, 4, 6, 5, 0,
+ 9, 3, 2, 4, 5, 2, 0, 0,
+ 3, 2, 4, 6, 5, 8, 1, 7,
+ 3, 2, 4, 5, 3, 2, 4, 5,
+ 0, 6, 3, 2, 4, 6, 5, 0,
+ 9, 3, 2, 4, 5, 2, 0, 0,
+
+#endif /* not MSDOS */
+};
diff --git a/gnu/usr.bin/ptx/diacrit.h b/gnu/usr.bin/ptx/diacrit.h
new file mode 100644
index 000000000000..c880a45ca8c8
--- /dev/null
+++ b/gnu/usr.bin/ptx/diacrit.h
@@ -0,0 +1,16 @@
+/* Diacritics processing for a few character codes.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Francois Pinard <pinard@iro.umontreal.ca>, 1988.
+
+ All this file is a temporary hack, waiting for locales in GNU.
+*/
+
+extern const char diacrit_base[]; /* characters without diacritics */
+extern const char diacrit_diac[]; /* diacritic code for each character */
+
+/* Returns CHR without its diacritic. CHR is known to be alphabetic. */
+#define tobase(chr) (diacrit_base[(unsigned char) (chr)])
+
+/* Returns a diacritic code for CHR. CHR is known to be alphabetic. */
+#define todiac(chr) (diacrit_diac[(unsigned char) (chr)])
+
diff --git a/gnu/usr.bin/ptx/error.c b/gnu/usr.bin/ptx/error.c
new file mode 100644
index 000000000000..41d66fb4f4f7
--- /dev/null
+++ b/gnu/usr.bin/ptx/error.c
@@ -0,0 +1,117 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
+
+#else /* !HAVE_VPRINTF */
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
+
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
+
+extern char *program_name;
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif /* !HAVE_VPRINTF or !__STDC__ */
+{
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif /* HAVE_VPRINTF */
+
+ fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+ VA_START (args, message);
+ vfprintf (stderr, message, args);
+ va_end (args);
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+ _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/gnu/usr.bin/ptx/examples/README b/gnu/usr.bin/ptx/examples/README
new file mode 100644
index 000000000000..038034f52618
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/README
@@ -0,0 +1,21 @@
+Various examples of GNU ptx usages.
+Francois Pinard <pinard@iro.umontreal.ca>, 1993.
+
+This directory contains a few examples contributed by GNU ptx users.
+Feel free to look at them for tricks or ideas. When an example
+requires many files, a subdirectory is used to hold them together.
+I have not necessarily tested these examples recently, if at all.
+
+If you have examples you would like to share, please submit them to
+me. You may also submit corrections to the examples given in this
+directory, however, please write to the authors first, since they most
+probably will like to have their say about their own contribution.
+
+* include.pl: A Perl script studying system include files.
+
+* luke/: A shell script permuting indices for man pages. It contains
+two examples of an .xx definition for *roff, one simple, one complex.
+
+* latex/: A simple example of \xx definition for latex.
+
+* ajay/: A more complex application of latex with ptx.
diff --git a/gnu/usr.bin/ptx/examples/ajay/Makefile b/gnu/usr.bin/ptx/examples/ajay/Makefile
new file mode 100644
index 000000000000..bff099c5f23c
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/Makefile
@@ -0,0 +1,28 @@
+JUNKFILES = tip-index.ps tip-index.dvi tip-index.tex tip-index.log \
+ tip-index.aux
+
+tip-index.ps : tip-index.dvi
+ dvips tip-index.dvi
+
+tip-index.dvi : tip-index.tex
+ latex tip-index.tex
+
+tip-index.tex : tip.texified header.tex footer.tex
+ cat header.tex tip.texified footer.tex > tip-index.tex
+
+tip.texified : tip.eign tip.forgptx Makefile
+ gptx -f -r -i ./tip.eign -T < tip.forgptx | x.pl > tip.texified
+
+tip.eign : /usr/lib/eign exclude-words
+ cat /usr/lib/eign exclude-words > tip.eign
+
+screenlist : tip.texified
+ cat tip.texified \
+ | gawk -F\{ '{count[$$4]++} \
+ END {for (s in count) printf("%d %20s\n", count[s], s)}' \
+ | tr -d '}' \
+ | sort -n > screenlist
+ @echo "Check (say) the last 100 lines of ./screenlist".
+
+clean :
+ rm -f tip.eign tip.texified $(JUNKFILES) screenlist
diff --git a/gnu/usr.bin/ptx/examples/ajay/README b/gnu/usr.bin/ptx/examples/ajay/README
new file mode 100644
index 000000000000..7b55ca2fbf47
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/README
@@ -0,0 +1,41 @@
+To: pinard@iro.umontreal.ca
+Subject: Re: Gptx suggestions and help request
+Date: Tue, 28 Sep 93 11:30:04 +0500
+From: ajayshah@cmie.ernet.in
+
+[...] My plaintext input looks like: "pagenum multiword-phrase" where
+the multiword phrase is atmost five words. So [...], I'm doing two
+columns in small type.
+
+I got one of the programmers here to write me a tex macro for my
+problem. When it goes into production I'll mail you a few files: a
+sample input, the gptx command, the output, and the tex macro. If you
+find these interesting you can ship them with future gptx releases.
+
+Thanks a lot for gptx. If you have a mailing list of loyal users,
+you can add us to it :-)
+
+
+To: pinard@iro.umontreal.ca
+Cc: rk@cmie.ernet.in
+Subject: All glue code I used with gptx
+Date: Tue, 05 Oct 93 15:23:44 +0500
+From: ajayshah@zigma.cmie.ernet.in
+
+That is a full set of a files for an example of "production use". You
+are welcome to post them, or use them as a sample supplied with the
+gptx distribution, etc., with absolutely no restrictions on what
+anyone does with this. In case you do so, please acknowledge the
+contribution of Rakesh Chauhan, rk@cmie.ernet.in, who is the author of
+x.pl and header.tex. [...]
+
+As you can tell, I used it for a 100% realworld problem, and it
+worked. Thanks a million. If you'd like, I can send you a hardcopy
+of the full finished document (just send me your mailing address). If
+you would like to mention the name of this document when you use
+these files as a demo, it is
+
+ Trends in Industrial Production
+ September 1993
+ Centre for Monitoring Indian Economy, Bombay, India.
+
diff --git a/gnu/usr.bin/ptx/examples/ajay/footer.tex b/gnu/usr.bin/ptx/examples/ajay/footer.tex
new file mode 100644
index 000000000000..6b47932f52ba
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/footer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/gnu/usr.bin/ptx/examples/ajay/header.tex b/gnu/usr.bin/ptx/examples/ajay/header.tex
new file mode 100644
index 000000000000..04a9c644802a
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/header.tex
@@ -0,0 +1,21 @@
+\documentstyle [twocolumn,a4]{article}
+
+\pagestyle{empty}
+
+\textwidth 6.8in
+\oddsidemargin -.8in
+\evensidemargin -.8in
+\textheight 10in
+\topmargin -1in
+% \columnseprule 1pt
+
+\begin{document}
+
+\def\xx #1#2#3#4#5#6{\hbox to \hsize{%
+\hbox to 1.4in{\hfill #2}\hskip .05in%
+\hbox to .8in{\it #3\hfil}\hskip .05in%
+\hbox to 1.4in{#4\hfil}\hskip .05in%
+\hbox{\hfil #6}\hfil}%
+}
+
+\scriptsize
diff --git a/gnu/usr.bin/ptx/examples/ajay/tip.forgptx b/gnu/usr.bin/ptx/examples/ajay/tip.forgptx
new file mode 100644
index 000000000000..ecf6e0e5e893
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/tip.forgptx
@@ -0,0 +1,10 @@
+1 Zinc concentrate
+1 Coal
+1 Ball clay
+1 Non-coking coal
+1 Calcareous sand
+1 Natural Gas
+1 Chalk
+1 Bauxite
+1 Clay (others)
+1 Copper ore
diff --git a/gnu/usr.bin/ptx/examples/ajay/x.pl b/gnu/usr.bin/ptx/examples/ajay/x.pl
new file mode 100644
index 000000000000..e0615ba0f666
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ajay/x.pl
@@ -0,0 +1,22 @@
+#! /usr/local/bin/perl
+
+while ($l = <>)
+{
+chop $l;
+
+$l =~ s/\\xx //;
+$l =~ s/}{/|/g;
+$l =~ s/{//g;
+$l =~ s/}//g;
+@x = split(/\|/, $l);
+
+printf ("\\xx ");
+for ($i = 0; $i <= $#x; $i++)
+ {
+ $v = substr($x[$i], 0, 17);
+ $v =~ s/\\$//;
+ printf("{%s}", $v);
+ }
+printf ("\n");
+
+}
diff --git a/gnu/usr.bin/ptx/examples/ignore/README b/gnu/usr.bin/ptx/examples/ignore/README
new file mode 100644
index 000000000000..33ee19ecb389
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ignore/README
@@ -0,0 +1,65 @@
+From beebe@math.utah.edu Wed Oct 27 19:37:22 1993
+Date: Tue, 26 Oct 93 15:43:19 MDT
+From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
+To: pinard@iro.umontreal.ca
+Subject: Re: Another short comment on gptx 0.2
+
+/usr/lib/eign: DECstation 5000, ULTRIX 4.3
+ HP 9000/735, HP-UX 9.0
+ IBM RS/6000, AIX 2.3
+ IBM 3090, AIX MP370 2.1
+ Stardent 1520, OS 2.2
+ Sun SPARCstation, SunOS 4.x
+
+No eign anywhere on: HP 375, BSD 4.3 (ptx.c is in /usr/src/usr.bin,
+ and the source code refers to /usr/lib/eign,
+ but I could not find it in the source tree)
+ NeXT, Mach 3.0 (though documented in man pages)
+ Sun SPARCstation, Solaris 2.x
+ SGI Indigo, IRIX 4.0.x
+
+The contents of the eign files that I found on the above machines were
+almost identical. With the exception of the Stardent and the IBM
+3090, there were only two such files, one with 150 words, and the
+other with 133, with only a few differences between them (some words
+in the 133-word file were not in the 150-word file). I found the
+133-word variant in groff-1.06/src/indxbib. I used archie to search
+for eign, and it found 7 sites, all with the groff versions.
+
+The Stardent and IBM 3090 eign files have the same contents as the
+150-word version, but have a multiline copyright comment at the
+beginning. None of the others contains a copyright.
+
+I recently had occasion to build a similar list of words for bibindex,
+which indexes a BibTeX .bib file, and for which omission of common
+words, like articles and prepositions, helps to reduce the size of the
+index. I didn't use eign to build that list, but instead, went
+through the word lists from 3.8MB of .bib files in the tuglib
+collection on ftp.math.utah.edu:pub/tex/bib, and collected words to be
+ignored. That list includes words from several languages. I'll leave
+it up to you to decide whether you wish to merge them or not; I
+suspect it may be a better design choice to keep a separate eign file
+for each language, although in my own application of ptx-ing
+bibliographies, the titles do occur in multiple languages, so a
+mixed-language eign is appropriate. Since there are standard ISO
+2-letter abbreviations for every country, perhaps one could have
+eign.xy for country xy (of course, only approximately is country ==
+language). The exact list of words in eign is not so critical; its
+only purpose is to reduce the size of the output by not indexing words
+that occur very frequently and have little content in themselves.
+
+I'm enclosing a shar bundle at the end of this message with the merger
+of the multiple eign versions (duplicates eliminated, and the list
+sorted into 179 unique words), followed by the bibindex list.
+
+
+
+========================================================================
+Nelson H. F. Beebe Tel: +1 801 581 5254
+Center for Scientific Computing FAX: +1 801 581 4148
+Department of Mathematics, 105 JWB Internet: beebe@math.utah.edu
+University of Utah
+Salt Lake City, UT 84112, USA
+========================================================================
+
+
diff --git a/gnu/usr.bin/ptx/examples/ignore/bix b/gnu/usr.bin/ptx/examples/ignore/bix
new file mode 100644
index 000000000000..b9a8ba69adef
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ignore/bix
@@ -0,0 +1,109 @@
+ab
+aber
+als
+an
+and
+are
+as
+auf
+aus
+az
+bei
+bir
+but
+da
+das
+dat
+de
+dei
+dem
+den
+der
+des
+det
+di
+die
+dos
+een
+eene
+egy
+ei
+ein
+eine
+einen
+einer
+eines
+eit
+el
+en
+er
+es
+et
+ett
+eyn
+eyne
+for
+from
+fuer
+fur
+gl
+gli
+ha
+haben
+had
+hai
+has
+hat
+have
+he
+heis
+hen
+hena
+henas
+het
+hin
+hinar
+hinir
+hinn
+hith
+ho
+hoi
+il
+in
+ist
+ka
+ke
+la
+las
+le
+les
+lo
+los
+mia
+mit
+na
+nji
+not
+oder
+of
+on
+or
+os
+others
+sie
+sind
+so
+ta
+the
+to
+um
+uma
+un
+una
+und
+une
+uno
+unter
+von
+with
+yr
diff --git a/gnu/usr.bin/ptx/examples/ignore/eign b/gnu/usr.bin/ptx/examples/ignore/eign
new file mode 100644
index 000000000000..0401245ed007
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/ignore/eign
@@ -0,0 +1,163 @@
+a
+about
+after
+against
+all
+also
+an
+and
+another
+any
+are
+as
+at
+back
+be
+because
+been
+before
+being
+between
+both
+but
+by
+came
+can
+come
+could
+current
+day
+did
+do
+down
+each
+end
+even
+first
+for
+from
+get
+go
+good
+great
+had
+has
+have
+he
+her
+here
+him
+his
+how
+i
+if
+in
+into
+is
+it
+its
+just
+know
+last
+life
+like
+little
+long
+made
+make
+man
+many
+may
+me
+men
+might
+more
+most
+mr
+much
+must
+my
+name
+never
+new
+no
+not
+now
+of
+off
+old
+on
+one
+only
+or
+other
+our
+out
+over
+own
+part
+people
+point
+right
+said
+same
+say
+see
+she
+should
+since
+so
+some
+start
+state
+still
+such
+take
+than
+that
+the
+their
+them
+then
+there
+these
+they
+this
+those
+three
+through
+time
+to
+too
+true
+try
+two
+under
+up
+us
+use
+used
+value
+very
+was
+way
+we
+well
+were
+what
+when
+where
+which
+while
+who
+why
+will
+with
+without
+work
+world
+would
+year
+years
+you
+your
diff --git a/gnu/usr.bin/ptx/examples/include.pl b/gnu/usr.bin/ptx/examples/include.pl
new file mode 100755
index 000000000000..cb3c0ffe5263
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/include.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl -- # -*-Perl-*-
+eval "exec /usr/bin/perl -S $0 $*"
+ if $running_under_some_shell;
+
+# Construct a permuted index for all system include files.
+# Copyright (C) 1991 Free Software Foundation, Inc.
+# Francois Pinard <pinard@iro.umontreal.ca>, June 1991.
+
+# NOTE: about removing asm statements?
+# NOTE: about removing strings?
+# NOTE: about ignoring 0xHEXDIGITS, unchar/ushort/etc.
+
+# Construct a sorted list of system include files.
+
+opendir (DIR, "/usr/include");
+@includes = sort grep (-f "/usr/include/$_", readdir (DIR));
+opendir (DIR, "/usr/include/sys");
+foreach (sort grep (-f "/usr/include/sys/$_", readdir (DIR))) {
+ push (@includes, "sys/$_");
+}
+closedir (DIR);
+
+# Launch the permuted indexer, with a list of ignore words.
+
+$ignore = "/tmp/incptx.$$";
+open (IGNORE, "> $ignore");
+print IGNORE join ("\n", split (' ', <<IGNORE)), "\n";
+asm at at386 break bss case ch char continue copyright corporation
+default define defined do double dst else endif enum extern file flag
+float for goto i286 i386 ident if ifdef ifndef int interactive len
+lint long m32 mpat num pdp11 printf ptr register return sco5 short siz
+sizeof src static str struct sun switch sys systems type typedef u370
+u3b u3b15 u3b2 u3b5 undef union unsigned vax void while win
+IGNORE
+close IGNORE;
+exit 0;
+
+open (OUTPUT, "| ptx -r -f -W '[a-zA-Z_][a-zA-Z_0-9]+' -F ... -i $ignore")
+ || die "ptx did not start\n";
+select (OUTPUT);
+
+# Reformat all files, removing C comments and adding a reference field.
+
+foreach $include (@includes)
+{
+ warn "Reading /usr/include/$include\n";
+ open (INPUT, "/usr/include/$include");
+ while (<INPUT>)
+ {
+
+ # Get rid of comments.
+
+ $comment = $next_comment;
+ if ($comment)
+ {
+ $next_comment = !s,^.*\*/,,;
+ }
+ else
+ {
+ s,/\*.*\*/,,g;
+ $next_comment = s,/\*.*,,;
+ }
+ next if $comment && $next_comment;
+
+ # Remove extraneous white space.
+
+ s/[ \t]+/ /g;
+ s/ $//;
+ next if /^$/;
+
+ # Print the line with its reference.
+
+ print "$include($.): ", $_;
+ }
+}
+
+warn "All read, now ptx' game!\n";
+close OUTPUT || die "ptx failed...\n";
+unlink $ignore;
diff --git a/gnu/usr.bin/ptx/examples/latex/Makefile b/gnu/usr.bin/ptx/examples/latex/Makefile
new file mode 100644
index 000000000000..5f930b2c7d0e
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/latex/Makefile
@@ -0,0 +1,15 @@
+# Example of using ptx with latex.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Francois Pinard <pinard@iro.umontreal.ca>, 1993.
+
+PTX = ../ptx
+PTX_OPTIONS = -AfTWi.i
+
+try: latex.dvi
+ xdvi latex
+
+latex.dvi: latex.tex table.tex
+ latex latex
+
+table.tex: Makefile ../COPYING
+ $(PTX) $(PTX_OPTIONS) ../COPYING | sed 's/ //' > table.tex
diff --git a/gnu/usr.bin/ptx/examples/latex/README b/gnu/usr.bin/ptx/examples/latex/README
new file mode 100644
index 000000000000..fc5098a8dd49
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/latex/README
@@ -0,0 +1,10 @@
+Date: Sun, 26 Sep 93 19:07:10 EDT
+From: Francois Pinard <pinard@iro.umontreal.ca>
+To: ajayshah@cmie.ernet.in
+Subject: Re: Gptx suggestions and help request
+
+ In fact, if you could send me such a macro right now I would be
+ thrilled :-)
+
+Ok, I worked out this example for you. Even if a little rude, you can
+still start from it for your own need. [...]
diff --git a/gnu/usr.bin/ptx/examples/latex/latex.tex b/gnu/usr.bin/ptx/examples/latex/latex.tex
new file mode 100644
index 000000000000..1f0a2f10bb1d
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/latex/latex.tex
@@ -0,0 +1,11 @@
+\documentstyle[11pt]{article}
+\begin{document}
+
+\def\xx#1#2#3#4#5#6{\hbox{
+ \hbox to2.5in{\hfil#5#2}
+ \hbox to3.0in{{\sl #3}\,#4#1\hfil}
+ \hbox to1.5in{\tiny#6\hfil}
+}}
+\input table
+
+\end{document}
diff --git a/gnu/usr.bin/ptx/examples/latex/table.tex b/gnu/usr.bin/ptx/examples/latex/table.tex
new file mode 100644
index 000000000000..b68ea38d7ca0
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/latex/table.tex
@@ -0,0 +1,65 @@
+\xx {}{ate to certain respons}{ibi}{lities for you if you}{}{../COPYING:30}
+\xx {}{These actions are proh}{ibi}{ted by law if you do n}{}{../COPYING:183}
+\xx {}{EN ADVISED OF THE POSS}{IBI}{LITY OF SUCH DAMAGES.}{}{../COPYING:278}
+\xx {}{icense may add an expl}{ici}{t geographical distrib}{}{../COPYING:232}
+\xx {}{OF ALL NECESSARY SERV}{ICI}{NG, REPAIR OR CORRECTI}{}{../COPYING:267}
+\xx {}{aims or to contest val}{idi}{ty of any such claims;}{}{../COPYING:216}
+\xx {}{If the software is mod}{ifi}{ed by someone else and}{}{../COPYING:45}
+\xx {}{, distribution and mod}{ifi}{cation follow.}{pying}{../COPYING:57}
+\xx {}{, DISTRIBUTION AND MOD}{IFI}{CATION 0. This Lice}{}{../COPYING:60}
+\xx {}{r verbatim or with mod}{ifi}{cations and/or transla}{}{../COPYING:68}
+\xx {}{ation in the term "mod}{ifi}{cation".)}{t limit}{../COPYING:70}
+\xx {}{, distribution and mod}{ifi}{cation are not covered}{}{../COPYING:72}
+\xx {}{nd distribute such mod}{ifi}{cations or work under}{}{../COPYING:92}
+\xx {}{You must cause the mod}{ifi}{ed files to carry prom}{}{../COPYING:95}
+\xx {ads c}{c) If the mod}{ifi}{ed program normally re}{}{../COPYING:103}
+\xx {}{ments apply to the mod}{ifi}{ed work as a whole.}{}{../COPYING:114}
+\xx {work are n}{If ident}{ifi}{able sections of that}{}{../COPYING:115}
+\xx {}{he work for making mod}{ifi}{cations to it.}{of t}{../COPYING:156}
+\xx {}{If the Program spec}{ifi}{es a version number of}{}{../COPYING:243}
+\xx {}{hey have is not the or}{igi}{nal, so that any probl}{}{../COPYING:46}
+\xx {}{not reflect on the or}{igi}{nal authors' reputatio}{}{../COPYING:47}
+\xx {}{a license from the or}{igi}{nal licensor to copy,}{}{../COPYING:191}
+\xx {}{ted interfaces, the or}{igi}{nal copyright holder w}{}{../COPYING:231}
+\xx {}{RRANTIES OF MERCHANTAB}{ILI}{TY AND FITNESS FOR A P}{}{../COPYING:265}
+\xx {}{OUT OF THE USE OR INAB}{ILI}{TY TO USE THE PROGRAM}{}{../COPYING:274}
+\xx {}{anty of MERCHANTAB}{ILI}{TY or FITNESS FOR A PA}{}{../COPYING:303}
+\xx {}{is included without l}{imi}{tation in the term "mo}{}{../COPYING:69}
+\xx {}{ny other reason (not l}{imi}{ted to patent issues),}{}{../COPYING:198}
+\xx {}{aphical distribution l}{imi}{tation excluding those}{}{../COPYING:232}
+\xx {}{nse incorporates the l}{imi}{tation as if written i}{}{../COPYING:235}
+\xx {}{new versions will be s}{imi}{lar in spirit to the p}{}{../COPYING:239}
+\xx {}{, INCLUDING, BUT NOT L}{IMI}{TED TO, THE IMPLIED WA}{}{../COPYING:264}
+\xx {}{M (INCLUDING BUT NOT L}{IMI}{TED TO LOSS OF DATA OR}{}{../COPYING:274}
+\xx {}{s to say, a work conta}{ini}{ng the Program or a po}{}{../COPYING:67}
+\xx {}{sociated interface def}{ini}{tion files, plus the s}{}{../COPYING:158}
+\xx {}{you must give the rec}{ipi}{ents all the rights th}{}{../COPYING:34}
+\xx {}{ed on, we want its rec}{ipi}{ents to know that what}{}{../COPYING:46}
+\xx {}{and give any other rec}{ipi}{ents of the Program a}{}{../COPYING:84}
+\xx {}{the Program), the rec}{ipi}{ent automatically rece}{}{../COPYING:190}
+\xx {}{estrictions on the rec}{ipi}{ents' exercise of the}{}{../COPYING:193}
+\xx {}{will be similar in sp}{iri}{t to the present versi}{}{../COPYING:239}
+\xx {he two goal}{Our dec}{isi}{on will be guided by t}{}{../COPYING:254}
+\xx {}{NSEQUENTIAL DAMAGES AR}{ISI}{NG OUT OF THE USE OR I}{}{../COPYING:273}
+\xx {}{tive mode: Gnomov}{isi}{on version 69, Copyrig}{}{../COPYING:315}
+\xx {}{e of author Gnomov}{isi}{on comes with ABSOLUTE}{}{../COPYING:316}
+\xx {}{the program `Gnomov}{isi}{on' (which makes passe}{}{../COPYING:330}
+\xx {}{to certain responsibil}{iti}{es for you if you dist}{}{../COPYING:30}
+\xx {}{precise terms and cond}{iti}{ons for copying, distr}{}{../COPYING:56}
+\xx {}{ENSE TERMS AND COND}{ITI}{ONS FOR COPYING, DISTR}{}{../COPYING:60}
+\xx {}{meet all of these cond}{iti}{ons: a) You must}{}{../COPYING:93}
+\xx {}{m under these cond}{iti}{ons, and telling the u}{}{../COPYING:109}
+\xx {f another wo}{In add}{iti}{on, mere aggregation o}{}{../COPYING:129}
+\xx {}{all its terms and cond}{iti}{ons for copying, distr}{}{../COPYING:186}
+\xx {}{o these terms and cond}{iti}{ons.}{bject t}{../COPYING:192}
+\xx {}{o patent issues), cond}{iti}{ons are imposed on you}{}{../COPYING:199}
+\xx {}{at contradict the cond}{iti}{ons of this License, t}{}{../COPYING:200}
+\xx {}{cuse you from the cond}{iti}{ons of this License.}{}{../COPYING:201}
+\xx {}{ing the terms and cond}{iti}{ons either of that ver}{}{../COPYING:244}
+\xx {}{hose distribution cond}{iti}{ons are different, wri}{}{../COPYING:251}
+\xx {}{OTHERWISE STATED IN WR}{ITI}{NG THE COPYRIGHT HOLDE}{}{../COPYING:262}
+\xx {}{LAW OR AGREED TO IN WR}{ITI}{NG WILL ANY COPYRIGHT}{}{../COPYING:270}
+\xx {}{END OF TERMS AND COND}{ITI}{ONS Appendix: How t}{}{../COPYING:280}
+\xx {}{under certain cond}{iti}{ons; type `show c' for}{}{../COPYING:318}
+\xx {}{free program will ind}{ivi}{dually obtain patent l}{}{../COPYING:52}
+\xx {g, distribution}{Act}{ivi}{ties other than copyin}{}{../COPYING:72}
diff --git a/gnu/usr.bin/ptx/examples/luke/README b/gnu/usr.bin/ptx/examples/luke/README
new file mode 100644
index 000000000000..62918611d4f4
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/luke/README
@@ -0,0 +1,2 @@
+From: Luke Kendall <luke@research.canon.oz.au>
+Date: Wed, 16 Oct 91 12:26:39 EST
diff --git a/gnu/usr.bin/ptx/examples/luke/xxroff.sh b/gnu/usr.bin/ptx/examples/luke/xxroff.sh
new file mode 100644
index 000000000000..55ef90826e49
--- /dev/null
+++ b/gnu/usr.bin/ptx/examples/luke/xxroff.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# Author: Luke Kendall
+#
+MYNAME=`basename $0`
+usage="usage: $MYNAME [man-directory]
+ (generates permuted index of -man files in directory)"
+md=/usr/man
+#
+if [ $# = 0 ]
+then
+ echo "$MYNAME: no man directory specified: assuming $md"
+elif [ $# != 1 ]
+then
+ echo "$usage"
+ exit 1
+elif [ -d $1 ]
+then
+ md="$1"
+else
+ echo "$usage"
+ exit 1
+fi
+echo "Permuted index of $md:"
+out=ptx.tr
+# ------ clumsy permuted index macros (replaced by stuff below) ------------
+cat <<'EOF' > $out
+.pn 1
+.de xx
+\\$1 \\$2 \\fB\\$3\\fR \\$4 \\s-1\\$5\\s0
+..
+.pl 10i
+.de NP
+.ev 1
+.ft 1
+.ps 10
+.sp 0.75c
+.tl '\s-2\\fIpermuted index\\fP\s0'\- \\n% \-'\s-2\\fIpermuted index\\fP\s0'
+.pn +1
+.bp
+.ev
+..
+.wh 9i NP
+.nf
+.na
+.ta 6.5i-1.1iR 6.5iR 6.51iR 6.52R
+.ll 6.0i
+.po 0i
+.sp 0.25i
+'\"
+EOF
+# ------ ------- ------- ------- ------- -------
+# ------ alternate permuted index macros (from net) ------------
+cat <<'EOF' > $out
+.pl 10i
+.de NP
+.ev 1
+.ft 1
+.ps 10
+.sp 0.75c
+.tl '\s-2\\fIpermuted index\\fP\s0'\- \\n% \-'\s-2\\fIpermuted index\\fP\s0'
+.pn +1
+.bp
+.ev
+..
+.wh 9i NP
+.po 0.5i
+.sp 0.25i
+.tr ~ \" tildes will translate to blanks
+'\".ll 80 \" line length of output
+.ll 6.0i \" line length of output
+.nf \" must be in no-fill mode
+.nr )r \n(.lu-10n \" set position of reference in line (10 less than length)
+.nr )k \n()ru/2u \" set position of keyword (approx. centered)
+.ds s2 ~~~ \" this is the center gap -- 3 spaces
+.de xx \"definition of xx macro
+.ds s1\" \" initialise to null string
+.if \w@\\$2@ .ds s1 ~\" \"set to single blank if there is second arg
+.ds s3\" \" initialise to null string
+.if \w@\\$4@ .ds s3 ~\" \"set to single blank if there is second arg
+.ds s4 ~\" \" set to single blank
+.ds s5 ~\" \" set to single blank
+.ds y \\*(s4\a\\*(s5\" \" blank, leader, blank
+.ta \\n()ru-\w@\\*(s5@u \" set tab just to left of ref
+\h@\\n()ku-\w@\\$1\\*(s1\\$2\\*(s2@u@\\$1\\*(s1\\$2\\*(s2\\$3\\*(s3\\$4\\*y\\$5
+..
+ ~
+EOF
+# ------ ------- ------- ------- ------- -------
+find $md -type f -name "*.[1-8nl]*" -print |
+while read f
+do
+ man=`basename $f`
+ man=`expr "$man" : "\(.*\)\.[^\.]*"`
+echo $man:
+ #
+ # Use 1st non-"." and non-"'" started line as input to ptx (this
+ # should be the synopsis after the `.SH NAME');
+ # strip any "\-" from it (a silly sort key for ptx to avoid);
+ # insert a leading man page name for the -r option to find
+ #
+ sed -n '/^[^.]/s/\\-//g;/^[^.]/p;/^[^.]/q' $f | sed "s/^/($man) /"
+done | ptx -t -f -r >> $out
+#
+# Turn the troff'able permuted index file into PostScript
+#
+psroff -t -rL10i $out > ptx.ps
+echo "$out and ptx.ps produced from man directory $md."
diff --git a/gnu/usr.bin/ptx/getopt.c b/gnu/usr.bin/ptx/getopt.c
new file mode 100644
index 000000000000..7a4673b8d8db
--- /dev/null
+++ b/gnu/usr.bin/ptx/getopt.c
@@ -0,0 +1,757 @@
+/* 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 roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* 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>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* 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 EOF, 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. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it.
+ (Supposedly there are some machines where it might get a warning,
+ but changing this conditional to __STDC__ is too risky.) */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* 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 (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ 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;
+ }
+ /* 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;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* 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 `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ 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. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* 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 ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - 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 nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ 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/gnu/usr.bin/ptx/getopt.h b/gnu/usr.bin/ptx/getopt.h
new file mode 100644
index 000000000000..45541f5ac0f9
--- /dev/null
+++ b/gnu/usr.bin/ptx/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/ptx/getopt1.c b/gnu/usr.bin/ptx/getopt1.c
new file mode 100644
index 000000000000..f784b5757c59
--- /dev/null
+++ b/gnu/usr.bin/ptx/getopt1.c
@@ -0,0 +1,187 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ 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/gnu/usr.bin/ptx/mkinstalldirs b/gnu/usr.bin/ptx/mkinstalldirs
new file mode 100755
index 000000000000..0e2937731092
--- /dev/null
+++ b/gnu/usr.bin/ptx/mkinstalldirs
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make directory hierarchy.
+# Written by Noah Friedman <friedman@prep.ai.mit.edu>
+# Public domain.
+
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ oIFS="${IFS}"
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS="${oIFS}"
+
+ pathcomp=''
+
+ for d in ${1+"$@"} ; do
+ pathcomp="${pathcomp}${d}"
+
+ if test ! -d "${pathcomp}"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "${pathcomp}" || errstatus=$?
+ fi
+
+ pathcomp="${pathcomp}/"
+ done
+done
+
+exit $errstatus
+
+# eof
diff --git a/gnu/usr.bin/ptx/ptx.c b/gnu/usr.bin/ptx/ptx.c
new file mode 100644
index 000000000000..2dc306e97150
--- /dev/null
+++ b/gnu/usr.bin/ptx/ptx.c
@@ -0,0 +1,2237 @@
+/* Permuted index for GNU, with keywords in their context.
+ Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
+ Francois Pinard <pinard@iro.umontreal.ca>, 1988.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+const char *version_string = "GNU ptx version 0.3";
+
+char *const copyright = "\
+This program is free software; you can redistribute it and/or modify\n\
+it under the terms of the GNU General Public License as published by\n\
+the Free Software Foundation; either version 2, or (at your option)\n\
+any later version.\n\
+\n\
+This program is distributed in the hope that it will be useful,\n\
+but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
+GNU General Public License for more details.\n\
+\n\
+You should have received a copy of the GNU General Public License\n\
+along with this program; if not, write to the Free Software\n\
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
+
+/* Reallocation step when swallowing non regular files. The value is not
+ the actual reallocation step, but its base two logarithm. */
+#define SWALLOW_REALLOC_LOG 12
+
+/* Imported from "regex.c". */
+#define Sword 1
+
+#ifdef STDC_HEADERS
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#else /* not STDC_HEADERS */
+
+/* These definitions work, for all 256 characters. */
+#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
+#define isxdigit(c) \
+ (((unsigned char) (c) >= 'a' && (unsigned char) (c) <= 'f') \
+ || ((unsigned char) (c) >= 'A' && (unsigned char) (c) <= 'F') \
+ || ((unsigned char) (c) >= '0' && (unsigned char) (c) <= '9'))
+#define islower(c) ((unsigned char) (c) >= 'a' && (unsigned char) (c) <= 'z')
+#define isupper(c) ((unsigned char) (c) >= 'A' && (unsigned char) (c) <= 'Z')
+#define isalpha(c) (islower (c) || isupper (c))
+#define toupper(c) (islower (c) ? (c) - 'a' + 'A' : (c))
+
+#endif /* not STDC_HEADERS */
+
+#if !defined (isascii) || defined (STDC_HEADERS)
+#undef isascii
+#define isascii(c) 1
+#endif
+
+#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
+#define ISODIGIT(c) ((c) >= '0' && (c) <= '7')
+#define HEXTOBIN(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
+#define OCTTOBIN(c) ((c) - '0')
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else /* not HAVE_STRING_H */
+#include <strings.h>
+#define strchr index
+#define strrchr rindex
+#endif /* not HAVE_STRING_H */
+
+#include "getopt.h"
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include "bumpalloc.h"
+#include "diacrit.h"
+#include "regex.h"
+
+#ifndef __STDC__
+void *xmalloc ();
+void *xrealloc ();
+#else
+void *xmalloc (int);
+void *xrealloc (void *, int);
+#endif
+
+
+/* Global definitions. */
+
+const char *program_name; /* name of this program */
+static int show_help = 0; /* display usage information and exit */
+static int show_version = 0; /* print the version and exit */
+
+/* Program options. */
+
+enum Format
+{
+ DUMB_FORMAT, /* output for a dumb terminal */
+ ROFF_FORMAT, /* output for `troff' or `nroff' */
+ TEX_FORMAT, /* output for `TeX' or `LaTeX' */
+ UNKNOWN_FORMAT /* output format still unknown */
+};
+
+int gnu_extensions = 1; /* trigger all GNU extensions */
+int auto_reference = 0; /* references are `file_name:line_number:' */
+int input_reference = 0; /* references at beginning of input lines */
+int right_reference = 0; /* output references after right context */
+int line_width = 72; /* output line width in characters */
+int gap_size = 3; /* number of spaces between output fields */
+const char *truncation_string = "/";
+ /* string used to mark line truncations */
+const char *macro_name = "xx"; /* macro name for roff or TeX output */
+enum Format output_format = UNKNOWN_FORMAT;
+ /* output format */
+
+int ignore_case = 0; /* fold lower to upper case for sorting */
+const char *context_regex_string = NULL;
+ /* raw regex for end of context */
+const char *word_regex_string = NULL;
+ /* raw regex for a keyword */
+const char *break_file = NULL; /* name of the `Break characters' file */
+const char *only_file = NULL; /* name of the `Only words' file */
+const char *ignore_file = NULL; /* name of the `Ignore words' file */
+
+/* A BLOCK delimit a region in memory of arbitrary size, like the copy of a
+ whole file. A WORD is something smaller, its length should fit in a
+ short integer. A WORD_TABLE may contain several WORDs. */
+
+typedef struct
+ {
+ char *start; /* pointer to beginning of region */
+ char *end; /* pointer to end + 1 of region */
+ }
+BLOCK;
+
+typedef struct
+ {
+ char *start; /* pointer to beginning of region */
+ short size; /* length of the region */
+ }
+WORD;
+
+typedef struct
+ {
+ WORD *start; /* array of WORDs */
+ size_t length; /* number of entries */
+ }
+WORD_TABLE;
+
+/* Pattern description tables. */
+
+/* For each character, provide its folded equivalent. */
+unsigned char folded_chars[CHAR_SET_SIZE];
+
+/* For each character, indicate if it is part of a word. */
+char syntax_table[CHAR_SET_SIZE];
+char *re_syntax_table = syntax_table;
+
+/* Compiled regex for end of context. */
+struct re_pattern_buffer *context_regex;
+
+/* End of context pattern register indices. */
+struct re_registers context_regs;
+
+/* Compiled regex for a keyword. */
+struct re_pattern_buffer *word_regex;
+
+/* Keyword pattern register indices. */
+struct re_registers word_regs;
+
+/* A word characters fastmap is used only when no word regexp has been
+ provided. A word is then made up of a sequence of one or more characters
+ allowed by the fastmap. Contains !0 if character allowed in word. Not
+ only this is faster in most cases, but it simplifies the implementation
+ of the Break files. */
+char word_fastmap[CHAR_SET_SIZE];
+
+/* Maximum length of any word read. */
+int maximum_word_length;
+
+/* Maximum width of any reference used. */
+int reference_max_width;
+
+
+/* Ignore and Only word tables. */
+
+WORD_TABLE ignore_table; /* table of words to ignore */
+WORD_TABLE only_table; /* table of words to select */
+
+#define ALLOC_NEW_WORD(table) \
+ BUMP_ALLOC ((table)->start, (table)->length, 8, WORD)
+
+/* Source text table, and scanning macros. */
+
+int number_input_files; /* number of text input files */
+int total_line_count; /* total number of lines seen so far */
+const char **input_file_name; /* array of text input file names */
+int *file_line_count; /* array of `total_line_count' values at end */
+
+BLOCK text_buffer; /* file to study */
+char *text_buffer_maxend; /* allocated end of text_buffer */
+
+/* SKIP_NON_WHITE used only for getting or skipping the reference. */
+
+#define SKIP_NON_WHITE(cursor, limit) \
+ while (cursor < limit && !isspace(*cursor)) \
+ cursor++
+
+#define SKIP_WHITE(cursor, limit) \
+ while (cursor < limit && isspace(*cursor)) \
+ cursor++
+
+#define SKIP_WHITE_BACKWARDS(cursor, start) \
+ while (cursor > start && isspace(cursor[-1])) \
+ cursor--
+
+#define SKIP_SOMETHING(cursor, limit) \
+ do \
+ if (word_regex_string) \
+ { \
+ int count; \
+ count = re_match (word_regex, cursor, limit - cursor, 0, NULL); \
+ cursor += count <= 0 ? 1 : count; \
+ } \
+ else if (word_fastmap[(unsigned char) *cursor]) \
+ while (cursor < limit && word_fastmap[(unsigned char) *cursor]) \
+ cursor++; \
+ else \
+ cursor++; \
+ while (0)
+
+/* Occurrences table.
+
+ The `keyword' pointer provides the central word, which is surrounded
+ by a left context and a right context. The `keyword' and `length'
+ field allow full 8-bit characters keys, even including NULs. At other
+ places in this program, the name `keyafter' refers to the keyword
+ followed by its right context.
+
+ The left context does not extend, towards the beginning of the file,
+ further than a distance given by the `left' value. This value is
+ relative to the keyword beginning, it is usually negative. This
+ insures that, except for white space, we will never have to backward
+ scan the source text, when it is time to generate the final output
+ lines.
+
+ The right context, indirectly attainable through the keyword end, does
+ not extend, towards the end of the file, further than a distance given
+ by the `right' value. This value is relative to the keyword
+ beginning, it is usually positive.
+
+ When automatic references are used, the `reference' value is the
+ overall line number in all input files read so far, in this case, it
+ is of type (int). When input references are used, the `reference'
+ value indicates the distance between the keyword beginning and the
+ start of the reference field, it is of type (DELTA) and usually
+ negative. */
+
+typedef short DELTA; /* to hold displacement within one context */
+
+typedef struct
+ {
+ WORD key; /* description of the keyword */
+ DELTA left; /* distance to left context start */
+ DELTA right; /* distance to right context end */
+ int reference; /* reference descriptor */
+ }
+OCCURS;
+
+/* The various OCCURS tables are indexed by the language. But the time
+ being, there is no such multiple language support. */
+
+OCCURS *occurs_table[1]; /* all words retained from the read text */
+size_t number_of_occurs[1]; /* number of used slots in occurs_table */
+
+#define ALLOC_NEW_OCCURS(language) \
+ BUMP_ALLOC (occurs_table[language], number_of_occurs[language], 9, OCCURS)
+
+
+/* Communication among output routines. */
+
+/* Indicate if special output processing is requested for each character. */
+char edited_flag[CHAR_SET_SIZE];
+
+int half_line_width; /* half of line width, reference excluded */
+int before_max_width; /* maximum width of before field */
+int keyafter_max_width; /* maximum width of keyword-and-after field */
+int truncation_string_length; /* length of string used to flag truncation */
+
+/* When context is limited by lines, wraparound may happen on final output:
+ the `head' pointer gives access to some supplementary left context which
+ will be seen at the end of the output line, the `tail' pointer gives
+ access to some supplementary right context which will be seen at the
+ beginning of the output line. */
+
+BLOCK tail; /* tail field */
+int tail_truncation; /* flag truncation after the tail field */
+
+BLOCK before; /* before field */
+int before_truncation; /* flag truncation before the before field */
+
+BLOCK keyafter; /* keyword-and-after field */
+int keyafter_truncation; /* flag truncation after the keyafter field */
+
+BLOCK head; /* head field */
+int head_truncation; /* flag truncation before the head field */
+
+BLOCK reference; /* reference field for input reference mode */
+
+
+/* Miscellaneous routines. */
+
+/*------------------------------------------------------.
+| Duplicate string STRING, while evaluating \-escapes. |
+`------------------------------------------------------*/
+
+/* Loosely adapted from GNU shellutils printf.c code. */
+
+char *
+copy_unescaped_string (const char *string)
+{
+ char *result; /* allocated result */
+ char *cursor; /* cursor in result */
+ int value; /* value of \nnn escape */
+ int length; /* length of \nnn escape */
+
+ result = xmalloc (strlen (string) + 1);
+ cursor = result;
+
+ while (*string)
+ if (*string == '\\')
+ {
+ string++;
+ switch (*string)
+ {
+ case 'x': /* \xhhh escape, 3 chars maximum */
+ value = 0;
+ for (length = 0, string++;
+ length < 3 && ISXDIGIT (*string);
+ length++, string++)
+ value = value * 16 + HEXTOBIN (*string);
+ if (length == 0)
+ {
+ *cursor++ = '\\';
+ *cursor++ = 'x';
+ }
+ else
+ *cursor++ = value;
+ break;
+
+ case '0': /* \0ooo escape, 3 chars maximum */
+ value = 0;
+ for (length = 0, string++;
+ length < 3 && ISODIGIT (*string);
+ length++, string++)
+ value = value * 8 + OCTTOBIN (*string);
+ *cursor++ = value;
+ break;
+
+ case 'a': /* alert */
+#if __STDC__
+ *cursor++ = '\a';
+#else
+ *cursor++ = 7;
+#endif
+ string++;
+ break;
+
+ case 'b': /* backspace */
+ *cursor++ = '\b';
+ string++;
+ break;
+
+ case 'c': /* cancel the rest of the output */
+ while (*string)
+ string++;
+ break;
+
+ case 'f': /* form feed */
+ *cursor++ = '\f';
+ string++;
+ break;
+
+ case 'n': /* new line */
+ *cursor++ = '\n';
+ string++;
+ break;
+
+ case 'r': /* carriage return */
+ *cursor++ = '\r';
+ string++;
+ break;
+
+ case 't': /* horizontal tab */
+ *cursor++ = '\t';
+ string++;
+ break;
+
+ case 'v': /* vertical tab */
+#if __STDC__
+ *cursor++ = '\v';
+#else
+ *cursor++ = 11;
+#endif
+ string++;
+ break;
+
+ default:
+ *cursor++ = '\\';
+ *cursor++ = *string++;
+ break;
+ }
+ }
+ else
+ *cursor++ = *string++;
+
+ *cursor = '\0';
+ return result;
+}
+
+/*-------------------------------------------------------------------.
+| Compile the regex represented by STRING, diagnose and abort if any |
+| error. Returns the compiled regex structure. |
+`-------------------------------------------------------------------*/
+
+struct re_pattern_buffer *
+alloc_and_compile_regex (const char *string)
+{
+ struct re_pattern_buffer *pattern; /* newly allocated structure */
+ const char *message; /* error message returned by regex.c */
+
+ pattern = (struct re_pattern_buffer *)
+ xmalloc (sizeof (struct re_pattern_buffer));
+ memset (pattern, 0, sizeof (struct re_pattern_buffer));
+
+ pattern->buffer = NULL;
+ pattern->allocated = 0;
+ pattern->translate = ignore_case ? (char *) folded_chars : NULL;
+ pattern->fastmap = (char *) xmalloc (CHAR_SET_SIZE);
+
+ message = re_compile_pattern (string, strlen (string), pattern);
+ if (message)
+ error (1, 0, "%s (for regexp `%s')", message, string);
+
+ /* The fastmap should be compiled before `re_match'. The following
+ call is not mandatory, because `re_search' is always called sooner,
+ and it compiles the fastmap if this has not been done yet. */
+
+ re_compile_fastmap (pattern);
+
+ /* Do not waste extra allocated space. */
+
+ if (pattern->allocated > pattern->used)
+ {
+ pattern->buffer
+ = (unsigned char *) xrealloc (pattern->buffer, pattern->used);
+ pattern->allocated = pattern->used;
+ }
+
+ return pattern;
+}
+
+/*------------------------------------------------------------------------.
+| This will initialize various tables for pattern match and compiles some |
+| regexps. |
+`------------------------------------------------------------------------*/
+
+void
+initialize_regex (void)
+{
+ int character; /* character value */
+
+ /* Initialize the regex syntax table. */
+
+ for (character = 0; character < CHAR_SET_SIZE; character++)
+ syntax_table[character] = isalpha (character) ? Sword : 0;
+
+ /* Initialize the case folding table. */
+
+ if (ignore_case)
+ for (character = 0; character < CHAR_SET_SIZE; character++)
+ folded_chars[character] = toupper (character);
+
+ /* Unless the user already provided a description of the end of line or
+ end of sentence sequence, select an end of line sequence to compile.
+ If the user provided an empty definition, thus disabling end of line
+ or sentence feature, make it NULL to speed up tests. If GNU
+ extensions are enabled, use end of sentence like in GNU emacs. If
+ disabled, use end of lines. */
+
+ if (context_regex_string)
+ {
+ if (!*context_regex_string)
+ context_regex_string = NULL;
+ }
+ else if (gnu_extensions && !input_reference)
+ context_regex_string = "[.?!][]\"')}]*\\($\\|\t\\| \\)[ \t\n]*";
+ else
+ context_regex_string = "\n";
+
+ if (context_regex_string)
+ context_regex = alloc_and_compile_regex (context_regex_string);
+
+ /* If the user has already provided a non-empty regexp to describe
+ words, compile it. Else, unless this has already been done through
+ a user provided Break character file, construct a fastmap of
+ characters that may appear in a word. If GNU extensions enabled,
+ include only letters of the underlying character set. If disabled,
+ include almost everything, even punctuations; stop only on white
+ space. */
+
+ if (word_regex_string && *word_regex_string)
+ word_regex = alloc_and_compile_regex (word_regex_string);
+ else if (!break_file)
+ if (gnu_extensions)
+ {
+
+ /* Simulate \w+. */
+
+ for (character = 0; character < CHAR_SET_SIZE; character++)
+ word_fastmap[character] = isalpha (character);
+ }
+ else
+ {
+
+ /* Simulate [^ \t\n]+. */
+
+ memset (word_fastmap, 1, CHAR_SET_SIZE);
+ word_fastmap[' '] = 0;
+ word_fastmap['\t'] = 0;
+ word_fastmap['\n'] = 0;
+ }
+}
+
+/*------------------------------------------------------------------------.
+| This routine will attempt to swallow a whole file name FILE_NAME into a |
+| contiguous region of memory and return a description of it into BLOCK. |
+| Standard input is assumed whenever FILE_NAME is NULL, empty or "-". |
+| |
+| Previously, in some cases, white space compression was attempted while |
+| inputting text. This was defeating some regexps like default end of |
+| sentence, which checks for two consecutive spaces. If white space |
+| compression is ever reinstated, it should be in output routines. |
+`------------------------------------------------------------------------*/
+
+void
+swallow_file_in_memory (const char *file_name, BLOCK *block)
+{
+ int file_handle; /* file descriptor number */
+ struct stat stat_block; /* stat block for file */
+ int allocated_length; /* allocated length of memory buffer */
+ int used_length; /* used length in memory buffer */
+ int read_length; /* number of character gotten on last read */
+
+ /* As special cases, a file name which is NULL or "-" indicates standard
+ input, which is already opened. In all other cases, open the file from
+ its name. */
+
+ if (!file_name || !*file_name || strcmp (file_name, "-") == 0)
+ file_handle = fileno (stdin);
+ else
+ if ((file_handle = open (file_name, O_RDONLY)) < 0)
+ error (1, errno, file_name);
+
+ /* If the file is a plain, regular file, allocate the memory buffer all at
+ once and swallow the file in one blow. In other cases, read the file
+ repeatedly in smaller chunks until we have it all, reallocating memory
+ once in a while, as we go. */
+
+ if (fstat (file_handle, &stat_block) < 0)
+ error (1, errno, file_name);
+
+ if (S_ISREG (stat_block.st_mode))
+ {
+ block->start = (char *) xmalloc ((int) stat_block.st_size);
+
+ if (read (file_handle, block->start, (int) stat_block.st_size)
+ != stat_block.st_size)
+ error (1, errno, file_name);
+
+ block->end = block->start + stat_block.st_size;
+ }
+ else
+ {
+ block->start = (char *) xmalloc (1 << SWALLOW_REALLOC_LOG);
+ used_length = 0;
+ allocated_length = (1 << SWALLOW_REALLOC_LOG);
+
+ while ((read_length = read (file_handle,
+ block->start + used_length,
+ allocated_length - used_length)) > 0)
+ {
+ used_length += read_length;
+ if (used_length == allocated_length)
+ {
+ allocated_length += (1 << SWALLOW_REALLOC_LOG);
+ block->start
+ = (char *) xrealloc (block->start, allocated_length);
+ }
+ }
+
+ if (read_length < 0)
+ error (1, errno, file_name);
+
+ block->end = block->start + used_length;
+ }
+
+ /* Close the file, but only if it was not the standard input. */
+
+ if (file_handle != fileno (stdin))
+ close (file_handle);
+}
+
+/* Sort and search routines. */
+
+/*--------------------------------------------------------------------------.
+| Compare two words, FIRST and SECOND, and return 0 if they are identical. |
+| Return less than 0 if the first word goes before the second; return |
+| greater than 0 if the first word goes after the second. |
+| |
+| If a word is indeed a prefix of the other, the shorter should go first. |
+`--------------------------------------------------------------------------*/
+
+int
+compare_words (const void *void_first, const void *void_second)
+{
+#define first ((WORD *) void_first)
+#define second ((WORD *) void_second)
+ int length; /* minimum of two lengths */
+ int counter; /* cursor in words */
+ int value; /* value of comparison */
+
+ length = first->size < second->size ? first->size : second->size;
+
+ if (ignore_case)
+ {
+ for (counter = 0; counter < length; counter++)
+ {
+ value = (folded_chars [(unsigned char) (first->start[counter])]
+ - folded_chars [(unsigned char) (second->start[counter])]);
+ if (value != 0)
+ return value;
+ }
+ }
+ else
+ {
+ for (counter = 0; counter < length; counter++)
+ {
+ value = ((unsigned char) first->start[counter]
+ - (unsigned char) second->start[counter]);
+ if (value != 0)
+ return value;
+ }
+ }
+
+ return first->size - second->size;
+#undef first
+#undef second
+}
+
+/*-----------------------------------------------------------------------.
+| Decides which of two OCCURS, FIRST or SECOND, should lexicographically |
+| go first. In case of a tie, preserve the original order through a |
+| pointer comparison. |
+`-----------------------------------------------------------------------*/
+
+int
+compare_occurs (const void *void_first, const void *void_second)
+{
+#define first ((OCCURS *) void_first)
+#define second ((OCCURS *) void_second)
+ int value;
+
+ value = compare_words (&first->key, &second->key);
+ return value == 0 ? first->key.start - second->key.start : value;
+#undef first
+#undef second
+}
+
+/*------------------------------------------------------------.
+| Return !0 if WORD appears in TABLE. Uses a binary search. |
+`------------------------------------------------------------*/
+
+int
+search_table (WORD *word, WORD_TABLE *table)
+{
+ int lowest; /* current lowest possible index */
+ int highest; /* current highest possible index */
+ int middle; /* current middle index */
+ int value; /* value from last comparison */
+
+ lowest = 0;
+ highest = table->length - 1;
+ while (lowest <= highest)
+ {
+ middle = (lowest + highest) / 2;
+ value = compare_words (word, table->start + middle);
+ if (value < 0)
+ highest = middle - 1;
+ else if (value > 0)
+ lowest = middle + 1;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------.
+| Sort the whole occurs table in memory. Presumably, `qsort' does not |
+| take intermediate copies or table elements, so the sort will be |
+| stabilized throughout the comparison routine. |
+`---------------------------------------------------------------------*/
+
+void
+sort_found_occurs (void)
+{
+
+ /* Only one language for the time being. */
+
+ qsort (occurs_table[0], number_of_occurs[0], sizeof (OCCURS),
+ compare_occurs);
+}
+
+/* Parameter files reading routines. */
+
+/*----------------------------------------------------------------------.
+| Read a file named FILE_NAME, containing a set of break characters. |
+| Build a content to the array word_fastmap in which all characters are |
+| allowed except those found in the file. Characters may be repeated. |
+`----------------------------------------------------------------------*/
+
+void
+digest_break_file (const char *file_name)
+{
+ BLOCK file_contents; /* to receive a copy of the file */
+ char *cursor; /* cursor in file copy */
+
+ swallow_file_in_memory (file_name, &file_contents);
+
+ /* Make the fastmap and record the file contents in it. */
+
+ memset (word_fastmap, 1, CHAR_SET_SIZE);
+ for (cursor = file_contents.start; cursor < file_contents.end; cursor++)
+ word_fastmap[(unsigned char) *cursor] = 0;
+
+ if (!gnu_extensions)
+ {
+
+ /* If GNU extensions are enabled, the only way to avoid newline as
+ a break character is to write all the break characters in the
+ file with no newline at all, not even at the end of the file.
+ If disabled, spaces, tabs and newlines are always considered as
+ break characters even if not included in the break file. */
+
+ word_fastmap[' '] = 0;
+ word_fastmap['\t'] = 0;
+ word_fastmap['\n'] = 0;
+ }
+
+ /* Return the space of the file, which is no more required. */
+
+ free (file_contents.start);
+}
+
+/*-----------------------------------------------------------------------.
+| Read a file named FILE_NAME, containing one word per line, then |
+| construct in TABLE a table of WORD descriptors for them. The routine |
+| swallows the whole file in memory; this is at the expense of space |
+| needed for newlines, which are useless; however, the reading is fast. |
+`-----------------------------------------------------------------------*/
+
+void
+digest_word_file (const char *file_name, WORD_TABLE *table)
+{
+ BLOCK file_contents; /* to receive a copy of the file */
+ char *cursor; /* cursor in file copy */
+ char *word_start; /* start of the current word */
+
+ swallow_file_in_memory (file_name, &file_contents);
+
+ table->start = NULL;
+ table->length = 0;
+
+ /* Read the whole file. */
+
+ cursor = file_contents.start;
+ while (cursor < file_contents.end)
+ {
+
+ /* Read one line, and save the word in contains. */
+
+ word_start = cursor;
+ while (cursor < file_contents.end && *cursor != '\n')
+ cursor++;
+
+ /* Record the word in table if it is not empty. */
+
+ if (cursor > word_start)
+ {
+ ALLOC_NEW_WORD (table);
+ table->start[table->length].start = word_start;
+ table->start[table->length].size = cursor - word_start;
+ table->length++;
+ }
+
+ /* This test allows for an incomplete line at end of file. */
+
+ if (cursor < file_contents.end)
+ cursor++;
+ }
+
+ /* Finally, sort all the words read. */
+
+ qsort (table->start, table->length, (size_t) sizeof (WORD), compare_words);
+}
+
+
+/* Keyword recognition and selection. */
+
+/*----------------------------------------------------------------------.
+| For each keyword in the source text, constructs an OCCURS structure. |
+`----------------------------------------------------------------------*/
+
+void
+find_occurs_in_text (void)
+{
+ char *cursor; /* for scanning the source text */
+ char *scan; /* for scanning the source text also */
+ char *line_start; /* start of the current input line */
+ char *line_scan; /* newlines scanned until this point */
+ int reference_length; /* length of reference in input mode */
+ WORD possible_key; /* possible key, to ease searches */
+ OCCURS *occurs_cursor; /* current OCCURS under construction */
+
+ char *context_start; /* start of left context */
+ char *context_end; /* end of right context */
+ char *word_start; /* start of word */
+ char *word_end; /* end of word */
+ char *next_context_start; /* next start of left context */
+
+ /* reference_length is always used within `if (input_reference)'.
+ However, GNU C diagnoses that it may be used uninitialized. The
+ following assignment is merely to shut it up. */
+
+ reference_length = 0;
+
+ /* Tracking where lines start is helpful for reference processing. In
+ auto reference mode, this allows counting lines. In input reference
+ mode, this permits finding the beginning of the references.
+
+ The first line begins with the file, skip immediately this very first
+ reference in input reference mode, to help further rejection any word
+ found inside it. Also, unconditionally assigning these variable has
+ the happy effect of shutting up lint. */
+
+ line_start = text_buffer.start;
+ line_scan = line_start;
+ if (input_reference)
+ {
+ SKIP_NON_WHITE (line_scan, text_buffer.end);
+ reference_length = line_scan - line_start;
+ SKIP_WHITE (line_scan, text_buffer.end);
+ }
+
+ /* Process the whole buffer, one line or one sentence at a time. */
+
+ for (cursor = text_buffer.start;
+ cursor < text_buffer.end;
+ cursor = next_context_start)
+ {
+
+ /* `context_start' gets initialized before the processing of each
+ line, or once for the whole buffer if no end of line or sentence
+ sequence separator. */
+
+ context_start = cursor;
+
+ /* If a end of line or end of sentence sequence is defined and
+ non-empty, `next_context_start' will be recomputed to be the end of
+ each line or sentence, before each one is processed. If no such
+ sequence, then `next_context_start' is set at the end of the whole
+ buffer, which is then considered to be a single line or sentence.
+ This test also accounts for the case of an incomplete line or
+ sentence at the end of the buffer. */
+
+ if (context_regex_string
+ && (re_search (context_regex, cursor, text_buffer.end - cursor,
+ 0, text_buffer.end - cursor, &context_regs)
+ >= 0))
+ next_context_start = cursor + context_regs.end[0];
+
+ else
+ next_context_start = text_buffer.end;
+
+ /* Include the separator into the right context, but not any suffix
+ white space in this separator; this insures it will be seen in
+ output and will not take more space than necessary. */
+
+ context_end = next_context_start;
+ SKIP_WHITE_BACKWARDS (context_end, context_start);
+
+ /* Read and process a single input line or sentence, one word at a
+ time. */
+
+ while (1)
+ {
+ if (word_regex)
+
+ /* If a word regexp has been compiled, use it to skip at the
+ beginning of the next word. If there is no such word, exit
+ the loop. */
+
+ {
+ if (re_search (word_regex, cursor, context_end - cursor,
+ 0, context_end - cursor, &word_regs)
+ < 0)
+ break;
+ word_start = cursor + word_regs.start[0];
+ word_end = cursor + word_regs.end[0];
+ }
+ else
+
+ /* Avoid re_search and use the fastmap to skip to the
+ beginning of the next word. If there is no more word in
+ the buffer, exit the loop. */
+
+ {
+ scan = cursor;
+ while (scan < context_end
+ && !word_fastmap[(unsigned char) *scan])
+ scan++;
+
+ if (scan == context_end)
+ break;
+
+ word_start = scan;
+
+ while (scan < context_end
+ && word_fastmap[(unsigned char) *scan])
+ scan++;
+
+ word_end = scan;
+ }
+
+ /* Skip right to the beginning of the found word. */
+
+ cursor = word_start;
+
+ /* Skip any zero length word. Just advance a single position,
+ then go fetch the next word. */
+
+ if (word_end == word_start)
+ {
+ cursor++;
+ continue;
+ }
+
+ /* This is a genuine, non empty word, so save it as a possible
+ key. Then skip over it. Also, maintain the maximum length of
+ all words read so far. It is mandatory to take the maximum
+ length of all words in the file, without considering if they
+ are actually kept or rejected, because backward jumps at output
+ generation time may fall in *any* word. */
+
+ possible_key.start = cursor;
+ possible_key.size = word_end - word_start;
+ cursor += possible_key.size;
+
+ if (possible_key.size > maximum_word_length)
+ maximum_word_length = possible_key.size;
+
+ /* In input reference mode, update `line_start' from its previous
+ value. Count the lines just in case auto reference mode is
+ also selected. If it happens that the word just matched is
+ indeed part of a reference; just ignore it. */
+
+ if (input_reference)
+ {
+ while (line_scan < possible_key.start)
+ if (*line_scan == '\n')
+ {
+ total_line_count++;
+ line_scan++;
+ line_start = line_scan;
+ SKIP_NON_WHITE (line_scan, text_buffer.end);
+ reference_length = line_scan - line_start;
+ }
+ else
+ line_scan++;
+ if (line_scan > possible_key.start)
+ continue;
+ }
+
+ /* Ignore the word if an `Ignore words' table exists and if it is
+ part of it. Also ignore the word if an `Only words' table and
+ if it is *not* part of it.
+
+ It is allowed that both tables be used at once, even if this
+ may look strange for now. Just ignore a word that would appear
+ in both. If regexps are eventually implemented for these
+ tables, the Ignore table could then reject words that would
+ have been previously accepted by the Only table. */
+
+ if (ignore_file && search_table (&possible_key, &ignore_table))
+ continue;
+ if (only_file && !search_table (&possible_key, &only_table))
+ continue;
+
+ /* A non-empty word has been found. First of all, insure
+ proper allocation of the next OCCURS, and make a pointer to
+ where it will be constructed. */
+
+ ALLOC_NEW_OCCURS (0);
+ occurs_cursor = occurs_table[0] + number_of_occurs[0];
+
+ /* Define the refence field, if any. */
+
+ if (auto_reference)
+ {
+
+ /* While auto referencing, update `line_start' from its
+ previous value, counting lines as we go. If input
+ referencing at the same time, `line_start' has been
+ advanced earlier, and the following loop is never really
+ executed. */
+
+ while (line_scan < possible_key.start)
+ if (*line_scan == '\n')
+ {
+ total_line_count++;
+ line_scan++;
+ line_start = line_scan;
+ SKIP_NON_WHITE (line_scan, text_buffer.end);
+ }
+ else
+ line_scan++;
+
+ occurs_cursor->reference = total_line_count;
+ }
+ else if (input_reference)
+ {
+
+ /* If only input referencing, `line_start' has been computed
+ earlier to detect the case the word matched would be part
+ of the reference. The reference position is simply the
+ value of `line_start'. */
+
+ occurs_cursor->reference
+ = (DELTA) (line_start - possible_key.start);
+ if (reference_length > reference_max_width)
+ reference_max_width = reference_length;
+ }
+
+ /* Exclude the reference from the context in simple cases. */
+
+ if (input_reference && line_start == context_start)
+ {
+ SKIP_NON_WHITE (context_start, context_end);
+ SKIP_WHITE (context_start, context_end);
+ }
+
+ /* Completes the OCCURS structure. */
+
+ occurs_cursor->key = possible_key;
+ occurs_cursor->left = context_start - possible_key.start;
+ occurs_cursor->right = context_end - possible_key.start;
+
+ number_of_occurs[0]++;
+ }
+ }
+}
+
+/* Formatting and actual output - service routines. */
+
+/*-----------------------------------------.
+| Prints some NUMBER of spaces on stdout. |
+`-----------------------------------------*/
+
+void
+print_spaces (int number)
+{
+ int counter;
+
+ for (counter = number; counter > 0; counter--)
+ putchar (' ');
+}
+
+/*-------------------------------------.
+| Prints the field provided by FIELD. |
+`-------------------------------------*/
+
+void
+print_field (BLOCK field)
+{
+ char *cursor; /* Cursor in field to print */
+ int character; /* Current character */
+ int base; /* Base character, without diacritic */
+ int diacritic; /* Diacritic code for the character */
+
+ /* Whitespace is not really compressed. Instead, each white space
+ character (tab, vt, ht etc.) is printed as one single space. */
+
+ for (cursor = field.start; cursor < field.end; cursor++)
+ {
+ character = (unsigned char) *cursor;
+ if (edited_flag[character])
+ {
+
+ /* First check if this is a diacriticized character.
+
+ This works only for TeX. I do not know how diacriticized
+ letters work with `roff'. Please someone explain it to me! */
+
+ diacritic = todiac (character);
+ if (diacritic != 0 && output_format == TEX_FORMAT)
+ {
+ base = tobase (character);
+ switch (diacritic)
+ {
+
+ case 1: /* Latin diphthongs */
+ switch (base)
+ {
+ case 'o':
+ printf ("\\oe{}");
+ break;
+
+ case 'O':
+ printf ("\\OE{}");
+ break;
+
+ case 'a':
+ printf ("\\ae{}");
+ break;
+
+ case 'A':
+ printf ("\\AE{}");
+ break;
+
+ default:
+ putchar (' ');
+ }
+ break;
+
+ case 2: /* Acute accent */
+ printf ("\\'%s%c", (base == 'i' ? "\\" : ""), base);
+ break;
+
+ case 3: /* Grave accent */
+ printf ("\\`%s%c", (base == 'i' ? "\\" : ""), base);
+ break;
+
+ case 4: /* Circumflex accent */
+ printf ("\\^%s%c", (base == 'i' ? "\\" : ""), base);
+ break;
+
+ case 5: /* Diaeresis */
+ printf ("\\\"%s%c", (base == 'i' ? "\\" : ""), base);
+ break;
+
+ case 6: /* Tilde accent */
+ printf ("\\~%s%c", (base == 'i' ? "\\" : ""), base);
+ break;
+
+ case 7: /* Cedilla */
+ printf ("\\c{%c}", base);
+ break;
+
+ case 8: /* Small circle beneath */
+ switch (base)
+ {
+ case 'a':
+ printf ("\\aa{}");
+ break;
+
+ case 'A':
+ printf ("\\AA{}");
+ break;
+
+ default:
+ putchar (' ');
+ }
+ break;
+
+ case 9: /* Strike through */
+ switch (base)
+ {
+ case 'o':
+ printf ("\\o{}");
+ break;
+
+ case 'O':
+ printf ("\\O{}");
+ break;
+
+ default:
+ putchar (' ');
+ }
+ break;
+ }
+ }
+ else
+
+ /* This is not a diacritic character, so handle cases which are
+ really specific to `roff' or TeX. All white space processing
+ is done as the default case of this switch. */
+
+ switch (character)
+ {
+ case '"':
+ /* In roff output format, double any quote. */
+ putchar ('"');
+ putchar ('"');
+ break;
+
+ case '$':
+ case '%':
+ case '&':
+ case '#':
+ case '_':
+ /* In TeX output format, precede these with a backslash. */
+ putchar ('\\');
+ putchar (character);
+ break;
+
+ case '{':
+ case '}':
+ /* In TeX output format, precede these with a backslash and
+ force mathematical mode. */
+ printf ("$\\%c$", character);
+ break;
+
+ case '\\':
+ /* In TeX output mode, request production of a backslash. */
+ printf ("\\backslash{}");
+ break;
+
+ default:
+ /* Any other flagged character produces a single space. */
+ putchar (' ');
+ }
+ }
+ else
+ putchar (*cursor);
+ }
+}
+
+
+/* Formatting and actual output - planning routines. */
+
+/*--------------------------------------------------------------------.
+| From information collected from command line options and input file |
+| readings, compute and fix some output parameter values. |
+`--------------------------------------------------------------------*/
+
+void
+fix_output_parameters (void)
+{
+ int file_index; /* index in text input file arrays */
+ int line_ordinal; /* line ordinal value for reference */
+ char ordinal_string[12]; /* edited line ordinal for reference */
+ int reference_width; /* width for the whole reference */
+ int character; /* character ordinal */
+ const char *cursor; /* cursor in some constant strings */
+
+ /* In auto reference mode, the maximum width of this field is
+ precomputed and subtracted from the overall line width. Add one for
+ the column which separate the file name from the line number. */
+
+ if (auto_reference)
+ {
+ reference_max_width = 0;
+ for (file_index = 0; file_index < number_input_files; file_index++)
+ {
+ line_ordinal = file_line_count[file_index] + 1;
+ if (file_index > 0)
+ line_ordinal -= file_line_count[file_index - 1];
+ sprintf (ordinal_string, "%d", line_ordinal);
+ reference_width = strlen (ordinal_string);
+ if (input_file_name[file_index])
+ reference_width += strlen (input_file_name[file_index]);
+ if (reference_width > reference_max_width)
+ reference_max_width = reference_width;
+ }
+ reference_max_width++;
+ reference.start = (char *) xmalloc (reference_max_width + 1);
+ }
+
+ /* If the reference appears to the left of the output line, reserve some
+ space for it right away, including one gap size. */
+
+ if ((auto_reference || input_reference) && !right_reference)
+ line_width -= reference_max_width + gap_size;
+
+ /* The output lines, minimally, will contain from left to right a left
+ context, a gap, and a keyword followed by the right context with no
+ special intervening gap. Half of the line width is dedicated to the
+ left context and the gap, the other half is dedicated to the keyword
+ and the right context; these values are computed once and for all here.
+ There also are tail and head wrap around fields, used when the keyword
+ is near the beginning or the end of the line, or when some long word
+ cannot fit in, but leave place from wrapped around shorter words. The
+ maximum width of these fields are recomputed separately for each line,
+ on a case by case basis. It is worth noting that it cannot happen that
+ both the tail and head fields are used at once. */
+
+ half_line_width = line_width / 2;
+ before_max_width = half_line_width - gap_size;
+ keyafter_max_width = half_line_width;
+
+ /* If truncation_string is the empty string, make it NULL to speed up
+ tests. In this case, truncation_string_length will never get used, so
+ there is no need to set it. */
+
+ if (truncation_string && *truncation_string)
+ truncation_string_length = strlen (truncation_string);
+ else
+ truncation_string = NULL;
+
+ if (gnu_extensions)
+ {
+
+ /* When flagging truncation at the left of the keyword, the
+ truncation mark goes at the beginning of the before field,
+ unless there is a head field, in which case the mark goes at the
+ left of the head field. When flagging truncation at the right
+ of the keyword, the mark goes at the end of the keyafter field,
+ unless there is a tail field, in which case the mark goes at the
+ end of the tail field. Only eight combination cases could arise
+ for truncation marks:
+
+ . None.
+ . One beginning the before field.
+ . One beginning the head field.
+ . One ending the keyafter field.
+ . One ending the tail field.
+ . One beginning the before field, another ending the keyafter field.
+ . One ending the tail field, another beginning the before field.
+ . One ending the keyafter field, another beginning the head field.
+
+ So, there is at most two truncation marks, which could appear both
+ on the left side of the center of the output line, both on the
+ right side, or one on either side. */
+
+ before_max_width -= 2 * truncation_string_length;
+ keyafter_max_width -= 2 * truncation_string_length;
+ }
+ else
+ {
+
+ /* I never figured out exactly how UNIX' ptx plans the output width
+ of its various fields. If GNU extensions are disabled, do not
+ try computing the field widths correctly; instead, use the
+ following formula, which does not completely imitate UNIX' ptx,
+ but almost. */
+
+ keyafter_max_width -= 2 * truncation_string_length + 1;
+ }
+
+ /* Compute which characters need special output processing. Initialize
+ by flagging any white space character. Some systems do not consider
+ form feed as a space character, but we do. */
+
+ for (character = 0; character < CHAR_SET_SIZE; character++)
+ edited_flag[character] = isspace (character);
+ edited_flag['\f'] = 1;
+
+ /* Complete the special character flagging according to selected output
+ format. */
+
+ switch (output_format)
+ {
+ case UNKNOWN_FORMAT:
+ /* Should never happen. */
+
+ case DUMB_FORMAT:
+ break;
+
+ case ROFF_FORMAT:
+
+ /* `Quote' characters should be doubled. */
+
+ edited_flag['"'] = 1;
+ break;
+
+ case TEX_FORMAT:
+
+ /* Various characters need special processing. */
+
+ for (cursor = "$%&#_{}\\"; *cursor; cursor++)
+ edited_flag[*cursor] = 1;
+
+ /* Any character with 8th bit set will print to a single space, unless
+ it is diacriticized. */
+
+ for (character = 0200; character < CHAR_SET_SIZE; character++)
+ edited_flag[character] = todiac (character) != 0;
+ break;
+ }
+}
+
+/*------------------------------------------------------------------.
+| Compute the position and length of all the output fields, given a |
+| pointer to some OCCURS. |
+`------------------------------------------------------------------*/
+
+void
+define_all_fields (OCCURS *occurs)
+{
+ int tail_max_width; /* allowable width of tail field */
+ int head_max_width; /* allowable width of head field */
+ char *cursor; /* running cursor in source text */
+ char *left_context_start; /* start of left context */
+ char *right_context_end; /* end of right context */
+ char *left_field_start; /* conservative start for `head'/`before' */
+ int file_index; /* index in text input file arrays */
+ const char *file_name; /* file name for reference */
+ int line_ordinal; /* line ordinal for reference */
+
+ /* Define `keyafter', start of left context and end of right context.
+ `keyafter' starts at the saved position for keyword and extend to the
+ right from the end of the keyword, eating separators or full words, but
+ not beyond maximum allowed width for `keyafter' field or limit for the
+ right context. Suffix spaces will be removed afterwards. */
+
+ keyafter.start = occurs->key.start;
+ keyafter.end = keyafter.start + occurs->key.size;
+ left_context_start = keyafter.start + occurs->left;
+ right_context_end = keyafter.start + occurs->right;
+
+ cursor = keyafter.end;
+ while (cursor < right_context_end
+ && cursor <= keyafter.start + keyafter_max_width)
+ {
+ keyafter.end = cursor;
+ SKIP_SOMETHING (cursor, right_context_end);
+ }
+ if (cursor <= keyafter.start + keyafter_max_width)
+ keyafter.end = cursor;
+
+ keyafter_truncation = truncation_string && keyafter.end < right_context_end;
+
+ SKIP_WHITE_BACKWARDS (keyafter.end, keyafter.start);
+
+ /* When the left context is wide, it might take some time to catch up from
+ the left context boundary to the beginning of the `head' or `before'
+ fields. So, in this case, to speed the catchup, we jump back from the
+ keyword, using some secure distance, possibly falling in the middle of
+ a word. A secure backward jump would be at least half the maximum
+ width of a line, plus the size of the longest word met in the whole
+ input. We conclude this backward jump by a skip forward of at least
+ one word. In this manner, we should not inadvertently accept only part
+ of a word. From the reached point, when it will be time to fix the
+ beginning of `head' or `before' fields, we will skip forward words or
+ delimiters until we get sufficiently near. */
+
+ if (-occurs->left > half_line_width + maximum_word_length)
+ {
+ left_field_start
+ = keyafter.start - (half_line_width + maximum_word_length);
+ SKIP_SOMETHING (left_field_start, keyafter.start);
+ }
+ else
+ left_field_start = keyafter.start + occurs->left;
+
+ /* `before' certainly ends at the keyword, but not including separating
+ spaces. It starts after than the saved value for the left context, by
+ advancing it until it falls inside the maximum allowed width for the
+ before field. There will be no prefix spaces either. `before' only
+ advances by skipping single separators or whole words. */
+
+ before.start = left_field_start;
+ before.end = keyafter.start;
+ SKIP_WHITE_BACKWARDS (before.end, before.start);
+
+ while (before.start + before_max_width < before.end)
+ SKIP_SOMETHING (before.start, before.end);
+
+ if (truncation_string)
+ {
+ cursor = before.start;
+ SKIP_WHITE_BACKWARDS (cursor, text_buffer.start);
+ before_truncation = cursor > left_context_start;
+ }
+ else
+ before_truncation = 0;
+
+ SKIP_WHITE (before.start, text_buffer.end);
+
+ /* The tail could not take more columns than what has been left in the
+ left context field, and a gap is mandatory. It starts after the
+ right context, and does not contain prefixed spaces. It ends at
+ the end of line, the end of buffer or when the tail field is full,
+ whichever comes first. It cannot contain only part of a word, and
+ has no suffixed spaces. */
+
+ tail_max_width
+ = before_max_width - (before.end - before.start) - gap_size;
+
+ if (tail_max_width > 0)
+ {
+ tail.start = keyafter.end;
+ SKIP_WHITE (tail.start, text_buffer.end);
+
+ tail.end = tail.start;
+ cursor = tail.end;
+ while (cursor < right_context_end
+ && cursor < tail.start + tail_max_width)
+ {
+ tail.end = cursor;
+ SKIP_SOMETHING (cursor, right_context_end);
+ }
+
+ if (cursor < tail.start + tail_max_width)
+ tail.end = cursor;
+
+ if (tail.end > tail.start)
+ {
+ keyafter_truncation = 0;
+ tail_truncation = truncation_string && tail.end < right_context_end;
+ }
+ else
+ tail_truncation = 0;
+
+ SKIP_WHITE_BACKWARDS (tail.end, tail.start);
+ }
+ else
+ {
+
+ /* No place left for a tail field. */
+
+ tail.start = NULL;
+ tail.end = NULL;
+ tail_truncation = 0;
+ }
+
+ /* `head' could not take more columns than what has been left in the right
+ context field, and a gap is mandatory. It ends before the left
+ context, and does not contain suffixed spaces. Its pointer is advanced
+ until the head field has shrunk to its allowed width. It cannot
+ contain only part of a word, and has no suffixed spaces. */
+
+ head_max_width
+ = keyafter_max_width - (keyafter.end - keyafter.start) - gap_size;
+
+ if (head_max_width > 0)
+ {
+ head.end = before.start;
+ SKIP_WHITE_BACKWARDS (head.end, text_buffer.start);
+
+ head.start = left_field_start;
+ while (head.start + head_max_width < head.end)
+ SKIP_SOMETHING (head.start, head.end);
+
+ if (head.end > head.start)
+ {
+ before_truncation = 0;
+ head_truncation = (truncation_string
+ && head.start > left_context_start);
+ }
+ else
+ head_truncation = 0;
+
+ SKIP_WHITE (head.start, head.end);
+ }
+ else
+ {
+
+ /* No place left for a head field. */
+
+ head.start = NULL;
+ head.end = NULL;
+ head_truncation = 0;
+ }
+
+ if (auto_reference)
+ {
+
+ /* Construct the reference text in preallocated space from the file
+ name and the line number. Find out in which file the reference
+ occurred. Standard input yields an empty file name. Insure line
+ numbers are one based, even if they are computed zero based. */
+
+ file_index = 0;
+ while (file_line_count[file_index] < occurs->reference)
+ file_index++;
+
+ file_name = input_file_name[file_index];
+ if (!file_name)
+ file_name = "";
+
+ line_ordinal = occurs->reference + 1;
+ if (file_index > 0)
+ line_ordinal -= file_line_count[file_index - 1];
+
+ sprintf (reference.start, "%s:%d", file_name, line_ordinal);
+ reference.end = reference.start + strlen (reference.start);
+ }
+ else if (input_reference)
+ {
+
+ /* Reference starts at saved position for reference and extends right
+ until some white space is met. */
+
+ reference.start = keyafter.start + (DELTA) occurs->reference;
+ reference.end = reference.start;
+ SKIP_NON_WHITE (reference.end, right_context_end);
+ }
+}
+
+
+/* Formatting and actual output - control routines. */
+
+/*----------------------------------------------------------------------.
+| Output the current output fields as one line for `troff' or `nroff'. |
+`----------------------------------------------------------------------*/
+
+void
+output_one_roff_line (void)
+{
+ /* Output the `tail' field. */
+
+ printf (".%s \"", macro_name);
+ print_field (tail);
+ if (tail_truncation)
+ printf ("%s", truncation_string);
+ putchar ('"');
+
+ /* Output the `before' field. */
+
+ printf (" \"");
+ if (before_truncation)
+ printf ("%s", truncation_string);
+ print_field (before);
+ putchar ('"');
+
+ /* Output the `keyafter' field. */
+
+ printf (" \"");
+ print_field (keyafter);
+ if (keyafter_truncation)
+ printf ("%s", truncation_string);
+ putchar ('"');
+
+ /* Output the `head' field. */
+
+ printf (" \"");
+ if (head_truncation)
+ printf ("%s", truncation_string);
+ print_field (head);
+ putchar ('"');
+
+ /* Conditionally output the `reference' field. */
+
+ if (auto_reference || input_reference)
+ {
+ printf (" \"");
+ print_field (reference);
+ putchar ('"');
+ }
+
+ putchar ('\n');
+}
+
+/*---------------------------------------------------------.
+| Output the current output fields as one line for `TeX'. |
+`---------------------------------------------------------*/
+
+void
+output_one_tex_line (void)
+{
+ BLOCK key; /* key field, isolated */
+ BLOCK after; /* after field, isolated */
+ char *cursor; /* running cursor in source text */
+
+ printf ("\\%s ", macro_name);
+ printf ("{");
+ print_field (tail);
+ printf ("}{");
+ print_field (before);
+ printf ("}{");
+ key.start = keyafter.start;
+ after.end = keyafter.end;
+ cursor = keyafter.start;
+ SKIP_SOMETHING (cursor, keyafter.end);
+ key.end = cursor;
+ after.start = cursor;
+ print_field (key);
+ printf ("}{");
+ print_field (after);
+ printf ("}{");
+ print_field (head);
+ printf ("}");
+ if (auto_reference || input_reference)
+ {
+ printf ("{");
+ print_field (reference);
+ printf ("}");
+ }
+ printf ("\n");
+}
+
+/*-------------------------------------------------------------------.
+| Output the current output fields as one line for a dumb terminal. |
+`-------------------------------------------------------------------*/
+
+void
+output_one_dumb_line (void)
+{
+ if (!right_reference)
+ if (auto_reference)
+ {
+
+ /* Output the `reference' field, in such a way that GNU emacs
+ next-error will handle it. The ending colon is taken from the
+ gap which follows. */
+
+ print_field (reference);
+ putchar (':');
+ print_spaces (reference_max_width
+ + gap_size
+ - (reference.end - reference.start)
+ - 1);
+ }
+ else
+ {
+
+ /* Output the `reference' field and its following gap. */
+
+ print_field (reference);
+ print_spaces (reference_max_width
+ + gap_size
+ - (reference.end - reference.start));
+ }
+
+ if (tail.start < tail.end)
+ {
+ /* Output the `tail' field. */
+
+ print_field (tail);
+ if (tail_truncation)
+ printf ("%s", truncation_string);
+
+ print_spaces (half_line_width - gap_size
+ - (before.end - before.start)
+ - (before_truncation ? truncation_string_length : 0)
+ - (tail.end - tail.start)
+ - (tail_truncation ? truncation_string_length : 0));
+ }
+ else
+ print_spaces (half_line_width - gap_size
+ - (before.end - before.start)
+ - (before_truncation ? truncation_string_length : 0));
+
+ /* Output the `before' field. */
+
+ if (before_truncation)
+ printf ("%s", truncation_string);
+ print_field (before);
+
+ print_spaces (gap_size);
+
+ /* Output the `keyafter' field. */
+
+ print_field (keyafter);
+ if (keyafter_truncation)
+ printf ("%s", truncation_string);
+
+ if (head.start < head.end)
+ {
+ /* Output the `head' field. */
+
+ print_spaces (half_line_width
+ - (keyafter.end - keyafter.start)
+ - (keyafter_truncation ? truncation_string_length : 0)
+ - (head.end - head.start)
+ - (head_truncation ? truncation_string_length : 0));
+ if (head_truncation)
+ printf ("%s", truncation_string);
+ print_field (head);
+ }
+ else
+
+ if ((auto_reference || input_reference) && right_reference)
+ print_spaces (half_line_width
+ - (keyafter.end - keyafter.start)
+ - (keyafter_truncation ? truncation_string_length : 0));
+
+ if ((auto_reference || input_reference) && right_reference)
+ {
+ /* Output the `reference' field. */
+
+ print_spaces (gap_size);
+ print_field (reference);
+ }
+
+ printf ("\n");
+}
+
+/*------------------------------------------------------------------------.
+| Scan the whole occurs table and, for each entry, output one line in the |
+| appropriate format. |
+`------------------------------------------------------------------------*/
+
+void
+generate_all_output (void)
+{
+ int occurs_index; /* index of keyword entry being processed */
+ OCCURS *occurs_cursor; /* current keyword entry being processed */
+
+
+ /* The following assignments are useful to provide default values in case
+ line contexts or references are not used, in which case these variables
+ would never be computed. */
+
+ tail.start = NULL;
+ tail.end = NULL;
+ tail_truncation = 0;
+
+ head.start = NULL;
+ head.end = NULL;
+ head_truncation = 0;
+
+
+ /* Loop over all keyword occurrences. */
+
+ occurs_cursor = occurs_table[0];
+
+ for (occurs_index = 0; occurs_index < number_of_occurs[0]; occurs_index++)
+ {
+ /* Compute the exact size of every field and whenever truncation flags
+ are present or not. */
+
+ define_all_fields (occurs_cursor);
+
+ /* Produce one output line according to selected format. */
+
+ switch (output_format)
+ {
+ case UNKNOWN_FORMAT:
+ /* Should never happen. */
+
+ case DUMB_FORMAT:
+ output_one_dumb_line ();
+ break;
+
+ case ROFF_FORMAT:
+ output_one_roff_line ();
+ break;
+
+ case TEX_FORMAT:
+ output_one_tex_line ();
+ break;
+ }
+
+ /* Advance the cursor into the occurs table. */
+
+ occurs_cursor++;
+ }
+}
+
+/* Option decoding and main program. */
+
+/*------------------------------------------------------.
+| Print program identification and options, then exit. |
+`------------------------------------------------------*/
+
+void
+usage (int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", program_name);
+ else
+ {
+ printf ("\
+Usage: %s [OPTION]... [INPUT]... (without -G)\n\
+ or: %s -G [OPTION]... [INPUT [OUTPUT]]\n", program_name, program_name);
+ printf ("\
+\n\
+ -A, --auto-reference output automatically generated references\n\
+ -C, --copyright display Copyright and copying conditions\n\
+ -G, --traditional behave more like System V `ptx'\n\
+ -F, --flag-truncation=STRING use STRING for flagging line truncations\n\
+ -M, --macro-name=STRING macro name to use instead of `xx'\n\
+ -O, --format=roff generate output as roff directives\n\
+ -R, --right-side-refs put references at right, not counted in -w\n\
+ -S, --sentence-regexp=REGEXP for end of lines or end of sentences\n\
+ -T, --format=tex generate output as TeX directives\n\
+ -W, --word-regexp=REGEXP use REGEXP to match each keyword\n\
+ -b, --break-file=FILE word break characters in this FILE\n\
+ -f, --ignore-case fold lower case to upper case for sorting\n\
+ -g, --gap-size=NUMBER gap size in columns between output fields\n\
+ -i, --ignore-file=FILE read ignore word list from FILE\n\
+ -o, --only-file=FILE read only word list from this FILE\n\
+ -r, --references first field of each line is a reference\n\
+ -t, --typeset-mode - not implemented -\n\
+ -w, --width=NUMBER output width in columns, reference excluded\n\
+ --help display this help and exit\n\
+ --version output version information and exit\n\
+\n\
+With no FILE or if FILE is -, read Standard Input. `-F /' by default.\n");
+ }
+ exit (status);
+}
+
+/*----------------------------------------------------------------------.
+| Main program. Decode ARGC arguments passed through the ARGV array of |
+| strings, then launch execution. |
+`----------------------------------------------------------------------*/
+
+/* Long options equivalences. */
+const struct option long_options[] =
+{
+ {"auto-reference", no_argument, NULL, 'A'},
+ {"break-file", required_argument, NULL, 'b'},
+ {"copyright", no_argument, NULL, 'C'},
+ {"flag-truncation", required_argument, NULL, 'F'},
+ {"ignore-case", no_argument, NULL, 'f'},
+ {"gap-size", required_argument, NULL, 'g'},
+ {"help", no_argument, &show_help, 1},
+ {"ignore-file", required_argument, NULL, 'i'},
+ {"macro-name", required_argument, NULL, 'M'},
+ {"only-file", required_argument, NULL, 'o'},
+ {"references", no_argument, NULL, 'r'},
+ {"right-side-refs", no_argument, NULL, 'R'},
+ {"format", required_argument, NULL, 10},
+ {"sentence-regexp", required_argument, NULL, 'S'},
+ {"traditional", no_argument, NULL, 'G'},
+ {"typeset-mode", no_argument, NULL, 't'},
+ {"version", no_argument, &show_version, 1},
+ {"width", required_argument, NULL, 'w'},
+ {"word-regexp", required_argument, NULL, 'W'},
+ {0, 0, 0, 0},
+};
+
+static char const* const format_args[] =
+{
+ "roff", "tex", 0
+};
+
+int
+main (int argc, char *const argv[])
+{
+ int optchar; /* argument character */
+ extern int optind; /* index of argument */
+ extern char *optarg; /* value or argument */
+ int file_index; /* index in text input file arrays */
+
+#ifdef HAVE_MCHECK
+ /* Use GNU malloc checking. It has proven to be useful! */
+ mcheck ();
+#endif /* HAVE_MCHECK */
+
+#ifdef STDC_HEADERS
+#ifdef HAVE_SETCHRCLASS
+ setchrclass (NULL);
+#endif
+#endif
+
+ /* Decode program options. */
+
+ program_name = argv[0];
+
+ while ((optchar = getopt_long (argc, argv, "ACF:GM:ORS:TW:b:i:fg:o:trw:",
+ long_options, NULL)),
+ optchar != EOF)
+ {
+ switch (optchar)
+ {
+ default:
+ usage (1);
+
+ case 0:
+ break;
+
+ case 'C':
+ printf ("%s", copyright);
+ exit (0);
+
+ case 'G':
+ gnu_extensions = 0;
+ break;
+
+ case 'b':
+ break_file = optarg;
+ break;
+
+ case 'f':
+ ignore_case = 1;
+ break;
+
+ case 'g':
+ gap_size = atoi (optarg);
+ break;
+
+ case 'i':
+ ignore_file = optarg;
+ break;
+
+ case 'o':
+ only_file = optarg;
+ break;
+
+ case 'r':
+ input_reference = 1;
+ break;
+
+ case 't':
+ /* A decouvrir... */
+ break;
+
+ case 'w':
+ line_width = atoi (optarg);
+ break;
+
+ case 'A':
+ auto_reference = 1;
+ break;
+
+ case 'F':
+ truncation_string = copy_unescaped_string (optarg);
+ break;
+
+ case 'M':
+ macro_name = optarg;
+ break;
+
+ case 'O':
+ output_format = ROFF_FORMAT;
+ break;
+
+ case 'R':
+ right_reference = 1;
+ break;
+
+ case 'S':
+ context_regex_string = copy_unescaped_string (optarg);
+ break;
+
+ case 'T':
+ output_format = TEX_FORMAT;
+ break;
+
+ case 'W':
+ word_regex_string = copy_unescaped_string (optarg);
+ break;
+
+ case 10:
+ switch (argmatch (optarg, format_args))
+ {
+ default:
+ usage (1);
+
+ case 0:
+ output_format = ROFF_FORMAT;
+ break;
+
+ case 1:
+ output_format = TEX_FORMAT;
+ break;
+ }
+ }
+ }
+
+ /* Process trivial options. */
+
+ if (show_help)
+ usage (0);
+
+ if (show_version)
+ {
+ printf ("%s\n", version_string);
+ exit (0);
+ }
+
+ /* Change the default Ignore file if one is defined. */
+
+#ifdef DEFAULT_IGNORE_FILE
+ if (!ignore_file)
+ ignore_file = DEFAULT_IGNORE_FILE;
+#endif
+
+ /* Process remaining arguments. If GNU extensions are enabled, process
+ all arguments as input parameters. If disabled, accept at most two
+ arguments, the second of which is an output parameter. */
+
+ if (optind == argc)
+ {
+
+ /* No more argument simply means: read standard input. */
+
+ input_file_name = (const char **) xmalloc (sizeof (const char *));
+ file_line_count = (int *) xmalloc (sizeof (int));
+ number_input_files = 1;
+ input_file_name[0] = NULL;
+ }
+ else if (gnu_extensions)
+ {
+ number_input_files = argc - optind;
+ input_file_name
+ = (const char **) xmalloc (number_input_files * sizeof (const char *));
+ file_line_count
+ = (int *) xmalloc (number_input_files * sizeof (int));
+
+ for (file_index = 0; file_index < number_input_files; file_index++)
+ {
+ input_file_name[file_index] = argv[optind];
+ if (!*argv[optind] || strcmp (argv[optind], "-") == 0)
+ input_file_name[0] = NULL;
+ else
+ input_file_name[0] = argv[optind];
+ optind++;
+ }
+ }
+ else
+ {
+
+ /* There is one necessary input file. */
+
+ number_input_files = 1;
+ input_file_name = (const char **) xmalloc (sizeof (const char *));
+ file_line_count = (int *) xmalloc (sizeof (int));
+ if (!*argv[optind] || strcmp (argv[optind], "-") == 0)
+ input_file_name[0] = NULL;
+ else
+ input_file_name[0] = argv[optind];
+ optind++;
+
+ /* Redirect standard output, only if requested. */
+
+ if (optind < argc)
+ {
+ fclose (stdout);
+ if (fopen (argv[optind], "w") == NULL)
+ error (1, errno, argv[optind]);
+ optind++;
+ }
+
+ /* Diagnose any other argument as an error. */
+
+ if (optind < argc)
+ usage (1);
+ }
+
+ /* If the output format has not been explicitly selected, choose dumb
+ terminal format if GNU extensions are enabled, else `roff' format. */
+
+ if (output_format == UNKNOWN_FORMAT)
+ output_format = gnu_extensions ? DUMB_FORMAT : ROFF_FORMAT;
+
+ /* Initialize the main tables. */
+
+ initialize_regex ();
+
+ /* Read `Break character' file, if any. */
+
+ if (break_file)
+ digest_break_file (break_file);
+
+ /* Read `Ignore words' file and `Only words' files, if any. If any of
+ these files is empty, reset the name of the file to NULL, to avoid
+ unnecessary calls to search_table. */
+
+ if (ignore_file)
+ {
+ digest_word_file (ignore_file, &ignore_table);
+ if (ignore_table.length == 0)
+ ignore_file = NULL;
+ }
+
+ if (only_file)
+ {
+ digest_word_file (only_file, &only_table);
+ if (only_table.length == 0)
+ only_file = NULL;
+ }
+
+ /* Prepare to study all the input files. */
+
+ number_of_occurs[0] = 0;
+ total_line_count = 0;
+ maximum_word_length = 0;
+ reference_max_width = 0;
+
+ for (file_index = 0; file_index < number_input_files; file_index++)
+ {
+
+ /* Read the file in core, than study it. */
+
+ swallow_file_in_memory (input_file_name[file_index], &text_buffer);
+ find_occurs_in_text ();
+
+ /* Maintain for each file how many lines has been read so far when its
+ end is reached. Incrementing the count first is a simple kludge to
+ handle a possible incomplete line at end of file. */
+
+ total_line_count++;
+ file_line_count[file_index] = total_line_count;
+ }
+
+ /* Do the output process phase. */
+
+ sort_found_occurs ();
+ fix_output_parameters ();
+ generate_all_output ();
+
+ /* All done. */
+
+ exit (0);
+}
diff --git a/gnu/usr.bin/ptx/ptx.info b/gnu/usr.bin/ptx/ptx.info
new file mode 100644
index 000000000000..3bbd1bb8cf07
--- /dev/null
+++ b/gnu/usr.bin/ptx/ptx.info
@@ -0,0 +1,496 @@
+This is Info file ptx.info, produced by Makeinfo-1.47 from the input
+file ./ptx.texinfo.
+
+ This file documents the `ptx' command, which has the purpose of
+generated permuted indices for group of files.
+
+ Copyright (C) 1990, 1991, 1993 by the Free Software Foundation, Inc.
+
+ 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 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 Foundation.
+
+
+File: ptx.info, Node: Top, Next: Invoking ptx, Prev: (dir), Up: (dir)
+
+Introduction
+************
+
+ This is the 0.3 beta release of `ptx', the GNU version of a permuted
+index generator. This software has the main goal of providing a
+replacement for the traditional `ptx' as found on System V machines,
+able to handle small files quickly, while providing a platform for more
+development.
+
+ This version reimplements and extends traditional `ptx'. Among
+other things, it can produce a readable "KWIC" (keywords in their
+context) without the need of `nroff', there is also an option to
+produce TeX compatible output. This version does not handle huge input
+files, that is, those files which do not fit in memory all at once.
+
+ *Please note* that an overall renaming of all options is
+foreseeable. In fact, GNU ptx specifications are not frozen yet.
+
+* Menu:
+
+* Invoking ptx:: How to use this program
+* Compatibility:: The GNU extensions to `ptx'
+
+ -- The Detailed Node Listing --
+
+How to use this program
+
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+
+
+File: ptx.info, Node: Invoking ptx, Next: Compatibility, Prev: Top, Up: Top
+
+How to use this program
+***********************
+
+ This tool reads a text file and essentially produces a permuted
+index, with each keyword in its context. The calling sketch is one of:
+
+ ptx [OPTION ...] [FILE ...]
+
+ or:
+
+ ptx -G [OPTION ...] [INPUT [OUTPUT]]
+
+ The `-G' (or its equivalent: `--traditional') option disables all
+GNU extensions and revert to traditional mode, thus introducing some
+limitations, and changes several of the program's default option values.
+When `-G' is not specified, GNU extensions are always enabled. GNU
+extensions to `ptx' are documented wherever appropriate in this
+document. See *Note Compatibility:: for an explicit list of them.
+
+ Individual options are explained later in this document.
+
+ When GNU extensions are enabled, there may be zero, one or several
+FILE after the options. If there is no FILE, the program reads the
+standard input. If there is one or several FILE, they give the name of
+input files which are all read in turn, as if all the input files were
+concatenated. However, there is a full contextual break between each
+file and, when automatic referencing is requested, file names and line
+numbers refer to individual text input files. In all cases, the
+program produces the permuted index onto the standard output.
+
+ When GNU extensions are *not* enabled, that is, when the program
+operates in traditional mode, there may be zero, one or two parameters
+besides the options. If there is no parameters, the program reads the
+standard input and produces the permuted index onto the standard output.
+If there is only one parameter, it names the text INPUT to be read
+instead of the standard input. If two parameters are given, they give
+respectively the name of the INPUT file to read and the name of the
+OUTPUT file to produce. *Be very careful* to note that, in this case,
+the contents of file given by the second parameter is destroyed. This
+behaviour is dictated only by System V `ptx' compatibility, because GNU
+Standards discourage output parameters not introduced by an option.
+
+ Note that for *any* file named as the value of an option or as an
+input text file, a single dash `-' may be used, in which case standard
+input is assumed. However, it would not make sense to use this
+convention more than once per program invocation.
+
+* Menu:
+
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+
+
+File: ptx.info, Node: General options, Next: Charset selection, Prev: Invoking ptx, Up: Invoking ptx
+
+General options
+===============
+
+`-C'
+`--copyright'
+ Prints a short note about the Copyright and copying conditions,
+ then exit without further processing.
+
+`-G'
+`--traditional'
+ As already explained, this option disables all GNU extensions to
+ `ptx' and switch to traditional mode.
+
+`--help'
+ Prints a short help on standard output, then exit without further
+ processing.
+
+`--version'
+ Prints the program verison on standard output, then exit without
+ further processing.
+
+
+File: ptx.info, Node: Charset selection, Next: Input processing, Prev: General options, Up: Invoking ptx
+
+Charset selection
+=================
+
+ As it is setup now, the program assumes that the input file is coded
+using 8-bit ISO 8859-1 code, also known as Latin-1 character set,
+*unless* if it is compiled for MS-DOS, in which case it uses the
+character set of the IBM-PC. (GNU `ptx' is not known to work on
+smaller MS-DOS machines anymore.) Compared to 7-bit ASCII, the set of
+characters which are letters is then different, this fact alters the
+behaviour of regular expression matching. Thus, the default regular
+expression for a keyword allows foreign or diacriticized letters.
+Keyword sorting, however, is still crude; it obeys the underlying
+character set ordering quite blindly.
+
+`-f'
+`--ignore-case'
+ Fold lower case letters to upper case for sorting.
+
+
+File: ptx.info, Node: Input processing, Next: Output formatting, Prev: Charset selection, Up: Invoking ptx
+
+Word selection
+==============
+
+`-b FILE'
+`--break-file=FILE'
+ This option is an alternative way to option `-W' for describing
+ which characters make up words. This option introduces the name
+ of a file which contains a list of characters which can*not* be
+ part of one word, this file is called the "Break file". Any
+ character which is not part of the Break file is a word
+ constituent. If both options `-b' and `-W' are specified, then
+ `-W' has precedence and `-b' is ignored.
+
+ When GNU extensions are enabled, the only way to avoid newline as a
+ break character is to write all the break characters in the file
+ with no newline at all, not even at the end of the file. When GNU
+ extensions are disabled, spaces, tabs and newlines are always
+ considered as break characters even if not included in the Break
+ file.
+
+`-i FILE'
+`--ignore-file=FILE'
+ The file associated with this option contains a list of words
+ which will never be taken as keywords in concordance output. It
+ is called the "Ignore file". The file contains exactly one word
+ in each line; the end of line separation of words is not subject
+ to the value of the `-S' option.
+
+ There is a default Ignore file used by `ptx' when this option is
+ not specified, usually found in `/usr/local/lib/eign' if this has
+ not been changed at installation time. If you want to deactivate
+ the default Ignore file, specify `/dev/null' instead.
+
+`-o FILE'
+`--only-file=FILE'
+ The file associated with this option contains a list of words
+ which will be retained in concordance output, any word not
+ mentioned in this file is ignored. The file is called the "Only
+ file". The file contains exactly one word in each line; the end
+ of line separation of words is not subject to the value of the
+ `-S' option.
+
+ There is no default for the Only file. In the case there are both
+ an Only file and an Ignore file, a word will be subject to be a
+ keyword only if it is given in the Only file and not given in the
+ Ignore file.
+
+`-r'
+`--references'
+ On each input line, the leading sequence of non white characters
+ will be taken to be a reference that has the purpose of
+ identifying this input line on the produced permuted index. See
+ *Note Output formatting:: for more information about reference
+ production. Using this option change the default value for option
+ `-S'.
+
+ Using this option, the program does not try very hard to remove
+ references from contexts in output, but it succeeds in doing so
+ *when* the context ends exactly at the newline. If option `-r' is
+ used with `-S' default value, or when GNU extensions are disabled,
+ this condition is always met and references are completely
+ excluded from the output contexts.
+
+`-S REGEXP'
+`--sentence-regexp=REGEXP'
+ This option selects which regular expression will describe the end
+ of a line or the end of a sentence. In fact, there is other
+ distinction between end of lines or end of sentences than the
+ effect of this regular expression, and input line boundaries have
+ no special significance outside this option. By default, when GNU
+ extensions are enabled and if `-r' option is not used, end of
+ sentences are used. In this case, the precise REGEX is imported
+ from GNU emacs:
+
+ [.?!][]\"')}]*\\($\\|\t\\| \\)[ \t\n]*
+
+ Whenever GNU extensions are disabled or if `-r' option is used, end
+ of lines are used; in this case, the default REGEXP is just:
+
+ \n
+
+ Using an empty REGEXP is equivalent to completely disabling end of
+ line or end of sentence recognition. In this case, the whole file
+ is considered to be a single big line or sentence. The user might
+ want to disallow all truncation flag generation as well, through
+ option `-F ""'. *Note Syntax of Regular Expressions:
+ (emacs)Regexps.
+
+ When the keywords happen to be near the beginning of the input
+ line or sentence, this often creates an unused area at the
+ beginning of the output context line; when the keywords happen to
+ be near the end of the input line or sentence, this often creates
+ an unused area at the end of the output context line. The program
+ tries to fill those unused areas by wrapping around context in
+ them; the tail of the input line or sentence is used to fill the
+ unused area on the left of the output line; the head of the input
+ line or sentence is used to fill the unused area on the right of
+ the output line.
+
+ As a matter of convenience to the user, many usual backslashed
+ escape sequences, as found in the C language, are recognized and
+ converted to the corresponding characters by `ptx' itself.
+
+`-W REGEXP'
+`--word-regexp=REGEXP'
+ This option selects which regular expression will describe each
+ keyword. By default, if GNU extensions are enabled, a word is a
+ sequence of letters; the REGEXP used is `\w+'. When GNU
+ extensions are disabled, a word is by default anything which ends
+ with a space, a tab or a newline; the REGEXP used is `[^ \t\n]+'.
+
+ An empty REGEXP is equivalent to not using this option, letting the
+ default dive in. *Note Syntax of Regular Expressions:
+ (emacs)Regexps.
+
+ As a matter of convenience to the user, many usual backslashed
+ escape sequences, as found in the C language, are recognized and
+ converted to the corresponding characters by `ptx' itself.
+
+
+File: ptx.info, Node: Output formatting, Prev: Input processing, Up: Invoking ptx
+
+Output formatting
+=================
+
+ Output format is mainly controlled by `-O' and `-T' options,
+described in the table below. When neither `-O' nor `-T' is selected,
+and if GNU extensions are enabled, the program choose an output format
+suited for a dumb terminal. Each keyword occurrence is output to the
+center of one line, surrounded by its left and right contexts. Each
+field is properly justified, so the concordance output could readily be
+observed. As a special feature, if automatic references are selected
+by option `-A' and are output before the left context, that is, if
+option `-R' is *not* selected, then a colon is added after the
+reference; this nicely interfaces with GNU Emacs `next-error'
+processing. In this default output format, each white space character,
+like newline and tab, is merely changed to exactly one space, with no
+special attempt to compress consecutive spaces. This might change in
+the future. Except for those white space characters, every other
+character of the underlying set of 256 characters is transmitted
+verbatim.
+
+ Output format is further controlled by the following options.
+
+`-g NUMBER'
+`--gap-size=NUMBER'
+ Select the size of the minimum white gap between the fields on the
+ output line.
+
+`-w NUMBER'
+`--width=NUMBER'
+ Select the output maximum width of each final line. If references
+ are used, they are included or excluded from the output maximum
+ width depending on the value of option `-R'. If this option is not
+ selected, that is, when references are output before the left
+ context, the output maximum width takes into account the maximum
+ length of all references. If this options is selected, that is,
+ when references are output after the right context, the output
+ maximum width does not take into account the space taken by
+ references, nor the gap that precedes them.
+
+`-A'
+`--auto-reference'
+ Select automatic references. Each input line will have an
+ automatic reference made up of the file name and the line ordinal,
+ with a single colon between them. However, the file name will be
+ empty when standard input is being read. If both `-A' and `-r'
+ are selected, then the input reference is still read and skipped,
+ but the automatic reference is used at output time, overriding the
+ input reference.
+
+`-R'
+`--right-side-refs'
+ In default output format, when option `-R' is not used, any
+ reference produced by the effect of options `-r' or `-A' are given
+ to the far right of output lines, after the right context. In
+ default output format, when option `-R' is specified, references
+ are rather given to the beginning of each output line, before the
+ left context. For any other output format, option `-R' is almost
+ ignored, except for the fact that the width of references is *not*
+ taken into account in total output width given by `-w' whenever
+ `-R' is selected.
+
+ This option is automatically selected whenever GNU extensions are
+ disabled.
+
+`-F STRING'
+`--flac-truncation=STRING'
+ This option will request that any truncation in the output be
+ reported using the string STRING. Most output fields
+ theoretically extend towards the beginning or the end of the
+ current line, or current sentence, as selected with option `-S'.
+ But there is a maximum allowed output line width, changeable
+ through option `-w', which is further divided into space for
+ various output fields. When a field has to be truncated because
+ cannot extend until the beginning or the end of the current line
+ to fit in the, then a truncation occurs. By default, the string
+ used is a single slash, as in `-F /'.
+
+ STRING may have more than one character, as in `-F ...'. Also, in
+ the particular case STRING is empty (`-F ""'), truncation flagging
+ is disabled, and no truncation marks are appended in this case.
+
+ As a matter of convenience to the user, many usual backslashed
+ escape sequences, as found in the C language, are recognized and
+ converted to the corresponding characters by `ptx' itself.
+
+`-M STRING'
+`--macro-name=STRING'
+ Select another STRING to be used instead of `xx', while generating
+ output suitable for `nroff', `troff' or TeX.
+
+`-O'
+`--format=roff'
+ Choose an output format suitable for `nroff' or `troff'
+ processing. Each output line will look like:
+
+ .xx "TAIL" "BEFORE" "KEYWORD_AND_AFTER" "HEAD" "REF"
+
+ so it will be possible to write an `.xx' roff macro to take care of
+ the output typesetting. This is the default output format when GNU
+ extensions are disabled. Option `-M' might be used to change `xx'
+ to another macro name.
+
+ In this output format, each non-graphical character, like newline
+ and tab, is merely changed to exactly one space, with no special
+ attempt to compress consecutive spaces. Each quote character: `"'
+ is doubled so it will be correctly processed by `nroff' or `troff'.
+
+`-T'
+`--format=tex'
+ Choose an output format suitable for TeX processing. Each output
+ line will look like:
+
+ \xx {TAIL}{BEFORE}{KEYWORD}{AFTER}{HEAD}{REF}
+
+ so it will be possible to write write a `\xx' definition to take
+ care of the output typesetting. Note that when references are not
+ being produced, that is, neither option `-A' nor option `-r' is
+ selected, the last parameter of each `\xx' call is inhibited.
+ Option `-M' might be used to change `xx' to another macro name.
+
+ In this output format, some special characters, like `$', `%',
+ `&', `#' and `_' are automatically protected with a backslash.
+ Curly brackets `{', `}' are also protected with a backslash, but
+ also enclosed in a pair of dollar signs to force mathematical
+ mode. The backslash itself produces the sequence `\backslash{}'.
+ Circumflex and tilde diacritics produce the sequence `^\{ }' and
+ `~\{ }' respectively. Other diacriticized characters of the
+ underlying character set produce an appropriate TeX sequence as
+ far as possible. The other non-graphical characters, like newline
+ and tab, and all others characters which are not part of ASCII,
+ are merely changed to exactly one space, with no special attempt
+ to compress consecutive spaces. Let me know how to improve this
+ special character processing for TeX.
+
+
+File: ptx.info, Node: Compatibility, Prev: Invoking ptx, Up: Top
+
+The GNU extensions to `ptx'
+***************************
+
+ This version of `ptx' contains a few features which do not exist in
+System V `ptx'. These extra features are suppressed by using the `-G'
+command line option, unless overridden by other command line options.
+Some GNU extensions cannot be recovered by overriding, so the simple
+rule is to avoid `-G' if you care about GNU extensions. Here are the
+differences between this program and System V `ptx'.
+
+ * This program can read many input files at once, it always writes
+ the resulting concordance on standard output. On the other end,
+ System V `ptx' reads only one file and produce the result on
+ standard output or, if a second FILE parameter is given on the
+ command, to that FILE.
+
+ Having output parameters not introduced by options is a quite
+ dangerous practice which GNU avoids as far as possible. So, for
+ using `ptx' portably between GNU and System V, you should pay
+ attention to always use it with a single input file, and always
+ expect the result on standard output. You might also want to
+ automatically configure in a `-G' option to `ptx' calls in
+ products using `ptx', if the configurator finds that the installed
+ `ptx' accepts `-G'.
+
+ * The only options available in System V `ptx' are options `-b',
+ `-f', `-g', `-i', `-o', `-r', `-t' and `-w'. All other options
+ are GNU extensions and are not repeated in this enumeration.
+ Moreover, some options have a slightly different meaning when GNU
+ extensions are enabled, as explained below.
+
+ * By default, concordance output is not formatted for `troff' or
+ `nroff'. It is rather formatted for a dumb terminal. `troff' or
+ `nroff' output may still be selected through option `-O'.
+
+ * Unless `-R' option is used, the maximum reference width is
+ subtracted from the total output line width. With GNU extensions
+ disabled, width of references is not taken into account in the
+ output line width computations.
+
+ * All 256 characters, even `NUL's, are always read and processed from
+ input file with no adverse effect, even if GNU extensions are
+ disabled. However, System V `ptx' does not accept 8-bit
+ characters, a few control characters are rejected, and the tilda
+ `~' is condemned.
+
+ * Input line length is only limited by available memory, even if GNU
+ extensions are disabled. However, System V `ptx' processes only
+ the first 200 characters in each line.
+
+ * The break (non-word) characters default to be every character
+ except all letters of the underlying character set, diacriticized
+ or not. When GNU extensions are disabled, the break characters
+ default to space, tab and newline only.
+
+ * The program makes better use of output line width. If GNU
+ extensions are disabled, the program rather tries to imitate
+ System V `ptx', but still, there are some slight disposition
+ glitches this program does not completely reproduce.
+
+ * The user can specify both an Ignore file and an Only file. This
+ is not allowed with System V `ptx'.
+
+
+
+Tag Table:
+Node: Top939
+Node: Invoking ptx2298
+Node: General options5025
+Node: Charset selection5639
+Node: Input processing6514
+Node: Output formatting12205
+Node: Compatibility18737
+
+End Tag Table
diff --git a/gnu/usr.bin/ptx/ptx.texinfo b/gnu/usr.bin/ptx/ptx.texinfo
new file mode 100644
index 000000000000..e690c55f80c1
--- /dev/null
+++ b/gnu/usr.bin/ptx/ptx.texinfo
@@ -0,0 +1,554 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ptx.info
+@settitle GNU @code{ptx} reference manual
+@finalout
+@c %**end of header
+
+@ifinfo
+This file documents the @code{ptx} command, which has the purpose of
+generated permuted indices for group of files.
+
+Copyright (C) 1990, 1991, 1993 by the Free Software Foundation, Inc.
+
+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.
+
+@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 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.
+
+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 Foundation.
+@end ifinfo
+
+@titlepage
+@title ptx
+@subtitle The GNU permuted indexer
+@subtitle Edition 0.3, for ptx version 0.3
+@subtitle November 1993
+@author by Francois Pinard
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990, 1991, 1993 Free Software Foundation, Inc.
+
+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 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 Foundation.
+@end titlepage
+
+@node Top, Invoking ptx, (dir), (dir)
+@chapter Introduction
+
+This is the 0.3 beta release of @code{ptx}, the GNU version of a
+permuted index generator. This software has the main goal of providing
+a replacement for the traditional @code{ptx} as found on System V
+machines, able to handle small files quickly, while providing a platform
+for more development.
+
+This version reimplements and extends traditional @code{ptx}. Among
+other things, it can produce a readable @dfn{KWIC} (keywords in their
+context) without the need of @code{nroff}, there is also an option to
+produce @TeX{} compatible output. This version does not handle huge
+input files, that is, those files which do not fit in memory all at
+once.
+
+@emph{Please note} that an overall renaming of all options is
+foreseeable. In fact, GNU ptx specifications are not frozen yet.
+
+@menu
+* Invoking ptx:: How to use this program
+* Compatibility:: The GNU extensions to @code{ptx}
+
+ --- The Detailed Node Listing ---
+
+How to use this program
+
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+@end menu
+
+@node Invoking ptx, Compatibility, Top, Top
+@chapter How to use this program
+
+This tool reads a text file and essentially produces a permuted index, with
+each keyword in its context. The calling sketch is one of:
+
+@example
+ptx [@var{option} @dots{}] [@var{file} @dots{}]
+@end example
+
+or:
+
+@example
+ptx -G [@var{option} @dots{}] [@var{input} [@var{output}]]
+@end example
+
+The @samp{-G} (or its equivalent: @samp{--traditional}) option disables
+all GNU extensions and revert to traditional mode, thus introducing some
+limitations, and changes several of the program's default option values.
+When @samp{-G} is not specified, GNU extensions are always enabled. GNU
+extensions to @code{ptx} are documented wherever appropriate in this
+document. See @xref{Compatibility} for an explicit list of them.
+
+Individual options are explained later in this document.
+
+When GNU extensions are enabled, there may be zero, one or several
+@var{file} after the options. If there is no @var{file}, the program
+reads the standard input. If there is one or several @var{file}, they
+give the name of input files which are all read in turn, as if all the
+input files were concatenated. However, there is a full contextual
+break between each file and, when automatic referencing is requested,
+file names and line numbers refer to individual text input files. In
+all cases, the program produces the permuted index onto the standard
+output.
+
+When GNU extensions are @emph{not} enabled, that is, when the program
+operates in traditional mode, there may be zero, one or two parameters
+besides the options. If there is no parameters, the program reads the
+standard input and produces the permuted index onto the standard output.
+If there is only one parameter, it names the text @var{input} to be read
+instead of the standard input. If two parameters are given, they give
+respectively the name of the @var{input} file to read and the name of
+the @var{output} file to produce. @emph{Be very careful} to note that,
+in this case, the contents of file given by the second parameter is
+destroyed. This behaviour is dictated only by System V @code{ptx}
+compatibility, because GNU Standards discourage output parameters not
+introduced by an option.
+
+Note that for @emph{any} file named as the value of an option or as an
+input text file, a single dash @kbd{-} may be used, in which case
+standard input is assumed. However, it would not make sense to use this
+convention more than once per program invocation.
+
+@menu
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+@end menu
+
+@node General options, Charset selection, Invoking ptx, Invoking ptx
+@section General options
+
+@table @code
+
+@item -C
+@itemx --copyright
+Prints a short note about the Copyright and copying conditions, then
+exit without further processing.
+
+@item -G
+@itemx --traditional
+As already explained, this option disables all GNU extensions to
+@code{ptx} and switch to traditional mode.
+
+@item --help
+Prints a short help on standard output, then exit without further
+processing.
+
+@item --version
+Prints the program verison on standard output, then exit without further
+processing.
+
+@end table
+
+@node Charset selection, Input processing, General options, Invoking ptx
+@section Charset selection
+
+As it is setup now, the program assumes that the input file is coded
+using 8-bit ISO 8859-1 code, also known as Latin-1 character set,
+@emph{unless} if it is compiled for MS-DOS, in which case it uses the
+character set of the IBM-PC. (GNU @code{ptx} is not known to work on
+smaller MS-DOS machines anymore.) Compared to 7-bit ASCII, the set of
+characters which are letters is then different, this fact alters the
+behaviour of regular expression matching. Thus, the default regular
+expression for a keyword allows foreign or diacriticized letters.
+Keyword sorting, however, is still crude; it obeys the underlying
+character set ordering quite blindly.
+
+@table @code
+
+@item -f
+@itemx --ignore-case
+Fold lower case letters to upper case for sorting.
+
+@end table
+
+@node Input processing, Output formatting, Charset selection, Invoking ptx
+@section Word selection
+
+@table @code
+
+@item -b @var{file}
+@item --break-file=@var{file}
+
+This option is an alternative way to option @code{-W} for describing
+which characters make up words. This option introduces the name of a
+file which contains a list of characters which can@emph{not} be part of
+one word, this file is called the @dfn{Break file}. Any character which
+is not part of the Break file is a word constituent. If both options
+@code{-b} and @code{-W} are specified, then @code{-W} has precedence and
+@code{-b} is ignored.
+
+When GNU extensions are enabled, the only way to avoid newline as a
+break character is to write all the break characters in the file with no
+newline at all, not even at the end of the file. When GNU extensions
+are disabled, spaces, tabs and newlines are always considered as break
+characters even if not included in the Break file.
+
+@item -i @var{file}
+@itemx --ignore-file=@var{file}
+
+The file associated with this option contains a list of words which will
+never be taken as keywords in concordance output. It is called the
+@dfn{Ignore file}. The file contains exactly one word in each line; the
+end of line separation of words is not subject to the value of the
+@code{-S} option.
+
+There is a default Ignore file used by @code{ptx} when this option is
+not specified, usually found in @file{/usr/local/lib/eign} if this has
+not been changed at installation time. If you want to deactivate the
+default Ignore file, specify @code{/dev/null} instead.
+
+@item -o @var{file}
+@itemx --only-file=@var{file}
+
+The file associated with this option contains a list of words which will
+be retained in concordance output, any word not mentioned in this file
+is ignored. The file is called the @dfn{Only file}. The file contains
+exactly one word in each line; the end of line separation of words is
+not subject to the value of the @code{-S} option.
+
+There is no default for the Only file. In the case there are both an
+Only file and an Ignore file, a word will be subject to be a keyword
+only if it is given in the Only file and not given in the Ignore file.
+
+@item -r
+@itemx --references
+
+On each input line, the leading sequence of non white characters will be
+taken to be a reference that has the purpose of identifying this input
+line on the produced permuted index. See @xref{Output formatting} for
+more information about reference production. Using this option change
+the default value for option @code{-S}.
+
+Using this option, the program does not try very hard to remove
+references from contexts in output, but it succeeds in doing so
+@emph{when} the context ends exactly at the newline. If option
+@code{-r} is used with @code{-S} default value, or when GNU extensions
+are disabled, this condition is always met and references are completely
+excluded from the output contexts.
+
+@item -S @var{regexp}
+@itemx --sentence-regexp=@var{regexp}
+
+This option selects which regular expression will describe the end of a
+line or the end of a sentence. In fact, there is other distinction
+between end of lines or end of sentences than the effect of this regular
+expression, and input line boundaries have no special significance
+outside this option. By default, when GNU extensions are enabled and if
+@code{-r} option is not used, end of sentences are used. In this
+case, the precise @var{regex} is imported from GNU emacs:
+
+@example
+[.?!][]\"')@}]*\\($\\|\t\\| \\)[ \t\n]*
+@end example
+
+Whenever GNU extensions are disabled or if @code{-r} option is used, end
+of lines are used; in this case, the default @var{regexp} is just:
+
+@example
+\n
+@end example
+
+Using an empty REGEXP is equivalent to completely disabling end of line or end
+of sentence recognition. In this case, the whole file is considered to
+be a single big line or sentence. The user might want to disallow all
+truncation flag generation as well, through option @code{-F ""}.
+@xref{Regexps, , Syntax of Regular Expressions, emacs, The GNU Emacs
+Manual}.
+
+When the keywords happen to be near the beginning of the input line or
+sentence, this often creates an unused area at the beginning of the
+output context line; when the keywords happen to be near the end of the
+input line or sentence, this often creates an unused area at the end of
+the output context line. The program tries to fill those unused areas
+by wrapping around context in them; the tail of the input line or
+sentence is used to fill the unused area on the left of the output line;
+the head of the input line or sentence is used to fill the unused area
+on the right of the output line.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@item -W @var{regexp}
+@itemx --word-regexp=@var{regexp}
+
+This option selects which regular expression will describe each keyword.
+By default, if GNU extensions are enabled, a word is a sequence of
+letters; the @var{regexp} used is @code{\w+}. When GNU extensions are
+disabled, a word is by default anything which ends with a space, a tab
+or a newline; the @var{regexp} used is @code{[^ \t\n]+}.
+
+An empty REGEXP is equivalent to not using this option, letting the
+default dive in. @xref{Regexps, , Syntax of Regular Expressions, emacs,
+The GNU Emacs Manual}.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@end table
+
+@node Output formatting, , Input processing, Invoking ptx
+@section Output formatting
+
+Output format is mainly controlled by @code{-O} and @code{-T} options,
+described in the table below. When neither @code{-O} nor @code{-T} is
+selected, and if GNU extensions are enabled, the program choose an
+output format suited for a dumb terminal. Each keyword occurrence is
+output to the center of one line, surrounded by its left and right
+contexts. Each field is properly justified, so the concordance output
+could readily be observed. As a special feature, if automatic
+references are selected by option @code{-A} and are output before the
+left context, that is, if option @code{-R} is @emph{not} selected, then
+a colon is added after the reference; this nicely interfaces with GNU
+Emacs @code{next-error} processing. In this default output format, each
+white space character, like newline and tab, is merely changed to
+exactly one space, with no special attempt to compress consecutive
+spaces. This might change in the future. Except for those white space
+characters, every other character of the underlying set of 256
+characters is transmitted verbatim.
+
+Output format is further controlled by the following options.
+
+@table @code
+
+@item -g @var{number}
+@itemx --gap-size=@var{number}
+
+Select the size of the minimum white gap between the fields on the output
+line.
+
+@item -w @var{number}
+@itemx --width=@var{number}
+
+Select the output maximum width of each final line. If references are
+used, they are included or excluded from the output maximum width
+depending on the value of option @code{-R}. If this option is not
+selected, that is, when references are output before the left context,
+the output maximum width takes into account the maximum length of all
+references. If this options is selected, that is, when references are
+output after the right context, the output maximum width does not take
+into account the space taken by references, nor the gap that precedes
+them.
+
+@item -A
+@itemx --auto-reference
+
+Select automatic references. Each input line will have an automatic
+reference made up of the file name and the line ordinal, with a single
+colon between them. However, the file name will be empty when standard
+input is being read. If both @code{-A} and @code{-r} are selected, then
+the input reference is still read and skipped, but the automatic
+reference is used at output time, overriding the input reference.
+
+@item -R
+@itemx --right-side-refs
+
+In default output format, when option @code{-R} is not used, any
+reference produced by the effect of options @code{-r} or @code{-A} are
+given to the far right of output lines, after the right context. In
+default output format, when option @code{-R} is specified, references
+are rather given to the beginning of each output line, before the left
+context. For any other output format, option @code{-R} is almost
+ignored, except for the fact that the width of references is @emph{not}
+taken into account in total output width given by @code{-w} whenever
+@code{-R} is selected.
+
+This option is automatically selected whenever GNU extensions are
+disabled.
+
+@item -F @var{string}
+@itemx --flac-truncation=@var{string}
+
+This option will request that any truncation in the output be reported
+using the string @var{string}. Most output fields theoretically extend
+towards the beginning or the end of the current line, or current
+sentence, as selected with option @code{-S}. But there is a maximum
+allowed output line width, changeable through option @code{-w}, which is
+further divided into space for various output fields. When a field has
+to be truncated because cannot extend until the beginning or the end of
+the current line to fit in the, then a truncation occurs. By default,
+the string used is a single slash, as in @code{-F /}.
+
+@var{string} may have more than one character, as in @code{-F ...}.
+Also, in the particular case @var{string} is empty (@code{-F ""}),
+truncation flagging is disabled, and no truncation marks are appended in
+this case.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@item -M @var{string}
+@itemx --macro-name=@var{string}
+
+Select another @var{string} to be used instead of @samp{xx}, while
+generating output suitable for @code{nroff}, @code{troff} or @TeX{}.
+
+@item -O
+@itemx --format=roff
+
+Choose an output format suitable for @code{nroff} or @code{troff}
+processing. Each output line will look like:
+
+@example
+.xx "@var{tail}" "@var{before}" "@var{keyword_and_after}" "@var{head}" "@var{ref}"
+@end example
+
+so it will be possible to write an @samp{.xx} roff macro to take care of
+the output typesetting. This is the default output format when GNU
+extensions are disabled. Option @samp{-M} might be used to change
+@samp{xx} to another macro name.
+
+In this output format, each non-graphical character, like newline and
+tab, is merely changed to exactly one space, with no special attempt to
+compress consecutive spaces. Each quote character: @kbd{"} is doubled
+so it will be correctly processed by @code{nroff} or @code{troff}.
+
+@item -T
+@itemx --format=tex
+
+Choose an output format suitable for @TeX{} processing. Each output
+line will look like:
+
+@example
+\xx @{@var{tail}@}@{@var{before}@}@{@var{keyword}@}@{@var{after}@}@{@var{head}@}@{@var{ref}@}
+@end example
+
+@noindent
+so it will be possible to write write a @code{\xx} definition to take
+care of the output typesetting. Note that when references are not being
+produced, that is, neither option @code{-A} nor option @code{-r} is
+selected, the last parameter of each @code{\xx} call is inhibited.
+Option @samp{-M} might be used to change @samp{xx} to another macro
+name.
+
+In this output format, some special characters, like @kbd{$}, @kbd{%},
+@kbd{&}, @kbd{#} and @kbd{_} are automatically protected with a
+backslash. Curly brackets @kbd{@{}, @kbd{@}} are also protected with a
+backslash, but also enclosed in a pair of dollar signs to force
+mathematical mode. The backslash itself produces the sequence
+@code{\backslash@{@}}. Circumflex and tilde diacritics produce the
+sequence @code{^\@{ @}} and @code{~\@{ @}} respectively. Other
+diacriticized characters of the underlying character set produce an
+appropriate @TeX{} sequence as far as possible. The other non-graphical
+characters, like newline and tab, and all others characters which are
+not part of ASCII, are merely changed to exactly one space, with no
+special attempt to compress consecutive spaces. Let me know how to
+improve this special character processing for @TeX{}.
+
+@end table
+
+@node Compatibility, , Invoking ptx, Top
+@chapter The GNU extensions to @code{ptx}
+
+This version of @code{ptx} contains a few features which do not exist in
+System V @code{ptx}. These extra features are suppressed by using the
+@samp{-G} command line option, unless overridden by other command line
+options. Some GNU extensions cannot be recovered by overriding, so the
+simple rule is to avoid @samp{-G} if you care about GNU extensions.
+Here are the differences between this program and System V @code{ptx}.
+
+@itemize @bullet
+
+@item
+This program can read many input files at once, it always writes the
+resulting concordance on standard output. On the other end, System V
+@code{ptx} reads only one file and produce the result on standard output
+or, if a second @var{file} parameter is given on the command, to that
+@var{file}.
+
+Having output parameters not introduced by options is a quite dangerous
+practice which GNU avoids as far as possible. So, for using @code{ptx}
+portably between GNU and System V, you should pay attention to always
+use it with a single input file, and always expect the result on
+standard output. You might also want to automatically configure in a
+@samp{-G} option to @code{ptx} calls in products using @code{ptx}, if
+the configurator finds that the installed @code{ptx} accepts @samp{-G}.
+
+@item
+The only options available in System V @code{ptx} are options @samp{-b},
+@samp{-f}, @samp{-g}, @samp{-i}, @samp{-o}, @samp{-r}, @samp{-t} and
+@samp{-w}. All other options are GNU extensions and are not repeated in
+this enumeration. Moreover, some options have a slightly different
+meaning when GNU extensions are enabled, as explained below.
+
+@item
+By default, concordance output is not formatted for @code{troff} or
+@code{nroff}. It is rather formatted for a dumb terminal. @code{troff}
+or @code{nroff} output may still be selected through option @code{-O}.
+
+@item
+Unless @code{-R} option is used, the maximum reference width is
+subtracted from the total output line width. With GNU extensions
+disabled, width of references is not taken into account in the output
+line width computations.
+
+@item
+All 256 characters, even @kbd{NUL}s, are always read and processed from
+input file with no adverse effect, even if GNU extensions are disabled.
+However, System V @code{ptx} does not accept 8-bit characters, a few
+control characters are rejected, and the tilda @kbd{~} is condemned.
+
+@item
+Input line length is only limited by available memory, even if GNU
+extensions are disabled. However, System V @code{ptx} processes only
+the first 200 characters in each line.
+
+@item
+The break (non-word) characters default to be every character except all
+letters of the underlying character set, diacriticized or not. When GNU
+extensions are disabled, the break characters default to space, tab and
+newline only.
+
+@item
+The program makes better use of output line width. If GNU extensions
+are disabled, the program rather tries to imitate System V @code{ptx},
+but still, there are some slight disposition glitches this program does
+not completely reproduce.
+
+@item
+The user can specify both an Ignore file and an Only file. This is not
+allowed with System V @code{ptx}.
+
+@end itemize
+
+@bye
diff --git a/gnu/usr.bin/ptx/regex.h b/gnu/usr.bin/ptx/regex.h
new file mode 100644
index 000000000000..a495005ce936
--- /dev/null
+++ b/gnu/usr.bin/ptx/regex.h
@@ -0,0 +1,490 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 89, 90, 91, 92, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* 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 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 RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* 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 RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 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 RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* 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 RE_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 RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* 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 RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* 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 RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* 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, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* 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 RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* 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 (REG_EXTENDED << 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 (REG_ICASE << 1)
+
+/* 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 (REG_NEWLINE << 1)
+
+
+/* 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)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `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 *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t 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 *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. */
+ char *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 can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned 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 fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
+#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_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
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_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 RE_NREGS
+#define RE_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. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* 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 _RE_ARGS ((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
+ _RE_ARGS ((const char *pattern, int 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 _RE_ARGS ((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->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int 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 int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int 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
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/ptx/texinfo.tex b/gnu/usr.bin/ptx/texinfo.tex
new file mode 100644
index 000000000000..ce11b7b828e0
--- /dev/null
+++ b/gnu/usr.bin/ptx/texinfo.tex
@@ -0,0 +1,4053 @@
+%% TeX macros to handle texinfo files
+
+% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 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, 675 Mass Ave, Cambridge, MA 02139,
+%USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them. Help stamp out software-hoarding!
+
+\def\texinfoversion{2.115}
+\message{Loading texinfo package [Version \texinfoversion]:}
+
+% Print the version number if in a .fmt file.
+\everyjob{\message{[Texinfo version \texinfoversion]}\message{}}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdots=\dots
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ } % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset \bindingoffset=0pt
+\newdimen \normaloffset \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+% 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.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{\tracingcommands2 \tracingstats2
+ \tracingpages1 \tracingoutput1 \tracinglostchars1
+ \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+
+%---------------------Begin change-----------------------
+%
+%%%% For @cropmarks command.
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks
+\outerhsize=7in
+%\outervsize=9.5in
+% Alternative @smallbook page size is 9.25in
+\outervsize=9.25in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+{\let\hsize=\pagewidth \makefootline}}}%
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+%%%% For @cropmarks command %%%%
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box. (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+ \shipout
+ \vbox to \outervsize{\hsize=\outerhsize
+ \vbox{\line{\ewtop\hfill\ewtop}}
+ \nointerlineskip
+ \line{\vbox{\moveleft\cornerthick\nstop}
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}}
+ \vskip \topandbottommargin
+ \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+ \vbox{
+ {\let\hsize=\pagewidth \makeheadline}
+ \pagebody{#1}
+ {\let\hsize=\pagewidth \makefootline}}
+ \ifodd\pageno\else\hskip\bindingoffset\fi}
+ \vskip \topandbottommargin plus1fill minus1fill
+ \boxmaxdepth\cornerthick
+ \line{\vbox{\moveleft\cornerthick\nsbot}
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}}
+ \nointerlineskip
+ \vbox{\line{\ewbot\hfill\ewbot}}
+ }}
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\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#1{%
+ \let\next = #1%
+ \begingroup
+ \obeylines
+ \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse. Otherwise, we're done.
+\def\parseargx{%
+ % \obeyedspace is defined far below, after the definition of \sepspaces.
+ \ifx\obeyedspace\temp
+ \expandafter\parseargdiscardspace
+ \else
+ \expandafter\parseargline
+ \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+ \gdef\parseargline#1^^M{%
+ \endgroup % End of the group started in \parsearg.
+ %
+ % First remove any @c comment, then any @comment.
+ % Result of each macro is put in \toks0.
+ \argremovec #1\c\relax %
+ \expandafter\argremovecomment \the\toks0 \comment\relax %
+ %
+ % Call the caller's macro, saved as \next in \parsearg.
+ \expandafter\next\expandafter{\the\toks0}%
+ }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us. The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+% @end itemize @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'. Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands. (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.) But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+ \begingroup
+ \ignoreactivespaces
+ \edef\temp{#1}%
+ \global\toks0 = \expandafter{\temp}%
+ \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+ \obeyspaces
+ \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment. Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+ \removeactivespaces{#1}%
+ \edef\endthing{\the\toks0}%
+ %
+ \expandafter\ifx\csname E\endthing\endcsname\relax
+ \expandafter\ifx\csname \endthing\endcsname\relax
+ % There's no \foo, i.e., no ``environment'' foo.
+ \errhelp = \EMsimple
+ \errmessage{Undefined command `@end \endthing'}%
+ \else
+ \unmatchedenderror\endthing
+ \fi
+ \else
+ % Everything's ok; the right environment has been started.
+ \csname E\endthing\endcsname
+ \fi
+}
+
+% There is an environment #1, but it hasn't been started. Give an error.
+%
+\def\unmatchedenderror#1{%
+ \errhelp = \EMsimple
+ \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+ \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+% Why was this kern here? It messes up equalizing space above and below
+% environments. --karl, 6may93
+%{\advance \baselineskip by -\singlespaceskip
+%\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt \char '100}}
+
+% 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 \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\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.
+%
+\def\group{\begingroup
+ \ifnum\catcode13=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ %
+ % The \vtop we start below 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. (See p.82 of
+ % the TeXbook.) Thus, space below is not quite equal to space
+ % above. But it's pretty close.
+ \def\Egroup{%
+ \egroup % End the \vtop.
+ \endgroup % End the \group.
+ }%
+ %
+ \vtop\bgroup
+ % We have to put a strut on the last line in case the @group is in
+ % the midst of an example, rather than completely enclosing it.
+ % Otherwise, the interline space between the last line of the group
+ % and the first line afterwards is too small. But we can't put the
+ % strut in \Egroup, since there it would be on a line by itself.
+ % Hence this just inserts a strut at the beginning of each line.
+ \everypar = {\strut}%
+ %
+ % Since we have a strut on every line, we don't need any of TeX's
+ % normal interline spacing.
+ \offinterlineskip
+ %
+ % OK, but now we have to do something about blank
+ % lines in the input in @example-like environments, which normally
+ % just turn into \lisppar, which will insert no space now that we've
+ % turned off the interline space. Simplest is to make them be an
+ % empty paragraph.
+ \ifx\par\lisppar
+ \edef\par{\leavevmode \par}%
+ %
+ % Reset ^^M's definition to new definition of \par.
+ \obeylines
+ \fi
+ %
+ % We do @comment here in case 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
+}
+%
+% 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
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\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\penalty 10000
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+ % Go into vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % Don't add any leading before our big empty box, but allow a page
+ % break, since the best break might be right here.
+ \allowbreak
+ \nointerlineskip
+ \vtop to #1\mil{\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
+}
+
+% @br forces paragraph break
+
+\let\br = \par
+
+% @dots{} output some dots
+
+\def\dots{$\ldots$}
+
+% @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.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+%Use \input\thisfile to avoid blank after \input, which may be an active
+%char (in which case the blank would become the \input argument).
+%The grouping keeps the value of \thisfile correct even when @include
+%is nested.
+\def\includezzz #1{\begingroup
+\def\thisfile{#1}\input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \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{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
+\parsearg \commentxxx}
+
+\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+ \let\defcv = \relax
+ \let\deffn = \relax
+ \let\deffnx = \relax
+ \let\defindex = \relax
+ \let\defivar = \relax
+ \let\defmac = \relax
+ \let\defmethod = \relax
+ \let\defop = \relax
+ \let\defopt = \relax
+ \let\defspec = \relax
+ \let\deftp = \relax
+ \let\deftypefn = \relax
+ \let\deftypefun = \relax
+ \let\deftypevar = \relax
+ \let\deftypevr = \relax
+ \let\defun = \relax
+ \let\defvar = \relax
+ \let\defvr = \relax
+ \let\ref = \relax
+ \let\xref = \relax
+ \let\printindex = \relax
+ \let\pxref = \relax
+ \let\settitle = \relax
+ \let\include = \relax
+ \let\lowersections = \relax
+ \let\down = \relax
+ \let\raisesections = \relax
+ \let\up = \relax
+ \let\set = \relax
+ \let\clear = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Also ignore @ifinfo, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define a command to swallow text until we reach `@end #1'.
+ \long\def\doignoretext##1\end #1{\enddoignore}%
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \catcode32 = 10
+ %
+ % And now expand that command.
+ \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+ \ifwarnedobs\relax\else
+ % We need to warn folks that they may have trouble with TeX 3.0.
+ % This uses \immediate\write16 rather than \message to get newlines.
+ \immediate\write16{}
+ \immediate\write16{***WARNING*** for users of Unix TeX 3.0!}
+ \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+ \immediate\write16{If you are running another version of TeX, relax.}
+ \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+ \immediate\write16{ Then upgrade your TeX installation if you can.}
+ \immediate\write16{If you are stuck with version 3.0, run the}
+ \immediate\write16{ script ``tex3patch'' from the Texinfo distribution}
+ \immediate\write16{ to use a workaround.}
+ \immediate\write16{}
+ \warnedobstrue
+ \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex. For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+ \obstexwarn
+ % We must actually expand the ignored text to look for the @end
+ % command, so that nested ignore constructs work. Thus, we put the
+ % text into a \vbox and then do nothing with the result. To minimize
+ % the change of memory overflow, we follow the approach outlined on
+ % page 401 of the TeXbook: make the current font be a dummy font.
+ %
+ \setbox0 = \vbox\bgroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define `@end #1' to end the box, which will in turn undefine the
+ % @end command again.
+ \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+ %
+ % We are going to be parsing Texinfo commands. Most cause no
+ % trouble when they are used incorrectly, but some commands do
+ % complicated argument parsing or otherwise get confused, so we
+ % undefine them.
+ %
+ % We can't do anything about stray @-signs, unfortunately;
+ % they'll produce `undefined control sequence' errors.
+ \ignoremorecommands
+ %
+ % Set the current font to be \nullfont, a TeX primitive, and define
+ % all the font commands to also use \nullfont. We don't use
+ % dummy.tfm, as suggested in the TeXbook, because not all sites
+ % might have that installed. Therefore, math mode will still
+ % produce output, but that should be an extremely small amount of
+ % stuff compared to the main input.
+ %
+ \nullfont
+ \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont
+ \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont
+ \let\tensf = \nullfont
+ % Similarly for index fonts (mostly for their use in
+ % smallexample)
+ \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont
+ \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont
+ \let\indsf = \nullfont
+ %
+ % Don't complain when characters are missing from the fonts.
+ \tracinglostchars = 0
+ %
+ % Don't bother to do space factor calculations.
+ \frenchspacing
+ %
+ % Don't report underfull hboxes.
+ \hbadness = 10000
+ %
+ % Do minimal line-breaking.
+ \pretolerance = 10000
+ %
+ % Do not execute instructions in @tex
+ \def\tex{\doignore{tex}}
+}
+
+% @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.
+%
+\def\set{\parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ \def\temp{#2}%
+ \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+ \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+ \fi
+}
+\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+%
+\def\value#1{\expandafter
+ \ifx\csname SET#1\endcsname\relax
+ {\{No value for ``#1''\}}
+ \else \csname SET#1\endcsname \fi}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifsetfail
+ \else
+ \expandafter\ifsetsucceed
+ \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifclearsucceed
+ \else
+ \expandafter\ifclearfail
+ \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex always succeeds; we read the text following, through @end
+% iftex). But `@end iftex' should be valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\defineunmatchedend{iftex}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group). So we must
+% define \Eiftex to redefine itself to be its previous value. (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+ \edef\temp{%
+ % Remember the current value of \E#1.
+ \let\nece{prevE#1} = \nece{E#1}%
+ %
+ % At the `@end #1', redefine \E#1 to be its previous value.
+ \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+ }%
+ \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written. Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo). So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\appendixnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+
+% @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{%
+ \readauxfile
+ \opencontents
+ \openindices
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+ \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+\message{fonts,}
+
+% Font-change commands.
+
+% Texinfo supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+%% Try out Computer Modern fonts at \magstephalf
+\let\mainmagstep=\magstephalf
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\font\textrm=cmr12
+\font\texttt=cmtt12
+\else
+\font\textrm=cmr10 scaled \mainmagstep
+\font\texttt=cmtt10 scaled \mainmagstep
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\textbf=cmb10 scaled \mainmagstep
+\font\textit=cmti10 scaled \mainmagstep
+\font\textsl=cmsl10 scaled \mainmagstep
+\font\textsf=cmss10 scaled \mainmagstep
+\font\textsc=cmcsc10 scaled \mainmagstep
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\font\deftt=cmtt10 scaled \magstep1
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples.
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\font\ninett=cmtt9
+\font\indrm=cmr9
+\font\indit=cmsl9
+\let\indsl=\indit
+\let\indtt=\ninett
+\let\indsf=\indrm
+\let\indbf=\indrm
+\let\indsc=\indrm
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for headings
+\font\chaprm=cmbx12 scaled \magstep2
+\font\chapit=cmti12 scaled \magstep2
+\font\chapsl=cmsl12 scaled \magstep2
+\font\chaptt=cmtt12 scaled \magstep2
+\font\chapsf=cmss12 scaled \magstep2
+\let\chapbf=\chaprm
+\font\chapsc=cmcsc10 scaled\magstep3
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+\font\secrm=cmbx12 scaled \magstep1
+\font\secit=cmti12 scaled \magstep1
+\font\secsl=cmsl12 scaled \magstep1
+\font\sectt=cmtt12 scaled \magstep1
+\font\secsf=cmss12 scaled \magstep1
+\font\secbf=cmbx12 scaled \magstep1
+\font\secsc=cmcsc10 scaled\magstep2
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \font\ssecrm=cmbx10 scaled \magstep1 % This size an font looked bad.
+% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded.
+% \font\ssecsl=cmsl10 scaled \magstep1
+% \font\ssectt=cmtt10 scaled \magstep1
+% \font\ssecsf=cmss10 scaled \magstep1
+
+%\font\ssecrm=cmb10 scaled 1315 % Note the use of cmb rather than cmbx.
+%\font\ssecit=cmti10 scaled 1315 % Also, the size is a little larger than
+%\font\ssecsl=cmsl10 scaled 1315 % being scaled magstep1.
+%\font\ssectt=cmtt10 scaled 1315
+%\font\ssecsf=cmss10 scaled 1315
+
+%\let\ssecbf=\ssecrm
+
+\font\ssecrm=cmbx12 scaled \magstephalf
+\font\ssecit=cmti12 scaled \magstephalf
+\font\ssecsl=cmsl12 scaled \magstephalf
+\font\ssectt=cmtt12 scaled \magstephalf
+\font\ssecsf=cmss12 scaled \magstephalf
+\font\ssecbf=cmbx12 scaled \magstephalf
+\font\ssecsc=cmcsc10 scaled \magstep1
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled \magstep1
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% Fonts for title page:
+\font\titlerm = cmbx12 scaled \magstep3
+\let\authorrm = \secrm
+
+% 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, 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 so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current. Plain TeX does, for example,
+% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need
+% to redefine \bf itself.
+\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
+ \resetmathfonts}
+\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
+ \resetmathfonts}
+\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
+ \resetmathfonts}
+\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
+ \resetmathfonts}
+\def\indexfonts{%
+ \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+ \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+ \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
+ \resetmathfonts}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\font\shortcontrm=cmr12
+\font\shortcontbf=cmbx12
+\font\shortcontsl=cmsl12
+
+%% 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\/\fi\fi\fi}
+\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartitalic
+\let\dfn=\smartitalic
+\let\emph=\smartitalic
+\let\cite=\smartitalic
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% 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 = `- }
+
+\def\t#1{%
+ {\tt \nohyphenation \rawbackslash \frenchspacing #1}%
+ \null
+}
+\let\ttfont = \t
+%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\samp #1{`\tclose{#1}'\null}
+\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\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 overful 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 an a dash.
+% -- rms.
+{
+\catcode`\-=\active
+\catcode`\_=\active
+\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex}
+% The following is used by \doprintindex to insure that long function names
+% wrap around. It is necessary for - and _ to be active before the index is
+% read from the file, as \entry parses the arguments long before \code is
+% ever called. -- mycroft
+\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder}
+}
+\def\realdash{-}
+\def\realunder{_}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\normalunderscore\discretionary{}{}{}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+\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{\look}\fi
+\else\tclose{\look}\fi}
+
+% 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}
+
+\def\l#1{{\li #1}\null} %
+
+\def\r#1{{\rm #1}} % roman font
+% Use of \lowercase was suggested.
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\def\titlefont#1{{\titlerm #1}}
+
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+ \endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+ \let\subtitlerm=\tenrm
+% I deinstalled the following change because \cmr12 is undefined.
+% This change was not in the ChangeLog anyway. --rms.
+% \let\subtitlerm=\cmr12
+ \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+ %
+ \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+ %
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ %
+ % Now you can print the title using @title.
+ \def\title{\parsearg\titlezzz}%
+ \def\titlezzz##1{\leftline{\titlefont{##1}}
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Now you can put text using @subtitle.
+ \def\subtitle{\parsearg\subtitlezzz}%
+ \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+ %
+ % @author should come last, but may come many times.
+ \def\author{\parsearg\authorzzz}%
+ \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+ {\authorfont \leftline{##1}}}%
+ %
+ % 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
+ \oldpage
+ \let\page = \oldpage
+ \hbox{}}%
+% \def\page{\oldpage \hbox{}}
+}
+
+\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
+ \HEADINGSon
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt width \hsize
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline % Token sequence for heading line of even pages
+\newtoks \oddheadline % Token sequence for heading line of odd pages
+\newtoks \evenfootline % Token sequence for footing line of even pages
+\newtoks \oddfootline % Token sequence for footing line of 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\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @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.
+
+\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{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\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}}
+}
+
+\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}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line... specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% @tabs -- simple alignment
+
+% These don't work. For one thing, \+ is defined as outer.
+% So these macros cannot even be defined.
+
+%\def\tabs{\parsearg\tabszzz}
+%\def\tabszzz #1{\settabs\+#1\cr}
+%\def\tabline{\parsearg\tablinezzz}
+%\def\tablinezzz #1{\+#1\cr}
+%\def\&{&}
+
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(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, @vtable, 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\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+ \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+ \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemfont{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % Be sure we are not still in the middle of a paragraph.
+ %{\parskip = 0in
+ %\par
+ %}%
+ %
+ % 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. Unfortunately
+ % we can't prevent a possible page break at the following
+ % \baselineskip glue.
+ \nobreak
+ \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. Since that
+ % text will be indented by \tableindent, we make the item text be in
+ % a zero-width box.
+ \noindent
+ \rlap{\hskip -\tableindent\box0}\ignorespaces%
+ \endgroup%
+ \itemxneedsnegativevskiptrue%
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1 \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1 \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1 \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+ \begingroup % ended by the @end itemsize
+ \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+ \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \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'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ \begingroup % ended by the @end enumerate
+ %
+ % 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 itemizey, 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
+ \itemizey{#1.}\Eenumerate\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}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \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{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @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.
+\def\synindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% 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}}}
+
+\def\indexdummies{%
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\char{\realbackslash char}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\t##1{\realbackslash r {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+
+\def\doind #1#2{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+}\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+}\penalty\count10}}
+
+% 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.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{%
+ \tex
+ \dobreak \chapheadingskip {10000}
+ \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+ \catcode`\$=\other
+ \catcode`\~=\other
+ \indexbreaks
+ %
+ % The following don't help, since the chars were translated
+ % when the raw index was written, and their fonts were discarded
+ % due to \indexnofonts.
+ %\catcode`\"=\active
+ %\catcode`\^=\active
+ %\catcode`\_=\active
+ %\catcode`\|=\active
+ %\catcode`\<=\active
+ %\catcode`\>=\active
+ % %
+ \def\indexbackslash{\rawbackslashxx}
+ \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+ \begindoublecolumns
+ %
+ % See if the index file exists and is nonempty.
+ \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.
+ (Index is nonexistent)
+ \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
+ (Index is empty)
+ \else
+ \input \jobname.#1s
+ \fi
+ \fi
+ \closein 1
+ \enddoublecolumns
+ \Etex
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\def\initial #1{%
+{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin. It is used for index and table of contents
+% entries. The paragraph is indented by \leftskip.
+%
+\def\entry #1#2{\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
+ %
+ % Start a ``paragraph'' for the index entry so the line breaking
+ % parameters we've set above will have an effect.
+ \noindent
+ %
+ % Insert the text of the index entry. TeX will do line-breaking on it.
+ #1%
+ % The following is kluged 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{#2}%
+ \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.
+ \ #2% The page number ends the paragraph.
+ \fi%
+ \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu . \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 #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXbook, page 416.
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup
+ % Grab any single-column material above us.
+ \output = {\global\setbox\partialpage
+ =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}%
+ \eject
+ %
+ % Now switch to the double-column output routine.
+ \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 once.
+ %
+ % 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
+ \doublecolumnpagegoal
+}
+
+\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage}
+
+\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+ \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage
+ \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1}
+ \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3}
+ \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+ \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+}
+\def\doublecolumnpagegoal{%
+ \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@
+}
+\def\pagesofar{\unvbox\partialpage %
+ \hsize=\doublecolumnhsize % have to restore this since output routine
+ \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\doublecolumnout{%
+ \setbox5=\copy255
+ {\vbadness=10000 \doublecolumnsplit}
+ \ifvbox255
+ \setbox0=\vtop to\dimen@{\unvbox0}
+ \setbox2=\vtop to\dimen@{\unvbox2}
+ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty
+ \else
+ \setbox0=\vbox{\unvbox5}
+ \ifvbox0
+ \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ {\vbadness=10000
+ \loop \global\setbox5=\copy0
+ \setbox1=\vsplit5 to\dimen@
+ \setbox3=\vsplit5 to\dimen@
+ \ifvbox5 \global\advance\dimen@ by1pt \repeat
+ \setbox0=\vbox to\dimen@{\unvbox1}
+ \setbox2=\vbox to\dimen@{\unvbox3}
+ \global\setbox\partialpage=\vbox{\pagesofar}
+ \doublecolumnpagegoal
+ }
+ \fi
+ \fi
+}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\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}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\def\chapternofonts{%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\def\result{\realbackslash result}
+\def\equiv{\realbackslash equiv}
+\def\expansion{\realbackslash expansion}
+\def\print{\realbackslash print}
+\def\TeX{\realbackslash TeX}
+\def\dots{\realbackslash dots}
+\def\copyright{\realbackslash copyright}
+\def\tt{\realbackslash tt}
+\def\bf{\realbackslash bf }
+\def\w{\realbackslash w}
+\def\less{\realbackslash less}
+\def\gtr{\realbackslash gtr}
+\def\hat{\realbackslash hat}
+\def\char{\realbackslash char}
+\def\tclose##1{\realbackslash tclose {##1}}
+\def\code##1{\realbackslash code {##1}}
+\def\samp##1{\realbackslash samp {##1}}
+\def\r##1{\realbackslash r {##1}}
+\def\b##1{\realbackslash b {##1}}
+\def\key##1{\realbackslash key {##1}}
+\def\file##1{\realbackslash file {##1}}
+\def\kbd##1{\realbackslash kbd {##1}}
+% These are redefined because @smartitalic wouldn't work inside xdef.
+\def\i##1{\realbackslash i {##1}}
+\def\cite##1{\realbackslash cite {##1}}
+\def\var##1{\realbackslash var {##1}}
+\def\emph##1{\realbackslash emph {##1}}
+\def\dfn##1{\realbackslash dfn {##1}}
+}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/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
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \chapterzzz{#2}
+\or
+ \seczzz{#2}
+\or
+ \numberedsubseczzz{#2}
+\or
+ \numberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \chapterzzz{#2}
+ \else
+ \numberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \appendixzzz{#2}
+\or
+ \appendixsectionzzz{#2}
+\or
+ \appendixsubseczzz{#2}
+\or
+ \appendixsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \appendixzzz{#2}
+ \else
+ \appendixsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \unnumberedzzz{#2}
+\or
+ \unnumberedseczzz{#2}
+\or
+ \unnumberedsubseczzz{#2}
+\or
+ \unnumberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \unnumberedzzz{#2}
+ \else
+ \unnumberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry
+ {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}}
+
+\outer\def\top{\parsearg\unnumberedyyy}
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% 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 the <toks register>.
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}}
+
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appenixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry %
+ {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
+ {\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+ {\appendixletter}
+ {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% 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.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\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{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+\def\subheading{\parsearg\subsecheadingi}
+
+\def\subsubheading{\parsearg\subsubsecheadingi}
+
+% 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}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\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\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+ \pchapsepmacro
+ {%
+ \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #2\enspace #1}%
+ }%
+ \bigskip
+ \penalty5000
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\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\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+% @paragraphindent is defined for the Info formatting commands only.
+\let\paragraphindent=\comment
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1,
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
+\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+ % Perhaps make sssec fonts scaled
+ % magstep half
+\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
+\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\def\startcontents#1{%
+ \pagealignmacro
+ \immediate\closeout \contentsfile
+ \ifnum \pageno>0
+ \pageno = -1 % Request roman numbered pages.
+ \fi
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \unnumbchapmacro{#1}\def\thischapter{}%
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+}
+
+
+% Normal (long) toc.
+\outer\def\contents{%
+ \startcontents{Table of Contents}%
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+ \startcontents{Short Contents}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+ \rm
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% 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, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm Appendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+ % We typeset #1 in a box of constant width, regardless of the text of
+ % #1, so the chapter titles will come out aligned.
+ \setbox0 = \hbox{#1}%
+ \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+ %
+ % This space should be plenty, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in in \shortchapentry above.)
+ \advance\dimen0 by 1.1em
+ \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+ \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% 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 would want to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip\baselineskip
+ \begingroup
+ \chapentryfonts
+ \tocentry{#1}{\dopageno{#2}}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here. (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+%
+\def\tocentry#1#2{\begingroup
+ \hyphenpenalty = 10000
+ \entry{#1}{#2}%
+\endgroup}
+
+% 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}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% 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.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox \newbox\longdblarrowbox
+\newbox\pushcharbox \newbox\bullbox
+\newbox\equivbox \newbox\errorbox
+
+\let\ptexequiv = \equiv
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+% depth .1ex\hfil}
+%}
+
+\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}}
+
+% Adapted from the TeXbook's \boxit.
+{\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}
+
+\global\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}
+
+% The @error{} command.
+\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.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode 43=12
+\catcode`\"=12
+\catcode`\==12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\let\dots=\ptexdots
+\def\@{@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (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}
+
+% 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.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is. This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% 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{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \cartouche: draw rectangle w/rounded corners around argument
+\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
+
+\long\def\cartouche{%
+\begingroup
+ \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 18pt % allow for 3pt kerns on either
+% side, and for 6pt waste from
+% each corner char
+ \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
+ \hsize=\cartinner
+ \kern3pt
+ \begingroup
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+\def\Ecartouche{%
+ \endgroup
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+ \aboveenvbreak
+ \inENV % This group ends at the end of the body
+ \hfuzz = 12pt % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \singlespace
+ \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
+ \let\exdent=\nofillexdent
+ \let\nonarrowing=\relax
+ \fi
+}
+
+% To ending an @example-like environment, we first end the paragraph
+% (via \afterenvbreak's vertical glue), and then the group. That way we
+% keep the zero \parskip that the environments set -- \parskip glue
+% will be inserted at the beginning of the next paragraph in the
+% document, after the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}%
+
+% This macro is
+\def\lisp{\begingroup
+ \nonfillstart
+ \let\Elisp = \nonfillfinish
+ \tt
+ \rawbackslash % have \ input char produce \ char from current font
+ \gobble
+}
+
+% Define the \E... control sequence only if we are inside the
+% environment, so the error checking in \end will work.
+%
+% We must call \lisp last in the definition, since it reads the
+% return following the @example (or whatever) command.
+%
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% @smallexample and @smalllisp. This is not used unless the @smallbook
+% command is given. Originally contributed by Pavel@xerox.
+%
+\def\smalllispx{\begingroup
+ \nonfillstart
+ \let\Esmalllisp = \nonfillfinish
+ \let\Esmallexample = \nonfillfinish
+ %
+ % Smaller interline space and fonts for small examples.
+ \baselineskip 10pt
+ \indexfonts \tt
+ \rawbackslash % output the \ character from the current font
+ \gobble
+}
+
+% This is @display; same as @lisp except use roman font.
+%
+\def\display{\begingroup
+ \nonfillstart
+ \let\Edisplay = \nonfillfinish
+ \gobble
+}
+
+% This is @format; same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eformat = \nonfillfinish
+ \gobble
+}
+
+% @flushleft (same as @format) and @flushright.
+%
+\def\flushleft{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushleft = \nonfillfinish
+ \gobble
+}
+\def\flushright{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushright = \nonfillfinish
+ \advance\leftskip by 0pt plus 1fill
+ \gobble}
+
+% @quotation does normal linebreaking and narrows the margins.
+%
+\def\quotation{%
+\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\let\Equotation = \nonfillfinish
+% @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}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\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 = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% 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.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\dimen3=\rightskip
+\advance\dimen3 by -\defbodyindent
+\noindent %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1 %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody. It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+ \begingroup\inENV %
+ \medbreak %
+ % Define the end token that this defining construct specifies
+ % so that it will exit this group.
+ \def#1{\endgraf\endgroup\medbreak}%
+ \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+ \parindent=0in
+ \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+ \exdentamount=\defbodyindent
+ \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument. Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name. That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any). That's what this does, putting the result in \tptemp.
+%
+\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}%
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+ \removeemptybraces#2\relax
+ #1{\tptemp}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\functionparens
+\code{#1}%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type. #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\code{#1} #2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% #1 is the classification. #2 is the data type. #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+% at least some C++ text from working
+\defname {\code{#2} #3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Method on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type. #2 is the name.
+\def\deftypevarheader #1#2{%
+\doind {vr}{\code{#2}}% Make entry in variables index
+\begingroup\defname {\code{#1} #2}{Variable}%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
+\begingroup\defname {\code{#2} #3}{#1}
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+\def\appendixsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Yappendixletterandtype}}
+
+% \xref, \pxref, and \ref generate cross-references to specified points.
+% 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{see \xrefX[#1,,,,,,,]}
+\def\xref#1{See \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup%
+\def\printedmanual{\ignorespaces #5}%
+\def\printednodename{\ignorespaces #3}%
+%
+\setbox1=\hbox{\printedmanual}%
+\setbox0=\hbox{\printednodename}%
+\ifdim \wd0=0pt%
+% No printed node name was explicitly given.
+\ifx SETxref-automatic-section-title %
+% This line should make the actual chapter or 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\printednodename{\ignorespaces #1} \else%
+% We know the real title if we have the xref values.
+\ifhavexrefs \def\printednodename{\refx{#1-title}}%
+% Otherwise just copy the Info node name.
+\else \def\printednodename{\ignorespaces #1} \fi%
+\fi\def\printednodename{#1-title}%
+\else% This line just uses the node name.
+\def\printednodename{\ignorespaces #1}%
+\fi% ends \ifx SETxref-automatic-section-title
+\fi% ends \ifdim \wd0
+%
+%
+% 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 simply give the text of
+% the node name again, so it is as if TeX is seeing it for the first
+% time.
+\ifdim \wd1>0pt
+section ``\printednodename'' in \cite{\printedmanual}%
+\else%
+\turnoffactive%
+\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}%
+\fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \turnoffactive so that punctuation chars such as underscore
+% work in node names.
+\def\dosetq #1#2{{\let\folio=0 \turnoffactive%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 Chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% 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 % Non-3.0.
+\else
+ \def\linenumber{\the\inputlineno:\space}
+\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{%
+ \expandafter\ifx\csname X#1\endcsname\relax
+ % If not defined, say something at least.
+ $\langle$un\-de\-fined$\rangle$%
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \csname X#1\endcsname
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\ =\other
+\catcode `\^^L=\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
+\catcode 26=\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
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% `\+ does not work, so use 43.
+\catcode 43=\other
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
+\global\warnedobstrue
+\fi
+% Open the new aux file. Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% 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.
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only..
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \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}\/\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \footnotezzz
+}%
+
+% 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.
+%
+\long\gdef\footnotezzz#1{\insert\footins{%
+ % 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.
+ \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
+ %
+ % Hang the footnote text off the number.
+ \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
+ #1\strut}%
+}
+
+}%end \catcode `\@=11
+
+% 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
+ }%
+}
+
+% @| 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
+ }%
+ }%
+}
+
+% 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}
+
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+%\hsize = 6.5in
+\newdimen\defaultparindent \defaultparindent = 15pt
+\parindent = \defaultparindent
+\parskip 18pt plus 1pt
+\setleading{15pt}
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% 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. This makes it come to about 9pt for the 8.5x11 format.
+%
+\ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+\else
+ \emergencystretch = \hsize
+ \divide\emergencystretch by 45
+\fi
+
+% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25)
+\def\smallbook{
+
+% These values for secheadingskip and subsecheadingskip are
+% experiments. RJC 7 Aug 1992
+\global\secheadingskip = 17pt plus 6pt minus 3pt
+\global\subsecheadingskip = 14pt plus 6pt minus 3pt
+
+\global\lispnarrowing = 0.3in
+\setleading{12pt}
+\advance\topskip by -1cm
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+\global\contentsrightmargin=0pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{
+\global\tolerance=700
+\global\hfuzz=1pt
+\setleading{12pt}
+\global\parskip 15pt plus 1pt
+
+\global\vsize= 53\baselineskip
+\advance\vsize by \topskip
+%\global\hsize= 5.85in % A4 wide 10pt
+\global\hsize= 6.5in
+\global\outerhsize=\hsize
+\global\advance\outerhsize by 0.5in
+\global\outervsize=\vsize
+\global\advance\outervsize by 0.6in
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+}
+
+% 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
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, 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\the\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 \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+% \lvvmode is equivalent in function to \leavevmode.
+% Using \leavevmode runs into trouble when written out to
+% an index file due to the expansion of \leavevmode into ``\unhbox
+% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our
+% magic tricks with @.
+\def\lvvmode{\vbox to 0pt{}}
+
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+\def\turnoffactive{\let"=\normaldoublequote
+\let~=\normaltilde
+\let^=\normalcaret
+\let_=\normalunderscore
+\let|=\normalverticalbar
+\let<=\normalless
+\let>=\normalgreater
+\let+=\normalplus}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0 % Define control-q
+\catcode`\\=\active
+
+% 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.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special. The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c page-delimiter: "^\\\\message"
+@c End:
diff --git a/gnu/usr.bin/ptx/xmalloc.c b/gnu/usr.bin/ptx/xmalloc.c
new file mode 100644
index 000000000000..58a81b5abbce
--- /dev/null
+++ b/gnu/usr.bin/ptx/xmalloc.c
@@ -0,0 +1,88 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+#if __STDC__ && defined (HAVE_VPRINTF)
+void error (int, int, char const *, ...);
+#else
+void error ();
+#endif
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+VOID *
+xmalloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = malloc (n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc.
+ If N is 0, run free and return NULL. */
+
+VOID *
+xrealloc (p, n)
+ VOID *p;
+ size_t n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ if (n == 0)
+ {
+ free (p);
+ return 0;
+ }
+ p = realloc (p, n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
diff --git a/gnu/usr.bin/rcs/co/co.1 b/gnu/usr.bin/rcs/co/co.1
index c97ec1eef032..41d774348808 100644
--- a/gnu/usr.bin/rcs/co/co.1
+++ b/gnu/usr.bin/rcs/co/co.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: co.1,v 1.1.1.1 1993/06/18 04:22:11 jkh Exp $
+.Id $Id: co.1,v 1.2 1994/05/14 07:00:09 rgrimes Exp $
.ds g \&\s-1UTC\s0
.ds r \&\s-1RCS\s0
.if n .ds - \%--
@@ -141,6 +141,14 @@ See also
.SM "FILE MODES"
below.
.TP
+.B \-K\f2keywordlist\fP
+Exclude or include keyword expansion when checking out a file.
+By default all keywords are expanded, you can turn individual
+keywords off with
+.BR \-K\f2eKeyword\fP
+or on with
+.BR \-K\f2iKeyword\fP .
+.TP
.B \-kkv
Generate keyword strings using the default form, e.g.\&
.B "$\&Revision: \*(Rv $"
diff --git a/gnu/usr.bin/rcs/co/co.c b/gnu/usr.bin/rcs/co/co.c
index efa625b7b3ea..6a5aee4fd864 100644
--- a/gnu/usr.bin/rcs/co/co.c
+++ b/gnu/usr.bin/rcs/co/co.c
@@ -34,6 +34,11 @@ Report problems and direct all questions to:
/* $Log: co.c,v $
+ * Revision 1.2 1994/05/14 07:00:10 rgrimes
+ * Add new option -K from David Dawes that allows you to turn on and off
+ * specific keyword substitution during a rcs co command.
+ * Add the new keyword FreeBSD that is IDENTICAL in operation to $Id$.
+ *
* Revision 1.1.1.1 1993/06/18 04:22:11 jkh
* Updated GNU utilities
*
@@ -155,7 +160,7 @@ static void cleanup P((void));
static char const quietarg[] = "-q";
-static char const *expandarg, *join, *suffixarg, *versionarg;
+static char const *expandarg, *join, *suffixarg, *versionarg, *incexcarg;
static char const *joinlist[joinlength]; /* revisions to be joined */
static FILE *neworkptr;
static int exitstatus;
@@ -167,7 +172,7 @@ static struct hshentries *gendeltas; /* deltas to be generated */
static struct hshentry *targetdelta; /* final delta to be generated */
static struct stat workstat;
-mainProg(coId, "co", "$Id: co.c,v 1.1.1.1 1993/06/18 04:22:11 jkh Exp $")
+mainProg(coId, "co", "$Id: co.c,v 1.2 1994/05/14 07:00:10 rgrimes Exp $")
{
static char const cmdusage[] =
"\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ...";
@@ -273,6 +278,10 @@ mainProg(coId, "co", "$Id: co.c,v 1.1.1.1 1993/06/18 04:22:11 jkh Exp $")
setRCSversion(versionarg);
break;
+ case 'K': /* set keyword inclusions/exclusions */
+ incexcarg = *argv;
+ setIncExc(incexcarg);
+ break;
case 'k': /* set keyword expand mode */
expandarg = *argv;
if (0 <= expmode) redefined('k');
diff --git a/gnu/usr.bin/rcs/lib/Makefile b/gnu/usr.bin/rcs/lib/Makefile
index 8428686b10ac..a69000b5b2c5 100644
--- a/gnu/usr.bin/rcs/lib/Makefile
+++ b/gnu/usr.bin/rcs/lib/Makefile
@@ -1,6 +1,6 @@
# Define FSYNC_ALL to get slower but safer writes in case of crashes in
# the middle of CVS/RCS changes
-CFLAGS += -DFSYNC_ALL
+#CFLAGS += -DFSYNC_ALL
LIB = rcs
SRCS = maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c \
diff --git a/gnu/usr.bin/rcs/lib/rcsbase.h b/gnu/usr.bin/rcs/lib/rcsbase.h
index 4f320465c3f1..746d273dabaf 100644
--- a/gnu/usr.bin/rcs/lib/rcsbase.h
+++ b/gnu/usr.bin/rcs/lib/rcsbase.h
@@ -2,7 +2,7 @@
/*
* RCS common definitions and data structures
*/
-#define RCSBASE "$Id: rcsbase.h,v 1.1.1.1 1993/06/18 04:22:13 jkh Exp $"
+#define RCSBASE "$Id: rcsbase.h,v 1.2 1994/05/14 07:00:20 rgrimes Exp $"
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
Copyright 1990, 1991 by Paul Eggert
@@ -43,6 +43,11 @@ Report problems and direct all questions to:
/* $Log: rcsbase.h,v $
+ * Revision 1.2 1994/05/14 07:00:20 rgrimes
+ * Add new option -K from David Dawes that allows you to turn on and off
+ * specific keyword substitution during a rcs co command.
+ * Add the new keyword FreeBSD that is IDENTICAL in operation to $Id$.
+ *
* Revision 1.1.1.1 1993/06/18 04:22:13 jkh
* Updated GNU utilities
*
@@ -383,10 +388,11 @@ struct assoc {
#define REVISION "Revision"
#define SOURCE "Source"
#define STATE "State"
+#define FREEBSD "FreeBSD"
#define keylength 8 /* max length of any of the above keywords */
enum markers { Nomatch, Author, Date, Header, Id,
- Locker, Log, RCSfile, Revision, Source, State };
+ Locker, Log, RCSfile, Revision, Source, State, FreeBSD };
/* This must be in the same order as rcskeys.c's Keyword[] array. */
#define DELNUMFORM "\n\n%s\n%s\n"
diff --git a/gnu/usr.bin/rcs/lib/rcsedit.c b/gnu/usr.bin/rcs/lib/rcsedit.c
index 218a8751d16c..3d85320d63a7 100644
--- a/gnu/usr.bin/rcs/lib/rcsedit.c
+++ b/gnu/usr.bin/rcs/lib/rcsedit.c
@@ -36,6 +36,11 @@ Report problems and direct all questions to:
/* $Log: rcsedit.c,v $
+ * Revision 1.2 1994/05/14 07:00:22 rgrimes
+ * Add new option -K from David Dawes that allows you to turn on and off
+ * specific keyword substitution during a rcs co command.
+ * Add the new keyword FreeBSD that is IDENTICAL in operation to $Id$.
+ *
* Revision 1.1.1.1 1993/06/18 04:22:12 jkh
* Updated GNU utilities
*
@@ -157,7 +162,7 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(editId, "$Id: rcsedit.c,v 1.1.1.1 1993/06/18 04:22:12 jkh Exp $")
+libId(editId, "$Id: rcsedit.c,v 1.2 1994/05/14 07:00:22 rgrimes Exp $")
static void keyreplace P((enum markers,struct hshentry const*,FILE*));
@@ -962,10 +967,14 @@ keyreplace(marker,delta,out)
case Date:
aputs(date2str(date,datebuf), out);
break;
+ /*
+ * The FreeBSD keyword is identical to Id.
+ */
+ case FreeBSD:
case Id:
case Header:
aprintf(out, "%s %s %s %s %s",
- marker==Id || RCSv<VERSION(4)
+ marker==Id || marker==FreeBSD || RCSv<VERSION(4)
? basename(RCSfilename)
: getfullRCSname(),
delta->num,
diff --git a/gnu/usr.bin/rcs/lib/rcskeys.c b/gnu/usr.bin/rcs/lib/rcskeys.c
index a6e84f64721d..76671226645d 100644
--- a/gnu/usr.bin/rcs/lib/rcskeys.c
+++ b/gnu/usr.bin/rcs/lib/rcskeys.c
@@ -31,6 +31,20 @@ Report problems and direct all questions to:
/* $Log: rcskeys.c,v $
+ * Revision 1.4 1994/06/22 00:51:42 rgrimes
+ * Fix serious off by one error for FreeBSD keyword, this has been driving
+ * me nuts as it was on by default and that is NOT what I wanted.
+ *
+ * Revision 1.3 1994/05/15 22:15:14 rgrimes
+ * To truely have the OLD behavior of RCS by default make the expansion
+ * of $FreeBSD$ false by default. This should keep them out
+ * of the pre 2.x repository. (Or at least make them useless in it).
+ *
+ * Revision 1.2 1994/05/14 07:00:23 rgrimes
+ * Add new option -K from David Dawes that allows you to turn on and off
+ * specific keyword substitution during a rcs co command.
+ * Add the new keyword FreeBSD that is IDENTICAL in operation to $Id: rcskeys.c,v 1.4 1994/06/22 00:51:42 rgrimes Exp $.
+ *
* Revision 1.1.1.1 1993/06/18 04:22:12 jkh
* Updated GNU utilities
*
@@ -63,17 +77,26 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(keysId, "$Id: rcskeys.c,v 1.1.1.1 1993/06/18 04:22:12 jkh Exp $")
+libId(keysId, "$Id: rcskeys.c,v 1.4 1994/06/22 00:51:42 rgrimes Exp $")
char const *const Keyword[] = {
/* This must be in the same order as rcsbase.h's enum markers type. */
nil,
AUTHOR, DATE, HEADER, IDH,
- LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE
+ LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE,
+ FREEBSD
};
+/* Expand all keywords by default */
+
+static int ExpandKeyword[] = {
+ nil,
+ true, true, true, true,
+ true, true, true, true, true, true,
+ false
+};
enum markers
trymatch(string)
@@ -86,6 +109,8 @@ trymatch(string)
register int j;
register char const *p, *s;
for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) {
+ if (!ExpandKeyword[j])
+ continue;
/* try next keyword */
p = Keyword[j];
s = string;
@@ -103,3 +128,35 @@ trymatch(string)
return(Nomatch);
}
+
+setIncExc(arg)
+ char *arg;
+/* Sets up the ExpandKeyword table according to command-line flags */
+{
+ char *key;
+ int include = 0, j;
+
+ arg += 2;
+ switch (*arg++) {
+ case 'e':
+ include = false;
+ break;
+ case 'i':
+ include = true;
+ break;
+ default:
+ return(false);
+ }
+ if (include)
+ for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); )
+ ExpandKeyword[j] = false;
+ key = strtok(arg, ",");
+ while (key) {
+ for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); )
+ if (!strcmp(key, Keyword[j]))
+ ExpandKeyword[j] = include;
+ key = strtok(NULL, ",");
+ }
+ return(true);
+}
+
diff --git a/gnu/usr.bin/rcs/rlog/rlog.1 b/gnu/usr.bin/rcs/rlog/rlog.1
index aa3546c37f27..bffd2c307a9e 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.1
+++ b/gnu/usr.bin/rcs/rlog/rlog.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rlog.1,v 1.1.1.1 1993/06/18 04:22:17 jkh Exp $
+.Id $Id: rlog.1,v 1.3 1994/05/12 00:37:57 phk Exp $
.ds g \&\s-1UTC\s0
.ds r \&\s-1RCS\s0
.if n .ds - \%--
@@ -54,6 +54,10 @@ Print only the name of the \*r file.
This is convenient for translating a
working pathname into an \*r pathname.
.TP
+.BI \-v "[string]"
+Print only the working pathname and tip-revision.
+The optional string is prepended to the outputline.
+.TP
.B \-h
Print only the \*r pathname, working pathname, head,
default branch, access list, locks,
diff --git a/gnu/usr.bin/rcs/rlog/rlog.c b/gnu/usr.bin/rcs/rlog/rlog.c
index 0195d0cb99b9..78f5a3dd36ea 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.c
+++ b/gnu/usr.bin/rcs/rlog/rlog.c
@@ -36,6 +36,15 @@ Report problems and direct all questions to:
/* $Log: rlog.c,v $
+ * Revision 1.5 1994/05/12 00:42:59 phk
+ * typo.
+ *
+ * Revision 1.4 1994/05/12 00:37:59 phk
+ * made -v produce tip-revision, which was what I wanted in the first place...
+ *
+ * Revision 1.3 1994/05/11 22:39:44 phk
+ * Added -v option to rlog. This gives a quick way to get a list of versions.
+ *
* Revision 1.2 1993/08/06 16:47:16 nate
* Have rlog output be much easier to parse. (Added one line which is not
* used by any CVS/RCS commands)
@@ -198,10 +207,10 @@ static struct lockers *lockerlist;
static struct stateattri *statelist;
-mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.2 1993/08/06 16:47:16 nate Exp $")
+mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.5 1994/05/12 00:42:59 phk Exp $")
{
static char const cmdusage[] =
- "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
+ "\nrlog usage: rlog -{bhLRt} [-v[string]] -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
register FILE *out;
char *a, **newargv;
@@ -214,11 +223,14 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.2 1993/08/06 16:47:16 nate Exp $")
struct lock const *currlock;
int descflag, selectflag;
int onlylockflag; /* print only files with locks */
+ int versionlist;
+ char *vstring;
int onlyRCSflag; /* print only RCS file name */
unsigned revno;
descflag = selectflag = true;
- onlylockflag = onlyRCSflag = false;
+ versionlist = onlylockflag = onlyRCSflag = false;
+ vstring=0;
out = stdout;
suffixes = X_DEFAULT;
@@ -281,6 +293,11 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.2 1993/08/06 16:47:16 nate Exp $")
setRCSversion(*argv);
break;
+ case 'v':
+ versionlist = true;
+ vstring = a;
+ break;
+
default:
faterror("unknown option: %s%s", *argv, cmdusage);
@@ -330,6 +347,12 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.2 1993/08/06 16:47:16 nate Exp $")
if (onlylockflag && !Locks)
continue;
+ if ( versionlist ) {
+ gettree();
+ aprintf(out, "%s%s %s\n", vstring, workfilename, tiprev());
+ continue;
+ }
+
if ( onlyRCSflag ) {
aprintf(out, "%s\n", RCSfilename);
continue;
diff --git a/gnu/usr.bin/tar/Makefile b/gnu/usr.bin/tar/Makefile
index 69a1f52cf9d3..cab7e00f96fd 100644
--- a/gnu/usr.bin/tar/Makefile
+++ b/gnu/usr.bin/tar/Makefile
@@ -10,6 +10,7 @@ CFLAGS+= -DHAVE_VPRINTF=1 -DNEEDPAD -I${.CURDIR}
CFLAGS+= -DDEF_AR_FILE=\"/dev/rst0\" -DDEFBLOCKING=20
CLEANFILES+=y.tab.h
NOMAN=noman
+NOSHARED=yes
.include <bsd.prog.mk>
.include "../../usr.bin/Makefile.inc"
diff --git a/gnu/usr.bin/tar/extract.c b/gnu/usr.bin/tar/extract.c
index d162cab04ec6..57f82227d886 100644
--- a/gnu/usr.bin/tar/extract.c
+++ b/gnu/usr.bin/tar/extract.c
@@ -310,6 +310,14 @@ extract_archive ()
fd = 1;
goto extract_file;
}
+
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
#ifdef O_CTG
/*
* Contiguous files (on the Masscomp) have to specify
@@ -556,6 +564,13 @@ extract_archive ()
{
struct stat st1, st2;
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = link (current_link_name, skipcrud + current_file_name);
if (check == 0)
@@ -578,6 +593,13 @@ extract_archive ()
#ifdef S_ISLNK
case LF_SYMLINK:
again_symlink:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = symlink (current_link_name,
skipcrud + current_file_name);
/* FIXME, don't worry uid, gid, etc... */
@@ -602,6 +624,13 @@ extract_archive ()
#endif
#if defined(S_IFCHR) || defined(S_IFBLK)
make_node:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = mknod (current_file_name + skipcrud,
(int) hstat.st_mode, (int) hstat.st_rdev);
if (check != 0)
@@ -619,6 +648,13 @@ extract_archive ()
/* If local system doesn't support FIFOs, use default case */
case LF_FIFO:
make_fifo:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = mkfifo (current_file_name + skipcrud,
(int) hstat.st_mode);
if (check != 0)
diff --git a/gnu/usr.bin/tar/tar.c b/gnu/usr.bin/tar/tar.c
index 938258233980..ec2c3d1bb8d7 100644
--- a/gnu/usr.bin/tar/tar.c
+++ b/gnu/usr.bin/tar/tar.c
@@ -181,6 +181,8 @@ struct option long_options[] =
{"force-local", 0, &f_force_local, 1},
{"atime-preserve", 0, &f_atime_preserve, 1},
+ {"unlink", 0, &f_unlink, 1},
+
{0, 0, 0, 0}
};
@@ -757,6 +759,7 @@ Other options:\n\
filter the archive through PROG (which must accept -d)\n\
--block-compress block the output of compression program for tapes\n\
-[0-7][lmh] specify drive and density\n\
+--unlink unlink files before creating them\n\
", stdout);
}
diff --git a/gnu/usr.bin/tar/tar.h b/gnu/usr.bin/tar/tar.h
index c3fec78743bb..46d29d81dd0e 100644
--- a/gnu/usr.bin/tar/tar.h
+++ b/gnu/usr.bin/tar/tar.h
@@ -231,6 +231,7 @@ TAR_EXTERN char *f_volno_file; /* --volno-file */
TAR_EXTERN int f_force_local; /* --force-local */
TAR_EXTERN int f_atime_preserve;/* --atime-preserve */
TAR_EXTERN int f_compress_block; /* --compress-block */
+TAR_EXTERN int f_unlink; /* --unlink */
/*
* We default to Unix Standard format rather than 4.2BSD tar format.
diff --git a/include/Makefile b/include/Makefile
index a00e9575c3b0..545998a239d5 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -15,7 +15,7 @@ FILES= a.out.h ar.h assert.h bitstring.h ctype.h db.h dirent.h disktab.h \
paths.h pwd.h queue.h ranlib.h regex.h resolv.h setjmp.h \
sgtty.h stab.h stdarg.h stddef.h stdio.h stdlib.h string.h strings.h \
struct.h sysexits.h time.h ttyent.h tzfile.h unistd.h utime.h utmp.h \
- varargs.h vis.h
+ varargs.h vis.h octype.h rune.h runetype.h skey.h
MFILES= float.h floatingpoint.h frame.h
LFILES= errno.h fcntl.h signal.h syslog.h syscall.h termios.h
diff --git a/include/ar.h b/include/ar.h
index 7aacb441cfd3..19bc23fbb2bc 100644
--- a/include/ar.h
+++ b/include/ar.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: ar.h,v 1.1.1.1.2.1 1994/05/04 07:37:40 rgrimes Exp $
+ * $Id: ar.h,v 1.2 1994/05/04 08:08:20 rgrimes Exp $
*/
/*-
* Copyright (c) 1991 The Regents of the University of California.
diff --git a/include/assert.h b/include/assert.h
index 99b1d8320282..9ffd6c6e2549 100644
--- a/include/assert.h
+++ b/include/assert.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: assert.h,v 1.2.2.1 1994/05/04 07:37:42 rgrimes Exp $
+ * $Id: assert.h,v 1.3 1994/05/04 08:08:25 rgrimes Exp $
*/
/*-
* Copyright (c) 1992 The Regents of the University of California.
diff --git a/include/ctype.h b/include/ctype.h
index cdfddcbb81b2..f3000073c259 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -5,11 +5,14 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: ctype.h,v 1.2.2.1 1994/05/04 07:37:44 rgrimes Exp $
+ * $Id: ctype.h,v 1.6 1994/05/04 08:50:12 rgrimes Exp $
*/
/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,53 +42,112 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)ctype.h 5.3 (Berkeley) 4/3/91
+ * @(#)ctype.h 8.1 (Berkeley) 6/6/93
*/
-#ifndef _CTYPE_H_
+#ifndef _CTYPE_H_
#define _CTYPE_H_
-#include <sys/cdefs.h>
+#ifndef _ANSI_SOURCE
+#include <runetype.h>
+#endif
+
+#define _A 0x00000100L /* Alpha */
+#define _C 0x00000200L /* Control */
+#define _D 0x00000400L /* Digit */
+#define _G 0x00000800L /* Graph */
+#define _L 0x00001000L /* Lower */
+#define _P 0x00002000L /* Punct */
+#define _S 0x00004000L /* Space */
+#define _U 0x00008000L /* Upper */
+#define _X 0x00010000L /* X digit */
+#define _B 0x00020000L /* Blank */
+#define _R 0x00040000L /* Print */
+#define _I 0x00080000L /* Ideogram */
+#define _T 0x00100000L /* Special */
+#define _Q 0x00200000L /* Phonogram */
-#define _U 0x01
-#define _L 0x02
-#define _N 0x04
-#define _S 0x08
-#define _P 0x10
-#define _C 0x20
-#define _X 0x40
-#define _B 0x80
+#define isalnum(c) __istype((c), (_A|_D))
+#define isalpha(c) __istype((c), _A)
+#define iscntrl(c) __istype((c), _C)
+#define isdigit(c) __isctype((c), _D) /* ANSI -- locale independent */
+#define isgraph(c) __istype((c), _G)
+#define islower(c) __istype((c), _L)
+#define isprint(c) __istype((c), _R)
+#define ispunct(c) __istype((c), _P)
+#define isspace(c) __istype((c), _S)
+#define isupper(c) __istype((c), _U)
+#define isxdigit(c) __isctype((c), _X) /* ANSI -- locale independent */
-extern char _ctype_[];
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define isascii(c) ((c & ~0x7F) == 0)
+#define toascii(c) ((c) & 0x7F)
+#define digittoint(c) __istype((c), 0xFF)
+#define isideogram(c) __istype((c), _I)
+#define isphonogram(c) __istype((c), _Q)
+#define isspecial(c) __istype((c), _T)
+#define isblank(c) __istype((c), _B)
+#define isrune(c) __istype((c), 0xFFFFFF00L)
+#define isnumber(c) __istype((c), _D)
+#define ishexnumber(c) __istype((c), _X)
+#endif
+/* See comments in <machine/ansi.h> about _BSD_RUNE_T_. */
__BEGIN_DECLS
-int isdigit __P((int));
-int islower __P((int));
-int isspace __P((int));
-int ispunkt __P((int));
-int isupper __P((int));
-int isalpha __P((int));
-int isxdigit __P((int));
-int isalnum __P((int));
-int isprint __P((int));
-int isgraph __P((int));
-int iscntrl __P((int));
-int toupper __P((int));
-int tolower __P((int));
+unsigned long ___runetype __P((_BSD_RUNE_T_));
+_BSD_RUNE_T_ ___tolower __P((_BSD_RUNE_T_));
+_BSD_RUNE_T_ ___toupper __P((_BSD_RUNE_T_));
__END_DECLS
-#define isdigit(c) ((_ctype_ + 1)[c] & _N)
-#define islower(c) ((_ctype_ + 1)[c] & _L)
-#define isspace(c) ((_ctype_ + 1)[c] & _S)
-#define ispunct(c) ((_ctype_ + 1)[c] & _P)
-#define isupper(c) ((_ctype_ + 1)[c] & _U)
-#define isalpha(c) ((_ctype_ + 1)[c] & (_U|_L))
-#define isxdigit(c) ((_ctype_ + 1)[c] & (_N|_X))
-#define isalnum(c) ((_ctype_ + 1)[c] & (_U|_L|_N))
-#define isprint(c) ((_ctype_ + 1)[c] & (_P|_U|_L|_N|_B))
-#define isgraph(c) ((_ctype_ + 1)[c] & (_P|_U|_L|_N))
-#define iscntrl(c) ((_ctype_ + 1)[c] & _C)
-#define isascii(c) ((unsigned)(c) <= 0177)
-#define toascii(c) ((c) & 0177)
+/*
+ * If your compiler supports prototypes and inline functions,
+ * #define _USE_CTYPE_INLINE_. Otherwise, use the C library
+ * functions.
+ */
+#if !defined(_USE_CTYPE_CLIBRARY_) && defined(__GNUC__) || defined(__cplusplus)
+#define _USE_CTYPE_INLINE_ 1
+#endif
+
+#if defined(_USE_CTYPE_INLINE_)
+static __inline__ int
+__istype(_BSD_RUNE_T_ __c, unsigned long __f)
+{
+ return((((__c & _CRMASK) ? ___runetype(__c) :
+ _CurrentRuneLocale->runetype[__c]) & __f) ? 1 : 0);
+}
+
+static __inline__ int
+__isctype(_BSD_RUNE_T_ __c, unsigned long __f)
+{
+ return((((__c & _CRMASK) ? 0 :
+ _DefaultRuneLocale.runetype[__c]) & __f) ? 1 : 0);
+}
+
+/* _ANSI_LIBRARY is defined by lib/libc/gen/isctype.c. */
+#if !defined(_ANSI_LIBRARY)
+static __inline__ _BSD_RUNE_T_
+toupper(_BSD_RUNE_T_ __c)
+{
+ return((__c & _CRMASK) ?
+ ___toupper(__c) : _CurrentRuneLocale->mapupper[__c]);
+}
+
+static __inline__ _BSD_RUNE_T_
+tolower(_BSD_RUNE_T_ __c)
+{
+ return((__c & _CRMASK) ?
+ ___tolower(__c) : _CurrentRuneLocale->maplower[__c]);
+}
+#endif /* !_ANSI_LIBRARY */
+
+#else /* !_USE_CTYPE_INLINE_ */
+
+__BEGIN_DECLS
+int __istype __P((_BSD_RUNE_T_, unsigned long));
+int __isctype __P((_BSD_RUNE_T_, unsigned long));
+_BSD_RUNE_T_ toupper __P((_BSD_RUNE_T_));
+_BSD_RUNE_T_ tolower __P((_BSD_RUNE_T_));
+__END_DECLS
+#endif /* _USE_CTYPE_INLINE_ */
#endif /* !_CTYPE_H_ */
diff --git a/include/grp.h b/include/grp.h
index 1a9afba0a521..ef2e60e183bd 100644
--- a/include/grp.h
+++ b/include/grp.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: grp.h,v 1.2.2.1 1994/05/04 07:37:45 rgrimes Exp $
+ * $Id: grp.h,v 1.3 1994/05/04 08:08:29 rgrimes Exp $
*/
/*-
* Copyright (c) 1989 The Regents of the University of California.
diff --git a/include/kvm.h b/include/kvm.h
index 5be440242ec1..8793b3506db9 100644
--- a/include/kvm.h
+++ b/include/kvm.h
@@ -36,10 +36,6 @@
#ifndef _KVM_H_
#define _KVM_H_
-/* Default version symbol. */
-#define VRS_SYM "_version"
-#define VRS_KEY "VERSION"
-
#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/include/nlist.h b/include/nlist.h
index 1191e7a9d7f1..607b024aed0f 100644
--- a/include/nlist.h
+++ b/include/nlist.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: nlist.h,v 1.2.2.1 1994/05/04 07:37:49 rgrimes Exp $
+ * $Id: nlist.h,v 1.3 1994/05/04 08:08:32 rgrimes Exp $
*/
/*-
* Copyright (c) 1991 The Regents of the University of California.
diff --git a/include/octype.h b/include/octype.h
new file mode 100644
index 000000000000..b7d292c3e670
--- /dev/null
+++ b/include/octype.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ *
+ * @(#)ctype.h 5.3 (Berkeley) 4/3/91
+ */
+
+#ifndef _CTYPE_H_
+#define _CTYPE_H_
+
+#include <sys/cdefs.h>
+
+#define _U 0x01
+#define _L 0x02
+#define _N 0x04
+#define _S 0x08
+#define _P 0x10
+#define _C 0x20
+#define _X 0x40
+#define _B 0x80
+
+extern char _ctype_[];
+
+__BEGIN_DECLS
+int isdigit __P((int));
+int islower __P((int));
+int isspace __P((int));
+int ispunkt __P((int));
+int isupper __P((int));
+int isalpha __P((int));
+int isxdigit __P((int));
+int isalnum __P((int));
+int isprint __P((int));
+int isgraph __P((int));
+int iscntrl __P((int));
+int toupper __P((int));
+int tolower __P((int));
+__END_DECLS
+
+#define isdigit(c) ((_ctype_ + 1)[c] & _N)
+#define islower(c) ((_ctype_ + 1)[c] & _L)
+#define isspace(c) ((_ctype_ + 1)[c] & _S)
+#define ispunct(c) ((_ctype_ + 1)[c] & _P)
+#define isupper(c) ((_ctype_ + 1)[c] & _U)
+#define isalpha(c) ((_ctype_ + 1)[c] & (_U|_L))
+#define isxdigit(c) ((_ctype_ + 1)[c] & (_N|_X))
+#define isalnum(c) ((_ctype_ + 1)[c] & (_U|_L|_N))
+#define isprint(c) ((_ctype_ + 1)[c] & (_P|_U|_L|_N|_B))
+#define isgraph(c) ((_ctype_ + 1)[c] & (_P|_U|_L|_N))
+#define iscntrl(c) ((_ctype_ + 1)[c] & _C)
+#define isascii(c) ((unsigned)(c) <= 0177)
+#define toascii(c) ((c) & 0177)
+
+#endif /* !_CTYPE_H_ */
diff --git a/include/protocols/dumprestore.h b/include/protocols/dumprestore.h
index ff6d868be4d6..12f9432fab26 100644
--- a/include/protocols/dumprestore.h
+++ b/include/protocols/dumprestore.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: dumprestore.h,v 1.1.1.1.2.1 1994/05/04 07:38:27 rgrimes Exp $
+ * $Id: dumprestore.h,v 1.2 1994/05/04 08:09:11 rgrimes Exp $
*/
/*
* Copyright (c) 1980 Regents of the University of California.
diff --git a/include/pwd.h b/include/pwd.h
index 7775f58ab0ee..19e56bc38e3b 100644
--- a/include/pwd.h
+++ b/include/pwd.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: pwd.h,v 1.3.2.1 1994/05/04 07:37:52 rgrimes Exp $
+ * $Id: pwd.h,v 1.4 1994/05/04 08:08:35 rgrimes Exp $
*/
/*-
* Copyright (c) 1989 The Regents of the University of California.
diff --git a/include/rpcsvc/Makefile b/include/rpcsvc/Makefile
index 8611daefde2a..e066a09155c3 100644
--- a/include/rpcsvc/Makefile
+++ b/include/rpcsvc/Makefile
@@ -1,5 +1,5 @@
# from: @(#)Makefile 2.3 88/08/11 4.0 RPCSRC
-# $Id: Makefile,v 1.1 1993/09/14 17:42:40 jtc Exp $
+# $Id: Makefile,v 1.2 1994/06/07 15:53:21 guido Exp $
.SUFFIXES: .x
@@ -32,6 +32,6 @@ install: all
.x.h:
@echo generating $@...
- @PWD=`pwd` ; cd ${.CURDIR} ; ${RPCCOM} -h $*.x -o $$PWD/$@
+ @CURPWD=`pwd` ; cd ${.CURDIR} ; ${RPCCOM} -h $*.x -o $$CURPWD/$@
.include <bsd.prog.mk>
diff --git a/include/rune.h b/include/rune.h
new file mode 100644
index 000000000000..c1e2b88b4595
--- /dev/null
+++ b/include/rune.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ *
+ * @(#)rune.h 8.1 (Berkeley) 6/27/93
+ */
+
+#ifndef _RUNE_H_
+#define _RUNE_H_
+
+#include <runetype.h>
+#include <stdio.h>
+
+#define _PATH_LOCALE "/usr/share/locale"
+
+#define _INVALID_RUNE _CurrentRuneLocale->invalid_rune
+
+#define __sgetrune _CurrentRuneLocale->sgetrune
+#define __sputrune _CurrentRuneLocale->sputrune
+
+#define sgetrune(s, n, r) (*__sgetrune)((s), (n), (r))
+#define sputrune(c, s, n, r) (*__sputrune)((c), (s), (n), (r))
+
+__BEGIN_DECLS
+char *mbrune __P((const char *, rune_t));
+char *mbrrune __P((const char *, rune_t));
+char *mbmb __P((const char *, char *));
+long fgetrune __P((FILE *));
+int fputrune __P((rune_t, FILE *));
+int fungetrune __P((rune_t, FILE *));
+int setrunelocale __P((char *));
+void setinvalidrune __P((rune_t));
+__END_DECLS
+
+#endif /*! _RUNE_H_ */
diff --git a/include/runetype.h b/include/runetype.h
new file mode 100644
index 000000000000..4bce6588b8ba
--- /dev/null
+++ b/include/runetype.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ *
+ * @(#)runetype.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _RUNETYPE_H_
+#define _RUNETYPE_H_
+
+#include <machine/ansi.h>
+#include <sys/cdefs.h>
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ rune_t;
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
+#endif
+
+#define _CACHED_RUNES (1 <<8 ) /* Must be a power of 2 */
+#define _CRMASK (~(_CACHED_RUNES - 1))
+
+/*
+ * The lower 8 bits of runetype[] contain the digit value of the rune.
+ */
+typedef struct {
+ rune_t min; /* First rune of the range */
+ rune_t max; /* Last rune (inclusive) of the range */
+ rune_t map; /* What first maps to in maps */
+ unsigned long *types; /* Array of types in range */
+} _RuneEntry;
+
+typedef struct {
+ int nranges; /* Number of ranges stored */
+ _RuneEntry *ranges; /* Pointer to the ranges */
+} _RuneRange;
+
+typedef struct {
+ char magic[8]; /* Magic saying what version we are */
+ char encoding[32]; /* ASCII name of this encoding */
+
+ rune_t (*sgetrune)
+ __P((const char *, unsigned int, char const **));
+ int (*sputrune)
+ __P((rune_t, char *, unsigned int, char **));
+ rune_t invalid_rune;
+
+ unsigned long runetype[_CACHED_RUNES];
+ rune_t maplower[_CACHED_RUNES];
+ rune_t mapupper[_CACHED_RUNES];
+
+ /*
+ * The following are to deal with Runes larger than _CACHED_RUNES - 1.
+ * Their data is actually contiguous with this structure so as to make
+ * it easier to read/write from/to disk.
+ */
+ _RuneRange runetype_ext;
+ _RuneRange maplower_ext;
+ _RuneRange mapupper_ext;
+
+ void *variable; /* Data which depends on the encoding */
+ int variable_len; /* how long that data is */
+} _RuneLocale;
+
+#define _RUNE_MAGIC_1 "RuneMagi" /* Indicates version 0 of RuneLocale */
+
+extern _RuneLocale _DefaultRuneLocale;
+extern _RuneLocale *_CurrentRuneLocale;
+
+#endif /* !_RUNETYPE_H_ */
diff --git a/include/setjmp.h b/include/setjmp.h
index 7bf4e85693ee..2ef7b86110a2 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: setjmp.h,v 1.2.2.1 1994/05/04 07:37:56 rgrimes Exp $
+ * $Id: setjmp.h,v 1.3 1994/05/04 08:08:38 rgrimes Exp $
*/
/*-
* Copyright (c) 1990 The Regents of the University of California.
diff --git a/include/skey.h b/include/skey.h
new file mode 100644
index 000000000000..030e46c41c46
--- /dev/null
+++ b/include/skey.h
@@ -0,0 +1,36 @@
+#ifndef _SKEY_H_
+#define _SKEY_H_
+
+#include <sys/cdefs.h>
+
+/* Server-side data structure for reading keys file during login */
+struct skey {
+ FILE *keyfile;
+ char buf[256];
+ char *logname;
+ int n;
+ char *seed;
+ char *val;
+ long recstart; /*needed so reread of buffer is efficient*/
+
+
+};
+
+/* Client-side structure for scanning data stream for challenge */
+struct mc {
+ char buf[256];
+ int skip;
+ int cnt;
+};
+
+void f __P((char *x));
+int keycrunch __P((char *result,char *seed,char *passwd));
+char *btoe __P((char *engout,char *c));
+char *put8 __P((char *out,char *s));
+int etob __P((char *out,char *e));
+void rip __P((char *buf));
+int skeychallenge __P((struct skey *mp,char *name, char *challenge));
+int skeylookup __P((struct skey *mp,char *name));
+int skeyverify __P((struct skey *mp,char *response));
+
+#endif /* _SKEY_H_ */
diff --git a/include/stddef.h b/include/stddef.h
index b5ebfd9b2fc9..0329904f2569 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -30,7 +30,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)stddef.h 5.5 (Berkeley) 4/3/91
+ * From: @(#)stddef.h 5.5 (Berkeley) 4/3/91
+ * $Id: stddef.h,v 1.2 1994/04/04 21:10:52 wollman Exp $
*/
#ifndef _STDDEF_H_
@@ -45,9 +46,12 @@ typedef _SIZE_T_ size_t;
#undef _SIZE_T_
#endif
-#ifdef _WCHAR_T_
-typedef _WCHAR_T_ wchar_t;
-#undef _WCHAR_T_
+#ifdef _BSD_WCHAR_T_
+#ifndef _ANSI_SOURCE
+typedef _BSD_WCHAR_T_ rune_t;
+#endif
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
#endif
#ifndef NULL
diff --git a/include/stdio.h b/include/stdio.h
index d9fbe98eb20d..7eff3ae7562d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -116,8 +116,8 @@ typedef struct __sFILE {
unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
unsigned char _nbuf[1]; /* guarantee a getc() buffer */
- /* separate buffer for fgetline() when line crosses buffer boundary */
- struct __sbuf _lb; /* buffer for fgetline() */
+ /* separate buffer for fgetln() when line crosses buffer boundary */
+ struct __sbuf _lb; /* buffer for fgetln() */
/* Unix stdio files get aligned to block boundaries on fseek() */
int _blksize; /* stat.st_blksize (may be != _bf._size) */
@@ -142,7 +142,7 @@ __END_DECLS
#define __SOPT 0x0400 /* do fseek() optimisation */
#define __SNPT 0x0800 /* do not do fseek() optimisation */
#define __SOFF 0x1000 /* set iff _offset is in fact correct */
-#define __SMOD 0x2000 /* true => fgetline modified _p text */
+#define __SMOD 0x2000 /* true => fgetln modified _p text */
/*
* The following three definitions are for ANSI C, which took them
@@ -259,7 +259,7 @@ __END_DECLS
*/
#if !defined (_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
__BEGIN_DECLS
-char *fgetline __P((FILE *, size_t *));
+char *fgetln __P((FILE *, size_t *));
int fpurge __P((FILE *));
int getw __P((FILE *));
int pclose __P((FILE *));
diff --git a/include/stdlib.h b/include/stdlib.h
index b1a65e36a147..3a6e6dc1ab7d 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -30,25 +30,36 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)stdlib.h 5.13 (Berkeley) 6/4/91
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00145
- * -------------------- ----- ----------------------
- *
- * 20 Apr 93 Richard Murphey stddef.h patch for XFree86
+ * From: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id: stdlib.h,v 1.5 1994/04/04 21:10:52 wollman Exp $
*/
#ifndef _STDLIB_H_
#define _STDLIB_H_
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
#include <sys/types.h>
+#else
+#include <machine/ansi.h>
+#endif
#ifdef _WCHAR_T_
typedef _WCHAR_T_ wchar_t;
#undef _WCHAR_T_
#endif
+#ifdef _BSD_WCHAR_T_
+#ifndef _ANSI_SOURCE
+typedef _BSD_WCHAR_T_ rune_t;
+#endif
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+
typedef struct {
int quot; /* quotient */
int rem; /* remainder */
@@ -63,7 +74,8 @@ typedef struct {
#define RAND_MAX 0x7fffffff
-#define MB_CUR_MAX 1 /* XXX */
+extern int __mb_cur_max;
+#define MB_CUR_MAX __mb_cur_max
#include <sys/cdefs.h>
@@ -102,7 +114,13 @@ int wctomb __P((char *, wchar_t));
int mbtowc __P((wchar_t *, const char *, size_t));
size_t wcstombs __P((char *, const wchar_t *, size_t));
-/* don't ask me where to put these -- MB XXX */
+#ifndef _ANSI_SOURCE
+void cfree __P((void *));
+int putenv __P((const char *));
+int setenv __P((const char *, const char *, int));
+#endif /* not ANSI */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
double drand48 __P((void));
double erand48 __P((unsigned short[3]));
long lrand48 __P((void));
@@ -113,13 +131,6 @@ void srand48 __P((long));
unsigned short *seed48 __P((unsigned short[3]));
void lcong48 __P((unsigned short[7]));
-#ifndef _ANSI_SOURCE
-void cfree __P((void *));
-int putenv __P((const char *));
-int setenv __P((const char *, const char *, int));
-#endif /* not ANSI */
-
-#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
#ifndef alloca
void *alloca __P((size_t));
#endif
@@ -132,7 +143,8 @@ int getsubopt __P((char **, char * const *, char **));
int heapsort __P((void *, size_t, size_t,
int (*)(const void *, const void *)));
char *initstate __P((unsigned, char *, int));
-int radixsort __P((const u_char **, int, const u_char *, u_char));
+int radixsort __P((const unsigned char **, int, const unsigned char *,
+ unsigned char));
long random __P((void));
char *setstate __P((char *));
void srandom __P((unsigned));
diff --git a/include/time.h b/include/time.h
index 4057efcb4dae..7c1351b35a73 100644
--- a/include/time.h
+++ b/include/time.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: time.h,v 1.1.1.1.2.1 1994/05/04 07:37:59 rgrimes Exp $
+ * $Id: time.h,v 1.2 1994/05/04 08:08:42 rgrimes Exp $
*/
/*
* Copyright (c) 1989 The Regents of the University of California.
diff --git a/include/utmp.h b/include/utmp.h
index 6976acd3c64a..a5b71156dbb6 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: utmp.h,v 1.1.1.1.2.1 1994/05/04 07:38:03 rgrimes Exp $
+ * $Id: utmp.h,v 1.2 1994/05/04 08:08:45 rgrimes Exp $
*/
/*
* Copyright (c) 1988 The Regents of the University of California.
diff --git a/include/varargs.h b/include/varargs.h
index ba91e22c73a9..f6522c46562f 100644
--- a/include/varargs.h
+++ b/include/varargs.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: varargs.h,v 1.1.1.1.2.1 1994/05/04 07:38:07 rgrimes Exp $
+ * $Id: varargs.h,v 1.2 1994/05/04 08:08:49 rgrimes Exp $
*/
/*-
* Copyright (c) 1990 The Regents of the University of California.
diff --git a/lib/Makefile b/lib/Makefile
index 29043c1fd223..7c72039dc047 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 5.25.1.1 (Berkeley) 5/7/91
-SUBDIR= csu.${MACHINE} libc libcurses libm libpthread \
- libresolv librpcsvc libtelnet libterm libutil liby
+SUBDIR= csu.${MACHINE} libc libcurses libmalloc libpthread \
+ libresolv librpcsvc libskey libtelnet libterm libutil liby
.if exists(libcrypt)
.if !defined(NOCRYPT)
@@ -15,4 +15,10 @@ SUBDIR+= libf2c
SUBDIR+= libI77 libF77
.endif
+.if !defined(WANT_MSUN)
+SUBDIR+= libm
+.else
+SUBDIR+= msun
+.endif
+
.include <bsd.subdir.mk>
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 8e9d1e78a221..848db237caae 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -1,3 +1,3 @@
# Default version for system libs (override in <lib>/Makefile if necessary)
SHLIB_MAJOR?= 1
-SHLIB_MINOR?= 0
+SHLIB_MINOR?= 1
diff --git a/lib/csu.i386/Makefile b/lib/csu.i386/Makefile
index 503ad9753294..adb0c85a0425 100644
--- a/lib/csu.i386/Makefile
+++ b/lib/csu.i386/Makefile
@@ -1,9 +1,12 @@
# from: @(#)Makefile 5.6 (Berkeley) 5/22/91
-# $Id: Makefile,v 1.8 1993/12/24 02:11:37 jkh Exp $
+# $Id: Makefile,v 1.12 1994/06/21 15:21:28 jkh Exp $
CFLAGS+= -DLIBC_SCCS -DDYNAMIC
-OBJS= crt0.o gcrt0.o crt1.so
+OBJS= crt0.o mcrt0.o c++rt0.o
CLEANFILES+= gmon.o moncrt0.o core a.out
+.if defined(STARTUP_LOCALE)
+CFLAGS+= -DSTARTUP_LOCALE
+.endif
all: ${OBJS}
@@ -12,9 +15,9 @@ crt0.o: crt0.c
${LD} -x -r ${.TARGET}
mv a.out ${.TARGET}
-crt1.so: crt1.c
+c++rt0.o: c++rt0.c
${CC} ${CFLAGS} -fpic -c ${.ALLSRC} -o ${.TARGET}
- ${LD} -X -r ${.TARGET}
+ @${LD} -x -r ${.TARGET}
@mv a.out ${.TARGET}
moncrt0.o: crt0.c
@@ -22,7 +25,7 @@ moncrt0.o: crt0.c
${LD} -x -r ${.TARGET}
mv a.out ${.TARGET}
-gcrt0.o: moncrt0.o gmon.o
+mcrt0.o: moncrt0.o gmon.o
${LD} -x -r -o ${.TARGET} moncrt0.o gmon.o
gmon.o: gmon.c gmon.h
diff --git a/lib/csu.i386/c++rt0.c b/lib/csu.i386/c++rt0.c
new file mode 100644
index 000000000000..d917a78a55e5
--- /dev/null
+++ b/lib/csu.i386/c++rt0.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: c++rt0.c,v 1.1 1994/03/09 17:12:59 nate Exp $
+ */
+
+/*
+ * Run-time module for GNU C++ compiled shared libraries.
+ *
+ * The linker constructs the following arrays of pointers to global
+ * constructors and destructors. The first element contains the
+ * number of pointers in each.
+ * The tables are also null-terminated.
+ */
+void (*__CTOR_LIST__[0])(void);
+void (*__DTOR_LIST__[0])(void);
+
+static void
+__dtors(void)
+{
+ unsigned long i = (unsigned long) __DTOR_LIST__[0];
+ void (**p)(void) = __DTOR_LIST__ + i;
+
+ while (i--)
+ (**p--)();
+}
+
+static void
+__ctors(void)
+{
+ void (**p)(void) = __CTOR_LIST__ + 1;
+
+ while (*p)
+ (**p++)();
+}
+
+extern void __init() asm(".init");
+
+void
+__init(void)
+{
+ static int initialized = 0;
+
+ /*
+ * Call global constructors.
+ * Arrange to call global destructors at exit.
+ */
+ if (!initialized) {
+ initialized = 1;
+ __ctors();
+ atexit(__dtors);
+ }
+
+}
diff --git a/lib/csu.i386/crt0.c b/lib/csu.i386/crt0.c
index 93bb1e1ff7fb..4c0deb0ae91d 100644
--- a/lib/csu.i386/crt0.c
+++ b/lib/csu.i386/crt0.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: crt0.c,v 1.9 1994/02/16 19:26:39 nate Exp $
+ * $Id: crt0.c,v 1.10 1994/06/12 10:51:01 ache Exp $
*/
@@ -39,6 +39,9 @@ extern void exit();
int _callmain();
#include <sys/param.h>
+#ifdef STARTUP_LOCALE
+#include <locale.h>
+#endif /* STARTUP_LOCALE */
#ifdef DYNAMIC
#include <sys/types.h>
@@ -166,7 +169,11 @@ asm("eprol:");
#ifdef MCRT0
atexit(_mcleanup);
monstartup(&eprol, &etext);
-#endif MCRT0
+#endif /* MCRT0 */
+
+#ifdef STARTUP_LOCALE
+ (void) setlocale(LC_ALL, "");
+#endif /* STARTUP_LOCALE */
asm ("__callmain:"); /* Defined for the benefit of debuggers */
exit(main(kfp->kargc, argv, environ));
diff --git a/lib/csu.i386/crt1.c b/lib/csu.i386/crt1.c
deleted file mode 100644
index bee2d1b6fb67..000000000000
--- a/lib/csu.i386/crt1.c
+++ /dev/null
@@ -1,47 +0,0 @@
-typedef void (*func_ptr) (void);
-
-func_ptr __CTOR_LIST__[2];
-func_ptr __DTOR_LIST__[2];
-
-/* Run all the global destructors on exit from the program. */
-
-static void
-__do_global_dtors ()
-{
- unsigned nptrs = (unsigned long) __DTOR_LIST__[0];
- unsigned i;
-
- /* Some systems place the number of pointers
- in the first word of the table.
- On other systems, that word is -1.
- In all cases, the table is null-terminated. */
-
- /* If the length is not recorded, count up to the null. */
- if (nptrs == -1)
- for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
-
- /* GNU LD format. */
- for (i = nptrs; i >= 1; i--)
- __DTOR_LIST__[i] ();
-
-}
-
-static void
-__do_global_ctors ()
-{
- func_ptr *p;
-
- for (p = __CTOR_LIST__ + 1; *p; )
- (*p++)();
- atexit (__do_global_dtors);
-}
-
-__init()
-{
- static int initialized = 0;
- if (! initialized) {
- initialized = 1;
- __do_global_ctors ();
- }
-
-}
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index 319a528c5a54..fe11e19456a1 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -15,7 +15,9 @@ INSTALL_PIC_ARCHIVE=
.include "${.CURDIR}/gen/Makefile.inc"
.include "${.CURDIR}/locale/Makefile.inc"
.include "${.CURDIR}/net/Makefile.inc"
+.if defined(GCC1_IN_LIBC)
.include "${.CURDIR}/quad/Makefile.inc"
+.endif
.include "${.CURDIR}/stdio/Makefile.inc"
.include "${.CURDIR}/stdlib/Makefile.inc"
.include "${.CURDIR}/string/Makefile.inc"
diff --git a/lib/libc/compat-43/Makefile.inc b/lib/libc/compat-43/Makefile.inc
index 63c330fcd813..bcb3d1efe3cb 100644
--- a/lib/libc/compat-43/Makefile.inc
+++ b/lib/libc/compat-43/Makefile.inc
@@ -1,9 +1,10 @@
-# @(#)Makefile.inc 5.3 (Berkeley) 2/20/91
+# From: @(#)Makefile.inc 5.3 (Berkeley) 2/20/91
+# $Id: Makefile.inc,v 1.5 1994/04/04 19:33:56 wollman Exp $
# compat-43 sources
.PATH: ${.CURDIR}/${MACHINE}/compat-43 ${.CURDIR}/compat-43
-SRCS+= creat.c getwd.c killpg.c setpgrp.c sigcompat.c
+SRCS+= creat.c getwd.c killpg.c setpgrp.c sigcompat.c setruid.c setrgid.c
MAN2+= compat-43/creat.2 compat-43/killpg.2 compat-43/sigblock.2 \
compat-43/sigpause.2 compat-43/sigsetmask.2 compat-43/sigvec.2
diff --git a/lib/libc/compat-43/setrgid.c b/lib/libc/compat-43/setrgid.c
new file mode 100644
index 000000000000..50484554ac8b
--- /dev/null
+++ b/lib/libc/compat-43/setrgid.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1983 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "From: @(#)setrgid.c 5.5 (Berkeley) 2/23/91";
+static const char rcsid[] =
+ "$Id: setrgid.c,v 1.5 1994/04/23 23:52:45 wollman Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <unistd.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses setrgid(), which doesn't do anything\r\n(but used to)\r\n"
+
+
+int
+#ifdef __STDC__
+setrgid(gid_t rgid)
+#else
+setrgid(rgid)
+ int rgid;
+#endif
+{
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
+ return (setregid(rgid, -1));
+}
+
+asm(".stabs \"warning: setrgid function referenced\", 30, 0,0,0");
+asm(".stabs \"_setrgid\", 1, 0, 0, 0");
diff --git a/lib/libc/compat-43/setruid.c b/lib/libc/compat-43/setruid.c
new file mode 100644
index 000000000000..72171a57b30d
--- /dev/null
+++ b/lib/libc/compat-43/setruid.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1983 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "From: @(#)setruid.c 5.5 (Berkeley) 2/23/91";
+static const char rcsid[] =
+ "$Id: setruid.c,v 1.4 1994/04/23 20:39:02 wollman Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <unistd.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses setruid, which doesn't do anything\r\n(but used to)\r\n"
+
+int
+#ifdef __STDC__
+setruid(uid_t ruid)
+#else
+setruid(ruid)
+ int ruid;
+#endif
+{
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
+ return (setreuid(ruid, -1));
+}
+
+asm(".stabs \"warning: setruid function referenced\", 30, 0, 0, 0");
+asm(".stabs \"_setruid\", 1, 0, 0, 0");
+
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
index e9b25831d20e..c6a52d738973 100644
--- a/lib/libc/db/hash/hash.c
+++ b/lib/libc/db/hash/hash.c
@@ -433,6 +433,8 @@ hdestroy(hashp)
if (hashp->fp != -1)
(void)close(hashp->fp);
+ free(hashp);
+
if (save_errno) {
errno = save_errno;
return (ERROR);
diff --git a/lib/libc/db/recno/rec_open.c b/lib/libc/db/recno/rec_open.c
index f05a44bb0026..514e9811f91a 100644
--- a/lib/libc/db/recno/rec_open.c
+++ b/lib/libc/db/recno/rec_open.c
@@ -160,7 +160,7 @@ slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
else {
t->bt_msize = sb.st_size;
if ((t->bt_smap = mmap(NULL, t->bt_msize,
- PROT_READ, MAP_PRIVATE, rfd,
+ PROT_READ, MAP_FILE|MAP_PRIVATE, rfd,
(off_t)0)) == (caddr_t)-1)
goto slow;
t->bt_cmap = t->bt_smap;
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 0f0a66405d13..3b54c31a5d12 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -8,10 +8,10 @@ SRCS+= alarm.c assert.c clock.c crypt.c ctermid.c ctime.c ctype_.c \
fnmatch.c frexp.c fstab.c fts.c getcap.c getcwd.c getgrent.c \
getlogin.c getmntinfo.c getpass.c getpwent.c getsubopt.c getttyent.c \
getusershell.c glob.c infinity.c initgroups.c insque.c isatty.c \
- isctype.c isinf.c mktemp.c msgctl.c msgget.c msgsnd.c msgrcv.c \
+ isinf.c mktemp.c msgctl.c msgget.c msgsnd.c msgrcv.c \
nice.c nlist.c pause.c popen.c psignal.c raise.c scandir.c \
semconfig.c semctl.c semget.c semop.c \
- setjmperr.c setmode.c setrgid.c setruid.c \
+ setjmperr.c setmode.c \
shmat.c shmctl.c shmdt.c shmget.c \
siginterrupt.c siglist.c signal.c sigsetops.c sleep.c syslog.c \
termios.c time.c times.c timezone.c ttyname.c ttyslot.c \
@@ -27,7 +27,9 @@ SRCS+= adddf3.s addsf3.s ashlsi3.s ashrsi3.s cmpdf2.s cmpsf2.s divdf3.s \
umodsi3.s umulsi3.s
.elif (${MACHINE} == "i386")
SRCS+= _setjmp.S alloca.S fabs.S ldexp.c modf.S setjmp.S sigsetjmp.S
+.if defined (GCC1_IN_LIBC)
SRCS+= divsi3.S fixdfsi.S fixunsdfsi.S udivsi3.S
+.endif
.elif (${MACHINE} == "tahoe")
CFLAGS+=-I/sys
SRCS+= _setjmp.s alloca.s fabs.s ldexp.s modf.s setjmp.s
@@ -36,6 +38,9 @@ SRCS+= udiv.s urem.s
SRCS+= _setjmp.s alloca.s fabs.s ldexp.s modf.s setjmp.s
SRCS+= udiv.s urem.s
.endif
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
MAN3+= gen/alarm.3 gen/clock.3 gen/crypt.3 gen/ctermid.3 gen/ctime.3 \
gen/ctype.3 gen/directory.3 gen/err.3 gen/exec.3 gen/fnmatch.3 \
@@ -47,7 +52,7 @@ MAN3+= gen/alarm.3 gen/clock.3 gen/crypt.3 gen/ctermid.3 gen/ctime.3 \
gen/islower.3 gen/isprint.3 gen/ispunct.3 gen/isspace.3 \
gen/isupper.3 gen/isxdigit.3 gen/ldexp.3 gen/modf.3 gen/nice.3 \
gen/nlist.3 gen/pause.3 gen/popen.3 gen/psignal.3 gen/raise.3 \
- gen/scandir.3 gen/setjmp.3 gen/setmode.3 gen/setuid.3 \
+ gen/scandir.3 gen/setjmp.3 gen/setmode.3 \
gen/siginterrupt.3 gen/signal.3 gen/sigsetops.3 gen/sleep.3 \
gen/syslog.3 gen/tcgetpgrp.3 gen/tcsendbreak.3 gen/tcsetattr.3 \
gen/tcsetpgrp.3 gen/time.3 gen/times.3 gen/timezone.3 gen/tolower.3 \
@@ -86,8 +91,6 @@ MLINKS+=scandir.3 alphasort.3
MLINKS+=setjmp.3 _longjmp.3 setjmp.3 _setjmp.3 setjmp.3 longjmp.3 \
setjmp.3 sigsetjmp.3 setjmp.3 siglongjmp.3 setjmp.3 longjmperror.3
MLINKS+=setmode.3 getmode.3
-MLINKS+=setuid.3 setegid.3 setuid.3 seteuid.3 setuid.3 setgid.3 \
- setuid.3 setrgid.3 setuid.3 setruid.3
MLINKS+=sigsetops.3 sigemptyset.3 sigsetops.3 sigfillset.3 \
sigsetops.3 sigaddset.3 sigsetops.3 sigdelset.3 \
sigsetops.3 sigismember.3
diff --git a/lib/libc/gen/ctype_.c b/lib/libc/gen/ctype_.c
index d361c1617cea..0f06fe2b8123 100644
--- a/lib/libc/gen/ctype_.c
+++ b/lib/libc/gen/ctype_.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: ctype_.c,v 1.1.1.1.2.1 1994/05/04 07:39:42 rgrimes Exp $
+ * $Id: ctype_.c,v 1.3 1994/05/04 08:17:14 rgrimes Exp $
*/
/*
* Copyright (c) 1989 The Regents of the University of California.
@@ -41,10 +41,12 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)ctype_.c 5.6 (Berkeley) 6/1/90";
+static char sccsid[] = "From: @(#)ctype_.c 5.6 (Berkeley) 6/1/90";
+static const char rcsid[] =
+ "$Id: ctype_.c,v 1.3 1994/05/04 08:17:14 rgrimes Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <ctype.h>
+#include <octype.h>
char _ctype_[1 + 256] = {
0,
diff --git a/lib/libc/gen/getcap.3 b/lib/libc/gen/getcap.3
index d18b3797bc7e..a2cf2665d0d4 100644
--- a/lib/libc/gen/getcap.3
+++ b/lib/libc/gen/getcap.3
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)getcap.3 5.4 (Berkeley) 8/11/92
-.\" $Id: getcap.3,v 1.1.2.1 1994/05/01 16:05:00 jkh Exp $
+.\" $Id: getcap.3,v 1.2 1994/04/17 09:16:14 alm Exp $
.\"
.Dd "August 11, 1992"
.Dt GETCAP 3
diff --git a/lib/libc/gen/getcap.c b/lib/libc/gen/getcap.c
index 7f70789450fd..647a5bff41a7 100644
--- a/lib/libc/gen/getcap.c
+++ b/lib/libc/gen/getcap.c
@@ -35,7 +35,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getcap.c 5.15 (Berkeley) 3/19/93";
+/*static char *sccsid = "from: @(#)getcap.c 5.15 (Berkeley) 3/19/93";*/
+static char *rcsid = "$Id: getcap.c,v 1.2 1994/04/17 09:16:16 alm Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
@@ -194,8 +195,8 @@ getent(cap, len, db_array, fd, name, depth, nfield)
DB *capdbp;
DBT key, data;
register char *r_end, *rp, **db_p;
- int myfd, eof, foundit, retval;
- char *record;
+ int myfd, eof, foundit, retval, clen;
+ char *record, *cbuf;
int tc_not_resolved;
char pbuf[_POSIX_PATH_MAX];
@@ -250,11 +251,21 @@ getent(cap, len, db_array, fd, name, depth, nfield)
!= NULL) {
free(record);
retval = cdbget(capdbp, &record, name);
- if (capdbp->close(capdbp) < 0)
+ if (retval < 0) {
+ /* no record available */
+ (void)capdbp->close(capdbp);
+ return (retval);
+ }
+ /* save the data; close frees it */
+ clen = strlen(record);
+ cbuf = malloc(clen + 1);
+ memcpy(cbuf, record, clen + 1);
+ if (capdbp->close(capdbp) < 0) {
+ free(cbuf);
return (-2);
- *len = strlen(record);
- *cap = malloc(*len + 1);
- memmove(*cap, record, *len + 1);
+ }
+ *len = clen;
+ *cap = cbuf;
return (retval);
} else {
fd = open(*db_p, O_RDONLY, 0);
@@ -657,7 +668,7 @@ cgetnext(bp, db_array)
gottoprec = 1;
line = toprec;
} else {
- line = fgetline(pfp, &len);
+ line = fgetln(pfp, &len);
if (line == NULL && pfp) {
(void)fclose(pfp);
if (ferror(pfp)) {
@@ -716,7 +727,7 @@ cgetnext(bp, db_array)
*np = '\0';
break;
} else { /* name field extends beyond the line */
- line = fgetline(pfp, &len);
+ line = fgetln(pfp, &len);
if (line == NULL && pfp) {
(void)fclose(pfp);
if (ferror(pfp)) {
diff --git a/lib/libc/gen/getfsent.3 b/lib/libc/gen/getfsent.3
index 16847ed0b5f7..e29ed40724df 100644
--- a/lib/libc/gen/getfsent.3
+++ b/lib/libc/gen/getfsent.3
@@ -43,7 +43,7 @@
.Nd get file system descriptor file entry
.Sh SYNOPSIS
.Fd #include <fstab.h>
-.Ft fstab *
+.Ft struct fstab *
.Fn getfsent void
.Ft struct fstab *
.Fn getfsspec "const char *spec"
diff --git a/lib/libc/gen/getmntinfo.3 b/lib/libc/gen/getmntinfo.3
index 6119c6a4b2b7..689a28e3ddbf 100644
--- a/lib/libc/gen/getmntinfo.3
+++ b/lib/libc/gen/getmntinfo.3
@@ -41,7 +41,7 @@
.Fd #include <sys/types.h>
.Fd #include <sys/mount.h>
.Ft int
-.Fn getmntinfo "int mntbufp" "int flags"
+.Fn getmntinfo "int *mntbufp" "int flags"
.Sh DESCRIPTION
The
.Fn getmntinfo
diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3
index 6d0b9194bb0b..7963afab91e6 100644
--- a/lib/libc/gen/getpwent.3
+++ b/lib/libc/gen/getpwent.3
@@ -200,6 +200,20 @@ and
.Fn setpwent
are fairly useless in a networked environment and should be
avoided, if possible.
+.Pp
+Standard database make routines are slow especially for big passwd
+files. Moreover, *pwd.db bases are too big and waste root space.
+You can have much faster routines with small *pwd.db,
+but loose binary compatibility
+with previous versions and with other BSD-like systems.
+If you want to setup much faster routines, define
+.B PW_COMPACT
+envirnoment variable (f.e. 'setenv PW_COMPACT' in csh) and use
+.I bootstrappwd
+target into /usr/src/Makefile.
+If you will want to return this changes back, use the same target
+without defining
+.BR PW_COMPACT .
.Sh COMPATIBILITY
The historic function
.Xr setpwfile 3 ,
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index 93a09ee52ff6..96ae370c761c 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -33,7 +33,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)getpwent.c 5.21 (Berkeley) 3/14/91";*/
-static char *rcsid = "$Id: getpwent.c,v 1.4 1994/01/11 19:00:58 nate Exp $";
+static char *rcsid = "$Id: getpwent.c,v 1.9 1994/05/05 18:16:44 ache Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@@ -54,8 +54,14 @@ static char *rcsid = "$Id: getpwent.c,v 1.4 1994/01/11 19:00:58 nate Exp $";
#include <rpcsvc/ypclnt.h>
#endif
+/* #define PW_COMPACT */
+/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
+
static struct passwd _pw_passwd; /* password structure */
static DB *_pw_db; /* password database */
+#ifdef PW_COMPACT
+static DB *_spw_db; /* shadow password database */
+#endif
static int _pw_keynum; /* key counter */
static int _pw_stayopen; /* keep fd's open */
static int __hashpw(), __initdb();
@@ -260,6 +266,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return &_pw_passwd;
}
@@ -268,6 +280,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return (struct passwd *)NULL;
}
@@ -283,6 +301,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return(rval ? &_pw_passwd : (struct passwd *)NULL);
}
@@ -355,6 +379,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return &_pw_passwd;
}
@@ -363,6 +393,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return (struct passwd *)NULL;
}
@@ -378,6 +414,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return(rval ? &_pw_passwd : (struct passwd *)NULL);
}
@@ -410,6 +452,12 @@ endpwent()
if (_pw_db) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
#ifdef YP
__ypmode = 0;
@@ -425,12 +473,30 @@ __initdb()
static int warned;
char *p;
+#ifdef PW_COMPACT
+ if (!geteuid()) {
+ _spw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (!_spw_db && !warned)
+ syslog(LOG_ERR, "%s: %m", _PATH_SMP_DB);
+ }
+ _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return(1);
+ if (!warned)
+ syslog(LOG_ERR, "%s: %m", _PATH_MP_DB);
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#else
p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
if (_pw_db)
return(1);
if (!warned)
syslog(LOG_ERR, "%s: %m", p);
+#endif
+ warned = 1;
return(0);
}
@@ -442,9 +508,26 @@ __hashpw(key)
static u_int max;
static char *line;
DBT data;
+#ifdef PW_COMPACT
+ DBT _key, *__key;
+ char bf[sizeof(_pw_keynum) + 1];
+#endif
if ((_pw_db->get)(_pw_db, key, &data, 0))
return(0);
+#ifdef PW_COMPACT
+ __key = key;
+ if (((char *)(*__key).data)[0] != _PW_KEYBYNUM) {
+ if (data.size != sizeof(_pw_keynum)) return(0);
+ bf[0] = _PW_KEYBYNUM;
+ bcopy(data.data, bf + 1, sizeof(_pw_keynum));
+ _key.data = (u_char *)bf;
+ _key.size = sizeof(_pw_keynum) + 1;
+ __key = (DBT *)&_key;
+ if ((_pw_db->get)(_pw_db, __key, &data, 0))
+ return(0);
+ }
+#endif
p = (char *)data.data;
if (data.size > max && !(line = realloc(line, max += 1024)))
return(0);
@@ -452,7 +535,9 @@ __hashpw(key)
t = line;
#define EXPAND(e) e = t; while (*t++ = *p++);
EXPAND(_pw_passwd.pw_name);
+#ifndef PW_COMPACT
EXPAND(_pw_passwd.pw_passwd);
+#endif
bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
p += sizeof(int);
bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
@@ -465,5 +550,11 @@ __hashpw(key)
EXPAND(_pw_passwd.pw_shell);
bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
p += sizeof(time_t);
+#ifdef PW_COMPACT
+ if (_spw_db && !(_spw_db->get)(_spw_db, __key, &data, 0))
+ p = (char *)data.data;
+ else p = "*";
+ EXPAND(_pw_passwd.pw_passwd);
+#endif
return(1);
}
diff --git a/lib/libc/gen/isctype.c b/lib/libc/gen/isctype.c
deleted file mode 100644
index d8dd5bc33e9f..000000000000
--- a/lib/libc/gen/isctype.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) UNIX System Laboratories, Inc. All or some portions
- * of this file are derived from material licensed to the
- * University of California by American Telephone and Telegraph Co.
- * or UNIX System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
- *
- * $Id: isctype.c,v 1.1.1.1.2.1 1994/05/04 07:39:44 rgrimes Exp $
- */
-/*
- * 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.
- *
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)isctype.c 5.2 (Berkeley) 6/1/90";
-#endif /* LIBC_SCCS and not lint */
-
-#define _ANSI_LIBRARY
-#include <ctype.h>
-
-#undef isalnum
-isalnum(c)
- int c;
-{
- return((_ctype_ + 1)[c] & (_U|_L|_N));
-}
-
-#undef isalpha
-isalpha(c)
- int c;
-{
- return((_ctype_ + 1)[c] & (_U|_L));
-}
-
-#undef iscntrl
-iscntrl(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _C);
-}
-
-#undef isdigit
-isdigit(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _N);
-}
-
-#undef isgraph
-isgraph(c)
- int c;
-{
- return((_ctype_ + 1)[c] & (_P|_U|_L|_N));
-}
-
-#undef islower
-islower(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _L);
-}
-
-#undef isprint
-isprint(c)
- int c;
-{
- return((_ctype_ + 1)[c] & (_P|_U|_L|_N|_B));
-}
-
-#undef ispunct
-ispunct(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _P);
-}
-
-#undef isspace
-isspace(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _S);
-}
-
-#undef isupper
-isupper(c)
- int c;
-{
- return((_ctype_ + 1)[c] & _U);
-}
-
-#undef isxdigit
-isxdigit(c)
- int c;
-{
- return((_ctype_ + 1)[c] & (_N|_X));
-}
-
-#undef tolower
-tolower(c)
- int c;
-{
-/* was: return((c) - 'A' + 'a');*/
- return ( isupper(c) ? c - 'A' + 'a' : c);
-}
-
-#undef toupper
-toupper(c)
- int c;
-{
-/* was: return((c) - 'a' + 'A');*/
- return ( islower(c) ? c - 'a' + 'A' : c);
-}
diff --git a/lib/libc/gen/semconfig.c b/lib/libc/gen/semconfig.c
index 66fbb2d93398..cf5399b6dde4 100644
--- a/lib/libc/gen/semconfig.c
+++ b/lib/libc/gen/semconfig.c
@@ -5,7 +5,7 @@
#if __STDC__
int semconfig(int cmd, int p1, int p2, int p3)
#else
-int semctl(cmd, p1, p2, p3)
+int semconfig(cmd, p1, p2, p3)
int cmd, p1, p2, p3;
#endif
{
diff --git a/lib/libc/gen/setmode.c b/lib/libc/gen/setmode.c
index 12f7c1ab1ca7..9858beaa4a06 100644
--- a/lib/libc/gen/setmode.c
+++ b/lib/libc/gen/setmode.c
@@ -215,6 +215,7 @@ setmode(p)
mode_t mask;
struct bitcmd *set, *saveset, *endset;
int permXbits, setlen;
+ int equalopdone;
static void compress_mode();
/*
@@ -285,6 +286,8 @@ setmode(p)
free(saveset);
return(NULL);
}
+ if(op == '=')
+ equalopdone = 0;
who &= ~S_ISTXT;
for (perm = 0, permXbits = 0;; ++p) {
@@ -321,10 +324,12 @@ setmode(p)
* to flush out any partial mode that we have,
* and then do the copying of the mode bits.
*/
- if (perm || op == '=') {
+ if (perm) {
ADDCMD(op, who, perm, mask);
perm = 0;
}
+ if (op == '=')
+ equalopdone = 1;
if (op == '+' && permXbits) {
ADDCMD('X', who, permXbits, mask);
permXbits = 0;
@@ -337,7 +342,9 @@ setmode(p)
* Add any permissions that we haven't already
* done.
*/
- if (perm || op == '=') {
+ if (perm || (op == '=' && !equalopdone)) {
+ if(op == '=')
+ equalopdone = 1;
ADDCMD(op, who, perm, mask);
perm = 0;
}
diff --git a/lib/libc/gen/setrgid.c b/lib/libc/gen/setrgid.c
deleted file mode 100644
index 43492306191e..000000000000
--- a/lib/libc/gen/setrgid.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 1983 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setrgid.c 5.5 (Berkeley) 2/23/91";
-#endif /* LIBC_SCCS and not lint */
-
-#include <unistd.h>
-
-int
-#ifdef __STDC__
-setrgid(gid_t rgid)
-#else
-setrgid(rgid)
- int rgid;
-#endif
-{
-
- return (setregid(rgid, -1));
-}
diff --git a/lib/libc/gen/setruid.c b/lib/libc/gen/setruid.c
deleted file mode 100644
index 1c224a33095d..000000000000
--- a/lib/libc/gen/setruid.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 1983 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setruid.c 5.5 (Berkeley) 2/23/91";
-#endif /* LIBC_SCCS and not lint */
-
-#include <unistd.h>
-
-int
-#ifdef __STDC__
-setruid(uid_t ruid)
-#else
-setruid(ruid)
- int ruid;
-#endif
-{
-
- return (setreuid(ruid, -1));
-}
diff --git a/lib/libc/gen/setuid.3 b/lib/libc/gen/setuid.3
deleted file mode 100644
index 4e0e4c3c9ea5..000000000000
--- a/lib/libc/gen/setuid.3
+++ /dev/null
@@ -1,99 +0,0 @@
-.\" Copyright (c) 1983, 1991 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.
-.\"
-.\" @(#)setuid.3 6.4 (Berkeley) 4/19/91
-.\"
-.Dd April 19, 1991
-.Dt SETUID 3
-.Os BSD 4.2
-.Sh NAME
-.Nm setuid ,
-.Nm seteuid ,
-.Nm setruid ,
-.Nm setgid ,
-.Nm setegid ,
-.Nm setrgid
-.Nd set user and group ID
-.Sh SYNOPSIS
-.Fd #include <sys/types.h>
-.Ft int
-.Fn setuid "uid_t uid"
-.Ft int
-.Fn seteuid "uid_t euid"
-.Ft int
-.Fn setruid "uid_t ruid"
-.Ft int
-.Fn setgid "gid_t gid"
-.Ft int
-.Fn setegid "gid_t egid"
-.Ft int
-.Fn setrgid "gid_t rgid"
-.Sh DESCRIPTION
-The
-.Fn setuid
-function
-.Pq Fn setgid
-sets both the real and effective
-user ID (group ID) of the current process
-as specified.
-.Pp
-The
-.Fn seteuid
-function
-.Pq Fn setegid
-sets the effective user ID (group ID) of the
-current process.
-.Pp
-The
-.Fn setruid
-function
-.Pq Fn setrgid
-sets the real user ID (group ID) of the
-current process.
-.Sh RETURN VALUES
-Upon success, these functions return 0;
-otherwise \-1 is returned.
-.Pp
-If the user is not the super user, or the uid
-specified is not the real or effective ID, these
-functions return \-1.
-.Sh SEE ALSO
-.Xr setreuid 2 ,
-.Xr setregid 2 ,
-.Xr getuid 2 ,
-.Xr getgid 2
-.Sh HISTORY
-A
-.Fn setuid
-and
-.Fn setgid
-syscall appeared in
-.At v6 .
diff --git a/lib/libc/i386/DEFS.h b/lib/libc/i386/DEFS.h
index 4b4df3e68ccb..6df18a13def7 100644
--- a/lib/libc/i386/DEFS.h
+++ b/lib/libc/i386/DEFS.h
@@ -35,7 +35,7 @@
*
* from: @(#)DEFS.h 5.1 (Berkeley) 4/23/90
*
- * $Id: DEFS.h,v 1.3.2.1 1994/05/04 08:44:15 rgrimes Exp $
+ * $Id: DEFS.h,v 1.4 1994/05/03 16:29:13 jkh Exp $
*/
/* XXX should use align 4,0x90 for -m486. */
diff --git a/lib/libc/i386/string/bcmp.S b/lib/libc/i386/string/bcmp.S
index 21027dadd8b4..d19922498d88 100644
--- a/lib/libc/i386/string/bcmp.S
+++ b/lib/libc/i386/string/bcmp.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: bcmp.S,v 1.1 1993/12/05 13:01:40 ats Exp $
+ * $Id: bcmp.S,v 1.2 1994/03/31 14:10:57 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: bcmp.S,v 1.1 1993/12/05 13:01:40 ats Exp $"
+ .asciz "$Id: bcmp.S,v 1.2 1994/03/31 14:10:57 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -48,17 +48,16 @@ ENTRY(bcmp)
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
- movl 20(%esp),%edx
xorl %eax,%eax /* clear return value */
cld /* set compare direction forward */
- movl %edx,%ecx /* compare by words */
+ movl 20(%esp),%ecx /* compare by words */
shrl $2,%ecx
repe
cmpsl
jne L1
- movl %edx,%ecx /* compare remainder by bytes */
+ movl 20(%esp),%ecx /* compare remainder by bytes */
andl $3,%ecx
repe
cmpsb
diff --git a/lib/libc/i386/string/memcmp.S b/lib/libc/i386/string/memcmp.S
index e1fdaaa31f6e..5e74a7373235 100644
--- a/lib/libc/i386/string/memcmp.S
+++ b/lib/libc/i386/string/memcmp.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: memcmp.S,v 1.1.2.1 1994/03/07 02:19:34 rgrimes Exp $
+ * $Id: memcmp.S,v 1.3 1994/03/31 14:10:59 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memcmp.S,v 1.1.2.1 1994/03/07 02:19:34 rgrimes Exp $"
+ .asciz "$Id: memcmp.S,v 1.3 1994/03/31 14:10:59 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -48,16 +48,15 @@ ENTRY(memcmp)
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
- movl 20(%esp),%edx
cld /* set compare direction forward */
- movl %edx,%ecx /* compare by words */
+ movl 20(%esp),%ecx /* compare by words */
shrl $2,%ecx
repe
cmpsl
jne L5 /* do we match so far? */
- movl %edx,%ecx /* compare remainder by bytes */
+ movl 20(%esp),%ecx /* compare remainder by bytes */
andl $3,%ecx
repe
cmpsb
@@ -73,8 +72,8 @@ L5: movl $4,%ecx /* We know that one of the next */
subl %ecx,%esi /* match. */
repe
cmpsb
-L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */
- movzbl -1(%esi),%edx
+L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */
+ movzbl -1(%esi),%edx
subl %edx,%eax
popl %esi
popl %edi
diff --git a/lib/libc/i386/string/memmove.S b/lib/libc/i386/string/memmove.S
index 57e52ad04295..7eeec5bd8c21 100644
--- a/lib/libc/i386/string/memmove.S
+++ b/lib/libc/i386/string/memmove.S
@@ -32,11 +32,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: memmove.S,v 1.1 1993/12/05 13:01:50 ats Exp $
+ * $Id: memmove.S,v 1.2 1994/03/31 14:11:00 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memmove.S,v 1.1 1993/12/05 13:01:50 ats Exp $"
+ .asciz "$Id: memmove.S,v 1.2 1994/03/31 14:11:00 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -51,20 +51,19 @@ ENTRY(memmove)
pushl %esi
pushl %edi
movl 12(%esp),%edi
- pushl %edi
- movl 20(%esp),%esi
- movl 24(%esp),%ecx
+ movl 16(%esp),%esi
+ movl 20(%esp),%ecx
cmpl %esi,%edi /* potentially overlapping? */
jnb 1f
cld /* nope, copy forwards. */
shrl $2,%ecx /* copy by words */
rep
movsl
- movl 24(%esp),%ecx
+ movl 20(%esp),%ecx
andl $3,%ecx /* any bytes left? */
rep
movsb
- popl %eax
+ movl 12(%esp),%eax
popl %edi
popl %esi
ret
@@ -77,13 +76,13 @@ ENTRY(memmove)
decl %esi
rep
movsb
- movl 24(%esp),%ecx /* copy remainder by words */
+ movl 20(%esp),%ecx /* copy remainder by words */
shrl $2,%ecx
subl $3,%esi
subl $3,%edi
rep
movsl
- popl %eax
+ movl 12(%esp),%eax
popl %edi
popl %esi
cld
diff --git a/lib/libc/i386/string/memset.S b/lib/libc/i386/string/memset.S
index 47e763781932..b7fc069da3c5 100644
--- a/lib/libc/i386/string/memset.S
+++ b/lib/libc/i386/string/memset.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: memset.S,v 1.1 1993/12/05 13:01:53 ats Exp $
+ * $Id: memset.S,v 1.2 1994/03/31 14:11:01 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memset.S,v 1.1 1993/12/05 13:01:53 ats Exp $"
+ .asciz "$Id: memset.S,v 1.2 1994/03/31 14:11:01 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -57,17 +57,15 @@ ENTRY(memset)
/*
* if the string is too short, it's really not worth the overhead
- * of aligning to word boundries, etc. So we jump to a plain
+ * of aligning to word boundries, etc. So we jump to a plain
* unaligned set.
*/
cmpl $0x0f,%ecx
jle L1
- movl %eax,%edx /* copy value to all bytes in word */
- sall $8,%edx /* XXX is there a better way? */
- orl %edx,%eax
+ movb %al,%ah /* copy char to all bytes in word */
movl %eax,%edx
- sall $16,%edx
+ sall $16,%eax
orl %edx,%eax
movl %edi,%edx /* compute misalignment */
@@ -75,7 +73,7 @@ ENTRY(memset)
andl $3,%edx
movl %ecx,%ebx
subl %edx,%ebx
-
+
movl %edx,%ecx /* set until word aligned */
rep
stosb
diff --git a/lib/libc/i386/string/strcmp.S b/lib/libc/i386/string/strcmp.S
index 015c21aa7fa3..bdc4585aed2f 100644
--- a/lib/libc/i386/string/strcmp.S
+++ b/lib/libc/i386/string/strcmp.S
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: strcmp.S,v 1.1.2.1 1994/03/07 02:19:31 rgrimes Exp $
+ * $Id: strcmp.S,v 1.2 1994/03/04 15:50:28 ache Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: strcmp.S,v 1.1.2.1 1994/03/07 02:19:31 rgrimes Exp $"
+ .asciz "$Id: strcmp.S,v 1.2 1994/03/04 15:50:28 ache Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
diff --git a/lib/libc/i386/string/strncmp.S b/lib/libc/i386/string/strncmp.S
index 72922fb30fec..a4df8025bfb5 100644
--- a/lib/libc/i386/string/strncmp.S
+++ b/lib/libc/i386/string/strncmp.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Winning Strategies, Inc.
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,20 +27,20 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: strncmp.S,v 1.1.2.1 1994/03/07 02:19:33 rgrimes Exp $
+ * $Id: strncmp.S,v 1.3 1994/03/31 14:11:02 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: strncmp.S,v 1.1.2.1 1994/03/07 02:19:33 rgrimes Exp $"
+ .asciz "$Id: strncmp.S,v 1.3 1994/03/31 14:11:02 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
/*
- * strncmp(s1, s2, n)
- * return an integer greater than, equal to, or less than 0,
+ * strncmp(s1, s2, n)
+ * return an integer greater than, equal to, or less than 0,
* according as the first n characters of string s1 is greater
- * than, equal to, or less than the string s2.
+ * than, equal to, or less than the string s2.
*
* %eax - pointer to s1
* %ecx - pointer to s2
@@ -53,7 +53,7 @@
/*
* I've unrolled the loop eight times: large enough to make a
* significant difference, and small enough not to totally trash the
- * cashe.
+ * cache.
*/
ENTRY(strncmp)
@@ -61,92 +61,93 @@ ENTRY(strncmp)
movl 8(%esp),%eax
movl 12(%esp),%ecx
movl 16(%esp),%edx
+ testl %edx,%edx
jmp L2 /* Jump into the loop! */
.align 2,0x90
L1: incl %eax
incl %ecx
decl %edx
-L2: testl %edx,%edx /* Have we compared n chars yet? */
- jle L4 /* Yes, strings are equal */
+L2: jz L4 /* strings are equal */
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
je L1
+
.align 2,0x90
-L3: movzbl (%eax),%eax /* unsigned comparision */
- movzbl (%ecx),%ecx
+L3: movzbl (%eax),%eax /* unsigned comparision */
+ movzbl (%ecx),%ecx
subl %ecx,%eax
popl %ebx
ret
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
index 855608475d59..aa9d8bb14b56 100644
--- a/lib/libc/locale/Makefile.inc
+++ b/lib/libc/locale/Makefile.inc
@@ -1,6 +1,20 @@
-# @(#)Makefile.inc 5.1 (Berkeley) 2/18/91
+# From: @(#)Makefile.inc 5.1 (Berkeley) 2/18/91
+# $Id: Makefile.inc,v 1.5 1994/04/13 20:12:15 wollman Exp $
# locale sources
.PATH: ${.CURDIR}/${MACHINE}/locale ${.CURDIR}/locale
-SRCS+= lconv.c localeconv.c setlocale.c
+SRCS+= ansi.c frune.c mbrune.c lconv.c localeconv.c rune.c setlocale.c \
+ table.c isctype.c \
+ euc.c none.c utf2.c
+MAN3+= locale/mbrune.3 locale/multibyte.3 locale/rune.3 locale/setlocale.3
+MAN4+= locale/euc.4 locale/utf2.4
+
+MLINKS+= mbrune.3 mbrrune.3 mbrune.3 mbmb.3
+MLINKS+= multibyte.3 mblen.3 multibyte.3 mbstowcs.3 \
+ multibyte.3 mbtowc.3 multibyte.3 wcstombs.3 \
+ multibyte.3 wctomb.3
+MLINKS+= rune.3 setrunelocale.3 rune.3 setinvalidrune.3 \
+ rune.3 sgetrune.3 rune.3 sputrune.3
+MLINKS+= setlocale.3 localeconv.3
+MLINKS+= utf2.4 utf8.4
diff --git a/lib/libc/locale/ansi.c b/lib/libc/locale/ansi.c
new file mode 100644
index 000000000000..e5c8e8ff96de
--- /dev/null
+++ b/lib/libc/locale/ansi.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ansi.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stddef.h>
+#include <rune.h>
+
+int
+mblen(s, n)
+ const char *s;
+ size_t n;
+{
+ char const *e;
+
+ if (s == 0 || *s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if (sgetrune(s, (int)n, &e) == _INVALID_RUNE)
+ return (s - e);
+ return (e - s);
+}
+
+int
+mbtowc(pwc, s, n)
+ wchar_t *pwc;
+ const char *s;
+ size_t n;
+{
+ char const *e;
+ rune_t r;
+
+ if (s == 0 || *s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if ((r = sgetrune(s, (int)n, &e)) == _INVALID_RUNE)
+ return (s - e);
+ if (pwc)
+ *pwc = r;
+ return (e - s);
+}
+
+int
+wctomb(s, wchar)
+ char *s;
+ wchar_t wchar;
+{
+ char *e;
+
+ if (s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if (wchar == 0) {
+ *s = 0;
+ return (1);
+ }
+
+ sputrune(wchar, s, MB_CUR_MAX, &e);
+ return (e ? e - s : -1);
+}
+
+size_t
+mbstowcs(pwcs, s, n)
+ wchar_t *pwcs;
+ const char *s;
+ size_t n;
+{
+ char const *e;
+ int cnt = 0;
+
+ if (!pwcs || !s)
+ return (-1);
+
+ while (n-- > 0) {
+ *pwcs = sgetrune(s, MB_LEN_MAX, &e);
+ if (*pwcs == _INVALID_RUNE)
+ return (-1);
+ if (*pwcs++ == 0)
+ break;
+ s = e;
+ ++cnt;
+ }
+ return (cnt);
+}
+
+size_t
+wcstombs(s, pwcs, n)
+ char *s;
+ const wchar_t *pwcs;
+ size_t n;
+{
+ char *e;
+ int cnt = 0;
+
+ if (!pwcs || !s)
+ return (-1);
+
+ while (n > 0) {
+ if (*pwcs == 0) {
+ *s = 0;
+ break;
+ }
+ if (!sputrune(*pwcs++, s, (int)n, &e))
+ return (-1); /* encoding error */
+ if (!e) /* too long */
+ return (cnt);
+ cnt += e - s;
+ s = e;
+ }
+ return (cnt);
+}
diff --git a/lib/libc/locale/euc.4 b/lib/libc/locale/euc.4
new file mode 100644
index 000000000000..966b896b657f
--- /dev/null
+++ b/lib/libc/locale/euc.4
@@ -0,0 +1,231 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)euc.4 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt EUC 4
+.Os
+.Sh NAME
+.Nm EUC
+.Nd EUC encoding of runes
+.Sh SYNOPSIS
+\fBENCODING "EUC"\fP
+.br
+\fBVARIABLE \fP\fIlen1 mask1 len2 mask2 len3 mask3 len4 mask4 mask\fP
+.Sh DESCRIPTION
+The
+.Nm EUC
+encoding is provided for compatibility with
+.Ux
+based systems.
+See
+.Xr mklocale 1
+for a complete description of the
+.Ev LC_CTYPE
+source file format.
+.Pp
+.Nm EUC
+implements a system of 4 multibyte codesets.
+A multibyte character in the first codeset consists of
+.Ar len1
+bytes starting with a byte in the range of 0x00 to 0x7f.
+To allow use of ASCII,
+.Ar len1
+is always 1.
+A multibyte character in the second codeset consists of
+.Ar len2
+bytes starting with a byte in the range of 0x80-0xff excluding 0x8e and 0x8f.
+A multibyte character in the third codeset consists of
+.Ar len3
+bytes starting with the byte 0x8e.
+A multibyte character in the fourth codeset consists of
+.Ar len4
+bytes starting with the byte 0x8f.
+.Pp
+The
+.Ev rune_t
+encoding of
+.Nm EUC
+multibyte characters is dependent on the
+.Ar len
+and
+.Ar mask
+arguments.
+First, the bytes are moved into a
+.Ev rune_t
+as follows:
+.Bd -literal
+byte0 << ((\fIlen\fPN-1) * 8) | byte1 << ((\fIlen\fPN-2) * 8) | ... | byte\fIlen\fPN-1
+.Ed
+.sp
+The result is then ANDed with
+.Ar ~mask
+and ORed with
+.Ar mask\fPN.
+Codesets 2 and 3 are special in that the leading byte (0x8e or 0x8f) is
+first removed and the
+.Ar len\fPN
+argument is reduced by 1.
+.sp
+For example, the Japanese locale has the following
+.Ev VARIABLE
+line:
+.Bd -literal
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+.Ed
+.sp
+Codeset 1 consists of the values 0x0000 - 0x007f.
+.sp
+Codeset 2 consists of the values who have the bits 0x8080 set.
+.sp
+Codeset 3 consists of the values 0x0080 - 0x00ff.
+.sp
+Codeset 4 consists of the values 0x8000 - 0xff7f excluding the values
+which have the 0x0080 bit set.
+.sp
+Notice that the global
+.Ar mask
+is set to 0x8080, this implies that from those 2 bits the codeset can
+be determined.
+.Sh "EXAMPLE - Japanese Locale"
+This is a complete example of an
+.Ev LC_CTYPE
+source file for the Japanese locale
+.Bd -literal
+/*
+ * Japanese LOCALE_CTYPE definitions using EUC of JIS character sets
+ */
+
+ENCODING "EUC"
+
+/* JIS JIS JIS */
+/* X201 X208 X201 */
+/* 00-7f 84-fe */
+
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+
+/*
+ * Code Set 1
+ */
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+
+MAPLOWER < 'A' - 'Z' : 'a' > < 'a' - 'z' : 'a' >
+MAPUPPER < 'A' - 'Z' : 'A' > < 'a' - 'z' : 'A' >
+TODIGIT < '0' - '9' : 0 >
+TODIGIT < 'A' - 'F' : 10 > < 'a' - 'f' : 10 >
+
+/*
+ * Code Set 2
+ */
+
+SPACE 0xa1a1
+PHONOGRAM 0xa1bc
+SPECIAL 0xa1a2 - 0xa1fe
+PUNCT 0xa1a2 - 0xa1f8 /* A few too many in here... */
+
+SPECIAL 0xa2a1 - 0xa2ae 0xa2ba - 0xa2c1 0xa2ca - 0xa2d0 0xa2dc - 0xa2ea
+SPECIAL 0xa2f2 - 0xa2f9 0xa2fe
+
+DIGIT 0xa3b0 - 0xa3b9
+UPPER 0xa3c1 - 0xa3da /* Romaji */
+LOWER 0xa3e1 - 0xa3fa /* Romaji */
+MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > /* English */
+MAPLOWER < 0xa3e1 - 0xa3fa : 0xa3e1 > /* English */
+MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 >
+MAPUPPER < 0xa3e1 - 0xa3fa : 0xa3c1 >
+
+XDIGIT 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
+
+TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
+TODIGIT < 0xa3c1 - 0xa3c6 : 10 > < 0xa3e1 - 0xa3e6 : 10 >
+
+PHONOGRAM 0xa4a1 - 0xa4f3
+PHONOGRAM 0xa5a1 - 0xa5f6
+
+UPPER 0xa6a1 - 0xa6b8 /* Greek */
+LOWER 0xa6c1 - 0xa6d8 /* Greek */
+MAPLOWER < 0xa6a1 - 0xa6b8 : 0xa6c1 > < 0xa6c1 - 0xa6d8 : 0xa6c1 >
+MAPUPPER < 0xa6a1 - 0xa6b8 : 0xa6a1 > < 0xa6c1 - 0xa6d8 : 0xa6a1 >
+
+UPPER 0xa7a1 - 0xa7c1 /* Cyrillic */
+LOWER 0xa7d1 - 0xa7f1 /* Cyrillic */
+MAPLOWER < 0xa7a1 - 0xa7c1 : 0xa7d1 > < 0xa7d1 - 0xa7f1 : 0xa7d1 >
+MAPUPPER < 0xa7a1 - 0xa7c1 : 0xa7a1 > < 0xa7d1 - 0xa7f1 : 0xa7a1 >
+
+SPECIAL 0xa8a1 - 0xa8c0
+
+IDEOGRAM 0xb0a1 - 0xb0fe 0xb1a1 - 0xb1fe 0xb2a1 - 0xb2fe
+IDEOGRAM 0xb3a1 - 0xb3fe 0xb4a1 - 0xb4fe 0xb5a1 - 0xb5fe
+IDEOGRAM 0xb6a1 - 0xb6fe 0xb7a1 - 0xb7fe 0xb8a1 - 0xb8fe
+IDEOGRAM 0xb9a1 - 0xb9fe 0xbaa1 - 0xbafe 0xbba1 - 0xbbfe
+IDEOGRAM 0xbca1 - 0xbcfe 0xbda1 - 0xbdfe 0xbea1 - 0xbefe
+IDEOGRAM 0xbfa1 - 0xbffe 0xc0a1 - 0xc0fe 0xc1a1 - 0xc1fe
+IDEOGRAM 0xc2a1 - 0xc2fe 0xc3a1 - 0xc3fe 0xc4a1 - 0xc4fe
+IDEOGRAM 0xc5a1 - 0xc5fe 0xc6a1 - 0xc6fe 0xc7a1 - 0xc7fe
+IDEOGRAM 0xc8a1 - 0xc8fe 0xc9a1 - 0xc9fe 0xcaa1 - 0xcafe
+IDEOGRAM 0xcba1 - 0xcbfe 0xcca1 - 0xccfe 0xcda1 - 0xcdfe
+IDEOGRAM 0xcea1 - 0xcefe 0xcfa1 - 0xcfd3 0xd0a1 - 0xd0fe
+IDEOGRAM 0xd1a1 - 0xd1fe 0xd2a1 - 0xd2fe 0xd3a1 - 0xd3fe
+IDEOGRAM 0xd4a1 - 0xd4fe 0xd5a1 - 0xd5fe 0xd6a1 - 0xd6fe
+IDEOGRAM 0xd7a1 - 0xd7fe 0xd8a1 - 0xd8fe 0xd9a1 - 0xd9fe
+IDEOGRAM 0xdaa1 - 0xdafe 0xdba1 - 0xdbfe 0xdca1 - 0xdcfe
+IDEOGRAM 0xdda1 - 0xddfe 0xdea1 - 0xdefe 0xdfa1 - 0xdffe
+IDEOGRAM 0xe0a1 - 0xe0fe 0xe1a1 - 0xe1fe 0xe2a1 - 0xe2fe
+IDEOGRAM 0xe3a1 - 0xe3fe 0xe4a1 - 0xe4fe 0xe5a1 - 0xe5fe
+IDEOGRAM 0xe6a1 - 0xe6fe 0xe7a1 - 0xe7fe 0xe8a1 - 0xe8fe
+IDEOGRAM 0xe9a1 - 0xe9fe 0xeaa1 - 0xeafe 0xeba1 - 0xebfe
+IDEOGRAM 0xeca1 - 0xecfe 0xeda1 - 0xedfe 0xeea1 - 0xeefe
+IDEOGRAM 0xefa1 - 0xeffe 0xf0a1 - 0xf0fe 0xf1a1 - 0xf1fe
+IDEOGRAM 0xf2a1 - 0xf2fe 0xf3a1 - 0xf3fe 0xf4a1 - 0xf4a4
+/*
+ * This is for Code Set 3, half-width kana
+ */
+SPECIAL 0xa1 - 0xdf
+PHONOGRAM 0xa1 - 0xdf
+CONTROL 0x84 - 0x97 0x9b - 0x9f 0xe0 - 0xfe
+.Ed
+.Sh "SEE ALSO"
+.Xr mklocale 1 ,
+.Xr setlocale 3
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
new file mode 100644
index 000000000000..e58c8556087a
--- /dev/null
+++ b/lib/libc/locale/euc.c
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)euc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+rune_t _EUC_sgetrune __P((const char *, size_t, char const **));
+int _EUC_sputrune __P((rune_t, char *, size_t, char **));
+
+typedef struct {
+ int count[4];
+ rune_t bits[4];
+ rune_t mask;
+} _EucInfo;
+
+int
+_EUC_init(rl)
+ _RuneLocale *rl;
+{
+ _EucInfo *ei;
+ int x;
+ char *v, *e;
+
+ rl->sgetrune = _EUC_sgetrune;
+ rl->sputrune = _EUC_sputrune;
+
+ if (!rl->variable) {
+ free(rl);
+ return (EFTYPE);
+ }
+ v = (char *) rl->variable;
+
+ while (*v == ' ' || *v == '\t')
+ ++v;
+
+ if ((ei = malloc(sizeof(_EucInfo))) == NULL) {
+ free(rl);
+ return (ENOMEM);
+ }
+ for (x = 0; x < 4; ++x) {
+ ei->count[x] = (int) strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ ei->bits[x] = (int) strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ }
+ ei->mask = (int)strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ if (sizeof(_EucInfo) <= rl->variable_len) {
+ memcpy(rl->variable, ei, sizeof(_EucInfo));
+ free(ei);
+ } else {
+ rl->variable = &ei;
+ }
+ rl->variable_len = sizeof(_EucInfo);
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 3;
+ return (0);
+}
+
+#define CEI ((_EucInfo *)(_CurrentRuneLocale->variable))
+
+#define _SS2 0x008e
+#define _SS3 0x008f
+
+static inline int
+_euc_set(c)
+ u_int c;
+{
+ c &= 0xff;
+
+ return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0);
+}
+rune_t
+_EUC_sgetrune(string, n, result)
+ const char *string;
+ size_t n;
+ char const **result;
+{
+ rune_t rune = 0;
+ int len, set;
+
+ if (n < 1 || (len = CEI->count[set = _euc_set(*string)]) > n) {
+ if (result)
+ *result = string;
+ return (_INVALID_RUNE);
+ }
+ switch (set) {
+ case 3:
+ case 2:
+ --len;
+ ++string;
+ /* FALLTHROUGH */
+ case 1:
+ case 0:
+ while (len-- > 0)
+ rune = (rune << 8) | ((u_int)(*string++) & 0xff);
+ break;
+ }
+ if (result)
+ *result = string;
+ return ((rune & ~CEI->mask) | CEI->bits[set]);
+}
+
+int
+_EUC_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
+ size_t n;
+{
+ rune_t m = c & CEI->mask;
+ rune_t nm = c & ~m;
+ int i, len;
+
+ if (m == CEI->bits[1]) {
+CodeSet1:
+ /* Codeset 1: The first byte must have 0x80 in it. */
+ i = len = CEI->count[1];
+ if (n >= len) {
+ if (result)
+ *result = string + len;
+ while (i-- > 0)
+ *string++ = (nm >> (i << 3)) | 0x80;
+ } else
+ if (result)
+ *result = (char *) 0;
+ } else {
+ if (m == CEI->bits[0]) {
+ i = len = CEI->count[0];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ } else
+ if (m == CEI->bits[2]) {
+ i = len = CEI->count[2];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ *string++ = _SS2;
+ --i;
+ } else
+ if (m == CEI->bits[3]) {
+ i = len = CEI->count[3];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ *string++ = _SS3;
+ --i;
+ } else
+ goto CodeSet1; /* Bletch */
+ while (i-- > 0)
+ *string++ = (nm >> (i << 3)) & 0xff;
+ if (result)
+ *result = string;
+ }
+ return (len);
+}
diff --git a/lib/libc/locale/frune.c b/lib/libc/locale/frune.c
new file mode 100644
index 000000000000..443d3ba6eb36
--- /dev/null
+++ b/lib/libc/locale/frune.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)frune.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+
+long
+fgetrune(fp)
+ FILE *fp;
+{
+ rune_t r;
+ int c, len;
+ char buf[MB_LEN_MAX];
+ char const *result;
+
+ len = 0;
+ do {
+ if ((c = getc(fp)) == EOF) {
+ if (len)
+ break;
+ return (EOF);
+ }
+ buf[len++] = c;
+
+ if ((r = sgetrune(buf, len, &result)) != _INVALID_RUNE)
+ return (r);
+ } while (result == buf && len < MB_LEN_MAX);
+
+ while (--len > 0)
+ ungetc(buf[len], fp);
+ return (_INVALID_RUNE);
+}
+
+int
+fungetrune(r, fp)
+ rune_t r;
+ FILE* fp;
+{
+ int len;
+ char buf[MB_LEN_MAX];
+
+ len = sputrune(r, buf, MB_LEN_MAX, 0);
+ while (len-- > 0)
+ if (ungetc(buf[len], fp) == EOF)
+ return (EOF);
+ return (0);
+}
+
+int
+fputrune(r, fp)
+ rune_t r;
+ FILE *fp;
+{
+ int i, len;
+ char buf[MB_LEN_MAX];
+
+ len = sputrune(r, buf, MB_LEN_MAX, 0);
+
+ for (i = 0; i < len; ++i)
+ if (putc(buf[i], fp) == EOF)
+ return (EOF);
+
+ return (0);
+}
diff --git a/lib/libc/locale/isctype.c b/lib/libc/locale/isctype.c
new file mode 100644
index 000000000000..06cb1254ce68
--- /dev/null
+++ b/lib/libc/locale/isctype.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)isctype.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#define _ANSI_LIBRARY
+#include <ctype.h>
+
+#undef isalnum
+int
+isalnum(c)
+ int c;
+{
+ return(__istype((c), (_A|_D)));
+}
+
+#undef isalpha
+int
+isalpha(c)
+ int c;
+{
+ return (__istype((c), _A));
+}
+
+#undef isascii
+int
+isascii(c)
+ int c;
+{
+ return((c & ~0x7F) == 0);
+}
+
+#undef isblank
+int
+isblank(c)
+ int c;
+{
+ return (__istype((c), _B));
+}
+
+#undef iscntrl
+int
+iscntrl(c)
+ int c;
+{
+ return (__istype((c), _C));
+}
+
+#undef isdigit
+int
+isdigit(c)
+ int c;
+{
+ return (__isctype((c), _D));
+}
+
+#undef isgraph
+int
+isgraph(c)
+ int c;
+{
+ return (__istype((c), _G));
+}
+
+#undef islower
+int
+islower(c)
+ int c;
+{
+ return (__istype((c), _L));
+}
+
+#undef isprint
+int
+isprint(c)
+ int c;
+{
+ return (__istype((c), _R));
+}
+
+#undef ispunct
+int
+ispunct(c)
+ int c;
+{
+ return (__istype((c), _P));
+}
+
+#undef isspace
+int
+isspace(c)
+ int c;
+{
+ return (__istype((c), _S));
+}
+
+#undef isupper
+int
+isupper(c)
+ int c;
+{
+ return (__istype((c), _U));
+}
+
+#undef isxdigit
+int
+isxdigit(c)
+ int c;
+{
+ return (__isctype((c), _X));
+}
+
+#undef toascii
+int
+toascii(c)
+ int c;
+{
+ return (c & 0177);
+}
+
+#undef toupper
+int
+toupper(c)
+ int c;
+{
+ return((c & _CRMASK) ? ___toupper(c) : _CurrentRuneLocale->mapupper[c]);
+}
+
+#undef tolower
+int
+tolower(c)
+ int c;
+{
+ return((c & _CRMASK) ? ___tolower(c) : _CurrentRuneLocale->maplower[c]);
+}
diff --git a/lib/libc/locale/mbrune.3 b/lib/libc/locale/mbrune.3
new file mode 100644
index 000000000000..83e9dfe938d2
--- /dev/null
+++ b/lib/libc/locale/mbrune.3
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)mbrune.3 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt MBRUNE 3
+.Os
+.Sh NAME
+.Nm mbrune ,
+.Nm mbrrune ,
+.Nm mbmb
+.Nd multibyte rune support for C
+.Sh SYNOPSIS
+.Fd #include <rune.h>
+.Ft char *
+.Fn mbrune "const char *string" "rune_t rune"
+.Ft char *
+.Fn mbrrune "const char *string" "rune_t rune"
+.Ft char *
+.Fn mbmb "const char *string" "char *pattern"
+.Sh DESCRIPTION
+These routines provide the corresponding functionality of
+.Fn strchr ,
+.Fn strrchr
+and
+.Fn strstr
+for multibyte strings.
+.Pp
+The
+.Fn mbrune
+function locates the first occurrence of
+.Fn rune
+in the string pointed to by
+.Ar string .
+The terminating
+.Dv NULL
+character is considered part of the string.
+If
+.Fa rune
+is
+.Ql \e0 ,
+.Fn mbrune
+locates the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn mbrrune
+function
+locates the last occurrence of
+.Fa rune
+in the string
+.Fa string .
+If
+.Fa rune
+is
+.Ql \e0 ,
+.Fn mbrune
+locates the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn mbmb
+function locates the first occurrence of the null-terminated string
+.Fa pattern
+in the null-terminated string
+.Fa string.
+If
+.Fa pattern
+is the empty string,
+.Fn mbmb
+returns
+.Fa string ;
+if
+.Fa pattern
+occurs nowhere in
+.Fa string ,
+.Fn mbmb
+returns
+.Dv NULL ;
+otherwise
+.Fn mbmb
+returns a pointer to the first character of the first occurrence of
+.Fa pattern .
+.Sh RETURN VALUES
+The function
+.Fn mbrune
+returns a pointer to the located character, or
+.Dv NULL
+if the character does not appear in the string.
+.Pp
+The
+.Fn mbrrune
+function
+returns a pointer to the character, or
+.Dv NULL
+if the character does not appear in the string.
+.Pp
+The
+.Fn mbmb
+function
+returns a pointer to the
+.Fa pattern ,
+or
+.Dv NULL
+if the
+.Fa pattern
+does not appear in the string.
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr rune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh HISTORY
+The
+.Fn mbrune ,
+.Fn mbrrune ,
+and
+.Fn mbmb
+functions
+first appeared in Plan 9 from Bell Labs as
+.Fn utfrune ,
+.Fn utfrrune ,
+and
+.Fn utfutf .
diff --git a/lib/libc/locale/mbrune.c b/lib/libc/locale/mbrune.c
new file mode 100644
index 000000000000..92efe838a036
--- /dev/null
+++ b/lib/libc/locale/mbrune.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mbrune.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <rune.h>
+#include <stddef.h>
+#include <string.h>
+
+char *
+mbrune(string, c)
+ const char *string;
+ rune_t c;
+{
+ char const *result;
+ rune_t r;
+
+ while ((r = sgetrune(string, MB_LEN_MAX, &result))) {
+ if (r == c)
+ return ((char *)string);
+ string = result == string ? string + 1 : result;
+ }
+
+ return (c == *string ? (char *)string : NULL);
+}
+
+char *
+mbrrune(string, c)
+ const char *string;
+ rune_t c;
+{
+ const char *last = 0;
+ char const *result;
+ rune_t r;
+
+ while ((r = sgetrune(string, MB_LEN_MAX, &result))) {
+ if (r == c)
+ last = string;
+ string = result == string ? string + 1 : result;
+ }
+ return (c == *string ? (char *)string : (char *)last);
+}
+
+char *
+mbmb(string, pattern)
+ const char *string;
+ char *pattern;
+{
+ rune_t first, r;
+ size_t plen, slen;
+ char const *result;
+
+ plen = strlen(pattern);
+ slen = strlen(string);
+ if (plen > slen)
+ return (0);
+
+ first = sgetrune(pattern, plen, &result);
+ if (result == string)
+ return (0);
+
+ while (slen >= plen && (r = sgetrune(string, slen, &result))) {
+ if (r == first) {
+ if (strncmp(string, pattern, slen) == 0)
+ return ((char *) string);
+ }
+ if (result == string) {
+ --slen;
+ ++string;
+ } else {
+ slen -= result - string;
+ string = result;
+ }
+ }
+ return (0);
+}
diff --git a/lib/libc/locale/multibyte.3 b/lib/libc/locale/multibyte.3
new file mode 100644
index 000000000000..3ea10e5ace3d
--- /dev/null
+++ b/lib/libc/locale/multibyte.3
@@ -0,0 +1,241 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" 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.
+.\"
+.\" @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt MULTIBYTE 3
+.Os
+.Sh NAME
+.Nm mblen ,
+.Nm mbstowcs ,
+.Nm mbtowc ,
+.Nm wcstombs ,
+.Nm wctomb
+.Nd multibyte character support for C
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Ft int
+.Fn mblen "const char *mbchar" "int nbytes"
+.Ft size_t
+.Fn mbstowcs "wchar_t *wcstring" "const char *mbstring" "size_t nwchars"
+.Ft int
+.Fn mbtowc "wchar_t *wcharp" "const char *mbchar" "size_t nbytes"
+.Ft size_t
+.Fn wcstombs "char *mbstring" "const wchar_t *wcstring" "size_t nbytes"
+.Ft int
+.Fn wctomb "char *mbchar" "wchar_t wchar"
+.Sh DESCRIPTION
+The basic elements of some written natural languages such as Chinese
+cannot be represented uniquely with single C
+.Va char Ns s .
+The C standard supports two different ways of dealing with
+extended natural language encodings,
+.Em wide
+characters and
+.Em multibyte
+characters.
+Wide characters are an internal representation
+which allows each basic element to map
+to a single object of type
+.Va wchar_t .
+Multibyte characters are used for input and output
+and code each basic element as a sequence of C
+.Va char Ns s .
+Individual basic elements may map into one or more
+.Pq up to Dv MB_CHAR_MAX
+bytes in a multibyte character.
+.Pp
+The current locale
+.Pq Xr setlocale 3
+governs the interpretation of wide and multibyte characters.
+The locale category
+.Dv LC_CTYPE
+specifically controls this interpretation.
+The
+.Va wchar_t
+type is wide enough to hold the largest value
+in the wide character representations for all locales.
+.Pp
+Multibyte strings may contain
+.Sq shift
+indicators to switch to and from
+particular modes within the given representation.
+If explicit bytes are used to signal shifting,
+these are not recognized as separate characters
+but are lumped with a neighboring character.
+There is always a distinguished
+.Sq initial
+shift state.
+The
+.Fn mbstowcs
+and
+.Fn wcstombs
+functions assume that multibyte strings are interpreted
+starting from the initial shift state.
+The
+.Fn mblen ,
+.Fn mbtowc
+and
+.Fn wctomb
+functions maintain static shift state internally.
+A call with a null
+.Fa mbchar
+pointer returns nonzero if the current locale requires shift states,
+zero otherwise;
+if shift states are required, the shift state is reset to the initial state.
+The internal shift states are undefined after a call to
+.Fn setlocale
+with the
+.Dv LC_CTYPE
+or
+.Dv LC_ALL
+categories.
+.Pp
+For convenience in processing,
+the wide character with value 0
+.Pq the null wide character
+is recognized as the wide character string terminator,
+and the character with value 0
+.Pq the null byte
+is recognized as the multibyte character string terminator.
+Null bytes are not permitted within multibyte characters.
+.Pp
+The
+.Fn mblen
+function computes the length in bytes
+of a multibyte character
+.Fa mbchar .
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+The
+.Fn mbtowc
+function converts a multibyte character
+.Fa mbchar
+into a wide character and stores the result
+in the object pointed to by
+.Fa wcharp.
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+The
+.Fn wctomb
+function converts a wide character
+.Fa wchar
+into a multibyte character and stores
+the result in
+.Fa mbchar .
+The object pointed to by
+.Fa mbchar
+must be large enough to accommodate the multibyte character.
+.Pp
+The
+.Fn mbstowcs
+function converts a multibyte character string
+.Fa mbstring
+into a wide character string
+.Fa wcstring .
+No more than
+.Fa nwchars
+wide characters are stored.
+A terminating null wide character is appended if there is room.
+.Pp
+The
+.Fn wcstombs
+function converts a wide character string
+.Fa wcstring
+into a multibyte character string
+.Fa mbstring .
+Up to
+.Fa nbytes
+bytes are stored in
+.Fa mbstring .
+Partial multibyte characters at the end of the string are not stored.
+The multibyte character string is null terminated if there is room.
+.Sh "RETURN VALUES
+If multibyte characters are not supported in the current locale,
+all of these functions will return \-1 if characters can be processed,
+otherwise 0.
+.Pp
+If
+.Fa mbchar
+is
+.Dv NULL ,
+the
+.Fn mblen ,
+.Fn mbtowc
+and
+.Fn wctomb
+functions return nonzero if shift states are supported,
+zero otherwise.
+If
+.Fa mbchar
+is valid,
+then these functions return
+the number of bytes processed in
+.Fa mbchar ,
+or \-1 if no multibyte character
+could be recognized or converted.
+.Pp
+The
+.Fn mbstowcs
+function returns the number of wide characters converted,
+not counting any terminating null wide character.
+The
+.Fn wcstombs
+function returns the number of bytes converted,
+not counting any terminating null byte.
+If any invalid multibyte characters are encountered,
+both functions return \-1.
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr rune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh STANDARDS
+The
+.Fn mblen ,
+.Fn mbstowcs ,
+.Fn mbtowc ,
+.Fn wcstombs
+and
+.Fn wctomb
+functions conform to
+.St -ansiC .
+.Sh BUGS
+The current implementation does not support shift states.
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
new file mode 100644
index 000000000000..b5d8e44299cd
--- /dev/null
+++ b/lib/libc/locale/none.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)none.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <rune.h>
+#include <errno.h>
+#include <stdlib.h>
+
+rune_t _none_sgetrune __P((const char *, size_t, char const **));
+int _none_sputrune __P((rune_t, char *, size_t, char **));
+
+int
+_none_init(rl)
+ _RuneLocale *rl;
+{
+ rl->sgetrune = _none_sgetrune;
+ rl->sputrune = _none_sputrune;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 1;
+ return(0);
+}
+
+rune_t
+_none_sgetrune(string, n, result)
+ const char *string;
+ size_t n;
+ char const **result;
+{
+ int c;
+
+ if (n < 1) {
+ if (result)
+ *result = string;
+ return(_INVALID_RUNE);
+ }
+ if (result)
+ *result = string + 1;
+ return(*string & 0xff);
+}
+
+int
+_none_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
+ size_t n;
+{
+ if (n >= 1) {
+ if (string)
+ *string = c;
+ if (result)
+ *result = string + 1;
+ } else if (result)
+ *result = (char *)0;
+ return(1);
+}
diff --git a/lib/libc/locale/rune.3 b/lib/libc/locale/rune.3
new file mode 100644
index 000000000000..8d2ca5dd4b5e
--- /dev/null
+++ b/lib/libc/locale/rune.3
@@ -0,0 +1,269 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)rune.3 8.1 (Berkeley) 6/27/93
+.\"
+.Dd "June 27, 1993"
+.Dt RUNE 3
+.Os
+.Sh NAME
+.Nm setrunelocale ,
+.Nm setinvalidrune ,
+.Nm sgetrune ,
+.Nm sputrune
+.Nd rune support for C
+.Sh SYNOPSIS
+.Fd #include <rune.h>
+.Fd #include <errno.h>
+.Ft int
+.Fn setrunelocale "char *locale"
+.Ft void
+.Fn setinvalidrune "rune_t rune"
+.Ft rune_t
+.Fn sgetrune "const char *string" "size_t n" "char const **result"
+.Ft int
+.Fn sputrune "rune_t rune" "char *string" "size_t n" "char **result"
+.sp
+.Fd #include <stdio.h>
+.Ft long
+.Fn fgetrune "FILE *stream"
+.Ft int
+.Fn fungetrune "rune_t rune" "FILE *stream"
+.Ft int
+.Fn fputrune "rune_t rune" "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn setrunelocale
+controls the type of encoding used to represent runes as multibyte strings
+as well as the properties of the runes as defined in
+\fB<ctype.h>\fP.
+The
+.Fa locale
+argument indicates the locale which to load.
+If the locale is successfully loaded,
+.Dv 0
+is returned, otherwise an errno value is returned to indicate the
+type of error.
+.Pp
+The
+.Fn setinvalidrune
+function sets the value of the global value
+.Ev _INVALID_RUNE
+to be
+.Fa rune.
+.Pp
+The
+.Fn sgetrune
+function tries to read a single multibyte character from
+.Fa string ,
+which is at most
+.Fa n
+bytes long.
+If
+.Fn sgetrune
+is successful, the rune is returned.
+If
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will point to the first byte which was not converted in
+.Fa string.
+If the first
+.Fa n
+bytes of
+.Fa string
+do not describe a full multibyte character,
+.Ev _INVALID_RUNE
+is returned and
+.Fa *result
+will point to
+.Fa string.
+If there is an encoding error at the start of
+.Fa string ,
+.Ev _INVALID_RUNE
+is returned and
+.Fa *result
+will point to the second character of
+.Fa string.
+.Pp
+the
+.Fn sputrune
+function tries to encode
+.Fa rune
+as a multibyte string and store it at
+.Fa string ,
+but no more than
+.Fa n
+bytes will be stored.
+If
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will be set to point to the first byte in string following the new
+multibyte character.
+If
+.Fa string
+is
+.Dv NULL ,
+.Fa *result
+will point to
+.Dv "(char *)0 +"
+.Fa x ,
+where
+.Fa x
+is the number of bytes that would be needed to store the multibyte value.
+If the multibyte character would consist of more than
+.Fa n
+bytes and
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will be set to
+.Dv NULL.
+In all cases,
+.Fn sputrune
+will return the number of bytes which would be needed to store
+.Fa rune
+as a multibyte character.
+.Pp
+The
+.Fn fgetrune
+function operates the same as
+.Fn sgetrune
+with the exception that it attempts to read enough bytes from
+.Fa stream
+to decode a single rune. It returns either
+.Ev EOF
+on end of file,
+.Ev _INVALID_RUNE
+on an encoding error, or the rune decoded if all went well.
+.Pp
+The
+.Fn fungetrune
+function function pushes the multibyte encoding, as provided by
+.Fn sputrune ,
+of
+.Fa rune
+onto
+.Fa stream
+such that the next
+.Fn fgetrune
+call will return
+.Fa rune .
+It returns
+.Ev EOF
+if it fails and
+.Dv 0
+on success.
+.Pp
+The
+.Fn fputrune
+function writes the multibyte encoding of
+.Fa rune ,
+as provided by
+.Fn sputrune ,
+onto
+.Fa stream .
+It returns
+.Ev EOF
+on failure and
+.Dv 0
+on success.
+.Sh RETURN VALUES
+The
+.Fn setrunelocale
+function returns one of the following values:
+.Bl -tag -width WWWWWWWW
+.It Dv 0
+.Fa setrunelocale was successful.
+.It Ev EFAULT
+.Fa locale
+was
+.Dv NULL .
+.It Ev ENOENT
+The locale could not be found.
+.It Ev EFTYPE
+The file found was not a valid file.
+.It Ev EINVAL
+The encoding indicated by the locale was unknown.
+.El
+.Pp
+The
+.Fn sgetrune
+function either returns the rune read or
+.Ev _INVALID_RUNE .
+The
+.Fn sputrune
+function returns the number of bytes needed to store
+.Fa rune
+as a multibyte string.
+.Sh FILES
+.Bl -tag -width /usr/share/locale/locale/LC_CTYPE -compact
+.It Pa $PATH_LOCALE/\fIlocale\fP/LC_CTYPE
+.It Pa /usr/share/locale/\fIlocale\fP/LC_CTYPE
+binary LC_CTYPE file for the locale \fIlocale\fP.
+.El
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh NOTE
+The ANSI C type
+.Ev wchar_t
+is the same as
+.Ev rune_t .
+.Ev Rune_t
+was chosen to accent the purposeful choice of not basing the
+system with the ANSI C
+primitives, which were, shall we say, less aesthetic.
+.Sh HISTORY
+These functions first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Fn setrunelocale
+function and the other non-ANSI rune functions were inspired by
+.Nm Plan 9 from Bell Labs
+as a much more sane alternative to the ANSI multibyte and
+wide character support.
+.\"They were conceived at the San Diego 1993 Summer USENIX conference by
+.\"Paul Borman of Krystal Technologies, Keith Bostic of CSRG and Andrew Hume
+.\"of Bell Labs.
+.Pp
+All of the ANSI multibyte and wide character
+support functions are built using the rune functions.
diff --git a/lib/libc/locale/rune.c b/lib/libc/locale/rune.c
new file mode 100644
index 000000000000..b239484fac81
--- /dev/null
+++ b/lib/libc/locale/rune.c
@@ -0,0 +1,334 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rune.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <rune.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int _none_init __P((_RuneLocale *));
+extern int _UTF2_init __P((_RuneLocale *));
+extern int _EUC_init __P((_RuneLocale *));
+static _RuneLocale *_Read_RuneMagi __P((FILE *));
+
+static char *PathLocale = 0;
+
+int
+setrunelocale(encoding)
+ char *encoding;
+{
+ FILE *fp;
+ char name[PATH_MAX];
+ _RuneLocale *rl;
+
+ if (!encoding)
+ return(EFAULT);
+
+ /*
+ * The "C" and "POSIX" locale are always here.
+ */
+ if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) {
+ _CurrentRuneLocale = &_DefaultRuneLocale;
+ return(0);
+ }
+
+ if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
+ PathLocale = _PATH_LOCALE;
+
+ sprintf(name, "%s/%s/LC_CTYPE", PathLocale, encoding);
+
+ if ((fp = fopen(name, "r")) == NULL)
+ return(ENOENT);
+
+ if ((rl = _Read_RuneMagi(fp)) == 0) {
+ fclose(fp);
+ return(EFTYPE);
+ }
+
+ if (!rl->encoding[0] || !strcmp(rl->encoding, "UTF2")) {
+ return(_UTF2_init(rl));
+ } else if (!strcmp(rl->encoding, "NONE")) {
+ return(_none_init(rl));
+ } else if (!strcmp(rl->encoding, "EUC")) {
+ return(_EUC_init(rl));
+ } else
+ return(EINVAL);
+}
+
+void
+setinvalidrune(ir)
+ rune_t ir;
+{
+ _INVALID_RUNE = ir;
+}
+
+static _RuneLocale *
+_Read_RuneMagi(fp)
+ FILE *fp;
+{
+ char *data;
+ void *np;
+ void *lastp;
+ _RuneLocale *rl;
+ _RuneEntry *rr;
+ struct stat sb;
+ int x;
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return(0);
+
+ if (sb.st_size < sizeof(_RuneLocale))
+ return(0);
+
+ if ((data = malloc(sb.st_size)) == NULL)
+ return(0);
+
+ rewind(fp); /* Someone might have read the magic number once already */
+
+ if (fread(data, sb.st_size, 1, fp) != 1) {
+ free(data);
+ return(0);
+ }
+
+ rl = (_RuneLocale *)data;
+ lastp = data + sb.st_size;
+
+ rl->variable = rl + 1;
+
+ if (memcmp(rl->magic, _RUNE_MAGIC_1, sizeof(rl->magic))) {
+ free(data);
+ return(0);
+ }
+
+ rl->invalid_rune = ntohl(rl->invalid_rune);
+ rl->variable_len = ntohl(rl->variable_len);
+ rl->runetype_ext.nranges = ntohl(rl->runetype_ext.nranges);
+ rl->maplower_ext.nranges = ntohl(rl->maplower_ext.nranges);
+ rl->mapupper_ext.nranges = ntohl(rl->mapupper_ext.nranges);
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ rl->runetype[x] = ntohl(rl->runetype[x]);
+ rl->maplower[x] = ntohl(rl->maplower[x]);
+ rl->mapupper[x] = ntohl(rl->mapupper[x]);
+ }
+
+ rl->runetype_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->runetype_ext.ranges + rl->runetype_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ rl->maplower_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->maplower_ext.ranges + rl->maplower_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ rl->mapupper_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->mapupper_ext.ranges + rl->mapupper_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ for (x = 0; x < rl->runetype_ext.nranges; ++x) {
+ rr = rl->runetype_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ if ((rr[x].map = ntohl(rr[x].map)) == 0) {
+ int len = rr[x].max - rr[x].min + 1;
+ rr[x].types = rl->variable;
+ rl->variable = rr[x].types + len;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+ while (len-- > 0)
+ rr[x].types[len] = ntohl(rr[x].types[len]);
+ } else
+ rr[x].types = 0;
+ }
+
+ for (x = 0; x < rl->maplower_ext.nranges; ++x) {
+ rr = rl->maplower_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ rr[x].map = ntohl(rr[x].map);
+ }
+
+ for (x = 0; x < rl->mapupper_ext.nranges; ++x) {
+ rr = rl->mapupper_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ rr[x].map = ntohl(rr[x].map);
+ }
+ if (((char *)rl->variable) + rl->variable_len > (char *)lastp) {
+ free(data);
+ return(0);
+ }
+
+ /*
+ * Go out and zero pointers that should be zero.
+ */
+ if (!rl->variable_len)
+ rl->variable = 0;
+
+ if (!rl->runetype_ext.nranges)
+ rl->runetype_ext.ranges = 0;
+
+ if (!rl->maplower_ext.nranges)
+ rl->maplower_ext.ranges = 0;
+
+ if (!rl->mapupper_ext.nranges)
+ rl->mapupper_ext.ranges = 0;
+
+ return(rl);
+}
+
+unsigned long
+___runetype(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->runetype_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(0);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(0L);
+ if (c <= re->max) {
+ if (re->types)
+ return(re->types[c - re->min]);
+ else
+ return(re->map);
+ }
+ }
+ return(0L);
+}
+
+_BSD_RUNE_T_
+___toupper(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->mapupper_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(EOF);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(c);
+ if (c <= re->max)
+ return(re->map + c - re->min);
+ }
+ return(c);
+}
+
+_BSD_RUNE_T_
+___tolower(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->maplower_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(EOF);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(c);
+ if (c <= re->max)
+ return(re->map + c - re->min);
+ }
+ return(c);
+}
+
+
+#if !defined(_USE_CTYPE_INLINE_) && !defined(_USE_CTYPE_MACROS_)
+/*
+ * See comments in <machine/ansi.h>
+ */
+int
+__istype(c, f)
+ _BSD_RUNE_T_ c;
+ unsigned long f;
+{
+ return ((((c & _CRMASK) ? ___runetype(c)
+ : _CurrentRuneLocale->runetype[c]) & f) ? 1 : 0);
+}
+
+int
+__isctype(_BSD_RUNE_T_ c, unsigned long f)
+ _BSD_RUNE_T_ c;
+ unsigned long f;
+{
+ return ((((c & _CRMASK) ? 0
+ : _DefaultRuneLocale.runetype[c]) & f) ? 1 : 0);
+}
+
+_BSD_RUNE_T_
+toupper(c)
+ _BSD_RUNE_T_ c;
+{
+ return ((c & _CRMASK) ?
+ ___toupper(c) : _CurrentRuneLocale->mapupper[c]);
+}
+
+_BSD_RUNE_T_
+tolower(c)
+ _BSD_RUNE_T_ c;
+{
+ return ((c & _CRMASK) ?
+ ___tolower(c) : _CurrentRuneLocale->maplower[c]);
+}
+#endif
diff --git a/lib/libc/locale/setlocale.3 b/lib/libc/locale/setlocale.3
new file mode 100644
index 000000000000..74cce03bfc5e
--- /dev/null
+++ b/lib/libc/locale/setlocale.3
@@ -0,0 +1,321 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" 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.
+.\"
+.\" @(#)setlocale.3 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt SETLOCALE 3
+.Os
+.Sh NAME
+.Nm setlocale ,
+.Nm localeconv
+.Nd natural language formatting for C
+.Sh SYNOPSIS
+.Fd #include <locale.h>
+.Ft char *
+.Fn setlocale "int category" "const char *locale"
+.Ft struct lconv *
+.Fn localeconv "void"
+.Sh DESCRIPTION
+The
+.Fn setlocale
+function sets the C library's notion
+of natural language formatting style
+for particular sets of routines.
+Each such style is called a
+.Sq locale
+and is invoked using an appropriate name passed as a C string.
+The
+.Fn localeconv
+routine returns the current locale's parameters
+for formatting numbers.
+.Pp
+The
+.Fn setlocale
+function recognizes several categories of routines.
+These are the categories and the sets of routines they select:
+.Pp
+.Bl -tag -width LC_MONETARY
+.It Dv LC_ALL
+Set the entire locale generically.
+.It Dv LC_COLLATE
+Set a locale for string collation routines.
+This controls alphabetic ordering in
+.Fn strcoll
+and
+.Fn strxfrm .
+.It Dv LC_CTYPE
+Set a locale for the
+.Xr ctype 3 ,
+.Xr mbrune 3 ,
+.Xr multibyte 3
+and
+.Xr rune 3
+functions.
+This controls recognition of upper and lower case,
+alphabetic or non-alphabetic characters,
+and so on. The real work is done by the
+.Fn setrunelocale
+function.
+.It Dv LC_MONETARY
+Set a locale for formatting monetary values;
+this affects the
+.Fn localeconv
+function.
+.It Dv LC_NUMERIC
+Set a locale for formatting numbers.
+This controls the formatting of decimal points
+in input and output of floating point numbers
+in functions such as
+.Fn printf
+and
+.Fn scanf ,
+as well as values returned by
+.Fn localeconv .
+.It Dv LC_TIME
+Set a locale for formatting dates and times using the
+.Fn strftime
+function.
+.El
+.Pp
+Only three locales are defined by default,
+the empty string
+.Li "\&""\|""
+which denotes the native environment, and the
+.Li "\&""C""
+and
+.LI "\&""POSIX""
+locales, which denote the C language environment.
+A
+.Fa locale
+argument of
+.Dv NULL
+causes
+.Fn setlocale
+to return the current locale.
+By default, C programs start in the
+.Li "\&""C""
+locale.
+The only function in the library that sets the locale is
+.Fn setlocale ;
+the locale is never changed as a side effect of some other routine.
+.Pp
+The
+.Fn localeconv
+function returns a pointer to a structure
+which provides parameters for formatting numbers,
+especially currency values:
+.Bd -literal -offset indent
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *int_curr_symbol;
+ char *currency_symbol;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+};
+.Ed
+.Pp
+The individual fields have the following meanings:
+.Pp
+.Bl -tag -width mon_decimal_point
+.It Fa decimal_point
+The decimal point character, except for currency values.
+.It Fa thousands_sep
+The separator between groups of digits
+before the decimal point, except for currency values.
+.It Fa grouping
+The sizes of the groups of digits, except for currency values.
+This is a pointer to a vector of integers, each of size
+.Va char ,
+representing group size from low order digit groups
+to high order (right to left).
+The list may be terminated with 0 or
+.Dv CHAR_MAX .
+If the list is terminated with 0,
+the last group size before the 0 is repeated to account for all the digits.
+If the list is terminated with
+.Dv CHAR_MAX ,
+no more grouping is performed.
+.It Fa int_curr_symbol
+The standardized international currency symbol.
+.It Fa currency_symbol
+The local currency symbol.
+.It Fa mon_decimal_point
+The decimal point character for currency values.
+.It Fa mon_thousands_sep
+The separator for digit groups in currency values.
+.It Fa mon_grouping
+Like
+.Fa grouping
+but for currency values.
+.It Fa positive_sign
+The character used to denote nonnegative currency values,
+usually the empty string.
+.It Fa negative_sign
+The character used to denote negative currency values,
+usually a minus sign.
+.It Fa int_frac_digits
+The number of digits after the decimal point
+in an international-style currency value.
+.It Fa frac_digits
+The number of digits after the decimal point
+in the local style for currency values.
+.It Fa p_cs_precedes
+1 if the currency symbol precedes the currency value
+for nonnegative values, 0 if it follows.
+.It Fa p_sep_by_space
+1 if a space is inserted between the currency symbol
+and the currency value for nonnegative values, 0 otherwise.
+.It Fa n_cs_precedes
+Like
+.Fa p_cs_precedes
+but for negative values.
+.It Fa n_sep_by_space
+Like
+.Fa p_sep_by_space
+but for negative values.
+.It Fa p_sign_posn
+The location of the
+.Fa positive_sign
+with respect to a nonnegative quantity and the
+.Fa currency_symbol ,
+coded as follows:
+.Bl -tag -width 3n -compact
+.It Li 0
+Parentheses around the entire string.
+.It Li 1
+Before the string.
+.It Li 2
+After the string.
+.It Li 3
+Just before
+.Fa currency_symbol .
+.It Li 4
+Just after
+.Fa currency_symbol .
+.El
+.It Fa n_sign_posn
+Like
+.Fa p_sign_posn
+but for negative currency values.
+.El
+.Pp
+Unless mentioned above,
+an empty string as a value for a field
+indicates a zero length result or
+a value that is not in the current locale.
+A
+.Dv CHAR_MAX
+result similarly denotes an unavailable value.
+.Sh "RETURN VALUES
+The
+.Fn setlocale
+function returns
+.Dv NULL
+and fails to change the locale
+if the given combination of
+.Fa category
+and
+.Fa locale
+makes no sense.
+The
+.Fn localeconv
+function returns a pointer to a static object
+which may be altered by later calls to
+.Fn setlocale
+or
+.Fn localeconv .
+.Sh FILES
+.Bl -tag -width /usr/share/locale/locale/category -compact
+.It Pa $PATH_LOCALE/\fIlocale\fP/\fIcategory\fP
+.It Pa /usr/share/locale/\fIlocale\fP/\fIcategory\fP
+locale file for the locale \fIlocale\fP
+and the category \fIcategory\fP.
+.El
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr multibyte 3 ,
+.Xr rune 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr utf2 4
+.Sh STANDARDS
+The
+.Fn setlocale
+and
+.Fn localeconv
+functions conform to
+.St -ansiC .
+.Sh HISTORY
+The
+.Fn setlocale
+and
+.Fn localeconv
+functions first appeared in 4.4BSD.
+.Sh BUGS
+The current implementation supports only the
+.Li "\&""C""
+and
+.Li "\&""POSIX""
+locales for all but the LC_CTYPE locale.
+.Pp
+In spite of the gnarly currency support in
+.Fn localeconv ,
+the standards don't include any functions
+for generalized currency formatting.
+.Pp
+.Dv LC_COLLATE
+does not make sense for many languages.
+Use of
+.Dv LC_MONETARY
+could lead to misleading results until we have a real time currency
+conversion function.
+.Dv LC_NUMERIC
+and
+.Dv LC_TIME
+are personal choices and should not be wrapped up with the other categories.
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
index 247a2782b0c9..414f58ef381a 100644
--- a/lib/libc/locale/setlocale.c
+++ b/lib/libc/locale/setlocale.c
@@ -1,6 +1,9 @@
/*
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,27 +35,200 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setlocale.c 5.2 (Berkeley) 2/24/91";
+static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93";
#endif /* LIBC_SCCS and not lint */
+#include <limits.h>
#include <locale.h>
+#include <rune.h>
+#include <stdlib.h>
#include <string.h>
-static char C[] = "C";
+/*
+ * Category names for getenv()
+ */
+static char *categories[_LC_LAST] = {
+ "LC_ALL",
+ "LC_COLLATE",
+ "LC_CTYPE",
+ "LC_MONETARY",
+ "LC_NUMERIC",
+ "LC_TIME",
+};
/*
- * The setlocale function.
- *
- * Sorry, for now we only accept the C locale.
+ * Current locales for each category
*/
+static char current_categories[_LC_LAST][32] = {
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+};
+
+/*
+ * The locales we are going to try and load
+ */
+static char new_categories[_LC_LAST][32];
+
+static char current_locale_string[_LC_LAST * 33];
+static char *PathLocale;
+
+static char *currentlocale __P((void));
+static char *loadlocale __P((int));
+
char *
setlocale(category, locale)
int category;
const char *locale;
{
- if ((unsigned int)category >= _LC_LAST)
+ int found, i, len;
+ char *env, *r;
+
+ if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
+ PathLocale = _PATH_LOCALE;
+
+ if (category < 0 || category >= _LC_LAST)
return (NULL);
- if (locale == NULL)
- return (C);
- return(strcmp(locale, C) ? NULL : C);
+
+ if (!locale)
+ return (category ?
+ current_categories[category] : currentlocale());
+
+ /*
+ * Default to the current locale for everything.
+ */
+ for (i = 1; i < _LC_LAST; ++i)
+ (void)strcpy(new_categories[i], current_categories[i]);
+
+ /*
+ * Now go fill up new_categories from the locale argument
+ */
+ if (!*locale) {
+ env = getenv(categories[category]);
+
+ if (!env)
+ env = getenv(categories[0]);
+
+ if (!env)
+ env = getenv("LANG");
+
+ if (!env)
+ env = "C";
+
+ (void) strncpy(new_categories[category], env, 31);
+ new_categories[category][31] = 0;
+ if (!category) {
+ for (i = 1; i < _LC_LAST; ++i) {
+ if (!(env = getenv(categories[i])))
+ env = new_categories[0];
+ (void)strncpy(new_categories[i], env, 31);
+ new_categories[i][31] = 0;
+ }
+ }
+ } else if (category) {
+ (void)strncpy(new_categories[category], locale, 31);
+ new_categories[category][31] = 0;
+ } else {
+ if ((r = strchr(locale, '/')) == 0) {
+ for (i = 1; i < _LC_LAST; ++i) {
+ (void)strncpy(new_categories[i], locale, 31);
+ new_categories[i][31] = 0;
+ }
+ } else {
+ for (i = 1; r[1] == '/'; ++r);
+ if (!r[1])
+ return (NULL); /* Hmm, just slashes... */
+ do {
+ len = r - locale > 31 ? 31 : r - locale;
+ (void)strncpy(new_categories[i++], locale, len);
+ new_categories[i++][len] = 0;
+ locale = r;
+ while (*locale == '/')
+ ++locale;
+ while (*++r && *r != '/');
+ } while (*locale);
+ while (i < _LC_LAST)
+ (void)strcpy(new_categories[i],
+ new_categories[i-1]);
+ }
+ }
+
+ if (category)
+ return (loadlocale(category));
+
+ found = 0;
+ for (i = 1; i < _LC_LAST; ++i)
+ if (loadlocale(i) != NULL)
+ found = 1;
+ if (found)
+ return (currentlocale());
+ return (NULL);
+}
+
+static char *
+currentlocale()
+{
+ int i;
+
+ (void)strcpy(current_locale_string, current_categories[1]);
+
+ for (i = 2; i < _LC_LAST; ++i)
+ if (strcmp(current_categories[1], current_categories[i])) {
+ (void)snprintf(current_locale_string,
+ sizeof(current_locale_string), "%s/%s/%s/%s/%s",
+ current_categories[1], current_categories[2],
+ current_categories[3], current_categories[4],
+ current_categories[5]);
+ break;
+ }
+ return (current_locale_string);
+}
+
+static char *
+loadlocale(category)
+ int category;
+{
+ char name[PATH_MAX];
+
+ if (strcmp(new_categories[category],
+ current_categories[category]) == 0)
+ return (current_categories[category]);
+
+ if (category == LC_CTYPE) {
+ if (setrunelocale(new_categories[LC_CTYPE]))
+ return (NULL);
+ (void)strcpy(current_categories[LC_CTYPE],
+ new_categories[LC_CTYPE]);
+ return (current_categories[LC_CTYPE]);
+ }
+
+ if (!strcmp(new_categories[category], "C") ||
+ !strcmp(new_categories[category], "POSIX")) {
+
+ /*
+ * Some day this will need to reset the locale to the default
+ * C locale. Since we have no way to change them as of yet,
+ * there is no need to reset them.
+ */
+ (void)strcpy(current_categories[category],
+ new_categories[category]);
+ return (current_categories[category]);
+ }
+
+ /*
+ * Some day we will actually look at this file.
+ */
+ (void)snprintf(name, sizeof(name), "%s/%s/%s",
+ PathLocale, new_categories[category], categories[category]);
+
+ switch (category) {
+ case LC_COLLATE:
+ case LC_MONETARY:
+ case LC_NUMERIC:
+ case LC_TIME:
+ return (NULL);
+ }
}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
new file mode 100644
index 000000000000..fb7344eafad5
--- /dev/null
+++ b/lib/libc/locale/table.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <rune.h>
+
+extern rune_t _none_sgetrune __P((const char *, size_t, char const **));
+extern int _none_sputrune __P((rune_t, char *, size_t, char **));
+extern int _none_init __P((char *, char **));
+
+_RuneLocale _DefaultRuneLocale = {
+ _RUNE_MAGIC_1,
+ "none",
+ _none_sgetrune,
+ _none_sputrune,
+ 0xFFFD,
+
+ { /*00*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*08*/ _C, _C|_S|_B, _C|_S, _C|_S,
+ _C|_S, _C|_S, _C, _C,
+ /*10*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*18*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*20*/ _S|_B|_R, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*28*/ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*30*/ _D|_R|_G|_X|0, _D|_R|_G|_X|1, _D|_R|_G|_X|2, _D|_R|_G|_X|3,
+ _D|_R|_G|_X|4, _D|_R|_G|_X|5, _D|_R|_G|_X|6, _D|_R|_G|_X|7,
+ /*38*/ _D|_R|_G|_X|8, _D|_R|_G|_X|9, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*40*/ _P|_R|_G, _U|_X|_R|_G|_A|10, _U|_X|_R|_G|_A|11, _U|_X|_R|_G|_A|12,
+ _U|_X|_R|_G|_A|13, _U|_X|_R|_G|_A|14, _U|_X|_R|_G|_A|15, _U|_R|_G|_A,
+ /*48*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ /*50*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ /*58*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*60*/ _P|_R|_G, _L|_X|_R|_G|_A|10, _L|_X|_R|_G|_A|11, _L|_X|_R|_G|_A|12,
+ _L|_X|_R|_G|_A|13, _L|_X|_R|_G|_A|14, _L|_X|_R|_G|_A|15, _L|_R|_G|_A,
+ /*68*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ /*70*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ /*78*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _C,
+ },
+ { 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, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 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,
+ },
+ { 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, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 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,
+ },
+};
+
+_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+
+int __mb_cur_max = 1;
diff --git a/lib/libc/locale/utf2.4 b/lib/libc/locale/utf2.4
new file mode 100644
index 000000000000..c46f4f986c41
--- /dev/null
+++ b/lib/libc/locale/utf2.4
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)utf2.4 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt UTF2 4
+.Os
+.Sh NAME
+.Nm UTF2
+.Nd "Universal character set Transformation Format encoding of runes
+.Sh SYNOPSIS
+\fBENCODING "UTF2"\fP
+.Sh DESCRIPTION
+The
+.Nm UTF2
+encoding is based on a proposed X-Open multibyte
+\s-1FSS-UCS-TF\s+1 (File System Safe Universal Character Set Transformation Format) encoding as used in
+.Nm Plan 9 from Bell Labs.
+Although it is capable of representing more than 16 bits,
+the current implementation is limited to 16 bits as defined by the
+Unicode Standard.
+UTF2 is also called UTF8 in some circles.
+.Pp
+.Nm UTF2
+representation is backwards compatible with ASCII, so 0x00-0x7f refer to the
+ASCII character set. The multibyte encoding of runes between 0x0080 and 0xffff
+consist entirely of bytes whose high order bit is set. The actual
+encoding is represented by the following table:
+.Bd -literal
+[0x0000 - 0x007f] [00000000.0bbbbbbb] -> 0bbbbbbb
+[0x0080 - 0x03ff] [00000bbb.bbbbbbbb] -> 110bbbbb, 10bbbbbb
+[0x0400 - 0xffff] [bbbbbbbb.bbbbbbbb] -> 1110bbbb, 10bbbbbb, 10bbbbbb
+.Ed
+.sp
+If more than a single representation of a value exists (for example,
+0x00; 0xC0 0x80; 0xE0 0x80 0x80) the shortest representation is always
+used (but the longer ones will be correctly decoded).
+.Pp
+The final three encodings provided by X-Open:
+.Bd -literal
+[00000000.000bbbbb.bbbbbbbb.bbbbbbbb] ->
+ 11110bbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+
+[000000bb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 111110bb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+
+[0bbbbbbb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 1111110b, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+.Ed
+.sp
+which provides for the entire proposed ISO-10646 31 bit standard are currently
+not implemented.
+.Sh "SEE ALSO"
+.Xr mklocale 1 ,
+.Xr setlocale 3
diff --git a/lib/libc/locale/utf2.c b/lib/libc/locale/utf2.c
new file mode 100644
index 000000000000..846fad90ed6f
--- /dev/null
+++ b/lib/libc/locale/utf2.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)utf2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <errno.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+rune_t _UTF2_sgetrune __P((const char *, size_t, char const **));
+int _UTF2_sputrune __P((rune_t, char *, size_t, char **));
+
+static _utf_count[16] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 2, 2, 3, 0,
+};
+
+int
+_UTF2_init(rl)
+ _RuneLocale *rl;
+{
+ rl->sgetrune = _UTF2_sgetrune;
+ rl->sputrune = _UTF2_sputrune;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 3;
+ return (0);
+}
+
+rune_t
+_UTF2_sgetrune(string, n, result)
+ const char *string;
+ size_t n;
+ char const **result;
+{
+ int c;
+
+ if (n < 1 || (c = _utf_count[(*string >> 4) & 0xf]) > n) {
+ if (result)
+ *result = string;
+ return (_INVALID_RUNE);
+ }
+ switch (c) {
+ case 1:
+ if (result)
+ *result = string + 1;
+ return (*string & 0xff);
+ case 2:
+ if ((string[1] & 0xC0) != 0x80)
+ goto encoding_error;
+ if (result)
+ *result = string + 2;
+ return (((string[0] & 0x1F) << 6) | (string[1] & 0x3F));
+ case 3:
+ if ((string[1] & 0xC0) != 0x80 || (string[2] & 0xC0) != 0x80)
+ goto encoding_error;
+ if (result)
+ *result = string + 3;
+ return (((string[0] & 0x1F) << 12) | ((string[1] & 0x3F) << 6)
+ | (string[2] & 0x3F));
+ default:
+encoding_error: if (result)
+ *result = string + 1;
+ return (_INVALID_RUNE);
+ }
+}
+
+int
+_UTF2_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
+ size_t n;
+{
+ if (c & 0xF800) {
+ if (n >= 3) {
+ if (string) {
+ string[0] = 0xE0 | ((c >> 12) & 0x0F);
+ string[1] = 0x80 | ((c >> 6) & 0x3F);
+ string[2] = 0x80 | ((c) & 0x3F);
+ }
+ if (result)
+ *result = string + 3;
+ } else
+ if (result)
+ *result = NULL;
+
+ return (3);
+ } else
+ if (c & 0x0780) {
+ if (n >= 2) {
+ if (string) {
+ string[0] = 0xC0 | ((c >> 6) & 0x1F);
+ string[1] = 0x80 | ((c) & 0x3F);
+ }
+ if (result)
+ *result = string + 2;
+ } else
+ if (result)
+ *result = NULL;
+ return (2);
+ } else {
+ if (n >= 1) {
+ if (string)
+ string[0] = c;
+ if (result)
+ *result = string + 1;
+ } else
+ if (result)
+ *result = NULL;
+ return (1);
+ }
+}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 2b1597a20796..b4c154672d58 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -120,6 +120,7 @@ init_services()
service_order[cc++] = SERVICE_NIS;
}
service_order[cc] = SERVICE_NONE;
+ fclose(fd);
}
service_done = 1;
}
diff --git a/lib/libc/net/ns_addr.c b/lib/libc/net/ns_addr.c
index e31e6d13570f..684dd8e79165 100644
--- a/lib/libc/net/ns_addr.c
+++ b/lib/libc/net/ns_addr.c
@@ -55,8 +55,8 @@ ns_addr(name)
char *hostname, *socketname, *cp;
char buf[50];
- (void)strncpy(buf, name, sizeof(buf - 1));
- buf[sizeof(buf - 1)] = '\0';
+ (void)strncpy(buf, name, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
/*
* First, figure out what he intends as a field separtor.
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
index d0cd18000ba9..5d1a575fe110 100644
--- a/lib/libc/net/rcmd.c
+++ b/lib/libc/net/rcmd.c
@@ -38,6 +38,7 @@ static char sccsid[] = "@(#)rcmd.c 5.24 (Berkeley) 2/24/91";
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
@@ -138,7 +139,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
FD_SET(s, &reads);
FD_SET(s2, &reads);
errno = 0;
- if (select(32, &reads, 0, 0, 0) < 1 ||
+ if (select(FD_SETSIZE, &reads, 0, 0, 0) < 1 ||
!FD_ISSET(s2, &reads)) {
if (errno != 0)
perror("select: setting up stderr");
@@ -230,6 +231,12 @@ ruserok(rhost, superuser, ruser, luser)
int first = 1;
register char *sp, *p;
int baselen = -1;
+ uid_t suid;
+ gid_t sgid;
+ int int_sgid; /* this is a kludge and should be removed
+ when we transition to FreeBSD 2.0. If you
+ find this code in a 2.0 source tree, please
+ contact the core team. */
sp = (char *)rhost;
p = fhost;
@@ -248,6 +255,12 @@ again:
if (hostf) {
if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
(void) fclose(hostf);
+ if (first == 0) {
+ (void)seteuid(suid);
+ (void)setegid(sgid);
+ int_sgid = sgid;
+ (void)setgroups(1, &int_sgid);
+ }
return(0);
}
(void) fclose(hostf);
@@ -258,12 +271,17 @@ again:
char pbuf[MAXPATHLEN];
first = 0;
+ suid = geteuid();
+ sgid = getegid();
if ((pwd = getpwnam(luser)) == NULL)
return(-1);
+ (void)setegid(pwd->pw_gid);
+ (void)initgroups(luser, pwd->pw_gid);
+ (void)seteuid(pwd->pw_uid);
(void)strcpy(pbuf, pwd->pw_dir);
(void)strcat(pbuf, "/.rhosts");
if ((hostf = fopen(pbuf, "r")) == NULL)
- return(-1);
+ goto bad;
/*
* if owned by someone other than user or root or if
* writeable by anyone but the owner, quit
@@ -272,10 +290,16 @@ again:
sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
sbuf.st_mode&022) {
fclose(hostf);
- return(-1);
+ goto bad;
}
goto again;
}
+bad:
+ if (first == 0) {
+ (void)seteuid(suid);
+ (void)setegid(sgid);
+ (void)setgroups(1, (int *)&sgid);
+ }
return (-1);
}
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
index ad87006fbac7..3fd05f51ffc3 100644
--- a/lib/libc/stdio/Makefile.inc
+++ b/lib/libc/stdio/Makefile.inc
@@ -3,8 +3,9 @@
# stdio sources
.PATH: ${.CURDIR}/stdio
-SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
- fgetline.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \
+SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c \
+ fgetc.c fgetline.c fgetln.c fgetpos.c fgets.c \
+ fileno.c findfp.c flags.c fopen.c \
fprintf.c fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
getc.c getchar.c gets.c getw.c makebuf.c perror.c printf.c putc.c \
@@ -14,7 +15,7 @@ SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
vfscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c vsscanf.c \
wbuf.c wsetup.c
-MAN3+= stdio/fclose.3 stdio/ferror.3 stdio/fflush.3 stdio/fgetline.3 \
+MAN3+= stdio/fclose.3 stdio/ferror.3 stdio/fflush.3 stdio/fgetln.3 \
stdio/fgets.3 stdio/fopen.3 stdio/fputs.3 stdio/fread.3 \
stdio/fseek.3 stdio/funopen.3 stdio/getc.3 stdio/mktemp.3 \
stdio/printf.3 stdio/putc.3 stdio/remove.3 stdio/scanf.3 \
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
index 27d873f2073f..974cd444853d 100644
--- a/lib/libc/stdio/fclose.c
+++ b/lib/libc/stdio/fclose.c
@@ -48,7 +48,7 @@ fclose(fp)
{
register int r;
- if (fp->_flags == 0) { /* not open! */
+ if (!fp || (fp->_flags == 0)) { /* not open! */
errno = EBADF;
return (EOF);
}
diff --git a/lib/libc/stdio/fgetline.3 b/lib/libc/stdio/fgetline.3
deleted file mode 100644
index 745e745c66f6..000000000000
--- a/lib/libc/stdio/fgetline.3
+++ /dev/null
@@ -1,124 +0,0 @@
-.\" Copyright (c) 1990, 1991 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.
-.\"
-.\" @(#)fgetline.3 5.4 (Berkeley) 4/19/91
-.\"
-.Dd April 19, 1991
-.Dt FGETLINE 3
-.Os
-.Sh NAME
-.Nm fgetline
-.Nd get a line from a stream
-.Sh SYNOPSIS
-.Fd #include <stdio.h>
-.Ft char *
-.Fn fgetline "FILE *stream" "size_t *len"
-.Sh DESCRIPTION
-The
-.Fn fgetline
-function
-returns a pointer to the next line from the stream referenced by
-.Fa stream .
-The newline character at the end of the line is replaced by a
-.Dv NUL .
-.Pp
-If
-.Fa len
-is non-NULL, the length of the line, not counting the terminating
-.Dv NUL ,
-is stored in the memory location it references.
-.Sh RETURN VALUES
-Upon successful completion a pointer is returned;
-this pointer becomes invalid after the next
-.Tn I/O
-operation on
-.Fa stream
-(whether successful or not)
-or as soon as the stream is closed.
-Otherwise,
-.Dv NULL
-is returned.
-The
-.Fn fgetline
-function
-does not distinguish between end-of-file and error; the routines
-.Xr feof 3
-and
-.Xr ferror 3
-must be used
-to determine which occurred.
-If an error occurrs, the global variable
-.Va errno
-is set to indicate the error.
-The end-of-file condition is remembered, even on a terminal, and all
-subsequent attempts to read will return
-.Dv NULL
-until the condition is
-cleared with
-.Xr clearerr 3 .
-.Pp
-The text to which the returned pointer points may be modified,
-provided that no changes are made beyond the terminating
-.Dv NUL .
-These changes are lost as soon as the pointer becomes invalid.
-.Sh ERRORS
-.Bl -tag -width [EBADF]
-.It Bq Er EBADF
-The argument
-.Fa stream
-is not a stream open for reading.
-.El
-.Pp
-The
-.Fn fgetline
-function
-may also fail and set
-.Va errno
-for any of the errors specified for the routines
-.Xr fflush 3 ,
-.Xr malloc 3 ,
-.Xr read 2 ,
-.Xr stat 2 ,
-or
-.Xr realloc 3 .
-.Sh SEE ALSO
-.Xr ferror 3 ,
-.Xr fgets 3 ,
-.Xr fopen 3 ,
-.Xr putc 3
-.Sh HISTORY
-The
-.Fn fgetline
-function is
-.Ud .
-.Sh BUGS
-It is not possible to tell whether the final line of an input file
-was terminated with a newline.
diff --git a/lib/libc/stdio/fgetline.c b/lib/libc/stdio/fgetline.c
index bcd80aca4e86..70fe9d65fe5b 100644
--- a/lib/libc/stdio/fgetline.c
+++ b/lib/libc/stdio/fgetline.c
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)fgetline.c 5.2 (Berkeley) 5/4/91";
* The `new size' does not account for a terminating '\0',
* so we add 1 here.
*/
+static int
__slbexpand(fp, newsize)
FILE *fp;
size_t newsize;
diff --git a/lib/libc/stdio/fgetln.3 b/lib/libc/stdio/fgetln.3
new file mode 100644
index 000000000000..a453cff29c13
--- /dev/null
+++ b/lib/libc/stdio/fgetln.3
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" 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: @(#)fgetline.3 8.1 (Berkeley) 6/9/93
+.\" $Id: fgetln.3,v 1.1 1994/04/17 09:16:36 alm Exp $
+.\"
+.Dd June 9, 1993
+.Dt FGETLN 3
+.Os
+.Sh NAME
+.Nm fgetln
+.Nd get a line from a stream
+.Sh SYNOPSIS
+.Fd #include <stdio.h>
+.Ft char *
+.Fn fgetln "FILE *stream" "size_t *len"
+.Sh DESCRIPTION
+The
+.Fn fgetln
+function
+returns a pointer to the next line from the stream referenced by
+.Fa stream .
+This line is
+.Em not
+a C string as it does not end with a terminating
+.Dv NUL
+character.
+The length of the line, including the final newline,
+is stored in the memory location to which
+.Fa len
+points.
+(Note, however, that if the line is the last
+in a file that does not end in a newline,
+the returned text will not contain a newline.)
+.Sh RETURN VALUES
+Upon successful completion a pointer is returned;
+this pointer becomes invalid after the next
+.Tn I/O
+operation on
+.Fa stream
+(whether successful or not)
+or as soon as the stream is closed.
+Otherwise,
+.Dv NULL
+is returned.
+The
+.Fn fgetln
+function
+does not distinguish between end-of-file and error; the routines
+.Xr feof 3
+and
+.Xr ferror 3
+must be used
+to determine which occurred.
+If an error occurs, the global variable
+.Va errno
+is set to indicate the error.
+The end-of-file condition is remembered, even on a terminal, and all
+subsequent attempts to read will return
+.Dv NULL
+until the condition is
+cleared with
+.Xr clearerr 3 .
+.Pp
+The text to which the returned pointer points may be modified,
+provided that no changes are made beyond the returned size.
+These changes are lost as soon as the pointer becomes invalid.
+.Sh ERRORS
+.Bl -tag -width [EBADF]
+.It Bq Er EBADF
+The argument
+.Fa stream
+is not a stream open for reading.
+.El
+.Pp
+The
+.Fn fgetln
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fflush 3 ,
+.Xr malloc 3 ,
+.Xr read 2 ,
+.Xr stat 2 ,
+or
+.Xr realloc 3 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fgets 3 ,
+.Xr fopen 3 ,
+.Xr putc 3
+.Sh HISTORY
+The
+.Fn fgetln
+function first appeared in 4.4BSD.
diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c
new file mode 100644
index 000000000000..992b4b57e088
--- /dev/null
+++ b/lib/libc/stdio/fgetln.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/* from: static char sccsid[] = "@(#)fgetline.c 8.1 (Berkeley) 6/4/93"; */
+static char *rcsid = "$Id: fgetln.c,v 1.1 1994/04/17 09:16:39 alm Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+/*
+ * Expand the line buffer. Return -1 on error.
+#ifdef notdef
+ * The `new size' does not account for a terminating '\0',
+ * so we add 1 here.
+#endif
+ */
+int
+__slbexpand(fp, newsize)
+ FILE *fp;
+ size_t newsize;
+{
+ void *p;
+
+#ifdef notdef
+ ++newsize;
+#endif
+ if (fp->_lb._size >= newsize)
+ return (0);
+ if ((p = realloc(fp->_lb._base, newsize)) == NULL)
+ return (-1);
+ fp->_lb._base = p;
+ fp->_lb._size = newsize;
+ return (0);
+}
+
+/*
+ * Get an input line. The returned pointer often (but not always)
+ * points into a stdio buffer. Fgetline does not alter the text of
+ * the returned line (which is thus not a C string because it will
+ * not necessarily end with '\0'), but does allow callers to modify
+ * it if they wish. Thus, we set __SMOD in case the caller does.
+ */
+char *
+fgetln(fp, lenp)
+ register FILE *fp;
+ size_t *lenp;
+{
+ register unsigned char *p;
+ register size_t len;
+ size_t off;
+
+ /* make sure there is input */
+ if (fp->_r <= 0 && __srefill(fp)) {
+ *lenp = 0;
+ return (NULL);
+ }
+
+ /* look for a newline in the input */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) {
+ register char *ret;
+
+ /*
+ * Found one. Flag buffer as modified to keep fseek from
+ * `optimising' a backward seek, in case the user stomps on
+ * the text.
+ */
+ p++; /* advance over it */
+ ret = (char *)fp->_p;
+ *lenp = len = p - fp->_p;
+ fp->_flags |= __SMOD;
+ fp->_r -= len;
+ fp->_p = p;
+ return (ret);
+ }
+
+ /*
+ * We have to copy the current buffered data to the line buffer.
+ * As a bonus, though, we can leave off the __SMOD.
+ *
+ * OPTIMISTIC is length that we (optimistically) expect will
+ * accomodate the `rest' of the string, on each trip through the
+ * loop below.
+ */
+#define OPTIMISTIC 80
+
+ for (len = fp->_r, off = 0;; len += fp->_r) {
+ register size_t diff;
+
+ /*
+ * Make sure there is room for more bytes. Copy data from
+ * file buffer to line buffer, refill file and look for
+ * newline. The loop stops only when we find a newline.
+ */
+ if (__slbexpand(fp, len + OPTIMISTIC))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ len - off);
+ off = len;
+ if (__srefill(fp))
+ break; /* EOF or error: return partial line */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL)
+ continue;
+
+ /* got it: finish up the line (like code above) */
+ p++;
+ diff = p - fp->_p;
+ len += diff;
+ if (__slbexpand(fp, len))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ diff);
+ fp->_r -= diff;
+ fp->_p = p;
+ break;
+ }
+ *lenp = len;
+#ifdef notdef
+ fp->_lb._base[len] = 0;
+#endif
+ return ((char *)fp->_lb._base);
+
+error:
+ *lenp = 0; /* ??? */
+ return (NULL); /* ??? */
+}
diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c
index a027109e5659..a8fb89449ed0 100644
--- a/lib/libc/stdio/fseek.c
+++ b/lib/libc/stdio/fseek.c
@@ -197,7 +197,7 @@ fseek(fp, offset, whence)
* If the target offset is within the current buffer,
* simply adjust the pointers, clear EOF, undo ungetc(),
* and return. (If the buffer was modified, we have to
- * skip this; see fgetline.c.)
+ * skip this; see fgetln.c.)
*/
if ((fp->_flags & __SMOD) == 0 &&
target >= curoff && target < curoff + n) {
diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c
index 4f1622369dbc..12fc115bc64f 100644
--- a/lib/libc/stdio/gets.c
+++ b/lib/libc/stdio/gets.c
@@ -35,11 +35,16 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)gets.c 5.3 (Berkeley) 1/20/91";
+static char sccsid[] = "From: @(#)gets.c 5.3 (Berkeley) 1/20/91";
+static char rcsid[] =
+ "$Id: gets.c,v 1.3 1994/04/23 20:35:27 wollman Exp $";
#endif /* LIBC_SCCS and not lint */
#include <unistd.h>
#include <stdio.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses gets(), which is unsafe.\r\n"
char *
gets(buf)
@@ -48,11 +53,11 @@ gets(buf)
register int c;
register char *s;
static int warned;
- static char w[] =
- "warning: this program uses gets(), which is unsafe.\r\n";
if (!warned) {
- (void) write(STDERR_FILENO, w, sizeof(w) - 1);
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
warned = 1;
}
for (s = buf; (c = getchar()) != '\n';)
diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h
index 21966d704dbd..87ed4e60d23e 100644
--- a/lib/libc/stdio/local.h
+++ b/lib/libc/stdio/local.h
@@ -78,7 +78,7 @@ extern int __sdidinit;
}
/*
- * test for an fgetline() buffer.
+ * test for an fgetln() buffer.
*/
#define HASLB(fp) ((fp)->_lb._base != NULL)
#define FREELB(fp) { \
diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3
index 130246ea1b0a..0d7c52873881 100644
--- a/lib/libc/stdio/printf.3
+++ b/lib/libc/stdio/printf.3
@@ -402,7 +402,7 @@ are used for
conversions; the letters
.Cm ABCDEF
are used for
-.m X
+.Cm X
conversions.
The precision, if any, gives the minimum number of digits that must
appear; if the converted value requires fewer digits, it is padded on
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 0bd1a90ab56a..c5736ba7172f 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -4,7 +4,7 @@
.PATH: ${.CURDIR}/${MACHINE}/stdlib ${.CURDIR}/stdlib
SRCS+= abort.c atexit.c atoi.c atol.c bsearch.c calloc.c exit.c \
- getenv.c getopt.c heapsort.c malloc.c multibyte.c \
+ getenv.c getopt.c heapsort.c malloc.c \
putenv.c qsort.c radixsort.c rand.c random.c setenv.c strtod.c \
strtol.c strtoul.c system.c \
_rand48.c drand48.c erand48.c jrand48.c lcong48.c lrand48.c \
diff --git a/lib/libc/stdlib/multibyte.c b/lib/libc/stdlib/multibyte.c
deleted file mode 100644
index 695127969633..000000000000
--- a/lib/libc/stdlib/multibyte.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 1991 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)multibyte.c 5.1 (Berkeley) 2/18/91";
-#endif /* LIBC_SCCS and not lint */
-
-#include <stdlib.h>
-
-/*
- * Stub multibyte character functions.
- * These ignore the current fixed ("C") locale and
- * always indicate that no multibyte characters are supported.
- */
-
-int
-mblen(s, n)
- const char *s;
- size_t n;
-{
- if (s && n && *s)
- return -1;
- return 0;
-}
-
-/*ARGSUSED*/
-int
-mbtowc(pwc, s, n)
- wchar_t *pwc;
- const char *s;
- size_t n;
-{
- if (s && n && *s)
- return -1;
- return 0;
-}
-
-/*ARGSUSED*/
-int
-#ifdef __STDC__
-wctomb(char *s, wchar_t wchar)
-#else
-wctomb(s, wchar)
- char *s;
- wchar_t wchar;
-#endif
-{
- if (s)
- return -1;
- return 0;
-}
-
-/*ARGSUSED*/
-size_t
-mbstowcs(pwcs, s, n)
- wchar_t *pwcs;
- const char *s;
- size_t n;
-{
- if (s && n && *s)
- return -1;
- return 0;
-}
-
-/*ARGSUSED*/
-size_t
-wcstombs(s, pwcs, n)
- char *s;
- const wchar_t *pwcs;
- size_t n;
-{
- if (pwcs && n && *pwcs)
- return -1;
- return 0;
-}
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
index f96af3005605..3879281d2581 100644
--- a/lib/libc/stdlib/rand.c
+++ b/lib/libc/stdlib/rand.c
@@ -43,7 +43,7 @@ static u_long next = 1;
int
rand()
{
- return ((next = next * 1103515245 + 12345) % (RAND_MAX + 1));
+ return ((next = next * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
}
void
diff --git a/lib/libc/string/index.3 b/lib/libc/string/index.3
index 12ca7112a402..f387409fc51f 100644
--- a/lib/libc/string/index.3
+++ b/lib/libc/string/index.3
@@ -54,7 +54,7 @@ locates the first character matching
in the null-terminated string
.Fa s .
.Sh RETURN VALUES
-The character
+The location of the character
.Fa c
is returned if it is found; otherwise
.Dv NULL
diff --git a/lib/libc/string/strftime.c b/lib/libc/string/strftime.c
index 16879d256821..99c68f9b31e2 100644
--- a/lib/libc/string/strftime.c
+++ b/lib/libc/string/strftime.c
@@ -196,6 +196,7 @@ _fmt(format, t)
case 'R':
if (!_fmt("%H:%M", t))
return(0);
+ continue;
case 'r':
if (!_fmt(t_fmt_ampm, t))
return(0);
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 3deb3bbcc702..d0689839bf9d 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -1,4 +1,5 @@
-# @(#)Makefile.inc 5.11 (Berkeley) 6/23/91
+# From: @(#)Makefile.inc 5.11 (Berkeley) 6/23/91
+# $Id: Makefile.inc,v 1.16 1994/03/16 19:01:06 wollman Exp $
# sys sources
.PATH: ${.CURDIR}/${MACHINE}/sys ${.CURDIR}/sys
@@ -19,7 +20,8 @@ ASM= accept.o access.o acct.o adjtime.o async_daemon.o bind.o chdir.o \
getpriority.o getrlimit.o getrusage.o getsockname.o getsockopt.o \
gettimeofday.o getuid.o ioctl.o kill.o ktrace.o link.o listen.o \
lseek.o lstat.o madvise.o mincore.o mkdir.o mkfifo.o mknod.o \
- mmap.o mount.o mprotect.o msgsys.o msync.o munmap.o nfssvc.o open.o \
+ mmap.o mount.o mprotect.o msgsys.o msync.o munmap.o nfssvc.o \
+ ntp_adjtime.o ntp_gettime.o open.o \
profil.o quotactl.o read.o readlink.o readv.o recvfrom.o recvmsg.o \
rename.o revoke.o rmdir.o select.o semsys.o sendmsg.o sendto.o \
setdomainname.o setegid.o seteuid.o setgid.o setgroups.o sethostid.o \
@@ -96,7 +98,7 @@ MAN2+= sys/accept.2 sys/access.2 sys/acct.2 sys/adjtime.2 sys/async_daemon.2 \
sys/msync.2 sys/munmap.2 sys/nfssvc.2 sys/open.2 sys/pipe.2 \
sys/quotactl.2 sys/read.2 sys/readlink.2 sys/reboot.2 sys/recv.2 \
sys/rename.2 sys/rmdir.2 sys/select.2 sys/send.2 sys/setgroups.2 \
- sys/setpgid.2 sys/setregid.2 sys/setreuid.2 sys/setsid.2 \
+ sys/setpgid.2 sys/setregid.2 sys/setreuid.2 sys/setsid.2 sys/setuid.2 \
sys/shutdown.2 sys/sigaction.2 sys/sigprocmask.2 sys/sigreturn.2 \
sys/sigstack.2 sys/sigsuspend.2 sys/socket.2 sys/socketpair.2 \
sys/stat.2 sys/statfs.2 sys/swapon.2 sys/symlink.2 sys/sync.2 \
@@ -127,6 +129,7 @@ MLINKS+=mount.2 unmount.2
MLINKS+=read.2 readv.2
MLINKS+=recv.2 recvfrom.2 recv.2 recvmsg.2
MLINKS+=send.2 sendmsg.2 send.2 sendto.2
+MLINKS+=setuid.2 setegid.2 setuid.2 seteuid.2 setuid.2 setgid.2
MLINKS+=setpgid.2 setpgrp.2
MLINKS+=stat.2 fstat.2 stat.2 lstat.2
MLINKS+=statfs.2 fstatfs.2
diff --git a/lib/libc/sys/execve.2 b/lib/libc/sys/execve.2
index 726de1f88448..48405320181d 100644
--- a/lib/libc/sys/execve.2
+++ b/lib/libc/sys/execve.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)execve.2 6.9 (Berkeley) 3/10/91
-.\" $Id: execve.2,v 1.2.2.1 1994/05/01 16:06:05 jkh Exp $
+.\" $Id: execve.2,v 1.4 1994/03/16 19:10:39 wollman Exp $
.\"
.Dd March 16, 1994
.Dt EXECVE 2
diff --git a/lib/libc/sys/setregid.2 b/lib/libc/sys/setregid.2
index 86b0aa7949be..764f89403e3a 100644
--- a/lib/libc/sys/setregid.2
+++ b/lib/libc/sys/setregid.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)setregid.2 6.4 (Berkeley) 3/10/91
-.\" $Id: setregid.2,v 1.1.1.1.2.1 1994/05/01 16:06:13 jkh Exp $
+.\" $Id: setregid.2,v 1.2 1994/03/16 19:01:08 wollman Exp $
.\"
.Dd March 16, 1994
.Dt SETREGID 2
diff --git a/lib/libc/sys/setreuid.2 b/lib/libc/sys/setreuid.2
index de34b029ab57..62f5dcdae68d 100644
--- a/lib/libc/sys/setreuid.2
+++ b/lib/libc/sys/setreuid.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)setreuid.2 6.4 (Berkeley) 3/10/91
-.\" $Id: setreuid.2,v 1.1.1.1.2.1 1994/05/01 16:06:14 jkh Exp $
+.\" $Id: setreuid.2,v 1.2 1994/03/16 19:01:09 wollman Exp $
.\"
.Dd March 16, 1994
.Dt SETREUID 2
diff --git a/lib/libc/sys/setuid.2 b/lib/libc/sys/setuid.2
new file mode 100644
index 000000000000..eb596cc4918f
--- /dev/null
+++ b/lib/libc/sys/setuid.2
@@ -0,0 +1,121 @@
+.\" Copyright (c) 1983, 1991 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: @(#)setuid.3 6.4 (Berkeley) 4/19/91
+.\" $Id: setuid.2,v 1.2 1994/04/21 21:30:20 wollman Exp $
+.\"
+.Dd March 16, 1994
+.Dt SETUID 2
+.Os
+.Sh NAME
+.Nm setuid ,
+.Nm seteuid ,
+.\" .Nm setruid ,
+.Nm setgid ,
+.Nm setegid ,
+.\" .Nm setrgid
+.Nd set user and group ID
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Ft int
+.Fn setuid "uid_t uid"
+.Ft int
+.Fn seteuid "uid_t euid"
+.\" .Ft int
+.\" .Fn setruid "uid_t ruid"
+.Ft int
+.Fn setgid "gid_t gid"
+.Ft int
+.Fn setegid "gid_t egid"
+.\" .Ft int
+.\" .Fn setrgid "gid_t rgid"
+.Sh DESCRIPTION
+The
+.Fn setuid
+function
+.Pq Fn setgid
+sets the real, effective, and saved
+user IDs (group IDs) of the current process
+as specified.
+.Pp
+The
+.Fn seteuid
+function
+.Pq Fn setegid
+sets the effective user ID (group ID) of the
+current process.
+.\".Pp
+.\" The
+.\" .Fn setruid
+.\" function
+.\" .Pq Fn setrgid
+.\" sets the real user ID (group ID) of the
+.\" current process.
+.Pp
+When any of these calls succeed, the
+.Dv SUGID
+process flag is turned on, and remains on until the process calls
+.Xr execve 2 ;
+this flag can be inspected with
+.Xr ps 1 .
+.Sh RETURN VALUES
+Upon success, these functions return 0;
+otherwise \-1 is returned.
+.Pp
+If the user is not the super user, and the ID specified is not the
+current real ID, the
+.Nm setuid
+and
+.Nm setgid
+functions return \-1.
+.Pp
+If the user is not the super user, and the ID specfied is not the
+current real ID, the
+.\" nor the saved ID, the
+.\" should this really be true that setuid(geteuid()) is not allowed?
+.Nm seteuid
+and
+.Nm setegid
+functions return \-1.
+.Sh SEE ALSO
+.Xr setreuid 2 ,
+.Xr setregid 2 ,
+.Xr getuid 2 ,
+.Xr getgid 2 ,
+.Xr execve 2 ,
+.Xr ps 1
+.Sh HISTORY
+A
+.Fn setuid
+and
+.Fn setgid
+syscall appeared in
+.At v6 .
diff --git a/lib/libc/sys/sigsuspend.2 b/lib/libc/sys/sigsuspend.2
index 8e0c73001c10..2b09e707f5e5 100644
--- a/lib/libc/sys/sigsuspend.2
+++ b/lib/libc/sys/sigsuspend.2
@@ -36,7 +36,7 @@
.Os
.Sh NAME
.Nm sigsuspend
-.Nd automatically release blocked signals and wait for interrupt
+.Nd atomically release blocked signals and wait for interrupt
.Sh SYNOPSIS
.Fd #include <sys/signal.h>
.Ft int
@@ -74,7 +74,7 @@ set to
.Xr sigsetops 3
.Sh STANDARDS
The
-.Nm sigsupend
+.Nm sigsuspend
function call
conforms to
.St -p1003.1-88 .
diff --git a/lib/libcompat/Makefile b/lib/libcompat/Makefile
new file mode 100644
index 000000000000..b4209eef15b8
--- /dev/null
+++ b/lib/libcompat/Makefile
@@ -0,0 +1,18 @@
+LIB= compat
+NOPIC= we dont need PIC for these puppies
+
+SRCS= sgtty.c ftime.c cftime.c regex.c setrgid.c setruid.c
+
+MAN3= libcompat.3
+
+MLINKS= libcompat.3 stty.3 libcompat.3 gtty.3 \
+ libcompat.3 ftime.3 \
+ libcompat.3 cftime.3 libcompat.3 ascftime.3 \
+ libcompat.3 re_exec.3 libcompat.3 re_comp.3 \
+ libcompat.3 setrgid.3 libcompat.3 setruid.3
+
+# Henry Spencer's regexp library from the UoT is
+# kept in a separate subdirectory
+.include "${.CURDIR}/regexp/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libcompat/cftime.c b/lib/libcompat/cftime.c
new file mode 100644
index 000000000000..8edb078b64ea
--- /dev/null
+++ b/lib/libcompat/cftime.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+#include <time.h>
+
+#define MAXLEN 1000 /* just a guess, only the user knows... */
+
+int
+#if __STDC__
+cftime(char *s, char *format, const time_t *clock)
+#else
+cftime(s, format, clock)
+ char *s;
+ char *format;
+ time_t *clock;
+#endif
+{
+ return strftime(s, MAXLEN, format? format: "%C", localtime(clock));
+}
+
+int
+#if __STDC__
+ascftime(char *s, const char *format, const struct tm *tmptr)
+#else
+ascftime(s, format, tmptr)
+ char *s;
+ char *format;
+ struct tm *tmptr;
+#endif
+{
+ return strftime(s, MAXLEN, format? format: "%C", tmptr);
+}
diff --git a/lib/libcompat/ftime.c b/lib/libcompat/ftime.c
new file mode 100644
index 000000000000..74c1c21f9992
--- /dev/null
+++ b/lib/libcompat/ftime.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/*
+ * ftime.c
+ * get time, OBSOLETED BY gettimeofday(2)
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+int
+#if __STDC__
+ftime(struct timeb *tp)
+#else
+ftime(tp)
+ struct timeb *tp;
+#endif
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ if(gettimeofday(&tv, &tz) < 0)
+ return -1; /* any error */
+
+ tp->time = tv.tv_sec;
+ tp->millitm = tv.tv_usec / 1000;
+ /*
+ * timezone and dstflag below are bogus
+ * the timezone is no longer part of the kernel, thus the information
+ * obtained by gettimeofday() wrt. the timezone is useless
+ */
+ tp->timezone = tz.tz_minuteswest;
+ tp->dstflag = tz.tz_dsttime != DST_NONE;
+ return 0;
+}
diff --git a/lib/libcompat/libcompat.3 b/lib/libcompat/libcompat.3
new file mode 100644
index 000000000000..b18d0b79f3ba
--- /dev/null
+++ b/lib/libcompat/libcompat.3
@@ -0,0 +1,205 @@
+.\"
+.\" Copyright (c) 1994 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" 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 Joerg Wunsch
+.\" 4. The name of the developer may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\"
+.\" libcompat man page,
+.\" written June 15, 1993 by Joerg Wunsch
+.\"
+.Dd June 15, 1993
+.Os
+.Dt LIBCOMPAT 3
+.Sh NAME
+.Nm libcompat
+.Nd compatibility library for older programs
+.Sh SYNOPSIS
+.Fd #include <sgtty.h>
+.Fn "int stty" "int fd" "struct sgttyb *s" ;
+.Fn "int gtty" "int fd" "struct sgttyb *s" ;
+.Fd #include <sys/timeb.h>
+.Fn "int ftime" "struct timeb *tp" ;
+.Fd #include <time.h>
+.Fn "int cftime" "char *s" "char *format" "const time_t *clock" ;
+.Fn "int ascftime" "char *s" "const char *format" "const struct tm *tmptr" ;
+
+.Fn "char *re_comp" "char *s" ;
+.Fn "int re_exec" "char *s" ;
+.Fd #include <sys/types.h>
+.Fn "int setruid" "uid_t uid" ;
+.Fn "int setrgid" "gid_t gid" ;
+.Sh DESCRIPTION
+.Em The functions described here are obsoleted .
+.Em The sole purpose \&of this library \&is providing
+.Em a compatibility module for older programs .
+To use the library, an option of
+.Fl lcompat
+has to be specified when linking those programs.
+
+The functions
+.Nm stty
+and
+.Nm gtty
+set or get, respectively, the terminal control flags from/into a
+variable of type
+.Em struct sgttyb .
+They are obsoleted by the new terminal controlling interface, see
+.Xr termios 3 .
+There used to be macros instead of functions, too.
+
+The function
+.Nm ftime
+returns information on the current time as well as the timezone.
+It is obsoleted by
+.Xr gettimeofday 3 .
+Note further that the timezone information is no longer kept inside
+the kernel, hence neither
+.Xr gettimeofday 3 ,
+nor
+.Nm ftime
+will return useful values for their timezone-related arguments. See
+.Xr tzset 3
+and
+.Xr ctime 3
+for an up-to-date timezone handling.
+
+Use of the functions
+.Nm cftime
+and
+.Nm ascftime
+is strongly deprecated, since there is no way to check for a buffer
+overflow condition. Use
+.Xr strftime 3
+instead.
+
+.Nm Ascftime
+is almost identical with
+.Xr strftime 3 ,
+with the only exception there's no parameter to tell about the
+maximal buffer length, and the
+.Ar format
+parameter defaults to
+.Dq %C
+if a
+.Em NULL
+pointer is given.
+
+.Nm Cftime
+does the same job, but it first invokes
+.Xr localtime 3
+in order to convert the given
+.Ar clock ,
+then also performs the conversions as requested by the
+.Ar format
+argument.
+
+.Nm Setruid
+and
+.Nm setrgid
+have been used previously to set the real user-ID or real group-ID,
+respectively. They are no longer available, because they are
+incompatible with the POSIX security model. If a process wants to set
+its real user-ID, then it must also simultaneously set its effective and
+saved IDs, which is what
+.Nm setuid
+does. Similiar considerations apply to
+.Nm setrgid .
+
+The functions
+.Nm re_comp
+and
+.Nm re_exec
+provide a traditional interface to the regular expression matching
+routines
+.Xr regcomp 3
+and
+.Xr regexec 3 .
+
+.Nm Re_comp
+compiles a string into an internal form suitable for pattern
+matching.
+.Nm Re_exec
+checks the argument string against the last string
+passed to
+.Nm re_comp .
+
+.Nm Re_comp
+returns 0 if the string s was compiled successfully;
+otherwise a string containing an error message is returned. If
+.Nm re_comp
+is passed 0 or a null string, it returns without changing the
+currently compiled regular expression.
+
+.Nm Re_exec
+returns 1 if the string s matches the last compiled regular
+expression, 0 if the string s failed to match the last compiled
+regular expression, and -1 if the compiled regular expression was
+invalid
+.Pq indicating an internal error .
+
+Note that
+.Nm re_comp
+and
+.Nm re_exec
+need the
+.Xr regexp 3
+library with the traditional
+.Pq V8
+function call interface rather than the new library as
+contained in the standard C library. The
+.Xr regexp 3
+library is also part of libcompat.a.
+
+.Sh RETURN VALUES
+The functions usually return with a negative value on error.
+
+The
+.Nm cftime
+and
+.Nm ascftime
+function return the number of characters written to the output
+buffer
+.Ar s ,
+not counting the trailing null character.
+
+.Sh SEE ALSO
+.Xr termios 3 ;
+.Xr gettimeofday 3 ;
+.Xr strftime 3 ,
+.Xr tzset 3 ,
+.Xr ctime 3 ,
+.Xr localtime 3 ;
+.Xr setreuid 2 ,
+.Xr setuid 3 ,
+.Xr setregid 2 ,
+.Xr setgid 3 ;
+.Xr regcomp 3 ,
+.Xr regexec 3 .
diff --git a/lib/libcompat/regex.c b/lib/libcompat/regex.c
new file mode 100644
index 000000000000..7760f9f87a4f
--- /dev/null
+++ b/lib/libcompat/regex.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James da Silva at the University of Maryland at College Park.
+ *
+ * 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.
+ */
+
+/*
+ * Compatibility routines that implement the old re_comp/re_exec interface in
+ * terms of the regcomp/regexec interface. It's possible that some programs
+ * rely on dark corners of re_comp/re_exec and won't work with this version,
+ * but most programs should be fine.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regex.c 5.1 (Berkeley) 3/29/92";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <regexp.h>
+#include <string.h>
+#include <stdlib.h>
+
+static regexp *re_regexp;
+static int re_goterr;
+static char *re_errstr;
+
+char *
+re_comp(s)
+ char *s;
+{
+ if (s == NULL)
+ return (NULL);
+ if (re_regexp)
+ free(re_regexp);
+ if (re_errstr)
+ free(re_errstr);
+ re_goterr = 0;
+ re_regexp = regcomp(s);
+ return (re_goterr ? re_errstr : NULL);
+}
+
+int
+re_exec(s)
+ char *s;
+{
+ int rc;
+
+ re_goterr = 0;
+ rc = regexec(re_regexp, s);
+ return (re_goterr ? -1 : rc);
+}
+
+void
+regerror(s)
+ const char *s;
+{
+ re_goterr = 1;
+ if (re_errstr)
+ free(re_errstr);
+ re_errstr = strdup(s);
+}
+
diff --git a/lib/libcompat/regexp/COPYRIGHT b/lib/libcompat/regexp/COPYRIGHT
new file mode 100644
index 000000000000..48b3f4339171
--- /dev/null
+++ b/lib/libcompat/regexp/COPYRIGHT
@@ -0,0 +1,22 @@
+This entire subtree is copyright the University of Toronto.
+The following copyright notice applies to all files found here. None of
+these files contain AT&T proprietary source code.
+_____________________________________________________________________________
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The author is not responsible for the consequences of use of
+ this software, no matter how awful, even if they arise
+ from defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
diff --git a/lib/libcompat/regexp/Makefile.inc b/lib/libcompat/regexp/Makefile.inc
new file mode 100644
index 000000000000..ba2d95367129
--- /dev/null
+++ b/lib/libcompat/regexp/Makefile.inc
@@ -0,0 +1,20 @@
+.PATH: ${.CURDIR}/regexp
+
+SRCS += regexp.c regsub.c regerror.c
+CFLAGS += -I ${.CURDIR}/regexp
+
+MAN3 += regexp/regexp.3
+
+# We need a different suffix for the man page links, so
+# we could have `man 3 regcomp' telling about both
+# libraries.
+# <bsd.man.mk> is not clever enough to handle this...
+
+M3COMPATLINKS = regcomp.3c regexec.3c regsub.3c regerror.3c
+
+afterinstall:
+ for link in ${M3COMPATLINKS} ; do \
+ rm -f ${DESTDIR}${MANDIR}3${MANSUBDIR}/$$link; \
+ ln ${DESTDIR}${MANDIR}3${MANSUBDIR}/regexp.3 \
+ ${DESTDIR}${MANDIR}3${MANSUBDIR}/$$link; \
+ done
diff --git a/lib/libcompat/regexp/README b/lib/libcompat/regexp/README
new file mode 100644
index 000000000000..37d6f51c7119
--- /dev/null
+++ b/lib/libcompat/regexp/README
@@ -0,0 +1,84 @@
+This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
+It gives C programs the ability to use egrep-style regular expressions, and
+does it in a much cleaner fashion than the analogous routines in SysV.
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The author is not responsible for the consequences of use of
+ this software, no matter how awful, even if they arise
+ from defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+Barring a couple of small items in the BUGS list, this implementation is
+believed 100% compatible with V8. It should even be binary-compatible,
+sort of, since the only fields in a "struct regexp" that other people have
+any business touching are declared in exactly the same way at the same
+location in the struct (the beginning).
+
+This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
+software. Even though U of T is a V8 licensee. This software is based on
+a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
+here is a complete rewrite and hence is not covered by AT&T copyright).
+The software was nearly complete at the time of arrival of our V8 tape.
+I haven't even looked at V8 yet, although a friend elsewhere at U of T has
+been kind enough to run a few test programs using the V8 regexp(3) to resolve
+a few fine points. I admit to some familiarity with regular-expression
+implementations of the past, but the only one that this code traces any
+ancestry to is the one published in Kernighan & Plauger (from which this
+one draws ideas but not code).
+
+Simplistically: put this stuff into a source directory, copy regexp.h into
+/usr/include, inspect Makefile for compilation options that need changing
+to suit your local environment, and then do "make r". This compiles the
+regexp(3) functions, compiles a test program, and runs a large set of
+regression tests. If there are no complaints, then put regexp.o, regsub.o,
+and regerror.o into your C library, and regexp.3 into your manual-pages
+directory.
+
+Note that if you don't put regexp.h into /usr/include *before* compiling,
+you'll have to add "-I." to CFLAGS before compiling.
+
+The files are:
+
+Makefile instructions to make everything
+regexp.3 manual page
+regexp.h header file, for /usr/include
+regexp.c source for regcomp() and regexec()
+regsub.c source for regsub()
+regerror.c source for default regerror()
+regmagic.h internal header file
+try.c source for test program
+timer.c source for timing program
+tests test list for try and timer
+
+This implementation uses nondeterministic automata rather than the
+deterministic ones found in some other implementations, which makes it
+simpler, smaller, and faster at compiling regular expressions, but slower
+at executing them. In theory, anyway. This implementation does employ
+some special-case optimizations to make the simpler cases (which do make
+up the bulk of regular expressions actually used) run quickly. In general,
+if you want blazing speed you're in the wrong place. Replacing the insides
+of egrep with this stuff is probably a mistake; if you want your own egrep
+you're going to have to do a lot more work. But if you want to use regular
+expressions a little bit in something else, you're in luck. Note that many
+existing text editors use nondeterministic regular-expression implementations,
+so you're in good company.
+
+This stuff should be pretty portable, given appropriate option settings.
+If your chars have less than 8 bits, you're going to have to change the
+internal representation of the automaton, although knowledge of the details
+of this is fairly localized. There are no "reserved" char values except for
+NUL, and no special significance is attached to the top bit of chars.
+The string(3) functions are used a fair bit, on the grounds that they are
+probably faster than coding the operations in line. Some attempts at code
+tuning have been made, but this is invariably a bit machine-specific.
diff --git a/lib/libcompat/regexp/regerror.c b/lib/libcompat/regexp/regerror.c
new file mode 100644
index 000000000000..6d0077d63429
--- /dev/null
+++ b/lib/libcompat/regexp/regerror.c
@@ -0,0 +1,18 @@
+#include <regexp.h>
+#include <stdio.h>
+
+void
+regerror(s)
+const char *s;
+{
+#ifdef ERRAVAIL
+ error("regexp: %s", s);
+#else
+/*
+ fprintf(stderr, "regexp(3): %s\n", s);
+ exit(1);
+*/
+ return; /* let std. egrep handle errors */
+#endif
+ /* NOTREACHED */
+}
diff --git a/lib/libcompat/regexp/regexp.3 b/lib/libcompat/regexp/regexp.3
new file mode 100644
index 000000000000..b8ca3047cd91
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.3
@@ -0,0 +1,321 @@
+.\" Copyright 1991 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.
+.\"
+.\" @(#)regexp.3 5.2 (Berkeley) 4/20/91
+.\"
+.Dd April 20, 1991
+.Dt REGEXP 3
+.Os
+.Sh NAME
+.Nm regcomp ,
+.Nm regexec ,
+.Nm regsub ,
+.Nm regerror
+.Nd regular expression handlers
+.Sh SYNOPSIS
+.Fd #include <regexp.h>
+.Ft regexp *
+.Fn regcomp "const char *exp"
+.Ft int
+.Fn regexec "const regexp *prog" "const char *string"
+.Ft void
+.Fn regsub "const regexp *prog" "const char *source" "char *dest"
+.Sh DESCRIPTION
+.Em The functions described here are obsoleted, see
+.Xr regex 3
+.Em for the new interface .
+.Em To use these functions, the program must be linked
+.Em against -lcompat .
+
+The
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+functions
+implement
+.Xr egrep 1 Ns -style
+regular expressions and supporting facilities.
+.Pp
+The
+.Fn regcomp
+function
+compiles a regular expression into a structure of type
+.Xr regexp ,
+and returns a pointer to it.
+The space has been allocated using
+.Xr malloc 3
+and may be released by
+.Xr free .
+.Pp
+The
+.Fn regexec
+function
+matches a
+.Dv NUL Ns -terminated
+.Fa string
+against the compiled regular expression
+in
+.Fa prog .
+It returns 1 for success and 0 for failure, and adjusts the contents of
+.Fa prog Ns 's
+.Em startp
+and
+.Em endp
+(see below) accordingly.
+.Pp
+The members of a
+.Xr regexp
+structure include at least the following (not necessarily in order):
+.Bd -literal -offset indent
+char *startp[NSUBEXP];
+char *endp[NSUBEXP];
+.Ed
+.Pp
+where
+.Dv NSUBEXP
+is defined (as 10) in the header file.
+Once a successful
+.Fn regexec
+has been done using the
+.Fn regexp ,
+each
+.Em startp Ns - Em endp
+pair describes one substring
+within the
+.Fa string ,
+with the
+.Em startp
+pointing to the first character of the substring and
+the
+.Em endp
+pointing to the first character following the substring.
+The 0th substring is the substring of
+.Fa string
+that matched the whole
+regular expression.
+The others are those substrings that matched parenthesized expressions
+within the regular expression, with parenthesized expressions numbered
+in left-to-right order of their opening parentheses.
+.Pp
+The
+.Fn regsub
+function
+copies
+.Fa source
+to
+.Fa dest ,
+making substitutions according to the
+most recent
+.Fn regexec
+performed using
+.Fa prog .
+Each instance of `&' in
+.Fa source
+is replaced by the substring
+indicated by
+.Em startp Ns Bq
+and
+.Em endp Ns Bq .
+Each instance of
+.Sq \e Ns Em n ,
+where
+.Em n
+is a digit, is replaced by
+the substring indicated by
+.Em startp Ns Bq Em n
+and
+.Em endp Ns Bq Em n .
+To get a literal `&' or
+.Sq \e Ns Em n
+into
+.Fa dest ,
+prefix it with `\e';
+to get a literal `\e' preceding `&' or
+.Sq \e Ns Em n ,
+prefix it with
+another `\e'.
+.Pp
+The
+.Fn regerror
+function
+is called whenever an error is detected in
+.Fn regcomp ,
+.Fn regexec ,
+or
+.Fn regsub .
+The default
+.Fn regerror
+writes the string
+.Fa msg ,
+with a suitable indicator of origin,
+on the standard
+error output
+and invokes
+.Xr exit 2 .
+The
+.Fn regerror
+function
+can be replaced by the user if other actions are desirable.
+.Sh REGULAR EXPRESSION SYNTAX
+A regular expression is zero or more
+.Em branches ,
+separated by `|'.
+It matches anything that matches one of the branches.
+.Pp
+A branch is zero or more
+.Em pieces ,
+concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.Pp
+A piece is an
+.Em atom
+possibly followed by `*', `+', or `?'.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a match of the atom, or the null string.
+.Pp
+An atom is a regular expression in parentheses (matching a match for the
+regular expression), a
+.Em range
+(see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of the input string), `$' (matching the null string at the
+end of the input string), a `\e' followed by a single character (matching
+that character), or a single character with no other significance
+(matching that character).
+.Pp
+A
+.Em range
+is a sequence of characters enclosed in `[]'.
+It normally matches any single character from the sequence.
+If the sequence begins with `^',
+it matches any single character
+.Em not
+from the rest of the sequence.
+If two characters in the sequence are separated by `\-', this is shorthand
+for the full list of
+.Tn ASCII
+characters between them
+(e.g. `[0-9]' matches any decimal digit).
+To include a literal `]' in the sequence, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character.
+.Sh AMBIGUITY
+If a regular expression could match two different parts of the input string,
+it will match the one which begins earliest.
+If both begin in the same place but match different lengths, or match
+the same length in different ways, life gets messier, as follows.
+.Pp
+In general, the possibilities in a list of branches are considered in
+left-to-right order, the possibilities for `*', `+', and `?' are
+considered longest-first, nested constructs are considered from the
+outermost in, and concatenated constructs are considered leftmost-first.
+The match that will be chosen is the one that uses the earliest
+possibility in the first choice that has to be made.
+If there is more than one choice, the next will be made in the same manner
+(earliest possibility) subject to the decision on the first choice.
+And so forth.
+.Pp
+For example,
+.Sq Li (ab|a)b*c
+could match
+`abc' in one of two ways.
+The first choice is between `ab' and `a'; since `ab' is earlier, and does
+lead to a successful overall match, it is chosen.
+Since the `b' is already spoken for,
+the `b*' must match its last possibility\(emthe empty string\(emsince
+it must respect the earlier choice.
+.Pp
+In the particular case where no `|'s are present and there is only one
+`*', `+', or `?', the net effect is that the longest possible
+match will be chosen.
+So
+.Sq Li ab* ,
+presented with `xabbbby', will match `abbbb'.
+Note that if
+.Sq Li ab* ,
+is tried against `xabyabbbz', it
+will match `ab' just after `x', due to the begins-earliest rule.
+(In effect, the decision on where to start the match is the first choice
+to be made, hence subsequent choices must respect it even if this leads them
+to less-preferred alternatives.)
+.Sh RETURN VALUES
+The
+.Fn regcomp
+function
+returns
+.Dv NULL
+for a failure
+.Pf ( Fn regerror
+permitting),
+where failures are syntax errors, exceeding implementation limits,
+or applying `+' or `*' to a possibly-null operand.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr ex 1 ,
+.Xr expr 1 ,
+.Xr egrep 1 ,
+.Xr fgrep 1 ,
+.Xr grep 1 ,
+.Xr regex 3
+.Sh HISTORY
+Both code and manual page for
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+were written at the University of Toronto
+and appeared in
+.Bx 4.3 tahoe .
+They are intended to be compatible with the Bell V8
+.Xr regexp 3 ,
+but are not derived from Bell code.
+.Sh BUGS
+Empty branches and empty regular expressions are not portable to V8.
+.Pp
+The restriction against
+applying `*' or `+' to a possibly-null operand is an artifact of the
+simplistic implementation.
+.Pp
+Does not support
+.Xr egrep Ns 's
+newline-separated branches;
+neither does the V8
+.Xr regexp 3 ,
+though.
+.Pp
+Due to emphasis on
+compactness and simplicity,
+it's not strikingly fast.
+It does give special attention to handling simple cases quickly.
diff --git a/lib/libcompat/regexp/regexp.c b/lib/libcompat/regexp/regexp.c
new file mode 100644
index 000000000000..0084295bfb37
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.c
@@ -0,0 +1,1320 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include <regexp.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "regmagic.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this string. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
+#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
+#define OPEN 20 /* no Mark this point in input as start of #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define FAIL(m) { regerror(m); return(NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regnode();
+STATIC char *regnext();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+#ifdef STRCSPN
+STATIC int strcspn();
+#endif
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp(exp)
+const char *exp;
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register int len;
+ int flags;
+
+ if (exp == NULL)
+ FAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+#ifdef notdef
+ if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
+#endif
+ regparse = (char *)exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+ if (r == NULL)
+ FAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = (char *)exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ */
+ if (flags&SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN+parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|' || *regparse == '\n') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE+parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (*regparse != '\0' && *regparse != ')' &&
+ *regparse != '\n' && *regparse != '|') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ /* FIXME: these chars only have meaning at beg/end of pat? */
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ register int class;
+ register int classend;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ class = UCHARAT(regparse-2)+1;
+ classend = UCHARAT(regparse);
+ if (class > classend+1)
+ FAIL("invalid [] range");
+ for (; class <= classend; class++)
+ regc(class);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']')
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case '\n':
+ case ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ break;
+ case '\\':
+ switch (*regparse++) {
+ case '\0':
+ FAIL("trailing \\");
+ break;
+ case '<':
+ ret = regnode(WORDA);
+ break;
+ case '>':
+ ret = regnode(WORDZ);
+ break;
+ /* FIXME: Someday handle \1, \2, ... */
+ default:
+ /* Handle general quoted chars in exact-match routine */
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default:
+ /*
+ * Encode a string of characters to be matched exactly.
+ *
+ * This is a bit tricky due to quoted chars and due to
+ * '*', '+', and '?' taking the SINGLE char previous
+ * as their operand.
+ *
+ * On entry, the char at regparse[-1] is going to go
+ * into the string, no matter what it is. (It could be
+ * following a \ if we are entered from the '\' case.)
+ *
+ * Basic idea is to pick up a good char in ch and
+ * examine the next char. If it's *+? then we twiddle.
+ * If it's \ then we frozzle. If it's other magic char
+ * we push ch and terminate the string. If none of the
+ * above, we push ch on the string and go around again.
+ *
+ * regprev is used to remember where "the current char"
+ * starts in the string, if due to a *+? we need to back
+ * up and put the current char in a separate, 1-char, string.
+ * When regprev is NULL, ch is the only char in the
+ * string; this is used in *+? handling, and in setting
+ * flags |= SIMPLE at the end.
+ */
+ {
+ char *regprev;
+ register char ch;
+
+ regparse--; /* Look at cur char */
+ ret = regnode(EXACTLY);
+ for ( regprev = 0 ; ; ) {
+ ch = *regparse++; /* Get current char */
+ switch (*regparse) { /* look at next one */
+
+ default:
+ regc(ch); /* Add cur to string */
+ break;
+
+ case '.': case '[': case '(':
+ case ')': case '|': case '\n':
+ case '$': case '^':
+ case '\0':
+ /* FIXME, $ and ^ should not always be magic */
+ magic:
+ regc(ch); /* dump cur char */
+ goto done; /* and we are done */
+
+ case '?': case '+': case '*':
+ if (!regprev) /* If just ch in str, */
+ goto magic; /* use it */
+ /* End mult-char string one early */
+ regparse = regprev; /* Back up parse */
+ goto done;
+
+ case '\\':
+ regc(ch); /* Cur char OK */
+ switch (regparse[1]){ /* Look after \ */
+ case '\0':
+ case '<':
+ case '>':
+ /* FIXME: Someday handle \1, \2, ... */
+ goto done; /* Not quoted */
+ default:
+ /* Backup point is \, scan * point is after it. */
+ regprev = regparse;
+ regparse++;
+ continue; /* NOT break; */
+ }
+ }
+ regprev = regparse; /* Set backup point */
+ }
+ done:
+ regc('\0');
+ *flagp |= HASWIDTH;
+ if (!regprev) /* One char? */
+ *flagp |= SIMPLE;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return(ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(prog, string)
+register const regexp *prog;
+register const char *string;
+{
+ register char *s;
+ extern char *strchr();
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ regerror("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL) {
+ s = (char *)string;
+ while ((s = strchr(s, prog->regmust[0])) != NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = (char *)string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = (char *)string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != NULL) {
+ if (regtry(prog, s))
+ return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(prog, string)
+regexp *prog;
+char *string;
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+ extern char *strchr();
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return(0);
+ break;
+ case WORDA:
+ /* Must be looking at a letter, digit, or _ */
+ if ((!isalnum(*reginput)) && *reginput != '_')
+ return(0);
+ /* Prev must be BOL or nonword */
+ if (reginput > regbol &&
+ (isalnum(reginput[-1]) || reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+ /* Must be looking at non letter, digit, or _ */
+ if (isalnum(*reginput) || *reginput == '_')
+ return(0);
+ /* We don't care what the previous char was */
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return(0);
+ reginput++;
+ break;
+ case EXACTLY: {
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[no] == NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[no] == NULL)
+ regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case BRANCH: {
+ register char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:
+ case PLUS: {
+ register char nextch;
+ register int no;
+ register char *save;
+ register int min;
+
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ break;
+ case END:
+ return(1); /* Success! */
+ break;
+ default:
+ regerror("memory corruption");
+ return(0);
+ break;
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ regerror("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(p)
+char *p;
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext(p)
+register char *p;
+{
+ register int offset;
+
+ if (p == &regdummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+ extern char *strchr();
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(op)
+char *op;
+{
+ register char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9:
+ sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+ p = NULL;
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9:
+ sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ case WORDA:
+ p = "WORDA";
+ break;
+ case WORDZ:
+ p = "WORDZ";
+ break;
+ default:
+ regerror("corrupted opcode");
+ break;
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries. They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(s1, s2)
+char *s1;
+char *s2;
+{
+ register char *scan1;
+ register char *scan2;
+ register int count;
+
+ count = 0;
+ for (scan1 = s1; *scan1 != '\0'; scan1++) {
+ for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
+ if (*scan1 == *scan2++)
+ return(count);
+ count++;
+ }
+ return(count);
+}
+#endif
diff --git a/lib/libcompat/regexp/regexp.h b/lib/libcompat/regexp/regexp.h
new file mode 100644
index 000000000000..73d6bf412424
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.h
@@ -0,0 +1,21 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#define NSUBEXP 10
+typedef struct regexp {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+extern regexp *regcomp();
+extern int regexec();
+extern void regsub();
+extern void regerror();
diff --git a/lib/libcompat/regexp/regmagic.h b/lib/libcompat/regexp/regmagic.h
new file mode 100644
index 000000000000..5acf4478ff71
--- /dev/null
+++ b/lib/libcompat/regexp/regmagic.h
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
diff --git a/lib/libcompat/regexp/regsub.c b/lib/libcompat/regexp/regsub.c
new file mode 100644
index 000000000000..e55b9b624d1d
--- /dev/null
+++ b/lib/libcompat/regexp/regsub.c
@@ -0,0 +1,81 @@
+/*
+ * regsub
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ */
+#include <regexp.h>
+#include <stdio.h>
+#include <string.h>
+#include "regmagic.h"
+
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void
+regsub(prog, source, dest)
+const regexp *prog;
+const char *source;
+char *dest;
+{
+ register char *src;
+ register char *dst;
+ register char c;
+ register int no;
+ register int len;
+ extern char *strncpy();
+
+ if (prog == NULL || source == NULL || dest == NULL) {
+ regerror("NULL parm to regsub");
+ return;
+ }
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("damaged regexp fed to regsub");
+ return;
+ }
+
+ src = (char *)source;
+ dst = dest;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && '0' <= *src && *src <= '9')
+ no = *src++ - '0';
+ else
+ no = -1;
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ *dst++ = c;
+ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+ len = prog->endp[no] - prog->startp[no];
+ (void) strncpy(dst, prog->startp[no], len);
+ dst += len;
+ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
+ regerror("damaged match string");
+ return;
+ }
+ }
+ }
+ *dst++ = '\0';
+}
diff --git a/lib/libcompat/setrgid.c b/lib/libcompat/setrgid.c
new file mode 100644
index 000000000000..c0766d71fbf7
--- /dev/null
+++ b/lib/libcompat/setrgid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int
+#if __STDC__
+setrgid(gid_t gid)
+#else
+setrgid(gid)
+ gid_t gid;
+#endif
+{
+ return setgid(gid);
+}
+
diff --git a/lib/libcompat/setruid.c b/lib/libcompat/setruid.c
new file mode 100644
index 000000000000..9fd649e810a0
--- /dev/null
+++ b/lib/libcompat/setruid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int
+#if __STDC__
+setruid(uid_t uid)
+#else
+setruid(uid)
+ uid_t uid;
+#endif
+{
+ return setuid(uid);
+}
+
diff --git a/lib/libcompat/sgtty.c b/lib/libcompat/sgtty.c
new file mode 100644
index 000000000000..3c3730d30a8d
--- /dev/null
+++ b/lib/libcompat/sgtty.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/* the V7-style interface to modify the terminals characteristics */
+
+#include <sgtty.h>
+
+/* these functions are just in case someone even did not get the macros... */
+#undef stty
+#undef gtty
+
+int
+#if __STDC__
+stty(int fd, struct sgttyb *s)
+#else
+stty(fd, s)
+ int fd;
+ struct sgttyb *s;
+#endif
+{
+ return ioctl(fd, TIOCSETP, s);
+}
+
+int
+#if __STDC__
+gtty(int fd, struct sgttyb *s)
+#else
+gtty(fd, s)
+ int fd;
+ struct sgttyb *s;
+#endif
+{
+ return ioctl(fd, TIOCGETP, s);
+}
+
+
diff --git a/lib/libcurses/Makefile b/lib/libcurses/Makefile
index 74baf7974571..b089a988b78a 100644
--- a/lib/libcurses/Makefile
+++ b/lib/libcurses/Makefile
@@ -9,7 +9,8 @@ SRCS= addbytes.c addch.c addnstr.c box.c clear.c clrtobot.c clrtoeol.c \
standout.c toucholap.c touchwin.c tscroll.c tstp.c tty.c unctrl.c
MAN3= curses.3
-CFLAGS+=-D_CURSES_PRIVATE -I${.CURDIR}
+CFLAGS+=-D_CURSES_PRIVATE
+SHARED_LDADD+= -ltermcap
beforeinstall:
-cd ${.CURDIR}; cmp -s curses.h ${DESTDIR}/usr/include/curses.h > \
diff --git a/lib/libcurses/cr_put.c b/lib/libcurses/cr_put.c
index b50875c91211..0afaf3a344d7 100644
--- a/lib/libcurses/cr_put.c
+++ b/lib/libcurses/cr_put.c
@@ -101,11 +101,11 @@ fgoto(in_refresh)
while (l > 0) {
if (__pfast)
if (CR)
- tputs(CR, 0, __cputchar);
+ tputs(CR, 1, __cputchar);
else
putchar('\r');
if (NL)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
l--;
@@ -146,7 +146,7 @@ fgoto(in_refresh)
* Eggert's Superbee description which wins better.
*/
if (NL /* && !XB */ && __pfast)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
l--;
@@ -166,7 +166,7 @@ fgoto(in_refresh)
if (outcol != COLS - 1 && plod(strlen(cgp), in_refresh) > 0)
plod(0, in_refresh);
else
- tputs(cgp, 0, __cputchar);
+ tputs(cgp, 1, __cputchar);
} else
plod(0, in_refresh);
outline = destline;
@@ -243,7 +243,7 @@ plod(cnt, in_refresh)
* Cheaper to home. Do it now and pretend it's a
* regular local motion.
*/
- tputs(HO, 0, plodput);
+ tputs(HO, 1, plodput);
outcol = outline = 0;
} else if (LL) {
/*
@@ -252,7 +252,7 @@ plod(cnt, in_refresh)
*/
k = (LINES - 1) - destline;
if (i + k + 2 < j && (k <= 0 || UP)) {
- tputs(LL, 0, plodput);
+ tputs(LL, 1, plodput);
outcol = 0;
outline = LINES - 1;
}
@@ -302,12 +302,12 @@ plod(cnt, in_refresh)
* into account.
*/
if (CR)
- tputs(CR, 0, plodput);
+ tputs(CR, 1, plodput);
else
plodput('\r');
if (NC) {
if (NL)
- tputs(NL, 0, plodput);
+ tputs(NL, 1, plodput);
else
plodput('\n');
outline++;
@@ -318,7 +318,7 @@ plod(cnt, in_refresh)
dontcr: while (outline < destline) {
outline++;
if (NL)
- tputs(NL, 0, plodput);
+ tputs(NL, 1, plodput);
else
plodput('\n');
if (plodcnt < 0)
@@ -333,7 +333,7 @@ dontcr: while (outline < destline) {
goto out;
#ifdef notdef
if (BT && outcol - destcol > k + 4) {
- tputs(BT, 0, plodput);
+ tputs(BT, 1, plodput);
outcol--;
outcol &= ~7;
continue;
@@ -357,14 +357,14 @@ dontcr: while (outline < destline) {
if (i > destcol)
break;
if (TA)
- tputs(TA, 0, plodput);
+ tputs(TA, 1, plodput);
else
plodput('\t');
outcol = i;
}
if (destcol - outcol > 4 && i < COLS && (BC || BS)) {
if (TA)
- tputs(TA, 0, plodput);
+ tputs(TA, 1, plodput);
else
plodput('\t');
outcol = i;
diff --git a/lib/libcurses/curses.h b/lib/libcurses/curses.h
index 14e82deac58a..fa68e08c79dc 100644
--- a/lib/libcurses/curses.h
+++ b/lib/libcurses/curses.h
@@ -199,6 +199,7 @@ typedef struct termios SGTTY;
extern SGTTY __orig_termios; /* Terminal state before curses */
extern SGTTY __baset; /* Our base terminal state */
extern int __tcaction; /* If terminal hardware set. */
+extern int __tty_fileno; /* Terminal file descriptor */
extern int COLS; /* Columns on the screen. */
extern int LINES; /* Lines on the screen. */
diff --git a/lib/libcurses/refresh.c b/lib/libcurses/refresh.c
index 1a371fe45b2a..b0a84b1dc4f2 100644
--- a/lib/libcurses/refresh.c
+++ b/lib/libcurses/refresh.c
@@ -76,7 +76,11 @@ wrefresh(win)
if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
- tputs(CL, 0, __cputchar);
+ if (curscr->flags & __WSTANDOUT) {
+ tputs(SE, 0, __cputchar);
+ curscr->flags &= ~__WSTANDOUT;
+ }
+ tputs(CL, win->maxy, __cputchar);
ly = 0;
lx = 0;
if (!curwin) {
@@ -266,9 +270,9 @@ makech(win, wy)
if (force) {
if (CM)
- tputs(tgoto(CM, lx, ly), 0, __cputchar);
+ tputs(tgoto(CM, lx, ly), 1, __cputchar);
else {
- tputs(HO, 0, __cputchar);
+ tputs(HO, 1, __cputchar);
__mvcur(0, 0, ly, lx, 1);
}
}
@@ -298,7 +302,7 @@ makech(win, wy)
&& wx <= lch) {
if (ce != NULL && win->maxx + win->begx ==
- curscr->maxx && wx >= nlsp && nsp->ch == ' ') {
+ curscr->maxx && wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) {
/* Check for clear to end-of-line. */
cep = &curscr->lines[win->begy + wy]->line[win->begx + win->maxx - 1];
while (cep->ch == ' ' && cep->attr == 0)
@@ -315,7 +319,11 @@ makech(win, wy)
#ifdef DEBUG
__CTRACE("makech: using CE\n");
#endif
- tputs(CE, 0, __cputchar);
+ if (curscr->flags & __WSTANDOUT) {
+ tputs(SE, 0, __cputchar);
+ curscr->flags &= ~__WSTANDOUT;
+ }
+ tputs(CE, 1, __cputchar);
lx = wx + win->begx;
while (wx++ <= clsp) {
csp->ch = ' ';
@@ -695,37 +703,37 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, top, 0, 1);
/* Scroll up the block */
if (DL && (!dl || n > 1))
- tputs(__tscroll(DL, n), 0, __cputchar);
+ tputs(__tscroll(DL, n), n, __cputchar);
else
for(i = 0; i < n; i++)
- tputs(dl, 0, __cputchar);
+ tputs(dl, 1, __cputchar);
/*
* Push down the bottom region.
*/
__mvcur(top, 0, bot - n + 1, 0, 1);
if (AL && (!al || n > 1))
- tputs(__tscroll(AL, n), 0, __cputchar);
+ tputs(__tscroll(AL, n), n, __cputchar);
else
for(i = 0; i < n; i++)
- tputs(al, 0, __cputchar);
+ tputs(al, 1, __cputchar);
__mvcur(bot - n + 1, 0, oy, ox, 1);
} else {
/* Preserve the bottom lines */
__mvcur(oy, ox, bot + n + 1, 0, 1); /* n < 0 */
if (DL && (!dl || -n > 1))
- tputs(__tscroll(DL, -n), 0, __cputchar);
+ tputs(__tscroll(DL, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(dl, 0, __cputchar);
+ tputs(dl, 1, __cputchar);
__mvcur(bot + n + 1, 0, top, 0, 1);
/* Scroll the block down */
if (AL && (!al || -n > 1))
- tputs(__tscroll(AL, -n), 0, __cputchar);
+ tputs(__tscroll(AL, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(al, 0, __cputchar);
+ tputs(al, 1, __cputchar);
__mvcur(top, 0, oy, ox, 1);
}
} else { /* Use change scroll region */
@@ -735,11 +743,11 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, bot, 0, 1);
/* Scroll up the block */
if (SF && n > 1)
- tputs(__tscroll(SF, n), 0, __cputchar);
+ tputs(__tscroll(SF, n), n, __cputchar);
else
for(i = 0; i < n; i++)
if (NL && __pfast)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
__mvcur(bot, 0, oy, ox, 1);
@@ -747,10 +755,10 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, top, 0, 1);
/* Scroll the block down */
if (SR && (!sr || -n > 1))
- tputs(__tscroll(SR, -n), 0, __cputchar);
+ tputs(__tscroll(SR, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(sr, 0, __cputchar);
+ tputs(sr, 1, __cputchar);
__mvcur(top, 0, oy, ox, 1);
}
if (bot != curscr->maxy - 1 || top != 0)
diff --git a/lib/libcurses/setterm.c b/lib/libcurses/setterm.c
index 35e4e55b26d6..b949ae337843 100644
--- a/lib/libcurses/setterm.c
+++ b/lib/libcurses/setterm.c
@@ -35,6 +35,7 @@
static char sccsid[] = "@(#)setterm.c 8.3 (Berkeley) 1/2/94";
#endif /* not lint */
+#include <termios.h>
#include <sys/ioctl.h>
#include <curses.h>
@@ -42,6 +43,9 @@ static char sccsid[] = "@(#)setterm.c 8.3 (Berkeley) 1/2/94";
#include <string.h>
#include <unistd.h>
+#undef ospeed
+extern short ospeed;
+
static void zap __P((void));
static char *sflags[] = {
@@ -149,6 +153,29 @@ setterm(type)
CA = 1;
PC = _PC ? _PC[0] : 0;
+
+ switch(cfgetospeed(&__baset)) {
+ case B0: ospeed = 0; break;
+ case B50: ospeed = 1; break;
+ case B75: ospeed = 2; break;
+ case B110: ospeed = 3; break;
+ case B134: ospeed = 4; break;
+ case B150: ospeed = 5; break;
+ case B200: ospeed = 6; break;
+ case B300: ospeed = 7; break;
+ case B600: ospeed = 8; break;
+ case B1200: ospeed = 9; break;
+ case B1800: ospeed = 10; break;
+ case B2400: ospeed = 11; break;
+ case B4800: ospeed = 12; break;
+ case B9600: ospeed = 13; break;
+ case EXTA: ospeed = 14; break;
+ case EXTB: ospeed = 15; break;
+ case B57600: ospeed = 16; break;
+ default:
+ case B115200: ospeed = 17; break;
+ }
+
aoftspace = tspace;
ttytype = longname(genbuf, __ttytype);
diff --git a/lib/libcurses/tstp.c b/lib/libcurses/tstp.c
index daac9174d745..164f10bdd8b0 100644
--- a/lib/libcurses/tstp.c
+++ b/lib/libcurses/tstp.c
@@ -54,8 +54,8 @@ __stop_signal_handler(signo)
sigset_t oset, set;
/* Get the current terminal state (which the user may have changed). */
- if (tcgetattr(STDIN_FILENO, &save))
- return;
+ if (tcgetattr(__tty_fileno, &save))
+ return;
/*
* Block window change and timer signals. The latter is because
@@ -87,10 +87,10 @@ __stop_signal_handler(signo)
__set_stophandler();
/* save the new "default" terminal state */
- (void)tcgetattr(STDIN_FILENO, &__orig_termios);
+ (void)tcgetattr(__tty_fileno, &__orig_termios);
/* Reset the terminal state to the mode just before we stopped. */
- (void)tcsetattr(STDIN_FILENO, __tcaction ?
+ (void)tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &save);
/* Restart the screen. */
diff --git a/lib/libcurses/tty.c b/lib/libcurses/tty.c
index d0345bfba993..3f9eabdb3a98 100644
--- a/lib/libcurses/tty.c
+++ b/lib/libcurses/tty.c
@@ -36,10 +36,12 @@ static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 1/2/94";
#endif /* not lint */
#include <sys/ioctl.h>
+#include <sys/file.h>
#include <curses.h>
#include <termios.h>
#include <unistd.h>
+#include <paths.h>
/*
* In general, curses should leave tty hardware settings alone (speed, parity,
@@ -54,6 +56,7 @@ int __tcaction = 1; /* Ignore hardware settings. */
int __tcaction = 0;
#endif
+int __tty_fileno;
struct termios __orig_termios, __baset;
static struct termios cbreakt, rawt, *curt;
static int useraw;
@@ -75,8 +78,12 @@ gettmode()
{
useraw = 0;
- if (tcgetattr(STDIN_FILENO, &__orig_termios))
- return (ERR);
+ if (tcgetattr(__tty_fileno = STDIN_FILENO, &__orig_termios)) {
+ if ((__tty_fileno = open(_PATH_TTY, O_RDONLY, 0)) < 0)
+ return (ERR);
+ else if (tcgetattr(__tty_fileno, &__orig_termios))
+ return (ERR);
+ }
__baset = __orig_termios;
__baset.c_oflag &= ~OXTABS;
@@ -116,7 +123,7 @@ gettmode()
}
curt = &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
}
@@ -125,7 +132,7 @@ raw()
{
useraw = __pfast = __rawmode = 1;
curt = &rawt;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -134,7 +141,7 @@ noraw()
{
useraw = __pfast = __rawmode = 0;
curt = &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -144,7 +151,7 @@ cbreak()
__rawmode = 1;
curt = useraw ? &rawt : &cbreakt;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -154,7 +161,7 @@ nocbreak()
__rawmode = 0;
curt = useraw ? &rawt : &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -166,7 +173,7 @@ echo()
__baset.c_lflag |= ECHO;
__echoit = 1;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -178,7 +185,7 @@ noecho()
__baset.c_lflag &= ~ECHO;
__echoit = 0;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -193,7 +200,7 @@ nl()
__baset.c_oflag |= ONLCR;
__pfast = __rawmode;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -208,7 +215,7 @@ nonl()
__baset.c_oflag &= ~ONLCR;
__pfast = 1;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -216,9 +223,9 @@ void
__set_scroll_region(top, bot)
int top, bot;
{
- tputs(SC, 0, __cputchar);
- tputs(tgoto(CS, bot, top), 0, __cputchar);
- tputs(RC, 0, __cputchar);
+ tputs(SC, 1, __cputchar);
+ tputs(tgoto(CS, bot, top), 1, __cputchar);
+ tputs(RC, 1, __cputchar);
}
void
@@ -253,7 +260,7 @@ endwin()
(void)fflush(stdout);
(void)setvbuf(stdout, NULL, _IOLBF, 0);
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &__orig_termios));
}
@@ -266,12 +273,12 @@ static struct termios savedtty;
int
savetty()
{
- return (tcgetattr(STDIN_FILENO, &savedtty));
+ return (tcgetattr(__tty_fileno, &savedtty));
}
int
resetty()
{
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty));
}
diff --git a/lib/libmalloc/CHANGES b/lib/libmalloc/CHANGES
new file mode 100644
index 000000000000..eaade6259236
--- /dev/null
+++ b/lib/libmalloc/CHANGES
@@ -0,0 +1,58 @@
+Jan 29, 1994 v1.13
+
+Subtle realloc bug uncovered by Gianni Mariani's super malloc stress test.
+(realloc could return a block less than _malloc_minchunk which could cause
+free to die under certain conditions). testmalloc now checks this case.
+
+Dec 15, 1993
+
+Fixed various problems with formats (printing ints for longs or vice versa)
+pointed out by der Mouse. Integrated old fix to make grabhunk work if
+blocks returned by the memfunc routine (sbrk, etc) are lower than the
+previous blocks. Not well-tested yet.
+
+Jul 30, 1993
+
+Bunch of fixes from mds@ilight.com (Mike Schechterman) to make it compile
+and work on Alpha/OSF1, RS6000/AIX3.2, SGI/Irix4.0.5, HP720/HP-UX8.0.7,
+DEC5000/Ultrix4.2. Thanks, Mike.
+
+Major user visible change is that 'make onefile' becomes 'make one' because
+of overly-smart 'make's. Minor change is that testmalloc, teststomp and
+simumalloc all want stdlib.h or proper stdio.h, else they have implicit
+ints. I don't want to declare libc functions.
+
+Added ecalloc, _ecalloc.
+
+--
+Added mmap() support.
+
+Cleaned up externs.h a bit more, added sysconf() call for Posix
+
+Merged some of the smaller files into larger ones.
+
+Added mal_contents from ZMailer version of malloc, changed counters in
+leak.c from long to unsigned long.
+
+On a pure allocation pattern, the old one started to take a bad
+performance hit on the search that precedes an sbrk, because of the
+wilderness preservation problem -- we search through every block in
+the free list before the sbrk, even though none of them will satisfy
+the request, since they're all probably little chunks left over from
+the last sbrk chunk. So our performance reduces to the same as that of
+the 4.1 malloc. Yech. If we were to preserve the wilderness, we
+wouldn't have these little chunks. Good enough reason to reverse the
+philosophy and cut blocks from the start, not the end. To minimize
+pointer munging, means we have to make the block pointer p point to
+the end of the block (i.e the end tag) NEXT becomes (p-1)->next, PREV
+becomes (p-2)->prev, and the start tag becomes (p + 1 -
+p->size)->size. The free logic is reversed -- preceding block merge
+needs pointer shuffle, following block merge doesn't require pointer
+shuffle. (has the additional advantage that realloc is more likely to
+grow into a free area) Did this -- malloc, free stayed as complex/big,
+but realloc and memalign simplified a fair bit. Now much faster on
+pure allocation pattern, as well as any pattern where allocation
+dominates, since fragmentation is less. Also much less wastage.
+
+Also trimmed down the search loop in malloc.c to make it much smaller
+and simpler, also a mite faster.
diff --git a/lib/libmalloc/COPYRIGHT b/lib/libmalloc/COPYRIGHT
new file mode 100644
index 000000000000..5c3c417945d3
--- /dev/null
+++ b/lib/libmalloc/COPYRIGHT
@@ -0,0 +1,23 @@
+/*
+ * Copyright University of Toronto 1988, 1989, 1993.
+ * Written by Mark Moraes
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author and the University of Toronto are not responsible
+ * for the consequences of use of this software, no matter how awful,
+ * even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+/* This COPYRIGHT does not apply to the subdirectory splay and its contents */
diff --git a/lib/libmalloc/Makefile b/lib/libmalloc/Makefile
new file mode 100644
index 000000000000..2ff0abf62b7f
--- /dev/null
+++ b/lib/libmalloc/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.2 1994/05/27 10:42:42 csgr Exp $
+
+CFLAGS+= -I${.CURDIR} -DHAVE_MMAP -DSTDHEADERS -fno-builtin
+PFLAGS+= -DTRACE -DPROFILESIZES
+
+LIB= malloc
+
+SRCS+= _emalloc.c _malloc.c _memalign.c _strdup.c _strsave.c botch.c \
+ dumpheap.c emalloc.c getmem.c leak.c malloc.c memalign.c setopts.c \
+ sptree.c stats.c strdup.c strsave.c verify.c
+NOMAN= noman
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/malloc.h \
+ ${DESTDIR}/usr/include
+
+.include <bsd.lib.mk>
diff --git a/lib/libmalloc/Makefile.moraes b/lib/libmalloc/Makefile.moraes
new file mode 100644
index 000000000000..c9d7fa3d45f6
--- /dev/null
+++ b/lib/libmalloc/Makefile.moraes
@@ -0,0 +1,187 @@
+# $Id: Makefile.moraes,v 1.1 1994/03/06 22:59:15 nate Exp $
+#
+# This Makefile is set up to make a debugging malloc called libmalloc_d.a
+# Also generates testmalloc and simumalloc, two regression tests.
+#
+# To make a production malloc, type 'make clean libmalloc'
+#
+# If you're impatient, and want it all in one file, type 'make one'
+# and it'll merge the all the source into one file. Bit bigger, but
+# avoids Unix linker misunderstandings if these are not in libc, and
+# ensures the debugging routines are linked in whether called or not.
+# On some machines, mv onefile.o libmalloc_d.a will work. On some, it
+# upsets the linker and you will need to "ar ruv libmalloc_d.a onefile.o".
+#
+# 'make dist' runs 'bundle' to create a shell archive on stdout.
+#
+# 'make veryclean' cleans out lib*.a as well.
+#
+# 'make depend' runs 'mkdep' (from BSD src or named) to create dependencies.
+#
+# 'make install' puts all the OBJS in $(ARCHIVE), ranlibs it, and
+# puts malloc.h in INCDIR.
+#
+
+# neutralize SystemV genius
+SHELL=/bin/sh
+
+# DEBUGDEFS are set for libmalloc_d.a. Say 'make libmalloc' for nondebug
+# version. (DEBUGDEFS=$(FASTDEFS))
+#
+DEBUGDEFS=-DDEBUG -DTRACE -DPROFILESIZES
+
+# FASTDEFS are used when the 'libmalloc' target is made.
+#
+# -DTRACE and -DPROFILESIZES shouldn't introduce very much overhead since the
+# former is turned off (one 'if'), and the latter is one 'if' + increment.
+# So you can keep them even in the fast production version.
+# You may want to define -DBUGCOMPATIBILITY if you want malloc(0) to
+# do the same thing as malloc(1). Some suntools programs expect this
+# behaviour. So does Xlib, and the X server has done it at least once.
+# (Note that SVID requires malloc(0) to return NULL, and the
+# May 13, 1988 ANSI C draft says that you can either return a NULL pointer
+# or a unique pointer (typically decisive standard...)
+#
+FASTDEFS=#-DBUGCOMPATIBILITY -DTRACE -DPROFILESIZES
+
+
+# NORMALDEFS are used for both debugging and non-debugging versions
+# -DSHORTNAMES makes sure all internal global symbols are unique within 6
+# characters. Avoid defining unless your linker is braindead.
+# -DUSESTDIO is to make this use fputs() instead of write() for trace
+# and debugging output. write() is preferable since it is unbuffered,
+# and does not call malloc() or suchlike. Avoid defining if possible.
+# -DSTDHEADERS if you have ANSI standard header files (stdlib.h, string.h)
+# This can be defined on Solaris2.1, Irix3.3.x, BSD3.3,
+# 386BSD, BSD386 and other sufficiently Posix systems.
+# -DHAVE_MMAP should be defined for SunOS4.x and other systems
+# that have a general purpose mmap call that allows memory-mapped files.
+#
+NORMALDEFS=-DHAVE_MMAP -DSTDHEADERS # -DSHORTNAMES -DUSESTDIO
+
+LIBMALLOC=libmalloc_d.a
+ARCHIVE = $(HOME)/lib/$(LIBMALLOC)
+
+DEFINES= $(NORMALDEFS) $(DEBUGDEFS)
+
+LIBDIR=$(HOME)/lib
+INCDIR=$(HOME)/include
+
+CC = gcc -Wall # -pedantic # add -pedantic if you fixed your includes.
+# SGI needs cc -xansi -D__STDC__ on Irix4.0.5.
+
+EXTRAINCLUDES=-I$(HOME)/include
+CDEBUGFLAGS=-g -O
+
+SPLAYOBJ = splay/sptree.o
+SPLAYSRC = splay/sptree.c
+SPLAYHDR = splay/sptree.h
+
+SRCS = _emalloc.c _malloc.c _memalign.c \
+ _strdup.c _strsave.c botch.c \
+ dumpheap.c emalloc.c getmem.c leak.c \
+ malloc.c memalign.c setopts.c \
+ stats.c strdup.c strsave.c verify.c
+
+OBJS = _emalloc.o _malloc.o _memalign.o \
+ _strdup.o _strsave.o botch.o \
+ dumpheap.o emalloc.o getmem.o leak.o \
+ malloc.o memalign.o setopts.o \
+ stats.o strdup.o strsave.o verify.o
+
+# HDRS, DOCS, TESTS and EXTRAS are used when making distributions.
+# so please keep them uptodate.
+# bundle is smart enough not to include object files, RCS, executables,
+# etc, and does subdirectories right, but there's often other files
+# in the development directory...
+
+# globals.c, version.c are included in malloc.c.
+HDRS = align.h assert.h defs.h externs.h globals.c globals.h globrename.h \
+ malloc.h trace.h version.c
+
+DOCS = README NOTE TODO CHANGES malloc.doc Makefile
+
+TESTS = testmalloc.c test.out testsbrk.c teststomp.c tests regress \
+ simumalloc.c testrun.sh plot.sh munge.sh
+
+EXTRAS = splay
+
+INCLUDES=-I./splay $(EXTRAINCLUDES)
+
+LN = ln -s
+OLDCC = cc
+OLDCFLAGS = -O
+AR = ar
+ARFLAGS = ruv
+RANLIB = ranlib
+
+LDFLAGS=#-Bstatic
+
+CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(DEFINES)
+
+all: $(LIBMALLOC) testmalloc simumalloc teststomp
+
+libmalloc:
+ make -f Makefile $(MFLAGS) CC="$(CC)" DEBUGDEFS="$(FASTDEFS)" \
+ LIBMALLOC=libmalloc.a CDEBUGFLAGS="$(CDEBUGFLAGS)"
+
+testmalloc: testmalloc.o $(LIBMALLOC)
+ $(CC) $(CFLAGS) -o testmalloc testmalloc.o $(LIBMALLOC) ${LDFLAGS}
+
+teststomp: teststomp.o $(LIBMALLOC)
+ $(CC) $(CFLAGS) -o teststomp teststomp.o $(LIBMALLOC) ${LDFLAGS}
+
+simumalloc: simumalloc.c $(LIBMALLOC)
+ $(CC) $(CFLAGS) -DMYMALLOC -o simumalloc \
+ simumalloc.c $(LIBMALLOC) ${LDFLAGS}
+
+$(LIBMALLOC): $(OBJS) $(SPLAYOBJ)
+ rm -f $(LIBMALLOC)
+ $(AR) $(ARFLAGS) $(LIBMALLOC) $(OBJS) $(SPLAYOBJ)
+ -$(RANLIB) $(LIBMALLOC)
+
+$(SPLAYOBJ): .foo
+ cd splay; make $(MFLAGS) DEFINES="$(DEFINES)" \
+ LIBMALLOC=../$(LIBMALLOC) CC="$(CC)"
+
+one: onefile.o
+
+onefile.c: $(SRCS) $(SPLAYSRC)
+ rm -f onefile.c
+ cat $(SRCS) $(SPLAYSRC) | sed '/RCSID/d' > onefile.c
+
+.foo:
+
+clean:
+ -rm -f *.o \#* *~ core a.out gmon.out mon.out testmalloc simumalloc \
+ teststomp onefile.c *.sL prof.out
+ cd splay; make clean
+
+veryclean: clean
+ -rm -f libmalloc.a libmalloc_d.a make.log make.out
+
+install:
+ $(AR) $(ARFLAGS) $(ARCHIVE) $(OBJS) $(SPLAYOBJ)
+ -$(RANLIB) $(ARCHIVE)
+ install -c -m 644 malloc.h $(INCDIR)
+
+.id: $(SRCS)
+ mkid $(SRCS) $(SPLAYSRC) $(HDRS) $(SPLAYHDR)
+ touch .id
+
+dist:
+ @rm -f Makefile.bak
+ @mv Makefile Makefile.bak;\
+ sed '/^# DO NOT PUT ANYTHING/,$$d' Makefile.bak > Makefile; \
+ (bundle -v $(DOCS) $(SRCS) $(HDRS) $(TESTS) $(EXTRAS)); \
+ mv Makefile.bak Makefile
+
+files:
+ find * -type f -print | \
+ egrep -v '(,v|\.o|core|make.log|simumalloc|testmalloc|teststomp)$$' | \
+ egrep -v '(libmalloc.*\.a|res\..*)$$' > FILES
+
+depend: onefile.c
+ mkdep $(INCLUDES) $(DEFINES) $(SRCS) onefile.c
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/lib/libmalloc/NOTE b/lib/libmalloc/NOTE
new file mode 100644
index 000000000000..dede8664d38e
--- /dev/null
+++ b/lib/libmalloc/NOTE
@@ -0,0 +1,151 @@
+Miscellaneous notes on the malloc internals.
+
+First fit malloc with boundary tags for fast freeing - based on the
+techniques described in 'The Art of Computer Programming' by Donald
+Knuth. The essential features of the boundary tag are described in
+Algorithm C, Section 2.5. The actual algorithms here incorporate the
+improvements suggested in Exercises 12 and and 15 (I think), and
+adaptations to the C/Un*x environment, plus some performance
+improvements. By keeping the list circular, we don't have an AVAIL at
+all - just use ROVER as the pointer into the list. It also tries to
+"preserve the wilderness" -- i.e. try to keep the block nearest the
+data break free as far as possible, but it does go overboard about it.
+(i.e. it is a simple first fit -- many wilderness preservation schemes
+tend to keep the wilderness block out of the free list, and search the
+rest of the free list first. I find that degrades performance
+somewhat, even if it keeps memory slightly less fragmented)
+
+This has a lot of debugging and tracing support built in - compiling
+with -DDEBUG provides fairly comprehensive ASSERT protection to detect
+heap corruption. (It aborts on the first sign of trouble). I hope that
+every pointer reference is protected with an assertion, so the malloc
+should never dump core or behave weirdly because of user program
+misbehaviour -- it should blow an assertion instead. If the debugging
+version ever gets a segmentation fault, bus error and dumps core
+instead of blowing an assertion and then dumping core on an IO trap or
+Illegal Instruction (depending on how your system does an abort()), I
+want to know...
+
+For the non-debugging malloc:
+
+A minimum size for an allocated block is 4 units - two for the
+leading and trailing size word, and two for the next and previous
+pointers. Therefore the minimum size that we can allocate is 2
+units, since allocated and freed blocks both have the leading and
+trailing size blocks. Only freed blocks have the next, prev
+pointers. The size block is actually a signed - the sign bit
+indicates whether it is a free or allocated block. i.e the tag.
+
+For the debugging malloc:
+
+The minimum size for an allocated block is still 4 units - two for the
+leading and trailing size word, and two for the next and previous
+pointers. But the minimum size that we can allocate is 1 units, since
+allocated and freed blocks both have the leading and trailing size
+blocks. Only freed blocks have the next, prev pointers. Only allocated
+blocks have the realsize word, which indicates the size of the block
+requested by the user in bytes. The next pointer and the realsize word
+share the same header word. So the overhead for an allocated block is
+3 words when debugging, as opposed to 2 words when not debugging.
+(even though the minimum block size is still 4 words)
+
+The size block is actually a signed - the sign bit indicates whether
+it is a free or allocated block. i.e the tag. Since the size is in
+words, this loss of a bit is no big deal. The realsize block is a full
+unsigned word, since it stores the size in bytes.
+
+For the leak tracing malloc
+
+The _*.c files all have the extra macros that record the blocks as
+they are allocated, and deleted. The extra tracing macro also prints
+the file name and line number before the usual tracing information
+about size etc. This permits you to find out where block xxx was
+freed, so that you can do an address to name mapping more easily.
+
+Note that to use this stuff, you HAVE to include malloc.h and define
+MALLOC_TRACE when compiling. It still works correctly when you don't
+include malloc.h, but you won't get all the information.
+
+Performance
+
+The fastest malloc I know of is the BSD4.3 malloc, which uses a number
+of bins with different sized blocks, sized in powers of two. All it
+has to do to find a free block is an iterated shift to compute the
+bin, if the bin is empty then split a block from one of the higher
+bins. Unfortunately, it can waste spectacular amounts of space for
+many programs.
+
+The most space efficient malloc I know is Sun's Cartesian tree "better
+fit" malloc (It has a hidden overhead of 8K of static data, though).
+It is also unpleasantly slow.
+
+My malloc is close to the BSD4.3 malloc in performance - the
+difference starts to become obvious only as the number of blocks in
+the free list climbs towards the 100000 to million range at which
+point the 4.3 malloc starts to pull ahead in user time, but quite
+often, its VM behaviour deteriorates and makes its elapsed times very
+large. My malloc is close to Sun's malloc in space efficiency.
+
+The key to the improved performance over typical first fit allocators
+is the roving pointer, as well as the coalescing of freed blocks,
+which keeps memory fragmentation and the size of the free list down.
+The wilderness preservation heuristic also helps a lot.
+
+Guide to porting it:
+
+Should port without trouble to machines where any ugliness or
+weirdness in pointers or segmentation is hidden from the programmer. I
+haven't tried porting it to the 286 and below under DOS, nor do I
+intend to at present.
+
+You may need to check align.h if your machine has non-standard
+alignment requirements. (I interpret standard alignment to be
+alignenment on one of char, int, char *, int *, char **, int **,
+whichever requires the strictest alignment) If not, define ALIGN and
+NALIGN.
+
+PLEASE LEAVE THE MAIN CODE FREE FROM #ifdefs. I'm interested in fixes
+for porting it to new machines, only if they do not damage the code.
+I'd prefer to find a least common denominator, or hide the difference
+in a macro.
+
+People interested in reading and understanding this code should start
+in defs.h (after this file, of course) -- it contains all the macros.
+It'll help if you've read the following references. After that, study
+globals.c, malloc.c, verify.c and dumpheap.c. Running testmalloc and
+following the development of the heap is recommended.
+
+After you've ported it, you should be able to run testmalloc without
+trouble, as well as the few runs of simumalloc listed in regress,
+compiled with the debugging version of malloc. (-DDEBUG defined)
+
+If you uncover a bug, please enhance testmalloc.c with a case that
+triggers the bug, if you can. That way, I can make sure future changes
+to malloc don't re-introduce that bug.
+
+References:
+
+%A Donald E. Knuth
+%T The Art of Computer Programming (Fundamental Algorithms)
+%V 1
+%I Addison Wesley
+%C Reading, Mass.
+%D 1973
+
+%A David G. Korn
+%A Kiem-Phong Vo
+%T In search of a better malloc
+%J Proceedings of the USENIX 1985 Summer Conference
+%C Portland, Oregon
+%D June 1985
+%P 489-506
+
+%A C.J. Stephenson
+%T Fast fits: new methods for dynamic storage allocation
+%J Proceedings of the Ninth ACM Symposium on Operating Systems Principles
+%C Bretton Woods, New Hampshire
+%D October 1983
+%P 30-32
+%O abstract only - paper to be published in TOCS
+%O published as Operating Systems Review 17:5
+%O also appeared in Scientific American somewhere -- reference in Korn and Vo
diff --git a/lib/libmalloc/README b/lib/libmalloc/README
new file mode 100644
index 000000000000..6d508d37477e
--- /dev/null
+++ b/lib/libmalloc/README
@@ -0,0 +1,68 @@
+This is a complete set of memory allocation functions (malloc and
+friends).
+ The allocator is small, fast and space-efficient.
+
+ It performs coalescing on frees.
+
+ It has hooks for profiling, tracing and memory leak detection.
+
+ It has very comprehensive and paranoid errorchecking as a compile
+ time option, enough to detect most forms of heap corruption.
+
+ Optionally, it attempts to be compatible with the proposed ANSI C
+ Standard definition for the standard library functions malloc(),
+ calloc(), realloc() and free(). By default, it is more or less
+ compatible with existing Unix malloc() functions - some
+ differences do exist. (Notably free(), cfree() returning void,
+ realloc() not accepting a freed block)
+
+See the file malloc.doc for the full details.
+
+Porting to other machines shouldn't be hard if they have a civilized C
+compiler, and an sbrk().
+
+Eventually, the goal is to make this malloc() conformant with ANSI C -
+it's getting there. It can be convinced to return void * and accept
+size_t, so you can use it for ANSI C conformant programs by defining
+ANSI_TYPES. Till then it's meant to be broadly conformant with Unix
+malloc()s.
+
+To compile it, make sure ALIGN (in align.h) is correct for your machine, and
+make it. testmalloc should run correctly and say Test done if it is
+working, producing amazing amounts of heap trace. If it dumps core, it
+isn't working...
+
+Depending on which end of the philosophical spectrum you lie, define
+-DBUGCOMPATIBILITY. If defined, malloc(0) will do the same thing as
+malloc(1). If not defined, the debugging malloc will abort() with an
+error, while the non-debugging malloc will return NULL. (and set errno
+to EINVAL). Note that the SVID requires malloc(0) to return NULL, and
+the May 13, 1988 ANSI C draft says that you can either return a NULL
+pointer or a unique pointer (typically decisive standard...)
+
+libmalloc.a is a fast, small version, with no
+debugging/profiling/tracing, while libmalloc_d.a is the version with
+all those three. (Profiling and tracing should not introduce serious
+overhead, since profiling is simple and fast, (one 'if' and increment),
+while tracing is turned off by default. So you may want to keep
+profiling and tracing in the fast version as well)
+ make clean all
+will make libmalloc_d.a and the test programs.
+
+ make clean libmalloc
+will make libmalloc.a.
+
+For linking convenience, you may want to compile the malloc as one
+file instead. To do that, simply make onefile.o. It concatenates all
+the src together and compiles it - the include files are protected
+against multiple inclusion. This has the advantage of compiling in
+things like mal_verify() and mal_trace() even if they aren't used, so
+you can use them when debugging.
+
+ Mark Moraes.
+ Computer Systems Research Institute,
+ Univerity of Toronto.
+ moraes@csri.toronto.{edu,cdn}
+ moraes@csri.utoronto.ca
+ moraes@utcsri.uucp
+ {your favourite backbone}!uunet!utai!utcsri!moraes
diff --git a/lib/libmalloc/TODO b/lib/libmalloc/TODO
new file mode 100644
index 000000000000..ae4430a74516
--- /dev/null
+++ b/lib/libmalloc/TODO
@@ -0,0 +1,62 @@
+alloca-like allocation with malloc -- mark()/release() paradigm. specify a
+point where one starts a stack (stk_create), and stk_alloc from that.
+stk_free releases the specified stack. This speeds up frees, doesn't speed
+up mallocs too much? Time it in trace situations.
+
+Tests all in subdirectory.
+
+sbrk stuff for Mach.
+
+Scan all my email on malloc?
+
+Make the document a manual page. Terser, less cutesy.
+
+mal_size() returns size of a malloc'ed block in bytes.
+
+before starting a search in malloc(), if rover points to wilderness, and
+wilderness->next is not null, rover = wilderness->next. need to keep
+wilderness uptodate. should help rayan.
+
+check alignment in IS_VALID_PTR.
+
+Adaptive sbrk size. Keep increasing it by DEF_SBRKUNITS, then if sbrk fails,
+half the sbrkunits till we're smaller than the request (in which case it's
+all over). Should reduce the number of calls to sbrk without increasing
+wastage too much.
+
+Generalize grabhunk() to work properly if new arenas are lower than the old
+ones - i.e. don't rely on sbrk() semantics at all. I already did some of
+this work in the port to the Firefly. [DONE -- Dec 15, 1993]
+
+Check that totalavail works right for realloc. Should we scrap totalavail
+and save a pointer to the max block, so that can both tell if we need to
+sbrk without a search, as well as realize if the max block has shrunk.
+Problem: how do we know if the max block shrank below the size of some other
+block? Heuristic? Average block size? Some adapting fraction of totalavail?
+We sbrk if request is greater than (1+fraction)*totalavail/nfree is what
+Korn and Vo suggest. Assuming fraction is always 1/K, we get
+(K+1)*totalavail/K/nfree. We can double K everytime we fail a search. To
+provide some negative feedback, we can change the 1 to M, and increment M
+everytime we succeed in a search. Doesn't sound good. Need a better
+heuristic. Grump. Avoid this stuff for now.
+
+Separate all system dependent stuff into a sysdep header where these things
+can fight it out.
+
+create stdlib.h and move std. decls there. keep malloc.h as a value added
+thing and declare new stuff there. decide on malloc(0).
+(malloc 0 should return 0 sized block by default, I think)
+
+setopt Non-ansi should cause malloc(0), realloc(0, *) or realloc(*, 0)
+to fail.
+
+some way to report when the last free happened when you try to use a freed
+pointer. maintain a splay tree where you add ptrs when you free'em and
+delete when you malloc them?
+
+finish my trace driven simulation stuff in ../maltrace.
+
+way to walk the heap. if it is a macro, then the other two could use it too.
+should probably switch to arena before all these changes.
+
+interns.h from externs.h. Then we don't need aexterns.h.
diff --git a/lib/libmalloc/_emalloc.c b/lib/libmalloc/_emalloc.c
new file mode 100644
index 000000000000..347e8960f088
--- /dev/null
+++ b/lib/libmalloc/_emalloc.c
@@ -0,0 +1,55 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _emalloc.c,v 1.1 1994/03/06 22:59:19 nate Exp $")
+
+univptr_t
+__emalloc(nbytes, fname, linenum)
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = emalloc(nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+
+univptr_t
+__erealloc(ptr, nbytes, fname, linenum)
+univptr_t ptr;
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = erealloc(ptr, nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+univptr_t
+__ecalloc(nelem, sz, fname, linenum)
+size_t nelem, sz;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = ecalloc(nelem, sz);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+
diff --git a/lib/libmalloc/_malloc.c b/lib/libmalloc/_malloc.c
new file mode 100644
index 000000000000..34104e47f8c7
--- /dev/null
+++ b/lib/libmalloc/_malloc.c
@@ -0,0 +1,88 @@
+/*
+ * These are the wrappers around malloc for detailed tracing and leak
+ * detection. Allocation routines call RECORD_FILE_AND_LINE to record the
+ * filename/line number keyed on the block address in the splay tree,
+ * de-allocation functions call DELETE_RECORD to delete the specified block
+ * address and its associated file/line from the splay tree.
+ */
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _malloc.c,v 1.1 1994/03/06 22:59:20 nate Exp $")
+
+univptr_t
+__malloc(nbytes, fname, linenum)
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = malloc(nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+/* ARGSUSED if TRACE is not defined */
+void
+__free(cp, fname, linenum)
+univptr_t cp;
+const char *fname;
+int linenum;
+{
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ DELETE_RECORD(cp);
+ free(cp);
+}
+
+univptr_t
+__realloc(cp, nbytes, fname, linenum)
+univptr_t cp;
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t old;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ old = cp;
+ cp = realloc(cp, nbytes);
+ if (old != cp) {
+ DELETE_RECORD(old);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ }
+ return(cp);
+}
+
+univptr_t
+__calloc(nelem, elsize, fname, linenum)
+size_t nelem, elsize;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = calloc(nelem, elsize);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+/* ARGSUSED if TRACE is not defined */
+void
+__cfree(cp, fname, linenum)
+univptr_t cp;
+const char *fname;
+int linenum;
+{
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ DELETE_RECORD(cp);
+ /* No point calling cfree() - it just calls free() */
+ free(cp);
+}
diff --git a/lib/libmalloc/_memalign.c b/lib/libmalloc/_memalign.c
new file mode 100644
index 000000000000..c39b3d269065
--- /dev/null
+++ b/lib/libmalloc/_memalign.c
@@ -0,0 +1,37 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _memalign.c,v 1.1 1994/03/06 22:59:21 nate Exp $")
+
+univptr_t
+__memalign(alignment, size, fname, linenum)
+size_t alignment, size;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = memalign(alignment, size);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+univptr_t
+__valloc(size, fname, linenum)
+size_t size;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = valloc(size);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/_strdup.c b/lib/libmalloc/_strdup.c
new file mode 100644
index 000000000000..074bc1d68916
--- /dev/null
+++ b/lib/libmalloc/_strdup.c
@@ -0,0 +1,23 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _strdup.c,v 1.1 1994/03/06 22:59:21 nate Exp $")
+
+char *
+__strdup(s, fname, linenum)
+char *s;
+const char *fname;
+int linenum;
+{
+ char *cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = strdup(s);
+ RECORD_FILE_AND_LINE((univptr_t) cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/_strsave.c b/lib/libmalloc/_strsave.c
new file mode 100644
index 000000000000..1db174d73d39
--- /dev/null
+++ b/lib/libmalloc/_strsave.c
@@ -0,0 +1,23 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _strsave.c,v 1.1 1994/03/06 22:59:22 nate Exp $")
+
+char *
+__strsave(s, fname, linenum)
+char *s;
+const char *fname;
+int linenum;
+{
+ char *cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = strsave(s);
+ RECORD_FILE_AND_LINE((univptr_t) cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/align.h b/lib/libmalloc/align.h
new file mode 100644
index 000000000000..c1424895a9a3
--- /dev/null
+++ b/lib/libmalloc/align.h
@@ -0,0 +1,94 @@
+/* $Id: align.h,v 1.1 1994/03/06 22:59:26 nate Exp $ */
+#ifndef __ALIGN_H__
+#define __ALIGN_H__
+/*
+ * 'union word' must be aligned to the most pessimistic alignment needed
+ * on the architecture (See align.h) since all pointers returned by
+ * malloc and friends are really pointers to a Word. This is the job of
+ * the 'foo' field in the union, which actually decides the size. (On
+ * Sun3s, 1 int/long (4 bytes) is good enough, on Sun4s, 8 bytes are
+ * necessary, i.e. 2 ints/longs)
+ */
+/*
+ * 'union word' should also be the size necessary to ensure that an
+ * sbrk() immediately following an sbrk(sizeof(union word) * n) returns
+ * an address one higher than the first sbrk. i.e. contiguous space from
+ * successive sbrks. (Most sbrks will do this regardless of the size -
+ * Sun's doesnt) This is not vital - the malloc will work, but will not
+ * be able to coalesce between sbrk'ed segments.
+ */
+
+#if defined(sparc) || defined(__sparc__) || defined(__sgi)
+/*
+ * Sparcs require doubles to be aligned on double word, SGI R4000 based
+ * machines are 64 bit, this is the conservative way out
+ */
+/* this will waste space on R4000s or the 64bit UltraSparc */
+# define ALIGN long foo[2]
+# define NALIGN 8
+#endif
+
+#if defined(__alpha)
+/* 64 bit */
+# define ALIGN long foo
+# define NALIGN 8
+#endif
+
+/* This default seems to work on most 32bit machines */
+#ifndef ALIGN
+# define ALIGN long foo
+# define NALIGN 4
+#endif
+
+/* Align with power of 2 */
+#define SIMPLEALIGN(X, N) (univptr_t)(((size_t)((char *)(X) + (N-1))) & ~(N-1))
+
+#if NALIGN == 2 || NALIGN == 4 || NALIGN == 8 || NALIGN == 16
+ /* if NALIGN is a power of 2, the next line will do ok */
+# define ALIGNPTR(X) SIMPLEALIGN(X, NALIGN)
+#else
+ /* otherwise we need the generic version; hope the compiler isn't too smart */
+ static size_t _N = NALIGN;
+# define ALIGNPTR(X) (univptr_t)((((size_t)((univptr_t)(X)+(NALIGN-1)))/_N)*_N)
+#endif
+
+/*
+ * If your sbrk does not return blocks that are aligned to the
+ * requirements of malloc(), as specified by ALIGN above, then you need
+ * to define SBRKEXTRA so that it gets the extra memory needed to find
+ * an alignment point. Not needed on Suns on which sbrk does return
+ * properly aligned blocks. But on U*x Vaxen, A/UX and UMIPS at least,
+ * you need to do this. It is safer to take the non Sun route (!! since
+ * the non-sun part also works on Suns, maybe we should just remove the
+ * Sun ifdef)
+ */
+#if ! (defined(sun) || defined(__sun__))
+# define SBRKEXTRA (sizeof(Word) - 1)
+# define SBRKALIGN(x) ALIGNPTR(x)
+#else
+# define SBRKEXTRA 0
+# define SBRKALIGN(x) (x)
+#endif
+
+#ifndef BITSPERBYTE
+ /*
+ * These values should work with any binary representation of integers
+ * where the high-order bit contains the sign. Should be in values.h,
+ * but just in case...
+ */
+ /* a number used normally for size of a shift */
+# if gcos
+# define BITSPERBYTE 9
+# else /* ! gcos */
+# define BITSPERBYTE 8
+# endif /* gcos */
+#endif /* BITSPERBYTE */
+
+#ifndef BITS
+# define BITS(type) (BITSPERBYTE * (int) sizeof(type))
+#endif /* BITS */
+
+/* size_t with only the high-order bit turned on */
+#define HIBITSZ (((size_t) 1) << (BITS(size_t) - 1))
+
+#endif /* __ALIGN_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/assert.h b/lib/libmalloc/assert.h
new file mode 100644
index 000000000000..08f11ff87994
--- /dev/null
+++ b/lib/libmalloc/assert.h
@@ -0,0 +1,10 @@
+/* $Id: assert.h,v 1.1 1994/05/19 14:34:09 nate Exp $ */
+#ifndef __ASSERT_H__
+#define __ASSERT_H__
+#ifdef DEBUG
+#define ASSERT(p, s) ((void) (!(p) ? __m_botch(s, __FILE__, __LINE__) : 0))
+extern int __m_botch proto((const char *, const char *, int));
+#else
+#define ASSERT(p, s)
+#endif
+#endif /* __ASSERT_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/botch.c b/lib/libmalloc/botch.c
new file mode 100644
index 000000000000..93b28b4938c8
--- /dev/null
+++ b/lib/libmalloc/botch.c
@@ -0,0 +1,45 @@
+#include "defs.h"
+#include "globals.h"
+
+int
+__nothing()
+{
+ return 0;
+}
+
+/*
+ * Simple botch routine - writes directly to stderr. CAREFUL -- do not use
+ * printf because of the vile hack we use to redefine fputs with write for
+ * normal systems (i.e not super-pure ANSI)!
+ */
+int
+__m_botch(s, filename, linenumber)
+const char *s;
+const char *filename;
+int linenumber;
+{
+ static char linebuf[32]; /* Enough for a BIG linenumber! */
+ static int notagain = 0;
+
+ if (notagain == 0) {
+ /* Try to flush the trace file and unbuffer stderr */
+ (void) fflush(_malloc_statsfile);
+ (void) setvbuf(stderr, (char *) 0, _IONBF, 0);
+ (void) sprintf(linebuf, "%d: ", linenumber);
+ (void) fputs("memory corruption error detected, file ",
+ stderr);
+ (void) fputs(filename, stderr);
+ (void) fputs(", line ", stderr);
+ (void) fputs(linebuf, stderr);
+ (void) fputs(s, stderr);
+ (void) fputs("\n", stderr);
+ /*
+ * In case stderr is buffered and was written to before we
+ * tried to unbuffer it
+ */
+ (void) fflush(stderr);
+ notagain++; /* just in case abort() tries to cleanup */
+ abort();
+ }
+ return 0; /* SHOULDNTHAPPEN */
+}
diff --git a/lib/libmalloc/bsd.lib.mk b/lib/libmalloc/bsd.lib.mk
new file mode 100644
index 000000000000..4e4c51298e8d
--- /dev/null
+++ b/lib/libmalloc/bsd.lib.mk
@@ -0,0 +1,269 @@
+# from: @(#)bsd.lib.mk 5.26 (Berkeley) 5/2/91
+# $Id: bsd.lib.mk,v 1.1 1994/03/06 22:59:28 nate Exp $
+#
+
+.if exists(${.CURDIR}/../Makefile.inc)
+.include "${.CURDIR}/../Makefile.inc"
+.endif
+
+.if exists(${.CURDIR}/shlib_version)
+SHLIB_MAJOR != . ${.CURDIR}/shlib_version ; echo $$major
+SHLIB_MINOR != . ${.CURDIR}/shlib_version ; echo $$minor
+.endif
+
+
+LIBDIR?= /usr/lib
+LINTLIBDIR?= /usr/libdata/lint
+LIBGRP?= bin
+LIBOWN?= bin
+LIBMODE?= 444
+
+STRIP?= -s
+
+BINGRP?= bin
+BINOWN?= bin
+BINMODE?= 555
+
+.MAIN: all
+
+# prefer .s to a .c, add .po, remove stuff not used in the BSD libraries
+# .so used for PIC object files
+.SUFFIXES:
+.SUFFIXES: .out .o .po .so .s .S .c .cc .cxx .m .C .f .y .l
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.c.po:
+ ${CC} -p ${CFLAGS} ${PFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.c.so:
+ ${CC} ${PICFLAG} -DPIC ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+.cc.o .cxx.o .C.o:
+ ${CXX} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.cc.po .C.po .cxx.o:
+ ${CXX} -p ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.cc.so .C.so:
+ ${CXX} ${PICFLAG} -DPIC ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+.f.o:
+ ${FC} ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.f.po:
+ ${FC} -p ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.f.so:
+ ${FC} ${PICFLAG} -DPIC ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+
+.s.o:
+ ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.s.po:
+ ${CPP} -E -DPROF ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.s.so:
+ ${CPP} -E -DPIC ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -k -o ${.TARGET}
+
+.S.o:
+ ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+
+.S.po:
+ ${CPP} -E -DPROF ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+
+.S.so:
+ ${CPP} -E -DPIC ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -k -o ${.TARGET}
+
+.m.po:
+ ${CC} ${CFLAGS} -p -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.m.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.if defined(PROFILE)
+_LIBS=lib${LIB}.a lib${LIB}_p.a
+.else
+_LIBS=lib${LIB}.a
+.endif
+
+.if !defined(NOPIC)
+.if defined(SHLIB_MAJOR) && defined(SHLIB_MINOR)
+_LIBS+=lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}
+.endif
+.if defined(INSTALL_PIC_ARCHIVE)
+_LIBS+=lib${LIB}_pic.a
+.endif
+.endif
+
+.if !defined(PICFLAG)
+PICFLAG=-fpic
+.endif
+
+all: ${_LIBS} # llib-l${LIB}.ln
+
+OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
+
+lib${LIB}.a:: ${OBJS}
+ @echo building standard ${LIB} library
+ @rm -f lib${LIB}.a
+ @${AR} cTq lib${LIB}.a `lorder ${OBJS} | tsort` ${LDADD}
+ ${RANLIB} lib${LIB}.a
+
+POBJS+= ${OBJS:.o=.po}
+lib${LIB}_p.a:: ${POBJS}
+ @echo building profiled ${LIB} library
+ @rm -f lib${LIB}_p.a
+ @${AR} cTq lib${LIB}_p.a `lorder ${POBJS} | tsort` ${LDADD}
+ ${RANLIB} lib${LIB}_p.a
+
+SOBJS+= ${OBJS:.o=.so}
+lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}: ${SOBJS}
+ @echo building shared ${LIB} library \(version ${SHLIB_MAJOR}.${SHLIB_MINOR}\)
+ @rm -f lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}
+ @$(LD) -Bshareable \
+ -o lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} \
+ ${SOBJS} ${LDADD}
+
+lib${LIB}_pic.a:: ${SOBJS}
+ @echo building special pic ${LIB} library
+ @rm -f lib${LIB}_pic.a
+ @${AR} cTq lib${LIB}_pic.a ${SOBJS} ${LDADD}
+ ${RANLIB} lib${LIB}_pic.a
+
+llib-l${LIB}.ln: ${SRCS}
+ ${LINT} -C${LIB} ${CFLAGS} ${.ALLSRC:M*.c}
+
+.if !target(clean)
+clean:
+ rm -f a.out Errs errs mklog ${CLEANFILES} ${OBJS}
+ rm -f lib${LIB}.a llib-l${LIB}.ln
+ rm -f ${POBJS} profiled/*.o lib${LIB}_p.a
+ rm -f ${SOBJS} shared/*.o
+ rm -f lib${LIB}.so.*.* lib${LIB}_pic.a
+.endif
+
+.if !target(cleandir)
+cleandir:
+ rm -f a.out Errs errs mklog ${CLEANFILES} ${OBJS}
+ rm -f lib${LIB}.a llib-l${LIB}.ln
+ rm -f ${.CURDIR}/tags .depend
+ rm -f ${POBJS} profiled/*.o lib${LIB}_p.a
+ rm -f ${SOBJS} shared/*.o
+ rm -f lib${LIB}.so.*.* lib${LIB}_pic.a
+ cd ${.CURDIR}; rm -rf obj;
+.endif
+
+.if defined(SRCS)
+afterdepend:
+ @(TMP=/tmp/_depend$$$$; \
+ sed -e 's/^\([^\.]*\).o[ ]*:/\1.o \1.po \1.so:/' < .depend > $$TMP; \
+ mv $$TMP .depend)
+.endif
+
+.if !target(install)
+.if !target(beforeinstall)
+beforeinstall:
+.endif
+
+realinstall: beforeinstall
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} lib${LIB}.a \
+ ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}.a
+.if defined(PROFILE)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}_p.a ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_p.a
+.endif
+.if !defined(NOPIC)
+.if defined(SHLIB_MAJOR) && defined(SHLIB_MINOR)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} ${DESTDIR}${LIBDIR}
+.endif
+.if defined(INSTALL_PIC_ARCHIVE)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}_pic.a ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_pic.a
+.endif
+.endif
+.if defined(LINKS) && !empty(LINKS)
+ @set ${LINKS}; \
+ while test $$# -ge 2; do \
+ l=${DESTDIR}$$1; \
+ shift; \
+ t=${DESTDIR}$$1; \
+ shift; \
+ echo $$t -\> $$l; \
+ rm -f $$t; \
+ ln $$l $$t; \
+ done; true
+.endif
+
+install: afterinstall
+.if !defined(NOMAN)
+afterinstall: realinstall maninstall
+.else
+afterinstall: realinstall
+.endif
+.endif
+
+.if !target(lint)
+lint:
+.endif
+
+.if !target(tags)
+tags: ${SRCS}
+ -cd ${.CURDIR}; ctags -f /dev/stdout ${.ALLSRC:M*.c} | \
+ sed "s;\${.CURDIR}/;;" > tags
+.endif
+
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.elif !target(maninstall)
+maninstall:
+.endif
+
+.if !target(obj)
+.if defined(NOOBJ)
+obj:
+.else
+obj:
+ @cd ${.CURDIR}; rm -rf obj; \
+ here=`pwd`; dest=/usr/obj`echo $$here | sed 's,^/usr/src,,'`; \
+ echo "$$here -> $$dest"; ln -s $$dest obj; \
+ if test -d /usr/obj -a ! -d $$dest; then \
+ mkdir -p $$dest; \
+ else \
+ true; \
+ fi;
+.endif
+.endif
+
+.include <bsd.dep.mk>
diff --git a/lib/libmalloc/defs.h b/lib/libmalloc/defs.h
new file mode 100644
index 000000000000..0f794f1cee71
--- /dev/null
+++ b/lib/libmalloc/defs.h
@@ -0,0 +1,386 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+/* $Id: defs.h,v 1.1 1994/03/06 22:59:29 nate Exp $ */
+#ifndef __DEFS_H__
+#define __DEFS_H__
+/*
+ * This file includes all relevant include files, and defines various
+ * types and constants. It also defines lots of macros which operate on
+ * the malloc blocks and pointers, to try and keep the ugliness
+ * abstracted away from the source code.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+extern int errno; /* Some errno.h don't declare this */
+
+/*
+ * ANSI defines malloc to return void *, and take size_t as an
+ * argument, while present Unix convention is char * and unsigned int
+ * respectively. This is not ifdef'ed with STDC because you may want to
+ * compile a Unix malloc with an ANSI C compiler or vice versa. Note
+ * that sys/types.h on BSD Unix systems defines size_t to be int or
+ * long. memsize_t is for routines that expect int in Unix and size_t
+ * in ANSI.
+ */
+#ifdef STDHEADERS
+# define univptr_t void *
+# define memsize_t size_t
+#else /* ! STDHEADERS */
+# define univptr_t char *
+# define size_t unsigned int
+# define memsize_t int
+#endif /* STDHEADERS */
+
+#ifndef REGISTER
+# ifdef __GNUC__
+ /* gcc probably does better register allocation than I do */
+# define REGISTER
+# else
+# define REGISTER register
+# endif
+#endif
+
+/*
+ * Just in case you want an ANSI malloc without an ANSI compiler, or
+ * ANSI includes
+ */
+#if defined(STDHEADERS) && !defined(offsetof) && !defined(__FreeBSD__)
+# define size_t unsigned long
+#endif
+
+#if defined(__STDC__)
+# define proto(x) x
+#else
+# define proto(x) ()
+# define const
+# define volatile
+#endif
+
+#include "externs.h"
+#include "assert.h"
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#ifdef __STDC__
+# include <limits.h>
+# ifndef BITSPERBYTE
+# define BITSPERBYTE CHAR_BIT
+# endif
+#else
+# include <values.h>
+#endif
+#include "align.h" /* Needs BITSPERBYTE */
+
+/*
+ * We assume that FREE is a 0 bit, and the for a free block,
+ * SIZE(p) == SIZEMASK(p) as an optimization to avoid an unnecessary
+ * masking operation with SIZEMASK. See FREESIZE below. Or'ing with
+ * ALLOCED should turn on the high bit, And'ing with SIZEMASK should
+ * turn it off.
+ */
+
+#define FREE ((size_t) 0)
+#define ALLOCED (HIBITSZ)
+#define SIZEMASK (~HIBITSZ)
+
+union word { /* basic unit of storage */
+ size_t size; /* size of this block + 1 bit status */
+ union word *next; /* next free block */
+ union word *prev; /* prev free block */
+ univptr_t ptr; /* stops lint complaining, keeps alignment */
+ char c;
+ int i;
+ char *cp;
+ char **cpp;
+ int *ip;
+ int **ipp;
+ ALIGN; /* alignment stuff - wild fun */
+};
+
+typedef union word Word;
+
+/*
+ * WARNING - Many of these macros are UNSAFE because they have multiple
+ * evaluations of the arguments. Use with care, avoid side-effects.
+ */
+/*
+ * These macros define operations on a pointer to a block. The zero'th
+ * word of a block is the size field, where the top bit is 1 if the
+ * block is allocated. This word is also referred to as the starting tag.
+ * The last word of the block is identical to the zero'th word of the
+ * block and is the end tag. IF the block is free, the second last word
+ * is a pointer to the next block in the free list (a doubly linked list
+ * of all free blocks in the heap), and the third from last word is a
+ * pointer to the previous block in the free list. HEADERWORDS is the
+ * number of words before the pointer in the block that malloc returns,
+ * TRAILERWORDS is the number of words after the returned block. Note
+ * that the zero'th and the last word MUST be the boundary tags - this
+ * is hard-wired into the algorithm. Increasing HEADERWORDS or
+ * TRAILERWORDS suitably should be accompanied by additional macros to
+ * operate on those words. The routines most likely to be affected are
+ * malloc/realloc/free/memalign/mal_verify/mal_heapdump.
+ */
+/*
+ * There are two ways we can refer to a block -- by pointing at the
+ * start tag, or by pointing at the end tag. For reasons of efficiency
+ * and performance, free blocks are always referred to by the end tag,
+ * while allocated blocks are usually referred to by the start tag.
+ * Accordingly, the following macros indicate the type of their argument
+ * by using either 'p', 'sp', or 'ep' to indicate a pointer. 'p' means
+ * the pointer could point at either the start or end tag. 'sp' means it
+ * must point at a start tag for that macro to work correctly, 'ep'
+ * means it must point at the end tag. Usually, macros operating on free
+ * blocks (NEXT, PREV, VALID_PREV_PTR, VALID_NEXT_PTR) take 'ep', while
+ * macros operating on allocated blocks (REALSIZE, MAGIC_PTR,
+ * SET_REALSIZE) take 'sp'. The size field may be validated using either
+ * VALID_START_SIZE_FIELD for an 'sp' or VALID_END_SIZE_FIELD for an
+ * 'ep'.
+ */
+/*
+ * SIZE, SIZEFIELD and TAG are valid for allocated and free blocks,
+ * REALSIZE is valid for allocated blocks when debugging, and NEXT and
+ * PREV are valid for free blocks. We could speed things up by making
+ * the free list singly linked when not debugging - the double link are
+ * just so we can check for pointer validity. (PREV(NEXT(ep)) == ep and
+ * NEXT(PREV(ep)) == ep). FREESIZE is used only to get the size field
+ * from FREE blocks - in this implementation, free blocks have a tag
+ * bit of 0 so no masking is necessary to operate on the SIZEFIELD when
+ * a block is free. We take advantage of that as a minor optimization.
+ */
+#define SIZEFIELD(p) ((p)->size)
+#define SIZE(p) ((size_t) (SIZEFIELD(p) & SIZEMASK))
+#define ALLOCMASK(n) ((n) | ALLOCED)
+#define FREESIZE(p) SIZEFIELD(p)
+/*
+ * FREEMASK should be (n) & SIZEMASK, but since (n) will always have
+ * the hi bit off after the conversion from bytes requested by the user
+ * to words.
+ */
+#define FREEMASK(n) (n)
+#define TAG(p) (SIZEFIELD(p) & ~SIZEMASK)
+
+#ifdef DEBUG
+# define REALSIZE(sp) (((sp)+1)->size)
+#endif /* DEBUG */
+
+#define NEXT(ep) (((ep)-1)->next)
+#define PREV(ep) (((ep)-2)->prev)
+
+/*
+ * HEADERWORDS is the real block header in an allocated block - the
+ * free block header uses extra words in the block itself
+ */
+#ifdef DEBUG
+# define HEADERWORDS 2 /* Start boundary tag + real size in bytes */
+#else /* ! DEBUG */
+# define HEADERWORDS 1 /* Start boundary tag */
+#endif /* DEBUG */
+
+#define TRAILERWORDS 1
+
+#define FREEHEADERWORDS 1 /* Start boundary tag */
+
+#define FREETRAILERWORDS 3 /* next and prev, end boundary tag */
+
+#define ALLOC_OVERHEAD (HEADERWORDS + TRAILERWORDS)
+#define FREE_OVERHEAD (FREEHEADERWORDS + FREETRAILERWORDS)
+
+/*
+ * The allocator views memory as a list of non-contiguous arenas. (If
+ * successive sbrks() return contiguous blocks, they are colaesced into
+ * one arena - if a program never calls sbrk() other than malloc(),
+ * then there should only be one arena. This malloc will however
+ * happily coexist with other allocators calling sbrk() and uses only
+ * the blocks given to it by sbrk. It expects the same courtesy from
+ * other allocators. The arenas are chained into a linked list using
+ * the first word of each block as a pointer to the next arena. The
+ * second word of the arena, and the last word, contain fake boundary
+ * tags that are permanantly marked allocated, so that no attempt is
+ * made to coalesce past them. See the code in dumpheap for more info.
+ */
+#define ARENASTART 2 /* next ptr + fake start tag */
+
+#ifdef DEBUG
+ /*
+ * 1 for prev link in free block - next link is absorbed by header
+ * REALSIZE word
+ */
+# define FIXEDOVERHEAD (1 + ALLOC_OVERHEAD)
+#else /* ! DEBUG */
+ /* 1 for prev link, 1 for next link, + header and trailer */
+# define FIXEDOVERHEAD (2 + ALLOC_OVERHEAD)
+#endif /* DEBUG */
+
+/*
+ * Check that pointer is safe to dereference i.e. actually points
+ * somewhere within the heap and is properly aligned.
+ */
+#define PTR_IN_HEAP(p) \
+ ((p) > _malloc_loword && (p) < _malloc_hiword && \
+ ALIGNPTR(p) == ((univptr_t) (p)))
+
+/* Check that the size field is valid */
+#define VALID_START_SIZE_FIELD(sp) \
+ (PTR_IN_HEAP((sp) + SIZE(sp) - 1) && \
+ SIZEFIELD(sp) == SIZEFIELD((sp) + SIZE(sp) - 1))
+
+#define VALID_END_SIZE_FIELD(ep) \
+ (PTR_IN_HEAP((ep) - SIZE(ep) + 1) && \
+ SIZEFIELD(ep) == SIZEFIELD((ep) - SIZE(ep) + 1))
+
+
+#define ulong unsigned long
+
+#ifdef DEBUG
+ /*
+ * Byte that is stored at the end of each block if the requested size
+ * of the block is not a multiple of sizeof(Word). (If it is a multiple
+ * of sizeof(Word), then we don't need to put the magic because the
+ * endboundary tag will be corrupted and the tests that check the
+ * validity of the boundary tag should detect it
+ */
+# ifndef u_char
+# define u_char unsigned char
+# endif /* u_char */
+
+# define MAGIC_BYTE ((u_char) '\252')
+ /*
+ * Check if size of the block is identical to requested size. Typical
+ * tests will be of the form DONT_NEED_MAGIC(p) || something for
+ * short-circuited protection, because blocks where DONT_NEED_MAGIC is
+ * true will be tested for boundary tag detection so we don't need the
+ * magic byte at the end.
+ */
+# define DONT_NEED_MAGIC(sp) \
+ (REALSIZE(sp) == ((SIZE(sp) - ALLOC_OVERHEAD) * sizeof(Word)))
+
+ /* Note that VALID_REALSIZE must not be used if DONT_NEED_MAGIC is true */
+# define VALID_REALSIZE(sp) \
+ (REALSIZE(sp) < ((SIZE(sp) - ALLOC_OVERHEAD)*sizeof(Word)))
+
+ /* Location of the magic byte */
+# define MAGIC_PTR(sp) ((u_char *)((sp) + HEADERWORDS) + REALSIZE(sp))
+
+ /*
+ * malloc code should only use the next two macros SET_REALSIZE and
+ * VALID_MAGIC, since they are the only ones which have non-DEBUG
+ * (null) alternatives
+ */
+
+ /* Macro sets the realsize of a block if necessary */
+# define SET_REALSIZE(sp, n) \
+ (REALSIZE(sp) = (n), \
+ DONT_NEED_MAGIC(sp) || (*MAGIC_PTR(sp) = MAGIC_BYTE))
+
+ /* Macro tests that the magic byte is valid if it exists */
+# define VALID_MAGIC(sp) \
+ (DONT_NEED_MAGIC(sp) || \
+ (VALID_REALSIZE(sp) && (*MAGIC_PTR(sp) == MAGIC_BYTE)))
+
+#else /* ! DEBUG */
+# define SET_REALSIZE(sp, n)
+# define VALID_MAGIC(sp) (1)
+#endif /* DEBUG */
+
+/*
+ * Check that a free list ptr points to a block with something pointing
+ * back. This is the only reason we use a doubly linked free list.
+ */
+#define VALID_NEXT_PTR(ep) (PTR_IN_HEAP(NEXT(ep)) && PREV(NEXT(ep)) == (ep))
+#define VALID_PREV_PTR(ep) (PTR_IN_HEAP(PREV(ep)) && NEXT(PREV(ep)) == (ep))
+
+/*
+ * quick bit-arithmetic to check a number (including 1) is a power of two.
+ */
+#define is_power_of_2(x) ((((x) - 1) & (x)) == 0)
+
+/*
+ * An array to try and keep track of the distribution of sizes of
+ * malloc'ed blocks
+ */
+#ifdef PROFILESIZES
+# define MAXPROFILESIZE 2*1024
+# define COUNTSIZE(nw) (_malloc_scount[((nw) < MAXPROFILESIZE) ? (nw) : 0]++)
+#else
+# define COUNTSIZE(nw)
+#endif
+
+#define DEF_SBRKUNITS 1024
+
+#ifndef USESTDIO
+ /*
+ * Much better not to use stdio - stdio calls malloc() and can
+ * therefore cause problems when debugging heap corruption. However,
+ * there's no guaranteed way to turn off buffering on a FILE pointer in
+ * ANSI. This is a vile kludge!
+ */
+# define fputs(s, f) write(fileno(f), (s), strlen(s))
+# define setvbuf(f, s, n, l) __nothing()
+# define fflush(f) __nothing()
+#endif /* USESTDIO */
+
+#ifdef TRACE
+ /*
+ * Prints a trace string. For convenience, x is an
+ * sprintf(_malloc_statsbuf, ...) or strcpy(_malloc_statsbuf, ...);
+ * something which puts the appropriate text to be printed in
+ * _malloc_statsbuf - ugly, but more convenient than making x a string.
+ */
+# define PRTRACE(x) \
+ if (_malloc_tracing) { \
+ (void) x; \
+ (void) fputs(_malloc_statsbuf, _malloc_statsfile); \
+ } else \
+ _malloc_tracing += 0
+#else
+# define PRTRACE(x)
+#endif
+
+#ifdef DEBUG
+# define CHECKHEAP() \
+ if (_malloc_debugging >= 2) \
+ (void) mal_verify(_malloc_debugging >= 3); \
+ else \
+ _malloc_debugging += 0
+#else
+# define CHECKHEAP()
+#endif
+
+#define FREEMAGIC '\125'
+
+/*
+ * Memory functions but in words. We just call memset/memcpy, and hope
+ * that someone has optimized them. If you are on pure 4.2BSD, either
+ * redefine these in terms of bcopy/your own memcpy, or
+ * get the functions from one of 4.3src/Henry Spencer's strings
+ * package/C News src
+ */
+#define MEMSET(p, c, n) \
+ (void) memset((univptr_t) (p), (c), (memsize_t) ((n) * sizeof(Word)))
+#define MEMCPY(p1, p2, n) \
+ (void) memcpy((univptr_t) (p1), (univptr_t) (p2), \
+ (memsize_t) ((n) * sizeof(Word)))
+
+
+#ifdef DEBUG
+# define DMEMSET(p, n) MEMSET((p), FREEMAGIC, (n))
+#else
+# define DMEMSET(p, n)
+#endif
+
+/*
+ * Thanks to Hugh Redelmeier for pointing out that an rcsid is "a
+ * variable accessed in a way not obvious to the compiler", so should
+ * be called volatile. Amazing - a use for const volatile...
+ */
+#ifndef RCSID /* define RCSID(x) to nothing if don't want the rcs headers */
+# ifndef lint
+# define RCSID(x) static const volatile char *rcsid = x ;
+# else
+# define RCSID(x)
+# endif
+#endif
+
+#endif /* __DEFS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/dumpheap.c b/lib/libmalloc/dumpheap.c
new file mode 100644
index 000000000000..e75ba8e8f279
--- /dev/null
+++ b/lib/libmalloc/dumpheap.c
@@ -0,0 +1,107 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: dumpheap.c,v 1.1 1994/03/06 22:59:30 nate Exp $")
+
+/*
+ * Same as malloc_verify except that it prints the heap as it goes
+ * along. Some would argue that the printout routine should not have
+ * the ASSERTS, and should print a corrupt heap as well.
+ * Unfortunately, if any of those ASSERTs is false, this routine could
+ * wander off into the sunset because of corrupt tags. I have relaxed
+ * the tests for free list pointers because this routine doesn't need
+ * them so it just whines
+ */
+void
+mal_heapdump(fd)
+FILE *fd;
+{
+ REGISTER Word *ptr;
+ REGISTER Word *blk;
+ REGISTER Word *blkend;
+ char buf[512]; /* long enough for the sprintfs below */
+
+ if (_malloc_loword == NULL) { /* Nothing malloc'ed yet */
+ (void) fputs("Null heap - nothing malloc'ed yet\n", fd);
+ return;
+ }
+
+ (void) fputs("Heap printout:\n", fd);
+ (void) sprintf(buf, "Rover pointer is 0x%lx\n", (ulong) _malloc_rover);
+ (void) fputs(buf, fd);
+ if(!(_malloc_rover == NULL
+ || PTR_IN_HEAP(_malloc_rover)
+ || VALID_END_SIZE_FIELD(_malloc_rover)
+ || VALID_NEXT_PTR(_malloc_rover)
+ || VALID_PREV_PTR(_malloc_rover)))
+ (void) fputs("corrupt Rover pointer\n", fd);
+ for(ptr = _malloc_mem; ptr != NULL; ptr = ptr->next) {
+ /* print the arena */
+ (void) sprintf(buf, "Arena from 0x%lx to 0x%lx, %lu (0x%lx) words\n",
+ (ulong) ptr, (ulong) (ptr + SIZE(ptr+1)),
+ (ulong) SIZE(ptr+1)+1, (ulong) SIZE(ptr+1)+1);
+ (void) fputs(buf, fd);
+ (void) sprintf(buf, "Next arena is 0x%lx\n", (ulong)ptr->next);
+ (void) fputs(buf, fd);
+ (void) fflush(fd);
+ ASSERT(SIZEFIELD(ptr+1) == SIZEFIELD(ptr + SIZE(ptr+1)),
+ "corrupt malloc arena");
+ blkend = ptr + SIZE(ptr + 1);
+ for(blk = ptr + ARENASTART; blk < blkend; blk += SIZE(blk)) {
+ (void) sprintf(buf, " %s blk: 0x%lx to 0x%lx, %lu (0x%lx) words",
+ TAG(blk) == FREE ? "Free" : "Allocated",
+ (ulong) blk, (ulong) (blk+SIZE(blk)-1),
+ (ulong) SIZE(blk), (ulong) SIZE(blk));
+ (void) fputs(buf, fd);
+ (void) fflush(fd);
+ ASSERT(PTR_IN_HEAP(blk), "corrupt pointer encountered");
+ if (TAG(blk) == FREE) {
+ int i, n;
+ char *cp;
+
+ (void) sprintf(buf, " next=0x%lx, prev=0x%lx\n",
+ (ulong) NEXT(blk + FREESIZE(blk) - 1),
+ (ulong) PREV(blk + FREESIZE(blk) - 1));
+ (void) fputs(buf, fd);
+ /* Make sure free block is filled with FREEMAGIC */
+ n = (SIZE(blk) - FREE_OVERHEAD) *
+ sizeof(Word);
+ cp = (char *) (blk + FREEHEADERWORDS);
+#ifdef DEBUG
+ for (i = 0; i < n; i++, cp++) {
+ if (*cp != FREEMAGIC) {
+ (void) fputs(
+ " ** free block changed after being freed.\n", fd);
+ break;
+ }
+ }
+#endif
+ } else {
+#ifdef DEBUG
+ (void) sprintf(buf, " really %lu bytes\n", (ulong) REALSIZE(blk));
+ (void) fputs(buf, fd);
+#else
+ (void) fputs("\n", fd);
+#endif
+ }
+ (void) fflush(fd);
+ ASSERT(VALID_START_SIZE_FIELD(blk),
+ "corrupt SIZE field encountered in mal_dumpheap()");
+ if (TAG(blk) == FREE) {
+ if( ! VALID_NEXT_PTR(blk + FREESIZE(blk) - 1))
+ (void) fputs(" ** bad next pointer\n", fd);
+ if( ! VALID_PREV_PTR(blk + FREESIZE(blk) - 1))
+ (void) fputs(" ** bad prev pointer\n", fd);
+ } else {
+ if ( ! VALID_MAGIC(blk))
+ (void) fputs(" ** end of block overwritten\n", fd);
+ }
+ }
+ }
+ (void) fputs("==============\n", fd);
+ (void) fflush(fd);
+}
diff --git a/lib/libmalloc/emalloc.c b/lib/libmalloc/emalloc.c
new file mode 100644
index 000000000000..13a7b9ab0244
--- /dev/null
+++ b/lib/libmalloc/emalloc.c
@@ -0,0 +1,69 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: emalloc.c,v 1.1 1994/03/06 22:59:31 nate Exp $")
+
+/*
+ * malloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+emalloc(nbytes)
+size_t nbytes;
+{
+ univptr_t cp = malloc(nbytes);
+
+ if (cp == 0) {
+ (void) fputs("No more memory for emalloc\n", stderr);
+#ifdef DEBUG
+ (void) fflush(stderr);
+ (void) fflush(_malloc_statsfile);
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+ }
+
+ return(cp);
+}
+
+/*
+ * realloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+erealloc(ptr, nbytes)
+univptr_t ptr;
+size_t nbytes;
+{
+ univptr_t cp = realloc(ptr, nbytes);
+
+ if (cp == 0) {
+ (void) fputs("No more memory for erealloc\n", stderr);
+#ifdef DEBUG
+ (void) fflush(stderr);
+ (void) fflush(_malloc_statsfile);
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+ }
+
+ return(cp);
+}
+
+/*
+ * calloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+ecalloc(nelem, sz)
+size_t nelem, sz;
+{
+ size_t nbytes = nelem * sz;
+ univptr_t cp = emalloc(nbytes);
+
+ (void) memset((univptr_t) cp, 0, (memsize_t) nbytes);
+ return(cp);
+}
diff --git a/lib/libmalloc/externs.h b/lib/libmalloc/externs.h
new file mode 100644
index 000000000000..77c0b19e014c
--- /dev/null
+++ b/lib/libmalloc/externs.h
@@ -0,0 +1,113 @@
+#ifndef EXTERNS_H__
+#define EXTERNS_H__
+
+/* Lots of ugliness as we cope with non-standardness */
+
+#ifdef STDHEADERS
+ /* if we have properly prototyped standard headers, use them */
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdio.h>
+# include <string.h>
+# include <unistd.h>
+
+#else /* ! STDHEADERS */
+
+/* # include <sys/types.h> */
+#define caddr_t char *
+
+/*
+ * Malloc definitions from General Utilities <stdlib.h>. Note that we
+ * disagree with Berkeley Unix on the return type of free/cfree.
+ */
+extern univptr_t malloc proto((size_t));
+extern univptr_t calloc proto((size_t, size_t));
+extern univptr_t realloc proto((univptr_t, size_t));
+extern void free proto((univptr_t));
+
+/* General Utilities <stdlib.h> */
+
+extern void abort proto((void));
+extern void exit proto((int));
+extern char *getenv proto((const char *));
+
+/*
+ * Input/Output <stdio.h> Note we disagree with Berkeley Unix on
+ * sprintf().
+ */
+
+#if 0 /* can't win with this one */
+extern int sprintf proto((char *, const char *, ...));
+#endif
+
+extern int fputs proto((const char *, FILE *));
+extern int fflush proto((FILE *));
+extern int setvbuf proto((FILE *, char *, int, memsize_t));
+
+/* Character Handling: <string.h> */
+
+extern univptr_t memset proto((univptr_t, int, memsize_t));
+
+#ifndef __GNUC__ /* clash with builtin, garn */
+extern univptr_t memcpy proto((univptr_t, const univptr_t, memsize_t));
+#endif
+
+extern char *strcpy proto((char *, const char *));
+extern memsize_t strlen proto((const char *));
+
+/* UNIX -- unistd.h */
+extern int write proto((int /*fd*/, const char * /*buf*/, int /*nbytes*/));
+extern int open proto((const char */*path*/, int /*flags*/, ...));
+
+#endif /* STDHEADERS */
+
+#ifdef _SC_PAGESIZE /* Solaris 2.x, SVR4? */
+# define getpagesize() sysconf(_SC_PAGESIZE)
+#else /* ! _SC_PAGESIZE */
+# ifdef _SC_PAGE_SIZE /* HP, IBM */
+# define getpagesize() sysconf(_SC_PAGE_SIZE)
+# else /* ! _SC_PAGE_SIZE */
+# ifndef getpagesize
+ extern int getpagesize proto((void));
+# endif /* getpagesize */
+# endif /* _SC_PAGE_SIZE */
+#endif /* _SC_PAGESIZE */
+
+extern caddr_t sbrk proto((int));
+
+/* Backwards compatibility with BSD/Sun -- these are going to vanish one day */
+extern univptr_t valloc proto((size_t));
+extern univptr_t memalign proto((size_t, size_t));
+extern void cfree proto((univptr_t));
+
+/* Malloc definitions - my additions. Yuk, should use malloc.h properly!! */
+extern univptr_t emalloc proto((size_t));
+extern univptr_t ecalloc proto((size_t, size_t));
+extern univptr_t erealloc proto((univptr_t, size_t));
+extern char *strdup proto((const char *));
+extern char *strsave proto((const char *));
+extern void mal_debug proto((int));
+extern void mal_dumpleaktrace proto((FILE *));
+extern void mal_heapdump proto((FILE *));
+extern void mal_leaktrace proto((int));
+extern void mal_mmap proto((char *));
+extern void mal_sbrkset proto((int));
+extern void mal_slopset proto((int));
+extern void mal_statsdump proto((FILE *));
+extern void mal_setstatsfile proto((FILE *));
+extern void mal_trace proto((int));
+extern int mal_verify proto((int));
+
+/* Internal definitions */
+extern int __nothing proto((void));
+extern univptr_t _mal_sbrk proto((size_t));
+extern univptr_t _mal_mmap proto((size_t));
+
+#ifdef HAVE_MMAP
+extern int madvise proto((caddr_t, size_t, int));
+#ifndef __FreeBSD__
+extern caddr_t mmap proto((caddr_t, size_t, int, int, int, off_t));
+#endif /* __FreeBSD__ */
+#endif /* HAVE_MMAP */
+
+#endif /* EXTERNS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/getmem.c b/lib/libmalloc/getmem.c
new file mode 100644
index 000000000000..4140c6da4cc3
--- /dev/null
+++ b/lib/libmalloc/getmem.c
@@ -0,0 +1,108 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: getmem.c,v 1.1 1994/03/06 22:59:42 nate Exp $")
+
+/* gets memory from the system via the sbrk() system call. Most Un*xes */
+univptr_t
+_mal_sbrk(nbytes)
+size_t nbytes;
+{
+ return sbrk((int) nbytes);
+}
+
+/*
+ * gets memory from the system via mmaping a file. This was written for SunOS
+ * versions greater than 4.0. The filename is specified by the environment
+ * variable CSRIMALLOC_MMAPFILE or by the call to mal_mmapset(). Using this
+ * instead of sbrk() has the advantage of bypassing the swap system, allowing
+ * processes to run with huge heaps even on systems configured with small swap
+ * space.
+ */
+static char *mmap_filename;
+
+#ifdef HAVE_MMAP
+/* Sun gets size_t wrong, and these follow, thanks to my #defines! */
+#undef caddr_t
+#undef size_t
+#undef u_char
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+univptr_t
+_mal_mmap(nbytes)
+size_t nbytes;
+{
+ static struct {
+ int i_fd;
+ caddr_t i_data;
+ caddr_t i_end;
+ size_t i_size;
+ size_t i_alloced;
+ } mmf;
+ struct stat stbuf;
+
+ if (mmf.i_data != NULL) {
+ /* Already initialized & mmaped the file */
+ univptr_t p = mmf.i_data + mmf.i_alloced;
+
+ if ((char *) p + nbytes > mmf.i_end) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ mmf.i_alloced += nbytes;
+ return p;
+ }
+
+ /*
+ * This code is run the first time the function is called, it opens
+ * the file and mmaps the
+ */
+ if (mmap_filename == NULL) {
+ mmap_filename = getenv("CSRIMALLOC_MMAPFILE");
+ if (mmap_filename == NULL) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ }
+
+ mmf.i_fd = open(mmap_filename, O_RDWR, 0666);
+ if (mmf.i_fd < 0 || fstat(mmf.i_fd, &stbuf) < 0)
+ return (univptr_t) -1;
+ if (stbuf.st_size < nbytes) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ mmf.i_size = stbuf.st_size;
+ mmf.i_data = mmap((caddr_t) 0, mmf.i_size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, mmf.i_fd, (off_t) 0);
+ if (mmf.i_data == (caddr_t) -1)
+ return (univptr_t) -1;
+ mmf.i_end = mmf.i_data + mmf.i_size;
+ mmf.i_alloced = nbytes;
+ /* Advise vm system of random access pattern */
+ (void) madvise(mmf.i_data, mmf.i_size, MADV_RANDOM);
+ return mmf.i_data;
+}
+#else /* !HAVE_MMAP */
+univptr_t
+_mal_mmap(nbytes)
+size_t nbytes;
+{
+ return (univptr_t) -1;
+}
+#endif /* HAVE_MMAP */
+
+void
+mal_mmap(fname)
+char *fname;
+{
+ _malloc_memfunc = _mal_mmap;
+ mmap_filename = fname;
+}
diff --git a/lib/libmalloc/globals.c b/lib/libmalloc/globals.c
new file mode 100644
index 000000000000..b1adf3d3f5a2
--- /dev/null
+++ b/lib/libmalloc/globals.c
@@ -0,0 +1,87 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*
+ * All globals are names starting with _malloc, which should not clash
+ * with anything else.
+ */
+/*
+ * Remember to initialize the variable in globals.c if you want, and
+ * provide an alternative short name in globrename.h
+ */
+#include "globrename.h"
+#include "version.c"
+
+/*
+ * _malloc_minchunk is the minimum number of units that a block can be
+ * cut down to. If the difference between the required block size, and
+ * the first available block is greater than _malloc_minchunk, the
+ * block is chopped into two pieces, else the whole block is returned.
+ * The larger this is, the less fragmentation there will be, but the
+ * greater the waste. The actual minimum size of a block is therefore
+ * _malloc_minchunk*sizeof(Word) This consists of one word each for the
+ * boundary tags, one for the next and one for the prev pointers in a
+ * free block.
+ */
+size_t _malloc_minchunk = FIXEDOVERHEAD;
+
+/*
+ * _malloc_rover is the pointer that points 'someplace' in the free
+ * list. We start our search for a block from _malloc_rover, thus
+ * starting the search at a different place everytime, rather than at
+ * the start of the list. This improves performance considerably, sez
+ * Knuth
+ */
+Word *_malloc_rover = NULL;
+Word *_malloc_hiword = NULL;
+Word *_malloc_loword = NULL;
+
+/*
+ * _malloc_sbrkunits is the multiple of sizeof(Word) to actually use in
+ * sbrk() calls - _malloc_sbrkunits should be large enough that sbrk
+ * isn't called too often, but small enough that any program that
+ * mallocs a few bytes doesn't end up being very large. I've set it to
+ * 1K resulting in a sbrk'ed size of 8K. This is (coincidentally!) the
+ * pagesize on Suns. I think that this seems a reasonable number for
+ * modern programs that malloc heavily. For small programs, you may
+ * want to set it to a lower number.
+ */
+size_t _malloc_sbrkunits = DEF_SBRKUNITS;
+
+/*
+ * optimization of keeping total amount available, so we know to sbrk
+ * without searching list. No point searching list unless we have a
+ * fair chance of success. Ideally, we'd keep the size of the largest
+ * block available and a pointer to it, so we could check definitely if
+ * we had enough space. But that is too much housekeeping - we'd have to
+ * update that on all mallocs and frees too. (Updating
+ * _malloc_totalavail is easier)
+ */
+size_t _malloc_totalavail = 0;
+
+Word *_malloc_mem = NULL;
+
+/*
+ * Do not call any output routine other than fputs() - use sprintf() if
+ * you want to format something before printing. We don't want stdio
+ * calling malloc() if we can help it
+ */
+int _malloc_tracing = 0; /* No tracing */
+FILE *_malloc_statsfile = stderr;
+char _malloc_statsbuf[128];
+
+int _malloc_leaktrace = 0;
+
+#ifdef PROFILESIZES
+int _malloc_scount[MAXPROFILESIZE];
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+int _malloc_debugging = 0;
+#endif /* DEBUG */
+
+univptr_t (* _malloc_memfunc) proto((size_t)) = _mal_sbrk;
diff --git a/lib/libmalloc/globals.h b/lib/libmalloc/globals.h
new file mode 100644
index 000000000000..4d3327edd81f
--- /dev/null
+++ b/lib/libmalloc/globals.h
@@ -0,0 +1,43 @@
+/* $Id: globals.h,v 1.1 1994/03/06 22:59:44 nate Exp $ */
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+/*
+ * Remember to initialize the variable in globals.c if you want, and
+ * provide an alternative short name in globrename.h
+ */
+#include "globrename.h"
+
+extern size_t _malloc_minchunk;
+
+extern Word *_malloc_rover;
+extern Word *_malloc_hiword;
+extern Word *_malloc_loword;
+
+extern size_t _malloc_sbrkunits;
+
+extern size_t _malloc_totalavail;
+
+extern Word *_malloc_mem;
+
+extern int _malloc_tracing; /* No tracing */
+extern FILE *_malloc_statsfile;
+extern char _malloc_statsbuf[];
+
+extern int _malloc_leaktrace;
+
+#ifdef PROFILESIZES
+extern int _malloc_scount[];
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+extern int _malloc_debugging;
+#endif /* DEBUG */
+
+extern univptr_t (* _malloc_memfunc) proto((size_t));
+
+#endif /* __GLOBALS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/globrename.h b/lib/libmalloc/globrename.h
new file mode 100644
index 000000000000..9739f4f3ac6a
--- /dev/null
+++ b/lib/libmalloc/globrename.h
@@ -0,0 +1,46 @@
+/* $Id: globrename.h,v 1.1 1994/03/06 22:59:45 nate Exp $ */
+#ifndef __GLOBALRENAME_H__
+#define __GLOBALRENAME_H__
+/*
+ * Renaming all external symbols that are internal to the malloc to be
+ * unique within 6 characters for machines whose linkers just can't keep
+ * up. We hope the cpp is smart enough - if not, get GNU cccp or the
+ * cpp that comes with X Windows Version 11 Release 3.
+ */
+#ifdef SHORTNAMES
+#define _malloc_minchunk __MAL1_minchunk
+
+#define _malloc_rover __MAL2_rover
+#define _malloc_hiword __MAL3_hiword
+#define _malloc_loword __MAL4_loword
+
+#define _malloc_sbrkunits __MAL5_sbrkunits
+
+#define _malloc_totalavail __MAL6_totalavail
+
+#define _malloc_mem __MAL7_mem
+
+#define _malloc_tracing __MAL8_tracing
+#define _malloc_statsfile __MAL9_statsfile
+#define _malloc_statsbuf __MALA_statsbuf
+
+#define _malloc_leaktrace __MALB_leaktrace
+
+#ifdef PROFILESIZES
+#define _malloc_scount __MALC_scount
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+#define _malloc_debugging __MALD_debugging
+#endif /* DEBUG */
+#define _malloc_version __MALE_version
+
+#define _malloc_memfunc __MALF_memfunc
+
+#endif /* SHORTNAMES */ /* Do not add anything after this line */
+#endif /* __GLOBALRENAME_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/leak.c b/lib/libmalloc/leak.c
new file mode 100644
index 000000000000..b4014582b32e
--- /dev/null
+++ b/lib/libmalloc/leak.c
@@ -0,0 +1,160 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "sptree.h"
+
+RCSID("$Id: leak.c,v 1.1 1994/03/06 22:59:46 nate Exp $")
+
+/*
+ * These routines provide an interface for tracing memory leaks. The
+ * user can turn on leak tracing at any time by calling
+ * mal_leaktrace(1), after which every block allocated by
+ * _malloc()/_calloc()/_realloc()/_valloc()/_memalign() has a string
+ * (containing the filename and linenumber of the routine invoking it)
+ * stored in a database. When _free()/_cfree() is called on that block,
+ * the record is deleted from the database. The user can call
+ * mal_dumpleaktrace() to show the list of blocks allocated, and
+ * where they were allocated. The location of leaks can usually be
+ * detected from this.
+ */
+/*
+ * The tree implementation used to store the blocks is a splay-tree,
+ * using an implementation in C by Dave Brower (daveb@rtech.uucp),
+ * translated from Douglas Jones' original Pascal. However, any data
+ * structure that permits insert(), delete() and traverse()/apply() of
+ * key, value pairs should be suitable. Only this file needs to be
+ * changed.
+ */
+static SPTREE *sp = NULL;
+
+/*
+ * num is a sequence number, incremented for ever block. min_num gets
+ * set to num after every dumpleaktrace - subsequent dumps do not print
+ * any blocks with sequence numbers less than min_num
+ */
+static unsigned long min_num = 0;
+static unsigned long num = 0;
+
+/*
+ * These are used by mal_contents to count number of allocated blocks and the
+ * number of bytes allocated. Better way to do this is to walk the heap
+ * rather than scan the splay tree.
+ */
+static unsigned long nmallocs;
+static unsigned long nbytes;
+
+static FILE *dumpfd = NULL;
+
+/*
+ * Turns recording of FILE and LINE number of each call to
+ * malloc/free/realloc/calloc/cfree/memalign/valloc on (if value != 0)
+ * or off, (if value == 0)
+ */
+void
+mal_leaktrace(value)
+int value;
+{
+ _malloc_leaktrace = (value != 0);
+ if (sp == NULL)
+ sp = __spinit();
+}
+
+/*
+ * The routine which actually does the printing. I know it is silly to
+ * print address in decimal, but sort doesn't read hex, so sorting the
+ * printed data by address is impossible otherwise. Urr. The format is
+ * FILE:LINE: sequence_number address_in_decimal (address_in_hex)
+ */
+void
+__m_prnode(spblk)
+SPBLK *spblk;
+{
+ if ((unsigned long) spblk->datb < min_num)
+ return;
+ (void) sprintf(_malloc_statsbuf, "%s%8lu %8lu(0x%08lx)\n",
+ (char *) spblk->data, (unsigned long) spblk->datb,
+ (unsigned long) spblk->key, (unsigned long) spblk->key);
+ (void) fputs(_malloc_statsbuf, dumpfd);
+}
+
+/*
+ * Dumps all blocks which have been recorded.
+ */
+void
+mal_dumpleaktrace(fd)
+FILE *fd;
+{
+ dumpfd = fd;
+ __spscan(__m_prnode, (SPBLK *) NULL, sp);
+ (void) fflush(dumpfd);
+ min_num = num;
+}
+
+/*
+ * Inserts a copy of a string keyed by the address addr into the tree
+ * that stores the leak trace information. The string is presumably of
+ * the form "file:linenumber:". It also stores a sequence number that
+ * gets incremented with each call to this routine.
+ */
+void
+__m_install_record(addr, s)
+univptr_t addr;
+const char *s;
+{
+ num++;
+ (void) __spadd(addr, strsave(s), (char *) num, sp);
+}
+
+/* Deletes the record keyed by addr if it exists */
+void
+__m_delete_record(addr)
+univptr_t addr;
+{
+ SPBLK *result;
+
+ if ((result = __splookup(addr, sp)) != NULL) {
+ free(result->data);
+ result->data = 0;
+ __spdelete(result, sp);
+ }
+}
+
+void
+__m_count(spblk)
+SPBLK *spblk;
+{
+ Word *p;
+
+ nmallocs++;
+ p = (Word *) spblk->key;
+ p -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p), "bad pointer seen in __m_count");
+ ASSERT(TAG(p) != FREE, "freed block seen in __m_count");
+ ASSERT(VALID_START_SIZE_FIELD(p), "corrupt block seen in __m_count");
+ ASSERT(VALID_MAGIC(p), "block with end overwritten seen in __m_count");
+
+ nbytes += SIZE(p) * sizeof(Word);
+ return;
+}
+
+void
+mal_contents(fp)
+FILE *fp;
+{
+ void __m_count proto((SPBLK *));
+
+ nmallocs = 0;
+ nbytes = 0;
+ __spscan(__m_count, (SPBLK *) NULL, sp);
+ (void) sprintf(_malloc_statsbuf,
+ "%% %lu bytes %lu mallocs %lu available %lu vm\n",
+ nbytes, nmallocs, (ulong) _malloc_totalavail,
+ (ulong) sbrk(0));
+ (void) fputs(_malloc_statsbuf, fp);
+ (void) fflush(fp);
+}
diff --git a/lib/libmalloc/malloc.c b/lib/libmalloc/malloc.c
new file mode 100644
index 000000000000..354520ac3da4
--- /dev/null
+++ b/lib/libmalloc/malloc.c
@@ -0,0 +1,622 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.c"
+
+RCSID("$Id: malloc.c,v 1.1 1994/03/06 22:59:47 nate Exp $")
+
+static int
+grabhunk(nwords)
+size_t nwords;
+{
+ univptr_t cp;
+ size_t morecore;
+ Word *ptr;
+ size_t sbrkwords;
+ size_t blksize;
+ static char *spare;
+ static int nspare;
+
+ /*
+ * two words for fake boundary tags for the entire block, and one
+ * for the next ptr of the block.
+ */
+#define EXCESS 3
+ sbrkwords = (size_t) (((nwords + EXCESS) / _malloc_sbrkunits + 1) *
+ _malloc_sbrkunits);
+ morecore = sbrkwords * sizeof(Word) + SBRKEXTRA;
+ if ((cp = (* _malloc_memfunc)(morecore)) == (univptr_t) -1)
+ return(0);
+ /*
+ * Should first GUARANTEE that what sbrk returns is aligned to
+ * Word boundaries - see align.h. Unfortunately, to guarantee
+ * that the pointer returned by sbrk is aligned on a word
+ * boundary, we must ask for sizeof(Word) -1 extra bytes, since
+ * we have no guarantee what other sbrk'ed blocks exist. (Sun
+ * sbrk always returns an aligned value, that is another story!)
+ * We use spare and nspare to keep track of the bytes wasted, so
+ * that we can try and reuse them later. If no other sbrk()s are
+ * called, then nspare rotates through the values 3, 2, 1, 0,
+ * and the first branch of the if() is always taken.
+ */
+ if ((spare + nspare) == (char *) cp) {
+ ptr = (Word *) SBRKALIGN(spare);
+ morecore += nspare;
+ sbrkwords = morecore / sizeof(Word);
+ } else {
+ ptr = (Word *) SBRKALIGN(cp);
+ morecore -= (char *) ptr - (char *) cp;
+ }
+ spare = (char *) (ptr + sbrkwords);
+ nspare = (morecore - sbrkwords * sizeof(Word));
+ _malloc_totalavail += sbrkwords;
+ PRTRACE(sprintf(_malloc_statsbuf, "sbrk %lu\n",
+ (ulong) sbrkwords*sizeof(Word)));
+
+ /*
+ * Here we need to check if it adjoins the _malloc_hiword. If it
+ * does, then _malloc_hiword need not be a fake boundary tag any
+ * longer, (its a real one) and the higher end of the block we
+ * sbrk'ed is the fake tag. So we tag it appropriately, make
+ * the start of the block point to the old _malloc_hiword, and free it.
+ * If we aren't next to _malloc_hiword, then someone else sbrk'ed in
+ * between, so we can't coalesce over the boundary anyway, in
+ * which case we just change _malloc_hiword to be in the new sbrk'ed
+ * block without damaging the old one. And we free the block.
+ */
+ if (ptr != _malloc_hiword + 1 || _malloc_rover == NULL) {
+ /* Non-contiguous sbrk'ed block, or first sbrk we've done. */
+ /*
+ * First push this block on the stack of non-contiguous blocks
+ * we've sbrked. !! For real paranoia, we'd also check
+ * _malloc_mem...
+ */
+ REGISTER Word *tmp = _malloc_mem;
+
+ _malloc_mem = ptr;
+ ptr->next = tmp;
+ ptr++;
+ sbrkwords--;
+
+ _malloc_hiword = ptr;
+ if (_malloc_loword == NULL || _malloc_loword > ptr) {
+ /* First time - set lower bound. */
+ PRTRACE(sprintf(_malloc_statsbuf, "heapstart 0x%lx\n",
+ (ulong) ptr));
+ _malloc_loword = ptr;
+ }
+ /*
+ * Fake boundary tags to indicate the ends of an arena. Since they
+ * are marked as allocated, no attempt will be made to coalesce
+ * before or after them.
+ */
+ SIZEFIELD(ptr) = ALLOCED | sbrkwords;
+ _malloc_hiword += sbrkwords - 1;
+ PRTRACE(sprintf(_malloc_statsbuf, "heapend 0x%lx\n",
+ (ulong) _malloc_hiword));
+ SIZEFIELD(_malloc_hiword) = ALLOCED | sbrkwords;
+
+ ptr++;
+ /*
+ * The 2 we subtract are the special arena end tags, which is
+ * why we don't use HEADERWORDS and TRAILERWORDS
+ */
+ sbrkwords -= 2;
+ SIZEFIELD(ptr) = FREEMASK(sbrkwords);
+ DMEMSET(ptr + FREEHEADERWORDS, sbrkwords - FREE_OVERHEAD);
+ ptr = _malloc_hiword - 1;
+ SIZEFIELD(ptr) = FREEMASK(sbrkwords);
+ /* links */
+ if (_malloc_rover == NULL) {
+ /* Only block in free list - links point to itself */
+ NEXT(ptr) = ptr;
+ PREV(ptr) = ptr;
+ } else {
+ /*
+ * Non-contiguous sbrk - insert into free list. No
+ * point calling free() because we know this cannot be
+ * coalesced
+ */
+ NEXT(ptr) = _malloc_rover;
+ tmp = PREV(_malloc_rover);
+ PREV(ptr) = tmp; /* PREV(ptr) = PREV(_malloc_rover); */
+ NEXT(tmp) = ptr; /* NEXT(PREV(_malloc_rover)) = ptr; */
+ PREV(_malloc_rover) = ptr;
+ }
+ _malloc_rover = ptr;
+ return(1);
+ }
+ /* Set boundary tags and size */
+ ptr--;
+ blksize = SIZE(ptr) + sbrkwords;
+ SIZEFIELD(ptr) = ALLOCMASK(sbrkwords);
+ _malloc_hiword += sbrkwords;
+ SIZEFIELD(_malloc_hiword-1) = SIZEFIELD(ptr);
+ /* Update fake end tags of the memory chunk */
+ SIZEFIELD(_malloc_hiword) = ALLOCMASK(blksize);
+ SIZEFIELD(_malloc_hiword - blksize + 1) = ALLOCMASK(blksize);
+ SET_REALSIZE(ptr, (sbrkwords - ALLOC_OVERHEAD) * sizeof(Word));
+ free((univptr_t) (ptr + HEADERWORDS));
+ return(1);
+}
+
+univptr_t
+malloc(nbytes)
+size_t nbytes;
+{
+ REGISTER Word *start, *search;
+ REGISTER Word *p;
+ REGISTER size_t required;
+ REGISTER size_t searchsize;
+ REGISTER size_t rest;
+ size_t roversize;
+
+#ifndef BUGCOMPATIBILITY
+ ASSERT(nbytes != 0, "What do you expect when you malloc(0)?!!");
+ if (nbytes == 0) { /* If we're debugging, then we died on the ASSERT */
+ errno = EINVAL;
+ return(NULL);
+ }
+#endif /* BUGCOMPATIBILITY */
+
+ required = ALLOC_OVERHEAD + (nbytes + sizeof(Word) - 1) /
+ sizeof(Word);
+ if (required < (size_t) _malloc_minchunk)
+ required = _malloc_minchunk;
+ search = _malloc_rover;
+ if (!search || required > _malloc_totalavail) {
+ /* Not enough memory in free list - allocate enough memory. */
+ if (grabhunk(required) == 0) {
+ errno = ENOMEM;
+ return( NULL);
+ }
+ search = _malloc_rover;
+ }
+
+ ASSERT(PTR_IN_HEAP(_malloc_rover), "corrupt rover pointer in malloc()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover), "corrupt block in malloc()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover), "corrupt block in malloc()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover), "corrupt block in malloc()");
+ CHECKHEAP();
+
+ roversize = FREESIZE(search);
+ if (search == _malloc_hiword - 1) { /* avoid wilderness */
+ search = NEXT(search);
+#if 0
+ {
+ char buf[1024];
+ sprintf(buf, "wilderness = 0x%x, skipping to 0x%x\n",
+ _malloc_hiword - 1, search);
+ fputs(buf, stderr);
+ }
+#endif
+ }
+ start = search;
+ do {
+ ASSERT(PTR_IN_HEAP(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_END_SIZE_FIELD(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_NEXT_PTR(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_PREV_PTR(search), "corrupt pointer in malloc()");
+ searchsize = FREESIZE(search);
+ if (searchsize >= required) {
+ break;
+ } else {
+ search = NEXT(search);
+ }
+ } while (search != start);
+
+ if (searchsize < required) {
+ if (grabhunk(required) == 0) {
+ errno = ENOMEM;
+ return( NULL);
+ }
+ /*
+ * We made sure in grabhunk() or free() that
+ * _malloc_rover is pointing to the newly sbrked (and
+ * freed) block.
+ */
+ search = _malloc_rover;
+ roversize = searchsize = FREESIZE(search);
+ }
+ rest = searchsize - required;
+ if (rest >= _malloc_minchunk) {
+ SIZEFIELD(search) = FREEMASK(rest);
+ p = search - rest;
+ SIZEFIELD(p+1) = FREEMASK(rest);
+ SIZEFIELD(p) = ALLOCMASK(required);
+ p -= required - 1;
+ SIZEFIELD(p) = ALLOCMASK(required);
+ _malloc_totalavail -= required;
+ /* keep rover at the larger block */
+ if (rest > roversize)
+ _malloc_rover = search;
+ } else {
+ /* alloc the entire block */
+ REGISTER Word *nextp = NEXT(search);
+
+ SIZEFIELD(search) |= ALLOCED;
+ p = search - searchsize + 1;
+ SIZEFIELD(p) = SIZEFIELD(search);
+ if (search == nextp) {
+ _malloc_rover = NULL;
+ } else {
+ REGISTER Word *prevp = PREV(search);
+
+ NEXT(prevp) = nextp;
+ PREV(nextp) = prevp;
+ /* keep rover at the larger block, unless we just allocated rover*/
+ if (search == _malloc_rover || FREESIZE(nextp) > roversize)
+ _malloc_rover = nextp;
+ }
+ _malloc_totalavail -= searchsize;
+ }
+ PRTRACE(sprintf(_malloc_statsbuf, "+ %lu %lu 0x%lx\n", (ulong) nbytes,
+ (ulong) (SIZE(p) - ALLOC_OVERHEAD) * sizeof(Word),
+ (ulong) (p + HEADERWORDS)));
+ COUNTSIZE(SIZE(p));
+ SET_REALSIZE(p, nbytes);
+ return((univptr_t) (p + HEADERWORDS));
+}
+
+
+
+void
+free(cp)
+univptr_t cp;
+{
+ /*
+ * This is where the boundary tags come into their own. The
+ * boundary tag guarantees a constant time insert with full
+ * coalescing (the time varies slightly for the four case possible,
+ * but still, essentially a very fast free.
+ */
+ /*
+ * P0 is the block being freed. P1 is the pointer to the block
+ * before the block being freed, and P2 is the block after it.
+ * We can either coalesce with P1, P2, both, or neither
+ */
+ REGISTER Word *p0, *p1, *p2;
+
+ if (cp == NULL)
+ return;
+
+ p0 = (Word *) cp;
+ p0 -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p0), "bad pointer passed to free()");
+ ASSERT(TAG(p0) != FREE, "freed block passed to free()");
+ ASSERT(VALID_START_SIZE_FIELD(p0), "corrupt block passed to free()");
+ ASSERT(VALID_MAGIC(p0), "block with end overwritten passed to free()");
+ /* With debugging, the assert would have already aborted */
+ if (TAG(p0) == FREE) {
+ errno = EINVAL;
+ return;
+ }
+
+ /*
+ * clear the entire block that used to be p0's, just in case someone
+ * tries to refer to it or anything in it again. We leave the end tags
+ * alone for now - we'll smash them individually depending on the way p0
+ * merges with p1 and/or p2.
+ */
+ DMEMSET(p0 + FREEHEADERWORDS, SIZE(p0) - FREE_OVERHEAD);
+ PRTRACE(sprintf(_malloc_statsbuf, "- %lu 0x%lx\n",
+ (ulong) (SIZE(p0) - ALLOC_OVERHEAD) * sizeof(Word),
+ (ulong) (p0 + HEADERWORDS)));
+ _malloc_totalavail += SIZE(p0);
+
+ p1 = p0 - 1;
+ /*
+ * p0 now points to the end of the block -- we start treating it as
+ * a free block
+ */
+ p0 += SIZE(p0) - 1;
+ p2 = p0 + 1;
+
+ /*
+ * More paranoia.... We can't match the SIZEFIELDs of p1/p2 with
+ * p1/p2 + SIZE(p1/p2) -1 because they might be a fake tag to
+ * indicate the bounds of the arena. Further, we should only check
+ * p1 if p0-1 is not the _malloc_loword or an arena bound - else p1 is
+ * probably not a valid pointer. If tag p0-1 is allocated, then it
+ * could be an arena bound.
+ */
+
+ if (TAG(p2) == FREE) {
+ /*
+ * Aha - block which is physically after p0 is free.
+ * Merging with it merely means increasing its size to
+ * incorporate the block being freed - no pointer
+ * shuffling.
+ */
+ p2 += FREESIZE(p2) - 1;
+ ASSERT(PTR_IN_HEAP(p2), "corrupt block in free()");
+ ASSERT(TAG(p2)==FREE, "corrupt block in free()");
+ ASSERT(VALID_END_SIZE_FIELD(p2), "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(p2), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(p2), "corrupt block in free()");
+
+ SIZEFIELD(p2) = FREEMASK(FREESIZE(p2) + SIZE(p0));
+ SIZEFIELD(p2 - FREESIZE(p2) + 1) = SIZEFIELD(p2);
+ /*
+ * Smash p0's old end tag and p2's old start tag.
+ */
+ DMEMSET(p0 - FREETRAILERWORDS + 1, FREETRAILERWORDS + FREEHEADERWORDS);
+ p0 = p2; /* p0 just vanished - became part of p2 */
+ }
+ if (TAG(p1) == FREE) {
+ /*
+ * Block that physically precedes p0 in memory is free. Merging
+ * with it means rearranging the links to because the end of
+ * the block (the handle it is known by) is now the end of p0
+ * rather than itself. So the blocks after and before it in the
+ * free list need to be told.
+ */
+ REGISTER Word *nextp1, *prevp1;
+
+ ASSERT(PTR_IN_HEAP(p1), "corrupt block in free()");
+ ASSERT(VALID_END_SIZE_FIELD(p1), "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(p1), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(p1), "corrupt block in free()");
+
+ /* p0 grows to absorb p1 */
+ SIZEFIELD(p0) = FREEMASK(SIZE(p0) + FREESIZE(p1));
+ SIZEFIELD(p0 - FREESIZE(p0) + 1) = SIZEFIELD(p0);
+ nextp1 = NEXT(p1);
+ prevp1 = PREV(p1);
+ /*
+ * We smash the free list pointers in p1 (SIZE, NEXT, PREV) to
+ * make sure no one refers to them again. We cannot smash the
+ * start boundary tag because in both cases, it becomes the start
+ * tag for the new block. We also trash p0's start tag.
+ */
+ DMEMSET(p1 - FREETRAILERWORDS + 1, FREETRAILERWORDS + FREEHEADERWORDS);
+ if (p0 != p2) {
+ /*
+ * Ok - p0 coalesced with the block physically
+ * before it (p1) (which is why we're here, but
+ * it didn't coalesce with the block after it
+ * (p2) which is why p0 != p2. So we need to
+ * insert p0 in the list in place of p1.
+ */
+
+ if (nextp1 != p1) {
+ /* Fix the PREV ptr of the next blk in the list */
+ PREV(nextp1) = p0;
+ /* Fix the NEXT ptr of the previous blk in the list */
+ NEXT(prevp1) = p0;
+ /* Copy the link info from p1 to p0 */
+ NEXT(p0) = nextp1;
+ PREV(p0) = prevp1;
+ } else {
+ NEXT(p0) = p0;
+ PREV(p0) = p0;
+ }
+ /* p1 just vanished - became part of p0 */
+ _malloc_rover = p0;
+ CHECKHEAP();
+ return;
+ } else {
+ /*
+ * p0 merged with p2, and with p1, which
+ * essentially means that p2 grows to absorb p1
+ * in the free list (bridged by p0). So we
+ * simply delete p1. Free list reduces by one blk.
+ */
+ /* Fix the PREV ptr of the next blk in the list */
+ PREV(nextp1) = prevp1;
+ /* Fix the NEXT ptr of the previous blk in the list */
+ NEXT(prevp1) = nextp1;
+ }
+ }
+ if (p0 != p2) {
+ /*
+ * If we're here, it means block P0 didn't coalesce, so
+ * we need to insert it in the free list - we put it
+ * before ROVER, and make ROVER point to it. Or it
+ * means ROVER was NULL, i.e. free list is empty, which
+ * means we have to take care of the boundary linking
+ * Free list grows by one.
+ */
+ if (_malloc_rover == NULL) {
+ /*
+ * Free list was empty - so we point _malloc_rover at
+ * the block we're freeing to get a proper
+ * circular linking.
+ */
+ _malloc_rover = p0;
+ } else {
+ ASSERT(PTR_IN_HEAP(_malloc_rover),
+ "corrupt rover pointer in free()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover),
+ "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover), "corrupt block in free()");
+ }
+ NEXT(p0) = _malloc_rover;
+ PREV(p0) = PREV(_malloc_rover);
+ PREV(_malloc_rover) = p0;
+ NEXT(PREV(p0)) = p0;
+ SIZEFIELD(p0) &= SIZEMASK; /* sets the boundary tag to FREE */
+ SIZEFIELD(p0 - FREESIZE(p0) + 1) = SIZEFIELD(p0);
+ }
+ _malloc_rover = p0;
+
+ CHECKHEAP();
+ return;
+}
+
+
+
+/*
+ * WARNING: This realloc() IS *NOT* upwards compatible with the
+ * convention that the last freed block since the last malloc may be
+ * realloced. Allegedly, this was because the old free() didn't
+ * coalesce blocks, and reallocing a freed block would perform the
+ * compaction. Yuk!
+ */
+univptr_t
+realloc(cp, nbytes)
+univptr_t cp;
+size_t nbytes;
+{
+ REGISTER Word *p0 = (Word *) cp;
+ REGISTER Word *p1;
+ univptr_t tmp;
+ REGISTER size_t required;
+ REGISTER size_t sizep0;
+
+ if (p0 == NULL)
+ return(malloc(nbytes));
+
+ if (nbytes == 0) {
+ free(cp);
+ return(NULL);
+ }
+
+ required = ALLOC_OVERHEAD + (nbytes + sizeof(Word) - 1) /
+ sizeof(Word);
+ if (required < (size_t) _malloc_minchunk)
+ required = _malloc_minchunk;
+
+ p0 -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p0), "bad pointer passed to realloc()");
+ ASSERT(TAG(p0) != FREE, "freed block passed to realloc()");
+ ASSERT(VALID_START_SIZE_FIELD(p0), "corrupt block passed to realloc()");
+ ASSERT(VALID_MAGIC(p0), "block with end overwritten passed to realloc()");
+ /* With debugging, the assert would have already aborted */
+ if (TAG(p0) == FREE) {
+ errno = EINVAL;
+ return(NULL);
+ }
+ sizep0 = SIZE(p0);
+ if (sizep0 >= required) {
+ /* Shrinking the block */
+ size_t after = sizep0 - required;
+
+ SET_REALSIZE(p0, nbytes);
+ if (after < _malloc_minchunk) {
+ /*
+ * Not enough to free what's left so we return the block
+ * intact - print no-op for neatness in output.
+ */
+ PRTRACE(strcpy(_malloc_statsbuf, "no-op\n"));
+ return(cp);
+ }
+ SIZEFIELD(p0) = ALLOCMASK(required);
+ SIZEFIELD(p0 + required - 1) = SIZEFIELD(p0);
+ p0 += required;
+ /*
+ * We free what's after the block - mark it alloced and
+ * throw it to free() to figure out whether to merge it
+ * with what follows...
+ */
+ SIZEFIELD(p0) = ALLOCMASK(after);
+ SIZEFIELD(p0 + after - 1) = SIZEFIELD(p0);
+ SET_REALSIZE(p0, (after - ALLOC_OVERHEAD) * sizeof(Word));
+ free((univptr_t) (p0 + HEADERWORDS));
+ return(cp);
+ }
+
+ /*
+ * If we get here, then we are growing the block to something
+ * bigger. If the following block is free and big enough to be
+ * realloced, then we grow using that block. This resembles the
+ * malloc code slightly.
+ */
+ p1 = p0 + sizep0;
+ required -= sizep0;
+ if (TAG(p1) == FREE) { /* p1 not free, may be an arena bound or hiword */
+ ASSERT(PTR_IN_HEAP(p1), "corrupt pointer in realloc()");
+ ASSERT(VALID_START_SIZE_FIELD(p1), "corrupt block in realloc()");
+ ASSERT(VALID_NEXT_PTR(p1 + FREESIZE(p1) - 1),
+ "corrupt block in realloc()");
+ ASSERT(VALID_PREV_PTR(p1 + FREESIZE(p1) - 1),
+ "corrupt block in realloc()");
+ }
+ if (TAG(p1) == FREE && FREESIZE(p1) >= required) {
+ size_t rest = FREESIZE(p1) - required;
+ REGISTER Word *p;
+
+ if (rest >= _malloc_minchunk) {
+ sizep0 += required;
+ SIZEFIELD(p0) = ALLOCMASK(sizep0);
+ p = p0 + sizep0;
+ SIZEFIELD(p-1) = SIZEFIELD(p0);;
+ SIZEFIELD(p) = FREEMASK(rest);
+ SIZEFIELD(p + rest - 1) = FREEMASK(rest);
+ _malloc_totalavail -= required;
+ } else {
+ /*
+ * alloc the entire block and merge into p0. Free list
+ * shrinks by a block
+ */
+ REGISTER Word *nextp1, *prevp1;
+
+ sizep0 += FREESIZE(p1);
+ SIZEFIELD(p0) = ALLOCMASK(sizep0);
+ SIZEFIELD(p0 + sizep0 - 1) = SIZEFIELD(p0);
+ p1 += FREESIZE(p1) - 1;
+ p = nextp1 = NEXT(p1);
+ if (p1 == nextp1) {
+ _malloc_rover = NULL;
+ } else {
+ prevp1 = PREV(p1);
+ PREV(nextp1) = prevp1;
+ NEXT(prevp1) = nextp1;
+ _malloc_rover = nextp1;
+ }
+ _malloc_totalavail -= SIZE(p1);
+ }
+ SET_REALSIZE(p0, nbytes);
+ CHECKHEAP();
+
+ PRTRACE(sprintf(_malloc_statsbuf, "++ %lu %lu 0x%lx %lu 0x%lx\n",
+ (ulong) nbytes,
+ (ulong) (SIZE(p0)-ALLOC_OVERHEAD)*sizeof(Word),
+ (ulong) cp, (ulong) SIZE(p)*sizeof(Word),
+ (ulong) p));
+ return(cp);
+ }
+ /* Have to do it the hard way */
+ tmp = malloc(nbytes);
+ if (tmp != NULL) {
+ MEMCPY(tmp, cp, ((SIZE(p0) - ALLOC_OVERHEAD)));
+ free(cp);
+ }
+ return(tmp);
+}
+
+
+
+/*
+ * !! Given what we know about alignment, we should be able to do better
+ * than memset and set words. Hopefully memset has been tuned.
+ */
+univptr_t
+calloc(nelem, elsize)
+size_t nelem, elsize;
+{
+ REGISTER size_t nbytes = nelem * elsize;
+ REGISTER univptr_t cp = malloc(nbytes);
+
+ if (cp)
+ (void) memset((univptr_t) cp, 0, (memsize_t) nbytes);
+ return(cp);
+}
+
+
+/*
+ * Why would anyone want this.... ?
+ */
+void
+cfree(cp)
+univptr_t cp;
+{
+ free(cp);
+}
diff --git a/lib/libmalloc/malloc.doc b/lib/libmalloc/malloc.doc
new file mode 100644
index 000000000000..f209baf5a7bf
--- /dev/null
+++ b/lib/libmalloc/malloc.doc
@@ -0,0 +1,653 @@
+$Header: /home/cvs/386BSD/src/lib/libmalloc/malloc.doc,v 1.1 1994/03/06 22:59:48 nate Exp $
+ Yet another malloc()
+ --------------------
+ Mark Moraes
+ <moraes@csri.toronto.edu>
+
+ Standard calls
+
+It provides the standard calls we expect from any self-respecting
+malloc, viz.
+
+ char *
+ malloc(nbytes)
+
+ unsigned int nbytes;
+
+which returns pointer to a contiguous memory block, at least nbytes
+bytes long,
+
+ char *
+ calloc(nelements, element_size)
+
+ unsigned int nelements, element_size;
+
+which returns a pointer to a contiguous memory block, at least
+nelements * element_size bytes long, with all locations set to zero,
+
+ char *
+ realloc(ptr, nbytes)
+
+ char *ptr;
+ unsigned int nbytes;
+
+attempts to change the size of the previously malloc'ed block pointed
+to by ptr to nbytes, and failing that, returns a pointer to a new block
+nbytes long, after copying the contents of the old block to it.
+Realloc returns NULL if it fails, and DOES NOTHING WITH THE OLD BLOCK.
+(This is not defined; some reallocs may free the old block they were
+passed)
+
+ void
+ free(ptr)
+
+ char *ptr;
+
+returns the previously malloc'ed block pointed to by ptr to the
+storage pool. It will do its best to keep storage as unfragmented as
+possible.
+
+ void
+ cfree(ptr)
+
+ char *ptr;
+
+The same as free(), used to free calloc()ed blocks.
+
+There are a couple of additional functions that Sun malloc provides,
+and that some programs need (notably the X Windows server on Suns)
+
+ char *
+ memalign(alignment, nbytes)
+
+ unsigned int alignment;
+ unsigned int nbytes;
+
+This returns a pointer to a memory block at least nbytes long,
+guaranteeing that the block starting address is an even multiple of
+alignment. Alignment must be a power of 2.
+
+ char *
+ valloc(nbytes)
+
+ unsigned int nbytes;
+
+This is the same as memalign(getpagesize(), nbytes).
+
+A frequently used function is to save a copy of a NULL-terminated
+character array (a C string) in storage malloc'ed exactly to fit it,
+for example when reading or parsing some input line from a large
+buffer. Newer systems provide the strdup() function to do just this.
+(This may not appear a complex funtion - using it eliminates the
+all-too-frequent error where you forget to add 1 to the length of the
+string to allow for the NULL terminator)
+
+ char *
+ strdup(s)
+
+ char *s;
+
+strdup returns NULL if the malloc fails.
+
+ Additional functions
+
+In addition to the usual functions, this malloc provides some
+debugging and profiling functions, which we discuss in more detail
+below. (NOTE: To use these special features, you have to include the
+header file "malloc.h" provided with this malloc. This header file
+also defines the C preprocessor symbol CSRIMALLOC. This allows anyone
+using any of the special features of this malloc to enclose any calls
+to the new features within #ifdef CSRIMALLOC, thus preserving code
+portability)
+
+Since this malloc library is usually installed as libmalloc.a, to use
+it instead of a regular system malloc, you need to specify something
+like -lmalloc on your link/load command line before -lc, if any.
+Make sure your program has at least one call to any one of
+malloc/free/calloc/realloc or the Unix loader may not link in this
+malloc, and will instead use the system one from libc, since it makes
+only one pass.
+
+Most of the debugging features will be available in a version of the
+malloc called malloc_d, which is what you should use for development
+and testing by specifying -lmalloc_d. For production programs, link
+with -lmalloc to get the fast version.
+
+Frequently, people forget to check the return value on a malloc()
+assuming that modern systems never run out of memory. Inevitably,
+Murphy ensures that some system will run out of memory, and a user
+will be faced with the illuminating error message "Segmentation
+violation - core dumped". Alas, when memory runs out, the core dump is
+likely to be large. This malloc provides an emalloc() function which
+exits if NULL is returned, with an out of memory message. Using this
+in place of malloc is advised if running out of memory is a fatal
+condition. (If not, either write your own emalloc() to recover
+gracefully, or check the value returned by malloc)
+
+ char *
+ emalloc(nbytes)
+
+ unsigned nbytes;
+
+Similarly, a realloc which will die instead of returning NULL is
+erealloc().
+
+ char *
+ erealloc(ptr, nbytes)
+
+ unsigned nbytes;
+
+A similar function, like strdup() but not returning NULL is strsave().
+
+ char *
+ strsave(s)
+
+ char *s;
+
+
+ Debugging support
+
+Alas, one of the more common, and unpleasant errors a C programmer can
+make is to accidentally exceed the bounds of an array, and write over
+the data that immediately follows (or less frequently, precedes) it in
+memory. Such "corruption" errors usually show up at a completely
+different place in the program from the place the actual overwriting
+occurs (A corollary to Murphy's Law suggests the error will appear in
+the last related module of the program), thus making it at least as
+hard to track down as the proverbial needle in the haystack. While
+there is little that we can do to help detect errors in static,
+automatic or global data, we can at least try to ensure the validity
+of the malloc()ed data.
+
+To get this support, the malloc() must be compiled with -DDEBUG -
+since this reduces performance somewhat, it is usually done in a
+separate object module from the one usually used in production code.
+This debugging malloc() makes sure all internal heap pointers relevant
+to an allocation (or free) are correct on every call to one of the
+allocation routines, and aborts if it detects any trouble, with a
+message starting with "assertion botched". This is
+useful because it causes the program to die nearer the trouble spot
+than would otherwise be the case, helping to pinpoint the error.
+This narrows down the location of the error to something less than the
+aforementioned haystack, but the problem is still somewhat large.
+
+ int
+ mal_verify(fullcheck)
+
+ int fullcheck;
+
+lends a helping hand in such distressing situations. It runs through
+all allocated and free blocks, checking all heap pointers for
+validity. Since the heap pointers (and block size values) are at the
+beginning and end of allocated (and free) blocks, any overwriting off
+the end of a memory block usually results in the corruption of the
+heap size values, or the pointer values of the next block. If
+'fullcheck' is non-zero, then additional checking of the contents of
+free blocks is done, to ensure that they haven't been written into
+after being freed. Calling mal_verify() with fullcheck as 1 is
+recommended. (More on this later)
+
+On detecting an error, mal_verify() aborts the program, on the not
+unreasonable grounds that such an error is A BAD THING and should be
+fixed immediately.
+
+A careful programmer will probably want to put calls to mal_verify()
+at frequent points in any code, as checkpoints to trap any stray
+overwriting or memory corruption that may take place. Since
+mal_verify() does nothing in a malloc compiled without -DDEBUG, it
+has no overhead in production code other than the procedure call.
+("But I can't be overwriting any data between X and Y in my code" are
+famous last words)
+
+Instead of putting calls to mal_verify(), the programmer can set
+the debugging level of the allocator.
+
+ void
+ mal_debug(level)
+
+ int level;
+
+Most debugging is done at level 1, which is the default. This only
+checks the internal pointers that are encountered during a malloc() or
+free(). Setting level to 2 with the mal_debug() call results in a
+complete check of the heap (i.e. a call to mal_verify(0) ) every time
+malloc(), realloc() or free() are called. (The other allocation
+routines call these three) This can be very slow if your program does
+a lot of debugging, but is worth turning on for a specific segment of
+the program where you suspect trouble. (The author uses this mode when
+writing and debugging a program initially, switches to normal
+debugging for alpha and beta test) Level 3 asks for mal_verify(1) on
+every malloc(), realloc() or free() which checks all free blocks'
+insides for any signs of someone writing to them.
+
+We recommend the use of a binary search technique for pinpointing the
+needle, er, the overwriting. This presupposes that malloc(), free(),
+or a previously (wisely) inserted mal_verify() has caused the
+program to die at some point with an "assertion botched" error. (If
+the programmer has not been using this malloc so far, or a variant
+compiled without -DDEBUG, then the only indication of a memory
+corruption error is utterly strange things happening to the program,
+possibly variable changing values when they're not supposed to, or
+mysterious deaths of the program in malloc(), free() or some such
+call)
+
+Insert a mal_verify() call (Referred to from now on as Checkpoint
+1) at some point well before the error occurs, if necessary, at the
+first executable statement in the program. Insert another
+mal_verify call on the statement just before you suspect the error
+manifesting itself. (Checkpoint 2)
+
+(Note that when we say insert a mal_verify() call at some point
+"before" an error occurs, we are referring to a temporal location,
+i.e some piece of code that is executed by the program in the time
+before the error occurs. Physically, this may be in a different
+procedure, or a different file altogether.)
+
+Run the program.
+
+If Checkpoint 1 causes the program to die, then the error is trapped
+in between it and the start of the program. (case A) If Checkpoint 2
+causes the program to die, then the error is trapped between it and
+Checkpoint 1, (case B) and if neither dies, the error is after
+Checkpoint 2, (case C) or is not an overwriting error at all, or is an
+error subtle enough to avoid the heap pointer checking. In the last
+case, we wish you luck...
+
+Case A: (The bug is before checkpoint 1)
+
+Move Checkpoint 2 to where checkpoint 1 presently is, and move
+checkpoint 1 further back. Run the program again.
+
+Case B: (The bug is between checkpoint 1 and checkpoint 2 - narrow the
+search area down further)
+
+This is the case we attempt to maintain. Having attained it, we
+promptly attempt to lose it again. (Why is this starting to sound like
+Zen...) To do so, we move either Checkpoint 1 or Checkpoint 2 closer
+to the other, and run the program again.
+
+Case C: (The bug is after checkpoint 2)
+
+Move Checkpoint 1 to where checkpoint 2 presently is, and move
+checkpoint 2 further ahead. Run the program again.
+
+The objective is to bring the two checkpoints as close to each other
+as is necessary to spot the bug. (Recognizing the bug is up to the
+programmer - loops exceeding the bound by one are a common problem
+causing this error - confusion with C's starting arrays at 0 unlike
+other languages which start them at 1 is another problem).
+
+Those familiar with numerical methods will see the similarity between
+this method and the binary search method for finding a root of an
+equation. (It also bears a resemblance to the binary search method on
+sorted data, but the resemblance is less striking)
+
+In a modular program, which has been well structured, placing such
+checkpoints is easy to do; simply start at the top level, narrow it
+down to some procedure call at that level, insert them at the entry and
+exit points of that procedure, narrow it down to some procedure call
+at this level, and recurse downward till the fault is detected.
+
+We noted earlier that some corruption bugs manifest themselves (Why is
+this starting to read like a ghostbusters' script...) as data values
+that change when they shouldn't. In this case, a simpler method to
+trace the bug is often to put a trace on that data location by setting
+a global pointer variable to point to it, and printing the value at
+the two checkpoints. The same search strategy can be employed. This
+has been found useful in at least one bug the author has encountered,
+which sneakily refused to corrupt the heap pointers, jumping over them
+straight into another block to do its dirty work.
+
+A vicious form of heap corruption is when someone frees a block of
+memory, but forgets to NULL or reset all pointers pointing to that
+block. At some point in the future, if that block is accessed, strange
+things can happen. If that block is still free, and in the heap, there
+is a chance of corrupting malloc's internal pointers and structures
+used to maintain the free list, in which case mal_verify() will detect
+the corruption and abort. Or the corruption may go into the middle of
+the block and go undetected. Even worse, the block or part of the
+block may have been allocated to the program for some other purpose,
+and the corruption may now be smashing data in another part of the
+program. This sort of corruption is insidious, and very hard to
+reproduce, let alone trace down. To help trace this down, when a block
+is freed, in debugging mode, the allocator scribbles a magic pattern
+all over it, thus making sure any data in there is likely to be wrong.
+Invoking mal_verify(1) will check every free block to make sure its
+contents are that magic pattern and abort if it detects corruption.
+Setting debug level to 3 with mal_debug() will force this sort of
+verification on every call to malloc(), realloc() or free().
+Obviously, if the block gets allocated, and then corrupted, the malloc
+verification cannot detect it, since it has no idea what goes on
+inside allocated blocks.
+
+
+ Advanced debugging tools.
+
+ void
+ mal_heapdump(fd)
+
+ FILE *fd;
+
+If all else fails, the programmer may obtain a printout of the entire
+heap by calling mal_heapdump() with a file descriptor to an already
+open file (fopen(3)). This will print the start address of
+all blocks, allocated or free, and their sizes. These can be matched
+with pointer addresses in the program and used to trace heap
+corruption. If you use this call, you probably know how to do this.
+Large doses of intuition (and strong beverages) are recommended.
+mal_heapdump() performs the same checking that mal_verify(1) does, but
+does not abort unless the error makes it impossible to dump the heap
+further. A knowledge of the malloc internals is necessary to fully
+exploit this call's output.
+
+ Profiling support
+
+This malloc() is faster than most other mallocs that I've seen - the
+search strategy is a first-free, which is not excitingly fast in
+theory, but, with small modifications turns out to be quite fast in
+practice; See Knuth for more details. (Theoretically, the time is of
+the same order as the size of the free list, so the free list is kept
+as small as possible by coalescing a block with adjacent freed blocks
+if possible, when it is freed) The free() is based on a boundary tags
+scheme, as described in Knuth. It is linear-time, for those who care
+about such things, and is a few statements of C code - 4 comparisons
+and a little pointer arithmetic. It also accesses memory locations
+next to the block only, so it has good virtual memory performance. (The
+malloc turns out to have good VM performance most of the time, but
+will occasionally scan through a few pages, and in worst case, through
+a lot of pages. If however, those pages are all being used, then the
+VM performance is likely to be influenced more by the program using
+the malloc than the malloc itself)
+
+Nonetheless, a program which calls malloc and free *very* frequently
+might be slow. In order to track down malloc usage, if compiled with
+-DPROFILEDSIZES, this malloc keeps count of the number of block sizes
+being used by the program. To print out these collected statistics,
+call
+
+ void
+ mal_statsdump(fd)
+
+ FILE *fd;
+
+where fd is an already opened file descriptor, and it will print a
+list of block sizes, and the number of times a block of that size was
+allocated. This information provides some indication of the allocation
+profile of the calling program.
+
+When mal_statsdump() is called, it zeroes all the counters, so that
+you can check the allocation profile of specific segments of a program
+by calling mal_statsdump() repeatedly.
+
+If more detailed tracing information is needed, the malloc must be
+compiled with -DTRACE. This prints out the size of every allocation
+or free. This can be turned on or off using
+
+ void
+ mal_trace(flag)
+
+ int flag;
+
+If flag is 0, tracing is turned off, (this is the default state), if
+it is non-zero, then tracing commences.
+
+The trace records are of the form:
+For a malloc,
+ + <nbytes> <realsize> <address>
+
+ where <nbytes> is the number of
+bytes requested, <realsize> is the number of bytes allocated (usually
+nbytes rounded up to a multiple of the word size, plus any slop if
+that is requested with mal_slopset), and <address> is the block
+returned.
+
+ If the malloc results in the system being asked for more memory,
+via sbrk(), it prints
+ sbrk <bytesobtained>
+where <bytesobtained> is the number of bytes the system was asked for.
+After the first such call, it will then print
+ heapstart <address>
+where <address> is the
+
+For a free,
+ - <realsize> <address>
+where <address> is the address of the block being freed
+and <realsize> is the malloc'ed size of the block. (the size requested
+by the user, rounded up to the word size with slop, if any)
+
+For a realloc, it may print out
+ the same as as a free if we're shrinking and the part of the
+block was freed
+
+ no-op
+ if we're shrinking and the remaining part of the block
+was too small to be freed, it prints
+
+ ++ <nbytes> <realsize> <address> <realsize_free> <address_free>
+where <nbytes> is the number of bytes requested, <realsize> is the actual
+number of bytes in the block returned, and <address> is the address of
+the block returned, <realsize_free> is the actual size of the free
+block after the one we're returning, which we grew into, <address_free>
+is the address of the free block after the one we're returning. The
+free block information is internal to the malloc and is of little use
+to the user.
+
+ the same as for a malloc and a free if the block ends up being
+copied to a new block.
+
+
+The trace records may be prefixed by the filename and linenumber of
+the call is the source if the file malloc.h was included and the C
+preprocessor symbol MALLOC_TRACE defined when compiling the program,
+and the malloc library was compield with the tracing option enabled.
+(Ask your system adminstrator, or whoever installed the malloc)
+(typically with the flag -DMALLOC_TRACE on the cc command line) This
+is advised - it makes debugging and leak tracing much easier.
+
+The file to which this information is printed can be set with
+
+ void
+ mal_setstatsfile(fd)
+
+ FILE *fd;
+
+The default is stderr.
+
+
+There are two variables in this malloc that can be set to tune
+performance somewhat, and keep memory fragmentation down. One is
+'slop', the other is the sbrk() size.
+
+ void
+ mal_slopset(slop)
+
+ int slop;
+
+The minimum size block allocated is slop. (The default for this is the
+minimum possible to maintain the heap pointers required for a free
+block, denoted by a slop of 0) If you notice however, that a lot of
+blocks are being used in a specific small size, or small range of
+small sizes, then you might want to increase slop so that slop is big
+enough to cover all those sizes - while this may waste some memory, it
+will speed up allocation for those sizes by guaranteeing that all
+blocks in the free list are at least that size, so the first fit
+becomes as fast as possible, and the memory fragmentation is reduced
+because of the more uniform block size.
+
+ void
+ mal_sbrkset(nbytes)
+
+ int nbytes;
+
+If there isn't a block large enough to supply a malloc request, then
+the allocator asks for the system to increase the data space of the
+process using the sbrk call. By default, sbrk() is called with 1K *
+sizeof(Word). (unless the malloc request is for a larger size) If your
+program uses less memory than this, you may want to reduce the size.
+On the other hand, in a program that allocates a lot of memory, to
+reduce the number of system calls, you may want to increase this size,
+using the mal_sbrkset() call.
+
+ Performance
+
+The 4.3 malloc, (variants of which are distributed with perl, tcsh,
+GNU and so on) is slightly faster than this malloc but it wastes more
+space because it allocates blocks in powers of 2. It does not coalesce
+free space, which can lead to it wasting lots of space. (There are some
+pathological allocation sequences where it will ask for more space
+from the system even though it has enough free space)
+
+The Sun malloc wastes somewhat less than this malloc, but is
+twice as slow, and causes more paging because it stores free blocks
+and their headers separately. It has debugging support similar to
+mal_verify() and mal_debug(), but not quite as thorough.
+
+The 4.1 malloc is much slower than this malloc, and wastes about the
+same space.
+
+ Incompatibilities
+
+There is only one serious incompatibility that I know of with some
+other malloc()s. In the old 4.1 malloc(), free was kept fast by not
+having it merge adjacent free blocks. This resulted in seriously
+fragmented arenas for programs that did a lot of allocation and
+freeing.
+
+The realloc() kludge provided a hook to force the merging of such
+blocks - the user called realloc() with a a block which had been freed.
+
+I think this practice is bad (Also, both ANSI and SVID do not support
+it) - since this malloc does a fast free that also merges the freed
+block to maintain the largest possible contiguous free blocks, there
+is no need for storage compaction. If compiled with -DDEBUG, this
+realloc() will die with an error if a freed block is passed to
+realloc() which would enable fixing programs that adhere to the old
+convention. If not compiled with -DDEBUG, it sets errno to EINVAL and
+returns NULL.
+
+ Memory leaks
+
+Some memory allocated by a program is meant for the entire lifetime of
+the program. (For many simple programs, this constitutes all the
+allocation done by the program, and this section does not apply to
+such programs) Some memory however is allocated for some time, and is
+later freed.
+
+Keeping track of memory to be freed is often a nuisance, and
+sometimes, programs may change the only pointer to an allocated block
+without freeing the block first. such unreferenced, but allocated
+memory is called "garbage" or a "memory leak", and is wasted, since
+the program has no way of finding it again. (Other languages, like
+Lisp, perform garbage collection frequently, finding all blocks that
+are unreferenced, and freeing them. In the Unix/C environment, this is
+difficult to do, even though garbage collecting mallocs exist. Even
+worse, it is often inefficient)
+
+Memory leaks are serious for programs that run for a long time -
+window managers, daemons, and suchlike, since the total memory wasted
+over time may be large. Meticulously freeing everything allocated
+by a program is the best solution - alas, for object-oriented
+programming styles, it becomes very hard to keep track of every object
+ever created so that open can free it.
+
+One method or providing temporary storage is the alloca() function.
+This is used to allocate space off the run-time stack so that it is
+automatically reclaimed upon procedure exit. It can therefore be used
+to provide temporary storage needed by a procedure and the procedures
+called by the procedure. Whether or not to use the alloca() call is a
+somewhat controversial matter. The manual page warns that
+ "alloca() is both machine- and compiler-dependent; its use is
+ discouraged."
+On the other hand, a fairly portable implementation using malloc() and
+free() does exist, and some compilers (eg) GNU cc provide a
+__builtin_alloca function, which they translate into a couple of
+machine instructions to extend the frame pointer in the appropriate
+direction. With these compilers, alloca() can be very fast - much
+faster than any other memory allocation technique short of statically
+allocated buffers.
+
+Alloca() still does not address the problem of storage which is needed
+temporarily, but which may be passed to a routine's parent.
+
+Another way for a programmer to trace what is going on is to define
+the preprocessor symbol MALLOC_TRACE (for example, with -DMALLOC_TRACE
+on the cc command line when compiling the program) and then include
+the header file "malloc.h" in the program. When MALLOC_TRACE is
+defined, this header redefines malloc() and friends to macros, which
+invoke _malloc() etc; the latter are routines which take the filename
+and linenumber at which they are called. Calling
+
+ void
+ mal_leaktrace(value)
+
+ int value;
+
+with value > 0 will start the leaktracing process, recording the
+address of each block returned by malloc, calloc, etc, along with the
+filename:linenumber at which it was called. If that block is freed, it
+deletes the record for that block. (Calling mal_leaktrace() with
+value == 0 turns off tracing)
+
+At any time, the programmer can call
+
+ void
+ mal_dumpleaktrace(fd)
+
+ FILE *fd;
+
+where fd is a file pointer onto a file openeed for writing with
+fopen() or freopen(), into which a list of unfreed blocks is dumped.
+This list is in the form
+
+ filename:linenumber: sequence-no. address-in-decimal (address-in-hex)
+
+This permits the programmer to examine the places in the program where
+blocks were allocated and not freed. These represent potential memory
+leaks. (Several text-editors will understand this sort of output as
+output from grep -n, and will be able to load and step through these
+files, eg. Jove)
+
+Typically, memory leaks take place within the main loop of a program,
+so the general structure of the program may look something like
+
+ initialization allocation
+ while (something) {
+ things to do
+ }
+
+The initial allocation is at worst a one-time memory wastage and does
+not concern us that much. Memory that is allocated inside the loop,
+and is not freed does concern us since it is a continuous loss, so
+after the initialization allocation, we insert a call to
+mal_leaktrace() to start tracing. When the second iteration starts,
+we call mal_dumpleaktrace() to dump the blocks that were presumably
+allocated during the first iteration and have not yet been freed, and
+do the same at the start of the third iteration for unfreed blocks
+from the second iteration and so on. The code now looks something like
+
+ initialization allocation
+ mal_leaktrace(1);
+ while(something) {
+ mal_dumpleaktrace(stderr);
+ things to do;
+ }
+
+The above is a simple example - more complex control-flow may require
+turning leak tracing on and off repeatedly, so as not to get deluged
+with information.
+
+If you use allocation functions within your code that layer on top of
+malloc, this leak tracing as it is will not be too useful since it
+will only report the location of your allocation functions. In that
+case, you have to define subsidiary allocation functions like
+_malloc() and #defines like those in the malloc.h file so that you can
+record the real address of the call. See the _malloc.c file and the
+malloc.h header for examples on how to do this. (You have to call the
+real allocation and then use the RECORD_FILE_AND_LINE() macro from
+trace.h to store the address of the allocated block. When you free the
+block you have to call the DELETE_RECORD() macro to remove that
+address. Do not include malloc.c in these files, and make sure you do
+call the real malloc from your allocation function - otherwise the
+allocation package will attempt to record the same address twice and
+fail) You may also want to include defs.h and then use PRTRACE() to
+print the line number and file name in the trace file.
diff --git a/lib/libmalloc/malloc.h b/lib/libmalloc/malloc.h
new file mode 100644
index 000000000000..f86ed22827ca
--- /dev/null
+++ b/lib/libmalloc/malloc.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright University of Toronto 1988, 1989, 1993.
+ * Written by Mark Moraes
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author and the University of Toronto are not responsible
+ * for the consequences of use of this software, no matter how awful,
+ * even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ * $Id: malloc.h,v 1.1 1994/03/06 22:59:49 nate Exp $
+ */
+#ifndef __XMALLOC_H__
+#define __XMALLOC_H__
+
+#if defined(ANSI_TYPES) || defined(__STDC__)
+#define univptr_t void *
+#else /* ! ANSI_TYPES */
+#define univptr_t char *
+#define size_t unsigned int
+#endif /* ANSI_TYPES */
+
+#if defined(ANSI_TYPES) && !defined(__STDC__)
+#define size_t unsigned long
+#endif
+
+#if defined(__STDC__)
+#define __proto(x) x
+#else
+#define __proto(x) ()
+#endif
+
+/*
+ * defined so users of new features of this malloc can #ifdef
+ * invocations of those features.
+ */
+#define CSRIMALLOC
+
+#ifdef MALLOC_TRACE
+/* Tracing malloc definitions - helps find leaks */
+
+extern univptr_t __malloc __proto((size_t, const char *, int));
+extern univptr_t __calloc __proto((size_t, size_t, const char *, int));
+extern univptr_t __realloc __proto((univptr_t, size_t, const char *, int));
+extern univptr_t __valloc __proto((size_t, const char *, int));
+extern univptr_t __memalign __proto((size_t, size_t, const char *, int));
+extern univptr_t __emalloc __proto((size_t, const char *, int));
+extern univptr_t __ecalloc __proto((size_t, size_t, const char *, int));
+extern univptr_t __erealloc __proto((univptr_t, size_t, const char *, int));
+extern char *__strdup __proto((const char *, const char *, int));
+extern char *__strsave __proto((const char *, const char *, int));
+extern void __free __proto((univptr_t, const char *, int));
+extern void __cfree __proto((univptr_t, const char *, int));
+
+#define malloc(x) __malloc((x), __FILE__, __LINE__)
+#define calloc(x, n) __calloc((x), (n), __FILE__, __LINE__)
+#define realloc(p, x) __realloc((p), (x), __FILE__, __LINE__)
+#define memalign(x, n) __memalign((x), (n), __FILE__, __LINE__)
+#define valloc(x) __valloc((x), __FILE__, __LINE__)
+#define emalloc(x) __emalloc((x), __FILE__, __LINE__)
+#define ecalloc(x, n) __ecalloc((x), (n), __FILE__, __LINE__)
+#define erealloc(p, x) __erealloc((p), (x), __FILE__, __LINE__)
+#define strdup(p) __strdup((p), __FILE__, __LINE__)
+#define strsave(p) __strsave((p), __FILE__, __LINE__)
+/* cfree and free are identical */
+#define cfree(p) __free((p), __FILE__, __LINE__)
+#define free(p) __free((p), __FILE__, __LINE__)
+
+#else /* MALLOC_TRACE */
+
+extern univptr_t malloc __proto((size_t));
+extern univptr_t calloc __proto((size_t, size_t));
+extern univptr_t realloc __proto((univptr_t, size_t));
+extern univptr_t valloc __proto((size_t));
+extern univptr_t memalign __proto((size_t, size_t));
+extern univptr_t emalloc __proto((size_t));
+extern univptr_t ecalloc __proto((size_t, size_t));
+extern univptr_t erealloc __proto((univptr_t, size_t));
+extern char *strdup __proto((const char *));
+extern char *strsave __proto((const char *));
+extern void free __proto((univptr_t));
+extern void cfree __proto((univptr_t));
+
+#endif /* MALLOC_TRACE */
+
+extern void mal_debug __proto((int));
+extern void mal_dumpleaktrace __proto((FILE *));
+extern void mal_heapdump __proto((FILE *));
+extern void mal_leaktrace __proto((int));
+extern void mal_sbrkset __proto((int));
+extern void mal_slopset __proto((int));
+extern void mal_statsdump __proto(());
+extern void mal_setstatsfile __proto((FILE *));
+extern void mal_trace __proto((int));
+extern int mal_verify __proto((int));
+extern void mal_mmap __proto((char *));
+
+
+/*
+ * You may or may not want this - In gcc version 1.30, on Sun3s running
+ * SunOS3.5, this works fine.
+ */
+#ifdef __GNUC__
+#define alloca(n) __builtin_alloca(n)
+#endif /* __GNUC__ */
+#ifdef sparc
+#define alloca(n) __builtin_alloca(n)
+#endif /* sparc */
+
+#ifdef ANSI_TYPES
+#undef univptr_t
+#else /* ! ANSI_TYPES */
+#undef univptr_t
+#undef size_t
+#endif /* ANSI_TYPES */
+
+/* Just in case you want an ANSI malloc without an ANSI compiler */
+#if defined(ANSI_TYPES) && !defined(__STDC__)
+#undef size_t
+#endif
+
+#undef __proto
+
+#endif /* __XMALLOC_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/memalign.c b/lib/libmalloc/memalign.c
new file mode 100644
index 000000000000..270aa4e62676
--- /dev/null
+++ b/lib/libmalloc/memalign.c
@@ -0,0 +1,160 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: memalign.c,v 1.1 1994/03/06 22:59:49 nate Exp $")
+
+/*
+ * !! memalign may leave small (< _malloc_minchunk) blocks as garbage.
+ * Not worth fixing now -- I've only seen two applications call valloc()
+ * or memalign(), and they do it only once in their life.
+ */
+/*
+ * This is needed to be compatible with Sun mallocs - Dunno how many
+ * programs need it - the X server sure does... Returns a block 'size'
+ * bytes long, such that the address is a multiple of 'alignment'.
+ * (alignment MUST be a power of 2). This routine is possibly more
+ * convoluted than free() - certainly uglier. Since it is rarely called
+ * - possibly once in a program, it should be ok. Since this is called
+ * from valloc() which is usually needed in conjunction with
+ * mmap()/munmap(), note the comment in the Sun manual page about
+ * freeing segments of size 128K and greater. Ugh.
+ */
+univptr_t
+memalign(alignment, size)
+size_t alignment, size;
+{
+ univptr_t cp;
+ univptr_t addr;
+ REGISTER Word *p0, *p1;
+ REGISTER size_t before, after;
+ size_t blksize;
+#ifdef DEBUG
+ int tmp_debugging = _malloc_debugging;
+#endif /* DEBUG */
+
+ if (alignment < sizeof(int) || !is_power_of_2(alignment) ||size == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+ if (alignment < sizeof(Word))
+ return(malloc(size)); /* We guarantee this alignment anyway */
+ /*
+ * Life starts to get complicated - need to get a block large
+ * enough to hold a block 'size' long, starting on an 'alignment'
+ * boundary
+ */
+ if ((cp = malloc((size_t) (size + alignment - 1))) == NULL)
+ return(NULL);
+ addr = SIMPLEALIGN(cp, alignment);
+ /*
+ * This is all we really need - can go back now, except that we
+ * might be wasting 'alignment - 1' bytes, which can be large since
+ * this junk is usually called to align with things like pagesize.
+ * So we try to push any free space before 'addr' and after 'addr +
+ * size' back on the free list by making the memaligned chunk
+ * ('addr' to 'addr + size') a block, and then doing stuff with the
+ * space left over - either making them free blocks or coelescing
+ * them whichever way is simplest. This usually involves making
+ * them look like allocated blocks and calling free() which has all
+ * the code to deal with this, and should do it reasonably fast.
+ */
+ p0 = (Word *) cp;
+ p0 -= HEADERWORDS;
+ /*
+ * p0 now points to the word tag starting the block which we got
+ * from malloc. This remains invariant from now on - p1 is our
+ * temporary pointer
+ */
+ p1 = (Word *) addr;
+ p1 -= HEADERWORDS;
+ blksize = (size + sizeof(Word) - 1) / sizeof(Word);
+ before = p1 - p0;
+ after = SIZE(p0) - ALLOC_OVERHEAD - blksize - before;
+ /*
+ * p1 now points to the word before addr - this is going to be the
+ * start of the memaligned block
+ */
+ if (after < _malloc_minchunk) {
+ /*
+ * We merge the extra space after the memaligned block into it
+ * since that space isn't enough for a separate block. Note
+ * that if the block after the one malloc returned is free, we
+ * might be able to merge the space into that block even if it
+ * is too small - unfortunately, free() won't accept a block of
+ * this size, and I don't want to do that code here, so we'll
+ * just let it go to waste in the memaligned block. !! fix later, maybe
+ */
+ blksize += after;
+ after = 0;
+ }
+ /*
+ * We mark the newly carved memaligned block p1 as alloced. addr is
+ * (p1 + 1) which is the address we'll return
+ */
+ SIZEFIELD(p1) = ALLOCMASK(blksize + ALLOC_OVERHEAD);
+ SIZEFIELD(p1 + blksize + ALLOC_OVERHEAD - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, size);
+ if (after > 0) {
+ /* We can now free the block after the memaligned block. */
+ p1 += blksize + ALLOC_OVERHEAD; /* SIZE(p1) */
+ /*
+ * p1 now points to the space after the memaligned block. we
+ * fix the size, mark it alloced, and call free - the block
+ * after this may be free, which isn't simple to coalesce - let
+ * free() do it.
+ */
+ SIZEFIELD(p1) = ALLOCMASK(after);
+ SIZEFIELD(p1 + after - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, (after - ALLOC_OVERHEAD) * sizeof(Word));
+#ifdef DEBUG
+ /* Full heap checking will break till we finish memalign */
+ _malloc_debugging = 0;
+#endif /* DEBUG */
+ free((univptr_t) (p1 + HEADERWORDS));
+ }
+ if (addr != cp) {
+ /*
+ * If what's 'before' is large enough to be freed, add p0 to
+ * free list after changing its size to just consist of the
+ * space before the memaligned block, also setting the
+ * alloced flag. Then call free() -- may merge with preceding
+ * block. (block after it is the memaligned block)
+ */
+ /*
+ * Else the space before the block is too small to form a
+ * free block, and the preceding block isn't free, so we
+ * aren't touching it. Theoretically, we could put it in
+ * the preceding alloc'ed block, but there are painful
+ * complications if this is the start of the arena. We
+ * pass, but MUST mark it as allocated. This sort of garbage
+ * can split up the arena -- fix later with special case maybe?!!
+ */
+ p1 = p0;
+ SIZEFIELD(p1) = ALLOCMASK(before);
+ SIZEFIELD(p1 + before - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, (before - ALLOC_OVERHEAD) * sizeof(Word));
+ if (before >= _malloc_minchunk) {
+ free(cp);
+ }
+ }
+#ifdef DEBUG
+ _malloc_debugging = tmp_debugging;
+#endif /* DEBUG */
+ return(addr);
+}
+
+/* Just following the Sun manual page here */
+univptr_t
+valloc(size)
+size_t size;
+{
+ static size_t pagesz = 0;
+
+ if (pagesz == 0)
+ pagesz = (size_t) getpagesize();
+ return(memalign(pagesz, size));
+}
diff --git a/lib/libmalloc/setopts.c b/lib/libmalloc/setopts.c
new file mode 100644
index 000000000000..d3ddb70f7c63
--- /dev/null
+++ b/lib/libmalloc/setopts.c
@@ -0,0 +1,120 @@
+/* Set various malloc options */
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: setopts.c,v 1.1 1994/03/06 22:59:50 nate Exp $")
+
+/*
+ * Sets debugging level - level 0 and 1 both perform normal checking -
+ * making sure a pointer is valid before it is used for any heap data,
+ * and doing consistency checking on any block it touches while it
+ * works. Level 2 asks for a mal_verify() on every malloc(), free() or
+ * realloc(), thus checking the entire heap's pointers for consistency.
+ * Level 3 makes mal_verify() check that all free blocks contain a
+ * magic pattern that is put into a free block when it is freed.
+ */
+void
+mal_debug(level)
+int level;
+{
+#ifdef DEBUG
+ if (level < 0 || level > 3) {
+ return;
+ }
+ _malloc_debugging = level;
+#endif /* DEBUG */
+}
+
+/*
+ * Allows you to control the number of system calls made, which might
+ * be helpful in a program allocating a lot of memory - call this once
+ * to set a number big enough to contain all the allocations. Or for
+ * very little allocation, so that you don't get a huge space just
+ * because you alloc'e a couple of strings
+ */
+void
+mal_sbrkset(n)
+int n;
+{
+ if (n < _malloc_minchunk * sizeof(Word)) {
+ /* sbrk'ing anything less than a Word isn't a great idea.*/
+ return;
+ }
+
+ _malloc_sbrkunits = (n + sizeof(Word) - 1) / sizeof(Word);
+ return;
+}
+
+/*
+ * Since the minimum size block allocated is sizeof(Word)*_malloc_minchunk,
+ * adjusting _malloc_minchunk is one way to control
+ * memory fragmentation, and if you do a lot of mallocs and frees of
+ * objects that have a similar size, then a good way to speed things up
+ * is to set _malloc_minchunk such that the minimum size block covers
+ * most of the objects you allocate
+ */
+void
+mal_slopset(n)
+int n;
+{
+ if (n < 0) {
+ return;
+ }
+
+ _malloc_minchunk = (n + sizeof(Word) - 1) / sizeof(Word) + FIXEDOVERHEAD;
+ return;
+}
+
+/*
+ * Sets the file used for verbose statistics to 'fd'. Does no
+ * verification whatsoever on the file descriptor
+ */
+void
+mal_setstatsfile(fd)
+FILE * fd;
+{
+ _malloc_statsfile = fd;
+ /*
+ * This file descriptor had better not have been written to before
+ * this
+ */
+ (void) setvbuf(fd, (char *) 0, _IONBF, 0);
+}
+
+/*
+ * Turns tracing on (if value != 0) or off, (if value == 0)
+ */
+void
+mal_trace(value)
+int value;
+{
+ if (value) {
+ /* Try to unbuffer the trace file */
+ (void) setvbuf(_malloc_statsfile, (char *) 0, _IONBF, 0);
+ /*
+ * Write something to the stats file so stdio can initialize
+ * its buffers i.e. call malloc() at least once while tracing
+ * is off, if the unbuffering failed.
+ */
+ (void) fputs("Malloc tracing starting\n", _malloc_statsfile);
+ _malloc_tracing = 1;
+ if (_malloc_loword != NULL) {
+ /*
+ * malloc happened before tracing turned on, so make
+ * sure we print the heap start for xmem analysis.
+ */
+ PRTRACE(sprintf(_malloc_statsbuf, "heapstart 0x%lx\n",
+ (ulong) _malloc_loword));
+ }
+ } else {
+ /* For symmetry */
+ (void) fputs("Malloc tracing stopped\n", _malloc_statsfile);
+ _malloc_tracing = 0;
+ }
+ (void) fflush(_malloc_statsfile);
+}
+
diff --git a/lib/libmalloc/sptree.c b/lib/libmalloc/sptree.c
new file mode 100644
index 000000000000..e7d28f00ab26
--- /dev/null
+++ b/lib/libmalloc/sptree.c
@@ -0,0 +1,763 @@
+/*
+ * This file contains a few splay tree routines snarfed from David
+ * Brower's package, with globals renamed to keep them internal to the
+ * malloc, and not clash with similar routines that the application may
+ * use. The comments have been left with the original names - most of
+ * the renaming just involved prepending an __ before the name -
+ * spinstall got remapped to __spadd. Function prototypes added for
+ * external declarations. - Mark Moraes.
+ */
+/*
+ * spdaveb.c -- daveb's new splay tree functions.
+ *
+ * The functions in this file provide an interface that is nearly
+ * the same as the hash library I swiped from mkmf, allowing
+ * replacement of one by the other. Hey, it worked for me!
+ *
+ * splookup() -- given a key, find a node in a tree.
+ * spinstall() -- install an item in the tree, overwriting existing value.
+ * spfhead() -- fast (non-splay) find the first node in a tree.
+ * spscan() -- forward scan tree from the head.
+ * spfnext() -- non-splaying next.
+ * spstats() -- make char string of stats for a tree.
+ *
+ * Written by David Brower, daveb@rtech.uucp 1/88.
+ */
+/*LINTLIBRARY*/
+
+#if defined(__STDC__) && defined(ANSI_TYPES)
+#include <stddef.h>
+#endif
+#include <stdio.h>
+
+#include "defs.h"
+
+# define COMPARE(a,b) (((char *) (a)) - ((char *) (b)))
+
+# include "sptree.h"
+
+/* insert item into the tree */
+static SPBLK * spenq proto((SPBLK *, SPTREE *));
+/* return and remove lowest item in subtree */
+static SPBLK * spdeq proto((SPBLK **));
+/* reorganize tree */
+static void splay proto((SPBLK *, SPTREE *));
+/* fast non-splaying head */
+static SPBLK * spfhead proto((SPTREE *));
+/* fast non-splaying next */
+static SPBLK * spfnext proto((SPBLK *));
+
+/* USER SUPPLIED! */
+
+extern univptr_t emalloc proto((size_t));
+
+
+/*----------------
+ *
+ * splookup() -- given key, find a node in a tree.
+ *
+ * Splays the found node to the root.
+ */
+SPBLK *
+__splookup( key, q )
+REGISTER univptr_t key;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK * n;
+ REGISTER int Sct;
+ REGISTER int c;
+
+ /* find node in the tree */
+ n = q->root;
+ c = ++(q->lkpcmps);
+ q->lookups++;
+ while( n && (Sct = COMPARE( key, n->key ) ) )
+ {
+ c++;
+ n = ( Sct < 0 ) ? n->leftlink : n->rightlink;
+ }
+ q->lkpcmps = c;
+
+ /* reorganize tree around this node */
+ if( n != NULL )
+ splay( n, q );
+
+ return( n );
+}
+
+
+
+/*----------------
+ *
+ * spinstall() -- install an entry in a tree, overwriting any existing node.
+ *
+ * If the node already exists, replace its contents.
+ * If it does not exist, then allocate a new node and fill it in.
+ */
+
+SPBLK *
+__spadd( key, data, datb, q )
+
+REGISTER univptr_t key;
+REGISTER univptr_t data;
+REGISTER univptr_t datb;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK *n;
+
+ if( NULL == ( n = __splookup( key, q ) ) )
+ {
+ n = (SPBLK *) emalloc( sizeof( *n ) );
+ n->key = (univptr_t) key;
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ n->uplink = NULL;
+ (void) spenq( n, q );
+ }
+
+ n->data = data;
+ n->datb = datb;
+
+ return( n );
+}
+
+
+
+
+/*----------------
+ *
+ * spfhead() -- return the "lowest" element in the tree.
+ *
+ * returns a reference to the head event in the event-set q.
+ * avoids splaying but just searches for and returns a pointer to
+ * the bottom of the left branch.
+ */
+static SPBLK *
+spfhead( q )
+
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ if( NULL != ( x = q->root ) )
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+
+ return( x );
+
+} /* spfhead */
+
+
+
+/*----------------
+ *
+ * spscan() -- apply a function to nodes in ascending order.
+ *
+ * if n is given, start at that node, otherwise start from
+ * the head.
+ */
+void
+__spscan( f, n, q )
+REGISTER void (*f)();
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * x;
+
+ for( x = n != NULL ? n : spfhead( q ); x != NULL ; x = spfnext( x ) )
+ (*f)( x );
+}
+
+
+/*----------------
+ *
+ * spfnext() -- fast return next higer item in the tree, or NULL.
+ *
+ * return the successor of n in q, represented as a splay tree.
+ * This is a fast (on average) version that does not splay.
+ */
+static SPBLK *
+spfnext( n )
+
+REGISTER SPBLK * n;
+
+{
+ REGISTER SPBLK * next;
+ REGISTER SPBLK * x;
+
+ /* a long version, avoids splaying for fast average,
+ * poor amortized bound
+ */
+
+ if( n == NULL )
+ return( n );
+
+ x = n->rightlink;
+ if( x != NULL )
+ {
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+ next = x;
+ }
+ else /* x == NULL */
+ {
+ x = n->uplink;
+ next = NULL;
+ while( x != NULL )
+ {
+ if( x->leftlink == n )
+ {
+ next = x;
+ x = NULL;
+ }
+ else
+ {
+ n = x;
+ x = n->uplink;
+ }
+ }
+ }
+
+ return( next );
+
+} /* spfnext */
+
+
+char *
+__spstats( q )
+SPTREE *q;
+{
+ static char buf[ 128 ];
+ float llen;
+ float elen;
+ float sloops;
+
+ if( q == NULL )
+ return("");
+
+ llen = q->lookups ? (float)q->lkpcmps / q->lookups : 0;
+ elen = q->enqs ? (float)q->enqcmps/q->enqs : 0;
+ sloops = q->splays ? (float)q->splayloops/q->splays : 0;
+
+ (void) sprintf(buf, "f(%d %4.2f) i(%d %4.2f) s(%d %4.2f)",
+ q->lookups, llen, q->enqs, elen, q->splays, sloops );
+
+ return buf;
+}
+
+/*
+ spaux.c: This code implements the following operations on an event-set
+ or priority-queue implemented using splay trees:
+
+ spdelete( n, q ) n is removed from q.
+
+ In the above, n and np are pointers to single items (type
+ SPBLK *); q is an event-set (type SPTREE *),
+ The type definitions for these are taken
+ from file sptree.h. All of these operations rest on basic
+ splay tree operations from file sptree.c.
+
+ The basic splay tree algorithms were originally presented in:
+
+ Self Adjusting Binary Trees,
+ by D. D. Sleator and R. E. Tarjan,
+ Proc. ACM SIGACT Symposium on Theory
+ of Computing (Boston, Apr 1983) 235-245.
+
+ The operations in this package supplement the operations from
+ file splay.h to provide support for operations typically needed
+ on the pending event set in discrete event simulation. See, for
+ example,
+
+ Introduction to Simula 67,
+ by Gunther Lamprecht, Vieweg & Sohn, Braucschweig, Wiesbaden, 1981.
+ (Chapter 14 contains the relevant discussion.)
+
+ Simula Begin,
+ by Graham M. Birtwistle, et al, Studentlitteratur, Lund, 1979.
+ (Chapter 9 contains the relevant discussion.)
+
+ Many of the routines in this package use the splay procedure,
+ for bottom-up splaying of the queue. Consequently, item n in
+ delete and item np in all operations listed above must be in the
+ event-set prior to the call or the results will be
+ unpredictable (eg: chaos will ensue).
+
+ Note that, in all cases, these operations can be replaced with
+ the corresponding operations formulated for a conventional
+ lexicographically ordered tree. The versions here all use the
+ splay operation to ensure the amortized bounds; this usually
+ leads to a very compact formulation of the operations
+ themselves, but it may slow the average performance.
+
+ Alternative versions based on simple binary tree operations are
+ provided (commented out) for head, next, and prev, since these
+ are frequently used to traverse the entire data structure, and
+ the cost of traversal is independent of the shape of the
+ structure, so the extra time taken by splay in this context is
+ wasted.
+
+ This code was written by:
+ Douglas W. Jones with assistance from Srinivas R. Sataluri
+
+ Translated to C by David Brower, daveb@rtech.uucp
+
+ Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ handling one-node trees. I botched the pascal translation of
+ a VAR parameter. Changed interface, so callers must also be
+ corrected to pass the node by address rather than value.
+ Mon Apr 3 15:18:32 PDT 1989 (daveb)
+ Apply fix supplied by Mark Moraes <moraes@csri.toronto.edu> to
+ spdelete(), which dropped core when taking out the last element
+ in a subtree -- that is, when the right subtree was empty and
+ the leftlink was also null, it tried to take out the leftlink's
+ uplink anyway.
+ */
+/*----------------
+ *
+ * spdelete() -- Delete node from a tree.
+ *
+ * n is deleted from q; the resulting splay tree has been splayed
+ * around its new root, which is the successor of n
+ *
+ */
+void
+__spdelete( n, q )
+
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ splay( n, q );
+ x = spdeq( &q->root->rightlink );
+ if( x == NULL ) /* empty right subtree */
+ {
+ q->root = q->root->leftlink;
+ if (q->root) q->root->uplink = NULL;
+ }
+ else /* non-empty right subtree */
+ {
+ x->uplink = NULL;
+ x->leftlink = q->root->leftlink;
+ x->rightlink = q->root->rightlink;
+ if( x->leftlink != NULL )
+ x->leftlink->uplink = x;
+ if( x->rightlink != NULL )
+ x->rightlink->uplink = x;
+ q->root = x;
+ }
+
+} /* spdelete */
+
+
+/*
+ *
+ * sptree.c: The following code implements the basic operations on
+ * an event-set or priority-queue implemented using splay trees:
+ *
+ * SPTREE *spinit( compare ) Make a new tree
+ * SPBLK *spenq( n, q ) Insert n in q after all equal keys.
+ * SPBLK *spdeq( np ) Return first key under *np, removing it.
+ * void splay( n, q ) n (already in q) becomes the root.
+ *
+ * In the above, n points to an SPBLK type, while q points to an
+ * SPTREE.
+ *
+ * The implementation used here is based on the implementation
+ * which was used in the tests of splay trees reported in:
+ *
+ * An Empirical Comparison of Priority-Queue and Event-Set Implementations,
+ * by Douglas W. Jones, Comm. ACM 29, 4 (Apr. 1986) 300-311.
+ *
+ * The changes made include the addition of the enqprior
+ * operation and the addition of up-links to allow for the splay
+ * operation. The basic splay tree algorithms were originally
+ * presented in:
+ *
+ * Self Adjusting Binary Trees,
+ * by D. D. Sleator and R. E. Tarjan,
+ * Proc. ACM SIGACT Symposium on Theory
+ * of Computing (Boston, Apr 1983) 235-245.
+ *
+ * The enq and enqprior routines use variations on the
+ * top-down splay operation, while the splay routine is bottom-up.
+ * All are coded for speed.
+ *
+ * Written by:
+ * Douglas W. Jones
+ *
+ * Translated to C by:
+ * David Brower, daveb@rtech.uucp
+ *
+ * Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ * handling one-node trees. I botched the pascal translation of
+ * a VAR parameter.
+ */
+/*----------------
+ *
+ * spinit() -- initialize an empty splay tree
+ *
+ */
+SPTREE *
+__spinit()
+{
+ REGISTER SPTREE * q;
+
+ q = (SPTREE *) emalloc( sizeof( *q ) );
+
+ q->lookups = 0;
+ q->lkpcmps = 0;
+ q->enqs = 0;
+ q->enqcmps = 0;
+ q->splays = 0;
+ q->splayloops = 0;
+ q->root = NULL;
+ return( q );
+}
+
+/*----------------
+ *
+ * spenq() -- insert item in a tree.
+ *
+ * put n in q after all other nodes with the same key; when this is
+ * done, n will be the root of the splay tree representing q, all nodes
+ * in q with keys less than or equal to that of n will be in the
+ * left subtree, all with greater keys will be in the right subtree;
+ * the tree is split into these subtrees from the top down, with rotations
+ * performed along the way to shorten the left branch of the right subtree
+ * and the right branch of the left subtree
+ */
+static SPBLK *
+spenq( n, q )
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * left; /* the rightmost node in the left tree */
+ REGISTER SPBLK * right; /* the leftmost node in the right tree */
+ REGISTER SPBLK * next; /* the root of the unsplit part */
+ REGISTER SPBLK * temp;
+
+ REGISTER univptr_t key;
+
+ q->enqs++;
+ n->uplink = NULL;
+ next = q->root;
+ q->root = n;
+ if( next == NULL ) /* trivial enq */
+ {
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ }
+ else /* difficult enq */
+ {
+ key = n->key;
+ left = n;
+ right = n;
+
+ /* n's left and right children will hold the right and left
+ splayed trees resulting from splitting on n->key;
+ note that the children will be reversed! */
+
+ q->enqcmps++;
+ if ( COMPARE( next->key, key ) > 0 )
+ goto two;
+
+ one: /* assert next->key <= key */
+
+ do /* walk to the right in the left tree */
+ {
+ temp = next->rightlink;
+ if( temp == NULL )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) > 0 )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ left = next;
+ next = temp;
+ goto two; /* change sides */
+ }
+
+ next->rightlink = temp->leftlink;
+ if( temp->leftlink != NULL )
+ temp->leftlink->uplink = next;
+ left->rightlink = temp;
+ temp->uplink = left;
+ temp->leftlink = next;
+ next->uplink = temp;
+ left = temp;
+ next = temp->rightlink;
+ if( next == NULL )
+ {
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) <= 0 ); /* change sides */
+
+ two: /* assert next->key > key */
+
+ do /* walk to the left in the right tree */
+ {
+ temp = next->leftlink;
+ if( temp == NULL )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) <= 0 )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ right = next;
+ next = temp;
+ goto one; /* change sides */
+ }
+ next->leftlink = temp->rightlink;
+ if( temp->rightlink != NULL )
+ temp->rightlink->uplink = next;
+ right->leftlink = temp;
+ temp->uplink = right;
+ temp->rightlink = next;
+ next->uplink = temp;
+ right = temp;
+ next = temp->leftlink;
+ if( next == NULL )
+ {
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) > 0 ); /* change sides */
+
+ goto one;
+
+ done: /* split is done, branches of n need reversal */
+
+ temp = n->leftlink;
+ n->leftlink = n->rightlink;
+ n->rightlink = temp;
+ }
+
+ return( n );
+
+} /* spenq */
+
+
+/*----------------
+ *
+ * spdeq() -- return and remove head node from a subtree.
+ *
+ * remove and return the head node from the node set; this deletes
+ * (and returns) the leftmost node from q, replacing it with its right
+ * subtree (if there is one); on the way to the leftmost node, rotations
+ * are performed to shorten the left branch of the tree
+ */
+static SPBLK *
+spdeq( np )
+
+SPBLK **np; /* pointer to a node pointer */
+
+{
+ REGISTER SPBLK * deq; /* one to return */
+ REGISTER SPBLK * next; /* the next thing to deal with */
+ REGISTER SPBLK * left; /* the left child of next */
+ REGISTER SPBLK * farleft; /* the left child of left */
+ REGISTER SPBLK * farfarleft; /* the left child of farleft */
+
+ if( np == NULL || *np == NULL )
+ {
+ deq = NULL;
+ }
+ else
+ {
+ next = *np;
+ left = next->leftlink;
+ if( left == NULL )
+ {
+ deq = next;
+ *np = next->rightlink;
+
+ if( *np != NULL )
+ (*np)->uplink = NULL;
+
+ }
+ else for(;;) /* left is not null */
+ {
+ /* next is not it, left is not NULL, might be it */
+ farleft = left->leftlink;
+ if( farleft == NULL )
+ {
+ deq = left;
+ next->leftlink = left->rightlink;
+ if( left->rightlink != NULL )
+ left->rightlink->uplink = next;
+ break;
+ }
+
+ /* next, left are not it, farleft is not NULL, might be it */
+ farfarleft = farleft->leftlink;
+ if( farfarleft == NULL )
+ {
+ deq = farleft;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ break;
+ }
+
+ /* next, left, farleft are not it, rotate */
+ next->leftlink = farleft;
+ farleft->uplink = next;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ farleft->rightlink = left;
+ left->uplink = farleft;
+ next = farleft;
+ left = farfarleft;
+ }
+ }
+
+ return( deq );
+
+} /* spdeq */
+
+
+/*----------------
+ *
+ * splay() -- reorganize the tree.
+ *
+ * the tree is reorganized so that n is the root of the
+ * splay tree representing q; results are unpredictable if n is not
+ * in q to start with; q is split from n up to the old root, with all
+ * nodes to the left of n ending up in the left subtree, and all nodes
+ * to the right of n ending up in the right subtree; the left branch of
+ * the right subtree and the right branch of the left subtree are
+ * shortened in the process
+ *
+ * this code assumes that n is not NULL and is in q; it can sometimes
+ * detect n not in q and complain
+ */
+
+static void
+splay( n, q )
+
+REGISTER SPBLK * n;
+SPTREE * q;
+
+{
+ REGISTER SPBLK * up; /* points to the node being dealt with */
+ REGISTER SPBLK * prev; /* a descendent of up, already dealt with */
+ REGISTER SPBLK * upup; /* the parent of up */
+ REGISTER SPBLK * upupup; /* the grandparent of up */
+ REGISTER SPBLK * left; /* the top of left subtree being built */
+ REGISTER SPBLK * right; /* the top of right subtree being built */
+
+ left = n->leftlink;
+ right = n->rightlink;
+ prev = n;
+ up = prev->uplink;
+
+ q->splays++;
+
+ while( up != NULL )
+ {
+ q->splayloops++;
+
+ /* walk up the tree towards the root, splaying all to the left of
+ n into the left subtree, all to right into the right subtree */
+
+ upup = up->uplink;
+ if( up->leftlink == prev ) /* up is to the right of n */
+ {
+ if( upup != NULL && upup->leftlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->leftlink = up->rightlink;
+ if( upup->leftlink != NULL )
+ upup->leftlink->uplink = upup;
+ up->rightlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->leftlink == upup )
+ upupup->leftlink = up;
+ else
+ upupup->rightlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->leftlink = right;
+ if( right != NULL )
+ right->uplink = up;
+ right = up;
+
+ }
+ else /* up is to the left of n */
+ {
+ if( upup != NULL && upup->rightlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->rightlink = up->leftlink;
+ if( upup->rightlink != NULL )
+ upup->rightlink->uplink = upup;
+ up->leftlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->rightlink == upup )
+ upupup->rightlink = up;
+ else
+ upupup->leftlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->rightlink = left;
+ if( left != NULL )
+ left->uplink = up;
+ left = up;
+ }
+ prev = up;
+ up = upup;
+ }
+
+# ifdef SPLAYDEBUG
+ if( q->root != prev )
+ {
+/* fprintf(stderr, " *** bug in splay: n not in q *** " ); */
+ abort();
+ }
+# endif
+
+ n->leftlink = left;
+ n->rightlink = right;
+ if( left != NULL )
+ left->uplink = n;
+ if( right != NULL )
+ right->uplink = n;
+ q->root = n;
+ n->uplink = NULL;
+
+} /* splay */
+
diff --git a/lib/libmalloc/sptree.h b/lib/libmalloc/sptree.h
new file mode 100644
index 000000000000..ea5a260d18df
--- /dev/null
+++ b/lib/libmalloc/sptree.h
@@ -0,0 +1,65 @@
+/*
+** sptree.h: The following type declarations provide the binary tree
+** representation of event-sets or priority queues needed by splay trees
+**
+** assumes that data and datb will be provided by the application
+** to hold all application specific information
+**
+** assumes that key will be provided by the application, comparable
+** with the compare function applied to the addresses of two keys.
+*/
+
+# ifndef SPTREE_H
+# define SPTREE_H
+
+typedef struct _spblk
+{
+ struct _spblk * leftlink;
+ struct _spblk * rightlink;
+ struct _spblk * uplink;
+
+ univptr_t key; /* formerly time/timetyp */
+ univptr_t data; /* formerly aux/auxtype */
+ univptr_t datb;
+} SPBLK;
+
+typedef struct
+{
+ SPBLK * root; /* root node */
+
+ /* Statistics, not strictly necessary, but handy for tuning */
+
+ int lookups; /* number of splookup()s */
+ int lkpcmps; /* number of lookup comparisons */
+
+ int enqs; /* number of spenq()s */
+ int enqcmps; /* compares in spenq */
+
+ int splays;
+ int splayloops;
+
+} SPTREE;
+
+#if defined(__STDC__)
+#define __proto(x) x
+#else
+#define __proto(x) ()
+#endif
+
+/* sptree.c */
+/* init tree */
+extern SPTREE * __spinit __proto((void));
+/* find key in a tree */
+extern SPBLK * __splookup __proto((univptr_t, SPTREE *));
+/* enter an item, allocating or replacing */
+extern SPBLK * __spadd __proto((univptr_t, univptr_t, univptr_t, SPTREE *));
+/* scan forward through tree */
+extern void __spscan __proto((void (*) __proto((SPBLK *)), SPBLK *, SPTREE *));
+/* return tree statistics */
+extern char *__spstats __proto((SPTREE *));
+/* delete node from tree */
+extern void __spdelete __proto((SPBLK *, SPTREE *));
+
+#undef __proto
+
+# endif /* SPTREE_H */
diff --git a/lib/libmalloc/stats.c b/lib/libmalloc/stats.c
new file mode 100644
index 000000000000..05ebb48ad869
--- /dev/null
+++ b/lib/libmalloc/stats.c
@@ -0,0 +1,38 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: stats.c,v 1.1 1994/03/06 22:59:53 nate Exp $")
+
+/*
+ * Dumps the distribution of allocated sizes we've gathered so far
+ */
+void
+mal_statsdump(fd)
+FILE *fd;
+{
+#ifdef PROFILESIZES
+ int i;
+ char buf[128];
+
+ for (i = 1; i < MAXPROFILESIZE; i++) {
+ if(_malloc_scount[i] > 0) {
+ (void) sprintf(buf, "%lu: %lu\n",(ulong)i*sizeof(Word),
+ (ulong) _malloc_scount[i]);
+ (void) fputs(buf, fd);
+ _malloc_scount[i] = 0;
+ }
+ }
+ if (_malloc_scount[0] > 0) {
+ (void) sprintf(buf, ">= %lu: %lu\n",
+ (ulong) MAXPROFILESIZE * sizeof(Word),
+ (ulong) _malloc_scount[0]);
+ (void) fputs(buf, fd);
+ _malloc_scount[0] = 0;
+ }
+ (void) fflush(fd);
+#endif /* PROFILESIZES */
+}
diff --git a/lib/libmalloc/strdup.c b/lib/libmalloc/strdup.c
new file mode 100644
index 000000000000..0e4a6bf24bb2
--- /dev/null
+++ b/lib/libmalloc/strdup.c
@@ -0,0 +1,26 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+
+RCSID("$Id: strdup.c,v 1.1 1994/03/06 22:59:54 nate Exp $")
+
+/*
+ * makes a copy of a null terminated string in malloc'ed storage.
+ * returns null if it fails.
+ */
+char *
+strdup(s)
+const char *s;
+{
+ char *cp;
+
+ if (s) {
+ cp = (char *) malloc((unsigned) (strlen(s)+1));
+ if (cp)
+ (void) strcpy(cp, s);
+ } else
+ cp = (char *) NULL;
+ return(cp);
+}
diff --git a/lib/libmalloc/strsave.c b/lib/libmalloc/strsave.c
new file mode 100644
index 000000000000..79fe856c4e45
--- /dev/null
+++ b/lib/libmalloc/strsave.c
@@ -0,0 +1,21 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+
+RCSID("$Id: strsave.c,v 1.1 1994/03/06 22:59:55 nate Exp $")
+
+/*
+ * makes a copy of a null terminated string in malloc'ed storage. Dies
+ * if enough memory isn't available or there is a malloc error
+ */
+char *
+strsave(s)
+const char *s;
+{
+ if (s)
+ return(strcpy(emalloc((size_t) (strlen(s)+1)),s));
+ else
+ return((char *) NULL);
+}
diff --git a/lib/libmalloc/tests/munge.sh b/lib/libmalloc/tests/munge.sh
new file mode 100755
index 000000000000..d9a23309c11c
--- /dev/null
+++ b/lib/libmalloc/tests/munge.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+# takes output of testrun and massages into columnar form for easier
+# evaluation and graphing
+cat $* | tr ',' ' ' |
+ awk 'BEGIN {
+ printf " Maxtime Maxsize Maxlife Sbrked Alloced Wastage";
+ printf " Real User Sys\n";
+ }
+ $1 == "Maxtime" {
+ if (t != 0) {
+ printf "%8d%8d%8d%8d%8d %7.2f", t, s, l, sb, ma, w;
+ printf " %7.1f %7.1f %7.1f\n", mr, mu, ms;
+ }
+ t = $3;
+ s = $6;
+ l = $9;
+ mr = 100000;
+ mu = 100000;
+ ms = 100000;
+ next;
+ }
+ $1 == "Sbrked" {
+ sb = $2;
+ ma = $4;
+ w = $6;
+ next;
+ }
+ $2 == "real" {
+ if ($1 < mr) mr = $1;
+ if ($3 < mu) mu = $3;
+ if ($5 < ms) ms = $5;
+ next;
+ }
+ END {
+ if (t != 0) {
+ printf "%8d%8d%8d%8d%8d %7.2f", t, s, l, sb, ma, w;
+ printf " %7.1f %7.1f %7.1f\n", mr, mu, ms;
+ }
+ }
+ '
diff --git a/lib/libmalloc/tests/plot.sh b/lib/libmalloc/tests/plot.sh
new file mode 100755
index 000000000000..74a8c8edd52e
--- /dev/null
+++ b/lib/libmalloc/tests/plot.sh
@@ -0,0 +1,81 @@
+#! /bin/sh
+# Things like
+# '-s 10 file...' should plot Maxlife vs Wastage, Real, user + sys for all
+# file for Maxsize == 10.
+# '-l 10 file...' should plot Maxsize vs ... for Maxlife == 10.
+usage="Usage: $0 [-s size | -l life] file..."
+case $# in
+[012])
+ echo $usage >&2
+ exit 1
+ ;;
+esac
+tmp=./tmp.$$
+case $1 in
+-s)
+ const='Maxsize'
+ indep='Maxlife'
+ units='iterations'
+ ;;
+-l)
+ const='Maxlife'
+ indep='Maxsize'
+ units='words'
+ ;;
+*)
+ echo $usage >&2
+ exit 1
+ ;;
+esac
+constval=$2
+shift
+shift
+mkdir $tmp
+for i
+do
+ base=`basename $i`
+ echo $base
+ ext=`expr "$base" : "res\.\(.*\)"`
+ awk '$1 == "Maxtime" {
+ for(i = 1; i <= NF; i++) {
+ field[$i] = i;
+ }
+ f1="'$tmp/W.$base'";
+ f2="'$tmp/R.$base'";
+ f3="'$tmp/US.$base'";
+ print "\"" "'$ext'" > f1
+ print "\"" "'$ext'" > f2
+ print "\"" "'$ext'" > f3
+ cfld=field["'$const'"];
+ cval='$constval';
+ xfld=field["'$indep'"];
+ y1=field["Wastage"];
+ y2=field["Real"];
+ y3=field["User"];
+ y4=field["Sys"];
+ }
+ $cfld == cval {
+ print $xfld, $y1 * 100 >> f1;
+ print $xfld, $y2 >> f2;
+ print $xfld, $y3 + $y4 >> f3;
+ }
+ END {
+ print "" >> f1;
+ print "" >> f2;
+ print "" >> f3;
+ }' $i
+done
+cat $tmp/W.* > $tmp/W
+rm -f $tmp/W.*
+cat $tmp/R.* > $tmp/R
+rm -f $tmp/R.*
+cat $tmp/US.* > $tmp/US
+rm -f $tmp/US.*
+cd $tmp
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'User + System time (seconds)' US &
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'Elapsed time (seconds)' R &
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'Wastage (percent of data segment)' W &
+
diff --git a/lib/libmalloc/tests/regress b/lib/libmalloc/tests/regress
new file mode 100755
index 000000000000..322aa608c196
--- /dev/null
+++ b/lib/libmalloc/tests/regress
@@ -0,0 +1,11 @@
+#! /bin/sh -x
+# testmalloc tests some unusual cases -- will test all branches in free,
+# which is important.
+./testmalloc $@
+# simumalloc makes a good thorough exercise for malloc and free.
+# need something for realloc, though.
+./simumalloc -t 15000 -s 1024 -l 2000 $@
+./simumalloc -t 5000 -s 512 -l 20 $@
+./simumalloc -d -t 500 -s 512 -l 20 $@
+./simumalloc -d -t 500 -s 512 -l 500 $@
+./simumalloc -d -t 500 -s 512 -a $@
diff --git a/lib/libmalloc/tests/simumalloc.c b/lib/libmalloc/tests/simumalloc.c
new file mode 100644
index 000000000000..f4607db3e453
--- /dev/null
+++ b/lib/libmalloc/tests/simumalloc.c
@@ -0,0 +1,239 @@
+/*
+ * To measure the speed of malloc - based on the algorithm described in
+ * "In Search of a Better Malloc" by David G. Korn and Kiem-Phong Vo,
+ * Usenix 1985. This is a vicious test of memory allocation, but does
+ * suffer from the problem that it asks for a uniform distribution of
+ * sizes - a more accurate distribution is a multi-normal distribution
+ * for all applications I've seen.
+ */
+/* Mark Moraes, CSRI, University of Toronto */
+#ifndef lint
+static char rcsid[] = "$Id: simumalloc.c,v 1.1 1994/03/06 23:01:46 nate Exp $";
+#endif /*lint*/
+
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * ANSI systems had better have this. Non-ANSI systems had better not
+ * complain about things that are implicitly declared int or void.
+ */
+#if defined(STDHEADERS)
+# include <stdlib.h>
+# include <unistd.h>
+#endif
+
+#include "malloc.h"
+
+char *progname;
+/* For getopt() */
+extern int getopt();
+extern int optind;
+extern char *optarg;
+
+
+int MaxTime, MaxLife, MaxSize, NumAllocs;
+
+typedef union u {
+ union u *ptr;
+ int size;
+} word;
+
+#define MAXTIME 100000
+static word *bufs[MAXTIME];
+
+unsigned long alloced = 0;
+static unsigned long maxalloced = 0;
+
+#ifdef HAVE_RANDOM
+extern long random();
+#define rnd(x) (random() % (long) (x))
+#define seedrnd(x) (srandom(x))
+#else /* ! HAVE_RANDOM */
+extern int rand();
+#define rnd(x) (rand() % (x))
+#define seedrnd(x) (srand(x))
+#endif /* HAVE_RANDOM */
+
+#ifdef MYMALLOC
+extern char * (* _malloc_memfunc)();
+#endif
+
+/*
+ * generally sprintf() to errstring and then call complain rather than
+ * use a varargs routine
+ */
+char errstring[128];
+
+/*
+ * Should probably have a more fancy version that does perror as well
+ * in a library someplace - like error()
+ */
+void
+complain(s)
+char *s;
+{
+ (void) fprintf(stderr, "%s: %s\n", progname, s);
+ exit(-1);
+}
+
+void
+usage()
+{
+ (void) fprintf(stderr, "\
+Usage: %s [-t MaxTime] [-s MaxSize] [-l MaxLife] [-m Mmapfile] [-a] [-d]\n", progname);
+ exit(-1);
+}
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int c;
+ register int t;
+ char *before, *after;
+ extern char *sbrk();
+ extern int atoi();
+ extern void freeall(), reserve();
+ unsigned long grew;
+ int alloconly = 0, use_mmap = 0, verbose = 0;
+
+ progname = argv[0] ? argv[0] : "(no-argv[0])";
+ NumAllocs = 1;
+ MaxTime = 15000;
+ MaxSize = 500;
+ MaxLife = 1000;
+ while((c = getopt(argc, argv, "n:t:s:l:dm:av")) != EOF) {
+ /* optarg has the current argument if the option was followed by ':'*/
+ switch (c) {
+ case 't':
+ MaxTime = atoi(optarg);
+ if (MaxTime < 0 || MaxTime > MAXTIME) {
+ (void) fprintf(stderr,
+ "%s: MaxTime must be > 0 and < %d\n", progname, MAXTIME);
+ exit(-1);
+ }
+ break;
+ case 's':
+ MaxSize = atoi(optarg);
+ if (MaxSize < 1)
+ complain("MaxSize must be > 0");
+ break;
+ case 'l':
+ MaxLife = atoi(optarg);
+ if (MaxLife < 0)
+ complain("MaxLife must be > 0");
+ break;
+ case 'n':
+ NumAllocs = atoi(optarg);
+ if (NumAllocs <= 0)
+ complain("NumAllocs must be > 0");
+ break;
+ case 'd':
+ /* Full heap debugging - S-L-O-W */
+#ifdef MYMALLOC
+ mal_debug(3);
+#endif
+ break;
+ case 'm':
+ use_mmap = 1;
+#ifdef MYMALLOC
+ mal_mmap(optarg);
+#else
+ complain("-m option needs CSRI malloc");
+#endif
+ break;
+ case 'a':
+ /* Only allocate -- no free */
+ alloconly = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case '?':
+ usage();
+ break;
+ }
+ }
+ /* Any filenames etc. after all the options */
+ if (optind < argc) {
+ usage();
+ }
+
+ for(t = 0; t < MaxTime; t++)
+ bufs[t] = 0;
+
+#ifdef MYMALLOC
+ before = (* _malloc_memfunc)(0);
+#else
+ before = sbrk(0);
+#endif
+ for(t = 0; t < MaxTime; t++) {
+ register int n;
+
+ for(n = rnd(NumAllocs) + 1; n > 0; n--) {
+ int s, l;
+
+ s = rnd(MaxSize) + 2;
+ l = rnd(MaxLife) + 1;
+ reserve(s, t + l);
+ }
+ if (! alloconly)
+ freeall(t);
+ }
+#ifdef MYMALLOC
+ after = (* _malloc_memfunc)(0);
+#else
+ after = sbrk(0);
+#endif
+ grew = after - before;
+ (void) sprintf(errstring, "Sbrked %ld, MaxAlloced %ld, Wastage %.2f\n",
+ grew, maxalloced * sizeof(word),
+ grew == 0 ? 0.0 :
+ (1.0 - ((double) maxalloced * sizeof(word)) / grew));
+ (void) write(1, errstring, strlen(errstring));
+#ifdef MYMALLOC
+ if (verbose)
+ (void) mal_statsdump(stderr);
+#endif
+ return 0;
+}
+
+/*
+ * Mallocs a block s words long, and adds it to the list of blocks to
+ * be freed at time tfree
+ */
+void
+reserve(s, tfree)
+int s;
+int tfree;
+{
+ word *wp;
+
+ wp = (word *) malloc(s * sizeof(word));
+ if (wp == NULL)
+ complain("Out of memory");
+ wp[0].ptr = bufs[tfree];
+ wp[1].size = s;
+ bufs[tfree] = wp;
+ alloced += s;
+ if (alloced > maxalloced)
+ maxalloced = alloced;
+}
+
+/* free all blocks whose lifetime expires at time t */
+void
+freeall(t)
+int t;
+{
+ word *wp;
+
+ wp = bufs[t];
+ while(wp != NULL) {
+ word *tmp = wp[0].ptr;
+ alloced -= wp[1].size;
+ free((char *) wp);
+ wp = tmp;
+ }
+}
diff --git a/lib/libmalloc/tests/t1.c b/lib/libmalloc/tests/t1.c
new file mode 100644
index 000000000000..7cdde93e4946
--- /dev/null
+++ b/lib/libmalloc/tests/t1.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+
+#define MAXALLOCS 1000
+#define SIZE 50
+
+extern char *sbrk();
+extern char *malloc();
+
+main()
+{
+ char *ptr[MAXALLOCS];
+ char *obrk, *nbrk;
+ int i;
+
+ obrk = sbrk(0);
+ printf("break is initially 0x%x\n", obrk);
+
+ for(i = 0; i < MAXALLOCS; i++) {
+ ptr[i] = malloc(SIZE);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked) after %d allocations of %d\n",
+ nbrk, nbrk - obrk, MAXALLOCS, SIZE);
+ for(i = 0; i < MAXALLOCS; i++) {
+ free(ptr[i]);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked) after freeing all allocations\n",
+ nbrk, nbrk - obrk);
+ fflush(stdout);
+
+ /* Should be enough memory for this without needing to sbrk */
+ (void) malloc(SIZE * (MAXALLOCS / 2));
+ nbrk = sbrk(0);
+
+ printf("break is 0x%x (%d bytes sbrked) after allocating %d\n",
+ nbrk, nbrk - obrk, SIZE * (MAXALLOCS/2));
+
+ exit(0);
+}
diff --git a/lib/libmalloc/tests/t2.c b/lib/libmalloc/tests/t2.c
new file mode 100644
index 000000000000..125c251e42b1
--- /dev/null
+++ b/lib/libmalloc/tests/t2.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+
+#define MAXALLOCS 100
+#define INC 50
+
+extern char *sbrk();
+extern char *malloc();
+
+main()
+{
+ char *ptr1, *ptr2;
+ char *obrk, *nbrk;
+ int i;
+ int small = 10;
+ int large = 128;
+
+ obrk = sbrk(0);
+ printf("break is initially 0x%x\n", obrk);
+
+ ptr1 = malloc(small);
+ ptr2 = malloc(small);
+ for(i = 0; i < MAXALLOCS; i++) {
+ (void) malloc(small);
+ free(ptr1);
+ ptr1 = malloc(large);
+ large += INC;
+ (void) malloc(small);
+ free(ptr2);
+ ptr2 = malloc(large);
+ large += INC;
+ mal_heapdump(stdout);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked)\n",
+ nbrk, nbrk - obrk);
+ exit(0);
+}
diff --git a/lib/libmalloc/tests/t3.c b/lib/libmalloc/tests/t3.c
new file mode 100644
index 000000000000..fdbc181e54f7
--- /dev/null
+++ b/lib/libmalloc/tests/t3.c
@@ -0,0 +1,110 @@
+/*
+Path: utstat!helios.physics.utoronto.ca!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!cs.utexas.edu!rice!sun-spots-request
+From: munsell!jwf@uunet.uu.net (Jim Franklin)
+Newsgroups: comp.sys.sun
+Subject: bug in SUN malloc()
+Keywords: Miscellaneous
+Message-ID: <4193@brazos.Rice.edu>
+Date: 4 Jan 90 13:05:06 GMT
+Sender: root@rice.edu
+Organization: Sun-Spots
+Lines: 95
+Approved: Sun-Spots@rice.edu
+X-Sun-Spots-Digest: Volume 9, Issue 4, message 10 of 12
+
+There is a bug in SUN's malloc() that causes it to sometimes attempt an
+sbrk() to grow the current process, even if there is a free block of the
+exact size available. The bug exists in OS 3.5 and 4.0.3, probably
+others.
+
+SUN's malloc() maintains the free list in a cartesian tree. The malloc()
+bug occurs when the root block is exactly equal in size to the requested
+allocation + alignment + overhead.
+
+malloc.c (416-427):
+> /-*
+> * ensure that at least one block is big enough to satisfy
+> * the request.
+> *-/
+>
+> if (weight(_root) <= nbytes) {
+> /-*
+> * the largest block is not enough.
+> *-/
+> if(!morecore(nbytes))
+> return 0;
+> }
+
+The '<=' should be '<'.
+
+The following 'malloc_bug' program illustrates the bug. Do a 'pstat -s'
+to see how much swap space you have, then run malloc_bug, requesting a
+chunk of memory at least 1/2 that size. E.g.,
+
+jwf@fechner #36 pstat -s
+8856k used (2120k text), 648872k free, 2776k wasted, 0k missing
+max process allocable = 229360k
+avail: 77*8192k 2*4096k 2*2048k 3*1024k 2*512k 3*256k 4*128k 3*64k 2*32k 4*16k 104*1k
+
+jwf@fechner #37 malloc_bug 200000000
+malloc_bug: requesting 200000000 bytes
+malloc_bug: got 200000000 bytes at 00022fd8
+malloc_bug: freeing 200000000 bytes
+malloc_bug: requesting 200000000 bytes
+malloc_bug: Not enough memory
+
+
+Jim Franklin, EPPS Inc., uunet!atexnet ---\
+32 Wiggins Ave., harvard!adelie ---+-- munsell!jwf
+Bedford, MA 01730 decvax!encore ---/
+(617) 276-7827
+
+
+*/
+#include <stdio.h>
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+ char *p;
+ unsigned int size;
+ int i;
+ extern char *malloc ();
+
+ if ( argc != 2 ) {
+ fprintf (stderr, "usage: malloc_bug <chunk_size>\n");
+ exit (-1);
+ }
+ size = atoi (argv[1]);
+ /* malloc our large chunk */
+
+ fprintf (stderr, "malloc_bug: requesting %d bytes\n", size);
+ p = malloc (size);
+ if ( p == NULL ) {
+ perror ("malloc_bug");
+ exit (-1);
+ }
+ fprintf (stderr, "malloc_bug: got %d bytes at %08x\n", size, p);
+
+ /* malloc a bunch of small trash to
+ try to use up any free fragments
+ near the large chunk */
+ for ( i = 0; i < 2000; i++ )
+ (void) malloc (8);
+ /* repeatedly free and malloc the
+ large chunk -- if this fails then
+ malloc is broken ... */
+ for (;;) {
+ fprintf (stderr, "malloc_bug: freeing %d bytes\n", size);
+ free (p);
+ fprintf (stderr, "malloc_bug: requesting %d bytes\n", size);
+ p = malloc (size);
+ if ( p == NULL ) {
+ perror ("malloc_bug");
+ exit (-1);
+ }
+ fprintf (stderr, "malloc_bug: got %d bytes at %08x\n", size, p);
+ }
+
+} /* main */
diff --git a/lib/libmalloc/tests/t4.c b/lib/libmalloc/tests/t4.c
new file mode 100644
index 000000000000..45161ad0cd49
--- /dev/null
+++ b/lib/libmalloc/tests/t4.c
@@ -0,0 +1,20 @@
+int
+main()
+{
+ char *cp;
+ int i;
+ int n = getpagesize();
+ extern char *malloc();
+
+ printf("pagesize = %d\n", n);
+
+ for(i = 0; i < 5; i++) {
+ cp = malloc(n);
+ printf("malloc(%d) returned 0x%x\n", n, cp);
+ cp = malloc(2*n);
+ printf("malloc(%d) returned 0x%x\n", 2*n, cp);
+ cp = malloc(4*n);
+ printf("malloc(%d) returned 0x%x\n", 4*n, cp);
+ }
+ return 0;
+}
diff --git a/lib/libmalloc/tests/t5.c b/lib/libmalloc/tests/t5.c
new file mode 100644
index 000000000000..f25df6045594
--- /dev/null
+++ b/lib/libmalloc/tests/t5.c
@@ -0,0 +1,31 @@
+/*
+ * posted to the net by someone who asked "Why is this causing malloc to
+ * dump core! Modified slightly to free the pointers, which causes my
+ * debugging malloc to find the bug. Turning on malloc_debug(2) also
+ * spots the problem.
+ */
+#include <stdio.h>
+
+int
+main()
+{
+ char *p[3], wd[128];
+ int len, i;
+ char *malloc();
+ int strlen();
+
+ strcpy(wd,"test");
+
+ for (i=0; i<3; i++) {
+ len = strlen(wd);
+ if ((p[i] = malloc(len)) == NULL) {
+ printf("ERROR: malloc failed\n");
+ exit(-1);
+ }
+ else
+ strcpy(p[i],wd);
+ }
+ for(i=0; i < 3; i++)
+ free(p[i]);
+ return 0;
+}
diff --git a/lib/libmalloc/tests/test.out b/lib/libmalloc/tests/test.out
new file mode 100644
index 000000000000..49d51d139cf6
--- /dev/null
+++ b/lib/libmalloc/tests/test.out
@@ -0,0 +1,415 @@
+Malloc tracing starting
+Test starting
+testmalloc.c:48:sbrk 4096
+heapstart 0x23108
+heapend 0x24100
++ 100 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:51:+ 150 152 0x23184
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x240fc, 952 (0x3b8) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:54:+ 191 192 0x23228
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Free blk: 0x232ec to 0x240fc, 901 (0x385) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:57:+ 2 4 0x232f4
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Free blk: 0x232fc to 0x240fc, 897 (0x381) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:60:+ 21 24 0x23304
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:63:+ 3540 3540 0x23328
+Heap printout:
+Rover pointer is 0x0
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Allocated blk: 0x23320 to 0x240fc, 888 (0x378) words really 3540 bytes
+==============
+testmalloc.c:67:- 3540 0x23328
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:69:- 192 0x23228
+Heap printout:
+Rover pointer is 0x232e8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x232e8, 51 (0x33) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232e8, prev=0x232e8
+==============
+testmalloc.c:71:- 4 0x232f4
+Heap printout:
+Rover pointer is 0x232f8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x232f8, 55 (0x37) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232f8, prev=0x232f8
+==============
+testmalloc.c:73:- 152 0x23184
+Heap printout:
+Rover pointer is 0x232f8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x232f8, 96 (0x60) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232f8, prev=0x232f8
+==============
+testmalloc.c:75:- 24 0x23304
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:77:- 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x240fc, 1021 (0x3fd) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:79:+ 100 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:82:+ 155 156 0x23184
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x240fc, 951 (0x3b7) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:85:sbrk 12288
+- 12276 0x24108
++ 8192 8192 0x2322c
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25230 to 0x270fc, 1972 (0x7b4) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:88:+ 100 100 0x25238
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Free blk: 0x252a0 to 0x270fc, 1944 (0x798) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:91:+ 29 32 0x252a8
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:94:- 8192 0x2322c
+Heap printout:
+Rover pointer is 0x2522c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x2522c, 2051 (0x803) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2522c, prev=0x2522c
+==============
+testmalloc.c:96:- 100 0x25238
+Heap printout:
+Rover pointer is 0x2529c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x2529c, 2079 (0x81f) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2529c, prev=0x2529c
+==============
+testmalloc.c:98:- 156 0x23184
+Heap printout:
+Rover pointer is 0x2529c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x2529c, 2121 (0x849) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2529c, prev=0x2529c
+==============
+testmalloc.c:100:- 32 0x252a8
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x270fc, 4065 (0xfe1) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:102:- 100 0x23114
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:105:+ 1005 1008 0x23114
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Free blk: 0x23508 to 0x270fc, 3838 (0xefe) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:108:+ 8192 8192 0x23510
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:111:sbrk 16384
+heapend 0x2b164
++ 16000 16000 0x27178
+Heap printout:
+Rover pointer is 0x2b160
+Arena from 0x27168 to 0x2b164, 4096 (0x1000) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2affc to 0x2b160, 90 (0x5a) words next=0x270fc, prev=0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2b160, prev=0x2b160
+==============
+testmalloc.c:114:+ 29 32 0x2b004
+Heap printout:
+Rover pointer is 0x2b160
+Arena from 0x27168 to 0x2b164, 4096 (0x1000) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2b160, 79 (0x4f) words next=0x270fc, prev=0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2b160, prev=0x2b160
+==============
+testmalloc.c:118:sbrk 77824
+- 77812 0x2b16c
++ 73727 73728 0x2b030
+- 4132 0x3c00c
+- 4036 0x2b030
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x3c000, 16387 (0x4003) words really 65536 bytes
+ Free blk: 0x3c004 to 0x3e160, 2136 (0x858) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:121:- 57524 0x2df4c
+Heap printout:
+Rover pointer is 0x3e160
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 8000 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:124:no-op
+Heap printout:
+Rover pointer is 0x3e160
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:127:- 1008 0x23114
+Heap printout:
+Rover pointer is 0x23504
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x23504, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x23504
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x23504, 255 (0xff) words next=0x3e160, prev=0x2bff4
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:129:- 8192 0x23510
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:131:- 32 0x2b004
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2affc to 0x2bff4, 1023 (0x3ff) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:133:- 16000 0x27178
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:135:++ 16000 16000 0x2c000 58080 0x2fe84
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2fe80, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2fe84 to 0x3e160, 14520 (0x38b8) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:138:++ 32000 32000 0x2c000 42080 0x33d04
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x33d00, 8003 (0x1f43) words really 32000 bytes
+ Free blk: 0x33d04 to 0x3e160, 10520 (0x2918) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+16: 1
+36: 1
+44: 2
+112: 3
+164: 1
+168: 1
+204: 1
+1020: 1
+3552: 1
+>= 8192: 4
+Test done
diff --git a/lib/libmalloc/tests/testmalloc.c b/lib/libmalloc/tests/testmalloc.c
new file mode 100644
index 000000000000..d037b5e1bf00
--- /dev/null
+++ b/lib/libmalloc/tests/testmalloc.c
@@ -0,0 +1,182 @@
+#if defined(STDHEADERS)
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+# include <unistd.h>
+#else
+# define u_int unsigned int
+extern char *memset();
+/* ignore some complaints about declarations. get ANSI headers */
+#endif
+
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Things to test. 1. first malloc. 2. couple of ordinary mallocs 3.
+ * ordinary frees 4. want check a free with prev. merge, next merge,
+ * both, and no merge, and one with empty free list. 5. malloc that
+ * requires sbrk. 6. malloc that requires an sbrk, after test
+ * program does non-contiguous sbrk to check if non-contigous arenas
+ * work. 7. valloc (this should test memalign as well) We should work
+ * out tests to check boundary conditions, when blocks at the start
+ * of the arena are allocated/freed, last free block is allocated...
+ */
+
+
+char *progname;
+/* For getopt() */
+extern int getopt();
+extern int optind;
+extern char *optarg;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ char *cp1;
+ char *cp2;
+ char *cp3;
+ char *cp4;
+ char *cp5;
+ char *cp6;
+ extern char *sbrk();
+ FILE *dumpfp = stdout;
+ int errs = 0, c;
+
+ progname = argv[0] ? argv[0] : "(no-argv[0])";
+ mal_debug(3);
+ mal_setstatsfile(stdout);
+ mal_trace(1);
+ while((c = getopt(argc, argv, "m:")) != EOF) {
+ /* optarg has the current argument if the option was followed by ':'*/
+ switch (c) {
+ case 'm':
+ mal_mmap(optarg);
+ break;
+ case '?':
+ errs++;
+ break;
+ }
+ }
+ if (optind < argc || errs > 0) {
+ fprintf(stderr, "Usage: %s [-m Mmapfile]\n", progname);
+ exit(1);
+ }
+ write(1, "Test starting\n", 14);
+ cp1 = (char *)malloc((u_int) 100);
+ (void) memset(cp1, 'A', 100);
+ mal_heapdump(dumpfp);
+ cp2 = (char *)calloc((u_int) 15, (u_int) 10);
+ (void) memset(cp2, 'B', 150);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)malloc((u_int) 191);
+ (void) memset(cp3, 'C', 191);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 2);
+ (void) memset(cp4, 'D', 2);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 21);
+ (void) memset(cp5, 'E', 21);
+ mal_heapdump(dumpfp);
+ cp6 = (char *)malloc((u_int) 3540);
+ (void) memset(cp6, 'P', 3540);
+ mal_heapdump(dumpfp);
+ /* On a machine where sizeof(Word) == 4, rover should be NULL here */
+ free(cp6);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)malloc((u_int) 100);
+ (void) memset(cp1, 'Q', 100);
+ mal_heapdump(dumpfp);
+ cp2 = (char *)malloc((u_int) 155);
+ (void) memset(cp2, 'F', 155);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)malloc((u_int) 8192);
+ (void) memset(cp3, 'G', 8192);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 100);
+ (void) memset(cp4, 'H', 100);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 29);
+ (void) memset(cp5, 'I', 29);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ cp1 = sbrk(100);
+ cp2 = (char *)malloc((u_int) 1005);
+ (void) memset(cp2, 'J', 1005);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)calloc((u_int) 1024, (u_int) 8);
+ (void) memset(cp3, 'K', 8192);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 16000);
+ (void) memset(cp4, 'L', 16000);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 29);
+ (void) memset(cp5, 'M', 29);
+ mal_heapdump(dumpfp);
+ /* !! Should really test memalign with various cases */
+ cp1 = (char *)valloc((u_int) 65536);
+ (void) memset(cp1, 'N', 65536);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 8000);
+ (void) memset(cp1, 'O', 8000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 7998);
+ (void) memset(cp1, 'T', 7998);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 16000);
+ (void) memset(cp1, 'R', 16000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 32000);
+ (void) memset(cp1, 'S', 32000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 1);
+ (void) memset(cp1, 'U', 1);
+ cp2 = (char *)malloc(60000);
+ (void) memset(cp2, 'V', 60000);
+ cp3 = (char *)malloc(18000);
+ (void) memset(cp3, 'W', 18000);
+ cp4 = (char *)malloc(18000);
+ (void) memset(cp4, 'W', 18000);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ mal_statsdump(dumpfp);
+ (void) write(1, "Test done\n", 10);
+ return 0;
+}
+
+#ifdef atarist
+getpagesize()
+{
+ return 8 * 1024;
+}
+#endif
diff --git a/lib/libmalloc/tests/testmemalign.c b/lib/libmalloc/tests/testmemalign.c
new file mode 100644
index 000000000000..2a5a729a9675
--- /dev/null
+++ b/lib/libmalloc/tests/testmemalign.c
@@ -0,0 +1,16 @@
+int
+main()
+{
+ extern char *memalign();
+ char *cp;
+
+ if ((cp = memalign(2, 1024)) == 0)
+ perror("memalign 2");
+ if ((cp = memalign(3, 1024)) == 0)
+ perror("memalign 3");
+ if ((cp = memalign(4, 1024)) == 0)
+ perror("memalign 4");
+
+ return 0;
+}
+
diff --git a/lib/libmalloc/tests/testrun.sh b/lib/libmalloc/tests/testrun.sh
new file mode 100755
index 000000000000..9da9568d2cdf
--- /dev/null
+++ b/lib/libmalloc/tests/testrun.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+time=time
+awk 'BEGIN {
+ maxtime = 15000;
+ maxsize = 610; isize = 50;
+ maxlife = 8010; ilife = 100;
+ hdrfmt = "echo \"Maxtime = %d, Maxsize = %d, Maxlife = %d\"\n";
+ fmt = "$time $cmd -t %d -s %d -l %d\n";
+ }
+ END {
+ for (i = 10; i < maxsize; i += isize) {
+ for (j = 10; j < maxlife; j += ilife) {
+ printf hdrfmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ }
+ }
+ }' /dev/null > /tmp/runs.$$
+for i
+do
+ ext=`expr "$i" : "simumalloc.exe\(.*\)"`
+ date
+ echo $i
+ cmd="./$i"
+ . /tmp/runs.$$ > times$ext 2>&1
+ date
+done
diff --git a/lib/libmalloc/tests/testsbrk.c b/lib/libmalloc/tests/testsbrk.c
new file mode 100644
index 000000000000..ff6c68d1bb45
--- /dev/null
+++ b/lib/libmalloc/tests/testsbrk.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+int incr = 201;
+char *cp;
+int i;
+
+main()
+{
+ extern char *sbrk();
+ int sz;
+
+ sz = getpagesize();
+ printf("pagesize is 0x%08x (%d)\n", sz, sz);
+ for(i = 0; i < 1000; i++) {
+ if ((cp = sbrk(incr)) == (char *) -1) {
+ fprintf(stderr, "Cannot sbrk further\n");
+ exit(-1);
+ }
+ printf("segment starts at 0x%08x, ends at 0x%08x\n", (int) cp,
+ (int) (cp + incr - 1));
+ }
+}
diff --git a/lib/libmalloc/tests/teststomp.c b/lib/libmalloc/tests/teststomp.c
new file mode 100644
index 000000000000..c591921144a9
--- /dev/null
+++ b/lib/libmalloc/tests/teststomp.c
@@ -0,0 +1,34 @@
+#if defined(STDHEADERS)
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+# include <unistd.h>
+#else
+# define u_int unsigned int
+extern char *memset();
+/* ignore some complaints about declarations. get ANSI headers */
+#endif
+
+#include <stdio.h>
+#include "malloc.h"
+
+int
+main(argc, argv)
+char **argv;
+int argc;
+{
+ char *cp;
+ int nbytes;
+
+ if (argc != 2) {
+ (void) fprintf(stderr, "Usage: %s nbytes\n", argv[0]);
+ exit(1);
+ }
+
+ nbytes = atoi(argv[1]);
+ cp = (char *) malloc(nbytes);
+ cp[nbytes] = 'a';
+ mal_verify(1);
+ /* We aren't going to get here, y'know... */
+ return 0;
+}
diff --git a/lib/libmalloc/trace.h b/lib/libmalloc/trace.h
new file mode 100644
index 000000000000..c3826dceca4b
--- /dev/null
+++ b/lib/libmalloc/trace.h
@@ -0,0 +1,19 @@
+#ifndef __TRACE_H__
+#define __TRACE_H__
+extern void __m_install_record proto((univptr_t, const char *));
+extern void __m_delete_record proto((univptr_t));
+
+#define RECORD_FILE_AND_LINE(addr, fname, linenum) \
+ if (_malloc_leaktrace) { \
+ (void) sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum); \
+ __m_install_record(addr, _malloc_statsbuf); \
+ } else \
+ _malloc_leaktrace += 0
+
+#define DELETE_RECORD(addr) \
+ if (_malloc_leaktrace) \
+ __m_delete_record(addr); \
+ else \
+ _malloc_leaktrace += 0
+
+#endif /* __TRACE_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/verify.c b/lib/libmalloc/verify.c
new file mode 100644
index 000000000000..9fbad097b986
--- /dev/null
+++ b/lib/libmalloc/verify.c
@@ -0,0 +1,81 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: verify.c,v 1.1 1994/03/06 22:59:57 nate Exp $")
+
+/*
+ * Goes through the entire heap checking all pointers, tags for
+ * consistency. Should catch most casual heap corruption (overwriting
+ * the end of a malloc'ed chunk, etc..) Nonetheless, heap corrupters
+ * tend to be devious and ingenious in ways they corrupt heaps (Believe
+ * me, I know:-). We should probably do the same thing if DEBUG is not
+ * defined, but return 0 instead of aborting. If fullcheck is non-zero,
+ * it also checks that free blocks contain the magic pattern written
+ * into them when they were freed to make sure the program is not still
+ * trying to access those blocks.
+ */
+int
+mal_verify(fullcheck)
+int fullcheck;
+{
+#ifdef DEBUG
+ REGISTER Word *ptr;
+ REGISTER Word *blk;
+ REGISTER Word *blkend;
+
+ if (_malloc_loword == NULL) /* Nothing malloc'ed yet */
+ return(0);
+
+ if (_malloc_rover != NULL) {
+ ASSERT(PTR_IN_HEAP(_malloc_rover),
+ "corrupt ROVER pointer found by mal_verify()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover),
+ "corrupt ROVER SIZE field found by mal_verify()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover),
+ "corrupt ROVER NEXT pointer found by mal_verify()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover),
+ "corrupt ROVER PREV pointer found by mal_verify()");
+ }
+ for(ptr = _malloc_mem; ptr != NULL; ptr = ptr->next) {
+ /*
+ * Check arena bounds - not same as checking block tags,
+ * despite similar appearance of the test
+ */
+ ASSERT(SIZEFIELD(ptr+1) == SIZEFIELD(ptr + SIZE(ptr+1)),
+ "corrupt malloc arena found by mal_verify");
+ blkend = ptr + SIZE(ptr + 1);
+ for(blk = ptr + ARENASTART; blk < blkend; blk += SIZE(blk)) {
+ ASSERT(PTR_IN_HEAP(blk), "corrupt pointer found by mal_verify()");
+ ASSERT(VALID_START_SIZE_FIELD(blk),
+ "corrupt SIZE field found by mal_verify()");
+ if (TAG(blk) == FREE) {
+ ASSERT(VALID_NEXT_PTR(blk + FREESIZE(blk) - 1),
+ "corrupt NEXT pointer found by mal_verify()");
+ ASSERT(VALID_PREV_PTR(blk + FREESIZE(blk) - 1),
+ "corrupt PREV pointer found by mal_verify()");
+ if (fullcheck) {
+ /* Make sure all free blocks are filled with FREEMAGIC */
+ int i, n;
+ char *cp;
+
+ n = (SIZE(blk) - FREE_OVERHEAD) *
+ sizeof(Word);
+ cp = (char *) (blk + FREEHEADERWORDS);
+ for (i = 0; i < n; i++, cp++) {
+ ASSERT(*cp == FREEMAGIC,
+ "corrupt free block found by mal_verify()");
+ }
+ }
+ } else {
+ ASSERT(VALID_MAGIC(blk),
+ "overwritten end of block found by mal_verify()");
+ }
+ }
+ }
+#endif /* DEBUG */
+ return(0);
+}
diff --git a/lib/libmalloc/version.c b/lib/libmalloc/version.c
new file mode 100644
index 000000000000..5752fb2c4220
--- /dev/null
+++ b/lib/libmalloc/version.c
@@ -0,0 +1 @@
+char *_malloc_version = "CSRI, University of Toronto Malloc Version 1.13beta";
diff --git a/lib/libpthread/include/stdio.h b/lib/libpthread/include/stdio.h
index 70a4265ae2ab..7e58f48875b5 100644
--- a/lib/libpthread/include/stdio.h
+++ b/lib/libpthread/include/stdio.h
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)stdio.h 5.17 (Berkeley) 6/3/91
- * $Id: stdio.h,v 1.1 1994/01/30 04:22:49 proven Exp $
+ * $Id: stdio.h,v 1.2 1994/04/09 15:34:53 ats Exp $
*/
#ifndef _STDIO_H_
@@ -296,6 +296,8 @@ __BEGIN_DECLS
int __srget __P((FILE *));
int __svfscanf __P((FILE *, const char *, va_list));
int __swbuf __P((int, FILE *));
+void flockfile(FILE *);
+void funlockfile(FILE *);
__END_DECLS
/*
diff --git a/lib/libpthread/stdio/fflush.c b/lib/libpthread/stdio/fflush.c
index b7f66c3b4a13..127040f0298e 100644
--- a/lib/libpthread/stdio/fflush.c
+++ b/lib/libpthread/stdio/fflush.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)fflush.c 5.1 (Berkeley) 1/20/91";*/
-static char *rcsid = "$Id: fflush.c,v 1.1 1994/01/30 04:24:37 proven Exp $";
+static char *rcsid = "$Id: fflush.c,v 1.2 1994/04/09 15:37:44 ats Exp $";
#endif /* LIBC_SCCS and not lint */
#include <pthread.h>
@@ -51,7 +51,7 @@ fflush(fp)
int retval;
if (fp == NULL)
- return (__swalk_sflush);
+ return (__swalk_sflush());
flockfile(fp);
if ((fp->_flags & (__SWR | __SRW)) == 0) {
diff --git a/lib/libpthread/stdio/ftell.c b/lib/libpthread/stdio/ftell.c
index d19e5825ad50..bf0eb4aa1769 100644
--- a/lib/libpthread/stdio/ftell.c
+++ b/lib/libpthread/stdio/ftell.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)ftell.c 5.4 (Berkeley) 2/5/91";*/
-static char *rcsid = "$Id: ftell.c,v 1.1 1994/01/30 04:25:01 proven Exp $";
+static char *rcsid = "$Id: ftell.c,v 1.2 1994/06/06 08:35:25 ats Exp $";
#endif /* LIBC_SCCS and not lint */
#include <pthread.h>
@@ -62,7 +62,7 @@ ftell(fp)
if (fp->_flags & __SOFF)
pos = fp->_offset;
else {
- pos = lseek(fp, (fpos_t)0, SEEK_CUR);
+ pos = lseek(fp->_file, (fpos_t)0, SEEK_CUR);
}
if (pos != -1L) {
diff --git a/lib/libpthread/stdio/vfprintf.c b/lib/libpthread/stdio/vfprintf.c
index 8b3d29e74e30..70bab40d6518 100644
--- a/lib/libpthread/stdio/vfprintf.c
+++ b/lib/libpthread/stdio/vfprintf.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
-static char *rcsid = "$Id: vfprintf.c,v 1.1 1994/01/30 04:25:51 proven Exp $";
+static char *rcsid = "$Id: vfprintf.c,v 1.2 1994/05/27 07:41:16 pst Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -473,7 +473,11 @@ reswitch: switch (ch) {
* -- ANSI X3J11
*/
/* NOSTRICT */
+#ifdef __i386
+ _uquad = (u_quad_t)(u_long)va_arg(ap, void *);
+#else
_uquad = (u_quad_t)va_arg(ap, void *);
+#endif
base = HEX;
xdigs = "0123456789abcdef";
flags |= HEXPREFIX;
diff --git a/lib/libskey/Makefile b/lib/libskey/Makefile
new file mode 100644
index 000000000000..ecf483333ce8
--- /dev/null
+++ b/lib/libskey/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.4 (Berkeley) 5/7/91
+
+LIB= skey
+SRCS= authfile.c md4.c put.c skey_crypt.c skeylogin.c skeysubr.c
+CFLAGS+=-DMPU8086
+.include <bsd.lib.mk>
+
diff --git a/lib/libskey/authfile.c b/lib/libskey/authfile.c
new file mode 100644
index 000000000000..ae7b0ace633d
--- /dev/null
+++ b/lib/libskey/authfile.c
@@ -0,0 +1,177 @@
+ /* Portions taken from the skey distribution on Oct 21 1993 */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <skey.h>
+
+#if (MAXHOSTNAMELEN < 64) /* AIX weirdness */
+#undef MAXHOSTNAMELEN
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 255
+#endif
+
+#include "pathnames.h"
+
+static int isaddr();
+static int rdnets();
+
+#define MAXADDR 16 /* how many addresses can a machine
+ * have? */
+
+ /*
+ * Turn host into an IP address and then look it up in the authorization
+ * database to determine if ordinary password logins are OK
+ */
+int authfile(host)
+char *host;
+{
+ char *addr[MAXADDR];
+ char **ap;
+ long n;
+ struct hostent *hp;
+ char **lp;
+ struct hostent *xp;
+ int addr_length;
+
+ if (strlen(host) == 0) {
+ /* Local login, okay */
+ return 1;
+ }
+ if (isaddr(host)) {
+ return rdnets(inet_addr(host));
+ } else {
+
+ /*
+ * Stash away a copy of the host address list because it will be
+ * clobbered by other gethostbyXXX() calls.
+ */
+
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ syslog(LOG_ERR, "unknown host: %s", host);
+ return 0;
+ }
+ if (hp->h_addrtype != AF_INET) {
+ syslog(LOG_ERR, "unknown network family: %d", hp->h_addrtype);
+ return 0;
+ }
+ for (lp = hp->h_addr_list, ap = addr; ap < addr + MAXADDR; lp++, ap++) {
+ if (*lp == NULL) {
+ *ap = 0;
+ break;
+ } else {
+ if ((*ap = malloc(hp->h_length)) == 0) {
+ syslog(LOG_ERR, "out of memory");
+ return 0;
+ }
+ memcpy(*ap, *lp, hp->h_length);
+ }
+ }
+ addr_length = hp->h_length;
+
+ /*
+ * See if any of the addresses matches a pattern in the control file.
+ * Report and skip the address if it does not belong to the remote
+ * host. Assume localhost == localhost.domain.
+ */
+
+#define NEQ(x,y) (strcasecmp((x),(y)) != 0)
+
+ while (ap-- > addr) {
+ memcpy((char *) &n, *ap, addr_length);
+ if (rdnets(n)) {
+ if ((hp = gethostbyaddr(*ap, addr_length, AF_INET)) == 0
+ || (NEQ(host, hp->h_name) && NEQ(host, "localhost"))) {
+ syslog(LOG_ERR, "IP address %s not registered for host %s",
+ inet_ntoa(*(struct in_addr *) * ap), host);
+ continue;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+static int rdnets(host)
+unsigned long host;
+{
+ FILE *fp;
+ char buf[128],
+ *cp;
+ long pattern,
+ mask;
+ char *strtok();
+ int permit_it = 0;
+
+ /*
+ * If auth file not found, be backwards compatible with standard login
+ * and allow hard coded passwords in from anywhere. Some may consider
+ * this a security hole, but backwards compatibility is more desirable
+ * than others. If you don't like it, change the return value to be zero.
+ */
+ if ((fp = fopen(_PATH_SKEYACCESS, "r")) == NULL)
+ return 1;
+
+ while (fgets(buf, sizeof(buf), fp), !feof(fp)) {
+ if (buf[0] == '#')
+ continue; /* Comment */
+ cp = strtok(buf, " \t");
+ if (cp == NULL)
+ continue;
+ /* two choices permit or deny */
+ if (strncasecmp(cp, "permit", 4) == 0) {
+ permit_it = 1;
+ } else {
+ if (strncasecmp(cp, "deny", 4) == 0) {
+ permit_it = 0;
+ } else {
+ continue; /* ignore this it is not
+ * permit/deny */
+ }
+ }
+ cp = strtok(NULL, " \t");
+ if (cp == NULL)
+ continue; /* Invalid line */
+ pattern = inet_addr(cp);
+ cp = strtok(NULL, " \t");
+ if (cp == NULL)
+ continue; /* Invalid line */
+ mask = inet_addr(cp);
+ if ((host & mask) == pattern) {
+ fclose(fp);
+ return permit_it;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+ /*
+ * Return TRUE if string appears to be an IP address in dotted decimal;
+ * return FALSE otherwise (i.e., if string is a domain name)
+ */
+static int isaddr(s)
+register char *s;
+{
+ char c;
+
+ if (s == NULL)
+ return 1; /* Can't happen */
+
+ while ((c = *s++) != '\0') {
+ if (c != '[' && c != ']' && !isdigit(c) && c != '.')
+ return 0;
+ }
+ return 1;
+}
diff --git a/lib/libskey/md4.c b/lib/libskey/md4.c
new file mode 100644
index 000000000000..495f4444e555
--- /dev/null
+++ b/lib/libskey/md4.c
@@ -0,0 +1,336 @@
+/*
+ * md4.c -- Implementation of MD4 Message Digest Algorithm
+ * Updated: 2/16/90 by Ronald L. Rivest
+ *
+ * Portability nits fixed and reformatted - 2/12/91 Phil Karn
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+/*
+ * To use MD4:
+ * -- Include md4.h in your program
+ * -- Declare an MDstruct MD to hold the state of the digest computation.
+ * -- Initialize MD using MDbegin(&MD)
+ * -- For each full block (64 bytes) X you wish to process, call
+ * MDupdate(&MD,X,512)
+ * (512 is the number of bits in a full block.)
+ * -- For the last block (less than 64 bytes) you wish to process,
+ * MDupdate(&MD,X,n)
+ * where n is the number of bits in the partial block. A partial
+ * block terminates the computation, so every MD computation should
+ * terminate by processing a partial block, even if it has n = 0.
+ * -- The message digest is available in MD.buffer[0] ... MD.buffer[3].
+ * (Least-significant byte of each word should be output first.)
+ * -- You can print out the digest using MDprint(&MD)
+ */
+
+/* Implementation notes:
+ * This implementation assumes that longs are 32-bit quantities.
+ * If the machine stores the least-significant byte of an long in the
+ * least-addressed byte (eg., VAX and 8086), then LOWBYTEFIRST should be
+ * set to TRUE. Otherwise (eg., SUNS), LOWBYTEFIRST should be set to
+ * FALSE. Note that on machines with LOWBYTEFIRST FALSE the routine
+ * MDupdate modifies has a side-effect on its input array (the order of bytes
+ * in each word are reversed). If this is undesired a call to MDreverse(X) can
+ * reverse the bytes of X back into order after each call to MDupdate.
+ */
+#define TRUE 1
+#define FALSE 0
+
+#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
+ || defined(vax) || defined (MIPSEL))
+#define LOWBYTEFIRST TRUE /* Low order bytes are first in memory */
+#else /* Almost all other machines are big-endian */
+#define LOWBYTEFIRST FALSE
+#endif
+
+
+/* Compile-time includes */
+#include <stdio.h>
+#include "md4.h"
+
+/* Compile-time declarations of MD4 ``magic constants'' */
+#define I0 0x67452301 /* Initial values for MD buffer */
+#define I1 0xefcdab89
+#define I2 0x98badcfe
+#define I3 0x10325476
+#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
+#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
+/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
+ * (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
+ * Table 2, page 660.
+ */
+#define fs1 3 /* round 1 shift amounts */
+#define fs2 7
+#define fs3 11
+#define fs4 19
+#define gs1 3 /* round 2 shift amounts */
+#define gs2 5
+#define gs3 9
+#define gs4 13
+#define hs1 3 /* round 3 shift amounts */
+#define hs2 9
+#define hs3 11
+#define hs4 15
+
+
+/* Compile-time macro declarations for MD4.
+ * Note: The ``rot'' operator uses the variable ``tmp''.
+ * It assumes tmp is declared as unsigned long, so that the >>
+ * operator will shift in zeros rather than extending the sign bit.
+ */
+#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
+#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
+#define h(X,Y,Z) (X^Y^Z)
+#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
+#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
+#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
+#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+
+void MDreverse __P((unsigned long *X));
+
+/* MDprint(MDp)
+ * Print message digest buffer MDp as 32 hexadecimal digits.
+ * Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
+ * Each byte is printed with high-order hexadecimal digit first.
+ * This is a user-callable routine.
+ */
+void
+MDprint(MDp)
+MDptr MDp;
+{
+ int i,j;
+
+ for(i=0;i<4;i++)
+ for(j=0;j<32;j=j+8)
+ printf("%02lx",(MDp->buffer[i]>>j) & 0xFF);
+}
+
+/* MDbegin(MDp)
+ * Initialize message digest buffer MDp.
+ * This is a user-callable routine.
+ */
+void
+MDbegin(MDp)
+MDptr MDp;
+{
+ int i;
+
+ MDp->buffer[0] = I0;
+ MDp->buffer[1] = I1;
+ MDp->buffer[2] = I2;
+ MDp->buffer[3] = I3;
+ for(i=0;i<8;i++)
+ MDp->count[i] = 0;
+ MDp->done = 0;
+}
+
+/* MDreverse(X)
+ * Reverse the byte-ordering of every long in X.
+ * Assumes X is an array of 16 longs.
+ * The macro revx reverses the byte-ordering of the next word of X.
+ */
+#define revx { t = (*X << 16) | (*X >> 16); \
+ *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
+void
+MDreverse(X)
+unsigned long *X;
+{
+ register unsigned long t;
+
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+}
+
+/* MDblock(MDp,X)
+ * Update message digest buffer MDp->buffer using 16-word data block X.
+ * Assumes all 16 words of X are full of data.
+ * Does not update MDp->count.
+ * This routine is not user-callable.
+ */
+static void
+MDblock(MDp,X)
+MDptr MDp;
+unsigned long *X;
+{
+ register unsigned long tmp, A, B, C, D;
+
+#if LOWBYTEFIRST == FALSE
+ MDreverse(X);
+#endif
+ A = MDp->buffer[0];
+ B = MDp->buffer[1];
+ C = MDp->buffer[2];
+ D = MDp->buffer[3];
+ /* Update the message digest buffer */
+ ff(A,B,C,D,0,fs1); /* Round 1 */
+ ff(D,A,B,C,1,fs2);
+ ff(C,D,A,B,2,fs3);
+ ff(B,C,D,A,3,fs4);
+ ff(A,B,C,D,4,fs1);
+ ff(D,A,B,C,5,fs2);
+ ff(C,D,A,B,6,fs3);
+ ff(B,C,D,A,7,fs4);
+ ff(A,B,C,D,8,fs1);
+ ff(D,A,B,C,9,fs2);
+ ff(C,D,A,B,10,fs3);
+ ff(B,C,D,A,11,fs4);
+ ff(A,B,C,D,12,fs1);
+ ff(D,A,B,C,13,fs2);
+ ff(C,D,A,B,14,fs3);
+ ff(B,C,D,A,15,fs4);
+ gg(A,B,C,D,0,gs1); /* Round 2 */
+ gg(D,A,B,C,4,gs2);
+ gg(C,D,A,B,8,gs3);
+ gg(B,C,D,A,12,gs4);
+ gg(A,B,C,D,1,gs1);
+ gg(D,A,B,C,5,gs2);
+ gg(C,D,A,B,9,gs3);
+ gg(B,C,D,A,13,gs4);
+ gg(A,B,C,D,2,gs1);
+ gg(D,A,B,C,6,gs2);
+ gg(C,D,A,B,10,gs3);
+ gg(B,C,D,A,14,gs4);
+ gg(A,B,C,D,3,gs1);
+ gg(D,A,B,C,7,gs2);
+ gg(C,D,A,B,11,gs3);
+ gg(B,C,D,A,15,gs4);
+ hh(A,B,C,D,0,hs1); /* Round 3 */
+ hh(D,A,B,C,8,hs2);
+ hh(C,D,A,B,4,hs3);
+ hh(B,C,D,A,12,hs4);
+ hh(A,B,C,D,2,hs1);
+ hh(D,A,B,C,10,hs2);
+ hh(C,D,A,B,6,hs3);
+ hh(B,C,D,A,14,hs4);
+ hh(A,B,C,D,1,hs1);
+ hh(D,A,B,C,9,hs2);
+ hh(C,D,A,B,5,hs3);
+ hh(B,C,D,A,13,hs4);
+ hh(A,B,C,D,3,hs1);
+ hh(D,A,B,C,11,hs2);
+ hh(C,D,A,B,7,hs3);
+ hh(B,C,D,A,15,hs4);
+ MDp->buffer[0] += A;
+ MDp->buffer[1] += B;
+ MDp->buffer[2] += C;
+ MDp->buffer[3] += D;
+}
+
+/* MDupdate(MDp,X,count)
+ * Input: MDp -- an MDptr
+ * X -- a pointer to an array of unsigned characters.
+ * count -- the number of bits of X to use.
+ * (if not a multiple of 8, uses high bits of last byte.)
+ * Update MDp using the number of bits of X given by count.
+ * This is the basic input routine for an MD4 user.
+ * The routine completes the MD computation when count < 512, so
+ * every MD computation should end with one call to MDupdate with a
+ * count less than 512. A call with count 0 will be ignored if the
+ * MD has already been terminated (done != 0), so an extra call with count
+ * 0 can be given as a ``courtesy close'' to force termination if desired.
+ */
+void
+MDupdate(MDp,X,count)
+MDptr MDp;
+unsigned char *X;
+unsigned int count;
+{
+ int i,bit,byte,mask;
+ unsigned long tmp;
+ unsigned char XX[64];
+ unsigned char *p;
+
+ /* return with no error if this is a courtesy close with count
+ * zero and MDp->done is true.
+ */
+ if(count == 0 && MDp->done)
+ return;
+ /* check to see if MD is already done and report error */
+ if(MDp->done){
+ printf("\nError: MDupdate MD already done.");
+ return;
+ }
+ /* Add count to MDp->count */
+ tmp = count;
+ p = MDp->count;
+ while(tmp){
+ tmp += *p;
+ *p++ = tmp;
+ tmp = tmp >> 8;
+ }
+ /* Process data */
+ if(count == 512){
+ /* Full block of data to handle */
+ MDblock(MDp,(unsigned long *)X);
+ } else if(count > 512){
+ /* Check for count too large */
+ printf("\nError: MDupdate called with illegal count value %ld.",count);
+ return;
+ } else {
+ /* partial block -- must be last block so finish up
+ * Find out how many bytes and residual bits there are
+ */
+ byte = count >> 3;
+ bit = count & 7;
+ /* Copy X into XX since we need to modify it */
+ for(i=0;i<=byte;i++)
+ XX[i] = X[i];
+ for(i=byte+1;i<64;i++)
+ XX[i] = 0;
+ /* Add padding '1' bit and low-order zeros in last byte */
+ mask = 1 << (7 - bit);
+ XX[byte] = (XX[byte] | mask) & ~( mask - 1);
+ /* If room for bit count, finish up with this block */
+ if(byte <= 55){
+ for(i=0;i<8;i++)
+ XX[56+i] = MDp->count[i];
+ MDblock(MDp,(unsigned long *)XX);
+ } else {
+ /* need to do two blocks to finish up */
+ MDblock(MDp,(unsigned long *)XX);
+ for(i=0;i<56;i++)
+ XX[i] = 0;
+ for(i=0;i<8;i++)
+ XX[56+i] = MDp->count[i];
+ MDblock(MDp,(unsigned long *)XX);
+ }
+ /* Set flag saying we're done with MD computation */
+ MDp->done = 1;
+ }
+}
+/* End of md4.c */
diff --git a/lib/libskey/md4.h b/lib/libskey/md4.h
new file mode 100644
index 000000000000..c0d341980a2c
--- /dev/null
+++ b/lib/libskey/md4.h
@@ -0,0 +1,47 @@
+
+#include <sys/cdefs.h>
+
+/*
+ *
+ * md4.h -- Header file for implementation of MD4 Message Digest Algorithm
+ * Updated: 2/13/90 by Ronald L. Rivest
+ * (C) 1990 RSA Data Security, Inc.
+ * Reformatted and de-linted - 2/12/91 Phil Karn
+ */
+
+/* MDstruct is the data structure for a message digest computation. */
+typedef struct {
+ unsigned long buffer[4];/* Holds 4-word result of MD computation */
+ unsigned char count[8]; /* Number of bits processed so far */
+ unsigned int done; /* Nonzero means MD computation finished */
+} MDstruct, *MDptr;
+
+/* MDbegin(MD)
+ * Input: MD -- an MDptr
+ * Initialize the MDstruct prepatory to doing a message digest computation.
+ */
+extern void MDbegin __P((MDptr MDp));
+
+/* MDupdate(MD,X,count)
+ * Input: MD -- an MDptr
+ * X -- a pointer to an array of unsigned characters.
+ * count -- the number of bits of X to use (an unsigned int).
+ * Updates MD using the first ``count'' bits of X.
+ * The array pointed to by X is not modified.
+ * If count is not a multiple of 8, MDupdate uses high bits of last byte.
+ * This is the basic input routine for a user.
+ * The routine terminates the MD computation when count < 512, so
+ * every MD computation should end with one call to MDupdate with a
+ * count less than 512. Zero is OK for a count.
+ */
+extern void MDupdate __P((MDptr MDp,unsigned char *X,unsigned int count));
+
+/* MDprint(MD)
+ * Input: MD -- an MDptr
+ * Prints message digest buffer MD as 32 hexadecimal digits.
+ * Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
+ * Each byte is printed with high-order hexadecimal digit first.
+ */
+extern void MDprint __P((MDptr MDp));
+
+/* End of md4.h */
diff --git a/lib/libskey/pathnames.h b/lib/libskey/pathnames.h
new file mode 100644
index 000000000000..763451901531
--- /dev/null
+++ b/lib/libskey/pathnames.h
@@ -0,0 +1,5 @@
+/* $Id: pathnames.h,v 1.1 1994/05/27 07:50:08 pst Exp $ (FreeBSD) */
+
+#include <paths.h>
+
+#define _PATH_SKEYACCESS "/etc/skey.access"
diff --git a/lib/libskey/put.c b/lib/libskey/put.c
new file mode 100644
index 000000000000..0f62d22499c1
--- /dev/null
+++ b/lib/libskey/put.c
@@ -0,0 +1,2289 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <skey.h>
+
+static unsigned long extract __P((char *s,int start,int length));
+static void standard __P((char *word));
+static void insert __P((char *s, int x, int start, int length));
+static int wsrch __P((char *w,int low,int high));
+
+/* Dictionary for integer-word translations */
+char Wp[2048][4] = {
+"A",
+"ABE",
+"ACE",
+"ACT",
+"AD",
+"ADA",
+"ADD",
+"AGO",
+"AID",
+"AIM",
+"AIR",
+"ALL",
+"ALP",
+"AM",
+"AMY",
+"AN",
+"ANA",
+"AND",
+"ANN",
+"ANT",
+"ANY",
+"APE",
+"APS",
+"APT",
+"ARC",
+"ARE",
+"ARK",
+"ARM",
+"ART",
+"AS",
+"ASH",
+"ASK",
+"AT",
+"ATE",
+"AUG",
+"AUK",
+"AVE",
+"AWE",
+"AWK",
+"AWL",
+"AWN",
+"AX",
+"AYE",
+"BAD",
+"BAG",
+"BAH",
+"BAM",
+"BAN",
+"BAR",
+"BAT",
+"BAY",
+"BE",
+"BED",
+"BEE",
+"BEG",
+"BEN",
+"BET",
+"BEY",
+"BIB",
+"BID",
+"BIG",
+"BIN",
+"BIT",
+"BOB",
+"BOG",
+"BON",
+"BOO",
+"BOP",
+"BOW",
+"BOY",
+"BUB",
+"BUD",
+"BUG",
+"BUM",
+"BUN",
+"BUS",
+"BUT",
+"BUY",
+"BY",
+"BYE",
+"CAB",
+"CAL",
+"CAM",
+"CAN",
+"CAP",
+"CAR",
+"CAT",
+"CAW",
+"COD",
+"COG",
+"COL",
+"CON",
+"COO",
+"COP",
+"COT",
+"COW",
+"COY",
+"CRY",
+"CUB",
+"CUE",
+"CUP",
+"CUR",
+"CUT",
+"DAB",
+"DAD",
+"DAM",
+"DAN",
+"DAR",
+"DAY",
+"DEE",
+"DEL",
+"DEN",
+"DES",
+"DEW",
+"DID",
+"DIE",
+"DIG",
+"DIN",
+"DIP",
+"DO",
+"DOE",
+"DOG",
+"DON",
+"DOT",
+"DOW",
+"DRY",
+"DUB",
+"DUD",
+"DUE",
+"DUG",
+"DUN",
+"EAR",
+"EAT",
+"ED",
+"EEL",
+"EGG",
+"EGO",
+"ELI",
+"ELK",
+"ELM",
+"ELY",
+"EM",
+"END",
+"EST",
+"ETC",
+"EVA",
+"EVE",
+"EWE",
+"EYE",
+"FAD",
+"FAN",
+"FAR",
+"FAT",
+"FAY",
+"FED",
+"FEE",
+"FEW",
+"FIB",
+"FIG",
+"FIN",
+"FIR",
+"FIT",
+"FLO",
+"FLY",
+"FOE",
+"FOG",
+"FOR",
+"FRY",
+"FUM",
+"FUN",
+"FUR",
+"GAB",
+"GAD",
+"GAG",
+"GAL",
+"GAM",
+"GAP",
+"GAS",
+"GAY",
+"GEE",
+"GEL",
+"GEM",
+"GET",
+"GIG",
+"GIL",
+"GIN",
+"GO",
+"GOT",
+"GUM",
+"GUN",
+"GUS",
+"GUT",
+"GUY",
+"GYM",
+"GYP",
+"HA",
+"HAD",
+"HAL",
+"HAM",
+"HAN",
+"HAP",
+"HAS",
+"HAT",
+"HAW",
+"HAY",
+"HE",
+"HEM",
+"HEN",
+"HER",
+"HEW",
+"HEY",
+"HI",
+"HID",
+"HIM",
+"HIP",
+"HIS",
+"HIT",
+"HO",
+"HOB",
+"HOC",
+"HOE",
+"HOG",
+"HOP",
+"HOT",
+"HOW",
+"HUB",
+"HUE",
+"HUG",
+"HUH",
+"HUM",
+"HUT",
+"I",
+"ICY",
+"IDA",
+"IF",
+"IKE",
+"ILL",
+"INK",
+"INN",
+"IO",
+"ION",
+"IQ",
+"IRA",
+"IRE",
+"IRK",
+"IS",
+"IT",
+"ITS",
+"IVY",
+"JAB",
+"JAG",
+"JAM",
+"JAN",
+"JAR",
+"JAW",
+"JAY",
+"JET",
+"JIG",
+"JIM",
+"JO",
+"JOB",
+"JOE",
+"JOG",
+"JOT",
+"JOY",
+"JUG",
+"JUT",
+"KAY",
+"KEG",
+"KEN",
+"KEY",
+"KID",
+"KIM",
+"KIN",
+"KIT",
+"LA",
+"LAB",
+"LAC",
+"LAD",
+"LAG",
+"LAM",
+"LAP",
+"LAW",
+"LAY",
+"LEA",
+"LED",
+"LEE",
+"LEG",
+"LEN",
+"LEO",
+"LET",
+"LEW",
+"LID",
+"LIE",
+"LIN",
+"LIP",
+"LIT",
+"LO",
+"LOB",
+"LOG",
+"LOP",
+"LOS",
+"LOT",
+"LOU",
+"LOW",
+"LOY",
+"LUG",
+"LYE",
+"MA",
+"MAC",
+"MAD",
+"MAE",
+"MAN",
+"MAO",
+"MAP",
+"MAT",
+"MAW",
+"MAY",
+"ME",
+"MEG",
+"MEL",
+"MEN",
+"MET",
+"MEW",
+"MID",
+"MIN",
+"MIT",
+"MOB",
+"MOD",
+"MOE",
+"MOO",
+"MOP",
+"MOS",
+"MOT",
+"MOW",
+"MUD",
+"MUG",
+"MUM",
+"MY",
+"NAB",
+"NAG",
+"NAN",
+"NAP",
+"NAT",
+"NAY",
+"NE",
+"NED",
+"NEE",
+"NET",
+"NEW",
+"NIB",
+"NIL",
+"NIP",
+"NIT",
+"NO",
+"NOB",
+"NOD",
+"NON",
+"NOR",
+"NOT",
+"NOV",
+"NOW",
+"NU",
+"NUN",
+"NUT",
+"O",
+"OAF",
+"OAK",
+"OAR",
+"OAT",
+"ODD",
+"ODE",
+"OF",
+"OFF",
+"OFT",
+"OH",
+"OIL",
+"OK",
+"OLD",
+"ON",
+"ONE",
+"OR",
+"ORB",
+"ORE",
+"ORR",
+"OS",
+"OTT",
+"OUR",
+"OUT",
+"OVA",
+"OW",
+"OWE",
+"OWL",
+"OWN",
+"OX",
+"PA",
+"PAD",
+"PAL",
+"PAM",
+"PAN",
+"PAP",
+"PAR",
+"PAT",
+"PAW",
+"PAY",
+"PEA",
+"PEG",
+"PEN",
+"PEP",
+"PER",
+"PET",
+"PEW",
+"PHI",
+"PI",
+"PIE",
+"PIN",
+"PIT",
+"PLY",
+"PO",
+"POD",
+"POE",
+"POP",
+"POT",
+"POW",
+"PRO",
+"PRY",
+"PUB",
+"PUG",
+"PUN",
+"PUP",
+"PUT",
+"QUO",
+"RAG",
+"RAM",
+"RAN",
+"RAP",
+"RAT",
+"RAW",
+"RAY",
+"REB",
+"RED",
+"REP",
+"RET",
+"RIB",
+"RID",
+"RIG",
+"RIM",
+"RIO",
+"RIP",
+"ROB",
+"ROD",
+"ROE",
+"RON",
+"ROT",
+"ROW",
+"ROY",
+"RUB",
+"RUE",
+"RUG",
+"RUM",
+"RUN",
+"RYE",
+"SAC",
+"SAD",
+"SAG",
+"SAL",
+"SAM",
+"SAN",
+"SAP",
+"SAT",
+"SAW",
+"SAY",
+"SEA",
+"SEC",
+"SEE",
+"SEN",
+"SET",
+"SEW",
+"SHE",
+"SHY",
+"SIN",
+"SIP",
+"SIR",
+"SIS",
+"SIT",
+"SKI",
+"SKY",
+"SLY",
+"SO",
+"SOB",
+"SOD",
+"SON",
+"SOP",
+"SOW",
+"SOY",
+"SPA",
+"SPY",
+"SUB",
+"SUD",
+"SUE",
+"SUM",
+"SUN",
+"SUP",
+"TAB",
+"TAD",
+"TAG",
+"TAN",
+"TAP",
+"TAR",
+"TEA",
+"TED",
+"TEE",
+"TEN",
+"THE",
+"THY",
+"TIC",
+"TIE",
+"TIM",
+"TIN",
+"TIP",
+"TO",
+"TOE",
+"TOG",
+"TOM",
+"TON",
+"TOO",
+"TOP",
+"TOW",
+"TOY",
+"TRY",
+"TUB",
+"TUG",
+"TUM",
+"TUN",
+"TWO",
+"UN",
+"UP",
+"US",
+"USE",
+"VAN",
+"VAT",
+"VET",
+"VIE",
+"WAD",
+"WAG",
+"WAR",
+"WAS",
+"WAY",
+"WE",
+"WEB",
+"WED",
+"WEE",
+"WET",
+"WHO",
+"WHY",
+"WIN",
+"WIT",
+"WOK",
+"WON",
+"WOO",
+"WOW",
+"WRY",
+"WU",
+"YAM",
+"YAP",
+"YAW",
+"YE",
+"YEA",
+"YES",
+"YET",
+"YOU",
+"ABED",
+"ABEL",
+"ABET",
+"ABLE",
+"ABUT",
+"ACHE",
+"ACID",
+"ACME",
+"ACRE",
+"ACTA",
+"ACTS",
+"ADAM",
+"ADDS",
+"ADEN",
+"AFAR",
+"AFRO",
+"AGEE",
+"AHEM",
+"AHOY",
+"AIDA",
+"AIDE",
+"AIDS",
+"AIRY",
+"AJAR",
+"AKIN",
+"ALAN",
+"ALEC",
+"ALGA",
+"ALIA",
+"ALLY",
+"ALMA",
+"ALOE",
+"ALSO",
+"ALTO",
+"ALUM",
+"ALVA",
+"AMEN",
+"AMES",
+"AMID",
+"AMMO",
+"AMOK",
+"AMOS",
+"AMRA",
+"ANDY",
+"ANEW",
+"ANNA",
+"ANNE",
+"ANTE",
+"ANTI",
+"AQUA",
+"ARAB",
+"ARCH",
+"AREA",
+"ARGO",
+"ARID",
+"ARMY",
+"ARTS",
+"ARTY",
+"ASIA",
+"ASKS",
+"ATOM",
+"AUNT",
+"AURA",
+"AUTO",
+"AVER",
+"AVID",
+"AVIS",
+"AVON",
+"AVOW",
+"AWAY",
+"AWRY",
+"BABE",
+"BABY",
+"BACH",
+"BACK",
+"BADE",
+"BAIL",
+"BAIT",
+"BAKE",
+"BALD",
+"BALE",
+"BALI",
+"BALK",
+"BALL",
+"BALM",
+"BAND",
+"BANE",
+"BANG",
+"BANK",
+"BARB",
+"BARD",
+"BARE",
+"BARK",
+"BARN",
+"BARR",
+"BASE",
+"BASH",
+"BASK",
+"BASS",
+"BATE",
+"BATH",
+"BAWD",
+"BAWL",
+"BEAD",
+"BEAK",
+"BEAM",
+"BEAN",
+"BEAR",
+"BEAT",
+"BEAU",
+"BECK",
+"BEEF",
+"BEEN",
+"BEER",
+"BEET",
+"BELA",
+"BELL",
+"BELT",
+"BEND",
+"BENT",
+"BERG",
+"BERN",
+"BERT",
+"BESS",
+"BEST",
+"BETA",
+"BETH",
+"BHOY",
+"BIAS",
+"BIDE",
+"BIEN",
+"BILE",
+"BILK",
+"BILL",
+"BIND",
+"BING",
+"BIRD",
+"BITE",
+"BITS",
+"BLAB",
+"BLAT",
+"BLED",
+"BLEW",
+"BLOB",
+"BLOC",
+"BLOT",
+"BLOW",
+"BLUE",
+"BLUM",
+"BLUR",
+"BOAR",
+"BOAT",
+"BOCA",
+"BOCK",
+"BODE",
+"BODY",
+"BOGY",
+"BOHR",
+"BOIL",
+"BOLD",
+"BOLO",
+"BOLT",
+"BOMB",
+"BONA",
+"BOND",
+"BONE",
+"BONG",
+"BONN",
+"BONY",
+"BOOK",
+"BOOM",
+"BOON",
+"BOOT",
+"BORE",
+"BORG",
+"BORN",
+"BOSE",
+"BOSS",
+"BOTH",
+"BOUT",
+"BOWL",
+"BOYD",
+"BRAD",
+"BRAE",
+"BRAG",
+"BRAN",
+"BRAY",
+"BRED",
+"BREW",
+"BRIG",
+"BRIM",
+"BROW",
+"BUCK",
+"BUDD",
+"BUFF",
+"BULB",
+"BULK",
+"BULL",
+"BUNK",
+"BUNT",
+"BUOY",
+"BURG",
+"BURL",
+"BURN",
+"BURR",
+"BURT",
+"BURY",
+"BUSH",
+"BUSS",
+"BUST",
+"BUSY",
+"BYTE",
+"CADY",
+"CAFE",
+"CAGE",
+"CAIN",
+"CAKE",
+"CALF",
+"CALL",
+"CALM",
+"CAME",
+"CANE",
+"CANT",
+"CARD",
+"CARE",
+"CARL",
+"CARR",
+"CART",
+"CASE",
+"CASH",
+"CASK",
+"CAST",
+"CAVE",
+"CEIL",
+"CELL",
+"CENT",
+"CERN",
+"CHAD",
+"CHAR",
+"CHAT",
+"CHAW",
+"CHEF",
+"CHEN",
+"CHEW",
+"CHIC",
+"CHIN",
+"CHOU",
+"CHOW",
+"CHUB",
+"CHUG",
+"CHUM",
+"CITE",
+"CITY",
+"CLAD",
+"CLAM",
+"CLAN",
+"CLAW",
+"CLAY",
+"CLOD",
+"CLOG",
+"CLOT",
+"CLUB",
+"CLUE",
+"COAL",
+"COAT",
+"COCA",
+"COCK",
+"COCO",
+"CODA",
+"CODE",
+"CODY",
+"COED",
+"COIL",
+"COIN",
+"COKE",
+"COLA",
+"COLD",
+"COLT",
+"COMA",
+"COMB",
+"COME",
+"COOK",
+"COOL",
+"COON",
+"COOT",
+"CORD",
+"CORE",
+"CORK",
+"CORN",
+"COST",
+"COVE",
+"COWL",
+"CRAB",
+"CRAG",
+"CRAM",
+"CRAY",
+"CREW",
+"CRIB",
+"CROW",
+"CRUD",
+"CUBA",
+"CUBE",
+"CUFF",
+"CULL",
+"CULT",
+"CUNY",
+"CURB",
+"CURD",
+"CURE",
+"CURL",
+"CURT",
+"CUTS",
+"DADE",
+"DALE",
+"DAME",
+"DANA",
+"DANE",
+"DANG",
+"DANK",
+"DARE",
+"DARK",
+"DARN",
+"DART",
+"DASH",
+"DATA",
+"DATE",
+"DAVE",
+"DAVY",
+"DAWN",
+"DAYS",
+"DEAD",
+"DEAF",
+"DEAL",
+"DEAN",
+"DEAR",
+"DEBT",
+"DECK",
+"DEED",
+"DEEM",
+"DEER",
+"DEFT",
+"DEFY",
+"DELL",
+"DENT",
+"DENY",
+"DESK",
+"DIAL",
+"DICE",
+"DIED",
+"DIET",
+"DIME",
+"DINE",
+"DING",
+"DINT",
+"DIRE",
+"DIRT",
+"DISC",
+"DISH",
+"DISK",
+"DIVE",
+"DOCK",
+"DOES",
+"DOLE",
+"DOLL",
+"DOLT",
+"DOME",
+"DONE",
+"DOOM",
+"DOOR",
+"DORA",
+"DOSE",
+"DOTE",
+"DOUG",
+"DOUR",
+"DOVE",
+"DOWN",
+"DRAB",
+"DRAG",
+"DRAM",
+"DRAW",
+"DREW",
+"DRUB",
+"DRUG",
+"DRUM",
+"DUAL",
+"DUCK",
+"DUCT",
+"DUEL",
+"DUET",
+"DUKE",
+"DULL",
+"DUMB",
+"DUNE",
+"DUNK",
+"DUSK",
+"DUST",
+"DUTY",
+"EACH",
+"EARL",
+"EARN",
+"EASE",
+"EAST",
+"EASY",
+"EBEN",
+"ECHO",
+"EDDY",
+"EDEN",
+"EDGE",
+"EDGY",
+"EDIT",
+"EDNA",
+"EGAN",
+"ELAN",
+"ELBA",
+"ELLA",
+"ELSE",
+"EMIL",
+"EMIT",
+"EMMA",
+"ENDS",
+"ERIC",
+"EROS",
+"EVEN",
+"EVER",
+"EVIL",
+"EYED",
+"FACE",
+"FACT",
+"FADE",
+"FAIL",
+"FAIN",
+"FAIR",
+"FAKE",
+"FALL",
+"FAME",
+"FANG",
+"FARM",
+"FAST",
+"FATE",
+"FAWN",
+"FEAR",
+"FEAT",
+"FEED",
+"FEEL",
+"FEET",
+"FELL",
+"FELT",
+"FEND",
+"FERN",
+"FEST",
+"FEUD",
+"FIEF",
+"FIGS",
+"FILE",
+"FILL",
+"FILM",
+"FIND",
+"FINE",
+"FINK",
+"FIRE",
+"FIRM",
+"FISH",
+"FISK",
+"FIST",
+"FITS",
+"FIVE",
+"FLAG",
+"FLAK",
+"FLAM",
+"FLAT",
+"FLAW",
+"FLEA",
+"FLED",
+"FLEW",
+"FLIT",
+"FLOC",
+"FLOG",
+"FLOW",
+"FLUB",
+"FLUE",
+"FOAL",
+"FOAM",
+"FOGY",
+"FOIL",
+"FOLD",
+"FOLK",
+"FOND",
+"FONT",
+"FOOD",
+"FOOL",
+"FOOT",
+"FORD",
+"FORE",
+"FORK",
+"FORM",
+"FORT",
+"FOSS",
+"FOUL",
+"FOUR",
+"FOWL",
+"FRAU",
+"FRAY",
+"FRED",
+"FREE",
+"FRET",
+"FREY",
+"FROG",
+"FROM",
+"FUEL",
+"FULL",
+"FUME",
+"FUND",
+"FUNK",
+"FURY",
+"FUSE",
+"FUSS",
+"GAFF",
+"GAGE",
+"GAIL",
+"GAIN",
+"GAIT",
+"GALA",
+"GALE",
+"GALL",
+"GALT",
+"GAME",
+"GANG",
+"GARB",
+"GARY",
+"GASH",
+"GATE",
+"GAUL",
+"GAUR",
+"GAVE",
+"GAWK",
+"GEAR",
+"GELD",
+"GENE",
+"GENT",
+"GERM",
+"GETS",
+"GIBE",
+"GIFT",
+"GILD",
+"GILL",
+"GILT",
+"GINA",
+"GIRD",
+"GIRL",
+"GIST",
+"GIVE",
+"GLAD",
+"GLEE",
+"GLEN",
+"GLIB",
+"GLOB",
+"GLOM",
+"GLOW",
+"GLUE",
+"GLUM",
+"GLUT",
+"GOAD",
+"GOAL",
+"GOAT",
+"GOER",
+"GOES",
+"GOLD",
+"GOLF",
+"GONE",
+"GONG",
+"GOOD",
+"GOOF",
+"GORE",
+"GORY",
+"GOSH",
+"GOUT",
+"GOWN",
+"GRAB",
+"GRAD",
+"GRAY",
+"GREG",
+"GREW",
+"GREY",
+"GRID",
+"GRIM",
+"GRIN",
+"GRIT",
+"GROW",
+"GRUB",
+"GULF",
+"GULL",
+"GUNK",
+"GURU",
+"GUSH",
+"GUST",
+"GWEN",
+"GWYN",
+"HAAG",
+"HAAS",
+"HACK",
+"HAIL",
+"HAIR",
+"HALE",
+"HALF",
+"HALL",
+"HALO",
+"HALT",
+"HAND",
+"HANG",
+"HANK",
+"HANS",
+"HARD",
+"HARK",
+"HARM",
+"HART",
+"HASH",
+"HAST",
+"HATE",
+"HATH",
+"HAUL",
+"HAVE",
+"HAWK",
+"HAYS",
+"HEAD",
+"HEAL",
+"HEAR",
+"HEAT",
+"HEBE",
+"HECK",
+"HEED",
+"HEEL",
+"HEFT",
+"HELD",
+"HELL",
+"HELM",
+"HERB",
+"HERD",
+"HERE",
+"HERO",
+"HERS",
+"HESS",
+"HEWN",
+"HICK",
+"HIDE",
+"HIGH",
+"HIKE",
+"HILL",
+"HILT",
+"HIND",
+"HINT",
+"HIRE",
+"HISS",
+"HIVE",
+"HOBO",
+"HOCK",
+"HOFF",
+"HOLD",
+"HOLE",
+"HOLM",
+"HOLT",
+"HOME",
+"HONE",
+"HONK",
+"HOOD",
+"HOOF",
+"HOOK",
+"HOOT",
+"HORN",
+"HOSE",
+"HOST",
+"HOUR",
+"HOVE",
+"HOWE",
+"HOWL",
+"HOYT",
+"HUCK",
+"HUED",
+"HUFF",
+"HUGE",
+"HUGH",
+"HUGO",
+"HULK",
+"HULL",
+"HUNK",
+"HUNT",
+"HURD",
+"HURL",
+"HURT",
+"HUSH",
+"HYDE",
+"HYMN",
+"IBIS",
+"ICON",
+"IDEA",
+"IDLE",
+"IFFY",
+"INCA",
+"INCH",
+"INTO",
+"IONS",
+"IOTA",
+"IOWA",
+"IRIS",
+"IRMA",
+"IRON",
+"ISLE",
+"ITCH",
+"ITEM",
+"IVAN",
+"JACK",
+"JADE",
+"JAIL",
+"JAKE",
+"JANE",
+"JAVA",
+"JEAN",
+"JEFF",
+"JERK",
+"JESS",
+"JEST",
+"JIBE",
+"JILL",
+"JILT",
+"JIVE",
+"JOAN",
+"JOBS",
+"JOCK",
+"JOEL",
+"JOEY",
+"JOHN",
+"JOIN",
+"JOKE",
+"JOLT",
+"JOVE",
+"JUDD",
+"JUDE",
+"JUDO",
+"JUDY",
+"JUJU",
+"JUKE",
+"JULY",
+"JUNE",
+"JUNK",
+"JUNO",
+"JURY",
+"JUST",
+"JUTE",
+"KAHN",
+"KALE",
+"KANE",
+"KANT",
+"KARL",
+"KATE",
+"KEEL",
+"KEEN",
+"KENO",
+"KENT",
+"KERN",
+"KERR",
+"KEYS",
+"KICK",
+"KILL",
+"KIND",
+"KING",
+"KIRK",
+"KISS",
+"KITE",
+"KLAN",
+"KNEE",
+"KNEW",
+"KNIT",
+"KNOB",
+"KNOT",
+"KNOW",
+"KOCH",
+"KONG",
+"KUDO",
+"KURD",
+"KURT",
+"KYLE",
+"LACE",
+"LACK",
+"LACY",
+"LADY",
+"LAID",
+"LAIN",
+"LAIR",
+"LAKE",
+"LAMB",
+"LAME",
+"LAND",
+"LANE",
+"LANG",
+"LARD",
+"LARK",
+"LASS",
+"LAST",
+"LATE",
+"LAUD",
+"LAVA",
+"LAWN",
+"LAWS",
+"LAYS",
+"LEAD",
+"LEAF",
+"LEAK",
+"LEAN",
+"LEAR",
+"LEEK",
+"LEER",
+"LEFT",
+"LEND",
+"LENS",
+"LENT",
+"LEON",
+"LESK",
+"LESS",
+"LEST",
+"LETS",
+"LIAR",
+"LICE",
+"LICK",
+"LIED",
+"LIEN",
+"LIES",
+"LIEU",
+"LIFE",
+"LIFT",
+"LIKE",
+"LILA",
+"LILT",
+"LILY",
+"LIMA",
+"LIMB",
+"LIME",
+"LIND",
+"LINE",
+"LINK",
+"LINT",
+"LION",
+"LISA",
+"LIST",
+"LIVE",
+"LOAD",
+"LOAF",
+"LOAM",
+"LOAN",
+"LOCK",
+"LOFT",
+"LOGE",
+"LOIS",
+"LOLA",
+"LONE",
+"LONG",
+"LOOK",
+"LOON",
+"LOOT",
+"LORD",
+"LORE",
+"LOSE",
+"LOSS",
+"LOST",
+"LOUD",
+"LOVE",
+"LOWE",
+"LUCK",
+"LUCY",
+"LUGE",
+"LUKE",
+"LULU",
+"LUND",
+"LUNG",
+"LURA",
+"LURE",
+"LURK",
+"LUSH",
+"LUST",
+"LYLE",
+"LYNN",
+"LYON",
+"LYRA",
+"MACE",
+"MADE",
+"MAGI",
+"MAID",
+"MAIL",
+"MAIN",
+"MAKE",
+"MALE",
+"MALI",
+"MALL",
+"MALT",
+"MANA",
+"MANN",
+"MANY",
+"MARC",
+"MARE",
+"MARK",
+"MARS",
+"MART",
+"MARY",
+"MASH",
+"MASK",
+"MASS",
+"MAST",
+"MATE",
+"MATH",
+"MAUL",
+"MAYO",
+"MEAD",
+"MEAL",
+"MEAN",
+"MEAT",
+"MEEK",
+"MEET",
+"MELD",
+"MELT",
+"MEMO",
+"MEND",
+"MENU",
+"MERT",
+"MESH",
+"MESS",
+"MICE",
+"MIKE",
+"MILD",
+"MILE",
+"MILK",
+"MILL",
+"MILT",
+"MIMI",
+"MIND",
+"MINE",
+"MINI",
+"MINK",
+"MINT",
+"MIRE",
+"MISS",
+"MIST",
+"MITE",
+"MITT",
+"MOAN",
+"MOAT",
+"MOCK",
+"MODE",
+"MOLD",
+"MOLE",
+"MOLL",
+"MOLT",
+"MONA",
+"MONK",
+"MONT",
+"MOOD",
+"MOON",
+"MOOR",
+"MOOT",
+"MORE",
+"MORN",
+"MORT",
+"MOSS",
+"MOST",
+"MOTH",
+"MOVE",
+"MUCH",
+"MUCK",
+"MUDD",
+"MUFF",
+"MULE",
+"MULL",
+"MURK",
+"MUSH",
+"MUST",
+"MUTE",
+"MUTT",
+"MYRA",
+"MYTH",
+"NAGY",
+"NAIL",
+"NAIR",
+"NAME",
+"NARY",
+"NASH",
+"NAVE",
+"NAVY",
+"NEAL",
+"NEAR",
+"NEAT",
+"NECK",
+"NEED",
+"NEIL",
+"NELL",
+"NEON",
+"NERO",
+"NESS",
+"NEST",
+"NEWS",
+"NEWT",
+"NIBS",
+"NICE",
+"NICK",
+"NILE",
+"NINA",
+"NINE",
+"NOAH",
+"NODE",
+"NOEL",
+"NOLL",
+"NONE",
+"NOOK",
+"NOON",
+"NORM",
+"NOSE",
+"NOTE",
+"NOUN",
+"NOVA",
+"NUDE",
+"NULL",
+"NUMB",
+"OATH",
+"OBEY",
+"OBOE",
+"ODIN",
+"OHIO",
+"OILY",
+"OINT",
+"OKAY",
+"OLAF",
+"OLDY",
+"OLGA",
+"OLIN",
+"OMAN",
+"OMEN",
+"OMIT",
+"ONCE",
+"ONES",
+"ONLY",
+"ONTO",
+"ONUS",
+"ORAL",
+"ORGY",
+"OSLO",
+"OTIS",
+"OTTO",
+"OUCH",
+"OUST",
+"OUTS",
+"OVAL",
+"OVEN",
+"OVER",
+"OWLY",
+"OWNS",
+"QUAD",
+"QUIT",
+"QUOD",
+"RACE",
+"RACK",
+"RACY",
+"RAFT",
+"RAGE",
+"RAID",
+"RAIL",
+"RAIN",
+"RAKE",
+"RANK",
+"RANT",
+"RARE",
+"RASH",
+"RATE",
+"RAVE",
+"RAYS",
+"READ",
+"REAL",
+"REAM",
+"REAR",
+"RECK",
+"REED",
+"REEF",
+"REEK",
+"REEL",
+"REID",
+"REIN",
+"RENA",
+"REND",
+"RENT",
+"REST",
+"RICE",
+"RICH",
+"RICK",
+"RIDE",
+"RIFT",
+"RILL",
+"RIME",
+"RING",
+"RINK",
+"RISE",
+"RISK",
+"RITE",
+"ROAD",
+"ROAM",
+"ROAR",
+"ROBE",
+"ROCK",
+"RODE",
+"ROIL",
+"ROLL",
+"ROME",
+"ROOD",
+"ROOF",
+"ROOK",
+"ROOM",
+"ROOT",
+"ROSA",
+"ROSE",
+"ROSS",
+"ROSY",
+"ROTH",
+"ROUT",
+"ROVE",
+"ROWE",
+"ROWS",
+"RUBE",
+"RUBY",
+"RUDE",
+"RUDY",
+"RUIN",
+"RULE",
+"RUNG",
+"RUNS",
+"RUNT",
+"RUSE",
+"RUSH",
+"RUSK",
+"RUSS",
+"RUST",
+"RUTH",
+"SACK",
+"SAFE",
+"SAGE",
+"SAID",
+"SAIL",
+"SALE",
+"SALK",
+"SALT",
+"SAME",
+"SAND",
+"SANE",
+"SANG",
+"SANK",
+"SARA",
+"SAUL",
+"SAVE",
+"SAYS",
+"SCAN",
+"SCAR",
+"SCAT",
+"SCOT",
+"SEAL",
+"SEAM",
+"SEAR",
+"SEAT",
+"SEED",
+"SEEK",
+"SEEM",
+"SEEN",
+"SEES",
+"SELF",
+"SELL",
+"SEND",
+"SENT",
+"SETS",
+"SEWN",
+"SHAG",
+"SHAM",
+"SHAW",
+"SHAY",
+"SHED",
+"SHIM",
+"SHIN",
+"SHOD",
+"SHOE",
+"SHOT",
+"SHOW",
+"SHUN",
+"SHUT",
+"SICK",
+"SIDE",
+"SIFT",
+"SIGH",
+"SIGN",
+"SILK",
+"SILL",
+"SILO",
+"SILT",
+"SINE",
+"SING",
+"SINK",
+"SIRE",
+"SITE",
+"SITS",
+"SITU",
+"SKAT",
+"SKEW",
+"SKID",
+"SKIM",
+"SKIN",
+"SKIT",
+"SLAB",
+"SLAM",
+"SLAT",
+"SLAY",
+"SLED",
+"SLEW",
+"SLID",
+"SLIM",
+"SLIT",
+"SLOB",
+"SLOG",
+"SLOT",
+"SLOW",
+"SLUG",
+"SLUM",
+"SLUR",
+"SMOG",
+"SMUG",
+"SNAG",
+"SNOB",
+"SNOW",
+"SNUB",
+"SNUG",
+"SOAK",
+"SOAR",
+"SOCK",
+"SODA",
+"SOFA",
+"SOFT",
+"SOIL",
+"SOLD",
+"SOME",
+"SONG",
+"SOON",
+"SOOT",
+"SORE",
+"SORT",
+"SOUL",
+"SOUR",
+"SOWN",
+"STAB",
+"STAG",
+"STAN",
+"STAR",
+"STAY",
+"STEM",
+"STEW",
+"STIR",
+"STOW",
+"STUB",
+"STUN",
+"SUCH",
+"SUDS",
+"SUIT",
+"SULK",
+"SUMS",
+"SUNG",
+"SUNK",
+"SURE",
+"SURF",
+"SWAB",
+"SWAG",
+"SWAM",
+"SWAN",
+"SWAT",
+"SWAY",
+"SWIM",
+"SWUM",
+"TACK",
+"TACT",
+"TAIL",
+"TAKE",
+"TALE",
+"TALK",
+"TALL",
+"TANK",
+"TASK",
+"TATE",
+"TAUT",
+"TEAL",
+"TEAM",
+"TEAR",
+"TECH",
+"TEEM",
+"TEEN",
+"TEET",
+"TELL",
+"TEND",
+"TENT",
+"TERM",
+"TERN",
+"TESS",
+"TEST",
+"THAN",
+"THAT",
+"THEE",
+"THEM",
+"THEN",
+"THEY",
+"THIN",
+"THIS",
+"THUD",
+"THUG",
+"TICK",
+"TIDE",
+"TIDY",
+"TIED",
+"TIER",
+"TILE",
+"TILL",
+"TILT",
+"TIME",
+"TINA",
+"TINE",
+"TINT",
+"TINY",
+"TIRE",
+"TOAD",
+"TOGO",
+"TOIL",
+"TOLD",
+"TOLL",
+"TONE",
+"TONG",
+"TONY",
+"TOOK",
+"TOOL",
+"TOOT",
+"TORE",
+"TORN",
+"TOTE",
+"TOUR",
+"TOUT",
+"TOWN",
+"TRAG",
+"TRAM",
+"TRAY",
+"TREE",
+"TREK",
+"TRIG",
+"TRIM",
+"TRIO",
+"TROD",
+"TROT",
+"TROY",
+"TRUE",
+"TUBA",
+"TUBE",
+"TUCK",
+"TUFT",
+"TUNA",
+"TUNE",
+"TUNG",
+"TURF",
+"TURN",
+"TUSK",
+"TWIG",
+"TWIN",
+"TWIT",
+"ULAN",
+"UNIT",
+"URGE",
+"USED",
+"USER",
+"USES",
+"UTAH",
+"VAIL",
+"VAIN",
+"VALE",
+"VARY",
+"VASE",
+"VAST",
+"VEAL",
+"VEDA",
+"VEIL",
+"VEIN",
+"VEND",
+"VENT",
+"VERB",
+"VERY",
+"VETO",
+"VICE",
+"VIEW",
+"VINE",
+"VISE",
+"VOID",
+"VOLT",
+"VOTE",
+"WACK",
+"WADE",
+"WAGE",
+"WAIL",
+"WAIT",
+"WAKE",
+"WALE",
+"WALK",
+"WALL",
+"WALT",
+"WAND",
+"WANE",
+"WANG",
+"WANT",
+"WARD",
+"WARM",
+"WARN",
+"WART",
+"WASH",
+"WAST",
+"WATS",
+"WATT",
+"WAVE",
+"WAVY",
+"WAYS",
+"WEAK",
+"WEAL",
+"WEAN",
+"WEAR",
+"WEED",
+"WEEK",
+"WEIR",
+"WELD",
+"WELL",
+"WELT",
+"WENT",
+"WERE",
+"WERT",
+"WEST",
+"WHAM",
+"WHAT",
+"WHEE",
+"WHEN",
+"WHET",
+"WHOA",
+"WHOM",
+"WICK",
+"WIFE",
+"WILD",
+"WILL",
+"WIND",
+"WINE",
+"WING",
+"WINK",
+"WINO",
+"WIRE",
+"WISE",
+"WISH",
+"WITH",
+"WOLF",
+"WONT",
+"WOOD",
+"WOOL",
+"WORD",
+"WORE",
+"WORK",
+"WORM",
+"WORN",
+"WOVE",
+"WRIT",
+"WYNN",
+"YALE",
+"YANG",
+"YANK",
+"YARD",
+"YARN",
+"YAWL",
+"YAWN",
+"YEAH",
+"YEAR",
+"YELL",
+"YOGA",
+"YOKE"
+};
+
+/* Encode 8 bytes in 'c' as a string of English words.
+ * Returns a pointer to a static buffer
+ */
+char *
+btoe(engout,c)
+char *c, *engout;
+{
+ char cp[9]; /* add in room for the parity 2 bits*/
+ int p,i ;
+
+ engout[0] = '\0';
+ memcpy(cp, c,8);
+ /* compute parity */
+ for(p = 0,i = 0; i < 64;i += 2)
+ p += extract(cp,i,2);
+
+ cp[8] = (char)p << 6;
+ strncat(engout,&Wp[extract(cp, 0,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,11,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,22,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,33,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,44,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,55,11)][0],4);
+#ifdef notdef
+ printf("engout is %s\n\r",engout);
+#endif
+ return(engout);
+}
+
+/* convert English to binary
+ * returns 1 OK - all good words and parity is OK
+ * 0 word not in data base
+ * -1 badly formed in put ie > 4 char word
+ * -2 words OK but parity is wrong
+ */
+int
+etob(out, e)
+char *out;
+char *e;
+{
+ char *word;
+ int i, p, v,l, low,high;
+ char b[9];
+ char input[36];
+
+ if(e == NULL)
+ return -1;
+
+ strncpy(input,e,sizeof(input));
+ memset(b, 0, sizeof(b));
+ memset(out, 0, 8);
+ for(i=0,p=0;i<6;i++,p+=11){
+ if((word = strtok(i == 0 ? input : NULL," ")) == NULL)
+ return -1;
+ l = strlen(word);
+ if(l > 4 || l < 1){
+ return -1;
+ } else if(l < 4){
+ low = 0;
+ high = 570;
+ } else {
+ low = 571;
+ high = 2047;
+ }
+ standard(word);
+ if( (v = wsrch(word,low,high)) < 0 )
+ return 0;
+ insert(b,v,p,11);
+ }
+
+ /* now check the parity of what we got */
+ for(p = 0, i = 0; i < 64; i +=2)
+ p += extract(b, i, 2);
+
+ if( (p & 3) != extract(b, 64,2) )
+ return -2;
+
+ memcpy(out,b,8);
+
+ return 1;
+}
+/* Display 8 bytes as a series of 16-bit hex digits */
+char *
+put8(out,s)
+char *out;
+char *s;
+{
+ sprintf(out,"%02X%02X %02X%02X %02X%02X %02X%02X",
+ s[0] & 0xff,s[1] & 0xff,s[2] & 0xff,
+ s[3] & 0xff,s[4] & 0xff,s[5] & 0xff,
+ s[6] & 0xff,s[7] & 0xff);
+ return out;
+}
+#ifdef notdef
+/* Encode 8 bytes in 'cp' as stream of ascii letters.
+ * Provided as a possible alternative to btoe()
+ */
+char *
+btoc(cp)
+char *cp;
+{
+ int i;
+ static char out[31];
+
+ /* code out put by characters 6 bits each added to 0x21 (!)*/
+ for(i=0;i <= 10;i++){
+ /* last one is only 4 bits not 6*/
+ out[i] = '!'+ extract(cp,6*i,i >= 10 ? 4:6);
+ }
+ out[i] = '\0';
+ return(out);
+}
+#endif
+
+/* Internal subroutines for word encoding/decoding */
+
+/* Dictionary binary search */
+static int
+wsrch(w,low,high)
+char *w;
+int low, high;
+{
+ int i,j;
+
+ for(;;){
+ i = (low + high)/2;
+ if((j = strncmp(w,Wp[i],4)) == 0)
+ return i; /* Found it */
+ if(high == low+1){
+ /* Avoid effects of integer truncation in /2 */
+ if(strncmp(w,Wp[high],4) == 0)
+ return high;
+ else
+ return -1;
+ }
+ if(low >= high)
+ return -1; /* I don't *think* this can happen...*/
+ if(j < 0)
+ high = i; /* Search lower half */
+ else
+ low = i; /* Search upper half */
+ }
+}
+static void
+insert(s, x, start, length)
+char *s;
+int x;
+int start, length;
+{
+ unsigned char cl;
+ unsigned char cc;
+ unsigned char cr;
+ unsigned long y;
+ int shift;
+
+ assert(length <= 11);
+ assert(start >= 0);
+ assert(length >= 0);
+ assert(start +length <= 66);
+
+ shift = ((8 -(( start + length) % 8))%8);
+ y = (long) x << shift;
+ cl = (y >> 16) & 0xff;
+ cc = (y >> 8) & 0xff;
+ cr = y & 0xff;
+ if(shift + length > 16){
+ s[start /8] |= cl;
+ s[start/8 +1] |= cc;
+ s[start/8 +2] |= cr;
+ } else if(shift +length > 8){
+ s[start/8] |= cc;
+ s[start/8 + 1] |= cr;
+ } else {
+ s[start/8] |= cr;
+ }
+}
+
+static void
+standard(word)
+register char *word;
+{
+ while(*word){
+ if(!isascii(*word))
+ break;
+ if(islower(*word))
+ *word = toupper(*word);
+ if(*word == '1')
+ *word = 'L';
+ if(*word == '0')
+ *word = 'O';
+ if(*word == '5')
+ *word = 'S';
+ word++;
+ }
+}
+
+/* Extract 'length' bits from the char array 's' starting with bit 'start' */
+static unsigned long
+extract(s, start, length)
+char *s;
+int start, length;
+{
+ unsigned char cl;
+ unsigned char cc;
+ unsigned char cr;
+ unsigned long x;
+
+ assert(length <= 11);
+ assert(start >= 0);
+ assert(length >= 0);
+ assert(start +length <= 66);
+
+ cl = s[start/8];
+ cc = s[start/8 +1];
+ cr = s[start/8 +2];
+ x = ((long)(cl<<8 | cc) <<8 | cr) ;
+ x = x >> (24 - (length + (start %8)));
+ x =( x & (0xffff >> (16-length) ) );
+ return(x);
+}
+
diff --git a/lib/libskey/skey_crypt.c b/lib/libskey/skey_crypt.c
new file mode 100644
index 000000000000..b61bef08c90b
--- /dev/null
+++ b/lib/libskey/skey_crypt.c
@@ -0,0 +1,37 @@
+/* Author: Wietse Venema, Eindhoven University of Technology. */
+
+#include <string.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <skey.h>
+
+/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */
+
+char *skey_crypt(pp, salt, pwd, pwok)
+char *pp;
+char *salt;
+struct passwd *pwd;
+int pwok;
+{
+ struct skey skey;
+ char *p;
+ char *crypt();
+
+ /* Try s/key authentication even when the UNIX password is permitted. */
+
+ if (pwd != 0 && skeylookup(&skey, pwd->pw_name) == 0
+ && skeyverify(&skey, pp) == 0) {
+ /* s/key authentication succeeded */
+ return (pwd->pw_passwd);
+ }
+
+ /* When s/key authentication does not work, always invoke crypt(). */
+
+ p = crypt(pp, salt);
+ if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0)
+ return (pwd->pw_passwd);
+
+ /* The user does not exist or entered bad input. */
+
+ return (":");
+}
diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c
new file mode 100644
index 000000000000..f2d41049e1d8
--- /dev/null
+++ b/lib/libskey/skeylogin.c
@@ -0,0 +1,328 @@
+/* Login code for S/KEY Authentication. S/KEY is a trademark
+ * of Bellcore.
+ *
+ * Mink is the former name of the S/KEY authentication system.
+ * Many references for mink may still be found in this program. */
+
+#include <sys/param.h>
+#ifdef QUOTA
+#include <sys/quota.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <skey.h>
+
+#define KEYFILE "/etc/skeykeys"
+
+char *skipspace();
+int skeylookup __P((struct skey *mp,char *name));
+
+#define setpriority(x,y,z) /* nothing */
+
+/* Issue a skey challenge for user 'name'. If successful,
+ * fill in the caller's skey structure and return 0. If unsuccessful
+ * (e.g., if name is unknown) return -1.
+ *
+ * The file read/write pointer is left at the start of the
+ * record.
+ */
+int
+getskeyprompt(mp,name,prompt)
+struct skey *mp;
+char *name;
+char *prompt;
+{
+ int rval;
+
+ sevenbit(name);
+ rval = skeylookup(mp,name);
+ strcpy(prompt,"s/key 55 latour1\n");
+ switch(rval){
+ case -1: /* File error */
+ return -1;
+ case 0: /* Lookup succeeded, return challenge */
+ sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed);
+ return 0;
+ case 1: /* User not found */
+ fclose(mp->keyfile);
+ return -1;
+ }
+ return -1; /* Can't happen */
+}
+/* Return a skey challenge string for user 'name'. If successful,
+ * fill in the caller's skey structure and return 0. If unsuccessful
+ * (e.g., if name is unknown) return -1.
+ *
+ * The file read/write pointer is left at the start of the
+ * record.
+ */
+int
+skeychallenge(mp,name, ss)
+struct skey *mp;
+char *name;
+char *ss;
+{
+ int rval;
+
+ rval = skeylookup(mp,name);
+ switch(rval){
+ case -1: /* File error */
+ return -1;
+ case 0: /* Lookup succeeded, issue challenge */
+ sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
+ return 0;
+ case 1: /* User not found */
+ fclose(mp->keyfile);
+ return -1;
+ }
+ return -1; /* Can't happen */
+}
+
+/* Find an entry in the One-time Password database.
+ * Return codes:
+ * -1: error in opening database
+ * 0: entry found, file R/W pointer positioned at beginning of record
+ * 1: entry not found, file R/W pointer positioned at EOF
+ */
+int
+skeylookup(mp,name)
+struct skey *mp;
+char *name;
+{
+ int found;
+ int len;
+ long recstart;
+ char *cp;
+ struct stat statbuf;
+
+ /* See if the KEYFILE exists, and create it if not */
+ if(stat(KEYFILE,&statbuf) == -1 && errno == ENOENT){
+ mp->keyfile = fopen(KEYFILE,"w+");
+ (void) chmod(KEYFILE, 0644);
+ } else {
+ /* Otherwise open normally for update */
+ mp->keyfile = fopen(KEYFILE,"r+");
+ }
+ if(mp->keyfile == NULL)
+ return -1;
+
+ /* Look up user name in database */
+ len = strlen(name);
+ if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */
+ found = 0;
+ while(!feof(mp->keyfile)){
+ recstart = ftell(mp->keyfile);
+ mp->recstart = recstart;
+ if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
+ break;
+ }
+ rip(mp->buf);
+ if(mp->buf[0] == '#')
+ continue; /* Comment */
+ if((mp->logname = strtok(mp->buf," \t")) == NULL)
+ continue;
+ if((cp = strtok(NULL," \t")) == NULL)
+ continue;
+ mp->n = atoi(cp);
+ if((mp->seed = strtok(NULL," \t")) == NULL)
+ continue;
+ if((mp->val = strtok(NULL," \t")) == NULL)
+ continue;
+ if(strlen(mp->logname) == len
+ && strncmp(mp->logname,name,len) == 0){
+ found = 1;
+ break;
+ }
+ }
+ if(found){
+ fseek(mp->keyfile,recstart,0);
+ return 0;
+ } else
+ return 1;
+}
+/* Verify response to a s/key challenge.
+ *
+ * Return codes:
+ * -1: Error of some sort; database unchanged
+ * 0: Verify successful, database updated
+ * 1: Verify failed, database unchanged
+ *
+ * The database file is always closed by this call.
+ */
+int
+skeyverify(mp,response)
+struct skey *mp;
+char *response;
+{
+ struct timeval startval;
+ struct timeval endval;
+long microsec;
+ char key[8];
+ char fkey[8];
+ char filekey[8];
+ time_t now;
+ struct tm *tm;
+ char tbuf[27],buf[60];
+ char me[80];
+ int rval;
+ char *cp;
+
+ time(&now);
+ tm = localtime(&now);
+ strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
+
+ if(response == NULL){
+ fclose(mp->keyfile);
+ return -1;
+ }
+ rip(response);
+
+ /* Convert response to binary */
+ if(etob(key,response) != 1 && atob8(key,response) != 0){
+ /* Neither english words or ascii hex */
+ fclose(mp->keyfile);
+ return -1;
+ }
+
+ /* Compute fkey = f(key) */
+ memcpy(fkey,key,sizeof(key));
+ f(fkey);
+ /* in order to make the window of update as short as possible
+ we must do the comparison here and if OK write it back
+ other wise the same password can be used twice to get in
+ to the system
+ */
+
+ setpriority(PRIO_PROCESS, 0, -4);
+/*
+ gettimeofday(&startval, (char *)0 );
+*/
+
+ /* reread the file record NOW*/
+
+ fseek(mp->keyfile,mp->recstart,0);
+ if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
+ setpriority(PRIO_PROCESS, 0, 0);
+ fclose(mp->keyfile);
+ return -1;
+ }
+ rip(mp->buf);
+ mp->logname = strtok(mp->buf," \t");
+ cp = strtok(NULL," \t") ;
+ mp->seed = strtok(NULL," \t");
+ mp->val = strtok(NULL," \t");
+ /* And convert file value to hex for comparison */
+ atob8(filekey,mp->val);
+
+ /* Do actual comparison */
+ if(memcmp(filekey,fkey,8) != 0){
+ /* Wrong response */
+ setpriority(PRIO_PROCESS, 0, 0);
+ fclose(mp->keyfile);
+ return 1;
+ }
+
+ /* Update key in database by overwriting entire record. Note
+ * that we must write exactly the same number of bytes as in
+ * the original record (note fixed width field for N)
+ */
+ btoa8(mp->val,key);
+ mp->n--;
+ fseek(mp->keyfile,mp->recstart,0);
+ fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
+ mp->val, tbuf);
+/*
+gettimeofday(&endval, (char *)0 );
+ microsec = (endval.tv_sec - startval.tv_sec) * 1000000 + (endval.tv_usec - startval.tv_usec);
+fprintf(stderr, "window= %d micro seconds \n" , microsec);
+*/
+
+
+ fclose(mp->keyfile);
+
+ setpriority(PRIO_PROCESS, 0, 0);
+ return 0;
+}
+
+
+/* Convert 8-byte hex-ascii string to binary array
+ * Returns 0 on success, -1 on error
+ */
+atob8(out,in)
+register char *out,*in;
+{
+ register int i;
+ register int val;
+
+ if(in == NULL || out == NULL)
+ return -1;
+
+ for(i=0;i<8;i++){
+ if((in = skipspace(in)) == NULL)
+ return -1;
+ if((val = htoi(*in++)) == -1)
+ return -1;
+ *out = val << 4;
+
+ if((in = skipspace(in)) == NULL)
+ return -1;
+ if((val = htoi(*in++)) == -1)
+ return -1;
+ *out++ |= val;
+ }
+ return 0;
+}
+
+char *
+skipspace(cp)
+register char *cp;
+{
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+
+ if(*cp == '\0')
+ return NULL;
+ else
+ return cp;
+}
+
+/* Convert 8-byte binary array to hex-ascii string */
+int
+btoa8(out,in)
+register char *out,*in;
+{
+ register int i;
+
+ if(in == NULL || out == NULL)
+ return -1;
+
+ for(i=0;i<8;i++){
+ sprintf(out,"%02x",*in++ & 0xff);
+ out += 2;
+ }
+ return 0;
+}
+
+
+/* Convert hex digit to binary integer */
+int
+htoi(c)
+register char c;
+{
+ if('0' <= c && c <= '9')
+ return c - '0';
+ if('a' <= c && c <= 'f')
+ return 10 + c - 'a';
+ if('A' <= c && c <= 'F')
+ return 10 + c - 'A';
+ return -1;
+}
diff --git a/lib/libskey/skeysubr.c b/lib/libskey/skeysubr.c
new file mode 100644
index 000000000000..bfac3a39d89a
--- /dev/null
+++ b/lib/libskey/skeysubr.c
@@ -0,0 +1,225 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __MSDOS__
+#include <dos.h>
+#endif
+#ifdef unix /* Assume POSIX */
+#include <fcntl.h>
+#include <termios.h>
+#endif
+#include <skey.h>
+#include "md4.h"
+
+#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
+ || defined(vax) || defined (MIPSEL))
+#define LITTLE_ENDIAN /* Low order bytes are first in memory */
+#endif /* Almost all other machines are big-endian */
+
+/* Crunch a key:
+ * concatenate the seed and the password, run through MD4 and
+ * collapse to 64 bits. This is defined as the user's starting key.
+ */
+int
+keycrunch(result,seed,passwd)
+char *result; /* 8-byte result */
+char *seed; /* Seed, any length */
+char *passwd; /* Password, any length */
+{
+ char *buf;
+ MDstruct md;
+ unsigned int buflen;
+#ifndef LITTLE_ENDIAN
+ int i;
+ register long tmp;
+#endif
+
+ buflen = strlen(seed) + strlen(passwd);
+ if((buf = malloc(buflen+1)) == NULL)
+ return -1;
+ strcpy(buf,seed);
+ strcat(buf,passwd);
+
+ /* Crunch the key through MD4 */
+ sevenbit(buf);
+ MDbegin(&md);
+ MDupdate(&md,(unsigned char *)buf,8*buflen);
+
+ free(buf);
+
+ /* Fold result from 128 to 64 bits */
+ md.buffer[0] ^= md.buffer[2];
+ md.buffer[1] ^= md.buffer[3];
+
+#ifdef LITTLE_ENDIAN
+ /* Only works on byte-addressed little-endian machines!! */
+ memcpy(result,(char *)md.buffer,8);
+#else
+ /* Default (but slow) code that will convert to
+ * little-endian byte ordering on any machine
+ */
+ for(i=0;i<2;i++){
+ tmp = md.buffer[i];
+ *result++ = tmp;
+ tmp >>= 8;
+ *result++ = tmp;
+ tmp >>= 8;
+ *result++ = tmp;
+ tmp >>= 8;
+ *result++ = tmp;
+ }
+#endif
+
+ return 0;
+}
+
+/* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */
+void
+f(x)
+char *x;
+{
+ MDstruct md;
+#ifndef LITTLE_ENDIAN
+ register long tmp;
+#endif
+
+ MDbegin(&md);
+ MDupdate(&md,(unsigned char *)x,64);
+
+ /* Fold 128 to 64 bits */
+ md.buffer[0] ^= md.buffer[2];
+ md.buffer[1] ^= md.buffer[3];
+
+#ifdef LITTLE_ENDIAN
+ /* Only works on byte-addressed little-endian machines!! */
+ memcpy(x,(char *)md.buffer,8);
+
+#else
+ /* Default (but slow) code that will convert to
+ * little-endian byte ordering on any machine
+ */
+ tmp = md.buffer[0];
+ *x++ = tmp;
+ tmp >>= 8;
+ *x++ = tmp;
+ tmp >>= 8;
+ *x++ = tmp;
+ tmp >>= 8;
+ *x++ = tmp;
+
+ tmp = md.buffer[1];
+ *x++ = tmp;
+ tmp >>= 8;
+ *x++ = tmp;
+ tmp >>= 8;
+ *x++ = tmp;
+ tmp >>= 8;
+ *x = tmp;
+#endif
+}
+
+/* Strip trailing cr/lf from a line of text */
+void
+rip(buf)
+char *buf;
+{
+ char *cp;
+
+ if((cp = strchr(buf,'\r')) != NULL)
+ *cp = '\0';
+
+ if((cp = strchr(buf,'\n')) != NULL)
+ *cp = '\0';
+}
+/************************/
+#ifdef __MSDOS__
+char *
+readpass(buf,n)
+char *buf;
+int n;
+{
+ int i;
+ char *cp;
+
+ for(cp=buf,i = 0; i < n ; i++)
+ if ((*cp++ = bdos(7,0,0)) == '\r')
+ break;
+ *cp = '\0';
+ printf("\n");
+ rip(buf);
+ return buf;
+}
+#else
+char *
+readpass(buf,n)
+char *buf;
+int n;
+{
+ struct termios saved_ttymode;
+ struct termios noecho_ttymode;
+
+ /* Save normal line editing modes */
+ tcgetattr(0, &saved_ttymode);
+
+ /* Turn off echoing */
+ tcgetattr(0, &noecho_ttymode);
+ noecho_ttymode.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSANOW, &noecho_ttymode);
+ fgets(buf,n,stdin);
+ rip(buf);
+
+ /* Restore previous tty modes */
+ tcsetattr(0, TCSANOW, &saved_ttymode);
+
+ /*
+ after the secret key is taken from the keyboard, the line feed is
+ written to standard error instead of standard output. That means that
+ anyone using the program from a terminal won't notice, but capturing
+ standard output will get the key words without a newline in front of
+ them.
+ */
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ sevenbit(buf);
+
+ return buf;
+}
+
+#endif
+
+/* removebackspaced over charaters from the string*/
+backspace(buf)
+char *buf;
+{
+ char bs = 0x8;
+ char *cp = buf;
+ char *out = buf;
+
+ while(*cp){
+ if( *cp == bs ) {
+ if(out == buf){
+ cp++;
+ continue;
+ }
+ else {
+ cp++;
+ out--;
+ }
+ }
+ else {
+ *out++ = *cp++;
+ }
+
+ }
+ *out = '\0';
+
+}
+sevenbit(s)
+char *s;
+{
+ /* make sure there are only 7 bit code in the line*/
+ while(*s){
+ *s = 0x7f & ( *s);
+ s++;
+ }
+}
diff --git a/lib/libterm/Makefile b/lib/libterm/Makefile
index c0ee1c1c90d7..a1cec58935c4 100644
--- a/lib/libterm/Makefile
+++ b/lib/libterm/Makefile
@@ -1,5 +1,5 @@
# from: @(#)Makefile 5.10 (Berkeley) 6/1/90
-# $Id: Makefile,v 1.6 1994/02/05 13:19:00 rgrimes Exp $
+# $Id: Makefile,v 1.7 1994/06/23 22:22:54 jkh Exp $
LIB= termcap
CFLAGS+=-DCM_N -DCM_GT -DCM_B -DCM_D
@@ -8,7 +8,7 @@ SRCS= termcap.c tgoto.c tputs.c
MAN3= termcap.3
MLINKS= termcap.3 tgetent.3 termcap.3 tgetflag.3 termcap.3 tgetnum.3 \
termcap.3 tgetstr.3 termcap.3 tgoto.3 termcap.3 tputs.3
-LINKS= ${LIBDIR}/libtermcap.a ${LIBDIR}/libtermlib.a \
+LINKS= ${LIBDIR}/libtermcap.a ${LIBDIR}/libtermlib.a
.if !defined(NOPROFILE)
LINKS+= ${LIBDIR}/libtermcap_p.a ${LIBDIR}/libtermlib_p.a
diff --git a/lib/libterm/tputs.c b/lib/libterm/tputs.c
index 89da56483331..58309ed4b181 100644
--- a/lib/libterm/tputs.c
+++ b/lib/libterm/tputs.c
@@ -44,8 +44,9 @@ static char sccsid[] = "@(#)tputs.c 5.3 (Berkeley) 6/1/90";
* baud returns a 7, there are 33.3 milliseconds per char at 300 baud.
*/
static
-short tmspc10[] = {
- 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5
+short tmspc10[] = {
+ 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5,
+ 3, 2, 1
};
short ospeed;
@@ -63,6 +64,7 @@ tputs(cp, affcnt, outc)
{
register int i = 0;
register int mspc10;
+ int speed;
if (cp == 0)
return;
@@ -106,8 +108,12 @@ tputs(cp, affcnt, outc)
*/
if (i == 0)
return;
- if (ospeed <= 0 || ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
+ if (ospeed <= 0)
return;
+ if (ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
+ speed = (sizeof tmspc10 / sizeof tmspc10[0]) - 1;
+ else
+ speed = ospeed;
/*
* Round up by a half a character frame,
@@ -116,7 +122,7 @@ tputs(cp, affcnt, outc)
* Transmitting pad characters slows many
* terminals down and also loads the system.
*/
- mspc10 = tmspc10[ospeed];
+ mspc10 = tmspc10[speed];
i += mspc10 / 2;
for (i /= mspc10; i > 0; i--)
(*outc)(PC);
diff --git a/lib/libutil/kvm.c b/lib/libutil/kvm.c
index 2c5de35dd0b8..5c9c856a5d92 100644
--- a/lib/libutil/kvm.c
+++ b/lib/libutil/kvm.c
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kvm.c,v 1.8 1994/02/23 09:56:45 rgrimes Exp $
+ * $Id: kvm.c,v 1.10 1994/03/22 21:56:48 davidg Exp $
*/
#if defined(LIBC_SCCS) && !defined(lint)
@@ -291,35 +291,6 @@ kvm_nlist(nl)
if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL)
goto hard2;
/*
- * read version out of database
- */
- bcopy("VERSION", symbuf, sizeof ("VERSION")-1);
- key.dsize = (sizeof ("VERSION") - 1);
- data = dbm_fetch(db, key);
- if (data.dptr == NULL)
- goto hard1;
- bcopy(data.dptr, dbversion, data.dsize);
- dbversionlen = data.dsize;
- /*
- * read version string from kernel memory
- */
- bcopy("_version", symbuf, sizeof ("_version")-1);
- key.dsize = (sizeof ("_version")-1);
- data = dbm_fetch(db, key);
- if (data.dptr == NULL)
- goto hard1;
- if (data.dsize != sizeof (struct nlist))
- goto hard1;
- bcopy(data.dptr, &nbuf, sizeof (struct nlist));
- lseek(kmem, nbuf.n_value, 0);
- if (read(kmem, kversion, dbversionlen) != dbversionlen)
- goto hard1;
- /*
- * if they match, we win - otherwise do it the hard way
- */
- if (bcmp(dbversion, kversion, dbversionlen) != 0)
- goto hard1;
- /*
* getem from the database.
*/
win:
@@ -513,7 +484,7 @@ again:
} else
eproc.e_tdev = NODEV;
if (proc.p_wmesg)
- kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN);
+ kvm_read((char *)proc.p_wmesg, eproc.e_wmesg, WMESGLEN);
(void) kvm_read(proc.p_vmspace, &eproc.e_vm,
sizeof (struct vmspace));
eproc.e_xsize = eproc.e_xrssize =
diff --git a/lib/libutil/login.c b/lib/libutil/login.c
index b4e4d60f773d..fb87570b41ba 100644
--- a/lib/libutil/login.c
+++ b/lib/libutil/login.c
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: login.c,v 1.2 1994/02/23 09:56:47 rgrimes Exp $
+ * $Id: login.c,v 1.3 1994/04/07 17:47:36 ache Exp $
*/
#if defined(LIBC_SCCS) && !defined(lint)
@@ -41,23 +41,42 @@ static char sccsid[] = "@(#)login.c 5.4 (Berkeley) 6/1/90";
#include <sys/file.h>
#include <utmp.h>
#include <stdio.h>
+#include <unistd.h>
+#include <ttyent.h>
+
+typedef struct utmp UTMP;
void
login(ut)
- struct utmp *ut;
+ UTMP *ut;
{
register int fd;
int tty;
- off_t lseek();
+ UTMP utmp;
- tty = ttyslot();
- if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
- (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET);
- (void)write(fd, (char *)ut, sizeof(struct utmp));
- (void)close(fd);
+ if ((fd = open(_PATH_UTMP, O_RDWR|O_CREAT, 0644)) >= 0) {
+ if ((tty = ttyslot()) > 0) {
+ (void)lseek(fd, (long)(tty * sizeof(UTMP)), L_SET);
+ (void)write(fd, (char *)ut, sizeof(UTMP));
+ (void)close(fd);
+ } else {
+ setttyent();
+ for (tty = 0; getttyent(); tty++)
+ ;
+ endttyent();
+ (void)lseek(fd, (long)(tty * sizeof(UTMP)), L_SET);
+ while (read(fd, (char *)&utmp, sizeof(UTMP)) == sizeof(UTMP)) {
+ if (!utmp.ut_name[0]) {
+ (void)lseek(fd, -(long)sizeof(UTMP), L_INCR);
+ break;
+ }
+ }
+ (void)write(fd, (char *)ut, sizeof(UTMP));
+ (void)close(fd);
+ }
}
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
- (void)write(fd, (char *)ut, sizeof(struct utmp));
+ (void)write(fd, (char *)ut, sizeof(UTMP));
(void)close(fd);
}
}
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
new file mode 100644
index 000000000000..9f4fbafe8933
--- /dev/null
+++ b/lib/msun/Makefile
@@ -0,0 +1,111 @@
+# @(#)Makefile 5.1beta 93/09/24
+# $Id: Makefile,v 1.6 1994/05/31 23:53:57 ljo Exp $
+#
+# ====================================================
+# Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+#
+# Developed at SunPro, a Sun Microsystems, Inc. business.
+# Permission to use, copy, modify, and distribute this
+# software is freely granted, provided that this notice
+# is preserved.
+# ====================================================
+#
+#
+
+#
+# There are two options in making libm at fdlibm compile time:
+# _IEEE_LIBM --- IEEE libm; smaller, and somewhat faster
+# _MULTI_LIBM --- Support multi-standard at runtime by
+# imposing wrapper functions defined in
+# fdlibm.h:
+# _IEEE_MODE -- IEEE
+# _XOPEN_MODE -- X/OPEN
+# _POSIX_MODE -- POSIX/ANSI
+# _SVID3_MODE -- SVID
+#
+# Here is how to set up CFLAGS to create the desired libm at
+# compile time:
+#
+# CFLAGS = -D_IEEE_LIBM ... IEEE libm (recommended)
+# CFLAGS = -D_SVID3_MODE ... Multi-standard supported
+# libm with SVID as the
+# default standard
+# CFLAGS = -D_XOPEN_MODE ... Multi-standard supported
+# libm with XOPEN as the
+# default standard
+# CFLAGS = -D_POSIX_MODE ... Multi-standard supported
+# libm with POSIX as the
+# default standard
+# CFLAGS = ... Multi-standard supported
+# libm with IEEE as the
+# default standard
+#
+
+#Define HAVE_FPU if you have a i387 (or i486 or Pentium)
+
+.if defined(HAVE_FPU)
+.PATH: ${.CURDIR}/i387
+
+ARCH_SRCS = e_acos.S e_asin.S e_atan2.S e_exp.S e_fmod.S e_log.S e_log10.S \
+ e_remainder.S e_scalb.S e_sqrt.S s_atan.S s_ceil.S s_copysign.S \
+ s_cos.S s_finite.S s_floor.S s_ilogb.S s_log1p.S s_logb.S \
+ s_rint.S s_scalbn.S s_significand.S s_sin.S s_tan.S
+
+.endif
+
+.PATH: ${.CURDIR}/src
+
+
+CFLAGS+= -D_IEEE_LIBM
+
+LIB= m
+first:
+SRCS = k_standard.c k_rem_pio2.c k_cos.c k_sin.c k_tan.c \
+ e_acos.c e_acosh.c e_asin.c e_atan2.c e_atanh.c e_cosh.c e_exp.c \
+ e_fmod.c e_gamma.c e_gamma_r.c e_hypot.c e_j0.c e_j1.c e_jn.c \
+ e_lgamma.c e_lgamma_r.c e_log.c e_log10.c e_pow.c e_rem_pio2.c \
+ e_remainder.c e_scalb.c e_sinh.c e_sqrt.c \
+ w_acos.c w_acosh.c w_asin.c w_atan2.c \
+ w_atanh.c w_cosh.c w_exp.c w_fmod.c \
+ w_gamma.c w_gamma_r.c w_hypot.c w_j0.c \
+ w_j1.c w_jn.c w_lgamma.c w_lgamma_r.c \
+ w_log.c w_log10.c w_pow.c w_remainder.c \
+ w_scalb.c w_sinh.c w_sqrt.c \
+ w_cabs.c w_drem.c \
+ s_asinh.c s_atan.c s_cbrt.c s_ceil.c s_copysign.c \
+ s_cos.c s_erf.c s_expm1.c s_finite.c s_floor.c \
+ s_ilogb.c s_lib_version.c \
+ s_log1p.c s_logb.c s_matherr.c s_nextafter.c \
+ s_rint.c s_scalbn.c s_signgam.c s_significand.c s_sin.c \
+ s_tanh.c s_tan.c
+
+SRCS+=${ARCH_SRCS}
+
+
+# Substitute common sources with any arch specific sources
+MANSRC= ${.CURDIR}/man
+
+MAN3+= acos.3 acosh.3 asin.3 asinh.3 atan.3 atan2.3 atanh.3 ceil.3 \
+ cos.3 cosh.3 erf.3 exp.3 fabs.3 floor.3 fmod.3 hypot.3 ieee.3 \
+ ieee_test.3 j0.3 lgamma.3 math.3 rint.3 sin.3 sinh.3 sqrt.3 \
+ tan.3 tanh.3
+
+MLINKS+=erf.3 erfc.3
+MLINKS+=exp.3 expm1.3 exp.3 log.3 exp.3 log10.3 exp.3 log1p.3 exp.3 pow.3
+MLINKS+=hypot.3 cabs.3
+MLINKS+=ieee.3 copysign.3 ieee.3 finite.3 ieee.3 ilogb.3 \
+ ieee.3 nextafter.3 ieee.3 remainder.3 ieee.3 scalbn.3
+MLINKS+=ieee_test.3 logb.3
+MLINKS+=ieee_test.3 scalb.3
+MLINKS+=ieee_test.3 significand.3
+MLINKS+=j0.3 j1.3 j0.3 jn.3 j0.3 y0.3 j0.3 y1.3 j0.3 yn.3
+MLINKS+=lgamma.3 gamma.3
+MLINKS+=sqrt.3 cbrt.3
+
+beforeinstall:
+ @echo Installing new math.h
+ @(cd ${.CURDIR}/src; cmp -s math.h ${DESTDIR}/usr/include/math.h || \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 math.h \
+ ${DESTDIR}/usr/include/math.h;)
+
+.include <bsd.lib.mk>
diff --git a/lib/msun/i387/DEFS.h b/lib/msun/i387/DEFS.h
new file mode 100644
index 000000000000..ce64c8c12bd9
--- /dev/null
+++ b/lib/msun/i387/DEFS.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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: @(#)DEFS.h 5.1 (Berkeley) 4/23/90
+ *
+ * $Id: DEFS.h,v 1.1 1994/05/07 01:50:29 ljo Exp $
+ */
+
+/* XXX should use align 4,0x90 for -m486. */
+#define _START_ENTRY .align 2,0x90;
+#if 0
+/* Data is not used, except perhaps by non-g prof, which we don't support. */
+#define _MID_ENTRY .data; .align 2; 8:; .long 0; \
+ .text; lea 8b,%eax;
+#else
+#define _MID_ENTRY
+#endif
+
+#ifdef PROF
+
+#define ALTENTRY(x) _START_ENTRY \
+ .globl _/**/x; .type _/**/x,@function; _/**/x:; \
+ _MID_ENTRY \
+ call mcount; jmp 9f
+
+#define ENTRY(x) _START_ENTRY \
+ .globl _/**/x; .type _/**/x,@function; _/**/x:; \
+ _MID_ENTRY \
+ call mcount; 9:
+
+
+#define ALTASENTRY(x) _START_ENTRY \
+ .globl x; .type x,@function; x:; \
+ _MID_ENTRY \
+ call mcount; jmp 9f
+
+#define ASENTRY(x) _START_ENTRY \
+ .globl x; .type x,@function; x:; \
+ _MID_ENTRY \
+ call mcount; 9:
+
+#else /* !PROF */
+
+#define ENTRY(x) _START_ENTRY .globl _/**/x; .type _/**/x,@function; \
+ _/**/x:
+#define ALTENTRY(x) ENTRY(x)
+
+#define ASENTRY(x) _START_ENTRY .globl x; .type x,@function; x:
+#define ALTASENTRY(x) ASENTRY(x)
+
+#endif
diff --git a/lib/msun/i387/e_acos.S b/lib/msun/i387/e_acos.S
new file mode 100644
index 000000000000..5e57d016e19e
--- /dev/null
+++ b/lib/msun/i387/e_acos.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+/* acos = atan (sqrt(1 - x^2) / x) */
+ENTRY(__ieee754_acos)
+ fldl 4(%esp) /* x */
+ fst %st(1)
+ fmul %st(0) /* x^2 */
+ fld1
+ fsubp /* 1 - x^2 */
+ fsqrt /* sqrt (1 - x^2) */
+ fxch %st(1)
+ fpatan
+ ret
diff --git a/lib/msun/i387/e_asin.S b/lib/msun/i387/e_asin.S
new file mode 100644
index 000000000000..7f8f9bab051a
--- /dev/null
+++ b/lib/msun/i387/e_asin.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+/* asin = atan (x / sqrt(1 - x^2)) */
+ENTRY(__ieee754_asin)
+ fldl 4(%esp) /* x */
+ fst %st(1)
+ fmul %st(0) /* x^2 */
+ fld1
+ fsubp /* 1 - x^2 */
+ fsqrt /* sqrt (1 - x^2) */
+ fpatan
+ ret
diff --git a/lib/msun/i387/e_atan2.S b/lib/msun/i387/e_atan2.S
new file mode 100644
index 000000000000..cc7917de5284
--- /dev/null
+++ b/lib/msun/i387/e_atan2.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_atan2)
+ fldl 4(%esp)
+ fldl 12(%esp)
+ fpatan
+ ret
diff --git a/lib/msun/i387/e_exp.S b/lib/msun/i387/e_exp.S
new file mode 100644
index 000000000000..1b19eb920aaa
--- /dev/null
+++ b/lib/msun/i387/e_exp.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+/* e^x = 2^(x * log2(e)) */
+ENTRY(__ieee754_exp)
+ fldl 4(%esp)
+ fldl2e
+ fmulp /* x * log2(e) */
+ fstl %st(1)
+ frndint /* int(x * log2(e)) */
+ fstl %st(2)
+ fsubrp /* fract(x * log2(e)) */
+ f2xm1 /* 2^(fract(x * log2(e))) - 1 */
+ fld1
+ faddp /* 2^(fract(x * log2(e))) */
+ fscale /* e^x */
+ ret
diff --git a/lib/msun/i387/e_fmod.S b/lib/msun/i387/e_fmod.S
new file mode 100644
index 000000000000..180cb61e3246
--- /dev/null
+++ b/lib/msun/i387/e_fmod.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_fmod)
+ fldl 12(%esp)
+ fldl 4(%esp)
+1: fprem
+ fstsw %ax
+ sahf
+ jp 1b
+ fstpl %st(1)
+ ret
diff --git a/lib/msun/i387/e_log.S b/lib/msun/i387/e_log.S
new file mode 100644
index 000000000000..7e19515c2785
--- /dev/null
+++ b/lib/msun/i387/e_log.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_log)
+ fldln2
+ fldl 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_log10.S b/lib/msun/i387/e_log10.S
new file mode 100644
index 000000000000..9750b543b7db
--- /dev/null
+++ b/lib/msun/i387/e_log10.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_log10)
+ fldlg2
+ fldl 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_remainder.S b/lib/msun/i387/e_remainder.S
new file mode 100644
index 000000000000..706ff6e5deca
--- /dev/null
+++ b/lib/msun/i387/e_remainder.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_remainder)
+ fldl 12(%esp)
+ fldl 4(%esp)
+1: fprem1
+ fstsw %ax
+ sahf
+ jp 1b
+ fstpl %st(1)
+ ret
diff --git a/lib/msun/i387/e_scalb.S b/lib/msun/i387/e_scalb.S
new file mode 100644
index 000000000000..2634832216d4
--- /dev/null
+++ b/lib/msun/i387/e_scalb.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_scalb)
+ fldl 12(%esp)
+ fldl 4(%esp)
+ fscale
+ ret
diff --git a/lib/msun/i387/e_sqrt.S b/lib/msun/i387/e_sqrt.S
new file mode 100644
index 000000000000..99f5207e1600
--- /dev/null
+++ b/lib/msun/i387/e_sqrt.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(__ieee754_sqrt)
+ fldl 4(%esp)
+ fsqrt
+ ret
diff --git a/lib/msun/i387/s_atan.S b/lib/msun/i387/s_atan.S
new file mode 100644
index 000000000000..44a42ccff8fb
--- /dev/null
+++ b/lib/msun/i387/s_atan.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(atan)
+ fldl 4(%esp)
+ fld1
+ fpatan
+ ret
diff --git a/lib/msun/i387/s_ceil.S b/lib/msun/i387/s_ceil.S
new file mode 100644
index 000000000000..f315a8d5f439
--- /dev/null
+++ b/lib/msun/i387/s_ceil.S
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(ceil)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -12(%ebp) /* store fpu control word */
+ movw -12(%ebp),%dx
+ orw $0x0800,%dx /* round towards +oo */
+ andw $0xfbff,%dx
+ movw %dx,-16(%ebp)
+ fldcw -16(%ebp) /* load modfied control word */
+
+ fldl 8(%ebp); /* round */
+ frndint
+
+ fldcw -12(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_copysign.S b/lib/msun/i387/s_copysign.S
new file mode 100644
index 000000000000..52118fa40d75
--- /dev/null
+++ b/lib/msun/i387/s_copysign.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(copysign)
+ movl 16(%esp),%edx
+ andl $0x80000000,%edx
+ movl 8(%esp),%eax
+ andl $0x7fffffff,%eax
+ orl %edx,%eax
+ movl %eax,8(%esp)
+ fldl 4(%esp)
+ ret
diff --git a/lib/msun/i387/s_cos.S b/lib/msun/i387/s_cos.S
new file mode 100644
index 000000000000..8861b82685f1
--- /dev/null
+++ b/lib/msun/i387/s_cos.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(cos)
+ fldl 4(%esp)
+ fcos
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fcos
+ ret
diff --git a/lib/msun/i387/s_finite.S b/lib/msun/i387/s_finite.S
new file mode 100644
index 000000000000..8c0a8a22e1e0
--- /dev/null
+++ b/lib/msun/i387/s_finite.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(finite)
+ movl 8(%esp),%eax
+ andl $0x7ff00000, %eax
+ cmpl $0x7ff00000, %eax
+ setnel %al
+ andl $0x000000ff, %eax
+ ret
diff --git a/lib/msun/i387/s_floor.S b/lib/msun/i387/s_floor.S
new file mode 100644
index 000000000000..6da994090952
--- /dev/null
+++ b/lib/msun/i387/s_floor.S
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(floor)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -12(%ebp) /* store fpu control word */
+ movw -12(%ebp),%dx
+ orw $0x0400,%dx /* round towards -oo */
+ andw $0xf7ff,%dx
+ movw %dx,-16(%ebp)
+ fldcw -16(%ebp) /* load modfied control word */
+
+ fldl 8(%ebp); /* round */
+ frndint
+
+ fldcw -12(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_ilogb.S b/lib/msun/i387/s_ilogb.S
new file mode 100644
index 000000000000..ae1c88e83ec7
--- /dev/null
+++ b/lib/msun/i387/s_ilogb.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(ilogb)
+ pushl %esp
+ movl %esp,%ebp
+ subl $4,%esp
+
+ fldl 8(%ebp)
+ fxtract
+ fstpl %st
+
+ fistpl -4(%ebp)
+ movl -4(%ebp),%eax
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_log1p.S b/lib/msun/i387/s_log1p.S
new file mode 100644
index 000000000000..45f95b9f87fe
--- /dev/null
+++ b/lib/msun/i387/s_log1p.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(log1p)
+ fldln2
+ fldl 4(%ebp)
+ fyl2xp1
+ ret
diff --git a/lib/msun/i387/s_logb.S b/lib/msun/i387/s_logb.S
new file mode 100644
index 000000000000..7e06205ca77e
--- /dev/null
+++ b/lib/msun/i387/s_logb.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(logb)
+ fldl 4(%esp)
+ fxtract
+ fstpl %st
+ ret
diff --git a/lib/msun/i387/s_rint.S b/lib/msun/i387/s_rint.S
new file mode 100644
index 000000000000..e13771cbdcea
--- /dev/null
+++ b/lib/msun/i387/s_rint.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(rint)
+ fldl 4(%esp)
+ frndint
+ ret
diff --git a/lib/msun/i387/s_scalbn.S b/lib/msun/i387/s_scalbn.S
new file mode 100644
index 000000000000..674081fb2596
--- /dev/null
+++ b/lib/msun/i387/s_scalbn.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(scalbn)
+ fildl 12(%esp)
+ fldl 4(%esp)
+ fscale
+ ret
diff --git a/lib/msun/i387/s_significand.S b/lib/msun/i387/s_significand.S
new file mode 100644
index 000000000000..1bcb8e9d12a8
--- /dev/null
+++ b/lib/msun/i387/s_significand.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(significand)
+ fldl 4(%esp)
+ fxtract
+ fstpl %st(1)
+ ret
diff --git a/lib/msun/i387/s_sin.S b/lib/msun/i387/s_sin.S
new file mode 100644
index 000000000000..272d8ae01c1d
--- /dev/null
+++ b/lib/msun/i387/s_sin.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+
+ENTRY(sin)
+ fldl 4(%esp)
+ fsin
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fsin
+ ret
diff --git a/lib/msun/i387/s_tan.S b/lib/msun/i387/s_tan.S
new file mode 100644
index 000000000000..d44bacfccea6
--- /dev/null
+++ b/lib/msun/i387/s_tan.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include "DEFS.h"
+
+ENTRY(tan)
+ fldl 4(%esp)
+ fptan
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ fstp %st(0)
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fptan
+ fstp %st(0)
+ ret
diff --git a/lib/msun/man/acos.3 b/lib/msun/man/acos.3
new file mode 100644
index 000000000000..63e35727172d
--- /dev/null
+++ b/lib/msun/man/acos.3
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1991 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: @(#)acos.3 5.1 (Berkeley) 5/2/91
+.\" $Id: acos.3,v 1.1.1.1 1994/05/06 00:19:43 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt ACOS 3
+.Os
+.Sh NAME
+.Nm acos
+.Nd arc cosine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn acos "double x"
+.Sh DESCRIPTION
+The
+.Fn acos
+function computes the principal value of the arc cosine of
+.Fa x .
+A domain error occurs for arguments not in the range [-1, +1].
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn acos
+function returns the arc cosine in the range
+.Bq 0 , \*(Pi
+radians.
+On the
+.Tn VAX
+and
+.Tn Tahoe ,
+if:
+.Bd -unfilled -offset indent
+.Pf \&| Ns Ar x Ns \&| > 1 ,
+.Ed
+.Pp
+.Fn acos x
+sets the global variable
+.Va errno
+to
+.Dv EDOM
+and a reserved operand fault is generated.
+.Sh SEE ALSO
+.Xr sin 3 ,
+.Xr cos 3 ,
+.Xr tan 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr sinh 3 ,
+.Xr cosh 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn acos
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/acosh.3 b/lib/msun/man/acosh.3
new file mode 100644
index 000000000000..235ddc92517e
--- /dev/null
+++ b/lib/msun/man/acosh.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1991 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: @(#)acosh.3 5.2 (Berkeley) 5/6/91
+.\" $Id: acosh.3,v 1.1.1.1 1994/05/06 00:19:44 gclarkii Exp $
+.\"
+.Dd May 6, 1991
+.Dt ACOSH 3
+.Os BSD 4.3
+.Sh NAME
+.Nm acosh
+.Nd inverse hyperbolic cosine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn acosh "double x"
+.Sh DESCRIPTION
+The
+.Fn acosh
+function computes the inverse hyperbolic cosine
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn acosh
+function
+returns the inverse hyperbolic cosine of
+.Ar x .
+On the
+.Tn VAX
+and
+.Tn Tahoe ,
+if the argument is less than one
+.Fn acosh
+sets the global variable
+.Va errno
+to
+.Er EDOM
+and
+causes a reserved operand fault.
+.Sh SEE ALSO
+.Xr asinh 3 ,
+.Xr atanh 3 ,
+.Xr exp 3 ,
+.Xr infnan 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn acosh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/asin.3 b/lib/msun/man/asin.3
new file mode 100644
index 000000000000..d13b60925ae7
--- /dev/null
+++ b/lib/msun/man/asin.3
@@ -0,0 +1,91 @@
+.\" Copyright (c) 1991 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: @(#)asin.3 5.1 (Berkeley) 5/2/91
+.\" $Id: asin.3,v 1.1.1.1 1994/05/06 00:19:44 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt ASIN 3
+.Os
+.Sh NAME
+.Nm asin
+.Nd arc sine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn asin "double x"
+.Sh DESCRIPTION
+The
+.Fn asin
+function computes the principal value of the arc sine of
+.Fa x .
+A domain error occurs for arguments not in the range [-1, +1].
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn asin
+function returns the arc sine in the range
+.Bk -words
+.Bq -\*(Pi/2, +\*(Pi/2
+.Ek
+radians.
+On the
+.Tn VAX ,
+and Tahoe ,
+if:
+.Bd -unfilled -offset indent
+.Pf \&| Ns Ar x Ns \&| > 1
+.Ed
+.Pp
+the
+global variable
+.Va errno
+is set to
+.Er EDOM
+and
+a reserved operand fault generated.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn asin
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/asinh.3 b/lib/msun/man/asinh.3
new file mode 100644
index 000000000000..918fa1131e3e
--- /dev/null
+++ b/lib/msun/man/asinh.3
@@ -0,0 +1,70 @@
+.\" Copyright (c) 1985, 1991 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: @(#)asinh.3 6.4 (Berkeley) 5/6/91
+.\" $Id: asinh.3,v 1.1.1.1 1994/05/06 00:19:44 gclarkii Exp $
+.\"
+.Dd May 6, 1991
+.Dt ASINH 3
+.Os BSD 4.3
+.Sh NAME
+.Nm asinh
+.Nd inverse hyperbolic sine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn asinh "double x"
+.Sh DESCRIPTION
+The
+.Fn asinh
+function computes the inverse hyperbolic sine
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn asinh
+function
+returns the inverse hyperbolic sine of
+.Ar x .
+.Sh SEE ALSO
+.Xr acosh 3 ,
+.Xr atanh 3 ,
+.Xr exp 3 ,
+.Xr infnan 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn asinh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/atan.3 b/lib/msun/man/atan.3
new file mode 100644
index 000000000000..1b74a3068f3e
--- /dev/null
+++ b/lib/msun/man/atan.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1991 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: @(#)atan.3 5.1 (Berkeley) 5/2/91
+.\" $Id: atan.3,v 1.1.1.1 1994/05/06 00:19:44 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt ATAN 3
+.Os
+.Sh NAME
+.Nm atan
+.Nd arc tangent function of one variable
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn atan "double x"
+.Sh DESCRIPTION
+The
+.Fn atan
+function computes the principal value of the arc tangent of
+.Fa x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn atan
+function returns the arc tangent in the range
+.Bk -words
+.Bq -\*(Pi/2 , +\*(Pi/2
+.Ek
+radians.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn atan
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/atan2.3 b/lib/msun/man/atan2.3
new file mode 100644
index 000000000000..b4f36add9e06
--- /dev/null
+++ b/lib/msun/man/atan2.3
@@ -0,0 +1,189 @@
+.\" Copyright (c) 1991 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: @(#)atan2.3 5.1 (Berkeley) 5/2/91
+.\" $Id: atan2.3,v 1.1.1.1 1994/05/06 00:19:45 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt ATAN2 3
+.Os
+.Sh NAME
+.Nm atan2
+.Nd arc tangent function of two variables
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn atan2 "double y" "double x"
+.Sh DESCRIPTION
+The
+.Xr atan2
+function computes the principal value of the arc tangent of
+.Ar y/ Ns Ar x ,
+using the signs of both arguments to determine the quadrant of
+the return value.
+.Sh RETURN VALUES
+The
+.Xr atan2
+function, if successful,
+returns the arc tangent of
+.Ar y/ Ns Ar x
+in the range
+.Bk -words
+.Bq \&- Ns \*(Pi , \&+ Ns \*(Pi
+.Ek
+radians.
+If both
+.Ar x
+and
+.Ar y
+are zero, the global variable
+.Va errno
+is set to
+.Er EDOM .
+On the
+.Tn VAX :
+.Bl -column atan_(y,x)_:=____ sign(y)_(Pi_atan2(Xy_xX))___
+.It Fn atan2 y x No := Ta
+.Fn atan y/x Ta
+if
+.Ar x
+> 0,
+.It Ta sign( Ns Ar y Ns )*(\*(Pi -
+.Fn atan "\\*(Bay/x\\*(Ba" ) Ta
+if
+.Ar x
+< 0,
+.It Ta
+.No 0 Ta
+if x = y = 0, or
+.It Ta
+.Pf sign( Ar y Ns )*\\*(Pi/2 Ta
+if
+.Ar x
+= 0 \*(!=
+.Ar y .
+.El
+.Sh NOTES
+The function
+.Fn atan2
+defines "if x > 0,"
+.Fn atan2 0 0
+= 0 on a
+.Tn VAX
+despite that previously
+.Fn atan2 0 0
+may have generated an error message.
+The reasons for assigning a value to
+.Fn atan2 0 0
+are these:
+.Bl -enum -offset indent
+.It
+Programs that test arguments to avoid computing
+.Fn atan2 0 0
+must be indifferent to its value.
+Programs that require it to be invalid are vulnerable
+to diverse reactions to that invalidity on diverse computer systems.
+.It
+The
+.Fn atan2
+function is used mostly to convert from rectangular (x,y)
+to polar
+.if n\
+(r,theta)
+.if t\
+(r,\(*h)
+coordinates that must satisfy x =
+.if n\
+r\(**cos theta
+.if t\
+r\(**cos\(*h
+and y =
+.if n\
+r\(**sin theta.
+.if t\
+r\(**sin\(*h.
+These equations are satisfied when (x=0,y=0)
+is mapped to
+.if n \
+(r=0,theta=0)
+.if t \
+(r=0,\(*h=0)
+on a VAX. In general, conversions to polar coordinates
+should be computed thus:
+.Bd -unfilled -offset indent
+.if n \{\
+r := hypot(x,y); ... := sqrt(x\(**x+y\(**y)
+theta := atan2(y,x).
+.\}
+.if t \{\
+r := hypot(x,y); ... := \(sr(x\u\s82\s10\d+y\u\s82\s10\d)
+\(*h := atan2(y,x).
+.\}
+.Ed
+.It
+The foregoing formulas need not be altered to cope in a
+reasonable way with signed zeros and infinities
+on a machine that conforms to
+.Tn IEEE 754 ;
+the versions of
+.Xr hypot 3
+and
+.Fn atan2
+provided for
+such a machine are designed to handle all cases.
+That is why
+.Fn atan2 \(+-0 \-0
+= \(+-\*(Pi
+for instance.
+In general the formulas above are equivalent to these:
+.Bd -unfilled -offset indent
+.if n \
+r := sqrt(x\(**x+y\(**y); if r = 0 then x := copysign(1,x);
+.if t \
+r := \(sr(x\(**x+y\(**y);\0\0if r = 0 then x := copysign(1,x);
+.Ed
+.El
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3 ,
+.Sh STANDARDS
+The
+.Fn atan2
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/atanh.3 b/lib/msun/man/atanh.3
new file mode 100644
index 000000000000..2125c085c748
--- /dev/null
+++ b/lib/msun/man/atanh.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1985, 1991 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: @(#)atanh.3 5.2 (Berkeley) 5/6/91
+.\" $Id: atanh.3,v 1.1.1.1 1994/05/06 00:19:45 gclarkii Exp $
+.\"
+.Dd May 6, 1991
+.Dt ATANH 3
+.Os BSD 4.3
+.Sh NAME
+.Nm atanh
+.Nd inverse hyperbolic tangent function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn atanh "double x"
+.Sh DESCRIPTION
+The
+.Fn atanh
+function computes the inverse hyperbolic tangent
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn atanh
+function
+returns the inverse hyperbolic tangent of
+.Ar x
+if successful.
+On the
+.Tn VAX
+and
+.Tn Tahoe ,
+if the argument has absolute value
+bigger than or equal to 1,
+.Fn atanh
+sets the global variable
+.Va errno
+to
+.Er EDOM
+and
+a reserved operand fault is generated.
+.Sh SEE ALSO
+.Xr acosh 3 ,
+.Xr asinh 3 ,
+.Xr exp 3 ,
+.Xr infnan 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn atanh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/ceil.3 b/lib/msun/man/ceil.3
new file mode 100644
index 000000000000..5a58261501ff
--- /dev/null
+++ b/lib/msun/man/ceil.3
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1991 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: @(#)ceil.3 5.1 (Berkeley) 5/2/91
+.\" $Id: ceil.3,v 1.1.1.1 1994/05/06 00:19:50 gclarkii Exp $
+.\"
+.Dd March 10, 1994
+.Dt CEIL 3
+.Os
+.Sh NAME
+.Nm ceil
+.Nd round to smallest integral value not greater than x
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn ceil "double x"
+.Sh DESCRIPTION
+The
+.Fn ceil
+function returns the smallest integral value
+(represented as a double precision number)
+greater than or equal to
+.Fa x .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr rint 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn ceil
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/cos.3 b/lib/msun/man/cos.3
new file mode 100644
index 000000000000..b8435a953af0
--- /dev/null
+++ b/lib/msun/man/cos.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1991 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: @(#)cos.3 5.1 (Berkeley) 5/2/91
+.\" $Id: cos.3,v 1.1.1.1 1994/05/06 00:19:45 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt COS 3
+.Os
+.Sh NAME
+.Nm cos
+.Nd cosine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn cos "double x"
+.Sh DESCRIPTION
+The
+.Fn cos
+function computes the cosine of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result with little or no
+significance.
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn cos
+function returns the cosine value.
+.Sh SEE ALSO
+.Xr sin 3 ,
+.Xr tan 3 ,
+.Xr asin 3 ,
+.Xr acos 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr sinh 3 ,
+.Xr cosh 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn cos
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/cosh.3 b/lib/msun/man/cosh.3
new file mode 100644
index 000000000000..64c850ce8e85
--- /dev/null
+++ b/lib/msun/man/cosh.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1989, 1991 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: @(#)cosh.3 5.1 (Berkeley) 5/2/91
+.\" $Id: cosh.3,v 1.1.1.1 1994/05/06 00:19:46 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt COSH 3
+.Os
+.Sh NAME
+.Nm cosh
+.Nd hyperbolic cosine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn cosh "double x"
+.Sh DESCRIPTION
+The
+.Fn cosh
+function computes the hyperbolic cosine of
+.Fa x .
+.Sh RETURN VALUES
+The
+.Fn cosh
+function returns the hyperbolic cosine unless the magnitude
+of
+.Fa x
+is too large; in this event, the global variable
+.Va errno
+is set to
+.Er ERANGE .
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn cosh
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/erf.3 b/lib/msun/man/erf.3
new file mode 100644
index 000000000000..f4654af3e55d
--- /dev/null
+++ b/lib/msun/man/erf.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1985, 1991 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: @(#)erf.3 6.4 (Berkeley) 4/20/91
+.\" $Id: erf.3,v 1.1.1.1 1994/05/06 00:19:46 gclarkii Exp $
+.\"
+.Dd April 20, 1991
+.Dt ERF 3
+.Os BSD 4.3
+.Sh NAME
+.Nm erf ,
+.Nm erfc
+.Nd error function operators
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn erf "double x"
+.Ft double
+.Fn erfc "double x"
+.Sh DESCRIPTION
+These functions calculate the error function of
+.Fa x .
+.Pp
+The
+.Fn erf
+calculates the error function of x; where
+.Bd -filled -offset indent
+.if n \{\
+erf(x) = 2/sqrt(pi)\(**\|integral from 0 to x of exp(\-t\(**t) dt. \}
+.if t \{\
+erf\|(x) :=
+(2/\(sr\(*p)\|\(is\d\s8\z0\s10\u\u\s8x\s10\d\|exp(\-t\u\s82\s10\d)\|dt. \}
+.Ed
+.Pp
+The
+.Fn erfc
+function calculates the complementary error function of
+.Fa x ;
+that is
+.Fn erfc
+subtracts the result of the error function
+.Fn erf x
+from 1.0.
+This is useful, since for large
+.Fa x
+places disappear.
+.Sh SEE ALSO
+.Xr math 3
+.Sh HISTORY
+The
+.Fn erf
+and
+.Fn erfc
+functions appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/exp.3 b/lib/msun/man/exp.3
new file mode 100644
index 000000000000..e6a6908a3801
--- /dev/null
+++ b/lib/msun/man/exp.3
@@ -0,0 +1,287 @@
+.\" Copyright (c) 1985, 1991 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: @(#)exp.3 6.12 (Berkeley) 7/31/91
+.\" $Id: exp.3,v 1.1.1.1 1994/05/06 00:19:46 gclarkii Exp $
+.\"
+.Dd July 31, 1991
+.Dt EXP 3
+.Os BSD 4
+.Sh NAME
+.Nm exp ,
+.Nm exp2 ,
+.Nm exp10 ,
+.Nm expm1 ,
+.Nm log ,
+.Nm log2 ,
+.Nm log10 ,
+.Nm log1p ,
+.Nm pow
+.Nd exponential, logarithm, power functions
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn exp "double x"
+.Ft double
+.Fn expm1 "double x"
+.Ft double
+.Fn log "double x"
+.Ft double
+.Fn log10 "double x"
+.Ft double
+.Fn log1p "double x"
+.Ft double
+.Fn pow "double x" "double y"
+.Sh DESCRIPTION
+The
+.Fn exp
+function computes the exponential value of the given argument
+.Fa x .
+.Pp
+The
+.Fn expm1
+function computes the value exp(x)\-1 accurately even for tiny argument
+.Fa x .
+.Pp
+The
+.Fn log
+function computes the value of the natural logarithm of argument
+.Fa x.
+.Pp
+The
+.Fn log10
+function computes the value of the logarithm of argument
+.Fa x
+to base 10.
+.Pp
+The
+.Fn log1p
+function computes
+the value of log(1+x) accurately even for tiny argument
+.Fa x .
+.Pp
+The
+.Fn pow
+computes the value
+of
+.Ar x
+to the exponent
+.Ar y .
+.Sh ERROR (due to Roundoff etc.)
+exp(x), log(x), expm1(x) and log1p(x) are accurate to within
+an
+.Em ulp ,
+and log10(x) to within about 2
+.Em ulps ;
+an
+.Em ulp
+is one
+.Em Unit
+in the
+.Em Last
+.Em Place .
+The error in
+.Fn pow x y
+is below about 2
+.Em ulps
+when its
+magnitude is moderate, but increases as
+.Fn pow x y
+approaches
+the over/underflow thresholds until almost as many bits could be
+lost as are occupied by the floating\-point format's exponent
+field; that is 8 bits for
+.Tn "VAX D"
+and 11 bits for IEEE 754 Double.
+No such drastic loss has been exposed by testing; the worst
+errors observed have been below 20
+.Em ulps
+for
+.Tn "VAX D" ,
+300
+.Em ulps
+for
+.Tn IEEE
+754 Double.
+Moderate values of
+.Fn pow
+are accurate enough that
+.Fn pow integer integer
+is exact until it is bigger than 2**56 on a
+.Tn VAX ,
+2**53 for
+.Tn IEEE
+754.
+.Sh RETURN VALUES
+These functions will return the appropriate computation unless an error
+occurs or an argument is out of range.
+The functions
+.Fn exp ,
+.Fn expm1
+and
+.Fn pow
+detect if the computed value will overflow,
+set the global variable
+.Va errno to
+.Er ERANGE
+and cause a reserved operand fault on a
+.Tn VAX
+or
+.Tn Tahoe .
+The function
+.Fn pow x y
+checks to see if
+.Fa x
+< 0 and
+.Fa y
+is not an integer, in the event this is true,
+the global variable
+.Va errno
+is set to
+.Er EDOM
+and on the
+.Tn VAX
+and
+.Tn Tahoe
+generate a reserved operand fault.
+On a
+.Tn VAX
+and
+.Tn Tahoe ,
+.Va errno
+is set to
+.Er EDOM
+and the reserved operand is returned
+by log unless
+.Fa x
+> 0, by
+.Fn log1p
+unless
+.Fa x
+> \-1.
+.Sh NOTES
+The functions exp(x)\-1 and log(1+x) are called
+expm1 and logp1 in
+.Tn BASIC
+on the Hewlett\-Packard
+.Tn HP Ns \-71B
+and
+.Tn APPLE
+Macintosh,
+.Tn EXP1
+and
+.Tn LN1
+in Pascal, exp1 and log1 in C
+on
+.Tn APPLE
+Macintoshes, where they have been provided to make
+sure financial calculations of ((1+x)**n\-1)/x, namely
+expm1(n\(**log1p(x))/x, will be accurate when x is tiny.
+They also provide accurate inverse hyperbolic functions.
+.Pp
+The function
+.Fn pow x 0
+returns x**0 = 1 for all x including x = 0,
+.if n \
+Infinity
+.if t \
+\(if
+(not found on a
+.Tn VAX ) ,
+and
+.Em NaN
+(the reserved
+operand on a
+.Tn VAX ) . Previous implementations of pow may
+have defined x**0 to be undefined in some or all of these
+cases. Here are reasons for returning x**0 = 1 always:
+.Bl -enum -width indent
+.It
+Any program that already tests whether x is zero (or
+infinite or \*(Na) before computing x**0 cannot care
+whether 0**0 = 1 or not. Any program that depends
+upon 0**0 to be invalid is dubious anyway since that
+expression's meaning and, if invalid, its consequences
+vary from one computer system to another.
+.It
+Some Algebra texts (e.g. Sigler's) define x**0 = 1 for
+all x, including x = 0.
+This is compatible with the convention that accepts a[0]
+as the value of polynomial
+.Bd -literal -offset indent
+p(x) = a[0]\(**x**0 + a[1]\(**x**1 + a[2]\(**x**2 +...+ a[n]\(**x**n
+.Ed
+.Pp
+at x = 0 rather than reject a[0]\(**0**0 as invalid.
+.It
+Analysts will accept 0**0 = 1 despite that x**y can
+approach anything or nothing as x and y approach 0
+independently.
+The reason for setting 0**0 = 1 anyway is this:
+.Bd -filled -offset indent
+If x(z) and y(z) are
+.Em any
+functions analytic (expandable
+in power series) in z around z = 0, and if there
+x(0) = y(0) = 0, then x(z)**y(z) \(-> 1 as z \(-> 0.
+.Ed
+.It
+If 0**0 = 1, then
+.if n \
+infinity**0 = 1/0**0 = 1 too; and
+.if t \
+\(if**0 = 1/0**0 = 1 too; and
+then \*(Na**0 = 1 too because x**0 = 1 for all finite
+and infinite x, i.e., independently of x.
+.El
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr infnan 3
+.Sh HISTORY
+A
+.Fn exp ,
+.Fn log
+and
+.Fn pow
+functions
+appeared in
+.At v6 .
+A
+.Fn log10
+function
+appeared in
+.At v7 .
+The
+.Fn log1p
+and
+.Fn expm1
+functions appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/fabs.3 b/lib/msun/man/fabs.3
new file mode 100644
index 000000000000..3f32780636e6
--- /dev/null
+++ b/lib/msun/man/fabs.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" @(#)fabs.3 5.1 (Berkeley) 5/2/91
+.\" 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: @(#)fabs.3 5.1 (Berkeley) 5/2/91
+.\" $Id: fabs.3,v 1.1.1.1 1994/05/06 00:19:46 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt FABS 3
+.Os
+.Sh NAME
+.Nm fabs
+.Nd floating-point absolute value function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn fabs "double x"
+.Sh DESCRIPTION
+The
+.Fn fabs
+function computes the absolute value of a floating-point number
+.Fa x .
+.Sh RETURN VALUES
+The
+.Fn fabs
+function returns the absolute value of
+.Fa x .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr ceil 3 ,
+.Xr floor 3 ,
+.Xr rint 3 ,
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fabs
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/floor.3 b/lib/msun/man/floor.3
new file mode 100644
index 000000000000..26ce6e5b8ec2
--- /dev/null
+++ b/lib/msun/man/floor.3
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1985, 1991 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: @(#)floor.3 6.5 (Berkeley) 4/19/91
+.\" $Id: floor.3,v 1.1.1.1 1994/05/06 00:19:45 gclarkii Exp $
+.\"
+.Dd March 10, 1994
+.Dt FLOOR 3
+.Os
+.Sh NAME
+.Nm floor
+.Nd round to largest integral value not greater than x
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn floor "double x"
+.Sh DESCRIPTION
+The
+.Fn floor
+function returns the largest integral value
+(represented as a double precision number)
+less than or equal to
+.Fa x .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr ceil 3 ,
+.Xr fabs 3 ,
+.Xr ieee 3 ,
+.Xr rint 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn floor
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/fmod.3 b/lib/msun/man/fmod.3
new file mode 100644
index 000000000000..5284d33ad5b1
--- /dev/null
+++ b/lib/msun/man/fmod.3
@@ -0,0 +1,76 @@
+.\" Copyright (c) 1991 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: @(#)fmod.3 5.1 (Berkeley) 5/2/91
+.\" $Id: fmod.3,v 1.1.1.1 1994/05/06 00:19:47 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt FMOD 3
+.Os
+.Sh NAME
+.Nm fmod
+.Nd floating-point remainder function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn fmod "double x" "double y"
+.Sh DESCRIPTION
+The
+.Fn fmod
+function computes the floating-point remainder of
+.Fa x Ns / Fa y .
+.Sh RETURN VALUES
+The
+.Fn fmod
+function returns the value
+.Sm off
+.Fa x - Em i * Fa y ,
+.Sm on
+for some integer
+.Em i
+such that, if
+.Fa y
+is non-zero, the result has the same sign as
+.Fa x
+and magnitude less than the magnitude of
+.Fa y .
+If
+.Fa y
+is zero, whether a domain error occurs or the
+.Fn fmod
+function returns zero is implementation-defined.
+.Sh SEE ALSO
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmod
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/hypot.3 b/lib/msun/man/hypot.3
new file mode 100644
index 000000000000..02b6d203a6ff
--- /dev/null
+++ b/lib/msun/man/hypot.3
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1985, 1991 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: @(#)hypot.3 6.7 (Berkeley) 5/6/91
+.\" $Id: hypot.3,v 1.1.1.1 1994/05/06 00:19:47 gclarkii Exp $
+.\"
+.Dd May 6, 1991
+.Dt HYPOT 3
+.Os BSD 4
+.Sh NAME
+.Nm hypot ,
+.Nm cabs
+.Nd euclidean distance and complex absolute value functions
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn hypot "double x" "double y"
+.Fd struct {double x, y;} z;
+.Ft double
+.Fn cabs z
+.Sh DESCRIPTION
+The
+.Fn hypot
+and
+.Fn cabs
+functions
+computes the
+sqrt(x*x+y*y)
+in such a way that underflow will not happen, and overflow
+occurs only if the final result deserves it.
+.Pp
+.Fn hypot "\*(If" "v"
+=
+.Fn hypot "v" "\*(If"
+= +\*(If for all
+.Ar v ,
+including \*(Na.
+.Sh ERROR (due to Roundoff, etc.)
+Below 0.97
+.Em ulps .
+Consequently
+.Fn hypot "5.0" "12.0"
+= 13.0
+exactly;
+in general, hypot and cabs return an integer whenever an
+integer might be expected.
+.Pp
+The same cannot be said for the shorter and faster version of hypot
+and cabs that is provided in the comments in cabs.c; its error can
+exceed 1.2
+.Em ulps .
+.Sh NOTES
+As might be expected,
+.Fn hypot "v" "\*(Na"
+and
+.Fn hypot "\*(Na" "v"
+are \*(Na for all
+.Em finite
+.Ar v ;
+with "reserved operand" in place of "\*(Na", the
+same is true on a
+.Tn VAX .
+But programmers on machines other than a
+.Tn VAX
+(if has no \*(If)
+might be surprised at first to discover that
+.Fn hypot "\(+-\*(If" "\*(Na"
+= +\*(If.
+This is intentional; it happens because
+.Fn hypot "\*(If" "v"
+= +\*(If
+for
+.Em all
+.Ar v ,
+finite or infinite.
+Hence
+.Fn hypot "\*(If" "v"
+is independent of
+.Ar v .
+Unlike the reserved operand fault on a
+.Tn VAX ,
+the
+.Tn IEEE
+\*(Na is designed to
+disappear when it turns out to be irrelevant, as it does in
+.Fn hypot "\*(If" "\*(Na" .
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr sqrt 3
+.Sh HISTORY
+Both a
+.Fn hypot
+function and a
+.Fn cabs
+function
+appeared in
+.At v7 .
diff --git a/lib/msun/man/ieee.3 b/lib/msun/man/ieee.3
new file mode 100644
index 000000000000..3ea72538af25
--- /dev/null
+++ b/lib/msun/man/ieee.3
@@ -0,0 +1,152 @@
+.\" Copyright (c) 1985, 1991 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: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $Id: ieee.3,v 1.1.1.1 1994/05/06 00:19:47 gclarkii Exp $
+.\"
+.Dd Feb 25, 1994
+.Dt IEEE 3
+.Os
+.Sh NAME
+.Nm copysign ,
+.Nm finite ,
+.Nm ilogb ,
+.Nm nextafter ,
+.Nm remainder ,
+.Nm scalbn
+.Nd Functions for IEEE arithmetic
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn copysign "double x" "double y"
+.Ft int
+.Fn finite "double x"
+.Ft int
+.Fn ilogb "double x"
+.Ft double
+.Fn nextafter "double x" "double y"
+.Ft double
+.Fn remainder "double x" "double y"
+.Ft double
+.Fn scalbn "double x" "int n"
+.Sh DESCRIPTION
+These functions are required or recommended by
+.St -ieee754 .
+.Pp
+.Fn copysign
+returns
+.Fa x
+with its sign changed to
+.Fa y Ns 's.
+.Pp
+.Fn finite
+returns the value 1 just when
+\-\*(If \*(Lt
+.Fa x
+\*(Lt +\*(If;
+otherwise a
+zero is returned
+(when
+.Pf \\*(Ba Ns Fa x Ns \\*(Ba
+= \*(If or
+.Fa x
+is \*(Na
+.Pp
+.Fn ilogb
+returns
+.Fa x Ns 's exponent
+.Fa n ,
+in integer format.
+.Fn ilogb \*(Pm\*(If
+returns
+.Dv INT_MAX
+and
+.Fn ilogb 0
+returns
+.Dv INT_MIN .
+.Pp
+.Fn nextafter
+returns the next machine representable number from
+.Fa x
+in direction
+.Fa y .
+.Pp
+.Fn remainder
+returns the remainder
+.Fa r
+:=
+.Fa x
+\-
+.Fa n\(**y
+where
+.Fa n
+is the integer nearest the exact value of
+.Bk -words
+.Fa x Ns / Ns Fa y ;
+.Ek
+moreover if
+.Pf \\*(Ba Fa n
+\-
+.Sm off
+.Fa x No / Fa y No \\*(Ba
+.Sm on
+=
+1/2
+then
+.Fa n
+is even. Consequently
+the remainder is computed exactly and
+.Sm off
+.Pf \\*(Ba Fa r No \\*(Ba
+.Sm on
+\*(Le
+.Sm off
+.Pf \\*(Ba Fa y No \\*(Ba/2.
+.Sm on
+But
+.Fn remainder x 0
+and
+.Fn remainder \*(If 0
+are invalid operations that produce a \*(Na.
+.Pp
+.Fn scalbn
+returns
+.Fa x Ns \(**(2** Ns Fa n )
+computed by exponent manipulation.
+.Sh SEE ALSO
+.Xr math 3
+.Sh HISTORY
+The
+.Nm ieee
+functions appeared in
+.Bx 4.3 .
+.Sh STANDARDS
+.St -ieee754
diff --git a/lib/msun/man/ieee_test.3 b/lib/msun/man/ieee_test.3
new file mode 100644
index 000000000000..6179b6d4adf9
--- /dev/null
+++ b/lib/msun/man/ieee_test.3
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1985, 1991 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: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $Id: ieee_test.3,v 1.1.1.1 1994/05/06 00:19:50 gclarkii Exp $
+.\"
+.Dd March 10, 1994
+.Dt IEEE_TEST 3
+.Os
+.Sh NAME
+.Nm logb ,
+.Nm scalb ,
+.Nm significand
+.Nd IEEE test functions
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn logb "double x"
+.Ft double
+.Fn scalb "double x" "double n"
+.Ft double
+.Fn significand "double x"
+.Sh DESCRIPTION
+These functions allow users to test conformance to
+.St -ieee754 .
+Their use is not otherwise recommended.
+.Pp
+.Fn logb x
+returns
+.Fa x Ns 's exponent
+.Fa n ,
+a signed integer converted to double\-precision floating\-point.
+.Fn logb \*(Pm\*(If
+= +\*(If;
+.Fn logb 0
+= -\*(If with a division by zero exception.
+.Pp
+.Fn scalbn x n
+returns
+.Fa x Ns \(**(2** Ns Fa n )
+computed by exponent manipulation.
+.Pp
+.Fn significand x
+returns
+.Fa sig ,
+where
+.Fa x
+:=
+.Fa sig No \(** 2** Ns Fa n
+with 1 \(<=
+.Fa sig
+< 2.
+.Fn significand x
+is not defined when
+.Fa x
+is 0, \*(Pm\*(If, or \*(Na.
+.Sh SEE ALSO
+.Xr ieee 3 ,
+.Xr math 3
+
+.Sh STANDARDS
+.St -ieee754
diff --git a/lib/msun/man/j0.3 b/lib/msun/man/j0.3
new file mode 100644
index 000000000000..63546bdd2e05
--- /dev/null
+++ b/lib/msun/man/j0.3
@@ -0,0 +1,128 @@
+.\" Copyright (c) 1985, 1991 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: @(#)j0.3 6.7 (Berkeley) 4/19/91
+.\" $Id: j0.3,v 1.1.1.1 1994/05/06 00:19:48 gclarkii Exp $
+.\"
+.Dd April 19, 1991
+.Dt J0 3
+.Os BSD 4
+.Sh NAME
+.Nm j0 ,
+.Nm j1 ,
+.Nm jn ,
+.Nm y0 ,
+.Nm y1 ,
+.Nm yn
+.Nd bessel functions of first and second kind
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn j0 "double x"
+.Ft double
+.Fn j1 "double x"
+.Ft double
+.Fn jn "int n" "double x"
+.Ft double
+.Fn y0 "double x"
+.Ft double
+.Fn y1 "double x"
+.Ft double
+.Fn yn "int n" "double x"
+.Sh DESCRIPTION
+The functions
+.Fn j0
+and
+.Fn j1
+compute the
+.Em Bessel function of the first kind of the order
+0 and the
+.Em order
+1, respectively,
+for the
+real value
+.Fa x ;
+the function
+.Fn jn
+computes the
+.Em Bessel function of the first kind of the integer order
+.Fa n
+for the real value
+.Fa x .
+.Pp
+The functions
+.Fn y0
+and
+.Fn y1
+compute the linearly independent
+.Em Bessel function of the second kind of the order
+0 and the
+.Em order
+1, respectively,
+for the
+positive
+.Em integer
+value
+.Fa x
+(expressed as a double);
+the function
+.Fn yn
+computes the
+.Em Bessel function of the second kind for the integer order
+.Fa n
+for the positive
+.Em integer
+value
+.Fa x
+(expressed as a double).
+.Sh RETURN VALUES
+If these functions are successful,
+the computed value is returned. On the
+.Tn VAX
+and
+.Tn Tahoe
+architectures,
+a negative
+.Fa x
+value
+results in an error; the global
+variable
+.Va errno
+is set to
+.Er EDOM
+and a reserve operand fault is generated.
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr infnan 3
+.Sh HISTORY
+This set of functions
+appeared in
+.At v7 .
diff --git a/lib/msun/man/lgamma.3 b/lib/msun/man/lgamma.3
new file mode 100644
index 000000000000..8e4426356905
--- /dev/null
+++ b/lib/msun/man/lgamma.3
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1985, 1991 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: @(#)lgamma.3 6.6 (Berkeley) 12/3/92
+.\" $Id: lgamma.3,v 1.1.1.1 1994/05/06 00:19:48 gclarkii Exp $
+.\"
+.Dd December 3, 1992
+.Dt LGAMMA 3
+.Os BSD 4.3
+.Sh NAME
+.Nm lgamma ,
+.Nm gamma
+.Nd log gamma function, gamma function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft extern int
+.Fa signgam ;
+.sp
+.Ft double
+.Fn lgamma "double x"
+.Ft double
+.Fn gamma "double x"
+.Sh DESCRIPTION
+.Fn Lgamma x
+.if t \{\
+returns ln\||\(*G(x)| where
+.Bd -unfilled -offset indent
+\(*G(x) = \(is\d\s8\z0\s10\u\u\s8\(if\s10\d t\u\s8x\-1\s10\d e\u\s8\-t\s10\d dt for x > 0 and
+.br
+\(*G(x) = \(*p/(\(*G(1\-x)\|sin(\(*px)) for x < 1.
+.Ed
+.\}
+.if n \
+returns ln\||\(*G(x)|.
+.Pp
+The external integer
+.Fa signgam
+returns the sign of \(*G(x).
+.Pp
+.Fn Gamma x
+returns \(*G(x), with no effect on
+.Fa signgam .
+.Sh IDIOSYNCRASIES
+Do not use the expression
+.Dq Li signgam\(**exp(lgamma(x))
+to compute g := \(*G(x).
+Instead use a program like this (in C):
+.Bd -literal -offset indent
+lg = lgamma(x); g = signgam\(**exp(lg);
+.Ed
+.Pp
+Only after
+.Fn lgamma
+has returned can signgam be correct.
+.Pp
+For arguments in its range,
+.Fn gamma
+is preferred, as for positive arguments
+it is accurate to within one unit in the last place.
+Exponentiation of
+.Fn lgamma
+will lose up to 10 significant bits.
+.Sh RETURN VALUES
+.Fn Gamma
+and
+.Fn lgamma
+return appropriate values unless an argument is out of range.
+Overflow will occur for sufficiently large positive values, and
+non-positive integers.
+On the
+.Tn VAX,
+the reserved operator is returned,
+and
+.Va errno
+is set to
+.Er ERANGE
+For large non-integer negative values,
+.Fn gamma
+will underflow.
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr infnan 3
+.Sh HISTORY
+The
+.Nm lgamma
+function appeared in
+.Bx 4.3 .
+The
+.Nm gamma
+function appeared in
+.Bx 4.4 .
+The name
+.Fn gamma
+was originally dedicated to the
+.Fn lgamma
+function, so some old code may no longer be compatible.
diff --git a/lib/msun/man/math.3 b/lib/msun/man/math.3
new file mode 100644
index 000000000000..9c3b6e2f2345
--- /dev/null
+++ b/lib/msun/man/math.3
@@ -0,0 +1,633 @@
+.\" Copyright (c) 1985 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: @(#)math.3 6.10 (Berkeley) 5/6/91
+.\" $Id: math.3,v 1.1.1.1 1994/05/06 00:19:43 gclarkii Exp $
+.\"
+.TH MATH 3M "May 6, 1991"
+.UC 4
+.ds up \fIulp\fR
+.ds nn \fINaN\fR
+.de If
+.if n \\
+\\$1Infinity\\$2
+.if t \\
+\\$1\\(if\\$2
+..
+.SH NAME
+math \- introduction to mathematical library functions
+.SH DESCRIPTION
+These functions constitute the C math library,
+.I libm.
+The link editor searches this library under the \*(lq\-lm\*(rq option.
+Declarations for these functions may be obtained from the include file
+.RI < math.h >.
+The Fortran math library is described in ``man 3f intro''.
+.SH "LIST OF FUNCTIONS"
+.sp 2
+.nf
+.ta \w'copysign'u+2n +\w'infnan.3m'u+10n +\w'inverse trigonometric func'u
+\fIName\fP \fIAppears on Page\fP \fIDescription\fP \fIError Bound (ULPs)\fP
+.ta \w'copysign'u+4n +\w'infnan.3m'u+4n +\w'inverse trigonometric function'u+6nC
+.sp 5p
+acos sin.3m inverse trigonometric function 3
+acosh asinh.3m inverse hyperbolic function 3
+asin sin.3m inverse trigonometric function 3
+asinh asinh.3m inverse hyperbolic function 3
+atan sin.3m inverse trigonometric function 1
+atanh asinh.3m inverse hyperbolic function 3
+atan2 sin.3m inverse trigonometric function 2
+cabs hypot.3m complex absolute value 1
+cbrt sqrt.3m cube root 1
+ceil floor.3m integer no less than 0
+copysign ieee.3m copy sign bit 0
+cos sin.3m trigonometric function 1
+cosh sinh.3m hyperbolic function 3
+erf erf.3m error function ???
+erfc erf.3m complementary error function ???
+exp exp.3m exponential 1
+expm1 exp.3m exp(x)\-1 1
+fabs floor.3m absolute value 0
+floor floor.3m integer no greater than 0
+hypot hypot.3m Euclidean distance 1
+ilogb ieee.3m exponent extraction 0
+infnan infnan.3m signals exceptions
+j0 j0.3m bessel function ???
+j1 j0.3m bessel function ???
+jn j0.3m bessel function ???
+lgamma lgamma.3m log gamma function; (formerly gamma.3m)
+log exp.3m natural logarithm 1
+log10 exp.3m logarithm to base 10 3
+log1p exp.3m log(1+x) 1
+pow exp.3m exponential x**y 60\-500
+remainder ieee.3m remainder 0
+rint floor.3m round to nearest integer 0
+scalbn ieee.3m exponent adjustment 0
+sin sin.3m trigonometric function 1
+sinh sinh.3m hyperbolic function 3
+sqrt sqrt.3m square root 1
+tan sin.3m trigonometric function 3
+tanh sinh.3m hyperbolic function 3
+y0 j0.3m bessel function ???
+y1 j0.3m bessel function ???
+yn j0.3m bessel function ???
+.ta
+.fi
+.SH NOTES
+In 4.3 BSD, distributed from the University of California
+in late 1985, most of the foregoing functions come in two
+versions, one for the double\-precision "D" format in the
+DEC VAX\-11 family of computers, another for double\-precision
+arithmetic conforming to the IEEE Standard 754 for Binary
+Floating\-Point Arithmetic. The two versions behave very
+similarly, as should be expected from programs more accurate
+and robust than was the norm when UNIX was born. For
+instance, the programs are accurate to within the numbers
+of \*(ups tabulated above; an \*(up is one \fIU\fRnit in the \fIL\fRast
+\fIP\fRlace. And the programs have been cured of anomalies that
+afflicted the older math library \fIlibm\fR in which incidents like
+the following had been reported:
+.RS
+sqrt(\-1.0) = 0.0 and log(\-1.0) = \-1.7e38.
+.br
+cos(1.0e\-11) > cos(0.0) > 1.0.
+.br
+pow(x,1.0)
+.if n \
+!=
+.if t \
+\(!=
+x when x = 2.0, 3.0, 4.0, ..., 9.0.
+.br
+pow(\-1.0,1.0e10) trapped on Integer Overflow.
+.br
+sqrt(1.0e30) and sqrt(1.0e\-30) were very slow.
+.RE
+However the two versions do differ in ways that have to be
+explained, to which end the following notes are provided.
+.PP
+\fBDEC VAX\-11 D_floating\-point:\fR
+.PP
+This is the format for which the original math library \fIlibm\fR
+was developed, and to which this manual is still principally
+dedicated. It is \fIthe\fR double\-precision format for the PDP\-11
+and the earlier VAX\-11 machines; VAX\-11s after 1983 were
+provided with an optional "G" format closer to the IEEE
+double\-precision format. The earlier DEC MicroVAXs have no
+D format, only G double\-precision. (Why? Why not?)
+.PP
+Properties of D_floating\-point:
+.RS
+Wordsize: 64 bits, 8 bytes. Radix: Binary.
+.br
+Precision: 56
+.if n \
+sig.
+.if t \
+significant
+bits, roughly like 17
+.if n \
+sig.
+.if t \
+significant
+decimals.
+.RS
+If x and x' are consecutive positive D_floating\-point
+numbers (they differ by 1 \*(up), then
+.br
+1.3e\-17 < 0.5**56 < (x'\-x)/x \(<= 0.5**55 < 2.8e\-17.
+.RE
+.nf
+.ta \w'Range:'u+1n +\w'Underflow threshold'u+1n +\w'= 2.0**127'u+1n
+Range: Overflow threshold = 2.0**127 = 1.7e38.
+ Underflow threshold = 0.5**128 = 2.9e\-39.
+ NOTE: THIS RANGE IS COMPARATIVELY NARROW.
+.ta
+.fi
+.RS
+Overflow customarily stops computation.
+.br
+Underflow is customarily flushed quietly to zero.
+.br
+CAUTION:
+.RS
+It is possible to have x
+.if n \
+!=
+.if t \
+\(!=
+y and yet
+x\-y = 0 because of underflow. Similarly
+x > y > 0 cannot prevent either x\(**y = 0
+or y/x = 0 from happening without warning.
+.RE
+.RE
+Zero is represented ambiguously.
+.RS
+Although 2**55 different representations of zero are accepted by
+the hardware, only the obvious representation is ever produced.
+There is no \-0 on a VAX.
+.RE
+.If
+is not part of the VAX architecture.
+.br
+Reserved operands:
+.RS
+of the 2**55 that the hardware
+recognizes, only one of them is ever produced.
+Any floating\-point operation upon a reserved
+operand, even a MOVF or MOVD, customarily stops
+computation, so they are not much used.
+.RE
+Exceptions:
+.RS
+Divisions by zero and operations that
+overflow are invalid operations that customarily
+stop computation or, in earlier machines, produce
+reserved operands that will stop computation.
+.RE
+Rounding:
+.RS
+Every rational operation (+, \-, \(**, /) on a
+VAX (but not necessarily on a PDP\-11), if not an
+over/underflow nor division by zero, is rounded to
+within half an \*(up, and when the rounding error is
+exactly half an \*(up then rounding is away from 0.
+.RE
+.RE
+.PP
+Except for its narrow range, D_floating\-point is one of the
+better computer arithmetics designed in the 1960's.
+Its properties are reflected fairly faithfully in the elementary
+functions for a VAX distributed in 4.3 BSD.
+They over/underflow only if their results have to lie out of range
+or very nearly so, and then they behave much as any rational
+arithmetic operation that over/underflowed would behave.
+Similarly, expressions like log(0) and atanh(1) behave
+like 1/0; and sqrt(\-3) and acos(3) behave like 0/0;
+they all produce reserved operands and/or stop computation!
+The situation is described in more detail in manual pages.
+.RS
+.ll -0.5i
+\fIThis response seems excessively punitive, so it is destined
+to be replaced at some time in the foreseeable future by a
+more flexible but still uniform scheme being developed to
+handle all floating\-point arithmetic exceptions neatly.
+See infnan(3M) for the present state of affairs.\fR
+.ll +0.5i
+.RE
+.PP
+How do the functions in 4.3 BSD's new \fIlibm\fR for UNIX
+compare with their counterparts in DEC's VAX/VMS library?
+Some of the VMS functions are a little faster, some are
+a little more accurate, some are more puritanical about
+exceptions (like pow(0.0,0.0) and atan2(0.0,0.0)),
+and most occupy much more memory than their counterparts in
+\fIlibm\fR.
+The VMS codes interpolate in large table to achieve
+speed and accuracy; the \fIlibm\fR codes use tricky formulas
+compact enough that all of them may some day fit into a ROM.
+.PP
+More important, DEC regards the VMS codes as proprietary
+and guards them zealously against unauthorized use. But the
+\fIlibm\fR codes in 4.3 BSD are intended for the public domain;
+they may be copied freely provided their provenance is always
+acknowledged, and provided users assist the authors in their
+researches by reporting experience with the codes.
+Therefore no user of UNIX on a machine whose arithmetic resembles
+VAX D_floating\-point need use anything worse than the new \fIlibm\fR.
+.PP
+\fBIEEE STANDARD 754 Floating\-Point Arithmetic:\fR
+.PP
+This standard is on its way to becoming more widely adopted
+than any other design for computer arithmetic.
+VLSI chips that conform to some version of that standard have been
+produced by a host of manufacturers, among them ...
+.nf
+.ta 0.5i +\w'Intel i8070, i80287'u+6n
+ Intel i8087, i80287 National Semiconductor 32081
+ Motorola 68881 Weitek WTL-1032, ... , -1165
+ Zilog Z8070 Western Electric (AT&T) WE32106.
+.ta
+.fi
+Other implementations range from software, done thoroughly
+in the Apple Macintosh, through VLSI in the Hewlett\-Packard
+9000 series, to the ELXSI 6400 running ECL at 3 Megaflops.
+Several other companies have adopted the formats
+of IEEE 754 without, alas, adhering to the standard's way
+of handling rounding and exceptions like over/underflow.
+The DEC VAX G_floating\-point format is very similar to the IEEE
+754 Double format, so similar that the C programs for the
+IEEE versions of most of the elementary functions listed
+above could easily be converted to run on a MicroVAX, though
+nobody has volunteered to do that yet.
+.PP
+The codes in 4.3 BSD's \fIlibm\fR for machines that conform to
+IEEE 754 are intended primarily for the National Semi. 32081
+and WTL 1164/65. To use these codes with the Intel or Zilog
+chips, or with the Apple Macintosh or ELXSI 6400, is to
+forego the use of better codes provided (perhaps freely) by
+those companies and designed by some of the authors of the
+codes above.
+Except for \fIatan\fR, \fIcabs\fR, \fIcbrt\fR, \fIerf\fR,
+\fIerfc\fR, \fIhypot\fR, \fIj0\-jn\fR, \fIlgamma\fR, \fIpow\fR
+and \fIy0\-yn\fR,
+the Motorola 68881 has all the functions in \fIlibm\fR on chip,
+and faster and more accurate;
+it, Apple, the i8087, Z8070 and WE32106 all use 64
+.if n \
+sig.
+.if t \
+significant
+bits.
+The main virtue of 4.3 BSD's
+\fIlibm\fR codes is that they are intended for the public domain;
+they may be copied freely provided their provenance is always
+acknowledged, and provided users assist the authors in their
+researches by reporting experience with the codes.
+Therefore no user of UNIX on a machine that conforms to
+IEEE 754 need use anything worse than the new \fIlibm\fR.
+.PP
+Properties of IEEE 754 Double\-Precision:
+.RS
+Wordsize: 64 bits, 8 bytes. Radix: Binary.
+.br
+Precision: 53
+.if n \
+sig.
+.if t \
+significant
+bits, roughly like 16
+.if n \
+sig.
+.if t \
+significant
+decimals.
+.RS
+If x and x' are consecutive positive Double\-Precision
+numbers (they differ by 1 \*(up), then
+.br
+1.1e\-16 < 0.5**53 < (x'\-x)/x \(<= 0.5**52 < 2.3e\-16.
+.RE
+.nf
+.ta \w'Range:'u+1n +\w'Underflow threshold'u+1n +\w'= 2.0**1024'u+1n
+Range: Overflow threshold = 2.0**1024 = 1.8e308
+ Underflow threshold = 0.5**1022 = 2.2e\-308
+.ta
+.fi
+.RS
+Overflow goes by default to a signed
+.If "" .
+.br
+Underflow is \fIGradual,\fR rounding to the nearest
+integer multiple of 0.5**1074 = 4.9e\-324.
+.RE
+Zero is represented ambiguously as +0 or \-0.
+.RS
+Its sign transforms correctly through multiplication or
+division, and is preserved by addition of zeros
+with like signs; but x\-x yields +0 for every
+finite x. The only operations that reveal zero's
+sign are division by zero and copysign(x,\(+-0).
+In particular, comparison (x > y, x \(>= y, etc.)
+cannot be affected by the sign of zero; but if
+finite x = y then
+.If
+\&= 1/(x\-y)
+.if n \
+!=
+.if t \
+\(!=
+\-1/(y\-x) =
+.If \- .
+.RE
+.If
+is signed.
+.RS
+it persists when added to itself
+or to any finite number. Its sign transforms
+correctly through multiplication and division, and
+.If (finite)/\(+- \0=\0\(+-0
+(nonzero)/0 =
+.If \(+- .
+But
+.if n \
+Infinity\-Infinity, Infinity\(**0 and Infinity/Infinity
+.if t \
+\(if\-\(if, \(if\(**0 and \(if/\(if
+are, like 0/0 and sqrt(\-3),
+invalid operations that produce \*(nn. ...
+.RE
+Reserved operands:
+.RS
+there are 2**53\-2 of them, all
+called \*(nn (\fIN\fRot \fIa N\fRumber).
+Some, called Signaling \*(nns, trap any floating\-point operation
+performed upon them; they are used to mark missing
+or uninitialized values, or nonexistent elements
+of arrays. The rest are Quiet \*(nns; they are
+the default results of Invalid Operations, and
+propagate through subsequent arithmetic operations.
+If x
+.if n \
+!=
+.if t \
+\(!=
+x then x is \*(nn; every other predicate
+(x > y, x = y, x < y, ...) is FALSE if \*(nn is involved.
+.br
+NOTE: Trichotomy is violated by \*(nn.
+.RS
+Besides being FALSE, predicates that entail ordered
+comparison, rather than mere (in)equality,
+signal Invalid Operation when \*(nn is involved.
+.RE
+.RE
+Rounding:
+.RS
+Every algebraic operation (+, \-, \(**, /,
+.if n \
+sqrt)
+.if t \
+\(sr)
+is rounded by default to within half an \*(up, and
+when the rounding error is exactly half an \*(up then
+the rounded value's least significant bit is zero.
+This kind of rounding is usually the best kind,
+sometimes provably so; for instance, for every
+x = 1.0, 2.0, 3.0, 4.0, ..., 2.0**52, we find
+(x/3.0)\(**3.0 == x and (x/10.0)\(**10.0 == x and ...
+despite that both the quotients and the products
+have been rounded. Only rounding like IEEE 754
+can do that. But no single kind of rounding can be
+proved best for every circumstance, so IEEE 754
+provides rounding towards zero or towards
+.If +
+or towards
+.If \-
+at the programmer's option. And the
+same kinds of rounding are specified for
+Binary\-Decimal Conversions, at least for magnitudes
+between roughly 1.0e\-10 and 1.0e37.
+.RE
+Exceptions:
+.RS
+IEEE 754 recognizes five kinds of floating\-point exceptions,
+listed below in declining order of probable importance.
+.RS
+.nf
+.ta \w'Invalid Operation'u+6n +\w'Gradual Underflow'u+2n
+Exception Default Result
+.tc \(ru
+
+.tc
+Invalid Operation \*(nn, or FALSE
+.if n \{\
+Overflow \(+-Infinity
+Divide by Zero \(+-Infinity \}
+.if t \{\
+Overflow \(+-\(if
+Divide by Zero \(+-\(if \}
+Underflow Gradual Underflow
+Inexact Rounded value
+.ta
+.fi
+.RE
+NOTE: An Exception is not an Error unless handled
+badly. What makes a class of exceptions exceptional
+is that no single default response can be satisfactory
+in every instance. On the other hand, if a default
+response will serve most instances satisfactorily,
+the unsatisfactory instances cannot justify aborting
+computation every time the exception occurs.
+.RE
+.PP
+For each kind of floating\-point exception, IEEE 754
+provides a Flag that is raised each time its exception
+is signaled, and stays raised until the program resets
+it. Programs may also test, save and restore a flag.
+Thus, IEEE 754 provides three ways by which programs
+may cope with exceptions for which the default result
+might be unsatisfactory:
+.IP 1) \w'\0\0\0\0'u
+Test for a condition that might cause an exception
+later, and branch to avoid the exception.
+.IP 2) \w'\0\0\0\0'u
+Test a flag to see whether an exception has occurred
+since the program last reset its flag.
+.IP 3) \w'\0\0\0\0'u
+Test a result to see whether it is a value that only
+an exception could have produced.
+.RS
+CAUTION: The only reliable ways to discover
+whether Underflow has occurred are to test whether
+products or quotients lie closer to zero than the
+underflow threshold, or to test the Underflow
+flag. (Sums and differences cannot underflow in
+IEEE 754; if x
+.if n \
+!=
+.if t \
+\(!=
+y then x\-y is correct to
+full precision and certainly nonzero regardless of
+how tiny it may be.) Products and quotients that
+underflow gradually can lose accuracy gradually
+without vanishing, so comparing them with zero
+(as one might on a VAX) will not reveal the loss.
+Fortunately, if a gradually underflowed value is
+destined to be added to something bigger than the
+underflow threshold, as is almost always the case,
+digits lost to gradual underflow will not be missed
+because they would have been rounded off anyway.
+So gradual underflows are usually \fIprovably\fR ignorable.
+The same cannot be said of underflows flushed to 0.
+.RE
+.PP
+At the option of an implementor conforming to IEEE 754,
+other ways to cope with exceptions may be provided:
+.IP 4) \w'\0\0\0\0'u
+ABORT. This mechanism classifies an exception in
+advance as an incident to be handled by means
+traditionally associated with error\-handling
+statements like "ON ERROR GO TO ...". Different
+languages offer different forms of this statement,
+but most share the following characteristics:
+.IP \(em \w'\0\0\0\0'u
+No means is provided to substitute a value for
+the offending operation's result and resume
+computation from what may be the middle of an
+expression. An exceptional result is abandoned.
+.IP \(em \w'\0\0\0\0'u
+In a subprogram that lacks an error\-handling
+statement, an exception causes the subprogram to
+abort within whatever program called it, and so
+on back up the chain of calling subprograms until
+an error\-handling statement is encountered or the
+whole task is aborted and memory is dumped.
+.IP 5) \w'\0\0\0\0'u
+STOP. This mechanism, requiring an interactive
+debugging environment, is more for the programmer
+than the program. It classifies an exception in
+advance as a symptom of a programmer's error; the
+exception suspends execution as near as it can to
+the offending operation so that the programmer can
+look around to see how it happened. Quite often
+the first several exceptions turn out to be quite
+unexceptionable, so the programmer ought ideally
+to be able to resume execution after each one as if
+execution had not been stopped.
+.IP 6) \w'\0\0\0\0'u
+\&... Other ways lie beyond the scope of this document.
+.RE
+.PP
+The crucial problem for exception handling is the problem of
+Scope, and the problem's solution is understood, but not
+enough manpower was available to implement it fully in time
+to be distributed in 4.3 BSD's \fIlibm\fR. Ideally, each
+elementary function should act as if it were indivisible, or
+atomic, in the sense that ...
+.IP i) \w'iii)'u+2n
+No exception should be signaled that is not deserved by
+the data supplied to that function.
+.IP ii) \w'iii)'u+2n
+Any exception signaled should be identified with that
+function rather than with one of its subroutines.
+.IP iii) \w'iii)'u+2n
+The internal behavior of an atomic function should not
+be disrupted when a calling program changes from
+one to another of the five or so ways of handling
+exceptions listed above, although the definition
+of the function may be correlated intentionally
+with exception handling.
+.PP
+Ideally, every programmer should be able \fIconveniently\fR to
+turn a debugged subprogram into one that appears atomic to
+its users. But simulating all three characteristics of an
+atomic function is still a tedious affair, entailing hosts
+of tests and saves\-restores; work is under way to ameliorate
+the inconvenience.
+.PP
+Meanwhile, the functions in \fIlibm\fR are only approximately
+atomic. They signal no inappropriate exception except
+possibly ...
+.RS
+Over/Underflow
+.RS
+when a result, if properly computed, might have lain barely within range, and
+.RE
+Inexact in \fIcabs\fR, \fIcbrt\fR, \fIhypot\fR, \fIlog10\fR and \fIpow\fR
+.RS
+when it happens to be exact, thanks to fortuitous cancellation of errors.
+.RE
+.RE
+Otherwise, ...
+.RS
+Invalid Operation is signaled only when
+.RS
+any result but \*(nn would probably be misleading.
+.RE
+Overflow is signaled only when
+.RS
+the exact result would be finite but beyond the overflow threshold.
+.RE
+Divide\-by\-Zero is signaled only when
+.RS
+a function takes exactly infinite values at finite operands.
+.RE
+Underflow is signaled only when
+.RS
+the exact result would be nonzero but tinier than the underflow threshold.
+.RE
+Inexact is signaled only when
+.RS
+greater range or precision would be needed to represent the exact result.
+.RE
+.RE
+.SH BUGS
+When signals are appropriate, they are emitted by certain
+operations within the codes, so a subroutine\-trace may be
+needed to identify the function with its signal in case
+method 5) above is in use. And the codes all take the
+IEEE 754 defaults for granted; this means that a decision to
+trap all divisions by zero could disrupt a code that would
+otherwise get correct results despite division by zero.
+.SH SEE ALSO
+An explanation of IEEE 754 and its proposed extension p854
+was published in the IEEE magazine MICRO in August 1984 under
+the title "A Proposed Radix\- and Word\-length\-independent
+Standard for Floating\-point Arithmetic" by W. J. Cody et al.
+The manuals for Pascal, C and BASIC on the Apple Macintosh
+document the features of IEEE 754 pretty well.
+Articles in the IEEE magazine COMPUTER vol. 14 no. 3 (Mar.
+1981), and in the ACM SIGNUM Newsletter Special Issue of
+Oct. 1979, may be helpful although they pertain to
+superseded drafts of the standard.
diff --git a/lib/msun/man/rint.3 b/lib/msun/man/rint.3
new file mode 100644
index 000000000000..83e847771e37
--- /dev/null
+++ b/lib/msun/man/rint.3
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1985, 1991 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: @(#)rint.3 5.1 (Berkeley) 5/2/91
+.\" $Id: rint.3,v 1.1.1.1 1994/05/06 00:19:47 gclarkii Exp $
+.\"
+.Dd March 10, 1994
+.Dt RINT 3
+.Os
+.Sh NAME
+.Nm rint
+.Nd round to integral value in floating-point format
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn rint "double x"
+.Sh DESCRIPTION
+The
+.Fn rint
+function returns the integral value (represented as a double precision number)
+nearest to
+.Fa x
+according to the prevailing rounding mode.
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr ceil 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr math 3
+.Sh HISTORY
+A
+.Fn rint
+function appeared in
+.At v6 .
diff --git a/lib/msun/man/sin.3 b/lib/msun/man/sin.3
new file mode 100644
index 000000000000..556af48b2c8f
--- /dev/null
+++ b/lib/msun/man/sin.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" @(#)sin.3 6.7 (Berkeley) 4/19/91
+.\" 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: @(#)sin.3 6.7 (Berkeley) 4/19/91
+.\" $Id: sin.3,v 1.1.1.1 1994/05/06 00:19:48 gclarkii Exp $
+.\"
+.Dd April 19, 1991
+.Dt SIN 3
+.Os
+.Sh NAME
+.Nm sin
+.Nd sine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn sin "double x"
+.Sh DESCRIPTION
+The
+.Fn sin
+function computes the sine of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result with little
+or no significance.
+.Sh RETURN VALUES
+The
+.Fn sin
+function returns the sine value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn sin
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/sinh.3 b/lib/msun/man/sinh.3
new file mode 100644
index 000000000000..c8367d1d8fa5
--- /dev/null
+++ b/lib/msun/man/sinh.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1991 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: @(#)sinh.3 6.6 (Berkeley) 4/19/91
+.\" $Id: sinh.3,v 1.1.1.1 1994/05/06 00:19:49 gclarkii Exp $
+.Dd April 19, 1991
+.Dt SINH 3
+.Os
+.Sh NAME
+.Nm sinh
+.Nd hyperbolic sine function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn sinh "double x"
+.Sh DESCRIPTION
+The
+.Fn sinh
+function computes the hyperbolic sine of
+.Fa x .
+.Sh RETURN VALUES
+The
+.Fn sinh
+function returns the hyperbolic sine value unless
+the magnitude
+of
+.Fa x
+is too large; in this event, the global variable
+.Va errno
+is set to
+.Er ERANGE .
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr tan 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn sinh
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/sqrt.3 b/lib/msun/man/sqrt.3
new file mode 100644
index 000000000000..f8f80dea133f
--- /dev/null
+++ b/lib/msun/man/sqrt.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 1985, 1991 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: @(#)sqrt.3 6.4 (Berkeley) 5/6/91
+.\" $Id: sqrt.3,v 1.1.1.1 1994/05/06 00:19:49 gclarkii Exp $
+.\"
+.Dd May 6, 1991
+.Dt SQRT 3
+.Os
+.Sh NAME
+.Nm cbrt ,
+.Nm sqrt
+.Nd cube root and square root functions
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn cbrt "double x"
+.Ft double
+.Fn sqrt "double x"
+.Sh DESCRIPTION
+The
+.Fn cbrt
+function computes
+the cube root of
+.Ar x .
+.Pp
+The
+.Fn sqrt
+computes the
+non-negative square root of x.
+.Sh RETURN VALUES
+The
+.Fn cbrt
+function returns the requested cube root.
+The
+.Fn sqrt
+function returns the requested square root
+unless an error occurs.
+On the
+.Tn VAX
+or
+.Tn Tahoe
+processor an attempt to take the
+.Fn sqrt
+of negative
+.Fa x
+causes an error; in this event,
+the global variable
+.Va errno
+is set to
+.Dv EDOM
+and a reserved operand fault is generated.
+.Sh ERROR (due to Roundoff etc.)
+The
+.Fn cbrt
+function
+is accurate to within 0.7
+.Em ulps .
+.Pp
+The
+.Fn sqrt
+function on a
+.Tn VAX
+is accurate to within 0.501
+.Em ulps .
+Sqrt on a machine that conforms to
+.Tn IEEE
+754 is correctly rounded
+in accordance with the rounding mode in force; the error is less than
+half an
+.Em ulp
+in the default mode (round\-to\-nearest).
+An
+.Em ulp
+is one
+.Em U Ns nit
+in the
+.Em L Ns ast
+.Em P Ns lace
+carried.
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr infnan 3
+.Sh STANDARDS
+The
+.Nm sqrt
+function conforms to
+.St -ansiC .
+.Sh HISTORY
+The
+.Nm cbrt
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/tan.3 b/lib/msun/man/tan.3
new file mode 100644
index 000000000000..f8e406abf47b
--- /dev/null
+++ b/lib/msun/man/tan.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1991 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: @(#)tan.3 5.1 (Berkeley) 5/2/91
+.\" $Id: tan.3,v 1.1.1.1 1994/05/06 00:19:49 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt TAN 3
+.Os
+.Sh NAME
+.Nm tan
+.Nd tangent function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn tan "double x"
+.Sh DESCRIPTION
+The
+.Fn tan
+function computes the tangent of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result
+with little or no significance.
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn tan
+function returns the tangent value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tanh 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn tan
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/man/tanh.3 b/lib/msun/man/tanh.3
new file mode 100644
index 000000000000..09ae02b84599
--- /dev/null
+++ b/lib/msun/man/tanh.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1991 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: @(#)tanh.3 5.1 (Berkeley) 5/2/91
+.\" $Id: tanh.3,v 1.1.1.1 1994/05/06 00:19:50 gclarkii Exp $
+.\"
+.Dd May 2, 1991
+.Dt TANH 3
+.Os
+.Sh NAME
+.Nm tanh
+.Nd hyperbolic tangent function
+.Sh SYNOPSIS
+.Fd #include <math.h>
+.Ft double
+.Fn tanh "double x"
+.Sh DESCRIPTION
+The
+.Fn tanh
+function computes the hyperbolic tangent of
+.Fa x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn tanh
+function returns the hyperbolic tangent value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn tanh
+function conforms to
+.St -ansiC .
diff --git a/lib/msun/src/Readme b/lib/msun/src/Readme
new file mode 100644
index 000000000000..97b134230ced
--- /dev/null
+++ b/lib/msun/src/Readme
@@ -0,0 +1,211 @@
+===========================================================
+ FDLIBM
+============================================================
+ (developed at SunPro, a Sun Microsystems, Inc. business.)
+ Version 5.1, 93/09/24
+
+
+FDLIBM (Freely Distributable LIBM) is a C math library
+for machines that support IEEE 754 floating-point arithmetic.
+In this release, only double precision is supported.
+
+FDLIBM is intended to provide a reasonably portable (see
+assumptions below), reference quality (below one ulp for
+major functions like sin,cos,exp,log) math library
+(libm.a). For a copy of FDLIBM, please send
+e-mail to
+ fdlibm-comments@sunpro.eng.sun.com
+
+--------------
+1. ASSUMPTIONS
+--------------
+FDLIBM (double precision version) assumes:
+ a. IEEE 754 style (if not precise compliance) arithmetic;
+ b. 32 bit 2's complement integer arithmetic;
+ c. Each double precision floating-point number must be in IEEE 754
+ double format, and that each number can be retrieved as two 32-bit
+ integers;
+
+ Example: let y = 2.0
+ double fp number y: 2.0
+ IEEE double format: 0x4000000000000000
+
+ Referencing y as two integers:
+ *(int*)&y,*(1+(int*)&y) = {0x40000000,0x0} (on sparc)
+ {0x0,0x40000000} (on 386)
+
+ Note: FDLIBM will detect, at run time, the correct ordering of
+ the high and low part of a floating-point number.
+
+ d. IEEE exceptions may trigger "signals" as is common in Unix
+ implementations.
+
+-------------------
+2. EXCEPTION CASES
+-------------------
+All exception cases in the FDLIBM functions will be mapped
+to one of the following four exceptions:
+
+ +-huge*huge, +-tiny*tiny, +-1.0/0.0, +-0.0/0.0
+ (overflow) (underflow) (divided-by-zero) (invalid)
+
+For example, log(0) is a singularity and is thus mapped to
+ -1.0/0.0 = -infinity.
+That is, FDLIBM's log will compute -one/zero and return the
+computed value. On an IEEE machine, this will trigger the
+divided-by-zero exception and a negative infinity is returned by
+default.
+
+Similarly, exp(-huge) will be mapped to tiny*tiny to generate
+an underflow signal.
+
+
+--------------------------------
+3. STANDARD CONFORMANCE WRAPPER
+--------------------------------
+The default FDLIBM functions (compiled with -D_IEEE_LIBM flag)
+are in "IEEE spirit" (i.e., return the most reasonable result in
+floating-point arithmetic). If one wants FDLIBM to comply with
+standards like SVID, X/OPEN, or POSIX/ANSI, then one can
+create a multi-standard compliant FDLIBM. In this case, each
+function in FDLIBM is actually a standard compliant wrapper
+function.
+
+File organization:
+ 1. For FDLIBM's kernel (internal) function,
+ File name Entry point
+ ---------------------------
+ k_sin.c __kernel_sin
+ k_tan.c __kernel_tan
+ ---------------------------
+ 2. For functions that have no standards conflict
+ File name Entry point
+ ---------------------------
+ s_sin.c sin
+ s_erf.c erf
+ ---------------------------
+ 3. Ieee754 core functions
+ File name Entry point
+ ---------------------------
+ e_exp.c __ieee754_exp
+ e_sinh.c __ieee754_sinh
+ ---------------------------
+ 4. Wrapper functions
+ File name Entry point
+ ---------------------------
+ w_exp.c exp
+ w_sinh.c sinh
+ ---------------------------
+
+Wrapper functions will twist the result of the ieee754
+function to comply to the standard specified by the value
+of _LIB_VERSION
+ if _LIB_VERSION = _IEEE_, return the ieee754 result;
+ if _LIB_VERSION = _SVID_, return SVID result;
+ if _LIB_VERSION = _XOPEN_, return XOPEN result;
+ if _LIB_VERSION = _POSIX_, return POSIX/ANSI result.
+(These are macros, see fdlibm.h for their definition.)
+
+
+--------------------------------
+4. HOW TO CREATE FDLIBM's libm.a
+--------------------------------
+There are two types of libm.a. One is IEEE only, and the other is
+multi-standard compliant (supports IEEE,XOPEN,POSIX/ANSI,SVID).
+
+To create the IEEE only libm.a, use
+ make "CFLAGS = -D_IEEE_LIBM"
+This will create an IEEE libm.a, which is smaller in size, and
+somewhat faster.
+
+To create a multi-standard compliant libm, use
+ make "CFLAGS = -D_IEEE_MODE" --- multi-standard fdlibm: default
+ to IEEE
+ make "CFLAGS = -D_XOPEN_MODE" --- multi-standard fdlibm: default
+ to X/OPEN
+ make "CFLAGS = -D_POSIX_MODE" --- multi-standard fdlibm: default
+ to POSIX/ANSI
+ make "CFLAGS = -D_SVID3_MODE" --- multi-standard fdlibm: default
+ to SVID
+
+
+Here is how one makes a SVID compliant libm.
+ Make the library by
+ make "CFLAGS = -D_SVID3_MODE".
+ The libm.a of FDLIBM will be multi-standard compliant and
+ _LIB_VERSION is initialized to the value _SVID_ .
+
+ example1:
+ ---------
+ main()
+ {
+ double y0();
+ printf("y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example1.c libm.a
+ % a.out
+ y0: TLOSS error
+ y0(1e300) = 0.00000000000000000000e+00
+
+
+It is possible to change the default standard in multi-standard
+fdlibm. Here is an example of how to do it:
+ example2:
+ ---------
+ #include "fdlibm.h" /* must include FDLIBM's fdlibm.h */
+ main()
+ {
+ double y0();
+ _LIB_VERSION = _IEEE_;
+ printf("IEEE: y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _XOPEN_;
+ printf("XOPEN y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _POSIX_;
+ printf("POSIX y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _SVID_;
+ printf("SVID y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example2.c libm.a
+ % a.out
+ IEEE: y0(1e300) = -1.36813604503424810557e-151
+ XOPEN y0(1e300) = 0.00000000000000000000e+00
+ POSIX y0(1e300) = 0.00000000000000000000e+00
+ y0: TLOSS error
+ SVID y0(1e300) = 0.00000000000000000000e+00
+
+Note: Here _LIB_VERSION is a global variable. If global variables
+ are forbidden, then one should modify fdlibm.h to change
+ _LIB_VERSION to be a global constant. In this case, one
+ may not change the value of _LIB_VERSION as in example2.
+
+---------------------------
+5. NOTES ON PORTING FDLIBM
+---------------------------
+ Care must be taken when installing FDLIBM over existing
+ libm.a.
+ All co-existing function prototypes must agree, otherwise
+ users will encounter mysterious failures.
+
+ So far, the only known likely conflict is the declaration
+ of the IEEE recommended function scalb:
+
+ double scalb(double,double) (1) SVID3 defined
+ double scalb(double,int) (2) IBM,DEC,...
+
+ FDLIBM follows Sun definition and use (1) as default.
+ If one's existing libm.a uses (2), then one may raise
+ the flags _SCALB_INT during the compilation of FDLIBM
+ to get the correct function prototype.
+ (E.g., make "CFLAGS = -D_IEEE_LIBM -D_SCALB_INT".)
+ NOTE that if -D_SCALB_INT is raised, it won't be SVID3
+ conformant.
+
+--------------
+6. PROBLEMS ?
+--------------
+Please send comments and bug report to:
+ fdlibm-comments@sunpro.eng.sun.com
diff --git a/lib/msun/src/dependencies b/lib/msun/src/dependencies
new file mode 100644
index 000000000000..54606205557a
--- /dev/null
+++ b/lib/msun/src/dependencies
@@ -0,0 +1,471 @@
+fdlibm*
+makefile:
+makefile
+e_acos.c:
+e_acos.c
+__ieee754_acos
+fdlibm.h?
+e_acosh.c:
+e_acosh.c
+__ieee754_acosh
+__ieee754_log?
+fdlibm.h?
+e_asin.c:
+e_asin.c
+__ieee754_asin
+fdlibm.h?
+e_atan2.c:
+e_atan2.c
+__ieee754_atan2
+fdlibm.h?
+e_atanh.c:
+e_atanh.c
+__ieee754_atanh
+fdlibm.h?
+e_cosh.c:
+e_cosh.c
+__ieee754_cosh
+__ieee754_exp?
+fdlibm.h?
+e_exp.c:
+e_exp.c
+__ieee754_exp
+fdlibm.h?
+e_fmod.c:
+e_fmod.c
+__ieee754_fmod
+fdlibm.h?
+e_gamma.c:
+e_gamma.c
+__ieee754_gamma
+__ieee754_gamma_r?
+'signgam?
+fdlibm.h?
+e_gamma_r.c:
+e_gamma_r.c
+__ieee754_gamma_r
+__ieee754_lgamma_r?
+fdlibm.h?
+e_hypot.c:
+e_hypot.c
+__ieee754_hypot
+fdlibm.h?
+e_j0.c:
+e_j0.c
+__ieee754_j0
+__ieee754_y0
+__ieee754_log?
+fdlibm.h?
+e_j1.c:
+e_j1.c
+__ieee754_j1
+__ieee754_y1
+__ieee754_log?
+fdlibm.h?
+e_jn.c:
+e_jn.c
+__ieee754_jn
+__ieee754_yn
+__ieee754_y1?
+__ieee754_y0?
+__ieee754_log?
+__ieee754_j1?
+__ieee754_j0?
+fdlibm.h?
+e_lgamma.c:
+e_lgamma.c
+__ieee754_lgamma
+__ieee754_lgamma_r?
+'signgam?
+fdlibm.h?
+e_lgamma_r.c:
+e_lgamma_r.c
+__ieee754_lgamma_r
+__ieee754_log?
+__kernel_cos?
+__kernel_sin?
+fdlibm.h?
+e_log.c:
+e_log.c
+__ieee754_log
+fdlibm.h?
+e_log10.c:
+e_log10.c
+__ieee754_log10
+__ieee754_log?
+fdlibm.h?
+e_pow.c:
+e_pow.c
+__ieee754_pow
+scalbn?
+fdlibm.h?
+e_rem_pio2.c:
+e_rem_pio2.c
+__ieee754_rem_pio2
+__kernel_rem_pio2?
+fdlibm.h?
+e_remainder.c:
+e_remainder.c
+__ieee754_remainder
+__ieee754_fmod?
+fdlibm.h?
+e_scalb.c:
+e_scalb.c
+__ieee754_scalb
+scalbn?
+isnan?
+fdlibm.h?
+e_sinh.c:
+e_sinh.c
+__ieee754_sinh
+__ieee754_exp?
+fdlibm.h?
+e_sqrt.c:
+e_sqrt.c
+__ieee754_sqrt
+fdlibm.h?
+fdlibm.h:
+fdlibm.h
+k_cos.c:
+k_cos.c
+__kernel_cos
+fdlibm.h?
+k_rem_pio2.c:
+k_rem_pio2.c
+__kernel_rem_pio2
+scalbn?
+fdlibm.h?
+k_sin.c:
+k_sin.c
+__kernel_sin
+fdlibm.h?
+k_standard.c:
+k_standard.c
+__kernel_standard
+matherr?
+'__stderr?
+'errno?
+'_fdlib_version?
+fdlibm.h?
+errno.h?
+stdio.h?
+unistd.h?
+k_tan.c:
+k_tan.c
+__kernel_tan
+fdlibm.h?
+s_asinh.c:
+s_asinh.c
+asinh
+__ieee754_log?
+fdlibm.h?
+s_atan.c:
+s_atan.c
+atan
+fdlibm.h?
+s_cbrt.c:
+s_cbrt.c
+cbrt
+fdlibm.h?
+s_ceil.c:
+s_ceil.c
+ceil
+fdlibm.h?
+s_copysign.c:
+s_copysign.c
+copysign
+fdlibm.h?
+s_cos.c:
+s_cos.c
+cos
+__kernel_sin?
+__ieee754_rem_pio2?
+__kernel_cos?
+fdlibm.h?
+s_erf.c:
+s_erf.c
+erf
+erfc
+__ieee754_exp?
+fdlibm.h?
+s_expm1.c:
+s_expm1.c
+expm1
+fdlibm.h?
+s_fabs.c:
+s_fabs.c
+fabs
+fdlibm.h?
+s_finite.c:
+s_finite.c
+finite
+fdlibm.h?
+s_floor.c:
+s_floor.c
+floor
+fdlibm.h?
+s_frexp.c:
+s_frexp.c
+frexp
+fdlibm.h?
+s_ilogb.c:
+s_ilogb.c
+ilogb
+fdlibm.h?
+s_isnan.c:
+s_isnan.c
+isnan
+fdlibm.h?
+s_ldexp.c:
+s_ldexp.c
+ldexp
+scalbn?
+'errno?
+fdlibm.h?
+errno.h?
+s_lib_version.c:
+s_lib_version.c
+'_fdlib_version
+fdlibm.h?
+s_log1p.c:
+s_log1p.c
+log1p
+fdlibm.h?
+s_logb.c:
+s_logb.c
+logb
+fdlibm.h?
+s_matherr.c:
+s_matherr.c
+matherr
+fdlibm.h?
+s_modf.c:
+s_modf.c
+modf
+fdlibm.h?
+s_nextafter.c:
+s_nextafter.c
+nextafter
+fdlibm.h?
+s_rint.c:
+s_rint.c
+rint
+fdlibm.h?
+s_scalbn.c:
+s_scalbn.c
+scalbn
+fdlibm.h?
+s_signgam.c:
+s_signgam.c
+'signgam
+fdlibm.h?
+s_significand.c:
+s_significand.c
+significand
+__ieee754_scalb?
+ilogb?
+fdlibm.h?
+s_sin.c:
+s_sin.c
+sin
+__kernel_cos?
+__ieee754_rem_pio2?
+__kernel_sin?
+fdlibm.h?
+s_tan.c:
+s_tan.c
+tan
+__ieee754_rem_pio2?
+__kernel_tan?
+fdlibm.h?
+s_tanh.c:
+s_tanh.c
+tanh
+fdlibm.h?
+w_acos.c:
+w_acos.c
+acos
+__kernel_standard?
+isnan?
+__ieee754_acos?
+'_fdlib_version?
+fdlibm.h?
+w_acosh.c:
+w_acosh.c
+acosh
+__kernel_standard?
+isnan?
+__ieee754_acosh?
+'_fdlib_version?
+fdlibm.h?
+w_asin.c:
+w_asin.c
+asin
+__kernel_standard?
+isnan?
+__ieee754_asin?
+'_fdlib_version?
+fdlibm.h?
+w_atan2.c:
+w_atan2.c
+atan2
+__kernel_standard?
+isnan?
+__ieee754_atan2?
+'_fdlib_version?
+fdlibm.h?
+w_atanh.c:
+w_atanh.c
+atanh
+__kernel_standard?
+isnan?
+__ieee754_atanh?
+'_fdlib_version?
+fdlibm.h?
+w_cosh.c:
+w_cosh.c
+cosh
+__kernel_standard?
+isnan?
+__ieee754_cosh?
+'_fdlib_version?
+fdlibm.h?
+w_exp.c:
+w_exp.c
+exp
+__kernel_standard?
+__ieee754_exp?
+'_fdlib_version?
+fdlibm.h?
+w_fmod.c:
+w_fmod.c
+fmod
+__kernel_standard?
+isnan?
+__ieee754_fmod?
+'_fdlib_version?
+fdlibm.h?
+w_gamma.c:
+w_gamma.c
+gamma
+__kernel_standard?
+__ieee754_gamma_r?
+'_fdlib_version?
+'signgam?
+fdlibm.h?
+w_gamma_r.c:
+w_gamma_r.c
+gamma_r
+__kernel_standard?
+__ieee754_gamma_r?
+'_fdlib_version?
+fdlibm.h?
+w_hypot.c:
+w_hypot.c
+hypot
+__kernel_standard?
+__ieee754_hypot?
+'_fdlib_version?
+fdlibm.h?
+w_j0.c:
+w_j0.c
+j0
+y0
+__ieee754_y0?
+__kernel_standard?
+isnan?
+__ieee754_j0?
+'_fdlib_version?
+fdlibm.h?
+w_j1.c:
+w_j1.c
+j1
+y1
+__ieee754_y1?
+__kernel_standard?
+isnan?
+__ieee754_j1?
+'_fdlib_version?
+fdlibm.h?
+w_jn.c:
+w_jn.c
+jn
+yn
+__ieee754_yn?
+__kernel_standard?
+isnan?
+__ieee754_jn?
+'_fdlib_version?
+fdlibm.h?
+w_lgamma.c:
+w_lgamma.c
+lgamma
+__kernel_standard?
+__ieee754_lgamma_r?
+'_fdlib_version?
+'signgam?
+fdlibm.h?
+w_lgamma_r.c:
+w_lgamma_r.c
+lgamma_r
+__kernel_standard?
+__ieee754_lgamma_r?
+'_fdlib_version?
+fdlibm.h?
+w_log.c:
+w_log.c
+log
+__kernel_standard?
+isnan?
+__ieee754_log?
+'_fdlib_version?
+fdlibm.h?
+w_log10.c:
+w_log10.c
+log10
+__kernel_standard?
+isnan?
+__ieee754_log10?
+'_fdlib_version?
+fdlibm.h?
+w_pow.c:
+w_pow.c
+pow
+__kernel_standard?
+isnan?
+__ieee754_pow?
+'_fdlib_version?
+fdlibm.h?
+w_remainder.c:
+w_remainder.c
+remainder
+__kernel_standard?
+isnan?
+__ieee754_remainder?
+'_fdlib_version?
+fdlibm.h?
+w_scalb.c:
+w_scalb.c
+scalb
+__kernel_standard?
+isnan?
+__ieee754_scalb?
+'errno?
+'_fdlib_version?
+fdlibm.h?
+errno.h?
+w_sinh.c:
+w_sinh.c
+sinh
+__kernel_standard?
+__ieee754_sinh?
+'_fdlib_version?
+fdlibm.h?
+w_sqrt.c:
+w_sqrt.c
+sqrt
+__kernel_standard?
+isnan?
+__ieee754_sqrt?
+'_fdlib_version?
+fdlibm.h?
diff --git a/lib/msun/src/e_acos.c b/lib/msun/src/e_acos.c
new file mode 100644
index 000000000000..cd9ae3004fc8
--- /dev/null
+++ b/lib/msun/src/e_acos.c
@@ -0,0 +1,116 @@
+/* @(#)e_acos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_acos.c,v 1.1.1.1 1994/05/06 00:20:00 gclarkii Exp $";
+#endif
+
+/* __ieee754_acos(x)
+ * Method :
+ * acos(x) = pi/2 - asin(x)
+ * acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
+ * For x>0.5
+ * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ * = 2asin(sqrt((1-x)/2))
+ * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
+ * = 2f + (2c + 2s*z*R(z))
+ * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ * for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_acos(double x)
+#else
+ double __ieee754_acos(x)
+ double x;
+#endif
+{
+ double z,p,q,r,w,s,c,df;
+ int hx,ix;
+
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x3ff00000) { /* |x| >= 1 */
+ if(((ix-0x3ff00000)|*(1-n0+(int*)&x))==0) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+2.0*pio2_lo; /* acos(-1)= pi */
+ }
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3fe00000) { /* |x| < 0.5 */
+ if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = sqrt(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - 2.0*(s+w);
+ } else { /* x > 0.5 */
+ z = (one-x)*0.5;
+ s = sqrt(z);
+ df = s;
+ *(1-n0+(int*)&df) = 0;
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return 2.0*(df+w);
+ }
+}
diff --git a/lib/msun/src/e_acosh.c b/lib/msun/src/e_acosh.c
new file mode 100644
index 000000000000..badbfe6927db
--- /dev/null
+++ b/lib/msun/src/e_acosh.c
@@ -0,0 +1,75 @@
+/* @(#)e_acosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_acosh.c,v 1.1.1.1 1994/05/06 00:19:52 gclarkii Exp $";
+#endif
+
+/* __ieee754_acosh(x)
+ * Method :
+ * Based on
+ * acosh(x) = log [ x + sqrt(x*x-1) ]
+ * we have
+ * acosh(x) := log(x)+ln2, if x is large; else
+ * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ * acosh(x) is NaN with signal if x<1.
+ * acosh(NaN) is NaN without signal.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */
+
+#ifdef __STDC__
+ double __ieee754_acosh(double x)
+#else
+ double __ieee754_acosh(x)
+ double x;
+#endif
+{
+ double t;
+ int hx;
+
+ hx = *(n0+(int*)&x);
+ if(hx<0x3ff00000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x41b00000) { /* x > 2**28 */
+ if(hx >=0x7ff00000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */
+ } else if(((hx-0x3ff00000)|*(1-n0+(int*)&x))==0) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return log1p(t+sqrt(2.0*t+t*t));
+ }
+}
diff --git a/lib/msun/src/e_asin.c b/lib/msun/src/e_asin.c
new file mode 100644
index 000000000000..30771a1cfd53
--- /dev/null
+++ b/lib/msun/src/e_asin.c
@@ -0,0 +1,125 @@
+/* @(#)e_asin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_asin.c,v 1.1.1.1 1994/05/06 00:19:52 gclarkii Exp $";
+#endif
+
+/* __ieee754_asin(x)
+ * Method :
+ * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ * we approximate asin(x) on [0,0.5] by
+ * asin(x) = x + x*x^2*R(x^2)
+ * where
+ * R(x^2) is a rational approximation of (asin(x)-x)/x^3
+ * and its remez error is bounded by
+ * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ * For x in [0.5,1]
+ * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ * then for x>0.98
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ * For x<=0.98, let pio4_hi = pio2_hi/2, then
+ * f = hi part of s;
+ * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
+ * and
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge = 1.000e+300,
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+ /* coefficient for R(x^2) */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_asin(double x)
+#else
+ double __ieee754_asin(x)
+ double x;
+#endif
+{
+ double t,w,p,q,c,r,s;
+ int hx,ix;
+
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>= 0x3ff00000) { /* |x|>= 1 */
+ if(((ix-0x3ff00000)|*(1-n0+(int*)&x))==0)
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3fe00000) { /* |x|<0.5 */
+ if(ix<0x3e400000) { /* if |x| < 2**-27 */
+ if(huge+x>one) return x;/* return x with inexact if x!=0*/
+ } else
+ t = x*x;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fabs(x);
+ t = w*0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = sqrt(t);
+ if(ix>=0x3FEF3333) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+ } else {
+ w = s;
+ *(1-n0+(int*)&w) = 0;
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = 2.0*s*r-(pio2_lo-2.0*c);
+ q = pio4_hi-2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_atan2.c b/lib/msun/src/e_atan2.c
new file mode 100644
index 000000000000..928060069cf0
--- /dev/null
+++ b/lib/msun/src/e_atan2.c
@@ -0,0 +1,132 @@
+/* @(#)e_atan2.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_atan2.c,v 1.1.1.1 1994/05/06 00:19:53 gclarkii Exp $";
+#endif
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ * 2. Reduce x to positive by (if x and y are unexceptional):
+ * ARG (x+iy) = arctan(y/x) ... if x > 0,
+ * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
+ *
+ * Special cases:
+ *
+ * ATAN2((anything), NaN ) is NaN;
+ * ATAN2(NAN , (anything) ) is NaN;
+ * ATAN2(+-0, +(anything but NaN)) is +-0 ;
+ * ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ * ATAN2(+-INF,+INF ) is +-pi/4 ;
+ * ATAN2(+-INF,-INF ) is +-3pi/4;
+ * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1.0e-300,
+zero = 0.0,
+pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+#ifdef __STDC__
+ double __ieee754_atan2(double y, double x)
+#else
+ double __ieee754_atan2(y,x)
+ double y,x;
+#endif
+{
+ double z;
+ int k,m,hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = *(n0+(int*)&x); ix = hx&0x7fffffff;
+ lx = *(1-n0+(int*)&x);
+ hy = *(n0+(int*)&y); iy = hy&0x7fffffff;
+ ly = *(1-n0+(int*)&y);
+ if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+ ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */
+ return x+y;
+ if((hx-0x3ff00000|lx)==0) return atan(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if((iy|ly)==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7ff00000) {
+ if(iy==0x7ff00000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>20;
+ if(k > 60) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=atan(fabs(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: *(n0+(int*)&z) ^= 0x80000000;
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
diff --git a/lib/msun/src/e_atanh.c b/lib/msun/src/e_atanh.c
new file mode 100644
index 000000000000..c69c04eada5b
--- /dev/null
+++ b/lib/msun/src/e_atanh.c
@@ -0,0 +1,78 @@
+/* @(#)e_atanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_atanh.c,v 1.1.1.1 1994/05/06 00:19:53 gclarkii Exp $";
+#endif
+
+/* __ieee754_atanh(x)
+ * Method :
+ * 1.Reduced x to positive by atanh(-x) = -atanh(x)
+ * 2.For x>=0.5
+ * 1 2x x
+ * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ * 2 1 - x 1 - x
+ *
+ * For x<0.5
+ * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ * atanh(x) is NaN if |x| > 1 with signal;
+ * atanh(NaN) is that NaN with no signal;
+ * atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0, huge = 1e300;
+#else
+static double one = 1.0, huge = 1e300;
+#endif
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_atanh(double x)
+#else
+ double __ieee754_atanh(x)
+ double x;
+#endif
+{
+ double t;
+ int hx,ix;
+ unsigned lx;
+
+ hx = *(n0+(int*)&x); /* high word */
+ lx = *(1-n0+(int*)&x); /* low word */
+ ix = hx&0x7fffffff;
+ if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3ff00000)
+ return x/zero;
+ if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */
+ *(n0+(int*)&x) = ix; /* x <- |x| */
+ if(ix<0x3fe00000) { /* x < 0.5 */
+ t = x+x;
+ t = 0.5*log1p(t+t*x/(one-x));
+ } else
+ t = 0.5*log1p((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_cosh.c b/lib/msun/src/e_cosh.c
new file mode 100644
index 000000000000..7920ee86da60
--- /dev/null
+++ b/lib/msun/src/e_cosh.c
@@ -0,0 +1,92 @@
+/* @(#)e_cosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_cosh.c,v 1.1.1.1 1994/05/06 00:19:53 gclarkii Exp $";
+#endif
+
+/* __ieee754_cosh(x)
+ * Method :
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ * 1. Replace x by |x| (cosh(x) = cosh(-x)).
+ * 2.
+ * [ exp(x) - 1 ]^2
+ * 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
+ * 2*exp(x)
+ *
+ * exp(x) + 1/exp(x)
+ * ln2/2 <= x <= 22 : cosh(x) := -------------------
+ * 2
+ * 22 <= x <= lnovft : cosh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ * cosh(x) is |x| if x is +INF, -INF, or NaN.
+ * only cosh(0)=1 is exact for finite x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+#else
+static double one = 1.0, half=0.5, huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_cosh(double x)
+#else
+ double __ieee754_cosh(x)
+ double x;
+#endif
+{
+ double t,w;
+ int ix;
+ unsigned lx;
+
+ /* High word of |x|. */
+ ix = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3fd62e43) {
+ t = expm1(fabs(x));
+ w = one+t;
+ if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = __ieee754_exp(fabs(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+ if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE ||
+ (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(half*fabs(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return huge*huge;
+}
diff --git a/lib/msun/src/e_exp.c b/lib/msun/src/e_exp.c
new file mode 100644
index 000000000000..bdba9acf0913
--- /dev/null
+++ b/lib/msun/src/e_exp.c
@@ -0,0 +1,167 @@
+/* @(#)e_exp.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_exp.c,v 1.1.1.1 1994/05/06 00:19:54 gclarkii Exp $";
+#endif
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Reme algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+huge = 1.0e+300,
+twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
+ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+#ifdef __STDC__
+ double __ieee754_exp(double x) /* default IEEE double exp */
+#else
+ double __ieee754_exp(x) /* default IEEE double exp */
+ double x;
+#endif
+{
+ double y,hi,lo,c,t;
+ int k,xsb;
+ unsigned hx;
+
+ hx = *(n0+(unsigned*)&x); /* high word of x */
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|*(1-n0+(int*)&x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = invln2*x+halF[xsb];
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ *(n0+(int*)&y) += (k<<20); /* add k to y's exponent */
+ return y;
+ } else {
+ *(n0+(int*)&y) += ((k+1000)<<20);/* add k to y's exponent */
+ return y*twom1000;
+ }
+}
diff --git a/lib/msun/src/e_fmod.c b/lib/msun/src/e_fmod.c
new file mode 100644
index 000000000000..b53d3d790513
--- /dev/null
+++ b/lib/msun/src/e_fmod.c
@@ -0,0 +1,153 @@
+/* @(#)e_fmod.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_fmod.c,v 1.1.1.1 1994/05/06 00:19:54 gclarkii Exp $";
+#endif
+
+/*
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#define n1 0
+#else
+#define n0 0
+#define n1 1
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+#else
+static double one = 1.0, Zero[] = {0.0, -0.0,};
+#endif
+
+#ifdef __STDC__
+ double __ieee754_fmod(double x, double y)
+#else
+ double __ieee754_fmod(x,y)
+ double x,y ;
+#endif
+{
+ int n,hx,hy,hz,ix,iy,sx,i;
+ int *px = (int*)&x, *py = (int*)&y;
+ unsigned lx,ly,lz;
+
+ hx = *( n0 + px); /* high word of x */
+ lx = *( n1 + px); /* low word of x */
+ hy = *( n0 + py); /* high word of y */
+ ly = *( n1 + py); /* low word of y */
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
+ if(lx==ly)
+ return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {
+ if((hz|lz)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ hx = hz+hz+(lz>>31); lx = lz+lz;
+ }
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ *(n0+px) = hx|sx;
+ *(n1+px) = lx;
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((unsigned)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ *(n0+px) = hx|sx;
+ *(n1+px) = lx;
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
diff --git a/lib/msun/src/e_gamma.c b/lib/msun/src/e_gamma.c
new file mode 100644
index 000000000000..5ede28b48d73
--- /dev/null
+++ b/lib/msun/src/e_gamma.c
@@ -0,0 +1,35 @@
+/* @(#)e_gamma.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_gamma.c,v 1.1.1.1 1994/05/06 00:19:55 gclarkii Exp $";
+#endif
+
+/* __ieee754_gamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_gamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_gamma(double x)
+#else
+ double __ieee754_gamma(x)
+ double x;
+#endif
+{
+ return __ieee754_gamma_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_gamma_r.c b/lib/msun/src/e_gamma_r.c
new file mode 100644
index 000000000000..46209cf81efb
--- /dev/null
+++ b/lib/msun/src/e_gamma_r.c
@@ -0,0 +1,34 @@
+/* @(#)e_gamma_r.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_gamma_r.c,v 1.1.1.1 1994/05/06 00:19:55 gclarkii Exp $";
+#endif
+
+/* __ieee754_gamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method: See __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double __ieee754_gamma_r(double x, int *signgamp)
+#else
+ double __ieee754_gamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ return __ieee754_lgamma_r(x,signgamp);
+}
diff --git a/lib/msun/src/e_hypot.c b/lib/msun/src/e_hypot.c
new file mode 100644
index 000000000000..4e73385226cb
--- /dev/null
+++ b/lib/msun/src/e_hypot.c
@@ -0,0 +1,125 @@
+/* @(#)e_hypot.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_hypot.c,v 1.1.1.1 1994/05/06 00:19:54 gclarkii Exp $";
+#endif
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :
+ * If (assume round-to-nearest) z=x*x+y*y
+ * has error less than sqrt(2)/2 ulp, than
+ * sqrt(z) has error less than 1 ulp (exercise).
+ *
+ * So, compute sqrt(x*x+y*y) with some care as
+ * follows to get the error below 1 ulp:
+ *
+ * Assume x>y>0;
+ * (if possible, set rounding to round-to-nearest)
+ * 1. if x > 2y use
+ * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ * 2. if x <= 2y use
+ * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ * y1= y with lower 32 bits chopped, y2 = y-y1.
+ *
+ * NOTE: scaling may be necessary if some argument is too
+ * large or too tiny
+ *
+ * Special cases:
+ * hypot(x,y) is INF if x or y is +INF or -INF; else
+ * hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * hypot(x,y) returns sqrt(x^2+y^2) with error less
+ * than 1 ulps (units in the last place)
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+ double __ieee754_hypot(double x, double y)
+#else
+ double __ieee754_hypot(x,y)
+ double x, y;
+#endif
+{
+ double a=x,b=y,t1,t2,y1,y2,w;
+ int j,k,ha,hb;
+
+ ha = *(n0+(int*)&x)&0x7fffffff; /* high word of x */
+ hb = *(n0+(int*)&y)&0x7fffffff; /* high word of y */
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ *(n0+(int*)&a) = ha; /* a <- |a| */
+ *(n0+(int*)&b) = hb; /* b <- |b| */
+ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+ k=0;
+ if(ha > 0x5f300000) { /* a>2**500 */
+ if(ha >= 0x7ff00000) { /* Inf or NaN */
+ w = a+b; /* for sNaN */
+ if(((ha&0xfffff)|*(1-n0+(int*)&a))==0) w = a;
+ if(((hb^0x7ff00000)|*(1-n0+(int*)&b))==0) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-600 */
+ ha -= 0x25800000; hb -= 0x25800000; k += 600;
+ *(n0+(int*)&a) = ha;
+ *(n0+(int*)&b) = hb;
+ }
+ if(hb < 0x20b00000) { /* b < 2**-500 */
+ if(hb <= 0x000fffff) { /* subnormal b or 0 */
+ if((hb|(*(1-n0+(int*)&b)))==0) return a;
+ t1=0;
+ *(n0+(int*)&t1) = 0x7fd00000; /* t1=2^1022 */
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else { /* scale a and b by 2^600 */
+ ha += 0x25800000; /* a *= 2^600 */
+ hb += 0x25800000; /* b *= 2^600 */
+ k -= 600;
+ *(n0+(int*)&a) = ha;
+ *(n0+(int*)&b) = hb;
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ t1 = 0;
+ *(n0+(int*)&t1) = ha;
+ t2 = a-t1;
+ w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ y1 = 0;
+ *(n0+(int*)&y1) = hb;
+ y2 = b - y1;
+ t1 = 0;
+ *(n0+(int*)&t1) = ha+0x00100000;
+ t2 = a - t1;
+ w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ t1 = 1.0;
+ *(n0+(int*)&t1) += (k<<20);
+ return t1*w;
+ } else return w;
+}
diff --git a/lib/msun/src/e_j0.c b/lib/msun/src/e_j0.c
new file mode 100644
index 000000000000..fc8317893b38
--- /dev/null
+++ b/lib/msun/src/e_j0.c
@@ -0,0 +1,488 @@
+/* @(#)e_j0.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_j0.c,v 1.1.1.1 1994/05/06 00:19:57 gclarkii Exp $";
+#endif
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ * 2. Reduce x to |x| since j0(x)=j0(-x), and
+ * for x in (0,2)
+ * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
+ * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ * for x in (2,inf)
+ * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * as follow:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (cos(x) + sin(x))
+ * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j0(nan)= nan
+ * j0(0) = 1
+ * j0(inf) = 0
+ *
+ * Method -- y0(x):
+ * 1. For x<2.
+ * Since
+ * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ * We use the following function to approximate y0,
+ * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ * where
+ * U(z) = u00 + u01*z + ... + u06*z^6
+ * V(z) = 1 + v01*z + ... + v04*z^4
+ * with absolute approximation error bounded by 2**-72.
+ * Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ * 2. For x>=2.
+ * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * by the method mentioned above.
+ * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static double pzero(double), qzero(double);
+#else
+static double pzero(), qzero();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j0(double x)
+#else
+ double __ieee754_j0(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,r,u,v;
+ int hx,ix;
+
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/(x*x);
+ x = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<0x3f200000) { /* |x| < 2**-13 */
+ if(huge+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x3e400000) return one; /* |x|<2**-27 */
+ else return one - 0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3FF00000) { /* |x| < 1.00 */
+ return one + z*(-0.25+(r/s));
+ } else {
+ u = 0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+#ifdef __STDC__
+ double __ieee754_y0(double x)
+#else
+ double __ieee754_y0(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = *(n0+(int*)&x);
+ ix = 0x7fffffff&hx;
+ lx = *(1-n0+(int*)&x);
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3e400000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_log(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+#ifdef __STDC__
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+#ifdef __STDC__
+static const double pS8[5] = {
+#else
+static double pS8[5] = {
+#endif
+ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+ 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+#ifdef __STDC__
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+#ifdef __STDC__
+static const double pS5[5] = {
+#else
+static double pS5[5] = {
+#endif
+ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+ 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+#ifdef __STDC__
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+#ifdef __STDC__
+static const double pS3[5] = {
+#else
+static double pS3[5] = {
+#endif
+ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+ 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+#ifdef __STDC__
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+#ifdef __STDC__
+static const double pS2[5] = {
+#else
+static double pS2[5] = {
+#endif
+ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+#ifdef __STDC__
+ static double pzero(double x)
+#else
+ static double pzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&(*( (((*(int*)&one)>>29)^1) + (int*)&x));
+ if(ix>=0x40200000) {p = pR8; q= pS8;}
+ else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+ else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+#ifdef __STDC__
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+ 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+ 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+#ifdef __STDC__
+static const double qS8[6] = {
+#else
+static double qS8[6] = {
+#endif
+ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+ 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+ 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+#ifdef __STDC__
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+ 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+ 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+#ifdef __STDC__
+static const double qS5[6] = {
+#else
+static double qS5[6] = {
+#endif
+ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+ 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+ 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+#ifdef __STDC__
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+ 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+ 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+#ifdef __STDC__
+static const double qS3[6] = {
+#else
+static double qS3[6] = {
+#endif
+ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+ 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+ 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+#ifdef __STDC__
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+ 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+ 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+#ifdef __STDC__
+static const double qS2[6] = {
+#else
+static double qS2[6] = {
+#endif
+ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+ 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+#ifdef __STDC__
+ static double qzero(double x)
+#else
+ static double qzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&(*( (((*(int*)&one)>>29)^1) + (int*)&x));
+ if(ix>=0x40200000) {p = qR8; q= qS8;}
+ else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+ else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-.125 + r/s)/x;
+}
diff --git a/lib/msun/src/e_j1.c b/lib/msun/src/e_j1.c
new file mode 100644
index 000000000000..32e53a320a78
--- /dev/null
+++ b/lib/msun/src/e_j1.c
@@ -0,0 +1,486 @@
+/* @(#)e_j1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_j1.c,v 1.1.1.1 1994/05/06 00:19:57 gclarkii Exp $";
+#endif
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ * 2. Reduce x to |x| since j1(x)=-j1(-x), and
+ * for x in (0,2)
+ * j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+ * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ * for x in (2,inf)
+ * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * as follow:
+ * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (sin(x) + cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j1(nan)= nan
+ * j1(0) = 0
+ * j1(inf) = 0
+ *
+ * Method -- y1(x):
+ * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+ * 2. For x<2.
+ * Since
+ * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ * We use the following function to approximate y1,
+ * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ * where for x in [0,2] (abs err less than 2**-65.89)
+ * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5
+ * Note: For tiny x, 1/x dominate y1 and hence
+ * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ * 3. For x>=2.
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * by method mentioned above.
+ */
+
+#include "math.h"
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static double pone(double), qone(double);
+#else
+static double pone(), qone();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0,2] */
+r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j1(double x)
+#else
+ double __ieee754_j1(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,r,u,v,y;
+ int hx,ix;
+
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/x;
+ y = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(y);
+ c = cos(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure y+y not overflow */
+ z = cos(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+ else {
+ u = pone(y); v = qone(y);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x3e400000) { /* |x|<2**-27 */
+ if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*0.5+r/s);
+}
+
+#ifdef __STDC__
+static const double U0[5] = {
+#else
+static double U0[5] = {
+#endif
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+#ifdef __STDC__
+static const double V0[5] = {
+#else
+static double V0[5] = {
+#endif
+ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+#ifdef __STDC__
+ double __ieee754_y1(double x)
+#else
+ double __ieee754_y1(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = *(n0+(int*)&x);
+ ix = 0x7fffffff&hx;
+ lx = *(1-n0+(int*)&x);
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = cos(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pone(x); v = qone(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3c900000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+#ifdef __STDC__
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+#ifdef __STDC__
+static const double ps8[5] = {
+#else
+static double ps8[5] = {
+#endif
+ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+#ifdef __STDC__
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+#ifdef __STDC__
+static const double ps5[5] = {
+#else
+static double ps5[5] = {
+#endif
+ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+#ifdef __STDC__
+static const double pr3[6] = {
+#else
+static double pr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+#ifdef __STDC__
+static const double ps3[5] = {
+#else
+static double ps3[5] = {
+#endif
+ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+#ifdef __STDC__
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+#ifdef __STDC__
+static const double ps2[5] = {
+#else
+static double ps2[5] = {
+#endif
+ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+#ifdef __STDC__
+ static double pone(double x)
+#else
+ static double pone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&(*( (((*(int*)&one)>>29)^1) + (int*)&x));
+ if(ix>=0x40200000) {p = pr8; q= ps8;}
+ else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+ else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+#ifdef __STDC__
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+#ifdef __STDC__
+static const double qs8[6] = {
+#else
+static double qs8[6] = {
+#endif
+ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+#ifdef __STDC__
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+#ifdef __STDC__
+static const double qs5[6] = {
+#else
+static double qs5[6] = {
+#endif
+ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+#ifdef __STDC__
+static const double qr3[6] = {
+#else
+static double qr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+#ifdef __STDC__
+static const double qs3[6] = {
+#else
+static double qs3[6] = {
+#endif
+ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+#ifdef __STDC__
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+#ifdef __STDC__
+static const double qs2[6] = {
+#else
+static double qs2[6] = {
+#endif
+ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+#ifdef __STDC__
+ static double qone(double x)
+#else
+ static double qone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&(*( (((*(int*)&one)>>29)^1) + (int*)&x));
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+ else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (.375 + r/s)/x;
+}
diff --git a/lib/msun/src/e_jn.c b/lib/msun/src/e_jn.c
new file mode 100644
index 000000000000..414379cf41bb
--- /dev/null
+++ b/lib/msun/src/e_jn.c
@@ -0,0 +1,282 @@
+/* @(#)e_jn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_jn.c,v 1.1.1.1 1994/05/06 00:19:57 gclarkii Exp $";
+#endif
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static double zero = 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ double __ieee754_jn(int n, double x)
+#else
+ double __ieee754_jn(n,x)
+ int n; double x;
+#endif
+{
+ int i,hx,ix,lx, sgn;
+ double a, b, temp, di;
+ double z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ hx = *(n0+(int*)&x);
+ ix = 0x7fffffff&hx;
+ lx = *(1-n0+(int*)&x);
+ /* if J(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0(x));
+ if(n==1) return(__ieee754_j1(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fabs(x);
+ if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */
+ b = zero;
+ else if((double)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = cos(x)+sin(x); break;
+ case 1: temp = -cos(x)+sin(x); break;
+ case 2: temp = -cos(x)-sin(x); break;
+ case 3: temp = cos(x)-sin(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_j0(x);
+ b = __ieee754_j1(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((double)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ }
+ } else {
+ if(ix<0x3e100000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (double)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ double t,v;
+ double q0,q1,h,tmp; int k,m;
+ w = (n+n)/(double)x; h = 2.0/(double)x;
+ q0 = w; z = w+h; q1 = w*z - 1.0; k=1;
+ while(q1<1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_log(fabs(v*tmp));
+ if(tmp<7.09782712893383973096e+02) {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>1e100) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+#ifdef __STDC__
+ double __ieee754_yn(int n, double x)
+#else
+ double __ieee754_yn(n,x)
+ int n; double x;
+#endif
+{
+ int i,hx,ix,lx;
+ int sign;
+ double a, b, temp;
+
+ hx = *(n0+(int*)&x);
+ ix = 0x7fffffff&hx;
+ lx = *(1-n0+(int*)&x);
+ /* if Y(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<2);
+ }
+ if(n==0) return(__ieee754_y0(x));
+ if(n==1) return(sign*__ieee754_y1(x));
+ if(ix==0x7ff00000) return zero;
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = sin(x)-cos(x); break;
+ case 1: temp = -sin(x)-cos(x); break;
+ case 2: temp = -sin(x)+cos(x); break;
+ case 3: temp = sin(x)+cos(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_y0(x);
+ b = __ieee754_y1(x);
+ /* quit if b is -inf */
+ for(i=1;i<n&&(*(n0+(int*)&b)!=0xfff00000);i++){
+ temp = b;
+ b = ((double)(i+i)/x)*b - a;
+ a = temp;
+ }
+ }
+ if(sign>0) return b; else return -b;
+}
diff --git a/lib/msun/src/e_lgamma.c b/lib/msun/src/e_lgamma.c
new file mode 100644
index 000000000000..335323e882c5
--- /dev/null
+++ b/lib/msun/src/e_lgamma.c
@@ -0,0 +1,35 @@
+/* @(#)e_lgamma.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_lgamma.c,v 1.1.1.1 1994/05/06 00:19:58 gclarkii Exp $";
+#endif
+
+/* __ieee754_lgamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_lgamma(double x)
+#else
+ double __ieee754_lgamma(x)
+ double x;
+#endif
+{
+ return __ieee754_lgamma_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_lgamma_r.c b/lib/msun/src/e_lgamma_r.c
new file mode 100644
index 000000000000..5fd23ac13b4d
--- /dev/null
+++ b/lib/msun/src/e_lgamma_r.c
@@ -0,0 +1,313 @@
+/* @(#)e_lgamma_r.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_lgamma_r.c,v 1.1.1.1 1994/05/06 00:19:57 gclarkii Exp $";
+#endif
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double zero= 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ static double sin_pi(double x)
+#else
+ static double sin_pi(x)
+ double x;
+#endif
+{
+ double y,z;
+ int n,ix;
+
+ ix = 0x7fffffff&(*(n0+(int*)&x));
+
+ if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floor(y);
+ if(z!=y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if(ix>=0x43400000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x43300000) z = y+two52; /* exact */
+ n = (*(1+(int*)&z))&1; /* lower word of z */
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sin(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
+ default: y = __kernel_sin(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+
+#ifdef __STDC__
+ double __ieee754_lgamma_r(double x, int *signgamp)
+#else
+ double __ieee754_lgamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,lx,ix;
+
+ hx = *(n0+(int*)&x);
+ lx = *(1-n0+(int*)&x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x*x;
+ if((ix|lx)==0) return one/zero;
+ if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_log(-x);
+ } else return -__ieee754_log(x);
+ }
+ if(hx<0) {
+ if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
+ return one/zero;
+ t = sin_pi(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_log(pi/fabs(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_log(x);
+ if(ix>=0x3FE76944) {y = one-x; i= 0;}
+ else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6.0); /* FALLTHRU */
+ case 6: z *= (y+5.0); /* FALLTHRU */
+ case 5: z *= (y+4.0); /* FALLTHRU */
+ case 4: z *= (y+3.0); /* FALLTHRU */
+ case 3: z *= (y+2.0); /* FALLTHRU */
+ r += __ieee754_log(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x43900000) {
+ t = __ieee754_log(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_log(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
diff --git a/lib/msun/src/e_log.c b/lib/msun/src/e_log.c
new file mode 100644
index 000000000000..bdd8ff24e539
--- /dev/null
+++ b/lib/msun/src/e_log.c
@@ -0,0 +1,149 @@
+/* @(#)e_log.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_log.c,v 1.1.1.1 1994/05/06 00:19:58 gclarkii Exp $";
+#endif
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * 2. Approximation of log(1+f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
+ * (the values of Lg1 to Lg7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lg1*s +...+Lg7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log(1+f) = f - s*(f - R) (if f is not too large)
+ * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+ *
+ * 3. Finally, log(x) = k*ln2 + log(1+f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log(x) is NaN with signal if x < 0 (including -INF) ;
+ * log(+INF) is +INF; log(0) is -INF with signal;
+ * log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log(double x)
+#else
+ double __ieee754_log(x)
+ double x;
+#endif
+{
+ double hfsq,f,s,z,R,w,t1,t2,dk;
+ int k,hx,i,j;
+ unsigned lx;
+
+ hx = *(n0+(int*)&x); /* high word of x */
+ lx = *(1-n0+(int*)&x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = *(n0+(int*)&x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ hx &= 0x000fffff;
+ i = (hx+0x95f64)&0x100000;
+ *(n0+(int*)&x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
+ k += (i>>20);
+ f = x-1.0;
+ if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero; else {dk=(double)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ R = f*f*(0.5-0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(double)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/(2.0+f);
+ dk = (double)k;
+ z = s*s;
+ i = hx-0x6147a;
+ w = z*z;
+ j = 0x6b851-hx;
+ t1= w*(Lg2+w*(Lg4+w*Lg6));
+ t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
diff --git a/lib/msun/src/e_log10.c b/lib/msun/src/e_log10.c
new file mode 100644
index 000000000000..dc81958a3270
--- /dev/null
+++ b/lib/msun/src/e_log10.c
@@ -0,0 +1,101 @@
+/* @(#)e_log10.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_log10.c,v 1.1.1.1 1994/05/06 00:19:58 gclarkii Exp $";
+#endif
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ *
+ * Method :
+ * Let log10_2hi = leading 40 bits of log10(2) and
+ * log10_2lo = log10(2) - log10_2hi,
+ * ivln10 = 1/log(10) rounded.
+ * Then
+ * n = ilogb(x),
+ * if(n<0) n = n+1;
+ * x = scalbn(x,-n);
+ * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ * To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+ * mode must set to Round-to-Nearest.
+ * Note 2:
+ * [1/log(10)] rounded to 53 bits has error .198 ulps;
+ * log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ * log10(x) is NaN with signal if x < 0;
+ * log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ * log10(NaN) is that NaN with no signal;
+ * log10(10**N) = N for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log10(double x)
+#else
+ double __ieee754_log10(x)
+ double x;
+#endif
+{
+ double y,z;
+ int i,k,hx;
+ unsigned lx;
+
+ hx = *(n0+(unsigned*)&x); /* high word of x */
+ lx = *(1-n0+(unsigned*)&x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = *(n0+(int*)&x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ i = ((unsigned)k&0x80000000)>>31;
+ hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+ y = (double)(k+i);
+ *(n0+(int*)&x) = hx;
+ z = y*log10_2lo + ivln10*__ieee754_log(x);
+ return z+y*log10_2hi;
+}
diff --git a/lib/msun/src/e_pow.c b/lib/msun/src/e_pow.c
new file mode 100644
index 000000000000..7658b92dfeb4
--- /dev/null
+++ b/lib/msun/src/e_pow.c
@@ -0,0 +1,308 @@
+/* @(#)e_pow.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_pow.c,v 1.1.1.1 1994/05/06 00:19:59 gclarkii Exp $";
+#endif
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+huge = 1.0e300,
+tiny = 1.0e-300,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+#ifdef __STDC__
+ double __ieee754_pow(double x, double y)
+#else
+ double __ieee754_pow(x,y)
+ double x, y;
+#endif
+{
+ double z,ax,z_h,z_l,p_h,p_l;
+ double y1,t1,t2,r,s,t,u,v,w;
+ int i0,i1,i,j,k,yisint,n;
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
+ hx = *(i0+(int*)&x); lx = *(i1+(int*)&x);
+ hy = *(i0+(int*)&y); ly = *(i1+(int*)&y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if((j<<(52-k))==ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return sqrt(x);
+ }
+ }
+
+ ax = fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+ }
+
+ /* (x<0)**(non-int) is NaN */
+ if((((hx>>31)+1)|yisint)==0) return (x-x)/(x-x);
+
+ /* |y| is huge */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = x-1; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ *(i1+(int*)&t1) = 0;
+ t2 = v-(t1-u);
+ } else {
+ double s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; ix = *(i0+(int*)&ax); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ *(i0+(int*)&ax) = ix;
+
+ /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ s = u*v;
+ s_h = s;
+ *(i1+(int*)&s_h) = 0;
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ *(i0+(int*)&t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = s*s;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+s);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ *(i1+(int*)&t_h) = 0;
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = s*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*s;
+ /* 2/(3log2)*(s+...) */
+ p_h = u+v;
+ *(i1+(int*)&p_h) = 0;
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ *(i1+(int*)&t1) = 0;
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((((hx>>31)+1)|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ *(i1+(int*)&y1) = 0;
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ j = *(i0+(int*)&z);
+ i = *(i1+(int*)&z);
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*huge*huge; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ *(i0+(int*)&t) = (n&~(0x000fffff>>k));
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ *(i1+(int*)&t) = 0;
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ j = *(i0+(int*)&z);
+ j += (n<<20);
+ if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+ else *(i0+(int*)&z) += (n<<20);
+ return s*z;
+}
diff --git a/lib/msun/src/e_rem_pio2.c b/lib/msun/src/e_rem_pio2.c
new file mode 100644
index 000000000000..932899d2aede
--- /dev/null
+++ b/lib/msun/src/e_rem_pio2.c
@@ -0,0 +1,153 @@
+/* @(#)e_rem_pio2.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_rem_pio2.c,v 1.1.1.1 1994/05/06 00:19:59 gclarkii Exp $";
+#endif
+
+/* __ieee754_rem_pio2(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include "math.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+#ifdef __STDC__
+static const int two_over_pi[] = {
+#else
+static int two_over_pi[] = {
+#endif
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+#ifdef __STDC__
+static const int npio2_hw[] = {
+#else
+static int npio2_hw[] = {
+#endif
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+#ifdef __STDC__
+ int __ieee754_rem_pio2(double x, double *y)
+#else
+ int __ieee754_rem_pio2(x,y)
+ double x,y[];
+#endif
+{
+ double z,w,t,r,fn;
+ double tx[3];
+ int e0,i,j,nx,n,ix,hx,i0;
+
+ i0 = ((*(int*)&two24)>>30)^1; /* high word index */
+ hx = *(i0+(int*)&x); /* high word of x */
+ ix = hx&0x7fffffff;
+ if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fabs(x);
+ n = (int) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 85 bit */
+ if(n<32&&ix!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ j = ix>>20;
+ y[0] = r-w;
+ i = j-(((*(i0+(int*)&y[0]))>>20)&0x7ff);
+ if(i>16) { /* 2nd iteration needed, good to 118 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ i = j-(((*(i0+(int*)&y[0]))>>20)&0x7ff);
+ if(i>49) { /* 3rd iteration need, 151 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7ff00000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-23) */
+ *(1-i0+(int*)&z) = *(1-i0+(int*)&x);
+ e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */
+ *(i0+(int*)&z) = ix - (e0<<20);
+ for(i=0;i<2;i++) {
+ tx[i] = (double)((int)(z));
+ z = (z-tx[i])*two24;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
diff --git a/lib/msun/src/e_remainder.c b/lib/msun/src/e_remainder.c
new file mode 100644
index 000000000000..bf3df2d5e2c4
--- /dev/null
+++ b/lib/msun/src/e_remainder.c
@@ -0,0 +1,89 @@
+/* @(#)e_remainder.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_remainder.c,v 1.1.1.1 1994/05/06 00:19:58 gclarkii Exp $";
+#endif
+
+/* __ieee754_remainder(x,p)
+ * Return :
+ * returns x REM p = x - [x/p]*p as if in infinite
+ * precise arithmetic, where [x/p] is the (infinite bit)
+ * integer nearest x/p (in half way case choose the even one).
+ * Method :
+ * Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#define n1 0
+#else
+#define n0 0
+#define n1 1
+#endif
+
+#ifdef __STDC__
+static const double zero = 0.0;
+#else
+static double zero = 0.0;
+#endif
+
+
+#ifdef __STDC__
+ double __ieee754_remainder(double x, double p)
+#else
+ double __ieee754_remainder(x,p)
+ double x,p;
+#endif
+{
+ int hx,hp;
+ unsigned sx,lx,lp;
+ double p_half;
+
+ hx = *( n0 + (int*)&x); /* high word of x */
+ lx = *( n1 + (int*)&x); /* low word of x */
+ hp = *( n0 + (int*)&p); /* high word of p */
+ lp = *( n1 + (int*)&p); /* low word of p */
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7ff00000)|| /* x not finite */
+ ((hp>=0x7ff00000)&& /* p is NaN */
+ (((hp-0x7ff00000)|lp)!=0)))
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */
+ if (((hx-hp)|(lx-lp))==0) return zero*x;
+ x = fabs(x);
+ p = fabs(p);
+ if (hp<0x00200000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = 0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ *(n0+(int*)&x) ^= sx;
+ return x;
+}
diff --git a/lib/msun/src/e_scalb.c b/lib/msun/src/e_scalb.c
new file mode 100644
index 000000000000..01d1726d0ea3
--- /dev/null
+++ b/lib/msun/src/e_scalb.c
@@ -0,0 +1,54 @@
+/* @(#)e_scalb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_scalb.c,v 1.1.1.1 1994/05/06 00:19:59 gclarkii Exp $";
+#endif
+
+/*
+ * __ieee754_scalb(x, fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "math.h"
+
+#ifdef _SCALB_INT
+#ifdef __STDC__
+ double __ieee754_scalb(double x, int fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x; int fn;
+#endif
+#else
+#ifdef __STDC__
+ double __ieee754_scalb(double x, double fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x, fn;
+#endif
+#endif
+{
+#ifdef _SCALB_INT
+ return scalbn(x,fn);
+#else
+ if (isnan(x)||isnan(fn)) return x*fn;
+ if (!finite(fn)) {
+ if(fn>0.0) return x*fn;
+ else return x/(-fn);
+ }
+ if (rint(fn)!=fn) return (fn-fn)/(fn-fn);
+ if ( fn > 65000.0) return scalbn(x, 65000);
+ if (-fn > 65000.0) return scalbn(x,-65000);
+ return scalbn(x,(int)fn);
+#endif
+}
diff --git a/lib/msun/src/e_sinh.c b/lib/msun/src/e_sinh.c
new file mode 100644
index 000000000000..92984dab2e04
--- /dev/null
+++ b/lib/msun/src/e_sinh.c
@@ -0,0 +1,85 @@
+/* @(#)e_sinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_sinh.c,v 1.1.1.1 1994/05/06 00:20:01 gclarkii Exp $";
+#endif
+
+/* __ieee754_sinh(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
+ * 2.
+ * E + E/(E+1)
+ * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
+ * 2
+ *
+ * 22 <= x <= lnovft : sinh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ * sinh(x) is |x| if x is +INF, -INF, or NaN.
+ * only sinh(0)=0 is exact for finite x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, shuge = 1.0e307;
+#else
+static double one = 1.0, shuge = 1.0e307;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sinh(double x)
+#else
+ double __ieee754_sinh(x)
+ double x;
+#endif
+{
+ double t,w,h;
+ int ix,jx;
+ unsigned lx;
+
+ /* High word of |x|. */
+ jx = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3e300000) /* |x|<2**-28 */
+ if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = expm1(fabs(x));
+ if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+ if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE || (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(0.5*fabs(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*shuge;
+}
diff --git a/lib/msun/src/e_sqrt.c b/lib/msun/src/e_sqrt.c
new file mode 100644
index 000000000000..53a0f0df80d0
--- /dev/null
+++ b/lib/msun/src/e_sqrt.c
@@ -0,0 +1,461 @@
+/* @(#)e_sqrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: e_sqrt.c,v 1.1.1.1 1994/05/06 00:20:00 gclarkii Exp $";
+#endif
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ * ------------------------------------------
+ * | Use the hardware sqrt if you have one |
+ * ------------------------------------------
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * 1. Normalization
+ * Scale x to y in [1,4) with even powers of 2:
+ * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+ * sqrt(x) = 2^k * sqrt(y)
+ * 2. Bit by bit computation
+ * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+ * i 0
+ * i+1 2
+ * s = 2*q , and y = 2 * ( y - q ). (1)
+ * i i i i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
+ *
+ * -(i+1) 2
+ * (q + 2 ) <= y. (2)
+ * i
+ * -(i+1)
+ * If (2) is false, then q = q ; otherwise q = q + 2 .
+ * i+1 i i+1 i
+ *
+ * With some algebric manipulation, it is not difficult to see
+ * that (2) is equivalent to
+ * -(i+1)
+ * s + 2 <= y (3)
+ * i i
+ *
+ * The advantage of (3) is that s and y can be computed by
+ * i i
+ * the following recurrence formula:
+ * if (3) is false
+ *
+ * s = s , y = y ; (4)
+ * i+1 i i+1 i
+ *
+ * otherwise,
+ * -i -(i+1)
+ * s = s + 2 , y = y - s - 2 (5)
+ * i+1 i i+1 i i
+ *
+ * One may easily use induction to prove (4) and (5).
+ * Note. Since the left hand side of (3) contain only i+2 bits,
+ * it does not necessary to do a full (53-bit) comparison
+ * in (3).
+ * 3. Final rounding
+ * After generating the 53 bits result, we compute one more bit.
+ * Together with the remainder, we can decide whether the
+ * result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ * (it will never equal to 1/2ulp).
+ * The rounding mode can be detected by checking whether
+ * huge + tiny is equal to huge, and whether huge - tiny is
+ * equal to huge for some floating point number "huge" and "tiny".
+ *
+ * Special cases:
+ * sqrt(+-0) = +-0 ... exact
+ * sqrt(inf) = inf
+ * sqrt(-ve) = NaN ... with invalid signal
+ * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0, tiny=1.0e-300;
+#else
+static double one = 1.0, tiny=1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sqrt(double x)
+#else
+ double __ieee754_sqrt(x)
+ double x;
+#endif
+{
+ double z;
+ int sign = (int)0x80000000;
+ unsigned r,t1,s1,ix1,q1;
+ int ix0,s0,q,m,t,i;
+
+ ix0 = *(n0+(int*)&x); /* high word of x */
+ ix1 = *((1-n0)+(int*)&x); /* low word of x */
+
+ /* take care of Inf and NaN */
+ if((ix0&0x7ff00000)==0x7ff00000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix0<=0) {
+ if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix0<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix0>>20);
+ if(m==0) { /* subnormal x */
+ while(ix0==0) {
+ m -= 21;
+ ix0 |= (ix1>>11); ix1 <<= 21;
+ }
+ for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+ m -= i-1;
+ ix0 |= (ix1>>(32-i));
+ ix1 <<= i;
+ }
+ m -= 1023; /* unbias exponent */
+ ix0 = (ix0&0x000fffff)|0x00100000;
+ if(m&1){ /* odd m, double x to make it even */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ }
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
+ r = 0x00200000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s0+r;
+ if(t<=ix0) {
+ s0 = t+r;
+ ix0 -= t;
+ q += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ r = sign;
+ while(r!=0) {
+ t1 = s1+r;
+ t = s0;
+ if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
+ s1 = t1+r;
+ if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+ ix0 -= t;
+ if (ix1 < t1) ix0 -= 1;
+ ix1 -= t1;
+ q1 += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if((ix0|ix1)!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
+ else if (z>one) {
+ if (q1==(unsigned)0xfffffffe) q+=1;
+ q1+=2;
+ } else
+ q1 += (q1&1);
+ }
+ }
+ ix0 = (q>>1)+0x3fe00000;
+ ix1 = q1>>1;
+ if ((q&1)==1) ix1 |= sign;
+ ix0 += (m <<20);
+ *(n0+(int*)&z) = ix0;
+ *((1-n0)+(int*)&z) = ix1;
+ return z;
+}
+
+/*
+Other methods (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan
+and K.C. Ng, written in May, 1986)
+
+ Two algorithms are given here to implement sqrt(x)
+ (IEEE double precision arithmetic) in software.
+ Both supply sqrt(x) correctly rounded. The first algorithm (in
+ Section A) uses newton iterations and involves four divisions.
+ The second one uses reciproot iterations to avoid division, but
+ requires more multiplications. Both algorithms need the ability
+ to chop results of arithmetic operations instead of round them,
+ and the INEXACT flag to indicate when an arithmetic operation
+ is executed exactly with no roundoff error, all part of the
+ standard (IEEE 754-1985). The ability to perform shift, add,
+ subtract and logical AND operations upon 32-bit words is needed
+ too, though not part of the standard.
+
+A. sqrt(x) by Newton Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+
+ 1 11 52 ...widths
+ ------------------------------------------------------
+ x: |s| e | f |
+ ------------------------------------------------------
+ msb lsb msb lsb ...order
+
+
+ ------------------------ ------------------------
+ x0: |s| e | f1 | x1: | f2 |
+ ------------------------ ------------------------
+
+ By performing shifts and subtracts on x0 and x1 (both regarded
+ as integers), we obtain an 8-bit approximation of sqrt(x) as
+ follows.
+
+ k := (x0>>1) + 0x1ff80000;
+ y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits
+ Here k is a 32-bit integer and T1[] is an integer array containing
+ correction terms. Now magically the floating value of y (y's
+ leading 32-bit word is y0, the value of its trailing word is 0)
+ approximates sqrt(x) to almost 8-bit.
+
+ Value of T1:
+ static int T1[32]= {
+ 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215,
+ 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581,
+ 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,};
+
+ (2) Iterative refinement
+
+ Apply Heron's rule three times to y, we have y approximates
+ sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+ y := (y+x/y)/2 ... almost 17 sig. bits
+ y := (y+x/y)/2 ... almost 35 sig. bits
+ y := y-(y-x/y)/2 ... within 1 ulp
+
+
+ Remark 1.
+ Another way to improve y to within 1 ulp is:
+
+ y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x)
+ y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x)
+
+ 2
+ (x-y )*y
+ y := y + 2* ---------- ...within 1 ulp
+ 2
+ 3y + x
+
+
+ This formula has one division fewer than the one above; however,
+ it requires more multiplications and additions. Also x must be
+ scaled in advance to avoid spurious overflow in evaluating the
+ expression 3y*y+x. Hence it is not recommended uless division
+ is slow. If division is very slow, then one should use the
+ reciproot algorithm given in section B.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ I := FALSE; ... reset INEXACT flag I
+ R := RZ; ... set rounding mode to round-toward-zero
+ z := x/y; ... chopped quotient, possibly inexact
+ If(not I) then { ... if the quotient is exact
+ if(z=y) {
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+ } else {
+ z := z - ulp; ... special rounding
+ }
+ }
+ i := TRUE; ... sqrt(x) is inexact
+ If (r=RN) then z=z+ulp ... rounded-to-nearest
+ If (r=RP) then { ... round-toward-+inf
+ y = y+ulp; z=z+ulp;
+ }
+ y := y+z; ... chopped sum
+ y0:=y0-0x00100000; ... y := y/2 is correctly rounded.
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+
+ (4) Special cases
+
+ Square root of +inf, +-0, or NaN is itself;
+ Square root of a negative number is NaN with invalid signal.
+
+
+B. sqrt(x) by Reciproot Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+ (see section A). By performing shifs and subtracts on x0 and y0,
+ we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+ k := 0x5fe80000 - (x0>>1);
+ y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits
+
+ Here k is a 32-bit integer and T2[] is an integer array
+ containing correction terms. Now magically the floating
+ value of y (y's leading 32-bit word is y0, the value of
+ its trailing word y1 is set to zero) approximates 1/sqrt(x)
+ to almost 7.8-bit.
+
+ Value of T2:
+ static int T2[64]= {
+ 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+ 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+ 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+ 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+ 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+ 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+ 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+ 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+ (2) Iterative refinement
+
+ Apply Reciproot iteration three times to y and multiply the
+ result by x to get an approximation z that matches sqrt(x)
+ to about 1 ulp. To be exact, we will have
+ -1ulp < sqrt(x)-z<1.0625ulp.
+
+ ... set rounding mode to Round-to-nearest
+ y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x)
+ y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+ ... special arrangement for better accuracy
+ z := x*y ... 29 bits to sqrt(x), with z*y<1
+ z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x)
+
+ Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+ (a) the term z*y in the final iteration is always less than 1;
+ (b) the error in the final result is biased upward so that
+ -1 ulp < sqrt(x) - z < 1.0625 ulp
+ instead of |sqrt(x)-z|<1.03125ulp.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ R := RZ; ... set rounding mode to round-toward-zero
+ switch(r) {
+ case RN: ... round-to-nearest
+ if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+ if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+ break;
+ case RZ:case RM: ... round-to-zero or round-to--inf
+ R:=RP; ... reset rounding mod to round-to-+inf
+ if(x<z*z ... rounded up) z = z - ulp; else
+ if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+ break;
+ case RP: ... round-to-+inf
+ if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+ if(x>z*z ...chopped) z = z+ulp;
+ break;
+ }
+
+ Remark 3. The above comparisons can be done in fixed point. For
+ example, to compare x and w=z*z chopped, it suffices to compare
+ x1 and w1 (the trailing parts of x and w), regarding them as
+ two's complement integers.
+
+ ...Is z an exact square root?
+ To determine whether z is an exact square root of x, let z1 be the
+ trailing part of z, and also let x0 and x1 be the leading and
+ trailing parts of x.
+
+ If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+ I := 1; ... Raise Inexact flag: z is not exact
+ else {
+ j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2
+ k := z1 >> 26; ... get z's 25-th and 26-th
+ fraction bits
+ I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+ }
+ R:= r ... restore rounded mode
+ return sqrt(x):=z.
+
+ If multiplication is cheaper then the foregoing red tape, the
+ Inexact flag can be evaluated by
+
+ I := i;
+ I := (z*z!=x) or I.
+
+ Note that z*z can overwrite I; this value must be sensed if it is
+ True.
+
+ Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+ zero.
+
+ --------------------
+ z1: | f2 |
+ --------------------
+ bit 31 bit 0
+
+ Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+ or even of logb(x) have the following relations:
+
+ -------------------------------------------------
+ bit 27,26 of z1 bit 1,0 of x1 logb(x)
+ -------------------------------------------------
+ 00 00 odd and even
+ 01 01 even
+ 10 10 odd
+ 10 00 even
+ 11 01 even
+ -------------------------------------------------
+
+ (4) Special cases (see (4) of Section A).
+
+ */
+
diff --git a/lib/msun/src/fdlibm.h b/lib/msun/src/fdlibm.h
new file mode 100644
index 000000000000..747626f8d3bc
--- /dev/null
+++ b/lib/msun/src/fdlibm.h
@@ -0,0 +1,196 @@
+
+/* @(#)fdlibm.h 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifdef __STDC__
+#define __P(p) p
+#else
+#define __P(p) ()
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+
+extern int signgam;
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix};
+
+#define _LIB_VERSION_TYPE enum fdversion
+#define _LIB_VERSION _fdlib_version
+
+/* if global variable _LIB_VERSION is not desirable, one may
+ * change the following to be a constant by:
+ * #define _LIB_VERSION_TYPE const enum version
+ * In that case, after one initializes the value _LIB_VERSION (see
+ * s_lib_version.c) during compile time, it cannot be modified
+ * in the middle of a program
+ */
+extern _LIB_VERSION_TYPE _LIB_VERSION;
+
+#define _IEEE_ fdlibm_ieee
+#define _SVID_ fdlibm_svid
+#define _XOPEN_ fdlibm_xopen
+#define _POSIX_ fdlibm_posix
+
+struct exception {
+ int type;
+ char *name;
+ double arg1;
+ double arg2;
+ double retval;
+};
+
+#define HUGE MAXFLOAT
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS 1.41484755040568800000e+16
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+/*
+ * ANSI/POSIX
+ */
+extern double acos __P((double));
+extern double asin __P((double));
+extern double atan __P((double));
+extern double atan2 __P((double, double));
+extern double cos __P((double));
+extern double sin __P((double));
+extern double tan __P((double));
+
+extern double cosh __P((double));
+extern double sinh __P((double));
+extern double tanh __P((double));
+
+extern double exp __P((double));
+extern double frexp __P((double, int *));
+extern double ldexp __P((double, int));
+extern double log __P((double));
+extern double log10 __P((double));
+extern double modf __P((double, double *));
+
+extern double pow __P((double, double));
+extern double sqrt __P((double));
+
+extern double ceil __P((double));
+extern double fabs __P((double));
+extern double floor __P((double));
+extern double fmod __P((double, double));
+
+extern double erf __P((double));
+extern double erfc __P((double));
+extern double gamma __P((double));
+extern double hypot __P((double, double));
+extern int isnan __P((double));
+extern int finite __P((double));
+extern double j0 __P((double));
+extern double j1 __P((double));
+extern double jn __P((int, double));
+extern double lgamma __P((double));
+extern double y0 __P((double));
+extern double y1 __P((double));
+extern double yn __P((int, double));
+
+extern double acosh __P((double));
+extern double asinh __P((double));
+extern double atanh __P((double));
+extern double cbrt __P((double));
+extern double logb __P((double));
+extern double nextafter __P((double, double));
+extern double remainder __P((double, double));
+#ifdef _SCALB_INT
+extern double scalb __P((double, int));
+#else
+extern double scalb __P((double, double));
+#endif
+
+extern int matherr __P((struct exception *));
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand __P((double));
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign __P((double, double));
+extern int ilogb __P((double));
+extern double rint __P((double));
+extern double scalbn __P((double, int));
+
+/*
+ * BSD math library entry points
+ */
+extern double expm1 __P((double));
+extern double log1p __P((double));
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r __P((double, int *));
+extern double lgamma_r __P((double, int *));
+#endif /* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_lgamma __P((double));
+extern double __ieee754_gamma __P((double));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern int __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*));
diff --git a/lib/msun/src/k_cos.c b/lib/msun/src/k_cos.c
new file mode 100644
index 000000000000..63c377757386
--- /dev/null
+++ b/lib/msun/src/k_cos.c
@@ -0,0 +1,102 @@
+/* @(#)k_cos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: k_cos.c,v 1.1.1.1 1994/05/06 00:20:00 gclarkii Exp $";
+#endif
+
+/*
+ * __kernel_cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the remez error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) = 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy when x > 0.3, let qx = |x|/4 with
+ * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ * Then
+ * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ * Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ * magnitude of the latter is at least a quarter of x*x/2,
+ * thus, reducing the rounding error in the subtraction.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+#ifdef __STDC__
+ double __kernel_cos(double x, double y)
+#else
+ double __kernel_cos(x, y)
+ double x,y;
+#endif
+{
+ double a,hz,z,r,qx;
+ int ix;
+ ix = (*(n0+(int*)&x))&0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x3e400000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3FD33333) /* if |x| < 0.3 */
+ return one - (0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3fe90000) { /* x > 0.78125 */
+ qx = 0.28125;
+ } else {
+ *(n0+(int*)&qx) = ix-0x00200000; /* x/4 */
+ *(1-n0+(int*)&qx) = 0;
+ }
+ hz = 0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
diff --git a/lib/msun/src/k_rem_pio2.c b/lib/msun/src/k_rem_pio2.c
new file mode 100644
index 000000000000..50fab684ca9d
--- /dev/null
+++ b/lib/msun/src/k_rem_pio2.c
@@ -0,0 +1,319 @@
+/* @(#)k_rem_pio2.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: k_rem_pio2.c,v 1.1.1.1 1994/05/06 00:20:01 gclarkii Exp $";
+#endif
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ *
+ * __kernel_rem_pio2 return the last three digits of N with
+ * y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * x[] The input value (must be positive) is broken into nx
+ * pieces of 24-bit integers in double precision format.
+ * x[i] will be the i-th 24 bit of x. The scaled exponent
+ * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
+ * match x's up to 24 bits.
+ *
+ * Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ * e0 = ilogb(z)-23
+ * z = scalbn(z,-e0)
+ * for i = 0,1,2
+ * x[i] = floor(z)
+ * z = (z-x[i])*2**24
+ *
+ *
+ * y[] ouput result in an array of double precision numbers.
+ * The dimension of y[] is:
+ * 24-bit precision 1
+ * 53-bit precision 2
+ * 64-bit precision 2
+ * 113-bit precision 3
+ * The actual value is the sum of them. Thus for 113-bit
+ * precison, one may have to do something like:
+ *
+ * long double t,w,r_head, r_tail;
+ * t = (long double)y[2] + (long double)y[1];
+ * w = (long double)y[0];
+ * r_head = t+w;
+ * r_tail = w - (r_head - t);
+ *
+ * e0 The exponent of x[0]
+ *
+ * nx dimension of x[]
+ *
+ * prec an integer indicating the precision:
+ * 0 24 bits (single)
+ * 1 53 bits (double)
+ * 2 64 bits (extended)
+ * 3 113 bits (quad)
+ *
+ * ipio2[]
+ * integer array, contains the (24*i)-th to (24*i+23)-th
+ * bit of 2/pi after binary point. The corresponding
+ * floating value is
+ *
+ * ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ * double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * jk jk+1 is the initial number of terms of ipio2[] needed
+ * in the computation. The recommended value is 2,3,4,
+ * 6 for single, double, extended,and quad.
+ *
+ * jz local integer variable indicating the number of
+ * terms of ipio2[] used.
+ *
+ * jx nx - 1
+ *
+ * jv index for pointing to the suitable ipio2[] for the
+ * computation. In general, we want
+ * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ * is an integer. Thus
+ * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ * Hence jv = max(0,(e0-3)/24).
+ *
+ * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * q[] double array with integral value, representing the
+ * 24-bits chunk of the product of x and 2/pi.
+ *
+ * q0 the corresponding exponent of q[0]. Note that the
+ * exponent for q[i] would be q0-24*i.
+ *
+ * PIo2[] double precision array, obtained by cutting pi/2
+ * into 24 bits chunks.
+ *
+ * f[] ipio2[] in floating point
+ *
+ * iq[] integer array by breaking up q[] in 24-bits chunk.
+ *
+ * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ * ih integer. If >0 it indicates q[] is >= 0.5, hence
+ * it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+#else
+static int init_jk[] = {2,3,4,6};
+#endif
+
+#ifdef __STDC__
+static const double PIo2[] = {
+#else
+static double PIo2[] = {
+#endif
+ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.0,
+one = 1.0,
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+#ifdef __STDC__
+ int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2)
+#else
+ int __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ double x[], y[]; int e0,nx,prec; int ipio2[];
+#endif
+{
+ int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ double z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/24; if(jv<0) jv=0;
+ q0 = e0-24*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (double)((int)(twon24* z));
+ iq[i] = (int)(z-two24*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbn(z,q0); /* actual value of z */
+ z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
+ n = (int) z;
+ z -= (double)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(24-q0)); n += i;
+ iq[jz-1] -= i<<(24-q0);
+ ih = iq[jz-1]>>(23-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>23;
+ else if(z>=0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x1000000- j;
+ }
+ } else iq[i] = 0xffffff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7fffff; break;
+ case 2:
+ iq[jz-1] &= 0x3fffff; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbn(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (double) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==0.0) {
+ jz -= 1; q0 -= 24;
+ while(iq[jz]==0) { jz--; q0-=24;}
+ } else { /* break z into 24-bit if necessary */
+ z = scalbn(z,-q0);
+ if(z>=two24) {
+ fw = (double)((int)(twon24*z));
+ iq[jz] = (int)(z-two24*fw);
+ jz += 1; q0 += 24;
+ iq[jz] = (int) fw;
+ } else iq[jz] = (int) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbn(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(double)iq[i]; fw*=twon24;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
diff --git a/lib/msun/src/k_sin.c b/lib/msun/src/k_sin.c
new file mode 100644
index 000000000000..a1ddc01022df
--- /dev/null
+++ b/lib/msun/src/k_sin.c
@@ -0,0 +1,84 @@
+/* @(#)k_sin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: k_sin.c,v 1.1.1.1 1994/05/06 00:20:01 gclarkii Exp $";
+#endif
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+#ifdef __STDC__
+ double __kernel_sin(double x, double y, int iy)
+#else
+ double __kernel_sin(x, y, iy)
+ double x,y; int iy; /* iy=0 if y is zero */
+#endif
+{
+ double z,r,v;
+ int ix;
+ ix = (*(n0+(int*)&x))&0x7fffffff; /* high word of x */
+ if(ix<0x3e400000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/lib/msun/src/k_standard.c b/lib/msun/src/k_standard.c
new file mode 100644
index 000000000000..acffaeaf9fd9
--- /dev/null
+++ b/lib/msun/src/k_standard.c
@@ -0,0 +1,737 @@
+/* @(#)k_standard.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: k_standard.c,v 1.1.1.1 1994/05/06 00:20:02 gclarkii Exp $";
+#endif
+
+#include "math.h"
+#include <errno.h>
+
+#ifndef _USE_WRITE
+#include <stdio.h> /* fputs(), stderr */
+#define WRITE2(u,v) fputs(u, stderr)
+#else /* !defined(_USE_WRITE) */
+#include <unistd.h> /* write */
+#define WRITE2(u,v) write(2, u, v)
+#undef fflush
+#endif /* !defined(_USE_WRITE) */
+
+static double zero = 0.0; /* used as const */
+
+/*
+ * Standard conformance (non-IEEE) on exception cases.
+ * Mapping:
+ * 1 -- acos(|x|>1)
+ * 2 -- asin(|x|>1)
+ * 3 -- atan2(+-0,+-0)
+ * 4 -- hypot overflow
+ * 5 -- cosh overflow
+ * 6 -- exp overflow
+ * 7 -- exp underflow
+ * 8 -- y0(0)
+ * 9 -- y0(-ve)
+ * 10-- y1(0)
+ * 11-- y1(-ve)
+ * 12-- yn(0)
+ * 13-- yn(-ve)
+ * 14-- lgamma(finite) overflow
+ * 15-- lgamma(-integer)
+ * 16-- log(0)
+ * 17-- log(x<0)
+ * 18-- log10(0)
+ * 19-- log10(x<0)
+ * 20-- pow(0.0,0.0)
+ * 21-- pow(x,y) overflow
+ * 22-- pow(x,y) underflow
+ * 23-- pow(0,negative)
+ * 24-- pow(neg,non-integral)
+ * 25-- sinh(finite) overflow
+ * 26-- sqrt(negative)
+ * 27-- fmod(x,0)
+ * 28-- remainder(x,0)
+ * 29-- acosh(x<1)
+ * 30-- atanh(|x|>1)
+ * 31-- atanh(|x|=1)
+ * 32-- scalb overflow
+ * 33-- scalb underflow
+ * 34-- j0(|x|>X_TLOSS)
+ * 35-- y0(x>X_TLOSS)
+ * 36-- j1(|x|>X_TLOSS)
+ * 37-- y1(x>X_TLOSS)
+ * 38-- jn(|x|>X_TLOSS, n)
+ * 39-- yn(x>X_TLOSS, n)
+ * 40-- gamma(finite) overflow
+ * 41-- gamma(-integer)
+ * 42-- pow(NaN,0.0)
+ */
+
+
+#ifdef __STDC__
+ double __kernel_standard(double x, double y, int type)
+#else
+ double __kernel_standard(x,y,type)
+ double x,y; int type;
+#endif
+{
+ struct exception exc;
+#ifndef HUGE_VAL /* this is the only routine that uses HUGE_VAL */
+#define HUGE_VAL inf
+ double one = 1.0, inf = 0.0;
+ int i0;
+
+ i0 = ((*(int*)&one)>>29)^1;
+ *(i0+(int*)&inf) = 0x7ff00000; /* set inf to infinite */
+#endif
+
+#ifdef _USE_WRITE
+ (void) fflush(stdout);
+#endif
+ exc.arg1 = x;
+ exc.arg2 = y;
+ switch(type) {
+ case 1:
+ /* acos(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "acos";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acos: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 2:
+ /* asin(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "asin";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("asin: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 3:
+ /* atan2(+-0,+-0) */
+ exc.arg1 = y;
+ exc.arg2 = x;
+ exc.type = DOMAIN;
+ exc.name = "atan2";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atan2: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 4:
+ /* hypot(finite,finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "hypot";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 5:
+ /* cosh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "cosh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 6:
+ /* exp(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "exp";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 7:
+ /* exp(finite) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "exp";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 8:
+ /* y0(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 9:
+ /* y0(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 10:
+ /* y1(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 11:
+ /* y1(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 12:
+ /* yn(n,0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 13:
+ /* yn(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 14:
+ /* lgamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 15:
+ /* lgamma(-integer) or lgamma(0) */
+ exc.type = SING;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("lgamma: SING error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 16:
+ /* log(0) */
+ exc.type = SING;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: SING error\n", 16);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 17:
+ /* log(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: DOMAIN error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 18:
+ /* log10(0) */
+ exc.type = SING;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 19:
+ /* log10(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 20:
+ /* pow(0.0,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION != _SVID_) exc.retval = 1.0;
+ else if (!matherr(&exc)) {
+ (void) WRITE2("pow(0,0): DOMAIN error\n", 23);
+ errno = EDOM;
+ }
+ break;
+ case 21:
+ /* pow(x,y) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_) {
+ exc.retval = HUGE;
+ y *= 0.5;
+ if(x<zero&&rint(y)!=y) exc.retval = -HUGE;
+ } else {
+ exc.retval = HUGE_VAL;
+ y *= 0.5;
+ if(x<zero&&rint(y)!=y) exc.retval = -HUGE_VAL;
+ }
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 22:
+ /* pow(x,y) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 23:
+ /* 0**neg */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("pow(0,neg): DOMAIN error\n", 25);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 24:
+ /* neg**non-integral */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero; /* X/Open allow NaN */
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("neg**non-integral: DOMAIN error\n", 32);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 25:
+ /* sinh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "sinh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = ( (x>zero) ? HUGE : -HUGE);
+ else
+ exc.retval = ( (x>zero) ? HUGE_VAL : -HUGE_VAL);
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 26:
+ /* sqrt(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "sqrt";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("sqrt: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 27:
+ /* fmod(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "fmod";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = x;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("fmod: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 28:
+ /* remainder(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "remainder";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("remainder: DOMAIN error\n", 24);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 29:
+ /* acosh(x<1) */
+ exc.type = DOMAIN;
+ exc.name = "acosh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acosh: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 30:
+ /* atanh(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "atanh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 31:
+ /* atanh(|x|=1) */
+ exc.type = SING;
+ exc.name = "atanh";
+ exc.retval = x/zero; /* sign(x)*inf */
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 32:
+ /* scalb overflow; SVID also returns +-HUGE_VAL */
+ exc.type = OVERFLOW;
+ exc.name = "scalb";
+ exc.retval = x > zero ? HUGE_VAL : -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 33:
+ /* scalb underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "scalb";
+ exc.retval = copysign(zero,x);
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 34:
+ /* j0(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 35:
+ /* y0(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 36:
+ /* j1(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 37:
+ /* y1(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 38:
+ /* jn(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "jn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 39:
+ /* yn(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "yn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 40:
+ /* gamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 41:
+ /* gamma(-integer) or gamma(0) */
+ exc.type = SING;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("gamma: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 42:
+ /* pow(NaN,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ & _XOPEN_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = x;
+ if (_LIB_VERSION == _IEEE_ ||
+ _LIB_VERSION == _POSIX_) exc.retval = 1.0;
+ else if (!matherr(&exc)) {
+ errno = EDOM;
+ }
+ break;
+ }
+ return exc.retval;
+}
diff --git a/lib/msun/src/k_tan.c b/lib/msun/src/k_tan.c
new file mode 100644
index 000000000000..4bcf8496d896
--- /dev/null
+++ b/lib/msun/src/k_tan.c
@@ -0,0 +1,137 @@
+/* @(#)k_tan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: k_tan.c,v 1.1.1.1 1994/05/06 00:20:02 gclarkii Exp $";
+#endif
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k=1) or
+ * -1/tan (if k= -1) is returned.
+ *
+ * Algorithm
+ * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ * 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ * 3. tan(x) is approximated by a odd polynomial of degree 27 on
+ * [0,0.67434]
+ * 3 27
+ * tan(x) ~ x + T1*x + ... + T13*x
+ * where
+ *
+ * |tan(x) 2 4 26 | -59.2
+ * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
+ * | x |
+ *
+ * Note: tan(x+y) = tan(x) + tan'(x)*y
+ * ~ tan(x) + (1+x*x)*y
+ * Therefore, for better accuracy in computing tan(x+y), let
+ * 3 2 2 2 2
+ * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ * then
+ * 3 2
+ * tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
+ * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pio4 = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+pio4lo= 3.06161699786838301793e-17, /* 0x3C81A626, 0x33145C07 */
+T[] = {
+ 3.33333333333334091986e-01, /* 0x3FD55555, 0x55555563 */
+ 1.33333333333201242699e-01, /* 0x3FC11111, 0x1110FE7A */
+ 5.39682539762260521377e-02, /* 0x3FABA1BA, 0x1BB341FE */
+ 2.18694882948595424599e-02, /* 0x3F9664F4, 0x8406D637 */
+ 8.86323982359930005737e-03, /* 0x3F8226E3, 0xE96E8493 */
+ 3.59207910759131235356e-03, /* 0x3F6D6D22, 0xC9560328 */
+ 1.45620945432529025516e-03, /* 0x3F57DBC8, 0xFEE08315 */
+ 5.88041240820264096874e-04, /* 0x3F4344D8, 0xF2F26501 */
+ 2.46463134818469906812e-04, /* 0x3F3026F7, 0x1A8D1068 */
+ 7.81794442939557092300e-05, /* 0x3F147E88, 0xA03792A6 */
+ 7.14072491382608190305e-05, /* 0x3F12B80F, 0x32F0A7E9 */
+ -1.85586374855275456654e-05, /* 0xBEF375CB, 0xDB605373 */
+ 2.59073051863633712884e-05, /* 0x3EFB2A70, 0x74BF7AD4 */
+};
+
+#ifdef __STDC__
+ double __kernel_tan(double x, double y, int iy)
+#else
+ double __kernel_tan(x, y, iy)
+ double x,y; int iy;
+#endif
+{
+ double z,r,v,w,s;
+ int ix,hx;
+
+ hx = *(n0+(int*)&x); /* high word of x */
+ ix = hx&0x7fffffff; /* high word of |x| */
+ if(ix<0x3e300000) /* x < 2**-28 */
+ {if((int)x==0) { /* generate inexact */
+ if(((ix|*(1-n0+(int*)&x))|(iy+1))==0) return one/fabs(x);
+ else return (iy==1)? x: -one/x;
+ }
+ }
+ if(ix>=0x3FE59428) { /* |x|>=0.6744 */
+ if(hx<0) {x = -x; y = -y;}
+ z = pio4-x;
+ w = pio4lo-y;
+ x = z+w; y = 0.0;
+ }
+ z = x*x;
+ w = z*z;
+ /* Break x^5*(T[1]+x^2*T[2]+...) into
+ * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+ * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ */
+ r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+ v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+ s = z*x;
+ r = y + z*(s*(r+v)+y);
+ r += T[0]*s;
+ w = x+r;
+ if(ix>=0x3FE59428) {
+ v = (double)iy;
+ return (double)(1-((hx>>30)&2))*(v-2.0*(x-(w*w/(w+v)-r)));
+ }
+ if(iy==1) return w;
+ else { /* if allow error up to 2 ulp,
+ simply return -1.0/(x+r) here */
+ /* compute -1.0/(x+r) accurately */
+ double a,t;
+ z = w;
+ *(1-n0+(int*)&z) = 0;
+ v = r-(z - x); /* z+v = r+x */
+ t = a = -1.0/w; /* a = -1.0/w */
+ *(1-n0+(int*)&t) = 0;
+ s = 1.0+t*z;
+ return t+a*(s+t*v);
+ }
+}
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
new file mode 100644
index 000000000000..8919e24c7361
--- /dev/null
+++ b/lib/msun/src/math.h
@@ -0,0 +1,224 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ * $Id: math.h,v 1.1.1.1 1994/05/06 00:20:14 gclarkii Exp $
+ */
+
+#ifndef _MATH_H_
+#define _MATH_H_
+
+/*
+ * ANSI/POSIX
+ */
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
+/*
+ * XOPEN/SVID
+ */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define M_E 2.7182818284590452354 /* e */
+#define M_LOG2E 1.4426950408889634074 /* log 2e */
+#define M_LOG10E 0.43429448190325182765 /* log 10e */
+#define M_LN2 0.69314718055994530942 /* log e2 */
+#define M_LN10 2.30258509299404568402 /* log e10 */
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
+#define M_1_PI 0.31830988618379067154 /* 1/pi */
+#define M_2_PI 0.63661977236758134308 /* 2/pi */
+#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+extern int signgam;
+
+#if !defined(_XOPEN_SOURCE)
+enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix};
+
+#define _LIB_VERSION_TYPE enum fdversion
+#define _LIB_VERSION _fdlib_version
+
+/* if global variable _LIB_VERSION is not desirable, one may
+ * change the following to be a constant by:
+ * #define _LIB_VERSION_TYPE const enum version
+ * In that case, after one initializes the value _LIB_VERSION (see
+ * s_lib_version.c) during compile time, it cannot be modified
+ * in the middle of a program
+ */
+extern _LIB_VERSION_TYPE _LIB_VERSION;
+
+#define _IEEE_ fdlibm_ieee
+#define _SVID_ fdlibm_svid
+#define _XOPEN_ fdlibm_xopen
+#define _POSIX_ fdlibm_posix
+
+struct exception {
+ int type;
+ char *name;
+ double arg1;
+ double arg2;
+ double retval;
+};
+
+#define HUGE MAXFLOAT
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS 1.41484755040568800000e+16
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+#endif /* !_XOPEN_SOURCE */
+#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
+
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+/*
+ * ANSI/POSIX
+ */
+extern double acos __P((double));
+extern double asin __P((double));
+extern double atan __P((double));
+extern double atan2 __P((double, double));
+extern double cos __P((double));
+extern double sin __P((double));
+extern double tan __P((double));
+
+extern double cosh __P((double));
+extern double sinh __P((double));
+extern double tanh __P((double));
+
+extern double exp __P((double));
+extern double frexp __P((double, int *));
+extern double ldexp __P((double, int));
+extern double log __P((double));
+extern double log10 __P((double));
+extern double modf __P((double, double *));
+
+extern double pow __P((double, double));
+extern double sqrt __P((double));
+
+extern double ceil __P((double));
+extern double fabs __P((double));
+extern double floor __P((double));
+extern double fmod __P((double, double));
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+extern double erf __P((double));
+extern double erfc __P((double));
+extern double gamma __P((double));
+extern double hypot __P((double, double));
+extern int isinf __P((double));
+extern int isnan __P((double));
+extern int finite __P((double));
+extern double j0 __P((double));
+extern double j1 __P((double));
+extern double jn __P((int, double));
+extern double lgamma __P((double));
+extern double y0 __P((double));
+extern double y1 __P((double));
+extern double yn __P((int, double));
+
+#if !defined(_XOPEN_SOURCE)
+extern double acosh __P((double));
+extern double asinh __P((double));
+extern double atanh __P((double));
+extern double cbrt __P((double));
+extern double logb __P((double));
+extern double nextafter __P((double, double));
+extern double remainder __P((double, double));
+extern double scalb __P((double, double));
+
+extern int matherr __P((struct exception *));
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand __P((double));
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign __P((double, double));
+extern int ilogb __P((double));
+extern double rint __P((double));
+extern double scalbn __P((double, int));
+
+/*
+ * BSD math library entry points
+ */
+extern double cabs();
+extern double drem __P((double, double));
+extern double expm1 __P((double));
+extern double log1p __P((double));
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r __P((double, int *));
+extern double lgamma_r __P((double, int *));
+#endif /* _REENTRANT */
+#endif /* !_XOPEN_SOURCE */
+#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_lgamma __P((double));
+extern double __ieee754_gamma __P((double));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern int __ieee754_rem_pio2 __P((double,double*));
+extern double __ieee754_scalb __P((double,double));
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*));
+__END_DECLS
+
+#endif /* _MATH_H_ */
diff --git a/lib/msun/src/s_asinh.c b/lib/msun/src/s_asinh.c
new file mode 100644
index 000000000000..2273a360df4e
--- /dev/null
+++ b/lib/msun/src/s_asinh.c
@@ -0,0 +1,71 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_asinh.c,v 1.1.1.1 1994/05/06 00:20:02 gclarkii Exp $";
+#endif
+
+/* asinh(x)
+ * Method :
+ * Based on
+ * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ * we have
+ * asinh(x) := x if 1+x*x=1,
+ * := sign(x)*(log(x)+ln2)) for large |x|, else
+ * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge= 1.00000000000000000000e+300;
+
+#ifdef __STDC__
+ double asinh(double x)
+#else
+ double asinh(x)
+ double x;
+#endif
+{
+ double t,w;
+ int hx,ix;
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
+ if(ix< 0x3e300000) { /* |x|<2**-28 */
+ if(huge+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x41b00000) { /* |x| > 2**28 */
+ w = __ieee754_log(fabs(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fabs(x);
+ w = __ieee754_log(2.0*t+one/(sqrt(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
diff --git a/lib/msun/src/s_atan.c b/lib/msun/src/s_atan.c
new file mode 100644
index 000000000000..abe5e61515e6
--- /dev/null
+++ b/lib/msun/src/s_atan.c
@@ -0,0 +1,143 @@
+/* @(#)s_atan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_atan.c,v 1.1.1.1 1994/05/06 00:20:02 gclarkii Exp $";
+#endif
+
+/* atan(x)
+ * Method
+ * 1. Reduce x to positive by atan(x) = -atan(-x).
+ * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ * is further reduced to one of the following intervals and the
+ * arctangent of t is evaluated by the corresponding formula:
+ *
+ * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double atanhi[] = {
+#else
+static double atanhi[] = {
+#endif
+ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+#ifdef __STDC__
+static const double atanlo[] = {
+#else
+static double atanlo[] = {
+#endif
+ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+#ifdef __STDC__
+static const double aT[] = {
+#else
+static double aT[] = {
+#endif
+ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+ 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+ 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+ 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+#ifdef __STDC__
+ static const double
+#else
+ static double
+#endif
+one = 1.0,
+huge = 1.0e300;
+
+#ifdef __STDC__
+ double atan(double x)
+#else
+ double atan(x)
+ double x;
+#endif
+{
+ double w,s1,s2,z;
+ int ix,hx,id;
+
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x44100000) { /* if |x| >= 2^66 */
+ if(ix>0x7ff00000||
+ (ix==0x7ff00000&&(*(1-n0+(int*)&x)!=0)))
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if(huge+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fabs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = (2.0*x-one)/(2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2; x = (x-1.5)/(one+1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
diff --git a/lib/msun/src/s_cbrt.c b/lib/msun/src/s_cbrt.c
new file mode 100644
index 000000000000..6fd7172d5ccc
--- /dev/null
+++ b/lib/msun/src/s_cbrt.c
@@ -0,0 +1,95 @@
+/* @(#)s_cbrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_cbrt.c,v 1.1.1.1 1994/05/06 00:20:03 gclarkii Exp $";
+#endif
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+#ifdef __STDC__
+static const unsigned
+#else
+static unsigned
+#endif
+ B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
+F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
+G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+#ifdef __STDC__
+ double cbrt(double x)
+#else
+ double cbrt(x)
+ double x;
+#endif
+{
+ int hx;
+ double r,s,t=0.0,w;
+ unsigned *pt = (unsigned *) &t, sign;
+
+ hx = *( n0 + (int*)&x); /* high word of x */
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if((hx|*(1-n0+(int*)&x))==0)
+ return(x); /* cbrt(0) is itself */
+
+ *(n0+(int*)&x) = hx; /* x <- |x| */
+ /* rough cbrt to 5 bits */
+ if(hx<0x00100000) /* subnormal number */
+ {pt[n0]=0x43500000; /* set t= 2**54 */
+ t*=x; pt[n0]=pt[n0]/3+B2;
+ }
+ else
+ pt[n0]=hx/3+B1;
+
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r=t*t/x;
+ s=C+r*t;
+ t*=G+F/(s+E+D/s);
+
+ /* chopped to 20 bits and make it larger than cbrt(x) */
+ pt[1-n0]=0; pt[n0]+=0x00000001;
+
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s;
+ w=t+t;
+ r=(r-t)/(w+r); /* r-s is exact */
+ t=t+t*r;
+
+ /* retore the sign bit */
+ pt[n0] |= sign;
+ return(t);
+}
diff --git a/lib/msun/src/s_ceil.c b/lib/msun/src/s_ceil.c
new file mode 100644
index 000000000000..a6a6a84fe12f
--- /dev/null
+++ b/lib/msun/src/s_ceil.c
@@ -0,0 +1,88 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_ceil.c,v 1.1.1.1 1994/05/06 00:20:02 gclarkii Exp $";
+#endif
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double huge = 1.0e300;
+#else
+static double huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double ceil(double x)
+#else
+ double ceil(x)
+ double x;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = *(n0+(int*)&x);
+ i1 = *(1-n0+(int*)&x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1 + (1<<(52-j0));
+ if(j<i1) i0+=1; /* got a carry */
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ *(n0+(int*)&x) = i0;
+ *(1-n0+(int*)&x) = i1;
+ return x;
+}
diff --git a/lib/msun/src/s_copysign.c b/lib/msun/src/s_copysign.c
new file mode 100644
index 000000000000..ec92acd078d4
--- /dev/null
+++ b/lib/msun/src/s_copysign.c
@@ -0,0 +1,42 @@
+/* @(#)s_copysign.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_copysign.c,v 1.1.1.1 1994/05/06 00:20:03 gclarkii Exp $";
+#endif
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+ double copysign(double x, double y)
+#else
+ double copysign(x,y)
+ double x,y;
+#endif
+{
+ *(n0+(unsigned*)&x) =
+ (*(n0+(unsigned*)&x)&0x7fffffff)|(*(n0+(unsigned*)&y)&0x80000000);
+ return x;
+}
diff --git a/lib/msun/src/s_cos.c b/lib/msun/src/s_cos.c
new file mode 100644
index 000000000000..4bb52ef97b04
--- /dev/null
+++ b/lib/msun/src/s_cos.c
@@ -0,0 +1,87 @@
+/* @(#)s_cos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_cos.c,v 1.1.1.1 1994/05/06 00:20:03 gclarkii Exp $";
+#endif
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cosine function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one=1.0;
+#else
+static double one=1.0;
+#endif
+
+#ifdef __STDC__
+ double cos(double x)
+#else
+ double cos(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cos(y[0],y[1]);
+ case 1: return -__kernel_sin(y[0],y[1],1);
+ case 2: return -__kernel_cos(y[0],y[1]);
+ default:
+ return __kernel_sin(y[0],y[1],1);
+ }
+ }
+}
diff --git a/lib/msun/src/s_erf.c b/lib/msun/src/s_erf.c
new file mode 100644
index 000000000000..acf76ad49cad
--- /dev/null
+++ b/lib/msun/src/s_erf.c
@@ -0,0 +1,320 @@
+/* @(#)s_erf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_erf.c,v 1.1.1.1 1994/05/06 00:20:03 gclarkii Exp $";
+#endif
+
+/* double erf(double x)
+ * double erfc(double x)
+ * x
+ * 2 |\
+ * erf(x) = --------- | exp(-t*t)dt
+ * sqrt(pi) \|
+ * 0
+ *
+ * erfc(x) = 1-erf(x)
+ * Note that
+ * erf(-x) = -erf(x)
+ * erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ * 1. For |x| in [0, 0.84375]
+ * erf(x) = x + x*R(x^2)
+ * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+ * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+ * where R = P/Q where P is an odd poly of degree 8 and
+ * Q is an odd poly of degree 10.
+ * -57.90
+ * | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ * Remark. The formula is derived by noting
+ * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ * and that
+ * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ * is close to one. The interval is chosen because the fix
+ * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ * near 0.6174), and by some experiment, 0.84375 is chosen to
+ * guarantee the error is less than one ulp for erf.
+ *
+ * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ * c = 0.84506291151 rounded to single (24 bits)
+ * erf(x) = sign(x) * (c + P1(s)/Q1(s))
+ * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+ * 1+(c+P1(s)/Q1(s)) if x < 0
+ * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ * Remark: here we use the taylor series expansion at x=1.
+ * erf(1+s) = erf(1) + s*Poly(s)
+ * = 0.845.. + P1(s)/Q1(s)
+ * That is, we use rational approximation to approximate
+ * erf(1+s) - (c = (single)0.84506291151)
+ * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ * where
+ * P1(s) = degree 6 poly in s
+ * Q1(s) = degree 6 poly in s
+ *
+ * 3. For x in [1.25,1/0.35(~2.857143)],
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ * erf(x) = 1 - erfc(x)
+ * where
+ * R1(z) = degree 7 poly in z, (z=1/x^2)
+ * S1(z) = degree 8 poly in z
+ *
+ * 4. For x in [1/0.35,28]
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ * = 2.0 - tiny (if x <= -6)
+ * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ * erf(x) = sign(x)*(1.0 - tiny)
+ * where
+ * R2(z) = degree 6 poly in z, (z=1/x^2)
+ * S2(z) = degree 7 poly in z
+ *
+ * Note1:
+ * To compute exp(-x*x-0.5625+R/S), let s be a single
+ * precision number and s := x; then
+ * -x*x = -s*s + (s-x)*(s+x)
+ * exp(-x*x-0.5626+R/S) =
+ * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ * Note2:
+ * Here 4 and 5 make use of the asymptotic series
+ * exp(-x*x)
+ * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ * x*sqrt(pi)
+ * We use rational approximation to approximate
+ * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ * Here is the error bound for R1/S1 and R2/S2
+ * |R1/S1 - f(x)| < 2**(-62.57)
+ * |R2/S2 - f(x)| < 2**(-61.52)
+ *
+ * 5. For inf > x >= 28
+ * erf(x) = sign(x) *(1 - tiny) (raise inexact)
+ * erfc(x) = tiny*tiny (raise underflow) if x > 0
+ * = 2 - tiny if x<0
+ *
+ * 7. Special case:
+ * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+ * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ * erfc/erf(NaN) is NaN
+ */
+
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1e-300,
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+ /* c = (float)0.84506291151 */
+erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+#ifdef __STDC__
+ double erf(double x)
+#else
+ double erf(x)
+ double x;
+#endif
+{
+ int hx,ix,i;
+ double R,S,P,Q,s,y,z,r;
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erf(nan)=nan */
+ i = ((unsigned)hx>>31)<<1;
+ return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3e300000) { /* |x|<2**-28 */
+ if (ix < 0x00800000)
+ return 0.125*(8.0*x+efx8*x); /*avoid underflow */
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40180000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ *(1-n0+(int*)&z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+#ifdef __STDC__
+ double erfc(double x)
+#else
+ double erfc(x)
+ double x;
+#endif
+{
+ int hx,ix;
+ double R,S,P,Q,s,y,z,r;
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (double)(((unsigned)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3c700000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3fd00000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x403c0000) { /* |x|<28 */
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ *(1-n0+(int*)&z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*
+ __ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
diff --git a/lib/msun/src/s_expm1.c b/lib/msun/src/s_expm1.c
new file mode 100644
index 000000000000..7c95f274e98b
--- /dev/null
+++ b/lib/msun/src/s_expm1.c
@@ -0,0 +1,226 @@
+/* @(#)s_expm1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_expm1.c,v 1.1.1.1 1994/05/06 00:20:03 gclarkii Exp $";
+#endif
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+ *
+ * Here a correction term c will be computed to compensate
+ * the error in r when rounded to a floating-point number.
+ *
+ * 2. Approximating expm1(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Since
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ * we define R1(r*r) by
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ * That is,
+ * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ * We use a special Reme algorithm on [0,0.347] to generate
+ * a polynomial of degree 5 in r*r to approximate R1. The
+ * maximum error of this polynomial approximation is bounded
+ * by 2**-61. In other words,
+ * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ * where Q1 = -1.6666666666666567384E-2,
+ * Q2 = 3.9682539681370365873E-4,
+ * Q3 = -9.9206344733435987357E-6,
+ * Q4 = 2.5051361420808517002E-7,
+ * Q5 = -6.2843505682382617102E-9;
+ * (where z=r*r, and the values of Q1 to Q5 are listed below)
+ * with error bounded by
+ * | 5 | -61
+ * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+ * | |
+ *
+ * expm1(r) = exp(r)-1 is then computed by the following
+ * specific way which minimize the accumulation rounding error:
+ * 2 3
+ * r r [ 3 - (R1 + R1*r/2) ]
+ * expm1(r) = r + --- + --- * [--------------------]
+ * 2 2 [ 6 - r*(3 - R1*r/2) ]
+ *
+ * To compensate the error in the argument reduction, we use
+ * expm1(r+c) = expm1(r) + c + expm1(r)*c
+ * ~ expm1(r) + c + r*c
+ * Thus c+r*c will be added in as the correction terms for
+ * expm1(r+c). Now rearrange the term to avoid optimization
+ * screw up:
+ * ( 2 2 )
+ * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+ * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+ * ( )
+ *
+ * = r - E
+ * 3. Scale back to obtain expm1(x):
+ * From step 1, we have
+ * expm1(x) = either 2^k*[expm1(r)+1] - 1
+ * = or 2^k*[expm1(r) + (1-2^-k)]
+ * 4. Implementation notes:
+ * (A). To save one multiplication, we scale the coefficient Qi
+ * to Qi*2^i, and replace z by (x^2)/2.
+ * (B). To achieve maximum accuracy, we compute expm1(x) by
+ * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ * (ii) if k=0, return r-E
+ * (iii) if k=-1, return 0.5*(r-E)-0.5
+ * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ * else return 1.0+2.0*(r-E);
+ * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ * (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ * expm1(INF) is INF, expm1(NaN) is NaN;
+ * expm1(-INF) is -1, and
+ * for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+huge = 1.0e+300,
+tiny = 1.0e-300,
+o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+#ifdef __STDC__
+ double expm1(double x)
+#else
+ double expm1(x)
+ double x;
+#endif
+{
+ double y,hi,lo,c,t,e,hxs,hfx,r1;
+ int k,xsb;
+ unsigned hx;
+
+ hx = *(n0+(unsigned*)&x); /* high word of x */
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out huge and non-finite argument */
+ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|*(1-n0+(int*)&x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ }
+ if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+ if(x+tiny<0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = invln2*x+((xsb==0)?0.5:-0.5);
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ t = huge+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(huge+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = 0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = 3.0-r1*hfx;
+ e = hxs*((r1-t)/(6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return 0.5*(x-e)-0.5;
+ if(k==1)
+ if(x < -0.25) return -2.0*(e-(x+0.5));
+ else return one+2.0*(x-e);
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ y = one-(e-x);
+ *(n0+(int*)&y) += (k<<20); /* add k to y's exponent */
+ return y-one;
+ }
+ t = one;
+ if(k<20) {
+ *(n0+(int*)&t) = 0x3ff00000 - (0x200000>>k); /* t=1-2^-k */
+ y = t-(e-x);
+ *(n0+(int*)&y) += (k<<20); /* add k to y's exponent */
+ } else {
+ *(n0+(int*)&t) = ((0x3ff-k)<<20); /* 2^-k */
+ y = x-(e+t);
+ y += one;
+ *(n0+(int*)&y) += (k<<20); /* add k to y's exponent */
+ }
+ }
+ return y;
+}
diff --git a/lib/msun/src/s_fabs.c b/lib/msun/src/s_fabs.c
new file mode 100644
index 000000000000..7cf1ccae8b28
--- /dev/null
+++ b/lib/msun/src/s_fabs.c
@@ -0,0 +1,38 @@
+/* @(#)s_fabs.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_fabs.c,v 1.1.1.1 1994/05/06 00:20:04 gclarkii Exp $";
+#endif
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0;
+#else
+static double one = 1.0;
+#endif
+
+#ifdef __STDC__
+ double fabs(double x)
+#else
+ double fabs(x)
+ double x;
+#endif
+{
+ *((((*(int*)&one)>>29)^1)+(int*)&x) &= 0x7fffffff;
+ return x;
+}
diff --git a/lib/msun/src/s_finite.c b/lib/msun/src/s_finite.c
new file mode 100644
index 000000000000..02fe3077f1c5
--- /dev/null
+++ b/lib/msun/src/s_finite.c
@@ -0,0 +1,41 @@
+/* @(#)s_finite.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_finite.c,v 1.1.1.1 1994/05/06 00:20:04 gclarkii Exp $";
+#endif
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+ int finite(double x)
+#else
+ int finite(x)
+ double x;
+#endif
+{
+ int hx;
+ hx = *(n0+(int*)&x);
+ return (unsigned)((hx&0x7fffffff)-0x7ff00000)>>31;
+}
diff --git a/lib/msun/src/s_floor.c b/lib/msun/src/s_floor.c
new file mode 100644
index 000000000000..2bb6ffc7c113
--- /dev/null
+++ b/lib/msun/src/s_floor.c
@@ -0,0 +1,89 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_floor.c,v 1.1.1.1 1994/05/06 00:20:04 gclarkii Exp $";
+#endif
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double huge = 1.0e300;
+#else
+static double huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double floor(double x)
+#else
+ double floor(x)
+ double x;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = *(n0+(int*)&x);
+ i1 = *(1-n0+(int*)&x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=i1=0;}
+ else if(((i0&0x7fffffff)|i1)!=0)
+ { i0=0xbff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1+(1<<(52-j0));
+ if(j<i1) i0 +=1 ; /* got a carry */
+ i1=j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ *(n0+(int*)&x) = i0;
+ *(1-n0+(int*)&x) = i1;
+ return x;
+}
diff --git a/lib/msun/src/s_frexp.c b/lib/msun/src/s_frexp.c
new file mode 100644
index 000000000000..a07ba0df696b
--- /dev/null
+++ b/lib/msun/src/s_frexp.c
@@ -0,0 +1,67 @@
+/* @(#)s_frexp.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_frexp.c,v 1.1.1.1 1994/05/06 00:20:04 gclarkii Exp $";
+#endif
+
+/*
+ * for non-zero x
+ * x = frexp(arg,&exp);
+ * return a double fp quantity x such that 0.5 <= |x| <1.0
+ * and the corresponding binary exponent "exp". That is
+ * arg = x*2^exp.
+ * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
+ * with *exp=0.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
+
+#ifdef __STDC__
+ double frexp(double x, int *eptr)
+#else
+ double frexp(x, eptr)
+ double x; int *eptr;
+#endif
+{
+ int hx, ix, lx;
+ hx = *(n0+(int*)&x);
+ ix = 0x7fffffff&hx;
+ lx = *(1-n0+(int*)&x);
+ *eptr = 0;
+ if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */
+ if (ix<0x00100000) { /* subnormal */
+ x *= two54;
+ hx = *(n0+(int*)&x);
+ ix = hx&0x7fffffff;
+ *eptr = -54;
+ }
+ *eptr += (ix>>20)-1022;
+ hx = (hx&0x800fffff)|0x3fe00000;
+ *(n0 + (int*)&x) = hx;
+ return x;
+}
diff --git a/lib/msun/src/s_ilogb.c b/lib/msun/src/s_ilogb.c
new file mode 100644
index 000000000000..6ca76107928a
--- /dev/null
+++ b/lib/msun/src/s_ilogb.c
@@ -0,0 +1,56 @@
+/* @(#)s_ilogb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_ilogb.c,v 1.1.1.1 1994/05/06 00:20:05 gclarkii Exp $";
+#endif
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = 0x80000001
+ * ilogb(inf/NaN) = 0x7fffffff (no signal is raised)
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+ int ilogb(double x)
+#else
+ int ilogb(x)
+ double x;
+#endif
+{
+ int hx,lx,ix;
+
+ hx = (*(n0+(unsigned*)&x))&0x7fffffff; /* high word of x */
+ if(hx<0x00100000) {
+ lx = *(1-n0+(int*)&x);
+ if((hx|lx)==0)
+ return 0x80000001; /* ilogb(0) = 0x80000001 */
+ else /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043; lx>0; lx<<=1) ix -=1;
+ } else {
+ for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+ }
+ return ix;
+ }
+ else if (hx<0x7ff00000) return (hx>>20)-1023;
+ else return 0x7fffffff;
+}
diff --git a/lib/msun/src/s_isnan.c b/lib/msun/src/s_isnan.c
new file mode 100644
index 000000000000..603ef810306b
--- /dev/null
+++ b/lib/msun/src/s_isnan.c
@@ -0,0 +1,50 @@
+/* @(#)s_isnan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_isnan.c,v 1.1.1.1 1994/05/06 00:20:05 gclarkii Exp $";
+#endif
+
+/*
+ * isnan(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0;
+#else
+static double one = 1.0;
+#endif
+
+#ifdef __STDC__
+ int isnan(double x)
+#else
+ int isnan(x)
+ double x;
+#endif
+{
+ int hx,lx;
+ hx = (*(n0+(int*)&x)&0x7fffffff);
+ lx = *(1-n0+(int*)&x);
+ hx |= (unsigned)(lx|(-lx))>>31;
+ hx = 0x7ff00000 - hx;
+ return ((unsigned)(hx))>>31;
+}
diff --git a/lib/msun/src/s_ldexp.c b/lib/msun/src/s_ldexp.c
new file mode 100644
index 000000000000..6976ee0a6513
--- /dev/null
+++ b/lib/msun/src/s_ldexp.c
@@ -0,0 +1,31 @@
+/* @(#)s_ldexp.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_ldexp.c,v 1.1.1.1 1994/05/06 00:20:05 gclarkii Exp $";
+#endif
+
+#include "math.h"
+#include <errno.h>
+
+#ifdef __STDC__
+ double ldexp(double value, int exp)
+#else
+ double ldexp(value, exp)
+ double value; int exp;
+#endif
+{
+ if(!finite(value)||value==0.0) return value;
+ value = scalbn(value,exp);
+ if(!finite(value)||value==0.0) errno = ERANGE;
+ return value;
+}
diff --git a/lib/msun/src/s_lib_version.c b/lib/msun/src/s_lib_version.c
new file mode 100644
index 000000000000..38c5c45a499d
--- /dev/null
+++ b/lib/msun/src/s_lib_version.c
@@ -0,0 +1,38 @@
+/* @(#)s_lib_version.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_lib_version.c,v 1.1.1.1 1994/05/06 00:20:06 gclarkii Exp $";
+#endif
+
+/*
+ * MACRO for standards
+ */
+
+#include "math.h"
+
+/*
+ * define and initialize _LIB_VERSION
+ */
+#ifdef _POSIX_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _POSIX_;
+#else
+#ifdef _XOPEN_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _XOPEN_;
+#else
+#ifdef _SVID3_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _SVID_;
+#else /* default _IEEE_MODE */
+_LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
+#endif
+#endif
+#endif
diff --git a/lib/msun/src/s_log1p.c b/lib/msun/src/s_log1p.c
new file mode 100644
index 000000000000..03cd6ecb9d49
--- /dev/null
+++ b/lib/msun/src/s_log1p.c
@@ -0,0 +1,175 @@
+/* @(#)s_log1p.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_log1p.c,v 1.1.1.1 1994/05/06 00:20:05 gclarkii Exp $";
+#endif
+
+/* double log1p(double x)
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * 1+x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * Note. If k=0, then f=x is exact. However, if k!=0, then f
+ * may not be representable exactly. In that case, a correction
+ * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ * and add back the correction term c/u.
+ * (Note: when x > 2**53, one can simply return log(x))
+ *
+ * 2. Approximation of log1p(f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+ * (the values of Lp1 to Lp7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lp1*s +...+Lp7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ * 3. Finally, log1p(x) = k*ln2 + log1p(f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ * log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ * u = 1+x;
+ * if(u==1.0) return x ; else
+ * return log(u)*(x/(u-1.0));
+ *
+ * See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double log1p(double x)
+#else
+ double log1p(x)
+ double x;
+#endif
+{
+ double hfsq,f,c,s,z,R,u;
+ int k,hx,hu,ax;
+
+ hx = *(n0+(int*)&x); /* high word of x */
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* x < 0.41422 */
+ if(ax>=0x3ff00000) { /* x <= -1.0 */
+ if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x3e200000) { /* |x| < 2**-29 */
+ if(two54+x>zero /* raise inexact */
+ &&ax<0x3c900000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*0.5;
+ }
+ if(hx>0||hx<=((int)0xbfd2bec3)) {
+ k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ if(k!=0) {
+ if(hx<0x43400000) {
+ u = 1.0+x;
+ hu = *(n0+(int*)&u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+ c /= u;
+ } else {
+ u = x;
+ hu = *(n0+(int*)&u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ if(hu<0x6a09e) {
+ *(n0+(int*)&u) = hu|0x3ff00000; /* normalize u */
+ } else {
+ k += 1;
+ *(n0+(int*)&u) = hu|0x3fe00000; /* normalize u/2 */
+ hu = (0x00100000-hu)>>2;
+ }
+ f = u-1.0;
+ }
+ hfsq=0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ R = hfsq*(1.0-0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/(2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/lib/msun/src/s_logb.c b/lib/msun/src/s_logb.c
new file mode 100644
index 000000000000..49b842f9d332
--- /dev/null
+++ b/lib/msun/src/s_logb.c
@@ -0,0 +1,48 @@
+/* @(#)s_logb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_logb.c,v 1.1.1.1 1994/05/06 00:20:06 gclarkii Exp $";
+#endif
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+ double logb(double x)
+#else
+ double logb(x)
+ double x;
+#endif
+{
+ int lx,ix;
+ ix = (*(n0+(int*)&x))&0x7fffffff; /* high |x| */
+ lx = *(1-n0+(int*)&x); /* low x */
+ if((ix|lx)==0) return -1.0/fabs(x);
+ if(ix>=0x7ff00000) return x*x;
+ if((ix>>=20)==0) /* IEEE 754 logb */
+ return -1022.0;
+ else
+ return (double) (ix-1023);
+}
diff --git a/lib/msun/src/s_matherr.c b/lib/msun/src/s_matherr.c
new file mode 100644
index 000000000000..eaaf46b17139
--- /dev/null
+++ b/lib/msun/src/s_matherr.c
@@ -0,0 +1,29 @@
+/* @(#)s_matherr.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_matherr.c,v 1.1.1.1 1994/05/06 00:20:06 gclarkii Exp $";
+#endif
+
+#include "math.h"
+
+#ifdef __STDC__
+ int matherr(struct exception *x)
+#else
+ int matherr(x)
+ struct exception *x;
+#endif
+{
+ int n=0;
+ if(x->arg1!=x->arg1) return 0;
+ return n;
+}
diff --git a/lib/msun/src/s_modf.c b/lib/msun/src/s_modf.c
new file mode 100644
index 000000000000..0dd0d50e5912
--- /dev/null
+++ b/lib/msun/src/s_modf.c
@@ -0,0 +1,92 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_modf.c,v 1.1.1.1 1994/05/06 00:20:06 gclarkii Exp $";
+#endif
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ * Bit twiddling.
+ *
+ * Exception:
+ * No exception.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#define n1 0
+#else
+#define n0 0
+#define n1 1
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0;
+#else
+static double one = 1.0;
+#endif
+
+#ifdef __STDC__
+ double modf(double x, double *iptr)
+#else
+ double modf(x, iptr)
+ double x,*iptr;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i;
+ i0 = *(n0+(int*)&x); /* high x */
+ i1 = *(n1+(int*)&x); /* low x */
+ j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
+ if(j0<20) { /* integer part in high x */
+ if(j0<0) { /* |x|<1 */
+ *(n0+(int*)iptr) = i0&0x80000000;
+ *(n1+(int*)iptr) = 0; /* *iptr = +-0 */
+ return x;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) { /* x is integral */
+ *iptr = x;
+ *(n0+(int*)&x) &= 0x80000000;
+ *(n1+(int*)&x) = 0; /* return +-0 */
+ return x;
+ } else {
+ *(n0+(int*)iptr) = i0&(~i);
+ *(n1+(int*)iptr) = 0;
+ return x - *iptr;
+ }
+ }
+ } else if (j0>51) { /* no fraction part */
+ *iptr = x*one;
+ *(n0+(int*)&x) &= 0x80000000;
+ *(n1+(int*)&x) = 0; /* return +-0 */
+ return x;
+ } else { /* fraction part in low x */
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) { /* x is integral */
+ *iptr = x;
+ *(n0+(int*)&x) &= 0x80000000;
+ *(n1+(int*)&x) = 0; /* return +-0 */
+ return x;
+ } else {
+ *(n0+(int*)iptr) = i0;
+ *(n1+(int*)iptr) = i1&(~i);
+ return x - *iptr;
+ }
+ }
+}
diff --git a/lib/msun/src/s_nextafter.c b/lib/msun/src/s_nextafter.c
new file mode 100644
index 000000000000..b10ca092a70b
--- /dev/null
+++ b/lib/msun/src/s_nextafter.c
@@ -0,0 +1,90 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_nextafter.c,v 1.1.1.1 1994/05/06 00:20:07 gclarkii Exp $";
+#endif
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#define n1 0
+#else
+#define n0 0
+#define n1 1
+#endif
+
+#ifdef __STDC__
+ double nextafter(double x, double y)
+#else
+ double nextafter(x,y)
+ double x,y;
+#endif
+{
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = *( n0 + (int*)&x); /* high word of x */
+ lx = *( n1 + (int*)&x); /* low word of x */
+ hy = *( n0 + (int*)&y); /* high word of y */
+ ly = *( n1 + (int*)&y); /* low word of y */
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */
+ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */
+ return x+y;
+ if(x==y) return x; /* x=y, return x */
+ if((ix|lx)==0) { /* x == 0 */
+ *(n0+(int*)&x) = hy&0x80000000; /* return +-minsubnormal */
+ *(n1+(int*)&x) = 1;
+ y = x*x;
+ if(y==x) return y; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x < y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x > y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ }
+ hy = hx&0x7ff00000;
+ if(hy>=0x7ff00000) return x+x; /* overflow */
+ if(hy<0x00100000) { /* underflow */
+ y = x*x;
+ if(y!=x) { /* raise underflow flag */
+ *(n0+(int*)&y) = hx; *(n1+(int*)&y) = lx;
+ return y;
+ }
+ }
+ *(n0+(int*)&x) = hx; *(n1+(int*)&x) = lx;
+ return x;
+}
diff --git a/lib/msun/src/s_rint.c b/lib/msun/src/s_rint.c
new file mode 100644
index 000000000000..5c310492b665
--- /dev/null
+++ b/lib/msun/src/s_rint.c
@@ -0,0 +1,94 @@
+/* @(#)s_rint.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_rint.c,v 1.1.1.1 1994/05/06 00:20:07 gclarkii Exp $";
+#endif
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ * Using floating addition.
+ * Exception:
+ * Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+TWO52[2]={
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+#ifdef __STDC__
+ double rint(double x)
+#else
+ double rint(x)
+ double x;
+#endif
+{
+ int i0,j0,sx;
+ unsigned i,i1;
+ double w,t;
+ i0 = *(n0+(int*)&x);
+ sx = (i0>>31)&1;
+ i1 = *(1-n0+(int*)&x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) {
+ if(((i0&0x7fffffff)|i1)==0) return x;
+ i1 |= (i0&0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1|-i1)>>12)&0x80000;
+ *(n0+(int*)&x)=i0;
+ w = TWO52[sx]+x;
+ t = w-TWO52[sx];
+ i0 = *(n0+(int*)&t);
+ *(n0+(int*)&t) = (i0&0x7fffffff)|(sx<<31);
+ return t;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ i>>=1;
+ if(((i0&i)|i1)!=0) {
+ if(j0==19) i1 = 0x40000000; else
+ i0 = (i0&(~i))|((0x20000)>>j0);
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ i>>=1;
+ if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+ }
+ *(n0+(int*)&x) = i0;
+ *(1-n0+(int*)&x) = i1;
+ w = TWO52[sx]+x;
+ return w-TWO52[sx];
+}
diff --git a/lib/msun/src/s_scalbn.c b/lib/msun/src/s_scalbn.c
new file mode 100644
index 000000000000..01fdceaf45d7
--- /dev/null
+++ b/lib/msun/src/s_scalbn.c
@@ -0,0 +1,73 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_scalbn.c,v 1.1.1.1 1994/05/06 00:20:07 gclarkii Exp $";
+#endif
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include "math.h"
+#include <machine/endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define n0 1
+#else
+#define n0 0
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge = 1.0e+300,
+tiny = 1.0e-300;
+
+#ifdef __STDC__
+ double scalbn (double x, int n)
+#else
+ double scalbn (x,n)
+ double x; int n;
+#endif
+{
+ int k,hx,lx;
+ hx = *(n0+(int*)&x);
+ lx = *(1-n0+(int*)&x);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ hx = *(n0+(int*)&x);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {*(n0+(int*)&x) = (hx&0x800fffff)|(k<<20); return x;}
+ if (k <= -54)
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*copysign(huge,x); /*overflow*/
+ else return tiny*copysign(tiny,x); /*underflow*/
+ k += 54; /* subnormal result */
+ *(n0+(int*)&x) = (hx&0x800fffff)|(k<<20);
+ return x*twom54;
+}
diff --git a/lib/msun/src/s_signgam.c b/lib/msun/src/s_signgam.c
new file mode 100644
index 000000000000..44ca79bc6da7
--- /dev/null
+++ b/lib/msun/src/s_signgam.c
@@ -0,0 +1,2 @@
+#include "math.h"
+int signgam = 0;
diff --git a/lib/msun/src/s_significand.c b/lib/msun/src/s_significand.c
new file mode 100644
index 000000000000..03bddfef1e39
--- /dev/null
+++ b/lib/msun/src/s_significand.c
@@ -0,0 +1,33 @@
+/* @(#)s_significand.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_significand.c,v 1.1.1.1 1994/05/06 00:20:08 gclarkii Exp $";
+#endif
+
+/*
+ * significand(x) computes just
+ * scalb(x, (double) -ilogb(x)),
+ * for exercising the fraction-part(F) IEEE 754-1985 test vector.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double significand(double x)
+#else
+ double significand(x)
+ double x;
+#endif
+{
+ return __ieee754_scalb(x,(double) -ilogb(x));
+}
diff --git a/lib/msun/src/s_sin.c b/lib/msun/src/s_sin.c
new file mode 100644
index 000000000000..7423fe2eb34a
--- /dev/null
+++ b/lib/msun/src/s_sin.c
@@ -0,0 +1,87 @@
+/* @(#)s_sin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_sin.c,v 1.1.1.1 1994/05/06 00:20:07 gclarkii Exp $";
+#endif
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cose function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one=1.0;
+#else
+static double one=1.0;
+#endif
+
+#ifdef __STDC__
+ double sin(double x)
+#else
+ double sin(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sin(y[0],y[1],1);
+ case 1: return __kernel_cos(y[0],y[1]);
+ case 2: return -__kernel_sin(y[0],y[1],1);
+ default:
+ return -__kernel_cos(y[0],y[1]);
+ }
+ }
+}
diff --git a/lib/msun/src/s_tan.c b/lib/msun/src/s_tan.c
new file mode 100644
index 000000000000..945ca5990a53
--- /dev/null
+++ b/lib/msun/src/s_tan.c
@@ -0,0 +1,81 @@
+/* @(#)s_tan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_tan.c,v 1.1.1.1 1994/05/06 00:20:08 gclarkii Exp $";
+#endif
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ * __kernel_tan ... tangent function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one=1.0;
+#else
+static double one=1.0;
+#endif
+
+#ifdef __STDC__
+ double tan(double x)
+#else
+ double tan(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x; /* NaN */
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
+ -1 -- n odd */
+ }
+}
diff --git a/lib/msun/src/s_tanh.c b/lib/msun/src/s_tanh.c
new file mode 100644
index 000000000000..baa9a9000bf7
--- /dev/null
+++ b/lib/msun/src/s_tanh.c
@@ -0,0 +1,85 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: s_tanh.c,v 1.1.1.1 1994/05/06 00:20:08 gclarkii Exp $";
+#endif
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ * x -x
+ * e - e
+ * 0. tanh(x) is defined to be -----------
+ * x -x
+ * e + e
+ * 1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ * 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x)
+ * -t
+ * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x)
+ * t + 2
+ * 2
+ * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t=expm1(2x)
+ * t + 2
+ * 22.0 < x <= INF : tanh(x) := 1.
+ *
+ * Special cases:
+ * tanh(NaN) is NaN;
+ * only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+#else
+static double one=1.0, two=2.0, tiny = 1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double tanh(double x)
+#else
+ double tanh(x)
+ double x;
+#endif
+{
+ double t,z;
+ int jx,ix;
+
+ /* High word of |x|. */
+ jx = *( (((*(int*)&one)>>29)^1) + (int*)&x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3c800000) /* |x|<2**-55 */
+ return x*(one+x); /* tanh(small) = small */
+ if (ix>=0x3ff00000) { /* |x|>=1 */
+ t = expm1(two*fabs(x));
+ z = one - two/(t+two);
+ } else {
+ t = expm1(-two*fabs(x));
+ z= -t/(t+two);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = one - tiny; /* raised inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
diff --git a/lib/msun/src/w_acos.c b/lib/msun/src/w_acos.c
new file mode 100644
index 000000000000..1afe4d14923a
--- /dev/null
+++ b/lib/msun/src/w_acos.c
@@ -0,0 +1,42 @@
+/* @(#)w_acos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_acos.c,v 1.1.1.1 1994/05/06 00:20:09 gclarkii Exp $";
+#endif
+
+/*
+ * wrap_acos(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double acos(double x) /* wrapper acos */
+#else
+ double acos(x) /* wrapper acos */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acos(x);
+#else
+ double z;
+ z = __ieee754_acos(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>1.0) {
+ return __kernel_standard(x,x,1); /* acos(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_acosh.c b/lib/msun/src/w_acosh.c
new file mode 100644
index 000000000000..17314d31d620
--- /dev/null
+++ b/lib/msun/src/w_acosh.c
@@ -0,0 +1,41 @@
+/* @(#)w_acosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_acosh.c,v 1.1.1.1 1994/05/06 00:20:09 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper acosh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double acosh(double x) /* wrapper acosh */
+#else
+ double acosh(x) /* wrapper acosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acosh(x);
+#else
+ double z;
+ z = __ieee754_acosh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<1.0) {
+ return __kernel_standard(x,x,29); /* acosh(x<1) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_asin.c b/lib/msun/src/w_asin.c
new file mode 100644
index 000000000000..577119d941e8
--- /dev/null
+++ b/lib/msun/src/w_asin.c
@@ -0,0 +1,43 @@
+/* @(#)w_asin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_asin.c,v 1.1.1.1 1994/05/06 00:20:09 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper asin(x)
+ */
+
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double asin(double x) /* wrapper asin */
+#else
+ double asin(x) /* wrapper asin */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_asin(x);
+#else
+ double z;
+ z = __ieee754_asin(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>1.0) {
+ return __kernel_standard(x,x,2); /* asin(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_atan2.c b/lib/msun/src/w_atan2.c
new file mode 100644
index 000000000000..b1660c81da35
--- /dev/null
+++ b/lib/msun/src/w_atan2.c
@@ -0,0 +1,42 @@
+/* @(#)w_atan2.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_atan2.c,v 1.1.1.1 1994/05/06 00:20:09 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper atan2(y,x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double atan2(double y, double x) /* wrapper atan2 */
+#else
+ double atan2(y,x) /* wrapper atan2 */
+ double y,x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atan2(y,x);
+#else
+ double z;
+ z = __ieee754_atan2(y,x);
+ if(_LIB_VERSION == _IEEE_||isnan(x)||isnan(y)) return z;
+ if(x==0.0&&y==0.0) {
+ return __kernel_standard(y,x,3); /* atan2(+-0,+-0) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_atanh.c b/lib/msun/src/w_atanh.c
new file mode 100644
index 000000000000..fb6b6735f5f0
--- /dev/null
+++ b/lib/msun/src/w_atanh.c
@@ -0,0 +1,46 @@
+/* @(#)w_atanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_atanh.c,v 1.1.1.1 1994/05/06 00:20:10 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper atanh(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double atanh(double x) /* wrapper atanh */
+#else
+ double atanh(x) /* wrapper atanh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atanh(x);
+#else
+ double z,y;
+ z = __ieee754_atanh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ y = fabs(x);
+ if(y>=1.0) {
+ if(y>1.0)
+ return __kernel_standard(x,x,30); /* atanh(|x|>1) */
+ else
+ return __kernel_standard(x,x,31); /* atanh(|x|==1) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_cabs.c b/lib/msun/src/w_cabs.c
new file mode 100644
index 000000000000..4c94adec0f4d
--- /dev/null
+++ b/lib/msun/src/w_cabs.c
@@ -0,0 +1,27 @@
+ /*
+ * cabs() wrapper for hypot().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#include "math.h"
+
+struct complex {
+ double x;
+ double y;
+};
+
+double
+cabs(z)
+ struct complex z;
+{
+ return hypot(z.x, z.y);
+}
+
+double
+z_abs(z)
+ struct complex *z;
+{
+ return hypot(z->x, z->y);
+}
diff --git a/lib/msun/src/w_cosh.c b/lib/msun/src/w_cosh.c
new file mode 100644
index 000000000000..3e952f04f2d7
--- /dev/null
+++ b/lib/msun/src/w_cosh.c
@@ -0,0 +1,41 @@
+/* @(#)w_cosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_cosh.c,v 1.1.1.1 1994/05/06 00:20:09 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper cosh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double cosh(double x) /* wrapper cosh */
+#else
+ double cosh(x) /* wrapper cosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_cosh(x);
+#else
+ double z;
+ z = __ieee754_cosh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>7.10475860073943863426e+02) {
+ return __kernel_standard(x,x,5); /* cosh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_drem.c b/lib/msun/src/w_drem.c
new file mode 100644
index 000000000000..2a9a5a526a08
--- /dev/null
+++ b/lib/msun/src/w_drem.c
@@ -0,0 +1,15 @@
+/*
+ * drem() wrapper for remainder().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#include "math.h"
+
+double
+drem(x, y)
+ double x, y;
+{
+ return remainder(x, y);
+}
diff --git a/lib/msun/src/w_exp.c b/lib/msun/src/w_exp.c
new file mode 100644
index 000000000000..5ca967c165f7
--- /dev/null
+++ b/lib/msun/src/w_exp.c
@@ -0,0 +1,52 @@
+/* @(#)w_exp.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_exp.c,v 1.1.1.1 1994/05/06 00:20:10 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper exp(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */
+
+#ifdef __STDC__
+ double exp(double x) /* wrapper exp */
+#else
+ double exp(x) /* wrapper exp */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_exp(x);
+#else
+ double z;
+ z = __ieee754_exp(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(finite(x)) {
+ if(x>o_threshold)
+ return __kernel_standard(x,x,6); /* exp overflow */
+ else if(x<u_threshold)
+ return __kernel_standard(x,x,7); /* exp underflow */
+ }
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_fmod.c b/lib/msun/src/w_fmod.c
new file mode 100644
index 000000000000..01e57174aab5
--- /dev/null
+++ b/lib/msun/src/w_fmod.c
@@ -0,0 +1,42 @@
+/* @(#)w_fmod.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_fmod.c,v 1.1.1.1 1994/05/06 00:20:10 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper fmod(x,y)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double fmod(double x, double y) /* wrapper fmod */
+#else
+ double fmod(x,y) /* wrapper fmod */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_fmod(x,y);
+#else
+ double z;
+ z = __ieee754_fmod(x,y);
+ if(_LIB_VERSION == _IEEE_ ||isnan(y)||isnan(x)) return z;
+ if(y==0.0) {
+ return __kernel_standard(x,y,27); /* fmod(x,0) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_gamma.c b/lib/msun/src/w_gamma.c
new file mode 100644
index 000000000000..e74a5c3e4b3a
--- /dev/null
+++ b/lib/msun/src/w_gamma.c
@@ -0,0 +1,48 @@
+/* @(#)w_gamma.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_gamma.c,v 1.1.1.1 1994/05/06 00:20:11 gclarkii Exp $";
+#endif
+
+/* double gamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call gamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double gamma(double x)
+#else
+ double gamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/lib/msun/src/w_gamma_r.c b/lib/msun/src/w_gamma_r.c
new file mode 100644
index 000000000000..b7b91f9bead6
--- /dev/null
+++ b/lib/msun/src/w_gamma_r.c
@@ -0,0 +1,45 @@
+/* @(#)w_gamma_r.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_gamma_r.c,v 1.1.1.1 1994/05/06 00:20:10 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper double gamma_r(double x, int *signgamp)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double gamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double gamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/lib/msun/src/w_hypot.c b/lib/msun/src/w_hypot.c
new file mode 100644
index 000000000000..33148a58d4a3
--- /dev/null
+++ b/lib/msun/src/w_hypot.c
@@ -0,0 +1,42 @@
+/* @(#)w_hypot.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_hypot.c,v 1.1.1.1 1994/05/06 00:20:11 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper hypot(x,y)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double hypot(double x, double y)/* wrapper hypot */
+#else
+ double hypot(x,y) /* wrapper hypot */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_hypot(x,y);
+#else
+ double z;
+ z = __ieee754_hypot(x,y);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if((!finite(z))&&finite(x)&&finite(y))
+ return __kernel_standard(x,y,4); /* hypot overflow */
+ else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_j0.c b/lib/msun/src/w_j0.c
new file mode 100644
index 000000000000..11c6eb38f74a
--- /dev/null
+++ b/lib/msun/src/w_j0.c
@@ -0,0 +1,68 @@
+/* @(#)w_j0.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_j0.c,v 1.1.1.1 1994/05/06 00:20:11 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper j0(double x), y0(double x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double j0(double x) /* wrapper j0 */
+#else
+ double j0(x) /* wrapper j0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j0(x);
+#else
+ double z = __ieee754_j0(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard(x,x,34); /* j0(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y0(double x) /* wrapper y0 */
+#else
+ double y0(x) /* wrapper y0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y0(x);
+#else
+ double z;
+ z = __ieee754_y0(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,8);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,9);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,35); /* y0(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_j1.c b/lib/msun/src/w_j1.c
new file mode 100644
index 000000000000..c06071df30f0
--- /dev/null
+++ b/lib/msun/src/w_j1.c
@@ -0,0 +1,69 @@
+/* @(#)w_j1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_j1.c,v 1.1.1.1 1994/05/06 00:20:12 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper of j1,y1
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double j1(double x) /* wrapper j1 */
+#else
+ double j1(x) /* wrapper j1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j1(x);
+#else
+ double z;
+ z = __ieee754_j1(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard(x,x,36); /* j1(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y1(double x) /* wrapper y1 */
+#else
+ double y1(x) /* wrapper y1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y1(x);
+#else
+ double z;
+ z = __ieee754_y1(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,10);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,11);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,37); /* y1(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_jn.c b/lib/msun/src/w_jn.c
new file mode 100644
index 000000000000..1793c0d82362
--- /dev/null
+++ b/lib/msun/src/w_jn.c
@@ -0,0 +1,91 @@
+/* @(#)w_jn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_jn.c,v 1.1.1.1 1994/05/06 00:20:11 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper jn(int n, double x), yn(int n, double x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double jn(int n, double x) /* wrapper jn */
+#else
+ double jn(n,x) /* wrapper jn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_jn(n,x);
+#else
+ double z;
+ z = __ieee754_jn(n,x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard((double)n,x,38); /* jn(|x|>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double yn(int n, double x) /* wrapper yn */
+#else
+ double yn(n,x) /* wrapper yn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_yn(n,x);
+#else
+ double z;
+ z = __ieee754_yn(n,x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard((double)n,x,12);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard((double)n,x,13);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard((double)n,x,39); /* yn(x>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_lgamma.c b/lib/msun/src/w_lgamma.c
new file mode 100644
index 000000000000..26c125f88a0c
--- /dev/null
+++ b/lib/msun/src/w_lgamma.c
@@ -0,0 +1,48 @@
+/* @(#)w_lgamma.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_lgamma.c,v 1.1.1.1 1994/05/06 00:20:12 gclarkii Exp $";
+#endif
+
+/* double lgamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double lgamma(double x)
+#else
+ double lgamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/lib/msun/src/w_lgamma_r.c b/lib/msun/src/w_lgamma_r.c
new file mode 100644
index 000000000000..b62697414d19
--- /dev/null
+++ b/lib/msun/src/w_lgamma_r.c
@@ -0,0 +1,45 @@
+/* @(#)w_lgamma_r.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_lgamma_r.c,v 1.1.1.1 1994/05/06 00:20:12 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper double lgamma_r(double x, int *signgamp)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double lgamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double lgamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/lib/msun/src/w_log.c b/lib/msun/src/w_log.c
new file mode 100644
index 000000000000..f1d9605dd6a7
--- /dev/null
+++ b/lib/msun/src/w_log.c
@@ -0,0 +1,42 @@
+/* @(#)w_log.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_log.c,v 1.1.1.1 1994/05/06 00:20:13 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper log(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double log(double x) /* wrapper log */
+#else
+ double log(x) /* wrapper log */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log(x);
+#else
+ double z;
+ z = __ieee754_log(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) || x > 0.0) return z;
+ if(x==0.0)
+ return __kernel_standard(x,x,16); /* log(0) */
+ else
+ return __kernel_standard(x,x,17); /* log(x<0) */
+#endif
+}
diff --git a/lib/msun/src/w_log10.c b/lib/msun/src/w_log10.c
new file mode 100644
index 000000000000..f092327d87e0
--- /dev/null
+++ b/lib/msun/src/w_log10.c
@@ -0,0 +1,45 @@
+/* @(#)w_log10.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_log10.c,v 1.1.1.1 1994/05/06 00:20:12 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper log10(X)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double log10(double x) /* wrapper log10 */
+#else
+ double log10(x) /* wrapper log10 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log10(x);
+#else
+ double z;
+ z = __ieee754_log10(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<=0.0) {
+ if(x==0.0)
+ return __kernel_standard(x,x,18); /* log10(0) */
+ else
+ return __kernel_standard(x,x,19); /* log10(x<0) */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_pow.c b/lib/msun/src/w_pow.c
new file mode 100644
index 000000000000..0f89b4bf3fbe
--- /dev/null
+++ b/lib/msun/src/w_pow.c
@@ -0,0 +1,62 @@
+/* @(#)w_pow.c 5.2 93/10/01 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_pow.c,v 1.1.1.1 1994/05/06 00:20:13 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper pow(x,y) return x**y
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double pow(double x, double y) /* wrapper pow */
+#else
+ double pow(x,y) /* wrapper pow */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_pow(x,y);
+#else
+ double z;
+ z=__ieee754_pow(x,y);
+ if(_LIB_VERSION == _IEEE_|| isnan(y)) return z;
+ if(isnan(x)) {
+ if(y==0.0)
+ return __kernel_standard(x,y,42); /* pow(NaN,0.0) */
+ else
+ return z;
+ }
+ if(x==0.0){
+ if(y==0.0)
+ return __kernel_standard(x,y,20); /* pow(0.0,0.0) */
+ if(finite(y)&&y<0.0)
+ return __kernel_standard(x,y,23); /* pow(0.0,negative) */
+ return z;
+ }
+ if(!finite(z)) {
+ if(finite(x)&&finite(y)) {
+ if(isnan(z))
+ return __kernel_standard(x,y,24); /* pow neg**non-int */
+ else
+ return __kernel_standard(x,y,21); /* pow overflow */
+ }
+ }
+ if(z==0.0&&finite(x)&&finite(y))
+ return __kernel_standard(x,y,22); /* pow underflow */
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_remainder.c b/lib/msun/src/w_remainder.c
new file mode 100644
index 000000000000..b3490ef0fe1a
--- /dev/null
+++ b/lib/msun/src/w_remainder.c
@@ -0,0 +1,41 @@
+/* @(#)w_remainder.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_remainder.c,v 1.1.1.1 1994/05/06 00:20:13 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper remainder(x,p)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double remainder(double x, double y) /* wrapper remainder */
+#else
+ double remainder(x,y) /* wrapper remainder */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_remainder(x,y);
+#else
+ double z;
+ z = __ieee754_remainder(x,y);
+ if(_LIB_VERSION == _IEEE_ || isnan(y)) return z;
+ if(y==0.0)
+ return __kernel_standard(x,y,28); /* remainder(x,0) */
+ else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_scalb.c b/lib/msun/src/w_scalb.c
new file mode 100644
index 000000000000..590347faf33f
--- /dev/null
+++ b/lib/msun/src/w_scalb.c
@@ -0,0 +1,59 @@
+/* @(#)w_scalb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_scalb.c,v 1.1.1.1 1994/05/06 00:20:14 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper scalb(double x, double fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "math.h"
+
+#include <errno.h>
+
+#ifdef __STDC__
+#ifdef _SCALB_INT
+ double scalb(double x, int fn) /* wrapper scalb */
+#else
+ double scalb(double x, double fn) /* wrapper scalb */
+#endif
+#else
+ double scalb(x,fn) /* wrapper scalb */
+#ifdef _SCALB_INT
+ double x; int fn;
+#else
+ double x,fn;
+#endif
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_scalb(x,fn);
+#else
+ double z;
+ z = __ieee754_scalb(x,fn);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!(finite(z)||isnan(z))&&finite(x)) {
+ return __kernel_standard(x,(double)fn,32); /* scalb overflow */
+ }
+ if(z==0.0&&z!=x) {
+ return __kernel_standard(x,(double)fn,33); /* scalb underflow */
+ }
+#ifndef _SCALB_INT
+ if(!finite(fn)) errno = ERANGE;
+#endif
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_sinh.c b/lib/msun/src/w_sinh.c
new file mode 100644
index 000000000000..7408ef856321
--- /dev/null
+++ b/lib/msun/src/w_sinh.c
@@ -0,0 +1,41 @@
+/* @(#)w_sinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_sinh.c,v 1.1.1.1 1994/05/06 00:20:13 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper sinh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double sinh(double x) /* wrapper sinh */
+#else
+ double sinh(x) /* wrapper sinh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sinh(x);
+#else
+ double z;
+ z = __ieee754_sinh(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!finite(z)&&finite(x)) {
+ return __kernel_standard(x,x,25); /* sinh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/lib/msun/src/w_sqrt.c b/lib/msun/src/w_sqrt.c
new file mode 100644
index 000000000000..b0282bc028f4
--- /dev/null
+++ b/lib/msun/src/w_sqrt.c
@@ -0,0 +1,41 @@
+/* @(#)w_sqrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: w_sqrt.c,v 1.1.1.1 1994/05/06 00:20:14 gclarkii Exp $";
+#endif
+
+/*
+ * wrapper sqrt(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double sqrt(double x) /* wrapper sqrt */
+#else
+ double sqrt(x) /* wrapper sqrt */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sqrt(x);
+#else
+ double z;
+ z = __ieee754_sqrt(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<0.0) {
+ return __kernel_standard(x,x,26); /* sqrt(negative) */
+ } else
+ return z;
+#endif
+}
diff --git a/libexec/Makefile b/libexec/Makefile
index ac0119481fc2..cdbb7dcc6e9d 100644
--- a/libexec/Makefile
+++ b/libexec/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.7 1994/01/25 22:51:39 martin Exp $
+# $Id: Makefile,v 1.8 1994/06/01 15:37:58 paul Exp $
# From: @(#)Makefile 5.7 (Berkeley) 4/1/91
#
SUBDIR= atrun bugfiler bootpd comsat elvispreserve fingerd ftpd getNAME \
getty mail.local makekey pppd rexecd rlogind rpc.rstatd \
- rpc.rusersd rpc.rwalld rshd talkd telnetd tftpd uucpd
+ rpc.rusersd rpc.rwalld rshd talkd telnetd tftpd uucpd xtend
# kpasswdd not ported, it is old kerberosIV
diff --git a/libexec/bootpd/bootpd.8 b/libexec/bootpd/bootpd.8
index bf0c69a62beb..3fad3f28007d 100644
--- a/libexec/bootpd/bootpd.8
+++ b/libexec/bootpd/bootpd.8
@@ -1,6 +1,6 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.8,v 1.1.2.1 1994/05/01 16:06:34 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.8,v 1.1 1994/01/25 22:53:33 martin Exp $
.\"
.TH BOOTPD 8 "November 11, 1991" "Carnegie Mellon University"
.UC 6
diff --git a/libexec/bootpd/bootptab.5 b/libexec/bootpd/bootptab.5
index 874ed48bad56..10bf21ba9502 100644
--- a/libexec/bootpd/bootptab.5
+++ b/libexec/bootpd/bootptab.5
@@ -1,6 +1,6 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootptab.5,v 1.1.2.1 1994/05/01 16:06:36 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootptab.5,v 1.1 1994/01/25 22:53:43 martin Exp $
.\"
.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
.UC 6
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index fe7ffd1a2c09..53cef2613b24 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -2,16 +2,19 @@
PROG= ftpd
-CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp -DSETPROCTITLE
-SRCS= ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c
+CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp \
+ -DSETPROCTITLE -DSKEY
+SRCS= ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c skey-stuff.c
MAN8= ftpd.8
CLEANFILES+=ftpcmd.c y.tab.h
.PATH: ${.CURDIR}/../../usr.bin/ftp
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
+
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
.endif
-
.include <bsd.prog.mk>
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 2638e8dd8b71..701d2a29a839 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -144,6 +144,11 @@ char *LastArgv = NULL; /* end of argv */
char proctitle[BUFSIZ]; /* initial part of title */
#endif /* SETPROCTITLE */
+#ifdef SKEY
+int pwok = 0;
+char *skey_challenge();
+char *skey_crypt();
+#endif
main(argc, argv, envp)
int argc;
char *argv[];
@@ -151,6 +156,9 @@ main(argc, argv, envp)
{
int addrlen, on = 1, tos;
char *cp;
+#ifdef SKEY
+ char addr_string[20]; /* XXX */
+#endif
/*
* LOG_NDELAY sets up the logging connection immediately,
@@ -162,6 +170,10 @@ main(argc, argv, envp)
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
exit(1);
}
+#ifdef SKEY
+ strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
+ pwok = authfile(addr_string);
+#endif
addrlen = sizeof (ctrl_addr);
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
@@ -384,7 +396,11 @@ user(name)
return;
}
}
+#ifdef SKEY
+ reply(331, "%s", skey_challenge(name, pw, pwok));
+#else
reply(331, "Password required for %s.", name);
+#endif
askpasswd = 1;
/*
* Delay before reading passwd after first failed
@@ -448,7 +464,11 @@ pass(passwd)
salt = "xx";
else
salt = pw->pw_passwd;
+#ifdef SKEY
+ xpasswd = skey_crypt(passwd, salt, pw, pwok);
+#else
xpasswd = crypt(passwd, salt);
+#endif
/* The strcmp does not catch null passwords! */
if (pw == NULL || *pw->pw_passwd == '\0' ||
strcmp(xpasswd, pw->pw_passwd)) {
diff --git a/libexec/ftpd/skey-stuff.c b/libexec/ftpd/skey-stuff.c
new file mode 100644
index 000000000000..fdec650bcef0
--- /dev/null
+++ b/libexec/ftpd/skey-stuff.c
@@ -0,0 +1,23 @@
+/* Author: Wietse Venema, Eindhoven University of Technology. */
+
+#include <stdio.h>
+#include <pwd.h>
+
+#include <skey.h>
+
+/* skey_challenge - additional password prompt stuff */
+
+char *skey_challenge(name, pwd, pwok)
+char *name;
+struct passwd *pwd;
+int pwok;
+{
+ static char buf[128];
+ struct skey skey;
+
+ /* Display s/key challenge where appropriate. */
+
+ if (pwd == 0 || skeychallenge(&skey, pwd->pw_name, buf) != 0)
+ sprintf(buf, "Password required for %s.", name);
+ return (buf);
+}
diff --git a/libexec/getty/gettytab.h b/libexec/getty/gettytab.h
index 33f797a4ec5c..6f393ce3b2e6 100644
--- a/libexec/getty/gettytab.h
+++ b/libexec/getty/gettytab.h
@@ -113,9 +113,9 @@ struct gettyflags {
#define EP gettyflags[2].value
#define EPset gettyflags[2].set
#define OP gettyflags[3].value
-#define OPset gettyflags[2].set
+#define OPset gettyflags[3].set
#define AP gettyflags[4].value
-#define APset gettyflags[2].set
+#define APset gettyflags[4].set
#define EC gettyflags[5].value
#define CO gettyflags[6].value
#define CB gettyflags[7].value
diff --git a/libexec/getty/main.c b/libexec/getty/main.c
index 18b35b8c58be..7c11279bc61e 100644
--- a/libexec/getty/main.c
+++ b/libexec/getty/main.c
@@ -143,9 +143,8 @@ main(argc, argv)
int repcnt = 0;
signal(SIGINT, SIG_IGN);
-/*
signal(SIGQUIT, SIG_DFL);
-*/
+
openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
gethostname(hostname, sizeof(hostname));
if (hostname[0] == '\0')
@@ -168,10 +167,6 @@ main(argc, argv)
chown(ttyn, 0, 0);
chmod(ttyn, 0600);
revoke(ttyn);
- /*
- * Delay the open so DTR stays down long enough to be detected.
- */
- sleep(2);
while ((i = open(ttyn, O_RDWR)) == -1) {
if (repcnt % 10 == 0) {
syslog(LOG_ERR, "%s: %m", ttyn);
@@ -242,9 +237,9 @@ main(argc, argv)
if (getname()) {
register int i;
- oflush();
alarm(0);
signal(SIGALRM, SIG_DFL);
+ oflush();
if (name[0] == '-') {
puts("user names may not start with '-'.");
continue;
@@ -253,7 +248,6 @@ main(argc, argv)
continue;
set_tmode(2);
ioctl(0, TIOCSLTC, &ltc);
- signal(SIGINT, SIG_DFL);
for (i = 0; environ[i] != (char *)0; i++)
env[i] = environ[i];
makeenv(&env[i]);
@@ -262,9 +256,9 @@ main(argc, argv)
syslog(LOG_ERR, "%s: %m", LO);
exit(1);
}
+ signal(SIGINT, SIG_IGN);
alarm(0);
signal(SIGALRM, SIG_DFL);
- signal(SIGINT, SIG_IGN);
if (NX && *NX)
tname = NX;
}
diff --git a/libexec/pppd/Makefile b/libexec/pppd/Makefile
index eb2c0066c78c..196adb0b2d22 100644
--- a/libexec/pppd/Makefile
+++ b/libexec/pppd/Makefile
@@ -1,23 +1,25 @@
-#
-# $Id: Makefile,v 1.2 1993/10/14 11:18:55 rgrimes Exp $
-#
-PROG= pppd
-MAN8= pppd.8
-SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c logwtmp.c chap.c md5.c
-MD5SRCS = md5driver.c
+# $Id: Makefile,v 1.3 1994/03/30 09:31:19 jkh Exp $
DEBUG_FLAGS = -DDEBUGFSM -DDEBUGLCP -DDEBUGIPCP -DDEBUGUPAP -DDEBUGCHAP \
-DDEBUGMAIN
+CFLAGS+= ${DEBUG_FLAGS}
+
+PROG= pppd
+SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c \
+ auth.c options.c sys-bsd.c
+MAN8= pppd.8
+BINMODE=4555
+BINGRP= daemon
+BINOWN= root
-CFLAGS= -DKVMLIB -DPPP ${DEBUG_FLAGS}
+.if exists(/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
DPADD+= ${LIBUTIL}
LDADD+= -lutil
-BINOWN= root
-BINGRP= daemon
-BINMODE= 4555
-
md5driver: md5.h md5.o md5driver.o
$(CC) $(CFLAGS) -o md5driver md5driver.o md5.o
diff --git a/libexec/pppd/README b/libexec/pppd/README
new file mode 100644
index 000000000000..c393aa94a781
--- /dev/null
+++ b/libexec/pppd/README
@@ -0,0 +1,284 @@
+ pppd-2.0 alpha release notes
+ Paul Mackerras 18 Oct 1993
+
+This file details the new and changed features in pppd since version 1.3.
+Briefly:
+ - the protocol code has been updated to conform with
+ RFCs 1331, 1332 and 1334
+ - security has been improved
+ - functionality has been improved in various ways.
+
+
+NEW FEATURES
+
+* The option negotiation automaton has been updated to RFC1331. LCP
+now rejects the Quality Protocol option, since LQR is not implemented
+yet. IPCP now uses the IP-Address option, and falls back to the old
+IP-Addresses option if the IP-Address option is rejected. IPCP also
+uses the new form of the VJ-Compression option.
+
+RFC1331 also defines the "passive" option differently from earlier
+versions: "passive" now means that the automaton outputs configure-
+request packets initially, but does not close down if no answer is
+received. A valid configure-request received will restart the
+negotiation. The "silent" option has been added with the old meaning
+of "passive", i.e. the automaton will not output configure-requests
+until it receives a valid one from the peer.
+
+* Options can be taken from files as well as the command line. pppd
+reads options from the files /etc/ppp/options and $HOME/.ppprc before
+looking at the command line. An options file is parsed into a series
+of words, delimited by whitespace. Whitespace can be included in a
+word by enclosing the word in quotes ("). Backslash (\) quotes the
+following character. A hash (#) starts a comment, which continues
+until the end of the line.
+
+* On those systems, such as NetBSD, where the serial line speed is
+stored in the termios structure in bits per second (i.e. B9600 ==
+9600), it is possible to set any speed.
+
+
+AUTHENTICATION
+
+Previous versions of pppd have provided no control over which IP
+addresses the peer can use. Thus it is possible for the peer to
+impersonate another host on the local network, leading to various
+security holes. In addition, the authentication mechanisms were quite
+weak: if the peer refused to agree to authenticate, pppd would print a
+warning message but still allow the link to come up. The CHAP
+implementation also appeared to be quite broken (has anybody actually
+used it?).
+
+This new version of pppd addresses these problems. My aim has been to
+provide system administrators with sufficient access control that PPP
+access to a server machine can be provided to legitimate users without
+fear of compromising the security of the server or the network it's
+on. In part this is provided by the /etc/ppp/options file, where the
+administrator can place options to require authentication which cannot
+be disabled by users. Thus the new pppd can made setuid-root and run
+by users.
+
+As a security feature, if pppd is compiled with -DREQ_SYSOPTIONS=1 on
+the command, pppd will refuse to run unless it can read the file
+/etc/ppp/options.
+
+The options related to authentication are:
+
+ auth Require authentication from the peer. If neither
+ +chap or +pap is also given, either CHAP or PAP
+ authentication will be accepted.
+ +chap Require CHAP authentication from the peer.
+ +pap Require PAP authentication from the peer.
+ -chap Don't agree to authenticate ourselves with the peer
+ using CHAP.
+ -pap Don't agree to authenticate ourselves using PAP.
+ +ua <f> Get username and password for authenticating ourselves
+ with the peer using PAP from file <f>.
+ name <n> Use <n> as the local name for authentication.
+ usehostname Use this machine's hostname as the local name for
+ authentication.
+ remotename <n> Use <n> as the name of the peer for authentication.
+ login If the peer authenticates using PAP, check the
+ supplied username and password against the system
+ password database, and make a wtmp entry.
+ user <n> Use <n> as the username for authenticating ourselves
+ using PAP.
+
+The defaults are to agree to authenticate if requested, and to not
+require authentication from the peer. However, pppd will not agree to
+authenticate itself with a particular protocol if it has no secrets
+which could be used to do so.
+
+Authentication is based on secrets, which are selected from secrets
+files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
+Both secrets files have the same format, and both can store secrets
+for several combinations of server (authenticating peer) and client
+(peer being authenticated). Note that each end can be both a server
+and client, and that different protocols can be used in the two
+directions if desired.
+
+A secrets file is parsed into words as for a options file. A secret
+is specified by a line containing at least 3 words, in the order
+client, server, secret. Any following words on the same line are
+taken to be a list of acceptable IP addresses for that client. If
+there are only 3 words on the line, it is assumed that any IP address
+is OK; to disallow all IP addresses, use "-". If the secret starts
+with an `@', what follows is assumed to be the name of a file from
+which to read the secret. A "*" as the client or server name matches
+any name. When selecting a secret, pppd takes the best match, i.e.
+the match with the fewest wildcards.
+
+Thus a secrets file contains both secrets for use in authenticating
+other hosts, plus secrets which we use for authenticating ourselves to
+others. Which secret to use is chosen based on the names of the host
+(the `local name') and its peer (the `remote name'). The local name
+is set as follows:
+
+ if the `usehostname' option is given,
+ then the local name is the hostname of this machine
+ (with the domain appended, if given)
+
+ else if the `name' option is given,
+ then use the argument of the first `name' option seen
+
+ else if the local IP address is specified with a
+ host name (e.g. `sirius:')
+ then use that host name
+
+ else use the hostname of this machine
+ (with the domain appended, if given)
+
+When authenticating ourselves using PAP, there is also a `username'
+which is the local name by default, but can be set with the `user'
+option or the `+ua' option.
+
+The remote name is set as follows:
+
+ if the `remotename' option is given,
+ then use the argument of the last `remotename' option seen
+
+ else if the remote IP address is specified with a
+ host name (e.g. `avago:')
+ then use that host name
+
+ else the remote name is the null string "".
+
+Secrets are selected from the PAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client ==
+username specified in the PAP authenticate-request, and server ==
+local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == our username, server == remote name.
+
+When authenticating the peer with PAP, a secret of "" matches any
+password supplied by the peer. If the password doesn't match the
+secret, the password is encrypted using crypt() and checked against
+the secret again; thus secrets for authenticating the peer can be
+stored in encrypted form. If the `login' option was specified, the
+username and password are also checked against the system password
+database. Thus, the system administrator can set up the pap-secrets
+file to allow PPP access only to certain users, and to restrict the
+set of IP addresses that each user can use.
+
+Secrets are selected from the CHAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client == name
+specified in the CHAP-Response message, and server == local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == local name, and server == name specified in the
+CHAP-Challenge message.
+
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If authentication
+fails, pppd will terminated the link (by closing LCP). If IPCP
+negotiates an unacceptable IP address for the remote host, IPCP will
+be closed. IP packets cannot be sent or received until IPCP is
+successfully opened.
+
+(some examples needed here perhaps)
+
+
+ROUTING
+
+Setting the addresses on a ppp interface is sufficient to create a
+host route to the remote end of the link. Sometimes it is desirable
+to add a default route through the remote host, as in the case of a
+machine whose only connection to the Internet is through the ppp
+interface. The `defaultroute' option causes pppd to create such a
+default route when IPCP comes up, and delete it when the link is
+terminated.
+
+In some cases it is desirable to use proxy ARP, for example on a
+server machine connected to a LAN, in order to allow other hosts to
+communicate with the remote host. The `proxyarp' option causes pppd
+to look for a network interface (an interface supporting broadcast and
+ARP, which is up and not a point-to-point or loopback interface) on
+the same subnet as the remote host. If found, pppd creates a
+permanent, published ARP entry with the IP address of the remote host
+and the hardware address of the network interface found.
+
+
+OTHER NEW AND CHANGED OPTIONS
+
+ modem Use modem control lines (not fully implemented
+ yet)
+ local Don't use modem control lines
+ persist Keep reopening connection (not fully
+ implemented yet)
+
+ lcp-restart <n> Set timeout for LCP retransmissions to <n>
+ seconds (default 3 seconds)
+ lcp-max-terminate <n> Set maximum number of LCP terminate-request
+ transmissions (default 2)
+ lcp-max-configure <n> Set maximum number of LCP configure-request
+ transmissions (default 10)
+ lcp-max-failure <n> Set maximum number of LCP configure-Naks sent
+ before converting to configure-rejects
+ (default 10)
+
+ ipcp-restart <n> Set timeout for IPCP retransmissions to <n>
+ seconds (default 3 seconds)
+ ipcp-max-terminate <n> Set maximum number of IPCP
+ terminate-request transmissions (default 2)
+ ipcp-max-configure <n> Set maximum number of IPCP
+ configure-request transmissions (default 10)
+ ipcp-max-failure <n> Set maximum number of IPCP configure-Naks
+ sent before converting to configure-rejects
+ (default 10)
+
+ upap-restart <n> Set timeout for PAP retransmissions to
+ <n> seconds (default 3 seconds)
+ upap-max-authreq <n> Set maximum number of Authenticate-request
+ retransmissions (default 10)
+
+ chap-restart <n> Set timeout for CHAP retransmissions to
+ <n> seconds (default 3 seconds)
+ chap-max-challenge <n> Set maximum number of CHAP Challenge
+ retransmissions (default 10)
+ chap-interval <n> Set the interval between CHAP rechallenges
+ (default 0, meaning infinity)
+
+The -ua option no longer exists.
+
+
+SOFTWARE RESTRUCTURING
+
+Many of the source files for pppd have changed significantly from
+ppp-1.3, upon which it is based. In particular:
+
+- the macros for system-dependent operations in pppd.h have mostly
+been removed. Instead these operations are performed by procedures in
+sys-bsd.c (for BSD-4.4ish systems like NetBSD, 386BSD, etc.) or
+sys-str.c (for SunOS-based systems using STREAMS). (I got sick of
+having to recompile everything every time I wanted to change one of
+those horrible macros.)
+
+- most of the system-dependent code in main.c has also been removed to
+sys-bsd.c and sys-str.c.
+
+- the option processing code in main.c has been removed to options.c.
+
+- the authentication code in main.c has been removed to auth.c, which
+also contains substantial amounts of new code.
+
+- fsm.c has changed significantly, and lcp.c, ipcp.c, and upap.c have
+changed somewhat. chap.c has also changed significantly.
+
+
+STILL TO DO
+
+* sort out appropriate modem control and implement the persist option
+properly; add an `answer' option for auto-answering a modem.
+
+* add demand dialing.
+
+* implement link quality monitoring.
+
+* implement other network control protocols.
+
+* at the ppp network interface level: provide support for the receive
+asyncmap, plus control over VJ slot-id compression and the maximum
+number of slots.
diff --git a/libexec/pppd/args.h b/libexec/pppd/args.h
index 80f5526d2d07..a2bfdffd20b1 100644
--- a/libexec/pppd/args.h
+++ b/libexec/pppd/args.h
@@ -1,5 +1,6 @@
/*
* neat macro from ka9q to "do the right thing" with ansi prototypes
+ * $Id: args.h,v 1.2 1994/03/30 09:31:21 jkh Exp $
*/
#ifndef __ARGS
diff --git a/libexec/pppd/auth.c b/libexec/pppd/auth.c
new file mode 100644
index 000000000000..9f8d5766b9ed
--- /dev/null
+++ b/libexec/pppd/auth.c
@@ -0,0 +1,828 @@
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: auth.c,v 1.1 1994/03/30 09:38:10 jkh Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+#ifdef sparc
+#include <alloca.h>
+#ifndef __GNUC__
+/* why alloca.h doesn't define what alloca() returns is a mystery */
+/* char *alloca __ARGS((int)); */
+#endif /*__GNUC__*/
+#endif /*sparc*/
+
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char word[1];
+};
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER 1
+#define NONWILD_CLIENT 2
+
+#define ISWILD(word) (word[0] == '*' && word[1] == 0)
+
+#define FALSE 0
+#define TRUE 1
+
+extern char user[];
+extern char passwd[];
+extern char devname[];
+extern char our_name[];
+extern char remote_name[];
+extern char hostname[];
+extern int uselogin;
+extern int usehostname;
+extern int auth_required;
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[_NPPP];
+static int logged_in;
+static struct wordlist *addresses[_NPPP];
+
+/* Bits in auth_pending[] */
+#define UPAP_WITHPEER 1
+#define UPAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+/* Prototypes */
+void check_access __ARGS((FILE *, char *));
+
+static int login __ARGS((char *, char *, char **, int *));
+static void logout __ARGS((void));
+static int get_upap_passwd __ARGS((void));
+static int have_upap_secret __ARGS((void));
+static int have_chap_secret __ARGS((char *, char *));
+static int scan_authfile __ARGS((FILE *, char *, char *, char *,
+ struct wordlist **, char *));
+static void free_wordlist __ARGS((struct wordlist *));
+
+extern char *crypt __ARGS((char *, char *));
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(unit)
+ int unit;
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(unit)
+ int unit;
+{
+ if (logged_in)
+ logout();
+ if (lcp_wantoptions[unit].restart) {
+ lcp_lowerdown(unit);
+ lcp_lowerup(unit);
+ } else
+ EXIT(unit);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(unit)
+ int unit;
+{
+ int auth;
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ho = &lcp_hisoptions[unit];
+
+ if (auth_required && !(go->neg_chap || go->neg_upap)) {
+ /*
+ * We wanted the peer to authenticate himself, and he refused:
+ * tell him to go away.
+ */
+ syslog(LOG_WARNING, "peer refused to authenticate");
+ lcp_close(unit);
+ return;
+ }
+
+ auth = 0;
+ if (go->neg_chap) {
+ ChapAuthPeer(unit, our_name, go->chap_mdtype);
+ auth |= CHAP_PEER;
+ } else if (go->neg_upap) {
+ upap_authpeer(unit);
+ auth |= UPAP_PEER;
+ }
+ if (ho->neg_chap) {
+ ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
+ auth |= CHAP_WITHPEER;
+ } else if (ho->neg_upap) {
+ upap_authwithpeer(unit, user, passwd);
+ auth |= UPAP_WITHPEER;
+ }
+ auth_pending[unit] = auth;
+
+ if (!auth)
+ ipcp_open(unit);
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * Authentication failure: take the link down
+ */
+ lcp_close(unit);
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case CHAP:
+ bit = CHAP_PEER;
+ break;
+ case UPAP:
+ bit = UPAP_PEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ return;
+ }
+
+ /*
+ * If there is no more authentication still to be done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ ipcp_open(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * We've failed to authenticate ourselves to our peer.
+ * He'll probably take the link down, and there's not much
+ * we can do except wait for that.
+ */
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case CHAP:
+ bit = CHAP_WITHPEER;
+ break;
+ case UPAP:
+ bit = UPAP_WITHPEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ }
+
+ /*
+ * If there is no more authentication still being done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ ipcp_open(unit);
+}
+
+
+/*
+ * check_auth_options - called to check authentication options.
+ */
+void
+check_auth_options()
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ lcp_options *ao = &lcp_allowoptions[0];
+
+ /* Default our_name to hostname, and user to our_name */
+ if (our_name[0] == 0 || usehostname)
+ strcpy(our_name, hostname);
+ if (user[0] == 0)
+ strcpy(user, our_name);
+
+ /* If authentication is required, ask peer for CHAP or PAP. */
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ wo->neg_chap = 1;
+ wo->neg_upap = 1;
+ }
+
+ /*
+ * Check whether we have appropriate secrets to use
+ * to authenticate ourselves and/or the peer.
+ */
+ if (ao->neg_upap && passwd[0] == 0 && !get_upap_passwd())
+ ao->neg_upap = 0;
+ if (wo->neg_upap && !uselogin && !have_upap_secret())
+ wo->neg_upap = 0;
+ if (ao->neg_chap && !have_chap_secret(our_name, remote_name))
+ ao->neg_chap = 0;
+ if (wo->neg_chap && !have_chap_secret(remote_name, our_name))
+ wo->neg_chap = 0;
+
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ fprintf(stderr, "\
+pppd: peer authentication required but no authentication files accessible\n");
+ exit(1);
+ }
+
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file. If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Authentication failed.
+ * UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
+ int unit;
+ char *auser;
+ int userlen;
+ char *apasswd;
+ int passwdlen;
+ char **msg;
+ int *msglen;
+{
+ int ret;
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char passwd[256], user[256];
+ char secret[MAXWORDLEN];
+ static int attempts = 0;
+
+ /*
+ * Make copies of apasswd and auser, then null-terminate them.
+ */
+ BCOPY(apasswd, passwd, passwdlen);
+ passwd[passwdlen] = '\0';
+ BCOPY(auser, user, userlen);
+ user[userlen] = '\0';
+
+ /*
+ * Open the file of upap secrets and scan for a suitable secret
+ * for authenticating this user.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ ret = UPAP_AUTHACK;
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ if (!uselogin) {
+ syslog(LOG_ERR, "Can't open upap password file %s: %m", filename);
+ ret = UPAP_AUTHNAK;
+ }
+
+ } else {
+ check_access(f, filename);
+ if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0
+ || (secret[0] != 0 && strcmp(passwd, secret) != 0
+ && strcmp(crypt(passwd, secret), secret) != 0)) {
+ syslog(LOG_WARNING, "upap authentication failure for %s", user);
+ ret = UPAP_AUTHNAK;
+ }
+ fclose(f);
+ }
+
+ if (uselogin && ret == UPAP_AUTHACK) {
+ ret = login(user, passwd, msg, msglen);
+ if (ret == UPAP_AUTHNAK) {
+ syslog(LOG_WARNING, "upap login failure for %s", user);
+ }
+ }
+
+ if (ret == UPAP_AUTHNAK) {
+ *msg = "Login incorrect";
+ *msglen = strlen(*msg);
+ /*
+ * Frustrate passwd stealer programs.
+ * Allow 10 tries, but start backing off after 3 (stolen from login).
+ * On 10'th, drop the connection.
+ */
+ if (attempts++ >= 10) {
+ syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
+ attempts, devname, user);
+ quit();
+ }
+ if (attempts > 3)
+ sleep((u_int) (attempts - 3) * 5);
+ if (addrs != NULL)
+ free_wordlist(addrs);
+
+ } else {
+ attempts = 0; /* Reset count */
+ *msg = "Login ok";
+ *msglen = strlen(*msg);
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ return ret;
+}
+
+
+/*
+ * login - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+static int
+login(user, passwd, msg, msglen)
+ char *user;
+ char *passwd;
+ char **msg;
+ int *msglen;
+{
+ struct passwd *pw;
+ char *epasswd;
+ char *tty;
+
+ if ((pw = getpwnam(user)) == NULL) {
+ return (UPAP_AUTHNAK);
+ }
+
+ /*
+ * XXX If no passwd, let them login without one.
+ */
+ if (pw->pw_passwd == '\0') {
+ return (UPAP_AUTHACK);
+ }
+
+ epasswd = crypt(passwd, pw->pw_passwd);
+ if (strcmp(epasswd, pw->pw_passwd)) {
+ return (UPAP_AUTHNAK);
+ }
+
+ syslog(LOG_INFO, "user %s logged in", user);
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ logwtmp(tty, user, ""); /* Add wtmp login entry */
+ logged_in = TRUE;
+
+ return (UPAP_AUTHACK);
+}
+
+/*
+ * logout - Logout the user.
+ */
+static void
+logout()
+{
+ char *tty;
+
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ logwtmp(tty, "", ""); /* Wipe out wtmp logout entry */
+ logged_in = FALSE;
+}
+
+
+/*
+ * get_upap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP. Returns 1 on success, 0 if no suitable password
+ * could be found.
+ */
+static int
+get_upap_passwd()
+{
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char secret[MAXWORDLEN];
+
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+ if (scan_authfile(f, user, remote_name, secret, NULL, filename) < 0)
+ return 0;
+ strncpy(passwd, secret, MAXSECRETLEN);
+ passwd[MAXSECRETLEN-1] = 0;
+ return 1;
+}
+
+
+/*
+ * have_upap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_upap_secret()
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_UPAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ ret = scan_authfile(f, NULL, our_name, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'. Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(client, server)
+ char *client;
+ char *server;
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_CHAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ if (client[0] == 0)
+ client = NULL;
+ else if (server[0] == 0)
+ server = NULL;
+
+ ret = scan_authfile(f, client, server, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(unit, client, server, secret, secret_len, save_addrs)
+ int unit;
+ char *client;
+ char *server;
+ char *secret;
+ int *secret_len;
+{
+ FILE *f;
+ int ret, len;
+ char *filename;
+ struct wordlist *addrs;
+ char secbuf[MAXWORDLEN];
+
+ filename = _PATH_CHAPFILE;
+ addrs = NULL;
+ secbuf[0] = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ syslog(LOG_ERR, "Can't open chap secret file %s: %m", filename);
+ return 0;
+ }
+ check_access(f, filename);
+
+ ret = scan_authfile(f, client, server, secbuf, &addrs, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ if (save_addrs) {
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ len = strlen(secbuf);
+ if (len > MAXSECRETLEN) {
+ syslog(LOG_ERR, "Secret for %s on %s is too long", client, server);
+ len = MAXSECRETLEN;
+ }
+ BCOPY(secbuf, secret, len);
+ *secret_len = len;
+
+ return 1;
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address. Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(unit, addr)
+ int unit;
+ u_long addr;
+{
+ u_long a;
+ struct hostent *hp;
+ struct wordlist *addrs;
+
+ if ((addrs = addresses[unit]) == NULL)
+ return 1; /* no restriction */
+
+ for (; addrs != NULL; addrs = addrs->next) {
+ /* "-" means no addresses authorized */
+ if (strcmp(addrs->word, "-") == 0)
+ break;
+ if ((a = inet_addr(addrs->word)) == -1) {
+ if ((hp = gethostbyname(addrs->word)) == NULL) {
+ syslog(LOG_WARNING, "unknown host %s in auth. address list",
+ addrs->word);
+ continue;
+ } else
+ a = *(u_long *)hp->h_addr;
+ }
+ if (addr == a)
+ return 1;
+ }
+ return 0; /* not in list => can't have it */
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+void
+check_access(f, filename)
+ FILE *f;
+ char *filename;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(f), &sbuf) < 0) {
+ syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename);
+ } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename);
+ }
+}
+
+
+/*
+ * scan_authfile - Scan an authorization file for a secret suitable
+ * for authenticating `client' on `server'. The return value is -1
+ * if no secret is found, otherwise >= 0. The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line (i.e. address authorization
+ * info) are placed in a wordlist and returned in *addrs.
+ */
+static int
+scan_authfile(f, client, server, secret, addrs, filename)
+ FILE *f;
+ char *client;
+ char *server;
+ char *secret;
+ struct wordlist **addrs;
+ char *filename;
+{
+ int newline, xxx;
+ int got_flag, best_flag;
+ FILE *sf;
+ struct wordlist *ap, *addr_list, *addr_last;
+ char word[MAXWORDLEN];
+ char atfile[MAXWORDLEN];
+
+ if (addrs != NULL)
+ *addrs = NULL;
+ addr_list = NULL;
+ if (!getword(f, word, &newline, filename))
+ return -1; /* file is empty??? */
+ newline = 1;
+ best_flag = -1;
+ for (;;) {
+ /*
+ * Skip until we find a word at the start of a line.
+ */
+ while (!newline && getword(f, word, &newline, filename))
+ ;
+ if (!newline)
+ break; /* got to end of file */
+
+ /*
+ * Got a client - check if it's a match or a wildcard.
+ */
+ got_flag = 0;
+ if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
+ newline = 0;
+ continue;
+ }
+ if (!ISWILD(word))
+ got_flag = NONWILD_CLIENT;
+
+ /*
+ * Now get a server and check if it matches.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+ if (server != NULL && strcmp(word, server) != 0 && !ISWILD(word))
+ continue;
+ if (!ISWILD(word))
+ got_flag |= NONWILD_SERVER;
+
+ /*
+ * Got some sort of a match - see if it's better than what
+ * we have already.
+ */
+ if (got_flag <= best_flag)
+ continue;
+
+ /*
+ * Get the secret.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+
+ /*
+ * Special syntax: @filename means read secret from file.
+ */
+ if (word[0] == '@') {
+ strcpy(atfile, word+1);
+ if ((sf = fopen(atfile, "r")) == NULL) {
+ syslog(LOG_WARNING, "can't open indirect secret file %s",
+ atfile);
+ continue;
+ }
+ check_access(sf, atfile);
+ if (!getword(sf, word, &xxx, atfile)) {
+ syslog(LOG_WARNING, "no secret in indirect secret file %s",
+ atfile);
+ fclose(sf);
+ continue;
+ }
+ fclose(sf);
+ }
+ if (secret != NULL)
+ strcpy(secret, word);
+
+ best_flag = got_flag;
+
+ /*
+ * Now read address authorization info and make a wordlist.
+ */
+ if (addr_list)
+ free_wordlist(addr_list);
+ addr_list = NULL;
+ for (;;) {
+ if (!getword(f, word, &newline, filename) || newline)
+ break;
+ ap = (struct wordlist *) malloc(sizeof(struct wordlist)
+ + strlen(word));
+ if (ap == NULL)
+ novm("authorized addresses");
+ ap->next = NULL;
+ strcpy(ap->word, word);
+ if (addr_list == NULL)
+ addr_list = ap;
+ else
+ addr_last->next = ap;
+ addr_last = ap;
+ }
+ if (!newline)
+ break;
+ }
+
+ if (addrs != NULL)
+ *addrs = addr_list;
+ else if (addr_list != NULL)
+ free_wordlist(addr_list);
+
+ return best_flag;
+}
+
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(wp)
+ struct wordlist *wp;
+{
+ struct wordlist *next;
+
+ while (wp != NULL) {
+ next = wp->next;
+ free(wp);
+ wp = next;
+ }
+}
diff --git a/libexec/pppd/callout.h b/libexec/pppd/callout.h
index cb265f1ea083..65b8319fc893 100644
--- a/libexec/pppd/callout.h
+++ b/libexec/pppd/callout.h
@@ -3,6 +3,8 @@
/* to a pointer to a function of type void (generic pointer) as per */
/* ANSI C */
+/* $Id: callout.h,v 1.2 1994/03/30 09:31:22 jkh Exp $ */
+
#ifndef _ppp_callout_h
#define _ppp_callout_h
diff --git a/libexec/pppd/chap.c b/libexec/pppd/chap.c
index 6643db16c0dc..ebdc6537fb0c 100644
--- a/libexec/pppd/chap.c
+++ b/libexec/pppd/chap.c
@@ -18,6 +18,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: chap.c,v 1.3 1994/03/30 09:38:11 jkh Exp $";
+#endif
+
/*
* TODO:
*/
@@ -27,33 +31,23 @@
#include <sys/time.h>
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/socket.h>
-#include <net/if.h>
-#include <sys/stream.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
-#include "fsm.h"
-#include "lcp.h"
#include "chap.h"
-#include "upap.h"
-#include "ipcp.h"
#include "md5.h"
-chap_state chap[NPPP]; /* CHAP state; one for each unit */
+chap_state chap[_NPPP]; /* CHAP state; one for each unit */
-static void ChapTimeout __ARGS((caddr_t));
+static void ChapChallengeTimeout __ARGS((caddr_t));
+static void ChapResponseTimeout __ARGS((caddr_t));
static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveResponse __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveFailure __ARGS((chap_state *, u_char *, int, int));
-static void ChapSendStatus __ARGS((chap_state *, int, int,
- u_char *, int));
+static void ChapSendStatus __ARGS((chap_state *, int));
static void ChapSendChallenge __ARGS((chap_state *));
-static void ChapSendResponse __ARGS((chap_state *, int, u_char *, int));
-static void ChapGenChallenge __ARGS((int, u_char *));
+static void ChapSendResponse __ARGS((chap_state *));
+static void ChapGenChallenge __ARGS((chap_state *));
extern double drand48 __ARGS((void));
extern void srand48 __ARGS((long));
@@ -62,21 +56,18 @@ extern void srand48 __ARGS((long));
* ChapInit - Initialize a CHAP unit.
*/
void
- ChapInit(unit)
-int unit;
+ChapInit(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
-
- cstate->unit = unit;
- cstate->chal_str[0] = '\000';
- cstate->chal_len = 0;
- cstate->clientstate = CHAPCS_CLOSED;
- cstate->serverstate = CHAPSS_CLOSED;
- cstate->flags = 0;
- cstate->id = 0;
- cstate->timeouttime = CHAP_DEFTIMEOUT;
- cstate->retransmits = 0;
- srand48((long) time(NULL)); /* joggle random number generator */
+ chap_state *cstate = &chap[unit];
+
+ BZERO(cstate, sizeof(*cstate));
+ cstate->unit = unit;
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+ cstate->timeouttime = CHAP_DEFTIMEOUT;
+ cstate->max_transmits = CHAP_DEFTRANSMITS;
+ srand48((long) time(NULL)); /* joggle random number generator */
}
@@ -85,35 +76,29 @@ int unit;
*
*/
void
- ChapAuthWithPeer(unit)
-int unit;
+ChapAuthWithPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
{
- chap_state *cstate = &chap[unit];
-
- cstate->flags &= ~CHAPF_AWPPENDING; /* Clear pending flag */
-
- /* Protect against programming errors that compromise security */
- if (cstate->serverstate != CHAPSS_CLOSED ||
- cstate->flags & CHAPF_APPENDING) {
- CHAPDEBUG((LOG_INFO,
- "ChapAuthWithPeer: we were called already!"))
- return;
- }
-
- if (cstate->clientstate == CHAPCS_CHALLENGE_SENT || /* should we be here? */
- cstate->clientstate == CHAPCS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(cstate->flags & CHAPF_LOWERUP)) {
- cstate->flags |= CHAPF_AWPPENDING; /* Nah, Wait */
- return;
- }
- ChapSendChallenge(cstate); /* crank it up dude! */
- TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime);
- /* set-up timeout */
- cstate->clientstate = CHAPCS_CHALLENGE_SENT; /* update state */
- cstate->retransmits = 0;
+ chap_state *cstate = &chap[unit];
+
+ cstate->resp_name = our_name;
+ cstate->resp_type = digest;
+
+ if (cstate->clientstate == CHAPCS_INITIAL ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->clientstate = CHAPCS_PENDING;
+ return;
+ }
+
+ /*
+ * We get here as a result of LCP coming up.
+ * So even if CHAP was open before, we will
+ * have to re-authenticate ourselves.
+ */
+ cstate->clientstate = CHAPCS_LISTEN;
}
@@ -121,44 +106,92 @@ int unit;
* ChapAuthPeer - Authenticate our peer (start server).
*/
void
- ChapAuthPeer(unit)
-int unit;
+ChapAuthPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags &= ~CHAPF_APPENDING; /* Clear pending flag */
-
- /* Already authenticat{ed,ing}? */
- if (cstate->serverstate == CHAPSS_LISTEN ||
- cstate->serverstate == CHAPSS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(cstate->flags & CHAPF_LOWERUP)) {
- cstate->flags |= CHAPF_APPENDING; /* Wait for desired event */
- return;
- }
- cstate->serverstate = CHAPSS_LISTEN;
+ cstate->chal_name = our_name;
+ cstate->chal_type = digest;
+
+ if (cstate->serverstate == CHAPSS_INITIAL ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->serverstate = CHAPSS_PENDING;
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate); /* crank it up dude! */
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
}
/*
- * ChapTimeout - Timeout expired.
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
*/
static void
- ChapTimeout(arg)
-caddr_t arg;
+ChapChallengeTimeout(arg)
+ caddr_t arg;
{
- chap_state *cstate = (chap_state *) arg;
+ chap_state *cstate = (chap_state *) arg;
- /* if we aren't sending challenges, don't worry. then again we */
- /* probably shouldn't be here either */
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT)
- return;
-
- ChapSendChallenge(cstate); /* Send challenge */
- TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime);
- ++cstate->retransmits;
+ /* if we aren't sending challenges, don't worry. then again we */
+ /* probably shouldn't be here either */
+ if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+ cstate->serverstate != CHAPSS_RECHALLENGE)
+ return;
+
+ if (cstate->chal_transmits >= cstate->max_transmits) {
+ /* give up on peer */
+ syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, CHAP);
+ return;
+ }
+
+ ChapSendChallenge(cstate); /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->clientstate != CHAPCS_RESPONSE)
+ return;
+
+ ChapSendResponse(cstate); /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->serverstate != CHAPSS_OPEN)
+ return;
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_RECHALLENGE;
+
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
}
@@ -168,16 +201,23 @@ caddr_t arg;
* Start up if we have pending requests.
*/
void
- ChapLowerUp(unit)
-int unit;
+ChapLowerUp(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags |= CHAPF_LOWERUP;
- if (cstate->flags & CHAPF_AWPPENDING) /* were we attempting authwithpeer? */
- ChapAuthWithPeer(unit); /* Try it now */
- if (cstate->flags & CHAPF_APPENDING) /* or authpeer? */
- ChapAuthPeer(unit);
+ if (cstate->clientstate == CHAPCS_INITIAL)
+ cstate->clientstate = CHAPCS_CLOSED;
+ else if (cstate->clientstate == CHAPCS_PENDING)
+ cstate->clientstate = CHAPCS_LISTEN;
+
+ if (cstate->serverstate == CHAPSS_INITIAL)
+ cstate->serverstate = CHAPSS_CLOSED;
+ else if (cstate->serverstate == CHAPSS_PENDING) {
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+ }
}
@@ -187,20 +227,23 @@ int unit;
* Cancel all timeouts.
*/
void
- ChapLowerDown(unit)
-int unit;
+ChapLowerDown(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags &= ~CHAPF_LOWERUP;
-
- if (cstate->clientstate == CHAPCS_CHALLENGE_SENT) /* Timeout pending? */
- UNTIMEOUT(ChapTimeout, (caddr_t) cstate); /* Cancel timeout */
-
- if (cstate->serverstate == CHAPSS_OPEN) /* have we successfully authed? */
- LOGOUT(unit);
- cstate->clientstate = CHAPCS_CLOSED;
- cstate->serverstate = CHAPSS_CLOSED;
+ /* Timeout(s) pending? Cancel if so. */
+ if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+ cstate->serverstate == CHAPSS_RECHALLENGE)
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+ else if (cstate->serverstate == CHAPSS_OPEN
+ && cstate->chal_interval != 0)
+ UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
}
@@ -208,13 +251,18 @@ int unit;
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
void
- ChapProtocolReject(unit)
-int unit;
+ChapProtocolReject(unit)
+ int unit;
{
- ChapLowerDown(unit); /* shutdown chap */
-
-
-/* Note: should we bail here if chap is required? */
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->serverstate != CHAPSS_INITIAL &&
+ cstate->serverstate != CHAPSS_CLOSED)
+ auth_peer_fail(unit, CHAP);
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED)
+ auth_withpeer_fail(unit, CHAP);
+ ChapLowerDown(unit); /* shutdown chap */
}
@@ -222,311 +270,335 @@ int unit;
* ChapInput - Input CHAP packet.
*/
void
- ChapInput(unit, inpacket, packet_len)
-int unit;
-u_char *inpacket;
-int packet_len;
+ChapInput(unit, inpacket, packet_len)
+ int unit;
+ u_char *inpacket;
+ int packet_len;
{
- chap_state *cstate = &chap[unit];
- u_char *inp;
- u_char code, id;
- int len;
+ chap_state *cstate = &chap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
- /*
- * Parse header (code, id and length).
- * If packet too short, drop it.
- */
- inp = inpacket;
- if (packet_len < CHAP_HEADERLEN) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."))
- return;
- }
- GETCHAR(code, inp);
- GETCHAR(id, inp);
- GETSHORT(len, inp);
- if (len < CHAP_HEADERLEN) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."))
- return;
- }
- if (len > packet_len) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."))
- return;
- }
- len -= CHAP_HEADERLEN;
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (packet_len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
+ return;
+ }
+ if (len > packet_len) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
+ return;
+ }
+ len -= CHAP_HEADERLEN;
- /*
- * Action depends on code.
- */
- switch (code) {
- case CHAP_CHALLENGE:
- ChapReceiveChallenge(cstate, inp, id, len);
- break;
+ /*
+ * Action depends on code (as in fact it usually does :-).
+ */
+ switch (code) {
+ case CHAP_CHALLENGE:
+ ChapReceiveChallenge(cstate, inp, id, len);
+ break;
- case CHAP_RESPONSE:
- ChapReceiveResponse(cstate, inp, id, len);
- break;
+ case CHAP_RESPONSE:
+ ChapReceiveResponse(cstate, inp, id, len);
+ break;
- case CHAP_FAILURE:
- ChapReceiveFailure(cstate, inp, id, len);
- break;
-
- case CHAP_SUCCESS:
- ChapReceiveSuccess(cstate, inp, id, len);
- break;
-
- default: /* Need code reject? */
- syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
- break;
- }
-}
-
+ case CHAP_FAILURE:
+ ChapReceiveFailure(cstate, inp, id, len);
+ break;
-/*
- * ChapReceiveChallenge - Receive Challenge.
- */
-static void
- ChapReceiveChallenge(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-int id;
-int len;
-{
- u_char rchallenge_len;
- u_char *rchallenge;
- u_char secret[MAX_SECRET_LEN];
- int secret_len;
- u_char rhostname[256];
- u_char buf[256];
- MD5_CTX mdContext;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id))
- if (cstate->serverstate != CHAPSS_LISTEN) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received challenge but not in listen state"))
- return;
- }
-
- if (len < 2) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
- return;
- }
- GETCHAR(rchallenge_len, inp);
- len -= sizeof (u_char) + rchallenge_len ;
- if (len < 0) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
- return;
- }
- rchallenge = inp;
- INCPTR(rchallenge_len, inp);
-
- BCOPY(inp, rhostname, len);
- rhostname[len] = '\000';
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
- rhostname))
- GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
-
- BCOPY(rchallenge, buf, rchallenge_len); /* copy challenge into buffer */
- BCOPY(secret, buf + rchallenge_len, secret_len); /* append secret */
-
- /* generate MD based on negotiated type */
-
- switch (lcp_hisoptions[cstate->unit].chap_mdtype) {
-
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- MD5Init(&mdContext);
- MD5Update(&mdContext, buf, rchallenge_len + secret_len);
- MD5Final(&mdContext);
- ChapSendResponse(cstate, id, &mdContext.digest[0], MD5_SIGNATURE_SIZE);
- break;
-
- default:
- CHAPDEBUG((LOG_INFO, "unknown digest type %d",
- lcp_hisoptions[cstate->unit].chap_mdtype))
- }
+ case CHAP_SUCCESS:
+ ChapReceiveSuccess(cstate, inp, id, len);
+ break;
+ default: /* Need code reject? */
+ syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
+ break;
+ }
}
/*
- * ChapReceiveResponse - Receive and process response.
+ * ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void
- ChapReceiveResponse(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-int id;
-int len;
+ChapReceiveChallenge(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
{
- u_char *remmd, remmd_len;
- u_char secret[MAX_SECRET_LEN];
- int secret_len;
- u_char chal_len = cstate->chal_len;
- u_char code;
- u_char rhostname[256];
- u_char buf[256];
- MD5_CTX mdContext;
- u_char msg[256], msglen;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id))
-
-/* sanity check */
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received response but did not send a challenge"))
- return;
- }
-
- if (len < 2) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
- return;
- }
- GETCHAR(remmd_len, inp); /* get length of MD */
- len -= sizeof (u_char) + remmd_len ;
+ int rchallenge_len;
+ u_char *rchallenge;
+ int secret_len;
+ char secret[MAXSECRETLEN];
+ char rhostname[256];
+ MD5_CTX mdContext;
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
+ if (cstate->clientstate == CHAPCS_CLOSED ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
+ cstate->clientstate));
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
- if (len < 0) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
- return;
- }
+ GETCHAR(rchallenge_len, inp);
+ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+ rchallenge = inp;
+ INCPTR(rchallenge_len, inp);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
+ rhostname));
+
+ /* get secret for authenticating ourselves with the specified host */
+ if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+ secret, &secret_len, 0)) {
+ secret_len = 0; /* assume null secret if can't find one */
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
+ rhostname);
+ }
- remmd = inp; /* get pointer to MD */
- INCPTR(remmd_len, inp);
+ /* cancel response send timeout if necessary */
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
- BCOPY(inp, rhostname, len);
- rhostname[len] = '\000';
+ cstate->resp_id = id;
+ cstate->resp_transmits = 0;
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
- rhostname))
+ /* generate MD based on negotiated type */
+ switch (cstate->resp_type) {
- GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->resp_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, rchallenge, rchallenge_len);
+ MD5Final(&mdContext);
+ BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE);
+ cstate->resp_length = MD5_SIGNATURE_SIZE;
+ break;
- BCOPY(cstate->chal_str, buf, chal_len); /* copy challenge */
- /* into buffer */
- BCOPY(secret, buf + chal_len, secret_len); /* append secret */
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
+ return;
+ }
- /* generate MD based on negotiated type */
+ ChapSendResponse(cstate);
+}
- switch (lcp_gotoptions[cstate->unit].chap_mdtype) {
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- MD5Init(&mdContext);
- MD5Update(&mdContext, buf, chal_len + secret_len);
- MD5Final(&mdContext);
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char *remmd, remmd_len;
+ int secret_len, old_state;
+ int code;
+ char rhostname[256];
+ u_char buf[256];
+ MD5_CTX mdContext;
+ u_char msg[256];
+ char secret[MAXSECRETLEN];
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
+
+ if (cstate->serverstate == CHAPSS_CLOSED ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
+ cstate->serverstate));
+ return;
+ }
- /* compare local and remote MDs and send the appropriate status */
+ if (id != cstate->chal_id)
+ return; /* doesn't match ID of last challenge */
+
+ /*
+ * If we have received a duplicate or bogus Response,
+ * we have to send the same answer (Success/Failure)
+ * as we did for the first Response we saw.
+ */
+ if (cstate->serverstate == CHAPSS_OPEN) {
+ ChapSendStatus(cstate, CHAP_SUCCESS);
+ return;
+ }
+ if (cstate->serverstate == CHAPSS_BADAUTH) {
+ ChapSendStatus(cstate, CHAP_FAILURE);
+ return;
+ }
- if (bcmp (&mdContext.digest[0], remmd, MD5_SIGNATURE_SIZE))
- code = CHAP_FAILURE; /* they ain't the same */
- else
- code = CHAP_SUCCESS; /* they are the same! */
- break;
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+ GETCHAR(remmd_len, inp); /* get length of MD */
+ remmd = inp; /* get pointer to MD */
+ INCPTR(remmd_len, inp);
+
+ len -= sizeof (u_char) + remmd_len;
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
- default:
- CHAPDEBUG((LOG_INFO, "unknown digest type %d",
- lcp_gotoptions[cstate->unit].chap_mdtype))
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
+ rhostname));
+
+ /*
+ * Get secret for authenticating them with us,
+ * do the hash ourselves, and compare the result.
+ */
+ code = CHAP_FAILURE;
+ if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+ secret, &secret_len, 1)) {
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
+ rhostname);
+ } else {
+
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE)
+ break; /* it's not even the right length */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(&mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (bcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0)
+ code = CHAP_SUCCESS; /* they are the same! */
+ break;
+
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
+ }
}
- if (code == CHAP_SUCCESS)
- sprintf((char *)msg, "Welcome to %s.", hostname);
- else
- sprintf((char *)msg, "I don't like you. Go 'way.");
- msglen = strlen(msg);
- ChapSendStatus(cstate, code, id, msg, msglen);
-
- /* only crank up IPCP when either we aren't doing PAP, or if we are, */
- /* that it is in open state */
+
+ ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
- cstate->serverstate = CHAPSS_OPEN;
- if (!lcp_hisoptions[cstate->unit].neg_upap ||
- (lcp_hisoptions[cstate->unit].neg_upap &&
- upap[cstate->unit].us_serverstate == UPAPSS_OPEN ))
- ipcp_activeopen(cstate->unit); /* Start IPCP */
+ old_state = cstate->serverstate;
+ cstate->serverstate = CHAPSS_OPEN;
+ if (old_state == CHAPSS_INITIAL_CHAL) {
+ auth_peer_success(cstate->unit, CHAP);
+ }
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
+
+ } else {
+ syslog(LOG_ERR, "CHAP peer authentication failed");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, CHAP);
}
}
+
/*
* ChapReceiveSuccess - Receive Success
*/
-/* ARGSUSED */
static void
- ChapReceiveSuccess(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-u_char id;
-int len;
+ChapReceiveSuccess(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
{
- u_char msglen;
- u_char *msg;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id))
-
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: received success, but did not send a challenge."))
- return;
- }
-
- /*
- * Parse message.
- */
- if (len < sizeof (u_char)) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
- return;
- }
- GETCHAR(msglen, inp);
- len -= sizeof (u_char);
- if (len < msglen) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
- return;
- }
- msg = inp;
- PRINTMSG(msg, msglen);
-
- cstate->clientstate = CHAPCS_OPEN;
- /* only crank up IPCP when either we aren't doing PAP, or if we are, */
- /* that it is in open state */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
+
+ if (cstate->clientstate == CHAPCS_OPEN)
+ /* presumably an answer to a duplicate response */
+ return;
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
- if (!lcp_gotoptions[cstate->unit].neg_chap ||
- (lcp_gotoptions[cstate->unit].neg_chap &&
- upap[cstate->unit].us_serverstate == UPAPCS_OPEN ))
- ipcp_activeopen(cstate->unit); /* Start IPCP */
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ cstate->clientstate = CHAPCS_OPEN;
+
+ auth_withpeer_success(cstate->unit, CHAP);
}
/*
* ChapReceiveFailure - Receive failure.
*/
-/* ARGSUSED */
static void
- ChapReceiveFailure(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-u_char id;
-int len;
+ChapReceiveFailure(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
{
- u_char msglen;
- u_char *msg;
+ u_char msglen;
+ u_char *msg;
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id))
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) /* XXX */
- return;
-
- /*
- * Parse message.
- */
- if (len < sizeof (u_char)) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
- return;
- }
- GETCHAR(msglen, inp);
- len -= sizeof (u_char);
- if (len < msglen) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
- return;
- }
- msg = inp;
- PRINTMSG(msg, msglen);
-
- cstate->flags &= ~CHAPF_UPVALID; /* Clear valid flag */
- cstate->clientstate = CHAPCS_CLOSED; /* Pretend for a moment */
- ChapAuthWithPeer(cstate->unit); /* Restart */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ syslog(LOG_ERR, "CHAP authentication failed");
+ auth_withpeer_fail(cstate->unit, CHAP);
}
@@ -534,43 +606,36 @@ int len;
* ChapSendChallenge - Send an Authenticate challenge.
*/
static void
- ChapSendChallenge(cstate)
-chap_state *cstate;
+ChapSendChallenge(cstate)
+ chap_state *cstate;
{
- u_char *outp;
- u_char chal_len;
- int outlen;
-
-/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
- MAX_CHALLENGE_LENGTH */
- cstate->chal_len = (unsigned) ((drand48() *
- (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
- MIN_CHALLENGE_LENGTH);
- chal_len = cstate->chal_len;
-
- outlen = CHAP_HEADERLEN + 2 * sizeof (u_char) + chal_len + hostname_len;
- outp = outpacket_buf;
+ u_char *outp;
+ int chal_len, name_len;
+ int outlen;
- MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
-
- PUTCHAR(CHAP_CHALLENGE, outp);
- PUTCHAR(++cstate->id, outp);
- PUTSHORT(outlen, outp);
+ chal_len = cstate->chal_len;
+ name_len = strlen(cstate->chal_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+ outp = outpacket_buf;
- PUTCHAR(chal_len, outp); /* put length of challenge */
+ MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
- ChapGenChallenge(chal_len, cstate->chal_str); /* generate a challenge string */
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
- BCOPY(cstate->chal_str, outp, chal_len); /* copy it the the output buffer */
- INCPTR(chal_len, outp);
+ PUTCHAR(chal_len, outp); /* put length of challenge */
+ BCOPY(cstate->challenge, outp, chal_len);
+ INCPTR(chal_len, outp);
- BCOPY(hostname, outp, hostname_len); /* append hostname */
- INCPTR(hostname_len, outp);
+ BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->id))
- cstate->clientstate |= CHAPCS_CHALLENGE_SENT;
+ CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
+
+ TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->chal_transmits;
}
@@ -578,88 +643,99 @@ chap_state *cstate;
* ChapSendStatus - Send a status response (ack or nak).
*/
static void
- ChapSendStatus(cstate, code, id, msg, msglen)
-chap_state *cstate;
-u_char code, id;
-u_char *msg;
-int msglen;
+ChapSendStatus(cstate, code)
+ chap_state *cstate;
+ int code;
{
- u_char *outp;
- int outlen;
-
- outlen = CHAP_HEADERLEN + msglen;
- outp = outpacket_buf;
+ u_char *outp;
+ int outlen, msglen;
+ char msg[256];
- MAKEHEADER(outp, CHAP); /* paste in a header */
+ if (code == CHAP_SUCCESS)
+ sprintf(msg, "Welcome to %s.", hostname);
+ else
+ sprintf(msg, "I don't like you. Go 'way.");
+ msglen = strlen(msg);
+
+ outlen = CHAP_HEADERLEN + msglen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, CHAP); /* paste in a header */
- PUTCHAR(code, outp);
- PUTCHAR(id, outp);
- PUTSHORT(outlen, outp);
- BCOPY(msg, outp, msglen);
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ PUTCHAR(code, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+ BCOPY(msg, outp, msglen);
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, id))
+ CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
+ cstate->chal_id));
}
/*
* ChapGenChallenge is used to generate a pseudo-random challenge string of
- * a pseudo-random length between min_len and max_len and return the
- * challenge string, and the message digest of the secret appended to
- * the challenge string. the message digest type is specified by mdtype.
- *
- * It returns with the string in the caller-supplied buffer str (which
- * should be instantiated with a length of max_len + 1), and the
- * length of the generated string into chal_len.
- *
+ * a pseudo-random length between min_len and max_len. The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
*/
static void
- ChapGenChallenge(chal_len, str)
-u_char chal_len;
-u_char * str;
+ChapGenChallenge(cstate)
+ chap_state *cstate;
{
- u_char * ptr = str;
- unsigned int i;
-
- /* generate a random string */
-
- for (i = 0; i < chal_len; i++ )
- *ptr++ = (char) (drand48() * 0xff);
-
- *ptr = 0; /* null terminate it so we can printf it */
+ int chal_len;
+ u_char *ptr = cstate->challenge;
+ unsigned int i;
+
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
+ chal_len = (unsigned) ((drand48() *
+ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+ MIN_CHALLENGE_LENGTH);
+ cstate->chal_len = chal_len;
+ cstate->chal_id = ++cstate->id;
+ cstate->chal_transmits = 0;
+
+ /* generate a random string */
+ for (i = 0; i < chal_len; i++ )
+ *ptr++ = (char) (drand48() * 0xff);
}
+
/*
- * ChapSendResponse - send a response packet with the message
- * digest specified by md and md_len
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
*/
/* ARGSUSED */
static void
- ChapSendResponse(cstate, id, md, md_len)
-chap_state *cstate;
-u_char id;
-u_char *md;
-int md_len;
+ChapSendResponse(cstate)
+ chap_state *cstate;
{
u_char *outp;
- int outlen;
+ int outlen, md_len, name_len;
- outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + hostname_len;
+ md_len = cstate->resp_length;
+ name_len = strlen(cstate->resp_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
outp = outpacket_buf;
- MAKEHEADER(outp, CHAP);
- PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
- PUTCHAR(id, outp); /* copy id from challenge packet */
- PUTSHORT(outlen, outp); /* packet length */
+ MAKEHEADER(outp, CHAP);
- PUTCHAR(md_len, outp); /* length of MD */
+ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
+ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+ PUTSHORT(outlen, outp); /* packet length */
- BCOPY(md, outp, md_len); /* copy MD to buffer */
+ PUTCHAR(md_len, outp); /* length of MD */
+ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
INCPTR(md_len, outp);
- BCOPY(hostname, outp, hostname_len); /* append hostname */
- INCPTR(hostname_len, outp);
+ BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+ /* send the packet */
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); /* bomb's away! */
+ cstate->clientstate = CHAPCS_RESPONSE;
+ TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->resp_transmits;
}
#ifdef NO_DRAND48
diff --git a/libexec/pppd/chap.h b/libexec/pppd/chap.h
index 2d5c51e3485e..51d41d5b6acf 100644
--- a/libexec/pppd/chap.h
+++ b/libexec/pppd/chap.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.h,v 1.2 1994/03/30 09:31:24 jkh Exp $
*/
#ifndef __CHAP_INCLUDE__
@@ -26,77 +28,80 @@
* CHAP codes.
*/
-#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
-
-#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
-
-#define CHAP_NOCALLBACK 0 /* don't call back after successful auth */
-#define CHAP_CALLBACK 1 /* do call back */
+#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
-#define CHAP_CHALLENGE 1
-#define CHAP_RESPONSE 2
-#define CHAP_SUCCESS 3
-#define CHAP_FAILURE 4
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
/*
- * Challenge lengths
+ * Challenge lengths (for challenges we send) and other limits.
*/
+#define MIN_CHALLENGE_LENGTH 32
+#define MAX_CHALLENGE_LENGTH 64
+#define MAX_RESPONSE_LENGTH 16 /* sufficient for MD5 */
-#define MIN_CHALLENGE_LENGTH 64
-#define MAX_CHALLENGE_LENGTH 128
-
-#define MAX_SECRET_LEN 128
/*
- * Each interface is described by chap structure.
+ * Each interface is described by a chap structure.
*/
typedef struct chap_state {
- int unit; /* Interface unit number */
- u_char chal_str[MAX_CHALLENGE_LENGTH + 1]; /* challenge string */
- u_char chal_len; /* challenge length */
+ int unit; /* Interface unit number */
int clientstate; /* Client state */
int serverstate; /* Server state */
- int flags; /* Flags */
- unsigned char id; /* Current id */
- int timeouttime; /* Timeout time in milliseconds */
- int retransmits; /* Number of retransmissions */
+ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+ u_char chal_len; /* challenge length */
+ u_char chal_id; /* ID of last challenge */
+ u_char chal_type; /* hash algorithm for challenges */
+ u_char id; /* Current id */
+ char *chal_name; /* Our name to use with challenge */
+ int chal_interval; /* Time until we challenge peer again */
+ int timeouttime; /* Timeout time in seconds */
+ int max_transmits; /* Maximum # of challenge transmissions */
+ int chal_transmits; /* Number of transmissions of challenge */
+ int resp_transmits; /* Number of transmissions of response */
+ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
+ u_char resp_length; /* length of response */
+ u_char resp_id; /* ID for response messages */
+ u_char resp_type; /* hash algorithm for responses */
+ char *resp_name; /* Our name to send with response */
} chap_state;
/*
- * Client states.
+ * Client (peer) states.
*/
-#define CHAPCS_CLOSED 1 /* Connection down */
-#define CHAPCS_CHALLENGE_SENT 2 /* We've sent a challenge */
-#define CHAPCS_OPEN 3 /* We've received an Ack */
+#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN 3 /* Listening for a challenge */
+#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
+#define CHAPCS_OPEN 5 /* We've received Success */
/*
- * Server states.
+ * Server (authenticator) states.
*/
-#define CHAPSS_CLOSED 1 /* Connection down */
-#define CHAPSS_LISTEN 2 /* Listening for a challenge */
-#define CHAPSS_OPEN 3 /* We've sent an Ack */
-
-/*
- * Flags.
- */
-#define CHAPF_LOWERUP 0x01 /* The lower level is UP */
-#define CHAPF_AWPPENDING 0x02 /* Auth with peer pending */
-#define CHAPF_APPENDING 0x04 /* Auth peer pending */
-#define CHAPF_UPVALID 0x08 /* values valid */
-#define CHAPF_UPPENDING 0x10 /* values pending */
-
+#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPSS_PENDING 2 /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
+#define CHAPSS_OPEN 4 /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
+#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
/*
* Timeouts.
*/
-#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
extern chap_state chap[];
void ChapInit __ARGS((int));
-void ChapAuthWithPeer __ARGS((int));
-void ChapAuthPeer __ARGS((int));
+void ChapAuthWithPeer __ARGS((int, char *, int));
+void ChapAuthPeer __ARGS((int, char *, int));
void ChapLowerUp __ARGS((int));
void ChapLowerDown __ARGS((int));
void ChapInput __ARGS((int, u_char *, int));
diff --git a/libexec/pppd/fsm.c b/libexec/pppd/fsm.c
index 19bfb97595c3..ba8b76082d69 100644
--- a/libexec/pppd/fsm.c
+++ b/libexec/pppd/fsm.c
@@ -17,10 +17,12 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: fsm.c,v 1.3 1994/03/30 09:38:12 jkh Exp $";
+#endif
+
/*
* TODO:
- * Mechanism to exit() and/or drop DTR.
- * Hold-down on open?
* Randomize fsm id on link/init.
* Deal with variable outgoing MTU.
*/
@@ -30,27 +32,24 @@
/*#include <malloc.h>*/
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/stream.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
#include "fsm.h"
extern char *proto_name();
static void fsm_timeout __ARGS((caddr_t));
-static void fsm_rconfack __ARGS((fsm *, u_char *, int, int));
-static void fsm_rconfnak __ARGS((fsm *, u_char *, int, int));
-static void fsm_rconfrej __ARGS((fsm *, u_char *, int, int));
+static void fsm_rconfreq __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfack __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __ARGS((fsm *, int, int, u_char *, int));
static void fsm_rtermreq __ARGS((fsm *, int));
static void fsm_rtermack __ARGS((fsm *));
static void fsm_rcoderej __ARGS((fsm *, u_char *, int));
-static void fsm_rprotrej __ARGS((fsm *, u_char *, int));
-static void fsm_sconfreq __ARGS((fsm *));
+static void fsm_sconfreq __ARGS((fsm *, int));
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[_NPPP];
/*
@@ -59,226 +58,225 @@ static void fsm_sconfreq __ARGS((fsm *));
* Initialize fsm state.
*/
void
- fsm_init(f)
-fsm *f;
+fsm_init(f)
+ fsm *f;
{
- f->state = CLOSED;
+ f->state = INITIAL;
f->flags = 0;
f->id = 0; /* XXX Start with random id? */
+ f->timeouttime = DEFTIMEOUT;
+ f->maxconfreqtransmits = DEFMAXCONFREQS;
+ f->maxtermtransmits = DEFMAXTERMREQS;
+ f->maxnakloops = DEFMAXNAKLOOPS;
}
/*
- * fsm_activeopen - Actively open connection.
- *
- * Set new state, reset desired options and send requests.
+ * fsm_lowerup - The lower layer is up.
*/
void
- fsm_activeopen(f)
-fsm *f;
+fsm_lowerup(f)
+ fsm *f;
{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == REQSENT || /* Already actively open(ing)? */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == OPEN)
- return;
- if (f->state == TERMSENT || /* Closing or */
- !(f->flags & LOWERUP)) { /* lower layer down? */
- f->flags |= AOPENDING; /* Wait for desired event */
- return;
- }
- if (f->callbacks->resetci)
- (*f->callbacks->resetci)(f); /* Reset options */
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = REQSENT;
- f->retransmits = 0; /* Reset retransmits count */
- f->nakloops = 0; /* Reset nakloops count */
-}
+ switch( f->state ){
+ case INITIAL:
+ f->state = CLOSED;
+ break;
+ case STARTING:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
-/*
- * fsm_passiveopen - Passively open connection.
- *
- * Set new state and reset desired options.
- */
-void
- fsm_passiveopen(f)
-fsm *f;
-{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == LISTEN || /* Already passively open(ing)? */
- f->state == OPEN)
- return;
- if (f->state == REQSENT || /* Active-Opening or */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == TERMSENT || /* closing or */
- !(f->flags & LOWERUP)) { /* lower layer down? */
- f->flags |= POPENDING; /* Wait for desired event */
- return;
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
+ PROTO_NAME(f), f->state));
}
- if (f->callbacks->resetci)
- (*f->callbacks->resetci)(f); /* Reset options */
- f->state = LISTEN;
- f->retransmits = 0; /* Reset retransmits count */
- f->nakloops = 0; /* Reset nakloops count */
}
/*
- * fsm_close - Start closing connection.
+ * fsm_lowerdown - The lower layer is down.
*
- * Cancel timeouts and either initiate close or possibly go directly to
- * the CLOSED state.
+ * Cancel all timeouts and inform upper layers.
*/
void
- fsm_close(f)
-fsm *f;
+fsm_lowerdown(f)
+ fsm *f;
{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == CLOSED || /* Already CLOSED or Closing? */
- f->state == TERMSENT)
- return;
- if (f->state == REQSENT || /* Timeout pending for Open? */
- f->state == ACKRCVD ||
- f->state == ACKSENT)
+ switch( f->state ){
+ case CLOSED:
+ f->state = INITIAL;
+ break;
+
+ case STOPPED:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSING:
+ f->state = INITIAL;
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->state == OPEN && /* Open? */
- f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers we're down */
- if (f->state == ACKSENT || /* Could peer be OPEN? */
- f->state == OPEN) {
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- /* Send Terminate-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = TERMSENT;
- f->retransmits = 0; /* Reset retransmits count */
- }
- else {
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = STARTING;
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+ f->state = STARTING;
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Down event in state %d!",
+ PROTO_NAME(f), f->state));
}
}
/*
- * fsm_timeout - Timeout expired.
+ * fsm_open - Link is allowed to come up.
*/
-static void
- fsm_timeout(arg)
-caddr_t arg;
+void
+fsm_open(f)
+ fsm *f;
{
- fsm *f = (fsm *) arg;
- switch (f->state) {
- case REQSENT:
- case ACKRCVD:
- case ACKSENT:
- if (f->flags & POPENDING) { /* Go passive? */
- f->state = CLOSED; /* Pretend for a moment... */
- fsm_passiveopen(f);
- return;
- }
- if (f->retransmits > f->maxconfreqtransmits) {
- if (f->nakloops > f->maxnakloops) {
- syslog(LOG_INFO, "%s: timeout sending Config-Requests",
- proto_name(f->protocol));
- } else
- syslog(LOG_INFO, "%s: timed out. Config-Requests not accepted",
- proto_name(f->protocol));
-
- /* timeout sending config-requests */
- fsm_close(f);
-
- return;
- }
- if (f->callbacks->retransmit) /* If there is a retransmit rtn? */
- (*f->callbacks->retransmit)(f);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = REQSENT;
- ++f->retransmits;
- f->nakloops = 0;
+ switch( f->state ){
+ case INITIAL:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
break;
- case TERMSENT:
- if (f->flags & POPENDING) { /* Go passive? */
- f->state = CLOSED; /* Pretend for a moment... */
- fsm_passiveopen(f);
- return;
+ case CLOSED:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
}
- if (++f->retransmits > f->maxtermtransmits) {
- /*
- * We've waited for an ack long enough. Peer probably heard us.
- */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
- return;
+ break;
+
+ case CLOSING:
+ f->state = STOPPING;
+ /* fall through */
+ case STOPPED:
+ case OPENED:
+ if( f->flags & OPT_RESTART ){
+ fsm_lowerdown(f);
+ fsm_lowerup(f);
}
- if (f->callbacks->retransmit) /* If there is a retransmit rtn? */
- (*f->callbacks->retransmit)(f);
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- /* Send Terminate-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ break;
}
}
/*
- * fsm_lowerup - The lower layer is up.
+ * fsm_close - Start closing connection.
*
- * Start Active or Passive Open if pending.
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
*/
void
- fsm_lowerup(f)
-fsm *f;
+fsm_close(f)
+ fsm *f;
{
- f->flags |= LOWERUP;
- if (f->flags & AOPENDING) /* Attempting Active-Open? */
- fsm_activeopen(f); /* Try it now */
- else if (f->flags & POPENDING) /* Attempting Passive-Open? */
- fsm_passiveopen(f); /* Try it now */
-}
+ switch( f->state ){
+ case STARTING:
+ f->state = INITIAL;
+ break;
+ case STOPPED:
+ f->state = CLOSED;
+ break;
+ case STOPPING:
+ f->state = CLOSING;
+ break;
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ case OPENED:
+ if( f->state != OPENED )
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ else if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers we're down */
-/*
- * fsm_lowerdown - The lower layer is down.
- *
- * Cancel all timeouts and inform upper layers.
- */
-void
- fsm_lowerdown(f)
-fsm *f;
-{
- f->flags &= ~LOWERUP;
- if (f->state == REQSENT || /* Timeout pending? */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == TERMSENT)
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->state == OPEN && /* OPEN? */
- f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = CLOSING;
+ break;
+ }
}
/*
- * fsm_protreject - Peer doesn't speak this protocol.
- *
- * Pretend that the lower layer went down.
+ * fsm_timeout - Timeout expired.
*/
-void
- fsm_protreject(f)
-fsm *f;
+static void
+fsm_timeout(arg)
+ caddr_t arg;
{
- fsm_lowerdown(f);
+ fsm *f = (fsm *) arg;
+
+ switch (f->state) {
+ case CLOSING:
+ case STOPPING:
+ if( f->retransmits <= 0 ){
+ /*
+ * We've waited for an ack long enough. Peer probably heard us.
+ */
+ f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ } else {
+ /* Send Terminate-Request */
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+ }
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ if (f->retransmits <= 0) {
+ syslog(LOG_WARNING, "%s: timeout sending Config-Requests",
+ PROTO_NAME(f));
+ f->state = STOPPED;
+ if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+
+ } else {
+ /* Retransmit the configure-request */
+ if (f->callbacks->retransmit)
+ (*f->callbacks->retransmit)(f);
+ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
}
@@ -286,302 +284,262 @@ fsm *f;
* fsm_input - Input packet.
*/
void
- fsm_input(f, inpacket, l)
-fsm *f;
-u_char *inpacket;
-int l;
+fsm_input(f, inpacket, l)
+ fsm *f;
+ u_char *inpacket;
+ int l;
{
- u_char *inp, *outp;
- u_char code, id;
- int len;
-
- /*
- * Parse header (code, id and length).
- * If packet too short, drop it.
- */
- inp = inpacket;
- if (l < HEADERLEN) {
- FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", f->protocol))
- return;
- }
- GETCHAR(code, inp);
- GETCHAR(id, inp);
- GETSHORT(len, inp);
- if (len < HEADERLEN) {
- FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
- f->protocol))
- return;
- }
- if (len > l) {
- FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
- f->protocol))
- return;
- }
- len -= HEADERLEN; /* subtract header length */
-
- /*
- * Action depends on code.
- */
- switch (code) {
- case CONFREQ:
- FSMDEBUG((LOG_INFO, "fsm_rconfreq(%x): Rcvd id %d.",
- f->protocol, id))
-
- if (f->state == TERMSENT)
- return;
- if (f->state == CLOSED) {
- fsm_sdata(f, TERMACK, id, NULL, 0);
- return;
+ u_char *inp, *outp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < HEADERLEN) {
+ FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.",
+ f->protocol));
+ return;
}
- if (f->state == OPEN && f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- if (f->state == OPEN || f->state == LISTEN) {
- /* XXX Possibly need hold-down on OPEN? */
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
+ f->protocol));
+ return;
}
-
- if (f->callbacks->reqci) /* Check CI */
- code = (*f->callbacks->reqci)(f, inp, &len);
- else if (len)
- code = CONFREJ; /* Reject all CI */
-
- len += HEADERLEN; /* add header length back on */
-
- inp = inpacket; /* Reset to header */
- outp = outpacket_buf; /* get pointer to output buffer */
- MAKEHEADER(outp, f->protocol); /* paste in DLL header */
- BCOPY(inp, outp, len); /* copy input packet */
- PUTCHAR(code, outp); /* put in the code, id, and length*/
- PUTCHAR(id, outp);
- PUTSHORT(len, outp);
- output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it out */
-
- if (code == CONFACK) {
- if (f->state == ACKRCVD) {
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->up)
- (*f->callbacks->up)(f); /* Inform upper layers */
- f->state = OPEN;
- }
- else
- f->state = ACKSENT;
+ if (len > l) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
+ f->protocol));
+ return;
}
- else {
- if (f->state != ACKRCVD)
- f->state = REQSENT;
+ len -= HEADERLEN; /* subtract header length */
+
+ if( f->state == INITIAL || f->state == STARTING ){
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
+ f->protocol, f->state));
+ return;
}
- return;
-
- case CONFACK:
- fsm_rconfack(f, inp, id, len);
- break;
-
- case CONFNAK:
- fsm_rconfnak(f, inp, id, len);
- break;
-
- case CONFREJ:
- fsm_rconfrej(f, inp, id, len);
- break;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case CONFREQ:
+ fsm_rconfreq(f, id, inp, len);
+ break;
- case TERMREQ:
- fsm_rtermreq(f, id);
- break;
+ case CONFACK:
+ fsm_rconfack(f, id, inp, len);
+ break;
- case TERMACK:
- fsm_rtermack(f);
- break;
+ case CONFNAK:
+ case CONFREJ:
+ fsm_rconfnakrej(f, code, id, inp, len);
+ break;
- case CODEREJ:
- fsm_rcoderej(f, inp, len);
- break;
+ case TERMREQ:
+ fsm_rtermreq(f, id);
+ break;
- case PROTREJ:
- fsm_rprotrej(f, inp, len);
- break;
+ case TERMACK:
+ fsm_rtermack(f);
+ break;
- case ECHOREQ:
- FSMDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ case CODEREJ:
+ fsm_rcoderej(f, inp, len);
+ break;
- switch (f->state) {
- case CLOSED:
- case LISTEN:
- fsm_sdata(f, TERMACK, id, NULL, 0);
- break;
-
- case OPEN:
- inp = inpacket; /* Reset to header */
- outp = outpacket_buf; /* get pointer to output buffer */
- MAKEHEADER(outp, f->protocol); /* add DLL header */
- len += HEADERLEN; /* add header length */
- BCOPY(inp, outp, len); /* copy input packet to output buffer */
- PUTCHAR(ECHOREP, outp); /* set code to echo reply */
- PUTCHAR(id, outp); /* add in id */
- PUTSHORT(len, outp); /* and length */
- output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it */
- return;
+ default:
+ if( !f->callbacks->extcode
+ || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+ fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+ break;
}
- break;
-
- case ECHOREP:
- case DISCREQ:
- /* XXX Deliver to ECHOREQ sender? */
- break;
-
- default:
- fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
- break;
- }
-
}
/*
- * fsm_rconfack - Receive Configure-Ack.
+ * fsm_rconfreq - Receive Configure-Request.
*/
static void
- fsm_rconfack(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfreq(f, id, inp, len)
+ fsm *f;
+ u_char id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfack(%x): Rcvd id %d.",
- f->protocol, id))
+ u_char *outp;
+ int code, reject_if_disagree;
- switch (f->state) {
- case LISTEN:
- case CLOSED:
+ FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
+ switch( f->state ){
+ case CLOSED:
+ /* Go away, we're closed */
fsm_sdata(f, TERMACK, id, NULL, 0);
+ return;
+ case CLOSING:
+ case STOPPING:
+ return;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
break;
- case ACKRCVD:
- case REQSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (f->callbacks->ackci &&
- (*f->callbacks->ackci)(f, inp, len)) /* Good ack? */
- f->state = ACKRCVD;
- else
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case STOPPED:
+ /* Negotiation started by our peer */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
+ }
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (f->callbacks->ackci &&
- (*f->callbacks->ackci)(f, inp, len)) { /* Good ack? */
+ /*
+ * Pass the requested configuration options
+ * to protocol-specific code for checking.
+ */
+ if (f->callbacks->reqci){ /* Check CI */
+ reject_if_disagree = (f->nakloops >= f->maxnakloops);
+ code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+ } else if (len)
+ code = CONFREJ; /* Reject all CI */
+
+ /* send the Ack, Nak or Rej to the peer */
+ fsm_sdata(f, code, id, inp, len);
+
+ if (code == CONFACK) {
+ if (f->state == ACKRCVD) {
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
- f->state = OPEN;
- }
- else
- f->state = REQSENT; /* Wait for timeout to retransmit */
- break;
+ } else
+ f->state = ACKSENT;
+ f->nakloops = 0;
- case OPEN:
- if (f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
- break;
+ } else {
+ /* we sent CONFACK or CONFREJ */
+ if (f->state != ACKRCVD)
+ f->state = REQSENT;
+ if( code == CONFNAK )
+ ++f->nakloops;
}
}
/*
- * fsm_rconfnak - Receive Configure-Nak.
+ * fsm_rconfack - Receive Configure-Ack.
*/
static void
- fsm_rconfnak(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfack(f, id, inp, len)
+ fsm *f;
+ int id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfnak(%x): Rcvd id %d.",
- f->protocol, id))
+ FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid) /* Expected id? */
+ return; /* Nope, toss... */
+ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){
+ /* Ack is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
+ PROTO_NAME(f), len));
+ return;
+ }
switch (f->state) {
- case LISTEN:
- case CLOSED:
+ case CLOSED:
+ case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
- case REQSENT:
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (++f->nakloops > f->maxnakloops) {
- FSMDEBUG((LOG_INFO,
- "fsm_rconfnak(%x): Possible CONFNAK loop!",
- f->protocol))
- break; /* Break the loop */
- }
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->nakci)
- (*f->callbacks->nakci)(f, inp, len);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ case REQSENT:
+ f->state = ACKRCVD;
+ f->retransmits = f->maxconfreqtransmits;
break;
- case ACKRCVD:
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case ACKRCVD:
+ /* Huh? an extra Ack? oh well... */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
break;
- case OPEN:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
+ f->retransmits = f->maxconfreqtransmits;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
}
}
/*
- * fsm_rconfrej - Receive Configure-Rej.
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
*/
static void
- fsm_rconfrej(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfnakrej(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfrej(%x): Rcvd id %d.",
- f->protocol, id))
+ int (*proc)();
+
+ FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid) /* Expected id? */
+ return; /* Nope, toss... */
+ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+ if( !proc || !proc(f, inp, len) ){
+ /* Nak/reject is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
+ PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+ return;
+ }
switch (f->state) {
- case LISTEN:
- case CLOSED:
+ case CLOSED:
+ case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
- case REQSENT:
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (++f->nakloops > f->maxnakloops)
- break; /* Break the loop */
+ case REQSENT:
+ case ACKSENT:
+ /* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->rejci)
- (*f->callbacks->rejci)(f, inp, len);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
- case ACKRCVD:
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case ACKRCVD:
+ /* Got a Nak/reject when we had already had an Ack?? oh well... */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
break;
- case OPEN:
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
}
}
@@ -591,26 +549,27 @@ int len;
* fsm_rtermreq - Receive Terminate-Req.
*/
static void
- fsm_rtermreq(f, id)
-fsm *f;
-u_char id;
+fsm_rtermreq(f, id)
+ fsm *f;
+ int id;
{
- FSMDEBUG((LOG_INFO, "fsm_rtermreq(%x): Rcvd id %d.",
- f->protocol, id))
+ FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
fsm_sdata(f, TERMACK, id, NULL, 0);
switch (f->state) {
- case ACKRCVD:
- case ACKSENT:
+ case ACKRCVD:
+ case ACKSENT:
f->state = REQSENT; /* Start over but keep trying */
break;
- case OPEN:
+ case OPENED:
+ syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f));
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ f->retransmits = 0;
+ f->state = STOPPING;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
break;
}
}
@@ -620,25 +579,31 @@ u_char id;
* fsm_rtermack - Receive Terminate-Ack.
*/
static void
- fsm_rtermack(f)
-fsm *f;
+fsm_rtermack(f)
+ fsm *f;
{
- FSMDEBUG((LOG_INFO, "fsm_rtermack(%x).", f->protocol))
+ FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
switch (f->state) {
- case OPEN:
- if (f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
+ case CLOSING:
f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+ case STOPPING:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
break;
- case TERMSENT:
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ case ACKRCVD:
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0);
break;
}
}
@@ -648,59 +613,77 @@ fsm *f;
* fsm_rcoderej - Receive an Code-Reject.
*/
static void
- fsm_rcoderej(f, inp, len)
-fsm *f;
-u_char *inp;
-int len;
+fsm_rcoderej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
{
- u_char code;
+ u_char code, id;
- FSMDEBUG((LOG_INFO, "fsm_rcoderej(%x).", f->protocol))
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
- if (len < sizeof (u_char)) {
- FSMDEBUG((LOG_INFO,
- "fsm_rcoderej: Rcvd short Code-Reject packet!"))
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
return;
}
GETCHAR(code, inp);
- FSMDEBUG((LOG_INFO,
- "fsm_rcoderej: Rcvd Code-Reject for code %d!",
- code))
+ GETCHAR(id, inp);
+ syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d",
+ PROTO_NAME(f), code, id);
+
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
}
/*
- * fsm_rprotrej - Receive an Protocol-Reject.
+ * fsm_protreject - Peer doesn't speak this protocol.
*
- * Figure out which protocol is rejected and inform it.
+ * Treat this as a catastrophic error (RXJ-).
*/
-static void
- fsm_rprotrej(f, inp, len)
-fsm *f;
-u_char *inp;
-int len;
+void
+fsm_protreject(f)
+ fsm *f;
{
- u_short prot;
+ switch( f->state ){
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case CLOSED:
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
- FSMDEBUG((LOG_INFO, "fsm_rprotrej."))
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case STOPPED:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
- if (len < sizeof (u_short)) {
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd short Protocol-Reject packet!"))
- return;
- }
- if (f->protocol != LCP) { /* Only valid for LCP */
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd non-LCP Protocol-Reject!"))
- return;
- }
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
- GETSHORT(prot, inp);
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = STOPPING;
+ break;
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd Protocol-Reject packet for %x!",
- prot))
- DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
}
@@ -708,58 +691,79 @@ int len;
* fsm_sconfreq - Send a Configure-Request.
*/
static void
- fsm_sconfreq(f)
-fsm *f;
+fsm_sconfreq(f, retransmit)
+ fsm *f;
+ int retransmit;
{
u_char *outp;
- int outlen;
+ int outlen, cilen;
- outlen = HEADERLEN + (f->callbacks->cilen ? (*f->callbacks->cilen)(f) : 0);
- /* XXX Adjust outlen to MTU */
- outp = outpacket_buf;
- MAKEHEADER(outp, f->protocol);
+ if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+ /* Not currently negotiating - reset options */
+ if( f->callbacks->resetci )
+ (*f->callbacks->resetci)(f);
+ f->nakloops = 0;
+ }
- PUTCHAR(CONFREQ, outp);
- PUTCHAR(f->reqid = ++f->id, outp);
- PUTSHORT(outlen, outp);
- if (f->callbacks->cilen && f->callbacks->addci)
- (*f->callbacks->addci)(f, outp);
- output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ if( !retransmit ){
+ /* New request - reset retransmission counter, use new ID */
+ f->retransmits = f->maxconfreqtransmits;
+ f->reqid = ++f->id;
+ }
+
+ /*
+ * Make up the request packet
+ */
+ if( f->callbacks->cilen && f->callbacks->addci ){
+ cilen = (*f->callbacks->cilen)(f);
+ if( cilen > peer_mru[f->unit] - HEADERLEN )
+ cilen = peer_mru[f->unit] - HEADERLEN;
+ outp = outpacket_buf + DLLHEADERLEN + HEADERLEN;
+ if (f->callbacks->addci)
+ (*f->callbacks->addci)(f, outp, &cilen);
+ } else
+ cilen = 0;
+
+ /* send the request to our peer */
+ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+ /* start the retransmit timer */
+ --f->retransmits;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
- proto_name(f->protocol), f->reqid))
+ PROTO_NAME(f), f->reqid));
}
/*
* fsm_sdata - Send some data.
*
- * Used for Terminate-Request, Terminate-Ack, Code-Reject, Protocol-Reject,
- * Echo-Request, and Discard-Request.
+ * Used for all packets sent to our peer by this module.
*/
void
- fsm_sdata(f, code, id, data, datalen)
-fsm *f;
-u_char code, id;
-u_char *data;
-int datalen;
+fsm_sdata(f, code, id, data, datalen)
+ fsm *f;
+ u_char code, id;
+ u_char *data;
+ int datalen;
{
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
- if (datalen > MTU - HEADERLEN)
- datalen = MTU - HEADERLEN;
- outlen = datalen + HEADERLEN;
outp = outpacket_buf;
+ if (datalen > peer_mru[f->unit] - HEADERLEN)
+ datalen = peer_mru[f->unit] - HEADERLEN;
+ if (datalen && data != outp + DLLHEADERLEN + HEADERLEN)
+ BCOPY(data, outp + DLLHEADERLEN + HEADERLEN, datalen);
+ outlen = datalen + HEADERLEN;
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
- if (datalen)
- BCOPY(data, outp, datalen);
output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
- FSMDEBUG((LOG_INFO, "fsm_sdata(%x): Sent code %d, id %d.",
- f->protocol, code, id))
+ FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
+ PROTO_NAME(f), code, id));
}
diff --git a/libexec/pppd/fsm.h b/libexec/pppd/fsm.h
index 82af3039ca55..abb242e21db5 100644
--- a/libexec/pppd/fsm.h
+++ b/libexec/pppd/fsm.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.h,v 1.2 1994/03/30 09:31:27 jkh Exp $
*/
/*
@@ -45,32 +47,35 @@
*/
typedef struct fsm_callbacks {
void (*resetci)(); /* Reset our Configuration Information */
- int (*cilen)(); /* Length of our Configuration Information */
+ int (*cilen)(); /* Length of our Configuration Information */
void (*addci)(); /* Add our Configuration Information */
- int (*ackci)(); /* ACK our Configuration Information */
- void (*nakci)(); /* NAK our Configuration Information */
- void (*rejci)(); /* Reject our Configuration Information */
- u_char (*reqci)(); /* Request peer's Configuration Information */
- void (*up)(); /* Called when fsm reaches OPEN state */
- void (*down)(); /* Called when fsm leaves OPEN state */
- void (*closed)(); /* Called when fsm reaches CLOSED state */
+ int (*ackci)(); /* ACK our Configuration Information */
+ int (*nakci)(); /* NAK our Configuration Information */
+ int (*rejci)(); /* Reject our Configuration Information */
+ int (*reqci)(); /* Request peer's Configuration Information */
+ void (*up)(); /* Called when fsm reaches OPENED state */
+ void (*down)(); /* Called when fsm leaves OPENED state */
+ void (*starting)(); /* Called when we want the lower layer */
+ void (*finished)(); /* Called when we don't want the lower layer */
void (*protreject)(); /* Called when Protocol-Reject received */
void (*retransmit)(); /* Retransmission is necessary */
+ int (*extcode)(); /* Called when unknown code received */
+ char *proto_name; /* String name for protocol (for messages) */
} fsm_callbacks;
typedef struct fsm {
int unit; /* Interface unit number */
- u_short protocol; /* Data Link Layer Protocol field value */
+ int protocol; /* Data Link Layer Protocol field value */
int state; /* State */
- int flags; /* Flags */
+ int flags; /* Contains option bits */
u_char id; /* Current id */
u_char reqid; /* Current request id */
int timeouttime; /* Timeout time in milliseconds */
int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
- int retransmits; /* Number of retransmissions */
+ int retransmits; /* Number of retransmissions left */
int maxtermtransmits; /* Maximum Terminate-Request transmissions */
- int nakloops; /* Number of nak loops since last timeout */
+ int nakloops; /* Number of nak loops since last ack */
int maxnakloops; /* Maximum number of nak loops tolerated */
fsm_callbacks *callbacks; /* Callback routines */
} fsm;
@@ -79,40 +84,49 @@ typedef struct fsm {
/*
* Link states.
*/
-#define CLOSED 1 /* Connection closed */
-#define LISTEN 2 /* Listening for a Config Request */
-#define REQSENT 3 /* We've sent a Config Request */
-#define ACKSENT 4 /* We've sent a Config Ack */
-#define ACKRCVD 5 /* We've received a Config Ack */
-#define OPEN 6 /* Connection open */
-#define TERMSENT 7 /* We've sent a Terminate Request */
+#define INITIAL 0 /* Down, hasn't been opened */
+#define STARTING 1 /* Down, been opened */
+#define CLOSED 2 /* Up, hasn't been opened */
+#define STOPPED 3 /* Open, waiting for down event */
+#define CLOSING 4 /* Terminating the connection, not open */
+#define STOPPING 5 /* Terminating, but open */
+#define REQSENT 6 /* We've sent a Config Request */
+#define ACKRCVD 7 /* We've received a Config Ack */
+#define ACKSENT 8 /* We've sent a Config Ack */
+#define OPENED 9 /* Connection available */
/*
- * Flags.
+ * Flags - indicate options controlling FSM operation
*/
-#define LOWERUP 1 /* The lower level is UP */
-#define AOPENDING 2 /* Active Open pending timeout of request */
-#define POPENDING 4 /* Passive Open pending timeout of request */
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT 4 /* Wait for peer to speak first */
/*
* Timeouts.
*/
#define DEFTIMEOUT 3 /* Timeout time in seconds */
-#define DEFMAXTERMTRANSMITS 10 /* Maximum Terminate-Request transmissions */
-#define DEFMAXCONFIGREQS 10 /* Maximum Configure-Request transmissions */
-
-
+#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
#define DEFMAXNAKLOOPS 10 /* Maximum number of nak loops */
+/*
+ * Prototypes
+ */
void fsm_init __ARGS((fsm *));
-void fsm_activeopen __ARGS((fsm *));
-void fsm_passiveopen __ARGS((fsm *));
-void fsm_close __ARGS((fsm *));
void fsm_lowerup __ARGS((fsm *));
void fsm_lowerdown __ARGS((fsm *));
-void fsm_protreject __ARGS((fsm *));
+void fsm_open __ARGS((fsm *));
+void fsm_close __ARGS((fsm *));
void fsm_input __ARGS((fsm *, u_char *, int));
+void fsm_protreject __ARGS((fsm *));
void fsm_sdata __ARGS((fsm *, int, int, u_char *, int));
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
diff --git a/libexec/pppd/ipcp.c b/libexec/pppd/ipcp.c
index a805a3b61253..3638419ea6ac 100644
--- a/libexec/pppd/ipcp.c
+++ b/libexec/pppd/ipcp.c
@@ -17,12 +17,12 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: ipcp.c,v 1.3 1994/03/30 09:38:13 jkh Exp $";
+#endif
+
/*
* TODO:
- * Fix IP address negotiation (wantoptions or hisoptions).
- * Don't set zero IP addresses.
- * Send NAKs for unsent CIs.
- * VJ compression.
*/
#include <stdio.h>
@@ -33,64 +33,42 @@
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_ppp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <string.h>
-#ifndef BSD
-#ifndef sun
-#define BSD 44
-#endif
-#endif /*BSD*/
-
-#ifdef STREAMS
-#include <sys/stream.h>
-#include "ppp_str.h"
-#endif
-
#include "pppd.h"
-#include <net/if_ppp.h>
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "fsm.h"
#include "ipcp.h"
/* global vars */
-ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */
-ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */
-ipcp_options ipcp_allowoptions[NPPP]; /* Options that we allow peer to
- request */
-ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */
+ipcp_options ipcp_wantoptions[_NPPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[_NPPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[_NPPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[_NPPP]; /* Options that we ack'd */
/* local vars */
+static int cis_received[_NPPP]; /* # Conf-Reqs received */
/*
- * VJ compression protocol mode for negotiation. See ipcp.h for a
- * description of each mode.
+ * Callbacks for fsm code. (CI = Configuration Information)
*/
-static int vj_mode = IPCP_VJMODE_RFC1332;
-
-static int vj_opt_len = 6; /* holds length in octets for valid vj */
- /* compression frame depending on mode */
-
-static int vj_opt_val = IPCP_VJ_COMP;
- /* compression negotiation frames */
- /* depending on vj_mode */
-
-static void ipcp_resetci __ARGS((fsm *)); /* Reset our Configuration Information */
-static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
-static void ipcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
-static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
-static void ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
-static void ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Reject some CIs */
-static u_char ipcp_reqci __ARGS((fsm *, u_char *, int *)); /* Check the requested CIs */
+static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */
+static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */
static void ipcp_up __ARGS((fsm *)); /* We're UP */
-static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
+static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
-static fsm ipcp_fsm[NPPP]; /* IPCP fsm structure */
+fsm ipcp_fsm[_NPPP]; /* IPCP fsm structure */
static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
ipcp_resetci, /* Reset our Configuration Information */
@@ -100,19 +78,38 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
ipcp_nakci, /* NAK our Configuration Information */
ipcp_rejci, /* Reject our Configuration Information */
ipcp_reqci, /* Request peer's Configuration Information */
- ipcp_up, /* Called when fsm reaches OPEN state */
- ipcp_down, /* Called when fsm leaves OPEN state */
- NULL, /* Called when fsm reaches CLOSED state */
+ ipcp_up, /* Called when fsm reaches OPENED state */
+ ipcp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ NULL, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
- NULL /* Retransmission is necessary */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPCP" /* String name of protocol */
};
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
+#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR 6 /* new-style single address option */
+#define CILEN_ADDRS 10 /* old-style dual address option */
+
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * Make a string representation of a network IP address.
+ */
char *
ip_ntoa(ipaddr)
u_long ipaddr;
{
- static char b1[64], b2[64], w = 0;
- char *b = (w++&1) ? b1 : b2;
+ static char b[64];
ipaddr = ntohl(ipaddr);
@@ -124,12 +121,13 @@ u_long ipaddr;
return b;
}
+
/*
* ipcp_init - Initialize IPCP.
*/
void
- ipcp_init(unit)
-int unit;
+ipcp_init(unit)
+ int unit;
{
fsm *f = &ipcp_fsm[unit];
ipcp_options *wo = &ipcp_wantoptions[unit];
@@ -137,17 +135,17 @@ int unit;
f->unit = unit;
f->protocol = IPCP;
- f->timeouttime = DEFTIMEOUT;
- f->maxconfreqtransmits = DEFMAXCONFIGREQS;
- f->maxtermtransmits = DEFMAXTERMTRANSMITS;
- f->maxnakloops = DEFMAXNAKLOOPS;
f->callbacks = &ipcp_callbacks;
+ fsm_init(&ipcp_fsm[unit]);
- wo->neg_addrs = 1;
+ wo->neg_addr = 1;
+ wo->old_addrs = 0;
wo->ouraddr = 0;
wo->hisaddr = 0;
wo->neg_vj = 1;
+ wo->old_vj = 0;
+ wo->vj_protocol = IPCP_VJ_COMP;
wo->maxslotindex = MAX_STATES - 1; /* really max index */
wo->cflag = 1;
@@ -155,77 +153,30 @@ int unit;
/* ppp_if.c to 16 and 1, this needs to be changed (among other */
/* things) gmc */
- ao->neg_addrs = 1; /* accept old style dual addr */
- ao->neg_addr = 1; /* accept new style single addr */
+ ao->neg_addr = 1;
ao->neg_vj = 1;
ao->maxslotindex = MAX_STATES - 1;
ao->cflag = 1;
- fsm_init(&ipcp_fsm[unit]);
}
-/*
- * ipcp_vj_setmode - set option length and option value for vj
- * compression negotiation frames depending on mode
- */
-
-void
- ipcp_vj_setmode(mode)
-int mode;
-{
- vj_mode = mode;
-
- switch (vj_mode) {
-
- case IPCP_VJMODE_OLD: /* with wrong code (0x0037) */
- vj_opt_len = 4;
- vj_opt_val = IPCP_VJ_COMP_OLD;
- break;
-
- case IPCP_VJMODE_RFC1172: /* as per rfc1172 */
- vj_opt_len = 4;
- vj_opt_val = IPCP_VJ_COMP;
- break;
- case IPCP_VJMODE_RFC1332: /* draft mode vj compression */
- vj_opt_len = 6; /* negotiation includes values for */
- /* maxslot and slot number compression */
- vj_opt_val = IPCP_VJ_COMP;
- break;
-
- default:
- IPCPDEBUG((LOG_WARNING, "Unknown vj compression mode %d. Please report \
-this error.", vj_mode))
- break;
- }
-
-}
/*
- * ipcp_activeopen - Actively open IPCP.
+ * ipcp_open - IPCP is allowed to come up.
*/
void
- ipcp_activeopen(unit)
-int unit;
-{
- fsm_activeopen(&ipcp_fsm[unit]);
-}
-
-
-/*
- * ipcp_passiveopen - Passively open IPCP.
- */
-void ipcp_passiveopen(unit)
+ipcp_open(unit)
int unit;
{
- fsm_passiveopen(&ipcp_fsm[unit]);
+ fsm_open(&ipcp_fsm[unit]);
}
/*
- * ipcp_close - Close IPCP.
+ * ipcp_close - Take IPCP down.
*/
void
- ipcp_close(unit)
-int unit;
+ipcp_close(unit)
+ int unit;
{
fsm_close(&ipcp_fsm[unit]);
}
@@ -235,8 +186,8 @@ int unit;
* ipcp_lowerup - The lower layer is up.
*/
void
- ipcp_lowerup(unit)
-int unit;
+ipcp_lowerup(unit)
+ int unit;
{
fsm_lowerup(&ipcp_fsm[unit]);
}
@@ -246,8 +197,8 @@ int unit;
* ipcp_lowerdown - The lower layer is down.
*/
void
- ipcp_lowerdown(unit)
-int unit;
+ipcp_lowerdown(unit)
+ int unit;
{
fsm_lowerdown(&ipcp_fsm[unit]);
}
@@ -257,10 +208,10 @@ int unit;
* ipcp_input - Input IPCP packet.
*/
void
- ipcp_input(unit, p, len)
-int unit;
-u_char *p;
-int len;
+ipcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
fsm_input(&ipcp_fsm[unit], p, len);
}
@@ -269,11 +220,11 @@ int len;
/*
* ipcp_protrej - A Protocol-Reject was received for IPCP.
*
- * Simply pretend that LCP went down.
+ * Pretend the lower layer went down, so we shut up.
*/
void
- ipcp_protrej(unit)
-int unit;
+ipcp_protrej(unit)
+ int unit;
{
fsm_lowerdown(&ipcp_fsm[unit]);
}
@@ -283,10 +234,18 @@ int unit;
* ipcp_resetci - Reset our CI.
*/
static void
- ipcp_resetci(f)
-fsm *f;
+ipcp_resetci(f)
+ fsm *f;
{
- ipcp_gotoptions[f->unit] = ipcp_wantoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+ if (wo->ouraddr == 0)
+ wo->accept_local = 1;
+ if (wo->hisaddr == 0)
+ wo->accept_remote = 1;
+ ipcp_gotoptions[f->unit] = *wo;
+ cis_received[f->unit] = 0;
}
@@ -294,21 +253,16 @@ fsm *f;
* ipcp_cilen - Return length of our CI.
*/
static int
- ipcp_cilen(f)
-fsm *f;
+ipcp_cilen(f)
+ fsm *f;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
+#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
-#define LENCISHORT(neg) (neg ? vj_opt_len : 0)
-
-#define LENCIADDRS(neg) (neg ? 10 : 0)
-
-#define LENCIADDR(neg) (neg ? 6 : 0)
-
- return (LENCIADDRS(go->neg_addrs) +
- LENCIADDR(go->neg_addr) +
- LENCISHORT(go->neg_vj));
+ return (LENCIADDR(go->neg_addr, go->old_addrs) +
+ LENCIVJ(go->neg_vj, go->old_vj));
}
@@ -316,50 +270,81 @@ fsm *f;
* ipcp_addci - Add our desired CIs to a packet.
*/
static void
- ipcp_addci(f, ucp)
-fsm *f;
-u_char *ucp;
+ipcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ int len = *lenp;
-
-#define ADDCISHORT(opt, neg, val, maxslotindex, cflag) \
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
if (neg) { \
- PUTCHAR(opt, ucp); \
- PUTCHAR(vj_opt_len, ucp); \
- PUTSHORT(val, ucp); \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- PUTCHAR(maxslotindex, ucp); \
- PUTCHAR(cflag, ucp); \
- } \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ if (!old) { \
+ PUTCHAR(maxslotindex, ucp); \
+ PUTCHAR(cflag, ucp); \
+ } \
+ len -= vjlen; \
+ } else \
+ neg = 0; \
}
-#define ADDCIADDRS(opt, neg, val1, val2) \
+#define ADDCIADDR(opt, neg, old, val1, val2) \
if (neg) { \
- u_long l; \
- PUTCHAR(opt, ucp); \
- PUTCHAR(2 + 2 * sizeof (long), ucp); \
- l = ntohl(val1); \
- PUTLONG(l, ucp); \
- l = ntohl(val2); \
- PUTLONG(l, ucp); \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ if (len >= addrlen) { \
+ u_long l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(addrlen, ucp); \
+ l = ntohl(val1); \
+ PUTLONG(l, ucp); \
+ if (old) { \
+ l = ntohl(val2); \
+ PUTLONG(l, ucp); \
+ } \
+ len -= addrlen; \
+ } else \
+ neg = 0; \
}
-#define ADDCIADDR(opt, neg, val) \
- if (neg) { \
- u_long l; \
- PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (long), ucp); \
- l = ntohl(val); \
- PUTLONG(l, ucp); \
+ /*
+ * First see if we want to change our options to the old
+ * forms because we have received old forms from the peer.
+ */
+ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+ /* use the old style of address negotiation */
+ go->neg_addr = 1;
+ go->old_addrs = 1;
+ }
+ if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+ /* try an older style of VJ negotiation */
+ if (cis_received[f->unit] == 0) {
+ /* keep trying the new style until we see some CI from the peer */
+ go->neg_vj = 1;
+ } else {
+ /* use the old style only if the peer did */
+ if (ho->neg_vj && ho->old_vj) {
+ go->neg_vj = 1;
+ go->old_vj = 1;
+ go->vj_protocol = ho->vj_protocol;
+ }
+ }
}
- ADDCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
+ ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
- ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
- ADDCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val,
- go->maxslotindex, go->cflag)
+ *lenp -= len;
}
@@ -371,93 +356,74 @@ u_char *ucp;
* 1 - Ack was good.
*/
static int
- ipcp_ackci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+ipcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_short cilen, citype, cishort;
u_long cilong;
u_char cimaxslotindex, cicflag;
+
/*
* CIs must be in exactly the same order that we sent...
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
-#define ACKCISHORT(opt, neg, val, maxslotindex, cflag) \
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
if (neg) { \
- if ((len -= vj_opt_len) < 0) \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if ((len -= vjlen) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != vj_opt_len || \
+ if (cilen != vjlen || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- GETCHAR(cimaxslotindex, p); \
- if (cimaxslotindex > maxslotindex) \
- goto bad; \
- GETCHAR(cicflag, p); \
- if (cicflag != cflag) \
- goto bad; \
- } \
- }
-
-#define ACKCIADDRS(opt, neg, val1, val2) \
- if (neg) { \
- u_long l; \
- if ((len -= 2 + 2 * sizeof (long)) < 0) \
- goto bad; \
- GETCHAR(citype, p); \
- GETCHAR(cilen, p); \
- if (cilen != 2 + 2 * sizeof (long) || \
- citype != opt) \
- goto bad; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- if (val1) { \
- if (val1 != cilong) \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslotindex) \
goto bad; \
- } \
- else \
- val1 = cilong; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- if (val2) { \
- if (val2 != cilong) \
+ GETCHAR(cicflag, p); \
+ if (cicflag != cflag) \
goto bad; \
} \
- else \
- val2 = cilong; \
}
-#define ACKCIADDR(opt, neg, val) \
+#define ACKCIADDR(opt, neg, old, val1, val2) \
if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
u_long l; \
- if ((len -= 2 + sizeof (long)) < 0) \
+ if ((len -= addrlen) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (long) || \
+ if (cilen != addrlen || \
citype != opt) \
goto bad; \
GETLONG(l, p); \
cilong = htonl(l); \
- if (val) { \
- if (val != cilong) \
+ if (val1 != cilong) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val2 != cilong) \
goto bad; \
} \
- else \
- val = cilong; \
}
- ACKCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
- ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
- ACKCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
+ ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
/*
* If there are any remaining CIs, then this packet is bad.
*/
@@ -467,153 +433,246 @@ int len;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
-
- if (vj_mode == IPCP_VJMODE_RFC1332 )
- IPCPDEBUG((LOG_INFO, "ipcp_ackci: citype %d, cilen %l",
- citype, cilen));
-
- if (citype == CI_COMPRESSTYPE) {
- IPCPDEBUG((LOG_INFO, "ipcp_ackci: compress_type %d", cishort));
- if (vj_mode == IPCP_VJMODE_RFC1332)
- IPCPDEBUG((LOG_INFO, ", maxslotindex %d, cflag %d",
- cishort, cimaxslotindex, cicflag));
- }
return (0);
}
/*
- * ipcp_nakci - NAK some of our CIs.
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
*
* Returns:
* 0 - Nak was bad.
* 1 - Nak was good.
*/
-static void
- ipcp_nakci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+ipcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
u_short cishort;
- u_long ciaddr1, ciaddr2;
+ u_long ciaddr1, ciaddr2, l;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
/*
* Any Nak'd CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
-#define NAKCISHORT(opt, neg, code) \
- if (neg && \
- len >= vj_opt_len && \
- p[1] == vj_opt_len && \
+#define NAKCIADDR(opt, neg, old, code) \
+ if (go->neg && \
+ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+ p[1] == cilen && \
p[0] == opt) { \
- len -= vj_opt_len; \
- INCPTR(2, p); \
- GETSHORT(cishort, p); \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- GETCHAR(cimaxslotindex, p); \
- GETCHAR(cicflag, p); \
- } \
- code \
- }
-
-#define NAKCIADDRS(opt, neg, code) \
- if (neg && \
- len >= 2 + 2 * sizeof (long) && \
- p[1] == 2 + 2 * sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + 2 * sizeof (long); \
+ len -= cilen; \
INCPTR(2, p); \
GETLONG(l, p); \
ciaddr1 = htonl(l); \
- GETLONG(l, p); \
- ciaddr2 = htonl(l); \
+ if (old) { \
+ GETLONG(l, p); \
+ ciaddr2 = htonl(l); \
+ no.old_addrs = 1; \
+ } else \
+ ciaddr2 = 0; \
+ no.neg = 1; \
code \
}
-#define NAKCIADDR(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+ len >= cilen && \
p[0] == opt) { \
- u_long l; \
- len -= 2 + sizeof (long); \
+ len -= cilen; \
INCPTR(2, p); \
- GETLONG(l, p); \
- ciaddr1 = htonl(l); \
- code \
+ GETSHORT(cishort, p); \
+ if (cilen == CILEN_VJ) { \
+ GETCHAR(cimaxslotindex, p); \
+ GETCHAR(cicflag, p); \
+ } \
+ no.neg = 1; \
+ code \
}
- NAKCIADDRS(CI_ADDRS, go->neg_addrs,
- if (!go->ouraddr) { /* Didn't know our address? */
- syslog(LOG_INFO, "local IP address %s", ip_ntoa(ciaddr1));
- go->ouraddr = ciaddr1;
- }
- if (ciaddr2) { /* Does he know his? */
- go->hisaddr = ciaddr2;
- syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr2));
- }
- )
-
- NAKCIADDR(CI_ADDR, go->neg_addr,
- logf(LOG_INFO, "acquired IP address %s", ip_ntoa(ciaddr1));
- if (!go->ouraddr) { /* Didn't know our address? */
- go->ouraddr = ciaddr1;
- syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr1));
- }
- )
-
- NAKCISHORT(CI_COMPRESSTYPE, go->neg_vj,
- if (cishort != vj_opt_val)
- goto bad;
- go->maxslotindex = cimaxslotindex; /* this is what it */
- go->cflag = cicflag; /* wants */
-
- )
/*
- * If there are any remaining CIs, then this packet is bad.
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
*/
- if (len == 0)
- return;
+ NAKCIADDR(CI_ADDR, neg_addr, go->old_addrs,
+ if (go->accept_local && ciaddr1) { /* Do we know our address? */
+ try.ouraddr = ciaddr1;
+ IPCPDEBUG((LOG_INFO, "local IP address %s",
+ ip_ntoa(ciaddr1)));
+ }
+ if (go->accept_remote && ciaddr2) { /* Does he know his? */
+ try.hisaddr = ciaddr2;
+ IPCPDEBUG((LOG_INFO, "remote IP address %s",
+ ip_ntoa(ciaddr2)));
+ }
+ );
+
+ /*
+ * Accept the peer's value of maxslotindex provided that it
+ * is less than what we asked for. Turn off slot-ID compression
+ * if the peer wants. Send old-style compress-type option if
+ * the peer wants.
+ */
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ if (cilen == CILEN_VJ) {
+ if (cishort == IPCP_VJ_COMP) {
+ try.old_vj = 0;
+ if (cimaxslotindex < go->maxslotindex)
+ try.maxslotindex = cimaxslotindex;
+ if (!cicflag)
+ try.cflag = 0;
+ } else {
+ try.neg_vj = 0;
+ }
+ } else {
+ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+ try.old_vj = 1;
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about IP addresses, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+ goto bad;
+ no.neg_vj = 1;
+ break;
+ case CI_ADDRS:
+ if (go->neg_addr && go->old_addrs || no.old_addrs
+ || cilen != CILEN_ADDRS)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 1;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ GETLONG(l, p);
+ ciaddr2 = htonl(l);
+ if (ciaddr2 && go->accept_remote)
+ try.hisaddr = ciaddr2;
+ no.old_addrs = 1;
+ break;
+ case CI_ADDR:
+ if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ no.neg_addr = 1;
+ break;
+ default:
+ goto bad;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
bad:
IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
+ return 0;
}
/*
* ipcp_rejci - Reject some of our CIs.
*/
-static void
- ipcp_rejci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+ipcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
- u_char cimaxslotindex, ciflag;
+ u_char cimaxslotindex, ciflag, cilen;
u_short cishort;
u_long cilong;
+ ipcp_options try; /* options to request next time */
+ try = *go;
/*
* Any Rejected CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
-#define REJCISHORT(opt, neg, val, maxslot, cflag) \
- if (neg && \
- len >= vj_opt_len && \
- p[1] == vj_opt_len && \
+#define REJCIADDR(opt, neg, old, val1, val2) \
+ if (go->neg && \
+ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ u_long l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val1) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val2) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+ if (go->neg && \
+ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+ len >= p[1] && \
p[0] == opt) { \
- len -= vj_opt_len; \
+ len -= p[1]; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
if (cishort != val) \
goto bad; \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
+ if (!old) { \
GETCHAR(cimaxslotindex, p); \
if (cimaxslotindex != maxslot) \
goto bad; \
@@ -621,60 +680,30 @@ int len;
if (ciflag != cflag) \
goto bad; \
} \
- neg = 0; \
+ try.neg = 0; \
}
-#define REJCIADDRS(opt, neg, val1, val2) \
- if (neg && \
- len >= 2 + 2 * sizeof (long) && \
- p[1] == 2 + 2 * sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + 2 * sizeof (long); \
- INCPTR(2, p); \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val2) \
- goto bad; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val1) \
- goto bad; \
- neg = 0; \
- }
+ REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
-#define REJCIADDR(opt, neg, val) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + sizeof (long); \
- INCPTR(2, p); \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val) \
- goto bad; \
- neg = 0; \
- }
-
- REJCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
-
- REJCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
-
- REJCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
/*
* If there are any remaining CIs, then this packet is bad.
*/
- if (len == 0)
- return;
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
+ return 0;
}
@@ -682,25 +711,27 @@ bad:
* ipcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
- * appropriately.
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
-static u_char
- ipcp_reqci(f, inp, len)
-fsm *f;
-u_char *inp; /* Requested CIs */
-int *len; /* Length of requested CIs */
+static int
+ipcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
{
ipcp_options *wo = &ipcp_wantoptions[f->unit];
ipcp_options *ho = &ipcp_hisoptions[f->unit];
ipcp_options *ao = &ipcp_allowoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
- u_char *cip; /* Pointer to Current CI */
+ u_char *cip, *next; /* Pointer to current and next CIs */
u_short cilen, citype; /* Parsed len, type */
u_short cishort; /* Parsed short value */
- u_long tl, ciaddr1, ciaddr2; /* Parsed address values */
+ u_long tl, ciaddr1, ciaddr2;/* Parsed address values */
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
- u_char *p = inp; /* Pointer to next char to parse */
+ u_char *p; /* Pointer to next char to parse */
u_char *ucp = inp; /* Pointer to current output char */
int l = *len; /* Length left */
u_char maxslotindex, cflag;
@@ -708,17 +739,15 @@ int *len; /* Length of requested CIs */
/*
* Reset all his options.
*/
- ho->neg_addrs = 0;
- ho->neg_vj = 0;
- ho->maxslotindex = 0;
- ho->cflag = 0;
+ BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
+ next = inp;
while (l) {
orc = CONFACK; /* Assume success */
- cip = p; /* Remember begining of CI */
+ cip = p = next; /* Remember begining of CI */
if (l < 2 || /* Not enough data for CI header or */
p[1] < 2 || /* CI length too small or */
p[1] > l) { /* CI length too big? */
@@ -731,15 +760,13 @@ int *len; /* Length of requested CIs */
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
- cilen -= 2; /* Adjust cilen to just data */
+ next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_ADDRS:
- logf(LOG_INFO, "ipcp: received ADDRS ");
- if (!ao->neg_addrs ||
- cilen != 2 * sizeof (long))
- { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
+ case CI_ADDRS:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDRS) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
@@ -752,13 +779,15 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse source address (his) */
ciaddr1 = htonl(tl);
- if (!ciaddr1 ||
- (wo->neg_addrs && wo->hisaddr && ciaddr1 != wo->hisaddr))
- {
+ IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = wo->neg_addrs ? ntohl(wo->hisaddr) : 0;
- PUTLONG(tl, p);
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
}
/*
@@ -767,37 +796,35 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse desination address (ours) */
ciaddr2 = htonl(tl);
- logf(LOG_INFO, "(%s:%s)", ip_ntoa(ciaddr1), ip_ntoa(ciaddr2));
- if (!ciaddr2 ||
- (wo->neg_addrs && wo->ouraddr && ciaddr2 != wo->ouraddr))
- {
- orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = ntohl(wo->ouraddr);
- PUTLONG(tl, p);
+ IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
+ if (ciaddr2 != wo->ouraddr) {
+ if (ciaddr2 == 0 || !wo->accept_local) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->ouraddr);
+ PUTLONG(tl, p);
+ }
+ } else {
+ go->ouraddr = ciaddr2; /* accept peer's idea */
+ }
}
- if (orc == CONFNAK)
- break;
- /* XXX ho or go? */
- ho->neg_addrs = 1;
+ ho->neg_addr = 1;
+ ho->old_addrs = 1;
ho->hisaddr = ciaddr1;
ho->ouraddr = ciaddr2;
break;
- case CI_ADDR:
- logf(LOG_INFO, "ipcp: received ADDR ");
- go->got_addr = 1;
- go->neg_addrs = 0;
- go->neg_addr = 1;
+ case CI_ADDR:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
if (!ao->neg_addr ||
- cilen != sizeof (long)) { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
- orc = CONFREJ; /* Reject CI */
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
break;
}
-
+
/*
* If he has no address, or if we both have his address but
* disagree about it, then NAK it with our idea.
@@ -806,86 +833,83 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse source address (his) */
ciaddr1 = htonl(tl);
- logf(LOG_INFO, "(%s)", ip_ntoa(ciaddr1));
- if (!ciaddr1 ||
- (wo->neg_addr && wo->hisaddr && ciaddr1 != wo->hisaddr)) {
+ IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = wo->neg_addr ? ntohl(wo->hisaddr) : 0;
- PUTLONG(tl, p);
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
}
- if (orc == CONFNAK)
- break;
-
- /* XXX ho or go? */
ho->neg_addr = 1;
ho->hisaddr = ciaddr1;
break;
- case CI_COMPRESSTYPE:
- logf(LOG_INFO, "ipcp: received COMPRESSTYPE ");
+ case CI_COMPRESSTYPE:
+ IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
if (!ao->neg_vj ||
- cilen != (vj_opt_len - 2)) {
- INCPTR(cilen, p);
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
orc = CONFREJ;
break;
}
GETSHORT(cishort, p);
- logf(LOG_INFO, "(%d)", cishort);
+ IPCPDEBUG((LOG_INFO, "(%d)", cishort));
- /*
- * Compresstype must be vj_opt_val.
- */
- if (cishort != vj_opt_val) {
- DECPTR(sizeof (short), p);
- orc = CONFNAK;
- PUTSHORT(vj_opt_val, p);
+ if (!(cishort == IPCP_VJ_COMP ||
+ (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+ orc = CONFREJ;
break;
}
- ho->neg_vj = 1;
- if (vj_mode == IPCP_VJMODE_RFC1332) {
- GETCHAR(maxslotindex, p);
- if (maxslotindex > wo->maxslotindex) {
- DECPTR(1, p);
- orc = CONFNAK;
- PUTCHAR(wo->maxslotindex, p);
- break;
- }
- ho->maxslotindex = maxslotindex;
- GETCHAR(cflag, p);
- if (cflag != wo->cflag) {
- DECPTR(1, p);
- orc = CONFNAK;
- PUTCHAR(wo->cflag, p);
- break;
- }
- ho->cflag = wo->cflag;
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ if (cilen == CILEN_VJ) {
+ GETCHAR(maxslotindex, p);
+ if (maxslotindex > ao->maxslotindex) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(ao->maxslotindex, p);
+ }
+ }
+ GETCHAR(cflag, p);
+ if (cflag && !ao->cflag) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(wo->cflag, p);
+ }
+ }
+ ho->maxslotindex = maxslotindex;
+ ho->cflag = wo->cflag;
}
break;
- default:
- INCPTR(cilen, p);
+ default:
orc = CONFREJ;
break;
}
- cilen += 2; /* Adjust cilen whole CI */
endswitch:
- logf(LOG_INFO, " (%s)\n",
- orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "Reject"));
+ IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
if (orc == CONFACK && /* Good CI */
rc != CONFACK) /* but prior CI wasnt? */
continue; /* Don't send this one */
if (orc == CONFNAK) { /* Nak this CI? */
- if (rc == CONFREJ) /* Rejecting prior CI? */
- continue; /* Don't send this one */
- if (rc == CONFACK) { /* Ack'd all prior CIs? */
- rc = CONFNAK; /* Not anymore... */
- ucp = inp; /* Backup */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
}
}
@@ -897,72 +921,137 @@ endswitch:
/* Need to move CI? */
if (ucp != cip)
- /* Move it */
- memcpy(ucp, cip, (size_t)cilen);
+ BCOPY(cip, ucp, cilen); /* Move it */
/* Update output pointer */
INCPTR(cilen, ucp);
}
/*
- * XXX If we wanted to send additional NAKs (for unsent CIs), the
- * code would go here. This must be done with care since it might
- * require a longer packet than we received.
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a CI_ADDR option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
*/
+ if (rc != CONFREJ && !ho->neg_addr &&
+ wo->req_addr && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_addr = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_ADDR, ucp);
+ PUTCHAR(CILEN_ADDR, ucp);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, ucp);
+ }
*len = ucp - inp; /* Compute output length */
-
- syslog(LOG_INFO, "ipcp: returning Configure-%s",
- rc == CONFACK ? "ACK" :
- rc == CONFNAK ? "NAK" : "Reject");
-
+ IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
return (rc); /* Return final code */
}
/*
* ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
*/
static void
- ipcp_up(f)
-fsm *f;
+ipcp_up(f)
+ fsm *f;
{
- u_long mask;
+ u_long mask;
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
- syslog(LOG_INFO, "ipcp: up");
+ IPCPDEBUG((LOG_INFO, "ipcp: up"));
+ go->default_route = 0;
+ go->proxy_arp = 0;
- if (ipcp_hisoptions[f->unit].hisaddr == 0)
- ipcp_hisoptions[f->unit].hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+ /*
+ * We must have a non-zero IP address for both ends of the link.
+ */
+ if (!ho->neg_addr)
+ ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
- syslog(LOG_INFO, "local IP address %s",
- ip_ntoa(ipcp_gotoptions[f->unit].ouraddr));
- syslog(LOG_INFO, "remote IP address %s",
- ip_ntoa(ipcp_hisoptions[f->unit].hisaddr));
+ if (ho->hisaddr == 0) {
+ syslog(LOG_ERR, "Could not determine remote IP address");
+ ipcp_close(f->unit);
+ return;
+ }
+ if (go->ouraddr == 0) {
+ syslog(LOG_ERR, "Could not determine local IP address");
+ ipcp_close(f->unit);
+ return;
+ }
- SIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
- ipcp_hisoptions[f->unit].hisaddr);
+ /*
+ * Check that the peer is allowed to use the IP address he wants.
+ */
+ if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+ syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
+ ip_ntoa(ho->hisaddr));
+ ipcp_close(f->unit);
+ return;
+ }
- /* set new netmask if specified */
- mask = GetMask(ipcp_gotoptions[f->unit].ouraddr);
- if (mask)
- SIFMASK(f->unit, mask);
+ syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
+ syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit);
+ return;
+ }
- /* set tcp compression */
- SIFVJCOMP(f->unit, ipcp_hisoptions[f->unit].neg_vj);
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag);
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ IPCPDEBUG((LOG_WARNING, "sifup failed"));
+ ipcp_close(f->unit);
+ return;
+ }
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, ho->hisaddr))
+ go->default_route = 1;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ go->proxy_arp = 1;
}
/*
* ipcp_down - IPCP has gone DOWN.
*
- * Alert other protocols.
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
*/
static void
- ipcp_down(f)
-fsm *f;
+ipcp_down(f)
+ fsm *f;
{
- syslog(LOG_INFO, "ipcp: down");
-
- CIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
- ipcp_hisoptions[f->unit].hisaddr);
+ u_long ouraddr, hisaddr;
+
+ IPCPDEBUG((LOG_INFO, "ipcp: down"));
+
+ ouraddr = ipcp_gotoptions[f->unit].ouraddr;
+ hisaddr = ipcp_hisoptions[f->unit].hisaddr;
+ if (ipcp_gotoptions[f->unit].proxy_arp)
+ cifproxyarp(f->unit, hisaddr);
+ if (ipcp_gotoptions[f->unit].default_route)
+ cifdefaultroute(f->unit, hisaddr);
+ sifdown(f->unit);
+ cifaddr(f->unit, ouraddr, hisaddr);
}
diff --git a/libexec/pppd/ipcp.h b/libexec/pppd/ipcp.h
index 3bbec12442ef..bae91e55c455 100644
--- a/libexec/pppd/ipcp.h
+++ b/libexec/pppd/ipcp.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h,v 1.2 1994/03/30 09:31:30 jkh Exp $
*/
/*
@@ -26,36 +28,38 @@
#define MAX_STATES 16 /* from slcompress.h */
-#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
-#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
-#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
- /* maxslot and slot number */
- /* compression from Aug. 1991 */
- /* ipcp draft RFC) */
+#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
+ /* maxslot and slot number compression) */
#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
/* compression option*/
typedef struct ipcp_options {
- int neg_addrs : 1; /* Negotiate IP Addresses? */
int neg_addr : 1; /* Negotiate IP Address? */
- int got_addr : 1; /* Got IP Address? */
- u_long ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+ int old_addrs : 1; /* Use old (IP-Addresses) option? */
+ int req_addr : 1; /* Ask peer to send IP address? */
+ int default_route : 1; /* Assign default route through interface? */
+ int proxy_arp : 1; /* Make proxy ARP entry for peer? */
int neg_vj : 1; /* Van Jacobson Compression? */
- u_char maxslotindex, cflag; /* fields for Aug. 1991 Draft VJ */
- /* compression negotiation */
+ int old_vj : 1; /* use old (short) form of VJ option? */
+ int accept_local : 1; /* accept peer's value for ouraddr */
+ int accept_remote : 1; /* accept peer's value for hisaddr */
+ u_short vj_protocol; /* protocol value to use in VJ option */
+ u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */
+ u_long ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
} ipcp_options;
+extern fsm ipcp_fsm[];
extern ipcp_options ipcp_wantoptions[];
extern ipcp_options ipcp_gotoptions[];
extern ipcp_options ipcp_allowoptions[];
extern ipcp_options ipcp_hisoptions[];
void ipcp_init __ARGS((int));
-void ipcp_vj_setmode __ARGS((int));
-void ipcp_activeopen __ARGS((int));
-void ipcp_passiveopen __ARGS((int));
+void ipcp_open __ARGS((int));
void ipcp_close __ARGS((int));
void ipcp_lowerup __ARGS((int));
void ipcp_lowerdown __ARGS((int));
diff --git a/libexec/pppd/lcp.c b/libexec/pppd/lcp.c
index d95a8faf575f..e991ef66d3a0 100644
--- a/libexec/pppd/lcp.c
+++ b/libexec/pppd/lcp.c
@@ -17,13 +17,13 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: lcp.c,v 1.3 1994/03/30 09:38:14 jkh Exp $";
+#endif
+
/*
* TODO:
- * Keepalive.
- * Send NAKs for unsent CIs.
- * Keep separate MTU, MRU.
* Option tracing.
- * Extra data on authtype option.
* Test restart.
*/
@@ -35,19 +35,13 @@
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_ppp.h>
#include <netinet/in.h>
#include <string.h>
-#ifdef STREAMS
-#include <sys/stream.h>
-#include "ppp_str.h"
-#endif
-
-#include <net/if_ppp.h>
#include "pppd.h"
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "fsm.h"
#include "lcp.h"
#include "magic.h"
@@ -56,26 +50,28 @@
#include "ipcp.h"
/* global vars */
-fsm lcp_fsm[NPPP]; /* LCP fsm structure (global)*/
-lcp_options lcp_wantoptions[NPPP]; /* Options that we want to request */
-lcp_options lcp_gotoptions[NPPP]; /* Options that peer ack'd */
-lcp_options lcp_allowoptions[NPPP]; /* Options that we allow peer to request */
-lcp_options lcp_hisoptions[NPPP]; /* Options that we ack'd */
-
-/* local vars */
-static void lcp_resetci __ARGS((fsm *));
- /* Reset our Configuration Information */
-static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
-static void lcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
-static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
-static void lcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
-static void lcp_rejci __ARGS((fsm *, u_char *, int));
- /* Reject some CIs */
-static u_char lcp_reqci __ARGS((fsm *, u_char *, int *));
- /* Check the requested CIs */
-static void lcp_up __ARGS((fsm *)); /* We're UP */
-static void lcp_down __ARGS((fsm *)); /* We're DOWN */
-static void lcp_closed __ARGS((fsm *)); /* We're CLOSED */
+fsm lcp_fsm[_NPPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[_NPPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[_NPPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[_NPPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[_NPPP]; /* Options that we ack'd */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void lcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __ARGS((fsm *)); /* We're UP */
+static void lcp_down __ARGS((fsm *)); /* We're DOWN */
+static void lcp_starting __ARGS((fsm *)); /* We need lower layer up */
+static void lcp_finished __ARGS((fsm *)); /* We need lower layer down */
+static int lcp_extcode __ARGS((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __ARGS((fsm *, u_char *, int));
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_resetci, /* Reset our Configuration Information */
@@ -85,96 +81,104 @@ static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_nakci, /* NAK our Configuration Information */
lcp_rejci, /* Reject our Configuration Information */
lcp_reqci, /* Request peer's Configuration Information */
- lcp_up, /* Called when fsm reaches OPEN state */
- lcp_down, /* Called when fsm leaves OPEN state */
- lcp_closed, /* Called when fsm reaches CLOSED state */
+ lcp_up, /* Called when fsm reaches OPENED state */
+ lcp_down, /* Called when fsm leaves OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
- NULL /* Retransmission is necessary */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
};
+int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
-
-#define DEFWARNLOOPS 10 /* XXX Move to lcp.h */
-static int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
/*
* lcp_init - Initialize LCP.
*/
void
- lcp_init(unit)
-int unit;
+lcp_init(unit)
+ int unit;
{
- fsm *f = &lcp_fsm[unit];
- lcp_options *wo = &lcp_wantoptions[unit];
- lcp_options *ao = &lcp_allowoptions[unit];
-
- f->unit = unit;
- f->protocol = LCP;
- f->timeouttime = DEFTIMEOUT;
- f->maxconfreqtransmits = DEFMAXCONFIGREQS;
- f->maxtermtransmits = DEFMAXTERMTRANSMITS;
- f->maxnakloops = DEFMAXNAKLOOPS;
- f->callbacks = &lcp_callbacks;
-
- wo->passive = 0;
- wo->restart = 0; /* Set to 1 in kernels or multi-line
- implementations */
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
- wo->neg_mru = 1;
- wo->mru = DEFMRU;
- wo->neg_asyncmap = 1;
- wo->asyncmap = 0;
- wo->neg_chap = 0; /* Set to 1 on server */
- wo->neg_upap = 0; /* Set to 1 on server */
- wo->neg_magicnumber = 1;
- wo->neg_pcompression = 1;
- wo->neg_accompression = 1;
-
- ao->neg_mru = 1;
- ao->neg_asyncmap = 1;
- ao->neg_chap = 0; /* Set to 1 on client */
- ao->chap_mdtype = CHAP_DIGEST_MD5;
- ao->chap_callback = CHAP_NOCALLBACK;
- ao->neg_upap = 0; /* Set to 1 on client */
-
- ao->neg_magicnumber = 1;
- ao->neg_pcompression = 1;
- ao->neg_accompression = 1;
-
- fsm_init(f);
-}
+ f->unit = unit;
+ f->protocol = LCP;
+ f->callbacks = &lcp_callbacks;
+ fsm_init(f);
+
+ wo->passive = 0;
+ wo->silent = 0;
+ wo->restart = 0; /* Set to 1 in kernels or multi-line
+ implementations */
+ wo->neg_mru = 1;
+ wo->mru = DEFMRU;
+ wo->neg_asyncmap = 1;
+ wo->asyncmap = 0;
+ wo->neg_chap = 0; /* Set to 1 on server */
+ wo->neg_upap = 0; /* Set to 1 on server */
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+ wo->neg_lqr = 0; /* no LQR implementation yet */
+
+ ao->neg_mru = 1;
+ ao->mru = MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->asyncmap = 0;
+ ao->neg_chap = 1;
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = 1;
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+ ao->neg_lqr = 0; /* no LQR implementation yet */
-/*
- * lcp_activeopen - Actively open LCP.
- */
-void
- lcp_activeopen(unit)
-int unit;
-{
- fsm_activeopen(&lcp_fsm[unit]);
}
/*
- * lcp_passiveopen - Passively open LCP.
+ * lcp_open - LCP is allowed to come up.
*/
void
- lcp_passiveopen(unit)
-int unit;
+lcp_open(unit)
+ int unit;
{
- fsm_passiveopen(&lcp_fsm[unit]);
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags = 0;
+ if (wo->passive)
+ f->flags |= OPT_PASSIVE;
+ if (wo->silent)
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
}
/*
- * lcp_close - Close LCP.
+ * lcp_close - Take LCP down.
*/
void
- lcp_close(unit)
-int unit;
+lcp_close(unit)
+ int unit;
{
fsm_close(&lcp_fsm[unit]);
}
@@ -184,14 +188,13 @@ int unit;
* lcp_lowerup - The lower layer is up.
*/
void
- lcp_lowerup(unit)
-int unit;
+lcp_lowerup(unit)
+ int unit;
{
- SIFDOWN(unit);
- SIFMTU(unit, MTU);
- SIFASYNCMAP(unit, 0xffffffff);
- CIFPCOMPRESSION(unit);
- CIFACCOMPRESSION(unit);
+ sifdown(unit);
+ ppp_send_config(unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, MTU, 0, 0, 0);
+ peer_mru[unit] = MTU;
fsm_lowerup(&lcp_fsm[unit]);
}
@@ -201,8 +204,8 @@ int unit;
* lcp_lowerdown - The lower layer is down.
*/
void
- lcp_lowerdown(unit)
-int unit;
+lcp_lowerdown(unit)
+ int unit;
{
fsm_lowerdown(&lcp_fsm[unit]);
}
@@ -212,28 +215,103 @@ int unit;
* lcp_input - Input LCP packet.
*/
void
- lcp_input(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
fsm_input(&lcp_fsm[unit], p, len);
}
/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if( f->state != OPENED )
+ break;
+ LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_short prot;
+
+ LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
+
+ if (len < sizeof (u_short)) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!",
+ prot));
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != OPENED ){
+ LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d",
+ f->state));
+ return;
+ }
+
+ DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+}
+
+
+/*
* lcp_protrej - A Protocol-Reject was received.
*/
/*ARGSUSED*/
void
- lcp_protrej(unit)
-int unit;
+lcp_protrej(unit)
+ int unit;
{
/*
* Can't reject LCP!
*/
LCPDEBUG((LOG_WARNING,
- "lcp_protrej: Received Protocol-Reject for LCP!"))
+ "lcp_protrej: Received Protocol-Reject for LCP!"));
+ fsm_protreject(&lcp_fsm[unit]);
}
@@ -241,13 +319,14 @@ int unit;
* lcp_sprotrej - Send a Protocol-Reject for some protocol.
*/
void
- lcp_sprotrej(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_sprotrej(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
- /* this is marginal, as rejected-info should be full frame,
- * but at least we return the rejected-protocol
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the OPENED state.
*/
p += 2;
len -= 2;
@@ -267,6 +346,7 @@ fsm *f;
lcp_wantoptions[f->unit].magicnumber = magic();
lcp_wantoptions[f->unit].numloops = 0;
lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+ peer_mru[f->unit] = MTU;
}
@@ -274,20 +354,25 @@ fsm *f;
* lcp_cilen - Return length of our CI.
*/
static int
- lcp_cilen(f)
-fsm *f;
+lcp_cilen(f)
+ fsm *f;
{
lcp_options *go = &lcp_gotoptions[f->unit];
-#define LENCIVOID(neg) (neg ? 2 : 0)
-#define LENCICHAP(neg) (neg ? 6 : 0)
-#define LENCISHORT(neg) (neg ? 4 : 0)
-#define LENCILONG(neg) (neg ? 6 : 0)
-
+#define LENCIVOID(neg) (neg ? CILEN_VOID : 0)
+#define LENCICHAP(neg) (neg ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) (neg ? CILEN_SHORT : 0)
+#define LENCILONG(neg) (neg ? CILEN_LONG : 0)
+#define LENCILQR(neg) (neg ? CILEN_LQR: 0)
+ /*
+ * NB: we only ask for one of CHAP and UPAP, even if we will
+ * accept either.
+ */
return (LENCISHORT(go->neg_mru) +
LENCILONG(go->neg_asyncmap) +
LENCICHAP(go->neg_chap) +
- LENCISHORT(go->neg_upap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
LENCILONG(go->neg_magicnumber) +
LENCIVOID(go->neg_pcompression) +
LENCIVOID(go->neg_accompression));
@@ -298,60 +383,75 @@ fsm *f;
* lcp_addci - Add our desired CIs to a packet.
*/
static void
- lcp_addci(f, ucp)
-fsm *f;
-u_char *ucp;
+lcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
#define ADDCIVOID(opt, neg) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
}
#define ADDCISHORT(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (short), ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
PUTSHORT(val, ucp); \
}
-#define ADDCICHAP(opt, neg, val, digest, callback) \
+#define ADDCICHAP(opt, neg, val, digest) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(6, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
PUTSHORT(val, ucp); \
PUTCHAR(digest, ucp); \
- PUTCHAR(callback, ucp); \
}
#define ADDCILONG(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (long), ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(LQR, ucp); \
PUTLONG(val, ucp); \
}
- ADDCISHORT(CI_MRU, go->neg_mru, go->mru)
- ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ADDCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
+ }
}
/*
* lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
*
* Returns:
* 0 - Ack was bad.
* 1 - Ack was good.
*/
static int
- lcp_ackci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+lcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
u_char cilen, citype, cichar;
@@ -365,34 +465,34 @@ int len;
*/
#define ACKCIVOID(opt, neg) \
if (neg) { \
- if ((len -= 2) < 0) \
+ if ((len -= CILEN_VOID) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 || \
+ if (cilen != CILEN_VOID || \
citype != opt) \
goto bad; \
}
#define ACKCISHORT(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (short)) < 0) \
+ if ((len -= CILEN_SHORT) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (short) || \
+ if (cilen != CILEN_SHORT || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
}
-#define ACKCICHAP(opt, neg, val, digest, callback) \
+#define ACKCICHAP(opt, neg, val, digest) \
if (neg) { \
- if ((len -= 4 + sizeof (short)) < 0) \
+ if ((len -= CILEN_CHAP) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 4 + sizeof (short) || \
+ if (cilen != CILEN_CHAP || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
@@ -401,31 +501,45 @@ int len;
GETCHAR(cichar, p); \
if (cichar != digest) \
goto bad; \
- GETCHAR(cichar, p); \
- if (cichar != callback) \
- goto bad; \
}
#define ACKCILONG(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (long)) < 0) \
+ if ((len -= CILEN_LONG) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (long) || \
+ if (cilen != CILEN_LONG || \
citype != opt) \
goto bad; \
GETLONG(cilong, p); \
if (cilong != val) \
goto bad; \
}
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
- ACKCISHORT(CI_MRU, go->neg_mru, go->mru)
- ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ACKCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
@@ -434,67 +548,97 @@ int len;
goto bad;
return (1);
bad:
- LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"))
+ LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"));
return (0);
}
/*
- * lcp_nakci - NAK some of our CIs.
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
*/
-static void
- lcp_nakci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char cilen, citype, cichar, *next;
u_short cishort;
u_long cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
/*
* Any Nak'd CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define NAKCIVOID(opt, neg, code) \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
code \
}
-#define NAKCICHAP(opt, neg, digest, callback, code) \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
- INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
code \
}
#define NAKCISHORT(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ no.neg = 1; \
code \
}
#define NAKCILONG(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
code \
}
@@ -502,143 +646,270 @@ int len;
* We don't care if they want to send us smaller packets than
* we want. Therefore, accept any MRU less than what we asked for,
* but then ignore the new value when setting the MRU in the kernel.
- * If they send us a bigger MRU than what we asked, reject it and
- * let him decide to accept our value.
+ * If they send us a bigger MRU than what we asked, accept it, up to
+ * the limit of the default MRU we'd get if we didn't negotiate.
+ */
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort < DEFMRU)
+ try.mru = cishort;
+ );
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ /*
+ * If they can't cope with our CHAP hash algorithm, we'll have
+ * to stop asking for CHAP. We haven't got any other algorithm.
+ */
+ NAKCICHAP(CI_AUTHTYPE, neg_chap,
+ try.neg_chap = 0;
+ );
+ /*
+ * Peer shouldn't send Nak for UPAP, protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
+ if (!go->neg_chap ){
+ NAKCISHORT(CI_AUTHTYPE, neg_upap,
+ try.neg_upap = 0;
+ );
+ }
+ /*
+ * If they can't cope with our link quality protocol, we'll have
+ * to stop asking for LQR. We haven't got any other protocol.
+ * If they Nak the reporting period, take their value XXX ?
+ */
+ NAKCILONG(CI_QUALITY, neg_lqr,
+ if (cishort != LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+ /*
+ * Check for a looped-back line.
*/
- NAKCISHORT(CI_MRU, go->neg_mru,
- if (cishort <= wo->mru)
- go->mru = cishort;
- else
- goto bad;
- )
- NAKCILONG(CI_ASYNCMAP, go->neg_asyncmap,
- go->asyncmap |= cilong;
- )
- NAKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype, go->chap_callback,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate chap!"))
- )
- NAKCISHORT(CI_AUTHTYPE, go->neg_upap,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate pap!"))
- )
- NAKCILONG(CI_MAGICNUMBER, go->neg_magicnumber,
- go->magicnumber = magic();
- if (++go->numloops % lcp_warnloops == 0)
- LCPDEBUG((LOG_INFO, "The line appears to be looped back."))
- )
- NAKCIVOID(CI_PCOMPRESSION, go->neg_pcompression,
- go->neg_pcompression = 0;
- )
- NAKCIVOID(CI_ACCOMPRESSION, go->neg_accompression,
- go->neg_accompression = 0;
- )
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ ++try.numloops;
+ looped_back = 1;
+ );
+
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+ try.neg_pcompression = 0;
+ );
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+ try.neg_accompression = 0;
+ );
/*
- * If there are any remaining CIs, then this packet is bad.
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
*/
- if (len == 0)
- return;
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT)
+ goto bad;
+ break;
+ case CI_ASYNCMAP:
+ if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+ goto bad;
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED) {
+ *go = try;
+ if (looped_back && try.numloops % lcp_warnloops == 0)
+ LCPDEBUG((LOG_INFO, "The line appears to be looped back."));
+ }
+
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"))
+ LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"));
+ return 0;
}
/*
- * lcp_rejci - Reject some of our CIs.
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
*/
-static void
- lcp_rejci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
u_short cishort;
u_long cilong;
u_char *start = p;
- int myopt, myval, xval, plen = len;
+ int plen = len;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
/*
* Any Rejected CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define REJCIVOID(opt, neg) \
- myopt = opt; \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected void opt %d",opt)) \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \
}
#define REJCISHORT(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
- xval = cishort; \
if (cishort != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \
}
-#define REJCICHAP(opt, neg, val, digest, callback) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
/* Check rejected value. */ \
- xval = cishort; \
- if (cishort != val) \
+ if (cishort != val || cichar != digest) \
goto bad; \
- neg = 0; \
- INCPTR(2, p); \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \
}
#define REJCILONG(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
- xval = cilong; \
/* Check rejected value. */ \
if (cilong != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != LQR || cichar != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
}
- REJCISHORT(CI_MRU, go->neg_mru, go->mru)
- REJCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- REJCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->callback)
- REJCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- REJCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- REJCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- REJCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, UPAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
*/
- if (len == 0)
- return;
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"))
- LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d, exp opt %d, found %d, val %d fval %d ",
- plen, len, p - start, myopt, p[0] &0xff, myval, xval ))
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"));
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d",
+ plen, len, p - start));
+ return 0;
}
@@ -646,48 +917,45 @@ bad:
* lcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
- * appropriately.
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
-static u_char
- lcp_reqci(f, inp, len)
-fsm *f;
-u_char *inp; /* Requested CIs */
-int *len; /* Length of requested CIs */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *lenp; /* Length of requested CIs */
+ int reject_if_disagree;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *ao = &lcp_allowoptions[f->unit];
- u_char *cip; /* Pointer to Current CI */
+ u_char *cip, *next; /* Pointer to current and next CIs */
u_char cilen, citype, cichar;/* Parsed len, type, char value */
u_short cishort; /* Parsed short value */
u_long cilong; /* Parse long value */
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
- u_char *p = inp; /* Pointer to next char to parse */
+ u_char *p; /* Pointer to next char to parse */
u_char *ucp = inp; /* Pointer to current output char */
- int l = *len; /* Length left */
+ int l = *lenp; /* Length left */
/*
* Reset all his options.
*/
- ho->neg_mru = 0;
- ho->neg_asyncmap = 0;
- ho->neg_chap = 0;
- ho->neg_upap = 0;
- ho->neg_magicnumber = 0;
- ho->neg_pcompression = 0;
- ho->neg_accompression = 0;
+ BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
+ next = inp;
while (l) {
orc = CONFACK; /* Assume success */
- cip = p; /* Remember begining of CI */
+ cip = p = next; /* Remember begining of CI */
if (l < 2 || /* Not enough data for CI header or */
p[1] < 2 || /* CI length too small or */
p[1] > l) { /* CI length too big? */
- LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"))
+ LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"));
orc = CONFREJ; /* Reject bad CI */
cilen = l; /* Reject till end of packet */
l = 0; /* Don't loop again */
@@ -696,19 +964,18 @@ int *len; /* Length of requested CIs */
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
- cilen -= 2; /* Adjust cilen to just data */
+ next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_MRU:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"))
+ case CI_MRU:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"));
if (!ao->neg_mru || /* Allow option? */
- cilen != sizeof (short)) { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
+ cilen != CILEN_SHORT) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
GETSHORT(cishort, p); /* Parse MRU */
- LCPDEBUG((LOG_INFO, "(%d)", cishort))
+ LCPDEBUG((LOG_INFO, "(%d)", cishort));
/*
* He must be able to receive at least our minimum.
@@ -717,131 +984,136 @@ int *len; /* Length of requested CIs */
*/
if (cishort < MINMRU) {
orc = CONFNAK; /* Nak CI */
- DECPTR(sizeof (short), p); /* Backup */
- PUTSHORT(MINMRU, p); /* Give him a hint */
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (short), p); /* Backup */
+ PUTSHORT(MINMRU, p); /* Give him a hint */
+ }
break;
}
- ho->neg_mru = 1; /* Remember he sent and MRU */
+ ho->neg_mru = 1; /* Remember he sent MRU */
ho->mru = cishort; /* And remember value */
break;
- case CI_ASYNCMAP:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"))
+ case CI_ASYNCMAP:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"));
if (!ao->neg_asyncmap ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
- /* XXX Accept anything he says */
-#if 0
/*
- * Asyncmap must be OR of two maps.
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
*/
- if ((lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != (lcp_wantoptions[f->unit].asyncmap | cilong)) ||
- (!lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != 0xffffffff)) {
+ if ((ao->asyncmap & ~cilong) != 0) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- PUTLONG(lcp_wantoptions[f->unit].neg_asyncmap ?
- lcp_wantoptions[f->unit].asyncmap | cilong :
- 0xffffffff, p);
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (long), p);
+ PUTLONG(ao->asyncmap | cilong, p);
+ }
break;
}
-#endif
ho->neg_asyncmap = 1;
ho->asyncmap = cilong;
break;
- case CI_AUTHTYPE:
- if (cilen < sizeof (short) ||
- (!ao->neg_upap && !ao->neg_chap)) {
- LCPDEBUG((LOG_WARNING,
- "lcp_reqci: rcvd AUTHTYPE, rejecting ...!"))
- INCPTR(cilen, p);
- orc = CONFREJ;
- break;
+ case CI_AUTHTYPE:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE"));
+ if (cilen < CILEN_SHORT ||
+ !(ao->neg_upap || ao->neg_chap)) {
+ orc = CONFREJ;
+ break;
}
GETSHORT(cishort, p);
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE (%x)",
- cishort))
+ LCPDEBUG((LOG_INFO, "(%x)", cishort));
/*
* Authtype must be UPAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
*/
+
if (cishort == UPAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_upap) { /* we don't want to do PAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."))
- orc = CONFREJ;
+ if (!ao->neg_upap || /* we don't want to do PAP */
+ ho->neg_chap || /* or we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG((LOG_WARNING,
+ "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_upap = 1;
break;
- }
- ho->neg_upap = 1;
- break;
}
- else if (cishort == CHAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_chap) { /* we don't want to do CHAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."))
- orc = CONFREJ;
+ if (cishort == CHAP) {
+ if (!ao->neg_chap || /* we don't want to do CHAP */
+ ho->neg_upap || /* or we've already accepted UPAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != ao->chap_mdtype) {
+ orc = CONFNAK;
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (u_char), p);
+ PUTCHAR(ao->chap_mdtype, p);
+ }
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
break;
- }
- GETCHAR(cichar, p); /* get digest type*/
- if (cichar != ao->chap_mdtype) {
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(ao->chap_mdtype, p);
- INCPTR(cilen - sizeof(u_char), p);
- break;
- }
- ho->chap_mdtype = cichar; /* save md type */
- GETCHAR(cichar, p); /* get callback type*/
- if (cichar != ao->chap_callback) { /* we don't callback yet */
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(CHAP_NOCALLBACK, p);
- INCPTR(cilen - sizeof(u_char), p);
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Reject it.
+ */
+ orc = CONFREJ;
+ break;
+
+ case CI_QUALITY:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY"));
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
break;
- }
- ho->chap_callback = cichar; /* save callback */
- ho->neg_chap = 1;
- break;
}
- else {
- DECPTR(sizeof (short), p);
- orc = CONFNAK;
- if (ao->neg_chap) { /* We prefer CHAP */
- PUTSHORT(CHAP, p);
- }
- else
- if (ao->neg_upap) {
- PUTSHORT(CHAP, p);
- }
- else {
- syslog(LOG_ERR, "Coding botch in lcp_reqci authnak. This shouldn't happen.");
- exit(1);
- }
- INCPTR(cilen - sizeof (u_short), p);
- break;
+
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x %lx)", cishort, cilong));
+ if (cishort != LQR) {
+ orc = CONFREJ;
+ break;
}
+ /*
+ * Check the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ break;
- case CI_MAGICNUMBER:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"))
- if (!ao->neg_magicnumber ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ case CI_MAGICNUMBER:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"));
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
/*
* He must have a different magic number.
@@ -859,50 +1131,49 @@ int *len; /* Length of requested CIs */
break;
- case CI_PCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"))
+ case CI_PCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"));
if (!ao->neg_pcompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_pcompression = 1;
break;
- case CI_ACCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"))
+ case CI_ACCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"));
if (!ao->neg_accompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_accompression = 1;
break;
- default:
+ default:
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d",
- citype))
- INCPTR(cilen, p);
+ citype));
orc = CONFREJ;
break;
}
- cilen += 2; /* Adjust cilen whole CI */
endswitch:
- LCPDEBUG((LOG_INFO, " (%s)",
- orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "REJ")))
+ LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc)));
if (orc == CONFACK && /* Good CI */
rc != CONFACK) /* but prior CI wasnt? */
continue; /* Don't send this one */
if (orc == CONFNAK) { /* Nak this CI? */
- if (rc == CONFREJ) /* Rejecting prior CI? */
- continue; /* Don't send this one */
- if (rc == CONFACK) { /* Ack'd all prior CIs? */
- rc = CONFNAK; /* Not anymore... */
- ucp = inp; /* Backup */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
}
}
if (orc == CONFREJ && /* Reject this CI */
@@ -916,15 +1187,14 @@ endswitch:
}
/*
- * XXX If we wanted to send additional NAKs (for unsent CIs), the
+ * If we wanted to send additional NAKs (for unsent CIs), the
* code would go here. This must be done with care since it might
- * require a longer packet than we received.
+ * require a longer packet than we received. At present there
+ * are no cases where we want to ask the peer to negotiate an option.
*/
- *len = ucp - inp; /* Compute output length */
- LCPDEBUG((LOG_INFO, "lcp_reqci: returning %s.",
- rc == CONFACK ? "CONFACK" :
- rc == CONFNAK ? "CONFNAK" : "CONFREJ"))
+ *lenp = ucp - inp; /* Compute output length */
+ LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc)));
return (rc); /* Return final code */
}
@@ -935,43 +1205,35 @@ endswitch:
* Start UPAP, IPCP, etc.
*/
static void
- lcp_up(f)
-fsm *f;
+lcp_up(f)
+ fsm *f;
{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *go = &lcp_gotoptions[f->unit];
- int auth = 0;
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ */
+ ppp_send_config(f->unit, (ho->neg_mru? MIN(ao->mru, ho->mru): MTU),
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ ho->neg_pcompression, ho->neg_accompression);
+ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): MTU),
+ (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+ go->neg_pcompression, go->neg_accompression);
if (ho->neg_mru)
- SIFMTU(f->unit, ho->mru);
- if (ho->neg_asyncmap)
- SIFASYNCMAP(f->unit, ho->asyncmap);
- if (ho->neg_pcompression)
- SIFPCOMPRESSION(f->unit);
- if (ho->neg_accompression)
- SIFACCOMPRESSION(f->unit);
- SIFUP(f->unit); /* Bring the interface up (set IFF_UP) */
+ peer_mru[f->unit] = ho->mru;
+
ChapLowerUp(f->unit); /* Enable CHAP */
upap_lowerup(f->unit); /* Enable UPAP */
ipcp_lowerup(f->unit); /* Enable IPCP */
- if (go->neg_chap) {
- ChapAuthPeer(f->unit);
- auth = 1;
- }
- if (ho->neg_chap) {
- ChapAuthWithPeer(f->unit);
- auth = 1;
- }
- if (go->neg_upap) {
- upap_authpeer(f->unit);
- auth = 1;
- }
- if (ho->neg_upap) {
- upap_authwithpeer(f->unit);
- auth = 1;
- }
- if (!auth)
- ipcp_activeopen(f->unit);
+
+ link_established(f->unit);
}
@@ -981,36 +1243,39 @@ fsm *f;
* Alert other protocols.
*/
static void
- lcp_down(f)
-fsm *f;
+lcp_down(f)
+ fsm *f;
{
- ipcp_lowerdown(f->unit);
- SIFDOWN(f->unit);
- SIFMTU(f->unit, MTU);
- SIFASYNCMAP(f->unit, 0xffffffff);
- CIFPCOMPRESSION(f->unit);
- CIFACCOMPRESSION(f->unit);
- ChapLowerDown(f->unit);
- upap_lowerdown(f->unit);
+ ipcp_lowerdown(f->unit);
+ ChapLowerDown(f->unit);
+ upap_lowerdown(f->unit);
+
+ sifdown(f->unit);
+ ppp_send_config(f->unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, MTU, 0, 0, 0);
+ peer_mru[f->unit] = MTU;
+ syslog(LOG_NOTICE, "Connection terminated.");
}
/*
- * lcp_closed - LCP has CLOSED.
- *
- * Alert other protocols.
+ * lcp_starting - LCP needs the lower layer up.
*/
static void
- lcp_closed(f)
-fsm *f;
+lcp_starting(f)
+ fsm *f;
{
- if (lcp_wantoptions[f->unit].restart) {
- if (lcp_wantoptions[f->unit].passive)
- lcp_passiveopen(f->unit); /* Start protocol in passive mode */
- else
- lcp_activeopen(f->unit); /* Start protocol in active mode */
- }
- else {
- EXIT(f->unit);
- }
+ link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+ fsm *f;
+{
+ link_terminated(f->unit);
}
+
diff --git a/libexec/pppd/lcp.h b/libexec/pppd/lcp.h
index d4db5344a925..3bcb59bcb73e 100644
--- a/libexec/pppd/lcp.h
+++ b/libexec/pppd/lcp.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.h,v 1.2 1994/03/30 09:31:32 jkh Exp $
*/
/*
@@ -23,9 +25,9 @@
#define CI_MRU 1 /* Maximum Receive Unit */
#define CI_ASYNCMAP 2 /* Async Control Character Map */
#define CI_AUTHTYPE 3 /* Authentication Type */
-#define CI_NOTDEFINED 4 /* not defined (used to be Encryption Type) */
+#define CI_QUALITY 4 /* Quality Protocol */
#define CI_MAGICNUMBER 5 /* Magic Number */
-#define CI_KEEPALIVE 6 /* Keep Alive Parameters */
+#define CI_KEEPALIVE 6 /* Keep Alive Parameters - OBSOLETE */
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
@@ -34,21 +36,23 @@
* The state of options is described by an lcp_options structure.
*/
typedef struct lcp_options {
- int passive : 1; /* Passives vs. active open */
+ int passive : 1; /* Don't die if we don't get a response */
+ int silent : 1; /* Wait for the other end to start first */
int restart : 1; /* Restart vs. exit after close */
int neg_mru : 1; /* Negotiate the MRU? */
- u_short mru; /* Value of MRU */
- int neg_asyncmap : 1; /* Async map? */
- u_long asyncmap;
- int neg_upap : 1; /* UPAP authentication? */
- int neg_chap : 1; /* CHAP authentication? */
- char chap_mdtype; /* which MD type */
- char chap_callback; /* callback ? */
- int neg_magicnumber : 1; /* Magic number? */
- u_long magicnumber;
- int numloops; /* Number loops during magic number negot. */
+ int neg_asyncmap : 1; /* Negotiate the async map? */
+ int neg_upap : 1; /* Ask for UPAP authentication? */
+ int neg_chap : 1; /* Ask for CHAP authentication? */
+ int neg_magicnumber : 1; /* Ask for magic number? */
int neg_pcompression : 1; /* HDLC Protocol Field Compression? */
int neg_accompression : 1; /* HDLC Address/Control Field Compression? */
+ int neg_lqr : 1; /* Negotiate use of Link Quality Reports */
+ u_short mru; /* Value of MRU */
+ char chap_mdtype; /* which MD type (hashing algorithm) */
+ u_long asyncmap; /* Value of async map */
+ u_long magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u_long lqr_period; /* Reporting period for link quality */
} lcp_options;
extern fsm lcp_fsm[];
@@ -59,13 +63,16 @@ extern lcp_options lcp_hisoptions[];
#define DEFMRU 1500 /* Try for this */
#define MINMRU 128 /* No MRUs below this */
+#define MAXMRU 16384 /* Normally limit MRU to this */
void lcp_init __ARGS((int));
-void lcp_activeopen __ARGS((int));
-void lcp_passiveopen __ARGS((int));
+void lcp_open __ARGS((int));
void lcp_close __ARGS((int));
void lcp_lowerup __ARGS((int));
void lcp_lowerdown __ARGS((int));
void lcp_input __ARGS((int, u_char *, int));
void lcp_protrej __ARGS((int));
void lcp_sprotrej __ARGS((int, u_char *, int));
+
+extern int lcp_warnloops; /* Warn about a loopback this often */
+#define DEFWARNLOOPS 10 /* Default value for above */
diff --git a/libexec/pppd/magic.c b/libexec/pppd/magic.c
index 87f2a7ac4cb3..44c7b29e87d2 100644
--- a/libexec/pppd/magic.c
+++ b/libexec/pppd/magic.c
@@ -17,6 +17,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: magic.c,v 1.2 1994/03/30 09:31:33 jkh Exp $";
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
diff --git a/libexec/pppd/magic.h b/libexec/pppd/magic.h
index a0479b2438f0..2a488d44c07d 100644
--- a/libexec/pppd/magic.h
+++ b/libexec/pppd/magic.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: magic.h,v 1.2 1994/03/30 09:31:34 jkh Exp $
*/
#include "args.h"
diff --git a/libexec/pppd/main.c b/libexec/pppd/main.c
index 557bc555e273..828d20bf818f 100644
--- a/libexec/pppd/main.c
+++ b/libexec/pppd/main.c
@@ -17,64 +17,45 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-/*
- * There are three scenarios:
- * 1. pppd used as daemon started from /etc/rc or perhaps /etc/ttys.
- * a. server
- * b. authentication necessary
- * c. want to use constant local ip addr
- * d. want to use constant remote ip addr, constant ip addr based on
- * authenticated user, or request ip addr
- * 2. pppd used on /dev/tty after remote login.
- * a. server
- * b. no authentication necessary or allowed
- * c. want to use constant local ip addr
- * d. want to use constant remote ip addr, constant ip addr based on
- * authenticated user, or request ip addr
- * 3. pppd used on line after tip'ing out.
- * a. client
- * b. remote end may request authentication
- * c. want to use constant local ip addr or request ip addr
- * d. want to use constant remote ip addr based on tip'd host, or
- * request remote ip addr
- */
-
-#ifdef __386BSD__
-#include <stdlib.h>
+#ifndef lint
+static char rcsid[] = "$Id: main.c,v 1.4 1994/03/30 09:31:35 jkh Exp $";
#endif
+#define SETSID
+
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
-#include <pwd.h>
#include <syslog.h>
#include <netdb.h>
#include <utmp.h>
-#ifdef sparc
-#include <alloca.h>
+/*
+ * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
+ * /etc/ppp/options exists.
+ */
+#ifndef REQ_SYSOPTIONS
+#define REQ_SYSOPTIONS 0
#endif
#ifdef STREAMS
-#include <sys/stream.h>
-#include <sys/stropts.h>
-#include <sys/termios.h>
-#else
+#undef SGTTY
+#endif
+
#ifdef SGTTY
#include <sgtty.h>
#else
+#ifndef sun
#include <sys/ioctl.h>
-#include <termios.h>
#endif
+#include <termios.h>
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <sys/time.h>
#include "callout.h"
@@ -82,19 +63,13 @@
#include <net/if.h>
#include <net/if_ppp.h>
-#ifdef STREAMS
-#include "ppp_str.h"
-#endif
-
-#define DEVNAME_SIZE 128 /* Buffer size for /dev filenames */
-
#include <string.h>
#ifndef BSD
#define BSD 43
#endif /*BSD*/
-#include <net/ppp.h>
+#include "ppp.h"
#include "magic.h"
#include "fsm.h"
#include "lcp.h"
@@ -116,55 +91,63 @@
#endif /*FALSE*/
#ifdef PIDPATH
-static char *pidpath = PIDPATH; /* filename in which pid will be */
- /* stored */
+static char *pidpath = PIDPATH; /* filename in which pid will be stored */
#else
static char *pidpath = _PATH_PIDFILE;
#endif /* PIDFILE */
-static char uinfopath[DEVNAME_SIZE];
-
/* interface vars */
-
char ifname[IFNAMSIZ]; /* Interface name */
-int ifunit; /* Interface unit number */
+int ifunit; /* Interface unit number */
char *progname; /* Name of this program */
-char hostname[MAX_HOSTNAME_LEN]; /* hostname */
-u_char hostname_len; /* hostname length */
-
-static pid_t pid; /* Our pid */
-static pid_t pgrpid; /* Process Group ID */
-static char pidfilename[DEVNAME_SIZE];
-
-static char devname[DEVNAME_SIZE] = "/dev/tty"; /* Device name */
-static int default_device = TRUE; /* use default device (stdin/out) */
-int fd; /* Device file descriptor */
-int s; /* Socket file descriptor */
-static int initdisc; /* Initial TTY discipline */
-#ifndef STREAMS
+char hostname[MAXNAMELEN]; /* Our hostname */
+char our_name[MAXNAMELEN];
+char remote_name[MAXNAMELEN];
+
+static pid_t pid; /* Our pid */
+static pid_t pgrpid; /* Process Group ID */
+static char pidfilename[MAXPATHLEN];
+
+char devname[MAXPATHLEN] = "/dev/tty"; /* Device name */
+int default_device = TRUE; /* use default device (stdin/out) */
+
+int fd; /* Device file descriptor */
+int s; /* Socket file descriptor */
+
#ifdef SGTTY
static struct sgttyb initsgttyb; /* Initial TTY sgttyb */
#else
-static struct termios inittermios; /* Initial TTY TIOCGETA */
-#endif
+static struct termios inittermios; /* Initial TTY termios */
#endif
-static int initfdflags; /* Initial file descriptor flags */
+static int initfdflags = -1; /* Initial file descriptor flags */
+
+static int restore_term; /* 1 => we've munged the terminal */
u_char outpacket_buf[MTU+DLLHEADERLEN]; /* buffer for outgoing packet */
static u_char inpacket_buf[MTU+DLLHEADERLEN]; /* buffer for incoming packet */
+int hungup; /* terminal has been hung up */
+
/* configured variables */
int debug = 0; /* Debug flag */
-static char user[80]; /* User name */
-static char passwd[80]; /* password */
-static char *connector = NULL; /* "connect" command */
-static int inspeed = 0; /* Input/Output speed */
-static u_long netmask = 0; /* netmask to use on ppp interface */
-static int crtscts = 0; /* use h/w flow control */
-static int nodetach = 0; /* don't fork */
+char user[MAXNAMELEN]; /* username for PAP */
+char passwd[MAXSECRETLEN]; /* password for PAP */
+char *connector = NULL; /* "connect" command */
+int inspeed = 0; /* Input/Output speed */
+u_long netmask = 0; /* netmask to use on ppp interface */
+int crtscts = 0; /* use h/w flow control */
+int nodetach = 0; /* don't fork */
+int modem = 0; /* use modem control lines */
+int auth_required = 0; /* require peer to authenticate */
+int defaultroute = 0; /* assign default route through interface */
+int proxyarp = 0; /* set entry in arp table */
+int persist = 0; /* re-initiate on termination */
+int answer = 0; /* wait for incoming call */
+int uselogin = 0; /* check PAP info against /etc/passwd */
+
/* prototypes */
static void hup __ARGS((int, int, struct sigcontext *, char *));
@@ -172,761 +155,657 @@ static void intr __ARGS((int, int, struct sigcontext *, char *));
static void term __ARGS((int, int, struct sigcontext *, char *));
static void alrm __ARGS((int, int, struct sigcontext *, char *));
static void io __ARGS((int, int, struct sigcontext *, char *));
-static void incdebug __ARGS((int, int, struct sigcontext *, char *));
-static void nodebug __ARGS((int, int, struct sigcontext *, char *));
-static void getuserpasswd __ARGS((void));
-
-static int setdebug __ARGS((int *, char ***));
-static int setpassive __ARGS((int *, char ***));
-static int noopt __ARGS((int *, char ***));
-static int setnovj __ARGS((int *, char ***));
-static int noupap __ARGS((int *, char ***));
-static int requpap __ARGS((int *, char ***));
-static int nochap __ARGS((int *, char ***));
-static int reqchap __ARGS((int *, char ***));
-static int setspeed __ARGS((int *, char ***));
-static int noaccomp __ARGS((int *, char ***));
-static int noasyncmap __ARGS((int *, char ***));
-static int noipaddr __ARGS((int *, char ***));
-static int nomagicnumber __ARGS((int *, char ***));
-static int setasyncmap __ARGS((int *, char ***));
-static int setvjmode __ARGS((int *, char ***));
-static int setmru __ARGS((int *, char ***));
-static int nomru __ARGS((int *, char ***));
-static int nopcomp __ARGS((int *, char ***));
-static int setconnector __ARGS((int *, char ***));
-static int setdomain __ARGS((int *, char ***));
-static int setnetmask __ARGS((int *, char ***));
-static int setcrtscts __ARGS((int *, char ***));
-static int setnodetach __ARGS((int *, char ***));
-static void cleanup __ARGS((int, caddr_t));
+static void incdebug __ARGS((int));
+static void nodebug __ARGS((int));
+void establish_ppp __ARGS((void));
+
+void cleanup __ARGS((int, caddr_t));
+void die __ARGS((int));
+void dumpbuffer __ARGS((unsigned char *, int, int));
#ifdef STREAMS
-static void str_restore __ARGS((void));
extern char *ttyname __ARGS((int));
-#define MAXMODULES 10 /* max number of module names that we can save */
-static struct modlist {
- char modname[FMNAMESZ+1];
-} str_modules[MAXMODULES];
-static int str_module_count = 0;
#endif
-
-/*
- * Valid arguments.
- */
-static struct cmd {
- char *cmd_name;
- int (*cmd_func)();
-} cmds[] = {
- "-all", noopt, /* Don't request/allow any options */
- "-ac", noaccomp, /* Disable Address/Control compress */
- "-am", noasyncmap, /* Disable asyncmap negotiation */
- "-as", setasyncmap, /* set the desired async map */
- "-d", setdebug, /* Increase debugging level */
- "-detach", setnodetach, /* don't fork */
- "-ip", noipaddr, /* Disable IP address negotiation */
- "-mn", nomagicnumber, /* Disable magic number negotiation */
- "-mru", nomru, /* Disable mru negotiation */
- "-p", setpassive, /* Set passive mode */
- "-pc", nopcomp, /* Disable protocol field compress */
- "+ua", requpap, /* Require UPAP authentication */
- "-ua", noupap, /* Don't allow UPAP authentication */
- "+chap", reqchap, /* Require CHAP authentication */
- "-chap", nochap, /* Don't allow CHAP authentication */
- "-vj", setnovj, /* disable VJ compression */
- "asyncmap", setasyncmap, /* set the desired async map */
- "connect", setconnector, /* A program to set up a connection */
- "crtscts", setcrtscts, /* set h/w flow control */
- "debug", setdebug, /* Increase debugging level */
- "domain", setdomain, /* Add given domain name to hostname*/
- "mru", setmru, /* Set MRU value for negotiation */
- "netmask", setnetmask, /* set netmask */
- "passive", setpassive, /* Set passive mode */
- "vjmode", setvjmode, /* set VJ compression mode */
- NULL
- };
-
+extern char *getlogin __ARGS((void));
/*
* PPP Data Link Layer "protocol" table.
* One entry per supported protocol.
*/
static struct protent {
- u_short protocol;
- void (*init)();
- void (*input)();
- void (*protrej)();
+ u_short protocol;
+ void (*init)();
+ void (*input)();
+ void (*protrej)();
} prottbl[] = {
- { LCP, lcp_init, lcp_input, lcp_protrej },
- { IPCP, ipcp_init, ipcp_input, ipcp_protrej },
- { UPAP, upap_init, upap_input, upap_protrej },
- { CHAP, ChapInit, ChapInput, ChapProtocolReject },
+ { LCP, lcp_init, lcp_input, lcp_protrej },
+ { IPCP, ipcp_init, ipcp_input, ipcp_protrej },
+ { UPAP, upap_init, upap_input, upap_protrej },
+ { CHAP, ChapInit, ChapInput, ChapProtocolReject },
};
-static char *usage = "pppd version %s patch level %d\n\
-Usage: %s [ arguments ], where arguments are:\n\
- -all Don't request/allow any options\n\
- -ac Disable Address/Control compression\n\
- -am Disable asyncmap negotiation\n\
- -as <n> Set the desired async map to hex <n>\n\
- -d Increase debugging level\n\
- -detach Don't fork to background\n\
- -ip Disable IP address negotiation\n\
- -mn Disable magic number negotiation\n\
- -mru Disable mru negotiation\n\
- -p Set passive mode\n\
- -pc Disable protocol field compression\n\
- +ua <p> Require UPAP authentication and use file <p> for\n\
- remote login data\n\
- -ua Don't allow UPAP authentication\n\
- +chap Require CHAP authentication\n\
- -chap Don't allow CHAP authentication\n\
- -vj disable VJ compression\n\
- connect <p> Invoke shell command <p> to set up the serial line\n\
- crtscts Use hardware RTS/CTS flow control\n\
- debug Increase debugging level\n\
- domain <d> Append domain name <d> to hostname for authentication\n\
- mru <n> Set MRU value to <n> for negotiation\n\
- netmask <n> Set interface netmask to <n>\n\
- passive Set passive mode\n\
- vjmode <m> VJ compression mode {old, rfc1172, rfc1132 (default)}\n\
- <device> Communicate over the named device\n\
- <speed> Set the baud rate to <speed>\n\
- <loc>:<rem> Set the local and/or remote interface IP\n\
- addresses. Either one may be omitted.\n";
-
-
main(argc, argv)
- int argc;
- char *argv[];
+ int argc;
+ char *argv[];
{
- int mask, i;
- struct sigvec sv;
- struct cmd *cmdp;
- FILE *pidfile;
-#ifndef STREAMS
- int pppdisc = PPPDISC;
-#endif
+ int mask, i;
+ struct sigvec sv;
+ struct cmd *cmdp;
+ FILE *pidfile;
+ char *p;
- /*
- * Initialize syslog system and magic number package.
- */
+ /*
+ * Initialize syslog system and magic number package.
+ */
#if BSD >= 43 || defined(sun)
- openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
- setlogmask(LOG_UPTO(LOG_INFO));
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
#else
- openlog("pppd", LOG_PID);
+ openlog("pppd", LOG_PID);
#define LOG_UPTO(x) (x)
#define setlogmask(x) (x)
#endif
#ifdef STREAMS
- if (ttyname(fileno(stdin)))
- strcpy(devname, ttyname(fileno(stdin)));
+ p = ttyname(fileno(stdin));
+ if (p)
+ strcpy(devname, p);
#endif
- magic_init();
-
- if (gethostname(hostname, MAX_HOSTNAME_LEN) < 0 ) {
- syslog(LOG_ERR, "couldn't get hostname: %m");
- exit(1);
- }
-
- /*
- * Initialize to the standard option set and then parse the command
- * line arguments.
- */
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
- (*prottbl[i].init)(0);
-
- progname = *argv;
- for (argc--, argv++; argc; ) {
- /*
- * First see if it's a command.
- */
- for (cmdp = cmds; cmdp->cmd_name; cmdp++)
- if (!strcmp(*argv, cmdp->cmd_name) &&
- (*cmdp->cmd_func)(&argc, &argv))
- break;
-
- /*
- * Maybe a tty name, speed or IP address?
- */
- if (cmdp->cmd_name == NULL &&
- !setdevname(&argc, &argv) &&
- !setspeed(&argc, &argv) &&
- !setipaddr(&argc, &argv)) {
- fprintf(stderr, usage, VERSION, PATCHLEVEL, progname);
- exit(1);
+ magic_init();
+
+ if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+ syslog(LOG_ERR, "couldn't get hostname: %m");
+ die(1);
}
- }
+ hostname[MAXNAMELEN-1] = 0;
- syslog(LOG_INFO, "Starting pppd %s patch level %d",
- VERSION, PATCHLEVEL);
+ pid = getpid();
- /*
- * Initialize state.
- */
+ if (!ppp_available()) {
+ fprintf(stderr, "Sorry - PPP is not available on this system\n");
+ exit(1);
+ }
+ /*
+ * Initialize to the standard option set, then parse, in order,
+ * the system options file, the user's options file, and the command
+ * line arguments.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
+ (*prottbl[i].init)(0);
+
+ progname = *argv;
+
+ if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS) ||
+ !options_from_user() ||
+ !parse_args(argc-1, argv+1))
+ die(1);
+ check_auth_options();
+ setipdefault();
+
+ p = getlogin();
+ if (p == NULL)
+ p = "(unknown)";
+ syslog(LOG_NOTICE, "pppd %s.%d started by %s, uid %d",
+ VERSION, PATCHLEVEL, p, getuid());
-#define SETSID
#ifdef SETSID
- if (default_device) {
- /* No device name was specified... inherit the old controlling
- terminal */
-
- if ((pgrpid = getpgrp(0)) < 0) {
- syslog(LOG_ERR, "getpgrp(0): %m");
- exit(1);
+ /*
+ * Make sure we can set the serial device to be our controlling terminal.
+ */
+ if (default_device) {
+ /*
+ * No device name was specified:
+ * we are in the device's session already.
+ */
+ if ((pgrpid = getpgrp(0)) < 0) {
+ syslog(LOG_ERR, "getpgrp(0): %m");
+ die(1);
+ }
+
+ } else {
+ /*
+ * Not default device: make sure we're not a process group leader,
+ * then become session leader of a new session (so we can make
+ * our device its controlling terminal and thus get SIGHUPs).
+ */
+ if (!nodetach) {
+ /* fork so we're not a process group leader */
+ if (pid = fork()) {
+ exit(0); /* parent is finished */
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
+ }
+ pid = getpid(); /* otherwise pid is 0 in child */
+ } else {
+ /*
+ * try to put ourself into our parent's process group,
+ * so we're not a process group leader
+ */
+ if (setpgrp(pid, getppid()) < 0)
+ syslog(LOG_WARNING, "setpgrp: %m");
+ }
+
+ /* create new session */
+ if ((pgrpid = setsid()) < 0) {
+ syslog(LOG_ERR, "setsid(): %m");
+ die(1);
+ }
}
- if (pgrpid != pid)
- syslog(LOG_WARNING, "warning... not a process group leader");
- }
- else /*default_device*/
- {
- /* become session leader... */
-
- if (!nodetach) {
- /* fork so we're not a process group leader */
- if (pid = fork()) {
- exit(0);
- }
- }
-#ifdef xxx
- else
- /* bag controlling terminal */
- if (ioctl(0, TIOCNOTTY) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCNOTTY): %m");
- exit(1);
- }
#endif
- /* create new session */
- if ((pgrpid = setsid()) < 0) {
- syslog(LOG_ERR, "setsid(): %m");
- exit(1);
- }
- }
+ /* Get an internet socket for doing socket ioctl's on. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket : %m");
+ die(1);
+ }
+
+ /*
+ * Compute mask of all interesting signals and install signal handlers
+ * for each. Only one signal handler may be active at a time. Therefore,
+ * all other signals should be masked when any handler is executing.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGALRM);
+ sigaddset(&mask, SIGIO);
+#ifdef STREAMS
+ sigaddset(&mask, SIGPOLL);
#endif
- /* open i/o device */
- if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
- syslog(LOG_ERR, "open(%s): %m", devname);
- exit(1);
- }
-
- /* drop dtr to hang up incase modem is off hook */
- if (!default_device) {
- setdtr(fd, FALSE);
- sleep(1);
- setdtr(fd, TRUE);
- }
-
- /* set device to be controlling tty */
- if (ioctl(fd, TIOCSCTTY) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
- exit(1);
- }
-
- /* run connection script */
- if (connector) {
- syslog(LOG_NOTICE, "Connecting with <%s>", connector);
- /* set line speed */
- set_up_tty(fd, 0);
- if (set_up_connection(connector, fd, fd) < 0) {
- syslog(LOG_ERR, "could not set up connection");
- setdtr(fd, FALSE);
- exit(1);
+#define SIGNAL(s, handler) { \
+ sv.sv_handler = handler; \
+ if (sigvec(s, &sv, NULL) < 0) { \
+ syslog(LOG_ERR, "sigvec(%d): %m", s); \
+ die(1); \
+ } \
}
- syslog(LOG_NOTICE, "Connected...");
- }
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "socket : %m");
- exit(1);
- }
-
- /* if we exit, then try and restore the stream */
-#ifdef sun
- on_exit(cleanup, NULL);
+
+ sv.sv_mask = mask;
+ sv.sv_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, intr); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGALRM, alrm); /* Timeout */
+ SIGNAL(SIGIO, io); /* Input available */
+#ifdef STREAMS
+ SIGNAL(SIGPOLL, io); /* Input available */
#endif
-
+
+ signal(SIGUSR1, incdebug); /* Increment debug flag */
+ signal(SIGUSR2, nodebug); /* Reset debug flag */
+
+ /*
+ * Block SIGIOs and SIGPOLLs for now
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGIO);
#ifdef STREAMS
- /* go through and save the name of all the modules, then pop em */
- while(1) {
- if(!ioctl(fd, I_LOOK, str_modules[str_module_count].modname))
- MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
- str_modules[str_module_count].modname))
- if(!ioctl(fd, I_POP, 0))
- str_module_count++;
- else
- break;
- }
-
- /* set line speed */
- set_up_tty(fd, 1);
-
- syslog(LOG_ERR, "about to push modules...");
-
- /* now push the async/fcs module */
- if(ioctl(fd, I_PUSH, "pppasync") < 0) {
- syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
- exit(1);
- }
- /* finally, push the ppp_if module that actually handles the */
- /* network interface */
- if(ioctl(fd, I_PUSH, "pppif") < 0) {
- syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
- exit(1);
- }
- if(ioctl(fd, I_SETSIG, S_INPUT) < 0) {
- syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
- exit(1);
- }
- /* read mode, message non-discard mode */
- if(ioctl(fd, I_SRDOPT, RMSGN) < 0) {
- syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
- exit(1);
- }
- /* Flush any waiting messages, or we'll never get SIGPOLL */
- if(ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
- syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
- exit(1);
- }
- /*
- * Find out which interface we were given.
- * (ppp_if handles this ioctl)
- */
- if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
- exit(1);
- }
-
- /* if debug, set debug flags in driver */
- {
- int flags = debug ? 0x3 : 0;
-syslog(LOG_INFO, "debug 0x%x, flags 0x%x", debug, flags);
- if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
- }
- }
-
- syslog(LOG_ERR, "done pushing modules, ifunit %d", ifunit);
-#else
- /* set line speed */
- set_up_tty(fd, 1);
-
- if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
- exit(1);
- }
- if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
- exit(1);
- }
-
- /*
- * Find out which interface we were given.
- */
- if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
- syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
- exit(1);
- }
+ sigaddset(&mask, SIGPOLL);
#endif
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ */
+ if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
+ syslog(LOG_ERR, "open(%s): %m", devname);
+ die(1);
+ }
+ hungup = 0;
- syslog(LOG_NOTICE, "Using interface ppp%d", ifunit);
- (void) sprintf(ifname, "ppp%d", ifunit);
- pid = getpid();
+ /* set device to be controlling tty */
+ if (!default_device && ioctl(fd, TIOCSCTTY) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
+ die(1);
+ }
- (void) sprintf(pidfilename, "%s/%s.pid", pidpath, ifname);
+ /* set line speed, flow control, etc. */
+ set_up_tty(fd);
- /* write pid to file */
+ /* run connection script */
+ if (connector) {
+ syslog(LOG_INFO, "Connecting with <%s>", connector);
- if ((pidfile = fopen(pidfilename, "w")) != NULL) {
- fprintf(pidfile, "%d\n", pid);
- (void) fclose(pidfile);
- }
+ /* drop dtr to hang up in case modem is off hook */
+ if (!default_device && modem) {
+ setdtr(fd, FALSE);
+ sleep(1);
+ setdtr(fd, TRUE);
+ }
- hostname_len = (u_char) strlen(hostname);
+ if (set_up_connection(connector, fd, fd) < 0) {
+ syslog(LOG_ERR, "could not set up connection");
+ setdtr(fd, FALSE);
+ die(1);
+ }
- MAINDEBUG((LOG_DEBUG, "hostname = %s", hostname))
-
-#ifdef SETSID
- if (default_device) {
- int id = tcgetpgrp(fd);
- if (id != pgrpid) {
- syslog(LOG_WARNING,
- "warning: pppd is not the leader of a forground process group");
+ syslog(LOG_INFO, "Connected...");
+ sleep(1); /* give it time to set up its terminal */
}
- }
- else
- if (tcsetpgrp(fd, pgrpid) < 0) {
- syslog(LOG_ERR, "tcsetpgrp(): %m");
- exit(1);
+
+ /* set up the serial device as a ppp interface */
+ establish_ppp();
+
+ syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+ (void) sprintf(ifname, "ppp%d", ifunit);
+
+ /* write pid to file */
+ (void) sprintf(pidfilename, "%s/%s.pid", pidpath, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "unable to create pid file: %m");
+ pidfilename[0] = 0;
+ }
+
+ /*
+ * Set process group of device to our process group so we can get
+ * SIGIOs and SIGHUPs.
+ */
+#ifdef SETSID
+ if (default_device) {
+ int id = tcgetpgrp(fd);
+ if (id != pgrpid) {
+ syslog(LOG_WARNING, "warning: not in tty's process group");
+ }
+ } else {
+ if (tcsetpgrp(fd, pgrpid) < 0) {
+ syslog(LOG_ERR, "tcsetpgrp(): %m");
+ die(1);
+ }
}
#else
- /* set process group on tty so we get SIGIO's */
- if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
- exit(1);
- }
+ /* set process group on tty so we get SIGIO's */
+ if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
+ die(1);
+ }
#endif
+
+ /*
+ * Record initial device flags, then set device to cause SIGIO
+ * signals to be generated.
+ */
+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
+ syslog(LOG_ERR, "fcntl(F_GETFL): %m");
+ die(1);
+ }
+ if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
+ syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
+ die(1);
+ }
- /*
- * Compute mask of all interesting signals and install signal handlers
- * for each. Only one signal handler may be active at a time. Therefore,
- * all other signals should be masked when any handler is executing.
- */
- mask = sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGALRM) |
- sigmask(SIGIO);
-#ifdef STREAMS
- mask |= sigmask(SIGPOLL);
-#endif
+ /*
+ * Block all signals, start opening the connection, and wait for
+ * incoming signals (reply, timeout, etc.).
+ */
+ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devname);
+ sigprocmask(SIG_BLOCK, &mask, NULL); /* Block signals now */
+ lcp_lowerup(0); /* XXX Well, sort of... */
+ lcp_open(0); /* Start protocol */
+ for (;;) {
+ sigpause(0); /* Wait for next signal */
+ }
+}
- sv.sv_handler = hup; /* Hangup */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGHUP, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGHUP)");
- exit(1);
- }
- sv.sv_handler = intr; /* Interrupt */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGINT, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGINT)");
- exit(1);
- }
- sv.sv_handler = term; /* Terminate */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGTERM, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGTERM)");
- exit(1);
- }
- sv.sv_handler = alrm; /* Timeout */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGALRM, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGALRM)");
- exit(1);
- }
- sv.sv_handler = io; /* Input available */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGIO, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGIO)");
- exit(1);
- }
-#ifdef STREAMS
- sv.sv_handler = io; /* Input available */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGPOLL, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGPOLL)");
- exit(1);
- }
-#endif
+#if B9600 == 9600
+/*
+ * XXX assume speed_t values numerically equal bits per second
+ * (so we can ask for any speed).
+ */
+#define translate_speed(bps) (bps)
-#ifdef __STDC__
- /* Increment debug flag */
- (void) signal(SIGUSR1, (void (*)(int))incdebug);
- /* Reset debug flag */
- (void) signal(SIGUSR2, (void (*)(int))nodebug);
#else
- /* Increment debug flag */
- (void) signal(SIGUSR1, (void (*)())incdebug);
- /* Reset debug flag */
- (void) signal(SIGUSR2, (void (*)())nodebug);
+/*
+ * List of valid speeds.
+ */
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
#endif
-
- /*
- * Record initial device flags, then set device to cause SIGIO
- * signals to be generated.
- */
- if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
- syslog(LOG_ERR, "fcntl(F_GETFL): %m");
- exit(1);
- }
- if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
- syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
- exit(1);
- }
-
- /*
- * Block all signals, start opening the connection, and wait for
- * incoming signals (reply, timeout, etc.).
- */
- syslog(LOG_INFO, "Connect: %s <--> %s", ifname, devname);
- sigblock(mask); /* Block signals now */
- lcp_lowerup(0); /* XXX Well, sort of... */
- if (lcp_wantoptions[0].passive)
- lcp_passiveopen(0); /* Start protocol in passive mode */
- else
- lcp_activeopen(0); /* Start protocol in active mode */
- for (;;) {
- sigpause(0); /* Wait for next signal */
-
- /* Need to read user/passwd? */
- if (upap[0].us_flags & UPAPF_UPPENDING) {
- sigsetmask(0); /* Allow other signals to occur */
- getuserpasswd(); /* Get user and passwd */
- upap[0].us_flags &= ~UPAPF_UPPENDING;
- upap[0].us_flags |= UPAPF_UPVALID;
- sigsetmask(mask); /* Disallow signals */
- upap_authwithpeer(0);
- }
- }
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Translate from bits/second to a speed_t.
+ */
+int
+translate_speed(bps)
+ int bps;
+{
+ struct speed *speedp;
+
+ if (bps == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ syslog(LOG_WARNING, "speed %d not supported", bps);
+ return 0;
}
+#endif
-set_up_tty(fd, flow)
-int fd;
-int flow;
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc.
+ */
+set_up_tty(fd)
+ int fd;
{
-#ifdef STREAMS
- int new_cflag;
- struct termios tios;
-
- if(ioctl(fd, TCGETS, (caddr_t) &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TCGETS): %m");
- exit(1);
- }
-
- new_cflag = CS8 | CREAD | HUPCL;
- new_cflag |= inspeed ? inspeed : (tios.c_cflag & CBAUD);
- if (flow)
- new_cflag |= crtscts ? CRTSCTS : 0;
-
- tios.c_cflag = new_cflag;
- tios.c_iflag = IGNBRK | IGNPAR;
- tios.c_oflag = 0;
- tios.c_lflag = 0;
-
- if(ioctl(fd, TCSETS, (caddr_t) &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TCSETS): %m");
- exit(1);
- }
-#else
-#ifdef SGTTY
- struct sgttyb sgttyb;
-
- /*
- * Put the tty in raw mode and set the discipline to PPP.
- */
- if (ioctl(fd, TIOCGETP, &initsgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
- exit(1);
- }
-
- sgttyb = initsgttyb;
- sgttyb.sg_flags = RAW | ANYP;
- if (inspeed)
- sgttyb.sg_ispeed = inspeed;
-
- if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
- exit(1);
- }
-#else
+#ifndef SGTTY
+ int speed;
struct termios tios;
- if (ioctl(fd, TIOCGETA, &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETA): %m");
- exit(1);
+ if (tcgetattr(fd, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ die(1);
}
- inittermios = tios;
+ if (!restore_term)
+ inittermios = tios;
- tios.c_cflag = CREAD | CS8 | HUPCL;
- if (flow)
- tios.c_cflag |= crtscts ? CRTSCTS : 0;
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CRTSCTS);
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (crtscts)
+ tios.c_cflag |= CRTSCTS;
+ if (!modem)
+ tios.c_cflag |= CLOCAL;
tios.c_iflag = IGNBRK | IGNPAR;
tios.c_oflag = 0;
tios.c_lflag = 0;
- tios.c_cc[VERASE] = tios.c_cc[VKILL] = 0;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
- if (inspeed) {
- tios.c_ispeed = inspeed;
- tios.c_ospeed = inspeed;
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed(&tios, speed);
+ cfsetispeed(&tios, speed);
}
- if (ioctl(fd, TIOCSETA, &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETA): %m");
- exit(1);
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ die(1);
+ }
+#else /* SGTTY */
+ int speed;
+ struct sgttyb sgttyb;
+
+ /*
+ * Put the tty in raw mode.
+ */
+ if (ioctl(fd, TIOCGETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
+ die(1);
+ }
+
+ if (!restore_term)
+ initsgttyb = sgttyb;
+
+ sgttyb.sg_flags = RAW | ANYP;
+ speed = translate_speed(inspeed);
+ if (speed)
+ sgttyb.sg_ispeed = speed;
+
+ if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+ die(1);
}
#endif
-#endif
+ restore_term = TRUE;
}
+
/*
* quit - Clean up state and exit.
*/
void
- quit()
+quit()
{
- syslog(LOG_NOTICE, "Quitting");
+ die(0);
+}
- if (fd == 0)
- return;
+/*
+ * die - like quit, except we can specify an exit status.
+ */
+void
+die(status)
+ int status;
+{
+ cleanup(0, NULL);
+ syslog(LOG_INFO, "Exit.");
+ exit(status);
+}
- if (fcntl(fd, F_SETFL, initfdflags) == -1) {
- syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
- exit(1);
- }
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+void
+cleanup(status, arg)
+ int status;
+ caddr_t arg;
+{
+ if (fd != 0) {
+ /* drop dtr to hang up */
+ if (modem)
+ setdtr(fd, FALSE);
-#ifdef STREAMS
- str_restore();
-#else
-#ifdef SGTTY
- if (ioctl(fd, TIOCSETP, &initsgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETP)");
- exit(1);
- }
-#else
- if (ioctl(fd, TIOCSETA, &inittermios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETA)");
- exit(1);
- }
+ if (fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
-#endif
- if (ioctl(fd, TIOCSETD, &initdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETD)");
- exit(1);
- }
-#endif
+ disestablish_ppp();
- /* drop dtr to hang up */
- setdtr(fd, FALSE);
+ if (restore_term) {
+#ifndef SGTTY
+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ syslog(LOG_ERR, "tcsetattr: %m");
+#else
+ if (ioctl(fd, TIOCSETP, &initsgttyb) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+#endif
+ }
- close(fd);
- fd = 0;
+ close(fd);
+ fd = 0;
+ }
- exit(0);
+ if (pidfilename[0] != 0 && unlink(pidfilename) < 0)
+ syslog(LOG_WARNING, "unable to unlink pid file: %m");
+ pidfilename[0] = 0;
}
static struct callout *callout = NULL; /* Callout list */
static struct timeval schedtime; /* Time last timeout was set */
-
/*
* timeout - Schedule a timeout.
*
* Note that this timeout takes the number of seconds, NOT hz (as in
* the kernel).
*/
-void timeout(func, arg, time)
- void (*func)();
- caddr_t arg;
- int time;
+void
+timeout(func, arg, time)
+ void (*func)();
+ caddr_t arg;
+ int time;
{
- struct itimerval itv;
- struct callout *newp, **oldpp;
+ struct itimerval itv;
+ struct callout *newp, **oldpp;
- MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
- (int) func, (int) arg, time))
+ MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
+ (int) func, (int) arg, time));
- /*
- * Allocate timeout.
- */
- if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
- syslog(LOG_ERR, "Out of memory in timeout()!");
- exit(1);
- }
- newp->c_arg = arg;
- newp->c_func = func;
+ /*
+ * Allocate timeout.
+ */
+ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
+ syslog(LOG_ERR, "Out of memory in timeout()!");
+ die(1);
+ }
+ newp->c_arg = arg;
+ newp->c_func = func;
- /*
- * Find correct place to link it in and decrement its time by the
- * amount of time used by preceding timeouts.
- */
- for (oldpp = &callout;
- *oldpp && (*oldpp)->c_time <= time;
- oldpp = &(*oldpp)->c_next)
- time -= (*oldpp)->c_time;
- newp->c_time = time;
- newp->c_next = *oldpp;
- if (*oldpp)
- (*oldpp)->c_time -= time;
- *oldpp = newp;
+ /*
+ * Find correct place to link it in and decrement its time by the
+ * amount of time used by preceding timeouts.
+ */
+ for (oldpp = &callout;
+ *oldpp && (*oldpp)->c_time <= time;
+ oldpp = &(*oldpp)->c_next)
+ time -= (*oldpp)->c_time;
+ newp->c_time = time;
+ newp->c_next = *oldpp;
+ if (*oldpp)
+ (*oldpp)->c_time -= time;
+ *oldpp = newp;
- /*
- * If this is now the first callout then we have to set a new
- * itimer.
- */
- if (callout == newp) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout->c_time;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
- }
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+ /*
+ * If this is now the first callout then we have to set a new
+ * itimer.
+ */
+ if (callout == newp) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
/*
* untimeout - Unschedule a timeout.
*/
-void untimeout(func, arg)
- void (*func)();
- caddr_t arg;
+void
+untimeout(func, arg)
+ void (*func)();
+ caddr_t arg;
{
+ struct itimerval itv;
+ struct callout **copp, *freep;
+ int reschedule = 0;
- struct itimerval itv;
- struct callout **copp, *freep;
- int reschedule = 0;
+ MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg));
- MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg))
-
- /*
- * If the first callout is unscheduled then we have to set a new
- * itimer.
- */
- if (callout &&
- callout->c_func == func &&
- callout->c_arg == arg)
- reschedule = 1;
+ /*
+ * If the first callout is unscheduled then we have to set a new
+ * itimer.
+ */
+ if (callout &&
+ callout->c_func == func &&
+ callout->c_arg == arg)
+ reschedule = 1;
- /*
- * Find first matching timeout. Add its time to the next timeouts
- * time.
- */
- for (copp = &callout; *copp; copp = &(*copp)->c_next)
- if ((*copp)->c_func == func &&
- (*copp)->c_arg == arg) {
- freep = *copp;
- *copp = freep->c_next;
- if (*copp)
- (*copp)->c_time += freep->c_time;
- (void) free((char *) freep);
- break;
- }
+ /*
+ * Find first matching timeout. Add its time to the next timeouts
+ * time.
+ */
+ for (copp = &callout; *copp; copp = &(*copp)->c_next)
+ if ((*copp)->c_func == func &&
+ (*copp)->c_arg == arg) {
+ freep = *copp;
+ *copp = freep->c_next;
+ if (*copp)
+ (*copp)->c_time += freep->c_time;
+ (void) free((char *) freep);
+ break;
+ }
- if (reschedule) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout ? callout->c_time : 0;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
- }
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+ if (reschedule) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout ? callout->c_time : 0;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
@@ -934,60 +813,29 @@ void untimeout(func, arg)
* adjtimeout - Decrement the first timeout by the amount of time since
* it was scheduled.
*/
-void adjtimeout()
+void
+adjtimeout()
{
- struct timeval tv;
- int timediff;
+ struct timeval tv;
+ int timediff;
- if (callout == NULL)
- return;
- /*
- * Make sure that the clock hasn't been warped dramatically.
- * Account for recently expired, but blocked timer by adding
- * small fudge factor.
- */
- if (gettimeofday(&tv, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
- }
- timediff = tv.tv_sec - schedtime.tv_sec;
- if (timediff < 0 ||
- timediff > callout->c_time + 1)
- return;
+ if (callout == NULL)
+ return;
+ /*
+ * Make sure that the clock hasn't been warped dramatically.
+ * Account for recently expired, but blocked timer by adding
+ * small fudge factor.
+ */
+ if (gettimeofday(&tv, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ timediff = tv.tv_sec - schedtime.tv_sec;
+ if (timediff < 0 ||
+ timediff > callout->c_time + 1)
+ return;
- callout->c_time -= timediff; /* OK, Adjust time */
-}
-
-
-/*
- * output - Output PPP packet.
- */
-void
- output(unit, p, len)
-int unit;
-u_char *p;
-int len;
-{
-#ifdef STREAMS
- struct strbuf str;
-
- str.len = len;
- str.buf = (caddr_t) p;
- if(putmsg(fd, NULL, &str, 0) < 0) {
- syslog(LOG_ERR, "putmsg");
- exit(1);
- }
-#else
- if (unit != 0) {
- MAINDEBUG((LOG_WARNING, "output: unit != 0!"))
- abort();
- }
-
- if (write(fd, p, len) < 0) {
- syslog(LOG_ERR, "write");
- exit(1);
- }
-#endif
+ callout->c_time -= timediff; /* OK, Adjust time */
}
@@ -998,14 +846,18 @@ int len;
*/
/*ARGSUSED*/
static void
- hup(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+hup(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Hangup (SIGHUP)");
- adjtimeout(); /* Adjust timeouts */
- lcp_lowerdown(0); /* Reset connection */
+ syslog(LOG_INFO, "Hangup (SIGHUP)");
+
+ hungup = 1; /* they hung up on us! */
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_lowerdown(0); /* Reset connection */
+ quit(); /* and die */
}
@@ -1016,14 +868,15 @@ char *addr;
*/
/*ARGSUSED*/
static void
- term(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+term(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Terminate signal received.");
- adjtimeout(); /* Adjust timeouts */
- lcp_close(0); /* Close connection */
+ syslog(LOG_INFO, "Terminating link.");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
}
@@ -1034,14 +887,15 @@ char *addr;
*/
/*ARGSUSED*/
static void
- intr(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+intr(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Interrupt received. Exiting.");
- adjtimeout(); /* Adjust timeouts */
- lcp_close(0); /* Close connection */
+ syslog(LOG_INFO, "Interrupt received: terminating link");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
}
@@ -1052,47 +906,47 @@ char *addr;
*/
/*ARGSUSED*/
static void
- alrm(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+alrm(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- struct itimerval itv;
- struct callout *freep;
-
- MAINDEBUG((LOG_DEBUG, "Alarm"))
-
- /*
- * Call and free first scheduled timeout and any that were scheduled
- * for the same time.
- */
- while (callout) {
- freep = callout; /* Remove entry before calling */
- callout = freep->c_next;
- (*freep->c_func)(freep->c_arg);
- (void) free((char *) freep);
- if (callout && callout->c_time)
- break;
- }
-
- /*
- * Set a new itimer if there are more timeouts scheduled.
- */
- if (callout) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout->c_time;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
+ struct itimerval itv;
+ struct callout *freep;
+
+ MAINDEBUG((LOG_DEBUG, "Alarm"));
+
+ /*
+ * Call and free first scheduled timeout and any that were scheduled
+ * for the same time.
+ */
+ while (callout) {
+ freep = callout; /* Remove entry before calling */
+ callout = freep->c_next;
+ (*freep->c_func)(freep->c_arg);
+ (void) free((char *) freep);
+ if (callout && callout->c_time)
+ break;
}
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+
+ /*
+ * Set a new itimer if there are more timeouts scheduled.
+ */
+ if (callout) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
@@ -1103,161 +957,112 @@ char *addr;
*/
/*ARGSUSED*/
static void
- io(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+io(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- int len, i;
- u_char *p;
- u_short protocol;
- fd_set fdset;
- struct timeval notime;
- int ready;
-#ifdef STREAMS
- struct strbuf str;
-#endif
+ int len, i;
+ u_char *p;
+ u_short protocol;
+ fd_set fdset;
+ struct timeval notime;
+ int ready;
+
+ MAINDEBUG((LOG_DEBUG, "IO signal received"));
+ adjtimeout(); /* Adjust timeouts */
+
+ /* we do this to see if the SIGIO handler is being invoked for input */
+ /* ready, or for the socket buffer hitting the low-water mark. */
+
+ notime.tv_sec = 0;
+ notime.tv_usec = 0;
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+
+ if ((ready = select(32, &fdset, (fd_set *) NULL, (fd_set *) NULL,
+ &notime)) == -1) {
+ syslog(LOG_ERR, "Error in io() select: %m");
+ die(1);
+ }
+
+ if (ready == 0) {
+ MAINDEBUG((LOG_DEBUG, "IO non-input ready SIGIO occured."));
+ return;
+ }
+ /* Yup, this is for real */
+ for (;;) { /* Read all available packets */
+ p = inpacket_buf; /* point to beginning of packet buffer */
- MAINDEBUG((LOG_DEBUG, "IO signal received"))
- adjtimeout(); /* Adjust timeouts */
+ len = read_packet(inpacket_buf);
+ if (len < 0)
+ return;
- /* we do this to see if the SIGIO handler is being invoked for input */
- /* ready, or for the socket buffer hitting the low-water mark. */
+ if (len == 0) {
+ syslog(LOG_ERR, "End of file on fd!");
+ die(1);
+ }
- notime.tv_sec = 0;
- notime.tv_usec = 0;
+ if (len < DLLHEADERLEN) {
+ MAINDEBUG((LOG_INFO, "io(): Received short packet."));
+ return;
+ }
- FD_ZERO(&fdset);
- FD_SET(fd, &fdset);
-
- if ((ready = select(32, &fdset, (fd_set *) NULL, (fd_set *) NULL,
- &notime)) == -1) {
- syslog(LOG_ERR, "Error in io() select: %m");
- exit(1);
- }
-
- if (ready == 0) {
- MAINDEBUG((LOG_DEBUG, "IO non-input ready SIGIO occured."));
- return;
- }
+ p += 2; /* Skip address and control */
+ GETSHORT(protocol, p);
+ len -= DLLHEADERLEN;
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ */
+ if (protocol != LCP && lcp_fsm[0].state != OPENED) {
+ MAINDEBUG((LOG_INFO,
+ "io(): Received non-LCP packet when LCP not open."));
+ if (debug)
+ dumpbuffer(inpacket_buf, len + DLLHEADERLEN, LOG_INFO);
+ return;
+ }
- /* Yup, this is for real */
- for (;;) { /* Read all available packets */
- p = inpacket_buf; /* point to beggining of packet buffer */
+ /*
+ * Upcall the proper protocol input routine.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
+ if (prottbl[i].protocol == protocol) {
+ (*prottbl[i].input)(0, p, len);
+ break;
+ }
-#ifdef STREAMS
- str.maxlen = MTU+DLLHEADERLEN;
- str.buf = (caddr_t) p;
- i = 0;
- len = getmsg(fd, NULL, &str, &i);
- if(len < 0) {
- if(errno == EAGAIN || errno == EWOULDBLOCK) {
- return;
- }
- syslog(LOG_ERR, "getmsg(fd) %m");
- exit(1);
- }
- else if(len)
- MAINDEBUG((LOG_DEBUG, "getmsg returns with length 0x%x",len))
-
- if(str.len < 0) {
- MAINDEBUG((LOG_DEBUG, "getmsg short return length %d",
- str.len))
- return;
- }
-
- len = str.len;
-#else
- if ((len = read(fd, p, MTU + DLLHEADERLEN)) < 0) {
- if (errno == EWOULDBLOCK) {
- MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"))
- return;
- }
- else {
- syslog(LOG_ERR, "read(fd): %m");
- exit(1);
- }
- }
- else
-#endif
- if (len == 0) {
- syslog(LOG_ERR, "End of file on fd!");
- exit(1);
- }
-
- if (len < DLLHEADERLEN) {
- MAINDEBUG((LOG_INFO, "io(): Received short packet."))
- return;
- }
-
- p += 2; /* Skip address and control */
- GETSHORT(protocol, p);
- len -= DLLHEADERLEN;
-
- /*
- * Toss all non-LCP packets unless LCP is OPEN.
- */
- if (protocol != LCP && lcp_fsm[0].state != OPEN) {
- MAINDEBUG((LOG_INFO, "io(): Received non-LCP packet and LCP is not in open state."))
- dumpbuffer(inpacket_buf, len + DLLHEADERLEN, LOG_ERR);
- return;
- }
-
- /*
- * Upcall the proper protocol input routine.
- */
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
- if (prottbl[i].protocol == protocol) {
- (*prottbl[i].input)(0, p, len);
- break;
- }
-
- if (i == sizeof (prottbl) / sizeof (struct protent)) {
- syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
- protocol);
- p -= DLLHEADERLEN;
- len += DLLHEADERLEN;
- lcp_sprotrej(0, p, len);
+ if (i == sizeof (prottbl) / sizeof (struct protent)) {
+ syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
+ protocol);
+ lcp_sprotrej(0, p - DLLHEADERLEN, len + DLLHEADERLEN);
+ }
}
- }
}
/*
- * cleanup - clean_up before we exit
- */
-/* ARGSUSED */
-static void
- cleanup(status, arg)
-int status;
-caddr_t arg;
-{
- adjtimeout();
- lcp_lowerdown(0);
- if (unlink(pidfilename) < 0)
- syslog(LOG_WARNING, "unable to unlink pid file: %m");
-}
-
-
-/*
* demuxprotrej - Demultiplex a Protocol-Reject.
*/
void
- demuxprotrej(unit, protocol)
-int unit;
-u_short protocol;
+demuxprotrej(unit, protocol)
+ int unit;
+ u_short protocol;
{
- int i;
-
- /*
- * Upcall the proper Protocol-Reject routine.
- */
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
- if (prottbl[i].protocol == protocol) {
- (*prottbl[i].protrej)(unit);
- return;
- }
- syslog(LOG_WARNING, "demuxprotrej: Unrecognized Protocol-Reject for protocol %d!", protocol);
+ int i;
+
+ /*
+ * Upcall the proper Protocol-Reject routine.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
+ if (prottbl[i].protocol == protocol) {
+ (*prottbl[i].protrej)(unit);
+ return;
+ }
+
+ syslog(LOG_WARNING,
+ "demuxprotrej: Unrecognized Protocol-Reject for protocol %d!",
+ protocol);
}
@@ -1268,14 +1073,12 @@ u_short protocol;
*/
/*ARGSUSED*/
static void
- incdebug(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+incdebug(sig)
+ int sig;
{
- syslog(LOG_NOTICE, "Debug turned ON, Level %d", debug);
- setlogmask(LOG_UPTO(LOG_DEBUG));
- debug++;
+ syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ debug++;
}
@@ -1286,913 +1089,82 @@ char *addr;
*/
/*ARGSUSED*/
static void
- nodebug(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
-{
- setlogmask(LOG_UPTO(LOG_WARNING));
- debug = 0;
-}
-
-
-/*
- * setdebug - Set debug (command line argument).
- */
-static int
- setdebug(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- debug++;
- setlogmask(LOG_UPTO(LOG_DEBUG));
- --*argcp, ++*argvp;
- return (1);
-}
-
-/*
- * noopt - Disable all options.
- */
-static int
- noopt(argcp, argvp)
-int *argcp;
-char ***argvp;
+nodebug(sig)
+ int sig;
{
- bzero((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
- bzero((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
- bzero((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
- bzero((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setconnector - Set a program to connect to a serial line
- */
-static int
- setconnector(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
-
- --*argcp, ++*argvp;
-
- connector = strdup(**argvp);
- if (connector == NULL) {
- syslog(LOG_ERR, "cannot allocate space for connector string");
- exit(1);
- }
-
- --*argcp, ++*argvp;
- return (1);
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ debug = 0;
}
/*
* set_up_connection - run a program to initialize the serial connector
*/
-int set_up_connection(program, in, out)
- char *program;
- int in, out;
-{
- int pid;
- int flags;
- int status;
-
- flags = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
- pid = fork();
-
- if (pid < 0) {
- syslog(LOG_ERR, "fork");
- exit(1);
- }
-
- if (pid == 0) {
- (void) setreuid(getuid(), getuid());
- (void) setregid(getgid(), getgid());
- (void) sigsetmask(flags);
- (void) dup2(in, 0);
- (void) dup2(out, 1);
- (void) execl("/bin/sh", "sh", "-c", program, (char *)0);
- syslog(LOG_ERR, "could not exec /bin/sh");
- _exit(99);
- }
- else {
- while (waitpid(pid, &status, 0) != pid) {
- if (errno == EINTR)
- continue;
- syslog(LOG_ERR, "waiting for connection process");
- exit(1);
- }
- (void) sigsetmask(flags);
- }
- return (status == 0 ? 0 : -1);
-}
-
-/*
- * noaccomp - Disable Address/Control field compression negotiation.
- */
-static int
- noaccomp(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_accompression = 0;
- lcp_allowoptions[0].neg_accompression = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noasyncmap - Disable async map negotiation.
- */
-static int
- noasyncmap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_asyncmap = 0;
- lcp_allowoptions[0].neg_asyncmap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noipaddr - Disable IP address negotiation.
- */
-static int
- noipaddr(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- ipcp_wantoptions[0].neg_addrs = 0;
- ipcp_allowoptions[0].neg_addrs = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nomagicnumber - Disable magic number negotiation.
- */
-static int
- nomagicnumber(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_magicnumber = 0;
- lcp_allowoptions[0].neg_magicnumber = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nomru - Disable mru negotiation.
- */
-static int
- nomru(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_mru = 0;
- lcp_allowoptions[0].neg_mru = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setmru - Set MRU for negotiation.
- */
-static int
- setmru(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- --*argcp, ++*argvp;
- lcp_wantoptions[0].mru = atoi(**argvp);
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nopcomp - Disable Protocol field compression negotiation.
- */
-static int
- nopcomp(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_pcompression = 0;
- lcp_allowoptions[0].neg_pcompression = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setpassive - Set passive mode.
- */
-static int
- setpassive(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].passive = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noupap - Disable UPAP authentication.
- */
-static int
- noupap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_allowoptions[0].neg_upap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * requpap - Require UPAP authentication.
- */
-static int
- requpap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- FILE * ufile;
- struct stat sbuf;
-
- lcp_wantoptions[0].neg_upap = 1;
- lcp_allowoptions[0].neg_upap = 0;
- --*argcp, ++*argvp;
- strcpy(uinfopath, **argvp);
- --*argcp, ++*argvp;
-
- /* open user info file */
-
- if ((ufile = fopen(uinfopath, "r")) == NULL) {
- fprintf(stderr, "unable to open user login data file %s\n", uinfopath);
- exit(1);
- };
-
- if (fstat(fileno(ufile), &sbuf) < 0) {
- perror("cannot stat user login data file!");
- exit(1);
- }
- if ((sbuf.st_mode & 077) != 0)
- syslog(LOG_WARNING, "Warning - user info file has world and/or group access!\n");
-
- /* get username */
- fgets(user, sizeof (user) - 1, ufile);
- if (strlen(user) == 0) {
- fprintf(stderr, "Unable to get user name from user login data file.\n");
- exit(2);
- }
- /* get rid of newline */
- user[strlen(user) - 1] = '\000';
-
- fgets(passwd, sizeof(passwd) - 1, ufile);
-
- if (strlen(passwd) == 0) {
- fprintf(stderr, "Unable to get password from user login data file.\n");
- exit(2);
- }
-
- passwd[strlen(passwd) - 1] = '\000';
-
- return (1);
-}
-
-
-/*
- * nochap - Disable CHAP authentication.
- */
-static int
- nochap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_allowoptions[0].neg_chap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * reqchap - Require CHAP authentication.
- */
-static int
- reqchap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_chap = 1;
- lcp_allowoptions[0].neg_chap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setvjmode - Set vj compression mode
- */
-
-static int
- setvjmode(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- extern int ipcp_vj_mode;
-
- --*argcp, ++*argvp;
-
- if (!strcmp(**argvp, "old")) { /* "old" mode */
- ipcp_vj_setmode(IPCP_VJMODE_OLD);
- }
-
- else if (!strcmp(**argvp, "rfc1172")) { /* "rfc1172" mode*/
- ipcp_vj_setmode(IPCP_VJMODE_RFC1172);
- }
-
- else if (!strcmp(**argvp, "rfc1332")) { /* "rfc1332" default mode */
- ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
- }
- else {
- syslog(LOG_WARNING,
- "Unknown vj compression mode %s. Defaulting to RFC1332", **argvp);
- ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
- }
- --*argcp, ++*argvp;
-
- return (1);
-}
-/*
- * setnovj - diable vj compression
- */
-
-static int
- setnovj(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- extern int ipcp_vj_mode;
-
- --*argcp, ++*argvp;
- ipcp_wantoptions[0].neg_vj = 0;
- ipcp_allowoptions[0].neg_vj = 0;
-
- return (1);
-}
-
-/*
- * setdomain - Set domain name to append to hostname
- */
-static int
- setdomain(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
-
- --*argcp, ++*argvp;
-
- strcat(hostname, **argvp);
- hostname_len = strlen(hostname);
-
- --*argcp, ++*argvp;
-
- return (1);
-}
-
-/*
- * Valid speeds.
- */
-struct speed {
- int speed_int, speed_val;
-} speeds[] = {
-#ifdef B50
- { 50, B50 },
-#endif
-#ifdef B75
- { 75, B75 },
-#endif
-#ifdef B110
- { 110, B110 },
-#endif
-#ifdef B150
- { 150, B150 },
-#endif
-#ifdef B200
- { 200, B200 },
-#endif
-#ifdef B300
- { 300, B300 },
-#endif
-#ifdef B600
- { 600, B600 },
-#endif
-#ifdef B1200
- { 1200, B1200 },
-#endif
-#ifdef B1800
- { 1800, B1800 },
-#endif
-#ifdef B2000
- { 2000, B2000 },
-#endif
-#ifdef B2400
- { 2400, B2400 },
-#endif
-#ifdef B3600
- { 3600, B3600 },
-#endif
-#ifdef B4800
- { 4800, B4800 },
-#endif
-#ifdef B7200
- { 7200, B7200 },
-#endif
-#ifdef B9600
- { 9600, B9600 },
-#endif
-#ifdef EXTA
- { 19200, EXTA },
-#endif
-#ifdef EXTB
- { 38400, EXTB },
-#endif
-#ifdef B57600
- { 57600, B57600 },
-#endif
-#ifdef B115200
- { 115200, B115200 },
-#endif
- { 0, 0 }
-};
-
-static int
- setasyncmap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- unsigned long asyncmap;
-
- asyncmap = 0xffffffff;
- ++*argvp;
- sscanf(**argvp,"%lx",&asyncmap);
- ++*argvp;
- lcp_wantoptions[0].asyncmap = asyncmap;
- *argcp -= 2;
- return(1);
-}
-
-/*
- * setspeed - Set the speed.
- */
-static int
- setspeed(argcp, argvp)
-int *argcp;
-char ***argvp;
+int
+set_up_connection(program, in, out)
+ char *program;
+ int in, out;
{
- int speed;
- struct speed *speedp;
-
- speed = atoi(**argvp);
- for (speedp = speeds; speedp->speed_int; speedp++)
- if (speed == speedp->speed_int) {
- inspeed = speedp->speed_val;
- --*argcp, ++*argvp;
- return (1);
- }
- return (0);
-}
+ int pid;
+ int status;
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &mask, &mask);
-/*
- * setdevname - Set the device name.
- */
-int setdevname(argcp, argvp)
- int *argcp;
- char ***argvp;
-{
- char dev[DEVNAME_SIZE];
- char *cp = **argvp;
- struct stat statbuf;
- char *tty, *ttyname();
-
- if (strncmp("/dev/", cp, sizeof ("/dev/") - 1)) {
- (void) sprintf(dev, "/dev/%s", cp);
- cp = dev;
- }
-
- /*
- * Check if there is a device by this name.
- */
- if (stat(cp, &statbuf) < 0) {
- if (errno == ENOENT)
- return (0);
- syslog(LOG_ERR, cp);
- exit(1);
- }
-
- (void) strcpy(devname, cp);
- default_device = FALSE;
- --*argcp, ++*argvp;
-
- /*
- * If we haven't already decided to require authentication,
- * or we are running ppp on the control terminal, then we can
- * allow authentication to be requested.
- */
- if ((tty = ttyname(fileno(stdin))) == NULL)
- tty = ""; /* running from init means no stdin. Null kills strcmp -KWK */
- if (lcp_wantoptions[0].neg_upap == 0 &&
- strcmp(devname, "/dev/tty") &&
- strcmp(devname, tty)) {
- lcp_wantoptions[0].neg_upap = 0;
- lcp_allowoptions[0].neg_upap = 1;
- }
- return (1);
-}
-
-
-/*
- * setipaddr - Set the IP address
- */
-int setipaddr(argcp, argvp)
- int *argcp;
- char ***argvp;
-{
- u_long local, remote;
- struct hostent *hp;
- char *colon, *index();
-
- /*
- * IP address pair separated by ":".
- */
- if ((colon = index(**argvp, ':')) == NULL)
- return (0);
+ pid = fork();
- /*
- * If colon first character, then no local addr.
- */
- if (colon == **argvp) {
- local = 0l;
- ++colon;
- }
- else {
- *colon++ = '\0';
- if ((local = inet_addr(**argvp)) == -1) {
- if ((hp = gethostbyname(**argvp)) == NULL) {
- syslog(LOG_WARNING, "unknown host: %s", **argvp);
- goto ret;
- }
- bcopy(hp->h_addr, (char *) &local, hp->h_length);
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
}
- }
- /*
- * If colon last character, then no remote addr.
- */
- if (*colon == '\0')
- remote = 0l;
- else {
- if ((remote = inet_addr(colon)) == -1) {
- if ((hp = gethostbyname(colon)) == NULL) {
- syslog(LOG_WARNING,"unknown host: %s", colon);
- goto ret;
- }
- bcopy(hp->h_addr, (char *) &remote, hp->h_length);
+ if (pid == 0) {
+ setreuid(getuid(), getuid());
+ setregid(getgid(), getgid());
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ dup2(in, 0);
+ dup2(out, 1);
+ execl("/bin/sh", "sh", "-c", program, (char *)0);
+ syslog(LOG_ERR, "could not exec /bin/sh: %m");
+ _exit(99);
+ /* NOTREACHED */
}
- }
-
- ipcp_wantoptions[0].neg_addrs = 1;
- ipcp_wantoptions[0].ouraddr = local;
- ipcp_wantoptions[0].hisaddr = remote;
-
- ret:
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setnetmask(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- u_long mask;
-
- --*argcp, ++*argvp;
- if ((mask = inet_addr(**argvp)) == -1) {
- fprintf(stderr, "Invalid netmask %s\n", **argvp);
- exit(1);
- }
-
- netmask = mask;
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setcrtscts(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- crtscts = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setnodetach(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- nodetach = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-/*
- * getuserpasswd - Get the user name and passwd.
- */
-static void
- getuserpasswd()
-{
-
- upap[0].us_user = user;
- upap[0].us_userlen = strlen(upap[0].us_user);
- upap[0].us_passwd = passwd;
- upap[0].us_passwdlen = strlen(upap[0].us_passwd);
-}
-
-
-/*
- * login - Check the user name and passwd and login the user.
- *
- * returns:
- * UPAP_AUTHNAK: Login failed.
- * UPAP_AUTHACK: Login succeeded.
- * In either case, msg points to an appropriate message.
- */
-u_char
- login(user, userlen, passwd, passwdlen, msg, msglen)
-char *user;
-int userlen;
-char *passwd;
-int passwdlen;
-char **msg;
-int *msglen;
-{
- struct passwd *pw;
- char *epasswd, *crypt();
- static int attempts = 0;
- char *tty, *rindex();
- char *tmp_passwd, *tmp_user;
-
- /* why alloca.h doesn't define what alloca() returns is a mystery */
- /* seems to be defined in stdlib.h for FreeBSD, rgrimes */
-
-#ifdef sparc
- char *__builtin_alloca __ARGS((int));
-#else
-#ifndef __386BSD__
- char *alloca __ARGS((int));
-#endif /* !__386BSD__ */
-#endif /*sparc*/
- tmp_passwd = alloca(passwdlen + 1); /* we best make copies before */
- /* null terminating the string */
- if (tmp_passwd == NULL) {
- syslog(LOG_ERR, "alloca failed");
- exit(1);
- }
- bcopy(passwd, tmp_passwd, passwdlen);
- tmp_passwd[passwdlen] = '\0';
-
- tmp_user = alloca(userlen + 1);
- if (tmp_user == NULL) {
- syslog(LOG_ERR, "alloca failed");
- exit(1);
- }
- bcopy(user, tmp_user, userlen);
- tmp_user[userlen] = '\0';
-
- if ((pw = getpwnam(tmp_user)) == NULL) {
- *msg = "Login incorrect";
- *msglen = strlen(*msg);
- syslog(LOG_WARNING, "upap login userid '%s' incorrect",tmp_user);
- return (UPAP_AUTHNAK);
- }
-
- /*
- * XXX If no passwd, let them login without one.
- */
- if (pw->pw_passwd == '\0') {
- *msg = "Login ok";
- *msglen = strlen(*msg);
- return (UPAP_AUTHACK);
- }
-
- epasswd = crypt(tmp_passwd, pw->pw_passwd);
- if (strcmp(epasswd, pw->pw_passwd)) {
- *msg = "Login incorrect";
- *msglen = strlen(*msg);
- syslog(LOG_WARNING, "upap login password '%s' incorrect", tmp_passwd);
- /*
- * Frustrate passwd stealer programs.
- * Allow 10 tries, but start backing off after 3 (stolen from login).
- * On 10'th, drop the connection.
- */
- if (attempts++ >= 10) {
- syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
- attempts, devname, tmp_user);
- lcp_close(0); /* Drop DTR? */
+ while (waitpid(pid, &status, 0) != pid) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "waiting for connection process: %m");
+ die(1);
}
- if (attempts > 3)
- sleep((u_int) (attempts - 3) * 5);
- return (UPAP_AUTHNAK);
- }
-
- attempts = 0; /* Reset count */
- *msg = "Login ok";
- *msglen = strlen(*msg);
- syslog(LOG_NOTICE, "user %s logged in", tmp_user);
- tty = rindex(devname, '/');
- if (tty == NULL)
- tty = devname;
- else
- tty++;
- logwtmp(tty, tmp_user, ""); /* Add wtmp login entry */
-
- return (UPAP_AUTHACK);
-}
-
+ sigprocmask(SIG_SETMASK, &mask, NULL);
-/*
- * logout - Logout the user.
- */
-void logout()
-{
- char *tty;
-
- tty = rindex(devname, '/');
- if (tty == NULL)
- tty = devname;
- else
- tty++;
- logwtmp(tty, "", ""); /* Add wtmp logout entry */
+ return (status == 0 ? 0 : -1);
}
/*
- * getuseropt - Get the options from /etc/hosts.ppp for this user.
- */
-int getuseropt(user)
- char *user;
-{
- char buf[1024], *s;
- FILE *fp;
- int rc = 0;
-
- if ((fp = fopen(PPPHOSTS, "r")) == NULL)
- return (0);;
-
- /*
- * Loop till we find an entry for this user.
- */
- for (;;) {
- if (fgets(buf, sizeof (buf), fp) == NULL) {
- if (feof(fp))
- break;
- else {
- syslog(LOG_ERR, "fgets");
- exit(1);
- }
- }
- if ((s = index(buf, ' ')) == NULL)
- continue;
- *s++ = '\0';
- if (!strcmp(user, buf)) {
- rc = 1;
- break;
- }
- }
- fclose(fp);
- return (rc);
-}
-/*
- * open "secret" file and return the secret matching the given name.
- * If no secret for a given name is found, use the one for "default".
- */
-
-void
- get_secret(name, secret, secret_len)
-u_char * name;
-u_char * secret;
-int * secret_len;
-{
- FILE * sfile;
- struct stat sbuf;
- u_char fname[256];
- int match_found, default_found;
-
- match_found = FALSE;
- default_found = FALSE;
-
- if ((sfile = fopen(_PATH_CHAPFILE, "r")) == NULL) {
- syslog(LOG_ERR, "unable to open secret file %s", _PATH_CHAPFILE);
- exit(1);
- };
-
- if (fstat(fileno(sfile), &sbuf) < 0) {
- syslog(LOG_ERR, "cannot stat secret file!: %m");
- exit(1);
- }
- if ((sbuf.st_mode & 077) != 0)
- syslog(LOG_WARNING, "Warning - secret file has world and/or group access!");
-
- while (!feof(sfile) && !match_found) {
- if (fscanf(sfile, "%s %s", fname, secret) == EOF)
- break;
- if (!strcasecmp((char *)fname, (char *)name)) {
- match_found = TRUE;
- }
- if (!strcasecmp("default", (char *)name)) {
- default_found = TRUE;
- }
- }
-
- if (!match_found && !default_found) {
- syslog(LOG_ERR, "No match or default entry found for %s in CHAP secret file! Aborting...", name);
- cleanup(0, NULL); /* shut us down */
- }
-#ifdef UNSECURE
-/* while this is useful for debugging, it is a security hole as well */
-
- syslog(LOG_DEBUG, "get_secret: found secret %s", secret);
-#endif /*UNSECURE*/
- fclose(sfile);
- *secret_len = strlen((char *)secret);
- if (*secret_len > MAX_SECRET_LEN) { /* don't let it overflow the buffer */
- syslog(LOG_ERR, "Length of secret for host %s is greater than the maximum %d characters! ", name, MAX_SECRET_LEN);
- cleanup(0, NULL); /* scream and die */
- }
- return;
-}
-/*
* Return user specified netmask. A value of zero means no netmask has
* been set.
*/
/* ARGSUSED */
u_long
- GetMask(addr)
-u_long addr;
+GetMask(addr)
+ u_long addr;
{
- return(netmask);
+ return(netmask);
}
-#ifdef STREAMS
-/*
- * this module will attempt to reconstruct the stream with the
- * previously popped modules
+/*
+ * dumpbuffer - print contents of a buffer in hex to standard output.
*/
-
-/*ARGSUSED*/
-static void
- str_restore()
-{
- /*EMPTY*/
- while(ioctl(fd, I_POP, 0) == 0); /* pop any we pushed */
-
- for(; str_module_count > 0; str_module_count--) {
- if(ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
- syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
- str_modules[str_module_count-1].modname);
- }
- else {
- MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
- str_modules[str_module_count-1].modname))
- }
- }
-}
-#endif
-
+void
dumpbuffer(buffer, size, level)
-unsigned char *buffer;
-int size;
-int level;
+ unsigned char *buffer;
+ int size;
+ int level;
{
register int i;
char line[256], *p;
@@ -2227,48 +1199,17 @@ int level;
}
}
-#ifdef sun
-setdtr(fd, on)
-int fd, on;
-{
- int linestate;
-
- ioctl(fd, TIOCMGET, &linestate);
-
- if (on)
- linestate |= TIOCM_DTR;
- else
- linestate &= ~TIOCM_DTR;
- ioctl(fd, TIOCMSET, &linestate);
-}
-#endif
-#ifdef __386BSD__
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
setdtr(fd, on)
int fd, on;
{
int modembits = TIOCM_DTR;
- if (on)
- ioctl(fd, TIOCMBIS, &modembits);
- else
- ioctl(fd, TIOCMBIC, &modembits);
-}
-#endif
-
-char *
-proto_name(proto)
-u_short proto;
-{
- switch (proto) {
- case LCP: return "lcp";
- case UPAP: return "pap";
- case CHAP: return "chap";
- case IPCP: return "ipcp";
-#define LQM 0xc025
- case LQM: return "lqm";
- }
- return "<unknown>";
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
}
#include <varargs.h>
@@ -2296,3 +1237,11 @@ va_dcl
line[0] = 0;
}
}
+
+void
+novm(msg)
+ char *msg;
+{
+ syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg);
+ die(1);
+}
diff --git a/libexec/pppd/md5.c b/libexec/pppd/md5.c
index d9ef47b76f9f..480c860c0aa9 100644
--- a/libexec/pppd/md5.c
+++ b/libexec/pppd/md5.c
@@ -92,6 +92,12 @@ static unsigned char PADDING[64] = {
(a) += (b); \
}
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
/* The routine MD5Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
@@ -202,88 +208,88 @@ UINT4 *in;
#define S12 12
#define S13 17
#define S14 22
- FF ( a, b, c, d, in[ 0], S11, 3614090360UL); /* 1 */
- FF ( d, a, b, c, in[ 1], S12, 3905402710UL); /* 2 */
- FF ( c, d, a, b, in[ 2], S13, 606105819UL); /* 3 */
- FF ( b, c, d, a, in[ 3], S14, 3250441966UL); /* 4 */
- FF ( a, b, c, d, in[ 4], S11, 4118548399UL); /* 5 */
- FF ( d, a, b, c, in[ 5], S12, 1200080426UL); /* 6 */
- FF ( c, d, a, b, in[ 6], S13, 2821735955UL); /* 7 */
- FF ( b, c, d, a, in[ 7], S14, 4249261313UL); /* 8 */
- FF ( a, b, c, d, in[ 8], S11, 1770035416UL); /* 9 */
- FF ( d, a, b, c, in[ 9], S12, 2336552879UL); /* 10 */
- FF ( c, d, a, b, in[10], S13, 4294925233UL); /* 11 */
- FF ( b, c, d, a, in[11], S14, 2304563134UL); /* 12 */
- FF ( a, b, c, d, in[12], S11, 1804603682UL); /* 13 */
- FF ( d, a, b, c, in[13], S12, 4254626195UL); /* 14 */
- FF ( c, d, a, b, in[14], S13, 2792965006UL); /* 15 */
- FF ( b, c, d, a, in[15], S14, 1236535329UL); /* 16 */
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
- GG ( a, b, c, d, in[ 1], S21, 4129170786UL); /* 17 */
- GG ( d, a, b, c, in[ 6], S22, 3225465664UL); /* 18 */
- GG ( c, d, a, b, in[11], S23, 643717713UL); /* 19 */
- GG ( b, c, d, a, in[ 0], S24, 3921069994UL); /* 20 */
- GG ( a, b, c, d, in[ 5], S21, 3593408605UL); /* 21 */
- GG ( d, a, b, c, in[10], S22, 38016083UL); /* 22 */
- GG ( c, d, a, b, in[15], S23, 3634488961UL); /* 23 */
- GG ( b, c, d, a, in[ 4], S24, 3889429448UL); /* 24 */
- GG ( a, b, c, d, in[ 9], S21, 568446438UL); /* 25 */
- GG ( d, a, b, c, in[14], S22, 3275163606UL); /* 26 */
- GG ( c, d, a, b, in[ 3], S23, 4107603335UL); /* 27 */
- GG ( b, c, d, a, in[ 8], S24, 1163531501UL); /* 28 */
- GG ( a, b, c, d, in[13], S21, 2850285829UL); /* 29 */
- GG ( d, a, b, c, in[ 2], S22, 4243563512UL); /* 30 */
- GG ( c, d, a, b, in[ 7], S23, 1735328473UL); /* 31 */
- GG ( b, c, d, a, in[12], S24, 2368359562UL); /* 32 */
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
- HH ( a, b, c, d, in[ 5], S31, 4294588738UL); /* 33 */
- HH ( d, a, b, c, in[ 8], S32, 2272392833UL); /* 34 */
- HH ( c, d, a, b, in[11], S33, 1839030562UL); /* 35 */
- HH ( b, c, d, a, in[14], S34, 4259657740UL); /* 36 */
- HH ( a, b, c, d, in[ 1], S31, 2763975236UL); /* 37 */
- HH ( d, a, b, c, in[ 4], S32, 1272893353UL); /* 38 */
- HH ( c, d, a, b, in[ 7], S33, 4139469664UL); /* 39 */
- HH ( b, c, d, a, in[10], S34, 3200236656UL); /* 40 */
- HH ( a, b, c, d, in[13], S31, 681279174UL); /* 41 */
- HH ( d, a, b, c, in[ 0], S32, 3936430074UL); /* 42 */
- HH ( c, d, a, b, in[ 3], S33, 3572445317UL); /* 43 */
- HH ( b, c, d, a, in[ 6], S34, 76029189UL); /* 44 */
- HH ( a, b, c, d, in[ 9], S31, 3654602809UL); /* 45 */
- HH ( d, a, b, c, in[12], S32, 3873151461UL); /* 46 */
- HH ( c, d, a, b, in[15], S33, 530742520UL); /* 47 */
- HH ( b, c, d, a, in[ 2], S34, 3299628645UL); /* 48 */
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
- II ( a, b, c, d, in[ 0], S41, 4096336452UL); /* 49 */
- II ( d, a, b, c, in[ 7], S42, 1126891415UL); /* 50 */
- II ( c, d, a, b, in[14], S43, 2878612391UL); /* 51 */
- II ( b, c, d, a, in[ 5], S44, 4237533241UL); /* 52 */
- II ( a, b, c, d, in[12], S41, 1700485571UL); /* 53 */
- II ( d, a, b, c, in[ 3], S42, 2399980690UL); /* 54 */
- II ( c, d, a, b, in[10], S43, 4293915773UL); /* 55 */
- II ( b, c, d, a, in[ 1], S44, 2240044497UL); /* 56 */
- II ( a, b, c, d, in[ 8], S41, 1873313359UL); /* 57 */
- II ( d, a, b, c, in[15], S42, 4264355552UL); /* 58 */
- II ( c, d, a, b, in[ 6], S43, 2734768916UL); /* 59 */
- II ( b, c, d, a, in[13], S44, 1309151649UL); /* 60 */
- II ( a, b, c, d, in[ 4], S41, 4149444226UL); /* 61 */
- II ( d, a, b, c, in[11], S42, 3174756917UL); /* 62 */
- II ( c, d, a, b, in[ 2], S43, 718787259UL); /* 63 */
- II ( b, c, d, a, in[ 9], S44, 3951481745UL); /* 64 */
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
buf[0] += a;
buf[1] += b;
diff --git a/libexec/pppd/options.c b/libexec/pppd/options.c
new file mode 100644
index 000000000000..9f622b1ba4c0
--- /dev/null
+++ b/libexec/pppd/options.c
@@ -0,0 +1,1195 @@
+/*
+ * options.c - handles option processing for PPP.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: options.c,v 1.1 1994/03/30 09:38:16 jkh Exp $";
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <syslog.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+
+#define FALSE 0
+#define TRUE 1
+
+
+/*
+ * Prototypes
+ */
+static int setdebug __ARGS((void));
+static int setpassive __ARGS((void));
+static int setsilent __ARGS((void));
+static int noopt __ARGS((void));
+static int setnovj __ARGS((void));
+static int reqpap __ARGS((void));
+static int nopap __ARGS((void));
+static int setupapfile __ARGS((char **));
+static int nochap __ARGS((void));
+static int reqchap __ARGS((void));
+static int setspeed __ARGS((char *));
+static int noaccomp __ARGS((void));
+static int noasyncmap __ARGS((void));
+static int noipaddr __ARGS((void));
+static int nomagicnumber __ARGS((void));
+static int setasyncmap __ARGS((char **));
+static int setmru __ARGS((char **));
+static int nomru __ARGS((void));
+static int nopcomp __ARGS((void));
+static int setconnector __ARGS((char **));
+static int setdomain __ARGS((char **));
+static int setnetmask __ARGS((char **));
+static int setcrtscts __ARGS((void));
+static int setnodetach __ARGS((void));
+static int setmodem __ARGS((void));
+static int setlocal __ARGS((void));
+static int setname __ARGS((char **));
+static int setuser __ARGS((char **));
+static int setremote __ARGS((char **));
+static int setauth __ARGS((void));
+static int readfile __ARGS((char **));
+static int setdefaultroute __ARGS((void));
+static int setproxyarp __ARGS((void));
+static int setpersist __ARGS((void));
+static int setdologin __ARGS((void));
+static int setusehostname __ARGS((void));
+static int setnoipdflt __ARGS((void));
+static int setlcptimeout __ARGS((char **));
+static int setlcpterm __ARGS((char **));
+static int setlcpconf __ARGS((char **));
+static int setlcpfails __ARGS((char **));
+static int setipcptimeout __ARGS((char **));
+static int setipcpterm __ARGS((char **));
+static int setipcpconf __ARGS((char **));
+static int setipcpfails __ARGS((char **));
+static int setpaptimeout __ARGS((char **));
+static int setpapreqs __ARGS((char **));
+static int setchaptimeout __ARGS((char **));
+static int setchapchal __ARGS((char **));
+static int setchapintv __ARGS((char **));
+static int setipcpaccl __ARGS((void));
+static int setipcpaccr __ARGS((void));
+
+static int number_option __ARGS((char *, long *, int));
+
+
+/*
+ * Option variables
+ */
+extern char *progname;
+extern int debug;
+extern int modem;
+extern int crtscts;
+extern int nodetach;
+extern char *connector;
+extern int inspeed;
+extern char devname[];
+extern int default_device;
+extern u_long netmask;
+extern int detach;
+extern char user[];
+extern char passwd[];
+extern int auth_required;
+extern int proxyarp;
+extern int persist;
+extern int uselogin;
+extern char our_name[];
+extern char remote_name[];
+int usehostname;
+int disable_defaultip;
+
+/*
+ * Valid arguments.
+ */
+static struct cmd {
+ char *cmd_name;
+ int num_args;
+ int (*cmd_func)();
+} cmds[] = {
+ "-all", 0, noopt, /* Don't request/allow any options */
+ "-ac", 0, noaccomp, /* Disable Address/Control compress */
+ "-am", 0, noasyncmap, /* Disable asyncmap negotiation */
+ "-as", 1, setasyncmap, /* set the desired async map */
+ "-d", 0, setdebug, /* Increase debugging level */
+ "-detach", 0, setnodetach, /* don't fork */
+ "-ip", 0, noipaddr, /* Disable IP address negotiation */
+ "-mn", 0, nomagicnumber, /* Disable magic number negotiation */
+ "-mru", 0, nomru, /* Disable mru negotiation */
+ "-p", 0, setpassive, /* Set passive mode */
+ "-pc", 0, nopcomp, /* Disable protocol field compress */
+ "+ua", 1, setupapfile, /* Get PAP user and password from file */
+ "+pap", 0, reqpap, /* Require PAP auth from peer */
+ "-pap", 0, nopap, /* Don't allow UPAP authentication with peer */
+ "+chap", 0, reqchap, /* Require CHAP authentication from peer */
+ "-chap", 0, nochap, /* Don't allow CHAP authentication with peer */
+ "-vj", 0, setnovj, /* disable VJ compression */
+ "asyncmap", 1, setasyncmap, /* set the desired async map */
+ "connect", 1, setconnector, /* A program to set up a connection */
+ "crtscts", 0, setcrtscts, /* set h/w flow control */
+ "debug", 0, setdebug, /* Increase debugging level */
+ "domain", 1, setdomain, /* Add given domain name to hostname*/
+ "mru", 1, setmru, /* Set MRU value for negotiation */
+ "netmask", 1, setnetmask, /* set netmask */
+ "passive", 0, setpassive, /* Set passive mode */
+ "silent", 0, setsilent, /* Set silent mode */
+ "modem", 0, setmodem, /* Use modem control lines */
+ "local", 0, setlocal, /* Don't use modem control lines */
+ "name", 1, setname, /* Set local name for authentication */
+ "user", 1, setuser, /* Set username for PAP auth with peer */
+ "usehostname", 0, setusehostname, /* Must use hostname for auth. */
+ "remotename", 1, setremote, /* Set remote name for authentication */
+ "auth", 0, setauth, /* Require authentication from peer */
+ "file", 1, readfile, /* Take options from a file */
+ "defaultroute", 0, setdefaultroute, /* Add default route */
+ "proxyarp", 0, setproxyarp, /* Add proxy ARP entry */
+ "persist", 0, setpersist, /* Keep on reopening connection after close */
+ "login", 0, setdologin, /* Use system password database for UPAP */
+ "noipdefault", 0, setnoipdflt, /* Don't use name for default IP adrs */
+ "lcp-restart", 1, setlcptimeout, /* Set timeout for LCP */
+ "lcp-max-terminate", 1, setlcpterm, /* Set max #xmits for term-reqs */
+ "lcp-max-configure", 1, setlcpconf, /* Set max #xmits for conf-reqs */
+ "lcp-max-failure", 1, setlcpfails, /* Set max #conf-naks for LCP */
+ "ipcp-restart", 1, setipcptimeout, /* Set timeout for IPCP */
+ "ipcp-max-terminate", 1, setipcpterm, /* Set max #xmits for term-reqs */
+ "ipcp-max-configure", 1, setipcpconf, /* Set max #xmits for conf-reqs */
+ "ipcp-max-failure", 1, setipcpfails, /* Set max #conf-naks for IPCP */
+ "pap-restart", 1, setpaptimeout, /* Set timeout for UPAP */
+ "pap-max-authreq", 1, setpapreqs, /* Set max #xmits for auth-reqs */
+ "chap-restart", 1, setchaptimeout, /* Set timeout for CHAP */
+ "chap-max-challenge", 1, setchapchal, /* Set max #xmits for challenge */
+ "chap-interval", 1, setchapintv, /* Set interval for rechallenge */
+ "ipcp-accept-local", 0, setipcpaccl, /* Accept peer's address for us */
+ "ipcp-accept-remote", 0, setipcpaccr, /* Accept peer's address for it */
+ NULL
+};
+
+
+static char *usage_string = "\
+pppd version %s patch level %d\n\
+Usage: %s [ arguments ], where arguments are:\n\
+ <device> Communicate over the named device\n\
+ <speed> Set the baud rate to <speed>\n\
+ <loc>:<rem> Set the local and/or remote interface IP\n\
+ addresses. Either one may be omitted.\n\
+ asyncmap <n> Set the desired async map to hex <n>\n\
+ auth Require authentication from peer\n\
+ connect <p> Invoke shell command <p> to set up the serial line\n\
+ crtscts Use hardware RTS/CTS flow control\n\
+ defaultroute Add default route through interface\n\
+ file <f> Take options from file <f>\n\
+ modem Use modem control lines\n\
+ mru <n> Set MRU value to <n> for negotiation\n\
+ netmask <n> Set interface netmask to <n>\n\
+See pppd(8) for more options.\n\
+";
+
+/*
+Options omitted:
+ -all Don't request/allow any options\n\
+ -ac Disable Address/Control compression\n\
+ -am Disable asyncmap negotiation\n\
+ -as <n> Set the desired async map to hex <n>\n\
+ -d Increase debugging level\n\
+ -detach Don't fork to background\n\
+ -ip Disable IP address negotiation\n\
+ -mn Disable magic number negotiation\n\
+ -mru Disable mru negotiation\n\
+ -p Set passive mode\n\
+ -pc Disable protocol field compression\n\
+ +ua <f> Get username and password for authenticating\n\
+ with peer using PAP from file <f>\n\
+ +pap Require PAP authentication from peer\n\
+ -pap Don't agree to authenticating with peer using PAP\n\
+ +chap Require CHAP authentication from peer\n\
+ -chap Don't agree to authenticating with peer using CHAP\n\
+ -vj disable VJ compression\n\
+ -auth Don't agree to authenticate with peer\n\
+ debug Increase debugging level\n\
+ domain <d> Append domain name <d> to hostname for authentication\n\
+ passive Set passive mode\n\
+ local Don't use modem control lines\n\
+ proxyarp Add proxy ARP entry\n\
+*/
+
+
+/*
+ * parse_args - parse a string of arguments, from the command
+ * line or from a file.
+ */
+int
+parse_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg, *val;
+ struct cmd *cmdp;
+
+ while (argc > 0) {
+ arg = *argv++;
+ --argc;
+
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(arg, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ if (argc < cmdp->num_args) {
+ fprintf(stderr, "Too few parameters for command %s\n", arg);
+ return 0;
+ }
+ if (!(*cmdp->cmd_func)(argv))
+ return 0;
+ argc -= cmdp->num_args;
+ argv += cmdp->num_args;
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if (!setdevname(arg) && !setspeed(arg) && !setipaddr(arg)) {
+ fprintf(stderr, "%s: unrecognized command\n", arg);
+ usage();
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ * usage - print out a message telling how to use the program.
+ */
+usage()
+{
+ fprintf(stderr, usage_string, VERSION, PATCHLEVEL, progname);
+}
+
+/*
+ * options_from_file - Read a string of options from a file,
+ * and interpret them.
+ */
+int
+options_from_file(filename, must_exist)
+ char *filename;
+ int must_exist;
+{
+ FILE *f;
+ int i, newline;
+ struct cmd *cmdp;
+ char *argv[MAXARGS];
+ char args[MAXARGS][MAXWORDLEN];
+ char cmd[MAXWORDLEN];
+
+ if ((f = fopen(filename, "r")) == NULL) {
+ if (!must_exist && errno == ENOENT)
+ return 1;
+ perror(filename);
+ exit(1);
+ }
+ while (getword(f, cmd, &newline, filename)) {
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(cmd, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ for (i = 0; i < cmdp->num_args; ++i) {
+ if (!getword(f, args[i], &newline, filename)) {
+ fprintf(stderr,
+ "In file %s: too few parameters for command %s\n",
+ filename, cmd);
+ fclose(f);
+ return 0;
+ }
+ argv[i] = args[i];
+ }
+ if (!(*cmdp->cmd_func)(argv)) {
+ fclose(f);
+ return 0;
+ }
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if (!setdevname(cmd) && !setspeed(cmd) && !setipaddr(cmd)) {
+ fprintf(stderr, "In file %s: unrecognized command %s\n",
+ filename, cmd);
+ fclose(f);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ * options_from_user - See if the use has a ~/.ppprc file,
+ * and if so, interpret options from it.
+ */
+int
+options_from_user()
+{
+ char *user, *path, *file;
+ int ret;
+
+ if ((user = getenv("HOME")) == NULL)
+ return;
+ file = "/.ppprc";
+ path = malloc(strlen(user) + strlen(file) + 1);
+ if (path == NULL)
+ novm("init file name");
+ strcpy(path, user);
+ strcat(path, file);
+ ret = options_from_file(path, 0);
+ free(path);
+ return ret;
+}
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (").
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> is ignored.
+ */
+int
+getword(f, word, newlinep, filename)
+ FILE *f;
+ char *word;
+ int *newlinep;
+ char *filename;
+{
+ int c, len, escape;
+ int quoted;
+
+ *newlinep = 0;
+ len = 0;
+ escape = 0;
+ quoted = 0;
+
+ /*
+ * First skip white-space and comments
+ */
+ while ((c = getc(f)) != EOF) {
+ if (c == '\\') {
+ /*
+ * \<newline> is ignored; \ followed by anything else
+ * starts a word.
+ */
+ if ((c = getc(f)) == '\n')
+ continue;
+ word[len++] = '\\';
+ escape = 1;
+ break;
+ }
+ if (c == '\n')
+ *newlinep = 1; /* next word starts a line */
+ else if (c == '#') {
+ /* comment - ignore until EOF or \n */
+ while ((c = getc(f)) != EOF && c != '\n')
+ ;
+ if (c == EOF)
+ break;
+ *newlinep = 1;
+ } else if (!isspace(c))
+ break;
+ }
+
+ /*
+ * End of file or error - fail
+ */
+ if (c == EOF) {
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+ return 0;
+ }
+
+ for (;;) {
+ /*
+ * Is this character escaped by \ ?
+ */
+ if (escape) {
+ if (c == '\n')
+ --len; /* ignore \<newline> */
+ else if (c == '"' || isspace(c) || c == '\\')
+ word[len-1] = c; /* put special char in word */
+ else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ }
+ escape = 0;
+ } else if (c == '"') {
+ quoted = !quoted;
+ } else if (!quoted && (isspace(c) || c == '#')) {
+ ungetc(c, f);
+ break;
+ } else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ if (c == '\\')
+ escape = 1;
+ }
+ if ((c = getc(f)) == EOF)
+ break;
+ }
+
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+
+ if (len >= MAXWORDLEN) {
+ word[MAXWORDLEN-1] = 0;
+ fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
+ progname, filename, word);
+ } else
+ word[len] = 0;
+
+ return 1;
+}
+
+/*
+ * number_option - parse a numeric parameter for an option
+ */
+static int
+number_option(str, valp, base)
+ char *str;
+ long *valp;
+ int base;
+{
+ char *ptr;
+
+ *valp = strtol(str, &ptr, base);
+ if (ptr == str) {
+ fprintf(stderr, "%s: invalid number: %s\n", progname, str);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * int_option - like number_option, but valp is int *,
+ * the base is assumed to be 0, and *valp is not changed
+ * if there is an error.
+ */
+static int
+int_option(str, valp)
+ char *str;
+ int *valp;
+{
+ long v;
+
+ if (!number_option(str, &v, 0))
+ return 0;
+ *valp = (int) v;
+ return 1;
+}
+
+
+/*
+ * The following procedures execute commands.
+ */
+
+/*
+ * readfile - take commands from a file.
+ */
+static int
+readfile(argv)
+ char **argv;
+{
+ return options_from_file(*argv, 1);
+}
+
+/*
+ * setdebug - Set debug (command line argument).
+ */
+static int
+setdebug()
+{
+ debug++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ return (1);
+}
+
+/*
+ * noopt - Disable all options.
+ */
+static int
+noopt()
+{
+ BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
+ BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
+ return (1);
+}
+
+/*
+ * noaccomp - Disable Address/Control field compression negotiation.
+ */
+static int
+noaccomp()
+{
+ lcp_wantoptions[0].neg_accompression = 0;
+ lcp_allowoptions[0].neg_accompression = 0;
+ return (1);
+}
+
+
+/*
+ * noasyncmap - Disable async map negotiation.
+ */
+static int
+noasyncmap()
+{
+ lcp_wantoptions[0].neg_asyncmap = 0;
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ return (1);
+}
+
+
+/*
+ * noipaddr - Disable IP address negotiation.
+ */
+static int
+noipaddr()
+{
+ ipcp_wantoptions[0].neg_addr = 0;
+ ipcp_allowoptions[0].neg_addr = 0;
+ return (1);
+}
+
+
+/*
+ * nomagicnumber - Disable magic number negotiation.
+ */
+static int
+nomagicnumber()
+{
+ lcp_wantoptions[0].neg_magicnumber = 0;
+ lcp_allowoptions[0].neg_magicnumber = 0;
+ return (1);
+}
+
+
+/*
+ * nomru - Disable mru negotiation.
+ */
+static int
+nomru()
+{
+ lcp_wantoptions[0].neg_mru = 0;
+ lcp_allowoptions[0].neg_mru = 0;
+ return (1);
+}
+
+
+/*
+ * setmru - Set MRU for negotiation.
+ */
+static int
+setmru(argv)
+ char **argv;
+{
+ long mru;
+
+ if (!number_option(*argv, &mru, 0))
+ return 0;
+ lcp_wantoptions[0].mru = mru;
+ lcp_wantoptions[0].neg_mru = 1;
+ return (1);
+}
+
+
+/*
+ * nopcomp - Disable Protocol field compression negotiation.
+ */
+static int
+nopcomp()
+{
+ lcp_wantoptions[0].neg_pcompression = 0;
+ lcp_allowoptions[0].neg_pcompression = 0;
+ return (1);
+}
+
+
+/*
+ * setpassive - Set passive mode (don't give up if we time out sending
+ * LCP configure-requests).
+ */
+static int
+setpassive()
+{
+ lcp_wantoptions[0].passive = 1;
+ return (1);
+}
+
+
+/*
+ * setsilent - Set silent mode (don't start sending LCP configure-requests
+ * until we get one from the peer).
+ */
+static int
+setsilent()
+{
+ lcp_wantoptions[0].silent = 1;
+ return 1;
+}
+
+
+/*
+ * nopap - Disable PAP authentication with peer.
+ */
+static int
+nopap()
+{
+ lcp_allowoptions[0].neg_upap = 0;
+ return (1);
+}
+
+
+/*
+ * reqpap - Require PAP authentication from peer.
+ */
+static int
+reqpap()
+{
+ lcp_wantoptions[0].neg_upap = 1;
+ auth_required = 1;
+}
+
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+ char **argv;
+{
+ FILE * ufile;
+ int l;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ if ((ufile = fopen(*argv, "r")) == NULL) {
+ fprintf(stderr, "unable to open user login data file %s\n", *argv);
+ exit(1);
+ }
+ check_access(ufile, *argv);
+
+ /* get username */
+ if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
+ || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
+ fprintf(stderr, "Unable to read user login data file %s.\n", *argv);
+ exit(2);
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(user);
+ if (l > 0 && user[l-1] == '\n')
+ user[l-1] = 0;
+ l = strlen(passwd);
+ if (l > 0 && passwd[l-1] == '\n')
+ passwd[l-1] = 0;
+
+ return (1);
+}
+
+
+/*
+ * nochap - Disable CHAP authentication with peer.
+ */
+static int
+nochap()
+{
+ lcp_allowoptions[0].neg_chap = 0;
+ return (1);
+}
+
+
+/*
+ * reqchap - Require CHAP authentication from peer.
+ */
+static int
+reqchap()
+{
+ lcp_wantoptions[0].neg_chap = 1;
+ auth_required = 1;
+ return (1);
+}
+
+
+/*
+ * setnovj - diable vj compression
+ */
+static int
+setnovj()
+{
+ ipcp_wantoptions[0].neg_vj = 0;
+ ipcp_allowoptions[0].neg_vj = 0;
+ return (1);
+}
+
+/*
+ * setconnector - Set a program to connect to a serial line
+ */
+static int
+setconnector(argv)
+ char **argv;
+{
+ connector = strdup(*argv);
+ if (connector == NULL)
+ novm("connector string");
+
+ return (1);
+}
+
+
+/*
+ * setdomain - Set domain name to append to hostname
+ */
+static int
+setdomain(argv)
+ char **argv;
+{
+ strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
+ hostname[MAXNAMELEN-1] = 0;
+ return (1);
+}
+
+static int
+setasyncmap(argv)
+ char **argv;
+{
+ long asyncmap;
+
+ if (!number_option(*argv, &asyncmap, 16))
+ return 0;
+ lcp_wantoptions[0].asyncmap |= asyncmap;
+ lcp_wantoptions[0].neg_asyncmap = 1;
+ return(1);
+}
+
+/*
+ * setspeed - Set the speed.
+ */
+static int
+setspeed(arg)
+ char *arg;
+{
+ char *ptr;
+ int spd;
+
+ spd = strtol(arg, &ptr, 0);
+ if (ptr == arg || *ptr != 0 || spd == 0)
+ return 0;
+ inspeed = spd;
+ return 1;
+}
+
+
+/*
+ * setdevname - Set the device name.
+ */
+int
+setdevname(cp)
+ char *cp;
+{
+ struct stat statbuf;
+ char *tty, *ttyname();
+ char dev[MAXPATHLEN];
+
+ if (strncmp("/dev/", cp, 5) != 0) {
+ strcpy(dev, "/dev/");
+ strncat(dev, cp, MAXPATHLEN - 5);
+ dev[MAXPATHLEN-1] = 0;
+ cp = dev;
+ }
+
+ /*
+ * Check if there is a device by this name.
+ */
+ if (stat(cp, &statbuf) < 0) {
+ if (errno == ENOENT)
+ return (0);
+ syslog(LOG_ERR, cp);
+ exit(1);
+ }
+
+ (void) strncpy(devname, cp, MAXPATHLEN);
+ devname[MAXPATHLEN-1] = 0;
+ default_device = FALSE;
+
+ return (1);
+}
+
+
+/*
+ * setipaddr - Set the IP address
+ */
+int
+setipaddr(arg)
+ char *arg;
+{
+ struct hostent *hp;
+ char *colon, *index();
+ u_long local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = index(arg, ':')) == NULL)
+ return (0);
+
+ /*
+ * If colon first character, then no local addr.
+ */
+ if (colon != arg) {
+ *colon = '\0';
+ if ((local = inet_addr(arg)) == -1) {
+ if ((hp = gethostbyname(arg)) == NULL) {
+ fprintf(stderr, "unknown host: %s", arg);
+ local = 0;
+ } else {
+ local = *(long *)hp->h_addr;
+ if (our_name[0] == 0) {
+ strncpy(our_name, arg, MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (local != 0)
+ wo->ouraddr = local;
+ *colon = ':';
+ }
+
+ /*
+ * If colon last character, then no remote addr.
+ */
+ if (*++colon != '\0') {
+ if ((remote = inet_addr(colon)) == -1) {
+ if ((hp = gethostbyname(colon)) == NULL) {
+ fprintf(stderr, "unknown host: %s", colon);
+ remote = 0;
+ } else {
+ remote = *(long *)hp->h_addr;
+ if (remote_name[0] == 0) {
+ strncpy(remote_name, colon, MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (remote != 0)
+ wo->hisaddr = remote;
+ }
+
+ return (1);
+}
+
+
+/*
+ * setnoipdflt - disable setipdefault()
+ */
+static int
+setnoipdflt()
+{
+ disable_defaultip = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccl - accept peer's idea of our address
+ */
+static int
+setipcpaccl()
+{
+ ipcp_wantoptions[0].accept_local = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccr - accept peer's idea of its address
+ */
+static int
+setipcpaccr()
+{
+ ipcp_wantoptions[0].accept_remote = 1;
+ return 1;
+}
+
+
+/*
+ * setipdefault - default our local IP address based on our hostname.
+ */
+void
+setipdefault()
+{
+ struct hostent *hp;
+ u_long local;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * If local IP address already given, don't bother.
+ */
+ if (wo->ouraddr != 0 || disable_defaultip)
+ return;
+
+ /*
+ * Look up our hostname (possibly with domain name appended)
+ * and take the first IP address as our local IP address.
+ * If there isn't an IP address for our hostname, too bad.
+ */
+ wo->accept_local = 1; /* don't insist on this default value */
+ if ((hp = gethostbyname(hostname)) == NULL)
+ return;
+ local = *(long *)hp->h_addr;
+ if (local != 0)
+ wo->ouraddr = local;
+}
+
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(argv)
+ char **argv;
+{
+ u_long mask;
+
+ if ((mask = inet_addr(*argv)) == -1) {
+ fprintf(stderr, "Invalid netmask %s\n", *argv);
+ exit(1);
+ }
+
+ netmask = mask;
+ return (1);
+}
+
+static int
+setcrtscts()
+{
+ crtscts = 1;
+ return (1);
+}
+
+static int
+setnodetach()
+{
+ nodetach = 1;
+ return (1);
+}
+
+static int
+setmodem()
+{
+ modem = 1;
+ return 1;
+}
+
+static int
+setlocal()
+{
+ modem = 0;
+ return 1;
+}
+
+static int
+setusehostname()
+{
+ usehostname = 1;
+ return 1;
+}
+
+static int
+setname(argv)
+ char **argv;
+{
+ if (our_name[0] == 0) {
+ strncpy(our_name, argv[0], MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ return 1;
+}
+
+static int
+setuser(argv)
+ char **argv;
+{
+ strncpy(user, argv[0], MAXNAMELEN);
+ user[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setremote(argv)
+ char **argv;
+{
+ strncpy(remote_name, argv[0], MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setauth()
+{
+ auth_required = 1;
+ return 1;
+}
+
+static int
+setdefaultroute()
+{
+ ipcp_wantoptions[0].default_route = 1;
+ return 1;
+}
+
+static int
+setproxyarp()
+{
+ ipcp_wantoptions[0].proxy_arp = 1;
+ return 1;
+}
+
+static int
+setpersist()
+{
+ persist = 1;
+ return 1;
+}
+
+static int
+setdologin()
+{
+ uselogin = 1;
+ return 1;
+}
+
+/*
+ * Functions to set timeouts, max transmits, etc.
+ */
+static int
+setlcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].timeouttime, 0);
+}
+
+static int setlcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxtermtransmits, 0);
+}
+
+static int setlcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxconfreqtransmits, 0);
+}
+
+static int setlcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops, 0);
+}
+
+static int setipcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].timeouttime, 0);
+}
+
+static int setipcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxtermtransmits, 0);
+}
+
+static int setipcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxconfreqtransmits, 0);
+}
+
+static int setipcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops, 0);
+}
+
+static int setpaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_timeouttime, 0);
+}
+
+static int setpapreqs(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_maxtransmits, 0);
+}
+
+static int setchaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].timeouttime, 0);
+}
+
+static int setchapchal(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].max_transmits, 0);
+}
+
+static int setchapintv(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].chal_interval, 0);
+}
diff --git a/libexec/pppd/patchlevel.h b/libexec/pppd/patchlevel.h
index 3c62d5286095..bcfe48398036 100644
--- a/libexec/pppd/patchlevel.h
+++ b/libexec/pppd/patchlevel.h
@@ -1,4 +1,5 @@
-#define PATCHLEVEL 0
+/* $Id: patchlevel.h,v 1.2 1994/03/30 09:31:38 jkh Exp $ */
+#define PATCHLEVEL 4
-#define VERSION "1.3"
-#define DATE "17 Jun 93"
+#define VERSION "2.0"
+#define DATE "9 Feb 94"
diff --git a/libexec/pppd/pathnames.h b/libexec/pppd/pathnames.h
index dac7cd94c54b..81ddeb1e73d4 100644
--- a/libexec/pppd/pathnames.h
+++ b/libexec/pppd/pathnames.h
@@ -1,11 +1,15 @@
-
/*
* define path names
+ *
+ * $Id: pathnames.h,v 1.2 1994/03/30 09:31:39 jkh Exp $
*/
-#define PPPHOSTS "/etc/ppp/hosts"
-
-#define _PATH_DEBUG "/usr/tmp/"
+#ifdef STREAMS
#define _PATH_PIDFILE "/etc/ppp"
-#define _PATH_UPAPFILE "/etc/ppp/upap"
-#define _PATH_CHAPFILE "/etc/ppp/chap"
+#else
+#define _PATH_PIDFILE "/var/run"
+#endif
+
+#define _PATH_UPAPFILE "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS "/etc/ppp/options"
diff --git a/libexec/pppd/ppp.h b/libexec/pppd/ppp.h
new file mode 100644
index 000000000000..f3615a756c7a
--- /dev/null
+++ b/libexec/pppd/ppp.h
@@ -0,0 +1,41 @@
+/*
+ * ppp.h - PPP global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ppp.h,v 1.1 1994/03/30 09:38:17 jkh Exp $
+ */
+
+#ifndef __PPP_H__
+#define __PPP_H__
+
+#define _NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Data Link Layer header = Address, Control, Protocol.
+ */
+#define ALLSTATIONS 0xff /* All-Stations Address */
+#define UI 0x03 /* Unnumbered Information */
+#define LCP 0xc021 /* Link Control Protocol */
+#define IPCP 0x8021 /* IP Control Protocol */
+#define UPAP 0xc023 /* User/Password Authentication Protocol */
+#define CHAP 0xc223 /* Crytpographic Handshake Protocol */
+#define LQR 0xc025 /* Link Quality Report protocol */
+#define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */
+#define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+#define MTU 1500 /* Default MTU */
+
+#endif /* __PPP_H__ */
diff --git a/libexec/pppd/pppd.8 b/libexec/pppd/pppd.8
index d64c26f40b11..1bc47df2f64e 100644
--- a/libexec/pppd/pppd.8
+++ b/libexec/pppd/pppd.8
@@ -1,5 +1,5 @@
.\" manual page [] for pppd 2.0
-.\" $Id: pppd.8,v 1.1.2.1 1994/05/01 16:06:43 jkh Exp $
+.\" $Id: pppd.8,v 1.3 1994/04/24 01:22:02 jkh Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
diff --git a/libexec/pppd/pppd.h b/libexec/pppd/pppd.h
index 2a114390e2c2..1cecd3555062 100644
--- a/libexec/pppd/pppd.h
+++ b/libexec/pppd/pppd.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pppd.h,v 1.3 1994/03/30 09:38:17 jkh Exp $
*/
/*
@@ -24,30 +26,41 @@
#ifndef __PPPD_H__
#define __PPPD_H__
#include "args.h"
-#define NPPP 1 /* One PPP interface supported (per process) */
+
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+
+#define _NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Limits.
+ */
+#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
+#define MAXARGS 1 /* max # args to a command */
+#define MAXNAMELEN 256 /* max length of hostname or name for auth */
+#define MAXSECRETLEN 256 /* max length of password or secret */
extern int debug; /* Debug flag */
+extern int ifunit; /* Interface unit number */
extern char ifname[]; /* Interface name */
extern int fd; /* Device file descriptor */
extern int s; /* socket descriptor */
extern char hostname[]; /* hostname */
-extern u_char hostname_len; /* and its length */
extern u_char outpacket_buf[]; /* buffer for outgoing packets */
-#define MAX_HOSTNAME_LEN 128 /* should be 255 - MAX_CHALLENGE_LEN + 1 */
-
-void quit __ARGS((void)); /* Cleanup and exit */
+void quit __ARGS((void)); /* Cleanup and exit */
void timeout __ARGS((void (*)(), caddr_t, int));
- /* Look-alike of kernel's timeout() */
+ /* Look-alike of kernel's timeout() */
void untimeout __ARGS((void (*)(), caddr_t));
- /* Look-alike of kernel's untimeout() */
-void output __ARGS((int, u_char *, int)); /* Output a PPP packet */
-void demuxprotrej __ARGS((int, int)); /* Demultiplex a Protocol-Reject */
-u_char login __ARGS((char *, int, char *, int, char **, int *)); /* Login user */
-void logout __ARGS((void)); /* Logout user */
-void get_secret __ARGS((u_char *, u_char *, int *)); /* get "secret" for chap */
+ /* Look-alike of kernel's untimeout() */
+void output __ARGS((int, u_char *, int));
+ /* Output a PPP packet */
+void demuxprotrej __ARGS((int, int));
+ /* Demultiplex a Protocol-Reject */
+int check_passwd __ARGS((int, char *, int, char *, int, char **, int *));
+ /* Check peer-supplied username/password */
+int get_secret __ARGS((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
u_long GetMask __ARGS((u_long)); /* get netmask for address */
-extern int errno;
/*
@@ -93,293 +106,35 @@ extern int errno;
* System dependent definitions for user-level 4.3BSD UNIX implementation.
*/
-#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
+#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
-#define TIMEOUT(r, f, t) timeout((r), (f), (t))
-#define UNTIMEOUT(r, f) untimeout((r), (f))
+#define TIMEOUT(r, f, t) timeout((r), (f), (t))
+#define UNTIMEOUT(r, f) untimeout((r), (f))
-#define BCOPY(s, d, l) bcopy(s, d, l)
-#define EXIT(u) quit()
+#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BZERO(s, n) memset(s, 0, n)
+#define EXIT(u) quit()
-#define GETUSERPASSWD(u)
-#define LOGIN(n, u, ul, p, pl, m, ml) login(u, ul, p, pl, m, ml);
-#define LOGOUT(n) logout()
-#define GETSECRET(n, s, sl) get_secret(n, s, sl)
#define PRINTMSG(m, l) { m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); }
/*
- * return a pointer to the beginning of the data part of a packet.
- */
-
-#define PACKET_DATA(p) (p + DLLHEADERLEN)
-
-/*
- * MAKEHEADER - Add Header fields to a packet. (Should we do
- * AC compression here?)
+ * MAKEHEADER - Add Header fields to a packet.
*/
#define MAKEHEADER(p, t) { \
PUTCHAR(ALLSTATIONS, p); \
PUTCHAR(UI, p); \
PUTSHORT(t, p); }
-/*
- * SIFASYNCMAP - Config the interface async map.
- */
-#ifdef STREAMS
-#define SIFASYNCMAP(u, a) { \
- u_long x = a; \
- if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m"); \
- } }
-#else
-#define SIFASYNCMAP(u, a) { \
- u_long x = a; \
- if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * SIFPCOMPRESSION - Config the interface for protocol compression.
- */
-#ifdef STREAMS
-#define SIFPCOMPRESSION(u) { \
- char c = 1; \
- if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); \
- }}
-#else
-#define SIFPCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x |= SC_COMP_PROT; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * CIFPCOMPRESSION - Config the interface for no protocol compression.
- */
-#ifdef STREAMS
-#define CIFPCOMPRESSION(u) { \
- char c = 0; \
- if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); \
- quit(); \
- }}
-#else
-#define CIFPCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x &= ~SC_COMP_PROT; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-/*
- * SIFACCOMPRESSION - Config the interface for address/control compression.
- */
-#ifdef STREAMS
-#define SIFACCOMPRESSION(u) { \
- char c = 1; \
- if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); \
- quit(); \
- }}
-#else
-#define SIFACCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x |= SC_COMP_AC; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * CIFACCOMPRESSION - Config the interface for no address/control compression.
- */
-#ifdef STREAMS
-#define CIFACCOMPRESSION(u) { \
- char c = 0; \
- if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); \
- quit(); \
- }}
-#else
-#define CIFACCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x &= ~SC_COMP_AC; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
+#ifdef DEBUGALL
+#define DEBUGMAIN 1
+#define DEBUGFSM 1
+#define DEBUGLCP 1
+#define DEBUGIPCP 1
+#define DEBUGUPAP 1
+#define DEBUGCHAP 1
#endif
-/*
- * SIFVJCOMP - config tcp header compression
- */
-#ifdef STREAMS
-#define SIFVJCOMP(u, a) { \
- char x = a; \
- if (debug) syslog(LOG_DEBUG, "SIFVJCOMP unit %d to value %d\n",u,x); \
- if(ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m"); \
- quit(); \
- } \
-}
-#else
-#define SIFVJCOMP(u, a) { \
- u_int x; \
- if (debug) \
- syslog(LOG_DEBUG, "PPPIOCSFLAGS unit %d set %s\n",u,a?"on":"off"); \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x = (x & ~SC_COMP_TCP) | ((a) ? SC_COMP_TCP : 0); \
- if(ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * SIFUP - Config the interface up.
- */
-#define SIFUP(u) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); \
- quit(); \
- } \
- ifr.ifr_flags |= IFF_UP; \
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); \
- quit(); \
- } }
-
-/*
- * SIFDOWN - Config the interface down.
- */
-#define SIFDOWN(u) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); \
- quit(); \
- } \
- ifr.ifr_flags &= ~IFF_UP; \
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); \
- quit(); \
- } }
-
-/*
- * SIFMTU - Config the interface MTU.
- */
-#define SIFMTU(u, m) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- ifr.ifr_mtu = m; \
- if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); \
- quit(); \
- } }
-
-
-#ifdef __386BSD__ /* BSD >= 44 ? */
-#define SET_SA_FAMILY(addr, family) \
- bzero((char *) &(addr), sizeof(addr)); \
- addr.sa_family = (family); \
- addr.sa_len = sizeof(addr);
-#else
-#define SET_SA_FAMILY(addr, family) \
- bzero((char *) &(addr), sizeof(addr)); \
- addr.sa_family = (family);
-#endif
-
-/*
- * SIFADDR - Config the interface IP addresses.
- */
-#define SIFADDR(u, o, h) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- SET_SA_FAMILY(ifr.ifr_addr, AF_INET); \
- ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; \
- if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); \
- } \
- ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h; \
- if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); \
- quit(); \
- } }
-
-/*
- * CIFADDR - Clear the interface IP addresses.
- */
-#if BSD > 43
-#define CIFADDR(u, o, h) { \
- struct ortentry rt; \
- SET_SA_FAMILY(rt.rt_dst, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; \
- SET_SA_FAMILY(rt.rt_gateway, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; \
- rt.rt_flags |= RTF_HOST; \
- syslog(LOG_INFO, "Deleting host route from %s to %s\n", \
- ip_ntoa(h), ip_ntoa(o)); \
- if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); \
- } }
-#else
-#define CIFADDR(u, o, h) { \
- struct rtentry rt; \
- SET_SA_FAMILY(rt.rt_dst, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; \
- SET_SA_FAMILY(rt.rt_gateway, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; \
- rt.rt_flags |= RTF_HOST; \
- syslog(LOG_INFO, "Deleting host route from %s to %s\n", \
- ip_ntoa(h), ip_ntoa(o)); \
- if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); \
- } }
-#endif
-
-/*
- * SIFMASK - Config the interface net mask
- */
-#define SIFMASK(u, m) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- SET_SA_FAMILY(ifr.ifr_addr, AF_INET); \
- ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m; \
- syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); \
- if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); \
- } }
-
#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
|| defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
@@ -391,37 +146,37 @@ extern int errno;
#endif /* LOG_PPP */
#ifdef DEBUGMAIN
-#define MAINDEBUG(x) if (debug) syslog x;
+#define MAINDEBUG(x) if (debug) syslog x
#else
#define MAINDEBUG(x)
#endif
#ifdef DEBUGFSM
-#define FSMDEBUG(x) if (debug) syslog x;
+#define FSMDEBUG(x) if (debug) syslog x
#else
#define FSMDEBUG(x)
#endif
#ifdef DEBUGLCP
-#define LCPDEBUG(x) if (debug) syslog x;
+#define LCPDEBUG(x) if (debug) syslog x
#else
#define LCPDEBUG(x)
#endif
#ifdef DEBUGIPCP
-#define IPCPDEBUG(x) if (debug) syslog x;
+#define IPCPDEBUG(x) if (debug) syslog x
#else
#define IPCPDEBUG(x)
#endif
#ifdef DEBUGUPAP
-#define UPAPDEBUG(x) if (debug) syslog x;
+#define UPAPDEBUG(x) if (debug) syslog x
#else
#define UPAPDEBUG(x)
#endif
#ifdef DEBUGCHAP
-#define CHAPDEBUG(x) if (debug) syslog x;
+#define CHAPDEBUG(x) if (debug) syslog x
#else
#define CHAPDEBUG(x)
#endif
@@ -433,4 +188,12 @@ extern int errno;
#define SIGTYPE int
#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#endif
+
#endif /* __PPP_H__ */
diff --git a/libexec/pppd/sys-bsd.c b/libexec/pppd/sys-bsd.c
new file mode 100644
index 000000000000..314af4447ebf
--- /dev/null
+++ b/libexec/pppd/sys-bsd.c
@@ -0,0 +1,503 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: sys-bsd.c,v 1.1 1994/03/30 09:38:18 jkh Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+
+static int initdisc; /* Initial TTY discipline */
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ int pppdisc = PPPDISC;
+
+ if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
+ die(1);
+ }
+ if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+}
+
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ if (ioctl(fd, TIOCSETD, &initdisc) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+
+ if (write(fd, p, len) < 0) {
+ syslog(LOG_ERR, "write: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
+ if (errno == EWOULDBLOCK) {
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+ return -1;
+ }
+ syslog(LOG_ERR, "read(fd): %m");
+ die(1);
+ }
+ return len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ u_int x;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
+ x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface. At present this does nothing.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+#ifdef notyet
+ if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+#endif /* notyet */
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp)
+{
+ u_int x;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ return 0;
+ }
+ x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
+ x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
+ if(ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family); \
+ addr.sa_len = sizeof(addr);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ if (m != 0) {
+ SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+ } else
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+ if (errno != EEXIST) {
+ syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ return 0;
+ }
+ syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0)
+ syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ /*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+ && ifr->ifr_addr.sa_family == AF_LINK) {
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *)&ifr->ifr_addr;
+ hwaddr->sa_len = sizeof(struct sockaddr);
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY(LLADDR(dla), hwaddr->sa_data, dla->sdl_alen);
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ return 0;
+}
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+
+int
+ppp_available()
+{
+ int s, ok;
+ struct ifreq ifr;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}
diff --git a/libexec/pppd/sys-str.c b/libexec/pppd/sys-str.c
new file mode 100644
index 000000000000..866a61a1738a
--- /dev/null
+++ b/libexec/pppd/sys-str.c
@@ -0,0 +1,643 @@
+/*
+ * sys-str.c - System-dependent procedures for setting up
+ * PPP interfaces on systems which use the STREAMS ppp interface.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include <net/ppp_str.h>
+
+#ifndef ifr_mtu
+#define ifr_mtu ifr_metric
+#endif
+
+#define MAXMODULES 10 /* max number of module names to save */
+static struct modlist {
+ char modname[FMNAMESZ+1];
+} str_modules[MAXMODULES];
+static int str_module_count = 0;
+
+extern int hungup; /* has the physical layer been disconnected? */
+
+/*
+ * ppp_available - check if this kernel supports PPP.
+ */
+int
+ppp_available()
+{
+ int fd, ret;
+
+ fd = open("/dev/tty", O_RDONLY, 0);
+ if (fd < 0)
+ return 1; /* can't find out - assume we have ppp */
+ ret = ioctl(fd, I_FIND, "pppasync") >= 0;
+ close(fd);
+ return ret;
+}
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ /* go through and save the name of all the modules, then pop em */
+ for (;;) {
+ if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
+ ioctl(fd, I_POP, 0) < 0)
+ break;
+ MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
+ str_modules[str_module_count].modname));
+ str_module_count++;
+ }
+
+ MAINDEBUG((LOG_INFO, "about to push modules..."));
+
+ /* now push the async/fcs module */
+ if (ioctl(fd, I_PUSH, "pppasync") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
+ die(1);
+ }
+ /* finally, push the ppp_if module that actually handles the */
+ /* network interface */
+ if (ioctl(fd, I_PUSH, "pppif") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
+ die(1);
+ }
+ if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
+ die(1);
+ }
+ /* read mode, message non-discard mode */
+ if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
+ die(1);
+ }
+ /* Flush any waiting messages, or we'll never get SIGPOLL */
+ if (ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
+ syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
+ die(1);
+ }
+ /*
+ * Find out which interface we were given.
+ * (ppp_if handles this ioctl)
+ */
+ if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
+ die(1);
+ }
+
+ /* if debug, set debug flags in driver */
+ {
+ int flags = debug ? 0x3 : 0;
+ if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
+ }
+ }
+
+ MAINDEBUG((LOG_INFO, "done pushing modules, ifunit %d", ifunit));
+}
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * It attempts to reconstruct the stream with the previously popped
+ * modules. This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ /*EMPTY*/
+
+ if (hungup) {
+ /* we can't push or pop modules after the stream has hung up */
+ str_module_count = 0;
+ return;
+ }
+
+ while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */
+ ;
+
+ for (; str_module_count > 0; str_module_count--) {
+ if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
+ syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
+ str_modules[str_module_count-1].modname);
+ } else {
+ MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
+ str_modules[str_module_count-1].modname));
+ }
+ }
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ struct strbuf str;
+
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+
+ str.len = len;
+ str.buf = (caddr_t) p;
+ if(putmsg(fd, NULL, &str, 0) < 0) {
+ syslog(LOG_ERR, "putmsg: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ struct strbuf str;
+ int len, i;
+
+ str.maxlen = MTU+DLLHEADERLEN;
+ str.buf = (caddr_t) buf;
+ i = 0;
+ len = getmsg(fd, NULL, &str, &i);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return -1;
+ }
+ syslog(LOG_ERR, "getmsg(fd) %m");
+ die(1);
+ }
+ if (len)
+ MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
+
+ if (str.len < 0) {
+ MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
+ return -1;
+ }
+
+ return str.len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
+ quit();
+ }
+
+ c = pcomp;
+ if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
+ quit();
+ }
+
+ c = accomp;
+ if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
+ quit();
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface. At present this just sets the MRU.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+
+ if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
+ }
+
+#ifdef notyet
+ if(ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
+ }
+
+ c = accomp;
+ if(ioctl(fd, SIOCSIFRCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFRCOMPAC): %m");
+ quit();
+ }
+#endif /* notyet */
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp)
+{
+ char x = vjcomp;
+
+ if(ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ int ret;
+ struct ifreq ifr;
+
+ ret = 1;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
+ if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
+ ret = 0;
+ }
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
+ if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
+ ret = 0;
+ }
+ if (m != 0) {
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
+ if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
+ rt.rt_flags = RTF_HOST;
+ if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr. Code borrowed from myetheraddr.c
+ * in the cslip-2.6 distribution, which is subject to the following
+ * copyright notice:
+ *
+ * Copyright (c) 1990, 1992 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <fcntl.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <arpa/inet.h>
+
+/* XXX SunOS 4.1 defines this and 3.5 doesn't... */
+#ifdef _nlist_h
+#define SUNOS4
+#endif
+
+#ifdef SUNOS4
+#include <netinet/in_var.h>
+#endif
+#include <netinet/if_ether.h>
+
+/* Cast a struct sockaddr to a structaddr_in */
+#define SATOSIN(sa) ((struct sockaddr_in *)(sa))
+
+/* Determine if "bits" is set in "flag" */
+#define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
+
+static struct nlist nl[] = {
+#define N_IFNET 0
+ { "_ifnet" },
+ 0
+};
+
+static void kread();
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ register kvm_t *kd;
+ register struct ifnet *ifp;
+ register struct arpcom *ac;
+ struct arpcom arpcom;
+ struct in_addr *inp;
+#ifdef SUNOS4
+ register struct ifaddr *ifa;
+ register struct in_ifaddr *in;
+ union {
+ struct ifaddr ifa;
+ struct in_ifaddr in;
+ } ifaddr;
+#endif
+ u_long addr, mask;
+
+ /* Open kernel memory for reading */
+ kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
+ if (kd == 0) {
+ syslog(LOG_ERR, "kvm_open: %m");
+ return 0;
+ }
+
+ /* Fetch namelist */
+ if (kvm_nlist(kd, nl) != 0) {
+ syslog(LOG_ERR, "kvm_nlist failed");
+ return 0;
+ }
+
+ ac = &arpcom;
+ ifp = &arpcom.ac_if;
+#ifdef SUNOS4
+ ifa = &ifaddr.ifa;
+ in = &ifaddr.in;
+#endif
+
+ if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
+ != sizeof(addr)) {
+ syslog(LOG_ERR, "error reading ifnet addr");
+ return 0;
+ }
+ for ( ; addr; addr = (u_long)ifp->if_next) {
+ if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
+ syslog(LOG_ERR, "error reading ifnet");
+ return 0;
+ }
+
+ /* Only look at configured, broadcast interfaces */
+ if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
+ continue;
+#ifdef SUNOS4
+ /* This probably can't happen... */
+ if (ifp->if_addrlist == 0)
+ continue;
+#endif
+
+ /* Get interface ip address */
+#ifdef SUNOS4
+ if (kvm_read(kd, (u_long)ifp->if_addrlist, (char *)&ifaddr,
+ sizeof(ifaddr)) != sizeof(ifaddr)) {
+ syslog(LOG_ERR, "error reading ifaddr");
+ return 0;
+ }
+ inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
+#else
+ inp = &SATOSIN(&ifp->if_addr)->sin_addr;
+#endif
+
+ /* Check if this interface on the right subnet */
+#ifdef SUNOS4
+ mask = in->ia_subnetmask;
+#else
+ mask = ifp->if_subnetmask;
+#endif
+ if ((ipaddr & mask) != (inp->s_addr & mask))
+ continue;
+
+ /* Copy out the local ethernet address */
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
+ sizeof(arpcom.ac_enaddr));
+ return 1; /* success! */
+ }
+
+ /* couldn't find one */
+ return 0;
+}
diff --git a/libexec/pppd/upap.c b/libexec/pppd/upap.c
index a58a01838836..7a9fa1f2db36 100644
--- a/libexec/pppd/upap.c
+++ b/libexec/pppd/upap.c
@@ -17,6 +17,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: upap.c,v 1.3 1994/03/30 09:38:20 jkh Exp $";
+#endif
+
/*
* TODO:
*/
@@ -26,38 +30,28 @@
#include <sys/time.h>
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/socket.h>
-#include <net/if.h>
-#include <sys/stream.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
-#include "fsm.h"
-#include "lcp.h"
#include "upap.h"
-#include "chap.h"
-#include "ipcp.h"
-upap_state upap[NPPP]; /* UPAP state; one for each unit */
+upap_state upap[_NPPP]; /* UPAP state; one for each unit */
static void upap_timeout __ARGS((caddr_t));
-static void upap_rauth __ARGS((upap_state *, u_char *, int, int));
+static void upap_rauthreq __ARGS((upap_state *, u_char *, int, int));
static void upap_rauthack __ARGS((upap_state *, u_char *, int, int));
static void upap_rauthnak __ARGS((upap_state *, u_char *, int, int));
-static void upap_sauth __ARGS((upap_state *));
-static void upap_sresp __ARGS((upap_state *, int, int, u_char *, int));
+static void upap_sauthreq __ARGS((upap_state *));
+static void upap_sresp __ARGS((upap_state *, int, int, char *, int));
/*
* upap_init - Initialize a UPAP unit.
*/
void
- upap_init(unit)
-int unit;
+upap_init(unit)
+ int unit;
{
upap_state *u = &upap[unit];
@@ -66,11 +60,11 @@ int unit;
u->us_userlen = 0;
u->us_passwd = NULL;
u->us_passwdlen = 0;
- u->us_clientstate = UPAPCS_CLOSED;
- u->us_serverstate = UPAPSS_CLOSED;
- u->us_flags = 0;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
u->us_id = 0;
u->us_timeouttime = UPAP_DEFTIMEOUT;
+ u->us_maxtransmits = 10;
}
@@ -80,45 +74,27 @@ int unit;
* Set new state and send authenticate's.
*/
void
- upap_authwithpeer(unit)
-int unit;
+upap_authwithpeer(unit, user, password)
+ int unit;
+ char *user, *password;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_AWPPENDING; /* Clear pending flag */
-
- /* Protect against programming errors that compromise security */
- if (u->us_serverstate != UPAPSS_CLOSED ||
- u->us_flags & UPAPF_APPENDING) {
- UPAPDEBUG((LOG_WARNING,
- "upap_authwithpeer: upap_authpeer already called!"))
+ /* Save the username and password we're given */
+ u->us_user = user;
+ u->us_userlen = strlen(user);
+ u->us_passwd = password;
+ u->us_passwdlen = strlen(password);
+ u->us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (u->us_clientstate == UPAPCS_INITIAL ||
+ u->us_clientstate == UPAPCS_PENDING) {
+ u->us_clientstate = UPAPCS_PENDING;
return;
}
- /* Already authenticat{ed,ing}? */
- if (u->us_clientstate == UPAPCS_AUTHSENT ||
- u->us_clientstate == UPAPCS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(u->us_flags & UPAPF_LOWERUP)) {
- u->us_flags |= UPAPF_AWPPENDING; /* Wait */
- return;
- }
-
- /* User/passwd values valid? */
- if (!(u->us_flags & UPAPF_UPVALID)) {
- GETUSERPASSWD(unit); /* Start getting user and passwd */
- if (!(u->us_flags & UPAPF_UPVALID)) {
- u->us_flags |= UPAPF_UPPENDING; /* Wait */
- return;
- }
- }
-
- upap_sauth(u); /* Start protocol */
-/* TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);*/
- u->us_clientstate = UPAPCS_AUTHSENT;
- u->us_retransmits = 0;
+ upap_sauthreq(u); /* Start protocol */
}
@@ -128,23 +104,18 @@ int unit;
* Set new state.
*/
void
- upap_authpeer(unit)
-int unit;
+upap_authpeer(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_APPENDING; /* Clear pending flag */
-
- /* Already authenticat{ed,ing}? */
- if (u->us_serverstate == UPAPSS_LISTEN ||
- u->us_serverstate == UPAPSS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(u->us_flags & UPAPF_LOWERUP)) {
- u->us_flags |= UPAPF_APPENDING; /* Wait for desired event */
+ /* Lower layer up yet? */
+ if (u->us_serverstate == UPAPSS_INITIAL ||
+ u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_PENDING;
return;
}
+
u->us_serverstate = UPAPSS_LISTEN;
}
@@ -153,19 +124,23 @@ int unit;
* upap_timeout - Timeout expired.
*/
static void
- upap_timeout(arg)
-caddr_t arg;
+upap_timeout(arg)
+ caddr_t arg;
{
- upap_state *u = (upap_state *) arg;
+ upap_state *u = (upap_state *) arg;
- if (u->us_clientstate != UPAPCS_AUTHSENT)
+ if (u->us_clientstate != UPAPCS_AUTHREQ)
return;
- /* XXX Print warning after many retransmits? */
+ if (u->us_transmits >= u->us_maxtransmits) {
+ /* give up in disgust */
+ syslog(LOG_ERR, "No response to PAP authenticate-requests");
+ u->us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(u->us_unit, UPAP);
+ return;
+ }
- upap_sauth(u); /* Send Configure-Request */
- TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
- ++u->us_retransmits;
+ upap_sauthreq(u); /* Send Authenticate-Request */
}
@@ -175,16 +150,21 @@ caddr_t arg;
* Start authenticating if pending.
*/
void
- upap_lowerup(unit)
-int unit;
+upap_lowerup(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags |= UPAPF_LOWERUP;
- if (u->us_flags & UPAPF_AWPPENDING) /* Attempting authwithpeer? */
- upap_authwithpeer(unit); /* Try it now */
- if (u->us_flags & UPAPF_APPENDING) /* Attempting authpeer? */
- upap_authpeer(unit); /* Try it now */
+ if (u->us_clientstate == UPAPCS_INITIAL)
+ u->us_clientstate = UPAPCS_CLOSED;
+ else if (u->us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(u); /* send an auth-request */
+ }
+
+ if (u->us_serverstate == UPAPSS_INITIAL)
+ u->us_serverstate = UPAPSS_CLOSED;
+ else if (u->us_serverstate == UPAPSS_PENDING)
+ u->us_serverstate = UPAPSS_LISTEN;
}
@@ -194,20 +174,16 @@ int unit;
* Cancel all timeouts.
*/
void
- upap_lowerdown(unit)
-int unit;
+upap_lowerdown(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_LOWERUP; /* XXX UPAP_UPVALID? */
-
- if (u->us_clientstate == UPAPCS_AUTHSENT) /* Timeout pending? */
+ if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
- if (u->us_serverstate == UPAPSS_OPEN) /* User logged in? */
- LOGOUT(unit);
- u->us_clientstate = UPAPCS_CLOSED;
- u->us_serverstate = UPAPSS_CLOSED;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
}
@@ -217,9 +193,19 @@ int unit;
* This shouldn't happen. In any case, pretend lower layer went down.
*/
void
- upap_protrej(unit)
-int unit;
+upap_protrej(unit)
+ int unit;
{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) {
+ syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
+ auth_withpeer_fail(unit, UPAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(unit, UPAP);
+ }
upap_lowerdown(unit);
}
@@ -228,10 +214,10 @@ int unit;
* upap_input - Input UPAP packet.
*/
void
- upap_input(unit, inpacket, l)
-int unit;
-u_char *inpacket;
-int l;
+upap_input(unit, inpacket, l)
+ int unit;
+ u_char *inpacket;
+ int l;
{
upap_state *u = &upap[unit];
u_char *inp;
@@ -244,18 +230,18 @@ int l;
*/
inp = inpacket;
if (l < UPAP_HEADERLEN) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."))
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < UPAP_HEADERLEN) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."))
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."));
return;
}
if (len > l) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
@@ -264,19 +250,19 @@ int l;
* Action depends on code.
*/
switch (code) {
- case UPAP_AUTH:
- upap_rauth(u, inp, id, len);
+ case UPAP_AUTHREQ:
+ upap_rauthreq(u, inp, id, len);
break;
- case UPAP_AUTHACK:
+ case UPAP_AUTHACK:
upap_rauthack(u, inp, id, len);
break;
- case UPAP_AUTHNAK:
+ case UPAP_AUTHNAK:
upap_rauthnak(u, inp, id, len);
break;
- default: /* XXX Need code reject */
+ default: /* XXX Need code reject */
break;
}
}
@@ -286,58 +272,72 @@ int l;
* upap_rauth - Receive Authenticate.
*/
static void
- upap_rauth(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthreq(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char ruserlen, rpasswdlen;
- u_char *ruser, *rpasswd;
- u_char retcode;
- u_char *msg;
+ char *ruser, *rpasswd;
+ int retcode;
+ char *msg;
int msglen;
- UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id))
- if (u->us_serverstate != UPAPSS_LISTEN) /* XXX Reset connection? */
+ UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
+
+ if (u->us_serverstate < UPAPSS_LISTEN)
return;
/*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (u->us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (u->us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
* Parse user/passwd.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);;
if (len < 0) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
- ruser = inp;
+ ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
- rpasswd = inp;
+ rpasswd = (char *) inp;
- retcode = LOGIN(u->us_unit, (char *) ruser, (int) ruserlen, (char *) rpasswd,
- (int) rpasswdlen, (char **) &msg, &msglen);
+ /*
+ * Check the username and password given.
+ */
+ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+ rpasswdlen, &msg, &msglen);
upap_sresp(u, retcode, id, msg, msglen);
- /* only crank up IPCP when either we aren't doing CHAP, or if we are, */
- /* that it is in open state */
-
if (retcode == UPAP_AUTHACK) {
u->us_serverstate = UPAPSS_OPEN;
- if (!lcp_hisoptions[u->us_unit].neg_chap ||
- (lcp_hisoptions[u->us_unit].neg_chap &&
- chap[u->us_unit].serverstate == CHAPSS_OPEN))
- ipcp_activeopen(u->us_unit); /* Start IPCP */
+ auth_peer_success(u->us_unit, UPAP);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, UPAP);
}
}
@@ -346,44 +346,38 @@ int len;
* upap_rauthack - Receive Authenticate-Ack.
*/
static void
- upap_rauthack(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthack(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char msglen;
- u_char *msg;
+ char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id))
- if (u->us_clientstate != UPAPCS_AUTHSENT) /* XXX */
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
- UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
return;
}
- msg = inp;
+ msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_OPEN;
- /* only crank up IPCP when either we aren't doing CHAP, or if we are, */
- /* that it is in open state */
-
- if (!lcp_gotoptions[u->us_unit].neg_chap ||
- (lcp_gotoptions[u->us_unit].neg_chap &&
- chap[u->us_unit].clientstate == CHAPCS_OPEN))
- ipcp_activeopen(u->us_unit); /* Start IPCP */
+ auth_withpeer_success(u->us_unit, UPAP);
}
@@ -391,47 +385,48 @@ int len;
* upap_rauthnak - Receive Authenticate-Nakk.
*/
static void
- upap_rauthnak(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthnak(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char msglen;
- u_char *msg;
+ char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id))
- if (u->us_clientstate != UPAPCS_AUTHSENT) /* XXX */
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
return;
}
- msg = inp;
+ msg = (char *) inp;
PRINTMSG(msg, msglen);
- u->us_flags &= ~UPAPF_UPVALID; /* Clear valid flag */
- u->us_clientstate = UPAPCS_CLOSED; /* Pretend for a moment */
- upap_authwithpeer(u->us_unit); /* Restart */
+ u->us_clientstate = UPAPCS_BADAUTH;
+
+ syslog(LOG_ERR, "PAP authentication failed");
+ auth_withpeer_fail(u->us_unit, UPAP);
}
/*
- * upap_sauth - Send an Authenticate.
+ * upap_sauthreq - Send an Authenticate-Request.
*/
static void
- upap_sauth(u)
-upap_state *u;
+upap_sauthreq(u)
+ upap_state *u;
{
u_char *outp;
int outlen;
@@ -442,7 +437,7 @@ upap_state *u;
MAKEHEADER(outp, UPAP);
- PUTCHAR(UPAP_AUTH, outp);
+ PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++u->us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(u->us_userlen, outp);
@@ -450,9 +445,14 @@ upap_state *u;
INCPTR(u->us_userlen, outp);
PUTCHAR(u->us_passwdlen, outp);
BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
- UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id))
+ UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
+
+ TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
+ ++u->us_transmits;
+ u->us_clientstate = UPAPCS_AUTHREQ;
}
@@ -460,11 +460,11 @@ upap_state *u;
* upap_sresp - Send a response (ack or nak).
*/
static void
- upap_sresp(u, code, id, msg, msglen)
-upap_state *u;
-u_char code, id;
-u_char *msg;
-int msglen;
+upap_sresp(u, code, id, msg, msglen)
+ upap_state *u;
+ u_char code, id;
+ char *msg;
+ int msglen;
{
u_char *outp;
int outlen;
@@ -480,5 +480,5 @@ int msglen;
BCOPY(msg, outp, msglen);
output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
- UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id))
+ UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
}
diff --git a/libexec/pppd/upap.h b/libexec/pppd/upap.h
index f25b9487ec5b..7f3b4e9613ca 100644
--- a/libexec/pppd/upap.h
+++ b/libexec/pppd/upap.h
@@ -15,6 +15,8 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: upap.h,v 1.2 1994/03/30 09:31:44 jkh Exp $
*/
/*
@@ -26,9 +28,9 @@
/*
* UPAP codes.
*/
-#define UPAP_AUTH 1 /* Authenticate */
-#define UPAP_AUTHACK 2 /* Authenticate Ack */
-#define UPAP_AUTHNAK 3 /* Authenticate Nak */
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
/*
@@ -42,35 +44,32 @@ typedef struct upap_state {
int us_passwdlen; /* Password length */
int us_clientstate; /* Client state */
int us_serverstate; /* Server state */
- int us_flags; /* Flags */
u_char us_id; /* Current id */
int us_timeouttime; /* Timeout time in milliseconds */
- int us_retransmits; /* Number of retransmissions */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
} upap_state;
/*
* Client states.
*/
-#define UPAPCS_CLOSED 1 /* Connection down */
-#define UPAPCS_AUTHSENT 2 /* We've sent an Authenticate */
-#define UPAPCS_OPEN 3 /* We've received an Ack */
+#define UPAPCS_INITIAL 0 /* Connection down */
+#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN 4 /* We've received an Ack */
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */
/*
* Server states.
*/
-#define UPAPSS_CLOSED 1 /* Connection down */
-#define UPAPSS_LISTEN 2 /* Listening for an Authenticate */
-#define UPAPSS_OPEN 3 /* We've sent an Ack */
-
-/*
- * Flags.
- */
-#define UPAPF_LOWERUP 1 /* The lower level is UP */
-#define UPAPF_AWPPENDING 2 /* Auth with peer pending */
-#define UPAPF_APPENDING 4 /* Auth peer pending */
-#define UPAPF_UPVALID 8 /* User/passwd values valid */
-#define UPAPF_UPPENDING 0x10 /* User/passwd values pending */
+#define UPAPSS_INITIAL 0 /* Connection down */
+#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
+#define UPAPSS_OPEN 4 /* We've sent an Ack */
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
/*
@@ -82,7 +81,7 @@ typedef struct upap_state {
extern upap_state upap[];
void upap_init __ARGS((int));
-void upap_authwithpeer __ARGS((int));
+void upap_authwithpeer __ARGS((int, char *, char *));
void upap_authpeer __ARGS((int));
void upap_lowerup __ARGS((int));
void upap_lowerdown __ARGS((int));
diff --git a/libexec/rexecd/Makefile b/libexec/rexecd/Makefile
index 093e9a6444f7..5916212ae5de 100644
--- a/libexec/rexecd/Makefile
+++ b/libexec/rexecd/Makefile
@@ -2,6 +2,12 @@
PROG= rexecd
MAN8= rexecd.8
+CFLAGS+= -DSKEY
+
+.PATH: ${.CURDIR}/../../usr.bin/key
+
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
diff --git a/libexec/rexecd/rexecd.c b/libexec/rexecd/rexecd.c
index 914e051ed916..ff2704bafe75 100644
--- a/libexec/rexecd/rexecd.c
+++ b/libexec/rexecd/rexecd.c
@@ -98,7 +98,13 @@ doit(f, fromp)
struct sockaddr_in *fromp;
{
char cmdbuf[NCARGS+1], *cp, *namep;
+#ifdef SKEY
+ char *skey_crypt();
+ int permit_passwd = authfile(inet_ntoa(fromp->sin_addr));
+ char user[16], pass[100];
+#else /* SKEY */
char user[16], pass[16];
+#endif /* SKEY */
struct passwd *pwd;
int s;
u_short port;
@@ -154,7 +160,11 @@ doit(f, fromp)
}
endpwent();
if (*pwd->pw_passwd != '\0') {
+#ifdef SKEY
+ namep = skey_crypt(pass, pwd->pw_passwd, pwd, permit_passwd);
+#else /* SKEY */
namep = crypt(pass, pwd->pw_passwd);
+#endif /* SKEY */
if (strcmp(namep, pwd->pw_passwd)) {
error("Password incorrect.\n");
exit(1);
@@ -208,6 +218,7 @@ doit(f, fromp)
pwd->pw_shell = _PATH_BSHELL;
if (f > 2)
(void) close(f);
+ (void) setlogin(pwd->pw_name);
(void) setgid((gid_t)pwd->pw_gid);
initgroups(pwd->pw_name, pwd->pw_gid);
(void) setuid((uid_t)pwd->pw_uid);
diff --git a/libexec/rlogind/Makefile b/libexec/rlogind/Makefile
index 90254a106465..3ca4401cf755 100644
--- a/libexec/rlogind/Makefile
+++ b/libexec/rlogind/Makefile
@@ -1,4 +1,5 @@
-# @(#)Makefile 5.9 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.5 1994/03/04 20:32:55 wollman Exp $
+# From: @(#)Makefile 5.9 (Berkeley) 9/27/90
PROG= rlogind
SRCS= rlogind.c
@@ -7,10 +8,14 @@ DPADD= ${LIBUTIL}
LDADD= -lutil
.PATH: ${.CURDIR}/../../usr.bin/rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+CFLAGS+= -DKERBEROS
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
.endif
.include <bsd.prog.mk>
diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c
index f3b50b696be4..f81c8253f2a3 100644
--- a/libexec/rlogind/rlogind.c
+++ b/libexec/rlogind/rlogind.c
@@ -44,7 +44,7 @@ static char sccsid[] = "@(#)rlogind.c 5.53 (Berkeley) 4/20/91";
#ifdef KERBEROS
/* From:
* $Source: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v $
- * $Header: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.1.1.1 1993/06/12 14:54:58 rgrimes Exp $
+ * $Header: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.2 1994/05/22 19:22:02 karl Exp $
*/
#endif
@@ -317,6 +317,11 @@ doit(f, fromp)
if (f > 2) /* f should always be 0, but... */
(void) close(f);
setup_term(0);
+ if (strchr(lusername, '-')) {
+ syslog(LOG_ERR, "tried to pass user \"%s\" to login",
+ lusername);
+ fatal(STDERR_FILENO, "invalid user", 0);
+ }
if (authenticated) {
#ifdef KERBEROS
if (use_kerberos && (pwd->pw_uid == 0))
diff --git a/libexec/rpc.rusersd/rusers_proc.c b/libexec/rpc.rusersd/rusers_proc.c
index 31f4bfe50d9f..ab9d6a0c53f3 100644
--- a/libexec/rpc.rusersd/rusers_proc.c
+++ b/libexec/rpc.rusersd/rusers_proc.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: rusers_proc.c,v 1.1.2.1 1994/03/07 02:28:00 rgrimes Exp $";
+static char rcsid[] = "$Id: rusers_proc.c,v 1.2 1994/03/06 02:07:58 jkh Exp $";
#endif /* not lint */
#include <signal.h>
diff --git a/libexec/rshd/Makefile b/libexec/rshd/Makefile
index bf4b594e99e6..2c0ac884c0e6 100644
--- a/libexec/rshd/Makefile
+++ b/libexec/rshd/Makefile
@@ -1,4 +1,5 @@
-# @(#)Makefile 5.6 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.5 1994/03/04 20:36:58 wollman Exp $
+# From: @(#)Makefile 5.6 (Berkeley) 9/27/90
PROG= rshd
SRCS= rshd.c
@@ -7,11 +8,14 @@ DPADD= ${LIBUTIL}
LDADD= -lutil
.PATH: ${.CURDIR}/../../usr.bin/rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS -DCRYPT
.endif
-
.include <bsd.prog.mk>
diff --git a/libexec/telnetd/sys_term.c b/libexec/telnetd/sys_term.c
index cde67833dfb4..675916174162 100644
--- a/libexec/telnetd/sys_term.c
+++ b/libexec/telnetd/sys_term.c
@@ -1273,7 +1273,7 @@ start_login(host, autologin, name)
{
register char *cp;
register char **argv;
- char **addarg();
+ char **addarg(), *user;
/*
* -h : pass on name of host.
@@ -1315,7 +1315,12 @@ start_login(host, autologin, name)
argv = addarg(argv, name);
} else
#endif
- if (getenv("USER")) {
+ if (user = getenv("USER")) {
+ if (strchr(user, '-')) {
+ syslog(LOG_ERR, "tried to pass user \"%s\" to login",
+ user);
+ fatal(net, "invalid user");
+ }
argv = addarg(argv, getenv("USER"));
#if defined(CRAY) && defined(NO_LOGIN_P)
{
diff --git a/libexec/uucpd/Makefile b/libexec/uucpd/Makefile
index 474992ec92e1..7904bfd53c3a 100644
--- a/libexec/uucpd/Makefile
+++ b/libexec/uucpd/Makefile
@@ -3,6 +3,7 @@
PROG= uucpd
NOMAN= noman
+LDADD+= -lutil
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
diff --git a/libexec/uucpd/pathnames.h b/libexec/uucpd/pathnames.h
index 380c7ef204dd..133f2f5a7347 100644
--- a/libexec/uucpd/pathnames.h
+++ b/libexec/uucpd/pathnames.h
@@ -35,4 +35,4 @@
#include <paths.h>
-#define _PATH_UUCICO "/usr/lib/uucp/uucico"
+#define _PATH_UUCICO "/usr/libexec/uucp/uucico"
diff --git a/libexec/uucpd/uucpd.c b/libexec/uucpd/uucpd.c
index 76a994c6b729..c862ccea137d 100644
--- a/libexec/uucpd/uucpd.c
+++ b/libexec/uucpd/uucpd.c
@@ -65,11 +65,18 @@ static char sccsid[] = "@(#)uucpd.c 5.10 (Berkeley) 2/26/91";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <utmp.h>
+#include <syslog.h>
+#include <varargs.h>
#include "pathnames.h"
-struct sockaddr_in hisctladdr;
+#define SCPYN(a, b) strncpy(a, b, sizeof (a))
+
+struct utmp utmp;
+
+struct sockaddr hisctladdr;
int hisaddrlen = sizeof hisctladdr;
-struct sockaddr_in myctladdr;
+struct sockaddr myctladdr;
int mypid;
char Username[64];
@@ -83,176 +90,128 @@ main(argc, argv)
int argc;
char **argv;
{
-#ifndef BSDINETD
- register int s, tcp_socket;
- struct servent *sp;
-#endif !BSDINETD
extern int errno;
int dologout();
environ = nenv;
-#ifdef BSDINETD
close(1); close(2);
dup(0); dup(0);
hisaddrlen = sizeof (hisctladdr);
+ openlog("uucpd", LOG_PID, LOG_DAEMON);
if (getpeername(0, &hisctladdr, &hisaddrlen) < 0) {
- fprintf(stderr, "%s: ", argv[0]);
- perror("getpeername");
+ syslog(LOG_ERR, "getpeername: %m");
_exit(1);
}
- if (fork() == 0)
- doit(&hisctladdr);
+ doit(&hisctladdr);
dologout();
- exit(1);
-#else !BSDINETD
- sp = getservbyname("uucp", "tcp");
- if (sp == NULL){
- perror("uucpd: getservbyname");
- exit(1);
- }
- if (fork())
- exit(0);
- if ((s=open(_PATH_TTY, 2)) >= 0){
- ioctl(s, TIOCNOTTY, (char *)0);
- close(s);
- }
+ _exit(0);
+}
- bzero((char *)&myctladdr, sizeof (myctladdr));
- myctladdr.sin_family = AF_INET;
- myctladdr.sin_port = sp->s_port;
-#ifdef BSD4_2
- tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (tcp_socket < 0) {
- perror("uucpd: socket");
- exit(1);
- }
- if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) {
- perror("uucpd: bind");
- exit(1);
- }
- listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */
- signal(SIGCHLD, dologout);
+login_incorrect()
+{
+ char passwd[64];
- for(;;) {
- s = accept(tcp_socket, &hisctladdr, &hisaddrlen);
- if (s < 0){
- if (errno == EINTR)
- continue;
- perror("uucpd: accept");
- exit(1);
- }
- if (fork() == 0) {
- close(0); close(1); close(2);
- dup(s); dup(s); dup(s);
- close(tcp_socket); close(s);
- doit(&hisctladdr);
- exit(1);
- }
- close(s);
+ printf("Password: "); fflush(stdout);
+ if (readline(passwd, sizeof passwd, 1) < 0) {
+ syslog(LOG_WARNING, "passwd read");
+ _exit(1);
}
-#endif BSD4_2
-
-#endif !BSDINETD
+ fprintf(stderr, "Login incorrect.\n");
+ exit(1);
}
doit(sinp)
-struct sockaddr_in *sinp;
+struct sockaddr *sinp;
{
- char user[64], passwd[64];
+ char user[64], passwd[64], ubuf[64];
char *xpasswd, *crypt();
struct passwd *pw, *getpwnam();
+ int s;
alarm(60);
printf("login: "); fflush(stdout);
- if (readline(user, sizeof user) < 0) {
- fprintf(stderr, "user read\n");
- return;
+ if (readline(user, sizeof user, 0) < 0) {
+ syslog(LOG_WARNING, "login read");
+ _exit(1);
}
/* truncate username to 8 characters */
user[8] = '\0';
pw = getpwnam(user);
- if (pw == NULL) {
- fprintf(stderr, "user unknown\n");
- return;
- }
- if (strcmp(pw->pw_shell, _PATH_UUCICO)) {
- fprintf(stderr, "Login incorrect.");
- return;
- }
+ if (pw == NULL)
+ login_incorrect();
+ if (strcmp(pw->pw_shell, _PATH_UUCICO))
+ login_incorrect();
if (pw->pw_passwd && *pw->pw_passwd != '\0') {
printf("Password: "); fflush(stdout);
- if (readline(passwd, sizeof passwd) < 0) {
- fprintf(stderr, "passwd read\n");
- return;
+ if (readline(passwd, sizeof passwd, 1) < 0) {
+ syslog(LOG_WARNING, "passwd read");
+ _exit(1);
}
xpasswd = crypt(passwd, pw->pw_passwd);
if (strcmp(xpasswd, pw->pw_passwd)) {
- fprintf(stderr, "Login incorrect.");
- return;
+ fprintf(stderr, "Login incorrect.\n");
+ exit(1);
}
}
alarm(0);
- sprintf(Username, "USER=%s", user);
- dologin(pw, sinp);
- setgid(pw->pw_gid);
-#ifdef BSD4_2
- initgroups(pw->pw_name, pw->pw_gid);
-#endif BSD4_2
- chdir(pw->pw_dir);
- setuid(pw->pw_uid);
-#ifdef BSD4_2
- execl(UUCICO, "uucico", (char *)0);
-#endif BSD4_2
- perror("uucico server: execl");
+ sprintf(Username, "USER=%s", pw->pw_name);
+ sprintf(ubuf, "-u%s", pw->pw_name);
+ if ((s = fork()) < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ _exit(1);
+ } else if (s == 0) {
+ dologin(pw, sinp);
+ setgid(pw->pw_gid);
+ initgroups(pw->pw_name, pw->pw_gid);
+ chdir(pw->pw_dir);
+ setuid(pw->pw_uid);
+ execl(pw->pw_shell, "uucico", ubuf, NULL);
+ syslog(LOG_ERR, "execl: %m");
+ _exit(1);
+ }
}
-readline(p, n)
-register char *p;
-register int n;
+readline(start, num, pass)
+char start[];
+int num, pass;
{
char c;
+ register char *p = start;
+ register int n = num;
while (n-- > 0) {
if (read(0, &c, 1) <= 0)
return(-1);
c &= 0177;
- if (c == '\n' || c == '\r') {
+ if (c == '\n' || c == '\r' || c == '\0') {
+ if (p == start && pass) {
+ n++;
+ continue;
+ }
*p = '\0';
return(0);
}
+ if (c == 025) {
+ n = num;
+ p = start;
+ continue;
+ }
*p++ = c;
}
return(-1);
}
-#include <utmp.h>
-#ifdef BSD4_2
-#include <fcntl.h>
-#endif BSD4_2
-
-#define SCPYN(a, b) strncpy(a, b, sizeof (a))
-
-struct utmp utmp;
dologout()
{
union wait status;
- int pid, wtmp;
+ int pid;
+ char line[32];
-#ifdef BSDINETD
while ((pid=wait((int *)&status)) > 0) {
-#else !BSDINETD
- while ((pid=wait3((int *)&status,WNOHANG,0)) > 0) {
-#endif !BSDINETD
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- sprintf(utmp.ut_line, "uucp%.4d", pid);
- SCPYN(utmp.ut_name, "");
- SCPYN(utmp.ut_host, "");
- (void) time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ sprintf(line, "uu%d", pid);
+ logout(line);
+ logwtmp(line, "", "");
}
}
@@ -265,7 +224,8 @@ struct sockaddr_in *sin;
{
char line[32];
char remotehost[32];
- int wtmp, f;
+ int f;
+ time_t cur_time;
struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
sizeof (struct in_addr), AF_INET);
@@ -275,26 +235,22 @@ struct sockaddr_in *sin;
} else
strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof (remotehost));
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- /* hack, but must be unique and no tty line */
- sprintf(line, "uucp%.4d", getpid());
- SCPYN(utmp.ut_line, line);
- SCPYN(utmp.ut_name, pw->pw_name);
- SCPYN(utmp.ut_host, remotehost);
- time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ sprintf(line, "uu%d", getpid());
+ /* hack, but must be unique and no tty line */
+ time(&cur_time);
if ((f = open(_PATH_LASTLOG, O_RDWR)) >= 0) {
struct lastlog ll;
- time(&ll.ll_time);
- lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), 0);
- strcpy(line, remotehost);
+ ll.ll_time = cur_time;
+ lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), L_SET);
SCPYN(ll.ll_line, line);
SCPYN(ll.ll_host, remotehost);
(void) write(f, (char *) &ll, sizeof ll);
(void) close(f);
}
+ utmp.ut_time = cur_time;
+ SCPYN(utmp.ut_line, line);
+ SCPYN(utmp.ut_name, pw->pw_name);
+ SCPYN(utmp.ut_host, remotehost);
+ login(&utmp);
}
diff --git a/libexec/xtend/Makefile b/libexec/xtend/Makefile
new file mode 100644
index 000000000000..4b9ade3ca6e0
--- /dev/null
+++ b/libexec/xtend/Makefile
@@ -0,0 +1,11 @@
+# Makefile for xtend (Stark) 10/30/93
+
+BINMODE= 4555
+
+PROG= xtend
+SRCS= xtend.c status.c packet.c user.c
+CFLAGS+=-I.
+
+MAN8= xtend.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/xtend/packet.c b/libexec/xtend/packet.c
new file mode 100644
index 000000000000..bc75fcb9393d
--- /dev/null
+++ b/libexec/xtend/packet.c
@@ -0,0 +1,317 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+
+char *X10housenames[] = {
+ "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P",
+ NULL
+};
+
+char *X10cmdnames[] = {
+ "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
+ "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
+ "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
+ NULL
+};
+
+/*
+ * Log a packet and update device status accordingly
+ */
+
+logpacket(p)
+unsigned char *p;
+{
+ fprintf(Log, "%s: %s %s ", thedate(),
+ X10housenames[p[1]], X10cmdnames[p[2]]);
+ if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,");
+ else fprintf(Log, "(rem,");
+ if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)");
+ else fprintf(Log, " ok)");
+ fprintf(Log, "\n");
+}
+
+/*
+ * Process a received packet p, updating device status information both
+ * in core and on disk.
+ */
+
+processpacket(p)
+unsigned char *p;
+{
+ int i, j, h, k;
+ STATUS *s;
+
+ /*
+ * If the packet had the error flag set, there is no other useful info.
+ */
+ if(p[0] & TW_RCV_ERROR) return;
+ /*
+ * First update in-core status information for the device.
+ */
+ h = p[1]; k = p[2];
+ if(k < 16) { /* We received a unit code, to select a particular device */
+ s = &Status[h][k];
+ s->selected = SELECTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ } else { /* We received a key code, to execute some function */
+ /*
+ * Change in status depends on the key code received
+ */
+ if(k == DIM) {
+ /*
+ * We can't really track DIM/BRIGHT properly the way things are right
+ * now. The TW523 reports the first, fourth, seventh, etc. Dim packet.
+ * We don't really have any way to tell when gaps occur, to cancel
+ * selection. For now, we'll assume that successive sequences of
+ * Dim/Bright commands are never transmitted without some other
+ * intervening command, and we make a good guess about how many units of
+ * dim/bright are represented by each packet actually reported by the
+ * TW523.
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness -= 2;
+ if(s->brightness < 0) s->brightness = 0;
+ s->selected = DIMMING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed */
+ s->brightness -=3;
+ if(s->brightness < 0) s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if(k == BRIGHT) {
+ /*
+ * Same problem here...
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness += 2;
+ if(s->brightness > 15) s->brightness = 15;
+ s->selected = BRIGHTENING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened */
+ s->brightness +=3;
+ if(s->brightness > 15) s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else { /* Other key codes besides Bright and Dim */
+ /*
+ * We cancel brightening and dimming on ALL units on ALL house codes,
+ * because the arrival of a different packet indicates a gap that
+ * terminates any prior sequence of brightening and dimming
+ */
+ for(j = 0; j < 16; j++) {
+ for(i = 0; i < 16; i++) {
+ s = &Status[j][i];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ switch(k) {
+ case ALLUNITSOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ break;
+ case ALLLIGHTSON:
+ /* Does AllLightsOn cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case ALLLIGHTSOFF:
+ /* Does AllLightsOff cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDCODE:
+ break;
+ case HAILREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = HAILED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case HAILACKNOWLEDGE:
+ /* Do these commands cancel selection of devices not affected? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == HAILED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case PRESETDIM0:
+ case PRESETDIM1:
+ /* I don't really understand these */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDDATA:
+ /* Who knows? The TW523 can't receive these anyway. */
+ break;
+ case STATUSON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == REQUESTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case STATUSOFF:
+ for(i = 0; i < 16; i++) {
+ if(s->selected == REQUESTED) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ case STATUSREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected) {
+ s->selected = REQUESTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/libexec/xtend/paths.h b/libexec/xtend/paths.h
new file mode 100644
index 000000000000..ad49443c5397
--- /dev/null
+++ b/libexec/xtend/paths.h
@@ -0,0 +1,11 @@
+/*
+ * Pathnames for files used by xtend
+ */
+
+#define X10DIR "/var/spool/xten/"
+#define X10LOGNAME "Log"
+#define X10STATNAME "Status"
+#define X10DUMPNAME "status.out"
+#define TWPATH "/dev/tw0"
+#define SOCKPATH "/var/run/tw523"
+#define PIDPATH "/var/run/xtend.pid"
diff --git a/libexec/xtend/status.c b/libexec/xtend/status.c
new file mode 100644
index 000000000000..6249577b4585
--- /dev/null
+++ b/libexec/xtend/status.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+/*
+ * Initialize the status table from the status files
+ */
+
+initstatus()
+{
+ int h, i;
+
+ if(lseek(status, 0, SEEK_SET) != 0) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ return;
+ }
+ if(read(status, Status, 16*16*sizeof(STATUS)) != 16*16*sizeof(STATUS)) {
+ fprintf(Log, "%s: Read error on status file\n", thedate());
+ return;
+ }
+}
+
+/*
+ * Checkpoint status of any devices whose status has changed
+ * and notify anyone monitoring those devices.
+ */
+
+checkpoint_status()
+{
+ int h, i, k, offset;
+
+ offset = 0;
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].changed) {
+ if(lseek(status, offset, SEEK_SET) != offset) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ } else {
+ if(write(status, &Status[h][i], sizeof(STATUS)) != sizeof(STATUS)) {
+ fprintf(Log, "%s: Write error on status file\n", thedate());
+ }
+ }
+ Status[h][i].changed = 0;
+ for(k = 0; k < MAXMON; k++) {
+ if(Monitor[k].inuse
+ && Monitor[k].house == h && Monitor[k].unit == i) {
+ /*
+ * Arrange to catch SIGPIPE in case client has gone away.
+ */
+ extern int client;
+ extern void clientgone();
+ void (*prev)();
+
+ client = k;
+ prev = signal(SIGPIPE, clientgone);
+ printstatus(Monitor[k].user, &Status[h][i]);
+ fflush(Monitor[k].user);
+ signal(SIGPIPE, prev);
+ }
+ }
+ }
+ offset += sizeof(STATUS);
+ }
+ }
+}
+
+int client;
+
+void clientgone()
+{
+ fprintf(Log, "%s: Deleting monitor table entry %d, client gone\n", thedate(), client);
+ fclose(Monitor[client].user);
+ Monitor[client].inuse = 0;
+}
diff --git a/libexec/xtend/user.c b/libexec/xtend/user.c
new file mode 100644
index 000000000000..15da74409bfc
--- /dev/null
+++ b/libexec/xtend/user.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+MONENTRY Monitor[MAXMON];
+
+/*
+ * Process a user command
+ */
+
+user_command()
+{
+ char h;
+ int i, k, c, n, error;
+ char cmd[512], dumppath[MAXPATHLEN+1], pkt[3];
+ FILE *dumpf;
+
+ error = 0;
+ if(fgets(cmd, 512, User) != NULL) {
+ if(sscanf(cmd, "status %c %d", &h, &i) == 2
+ && h >= 'A' && h <= 'P' && i >= 1 && i <= 16) {
+ h -= 'A';
+ i--;
+ printstatus(User, &Status[h][i]);
+ } else if(sscanf(cmd, "send %c %s %d", &h, cmd, &n) == 3
+ && h >= 'A' && h <= 'P' && (i = find(cmd, X10cmdnames)) >= 0) {
+ h -= 'A';
+ pkt[0] = h;
+ pkt[1] = i;
+ pkt[2] = n;
+ if(write(tw523, pkt, 3) != 3) {
+ fprintf(Log, "%s: Transmission error (packet [%s %s]:%d).\n",
+ thedate(), X10housenames[h], X10cmdnames[i], n);
+ error++;
+ } else {
+ fprintf(User, "OK\n");
+ }
+ } else if(!strcmp("dump", cmd)) {
+ strcpy(dumppath, X10DIR);
+ strcat(dumppath, X10DUMPNAME);
+ if((dumpf = fopen(dumppath, "w")) != NULL) {
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].lastchange) {
+ fprintf(dumpf, "%s%d\t", X10housenames[h], i+1);
+ printstatus(dumpf, &Status[h][i]);
+ }
+ }
+ }
+ fclose(dumpf);
+ fprintf(User, "OK\n");
+ } else {
+ error++;
+ }
+ } else if(sscanf(cmd, "monitor %c %d", &h, &i) == 2
+ && h >= 'A' && h <= 'P' && i >= 1 && i <= 16) {
+ h -= 'A';
+ i--;
+ for(k = 0; k < MAXMON; k++) {
+ if(!Monitor[k].inuse) break;
+ }
+ if(k == MAXMON) {
+ error++;
+ } else {
+ Monitor[k].house = h;
+ Monitor[k].unit = i;
+ Monitor[k].user = User;
+ Monitor[k].inuse = 1;
+ fprintf(Log, "%s: Adding %c %d to monitor list (entry %d)\n",
+ thedate(), h+'A', i+1, k);
+ fprintf(User, "OK\n");
+ fflush(User);
+ User = NULL;
+ return(0); /* We don't want caller to close stream */
+ }
+ } else {
+ if(feof(User)) {
+ return(1);
+ } else {
+ error++;
+ }
+ }
+ } else {
+ error++;
+ }
+ if(error) {
+ fprintf(User, "ERROR\n");
+ }
+ fflush(User);
+ return(0);
+}
+
+find(s, tab)
+char *s;
+char *tab[];
+{
+ int i;
+
+ for(i = 0; tab[i] != NULL; i++) {
+ if(strcmp(s, tab[i]) == 0) return(i);
+ }
+ return(-1);
+}
+
+printstatus(f, s)
+FILE *f;
+STATUS *s;
+{
+ fprintf(f, "%s:%d", s->onoff ? "On" : "Off", s->brightness);
+ switch(s->selected) {
+ case IDLE:
+ fprintf(f, " (normal) "); break;
+ case SELECTED:
+ fprintf(f, " (selected) "); break;
+ case DIMMING:
+ fprintf(f, " (dimming) "); break;
+ case BRIGHTENING:
+ fprintf(f, " (brightening) "); break;
+ case REQUESTED:
+ fprintf(f, " (requested) "); break;
+ case HAILED:
+ fprintf(f, " (hailed) "); break;
+ default:
+ fprintf(f, " (bogus) "); break;
+ }
+ fprintf(f, "%s", ctime(&s->lastchange));
+}
+
diff --git a/libexec/xtend/xten.h b/libexec/xtend/xten.h
new file mode 100644
index 000000000000..fea7e1786039
--- /dev/null
+++ b/libexec/xtend/xten.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+extern char *X10housenames[];
+extern char *X10cmdnames[];
+
+#define ALLUNITSOFF 16
+#define ALLLIGHTSON 17
+#define UNITON 18
+#define UNITOFF 19
+#define DIM 20
+#define BRIGHT 21
+#define ALLLIGHTSOFF 22
+#define EXTENDEDCODE 23
+#define HAILREQUEST 24
+#define HAILACKNOWLEDGE 25
+#define PRESETDIM0 26
+#define PRESETDIM1 27
+#define EXTENDEDDATA 28
+#define STATUSON 29
+#define STATUSOFF 30
+#define STATUSREQUEST 31
+
+/*
+ * Flags for first byte of received packet
+ */
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
diff --git a/libexec/xtend/xtend.8 b/libexec/xtend/xtend.8
new file mode 100644
index 000000000000..e6ac50ac5602
--- /dev/null
+++ b/libexec/xtend/xtend.8
@@ -0,0 +1,174 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" 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 Eugene W. Stark.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+.\"
+.Th XTEND 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt XTEND 8
+.Os BSD FreeBSD
+.Sh NAME
+xtend \- X-10 daemon
+.Sh SYNOPSIS
+.Nm xtend
+.Sh DESCRIPTION
+.Nm Xtend
+interfaces between user-level programs and the TW523 X-10 controller.
+It logs all packets received from the TW523, attempts to track the
+status of all X-10 devices, and accepts socket connections from user-level
+client programs that need to manipulate X-10 devices.
+.Pp
+When
+.Nm xtend
+is started, it forks, releases the controlling terminal, then opens
+its log file, where it subsequently records all X-10 activity and
+diagnostic messages. It then begins processing packets received from
+the TW523 and accepting connections one at a time from clients
+wishing to issue X-10 commands. The usual place to start xtend would
+be from the
+.Pa /etc/rc.local
+startup script.
+.Pp
+Sending
+.Nm xtend
+a SIGHUP causes it to close and reopen its log file. This is useful
+in shell scripts that rotate the log files to keep them from growing
+indefinitely.
+If
+.Nm xtend
+receives a SIGTERM, it shuts down gracefully and exits.
+A SIGPIPE causes
+.Nm xtend
+to abort the current client connection.
+.Pp
+.Nm Xtend
+communicates with client processes by a simple protocol in which a one-line
+command is sent by the client, and is acknowledged by a one-line response
+from the daemon.
+.Pp
+.Nm Xtend
+understands four types of commands. The command
+.Bl -tag
+.It status H U
+.El
+.Pp
+where H is a single letter house code, and U is a numeric unit code,
+causes
+.Nm xtend
+to respond with one line of status information about the specified device.
+The command
+.Bl -tag
+.It send H U N
+.El
+.Pp
+where H is a single-letter house code, U is either a numeric unit code
+or a function code (see source file
+.Pa xtend/packet.c
+) for a list, and N is a number indicating the number of times (usually 2)
+the packet is to be transmitted without gaps,
+causes
+.Nm xtend
+to perform the specified X-10 transmission. If the transmission was apparently
+successful, a single-line response containing
+.B
+OK
+is issued, otherwise a single-line response containing
+.B
+ERROR
+is produced.
+The command
+.Bl -tag
+.It dump
+.El
+.Pp
+causes
+.Nm xtend
+to dump the current status of all devices to an ASCII file in the spool
+directory. The response
+.B
+OK
+is issued, regardless of whether the status dump was successful.
+The command
+.Bl -tag
+.It monitor H U
+.El
+.Pp
+causes
+.Nm xtend
+to add the current client socket connection to a list of clients that are to
+be notified about activity concerning the specified X-10 device.
+The single-line acknowledgement
+.B
+OK
+is returned if the maximum (currently 5) number of such clients was not
+exceeded, otherwise
+.B
+ERROR
+is returned.
+.Nm Xtend
+then returns to its normal mode of accepting connections from clients.
+However, each subsequent change in the status of the specified device will
+cause
+.Nm xtend
+to write one line of status information for the device (in the same
+format as produced by the
+.B
+status
+command) to the saved socket. This feature is useful for writing programs
+that need to monitor the activity of devices, like motion detectors, that can
+perform X-10 transmissions.
+.Sh OPTIONS
+None.
+.Sh SEE ALSO
+.Xr xten 1
+.Xr tw 4
+.Sh FILES
+.Bl -tag -width /var/spool/xten/Status -compact
+.It Pa /dev/tw0
+the TW523 special file
+.It Pa /var/run/tw523
+socket for client connections
+.It Pa /var/run/xtend.pid
+pid file
+.It Pa /var/spool/xten/Log
+log file
+.It Pa /var/spool/xten/Status
+device status file (binary)
+.It Pa /var/spool/status.out
+ASCII dump of device status
+.El
+.Sh BUGS
+There is currently no timeout on client socket connections, so a hung
+client program can prevent other clients from accessing the daemon.
+.Pp
+.Nm Xtend
+does the best it can at trying to track device status, but there is
+usually no way it can tell when a device has been operated manually.
+This is due to the fact that most X-10 devices are not able to
+respond to queries about their status.
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/libexec/xtend/xtend.c b/libexec/xtend/xtend.c
new file mode 100644
index 000000000000..4372481008c9
--- /dev/null
+++ b/libexec/xtend/xtend.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+/*
+ * xtend - X-10 daemon
+ * Eugene W. Stark (stark@cs.sunysb.edu)
+ * January 14, 1993
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+FILE *Log; /* Log file */
+FILE *User; /* User connection */
+STATUS Status[16][16]; /* Device status table */
+int status; /* Status file descriptor */
+int tw523; /* tw523 controller */
+int sock; /* socket for user */
+jmp_buf mainloop; /* longjmp point after SIGHUP */
+void onhup(); /* SIGHUP handler */
+void onterm(); /* SIGTERM handler */
+void onpipe(); /* SIGPIPE handler */
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *twpath = TWPATH;
+ char *sockpath = SOCKPATH;
+ char logpath[MAXPATHLEN+1];
+ char statpath[MAXPATHLEN+1];
+ struct sockaddr_un sa;
+ struct timeval tv;
+ int user;
+ int fd;
+ FILE *pidf;
+
+ /*
+ * Open the log file before doing anything
+ */
+ strcpy(logpath, X10DIR);
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+
+ /*
+ * Next fork like a proper daemon
+ */
+ switch(fork()) {
+ case -1:
+ fprintf(Log, "%s: %s unable to fork\n", thedate(), argv[0]);
+ exit(1);
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+ fprintf(Log, "%s: %s[%d] started\n", thedate(), argv[0], getpid());
+
+ /*
+ * Release the controlling terminal so we don't get any signals from it.
+ */
+ setpgrp(0, getpid());
+ if ((fd = open("/dev/tty", 2)) >= 0)
+ {
+ ioctl(fd, TIOCNOTTY, (char*)0);
+ close(fd);
+ }
+
+ /*
+ * Get ahold of the TW523 device
+ */
+ if((tw523 = open(twpath, O_RDWR)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), twpath);
+ exit(1);
+ }
+ fprintf(Log, "%s: %s successfully opened\n", thedate(), twpath);
+
+ /*
+ * Initialize the status table
+ */
+ strcpy(statpath, X10DIR);
+ strcat(statpath, X10STATNAME);
+ if((status = open(statpath, O_RDWR)) < 0) {
+ if((status = open(statpath, O_RDWR | O_CREAT, 0666)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), statpath);
+ exit(1);
+ }
+ if(write(status, Status, 16 * 16 * sizeof(STATUS))
+ != 16 * 16 * sizeof(STATUS)) {
+ fprintf(Log, "%s: Error initializing status file\n", thedate());
+ exit(1);
+ }
+ }
+ initstatus();
+
+ /*
+ * Put our pid in a file so we can be signalled by shell scripts
+ */
+ if((pidf = fopen(PIDPATH, "w")) == NULL) {
+ fprintf(Log, "%s: Error writing pid file: %s\n", thedate(), PIDPATH);
+ exit(1);
+ }
+ fprintf(pidf, "%d\n", getpid());
+ fclose(pidf);
+
+ /*
+ * Set up socket to accept user commands
+ */
+ if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fprintf(Log, "%s: Can't create socket\n", thedate());
+ exit(1);
+ }
+ strcpy(sa.sun_path, sockpath);
+ sa.sun_family = AF_UNIX;
+ unlink(sockpath);
+ if(bind(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) {
+ fprintf(Log, "%s: Can't bind socket to %s\n", thedate(), sockpath);
+ exit(1);
+ }
+ if(listen(sock, 5) < 0) {
+ fprintf(Log, "%s: Can't listen on socket\n", thedate());
+ exit(1);
+ }
+
+ signal(SIGHUP, onhup);
+ signal(SIGTERM, onterm);
+ signal(SIGPIPE, onpipe);
+ /*
+ * Return here on SIGHUP after closing and reopening log file.
+ * Also on SIGPIPE after closing user connection.
+ */
+ setjmp(mainloop);
+
+ /*
+ * Now start the main processing loop.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ while(1) {
+ fd_set fs;
+ unsigned char rpkt[3];
+ int sel, h, k;
+ STATUS *s;
+
+ FD_ZERO(&fs);
+ FD_SET(tw523, &fs);
+ if(User != NULL) FD_SET(user, &fs);
+ else FD_SET(sock, &fs);
+ sel = select(FD_SETSIZE, &fs, 0, 0, &tv);
+ if(sel == 0) {
+ /*
+ * Cancel brightening and dimming on ALL units on ALL house codes,
+ * because the fact that we haven't gotten a packet for awhile means
+ * that there was a gap in transmission.
+ */
+ for(h = 0; h < 16; h++) {
+ for(k = 0; k < 16; k++) {
+ s = &Status[h][k];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ fflush(Log);
+ checkpoint_status();
+ /*
+ * Now that we've done this stuff, we'll set the timeout a little
+ * longer, so we don't keep looping too frequently.
+ */
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ continue;
+ }
+ /*
+ * While there is stuff happening, we keep a short timeout, so we
+ * don't get stuck for some unknown reason, and so we can keep the
+ * brightening and dimming data up-to-date.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ if(FD_ISSET(tw523, &fs)) { /* X10 data arriving from TW523 */
+ if(read(tw523, rpkt, 3) < 3) {
+ fprintf(Log, "%s: Error reading from TW523\n", thedate());
+ } else {
+ logpacket(rpkt);
+ processpacket(rpkt);
+ }
+ } else if(FD_ISSET(user, &fs)) {
+ if(User != NULL) {
+ if(user_command()) {
+ fprintf(Log, "%s: Closing user connection\n", thedate());
+ fclose(User);
+ User = NULL;
+ }
+ } else {
+ /* "Can't" happen */
+ }
+ } else if(FD_ISSET(sock, &fs)) { /* Accept a connection */
+ if (User == NULL) {
+ int len = sizeof(struct sockaddr_un);
+ if((user = accept(sock, (struct sockaddr *)(&sa), &len)) >= 0) {
+ fprintf(Log, "%s: Accepting user connection\n", thedate());
+ if((User = fdopen(user, "w+")) == NULL) {
+ fprintf(Log, "%s: Can't attach socket to stream\n", thedate());
+ }
+ } else {
+ fprintf(Log, "%s: Failure in attempt to accept connection\n", thedate());
+ }
+ } else {
+ /* "Can't happen */
+ }
+ }
+ }
+ /* Not reached */
+}
+
+char *thedate()
+{
+ char *cp, *cp1;
+ time_t tod;
+
+ tod = time(NULL);
+ cp = cp1 = ctime(&tod);
+ while(*cp1 != '\n') cp1++;
+ *cp1 = '\0';
+ return(cp);
+}
+
+/*
+ * When SIGHUP received, close and reopen the Log file
+ */
+
+void onhup()
+{
+ char logpath[MAXPATHLEN+1];
+
+ fprintf(Log, "%s: SIGHUP received, reopening Log\n", thedate());
+ fclose(Log);
+ strcpy(logpath, X10DIR);
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
+
+/*
+ * When SIGTERM received, just exit normally
+ */
+
+void onterm()
+{
+ fprintf(Log, "%s: SIGTERM received, shutting down\n", thedate());
+ exit(0);
+}
+
+/*
+ * When SIGPIPE received, reset user connection
+ */
+
+void onpipe()
+{
+ fprintf(Log, "%s: SIGPIPE received, resetting user connection\n",
+ thedate());
+ if(User != NULL) {
+ fclose(User);
+ User = NULL;
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
diff --git a/libexec/xtend/xtend.h b/libexec/xtend/xtend.h
new file mode 100644
index 000000000000..d52ea9bc8427
--- /dev/null
+++ b/libexec/xtend/xtend.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+/*
+ * Device capabilities
+ */
+
+#define ISLIGHT 1 /* Is device a light? */
+#define CANQUERY 2 /* Responds to status query */
+
+/*
+ * Device status
+ */
+
+typedef enum {
+ IDLE,
+ SELECTED,
+ DIMMING,
+ BRIGHTENING,
+ REQUESTED,
+ HAILED
+ } SELECT;
+
+typedef struct {
+ unsigned int devcap; /* device capabilities */
+ unsigned int changed; /* status changed since last checkpoint? */
+ time_t lastchange; /* time status last changed */
+ SELECT selected; /* select status of device */
+ unsigned int onoff; /* nonzero if on */
+ unsigned int brightness; /* value in range 0-15 */
+} STATUS;
+
+typedef struct {
+ int inuse; /* Is entry in use? */
+ FILE *user; /* Socket to notify user */
+ int house; /* House code of device to monitor */
+ int unit; /* Unit code of device to monitor */
+} MONENTRY;
+
+#define MAXMON 5 /* Maximum number of monitor entries */
+
+extern FILE *Log; /* Log file */
+extern FILE *User; /* User connection */
+extern STATUS Status[16][16]; /* Device status table */
+extern int status; /* Status file descriptor */
+extern int tw523; /* tw523 controller */
+extern MONENTRY Monitor[MAXMON];/* Monitor table */
+
+extern char *thedate();
diff --git a/sbin/Makefile b/sbin/Makefile
index a1ac2c6c8c66..80613ba20d4c 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -1,11 +1,11 @@
# @(#)Makefile 5.4.1.1 (Berkeley) 5/7/91
-# $Id: Makefile,v 1.10 1994/02/07 05:23:06 alm Exp $
+# $Id: Makefile,v 1.13 1994/05/18 16:40:00 jkh Exp $
#
-SUBDIR= XNSrouted adjkerntz badsect chkconfig clri comcontrol disklabel dmesg \
- dump dumpfs fastboot fdisk fsck ft halt ifconfig mknod mount \
- mount_isofs mount_pcfs mount_procfs mountd newfs nfsd nfsiod ping \
- quotacheck reboot restore route routed savecore scsi shutdown \
+SUBDIR= adjkerntz badsect chkconfig clri comcontrol disklabel dmesg \
+ dump dumpfs fastboot fdisk fsck ft halt ifconfig md5 mknod mount \
+ mount_isofs mount_pcfs mount_procfs mountd newfs nfsd nfsiod \
+ ping quotacheck reboot restore route savecore scsi shutdown \
slattach st swapon tunefs umount
.if defined(INIT_ORIG)
diff --git a/sbin/chkconfig/chkconfig.c b/sbin/chkconfig/chkconfig.c
index 0c0f51da79d8..0c6af5ae851d 100644
--- a/sbin/chkconfig/chkconfig.c
+++ b/sbin/chkconfig/chkconfig.c
@@ -26,7 +26,7 @@
*/
const char chkconfig_c_rcsid[] =
- "$Id: chkconfig.c,v 1.4 1993/11/12 03:54:24 wollman Exp $";
+ "$Id: chkconfig.c,v 1.5 1994/04/17 09:22:15 alm Exp $";
#include <stdio.h>
#include <stdlib.h>
@@ -43,7 +43,7 @@ static int setvalue(const char *, int);
static int printvalues(void);
static void usage(void);
static void die(const char *);
-static int is_on(const char *);
+static int is_on(const char *, size_t);
const char *whoami;
static const char *configdir = _PATH_CONFIG;
@@ -101,7 +101,8 @@ int main(int argc, char **argv) {
return doflags ? printflags(argv[optind]) : testvalue(argv[optind]);
case 2:
- return setvalue(argv[optind], is_on(argv[optind + 1]));
+ return setvalue(argv[optind], is_on(argv[optind + 1],
+ strlen(argv[optind + 1])));
default:
usage();
@@ -109,11 +110,11 @@ int main(int argc, char **argv) {
}
}
-static int is_on(const char *str) {
- if(!str) return 0;
+static int is_on(const char *str, size_t len) {
+ if(!str || len < 2) return 0;
return ( ((str[0] == 'o') || (str[0] == 'O'))
&& ((str[1] == 'n') || (str[1] == 'N'))
- && ((str[2] == '\n')|| (str[2] == '\0')));
+ && ((len == 2) || (str[2] == '\n')));
}
static void chat(const char *str, int state) {
@@ -141,15 +142,16 @@ static int testvalue(const char *str) {
FILE *fp;
char *line;
const char *fname;
+ size_t len = 0;
int rv = 1; /* NB: shell's convention is opposite C's */
fname = confname(str, "");
fp = fopen(fname, "r");
if(fp) {
do {
- line = fgetline(fp, (size_t *)0);
+ line = fgetln(fp, &len);
} while(line && line[0] == '#');
- rv = !is_on(line); /* shell's convention is opposite C's */
+ rv = !is_on(line, len); /* shell's convention is opposite C's */
fclose(fp);
}
@@ -163,6 +165,7 @@ static char *getflags(const char *str) {
char *line;
const char *fname;
char *rv = strdup("");
+ size_t len = 0;
if(!rv) {
errno = ENOMEM;
@@ -173,17 +176,18 @@ static char *getflags(const char *str) {
fp = fopen(fname, "r");
if(fp) {
do {
- line = fgetline(fp, (size_t *)0);
+ line = fgetln(fp, &len);
} while(line && line[0] == '#');
if(line) {
free(rv);
- rv = strdup(line);
-
- if(!rv) {
+ if(line[len - 1] == '\n') --len;
+ if((rv = (char *) malloc(len + 1)) == NULL) {
errno = ENOMEM;
- die("getflags: strdup");
+ die("getflags: malloc");
}
+ bcopy(line, rv, len);
+ rv[len] = '\0';
}
fclose(fp);
diff --git a/sbin/comcontrol/comcontrol.8 b/sbin/comcontrol/comcontrol.8
index bcb44e1088ee..eec9520db62f 100644
--- a/sbin/comcontrol/comcontrol.8
+++ b/sbin/comcontrol/comcontrol.8
@@ -1,47 +1,30 @@
-.Dd December 10, 1993
+.Dd May 15, 1994
.Dt COMCONTROL 8
.Os FreeBSD
.Sh NAME
.Nm comcontrol
-.Nd "control the bidirectional status of a sio port and waiting time after DTR drop"
+.Nd control an sio device.
.Sh SYNOPSIS
.Nm comcontrol
.Ar sio_special_device
-.Op Cm bidir | Fl bidir
-.Op Cm dtrwait Ar ticks
+.Op options
.Sh DESCRIPTION
.Nm Comcontrol
-is used to examine and modify the bidirectional status
-of a specified
-sio communications port
-and its waiting time after DTR drop.
-By default (if
-.Ar sio_special_device
-only specified),
-.Nm comcontrol
-will print the current port state
-(if kernel was built with
-.Cm options COM_BIDIR )
-as either
-.Cm bidir
-to indicate that bidirectional operation is enabled or
-.Fl bidir
-to indicate that it is disabled, string
-.Cm dtrwait
-and current waiting time in ticks
-after DTR drop.
-To modify the status of the port or waiting time, simply
-specify the desired new state
-and/or new waiting time
-on the command line. All users with
-read access to the
-.Ar sio_special_device
-can use
-.Nm comcontrol
-to get the port's status and current waiting time.
-Only root can set a port's status and waiting time.
-By default, each port is initially unidirectional, waiting time is
-2 seconds.
+is used to examine and modify some of the special characterstics
+of the specified sio device.
+If no arguments other than the device are specified,
+it prints the settings of all controllable characteristics.
+This usage requires only read access on the device.
+Only the superuser can change the settings.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Cm dtrwait Ar number
+Set the time to wait after dropping DTR
+to the given number.
+The units are hundredths of a second.
+The default is 300 hundredths, i.e., 3 seconds.
+.El
.Pp
The standard way to use
.Nm comcontrol
@@ -50,25 +33,21 @@ is to put invocations of it in the
startup script.
.Sh SEE ALSO
.Xr sio 4
+.Xr stty 1 .
.Sh FILES
.Bl -tag -width Pa
-.It Pa /dev/sio??
-.Sh DIAGNOSTICS
-.Cm TIOCMSBIDIR: Inappropriate ioctl for device.
-.Pp
-This indicates attempt to change port status on
-a non-sio special device file,
-or the kernel has not been built with
-.Cm options COM_BIDIR .
-For more information concerning reconfiguration
-of your kernel see
-.Ar /usr/src/sys/i386/doc/config_options.doc.
+.It Pa /dev/ttyd?
+dialin devices.
+.It Pa /dev/cua0?
+dialout devices.
.Sh AUTHOR
Christopher G. Demetriou
.Sh BUGS
-It is strongly recommended that you do *not*
-change the bidirectional status of a port while there are programs
-using the port. Read that as: if you do, and it breaks, don't yell
-at me; that's a really weird thing to do.
+.Nm comcontrol
+should be named
+.Nm siocontrol .
+.
.Sh HISTORY
Originally part of cgd's com package patches, version 0.2.1, to 386BSD 0.1.
+Once controlled bidirectional capabilities. Little is left to control now
+that these capabilities are standard.
diff --git a/sbin/comcontrol/comcontrol.c b/sbin/comcontrol/comcontrol.c
index e88e3d8f71e0..40cf8d25c8a8 100644
--- a/sbin/comcontrol/comcontrol.c
+++ b/sbin/comcontrol/comcontrol.c
@@ -38,7 +38,7 @@
void usage(char *progname)
{
- fprintf(stderr, "usage: %s <filename> [[-]bidir] [dtrwait <n>]\n", progname);
+ fprintf(stderr, "usage: %s <filename> [dtrwait <n>]\n", progname);
exit(1);
}
@@ -58,10 +58,6 @@ int main(int argc, char *argv[])
}
if (argc == 2) {
- if (ioctl(fd, TIOCMGBIDIR, &res) >= 0) {
- if (!res) printf("-");
- printf("bidir ");
- }
if (ioctl(fd, TIOCMGDTRWAIT, &dtrwait) < 0) {
perror("TIOCMGDTRWAIT");
exit(1);
@@ -72,17 +68,7 @@ int main(int argc, char *argv[])
res = dtrwait = -1;
while (argv[2] != NULL) {
- if (!strcmp(argv[2],"bidir")) {
- if (res >= 0)
- usage(prg);
- res = 1;
- argv++;
- } else if (!strcmp(argv[2],"-bidir")) {
- if (res >= 0)
- usage(prg);
- res = 0;
- argv++;
- } else if (!strcmp(argv[2],"dtrwait")) {
+ if (!strcmp(argv[2],"dtrwait")) {
if (dtrwait >= 0)
usage(prg);
if (argv[3] == NULL || !isdigit(argv[3][0]))
@@ -93,12 +79,6 @@ int main(int argc, char *argv[])
usage(prg);
}
}
- if (res >= 0) {
- if (ioctl(fd, TIOCMSBIDIR, &res) < 0) {
- perror("TIOCMSBIDIR");
- exit(1);
- }
- }
if (dtrwait >= 0) {
if (ioctl(fd, TIOCMSDTRWAIT, &dtrwait) < 0) {
perror("TIOCMSDTRWAIT");
diff --git a/sbin/disklabel/disklabel.c b/sbin/disklabel/disklabel.c
index f8810370dd6a..4fd3bbdcd58e 100644
--- a/sbin/disklabel/disklabel.c
+++ b/sbin/disklabel/disklabel.c
@@ -88,13 +88,14 @@ static char sccsid[] = "@(#)disklabel.c 5.20 (Berkeley) 2/9/91";
#define RAWPARTITION 'c'
#endif
-#if defined(i386)
+#if defined(__386BSD__)
/* with 386BSD, 'c' maps the portion of the disk given over to 386BSD,
and 'd' maps the entire drive, ignoring any partition tables */
+#define LABELPARTITION ('c' - 'a')
#define RAWPARTITION 'd'
#endif
-#if defined(vax)==0 && defined(i386)==0
+#ifndef RAWPARTITION
#define RAWPARTITION 'a'
#endif
@@ -102,7 +103,7 @@ static char sccsid[] = "@(#)disklabel.c 5.20 (Berkeley) 2/9/91";
#define BBSIZE 8192 /* size of boot area, with label */
#endif
-#if defined(vax) || defined(i386)
+#if defined(vax) || defined(__386BSD__)
#define BOOT /* also have bootstrap in "boot area" */
#define BOOTDIR _PATH_BOOTDIR /* source of boot binaries */
#else
@@ -226,12 +227,14 @@ main(argc, argv)
* partition.
*/
dosdp = readmbr(f);
+#ifdef notdef /* not used (some bootstraps copy wd tables to 0x300) */
{ int mfd; unsigned char params[0x10];
/* sleezy, but we need it fast! */
mfd = open("/dev/mem", 0);
lseek(mfd, 0x300, 0);
read (mfd, params, 0x10);
}
+#endif
#endif
@@ -240,6 +243,19 @@ main(argc, argv)
if (argc != 1)
usage();
lp = readlabel(f);
+ if (lp == NULL) {
+ /*
+ * It's too much trouble to make -e -r work
+ * when there is no on-disk label.
+ *
+ * XXX -e without -r will fail if there is no
+ * on-disk label, but not until the user has
+ * wasted time editing the in-core label.
+ */
+ errno = ESRCH;
+ l_perror("-e flag is not suitable");
+ exit(1);
+ }
error = edit(lp, f);
break;
case NOWRITE: {
@@ -253,6 +269,12 @@ main(argc, argv)
usage();
lp = readlabel(f);
+ if (lp == NULL) {
+ fprintf(stderr,
+ "Ignoring -r and trying to read in-core label\n");
+ rflag = 0;
+ lp = readlabel(f);
+ }
display(stdout, lp);
error = checklabel(lp);
break;
@@ -370,7 +392,7 @@ writelabel(f, boot, lp)
register int i;
int flag;
#ifdef __386BSD__
- off_t lbl_off; struct partition *pp = lp->d_partitions;
+ off_t lbl_off; struct partition *pp = lp->d_partitions + LABELPARTITION;
#endif
lp->d_magic = DISKMAGIC;
@@ -385,7 +407,7 @@ writelabel(f, boot, lp)
* the label to be written is not within partition,
* prompt first. Need to allow this in case operator
* wants to convert the drive for dedicated use.
- * In this case, partition 'a' had better start at 0,
+ * In this case, partition 'c' had better start at 0,
* otherwise we reject the request as meaningless. -wfj
*/
@@ -394,15 +416,15 @@ writelabel(f, boot, lp)
lbl_off = pp->p_offset;
} else {
if (dosdp) {
- char c;
+ int c;
- printf("overwriting disk with DOS partition table? (n):");
+ printf("overwrite DOS partition table? [n]: ");
fflush(stdout);
c = getchar();
- if (c != EOF && c != (int)'\n')
- while (getchar() != (int)'\n')
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n')
;
- if (c == (int)'n')
+ if (c != 'y')
exit(0);
}
lbl_off = 0;
@@ -444,10 +466,23 @@ writelabel(f, boot, lp)
if (lp->d_type != DTYPE_SCSI && lp->d_flags & D_BADSECT) {
daddr_t alt;
- alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
+ /*
+ * XXX this knows too much about bad144 internals
+ */
+#ifdef __386BSD__
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (lp->d_partitions[BSD_PART].p_offset != 0)
+ alt = lp->d_partitions[BAD144_PART].p_offset
+ + lp->d_partitions[BAD144_PART].p_size;
+ else
+#endif
+ alt = lp->d_secperunit;
+ alt -= lp->d_nsectors;
for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
- (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), L_SET);
- if (write(f, boot, lp->d_secsize) < lp->d_secsize) {
+ lseek(f, (off_t)((alt + i) * lp->d_secsize), L_SET);
+ if (write(f, boot + (LABELSECTOR * lp->d_secsize),
+ lp->d_secsize) < lp->d_secsize) {
int oerrno = errno;
fprintf(stderr, "alternate label %d ", i/2);
errno = oerrno;
@@ -471,7 +506,7 @@ l_perror(s)
case ESRCH:
fprintf(stderr, "No disk label on disk;\n");
fprintf(stderr,
- "use \"disklabel -r\" to install initial label\n");
+ "use flags \"-w -r\" or \"-R -r\" to install initial label\n");
break;
case EINVAL:
@@ -506,7 +541,7 @@ readmbr(f)
{
static struct dos_partition dos_partitions[NDOSPART];
struct dos_partition *dp, *bsdp;
- char mbr[DEV_BSIZE];
+ char mbr[DEV_BSIZE]; /* XXX - DOS_DEV_BSIZE */
int i, npart, nboot, njunk;
(void)lseek(f, (off_t)DOSBBSECTOR, L_SET);
@@ -519,6 +554,10 @@ readmbr(f)
* Don't (yet) know disk geometry (BIOS), use
* partition table to find 386BSD partition, and obtain
* disklabel from there.
+ *
+ * XXX - the checks for a valid partition table are inadequate.
+ * This gets called for floppies, which will never have an mbr
+ * and may have junk that looks like a partition table...
*/
dp = dos_partitions;
npart = njunk = nboot = 0;
@@ -533,6 +572,11 @@ readmbr(f)
}
/* valid partition table? */
+ /*
+ * XXX - ignore `nboot'. Drives other than the first do not need a
+ * boot flag. The first drive doesn't need a boot flag when it is
+ * booted from a multi-boot program.
+ */
if (npart == 0 || njunk) /* 18 Sep 92*/
/* was: if (nboot != 1 || npart == 0 || njunk)*/
return (0);
@@ -579,12 +623,9 @@ readlabel(f)
dkcksum(lp) != 0) {
fprintf(stderr,
"Bad pack magic number (label is damaged, or pack is unlabeled)\n");
- /* lp = (struct disklabel *)(bootarea + LABELOFFSET);
- exit (1); */
- goto tryioctl;
+ return (NULL);
}
} else {
-tryioctl:
lp = &lab;
if (ioctl(f, DIOCGDINFO, lp) < 0)
Perror("ioctl DIOCGDINFO");
@@ -746,7 +787,7 @@ display(f, lp)
(pp->p_offset +
pp->p_size + lp->d_secpercyl - 1) /
lp->d_secpercyl - 1);
- if (pp->p_size % lp->d_secpercyl)
+ if ((pp->p_offset + pp->p_size) % lp->d_secpercyl)
putc('*', f);
fprintf(f, ")\n");
}
@@ -791,10 +832,10 @@ edit(lp, f)
}
printf("re-edit the label? [y]: "); fflush(stdout);
c = getchar();
- if (c != EOF && c != (int)'\n')
- while (getchar() != (int)'\n')
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n')
;
- if (c == (int)'n')
+ if (c == 'n')
break;
}
(void) unlink(tmpfil);
@@ -1169,6 +1210,7 @@ checklabel(lp)
register struct partition *pp;
int i, errors = 0;
char part;
+ unsigned long secper;
if (lp->d_secsize == 0) {
fprintf(stderr, "sector size %d\n", lp->d_secsize);
@@ -1188,10 +1230,31 @@ checklabel(lp)
}
if (lp->d_rpm == 0)
Warning("revolutions/minute %d\n", lp->d_rpm);
+ secper = lp->d_nsectors * lp->d_ntracks;
if (lp->d_secpercyl == 0)
- lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
+ lp->d_secpercyl = secper;
+ else if (lp->d_secpercyl != secper) {
+ fprintf(stderr, "sectors/cylinder %lu should be %lu\n",
+ lp->d_secpercyl, secper);
+ errors++;
+ }
+ secper = lp->d_secpercyl * lp->d_ncylinders;
if (lp->d_secperunit == 0)
- lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
+ lp->d_secperunit = secper;
+ else if (lp->d_secperunit != secper) {
+ /*
+ * lp->d_secperunit makes sense as a limit on the disk size
+ * independent of the product. However, bad144 handling at
+ * least requires it to be the same as the product, and the
+ * "whole disk" partition may be used to limit the size.
+ *
+ * XXX It's silly to accept derived quantities as input only
+ * to reject them.
+ */
+ fprintf(stderr, "sectors/unit %lu should be %lu\n",
+ lp->d_secperunit, secper);
+ errors++;
+ }
#ifdef __386BSD__notyet
if (dosdp && dosdp->dp_size && dosdp->dp_typ == DOSPTYP_386BSD
&& lp->d_secperunit > dosdp->dp_start + dosdp->dp_size) {
diff --git a/sbin/dump/dump.8 b/sbin/dump/dump.8
index ff5a914a191b..1cefb8f39747 100644
--- a/sbin/dump/dump.8
+++ b/sbin/dump/dump.8
@@ -31,7 +31,7 @@
.\"
.\" @(#)dump.8 6.8 (Berkeley) 6/17/91
.\"
-.\" $Header: /home/cvs/386BSD/src/sbin/dump/dump.8,v 1.2.2.1 1994/05/01 16:06:51 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/sbin/dump/dump.8,v 1.2 1993/07/22 16:49:13 jkh Exp $
.\"
.Dd June 17, 1991
.Dt DUMP 8
diff --git a/sbin/dump/dumpoptr.c b/sbin/dump/dumpoptr.c
index deff36a7fd19..5db2bc134473 100644
--- a/sbin/dump/dumpoptr.c
+++ b/sbin/dump/dumpoptr.c
@@ -33,7 +33,7 @@
#ifndef lint
static char sccsid[] = "@(#)dumpoptr.c 5.8 (Berkeley) 3/7/91";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/dump/dumpoptr.c,v 1.2 1993/07/22 16:49:17 jkh Exp $";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/dump/dumpoptr.c,v 1.3 1994/03/07 16:37:08 ats Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -505,6 +505,7 @@ lastdump(arg)
time(&tnow);
getfstab(); /* /etc/fstab input */
initdumptimes(); /* /etc/dumpdates input */
+ if(ddatev == NULL) exit(1); /* /etc/dumpdates doesn't exist */
qsort(ddatev, nddates, sizeof(struct dumpdates *), datesort);
if (arg == 'w')
diff --git a/sbin/dump/dumptape.c b/sbin/dump/dumptape.c
index 52992ecf8117..b1f7fddc82c6 100644
--- a/sbin/dump/dumptape.c
+++ b/sbin/dump/dumptape.c
@@ -33,7 +33,7 @@
#ifndef lint
static char sccsid[] = "@(#)dumptape.c 5.18 (Berkeley) 4/24/91";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/dump/dumptape.c,v 1.2 1993/07/22 16:49:19 jkh Exp $";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/dump/dumptape.c,v 1.3 1994/03/08 16:20:06 ats Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -66,7 +66,7 @@ char *nexttape;
extern char *host;
int rmtopen(), rmtwrite();
void rmtclose();
-#endif RDUMP
+#endif /* RDUMP */
int atomic();
void doslave(), enslave(), flushtape(), killall();
@@ -231,7 +231,7 @@ trewind()
rmtclose();
return;
}
-#endif RDUMP
+#endif /* RDUMP */
close(tapefd);
while ((f = open(tape, 0)) < 0)
sleep (10);
@@ -363,10 +363,10 @@ startnewtape()
#ifdef RDUMP
while ((tapefd = (host ? rmtopen(tape, 2) :
pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
-#else RDUMP
+#else /* RDUMP */
while ((tapefd =
pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666)) < 0)
-#endif RDUMP
+#endif /* RDUMP */
{
msg("Cannot open output \"%s\".\n", tape);
if (!query("Do you want to retry the open?"))
@@ -404,6 +404,9 @@ dumpabort()
killall();
msg("The ENTIRE dump is aborted.\n");
}
+#ifdef RDUMP
+ rmtclose();
+#endif
Exit(X_ABORT);
}
@@ -538,10 +541,10 @@ doslave(cmd, prev, next)
#ifdef RDUMP
if ((nwrite = (host ? rmtwrite(tblock[0], writesize)
: write(tapefd, tblock[0], writesize))) != writesize) {
-#else RDUMP
+#else /* RDUMP */
if ((nwrite = write(tapefd, tblock[0], writesize))
!= writesize) {
-#endif RDUMP
+#endif /* RDUMP */
if (nwrite == -1)
perror("write");
else
diff --git a/sbin/dump/rdump.8 b/sbin/dump/rdump.8
index acbfeab5367b..41b65836cdf0 100644
--- a/sbin/dump/rdump.8
+++ b/sbin/dump/rdump.8
@@ -31,7 +31,7 @@
.\"
.\" @(#)rdump.8 6.3 (Berkeley) 3/16/91
.\"
-.\" $Header: /home/cvs/386BSD/src/sbin/dump/rdump.8,v 1.3.2.1 1994/05/01 16:06:53 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/sbin/dump/rdump.8,v 1.3 1993/09/13 21:25:13 rgrimes Exp $
.\"
.Dd March 16, 1991
.Dt RDUMP 8
diff --git a/sbin/fsck/fsck.8 b/sbin/fsck/fsck.8
index ecc96c322b53..b3ecd7b43f9f 100644
--- a/sbin/fsck/fsck.8
+++ b/sbin/fsck/fsck.8
@@ -31,7 +31,7 @@
.\"
.\" @(#)fsck.8 6.9 (Berkeley) 4/20/91
.\"
-.\" $Header: /home/cvs/386BSD/src/sbin/fsck/fsck.8,v 1.2.2.1 1994/05/01 16:06:58 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/sbin/fsck/fsck.8,v 1.2 1993/07/22 16:51:48 jkh Exp $
.\"
.TH FSCK 8 "April 20, 1991"
.UC 4
diff --git a/sbin/fsck/pass5.c b/sbin/fsck/pass5.c
index 475b9a15ed85..4d0385732b0b 100644
--- a/sbin/fsck/pass5.c
+++ b/sbin/fsck/pass5.c
@@ -33,7 +33,7 @@
#ifndef lint
static char sccsid[] = "@(#)pass5.c 5.13 (Berkeley) 7/20/90";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/pass5.c,v 1.2 1993/07/22 16:51:58 jkh Exp $";
+static char rcsid[] = "$Id: pass5.c,v 1.3 1994/05/05 23:41:06 wollman Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -42,6 +42,14 @@ static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/pass5.c,v 1.2 199
#include <string.h>
#include "fsck.h"
+/*
+ * Allow time in cg summary data to be this number of seconds in the future.
+ * Currently we allow up to one day of slack because of problem that
+ * adjkerntz(8) can change the time by up to a day when it runs and adjusts
+ * the timezone.
+ */
+#define TIME_SLACK (60*60*24)
+
pass5()
{
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
@@ -110,7 +118,10 @@ pass5()
dmax = dbase + fs->fs_fpg;
if (dmax > fs->fs_size)
dmax = fs->fs_size;
- if (now > cg->cg_time)
+#ifndef TIME_SLACK
+#define TIME_SLACK 0
+#endif
+ if (now > cg->cg_time - TIME_SLACK)
newcg->cg_time = cg->cg_time;
else
newcg->cg_time = now;
diff --git a/sbin/fsck/setup.c b/sbin/fsck/setup.c
index 9f10ccb5b63a..e7e111371488 100644
--- a/sbin/fsck/setup.c
+++ b/sbin/fsck/setup.c
@@ -33,7 +33,7 @@
#ifndef lint
static char sccsid[] = "@(#)setup.c 5.33 (Berkeley) 2/22/91";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/setup.c,v 1.2 1993/07/22 16:52:00 jkh Exp $";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/setup.c,v 1.3 1994/03/07 22:27:23 ats Exp $";
#endif /* not lint */
#define DKTYPENAMES
@@ -461,6 +461,8 @@ calcsb(dev, devfd, fs)
fs->fs_cgoffset = roundup(
howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
+ /* Make sure, that fs->fs_cpg is not zero to avoid a divide by zero */
+ if(fs->fs_cpg == 0) fs->fs_cpg = 1;
fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
fs->fs_fsbtodb++;
diff --git a/sbin/fsck/utilities.c b/sbin/fsck/utilities.c
index 85b67288b52b..7fa78324e395 100644
--- a/sbin/fsck/utilities.c
+++ b/sbin/fsck/utilities.c
@@ -33,7 +33,7 @@
#ifndef lint
static char sccsid[] = "@(#)utilities.c 5.30 (Berkeley) 7/26/91";
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/utilities.c,v 1.2 1993/07/22 16:52:01 jkh Exp $";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/sbin/fsck/utilities.c,v 1.3 1994/06/03 22:04:59 ats Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -195,7 +195,7 @@ flush(fd, bp)
{
register int i, j;
- if (!bp->b_dirty)
+ if (!bp || !bp->b_dirty)
return;
if (bp->b_errs != 0)
pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
@@ -240,7 +240,7 @@ ckfini()
}
flush(fswritefd, &cgblk);
free(cgblk.b_un.b_buf);
- for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
+ for (bp = bufhead.b_prev; bp && (bp != &bufhead); bp = nbp) {
cnt++;
flush(fswritefd, bp);
nbp = bp->b_prev;
diff --git a/sbin/ft/Makefile b/sbin/ft/Makefile
index 41acb7b37fb9..95e8a96f062f 100644
--- a/sbin/ft/Makefile
+++ b/sbin/ft/Makefile
@@ -1,7 +1,8 @@
-# $Id: Makefile,v 1.2 1994/02/07 08:40:16 rgrimes Exp $
+# $Id: Makefile,v 1.3 1994/06/22 04:49:02 jkh Exp $
PROG= ft
MAN8= ft.8
SRCS= ft.c ftecc.c
+COPTS= -O2 -finline-functions -funroll-loops -fexpensive-optimizations
.include <bsd.prog.mk>
diff --git a/sbin/ft/ft.8 b/sbin/ft/ft.8
index 477f09b36d28..962001ec7bef 100644
--- a/sbin/ft/ft.8
+++ b/sbin/ft/ft.8
@@ -40,7 +40,7 @@
.Sh SYNOPSIS
.Nm ft
.Op Fl f Ar tape
-.Op Fl description
+.Op Ar description
.Sh DESCRIPTION
The
.Nm ft
@@ -59,8 +59,8 @@ To extract /usr from tape:
.Bd -literal -offset indent
% ft | tar xvzf -
.Ed
-.Sh SEE ALSO
-.Xr qtar 1
+.\" .Sh SEE ALSO
+.\" .Xr qtar 1
.Sh BUGS
Formatting/Verifying is in the works. You will need to use your
existing backup program to do this for the time being.
diff --git a/sbin/ft/ft.c b/sbin/ft/ft.c
index 4aa92f81625f..49aadd3331cc 100644
--- a/sbin/ft/ft.c
+++ b/sbin/ft/ft.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Steve Gerakines
+ * Copyright (c) 1993, 1994 Steve Gerakines
*
* This is freely redistributable software. You may do anything you
* wish with it, so long as the above notice stays intact.
@@ -18,6 +18,10 @@
*
* ft.c - simple floppy tape filter
*
+ * 06/07/94 v1.0 ++sg
+ * Added support for tape retension. Added retries for ecc failures.
+ * Moved to release.
+ *
* 01/28/94 v0.3b (Jim Babb)
* Fixed bug when all sectors in a segment are marked bad.
*
@@ -27,7 +31,7 @@
* 09/02/93 v0.2 pl01
* Initial revision.
*
- * usage: ftfilt [ -f tape ] [ description ]
+ * usage: ft [ -f tape ] [ description ]
*/
#include <stdio.h>
@@ -51,6 +55,7 @@ int tvlast; /* TRUE if last volume in set */
long tvsize = 0; /* tape volume size in bytes */
long tvtime = NULL; /* tape change time */
char *tvnote = ""; /* tape note */
+int doretension = 0; /* TRUE if we should retension tape */
/* Lookup the badmap for a given track and segment. */
#define BADMAP(t,s) hptr->qh_badmap[(t)*geo.g_segtrk+(s)]
@@ -62,45 +67,22 @@ char *tvnote = ""; /* tape note */
#define equal(s1,s2) (strcmp(s1, s2) == 0)
-
-/* Entry */
-main(int argc, char *argv[])
+/*
+ * Print tape usage and then leave.
+ */
+void
+usage(void)
{
- int r, s;
- char *tape, *getenv();
-
- if (argc > 2 && (equal(argv[1], "-t") || equal(argv[1], "-f"))) {
- argc -= 2;
- tape = argv[2];
- argv += 2;
- } else
- if ((tape = getenv("TAPE")) == NULL)
- tape = DEFQIC;
- if (argc > 1) {
- tvnote = argv[1];
- if (strlen(tvnote) > 18) argv[1][18] = '\0';
- }
-
- /* Open the tape device */
- if ((tfd = open(tape, 2)) < 0) {
- perror(tape);
- exit(1);
- }
-
- if (!isatty(0))
- do_write();
- else if (!isatty(1))
- do_read();
- else
- do_getname();
-
- close(tfd);
- exit(0);
+ fprintf(stderr, "usage: ft [ -r ] [ -f device ] [ \"description\" ]\n");
+ exit(1);
}
-/* Check status of tape drive */
-int check_stat(int fd, int wr)
+/*
+ * Check status of tape drive
+ */
+int
+check_stat(int fd, int wr)
{
int r, s;
int sawit = 0;
@@ -138,8 +120,11 @@ int check_stat(int fd, int wr)
}
-
-ULONG qtimeval(time_t t)
+/*
+ * Convert time_t value to QIC time value.
+ */
+ULONG
+qtimeval(time_t t)
{
struct tm *tp;
ULONG r;
@@ -154,8 +139,12 @@ ULONG qtimeval(time_t t)
return(r);
}
-/* Return tm struct from QIC date format. */
-struct tm *qtime(UCHAR *qt)
+
+/*
+ * Return tm struct from QIC date format.
+ */
+struct tm *
+qtime(UCHAR *qt)
{
ULONG *vp = (ULONG *)qt;
struct tm t;
@@ -178,7 +167,10 @@ struct tm *qtime(UCHAR *qt)
return(localtime(&tv));
}
-/* Return a string, zero terminated */
+
+/*
+ * Return a string, zero terminated.
+ */
char *qstr(char *str, int nchar)
{
static char tstr[256];
@@ -187,7 +179,11 @@ char *qstr(char *str, int nchar)
return(tstr);
}
-/* Read header from tape */
+
+/*
+ * Read header from tape
+ */
+int
get_header(int fd)
{
int r, sn, bytes;
@@ -238,6 +234,9 @@ get_header(int fd)
}
+/*
+ * Open /dev/tty and ask for next volume.
+ */
ask_vol(int vn)
{
FILE *inp;
@@ -255,21 +254,26 @@ ask_vol(int vn)
}
-/* Return the name of the tape only. */
-do_getname()
+/*
+ * Return the name of the tape only.
+ */
+void
+do_getname(void)
{
if (check_stat(tfd, 0)) exit(1);
if (get_header(tfd)) exit(1);
fprintf(stderr, "\"%s\" - %s",
qstr(hptr->qh_tname,44), asctime(qtime(hptr->qh_chgdate)));
- ioctl(tfd, QIOREWIND);
}
-/* Extract data from tape to stdout */
-do_read()
+/*
+ * Extract data from tape to stdout.
+ */
+void
+do_read(void)
{
- int sno, vno, sbytes, r;
+ int sno, vno, sbytes, r, eccfails;
long curpos;
char *hname;
QIC_Segment s;
@@ -281,6 +285,13 @@ do_read()
ask_vol(vno);
continue;
}
+
+ if (doretension) {
+ ioctl(tfd, QIOBOT);
+ ioctl(tfd, QIOEOT);
+ ioctl(tfd, QIOBOT);
+ }
+
if (get_header(tfd)) {
ask_vol(vno);
continue;
@@ -303,36 +314,50 @@ do_read()
/* Process this volume */
curpos = 0;
- for (sno = hptr->qh_first; tvsize > 0; sno++) {
+ eccfails = 0;
+ sno = hptr->qh_first;
+ while (tvsize > 0) {
s.sg_trk = sno / geo.g_segtrk;
s.sg_seg = sno % geo.g_segtrk;
s.sg_badmap = BADMAP(s.sg_trk,s.sg_seg);
sbytes = sect_bytes(s.sg_badmap) - QCV_ECCSIZE;
s.sg_data = (UCHAR *)&buff[0];
-
- /* skip segments with *all* sectors flagged as bad */
- if (sbytes > 0) {
- if (ioctl(tfd, QIOREAD, &s) < 0) perror("QIOREAD");
- r = check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap);
- if (r) fprintf(stderr, "** warning: ecc failed at byte %ld\n",
- curpos);
- if (tvsize < sbytes) sbytes = tvsize;
- write(1, s.sg_data, sbytes);
- tvsize -= sbytes;
- curpos += sbytes;
+ if (sbytes <= 0) {
+ sno++;
+ continue;
+ }
+ if (ioctl(tfd, QIOREAD, &s) < 0) perror("QIOREAD");
+
+ if (check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap)) {
+ if (++eccfails <= 5) {
+ fprintf(stderr,
+ "ft: retry %d at segment %d byte %ld\n",
+ eccfails, sno, curpos);
+ continue;
+ } else
+ fprintf(stderr,
+ "ft: *** ecc failure in segment %d at byte %ld\n",
+ sno, curpos);
}
+ if (tvsize < sbytes) sbytes = tvsize;
+ write(1, s.sg_data, sbytes);
+ tvsize -= sbytes;
+ curpos += sbytes;
+ sno++;
+ eccfails = 0;
}
if (tvlast) break;
ioctl(tfd, QIOREWIND);
ask_vol(++vno);
}
- ioctl(tfd, QIOREWIND);
- return(0);
}
-/* Dump data from stdin to tape */
-do_write()
+/*
+ * Dump data from stdin to tape.
+ */
+void
+do_write(void)
{
int sno, vno, amt, sbytes;
int c, maxseg, r;
@@ -348,6 +373,13 @@ do_write()
ask_vol(vno);
continue;
}
+
+ if (doretension) {
+ ioctl(tfd, QIOBOT);
+ ioctl(tfd, QIOEOT);
+ ioctl(tfd, QIOBOT);
+ }
+
if (get_header(tfd)) {
ask_vol(vno);
continue;
@@ -376,6 +408,7 @@ do_write()
break;
}
}
+
/* skip the segment if *all* sectors are flagged as bad */
if (amt) {
if (amt < sbytes)
@@ -410,7 +443,7 @@ do_write()
if (ioctl(tfd, QIOWRITE, &s) < 0) {
perror("QIOWRITE");
exit(1);
- }
+ }
}
if (dhsn >= 0) {
s.sg_trk = dhsn / geo.g_segtrk;
@@ -428,5 +461,57 @@ do_write()
if (tvlast) break;
ask_vol(++vno);
}
- return(0);
+}
+
+
+/*
+ * Entry.
+ */
+void
+main(int argc, char *argv[])
+{
+ int r, s, i;
+ char *tape, *getenv();
+
+
+ /* Get device from environment, command line will override. */
+ if ((tape = getenv("TAPE")) == NULL) tape = DEFQIC;
+
+ /* Process args. */
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') break;
+ switch (argv[i][1]) {
+ case 'f':
+ case 't':
+ if (i == (argc - 1)) usage();
+ tape = argv[++i];
+ break;
+ case 'r':
+ doretension = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (i < (argc - 1)) usage();
+ if (i < argc) {
+ tvnote = argv[i];
+ if (strlen(tvnote) > 18) argv[i][18] = '\0';
+ }
+
+ /* Open the tape device */
+ if ((tfd = open(tape, 2)) < 0) {
+ perror(tape);
+ exit(1);
+ }
+
+ if (!isatty(0))
+ do_write();
+ else if (!isatty(1))
+ do_read();
+ else
+ do_getname();
+
+ close(tfd);
+ exit(0);
}
diff --git a/sbin/ft/ftecc.c b/sbin/ft/ftecc.c
index 430f3a8316bb..fbba10f07fa5 100644
--- a/sbin/ft/ftecc.c
+++ b/sbin/ft/ftecc.c
@@ -1,32 +1,46 @@
/*
- * ftecc.c 10/30/93 v0.3
- * Handle error correction for floppy tape drives.
+ * Copyright (c) 1994 Steve Gerakines
*
- * File contents are copyrighted by David L. Brown and falls under the
- * terms of the GPL version 2 or greater. See his original release for
- * the specific terms.
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
*
- * Steve Gerakines
- * steve2@genesis.nred.ma.us
- * Modified slightly to fit with my tape driver. I'm not at all happy
- * with this module and will have it replaced with a more functional one
- * in the next release(/RSN). I am close, but progress will continue to
- * be slow until I can find a book on the subject where the translator
- * understands both the to and from languages. :-( For now it will
- * suffice.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * ftecc.c - QIC-40/80 Reed-Solomon error correction
+ * 05/30/94 v1.0 ++sg
+ * Did some minor optimization. The multiply by 0xc0 was a dog so it
+ * was replaced with a table lookup. Fixed a couple of places where
+ * bad sectors could go unnoticed. Moved to release.
+ *
+ * 03/22/94 v0.4
+ * Major re-write. It can handle everything required by QIC now.
+ *
+ * 09/14/93 v0.2 pl01
+ * Modified slightly to fit with my driver. Based entirely upon David
+ * L. Brown's package.
*/
#include <sys/ftape.h>
-/*
- * In order to speed up the correction and adjustment, we can compute
- * a matrix of coefficients for the multiplication.
- */
+/* Inverse matrix */
struct inv_mat {
- UCHAR log_denom; /* The log z of the denominator. */
- UCHAR zs[3][3]; /* The coefficients for the adjustment matrix. */
+ UCHAR log_denom; /* Log of the denominator */
+ UCHAR zs[3][3]; /* The matrix */
};
-/* This array is a table of powers of x, from 0 to 254. */
+
+/*
+ * Powers of x, modulo 255.
+ */
static UCHAR alpha_power[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
@@ -59,12 +73,12 @@ static UCHAR alpha_power[] = {
0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
- 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3
+ 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
};
+
/*
- * This is the reverse lookup table. There is no log of 0, so the
- * first element is not valid.
+ * Log table, modulo 255 + 1.
*/
static UCHAR alpha_log[] = {
0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
@@ -101,8 +115,51 @@ static UCHAR alpha_log[] = {
0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
};
-/* Return number of sectors available in a segment. */
-int sect_count(ULONG badmap)
+
+/*
+ * Multiplication table for 0xc0.
+ */
+static UCHAR mult_c0[] = {
+ 0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9,
+ 0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5,
+ 0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1,
+ 0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed,
+ 0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9,
+ 0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5,
+ 0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81,
+ 0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d,
+ 0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29,
+ 0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35,
+ 0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11,
+ 0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d,
+ 0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59,
+ 0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45,
+ 0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61,
+ 0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d,
+ 0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e,
+ 0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92,
+ 0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6,
+ 0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa,
+ 0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe,
+ 0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2,
+ 0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6,
+ 0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda,
+ 0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e,
+ 0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72,
+ 0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56,
+ 0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a,
+ 0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e,
+ 0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02,
+ 0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26,
+ 0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a
+};
+
+
+/*
+ * Return number of sectors available in a segment.
+ */
+int
+sect_count(ULONG badmap)
{
int i, amt;
@@ -111,8 +168,12 @@ int sect_count(ULONG badmap)
return(amt);
}
-/* Return number of bytes available in a segment. */
-int sect_bytes(ULONG badmap)
+
+/*
+ * Return number of bytes available in a segment.
+ */
+int
+sect_bytes(ULONG badmap)
{
int i, amt;
@@ -121,146 +182,215 @@ int sect_bytes(ULONG badmap)
return(amt);
}
-/* Multiply two numbers in the field. */
-static UCHAR multiply(UCHAR a, UCHAR b)
+
+/*
+ * Multiply two numbers in the field.
+ */
+static inline UCHAR
+multiply(UCHAR a, UCHAR b)
{
int tmp;
- if (a == 0 || b == 0) return(0);
- tmp = (alpha_log[a] + alpha_log[b]);
+ if (!a || !b) return(0);
+ tmp = alpha_log[a] + alpha_log[b];
if (tmp > 254) tmp -= 255;
- return (alpha_power[tmp]);
+ return(alpha_power[tmp]);
+}
+
+
+/*
+ * Multiply by an exponent.
+ */
+static inline UCHAR
+multiply_out(UCHAR a, int b)
+{
+ int tmp;
+
+ if (!a) return(0);
+ tmp = alpha_log[a] + b;
+ if (tmp > 254) tmp -= 255;
+ return(alpha_power[tmp]);
}
-static UCHAR divide(UCHAR a, UCHAR b)
+
+/*
+ * Divide two numbers.
+ */
+static inline UCHAR
+divide(UCHAR a, UCHAR b)
{
int tmp;
- if (a == 0 || b == 0) return(0);
- tmp = (alpha_log[a] - alpha_log[b]);
+ if (!a || !b) return(0);
+ tmp = alpha_log[a] - alpha_log[b];
if (tmp < 0) tmp += 255;
return (alpha_power[tmp]);
}
+
/*
- * This is just like divide, except we have already looked up the log
- * of the second number.
+ * Divide using exponent.
*/
-static UCHAR divide_out(UCHAR a, UCHAR b)
+static inline UCHAR
+divide_out(UCHAR a, UCHAR b)
{
int tmp;
- if (a == 0) return 0;
+ if (!a) return 0;
tmp = alpha_log[a] - b;
if (tmp < 0) tmp += 255;
return (alpha_power[tmp]);
}
-/* This returns the value z^{a-b}. */
-static UCHAR z_of_ab(UCHAR a, UCHAR b)
+
+/*
+ * This returns the value z^{a-b}.
+ */
+static inline UCHAR
+z_of_ab(UCHAR a, UCHAR b)
{
- int tmp = (int)a - (int)b;
+ int tmp = a - b;
- if (tmp < 0)
- tmp += 255;
- else if (tmp >= 255)
- tmp -= 255;
+ if (tmp < 0) tmp += 255;
return(alpha_power[tmp]);
}
-/* Calculate the inverse matrix. Returns 1 if the matrix is valid, or
- * zero if there is no inverse. The i's are the indices of the bytes
- * to be corrected.
+
+/*
+ * Calculate the inverse matrix for two or three errors. Returns 0
+ * if there is no inverse or 1 if successful.
*/
-static int calculate_inverse (int *pblk, struct inv_mat *inv)
+static inline int
+calculate_inverse(int nerrs, int *pblk, struct inv_mat *inv)
{
/* First some variables to remember some of the results. */
UCHAR z20, z10, z21, z12, z01, z02;
UCHAR i0, i1, i2;
+ UCHAR iv0, iv1, iv2;
- i0 = pblk[0]; i1 = pblk[1]; i2 = pblk[2];
+ if (nerrs < 2) return(1);
+ if (nerrs > 3) return(0);
- z20 = z_of_ab (i2, i0); z10 = z_of_ab (i1, i0);
- z21 = z_of_ab (i2, i1); z12 = z_of_ab (i1, i2);
- z01 = z_of_ab (i0, i1); z02 = z_of_ab (i0, i2);
- inv->log_denom = (z20 ^ z10 ^ z21 ^ z12 ^ z01 ^ z02);
- if (inv->log_denom == 0) return 0;
- inv->log_denom = alpha_log[inv->log_denom];
-
- /* Calculate all of the coefficients on the top. */
- inv->zs[0][0] = alpha_power[i1] ^ alpha_power[i2];
- inv->zs[0][1] = z21 ^ z12;
- inv->zs[0][2] = alpha_power[255-i1] ^ alpha_power[255-i2];
-
- inv->zs[1][0] = alpha_power[i0] ^ alpha_power[i2];
- inv->zs[1][1] = z20 ^ z02;
- inv->zs[1][2] = alpha_power[255-i0] ^ alpha_power[255-i2];
-
- inv->zs[2][0] = alpha_power[i0] ^ alpha_power[i1];
- inv->zs[2][1] = z10 ^ z01;
- inv->zs[2][2] = alpha_power[255-i0] ^ alpha_power[255-i1];
+ i0 = pblk[0]; i1 = pblk[1]; i2 = pblk[2];
+ if (nerrs == 2) {
+ /* 2 errs */
+ z01 = alpha_power[255 - i0];
+ z02 = alpha_power[255 - i1];
+ inv->log_denom = (z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ inv->zs[0][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[0][1] = multiply_out(z02, inv->log_denom);
+ inv->zs[1][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[1][1] = multiply_out(z01, inv->log_denom);
+ } else {
+ /* 3 errs */
+ z20 = z_of_ab (i2, i0);
+ z10 = z_of_ab (i1, i0);
+ z21 = z_of_ab (i2, i1);
+ z12 = z_of_ab (i1, i2);
+ z01 = z_of_ab (i0, i1);
+ z02 = z_of_ab (i0, i2);
+ inv->log_denom = (z20 ^ z10 ^ z21 ^ z12 ^ z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ iv0 = alpha_power[255 - i0];
+ iv1 = alpha_power[255 - i1];
+ iv2 = alpha_power[255 - i2];
+ i0 = alpha_power[i0];
+ i1 = alpha_power[i1];
+ i2 = alpha_power[i2];
+ inv->zs[0][0] = multiply_out(i1 ^ i2, inv->log_denom);
+ inv->zs[0][1] = multiply_out(z21 ^ z12, inv->log_denom);
+ inv->zs[0][2] = multiply_out(iv1 ^ iv2, inv->log_denom);
+ inv->zs[1][0] = multiply_out(i0 ^ i2, inv->log_denom);
+ inv->zs[1][1] = multiply_out(z20 ^ z02, inv->log_denom);
+ inv->zs[1][2] = multiply_out(iv0 ^ iv2, inv->log_denom);
+ inv->zs[2][0] = multiply_out(i0 ^ i1, inv->log_denom);
+ inv->zs[2][1] = multiply_out(z10 ^ z01, inv->log_denom);
+ inv->zs[2][2] = multiply_out(iv0 ^ iv1, inv->log_denom);
+ }
return(1);
}
+
/*
- * Determine the error values for a given inverse matrix and syndromes.
+ * Determine the error magnitudes for a given matrix and syndromes.
*/
-static void determine3(struct inv_mat *inv, UCHAR *es, UCHAR *ss)
+static inline void
+determine(int nerrs, struct inv_mat *inv, UCHAR *ss, UCHAR *es)
{
UCHAR tmp;
int i, j;
- for (i = 0; i < 3; i++) {
- tmp = 0;
- for (j = 0; j < 3; j++) tmp ^= multiply (ss[j], inv->zs[i][j]);
- es[i] = divide_out(tmp, inv->log_denom);
+ for (i = 0; i < nerrs; i++) {
+ es[i] = 0;
+ for (j = 0; j < nerrs; j++)
+ es[i] ^= multiply(ss[j], inv->zs[i][j]);
}
}
/*
- * Compute the 3 syndrome values. The data pointer should point to
- * the offset within the first block of the column to calculate. The
- * count of blocks is in blocks. The three bytes will be placed in
- * ss[0], ss[1], and ss[2].
+ * Compute the 3 syndrome values.
*/
-static void compute_syndromes(UCHAR *data, int nblks, int col, UCHAR *ss)
+static inline int
+compute_syndromes(UCHAR *data, int nblks, int col, UCHAR *ss)
{
- int i;
- UCHAR v;
-
- ss[0] = 0; ss[1] = 0; ss[2] = 0;
- for (i = (nblks-1)*QCV_BLKSIZE; i >= 0; i -= QCV_BLKSIZE) {
- v = data[i+col];
- if (ss[0] & 0x01) { ss[0] >>= 1; ss[0] ^= 0xc3; } else ss[0] >>= 1;
- ss[0] ^= v;
- ss[1] ^= v;
- if (ss[2] & 0x80) { ss[2] <<= 1; ss[2] ^= 0x87; } else ss[2] <<= 1;
- ss[2] ^= v;
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+
+ rptr = data + col;
+ data += nblks << 10;
+ r0 = r1 = r2 = 0;
+ while (rptr < data) {
+ t1 = *rptr ^ r0;
+ t2 = mult_c0[t1];
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ rptr += QCV_BLKSIZE;
+ }
+ if (r0 || r1 || r2) {
+ ss[0] = divide_out(r0 ^ divide_out(r1 ^ divide_out(r2, 1), 1), nblks);
+ ss[1] = r0 ^ r1 ^ r2;
+ ss[2] = multiply_out(r0 ^ multiply_out(r1 ^ multiply_out(r2, 1), 1), nblks);
+ return(0);
}
+ return(1);
}
+
/*
- * Calculate the parity bytes for a segment. Returns 0 on success.
+ * Calculate the parity bytes for a segment, returns 0 on success (always).
*/
-int set_parity (UCHAR *data, ULONG badmap)
+int
+set_parity (UCHAR *data, ULONG badmap)
{
- int col;
- struct inv_mat inv;
- UCHAR ss[3], es[3];
- int nblks, pblk[3];
-
- nblks = sect_count(badmap);
- pblk[0] = nblks-3; pblk[1] = nblks-2; pblk[2] = nblks-1;
- if (!calculate_inverse(pblk, &inv)) return(1);
-
- pblk[0] *= QCV_BLKSIZE; pblk[1] *= QCV_BLKSIZE; pblk[2] *= QCV_BLKSIZE;
- for (col = 0; col < QCV_BLKSIZE; col++) {
- compute_syndromes (data, nblks-3, col, ss);
- determine3(&inv, es, ss);
- data[pblk[0]+col] = es[0];
- data[pblk[1]+col] = es[1];
- data[pblk[2]+col] = es[2];
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+ int max, row, col;
+
+ max = sect_count(badmap) - 3;
+ col = QCV_BLKSIZE;
+ while (col--) {
+ rptr = data;
+ r0 = r1 = r2 = 0;
+ row = max;
+ while (row--) {
+ t1 = *rptr ^ r0;
+ t2 = mult_c0[t1];
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ rptr += QCV_BLKSIZE;
+ }
+ *rptr = r0; rptr += QCV_BLKSIZE;
+ *rptr = r1; rptr += QCV_BLKSIZE;
+ *rptr = r2;
+ data++;
}
return(0);
}
@@ -270,47 +400,81 @@ int set_parity (UCHAR *data, ULONG badmap)
* Check and correct errors in a block. Returns 0 on success,
* 1 if failed.
*/
-int check_parity(UCHAR *data, ULONG badmap, ULONG crcmap)
+int
+check_parity(UCHAR *data, ULONG badmap, ULONG crcmap)
{
- int i, j, col, crcerrs, r, tries, nblks;
- struct inv_mat inv;
+ int crcerrs, eblk[3];
+ int col, row;
+ int i, j, nblks;
UCHAR ss[3], es[3];
- int i1, i2, eblk[3];
+ int i1, i2, saverrs;
+ struct inv_mat inv;
nblks = sect_count(badmap);
- crcerrs = 0;
- for (i = 0; crcerrs < 3 && i < nblks; i++)
- if (crcmap & (1 << i)) eblk[crcerrs++] = i;
- for (i = 1, j = crcerrs; j < 3 && i < nblks; i++)
- if ((crcmap & (1 << i)) == 0) eblk[j++] = i;
+ /* Count the number of CRC errors and note their locations. */
+ crcerrs = 0;
+ if (crcmap) {
+ for (i = 0; i < nblks; i++) {
+ if (crcmap & (1 << i)) {
+ if (crcerrs == 3) return(1);
+ eblk[crcerrs++] = i;
+ }
+ }
+ }
- if (!calculate_inverse (eblk, &inv)) return(1);
+ /* Calculate the inverse matrix */
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
- eblk[0] *= QCV_BLKSIZE; eblk[1] *= QCV_BLKSIZE; eblk[2] *= QCV_BLKSIZE;
- r = 0;
+ /* Scan each column for problems and attempt to correct. */
for (col = 0; col < QCV_BLKSIZE; col++) {
- compute_syndromes (data, nblks, col, ss);
-
- if (!ss[0] && !ss[1] && !ss[2]) continue;
- if (crcerrs) {
- determine3 (&inv, es, ss);
- for (j = 0; j < crcerrs; j++)
- data[eblk[j] + col] ^= es[j];
- compute_syndromes (data, nblks, col, ss);
- if (!ss[0] && !ss[1] && !ss[2]) {
- r = 1;
- continue;
+ if (compute_syndromes(data, nblks, col, ss)) continue;
+ es[0] = es[1] = es[2] = 0;
+
+ /* Analyze the error situation. */
+ switch (crcerrs) {
+ case 0: /* 0 errors >0 failures */
+ if (!ss[0]) return(1);
+ eblk[crcerrs] = alpha_log[divide(ss[1], ss[0])];
+ if (eblk[crcerrs] >= nblks) return(1);
+ es[0] = ss[1];
+ if (++crcerrs > 3) return(1);
+ break;
+
+ case 1: /* 1 error (+ possible failures) */
+ i1 = ss[2] ^ multiply_out(ss[1], eblk[0]);
+ i2 = ss[1] ^ multiply_out(ss[0], eblk[0]);
+ if (!i1 && !i2) { /* only 1 error */
+ inv.zs[0][0] = alpha_power[eblk[0]];
+ inv.log_denom = 0;
+ } else if (!i1 || !i2) { /* too many errors */
+ return(1);
+ } else { /* add failure */
+ eblk[crcerrs] = alpha_log[divide(i1, i2)];
+ if (eblk[crcerrs] >= nblks) return(1);
+ if (++crcerrs > 3) return(1);
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
}
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ case 2: /* 2 errors */
+ case 3: /* 3 errors */
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ default:
+ return(1);
}
- determine3 (&inv, es, ss);
- i1 = alpha_log[divide(ss[2], ss[1])];
- i2 = alpha_log[divide(ss[1], ss[0])];
- if (i1 != i2 || ((QCV_BLKSIZE * i1) + col) > QCV_SEGSIZE)
- r = 1;
- else
- data[QCV_BLKSIZE * i1 + col] ^= ss[1];
- }
- return(r);
+ /* Make corrections. */
+ for (i = 0; i < crcerrs; i++) {
+ data[(eblk[i] << 10) | col] ^= es[i];
+ ss[0] ^= divide_out(es[i], eblk[i]);
+ ss[1] ^= es[i];
+ ss[2] ^= multiply_out(es[i], eblk[i]);
+ }
+ if (ss[0] || ss[1] || ss[2]) return(1);
+ }
+ return(0);
}
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 45a3628afe0e..06413bb9da30 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -41,7 +41,7 @@ char copyright[] =
#ifndef lint
static char sccsid[] = "@(#)ifconfig.c 5.1 (Berkeley) 2/28/91";
static const char rcsid[] =
- "$Id: ifconfig.c,v 1.6 1994/01/22 08:23:47 rgrimes Exp $";
+ "$Id: ifconfig.c,v 1.7 1994/05/17 15:17:16 jkh Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -78,7 +78,7 @@ struct iso_aliasreq iso_addreq;
struct sockaddr_in netmask;
char name[30];
-int flags;
+u_int flags;
int metric;
int nsellength = 1;
int setaddr;
@@ -620,7 +620,7 @@ in_getaddr(s, which)
printb(s, v, bits)
char *s;
register char *bits;
- register unsigned short v;
+ register unsigned int v;
{
register int i, any = 0;
register char c;
diff --git a/sbin/init.chmr/configure.c b/sbin/init.chmr/configure.c
index 367c4f03102b..1c8ca0f2e452 100644
--- a/sbin/init.chmr/configure.c
+++ b/sbin/init.chmr/configure.c
@@ -35,6 +35,7 @@
#ifdef CONFIGURE
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -58,7 +59,7 @@ static int evaluate_line(char *, int, int, char **, int);
static int parseline(char *, int, int, char **);
-char *fgetline(FILE *, size_t *); /* XXX */
+char *fgetln(FILE *, size_t *); /* XXX */
extern const struct Command Commands[];
@@ -76,10 +77,11 @@ char *filename;
{
static int ncalled = 0;
FILE *cf;
-char *line, *s, *errmsg;
+char *fline, *line, *s, *errmsg;
int lineno;
char **cline;
int argc;
+size_t len;
Debug (1, "Configuring from file %s", filename);
@@ -97,11 +99,25 @@ int argc;
}
Debug(1, "Config file %s opened.", filename);
+ if ((line = (char *) malloc(1)) == (char *) 0) {
+ syslog(LOG_ERR, "%s: %s", filename, strerror(errno));
+ ncalled --;
+ return;
+ }
+
lineno = 0;
- while ((line = fgetline(cf, (size_t *)0))) {
+ while ((fline = fgetln(cf, &len))) {
lineno ++;
- if (*line == '#')
+ if (*fline == '#')
continue; /* Skip comment line */
+ else if (fline[len - 1] == '\n')
+ --len;
+ if ((line = (char *) realloc(line, len + 1)) == (char *) 0) {
+ syslog(LOG_ERR, "%s: %s", filename, strerror(errno));
+ break;
+ }
+ bcopy(fline, line, len);
+ line[len] = '\0';
for (s = line; *s; s++)
if ((*s != ' ') && (*s != '\t'))
break;
@@ -112,8 +128,8 @@ int argc;
syslog(LOG_ERR, "%s line %d: %s", filename, lineno, errmsg);
if (cline && argc > 0)
(void)parseline(filename, lineno, argc, cline);
-
}
+ free(line);
fclose(cf);
ncalled --;
}
diff --git a/sbin/init/init.o b/sbin/init/init.o
new file mode 100644
index 000000000000..15ec01b7f530
--- /dev/null
+++ b/sbin/init/init.o
Binary files differ
diff --git a/sbin/md5/Makefile b/sbin/md5/Makefile
new file mode 100644
index 000000000000..80df7e5f4108
--- /dev/null
+++ b/sbin/md5/Makefile
@@ -0,0 +1,34 @@
+# $Id: Makefile,v 1.3 1994/05/21 21:30:07 jkh Exp $
+
+PROG= md5
+MAN1= md5.1
+SRCS= md5c.c mddriver.c
+CFLAGS+= -DMD=5
+CLEANFILES= test.rfc
+
+# For security reasons, this has to be static.
+LDFLAGS= -static
+
+all: ${PROG} test
+
+test: md5 test.rfc
+ -./md5 -x | diff - test.rfc > diffs 2>&1
+ @-if test -s diffs ; then \
+ echo '*** MD5 TEST FAILED'; cat diffs; \
+ else \
+ echo ' MD5 Test Passed'; \
+ fi
+ rm -f diffs
+
+# test.rfc is taken from Appendix 5 of RFC 1321.
+test.rfc:
+ @echo 'MD5 test suite:' > test.rfc
+ @echo 'MD5 ("") = d41d8cd98f00b204e9800998ecf8427e' >> test.rfc
+ @echo 'MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661' >> test.rfc
+ @echo 'MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72' >> test.rfc
+ @echo 'MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0' >> test.rfc
+ @echo 'MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b' >> test.rfc
+ @echo 'MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f' >> test.rfc
+ @echo 'MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a' >> test.rfc
+
+.include <bsd.prog.mk>
diff --git a/sbin/md5/README b/sbin/md5/README
new file mode 100644
index 000000000000..387790748869
--- /dev/null
+++ b/sbin/md5/README
@@ -0,0 +1,34 @@
+Adapted for FreeBSD by Poul-Henning Kamp, phk@login.dkuug.dk. Only the
+Makefile is modified.
+-----------------------------------------------------------------------
+This directory contains source code for the MD5 message-digest algorithm.
+
+MD5.tar.Z is a compressed tar file of all the other files in this directory.
+
+"md5-announcement.txt" is the announcement from RSA Data Security that
+MD5 is being placed in the public domain for free general use.
+
+"rfc1321.txt" is the RFC that describes in detail the MD2, MD4, and MD5
+message-digest algorithms.
+
+The *.[ch] files were taken exactly from RFC 1321.
+I wrote a simple Makefile to build an md5 executable by default,
+with targets for "test" (which implements the test in Appendix A.5 in the RFC)
+and "clean". Running Makefile with no targets will build the "md5" binary.
+
+There is a typo in the RFC Appendix A.4 (mddriver.c).
+Line 20 sets MD to "MD5" by default, but the code wants
+MD to be set to one of "2", "4", or "5".
+I put a -DMD=5 in the Makefile to mask this problem so that the
+code itself remains unchanged from what is in RFC 1321.
+
+Ric Anderson, ric@Artisoft.COM, provided a bug fix to the timing test
+code that caused a divide by zero aborts on a Sun sparc station-10
+running soalris 2.3. This fix to mddriver.c is the only change to the
+code in RFC 1321 and corrects only a problem with the timing tests.
+No change to the code that implements the actual checksum has been made.
+
+Ric has also provided a man page - "md5.1". A postscript version
+of this man page is in "md5.1.ps" and a text version in "md5.1.txt".
+
+ -- Jim Ellis (jte@cert.org)
diff --git a/sbin/md5/global.h b/sbin/md5/global.h
new file mode 100644
index 000000000000..ee255142f5dc
--- /dev/null
+++ b/sbin/md5/global.h
@@ -0,0 +1,30 @@
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
diff --git a/sbin/md5/md5-announcement.txt b/sbin/md5/md5-announcement.txt
new file mode 100644
index 000000000000..931a1b73f1d0
--- /dev/null
+++ b/sbin/md5/md5-announcement.txt
@@ -0,0 +1,37 @@
+ MD5 -- New Message Digest Algorithm
+ (Feel free to distribute further)
+
+RSA Data Security is announcing MD5, a new message-digest algorithm.
+Like MD4, this algorithm is being placed in the public domain for free
+general use.
+
+The MD5 algorithm is a strengthened version of MD4. It has four
+rounds instead of three, and incorporates other revisions based on a
+year's worth of collected comments on the MD4 algorithm. For example,
+the input access patterns in rounds two and three have been improved,
+and the rotation amounts have been optimized for maximum ``avalanche
+effect.'' The additive constants have been made unique in each step,
+and an additional dependence of each step on the previous one has been
+added.
+
+These changes cause MD5 to be somewhat slower than MD4. We estimate
+that MD5 will typically run about 15-30% slower than MD4, depending on
+the degree to which the versions of MD4 and MD5 have been optimized.
+The more they are both optimized, the greater the percentage
+difference in speed. An optimized version of MD5 on a Sun
+SparcStation runs at about 890 Kbytes/second.
+
+Why MD5? While we do not know of any way to ``break'' MD4, we feel
+that MD4 is being pressed into service far too quickly for such an
+``aggressive'' design. We have been surprised at the speed with which
+MD4 is being designed into products. MD5 is ``MD4 with seatbelts''
+and thus, as a more conservative design, is more suitable for rapid
+deployment.
+
+It is the intent of RSA Data Security to use MD5 in its products and
+standards instead of MD4. We recommend that our customers generally
+do the same, unless there is an overwhelming need for the higher speed
+of MD4. Copies of the MD5 algorithm, including a reference
+implementation in C, are available from the company. (Over the
+Internet, you can access this documentation by anonymous FTP to
+rsa.com and obtaining the file pub/md5.doc.)
diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1
new file mode 100644
index 000000000000..ccccb01f7e78
--- /dev/null
+++ b/sbin/md5/md5.1
@@ -0,0 +1,43 @@
+.TH MD5 1 "Feb 14, 1994"
+.SH NAME
+md5 \- calculate a message-digest fingerprint (checksum) for a file
+.SH SYNOPSIS
+.B md5
+[ -t | -x | -sstring | filename(s) ]
+.SH DESCRIPTION
+.B md5
+takes as input a message of arbitrary length and produces
+as output a 128-bit "fingerprint" or "message digest" of the input.
+It is conjectured that it is computationally infeasible to produce
+two messages having the same message digest, or to produce any
+message having a given prespecified target message digest.
+The MD5 algorithm is intended for digital signature applications, where a
+large file must be "compressed" in a secure manner before being
+encrypted with a private (secret) key under a public-key cryptosystem
+such as
+.I RSA.
+.SH OPTIONS
+The following four options may be used in any combination, except
+that
+.B "filename(s)"
+must be the last objects on the command line.
+.in +5
+.PP
+.B -sstring
+prints a checksum of the given "string".
+.PP
+.B -t
+runs a built-in time trial.
+.PP
+.B -x
+runs a built-in test script.
+.PP
+.B filename(s)
+prints a checksum(s) for each of the files.
+.SH "SEE ALSO"
+.BR sum (1)
+.PP
+RFC 1321 describes in detail the MD2, MD4, and MD5 message-digest algorithms.
+.SH ACKNOWLEDGEMENTS
+This program is placed in the public domain for free general use by
+RSA Data Security.
diff --git a/sbin/md5/md5.h b/sbin/md5/md5.h
new file mode 100644
index 000000000000..f9d29c7d9649
--- /dev/null
+++ b/sbin/md5/md5.h
@@ -0,0 +1,36 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
diff --git a/sbin/md5/md5c.c b/sbin/md5/md5c.c
new file mode 100644
index 000000000000..7023bff6b8b3
--- /dev/null
+++ b/sbin/md5/md5c.c
@@ -0,0 +1,333 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
diff --git a/sbin/md5/mddriver.c b/sbin/md5/mddriver.c
new file mode 100644
index 000000000000..c2a246eb2490
--- /dev/null
+++ b/sbin/md5/mddriver.c
@@ -0,0 +1,231 @@
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+ defined with C compiler flags.
+ */
+#ifndef MD
+#define MD MD5
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "global.h"
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+#include "md4.h"
+#endif
+#if MD == 5
+#include "md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString PROTO_LIST ((char *));
+static void MDTimeTrial PROTO_LIST ((void));
+static void MDTestSuite PROTO_LIST ((void));
+static void MDFile PROTO_LIST ((char *));
+static void MDFilter PROTO_LIST ((void));
+static void MDPrint PROTO_LIST ((unsigned char [16]));
+
+#if MD == 2
+#define MD_CTX MD2_CTX
+#define MDInit MD2Init
+#define MDUpdate MD2Update
+#define MDFinal MD2Final
+#endif
+#if MD == 4
+#define MD_CTX MD4_CTX
+#define MDInit MD4Init
+#define MDUpdate MD4Update
+#define MDFinal MD4Final
+#endif
+#if MD == 5
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+#endif
+
+/* Main driver.
+
+Arguments (may be any combination):
+ -sstring - digests string
+ -t - runs time trial
+ -x - runs test script
+ filename - digests file
+ (none) - digests standard input
+ */
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+ int i;
+
+ if (argc > 1)
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == 's')
+ MDString (argv[i] + 2);
+ else if (strcmp (argv[i], "-t") == 0)
+ MDTimeTrial ();
+ else if (strcmp (argv[i], "-x") == 0)
+ MDTestSuite ();
+ else
+ MDFile (argv[i]);
+ else
+ MDFilter ();
+
+ return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+ MD_CTX context;
+ unsigned char digest[16];
+ unsigned int len = strlen (string);
+
+ MDInit (&context);
+ MDUpdate (&context, string, len);
+ MDFinal (digest, &context);
+
+ printf ("MD%d (\"%s\") = ", MD, string);
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+ blocks.
+ */
+static void MDTimeTrial ()
+{
+ MD_CTX context;
+ time_t endTime, startTime;
+ unsigned char block[TEST_BLOCK_LEN], digest[16];
+ unsigned int i;
+
+ printf
+ ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+ TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+ /* Initialize block */
+ for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char)(i & 0xff);
+
+ /* Start timer */
+ time (&startTime);
+
+ /* Digest blocks */
+ MDInit (&context);
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ MDUpdate (&context, block, TEST_BLOCK_LEN);
+ MDFinal (digest, &context);
+
+ /* Stop timer */
+ time (&endTime);
+
+ printf (" done\n");
+ printf ("Digest = ");
+ MDPrint (digest);
+ printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+ /*
+ * Be careful that endTime-startTime is not zero.
+ * (Bug fix from Ric Anderson, ric@Artisoft.COM.)
+ */
+ printf
+ ("Speed = %ld bytes/second\n",
+ (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/((endTime-startTime) != 0 ? (endTime-startTime):1));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+ printf ("MD%d test suite:\n", MD);
+
+ MDString ("");
+ MDString ("a");
+ MDString ("abc");
+ MDString ("message digest");
+ MDString ("abcdefghijklmnopqrstuvwxyz");
+ MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ MDString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+
+/* Digests a file and prints the result.
+ */
+static void MDFile (filename)
+char *filename;
+{
+ FILE *file;
+ MD_CTX context;
+ int len;
+ unsigned char buffer[1024], digest[16];
+
+ if ((file = fopen (filename, "rb")) == NULL)
+ printf ("%s can't be opened\n", filename);
+
+ else {
+ MDInit (&context);
+ while (len = fread (buffer, 1, 1024, file))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ fclose (file);
+
+ printf ("MD%d (%s) = ", MD, filename);
+ MDPrint (digest);
+ printf ("\n");
+ }
+}
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+ MD_CTX context;
+ int len;
+ unsigned char buffer[16], digest[16];
+
+ MDInit (&context);
+ while (len = fread (buffer, 1, 16, stdin))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+ unsigned int i;
+
+ for (i = 0; i < 16; i++)
+ printf ("%02x", digest[i]);
+}
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index ae55108c7c72..bf37d462257e 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -234,6 +234,10 @@ Use
.Tn TCP
transport instead of
.Tn UDP .
+.It port=#
+Set server IP port number to
+.Ar # .
+If not specified, the portmapper is queried for the NFS service.
.It rsize=#
Set read size to
.Ar #
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
index 0d468233e78c..4c3bfa40a9c7 100644
--- a/sbin/mount/mount.c
+++ b/sbin/mount/mount.c
@@ -103,6 +103,7 @@ int retrycnt;
#define BGRND 1
#define ISBGRND 2
int opflags = 0;
+u_short serverport = 0;
#endif
main(argc, argv, arge)
@@ -301,9 +302,11 @@ mountfs(spec, name, flags, type, options, mntopts)
case MOUNT_NFS:
retrycnt = DEF_RETRY;
if (mntopts)
- getnfsopts(mntopts, &nfsargs, &opflags, &retrycnt);
+ getnfsopts(mntopts, &nfsargs, &opflags, &retrycnt,
+ &serverport);
if (options)
- getnfsopts(options, &nfsargs, &opflags, &retrycnt);
+ getnfsopts(options, &nfsargs, &opflags, &retrycnt,
+ &serverport);
if (argp = getnfsargs(spec, &nfsargs))
break;
return (1);
@@ -643,11 +646,12 @@ exclusive(a, b)
* Handle the getoption arg.
* Essentially update "opflags", "retrycnt" and "nfsargs"
*/
-getnfsopts(optarg, nfsargsp, opflagsp, retrycntp)
+getnfsopts(optarg, nfsargsp, opflagsp, retrycntp, serverport)
char *optarg;
register struct nfs_args *nfsargsp;
int *opflagsp;
int *retrycntp;
+ u_short *serverport;
{
register char *cp, *nextcp;
int num;
@@ -696,6 +700,8 @@ getnfsopts(optarg, nfsargsp, opflagsp, retrycntp)
} else if (!strcmp(cp, "retrans") && num > 0) {
nfsargsp->retrans = num;
nfsargsp->flags |= NFSMNT_RETRANS;
+ } else if (!strcmp(cp, "port") && num > 0) {
+ *serverport = num;
}
}
if (nfsargsp->sotype == SOCK_DGRAM) {
@@ -748,8 +754,10 @@ getnfsargs(spec, nfsargsp)
while (retrycnt > 0) {
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PMAPPORT);
- if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
- NFS_VER2, IPPROTO_UDP)) == 0) {
+ tport = serverport;
+ if (serverport == 0 &&
+ ((tport = pmap_getport(&saddr, RPCPROG_NFS,
+ NFS_VER2, IPPROTO_UDP)) == 0)) {
if ((opflags & ISBGRND) == 0)
clnt_pcreateerror("NFS Portmap");
} else {
diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c
index e2e5a26a2100..67490e81a905 100644
--- a/sbin/mountd/mountd.c
+++ b/sbin/mountd/mountd.c
@@ -820,7 +820,7 @@ send_umntall()
{
(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
- exit();
+ exit(0);
}
umntall_each(resultsp, raddr)
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index 3609ae2fe621..13f3344cbcbb 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -105,6 +105,12 @@ int options;
#define F_SO_DONTROUTE 0x080
#define F_VERBOSE 0x100
+/* multicast options */
+int moptions;
+#define MULTICAST_NOLOOP 0x001
+#define MULTICAST_TTL 0x002
+#define MULTICAST_IF 0x004
+
/*
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
* number of received sequence numbers we can keep track of. Change 128
@@ -149,17 +155,19 @@ main(argc, argv)
struct hostent *hp;
struct sockaddr_in *to;
struct protoent *proto;
- register int i;
+ struct in_addr ifaddr;
+ int i;
int ch, fdmask, hold, packlen, preload;
u_char *datap, *packet;
char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
+ u_char ttl, loop;
#ifdef IP_OPTIONS
char rspace[3 + 4 * NROUTES + 1]; /* record route space */
#endif
preload = 0;
datap = &outpack[8 + sizeof(struct timeval)];
- while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)
+ while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF)
switch(ch) {
case 'c':
npackets = atoi(optarg);
@@ -230,12 +238,40 @@ main(argc, argv)
case 'v':
options |= F_VERBOSE;
break;
+ case 'L':
+ moptions |= MULTICAST_NOLOOP;
+ loop = 0;
+ break;
+ case 't':
+ moptions |= MULTICAST_TTL;
+ i = atoi(optarg);
+ if (i < 0 || i > 255) {
+ printf("ttl %u out of range\n", i);
+ exit(1);
+ }
+ ttl = i;
+ break;
+ case 'I':
+ moptions |= MULTICAST_IF;
+ {
+ int i1, i2, i3, i4;
+
+ if (sscanf(optarg, "%u.%u.%u.%u%c",
+ &i1, &i2, &i3, &i4, &i) != 4) {
+ printf("bad interface address '%s'\n",
+ optarg);
+ exit(1);
+ }
+ ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;
+ ifaddr.s_addr = htonl(ifaddr.s_addr);
+ }
+ break;
default:
usage();
}
argc -= optind;
argv += optind;
-
+
if (argc != 1)
usage();
target = *argv;
@@ -322,6 +358,28 @@ main(argc, argv)
(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
sizeof(hold));
+ if (moptions & MULTICAST_NOLOOP) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP,
+ &loop, 1) == -1) {
+ perror ("can't disable multicast loopback");
+ exit(92);
+ }
+ }
+ if (moptions & MULTICAST_TTL) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
+ &ttl, 1) == -1) {
+ perror ("can't set multicast time-to-live");
+ exit(93);
+ }
+ }
+ if (moptions & MULTICAST_IF) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
+ &ifaddr, sizeof(ifaddr)) == -1) {
+ perror ("can't set multicast source interface");
+ exit(94);
+ }
+ }
+
if (to->sin_family == AF_INET)
(void)printf("PING %s (%s): %d data bytes\n", hostname,
inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
@@ -990,6 +1048,6 @@ fill(bp, patp)
usage()
{
(void)fprintf(stderr,
- "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");
+ "usage: ping [-LRdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] [-I interface address] host\n");
exit(1);
}
diff --git a/sbin/restore/Makefile b/sbin/restore/Makefile
index 782f8d179422..a4a0926c9402 100644
--- a/sbin/restore/Makefile
+++ b/sbin/restore/Makefile
@@ -11,7 +11,7 @@ CLEANFILES+=dumprmt.o rtape.o rrestore
all: rrestore
rrestore: ${ROBJS} ${LIBC}
- ${CC} ${CFLAGS} -o ${.TARGET} ${ROBJS}
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} ${ROBJS}
rtape.o: tape.c ${LIBC}
${CC} ${CFLAGS} -c -DRRESTORE ${.CURDIR}/tape.c -o ${.TARGET}
diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c
index d5da24a456ab..b35372132886 100644
--- a/sbin/restore/dirs.c
+++ b/sbin/restore/dirs.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: dirs.c,v 1.1.1.1.2.1 1994/05/04 07:42:51 rgrimes Exp $
+ * $Id: dirs.c,v 1.2 1994/05/04 08:20:30 rgrimes Exp $
*/
/*
* Copyright (c) 1983 The Regents of the University of California.
diff --git a/sbin/restore/pathnames.h b/sbin/restore/pathnames.h
index 6c3ef24e8829..9fd333ec7db9 100644
--- a/sbin/restore/pathnames.h
+++ b/sbin/restore/pathnames.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: pathnames.h,v 1.1.1.1.2.1 1994/05/04 07:42:53 rgrimes Exp $
+ * $Id: pathnames.h,v 1.2 1994/05/04 08:20:38 rgrimes Exp $
*/
/*
* Copyright (c) 1989 The Regents of the University of California.
diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h
index 85c951caa348..8d4bf8bf398f 100644
--- a/sbin/restore/restore.h
+++ b/sbin/restore/restore.h
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: restore.h,v 1.1.1.1.2.1 1994/05/04 07:42:55 rgrimes Exp $
+ * $Id: restore.h,v 1.2 1994/05/04 08:20:44 rgrimes Exp $
*/
/*
* Copyright (c) 1983 The Regents of the University of California.
diff --git a/sbin/restore/rrestore.8 b/sbin/restore/rrestore.8
index e597806e8af8..e0d5a32778cf 100644
--- a/sbin/restore/rrestore.8
+++ b/sbin/restore/rrestore.8
@@ -55,7 +55,7 @@ except the
.Cm f
key should be specified and the file
supplied should be of the form
-.Ar machine:device .
+.Ar [user@]machine:device .
.Pp
.Nm Rrestore
creates a remote server,
diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c
index 02bda1d6d478..40ba9da5be41 100644
--- a/sbin/restore/tape.c
+++ b/sbin/restore/tape.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: tape.c,v 1.2.2.1 1994/05/04 07:42:57 rgrimes Exp $
+ * $Id: tape.c,v 1.3 1994/05/04 08:20:52 rgrimes Exp $
*/
/*
* Copyright (c) 1983 The Regents of the University of California.
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 4d0c02746ed6..1930ea6ffb31 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -40,7 +40,7 @@ char copyright[] =
#ifndef lint
/* From: static char sccsid[] = "@(#)route.c 5.35 (Berkeley) 6/27/91"; */
const char main_c_rcsid[] =
- "$Id: route.c,v 1.3 1993/11/17 21:27:20 wollman Exp $";
+ "$Id: route.c,v 1.4 1994/06/23 17:10:40 ats Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -166,7 +166,7 @@ main(argc, argv)
break;
case '?':
default:
- usage();
+ usage((char *)NULL);
}
argc -= optind;
argv += optind;
diff --git a/sbin/routed/interface.h b/sbin/routed/interface.h
deleted file mode 100644
index 6e555cb27830..000000000000
--- a/sbin/routed/interface.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 1983 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.
- *
- * @(#)interface.h 5.6 (Berkeley) 6/1/90
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * An ``interface'' is similar to an ifnet structure,
- * except it doesn't contain q'ing info, and it also
- * handles ``logical'' interfaces (remote gateways
- * that we want to keep polling even if they go down).
- * The list of interfaces which we maintain is used
- * in supplying the gratuitous routing table updates.
- */
-struct interface {
- struct interface *int_next;
- struct sockaddr int_addr; /* address on this host */
- union {
- struct sockaddr intu_broadaddr;
- struct sockaddr intu_dstaddr;
- } int_intu;
-#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
-#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
- int int_metric; /* init's routing entry */
- int int_flags; /* see below */
- /* START INTERNET SPECIFIC */
- u_long int_net; /* network # */
- u_long int_netmask; /* net mask for addr */
- u_long int_subnet; /* subnet # */
- u_long int_subnetmask; /* subnet mask for addr */
- /* END INTERNET SPECIFIC */
- struct ifdebug int_input, int_output; /* packet tracing stuff */
- int int_ipackets; /* input packets received */
- int int_opackets; /* output packets sent */
- char *int_name; /* from kernel if structure */
- u_short int_transitions; /* times gone up-down */
-};
-
-/*
- * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
- * the others agree with the RTS_ flags defined elsewhere.
- */
-#define IFF_UP 0x1 /* interface is up */
-#define IFF_BROADCAST 0x2 /* broadcast address valid */
-#define IFF_DEBUG 0x4 /* turn on debugging */
-#define IFF_LOOPBACK 0x8 /* software loopback net */
-#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
-
-#define IFF_SUBNET 0x1000 /* interface on subnetted network */
-#define IFF_PASSIVE 0x2000 /* can't tell if up/down */
-#define IFF_INTERFACE 0x4000 /* hardware interface */
-#define IFF_REMOTE 0x8000 /* interface isn't on this machine */
-
-struct interface *if_ifwithaddr();
-struct interface *if_ifwithdstaddr();
-struct interface *if_ifwithnet();
-struct interface *if_iflookup();
diff --git a/sbin/routed/startup.c b/sbin/routed/startup.c
deleted file mode 100644
index f88d5935c025..000000000000
--- a/sbin/routed/startup.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright (c) 1983, 1988 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)startup.c 5.19 (Berkeley) 2/28/91";
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <syslog.h>
-#include <stdlib.h>
-#include "pathnames.h"
-
-struct interface *ifnet;
-struct interface **ifnext = &ifnet;
-int lookforinterfaces = 1;
-int externalinterfaces = 0; /* # of remote and local interfaces */
-int foundloopback; /* valid flag for loopaddr */
-struct sockaddr loopaddr; /* our address on loopback */
-
-/*
- * Find the network interfaces which have configured themselves.
- * If the interface is present but not yet up (for example an
- * ARPANET IMP), set the lookforinterfaces flag so we'll
- * come back later and look again.
- */
-ifinit()
-{
- struct interface ifs, *ifp;
- int s;
- char buf[BUFSIZ], *cp, *cplim;
- struct ifconf ifc;
- struct ifreq ifreq, *ifr;
- struct sockaddr_in *sin;
- u_long i;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "socket: %m");
- close(s);
- return;
- }
- ifc.ifc_len = sizeof (buf);
- ifc.ifc_buf = buf;
- if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
- syslog(LOG_ERR, "ioctl (get interface configuration)");
- close(s);
- return;
- }
- ifr = ifc.ifc_req;
- lookforinterfaces = 0;
-#ifdef RTM_ADD
-#define max(a, b) (a > b ? a : b)
-#define size(p) max((p).sa_len, sizeof(p))
-#else
-#define size(p) (sizeof (p))
-#endif
- cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
- for (cp = buf; cp < cplim;
- cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
- ifr = (struct ifreq *)cp;
- bzero((char *)&ifs, sizeof(ifs));
- ifs.int_addr = ifr->ifr_addr;
- ifreq = *ifr;
- if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
- syslog(LOG_ERR, "%s: ioctl (get interface flags)",
- ifr->ifr_name);
- continue;
- }
- ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
- if ((ifs.int_flags & IFF_UP) == 0 ||
- ifr->ifr_addr.sa_family == AF_UNSPEC) {
- lookforinterfaces = 1;
- continue;
- }
- /* argh, this'll have to change sometime */
- if (ifs.int_addr.sa_family != AF_INET)
- continue;
- if (ifs.int_flags & IFF_POINTOPOINT) {
- if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
- syslog(LOG_ERR, "%s: ioctl (get dstaddr)",
- ifr->ifr_name);
- continue;
- }
- if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
- lookforinterfaces = 1;
- continue;
- }
- ifs.int_dstaddr = ifreq.ifr_dstaddr;
- }
- /*
- * already known to us?
- * This allows multiple point-to-point links
- * to share a source address (possibly with one
- * other link), but assumes that there will not be
- * multiple links with the same destination address.
- */
- if (ifs.int_flags & IFF_POINTOPOINT) {
- if (if_ifwithdstaddr(&ifs.int_dstaddr))
- continue;
- } else if (if_ifwithaddr(&ifs.int_addr))
- continue;
- if (ifs.int_flags & IFF_LOOPBACK) {
- ifs.int_flags |= IFF_PASSIVE;
- foundloopback = 1;
- loopaddr = ifs.int_addr;
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if (ifp->int_flags & IFF_POINTOPOINT)
- add_ptopt_localrt(ifp);
- }
- if (ifs.int_flags & IFF_BROADCAST) {
- if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
- syslog(LOG_ERR, "%s: ioctl (get broadaddr)",
- ifr->ifr_name);
- continue;
- }
-#ifndef sun
- ifs.int_broadaddr = ifreq.ifr_broadaddr;
-#else
- ifs.int_broadaddr = ifreq.ifr_addr;
-#endif
- }
-#ifdef SIOCGIFMETRIC
- if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) {
- syslog(LOG_ERR, "%s: ioctl (get metric)",
- ifr->ifr_name);
- ifs.int_metric = 0;
- } else
- ifs.int_metric = ifreq.ifr_metric;
-#else
- ifs.int_metric = 0;
-#endif
- /*
- * Use a minimum metric of one;
- * treat the interface metric (default 0)
- * as an increment to the hop count of one.
- */
- ifs.int_metric++;
- if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
- syslog(LOG_ERR, "%s: ioctl (get netmask)",
- ifr->ifr_name);
- continue;
- }
- sin = (struct sockaddr_in *)&ifreq.ifr_addr;
- ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
- sin = (struct sockaddr_in *)&ifs.int_addr;
- i = ntohl(sin->sin_addr.s_addr);
- if (IN_CLASSA(i))
- ifs.int_netmask = IN_CLASSA_NET;
- else if (IN_CLASSB(i))
- ifs.int_netmask = IN_CLASSB_NET;
- else
- ifs.int_netmask = IN_CLASSC_NET;
- ifs.int_net = i & ifs.int_netmask;
- ifs.int_subnet = i & ifs.int_subnetmask;
- if (ifs.int_subnetmask != ifs.int_netmask)
- ifs.int_flags |= IFF_SUBNET;
- ifp = (struct interface *)malloc(sizeof (struct interface));
- if (ifp == 0) {
- printf("routed: out of memory\n");
- break;
- }
- *ifp = ifs;
- /*
- * Count the # of directly connected networks
- * and point to point links which aren't looped
- * back to ourself. This is used below to
- * decide if we should be a routing ``supplier''.
- */
- if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
- ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
- if_ifwithaddr(&ifs.int_dstaddr) == 0))
- externalinterfaces++;
- /*
- * If we have a point-to-point link, we want to act
- * as a supplier even if it's our only interface,
- * as that's the only way our peer on the other end
- * can tell that the link is up.
- */
- if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
- supplier = 1;
- ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
- if (ifp->int_name == 0) {
- fprintf(stderr, "routed: ifinit: out of memory\n");
- syslog(LOG_ERR, "routed: ifinit: out of memory\n");
- close(s);
- return;
- }
- strcpy(ifp->int_name, ifr->ifr_name);
- *ifnext = ifp;
- ifnext = &ifp->int_next;
- traceinit(ifp);
- addrouteforif(ifp);
- }
- if (externalinterfaces > 1 && supplier < 0)
- supplier = 1;
- close(s);
-}
-
-/*
- * Add route for interface if not currently installed.
- * Create route to other end if a point-to-point link,
- * otherwise a route to this (sub)network.
- * INTERNET SPECIFIC.
- */
-addrouteforif(ifp)
- register struct interface *ifp;
-{
- struct sockaddr_in net;
- struct sockaddr *dst;
- int state;
- register struct rt_entry *rt;
-
- if (ifp->int_flags & IFF_POINTOPOINT)
- dst = &ifp->int_dstaddr;
- else {
- bzero((char *)&net, sizeof (net));
- net.sin_family = AF_INET;
- net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
- dst = (struct sockaddr *)&net;
- }
- rt = rtfind(dst);
- if (rt &&
- (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
- return;
- if (rt)
- rtdelete(rt);
- /*
- * If interface on subnetted network,
- * install route to network as well.
- * This is meant for external viewers.
- */
- if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
- struct in_addr subnet;
-
- subnet = net.sin_addr;
- net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
- rt = rtfind(dst);
- if (rt == 0)
- rtadd(dst, &ifp->int_addr, ifp->int_metric,
- ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
- RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
- else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
- (RTS_INTERNAL|RTS_SUBNET) &&
- ifp->int_metric < rt->rt_metric)
- rtchange(rt, &rt->rt_router, ifp->int_metric);
- net.sin_addr = subnet;
- }
- if (ifp->int_transitions++ > 0)
- syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
- state = ifp->int_flags &
- (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
- if (ifp->int_flags & IFF_POINTOPOINT &&
- (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
- ifp->int_netmask) != ifp->int_net)
- state &= ~RTS_SUBNET;
- if (ifp->int_flags & IFF_LOOPBACK)
- state |= RTS_EXTERNAL;
- rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
- if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
- add_ptopt_localrt(ifp);
-}
-
-/*
- * Add route to local end of point-to-point using loopback.
- * If a route to this network is being sent to neighbors on other nets,
- * mark this route as subnet so we don't have to propagate it too.
- */
-add_ptopt_localrt(ifp)
- register struct interface *ifp;
-{
- struct rt_entry *rt;
- struct sockaddr *dst;
- struct sockaddr_in net;
- int state;
-
- state = RTS_INTERFACE | RTS_PASSIVE;
-
- /* look for route to logical network */
- bzero((char *)&net, sizeof (net));
- net.sin_family = AF_INET;
- net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
- dst = (struct sockaddr *)&net;
- rt = rtfind(dst);
- if (rt && rt->rt_state & RTS_INTERNAL)
- state |= RTS_SUBNET;
-
- dst = &ifp->int_addr;
- if (rt = rtfind(dst)) {
- if (rt && rt->rt_state & RTS_INTERFACE)
- return;
- rtdelete(rt);
- }
- rtadd(dst, &loopaddr, 1, state);
-}
-
-/*
- * As a concession to the ARPANET we read a list of gateways
- * from /etc/gateways and add them to our tables. This file
- * exists at each ARPANET gateway and indicates a set of ``remote''
- * gateways (i.e. a gateway which we can't immediately determine
- * if it's present or not as we can do for those directly connected
- * at the hardware level). If a gateway is marked ``passive''
- * in the file, then we assume it doesn't have a routing process
- * of our design and simply assume it's always present. Those
- * not marked passive are treated as if they were directly
- * connected -- they're added into the interface list so we'll
- * send them routing updates.
- *
- * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
- */
-gwkludge()
-{
- struct sockaddr_in dst, gate;
- FILE *fp;
- char *type, *dname, *gname, *qual, buf[BUFSIZ];
- struct interface *ifp;
- int metric, n;
- struct rt_entry route;
-
- fp = fopen(_PATH_GATEWAYS, "r");
- if (fp == NULL)
- return;
- qual = buf;
- dname = buf + 64;
- gname = buf + ((BUFSIZ - 64) / 3);
- type = buf + (((BUFSIZ - 64) * 2) / 3);
- bzero((char *)&dst, sizeof (dst));
- bzero((char *)&gate, sizeof (gate));
- bzero((char *)&route, sizeof(route));
-/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
-#define readentry(fp) \
- fscanf((fp), "%s %s gateway %s metric %d %s\n", \
- type, dname, gname, &metric, qual)
- for (;;) {
- if ((n = readentry(fp)) == EOF)
- break;
- if (!getnetorhostname(type, dname, &dst))
- continue;
- if (!gethostnameornumber(gname, &gate))
- continue;
- if (metric == 0) /* XXX */
- metric = 1;
- if (strcmp(qual, "passive") == 0) {
- /*
- * Passive entries aren't placed in our tables,
- * only the kernel's, so we don't copy all of the
- * external routing information within a net.
- * Internal machines should use the default
- * route to a suitable gateway (like us).
- */
- route.rt_dst = *(struct sockaddr *) &dst;
- route.rt_router = *(struct sockaddr *) &gate;
- route.rt_flags = RTF_UP;
- if (strcmp(type, "host") == 0)
- route.rt_flags |= RTF_HOST;
- if (metric)
- route.rt_flags |= RTF_GATEWAY;
- (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
- continue;
- }
- if (strcmp(qual, "external") == 0) {
- /*
- * Entries marked external are handled
- * by other means, e.g. EGP,
- * and are placed in our tables only
- * to prevent overriding them
- * with something else.
- */
- rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
- continue;
- }
- /* assume no duplicate entries */
- externalinterfaces++;
- ifp = (struct interface *)malloc(sizeof (*ifp));
- bzero((char *)ifp, sizeof (*ifp));
- ifp->int_flags = IFF_REMOTE;
- /* can't identify broadcast capability */
- ifp->int_net = inet_netof(dst.sin_addr);
- if (strcmp(type, "host") == 0) {
- ifp->int_flags |= IFF_POINTOPOINT;
- ifp->int_dstaddr = *((struct sockaddr *)&dst);
- }
- ifp->int_addr = *((struct sockaddr *)&gate);
- ifp->int_metric = metric;
- ifp->int_next = ifnet;
- ifnet = ifp;
- addrouteforif(ifp);
- }
- fclose(fp);
-}
-
-getnetorhostname(type, name, sin)
- char *type, *name;
- struct sockaddr_in *sin;
-{
-
- if (strcmp(type, "net") == 0) {
- struct netent *np = getnetbyname(name);
- int n;
-
- if (np == 0)
- n = inet_network(name);
- else {
- if (np->n_addrtype != AF_INET)
- return (0);
- n = np->n_net;
- /*
- * getnetbyname returns right-adjusted value.
- */
- if (n < 128)
- n <<= IN_CLASSA_NSHIFT;
- else if (n < 65536)
- n <<= IN_CLASSB_NSHIFT;
- else
- n <<= IN_CLASSC_NSHIFT;
- }
- sin->sin_family = AF_INET;
- sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
- return (1);
- }
- if (strcmp(type, "host") == 0) {
- struct hostent *hp = gethostbyname(name);
-
- if (hp == 0)
- sin->sin_addr.s_addr = inet_addr(name);
- else {
- if (hp->h_addrtype != AF_INET)
- return (0);
- bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
- }
- sin->sin_family = AF_INET;
- return (1);
- }
- return (0);
-}
-
-gethostnameornumber(name, sin)
- char *name;
- struct sockaddr_in *sin;
-{
- struct hostent *hp;
-
- hp = gethostbyname(name);
- if (hp) {
- bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
- sin->sin_family = hp->h_addrtype;
- return (1);
- }
- sin->sin_addr.s_addr = inet_addr(name);
- sin->sin_family = AF_INET;
- return (sin->sin_addr.s_addr != -1);
-}
diff --git a/sbin/slattach/slattach.c b/sbin/slattach/slattach.c
index 66b8e1577075..8d429f06ef3a 100644
--- a/sbin/slattach/slattach.c
+++ b/sbin/slattach/slattach.c
@@ -145,6 +145,7 @@ int exiting = 0; /* allready running exit_handler */
FILE *console;
struct termios tty;
+struct termios tty_orig; /* For saving original tty state */
char devname[32];
char hostname[MAXHOSTNAMELEN];
@@ -268,6 +269,12 @@ int main(int argc, char **argv)
/* upon HUP redial and reconnect. */
if ((int)signal(SIGHUP,sighup_handler) < 0)
syslog(LOG_NOTICE,"cannot install SIGHUP handler: %s: %m");
+ /* Keep track of our original terminal values for redialing */
+ if (tcgetattr(fd, &tty_orig) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ exit_handler(1);
+ }
+
setup_line();
@@ -362,8 +369,8 @@ again:
syslog(LOG_NOTICE,"SIGHUP on %s (sl%d); running %s",
dev,unit,redial_cmd);
if (!(modem_control & CLOCAL)) {
- tty.c_cflag |= CLOCAL;
- if (tcsetattr(fd, TCSAFLUSH, &tty) < 0) {
+ tty_orig.c_cflag |= CLOCAL;
+ if (tcsetattr(fd, TCSAFLUSH, &tty_orig) < 0) {
syslog(LOG_ERR, "tcsetattr(TCSAFLUSH): %m");
exit_handler(1);
}
diff --git a/share/Makefile b/share/Makefile
index 63922a09cbb2..847d13babe94 100644
--- a/share/Makefile
+++ b/share/Makefile
@@ -1,10 +1,10 @@
# From: @(#)Makefile 5.8.1.1 (Berkeley) 5/7/91
-# $Id: Makefile,v 1.3 1993/09/29 02:15:37 rgrimes Exp $
+# $Id: Makefile,v 1.4 1994/04/08 07:03:04 csgr Exp $
# Missing: ms
# Broken: doc
-SUBDIR= dict man me misc mk skel syscons tabset \
+SUBDIR= dict locale man me misc mk skel syscons tabset \
termcap tmac zoneinfo
.include <bsd.subdir.mk>
diff --git a/share/doc/ps1/06.sysman/a.t b/share/doc/ps1/06.sysman/a.t
index 5529d08fd0f3..71bd67cbe7db 100644
--- a/share/doc/ps1/06.sysman/a.t
+++ b/share/doc/ps1/06.sysman/a.t
@@ -86,10 +86,10 @@ madvise\(dg give memory management advice
mincore\(dg determine core residency of pages
msleep\(dg sleep on a lock
mwakeup\(dg wakeup process sleeping on a lock
+.TE
.FS
\(dg Not supported in 4.3BSD.
.FE
-.TE
.in -5
.h 1.3 "Signals
.in +5
@@ -128,10 +128,10 @@ close close descriptor
select multiplex input/output
fcntl control descriptor options
wrap\(dg wrap descriptor with protocol
+.TE
.FS
\(dg Not supported in 4.3BSD.
.FE
-.TE
.in -5
.h 1.6 "Resource controls
.in +5
diff --git a/share/doc/smm/05.fsck/3.t b/share/doc/smm/05.fsck/3.t
index fb4d3a40792f..28fc28a9a1a1 100644
--- a/share/doc/smm/05.fsck/3.t
+++ b/share/doc/smm/05.fsck/3.t
@@ -371,7 +371,7 @@ will replace them with the correct values.
If there are multiple hard links to a directory,
the first one encountered is considered the real parent
to which ``\fB..\fP'' should point;
-\fIfsck\P recommends deletion for the subsequently discovered names.
+\fIfsck\fP recommends deletion for the subsequently discovered names.
.NH 2
File system connectivity
.PP
diff --git a/share/doc/smm/05.fsck/Makefile b/share/doc/smm/05.fsck/Makefile
index 6356d4fcc348..a0ad254a13d5 100644
--- a/share/doc/smm/05.fsck/Makefile
+++ b/share/doc/smm/05.fsck/Makefile
@@ -5,7 +5,7 @@ VOLUME= smm
DOC= 05.fsck
SRCS= 0.t 1.t 2.t 3.t 4.t
-TROFF= ditroff
+MACROS = -ms
.include <bsd.doc.mk>
diff --git a/share/doc/usd/04.csh/Makefile b/share/doc/usd/04.csh/Makefile
index b0b8ee3a2eb3..cbbac8aeacc9 100644
--- a/share/doc/usd/04.csh/Makefile
+++ b/share/doc/usd/04.csh/Makefile
@@ -3,6 +3,7 @@
VOLUME= usd
DOC= 04.csh
+MACROS = -ms
SRCS= tabs csh.1 csh.2 csh.3 csh.4 csh.a csh.g
diff --git a/share/doc/usd/04.csh/csh.a b/share/doc/usd/04.csh/csh.a
index 8482b6d074a1..6766b0851cd7 100644
--- a/share/doc/usd/04.csh/csh.a
+++ b/share/doc/usd/04.csh/csh.a
@@ -56,7 +56,7 @@ Syntactic metacharacters
Filename metacharacters
.DS
/ 1.6 separates components of a file's pathname
-\. 1.6 separates root parts of a file name from extensions
+\&. 1.6 separates root parts of a file name from extensions
? 1.6 expansion character matching any single character
* 1.6 expansion character matching any sequence of characters
[ ] 1.6 expansion sequence matching any single character from a set
diff --git a/share/doc/usd/34.trek/trek.me b/share/doc/usd/34.trek/trek.me
index 13bbd1e0ce16..64dd26d8b19d 100644
--- a/share/doc/usd/34.trek/trek.me
+++ b/share/doc/usd/34.trek/trek.me
@@ -311,7 +311,6 @@ K the villain
a black hole
.in -12
.fi
-.ev
.pp
The name of the starsystem is listed underneath
the short range scan.
@@ -429,19 +428,19 @@ Long range scan for quadrant 0,3
.sp
.ie t \{\
.TS
-l1 c1 ce1 c1 ce1 c1 ce1 c0
-l1 l s s s s s s s0
-l1 c1 ce1 c1 ce1 c1 ce1 c0
-l1 l s s s s s s s0.
+l1 c1 ce1 c1 ce1 c1 ce1 c
+l1 l s s s s s s s
+l1 c1 ce1 c1 ce1 c1 ce1 c
+l1 l s s s s s s s.
2 3 4
_
! * ! * ! * !
_
.T&
-l1 c1 re1 c1 re1 c1 re1 c0
-l1 l s s s s s s s0
-l1 c1 re1 c1 re1 c1 re1 c0
-l1 l s s s s s s s0.
+l1 c1 re1 c1 re1 c1 re1 c
+l1 l s s s s s s s
+l1 c1 re1 c1 re1 c1 re1 c
+l1 l s s s s s s s.
0 ! 108 ! 6 ! 19 !
_
1 ! 9 ! /// ! 8 !
diff --git a/share/locale/Ja_JP.EUC b/share/locale/Ja_JP.EUC
new file mode 100644
index 000000000000..55eb1559660f
--- /dev/null
+++ b/share/locale/Ja_JP.EUC
@@ -0,0 +1,158 @@
+# @(#)Japanese 8.1 (Berkeley) 6/6/93
+
+/*
+ * Japanese LOCALE_CTYPE definitions using EUC of JIS character sets
+ */
+
+ENCODING "EUC"
+
+/* JIS JIS JIS */
+/* X201 X208 X201 */
+/* 00-7f 84-fe */
+
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+
+/*
+ * Code Set 1
+ */
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+
+MAPLOWER < 'A' - 'Z' : 'a' >
+MAPLOWER < 'a' - 'z' : 'a' >
+MAPUPPER < 'A' - 'Z' : 'A' >
+MAPUPPER < 'a' - 'z' : 'A' >
+TODIGIT < '0' - '9' : 0 >
+TODIGIT < 'A' - 'F' : 10 >
+TODIGIT < 'a' - 'f' : 10 >
+
+/*
+ * Code Set 2
+ */
+
+SPACE 0xa1a1
+PHONOGRAM 0xa1bc
+SPECIAL 0xa1a2 - 0xa1fe
+PUNCT 0xa1a2 - 0xa1f8 /* A few too many in here... */
+
+SPECIAL 0xa2a1 - 0xa2ae 0xa2ba - 0xa2c1 0xa2ca - 0xa2d0 0xa2dc - 0xa2ea
+SPECIAL 0xa2f2 - 0xa2f9 0xa2fe
+
+DIGIT 0xa3b0 - 0xa3b9
+UPPER 0xa3c1 - 0xa3da /* Romaji */
+LOWER 0xa3e1 - 0xa3fa /* Romaji */
+MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > /* English */
+MAPLOWER < 0xa3e1 - 0xa3fa : 0xa3e1 > /* English */
+MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 >
+MAPUPPER < 0xa3e1 - 0xa3fa : 0xa3c1 >
+
+XDIGIT 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
+
+TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
+TODIGIT < 0xa3c1 - 0xa3c6 : 10 >
+TODIGIT < 0xa3e1 - 0xa3e6 : 10 >
+
+PHONOGRAM 0xa4a1 - 0xa4f3
+PHONOGRAM 0xa5a1 - 0xa5f6
+
+UPPER 0xa6a1 - 0xa6b8 /* Greek */
+LOWER 0xa6c1 - 0xa6d8 /* Greek */
+MAPLOWER < 0xa6a1 - 0xa6b8 : 0xa6c1 >
+MAPLOWER < 0xa6c1 - 0xa6d8 : 0xa6c1 >
+MAPUPPER < 0xa6a1 - 0xa6b8 : 0xa6a1 >
+MAPUPPER < 0xa6c1 - 0xa6d8 : 0xa6a1 >
+
+UPPER 0xa7a1 - 0xa7c1 /* Cyrillic */
+LOWER 0xa7d1 - 0xa7f1 /* Cyrillic */
+MAPLOWER < 0xa7a1 - 0xa7c1 : 0xa7d1 >
+MAPLOWER < 0xa7d1 - 0xa7f1 : 0xa7d1 >
+MAPUPPER < 0xa7a1 - 0xa7c1 : 0xa7a1 >
+MAPUPPER < 0xa7d1 - 0xa7f1 : 0xa7a1 >
+
+SPECIAL 0xa8a1 - 0xa8c0
+
+IDEOGRAM 0xb0a1 - 0xb0fe
+IDEOGRAM 0xb1a1 - 0xb1fe
+IDEOGRAM 0xb2a1 - 0xb2fe
+IDEOGRAM 0xb3a1 - 0xb3fe
+IDEOGRAM 0xb4a1 - 0xb4fe
+IDEOGRAM 0xb5a1 - 0xb5fe
+IDEOGRAM 0xb6a1 - 0xb6fe
+IDEOGRAM 0xb7a1 - 0xb7fe
+IDEOGRAM 0xb8a1 - 0xb8fe
+IDEOGRAM 0xb9a1 - 0xb9fe
+IDEOGRAM 0xbaa1 - 0xbafe
+IDEOGRAM 0xbba1 - 0xbbfe
+IDEOGRAM 0xbca1 - 0xbcfe
+IDEOGRAM 0xbda1 - 0xbdfe
+IDEOGRAM 0xbea1 - 0xbefe
+IDEOGRAM 0xbfa1 - 0xbffe
+IDEOGRAM 0xc0a1 - 0xc0fe
+IDEOGRAM 0xc1a1 - 0xc1fe
+IDEOGRAM 0xc2a1 - 0xc2fe
+IDEOGRAM 0xc3a1 - 0xc3fe
+IDEOGRAM 0xc4a1 - 0xc4fe
+IDEOGRAM 0xc5a1 - 0xc5fe
+IDEOGRAM 0xc6a1 - 0xc6fe
+IDEOGRAM 0xc7a1 - 0xc7fe
+IDEOGRAM 0xc8a1 - 0xc8fe
+IDEOGRAM 0xc9a1 - 0xc9fe
+IDEOGRAM 0xcaa1 - 0xcafe
+IDEOGRAM 0xcba1 - 0xcbfe
+IDEOGRAM 0xcca1 - 0xccfe
+IDEOGRAM 0xcda1 - 0xcdfe
+IDEOGRAM 0xcea1 - 0xcefe
+IDEOGRAM 0xcfa1 - 0xcfd3
+IDEOGRAM 0xd0a1 - 0xd0fe
+IDEOGRAM 0xd1a1 - 0xd1fe
+IDEOGRAM 0xd2a1 - 0xd2fe
+IDEOGRAM 0xd3a1 - 0xd3fe
+IDEOGRAM 0xd4a1 - 0xd4fe
+IDEOGRAM 0xd5a1 - 0xd5fe
+IDEOGRAM 0xd6a1 - 0xd6fe
+IDEOGRAM 0xd7a1 - 0xd7fe
+IDEOGRAM 0xd8a1 - 0xd8fe
+IDEOGRAM 0xd9a1 - 0xd9fe
+IDEOGRAM 0xdaa1 - 0xdafe
+IDEOGRAM 0xdba1 - 0xdbfe
+IDEOGRAM 0xdca1 - 0xdcfe
+IDEOGRAM 0xdda1 - 0xddfe
+IDEOGRAM 0xdea1 - 0xdefe
+IDEOGRAM 0xdfa1 - 0xdffe
+IDEOGRAM 0xe0a1 - 0xe0fe
+IDEOGRAM 0xe1a1 - 0xe1fe
+IDEOGRAM 0xe2a1 - 0xe2fe
+IDEOGRAM 0xe3a1 - 0xe3fe
+IDEOGRAM 0xe4a1 - 0xe4fe
+IDEOGRAM 0xe5a1 - 0xe5fe
+IDEOGRAM 0xe6a1 - 0xe6fe
+IDEOGRAM 0xe7a1 - 0xe7fe
+IDEOGRAM 0xe8a1 - 0xe8fe
+IDEOGRAM 0xe9a1 - 0xe9fe
+IDEOGRAM 0xeaa1 - 0xeafe
+IDEOGRAM 0xeba1 - 0xebfe
+IDEOGRAM 0xeca1 - 0xecfe
+IDEOGRAM 0xeda1 - 0xedfe
+IDEOGRAM 0xeea1 - 0xeefe
+IDEOGRAM 0xefa1 - 0xeffe
+IDEOGRAM 0xf0a1 - 0xf0fe
+IDEOGRAM 0xf1a1 - 0xf1fe
+IDEOGRAM 0xf2a1 - 0xf2fe
+IDEOGRAM 0xf3a1 - 0xf3fe
+IDEOGRAM 0xf4a1 - 0xf4a4
+
+/*
+ * This is for Code Set 3, half-width kana
+ */
+SPECIAL 0xa1 - 0xdf
+PHONOGRAM 0xa1 - 0xdf
+CONTROL 0x84 - 0x97 0x9b - 0x9f 0xe0 - 0xfe
diff --git a/share/locale/Makefile b/share/locale/Makefile
new file mode 100644
index 000000000000..76b34640c45e
--- /dev/null
+++ b/share/locale/Makefile
@@ -0,0 +1,23 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/7/93
+# $Id: Makefile,v 1.4 1994/04/07 14:09:53 ats Exp $
+
+PROG= mklocale
+SRCS= yacc.c lex.c
+CFLAGS+=-I.
+CLEANFILES+=y.tab.h yacc.c lex.c
+BINDIR= /usr/bin
+MAN1= mklocale.1
+
+LOCALES= Ja_JP.EUC POSIX Russian.koi8-r
+LOCALEDIR= ${DESTDIR}/usr/share/locale
+
+afterinstall:
+ -if [ -d ${LOCALEDIR} ]; then true; else mkdir -p ${LOCALEDIR}; fi
+ for locale in ${LOCALES}; do \
+ mkdir -p ${LOCALEDIR}/$$locale || true; \
+ mklocale -o ${LOCALEDIR}/$$locale/LC_CTYPE ${.CURDIR}/$$locale; \
+ chmod ${BINMODE} ${LOCALEDIR}/$$locale; \
+ done
+ chown -R ${BINOWN}.${BINGRP} ${LOCALEDIR}
+
+.include <bsd.prog.mk>
diff --git a/share/locale/POSIX b/share/locale/POSIX
new file mode 100644
index 000000000000..ead0bc8c18ce
--- /dev/null
+++ b/share/locale/POSIX
@@ -0,0 +1,33 @@
+# @(#)POSIX 8.1 (Berkeley) 6/6/93
+
+/*
+ * Standard LOCALE_CTYPE for the C Locale
+ */
+ENCODING "UTF2"
+VARIABLE A comment line or data line. Only 1 allowed. Copied verbatim.
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/share/locale/Russian.koi8-r b/share/locale/Russian.koi8-r
new file mode 100644
index 000000000000..d2164c45a997
--- /dev/null
+++ b/share/locale/Russian.koi8-r
@@ -0,0 +1,39 @@
+/*
+ * LOCALE_CTYPE for Russian koi8-r character set (RFC1489)
+ */
+ENCODING "NONE"
+VARIABLE Russian koi8-r character set by ache@astral.msk.su
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z' 0xa3 0xb3 0xc0 - 0xff
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e 0x80 - 0xff
+LOWER 'a' - 'z' 0xa3 0xc0 - 0xdf
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z' 0xb3 0xe0 - 0xff
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e 0x80 - 0xff
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPLOWER <0xb3 0xa3>
+MAPLOWER <0xa3 0xa3>
+MAPLOWER <0xe0 - 0xff : 0xc0>
+MAPLOWER <0xc0 - 0xdf : 0xc0>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+MAPUPPER <0xb3 0xb3>
+MAPUPPER <0xa3 0xb3>
+MAPUPPER <0xe0 - 0xff : 0xe0>
+MAPUPPER <0xc0 - 0xdf : 0xe0>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/share/locale/ldef.h b/share/locale/ldef.h
new file mode 100644
index 000000000000..95b51dac478f
--- /dev/null
+++ b/share/locale/ldef.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ *
+ * @(#)ldef.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * This should look a LOT like a _RuneEntry
+ */
+typedef struct rune_list {
+ rune_t min;
+ rune_t max;
+ rune_t map;
+ u_long *types;
+ struct rune_list *next;
+} rune_list;
+
+typedef struct rune_map {
+ u_long map[_CACHED_RUNES];
+ rune_list *root;
+} rune_map;
diff --git a/share/locale/lex.l b/share/locale/lex.l
new file mode 100644
index 000000000000..0e2f1a9833b3
--- /dev/null
+++ b/share/locale/lex.l
@@ -0,0 +1,152 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lex.l 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ldef.h"
+#include "y.tab.h"
+%}
+
+ODIGIT [0-7]
+DIGIT [0-9]
+XDIGIT [0-9a-fA-F]
+W [\t\n\r ]
+
+%%
+\'.\' { yylval.rune = yytext[1];
+ return(RUNE); }
+
+'\\a' { yylval.rune = '\a';
+ return(RUNE); }
+'\\b' { yylval.rune = '\b';
+ return(RUNE); }
+'\\f' { yylval.rune = '\f';
+ return(RUNE); }
+'\\n' { yylval.rune = '\n';
+ return(RUNE); }
+'\\r' { yylval.rune = '\r';
+ return(RUNE); }
+'\\t' { yylval.rune = '\t';
+ return(RUNE); }
+'\\v' { yylval.rune = '\v';
+ return(RUNE); }
+
+0x{XDIGIT}+ { yylval.rune = strtol(yytext, 0, 16);
+ return(RUNE); }
+0{ODIGIT}+ { yylval.rune = strtol(yytext, 0, 8);
+ return(RUNE); }
+{DIGIT}+ { yylval.rune = strtol(yytext, 0, 10);
+ return(RUNE); }
+
+
+MAPLOWER { return(MAPLOWER); }
+MAPUPPER { return(MAPUPPER); }
+TODIGIT { return(DIGITMAP); }
+INVALID { return(INVALID); }
+
+ALPHA { yylval.i = _A|_R|_G; return(LIST); }
+CONTROL { yylval.i = _C; return(LIST); }
+DIGIT { yylval.i = _D|_R|_G; return(LIST); }
+GRAPH { yylval.i = _G|_R; return(LIST); }
+LOWER { yylval.i = _L|_R|_G; return(LIST); }
+PUNCT { yylval.i = _P|_R|_G; return(LIST); }
+SPACE { yylval.i = _S; return(LIST); }
+UPPER { yylval.i = _U|_R|_G; return(LIST); }
+XDIGIT { yylval.i = _X|_R|_G; return(LIST); }
+BLANK { yylval.i = _B; return(LIST); }
+PRINT { yylval.i = _R; return(LIST); }
+IDEOGRAM { yylval.i = _I|_R|_G; return(LIST); }
+SPECIAL { yylval.i = _T|_R|_G; return(LIST); }
+PHONOGRAM { yylval.i = _Q|_R|_G; return(LIST); }
+
+VARIABLE[\t ] { static char vbuf[1024];
+ char *v = vbuf;
+ while ((*v = input()) && *v != '\n')
+ ++v;
+ if (*v) {
+ unput(*v);
+ *v = 0;
+ }
+ yylval.str = vbuf;
+ return(VARIABLE);
+ }
+
+ENCODING { return(ENCODING); }
+
+\".*\" { char *e = yytext + 1;
+ yylval.str = e;
+ while (*e && *e != '"')
+ ++e;
+ *e = 0;
+ return(STRING); }
+
+\<|\(|\[ { return(LBRK); }
+
+\>|\)|\] { return(RBRK); }
+
+\- { return(THRU); }
+\.\.\. { return(THRU); }
+
+\: { return(':'); }
+
+{W}+ ;
+
+^\#.*\n ;
+\/\* { char lc = 0;
+ do {
+ while ((lc) != '*')
+ if ((lc = input()) == 0)
+ break;
+ } while((lc = input()) != '/');
+ }
+
+\\$ ;
+. { printf("Lex is skipping '%s'\n", yytext); }
+%%
+
+#if !defined(yywrap)
+yywrap()
+{
+ return(1);
+}
+#endif
diff --git a/share/locale/mklocale.1 b/share/locale/mklocale.1
new file mode 100644
index 000000000000..bf39466fb559
--- /dev/null
+++ b/share/locale/mklocale.1
@@ -0,0 +1,257 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)mklocale.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd "June 6, 1993"
+.Dt MKLOCALE 1
+.Os
+.Sh NAME
+.Nm mklocale
+.Nd make LC_CTYPE locale files
+.Sh SYNOPSIS
+.Nm mklocale
+.Ar "< src-file"
+.Ar "> language/LC_CTYPE"
+.Sh DESCRIPTION
+The
+.Nm mklocale
+utility reads a
+.Dv LC_CTYPE
+source file from standard input and produces a
+.Dv LC_CTYPE
+binary file on standard output suitable for placement in
+.Dv /usr/share/locale/\fIlanguage\fP/LC_CTYPE.
+.Pp
+The format of
+.Ar src-file
+is quite simple.
+It consists of a series of lines which start with a keyword and have
+associated data following. C style comments are used
+to place comments in the file.
+.Pp
+Besides the keywords which will be listed below,
+the following are valid tokens in
+.Ar src-file :
+.Bl -tag -width literal
+.It Dv RUNE
+A
+.Dv RUNE
+may be any of the following:
+.Bl -tag -width 0x[0-9a-z]*
+.It Ar 'x'
+The ascii character
+.Ar x .
+.It Ar '\ex'
+The ANSI C character
+.Ar \ex
+where
+.Ar \ex
+is one of
+.Dv \ea ,
+.Dv \eb ,
+.Dv \ef ,
+.Dv \en ,
+.Dv \er ,
+.Dv \et ,
+or
+.Dv \ev .
+.It Ar 0x[0-9a-z]*
+A hexadecimal number representing a rune code.
+.It Ar 0[0-7]*
+An octal number representing a rune code.
+.It Ar [1-9][0-9]*
+A decimal number representing a rune code.
+.El
+.It Dv STRING
+A string enclosed in double quotes (").
+.It Dv THRU
+Either
+.Dv ...
+or
+.Dv - .
+Used to indicate ranges.
+.It Ar literal
+The follow characters are taken literally:
+.Bl -tag -width "<\|\|(\|\|["
+.It Dv "<\|(\|["
+Used to start a mapping. All are equivalent.
+.It Dv ">\|\^)\|]"
+Used to end a mapping. All are equivalent.
+.It Dv :
+Used as a delimiter in mappings.
+.El
+.El
+.sp
+Key words which should only appear once are:
+.Bl -tag -width PHONOGRAM
+.It Dv ENCODING
+Followed by a
+.Dv STRING
+which indicates the encoding mechanism to be used for this locale.
+The current encodings are:
+.Bl -tag -width NONE
+.It Dv NONE
+No translation and the default.
+.It Dv UTF2
+.Dv "Universal character set Transformation Format"
+adopted from
+.Nm "Plan 9 from Bell Labs" .
+This is the preferred encoding.
+.It Dv EUC
+.Dv EUC
+encoding as used by several
+vendors of
+.Ux
+systems.
+.El
+.It Dv VARIABLE
+This keyword must be followed by a single tab or space character,
+after which encoding specific data is placed.
+Currently only the
+.Dv "EUC"
+encoding requires variable data.
+See
+.Xr euc 4
+for further details.
+.It Dv INVALID
+A single
+.Dv RUNE
+follows and is used as the invalid rune for this locale.
+.El
+.sp
+The following keywords may appear multiple times and have the following
+format for data:
+.in +.5i
+.Bl -tag -width "<RUNE1 THRU RUNEn : RUNE2>"
+.It Dv <RUNE1 RUNE2>
+.Dv RUNE1
+is mapped to
+.Dv RUNE2 .
+.It Dv <RUNE1 THRU RUNEn : RUNE2>
+Runes
+.Dv RUNE1
+through
+.Dv RUNEn
+are mapped to
+.Dv RUNE2
+through
+.Dv RUNE2
++ n-1.
+.El
+.in -.5i
+.Bl -tag -width PHONOGRAM
+.It Dv MAPLOWER
+Defines the tolower mappings.
+.Dv RUNE2
+is the lower case representatin of
+.Dv RUNE1.
+.It Dv MAPUPPER
+Defines the toupper mappings.
+.Dv RUNE2
+is the upper case representatin of
+.Dv RUNE1.
+.It Dv TODIGIT
+Defines a map from runes to their digit value.
+.Dv RUNE2
+is the integer value represented by
+.Dv RUNE1 .
+For example, the ascii character
+.Nm '0'
+would map to the decimal value
+.Nm 0 .
+Only values up to
+.Nm 255
+are allowed.
+.El
+.sp
+The following keywords may appear multiple times and have the following
+format for data:
+.in +.5i
+.Bl -tag -width "RUNE1 THRU RUNEn"
+.It Dv RUNE
+This rune has the property defined by the keyword.
+.It Dv "RUNE1 THRU RUNEn"
+All the runes between and including
+.Dv RUNE1
+and
+.Dv RUNEn
+have the property defined by the keyword.
+.El
+.in -.5i
+.Bl -tag -width PHONOGRAM
+.It Dv ALPHA
+Defines runes which are alphabetic, printable and graphic.
+.It Dv CONTROL
+Defines runes which are control characters.
+.It Dv DIGIT
+Defines runes which are decimal digits, printable and graphic.
+.It Dv GRAPH
+Defines runes which are graphic and printable.
+.It Dv LOWER
+Defines runes which are lower case, printable and graphic.
+.It Dv PUNCT
+Defines runes which are punctuation, printable and graphic.
+.It Dv SPACE
+Defines runes which are spaces.
+.It Dv UPPER
+Defines runes which are upper case, printable and graphic.
+.It Dv XDIGIT
+Defines runes which are hexadecimal digits, printable and graphic.
+.It Dv BLANK
+Defines runes which are blank.
+.It Dv PRINT
+Defines runes which are printable.
+.It Dv IDEOGRAM
+Defines runes which are ideograms, printable and graphic.
+.It Dv SPECIAL
+Defines runes which are special characters, printable and graphic.
+.It Dv PHONOGRAM
+Defines runes which are phonograms, printable and graphic.
+.El
+.Sh SEE ALSO
+.Xr mbrune 3 ,
+.Xr rune 3 ,
+.Xr setlocale 3 ,
+.Xr euc 4 ,
+.Xr utf2 4
+.Sh BUGS
+The
+.Nm mklocale
+utility is overly simplistic.
+.Sh HISTORY
+The
+.Nm mklocale
+utility first appeared in
+.Bx 4.4 .
diff --git a/share/locale/yacc.y b/share/locale/yacc.y
new file mode 100644
index 000000000000..193b7b1af63d
--- /dev/null
+++ b/share/locale/yacc.y
@@ -0,0 +1,821 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)yacc.y 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ldef.h"
+
+char *locale_file = "<stdout>";
+
+rune_map maplower = { 0, };
+rune_map mapupper = { 0, };
+rune_map types = { 0, };
+
+_RuneLocale new_locale = { 0, };
+
+void set_map __P((rune_map *, rune_list *, u_long));
+void set_digitmap __P((rune_map *, rune_list *));
+void add_map __P((rune_map *, rune_list *, u_long));
+%}
+
+%union {
+ rune_t rune;
+ int i;
+ char *str;
+
+ rune_list *list;
+}
+
+%token <rune> RUNE
+%token LBRK
+%token RBRK
+%token THRU
+%token MAPLOWER
+%token MAPUPPER
+%token DIGITMAP
+%token <i> LIST
+%token <str> VARIABLE
+%token ENCODING
+%token INVALID
+%token <str> STRING
+
+%type <list> list
+%type <list> map
+
+
+%%
+
+locale : /* empty */
+ | table
+ { dump_tables(); }
+ ;
+
+table : entry
+ | table entry
+ ;
+
+entry : ENCODING STRING
+ { strncpy(new_locale.encoding, $2, sizeof(new_locale.encoding)); }
+ | VARIABLE
+ { new_locale.variable_len = strlen($1) + 1;
+ new_locale.variable = malloc(new_locale.variable_len);
+ strcpy((char *)new_locale.variable, $1);
+ }
+ | INVALID RUNE
+ { new_locale.invalid_rune = $2; }
+ | LIST list
+ { set_map(&types, $2, $1); }
+ | MAPLOWER map
+ { set_map(&maplower, $2, 0); }
+ | MAPUPPER map
+ { set_map(&mapupper, $2, 0); }
+ | DIGITMAP map
+ { set_digitmap(&types, $2); }
+ ;
+
+list : RUNE
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $1;
+ $$->next = 0;
+ }
+ | RUNE THRU RUNE
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $3;
+ $$->next = 0;
+ }
+ | list RUNE
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->next = $1;
+ }
+ | list RUNE THRU RUNE
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->next = $1;
+ }
+ ;
+
+map : LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->map = $3;
+ $$->next = 0;
+ }
+ | map LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $3;
+ $$->map = $4;
+ $$->next = $1;
+ }
+ | LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->map = $6;
+ $$->next = 0;
+ }
+ | map LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)malloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $5;
+ $$->map = $7;
+ $$->next = $1;
+ }
+ ;
+%%
+
+int debug = 0;
+FILE *fp = stdout;
+
+main(ac, av)
+ int ac;
+ char *av[];
+{
+ int x;
+
+ extern char *optarg;
+ extern int optind;
+
+ while ((x = getopt(ac, av, "do:")) != EOF) {
+ switch(x) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'o':
+ locale_file = optarg;
+ if ((fp = fopen(locale_file, "w")) == 0) {
+ perror(locale_file);
+ exit(1);
+ }
+ break;
+ default:
+ usage:
+ fprintf(stderr, "Usage: mklocale [-d] [-o output] [source]\n");
+ exit(1);
+ }
+ }
+
+ switch (ac - optind) {
+ case 0:
+ break;
+ case 1:
+ if (freopen(av[optind], "r", stdin) == 0) {
+ perror(av[optind]);
+ exit(1);
+ }
+ break;
+ default:
+ goto usage;
+ }
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ mapupper.map[x] = x;
+ maplower.map[x] = x;
+ }
+ new_locale.invalid_rune = _INVALID_RUNE;
+ memcpy(new_locale.magic, _RUNE_MAGIC_1, sizeof(new_locale.magic));
+
+ yyparse();
+}
+
+yyerror(s)
+ char *s;
+{
+ fprintf(stderr, "%s\n", s);
+}
+
+void *
+xmalloc(sz)
+ unsigned int sz;
+{
+ void *r = malloc(sz);
+ if (!r) {
+ perror("xmalloc");
+ abort();
+ }
+ return(r);
+}
+
+u_long *
+xlalloc(sz)
+ unsigned int sz;
+{
+ u_long *r = (u_long *)malloc(sz * sizeof(u_long));
+ if (!r) {
+ perror("xlalloc");
+ abort();
+ }
+ return(r);
+}
+
+u_long *
+xrelalloc(old, sz)
+ u_long *old;
+ unsigned int sz;
+{
+ u_long *r = (u_long *)realloc((char *)old, sz * sizeof(u_long));
+ if (!r) {
+ perror("xrelalloc");
+ abort();
+ }
+ return(r);
+}
+
+void
+set_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ u_long flag;
+{
+ while (list) {
+ rune_list *nlist = list->next;
+ add_map(map, list, flag);
+ list = nlist;
+ }
+}
+
+void
+set_digitmap(map, list)
+ rune_map *map;
+ rune_list *list;
+{
+ rune_t i;
+
+ while (list) {
+ rune_list *nlist = list->next;
+ for (i = list->min; i <= list->max; ++i) {
+ if (list->map + (i - list->min)) {
+ rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
+ tmp->min = i;
+ tmp->max = i;
+ add_map(map, tmp, list->map + (i - list->min));
+ }
+ }
+ free(list);
+ list = nlist;
+ }
+}
+
+void
+add_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ u_long flag;
+{
+ rune_t i;
+ rune_list *lr = 0;
+ rune_list *r;
+ rune_t run;
+
+ while (list->min < _CACHED_RUNES && list->min <= list->max) {
+ if (flag)
+ map->map[list->min++] |= flag;
+ else
+ map->map[list->min++] = list->map++;
+ }
+
+ if (list->min > list->max) {
+ free(list);
+ return;
+ }
+
+ run = list->max - list->min + 1;
+
+ if (!(r = map->root) || (list->max < r->min - 1)
+ || (!flag && list->max == r->min - 1)) {
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = map->root;
+ map->root = list;
+ return;
+ }
+
+ for (r = map->root; r && r->max + 1 < list->min; r = r->next)
+ lr = r;
+
+ if (!r) {
+ /*
+ * We are off the end.
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = 0;
+ lr->next = list;
+ return;
+ }
+
+ if (list->max < r->min - 1) {
+ /*
+ * We come before this range and we do not intersect it.
+ * We are not before the root node, it was checked before the loop
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = lr->next;
+ lr->next = list;
+ return;
+ }
+
+ /*
+ * At this point we have found that we at least intersect with
+ * the range pointed to by `r', we might intersect with one or
+ * more ranges beyond `r' as well.
+ */
+
+ if (!flag && list->map - list->min != r->map - r->min) {
+ /*
+ * There are only two cases when we are doing case maps and
+ * our maps needn't have the same offset. When we are adjoining
+ * but not intersecting.
+ */
+ if (list->max + 1 == r->min) {
+ lr->next = list;
+ list->next = r;
+ return;
+ }
+ if (list->min - 1 == r->max) {
+ list->next = r->next;
+ r->next = list;
+ return;
+ }
+ fprintf(stderr, "Error: conflicting map entries\n");
+ exit(1);
+ }
+
+ if (list->min >= r->min && list->max <= r->max) {
+ /*
+ * Subset case.
+ */
+
+ if (flag) {
+ for (i = list->min; i <= list->max; ++i)
+ r->types[i - r->min] |= flag;
+ }
+ free(list);
+ return;
+ }
+ if (list->min <= r->min && list->max >= r->max) {
+ /*
+ * Superset case. Make him big enough to hold us.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ list->types = xlalloc(list->max - list->min + 1);
+
+ for (i = list->min; i <= list->max; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] |= r->types[i - r->min];
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ r->max = list->max;
+ free(list);
+ } else if (list->min < r->min) {
+ /*
+ * Our tail intersects his head.
+ */
+ if (flag) {
+ list->types = xlalloc(r->max - list->min + 1);
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] = r->types[i - r->min];
+
+ for (i = list->min; i < r->min; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= list->max; ++i)
+ list->types[i - list->min] |= flag;
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ free(list);
+ return;
+ } else {
+ /*
+ * Our head intersects his tail.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ r->types = xrelalloc(r->types, list->max - r->min + 1);
+
+ for (i = list->min; i <= r->max; ++i)
+ r->types[i - r->min] |= flag;
+
+ for (i = r->max+1; i <= list->max; ++i)
+ r->types[i - r->min] = flag;
+ }
+ r->max = r->max;
+ free(list);
+ }
+
+ /*
+ * Okay, check to see if we grew into the next guy(s)
+ */
+ while ((lr = r->next) && r->max >= lr->min) {
+ if (flag) {
+ if (r->max >= lr->max) {
+ /*
+ * Good, we consumed all of him.
+ */
+ for (i = lr->min; i <= lr->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+ } else {
+ /*
+ * "append" him on to the end of us.
+ */
+ r->types = xrelalloc(r->types, lr->max - r->min + 1);
+
+ for (i = lr->min; i <= r->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+
+ for (i = r->max+1; i <= lr->max; ++i)
+ r->types[i - r->min] = lr->types[i - lr->min];
+
+ r->max = lr->max;
+ }
+ } else {
+ if (lr->max > r->max)
+ r->max = lr->max;
+ }
+
+ r->next = lr->next;
+
+ if (flag)
+ free(lr->types);
+ free(lr);
+ }
+}
+
+void
+dump_tables()
+{
+ int x;
+ rune_list *list;
+
+ /*
+ * See if we can compress some of the istype arrays
+ */
+ for(list = types.root; list; list = list->next) {
+ list->map = list->types[0];
+ for (x = 1; x < list->max - list->min + 1; ++x) {
+ if (list->types[x] != list->map) {
+ list->map = 0;
+ break;
+ }
+ }
+ }
+
+ new_locale.invalid_rune = htonl(new_locale.invalid_rune);
+
+ /*
+ * Fill in our tables. Do this in network order so that
+ * diverse machines have a chance of sharing data.
+ * (Machines like Crays cannot share with little machines due to
+ * word size. Sigh. We tried.)
+ */
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ new_locale.runetype[x] = htonl(types.map[x]);
+ new_locale.maplower[x] = htonl(maplower.map[x]);
+ new_locale.mapupper[x] = htonl(mapupper.map[x]);
+ }
+
+ /*
+ * Count up how many ranges we will need for each of the extents.
+ */
+ list = types.root;
+
+ while (list) {
+ new_locale.runetype_ext.nranges++;
+ list = list->next;
+ }
+ new_locale.runetype_ext.nranges = htonl(new_locale.runetype_ext.nranges);
+
+ list = maplower.root;
+
+ while (list) {
+ new_locale.maplower_ext.nranges++;
+ list = list->next;
+ }
+ new_locale.maplower_ext.nranges = htonl(new_locale.maplower_ext.nranges);
+
+ list = mapupper.root;
+
+ while (list) {
+ new_locale.mapupper_ext.nranges++;
+ list = list->next;
+ }
+ new_locale.mapupper_ext.nranges = htonl(new_locale.mapupper_ext.nranges);
+
+ new_locale.variable_len = htonl(new_locale.variable_len);
+
+ /*
+ * Okay, we are now ready to write the new locale file.
+ */
+
+ /*
+ * PART 1: The _RuneLocale structure
+ */
+ if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+ /*
+ * PART 2: The runetype_ext structures (not the actual tables)
+ */
+ list = types.root;
+
+ while (list) {
+ _RuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 3: The maplower_ext structures
+ */
+ list = maplower.root;
+
+ while (list) {
+ _RuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 4: The mapupper_ext structures
+ */
+ list = mapupper.root;
+
+ while (list) {
+ _RuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 5: The runetype_ext tables
+ */
+ list = types.root;
+
+ while (list) {
+ for (x = 0; x < list->max - list->min + 1; ++x)
+ list->types[x] = htonl(list->types[x]);
+
+ if (!list->map) {
+ if (fwrite((char *)&list->types,
+ (list->max - list->min + 1)*sizeof(u_long), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+ }
+ list = list->next;
+ }
+ /*
+ * PART 5: And finally the variable data
+ */
+ if (fwrite((char *)new_locale.variable,
+ ntohl(new_locale.variable_len), 1, fp) != 1) {
+ perror(locale_file);
+ exit(1);
+ }
+ fclose(fp);
+
+ if (!debug)
+ return;
+
+ if (new_locale.encoding[0])
+ fprintf(stderr, "ENCODING %s\n", new_locale.encoding);
+ if (new_locale.variable)
+ fprintf(stderr, "VARIABLE %s\n", new_locale.variable);
+
+ fprintf(stderr, "\nMAPLOWER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(maplower.map[x]))
+ fprintf(stderr, " '%c'", maplower.map[x]);
+ else if (maplower.map[x])
+ fprintf(stderr, "%04x", maplower.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = maplower.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+ fprintf(stderr, "\nMAPUPPER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(mapupper.map[x]))
+ fprintf(stderr, " '%c'", mapupper.map[x]);
+ else if (mapupper.map[x])
+ fprintf(stderr, "%04x", mapupper.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = mapupper.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+
+ fprintf(stderr, "\nTYPES:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ u_long r = types.map[x];
+
+ if (r) {
+ if (isprint(x))
+ fprintf(stderr, " '%c': %2d", x, r & 0xff);
+ else
+ fprintf(stderr, "%04x: %2d", x, r & 0xff);
+
+ fprintf(stderr, " %4s", (r & _A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+
+ for (list = types.root; list; list = list->next) {
+ if (list->map && list->min + 3 < list->max) {
+ u_long r = list->map;
+
+ fprintf(stderr, "%04x: %2d", list->min, r & 0xff);
+
+ fprintf(stderr, " %4s", (r & _A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _Q) ? "phon" : "");
+ fprintf(stderr, "\n...\n");
+
+ fprintf(stderr, "%04x: %2d", list->max, r & 0xff);
+
+ fprintf(stderr, " %4s", (r & _A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ } else
+ for (x = list->min; x <= list->max; ++x) {
+ u_long r = ntohl(list->types[x - list->min]);
+
+ if (r) {
+ fprintf(stderr, "%04x: %2d", x, r & 0xff);
+
+ fprintf(stderr, " %4s", (r & _A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+ }
+}
diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4
index 62bebbf6f43f..9255c0d70ef5 100644
--- a/share/man/man4/ddb.4
+++ b/share/man/man4/ddb.4
@@ -23,6 +23,7 @@
.\" any improvements or extensions that they make and grant Carnegie Mellon
.\" the rights to redistribute these changes.
.\"
+.\" changed a \# to #, since groff choked on it.
.\"
.\" HISTORY
.\" ddb.4,v
@@ -394,7 +395,7 @@ last address explicitly specified.
.IP "$<variable>" 15n
register name or variable. It is translated to the value of it.
It may be followed by a ':' and modifiers as described above.
-.IP \# 15n
+.IP # 15n
a binary operator which rounds up the left hand side to the next
multiple of right hand side.
.IP "*<expr>" 15n
diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile
index 17702805c040..979c5c77756c 100644
--- a/share/man/man4/man4.i386/Makefile
+++ b/share/man/man4/man4.i386/Makefile
@@ -1,10 +1,9 @@
# @(#)Makefile 0.1 (RWGrimes) 3/25/93
-MAN4= com.4 keyboard.4 lpa.4 lpt.4 mem.4 mse.4 npx.4 screen.4 sio.4 spkr.4
+MAN4= com.4 keyboard.4 lpt.4 mem.4 mse.4 npx.4 screen.4 sio.4 spkr.4 tw.4
MLINKS= com.4 ../com.4
MLINKS+= keyboard.4 ../keyboard.4
-MLINKS+= lpa.4 ../lpa.4
MLINKS+= lpt.4 ../lpt.4
MLINKS+= mem.4 ../mem.4
MLINKS+= mem.4 ../kmem.4
@@ -13,6 +12,7 @@ MLINKS+= npx.4 ../npx.4
MLINKS+= screen.4 ../screen.4
MLINKS+= sio.4 ../sio.4
MLINKS+= spkr.4 ../spkr.4
+MLINKS+= tw.4 ../tw.4
MANSUBDIR=/i386
diff --git a/share/man/man4/man4.i386/lpa.4 b/share/man/man4/man4.i386/lpa.4
deleted file mode 100644
index ef5f422f6490..000000000000
--- a/share/man/man4/man4.i386/lpa.4
+++ /dev/null
@@ -1,62 +0,0 @@
-.\"
-.\" Copyright (c) 1993 Christopher G. Demetriou
-.\" 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 Christopher G. Demetriou.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software withough specific prior written permission
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: lpa.4,v 1.1 1993/08/06 10:34:11 cgd Exp
-.\" $Id: lpa.4,v 1.1 1993/08/28 12:41:20 rgrimes Exp $
-.\"
-.Dd August 28, 1993
-.Dt LPA 4 i386
-.Os FreeBSD
-.Sh NAME
-.Nm lpa
-.Nd
-Interruptless parallel port driver
-.Sh SYNOPSIS
-.\" XXX this is awful hackery to get it to work right... -- cgd
-.Cd "device lpa0 at isa? port" \&"IO_LPT1\&" tty
-.Cd "device lpa1 at isa? port" \&"IO_LPT2\&" tty
-.Cd "device lpa2 at isa? port" \&"IO_LPT3\&" tty
-.Sh DESCRIPTION
-This driver provides access to parallel ports. It assumes that
-the parallel port controller will not cause an interrupt, and
-therefore must poll the controller.
-.Sh FILES
-.Bl -tag -width Pa -compact
-.It Pa /dev/lpa0
-first interruptless parallel port driver
-.El
-.Sh SEE ALSO
-.Xr lpt 4
-.Sh BUGS
-This driver only exists to support broken parallel port implementations.
-Systems with properly working parallel ports should use the
-.Nm lpt
-driver instead, as it is less resource-hungry.
-.Pp
-This driver could stand a rewrite.
diff --git a/share/man/man4/man4.i386/lpt.4 b/share/man/man4/man4.i386/lpt.4
index 0fb89387bab9..ad20a65b7a04 100644
--- a/share/man/man4/man4.i386/lpt.4
+++ b/share/man/man4/man4.i386/lpt.4
@@ -1,5 +1,6 @@
.\"
.\" Copyright (c) 1993 Christopher G. Demetriou
+.\" Copyright (c) 1994 Geoffrey M. Rehmet
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -69,5 +70,10 @@ first parallel port driver
.Xr lptcontrol 1
.Sh BUGS
There are lots of them, especially in cheap parallel port implementations.
+.sp
+It is only possible to open a lpt port when a printer is connected and
+on-line, making it impossible to run
+.Xr lptcontrol 1
+when there is no printer connected.
.Pp
This driver could still stand a rewrite.
diff --git a/share/man/man4/man4.i386/sio.4 b/share/man/man4/man4.i386/sio.4
index 8fcd2c17cfd1..e79d3864880b 100644
--- a/share/man/man4/man4.i386/sio.4
+++ b/share/man/man4/man4.i386/sio.4
@@ -34,9 +34,9 @@
.\"
.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91
.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp
-.\" $Id: sio.4,v 1.8.2.1 1994/05/01 16:07:37 jkh Exp $
+.\" $Id: sio.4,v 1.13 1994/06/15 23:28:07 jkh Exp $
.\"
-.Dd February 9, 1994
+.Dd June 3, 1994
.Dt SIO 4 i386
.Os FreeBSD
.Sh NAME
@@ -50,20 +50,42 @@ For standard ports:
.Cd "device sio2 at isa? port" \&"IO_COM3\&" tty irq 5 vector siointr
.Cd "device sio3 at isa? port" \&"IO_COM4\&" tty irq 9 vector siointr
.sp
-For multiport cards:
+For AST compatible multiport cards with 4 ports:
.Cd "options" \&"COM_MULTIPORT\&"
-.Cd "device sio4 at isa? port 0x2a0 tty irq 12 flags 0x401 vector siointr"
-.Cd "device sio5 at isa? port 0x2a8 tty flags 0x401 vector siointr"
-.Cd "device sio6 at isa? port 0x2b0 tty flags 0x401 vector siointr"
-.Cd "device sio7 at isa? port 0x2b8 tty flags 0x401 vector siointr"
+.Cd "device sio4 at isa? port 0x2a0 tty flags 0x701"
+.Cd "device sio5 at isa? port 0x2a8 tty flags 0x701"
+.Cd "device sio6 at isa? port 0x2b0 tty flags 0x701"
+.Cd "device sio7 at isa? port 0x2b8 tty flags 0x701 irq 12 vector siointr"
.sp
-For bidirectional use of ports:
-.Cd "options" \&"COM_BIDIR\&"
+For Boca Board compatible multiport cards with 8 ports:
+.Cd "options" \&"COM_MULTIPORT\&"
+.Cd "device sio4 at isa? port 0x100 tty flags 0xb05"
+.Cd "..."
+.Cd "device sio11 at isa? port 0x138 tty flags 0xb05 irq 12 vector siointr"
.sp
-For control FIFO trigger:
-.Cd "options" \&"FIFO_TRIGGER=FIFO_TRIGGER_14\&"
+Meaning of \fBflags\fR:
+.br
+\fB0x0001\fR shared IRQs
+.br
+\fB0x0002\fR disable FIFO
+.br
+\fB0x0004\fR no AST/4 compatible IRQ control register
+.br
+\fB0x0080\fR enable diagnostics in probe
+.br
+\fB0x\fI??\fB00\fR minor number of master port
.sp
-Use 0x02 bit in flags field to disable FIFO on specified port.
+Minor numbering:
+.br
+0b\fIOLIMMMMM\fR
+.br
+ call\fBO\fRut
+.br
+ \fBL\fRock
+.br
+ \fBI\fRnitial
+.br
+ \fBMMMMMM\fRinor
.Sh DESCRIPTION
The
.Nm sio
@@ -73,117 +95,199 @@ driver provides support for NS8250-, NS16450-, NS16550 and NS16550A-based
.Pf ( Tn CCITT
.Tn V.24 )
communications interfaces. The NS8250 and NS16450 have single character
-buffers, the NS16550A has a 16 character FIFO buffer.
+buffers, the NS16550A has 16 character FIFO input and output buffers.
.Pp
Input and output for each line may set to one of following baud rates;
50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600,
19200, 38400, 57600, or 115200. Your hardware may limit your baud
rate choices.
.Pp
-The driver supports `multiport' cards.
+The driver supports `multiport' cards.
Multiport cards are those that have one or more groups of ports
-that share a common IRQ and Interrupt Request register set per group.
-Frequently 4 ports share 1 IRQ, some 8 port cards have 2 groups of 4 ports,
+that share an Interrupt Request (IRQ) line per group.
+Shared IRQs on different cards are not supported.
+Frequently 4 ports share 1 IRQ; some 8 port cards have 2 groups of 4 ports,
thus using 2 IRQs.
Some cards allow the first 2 serial ports to have seperate IRQs per port
(as per DOS PC standard).
.sp
+Some cards have an IRQ control register for each group.
+Some cards require special initialization related to such registers.
+Only AST/4 compatible IRQ control registers are supported.
+Some cards have an IRQ status register for each group.
+The driver does not require or use such registers yet.
+To work, the control and status registers for a group, if any,
+must be mapped to the scratch register (register 7)
+of a port in the group.
+Such a port is called a
+.Nm master
+port.
+.sp
The
.Nm flags
-keyword specifies for each
+keyword may be used on each
.Nm device sio
-line in the kernel configuration file,
-whether the port is part of an IRQ sharing group, & if so,
-which port is the master device for
-the group (ie which port has the IRQ control registers).
-The master device is the port which
-has registers through which all interrupts of the port group are funneled.
-All ports of a port group report pending interrupts using this
-single register.
-.sp
-The master device is an integer embedded in the high byte of the
-.Nm flags
-bitfield, so all sio entries in the kernel config file that are part of a
-multiport card must include the correct
+line in the kernel configuration file
+to silence the probe
+or to disable the FIFO on 16550A UARTs
+(see the synopsis).
+Disabling the FIFO should rarely be necessary
+since the driver automatically adjusts the receiver
+FIFO trigger level for low latency and high efficiency.
+.sp
+The
.Nm flags
-specification.
-The bitwise assignment allows multiple port groups to
-be configured in one system. It does
+keyword
+.Nm must
+be used for all ports that are part of an IRQ sharing group.
+One bit specifies IRQ sharing; another bit specifies whether the port does
.Nm not
-imply that more than one port group (or card) can share
-the same physical interrupt line!
+require AST/4 compatible initialization.
+The minor number of the device corresponding a master port
+for the group is encoded as a bitfield in the high byte.
+The same master port must be specified for all ports in a group.
+.sp
+The
+.Nm irq
+and
+.Nm vector
+specifications must be given for master ports
+and for ports that are not part of an IRQ sharing group,
+and not for other ports.
.Pp
-In the synopsis the
-.Nm flags 0x401
-means that the 5th port (sio4) is the master
-device (so the MSB of the flags), and that the ports are part of a
-multiport card (the LSB of the flags, actually only the LS
-.Nm bit
-).
-F.e. if you have only two standard ports in addition to multiport
-card, this
-.Nm flags
-will be
-.Nm 0x201
-(assuming the control port is
-.Nm sio2
-).
+In the synopsis,
+.Nm flags 0x701
+means that the 8th port (sio7) is the master
+port, and that the port is on a multiport card with shared IRQs
+and an AST/4 compatible IRQ control register.
+.sp
+.Nm flags 0xb05
+means that the 12th port (sio11) is the master
+port, and that the port is on a multiport card with shared IRQs
+and no special IRQ control register.
.Pp
-Which port is the master device depends on the card type. Consult
-the hardware documentation of your card.
+Which port is the master port depends on the card type.
+Consult the hardware documentation of your card.
+Since IRQ status registers are never used,
+and IRQ control registers are only used for AST/4 compatible cards,
+and some cards map the control/status registers to all ports in a group,
+any port in a group will sometimes do for the master port.
+Choose a port containing an IRQ status register for forwards compatibility,
+and the highest possible port for consistency.
.Pp
-Serial ports controlled by the
+Serial ports controlled by the
.Nm sio
-driver can be used for both dialin and dialout. Use
-.Xr comcontrol 8
-to enable/disable bidirectional use of the
+driver can be used for both `callin' and `callout'.
+For each port there is a callin device and a callout device.
+The minor number of the callout device is 128 higher
+than that of the corresponding callin port.
+The callin device is general purpose.
+Processes opening it normally wait for carrier
+and for the callout device to become inactive.
+The callout device is used to steal the port from
+processes waiting for carrier on the callin device.
+Processes opening it do not wait for carrier
+and put any processes waiting for carrier on the callin device into
+a deeper sleep so that they do not conflict with the callout session.
+The callout device is abused for handling programs that are supposed
+to work on general ports and need to open the port without waiting
+but are too stupid to do so.
+.Pp
+The
.Nm sio
-ports. The minor number of the dialout
-port is 128 higher than that of the corresponding dialin port. Use
+driver also supports an initial-state and a lock-state control
+device for each of the callin and the callout "data" devices.
+The minor number of the initial-state device is 32 higher
+than that of the corresponding data device.
+The minor number of the lock-state device is 64 higher
+than that of the corresponding data device.
+The termios settings of a data device are copied
+from those of the corresponding initial-state device
+on first opens and are not inherited from previous opens.
+Use
.Xr stty 1
-to enable or disable modem control as required by your setup.
-.Pp
-While testing new cards & resolving card config DIP header &
-.Nm sio flags
-settings, to avoid coms. failure from lack of full modem DC level
-settings on ports,
-you are recommended to temporarily use syntax such as:
-.Nm stty -f /dev/tty03 clocal
-or open
-.Nm /dev/cua03
-if you have bidirectional mode active
-to force serial port to open without
-.Nm O_NONBLOCK
-flag.
+in the normal way on the initial-state devices to program
+initial termios states suitable for your setup.
+.sp
+The lock termios state acts as flags to disable changing
+the termios state. E.g., to lock a flag variable such as
+CRTSCTS, use
+.Nm stty crtscts
+on the lock-state device. Speeds and special characters
+may be locked by setting the corresponding value in the lock-state
+device to any nonzero value.
+.sp
+Correct programs talking to correctly wired external devices
+work with arbitrary initial states and almost no locking,
+but other setups may benefit from changing some of the default
+initial state and locking the state.
+E.g., CRTSCTS should be locked on for devices that support
+RTS/CTS handshaking at all times and off for devices that don't
+support it at all. CLOCAL should be locked on for devices
+that don't support carrier. HUPCL may be locked off if you don't
+want to hang up for reason. In general, very bad things happen
+if something is locked to the wrong state, and things should not
+be locked for devices that support more than one setting. The
+CLOCAL flag on callin ports should be locked off for logins
+to avoid certain security holes, but this needs to be done by
+getty if the callin port is used for anything else.
.Sh FILES
-.Bl -tag -width /dev/tty0? -compact
+.Bl -tag -width /dev/ttyi0? -compact
.It Pa /dev/tty0?
for hardwired terminals
+.It Pa /dev/ttyi0?
+.It Pa /dev/ttyl0?
+corresponding initial-state and lock-state devices
.El
+.sp
or
-.Bl -tag -width /dev/tty0? -compact
+.sp
+.Bl -tag -width /dev/ttyi0? -compact
.It Pa /dev/ttyd?
-for dialin ports (and dialout when bidirectional usage disabled)
+for callin ports
+.It Pa /dev/ttyid?
+.It Pa /dev/ttyld?
+corresponding callin initial-state and lock-state devices
+.sp
.It Pa /dev/cua0?
-for dialout ports when bidirectional usage enabled
+for callout ports
+.It Pa /dev/cuai0?
+.It Pa /dev/cual0?
+corresponding callout initial-state and lock-state devices
+.El
+.sp
+.Bl -tag -width /etc/rc.serial -compact
+.It Pa /etc/rc.serial
+examples of setting the initial-state and lock-state devices
.El
.Pp
-The devices numbers are made from the set [0-9a-z] so that more than
+The devices numbers are made from the set [0-9a-v] so that more than
10 ports can be supported.
/dev/tty0? and /dev/ttyd? are mutually exclusive, if you have
/dev/tty0? corresponding /dev/ttyd? must be removed and vice versa.
.Sh DIAGNOSTICS
.Bl -diag
.It sio%d: silo overflow.
-The single-character input
-.Dq silo
-has overflowed and incoming data has been lost.
-.\".It com%d: weird interrupt: %x.
-.\"The device has generated an unexpected interrupt
-.\"with the code listed.
+Problem in the interrupt handler.
+.El
+.Bl -diag
+.It sio%d: interrupt-level buffer overflow.
+Problem in the bottom half of the driver.
+.El
+.Bl -diag
+.It sio%d: tty-level buffer overflow.
+Problem in the application.
+.sp
+Input has arrived faster than the given module could process it
+and some has been lost.
+.sp
.El
+.Bl -diag
+.It sio%d: reduced fifo trigger level to %d.
+Attempting to avoid further silo overflows.
.Sh SEE ALSO
.Xr tty 4 ,
+.Xr termios 4 ,
.Xr comcontrol 8 ,
.Xr stty 1 .
.Sh HISTORY
@@ -195,12 +299,12 @@ driver is derived from the
driver and is
.Ud
.Sh BUGS
-Data loss is not near as likely on busy systems as they are with the
+Data loss is not nearly as likely on busy systems as it is with the
.Xr com 4
-driver but they still can occur at very high baud rates on slow systems. The
-use of NS16550A's helps lot to handle high baud rates.
+driver but it can still occur at very high baud rates on slow systems.
+The use of NS16550A's reduces system load and helps to avoid data loss.
.Pp
-Stay away from NS16550 (so without the trailing A). These are early
+Stay away from plain NS16550's. These are early
implementations of the chip with non-functional FIFO hardware.
.Pp
The constants which define the locations
@@ -208,12 +312,13 @@ of the various serial ports are holdovers from
.Nm DOS .
As shown, hex addresses can be and for clarity probably should be used instead.
.Pp
-As usual, you get what you pay for; cheap NS16550 clones generally don't work.
-.Pp
-The multiport example is based on an AST/4 card, your
-mileage may vary however. Note that on the AST/4 the card's dipswitches should
+Note that on the AST/4 the card's dipswitches should
.Nm not
-be set to use interrupt sharing. AST/4-like interrupt sharing is only used when
+be set to use interrupt sharing. AST/4-like interrupt sharing is only used when
.Nm multiple
-AST/4 cards are installed in the same system. The sio driver does not
+AST/4 cards are installed in the same system. The sio driver does not
support more than 1 AST/4 on one IRQ.
+.Pp
+Hardwired terminals should not have different device names.
+.Pp
+The examples in the synopsis are too vendor-specific.
diff --git a/share/man/man4/man4.i386/tw.4 b/share/man/man4/man4.i386/tw.4
new file mode 100644
index 000000000000..8c093e58ae53
--- /dev/null
+++ b/share/man/man4/man4.i386/tw.4
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" 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 Eugene W. Stark.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+.\"
+.Th XTEN 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt TW 4
+.Os BSD FreeBSD
+.Sh NAME
+tw \- TW-523 X-10 device driver
+.Sh DESCRIPTION
+.Nm Tw
+is the driver for the TW-523 power line interface, for use with X-10 home
+control products. The X-10 protocol is compatible with a number of home
+control systems, including Radio Shack ``Plug 'n Power(tm)'' and
+Stanley ``Lightmaker(tm).''
+.Pp
+The driver supports
+.Fn read
+.Fn write
+and
+.Fn select
+system calls.
+The driver allows multiple processes to read and write simultaneously,
+but there is probably not much sense in having more than one reader or more
+than one writer at a time, and in fact there may currently be a race
+condition in the driver if two processes try to transmit simultaneously
+(due to unsynchronized access to the sc_pkt structure in tw_sc).
+.Pp
+Transmission is done by calling
+.Fn write
+to send three byte packets of data.
+The first byte contains a four bit house code (0=A to 15=P). The second byte
+contains a five bit unit/key code (0=unit 1 to 15=unit 16, 16=All Units Off
+to 31 = Status Request). The third byte specifies the number of times the
+packet is to be transmitted without any gaps between successive transmissions.
+Normally this is 2, as per the X-10 documentation, but sometimes (e.g. for
+bright and dim codes) it can be another value. Each call to
+.Fn write
+can specify
+an arbitrary number of data bytes, but at most one packet will actually be
+processed in any call. Any incomplete packet is buffered until a subsequent
+call to
+.Fn write
+provides data to complete it. Successive calls to
+.Fn write
+leave a three-cycle gap between transmissions, per the X-10 documentation.
+The driver transmits each bit only once per half cycle, not three times as
+the X-10 documentation states, because the TW523 only provides sync on
+each power line zero crossing. So, the driver will probably not work
+properly if you have three-phase service. Most residences use a two-wire
+system, for which the driver does work.
+.Pp
+Reception is done using
+.Fn read
+The driver produces a series of three
+character packets. In each packet, the first character consists of flags,
+the second character is a four bit house code (0-15), and the third character
+is a five bit key/function code (0-31). The flags are the following:
+.Bl -diag
+.It
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+.It
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+.El
+.Pp
+The
+.Fn select
+system call can be used in the usual way to determine if there
+is data ready for reading.
+.Sh SEE ALSO
+.Bl -diag
+.It
+.Xr xten 1
+.It
+.Xr xtend 8
+.It
+TW-523 documentation from X-10 Inc.
+.El
+.Sh FILES
+.Bl -tag -width /dev/tw
+.It Pa /dev/tw?
+the TW523 special file
+.El
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile
index 4fe2321078c6..7fa200021ba6 100644
--- a/share/man/man5/Makefile
+++ b/share/man/man5/Makefile
@@ -2,10 +2,10 @@
# Clean up and added pcfs, humm should pcfs be a subdir i386?
MAN5= a.out.5 acct.5 core.5 dir.5 disktab.5 \
- fs.5 fstab.5 group.5 hosts.5 networks.5 \
- passwd.5 pcfs.5 phones.5 printcap.5 \
+ fs.5 fstab.5 group.5 hosts.5 \
+ networks.5 passwd.5 pcfs.5 phones.5 printcap.5 \
protocols.5 remote.5 resolver.5 services.5 \
- shells.5 stab.5 types.5 utmp.5
+ shells.5 skey.access.5 stab.5 types.5 utmp.5
MLINKS= fs.5 inode.5 utmp.5 wtmp.5 utmp.5 lastlog.5
diff --git a/share/man/man5/pcfs.5 b/share/man/man5/pcfs.5
index 4fe6b861a08d..bf57205a1f0a 100644
--- a/share/man/man5/pcfs.5
+++ b/share/man/man5/pcfs.5
@@ -1,114 +1,268 @@
-PCFS quirks file
-
-PCFS filesystems on floppy disks only are supported in this release.
-And, only high density floppy disks are supported. This is because
-the floppy disk driver only supports high density disks.
-
+.\" Copyright 1994 Ollivier Robert (roberto@keltia.frmug.fr.net)
+.\" All rights reserved.
+.\"
+.\" Based on previous pcfs.5 found in FreeBSD.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY ME ``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 I 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.
+.\"
+.\" $Id: pcfs.5,v 1.2 1994/06/22 08:55:58 jkh Exp $
+.\""
+.Dd June 21, 1994
+.Dt PCFS 5
+.Os FreeBSD
+.Sh NAME
+.Nm pcfs
+.Nd MS-DOS[TM] compatible filesystem
+.Sh SYNOPSYS
+Add the following statements to your configuration file in /sys/i386/conf/BLOT.
+Or whatever you call your config file.
+.Bd -literal
+.Cd options PCFS
+.Ed
+.Pp
+PCFS consumes approximately 24000 bytes of kernel code space and
+approximately 4000 bytes of bss.
+.Pp
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+filesystem enables you to access of DOS floppy and hard
+disks with UN*X compatible semantics without having to resort to special
+utilities such as
+.Xr mdir 1
+and
+.Xr mcopy 1 .
+.Pp
+The
+.Nm
+filesystem should be considered as
+.Em experimental
+but it seems stable enough. We hope to integrate a better version in latter
+versions of FreeBSD.
+.Pp
+.Sh OPERATIONAL DETAILS
+.Em Floppy disks
+.Pp
+To mount a pcfs filesystem:
+.Bd -literal
+ mount -t pcfs /dev/fd0a /mnt
+.Ed
+.Pp
+To unmount a pcfs filesystem:
+.Bd -literal
+ umount /mnt
+.Ed
+.Pp
+If you want to be sure the fat is
+.Nm ALWAYS
+up to date, mount the filesystem with the synchronous option:
+.Bd -literal
+ mount -t pcfs -o synchronous /dev/fd0a /mnt
+.Ed
+.Pp
+This results in
+.Nm very slow
+file write performance because it turns off write behind of fst disk blocks.
+.Pp
+.Em Hard disks
+.Pp
+You must modify your current disk label (see
+.Xr disklabel 5 )
+to include a reference to your DOS partition.
+.Pp
+Assuming you'll use partition
+.Dq Pa h ,
+the last one, as your MS-DOS partition and that it is at the beginning of
+the disk, you'll end with an entry like that in
+.Em /etc/disktab
+:
+.Bd -literal
+#
+# Seagate ST-31200N
+#
+# a = / 12
+# b = swap 32
+# e = /usr/local 160
+# f = /usr 55
+# g = /spare 597
+# h = /root/dos 150
+#
+st31200n|Seagate ST31200N 1 GB SCSI-2F:\\
+ :dt=SCSI:ty=winchester:\\
+ :nc#1006:ns#32:nt#64:se#512:rm#6300:\\
+ :oa#307200:pa#24576:ta=4.2BSD:ba#8192:fa#1024:\\
+ :ob#331776:pb#65536:tb=swap:\\
+ :oe#397312:pe#327680:te=4.2BSD:be#8192:fe#1024:\\
+ :of#724992:pf#112640:tf=4.2BSD:bf#8192:ff#1024:\\
+ :og#837632:pg#1222656:tg=4.2BSD:bg#8192:fg#1024:\\
+ :oh#32:ph#307168:th=MSDOS:
+.Ed
+.Pp
+The DOS partition begins
+.Em 32
+sectors from the beginning of the disk (the first track of the first
+cylinder is reserved for the partition table and other data). The type of
+the partition (keyword
+.Em th
+) on the last line is set to MS-DOS.
+.Pp
+Run
+.Xr disklabel 8
+to install the new label.
+.Pp
+You must now decide whether you want to mount the partition at boot
+time. If not, you
+.Nm must
+run the following command as
+.Nm root
+when you want to access the partition:
+.Bd -literal
+ mount -t pcfs /dev/sd0h /dos
+.Ed
+.Pp
+(replace /dos by your favorite mount point).
+.Pp
+If you want to mount it at boot time, you must include a statement into
+your
+.Dq Pa /etc/fstab
+file (see
+.Xr fstab 5 )
+like that:
+.Bd -literal
+ /dev/sd0h /root/dos pcfs rw 0 0
+.Ed
+.Pp
+.Sh BUGS
+This is the first release and as such has performance problems.
+Reading large files is very slow because the read ahead code in pcfs_read()
+doesn't read far enough ahead for filesystems with small blocksizes.
+Performance and dos hard disk paritions are the next areas to be
+worked on. Unless someone else does it.
+.Pp
+.Em PCFS quirks
+.Pp
+PCFS filesystems on floppy and hard disks are supported in this
+release. You must add an entry in your disklabel for the DOS partition.
+.Pp
Created files use only the user permissions bits. And of these
only the write bit is meaningful. DOS files always have the
execute and read bits on.
-
+.Pp
PCFS does not turn on or off the DOS archive attribute bit.
-
+.Pp
The timestamp on dos files is updated when ever the file is modified.
There is no inode time or create time stamp.
-
+.Pp
The timestamp placed on a dos file does not have corrections for
daylight savings time included. It does have the correction for
timezone though.
-
+.Pp
Unix times before 1980 will have their year set to 1980 in dos file
-timestamps. This is because dos's idea of time starts in 1980.
-
+timestamps. This is because DOS's idea of time starts in 1980.
+.Pp
PCFS filesystems do not support sparse files. Any attempt to seek
past the end of a file results in the blocks being allocated and
cleared.
-
-When read() is used to examine pcfs directories you will get dos
+.Pp
+When
+.Xr read 2
+is used to examine pcfs directories you will get dos
directory contents. Note that the root directory does not contain
-a "." or ".." entry. Only the readdir() system call simulates these
-entries in the root directory of a dos filesystem. readdir() returns
-directory entries as described in getdirentries(2).
-
-Using read() and write() to manipulate the contents of dos directories
-is unwise on an active dos filesystem since a more up to date copy of
+a "." or ".." entry. Only the
+.Xr readdir 2
+system call simulates these entries in the root directory of a dos
+filesystem.
+.Xr readdir 2
+returns directory entries as described in
+.Xr getdirentries 2 .
+.Pp
+Using
+.Xr read 2
+and
+.Xr write 2
+to manipulate the contents of dos directories
+is unwise on an active DOS filesystem since a more up to date copy of
their contents may reside in data structures in the kernel. It is
probably safe to examine the filename field of dos directory entries.
The filesystem code keeps this up to date at all times.
-
+.Pp
The cluster allocation algorithm is very simplistic. It starts at
cluster 2 and searchs until the last cluster of the filesystem and
takes the first available cluster.
-
-The fsync() system call does not work on file descriptors open on
+.Pp
+The
+.Xr fsync 2
+system call does not work on file descriptors open on
directories. This isn't a terrible thing since very few programs
open directories for writing.
-
-The pcfs filesystem truncates filenames quietly. If a filename has
+.Pp
+The PCFS filesystem truncates filenames quietly. If a filename has
more than 8 characters before the 1st period only the 1st eigth are
used. It only uses the 1st three characters after the period if
-they exist. The filenames "abc" and "abc." are the same to pcfs.
-Filenames that begin with a "." are considered to be dos filenames
-with an extension only and so are limited to 3 characters after the
-leading ".". For example ".imlost" would be seen as ".iml" by pcfs.
-PCFS folds filenames to upper case before writing them to disk or
+they exist. The filenames
+.Dq Pa abc
+and
+.Dq Pa abc.
+are the same to PCFS. Filenames that begin with a "." are considered to be
+dos filenames with an extension only and so are limited to 3 characters
+after the leading ".". For example
+.Dq Pa .imlost
+would be seen as
+.Dq Pa .iml
+by PCFS. PCFS folds filenames to upper case before writing them to disk or
looking up filenames, and folds them to lower case when reading them
-from disk for presentation to the user (for example by readdir()).
-
+from disk for presentation to the user (for example by
+.Xr readdir 2 ).
+.Pp
Directory entries for the DOS filesystem label are quietly ignored.
-
+.Pp
This is probably going to be a problem. This implementation expects
the length of the root directory to be a multiple of the size of
a cluster. If this is not true a warning message is printed when
the filesystem is mounted.
-
+.Pp
PCFS supports DOS filesystems with 12 bit or 16 bit FATs. It supports
both regular and huge filesystems ( > 32 megabytes). It supports
both version 3.3 and 5.0 BPB's. Don't know about version 4.x and
less than 3.3. It has not been tested with 16 bit fats or huge
filesystems. This is because the hard disk drivers need to support
dos partitions to do these things.
-
+.Pp
PCFS does not support symbolic links or hard links. It does not
support quotas. How could it, pcfs files have no owners. PCFS
files have a simulated owner and group of 0. PCFS does not support
file locking. Though it may in the future. PCFS filesystems are
not remote mountable, but they will be in the future.
-
-This is the first release and as such has performance problems.
-Reading large files is very slow because the read ahead code in pcfs_read()
-doesn't read far enough ahead for filesystems with small blocksizes.
-Performance and dos hard disk paritions are the next areas to be
-worked on. Unless someone else does it.
-
-
-Operational Details
--------------------
-
-To mount a pcfs filesystem:
- mount -t pcfs /dev/fd0a /mnt
-
-To unmount a pcfs filesystem:
- umount /mnt
-
-If you want to be sure the fat is ALWAYS up to date, mount the
-filesystem with the synchronous option:
- mount -t pcfs -o synchronous /dev/fd0a /mnt
-This reasults in very slow file write performance because it turns
-off write behind of fst disk blocks.
-
-
-Configuring PCFS into your kernel
----------------------------------
-
-Add the following statements to your configuration file in /sys/i386/conf/BLOT.
-Or whatever you call your config file.
-
- options PCFS
-
-PCFS consumes approximately 24000 bytes of kernel code space and
-approximately 4000 bytes of bss.
-
+.Pp
PCFS has some debug printf's that can be turned on by defining PCFSDEBUG.
It produces lots of output. If you use it be sure to kill syslogd before
using a PCFS filesystem with debug.
+.Sh SEE ALSO
+.Xr disklabel 5 ,
+.Xr disklabel 8 ,
+.Xr fstab 5 ,
+.Xr mount 8 .
+.Sh HISTORY
+A
+.Nm
+filesystem first appeared in 386BSD 0.1, patchkit 0.2.3.
diff --git a/share/man/man5/skey.access.5 b/share/man/man5/skey.access.5
new file mode 100644
index 000000000000..08924376da12
--- /dev/null
+++ b/share/man/man5/skey.access.5
@@ -0,0 +1,34 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt SKEY.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm skey.access
+.Nd List of S/Key obligated host adresses
+.Sh DESCRIPTION
+The
+.Nm skey.access
+file contains a number of lines specifying host IP adresses
+for which the use of S/Key passwords is obligated.
+.Pp
+The first word of each line says if UNIX passwords are
+to be permitted or denied. When denied, only S/Key passwords
+are allowed.
+The remainder of the rule is a networknumber and mask. A rule matches a
+host if any of its addresses satisfies:
+ network = (address & mask)
+.Sh FILES
+.Bl -tag -width /etc/skey.access -compact
+.It Pa /etc/skey.access
+The
+.Nm skey.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr skey 1 ,
+.Xr keyinit 1 ,
+.Xr key 1 ,
+.Xr keyinfo 1
+.Sh AUTHOR
+Guido van Rooij
diff --git a/share/man/man7/mdoc.7 b/share/man/man7/mdoc.7
new file mode 100644
index 000000000000..44028651237e
--- /dev/null
+++ b/share/man/man7/mdoc.7
@@ -0,0 +1,409 @@
+.\" Copyright (c) 1991 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.
+.\"
+.\" @(#)mdoc.7 5.1 (Berkeley) 2/19/92
+.\"
+.Dd February 19, 1992
+.Os
+.Dt MDOC 7
+.Sh NAME
+.Nm mdoc
+.Nd quick reference guide for the
+.Nm \-mdoc
+macro package
+.Sh SYNOPSIS
+.Nm groff
+.Fl m Ns Ar doc
+.Ar files ...
+.Sh DESCRIPTION
+The
+.Nm \-mdoc
+package is a set of content-based and domain-based macros
+used to format the
+.Bx
+man pages.
+The macro names and their meanings are
+listed below for quick reference; for
+a detailed explanation on using the package,
+see the tutorial sampler
+.Xr mdoc.samples 7 .
+.Pp
+The macros are described in two groups, the first
+includes the structural and physical page layout macros.
+The second contains the manual and general text domain
+macros which differentiate the
+.Nm -\mdoc
+package from other
+.Xr troff
+formatting packages.
+.Sh PAGE STRUCTURE DOMAIN
+.Ss Title Macros
+To create a valid manual page, these three macros, in this order,
+are required:
+.Bl -tag -width "xxxx.Os OPERATINGxSYSTEM [version/release]" -compact
+.It Li "\&.Dd " Ar "Month day, year"
+Document date.
+.It Li "\&.Dt " Ar "DOCUMENT_TITLE [section] [volume]"
+Title, in upper case.
+.It Li "\&.Os " Ar "OPERATING_SYSTEM [version/release]"
+Operating system
+.Pq Tn BSD .
+.El
+.Ss Page Layout Macros
+Section headers, paragraph breaks, lists and displays.
+.Bl -tag -width flag -compact
+.It Li \&.Sh
+Section Headers.
+Valid headers, in the order of presentation:
+.Bl -tag -width "RETURN VALUES" -compact
+.It Ar NAME
+Name section, should include the
+.Ql \&.Nm
+or
+.Ql \&.Fn
+and the
+.Ql \&.Nd
+macros.
+.It Ar SYNOPSIS
+Usage.
+.It Ar DESCRIPTION
+General description, should include
+options and parameters.
+.It Ar RETURN VALUES
+Sections two and three function calls.
+.It Ar ENVIRONMENT
+Describe environment variables.
+.It Ar FILES
+Files associated with the subject.
+.It Ar EXAMPLES
+Examples and suggestions.
+.It Ar DIAGNOSTICS
+Normally used for section four device interface diagnostics.
+.It Ar ERRORS
+Sections two and three error and signal
+handling.
+.It Ar SEE ALSO
+Cross references and citations.
+.It Ar STANDARDS
+Conformance to standards if applicable.
+.It Ar HISTORY
+If a standard is not applicable, the history
+of the subject should be given.
+.It Ar BUGS
+Gotchas and caveats.
+.It Ar other
+Customized headers may be added at
+the authors discretion.
+.El
+.It Li \&.Ss
+Subsection Headers.
+.It Li \&.Pp
+Paragraph Break.
+Vertical space (one line).
+.It Li \&.D1
+(D-one) Display-one
+Indent and display one text line.
+.It Li \&.Dl
+(D-ell) Display-one literal.
+Indent and display one line of literal text.
+.It Li \&.Bd
+Begin-display block.
+Display options:
+.Bl -tag -width "xoffset string " -compact
+.It Fl ragged
+Unjustified (ragged edges).
+.It Fl filled
+Justified.
+.It Fl literal
+Literal text or code.
+.It Fl file Ar name
+Read in named
+.Ar file
+and display.
+.It Fl offset Ar string
+Offset display.
+Acceptable
+.Ar string
+values:
+.Bl -tag -width indent-two -compact
+.It Ar left
+Align block on left (default).
+.It Ar center
+Approximate center margin.
+.It Ar indent
+Six constant width spaces (a tab).
+.It Ar indent-two
+Two tabs.
+.It Ar right
+Left aligns block 2 inches from
+right.
+.It Ar xx Ns Cm n
+Where
+.Ar xx
+is a number from
+.No \&4 Ns Cm n
+to
+.No \&9\&9 Ns Cm n .
+.It Ar Aa
+Where
+.Ar Aa
+is a callable macro name.
+.It Ar string
+The width of
+.Ar string
+is used.
+.El
+.El
+.It Li \&.Ed
+End-display (matches \&.Bd).
+.It Li \&.Bl
+Begin-list.
+Create lists or columns. Options:
+.Bl -tag -width flag -compact
+.It Ar List-types
+.Bl -column xbullet -compact
+.It Fl bullet Ta "Bullet Item List"
+.It Fl item Ta "Unlabeled List"
+.It Fl enum Ta "Enumerated List"
+.It Fl tag Ta "Tag Labeled List"
+.It Fl diag Ta "Diagnostic List"
+.It Fl hang Ta "Hanging Labeled List"
+.It Fl ohang Ta "Overhanging Labeled List"
+.It Fl inset Ta "Inset or Run-on Labeled List"
+.El
+.It List-parameters
+.Bl -tag -width "xcompact " -compact
+.It Fl offset
+(All lists.) See
+.Ql \&.Bd
+begin-display above.
+.It Fl width
+.Pf ( Fl tag
+and
+.Fl hang
+lists only.)
+See
+.Ql \&.Bd .
+.It Fl compact
+(All lists.)
+Suppresses blank lines.
+.El
+.El
+.It Li \&.El
+End-list.
+.It Li \&.It
+List item.
+.El
+.Sh MANUAL AND GENERAL TEXT DOMAIN MACROS
+The manual and general text domain macros are special in that
+most of them are parsed for callable macros
+for example:
+.Bl -tag -width ".Op Fl s Ar filex" -offset indent
+.It Li "\&.Op Fl s Ar file"
+Produces
+.Op Fl s Ar file
+.El
+.Pp
+In this example, the option enclosure macro
+.Ql \&.Op
+is parsed, and calls the callable content macro
+.Ql \&Fl
+which operates on the argument
+.Ql s
+and then calls the callable content macro
+.Ql \&Ar
+which operates on the argument
+.Ql file .
+Some macros may be callable, but are not parsed and vice versa.
+These macros are indicated in the
+.Em parsed
+and
+.Em callable
+columns below.
+.Pp
+Unless stated, manual domain macros share a common syntax:
+.Pp
+.Dl \&.Va argument [\ .\ ,\ ;\ :\ (\ )\ [\ ]\ argument \...\ ]
+.Pp
+.Sy Note :
+Opening and closing
+punctuation characters are only recognized as such if they are presented
+one at a time.
+The string
+.Ql "),"
+is not recognized as punctuation and will be output with a leading white
+space and in what ever font the calling macro uses.
+The
+the argument list
+.Ql "] ) ,"
+is recognized as three sequential closing punctuation characters
+and a leading white space is not output between the characters
+and the previous argument (if any).
+The special meaning of a punctuation character may be escaped
+with the string
+.Ql \e& .
+For example the following string,
+.Bl -tag -width "&.Ar file1\ , file2\ , file3\ )\ ." -offset indent
+.It Li "\&.Ar file1\ , file2\ , file3\ )\ ."
+Produces
+.Ar file1 , file2 , file3 ) .
+.El
+.ne 5
+.Ss Manual Domain Macros
+.Bl -column "Name" "Parsed" Callable" -compact
+.It Em Name Parsed Callable Description
+.It Li \&Ad Ta Yes Ta Yes Ta Address. "(This macro may be deprecated.)"
+.It Li \&Ar Ta Yes Ta Yes Ta "Command line argument."
+.It Li \&Cd Ta \&No Ta \&No Ta "Configuration declaration (section four only)."
+.It Li \&Cm Ta Yes Ta Yes Ta "Command line argument modifier."
+.It Li \&Dv Ta Yes Ta Yes Ta "Defined variable (source code)."
+.It Li \&Er Ta Yes Ta Yes Ta "Error number (source code)."
+.It Li \&Ev Ta Yes Ta Yes Ta "Environment variable."
+.It Li \&Fa Ta Yes Ta Yes Ta "Function argument."
+.It Li \&Fd Ta Yes Ta Yes Ta "Function declaration."
+.It Li \&Fn Ta Yes Ta Yes Ta "Function call (also .Fo and .Fc)."
+.It Li \&Ic Ta Yes Ta Yes Ta "Interactive command."
+.It Li \&Li Ta Yes Ta Yes Ta "Literal text."
+.It Li \&Nm Ta Yes Ta Yes Ta "Command name."
+.It Li \&Op Ta Yes Ta Yes Ta "Option (also .Oo and .Oc)."
+.It Li \&Ot Ta Yes Ta Yes Ta "Old style function type (Fortran only)."
+.It Li \&Pa Ta Yes Ta Yes Ta "Pathname or file name."
+.It Li \&St Ta Yes Ta Yes Ta "Standards (-p1003.2, -p1003.1 or -ansiC)"
+.It Li \&Va Ta Yes Ta Yes Ta "Variable name."
+.It Li \&Vt Ta Yes Ta Yes Ta "Variable type (Fortran only)."
+.It Li \&Xr Ta Yes Ta Yes Ta "Manual Page Cross Reference."
+.El
+.Ss General Text Domain Macros
+.Bl -column "Name" "Parsed" Callable" -compact
+.It Em "Name Parsed Callable Description"
+.It Li \&%A Ta Yes Ta \&No Ta "Reference author."
+.It Li \&%B Ta Yes Ta Yes Ta "Reference book title."
+.It Li \&%\&C Ta \&No Ta \&No Ta "Reference place of publishing (city)."
+.It Li \&%\&D Ta \&No Ta \&No Ta "Reference date."
+.It Li \&%J Ta Yes Ta Yes Ta "Reference journal title."
+.It Li \&%N Ta \&No Ta \&No Ta "Reference issue number."
+.It Li \&%\&O Ta \&No Ta \&No Ta "Reference optional information."
+.It Li \&%P Ta \&No Ta \&No Ta "Reference page number(s)."
+.It Li \&%R Ta \&No Ta \&No Ta "Reference report Name."
+.It Li \&%T Ta Yes Ta Yes Ta "Reference article title."
+.It Li \&%V Ta \&No Ta \&No Ta "Reference volume."
+.It Li \&Ac Ta Yes Ta Yes Ta "Angle close quote."
+.It Li \&Ao Ta Yes Ta Yes Ta "Angle open quote."
+.It Li \&Aq Ta Yes Ta Yes Ta "Angle quote."
+.It Li \&At Ta \&No Ta \&No Ta Tn "AT&T UNIX"
+.It Li \&Bc Ta Yes Ta Yes Ta "Bracket close quote."
+.It Li \&Bf Ta \&No Ta \&No Ta "Begin font mode."
+.It Li \&Bo Ta Yes Ta Yes Ta "Bracket open quote."
+.It Li \&Bq Ta Yes Ta Yes Ta "Bracket quote."
+.It Li \&Bx Ta Yes Ta Yes Ta Bx .
+.It Li \&Db Ta \&No Ta \&No Ta "Debug (default is \\*qoff\\*q)"
+.It Li \&Dc Ta Yes Ta Yes Ta "Double close quote."
+.It Li \&Do Ta Yes Ta Yes Ta "Double open quote."
+.It Li \&Dq Ta Yes Ta Yes Ta "Double quote."
+.It Li \&Ec Ta Yes Ta Yes Ta "Enclose string close quote."
+.It Li \&Ef Ta \&No Ta \&No Ta "End font mode."
+.It Li \&Em Ta Yes Ta Yes Ta "Emphasis (traditional English)."
+.It Li \&Eo Ta Yes Ta Yes Ta "Enclose string open quote."
+.It Li \&No Ta Yes Ta Yes Ta "Normal text (no-op)."
+.It Li \&Ns Ta Yes Ta Yes Ta "No space."
+.It Li \&Pc Ta Yes Ta Yes Ta "Parenthesis close quote."
+.It Li \&Pf Ta Yes Ta \&No Ta "Prefix string."
+.It Li \&Po Ta Yes Ta Yes Ta "Parenthesis open quote."
+.It Li \&Pq Ta Yes Ta Yes Ta "Parentheses quote."
+.It Li \&Qc Ta Yes Ta Yes Ta "Strait Double close quote."
+.It Li \&Ql Ta Yes Ta Yes Ta "Quoted literal."
+.It Li \&Qo Ta Yes Ta Yes Ta "Strait Double open quote."
+.It Li \&Qq Ta Yes Ta Yes Ta "Strait Double quote."
+.It Li \&Re Ta \&No Ta \&No Ta "Reference start."
+.It Li \&Rs Ta \&No Ta \&No Ta "Reference start."
+.It Li \&Sc Ta Yes Ta Yes Ta "Single close quote."
+.It Li \&So Ta Yes Ta Yes Ta "Single open quote."
+.It Li \&Sq Ta Yes Ta Yes Ta "Single quote."
+.It Li \&Sm Ta \&No Ta \&No Ta "Space mode (default is \\*qon\\*q)"
+.It Li \&Sx Ta Yes Ta Yes Ta "Section Cross Reference."
+.It Li \&Sy Ta Yes Ta Yes Ta "Symbolic (traditional English)."
+.It Li \&Tn Ta Yes Ta Yes Ta "Trade or type name (small Caps)."
+.It Li \&Ux Ta Yes Ta Yes Ta Ux
+.It Li \&Xc Ta Yes Ta Yes Ta "Extend argument list close."
+.It Li \&Xo Ta Yes Ta Yes Ta "Extend argument list close."
+.El
+.\" .It Sy \&Hf Ta \&No Ta \&No Ta "Include file with header"
+.Pp
+Macro names ending in
+.Ql q
+quote remaining items on the argument list.
+Macro names ending in
+.Ql o
+begin a quote which may span more than one line of input and
+are close quoted with the matching macro name ending in
+.Ql c .
+Enclosure macros may be nested and are limited to
+eight arguments.
+.Pp
+Note: the extended argument list macros
+.Pf ( Ql \&.Xo ,
+.Ql \&.Xc )
+and the function enclosure macros
+.Pf ( Ql \&.Fo ,
+.Ql \&.Fc )
+are irregular.
+The extended list macros are used when the number of macro arguments
+would exceed the
+.Xr troff
+limitation of nine arguments.
+.Sh CONFIGURATION
+For site specific configuration of the macro package,
+see the file
+.Pa /usr/src/share/tmac/README .
+.Sh FILES
+.Bl -tag -width "tmac.doc-ditroff" -compact
+.It Pa tmac.doc
+Manual and general text domain macros.
+.It Pa tmac.doc-common
+Common structural macros and definitions.
+.It Pa tmac.doc-nroff
+Site dependent
+.Xr nroff
+style file.
+.It Pa tmac.doc-ditroff
+Site dependent
+.Xr troff
+style file.
+.It Pa tmac.doc-syms
+Special defines (such as the standards macro).
+.El
+.Sh SEE ALSO
+.Xr mdoc.samples 7
+.Sh HISTORY
+The
+.Nm \-mdoc
+macro package is
+.Ud .
diff --git a/share/man/man8/adduser.8 b/share/man/man8/adduser.8
index f6dde2d200b4..519c65df3e6d 100644
--- a/share/man/man8/adduser.8
+++ b/share/man/man8/adduser.8
@@ -38,6 +38,9 @@
.Nm adduser
.Nd procedure for adding new users
.Sh DESCRIPTION
+This is a proceduce for adding now users, not a command. Read the
+descriptions below and follow the steps.
+.Pp
A new user must choose a login name, which must not already appear in
.Pa /etc/passwd
or
@@ -66,13 +69,24 @@ A skeletal account for a new user
\*(lqernie\*(rq
might look like:
.Bd -literal
-ernie::25:30::0:0:Ernie Kovacs,508 Evans Hall,x7925,
+ernie:*:25:30::0:0:Ernie Kovacs,508 Evans Hall,x7925,
642-8202:/a/users/ernie:/bin/csh
.Ed
.Pp
For a description of each of these fields, see
.Xr passwd 5 .
.Pp
+Use the
+.Xr passwd 1
+command to give the user an initial password. You can type
+.Bd -literal
+passwd ernie
+.Ed
+.Pp
+as root to give ernie a password. Remember, the password field (the *
+in the above example) holds the encrypted password, so
+writing the password there in plain text will not work.
+.Pp
It is useful to give new users some help in getting started, supplying
them with a few skeletal files such as
.Pa \&.profile
diff --git a/share/me/footnote.me b/share/me/footnote.me
index 02c0b2dc3ece..b1b6f25a42d8 100644
--- a/share/me/footnote.me
+++ b/share/me/footnote.me
@@ -90,7 +90,7 @@
\{\
. if \\n* \
. nr $f +1
-. ds * \\*[\\n($f\\*]\k*
+. ds * \\*\[\\n($f\\*\]\k*
. rr *
. in 0
. da
diff --git a/share/me/me.7 b/share/me/me.7
index a9ec5bc9a39e..6ad45fb26fab 100644
--- a/share/me/me.7
+++ b/share/me/me.7
@@ -111,40 +111,40 @@ for interesting details.
.br
.di
.in \nau
-.ti0
+.ti 0
Request Initial Cause Explanation
-.ti0
+.ti 0
Value Break
.br
.in \nau
-.ti0
+.ti 0
\&.(c - yes Begin centered block
-.ti0
+.ti 0
\&.(d - no Begin delayed text
-.ti0
+.ti 0
\&.(f - no Begin footnote
-.ti0
+.ti 0
\&.(l - yes Begin list
-.ti0
+.ti 0
\&.(q - yes Begin major quote
-.ti0
+.ti 0
\&.(x \fIx\fR - no Begin indexed item in index
.I x
-.ti0
+.ti 0
\&.(z - no Begin floating keep
-.ti0
+.ti 0
\&.)c - yes End centered block
-.ti0
+.ti 0
\&.)d - yes End delayed text
-.ti0
+.ti 0
\&.)f - yes End footnote
-.ti0
+.ti 0
\&.)l - yes End list
-.ti0
+.ti 0
\&.)q - yes End major quote
-.ti0
+.ti 0
\&.)x - yes End index item
-.ti0
+.ti 0
\&.)z - yes End floating keep
.ti 0
\&.++ \fIm H\fR - no Define paper section.
@@ -168,17 +168,17 @@ or
set by .++).
.I T
is the chapter title.
-.ti0
+.ti 0
\&.1c 1 yes One column format on a new page.
-.ti0
+.ti 0
\&.2c 1 yes Two column format.
-.ti0
+.ti 0
\&.EN - yes Space after equation
produced by
.I eqn
or
.IR neqn .
-.ti0
+.ti 0
\&.EQ \fIx y\fR - yes Precede equation; break out and
add space.
Equation number is
@@ -191,19 +191,19 @@ to indent equation (default),
to left-adjust the equation, or
.I C
to center the equation.
-.ti0
+.ti 0
\&.GE - yes End \fIgremlin\fP picture.
-.ti0
+.ti 0
\&.GS - yes Begin \fIgremlin\fP picture.
-.ti0
+.ti 0
\&.PE - yes End \fIpic\fP picture.
-.ti0
+.ti 0
\&.PS - yes Begin \fIpic\fP picture.
-.ti0
+.ti 0
\&.TE - yes End table.
-.ti0
+.ti 0
\&.TH - yes End heading section of table.
-.ti0
+.ti 0
\&.TS \fIx\fR - yes Begin table; if \fIx\fR is
.I H
table has repeated heading.
@@ -214,7 +214,7 @@ is the Author's name(s),
.I N
is the total number of pages.
Must be given before the first initialization.
-.ti0
+.ti 0
\&.b \fIx\fR no no Print
.I x
in boldface; if no argument switch to boldface.
@@ -223,15 +223,15 @@ in boldface; if no argument switch to boldface.
.I n.
This indent is used to set the indent on regular text
(like paragraphs).
-.ti0
+.ti 0
\&.bc no yes Begin new column
-.ti0
+.ti 0
\&.bi \fIx\fR no no Print
.I x
in bold italics (nofill only)
-.ti0
+.ti 0
\&.bu - yes Begin bulleted paragraph
-.ti0
+.ti 0
\&.bx \fIx\fR no no Print \fIx\fR in a box (nofill only).
.ti 0
\&.ef \fI\'x\'y\'z\'\fR \'\'\'\' no Set even footer to x y z
@@ -241,31 +241,31 @@ in bold italics (nofill only)
\&.fo \fI\'x\'y\'z\'\fR \'\'\'\' no Set footer to x y z
.ti 0
\&.hx - no Suppress headers and footers on next page.
-.ti0
+.ti 0
\&.he \fI\'x\'y\'z\'\fR \'\'\'\' no Set header to x y z
-.ti0
+.ti 0
\&.hl - yes Draw a horizontal line
-.ti0
+.ti 0
\&.i \fIx\fR no no Italicize
.I x;
if
.I x
missing, italic text follows.
-.ti0
+.ti 0
\&.ip \fIx y\fR no yes Start indented paragraph,
with hanging tag
.IR x .
Indentation is
.I y
ens (default 5).
-.ti0
+.ti 0
\&.lp yes yes Start left-blocked paragraph.
.ti 0
\&.lo - no Read in a file of local macros of the
form
.BI \&.* x.
Must be given before initialization.
-.ti0
+.ti 0
\&.np 1 yes Start numbered paragraph.
.ti 0
\&.of \fI\'x\'y\'z\'\fR \'\'\'\' no Set odd footer to x y z
@@ -273,10 +273,10 @@ Must be given before initialization.
\&.oh \fI\'x\'y\'z\'\fR \'\'\'\' no Set odd header to x y z
.ti 0
\&.pd - yes Print delayed text.
-.ti0
+.ti 0
\&.pp no yes Begin paragraph.
First line indented.
-.ti0
+.ti 0
\&.r yes no Roman text follows.
.ti 0
\&.re - no Reset tabs to default values.
@@ -284,7 +284,7 @@ First line indented.
\&.sc no no Read in a file of special characters
and diacritical marks.
Must be given before initialization.
-.ti0
+.ti 0
\&.sh \fIn x\fR - yes Section head follows,
font automatically bold.
.I n
@@ -294,7 +294,7 @@ is title of section.
.ti 0
\&.sk no no Leave the next page blank.
Only one page is remembered ahead.
-.ti0
+.ti 0
\&.sm \fIx\fR - no Set
.I x
in a smaller pointsize.
@@ -307,11 +307,11 @@ points.
Must be given before initialization.
.ti 0
\&.tp no yes Begin title page.
-.ti0
+.ti 0
\&.u \fIx\fR - no Underline argument (even in \fItroff\fR).
(Nofill only).
-.ti0
+.ti 0
\&.uh - yes Like .sh but unnumbered.
-.ti0
+.ti 0
\&.xp \fIx\fR - no Print index
.I x.
diff --git a/share/me/tmac.e b/share/me/tmac.e
index f703c0ae0f2f..dd5f5f6d8e5e 100644
--- a/share/me/tmac.e
+++ b/share/me/tmac.e
@@ -959,7 +959,7 @@
.\}
.nr ?C 1
.nr $f 1 1
-.ds * \\*[1\\*]\k*
+.ds * \\*\[1\\*\]\k*
.if \\n(?R \
. pn 1
.bp
@@ -1170,7 +1170,7 @@
.nr _L \n(.lu \" line length of page
.nr $c 1 \" current column number
.nr $f 1 1 \" footnote number
-.ds * \*[1\*]\k*\" \" footnote "name"
+.ds * \*\[1\*\]\k*\" \" footnote "name"
.nr $d 1 1 \" delayed text number
.ds # [1]\k#\" \" delayed text "name"
.nr _M 1 \" chapter mode is chapter
diff --git a/share/mk/bsd.dep.mk b/share/mk/bsd.dep.mk
index 3663abd22361..b75b9466cabd 100644
--- a/share/mk/bsd.dep.mk
+++ b/share/mk/bsd.dep.mk
@@ -1,4 +1,4 @@
-# $Id: bsd.dep.mk,v 1.3.2.1 1994/03/07 01:53:47 rgrimes Exp $
+# $Id: bsd.dep.mk,v 1.4 1994/02/27 19:28:44 nate Exp $
# some of the rules involve .h sources, so remove them from mkdep line
.if !target(depend)
diff --git a/share/mk/bsd.doc.mk b/share/mk/bsd.doc.mk
index 8d64918ddc74..7df1d71882ca 100644
--- a/share/mk/bsd.doc.mk
+++ b/share/mk/bsd.doc.mk
@@ -1,5 +1,5 @@
# from: @(#)bsd.doc.mk 5.3 (Berkeley) 1/2/91
-# $Id: bsd.doc.mk,v 1.6 1994/02/03 19:58:23 jkh Exp $
+# $Id: bsd.doc.mk,v 1.7 1994/04/19 17:15:55 jkh Exp $
PRINTER?= ps
@@ -8,6 +8,7 @@ EQN?= eqn -T${PRINTER}
GREMLIN?= grn
GRIND?= vgrind -f
INDXBIB?= indxbib
+INSTALL?= install
PIC?= pic
REFER?= refer
ROFF?= groff -T${PRINTER} ${MACROS} -o${PAGES}
@@ -72,7 +73,7 @@ install:
else \
true ; \
fi
- install ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 ${DOC}.* \
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 ${DOC}.* \
${DESTDIR}${BINDIR}/${VOLUME}
spell: ${SRCS}
diff --git a/share/mk/bsd.lib.mk b/share/mk/bsd.lib.mk
index 313b52e72d9a..3667b73d0495 100644
--- a/share/mk/bsd.lib.mk
+++ b/share/mk/bsd.lib.mk
@@ -1,5 +1,5 @@
# from: @(#)bsd.lib.mk 5.26 (Berkeley) 5/2/91
-# $Id: bsd.lib.mk,v 1.30 1994/02/09 16:23:21 ache Exp $
+# $Id: bsd.lib.mk,v 1.39 1994/06/15 10:14:40 ache Exp $
#
.if exists(${.CURDIR}/../Makefile.inc)
@@ -11,7 +11,11 @@ SHLIB_MAJOR != . ${.CURDIR}/shlib_version ; echo $$major
SHLIB_MINOR != . ${.CURDIR}/shlib_version ; echo $$minor
.endif
-
+.if defined(DESTDIR)
+CFLAGS+= -I${DESTDIR}/usr/include
+CXXINCLUDES+= -I${DESTDIR}/usr/include/${CXX}
+.endif
+INSTALL?= install
LIBDIR?= /usr/lib
LINTLIBDIR?= /usr/libdata/lint
LIBGRP?= bin
@@ -144,13 +148,21 @@ lib${LIB}_p.a:: ${POBJS}
@${AR} cTq lib${LIB}_p.a `lorder ${POBJS} | tsort` ${LDADD}
${RANLIB} lib${LIB}_p.a
+.if defined(DESTDIR)
+LDDESTDIR?= -L${DESTDIR}/usr/lib
+.endif
+
+.if defined(CPLUSPLUSLIB) && !make(clean) && !make(cleandir)
+SOBJS+= ${DESTDIR}/usr/lib/c++rt0.o
+.endif
+
SOBJS+= ${OBJS:.o=.so}
lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}: ${SOBJS}
@echo building shared ${LIB} library \(version ${SHLIB_MAJOR}.${SHLIB_MINOR}\)
@rm -f lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}
@$(LD) -Bshareable \
-o lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} \
- ${SOBJS} ${LDADD}
+ ${SOBJS} ${LDDESTDIR} ${LDADD} ${SHARED_LDADD}
lib${LIB}_pic.a:: ${SOBJS}
@echo building special pic ${LIB} library
@@ -194,21 +206,21 @@ beforeinstall:
.endif
realinstall: beforeinstall
- install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} lib${LIB}.a \
+ ${INSTALL} ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} lib${LIB}.a \
${DESTDIR}${LIBDIR}
${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}.a
.if !defined(NOPROFILE)
- install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${INSTALL} ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
lib${LIB}_p.a ${DESTDIR}${LIBDIR}
${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_p.a
.endif
.if !defined(NOPIC)
.if defined(SHLIB_MAJOR) && defined(SHLIB_MINOR)
- install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${INSTALL} ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} ${DESTDIR}${LIBDIR}
.endif
.if defined(INSTALL_PIC_ARCHIVE)
- install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${INSTALL} ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
lib${LIB}_pic.a ${DESTDIR}${LIBDIR}
${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_pic.a
.endif
diff --git a/share/mk/bsd.man.mk b/share/mk/bsd.man.mk
index dd5aee25e345..7836d0399948 100644
--- a/share/mk/bsd.man.mk
+++ b/share/mk/bsd.man.mk
@@ -1,19 +1,32 @@
# from: @(#)bsd.man.mk 5.2 (Berkeley) 5/11/90
-# $Id: bsd.man.mk,v 1.4 1994/01/31 06:10:33 rgrimes Exp $
+# $Id: bsd.man.mk,v 1.6 1994/06/05 20:42:39 csgr Exp $
.if exists(${.CURDIR}/../Makefile.inc)
.include "${.CURDIR}/../Makefile.inc"
.endif
+INSTALL?= install
MANGRP?= bin
MANOWN?= bin
MANMODE?= 444
MANDIR?= /usr/share/man/man
MANSRC?= ${.CURDIR}
-MINSTALL= install ${COPY} -o ${MANOWN} -g ${MANGRP} -m ${MANMODE}
+MINSTALL= ${INSTALL} ${COPY} -o ${MANOWN} -g ${MANGRP} -m ${MANMODE}
-maninstall:
+MCOMPRESS= gzip -f
+BASENAME= basename
+ZEXTENSION= .gz
+.if !defined(NOMANCOMPRESS)
+ZEXT= ${ZEXTENSION}
+.else
+ZEXT=
+.endif
+
+MANALL= ${MAN1} ${MAN2} ${MAN3} ${MAN3F} ${MAN4} ${MAN5} \
+ ${MAN6} ${MAN7} ${MAN8}
+
+maninstall: ${MANDEPEND}
.if defined(MAN1) && !empty(MAN1)
(cd ${MANSRC}; ${MINSTALL} ${MAN1} ${DESTDIR}${MANDIR}1${MANSUBDIR})
.endif
@@ -41,6 +54,33 @@ maninstall:
.if defined(MAN8) && !empty(MAN8)
(cd ${MANSRC}; ${MINSTALL} ${MAN8} ${DESTDIR}${MANDIR}8${MANSUBDIR})
.endif
+
+# by default all pages are compressed
+# we don't handle .so's yet
+.if !empty(MANALL:S/ //g)
+.if !defined(NOMANCOMPRESS)
+ @set ${MANALL} ; \
+ while test $$# -ge 1; do \
+ name=`${BASENAME} $$1`; \
+ sect=`expr $$name : '.*\.\([^.]*\)'`; \
+ echo "compressing in" \
+ "${DESTDIR}${MANDIR}$${sect}${MANSUBDIR}:" \
+ "$$name -> $${name}${ZEXT}"; \
+ ${MCOMPRESS} ${DESTDIR}${MANDIR}$${sect}${MANSUBDIR}/$$name ; \
+ shift ; \
+ done ; true
+.else
+# we are installing uncompressed pages, so nuke any compressed pages
+ @set ${MANALL} ; \
+ while test $$# -ge 1; do \
+ name=`${BASENAME} $$1`; \
+ sect=`expr $$name : '.*\.\([^.]*\)'`; \
+ rm -f ${DESTDIR}${MANDIR}$${sect}${MANSUBDIR}/$$name${ZEXTENSION};\
+ shift ; \
+ done ; true
+.endif
+.endif
+
.if defined(MLINKS) && !empty(MLINKS)
@set ${MLINKS}; \
while test $$# -ge 2; do \
@@ -54,8 +94,9 @@ maninstall:
sect=`expr $$name : '.*\.\([^.]*\)'`; \
dir=${DESTDIR}${MANDIR}$$sect; \
t=$${dir}${MANSUBDIR}/$$name; \
- echo $$t -\> $$l; \
- rm -f $$t; \
- ln $$l $$t; \
+ echo $${t}${ZEXT} -\> $${l}${ZEXT}; \
+ rm -f $${t}${ZEXTENSION}; \
+ rm -f $${t}; \
+ ln $${l}${ZEXT} $${t}${ZEXT}; \
done; true
.endif
diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk
index fb7a348c4633..dc17f18f6785 100644
--- a/share/mk/bsd.own.mk
+++ b/share/mk/bsd.own.mk
@@ -1,4 +1,4 @@
-# $Id: bsd.own.mk,v 1.3 1994/01/31 06:10:35 rgrimes Exp $
+# $Id: bsd.own.mk,v 1.5 1994/03/19 22:02:35 jkh Exp $
BINGRP?= bin
BINOWN?= bin
diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk
index 80ab11fcf589..8a24d4d52ec8 100644
--- a/share/mk/bsd.prog.mk
+++ b/share/mk/bsd.prog.mk
@@ -1,5 +1,5 @@
# from: @(#)bsd.prog.mk 5.26 (Berkeley) 6/25/91
-# $Id: bsd.prog.mk,v 1.18 1994/01/31 06:10:37 rgrimes Exp $
+# $Id: bsd.prog.mk,v 1.28 1994/06/15 10:14:41 ache Exp $
.if exists(${.CURDIR}/../Makefile.inc)
.include "${.CURDIR}/../Makefile.inc"
@@ -8,6 +8,10 @@
.SUFFIXES: .out .o .c .cc .cxx .C .y .l .s .S
CFLAGS+=${COPTS}
+.if defined(DESTDIR)
+CFLAGS+= -I${DESTDIR}/usr/include
+CXXINCLUDES+= -I${DESTDIR}/usr/include/${CXX}
+.endif
STRIP?= -s
@@ -15,6 +19,8 @@ BINGRP?= bin
BINOWN?= bin
BINMODE?= 555
+INSTALL?= install
+.if !defined(DESTDIR)
LIBCRT0?= /usr/lib/crt0.o
LIBC?= /usr/lib/libc.a
LIBCOMPAT?= /usr/lib/libcompat.a
@@ -31,12 +37,38 @@ LIBM?= /usr/lib/libm.a
LIBMP?= /usr/lib/libmp.a
LIBPC?= /usr/lib/libpc.a
LIBPLOT?= /usr/lib/libplot.a
+LIBREADLINE?= /usr/lib/libreadline.a
LIBRESOLV?= /usr/lib/libresolv.a
LIBRPCSVC?= /usr/lib/librpcsvc.a
+LIBSKEY?= /usr/lib/libskey.a
LIBTELNET?= /usr/lib/libtelnet.a
-LIBTERM?= /usr/lib/libterm.a
+LIBTERM?= /usr/lib/libtermcap.a
LIBUTIL?= /usr/lib/libutil.a
-
+.else
+LIBCRT0?= ${DESTDIR}/usr/lib/crt0.o
+LIBC?= ${DESTDIR}/usr/lib/libc.a
+LIBCOMPAT?= ${DESTDIR}/usr/lib/libcompat.a
+LIBCRYPT?= ${DESTDIR}/usr/lib/libcrypt.a
+LIBCURSES?= ${DESTDIR}/usr/lib/libcurses.a
+LIBDBM?= ${DESTDIR}/usr/lib/libdbm.a
+LIBDES?= ${DESTDIR}/usr/lib/libdes.a
+LIBGNUMALLOC?= ${DESTDIR}/usr/lib/libgnumalloc.a
+LIBGNUREGEX?= ${DESTDIR}/usr/lib/libgnuregex.a
+LIBL?= ${DESTDIR}/usr/lib/libl.a
+LIBKDB?= ${DESTDIR}/usr/lib/libkdb.a
+LIBKRB?= ${DESTDIR}/usr/lib/libkrb.a
+LIBM?= ${DESTDIR}/usr/lib/libm.a
+LIBMP?= ${DESTDIR}/usr/lib/libmp.a
+LIBPC?= ${DESTDIR}/usr/lib/libpc.a
+LIBPLOT?= ${DESTDIR}/usr/lib/libplot.a
+LIBREADLINE?= ${DESTDIR}/usr/lib/libreadline.a
+LIBRESOLV?= ${DESTDIR}/usr/lib/libresolv.a
+LIBRPCSVC?= ${DESTDIR}/usr/lib/librpcsvc.a
+LIBSKEY?= ${DESTDIR}/usr/lib/libskey.a
+LIBTELNET?= ${DESTDIR}/usr/lib/libtelnet.a
+LIBTERM?= ${DESTDIR}/usr/lib/libtermcap.a
+LIBUTIL?= ${DESTDIR}/usr/lib/libutil.a
+.endif
.if defined(NOSHARED)
LDFLAGS+= -static
.endif
@@ -55,6 +87,10 @@ CLEANFILES+=strings
.endif
+.if defined(DESTDIR)
+LDDESTDIR?= -L${DESTDIR}/usr/lib
+.endif
+
.if defined(PROG)
.if defined(SRCS)
@@ -64,12 +100,13 @@ OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
.if defined(LDONLY)
${PROG}: ${LIBCRT0} ${LIBC} ${DPSRCS} ${OBJS} ${DPADD}
- ${LD} ${LDFLAGS} -o ${.TARGET} ${LIBCRT0} ${OBJS} ${LIBC} ${LDADD}
+ ${LD} ${LDFLAGS} -o ${.TARGET} ${LIBCRT0} ${OBJS} ${LIBC} ${LDDESTDR} \
+ ${LDADD}
.else defined(LDONLY)
${PROG}: ${DPSRCS} ${OBJS} ${LIBC} ${DPADD}
- ${CC} ${LDFLAGS} -o ${.TARGET} ${OBJS} ${LDADD}
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} ${OBJS} ${LDDESTDIR} ${LDADD}
.endif
@@ -78,7 +115,8 @@ ${PROG}: ${DPSRCS} ${OBJS} ${LIBC} ${DPADD}
SRCS= ${PROG}.c
${PROG}: ${DPSRCS} ${SRCS} ${LIBC} ${DPADD}
- ${CC} ${LDFLAGS} ${CFLAGS} -o ${.TARGET} ${.CURDIR}/${SRCS} ${LDADD}
+ ${CC} ${LDFLAGS} ${CFLAGS} -o ${.TARGET} ${.CURDIR}/${SRCS} \
+ ${LDDESTDIR} ${LDADD}
MKDEP= -p
@@ -129,7 +167,7 @@ afterinstall:
realinstall: _PROGSUBDIR
.if defined(PROG)
- install ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${INSTALL} ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${PROG} ${DESTDIR}${BINDIR}
.endif
.if defined(HIDEGAME)
diff --git a/share/mk/sys.mk b/share/mk/sys.mk
index 71d12562ed44..154bd5183896 100644
--- a/share/mk/sys.mk
+++ b/share/mk/sys.mk
@@ -1,5 +1,5 @@
# from: @(#)sys.mk 5.11 (Berkeley) 3/13/91
-# $Id: sys.mk,v 1.5 1994/02/04 03:19:16 wollman Exp $
+# $Id: sys.mk,v 1.7 1994/06/13 21:02:48 csgr Exp $
unix= We run FreeBSD, not UNIX.
@@ -18,7 +18,7 @@ CC= cc
CFLAGS= -O
CXX= g++
-CXXFLAGS= ${CFLAGS}
+CXXFLAGS= ${CXXINCLUDES} ${CFLAGS}
CPP= cpp
@@ -100,3 +100,7 @@ YFLAGS=-d
rm -f lex.yy.c
.include <bsd.own.mk>
+
+.if exists(/etc/make.conf)
+.include </etc/make.conf>
+.endif
diff --git a/share/syscons/examples/setrus b/share/syscons/examples/setrus
index d88f4ac273a5..91f31e21f9af 100755
--- a/share/syscons/examples/setrus
+++ b/share/syscons/examples/setrus
@@ -1,17 +1,17 @@
#!/bin/sh
# Load KOI8-R screen mapping.
-syscons -S koi8-r2alt
+vidcontrol -l koi8-r2alt
# Load Alternate Codes screen font.
-syscons -f 16 alt8x16
-syscons -f 14 alt-8x14
-syscons -f 8 alt-8x8
+vidcontrol -f 8x16 altb-8x16
+vidcontrol -f 8x14 alt-8x14
+vidcontrol -f 8x8 alt-8x8
# Install JCUKEN keyboard mapping.
-# syscons -k ru.koi8-r # Not needed for kernel compiled with RUKEYMAP option
+# kbdcontrol -l ru.koi8-r # Not needed for kernel compiled with RUKEYMAP option
# Remap Del to Esc[K.
-syscons -F 54 ""
+kbdcontrol -f 54 ""
# Remap -5- to Esc[E.
-syscons -F 48 ""
+kbdcontrol -f 48 ""
# Maximum key rate
-syscons -r fast
+kbdcontrol -r fast
# Blank after 5 min
-syscons -s 300
+vidcontrol -t 300
diff --git a/share/syscons/fonts/Makefile b/share/syscons/fonts/Makefile
index 73b8698c6a79..289f3b9a6e66 100644
--- a/share/syscons/fonts/Makefile
+++ b/share/syscons/fonts/Makefile
@@ -1,9 +1,20 @@
-FONTS = cp850-8x14 cp850-8x16 cp850-8x8 cp865-8x14 cp865-8x16 \
- cp865-8x8 iso-8x14 iso-8x16 iso-8x8
+UUFONTS=altc-8x16.fnt cp865-8x14.fnt iso-8x16.fnt koi8-8x8.fnt alt-8x14.fnt \
+ cp850-8x14.fnt cp865-8x16.fnt iso-8x8.fnt koi8c-8x16.fnt alt-8x16.fnt \
+ cp850-8x16.fnt cp865-8x8.fnt koi8-8x14.fnt alt-8x8.fnt cp850-8x8.fnt \
+ iso-8x14.fnt koi8-8x16.fnt altb-8x16.fnt koi8b-8x16.fnt
+
+FONTS=altc-8x16 cp865-8x14 iso-8x16 koi8-8x8 alt-8x14 \
+ cp850-8x14 cp865-8x16 iso-8x8 koi8c-8x16 alt-8x16 \
+ cp850-8x16 cp865-8x8 koi8-8x14 alt-8x8 cp850-8x8 \
+ iso-8x14 koi8-8x16 koi8b-8x16 altb-8x16
+
FONTDIR = /usr/share/syscons/fonts
+NOMAN = noman
install:
cd ${.CURDIR}; \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${UUFONTS} \
+ ${DESTDIR}${FONTDIR}; \
install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${FONTS} \
${DESTDIR}${FONTDIR}
diff --git a/share/syscons/fonts/alt-8x14.fnt b/share/syscons/fonts/alt-8x14.fnt
new file mode 100644
index 000000000000..9dacecb94ce5
--- /dev/null
+++ b/share/syscons/fonts/alt-8x14.fnt
@@ -0,0 +1,83 @@
+begin 644 alt-8x14
+M`````````````````````'Z!I8&!I9F!?@``````?O_;___#Y_]^````````
+M;/[^_OY\.!`````````0.'S^?#@0````````&#P\Y^?G&!@\```````8/'[_
+M_WX8&#P``````````!@\/!@``````/______Y\/#Y_______`````#QF0D)F
+M/`````#_____PYF]O9G#_____P``'@X:,GC,S,QX```````\9F9F/!A^&!@`
+M`````#\S/S`P,'#PX```````?V-_8V-C9^?FP``````8&-L\YSS;&!@`````
+M`(#`X/C^^.#`@````````@8./OX^#@8"```````8/'X8&!A^/!@``````&9F
+M9F9F9@!F9@``````?]O;VWL;&QL;`````'S&8#ALQL9L.`S&?```````````
+M`/[^_@``````&#Q^&!@8?CP8?@`````8/'X8&!@8&!@``````!@8&!@8&'X\
+M&``````````8#/X,&````````````#!@_F`P`````````````,#`P/X`````
+M```````H;/YL*```````````$#@X?'S^_@````````#^_GQ\.#@0````````
+M```````````````````8/#P\&!@`&!@`````9F9F)```````````````;&S^
+M;&QL_FQL````&!A\QL+`?`:&QGP8&```````PL8,&#!FQ@``````.&QL.';<
+MS,QV`````#`P,&````````````````P8,#`P,#`8#```````,!@,#`P,#!@P
+M`````````&8\_SQF````````````&!A^&!@`````````````````&!@8,```
+M````````_@`````````````````````8&````````@8,&#!@P(````````!\
+MQL[>]N;&QGP``````!@X>!@8&!@8?@``````?,8&#!@P8,;^``````!\Q@8&
+M/`8&QGP```````P</&S,_@P,'@``````_L#`P/P&!L9\```````X8,#`_,;&
+MQGP``````/[&!@P8,#`P,```````?,;&QGS&QL9\``````!\QL;&?@8&#'@`
+M```````8&````!@8`````````!@8````&!@P```````&#!@P8#`8#`8`````
+M`````'X``'X`````````8#`8#`8,&#!@``````!\QL8,&!@`&!@``````'S&
+MQM[>WMS`?```````$#ALQL;^QL;&``````#\9F9F?&9F9OP``````#QFPL#`
+MP,)F/```````^&QF9F9F9FSX``````#^9F)H>&AB9OX``````/YF8FAX:&!@
+M\```````/&;"P,#>QF8Z``````#&QL;&_L;&QL8``````#P8&!@8&!@8/```
+M````'@P,#`P,S,QX``````#F9FQL>&QL9N8``````/!@8&!@8&)F_@``````
+MQN[^_M;&QL;&``````#&YO;^WL[&QL8``````#ALQL;&QL9L.```````_&9F
+M9GQ@8&#P``````!\QL;&QM;>?`P.`````/QF9F9\;&9FY@``````?,;&8#@,
+MQL9\``````!^?EH8&!@8&#P``````,;&QL;&QL;&?```````QL;&QL;&;#@0
+M``````#&QL;&UM;^?&P``````,;&;#@X.&S&Q@``````9F9F9CP8&!@\````
+M``#^QHP8,&#"QOX``````#PP,#`P,#`P/```````@,#@<#@<#@8"```````\
+M#`P,#`P,##P````0.&S&`````````````````````````````/\`,#`8````
+M`````````````````'@,?,S,=@``````X&!@>&QF9F9\``````````!\QL#`
+MQGP``````!P,##QLS,S,=@``````````?,;^P,9\```````X;&1@\&!@8/``
+M`````````';,S,Q\#,QX````X&!@;'9F9F;F```````8&``X&!@8&#P`````
+M``8&``X&!@8&9F8\````X&!@9FQX;&;F```````X&!@8&!@8&#P`````````
+M`.S^UM;6Q@``````````W&9F9F9F``````````!\QL;&QGP``````````-QF
+M9F9\8&#P````````=LS,S'P,#!X```````#<=F9@8/```````````'S&<!S&
+M?```````$#`P_#`P,#8<``````````#,S,S,S'8``````````&9F9F8\&```
+M````````QL;6UOYL``````````#&;#@X;,8``````````,;&QL9^!@SX````
+M````_LP8,&;^```````.&!@8<!@8&`X``````!@8&!@`&!@8&```````<!@8
+M&`X8&!AP``````!VW```````````````````$#ALQL;^````````/F;&QL;^
+MQL;&``````#^P,#\QL;&QOP``````/S&QL;\QL;&_```````_L;`P,#`P,#`
+M```````\;&QL;&QL;/[&@@```/[&P,#PP,#&_@``````UM;65'S6UM;6````
+M``!\Q@8<!@;&QGP``````,;&QL[>]N;&Q@`````,VL;&SM[VYL;&``````#&
+MS-CP\-C,QL8``````!XV9L;&QL;&Q@``````@L;&[N[^UL;&``````#&QL;&
+M_L;&QL8``````'[&QL;&QL;&_```````_L;&QL;&QL;&``````#\QL;&QOS`
+MP,```````'S&QL#`P,;&?```````?GY:&!@8&!@8``````#&QL;&QGX&QGP`
+M`````'S6UM;6UGP0.```````QL9L.#ALQL;&``````#,S,S,S,S,S/X"!@``
+M`,;&QL;&?@8&!@````#6UM;6UM;6UM;^`````-;6UM;6UM;6UOX"!@```.#@
+M8'QF9F9F?```````QL;&YK:VMK;F``````#`P,#\QL;&QOP``````'S&!AX&
+M!L;&?```````G+:VMO:VMK:<``````!^QL;&QGXV9L8``````````'S&QO[&
+MQ@``````````_L#\QL;\``````````#\QOS&QOP``````````/["P,#`P```
+M````````/&QL;&S^QH(```````!\QOS`QGP``````````-;6?-;6U@``````
+M````?,8<!L9\``````````#&SM[VYL8````````,&,;.WO;FQ@``````````
+MQLSXV,S&```````````^9F9F9L8``````````,;N_M;&Q@``````````QL;&
+M_L;&``````````!^QL;&QOP``````````/[&QL;&Q@```!%$$4011!%$$401
+M1!%$5:I5JE6J5:I5JE6J5:K==]UWW7?==]UWW7?==Q@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&!@8&/@8^!@8&!@8&#8V-C8V-C;V-C8V-C8V````
+M`````/XV-C8V-C8``````/@8^!@8&!@8&#8V-C8V]@;V-C8V-C8V-C8V-C8V
+M-C8V-C8V-C8``````/X&]C8V-C8V-C8V-C8V]@;^````````-C8V-C8V-OX`
+M```````8&!@8&/@8^`````````````````#X&!@8&!@8&!@8&!@8&!\`````
+M```8&!@8&!@8_P````````````````#_&!@8&!@8&!@8&!@8&!\8&!@8&!@`
+M````````_P```````!@8&!@8&!C_&!@8&!@8&!@8&!@?&!\8&!@8&!@V-C8V
+M-C8V-S8V-C8V-C8V-C8V-S`_```````````````_,#<V-C8V-C8V-C8V-O<`
+M_P``````````````_P#W-C8V-C8V-C8V-C8W,#<V-C8V-C8``````/\`_P``
+M`````#8V-C8V]P#W-C8V-C8V&!@8&!C_`/\````````V-C8V-C8V_P``````
+M````````_P#_&!@8&!@8`````````/\V-C8V-C8V-C8V-C8V/P```````!@8
+M&!@8'Q@?```````````````?&!\8&!@8&!@`````````/S8V-C8V-C8V-C8V
+M-C;_-C8V-C8V&!@8&!C_&/\8&!@8&!@8&!@8&!@8^``````````````````?
+M&!@8&!@8__________________\`````````__________#P\/#P\/#P\/#P
+M\/#P#P\/#P\/#P\/#P\/#P__________````````````````_,;&QL;\P,``
+M``````!\QL#`QGP``````````'Y:&!@8&```````````QL;&QL9^!GP`````
+M`!!\UM;6UGP0.````````,9L.#ALQ@``````````S,S,S,S^!@P```````#&
+MQL9^!@8``````````-;6UM;6_@``````````UM;6UM;^`@8```````#@8'QF
+M9GP``````````,;&YK:VY@``````````P,#\QL;\``````````!\QAX&QGP`
+M`````````)RVMO:VG```````````?L9^-F;&````;&P`_L;`\,#`QOX`````
+M`&QL`'S&_,#&?```````,!@,!@P8,`!^```````,&#!@,!@,`'X```````X;
+M&Q@8&!@8&!@8&!@8&!@8&!@8V-AP````````&!@`?@`8&```````````=MP`
+M=MP````````X;&PX````````````````````&!@`````````````````&```
+M```````/#`P,#`SL;#P<``````!\@KJJHJ*JNH)\````<-@P8,CX````````
+=``````!\?'Q\?'P```````````````````````!\
+`
+end
diff --git a/share/syscons/fonts/alt-8x16.fnt b/share/syscons/fonts/alt-8x16.fnt
new file mode 100644
index 000000000000..117db34fa9ec
--- /dev/null
+++ b/share/syscons/fonts/alt-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 alt-8x16
+M````````````````````````?H&E@8&EF8&!?@```````'[_V___V^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X&
+M#AIXS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P``,#`8````````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````X;&1@\&!@8&#P````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````9F9F9F8\&````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&``8&!@8&````````'`8&!@.&!@8&'````````!VW```````
+M```````````````0.&S&QL;^`````````#YFQL;&_L;&QL8```````#^P,#`
+M_,;&QL;\````````_,;&QOS&QL;&_````````/[&P,#`P,#`P,`````````\
+M;&QL;&QL;&S^QH(`````_L;`P/#`P,#&_@```````-;6UE1\UM;6UM8`````
+M``!\Q@8&'`8&QL9\````````QL;&QL[>]N;&Q@``````#-K&QL;.WO;FQL8`
+M``````#&S-CP\-C,QL;&````````'C9FQL;&QL;&Q@```````,;&[N[^_M;6
+MQL8```````#&QL;&_L;&QL;&````````?L;&QL;&QL;&_````````/[&QL;&
+MQL;&QL8```````#\QL;&QL;\P,#`````````?,;&P,#`P,;&?````````'Y^
+M6A@8&!@8&!@```````#&QL;&QL9^!L9\````````?-;6UM;6UGP0.```````
+M`,;&;#@X;,;&QL8```````#,S,S,S,S,S,S^`@8$````QL;&QL9^!@8&!@``
+M`````-;6UM;6UM;6UOX```````#6UM;6UM;6UM;^`@8$````X.!@8'QF9F9F
+M?````````,;&QL;FMK:VMN8```````#`P,#`_,;&QL;\````````>,P&!AX>
+M!@;,>````````)RVMK;VMK:VMIP```````!^QL;&QGXV9L;&````````````
+M?,;&QO[&Q@```````````/[`_,;&QOP```````````#\QL;\QL;\````````
+M````_L;"P,#`P````````````#QL;&QL;/[&@@````````!\QL;\P,9\````
+M````````UM;6?-;6U@```````````'S&!AP&QGP```````````#&QL[>]N;&
+M``````````P8QL;.WO;FQ@```````````,;,V/C8S,8````````````^9F9F
+M9F;&````````````QN[^UL;&Q@```````````,;&QO[&QL8```````````!^
+MQL;&QL;\````````````_L;&QL;&Q@`````11!%$$4011!%$$4011!%$5:I5
+MJE6J5:I5JE6J5:I5JMUWW7?==]UWW7?==]UWW7<8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&!@8&!@8^!CX&!@8&!@8&!@V-C8V-C8V]C8V-C8V
+M-C8V`````````/XV-C8V-C8V-@``````^!CX&!@8&!@8&!@V-C8V-O8&]C8V
+M-C8V-C8V-C8V-C8V-C8V-C8V-C8V-@``````_@;V-C8V-C8V-C8V-C8V-O8&
+M_@``````````-C8V-C8V-OX``````````!@8&!@8^!CX````````````````
+M````^!@8&!@8&!@8&!@8&!@8&!\``````````!@8&!@8&!C_````````````
+M````````_Q@8&!@8&!@8&!@8&!@8&!\8&!@8&!@8&`````````#_````````
+M```8&!@8&!@8_Q@8&!@8&!@8&!@8&!@?&!\8&!@8&!@8&#8V-C8V-C8W-C8V
+M-C8V-C8V-C8V-C<P/P`````````````````_,#<V-C8V-C8V-C8V-C8V]P#_
+M`````````````````/\`]S8V-C8V-C8V-C8V-C8W,#<V-C8V-C8V-@``````
+M_P#_```````````V-C8V-O<`]S8V-C8V-C8V&!@8&!C_`/\``````````#8V
+M-C8V-C;_`````````````````/\`_Q@8&!@8&!@8`````````/\V-C8V-C8V
+M-C8V-C8V-C8_```````````8&!@8&!\8'P`````````````````?&!\8&!@8
+M&!@8&``````````_-C8V-C8V-C8V-C8V-C8V_S8V-C8V-C8V&!@8&!C_&/\8
+M&!@8&!@8&!@8&!@8&!CX````````````````````'Q@8&!@8&!@8________
+M_____________P````````#____________P\/#P\/#P\/#P\/#P\/#P#P\/
+M#P\/#P\/#P\/#P\/#_________\``````````````````/S&QL;&QOS`P,``
+M``````!\QL#`PL9\````````````?EH8&!@8&````````````,;&QL;&QGX&
+MQGP``````!!\UM;6UM9\$#@`````````QFPX.&S&Q@```````````,S,S,S,
+MS/X&#`````````#&QL;&?@8&````````````UM;6UM;6_@```````````-;6
+MUM;6UOX"!@0```````#@8'QF9F9\````````````QL;FMK:VY@``````````
+M`,#`_,;&QOP```````````!\Q@8>!L9\````````````G+:V]K:VG```````
+M`````'[&QGXV9L8`````9F8`_L;`P/#`P,;^````````;&P`?,;&_,#&?```
+M```````P&`P&#!@P`'X`````````#!@P8#`8#`!^````````#AL;&!@8&!@8
+M&!@8&!@8&!@8&!@8&-C8V'```````````!@8`'X`&!@`````````````=MP`
+M=MP`````````.&QL.````````````````````````!@8````````````````
+M````&```````````#PP,#`P,[&QL/!P```````!\@KJJHJ*BJKJ"?`````!P
+MV#!@R/@`````````````````?'Q\?'Q\?```````````````````````````
+!`#!@
+`
+end
diff --git a/share/syscons/fonts/alt-8x8.fnt b/share/syscons/fonts/alt-8x8.fnt
new file mode 100644
index 000000000000..8db1c42fb9eb
--- /dev/null
+++ b/share/syscons/fonts/alt-8x8.fnt
@@ -0,0 +1,49 @@
+begin 644 alt-8x8
+M``````````!^@:6!O9F!?G[_V__#Y_]^;/[^_GPX$``0.'S^?#@0`#A\./[^
+M?#A\$!`X?/Y\.'P``!@\/!@``/__Y\/#Y___`#QF0D)F/`#_PYF]O9G#_P\'
+M#WW,S,QX/&9F9CP8?A@_,S\P,'#PX']C?V-C9^;`F5H\Y^<\6IF`X/C^^."`
+M``(./OX^#@(`&#Q^&!A^/!AF9F9F9@!F`'_;VWL;&QL`/F,X;&PXS'@`````
+M?GY^`!@\?AA^/!C_&#Q^&!@8&``8&!@8?CP8```8#/X,&````#!@_F`P````
+M`,#`P/X````D9O]F)````!@\?O__````__]^/!@`````````````,'AX,#``
+M,`!L;&P``````&QL_FS^;&P`,'S`>`SX,```QLP8,&;&`#AL.';<S'8`8&#`
+M```````8,&!@8#`8`&`P&!@8,&```&8\_SQF````,##\,#``````````,#!@
+M````_````````````#`P``8,&#!@P(``?,;.WO;F?``P<#`P,##\`'C,##A@
+MS/P`>,P,.`S,>``</&S,_@P>`/S`^`P,S'@`.&#`^,S,>`#\S`P8,#`P`'C,
+MS'C,S'@`>,S,?`P8<```,#```#`P```P,```,#!@&#!@P&`P&````/P``/P`
+M`&`P&`P8,&``>,P,&#``,`!\QM[>WL!X`#!XS,S\S,P`_&9F?&9F_``\9L#`
+MP&8\`/AL9F9F;/@`_F)H>&AB_@#^8FAX:&#P`#QFP,#.9CX`S,S,_,S,S`!X
+M,#`P,#!X`!X,#`S,S'@`YF9L>&QFY@#P8&!@8F;^`,;N_O[6QL8`QN;VWL[&
+MQ@`X;,;&QFPX`/QF9GQ@8/``>,S,S-QX'`#\9F9\;&;F`'C,X'`<S'@`_+0P
+M,#`P>`#,S,S,S,S\`,S,S,S,>#``QL;&UO[NQ@#&1&PX.&S&`,S,S'@P,'@`
+M_L:,&#)F_@!X8&!@8&!X`,!@,!@,!@(`>!@8&!@8>``0.&S&````````````
+M``#_,#`8`````````'@,?,Q\`&!@8'QF9GP```!XS,#,>``,#`Q\S,Q\````
+M>,S\P'@`.&Q@\&!@\````'S,S'P,^&!@?&9F9F8`,`!P,#`P>``,``P,#`QL
+M.&!@9FQX;&8`<#`P,#`P>````,S^_M;&````^,S,S,P```!XS,S,>````'QF
+M9GQ@8```?,S,?`P,``#<=F9@\````'S`>`SX`!`P?#`P-!@```#,S,S,?```
+M`,S,S'@P````QM;^_FP```#&;#ALQ@```,S,S'P,^```_)@P9/P`'#`PX#`P
+M'``8&!@`&!@8`.`P,!PP,.``=MP`````````$#ALQL;^`!XV9F9^9F8`?&!@
+M?&9F?`!\9F9\9F9\`'Y@8&!@8&``.&QL;&QL_L9^8&!\8&!^`-O;?CQ^V]L`
+M/&8&'`9F/`!F9FY^=F9F`#QF;GYV9F8`9FQX<'AL9@`>-F9F9F9F`,;N_O[6
+MQL8`9F9F?F9F9@`\9F9F9F8\`'YF9F9F9F8`?&9F9GQ@8``\9F!@8&8\`'X8
+M&!@8&!@`9F9F/@9F/`!^V]O;?A@8`&9F/!@\9F8`9F9F9F9F?P-F9F8^!@8&
+M`-O;V]O;V_\`V]O;V]O;_P/@8&!\9F9\`,;&QO;>WO8`8&!@?&9F?`!XC`8^
+M!HQX`,[;V_O;V\X`/F9F9CXV9@```'@,?,QV```\8#QF9CP```!\9GQF?```
+M`'Y@8&!@````/&QL;/[&```\9GY@/````-M^/'[;````/&8,9CP```!F;GYV
+M9@``&&9N?G9F````9FQX;&8````>-F9F9@```,;^_M;&````9F9^9F8````\
+M9F9F/````'YF9F9F`!%$$4011!%$5:I5JE6J5:K==]UWW7?==Q@8&!@8&!@8
+M&!@8^!@8&!@8^!CX&!@8&#8V-O8V-C8V````_C8V-C8`^!CX&!@8&#;V!O8V
+M-C8V-C8V-C8V-C8`_@;V-C8V-C;V!OX`````-C8V_@`````8^!CX````````
+M`/@8&!@8&!@8'P`````8&!C_`````````/\8&!@8&!@8'Q@8&!@```#_````
+M`!@8&/\8&!@8&!\8'Q@8&!@V-C8W-C8V-C8W,#\``````#\P-S8V-C8V]P#_
+M``````#_`/<V-C8V-C<P-S8V-C8`_P#_`````#;W`/<V-C8V&/\`_P`````V
+M-C;_``````#_`/\8&!@8````_S8V-C8V-C8_`````!@?&!\``````!\8'Q@8
+M&!@````_-C8V-C8V-O\V-C8V&/\8_Q@8&!@8&!CX`````````!\8&!@8____
+M______\```#_______#P\/#P\/#P#P\/#P\/#P____\`````````?&9F?&``
+M```\9F!F/````'X8&!@8````9F8^!CP```!^V]M^&````&8\&#QF````9F9F
+M9G\#``!F9CX&!@```-O;V]O_````V]O;V_\#``#@8'QF?````,;&]M[V````
+M8&!\9GP```!\!CX&?````,[;^]O.````/F8^-F8`9@!^8'Q@?@`D`#QF?F`\
+M```P&`P&#!@P``P8,&`P&`P.&QL8&!@8&!@8&!@8V-AP`!@8`'X`&!@`=MP`
+M=MP````X;&PX`````````!@````````X.`````,"!@3,:#@0/$*9H:&90CPP
+72!`@>```````?'Q\?`````````!"?@`X
+`
+end
diff --git a/share/syscons/fonts/alt8x16.fnt b/share/syscons/fonts/altb-8x16
index 2e8400196a29..2e8400196a29 100644
--- a/share/syscons/fonts/alt8x16.fnt
+++ b/share/syscons/fonts/altb-8x16
Binary files differ
diff --git a/share/syscons/fonts/altb-8x16.fnt b/share/syscons/fonts/altb-8x16.fnt
new file mode 100644
index 000000000000..e072d63716a7
--- /dev/null
+++ b/share/syscons/fonts/altb-8x16.fnt
@@ -0,0 +1,95 @@
+begin 664 altb-8x16
+M``````````````!$`````````'Z!I8&!O9F!@7X```````!^_]O__\/G__]^
+M````````9O____]^?CP\&!@`````&!@\/'Y^_WY^/#P8&``````8/#P89O__
+M9A@\?@`````8&#P\?O___WX8/'X`````````&#P\/!@```````#______^?#
+MP\/G________`````#QF0D)"9CP``````/_____#F;V]O9G#______\````>
+M#AHR>,S,S,QX````````/&9F9F8\&'X8&````````#\S,S\P,#!P\.``````
+M``!_8V-_8V-C9^?FP```````&!C;/.?G/-L8&````````(#`X/C^_OC@P(``
+M```````"!@X^_OX^#@8"`````!@\?A@8&!@8&!@8&'X\&```9F9F9F9F9F9F
+M`&9F`````'_;V]O;VWL;&QL;&P````!\QF`X;,;&;#@,QGP`````````````
+M`/[^_O[^`````!@\?A@8&!@8?CP8?@```!@\?O\8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8_WX\&`````````@,#O\.#`@````````````0,'#_<#`0````````
+M`````,#`P,#^_@`````````````D9O]F)````````````!`0.#A\?/[^````
+M``````#^_GQ\.#@0$````````````````````````````!@\/#P\&!@8&``8
+M&`````!C8\8`````````````````;&QL_OYL;&S^_FQL;````!A^V]OH>#P>
+M%]O;?A@8``#FINP,&!@P,&!NRLX`````.&QL;#@X;<W&QLMS`````!@8,```
+M```````````````,&!@P,#`P,#`P&!@,````,!@8#`P,#`P,#!@8,```````
+M`&9F//__/&9F````````````&!A^?A@8`````````````````````!@8,```
+M`````````'Y^````````````````````````&!@`````!@8,#!@8,#!@8,#`
+M`````'S&QL;.WO;FQL;&?``````8.'@8&!@8&!@8&'X`````/&;#PP,&#!@P
+M8,/_`````/[&#!@\!@,#`\-F/``````<'#P\;&S,S?\-#!X`````_L#`P/SF
+MPP,#PV8\`````#QFQL#\YL/#P\-F/`````#^Q@8,#!@8,#`P,#``````/&;#
+MPV8\9L/#PV8\`````#QFP\/#PV<_`V-F/```````````&!@`````&!@`````
+M`````!@8`````!@8,``````#!@P8,'`P&`P&`P``````````?GX`?GX`````
+M`````,!@,!@,!@P8,&#``````#QFP\,#!@P8&``8&````````'[#P]_;V][`
+MP'P`````$#A\[L;&QL;^QL;&`````/YC8V-C?F-C8V-C_@`````\9L/#P,#`
+MP,/#9CP`````_&9C8V-C8V-C8V;\`````/]C86!D?&1@8&%C_P````#_8V%@
+M9'QD8&!@8/@`````/&;#P\#`S\/#PV<]`````,;&QL;&_L;&QL;&Q@`````\
+M&!@8&!@8&!@8&#P`````#P8&!@8&!@;&QL9\`````.-C9F9L?&QF9F-CXP``
+M``#P8&!@8&!@8&!A8_\`````P^?__]O;V\/#P\/#`````,;&YN;V]M[>SL[&
+MQ@`````\9L/#P\/#P\/#9CP`````_F-C8V-C?F!@8&#P`````#QFP\/#P\/#
+MR\]^/`8'``#^8V-C8V-^;&9F9O<`````?L/#P,!^`P,#P\-^`````/_;F1@8
+M&!@8&!@8/`````#&QL;&QL;&QL;&QGP`````QL;&QL;&QL;&?#@0`````,/#
+MP\/;V]O;V_]F9@````#&QFQL.#@X.&QLQL8`````P\/#P^=^/!@8&!@\````
+M`/[&C`P8&#`P8&+&_@`````\,#`P,#`P,#`P,#P`````P,!@8#`P&!@,#`8&
+M`````#P,#`P,#`P,#`P,/``````8/&;#````````````````````````````
+M````_P```#`P&```````````````````````/`8^9F9F9CL`````X&!@8'YC
+M8V-C8V/>``````````!\QL#`P,#&?``````.!@8&?L;&QL;&QGL`````````
+M`'S&QO[`P,9\`````#QF9F#P8&!@8&!@\```````````>\;&QL;&QGX&QGP`
+MX&!@8'QF9F9F9F;F```````8&``X&!@8&!@8/```````!@8`#@8&!@8&!@9F
+M9CP`X&!@8&9F;'AL9F;F`````#@8&!@8&!@8&!@8/```````````YO_;V]O#
+MP\,``````````-QF9F9F9F9F``````````!\QL;&QL;&?```````````WF-C
+M8V-C8WY@8/```````'O&QL;&QL9^!@8/``````#><V-@8&!@\```````````
+M?,;`<!P&QGP``````!`P,/PP,#`P,#8<``````````#&QL;&QL;&>P``````
+M````QL;&QNY\.!```````````,/#V]O;V_]F``````````#&[GPX.'SNQ@``
+M````````QL;&QL;&QGX,&'```````/[&#!@P8,;^``````X8&!@8<'`8&!@8
+M#@`````8&!@8&```&!@8&!@`````<!@8&!@>'A@8&!AP``````!VW```````
+M````````````````$#ALQL;&_@`````````0.&S&QO[&QL;&````````_F)B
+M8'QF9F9F_````````/QF9F9\9F9F9OP```````#^8F)@8&!@8&#P````````
+M'C9F9F9F9F9F_\.!`````/YF8FAX:&!B9OX```````#6UE14?'Q4UM;6````
+M````?,8&!CP&!@;&?````````,;&SL[6YN;&QL8`````.#C&QL[.UN;FQL;&
+M````````YF9L;'AX;&QFY@```````!XV9L;&QL;&QL8```````#&[O[^UL;&
+MQL;&````````QL;&QO[&QL;&Q@```````'S&QL;&QL;&QGP```````#^QL;&
+MQL;&QL;&````````_&9F9GQ@8&!@\````````#QFPL#`P,#"9CP```````!^
+M6A@8&!@8&!@\````````QL;&QL9^!@;&?```````/!A^V]O;V]M^&#P`````
+M``#&QFQ\.#A\;,;&````````S,S,S,S,S,S,_@8&`````,;&QL;&?@8&!@8`
+M``````#;V]O;V]O;V]O_````````V]O;V]O;V]O;_P,#`````/BP,#`\-C8V
+M-GP```````##P\/#\]O;V]OS````````\&!@8'QF9F9F_````````'C,!B8^
+M)@8&S'@```````#.V]O;^]O;V]O.````````/V9F9CX^9F9FYP``````````
+M`'@,?,S,S'8```````(&/&!@?&9F9F8\````````````_&9F?&9F_```````
+M`````'XR,C`P,'@````````````>-C9F9F;_P\,`````````?,;^P,#&?```
+M`````````-;65'Q4UM8````````````\9@8,!F8\````````````QL;.UN;&
+MQ@`````````X.,;&SM;FQL8```````````#F;'AX;&;F````````````'C9F
+M9F9F9@```````````,;N_O[6UL8```````````#&QL;^QL;&````````````
+M?,;&QL;&?````````````/[&QL;&QL8```""$((0@A""$((0@A""$((0PQC#
+M&,,8PQC#&,,8PQC#&-B#VA/8@]H3V(/:$]B#VA,8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&!CX&!@8&!@8&!@8&!@8&/@8^!@8&!@8&!@V-C8V-C8V-O8V-C8V
+M-C8V``````````#^-C8V-C8V-@```````/@8^!@8&!@8&!@V-C8V-C;V!O8V
+M-C8V-C8V-C8V-C8V-C8V-C8V-C8V-@```````/X&]C8V-C8V-C8V-C8V-C;V
+M!OX`````````-C8V-C8V-C;^`````````!@8&!@8&/@8^```````````````
+M`````/@8&!@8&!@8&!@8&!@8&!@?`````````!@8&!@8&!@8_P``````````
+M`````````/\8&!@8&!@8&!@8&!@8&!@?&!@8&!@8&```````````_P``````
+M```8&!@8&!@8&/\8&!@8&!@8&!@8&!@8'Q@?&!@8&!@8&#8V-C8V-C8V-S8V
+M-C8V-C8V-C8V-C8W,#\`````````````````/S`W-C8V-C8V-C8V-C8V-O<`
+M_P````````````````#_`/<V-C8V-C8V-C8V-C8V-S`W-C8V-C8V-@``````
+M`/\`_P`````````V-C8V-C;W`/<V-C8V-C8V&!@8&!@8_P#_`````````#8V
+M-C8V-C8V_P````````````````#_`/\8&!@8&!@8``````````#_-C8V-C8V
+M-C8V-C8V-C8V/P`````````8&!@8&!@?&!\`````````````````'Q@?&!@8
+M&!@8&```````````/S8V-C8V-C8V-C8V-C8V-O\V-C8V-C8V&!@8&!@8_QC_
+M&!@8&!@8&!@8&!@8&!@8^````````````````````!\8&!@8&!@8________
+M_____________P``````````___________P\/#P\/#P\/#P\/#P\/#P#P\/
+M#P\/#P\/#P\/#P\/#___________``````````````````#<9F9F9F9\8&#P
+M````````?,;`P,#&?````````````'Y:&!@8&#P```````````#&QL;&QGX&
+M!L9\```````\&'[;V]O;?A@8/````````,9L.#@X;,8```````````#,S,S,
+MS,S^!@8`````````QL;&QGX&!@```````````-;6UM;6UOX```````````#6
+MUM;6UM;^`P,`````````^+`P/C,S?@```````````,;&QO;>WO8`````````
+M``#P8&!\9F;\````````````/F<#'P-G/@```````````,[;V_O;V\X`````
+M``````!^S,S\;,S.``````!L;`#^9F!\8&!F_@```````,8``'S&_L#`QGP`
+M`````&`P&`P&#!@P8`!^```````,&#!@P&`P&`P`?```````#AL;&!@8&!@8
+M&!@8&!@8&!@8&!@8&!@8V/AP`````````!@8`'Y^`!@8````````````=MP`
+M=MP``````````#AL;&PX`````````````````````!@8````````````````
+M````&```````````#PP,#`P,#`SL;#P<````````/$*9H:&90CP```````!P
+MB!!@B/@`````````````````?'Q\?'Q\?````````````````````$)"?@``
+!`!!@
+`
+end
diff --git a/share/syscons/fonts/altc-8x16.fnt b/share/syscons/fonts/altc-8x16.fnt
new file mode 100644
index 000000000000..bb36c7ef3170
--- /dev/null
+++ b/share/syscons/fonts/altc-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 altc-8x16
+M````````````````````````?H&E@8&EF8&!?@```````'[_V___V^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X&
+M#AIXS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P``,#`8````````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````X;&1@\&!@8&#P````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````9F9F9F8\&````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&``8&!@8&````````'`8&!@.&!@8&'````````!VW```````
+M```````````````0.&S&QL;^`````````#YFQL;&_L;&QL8```````#^P,#`
+M_,;&QL;\````````_,;&QOS&QL;&_````````/[&P,#`P,#`P,`````````\
+M;&QL;&QL;&S^QH(`````_L;`P/#`P,#&_@```````-;6UE1\UM;6UM8`````
+M``!\Q@8&'`8&QL9\````````QL;&QL[>]N;&Q@``````#-K&QL;.WO;FQL8`
+M``````#&S-CP\-C,QL;&````````'C9FQL;&QL;&Q@```````,;&[N[^_M;6
+MQL8```````#&QL;&_L;&QL;&````````?L;&QL;&QL;&_````````/[&QL;&
+MQL;&QL8```````#\QL;&QL;\P,#`````````?,;&P,#`P,;&?````````'Y^
+M6A@8&!@8&!@```````#&QL;&QL9^!L9\````````?-;6UM;6UGP0.```````
+M`,;&;#@X;,;&QL8```````#,S,S,S,S,S,S^`@8$````QL;&QL9^!@8&!@``
+M`````-;6UM;6UM;6UOX```````#6UM;6UM;6UM;^`@8$````X.!@8'QF9F9F
+M?````````,;&QL;FMK:VMN8```````#`P,#`_,;&QL;\````````>,P&!AX>
+M!@;,>````````)RVMK;VMK:VMIP```````!^QL;&QGXV9L;&````````````
+M?,;&QO[&Q@```````````/[`_,;&QOP```````````#\QL;\QL;\````````
+M````_L;"P,#`P````````````#QL;&QL;/[&@@````````!\QL;\P,9\````
+M````````UM;6?-;6U@```````````'S&!AP&QGP```````````#&QL[>]N;&
+M``````````P8QL;.WO;FQ@```````````,;,V/C8S,8````````````^9F9F
+M9F;&````````````QN[^UL;&Q@```````````,;&QO[&QL8```````````!^
+MQL;&QL;\````````````_L;&QL;&Q@`````11!%$$4011!%$$4011!%$5:I5
+MJE6J5:I5JE6J5:I5JMUWW7?==]UWW7?==]UWW7<8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&!@0_F9B8&!@8&!@\````````#QFP,#HT,#`9CP`
+M```````V)`!X,#`P,#!X````````&!``>#`P,#`P>````````'S&QF`X#`;&
+MQGP```````!@\&!L=F9F9F;F!@PP````#`@`/!@8&!@8&!BP8````"08`,;&
+MQL;&QGX&QGP```````+^P,#`P,#`````````&!``QLS8^-C,Q@``````````
+M````^!@8&!@8&!@8&!@8&!@8&!\``````````!@8&!@8&!C_````````````
+M````````_Q@8&!@8&!@8&!@8&!@8&!\8&!@8&!@8&`````````#_````````
+M```8&!@8&!@8_Q@8&!@8&!@8``````#&QL;&QL;^$!`X```````'B,NKJ*N;
+MB````````&#P8&!\9F9F9N8```````````!\QL!\!L9\``````#P8&!@?&9F
+M9F9FYP`````,&``\&!@8&!@8&!BP8````&#X8&!\=F9F9F;G````````_L;&
+MQL;&QL;&QOX```!L.,;&QL;&QGX&QGP```````!\;&QL;FEI:6G.````````
+MS,S,S/[)R<G)S@`````,&``\&!@8&!@8&#P`````-B0`/!@8&!@8&!@\````
+M````````S,S,_LG)S@```````````#Q,3$Y)2<X````````8$`#^PL#`P,#`
+M````````````/&+`^,!B/``````"!O[`P,#`P,#`P,``````&!#&QLS8\/#8
+MS,;&`````!@8&!@8&!CX````````````````````'Q@8&!@8&!@8________
+M_____________P````````#____________P\/#P\/#P\/#P\/#P\/#P#P\/
+M#P\/#P\/#P\/#P\/#_________\``````````````````/S&QL;&QOS`P,``
+M``````!\QL#`PL9\````````````?EH8&!@8&````````````,;&QL;&QGX&
+MQGP``````!!\UM;6UM9\$#@`````````QFPX.&S&Q@```````````,S,S,S,
+MS/X&#`````````#&QL;&?@8&````````````UM;6UM;6_@```````````-;6
+MUM;6UOX"!@0```````#@8'QF9F9\````````````QL;FMK:VY@``````````
+M`,#`_,;&QOP```````````!\Q@8>!L9\````````````G+:V]K:VG```````
+M`````'[&QGXV9L8`````9F8`_L;`P/#`P,;^````````;&P`?,;&_,#&?```
+M```````P&`P&#!@P`'X`````````#!@P8#`8#`!^````````#AL;&!@8&!@8
+M&!@8&!@8&!@8&!@8&-C8V'```````````!@8`'X`&!@`````````````=MP`
+M=MP`````````.&QL.````````````````````````!@8````````````````
+M````&```````````#PP,#`P,[&QL/!P```````#&QL;&QL;&QL;^$!`X``!P
+MV#!@R/@`````````````````?'Q\?'Q\?```````````````````````````
+!`#!@
+`
+end
diff --git a/share/syscons/fonts/cp850-8x14.fnt b/share/syscons/fonts/cp850-8x14.fnt
new file mode 100644
index 000000000000..803f95df6585
--- /dev/null
+++ b/share/syscons/fonts/cp850-8x14.fnt
@@ -0,0 +1,83 @@
+begin 644 cp850-8x14
+M``````````````````````!^@:6!@;V9@7X``````'[_V___P^?_?@``````
+M`&S^_O[^?#@0````````$#A\_GPX$````````!@\/.?GYQ@8/```````&#Q^
+M__]^&!@\```````````8/#P8`````/_______^?#P^?_____```````\9D)"
+M9CP```#______\.9O;V9P____P```!X.&C)XS,S,>```````/&9F9CP8?A@8
+M```````_,S\P,#!P\.```````']C?V-C8V?GYL``````&!C;/.<\VQ@8````
+M``"`P.#X_OC@P(````````(&#C[^/@X&`@``````&#Q^&!@8?CP8``````!F
+M9F9F9F8`9F8``````'_;V]M[&QL;&P````!\QF`X;,;&;#@,QGP`````````
+M``#^_OX``````!@\?A@8&'X\&'X`````&#Q^&!@8&!@8```````8&!@8&!A^
+M/!@`````````&`S^#!@````````````P8/Y@,`````````````#`P,#^````
+M````````*&S^;"@``````````!`X.'Q\_OX`````````_OY\?#@X$```````
+M````````````````````&#P\/!@8`!@8````9F9F)````````````````&QL
+M_FQL;/YL;````!@8?,;"P'P&AL9\&!@``````,+&#!@P9L8``````#AL;#AV
+MW,S,=@```!@8&#`````````````````,&#`P,#`P&`P``````#`8#`P,#`P8
+M,`````````!F//\\9@```````````!@8?A@8`````````````````!@8&#``
+M`````````/X`````````````````````&!@```````(&#!@P8,"`````````
+M.&S&QM;&QFPX```````8.'@8&!@8&'X``````'S&!@P8,&#&_@``````?,8&
+M!CP&!L9\```````,'#QLS/X,#!X``````/[`P,#\!@;&?```````.&#`P/S&
+MQL9\``````#^Q@8,&#`P,#```````'S&QL9\QL;&?```````?,;&QGX&!@QX
+M````````&!@````8&``````````8&````!@8,```````#!@P8,!@,!@,````
+M``````!^``!^`````````&`P&`P&#!@P8```````?,;&#!@8`!@8``````!\
+MQL;>WM[<P'P``````!`X;,;&_L;&Q@``````_&9F9GQF9F;\```````\9L+`
+MP,#"9CP``````/AL9F9F9F9L^```````_F9B:'AH8F;^``````#^9F)H>&A@
+M8/```````#QFPL#`WL9F.@``````QL;&QO[&QL;&```````\&!@8&!@8&#P`
+M`````!X,#`P,#,S,>```````YF9L;'AL;&;F``````#P8&!@8&!B9OX`````
+M`,;N_M;&QL;&Q@``````QN;V_M[.QL;&``````!\QL;&QL;&QGP``````/QF
+M9F9\8&!@\```````?,;&QL;&UMY\#@````#\9F9F?&QF9N8``````'S&QF`X
+M#,;&?```````?GY:&!@8&!@\``````#&QL;&QL;&QGP``````,;&QL;&QFPX
+M$```````QL;&QM;6_FQL``````#&QL9\.'S&QL8``````&9F9F8\&!@8/```
+M````_L:,&#!@PL;^```````\,#`P,#`P,#P``````(#`X'`X'`X&`@``````
+M/`P,#`P,#`P\```0.&S&``````````````````````````````#_`#`8#```
+M``````````````````!X#'S,S'8``````.!@8'AL9F9F?```````````?,;`
+MP,9\```````<#`P\;,S,S'8``````````'S&_L#&?```````'#8R,'PP,#!X
+M``````````!VS,S,?`S,>````.!@8&QV9F9FY@``````&!@`.!@8&!@\````
+M```&!@`.!@8&!F9F/````.!@8&9L>&QFY@``````.!@8&!@8&!@\````````
+M``#L_M;6UM8``````````-QF9F9F9@``````````?,;&QL9\``````````#<
+M9F9F?&!@\````````';,S,Q\#`P>````````W'9F8&#P``````````!\QG`<
+MQGP``````!`P,/PP,#`V'```````````S,S,S,QV``````````#&QL9L.!``
+M`````````,;&UM;^;```````````QFPX.&S&``````````#&QL;&?@8,>```
+M`````/[,&#!F_@``````#A@8&'`8&!@.```````8&!@8&!@8&!@``````'`8
+M&!@.&!@8<````';<`````````````````````!`X;,;&_@```````#QFPL#`
+MP,)F/`QX````S```S,S,S,QV``````P8,`!\QO[`QGP`````$#AL`'@,?,S,
+M=@``````Q@``>`Q\S,QV`````&`P&`!X#'S,S'8`````.&PX`'@,?,S,=@``
+M````````?,;`P,9\#'@``!`X;`!\QO[`QGP``````,8``'S&_L#&?`````!@
+M,!@`?,;^P,9\``````!F```X&!@8&#P`````&#QF`#@8&!@8/`````!@,!@`
+M.!@8&!@\````Q@`0.&S&QO[&QL8``#AL.!`X;,;&_L;&Q@``#!@`_F9B:'AH
+M8F;^``````````#L-G;<V&X``````#YLS,S^S,S,S@`````0.&P`?,;&QL9\
+M``````#&``!\QL;&QGP`````8#`8`'S&QL;&?``````P>,P`S,S,S,QV````
+M`&`P&`#,S,S,S'8``````,8``,;&QL9^!@QX`,8`?,;&QL;&QL9\````Q@#&
+MQL;&QL;&QGP``````````'S.WO;F?``````X;&1@\&!@8.;\``````1\SL[6
+MUM;FYGQ`````````QFPX.&S&```````.&Q@8&'X8&!C8<`````P8,`!X#'S,
+MS'8`````#!@P`#@8&!@8/``````,&#``?,;&QL9\``````P8,`#,S,S,S'8`
+M`````';<`-QF9F9F9@``=MP`QN;V_M[.QL;&`````#QL;#X`?@``````````
+M.&QL.`!\````````````,#``,#!@QL9\```````X1+JJLJJJ1#@`````````
+M``#^!@8&``````!@X&-F;!@P;L,&#!\``&#@8V9L&C9NVC\&!@```!@8`!@8
+M/#P\&``````````V;-AL-@```````````-AL-FS8`````!%$$4011!%$$401
+M1!%$5:I5JE6J5:I5JE6J5:K==]UWW7?==]UWW7?==Q@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@P8,`0.&S&QO[&QL8``#ALQA`X;,;&_L;&Q@``&`P&
+M$#ALQL;^QL;&```````X1)JBHJ*:1#@``#8V-C8V]@;V-C8V-C8V-C8V-C8V
+M-C8V-C8V-C8``````/X&]C8V-C8V-C8V-C8V]@;^```````````8&'S&P,#&
+M?!@8``````!F9CP8?AA^&!@```````````#X&!@8&!@8&!@8&!@8&!\`````
+M```8&!@8&!@8_P````````````````#_&!@8&!@8&!@8&!@8&!\8&!@8&!@`
+M````````_P```````!@8&!@8&!C_&!@8&!@8````=MP`>`Q\S,QV``!VW``0
+M.&S&QO[&QL8``#8V-C8V-S`_```````````````_,#<V-C8V-C8V-C8V-O<`
+M_P``````````````_P#W-C8V-C8V-C8V-C8W,#<V-C8V-C8``````/\`_P``
+M`````#8V-C8V]P#W-C8V-C8V``````#&?,;&QGS&```````T&"P&/F9F9CP`
+M`````/AL9F;V9F9L^```.&P`_F9B:'AH8F;^````Q@#^9F)H>&AB9OX``#`8
+M`/YF8FAX:&)F_@``````````.!@8&!@\```,&``\&!@8&!@8&#P``#QF`#P8
+M&!@8&!@8/````&8`/!@8&!@8&!@\```8&!@8&!@8^``````````````````?
+M&!@8&!@8__________________\`````````_________P``&!@8&````!@8
+M&!@`,!@`/!@8&!@8&!@\``#_________`````````!@P`'S&QL;&QL;&?```
+M````>,S,S-C,QL;,```X;`!\QL;&QL;&QGP``#`8`'S&QL;&QL;&?```````
+M=MP`?,;&QL9\``!VW`!\QL;&QL;&QGP``````````&9F9F9F?&#`````X&!@
+M?&9F9F9\8/````#P8'QF9F9\8/```!@P`,;&QL;&QL;&?```.&P`QL;&QL;&
+MQL9\```P&`#&QL;&QL;&QGP`````#!@P`,;&QL9^!@SX#!@`9F9F9CP8&!@\
+M````_P`````````````````,&#```````````````````````/X`````````
+M````&!A^&!@``'X`````````````````_P#_`.`P8S;L&#9NVC\&!@````!_
+MV]O;>QL;&QL`````?,9@.&S&QFPX#,9\```````8`'X`&```````````````
+M`````!@,>``X;&PX`````````````,8`````````````````````````&```
+M```````8.!@8&#P``````````'@,.`P,>```````````/&8,&#)^````````
+=````````?GY^?GY^````````````````````````
+`
+end
diff --git a/share/syscons/fonts/cp850-8x16.fnt b/share/syscons/fonts/cp850-8x16.fnt
new file mode 100644
index 000000000000..10f7bb2f9fe9
--- /dev/null
+++ b/share/syscons/fonts/cp850-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 cp850-8x16
+M````````````````````````?H&E@8&]F8&!?@```````'[_V___P^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X.
+M&C)XS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P```#`8#```````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````<-C(P>#`P,#!X````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````QL;&QL9L.````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&!@8&!@8&````````'`8&!@.&!@8&'```````';<````````
+M```````````````0.&S&QL;^`````````#QFPL#`P,#"9CP8<`````#,``#,
+MS,S,S,QV```````,&#``?,;^P,#&?```````$#AL`'@,?,S,S'8```````#,
+M``!X#'S,S,QV``````!@,!@`>`Q\S,S,=@``````.&PX`'@,?,S,S'8`````
+M``````!\QL#`P,9\&'`````0.&P`?,;^P,#&?````````,8``'S&_L#`QGP`
+M`````&`P&`!\QO[`P,9\````````9@``.!@8&!@8/```````&#QF`#@8&!@8
+M&#P``````&`P&``X&!@8&!@\``````#&`!`X;,;&_L;&Q@`````X;#@0.&S&
+MQO[&QL8`````#!@`_F9B:'AH8F;^````````````[#8V?MC8;@```````#YL
+MS,S^S,S,S,X``````!`X;`!\QL;&QL9\````````Q@``?,;&QL;&?```````
+M8#`8`'S&QL;&QGP``````#!XS`#,S,S,S,QV``````!@,!@`S,S,S,S,=@``
+M`````,8``,;&QL;&QGX&#'@``,8`?,;&QL;&QL9\``````#&`,;&QL;&QL;&
+M?````````````'S.WO;FQGP``````#AL9&#P8&!@8.;\```````$?,[.UM;6
+MUN;F?$```````````,9L.#ALQ@````````X;&!@8?A@8&-AP```````8,&``
+M>`Q\S,S,=@``````#!@P`#@8&!@8&#P``````!@P8`!\QL;&QL9\```````8
+M,&``S,S,S,S,=@```````';<`-QF9F9F9F8`````=MP`QN;V_M[.QL;&````
+M````/&QL/@!^`````````````#AL;#@`?``````````````P,``P,&#`QL9\
+M````````?(*RJK*JJH)\``````````````#^!@8&!@```````&#@8F9L&#!@
+MW(8,&#X```!@X&)F;!@P9LZ:/P8&`````!@8`!@8&#P\/!@````````````V
+M;-AL-@``````````````V&PV;-@````````11!%$$4011!%$$4011!%$5:I5
+MJE6J5:I5JE6J5:I5JMUWW7?==]UWW7?==]UWW7<8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&&#`$#ALQL;^QL;&Q@````!\QA`X;,;&_L;&QL8`
+M````#`80.&S&QO[&QL;&````````?(*:HJ*BFH)\```````V-C8V-O8&]C8V
+M-C8V-C8V-C8V-C8V-C8V-C8V-C8V-@``````_@;V-C8V-C8V-C8V-C8V-O8&
+M_@`````````````8&'S&P,#&?!@8`````````&9F/!A^&'X8&```````````
+M````^!@8&!@8&!@8&!@8&!@8&!\``````````!@8&!@8&!C_````````````
+M````````_Q@8&!@8&!@8&!@8&!@8&!\8&!@8&!@8&`````````#_````````
+M```8&!@8&!@8_Q@8&!@8&!@8``!VW`!X#'S,S,QV`````';<`#ALQL;^QL;&
+MQ@`````V-C8V-C<P/P`````````````````_,#<V-C8V-C8V-C8V-C8V]P#_
+M`````````````````/\`]S8V-C8V-C8V-C8V-C8W,#<V-C8V-C8V-@``````
+M_P#_```````````V-C8V-O<`]S8V-C8V-C8V`````,9\QL;&QGS&````````
+M-!@L!CYF9F9F/````````/AL9F;V9F9F;/@`````.&P`_F9B:'AH8F;^````
+M``#&`/YF8FAX:&)F_@`````P&`#^9F)H>&AB9OX````````````X&!@8&!@\
+M``````P8`#P8&!@8&!@8/``````\9@`\&!@8&!@8&#P``````&8`/!@8&!@8
+M&!@\`````!@8&!@8&!CX````````````````````'Q@8&!@8&!@8________
+M_____________P````````#___________\`&!@8&!@``!@8&!@8````,!@`
+M/!@8&!@8&!@\`````/________\````````````8,`!\QL;&QL;&QGP`````
+M``!XS,S,V,S&QL;,`````#AL`'S&QL;&QL;&?``````P&`!\QL;&QL;&QGP`
+M``````!VW`!\QL;&QL9\`````';<`'S&QL;&QL;&?````````````&9F9F9F
+M9GQ@8,````#@8&!\9F9F9F9\8&#P````\&!\9F9F9GQ@\``````8,`#&QL;&
+MQL;&QGP`````.&P`QL;&QL;&QL9\`````#`8`,;&QL;&QL;&?```````#!@P
+M`,;&QL;&QGX&#/@`#!@`9F9F9CP8&!@\``````#_````````````````````
+M#!@P`````````````````````````/X````````````````8&'X8&```?@``
+M``````````````````#_`/\``.`P8C;L&#!FSIH_!@8`````?]O;VWL;&QL;
+M&P``````?,9@.&S&QFPX#,9\```````````8`'X`&```````````````````
+M````&`QX````.&QL.````````````````,8`````````````````````````
+M```8````````````&#@8&!@\`````````````'P&/`8&?``````````````\
+M9@P8,GX`````````````````?GY^?GY^?@``````````````````````````
+!``P8
+`
+end
diff --git a/share/syscons/fonts/cp850-8x8.fnt b/share/syscons/fonts/cp850-8x8.fnt
new file mode 100644
index 000000000000..21a4aa4d3ba3
--- /dev/null
+++ b/share/syscons/fonts/cp850-8x8.fnt
@@ -0,0 +1,49 @@
+begin 644 cp850-8x8
+M``````````!^@:6!O9F!?G[_V__#Y_]^;/[^_GPX$``0.'S^?#@0`#A\./[^
+MUA`X$#A\_OY\$#@``!@\/!@``/__Y\/#Y___`#QF0D)F/`#_PYF]O9G#_P\'
+M#WW,S,QX/&9F9CP8?A@_,S\P,'#PX']C?V-C9^;`&-L\Y^<\VQB`X/C^^."`
+M``(./OX^#@(`&#Q^&!A^/!AF9F9F9@!F`'_;VWL;&QL`/F$\9F8\AGP`````
+M?GY^`!@\?AA^/!C_&#Q^&!@8&``8&!@8?CP8```8#/X,&````#!@_F`P````
+M`,#`P/X````D9O]F)````!@\?O__````__]^/!@`````````````&#P\&!@`
+M&`!F9B0``````&QL_FS^;&P`&#Y@/`9\&```QLP8,&;&`#AL.';<S'8`&!@P
+M```````,&#`P,!@,`#`8#`P,&#```&8\_SQF````&!A^&!@`````````&!@P
+M````?@```````````!@8``8,&#!@P(``.&S&UL9L.``8.!@8&!A^`'S&!APP
+M9OX`?,8&/`;&?``</&S,_@P>`/[`P/P&QGP`.&#`_,;&?`#^Q@P8,#`P`'S&
+MQGS&QGP`?,;&?@8,>```&!@``!@8```8&```&!@P!@P8,!@,!@```'X``'X`
+M`&`P&`P8,&``?,8,&!@`&`!\QM[>WL!X`#ALQO[&QL8`_&9F?&9F_``\9L#`
+MP&8\`/AL9F9F;/@`_F)H>&AB_@#^8FAX:&#P`#QFP,#.9CH`QL;&_L;&Q@`\
+M&!@8&!@\`!X,#`S,S'@`YF9L>&QFY@#P8&!@8F;^`,;N_O[6QL8`QN;VWL[&
+MQ@!\QL;&QL9\`/QF9GQ@8/``?,;&QL;.?`[\9F9\;&;F`#QF,!@,9CP`?GY:
+M&!@8/`#&QL;&QL9\`,;&QL;&;#@`QL;&UM;^;`#&QFPX;,;&`&9F9CP8&#P`
+M_L:,&#)F_@`\,#`P,#`\`,!@,!@,!@(`/`P,#`P,/``0.&S&````````````
+M``#_,!@,`````````'@,?,QV`.!@?&9F9MP```!\QL#&?``<#'S,S,QV````
+M?,;^P'P`/&9@^&!@\````';,S'P,^.!@;'9F9N8`&``X&!@8/``&``8&!F9F
+M/.!@9FQX;.8`.!@8&!@8/````.S^UM;6````W&9F9F8```!\QL;&?````-QF
+M9GQ@\```=LS,?`P>``#<=F!@\````'[`?`;\`#`P_#`P-AP```#,S,S,=@``
+M`,;&QFPX````QM;6_FP```#&;#ALQ@```,;&QGX&_```?DP8,GX`#A@8<!@8
+M#@`8&!@8&!@8`'`8&`X8&'``=MP`````````$#ALQL;^`'S&P,#&?`QXS`#,
+MS,S,=@`,&'S&_L!\`'R">`Q\S'8`Q@!X#'S,=@`P&'@,?,QV`#`P>`Q\S'8`
+M``!^P,!^##A\@GS&_L!\`,8`?,;^P'P`,!A\QO[`?`!F`#@8&!@\`'R".!@8
+M&#P`,!@`.!@8/`#&.&S&_L;&`#AL?,;^QL8`&##^P/C`_@```'X2_I#^`#YL
+MS/[,S,X`?()\QL;&?`#&`'S&QL9\`#`8?,;&QGP`>(0`S,S,=@!@,,S,S,QV
+M`,8`QL;&?@;\QCALQL9L.`#&`,;&QL9\```"?,[6YGR`.&QD\&!F_``Z;,[6
+MYFRX``#&;#ALQ@``#AL8/!C8<``8,'@,?,QV``P8`#@8&#P`#!A\QL;&?``8
+M,,S,S,QV`';<`-QF9F8`=MP`YO;>S@`\;&P^`'X``#AL;#@`?```&``8&#!C
+M/@!^@;FEN:6!?@```/X&!@``8^9L?C-FS`]CYFQZ-FK?!A@`&!@\/!@``#-F
+MS&8S````S&8S9LP``"*((H@BB"*(5:I5JE6J5:IWW7?==]UWW1@8&!@8&!@8
+M&!@8&/@8&!@P8#ALQO[&`'R".&S&_L8`&`PX;,;^Q@!^@9VAH9V!?C8V]@;V
+M-C8V-C8V-C8V-C8``/X&]C8V-C8V]@;^````&!A^P,!^&!AF9CQ^&'X8&```
+M``#X&!@8&!@8&!\````8&!@8_P````````#_&!@8&!@8&!\8&!@`````_P``
+M`!@8&!C_&!@8=MQ\!G[&?@!VW#ALQO[&`#8V-S`_```````_,#<V-C8V-O<`
+M_P``````_P#W-C8V-C8W,#<V-C8``/\`_P```#8V]P#W-C8V`,9\QL9\Q@`P
+M?@Q\S,QX`/AL9O9F;/@`?(+^P/S`_@#&`/[`_,#^`#`8_L#\P/X````X&!@8
+M/``,&#P8&!@\`#Q"/!@8&#P`9@`\&!@8/``8&!@8^``````````?&!@8____
+M______\`````_____Q@8&```&!@8,!@\&!@8/`#_____`````#!@.&S&;#@`
+M>,S,V,S&S`!\@CALQFPX``P&.&S&;#@`=MQ\QL;&?`!VW#ALQFPX````9F9F
+M9GS`X&!\9F9\8/#P8'QF?&#P`!@PQL;&QGP`?((`QL;&?`!@,,;&QL9\`!@P
+MQL;&?@;\#!AF9CP8/`#_``````````P8,```````````?@`````8&'X8&`!^
+M````````_P#_X3+D.O8J7X9_V]M[&QL;`#YA/&9F/(9\`!@`?@`8````````
+M`!@,.#AL;#@``````,8````````````8`````!@X&!@\````>`PX#'@```!X
+7#!@P?```````/#P\/``````````````8
+`
+end
diff --git a/share/syscons/fonts/cp865-8x14.fnt b/share/syscons/fonts/cp865-8x14.fnt
new file mode 100644
index 000000000000..a5a2dd7e2742
--- /dev/null
+++ b/share/syscons/fonts/cp865-8x14.fnt
@@ -0,0 +1,83 @@
+begin 644 cp865-8x14
+M``````````````````````!^@:6!@;V9@7X``````'[_V___P^?_?@``````
+M`&S^_O[^?#@0````````$#A\_GPX$````````!@\/.?GYQ@8/```````&#Q^
+M__]^&!@\```````````8/#P8`````/_______^?#P^?_____```````\9D)"
+M9CP```#______\.9O;V9P____P```!X.&C)XS,S,>```````/&9F9CP8?A@8
+M```````_,S\P,#!P\.```````']C?V-C8V?GYL``````&!C;/.<\VQ@8````
+M``"`P.#X_OC@P(````````(&#C[^/@X&`@``````&#Q^&!@8?CP8``````!F
+M9F9F9F8`9F8``````'_;V]M[&QL;&P````!\QF`X;,;&;#@,QGP`````````
+M``#^_OX``````!@\?A@8&'X\&'X`````&#Q^&!@8&!@8```````8&!@8&!A^
+M/!@`````````&`S^#!@````````````P8/Y@,`````````````#`P,#^````
+M````````*&S^;"@``````````!`X.'Q\_OX`````````_OY\?#@X$```````
+M````````````````````&#P\/!@8`!@8````9F9F)````````````````&QL
+M_FQL;/YL;````!@8?,;"P'P&AL9\&!@``````,+&#!@P9L8``````#AL;#AV
+MW,S,=@```!@8&#`````````````````,&#`P,#`P&`P``````#`8#`P,#`P8
+M,`````````!F//\\9@```````````!@8?A@8`````````````````!@8&#``
+M`````````/X`````````````````````&!@```````(&#!@P8,"`````````
+M.&S&QM;&QFPX```````8.'@8&!@8&'X``````'S&!@P8,&#&_@``````?,8&
+M!CP&!L9\```````,'#QLS/X,#!X``````/[`P,#\!@;&?```````.&#`P/S&
+MQL9\``````#^Q@8,&#`P,#```````'S&QL9\QL;&?```````?,;&QGX&!@QX
+M````````&!@````8&``````````8&````!@8,```````#!@P8,!@,!@,````
+M``````!^``!^`````````&`P&`P&#!@P8```````?,;&#!@8`!@8``````!\
+MQL;>WM[<P'P``````!`X;,;&_L;&Q@``````_&9F9GQF9F;\```````\9L+`
+MP,#"9CP``````/AL9F9F9F9L^```````_F9B:'AH8F;^``````#^9F)H>&A@
+M8/```````#QFPL#`WL9F.@``````QL;&QO[&QL;&```````\&!@8&!@8&#P`
+M`````!X,#`P,#,S,>```````YF9L;'AL;&;F``````#P8&!@8&!B9OX`````
+M`,;N_M;&QL;&Q@``````QN;V_M[.QL;&``````!\QL;&QL;&QGP``````/QF
+M9F9\8&!@\```````?,;&QL;&UMY\#@````#\9F9F?&QF9N8``````'S&QF`X
+M#,;&?```````?GY:&!@8&!@\``````#&QL;&QL;&QGP``````,;&QL;&QFPX
+M$```````QL;&QM;6_FQL``````#&QL9\.'S&QL8``````&9F9F8\&!@8/```
+M````_L:,&#!@PL;^```````\,#`P,#`P,#P``````(#`X'`X'`X&`@``````
+M/`P,#`P,#`P\```0.&S&``````````````````````````````#_`#`8#```
+M``````````````````!X#'S,S'8``````.!@8'AL9F9F?```````````?,;`
+MP,9\```````<#`P\;,S,S'8``````````'S&_L#&?```````'#8R,'PP,#!X
+M``````````!VS,S,?`S,>````.!@8&QV9F9FY@``````&!@`.!@8&!@\````
+M```&!@`.!@8&!F9F/````.!@8&9L>&QFY@``````.!@8&!@8&!@\````````
+M``#L_M;6UM8``````````-QF9F9F9@``````````?,;&QL9\``````````#<
+M9F9F?&!@\````````';,S,Q\#`P>````````W'9F8&#P``````````!\QG`<
+MQGP``````!`P,/PP,#`V'```````````S,S,S,QV``````````#&QL9L.!``
+M`````````,;&UM;^;```````````QFPX.&S&``````````#&QL;&?@8,>```
+M`````/[,&#!F_@``````#A@8&'`8&!@.```````8&!@8&!@8&!@``````'`8
+M&!@.&!@8<````';<`````````````````````!`X;,;&_@```````#QFPL#`
+MP,)F/`QX````S```S,S,S,QV``````P8,`!\QO[`QGP`````$#AL`'@,?,S,
+M=@``````Q@``>`Q\S,QV`````&`P&`!X#'S,S'8`````.&PX`'@,?,S,=@``
+M````````?,;`P,9\#'@``!`X;`!\QO[`QGP``````,8``'S&_L#&?`````!@
+M,!@`?,;^P,9\``````!F```X&!@8&#P`````&#QF`#@8&!@8/`````!@,!@`
+M.!@8&!@\````Q@`0.&S&QO[&QL8``#AL.!`X;,;&_L;&Q@``#!@`_F9B:'AH
+M8F;^``````````#L-G;<V&X``````#YLS,S^S,S,S@`````0.&P`?,;&QL9\
+M``````#&``!\QL;&QGP`````8#`8`'S&QL;&?``````P>,P`S,S,S,QV````
+M`&`P&`#,S,S,S'8``````,8``,;&QL9^!@QX`,8`?,;&QL;&QL9\````Q@#&
+MQL;&QL;&QGP``````````'S.WO;F?``````X;&1@\&!@8.;\``````1\SL[6
+MUM;FYGQ`````_&9F?&)F;V9F\P`````.&Q@8&'X8&!C8<`````P8,`!X#'S,
+MS'8`````#!@P`#@8&!@8/``````,&#``?,;&QL9\``````P8,`#,S,S,S'8`
+M`````';<`-QF9F9F9@``=MP`QN;V_M[.QL;&`````#QL;#X`?@``````````
+M.&QL.`!\````````````,#``,#!@QL9\````````````_L#`P```````````
+M``#^!@8&``````!@X&-F;!@P;L,&#!\``&#@8V9L&C9NVC\&!@```!@8`!@8
+M/#P\&``````````V;-AL-@```````````,9\QL;&?,8``!%$$4011!%$$401
+M1!%$5:I5JE6J5:I5JE6J5:K==]UWW7?==]UWW7?==Q@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&!@8&/@8^!@8&!@8&#8V-C8V-C;V-C8V-C8V````
+M`````/XV-C8V-C8``````/@8^!@8&!@8&#8V-C8V]@;V-C8V-C8V-C8V-C8V
+M-C8V-C8V-C8``````/X&]C8V-C8V-C8V-C8V]@;^````````-C8V-C8V-OX`
+M```````8&!@8&/@8^`````````````````#X&!@8&!@8&!@8&!@8&!\`````
+M```8&!@8&!@8_P````````````````#_&!@8&!@8&!@8&!@8&!\8&!@8&!@`
+M````````_P```````!@8&!@8&!C_&!@8&!@8&!@8&!@?&!\8&!@8&!@V-C8V
+M-C8V-S8V-C8V-C8V-C8V-S`_```````````````_,#<V-C8V-C8V-C8V-O<`
+M_P``````````````_P#W-C8V-C8V-C8V-C8W,#<V-C8V-C8``````/\`_P``
+M`````#8V-C8V]P#W-C8V-C8V&!@8&!C_`/\````````V-C8V-C8V_P``````
+M````````_P#_&!@8&!@8`````````/\V-C8V-C8V-C8V-C8V/P```````!@8
+M&!@8'Q@?```````````````?&!\8&!@8&!@`````````/S8V-C8V-C8V-C8V
+M-C;_-C8V-C8V&!@8&!C_&/\8&!@8&!@8&!@8&!@8^``````````````````?
+M&!@8&!@8__________________\`````````__________#P\/#P\/#P\/#P
+M\/#P#P\/#P\/#P\/#P\/#P__________`````````````````';<V-C<=@``
+M````>,S,S-C,QL;,``````#^QL;`P,#`P,```````````/YL;&QL;```````
+M_L9@,!@P8,;^``````````!^V-C8V'```````````&9F9F9F?&#```````!V
+MW!@8&!@8``````!^&#QF9F8\&'X``````#ALQL;^QL9L.```````.&S&QL9L
+M;&SN```````>,!@,/F9F9CP``````````'[;VWX``````````P9^V]OS?F#`
+M```````>,&!@?F!@,!X```````!\QL;&QL;&Q@```````/X``/X``/X`````
+M````&!A^&!@``'X``````#`8#`8,&#``?@``````#!@P8#`8#`!^``````X;
+M&Q@8&!@8&!@8&!@8&!@8&!@8V-AP```````````8`'X`&````````````';<
+M`';<```````X;&PX`````````````````````!@8````````````````&```
+M```````/#`P,#`P,[&P\'````&PV-C8V-@``````````/&8,&#)^````````
+=````````?GY^?GY^````````````````````````
+`
+end
diff --git a/share/syscons/fonts/cp865-8x16.fnt b/share/syscons/fonts/cp865-8x16.fnt
new file mode 100644
index 000000000000..e23b5b811dd6
--- /dev/null
+++ b/share/syscons/fonts/cp865-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 cp865-8x16
+M````````````````````````?H&E@8&]F8&!?@```````'[_V___P^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X.
+M&C)XS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P```#`8#```````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````<-C(P>#`P,#!X````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````QL;&QL9L.````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&!@8&!@8&````````'`8&!@.&!@8&'```````';<````````
+M```````````````0.&S&QL;^`````````#QFPL#`P,#"9CP8<`````#,``#,
+MS,S,S,QV```````,&#``?,;^P,#&?```````$#AL`'@,?,S,S'8```````#,
+M``!X#'S,S,QV``````!@,!@`>`Q\S,S,=@``````.&PX`'@,?,S,S'8`````
+M``````!\QL#`P,9\&'`````0.&P`?,;^P,#&?````````,8``'S&_L#`QGP`
+M`````&`P&`!\QO[`P,9\````````9@``.!@8&!@8/```````&#QF`#@8&!@8
+M&#P``````&`P&``X&!@8&!@\``````#&`!`X;,;&_L;&Q@`````X;#@0.&S&
+MQO[&QL8`````#!@`_F9B:'AH8F;^````````````[#8V?MC8;@```````#YL
+MS,S^S,S,S,X``````!`X;`!\QL;&QL9\````````Q@``?,;&QL;&?```````
+M8#`8`'S&QL;&QGP``````#!XS`#,S,S,S,QV``````!@,!@`S,S,S,S,=@``
+M`````,8``,;&QL;&QGX&#'@``,8`?,;&QL;&QL9\``````#&`,;&QL;&QL;&
+M?````````````'S&SM;FQGP``````#AL9&#P8&!@8.;\```````$?,[.UM;6
+MUN;F?$``````^,S,^,3,WLS,S,8```````X;&!@8?A@8&-AP```````8,&``
+M>`Q\S,S,=@``````#!@P`#@8&!@8&#P``````!@P8`!\QL;&QL9\```````8
+M,&``S,S,S,S,=@```````';<`-QF9F9F9F8`````=MP`QN;V_M[.QL;&````
+M````/&QL/@!^`````````````#AL;#@`?``````````````P,``P,&#`QL9\
+M`````````````/[`P,#```````````````#^!@8&!@```````&#@8F9L&#!@
+MW(8,&#X```!@X&)F;!@P9LZ:/P8&`````!@8`!@8&#P\/!@````````````V
+M;-AL-@````````````#&?,;&QL9\Q@`````11!%$$4011!%$$4011!%$5:I5
+MJE6J5:I5JE6J5:I5JMUWW7?==]UWW7?==]UWW7<8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&!@8&!@8^!CX&!@8&!@8&!@V-C8V-C8V]C8V-C8V
+M-C8V`````````/XV-C8V-C8V-@``````^!CX&!@8&!@8&!@V-C8V-O8&]C8V
+M-C8V-C8V-C8V-C8V-C8V-C8V-C8V-@``````_@;V-C8V-C8V-C8V-C8V-O8&
+M_@``````````-C8V-C8V-OX``````````!@8&!@8^!CX````````````````
+M````^!@8&!@8&!@8&!@8&!@8&!\``````````!@8&!@8&!C_````````````
+M````````_Q@8&!@8&!@8&!@8&!@8&!\8&!@8&!@8&`````````#_````````
+M```8&!@8&!@8_Q@8&!@8&!@8&!@8&!@?&!\8&!@8&!@8&#8V-C8V-C8W-C8V
+M-C8V-C8V-C8V-C<P/P`````````````````_,#<V-C8V-C8V-C8V-C8V]P#_
+M`````````````````/\`]S8V-C8V-C8V-C8V-C8W,#<V-C8V-C8V-@``````
+M_P#_```````````V-C8V-O<`]S8V-C8V-C8V&!@8&!C_`/\``````````#8V
+M-C8V-C;_`````````````````/\`_Q@8&!@8&!@8`````````/\V-C8V-C8V
+M-C8V-C8V-C8_```````````8&!@8&!\8'P`````````````````?&!\8&!@8
+M&!@8&``````````_-C8V-C8V-C8V-C8V-C8V_S8V-C8V-C8V&!@8&!C_&/\8
+M&!@8&!@8&!@8&!@8&!CX````````````````````'Q@8&!@8&!@8________
+M_____________P````````#____________P\/#P\/#P\/#P\/#P\/#P#P\/
+M#P\/#P\/#P\/#P\/#_________\``````````````````';<V-C8W'8`````
+M``!XS,S,V,S&QL;,````````_L;&P,#`P,#`P````````````/YL;&QL;&P`
+M``````#^QF`P&!@P8,;^````````````?MC8V-C8<````````````&9F9F9F
+M9GQ@8,```````';<&!@8&!@8````````?A@\9F9F9CP8?@```````#ALQL;^
+MQL;&;#@````````X;,;&QFQL;&SN````````'C`8##YF9F9F/```````````
+M`'[;V]M^`````````````P9^V]OS?F#`````````'#!@8'Q@8&`P'```````
+M``!\QL;&QL;&QL8``````````/X``/X``/X````````````8&'X8&```?@``
+M```````P&`P&#!@P`'X`````````#!@P8#`8#`!^````````#AL;&!@8&!@8
+M&!@8&!@8&!@8&!@8&!C8V-AP```````````8`'X`&```````````````=MP`
+M=MP`````````.&QL.````````````````````````!@8````````````````
+M```8````````````#PP,#`P,[&QL/!P``````&PV-C8V-@`````````````\
+M9@P8,GX`````````````````?GY^?GY^?@``````````````````````````
+!``P8
+`
+end
diff --git a/share/syscons/fonts/cp865-8x8.fnt b/share/syscons/fonts/cp865-8x8.fnt
new file mode 100644
index 000000000000..de8b0b365dad
--- /dev/null
+++ b/share/syscons/fonts/cp865-8x8.fnt
@@ -0,0 +1,49 @@
+begin 644 cp865-8x8
+M``````````!^@:6!O9F!?G[_V__#Y_]^;/[^_GPX$``0.'S^?#@0`#A\./[^
+MUA`X$#A\_OY\$#@``!@\/!@``/__Y\/#Y___`#QF0D)F/`#_PYF]O9G#_P\'
+M#WW,S,QX/&9F9CP8?A@_,S\P,'#PX']C?V-C9^;`&-L\Y^<\VQB`X/C^^."`
+M``(./OX^#@(`&#Q^&!A^/!AF9F9F9@!F`'_;VWL;&QL`/F$\9F8\AGP`````
+M?GY^`!@\?AA^/!C_&#Q^&!@8&``8&!@8?CP8```8#/X,&````#!@_F`P````
+M`,#`P/X````D9O]F)````!@\?O__````__]^/!@`````````````&#P\&!@`
+M&`!F9B0``````&QL_FS^;&P`&#Y@/`9\&```QLP8,&;&`#AL.';<S'8`&!@P
+M```````,&#`P,!@,`#`8#`P,&#```&8\_SQF````&!A^&!@`````````&!@P
+M````?@```````````!@8``8,&#!@P(``.&S&UL9L.``8.!@8&!A^`'S&!APP
+M9OX`?,8&/`;&?``</&S,_@P>`/[`P/P&QGP`.&#`_,;&?`#^Q@P8,#`P`'S&
+MQGS&QGP`?,;&?@8,>```&!@``!@8```8&```&!@P!@P8,!@,!@```'X``'X`
+M`&`P&`P8,&``?,8,&!@`&`!\QM[>WL!X`#ALQO[&QL8`_&9F?&9F_``\9L#`
+MP&8\`/AL9F9F;/@`_F)H>&AB_@#^8FAX:&#P`#QFP,#.9CH`QL;&_L;&Q@`\
+M&!@8&!@\`!X,#`S,S'@`YF9L>&QFY@#P8&!@8F;^`,;N_O[6QL8`QN;VWL[&
+MQ@!\QL;&QL9\`/QF9GQ@8/``?,;&QL;.?`[\9F9\;&;F`#QF,!@,9CP`?GY:
+M&!@8/`#&QL;&QL9\`,;&QL;&;#@`QL;&UM;^;`#&QFPX;,;&`&9F9CP8&#P`
+M_L:,&#)F_@`\,#`P,#`\`,!@,!@,!@(`/`P,#`P,/``0.&S&````````````
+M``#_,!@,`````````'@,?,QV`.!@?&9F9MP```!\QL#&?``<#'S,S,QV````
+M?,;^P'P`/&9@^&!@\````';,S'P,^.!@;'9F9N8`&``X&!@8/``&``8&!F9F
+M/.!@9FQX;.8`.!@8&!@8/````.S^UM;6````W&9F9F8```!\QL;&?````-QF
+M9GQ@\```=LS,?`P>``#<=F!@\````'[`?`;\`#`P_#`P-AP```#,S,S,=@``
+M`,;&QFPX````QM;6_FP```#&;#ALQ@```,;&QGX&_```?DP8,GX`#A@8<!@8
+M#@`8&!@8&!@8`'`8&`X8&'``=MP`````````$#ALQL;^`'S&P,#&?`QXS`#,
+MS,S,=@`,&'S&_L!\`'R">`Q\S'8`Q@!X#'S,=@`P&'@,?,QV`#`P>`Q\S'8`
+M``!^P,!^##A\@GS&_L!\`,8`?,;^P'P`,!A\QO[`?`!F`#@8&!@\`'R".!@8
+M&#P`,!@`.!@8/`#&.&S&_L;&`#AL?,;^QL8`&##^P/C`_@```'X2_I#^`#YL
+MS/[,S,X`?()\QL;&?`#&`'S&QL9\`#`8?,;&QGP`>(0`S,S,=@!@,,S,S,QV
+M`,8`QL;&?@;\QCALQL9L.`#&`,;&QL9\```"?,[6YGR`.&QD\&!F_``Z;,[6
+MYFRX`/C,S/K&S\;'#AL8/!C8<``8,'@,?,QV``P8`#@8&#P`#!A\QL;&?``8
+M,,S,S,QV`';<`-QF9F8`=MP`YO;>S@`\;&P^`'X``#AL;#@`?```&``8&#!C
+M/@````#^P,```````/X&!@``8^9L?C-FS`]CYFQZ-FK?!A@`&!@\/!@``#-F
+MS&8S````QGS&QGS&`"*((H@BB"*(5:I5JE6J5:IWW7?==]UWW1@8&!@8&!@8
+M&!@8&/@8&!@8&/@8^!@8&#8V-C;V-C8V`````/XV-C8``/@8^!@8&#8V]@;V
+M-C8V-C8V-C8V-C8``/X&]C8V-C8V]@;^````-C8V-OX````8&/@8^```````
+M``#X&!@8&!@8&!\````8&!@8_P````````#_&!@8&!@8&!\8&!@`````_P``
+M`!@8&!C_&!@8&!@?&!\8&!@V-C8V-S8V-C8V-S`_```````_,#<V-C8V-O<`
+M_P``````_P#W-C8V-C8W,#<V-C8``/\`_P```#8V]P#W-C8V&!C_`/\````V
+M-C8V_P``````_P#_&!@8`````/\V-C8V-C8V/P```!@8'Q@?```````?&!\8
+M&!@`````/S8V-C8V-C;_-C8V&!C_&/\8&!@8&!@8^``````````?&!@8____
+M______\`````______#P\/#P\/#P#P\/#P\/#P______````````=MS(W'8`
+M>,S,V,S&S`#^QL#`P,#`````_FQL;&P`_L9@,&#&_@```'[8V-AP````9F9F
+M9GS``';<&!@8&`!^&#QF9CP8?CALQO[&;#@`.&S&QFQL[@`.&`P^9F8\````
+M?MO;?@``!@Q^V]M^8,`>,&!^8#`>``!\QL;&QL8``/X`_@#^```8&'X8&`!^
+M`#`8#!@P`'X`#!@P&`P`?@`.&QL8&!@8&!@8&!@8V-AP`!@`?@`8````=MP`
+M=MP``#AL;#@`````````&!@````````8``````\,#`SL;#P<;#8V-C8```!X
+7#!@P?```````/#P\/``````````````8
+`
+end
diff --git a/share/syscons/fonts/iso-8x14.fnt b/share/syscons/fonts/iso-8x14.fnt
new file mode 100644
index 000000000000..0c0e4d87194f
--- /dev/null
+++ b/share/syscons/fonts/iso-8x14.fnt
@@ -0,0 +1,83 @@
+begin 644 iso-8x14
+M`````````````````````'Z!I8&!O9F!?@``````?O_;___#Y_]^````````
+M-G]_?W\^'`@````````('#Y_/AP(````````&#P\Y^?G&!@\```````8/'[_
+M_WX8&#P``````````!@\/!@``````/______Y\/#Y_______`````#PD0D(D
+M/`````#_____P]N]O=O#_____P``'P<-&7C,S,QX```````\9F9F/!A^&!@`
+M``````P*"0D)"@@X>'@P````'Q$?$1$1$S=W<B`````8&-L\YSS;&!@`````
+M`$!@<'Q_?'!@0````````0,''W\?!P,!```````8/'X8&!A^/!@``````#,S
+M,S,S,P`S,P``````?]O;VWL;&QL;`````#YC,!PV8V,V'`9C/@``````````
+M`']_?P``````&#Q^&!@8?CP8?@`````8/'X8&!@8&!@``````!@8&!@8&'X\
+M&``````````,!G\&#````````````!@P?S`8````````````8&!@8']_````
+M```````D0O]")````````````````!@\?O\``````````/]^/!@`````````
+M```````````````````8/#P\&!@`&!@`````9F9F)```````````````-C9_
+M-C8V?S8V````"`@^8V!@/@,#8SX("`````!A8P8,&#!C0P``````'#8V'#MN
+M9F8[`````#`P,&````````````````P8,#`P,#`8#```````,!@,#`P,#!@P
+M`````````&8\?CQF````````````&!A^&!@`````````````````&!@8,```
+M````````?@`````````````````````8&````````0,&#!@P8$`````````^
+M8V=O>W-C8SX```````P</`P,#`P,/P``````/F,#!@P8,&-_```````^8P,#
+M'@,#8SX```````8.'C9F?P8&#P``````?F!@8'X#`V,^```````<,&!@?F-C
+M8SX``````']C`P8,&!@8&```````/F-C8SYC8V,^```````^8V-C/P,#!AP`
+M````````&!@````8&``````````8&````!@8,``````&#!@P8#`8#`8`````
+M````?@```'X`````````8#`8#`8,&#!@```````^8V,&#`P`#`P``````#YC
+M8V]O;VY@/@``````"!PV8V-_8V-C``````!^,S,S/C,S,WX``````!XS8&!@
+M8&`S'@``````?#8S,S,S,S9\``````!_,S`T/#0P,W\``````'\S,#0\-#`P
+M>```````'C-@8&!O8S,=``````!C8V-C?V-C8V,``````#P8&!@8&!@8/```
+M````#P8&!@8&9F8\``````!S,S8V/#8V,W,``````'@P,#`P,#`S?P``````
+M8W=_:V-C8V-C``````!C<WM_;V=C8V,``````!PV8V-C8V,V'```````?C,S
+M,SXP,#!X```````<-F-C8V-K/AP&`P```'XS,S,^-C,S<P``````/F-C,!P&
+M8V,^``````!^6A@8&!@8&#P``````&-C8V-C8V-C/@``````8V-C8V-C-AP(
+M``````!C8V-C8VMK?S8``````&-C8S8<-F-C8P``````9F9F9F8\&!@\````
+M``!_8P8,&#!@8W\``````#PP,#`P,#`P/```````0&`P&`P&`P$````````\
+M#`P,#`P,##P````('#9C``````````````````````````````#_&!@,````
+M`````````````````#P&/F9F.P``````<#`P/C,S,S-N```````````^8V!@
+M8SX```````X&!CYF9F9F.P``````````/F-_8&,^```````>,S!\,#`P,'@`
+M`````````#MF9F8^!F8\````<#`P-CLS,S-S```````,#``<#`P,#!X`````
+M``P,`!P,#`P,#,QX````<#`P,S8\-C-S```````<#`P,#`P,#!X`````````
+M`&9_:VMK:P``````````;C,S,S,S```````````^8V-C8SX``````````&XS
+M,S,^,#!X````````.V9F9CX&!@\```````!N,S`P,'@``````````#YC.`YC
+M/@````````@8?A@8&!L.``````````!F9F9F9CL``````````&-C8S8<"```
+M````````8V-K:W\V``````````!C-AP<-F,``````````&-F9F8^!F8\````
+M````?V8,&#-_```````.&!@8<!@8&`X``````!@8&!@8&!@8&```````<!@8
+M&`X8&!AP```````[;@``````````````````"!PV8V-_````````````````
+M````````````&#Q^__]^/!@```!5JE6J5:I5JE6J5:I5J@!$1'Q$1``?!`0$
+M!````'Q`>$!``!\0'A`0````.$1`1#@`'A$>%!,```!`0$!`?``?$!X0$```
+M`#AL;#@`````````````````&!A^&!@`?@````!$9%1,1``0$!`0'P```$1$
+M1"@0`!\$!`0$```8&!@8&!@8^`````````````````#X&!@8&!@8````````
+M`!\8&!@8&!@8&!@8&!@8'P```````!@8&!@8&!C_&!@8&!@8_P``````````
+M``````````#_``````````````````````#_`````````````````````/\`
+M````````````````````_Q@8&!@8&!@?&!@8&!@8&!@8&!@8&/@8&!@8&!@8
+M&!@8&!@8_P````````````````#_&!@8&!@8&!@8&!@8&!@8&!@8&!@```P8
+M,&`P&`P`?@``````,!@,!@P8,`!^``````````,^=C8V-FP````````"!'X(
+M$'X@0```````'#8P,'PP,'-^```````````8&```````````````````````
+M````````&!@`&!@\/#P8````````"`@^8V!@8SX("````!PV,#!\,#!S?@``
+M`````$(\9F9F/$(```````!F9F8\&'X8?A@``````!@8&!@`&!@8&``````^
+M8S`<-F-C-AP&8SX``&-C```````````````````^05U145U!/@`````X!#Q$
+M/`!\`````````````!LV;#8;``````````````!_`P,``````````````'\`
+M````````````/D%=55E503X`````?@`````````````````X;&PX````````
+M`````````!@8?A@8`'X`````.&P8,&1\``````````!\##@,;#@`````````
+M``8,&````````````````````&9F9F9F.V#`````?]O;VWL;&QL;````````
+M```8&```````````````````````#`P&'``P<#`P,'@``````````#A$1$0X
+M`'P`````````````;#8;-FP```````!@X&-F;!@S9\\?`P,``&#@8V9L&#!N
+MPP8,'P``\#!C]FP8,V?/'P,#````&!@`&!@P8V,^````8#`8`!PV8V-_8V,`
+M```#!@P`'#9C8W]C8P````@<-@`<-F-C?V-C````.VX`"!PV8V-_8V,`````
+M8V,('#9C8W]C8P```!PV'``<-F-C?V-C```````?-F9F9WYF9F<``````!XS
+M8&!@8&`S'@P&'&`P&`!_,S`^,#-_````!@P8`'\S,#XP,W\````('#8`?S,P
+M/C`S?P````!C8P!_,S`^,#-_````8#`8`#P8&!@8&#P````&#!@`/!@8&!@8
+M/````!@\9@`\&!@8&!@\`````&9F`#P8&!@8&#P``````#PV,S-[,S,V/```
+M`#MN`&-S>W]O9V-C````8#`8`!PV8V-C-AP````#!@P`'#9C8V,V'`````@<
+M-@`<-F-C8S8<`````#MN`!PV8V-C-AP`````8V,`'#9C8V,V'````````&,V
+M'`@<-F,```````,>-F=O:WMS-CQ@``!@,!@`8V-C8V-C/@````,&#`!C8V-C
+M8V,^````"!PV`&-C8V-C8SX`````8V,`8V-C8V-C/@````8,&`!F9F8\&!@\
+M`````'@P/C,S/C`P,'@``````!PV8V9L9V-K;F!@``!@,!@`/`8^9F8[````
+M``8,&``\!CYF9CL`````"!PV`#P&/F9F.P``````.VX`/`8^9F8[``````!F
+M9@`\!CYF9CL`````'#8<`#P&/F9F.P``````````=@L[;F@W```````````^
+M8V!@8SX,!AP`,!@,`#YC?V!C/@`````#!@P`/F-_8&,^``````@<-@`^8W]@
+M8SX``````&-C`#YC?V!C/@````!@,!@`.!@8&!@\``````8,&``X&!@8&#P`
+M````&#QF`#@8&!@8/```````9F8`.!@8&!@\```````V'#8&/F9F9CP`````
+M`#MN`&XS,S,S,P````!@,!@`/F-C8V,^``````8,&``^8V-C8SX`````"!PV
+M`#YC8V-C/@``````.VX`/F-C8V,^``````!C8P`^8V-C8SX``````!@8``!^
+M```8&``````````#/F=O>W,^8````&`P&`!F9F9F9CL`````!@P8`&9F9F9F
+M.P`````8/&8`9F9F9F8[``````!F9@!F9F9F9CL`````!@P8`&-F9F8^!F8\
+=`````'@P/C,S,S,^,'@```!F9@!F9F9F/@9F/```
+`
+end
diff --git a/share/syscons/fonts/iso-8x16.fnt b/share/syscons/fonts/iso-8x16.fnt
new file mode 100644
index 000000000000..d08791bbbb7b
--- /dev/null
+++ b/share/syscons/fonts/iso-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 iso-8x16
+M````````````````````````?H&E@8&]F8&!?@```````'[_V___P^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X.
+M&C)XS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"1F_V8D`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````\9L/#V]O#PV8\````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,/G___;P\/#P\,```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````#_VYD8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,/#P\/#P\-F/!@```````##
+MP\/#P]O;_V9F````````P\-F/!@8/&;#PP```````,/#PV8\&!@8&#P`````
+M``#_PX8,&#!@P</_````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P``,#`8````````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````X;&1@\&!@8&#P````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````YO_;V]O;
+MVP```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````P\/#PV8\&````````````,/#P]O;_V8```````````##9CP8/&;#````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&!@8&!@8&````````'`8&!@.&!@8&'````````!VW```````
+M```````````````0.&S&QL;^`````````````````````````````````!@\
+M?O__?CP8`````%6J5:I5JE6J5:I5JE6J5:H`B(CXB(B(`#X("`@("````/B`
+M\("`@``^(#P@("````!PB("`B'``/"(\*"0B````@("`@(#X`#X@/"`@(```
+M`#AL;#@````````````````````8&'X8&```_P``````B,BHJ)B(`"`@("`@
+M/@```(B(B(A0(``^"`@("`@``!@8&!@8&!CX````````````````````^!@8
+M&!@8&!@8`````````!\8&!@8&!@8&!@8&!@8&!@?```````````8&!@8&!@8
+M_Q@8&!@8&!@8_P````````````````````````#_````````````````````
+M````_P````````````````````````#_`````````````````````````/\8
+M&!@8&!@8'Q@8&!@8&!@8&!@8&!@8&/@8&!@8&!@8&!@8&!@8&!C_````````
+M````````````_Q@8&!@8&!@8&!@8&!@8&!@8&!@8&!@8&`````P8,&`P&`P`
+M?@`````````P&`P&#!@P`'X``````````G[L;&QL;&S,``````````8,?A@8
+M?C!@````````.&QD8/!@8&!@YOP``````````````!@8````````````````
+M`````````````````!@8`!@8&#P\/!@``````!@8?L/`P,##?A@8```````X
+M;&1@\&!@8&#F_`````````""QGS&QL;&?,:"``````##9CP8_QC_&!@8````
+M````&!@8&``8&!@8&```````?,9@.&S&QFPX#,9\`````,8`````````````
+M````````?,:"NJ*BNH+&?```````<!AXR'@`^``````````````````V;-AL
+M-@```````````````/X&!@8&````````````````?`````````````!\QH*Z
+MJK*J@L9\``````#^````````````````````.&QL.```````````````````
+M`!@8?A@8``!^``````!PV#!@R/@`````````````^!@P&-AP````````````
+M&#!@``````````````````````!F9F9F9GYC8,```````'_;V]M[&QL;&QL`
+M`````````````!@8```````````````````````8#`8\````8.!@8&#P````
+M`````````'#8B-AP`/@`````````````````V&PV;-@`````````P,#"QLP8
+M,&;.ECX&!@```,#`PL;,&#!@SIL&#!\```#P,'(V[!@P9LZ6/@8&`````#`P
+M`#`P8,#&QGP`````8#`8`#ALQL;^QL;&``````P8,``X;,;&_L;&Q@`````0
+M.&P`.&S&QO[&QL8``````';<`#ALQL;^QL;&``````#&`!`X;,;&_L;&Q@``
+M```X;#@`.&S&QO[&QL8````````^;,S,_LS,S,S.````````/&;"P,#`PF8\
+M#`9\```P&`P`_F9@?&!@9OX`````&#!@`/YF8'Q@8&;^`````!`X;`#^9F!\
+M8&!F_@``````Q@#^9F!@?&!@9OX`````,!@,`#P8&!@8&!@\``````P8,``\
+M&!@8&!@8/``````8/&8`/!@8&!@8&#P``````&8`/!@8&!@8&!@\````````
+M>&QF9F;V9F9L>`````!VW`#&YO;^WL[&QL8`````8#`8`'S&QL;&QL9\````
+M``P8,`!\QL;&QL;&?``````0.&P`?,;&QL;&QGP`````=MP`?,;&QL;&QL9\
+M``````#&`'S&QL;&QL;&?```````````QFPX$#ALQ@```````@9\SL[>UM;V
+MYN9\P(```&`P&`#&QL;&QL;&?``````,&#``QL;&QL;&QGP`````$#AL`,;&
+MQL;&QL9\``````#&`,;&QL;&QL;&?``````,&#``P\-F/!@8&#P`````\&!\
+M9F9F?&!@8&#P````````.&S&SMS8S,;6W,"`````8#`8`'@,?,S,S'8`````
+M`!@P8`!X#'S,S,QV```````0.&P`>`Q\S,S,=@```````';<`'@,?,S,S'8`
+M``````#,``!X#'S,S,QV```````X;#@`>`Q\S,S,=@```````````&X[&W[8
+MW'<``````````#QF8&!F/`P&/`````!@,!@`?,;^P,#&?```````#!@P`'S&
+M_L#`QGP``````!`X;`!\QO[`P,9\````````Q@``?,;^P,#&?```````8#`8
+M`#@8&!@8&#P```````8,&``X&!@8&!@\```````8/&8`.!@8&!@8/```````
+M`&8``#@8&!@8&#P``````&PX.&P,/&S,S,QX````````=MP`W&9F9F9F9@``
+M````8#`8`'S&QL;&QGP``````!@P8`!\QL;&QL9\```````0.&P`?,;&QL;&
+M?````````';<`'S&QL;&QGP```````#&``!\QL;&QL9\```````````8&`!^
+M`!@8```````````"!GS.WM;VYGS`@````&`P&`#,S,S,S,QV```````8,&``
+MS,S,S,S,=@``````,'C,`,S,S,S,S'8```````#,``#,S,S,S,QV```````8
+M,&``QL;&QL;&?@8,^`````#P8'QF9F9F9GQ@8/````!F9@#N9F9F9F8^!@PX
+!`&``
+`
+end
diff --git a/share/syscons/fonts/iso-8x8.fnt b/share/syscons/fonts/iso-8x8.fnt
new file mode 100644
index 000000000000..5e787e26798b
--- /dev/null
+++ b/share/syscons/fonts/iso-8x8.fnt
@@ -0,0 +1,49 @@
+begin 644 iso-8x8
+M``````````!^@:6!O9F!?G[_V__#Y_]^;/[^_GPX$``0.'S^?#@0`#A\./[^
+M?#A\$!`X?/Y\.'P``!@\/!@``/__Y\/#Y___`#QF0D)F/`#_PYF]O9G#_P\'
+M#WW,S,QX/&9F9CP8?A@_,S\P,'#PX']C?V-C9^;`F5H\Y^<\6IF`X/C^^."`
+M``(./OX^#@(`&#Q^&!A^/!AF9F9F9@!F`'_;VWL;&QL`/F,X;&PXS'@`````
+M?GY^`!@\?AA^/!C_&#Q^&!@8&``8&!@8?CP8```8#/X,&````#!@_F`P````
+M`,#`P/X````D9O]F)````!@\?O__````__]^/!@`````````````,'AX,#``
+M,`!L;&P``````&QL_FS^;&P`,'S`>`SX,```QLP8,&;&`#AL.';<S'8`8&#`
+M```````8,&!@8#`8`&`P&!@8,&```&8\_SQF````,##\,#``````````,#!@
+M````_````````````#`P``8,&#!@P(``?,;.WO;F?``P<#`P,##\`'C,##A@
+MS/P`>,P,.`S,>``</&S,_@P>`/S`^`P,S'@`.&#`^,S,>`#\S`P8,#`P`'C,
+MS'C,S'@`>,S,?`P8<```,#```#`P```P,```,#!@&#!@P&`P&````/P``/P`
+M`&`P&`P8,&``>,P,&#``,`!\QM[>WL!X`#!XS,S\S,P`_&9F?&9F_``\9L#`
+MP&8\`/AL9F9F;/@`_F)H>&AB_@#^8FAX:&#P`#QFP,#.9CX`S,S,_,S,S`!X
+M,#`P,#!X`!X,#`S,S'@`YF9L>&QFY@#P8&!@8F;^`,;N_O[6QL8`QN;VWL[&
+MQ@`X;,;&QFPX`/QF9GQ@8/``>,S,S-QX'`#\9F9\;&;F`'C,X'`<S'@`_+0P
+M,#`P>`#,S,S,S,S\`,S,S,S,>#``QL;&UO[NQ@#&QFPX.&S&`,S,S'@P,'@`
+M_L:,&#)F_@!X8&!@8&!X`,!@,!@,!@(`>!@8&!@8>``0.&S&````````````
+M``#_,#`8`````````'@,?,QV`.!@8'QF9MP```!XS,#,>``<#`Q\S,QV````
+M>,S\P'@`.&Q@\&!@\````';,S'P,^.!@;'9F9N8`,`!P,#`P>``,``P,#,S,
+M>.!@9FQX;.8`<#`P,#`P>````,S^_M;&````^,S,S,P```!XS,S,>````-QF
+M9GQ@\```=LS,?`P>``#<=F9@\````'S`>`SX`!`P?#`P-!@```#,S,S,=@``
+M`,S,S'@P````QM;^_FP```#&;#ALQ@```,S,S'P,^```_)@P9/P`'#`PX#`P
+M'``8&!@`&!@8`.`P,!PP,.``=MP`````````$#ALQL;^```````````````\
+M?O]^&`"J556JJE55JD1$1$0?!`0$?$!`0!\0$!`X1$0X'A$4$T!`0'P?$!`0
+M.&PX`````````!@8&!A^`$1D3$00$!`?1$0H$!\$!`08&!@8^`````````#X
+M&!@8`````!\8&!@8&!@8'P```!@8&!C_&!@8````````````````````````
+M``#_````````````_P```````````!@8&!@?&!@8&!@8&/@8&!@8&!@8_P``
+M``````#_&!@8&!@8&!@8&!@`##!@&`Q^```P#`88,'X````#/C8V;`````1^
+M$'Y````<,#`P,'X`````&````````````````#``,#!X>#`````0?,#`?!``
+M.&!@\&#\``##/&9F/,,``,S,>##\,``8&!@`&!@8`'[`?,9\!OP`Q@``````
+M``!\@KJBNH)\`!P&'B(?/P```#-FS&8S````_@8`````````````````?(*Z
+MLJJ"?`#^`````````#AL.````````!!\$`!\```<-@88/@```!X"#@(>````
+M&#```````````,S,S,QVP'[*RGX*"@H`````&``````````````8,`8.!@8&
+M````#A$1$0X?````S&8S9LP``&#@9FPS9P\#8.!F;#9J!`[P()9L,V</`S``
+M,&#`S'@`&`PP>,S\S`!@P#!XS/S,`'B$,'C,_,P`9I@P>,S\S`#,`#!XS/S,
+M`#!(,'C,_,P`/GB8G/B8G@`\9L#`P&8<,#`8_F)X8OX`&##^8GAB_@`X1/YB
+M>&+^`&8`_F)X8OX`8#!X,#`P>``8,'@P,#!X`'B$>#`P,'@`S`!X,#`P>`!X
+M;&;V9FQX`&:8YO;>SL8`,!A\QL;&?``8,'S&QL9\`#A$?,;&QGP`9IA\QL;&
+M?`#&`'S&QL9\``#&;#@X;,8`!GS.FK+F>,!@,,S,S,S\`!@PS,S,S/P`>(3,
+MS,S,_`#,`,S,S,S\`!@PS,QX,'@`8'AL>&!@8`!XS,3<QL;<P#`8>`Q\S'8`
+M&#!X#'S,=@!XA'@,?,QV`&:8>`Q\S'8`S`!X#'S,=@`P2#@,?,QV````[#)^
+ML&X````\9L!F'#`P&'C,_,!X`!@P>,S\P'@`>(1XS/S`>`#,`'C,_,!X`&`P
+M`'`P,'@`&#``<#`P>`!PB`!P,#!X`,P``'`P,'@`;#AL#&S,>`!FF/C,S,S,
+M`&`P`'S&QGP`&#``?,;&?``X1`!\QL9\`&:8`'S&QGP`Q@``?,;&?````!@`
+M?@`8````!GS>]GS`8#``S,S,=@`8,`#,S,QV`#!(`,S,S'8`S```S,S,=@`8
+7,,S,S'P,^.!X;&9L>.``S`#,S,Q\#/C,
+`
+end
diff --git a/share/syscons/fonts/koi8-8x14.fnt b/share/syscons/fonts/koi8-8x14.fnt
new file mode 100644
index 000000000000..221c3fdfb0f3
--- /dev/null
+++ b/share/syscons/fonts/koi8-8x14.fnt
@@ -0,0 +1,83 @@
+begin 644 koi8-8x14
+M`````````````````````'Z!I8&!I9F!?@``````?O_;___#Y_]^````````
+M;/[^_OY\.!`````````0.'S^?#@0````````&#P\Y^?G&!@\```````8/'[_
+M_WX8&#P``````````!@\/!@``````/______Y\/#Y_______`````#QF0D)F
+M/`````#_____PYF]O9G#_____P``'@X:,GC,S,QX```````\9F9F/!A^&!@`
+M`````#\S/S`P,'#PX```````?V-_8V-C9^?FP``````8&-L\YSS;&!@`````
+M`(#`X/C^^.#`@````````@8./OX^#@8"```````8/'X8&!A^/!@``````&9F
+M9F9F9@!F9@``````?]O;VWL;&QL;`````'S&8#ALQL9L.`S&?```````````
+M`/[^_@``````&#Q^&!@8?CP8?@`````8/'X8&!@8&!@``````!@8&!@8&'X\
+M&``````````8#/X,&````````````#!@_F`P`````````````,#`P/X`````
+M```````H;/YL*```````````$#@X?'S^_@````````#^_GQ\.#@0````````
+M```````````````````8/#P\&!@`&!@`````9F9F)```````````````;&S^
+M;&QL_FQL````&!A\QL+`?`:&QGP8&```````PL8,&#!FQ@``````.&QL.';<
+MS,QV`````#`P,&````````````````P8,#`P,#`8#```````,!@,#`P,#!@P
+M`````````&8\_SQF````````````&!A^&!@`````````````````&!@8,```
+M````````_@`````````````````````8&````````@8,&#!@P(````````!\
+MQL[>]N;&QGP``````!@X>!@8&!@8?@``````?,8&#!@P8,;^``````!\Q@8&
+M/`8&QGP```````P</&S,_@P,'@``````_L#`P/P&!L9\```````X8,#`_,;&
+MQGP``````/[&!@P8,#`P,```````?,;&QGS&QL9\``````!\QL;&?@8&#'@`
+M```````8&````!@8`````````!@8````&!@P```````&#!@P8#`8#`8`````
+M`````'X``'X`````````8#`8#`8,&#!@``````!\QL8,&!@`&!@``````'S&
+MQM[>WMS`?```````$#ALQL;^QL;&``````#\9F9F?&9F9OP``````#QFPL#`
+MP,)F/```````^&QF9F9F9FSX``````#^9F)H>&AB9OX``````/YF8FAX:&!@
+M\```````/&;"P,#>QF8Z``````#&QL;&_L;&QL8``````#P8&!@8&!@8/```
+M````'@P,#`P,S,QX``````#F9FQL>&QL9N8``````/!@8&!@8&)F_@``````
+MQN[^_M;&QL;&``````#&YO;^WL[&QL8``````#ALQL;&QL9L.```````_&9F
+M9GQ@8&#P``````!\QL;&QM;>?`P.`````/QF9F9\;&9FY@``````?,;&8#@,
+MQL9\``````!^?EH8&!@8&#P``````,;&QL;&QL;&?```````QL;&QL;&;#@0
+M``````#&QL;&UM;^?&P``````,;&;#@X.&S&Q@``````9F9F9CP8&!@\````
+M``#^QHP8,&#"QOX``````#PP,#`P,#`P/```````@,#@<#@<#@8"```````\
+M#`P,#`P,##P````0.&S&`````````````````````````````/\`,#`8````
+M`````````````````'@,?,S,=@``````X&!@>&QF9F9\``````````!\QL#`
+MQGP``````!P,##QLS,S,=@``````````?,;^P,9\```````X;&1@\&!@8/``
+M`````````';,S,Q\#,QX````X&!@;'9F9F;F```````8&``X&!@8&#P`````
+M``8&``X&!@8&9F8\````X&!@9FQX;&;F```````X&!@8&!@8&#P`````````
+M`.S^UM;6Q@``````````W&9F9F9F``````````!\QL;&QGP``````````-QF
+M9F9\8&#P````````=LS,S'P,#!X```````#<=F9@8/```````````'S&<!S&
+M?```````$#`P_#`P,#8<``````````#,S,S,S'8``````````&9F9F8\&```
+M````````QL;6UOYL``````````#&;#@X;,8``````````,;&QL9^!@SX````
+M````_LP8,&;^```````.&!@8<!@8&`X``````!@8&!@`&!@8&```````<!@8
+M&`X8&!AP``````!VW```````````````````$#ALQL;^``````````````#_
+M````````&!@8&!@8&!@8&!@8&!@`````````'Q@8&!@8&`````````#X&!@8
+M&!@8&!@8&!@8&!\````````8&!@8&!@8^````````!@8&!@8&!@?&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@`````````_Q@8&!@8&!@8&!@8&!C_````````&!@8
+M&!@8&/\8&!@8&!C_________``````````````````#_________________
+M___________P\/#P\/#P\/#P\/#P\`\/#P\/#P\/#P\/#P\/$4011!%$$401
+M1!%$$415JE6J5:I5JE6J5:I5JMUWW7?==]UWW7?==]UW```.&QL8&!@8&!@8
+M&!@`````?'Q\?'Q\`````````````!@8``````````\,#`P,#.QL/!P`````
+M````=MP`=MP`````````#!@P8#`8#`!^```````P&`P&#!@P`'X`````````
+M`````````````!@8&!@8&!@8V-AP`````#AL;#@`````````````<-@P8,CX
+M```````````````````8````````````&!@`?@`8&````````````/\`_P``
+M`````#8V-C8V-C8V-C8V-C8V```````?&!\8&!@8&!@``&QL`'S&_,#&?```
+M```````````_-C8V-C8V```````_,#<V-C8V-C8``````/@8^!@8&!@8&```
+M``````#^-C8V-C8V``````#^!O8V-C8V-C88&!@8&!\8'P```````#8V-C8V
+M-C8_````````-C8V-C8W,#\````````8&!@8&/@8^````````#8V-C8V-C;^
+M````````-C8V-C;V!OX````````8&!@8&!\8'Q@8&!@8&#8V-C8V-C8W-C8V
+M-C8V-C8V-C8W,#<V-C8V-C88&!@8&/@8^!@8&!@8&&QL`/[&P/#`P,;^````
+M-C8V-C8V-O8V-C8V-C8V-C8V-O8&]C8V-C8V-@``````_P#_&!@8&!@8````
+M`````/\V-C8V-C8``````/\`]S8V-C8V-A@8&!@8_P#_````````-C8V-C8V
+M-O\````````V-C8V-O<`_P```````!@8&!@8_QC_&!@8&!@8-C8V-C8V-O\V
+M-C8V-C8V-C8V-O<`]S8V-C8V-@``?(*ZJJ*BJKJ"?`````````"<MK;VMIP`
+M`````````'S&QO[&Q@``````````_L#\QL;\``````````#,S,S,S/X&#```
+M`````#QL;&QL_L:"````````?,;\P,9\`````````!!\UM;6UGP0.```````
+M`/["P,#`P```````````QFPX.&S&``````````#&SM[VYL8````````,&,;.
+MWO;FQ@``````````QLSXV,S&```````````^9F9F9L8``````````,;N_M;&
+MQ@``````````QL;&_L;&``````````!^QL;&QOP``````````/[&QL;&Q@``
+M````````?L9^-F;&``````````#\QL;&QOS`P````````'S&P,#&?```````
+M````?EH8&!@8``````````#&QL;&QGX&?````````-;6?-;6U@``````````
+M_,;\QL;\``````````#`P/S&QOP``````````,;&YK:VY@``````````?,8<
+M!L9\``````````#6UM;6UOX``````````'S&'@;&?```````````UM;6UM;^
+M`@8```````#&QL9^!@8``````````.!@?&9F?```````G+:VMO:VMK:<````
+M```^9L;&QO[&QL8``````/[`P/S&QL;&_```````S,S,S,S,S,S^`@8````\
+M;&QL;&QL;/[&@@```/[&P,#PP,#&_@``````?-;6UM;6?!`X``````#^QL#`
+MP,#`P,```````,;&;#@X;,;&Q@``````QL;&SM[VYL;&``````S:QL;.WO;F
+MQL8``````,;,V/#PV,S&Q@``````'C9FQL;&QL;&``````""QL;N[O[6QL8`
+M`````,;&QL;^QL;&Q@``````?L;&QL;&QL;\``````#^QL;&QL;&QL8`````
+M`'[&QL;&?C9FQ@``````_,;&QL;\P,#```````!\QL;`P,#&QGP``````'Y^
+M6A@8&!@8&```````QL;&QL9^!L9\``````#6UM94?-;6UM8``````/S&QL;\
+MQL;&_```````P,#`_,;&QL;\``````#&QL;FMK:VMN8``````'S&!AP&!L;&
+M?`````#6UM;6UM;6UM;^``````!\Q@8>!@;&QGP`````UM;6UM;6UM;6_@(&
+=````QL;&QL9^!@8&``````#@X&!\9F9F9GP`````
+`
+end
diff --git a/share/syscons/fonts/koi8-8x16.fnt b/share/syscons/fonts/koi8-8x16.fnt
new file mode 100644
index 000000000000..4648e8839be2
--- /dev/null
+++ b/share/syscons/fonts/koi8-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 koi8-8x16
+M````````````````````````?H&E@8&EF8&!?@```````'[_V___V^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X&
+M#AIXS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P``,#`8````````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````X;&1@\&!@8&#P````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````9F9F9F8\&````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&``8&!@8&````````'`8&!@.&!@8&'````````!VW```````
+M```````````````0.&S&QL;^````````````````_P``````````&!@8&!@8
+M&!@8&!@8&!@8&``````````?&!@8&!@8&!@`````````^!@8&!@8&!@8&!@8
+M&!@8&!\``````````!@8&!@8&!CX```````````8&!@8&!@8'Q@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&`````````#_&!@8&!@8&!@8&!@8&!@8_P``````
+M````&!@8&!@8&/\8&!@8&!@8&/________\`````````````````````____
+M______________________________#P\/#P\/#P\/#P\/#P\/`/#P\/#P\/
+M#P\/#P\/#P\/$4011!%$$4011!%$$4011%6J5:I5JE6J5:I5JE6J5:K==]UW
+MW7?==]UWW7?==]UW```.&QL8&!@8&!@8&!@8&`````!\?'Q\?'Q\````````
+M````````&!@```````````\,#`P,#.QL;#P<````````````=MP`=MP`````
+M```````,&#!@,!@,`'X`````````,!@,!@P8,`!^````````````````````
+M```````8&!@8&!@8&-C8V'```````#AL;#@```````````````!PV#!@R/@`
+M`````````````````````!@``````````````!@8`'X`&!@`````````````
+M_P#_```````````V-C8V-C8V-C8V-C8V-C8V```````?&!\8&!@8&!@8&```
+M;&P`?,;&_,#&?```````````````/S8V-C8V-C8V```````_,#<V-C8V-C8V
+M-@``````^!CX&!@8&!@8&!@`````````_C8V-C8V-C8V``````#^!O8V-C8V
+M-C8V-A@8&!@8'Q@?```````````V-C8V-C8V/P``````````-C8V-C8W,#\`
+M`````````!@8&!@8^!CX```````````V-C8V-C8V_@``````````-C8V-C;V
+M!OX``````````!@8&!@8'Q@?&!@8&!@8&!@V-C8V-C8V-S8V-C8V-C8V-C8V
+M-C8W,#<V-C8V-C8V-A@8&!@8^!CX&!@8&!@8&!AF9@#^QL#`\,#`QOX`````
+M-C8V-C8V-O8V-C8V-C8V-C8V-C8V]@;V-C8V-C8V-C8``````/\`_Q@8&!@8
+M&!@8`````````/\V-C8V-C8V-@``````_P#W-C8V-C8V-C88&!@8&/\`_P``
+M````````-C8V-C8V-O\``````````#8V-C8V]P#_```````````8&!@8&/\8
+M_Q@8&!@8&!@8-C8V-C8V-O\V-C8V-C8V-C8V-C8V]P#W-C8V-C8V-C8``'R"
+MNJJBHJ*JNH)\``````````"<MK;VMK:<````````````?,;&QO[&Q@``````
+M`````/[`_,;&QOP```````````#,S,S,S,S^!@P`````````/&QL;&QL_L:"
+M`````````'S&QOS`QGP``````````!!\UM;6UM9\$#@`````````_L;"P,#`
+MP````````````,9L.#ALQL8```````````#&QL[>]N;&``````````P8QL;.
+MWO;FQ@```````````,;,V/C8S,8````````````^9F9F9F;&````````````
+MQN[^UL;&Q@```````````,;&QO[&QL8```````````!^QL;&QL;\````````
+M````_L;&QL;&Q@```````````'[&QGXV9L8```````````#\QL;&QL;\P,#`
+M````````?,;`P,+&?````````````'Y:&!@8&!@```````````#&QL;&QL9^
+M!L9\````````UM;6?-;6U@```````````/S&QOS&QOP```````````#`P/S&
+MQL;\````````````QL;FMK:VY@```````````'S&!AP&QGP```````````#6
+MUM;6UM;^````````````?,8&'@;&?````````````-;6UM;6UOX"!@0`````
+M``#&QL;&?@8&````````````X&!\9F9F?````````)RVMK;VMK:VMIP`````
+M```^9L;&QO[&QL;&````````_L#`P/S&QL;&_````````,S,S,S,S,S,S/X"
+M!@0````\;&QL;&QL;&S^QH(`````_L;`P/#`P,#&_@```````'S6UM;6UM9\
+M$#@```````#^QL#`P,#`P,#`````````QL9L.#ALQL;&Q@```````,;&QL;.
+MWO;FQL8```````S:QL;&SM[VYL;&````````QLS8\/#8S,;&Q@```````!XV
+M9L;&QL;&QL8```````#&QN[N_O[6UL;&````````QL;&QO[&QL;&Q@``````
+M`'[&QL;&QL;&QOP```````#^QL;&QL;&QL;&````````?L;&QL9^-F;&Q@``
+M`````/S&QL;&QOS`P,````````!\QL;`P,#`QL9\````````?GY:&!@8&!@8
+M&````````,;&QL;&QGX&QGP```````#6UM94?-;6UM;6````````_,;&QOS&
+MQL;&_````````,#`P,#\QL;&QOP```````#&QL;&YK:VMK;F````````?,8&
+M!AP&!L;&?````````-;6UM;6UM;6UOX```````!XS`8&'AX&!LQX````````
+MUM;6UM;6UM;6_@(&!````,;&QL;&?@8&!@8```````#@X&!@?&9F9F9\````
+!`-;6
+`
+end
diff --git a/share/syscons/fonts/koi8-8x8.fnt b/share/syscons/fonts/koi8-8x8.fnt
new file mode 100644
index 000000000000..ec262866bb89
--- /dev/null
+++ b/share/syscons/fonts/koi8-8x8.fnt
@@ -0,0 +1,49 @@
+begin 644 koi8-8x8
+M``````````!^@:6!O9F!?G[_V__#Y_]^;/[^_GPX$``0.'S^?#@0`#A\./[^
+M?#A\$!`X?/Y\.'P``!@\/!@``/__Y\/#Y___`#QF0D)F/`#_PYF]O9G#_P\'
+M#WW,S,QX/&9F9CP8?A@_,S\P,'#PX']C?V-C9^;`F5H\Y^<\6IF`X/C^^."`
+M``(./OX^#@(`&#Q^&!A^/!AF9F9F9@!F`'_;VWL;&QL`/F,X;&PXS'@`````
+M?GY^`!@\?AA^/!C_&#Q^&!@8&``8&!@8?CP8```8#/X,&````#!@_F`P````
+M`,#`P/X````D9O]F)````!@\?O__````__]^/!@`````````````,'AX,#``
+M,`!L;&P``````&QL_FS^;&P`,'S`>`SX,```QLP8,&;&`#AL.';<S'8`8&#`
+M```````8,&!@8#`8`&`P&!@8,&```&8\_SQF````,##\,#``````````,#!@
+M````_````````````#`P``8,&#!@P(``?,;.WO;F?``P<#`P,##\`'C,##A@
+MS/P`>,P,.`S,>``</&S,_@P>`/S`^`P,S'@`.&#`^,S,>`#\S`P8,#`P`'C,
+MS'C,S'@`>,S,?`P8<```,#```#`P```P,```,#!@&#!@P&`P&````/P``/P`
+M`&`P&`P8,&``>,P,&#``,`!\QM[>WL!X`#!XS,S\S,P`_&9F?&9F_``\9L#`
+MP&8\`/AL9F9F;/@`_F)H>&AB_@#^8FAX:&#P`#QFP,#.9CX`S,S,_,S,S`!X
+M,#`P,#!X`!X,#`S,S'@`YF9L>&QFY@#P8&!@8F;^`,;N_O[6QL8`QN;VWL[&
+MQ@`X;,;&QFPX`/QF9GQ@8/``>,S,S-QX'`#\9F9\;&;F`'C,X'`<S'@`_+0P
+M,#`P>`#,S,S,S,S\`,S,S,S,>#``QL;&UO[NQ@#&1&PX.&S&`,S,S'@P,'@`
+M_L:,&#)F_@!X8&!@8&!X`,!@,!@,!@(`>!@8&!@8>``0.&S&````````````
+M``#_,#`8`````````'@,?,Q\`&!@8'QF9GP```!XS,#,>``,#`Q\S,Q\````
+M>,S\P'@`.&Q@\&!@\````'S,S'P,^&!@?&9F9F8`,`!P,#`P>``,``P,#`QL
+M.&!@9FQX;&8`<#`P,#`P>````,S^_M;&````^,S,S,P```!XS,S,>````'QF
+M9GQ@8```?,S,?`P,``#<=F9@\````'S`>`SX`!`P?#`P-!@```#,S,S,?```
+M`,S,S'@P````QM;^_FP```#&;#ALQ@```,S,S'P,^```_)@P9/P`'#`PX#`P
+M'``8&!@`&!@8`.`P,!PP,.``=MP`````````$#ALQL;^`````/\`````&!@8
+M&!@8&!@````?&!@8&````/@8&!@8&!@8'P`````8&!CX`````!@8&!\8&!@8
+M&!@8^!@8&!@```#_&!@8&!@8&/\`````&!@8_Q@8&!C___\``````````/__
+M_______________P\/#P\/#P\`\/#P\/#P\/$4011!%$$415JE6J5:I5JMUW
+MW7?==]UW#AL;&!@8&!@``'Q\?'P````````8`````P(&!,QH.!``=MP`=MP`
+M```,&#!@,!@,`#`8#`8,&#```````$)^`!@8&!@8V-AP`#AL;#@````P2!`@
+M>````````#@X`````!@8`'X`&!@`_P#_`````#8V-C8V-C8V`!\8'Q@8&!@D
+M`#QF?F`\`````#\V-C8V`#\P-S8V-C8`^!CX&!@8&````/XV-C8V`/X&]C8V
+M-C88'Q@?`````#8V-C\`````-C<P/P`````8^!CX`````#8V-OX`````-O8&
+M_@`````8'Q@?&!@8&#8V-C<V-C8V-C<P-S8V-C88^!CX&!@8&&8`?F!\8'X`
+M-C8V]C8V-C8V]@;V-C8V-@#_`/\8&!@8````_S8V-C8`_P#W-C8V-AC_`/\`
+M````-C8V_P`````V]P#_`````!C_&/\8&!@8-C8V_S8V-C8V]P#W-C8V-CQ"
+MF:&AF4(\``#.V_O;S@```'@,?,QV```\8#QF9CP```!F9F9F?P,``#QL;&S^
+MQ@``/&9^8#P```!^V]M^&````'Y@8&!@````9CP8/&8```!F;GYV9@``&&9N
+M?G9F````9FQX;&8````>-F9F9@```,;^_M;&````9F9^9F8````\9F9F/```
+M`'YF9F9F````/F8^-F8```!\9F9\8````#QF8&8\````?A@8&!@```!F9CX&
+M/````-M^/'[;````?&9\9GP```!@8'QF?````,;&]M[V````/&8,9CP```#;
+MV]O;_P```'P&/@9\````V]O;V_\#``!F9CX&!@```.!@?&9\`,[;V_O;V\X`
+M'C9F9GYF9@!\8&!\9F9\`&9F9F9F9G\#.&QL;&QL_L9^8&!\8&!^`'[;V]M^
+M&!@`?F!@8&!@8`!F9CP8/&9F`&9F;GYV9F8`/&9N?G9F9@!F;'AP>&QF`!XV
+M9F9F9F8`QN[^_M;&Q@!F9F9^9F9F`#QF9F9F9CP`?F9F9F9F9@`^9F9F/C9F
+M`'QF9F9\8&``/&9@8&!F/`!^&!@8&!@8`&9F9CX&9CP`V]M^/'[;VP!\9F9\
+M9F9\`&!@8'QF9GP`QL;&]M[>]@`\9@8<!F8\`-O;V]O;V_\`>(P&/@:,>`#;
+7V]O;V]O_`V9F9CX&!@8`X&!@?&9F?``<
+`
+end
diff --git a/share/syscons/fonts/koi8b-8x16 b/share/syscons/fonts/koi8b-8x16
new file mode 100644
index 000000000000..1a34e5f090e3
--- /dev/null
+++ b/share/syscons/fonts/koi8b-8x16
Binary files differ
diff --git a/share/syscons/fonts/koi8b-8x16.fnt b/share/syscons/fonts/koi8b-8x16.fnt
new file mode 100644
index 000000000000..b64dc266e222
--- /dev/null
+++ b/share/syscons/fonts/koi8b-8x16.fnt
@@ -0,0 +1,95 @@
+begin 664 koi8b-8x16
+M``````````````!$`````````'Z!I8&!O9F!@7X```````!^_]O__\/G__]^
+M````````9O____]^?CP\&!@`````&!@\/'Y^_WY^/#P8&``````8/#P89O__
+M9A@\?@`````8&#P\?O___WX8/'X`````````&#P\/!@```````#______^?#
+MP\/G________`````#QF0D)"9CP``````/_____#F;V]O9G#______\````>
+M#AHR>,S,S,QX````````/&9F9F8\&'X8&````````#\S,S\P,#!P\.``````
+M``!_8V-_8V-C9^?FP```````&!C;/.?G/-L8&````````(#`X/C^_OC@P(``
+M```````"!@X^_OX^#@8"`````!@\?A@8&!@8&!@8&'X\&```9F9F9F9F9F9F
+M`&9F`````'_;V]O;VWL;&QL;&P````!\QF`X;,;&;#@,QGP`````````````
+M`/[^_O[^`````!@\?A@8&!@8?CP8?@```!@\?O\8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@8_WX\&`````````@,#O\.#`@````````````0,'#_<#`0````````
+M`````,#`P,#^_@`````````````D9O]F)````````````!`0.#A\?/[^````
+M``````#^_GQ\.#@0$````````````````````````````!@\/#P\&!@8&``8
+M&`````!C8\8`````````````````;&QL_OYL;&S^_FQL;````!A^V]OH>#P>
+M%]O;?A@8``#FINP,&!@P,&!NRLX`````.&QL;#@X;<W&QLMS`````!@8,```
+M```````````````,&!@P,#`P,#`P&!@,````,!@8#`P,#`P,#!@8,```````
+M`&9F//__/&9F````````````&!A^?A@8`````````````````````!@8,```
+M`````````'Y^````````````````````````&!@`````!@8,#!@8,#!@8,#`
+M`````'S&QL;.WO;FQL;&?``````8.'@8&!@8&!@8&'X`````/&;#PP,&#!@P
+M8,/_`````/[&#!@\!@,#`\-F/``````<'#P\;&S,S?\-#!X`````_L#`P/SF
+MPP,#PV8\`````#QFQL#\YL/#P\-F/`````#^Q@8,#!@8,#`P,#``````/&;#
+MPV8\9L/#PV8\`````#QFP\/#PV<_`V-F/```````````&!@`````&!@`````
+M`````!@8`````!@8,``````#!@P8,'`P&`P&`P``````````?GX`?GX`````
+M`````,!@,!@,!@P8,&#``````#QFP\,#!@P8&``8&````````'[#P]_;V][`
+MP'P`````$#A\[L;&QL;^QL;&`````/YC8V-C?F-C8V-C_@`````\9L/#P,#`
+MP,/#9CP`````_&9C8V-C8V-C8V;\`````/]C86!D?&1@8&%C_P````#_8V%@
+M9'QD8&!@8/@`````/&;#P\#`S\/#PV<]`````,;&QL;&_L;&QL;&Q@`````\
+M&!@8&!@8&!@8&#P`````#P8&!@8&!@;&QL9\`````.-C9F9L?&QF9F-CXP``
+M``#P8&!@8&!@8&!A8_\`````P^?__]O;V\/#P\/#`````,;&YN;V]M[>SL[&
+MQ@`````\9L/#P\/#P\/#9CP`````_F-C8V-C?F!@8&#P`````#QFP\/#P\/#
+MR\]^/`8'``#^8V-C8V-^;&9F9O<`````?L/#P,!^`P,#P\-^`````/_;F1@8
+M&!@8&!@8/`````#&QL;&QL;&QL;&QGP`````QL;&QL;&QL;&?#@0`````,/#
+MP\/;V]O;V_]F9@````#&QFQL.#@X.&QLQL8`````P\/#P^=^/!@8&!@\````
+M`/[&C`P8&#`P8&+&_@`````\,#`P,#`P,#`P,#P`````P,!@8#`P&!@,#`8&
+M`````#P,#`P,#`P,#`P,/``````8/&;#````````````````````````````
+M````_P```#`P&```````````````````````/`8^9F9F9CL`````X&!@8'YC
+M8V-C8V/>``````````!\QL#`P,#&?``````.!@8&?L;&QL;&QGL`````````
+M`'S&QO[`P,9\`````#QF9F#P8&!@8&!@\```````````>\;&QL;&QGX&QGP`
+MX&!@8'QF9F9F9F;F```````8&``X&!@8&!@8/```````!@8`#@8&!@8&!@9F
+M9CP`X&!@8&9F;'AL9F;F`````#@8&!@8&!@8&!@8/```````````YO_;V]O#
+MP\,``````````-QF9F9F9F9F``````````!\QL;&QL;&?```````````WF-C
+M8V-C8WY@8/```````'O&QL;&QL9^!@8/``````#><V-@8&!@\```````````
+M?,;`<!P&QGP``````!`P,/PP,#`P,#8<``````````#&QL;&QL;&>P``````
+M````QL;&QNY\.!```````````,/#V]O;V_]F``````````#&[GPX.'SNQ@``
+M````````QL;&QL;&QGX,&'```````/[&#!@P8,;^``````X8&!@8<'`8&!@8
+M#@`````8&!@8&```&!@8&!@`````<!@8&!@>'A@8&!AP``````!VW```````
+M````````````````$#ALQL;&_@```````````````/\`````````&!@8&!@8
+M&!@8&!@8&!@8&```````````'Q@8&!@8&!@``````````/@8&!@8&!@8&!@8
+M&!@8&!@?`````````!@8&!@8&!@8^``````````8&!@8&!@8&!\8&!@8&!@8
+M&!@8&!@8&!CX&!@8&!@8&```````````_Q@8&!@8&!@8&!@8&!@8&/\`````
+M````&!@8&!@8&!C_&!@8&!@8&/__________`````````````````````/__
+M______________________________#P\/#P\/#P\/#P\/#P\/`/#P\/#P\/
+M#P\/#P\/#P\/@A""$((0@A""$((0@A""$,,8PQC#&,,8PQC#&,,8PQC8@]H3
+MV(/:$]B#VA/8@]H3```.&QL8&!@8&!@8&!@8&`````!\?'Q\?'Q\````````
+M````````&!@```````````\,#`P,#`P,[&P\'```````````=MP`=MP`````
+M``````P8,&#`8#`8#`!\``````!@,!@,!@P8,&``?@````````````````!"
+M0GX````8&!@8&!@8&!@8V/AP```````X;&QL.`````````````!PB!!@B/@`
+M`````````````````````!@``````````````!@8`'Y^`!@8````````````
+M`/\`_P`````````V-C8V-C8V-C8V-C8V-C8V````````'Q@?&!@8&!@8&```
+M`,8``'S&_L#`QGP``````````````#\V-C8V-C8V````````/S`W-C8V-C8V
+M-@```````/@8^!@8&!@8&!@``````````/XV-C8V-C8V````````_@;V-C8V
+M-C8V-A@8&!@8&!\8'P`````````V-C8V-C8V-C\`````````-C8V-C8V-S`_
+M`````````!@8&!@8&/@8^``````````V-C8V-C8V-OX`````````-C8V-C8V
+M]@;^`````````!@8&!@8&!\8'Q@8&!@8&!@V-C8V-C8V-C<V-C8V-C8V-C8V
+M-C8V-S`W-C8V-C8V-A@8&!@8&/@8^!@8&!@8&!@``&QL`/YF8'Q@8&;^````
+M-C8V-C8V-C;V-C8V-C8V-C8V-C8V-O8&]C8V-C8V-C8```````#_`/\8&!@8
+M&!@8``````````#_-C8V-C8V-@```````/\`]S8V-C8V-C88&!@8&!C_`/\`
+M````````-C8V-C8V-C;_`````````#8V-C8V-O<`_P`````````8&!@8&!C_
+M&/\8&!@8&!@8-C8V-C8V-C;_-C8V-C8V-C8V-C8V-O<`]S8V-C8V-C8````\
+M0IFAH9E"/```````````````SMO;^]O;S@```````````'@,?,S,S'8`````
+M``(&/&!@?&9F9F8\````````````S,S,S,S,_@8&`````````!XV-F9F9O_#
+MPP````````!\QO[`P,9\```````````\&'[;V]O;?A@8/````````'XR,C`P
+M,'@```````````#&;#@X.&S&````````````QL;.UN;&Q@`````````X.,;&
+MSM;FQL8```````````#F;'AX;&;F````````````'C9F9F9F9@``````````
+M`,;N_O[6UL8```````````#&QL;^QL;&````````````?,;&QL;&?```````
+M`````/[&QL;&QL8```````````!^S,S\;,S.````````````W&9F9F9F?&!@
+M\````````'S&P,#`QGP```````````!^6A@8&!@\````````````QL;&QL9^
+M!@;&?````````-;65'Q4UM8```````````#\9F9\9F;\````````````\&!@
+M?&9F_````````````,;&QO;>WO8````````````\9@8,!F8\````````````
+MUM;6UM;6_@```````````#YG`Q\#9SX```````````#6UM;6UM;^`P,`````
+M````QL;&QGX&!@```````````/BP,#XS,WX```````#.V]O;^]O;V]O.````
+M````$#ALQL;^QL;&Q@```````/YB8F!\9F9F9OP```````#,S,S,S,S,S,S^
+M!@8`````'C9F9F9F9F9F_\.!`````/YF8FAX:&!B9OX``````#P8?MO;V]O;
+M?A@\````````_F)B8&!@8&!@\````````,;&;'PX.'QLQL8```````#&QL[.
+MUN;FQL;&`````#@XQL;.SM;FYL;&Q@```````.9F;&QX>&QL9N8````````>
+M-F;&QL;&QL;&````````QN[^_M;&QL;&Q@```````,;&QL;^QL;&QL8`````
+M``!\QL;&QL;&QL9\````````_L;&QL;&QL;&Q@```````#]F9F8^/F9F9N<`
+M``````#\9F9F?&!@8&#P````````/&;"P,#`P,)F/````````'Y:&!@8&!@8
+M&#P```````#&QL;&QGX&!L9\````````UM945'Q\5-;6U@```````/QF9F9\
+M9F9F9OP```````#P8&!@?&9F9F;\````````P\/#P_/;V]O;\P```````'S&
+M!@8\!@8&QGP```````#;V]O;V]O;V]O_````````>,P&)CXF!@;,>```````
+M`-O;V]O;V]O;V_\#`P````#&QL;&QGX&!@8&````````^+`P,#PV-C8V?```
+!`-O;
+`
+end
diff --git a/share/syscons/fonts/koi8c-8x16.fnt b/share/syscons/fonts/koi8c-8x16.fnt
new file mode 100644
index 000000000000..4159dec1b11a
--- /dev/null
+++ b/share/syscons/fonts/koi8c-8x16.fnt
@@ -0,0 +1,95 @@
+begin 644 koi8c-8x16
+M````````````````````````?H&E@8&EF8&!?@```````'[_V___V^?__WX`
+M`````````&S^_O[^?#@0```````````0.'S^?#@0```````````8/#SGY^<8
+M&#P`````````&#Q^__]^&!@\`````````````!@\/!@```````#________G
+MP\/G________```````\9D)"9CP``````/______PYF]O9G#______\``!X&
+M#AIXS,S,S'@````````\9F9F9CP8?A@8````````/S,_,#`P,'#PX```````
+M`']C?V-C8V-GY^;`````````&!C;/.<\VQ@8``````"`P.#P^/[X\.#`@```
+M`````@8.'C[^/AX.!@(````````8/'X8&!A^/!@`````````9F9F9F9F9@!F
+M9@```````'_;V]M[&QL;&QL``````'S&8#ALQL9L.`S&?```````````````
+M_O[^_@```````!@\?A@8&'X\&'X````````8/'X8&!@8&!@8````````&!@8
+M&!@8&'X\&````````````!@,_@P8```````````````P8/Y@,```````````
+M`````,#`P/X``````````````"AL_FPH`````````````!`X.'Q\_OX`````
+M``````#^_GQ\.#@0```````````````````````````````8/#P\&!@8`!@8
+M``````!F9F8D``````````````````!L;/YL;&S^;&P`````&!A\QL+`?`8&
+MAL9\&!@```````#"Q@P8,&#&A@```````#AL;#AVW,S,S'8``````#`P,&``
+M````````````````#!@P,#`P,#`8#````````#`8#`P,#`P,&#``````````
+M``!F//\\9@``````````````&!A^&!@````````````````````8&!@P````
+M`````````/X````````````````````````8&````````````@8,&#!@P(``
+M```````X;,;&UM;&QFPX````````&#AX&!@8&!@8?@```````'S&!@P8,&#`
+MQOX```````!\Q@8&/`8&!L9\````````#!P\;,S^#`P,'@```````/[`P,#\
+M!@8&QGP````````X8,#`_,;&QL9\````````_L8&!@P8,#`P,````````'S&
+MQL9\QL;&QGP```````!\QL;&?@8&!@QX```````````8&````!@8````````
+M````&!@````8&#``````````!@P8,&`P&`P&````````````?@``?@``````
+M``````!@,!@,!@P8,&````````!\QL8,&!@8`!@8`````````'S&QM[>WMS`
+M?````````!`X;,;&_L;&QL8```````#\9F9F?&9F9F;\````````/&;"P,#`
+MP,)F/````````/AL9F9F9F9F;/@```````#^9F)H>&A@8F;^````````_F9B
+M:'AH8&!@\````````#QFPL#`WL;&9CH```````#&QL;&_L;&QL;&````````
+M/!@8&!@8&!@8/````````!X,#`P,#,S,S'@```````#F9F9L>'AL9F;F````
+M````\&!@8&!@8&)F_@```````,;N_O[6QL;&QL8```````#&YO;^WL[&QL;&
+M````````?,;&QL;&QL;&?````````/QF9F9\8&!@8/````````!\QL;&QL;&
+MUMY\#`X`````_&9F9GQL9F9FY@```````'S&QF`X#`;&QGP```````!^?EH8
+M&!@8&!@\````````QL;&QL;&QL;&?````````,;&QL;&QL9L.!````````#&
+MQL;&UM;6_NYL````````QL9L?#@X?&S&Q@```````&9F9F8\&!@8&#P`````
+M``#^QH8,&#!@PL;^````````/#`P,#`P,#`P/`````````"`P.!P.!P.!@(`
+M```````\#`P,#`P,#`P\`````!`X;,8`````````````````````````````
+M````_P``,#`8````````````````````````>`Q\S,S,=@```````.!@8'AL
+M9F9F9GP```````````!\QL#`P,9\````````'`P,/&S,S,S,=@``````````
+M`'S&_L#`QGP````````X;&1@\&!@8&#P````````````=LS,S,S,?`S,>```
+M`.!@8&QV9F9F9N8````````8&``X&!@8&!@\````````!@8`#@8&!@8&!F9F
+M/````.!@8&9L>'AL9N8````````X&!@8&!@8&!@\````````````[/[6UM;6
+MQ@```````````-QF9F9F9F8```````````!\QL;&QL9\````````````W&9F
+M9F9F?&!@\````````';,S,S,S'P,#!X```````#<=F9@8&#P````````````
+M?,9@.`S&?````````!`P,/PP,#`P-AP```````````#,S,S,S,QV````````
+M````9F9F9F8\&````````````,;&UM;6_FP```````````#&;#@X.&S&````
+M````````QL;&QL;&?@8,^````````/[,&#!@QOX````````.&!@8<!@8&!@.
+M````````&!@8&``8&!@8&````````'`8&!@.&!@8&'````````!VW```````
+M```````````````0.&S&QL;^````````````````_P``````````&!@8&!@8
+M&!@8&!@8&!@8&``````````?&!@8&!@8&!@`````````^!@8&!@8&!@8&!@8
+M&!@8&!\``````````!@8&!@8&!CX```````````8&!@8&!@8'Q@8&!@8&!@8
+M&!@8&!@8&/@8&!@8&!@8&`````````#_&!@8&!@8&!@8&!@8&!@8_P``````
+M````&!@8&!@8&/\8&!@8&!@8&/________\`````````````````````____
+M______________________________#P\/#P\/#P\/#P\/#P\/`/#P\/#P\/
+M#P\/#P\/#P\/$4011!%$$4011!%$$4011%6J5:I5JE6J5:I5JE6J5:K==]UW
+MW7?==]UWW7?==]UW```.&QL8&!@8&!@8&!@8&`````!\?'Q\?'Q\````````
+M````````&!@```````````\,#`P,#.QL;#P<````````````=MP`=MP`````
+M```````,&#!@,!@,`'X`````````,!@,!@P8,`!^````````````````````
+M```````8&!@8&!@8&-C8V'```````#AL;#@```````````````!PV#!@R/@`
+M`````````````````````!@``````````````!@8`'X`&!@`````````_L;&
+MQL;&QL;&QOX``````&#P8&QV9F9F9N8&##`````8$`#^PL#`P,#`````````
+M;&P`?,;&_,#&?````````````#QBP/C`8CP```````````!\QL!\!L9\````
+M````&!``>#`P,#`P>````````#8D`'@P,#`P,'@````````,"``\&!@8&!@8
+M&+!@````````/$Q,3DE)S@```````````,S,S/[)R<X```````!@\&!@?&9F
+M9F;F````````&!``QLS8^-C,Q@```````````O[`P,#`P,`````````D&`#&
+MQL;&QL9^!L9\````````QL;&QL;&_A`0.```````!XC+JZBKFX@``````&#X
+M8&!\=F9F9F;G`````!@0_F9B8&!@8&!@\`````!F9@#^QL#`\,#`QOX`````
+M```\9L#`Z-#`P&8\````````?,;&8#@,!L;&?``````,&``\&!@8&!@8&#P`
+M````-B0`/!@8&!@8&!@\``````P8`#P8&!@8&!@8&+!@`````'QL;&QN:6EI
+M:<X```````#,S,S,_LG)R<G.``````#P8&!@?&9F9F9FYP`````8$,;&S-CP
+M\-C,QL8``````@;^P,#`P,#`P,#``````&PXQL;&QL;&?@;&?````````,;&
+MQL;&QL;&QOX0$#@```````"<MK;VMK:<````````````?,;&QO[&Q@``````
+M`````/[`_,;&QOP```````````#,S,S,S,S^!@P`````````/&QL;&QL_L:"
+M`````````'S&QOS`QGP``````````!!\UM;6UM9\$#@`````````_L;"P,#`
+MP````````````,9L.#ALQL8```````````#&QL[>]N;&``````````P8QL;.
+MWO;FQ@```````````,;,V/C8S,8````````````^9F9F9F;&````````````
+MQN[^UL;&Q@```````````,;&QO[&QL8```````````!^QL;&QL;\````````
+M````_L;&QL;&Q@```````````'[&QGXV9L8```````````#\QL;&QL;\P,#`
+M````````?,;`P,+&?````````````'Y:&!@8&!@```````````#&QL;&QL9^
+M!L9\````````UM;6?-;6U@```````````/S&QOS&QOP```````````#`P/S&
+MQL;\````````````QL;FMK:VY@```````````'S&!AP&QGP```````````#6
+MUM;6UM;^````````````?,8&'@;&?````````````-;6UM;6UOX"!@0`````
+M``#&QL;&?@8&````````````X&!\9F9F?````````)RVMK;VMK:VMIP`````
+M```^9L;&QO[&QL;&````````_L#`P/S&QL;&_````````,S,S,S,S,S,S/X"
+M!@0````\;&QL;&QL;&S^QH(`````_L;`P/#`P,#&_@```````'S6UM;6UM9\
+M$#@```````#^QL#`P,#`P,#`````````QL9L.#ALQL;&Q@```````,;&QL;.
+MWO;FQL8```````S:QL;&SM[VYL;&````````QLS8\/#8S,;&Q@```````!XV
+M9L;&QL;&QL8```````#&QN[N_O[6UL;&````````QL;&QO[&QL;&Q@``````
+M`'[&QL;&QL;&QOP```````#^QL;&QL;&QL;&````````?L;&QL9^-F;&Q@``
+M`````/S&QL;&QOS`P,````````!\QL;`P,#`QL9\````````?GY:&!@8&!@8
+M&````````,;&QL;&QGX&QGP```````#6UM94?-;6UM;6````````_,;&QOS&
+MQL;&_````````,#`P,#\QL;&QOP```````#&QL;&YK:VMK;F````````?,8&
+M!AP&!L;&?````````-;6UM;6UM;6UOX```````!XS`8&'AX&!LQX````````
+MUM;6UM;6UM;6_@(&!````,;&QL;&?@8&!@8```````#@X&!@?&9F9F9\````
+!`-;6
+`
+end
diff --git a/share/syscons/keymaps/Makefile b/share/syscons/keymaps/Makefile
index 9ee24f47c9fa..2f9a66c65c8f 100644
--- a/share/syscons/keymaps/Makefile
+++ b/share/syscons/keymaps/Makefile
@@ -1,22 +1,30 @@
-KEYMAPS=danish.cp865.map danish.iso.map german.cp850.map german.iso.map \
- ru.koi8-r.map swedish.cp850.map swedish.iso.map uk.cp850.map uk.iso.map \
- us.iso.map
-KEYMAPS_MK = ${KEYMAPS:R:S/$/.mk/g}
+OLDKEYMAPS=danish.cp865.map danish.iso.map german.cp850.map german.iso.map \
+ ru.koi8-r.map swedish.cp850.map swedish.iso.map uk.cp850.map \
+ uk.iso.map us.iso.map
+
+KEYMAPS=danish.cp865.kbd danish.iso.kbd german.cp850.kbd german.iso.kbd \
+ swedish.cp850.kbd swedish.iso.kbd uk.cp850.kbd uk.iso.kbd \
+ us.iso.kbd ru.koi8-r.kbd
+
+KEYMAPS_MK = ${OLDKEYMAPS:R:S/$/.mk/g}
MAPSDIR = /usr/share/syscons/keymaps
NOMAN = noman
-CLEANFILES += ${KEYMAPS} ${KEYMAPS_MK}
+CLEANFILES += ${OLDKEYMAPS} ${KEYMAPS_MK}
-all: ${KEYMAPS}
+all: ${OLDKEYMAPS}
install:
+ cd ${.CURDIR}; \
install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${KEYMAPS} \
${DESTDIR}${MAPSDIR}
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${OLDKEYMAPS} \
+ ${DESTDIR}${MAPSDIR}
clean:
- -rm -f ${KEYMAPS} ${KEYMAPS_MK} core *.o
+ -rm -f ${OLDKEYMAPS} ${KEYMAPS_MK} core *.o
-${KEYMAPS}: ${.TARGET:R}.mk
+${OLDKEYMAPS}: ${.TARGET:R}.mk
./${.TARGET:R}.mk ${.TARGET}
${KEYMAPS_MK}: ${.TARGET:R} mkkbdfil.c
diff --git a/share/syscons/keymaps/danish.cp865.kbd b/share/syscons/keymaps/danish.cp865.kbd
new file mode 100644
index 000000000000..38a856d95d08
--- /dev/null
+++ b/share/syscons/keymaps/danish.cp865.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc nop nop esc esc nop nop O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '"' nul nul '@' '"' nul nul O
+ 004 '3' '#' nop nop 156 '#' nop nop O
+ 005 '4' 175 nop nop '$' 175 nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '&' nop nop '6' '&' nop nop O
+ 008 '7' '/' nop nop '{' '/' nop nop O
+ 009 '8' '(' esc esc '[' '(' esc esc O
+ 010 '9' ')' gs gs ']' ')' gs gs O
+ 011 '0' '=' nop nop '}' '=' nop nop O
+ 012 '+' '?' nop nop '+' '?' nop nop O
+ 013 ''' '`' nop nop '|' '`' nop nop O
+ 014 del del del del del del del del O
+ 015 ht bs nop nop ht bs nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 134 143 nop nop 229 197 nop nop C
+ 027 '"' '^' rs rs '~' '^' rs rs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 145 146 nop nop 230 198 nop nop C
+ 040 155 157 nop nop 248 216 nop nop C
+ 041 171 '~' nop nop 171 '~' nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 ''' '*' nop nop ''' '*' nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' ';' nop nop ',' ';' nop nop O
+ 052 '.' ':' nop nop '.' ':' nop nop O
+ 053 '-' '_' ns ns '-' '_' ns ns O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' fkey16 fkey16 '*' '*' fkey16 fkey16 O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock nlock nlock nlock nlock nlock nlock O
+ 070 slock slock slock slock slock slock slock slock O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '/' '/' '/' '/' '/' '/' '/' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' '.' '.' '.' '.' '.' '.' N
+ 084 nop nop nop nop nop nop nop nop O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '<' '>' fs fs '\' '>' fs fs O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/danish.iso.kbd b/share/syscons/keymaps/danish.iso.kbd
new file mode 100644
index 000000000000..bfb291049033
--- /dev/null
+++ b/share/syscons/keymaps/danish.iso.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc debug esc O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '"' nul nul '@' '"' nul nul O
+ 004 '3' '#' nop nop 158 '#' nop nop O
+ 005 '4' 164 nop nop '$' 164 nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '&' nop nop '6' '&' nop nop O
+ 008 '7' '/' nop nop '{' '/' nop nop O
+ 009 '8' '(' esc esc '[' '(' esc esc O
+ 010 '9' ')' gs gs ']' ')' gs gs O
+ 011 '0' '=' nop nop '}' '=' nop nop O
+ 012 '+' '?' nop nop '+' '?' nop nop O
+ 013 ''' '`' nop nop '|' '`' nop nop O
+ 014 del del bs bs del del bs bs O
+ 015 ht bs nop nop ht bs nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 229 197 nop nop 134 143 nop nop C
+ 027 '"' '^' rs rs '~' '^' rs rs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 230 198 nop nop 145 146 nop nop C
+ 040 248 216 nop nop 155 157 nop nop C
+ 041 189 167 nop nop 189 167 nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 ''' '*' nop nop ''' '*' nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' ';' nop nop ',' ';' nop nop O
+ 052 '.' ':' nop nop '.' ':' nop nop O
+ 053 '-' '_' ns ns '-' '_' ns ns O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' '*' '*' '*' '*' '*' '*' O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock nlock nlock nlock nlock nlock nlock O
+ 070 slock slock slock slock slock slock slock slock O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 nop '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del boot del N
+ 084 nop nop nop nop nop nop nop nop O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '<' '>' fs fs '\' '>' fs fs O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 cr cr cr cr cr cr cr cr N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' O
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/german.cp850.kbd b/share/syscons/keymaps/german.cp850.kbd
new file mode 100644
index 000000000000..11b2ac75fcb8
--- /dev/null
+++ b/share/syscons/keymaps/german.cp850.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc esc esc O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '"' nop nop 253 253 nop nop O
+ 004 '3' 245 nop nop 252 252 nop nop O
+ 005 '4' '$' nop nop '4' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '&' nop nop '6' '&' nop nop O
+ 008 '7' '/' nop nop '{' '{' nop nop O
+ 009 '8' '(' esc esc '[' '[' esc esc O
+ 010 '9' ')' gs gs ']' ']' gs gs O
+ 011 '0' '=' nop nop '}' '}' nop nop O
+ 012 225 '?' fs fs '\' '\' fs fs O
+ 013 179 180 nop nop 179 180 nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 '@' '@' nul nul C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 129 154 nop nop 129 154 nop nop C
+ 027 '+' '*' nop nop '~' '~' nop nop O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 148 153 nop nop 148 153 nop nop C
+ 040 132 142 nop nop 132 142 nop nop C
+ 041 '^' 248 rs rs '^' 248 rs rs O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '#' ''' nop nop '#' ''' nop nop O
+ 044 'y' 'Y' em em 'y' 'Y' em em C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 230 230 nop nop C
+ 051 ',' ';' nop nop ',' ';' nop nop O
+ 052 '.' ':' nop nop '.' ':' nop nop O
+ 053 '-' '_' ns ns '-' '_' ns ns O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del ',' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '<' '>' nop nop '|' '|' nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/german.iso.kbd b/share/syscons/keymaps/german.iso.kbd
new file mode 100644
index 000000000000..acbfa39f4941
--- /dev/null
+++ b/share/syscons/keymaps/german.iso.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc esc esc O
+ 002 '1' '!' nop nop '`' '`' nop nop O
+ 003 '2' '"' nul nul '@' '@' nul nul O
+ 004 '3' 167 nop nop '#' '#' nop nop O
+ 005 '4' '$' nop nop '4' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '&' rs rs '^' '^' rs rs O
+ 008 '7' '/' esc esc '[' '[' esc esc O
+ 009 '8' '(' nop nop '8' '(' nop nop O
+ 010 '9' ')' gs gs ']' ']' gs gs O
+ 011 '0' '=' nop nop '{' '{' nop nop O
+ 012 223 '?' nop nop '|' '|' nop nop O
+ 013 146 147 nop nop ''' '`' nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 252 220 esc esc '[' '{' esc esc C
+ 027 '+' '*' gs gs ']' '}' gs gs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 246 214 nop nop 246 214 nop nop C
+ 040 228 196 nop nop 228 196 nop nop C
+ 041 '<' '>' fs fs '\' '|' fs fs O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '#' '^' rs rs '`' '~' rs rs O
+ 044 'y' 'Y' em em 'y' 'Y' em em C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' ';' nop nop ',' ';' nop nop O
+ 052 '.' ':' nop nop '.' ':' nop nop O
+ 053 '-' '_' ns ns '-' '_' ns ns O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' ns ns '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' rs rs '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 nop nop nop nop nop nop nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/ru.koi8-r b/share/syscons/keymaps/ru.koi8-r
index 20f263655d85..1014854ed6dd 100644
--- a/share/syscons/keymaps/ru.koi8-r
+++ b/share/syscons/keymaps/ru.koi8-r
@@ -115,7 +115,7 @@ keymap_t keymap = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
@@ -244,7 +244,7 @@ keymap_t keymap = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
diff --git a/share/syscons/keymaps/ru.koi8-r.kbd b/share/syscons/keymaps/ru.koi8-r.kbd
new file mode 100644
index 000000000000..40e3b611c1c6
--- /dev/null
+++ b/share/syscons/keymaps/ru.koi8-r.kbd
@@ -0,0 +1,237 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc nop nop 155 155 debug nop O
+ 002 '1' '!' nop nop 177 161 nop nop O
+ 003 '2' '@' nul nul 178 192 128 128 O
+ 004 '3' '#' nop nop 179 163 nop nop O
+ 005 '4' '$' nop nop 180 164 nop nop O
+ 006 '5' '%' nop nop 181 165 nop nop O
+ 007 '6' '^' rs rs 182 222 158 158 O
+ 008 '7' '&' nop nop 183 166 nop nop O
+ 009 '8' '*' nop nop 184 170 nop nop O
+ 010 '9' '(' nop nop 185 168 nop nop O
+ 011 '0' ')' nop nop 176 169 nop nop O
+ 012 '-' '_' ns ns 173 223 159 159 O
+ 013 '=' '+' nop nop 189 171 nop nop O
+ 014 bs bs del del 136 136 255 255 O
+ 015 ht fkey16 nop nop 137 fkey16 nop nop O
+ 016 'q' 'Q' dc1 dc1 241 209 145 145 C
+ 017 'w' 'W' etb etb 247 215 151 151 C
+ 018 'e' 'E' enq enq 229 197 133 133 C
+ 019 'r' 'R' dc2 dc2 242 210 146 146 C
+ 020 't' 'T' dc4 dc4 244 212 148 148 C
+ 021 'y' 'Y' em em 249 217 153 153 C
+ 022 'u' 'U' nak nak 245 213 149 149 C
+ 023 'i' 'I' ht ht 233 201 137 137 C
+ 024 'o' 'O' si si 239 207 143 143 C
+ 025 'p' 'P' dle dle 240 208 144 144 C
+ 026 '[' '{' esc esc 219 251 155 155 O
+ 027 ']' '}' gs gs 221 253 157 157 O
+ 028 cr cr nl nl 141 141 138 138 O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 225 193 129 129 C
+ 031 's' 'S' dc3 dc3 243 211 147 147 C
+ 032 'd' 'D' eot eot 228 196 132 132 C
+ 033 'f' 'F' ack ack 230 198 134 134 C
+ 034 'g' 'G' bel bel 231 199 135 135 C
+ 035 'h' 'H' bs bs 232 200 136 136 C
+ 036 'j' 'J' nl nl 234 202 138 138 C
+ 037 'k' 'K' vt vt 235 203 139 139 C
+ 038 'l' 'L' ff ff 236 204 140 140 C
+ 039 ';' ':' nop nop 187 186 nop nop O
+ 040 ''' '"' nop nop 167 162 nop nop O
+ 041 '`' '~' nop nop 224 254 nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '\' '|' fs fs 220 252 156 156 O
+ 044 'z' 'Z' sub sub 250 218 154 154 C
+ 045 'x' 'X' can can 248 216 152 152 C
+ 046 'c' 'C' etx etx 227 195 131 131 C
+ 047 'v' 'V' syn syn 246 214 150 150 C
+ 048 'b' 'B' stx stx 226 194 130 130 C
+ 049 'n' 'N' so so 238 206 142 142 C
+ 050 'm' 'M' cr cr 237 205 141 141 C
+ 051 ',' '<' nop nop 172 188 nop nop O
+ 052 '.' '>' nop nop 174 190 nop nop O
+ 053 '/' '?' nop nop 175 191 nop nop O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nl nl 170 170 138 138 O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' 160 160 160 160 O
+ 058 alock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock nlock nlock nlock nlock nlock nlock O
+ 070 slock slock slock slock slock slock slock slock O
+ 071 fkey49 '7' '7' '7' 183 183 183 183 N
+ 072 fkey50 '8' '8' '8' 184 184 184 184 N
+ 073 fkey51 '9' '9' '9' 185 185 185 185 N
+ 074 fkey52 '-' '-' '-' 173 173 173 173 N
+ 075 fkey53 '4' '4' '4' 180 180 180 180 N
+ 076 fkey48 '5' '5' '5' 181 181 181 181 N
+ 077 fkey55 '6' '6' '6' 182 182 182 182 N
+ 078 fkey56 '+' '+' '+' 171 171 171 171 N
+ 079 fkey57 '1' '1' '1' 177 177 177 177 N
+ 080 fkey58 '2' '2' '2' 178 178 178 178 N
+ 081 fkey59 '3' '3' '3' 179 179 179 179 N
+ 082 fkey60 '0' '0' '0' 176 176 176 176 N
+ 083 fkey54 '.' del del 255 255 boot boot N
+ 084 alock alock alock alock alock alock alock alock O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 nop nop nop nop nop nop nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 cr cr nl nl 141 141 138 138 O
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' nop nop 175 175 nop nop O
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 del del 255 255 boot 255 O
+ 104 slock slock slock slock slock slock slock slock O
+ 105 nop nop nop nop nop nop nop nop O
+ 106 nop nop nop nop nop nop nop nop O
+ 107 nop nop nop nop nop nop nop nop O
+ 108 nop nop nop nop nop nop nop nop O
+ 109 nop nop nop nop nop nop nop nop O
+ 110 nop nop nop nop nop nop nop nop O
+ 111 nop nop nop nop nop nop nop nop O
+ 112 nop nop nop nop nop nop nop nop O
+ 113 nop nop nop nop nop nop nop nop O
+ 114 nop nop nop nop nop nop nop nop O
+ 115 nop nop nop nop nop nop nop nop O
+ 116 nop nop nop nop nop nop nop nop O
+ 117 nop nop nop nop nop nop nop nop O
+ 118 nop nop nop nop nop nop nop nop O
+ 119 nop nop nop nop nop nop nop nop O
+ 120 nop nop nop nop nop nop nop nop O
+ 121 nop nop nop nop nop nop nop nop O
+ 122 nop nop nop nop nop nop nop nop O
+ 123 nop nop nop nop nop nop nop nop O
+ 124 nop nop nop nop nop nop nop nop O
+ 125 nop nop nop nop nop nop nop nop O
+ 126 nop nop nop nop nop nop nop nop O
+ 127 nop nop nop nop nop nop nop nop O
+ 128 nop nop nop nop nop nop nop nop O
+ 129 esc esc nop nop 155 155 debug nop O
+ 130 '!' '1' nop nop 177 161 nop nop O
+ 131 '"' '2' nul nul 178 192 128 128 O
+ 132 ''' '3' nop nop 179 163 nop nop O
+ 133 ';' '4' nop nop 180 164 nop nop O
+ 134 ':' '5' nop nop 181 165 nop nop O
+ 135 ',' '6' rs rs 182 222 158 158 O
+ 136 '.' '7' nop nop 183 166 nop nop O
+ 137 '*' '8' nop nop 184 170 nop nop O
+ 138 '(' '9' nop nop 185 168 nop nop O
+ 139 ')' '0' nop nop 176 169 nop nop O
+ 140 '-' '_' ns ns 173 223 159 159 O
+ 141 '=' '+' nop nop 189 171 nop nop O
+ 142 bs bs del del 136 136 255 255 O
+ 143 ht fkey16 nop nop 137 fkey16 nop nop O
+ 144 202 234 dc1 dc1 241 209 145 145 C
+ 145 195 227 etb etb 247 215 151 151 C
+ 146 213 245 enq enq 229 197 133 133 C
+ 147 203 235 dc2 dc2 242 210 146 146 C
+ 148 197 229 dc4 dc4 244 212 148 148 C
+ 149 206 238 em em 249 217 153 153 C
+ 150 199 231 nak nak 245 213 149 149 C
+ 151 219 251 ht ht 233 201 137 137 C
+ 152 221 253 si si 239 207 143 143 C
+ 153 218 250 dle dle 240 208 144 144 C
+ 154 200 232 esc esc 219 251 155 155 C
+ 155 223 255 gs gs 221 253 157 157 C
+ 156 cr cr nl nl 141 141 138 138 O
+ 157 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 158 198 230 soh soh 225 193 129 129 C
+ 159 217 249 dc3 dc3 243 211 147 147 C
+ 160 215 247 eot eot 228 196 132 132 C
+ 161 193 225 ack ack 230 198 134 134 C
+ 162 208 240 bel bel 231 199 135 135 C
+ 163 210 242 bs bs 232 200 136 136 C
+ 164 207 239 nl nl 234 202 138 138 C
+ 165 204 236 vt vt 235 203 139 139 C
+ 166 196 228 ff ff 236 204 140 140 C
+ 167 214 246 nop nop 187 186 nop nop C
+ 168 220 252 nop nop 167 162 nop nop C
+ 169 163 179 nop nop 224 254 nop nop C
+ 170 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 171 '\' '|' fs fs 220 252 156 156 O
+ 172 209 241 sub sub 250 218 154 154 C
+ 173 222 254 can can 248 216 152 152 C
+ 174 211 243 etx etx 227 195 131 131 C
+ 175 205 237 syn syn 246 214 150 150 C
+ 176 201 233 stx stx 226 194 130 130 C
+ 177 212 244 so so 238 206 142 142 C
+ 178 216 248 cr cr 237 205 141 141 C
+ 179 194 226 nop nop 172 188 nop nop C
+ 180 192 224 nop nop 174 190 nop nop C
+ 181 '/' '?' nop nop 175 191 nop nop O
+ 182 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 183 '*' '*' nl nl 170 170 138 138 O
+ 184 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 185 ' ' ' ' ' ' ' ' 160 160 160 160 O
+ 186 alock clock clock clock clock clock clock clock O
+ 187 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 188 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 189 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 190 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 191 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 192 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 193 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 194 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 195 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 196 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 197 nlock nlock nlock nlock nlock nlock nlock nlock O
+ 198 slock slock slock slock slock slock slock slock O
+ 199 fkey49 '7' '7' '7' 183 183 183 183 N
+ 200 fkey50 '8' '8' '8' 184 184 184 184 N
+ 201 fkey51 '9' '9' '9' 185 185 185 185 N
+ 202 fkey52 '-' '-' '-' 173 173 173 173 N
+ 203 fkey53 '4' '4' '4' 180 180 180 180 N
+ 204 fkey48 '5' '5' '5' 181 181 181 181 N
+ 205 fkey55 '6' '6' '6' 182 182 182 182 N
+ 206 fkey56 '+' '+' '+' 171 171 171 171 N
+ 207 fkey57 '1' '1' '1' 177 177 177 177 N
+ 208 fkey58 '2' '2' '2' 178 178 178 178 N
+ 209 fkey59 '3' '3' '3' 179 179 179 179 N
+ 210 fkey60 '0' '0' '0' 176 176 176 176 N
+ 211 fkey54 '.' del del 255 255 boot boot N
+ 212 alock alock alock alock alock alock alock alock O
+ 213 nop nop nop nop nop nop nop nop O
+ 214 nop nop nop nop nop nop nop nop O
+ 215 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 216 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 217 cr cr nl nl 141 141 138 138 O
+ 218 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 219 '/' '/' nop nop 175 175 nop nop O
+ 220 nscr nop debug nop nop nop nop nop O
+ 221 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 222 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 223 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 224 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 225 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 226 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 227 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 228 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 229 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 230 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 231 fkey54 fkey54 del del 255 255 boot 255 O
+ 232 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/swedish.cp850.kbd b/share/syscons/keymaps/swedish.cp850.kbd
new file mode 100644
index 000000000000..057bfa527600
--- /dev/null
+++ b/share/syscons/keymaps/swedish.cp850.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc nop nop nop nop O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '"' nul nul '@' '@' nul nul O
+ 004 '3' '#' nop nop 156 156 nop nop O
+ 005 '4' 207 nop nop '$' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '&' nop nop '6' '&' nop nop O
+ 008 '7' '/' nop nop '{' '{' nop nop O
+ 009 '8' '(' esc esc '[' '[' esc esc O
+ 010 '9' ')' gs gs ']' ']' gs gs O
+ 011 '0' '=' nop nop '}' '}' nop nop O
+ 012 '+' '?' fs fs '\' '\' fs fs O
+ 013 179 180 nop nop 179 180 nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 134 143 nop nop 134 143 nop nop C
+ 027 177 176 rs rs 178 178 nop nop O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 148 153 nop nop 148 153 nop nop C
+ 040 132 142 nop nop 132 142 nop nop C
+ 041 245 171 nop nop 245 171 nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 ''' '*' nop nop ''' '*' nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' ';' nop nop ',' ';' nop nop O
+ 052 '.' ':' nop nop '.' ':' nop nop O
+ 053 '-' '_' ns ns '-' '_' ns ns O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '<' '>' nop nop '|' '|' nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/swedish.iso b/share/syscons/keymaps/swedish.iso
index c6e36107b01c..24f53b22585f 100644
--- a/share/syscons/keymaps/swedish.iso
+++ b/share/syscons/keymaps/swedish.iso
@@ -11,26 +11,26 @@
* DK9210 Aalborg SO Phone: +45 9814 8076
*/
-keymap_t keymap = { 107, /* swedish iso8859 keymap */
+keymap_t keymap = { 105, /* swedish iso8859 keymap */
/* alt
* scan cntrl alt alt cntrl
* code base shift cntrl shift alt shift cntrl shift spcl flgs
* ---------------------------------------------------------------------------
*/
/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
-/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00,
-/* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00,
-/* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00,
-/* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00,
-/* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00,
-/* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00,
-/* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00,
-/* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
-/* sc=0d */ 0xB4, '`', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
@@ -43,8 +43,8 @@ keymap_t keymap = { 107, /* swedish iso8859 keymap */
/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
-/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01,
-/* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 0x00,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
@@ -56,11 +56,11 @@ keymap_t keymap = { 107, /* swedish iso8859 keymap */
/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
-/* sc=27 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01,
-/* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01,
-/* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 0x00,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
-/* sc=2b */ '\'', '*', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
@@ -100,28 +100,26 @@ keymap_t keymap = { 107, /* swedish iso8859 keymap */
/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
-/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
-/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
-/* sc=5c */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
-/* sc=5e */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
-/* sc=5f */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
-/* sc=60 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
-/* sc=61 */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
-/* sc=62 */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
-/* sc=63 */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
-/* sc=64 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
-/* sc=65 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
-/* sc=66 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
-/* sc=67 */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
-/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
-/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
};
diff --git a/share/syscons/keymaps/swedish.iso.kbd b/share/syscons/keymaps/swedish.iso.kbd
new file mode 100644
index 000000000000..f8c348a00e49
--- /dev/null
+++ b/share/syscons/keymaps/swedish.iso.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc debug esc O
+ 002 '1' '!' nop nop nop nop nop nop O
+ 003 '2' '"' nop nop '@' nop nop nop O
+ 004 '3' '#' nop nop 163 nop nop nop O
+ 005 '4' '$' nop nop 164 nop nop nop O
+ 006 '5' '%' nop nop nop nop nop nop O
+ 007 '6' '&' nop nop nop nop nop nop O
+ 008 '7' '/' nop nop '{' nop nop nop O
+ 009 '8' '(' nop nop '[' nop nop nop O
+ 010 '9' ')' nop nop ']' nop nop nop O
+ 011 '0' '=' nop nop '}' nop nop nop O
+ 012 '+' '?' nop nop '\' nop fs nop O
+ 013 128 '`' nop nop nop nop nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 229 197 nop nop '}' ']' nop nop C
+ 027 168 '^' nop nop '~' nop nop nop O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 246 214 nop nop '|' '\' nop nop C
+ 040 228 196 nop nop '{' '[' nop nop C
+ 041 167 189 nop nop '\' '|' nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 ''' '*' nop nop nop nop nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' ';' nop nop nop '<' nop nop O
+ 052 '.' ':' nop nop nop '>' nop nop O
+ 053 '-' '_' ns nop '/' '?' nop nop O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' ns ns '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' rs rs '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del boot del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '<' '>' nop nop '|' nop nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/uk.cp850.kbd b/share/syscons/keymaps/uk.cp850.kbd
new file mode 100644
index 000000000000..f9728bf92f95
--- /dev/null
+++ b/share/syscons/keymaps/uk.cp850.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc esc esc O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '"' nop nop '2' '"' nop nop O
+ 004 '3' 156 nop nop '3' 156 nop nop O
+ 005 '4' '$' nop nop '4' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '^' rs rs '6' '^' rs rs O
+ 008 '7' '&' nop nop '7' '&' nop nop O
+ 009 '8' '*' nop nop '8' '*' nop nop O
+ 010 '9' '(' nop nop '9' '(' nop nop O
+ 011 '0' ')' nop nop '0' ')' nop nop O
+ 012 '-' '_' ns ns '-' '_' ns ns O
+ 013 '=' '+' nop nop '=' '+' nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 '[' '{' esc esc '[' '{' esc esc O
+ 027 ']' '}' gs gs ']' '}' gs gs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 ';' ':' nop nop ';' ':' nop nop O
+ 040 ''' '@' nul nul ''' '@' nul nul O
+ 041 '`' 170 nop nop '|' '|' nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '#' '~' nop nop '#' '~' nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' '<' nop nop ',' '<' nop nop O
+ 052 '.' '>' nop nop '.' '>' nop nop O
+ 053 '/' '?' nop nop '/' '?' nop nop O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '\' '|' fs fs '\' '|' fs fs O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/uk.iso.kbd b/share/syscons/keymaps/uk.iso.kbd
new file mode 100644
index 000000000000..4402e5fa5e3e
--- /dev/null
+++ b/share/syscons/keymaps/uk.iso.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc esc esc esc esc esc esc O
+ 002 '1' '!' nop nop '`' '`' nop nop O
+ 003 '2' '"' nul nul '@' '@' nul nul O
+ 004 '3' 163 nop nop '#' '#' nop nop O
+ 005 '4' '$' nop nop '4' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '^' rs rs '^' '^' rs rs O
+ 008 '7' '&' nop nop '[' '[' esc esc O
+ 009 '8' '*' nop nop '8' '*' nop nop O
+ 010 '9' '(' nop nop ']' ']' gs gs O
+ 011 '0' ')' nop nop '{' '{' nop nop O
+ 012 '-' '_' ns ns '|' '|' ns ns O
+ 013 '=' '+' nop nop '}' '}' nop nop O
+ 014 bs bs del del bs bs del del O
+ 015 ht btab nop nop ht btab nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 '[' '{' esc esc '[' '{' esc esc O
+ 027 ']' '}' gs gs ']' '}' gs gs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 ';' ':' nop nop ';' ':' nop nop O
+ 040 ''' '@' nul nul ''' '@' nul nul O
+ 041 '\' '|' fs fs '\' '\' fs fs O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '#' '~' nop nop '~' '~' nop nop O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' '<' nop nop ',' '<' nop nop O
+ 052 '.' '>' nop nop '.' '>' nop nop O
+ 053 '/' '?' nop nop '/' '?' nop nop O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O
+ 070 slock slock del del slock slock del del O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' ns ns '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' rs rs '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 '\' '|' fs fs '\' '|' fs fs O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/keymaps/us.iso.kbd b/share/syscons/keymaps/us.iso.kbd
new file mode 100644
index 000000000000..51947d36c167
--- /dev/null
+++ b/share/syscons/keymaps/us.iso.kbd
@@ -0,0 +1,109 @@
+# alt
+# scan cntrl alt alt cntrl lock
+# code base shift cntrl shift alt shift cntrl shift state
+# ------------------------------------------------------------------
+ 000 nop nop nop nop nop nop nop nop O
+ 001 esc esc nop nop esc esc nop nop O
+ 002 '1' '!' nop nop '1' '!' nop nop O
+ 003 '2' '@' nul nul '2' '@' nul nul O
+ 004 '3' '#' nop nop '3' '#' nop nop O
+ 005 '4' '$' nop nop '4' '$' nop nop O
+ 006 '5' '%' nop nop '5' '%' nop nop O
+ 007 '6' '^' rs rs '6' '^' rs rs O
+ 008 '7' '&' nop nop '7' '&' nop nop O
+ 009 '8' '*' nop nop '8' '*' nop nop O
+ 010 '9' '(' nop nop '9' '(' nop nop O
+ 011 '0' ')' nop nop '0' ')' nop nop O
+ 012 '-' '_' ns ns '-' '_' ns ns O
+ 013 '=' '+' nop nop '=' '+' nop nop O
+ 014 del del bs bs del del bs bs O
+ 015 ht bs nop nop ht bs nop nop O
+ 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C
+ 017 'w' 'W' etb etb 'w' 'W' etb etb C
+ 018 'e' 'E' enq enq 'e' 'E' enq enq C
+ 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C
+ 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C
+ 021 'y' 'Y' em em 'y' 'Y' em em C
+ 022 'u' 'U' nak nak 'u' 'U' nak nak C
+ 023 'i' 'I' ht ht 'i' 'I' ht ht C
+ 024 'o' 'O' si si 'o' 'O' si si C
+ 025 'p' 'P' dle dle 'p' 'P' dle dle C
+ 026 '[' '{' esc esc '[' '{' esc esc O
+ 027 ']' '}' gs gs ']' '}' gs gs O
+ 028 cr cr nl nl cr cr nl nl O
+ 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O
+ 030 'a' 'A' soh soh 'a' 'A' soh soh C
+ 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C
+ 032 'd' 'D' eot eot 'd' 'D' eot eot C
+ 033 'f' 'F' ack ack 'f' 'F' ack ack C
+ 034 'g' 'G' bel bel 'g' 'G' bel bel C
+ 035 'h' 'H' bs bs 'h' 'H' bs bs C
+ 036 'j' 'J' nl nl 'j' 'J' nl nl C
+ 037 'k' 'K' vt vt 'k' 'K' vt vt C
+ 038 'l' 'L' ff ff 'l' 'L' ff ff C
+ 039 ';' ':' nop nop ';' ':' nop nop O
+ 040 ''' '"' nop nop ''' '"' nop nop O
+ 041 '`' '~' nop nop '`' '~' nop nop O
+ 042 lshift lshift lshift lshift lshift lshift lshift lshift O
+ 043 '\' '|' fs fs '\' '|' fs fs O
+ 044 'z' 'Z' sub sub 'z' 'Z' sub sub C
+ 045 'x' 'X' can can 'x' 'X' can can C
+ 046 'c' 'C' etx etx 'c' 'C' etx etx C
+ 047 'v' 'V' syn syn 'v' 'V' syn syn C
+ 048 'b' 'B' stx stx 'b' 'B' stx stx C
+ 049 'n' 'N' so so 'n' 'N' so so C
+ 050 'm' 'M' cr cr 'm' 'M' cr cr C
+ 051 ',' '<' nop nop ',' '<' nop nop O
+ 052 '.' '>' nop nop '.' '>' nop nop O
+ 053 '/' '?' nop nop '/' '?' nop nop O
+ 054 rshift rshift rshift rshift rshift rshift rshift rshift O
+ 055 '*' '*' nscr nscr '*' '*' nscr nscr O
+ 056 lalt lalt lalt lalt lalt lalt lalt lalt O
+ 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O
+ 058 clock clock clock clock clock clock clock clock O
+ 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O
+ 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O
+ 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O
+ 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O
+ 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O
+ 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O
+ 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O
+ 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O
+ 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O
+ 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O
+ 069 nlock nlock nlock nlock nlock nlock nlock nlock O
+ 070 slock slock slock slock slock slock slock slock O
+ 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N
+ 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N
+ 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N
+ 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N
+ 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N
+ 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N
+ 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N
+ 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N
+ 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N
+ 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N
+ 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N
+ 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N
+ 083 del '.' del del del del del del N
+ 084 ns ns ns ns ns ns ns ns O
+ 085 nop nop nop nop nop nop nop nop O
+ 086 nop nop nop nop nop nop nop nop O
+ 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O
+ 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O
+ 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N
+ 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O
+ 091 '/' '/' '/' '/' '/' '/' '/' '/' N
+ 092 nscr nop debug nop nop nop nop nop O
+ 093 ralt ralt ralt ralt ralt ralt ralt ralt O
+ 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O
+ 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O
+ 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O
+ 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O
+ 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O
+ 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O
+ 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O
+ 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O
+ 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O
+ 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O
+ 104 slock slock slock slock slock slock slock slock O
diff --git a/share/syscons/scrnmaps/Makefile b/share/syscons/scrnmaps/Makefile
index 5a78201820b6..b8efbc528d33 100644
--- a/share/syscons/scrnmaps/Makefile
+++ b/share/syscons/scrnmaps/Makefile
@@ -1,17 +1,23 @@
-SCRMAPS = koi8-r2alt.scr
+OLDSCRMAPS = koi8-r2alt.scr
-SCRMAPS_MK = ${SCRMAPS:R:S/$/.mk/g}
+SCRMAPS = koi8-r2alt.scm
+
+SCRMAPS_MK = ${OLDSCRMAPS:R:S/$/.mk/g}
SCRDIR = /usr/share/syscons/scrnmaps
-CLEANFILES+= ${SCRMAPS} ${SCRMAPS_MK}
+CLEANFILES+= ${OLDSCRMAPS} ${SCRMAPS_MK}
+
NOMAN = noman
-all: ${SCRMAPS}
+all: ${OLDSCRMAPS}
install:
+ cd ${.CURDIR}; \
install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${SCRMAPS} \
${DESTDIR}${SCRDIR}
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${OLDSCRMAPS} \
+ ${DESTDIR}${SCRDIR}
-${SCRMAPS}: ${.TARGET:R}.mk
+${OLDSCRMAPS}: ${.TARGET:R}.mk
./${.TARGET:R}.mk ${.TARGET}
${SCRMAPS_MK}: ${.TARGET:R} mkscrfil.c
diff --git a/share/syscons/scrnmaps/koi8-r2alt.scm b/share/syscons/scrnmaps/koi8-r2alt.scm
new file mode 100644
index 000000000000..1810ae173b25
--- /dev/null
+++ b/share/syscons/scrnmaps/koi8-r2alt.scm
@@ -0,0 +1,9 @@
+begin 444 koi8-r2alt
+M``$"`P0%!@<("0H+#`T.#Q`1$A,4%187&!D:&QP='A\@(2(C)"4F)R@I*BLL
+M+2XO,#$R,S0U-C<X.3H[/#T^/T!!0D-$149'2$E*2TQ-3D]045)35%565UA9
+M6EM<75Y?8&%B8V1E9F=H:6IK;&UN;W!Q<G-T=79W>'EZ>WQ]?G_$L]J_P-G#
+MM,+!Q=_<V]W>L+&R]/[Y^_?S\O_U^/WZ]LVZU?'6R;BWN]33R+Z]O,;'S+7P
+MMKG1TLO/T,K8U\[\[J"AYJ2EY*/EJ*FJJZRMKJ_OX.'BXZ:B[.NGZ.WIY^J>
+?@(&6A(64@Y6(B8J+C(V.CY^0D9*3AH*<FX>8G9F7FN'B
+`
+end
diff --git a/share/tmac/Makefile b/share/tmac/Makefile
index 4f588dc1ce39..4aeb347d2f0c 100644
--- a/share/tmac/Makefile
+++ b/share/tmac/Makefile
@@ -11,12 +11,9 @@ OFILES= tmac.an.v6compat tmac.an6n tmac.an6t tmac.a tmac.cp tmac.doc.old
all clean cleandir depend lint tags:
-strip.sed:
- ln -s ../me/strip.sed strip.sed
-
-beforeinstall: strip.sed
+beforeinstall: ../me/strip.sed
for i in ${MSRCS}; do \
- sed -f strip.sed < $$i > ${DESTDIR}${BINDIR}/tmac/tmac.$$i; \
+ sed -f ../me/strip.sed < $$i > ${DESTDIR}${BINDIR}/tmac/tmac.$$i; \
chown ${BINOWN}.${BINGRP} ${DESTDIR}${BINDIR}/tmac/tmac.$$i; \
chmod 444 ${DESTDIR}${BINDIR}/tmac/tmac.$$i; \
done
diff --git a/share/tmac/doc-syms b/share/tmac/doc-syms
index fc1e2a639834..8a0782920119 100644
--- a/share/tmac/doc-syms
+++ b/share/tmac/doc-syms
@@ -237,11 +237,11 @@
. \}
. if "\\*(A\\n(aP"-ansiC" \{\
. ie \\n(sT==1 \{\
-. ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+. ds b1 \&\\*(tNISO \\*(aa9899:1990\\*(sV
. as b1 (``\\*(tNANSI C\\*(aa'')
. \}
. el \{\
-. ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+. ds b1 \&\\*(tNISO \\*(aa9899:1990\\*(sV
. as b1 (``\\*(tNANSI C\\*(aa'')
. \}
. \}
@@ -255,6 +255,16 @@
. as b1 (``\\*(tNANSI C\\*(aa'')
. \}
. \}
+. if "\\*(A\\n(aP"-isoC-90" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:1990\\*(sV
+. as b1 (``\\*(tNANSI/ISO C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:1990\\*(sV
+. as b1 (``\\*(tNANSI/ISO C\\*(aa'')
+. \}
+. \}
. if "\\*(A\\n(aP"-iso8802-3" \{\
. ie \\n(sT==1 \{\
. ds b1 \&\\*(tNISO \\*(aa8802-3: 1989\\*(sV
diff --git a/share/zoneinfo/Makefile b/share/zoneinfo/Makefile
index b0cbbe14db4c..c1dc520b3ccc 100644
--- a/share/zoneinfo/Makefile
+++ b/share/zoneinfo/Makefile
@@ -34,7 +34,7 @@ TZDIR= ${DESTDIR}/usr/share/zoneinfo
# REDO= right_posix
# below.
-REDO= right_posix
+REDO= posix_right
# If you're running on a System V-style system and don't want lint grief,
# add
diff --git a/sys/conf/files b/sys/conf/files
index 3fdbb5a24850..82cf5c8fd714 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $Id: files,v 1.20 1994/01/25 11:16:01 rgrimes Exp $
+# $Id: files,v 1.22 1994/05/17 22:30:25 jkh Exp $
#
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
@@ -39,6 +39,7 @@ kern/kern_fork.c standard
kern/kern_kinfo.c standard
kern/kern_ktrace.c standard
kern/kern_malloc.c standard
+kern/kern_ntptime.c standard
kern/kern_proc.c standard
kern/kern_prot.c standard
kern/kern_resource.c standard
@@ -132,6 +133,8 @@ netinet/tcp_subr.c optional inet
netinet/tcp_timer.c optional inet
netinet/tcp_usrreq.c optional inet
netinet/udp_usrreq.c optional inet
+netinet/igmp.c optional multicast
+netinet/ip_mroute.c optional inet multicast mrouting
netiso/clnp_debug.c optional iso
netiso/clnp_er.c optional iso
netiso/clnp_frag.c optional iso
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index ab111aa33136..949e4cf49f08 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -32,7 +32,7 @@
# SUCH DAMAGE.
#
# from: @(#)newvers.sh 7.4 (Berkeley) 12/7/90
-# $Id: newvers.sh,v 1.7.2.3 1994/05/01 19:19:34 rgrimes Exp $
+# $Id: newvers.sh,v 1.10 1994/06/28 10:39:08 jkh Exp $
#
if [ ! -r version ]
@@ -44,12 +44,18 @@ fi
touch version
-kernvers="FreeBSD 1.1(Release)"
+ostype="FreeBSD"
+osrelease="1.1.5.1(RELEASE)"
+kernvers="${ostype} ${osrelease}"
v=`cat version` t=`date "+ %m/%d/%y %H:%M"`
t=`date`
user=${USER-root}
host=`hostname`
dir=`pwd`
(
- echo "char version[] = \"${kernvers} ($1) #${v}: ${t}\\n ${user}@${host}:${dir}\\n\";"
+ echo "const char version[] = \"${kernvers} ($1) #${v}: ${t}\\n ${user}@${host}:${dir}\\n\";"
+ echo "const char ostype[] = \"${ostype}\";"
+ echo "const char osrelease[] = \"${osrelease}\";"
+ echo "const int osbuild = ${v};"
+ echo "const char osconfig[] = \"$1\";"
) > vers.c
diff --git a/sys/conf/param.c b/sys/conf/param.c
index 115a3239c44e..1c4fcb161b33 100644
--- a/sys/conf/param.c
+++ b/sys/conf/param.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)param.c 7.20 (Berkeley) 6/27/91
- * $Id: param.c,v 1.9.2.1 1994/05/04 07:44:02 rgrimes Exp $
+ * $Id: param.c,v 1.10 1994/05/04 08:22:05 rgrimes Exp $
*/
#include "sys/param.h"
diff --git a/sys/doc/Changes b/sys/doc/Changes
new file mode 100644
index 000000000000..685f1f3173b5
--- /dev/null
+++ b/sys/doc/Changes
@@ -0,0 +1,277 @@
+Hello, Emacs, this is an -*- Indented-Text -*- file!
+
+$Id: Changes,v 1.5 1994/04/20 19:22:38 wollman Exp $
+
+This file is intended to keep track of important kernel and user
+changes in FreeBSD between releases. Entries are in reverse
+chronological order; userids can be decoded with the chart at the end
+of this file.
+
+---------------
+Since 1.1 BETA:
+---------------
+
+- I/O clustering is implemented for all block devices. This should
+ substantially improve the performance of disk drives which don't
+ have write-behind caches, especially on IDE drives. (dyson/davidg)
+
+- Allow mbufs to point to other ``external'' objects than just
+ clusters, and add in performance enhancements for NFS from Yuval
+ Yarom. (davidg)
+
+- Yet more VM system improvements. (dyson/davidg)
+ o 4-MB systems should now spend substantially less time in the VM
+ system.
+ o General cleanup and some portability fixes.
+ o A new system process is now responsible for keeping page
+ statistics, rather than making the pagedaemon do it, which was
+ getting impractical. Performance is improved on small-memory
+ machines.
+ o Process resource usage counters are now properly updated for
+ faults and swaps.
+
+- Fixed bugs in truncating mapped files. (dyson/davidg)
+
+- A new version of the interrupt-handler glue code has been added, which
+ is faster and architecturally cleaner than the previous version. The
+ beginnings of better profiling support have also been added. (bde/davidg)
+
+- This file moved from /sys/i386/doc to /sys/doc. (wollman)
+
+- Bounce buffers have been implemented for ISA devices which use
+ DMA (although not all devices can make use of it yet). (davidg/dyson)
+
+- The set*id() functions have been changed (wollman):
+ o A significant security hole involving the POSIX saved uid and gid
+ has been plugged.
+ o The setreuid() and setregid() functions now never change the real
+ ID, but rather only ensure that you will be able to change the
+ EFFECTIVE ID back to what you specified as a real ID. This change
+ breaks the setruid() and setrgid() functions, which were a bad
+ idea in a POSIX environment anyway. Logic taken from 4.4BSD.
+ o The SUGID process flag bit has been implemented as in 4.4, and the
+ `ps' program modified to print it out.
+
+- The scheduling algorithm has been changed to penalize
+ processes that fork a lot, like `make', which should enhance
+ interactive performance during such operations significantly.
+ (davidg/dyson)
+
+- MCLBYTES is now 4096, so each mbuf cluster is given a whole page, in
+ preparation for page flipping. (davidg/dyson)
+
+- More VM system improvements (dyson/davidg):
+ o Pre-faulting of initial pages on process startup and mmap (faster
+ than starting and immediately taking a fault).
+ o Even more efficient physical map (pmap) code.
+ o Pageouts are now clustered, similar to pagein clustering in 1.1.
+ o The pageout code is more efficient and keeps better statistics.
+ o The procfs can now provide more information from the VM system.
+ o Some pager bugs have been fixed.
+
+- Improved IP checksum and bzero routines. (bde/dyson)
+
+- The Mitsumi CD-ROM driver is more careful about recognizing Ethernet
+ cards as CD-ROMs. (jkh)
+
+- `struct tty's now allocated dynamically, and ring buffers can be
+ deallocated. (guido)
+
+
+---------------------------
+Between 1.1 BETA and 1.0.2:
+---------------------------
+
+- QIC-40 and QIC-80 tapes are now supported, using the `ft' driver
+ from Jim Babb. (alm/nate)
+
+- Improved lpt driver, should no longer lock up when lprm is done on
+ an active job. Fixed up the probe routine so that it works on most
+ if not all printers now. (csgr/rgrimes)
+
+- Substantial changes to system configuration; you MUST re-build
+ `config' before attempting to build a 1.1 kernel. (nate/martin)
+
+- Improved the quality of the information given to the user when
+ a fatal trap occurs. (davidg)
+
+- Added support in the if_ed driver for the WD8013W, WD8003W, and
+ WD8003EB. (davidg)
+
+- Change to generic console code to eliminate console hangs with all
+ `pc' consoles. (davidg)
+
+- Upgrade to new version of syscons which handles the `hanging console'
+ problem and adds some new features and code cleanup. (nate)
+
+- Various TCP bugs fixed - don't forward loopback packets; Nagel
+ congestion avoidence - immediately ack small packets. (davidg)
+
+- TCP debugging code is now truly optional, thus reducing kernel size
+ when it is disabled (the default). (davidg)
+
+- Because the `sio' FIFOs are now configurable, the `com' driver is no
+ longer supported. (team sighs with relief)
+
+- Performance and stylistic improvements to the `sio' serial driver.
+ Probe code now works somewhat better for oddball devices. The 16550
+ FIFO length is now configurable using `flags' in the config
+ declaration. (ache/bde)
+
+- Performance improvements and complete implementation of POSIX VMIN
+ and VTIME for the generic TTY code. (ache/bde)
+
+- Crash dumps on SCSI disks now work and are standard. (rgrimes/davidg)
+
+- QMAGIC is now the official default executable format. (davidg)
+
+- Network booting is now supported, as is booting from DOS. (martin)
+
+- Local LDTs are now supported for WINE (based on work by John Brezak).
+ (hsu/davidg)
+
+- DDB will now print symbolic arguments and line numbers in
+ backtraces (from John Brezak). (davidg)
+
+- Added four pattern memory test to eliminate problems with buggy
+ chipsets that incorrectly map memory, and to find problems with
+ defective memory. The memory sizing code has been improved to
+ further eliminate problems with buggy chipsets/BIOSs. (davidg)
+
+- USE_486_WRITE_PROTECT is now gone; the system will automatically
+ detect 486 CPUs and behave accordingly. (davidg)
+
+- Added SysV IPC, messaging, and semaphore code by Danny Boulet.
+ (hsu/davidg)
+
+- Because of the VM system changes, Paul Kranenburg's process
+ filesystem is now MANDATORY in order for `ps' and friends to be able
+ to dig up process information which has been paged out. (davidg)
+
+- Substantial VM system improvements: (dyson/davidg)
+ o FreeBSD once again works on 4-MB machines.
+ o Maximum and default size limits set to reasonable values.
+ o The user area is now in the process address space, and can
+ now be paged out along with the rest of the process.
+ o Process page tables can now be paged out.
+ o The physical map (pmap) module has been mostly rewritten for
+ efficiency, and is considerably faster than it used to be.
+ o The pageout system now actually implements modified LRU.
+ o Process RSS soft limits implemented. Hooks are in place for
+ RSS hard limits.
+ o Pagers can now do multiple-page operations ("page fault
+ clustering"), and page fault read behind and read ahead
+ have been implemented to take advantage of this.
+ o The vnode pager no longer drags pages through the buffer
+ cache, eliminating an expensive memory copy and flushing
+ of cached data.
+ o When the system runs out of swap space, the faulting process
+ is killed off (with a message to syslog); the old code would
+ just deadlock.
+ o Swap space allocation is much more efficient, and swap
+ striping actually works now. It's now possible for every
+ last block of swap space to be used before the systems runs
+ out.
+ o The pagedaemon's algorithms are considerably improved, thus
+ reducing the amount of CPU time used by the pagedaemon.
+ o All kernels MUST now load at virtual address 0xf010000, and
+ the lower 640k is reclaimed for system use. This removes
+ the 640K kernel size limit.
+ o VM object cache size is now dynamic and a function of the
+ kernel `maxusers' parameter.
+ o Memory in the I/O hole is explicitly marked non-cacheable.
+
+- Added 3C509 driver written by Herb Peyerl. (ats/nate)
+
+- Added a new `wd' driver which does a much better job of probing, handles
+ stray interrupts better, and supports multiple controllers. In addition
+ this driver supports DOS partitions much better and conforms to ATA specs
+ much better. NB: configuration lines for this driver are different
+ than those for pervious versions; see a GENERIC for details.
+ (nate/bde/guido)
+
+- Added support in the if_ed driver for the Toshiba ethernet cards.The
+ support must be enabled with an "options TOSH_ETHER" in the config
+ file. Done it this way, because I don't know how widespread the cards
+ are. (ats)
+
+- Added support in the if_ed driver for the SMC Ultra via patches from
+ Glen Lowe. (davidg)
+
+- Updated Mitsumi CD driver to work with FX models. (jkh/Gary
+ Clark II)
+
+- Add extended formats set to floppy driver, improve autoconfiguration,
+ add "fdformat" utility for floppy formatting.
+ The format of floppy disk minor numbers has changed, thus
+ necessitating a new `MAKEDEV fd'. (ache/joerg/Serge Vakulenko)
+
+- Add XNTPD to contrib section, and (un-compilable) kernel support for
+ same to /sys/kern. (wollman)
+
+- Use linker-constructed sets to initialize certain system tables
+ rather than manually enumerating all the options in the source files.
+ This makes certain pseudo-devices and all image activators drop-in at
+ link time, if desired. (wollman)
+
+- Added YP code from Theo Deraadt. (paul/nate)
+
+- Make all mandatory options ``standard''. (wollman)
+
+- Update `wt' driver to support more devices and controllers. The
+ driver will also auto-detect tape density on models which support
+ it. The structure of `wt' device minor numbers has changed;
+ `MAKEDEV wt' must be run to create the new device nodes.
+
+- Re-design execve() system call to allow for multiple ``image activators''
+ which recognize and load various file formats. Currently only
+ a.out and interpreted formats are recognized. (davidg)
+
+- Provide the address of the faulting reference to signal handlers, to
+ make life easier for smart garbage-collection algorithms. (hsu)
+
+- New, improved process tracing code from Sean Eric Fagan. (davidg)
+
+- Re-organize locore into several different source files according to
+ function. (davidg)
+
+- On panic, don't reboot right away but give the user some time to
+ abort the reboot or at least write down the panic message. (davidg)
+
+- Kernel timezone handling is now delegated to an external program,
+ `adjkerntz'. No more bogus summer time jumps. (ache)
+
+- Separate all IP-related variables that users might want to modify into
+ netinet/in_var.c. (wollman)
+
+- New, redesigned SCSI system; should run faster and have fewer bugs.
+ (julian)
+
+- Make it possible to mmap(2) /dev/mem. (julian)
+
+
+-----------------------
+Userids map as follows:
+-----------------------
+ache Andrew Chernov
+alm Andrew Moore
+ats Andreas Schulz
+chmr Christoph Robitscho
+csgr Geoff Rehmet
+davidg David Greenman
+dyson John Dyson
+guido Guido van Rooij
+hsu Jeffrey Hsu
+jkh Jordan Hubbard
+joerg Joerg Wunsch
+jtc J.T. Conklin
+ljo L. Jonas Olson
+martin Martin Renters
+nate Nate Williams
+paul Paul Richards
+proven Chris Provenzano
+rich Rich Murphey
+rls Rob Shady
+smace Scott Mace
+swallace Steven Wallace
+wollman Garrett Wollman
diff --git a/sys/doc/Makefile b/sys/doc/Makefile
new file mode 100644
index 000000000000..78e3021c3831
--- /dev/null
+++ b/sys/doc/Makefile
@@ -0,0 +1,19 @@
+# $Id: Makefile,v 1.1 1994/03/30 20:36:32 wollman Exp $
+#
+# Makefile for /sys/i386/doc
+# This creates options.info and options.doc from options.texi, if the
+# GNU makeinfo program is present, and fails miserably otherwise.
+#
+
+all: options.info options.doc
+
+options.info: options.texi
+ makeinfo options.texi
+
+options.doc: options.texi
+ makeinfo -o options.doc+ --no-headers options.texi
+ sed '/^General Index/,$$d' < options.doc+ > options.doc
+ rm -f options.doc+
+
+clean:
+ rm -f options.info options.doc options.doc+
diff --git a/sys/i386/doc/ata/ata-1 b/sys/doc/ata/ata-1
index 5486217b026b..5486217b026b 100644
--- a/sys/i386/doc/ata/ata-1
+++ b/sys/doc/ata/ata-1
diff --git a/sys/i386/doc/ata/ata-10 b/sys/doc/ata/ata-10
index f4c0336944d4..f4c0336944d4 100644
--- a/sys/i386/doc/ata/ata-10
+++ b/sys/doc/ata/ata-10
diff --git a/sys/i386/doc/ata/ata-11 b/sys/doc/ata/ata-11
index bba6a1073cc8..bba6a1073cc8 100644
--- a/sys/i386/doc/ata/ata-11
+++ b/sys/doc/ata/ata-11
diff --git a/sys/i386/doc/ata/ata-2 b/sys/doc/ata/ata-2
index bad2d9eea869..bad2d9eea869 100644
--- a/sys/i386/doc/ata/ata-2
+++ b/sys/doc/ata/ata-2
diff --git a/sys/i386/doc/ata/ata-3 b/sys/doc/ata/ata-3
index 54645e040b7f..54645e040b7f 100644
--- a/sys/i386/doc/ata/ata-3
+++ b/sys/doc/ata/ata-3
diff --git a/sys/i386/doc/ata/ata-4 b/sys/doc/ata/ata-4
index 0c2fb638ce8d..0c2fb638ce8d 100644
--- a/sys/i386/doc/ata/ata-4
+++ b/sys/doc/ata/ata-4
diff --git a/sys/i386/doc/ata/ata-5 b/sys/doc/ata/ata-5
index c120a39b3736..c120a39b3736 100644
--- a/sys/i386/doc/ata/ata-5
+++ b/sys/doc/ata/ata-5
diff --git a/sys/i386/doc/ata/ata-6 b/sys/doc/ata/ata-6
index 1bce4866f5b5..1bce4866f5b5 100644
--- a/sys/i386/doc/ata/ata-6
+++ b/sys/doc/ata/ata-6
diff --git a/sys/i386/doc/ata/ata-7 b/sys/doc/ata/ata-7
index 240706912a85..240706912a85 100644
--- a/sys/i386/doc/ata/ata-7
+++ b/sys/doc/ata/ata-7
diff --git a/sys/i386/doc/ata/ata-8 b/sys/doc/ata/ata-8
index f651b6b49326..f651b6b49326 100644
--- a/sys/i386/doc/ata/ata-8
+++ b/sys/doc/ata/ata-8
diff --git a/sys/i386/doc/ata/ata-9 b/sys/doc/ata/ata-9
index 4cd3f6684989..4cd3f6684989 100644
--- a/sys/i386/doc/ata/ata-9
+++ b/sys/doc/ata/ata-9
diff --git a/sys/i386/doc/ata/ata-apx b/sys/doc/ata/ata-apx
index cd8981c58eab..cd8981c58eab 100644
--- a/sys/i386/doc/ata/ata-apx
+++ b/sys/doc/ata/ata-apx
diff --git a/sys/i386/doc/ata/ata-prt b/sys/doc/ata/ata-prt
index 546510bcf6a0..546510bcf6a0 100644
--- a/sys/i386/doc/ata/ata-prt
+++ b/sys/doc/ata/ata-prt
diff --git a/sys/i386/doc/ata/ata-toc b/sys/doc/ata/ata-toc
index 1866f7677596..1866f7677596 100644
--- a/sys/i386/doc/ata/ata-toc
+++ b/sys/doc/ata/ata-toc
diff --git a/sys/doc/ed.relnotes b/sys/doc/ed.relnotes
new file mode 100644
index 000000000000..c46c26124f8f
--- /dev/null
+++ b/sys/doc/ed.relnotes
@@ -0,0 +1,174 @@
+
+ Release Notes for 'ed' Device Driver
+ David Greenman, 24-May-1993
+ ------------------------------------
+
+Last updated: 22-November-1993
+
+INTRODUCTION
+------------
+ The 'ed' device driver is a new, high performance device driver supporting
+the Western Digital/SMC 80x3 series (including 'EtherCard PLUS' 'Elite16' and
+'Ultra'), the 3Com 3c503 (both 8 and 16 bit versions), and the Novell NE1000/
+NE2000. All of the ethernet controllers use the DS8390, 83C690, or 83C790
+Network Interface Controller (NIC). The differences between the boards are in
+their memory capacity, bus width (8/16 bits), special logic (asic) used to
+configure the board, and the host access method to the NIC memory (shared or
+programmed I/O). Every effort has been made to conform to the manufactures'
+specifications for the NIC and asic. This includes both normal operation and
+error recovery.
+
+PERFORMANCE
+-----------
+
+transmit
+--------
+ The 8390 doesn't provide a mechanism for chained write buffers, so it is
+very important for maximum performance to queue the next packet for
+transmission as soon as the current one has completed. On boards with 16k or
+more of memory, the NIC memory is divided in a way that allows enough space
+for two full size packets to be buffered for transmission. When sufficient
+data is available for transmission, a packet is copied into the NIC memory,
+the transmission is started, and then an additional packet is copied into the
+NIC memory (to a different memory area). As soon as the first packet has
+completed, transmission of a second packet can then be started immediately.
+This results in nearly the highest performance possible from ethernet.
+
+Packets go out on the 'wire' with the following format:
+
+preamble dest-addr src-addr type data FCS intr-frame
+64bits 48bits 48bits 16bits 1500bytes 32bits 96bits
+
+ With 10Mbits/sec, each bit is 100ns in duration. All of the above fields,
+except for data are of fixed length. With full sized packets (1500 bytes), the
+maximum unidirectional data rate can be calculated as: 6.4us + 4.8us + 4.8us +
+1.6us + 1200us + 3.2us + 9.6us = 1230.4us/packet = 812.74382 packets/second =
+1219115.7 (1190k) bytes/second. With TCP, there is a 40 byte overhead for the
+IP and TCP headers, so there is only 1460 bytes of data per packet. This
+reduces the maximum data rate to 1186606 bytes/second. With TCP, there will
+also be periodic acknowledgments which will reduce this figure somewhat both
+because of the additional traffic in the reverse direction and because of the
+occasional collisions that this will cause. Despite this, the data rate has
+still been consistantly measured at 1125000 (~1100k) bytes/second through a TCP
+socket. In these tests, the TCP window was set to 16384 bytes. With UDP, there
+is less overhead for the headers, and with 1472 bytes of data per packet, a
+data rate of 1196358.9 (1168k) bytes/sec is possible. UDP performance hasn't
+been precisely measured with this device driver, but less precise tests show
+this to be true (measured at around 1135k/second).
+
+receive
+-------
+ The 8390 implements an NIC memory ring-buffer to store incoming packets.
+The 8bit boards (8003, 3c503, and NE1000) usually have only 8k bytes of shared
+memory. This is only enough room for about 4 full size (1500 byte) packets.
+This can sometimes be a problem, especially on the original WD8003E and 3c503.
+This is because these boards' NIC memory access speed is also quite slow
+compared to newer 16bit boards - typically less than 1MB/second. The additional
+overhead of this slow memory access, and the fact that there is only room for 4
+full-sized packets means that the ring-buffer will occassionally overflow. When
+this happens, the board must be reset to avoid a lockup problem in early
+revision 8390's. Resetting the board will cause all of the data in the ring-
+buffer to be lost - requiring it to be re-transmitted/received...slowing things
+even further. Because of these problems, maximum throughput on boards of this
+type is only about 400-600k per second. The 16bit boards, however, have 16k of
+memory as well as much faster memory access speed. Typical memory access speed
+on these boards is about 1.7-4MB/second (with the Novell NE2000 being the
+slowest and the SMC 8013 being the fastest). These boards generally have no
+problems keeping up with full ethernet speed. The only problem I've seen with
+these boards is related to the (slow) performance of the BSD Net/2 malloc code
+when additional mbufs must be added to the pool. This can sometimes increase
+the total time to remove a packet enough for a ring-buffer overflow to occur.
+This tends to be highly transient, and quite rare on fast machines. I've only
+seen this problem when doing tests with large amounts of UDP traffic without
+any acknowledgments (uni-directional). Again, this has been very rare.
+
+ All of the above tests were done using a 486DX2/66, 486DX/33, 386DX/40,
+8-9Mhz ISA bus, using FreeBSD 1.0. TCP tests were done with the 'ttcp'
+performance test utility, and also with FTP client/server. UDP tests were done
+with a modified version of ttcp (to work around a bug in the BSD Net/2 UDP
+code related to queue depth), and also with NFS.
+
+KERNEL INSTALLATION
+-------------------
+ (Note that this driver comes standard in FreeBSD 1.0, NetBSD 0.9, and 386BSD
+0.2, and therefore doesn't require installation)
+ To 'install' this driver, the files if_ed.c and if_edreg.h must be copied
+into the i386/isa kernel source directory and the following line must be
+added into the file i386/conf/files.i386:
+
+i386/isa/if_ed.c optional ed device-driver
+
+ To build a kernel that includes this driver, first comment out any 'we',
+'ec', or 'ne' devices in your kernel config file. Then, add a line similar to
+the following (modify to match your cards configuration):
+
+device ed0 at isa? port 0x300 net irq 10 iomem 0xcc000 vector edintr
+
+ Note that the 'iosiz' option is not needed because the driver automatically
+figures this out. However, if you have problems with this, it can be specified
+to force the use of the size you specify.
+ The iomem 0xcc000 option is not need for NE1000/NE2000 boards because they
+use programmed I/O rather than shared memory to access the NIC's memory.
+ On 3Com boards, the tranceiver must be enabled in software (there is no
+hardware default). In this driver, this is controlled using the "LLC0" link-
+level control flag. The default for this flag can be set in your kernel config
+file by specifying 'flags 0x01' in the 'ed' device specification line (this
+is necessary for diskless support). Otherwise, the tranceiver is easily enabled
+and disabled with a command like "ifconfig ed0 -llc0" to enable the tranceiver
+or "ifconfig ed0 llc0" to disable it; this assumes that you have the modified
+ifconfig(8) that originally appeared in the 386BSD patchkit. To specify the
+'flags' option, use a line similar to:
+
+device ed0 at isa? port 0x300 net irq 10 flags 0x01 iomem 0xcc000 vector edintr
+
+ Flags can be similarly specified to force 8 or 16bit mode, and disabling
+the use of transmitter double buffering. The various supported flag values
+are:
+
+ Disable tranceiver 0x01
+ Force 8 bit mode 0x02
+ Force 16 bit mode 0x04
+ Disable multi TX buffering 0x08
+
+ To use multiple flags, simply add the values together. Note that these
+numbers are in hexadecimal. If the 'Force 8 bit' and 'Force 16 bit' flags are
+both specified, the 8 bit flag has precedence.
+ The use of the above flags should only be necessary under exceptional
+conditions where the probe routine incorrectly determines the board type (such
+is the case with Compex boards, which require the 16bit flag and an iosiz
+16384), or where the high performance of the transmitter causes problems with
+other vendors hardware.
+
+
+KNOWN PROBLEMS
+--------------
+
+1) Early revision DS8390B chips have problems. They lock-up whenever the
+ receive ring-buffer overflows. They occassionally switch the byte order
+ of the length field in the packet ring header (several different causes
+ of this related to an off-by-one byte alignment) - resulting in "NIC
+ memory corrupt - invalid length NNNNN" messages. The board is reset
+ whenever these problems occur, but otherwise there is no problem with
+ recovering from these conditions.
+2) 16bit boards that use shared memory can conflict with 8bit BIOSes, BIOS
+ extensions (like the VGA), and 8bit devices with shared memory (again
+ like the VGA, or perhaps a second ethernet board). There is a work-
+ around for this in the driver, however. The problem is that the
+ ethernet board stays in 16bit mode, asserting its '16bit' signal on
+ the ISA bus. This signal is shared by other devices/ROMs in the same
+ 128K memory segment as the ethernet card - causing the CPU to read the
+ 8bit ROMs as if they were 16bit wide. The work-around involves setting
+ the host access to the shared memory to 16bits only when the memory is
+ actually accessed, and setting it back to 8bit mode all other times.
+ Without this work-around, the machine will hang whenever a reboot is
+ attempted. This work-around also allows the board to co-exist with
+ other 8bit devices that have shared memory. This has only been
+ implemented for SMC/WD boards, but I haven't seen this problem with
+ 3Com boards (i.e. if you have a 3Com board, you might experiance the
+ above problem - I haven't specifically tested for it).
+3) The NIC memory access to 3Com and Novell boards is much slower than it is on
+ SMC boards; it's less than 1MB on 8bit boards and less than 2MB/second
+ on the 16bit boards. This can lead to ring-buffer overruns resulting in
+ additional lost data during heavy network traffic.
+
+$Id: ed.relnotes,v 1.1 1994/03/30 20:36:33 wollman Exp $
diff --git a/sys/doc/memory-test.doc b/sys/doc/memory-test.doc
new file mode 100644
index 000000000000..cda44f7f1a48
--- /dev/null
+++ b/sys/doc/memory-test.doc
@@ -0,0 +1,40 @@
+Message-Id: <199403270118.RAA00584@corbin.Root.COM>
+From: David Greenman <davidg@root.com>
+To: "Jordan K. Hubbard" <jkh@whisker.hubbard.ie>
+Cc: csgr@alpha.ru.ac.za, freebsd-hackers@freefall.cdrom.com
+Subject: Re: Boune Buffers : Crash and Burn ^&%$&&^%
+Date: Sat, 26 Mar 1994 17:18:04 -0800
+
+>Ummm. I suppose it would be stupid to wonder whether or not this is good
+>memory you just stuck in there? :-) It does raise the point: David - what
+>does your memory test do when it finds memory errors?
+
+ The order of events is like this:
+
+1) Determine amount of memory by looking at CMOS.
+2) Do memory test of this memory, starting at the highest address and going
+backwards.
+3) If a bad page is found, TRUNCATE the physical memory to end just before
+this page. Continue until all memory is tested.
+
+ So all memory past the lowest bad page is ignored. The number of pages that
+were chopped are then reported as # of "bad pages" when the memory information
+is printed. If there aren't any, then nothing is printed.
+ The rationale for not constructing a bit mask and weeding out just the
+pages that test bad is a flimsy one - doing so would have required moving the
+memory test into the machine independant portion of the VM system, and would
+have required much trickier coding. Since the main purpose of this was to
+verify that what the CMOS was telling us was correct, and also to identify
+when there is bad memory, trying to make the best of it when there really is
+some bad memory didn't seem important to me. ..but hey, if somebody wants to
+recode it, I won't complain. :-)
+ The problem that Terry eluded to, but didn't state, is where you test memory
+for the purpose of determining how much you have. This is problematic because
+many memory controllers will generate a fatal NMI when you 'test' non-existant
+memory (i.e. the parity check fails, and the condition is handled less than
+gracefully), and can also happen with some memory controllers that do strange
+address wrapping in the non-existant memory area. Compaq machines are alledged
+to be suseptable to one of these two problems.
+
+-DG
+
diff --git a/sys/doc/options.doc b/sys/doc/options.doc
new file mode 100644
index 000000000000..178eaf0b3c59
--- /dev/null
+++ b/sys/doc/options.doc
@@ -0,0 +1,682 @@
+$Id: options.doc,v 1.10 1994/06/28 14:00:21 jkh Exp $
+
+ This file documents the configuration options available in the
+FreeBSD operating system.
+
+ Copyright (C) 1993, 1994, Garrett A. Wollman. All rights reserved.
+
+ Redistribution and use in source and printed 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 and this list of conditions.
+ 2. Redistributions in printed form must reproduce the above copyright
+ notice, this list of conditions and the following notice of
+ authorship.
+
+ Trademarks are property of their respective owners.
+
+FreeBSD Configuration Options
+*****************************
+
+ This document describes kernel configuration options relevant to the
+FreeBSD operating system between versions 1.1 and 1.2. It is intended
+for readers who already have a general understanding of the process of
+configuring a BSD kernel and wish to get a general overview of the
+meaning of various configuration options. This document covers
+configurable options and pseudo-devices; it is intended that devices may
+be added at a later date.
+
+Options for Subsystems
+**********************
+
+ This chapter discusses options controlling the inclusion of various
+subsystems in FreeBSD. These include things like filesystems,
+networking modules, and whatnot. Remember that options containing
+underscores must be quoted.
+
+`pseudo-device bpfilter NUMBER'
+ The `bpfilter' pseudo-device is the Berkeley Packet Filter,
+ developed by Lawrence Berkeley Labs and based on an earlier packet
+ filter from Stanford. See the `bpf' manual page for more details.
+ The NUMBER given is the maximum number of simultaneous users
+ permitted. (NB: in previous version of BPF, the NUMBER had to be
+ greater than the number of interfaces; this space is now
+ dynamically allocated so this requirement is no longer present.)
+
+`options CCITT'
+ The `CCITT' option enables support for the ITU-T X.25(1980)
+ network-layer protocol. Nobody we know has a direct X.25
+ connection to anything, so this code has never been tested.
+
+ This option will likely be removed in a future release of FreeBSD.
+
+`options "COMPAT_42"'
+ This option is used to disable UDP checksumming. Under ordinary
+ circumstances it should never ever ever be defined; however, if
+ you are stuck trying to communicate with an old 4.2BSD machine, or
+ one running something derived from 4.2 like SunOS 3.5 or Ultrix
+ 2.0, this may be necessary in order to successfully receive UDP
+ packets.
+
+ This option will be replaced by run-time configuration in a future
+ release of FreeBSD.
+
+`options "COMPAT_43"'
+ This option controls a whole host of features, mostly relating to
+ system-call compatibilty with 4.3BSD. At the present time, it
+ should not be turned off, as many utilities and library routines
+ still depend on these obsolescent system calls being present. At
+ some future date, this will probably be split up into two separate
+ options, one for binary compatibility and one for the old but
+ useful system calls.
+
+`options "COMPAT_102"'
+ This option, which is not yet implemented, will control whether
+ certain entry points which were system calls in FreeBSD 1.0.2 but
+ have been replaced with library routines, are supported in the
+ kernel for backwards compatiblity.
+
+`options "DIRECTED_BROADCAST"'
+ If this option is enabled, the kernel will support sending IP
+ broadcast packets to subnets other than the one that the machine
+ is on, and when forwarding will accept such packets. That is to
+ say, if your host lives on subnets `132.198.3' and `132.198.4',
+ and the `132.198.3' side receives a packet addressed to
+ `132.198.4.255', it will forward the packet as a broadcast on that
+ subnet.
+
+ This option will likely be replaced by run-time configuration in a
+ future release of FreeBSD.
+
+`options "DISKLABEL_UNPROTECTED"'
+ This options disables the checks which normally protects the
+ disklabel from being overwritten. This allows dd of=/dev/rwd0d
+ if=file bs=8k to restore an diskimage.
+
+`pseudo-device ether'
+ This pseudo-device provides link-layer support for Ethernet device
+ drivers. It is mandatory for all systems which include Ethernet or
+ Ethernet-like devices, such as `ed', `ie', and `is'. This code is
+ due for a redesign.
+
+`options EON'
+`pseudo-device eon'
+ The `eon' network interface supports the ISO 8473
+ Connectionless-Mode Network Protocol, tunnelled through IP version
+ 4. `eon' interfaces are created automatically once initially
+ configured by adding ISO routes with IP destinations. At present,
+ both the pseudo-device and option declaration are necessary.
+
+ This option will likely be removed in a future release of FreeBSD.
+
+`options FIFO'
+ This option enables support for System V- and POSIX-style named
+ pipes or fifos.
+
+`options GATEWAY'
+`options IPFORWARDING=VALUE'
+`options IPSENDREDIRECTS=VALUE'
+ These three options control whether FreeBSD's IP forwarding
+ functions are enabled. Technically speaking, because FreeBSD does
+ not meet the standards set out in the "Router Requirements"
+ document (RFC 1009), these should not be enabled, but sometimes it
+ is necessary to enable this function. The `GATEWAY' option turns
+ on `IPFORWARDING', and also controls the sizing of certain system
+ tables. The `IPFORWARDING' option controls the initial value of
+ the `ipforwarding' kernel variable (default 1 if `GATEWAY'
+ defined, 0 otherwise), which controls whether packets are acutally
+ forwarded or not; VALUE should be either `0' or `1'.
+ `IPSENDREDIRECTS' controls the initial value of the
+ `ipsendredirects' variable (default is one, but should be changed
+ to zero); its VALUE should also be either `0' or `1'.
+
+ This option will be replaced by run-time configuration in a future
+ release of FreeBSD.
+
+`options INET'
+ This option controls the inclusion of the Internet protocol suite,
+ including IP version 4, TCP, UDP, and ICMP. Support for IP
+ multicast, IP next generation, and IGMP will be provided at a
+ future date. It is not recommended to even attempt to generate a
+ system with this option turned off, as many parts of the system
+ depend on Internet networking in important and subtle ways.
+
+`options ISO'
+`options TPIP'
+ These options control the inclusion of ISO OSI networking
+ protocols. The TPIP option includes just enough support to run
+ ISO Transport Protocol class 4 over IP, supporing the
+ `SOCK_SEQPACKET' abstraction. The ISO option includes support for
+ CLNP, TP class 0, ISO 9542 ESIS, and IEEE 802.2 logical link
+ control class 0 (for CLNP only).
+
+ This option will likely be removed in a future release of FreeBSD.
+
+`options ISOFS'
+ The `ISOFS' option enables kernel support for the ISO 9660 CD-ROM
+ filesystem, including RockRidge extensions.
+
+`options "ISO_X25ESIS"'
+ This option controls whether ISO 9542 ESIS is run over ITU-T X.25
+ link layers. This requires the `CCITT' option to be enabled as
+ well.
+
+ This option will likely be removed in a future release of FreeBSD.
+
+`options KTRACE'
+ This option enables the tracing of several classes of internal
+ kernel events. See the `ktrace' command for more details.
+ Recommended.
+
+`pseudo-device log'
+ The `log' pseudo-device provides kernel support to send kernel
+ messages to `syslog'. It is mandatory.
+
+`pseudo-device loop'
+ The `loop' pseudo-device provides the trivial network interface.
+ It is required when any networking options are enabled.
+
+`options MACHVMCOMPAT'
+ This option enables a Mach-compatible interface to the virtual
+ memory subsystem, supporting system calls `vm_allocate',
+ `vm_deallocate', `vm_inherit', and `vm_protect'. (Given the
+ nature of the VM system, it is impossible to support a Mach-style
+ `vm_region' call, and in every case the `map' argument is ignored
+ and replaced with the calling process's own map.)
+
+`options MFS'
+ This option enables support for the memory filesystem, an in-core
+ filesystem which lives in the swap area. Using MFS as a `/tmp'
+ filesystem can dramatically increase the speed of
+ temporary-space-intensive operations such as compilations. See the
+ `mount_mfs' manual page for more details.
+
+`options MULTICAST'
+ Enable multicast support for things like vat, nv, etc.
+
+`options MROUTING'
+ Enable multicast routing support (generally goes hand-in-hand with
+ the above). See also mrouted(1).
+
+`options NFS'
+ The `NFS' option enables support for Sun's Network File System.
+ (Also called "Nightmare" or "Not a"....) This presently includes
+ both client- and server-side kernelized NFS support; it may in the
+ future be broken into separate options. This NFS implmentation
+ comes to BSD courtesy of Rick Macklem of the University of Guelph,
+ and is not derived from Sun licensed source code. As a result,
+ there are sometimes interoperability problems where the published
+ specification is vague, and this option supports several new and
+ useful features compared to Sun's. See the `mount' manual page
+ for more details.
+
+`options NS'
+`options NSIP'
+ `NS' controls the inclusion of support for the Xerox Network
+ Service protocol family. At the present time, it is not known
+ whether this code even works; testers are welcome. The `NSIP'
+ option enables encapsulation of XNS IDP over IP.
+
+ These options will likely be removed in a future release of
+ FreeBSD.
+
+`options "PANIC_REBOOT_WAIT_TIME=TIME"'
+ This option controls how long the system waits after a panic
+ before it reboots. If a TIME of zero is specified, it reboots
+ immediately; otherwise, TIME is the number of seconds to wait
+ before rebooting. If, during the waiting period, a key is hit on
+ the console, the countdown stops and the system will wait for the
+ user to copy down the panic message and hit another key before
+ rebooting.
+
+`options PCFS'
+ This option controls support for mounting MS-DOS disks and disk
+ partitions under FreeBSD. The `pcfs' manual page is presently very
+ bogus.
+
+`pseudo-device ppp NUMBER'
+ The `ppp' pseudo-device provides support for the Internet
+ Point-to-Point protocol (RFC 1351 et seq), implemented as a line
+ discipline over standard serial links. NUMBER should be the
+ number of simultaneous PPP interfaces which will be configured.
+
+`pseudo-device pty NUMBER'
+ This pseudo-device provides support for pseudo-ttys, which are
+ required for `rlogin', `telnet', and `xterm' to operate correctly;
+ NUMBER should be set to the total number of these programs you
+ expect to have running at any given time. Because pty's are not
+ as yet dynamically allocated, and the underlying structures are
+ large, it is best to keep this value as small as feasible, until
+ this deficiency is remedied.
+
+`options QUOTA'
+ The `QUOTA' option enables support for disk quotas. Note that NFS
+ quota support is not available.
+
+`pseudo-device sl NUMBER'
+ This pseudo-device provides support for the Serial Line Internet
+ Protocol (RFC 1055), implemented as a line discipline over standard
+ serial links. It includes support for Van Jacobson header
+ compression. NUMBER should be the number of simultaneous SLIP
+ interfaces which will be configured. See also the `slattach'
+ manual page.
+
+`options SYSVSHM'
+`options SYSVSEM'
+`options SYSVMSG'
+`options SHMMAXPGS=VALUE'
+ The `SYSVSHM' option enables kernel-side emulation of System
+ V-compatible shared memory. The `SHMMAXPGS' option (default 64
+ pages or 256K) determines the maximum amount of shared memory
+ available under this mechanism. The `SYSVSEM' option provides
+ emulation of System V-compatible semaphores, and likewise
+ `SYSVMSG' for message queues.
+
+`options "TCP_COMPAT_42"'
+ This option controls the perpetuation of several bugs inherited
+ from the 4.2BSD implementation of TCP. It should only be defined
+ in the circumstances outlined for `COMPAT_42', above.
+
+ This option will likely be replaced by run-time configuration in a
+ future release of FreeBSD.
+
+`pseudo-device tun'
+ The `tun' driver provides a network interface which is attached to
+ a character device. In this way, a user-mode program can grab
+ packets out of the networking system, fiddle with them or move
+ them around, and pass stuff packets back up into the kernel. It
+ is not known if this device either compiles or operates correctly,
+ although it was believed to do both at some time in the past.
+
+`options UCONSOLE'
+ This option allows any old user to grab kernel output away from the
+ console and send it to the tty of their choice. It presents an
+ incredile security hole for some systems, but is necessary in
+ order to allow programs like `xconsole' to operate.
+
+`options XSERVER'
+ This obsolescent option enables support in the `pc' console driver
+ for certain operations required by the XFree86 server.
+
+Performace and Debugging Options
+********************************
+
+ The following options are provided for system performace
+optimization. Note that kernel profiling is supported via the `-p'
+option to the `config' command; for more information see the `config'
+manual page.
+
+`psuedo-device ddb'
+ This option enables the `ddb' debugger, taken from Mach. See the
+ `ddb' and `dbsym' manual pages for more information on the use of
+ this debugger.
+
+`options DIAGNOSTIC'
+`options NAMEI_DIAGNOSTIC'
+`options PARANOID'
+ These debugging options reduce performace. They are intended to
+ enable certain internal consistency checks which are not supposed
+ to fail during correct operation, and so are normally disabled for
+ performace reasons.
+
+`options FASTLINKS'
+ The `FASTLINKS' option enables the creation of symbolic links whose
+ target names reside entirely within the i-node of the link, when
+ possible. This results in faster access for those links which are
+ short enough (in practice, most of them). All kernels can read
+ such links, but only `FASTLINKS' kernels will create them, for
+ compatibility with older kernels lacking such support.
+
+`options ICMPPRINTFS'
+ This option is defined to allow debugging of ICMP ("Internet
+ Control Message Protocol") packets in the kernel. When defined
+ and the `icmpprintfs' kernel variable (default false) is set to
+ true, ICMP packets will be printed out to the console when
+ received. Note that it is probably better to use `tcpdump' for
+ this kind of debugging.
+
+`options KGDB'
+ The `KGDB' option enables certain bits of kernel code which will
+ eventually be able to talk to a remote copy of the `gdb' debugger
+ over a serial connection. The present code does not work, but
+ users are invited to hack on it and contribute the changes back to
+ the FreeBSD team.
+
+`options MAXMEM=SIZE'
+ The `MAXMEM' option controls how much memory the kernel will
+ recognize on bootup, specified in kilobytes. This may be useful
+ for dealing with certain broken attachment busses (or the adapters
+ thereon) which are unable to deal with memory beyond a certain
+ address.
+
+`options SUBNETSARELOCAL'
+ This option controls whether the TCP system believes that machines
+ on other subnets of your network are considered to be "local" to
+ your host. For most systems, this option should be on (the
+ default); if you are directly connected to a class A network,
+ however, then it may need to be turned off. (This is true of
+ networks like the MILNET.)
+
+`options "SYMTAB_SPACE=VALUE"'
+ This obsolescent option controls the amount of space that will be
+ statically allocated in the debugger source code to hold the kernel
+ symbol table that `dbsym' sticks there. Eventually this will be
+ dynamically allocated at load time. The default VALUE is 63000
+ bytes.
+
+`options "UPDATE_INTERVAL=VALUE"'
+ This option controls the wait time between successive `sync'
+ operations run by the `update' system process (pid 3). This option
+ will be replaced by run-time configuration in a future release of
+ FreeBSD.
+
+`options DUMMY_NOPS'
+ This option controls the use of real Nops for bus operations.
+ This might break on older systems so should be used with care.
+
+Device Options
+**************
+
+ There are different device selections available depending on the
+type of bus present in your computer. We will cover generic FreeBSD
+devices, ISA-bus devices, and EISA-bus devices. A separate section
+describes the devices available in the SCSI subsystem.
+
+Generic Devices and Options
+===========================
+
+ The following devices and options are available in all FreeBSD
+configurations. In addition to these devices, a selection of ISA
+devices (*note ISA::.) is required in order to generate a workable
+system.
+
+`machine "i386"'
+ This mandatory declaration informs the `config' program that you
+ are using an i386 or compatible CPU, and enables the selection of
+ all the other devices listed here.
+
+`cpu "I386_CPU"'
+`cpu "I486_CPU"'
+ These two options control which specific CPUs will be supported by
+ the generated kernel. If the kernel detects that it is not
+ running on a CPU for which support was enabled, it will panic
+ quickly upon startup. If you do not expect to need to run your
+ kernel on an i386 or similar CPU, leaving out that support can
+ increase virtual memory system performance.
+
+`options "MATH_EMULATE"'
+ When this option is defined, the math coprocessor emulator is
+ compiled into the kernel. When it is not defined and the
+ coprocessor is absent, programs which use floating-point
+ operations are automatically killed.
+
+`device npx0 at isa? port "IO_NPX" irq 13 vector npxintr'
+ The `npx' device provides support for the i387 numeric coprocessor
+ and the floating-point portions of the i486 CPU. This will
+ eventually be fixed to not require ISA to be configured.
+
+`pseudo-device speaker'
+ The `speaker' pseudo-device provides support for rudimentary access
+ to the PC's speaker via `/dev/spkr'. It provides a
+ character-device interface which interprets `PLAY' strings similar
+ to IBM PC Advanced BASIC, as well as an `ioctl' interface with more
+ fine-grained control. See the `spkr' manual page for more
+ information.
+
+ISA-bus Devices and Options
+===========================
+
+ The following options are specific to ISA-bus devices and systems.
+Since the EISA bus is backwards-compatible with the ISA bus, all these
+options also apply to EISA systems. The same goes for VESA Local Bus
+(VL-Bus) systems.
+
+`controller isa0'
+ This *mandatory* declaration must precede any other devices listed
+ in this section. It provides the basic support for the ISA-bus
+ glue logic, including DMA and autoconfiguration.
+
+`controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr'
+`options "TUNE_1542"'
+ The `aha' device supports the Adaptec 154x series of SCSI
+ controllers, and attempts to support other vendors' controllers
+ which claim compatibility with the Adaptec 1542, such as the
+ BusLogic 545. This device is included in the `GENERICAH'
+ distribution kernel. The `scbus' device (*note SCSI::.) is a
+ prerequisite for this device.
+
+ Some older versions of this code would attempt to set the
+ controller's bus access speed to the fastest possible without
+ losing data; we have found that this makes the driver unusable for
+ some users. If you wish to enable this optimization, or if you
+ suspect that your SCSI transfers are running slower than they
+ should, then you can use the `TUNE_1542' option to enable
+ bus-timing detection.
+
+`controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr'
+ This device supports the Bustek 742 SCSI controller. It is
+ included in the `GENERICBT' distribution kernel; the `scbus' device
+ (*note SCSI::.) is a prerequisite.
+
+`options ALLOW_CONFLICT_IOADDR'
+ Allow devices on the ISA bus to share conflicting IO address
+ spaces. This is generally an error, though things like PS/2 mouse
+ drivers which are implemented seperately from the keyboard driver
+ will require this option to be set. Note that this is almost
+ always sub-optimal, and the current PS/2 mouse driver will, in
+ fact, frequently fight with the keyboard if you try to use them
+ concurrently. Needing this option enabled is a sure sign that you
+ need to consider a different design for your driver.
+
+`options ALLOW_CONFLICT_IRQ'
+ Allow devices on the ISA bus to share conflicting IRQ's. This is
+ often necessary for multiport serial cards which have several
+ devices at the same IRQ. Enable this only with caution!
+
+`options COM_MULTIPORT'
+ This option enables support in the `sio' serial driver for certain
+ multi-port serial boards.
+
+`device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr'
+`device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr'
+ The `ed' network interface driver provides support for the Western
+ Digital/SMC 80x3 series, the 3Com 3c503, and Novell NE1000 and
+ NE2000 series of Ethernet controllers. It automatically detects
+ differences among the various versions of these controllers and
+ adapts appropriately. The `ed1' line shown is for the Novell
+ boards; the `ed0' line is appropriate for all other supported
+ controllers. (The Novell controllers cannot be configured to use
+ port 0x280.)
+
+`controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr'
+`disk fd0 at fdc0 drive 0'
+`disk fd1 at fdc0 drive 1'
+`tape ft0 at fdc0 drive 2'
+ The `fdc' driver provides support for the standard PC floppy-disk
+ controller. The `fd' sub-driver supports 3.5- and 5.25-inch
+ floppy disks in the standard 360KB, 720KB, 1200KB, 1440KB, and
+ 2880KB formats, as well as a number of other formats not supported
+ by DOS. The `ft' driver is available for QIC-80 "floppy tape"
+ support. The drivers support formatting of both tapes and disks.
+ This driver is substantially improved from that shipped in
+ previous releases of FreeBSD.
+
+`device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr'
+ This network interface driver provides support for the AT&T
+ StarLAN 10 and EN100 family of controllers. Note that the
+ configuration specified here is not the default configuration, but
+ one which attempts to deal with the conflicts that arise in more
+ modern systems. (It is expected that this driver will be expanded
+ in the future to support other similar cards in the manner of
+ `ed'.)
+
+`device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr'
+ The `is' network interface driver supports the Isolan 4141-0 and
+ Isolink 4110 Ethernet controllers.
+
+`device lpt0 at isa? port "IO_LPT1" tty'
+`device lpt0 at isa? port "IO_LPT1" tty irq 7 vector lptintr'
+`device lpt0 at isa? port ? tty irq 7 vector lptintr'
+`device lpt0 at isa? port ? tty'
+ The `lpt' driver provides support for the parallel printer driver
+ accessed as `/dev/lptN' (N=0, 1, ...). The current version of
+ this driver provides support for either polled or interrupt-driven
+ ports, a unification of the `lpt' and `lpa' drivers from FreeBSD
+ 1.1.
+
+ The first and second examples show explicit selection of a port
+ address. If the port is not specified, as in the third and fourth
+ examples, the driver defaults to whatever address the BIOS printer
+ driver would have used. The second and third examples select
+ interrupt-driven I/O; if polled mode is specified, as in the first
+ and fourth examples, it is impossible to enable interrupt-driven
+ access at run time.
+
+ If you receive "ISA strayintr 7" messages correlated with the use
+ of the polled mode of `lpt', chances are that your controller
+ supports interrupt-driven operation, and you should switch to that
+ mode.
+
+`device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr'
+ This device provides support for the Mitsumi non-SCSI CD-ROM drive.
+ Performance is known to be quite slow.
+
+`device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint'
+`device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr'
+`options NCONS=VALUE'
+`options COMCONSOLE'
+ The `pc' and `sc' devices provide support for the system display
+ and keyboard, which is the default console. There might actually
+ be documentation somewhere for both of these. The `sc' device
+ requires the `NCONS' option to be defined to some value; it
+ represents the number of virtual consoles to be provided by the
+ driver; a reasonable value is 8. One of `pc' or `sc' is presently
+ required unless `COMCONSOLE' is enabled, in which case a serial
+ port is made into the console.
+
+`device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr'
+ This driver provides support for the IBM-style PS/2 mouse now
+ popular on many PCs. This driver shares an address with the
+ console driver and therefore requires that the option
+ `ALLOW_CONFLICT_IOADDR' also be set. It is also important that
+ the console driver (`pc' or `sc') *preceed* this driver in your
+ kernel configuration file in order to get priority. All in all,
+ this driver is a hack and should really be integrated into the
+ console driver itself, evidence of which can be easily seen when
+ trying to use the mouse and keyboard at the same time in X (try
+ it). Volunteers willing to clean this up and do it properly are
+ most welcome!
+
+`device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr'
+`device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr'
+`device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr'
+`device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr'
+ The `sio' driver provides support for high-speed serial
+ communications using the standard 8250, 16450, and 16550 UART
+ chips. It provides a standard tty interface for these devices as
+ `/dev/ttyUNIT', and, when enabled with the `comcontrol' program, a
+ call-out capability as `/dev/cuaUNIT' (UNIT is two digits,
+ zero-padded in both cases). Certain multi-port systems are also
+ supported.
+
+`device uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr'
+ This device supports the Ultrastor 14F and related SCSI
+ controllers. It is included in the `GENERICBT' distribution
+ kernel, and requires `scbus' (*note SCSI::.) as a prerequisite.
+ The Ultrastor 24F is not supported.
+
+`controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr'
+`disk wd0 at wdc0 drive 0'
+`disk wd1 at wdc0 drive 1'
+ The `wd' device supports standard ST-506, RLL, ESDI, and IDE hard
+ disks, as controlled by the Western Digital WD100x series of
+ controllers (and compatible hardware). This version is
+ substantially improved from that provided in FreeBSD 1.0.
+
+`device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr'
+ This driver supports Archive QIC-02 and Wangtek QIC-02 and QIC-36
+ cartridge tape controllers.
+
+`device ze0 at isa? port 0x300 net irq 5 iomem 0xd8000 vector zeintr'
+ This driver supports certain PCMCIA ethernet cards. It was
+ originally written for the IBM Credit Card Adapter and has also
+ been tested with the National Semi `InfoMover' PCMCIA card.
+
+EISA-bus Devices and Options
+============================
+
+ There is presently only one EISA-specific device driver.
+
+`controller ahb0 at isa? bio irq 11 vector ahbintr'
+ The `ahb' driver provides support for the Adaptec AHA-174x series
+ of SCSI controllers. This controller is included in the
+ `GENERICAH' distribution kernel, and requires the `scbus' driver
+ (*note SCSI::.) as a prerequisite.
+
+Micro Channel Devices and Options
+=================================
+
+ We don't support Micro Channel right now. Anyone interested in
+working on Micro Channel support should send mail to
+`FreeBSD-Questions@freefall.cdrom.com' for information on how to help.
+
+PCI Devices and Options
+=======================
+
+ We don't support PCI, either. Anyone interested in working on PCI
+support should send mail to `FreeBSD-Questions@freefall.cdrom.com' for
+information on how to help.
+
+The SCSI Subsystem
+==================
+
+ The SCSI subsystem consists of a set of adaptor-specific driver
+routines, which were described in the previous sections, and the generic
+SCSI device drivers, which handle the standardized interactions with
+devices on the SCSI bus.
+
+`device cd0'
+ The `cd' device provides support for CD-ROM drives. Only one `cd'
+ device need be configured, as the driver automatically allocates
+ units for each CD-ROM drive found. Playing of audio CDs is also
+ supported, on drives which support it, through `ioctl' calls.
+ Support for retrieval of CD audio over the SCSI bus is not
+ presently available.
+
+`device ch0'
+ The `ch' driver supports SCSI media changers; this may include
+ tape, removable disk, and CD changers. One `ch' device should be
+ configured for each changer you expect to support.
+
+`device scbus0'
+ This driver forms the core of the SCSI subsystem. It provides the
+ device-independent routines that manage SCSI transactions, keep
+ track of attached devices, and act as glue between
+ SCSI-device-specific drivers and system-specific host adaptors.
+ This device is *mandatory* for all SCSI systems.
+
+`device sd0'
+ The `sd' driver provides access to non-removable SCSI disks. One
+ `sd' device should be defined for each disk you expect to have
+ simultaneously connected to the system.
+
+`device st0'
+ The `st' driver supports generic SCSI tape drives. One `st'
+ device should be defined for each tape drive you wish to access.
+ See the `st' manual page for information about how to manipulate
+ the parameters of this device.
+
+`device uk0'
+ The `uk' driver provides an attachment point for all otherwise
+ unrecognized SCSI devices. You can't actually do anything with
+ such a device, except perhaps send it an inquiry command using the
+ `scsi' program (q.v.).
+
+Internal Use Only
+*****************
+
+ Eventually, this chapter will document some of the kernel manifest
+constants which are not defines, but which can be tweaked in various
+header files.
+
diff --git a/sys/doc/options.texi b/sys/doc/options.texi
new file mode 100644
index 000000000000..7df30b8b442b
--- /dev/null
+++ b/sys/doc/options.texi
@@ -0,0 +1,1074 @@
+\input texinfo @c -*- texinfo -*-
+@c -----------------------------------------------------------------------
+@c Thus spoke the elders in days long gone by:
+@c How to edit: use an existing entry as template, keep the file sorted
+@c using the most keyword-ish thing. When done, make sure /usr/gnu/bin
+@c is in your path, run "make" and THEN "cvs commit".
+@c -----------------------------------------------------------------------
+@c %**start of header
+@setfilename options.info
+@settitle Configuration Options for FreeBSD
+@c @setchapternewpage odd
+@c function index is option/pseudo/device names; concept is everything
+@c else
+@syncodeindex fn cp
+@finalout
+@c %**end of header
+
+@ifinfo
+$Id: options.texi,v 1.11 1994/06/28 06:10:40 jkh Exp $
+
+This file documents the configuration options available in the FreeBSD
+operating system.
+
+@display
+Copyright @copyright{} 1993, 1994, Garrett A. Wollman. All rights reserved.
+
+Redistribution and use in source and printed 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 and this list of conditions.
+2. Redistributions in printed form must reproduce the above copyright
+ notice, this list of conditions and the following notice of
+ authorship.
+
+Trademarks are property of their respective owners.
+@end display
+@end ifinfo
+
+@titlepage
+@title Configuration Options in FreeBSD
+@subtitle for FreeBSD 1.1.5
+@author Garrett A. Wollman
+@author FreeBSD Project
+
+@page
+@vskip 0pt plus 1filll
+
+i386, i387, and i486 are trademarks of Intel Corporation. SunOS is a
+registered trademark and NFS is a trademark of Sun Microsystems, Inc.
+Ultrix is a registered trademark of Digital Equipment Corporation.
+Xerox is a registered trademark and XNS is a trademark of Xerox
+Corporation. VESA is a trademark of the Video Electronics Standards
+Association. System V is a registered trademark of Novell Corporation.
+All other trademarks are property of their respective owners. FreeBSD
+is nobody's trademark, and damn proud of it.
+
+Copyright @copyright{} 1993, 1994, Garrett A. Wollman. All rights reserved.
+
+Redistribution and use in source and printed forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+@enumerate
+@item
+Redistributions of source code must retain the above copyright
+notice and this list of conditions.
+
+@item
+Redistributions in printed form must reproduce the above copyright
+notice, this list of conditions and the preceding notice of
+authorship.
+@end enumerate
+@end titlepage
+
+@node Top, Subsystems, (dir), (dir)
+@top FreeBSD Configuration Options
+
+This document describes kernel configuration options relevant to the
+FreeBSD operating system between versions 1.1 and 1.2. It is intended
+for readers who already have a general understanding of the process of
+configuring a BSD kernel and wish to get a general overview of the
+meaning of various configuration options. This document covers
+configurable options and pseudo-devices; it is intended that devices may
+be added at a later date.
+
+@menu
+* Subsystems:: Controlling subsystems.
+* Performance:: Performance enhancement.
+* Devices:: Device-control options.
+* Internals:: Non-user-serviceable parts.
+
+* Index:: General Index.
+@end menu
+
+@node Subsystems, Performance, Top, Top
+@c node,next,prev,up
+
+@chapter Options for Subsystems
+
+This chapter discusses options controlling the inclusion of various
+subsystems in FreeBSD. These include things like filesystems,
+networking modules, and whatnot. Remember that options containing
+underscores must be quoted.
+
+@table @code
+@item pseudo-device bpfilter @var{number}
+@findex bpfilter
+@cindex Berkeley packet filter
+@cindex Network interfaces
+The @samp{bpfilter} pseudo-device is the Berkeley Packet Filter,
+developed by Lawrence Berkeley Labs and based on an earlier packet
+filter from Stanford. See the @samp{bpf} manual page for more details.
+The @var{number} given is the maximum number of simultaneous users
+permitted. (NB: in previous version of BPF, the @var{number} had to be
+greater than the number of interfaces; this space is now dynamically
+allocated so this requirement is no longer present.)
+
+@item options CCITT
+@findex CCITT
+@cindex X.25
+@cindex Networking domains
+The @samp{CCITT} option enables support for the ITU-T X.25(1980)
+network-layer protocol. Nobody we know has a direct X.25 connection to
+anything, so this code has never been tested.
+
+This option will likely be removed in a future release of FreeBSD.
+
+@item options "COMPAT_42"
+@findex COMPAT_42
+@cindex UDP Checksums
+@cindex Checksums, UDP
+@cindex 4.2 Compatibility
+@cindex Compatibility options
+This option is used to disable UDP checksumming. Under ordinary
+circumstances it should never ever ever be defined; however, if you are
+stuck trying to communicate with an old 4.2BSD machine, or one running
+something derived from 4.2 like SunOS 3.5 or Ultrix 2.0, this may be
+necessary in order to successfully receive UDP packets.
+
+This option will be replaced by run-time configuration in a future
+release of FreeBSD.
+
+@item options "COMPAT_43"
+@findex COMPAT_43
+@cindex 4.3 Compatibility
+@cindex Compatibility options
+This option controls a whole host of features, mostly relating to
+system-call compatibilty with 4.3BSD. At the present time, it should
+not be turned off, as many utilities and library routines still depend
+on these obsolescent system calls being present. At some future date,
+this will probably be split up into two separate options, one for binary
+compatibility and one for the old but useful system calls.
+
+@item options "COMPAT_102"
+@findex COMPAT_102
+@cindex FreeBSD 1.0.2 compatibility
+@cindex 1.0.2 Compatibility
+@cindex Compatibility options
+This option, which is not yet implemented, will control whether certain
+entry points which were system calls in FreeBSD 1.0.2 but have been
+replaced with library routines, are supported in the kernel for
+backwards compatiblity.
+
+@item options "DIRECTED_BROADCAST"
+@findex DIRECTED_BROADCAST
+@cindex IP
+@cindex UDP
+If this option is enabled, the kernel will support sending IP broadcast
+packets to subnets other than the one that the machine is on, and when
+forwarding will accept such packets. That is to say, if your host lives
+on subnets @samp{132.198.3} and @samp{132.198.4}, and the
+@samp{132.198.3} side receives a packet addressed to
+@samp{132.198.4.255}, it will forward the packet as a broadcast on that
+subnet.
+
+This option will likely be replaced by run-time configuration in a
+future release of FreeBSD.
+
+@item options "DISKLABEL_UNPROTECTED"
+@findex DISKLABEL_UNPROTECTED
+@cindex disk
+@cindex disklabel
+@cindex rawdisk
+This options disables the checks which normally protects the disklabel from
+being overwritten. This allows dd of=/dev/rwd0d if=file bs=8k to restore
+an diskimage.
+
+@item pseudo-device ether
+@findex ether
+@cindex Ethernet
+@cindex Network interfaces
+This pseudo-device provides link-layer support for Ethernet device
+drivers. It is mandatory for all systems which include Ethernet or
+Ethernet-like devices, such as @samp{ed}, @samp{ie}, and @samp{is}.
+This code is due for a redesign.
+
+@item options EON
+@itemx pseudo-device eon
+@findex EON
+@cindex ISO 8473 CLNP
+@cindex Network interfaces
+The @samp{eon} network interface supports the ISO 8473
+Connectionless-Mode Network Protocol, tunnelled through IP version 4.
+@samp{eon} interfaces are created automatically once initially
+configured by adding ISO routes with IP destinations. At present, both
+the pseudo-device and option declaration are necessary.
+
+This option will likely be removed in a future release of FreeBSD.
+
+@item options FIFO
+@findex FIFO
+@cindex Named pipes
+This option enables support for System V-- and POSIX-style named pipes
+or fifos.
+
+@item options GATEWAY
+@itemx options IPFORWARDING=@var{value}
+@itemx options IPSENDREDIRECTS=@var{value}
+@findex GATEWAY
+@findex IPFORWARDING
+@findex IPSENDREDIRECTS
+@cindex ICMP
+@cindex IP
+@cindex Network parameters
+These three options control whether FreeBSD's IP forwarding functions
+are enabled. Technically speaking, because FreeBSD does not meet the
+standards set out in the ``Router Requirements'' document (RFC 1009),
+these should not be enabled, but sometimes it is necessary to enable
+this function. The @samp{GATEWAY} option turns on @samp{IPFORWARDING},
+and also controls the sizing of certain system tables. The
+@samp{IPFORWARDING} option controls the initial value of the
+@samp{ipforwarding} kernel variable (default 1 if @samp{GATEWAY}
+defined, 0 otherwise), which controls whether packets are acutally
+forwarded or not; @var{value} should be either @samp{0} or @samp{1}.
+@samp{IPSENDREDIRECTS} controls the initial value of the
+@samp{ipsendredirects} variable (default is one, but should be changed
+to zero); its @var{value} should also be either @samp{0} or @samp{1}.
+
+This option will be replaced by run-time configuration in a future
+release of FreeBSD.
+
+@item options INET
+@findex INET
+@cindex IP
+@cindex TCP
+@cindex UDP
+@cindex ICMP
+@cindex Networking domains
+This option controls the inclusion of the Internet protocol suite,
+including IP version 4, TCP, UDP, and ICMP. Support for IP multicast,
+IP next generation, and IGMP will be provided at a future date. It is
+not recommended to even attempt to generate a system with this option
+turned off, as many parts of the system depend on Internet networking in
+important and subtle ways.
+
+@item options ISO
+@itemx options TPIP
+@findex ISO
+@findex TPIP
+@cindex ISO 8473 CLNP
+@cindex ISO TP4
+@cindex ISO TP0
+@cindex ISO 9542 ESIS
+@cindex IEEE 802.2 LLC
+@cindex Networking domains
+These options control the inclusion of ISO OSI networking protocols.
+The TPIP option includes just enough support to run ISO Transport
+Protocol class 4 over IP, supporing the @samp{SOCK_SEQPACKET}
+abstraction. The ISO option includes support for CLNP, TP class 0,
+ISO 9542 ESIS, and IEEE 802.2 logical link control class 0 (for CLNP
+only).
+
+This option will likely be removed in a future release of FreeBSD.
+
+@item options ISOFS
+@findex ISOFS
+@cindex ISO 9660 filesystem
+@cindex CD-ROM
+@cindex Rock Ridge filesystem
+@cindex Filesystems
+The @samp{ISOFS} option enables kernel support for the ISO 9660 CD-ROM
+filesystem, including RockRidge extensions.
+
+@item options "ISO_X25ESIS"
+@findex ISO_X25ESIS
+@cindex ISO 9542 ESIS
+@cindex X.25
+This option controls whether ISO 9542 ESIS is run over ITU-T X.25 link
+layers. This requires the @samp{CCITT} option to be enabled as well.
+
+This option will likely be removed in a future release of FreeBSD.
+
+@item options KTRACE
+@findex KTRACE
+@cindex Kernel tracing
+This option enables the tracing of several classes of internal kernel
+events. See the @samp{ktrace} command for more details. Recommended.
+
+@item pseudo-device log
+@findex log
+@cindex Kernel message logging
+The @samp{log} pseudo-device provides kernel support to send kernel
+messages to @samp{syslog}. It is mandatory.
+
+@item pseudo-device loop
+@findex loop
+@cindex Network interfaces
+The @samp{loop} pseudo-device provides the trivial network interface.
+It is required when any networking options are enabled.
+
+@item options MACHVMCOMPAT
+@findex MACHVMCOMPAT
+@cindex Mach virtual memory
+This option enables a Mach-compatible interface to the virtual memory
+subsystem, supporting system calls @samp{vm_allocate},
+@samp{vm_deallocate}, @samp{vm_inherit}, and @samp{vm_protect}.
+(Given the nature of the VM system, it is impossible to support a
+Mach-style @samp{vm_region} call, and in every case the `map' argument
+is ignored and replaced with the calling process's own map.)
+
+@item options MFS
+@findex MFS
+@cindex Memory filesystem
+@cindex Filesystems
+This option enables support for the memory filesystem, an in-core
+filesystem which lives in the swap area. Using MFS as a @file{/tmp}
+filesystem can dramatically increase the speed of
+temporary-space-intensive operations such as compilations. See the
+@samp{mount_mfs} manual page for more details.
+
+@item options MULTICAST
+@findex MULTICAST
+@cindex Multicast IP
+@cindex Networking
+Enable multicast support for things like vat, nv, etc.
+
+
+@item options MROUTING
+@findex MROUTING
+@cindex Multicast Routing
+@cindex Networking
+Enable multicast routing support (generally goes hand-in-hand with the
+above). See also mrouted(1).
+
+@item options NFS
+@findex NFS
+@cindex Network File System
+@cindex Filesystems
+The @samp{NFS} option enables support for Sun's Network File System.
+(Also called ``Nightmare'' or ``Not a''@dots{}.) This presently includes
+both client-- and server-side kernelized NFS support; it may in the
+future be broken into separate options. This NFS implmentation comes to
+BSD courtesy of Rick Macklem of the University of Guelph, and is not
+derived from Sun licensed source code. As a result, there are sometimes
+interoperability problems where the published specification is vague,
+and this option supports several new and useful features compared to
+Sun's. See the @samp{mount} manual page for more details.
+
+@item options NS
+@itemx options NSIP
+@findex NS
+@findex NSIP
+@cindex Xerox Network System
+@cindex XNS IDP
+@cindex XNS SPP
+@cindex Network interfaces
+@samp{NS} controls the inclusion of support for the Xerox Network
+Service protocol family. At the present time, it is not known whether
+this code even works; testers are welcome. The @samp{NSIP} option
+enables encapsulation of XNS IDP over IP.
+
+These options will likely be removed in a future release of FreeBSD.
+
+@item options "PANIC_REBOOT_WAIT_TIME=@var{time}"
+@findex PANIC_REBOOT_WAIT_TIME
+@cindex Kernel panics
+This option controls how long the system waits after a panic before it
+reboots. If a @var{time} of zero is specified, it reboots immediately;
+otherwise, @var{time} is the number of seconds to wait before rebooting.
+If, during the waiting period, a key is hit on the console, the
+countdown stops and the system will wait for the user to copy down the
+panic message and hit another key before rebooting.
+
+@item options PCFS
+@findex PCFS
+@cindex MS-DOS filesystem
+@cindex Filesystems
+This option controls support for mounting MS-DOS disks and disk
+partitions under FreeBSD. The @samp{pcfs} manual page is presently very
+bogus.
+
+@item pseudo-device ppp @var{number}
+@findex ppp
+@cindex Point-To-Point Protocol
+@cindex Network interfaces
+The @samp{ppp} pseudo-device provides support for the Internet
+Point-to-Point protocol (RFC 1351 @i{et seq}), implemented as a line
+discipline over standard serial links. @var{number} should be the
+number of simultaneous PPP interfaces which will be configured.
+
+@item pseudo-device pty @var{number}
+@findex pty
+@cindex Pseudo-terminals
+This pseudo-device provides support for pseudo-ttys, which are required
+for @samp{rlogin}, @samp{telnet}, and @samp{xterm} to operate correctly;
+@var{number} should be set to the total number of these programs you
+expect to have running at any given time. Because pty's are not as yet
+dynamically allocated, and the underlying structures are large, it is
+best to keep this value as small as feasible, until this deficiency is
+remedied.
+
+@item options QUOTA
+@findex QUOTA
+@cindex Disk quotas
+@cindex Filesystems
+The @samp{QUOTA} option enables support for disk quotas. Note that NFS
+quota support is not available.
+
+@item pseudo-device sl @var{number}
+@findex sl
+@cindex Serial Line Internet Protocol
+@cindex SLIP
+@cindex CSLIP
+@cindex IP
+@cindex Network interfaces
+This pseudo-device provides support for the Serial Line Internet
+Protocol (RFC 1055), implemented as a line discipline over standard
+serial links. It includes support for Van Jacobson header compression.
+@var{number} should be the number of simultaneous SLIP interfaces which
+will be configured. See also the @samp{slattach} manual page.
+
+@item options SYSVSHM
+@item options SYSVSEM
+@item options SYSVMSG
+@itemx options SHMMAXPGS=@var{value}
+@findex SYSVSHM
+@findex SYSVSEM
+@findex SYSVMSG
+@findex SHMMAXPGS
+@cindex System V shared memory
+@cindex System V semaphores
+@cindex System V message queues
+@cindex System V IPC
+@cindex Shared memory, System V
+@cindex Semaphores, System V
+@cindex Message queues, System V
+@cindex IPC, System V
+The @samp{SYSVSHM} option enables kernel-side emulation of System
+V-compatible shared memory. The @samp{SHMMAXPGS} option (default 64
+pages or 256K) determines the maximum amount of shared memory available
+under this mechanism. The @samp{SYSVSEM} option provides emulation of
+System V-compatible semaphores, and likewise @samp{SYSVMSG} for message
+queues.
+
+@item options "TCP_COMPAT_42"
+@findex TCP_COMPAT_42
+@cindex 4.2 Compatibility
+@cindex Compatibility options
+@cindex TCP
+This option controls the perpetuation of several bugs inherited from the
+4.2BSD implementation of TCP. It should only be defined in the
+circumstances outlined for @samp{COMPAT_42}, above.
+
+This option will likely be replaced by run-time configuration in a
+future release of FreeBSD.
+
+@item pseudo-device tun
+@findex tun
+@cindex Network interfaces
+The @samp{tun} driver provides a network interface which is attached to
+a character device. In this way, a user-mode program can grab packets
+out of the networking system, fiddle with them or move them around, and
+pass stuff packets back up into the kernel. It is not known if this
+device either compiles or operates correctly, although it was believed
+to do both at some time in the past.
+
+@item options UCONSOLE
+@findex UCONSOLE
+@cindex Console redirection
+This option allows any old user to grab kernel output away from the
+console and send it to the tty of their choice. It presents an
+incredile security hole for some systems, but is necessary in order to
+allow programs like @samp{xconsole} to operate.
+
+@item options XSERVER
+@findex XSERVER
+@cindex X Window System
+This obsolescent option enables support in the @samp{pc} console
+driver for certain operations required by the XFree86 server.
+@end table
+
+@node Performance, Devices, Subsystems, Top
+@c node,next,prev,up
+
+@chapter Performace and Debugging Options
+
+The following options are provided for system performace optimization.
+Note that kernel profiling is supported via the @samp{-p} option to the
+@samp{config} command; for more information see the @samp{config} manual
+page.
+
+@table @code
+@item psuedo-device ddb
+@findex ddb
+@cindex Kernel debugger
+@cindex Debugger, kernel
+This option enables the @samp{ddb} debugger, taken from Mach. See the
+@samp{ddb} and @samp{dbsym} manual pages for more information on the use
+of this debugger.
+
+@item options DIAGNOSTIC
+@itemx options NAMEI_DIAGNOSTIC
+@itemx options PARANOID
+@findex DIAGNOSTIC
+@findex NAMEI_DIAGNOSTIC
+@findex PARANOID
+@cindex Debugging options
+These debugging options reduce performace. They are intended to enable
+certain internal consistency checks which are not supposed to fail
+during correct operation, and so are normally disabled for performace
+reasons.
+
+@item options FASTLINKS
+@findex FASTLINKS
+@cindex Symbolic links
+@cindex Filesystems
+The @samp{FASTLINKS} option enables the creation of symbolic links whose
+target names reside entirely within the i-node of the link, when
+possible. This results in faster access for those links which are short
+enough (in practice, most of them). All kernels can read such links,
+but only @samp{FASTLINKS} kernels will create them, for compatibility
+with older kernels lacking such support.
+
+@item options ICMPPRINTFS
+@findex ICMPPRINTFS
+@cindex Debugging options
+@cindex ICMP
+This option is defined to allow debugging of ICMP (@dfn{Internet Control
+Message Protocol}) packets in the kernel. When defined and the
+@samp{icmpprintfs} kernel variable (default false) is set to true, ICMP
+packets will be printed out to the console when received. Note that it
+is probably better to use @samp{tcpdump} for this kind of debugging.
+
+@item options KGDB
+@findex KGDB
+@cindex Kernel debugger
+@cindex Debugger, kernel
+@cindex Remote debugging
+The @samp{KGDB} option enables certain bits of kernel code which will
+eventually be able to talk to a remote copy of the @samp{gdb} debugger
+over a serial connection. The present code does not work, but users are
+invited to hack on it and contribute the changes back to the FreeBSD
+team.
+
+@item options MAXMEM=@var{size}
+@findex MAXMEM
+The @samp{MAXMEM} option controls how much memory the kernel will
+recognize on bootup, specified in kilobytes. This may be useful for
+dealing with certain broken attachment busses (or the adapters thereon)
+which are unable to deal with memory beyond a certain address.
+
+@item options SUBNETSARELOCAL
+@findex SUBNETSARELOCAL
+@cindex TCP
+@cindex Network parameters
+This option controls whether the TCP system believes that machines on
+other subnets of your network are considered to be ``local'' to your
+host. For most systems, this option should be on (the default); if you
+are directly connected to a class A network, however, then it may need
+to be turned off. (This is true of networks like the MILNET.)
+
+@item options "SYMTAB_SPACE=@var{value}"
+@findex SYMTAB_SPACE
+@cindex Debugger, kernel
+@cindex Kernel debugger
+This obsolescent option controls the amount of space that will be
+statically allocated in the debugger source code to hold the kernel
+symbol table that @samp{dbsym} sticks there. Eventually this will be
+dynamically allocated at load time. The default @var{value} is 63000
+bytes.
+
+@item options "UPDATE_INTERVAL=@var{value}"
+@findex UPDATE_INTERVAL
+@cindex Update process
+This option controls the wait time between successive @samp{sync}
+operations run by the @samp{update} system process (pid 3). This option
+will be replaced by run-time configuration in a future release of
+FreeBSD.
+
+@item options DUMMY_NOPS
+@findex DUMMY_NOPS
+@cindex Fast i/o bus operations
+This option controls the use of real Nops for bus operations.
+This might break on older systems so should be used with care.
+
+@end table
+
+@node Devices, Internals, Performance, Top
+
+@chapter Device Options
+
+There are different device selections available depending on the type of
+bus present in your computer. We will cover generic FreeBSD devices,
+ISA-bus devices, and EISA-bus devices. A separate section describes the
+devices available in the SCSI subsystem.
+
+@menu
+* Generic:: Devices available in all FreeBSD systems.
+* ISA:: Devices specific to the ISA bus.
+* EISA:: Devices specific to the EISA bus.
+* MCA:: No support for Micro Channel, yet.
+* PCI:: No support for PCI, yet.
+* SCSI:: The SCSI subsystem.
+@end menu
+
+@node Generic, ISA,, Devices
+@section Generic Devices and Options
+
+The following devices and options are available in all FreeBSD
+configurations. In addition to these devices, a selection of ISA
+devices (@pxref{ISA}) is required in order to generate a workable
+system.
+
+@table @code
+@item machine "i386"
+@findex i386
+This mandatory declaration informs the @samp{config} program that you
+are using an i386 or compatible CPU, and enables the selection of all
+the other devices listed here.
+
+@item cpu "I386_CPU"
+@itemx cpu "I486_CPU"
+@findex I386_CPU
+@findex I486_CPU
+These two options control which specific CPUs will be supported by the
+generated kernel. If the kernel detects that it is not running on a CPU
+for which support was enabled, it will panic quickly upon startup. If
+you do not expect to need to run your kernel on an i386 or similar CPU,
+leaving out that support can increase virtual memory system performance.
+
+@item options "MATH_EMULATE"
+@findex MATH_EMULATE
+@cindex Floating-point emulator
+@cindex i387
+When this option is defined, the math coprocessor emulator is compiled
+into the kernel. When it is not defined and the coprocessor is absent,
+programs which use floating-point operations are automatically killed.
+
+@item device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+@findex npx
+@cindex i386
+The @samp{npx} device provides support for the i387 numeric coprocessor
+and the floating-point portions of the i486 CPU. This will eventually
+be fixed to not require ISA to be configured.
+
+@item pseudo-device speaker
+@findex speaker
+The @samp{speaker} pseudo-device provides support for rudimentary access
+to the PC's speaker via @file{/dev/spkr}. It provides a
+character-device interface which interprets @samp{PLAY} strings similar
+to IBM PC Advanced BASIC, as well as an @samp{ioctl} interface with more
+fine-grained control. See the @samp{spkr} manual page for more
+information.
+@end table
+
+@node ISA, EISA, Generic, Devices
+@section ISA-bus Devices and Options
+
+The following options are specific to ISA-bus devices and systems.
+Since the EISA bus is backwards-compatible with the ISA bus, all these
+options also apply to EISA systems. The same goes for VESA Local Bus
+(VL-Bus) systems.
+
+@table @code
+@item controller isa0
+@findex isa
+This @strong{mandatory} declaration must precede any other devices
+listed in this section. It provides the basic support for the ISA-bus
+glue logic, including DMA and autoconfiguration.
+
+@item controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+@item options "TUNE_1542"
+@findex aha
+@findex TUNE_1542
+@cindex Adaptec 154x
+@cindex SCSI host adaptors
+The @samp{aha} device supports the Adaptec 154x series of SCSI
+controllers, and attempts to support other vendors' controllers which
+claim compatibility with the Adaptec 1542, such as the BusLogic 545.
+This device is included in the @samp{GENERICAH} distribution kernel.
+The @samp{scbus} device (@pxref{SCSI}) is a prerequisite for this
+device.
+
+Some older versions of this code would attempt to set the controller's
+bus access speed to the fastest possible without losing data; we have
+found that this makes the driver unusable for some users. If you wish
+to enable this optimization, or if you suspect that your SCSI transfers
+are running slower than they should, then you can use the @samp{TUNE_1542}
+option to enable bus-timing detection.
+
+@item controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
+@findex bt
+@cindex Bustek 742
+@cindex SCSI host adaptors
+This device supports the Bustek 742 SCSI controller. It is included in
+the @samp{GENERICBT} distribution kernel; the @samp{scbus} device
+(@pxref{SCSI}) is a prerequisite.
+
+@item options ALLOW_CONFLICT_IOADDR
+@findex ALLOW_CONFLICT_IOADDR
+@cindex Allow IO Address Conflict
+@cindex ISA device management
+Allow devices on the ISA bus to share conflicting IO address spaces.
+This is generally an error, though things like PS/2 mouse drivers which
+are implemented seperately from the keyboard driver will require this
+option to be set. Note that this is almost always sub-optimal, and the
+current PS/2 mouse driver will, in fact, frequently fight with the
+keyboard if you try to use them concurrently. Needing this option
+enabled is a sure sign that you need to consider a different design for
+your driver.
+
+@item options ALLOW_CONFLICT_IRQ
+@findex ALLOW_CONFLICT_IRQ
+@cindex Allow IRQ Conflict
+@cindex ISA device management
+
+Allow devices on the ISA bus to share conflicting IRQ's. This is often
+necessary for multiport serial cards which have several devices at the
+same IRQ. Enable this only with caution!
+
+@item options COM_MULTIPORT
+@findex COM_MULTIPORT
+@cindex Multi-port serial boards
+@cindex Serial ports
+This option enables support in the @samp{sio} serial driver for certain
+multi-port serial boards.
+
+@item device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+@itemx device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
+@findex ed
+@cindex Western Digital 80x3
+@cindex 3Com 3C503
+@cindex Novel NE1000/NE2000
+@cindex Network interfaces
+@cindex Ethernet
+The @samp{ed} network interface driver provides support for the Western
+Digital/SMC 80x3 series, the 3Com 3c503, and Novell NE1000 and NE2000
+series of Ethernet controllers. It automatically detects differences
+among the various versions of these controllers and adapts
+appropriately. The @samp{ed1} line shown is for the Novell boards; the
+@samp{ed0} line is appropriate for all other supported controllers.
+(The Novell controllers cannot be configured to use port 0x280.)
+
+@item controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+@itemx disk fd0 at fdc0 drive 0
+@itemx disk fd1 at fdc0 drive 1
+@itemx tape ft0 at fdc0 drive 2
+@findex fd
+@findex ft
+@cindex Floppy disk
+@cindex Floppy tape
+@cindex QIC-80
+@cindex Tape drives
+@cindex Cartridge tape drives
+@cindex Quarter-Inch-Cartridge (QIC) tape drives
+@cindex Disk drives
+The @samp{fdc} driver provides support for the standard PC floppy-disk
+controller. The @samp{fd} sub-driver supports 3.5-- and 5.25-inch
+floppy disks in the standard 360KB, 720KB, 1200KB, 1440KB, and 2880KB
+formats, as well as a number of other formats not supported by DOS. The
+@samp{ft} driver is available for QIC-80 ``floppy tape'' support.
+The drivers support formatting of both tapes and disks. This driver is
+substantially improved from that shipped in previous releases of
+FreeBSD.
+
+@item device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+@findex ie
+@cindex AT&T EN100
+@cindex AT&T StarLAN 10
+@cindex Network interfaces
+@cindex Ethernet
+@cindex StarLAN
+This network interface driver provides support for the AT&T StarLAN 10
+and EN100 family of controllers. Note that the configuration specified
+here is not the default configuration, but one which attempts to deal
+with the conflicts that arise in more modern systems. (It is expected
+that this driver will be expanded in the future to support other similar
+cards in the manner of @samp{ed}.)
+
+@item device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+@findex is
+@cindex Isolan 4141-0
+@cindex Isolink 4110
+@cindex Ethernet
+@cindex Network interfaces
+The @samp{is} network interface driver supports the Isolan 4141-0 and
+Isolink 4110 Ethernet controllers.
+
+@c @item device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 \
+@c @itemx vector ixintr
+@c @findex ix
+@c @cindex Intel EtherEXPRESS
+@c @cindex Ethernet
+@c @cindex Network interfaces
+@c This device is known to exist, but is not presently in the FreeBSD
+@c source tree. When it is made available, this information will be
+@c updated.
+
+@item device lpt0 at isa? port "IO_LPT1" tty
+@itemx device lpt0 at isa? port "IO_LPT1" tty irq 7 vector lptintr
+@itemx device lpt0 at isa? port ? tty irq 7 vector lptintr
+@itemx device lpt0 at isa? port ? tty
+@findex lpa
+@findex lpt
+@cindex Parallel printers
+
+The @samp{lpt} driver provides support for the parallel printer driver
+accessed as @file{/dev/lpt@var{N}} (@var{N}=0, 1, @dots{}). The current
+version of this driver provides support for either polled or
+interrupt-driven ports, a unification of the @samp{lpt} and @samp{lpa}
+drivers from FreeBSD 1.1.
+
+The first and second examples show explicit selection of a port address.
+If the port is not specified, as in the third and fourth examples, the
+driver defaults to whatever address the BIOS printer driver would have
+used. The second and third examples select interrupt-driven I/O; if
+polled mode is specified, as in the first and fourth examples, it is
+impossible to enable interrupt-driven access at run time.
+
+If you receive ``ISA strayintr 7'' messages correlated with the use of
+the polled mode of @samp{lpt}, chances are that your controller supports
+interrupt-driven operation, and you should switch to that mode.
+
+
+@item device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+@findex mcd
+@cindex Mitsumi CD-ROM
+@cindex CD-ROM
+This device provides support for the Mitsumi non-SCSI CD-ROM drive.
+Performance is known to be quite slow.
+
+@c mse, anyone?
+
+@item device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+@itemx device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+@itemx options NCONS=@var{value}
+@itemx options COMCONSOLE
+@findex pc
+@findex sc
+@findex NCONS
+@findex COMCONSOLE
+@cindex Console devices
+@cindex pccons
+@cindex Syscons
+@cindex Virtual consoles
+@cindex X Window System
+The @samp{pc} and @samp{sc} devices provide support for the system
+display and keyboard, which is the default console. There might
+actually be documentation somewhere for both of these. The @samp{sc}
+device requires the @samp{NCONS} option to be defined to some value; it
+represents the number of virtual consoles to be provided by the driver;
+a reasonable value is 8. One of @samp{pc} or @samp{sc} is presently
+required unless @samp{COMCONSOLE} is enabled, in which case a serial
+port is made into the console.
+
+@item device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+@findex psm
+@cindex PS/2 mouse
+@cindex Mouse
+This driver provides support for the IBM-style PS/2 mouse now popular
+on many PCs. This driver shares an address with the console driver
+and therefore requires that the option @samp{ALLOW_CONFLICT_IOADDR}
+also be set. It is also important that the console driver
+(@samp{pc} or @samp{sc}) *preceed* this driver in your kernel configuration
+file in order to get priority. All in all, this driver is a hack and
+should really be integrated into the console driver itself, evidence of
+which can be easily seen when trying to use the mouse and keyboard at the
+same time in X (try it). Volunteers willing to clean this up and do it
+properly are most welcome!
+
+@c sb, anyone?
+
+@item device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+@itemx device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+@itemx device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+@itemx device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+@findex sio
+@cindex Serial ports
+@cindex National 8250/16450/16550
+@cindex Bi-directional serial ports
+@cindex Multi-port serial boards
+The @samp{sio} driver provides support for high-speed serial
+communications using the standard 8250, 16450, and 16550 UART chips. It
+provides a standard tty interface for these devices as
+@file{/dev/tty@var{unit}}, and, when enabled with the @samp{comcontrol}
+program, a call-out capability as @file{/dev/cua@var{unit}} (@var{unit}
+is two digits, zero-padded in both cases). Certain multi-port systems
+are also supported.
+
+@item device uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
+@findex uha
+@cindex Ultrastor 14F
+@cindex Ultrastor 34F
+@cindex SCSI host adaptors
+This device supports the Ultrastor 14F and related SCSI controllers. It
+is included in the @samp{GENERICBT} distribution kernel, and requires
+@samp{scbus} (@pxref{SCSI}) as a prerequisite. The Ultrastor 24F is not
+supported.
+
+@item controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+@itemx disk wd0 at wdc0 drive 0
+@itemx disk wd1 at wdc0 drive 1
+@findex wd
+@cindex Western Digital WD100x
+@cindex ST-506 hard disks
+@cindex RLL hard disks
+@cindex ESDI hard disks
+@cindex IDE hard disks
+@cindex Disk drives
+The @samp{wd} device supports standard ST-506, RLL, ESDI, and IDE hard
+disks, as controlled by the Western Digital WD100x series of controllers
+(and compatible hardware). This version is substantially improved from
+that provided in FreeBSD 1.0.
+
+@item device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+@findex wt
+@cindex Archive QIC-02
+@cindex Wangtek QIC-02
+@cindex Cartridge tape drives
+@cindex QIC-02
+@cindex QIC-36
+@cindex Tape drives
+@cindex Quarter-Inch-Cartridge (QIC) tape drives
+This driver supports Archive QIC-02 and Wangtek QIC-02 and QIC-36
+cartridge tape controllers.
+
+@item device ze0 at isa? port 0x300 net irq 5 iomem 0xd8000 vector zeintr
+@findex ze
+@cindex Ethernet
+@cindex Network Interfaces
+@cindex PCMCIA
+@cindex PCMCIA Ethernet Cards
+This driver supports certain PCMCIA ethernet cards. It was originally
+written for the IBM Credit Card Adapter and has also been tested
+with the National Semi `InfoMover' PCMCIA card.
+@end table
+
+@node EISA, MCA, ISA, Devices
+@section EISA-bus Devices and Options
+
+There is presently only one EISA-specific device driver.
+
+@table @code
+@item controller ahb0 at isa? bio irq 11 vector ahbintr
+@findex ahb
+@cindex Adaptec 174x
+@cindex SCSI host adaptors
+The @samp{ahb} driver provides support for the Adaptec AHA-174x series
+of SCSI controllers. This controller is included in the
+@samp{GENERICAH} distribution kernel, and requires the @samp{scbus}
+driver (@pxref{SCSI}) as a prerequisite.
+@end table
+
+@node MCA, PCI, EISA, Devices
+@section Micro Channel Devices and Options
+
+@cindex Micro Channel Architecture
+We don't support Micro Channel right now. Anyone interested in working
+on Micro Channel support should send mail to
+@samp{FreeBSD-Questions@@freefall.cdrom.com} for information on how to
+help.
+
+@node PCI, SCSI, MCA, Devices
+@section PCI Devices and Options
+
+@cindex PCI
+We don't support PCI, either. Anyone interested in working on PCI
+support should send mail to @samp{FreeBSD-Questions@@freefall.cdrom.com}
+for information on how to help.
+
+@node SCSI,, PCI, Devices
+@section The SCSI Subsystem
+
+The SCSI subsystem consists of a set of adaptor-specific driver
+routines, which were described in the previous sections, and the generic
+SCSI device drivers, which handle the standardized interactions with
+devices on the SCSI bus.
+
+@c devices: cd, ch, scbus, sd, sg, st
+
+@table @code
+@item device cd0
+@findex cd
+@cindex CD-ROM
+@cindex SCSI devices
+The @samp{cd} device provides support for CD-ROM drives. Only one
+@samp{cd} device need be configured, as the driver automatically
+allocates units for each CD-ROM drive found. Playing of audio CDs is
+also supported, on drives which support it, through @code{ioctl} calls.
+Support for retrieval of CD audio over the SCSI bus is not presently
+available.
+
+@item device ch0
+@findex ch
+@cindex Media changers
+@cindex SCSI devices
+The @samp{ch} driver supports SCSI media changers; this may include
+tape, removable disk, and CD changers. One @samp{ch} device should be
+configured for each changer you expect to support.
+
+@item device scbus0
+@findex scbus
+@cindex SCSI bus management
+This driver forms the core of the SCSI subsystem. It provides the
+device-independent routines that manage SCSI transactions, keep track of
+attached devices, and act as glue between SCSI-device-specific drivers
+and system-specific host adaptors. This device is @emph{mandatory} for
+all SCSI systems.
+
+@item device sd0
+@findex sd
+@cindex SCSI devices
+@cindex Disk drives
+The @samp{sd} driver provides access to non-removable SCSI disks. One
+@samp{sd} device should be defined for each disk you expect to have
+simultaneously connected to the system.
+
+@c @item device sg0
+@c @findex sg
+@c @cindex SCSI devices
+@c @cindex Generic SCSI
+@c @cindex Unsupported SCSI devices
+@c This driver provides support for development of user-mode drivers and
+@c other programs which access the SCSI bus directly. One @samp{sg} device
+@c should be defined for each @emph{host adaptor} you have installed in
+@c your system.
+
+@item device st0
+@findex st
+@cindex SCSI devices
+@cindex Tape drives
+@cindex Quarter-Inch-Cartridge (QIC) tape drives
+The @samp{st} driver supports generic SCSI tape drives. One @samp{st}
+device should be defined for each tape drive you wish to access. See
+the @samp{st} manual page for information about how to manipulate the
+parameters of this device.
+
+@item device uk0
+@findex uk
+@cindex SCSI devices
+@cindex Unknown SCSI devices
+The @samp{uk} driver provides an attachment point for all otherwise
+unrecognized SCSI devices. You can't actually do anything with such a
+device, except perhaps send it an inquiry command using the @samp{scsi}
+program (q.v.).
+@end table
+
+@node Internals, Index, Devices, Top
+
+@chapter Internal Use Only
+
+Eventually, this chapter will document some of the kernel manifest
+constants which are not defines, but which can be tweaked in various
+header files.
+
+@node Index,, Internals, Top
+@appendix General Index
+
+Items in @code{typewriter} font are option or device names.
+
+@printindex cp
+
+@bye
diff --git a/sys/doc/seagate.doc b/sys/doc/seagate.doc
new file mode 100644
index 000000000000..b22f2c9bca4e
--- /dev/null
+++ b/sys/doc/seagate.doc
@@ -0,0 +1,125 @@
+This is a low level driver for Seagate ST01/02, Future Domain TMC-885, TMC-950
+SCSI host adapter that uses Julian Elishers SCSI code.
+
+This driver is the result of looking at code written by the following people:
+
+ Drew Eckhardt
+ Julian Elischer
+ Glen Overby
+ Gary Close
+
+Special thank to
+
+ Robert Knier
+
+that made the fast blind transfer routines, and also helped with debugging.
+
+I am very grateful to these people.
+
+
+Operating system requirements:
+
+This driver uses the latest version of Julian Elischers scsi code, available
+at FreeBSD.cdrom.com in the file called newscsi3.tar.gz. The driver has been
+tested on FreeBSD 1.1-BETA, FreeBSD 1.0.2, 386bsd 0.1. I don't know if will
+work with NetBSD. (I hope it will.)
+
+
+The hardware:
+
+The ST01/02, and Future Domain 950 are very simple SCSI controllers. They are
+not busmastering, so the processor must do all transfers a la IDE. They support
+blind transfer by adding wait states (up to a certain limit). Interrupt is
+generated for reconnect and parity errors (maybe also for some other events).
+
+The card consists of one command port that writes to scsi control lines, reads
+status lines, and a data port that read/writes to the 8 data lines. The address
+decoding gives both data and control ports large memory areas to a single
+port. This is used by the code.
+
+The ST01/02 differs from the FD950 in memory address location and SCSI id.
+
+Probing for the card:
+
+A card is recognized by comparing the BIOS signature with known signatures. A
+new card may not be recognized if the BIOS signature has changed. Please send
+new signatures to me.
+
+Driver function:
+
+A scsi command is sent to scsi_cmd function. The command is either placed in
+the queue or an retryable message is returned. The routine may wait for
+completion of the command depending on the supplied flags. A timer is started
+for every command placed in the queue. The commands are added in the order they
+are received. There is a possiblity to make all REQUEST SENSE commands be
+queued before all other commands, but I dont think it is a good thing (Linux
+do however use this).
+
+The card is mostly controlled by the sea_main function. It is called by
+scsi_cmd, the interrupt routine, and the timeout routine. The sea_main routine
+runs as long there are something to do (transfer data, issue queued commands,
+and handle reconnected commands).
+
+The data transfers may be done in two different ways: Blind and polled
+transfers. They differ in the way the driver does it handshaking with the
+target. During a blind transfer, the driver code blindly transfers a block
+of data without checking for changed phase. During polled transfers, the
+phase is checked between every character transfered. The polled transfers
+are always used for status information and command transfers.
+
+Because the card does not use dma in any way, there is no need to handle
+physical addresses. There is no problem with the isa-bus address limit of
+16MB, making bounce-buffers unnecessary.
+
+The data structures:
+
+Every card has a sea_data structure keeping the queues of commands waiting to
+be issued, and commands currently disconnected. The type of card (Seagate or
+Future Domain), data and control port addresses, scsi id, busy flags for all
+possible targets, and interrupt vector for the card.
+
+Every scsi command to be issued are stored in a sea_scb structure. It contains
+a flag describing status/error of the command, current data buffer position,
+and number of bytes remaining to be transfered.
+
+
+INSTALLATION
+
+1) Alter defines in /sys/i386/isa/seagate.c if you don't
+ want to use blind transfers and/or disconnects. Please note that
+ interrupts must be enabled on the board if disconnects are used.
+2) Create a new config file in /sys/i386/conf containing defines for Julian's
+ scsi code (see GENERICAH or GENERICBT). Replace the aha or bt controller
+ with:
+ controller sea0 at isa? bio irq 5 iomem 0xC8000 iosiz 0x2000 vector seaintr
+3) config, make depend, make, cp, shutdown -r
+
+You should now have a working kernel booted.
+
+I have tested the code on the following hardware: 386DX 24MHz 8MB AMI BIOS,
+Maxtor 7120A IDE, Seagate ST02, Maxtor LXT340S scsi disk, SONY CDU-8003 cdrom,
+(short test with) WANGTEK 6200HS DAT drive.
+
+
+PROBLEMS
+
+I have had problems getting the ST02 boot using FreeBSD boot floppies. I think
+is some problem with BIOS calls not working. It is unfortunately impossible to
+disconnect the ST02 floppy controller.
+
+I have had problems getting the driver to talk to a 40 MB Seagate disk. I
+don't have access to it any more, so I can't do any more checking on it.
+
+NOTE: The ST02 creates its own description of the disk attached. This is not
+the same as the disk says. This translation problem may cause problems when
+sharing a disk between both DOS and BSD. It is however not impossible.
+
+
+/Kent
+
+
+Kent Palmkvist
+kentp@isy.liu.se
+
+
+$Id: seagate.doc,v 1.1 1994/06/28 15:47:12 jkh Exp $
diff --git a/sys/doc/sound.doc b/sys/doc/sound.doc
new file mode 100644
index 000000000000..0c2f10034287
--- /dev/null
+++ b/sys/doc/sound.doc
@@ -0,0 +1,80 @@
+NOTE! Check that there is no #define EXCLUDE_<cardname> lines for
+ the cards you are configuring in the sound/local.h. Otherwise
+ the low level driver for the card is not compiled in the kernel.
+You may add one or more of the following depending on what you do NOT
+want compiled into your kernel. Only use the options for which you
+do NOT have a card to support it, or if you do not want a particular
+functionality.
+
+ options EXCLUDE_AUDIO # NO digital audio support
+ options EXCLUDE_SEQUENCER # NO sequencer support
+ options "EXCLUDE_MPU401" # NO MPU401 support
+ options EXCLUDE_GUS # NO GUS support
+ options EXCLUDE_GUS_IODETECT # NO GUS io detection
+ options EXCLUDE_SB # NO SB support
+ options EXCLUDE_SB_EMULATION # NO PAS SB emulation support
+ options EXCLUDE_SBPRO # NO SB Pro support
+ options "EXCLUDE_SB16" # NO SB 16 support
+ options "EXCLUDE_YM3812" # NO AdLib support
+ options "EXCLUDE_OPL3" # NO OPL3 chip support
+ options EXCLUDE_PAS # NO Pro Audio Studio support
+ options EXCLUDE_PRO_MIDI # NO PAS MIDI support
+ options EXCLUDE_CHIP_MIDI # NO MIDI chip support
+ options EXCLUDE_MIDI # NO MIDI support whatsoever
+
+To enable sound card support, you need to uncomment and add one or more of
+the following lines to your kernel configuration file according to the
+directions below:
+
+#device snd5 at isa? port 0x330 irq 6 vector mpuintr
+#device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
+#device snd3 at isa? port 0x388 irq 10 drq 6 vector pasintr
+#device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
+#device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr
+#device snd7 at isa? port 0x300
+#device snd1 at isa? port 0x388
+
+Note for PAS user: you should change snd1 line to
+#device snd1 at isa? port 0x38a
+(next stereo port) to avoid conflict with snd3
+
+ Unit numbers are:
+ 1 for Yamaha FM synth
+ 2 for SB/SB Pro DSP
+ 3 for PAS PCM and Midi
+ 4 for GUS
+ 5 for MPU-401 (there is separate driver for the SB16)
+ 6 for SB16 (DSP)
+ 7 for SB16 Midi (MPU-401 emulation)
+
+ If you have ProAudioSpectrum, uncomment units 3, 2 and 1
+ If you have SoundBlaster 1.0 to 2.0 or SB Pro, uncomment 2 and 1.
+ If you have SoundBlaster 16, uncomment 2, 1, 6 and 7.
+ (use the same IRQ for the cards 2, 6 and 7. The DMA of the
+ card 2 is the 8 bit one and the DMA of the card 6 is the 16 bit one.
+ the port address of the card 7 is the Midi I/O address of the SB16.
+ If you have GravisUltrasound, uncomment 4
+ If you have MPU-401, uncomment 5
+
+NOTE: The MPU-401 driver may or may not work, and is unfortunately
+unverifiable since no one I know has one. If you can test this,
+please let me know! Also note that you will have to change these
+settings if your soundcard is set for a non-standard address or IRQ.
+Please check your documentation (or verify with any provided DOS utilities
+that may have come with your card) and set the IRQ or address fields
+accordingly.
+
+Also: Some systems with the OPTI chipset will require you to #define
+BROKEN_BUS_CLOCK in /sys/i386/sound/pas2_card.c. Symptoms are that
+you will hear a lot of clicking and popping sounds, like a geiger counter,
+coming out of the PAS even when is not playing anything.
+
+Probing problems: Since the SB16 uses the same IRQ and addresses for
+the different drivers, some of the snd dirvers will not be probed because
+the kernel thinks there is a conflict. Until a real solution is implemented,
+to get all the snd drivers to work, immediately return(0) to the haveseen()
+call in /sys/i386/isa/isa.c on your local copy. (Warning: doing this
+will bypass checks for ALL drivers, so be careful)
+
+ - Jordan Hubbard (jkh@freefall.cdrom.com)
+ - Steven Wallace (swallace@freefall.cdrom.com)
diff --git a/sys/doc/vm_layout.doc b/sys/doc/vm_layout.doc
new file mode 100644
index 000000000000..6b95bcaf85d6
--- /dev/null
+++ b/sys/doc/vm_layout.doc
@@ -0,0 +1,32 @@
+Physical Memory Layout:
+
+NOT YET DONE
+
+
+
+Virtual Memory Layout:
+
+Page Table Directories, and how they relate to the vm address space
+Note: PTDI stands for Page Table Directory Index.
+
+PTDI Address pmap.h/param.h Calculation to locate it in vm space
+--------------------------------------------------------------------------------
+ FFFFF000 APTD APTmap + (APTDPTDI * NBPG)
+ FFC00000 APTmap APTDPTDI << PDRSHIFT
+3FF FFC00000 APTDPTDI #define (NPTEPG-1)
+ FFBFFFFF KERNEND ((KPTDI+NKPDE) << PDRSHIFT) - 1
+3FD FF400000 .
+3FC FF000000 .
+3FB FEC00000 .
+3FA FE800000 .
+3F9 FE400000 .
+ FE000000 KERNBASE KPTDI << PDRSHIFT
+3F8 FE000000 KPTDI #define (APTDPTDI-NKPDE)
+ FDFF8000 Sysmap PTmap + (KPTDI * NBPG)
+ FDFF7FF8 APTpde PTD + (APTDPTDI * sizeof(pde))
+ FDFF7FDC PTDpde PTD + (PTDPTDI * sizeof(pde))
+ FDFF7000 PTD PTmap + (PTDPTDI * NBPG)
+ FDC00000 PTmap PTDPTDI << PDRSHIFT
+3F7 FDC00000 PTDPTDI #define (KPTDI-1)
+
+$Id: vm_layout.doc,v 1.1 1994/03/30 20:36:36 wollman Exp $
diff --git a/sys/i386/doc/wt.doc b/sys/doc/wt.doc
index 1e9f1bafec8a..1e9f1bafec8a 100644
--- a/sys/i386/doc/wt.doc
+++ b/sys/doc/wt.doc
diff --git a/sys/gnu/fpemul/Changelog b/sys/gnu/fpemul/Changelog
new file mode 100644
index 000000000000..a2fbccd15c2c
--- /dev/null
+++ b/sys/gnu/fpemul/Changelog
@@ -0,0 +1,36 @@
+This file contains the changes made to W. Metzenthem's 387 FPU
+emulator to make it work under NetBSD.
+
+a, Changes to make it compile:
+
+ 1 - Changed the #include's to get the appropriate .h files.
+ 2 - Renamed .S to .s, to satisfy the kernel Makefile.
+ 3 - Changed the C++ style // comments to /* */
+ 4 - Changed the FPU_ORIG_EIP macro. A letter from bde included
+ in the package suggested using tf_isp for using instead
+ of the linux __orig_eip. This later turned out to interfere
+ with the user stack, so i created a separate variable, stored
+ in the i387_union.
+ 5 - Changed the get_fs_.. put_fs_.. fns to fubyte,fuword,subyte,
+ suword.
+ 6 - Removed the verify_area fns. I don't really know what they do,
+ i suppose they verify access to memory. The sufu routines
+ should do this.
+
+b, Changes to make it work:
+
+ 1 - Made math_emulate() to return 0 when successful, so trap() won't
+ try to generate a signal.
+ 2 - Changed the size of the save87 struct in /sys/arch/i387/include/
+ npx.h to accomodate the i387_union.
+
+d, Other changes:
+
+ 1 - Removed obsolate and/or linux specific stuff.
+ 2 - Changed the RE_ENTRANT_CHECK_[ON|OFF] macro to
+ REENTRANT_CHECK([ON|OFF]) so indent can grok it.
+ 3 - Re-indented to Berkeley style.
+ 4 - Limited max no of lookaheads. LOOKAHEAD_LIMIT in fpu_entry.c
+
+
+ Szabolcs Szigeti (pink@fsz.bme.hu)
diff --git a/sys/gnu/fpemul/README b/sys/gnu/fpemul/README
new file mode 100644
index 000000000000..0cef6c456fc7
--- /dev/null
+++ b/sys/gnu/fpemul/README
@@ -0,0 +1,277 @@
+/*
+ * wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ */
+
+wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
+which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
+in turn based upon emu387 which was written by DJ Delorie for djgpp.
+The interface to the Linux kernel is based upon the original Linux
+math emulator by Linus Torvalds.
+
+My target FPU for wm-FPU-emu is that described in the Intel486
+Programmer's Reference Manual (1992 edition). Numerous facets of the
+functioning of the FPU are not well covered in the Reference Manual;
+in the absence of clear details I have made guesses about the most
+reasonable behaviour. Recently, this situation has improved because
+I now have some access to the results produced by a real 80486 FPU.
+
+wm-FPU-emu does not implement all of the behaviour of the 80486 FPU.
+See "Limitations" later in this file for a partial list of some
+differences. I believe that the missing features are never used by
+normal C or FORTRAN programs.
+
+
+Please report bugs, etc to me at:
+ apm233m@vaxc.cc.monash.edu.au
+
+
+--Bill Metzenthen
+ May 1993
+
+
+----------------------- Internals of wm-FPU-emu -----------------------
+
+Numeric algorithms:
+(1) Add, subtract, and multiply. Nothing remarkable in these.
+(2) Divide has been tuned to get reasonable performance. The algorithm
+ is not the obvious one which most people seem to use, but is designed
+ to take advantage of the characteristics of the 80386. I expect that
+ it has been invented many times before I discovered it, but I have not
+ seen it. It is based upon one of those ideas which one carries around
+ for years without ever bothering to check it out.
+(3) The sqrt function has been tuned to get good performance. It is based
+ upon Newton's classic method. Performance was improved by capitalizing
+ upon the properties of Newton's method, and the code is once again
+ structured taking account of the 80386 characteristics.
+(4) The trig, log, and exp functions are based in each case upon quasi-
+ "optimal" polynomial approximations. My definition of "optimal" was
+ based upon getting good accuracy with reasonable speed.
+
+The code of the emulator is complicated slightly by the need to
+account for a limited form of re-entrancy. Normally, the emulator will
+emulate each FPU instruction to completion without interruption.
+However, it may happen that when the emulator is accessing the user
+memory space, swapping may be needed. In this case the emulator may be
+temporarily suspended while disk i/o takes place. During this time
+another process may use the emulator, thereby changing some static
+variables (eg FPU_st0_ptr, etc). The code which accesses user memory
+is confined to five files:
+ fpu_entry.c
+ reg_ld_str.c
+ load_store.c
+ get_address.c
+ errors.c
+
+----------------------- Limitations of wm-FPU-emu -----------------------
+
+There are a number of differences between the current wm-FPU-emu
+(version beta 1.4) and the 80486 FPU (apart from bugs). Some of the
+more important differences are listed below:
+
+All internal computations are performed at 64 bit or higher precision
+and rounded etc as required by the PC bits of the FPU control word.
+Under the crt0 version for Linux current at March 1993, the FPU PC
+bits specify 53 bits precision.
+
+The precision flag (PE of the FPU status word) and the Roundup flag
+(C1 of the status word) are now partially implemented. Does anyone
+write code which uses these features?
+
+The functions which load/store the FPU state are partially implemented,
+but the implementation should be sufficient for handling FPU errors etc
+in 32 bit protected mode.
+
+The implementation of the exception mechanism is flawed for unmasked
+interrupts.
+
+Detection of certain conditions, such as denormal operands, is not yet
+complete.
+
+----------------------- Performance of wm-FPU-emu -----------------------
+
+Speed.
+-----
+
+The speed of floating point computation with the emulator will depend
+upon instruction mix. Relative performance is best for the instructions
+which require most computation. The simple instructions are adversely
+affected by the fpu instruction trap overhead.
+
+
+Timing: Some simple timing tests have been made on the emulator functions.
+The times include load/store instructions. All times are in microseconds
+measured on a 33MHz 386 with 64k cache. The Turbo C tests were under
+ms-dos, the next two columns are for emulators running with the djgpp
+ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97,
+using libm4.0 (hard).
+
+function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
+
+ + 60.5 154.8 76.5 139.4
+ - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7
+ * 71.0 190.8 79.6 146.6
+ / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1
+
+ sin() 310.8 4692.0 319.0 398.5
+ cos() 284.4 4855.2 308.0 388.7
+ tan() 495.0 8807.1 394.9 504.7
+ atan() 328.9 4866.4 601.1 419.5-491.9
+
+ sqrt() 128.7 crashed 145.2 227.0
+ log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1
+ exp() 479.1 6619.2 469.1 850.8
+
+
+The performance under Linux is improved by the use of look-ahead code.
+The following results show the improvement which is obtained under
+Linux due to the look-ahead code. Also given are the times for the
+original Linux emulator with the 4.1 'soft' lib.
+
+ [ Linus' note: I changed look-ahead to be the default under linux, as
+ there was no reason not to use it after I had edited it to be
+ disabled during tracing ]
+
+ wm-FPU-emu w original w
+ look-ahead 'soft' lib
+ + 106.4 190.2
+ - 108.6-111.6 192.4-216.2
+ * 113.4 193.1
+ / 108.8-124.4 700.1-706.2
+
+ sin() 390.5 2642.0
+ cos() 381.5 2767.4
+ tan() 496.5 3153.3
+ atan() 367.2-435.5 2439.4-3396.8
+
+ sqrt() 195.1 4732.5
+ log() 358.0-387.5 3359.2-3390.3
+ exp() 619.3 4046.4
+
+
+These figures are now somewhat out-of-date. The emulator has become
+progressively slower for most functions as more of the 80486 features
+have been implemented.
+
+
+----------------------- Accuracy of wm-FPU-emu -----------------------
+
+
+Accuracy: The following table gives the accuracy of the sqrt(), trig
+and log functions. Each function was tested at about 400 points. Ideal
+results would be 64 bits. The reduced accuracy of cos() and tan() for
+arguments greater than pi/4 can be thought of as being due to the
+precision of the argument x; e.g. an argument of pi/2-(1e-10) which is
+accurate to 64 bits can result in a relative accuracy in cos() of about
+64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given
+in the last column.
+
+
+Function Tested x range Worst result (bits) Turbo C
+
+sqrt(x) 1 .. 2 64.1 63.2
+atan(x) 1e-10 .. 200 62.6 62.8
+cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4
+ 35.2 (x = pi/2-(1e-10)) 31.9
+sin(x) 1e-10 .. pi/2 63.0 62.8
+tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1
+ 35.2 (x = pi/2-(1e-10)) 31.9
+exp(x) 0 .. 1 63.1 62.9
+log(x) 1+1e-6 .. 2 62.4 62.1
+
+
+As of version 1.3 of the emulator, the accuracy of the basic
+arithmetic has been improved (by a small fraction of a bit). Care has
+been taken to ensure full accuracy of the rounding of the basic
+arithmetic functions (+,-,*,/,and fsqrt), and they all now produce
+results which are exact to the 64th bit (unless there are any bugs
+left). To ensure this, it was necessary to effectively get information
+of up to about 128 bits precision. The emulator now passes the
+"paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24
+bit precision numbers) when precision control is set to 24, 53 or 64
+bits, and for 'double' variables (53 bit precision numbers) when
+precision control is set to 53 bits (a properly performing FPU cannot
+pass the 'paranoia' tests for 'double' variables when precision
+control is set to 64 bits).
+
+------------------------- Contributors -------------------------------
+
+A number of people have contributed to the development of the
+emulator, often by just reporting bugs, sometimes with a suggested
+fix, and a few kind people have provided me with access in one way or
+another to an 80486 machine. Contributors include (to those people who
+I have forgotten, please excuse me):
+
+Linus Torvalds
+Tommy.Thorn@daimi.aau.dk
+Andrew.Tridgell@anu.edu.au
+Nick Holloway alfie@dcs.warwick.ac.uk
+Hermano Moura moura@dcs.gla.ac.uk
+Jon Jagger J.Jagger@scp.ac.uk
+Lennart Benschop
+Brian Gallew geek+@CMU.EDU
+Thomas Staniszewski ts3v+@andrew.cmu.edu
+Martin Howell mph@plasma.apana.org.au
+M Saggaf alsaggaf@athena.mit.edu
+Peter Barker PETER@socpsy.sci.fau.edu
+tom@vlsivie.tuwien.ac.at
+Dan Russel russed@rpi.edu
+Daniel Carosone danielce@ee.mu.oz.au
+cae@jpmorgan.com
+Hamish Coleman t933093@minyos.xx.rmit.oz.au
+
+...and numerous others who responded to my request for help with
+a real 80486.
+
diff --git a/sys/gnu/fpemul/control_w.h b/sys/gnu/fpemul/control_w.h
new file mode 100644
index 000000000000..2f3dc2ec854a
--- /dev/null
+++ b/sys/gnu/fpemul/control_w.h
@@ -0,0 +1,95 @@
+/*
+ * control_w.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: control_w.h,v 1.3 1994/06/10 07:44:07 rich Exp $
+ *
+ */
+
+#ifndef _CONTROLW_H_
+#define _CONTROLW_H_
+
+#ifdef LOCORE
+#define _Const_(x) $/**/x
+#else
+#define _Const_(x) x
+#endif
+
+#define CW_RC _Const_(0x0C00) /* rounding control */
+#define CW_PC _Const_(0x0300) /* precision control */
+
+#define CW_Precision Const_(0x0020) /* loss of precision mask */
+#define CW_Underflow Const_(0x0010) /* underflow mask */
+#define CW_Overflow Const_(0x0008) /* overflow mask */
+#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */
+#define CW_Denormal Const_(0x0002) /* denormalized operand mask */
+#define CW_Invalid Const_(0x0001) /* invalid operation mask */
+
+#define CW_Exceptions _Const_(0x003f) /* all masks */
+
+#define RC_RND _Const_(0x0000)
+#define RC_DOWN _Const_(0x0400)
+#define RC_UP _Const_(0x0800)
+#define RC_CHOP _Const_(0x0C00)
+
+/* p 15-5: Precision control bits affect only the following:
+ ADD, SUB(R), MUL, DIV(R), and SQRT */
+#define PR_24_BITS _Const_(0x000)
+#define PR_53_BITS _Const_(0x200)
+#define PR_64_BITS _Const_(0x300)
+/* FULL_PRECISION simulates all exceptions masked */
+#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f)
+
+#endif /* _CONTROLW_H_ */
diff --git a/sys/gnu/fpemul/div_small.s b/sys/gnu/fpemul/div_small.s
new file mode 100644
index 000000000000..aff2738fe43f
--- /dev/null
+++ b/sys/gnu/fpemul/div_small.s
@@ -0,0 +1,101 @@
+ .file "div_small.S"
+/*
+ * div_small.S
+ *
+ * Divide a 64 bit integer by a 32 bit integer & return remainder.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: div_small.s,v 1.3 1994/06/10 07:44:08 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | unsigned long div_small(unsigned long long *x, unsigned long y) |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+
+.globl _div_small
+
+_div_small:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ecx /* The denominator */
+
+ movl 4(%esi),%eax /* Get the current num msw */
+ xorl %edx,%edx
+ divl %ecx
+
+ movl %eax,4(%esi)
+
+ movl (%esi),%eax /* Get the num lsw */
+ divl %ecx
+
+ movl %eax,(%esi)
+
+ movl %edx,%eax /* Return the remainder in eax */
+
+ popl %esi
+
+ leave
+ ret
+
diff --git a/sys/gnu/fpemul/errors.c b/sys/gnu/fpemul/errors.c
new file mode 100644
index 000000000000..dd8f1b2a1692
--- /dev/null
+++ b/sys/gnu/fpemul/errors.c
@@ -0,0 +1,612 @@
+/*
+ * errors.c
+ *
+ * The error handling functions for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: errors.c,v 1.3 1994/06/10 07:44:10 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "control_w.h"
+#include "reg_constant.h"
+#include "version.h"
+
+/* */
+#undef PRINT_MESSAGES
+/* */
+
+
+void
+Un_impl(void)
+{
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+ printf("Unimplemented FPU Opcode at eip=%p : %02x ",
+ FPU_ORIG_EIP, byte1);
+
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d\n", (FPU_modrm >> 3) & 7);
+ REENTRANT_CHECK(ON);
+
+ EXCEPTION(EX_Invalid);
+
+}
+
+
+
+
+void
+emu_printall()
+{
+ int i;
+ static char *tag_desc[] = {"Valid", "Zero", "ERROR", "ERROR",
+ "DeNorm", "Inf", "NaN", "Empty"};
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+#ifdef DEBUGGING
+ if (status_word & SW_Backward)
+ printf("SW: backward compatibility\n");
+ if (status_word & SW_C3)
+ printf("SW: condition bit 3\n");
+ if (status_word & SW_C2)
+ printf("SW: condition bit 2\n");
+ if (status_word & SW_C1)
+ printf("SW: condition bit 1\n");
+ if (status_word & SW_C0)
+ printf("SW: condition bit 0\n");
+ if (status_word & SW_Summary)
+ printf("SW: exception summary\n");
+ if (status_word & SW_Stack_Fault)
+ printf("SW: stack fault\n");
+ if (status_word & SW_Precision)
+ printf("SW: loss of precision\n");
+ if (status_word & SW_Underflow)
+ printf("SW: underflow\n");
+ if (status_word & SW_Overflow)
+ printf("SW: overflow\n");
+ if (status_word & SW_Zero_Div)
+ printf("SW: divide by zero\n");
+ if (status_word & SW_Denorm_Op)
+ printf("SW: denormalized operand\n");
+ if (status_word & SW_Invalid)
+ printf("SW: invalid operation\n");
+#endif /* DEBUGGING */
+
+ status_word = status_word & ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ printf("At %p: %02x ", FPU_ORIG_EIP, byte1);
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d, mod=%d rm=%d\n",
+ (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+
+ printf(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
+ status_word & 0x8000 ? 1 : 0, /* busy */
+ (status_word & 0x3800) >> 11, /* stack top pointer */
+ status_word & 0x80 ? 1 : 0, /* Error summary status */
+ status_word & 0x40 ? 1 : 0, /* Stack flag */
+ status_word & SW_C3 ? 1 : 0, status_word & SW_C2 ? 1 : 0, /* cc */
+ status_word & SW_C1 ? 1 : 0, status_word & SW_C0 ? 1 : 0, /* cc */
+ status_word & SW_Precision ? 1 : 0, status_word & SW_Underflow ? 1 : 0,
+ status_word & SW_Overflow ? 1 : 0, status_word & SW_Zero_Div ? 1 : 0,
+ status_word & SW_Denorm_Op ? 1 : 0, status_word & SW_Invalid ? 1 : 0);
+
+ printf(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
+ control_word & 0x1000 ? 1 : 0,
+ (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
+ (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
+ control_word & 0x80 ? 1 : 0,
+ control_word & SW_Precision ? 1 : 0, control_word & SW_Underflow ? 1 : 0,
+ control_word & SW_Overflow ? 1 : 0, control_word & SW_Zero_Div ? 1 : 0,
+ control_word & SW_Denorm_Op ? 1 : 0, control_word & SW_Invalid ? 1 : 0);
+
+ for (i = 0; i < 8; i++) {
+ FPU_REG *r = &st(i);
+ switch (r->tag) {
+ case TW_Empty:
+ continue;
+ break;
+ case TW_Zero:
+ printf("st(%d) %c .0000 0000 0000 0000 ",
+ i, r->sign ? '-' : '+');
+ break;
+ case TW_Valid:
+ case TW_NaN:
+ case TW_Denormal:
+ case TW_Infinity:
+ printf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
+ r->sign ? '-' : '+',
+ (long) (r->sigh >> 16),
+ (long) (r->sigh & 0xFFFF),
+ (long) (r->sigl >> 16),
+ (long) (r->sigl & 0xFFFF),
+ r->exp - EXP_BIAS + 1);
+ break;
+ default:
+ printf("Whoops! Error in errors.c ");
+ break;
+ }
+ printf("%s\n", tag_desc[(int) (unsigned) r->tag]);
+ }
+
+ printf("[data] %c .%04x %04x %04x %04x e%+-6d ",
+ FPU_loaded_data.sign ? '-' : '+',
+ (long) (FPU_loaded_data.sigh >> 16),
+ (long) (FPU_loaded_data.sigh & 0xFFFF),
+ (long) (FPU_loaded_data.sigl >> 16),
+ (long) (FPU_loaded_data.sigl & 0xFFFF),
+ FPU_loaded_data.exp - EXP_BIAS + 1);
+ printf("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
+ REENTRANT_CHECK(ON);
+
+}
+
+static struct {
+ int type;
+ char *name;
+} exception_names[] = {
+ {
+ EX_StackOver, "stack overflow"
+ },
+ {
+ EX_StackUnder, "stack underflow"
+ },
+ {
+ EX_Precision, "loss of precision"
+ },
+ {
+ EX_Underflow, "underflow"
+ },
+ {
+ EX_Overflow, "overflow"
+ },
+ {
+ EX_ZeroDiv, "divide by zero"
+ },
+ {
+ EX_Denormal, "denormalized operand"
+ },
+ {
+ EX_Invalid, "invalid operation"
+ },
+ {
+ EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION
+ },
+ {
+ 0, NULL
+ }
+};
+/*
+ EX_INTERNAL is always given with a code which indicates where the
+ error was detected.
+
+ Internal error types:
+ 0x14 in e14.c
+ 0x1nn in a *.c file:
+ 0x101 in reg_add_sub.c
+ 0x102 in reg_mul.c
+ 0x103 in poly_sin.c
+ 0x104 in poly_tan.c
+ 0x105 in reg_mul.c
+ 0x106 in reg_mov.c
+ 0x107 in fpu_trig.c
+ 0x108 in reg_compare.c
+ 0x109 in reg_compare.c
+ 0x110 in reg_add_sub.c
+ 0x111 in interface.c
+ 0x112 in fpu_trig.c
+ 0x113 in reg_add_sub.c
+ 0x114 in reg_ld_str.c
+ 0x115 in fpu_trig.c
+ 0x116 in fpu_trig.c
+ 0x117 in fpu_trig.c
+ 0x118 in fpu_trig.c
+ 0x119 in fpu_trig.c
+ 0x120 in poly_atan.c
+ 0x121 in reg_compare.c
+ 0x122 in reg_compare.c
+ 0x123 in reg_compare.c
+ 0x2nn in an *.s file:
+ 0x201 in reg_u_add.S
+ 0x202 in reg_u_div.S
+ 0x203 in reg_u_div.S
+ 0x204 in reg_u_div.S
+ 0x205 in reg_u_mul.S
+ 0x206 in reg_u_sub.S
+ 0x207 in wm_sqrt.S
+ 0x208 in reg_div.S
+ 0x209 in reg_u_sub.S
+ 0x210 in reg_u_sub.S
+ 0x211 in reg_u_sub.S
+ 0x212 in reg_u_sub.S
+ 0x213 in wm_sqrt.S
+ 0x214 in wm_sqrt.S
+ 0x215 in wm_sqrt.S
+ 0x216 in reg_round.S
+ 0x217 in reg_round.S
+ 0x218 in reg_round.S
+ */
+
+void
+exception(int n)
+{
+ int i, int_type;
+
+ int_type = 0; /* Needed only to stop compiler warnings */
+ if (n & EX_INTERNAL) {
+ int_type = n - EX_INTERNAL;
+ n = EX_INTERNAL;
+ /* Set lots of exception bits! */
+ status_word |= (SW_Exc_Mask | SW_Summary | FPU_BUSY);
+ } else {
+ /* Extract only the bits which we use to set the status word */
+ n &= (SW_Exc_Mask);
+ /* Set the corresponding exception bit */
+ status_word |= n;
+ if (status_word & ~control_word & CW_Exceptions)
+ status_word |= SW_Summary;
+ if (n & (SW_Stack_Fault | EX_Precision)) {
+ if (!(n & SW_C1))
+ /* This bit distinguishes over- from underflow
+ * for a stack fault, and roundup from
+ * round-down for precision loss. */
+ status_word &= ~SW_C1;
+ }
+ }
+
+ REENTRANT_CHECK(OFF);
+ if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
+#ifdef PRINT_MESSAGES
+ /* My message from the sponsor */
+ printf(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
+#endif /* PRINT_MESSAGES */
+
+ /* Get a name string for error reporting */
+ for (i = 0; exception_names[i].type; i++)
+ if ((exception_names[i].type & n) == exception_names[i].type)
+ break;
+
+ if (exception_names[i].type) {
+#ifdef PRINT_MESSAGES
+ printf("FP Exception: %s!\n", exception_names[i].name);
+#endif /* PRINT_MESSAGES */
+ } else
+ printf("FP emulator: Unknown Exception: 0x%04x!\n", n);
+
+ if (n == EX_INTERNAL) {
+ printf("FP emulator: Internal error type 0x%04x\n", int_type);
+ emu_printall();
+ }
+#ifdef PRINT_MESSAGES
+ else
+ emu_printall();
+#endif /* PRINT_MESSAGES */
+
+ /* The 80486 generates an interrupt on the next non-control
+ * FPU instruction. So we need some means of flagging it. We
+ * use the ES (Error Summary) bit for this, assuming that this
+ * is the way a real FPU does it (until I can check it out),
+ * if not, then some method such as the following kludge might
+ * be needed. */
+/* regs[0].tag |= TW_FPU_Interrupt; */
+ }
+ REENTRANT_CHECK(ON);
+
+#ifdef __DEBUG__
+ math_abort(SIGFPE);
+#endif /* __DEBUG__ */
+
+}
+
+
+/* Real operation attempted on two operands, one a NaN */
+void
+real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest)
+{
+ FPU_REG *x;
+ int signalling;
+
+ x = a;
+ if (a->tag == TW_NaN) {
+ if (b->tag == TW_NaN) {
+ signalling = !(a->sigh & b->sigh & 0x40000000);
+ /* find the "larger" */
+ if (*(long long *) &(a->sigl) < *(long long *) &(b->sigl))
+ x = b;
+ } else {
+ /* return the quiet version of the NaN in a */
+ signalling = !(a->sigh & 0x40000000);
+ }
+ } else
+#ifdef PARANOID
+ if (b->tag == TW_NaN)
+#endif /* PARANOID */
+ {
+ signalling = !(b->sigh & 0x40000000);
+ x = b;
+ }
+#ifdef PARANOID
+ else {
+ signalling = 0;
+ EXCEPTION(EX_INTERNAL | 0x113);
+ x = &CONST_QNaN;
+ }
+#endif /* PARANOID */
+
+ if (!signalling) {
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ return;
+ }
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ /* ensure a Quiet NaN */
+ dest->sigh |= 0x40000000;
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+}
+/* Invalid arith operation on Valid registers */
+void
+arith_invalid(FPU_REG * dest)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, dest);
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+
+}
+
+
+/* Divide a finite number by zero */
+void
+divide_by_zero(int sign, FPU_REG * dest)
+{
+
+ if (control_word & CW_ZeroDiv) {
+ /* The masked response */
+ reg_move(&CONST_INF, dest);
+ dest->sign = (unsigned char) sign;
+ }
+ EXCEPTION(EX_ZeroDiv);
+
+ return;
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_up(void)
+{
+ if (control_word & CW_Precision)
+ status_word |= (SW_Precision | SW_C1); /* The masked response */
+ else
+ exception(EX_Precision | SW_C1);
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_down(void)
+{
+ if (control_word & CW_Precision) { /* The masked response */
+ status_word &= ~SW_C1;
+ status_word |= SW_Precision;
+ } else
+ exception(EX_Precision);
+}
+
+
+int
+denormal_operand(void)
+{
+ if (control_word & CW_Denormal) { /* The masked response */
+ status_word |= SW_Denorm_Op;
+ return 0;
+ } else {
+ exception(EX_Denormal);
+ return 1;
+ }
+}
+
+
+void
+arith_overflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Overflow) {
+ char sign;
+ /* The masked response */
+/* **** The response here depends upon the rounding mode */
+ sign = dest->sign;
+ reg_move(&CONST_INF, dest);
+ dest->sign = sign;
+ } else {
+ /* Subtract the magic number from the exponent */
+ dest->exp -= (3 * (1 << 13));
+ }
+
+ /* By definition, precision is lost. It appears that the roundup bit
+ * (C1) is also set by convention. */
+ EXCEPTION(EX_Overflow | EX_Precision | SW_C1);
+
+ return;
+
+}
+
+
+void
+arith_underflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Underflow) {
+ /* The masked response */
+ if (dest->exp <= EXP_UNDER - 63)
+ reg_move(&CONST_Z, dest);
+ } else {
+ /* Add the magic number to the exponent */
+ dest->exp += (3 * (1 << 13));
+ }
+
+ EXCEPTION(EX_Underflow);
+
+ return;
+}
+
+
+void
+stack_overflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ top--;
+ reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
+ }
+ EXCEPTION(EX_StackOver);
+
+ return;
+
+}
+
+
+void
+stack_underflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, FPU_st0_ptr);
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_i(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_pop(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ pop();
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
diff --git a/sys/gnu/fpemul/exception.h b/sys/gnu/fpemul/exception.h
new file mode 100644
index 000000000000..af814f1d5191
--- /dev/null
+++ b/sys/gnu/fpemul/exception.h
@@ -0,0 +1,102 @@
+/*
+ * exception.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: exception.h,v 1.3 1994/06/10 07:44:12 rich Exp $
+ *
+ *
+ */
+
+#ifndef _EXCEPTION_H_
+#define _EXCEPTION_H_
+
+
+#ifdef LOCORE
+#define Const_(x) $/**/x
+#else
+#define Const_(x) x
+#endif
+
+#ifndef SW_C1
+#include "fpu_emu.h"
+#endif /* SW_C1 */
+
+#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
+#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
+/* Special exceptions: */
+#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
+#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
+#define EX_StackUnder Const_(0x0041) /* stack underflow */
+/* Exception flags: */
+#define EX_Precision Const_(0x0020) /* loss of precision */
+#define EX_Underflow Const_(0x0010) /* underflow */
+#define EX_Overflow Const_(0x0008) /* overflow */
+#define EX_ZeroDiv Const_(0x0004) /* divide by zero */
+#define EX_Denormal Const_(0x0002) /* denormalized operand */
+#define EX_Invalid Const_(0x0001) /* invalid operation */
+
+
+#ifndef LOCORE
+
+#ifdef DEBUG
+#define EXCEPTION(x) { printf("exception in %s at line %d\n", \
+ __FILE__, __LINE__); exception(x); }
+#else
+#define EXCEPTION(x) exception(x)
+#endif
+
+#endif /* LOCORE */
+
+#endif /* _EXCEPTION_H_ */
diff --git a/sys/gnu/fpemul/fpu_arith.c b/sys/gnu/fpemul/fpu_arith.c
new file mode 100644
index 000000000000..0ffb6615e70b
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_arith.c
@@ -0,0 +1,235 @@
+/*
+ * fpu_arith.c
+ *
+ * Code to implement the FPU register/register arithmetic instructions
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_arith.c,v 1.3 1994/06/10 07:44:14 rich Exp $
+ *
+ */
+
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+
+
+void
+fadd__()
+{
+ /* fadd st,st(i) */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fmul__()
+{
+ /* fmul st,st(i) */
+ reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fsub__()
+{
+ /* fsub st,st(i) */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fsubr_()
+{
+ /* fsubr st,st(i) */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+void
+fdiv__()
+{
+ /* fdiv st,st(i) */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fdivr_()
+{
+ /* fdivr st,st(i) */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fadd_i()
+{
+ /* fadd st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fmul_i()
+{
+ /* fmul st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fsubri()
+{
+ /* fsubr st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fsub_i()
+{
+ /* fsub st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fdivri()
+{
+ /* fdivr st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fdiv_i()
+{
+ /* fdiv st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+
+void
+faddp_()
+{
+ /* faddp st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fmulp_()
+{
+ /* fmulp st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+
+void
+fsubrp()
+{
+ /* fsubrp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fsubp_()
+{
+ /* fsubp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivrp()
+{
+ /* fdivrp st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivp_()
+{
+ /* fdivp st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
diff --git a/sys/gnu/fpemul/fpu_asm.h b/sys/gnu/fpemul/fpu_asm.h
new file mode 100644
index 000000000000..2f6e58a65410
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_asm.h
@@ -0,0 +1,82 @@
+/*
+ * fpu_asm.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_asm.h,v 1.3 1994/06/10 07:44:16 rich Exp $
+ *
+ */
+
+#ifndef _FPU_ASM_H_
+#define _FPU_ASM_H_
+
+#include "fpu_emu.h"
+
+#define EXCEPTION _exception
+
+
+#define PARAM1 8(%ebp)
+#define PARAM2 12(%ebp)
+#define PARAM3 16(%ebp)
+#define PARAM4 20(%ebp)
+
+#define SIGL_OFFSET 8
+#define SIGN(x) (x)
+#define TAG(x) 1(x)
+#define EXP(x) 4(x)
+#define SIG(x) SIGL_OFFSET/**/(x)
+#define SIGL(x) SIGL_OFFSET/**/(x)
+#define SIGH(x) 12(x)
+
+#endif /* _FPU_ASM_H_ */
diff --git a/sys/gnu/fpemul/fpu_aux.c b/sys/gnu/fpemul/fpu_aux.c
new file mode 100644
index 000000000000..135fef9e105f
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_aux.c
@@ -0,0 +1,233 @@
+/*
+ * fpu_aux.c
+ *
+ * Code to implement some of the FPU auxiliary instructions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_aux.c,v 1.3 1994/06/10 07:44:17 rich Exp $
+ *
+ */
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+
+
+
+void
+fclex(void)
+{
+ status_word &= ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
+ SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
+ SW_Invalid);
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+}
+/* Needs to be externally visible */
+void
+finit()
+{
+ int r;
+ control_word = 0x037f;
+ status_word = 0;
+ top = 0; /* We don't keep top in the status word
+ * internally. */
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ FPU_entry_eip = ip_offset = 0;
+}
+
+static FUNC finit_table[] = {
+ Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+finit_()
+{
+ (finit_table[FPU_rm]) ();
+}
+
+
+static void
+fstsw_ax(void)
+{
+
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ *(short *) &FPU_EAX = status_word;
+
+}
+
+static FUNC fstsw_table[] = {
+ fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fstsw_()
+{
+ (fstsw_table[FPU_rm]) ();
+}
+
+
+
+static void
+fnop(void)
+{
+}
+
+FUNC fp_nop_table[] = {
+ fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fp_nop()
+{
+ (fp_nop_table[FPU_rm]) ();
+}
+
+
+void
+fld_i_()
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ /* fld st(i) */
+ if (NOT_EMPTY(FPU_rm)) {
+ reg_move(&st(FPU_rm), st_new_ptr);
+ push();
+ } else {
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+
+}
+
+
+void
+fxch_i()
+{
+ /* fxch st(i) */
+ FPU_REG t;
+ register FPU_REG *sti_ptr = &st(FPU_rm);
+
+ if (FPU_st0_tag == TW_Empty) {
+ if (sti_ptr->tag == TW_Empty) {
+ stack_underflow();
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ reg_move(sti_ptr, FPU_st0_ptr);
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ if (sti_ptr->tag == TW_Empty) {
+ reg_move(FPU_st0_ptr, sti_ptr);
+ stack_underflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ reg_move(sti_ptr, FPU_st0_ptr);
+ reg_move(&t, sti_ptr);
+}
+
+
+void
+ffree_()
+{
+ /* ffree st(i) */
+ st(FPU_rm).tag = TW_Empty;
+}
+
+
+void
+ffreep()
+{
+ /* ffree st(i) + pop - unofficial code */
+ st(FPU_rm).tag = TW_Empty;
+ pop();
+}
+
+
+void
+fst_i_()
+{
+ /* fst st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+}
+
+
+void
+fstp_i()
+{
+ /* fstp st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+ pop();
+}
diff --git a/sys/gnu/fpemul/fpu_emu.h b/sys/gnu/fpemul/fpu_emu.h
new file mode 100644
index 000000000000..b81a85127fec
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_emu.h
@@ -0,0 +1,188 @@
+/*
+ * fpu_emu.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_emu.h,v 1.3 1994/06/10 07:44:19 rich Exp $
+ *
+ */
+
+
+#ifndef _FPU_EMU_H_
+#define _FPU_EMU_H_
+
+/*
+ * Define DENORM_OPERAND to make the emulator detect denormals
+ * and use the denormal flag of the status word. Note: this only
+ * affects the flag and corresponding interrupt, the emulator
+ * will always generate denormals and operate upon them as required.
+ */
+#define DENORM_OPERAND
+
+/*
+ * Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
+ * rather than behaviour which appears to be cleaner.
+ * This is a matter of opinion: for all I know, the 80486 may simply
+ * be complying with the IEEE spec. Maybe one day I'll get to see the
+ * spec...
+ */
+#define PECULIAR_486
+
+#ifdef LOCORE
+#include "fpu_asm.h"
+#define Const(x) $/**/x
+#else
+#define Const(x) x
+#endif
+
+#define EXP_BIAS Const(0)
+#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
+#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
+
+#define SIGN_POS Const(0)
+#define SIGN_NEG Const(1)
+
+/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
+#define TW_Valid Const(0)/* valid */
+#define TW_Zero Const(1)/* zero */
+/* The following fold to 2 (Special) in the Tag Word */
+#define TW_Denormal Const(4)/* De-normal */
+#define TW_Infinity Const(5)/* + or - infinity */
+#define TW_NaN Const(6)/* Not a Number */
+
+#define TW_Empty Const(7)/* empty */
+
+ /* #define TW_FPU_Interrupt Const(0x80) *//* Signals an interrupt */
+
+
+#ifndef LOCORE
+
+#include "types.h"
+#include "math_emu.h"
+
+#ifdef PARANOID
+extern char emulating;
+#define REENTRANT_CHECK(state) emulating = (state)
+#define ON 1
+#define OFF 0
+#else
+#define REENTRANT_CHECK(state)
+#endif /* PARANOID */
+
+typedef void (*FUNC) (void);
+typedef struct fpu_reg FPU_REG;
+
+#define st(x) ( regs[((top+x) &7 )] )
+
+#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
+#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
+#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty)
+
+extern unsigned char FPU_rm;
+
+extern char FPU_st0_tag;
+extern FPU_REG *FPU_st0_ptr;
+
+extern void *FPU_data_address;
+
+extern FPU_REG FPU_loaded_data;
+
+#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; }
+
+/* push() does not affect the tags */
+#define push() { top--; FPU_st0_ptr = st_new_ptr; }
+
+
+#define reg_move(x, y) { \
+ *(short *)&((y)->sign) = *(short *)&((x)->sign); \
+ *(long *)&((y)->exp) = *(long *)&((x)->exp); \
+ *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
+
+
+/*----- Prototypes for functions written in assembler -----*/
+/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
+
+extern void mul64(long long *a, long long *b, long long *result);
+extern void poly_div2(long long *x);
+extern void poly_div4(long long *x);
+extern void poly_div16(long long *x);
+extern void
+polynomial(unsigned accum[], unsigned x[],
+ unsigned short terms[][4], int n);
+ extern void normalize(FPU_REG * x);
+ extern void normalize_nuo(FPU_REG * x);
+ extern void reg_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_sub(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_mul(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_add(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void wm_sqrt(FPU_REG * n, unsigned int control_w);
+ extern unsigned shrx(void *l, unsigned x);
+ extern unsigned shrxs(void *v, unsigned x);
+ extern unsigned long div_small(unsigned long long *x, unsigned long y);
+ extern void round_reg(FPU_REG * arg, unsigned int extent,
+ unsigned int control_w);
+
+#ifndef MAKING_PROTO
+#include "fpu_proto.h"
+#endif
+
+#endif /* LOCORE */
+
+#endif /* _FPU_EMU_H_ */
diff --git a/sys/gnu/fpemul/fpu_entry.c b/sys/gnu/fpemul/fpu_entry.c
new file mode 100644
index 000000000000..7a882227bcdb
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_entry.c
@@ -0,0 +1,483 @@
+/*
+ * fpu_entry.c
+ *
+ * The entry function for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ * $Id: fpu_entry.c,v 1.4 1994/06/22 05:52:14 jkh Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | math_emulate() is the sole entry point for wm-FPU-emu |
+ +---------------------------------------------------------------------------*/
+
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define __BAD__ Un_impl /* Not implemented */
+
+#define FPU_LOOKAHEAD 1 /* For performance boost */
+
+#if FPU_LOOKAHEAD != 0 /* I think thet we have to limit the */
+#define LOOKAHEAD_LIMIT 7 /* Max number of lookahead instructions*/
+#endif /* Or else a prog consisting of a million */
+ /* fnops will spend all its time in kernel*/
+
+#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by
+ * default. */
+
+/* WARNING: These codes are not documented by Intel in their 80486 manual
+ and may not work on FPU clones or later Intel FPUs. */
+
+/* Changes to support the un-doc codes provided by Linus Torvalds. */
+
+#define _d9_d8_ fstp_i /* unofficial code (19) */
+#define _dc_d0_ fcom_st /* unofficial code (14) */
+#define _dc_d8_ fcompst /* unofficial code (1c) */
+#define _dd_c8_ fxch_i /* unofficial code (0d) */
+#define _de_d0_ fcompst /* unofficial code (16) */
+#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
+#define _df_c8_ fxch_i /* unofficial code (0f) */
+#define _df_d0_ fstp_i /* unofficial code (17) */
+#define _df_d8_ fstp_i /* unofficial code (1f) */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
+ fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
+ fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#else /* Support only documented FPU op-codes */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#endif /* NO_UNDOC_CODE */
+
+
+#define _NONE_ 0 /* Take no special action */
+#define _REG0_ 1 /* Need to check for not empty st(0) */
+#define _REGI_ 2 /* Need to check for not empty st(0) and
+ * st(rm) */
+#define _REGi_ 0 /* Uses st(rm) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
+#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm)
+ * then pop */
+#define _REGIc 0 /* Compare st(0) and st(rm) */
+#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks
+ * later */
+
+#ifndef NO_UNDOC_CODE
+
+/* Un-documented FPU op-codes supported by default. (see above) */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
+ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#else /* Support only documented FPU op-codes */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
+ _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#endif /* NO_UNDOC_CODE */
+
+/* Be careful when using any of these global variables...
+ they might change if swapping is triggered */
+unsigned char FPU_rm;
+char FPU_st0_tag;
+FPU_REG *FPU_st0_ptr;
+
+#ifdef PARANOID
+char emulating = 0;
+#endif /* PARANOID */
+
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define math_abort(signo) \
+ FPU_EIP = FPU_ORIG_EIP;REENTRANT_CHECK(OFF);return(signo);
+
+int
+math_emulate(struct trapframe * tframe)
+{
+
+ unsigned char FPU_modrm;
+ unsigned short code;
+#ifdef LOOKAHEAD_LIMIT
+ int lookahead_limit = LOOKAHEAD_LIMIT;
+#endif
+#ifdef PARANOID
+ if (emulating) {
+ printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
+ }
+ REENTRANT_CHECK(ON);
+#endif /* PARANOID */
+
+ if ((((struct pcb *) curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
+ finit();
+ control_word = __INITIAL_NPXCW__;
+ ((struct pcb *) curproc->p_addr)->pcb_flags |= FP_SOFTFP;
+ }
+ FPU_info = tframe;
+ FPU_ORIG_EIP = FPU_EIP; /* --pink-- */
+
+ if (FPU_CS != 0x001f) {
+ printf("math_emulate: %x : %x\n", FPU_CS, FPU_EIP);
+ panic("FPU emulation in kernel");
+ }
+#ifdef notyet
+ /* We cannot handle emulation in v86-mode */
+ if (FPU_EFLAGS & 0x00020000) {
+ FPU_ORIG_EIP = FPU_EIP;
+ math_abort(FPU_info, SIGILL);
+ }
+#endif
+
+ FPU_lookahead = FPU_LOOKAHEAD;
+ if (curproc->p_flag & STRC)
+ FPU_lookahead = 0;
+
+do_another_FPU_instruction:
+
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if ((code & 0xff) == 0x9b) { /* fwait */
+ if (status_word & SW_Summary)
+ goto do_the_FPU_interrupt;
+ else {
+ FPU_EIP++;
+ goto FPU_instruction_done;
+ }
+ }
+ if (status_word & SW_Summary) {
+ /* Ignore the error for now if the current instruction is a
+ * no-wait control instruction */
+ /* The 80486 manual contradicts itself on this topic, so I use
+ * the following list of such instructions until I can check
+ * on a real 80486: fninit, fnstenv, fnsave, fnstsw, fnstenv,
+ * fnclex. */
+ if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit,
+ * fnstsw */
+ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw,
+ * fnstenv, fnstsw */
+ ((code & 0xc000) != 0xc000))))) {
+ /* This is a guess about what a real FPU might do to
+ * this bit: */
+/* status_word &= ~SW_Summary; ****/
+
+ /* We need to simulate the action of the kernel to FPU
+ * interrupts here. Currently, the "real FPU" part of
+ * the kernel (0.99.10) clears the exception flags,
+ * sets the registers to empty, and passes information
+ * back to the interrupted process via the cs selector
+ * and operand selector, so we do the same. */
+ do_the_FPU_interrupt:
+ cs_selector &= 0xffff0000;
+ cs_selector |= (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift);
+ operand_selector = tag_word();
+ status_word = 0;
+ top = 0;
+ {
+ int r;
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ math_abort(SIGFPE);
+ }
+ }
+ FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
+
+ if ((code & 0xff) == 0x66) { /* size prefix */
+ FPU_EIP++;
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ }
+ FPU_EIP += 2;
+
+ FPU_modrm = code >> 8;
+ FPU_rm = FPU_modrm & 7;
+
+ if (FPU_modrm < 0300) {
+ /* All of these instructions use the mod/rm byte to get a data
+ * address */
+ get_address(FPU_modrm);
+ if (!(code & 1)) {
+ unsigned short status1 = status_word;
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* Stack underflow has priority */
+ if (NOT_EMPTY_0) {
+ switch ((code >> 1) & 3) {
+ case 0:
+ reg_load_single();
+ break;
+ case 1:
+ reg_load_int32();
+ break;
+ case 2:
+ reg_load_double();
+ break;
+ case 3:
+ reg_load_int16();
+ break;
+ }
+
+ /* No more access to user memory, it is safe
+ * to use static data now */
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* NaN operands have the next priority. */
+ /* We have to delay looking at st(0) until
+ * after loading the data, because that data
+ * might contain an SNaN */
+ if ((FPU_st0_tag == TW_NaN) ||
+ (FPU_loaded_data.tag == TW_NaN)) {
+ /* Restore the status word; we might
+ * have loaded a denormal. */
+ status_word = status1;
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* fcom or fcomp */
+ EXCEPTION(EX_Invalid);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, so we pop. */
+ } else
+ real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
+ goto reg_mem_instr_done;
+ }
+ switch ((FPU_modrm >> 3) & 7) {
+ case 0: /* fadd */
+ reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 1: /* fmul */
+ reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 2: /* fcom */
+ compare_st_data();
+ break;
+ case 3: /* fcomp */
+ compare_st_data();
+ pop();
+ break;
+ case 4: /* fsub */
+ reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 5: /* fsubr */
+ reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ case 6: /* fdiv */
+ reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 7: /* fdivr */
+ if (FPU_st0_tag == TW_Zero)
+ status_word = status1; /* Undo any denorm tag,
+ * zero-divide has
+ * priority. */
+ reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ }
+ } else {
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* The instruction is fcom or fcomp */
+ EXCEPTION(EX_StackUnder);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, Empty or not,
+ * we pop. */
+ } else
+ stack_underflow();
+ }
+ } else {
+ load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
+ }
+
+reg_mem_instr_done:
+
+ data_operand_offset = (unsigned long) FPU_data_address;
+ } else {
+ /* None of these instructions access user memory */
+ unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
+
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ switch (type_table[(int) instr_index]) {
+ case _NONE_: /* also _REGIc: _REGIn */
+ break;
+ case _REG0_:
+ if (!NOT_EMPTY_0) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIi:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIp:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ pop();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGI_:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _PUSH_: /* Only used by the fld st(i) instruction */
+ break;
+ case _null_:
+ Un_impl();
+ goto FPU_instruction_done;
+ default:
+ EXCEPTION(EX_INTERNAL | 0x111);
+ goto FPU_instruction_done;
+ }
+ (*st_instr_table[(int) instr_index]) ();
+ }
+
+FPU_instruction_done:
+
+ ip_offset = FPU_entry_eip;
+ bswapw(code);
+ *(1 + (unsigned short *) &cs_selector) = code & 0x7ff;
+
+#ifdef DEBUG
+ REENTRANT_CHECK(OFF);
+ emu_printall();
+ REENTRANT_CHECK(ON);
+#endif /* DEBUG */
+#ifdef LOOKAHEAD_LIMIT
+if (--lookahead_limit)
+#endif
+ if (FPU_lookahead) {
+ unsigned char next;
+
+ /* (This test should generate no machine code) */
+ while (1) {
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if (((next & 0xf8) == 0xd8) || (next == 0x9b)) { /* fwait */
+ goto do_another_FPU_instruction;
+ } else
+ if (next == 0x66) { /* size prefix */
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) (FPU_EIP + 1));
+ REENTRANT_CHECK(ON);
+ if ((next & 0xf8) == 0xd8) {
+ FPU_EIP++;
+ goto do_another_FPU_instruction;
+ }
+ }
+ break;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ return (0); /* --pink-- */
+}
diff --git a/sys/gnu/fpemul/fpu_etc.c b/sys/gnu/fpemul/fpu_etc.c
new file mode 100644
index 000000000000..9993d3bddfd4
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_etc.c
@@ -0,0 +1,175 @@
+/*
+ * fpu_etc.c
+ *
+ * Implement a few FPU instructions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_etc.c,v 1.3 1994/06/10 07:44:24 rich Exp $
+ *
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "reg_constant.h"
+
+
+static void
+fchs(void)
+{
+ if (NOT_EMPTY_0) {
+ FPU_st0_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+static void
+fabs(void)
+{
+ if (FPU_st0_tag ^ TW_Empty) {
+ FPU_st0_ptr->sign = SIGN_POS;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+
+static void
+ftst_(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Zero:
+ setcc(SW_C3);
+ break;
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ case TW_NaN:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Empty:
+ setcc(SW_C0 | SW_C2 | SW_C3);
+ EXCEPTION(EX_StackUnder);
+ break;
+ default:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_INTERNAL | 0x14);
+ break;
+ }
+}
+
+static void
+fxam(void)
+{
+ int c = 0;
+ switch (FPU_st0_tag) {
+ case TW_Empty:
+ c = SW_C3 | SW_C0;
+ break;
+ case TW_Zero:
+ c = SW_C3;
+ break;
+ case TW_Valid:
+ /* This will need to be changed if TW_Denormal is ever used. */
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ c = SW_C2 | SW_C3; /* Denormal */
+ else
+ c = SW_C3;
+ break;
+ case TW_NaN:
+ c = SW_C0;
+ break;
+ case TW_Infinity:
+ c = SW_C2 | SW_C0;
+ break;
+ }
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ c |= SW_C1;
+ setcc(c);
+}
+
+static FUNC fp_etc_table[] = {
+ fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl
+};
+
+void
+fp_etc()
+{
+ (fp_etc_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/fpemul/fpu_proto.h b/sys/gnu/fpemul/fpu_proto.h
new file mode 100644
index 000000000000..463f31b7d7be
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_proto.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * $Id: fpu_proto.h,v 1.2 1994/04/29 21:16:23 gclarkii Exp $
+ *
+ */
+
+
+/* errors.c */
+extern void Un_impl(void);
+extern void emu_printall(void);
+extern void exception(int n);
+extern void real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest);
+extern void arith_invalid(FPU_REG * dest);
+extern void divide_by_zero(int sign, FPU_REG * dest);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern void arith_overflow(FPU_REG * dest);
+extern void arith_underflow(FPU_REG * dest);
+extern void stack_overflow(void);
+extern void stack_underflow(void);
+extern void stack_underflow_i(int i);
+extern void stack_underflow_pop(int i);
+/* fpu_arith.c */
+extern void fadd__(void);
+extern void fmul__(void);
+extern void fsub__(void);
+extern void fsubr_(void);
+extern void fdiv__(void);
+extern void fdivr_(void);
+extern void fadd_i(void);
+extern void fmul_i(void);
+extern void fsubri(void);
+extern void fsub_i(void);
+extern void fdivri(void);
+extern void fdiv_i(void);
+extern void faddp_(void);
+extern void fmulp_(void);
+extern void fsubrp(void);
+extern void fsubp_(void);
+extern void fdivrp(void);
+extern void fdivp_(void);
+/* fpu_aux.c */
+extern void fclex(void);
+extern void finit(void);
+extern void finit_(void);
+extern void fstsw_(void);
+extern void fp_nop(void);
+extern void fld_i_(void);
+extern void fxch_i(void);
+extern void ffree_(void);
+extern void ffreep(void);
+extern void fst_i_(void);
+extern void fstp_i(void);
+/* fpu_entry.c */
+extern int math_emulate(struct trapframe * info);
+/* fpu_etc.c */
+extern void fp_etc(void);
+/* fpu_trig.c */
+extern void convert_l2reg(long *arg, FPU_REG * dest);
+extern void trig_a(void);
+extern void trig_b(void);
+/* get_address.c */
+extern void get_address(unsigned char FPU_modrm);
+/* load_store.c */
+extern void load_store_instr(char type);
+/* poly_2xm1.c */
+extern int poly_2xm1(FPU_REG * arg, FPU_REG * result);
+/* poly_atan.c */
+extern void poly_atan(FPU_REG * arg);
+extern void poly_add_1(FPU_REG * src);
+/* poly_l2.c */
+extern void poly_l2(FPU_REG * arg, FPU_REG * result);
+extern int poly_l2p1(FPU_REG * arg, FPU_REG * result);
+/* poly_sin.c */
+extern void poly_sine(FPU_REG * arg, FPU_REG * result);
+/* poly_tan.c */
+extern void poly_tan(FPU_REG * arg, FPU_REG * y_reg);
+/* reg_add_sub.c */
+extern void reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+extern void reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+/* reg_compare.c */
+extern int compare(FPU_REG * b);
+extern int compare_st_data(void);
+extern void fcom_st(void);
+extern void fcompst(void);
+extern void fcompp(void);
+extern void fucom_(void);
+extern void fucomp(void);
+extern void fucompp(void);
+/* reg_constant.c */
+extern void fconst(void);
+/* reg_ld_str.c */
+extern void reg_load_extended(void);
+extern void reg_load_double(void);
+extern void reg_load_single(void);
+extern void reg_load_int64(void);
+extern void reg_load_int32(void);
+extern void reg_load_int16(void);
+extern void reg_load_bcd(void);
+extern int reg_store_extended(void);
+extern int reg_store_double(void);
+extern int reg_store_single(void);
+extern int reg_store_int64(void);
+extern int reg_store_int32(void);
+extern int reg_store_int16(void);
+extern int reg_store_bcd(void);
+extern int round_to_int(FPU_REG * r);
+extern char *fldenv(void);
+extern void frstor(void);
+extern unsigned short tag_word(void);
+extern char *fstenv(void);
+extern void fsave(void);
+/* reg_mul.c */
+extern void reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w);
diff --git a/sys/gnu/fpemul/fpu_system.h b/sys/gnu/fpemul/fpu_system.h
new file mode 100644
index 000000000000..ac5263615b5f
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_system.h
@@ -0,0 +1,97 @@
+/*
+ * fpu_system.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_system.h,v 1.3 1994/06/10 07:44:25 rich Exp $
+ *
+ */
+
+
+#ifndef _FPU_SYSTEM_H
+#define _FPU_SYSTEM_H
+
+/* system dependent definitions */
+
+/*
+#include <linux/sched.h>
+#include <linux/kernel.h>
+*/
+
+#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
+#define FPU_info (I387.soft.frame)
+
+#define FPU_CS (*(unsigned short *) &(FPU_info->tf_cs))
+#define FPU_DS (*(unsigned short *) &(FPU_info->tf_ds))
+#define FPU_EAX (FPU_info->tf_eax)
+#define FPU_EFLAGS (FPU_info->tf_eflags)
+#define FPU_EIP (FPU_info->tf_eip)
+/*#define FPU_ORIG_EIP (FPU_info->___orig_eip) */
+/*#define FPU_ORIG_EIP (FPU_info->tf_isp)*/
+#define FPU_ORIG_EIP (I387.soft.orig_eip)
+
+#define FPU_lookahead (I387.soft.lookahead)
+#define FPU_entry_eip (I387.soft.entry_eip)
+
+#define status_word (I387.soft.swd)
+#define control_word (I387.soft.cwd)
+#define regs (I387.soft.regs)
+#define top (I387.soft.top)
+
+#define ip_offset (I387.soft.fip)
+#define cs_selector (I387.soft.fcs)
+#define data_operand_offset (I387.soft.foo)
+#define operand_selector (I387.soft.fos)
+
+#endif
diff --git a/sys/gnu/fpemul/fpu_trig.c b/sys/gnu/fpemul/fpu_trig.c
new file mode 100644
index 000000000000..af2bd0553ce9
--- /dev/null
+++ b/sys/gnu/fpemul/fpu_trig.c
@@ -0,0 +1,1367 @@
+/*
+ * fpu_trig.c
+ *
+ * Implementation of the FPU "transcendental" functions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: fpu_trig.c,v 1.4 1994/06/10 07:44:27 rich Exp $
+ *
+ */
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "reg_constant.h"
+#include "control_w.h"
+
+static int
+trig_arg(FPU_REG * X)
+{
+ FPU_REG tmp, quot;
+ int rv;
+ long long q;
+ int old_cw = control_word;
+
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+
+ reg_move(X, &quot);
+ reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);
+
+ reg_move(&quot, &tmp);
+ round_to_int(&tmp);
+ if (tmp.sigh & 0x80000000)
+ return -1; /* |Arg| is >= 2^63 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_sub(&quot, &tmp, X, FULL_PRECISION);
+ rv = q & 7;
+
+ control_word = old_cw;
+ return rv;;
+}
+
+
+/* Convert a long to register */
+void
+convert_l2reg(long *arg, FPU_REG * dest)
+{
+ long num = *arg;
+
+ if (num == 0) {
+ reg_move(&CONST_Z, dest);
+ return;
+ }
+ if (num > 0)
+ dest->sign = SIGN_POS;
+ else {
+ num = -num;
+ dest->sign = SIGN_NEG;
+ }
+
+ dest->sigh = num;
+ dest->sigl = 0;
+ dest->exp = EXP_BIAS + 31;
+ dest->tag = TW_Valid;
+ normalize(dest);
+}
+
+
+static void
+single_arg_error(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_NaN:
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ break; /* return with a NaN in st(0) */
+ case TW_Empty:
+ stack_underflow(); /* Puts a QNaN in st(0) */
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x0112);
+#endif /* PARANOID */
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static void
+f2xm1(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+ {
+ FPU_REG rv, tmp;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ /* poly_2xm1(x) requires 0 < x < 1. */
+ if (poly_2xm1(FPU_st0_ptr, &rv))
+ return; /* error */
+ reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+ } else {
+/* **** Should change poly_2xm1() to at least handle numbers near 0 */
+ /* poly_2xm1(x) doesn't handle negative
+ * numbers. */
+ /* So we compute (poly_2xm1(x+1)-1)/2, for -1
+ * < x < 0 */
+ reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
+ poly_2xm1(&tmp, &rv);
+ reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
+ FPU_st0_ptr->exp--;
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ }
+ return;
+ }
+ case TW_Zero:
+ return;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ /* -infinity gives -1 (p16-10) */
+ reg_move(&CONST_1, FPU_st0_ptr);
+ FPU_st0_ptr->sign = SIGN_NEG;
+ }
+ return;
+ default:
+ single_arg_error();
+ }
+}
+
+static void
+fptan(void)
+{
+ FPU_REG *st_new_ptr;
+ int q;
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ FPU_st0_ptr->sign = SIGN_POS;
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_tan(FPU_st0_ptr, FPU_st0_ptr);
+
+ FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ break;
+ case TW_Infinity:
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ case TW_Zero:
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ break;
+ default:
+ single_arg_error();
+ break;
+ }
+}
+
+
+static void
+fxtract(void)
+{
+ FPU_REG *st_new_ptr;
+ register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ long e;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ FPU_st0_ptr->exp = EXP_BIAS;
+ e = st1_ptr->exp - EXP_BIAS;
+ convert_l2reg(&e, st1_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ char sign = FPU_st0_ptr->sign;
+ divide_by_zero(SIGN_NEG, FPU_st0_ptr);
+ push();
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ char sign = FPU_st0_ptr->sign;
+ FPU_st0_ptr->sign = SIGN_POS;
+ push();
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Is this the correct
+ * behaviour? */
+ if (control_word & EX_Invalid) {
+ stack_underflow();
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x119);
+#endif /* PARANOID */
+}
+
+
+static void
+fdecstp(void)
+{
+ top--; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+static void
+fincstp(void)
+{
+ top++; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+
+static void
+fsqrt_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ int expon;
+
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ arith_invalid(FPU_st0_ptr); /* sqrt(negative) is
+ * invalid */
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ expon = FPU_st0_ptr->exp - EXP_BIAS;
+ FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0
+ * .. 4.0) */
+
+ wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */
+
+ FPU_st0_ptr->exp += expon >> 1;
+ FPU_st0_ptr->sign = SIGN_POS;
+ } else
+ if (FPU_st0_tag == TW_Zero)
+ return;
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is
+ * invalid */
+ return;
+ } else {
+ single_arg_error();
+ return;
+ }
+
+}
+
+
+static void
+frndint_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ if (FPU_st0_ptr->exp > EXP_BIAS + 63)
+ return;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ round_to_int(FPU_st0_ptr); /* Fortunately, this can't
+ * overflow to 2^64 */
+ FPU_st0_ptr->exp = EXP_BIAS + 63;
+ normalize(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity))
+ return;
+ else
+ single_arg_error();
+}
+
+
+static void
+fsin(void)
+{
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int q;
+ FPU_st0_ptr->sign = SIGN_POS;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ FPU_REG rv;
+
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_sine(FPU_st0_ptr, &rv);
+
+ setcc(0);
+ if (q & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ rv.sign ^= arg_sign;
+ reg_move(&rv, FPU_st0_ptr);
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ setcc(0);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ } else
+ single_arg_error();
+}
+
+
+static int
+f_cos(FPU_REG * arg)
+{
+ char arg_sign = arg->sign;
+
+ if (arg->tag == TW_Valid) {
+ int q;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return 1;
+#endif /* DENORM_OPERAND */
+
+ arg->sign = SIGN_POS;
+ if ((q = trig_arg(arg)) != -1) {
+ FPU_REG rv;
+
+ if (!(q & 1))
+ reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
+
+ poly_sine(arg, &rv);
+
+ setcc(0);
+ if ((q + 1) & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ reg_move(&rv, arg);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return 0;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ }
+ } else
+ if (arg->tag == TW_Zero) {
+ reg_move(&CONST_1, arg);
+ setcc(0);
+ return 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ } else {
+ single_arg_error(); /* requires arg ==
+ * &st(0) */
+ return 1;
+ }
+}
+
+
+static void
+fcos(void)
+{
+ f_cos(FPU_st0_ptr);
+}
+
+
+static void
+fsincos(void)
+{
+ FPU_REG *st_new_ptr;
+ FPU_REG arg;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &arg);
+ if (!f_cos(&arg)) {
+ fsin();
+ push();
+ reg_move(&arg, FPU_st0_ptr);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* The following all require two arguments: st(0) and st(1) */
+
+/* remainder of st(0) / st(1) */
+/* Assumes that st(0) and st(1) are both TW_Valid */
+static void
+fprem_kernel(int round)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ FPU_REG tmp;
+ int old_cw = control_word;
+ int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ control_word &= ~CW_RC;
+ control_word |= round;
+
+ if (expdif < 64) {
+ /* This should be the most common case */
+ long long q;
+ int c = 0;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ if (q & 4)
+ c |= SW_C3;
+ if (q & 2)
+ c |= SW_C1;
+ if (q & 1)
+ c |= SW_C0;
+
+ setcc(c);
+ } else {
+ /* There is a large exponent difference ( >= 64 ) */
+ int N_exp;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+ /* N is 'a number between 32 and 63' (p26-113) */
+ N_exp = (tmp.exp & 31) + 32;
+ tmp.exp = EXP_BIAS + N_exp;
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ normalize(&tmp);
+
+ tmp.exp = EXP_BIAS + expdif - N_exp;
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ setcc(SW_C2);
+ }
+ control_word = old_cw;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ setcc(0);
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr);
+ return;
+ }
+ /* fprem(?,0) always invalid */
+ else
+ if (st1_tag == TW_Infinity) {
+ setcc(0);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is
+ * invalid */
+ return;
+ } else
+ if (st1_tag != TW_NaN) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_tag == TW_Infinity) {
+ /* fprem(Valid,
+ * Infinity)
+ * is o.k. */
+ setcc(0);
+ return;
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag != TW_NaN) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is
+ * invalid */
+ return;
+ }
+ }
+ /* One of the registers must contain a NaN is we got here. */
+
+#ifdef PARANOID
+ if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN))
+ EXCEPTION(EX_INTERNAL | 0x118);
+#endif /* PARANOID */
+
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+
+}
+
+
+/* ST(1) <- ST(1) * log ST; pop ST */
+static void
+fyl2x(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic, so we need
+ * to save these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ poly_l2(FPU_st0_ptr, FPU_st0_ptr);
+
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ } else {
+ /* negative */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* st(0) cannot be
+ * negative */
+ return;
+ }
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) {
+ /* one of the args is zero, the other
+ * valid, or both zero */
+ if (FPU_st0_tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ if (FPU_st0_ptr->tag == TW_Zero)
+ arith_invalid(FPU_st0_ptr); /* Both args zero is
+ * invalid */
+#ifdef PECULIAR_486
+ /* This case is not
+ * specifically covered in the
+ * manual, but divide-by-zero
+ * would seem to be the best
+ * response. However, a real
+ * 80486 does it this way... */
+ else
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ return;
+ }
+#endif /* PECULIAR_486 */
+ else
+ divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr);
+ return;
+ } else {
+ /* st(1) contains zero, st(0)
+ * valid <> 0 */
+ /* Zero is the valid answer */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ return;
+ }
+ if (FPU_st0_ptr->exp < EXP_BIAS)
+ sign ^= SIGN_NEG ^ SIGN_POS;
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* One or both arg must be an infinity */
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(-infinity) or
+ * 0*log(infinity) */
+ return;
+ } else {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* st(1) must be infinity here */
+ else
+ if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ if ((FPU_st0_ptr->exp == EXP_BIAS) &&
+ (FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0)) {
+ /* st(0
+ * )
+ * hold
+ * s
+ * 1.0 */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* infinity*log(1) */
+ return;
+ }
+ /* st(0) is
+ * positive
+ * and > 1.0 */
+ pop();
+ } else {
+ /* st(0) is
+ * positive
+ * and < 1.0 */
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= SIGN_NEG;
+ pop();
+ }
+ return;
+ } else {
+ /* st(0) must be zero
+ * or negative */
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS;
+ /* This should
+ * be invalid,
+ * but a real
+ * 80486 is
+ * happy with
+ * it. */
+#ifndef PECULIAR_486
+ divide_by_zero(st1_ptr->sign, FPU_st0_ptr);
+#endif /* PECULIAR_486 */
+ } else {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ }
+ return;
+ }
+}
+
+
+static void
+fpatan(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+ FPU_REG sum;
+ int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1);
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
+ if (compare(st1_ptr) == COMP_A_lt_B) {
+ quadrant |= 4;
+ reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
+ } else
+ reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
+
+ poly_atan(&sum);
+
+ if (quadrant & 4) {
+ reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 2) {
+ reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 1)
+ sum.sign ^= SIGN_POS ^ SIGN_NEG;
+
+ /* All of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ reg_move(&sum, st1_ptr);
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
+ char sign = st1_ptr->sign;
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_PI4, st1_ptr);
+ } else
+ reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
+ } else {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ }
+ } else {
+ /* st(1) is infinity, st(0)
+ * not infinity */
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ }
+ st1_ptr->sign = sign;
+ } else
+ if (st1_tag == TW_Zero) {
+ /* st(0) must be valid or zero */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ st1_ptr->sign = sign;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* st(1) must be
+ * TW_Valid here */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x220);
+#endif /* PARANOID */
+
+ pop();
+ set_precision_flag_up();/* We do not really know if up or down */
+}
+
+
+static void
+fprem(void)
+{
+ fprem_kernel(RC_CHOP);
+}
+
+
+static void
+fprem1(void)
+{
+ fprem_kernel(RC_RND);
+}
+
+
+static void
+fyl2xp1(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) {
+ arith_invalid(st1_ptr); /* poly_l2p1() returned
+ * invalid */
+ pop();
+ return;
+ }
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag <= TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
+ (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= FPU_st0_ptr->sign;
+ reg_move(FPU_st0_ptr, st1_ptr);
+ } else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(st1_ptr); /* Infinity*log(1) */
+ pop();
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x116);
+ return;
+ }
+#endif /* PARANOID */
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ /* st(0) holds
+ * <= -1.0 */
+ arith_invalid(st1_ptr); /* infinity*log(1) */
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if ((FPU_st0_ptr->exp >= EXP_BIAS) &&
+ !((FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0))) {
+ /* st(0) holds
+ * < -1.0 */
+ arith_invalid(st1_ptr);
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_ptr->sign == SIGN_NEG) ||
+ (st1_tag == TW_Zero)) {
+ arith_invalid(st1_ptr); /* log(infinity) */
+ pop();
+ return;
+ }
+ /* st(1) must be valid
+ * here. */
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* The Manual says
+ * that log(Infinity)
+ * is invalid, but a
+ * real 80486 sensibly
+ * says that it is
+ * o.k. */
+ {
+ char sign = st1_ptr->sign;
+ reg_move(&CONST_INF, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x117);
+ }
+#endif /* PARANOID */
+}
+
+
+static void
+emu_fscale(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+ int old_cw = control_word;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ long scale;
+ FPU_REG tmp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_ptr->exp > EXP_BIAS + 30) {
+ /* 2^31 is far too large, would require 2^(2^30) or
+ * 2^(-2^30) */
+ char sign;
+
+ if (st1_ptr->sign == SIGN_POS) {
+ EXCEPTION(EX_Overflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ } else {
+ EXCEPTION(EX_Underflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ }
+ return;
+ }
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+ reg_move(st1_ptr, &tmp);
+ round_to_int(&tmp); /* This can never overflow here */
+ control_word = old_cw;
+ scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
+ scale += FPU_st0_ptr->exp;
+ FPU_st0_ptr->exp = scale;
+
+ /* Use round_reg() to properly detect under/overflow etc */
+ round_reg(FPU_st0_ptr, 0, control_word);
+
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (sign == SIGN_POS) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ } else
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ return;
+ } else
+ if (st1_tag == TW_Infinity) {
+ if (st1_ptr->sign == SIGN_NEG)
+ return;
+ else {
+ arith_invalid(FPU_st0_ptr); /* Zero scaled by
+ * +Infinity */
+ return;
+ }
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
+ || (st1_tag == TW_Zero))
+ return;
+ else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(FPU_st0_ptr); /* Infinity scaled by
+ * -Infinity */
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (st1_tag != TW_Empty) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ }
+#ifdef PARANOID
+ if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) {
+ EXCEPTION(EX_INTERNAL | 0x115);
+ return;
+ }
+#endif
+
+ /* At least one of st(0), st(1) must be empty */
+ stack_underflow();
+
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static FUNC trig_table_a[] = {
+ f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
+};
+
+void
+trig_a(void)
+{
+ (trig_table_a[FPU_rm]) ();
+}
+
+
+static FUNC trig_table_b[] =
+{
+ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos
+};
+
+void
+trig_b(void)
+{
+ (trig_table_b[FPU_rm]) ();
+}
diff --git a/sys/gnu/fpemul/get_address.c b/sys/gnu/fpemul/get_address.c
new file mode 100644
index 000000000000..957ea4e2eeba
--- /dev/null
+++ b/sys/gnu/fpemul/get_address.c
@@ -0,0 +1,203 @@
+/*
+ * get_address.c
+ *
+ * Get the effective address from an FPU instruction.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: get_address.c,v 1.3 1994/06/10 07:44:29 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/reg.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+
+static int reg_offset[] = {
+tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI};
+#define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)]))
+
+void *FPU_data_address;
+
+
+/* Decode the SIB byte. This function assumes mod != 0 */
+static void *
+sib(int mod)
+{
+ unsigned char ss, index, base;
+ long offset;
+
+ REENTRANT_CHECK(OFF);
+ base = fubyte((char *) FPU_EIP); /* The SIB byte */
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+
+ if ((mod == 0) && (base == 5))
+ offset = 0; /* No base register */
+ else
+ offset = REG_(base);
+
+ if (index == 4) {
+ /* No index register */
+ /* A non-zero ss is illegal */
+ if (ss)
+ EXCEPTION(EX_Invalid);
+ } else {
+ offset += (REG_(index)) << ss;
+ }
+
+ if (mod == 1) {
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset += (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ } else
+ if (mod == 2 || base == 5) { /* The second condition also
+ * has mod==0 */
+ /* 32 bit displacment */
+ REENTRANT_CHECK(OFF);
+ offset += (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ }
+ return (void *) offset;
+}
+
+
+/*
+ MOD R/M byte: MOD == 3 has a special use for the FPU
+ SIB byte used iff R/M = 100b
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ MOD OPCODE(2) R/M
+
+
+ SIB byte
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ SS INDEX BASE
+
+*/
+
+void
+get_address(unsigned char FPU_modrm)
+{
+ unsigned char mod;
+ long *cpu_reg_ptr;
+ int offset = 0; /* Initialized just to stop compiler warnings. */
+
+ mod = (FPU_modrm >> 6) & 3;
+
+ if (FPU_rm == 4 && mod != 3) {
+ FPU_data_address = sib(mod);
+ return;
+ }
+ cpu_reg_ptr = (long *) &REG_(FPU_rm);
+ switch (mod) {
+ case 0:
+ if (FPU_rm == 5) {
+ /* Special case: disp32 */
+ REENTRANT_CHECK(OFF);
+ offset = fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ FPU_data_address = (void *) offset;
+ return;
+ } else {
+ FPU_data_address = (void *) *cpu_reg_ptr; /* Just return the
+ * contents of the cpu
+ * register */
+ return;
+ }
+ case 1:
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ break;
+ case 2:
+ /* 32 bit displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ break;
+ case 3:
+ /* Not legal for the FPU */
+ EXCEPTION(EX_Invalid);
+ }
+
+ FPU_data_address = offset + (char *) *cpu_reg_ptr;
+}
diff --git a/sys/gnu/fpemul/load_store.c b/sys/gnu/fpemul/load_store.c
new file mode 100644
index 000000000000..a86a2fd3ec82
--- /dev/null
+++ b/sys/gnu/fpemul/load_store.c
@@ -0,0 +1,269 @@
+/*
+ * load_store.c
+ *
+ * This file contains most of the code to interpret the FPU instructions
+ * which load and store from user memory.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: load_store.c,v 1.3 1994/06/10 07:44:30 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+
+
+#define _NONE_ 0 /* FPU_st0_ptr etc not needed */
+#define _REG0_ 1 /* Will be storing st(0) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+
+#define pop_0() { pop_ptr->tag = TW_Empty; top++; }
+
+
+static unsigned char type_table[32] = {
+ _PUSH_, _PUSH_, _PUSH_, _PUSH_,
+ _null_, _null_, _null_, _null_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _NONE_, _null_, _NONE_, _PUSH_,
+ _NONE_, _PUSH_, _null_, _PUSH_,
+ _NONE_, _null_, _NONE_, _REG0_,
+ _NONE_, _REG0_, _NONE_, _REG0_
+};
+
+void
+load_store_instr(char type)
+{
+ FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which
+ * won't change. */
+
+ pop_ptr = NULL; /* Initialized just to stop compiler warnings. */
+
+
+ switch (type_table[(int) (unsigned) type]) {
+ case _NONE_:
+ break;
+ case _REG0_:
+ pop_ptr = &st(0); /* Some of these instructions pop
+ * after storing */
+
+ FPU_st0_ptr = pop_ptr; /* Set the global variables. */
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ break;
+ case _PUSH_:
+ {
+ pop_ptr = &st(-1);
+ if (pop_ptr->tag != TW_Empty) {
+ stack_overflow();
+ return;
+ }
+ top--;
+ }
+ break;
+ case _null_:
+ return Un_impl();
+#ifdef PARANOID
+ default:
+ return EXCEPTION(EX_INTERNAL);
+#endif /* PARANOID */
+ }
+
+ switch (type) {
+ case 000: /* fld m32real */
+ reg_load_single();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 001: /* fild m32int */
+ reg_load_int32();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 002: /* fld m64real */
+ reg_load_double();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 003: /* fild m16int */
+ reg_load_int16();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 010: /* fst m32real */
+ reg_store_single();
+ break;
+ case 011: /* fist m32int */
+ reg_store_int32();
+ break;
+ case 012: /* fst m64real */
+ reg_store_double();
+ break;
+ case 013: /* fist m16int */
+ reg_store_int16();
+ break;
+ case 014: /* fstp m32real */
+ if (reg_store_single())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 015: /* fistp m32int */
+ if (reg_store_int32())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 016: /* fstp m64real */
+ if (reg_store_double())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 017: /* fistp m16int */
+ if (reg_store_int16())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 020: /* fldenv m14/28byte */
+ fldenv();
+ break;
+ case 022: /* frstor m94/108byte */
+ frstor();
+ break;
+ case 023: /* fbld m80dec */
+ reg_load_bcd();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 024: /* fldcw */
+ REENTRANT_CHECK(OFF);
+ control_word = fuword((unsigned short *) FPU_data_address);
+ REENTRANT_CHECK(ON);
+#ifdef NO_UNDERFLOW_TRAP
+ if (!(control_word & EX_Underflow)) {
+ control_word |= EX_Underflow;
+ }
+#endif
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 025: /* fld m80real */
+ reg_load_extended();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 027: /* fild m64int */
+ reg_load_int64();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 030: /* fstenv m14/28byte */
+ fstenv();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 032: /* fsave */
+ fsave();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 033: /* fbstp m80dec */
+ if (reg_store_bcd())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 034: /* fstcw m16int */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ suword( (short *) FPU_data_address,control_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 035: /* fstp m80real */
+ if (reg_store_extended())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 036: /* fstsw m2byte */
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ suword( (short *) FPU_data_address,status_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 037: /* fistp m64int */
+ if (reg_store_int64())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ }
+}
diff --git a/sys/gnu/fpemul/math_emu.h b/sys/gnu/fpemul/math_emu.h
new file mode 100644
index 000000000000..031d391595b5
--- /dev/null
+++ b/sys/gnu/fpemul/math_emu.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * $Id: math_emu.h,v 1.2 1994/04/29 21:23:24 gclarkii Exp $
+ *
+ */
+
+#ifndef _MATH_EMU_H
+#define _MATH_EMU_H
+
+struct fpu_reg {
+ char sign;
+ char tag;
+ long exp;
+ u_long sigl;
+ u_long sigh;
+};
+
+union i387_union {
+ struct i387_hard_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80
+ * bytes */
+ } hard;
+ struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long top;
+ struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128
+ * bytes */
+ unsigned char lookahead;
+ struct trapframe *frame;
+ unsigned long entry_eip;
+ int orig_eip;
+ } soft;
+};
+#endif
diff --git a/sys/gnu/fpemul/poly_2xm1.c b/sys/gnu/fpemul/poly_2xm1.c
new file mode 100644
index 000000000000..d4da1bb81527
--- /dev/null
+++ b/sys/gnu/fpemul/poly_2xm1.c
@@ -0,0 +1,141 @@
+/*
+ * poly_2xm1.c
+ *
+ * Function to compute 2^x-1 by a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_2xm1.c,v 1.3 1994/06/10 07:44:32 rich Exp $
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+
+
+
+#define HIPOWER 13
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x79b5, 0xd1cf, 0x17f7, 0xb172},
+ {0x1b56, 0x058b, 0x7bff, 0x3d7f},
+ {0x8bb0, 0x8250, 0x846b, 0x0e35},
+ {0xbc65, 0xf747, 0x556d, 0x0276},
+ {0x17cb, 0x9e39, 0x61ff, 0x0057},
+ {0xe018, 0x9776, 0x1848, 0x000a},
+ {0x66f2, 0xff30, 0xffe5, 0x0000},
+ {0x682f, 0xffb6, 0x162b, 0x0000},
+ {0xb7ca, 0x2956, 0x01b5, 0x0000},
+ {0xcd3e, 0x4817, 0x001e, 0x0000},
+ {0xb7e2, 0xecbe, 0x0001, 0x0000},
+ {0x0ed5, 0x1a27, 0x0000, 0x0000},
+ {0x101d, 0x0222, 0x0000, 0x0000},
+};
+
+
+/*--- poly_2xm1() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+int
+poly_2xm1(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ long long Xll;
+ FPU_REG accum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return 0;
+ }
+ if (exponent >= 0) { /* Can't hack a number >= 1.0 */
+ arith_invalid(result); /* Number too large */
+ return 1;
+ }
+ if (arg->sign != SIGN_POS) { /* Can't hack a number < 0.0 */
+ arith_invalid(result); /* Number negative */
+ return 1;
+ }
+ if (exponent < -64) {
+ reg_move(&CONST_LN2, result);
+ return 0;
+ }
+ *(unsigned *) &Xll = arg->sigl;
+ *(((unsigned *) &Xll) + 1) = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&Xll, -1 - exponent) >= (unsigned)0x80000000)
+ Xll++; /* round up */
+ }
+ *(short *) &(accum.sign) = 0; /* will be a valid positive nr with
+ * expon = 0 */
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xll, lterms, HIPOWER - 1);
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+
+ normalize(result);
+
+ return 0;
+
+}
diff --git a/sys/gnu/fpemul/poly_atan.c b/sys/gnu/fpemul/poly_atan.c
new file mode 100644
index 000000000000..f597ed9af43e
--- /dev/null
+++ b/sys/gnu/fpemul/poly_atan.c
@@ -0,0 +1,252 @@
+/*
+ * p_atan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_atan.c,v 1.4 1994/06/10 07:44:34 rich Exp $
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWERon 6 /* odd poly, negative terms */
+static unsigned oddnegterms[HIPOWERon][2] =
+{
+ {0x00000000, 0x00000000}, /* for + 1.0 */
+ {0x763b6f3d, 0x1adc4428},
+ {0x20f0630b, 0x0502909d},
+ {0x4e825578, 0x0198ce38},
+ {0x22b7cb87, 0x008da6e3},
+ {0x9b30ca03, 0x00239c79}
+};
+#define HIPOWERop 6 /* odd poly, positive terms */
+static unsigned oddplterms[HIPOWERop][2] =
+{
+ {0xa6f67cb8, 0x94d910bd},
+ {0xa02ffab4, 0x0a43cb45},
+ {0x04265e6b, 0x02bf5655},
+ {0x0a728914, 0x00f280f7},
+ {0x6d640e01, 0x004d6556},
+ {0xf1dd2dbf, 0x000a530a}
+};
+
+
+static unsigned denomterm[2] =
+{0xfc4bd208, 0xea2e6612};
+
+
+
+/*--- poly_atan() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_atan(FPU_REG * arg)
+{
+ char recursions = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(arg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, arg);
+ return;
+ }
+ if (exponent >= -2) {
+ /* argument is in the range [0.25 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ reg_move(&CONST_PI4, arg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+#endif /* PARANOID */
+ }
+ /* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
+ /* convert the argument by an identity for atan */
+ if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) {
+ FPU_REG numerator, denom;
+
+ recursions++;
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ *(long long *) &(numerator.sigl) = -arg_signif;
+ numerator.exp = EXP_BIAS - 1;
+ normalize(&numerator); /* 1 - arg */
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ *(long long *) &(denom.sigl) = arg_signif;
+ denom.sigh |= 0x80000000; /* 1 + arg */
+
+ arg->exp = numerator.exp;
+ reg_u_div(&numerator, &denom, arg, FULL_PRECISION);
+
+ exponent = arg->exp - EXP_BIAS;
+ }
+ }
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+
+#ifdef PARANOID
+ /* This must always be true */
+ if (exponent >= -1) {
+ EXCEPTION(EX_INTERNAL | 0x120); /* There must be a logic error */
+ }
+#endif /* PARANOID */
+
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+
+ /* Now have arg_signif with binary point at the left .1xxxxxxxx */
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddplterms, HIPOWERop - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl),
+ (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ reg_move(&pos_poly, &odd_poly);
+ poly_add_1(&odd_poly);
+
+ /* The complete odd polynomial */
+ reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(even_poly.sign) = 0;
+
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&denomterm), (long long *) (&even_poly.sigl));
+
+ poly_add_1(&even_poly);
+
+ reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);
+
+ if (recursions)
+ reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
+}
+
+
+/* The argument to this function must be polynomial() compatible,
+ i.e. have an exponent (not checked) of EXP_BIAS-1 but need not
+ be normalized.
+ This function adds 1.0 to the (assumed positive) argument. */
+void
+poly_add_1(FPU_REG * src)
+{
+/* Rounding in a consistent direction produces better results
+ for the use of this function in poly_atan. Simple truncation
+ is used here instead of round-to-nearest. */
+
+#ifdef OBSOLETE
+ char round = (src->sigl & 3) == 3;
+#endif /* OBSOLETE */
+
+ shrx(&src->sigl, 1);
+
+#ifdef OBSOLETE
+ if (round)
+ (*(long long *) &src->sigl)++; /* Round to even */
+#endif /* OBSOLETE */
+
+ src->sigh |= 0x80000000;
+
+ src->exp = EXP_BIAS;
+
+}
diff --git a/sys/gnu/fpemul/poly_div.s b/sys/gnu/fpemul/poly_div.s
new file mode 100644
index 000000000000..dce95ed82aae
--- /dev/null
+++ b/sys/gnu/fpemul/poly_div.s
@@ -0,0 +1,144 @@
+ .file "poly_div.S"
+/*
+ * poly_div.S
+ *
+ * A set of functions to divide 64 bit integers by fixed numbers.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_div.s,v 1.3 1994/06/10 07:44:36 rich Exp $
+ *
+ */
+
+#include "fpu_asm.h"
+
+.text
+
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div2
+_poly_div2:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ shrl $1,4(%ecx)
+ rcrl $1,(%ecx)
+
+ testw $1,%ax
+ je poly_div2_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div2_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div4
+_poly_div4:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $30,%edx
+
+ shrl $2,4(%ecx)
+ shrl $2,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $2,%ax
+ je poly_div4_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div4_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div16
+_poly_div16:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $28,%edx
+
+ shrl $4,4(%ecx)
+ shrl $4,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $8,%ax
+ je poly_div16_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div16_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
diff --git a/sys/gnu/fpemul/poly_l2.c b/sys/gnu/fpemul/poly_l2.c
new file mode 100644
index 000000000000..7c44103fd049
--- /dev/null
+++ b/sys/gnu/fpemul/poly_l2.c
@@ -0,0 +1,318 @@
+/*
+ * poly_l2.c
+ *
+ * Compute the base 2 log of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_l2.c,v 1.5 1994/06/10 07:44:38 rich Exp $
+ *
+ */
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+
+#define HIPOWER 9
+static unsigned short lterms[HIPOWER][4] =
+{
+ /* Ideal computation with these coeffs gives about 64.6 bit rel
+ * accuracy. */
+ {0xe177, 0xb82f, 0x7652, 0x7154},
+ {0xee0f, 0xe80f, 0x2770, 0x7b1c},
+ {0x0fc0, 0xbe87, 0xb143, 0x49dd},
+ {0x78b9, 0xdadd, 0xec54, 0x34c2},
+ {0x003a, 0x5de9, 0x628b, 0x2909},
+ {0x5588, 0xed16, 0x4abf, 0x2193},
+ {0xb461, 0x85f7, 0x347a, 0x1c6a},
+ {0x0975, 0x87b3, 0xd5bf, 0x1876},
+ {0xe85c, 0xcec9, 0x84e7, 0x187d}
+};
+
+
+
+
+/*--- poly_l2() -------------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ +---------------------------------------------------------------------------*/
+void
+poly_l2(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ char zero; /* flag for an Xx == 0 */
+ unsigned short bits, shift;
+ long long Xsq;
+ FPU_REG accum, denom, num, Xx;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+
+ if (arg->sigh > (unsigned) 0xb504f334) {
+ /* This is good enough for the computation of the polynomial
+ * sum, but actually results in a loss of precision for the
+ * computation of Xx. This will matter only if exponent
+ * becomes zero. */
+ exponent++;
+ accum.sign = 1; /* sign to negative */
+ num.exp = EXP_BIAS; /* needed to prevent errors in div
+ * routine */
+ reg_u_div(&CONST_1, arg, &num, FULL_PRECISION);
+ } else {
+ accum.sign = 0; /* set the sign to positive */
+ num.sigl = arg->sigl; /* copy the mantissa */
+ num.sigh = arg->sigh;
+ }
+
+
+ /* shift num left, lose the ms bit */
+ num.sigh <<= 1;
+ if (num.sigl & 0x80000000)
+ num.sigh |= 1;
+ num.sigl <<= 1;
+
+ denom.sigl = num.sigl;
+ denom.sigh = num.sigh;
+ poly_div4((long long *) &(denom.sigl));
+ denom.sigh += 0x80000000; /* set the msb */
+ Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */
+ reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
+
+ zero = !(Xx.sigh | Xx.sigl);
+
+ mul64((long long *) &Xx.sigl, (long long *) &Xx.sigl, &Xsq);
+ poly_div16(&Xsq);
+
+ accum.exp = -1; /* exponent of accum */
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ if (!exponent) {
+ /* If the exponent is zero, then we would lose precision by
+ * sticking to fixed point computation here */
+ /* We need to re-compute Xx because of loss of precision. */
+ FPU_REG lXx;
+ char sign;
+
+ sign = accum.sign;
+ accum.sign = 0;
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS + accum.exp;
+ normalize(&accum);
+
+ if (zero) {
+ reg_move(&CONST_Z, result);
+ } else {
+ /* we need to re-compute lXx to better accuracy */
+ num.tag = TW_Valid; /* set the tags to Vaild */
+ num.sign = 0; /* set the sign to positive */
+ num.exp = EXP_BIAS - 1;
+ if (sign) {
+ /* The argument is of the form 1-x */
+ /* Use 1-1/(1-x) = x/(1-x) */
+ *((long long *) &num.sigl) = -*((long long *) &(arg->sigl));
+ normalize(&num);
+ reg_div(&num, arg, &num, FULL_PRECISION);
+ } else {
+ normalize(&num);
+ }
+
+ denom.tag = TW_Valid; /* set the tags to Valid */
+ denom.sign = SIGN_POS; /* set the sign to positive */
+ denom.exp = EXP_BIAS;
+
+ reg_div(&num, &denom, &lXx, FULL_PRECISION);
+
+ reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&lXx, &accum, result, FULL_PRECISION);
+
+ normalize(result);
+ }
+
+ result->sign = sign;
+ return;
+ }
+ mul64((long long *) &accum.sigl,
+ (long long *) &Xx.sigl, (long long *) &accum.sigl);
+
+ *((long long *) (&accum.sigl)) += *((long long *) (&Xx.sigl));
+
+ if (Xx.sigh > accum.sigh) {
+ /* There was an overflow */
+
+ poly_div2((long long *) &accum.sigl);
+ accum.sigh |= 0x80000000;
+ accum.exp++;
+ }
+ /* When we add the exponent to the accum result later, we will require
+ * that their signs are the same. Here we ensure that this is so. */
+ if (exponent && ((exponent < 0) ^ (accum.sign))) {
+ /* signs are different */
+
+ accum.sign = !accum.sign;
+
+ /* An exceptional case is when accum is zero */
+ if (accum.sigl | accum.sigh) {
+ /* find 1-accum */
+ /* Shift to get exponent == 0 */
+ if (accum.exp < 0) {
+ poly_div2((long long *) &accum.sigl);
+ accum.exp++;
+ }
+ /* Just negate, but throw away the sign */
+ *((long long *) &(accum.sigl)) = -*((long long *) &(accum.sigl));
+ if (exponent < 0)
+ exponent++;
+ else
+ exponent--;
+ }
+ }
+ shift = exponent >= 0 ? exponent : -exponent;
+ bits = 0;
+ if (shift) {
+ if (accum.exp) {
+ accum.exp++;
+ poly_div2((long long *) &accum.sigl);
+ }
+ while (shift) {
+ poly_div2((long long *) &accum.sigl);
+ if (shift & 1)
+ accum.sigh |= 0x80000000;
+ shift >>= 1;
+ bits++;
+ }
+ }
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += bits + EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+ normalize(result);
+
+ return;
+}
+
+
+/*--- poly_l2p1() -----------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ | log2(x+1) |
+ +---------------------------------------------------------------------------*/
+int
+poly_l2p1(FPU_REG * arg, FPU_REG * result)
+{
+ char sign = 0;
+ long long Xsq;
+ FPU_REG arg_pl1, denom, accum, local_arg, poly_arg;
+
+
+ sign = arg->sign;
+
+ reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION);
+
+ if ((arg_pl1.sign) | (arg_pl1.tag)) { /* We need a valid positive
+ * number! */
+ return 1;
+ }
+ reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION);
+ reg_div(arg, &denom, &local_arg, FULL_PRECISION);
+ local_arg.sign = 0; /* Make the sign positive */
+
+ /* Now we need to check that |local_arg| is less than 3-2*sqrt(2) =
+ * 0.17157.. = .0xafb0ccc0 * 2^-2 */
+
+ if (local_arg.exp >= EXP_BIAS - 3) {
+ if ((local_arg.exp > EXP_BIAS - 3) ||
+ (local_arg.sigh > (unsigned) 0xafb0ccc0)) {
+ /* The argument is large */
+ poly_l2(&arg_pl1, result);
+ return 0;
+ }
+ }
+ /* Make a copy of local_arg */
+ reg_move(&local_arg, &poly_arg);
+
+ /* Get poly_arg bits aligned as required */
+ shrx((unsigned *) &(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3));
+
+ mul64((long long *) &(poly_arg.sigl), (long long *) &(poly_arg.sigl), &Xsq);
+ poly_div16(&Xsq);
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+ accum.sign = SIGN_POS; /* and make accum positive */
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS - 1;
+ normalize(&accum);
+
+ reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&local_arg, &accum, result, FULL_PRECISION);
+
+ /* Multiply the result by 2 */
+ result->exp++;
+
+ result->sign = sign;
+
+ return 0;
+}
diff --git a/sys/gnu/fpemul/poly_mul64.s b/sys/gnu/fpemul/poly_mul64.s
new file mode 100644
index 000000000000..be5a136a1299
--- /dev/null
+++ b/sys/gnu/fpemul/poly_mul64.s
@@ -0,0 +1,124 @@
+/*
+ * poly_mul64.S
+ *
+ * Multiply two 64 bit integers.
+ *
+ * Call from C as:
+ * void mul64(long long *a, long long *b, long long *result)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_mul64.s,v 1.3 1994/06/10 07:44:39 rich Exp $
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+.globl _mul64
+_mul64:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+ movl PARAM3,%ebx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax
+ mull (%ecx)
+ movl %eax,-16(%ebp) /* Not used */
+ movl %edx,-12(%ebp)
+
+ movl (%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull (%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ testb $128,-9(%ebp)
+ je L_no_round
+
+ addl $1,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+L_no_round:
+ movl -8(%ebp),%esi
+ movl %esi,(%ebx)
+ movl -4(%ebp),%esi
+ movl %esi,4(%ebx)
+
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/fpemul/poly_sin.c b/sys/gnu/fpemul/poly_sin.c
new file mode 100644
index 000000000000..c48cacee24dc
--- /dev/null
+++ b/sys/gnu/fpemul/poly_sin.c
@@ -0,0 +1,192 @@
+/*
+ * poly_sin.c
+ *
+ * Computation of an approximation of the sin function by a polynomial
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_sin.c,v 1.4 1994/06/10 07:44:41 rich Exp $
+ *
+ */
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWER 5
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0xe110, 0x75aa, 0xbc67, 0x1466},
+ {0x503d, 0xa43f, 0x83c1, 0x000a},
+ {0x8f9d, 0x7a19, 0x00f4, 0x0000},
+ {0xda03, 0x06aa, 0x0000, 0x0000},
+};
+
+static unsigned short negterms[HIPOWER][4] =
+{
+ {0x95ed, 0x2df2, 0xe731, 0xa55d},
+ {0xd159, 0xe62b, 0xd2cc, 0x0132},
+ {0x6342, 0xe9fb, 0x3c60, 0x0000},
+ {0x6256, 0xdf5a, 0x0002, 0x0000},
+ {0xf279, 0x000b, 0x0000, 0x0000},
+};
+
+
+/*--- poly_sine() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_sine(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ FPU_REG Xx, Xx2, Xx4, accum, negaccum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+ if (exponent >= 0) { /* Can't hack a number > 1.0 */
+ if ((exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000)) {
+ reg_move(&CONST_1, result);
+ return;
+ }
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+#endif /* PARANOID */
+
+ Xx.sigl = arg->sigl;
+ Xx.sigh = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&(Xx.sigl), -1 - exponent) >= (unsigned)0x80000000)
+ (*((long long *) (&(Xx.sigl))))++; /* round up */
+ }
+ mul64((long long *) &(Xx.sigl), (long long *) &(Xx.sigl),
+ (long long *) &(Xx2.sigl));
+ mul64((long long *) &(Xx2.sigl), (long long *) &(Xx2.sigl),
+ (long long *) &(Xx4.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(accum.sign) = 0;
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(accum.sigl), &(Xx4.sigl), lterms, HIPOWER - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(negaccum.sign) = 0;
+ negaccum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(negaccum.sigl), &(Xx4.sigl), negterms, HIPOWER - 1);
+ mul64((long long *) &(Xx2.sigl), (long long *) &(negaccum.sigl),
+ (long long *) &(negaccum.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&(accum.sigl))) -= *((long long *) (&(negaccum.sigl)));
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp = EXP_BIAS - 1 + accum.exp;
+
+ *(short *) &(result->sign) = *(short *) &(accum.sign);
+ result->exp = accum.exp;
+ result->sigl = accum.sigl;
+ result->sigh = accum.sigh;
+
+ normalize(result);
+
+ reg_mul(result, arg, result, FULL_PRECISION);
+ reg_u_add(result, arg, result, FULL_PRECISION);
+
+ /* A small overflow may be possible... but an illegal result. */
+ if (result->exp >= EXP_BIAS) {
+ if ((result->exp > EXP_BIAS) /* Larger or equal 2.0 */
+ ||(result->sigl > 1) /* Larger than 1.0+msb */
+ ||(result->sigh != 0x80000000) /* Much > 1.0 */
+ ) {
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+ EXCEPTION(EX_INTERNAL | 0x103);
+ }
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
+ printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+
+ result->sigl = 0; /* Truncate the result to 1.00 */
+ }
+}
diff --git a/sys/gnu/fpemul/poly_tan.c b/sys/gnu/fpemul/poly_tan.c
new file mode 100644
index 000000000000..b167bd51a904
--- /dev/null
+++ b/sys/gnu/fpemul/poly_tan.c
@@ -0,0 +1,229 @@
+/*
+ * poly_tan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: poly_tan.c,v 1.4 1994/06/10 07:44:42 rich Exp $
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWERop 3 /* odd poly, positive terms */
+static unsigned short oddplterms[HIPOWERop][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0x6fb2, 0x0215, 0x95c0, 0x099c},
+ {0xfce6, 0x0cc8, 0x1c9a, 0x0000}
+};
+#define HIPOWERon 2 /* odd poly, negative terms */
+static unsigned short oddnegterms[HIPOWERon][4] =
+{
+ {0x6906, 0xe205, 0x25c8, 0x8838},
+ {0x1dd7, 0x3fe3, 0x944e, 0x002c}
+};
+#define HIPOWERep 2 /* even poly, positive terms */
+static unsigned short evenplterms[HIPOWERep][4] =
+{
+ {0xdb8f, 0x3761, 0x1432, 0x2acf},
+ {0x16eb, 0x13c1, 0x3099, 0x0003}
+};
+#define HIPOWERen 2 /* even poly, negative terms */
+static unsigned short evennegterms[HIPOWERen][4] =
+{
+ {0x3a7c, 0xe4c5, 0x7f87, 0x2945},
+ {0x572b, 0x664c, 0xc543, 0x018c}
+};
+
+
+/*--- poly_tan() ------------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_tan(FPU_REG * arg, FPU_REG * y_reg)
+{
+ char invert = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, y_reg);
+ return;
+ }
+ if (exponent >= -1) {
+ /* argument is in the range [0.5 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ arith_overflow(y_reg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+ return;
+#endif /* PARANOID */
+ }
+ /* The argument is in the range [0.5 .. 1.0) */
+ /* Convert the argument to a number in the range (0.0 .. 0.5] */
+ *((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl));
+ normalize(arg); /* Needed later */
+ exponent = arg->exp - EXP_BIAS;
+ invert = 1;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(y_reg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl),
+ (long long *) (&neg_poly.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ /* Convert to 64 bit signed-compatible */
+ pos_poly.exp -= 1;
+
+ reg_move(&pos_poly, &odd_poly);
+ normalize(&odd_poly);
+
+ reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+ reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); /* This is just the odd
+ * polynomial */
+
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1);
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl));
+ /* and multiply by argSq */
+
+ /* Convert argSq to a valid reg number */
+ *(short *) &(argSq.sign) = 0;
+ argSq.exp = EXP_BIAS - 1;
+ normalize(&argSq);
+
+ /* Convert to 64 bit signed-compatible */
+ neg_poly.exp -= 1;
+
+ reg_move(&neg_poly, &even_poly);
+ normalize(&even_poly);
+
+ reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); /* This is just the even
+ * polynomial */
+
+ /* Now ready to copy the results */
+ if (invert) {
+ reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION);
+ } else {
+ reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION);
+ }
+
+}
diff --git a/sys/gnu/fpemul/polynomial.s b/sys/gnu/fpemul/polynomial.s
new file mode 100644
index 000000000000..8f48ff4183ae
--- /dev/null
+++ b/sys/gnu/fpemul/polynomial.s
@@ -0,0 +1,192 @@
+/*
+ * polynomial.S
+ *
+ * Fixed point arithmetic polynomial evaluation.
+ *
+ * Call from C as:
+ * void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2],
+ * int n)
+ *
+ * Computes:
+ * terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x
+ * The result is returned in accum.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: polynomial.s,v 1.3 1994/06/10 07:44:43 rich Exp $
+ *
+ */
+
+ .file "fpolynom.s"
+
+#include "fpu_asm.h"
+
+
+/* #define EXTRA_PRECISE*/
+
+#define TERM_SIZE $8
+
+
+.text
+ .align 2,144
+.globl _polynomial
+_polynomial:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $32,%esp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* accum */
+ movl PARAM2,%edi /* x */
+ movl PARAM3,%ebx /* terms */
+ movl PARAM4,%ecx /* n */
+
+ movl TERM_SIZE,%eax
+ mull %ecx
+ movl %eax,%ecx
+
+ movl 4(%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-20(%ebp)
+ movl (%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-24(%ebp)
+ xor %eax,%eax
+ movl %eax,-28(%ebp)
+
+ subl TERM_SIZE,%ecx
+ js L_accum_done
+
+L_accum_loop:
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -28(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ movl %edx,-12(%ebp)
+#endif EXTRA_PRECISE
+
+ movl -24(%ebp),%eax
+ mull (%edi) /* x ls long */
+/* movl %eax,-16(%ebp) */ /* Not needed */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+
+ movl -24(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull (%edi)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull 4(%edi)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+/* Now add the next term */
+ movl (%ebx,%ecx,1),%eax
+ addl %eax,-8(%ebp)
+ movl 4(%ebx,%ecx,1),%eax
+ adcl %eax,-4(%ebp)
+
+/* And put into the second register */
+ movl -4(%ebp),%eax
+ movl %eax,-20(%ebp)
+ movl -8(%ebp),%eax
+ movl %eax,-24(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -12(%ebp),%eax
+ movl %eax,-28(%ebp)
+#else
+ testb $128,-25(%ebp)
+ je L_no_poly_round
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+L_no_poly_round:
+#endif EXTRA_PRECISE
+
+ subl TERM_SIZE,%ecx
+ jns L_accum_loop
+
+L_accum_done:
+#ifdef EXTRA_PRECISE
+/* And round the result */
+ testb $128,-25(%ebp)
+ je L_poly_done
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+#endif EXTRA_PRECISE
+
+L_poly_done:
+ movl -24(%ebp),%eax
+ movl %eax,(%esi)
+ movl -20(%ebp),%eax
+ movl %eax,4(%esi)
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/fpemul/reg_add_sub.c b/sys/gnu/fpemul/reg_add_sub.c
new file mode 100644
index 000000000000..ff8b0ea37c2e
--- /dev/null
+++ b/sys/gnu/fpemul/reg_add_sub.c
@@ -0,0 +1,303 @@
+/*
+ * reg_add_sub.c
+ *
+ * Functions to add or subtract two registers and put the result in a third.
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_add_sub.c,v 1.3 1994/06/10 07:44:44 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | For each function, the destination may be any FPU_REG, including one of |
+ | the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "fpu_system.h"
+
+
+void
+reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ if (!(a->sign ^ b->sign)) {
+ /* signs are the same */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = a->sign;
+ return;
+ }
+ /* The signs are different, so do a subtraction */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = b->sign;
+ }
+ return;
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+ if (b->tag == TW_Zero) {
+ char different_signs = a->sign ^ b->sign;
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest);
+ if (different_signs) {
+ /* Signs are different. */
+ /* Sign of answer depends upon
+ * rounding mode. */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ }
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ if (a->sign == b->sign) {
+ /* They are both + or
+ * - infinity */
+ reg_move(a, dest);
+ return;
+ }
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x101);
+#endif
+}
+
+
+/* Subtract b from a. (a-b) -> dest */
+void
+reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ switch (a->sign * 2 + b->sign) {
+ case 0: /* P - P */
+ case 3: /* N - N */
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = a->sign ^ SIGN_POS ^ SIGN_NEG;
+ }
+ return;
+ case 1: /* P - N */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_POS;
+ return;
+ case 2: /* N - P */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_NEG;
+ return;
+ }
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+ if (a->tag == TW_Zero) {
+ char same_signs = !(a->sign ^ b->sign);
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest); /* Answer for different
+ * signs. */
+ if (same_signs) {
+ /* Sign depends upon rounding
+ * mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ }
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ /* Both args are Infinity */
+ if (a->sign == b->sign) {
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ }
+ reg_move(a, dest);
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x110);
+#endif
+}
diff --git a/sys/gnu/fpemul/reg_compare.c b/sys/gnu/fpemul/reg_compare.c
new file mode 100644
index 000000000000..692cdc3910f8
--- /dev/null
+++ b/sys/gnu/fpemul/reg_compare.c
@@ -0,0 +1,384 @@
+/*
+ * reg_compare.c
+ *
+ * Compare two floating point registers
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_compare.c,v 1.3 1994/06/10 07:44:47 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | compare() is the core FPU_REG comparison function |
+ +---------------------------------------------------------------------------*/
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+int
+compare(FPU_REG * b)
+{
+ int diff;
+
+ if (FPU_st0_ptr->tag | b->tag) {
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ if (b->tag == TW_Zero)
+ return COMP_A_eq_B;
+ if (b->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((b->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ } else
+ if (b->tag == TW_Zero) {
+ if (FPU_st0_ptr->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ }
+ }
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ if ((b->tag == TW_Valid) || (b->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ } else
+ if (b->tag == TW_Infinity) {
+ /* The 80486 book says that infinities
+ * can be equal! */
+ return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
+ ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ }
+ /* Fall through to the NaN code */
+ } else
+ if (b->tag == TW_Infinity) {
+ if ((FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->tag == TW_Valid)
+ && (FPU_st0_ptr->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ /* Fall through to the NaN code */
+ }
+ /* The only possibility now should be that one of the
+ * arguments is a NaN */
+ if ((FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ if (((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
+ || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)))
+ /* At least one arg is a signaling NaN */
+ return COMP_No_Comp | COMP_SNaN | COMP_NaN;
+ else
+ /* Neither is a signaling NaN */
+ return COMP_No_Comp | COMP_NaN;
+ }
+ EXCEPTION(EX_Invalid);
+ }
+#ifdef PARANOID
+ if (!(FPU_st0_ptr->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+ if (!(b->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+#endif /* PARANOID */
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (b->exp <= EXP_UNDER)) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign != b->sign)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+
+ diff = FPU_st0_ptr->exp - b->exp;
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigl > b->sigl;
+ if (diff == 0)
+ diff = -(FPU_st0_ptr->sigl < b->sigl);
+ }
+ }
+ if (diff > 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ if (diff < 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ return COMP_A_eq_B;
+
+}
+
+
+/* This function requires that st(0) is not empty */
+int
+compare_st_data(void)
+{
+ int f, c;
+
+ c = compare(&FPU_loaded_data);
+
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ EXCEPTION(EX_Invalid);
+ f = SW_C3 | SW_C2 | SW_C0;
+ } else {
+ /* One of the operands is a de-normal */
+ return 0;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x121);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_st_st(int nr)
+{
+ int f, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x122);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_u_st_st(int nr)
+{
+ int f, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (c & COMP_SNaN) { /* This is the only difference
+ * between un-ordered and
+ * ordinary comparisons */
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ }
+ return 1;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x123);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+/*---------------------------------------------------------------------------*/
+
+void
+fcom_st()
+{
+ /* fcom st(i) */
+ compare_st_st(FPU_rm);
+}
+
+
+void
+fcompst()
+{
+ /* fcomp st(i) */
+ if (compare_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fcompp()
+{
+ /* fcompp */
+ if (FPU_rm != 1)
+ return Un_impl();
+ if (compare_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+}
+
+
+void
+fucom_()
+{
+ /* fucom st(i) */
+ compare_u_st_st(FPU_rm);
+
+}
+
+
+void
+fucomp()
+{
+ /* fucomp st(i) */
+ if (compare_u_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fucompp()
+{
+ /* fucompp */
+ if (FPU_rm == 1) {
+ if (compare_u_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+ } else
+ Un_impl();
+}
diff --git a/sys/gnu/fpemul/reg_constant.c b/sys/gnu/fpemul/reg_constant.c
new file mode 100644
index 000000000000..f33427358e1c
--- /dev/null
+++ b/sys/gnu/fpemul/reg_constant.c
@@ -0,0 +1,175 @@
+/*
+ * reg_constant.c
+ *
+ * All of the constant FPU_REGs
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $id:$
+ *
+ */
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "status_w.h"
+#include "reg_constant.h"
+
+
+FPU_REG CONST_1 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x00000000, 0x80000000};
+FPU_REG CONST_2 = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0x00000000, 0x80000000};
+FPU_REG CONST_HALF = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0x00000000, 0x80000000};
+FPU_REG CONST_L2T = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0xcd1b8afe, 0xd49a784b};
+FPU_REG CONST_L2E = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x5c17f0bc, 0xb8aa3b29};
+FPU_REG CONST_PI = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI2 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI4 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_LG2 = {SIGN_POS, TW_Valid, EXP_BIAS - 2,
+0xfbcff799, 0x9a209a84};
+FPU_REG CONST_LN2 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0xd1cf79ac, 0xb17217f7};
+/* Only the sign (and tag) is used in internal zeroes */
+FPU_REG CONST_Z = {SIGN_POS, TW_Zero, 0, 0x0, 0x0};
+/* Only the sign and significand (and tag) are used in internal NaNs */
+/* The 80486 never generates one of these
+FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+ */
+/* This is the real indefinite QNaN */
+FPU_REG CONST_QNaN = {SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000};
+/* Only the sign (and tag) is used in internal infinities */
+FPU_REG CONST_INF = {SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000};
+
+
+
+static void
+fld_const(FPU_REG * c)
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ push();
+ reg_move(c, FPU_st0_ptr);
+ status_word &= ~SW_C1;
+}
+
+
+static void
+fld1(void)
+{
+ fld_const(&CONST_1);
+}
+
+static void
+fldl2t(void)
+{
+ fld_const(&CONST_L2T);
+}
+
+static void
+fldl2e(void)
+{
+ fld_const(&CONST_L2E);
+}
+
+static void
+fldpi(void)
+{
+ fld_const(&CONST_PI);
+}
+
+static void
+fldlg2(void)
+{
+ fld_const(&CONST_LG2);
+}
+
+static void
+fldln2(void)
+{
+ fld_const(&CONST_LN2);
+}
+
+static void
+fldz(void)
+{
+ fld_const(&CONST_Z);
+}
+
+static FUNC constants_table[] = {
+ fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl
+};
+
+void
+fconst(void)
+{
+ (constants_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/fpemul/reg_constant.h b/sys/gnu/fpemul/reg_constant.h
new file mode 100644
index 000000000000..d64a3d55f91b
--- /dev/null
+++ b/sys/gnu/fpemul/reg_constant.h
@@ -0,0 +1,82 @@
+/*
+ * reg_constant.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_constant.h,v 1.3 1994/06/10 07:44:49 rich Exp $
+ *
+ */
+
+#ifndef _REG_CONSTANT_H_
+#define _REG_CONSTANT_H_
+
+#include "fpu_emu.h"
+
+extern FPU_REG CONST_1;
+extern FPU_REG CONST_2;
+extern FPU_REG CONST_HALF;
+extern FPU_REG CONST_L2T;
+extern FPU_REG CONST_L2E;
+extern FPU_REG CONST_PI;
+extern FPU_REG CONST_PI2;
+extern FPU_REG CONST_PI4;
+extern FPU_REG CONST_LG2;
+extern FPU_REG CONST_LN2;
+extern FPU_REG CONST_Z;
+extern FPU_REG CONST_PINF;
+extern FPU_REG CONST_INF;
+extern FPU_REG CONST_MINF;
+extern FPU_REG CONST_QNaN;
+
+#endif /* _REG_CONSTANT_H_ */
diff --git a/sys/gnu/fpemul/reg_div.s b/sys/gnu/fpemul/reg_div.s
new file mode 100644
index 000000000000..8f7357530b7e
--- /dev/null
+++ b/sys/gnu/fpemul/reg_div.s
@@ -0,0 +1,295 @@
+ .file "reg_div.S"
+/*
+ * reg_div.S
+ *
+ * Divide one FPU_REG by another and put the result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_div.s,v 1.3 1994/06/10 07:44:50 rich Exp $
+ *
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2
+
+.globl _reg_div
+_reg_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ebx
+ movl PARAM3,%edi
+
+ movb TAG(%esi),%al
+ orb TAG(%ebx),%al
+
+ jne L_div_special /* Not (both numbers TW_Valid) */
+
+#ifdef DENORM_OPERAND
+/* Check for denormals */
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xL_arg1_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg1_not_denormal:
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg xL_arg2_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg2_not_denormal:
+#endif DENORM_OPERAND
+
+/* Both arguments are TW_Valid */
+ movb TW_Valid,TAG(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
+
+ movl EXP(%esi),%edx
+ movl EXP(%ebx),%eax
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
+ movl %edx,EXP(%edi)
+
+ jmp _divide_kernel
+
+
+/*-----------------------------------------------------------------------*/
+L_div_special:
+ cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
+ je L_arg1_NaN
+
+ cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
+ jne L_no_NaN_arg
+
+/* Operations on NaNs */
+L_arg1_NaN:
+L_arg2_NaN:
+ pushl %edi /* Destination */
+ pushl %ebx
+ pushl %esi
+ call _real_2op_NaN
+ jmp LDiv_exit
+
+/* Invalid operations */
+L_zero_zero:
+L_inf_inf:
+ pushl %edi /* Destination */
+ call _arith_invalid /* 0/0 or Infinity/Infinity */
+ jmp LDiv_exit
+
+L_no_NaN_arg:
+ cmpb TW_Infinity,TAG(%esi)
+ jne L_arg1_not_inf
+
+ cmpb TW_Infinity,TAG(%ebx)
+ je L_inf_inf /* invalid operation */
+
+ cmpb TW_Valid,TAG(%ebx)
+ je L_inf_valid
+
+#ifdef PARANOID
+ /* arg2 must be zero or valid */
+ cmpb TW_Zero,TAG(%ebx)
+ ja L_unknown_tags
+#endif PARANOID
+
+ /* Note that p16-9 says that infinity/0 returns infinity */
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_inf_valid:
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is Inf */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_arg1_not_inf:
+ cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
+ jne L_arg2_not_zero
+
+ cmpb TW_Zero,TAG(%esi)
+ je L_zero_zero /* invalid operation */
+
+#ifdef PARANOID
+ /* arg1 must be valid */
+ cmpb TW_Valid,TAG(%esi)
+ ja L_unknown_tags
+#endif PARANOID
+
+/* Division by zero error */
+ pushl %edi /* destination */
+ movb SIGN(%esi),%al
+ xorb SIGN(%ebx),%al
+ pushl %eax /* lower 8 bits have the sign */
+ call _divide_by_zero
+ jmp LDiv_exit
+
+L_arg2_not_zero:
+ cmpb TW_Infinity,TAG(%ebx)
+ jne L_arg2_not_inf
+
+#ifdef DENORM_OPERAND
+ cmpb TW_Valid,TAG(%esi)
+ jne L_return_zero
+
+ cmpl EXP_UNDER,EXP(%esi)
+ jg L_return_zero /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_return_zero /* Answer is zero */
+
+L_arg2_not_inf:
+
+#ifdef PARANOID
+ cmpb TW_Zero,TAG(%esi)
+ jne L_unknown_tags
+#endif PARANOID
+
+ /* arg1 is zero, arg2 is not Infinity or a NaN */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+L_copy_arg1:
+ movb TAG(%esi),%ax
+ movb %ax,TAG(%edi)
+ movl EXP(%esi),%eax
+ movl %eax,EXP(%edi)
+ movl SIGL(%esi),%eax
+ movl %eax,SIGL(%edi)
+ movl SIGH(%esi),%eax
+ movl %eax,SIGH(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%edi)
+ jmp LDiv_exit
+
+LDiv_set_result_sign:
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%edi)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%ebx)
+ jmp LDiv_exit
+
+LDiv_negative_result:
+ movb SIGN_NEG,SIGN(%edi)
+
+LDiv_exit:
+ leal -12(%ebp),%esp
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_return_zero:
+ movb TW_Zero,TAG(%edi)
+ jmp LDiv_set_result_sign
+
+#ifdef PARANOID
+L_unknown_tags:
+ push EX_INTERNAL | 0x208
+ call EXCEPTION
+
+ /* Generate a NaN for unknown tags */
+ movl _CONST_QNaN,%eax
+ movl %eax,(%edi)
+ movl _CONST_QNaN+4,%eax
+ movl %eax,SIGL(%edi)
+ movl _CONST_QNaN+8,%eax
+ movl %eax,SIGH(%edi)
+ jmp LDiv_exit
+#endif PARANOID
diff --git a/sys/gnu/fpemul/reg_ld_str.c b/sys/gnu/fpemul/reg_ld_str.c
new file mode 100644
index 000000000000..37b69a6bbfe2
--- /dev/null
+++ b/sys/gnu/fpemul/reg_ld_str.c
@@ -0,0 +1,1387 @@
+/*
+ * reg_ld_str.c
+ *
+ * All of the functions which transfer data between user memory and FPU_REGs.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_ld_str.c,v 1.3 1994/06/10 07:44:52 rich Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "reg_constant.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define EXTENDED_Emax 0x3fff /* largest valid exponent */
+#define EXTENDED_Ebias 0x3fff
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
+#define DOUBLE_Emax 1023 /* largest valid exponent */
+#define DOUBLE_Ebias 1023
+#define DOUBLE_Emin (-1022) /* smallest valid exponent */
+
+#define SINGLE_Emax 127 /* largest valid exponent */
+#define SINGLE_Ebias 127
+#define SINGLE_Emin (-126) /* smallest valid exponent */
+
+#define LOST_UP (EX_Precision | SW_C1)
+#define LOST_DOWN EX_Precision
+
+FPU_REG FPU_loaded_data;
+
+
+/* Get a long double from user memory */
+void
+reg_load_extended(void)
+{
+ long double *s = (long double *) FPU_data_address;
+ unsigned long sigl, sigh, exp;
+
+ REENTRANT_CHECK(OFF);
+ /* Use temporary variables here because FPU_loaded data is static and
+ * hence re-entrancy problems can arise */
+ sigl = fuword((unsigned long *) s);
+ sigh = fuword(1 + (unsigned long *) s);
+ exp = fuword(4 + (unsigned short *) s);
+ REENTRANT_CHECK(ON);
+
+ FPU_loaded_data.sigl = sigl;
+ FPU_loaded_data.sigh = sigh;
+ FPU_loaded_data.exp = exp;
+
+ if (FPU_loaded_data.exp & 0x8000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if ((FPU_loaded_data.exp &= 0x7fff) == 0) {
+ if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) {
+ FPU_loaded_data.tag = TW_Zero;
+ return;
+ }
+ /* The number is a de-normal or pseudodenormal. */
+ /* The 80486 doesn't regard pseudodenormals as denormals here. */
+ if (!(FPU_loaded_data.sigh & 0x80000000))
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp++;
+
+ /* The default behaviour will now take care of it. */
+ } else
+ if (FPU_loaded_data.exp == 0x7fff) {
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ if ((FPU_loaded_data.sigh == 0x80000000)
+ && (FPU_loaded_data.sigl == 0)) {
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else
+ if (!(FPU_loaded_data.sigh & 0x80000000)) {
+ /* Unsupported NaN data type */
+ EXCEPTION(EX_Invalid);
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
+ + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+
+ if (!(sigh & 0x80000000)) {
+ /* Unsupported data type */
+ EXCEPTION(EX_Invalid);
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+
+
+/* Get a double from user memory */
+void
+reg_load_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ int exp;
+ unsigned m64, l64;
+
+ REENTRANT_CHECK(OFF);
+ m64 = fuword(1 + (unsigned long *) dfloat);
+ l64 = fuword((unsigned long *) dfloat);
+ REENTRANT_CHECK(ON);
+
+ if (m64 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
+ m64 &= 0xfffff;
+ if (exp > DOUBLE_Emax) {
+ /* Infinity or NaN */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ return;
+ }
+ } else
+ if (exp < DOUBLE_Emin) {
+ /* Zero or de-normal */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ } else {
+ /* De-normal */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m64 << 11;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+
+ return;
+ }
+}
+
+
+/* Get a float from user memory */
+void
+reg_load_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ unsigned m32;
+ int exp;
+
+ REENTRANT_CHECK(OFF);
+ m32 = fuword((unsigned long *) single);
+ REENTRANT_CHECK(ON);
+
+ if (m32 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if (!(m32 & 0x7fffffff)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ }
+ exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
+ m32 = (m32 & 0x7fffff) << 8;
+ if (exp < SINGLE_Emin) {
+ /* De-normals */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m32;
+ FPU_loaded_data.sigl = 0;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ } else
+ if (exp > SINGLE_Emax) {
+ /* Infinity or NaN */
+ if (m32 == 0) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.tag = TW_Valid;
+ }
+}
+
+
+/* Get a long long from user memory */
+void
+reg_load_int64(void)
+{
+ long long *_s = (long long *) FPU_data_address;
+ int e;
+ long long s;
+
+ REENTRANT_CHECK(OFF);
+ ((unsigned long *) &s)[0] = fuword((unsigned long *) _s);
+ ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 63;
+ *((long long *) &FPU_loaded_data.sigl) = s;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a long from user memory */
+void
+reg_load_int32(void)
+{
+ long *_s = (long *) FPU_data_address;
+ long s;
+ int e;
+
+ REENTRANT_CHECK(OFF);
+ s = (long) fuword((unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 31;
+ FPU_loaded_data.sigh = s;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a short from user memory */
+void
+reg_load_int16(void)
+{
+ short *_s = (short *) FPU_data_address;
+ int s, e;
+
+ REENTRANT_CHECK(OFF);
+ /* Cast as short to get the sign extended. */
+ s = (short) fuword((unsigned short *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 15;
+ FPU_loaded_data.sigh = s << 16;
+
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a packed bcd array from user memory */
+void
+reg_load_bcd(void)
+{
+ char *s = (char *) FPU_data_address;
+ int pos;
+ unsigned char bcd;
+ long long l = 0;
+
+ for (pos = 8; pos >= 0; pos--) {
+ l *= 10;
+ REENTRANT_CHECK(OFF);
+ bcd = (unsigned char) fubyte((unsigned char *) s + pos);
+ REENTRANT_CHECK(ON);
+ l += bcd >> 4;
+ l *= 10;
+ l += bcd & 0x0f;
+ }
+
+ /* Finish all access to user memory before putting stuff into the
+ * static FPU_loaded_data */
+ REENTRANT_CHECK(OFF);
+ FPU_loaded_data.sign =
+ ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ?
+ SIGN_NEG : SIGN_POS;
+ REENTRANT_CHECK(ON);
+
+ if (l == 0) {
+ char sign = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = sign;
+ } else {
+ *((long long *) &FPU_loaded_data.sigl) = l;
+ FPU_loaded_data.exp = EXP_BIAS + 63;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+/*===========================================================================*/
+
+/* Put a long double into user memory */
+int
+reg_store_extended(void)
+{
+ long double *d = (long double *) FPU_data_address;
+ long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
+ unsigned short sign = FPU_st0_ptr->sign * 0x8000;
+ unsigned long ls, ms;
+
+
+ if (FPU_st0_tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ EXCEPTION(EX_Overflow); /* Overflow */
+ /* This is a special case: see sec 16.2.5.1 of the
+ * 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ return 0;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Correctly format the de-normal */
+ int precision_loss;
+ FPU_REG tmp;
+
+ EXCEPTION(EX_Denormal);
+ reg_move(FPU_st0_ptr, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ if ((precision_loss = round_to_int(&tmp))) {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see
+ * sec 16.2.5.1 of the 80486
+ * book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ e = 0;
+ ls = tmp.sigl;
+ ms = tmp.sigh;
+ } else {
+ /* ****** ??? This should not be
+ * possible */
+ EXCEPTION(EX_Underflow); /* Underflow */
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Underflow) {
+ /* Underflow to zero */
+ ls = 0;
+ ms = 0;
+ e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff;
+ } else
+ return 0;
+ }
+ } else {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ ls = ms = 0;
+ e = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ ls = 0;
+ ms = 0xc0000000;
+ e = 0xffff;
+ } else
+ return 0;
+ } else {
+ /* We don't use TW_Denormal
+ * yet ... perhaps never! */
+ EXCEPTION(EX_Invalid);
+ /* Store a NaN */
+ e = 0x7fff;
+ ls = 1;
+ ms = 0x80000000;
+ }
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10); */
+ suword((unsigned long *) d, ls);
+ suword(1 + (unsigned long *) d, ms);
+ suword(4 + (short *) d, (unsigned short) e | sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+
+}
+
+
+/* Put a double into user memory */
+int
+reg_store_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ unsigned long l[2];
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < DOUBLE_Emin) { /* It may be a denormal */
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
+ (FPU_st0_ptr->sigl & 0x000007ff))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ l[0] = tmp.sigl;
+ l[1] = tmp.sigh;
+ } else {
+ if (tmp.sigl & 0x000007ff) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ /* Rounding can get a little messy.. */
+ increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
+ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate the mantissa */
+ tmp.sigl &= 0xfffff800;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (tmp.sigl >= 0xfffff800) {
+ /* the sigl part overflows */
+ if (tmp.sigh == 0xffffffff) {
+ /* The sigh part
+ * overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh++;
+ }
+ tmp.sigl = 0x00000000;
+ } else {
+ /* We only need to increment
+ * sigl */
+ tmp.sigl += 0x00000800;
+ }
+ } else
+ set_precision_flag_down();
+ }
+ l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
+ l[1] = ((tmp.sigh >> 11) & 0xfffff);
+
+ if (exp > DOUBLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ l[0] = 0x00000000; /* Set to */
+ l[1] = 0x7ff00000; /* + INF */
+ } else
+ return 0;
+ } else {
+ /* Add the exponent */
+ l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* Number is zero */
+ l[0] = 0;
+ l[1] = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ l[0] = 0;
+ l[1] = 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
+ l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
+ if (!(l[0] | l[1])) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ l[1] |= 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+ /* verify_area(VERIFY_W
+ * RITE, (void *)
+ * dfloat, 8); */
+ suword((unsigned long *) dfloat, 0);
+ suword(1 + (unsigned long *) dfloat, 0xfff80000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * double real will
+ * always underflow */
+ l[0] = l[1] = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ l[1] |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/
+ suword((u_long *) dfloat, l[0]);
+ suword((u_long *) dfloat + 1, l[1]);
+/*
+ suword(l[0], (unsigned long *) dfloat);
+ suword(l[1], 1 + (unsigned long *) dfloat);*/
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a float into user memory */
+int
+reg_store_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ long templ;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < SINGLE_Emin) {
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigl == 0x00800000) &&
+ ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ templ = tmp.sigl;
+ } else {
+ if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+ unsigned long sigh = tmp.sigh;
+ unsigned long sigl = tmp.sigl;
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ increment = ((sigh & 0xff) > 0x80) /* more than half */
+ ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
+ ||((sigh & 0x180) == 0x180); /* round to even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? 0 : (sigl | (sigh & 0xff));
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? (sigl | (sigh & 0xff)) : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate part of the mantissa */
+ tmp.sigl = 0;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (sigh >= 0xffffff00) {
+ /* The sigh part overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh &= 0xffffff00;
+ tmp.sigh += 0x100;
+ }
+ } else {
+ set_precision_flag_down();
+ tmp.sigh &= 0xffffff00; /* Finish the truncation */
+ }
+ }
+ templ = (tmp.sigh >> 8) & 0x007fffff;
+
+ if (exp > SINGLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ templ = 0x7f800000;
+ } else
+ return 0;
+ } else
+ templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ templ = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ templ = 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ templ = FPU_st0_ptr->sigh >> 8;
+ if (!(templ & 0x3fffff)) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ templ |= 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, 0xffc00000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * real will always
+ * underflow */
+ templ = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x106);
+ return 0;
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ templ |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, templ);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long long into user memory */
+int
+reg_store_int64(void)
+{
+ long long *d = (long long *) FPU_data_address;
+ FPU_REG t;
+ long long tll;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ((long *) &tll)[0] = t.sigl;
+ ((long *) &tll)[1] = t.sigh;
+ if ((t.sigh & 0x80000000) &&
+ !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ put_indefinite:
+ ((long *) &tll)[1] = 0x80000000;
+ ((long *) &tll)[0] = 0;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ tll = -tll;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) d, 8); */
+ suword((unsigned long *) d, ((long *) &tll)[0]);
+ suword(1 + (unsigned long *) d, ((long *) &tll)[1]);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long into user memory */
+int
+reg_store_int32(void)
+{
+ long *d = (long *) FPU_data_address;
+ FPU_REG t;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4);*/
+ suword((unsigned long *) d, 0x80000000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0x80000000) &&
+ !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ t.sigl = 0x80000000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -(long) t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4); */
+ suword((unsigned long *) d, t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a short into user memory */
+int
+reg_store_int16(void)
+{
+ short *d = (short *) FPU_data_address;
+ FPU_REG t;
+ short ts;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2);*/
+ suword((unsigned short *) d, 0x8000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0xffff8000) &&
+ !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ ts = 0x8000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2); */
+ suword((short *) d, (short) t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a packed bcd array into user memory */
+int
+reg_store_bcd(void)
+{
+ char *d = (char *) FPU_data_address;
+ FPU_REG t;
+ long long ll;
+ unsigned char b;
+ int i;
+ unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ll = *(long long *) (&t.sigl);
+
+ /* Check for overflow, by comparing with 999999999999999999 decimal. */
+ if ((t.sigh > 0x0de0b6b3) ||
+ ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ put_indefinite:
+ /* Produce "indefinite" */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ subyte((unsigned char *) d + 7, 0xff);
+ subyte((unsigned char *) d + 8, 0xff);
+ subyte((unsigned char *) d + 9, 0xff);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ for (i = 0; i < 9; i++) {
+ b = div_small(&ll, 10);
+ b |= (div_small(&ll, 10)) << 4;
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + i, b);
+ REENTRANT_CHECK(ON);
+ }
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + 9, sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+/*===========================================================================*/
+
+/* r gets mangled such that sig is int, sign:
+ it is NOT normalized */
+/* The return value (in eax) is zero if the result is exact,
+ if bits are changed due to rounding, truncation, etc, then
+ a non-zero value is returned */
+/* Overflow is signalled by a non-zero return value (in eax).
+ In the case of overflow, the returned significand always has the
+ the largest possible value */
+/* The value returned in eax is never actually needed :-) */
+int
+round_to_int(FPU_REG * r)
+{
+ char very_big;
+ unsigned eax;
+
+ if (r->tag == TW_Zero) {
+ /* Make sure that zero is returned */
+ *(long long *) &r->sigl = 0;
+ return 0; /* o.k. */
+ }
+ if (r->exp > EXP_BIAS + 63) {
+ r->sigl = r->sigh = ~0; /* The largest representable number */
+ return 1; /* overflow */
+ }
+ eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+ very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
+#define half_or_more (eax & 0x80000000)
+#define frac_part (eax)
+#define more_than_half ((eax & 0x80000001) == 0x80000001)
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ if (more_than_half /* nearest */
+ || (half_or_more && (r->sigl & 1))) { /* odd -> even */
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_DOWN:
+ if (frac_part && r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_UP:
+ if (frac_part && !r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_CHOP:
+ break;
+ }
+
+ return eax ? LOST_DOWN : 0;
+
+}
+/*===========================================================================*/
+
+char *
+fldenv(void)
+{
+ char *s = (char *) FPU_data_address;
+ unsigned short tag_word = 0;
+ unsigned char tag;
+ int i;
+
+ REENTRANT_CHECK(OFF);
+ control_word = fuword((unsigned short *) s);
+ status_word = fuword((unsigned short *) (s + 4));
+ tag_word = fuword((unsigned short *) (s + 8));
+ ip_offset = fuword((unsigned long *) (s + 0x0c));
+ cs_selector = fuword((unsigned long *) (s + 0x10));
+ data_operand_offset = fuword((unsigned long *) (s + 0x14));
+ operand_selector = fuword((unsigned long *) (s + 0x18));
+ REENTRANT_CHECK(ON);
+
+ top = (status_word >> SW_Top_Shift) & 7;
+
+ for (i = 0; i < 8; i++) {
+ tag = tag_word & 3;
+ tag_word >>= 2;
+
+ switch (tag) {
+ case 0:
+ regs[i].tag = TW_Valid;
+ break;
+ case 1:
+ regs[i].tag = TW_Zero;
+ break;
+ case 2:
+ regs[i].tag = TW_NaN;
+ break;
+ case 3:
+ regs[i].tag = TW_Empty;
+ break;
+ }
+ }
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+
+ return s + 0x1c;
+}
+
+
+void
+frstor(void)
+{
+ int i, stnr;
+ unsigned char tag;
+ unsigned short saved_status, saved_control;
+ char *s = (char *) fldenv();
+
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = 0x037f; /* Mask all interrupts while we load. */
+ for (i = 0; i < 8; i++) {
+ /* load each register */
+ FPU_data_address = (void *) (s + i * 10);
+ reg_load_extended();
+ stnr = (i + top) & 7;
+ tag = regs[stnr].tag; /* derived from the loaded tag word */
+ reg_move(&FPU_loaded_data, &regs[stnr]);
+ if (tag == TW_NaN) {
+ /* The current data is a special, i.e. NaN,
+ * unsupported, infinity, or denormal */
+ unsigned char t = regs[stnr].tag; /* derived from the new
+ * data */
+ if ( /* (t == TW_Valid) || *** */ (t == TW_Zero))
+ regs[stnr].tag = TW_NaN;
+ } else
+ regs[stnr].tag = tag;
+ }
+ control_word = saved_control;
+ status_word = saved_status;
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+}
+
+
+unsigned short
+tag_word(void)
+{
+ unsigned short word = 0;
+ unsigned char tag;
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ switch (tag = regs[i].tag) {
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ case TW_Denormal:
+#endif
+ case TW_Valid:
+ if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias))
+ tag = 2;
+ break;
+ case TW_Infinity:
+ case TW_NaN:
+ tag = 2;
+ break;
+ case TW_Empty:
+ tag = 3;
+ break;
+ /* TW_Valid and TW_Zero already have the correct value */
+ }
+ word <<= 2;
+ word |= tag;
+ }
+ return word;
+}
+
+
+char *
+fstenv(void)
+{
+ char *d = (char *) FPU_data_address;
+
+/* verify_area(VERIFY_WRITE, d, 28);*/
+
+#if 0 /****/
+ *(unsigned short *) &cs_selector = fpu_cs;
+ *(unsigned short *) &operand_selector = fpu_os;
+#endif /****/
+
+ REENTRANT_CHECK(OFF);
+ suword((unsigned short *) d, control_word);
+ suword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift));
+ suword((unsigned short *) (d + 8), tag_word());
+ suword((unsigned long *) (d + 0x0c), ip_offset);
+ suword((unsigned long *) (d + 0x10), cs_selector);
+ suword((unsigned long *) (d + 0x14), data_operand_offset);
+ suword((unsigned long *) (d + 0x18), operand_selector);
+ REENTRANT_CHECK(ON);
+
+ return d + 0x1c;
+}
+
+
+void
+fsave(void)
+{
+ char *d;
+ FPU_REG tmp, *rp;
+ int i;
+ short e;
+
+ d = fstenv();
+/* verify_area(VERIFY_WRITE, d, 80);*/
+ for (i = 0; i < 8; i++) {
+ /* Store each register in the order: st(0), st(1), ... */
+ rp = &regs[(top + i) & 7];
+
+ e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
+
+ if (rp->tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ /* Overflow to infinity */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Make a de-normal */
+ reg_move(rp, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ round_to_int(&tmp);
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), tmp.sigl);
+ suword((unsigned long *) (d + i * 10 + 4), tmp.sigh);
+ REENTRANT_CHECK(ON);
+ } else {
+ /* Underflow to zero */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ }
+ e = 0;
+ } else {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ } else
+ if (rp->tag == TW_Zero) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0;
+ } else
+ if (rp->tag == TW_Infinity) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0x80000000);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_NaN) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_Empty) {
+ /* just copy the reg */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ e |= rp->sign == SIGN_POS ? 0 : 0x8000;
+ REENTRANT_CHECK(OFF);
+ suword((unsigned short *) (d + i * 10 + 8), e);
+ REENTRANT_CHECK(ON);
+ }
+
+ finit();
+
+}
+/*===========================================================================*/
diff --git a/sys/gnu/fpemul/reg_mul.c b/sys/gnu/fpemul/reg_mul.c
new file mode 100644
index 000000000000..5924e5e75df2
--- /dev/null
+++ b/sys/gnu/fpemul/reg_mul.c
@@ -0,0 +1,162 @@
+/*
+ * reg_mul.c
+ *
+ * Multiply one FPU_REG by another, put the result in a destination FPU_REG.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_mul.c,v 1.3 1994/06/10 07:44:53 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+
+
+/* This routine must be called with non-empty source registers */
+void
+reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w)
+{
+ char sign = (a->sign ^ b->sign);
+
+ if (!(a->tag | b->tag)) {
+ /* This should be the most common case */
+ reg_u_mul(a, b, dest, control_w);
+ dest->sign = sign;
+ return;
+ } else
+ if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
+ ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER))) {
+ if (denormal_operand())
+ return;
+ }
+#endif /* DENORM_OPERAND */
+ /* Must have either both arguments == zero, or one
+ * valid and the other zero. The result is therefore
+ * zero. */
+ reg_move(&CONST_Z, dest);
+#ifdef PECULIAR_486
+ /* The 80486 book says that the answer is +0, but a
+ * real 80486 appears to behave this way... */
+ dest->sign = sign;
+#endif /* PECULIAR_486 */
+ return;
+ }
+#if 0 /* TW_Denormal is not used yet... perhaps
+ * never will be. */
+ else
+ if ((a->tag <= TW_Denormal) && (b->tag <= TW_Denormal)) {
+ /* One or both arguments are de-normalized */
+ /* Internal de-normalized numbers are not
+ * supported yet */
+ EXCEPTION(EX_INTERNAL | 0x105);
+ reg_move(&CONST_Z, dest);
+ }
+#endif
+ else {
+ /* Must have infinities, NaNs, etc */
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ dest->sign = sign;
+ }
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+ if (a->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is
+ * invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign = sign;
+ }
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x102);
+ }
+#endif /* PARANOID */
+ }
+}
diff --git a/sys/gnu/fpemul/reg_norm.s b/sys/gnu/fpemul/reg_norm.s
new file mode 100644
index 000000000000..37b080e0271b
--- /dev/null
+++ b/sys/gnu/fpemul/reg_norm.s
@@ -0,0 +1,182 @@
+/*
+ * reg_norm.s
+ *
+ * Normalize the value in a FPU_REG.
+ *
+ * Call from C as:
+ * void normalize(FPU_REG *n)
+ *
+ * void normalize_nuo(FPU_REG *n)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_norm.s,v 1.3 1994/06/10 07:44:54 rich Exp $
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+
+.text
+
+ .align 2,144
+.globl _normalize
+
+_normalize:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_done /* Already normalized */
+ jnz L_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+
+L_done:
+ cmpl EXP_OVER,EXP(%ebx)
+ jge L_overflow
+
+ cmpl EXP_UNDER,EXP(%ebx)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ leave
+ ret
+
+
+L_zero:
+ movl EXP_UNDER,EXP(%ebx)
+ movb TW_Zero,TAG(%ebx)
+ jmp L_exit
+
+L_underflow:
+ push %ebx
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
+L_overflow:
+ push %ebx
+ call _arith_overflow
+ pop %ebx
+ jmp L_exit
+
+
+
+/* Normalise without reporting underflow or overflow */
+ .align 2,144
+.globl _normalize_nuo
+
+_normalize_nuo:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_exit /* Already normalized */
+ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_nuo_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_nuo_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+ jmp L_exit
+
+
diff --git a/sys/gnu/fpemul/reg_round.s b/sys/gnu/fpemul/reg_round.s
new file mode 100644
index 000000000000..7490bbb31d7e
--- /dev/null
+++ b/sys/gnu/fpemul/reg_round.s
@@ -0,0 +1,653 @@
+ .file "reg_round.S"
+/*
+ * reg_round.S
+ *
+ * Rounding/truncation/etc for FPU basic arithmetic functions.
+ *
+ * This code has four possible entry points.
+ * The following must be entered by a jmp intruction:
+ * FPU_round, FPU_round_sqrt, and FPU_Arith_exit.
+ *
+ * The _round_reg entry point is intended to be used by C code.
+ * From C, call as:
+ * void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_round.s,v 1.3 1994/06/10 07:44:55 rich Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Four entry points. |
+ | |
+ | Needed by both the FPU_round and FPU_round_sqrt entry points: |
+ | %eax:%ebx 64 bit significand |
+ | %edx 32 bit extension of the significand |
+ | %edi pointer to an FPU_REG for the result to be stored |
+ | stack calling function must have set up a C stack frame and |
+ | pushed %esi, %edi, and %ebx |
+ | |
+ | Needed just for the FPU_round_sqrt entry point: |
+ | %cx A control word in the same format as the FPU control word. |
+ | Otherwise, PARAM4 must give such a value. |
+ | |
+ | |
+ | The significand and its extension are assumed to be exact in the |
+ | following sense: |
+ | If the significand by itself is the exact result then the significand |
+ | extension (%edx) must contain 0, otherwise the significand extension |
+ | must be non-zero. |
+ | If the significand extension is non-zero then the significand is |
+ | smaller than the magnitude of the correct exact result by an amount |
+ | greater than zero and less than one ls bit of the significand. |
+ | The significand extension is only required to have three possible |
+ | non-zero values: |
+ | less than 0x80000000 <=> the significand is less than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
+ | smaller than the magnitude of the true |
+ | exact result. |
+ | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The code in this module has become quite complex, but it should handle |
+ | all of the FPU flags which are set at this stage of the basic arithmetic |
+ | computations. |
+ | There are a few rare cases where the results are not set identically to |
+ | a real FPU. These require a bit more thought because at this stage the |
+ | results of the code here appear to be more consistent... |
+ | This may be changed in a future version. |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_asm.h"
+#include "exception.h"
+#include "control_w.h"
+
+#define LOST_DOWN $1
+#define LOST_UP $2
+#define DENORMAL $1
+#define UNMASKED_UNDERFLOW $2
+
+.data
+ .align 2,0
+FPU_bits_lost:
+ .byte 0
+FPU_denormal:
+ .byte 0
+
+.text
+ .align 2,144
+.globl FPU_round
+.globl FPU_round_sqrt
+.globl FPU_Arith_exit
+.globl _round_reg
+
+/* Entry point when called from C */
+_round_reg:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%edi
+ movl SIGH(%edi),%eax
+ movl SIGL(%edi),%ebx
+ movl PARAM2,%edx
+ movl PARAM3,%ecx
+ jmp FPU_round_sqrt
+
+FPU_round: /* Normal entry point */
+ movl PARAM4,%ecx
+
+FPU_round_sqrt: /* Entry point from wm_sqrt.S */
+
+#ifdef PARANOID
+/* Cannot use this here yet */
+/* orl %eax,%eax */
+/* jns L_entry_bugged */
+#endif PARANOID
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle xMake_denorm /* The number is a de-normal*/
+
+ movb $0,FPU_denormal /* 0 -> not a de-normal*/
+
+xDenorm_done:
+ movb $0,FPU_bits_lost /*No bits yet lost in rounding*/
+
+ movl %ecx,%esi
+ andl CW_PC,%ecx
+ cmpl PR_64_BITS,%ecx
+ je LRound_To_64
+
+ cmpl PR_53_BITS,%ecx
+ je LRound_To_53
+
+ cmpl PR_24_BITS,%ecx
+ je LRound_To_24
+
+#ifdef PARANOID
+ jmp L_bugged /* There is no bug, just a bad control word */
+#endif PARANOID
+
+
+/* Round etc to 24 bit precision */
+LRound_To_24:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_24
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_24
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_24
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_24
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_24 /* If negative then up==truncate */
+
+ jmp LCheck_24_round_up
+
+LDown_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_24 /* If positive then down==truncate */
+
+LCheck_24_round_up:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jnz LDo_24_round_up
+ jmp LRe_normalise
+
+LRound_nearest_24:
+ /* Do rounding of the 24th bit if needed (nearest or even) */
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ cmpl $0x00000080,%ecx
+ jc LCheck_truncate_24 /*less than half, no increment needed*/
+
+ jne LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Possibly half, we need to check the ls bits */
+ orl %ebx,%ebx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ orl %edx,%edx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 24th bit is 1 (round to even)*/
+ testl $0x00000100,%eax
+ jz LDo_truncate_24
+
+LGreater_Half_24: /*Rounding: increment at the 24th bit*/
+LDo_24_round_up:
+ andl $0xffffff00,%eax /*Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_UP,FPU_bits_lost
+ addl $0x00000100,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_24:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise /* No truncation needed*/
+
+LDo_truncate_24:
+ andl $0xffffff00,%eax /* Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_DOWN,FPU_bits_lost
+ jmp LRe_normalise
+
+
+/* Round etc to 53 bit precision */
+LRound_To_53:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_53
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_53
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_53
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_53
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_53 /* If negative then up==truncate*/
+
+ jmp LCheck_53_round_up
+
+LDown_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_53 /* If positive then down==truncate*/
+
+LCheck_53_round_up:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jnz LDo_53_round_up
+ jmp LRe_normalise
+
+LRound_nearest_53:
+ /*Do rounding of the 53rd bit if needed (nearest or even)*/
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ cmpl $0x00000400,%ecx
+ jc LCheck_truncate_53 /* less than half, no increment needed*/
+
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /*Possibly half, we need to check the ls bits*/
+ orl %edx,%edx
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 53rd bit is 1 (round to even)*/
+ testl $0x00000800,%ebx
+ jz LTruncate_53
+
+LGreater_Half_53: /*Rounding: increment at the 53rd bit*/
+LDo_53_round_up:
+ movb LOST_UP,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ addl $0x00000800,%ebx
+ adcl $0,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_53:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise
+
+LTruncate_53:
+ movb LOST_DOWN,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ jmp LRe_normalise
+
+
+/* Round etc to 64 bit precision*/
+LRound_To_64:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_64
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_64
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_64
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_64
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_64 /* If negative then up==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LDown_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_64 /*If positive then down==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LRound_nearest_64:
+ cmpl $0x80000000,%edx
+ jc LCheck_truncate_64
+
+ jne LDo_64_round_up
+
+ /* Now test for round-to-even */
+ testb $1,%ebx
+ jz LCheck_truncate_64
+
+LDo_64_round_up:
+ movb LOST_UP,FPU_bits_lost
+ addl $1,%ebx
+ adcl $0,%eax
+
+LCheck_Round_Overflow:
+ jnc LRe_normalise /* Rounding done, no overflow */
+
+ /* Overflow, adjust the result (to 1.0) */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ incl EXP(%edi)
+ jmp LRe_normalise
+
+LCheck_truncate_64:
+ orl %edx,%edx
+ jz LRe_normalise
+
+LTruncate_64:
+ movb LOST_DOWN,FPU_bits_lost
+
+LRe_normalise:
+ testb $0xff,FPU_denormal
+ jnz xNormalise_result
+
+xL_Normalised:
+ cmpb LOST_UP,FPU_bits_lost
+ je xL_precision_lost_up
+
+ cmpb LOST_DOWN,FPU_bits_lost
+ je xL_precision_lost_down
+
+xL_no_precision_loss:
+ cmpl EXP_OVER,EXP(%edi)
+ jge L_overflow
+
+ /* store the result */
+ movb TW_Valid,TAG(%edi)
+
+xL_Store_significand:
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+FPU_Arith_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* round-up.*/
+xL_precision_lost_up:
+ push %eax
+ call _set_precision_flag_up
+ popl %eax
+ jmp xL_no_precision_loss
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* truncation.*/
+xL_precision_lost_down:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+ jmp xL_no_precision_loss
+
+
+/* The number is a denormal (which might get rounded up to a normal)
+// Shift the number right the required number of bits, which will
+// have to be undone later...*/
+xMake_denorm:
+ /* The action to be taken depends upon whether the underflow
+ // exception is masked*/
+ testb CW_Underflow,%cl /* Underflow mask.*/
+ jz xUnmasked_underflow /* Do not make a denormal.*/
+
+ movb DENORMAL,FPU_denormal
+
+ pushl %ecx /* Save*/
+ movl EXP(%edi),%ecx
+ subl EXP_UNDER+1,%ecx
+ negl %ecx
+
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+// is for a small de-normalising shift.
+// Shift by [1..31] bits */
+ addl %ecx,EXP(%edi)
+ orl %edx,%edx /* extension*/
+ setne %ch
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orb %ch,%dl
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [32..63] bits*/
+xDenorm_shift_more_than_32:
+ addl %ecx,EXP(%edi)
+ subb $32,%cl
+ orl %edx,%edx
+ setne %ch
+ orb %ch,%bl
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %edx,%edx /*test these 32 bits*/
+ setne %cl
+ orb %ch,%bl
+ orb %cl,%bl
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [64..) bits*/
+xDenorm_shift_more_than_63:
+ cmpl $64,%ecx
+ jne xDenorm_shift_more_than_64
+
+/* Exactly 64 bit shift*/
+ addl %ecx,EXP(%edi)
+ xorl %ecx,%ecx
+ orl %edx,%edx
+ setne %cl
+ orl %ebx,%ebx
+ setne %ch
+ orb %ch,%cl
+ orb %cl,%al
+ movl %eax,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+xDenorm_shift_more_than_64:
+ movl EXP_UNDER+1,EXP(%edi)
+/* This is easy, %eax must be non-zero, so..*/
+ movl $1,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+
+xUnmasked_underflow:
+ /* Increase the exponent by the magic number*/
+ addl $(3*(1<<13)),EXP(%edi)
+ movb UNMASKED_UNDERFLOW,FPU_denormal
+ jmp xDenorm_done
+
+
+/* Undo the de-normalisation.*/
+xNormalise_result:
+ cmpb UNMASKED_UNDERFLOW,FPU_denormal
+ je xSignal_underflow
+
+/* The number must be a denormal if we got here.*/
+#ifdef PARANOID
+ /* But check it... just in case.*/
+ cmpl EXP_UNDER+1,EXP(%edi)
+ jne L_norm_bugged
+#endif PARANOID
+
+ orl %eax,%eax /* ms bits*/
+ jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/
+
+ orl %ebx,%ebx
+ jz L_underflow_to_zero /* The contents are zero*/
+
+/* Shift left 32 - 63 bits*/
+ movl %ebx,%eax
+ xorl %ebx,%ebx
+ subl $32,EXP(%edi)
+
+LNormalise_shift_up_to_31:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shl %cl,%ebx
+ subl %ecx,EXP(%edi)
+
+LNormalise_shift_done:
+ testb $0xff,FPU_bits_lost /* bits lost == underflow*/
+ jz xL_Normalised
+
+ /* There must be a masked underflow*/
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+/* The operations resulted in a number too small to represent.
+// Masked response.*/
+L_underflow_to_zero:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+
+ movb TW_Zero,TAG(%edi)
+ jmp xL_Store_significand
+
+
+/* The operations resulted in a number too large to represent.*/
+L_overflow:
+ push %edi
+ call _arith_overflow
+ pop %edi
+ jmp FPU_Arith_exit
+
+
+xSignal_underflow:
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_norm_bugged:
+ pushl EX_INTERNAL|0x216
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_entry_bugged:
+ pushl EX_INTERNAL|0x217
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+#endif PARANOID
diff --git a/sys/gnu/fpemul/reg_u_add.s b/sys/gnu/fpemul/reg_u_add.s
new file mode 100644
index 000000000000..35b5025643d7
--- /dev/null
+++ b/sys/gnu/fpemul/reg_u_add.s
@@ -0,0 +1,244 @@
+ .file "reg_u_add.S"
+/*
+ * reg_u_add.S
+ *
+ * Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the
+ * result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_u_add.s,v 1.3 1994/06/10 07:44:56 rich Exp $
+ *
+ */
+
+
+/*
+ | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their sum as a TW_Valid or TW_S f.p. number.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2,144
+.globl _reg_u_add
+_reg_u_add:
+ pushl %ebp
+ movl %esp,%ebp
+/* subl $16,%esp*/
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx*/
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+/* jnc L_arg1_larger*/
+ jge L_arg1_larger
+
+ /* num1 is smaller */
+ movl SIGL(%esi),%ebx
+ movl SIGH(%esi),%eax
+
+ movl %edi,%esi
+ negw %cx
+ jmp L_accum_loaded
+
+L_arg1_larger:
+ /* num1 has larger or equal exponent */
+ movl SIGL(%edi),%ebx
+ movl SIGH(%edi),%eax
+
+L_accum_loaded:
+ movl PARAM3,%edi /* destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+
+ xorl %edx,%edx /* clear the extension */
+
+#ifdef PARANOID
+ testl $0x80000000,%eax
+ je L_bugged
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged
+#endif PARANOID
+
+/* The number to be shifted is in %eax:%ebx:%edx*/
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpw $64,%cx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set*/
+
+ orl $1,%edx /* record the fact in the extension*/
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ movl $1,%edx /* The shifted nr always at least one '1'*/
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+ /* Now do the addition */
+ addl SIGL(%esi),%ebx
+ adcl SIGH(%esi),%eax
+ jnc L_round_the_result
+
+ /* Overflow, adjust the result */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ rcrl $1,%edx
+ jnc L_no_bit_lost
+
+ orl $1,%edx
+
+L_no_bit_lost:
+ incl EXP(%edi)
+
+L_round_the_result:
+ jmp FPU_round /* Round the result*/
+
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/fpemul/reg_u_div.s b/sys/gnu/fpemul/reg_u_div.s
new file mode 100644
index 000000000000..7f61b057fd78
--- /dev/null
+++ b/sys/gnu/fpemul/reg_u_div.s
@@ -0,0 +1,506 @@
+ .file "reg_u_div.S"
+/*
+ * reg_u_div.S
+ *
+ * Core division routines
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_u_div.s,v 1.3 1994/06/10 07:44:57 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Kernel for the division routines. |
+ | |
+ | void reg_u_div(FPU_REG *a, FPU_REG *a, |
+ | FPU_REG *dest, unsigned int control_word) |
+ | |
+ | Does not compute the destination exponent, but does adjust it. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+
+/* #define dSIGL(x) (x) */
+/* #define dSIGH(x) 4(x) */
+
+
+.data
+/*
+ Local storage:
+ Result: accum_3:accum_2:accum_1:accum_0
+ Overflow flag: ovfl_flag
+ */
+ .align 2,0
+accum_3:
+ .long 0
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+result_1:
+ .long 0
+result_2:
+ .long 0
+ovfl_flag:
+ .byte 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_div
+
+.globl _divide_kernel
+
+_reg_u_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ebx /* pointer to denom */
+ movl PARAM3,%edi /* pointer to answer */
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%ebx),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+_divide_kernel:
+#ifdef PARANOID
+/* testl $0x80000000, SIGH(%esi) *//* Dividend */
+/* je L_bugged */
+ testl $0x80000000, SIGH(%ebx) /* Divisor*/
+ je L_bugged
+#endif PARANOID
+
+/* Check if the divisor can be treated as having just 32 bits */
+ cmpl $0,SIGL(%ebx)
+ jnz L_Full_Division /* Can't do a quick divide */
+
+/* We should be able to zip through the division here */
+ movl SIGH(%ebx),%ecx /* The divisor */
+ movl SIGH(%esi),%edx /* Dividend */
+ movl SIGL(%esi),%eax /* Dividend */
+
+ cmpl %ecx,%edx
+ setaeb ovfl_flag /* Keep a record */
+ jb L_no_adjust
+
+ subl %ecx,%edx /* Prevent the overflow */
+
+L_no_adjust:
+ /* Divide the 64 bit number by the 32 bit denominator */
+ divl %ecx
+ movl %eax,result_2
+
+ /* Work on the remainder of the first division */
+ xorl %eax,%eax
+ divl %ecx
+ movl %eax,result_1
+
+ /* Work on the remainder of the 64 bit division */
+ xorl %eax,%eax
+ divl %ecx
+
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je L_no_overflow
+
+ /* Do the shifting here */
+ /* increase the exponent */
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* To set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+L_no_overflow:
+ jmp LRound_precision /* Do the rounding as required*/
+
+
+/*---------------------------------------------------------------------------+
+ | Divide: Return arg1/arg2 to arg3. |
+ | |
+ | This routine does not use the exponents of arg1 and arg2, but does |
+ | adjust the exponent of arg3. |
+ | |
+ | The maximum returned value is (ignoring exponents) |
+ | .ffffffff ffffffff |
+ | ------------------ = 1.ffffffff fffffffe |
+ | .80000000 00000000 |
+ | and the minimum is |
+ | .80000000 00000000 |
+ | ------------------ = .80000000 00000001 (rounded) |
+ | .ffffffff ffffffff |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+L_Full_Division:
+ /* Save extended dividend in local register*/
+ movl SIGL(%esi),%eax
+ movl %eax,accum_2
+ movl SIGH(%esi),%eax
+ movl %eax,accum_3
+ xorl %eax,%eax
+ movl %eax,accum_1 /* zero the extension */
+ movl %eax,accum_0 /* zero the extension */
+
+ movl SIGL(%esi),%eax /* Get the current num */
+ movl SIGH(%esi),%edx
+
+/*----------------------------------------------------------------------*/
+/* Initialization done */
+/* Do the first 32 bits */
+
+ movb $0,ovfl_flag
+ cmpl SIGH(%ebx),%edx /* Test for imminent overflow */
+ jb LLess_than_1
+ ja LGreater_than_1
+
+ cmpl SIGL(%ebx),%eax
+ jb LLess_than_1
+
+LGreater_than_1:
+/* The dividend is greater or equal, would cause overflow */
+ setaeb ovfl_flag /* Keep a record */
+
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx /* Prevent the overflow */
+ movl %eax,accum_2
+ movl %edx,accum_3
+
+LLess_than_1:
+/* At this point, we have a dividend < divisor, with a record of
+ adjustment in ovfl_flag */
+
+ /* We will divide by a number which is too large */
+ movl SIGH(%ebx),%ecx
+ addl $1,%ecx
+ jnc LFirst_div_not_1
+
+ /* here we need to divide by 100000000h,
+ i.e., no division at all.. */
+ mov %edx,%eax
+ jmp LFirst_div_done
+
+LFirst_div_not_1:
+ divl %ecx /* Divide the numerator by the augmented
+ denom ms dw */
+
+LFirst_div_done:
+ movl %eax,result_2 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_2 /* Subtract from the num local reg */
+ sbbl %edx,accum_3
+
+ movl result_2,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+ sbbl $0,accum_3
+ je LDo_2nd_32_bits /* Must check for non-zero result here */
+
+#ifdef PARANOID
+ jb L_bugged_1
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ incl result_2 /* Correct the answer */
+
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ sbbl $0,accum_3
+ jne L_bugged_1 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* Half of the main problem is done, there is just a reduced numerator
+ to handle now */
+/* Work with the second 32 bits, accum_0 not used from now on */
+LDo_2nd_32_bits:
+ movl accum_2,%edx /* get the reduced num */
+ movl accum_1,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx
+ jb LDo_2nd_div
+ ja LPrevent_2nd_overflow
+
+ cmpl SIGL(%ebx),%eax
+ jb LDo_2nd_div
+
+LPrevent_2nd_overflow:
+/* The numerator is greater or equal, would cause overflow */
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_2
+ movl %eax,accum_1
+
+ incl result_2 /* Reflect the subtraction in the answer */
+
+#ifdef PARANOID
+ je L_bugged_2 /* Can't bump the result to 1.0 */
+#endif PARANOID
+
+LDo_2nd_div:
+ cmpl $0,%ecx /* augmented denom msw*/
+ jnz LSecond_div_not_1
+
+ /* %ecx == 0, we are dividing by 1.0 */
+ mov %edx,%eax
+ jmp LSecond_div_done
+
+LSecond_div_not_1:
+ divl %ecx /* Divide the numerator by the denom ms dw */
+
+LSecond_div_done:
+ movl %eax,result_1 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ movl result_1,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1 /* Subtract from the num local reg */
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ jz LDo_3rd_32_bits
+
+#ifdef PARANOID
+ cmpl $1,accum_2
+ jne L_bugged_2
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+ jne L_bugged_2
+#endif PARANOID
+
+ addl $1,result_1 /* Correct the answer */
+ adcl $0,result_2
+
+#ifdef PARANOID
+ jc L_bugged_2 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* The division is essentially finished here, we just need to perform
+ tidying operations. */
+/* deal with the 3rd 32 bits */
+LDo_3rd_32_bits:
+ movl accum_1,%edx /* get the reduced num */
+ movl accum_0,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx /* denom*/
+ jb LRound_prep
+ ja LPrevent_3rd_overflow
+
+ cmpl SIGL(%ebx),%eax /* denom */
+ jb LRound_prep
+
+LPrevent_3rd_overflow:
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_1
+ movl %eax,accum_0
+
+ addl $1,result_1 /* Reflect the subtraction in the answer */
+ adcl $0,result_2
+ jne LRound_prep
+ jnc LRound_prep
+
+ /* This is a tricky spot, there is an overflow of the answer */
+ movb $255,ovfl_flag /* Overflow -> 1.000 */
+
+LRound_prep:
+/* Prepare for rounding.
+// To test for rounding, we just need to compare 2*accum with the
+// denom. */
+ movl accum_0,%ecx
+ movl accum_1,%edx
+ movl %ecx,%eax
+ orl %edx,%eax
+ jz LRound_ovfl /* The accumulator contains zero.*/
+
+ /* Multiply by 2 */
+ clc
+ rcll $1,%ecx
+ rcll $1,%edx
+ jc LRound_large /* No need to compare, denom smaller */
+
+ subl SIGL(%ebx),%ecx
+ sbbl SIGH(%ebx),%edx
+ jnc LRound_not_small
+
+ movl $0x70000000,%eax /* Denom was larger */
+ jmp LRound_ovfl
+
+LRound_not_small:
+ jnz LRound_large
+
+ movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
+ jmp LRound_ovfl
+
+LRound_large:
+ movl $0xff000000,%eax /* Denom was smaller */
+
+LRound_ovfl:
+/* We are now ready to deal with rounding, but first we must get
+ the bits properly aligned */
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je LRound_precision
+
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* Will set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+/* Round the result as required */
+LRound_precision:
+ decl EXP(%edi) /* binary point between 1st & 2nd bits */
+
+ movl %eax,%edx
+ movl result_1,%ebx
+ movl result_2,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+/* The logic is wrong if we got here */
+L_bugged:
+ pushl EX_INTERNAL|0x202
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_1:
+ pushl EX_INTERNAL|0x203
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x204
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ leave
+ ret
+#endif PARANOID
diff --git a/sys/gnu/fpemul/reg_u_mul.s b/sys/gnu/fpemul/reg_u_mul.s
new file mode 100644
index 000000000000..328d2b07da56
--- /dev/null
+++ b/sys/gnu/fpemul/reg_u_mul.s
@@ -0,0 +1,199 @@
+ .file "reg_u_mul.S"
+/*
+ * reg_u_mul.S
+ *
+ * Core multiplication routine
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_u_mul.s,v 1.3 1994/06/10 07:44:58 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Basic multiplication routine. |
+ | Does not check the resulting exponent for overflow/underflow |
+ | |
+ | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
+ | |
+ | Internal working is at approx 128 bits. |
+ | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+
+.data
+ .align 2,0
+accum_0:
+ .long 0
+accum_1:
+ .long 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_mul
+_reg_u_mul:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%edi
+
+#ifdef PARANOID
+ testl $0x80000000,SIGH(%esi)
+ jz L_bugged
+ testl $0x80000000,SIGH(%edi)
+ jz L_bugged
+#endif PARANOID
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%edi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+ xorl %ecx,%ecx
+ xorl %ebx,%ebx
+
+ movl SIGL(%esi),%eax
+ mull SIGL(%edi)
+ movl %eax,accum_0
+ movl %edx,accum_1
+
+ movl SIGL(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+/* adcl $0,%ecx *//* overflow here is not possible */
+
+ movl SIGH(%esi),%eax
+ mull SIGL(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+ adcl $0,%ecx
+
+ movl SIGH(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,%ebx
+ adcl %edx,%ecx
+
+ movl EXP(%esi),%eax /* Compute the exponent */
+ addl EXP(%edi),%eax
+ subl EXP_BIAS-1,%eax
+/* Have now finished with the sources */
+ movl PARAM3,%edi /* Point to the destination */
+ movl %eax,EXP(%edi)
+
+/* Now make sure that the result is normalized */
+ testl $0x80000000,%ecx
+ jnz LResult_Normalised
+
+ /* Normalize by shifting left one bit */
+ shll $1,accum_0
+ rcll $1,accum_1
+ rcll $1,%ebx
+ rcll $1,%ecx
+ decl EXP(%edi)
+
+LResult_Normalised:
+ movl accum_0,%eax
+ movl accum_1,%edx
+ orl %eax,%eax
+ jz L_extent_zero
+
+ orl $1,%edx
+
+L_extent_zero:
+ movl %ecx,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+L_bugged:
+ pushl EX_INTERNAL|0x205
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+#endif PARANOID
+
diff --git a/sys/gnu/fpemul/reg_u_sub.s b/sys/gnu/fpemul/reg_u_sub.s
new file mode 100644
index 000000000000..7d6d8961669e
--- /dev/null
+++ b/sys/gnu/fpemul/reg_u_sub.s
@@ -0,0 +1,361 @@
+ .file "reg_u_sub.S"
+/*
+ * reg_u_sub.S
+ *
+ * Core floating point subtraction routine.
+ *
+ * Call from C as:
+ * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: reg_u_sub.s,v 1.3 1994/06/10 07:44:59 rich Exp $
+ *
+ */
+
+/*
+ | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their difference as a TW_Valid or TW_Zero f.p.
+ | number.
+ | The first number (arg1) must be the larger.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2,144
+.globl _reg_u_sub
+_reg_u_sub:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx */
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+
+#ifdef PARANOID
+ /* source 2 is always smaller than source 1 */
+/* jc L_bugged */
+ js L_bugged_1
+
+ testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
+ je L_bugged_2
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged_2
+#endif PARANOID
+
+/*--------------------------------------+
+ | Form a register holding the |
+ | smaller number |
+ +--------------------------------------*/
+ movl SIGH(%edi),%eax /* register ms word */
+ movl SIGL(%edi),%ebx /* register ls word */
+
+ movl PARAM3,%edi /* destination */
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+ xorl %edx,%edx /* register extension */
+
+/*--------------------------------------+
+ | Shift the temporary register |
+ | right the required number of |
+ | places. |
+ +--------------------------------------*/
+L_shift_r:
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set */
+
+ orl $1,%edx /* record the fact in the extension */
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ /* Shift right by 64 bits */
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ jne L_more_than_65
+
+ /* Shift right by 65 bits */
+ /* Carry is clear if we get here */
+ movl %eax,%edx
+ rcrl %edx
+ jnc L_shift_65_nc
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_shift_65_nc:
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_65:
+ movl $1,%edx /* The shifted nr always at least one '1' */
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+L_subtr:
+/*------------------------------+
+ | Do the subtraction |
+ +------------------------------*/
+ xorl %ecx,%ecx
+ subl %edx,%ecx
+ movl %ecx,%edx
+ movl SIGL(%esi),%ecx
+ sbbl %ebx,%ecx
+ movl %ecx,%ebx
+ movl SIGH(%esi),%ecx
+ sbbl %eax,%ecx
+ movl %ecx,%eax
+
+#ifdef PARANOID
+ /* We can never get a borrow */
+ jc L_bugged
+#endif PARANOID
+
+/*--------------------------------------+
+ | Normalize the result |
+ +--------------------------------------*/
+ testl $0x80000000,%eax
+ jnz L_round /* no shifting needed */
+
+ orl %eax,%eax
+ jnz L_shift_1 /* shift left 1 - 31 bits */
+
+ orl %ebx,%ebx
+ jnz L_shift_32 /* shift left 32 - 63 bits */
+
+/* A rare case, the only one which is non-zero if we got here
+// is: 1000000 .... 0000
+// -0111111 .... 1111 1
+// --------------------
+// 0000000 .... 0000 1 */
+
+ cmpl $0x80000000,%edx
+ jnz L_must_be_zero
+
+ /* Shift left 64 bits */
+ subl $64,EXP(%edi)
+ movl %edx,%eax
+ jmp L_store
+
+L_must_be_zero:
+#ifdef PARANOID
+ orl %edx,%edx
+ jnz L_bugged_3
+#endif PARANOID
+
+ /* The result is zero */
+ movb TW_Zero,TAG(%edi)
+ movl $0,EXP(%edi) /* exponent */
+ movl $0,SIGL(%edi)
+ movl $0,SIGH(%edi)
+ jmp L_exit /* Does not underflow */
+
+L_shift_32:
+ movl %ebx,%eax
+ movl %edx,%ebx
+ movl $0,%edx
+ subl $32,EXP(%edi) /* Can get underflow here */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shld %cl,%edx,%ebx
+ shl %cl,%edx
+ subl %ecx,EXP(%edi) /* Can get underflow here */
+
+L_round:
+ jmp FPU_round /* Round the result */
+
+
+#ifdef PARANOID
+L_bugged_1:
+ pushl EX_INTERNAL|0x206
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x209
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_3:
+ pushl EX_INTERNAL|0x210
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_4:
+ pushl EX_INTERNAL|0x211
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged:
+ pushl EX_INTERNAL|0x212
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_store:
+/*------------------------------+
+ | Store the result |
+ +------------------------------*/
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+ movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_underflow:
+ push %edi
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
diff --git a/sys/gnu/fpemul/status_w.h b/sys/gnu/fpemul/status_w.h
new file mode 100644
index 000000000000..e54b36415c9d
--- /dev/null
+++ b/sys/gnu/fpemul/status_w.h
@@ -0,0 +1,106 @@
+/*
+ * status_w.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: status_w.h,v 1.3 1994/06/10 07:45:01 rich Exp $
+ *
+ */
+
+
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+
+#ifdef LOCORE
+#define Const__(x) $/**/x
+#else
+#define Const__(x) x
+#endif
+
+#define SW_Backward Const__(0x8000) /* backward compatibility */
+#define SW_C3 Const__(0x4000) /* condition bit 3 */
+#define SW_Top Const__(0x3800) /* top of stack */
+#define SW_Top_Shift Const__(11) /* shift for top of stack bits */
+#define SW_C2 Const__(0x0400) /* condition bit 2 */
+#define SW_C1 Const__(0x0200) /* condition bit 1 */
+#define SW_C0 Const__(0x0100) /* condition bit 0 */
+#define SW_Summary Const__(0x0080) /* exception summary */
+#define SW_Stack_Fault Const__(0x0040) /* stack fault */
+#define SW_Precision Const__(0x0020) /* loss of precision */
+#define SW_Underflow Const__(0x0010) /* underflow */
+#define SW_Overflow Const__(0x0008) /* overflow */
+#define SW_Zero_Div Const__(0x0004) /* divide by zero */
+#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
+#define SW_Invalid Const__(0x0001) /* invalid operation */
+
+#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
+
+#ifndef LOCORE
+
+#define COMP_A_gt_B 1
+#define COMP_A_eq_B 2
+#define COMP_A_lt_B 3
+#define COMP_No_Comp 4
+#define COMP_Denormal 0x20
+#define COMP_NaN 0x40
+#define COMP_SNaN 0x80
+
+#define setcc(cc) ({ \
+ status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
+ status_word |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); })
+
+#endif /* LOCORE */
+
+#endif /* _STATUS_H_ */
diff --git a/sys/gnu/fpemul/version.h b/sys/gnu/fpemul/version.h
new file mode 100644
index 000000000000..40c4513175a3
--- /dev/null
+++ b/sys/gnu/fpemul/version.h
@@ -0,0 +1,61 @@
+/*
+ * version.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: version.h,v 1.3 1994/06/10 07:45:02 rich Exp $
+ *
+ */
+
+#define FPU_VERSION "wm-FPU-emu version BETA 1.4"
diff --git a/sys/gnu/fpemul/wm_shrx.s b/sys/gnu/fpemul/wm_shrx.s
new file mode 100644
index 000000000000..2044a682141e
--- /dev/null
+++ b/sys/gnu/fpemul/wm_shrx.s
@@ -0,0 +1,261 @@
+ .file "wm_shrx.S"
+/*
+ * wm_shrx.S
+ *
+ * 64 bit right shift functions
+ *
+ * Call from C as:
+ * unsigned shrx(void *arg1, unsigned arg2)
+ * and
+ * unsigned shrxs(void *arg1, unsigned arg2)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: wm_shrx.s,v 1.3 1994/06/10 07:45:03 rich Exp $
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrx(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+ .globl _shrx
+
+_shrx:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ pushl %ebx
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_63:
+ cmpl $96,%ecx
+ jnc L_more_than_95
+
+ subb $64,%cl
+ movl 4(%esi),%eax /* msl */
+ shr %cl,%eax
+ xorl %edx,%edx
+ movl %edx,(%esi)
+ movl %edx,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_95:
+ xorl %eax,%eax
+ movl %eax,(%esi)
+ movl %eax,4(%esi)
+ popl %esi
+ leave
+ ret
+
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrxs(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function (optimized for small floating point |
+ | integers). |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | The lower 8 bits of eax are lost and replaced by a flag which is |
+ | set (to 0x01) if any bit, apart from the first one, is set in the |
+ | part which has been shifted out of the arg. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+ .globl _shrxs
+_shrxs:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %ebx
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc Ls_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jc Ls_less_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+ is for small integers */
+/* Shift by [32..63] bits */
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %ebx,%ebx
+ shrd %cl,%eax,%ebx
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ orl %ebx,%ebx /* test these 32 bits */
+ setne %bl
+ test $0x7fffffff,%eax /* and 31 bits here */
+ setne %bh
+ orw %bx,%bx /* Any of the 63 bit set ? */
+ setne %al
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [0..31] bits */
+Ls_less_than_32:
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %al
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [64..95] bits */
+Ls_more_than_63:
+ cmpl $96,%ecx
+ jnc Ls_more_than_95
+
+ subb $64,%cl
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%eax /* msl */
+ xorl %edx,%edx /* extension */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %ebx,%edx
+ setne %bl
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %bh
+ orw %bx,%bx
+ setne %al
+ xorl %edx,%edx
+ movl %edx,(%esi) /* set to zero */
+ movl %edx,4(%esi) /* set to zero */
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+Ls_more_than_95:
+/* Shift by [96..inf) bits */
+ xorl %eax,%eax
+ movl (%esi),%ebx
+ orl 4(%esi),%ebx
+ setne %al
+ xorl %ebx,%ebx
+ movl %ebx,(%esi)
+ movl %ebx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/fpemul/wm_sqrt.s b/sys/gnu/fpemul/wm_sqrt.s
new file mode 100644
index 000000000000..cbe0451f5f46
--- /dev/null
+++ b/sys/gnu/fpemul/wm_sqrt.s
@@ -0,0 +1,496 @@
+ .file "wm_sqrt.S"
+/*
+ * wm_sqrt.S
+ *
+ * Fixed point arithmetic square root evaluation.
+ *
+ * Call from C as:
+ * void wm_sqrt(FPU_REG *n, unsigned int control_word)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * 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 include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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
+ * W. METZENTHEN 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.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $Id: wm_sqrt.s,v 1.3 1994/06/10 07:45:04 rich Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | returns the square root of n in n. |
+ | |
+ | Use Newton's method to compute the square root of a number, which must |
+ | be in the range [1.0 .. 4.0), to 64 bits accuracy. |
+ | Does not check the sign or tag of the argument. |
+ | Sets the exponent, but not the sign or tag of the result. |
+ | |
+ | The guess is kept in %esi:%edi |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+
+
+.data
+/*
+ Local storage:
+ */
+ .align 4,0
+accum_3:
+ .long 0 /* ms word */
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+
+/* The de-normalised argument:
+// sq_2 sq_1 sq_0
+// b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+// ^ binary point here */
+fsqrt_arg_2:
+ .long 0 /* ms word */
+fsqrt_arg_1:
+ .long 0
+fsqrt_arg_0:
+ .long 0 /* ls word, at most the ms bit is set */
+
+.text
+ .align 2,144
+
+.globl _wm_sqrt
+
+_wm_sqrt:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+
+ movl SIGH(%esi),%eax
+ movl SIGL(%esi),%ecx
+ xorl %edx,%edx
+
+/* We use a rough linear estimate for the first guess.. */
+
+ cmpl EXP_BIAS,EXP(%esi)
+ jnz sqrt_arg_ge_2
+
+ shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
+ rcrl $1,%ecx
+ rcrl $1,%edx
+
+sqrt_arg_ge_2:
+/* From here on, n is never accessed directly again until it is
+// replaced by the answer. */
+
+ movl %eax,fsqrt_arg_2 /* ms word of n */
+ movl %ecx,fsqrt_arg_1
+ movl %edx,fsqrt_arg_0
+
+/* Make a linear first estimate */
+ shrl $1,%eax
+ addl $0x40000000,%eax
+ movl $0xaaaaaaaa,%ecx
+ mull %ecx
+ shll %edx /* max result was 7fff... */
+ testl $0x80000000,%edx /* but min was 3fff... */
+ jnz sqrt_prelim_no_adjust
+
+ movl $0x80000000,%edx /* round up */
+
+sqrt_prelim_no_adjust:
+ movl %edx,%esi /* Our first guess */
+
+/* We have now computed (approx) (2 + x) / 3, which forms the basis
+ for a few iterations of Newton's method */
+
+ movl fsqrt_arg_2,%ecx /* ms word */
+
+/* From our initial estimate, three iterations are enough to get us
+// to 30 bits or so. This will then allow two iterations at better
+// precision to complete the process.
+
+// Compute (g + n/g)/2 at each iteration (g is the guess). */
+ shrl %ecx /* Doing this first will prevent a divide */
+ /* overflow later. */
+
+ movl %ecx,%edx /* msw of the arg / 2 */
+ divl %esi /* current estimate */
+ shrl %esi /* divide by 2 */
+ addl %eax,%esi /* the new estimate */
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+/* Now that an estimate accurate to about 30 bits has been obtained (in %esi),
+// we improve it to 60 bits or so.
+
+// The strategy from now on is to compute new estimates from
+// guess := guess + (n - guess^2) / (2 * guess) */
+
+/* First, find the square of the guess */
+ movl %esi,%eax
+ mull %esi
+/* guess^2 now in %edx:%eax */
+
+ movl fsqrt_arg_1,%ecx
+ subl %ecx,%eax
+ movl fsqrt_arg_2,%ecx /* ms word of normalized n */
+ sbbl %ecx,%edx
+ jnc sqrt_stage_2_positive
+/* subtraction gives a negative result
+// negate the result before division */
+ notl %edx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%edx
+
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+ jmp sqrt_stage_2_finish
+
+sqrt_stage_2_positive:
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ notl %ecx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%ecx
+
+sqrt_stage_2_finish:
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* Form the new estimate in %esi:%edi */
+ movl %eax,%edi
+ addl %ecx,%esi
+
+ jnz sqrt_stage_2_done /* result should be [1..2) */
+
+#ifdef PARANOID
+/* It should be possible to get here only if the arg is ffff....ffff*/
+ cmp $0xffffffff,fsqrt_arg_1
+ jnz sqrt_stage_2_error
+#endif PARANOID
+
+/* The best rounded result.*/
+ xorl %eax,%eax
+ decl %eax
+ movl %eax,%edi
+ movl %eax,%esi
+ movl $0x7fffffff,%eax
+ jmp sqrt_round_result
+
+#ifdef PARANOID
+sqrt_stage_2_error:
+ pushl EX_INTERNAL|0x213
+ call EXCEPTION
+#endif PARANOID
+
+sqrt_stage_2_done:
+
+/* Now the square root has been computed to better than 60 bits */
+
+/* Find the square of the guess*/
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,accum_1
+
+ movl %esi,%eax
+ mull %esi
+ movl %edx,accum_3
+ movl %eax,accum_2
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* movl %esi,%eax*/
+/* mull %edi*/
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* guess^2 now in accum_3:accum_2:accum_1*/
+
+ movl fsqrt_arg_0,%eax /* get normalized n*/
+ subl %eax,accum_1
+ movl fsqrt_arg_1,%eax
+ sbbl %eax,accum_2
+ movl fsqrt_arg_2,%eax /* ms word of normalized n*/
+ sbbl %eax,accum_3
+ jnc sqrt_stage_3_positive
+
+/* subtraction gives a negative result*/
+/* negate the result before division */
+ notl accum_1
+ notl accum_2
+ notl accum_3
+ addl $1,accum_1
+ adcl $0,accum_2
+
+#ifdef PARANOID
+ adcl $0,accum_3 /* This must be zero */
+ jz sqrt_stage_3_no_error
+
+sqrt_stage_3_error:
+ pushl EX_INTERNAL|0x207
+ call EXCEPTION
+
+sqrt_stage_3_no_error:
+#endif PARANOID
+
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx / divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+ jmp sqrt_stage_3_finished
+
+sqrt_stage_3_positive:
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx /* divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ notl %eax /* Negate the correction term*/
+ notl %ecx
+ addl $1,%eax
+ adcl $0,%ecx /* carry here ==> correction == 0*/
+ adcl $0xffffffff,%esi
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+sqrt_stage_3_finished:
+
+/* The result in %esi:%edi:%esi should be good to about 90 bits here,
+// and the rounding information here does not have sufficient accuracy
+// in a few rare cases. */
+ cmpl $0xffffffe0,%eax
+ ja sqrt_near_exact_x
+
+ cmpl $0x00000020,%eax
+ jb sqrt_near_exact
+
+ cmpl $0x7fffffe0,%eax
+ jb sqrt_round_result
+
+ cmpl $0x80000020,%eax
+ jb sqrt_get_more_precision
+
+sqrt_round_result:
+/* Set up for rounding operations*/
+ movl %eax,%edx
+ movl %esi,%eax
+ movl %edi,%ebx
+ movl PARAM1,%edi
+ movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0)*/
+ movl PARAM2,%ecx
+ jmp FPU_round_sqrt
+
+
+sqrt_near_exact_x:
+/* First, the estimate must be rounded up.*/
+ addl $1,%edi
+ adcl $0,%esi
+
+sqrt_near_exact:
+/* This is an easy case because x^1/2 is monotonic.
+// We need just find the square of our estimate, compare it
+// with the argument, and deduce whether our estimate is
+// above, below, or exact. We use the fact that the estimate
+// is known to be accurate to about 90 bits. */
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+#ifdef PARANOID
+ cmp $0xffffffb0,%ebx
+ jb sqrt_near_exact_ok
+
+ cmp $0x00000050,%ebx
+ ja sqrt_near_exact_ok
+
+ pushl EX_INTERNAL|0x214
+ call EXCEPTION
+
+sqrt_near_exact_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_near_exact_small
+
+ jnz sqrt_near_exact_large
+
+ or %ebx,%edx
+ jnz sqrt_near_exact_large
+
+/* Our estimate is exactly the right answer*/
+ xorl %eax,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_small:
+/* Our estimate is too small*/
+ movl $0x000000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_large:
+/* Our estimate is too large, we need to decrement it*/
+ subl $1,%edi
+ sbbl $0,%esi
+ movl $0xffffff00,%eax
+ jmp sqrt_round_result
+
+
+sqrt_get_more_precision:
+/* This case is almost the same as the above, except we start*/
+/* with an extra bit of precision in the estimate.*/
+ stc /* The extra bit.*/
+ rcll $1,%edi /* Shift the estimate left one bit*/
+ rcll $1,%esi
+
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+/* Put our estimate back to its original value*/
+ stc /* The ms bit.*/
+ rcrl $1,%esi /* Shift the estimate left one bit*/
+ rcrl $1,%edi
+
+#ifdef PARANOID
+ cmp $0xffffff60,%ebx
+ jb sqrt_more_prec_ok
+
+ cmp $0x000000a0,%ebx
+ ja sqrt_more_prec_ok
+
+ pushl EX_INTERNAL|0x215
+ call EXCEPTION
+
+sqrt_more_prec_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_more_prec_small
+
+ jnz sqrt_more_prec_large
+
+ or %ebx,%ecx
+ jnz sqrt_more_prec_large
+
+/* Our estimate is exactly the right answer*/
+ movl $0x80000000,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_small:
+/* Our estimate is too small*/
+ movl $0x800000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_large:
+/* Our estimate is too large*/
+ movl $0x7fffff00,%eax
+ jmp sqrt_round_result
diff --git a/sys/i386/boot/Makefile b/sys/i386/boot/Makefile
index 3f402426ee49..3c7418f7ddda 100644
--- a/sys/i386/boot/Makefile
+++ b/sys/i386/boot/Makefile
@@ -20,7 +20,7 @@
# the rights to redistribute these changes.
#
# from: Mach, Revision 2.2 92/04/04 11:33:46 rpd
-# $Id: Makefile,v 1.5 1993/12/11 20:35:15 ats Exp $
+# $Id: Makefile,v 1.10 1994/06/20 04:32:40 jkh Exp $
#
wd0:
@@ -32,7 +32,10 @@ wd0:
NOPROG= noprog
NOMAN= noman
-CFLAGS = -O -DDO_BAD144 -I${.CURDIR}
+# tunable loopcount parameter, waiting for keypress
+BOOTWAIT?= 2400
+
+CFLAGS = -O2 -DDO_BAD144 -DBOOTWAIT=${BOOTWAIT} -I${.CURDIR}
LIBS= -lc
INC= -I${.CURDIR}/../..
@@ -61,31 +64,31 @@ biosboot: boot
bootbios: boot
dd if=boot of=bootbios skip=1
-/usr/mdec/bootsd: bootbios
- cp bootbios /usr/mdec/bootsd
+${DESTDIR}/usr/mdec/bootsd: bootbios
+ cp bootbios ${DESTDIR}/usr/mdec/bootsd
-/usr/mdec/sdboot: biosboot
- cp biosboot /usr/mdec/sdboot
+${DESTDIR}/usr/mdec/sdboot: biosboot
+ cp biosboot ${DESTDIR}/usr/mdec/sdboot
-/usr/mdec/bootwd: /usr/mdec/bootsd
- rm -f /usr/mdec/bootwd
- ln /usr/mdec/bootsd /usr/mdec/bootwd
+${DESTDIR}/usr/mdec/bootwd: ${DESTDIR}/usr/mdec/bootsd
+ rm -f ${DESTDIR}/usr/mdec/bootwd
+ ln ${DESTDIR}/usr/mdec/bootsd ${DESTDIR}/usr/mdec/bootwd
-/usr/mdec/wdboot: /usr/mdec/sdboot
- rm -f /usr/mdec/wdboot
- ln /usr/mdec/sdboot /usr/mdec/wdboot
+${DESTDIR}/usr/mdec/wdboot: ${DESTDIR}/usr/mdec/sdboot
+ rm -f ${DESTDIR}/usr/mdec/wdboot
+ ln ${DESTDIR}/usr/mdec/sdboot ${DESTDIR}/usr/mdec/wdboot
-/usr/mdec/bootfd: /usr/mdec/bootsd
- rm -f /usr/mdec/bootfd
- ln /usr/mdec/bootsd /usr/mdec/bootfd
+${DESTDIR}/usr/mdec/bootfd: ${DESTDIR}/usr/mdec/bootsd
+ rm -f ${DESTDIR}/usr/mdec/bootfd
+ ln ${DESTDIR}/usr/mdec/bootsd ${DESTDIR}/usr/mdec/bootfd
-/usr/mdec/fdboot: /usr/mdec/sdboot
- rm -f /usr/mdec/fdboot
- ln /usr/mdec/sdboot /usr/mdec/fdboot
+${DESTDIR}/usr/mdec/fdboot: ${DESTDIR}/usr/mdec/sdboot
+ rm -f ${DESTDIR}/usr/mdec/fdboot
+ ln ${DESTDIR}/usr/mdec/sdboot ${DESTDIR}/usr/mdec/fdboot
-sd: /usr/mdec/bootsd /usr/mdec/sdboot
-wd: /usr/mdec/bootwd /usr/mdec/wdboot
-fd: /usr/mdec/bootfd /usr/mdec/fdboot
+sd: ${DESTDIR}/usr/mdec/bootsd ${DESTDIR}/usr/mdec/sdboot
+wd: ${DESTDIR}/usr/mdec/bootwd ${DESTDIR}/usr/mdec/wdboot
+fd: ${DESTDIR}/usr/mdec/bootfd ${DESTDIR}/usr/mdec/fdboot
all: biosboot bootbios
diff --git a/sys/i386/boot/biosboot b/sys/i386/boot/biosboot
new file mode 100644
index 000000000000..9c572c5d2422
--- /dev/null
+++ b/sys/i386/boot/biosboot
Binary files differ
diff --git a/sys/i386/boot/boot b/sys/i386/boot/boot
new file mode 100644
index 000000000000..bba109001d81
--- /dev/null
+++ b/sys/i386/boot/boot
Binary files differ
diff --git a/sys/i386/boot/boot.c b/sys/i386/boot/boot.c
index 19de113b0c51..ad3c7b2ee258 100644
--- a/sys/i386/boot/boot.c
+++ b/sys/i386/boot/boot.c
@@ -24,7 +24,7 @@
* the rights to redistribute these changes.
*
* from: Mach, [92/04/03 16:51:14 rvb]
- * $Id: boot.c,v 1.9.2.1 1994/05/01 05:14:49 rgrimes Exp $
+ * $Id: boot.c,v 1.14 1994/06/16 03:53:27 adam Exp $
*/
@@ -60,8 +60,7 @@ struct exec head;
int argv[10], esym;
char *name;
char *names[] = {
- "/386bsd", "/o386bsd", "/386bsd.old",
- "/vmunix", "/ovmunix", "/vmunix.old"
+ "/386bsd", "/o386bsd", "/386bsd.old"
};
#define NUMNAMES (sizeof(names)/sizeof(char *))
@@ -76,7 +75,7 @@ int drive;
ouraddr,
argv[7] = memsize(0),
argv[8] = memsize(1),
- "$Revision: 1.9.2.1 $");
+ "$Revision: 1.14 $");
printf("use hd(1,a)/386bsd to boot sd0 when wd0 is also installed\n");
gateA20();
loadstart:
@@ -138,13 +137,12 @@ loadprog(howto)
{
if((addr + head.a_text + head.a_data) > ouraddr)
{
- printf("kernel will not fit below loader\n");
+ printf("kernel overlaps loader\n");
return;
}
if((addr + head.a_text + head.a_data + head.a_bss) > 0xa0000)
{
- printf("kernel too big, won't fit in 640K with bss\n");
- printf("Only hope is to link the kernel for > 1MB\n");
+ printf("bss exceeds 640k limit\n");
return;
}
}
diff --git a/sys/i386/boot/boot.sym b/sys/i386/boot/boot.sym
new file mode 100755
index 000000000000..8249abc812dc
--- /dev/null
+++ b/sys/i386/boot/boot.sym
Binary files differ
diff --git a/sys/i386/boot/boot2.S b/sys/i386/boot/boot2.S
index 9270d4de0f3c..c49bde8d377e 100644
--- a/sys/i386/boot/boot2.S
+++ b/sys/i386/boot/boot2.S
@@ -24,7 +24,7 @@
* the rights to redistribute these changes.
*
* from: Mach, Revision 2.2 92/04/04 11:35:26 rpd
- * $Id: boot2.S,v 1.3 1993/11/13 04:43:25 rgrimes Exp $
+ * $Id: boot2.S,v 1.4 1994/06/22 05:52:25 jkh Exp $
*/
#include "asm.h"
@@ -128,14 +128,22 @@ ENTRY(boot2)
mov %ax, %es
/* fix up IDT entries for bdb */
- subl $2, %ebx
+ data32
+ subl $2, %ebx /* calculate EA to check it */
+ jb 1f /* give up if it would trap */
+ addr32
movl %es: (%ebx), %eax /* actually movw to %ax */
addr32
movl %eax, EXT(Idt)+8*DEBUG_VECTOR /* actually movw %ax */
+1:
+ data32
subl $2, %ecx
+ jb 1f
+ addr32
movl %es: (%ecx), %eax /* actually movw to %ax */
addr32
movl %eax, EXT(Idt)+8*BREAKPOINT_VECTOR /* actually movw %ax */
+1:
/* finished with groping in real mode segments */
pop %es
diff --git a/sys/i386/boot/bootbios b/sys/i386/boot/bootbios
new file mode 100644
index 000000000000..a0ed09db1e0c
--- /dev/null
+++ b/sys/i386/boot/bootbios
Binary files differ
diff --git a/sys/i386/boot/disk.c b/sys/i386/boot/disk.c
index 1c7712f10517..8db41bbb6f4b 100644
--- a/sys/i386/boot/disk.c
+++ b/sys/i386/boot/disk.c
@@ -24,7 +24,17 @@
* the rights to redistribute these changes.
*
* from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
- * $Id: disk.c,v 1.4 1994/02/22 22:59:40 rgrimes Exp $
+ * $Id: disk.c,v 1.5 1994/05/16 03:06:00 ache Exp $
+ */
+
+/*
+ * 93/10/08 bde
+ * If there is no 386BSD partition, initialize the label sector with
+ * LABELSECTOR instead of with garbage.
+ *
+ * 93/08/22 bde
+ * Fixed reading of bad sector table. It is at the end of the 'c'
+ * partition, which is not always at the end of the disk.
*/
#include "boot.h"
@@ -80,10 +90,12 @@ devopen()
#else EMBEDDED_DISKLABEL
Bread(dosdev, 0);
dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF);
+ sector = LABELSECTOR;
for (i = 0; i < NDOSPART; i++, dptr++)
- if (dptr->dp_typ == DOSPTYP_386BSD)
+ if (dptr->dp_typ == DOSPTYP_386BSD) {
+ sector = dptr->dp_start + LABELSECTOR;
break;
- sector = dptr->dp_start + LABELSECTOR;
+ }
Bread(dosdev, sector++);
dl=((struct disklabel *)0);
disklabel = *dl; /* structure copy (maybe useful later)*/
@@ -113,10 +125,20 @@ devopen()
int dkbbnum;
struct dkbad *dkbptr;
- /* find the first readable bad144 sector */
- /* some of this code is copied from ufs/disk_subr.c */
+ /* find the first readable bad sector table */
+ /* some of this code is copied from ufs/ufs_disksubr.c */
+ /* including the bugs :-( */
/* read a bad sector table */
- dkbbnum = dl->d_secperunit - dl->d_nsectors;
+
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ dkbbnum = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ dkbbnum = dl->d_secperunit;
+ dkbbnum -= dl->d_nsectors;
+
if (dl->d_secsize > DEV_BSIZE)
dkbbnum *= dl->d_secsize / DEV_BSIZE;
else
@@ -138,9 +160,9 @@ devopen()
i += 2;
} while (i < 10 && i < dl->d_nsectors);
if (!do_bad144)
- printf("Bad badsect table\n");
+ printf("Bad bad sector table\n");
else
- printf("Using bad144 bad sector at %d\n", dkbbnum+i);
+ printf("Using bad sector table at %d\n", dkbbnum+i);
}
#endif DO_BAD144
}
@@ -245,7 +267,12 @@ badsect(dosdev, sector)
goto no_remap;
}
/* otherwise find replacement sector */
- newsec = dl->d_secperunit - dl->d_nsectors - i -1;
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ newsec = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ newsec = dl->d_secperunit;
+ newsec -= dl->d_nsectors + i + 1;
return newsec;
}
#endif DO_BAD144
diff --git a/sys/i386/boot/io.c b/sys/i386/boot/io.c
index 7cb6d02ba93a..29fd128c9ce7 100644
--- a/sys/i386/boot/io.c
+++ b/sys/i386/boot/io.c
@@ -1,3 +1,4 @@
+
/*
* Mach Operating System
* Copyright (c) 1992, 1991 Carnegie Mellon University
@@ -24,7 +25,7 @@
* the rights to redistribute these changes.
*
* from: Mach, Revision 2.2 92/04/04 11:35:57 rpd
- * $Id: io.c,v 1.3 1993/10/16 19:11:36 rgrimes Exp $
+ * $Id: io.c,v 1.6 1994/06/16 03:53:29 adam Exp $
*/
#include <i386/include/pio.h>
@@ -38,10 +39,10 @@
#define KC_CMD_WIN 0xd0 /* read output port */
#define KC_CMD_WOUT 0xd1 /* write output port */
-#define KB_A20 0x9f /* enable A20,
+#define KB_A20 0xdf /* enable A20,
enable output buffer full interrupt
enable data line
- disable clock line */
+ enable clock line */
/*
* Gate A20 for high memory
@@ -137,13 +138,24 @@ getchar()
return(c);
}
+#if BOOTWAIT
+spinwait(i)
+int i;
+{
+ while (--i >= 0)
+ (void)inb(0x84);
+}
+#endif
+
gets(buf)
char *buf;
{
int i;
char *ptr=buf;
- for (i = 240000; i>0; i--)
+#if BOOTWAIT
+ for (i = BOOTWAIT; i>0; spinwait(10000),i--)
+#endif
if (ischar())
for (;;)
switch(*ptr = getchar() & 0xff) {
diff --git a/sys/i386/boot/start.S b/sys/i386/boot/start.S
index bdf387667780..44de86eb89f4 100644
--- a/sys/i386/boot/start.S
+++ b/sys/i386/boot/start.S
@@ -24,7 +24,7 @@
* the rights to redistribute these changes.
*
* from: Mach, Revision 2.2 92/04/04 11:36:29 rpd
- * $Id: start.S,v 1.2 1993/10/16 19:11:38 rgrimes Exp $
+ * $Id: start.S,v 1.3 1994/06/13 19:27:52 jkh Exp $
*/
/*
@@ -99,6 +99,7 @@ start:
jae hd
fd:
+ mov $0x0, %dl
# reset the disk system
#ifdef DEBUG
data32
diff --git a/sys/i386/conf/ECLIPSE b/sys/i386/conf/ECLIPSE
new file mode 100644
index 000000000000..31eede546035
--- /dev/null
+++ b/sys/i386/conf/ECLIPSE
@@ -0,0 +1,66 @@
+#
+# GENERICAH -- Generic machine with WD/AHx family disks
+#
+# $Id: GENERICAH,v 1.36 1994/06/17 06:56:59 sean Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident ECLIPSE
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+options "NCONS=4" #4 virtual consoles
+
+config "386bsd" root on sd0 swap on sd0 dumps on sd0
+
+controller isa0
+
+device pci0 at isa? bio irq 9 vector pciintr
+device ncr0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+controller scbus0
+
+device sd0
+device sd1
+
+device st0
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+
+device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 1
+pseudo-device ppp 1
+pseudo-device pty 32
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/GENERICAH b/sys/i386/conf/GENERICAH
index 4bba699be512..2c10cd45daa1 100644
--- a/sys/i386/conf/GENERICAH
+++ b/sys/i386/conf/GENERICAH
@@ -1,12 +1,13 @@
#
# GENERICAH -- Generic machine with WD/AHx family disks
#
-# $Id: GENERICAH,v 1.25.2.2 1994/04/12 16:37:30 csgr Exp $
+# $Id: GENERICAH,v 1.36 1994/06/17 06:56:59 sean Exp $
#
machine "i386"
cpu "I386_CPU"
cpu "I486_CPU"
+cpu "I586_CPU"
ident GENERICAH
timezone 8 dst
maxusers 10
@@ -22,14 +23,17 @@ options XSERVER #Xserver
options UCONSOLE #X Console support
options "FAT_CURSOR" #block cursor in syscons or pccons
#options GATEWAY #Host is a Gateway (forwards packets)
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+options "NCONS=4" #4 virtual consoles
-config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+config "386bsd" root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0
controller isa0
controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
disk fd0 at fdc0 drive 0
disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
@@ -41,6 +45,7 @@ disk wd3 at wdc1 drive 1
controller ahb0 at isa? bio irq 11 vector ahbintr
controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+controller sea0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector seaintr
controller scbus0
device sd0
@@ -57,7 +62,7 @@ device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
device mcd1 at isa? port 0x340 bio irq 11 vector mcdintr
-device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
@@ -78,7 +83,7 @@ pseudo-device loop
pseudo-device ether
pseudo-device log
pseudo-device sl 2
-pseudo-device pty 12
+pseudo-device pty 16
pseudo-device speaker
pseudo-device swappager
diff --git a/sys/i386/conf/GENERICBT b/sys/i386/conf/GENERICBT
index 5311d76f7388..fae078940fa7 100644
--- a/sys/i386/conf/GENERICBT
+++ b/sys/i386/conf/GENERICBT
@@ -1,12 +1,13 @@
#
# GENERICBT -- Generic machine with WD/BTx family disks
#
-# $Id: GENERICBT,v 1.25.2.2 1994/04/12 16:37:32 csgr Exp $
+# $Id: GENERICBT,v 1.35 1994/06/08 00:30:32 phk Exp $
#
machine "i386"
cpu "I386_CPU"
cpu "I486_CPU"
+cpu "I586_CPU"
ident GENERICBT
timezone 8 dst
maxusers 10
@@ -22,14 +23,17 @@ options XSERVER #Xserver
options UCONSOLE #X Console support
options "FAT_CURSOR" #block cursor in syscons or pccons
#options GATEWAY #Host is a Gateway (forwards packets)
+options "NCONS=4" #4 virtual consoles
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
-config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+config "386bsd" root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0
controller isa0
controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
disk fd0 at fdc0 drive 0
disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
@@ -57,7 +61,7 @@ device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
device mcd1 at isa? port 0x340 bio irq 11 vector mcdintr
-device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
@@ -78,7 +82,7 @@ pseudo-device loop
pseudo-device ether
pseudo-device log
pseudo-device sl 2
-pseudo-device pty 12
+pseudo-device pty 16
pseudo-device speaker
pseudo-device swappager
diff --git a/sys/i386/conf/HAMSTER b/sys/i386/conf/HAMSTER
new file mode 100644
index 000000000000..a3da520cd05e
--- /dev/null
+++ b/sys/i386/conf/HAMSTER
@@ -0,0 +1,67 @@
+#
+# GENERICAH -- Generic machine with WD/AHx family disks
+#
+# $Id: GENERICAH,v 1.36 1994/06/17 06:56:59 sean Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident GENERICAH
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+#options GATEWAY #Host is a Gateway (forwards packets)
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+options "NCONS=8" #4 virtual consoles
+
+config "386bsd" root on sd0 swap on sd0 dumps on sd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+controller scbus0
+
+device sd0
+device sd1
+device sd2
+device sd3
+
+device st0
+device st1
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+
+device ix0 at isa? port 0x300 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 32
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/LAPTOP b/sys/i386/conf/LAPTOP
new file mode 100644
index 000000000000..4c7ce3b2fbd7
--- /dev/null
+++ b/sys/i386/conf/LAPTOP
@@ -0,0 +1,68 @@
+#
+# LAPTOP -- Minimal machine with IDE drives.
+#
+# $Id: LAPTOP,v 1.3 1994/06/22 05:58:53 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident LAPTOP
+timezone 8 dst
+maxusers 8
+maxfdescs 256 #Max file descriptors per process
+options INET #InterNETworking
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+options "NCONS=8" #8 virtual consoles
+options LAPTOP
+
+# Do not use in binary distributions; put here because most laptops lack 387
+# support, and LAPTOP is not one of the kernels we build by default.
+options GPL_MATH_EMULATE #Support for x87 emualtion via GPL'd emu
+
+# Most laptops have PS/2 style trackball mice.
+options ALLOW_CONFLICT_IOADDR #no IO addr conflict checks (PS/2 mice)
+
+config "386bsd" root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device lpt0 at isa? port? tty irq 7 vector lptintr
+device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+
+# IBM/National PCMCIA ethernet cards
+device ze0 at isa? port 0x300 net irq 5 iomem 0xd8000 vector zeintr
+
+# The digital speaker driver (/dev/pcaudio). Might as well since we almost
+# certainly won't have a sound card!
+device pca0 at isa? tty
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 1
+pseudo-device ppp 1
+pseudo-device pty 16
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 129d2c5d6ea0..9235212a9920 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -4,38 +4,40 @@
#
# This kernel is NOT MEANT to be runnable!
#
-# $Id: LINT,v 1.53 1994/02/09 05:35:57 nate Exp $
+# $Id: LINT,v 1.79 1994/06/16 05:31:16 jkh Exp $
#
machine "i386"
cpu "I386_CPU"
cpu "I486_CPU"
+cpu "I586_CPU"
ident LINT
timezone 8 dst
maxusers 10
maxfdescs 2048 #Max file descriptors per process
options MATH_EMULATE #Support for x87 emulation
+# Do not use in binary distributions
+#options GPL_MATH_EMULATE #Support for x87 emualtion via
+ #new math emulator
+
config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
#
# options that appear as inline #ifdef's
#
-options "COM_BIDIR" #Bidirectional support in sys/isa/sio.c
options "COM_MULTIPORT" #Multiport support in sys/isa/sio.c
-options "FIFO_TRIGGER=FIFO_TRIGGER_1" #Use this fifo value in sio.c
options "COMPAT_43" #compatible with BSD 4.3
-options "SYMTAB_SPACE=104705" #This kernel needs LOTS of symtable
+options "SYMTAB_SPACE=119000" #This kernel needs LOTS of symtable
options GATEWAY #internetwork gateway
options KTRACE #kernel tracing
options "NCONS=8" #number of syscons virtual consoles
options "FAT_CURSOR" #block cursor in syscons or pccons
-options "STAR_SAVER" #syscons "stars" screen saver
-options "FADE_SAVER" #syscons "fade" screen saver
-options "SNAKE_SAVER" #syscons "snake" screen saver
-options "BLANK_SAVER" #syscons "blank" screen saver
+
+#options ALLOW_CONFLICT_IOADDR #no IO addr conflict checks (PS/2 mice)
+#options ALLOW_CONFLICT_IRQ #no IRQ conflict checks (mport serial)
options "TCP_COMPAT_42" #tcp/ip compatible with 4.2
# ^^^ NOT RECOMMENDED FOR NORMAL USE
@@ -53,13 +55,14 @@ options MACHVMCOMPAT #support for Mach-style vm calls
options IPBROADCASTECHO=1 #send reply to broadcast pings
options IPMASKAGENT=1 #send reply to icmp mask requests
options TPCONS #support X.25 network-layer service
+options USER_LDT #allow user-level control of i386 ldt
-options EXCLUDE_CHIP_MIDI # \ sound driver options
-options "EXCLUDE_MPU401" # \ exclude specified
-options EXCLUDE_GUS # / device or chip
-options EXCLUDE_SBPRO # / from driver
+# See /sys/i386/doc/sound.doc for information about EXCLUDE options for
+# the sound drivers.
-options USER_LDT #allow user-level control of i386 ldt
+# Multicast support.
+options MULTICAST # Multicast code
+options MROUTING # Multicast routing
#
# options that are in sys/conf/files
@@ -120,13 +123,15 @@ controller ahb0 at isa? bio irq 11 vector ahbintr
controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
# driver for the Seagate ST01/ST02 card, not yet finished.
#controller sg0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector sgintr
-#dcfclk device-driver
+# driver for the Seagate ST01/ST02 or Future Domain 950 card, works
+controller sea0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector seaintr
controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
disk fd0 at fdc0 drive 0
disk fd1 at fdc0 drive 1
tape ft0 at fdc0 drive 2
+
# driver for the Western Digital and SMCC WD80xx cards, for the Novell
-# NE1000/200 card and the 3COM 3C503 card.
+# NE1000/2000 card and the 3COM 3C503 card.
device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
# driver for the AT&T Starlan card.
device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
@@ -135,27 +140,38 @@ device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
#device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
# driver for the Etherlink III ( 3C509 ) card, beta version.
device ep0 at isa? port 0x300 net irq 10 vector epintr
+#driver for the 3c501
+device el0 at isa? port 0x300 net irq 9 vector elintr
+# IBM/National PCMCIA ethernet cards
+device ze0 at isa? port 0x300 net irq 5 iomem 0xd8000 vector zeintr
+
#special cased above:
#controller isa0
-# interruptless parallel printer port driver
-device lpa0 at isa? port "IO_LPT1" tty
-device lpa1 at isa? port "IO_LPT2" tty
+
+# interruptless parallel printer port driver. NOW OBSOLETE, DON'T USE.
+#device lpa0 at isa? port "IO_LPT1" tty
+#device lpa1 at isa? port "IO_LPT2" tty
# interrupt driven parallel printer port driver
device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
-# Driver for Mutsumi CD-ROM players
-device mcd0 at isa? port 0x300 bio irq 10 vector mcdint
+# Driver for Mitsumi CD-ROM players
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
# Driver for Logitech and ATI inport bus mice
device mse0 at isa? port 0x23c tty irq 5 vector mseintr
device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
-device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
#only one of pc0 or sc0 allowed
-#device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+#device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+#PS/2 mouse driver (must follow pc0 or sc0 if enabled). Also enable
+#ALLOW_CONFLICT_IOADDR option (see above) if you want to use this.
+#device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+
pseudo-device speaker
-#tw device-driver
+device tw0 at isa? port 0x278 tty irq 5 vector twintr
+
controller uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
@@ -166,14 +182,17 @@ disk wd3 at wdc1 drive 1
device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
# Various sound card drivers.
-# See /sys/i386/doc/sound.doc for more information.
-device snd5 at isa? port 0x330 irq 6 drq 0 vector mpuintr
+# See /sys/doc/sound.doc for more information.
+device snd5 at isa? port 0x330 irq 6 vector mpuintr
device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
-device snd3 at isa? port 0x388 irq 12 drq 3 vector pasintr
+device snd3 at isa? port 0x388 irq 10 drq 6 vector pasintr
device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
-device snd1 at isa? port 0x388 irq 0 drq 0 vector sbintr
-#
-#
+device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr
+device snd7 at isa? port 0x300
+device snd1 at isa? port 0x388
+
+# The digital speaker driver (/dev/pcaudio).
+device pca0 at isa? tty
+
# options that have not been resolved yet
-#
pseudo-device log
diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386
index df5fcf18c66c..0ecf4c5e14e5 100644
--- a/sys/i386/conf/Makefile.i386
+++ b/sys/i386/conf/Makefile.i386
@@ -1,6 +1,6 @@
# Copyright 1990 W. Jolitz
# from: @(#)Makefile.i386 7.1 5/10/91
-# $Id: Makefile.i386,v 1.22 1994/02/17 06:51:15 rgrimes Exp $
+# $Id: Makefile.i386,v 1.27 1994/06/16 00:45:02 adam Exp $
#
# Makefile for FreeBSD
#
@@ -24,7 +24,15 @@ TOUCH= touch -f -c
LD= /usr/bin/ld
CC= cc
CPP= cpp
+.if defined(DEBUG)
+.if defined(NOSTRIP)
+STRIP= echo '(skipping) strip'
+.else
+STRIP= cp $@ $@.sym; strip
+.endif
+.else
STRIP= strip
+.endif
DBSYM= /usr/sbin/dbsym
S= ../..
@@ -51,11 +59,11 @@ NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
-SYSTEM_OBJS=locore.o exception.o swtch.o support.o ${OBJS} param.o \
+SYSTEM_OBJS=locore.o config.o exception.o swtch.o support.o ${OBJS} param.o \
ioconf.o conf.o machdep.o
SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
-SYSTEM_LD= @${LD} -Bstatic -Z -T ${LOAD_ADDRESS} -o $@ -X vers.o ${SYSTEM_OBJS}
+SYSTEM_LD= @${LD} -Bstatic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
${DBSYM} -fT ${LOAD_ADDRESS} $@; ${STRIP} -x $@; size $@; chmod 755 $@
@@ -90,7 +98,7 @@ symbols.sort: ${I386}/i386/symbols.raw
locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
- $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \
+ $S/sys/errno.h machine/specialreg.h \
${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h \
machine/asmacros.h
${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
@@ -104,7 +112,7 @@ exception.o: assym.s ${I386}/i386/exception.s machine/trap.h \
${AS} ${ASFLAGS} -o exception.o
swtch.o: assym.s ${I386}/i386/swtch.s \
- $S/sys/errno.h ${I386}/isa/debug.h machine/asmacros.h
+ $S/sys/errno.h machine/asmacros.h
${CPP} -I. ${COPTS} ${I386}/i386/swtch.s | \
${AS} ${ASFLAGS} -o swtch.o
diff --git a/sys/i386/conf/SYSCONS b/sys/i386/conf/SYSCONS
deleted file mode 100644
index 2143ec61c60d..000000000000
--- a/sys/i386/conf/SYSCONS
+++ /dev/null
@@ -1,86 +0,0 @@
-#
-# SYSCONS -- Generic machine with WD/AHx family disks and syscons
-#
-# $Id: SYSCONS,v 1.18 1994/02/07 10:42:04 rgrimes Exp $
-#
-
-machine "i386"
-cpu "I386_CPU"
-cpu "I486_CPU"
-ident SYSCONS
-timezone 8 dst
-maxusers 10
-maxfdescs 2048 #Max file descriptors per process
-options MATH_EMULATE #Support for x87 emulation
-options INET #InterNETworking
-options ISOFS #ISO File System
-options NFS #Network File System
-options PCFS #MSDOS File System
-options "COMPAT_43" #Compatible with BSD 4.3
-options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
-options XSERVER #Xserver
-options UCONSOLE #X Console support
-options "NCONS=8" #8 virtual consoles
-options "FAT_CURSOR" #block cursor in syscons
-options "STAR_SAVER" #syscons "stars" screen saver
-#options GATEWAY #Host is a Gateway (forwards packets)
-
-config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
-
-controller isa0
-
-controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
-disk fd0 at fdc0 drive 0
-disk fd1 at fdc0 drive 1
-
-controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
-disk wd0 at wdc0 drive 0
-disk wd1 at wdc0 drive 1
-
-controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
-disk wd2 at wdc1 drive 0
-disk wd3 at wdc1 drive 1
-
-controller ahb0 at isa? bio irq 11 vector ahbintr
-controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
-controller scbus0
-
-device sd0
-device sd1
-device sd2
-device sd3
-
-device st0
-device st1
-
-device cd0 #Only need one of these, the code dynamically grows
-
-device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
-device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
-
-device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
-device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
-device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
-device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
-
-device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
-device lpa0 at isa? port "IO_LPT1" tty
-device lpa1 at isa? port "IO_LPT2" tty
-
-device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
-device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
-device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
-device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
-
-device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
-
-pseudo-device loop
-pseudo-device ether
-pseudo-device log
-pseudo-device sl 2
-pseudo-device pty 4
-pseudo-device speaker
-
-pseudo-device swappager
-pseudo-device vnodepager
-pseudo-device devpager
diff --git a/sys/i386/conf/TIME b/sys/i386/conf/TIME
new file mode 100644
index 000000000000..bc9c0d8e8752
--- /dev/null
+++ b/sys/i386/conf/TIME
@@ -0,0 +1,64 @@
+#
+# GENERICBT -- Generic machine with WD/BTx family disks
+#
+# $Id: GENERICBT,v 1.35 1994/06/08 00:30:32 phk Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident TIME
+timezone 8 dst
+maxusers 10
+maxfdescs 1024 #Max file descriptors per process
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "NCONS=4" #4 virtual consoles
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+
+config "386bsd" root on sd0 swap on sd0 dumps on sd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+controller bt0 at isa? port "IO_BT0" bio irq 11 vector btintr
+controller scbus0
+
+device sd0
+device sd1
+
+device st0
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+
+device ed0 at isa? port 0x360 net irq 10 iomem 0xd8000 iosiz 16384 vector edintr
+#device ix0 at isa? port 0x320 net irq 10 iomem 0xd8000 iosiz 32768 vector ixintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 32
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/WCARCH b/sys/i386/conf/WCARCH
new file mode 100644
index 000000000000..f228ec5752d8
--- /dev/null
+++ b/sys/i386/conf/WCARCH
@@ -0,0 +1,67 @@
+#
+# GENERICBT -- Generic machine with WD/BTx family disks
+#
+# $Id: GENERICBT,v 1.35 1994/06/08 00:30:32 phk Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident TIME
+timezone 8 dst
+maxusers 10
+maxfdescs 1024 #Max file descriptors per process
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "NCONS=4" #4 virtual consoles
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+
+config "386bsd" root on sd0 swap on sd0 dumps on sd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+# driver for the Adaptec 154x SCSI cards.
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+
+#controller bt0 at isa? port "IO_BT0" bio irq 11 vector btintr
+#controller scbus0
+
+device sd0
+device sd1
+
+device st0
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+
+device ed0 at isa? port 0x360 net irq 10 iomem 0xd8000 iosiz 16384 vector edintr
+#device ix0 at isa? port 0x320 net irq 10 iomem 0xd8000 iosiz 32768 vector ixintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 32
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/WCARCHIVE b/sys/i386/conf/WCARCHIVE
new file mode 100644
index 000000000000..0ce90784f3fd
--- /dev/null
+++ b/sys/i386/conf/WCARCHIVE
@@ -0,0 +1,73 @@
+#
+# GENERICAH -- Generic machine with WD/AHx family disks
+#
+# $Id: GENERICAH,v 1.36 1994/06/17 06:56:59 sean Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+cpu "I586_CPU"
+ident WCARCHIVE
+timezone 8 dst
+maxusers 40
+maxfdescs 1024 #Max file descriptors per process
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options GATEWAY #Host is a Gateway (forwards packets)
+options "SCSI_DELAY=10" #Be pessimistic about Joe SCSI device
+options "NCONS=4" #4 virtual consoles
+options "NMBCLUSTERS=1024" #Needed space for many ftp connections
+
+config "386bsd" root on sd0 swap on sd0 and sd1 and sd2 dumps on sd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+
+controller ahb0 at isa? bio irq 11 vector ahbintr
+controller ahb1 at isa? bio irq 12 vector ahbintr
+
+#controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+#controller aha1 at isa? port 0x230 bio irq 12 drq 6 vector ahaintr
+
+controller scbus0
+controller scbus1
+
+device sd0
+device sd1
+device sd2
+device sd3
+device sd4
+device sd5
+device sd6
+device sd7
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 flags 0x4 vector edintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device pty 32
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386
index c388159afee3..3abc0605aac1 100644
--- a/sys/i386/conf/devices.i386
+++ b/sys/i386/conf/devices.i386
@@ -1,6 +1,6 @@
# This file tells what major numbers the various possible swap devices have.
#
-# $Id: devices.i386,v 1.5 1994/01/04 20:09:28 nate Exp $
+# $Id: devices.i386,v 1.6 1994/03/21 20:48:49 ats Exp $
#
wd 0
dk 1
@@ -10,3 +10,4 @@ sd 4
st 5
cd 6
mcd 7
+scd 8
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index 1b84847c7713..92a79684af05 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.25 1994/02/07 04:27:59 alm Exp $
+# $Id: files.i386,v 1.39 1994/06/16 05:31:20 jkh Exp $
#
i386/i386/autoconf.c standard device-driver
i386/i386/cons.c standard
@@ -17,53 +17,61 @@ i386/i386/pmap.c standard
i386/i386/sys_machdep.c standard
i386/i386/trap.c standard
i386/i386/vm_machdep.c standard
+i386/i386/random.s optional multicast
i386/isa/aha1542.c optional aha device-driver
i386/isa/aha1742.c optional ahb device-driver
i386/isa/bt742a.c optional bt device-driver
i386/isa/clock.c standard
i386/isa/com.c optional com device-driver
-i386/isa/dcfclk.c optional dcfclk device-driver
i386/isa/fd.c optional fd device-driver
i386/isa/ft.c optional ft device-driver
i386/isa/if_ed.c optional ed device-driver
+i386/isa/if_el.c optional el device-driver
i386/isa/if_ep.c optional ep device-driver
i386/isa/if_ie.c optional ie device-driver
i386/isa/if_is.c optional is device-driver
i386/isa/if_ix.c optional ix device-driver
i386/isa/isa.c optional isa device-driver
-i386/isa/lpa.c optional lpa device-driver
i386/isa/lpt.c optional lpt device-driver
i386/isa/mcd.c optional mcd device-driver
i386/isa/mse.c optional mse device-driver
i386/isa/npx.c optional npx device-driver
i386/isa/syscons.c optional sc device-driver
i386/isa/pccons.c optional pc device-driver
+i386/isa/pcaudio.c optional pca device-driver
i386/isa/psm.c optional psm device-driver
i386/isa/sb.c optional sb device-driver
+i386/isa/scd.c optional scd device-driver
+i386/isa/seagate.c optional sea device-driver
i386/isa/sg.c optional sg device-driver
i386/isa/sio.c optional sio device-driver
-i386/isa/sound/adlib_card.c optional snd device-driver
-i386/isa/sound/audio.c optional snd device-driver
-i386/isa/sound/dev_table.c optional snd device-driver
-i386/isa/sound/dmabuf.c optional snd device-driver
-i386/isa/sound/dsp.c optional snd device-driver
-i386/isa/sound/gus_card.c optional snd device-driver
-i386/isa/sound/gus_midi.c optional snd device-driver
-i386/isa/sound/gus_vol.c optional snd device-driver
-i386/isa/sound/gus_wave.c optional snd device-driver
-i386/isa/sound/midi.c optional snd device-driver
-i386/isa/sound/midibuf.c optional snd device-driver
-i386/isa/sound/mpu401.c optional snd device-driver
-i386/isa/sound/opl3.c optional snd device-driver
-i386/isa/sound/pas2_card.c optional snd device-driver
-i386/isa/sound/pas2_midi.c optional snd device-driver
-i386/isa/sound/pas2_mixer.c optional snd device-driver
-i386/isa/sound/pas2_pcm.c optional snd device-driver
-i386/isa/sound/patmgr.c optional snd device-driver
-i386/isa/sound/pro_midi.c optional snd device-driver
-i386/isa/sound/sb_card.c optional snd device-driver
-i386/isa/sound/sb_dsp.c optional snd device-driver
-i386/isa/sound/sequencer.c optional snd device-driver
+i386/isa/sound/adlib_card.c optional snd device-driver
+i386/isa/sound/audio.c optional snd device-driver
+i386/isa/sound/dev_table.c optional snd device-driver
+i386/isa/sound/dmabuf.c optional snd device-driver
+i386/isa/sound/gus_card.c optional snd device-driver
+i386/isa/sound/gus_midi.c optional snd device-driver
+i386/isa/sound/gus_vol.c optional snd device-driver
+i386/isa/sound/gus_wave.c optional snd device-driver
+i386/isa/sound/ics2101.c optional snd device-driver
+i386/isa/sound/midi.c optional snd device-driver
+i386/isa/sound/midibuf.c optional snd device-driver
+i386/isa/sound/mpu401.c optional snd device-driver
+i386/isa/sound/opl3.c optional snd device-driver
+i386/isa/sound/pas2_card.c optional snd device-driver
+i386/isa/sound/pas2_midi.c optional snd device-driver
+i386/isa/sound/pas2_mixer.c optional snd device-driver
+i386/isa/sound/pas2_pcm.c optional snd device-driver
+i386/isa/sound/patmgr.c optional snd device-driver
+i386/isa/sound/pro_midi.c optional snd device-driver
+i386/isa/sound/sb16_dsp.c optional snd device-driver
+i386/isa/sound/sb16_midi.c optional snd device-driver
+i386/isa/sound/sb_card.c optional snd device-driver
+i386/isa/sound/sb_dsp.c optional snd device-driver
+i386/isa/sound/sb_midi.c optional snd device-driver
+i386/isa/sound/sb_mixer.c optional snd device-driver
+i386/isa/sound/sequencer.c optional snd device-driver
+i386/isa/sound/sound_switch.c optional snd device-driver
i386/isa/sound/soundcard.c optional snd device-driver
i386/isa/spkr.c optional speaker
i386/isa/tw.c optional tw device-driver
@@ -76,3 +84,39 @@ i386/isa/pcvt/pcvt_out.c optional vt device-driver
i386/isa/pcvt/pcvt_kbd.c optional vt device-driver
i386/isa/pcvt/pcvt_vtf.c optional vt device-driver
i386/isa/pcvt/pcvt_ext.c optional vt device-driver
+i386/isa/if_ze.c optional ze device-driver
+gnu/fpemul/div_small.s optional gpl_math_emulate
+gnu/fpemul/errors.c optional gpl_math_emulate
+gnu/fpemul/fpu_arith.c optional gpl_math_emulate
+gnu/fpemul/fpu_aux.c optional gpl_math_emulate
+gnu/fpemul/fpu_entry.c optional gpl_math_emulate
+gnu/fpemul/fpu_etc.c optional gpl_math_emulate
+gnu/fpemul/fpu_trig.c optional gpl_math_emulate
+gnu/fpemul/get_address.c optional gpl_math_emulate
+gnu/fpemul/load_store.c optional gpl_math_emulate
+gnu/fpemul/poly_2xm1.c optional gpl_math_emulate
+gnu/fpemul/poly_atan.c optional gpl_math_emulate
+gnu/fpemul/poly_div.s optional gpl_math_emulate
+gnu/fpemul/poly_l2.c optional gpl_math_emulate
+gnu/fpemul/poly_mul64.s optional gpl_math_emulate
+gnu/fpemul/poly_sin.c optional gpl_math_emulate
+gnu/fpemul/poly_tan.c optional gpl_math_emulate
+gnu/fpemul/polynomial.s optional gpl_math_emulate
+gnu/fpemul/reg_add_sub.c optional gpl_math_emulate
+gnu/fpemul/reg_compare.c optional gpl_math_emulate
+gnu/fpemul/reg_constant.c optional gpl_math_emulate
+gnu/fpemul/reg_div.s optional gpl_math_emulate
+gnu/fpemul/reg_ld_str.c optional gpl_math_emulate
+gnu/fpemul/reg_mul.c optional gpl_math_emulate
+gnu/fpemul/reg_norm.s optional gpl_math_emulate
+gnu/fpemul/reg_round.s optional gpl_math_emulate
+gnu/fpemul/reg_u_add.s optional gpl_math_emulate
+gnu/fpemul/reg_u_div.s optional gpl_math_emulate
+gnu/fpemul/reg_u_mul.s optional gpl_math_emulate
+gnu/fpemul/reg_u_sub.s optional gpl_math_emulate
+gnu/fpemul/wm_shrx.s optional gpl_math_emulate
+gnu/fpemul/wm_sqrt.s optional gpl_math_emulate
+i386/pci/ncr.c optional ncr device-driver
+i386/pci/pci.c optional pci device-driver
+i386/pci/pcibios.c optional pci device-driver
+i386/pci/pci_config.c optional pci device-driver
diff --git a/sys/i386/doc/Changes b/sys/i386/doc/Changes
deleted file mode 100644
index 590f087f85bf..000000000000
--- a/sys/i386/doc/Changes
+++ /dev/null
@@ -1,209 +0,0 @@
-Hello, Emacs, this is an -*- Indented-Text -*- file!
-
-$Id: Changes,v 1.15 1994/02/21 23:03:09 rgrimes Exp $
-
-This file is intended to keep track of important kernel and user
-changes in FreeBSD between releases. Entries are in reverse
-chronological order; userids can be decoded with the chart at the end
-of this file.
-
-Since 1.1 BETA:
-
-Between 1.1 BETA and 1.0.2:
-- Improved lpt driver, should no longer lock up when lprm is done on
- an active job. Fixed up the probe routine so that it works on most
- if not all printers now. (csgr/rgrimes)
-
-- Substantial changes to system configuration; you MUST re-build
- `config' before attempting to build a 1.1 kernel. (nate/martin)
-
-- Improved the quality of the information given to the user when
- a fatal trap occurs. (davidg)
-
-- Added support in the if_ed driver for the WD8013W, WD8003W, and
- WD8003EB. (davidg)
-
-- Change to generic console code to eliminate console hangs with all
- `pc' consoles. (davidg)
-
-- Upgrade to new version of syscons which handles the `hanging console'
- problem and adds some new features and code cleanup. (nate)
-
-- Various TCP bugs fixed - don't forward loopback packets; Nagel
- congestion avoidence - immediately ack small packets. (davidg)
-
-- TCP debugging code is now truly optional, thus reducing kernel size
- when it is disabled (the default). (davidg)
-
-- Because the `sio' FIFOs are now configurable, the `com' driver is no
- longer supported. (team sighs with relief)
-
-- Performance and stylistic improvements to the `sio' serial driver.
- Probe code now works somewhat better for oddball devices. The 16550
- FIFO length is now configurable using `flags' in the config
- declaration. (ache/bde)
-
-- Performance improvements and complete implementation of POSIX VMIN
- and VTIME for the generic TTY code. (ache/bde)
-
-- Crash dumps on SCSI disks now work and are standard. (rgrimes/davidg)
-
-- QMAGIC is now the official default executable format. (davidg)
-
-- Network booting is now supported, as is booting from DOS. (martin)
-
-- Local LDTs are now supported for WINE (based on work by John Brezak).
- (hsu/davidg)
-
-- DDB will now print symbolic arguments and line numbers in
- backtraces (from John Brezak). (davidg)
-
-- Added four pattern memory test to eliminate problems with buggy
- chipsets that incorrectly map memory, and to find problems with
- defective memory. The memory sizing code has been improved to
- further eliminate problems with buggy chipsets/BIOSs. (davidg)
-
-- USE_486_WRITE_PROTECT is now gone; the system will automatically
- detect 486 CPUs and behave accordingly. (davidg)
-
-- Added SysV IPC, messaging, and semaphore code by Danny Boulet.
- (hsu/davidg)
-
-- Because of the VM system changes, Paul Kranenburg's process
- filesystem is now MANDATORY in order for `ps' and friends to be able
- to dig up process information which has been paged out. (davidg)
-
-- Substantial VM system improvements: (dyson/davidg)
- o FreeBSD once again works on 4-MB machines.
- o Maximum and default size limits set to reasonable values.
- o The user area is now in the process address space, and can
- now be paged out along with the rest of the process.
- o Process page tables can now be paged out.
- o The physical map (pmap) module has been mostly rewritten for
- efficiency, and is considerably faster than it used to be.
- o The pageout system now actually implements modified LRU.
- o Process RSS soft limits implemented. Hooks are in place for
- RSS hard limits.
- o Pagers can now do multiple-page operations ("page fault
- clustering"), and page fault read behind and read ahead
- have been implemented to take advantage of this.
- o The vnode pager no longer drags pages through the buffer
- cache, eliminating an expensive memory copy and flushing
- of cached data.
- o When the system runs out of swap space, the faulting process
- is killed off (with a message to syslog); the old code would
- just deadlock.
- o Swap space allocation is much more efficient, and swap
- striping actually works now. It's now possible for every
- last block of swap space to be used before the systems runs
- out.
- o The pagedaemon's algorithms are considerably improved, thus
- reducing the amount of CPU time used by the pagedaemon.
- o All kernels MUST now load at virtual address 0xf010000, and
- the lower 640k is reclaimed for system use. This removes
- the 640K kernel size limit.
- o VM object cache size is now dynamic and a function of the
- kernel 'maxusers' parameter.
- o Memory in the I/O hole is explicitly marked non-cacheable.
-
-- Added 3C509 driver written by Herb Peyerl. (ats/nate)
-
-- Added a new 'wd' driver which does a much better job of probing, handles
- stray interrupts better, and supports multiple controllers. In addition
- this driver supports DOS partitions much better and conforms to ATA specs
- much better. NB: configuration lines for this driver are different
- than those for pervious versions; see a GENERIC for details.
- (nate/bde/guido)
-
-- Added support in the if_ed driver for the Toshiba ethernet cards.The
- support must be enabled with an "options TOSH_ETHER" in the config
- file. Done it this way, because i don't know how widespread the cards
- are. (ats)
-
-- Added support in the if_ed driver for the SMC Ultra via patches from
- Glen Lowe. (davidg)
-
-- Updated Mitsumi CD driver to work with FX models. (jkh/Gary
- Clark II)
-
-- Add extended formats set to floppy driver, improve autoconfiguration,
- add "fdformat" utility for floppy formatting.
- The format of floppy disk minor numbers has changed, thus
- necessitating a new `MAKEDEV fd'. (ache/joerg/Serge Vakulenko)
-
-- Add XNTPD to contrib section, and (un-compilable) kernel support for
- same to /sys/kern. (wollman)
-
-- Use linker-constructed sets to initialize certain system tables
- rather than manually enumerating all the options in the source files.
- This makes certain pseudo-devices and all image activators drop-in at
- link time, if desired. (wollman)
-
-- Added YP code from Theo Deraadt. (paul/nate)
-
-- Make all mandatory options ``standard''. (wollman)
-
-- Update `wt' driver to support more devices and controllers. The
- driver will also auto-detect tape density on models which support
- it. The structure of `wt' device minor numbers has changed;
- `MAKEDEV wt' must be run to create the new device nodes.
-
-- Re-design execve() system call to allow for multiple ``image activators''
- which recognize and load various file formats. Currently only
- a.out and interpreted formats are recognized. (davidg)
-
-- Provide the address of the faulting reference to signal handlers, to
- make life easier for smart garbage-collection algorithms. (hsu)
-
-- New, improved process tracing code from Sean Eric Fagan. (davidg)
-
-- Re-organize locore into several different source files according to
- function. (davidg)
-
-- On panic, don't reboot right away but give the user some time to
- abort the reboot or at least write down the panic message. (davidg)
-
-- Kernel timezone handling is now delegated to an external program,
- `adjkerntz'. No more bogus summer time jumps. (ache)
-
-- Separate all IP-related variables that users might want to modify into
- netinet/in_var.c. (wollman)
-
-- New, redesigned SCSI system; should run faster and have fewer bugs.
- (julian)
-
-- Make it possible to mmap(2) /dev/mem. (julian)
-
-Between 1.0.2 and 1.0:
-
-Between 1.0 EPSILON and 1.0 GAMMA:
-
-Between 1.0 GAMMA and 1.0 BETA:
-
-Between 1.0 BETA and 1.0 ALPHA:
-
-Between 1.0 ALPHA and Patchkit 0.2.4:
-
-Userids map as follows:
-ache Andrew Chernov
-alm Andrew Moore
-ats Andreas Schulz
-chmr Christoph Robitscho
-csgr Geoff Rehmet
-davidg David Greenman
-dyson John Dyson
-guido Guido van Rooij
-hsu Jeffrey Hsu
-jkh Jordan Hubbard
-joerg Joerg Wunsch
-jtc J.T. Conklin
-ljo L. Jonas Olson
-martin Martin Renters
-nate Nate Williams
-paul Paul Richards
-proven Chris Provenzano
-rich Rich Murphey
-rls Rob Shady
-smace Scott Mace
-swallace Steven Wallace
-wollman Garrett Wollman
diff --git a/sys/i386/doc/Makefile b/sys/i386/doc/Makefile
deleted file mode 100644
index 67fb36b0ceac..000000000000
--- a/sys/i386/doc/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# $Id: Makefile,v 1.1 1993/11/06 00:07:42 wollman Exp $
-#
-# Makefile for /sys/i386/doc
-# This creates options.info and options.doc from options.texi, if the
-# GNU makeinfo program is present, and fails miserably otherwise.
-#
-
-all: options.info options.doc
-
-options.info: options.texi
- makeinfo options.texi
-
-options.doc: options.texi
- makeinfo -o options.doc+ --no-headers options.texi
- sed '/^General Index/,$$d' < options.doc+ > options.doc
- rm -f options.doc+
-
-clean:
- rm -f options.info options.doc options.doc+
diff --git a/sys/i386/doc/ed.relnotes b/sys/i386/doc/ed.relnotes
deleted file mode 100644
index d01e21d4c427..000000000000
--- a/sys/i386/doc/ed.relnotes
+++ /dev/null
@@ -1,174 +0,0 @@
-
- Release Notes for 'ed' Device Driver
- David Greenman, 24-May-1993
- ------------------------------------
-
-Last updated: 22-November-1993
-
-INTRODUCTION
-------------
- The 'ed' device driver is a new, high performance device driver supporting
-the Western Digital/SMC 80x3 series (including 'EtherCard PLUS' 'Elite16' and
-'Ultra'), the 3Com 3c503 (both 8 and 16 bit versions), and the Novell NE1000/
-NE2000. All of the ethernet controllers use the DS8390, 83C690, or 83C790
-Network Interface Controller (NIC). The differences between the boards are in
-their memory capacity, bus width (8/16 bits), special logic (asic) used to
-configure the board, and the host access method to the NIC memory (shared or
-programmed I/O). Every effort has been made to conform to the manufactures'
-specifications for the NIC and asic. This includes both normal operation and
-error recovery.
-
-PERFORMANCE
------------
-
-transmit
---------
- The 8390 doesn't provide a mechanism for chained write buffers, so it is
-very important for maximum performance to queue the next packet for
-transmission as soon as the current one has completed. On boards with 16k or
-more of memory, the NIC memory is divided in a way that allows enough space
-for two full size packets to be buffered for transmission. When sufficient
-data is available for transmission, a packet is copied into the NIC memory,
-the transmission is started, and then an additional packet is copied into the
-NIC memory (to a different memory area). As soon as the first packet has
-completed, transmission of a second packet can then be started immediately.
-This results in nearly the highest performance possible from ethernet.
-
-Packets go out on the 'wire' with the following format:
-
-preamble dest-addr src-addr type data FCS intr-frame
-64bits 48bits 48bits 16bits 1500bytes 32bits 96bits
-
- With 10Mbits/sec, each bit is 100ns in duration. All of the above fields,
-except for data are of fixed length. With full sized packets (1500 bytes), the
-maximum unidirectional data rate can be calculated as: 6.4us + 4.8us + 4.8us +
-1.6us + 1200us + 3.2us + 9.6us = 1230.4us/packet = 812.74382 packets/second =
-1219115.7 (1190k) bytes/second. With TCP, there is a 40 byte overhead for the
-IP and TCP headers, so there is only 1460 bytes of data per packet. This
-reduces the maximum data rate to 1186606 bytes/second. With TCP, there will
-also be periodic acknowledgments which will reduce this figure somewhat both
-because of the additional traffic in the reverse direction and because of the
-occasional collisions that this will cause. Despite this, the data rate has
-still been consistantly measured at 1125000 (~1100k) bytes/second through a TCP
-socket. In these tests, the TCP window was set to 16384 bytes. With UDP, there
-is less overhead for the headers, and with 1472 bytes of data per packet, a
-data rate of 1196358.9 (1168k) bytes/sec is possible. UDP performance hasn't
-been precisely measured with this device driver, but less precise tests show
-this to be true (measured at around 1135k/second).
-
-receive
--------
- The 8390 implements an NIC memory ring-buffer to store incoming packets.
-The 8bit boards (8003, 3c503, and NE1000) usually have only 8k bytes of shared
-memory. This is only enough room for about 4 full size (1500 byte) packets.
-This can sometimes be a problem, especially on the original WD8003E and 3c503.
-This is because these boards' NIC memory access speed is also quite slow
-compared to newer 16bit boards - typically less than 1MB/second. The additional
-overhead of this slow memory access, and the fact that there is only room for 4
-full-sized packets means that the ring-buffer will occassionally overflow. When
-this happens, the board must be reset to avoid a lockup problem in early
-revision 8390's. Resetting the board will cause all of the data in the ring-
-buffer to be lost - requiring it to be re-transmitted/received...slowing things
-even further. Because of these problems, maximum throughput on boards of this
-type is only about 400-600k per second. The 16bit boards, however, have 16k of
-memory as well as much faster memory access speed. Typical memory access speed
-on these boards is about 1.7-4MB/second (with the Novell NE2000 being the
-slowest and the SMC 8013 being the fastest). These boards generally have no
-problems keeping up with full ethernet speed. The only problem I've seen with
-these boards is related to the (slow) performance of the BSD Net/2 malloc code
-when additional mbufs must be added to the pool. This can sometimes increase
-the total time to remove a packet enough for a ring-buffer overflow to occur.
-This tends to be highly transient, and quite rare on fast machines. I've only
-seen this problem when doing tests with large amounts of UDP traffic without
-any acknowledgments (uni-directional). Again, this has been very rare.
-
- All of the above tests were done using a 486DX2/66, 486DX/33, 386DX/40,
-8-9Mhz ISA bus, using FreeBSD 1.0. TCP tests were done with the 'ttcp'
-performance test utility, and also with FTP client/server. UDP tests were done
-with a modified version of ttcp (to work around a bug in the BSD Net/2 UDP
-code related to queue depth), and also with NFS.
-
-KERNEL INSTALLATION
--------------------
- (Note that this driver comes standard in FreeBSD 1.0, NetBSD 0.9, and 386BSD
-0.2, and therefore doesn't require installation)
- To 'install' this driver, the files if_ed.c and if_edreg.h must be copied
-into the i386/isa kernel source directory and the following line must be
-added into the file i386/conf/files.i386:
-
-i386/isa/if_ed.c optional ed device-driver
-
- To build a kernel that includes this driver, first comment out any 'we',
-'ec', or 'ne' devices in your kernel config file. Then, add a line similar to
-the following (modify to match your cards configuration):
-
-device ed0 at isa? port 0x300 net irq 10 iomem 0xcc000 vector edintr
-
- Note that the 'iosiz' option is not needed because the driver automatically
-figures this out. However, if you have problems with this, it can be specified
-to force the use of the size you specify.
- The iomem 0xcc000 option is not need for NE1000/NE2000 boards because they
-use programmed I/O rather than shared memory to access the NIC's memory.
- On 3Com boards, the tranceiver must be enabled in software (there is no
-hardware default). In this driver, this is controlled using the "LLC0" link-
-level control flag. The default for this flag can be set in your kernel config
-file by specifying 'flags 0x01' in the 'ed' device specification line (this
-is necessary for diskless support). Otherwise, the tranceiver is easily enabled
-and disabled with a command like "ifconfig ed0 -llc0" to enable the tranceiver
-or "ifconfig ed0 llc0" to disable it; this assumes that you have the modified
-ifconfig(8) that originally appeared in the 386BSD patchkit. To specify the
-'flags' option, use a line similar to:
-
-device ed0 at isa? port 0x300 net irq 10 flags 0x01 iomem 0xcc000 vector edintr
-
- Flags can be similarly specified to force 8 or 16bit mode, and disabling
-the use of transmitter double buffering. The various supported flag values
-are:
-
- Disable tranceiver 0x01
- Force 8 bit mode 0x02
- Force 16 bit mode 0x04
- Disable multi TX buffering 0x08
-
- To use multiple flags, simply add the values together. Note that these
-numbers are in hexadecimal. If the 'Force 8 bit' and 'Force 16 bit' flags are
-both specified, the 8 bit flag has precedence.
- The use of the above flags should only be necessary under exceptional
-conditions where the probe routine incorrectly determines the board type (such
-is the case with Compex boards, which require the 16bit flag and an iosiz
-16384), or where the high performance of the transmitter causes problems with
-other vendors hardware.
-
-
-KNOWN PROBLEMS
---------------
-
-1) Early revision DS8390B chips have problems. They lock-up whenever the
- receive ring-buffer overflows. They occassionally switch the byte order
- of the length field in the packet ring header (several different causes
- of this related to an off-by-one byte alignment) - resulting in "NIC
- memory corrupt - invalid length NNNNN" messages. The board is reset
- whenever these problems occur, but otherwise there is no problem with
- recovering from these conditions.
-2) 16bit boards that use shared memory can conflict with 8bit BIOSes, BIOS
- extensions (like the VGA), and 8bit devices with shared memory (again
- like the VGA, or perhaps a second ethernet board). There is a work-
- around for this in the driver, however. The problem is that the
- ethernet board stays in 16bit mode, asserting its '16bit' signal on
- the ISA bus. This signal is shared by other devices/ROMs in the same
- 128K memory segment as the ethernet card - causing the CPU to read the
- 8bit ROMs as if they were 16bit wide. The work-around involves setting
- the host access to the shared memory to 16bits only when the memory is
- actually accessed, and setting it back to 8bit mode all other times.
- Without this work-around, the machine will hang whenever a reboot is
- attempted. This work-around also allows the board to co-exist with
- other 8bit devices that have shared memory. This has only been
- implemented for SMC/WD boards, but I haven't seen this problem with
- 3Com boards (i.e. if you have a 3Com board, you might experiance the
- above problem - I haven't specifically tested for it).
-3) The NIC memory access to 3Com and Novell boards is much slower than it is on
- SMC boards; it's less than 1MB on 8bit boards and less than 2MB/second
- on the 16bit boards. This can lead to ring-buffer overruns resulting in
- additional lost data during heavy network traffic.
-
-$Id: ed.relnotes,v 1.4 1993/11/22 11:15:16 davidg Exp $
diff --git a/sys/i386/doc/options.texi b/sys/i386/doc/options.texi
deleted file mode 100644
index 4313cf009459..000000000000
--- a/sys/i386/doc/options.texi
+++ /dev/null
@@ -1,974 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-@c %**start of header
-@setfilename options.info
-@settitle Configuration Options for FreeBSD
-@c @setchapternewpage odd
-@c function index is option/pseudo/device names; concept is everything
-@c else
-@syncodeindex fn cp
-@finalout
-@c %**end of header
-
-@ifinfo
-$Id: options.texi,v 1.4.2.1 1994/03/07 01:51:59 rgrimes Exp $
-
-This file documents the configuration options available in the FreeBSD
-operating system.
-
-@display
-Copyright @copyright{} 1993, 1994, Garrett A. Wollman. All rights reserved.
-
-Redistribution and use in source and printed 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 and this list of conditions.
-2. Redistributions in printed form must reproduce the above copyright
- notice, this list of conditions and the following notice of
- authorship.
-
-Trademarks are property of their respective owners.
-@end display
-@end ifinfo
-
-@titlepage
-@title Configuration Options in FreeBSD
-@subtitle for FreeBSD 1.1
-@author Garrett A. Wollman
-@author FreeBSD Project
-
-@page
-@vskip 0pt plus 1filll
-
-i386, i387, and i486 are trademarks of Intel Corporation. SunOS is a
-registered trademark and NFS is a trademark of Sun Microsystems, Inc.
-Ultrix is a registered trademark of Digital Equipment Corporation.
-Xerox is a registered trademark and XNS is a trademark of Xerox
-Corporation. VESA is a trademark of the Video Electronics Standards
-Association. System V is a registered trademark of Novell Corporation.
-All other trademarks are property of their respective owners. FreeBSD
-is nobody's trademark, and damn proud of it.
-
-Copyright @copyright{} 1993, 1994, Garrett A. Wollman. All rights reserved.
-
-Redistribution and use in source and printed forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-@enumerate
-@item
-Redistributions of source code must retain the above copyright
-notice and this list of conditions.
-
-@item
-Redistributions in printed form must reproduce the above copyright
-notice, this list of conditions and the preceding notice of
-authorship.
-@end enumerate
-@end titlepage
-
-@node Top, Subsystems, (dir), (dir)
-@top FreeBSD Configuration Options
-
-This document describes kernel configuration options relevant to the
-FreeBSD operating system version 1.1. It is intended for readers who
-already have a general understanding of the process of configuring a BSD
-kernel and wish to get a general overview of the meaning of various
-configuration options. This document covers configurable options and
-pseudo-devices; it is intended that devices may be added at a later
-date.
-
-@menu
-* Subsystems:: Controlling subsystems.
-* Performance:: Performance enhancement.
-* Devices:: Device-control options.
-* Internals:: Non-user-serviceable parts.
-
-* Index:: General Index.
-@end menu
-
-@node Subsystems, Performance, Top, Top
-@c node,next,prev,up
-
-@chapter Options for Subsystems
-
-This chapter discusses options controlling the inclusion of various
-subsystems in FreeBSD. These include things like filesystems,
-networking modules, and whatnot. Remember that options containing
-underscores must be quoted.
-
-@table @code
-@item pseudo-device bpfilter @var{number}
-@findex bpfilter
-@cindex Berkeley packet filter
-@cindex Network interfaces
-The @samp{bpfilter} pseudo-device is the Berkeley Packet Filter,
-developed by Lawrence Berkeley Labs and based on an earlier packet
-filter from Stanford. See the @samp{bpf} manual page for more details.
-The @var{number} given is the maximum number of simultaneous users
-permitted. (NB: in previous version of BPF, the @var{number} had to be
-greater than the number of interfaces; this space is now dynamically
-allocated so this requirement is no longer present.)
-
-@item options CCITT
-@findex CCITT
-@cindex X.25
-@cindex Networking domains
-The @samp{CCITT} option enables support for the ITU-T X.25(1980)
-network-layer protocol. Nobody we know has a direct X.25 connection to
-anything, so this code has never been tested.
-
-@item options "COMPAT_42"
-@findex COMPAT_42
-@cindex UDP Checksums
-@cindex Checksums, UDP
-@cindex 4.2 Compatibility
-@cindex Compatibility options
-This option is used to disable UDP checksumming. Under ordinary
-circumstances it should never ever ever be defined; however, if you are
-stuck trying to communicate with an old 4.2BSD machine, or one running
-something derived from 4.2 like SunOS 3.5 or Ultrix 2.0, this may be
-necessary in order to successfully receive UDP packets.
-
-@item options "COMPAT_43"
-@findex COMPAT_43
-@cindex 4.3 Compatibility
-@cindex Compatibility options
-This option controls a whole host of features, mostly relating to
-system-call compatibilty with 4.3BSD. At the present time, it should
-not be turned off, as many utilities and library routines still depend
-on these obsolescent system calls being present. At some future date,
-this will probably be split up into two separate options, one for binary
-compatibility and one for the old but useful system calls.
-
-@item options "DIRECTED_BROADCAST"
-@findex DIRECTED_BROADCAST
-@cindex IP
-@cindex UDP
-If this option is enabled, the kernel will support sending IP broadcast
-packets to subnets other than the one that the machine is on, and when
-forwarding will accept such packets. That is to say, if your host lives
-on subnets @samp{132.198.3} and @samp{132.198.4}, and the
-@samp{132.198.3} side receives a packet addressed to
-@samp{132.198.4.255}, it will forward the packet as a broadcast on that
-subnet.
-
-@item pseudo-device ether
-@findex ether
-@cindex Ethernet
-@cindex Network interfaces
-This pseudo-device provides link-layer support for Ethernet device
-drivers. It is mandatory for all systems which include Ethernet or
-Ethernet-like devices, such as @samp{ed}, @samp{ie}, and @samp{is}.
-This code is due for a redesign.
-
-@item options EON
-@itemx pseudo-device eon
-@findex EON
-@cindex ISO 8473 CLNP
-@cindex Network interfaces
-The @samp{eon} network interface supports the ISO 8473
-Connectionless-Mode Network Protocol, tunnelled through IP version 4.
-@samp{eon} interfaces are created automatically once initially
-configured by adding ISO routes with IP destinations. At present, both
-the pseudo-device and option declaration are necessary.
-
-@item options FIFO
-@findex FIFO
-@cindex Named pipes
-This option enables support for System V-- and POSIX-style named pipes
-or fifos.
-
-@item options GATEWAY
-@itemx options IPFORWARDING=@var{value}
-@itemx options IPSENDREDIRECTS=@var{value}
-@findex GATEWAY
-@findex IPFORWARDING
-@findex IPSENDREDIRECTS
-@cindex ICMP
-@cindex IP
-@cindex Network parameters
-These three options control whether FreeBSD's IP forwarding functions
-are enabled. Technically speaking, because FreeBSD does not meet the
-standards set out in the ``Router Requirements'' document (RFC 1009),
-these should not be enabled, but sometimes it is necessary to enable
-this function. The @samp{GATEWAY} option turns on @samp{IPFORWARDING},
-and also controls the sizing of certain system tables. The
-@samp{IPFORWARDING} option controls the initial value of the
-@samp{ipforwarding} kernel variable (default 1 if @samp{GATEWAY}
-defined, 0 otherwise), which controls whether packets are acutally
-forwarded or not; @var{value} should be either @samp{0} or @samp{1}.
-@samp{IPSENDREDIRECTS} controls the initial value of the
-@samp{ipsendredirects} variable (default is one, but should be changed
-to zero); its @var{value} should also be either @samp{0} or @samp{1}.
-
-@item options INET
-@findex INET
-@cindex IP
-@cindex TCP
-@cindex UDP
-@cindex ICMP
-@cindex Networking domains
-This option controls the inclusion of the Internet protocol suite,
-including IP version 4, TCP, UDP, and ICMP. Support for IP multicast,
-IP next generation, and IGMP will be provided at a future date. It is
-not recommended to even attempt to generate a system with this option
-turned off, as many parts of the system depend on Internet networking in
-important and subtle ways.
-
-@item options ISO
-@itemx options TPIP
-@findex ISO
-@findex TPIP
-@cindex ISO 8473 CLNP
-@cindex ISO TP4
-@cindex ISO TP0
-@cindex ISO 9542 ESIS
-@cindex IEEE 802.2 LLC
-@cindex Networking domains
-These options control the inclusion of ISO OSI networking protocols.
-The TPIP option includes just enough support to run ISO Transport
-Protocol class 4 over IP, supporing the @samp{SOCK_SEQPACKET}
-abstraction. The ISO option includes support for CLNP, TP class 0,
-ISO 9542 ESIS, and IEEE 802.2 logical link control class 0 (for CLNP only).
-
-@item options ISOFS
-@findex ISOFS
-@cindex ISO 9660 filesystem
-@cindex CD-ROM
-@cindex Rock Ridge filesystem
-@cindex Filesystems
-The @samp{ISOFS} option enables kernel support for the ISO 9660 CD-ROM
-filesystem, including RockRidge extensions.
-
-@item options "ISO_X25ESIS"
-@findex ISO_X25ESIS
-@cindex ISO 9542 ESIS
-@cindex X.25
-This option controls whether ISO 9542 ESIS is run over ITU-T X.25 link
-layers. This requires the @samp{CCITT} option to be enabled as well.
-
-@item options KTRACE
-@findex KTRACE
-@cindex Kernel tracing
-This option enables the tracing of several classes of internal kernel
-events. See the @samp{ktrace} command for more details.
-
-@item pseudo-device log
-@findex log
-@cindex Kernel message logging
-The @samp{log} pseudo-device provides kernel support to send kernel
-messages to @samp{syslog}. It is mandatory.
-
-@item pseudo-device loop
-@findex loop
-@cindex Network interfaces
-The @samp{loop} pseudo-device provides the trivial network interface.
-It is required when any networking options are enabled.
-
-@item options MACHVMCOMPAT
-@findex MACHVMCOMPAT
-@cindex Mach virtual memory
-This option enables a Mach-compatible interface to the virtual memory
-subsystem, supporting system calls @samp{vm_allocate},
-@samp{vm_deallocate}, @samp{vm_inherit}, and @samp{vm_protect}.
-(Given the nature of the VM system, it is impossible to support a
-Mach-style @samp{vm_region} call, and in every case the `map' argument
-is ignored and replaced with the calling process's own map.)
-
-@item options MFS
-@findex MFS
-@cindex Memory filesystem
-@cindex Filesystems
-This option enables support for the memory filesystem, an in-core
-filesystem which lives in the swap area. Using MFS as a @file{/tmp}
-filesystem can dramatically increase the speed of
-temporary-space-intensive operations such as compilations. See the
-@samp{mount_mfs} manual page for more details.
-
-@item options NFS
-@findex NFS
-@cindex Network File System
-@cindex Filesystems
-The @samp{NFS} option enables support for Sun's Network File System.
-(Also called ``Nightmare'' or ``Not a''@dots{}.) This presently includes
-both client-- and server-side kernelized NFS support; it may in the
-future be broken into separate options. This NFS implmentation comes to
-BSD courtesy of Rick Macklem of the University of Guelph, and is not
-derived from Sun licensed source code. As a result, there are sometimes
-interoperability problems where the published specification is vague,
-and this option supports several new and useful features compared to
-Sun's. See the @samp{mount} manual page for more details.
-
-@item options NS
-@itemx options NSIP
-@findex NS
-@findex NSIP
-@cindex Xerox Network System
-@cindex XNS IDP
-@cindex XNS SPP
-@cindex Network interfaces
-@samp{NS} controls the inclusion of support for the Xerox Network
-Service protocol family. At the present time, it is not known whether
-this code even works; testers are welcome. The @samp{NSIP} option
-enables encapsulation of XNS IDP over IP.
-
-@item options PANICDELAY
-@itemx options PANICWAIT
-@findex PANICDELAY
-@findex PANICWAIT
-@cindex Kernel panics
-These options control whether the system waits after a panic. This is
-necessary on some systems which do not support crash dumps, so that the
-actual panic message can be read. The @samp{PANICDELAY} option inserts
-a delay of twenty seconds before self-destructing; the @samp{PANICWAIT}
-option instead waits for a key to be pressed on the console.
-
-@item options PCFS
-@findex PCFS
-@cindex MS-DOS filesystem
-@cindex Filesystems
-This option controls support for mounting MS-DOS disks and disk
-partitions under FreeBSD. The @samp{pcfs} manual page is presently very
-bogus.
-
-@item pseudo-device ppp @var{number}
-@findex ppp
-@cindex Point-To-Point Protocol
-@cindex Network interfaces
-The @samp{ppp} pseudo-device provides support for the Internet
-Point-to-Point protocol (RFC 1351 @i{et seq}), implemented as a line
-discipline over standard serial links. @var{number} should be the
-number of simultaneous PPP interfaces which will be configured.
-
-@item pseudo-device pty @var{number}
-@findex pty
-@cindex Pseudo-terminals
-This pseudo-device provides support for pseudo-ttys, which are required
-for @samp{rlogin}, @samp{telnet}, and @samp{xterm} to operate correctly;
-@var{number} should be set to the total number of these programs you
-expect to have running at any given time. Because pty's are not as yet
-dynamically allocated, and the underlying structures are large, it is
-best to keep this value as small as feasible, until this deficiency is
-remedied.
-
-@item options QUOTA
-@findex QUOTA
-@cindex Disk quotas
-@cindex Filesystems
-The @samp{QUOTA} option enables support for disk quotas. Note that NFS
-quota support is not available.
-
-@item pseudo-device sl @var{number}
-@findex sl
-@cindex Serial Line Internet Protocol
-@cindex SLIP
-@cindex CSLIP
-@cindex IP
-@cindex Network interfaces
-This pseudo-device provides support for the Serial Line Internet
-Protocol (RFC 1055), implemented as a line discipline over standard
-serial links. It includes support for Van Jacobson header compression.
-@var{number} should be the number of simultaneous SLIP interfaces which
-will be configured. See also the @samp{slattach} manual page.
-
-@item options SYSVSHM
-@item options SYSVSEM
-@item options SYSVMSG
-@itemx options SHMMAXPGS=@var{value}
-@findex SYSVSHM
-@findex SYSVSEM
-@findex SYSVMSG
-@findex SHMMAXPGS
-@cindex System V shared memory
-@cindex System V semaphores
-@cindex System V message queues
-@cindex System V IPC
-@cindex Shared memory, System V
-@cindex Semaphores, System V
-@cindex Message queues, System V
-@cindex IPC, System V
-The @samp{SYSVSHM} option enables kernel-side emulation of System
-V-compatible shared memory. The @samp{SHMMAXPGS} option (default 64
-pages or 256K) determines the maximum amount of shared memory available
-under this mechanism. The @samp{SYSVSEM} option provides emulation of
-System V-compatible semaphores, and likewise @samp{SYSVMSG} for message
-queues.
-
-@item options RMP
-@findex RMP
-@cindex Remote maintenance protocol
-@cindex Networking domains
-This option should control the inclusion of support for HP's remote
-maintenance protocol, but the source code is not included in FreeBSD at
-present, so enabling it will not result in any good.
-
-@item pseudo-device tb
-@findex tb
-@cindex Tablet line discipline
-The @samp{tb} pseudo-device provides support for the `tablet' line
-discipline. Nobody on the FreeBSD team actually has one of the tablets
-in question, so we have no idea if this actually works or not. It may
-not even compile.
-
-@item options "TCP_COMPAT_42"
-@findex TCP_COMPAT_42
-@cindex 4.2 Compatibility
-@cindex Compatibility options
-@cindex TCP
-This option controls the perpetuation of several bugs inherited from the
-4.2BSD implementation of TCP. It should only be defined in the
-circumstances outlined for @samp{COMPAT_42}, above.
-
-@item pseudo-device tun
-@findex tun
-@cindex Network interfaces
-The @samp{tun} driver provides a network interface which is attached to
-a character device. In this way, a user-mode program can grab packets
-out of the networking system, fiddle with them or move them around, and
-pass stuff packets back up into the kernel. It is not known if this
-device either compiles or operates correctly, although it was believed
-to do both at some time in the past.
-
-@item options UCONSOLE
-@findex UCONSOLE
-@cindex Console redirection
-This option allows any old user to grab kernel output away from the
-console and send it to the tty of their choice. It presents an
-incredile security hole for some systems, but is necessary in order to
-allow programs like @samp{xconsole} to operate. (The alternative,
-making @samp{xconsole} set-uid root, opens the exact same security
-hole.)
-
-@item options XE
-@findex XE
-@cindex X.25
-@cindex IEEE 802.2 LLC
-@cindex Network interfaces
-@cindex Ethernet
-This option should control the inclusion of support for running X.25
-over IEEE 802.2 LLC class 2, but that code was not included in the
-Networking/2 release, so enabling it will disable kernel compilation.
-Requires @samp{CCITT}.
-
-@item options XSERVER
-@findex XSERVER
-@cindex X Window System
-This obsolescent option enables support in the @samp{pc} console
-driver for certain operations required by the XFree86 server.
-@end table
-
-@node Performance, Devices, Subsystems, Top
-@c node,next,prev,up
-
-@chapter Performace and Debugging Options
-
-The following options are provided for system performace optimization.
-Note that kernel profiling is supported via the @samp{-p} option to the
-@samp{config} command; for more information see the @samp{config} manual
-page.
-
-@table @code
-@item psuedo-device ddb
-@findex ddb
-@cindex Kernel debugger
-@cindex Debugger, kernel
-This option enables the @samp{ddb} debugger, taken from Mach. See the
-@samp{ddb} and @samp{dbsym} manual pages for more information on the use
-of this debugger.
-
-@item options DIAGNOSTIC
-@itemx options NAMEI_DIAGNOSTIC
-@itemx options PARANOID
-@findex DIAGNOSTIC
-@findex NAMEI_DIAGNOSTIC
-@findex PARANOID
-@cindex Debugging options
-These debugging options reduce performace. They are intended to enable
-certain internal consistency checks which are not supposed to fail
-during correct operation, and so are normally disabled for performace
-reasons.
-
-@item options FASTLINKS
-@findex FASTLINKS
-@cindex Symbolic links
-@cindex Filesystems
-The @samp{FASTLINKS} option enables the creation of symbolic links whose
-target names reside entirely within the i-node of the link, when
-possible. This results in faster access for those links which are short
-enough (in practice, most of them). All kernels can read such links,
-but only @samp{FASTLINKS} kernels will create them, for compatibility
-with older kernels lacking such support.
-
-@item options ICMPPRINTFS
-@findex ICMPPRINTFS
-@cindex Debugging options
-@cindex ICMP
-This option is defined to allow debugging of ICMP (@dfn{Internet Control
-Message Protocol}) packets in the kernel. When defined and the
-@samp{icmpprintfs} kernel variable (default false) is set to true, ICMP
-packets will be printed out to the console when received. Note that it
-is probably better to use @samp{tcpdump} for this kind of debugging.
-
-@item options KGDB
-@findex KGDB
-@cindex Kernel debugger
-@cindex Debugger, kernel
-@cindex Remote debugging
-The @samp{KGDB} option enables certain bits of kernel code which will
-eventually be able to talk to a remote copy of the @samp{gdb} debugger
-over a serial connection. The present code does not work, but users are
-invited to hack on it and contribute the changes back to the FreeBSD
-team.
-
-@item options MCLSHIFT=@var{value}
-@findex MCLSHIFT
-@cindex Network parameters
-This option controls the number of bytes in an mbuf cluster, which is
-one of the basic units through which network data is managed. It is
-equal to the log base two of @samp{MCLBYTES}, the size of an mbuf
-cluster, and defaults to eleven (for an @samp{MCLBYTES} of 2048). It
-will likely eventually be bumped up to twelve (4096), so that the
-network code can take advantage of page flipping to reduce the numer of
-copies necessary.
-
-@item options SUBNETSARELOCAL
-@findex SUBNETSARELOCAL
-@cindex TCP
-@cindex Network parameters
-This option controls whether the TCP system believes that machines on
-other subnets of your network are considered to be ``local'' to your
-host. For most systems, this option should be on (the default); if you
-are directly connected to a class A network, however, then it may need
-to be turned off. (This is true of networks like the MILNET.)
-
-@item options "SYMTAB_SPACE=@var{value}"
-@findex SYMTAB_SPACE
-@cindex Debugger, kernel
-@cindex Kernel debugger
-This obsolescent option controls the amount of space that will be
-statically allocated in the debugger source code to hold the kernel
-symbol table that @samp{dbsym} sticks there. Eventually this will be
-dynamically allocated at load time. The default @var{value} is 63000
-bytes.
-@end table
-
-@node Devices, Internals, Performance, Top
-
-@chapter Device Options
-
-There are different device selections available depending on the type of
-bus present in your computer. We will cover generic FreeBSD devices,
-ISA-bus devices, and EISA-bus devices. A separate section describes the
-devices available in the SCSI subsystem.
-
-@menu
-* Generic:: Devices available in all FreeBSD systems.
-* ISA:: Devices specific to the ISA bus.
-* EISA:: Devices specific to the EISA bus.
-* MCA:: No support for Micro Channel, yet.
-* PCI:: No support for PCI, yet.
-* SCSI:: The SCSI subsystem.
-@end menu
-
-@node Generic, ISA,, Devices
-@section Generic Devices and Options
-
-The following devices and options are available in all FreeBSD
-configurations. In addition to these devices, a selection of ISA
-devices (@pxref{ISA}) is required in order to generate a workable
-system.
-
-@table @code
-@item machine "i386"
-@findex i386
-This mandatory declaration informs the @samp{config} program that you
-are using an i386 or compatible CPU, and enables the selection of all
-the other devices listed here.
-
-@item cpu "I386_CPU"
-@itemx cpu "I486_CPU"
-@findex I386_CPU
-@findex I486_CPU
-These two options control which specific CPUs will be supported by the
-generated kernel. If the kernel detects that it is not running on a CPU
-for which support was enabled, it will panic quickly upon startup. If
-you do not expect to need to run your kernel on an i386 or similar CPU,
-leaving out that support can increase virtual memory system performance.
-
-@item options "MATH_EMULATE"
-@findex MATH_EMULATE
-@cindex Floating-point emulator
-@cindex i387
-When this option is defined, the math coprocessor emulator is compiled
-into the kernel. When it is not defined and the coprocessor is absent,
-programs which use floating-point operations are automatically killed.
-
-@item device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
-@findex npx
-@cindex i386
-The @samp{npx} device provides support for the i387 numeric coprocessor
-and the floating-point portions of the i486 CPU. This will eventually
-be fixed to not require ISA to be configured.
-
-@item pseudo-device speaker
-@findex speaker
-The @samp{speaker} pseudo-device provides support for rudimentary access
-to the PC's speaker via @file{/dev/spkr}. It provides a
-character-device interface which interprets @samp{PLAY} strings similar
-to IBM PC Advanced BASIC, as well as an @samp{ioctl} interface with more
-fine-grained control. See the @samp{spkr} manual page for more
-information.
-@end table
-
-@node ISA, EISA, Generic, Devices
-@section ISA-bus Devices and Options
-
-The following options are specific to ISA-bus devices and systems.
-Since the EISA bus is backwards-compatible with the ISA bus, all these
-options also apply to EISA systems. The same goes for VESA Local Bus
-(VL-Bus) systems.
-
-@table @code
-@item controller isa0
-@findex isa
-This @strong{mandatory} declaration must precede any other devices
-listed in this section. It provides the basic support for the ISA-bus
-glue logic, including DMA and autoconfiguration.
-
-@item controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
-@findex aha
-@cindex Adaptec 154x
-@cindex SCSI host adaptors
-The @samp{aha} device supports the Adaptec 154x series of SCSI
-controllers, and attempts to support other vendors' controllers which
-claim compatibility with the Adaptec 1542, such as the BusLogic 545.
-This device is included in the @samp{GENERICAH} distribution kernel.
-The @samp{scbus} device (@pxref{SCSI}) is a prerequisite for this
-device.
-
-@item controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
-@findex bt
-@cindex Bustek 742
-@cindex SCSI host adaptors
-This device supports the Bustek 742 SCSI controller. It is included in
-the @samp{GENERICBT} distribution kernel; the @samp{scbus} device
-(@pxref{SCSI}) is a prerequisite.
-
-@item options COM_BIDIR
-@findex COM_BIDIR
-@cindex Bi-directional serial ports
-@cindex Serial ports
-This option enables bi-directional support in the @samp{sio} serial
-driver. This option is slated for removal, at which time bi-directional
-support will always be enabled. See the @samp{comcontrol} manual page
-for more information.
-
-@item options COM_MULTIPORT
-@findex COM_MULTIPORT
-@cindex Multi-port serial boards
-@cindex Serial ports
-This option enables support in the @samp{sio} serial driver for certain
-multi-port serial boards.
-
-@item device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
-@itemx device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
-@findex ed
-@cindex Western Digital 80x3
-@cindex 3Com 3C503
-@cindex Novel NE1000/NE2000
-@cindex Network interfaces
-@cindex Ethernet
-The @samp{ed} network interface driver provides support for the Western
-Digital/SMC 80x3 series, the 3Com 3c503, and Novell NE1000 and NE2000
-series of Ethernet controllers. It automatically detects differences
-among the various versions of these controllers and adapts
-appropriately. The @samp{ed1} line shown is for the Novell boards; the
-@samp{ed0} line is appropriate for all other supported controllers.
-(The Novell controllers cannot be configured to use port 0x280.)
-
-@item controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
-@itemx disk fd0 at fdc0 drive 0
-@itemx disk fd1 at fdc0 drive 1
-@itemx tape ft0 at fdc0 drive 2
-@findex fd
-@findex ft
-@cindex Floppy disk
-@cindex Floppy tape
-@cindex QIC-80
-@cindex Tape drives
-@cindex Cartridge tape drives
-@cindex Quarter-Inch-Cartridge (QIC) tape drives
-@cindex Disk drives
-The @samp{fdc} driver provides support for the standard PC floppy-disk
-controller. The @samp{fd} sub-driver supports 3.5-- and 5.25-inch
-floppy disks in the standard 360KB, 720KB, 1200KB, 1440KB, and 2880KB
-formats, as well as a number of other formats not supported by DOS. The
-@samp{ft} driver is available for QIC-80 ``floppy tape'' support.
-The drivers support formatting of both tapes and disks. This driver is
-substantially improved from that shipped in previous releases of
-FreeBSD.
-
-@item device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
-@findex ie
-@cindex AT&T EN100
-@cindex AT&T StarLAN 10
-@cindex Network interfaces
-@cindex Ethernet
-@cindex StarLAN
-This network interface driver provides support for the AT&T StarLAN 10
-and EN100 family of controllers. Note that the configuration specified
-here is not the default configuration, but one which attempts to deal
-with the conflicts that arise in more modern systems. (It is expected
-that this driver will be expanded in the future to support other similar
-cards in the manner of @samp{ed}.)
-
-@item device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
-@findex is
-@cindex Isolan 4141-0
-@cindex Isolink 4110
-@cindex Ethernet
-@cindex Network interfaces
-The @samp{is} network interface driver supports the Isolan 4141-0 and
-Isolink 4110 Ethernet controllers.
-
-@c @item device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 \
-@c @itemx vector ixintr
-@c @findex ix
-@c @cindex Intel EtherEXPRESS
-@c @cindex Ethernet
-@c @cindex Network interfaces
-@c This device is known to exist, but is not presently in the FreeBSD
-@c source tree. When it is made available, this information will be
-@c updated.
-
-@item device lpa0 at isa? port "IO_LPT1" tty
-@itemx device lpt0 at isa? port "IO_LPT1" tty irq 7 vector lptintr
-@findex lpa
-@findex lpt
-@cindex Parallel printers
-The @samp{lpa} device provides support for the parallel printer driver
-accessed as @file{/dev/lp}. The @samp{lpt} driver provides the same
-functionality, but only works with those printer controllers which
-support interrupt-driven operations. If you receive @samp{ISA strayintr
-7} messages correlated with the use of the @samp{lpa} driver, chances
-are that your controller supports interrupt-driven operation, and you
-should switch to the @samp{lpt} driver.
-
-The @samp{lpa} driver is obsolete, and will be removed in release 1.2,
-to be replaced by special flags to the @samp{lpt} driver.
-
-@item device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
-@findex mcd
-@cindex Mitsumi CD-ROM
-@cindex CD-ROM
-This device provides support for the Mitsumi non-SCSI CD-ROM drive.
-Performance is known to be quite slow.
-
-@c mse, anyone?
-
-@item device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
-@itemx device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
-@itemx options NCONS=@var{value}
-@itemx options COMCONSOLE
-@findex pc
-@findex sc
-@findex NCONS
-@findex COMCONSOLE
-@cindex Console devices
-@cindex pccons
-@cindex Syscons
-@cindex Virtual consoles
-@cindex X Window System
-The @samp{pc} and @samp{sc} devices provide support for the system
-display and keyboard, which is the default console. There might
-actually be documentation somewhere for both of these. The @samp{sc}
-device requires the @samp{NCONS} option to be defined to some value; it
-represents the number of virtual consoles to be provided by the driver;
-a reasonable value is 8. One of @samp{pc} or @samp{sc} is presently
-required unless @samp{COMSONSOLE} is enabled, in which case a serial
-port is made into the console.
-
-@c sb, anyone?
-
-@item device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
-@itemx device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
-@itemx device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
-@itemx device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
-@findex sio
-@cindex Serial ports
-@cindex National 8250/16450/16550
-@cindex Bi-directional serial ports
-@cindex Multi-port serial boards
-The @samp{sio} driver provides support for high-speed serial
-communications using the standard 8250, 16450, and 16550 UART chips. It
-provides a standard tty interface for these devices as
-@file{/dev/tty@var{unit}}, and, when enabled with the @samp{comcontrol}
-program, a call-out capability as @file{/dev/cua@var{unit}} (@var{unit}
-is two digits, zero-padded in both cases). Certain multi-port systems
-are also supported.
-
-@item device uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
-@findex uha
-@cindex Ultrastor 14F
-@cindex Ultrastor 34F
-@cindex SCSI host adaptors
-This device supports the Ultrastor 14F and related SCSI controllers. It
-is included in the @samp{GENERICBT} distribution kernel, and requires
-@samp{scbus} (@pxref{SCSI}) as a prerequisite. The Ultrastor 24F is not
-supported.
-
-@item controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
-@itemx disk wd0 at wdc0 drive 0
-@itemx disk wd1 at wdc0 drive 1
-@findex wd
-@cindex Western Digital WD100x
-@cindex ST-506 hard disks
-@cindex RLL hard disks
-@cindex ESDI hard disks
-@cindex IDE hard disks
-@cindex Disk drives
-The @samp{wd} device supports standard ST-506, RLL, ESDI, and IDE hard
-disks, as controlled by the Western Digital WD100x series of controllers
-(and compatible hardware). This version is substantially improved from
-that provided in FreeBSD 1.0.
-
-@item device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
-@findex wt
-@cindex Archive QIC-02
-@cindex Wangtek QIC-02
-@cindex Cartridge tape drives
-@cindex QIC-02
-@cindex QIC-36
-@cindex Tape drives
-@cindex Quarter-Inch-Cartridge (QIC) tape drives
-This driver supports Archive QIC-02 and Wangtek QIC-02 and QIC-36
-cartridge tape controllers.
-@end table
-
-@node EISA, MCA, ISA, Devices
-@section EISA-bus Devices and Options
-
-There is presently only one EISA-specific device driver.
-
-@table @code
-@item controller ahb0 at isa? bio irq 11 vector ahbintr
-@findex ahb
-@cindex Adaptec 174x
-@cindex SCSI host adaptors
-The @samp{ahb} driver provides support for the Adaptec AHA-174x series
-of SCSI controllers. This controller is included in the
-@samp{GENERICAH} distribution kernel, and requires the @samp{scbus}
-driver (@pxref{SCSI}) as a prerequisite.
-@end table
-
-@node MCA, PCI, EISA, Devices
-@section Micro Channel Devices and Options
-
-@cindex Micro Channel Architecture
-We don't support Micro Channel right now. Anyone interested in working
-on Micro Channel support should send mail to
-@samp{FreeBSD-Questions@@freefall.cdrom.com} for information on how to
-help.
-
-@node PCI, SCSI, MCA, Devices
-@section PCI Devices and Options
-
-@cindex PCI
-We don't support PCI, either. Anyone interested in working on PCI
-support should send mail to @samp{FreeBSD-Questions@@freefall.cdrom.com}
-for information on how to help.
-
-@node SCSI,, PCI, Devices
-@section The SCSI Subsystem
-
-The SCSI subsystem consists of a set of adaptor-specific driver
-routines, which were described in the previous sections, and the generic
-SCSI device drivers, which handle the standardized interactions with
-devices on the SCSI bus.
-
-@c devices: cd, ch, scbus, sd, sg, st
-
-@table @code
-@item device cd0
-@findex cd
-@cindex CD-ROM
-@cindex SCSI devices
-The @samp{cd} device provides support for CD-ROM drives. Only one
-@samp{cd} device need be configured, as the driver automatically
-allocates units for each CD-ROM drive found. Playing of audio CDs is
-also supported, on drives which support it, through @code{ioctl} calls.
-Support for retrieval of CD audio over the SCSI bus is not presently
-available.
-
-@item device ch0
-@findex ch
-@cindex Media changers
-@cindex SCSI devices
-The @samp{ch} driver supports SCSI media changers; this may include
-tape, removable disk, and CD changers. One @samp{ch} device should be
-configured for each changer you expect to support.
-
-@item device scbus0
-@findex scbus
-@cindex SCSI bus management
-This driver forms the core of the SCSI subsystem. It provides the
-device-independent routines that manage SCSI transactions, keep track of
-attached devices, and act as glue between SCSI-device-specific drivers
-and system-specific host adaptors. This device is @emph{mandatory} for
-all SCSI systems.
-
-@item device sd0
-@findex sd
-@cindex SCSI devices
-@cindex Disk drives
-The @samp{sd} driver provides access to non-removable SCSI disks. One
-@samp{sd} device should be defined for each disk you expect to have
-simultaneously connected to the system.
-
-@c @item device sg0
-@c @findex sg
-@c @cindex SCSI devices
-@c @cindex Generic SCSI
-@c @cindex Unsupported SCSI devices
-@c This driver provides support for development of user-mode drivers and
-@c other programs which access the SCSI bus directly. One @samp{sg} device
-@c should be defined for each @emph{host adaptor} you have installed in
-@c your system.
-
-@item device st0
-@findex st
-@cindex SCSI devices
-@cindex Tape drives
-@cindex Quarter-Inch-Cartridge (QIC) tape drives
-The @samp{st} driver supports generic SCSI tape drives. One @samp{st}
-device should be defined for each tape drive you wish to access. See
-the @samp{st} manual page for information about how to manipulate the
-parameters of this device.
-
-@item device uk0
-@findex uk
-@cindex SCSI devices
-@cindex Unknown SCSI devices
-The @samp{uk} driver provides an attachment point for all otherwise
-unrecognized SCSI devices. You can't actually do anything with such a
-device, except perhaps send it an inquiry command using the @samp{scsi}
-program (q.v.).
-@end table
-
-@node Internals, Index, Devices, Top
-
-@chapter Internal Use Only
-
-Eventually, this chapter will document some of the kernel manifest
-constants which are not defines, but which can be tweaked in various
-header files.
-
-@node Index,, Internals, Top
-@appendix General Index
-
-Items in @code{typewriter} font are option or device names.
-
-@printindex cp
-
-@bye
diff --git a/sys/i386/doc/sound.doc b/sys/i386/doc/sound.doc
deleted file mode 100644
index 7f5b9da64e6d..000000000000
--- a/sys/i386/doc/sound.doc
+++ /dev/null
@@ -1,38 +0,0 @@
-To enable sound card support, you need to add one or more of the following
-lines to your kernel configuration file:
-
-device snd5 at isa? port 0x330 irq 6 drq 0 vector mpuintr
-device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
-device snd3 at isa? port 0x388 irq 12 drq 3 vector pasintr
-device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
-device snd1 at isa? port 0x388 irq 0 drq 0 vector sbintr
-
- Unit numbers are:
- 1 for Yamaha FM synth
- 2 for SB/SB Pro DSP
- 3 for PAS PCM and Midi
- 4 for GUS
- 5 for MPU-401
-
- If you have ProAudioSpectrum, uncomment units 3 and 2.
- If you have SoundBlaster, uncomment 2 and 1.
- If you have GravisUltrasound, uncomment 4
- If you have MPU-401, uncomment 5
-
-NOTE: The MPU-401 driver may or may not work, and is unfortunately
-unverifiable since no one I know has one. If you can test this,
-please let me know! Also note that you will have to change these
-settings if your soundcard is set for a non-standard address or IRQ.
-Please check your documentation (or verify with any provided DOS utilities
-that may have come with your card) and set the IRQ or address fields
-accordingly.
-
-
-Also: Some systems with the OPTI chipset will require you to #define
-BROKEN_BUS_CLOCK in /sys/i386/sound/pas2_card.c. Symptoms are that
-you will hear a lot of clicking and popping sounds, like a geiger counter,
-coming out of the PAS even when is not playing anything.
-
-
-
- - Jordan Hubbard (jkh@freefall.cdrom.com)
diff --git a/sys/i386/doc/vm_layout.doc b/sys/i386/doc/vm_layout.doc
deleted file mode 100644
index 3734fd8ab088..000000000000
--- a/sys/i386/doc/vm_layout.doc
+++ /dev/null
@@ -1,32 +0,0 @@
-Physical Memory Layout:
-
-NOT YET DONE
-
-
-
-Virtual Memory Layout:
-
-Page Table Directories, and how they relate to the vm address space
-Note: PTDI stands for Page Table Directory Index.
-
-PTDI Address pmap.h/param.h Calculation to locate it in vm space
---------------------------------------------------------------------------------
- FFFFF000 APTD APTmap + (APTDPTDI * NBPG)
- FFC00000 APTmap APTDPTDI << PDRSHIFT
-3FF FFC00000 APTDPTDI #define (NPTEPG-1)
- FFBFFFFF KERNEND ((KPTDI+NKPDE) << PDRSHIFT) - 1
-3FD FF400000 .
-3FC FF000000 .
-3FB FEC00000 .
-3FA FE800000 .
-3F9 FE400000 .
- FE000000 KERNBASE KPTDI << PDRSHIFT
-3F8 FE000000 KPTDI #define (APTDPTDI-NKPDE)
- FDFF8000 Sysmap PTmap + (KPTDI * NBPG)
- FDFF7FF8 APTpde PTD + (APTDPTDI * sizeof(pde))
- FDFF7FDC PTDpde PTD + (PTDPTDI * sizeof(pde))
- FDFF7000 PTD PTmap + (PTDPTDI * NBPG)
- FDC00000 PTmap PTDPTDI << PDRSHIFT
-3F7 FDC00000 PTDPTDI #define (KPTDI-1)
-
-$Id: vm_layout.doc,v 1.6 1993/10/16 19:25:07 rgrimes Exp $
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
index 7584c02b353e..5b571a04432c 100644
--- a/sys/i386/i386/autoconf.c
+++ b/sys/i386/i386/autoconf.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
- * $Id: autoconf.c,v 1.8.2.1 1994/03/23 23:45:08 rgrimes Exp $
+ * $Id: autoconf.c,v 1.11 1994/03/21 15:02:47 ache Exp $
*/
/*
@@ -79,6 +79,11 @@ configure()
isa_configure();
#endif
+#include "pci.h"
+#if NPCI > 0
+ pci_configure();
+#endif
+
#if GENERICxxx && !defined(DISKLESS)
if ((boothowto & RB_ASKNAME) == 0)
setroot();
diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c
index b1ed3063a3b1..8e0bf2673c3a 100644
--- a/sys/i386/i386/conf.c
+++ b/sys/i386/i386/conf.c
@@ -41,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)conf.c 5.8 (Berkeley) 5/12/91
- * $Id: conf.c,v 1.20.2.1 1994/05/04 07:45:12 rgrimes Exp $
+ * $Id: conf.c,v 1.28 1994/05/30 03:35:53 ache Exp $
*/
#include "param.h"
@@ -213,6 +213,7 @@ struct bdevsw bdevsw[] =
cddump, cdsize, 0 },
{ mcdopen, mcdclose, mcdstrategy, mcdioctl, /*7*/
mcddump, mcdsize, 0 },
+ { 0, } /* block major 8 is reserved for local use */
/*
* If you need a bdev major number, please contact the FreeBSD team
* by sending mail to "FreeBSD-hackers@freefall.cdrom.com".
@@ -236,7 +237,7 @@ d_close_t pcclose;
d_rdwr_t pcread, pcwrite;
d_ioctl_t pcioctl;
d_mmap_t pcmmap;
-extern struct tty pccons;
+extern struct tty *pccons;
/* controlling TTY */
d_open_t cttyopen;
@@ -262,7 +263,7 @@ d_close_t ptcclose;
d_rdwr_t ptcread, ptcwrite;
d_select_t ptcselect;
d_ioctl_t ptyioctl;
-extern struct tty pt_tty[];
+extern struct tty *pt_tty[];
#else
#define ptsopen (d_open_t *)enxio
#define ptsclose (d_close_t *)enxio
@@ -285,9 +286,8 @@ d_close_t comclose;
d_rdwr_t comread;
d_rdwr_t comwrite;
d_ioctl_t comioctl;
-d_select_t comselect;
#define comreset (d_reset_t *)enxio
-extern struct tty com_tty[];
+extern struct tty *com_tty[];
#else
#define comopen (d_open_t *)enxio
#define comclose (d_close_t *)enxio
@@ -295,7 +295,6 @@ extern struct tty com_tty[];
#define comwrite (d_rdwr_t *)enxio
#define comioctl (d_ioctl_t *)enxio
#define comreset (d_reset_t *)enxio
-#define comselect (d_select_t *)enxio
#define com_tty NULL
#endif
@@ -401,33 +400,15 @@ d_ioctl_t bpfioctl;
#define bpfioctl (d_ioctl_t *)enxio
#endif
-#include "dcfclk.h"
-#if NDCFCLK > 0
-d_open_t dcfclkopen;
-d_close_t dcfclkclose;
-d_rdwr_t dcfclkread;
-d_ioctl_t dcfclkioctl;
-d_select_t dcfclkselect;
-#else
-#define dcfclkopen (d_open_t *)enxio
-#define dcfclkclose (d_close_t *)enxio
-#define dcfclkread (d_rdwr_t *)enxio
-#define dcfclkioctl (d_ioctl_t *)enxio
-#define dcfclkselect (d_select_t *)enxio
-#endif
-
-#include "lpa.h"
-#if NLPA > 0
-d_open_t lpaopen;
-d_close_t lpaclose;
-d_rdwr_t lpawrite;
-d_ioctl_t lpaioctl;
-#else
+/*
+ * lpa has been removed from the tree,
+ * but the major dev no for it still remains.
+ * (lpt now provides all the functionality which lpa used to.)
+ */
#define lpaopen (d_open_t *)enxio
#define lpaclose (d_close_t *)enxio
#define lpawrite (d_rdwr_t *)enxio
#define lpaioctl (d_ioctl_t *)enxio
-#endif
#include "speaker.h"
#if NSPEAKER > 0
@@ -442,6 +423,21 @@ d_ioctl_t spkrioctl;
#define spkrioctl (d_ioctl_t *)enxio
#endif
+#include "pca.h"
+#if NPCA > 0
+d_open_t pcaopen;
+d_close_t pcaclose;
+d_rdwr_t pcawrite;
+d_ioctl_t pcaioctl;
+d_select_t pcaselect;
+#else
+#define pcaopen (d_open_t *)enxio
+#define pcaclose (d_close_t *)enxio
+#define pcawrite (d_rdwr_t *)enxio
+#define pcaioctl (d_ioctl_t *)enxio
+#define pcaselect (d_select_t *)enxio
+#endif
+
#include "mse.h"
#if NMSE > 0
d_open_t mseopen;
@@ -464,7 +460,7 @@ d_ioctl_t sioioctl;
d_select_t sioselect;
d_stop_t siostop;
#define sioreset (d_reset_t *)enxio
-extern struct tty sio_tty[];
+extern struct tty *sio_tty[];
#else
#define sioopen (d_open_t *)enxio
#define sioclose (d_close_t *)enxio
@@ -544,7 +540,7 @@ struct cdevsw cdevsw[] =
logselect, nommap, NULL },
{ comopen, comclose, comread, comwrite, /*8*/
comioctl, nostop, comreset, com_tty, /* com */
- comselect, nommap, NULL },
+ ttselect, nommap, NULL },
{ Fdopen, fdclose, rawread, rawwrite, /*9*/
fdioctl, nostop, nullreset, NULL, /* Fd (!=fd) */
seltrue, nommap, fdstrategy },
@@ -590,9 +586,9 @@ struct cdevsw cdevsw[] =
{ bpfopen, bpfclose, bpfread, bpfwrite, /*23*/
bpfioctl, nostop, nullreset, NULL, /* bpf */
bpfselect, nommap, NULL },
- { dcfclkopen, dcfclkclose, dcfclkread, nowrite, /*24*/
- dcfclkioctl, nostop, nullreset, NULL, /* dcfclk */
- dcfclkselect, nommap, NULL },
+ { pcaopen, pcaclose, noread, pcawrite, /*24*/
+ pcaioctl, nostop, nullreset, NULL, /* pcaudio */
+ pcaselect, nommap, NULL },
{ lpaopen, lpaclose, noread, lpawrite, /*25*/
lpaioctl, nullstop, nullreset, NULL, /* lpa */
seltrue, nommap, NULL },
@@ -614,6 +610,7 @@ struct cdevsw cdevsw[] =
{ ukopen, ukclose, noread, nowrite, /*31*/
ukioctl, nostop, nullreset, NULL, /* unknown */
seltrue, nommap, NULL }, /* scsi */
+ { 0, } /* character device 32 is reserved for local use */
/*
* If you need a cdev major number, please contact the FreeBSD team
* by sending mail to `freebsd-hackers@freefall.cdrom.com'.
diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c
index 7e68844e4ade..aeeedbecdac1 100644
--- a/sys/i386/i386/db_interface.c
+++ b/sys/i386/i386/db_interface.c
@@ -23,7 +23,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
- * $Id: db_interface.c,v 1.5 1993/12/19 00:50:00 wollman Exp $
+ * $Id: db_interface.c,v 1.7 1994/06/22 05:52:28 jkh Exp $
*/
/*
@@ -178,8 +178,6 @@ db_read_bytes(addr, size, data)
db_nofault = 0;
}
-struct pte *pmap_pte(pmap_t, vm_offset_t);
-
/*
* Write bytes to kernel address space for debugger.
*/
@@ -234,9 +232,24 @@ db_write_bytes(addr, size, data)
}
}
+/*
+ * XXX move this to machdep.c and allow it to be called iff any debugger is
+ * installed.
+ * XXX msg is not printed.
+ */
void
Debugger (msg)
const char *msg;
{
- asm ("int $3");
+ static volatile u_char in_Debugger;
+
+ if (!in_Debugger) {
+ in_Debugger = 1;
+#ifdef __GNUC__
+ asm("int $3");
+#else
+ int3();
+#endif
+ in_Debugger = 0;
+ }
}
diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s
index aa2e3d940fd1..f247c0a233af 100644
--- a/sys/i386/i386/exception.s
+++ b/sys/i386/i386/exception.s
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: exception.s,v 1.2 1994/01/03 07:55:20 davidg Exp $
+ * $Id: exception.s,v 1.3 1994/04/02 07:00:23 davidg Exp $
*/
#include "npx.h" /* NNPX */
@@ -39,7 +39,9 @@
#include "errno.h" /* error return codes */
-#include "i386/isa/debug.h" /* BDE debugging macros */
+#include "machine/spl.h" /* SWI_AST_MASK ... */
+
+#include "machine/psl.h" /* PSL_I */
#include "machine/trap.h" /* trap codes */
#include "syscall.h" /* syscall numbers */
@@ -57,31 +59,49 @@
/*****************************************************************************/
/*
* Trap and fault vector routines
- *
+ */
+#define IDTVEC(name) ALIGN_TEXT ; .globl _X/**/name ; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp _alltraps
+
+/*
* XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
* control. The sti's give the standard losing behaviour for ddb and kgdb.
*/
-#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name:
-#define TRAP(a) pushl $(a) ; jmp alltraps
+#ifdef BDE_DEBUGGER
+#define BDBTRAP(name) \
+ ss ; \
+ cmpb $0,_bdb_exists ; \
+ je 1f ; \
+ testb $SEL_RPL_MASK,4(%esp) ; \
+ jne 1f ; \
+ ss ; \
+ .globl bdb_/**/name/**/_ljmp ; \
+bdb_/**/name/**/_ljmp: ; \
+ ljmp $0,$0 ; \
+1:
+#else
+#define BDBTRAP(name)
+#endif
+
#ifdef KGDB
-# define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; \
+ pushl $(a) ; jmp _bpttraps
#else
-# define BPTTRAP(a) sti; TRAP(a)
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; TRAP(a)
#endif
+MCOUNT_LABEL(user)
+MCOUNT_LABEL(btrap)
+
IDTVEC(div)
pushl $0; TRAP(T_DIVIDE)
IDTVEC(dbg)
-#if defined(BDE_DEBUGGER) && defined(BDBTRAP)
BDBTRAP(dbg)
-#endif
pushl $0; BPTTRAP(T_TRCTRAP)
IDTVEC(nmi)
pushl $0; TRAP(T_NMI)
IDTVEC(bpt)
-#if defined(BDE_DEBUGGER) && defined(BDBTRAP)
BDBTRAP(bpt)
-#endif
pushl $0; BPTTRAP(T_BPTFLT)
IDTVEC(ofl)
pushl $0; TRAP(T_OFLOW)
@@ -114,22 +134,24 @@ IDTVEC(fpu)
* error. It would be better to handle npx interrupts as traps but
* this is difficult for nested interrupts.
*/
- pushl $0 /* dummy error code */
- pushl $T_ASTFLT
+ pushl $0 /* dumby error code */
+ pushl $0 /* dumby trap type */
pushal
- nop /* silly, the bug is for popal and it only
- * bites when the next instruction has a
- * complicated address mode */
pushl %ds
pushl %es /* now the stack frame is a trap frame */
movl $KDSEL,%eax
movl %ax,%ds
movl %ax,%es
- pushl _cpl
+ FAKE_MCOUNT(12*4(%esp))
+ movl _cpl,%eax
+ pushl %eax
pushl $0 /* dummy unit to finish building intr frame */
incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,%eax
+ movl %eax,_cpl
call _npxintr
- jmp doreti
+ MEXITCOUNT
+ jmp _doreti
#else /* NNPX > 0 */
pushl $0; TRAP(T_ARITHTRAP)
#endif /* NNPX > 0 */
@@ -166,25 +188,37 @@ IDTVEC(rsvd14)
pushl $0; TRAP(31)
SUPERALIGN_TEXT
-alltraps:
+_alltraps:
pushal
- nop
pushl %ds
pushl %es
movl $KDSEL,%eax
movl %ax,%ds
movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
calltrap:
+ FAKE_MCOUNT(_btrap) /* init "from" _btrap -> calltrap */
incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,_cpl
call _trap
/*
- * Return through doreti to handle ASTs. Have to change trap frame
+ * There was no place to save the cpl so we have to recover it
+ * indirectly. For traps from user mode it was 0, and for traps
+ * from kernel mode Oring SWI_AST_MASK into it didn't change it.
+ */
+ subl %eax,%eax
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ jne 1f
+ movl _cpl,%eax
+1:
+ /*
+ * Return via _doreti to handle ASTs. Have to change trap frame
* to interrupt frame.
*/
- movl $T_ASTFLT,TF_TRAPNO(%esp) /* new trap type (err code not used) */
- pushl _cpl
- pushl $0 /* dummy unit */
- jmp doreti
+ pushl %eax
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
#ifdef KGDB
/*
@@ -192,17 +226,18 @@ calltrap:
* to the regular trap code.
*/
SUPERALIGN_TEXT
-bpttraps:
+_bpttraps:
pushal
- nop
pushl %ds
pushl %es
movl $KDSEL,%eax
movl %ax,%ds
movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) /* non-kernel mode? */
jne calltrap /* yes */
call _kgdb_trap_glue
+ MEXITCOUNT
jmp calltrap
#endif
@@ -214,7 +249,6 @@ IDTVEC(syscall)
pushfl /* Room for tf_err */
pushfl /* Room for tf_trapno */
pushal
- nop
pushl %ds
pushl %es
movl $KDSEL,%eax /* switch to kernel segments */
@@ -222,51 +256,17 @@ IDTVEC(syscall)
movl %ax,%es
movl TF_ERR(%esp),%eax /* copy eflags from tf_err to fs_eflags */
movl %eax,TF_EFLAGS(%esp)
- movl $0,TF_ERR(%esp) /* zero tf_err */
+ FAKE_MCOUNT(12*4(%esp))
incl _cnt+V_SYSCALL
+ movl $SWI_AST_MASK,_cpl
call _syscall
/*
- * Return through doreti to handle ASTs.
+ * Return via _doreti to handle ASTs.
*/
- movl $T_ASTFLT,TF_TRAPNO(%esp) /* new trap type (err code not used) */
- pushl _cpl
- pushl $0
- jmp doreti
-
-#ifdef SHOW_A_LOT
-/*
- * 'show_bits' was too big when defined as a macro. The line length for some
- * enclosing macro was too big for gas. Perhaps the code would have blown
- * the cache anyway.
- */
- ALIGN_TEXT
-show_bits:
- pushl %eax
- SHOW_BIT(0)
- SHOW_BIT(1)
- SHOW_BIT(2)
- SHOW_BIT(3)
- SHOW_BIT(4)
- SHOW_BIT(5)
- SHOW_BIT(6)
- SHOW_BIT(7)
- SHOW_BIT(8)
- SHOW_BIT(9)
- SHOW_BIT(10)
- SHOW_BIT(11)
- SHOW_BIT(12)
- SHOW_BIT(13)
- SHOW_BIT(14)
- SHOW_BIT(15)
- popl %eax
- ret
-
- .data
-bit_colors:
- .byte GREEN,RED,0,0
- .text
-
-#endif /* SHOW_A_LOT */
+ pushl $0 /* cpl to restore */
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
/*
* include generated interrupt vectors and ISA intr code
diff --git a/sys/i386/i386/in_cksum.c b/sys/i386/i386/in_cksum.c
index 0dec1d67056d..0b3d3e5d9637 100644
--- a/sys/i386/i386/in_cksum.c
+++ b/sys/i386/i386/in_cksum.c
@@ -32,7 +32,7 @@
*
* from tahoe: in_cksum.c 1.2 86/01/05
* from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
- * $Id: in_cksum.c,v 1.4 1993/12/19 00:50:02 wollman Exp $
+ * $Id: in_cksum.c,v 1.5 1994/03/07 11:47:30 davidg Exp $
*/
#include "param.h"
@@ -56,9 +56,10 @@
* Thanks to gcc we don't have to guess
* which registers contain sum & w.
*/
-#define CLC asm("clc")
-#define ADD(n) asm("adcl " #n "(%2), %0": "=r"(sum): "0"(sum), "r"(w))
-#define MOP asm("adcl $0, %0": "=r"(sum): "0"(sum))
+#define ADD(n) asm("addl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
+#define ADDC(n) asm("adcl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
+#define LOAD(n) asm volatile("movb " #n "(%1), %0" : "=r" (junk) : "r" (w))
+#define MOP asm("adcl $0, %0" : "=r" (sum) : "0" (sum))
int
in_cksum(m, len)
@@ -114,28 +115,90 @@ in_cksum(m, len)
}
}
/*
+ * Advance to a 486 cache line boundary.
+ */
+ if (4 & (int) w && mlen >= 4) {
+ ADD(0);
+ MOP;
+ w += 2;
+ mlen -= 4;
+ }
+ if (8 & (int) w && mlen >= 8) {
+ ADD(0);
+ ADDC(4);
+ MOP;
+ w += 4;
+ mlen -= 8;
+ }
+ /*
* Do as much of the checksum as possible 32 bits at at time.
* In fact, this loop is unrolled to make overhead from
* branches &c small.
*/
+ mlen -= 1;
while ((mlen -= 32) >= 0) {
+ u_char junk;
/*
- * Clear the carry flag, add with carry 16 words
- * and fold-in last carry by adding a 0 with carry.
+ * Add with carry 16 words and fold in the last
+ * carry by adding a 0 with carry.
+ *
+ * The early ADD(16) and the LOAD(32) are to load
+ * the next 2 cache lines in advance on 486's. The
+ * 486 has a penalty of 2 clock cycles for loading
+ * a cache line, plus whatever time the external
+ * memory takes to load the first word(s) addressed.
+ * These penalties are unavoidable. Subsequent
+ * accesses to a cache line being loaded (and to
+ * other external memory?) are delayed until the
+ * whole load finishes. These penalties are mostly
+ * avoided by not accessing external memory for
+ * 8 cycles after the ADD(16) and 12 cycles after
+ * the LOAD(32). The loop terminates when mlen
+ * is initially 33 (not 32) to guaranteed that
+ * the LOAD(32) is within bounds.
*/
- CLC;
- ADD(0); ADD(4); ADD(8); ADD(12);
- ADD(16); ADD(20); ADD(24); ADD(28);
- MOP; w += 16;
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ LOAD(32);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ }
+ mlen += 32 + 1;
+ if (mlen >= 32) {
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ mlen -= 32;
}
- mlen += 32;
- while ((mlen -= 8) >= 0) {
- CLC;
- ADD(0); ADD(4);
+ if (mlen >= 16) {
+ ADD(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ MOP;
+ w += 8;
+ mlen -= 16;
+ }
+ if (mlen >= 8) {
+ ADD(0);
+ ADDC(4);
MOP;
w += 4;
+ mlen -= 8;
}
- mlen += 8;
if (mlen == 0 && byte_swapped == 0)
continue; /* worth 1% maybe ?? */
REDUCE;
@@ -172,4 +235,3 @@ in_cksum(m, len)
REDUCE;
return (~sum & 0xffff);
}
-
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
index 57ee6a93832d..d0317103d43e 100644
--- a/sys/i386/i386/locore.s
+++ b/sys/i386/i386/locore.s
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
- * $Id: locore.s,v 1.15 1994/02/01 04:08:54 davidg Exp $
+ * $Id: locore.s,v 1.20 1994/06/14 17:49:42 davidg Exp $
*/
/*
@@ -51,7 +51,6 @@
#include "machine/pte.h" /* page table entry definitions */
#include "errno.h" /* error return codes */
#include "machine/specialreg.h" /* x86 special registers */
-#include "i386/isa/debug.h" /* BDE debugging macros */
#include "machine/cputypes.h" /* x86 cpu type definitions */
#include "syscall.h" /* system call numbers */
#include "machine/asmacros.h" /* miscellaneous asm macros */
@@ -102,8 +101,10 @@ _esym: .long 0 /* ptr to end of syms */
.globl _boothowto,_bootdev,_curpcb
- .globl _cpu,_cold,_atdevbase
+ .globl _cpu,_cold,_atdevbase,_cpu_vendor,_cpu_id
_cpu: .long 0 /* are we 386, 386sx, or 486 */
+_cpu_id: .long 0
+_cpu_vendor: .space 17
_cold: .long 1 /* cold till we are not */
_atdevbase: .long 0 /* location of start of iomem in virtual */
_atdevphys: .long 0 /* location of device mapping ptes (phys) */
@@ -123,7 +124,7 @@ _proc0paddr: .long 0 /* address of proc 0 address space */
#ifdef BDE_DEBUGGER
.globl _bdb_exists /* flag to indicate BDE debugger is available */
-_bde_exists: .long 0
+_bdb_exists: .long 0
#endif
.globl tmpstk
@@ -140,10 +141,10 @@ tmpstk:
* btext: beginning of text section.
* Also the entry point (jumped to directly from the boot blocks).
*/
-ENTRY(btext)
+NON_GPROF_ENTRY(btext)
movw $0x1234,0x472 /* warm boot */
jmp 1f
- .space 0x500 /* skip over warm boot shit */
+ .org 0x500 /* space for BIOS variables */
/*
* pass parameters on stack (howto, bootdev, unit, cyloffset, esym)
@@ -151,7 +152,8 @@ ENTRY(btext)
* ( if we want to hold onto /boot, it's physical %esp up to _end)
*/
- 1: movl 4(%esp),%eax
+ 1:
+ movl 4(%esp),%eax
movl %eax,_boothowto-KERNBASE
movl 8(%esp),%eax
movl %eax,_bootdev-KERNBASE
@@ -164,30 +166,76 @@ ENTRY(btext)
movl _nfs_diskless_size-KERNBASE,%ecx
movl 20(%esp),%esi
movl $(_nfs_diskless-KERNBASE),%edi
+ cld
rep
movsb
#endif
- /* find out our CPU type. */
- pushfl
- popl %eax
- movl %eax,%ecx
- xorl $0x40000,%eax
- pushl %eax
- popfl
- pushfl
- popl %eax
- xorl %ecx,%eax
- shrl $18,%eax
- andl $1,%eax
- push %ecx
- popfl
-
- cmpl $0,%eax
- jne 1f
- movl $CPU_386,_cpu-KERNBASE
+ /* don't trust what the BIOS gives for eflags */
+ pushl $PSL_MBO
+ popfl
+
+ /* Find out our CPU type. */
+
+ /* Try to toggle alignment check flag; does not exist on 386. */
+ pushfl
+ popl %eax
+ movl %eax,%ecx
+ orl $PSL_AC,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ xorl %ecx,%eax
+ andl $PSL_AC,%eax
+ pushl %ecx
+ popfl
+
+ testl %eax,%eax
+ jnz 1f
+ movl $CPU_386,_cpu-KERNBASE
+ jmp 2f
+
+1: /* Try to toggle identification flag; does not exist on early 486s. */
+ pushfl
+ popl %eax
+ movl %eax,%ecx
+ xorl $PSL_ID,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ xorl %ecx,%eax
+ andl $PSL_ID,%eax
+ pushl %ecx
+ popfl
+
+ testl %eax,%eax
+ jnz 1f
+ movl $CPU_486,_cpu-KERNBASE
+ jmp 2f
+
+1: /* Use the `cpuid' instruction. */
+ xorl %eax,%eax
+ .byte 0x0f,0xa2 # cpuid 0
+ movl %ebx,_cpu_vendor-KERNBASE # store vendor string
+ movl %edx,_cpu_vendor+4-KERNBASE
+ movl %ecx,_cpu_vendor+8-KERNBASE
+ movb $0,_cpu_vendor+12-KERNBASE
+
+ movl $1,%eax
+ .byte 0x0f,0xa2 # cpuid 1
+ movl %eax,_cpu_id-KERNBASE # store cpu_id
+ rorl $8,%eax # extract family type
+ andl $15,%eax
+ cmpl $5,%eax
+ jae 1f
+
+ /* less than Pentium; must be 486 */
+ movl $CPU_486,_cpu-KERNBASE
jmp 2f
-1: movl $CPU_486,_cpu-KERNBASE
+
+1: movl $CPU_586,_cpu-KERNBASE
2:
/*
@@ -217,7 +265,7 @@ ENTRY(btext)
movl $_end-KERNBASE,%ecx
addl $NBPG-1,%ecx /* page align up */
andl $~(NBPG-1),%ecx
- movl %ecx,%esi /* esi=start of tables */
+ movl %ecx,%esi /* esi = start of free memory */
movl %ecx,_KERNend-KERNBASE /* save end of kernel */
/* clear bss */
@@ -296,7 +344,7 @@ ENTRY(btext)
shrl $PGSHIFT,%ecx
orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
fillkpt
-#endif
+#endif /* KGDB || BDE_DEBUGGER */
/* now initialize the page dir, upages, p0stack PT, and page tables */
@@ -309,7 +357,7 @@ ENTRY(btext)
addl %esi,%ebx /* address of page directory */
addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */
fillkpt
-
+
/* map I/O memory map */
movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */
@@ -368,6 +416,7 @@ ENTRY(btext)
movl $_gdt-KERNBASE,%edi
movl %edi,2(%esp)
movl $8*18/4,%ecx
+ cld
rep /* copy gdt */
movsl
movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */
@@ -389,6 +438,7 @@ ENTRY(btext)
movl $_idt-KERNBASE,%edi
movl %edi,6+2(%esp)
movl $8*4/4,%ecx
+ cld
rep /* copy idt */
movsl
@@ -397,7 +447,7 @@ ENTRY(btext)
addl $2*6,%esp
popal
-#endif
+#endif /* BDE_DEBUGGER */
/* load base of page directory and enable mapping */
movl %esi,%eax /* phys address of ptd in proc 0 */
@@ -436,7 +486,7 @@ begin: /* now running relocated at KERNBASE where the system is linked to run */
movl $_gdt+8*9,%eax /* adjust slots 9-17 */
movl $9,%ecx
reloc_gdt:
- movb $0xfe,7(%eax) /* top byte of base addresses, was 0, */
+ movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */
addl $8,%eax /* now KERNBASE>>24 */
loop reloc_gdt
@@ -444,7 +494,7 @@ reloc_gdt:
je 1f
int $3
1:
-#endif
+#endif /* BDE_DEBUGGER */
/*
* Skip over the page tables and the kernel stack
@@ -494,7 +544,7 @@ lretmsg1:
.asciz "lret: toinit\n"
-#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+#define LCALL(x,y) .byte 0x9a ; .long y ; .word x
/*
* Icode is copied out to process 1 and executed in user mode:
* execve("/sbin/init", argv, envp); exit(0);
@@ -551,4 +601,3 @@ NON_GPROF_ENTRY(sigcode)
.globl _szsigcode
_szsigcode:
.long _szsigcode-_sigcode
-
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 3e0a368b4b44..05546058fbd0 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -35,13 +35,12 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
- * $Id: machdep.c,v 1.36.2.5 1994/04/18 04:56:56 rgrimes Exp $
+ * $Id: machdep.c,v 1.47 1994/06/17 13:32:07 davidg Exp $
*/
#include "npx.h"
#include "isa.h"
-#include <stddef.h>
#include "param.h"
#include "systm.h"
#include "signalvar.h"
@@ -58,7 +57,6 @@
#include "malloc.h"
#include "mbuf.h"
#include "msgbuf.h"
-#include "net/netisr.h"
#ifdef SYSVSHM
#include "sys/shm.h"
@@ -96,6 +94,8 @@ static void initcpu(void);
static int test_page(int *, int);
extern int grow(struct proc *,int);
+const char machine[] = "PC-Class";
+const char *cpu_model;
#ifndef PANIC_REBOOT_WAIT_TIME
#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
@@ -115,22 +115,22 @@ int bufpages = BUFPAGES;
#else
int bufpages = 0;
#endif
+#ifdef BOUNCEPAGES
+int bouncepages = BOUNCEPAGES;
+#else
+int bouncepages = 0;
+#endif
extern int freebufspace;
+extern char *bouncememory;
int _udatasel, _ucodesel;
/*
* Machine-dependent startup code
*/
-int boothowto = 0, Maxmem = 0, maxmem = 0, badpages = 0, physmem = 0;
+int boothowto = 0, Maxmem = 0, badpages = 0, physmem = 0;
long dumplo;
extern int bootdev;
-#ifdef SMALL
-extern int forcemaxmem;
-#endif
-#if defined(GENERICAH) || defined(GENERICBT)
-int generic_hack = 1;
-#endif
int biosmem;
vm_offset_t phys_avail[6];
@@ -141,6 +141,8 @@ int cpu_class;
void dumpsys __P((void));
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+
void
cpu_startup()
{
@@ -255,6 +257,7 @@ again:
panic("startup: no room for tables");
goto again;
}
+
/*
* End of second pass, addresses have been assigned
*/
@@ -295,6 +298,22 @@ again:
printf("using %d buffers containing %d bytes of memory\n",
nbuf, bufpages * CLBYTES);
+#ifndef NOBOUNCE
+ /*
+ * If there is more than 16MB of memory, allocate some bounce buffers
+ */
+ if (Maxmem > 4096) {
+ if (bouncepages == 0)
+ bouncepages = 96; /* largest physio size + extra */
+ bouncememory = (char *)kmem_alloc(kernel_map, bouncepages * PAGE_SIZE);
+ }
+
+ /*
+ * init bounce buffers
+ */
+ vm_bounce_init();
+#endif
+
/*
* Set up CPU-specific registers, cache, etc.
*/
@@ -324,10 +343,13 @@ struct cpu_nameclass i386_cpus[] = {
static void
identifycpu()
{
+ extern unsigned long cpu_id;
+ extern char cpu_vendor[];
printf("CPU: ");
if (cpu >= 0 && cpu < (sizeof i386_cpus/sizeof(struct cpu_nameclass))) {
printf("%s", i386_cpus[cpu].cpu_name);
cpu_class = i386_cpus[cpu].cpu_class;
+ cpu_model = i386_cpus[cpu].cpu_name;
} else {
printf("unknown cpu type %d\n", cpu);
panic("startup: bad cpu id");
@@ -350,6 +372,10 @@ identifycpu()
printf("unknown"); /* will panic below... */
}
printf("-class CPU)");
+ if(cpu_id)
+ printf(" Id = 0x%x",cpu_id);
+ if(*cpu_vendor)
+ printf(" Origin = \"%s\"",cpu_vendor);
printf("\n"); /* cpu speed would be nice, but how? */
/*
@@ -503,7 +529,7 @@ sendsig(catcher, sig, mask, code)
* Return to previous pc and psl as specified by
* context left by sendsig. Check carefully to
* make sure that the user has not modified the
- * psl to gain improper priviledges or to cause
+ * psl to gain improper privileges or to cause
* a machine fault.
*/
struct sigreturn_args {
@@ -558,11 +584,11 @@ sigreturn(p, uap, retval)
#define null_sel(sel) \
(!ISLDT(sel) && IDXSEL(sel) == 0)
- if ((scp->sc_cs&0xffff != _ucodesel && !valid_ldt_sel(scp->sc_cs)) ||
- (scp->sc_ss&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ss)) ||
- (scp->sc_ds&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ds) &&
+ if (((scp->sc_cs&0xffff) != _ucodesel && !valid_ldt_sel(scp->sc_cs)) ||
+ ((scp->sc_ss&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ss)) ||
+ ((scp->sc_ds&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ds) &&
!null_sel(scp->sc_ds)) ||
- (scp->sc_es&0xffff != _udatasel && !valid_ldt_sel(scp->sc_es) &&
+ ((scp->sc_es&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_es) &&
!null_sel(scp->sc_es))) {
#ifdef DEBUG
printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n",
@@ -709,10 +735,10 @@ boot(arghowto)
#endif
die:
printf("Rebooting...\n");
- DELAY (100000); /* wait 100ms for printf's to complete */
+ DELAY(1000000); /* wait 1 sec for printf's to complete and be read */
cpu_reset();
for(;;) ;
- /*NOTREACHED*/
+ /* NOTREACHED */
}
unsigned long dumpmag = 0x8fca0101UL; /* magic number for savecore */
@@ -782,36 +808,6 @@ microtime(tvp)
}
#endif /* HZ */
-void
-physstratdone(bp)
- struct buf *bp;
-{
- wakeup((caddr_t) bp);
- bp->b_flags &= ~B_CALL;
-}
-
-void
-physstrat(bp, strat, prio)
- struct buf *bp;
- int (*strat)(), prio;
-{
- register int s;
- caddr_t baddr;
-
- bp->b_flags |= B_CALL;
- bp->b_iodone = physstratdone;
- vmapbuf(bp);
- (*strat)(bp);
- /* pageout daemon doesn't wait for pushed pages */
- if (bp->b_flags & B_DIRTY)
- return;
- s = splbio();
- while ((bp->b_flags & B_DONE) == 0)
- tsleep((caddr_t)bp, prio, "physstr", 0);
- splx(s);
- vunmapbuf(bp);
-}
-
static void
initcpu()
{
@@ -1001,7 +997,7 @@ setidt(idx, func, typ, dpl)
ip->gd_hioffset = ((int)func)>>16 ;
}
-#define IDTVEC(name) __CONCAT(X, name)
+#define IDTVEC(name) __CONCAT(X,name)
typedef void idtvec_t();
extern idtvec_t
@@ -1012,7 +1008,7 @@ extern idtvec_t
IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
- IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
+ IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(syscall);
int _gsel_tss;
@@ -1044,8 +1040,9 @@ init386(first)
* the address space
*/
gdt_segs[GCODE_SEL].ssd_limit = i386_btop(i386_round_page(&etext)) - 1;
- gdt_segs[GDATA_SEL].ssd_limit = 0xffffffffUL; /* XXX constant? */
+ gdt_segs[GDATA_SEL].ssd_limit = i386_btop(0) - 1;
for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
+
/* make ldt memory segments */
/*
* The data segment limit must not cover the user area because we
@@ -1146,7 +1143,7 @@ init386(first)
#ifndef LARGEMEM
if (biosextmem > 65536) {
panic("extended memory beyond limit of 64MB");
- /* NOT REACHED */
+ /* NOTREACHED */
}
#endif
@@ -1169,25 +1166,6 @@ init386(first)
if ((pagesinext > 3840) && (pagesinext < 4096))
pagesinext = 3840;
-#if defined(GENERICAH) || defined(GENERICBT)
- /* XXX This is an ugle hack so that machines with >16MB of memory
- * can be booted using the GENERIC* kernels and not have to worry
- * about bus mastered DMA on the ISA bus. It is ONLY compiled into
- * the GENERIC* kernels and can be disabled by tweaking the global
- * generic_hack to be zero using gdb.
- */
- if (generic_hack) {
- if (pagesinext > 3840) {
- printf("WARNING WARNING WARNING WARNING WARNING WARNING\n");
- printf("GENERIC* kernels only USE the first 16MB of your ");
- printf("%dMB.\n", (pagesinext + 256) / 256);
- printf("Read the RELNOTES.FreeBSD file for the reason.\n");
- printf("WARNING WARNING WARNING WARNING WARNING WARNING\n");
- pagesinext = 3840;
- }
- }
-#endif /* defined (GENERICAH) || defiend(GENERICBT) */
-
/*
* Maxmem isn't the "maximum memory", it's the highest page of
* of the physical address space. It should be "Maxphyspage".
@@ -1266,9 +1244,9 @@ init386(first)
}
}
printf("done.\n");
-
- maxmem = Maxmem - 1; /* highest page of usable memory */
- avail_end = (maxmem << PAGE_SHIFT) - i386_round_page(sizeof(struct msgbuf));
+
+ avail_end = (Maxmem << PAGE_SHIFT)
+ - i386_round_page(sizeof(struct msgbuf));
/*
* Initialize pointers to the two chunks of memory; for use
@@ -1334,15 +1312,6 @@ test_page(address, pattern)
return(0);
}
-/*aston() {
- schednetisr(NETISR_AST);
-}*/
-
-void
-setsoftclock() {
- schednetisr(NETISR_SCLK);
-}
-
/*
* insert an element into a queue
*/
diff --git a/sys/i386/i386/math_emulate.c b/sys/i386/i386/math_emulate.c
index 256f8fb1033d..c6df09e9dddb 100644
--- a/sys/i386/i386/math_emulate.c
+++ b/sys/i386/i386/math_emulate.c
@@ -6,7 +6,7 @@
* [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj]
*
* from: 386BSD 0.1
- * $Id: math_emulate.c,v 1.7 1994/01/29 22:07:16 nate Exp $
+ * $Id: math_emulate.c,v 1.9 1994/06/05 19:31:45 ats Exp $
*/
/*
@@ -107,243 +107,255 @@ math_emulate(struct trapframe * info)
switch (code) {
case 0x1d0: /* fnop */
return(0);
- case 0x1d1: case 0x1d2: case 0x1d3:
+ case 0x1d1: case 0x1d2: case 0x1d3: /* fst to 32-bit mem */
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
math_abort(info,SIGILL);
- case 0x1e0:
+ case 0x1e0: /* fchs */
ST(0).exponent ^= 0x8000;
return(0);
- case 0x1e1:
+ case 0x1e1: /* fabs */
ST(0).exponent &= 0x7fff;
return(0);
case 0x1e2: case 0x1e3:
math_abort(info,SIGILL);
- case 0x1e4:
+ case 0x1e4: /* ftst */
ftst(PST(0));
return(0);
- case 0x1e5:
+ case 0x1e5: /* fxam */
printf("fxam not implemented\n\r");
math_abort(info,SIGILL);
- case 0x1e6: case 0x1e7:
+ case 0x1e6: case 0x1e7: /* fldenv */
math_abort(info,SIGILL);
- case 0x1e8:
+ case 0x1e8: /* fld1 */
fpush();
ST(0) = CONST1;
return(0);
- case 0x1e9:
+ case 0x1e9: /* fld2t */
fpush();
ST(0) = CONSTL2T;
return(0);
- case 0x1ea:
+ case 0x1ea: /* fld2e */
fpush();
ST(0) = CONSTL2E;
return(0);
- case 0x1eb:
+ case 0x1eb: /* fldpi */
fpush();
ST(0) = CONSTPI;
return(0);
- case 0x1ec:
+ case 0x1ec: /* fldlg2 */
fpush();
ST(0) = CONSTLG2;
return(0);
- case 0x1ed:
+ case 0x1ed: /* fldln2 */
fpush();
ST(0) = CONSTLN2;
return(0);
- case 0x1ee:
+ case 0x1ee: /* fldz */
fpush();
ST(0) = CONSTZ;
return(0);
case 0x1ef:
math_abort(info,SIGILL);
- case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
- case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
- case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
- case 0x1fe: case 0x1ff:
+ case 0x1f0: /* f2xm1 */
+ case 0x1f1: /* fyl2x */
+ case 0x1f2: /* fptan */
+ case 0x1f3: /* fpatan */
+ case 0x1f4: /* fxtract */
+ case 0x1f5: /* fprem1 */
+ case 0x1f6: /* fdecstp */
+ case 0x1f7: /* fincstp */
+ case 0x1f8: /* fprem */
+ case 0x1f9: /* fyl2xp1 */
+ case 0x1fa: /* fsqrt */
+ case 0x1fb: /* fsincos */
+ case 0x1fe: /* fsin */
+ case 0x1ff: /* fcos */
uprintf(
"math_emulate: instruction %04x not implemented\n",
code + 0xd800);
math_abort(info,SIGILL);
- case 0x1fd:
+ case 0x1fc: /* frndint */
+ frndint(PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1fd: /* fscale */
/* incomplete and totally inadequate -wfj */
Fscale(PST(0), PST(1), &tmp);
real_to_real(&tmp,&ST(0));
return(0); /* 19 Sep 92*/
- case 0x1fc:
- frndint(PST(0),&tmp);
- real_to_real(&tmp,&ST(0));
- return(0);
- case 0x2e9:
+ case 0x2e9: /* ????? */
+/* if this should be a fucomp ST(0),ST(1) , it must be a 0x3e9 ATS */
fucom(PST(1),PST(0));
fpop(); fpop();
return(0);
- case 0x3d0: case 0x3d1:
+ case 0x3d0: case 0x3d1: /* fist ?? */
return(0);
- case 0x3e2:
+ case 0x3e2: /* fclex */
I387.swd &= 0x7f00;
return(0);
- case 0x3e3:
+ case 0x3e3: /* fninit */
I387.cwd = 0x037f;
I387.swd = 0x0000;
I387.twd = 0x0000;
return(0);
case 0x3e4:
return(0);
- case 0x6d9:
+ case 0x6d9: /* fcompp */
fcom(PST(1),PST(0));
fpop(); fpop();
return(0);
- case 0x7e0:
+ case 0x7e0: /* fstsw ax */
*(short *) &info->tf_eax = I387.swd;
return(0);
}
switch (code >> 3) {
- case 0x18:
+ case 0x18: /* fadd */
fadd(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x19:
+ case 0x19: /* fmul */
fmul(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x1a:
+ case 0x1a: /* fcom */
fcom(PST(code & 7),PST(0));
return(0);
- case 0x1b:
+ case 0x1b: /* fcomp */
fcom(PST(code & 7),PST(0));
fpop();
return(0);
- case 0x1c:
+ case 0x1c: /* fsubr */
real_to_real(&ST(code & 7),&tmp);
tmp.exponent ^= 0x8000;
fadd(PST(0),&tmp,&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x1d:
+ case 0x1d: /* fsub */
ST(0).exponent ^= 0x8000;
fadd(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x1e:
+ case 0x1e: /* fdivr */
fdiv(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x1f:
+ case 0x1f: /* fdiv */
fdiv(PST(code & 7),PST(0),&tmp);
real_to_real(&tmp,&ST(0));
return(0);
- case 0x38:
+ case 0x38: /* fld */
fpush();
- ST(0) = ST((code & 7)+1);
+ ST(0) = ST((code & 7)+1); /* why plus 1 ????? ATS */
return(0);
- case 0x39:
+ case 0x39: /* fxch */
fxchg(&ST(0),&ST(code & 7));
return(0);
- case 0x3b:
+ case 0x3b: /* ??? ??? wrong ???? ATS */
ST(code & 7) = ST(0);
fpop();
return(0);
- case 0x98:
+ case 0x98: /* fadd */
fadd(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0x99:
+ case 0x99: /* fmul */
fmul(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0x9a:
+ case 0x9a: /* ???? , my manual don't list a direction bit
+for fcom , ??? ATS */
fcom(PST(code & 7),PST(0));
return(0);
- case 0x9b:
+ case 0x9b: /* same as above , ATS */
fcom(PST(code & 7),PST(0));
fpop();
return(0);
- case 0x9c:
+ case 0x9c: /* fsubr */
ST(code & 7).exponent ^= 0x8000;
fadd(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0x9d:
+ case 0x9d: /* fsub */
real_to_real(&ST(0),&tmp);
tmp.exponent ^= 0x8000;
fadd(PST(code & 7),&tmp,&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0x9e:
+ case 0x9e: /* fdivr */
fdiv(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0x9f:
+ case 0x9f: /* fdiv */
fdiv(PST(code & 7),PST(0),&tmp);
real_to_real(&tmp,&ST(code & 7));
return(0);
- case 0xb8:
+ case 0xb8: /* ffree */
printf("ffree not implemented\n\r");
math_abort(info,SIGILL);
- case 0xb9:
+ case 0xb9: /* fstp ???? where is the pop ? ATS */
fxchg(&ST(0),&ST(code & 7));
return(0);
- case 0xba:
+ case 0xba: /* fst */
ST(code & 7) = ST(0);
return(0);
- case 0xbb:
+ case 0xbb: /* ????? encoding of fstp to mem ? ATS */
ST(code & 7) = ST(0);
fpop();
return(0);
- case 0xbc:
+ case 0xbc: /* fucom */
fucom(PST(code & 7),PST(0));
return(0);
- case 0xbd:
+ case 0xbd: /* fucomp */
fucom(PST(code & 7),PST(0));
fpop();
return(0);
- case 0xd8:
+ case 0xd8: /* faddp */
fadd(PST(code & 7),PST(0),&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xd9:
+ case 0xd9: /* fmulp */
fmul(PST(code & 7),PST(0),&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xda:
+ case 0xda: /* ??? encoding of ficom with 16 bit mem ? ATS */
fcom(PST(code & 7),PST(0));
fpop();
return(0);
- case 0xdc:
+ case 0xdc: /* fsubrp */
ST(code & 7).exponent ^= 0x8000;
fadd(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xdd:
+ case 0xdd: /* fsubp */
real_to_real(&ST(0),&tmp);
tmp.exponent ^= 0x8000;
fadd(PST(code & 7),&tmp,&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xde:
+ case 0xde: /* fdivrp */
fdiv(PST(0),PST(code & 7),&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xdf:
+ case 0xdf: /* fdivp */
fdiv(PST(code & 7),PST(0),&tmp);
real_to_real(&tmp,&ST(code & 7));
fpop();
return(0);
- case 0xf8:
+ case 0xf8: /* fild 16-bit mem ???? ATS */
printf("ffree not implemented\n\r");
math_abort(info,SIGILL);
fpop();
return(0);
- case 0xf9:
+ case 0xf9: /* ????? ATS */
fxchg(&ST(0),&ST(code & 7));
return(0);
- case 0xfa:
- case 0xfb:
+ case 0xfa: /* fist 16-bit mem ? ATS */
+ case 0xfb: /* fistp 16-bit mem ? ATS */
ST(code & 7) = ST(0);
fpop();
return(0);
diff --git a/sys/i386/i386/microtime.s b/sys/i386/i386/microtime.s
index d167b6ee556a..4c77fd08117d 100644
--- a/sys/i386/i386/microtime.s
+++ b/sys/i386/i386/microtime.s
@@ -31,10 +31,10 @@
* SUCH DAMAGE.
*
* from: Steve McCanne's microtime code
- * $Id: microtime.s,v 1.2 1993/10/16 14:15:08 rgrimes Exp $
+ * $Id: microtime.s,v 1.4 1994/05/02 09:44:20 sos Exp $
*/
-#include "asm.h"
+#include "machine/asmacros.h"
#include "../isa/isa.h"
#include "../isa/timerreg.h"
@@ -44,31 +44,25 @@
*/
#ifndef HZ
ENTRY(microtime)
- pushl %edi
+ pushl %edi # save registers
pushl %esi
pushl %ebx
- movl $_time,%ebx
+ movl $_time, %ebx # get timeval ptr
+ movl (%ebx), %edi # sec = time.tv_sec
+ movl 4(%ebx), %esi # usec = time.tv_usec
cli # disable interrupts
- movl (%ebx),%edi # sec = time.tv_sec
- movl 4(%ebx),%esi # usec = time.tv_usec
+ movl $(TIMER_SEL0|TIMER_LATCH), %eax
+ outb %al, $TIMER_MODE # latch timer 0's counter
- movl $(TIMER_SEL0|TIMER_LATCH),%eax
- outb %al,$TIMER_MODE # latch timer 0's counter
+ xorl %ebx, %ebx # clear ebx
+ inb $TIMER_CNTR0, %al # Read counter value, LSB first
+ movb %al, %bl
+ inb $TIMER_CNTR0, %al
+ movb %al, %bh
- #
- # Read counter value into ebx, LSB first
- #
- inb $TIMER_CNTR0,%al
- movzbl %al,%ebx
- inb $TIMER_CNTR0,%al
- movzbl %al,%eax
- sall $8,%eax
- orl %eax,%ebx
-
- #
# Now check for counter overflow. This is tricky because the
# timer chip doesn't let us atomically read the current counter
# value and the output state (i.e., overflow state). We have
@@ -96,38 +90,45 @@ ENTRY(microtime)
# we're called from an ipl less than the clock. Otherwise,
# it might not work. Currently, only gettimeofday and bpf
# call microtime so it's not a problem.
- #
- cmpl $11890,%ebx
- jle 2f
- movl $0x0a,%eax # tell ICU we want IRR
- outb %al,$IO_ICU1
- inb $IO_ICU1,%al # read IRR in ICU
- testb $1,%al # is a timer interrupt pending?
+ movl _timer0_prescale, %eax # adjust value if timer is
+ addl _timer0_divisor, %eax # reprogrammed
+ addl $-11932, %eax
+ subl %eax, %ebx
+
+ cmpl $11890, %ebx # do we have a possible overflow condition
+ jle 1f
+
+ inb $IO_ICU1, %al # read IRR in ICU
+ testb $1, %al # is a timer interrupt pending?
je 1f
- addl $-11932,%ebx # yes, subtract one clock period
+ addl $-11932, %ebx # yes, subtract one clock period
1:
- movl $0x0b,%eax # tell ICU we want ISR
- outb %al,$IO_ICU1 # (rest of kernel expects this)
-2:
sti # enable interrupts
- movl $11932,%eax # subtract counter value from 11932 since
- subl %ebx,%eax # it is a count-down value
- imull $1000,%eax,%eax
- movl $0,%edx # zero extend eax for div
- movl $1193,%ecx
+ movl $11932, %eax # subtract counter value from 11932 since
+ subl %ebx, %eax # it is a count-down value
+
+ movl %eax, %ebx # this really is a "imull $1000, %eax, %eax"
+ sall $10, %eax # instruction, but this saves us
+ sall $3, %ebx # 33/23 clocks on a 486/386 CPU
+ subl %ebx, %eax #
+ sall $1, %ebx # /sos
+ subl %ebx, %eax #
+
+ movl $0, %edx # zero extend eax into edx for div
+ movl $1193, %ecx
idivl %ecx # convert to usecs: mult by 1000/1193
- addl %eax,%esi # add counter usecs to time.tv_usec
- cmpl $1000000,%esi # carry in timeval?
- jl 3f
- subl $1000000,%esi # adjust usec
+ addl %eax, %esi # add counter usecs to time.tv_usec
+ cmpl $1000000, %esi # carry in timeval?
+ jl 2f
+ subl $1000000, %esi # adjust usec
incl %edi # bump sec
-3:
- movl 16(%esp),%ecx # load timeval pointer arg
- movl %edi,(%ecx) # tvp->tv_sec = sec
- movl %esi,4(%ecx) # tvp->tv_usec = usec
+2:
+ movl 16(%esp), %ecx # load timeval pointer arg
+ movl %edi, (%ecx) # tvp->tv_sec = sec
+ movl %esi, 4(%ecx) # tvp->tv_usec = usec
popl %ebx # restore regs
popl %esi
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index da74b5f6455b..a1c04662cb8b 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -1,6 +1,10 @@
/*
* Copyright (c) 1991 Regents of the University of California.
* All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ * Copyright (c) 1994 David Greenman
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
@@ -35,7 +39,7 @@
* SUCH DAMAGE.
*
* from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
- * $Id: pmap.c,v 1.19.2.1 1994/04/18 04:56:59 rgrimes Exp $
+ * $Id: pmap.c,v 1.26 1994/06/11 17:09:39 paul Exp $
*/
/*
@@ -51,7 +55,8 @@
* Major modifications by John S. Dyson primarily to support
* pageable page tables, eliminating pmap_attributes,
* discontiguous memory pages, and using more efficient string
- * instructions. Jan 13, 1994.
+ * instructions. Jan 13, 1994. Further modifications on Mar 2, 1994,
+ * general clean-up and efficiency mods.
*/
/*
@@ -86,6 +91,7 @@
#include "malloc.h"
#include "user.h"
#include "i386/include/cpufunc.h"
+#include "i386/include/cputypes.h"
#include "vm/vm.h"
#include "vm/vm_kern.h"
@@ -99,55 +105,6 @@
*/
#define BSDVM_COMPAT 1
-#ifdef DEBUG
-struct {
- int kernel; /* entering kernel mapping */
- int user; /* entering user mapping */
- int ptpneeded; /* needed to allocate a PT page */
- int pwchange; /* no mapping change, just wiring or protection */
- int wchange; /* no mapping change, just wiring */
- int mchange; /* was mapped but mapping to different page */
- int managed; /* a managed page */
- int firstpv; /* first mapping for this PA */
- int secondpv; /* second mapping for this PA */
- int ci; /* cache inhibited */
- int unmanaged; /* not a managed page */
- int flushes; /* cache flushes */
-} enter_stats;
-struct {
- int calls;
- int removes;
- int pvfirst;
- int pvsearch;
- int ptinvalid;
- int uflushes;
- int sflushes;
-} remove_stats;
-
-int debugmap = 0;
-int pmapdebug = 0 /* 0xffff */;
-#define PDB_FOLLOW 0x0001
-#define PDB_INIT 0x0002
-#define PDB_ENTER 0x0004
-#define PDB_REMOVE 0x0008
-#define PDB_CREATE 0x0010
-#define PDB_PTPAGE 0x0020
-#define PDB_CACHE 0x0040
-#define PDB_BITS 0x0080
-#define PDB_COLLECT 0x0100
-#define PDB_PROTECT 0x0200
-#define PDB_PDRTAB 0x0400
-#define PDB_PARANOIA 0x2000
-#define PDB_WIRING 0x4000
-#define PDB_PVDUMP 0x8000
-
-int pmapvacflush = 0;
-#define PVF_ENTER 0x01
-#define PVF_REMOVE 0x02
-#define PVF_PROTECT 0x04
-#define PVF_TOTAL 0x80
-#endif
-
/*
* Get PDEs and PTEs for user/kernel address space
*/
@@ -156,14 +113,14 @@ int pmapvacflush = 0;
#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
-#define pmap_pde_v(pte) ((pte)->pd_v)
-#define pmap_pte_w(pte) ((pte)->pg_w)
-/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */
-#define pmap_pte_m(pte) ((pte)->pg_m)
-#define pmap_pte_u(pte) ((pte)->pg_u)
-#define pmap_pte_v(pte) ((pte)->pg_v)
-#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v))
-#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v))
+#define pmap_pde_v(pte) ((*(int *)pte & PG_V) != 0)
+#define pmap_pte_w(pte) ((*(int *)pte & PG_W) != 0)
+#define pmap_pte_m(pte) ((*(int *)pte & PG_M) != 0)
+#define pmap_pte_u(pte) ((*(int *)pte & PG_U) != 0)
+#define pmap_pte_v(pte) ((*(int *)pte & PG_V) != 0)
+
+#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W))
+#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
/*
* Given a map and a machine independent protection code,
@@ -184,19 +141,21 @@ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
vm_offset_t vm_first_phys, vm_last_phys;
-vm_offset_t pager_sva, pager_eva;
-
-static inline boolean_t pmap_testbit();
-static inline void pmap_changebit();
-static inline int pmap_is_managed();
-static inline void *vm_get_pmap();
-static inline void vm_put_pmap();
-static inline void pmap_use_pt();
-inline struct pte *pmap_pte();
-static inline pv_entry_t get_pv_entry();
-void pmap_alloc_pv_entry();
-void pmap_clear_modify();
-void i386_protection_init();
+
+static inline boolean_t pmap_testbit();
+static inline void pmap_changebit();
+static inline int pmap_is_managed();
+static inline void *vm_get_pmap();
+static inline void vm_put_pmap();
+inline void pmap_use_pt();
+inline void pmap_unuse_pt();
+inline pt_entry_t * const pmap_pte();
+static inline pv_entry_t get_pv_entry();
+void pmap_alloc_pv_entry();
+void pmap_clear_modify();
+void i386_protection_init();
+extern vm_offset_t pager_sva, pager_eva;
+extern int cpu_class;
#if BSDVM_COMPAT
#include "msgbuf.h"
@@ -204,13 +163,12 @@ void i386_protection_init();
/*
* All those kernel PT submaps that BSD is so fond of
*/
-struct pte *CMAP1, *CMAP2, *mmap;
+pt_entry_t *CMAP1, *CMAP2, *mmap;
caddr_t CADDR1, CADDR2, vmmap;
-struct pte *msgbufmap;
+pt_entry_t *msgbufmap;
struct msgbuf *msgbufp;
#endif
-struct vm_map * pmap_fmap(pmap_t pmap) ;
void init_pv_entries(int) ;
/*
@@ -221,26 +179,24 @@ void init_pv_entries(int) ;
* [ what about induced faults -wfj]
*/
-inline struct pte *
-pmap_pte(pmap, va)
+inline pt_entry_t *
+const pmap_pte(pmap, va)
register pmap_t pmap;
vm_offset_t va;
{
- if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
/* are we current address space or kernel? */
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
- || pmap == kernel_pmap)
- return ((struct pte *) vtopte(va));
-
+ if ( (pmap == kernel_pmap) || (frame == ((int) PTDpde & PG_FRAME)))
+ return ((pt_entry_t *) vtopte(va));
/* otherwise, we are alternate address space */
else {
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum
- != APTDpde.pd_pfnum) {
+ if ( frame != ((int) APTDpde & PG_FRAME) ) {
APTDpde = pmap->pm_pdir[PTDPTDI];
tlbflush();
}
- return((struct pte *) avtopte(va));
+ return((pt_entry_t *) avtopte(va));
}
}
return(0);
@@ -258,40 +214,34 @@ pmap_extract(pmap, va)
register pmap_t pmap;
vm_offset_t va;
{
- struct pde save;
+ pd_entry_t save;
vm_offset_t pa;
int s;
- s = splhigh();
- if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
/* are we current address space or kernel? */
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
- || pmap == kernel_pmap) {
+ if ( (pmap == kernel_pmap)
+ || (frame == ((int) PTDpde & PG_FRAME)) ) {
pa = *(int *) vtopte(va);
/* otherwise, we are alternate address space */
} else {
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum
- != APTDpde.pd_pfnum) {
- save = APTDpde;
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
APTDpde = pmap->pm_pdir[PTDPTDI];
tlbflush();
- pa = *(int *) avtopte(va);
- APTDpde = save;
- tlbflush();
- } else {
- tlbflush();
- pa = *(int *) avtopte(va);
}
+ pa = *(int *) avtopte(va);
}
pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
- splx(s);
return pa;
}
- splx(s);
return 0;
}
+/*
+ * determine if a page is managed (memory vs. device)
+ */
static inline int
pmap_is_managed(pa)
vm_offset_t pa;
@@ -309,36 +259,51 @@ pmap_is_managed(pa)
}
/*
- * increment/decrement pmap wiring count
+ * find the vm_page_t of a pte (only) given va of pte and pmap
*/
-static inline void
-pmap_use_pt(pmap, va, use)
+inline vm_page_t
+pmap_pte_vm_page(pmap, pt)
+ pmap_t pmap;
+ vm_offset_t pt;
+{
+ pt = i386_trunc_page( pt);
+ pt = (pt - UPT_MIN_ADDRESS) / NBPG;
+ pt = ((vm_offset_t) pmap->pm_pdir[pt]) & PG_FRAME;
+ return PHYS_TO_VM_PAGE(pt);
+}
+
+/*
+ * Wire a page table page
+ */
+inline void
+pmap_use_pt(pmap, va)
pmap_t pmap;
vm_offset_t va;
- int use;
{
- vm_offset_t pt, pa;
- pv_entry_t pv;
- vm_page_t m;
+ vm_offset_t pt;
- if (va >= VM_MAX_ADDRESS)
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
return;
- pt = i386_trunc_page(vtopte(va));
- pa = pmap_extract(pmap, pt);
- if (pa == 0) {
- printf("Warning pmap_use_pt pte paging failure\n");
- }
- if (!pa || !pmap_is_managed(pa))
- return;
- pv = pa_to_pvh(pa);
-
- m = PHYS_TO_VM_PAGE(pa);
- if (use) {
- vm_page_wire(m);
- } else {
- vm_page_unwire(m);
- }
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_hold( pmap_pte_vm_page(pmap, pt));
+}
+
+/*
+ * Unwire a page table page
+ */
+inline void
+pmap_unuse_pt(pmap, va)
+ pmap_t pmap;
+ vm_offset_t va;
+{
+ vm_offset_t pt;
+
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
+ return;
+
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_unhold( pmap_pte_vm_page(pmap, pt));
}
/* [ macro again?, should I force kstack into user map here? -wfj ] */
@@ -370,7 +335,7 @@ pmap_bootstrap(firstaddr, loadaddr)
{
#if BSDVM_COMPAT
vm_offset_t va;
- struct pte *pte;
+ pt_entry_t *pte;
#endif
extern int IdlePTD;
@@ -436,6 +401,8 @@ pmap_bootstrap(firstaddr, loadaddr)
* Initialize the pmap module.
* Called by vm_init, to initialize any structures that the pmap
* system needs to map virtual memory.
+ * pmap_init has been enhanced to support in a fairly consistant
+ * way, discontiguous physical memory.
*/
void
pmap_init(phys_start, phys_end)
@@ -538,12 +505,7 @@ pmap_create(size)
if (size)
return(NULL);
- /* XXX: is it ok to wait here? */
pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
-#ifdef notifwewait
- if (pmap == NULL)
- panic("pmap_create: cannot allocate a pmap");
-#endif
bzero(pmap, sizeof(*pmap));
pmap_pinit(pmap);
return (pmap);
@@ -590,7 +552,7 @@ pmap_pinit(pmap)
/* install self-referential address mapping entry */
*(int *)(pmap->pm_pdir+PTDPTDI) =
- ((int)pmap_extract(kernel_pmap, (vm_offset_t)pmap->pm_pdir)) | PG_V | PG_KW;
+ ((int)pmap_kextract((vm_offset_t)pmap->pm_pdir)) | PG_V | PG_KW;
pmap->pm_count = 1;
simple_lock_init(&pmap->pm_lock);
@@ -698,6 +660,11 @@ get_pv_entry()
return tmp;
}
+/*
+ * this *strange* allocation routine *statistically* eliminates the
+ * *possibility* of a malloc failure (*FATAL*) for a pv_entry_t data structure.
+ * also -- this code is MUCH MUCH faster than the malloc equiv...
+ */
void
pmap_alloc_pv_entry()
{
@@ -755,7 +722,7 @@ pmap_alloc_pv_entry()
/*
* init the pv_entry allocation system
*/
-#define PVSPERPAGE 16
+#define PVSPERPAGE 64
void
init_pv_entries(npg)
int npg;
@@ -778,15 +745,13 @@ get_pt_entry(pmap)
pmap_t pmap;
{
pt_entry_t *ptp;
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
/* are we current address space or kernel? */
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
- || pmap == kernel_pmap)
+ if (pmap == kernel_pmap || frame == ((int) PTDpde & PG_FRAME)) {
ptp=PTmap;
-
/* otherwise, we are alternate address space */
- else {
- if (pmap->pm_pdir[PTDPTDI].pd_pfnum
- != APTDpde.pd_pfnum) {
+ } else {
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
APTDpde = pmap->pm_pdir[PTDPTDI];
tlbflush();
}
@@ -808,9 +773,9 @@ pmap_remove_entry(pmap, pv, va)
vm_offset_t va;
{
pv_entry_t npv;
- int s;
int wired;
- s = splhigh();
+ int s;
+ s = splimp();
if (pmap == pv->pv_pmap && va == pv->pv_va) {
npv = pv->pv_next;
if (npv) {
@@ -849,121 +814,144 @@ pmap_remove(pmap, sva, eva)
register pt_entry_t *ptp,*ptq;
vm_offset_t pa;
register pv_entry_t pv;
- vm_offset_t asva, va;
+ vm_offset_t va;
vm_page_t m;
- int oldpte;
+ pt_entry_t oldpte;
if (pmap == NULL)
return;
ptp = get_pt_entry(pmap);
+/*
+ * special handling of removing one page. a very
+ * common operation and easy to short circuit some
+ * code.
+ */
+ if( (sva + NBPG) == eva) {
+
+ if( *pmap_pde( pmap, sva) == 0)
+ return;
+
+ ptq = ptp + i386_btop(sva);
+
+ if( !*ptq)
+ return;
+ /*
+ * Update statistics
+ */
+ if (pmap_pte_w(ptq))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ pa = pmap_pte_pa(ptq);
+ oldpte = *ptq;
+ *ptq = 0;
+
+ if (pmap_is_managed(pa)) {
+ if ((((int) oldpte & PG_M) && (sva < USRSTACK || sva > UPT_MAX_ADDRESS))
+ || (sva >= USRSTACK && sva < USRSTACK+(UPAGES*NBPG))) {
+ if (sva < pager_sva || sva >= pager_eva) {
+ m = PHYS_TO_VM_PAGE(pa);
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ pv = pa_to_pvh(pa);
+ pmap_remove_entry(pmap, pv, sva);
+ pmap_unuse_pt(pmap, sva);
+ }
+ tlbflush();
+ return;
+ }
- /* this is essential since we must check the PDE(sva) for precense */
- while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva)))
- sva = (sva & PD_MASK) + (1<<PD_SHIFT);
sva = i386_btop(sva);
eva = i386_btop(eva);
- for (; sva < eva; sva++) {
+ while (sva < eva) {
/*
* Weed out invalid mappings.
* Note: we assume that the page directory table is
* always allocated, and in kernel virtual.
*/
- if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva))))
- {
+ if ( *pmap_pde(pmap, i386_ptob(sva)) == 0 ) {
/* We can race ahead here, straight to next pde.. */
- sva = sva & ~((NBPG/PTESIZE) - 1);
- sva = sva + NBPG/PTESIZE - 1;
+ nextpde:
+ sva = ((sva + NPTEPG) & ~(NPTEPG - 1));
continue;
- }
+ }
- ptq=ptp+sva;
-
+ ptq = ptp + sva;
/*
- * search for page table entries
+ * search for page table entries, use string operations
+ * that are much faster than
+ * explicitly scanning when page tables are not fully
+ * populated.
*/
- if (!pmap_pte_v(ptq)) {
- vm_offset_t nscan = ((sva + (NBPG/PTESIZE)) & ~((NBPG/PTESIZE) - 1)) - sva;
+ if ( *ptq == 0) {
+ vm_offset_t pdnxt = ((sva + NPTEPG) & ~(NPTEPG - 1));
+ vm_offset_t nscan = pdnxt - sva;
+ int found = 0;
+
if ((nscan + sva) > eva)
nscan = eva - sva;
- if (nscan) {
- int found;
-
- asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
- :"=D"(ptq),"=a"(found)
- :"c"(nscan),"0"(ptq)
- :"cx");
- if (found)
- ptq -= 1;
+ asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
+ :"=D"(ptq),"=a"(found)
+ :"c"(nscan),"0"(ptq)
+ :"cx");
- sva = ptq - ptp;
+ if( !found) {
+ sva = pdnxt;
+ continue;
}
- if (sva >= eva)
- goto endofloop;
- }
-
-
- if (!(sva & 0x3ff)) /* Only check once in a while */
- {
- if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva)))) {
- /* We can race ahead here, straight to next pde.. */
- sva = sva & ~((NBPG/PTESIZE) - 1);
- sva = sva + NBPG/PTESIZE - 1;
- continue;
- }
- }
+ ptq -= 1;
- if (!pmap_pte_v(ptq))
- continue;
+ sva = ptq - ptp;
+ }
/*
* Update statistics
*/
- if (pmap_pte_w(ptq))
+ oldpte = *ptq;
+ if (((int)oldpte) & PG_W)
pmap->pm_stats.wired_count--;
pmap->pm_stats.resident_count--;
- pa = pmap_pte_pa(ptq);
- oldpte = *(int *) ptq;
-
/*
* Invalidate the PTEs.
* XXX: should cluster them up and invalidate as many
* as possible at once.
*/
- *(int *)ptq = 0;
+ *ptq = 0;
+
+ va = i386_ptob(sva);
/*
* Remove from the PV table (raise IPL since we
* may be called at interrupt time).
*/
- if (!pmap_is_managed(pa))
+ pa = ((int)oldpte) & PG_FRAME;
+ if (!pmap_is_managed(pa)) {
+ ++sva;
continue;
+ }
- va = i386_ptob(sva);
-
- if (((oldpte & PG_M) && (va < USRSTACK || va > UPT_MAX_ADDRESS))
+ if ((((int) oldpte & PG_M) && (va < USRSTACK || va > UPT_MAX_ADDRESS))
|| (va >= USRSTACK && va < USRSTACK+(UPAGES*NBPG))) {
- /*
- * don't update the dirty bit for pager mappings
- */
- if( va < pager_sva || va >= pager_eva) {
+ if (va < pager_sva || va >= pager_eva) {
m = PHYS_TO_VM_PAGE(pa);
m->flags &= ~PG_CLEAN;
}
}
pv = pa_to_pvh(pa);
- asva = i386_ptob(sva);
- pmap_remove_entry(pmap, pv, asva);
- pmap_use_pt(pmap, asva, 0);
+ pmap_remove_entry(pmap, pv, va);
+ pmap_unuse_pt(pmap, va);
+ ++sva;
}
-endofloop:
tlbflush();
}
@@ -973,6 +961,11 @@ endofloop:
* Removes this physical page from
* all physical maps in which it resides.
* Reflects back modify bits to the pager.
+ *
+ * Notes:
+ * Original versions of this routine were very
+ * inefficient because they iteratively called
+ * pmap_remove (slow...)
*/
void
pmap_remove_all(pa)
@@ -1004,21 +997,22 @@ pmap_remove_all(pa)
pte = ptp + va;
if (pmap_pte_w(pte))
pmap->pm_stats.wired_count--;
- if (pmap_pte_v(pte))
+ if ( *pte)
pmap->pm_stats.resident_count--;
- if (((*(int *)pte & PG_M) && (pv->pv_va < USRSTACK || pv->pv_va > UPT_MAX_ADDRESS))
+ /*
+ * update the vm_page_t clean bit
+ */
+ if ( (m->flags & PG_CLEAN) &&
+ ((((int) *pte) & PG_M) && (pv->pv_va < USRSTACK || pv->pv_va > UPT_MAX_ADDRESS))
|| (pv->pv_va >= USRSTACK && pv->pv_va < USRSTACK+(UPAGES*NBPG))) {
- /*
- * don't update the dirty bit for pager mappings
- */
- if( pv->pv_va < pager_sva || pv->pv_va >= pager_eva) {
+ if (pv->pv_va < pager_sva || pv->pv_va >= pager_eva) {
m->flags &= ~PG_CLEAN;
}
}
- *(int *)pte = 0;
- pmap_use_pt(pmap, pv->pv_va, 0);
+ *pte = 0;
+ pmap_unuse_pt(pmap, pv->pv_va);
npv = pv->pv_next;
if (npv) {
@@ -1027,10 +1021,8 @@ pmap_remove_all(pa)
} else {
pv->pv_pmap = NULL;
}
-
}
splx(s);
-
tlbflush();
}
@@ -1049,7 +1041,6 @@ pmap_protect(pmap, sva, eva, prot)
register vm_offset_t va;
int i386prot;
register pt_entry_t *ptp;
- int reqactivate = 0;
int evap = i386_btop(eva);
int s;
@@ -1065,70 +1056,62 @@ pmap_protect(pmap, sva, eva, prot)
ptp = get_pt_entry(pmap);
- for (va = sva; va < eva; va += PAGE_SIZE) {
+ va = sva;
+ while (va < eva) {
+ int found=0;
+ int svap;
+ vm_offset_t nscan;
/*
* Page table page is not allocated.
* Skip it, we don't want to force allocation
* of unnecessary PTE pages just to set the protection.
*/
- if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ if (! *pmap_pde(pmap, va)) {
/* XXX: avoid address wrap around */
+nextpde:
if (va >= i386_trunc_pdr((vm_offset_t)-1))
break;
- va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE;
+ va = i386_round_pdr(va + PAGE_SIZE);
continue;
}
pte = ptp + i386_btop(va);
+ if( *pte == 0) {
/*
* scan for a non-empty pte
*/
- {
- int found=0;
- int svap = pte - ptp;
- vm_offset_t nscan =
- ((svap + (NBPG/PTESIZE)) & ~((NBPG/PTESIZE) - 1)) - svap;
+ svap = pte - ptp;
+ nscan = ((svap + NPTEPG) & ~(NPTEPG - 1)) - svap;
+
if (nscan + svap > evap)
nscan = evap - svap;
- if (nscan) {
+
+ found = 0;
+ if (nscan)
asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
:"=D"(pte),"=a"(found)
:"c"(nscan),"0"(pte):"cx");
- pte -= 1;
- svap = pte - ptp;
+ if( !found)
+ goto nextpde;
+
+ pte -= 1;
+ svap = pte - ptp;
- }
- if (svap >= evap)
- goto endofloop;
va = i386_ptob(svap);
- if (!found)
- continue;
}
- /*
- * Page not valid. Again, skip it.
- * Should we do this? Or set protection anyway?
- */
- if (!pmap_pte_v(pte))
- continue;
-
i386prot = pte_prot(pmap, prot);
-
- if (va < UPT_MIN_ADDRESS)
+ if (va < UPT_MAX_ADDRESS) {
i386prot |= PG_u;
- else if (va < UPT_MAX_ADDRESS)
- i386prot |= PG_u | PG_RW;
-
- if (i386prot != pte->pg_prot) {
- reqactivate = 1;
- pmap_pte_set_prot(pte, i386prot);
+ if( va >= UPT_MIN_ADDRESS)
+ i386prot |= PG_RW;
}
+ pmap_pte_set_prot(pte, i386prot);
+ va += PAGE_SIZE;
}
-endofloop:
- if (reqactivate)
- tlbflush();
+ tlbflush();
}
/*
@@ -1152,10 +1135,9 @@ pmap_enter(pmap, va, pa, prot, wired)
boolean_t wired;
{
register pt_entry_t *pte;
- register int npte;
+ register pt_entry_t npte;
vm_offset_t opa;
- boolean_t cacheable = TRUE;
- boolean_t checkpv = TRUE;
+ int cacheable=1;
if (pmap == NULL)
return;
@@ -1167,7 +1149,7 @@ pmap_enter(pmap, va, pa, prot, wired)
/*
* Page Directory table entry not valid, we need a new PT page
*/
- if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ if ( *pmap_pde(pmap, va) == 0) {
pg("ptdi %x, va %x", pmap->pm_pdir[PTDPTDI], va);
}
@@ -1211,7 +1193,7 @@ pmap_enter(pmap, va, pa, prot, wired)
int s;
pv = pa_to_pvh(pa);
- s = splhigh();
+ s = splimp();
/*
* No entries yet, use header as the first entry
*/
@@ -1232,11 +1214,12 @@ pmap_enter(pmap, va, pa, prot, wired)
pv->pv_next = npv;
}
splx(s);
+ cacheable = 1;
} else {
- cacheable = FALSE;
+ cacheable = 0;
}
- pmap_use_pt(pmap, va, 1);
+ pmap_use_pt(pmap, va);
/*
* Increment counters
@@ -1249,11 +1232,12 @@ validate:
/*
* Now validate mapping with desired protection/wiring.
*/
- npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V;
-
- if (!cacheable) {
- npte |= PG_N;
- }
+ npte = (pt_entry_t) ( (int) (pa | pte_prot(pmap, prot) | PG_V));
+ /*
+ * for correctness:
+ */
+ if( !cacheable)
+ (int) npte |= PG_N;
/*
* When forking (copy-on-write, etc):
@@ -1269,43 +1253,244 @@ validate:
* used (referenced) bits.
*/
if (pa == opa)
- npte |= *(int *)pte & (PG_M|PG_U);
+ (int) npte |= (int) *pte & (PG_M|PG_U);
+
if (wired)
- npte |= PG_W;
+ (int) npte |= PG_W;
if (va < UPT_MIN_ADDRESS)
- npte |= PG_u;
+ (int) npte |= PG_u;
else if (va < UPT_MAX_ADDRESS)
- npte |= PG_u | PG_RW;
+ (int) npte |= PG_u | PG_RW;
- if (npte != *(int *)pte) {
- *(int *)pte = npte;
+ if( *pte != npte) {
+ *pte = npte;
tlbflush();
}
}
/*
- * pmap_page_protect:
- *
- * Lower the permission for all mappings to a given page.
+ * add a wired page to the kva
*/
void
-pmap_page_protect(phys, prot)
- vm_offset_t phys;
- vm_prot_t prot;
+pmap_kenter(va, pa)
+ vm_offset_t va;
+ register vm_offset_t pa;
{
- void pmap_copy_on_write();
- switch (prot) {
- case VM_PROT_READ:
- case VM_PROT_READ|VM_PROT_EXECUTE:
- pmap_copy_on_write(phys);
- break;
- case VM_PROT_ALL:
- break;
- default:
- pmap_remove_all(phys);
- break;
- }
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ vm_offset_t opa;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+
+ opa = pmap_pte_pa(pte);
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (!pmap_pte_w(pte)) {
+ kernel_pmap->pm_stats.wired_count++;
+ }
+ goto validate;
+ }
+
+ if (opa) {
+ pmap_remove(kernel_pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = kernel_pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = kernel_pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ /*
+ * Increment counters
+ */
+ kernel_pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RW | PG_V | PG_W));
+}
+
+/*
+ * this code makes some *MAJOR* assumptions:
+ * 1. Current pmap & pmap exists.
+ * 2. Not wired.
+ * 3. Read access.
+ * 4. No page table pages.
+ * 5. Tlbflush is deferred to calling procedure.
+ * 6. Page IS managed.
+ * but is *MUCH* faster than pmap_enter...
+ */
+
+static inline void
+pmap_enter_quick(pmap, va, pa)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+{
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+ if (pmap_pte_pa(pte)) {
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ pmap_use_pt(pmap, va);
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RO | PG_V | PG_u));
+}
+
+/*
+ * pmap_object_init_pt preloads the ptes for a given object
+ * into the specified pmap. This eliminates the blast of soft
+ * faults on process startup and immediately after an mmap.
+ */
+void
+pmap_object_init_pt(pmap, addr, object, offset, size)
+ pmap_t pmap;
+ vm_offset_t addr;
+ vm_object_t object;
+ vm_offset_t offset;
+ vm_offset_t size;
+{
+
+ vm_offset_t tmpoff;
+ vm_page_t p;
+ int s;
+ vm_offset_t v, lastv=0;
+ pt_entry_t pte;
+ extern vm_map_t kernel_map;
+ vm_offset_t objbytes;
+
+ if (!pmap)
+ return;
+
+ /*
+ * if we are processing a major portion of the object, then
+ * scan the entire thing.
+ */
+ if( size > object->size / 2) {
+ objbytes = size;
+ p = (vm_page_t) queue_first(&object->memq);
+ while (!queue_end(&object->memq, (queue_entry_t) p) && objbytes != 0) {
+ tmpoff = p->offset;
+ if( tmpoff < offset) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+ tmpoff -= offset;
+ if( tmpoff >= size) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+
+ if ((p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0 ) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ p = (vm_page_t) queue_next(&p->listq);
+ objbytes -= NBPG;
+ }
+ } else {
+ /*
+ * else lookup the pages one-by-one.
+ */
+ for(tmpoff = 0; tmpoff < size; tmpoff += NBPG) {
+ if( p = vm_page_lookup(object, tmpoff + offset)) {
+ if( (p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ }
+ }
+ }
+
+ tlbflush();
}
/*
@@ -1343,7 +1528,7 @@ pmap_change_wiring(pmap, va, wired)
* been changed by the kernel
*/
if (!wired)
- pmap_pte_m(pte) = 1;
+ (int) *pte |= PG_M;
}
@@ -1357,14 +1542,12 @@ pmap_change_wiring(pmap, va, wired)
*/
void
pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
- pmap_t dst_pmap;
- pmap_t src_pmap;
+ pmap_t dst_pmap, src_pmap;
vm_offset_t dst_addr;
vm_size_t len;
vm_offset_t src_addr;
{
}
-
/*
* Require that all active physical maps contain no
* incorrect entries NOW. [This update includes
@@ -1450,20 +1633,23 @@ pmap_pageable(pmap, sva, eva, pageable)
{
}
+/*
+ * this routine returns true if a physical page resides
+ * in the given pmap.
+ */
boolean_t
pmap_page_exists(pmap, pa)
pmap_t pmap;
vm_offset_t pa;
{
register pv_entry_t pv;
- register int *pte;
int s;
if (!pmap_is_managed(pa))
return FALSE;
pv = pa_to_pvh(pa);
- s = splhigh();
+ s = splimp();
/*
* Not found, check current mappings returning
@@ -1481,20 +1667,25 @@ pmap_page_exists(pmap, pa)
return(FALSE);
}
+/*
+ * pmap_testbit tests bits in pte's
+ * note that the testbit/changebit routines are inline,
+ * and a lot of things compile-time evaluate.
+ */
static inline boolean_t
pmap_testbit(pa, bit)
register vm_offset_t pa;
int bit;
{
register pv_entry_t pv;
- register int *pte;
+ pt_entry_t *pte;
int s;
if (!pmap_is_managed(pa))
return FALSE;
pv = pa_to_pvh(pa);
- s = splhigh();
+ s = splimp();
/*
* Not found, check current mappings returning
@@ -1502,8 +1693,21 @@ pmap_testbit(pa, bit)
*/
if (pv->pv_pmap != NULL) {
for (; pv; pv = pv->pv_next) {
+ /*
+ * if the bit being tested is the modified bit,
+ * then mark UPAGES as always modified, and
+ * ptes as never modified.
+ */
+ if (bit & PG_U ) {
+ if ((pv->pv_va >= pager_sva) && (pv->pv_va < pager_eva)) {
+ continue;
+ }
+ }
if (bit & PG_M ) {
if (pv->pv_va >= USRSTACK) {
+ if (pv->pv_va >= pager_sva && pv->pv_va < pager_eva) {
+ continue;
+ }
if (pv->pv_va < USRSTACK+(UPAGES*NBPG)) {
splx(s);
return TRUE;
@@ -1514,8 +1718,8 @@ pmap_testbit(pa, bit)
}
}
}
- pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va);
- if (*pte & bit) {
+ pte = pmap_pte(pv->pv_pmap, pv->pv_va);
+ if ((int) *pte & bit) {
splx(s);
return TRUE;
}
@@ -1525,6 +1729,9 @@ pmap_testbit(pa, bit)
return(FALSE);
}
+/*
+ * this routine is used to modify bits in ptes
+ */
static inline void
pmap_changebit(pa, bit, setem)
vm_offset_t pa;
@@ -1532,16 +1739,15 @@ pmap_changebit(pa, bit, setem)
boolean_t setem;
{
register pv_entry_t pv;
- register int *pte, npte;
+ register pt_entry_t *pte, npte;
vm_offset_t va;
int s;
- int reqactivate = 0;
if (!pmap_is_managed(pa))
return;
pv = pa_to_pvh(pa);
- s = splhigh();
+ s = splimp();
/*
* Loop over all current mappings setting/clearing as appropos
@@ -1551,34 +1757,47 @@ pmap_changebit(pa, bit, setem)
for (; pv; pv = pv->pv_next) {
va = pv->pv_va;
- /*
- * XXX don't write protect pager mappings
- */
- if (!setem && (bit == PG_RW)) {
- extern vm_offset_t pager_sva, pager_eva;
-
- if (va >= pager_sva && va < pager_eva)
- continue;
- }
+ /*
+ * don't write protect pager mappings
+ */
+ if (!setem && (bit == PG_RW)) {
+ if (va >= pager_sva && va < pager_eva)
+ continue;
+ }
- pte = (int *) pmap_pte(pv->pv_pmap, va);
+ pte = pmap_pte(pv->pv_pmap, va);
if (setem)
- npte = *pte | bit;
+ (int) npte = (int) *pte | bit;
else
- npte = *pte & ~bit;
- if (*pte != npte) {
- *pte = npte;
- tlbflush();
- }
+ (int) npte = (int) *pte & ~bit;
+ *pte = npte;
}
}
splx(s);
+ tlbflush();
}
/*
- * Clear the modify bits on the specified physical page.
+ * pmap_page_protect:
+ *
+ * Lower the permission for all mappings to a given page.
*/
+void
+pmap_page_protect(phys, prot)
+ vm_offset_t phys;
+ vm_prot_t prot;
+{
+ if ((prot & VM_PROT_WRITE) == 0) {
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE))
+ pmap_changebit(phys, PG_RW, FALSE);
+ else
+ pmap_remove_all(phys);
+ }
+}
+/*
+ * Clear the modify bits on the specified physical page.
+ */
void
pmap_clear_modify(pa)
vm_offset_t pa;
@@ -1591,7 +1810,6 @@ pmap_clear_modify(pa)
*
* Clear the reference bit on the specified physical page.
*/
-
void
pmap_clear_reference(pa)
vm_offset_t pa;
@@ -1624,7 +1842,6 @@ boolean_t
pmap_is_modified(pa)
vm_offset_t pa;
{
-
return(pmap_testbit(pa, PG_M));
}
@@ -1680,32 +1897,17 @@ i386_protection_init()
}
#ifdef DEBUG
-void
-pmap_pvdump(pa)
- vm_offset_t pa;
-{
- register pv_entry_t pv;
-
- printf("pa %x", pa);
- for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
- printf(" -> pmap %x, va %x, flags %x",
- pv->pv_pmap, pv->pv_va, pv->pv_flags);
- pads(pv->pv_pmap);
- }
- printf(" ");
-}
-
/* print address space of pmap*/
void
pads(pm)
pmap_t pm;
{
unsigned va, i, j;
- struct pte *ptep;
+ pt_entry_t *ptep;
if (pm == kernel_pmap) return;
for (i = 0; i < 1024; i++)
- if (pm->pm_pdir[i].pd_v)
+ if (pm->pm_pdir[i])
for (j = 0; j < 1024 ; j++) {
va = (i<<PD_SHIFT)+(j<<PG_SHIFT);
if (pm == kernel_pmap && va < KERNBASE)
@@ -1718,4 +1920,23 @@ pads(pm)
} ;
}
+
+void
+pmap_pvdump(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+
+ printf("pa %x", pa);
+ for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
+#ifdef used_to_be
+ printf(" -> pmap %x, va %x, flags %x",
+ pv->pv_pmap, pv->pv_va, pv->pv_flags);
+#endif
+ printf(" -> pmap %x, va %x",
+ pv->pv_pmap, pv->pv_va);
+ pads(pv->pv_pmap);
+ }
+ printf(" ");
+}
#endif
diff --git a/sys/i386/i386/random.s b/sys/i386/i386/random.s
new file mode 100644
index 000000000000..eab2f74475f5
--- /dev/null
+++ b/sys/i386/i386/random.s
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1990,1993 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Here is a very good random number generator. This implementation is
+ * based on ``Two Fast Implementations of the "Minimal Standard" Random
+ * Number Generator'', David G. Carta, Communications of the ACM, Jan 1990,
+ * Vol 33 No 1. Do NOT modify this code unless you have a very thorough
+ * understanding of the algorithm. It's trickier than you think. If
+ * you do change it, make sure that its 10,000'th invocation returns
+ * 1043618065.
+ *
+ * Here is easier-to-decipher pseudocode:
+ *
+ * p = (16807*seed)<30:0> # e.g., the low 31 bits of the product
+ * q = (16807*seed)<62:31> # e.g., the high 31 bits starting at bit 32
+ * if (p + q < 2^31)
+ * seed = p + q
+ * else
+ * seed = ((p + q) & (2^31 - 1)) + 1
+ * return (seed);
+ *
+ * The result is in (0,2^31), e.g., it's always positive.
+ */
+#include "asm.h"
+
+ .data
+randseed:
+ .word 1
+ .text
+ENTRY(random)
+ movl $16807,%eax
+ imull randseed
+ shll $1,%edx
+ movl %eax,%ecx
+ and $0x7fffffff,%eax
+ shrl $31,%ecx
+ orl %ecx,%edx
+ addl %edx,%eax
+ jge 1f
+ incl %eax
+1:
+ movl %eax,randseed
+ ret
diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s
index 14808109213f..2f3aa9a10410 100644
--- a/sys/i386/i386/support.s
+++ b/sys/i386/i386/support.s
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: support.s,v 1.4 1994/02/01 04:09:07 davidg Exp $
+ * $Id: support.s,v 1.11 1994/06/11 02:30:05 davidg Exp $
*/
#include "assym.s" /* system definitions */
@@ -75,7 +75,7 @@ ENTRY(inw) /* val = inw(port) */
ENTRY(insb) /* insb(port, addr, cnt) */
pushl %edi
- movw 8(%esp),%dx
+ movl 8(%esp),%edx
movl 12(%esp),%edi
movl 16(%esp),%ecx
cld
@@ -88,7 +88,7 @@ ENTRY(insb) /* insb(port, addr, cnt) */
ENTRY(insw) /* insw(port, addr, cnt) */
pushl %edi
- movw 8(%esp),%dx
+ movl 8(%esp),%edx
movl 12(%esp),%edi
movl 16(%esp),%ecx
cld
@@ -99,6 +99,19 @@ ENTRY(insw) /* insw(port, addr, cnt) */
popl %edi
ret
+ENTRY(insl) /* insl(port, addr, cnt) */
+ pushl %edi
+ movl 8(%esp),%edx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insl
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
ENTRY(rtcin) /* rtcin(val) */
movl 4(%esp),%eax
outb %al,$0x70
@@ -124,7 +137,7 @@ ENTRY(outw) /* outw(port, val) */
ENTRY(outsb) /* outsb(port, addr, cnt) */
pushl %esi
- movw 8(%esp),%dx
+ movl 8(%esp),%edx
movl 12(%esp),%esi
movl 16(%esp),%ecx
cld
@@ -137,7 +150,7 @@ ENTRY(outsb) /* outsb(port, addr, cnt) */
ENTRY(outsw) /* outsw(port, addr, cnt) */
pushl %esi
- movw 8(%esp),%dx
+ movl 8(%esp),%edx
movl 12(%esp),%esi
movl 16(%esp),%ecx
cld
@@ -148,11 +161,36 @@ ENTRY(outsw) /* outsw(port, addr, cnt) */
popl %esi
ret
+ENTRY(outsl) /* outsl(port, addr, cnt) */
+ pushl %esi
+ movl 8(%esp),%edx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsl
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
/*
* bcopy family
*/
-/* void bzero(void *base, u_int cnt) */
+
+/*
+ * void bzero(void *base, u_int cnt)
+ * Special code for I486 because stosl uses lots
+ * of clocks. Makes little or no difference on DX2 type
+ * machines, but stosl is about 1/2 as fast as
+ * memory moves on a standard DX !!!!!
+ */
ENTRY(bzero)
+#if defined(I486_CPU)
+ cmpl $CPUCLASS_486,_cpu_class
+ jz 1f
+#endif
+
pushl %edi
movl 8(%esp),%edi
movl 12(%esp),%ecx
@@ -168,6 +206,107 @@ ENTRY(bzero)
popl %edi
ret
+#if defined(I486_CPU)
+ SUPERALIGN_TEXT
+1:
+ movl 4(%esp),%edx
+ movl 8(%esp),%ecx
+ xorl %eax,%eax
+/
+/ do 64 byte chunks first
+/
+/ XXX this is probably over-unrolled at least for DX2's
+/
+2:
+ cmpl $64,%ecx
+ jb 3f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ movl %eax,16(%edx)
+ movl %eax,20(%edx)
+ movl %eax,24(%edx)
+ movl %eax,28(%edx)
+ movl %eax,32(%edx)
+ movl %eax,36(%edx)
+ movl %eax,40(%edx)
+ movl %eax,44(%edx)
+ movl %eax,48(%edx)
+ movl %eax,52(%edx)
+ movl %eax,56(%edx)
+ movl %eax,60(%edx)
+ addl $64,%edx
+ subl $64,%ecx
+ jnz 2b
+ ret
+
+/
+/ do 16 byte chunks
+/
+ SUPERALIGN_TEXT
+3:
+ cmpl $16,%ecx
+ jb 4f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ addl $16,%edx
+ subl $16,%ecx
+ jnz 3b
+ ret
+
+/
+/ do 4 byte chunks
+/
+ SUPERALIGN_TEXT
+4:
+ cmpl $4,%ecx
+ jb 5f
+ movl %eax,(%edx)
+ addl $4,%edx
+ subl $4,%ecx
+ jnz 4b
+ ret
+
+/
+/ do 1 byte chunks
+/ a jump table seems to be faster than a loop or more range reductions
+/
+/ XXX need a const section for non-text
+/
+ SUPERALIGN_TEXT
+jtab:
+ .long do0
+ .long do1
+ .long do2
+ .long do3
+
+ SUPERALIGN_TEXT
+5:
+ jmp jtab(,%ecx,4)
+
+ SUPERALIGN_TEXT
+do3:
+ movw %ax,(%edx)
+ movb %al,2(%edx)
+ ret
+
+ SUPERALIGN_TEXT
+do2:
+ movw %ax,(%edx)
+ ret
+
+ SUPERALIGN_TEXT
+do1:
+ movb %al,(%edx)
+
+ SUPERALIGN_TEXT
+do0:
+ ret
+#endif /* I486_CPU */
+
/* fillw(pat, base, cnt) */
ENTRY(fillw)
pushl %edi
@@ -182,7 +321,6 @@ ENTRY(fillw)
/* filli(pat, base, cnt) */
ENTRY(filli)
-filli:
pushl %edi
movl 8(%esp),%eax
movl 12(%esp),%edi
@@ -232,8 +370,8 @@ bcopyw:
movl 20(%esp),%ecx
cmpl %esi,%edi /* potentially overlapping? */
jnb 1f
- cld /* nope, copy forwards */
shrl $1,%ecx /* copy by 16-bit words */
+ cld /* nope, copy forwards */
rep
movsw
adc %ecx,%ecx /* any bytes left? */
@@ -247,10 +385,10 @@ bcopyw:
1:
addl %ecx,%edi /* copy backwards */
addl %ecx,%esi
- std
andl $1,%ecx /* any fractional bytes? */
decl %edi
decl %esi
+ std
rep
movsb
movl 20(%esp),%ecx /* copy remainder by 16-bit words */
@@ -269,7 +407,7 @@ ENTRY(bcopyx)
cmpl $2,%eax
je bcopyw /* not _bcopyw, to avoid multiple mcounts */
cmpl $4,%eax
- je bcopy
+ je bcopy /* XXX the shared ret's break mexitcount */
jmp bcopyb
/*
@@ -286,8 +424,8 @@ bcopy:
movl 20(%esp),%ecx
cmpl %esi,%edi /* potentially overlapping? */
jnb 1f
- cld /* nope, copy forwards */
shrl $2,%ecx /* copy by 32-bit words */
+ cld /* nope, copy forwards */
rep
movsl
movl 20(%esp),%ecx
@@ -302,10 +440,10 @@ bcopy:
1:
addl %ecx,%edi /* copy backwards */
addl %ecx,%esi
- std
andl $3,%ecx /* any fractional bytes? */
decl %edi
decl %esi
+ std
rep
movsb
movl 20(%esp),%ecx /* copy remainder by 32-bit words */
@@ -395,6 +533,12 @@ ENTRY(copyout) /* copyout(from_kernel, to_user, len) */
movl %edi,%eax
addl %ebx,%eax
jc copyout_fault
+/*
+ * XXX STOP USING VM_MAXUSER_ADDRESS.
+ * It is an end address, not a max, so every time it is used correctly it
+ * looks like there is an off by one error, and of course it caused an off
+ * by one error in several places.
+ */
cmpl $VM_MAXUSER_ADDRESS,%eax
ja copyout_fault
@@ -449,13 +593,13 @@ ENTRY(copyout) /* copyout(from_kernel, to_user, len) */
/* bcopy(%esi, %edi, %ebx) */
3:
- cld
movl %ebx,%ecx
shrl $2,%ecx
+ cld
rep
movsl
movb %bl,%cl
- andb $3,%cl /* XXX can we trust the rest of %ecx on clones? */
+ andb $3,%cl
rep
movsb
@@ -488,15 +632,22 @@ ENTRY(copyin)
movl 16(%esp),%edi /* caddr_t to */
movl 20(%esp),%ecx /* size_t len */
+ /*
+ * make sure address is valid
+ */
+ movl %esi,%edx
+ addl %ecx,%edx
+ jc copyin_fault
+ cmpl $VM_MAXUSER_ADDRESS,%edx
+ ja copyin_fault
+
movb %cl,%al
shrl $2,%ecx /* copy longword-wise */
cld
- gs
rep
movsl
movb %al,%cl
andb $3,%cl /* copy remaining bytes */
- gs
rep
movsb
@@ -517,39 +668,42 @@ copyin_fault:
ret
/*
- * fu{byte,sword,word} : fetch a byte(sword, word) from user memory
+ * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
*/
ALTENTRY(fuiword)
ENTRY(fuword)
- movl __udatasel,%ax
- movl %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
- movl 4(%esp),%edx
- gs
+ movl 4(%esp),%edx /* from */
+
+ cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */
+ ja fusufault
+
movl (%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
ENTRY(fusword)
- movl __udatasel,%ax
- movl %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
movl 4(%esp),%edx
- gs
+
+ cmpl $VM_MAXUSER_ADDRESS-2,%edx
+ ja fusufault
+
movzwl (%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
ALTENTRY(fuibyte)
ENTRY(fubyte)
- movl __udatasel,%ax
- movl %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
movl 4(%esp),%edx
- gs
+
+ cmpl $VM_MAXUSER_ADDRESS-1,%edx
+ ja fusufault
+
movzbl (%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
@@ -563,15 +717,10 @@ fusufault:
ret
/*
- * su{byte,sword,word}: write a byte(word, longword) to user memory
- */
-/*
- * we only have to set the right segment selector.
+ * su{byte,sword,word}: write a byte (word, longword) to user memory
*/
ALTENTRY(suiword)
ENTRY(suword)
- movl __udatasel,%ax
- movl %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
movl 4(%esp),%edx
@@ -580,9 +729,10 @@ ENTRY(suword)
#if defined(I486_CPU) || defined(I586_CPU)
cmpl $CPUCLASS_386,_cpu_class
- jne 2f
+ jne 2f /* we only have to set the right segment selector */
#endif /* I486_CPU || I586_CPU */
+ /* XXX - page boundary crossing is still not handled */
movl %edx,%eax
shrl $IDXSHIFT,%edx
andb $0xfc,%dl
@@ -603,16 +753,16 @@ ENTRY(suword)
#endif
2:
+ cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */
+ ja fusufault
+
movl 8(%esp),%eax
- gs
movl %eax,(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx)
ret
ENTRY(susword)
- movl __udatasel,%eax
- movl %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
movl 4(%esp),%edx
@@ -624,6 +774,7 @@ ENTRY(susword)
jne 2f
#endif /* I486_CPU || I586_CPU */
+ /* XXX - page boundary crossing is still not handled */
movl %edx,%eax
shrl $IDXSHIFT,%edx
andb $0xfc,%dl
@@ -644,8 +795,10 @@ ENTRY(susword)
#endif
2:
+ cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */
+ ja fusufault
+
movw 8(%esp),%ax
- gs
movw %ax,(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx)
@@ -684,8 +837,10 @@ ENTRY(subyte)
#endif
2:
+ cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */
+ ja fusufault
+
movb 8(%esp),%al
- gs
movb %al,(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx)
@@ -702,11 +857,12 @@ ENTRY(copyoutstr)
pushl %esi
pushl %edi
movl _curpcb,%ecx
- movl $cpystrflt,PCB_ONFAULT(%ecx)
+ movl $cpystrflt,PCB_ONFAULT(%ecx) /* XXX rename copyoutstr_fault */
movl 12(%esp),%esi /* %esi = from */
movl 16(%esp),%edi /* %edi = to */
movl 20(%esp),%edx /* %edx = maxlen */
+ cld
#if defined(I386_CPU)
@@ -721,8 +877,8 @@ ENTRY(copyoutstr)
* we look at a page at a time and the end address is on a page
* boundary.
*/
- cmpl $VM_MAXUSER_ADDRESS,%edi
- jae cpystrflt
+ cmpl $VM_MAXUSER_ADDRESS-1,%edi
+ ja cpystrflt
movl %edi,%eax
shrl $IDXSHIFT,%eax
@@ -736,6 +892,7 @@ ENTRY(copyoutstr)
pushl %edx
pushl %edi
call _trapwrite
+ cld
popl %edi
popl %edx
orl %eax,%eax
@@ -747,7 +904,7 @@ ENTRY(copyoutstr)
movl $NBPG,%ecx
subl %eax,%ecx /* ecx = NBPG - (src % NBPG) */
cmpl %ecx,%edx
- jge 3f
+ jae 3f
movl %edx,%ecx /* ecx = min(ecx, edx) */
3:
orl %ecx,%ecx
@@ -780,13 +937,11 @@ ENTRY(copyoutstr)
decl %edx
jz 2f
/*
- * gs override doesn't work for stosb. Use the same explicit check
- * as in copyout(). It's much slower now because it is per-char.
- * XXX - however, it would be faster to rewrite this function to use
+ * XXX - would be faster to rewrite this function to use
* strlen() and copyout().
*/
- cmpl $VM_MAXUSER_ADDRESS,%edi
- jae cpystrflt
+ cmpl $VM_MAXUSER_ADDRESS-1,%edi
+ ja cpystrflt
lodsb
stosb
@@ -805,6 +960,28 @@ ENTRY(copyoutstr)
#endif /* I486_CPU || I586_CPU */
/*
+ * This was split from copyinstr_fault mainly because pushing gs changes the
+ * stack offsets. It's better to have it separate for mcounting too.
+ */
+cpystrflt:
+ movl $EFAULT,%eax
+cpystrflt_x:
+ /* set *lencopied and return %eax */
+ movl _curpcb,%ecx
+ movl $0,PCB_ONFAULT(%ecx)
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 1f
+ movl %ecx,(%edx)
+1:
+ popl %edi
+ popl %esi
+ ret
+
+
+/*
* copyinstr(from, to, maxlen, int *lencopied)
* copy a string from from to to, stop when a 0 character is reached.
* return ENAMETOOLONG if string is longer than maxlen, and
@@ -815,18 +992,24 @@ ENTRY(copyinstr)
pushl %esi
pushl %edi
movl _curpcb,%ecx
- movl $cpystrflt,PCB_ONFAULT(%ecx)
+ movl $copyinstr_fault,PCB_ONFAULT(%ecx)
movl 12(%esp),%esi /* %esi = from */
movl 16(%esp),%edi /* %edi = to */
movl 20(%esp),%edx /* %edx = maxlen */
+ /*
+ * XXX should avoid touching gs. Either copy the string in and
+ * check the bounds later or get its length and check the bounds
+ * and then use copyin().
+ */
+ pushl %gs
movl __udatasel,%eax
movl %ax,%gs
incl %edx
-
+ cld
1:
decl %edx
- jz 4f
+ jz 2f
gs
lodsb
stosb
@@ -836,26 +1019,27 @@ ENTRY(copyinstr)
/* Success -- 0 byte reached */
decl %edx
xorl %eax,%eax
- jmp 6f
-4:
+ jmp 3f
+2:
/* edx is zero -- return ENAMETOOLONG */
movl $ENAMETOOLONG,%eax
- jmp 6f
+ jmp 3f
-cpystrflt:
+ ALIGN_TEXT
+copyinstr_fault:
movl $EFAULT,%eax
-cpystrflt_x:
-6:
+3:
/* set *lencopied and return %eax */
movl _curpcb,%ecx
movl $0,PCB_ONFAULT(%ecx)
- movl 20(%esp),%ecx
+ movl 24(%esp),%ecx
subl %edx,%ecx
- movl 24(%esp),%edx
+ movl 28(%esp),%edx
orl %edx,%edx
- jz 7f
+ jz 4f
movl %ecx,(%edx)
-7:
+4:
+ popl %gs
popl %edi
popl %esi
ret
@@ -872,7 +1056,7 @@ ENTRY(copystr)
movl 16(%esp),%edi /* %edi = to */
movl 20(%esp),%edx /* %edx = maxlen */
incl %edx
-
+ cld
1:
decl %edx
jz 4f
@@ -971,15 +1155,6 @@ ENTRY(ssdtosd)
popl %ebx
ret
-#if 0
-/* tlbflush() */
-ENTRY(tlbflush)
- movl %cr3,%eax
- orl $I386_CR3PAT,%eax
- movl %eax,%cr3
- ret
-#endif
-
/* load_cr0(cr0) */
ENTRY(load_cr0)
movl 4(%esp),%eax
@@ -991,11 +1166,6 @@ ENTRY(rcr0)
movl %cr0,%eax
ret
-/* rcr2() */
-ENTRY(rcr2)
- movl %cr2,%eax
- ret
-
/* rcr3() */
ENTRY(rcr3)
movl %cr3,%eax
@@ -1037,4 +1207,3 @@ ENTRY(longjmp)
xorl %eax,%eax /* return(1); */
incl %eax
ret
-
diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s
index 0851bae3a001..f9d4f91c082c 100644
--- a/sys/i386/i386/swtch.s
+++ b/sys/i386/i386/swtch.s
@@ -33,15 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: swtch.s,v 1.4 1994/01/31 10:26:59 davidg Exp $
+ * $Id: swtch.s,v 1.6 1994/04/20 07:06:18 davidg Exp $
*/
#include "npx.h" /* for NNPX */
#include "assym.s" /* for preprocessor defines */
#include "errno.h" /* for error codes */
-#include "i386/isa/debug.h" /* for SHOW macros */
#include "machine/asmacros.h" /* for miscellaneous assembly macros */
+#define LOCORE /* XXX inhibit C declarations */
+#include "machine/spl.h" /* for SWI_AST_MASK ... */
+
/*****************************************************************************/
/* Scheduling */
@@ -132,23 +134,31 @@ rem3: .asciz "remrq"
sw0: .asciz "swtch"
/*
- * When no processes are on the runq, Swtch branches to idle
+ * When no processes are on the runq, swtch() branches to _idle
* to wait for something to come ready.
*/
ALIGN_TEXT
-Idle:
+_idle:
+ MCOUNT
movl _IdlePTD,%ecx
movl %ecx,%cr3
movl $tmpstk-4,%esp
sti
- SHOW_STI
+
+ /*
+ * XXX callers of swtch() do a bogus splclock(). Locking should
+ * be left to swtch().
+ */
+ movl $SWI_AST_MASK,_cpl
+ testl $~SWI_AST_MASK,_ipending
+ je idle_loop
+ call _splz
ALIGN_TEXT
idle_loop:
- call _spl0
cli
cmpl $0,_whichqs
- jne sw1
+ jne sw1a
sti
hlt /* wait for interrupt */
jmp idle_loop
@@ -161,9 +171,7 @@ badsw:
/*
* Swtch()
*/
- SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */
ENTRY(swtch)
-
incl _cnt+V_SWTCH
/* switch to new process. first, save context as needed */
@@ -208,14 +216,14 @@ ENTRY(swtch)
/* save is done, now choose a new process or idle */
sw1:
cli
- SHOW_CLI
+sw1a:
movl _whichqs,%edi
2:
/* XXX - bsf is sloow */
bsfl %edi,%eax /* find a full q */
- je Idle /* if none, idle */
+ je _idle /* if none, idle */
+
/* XX update whichqs? */
-swfnd:
btrl %eax,%edi /* clear q full status */
jnb 2b /* if it was clear, look for another */
movl %eax,%ebx /* save which one we are using */
@@ -296,7 +304,6 @@ swfnd:
*/
pushl PCB_IML(%edx)
sti
- SHOW_STI
#if 0
call _splx
#endif
@@ -312,7 +319,7 @@ ENTRY(mvesp)
movl %esp,%eax
ret
/*
- * struct proc *swtch_to_inactive(p) ; struct proc *p;
+ * struct proc *swtch_to_inactive(struct proc *p);
*
* At exit of a process, move off the address space of the
* process and onto a "safe" one. Then, on a temporary stack
@@ -327,6 +334,7 @@ ENTRY(swtch_to_inactive)
movl %ecx,%cr3 /* good bye address space */
#write buffer?
movl $tmpstk-4,%esp /* temporary stack, compensated for call */
+ MEXITCOUNT
jmp %edx /* return, execute remainder of cleanup */
/*
@@ -418,7 +426,7 @@ ENTRY(addupc)
movl 8(%ebp),%eax /* pc */
subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
- jl L1 /* if (pc < 0) return */
+ jb L1 /* if (pc was < off) return */
shrl $1,%eax /* praddr = pc >> 1 */
imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
@@ -448,8 +456,3 @@ proffault:
movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
leave
ret
-
-/* To be done: */
-ENTRY(astoff)
- ret
-
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 34a2993ba1e7..c21693c85990 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (C) 1994, David Greenman
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
@@ -34,11 +35,11 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
- * $Id: trap.c,v 1.17 1994/02/08 09:26:01 davidg Exp $
+ * $Id: trap.c,v 1.27 1994/06/22 05:52:30 jkh Exp $
*/
/*
- * 386 Trap and System call handleing
+ * 386 Trap and System call handling
*/
#include "isa.h"
@@ -68,28 +69,13 @@
#include "machine/trap.h"
-#ifdef __GNUC__
-
-/*
- * The "r" contraint could be "rm" except for fatal bugs in gas. As usual,
- * we omit the size from the mov instruction to avoid nonfatal bugs in gas.
- */
-#define read_gs() ({ u_short gs; __asm("mov %%gs,%0" : "=r" (gs)); gs; })
-#define write_gs(newgs) __asm("mov %0,%%gs" : : "r" ((u_short) newgs))
-
-#else /* not __GNUC__ */
-
-u_short read_gs __P((void));
-void write_gs __P((/* promoted u_short */ int gs));
-
-#endif /* __GNUC__ */
+int trap_pfault __P((struct trapframe *, int));
+void trap_fatal __P((struct trapframe *));
extern int grow(struct proc *,int);
struct sysent sysent[];
int nsysent;
-extern short cpl;
-extern short netmask, ttymask, biomask;
#define MAX_TRAP_MSG 27
char *trap_msg[] = {
@@ -102,7 +88,7 @@ char *trap_msg[] = {
"arithmetic trap", /* 6 T_ARITHTRAP */
"system forced exception", /* 7 T_ASTFLT */
"segmentation (limit) fault", /* 8 T_SEGFLT */
- "protection fault", /* 9 T_PROTFLT */
+ "general protection fault", /* 9 T_PROTFLT */
"trace trap", /* 10 T_TRCTRAP */
"", /* 11 unused */
"page fault", /* 12 T_PAGEFLT */
@@ -123,15 +109,59 @@ char *trap_msg[] = {
"stack fault", /* 27 T_STKFLT */
};
-#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+static inline void
+userret(p, frame, osyst)
+ struct proc *p;
+ struct trapframe *frame;
+ struct timeval *osyst;
+{
+ int sig, s;
+
+ while (sig = CURSIG(p))
+ psig(sig);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happend after we put ourselves on the run queue
+ * but before swtch()'ed, we might not be on the queue
+ * indicated by our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (sig = CURSIG(p))
+ psig(sig);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - osyst->tv_sec) * 1000 +
+ (tv->tv_usec - osyst->tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame->tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame->tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+}
/*
* trap(frame):
- * Exception, fault, and trap interface to BSD kernel. This
- * common code is called from assembly language IDT gate entry
+ * Exception, fault, and trap interface to the FreeBSD kernel.
+ * This common code is called from assembly language IDT gate entry
* routines that prepare a suitable stack frame, and restore this
- * frame after the exception has been processed. Note that the
- * effect is as if the arguments were passed call by reference.
+ * frame after the exception has been processed.
*/
/*ARGSUSED*/
@@ -139,361 +169,369 @@ void
trap(frame)
struct trapframe frame;
{
- register int i;
- register struct proc *p = curproc;
+ struct proc *p = curproc;
struct timeval syst;
- int ucode, type, code, eva, fault_type;
+ int i = 0, ucode = 0, type, code, eva, fault_type;
frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
type = frame.tf_trapno;
+ code = frame.tf_err;
+
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ /* user trap */
+
+ syst = p->p_stime;
+ p->p_regs = (int *)&frame;
+
+ switch (type) {
+ case T_RESADFLT: /* reserved addressing fault */
+ case T_PRIVINFLT: /* privileged instruction fault */
+ case T_RESOPFLT: /* reserved operand fault */
+ ucode = type;
+ i = SIGILL;
+ break;
+
+ case T_BPTFLT: /* bpt instruction fault */
+ case T_TRCTRAP: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+ case T_ARITHTRAP: /* arithmetic trap */
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ case T_ASTFLT: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_PROTFLT: /* general protection fault */
+ case T_SEGNPFLT: /* segment not present fault */
+ case T_STKFLT: /* stack fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PAGEFLT: /* page fault */
+ i = trap_pfault(&frame, TRUE);
+
+ if (i == 0)
+ goto out;
+
+ ucode = T_PAGEFLT;
+ break;
+
+ case T_DIVIDE: /* integer divide fault */
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+#if NISA > 0
+ case T_NMI:
#if NDDB > 0
- if (curpcb && curpcb->pcb_onfault) {
- if (frame.tf_trapno == T_BPTFLT
- || frame.tf_trapno == T_TRCTRAP)
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
if (kdb_trap (type, 0, &frame))
return;
- }
#endif
-
- if (curpcb == 0 || curproc == 0)
- goto skiptoswitch;
- if (curpcb->pcb_onfault && frame.tf_trapno != T_PAGEFLT) {
- extern int _udatasel;
-
- if (read_gs() != (u_short) _udatasel)
- /*
- * Some user has corrupted %gs but we depend on it in
- * copyout() etc. Fix it up and retry.
- *
- * (We don't preserve %fs or %gs, so users can change
- * them to either _ucodesel, _udatasel or a not-present
- * selector, possibly ORed with 0 to 3, making them
- * volatile for other users. Not preserving them saves
- * time and doesn't lose functionality or open security
- * holes.)
- */
- write_gs(_udatasel);
- else
-copyfault:
- frame.tf_eip = (int)curpcb->pcb_onfault;
- return;
- }
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(code) == 0) return;
+ /* FALL THROUGH */
+#endif
- syst = p->p_stime;
- if (ISPL(frame.tf_cs) == SEL_UPL) {
- type |= T_USER;
- p->p_regs = (int *)&frame;
- }
+ case T_OFLOW: /* integer overflow fault */
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
-skiptoswitch:
- ucode=0;
- eva = rcr2();
- code = frame.tf_err;
+ case T_BOUND: /* bounds check fault */
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
- if ((type & ~T_USER) == T_PAGEFLT)
- goto pfault;
+ case T_DNA:
+#if NNPX > 0
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna())
+ return;
+#endif /* NNPX > 0 */
- switch (type) {
- case T_SEGNPFLT|T_USER:
- case T_STKFLT|T_USER:
- case T_PROTFLT|T_USER: /* protection fault */
- ucode = code + BUS_SEGM_FAULT ;
- i = SIGBUS;
- break;
+#if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
+ i = math_emulate(&frame);
+ if (i == 0) {
+ if (!(frame.tf_eflags & PSL_T))
+ return;
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ }
+ /* else ucode = emulator_only_knows() XXX */
+#else /* MATH_EMULATE || GPL_MATH_EMULATE */
+ i = SIGFPE;
+ ucode = FPE_FPU_NP_TRAP;
+#endif /* MATH_EMULATE || GPL_MATH_EMULATE */
+ break;
+
+ case T_FPOPFLT: /* FPU operand fetch fault */
+ ucode = T_FPOPFLT;
+ i = SIGILL;
+ break;
+
+ default:
+ trap_fatal(&frame);
+ }
+ } else {
+ /* kernel trap */
- case T_PRIVINFLT|T_USER: /* privileged instruction fault */
- case T_RESADFLT|T_USER: /* reserved addressing fault */
- case T_RESOPFLT|T_USER: /* reserved operand fault */
- case T_FPOPFLT|T_USER: /* coprocessor operand fault */
- ucode = type &~ T_USER;
- i = SIGILL;
- break;
+ switch (type) {
+ case T_PAGEFLT: /* page fault */
+ (void) trap_pfault(&frame, FALSE);
+ return;
- case T_ASTFLT|T_USER: /* Allow process switch */
- astoff();
- cnt.v_soft++;
- if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
- addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
- p->p_flag &= ~SOWEUPC;
+ case T_PROTFLT: /* general protection fault */
+ case T_SEGNPFLT: /* segment not present fault */
+ if (curpcb && curpcb->pcb_onfault) {
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+ break;
+
+#if NDDB > 0
+ case T_BPTFLT:
+ case T_TRCTRAP:
+ if (kdb_trap (type, 0, &frame))
+ return;
+ break;
+#else
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ /* Q: how do we turn it on again? */
+ frame.tf_eflags &= ~PSL_T;
+ return;
+#endif
+
+#if NISA > 0
+ case T_NMI:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(code) == 0) return;
+ /* FALL THROUGH */
+#endif
}
- goto out;
- case T_DNA|T_USER:
-#if NNPX > 0
- /* if a transparent fault (due to context switch "late") */
- if (npxdna()) return;
-#endif /* NNPX > 0 */
-#ifdef MATH_EMULATE
- i = math_emulate(&frame);
- if (i == 0) return;
-#else /* MATH_EMULTATE */
- panic("trap: math emulation necessary!");
-#endif /* MATH_EMULTATE */
- ucode = FPE_FPU_NP_TRAP;
- break;
+ trap_fatal(&frame);
+ }
- case T_BOUND|T_USER:
- ucode = FPE_SUBRNG_TRAP;
- i = SIGFPE;
- break;
+ trapsignal(p, i, ucode);
- case T_OFLOW|T_USER:
- ucode = FPE_INTOVF_TRAP;
- i = SIGFPE;
- break;
+#ifdef DIAGNOSTIC
+ eva = rcr2();
+ if (type <= MAX_TRAP_MSG) {
+ uprintf("fatal process exception: %s",
+ trap_msg[type]);
+ if ((type == T_PAGEFLT) || (type == T_PROTFLT))
+ uprintf(", fault VA = 0x%x", eva);
+ uprintf("\n");
+ }
+#endif
- case T_DIVIDE|T_USER:
- ucode = FPE_INTDIV_TRAP;
- i = SIGFPE;
- break;
+out:
+ userret(p, &frame, &syst);
+}
- case T_ARITHTRAP|T_USER:
- ucode = code;
- i = SIGFPE;
- break;
+int
+trap_pfault(frame, usermode)
+ struct trapframe *frame;
+ int usermode;
+{
+ vm_offset_t va;
+ struct vmspace *vm;
+ vm_map_t map = 0;
+ int rv = 0, oldflags;
+ vm_prot_t ftype;
+ extern vm_map_t kernel_map;
+ int eva;
+ struct proc *p = curproc;
+
+ eva = rcr2();
+ va = trunc_page((vm_offset_t)eva);
- pfault:
- case T_PAGEFLT: /* allow page faults in kernel mode */
- case T_PAGEFLT|T_USER: /* page fault */
- {
- vm_offset_t va;
- struct vmspace *vm;
- vm_map_t map = 0;
- int rv = 0, oldflags;
- vm_prot_t ftype;
- unsigned nss, v;
- extern vm_map_t kernel_map;
+ /*
+ * Don't allow user-mode faults in kernel address space
+ */
+ if (usermode && (va >= KERNBASE)) {
+ goto nogo;
+ }
+
+ if ((p == 0) || (va >= KERNBASE)) {
+ vm = 0;
+ map = kernel_map;
+ } else {
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+ }
+
+ if (frame->tf_err & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
- va = trunc_page((vm_offset_t)eva);
+ oldflags = p->p_flag;
+ if (map != kernel_map) {
+ vm_offset_t pa;
+ vm_offset_t v = (vm_offset_t) vtopte(va);
+ vm_page_t ptepg;
/*
- * Don't allow user-mode faults in kernel address space
+ * Keep swapout from messing with us during this
+ * critical time.
*/
- if ((type == (T_PAGEFLT|T_USER)) && (va >= KERNBASE)) {
- goto nogo;
- }
+ p->p_flag |= SLOCK;
- if ((p == 0) || (type == T_PAGEFLT && va >= KERNBASE)) {
- vm = 0;
- map = kernel_map;
- } else {
- vm = p->p_vmspace;
- map = &vm->vm_map;
+ /*
+ * Grow the stack if necessary
+ */
+ if ((caddr_t)va > vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ rv = KERN_FAILURE;
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ goto nogo;
+ }
}
- if (code & PGEX_W)
- ftype = VM_PROT_READ | VM_PROT_WRITE;
- else
- ftype = VM_PROT_READ;
-
- oldflags = p->p_flag;
- if (map != kernel_map) {
- vm_offset_t pa;
- vm_offset_t v = (vm_offset_t) vtopte(va);
-
- /*
- * Keep swapout from messing with us during this
- * critical time.
- */
- p->p_flag |= SLOCK;
-
- /*
- * Grow the stack if necessary
- */
- if ((caddr_t)va > vm->vm_maxsaddr
- && (caddr_t)va < (caddr_t)USRSTACK) {
- if (!grow(p, va)) {
- rv = KERN_FAILURE;
- p->p_flag &= ~SLOCK;
- p->p_flag |= (oldflags & SLOCK);
- goto nogo;
- }
- }
+ /*
+ * Check if page table is mapped, if not,
+ * fault it first
+ */
- /*
- * Check if page table is mapped, if not,
- * fault it first
- */
+ /* Fault the pte only if needed: */
+ *(volatile char *)v += 0;
- /* Fault the pte only if needed: */
- *(volatile char *)v += 0;
+ ptepg = (vm_page_t) pmap_pte_vm_page(vm_map_pmap(map), v);
+ if( ptepg->hold_count == 0)
+ ptepg->act_count += 3;
+ vm_page_hold(ptepg);
- /* Get the physical address: */
- pa = pmap_extract(vm_map_pmap(map), v);
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype, FALSE);
- /* And wire the pte page at system vm level: */
- vm_page_wire(PHYS_TO_VM_PAGE(pa));
+ vm_page_unhold(ptepg);
- /* Fault in the user page: */
- rv = vm_fault(map, va, ftype, FALSE);
+ /*
+ * page table pages don't need to be kept if they
+ * are not held
+ */
+ if( ptepg->hold_count == 0 && ptepg->wire_count == 0) {
+ pmap_page_protect( VM_PAGE_TO_PHYS(ptepg),
+ VM_PROT_NONE);
+ vm_page_free(ptepg);
+ }
- /* Unwire the pte page: */
- vm_page_unwire(PHYS_TO_VM_PAGE(pa));
- p->p_flag &= ~SLOCK;
- p->p_flag |= (oldflags & SLOCK);
- } else {
- /*
- * Since we know that kernel virtual address addresses
- * always have pte pages mapped, we just have to fault
- * the page.
- */
- rv = vm_fault(map, va, ftype, FALSE);
- }
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ } else {
+ /*
+ * Since we know that kernel virtual address addresses
+ * always have pte pages mapped, we just have to fault
+ * the page.
+ */
+ rv = vm_fault(map, va, ftype, FALSE);
+ }
- if (rv == KERN_SUCCESS) {
- if (type == T_PAGEFLT)
- return;
- goto out;
- }
+ if (rv == KERN_SUCCESS)
+ return (0);
nogo:
- if (type == T_PAGEFLT) {
- if (curpcb->pcb_onfault)
- goto copyfault;
-
- goto we_re_toast;
+ if (!usermode) {
+ if (curpcb->pcb_onfault) {
+ frame->tf_eip = (int)curpcb->pcb_onfault;
+ return (0);
}
- i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ trap_fatal(frame);
+ }
- /* kludge to pass faulting virtual address to sendsig */
- ucode = type &~ T_USER;
- frame.tf_err = eva;
+ /* kludge to pass faulting virtual address to sendsig */
+ frame->tf_err = eva;
- break;
- }
+ return((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
+}
-#if NDDB == 0
- case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
- frame.tf_eflags &= ~PSL_T;
+void
+trap_fatal(frame)
+ struct trapframe *frame;
+{
+ int code, type, eva;
- /* Q: how do we turn it on again? */
- return;
-#endif
-
- case T_BPTFLT|T_USER: /* bpt instruction fault */
- case T_TRCTRAP|T_USER: /* trace trap */
- frame.tf_eflags &= ~PSL_T;
- i = SIGTRAP;
- break;
+ code = frame->tf_err;
+ type = frame->tf_trapno;
+ eva = rcr2();
-#if NISA > 0
- case T_NMI:
- case T_NMI|T_USER:
-#if NDDB > 0
- /* NMI can be hooked up to a pushbutton for debugging */
- printf ("NMI ... going to debugger\n");
- if (kdb_trap (type, 0, &frame))
- return;
-#endif
- /* machine/parity/power fail/"kitchen sink" faults */
- if (isa_nmi(code) == 0) return;
- /* FALL THROUGH */
-#endif
- default:
- we_re_toast:
-
- fault_type = type & ~T_USER;
- if (fault_type <= MAX_TRAP_MSG)
- printf("\n\nFatal trap %d: %s while in %s mode\n",
- fault_type, trap_msg[fault_type],
- ISPL(frame.tf_cs) == SEL_UPL ? "user" : "kernel");
- if (fault_type == T_PAGEFLT) {
- printf("fault virtual address = 0x%x\n", eva);
- printf("fault code = %s %s, %s\n",
- code & PGEX_U ? "user" : "supervisor",
- code & PGEX_W ? "write" : "read",
- code & PGEX_P ? "protection violation" : "page not present");
- }
- printf("instruction pointer = 0x%x\n", frame.tf_eip);
- printf("processor eflags = ");
- if (frame.tf_eflags & EFL_TF)
- printf("trace/trap, ");
- if (frame.tf_eflags & EFL_IF)
- printf("interrupt enabled, ");
- if (frame.tf_eflags & EFL_NT)
- printf("nested task, ");
- if (frame.tf_eflags & EFL_RF)
- printf("resume, ");
- if (frame.tf_eflags & EFL_VM)
- printf("vm86, ");
- printf("IOPL = %d\n", (frame.tf_eflags & EFL_IOPL) >> 12);
- printf("current process = ");
- if (curproc) {
- printf("%d (%s)\n",
- curproc->p_pid, curproc->p_comm ?
- curproc->p_comm : "");
- } else {
- printf("Idle\n");
- }
- printf("interrupt mask = ");
- if ((cpl & netmask) == netmask)
- printf("net ");
- if ((cpl & ttymask) == ttymask)
- printf("tty ");
- if ((cpl & biomask) == biomask)
- printf("bio ");
- if (cpl == 0)
- printf("none");
- printf("\n");
+ if (type <= MAX_TRAP_MSG)
+ printf("\n\nFatal trap %d: %s while in %s mode\n",
+ type, trap_msg[type],
+ ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel");
+ if (type == T_PAGEFLT) {
+ printf("fault virtual address = 0x%x\n", eva);
+ printf("fault code = %s %s, %s\n",
+ code & PGEX_U ? "user" : "supervisor",
+ code & PGEX_W ? "write" : "read",
+ code & PGEX_P ? "protection violation" : "page not present");
+ }
+ printf("instruction pointer = 0x%x\n", frame->tf_eip);
+ printf("processor eflags = ");
+ if (frame->tf_eflags & EFL_TF)
+ printf("trace/trap, ");
+ if (frame->tf_eflags & EFL_IF)
+ printf("interrupt enabled, ");
+ if (frame->tf_eflags & EFL_NT)
+ printf("nested task, ");
+ if (frame->tf_eflags & EFL_RF)
+ printf("resume, ");
+ if (frame->tf_eflags & EFL_VM)
+ printf("vm86, ");
+ printf("IOPL = %d\n", (frame->tf_eflags & EFL_IOPL) >> 12);
+ printf("current process = ");
+ if (curproc) {
+ printf("%d (%s)\n",
+ curproc->p_pid, curproc->p_comm ?
+ curproc->p_comm : "");
+ } else {
+ printf("Idle\n");
+ }
+ printf("interrupt mask = ");
+ if ((cpl & net_imask) == net_imask)
+ printf("net ");
+ if ((cpl & tty_imask) == tty_imask)
+ printf("tty ");
+ if ((cpl & bio_imask) == bio_imask)
+ printf("bio ");
+ if (cpl == 0)
+ printf("none");
+ printf("\n");
#ifdef KDB
- if (kdb_trap(&psl))
- return;
+ if (kdb_trap(&psl))
+ return;
#endif
#if NDDB > 0
- if (kdb_trap (type, 0, &frame))
- return;
-#endif
- if (fault_type <= MAX_TRAP_MSG)
- panic(trap_msg[fault_type]);
- else
- panic("unknown/reserved trap");
-
- /* NOT REACHED */
- }
-
- trapsignal(p, i, ucode);
- if ((type & T_USER) == 0)
+ if (kdb_trap (type, 0, frame))
return;
-out:
- while (i = CURSIG(p))
- psig(i);
- p->p_pri = p->p_usrpri;
- if (want_resched) {
- int s;
- /*
- * Since we are curproc, clock will normally just change
- * our priority without moving us from one queue to another
- * (since the running process is not on a queue.)
- * If that happened after we setrq ourselves but before we
- * swtch()'ed, we might not be on the queue indicated by
- * our priority.
- */
- s = splclock();
- setrq(p);
- p->p_stats->p_ru.ru_nivcsw++;
- swtch();
- splx(s);
- while (i = CURSIG(p))
- psig(i);
- }
- if (p->p_stats->p_prof.pr_scale) {
- int ticks;
- struct timeval *tv = &p->p_stime;
-
- ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
- (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
- if (ticks) {
-#ifdef PROFTIMER
- extern int profscale;
- addupc(frame.tf_eip, &p->p_stats->p_prof,
- ticks * profscale);
-#else
- addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
#endif
- }
- }
- curpri = p->p_pri;
+ if (type <= MAX_TRAP_MSG)
+ panic(trap_msg[type]);
+ else
+ panic("unknown/reserved trap");
}
/*
@@ -505,7 +543,6 @@ out:
int trapwrite(addr)
unsigned addr;
{
- unsigned nss;
struct proc *p;
vm_offset_t va, v;
struct vmspace *vm;
@@ -572,21 +609,17 @@ int trapwrite(addr)
/*ARGSUSED*/
void
syscall(frame)
- volatile struct trapframe frame;
+ struct trapframe frame;
{
- register int *locr0 = ((int *)&frame);
- register caddr_t params;
- register int i;
- register struct sysent *callp;
- register struct proc *p = curproc;
+ caddr_t params;
+ int i;
+ struct sysent *callp;
+ struct proc *p = curproc;
struct timeval syst;
int error, opc;
int args[8], rval[2];
int code;
-#ifdef lint
- r0 = 0; r0 = r0; r1 = 0; r1 = r1;
-#endif
syst = p->p_stime;
if (ISPL(frame.tf_cs) != SEL_UPL)
panic("syscall");
@@ -610,13 +643,11 @@ syscall(frame)
if ((i = callp->sy_narg * sizeof (int)) &&
(error = copyin(params, (caddr_t)args, (u_int)i))) {
- frame.tf_eax = error;
- frame.tf_eflags |= PSL_C; /* carry bit */
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
#endif
- goto done;
+ goto bad;
}
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
@@ -624,81 +655,40 @@ syscall(frame)
#endif
rval[0] = 0;
rval[1] = frame.tf_edx;
-/*pg("%d. s %d\n", p->p_pid, code);*/
+
error = (*callp->sy_call)(p, args, rval);
- if (error == ERESTART)
- frame.tf_eip = opc;
- else if (error != EJUSTRETURN) {
- if (error) {
-/*pg("error %d", error);*/
- frame.tf_eax = error;
- frame.tf_eflags |= PSL_C; /* carry bit */
- } else {
- frame.tf_eax = rval[0];
- frame.tf_edx = rval[1];
- frame.tf_eflags &= ~PSL_C; /* carry bit */
- }
- }
- /* else if (error == EJUSTRETURN) */
- /* nothing to do */
-done:
- /*
- * Reinitialize proc pointer `p' as it may be different
- * if this is a child returning from fork syscall.
- */
- p = curproc;
- while (i = CURSIG(p))
- psig(i);
- p->p_pri = p->p_usrpri;
- if (want_resched) {
- int s;
+
+ switch (error) {
+
+ case 0:
/*
- * Since we are curproc, clock will normally just change
- * our priority without moving us from one queue to another
- * (since the running process is not on a queue.)
- * If that happened after we setrq ourselves but before we
- * swtch()'ed, we might not be on the queue indicated by
- * our priority.
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
*/
- s = splclock();
- setrq(p);
- p->p_stats->p_ru.ru_nivcsw++;
- swtch();
- splx(s);
- while (i = CURSIG(p))
- psig(i);
- }
- if (p->p_stats->p_prof.pr_scale) {
- int ticks;
- struct timeval *tv = &p->p_stime;
+ p = curproc;
+ frame.tf_eax = rval[0];
+ frame.tf_edx = rval[1];
+ frame.tf_eflags &= ~PSL_C; /* carry bit */
+ break;
- ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
- (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
- if (ticks) {
-#ifdef PROFTIMER
- extern int profscale;
- addupc(frame.tf_eip, &p->p_stats->p_prof,
- ticks * profscale);
-#else
- addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
-#endif
- }
+ case ERESTART:
+ frame.tf_eip = opc;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ bad:
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+ break;
}
- curpri = p->p_pri;
+
+ userret(p, &frame, &syst);
+
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p->p_tracep, code, error, rval[0]);
#endif
-#ifdef DIAGNOSTICx
-{ extern int _udatasel, _ucodesel;
- if (frame.tf_ss != _udatasel)
- printf("ss %x call %d\n", frame.tf_ss, code);
- if ((frame.tf_cs&0xffff) != _ucodesel)
- printf("cs %x call %d\n", frame.tf_cs, code);
- if (frame.tf_eip > VM_MAXUSER_ADDRESS) {
- printf("eip %x call %d\n", frame.tf_eip, code);
- frame.tf_eip = 0;
- }
-}
-#endif
}
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index ac7174eb8b53..8b7e625cf41e 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 1982, 1986 The Regents of the University of California.
* Copyright (c) 1989, 1990 William Jolitz
+ * Copyright (c) 1994 John Dyson
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -37,7 +38,7 @@
*
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
- * $Id: vm_machdep.c,v 1.11.2.1 1994/03/24 08:56:56 rgrimes Exp $
+ * $Id: vm_machdep.c,v 1.28 1994/06/06 12:08:16 davidg Exp $
*/
#include "npx.h"
@@ -53,6 +54,837 @@
#include "vm/vm.h"
#include "vm/vm_kern.h"
+#define b_cylin b_resid
+
+#define MAXCLSTATS 256
+int clstats[MAXCLSTATS];
+int rqstats[MAXCLSTATS];
+
+
+#ifndef NOBOUNCE
+vm_map_t io_map;
+volatile int kvasfreecnt;
+
+
+caddr_t bouncememory;
+int bouncepages, bpwait;
+vm_offset_t *bouncepa;
+int bmwait, bmfreeing;
+
+#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
+int bounceallocarraysize;
+unsigned *bounceallocarray;
+int bouncefree;
+
+#define SIXTEENMEG (4096*4096)
+#define MAXBKVA 1024
+
+/* special list that can be used at interrupt time for eventual kva free */
+struct kvasfree {
+ vm_offset_t addr;
+ vm_offset_t size;
+} kvaf[MAXBKVA];
+
+
+vm_offset_t vm_bounce_kva();
+/*
+ * get bounce buffer pages (count physically contiguous)
+ * (only 1 inplemented now)
+ */
+vm_offset_t
+vm_bounce_page_find(count)
+ int count;
+{
+ int bit;
+ int s,i;
+
+ if (count != 1)
+ panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
+
+ s = splbio();
+retry:
+ for (i = 0; i < bounceallocarraysize; i++) {
+ if (bounceallocarray[i] != 0xffffffff) {
+ if (bit = ffs(~bounceallocarray[i])) {
+ bounceallocarray[i] |= 1 << (bit - 1) ;
+ bouncefree -= count;
+ splx(s);
+ return bouncepa[(i * BITS_IN_UNSIGNED + (bit - 1))];
+ }
+ }
+ }
+ bpwait = 1;
+ tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
+ goto retry;
+}
+
+void
+vm_bounce_kva_free(addr, size, now)
+ vm_offset_t addr;
+ vm_offset_t size;
+ int now;
+{
+ int s = splbio();
+ kvaf[kvasfreecnt].addr = addr;
+ kvaf[kvasfreecnt].size = size;
+ ++kvasfreecnt;
+ if( now) {
+ /*
+ * this will do wakeups
+ */
+ vm_bounce_kva(0,0);
+ } else {
+ if (bmwait) {
+ /*
+ * if anyone is waiting on the bounce-map, then wakeup
+ */
+ wakeup((caddr_t) io_map);
+ bmwait = 0;
+ }
+ }
+ splx(s);
+}
+
+/*
+ * free count bounce buffer pages
+ */
+void
+vm_bounce_page_free(pa, count)
+ vm_offset_t pa;
+ int count;
+{
+ int allocindex;
+ int index;
+ int bit;
+
+ if (count != 1)
+ panic("vm_bounce_page_free -- no support for > 1 page yet!!!\n");
+
+ for(index=0;index<bouncepages;index++) {
+ if( pa == bouncepa[index])
+ break;
+ }
+
+ if( index == bouncepages)
+ panic("vm_bounce_page_free: invalid bounce buffer");
+
+ allocindex = index / BITS_IN_UNSIGNED;
+ bit = index % BITS_IN_UNSIGNED;
+
+ bounceallocarray[allocindex] &= ~(1 << bit);
+
+ bouncefree += count;
+ if (bpwait) {
+ bpwait = 0;
+ wakeup((caddr_t) &bounceallocarray);
+ }
+}
+
+/*
+ * allocate count bounce buffer kva pages
+ */
+vm_offset_t
+vm_bounce_kva(size, waitok)
+ int size;
+ int waitok;
+{
+ int i;
+ int startfree;
+ vm_offset_t kva = 0;
+ int s = splbio();
+more:
+ if (!bmfreeing && kvasfreecnt) {
+ bmfreeing = 1;
+ for (i = 0; i < kvasfreecnt; i++) {
+ pmap_remove(kernel_pmap,
+ kvaf[i].addr, kvaf[i].addr + kvaf[i].size);
+ kmem_free_wakeup(io_map, kvaf[i].addr,
+ kvaf[i].size);
+ }
+ kvasfreecnt = 0;
+ bmfreeing = 0;
+ if( bmwait) {
+ bmwait = 0;
+ wakeup( (caddr_t) io_map);
+ }
+ }
+
+ if( size == 0) {
+ splx(s);
+ return NULL;
+ }
+
+ if ((kva = kmem_alloc_pageable(io_map, size)) == 0) {
+ if( !waitok) {
+ splx(s);
+ return NULL;
+ }
+ bmwait = 1;
+ tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
+ goto more;
+ }
+ splx(s);
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva -- but really allocate (but takes pages as arg)
+ */
+vm_offset_t
+vm_bounce_kva_alloc(count)
+int count;
+{
+ int i;
+ vm_offset_t kva;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
+ return kva;
+ }
+ kva = vm_bounce_kva(count*NBPG, 1);
+ for(i=0;i<count;i++) {
+ pa = vm_bounce_page_find(1);
+ pmap_kenter(kva + i * NBPG, pa);
+ }
+ pmap_update();
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva_free -- but really free
+ */
+void
+vm_bounce_kva_alloc_free(kva, count)
+ vm_offset_t kva;
+ int count;
+{
+ int i;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ free((caddr_t) kva, M_TEMP);
+ return;
+ }
+ for(i = 0; i < count; i++) {
+ pa = pmap_kextract(kva + i * NBPG);
+ vm_bounce_page_free(pa, 1);
+ }
+ vm_bounce_kva_free(kva, count*NBPG, 0);
+}
+
+/*
+ * do the things necessary to the struct buf to implement
+ * bounce buffers... inserted before the disk sort
+ */
+void
+vm_bounce_alloc(bp)
+ struct buf *bp;
+{
+ int countvmpg;
+ vm_offset_t vastart, vaend;
+ vm_offset_t vapstart, vapend;
+ vm_offset_t va, kva;
+ vm_offset_t pa;
+ int dobounceflag = 0;
+ int bounceindex;
+ int i;
+ int s;
+
+ if (bouncepages == 0)
+ return;
+
+ if (bp->b_flags & B_BOUNCE) {
+ printf("vm_bounce_alloc: called recursively???\n");
+ return;
+ }
+
+ if (bp->b_bufsize < bp->b_bcount) {
+ printf("vm_bounce_alloc: b_bufsize(0x%x) < b_bcount(0x%x) !!!!\n",
+ bp->b_bufsize, bp->b_bcount);
+ panic("vm_bounce_alloc");
+ }
+
+/*
+ * This is not really necessary
+ * if( bp->b_bufsize != bp->b_bcount) {
+ * printf("size: %d, count: %d\n", bp->b_bufsize, bp->b_bcount);
+ * }
+ */
+
+
+ vastart = (vm_offset_t) bp->b_un.b_addr;
+ vaend = (vm_offset_t) bp->b_un.b_addr + bp->b_bufsize;
+
+ vapstart = i386_trunc_page(vastart);
+ vapend = i386_round_page(vaend);
+ countvmpg = (vapend - vapstart) / NBPG;
+
+/*
+ * if any page is above 16MB, then go into bounce-buffer mode
+ */
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG)
+ ++dobounceflag;
+ va += NBPG;
+ }
+ if (dobounceflag == 0)
+ return;
+
+ if (bouncepages < dobounceflag)
+ panic("Not enough bounce buffers!!!");
+
+/*
+ * allocate a replacement kva for b_addr
+ */
+ kva = vm_bounce_kva(countvmpg*NBPG, 1);
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG) {
+ /*
+ * allocate a replacement page
+ */
+ vm_offset_t bpa = vm_bounce_page_find(1);
+ pmap_kenter(kva + (NBPG * i), bpa);
+ /*
+ * if we are writing, the copy the data into the page
+ */
+ if ((bp->b_flags & B_READ) == 0) {
+ pmap_update();
+ bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
+ }
+ } else {
+ /*
+ * use original page
+ */
+ pmap_kenter(kva + (NBPG * i), pa);
+ }
+ va += NBPG;
+ }
+ pmap_update();
+
+/*
+ * flag the buffer as being bounced
+ */
+ bp->b_flags |= B_BOUNCE;
+/*
+ * save the original buffer kva
+ */
+ bp->b_savekva = bp->b_un.b_addr;
+/*
+ * put our new kva into the buffer (offset by original offset)
+ */
+ bp->b_un.b_addr = (caddr_t) (((vm_offset_t) kva) |
+ ((vm_offset_t) bp->b_savekva & (NBPG - 1)));
+ return;
+}
+
+/*
+ * hook into biodone to free bounce buffer
+ */
+void
+vm_bounce_free(bp)
+ struct buf *bp;
+{
+ int i;
+ vm_offset_t origkva, bouncekva, bouncekvaend;
+ int countvmpg;
+ int s;
+
+/*
+ * if this isn't a bounced buffer, then just return
+ */
+ if ((bp->b_flags & B_BOUNCE) == 0)
+ return;
+
+/*
+ * This check is not necessary
+ * if (bp->b_bufsize != bp->b_bcount) {
+ * printf("vm_bounce_free: b_bufsize=%d, b_bcount=%d\n",
+ * bp->b_bufsize, bp->b_bcount);
+ * }
+ */
+
+ origkva = (vm_offset_t) bp->b_savekva;
+ bouncekva = (vm_offset_t) bp->b_un.b_addr;
+
+/*
+ * check every page in the kva space for b_addr
+ */
+ for (i = 0; i < bp->b_bufsize; ) {
+ vm_offset_t mybouncepa;
+ vm_offset_t copycount;
+
+ copycount = i386_round_page(bouncekva + 1) - bouncekva;
+ mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
+
+/*
+ * if this is a bounced pa, then process as one
+ */
+ if ( mybouncepa != pmap_kextract( i386_trunc_page( origkva))) {
+ vm_offset_t tocopy = copycount;
+ if (i + tocopy > bp->b_bufsize)
+ tocopy = bp->b_bufsize - i;
+/*
+ * if this is a read, then copy from bounce buffer into original buffer
+ */
+ if (bp->b_flags & B_READ)
+ bcopy((caddr_t) bouncekva, (caddr_t) origkva, tocopy);
+/*
+ * free the bounce allocation
+ */
+ vm_bounce_page_free(mybouncepa, 1);
+ }
+
+ origkva += copycount;
+ bouncekva += copycount;
+ i += copycount;
+ }
+
+/*
+ * add the old kva into the "to free" list
+ */
+
+ bouncekva= i386_trunc_page((vm_offset_t) bp->b_un.b_addr);
+ bouncekvaend= i386_round_page((vm_offset_t)bp->b_un.b_addr + bp->b_bufsize);
+
+ vm_bounce_kva_free( bouncekva, (bouncekvaend - bouncekva), 0);
+ bp->b_un.b_addr = bp->b_savekva;
+ bp->b_savekva = 0;
+ bp->b_flags &= ~B_BOUNCE;
+
+ return;
+}
+
+
+/*
+ * init the bounce buffer system
+ */
+void
+vm_bounce_init()
+{
+ vm_offset_t minaddr, maxaddr;
+ int i;
+
+ io_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, MAXBKVA * NBPG, FALSE);
+ kvasfreecnt = 0;
+
+ if (bouncepages == 0)
+ return;
+
+ bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
+ bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
+
+ if (!bounceallocarray)
+ panic("Cannot allocate bounce resource array\n");
+
+ bzero(bounceallocarray, bounceallocarraysize * sizeof(unsigned));
+ bouncepa = malloc(bouncepages * sizeof(vm_offset_t), M_TEMP, M_NOWAIT);
+ if (!bouncepa)
+ panic("Cannot allocate physical memory array\n");
+
+ for(i=0;i<bouncepages;i++) {
+ vm_offset_t pa;
+ if( (pa = pmap_kextract((vm_offset_t) bouncememory + i * NBPG)) >= SIXTEENMEG)
+ panic("bounce memory out of range");
+ if( pa == 0)
+ panic("bounce memory not resident");
+ bouncepa[i] = pa;
+ }
+ bouncefree = bouncepages;
+
+}
+#endif /* NOBOUNCE */
+
+
+static void
+cldiskvamerge( kvanew, orig1, orig1cnt, orig2, orig2cnt)
+ vm_offset_t kvanew;
+ vm_offset_t orig1, orig1cnt;
+ vm_offset_t orig2, orig2cnt;
+{
+ int i;
+ vm_offset_t pa;
+/*
+ * enter the transfer physical addresses into the new kva
+ */
+ for(i=0;i<orig1cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig1 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + i * PAGE_SIZE, pa);
+ }
+
+ for(i=0;i<orig2cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig2 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + (i + orig1cnt) * PAGE_SIZE, pa);
+ }
+ pmap_update();
+}
+
+void
+cldisksort(struct buf *dp, struct buf *bp, vm_offset_t maxio)
+{
+ register struct buf *ap, *newbp;
+ int i, trycount=0;
+ vm_offset_t orig1pages, orig2pages;
+ vm_offset_t orig1begin, orig2begin;
+ vm_offset_t kvanew, kvaorig;
+
+ if( bp->b_bcount < MAXCLSTATS*PAGE_SIZE)
+ ++rqstats[bp->b_bcount/PAGE_SIZE];
+ /*
+ * If nothing on the activity queue, then
+ * we become the only thing.
+ */
+ ap = dp->b_actf;
+ if(ap == NULL) {
+ dp->b_actf = bp;
+ dp->b_actl = bp;
+ bp->av_forw = NULL;
+ return;
+ }
+
+
+ if (bp->b_flags & B_READ) {
+ while( ap->av_forw && (ap->av_forw->b_flags & B_READ))
+ ap = ap->av_forw;
+ goto insert;
+ }
+
+ /*
+ * If we lie after the first (currently active)
+ * request, then we must locate the second request list
+ * and add ourselves to it.
+ */
+
+ if (bp->b_pblkno < ap->b_pblkno) {
+ while (ap->av_forw) {
+ /*
+ * Check for an ``inversion'' in the
+ * normally ascending block numbers,
+ * indicating the start of the second request list.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno) {
+ /*
+ * Search the second request list
+ * for the first request at a larger
+ * block number. We go before that;
+ * if there is no such request, we go at end.
+ */
+ do {
+ if (bp->b_pblkno < ap->av_forw->b_pblkno)
+ goto insert;
+ ap = ap->av_forw;
+ } while (ap->av_forw);
+ goto insert; /* after last */
+ }
+ ap = ap->av_forw;
+ }
+ /*
+ * No inversions... we will go after the last, and
+ * be the first request in the second request list.
+ */
+ goto insert;
+ }
+ /*
+ * Request is at/after the current request...
+ * sort in the first request list.
+ */
+ while (ap->av_forw) {
+ /*
+ * We want to go after the current request
+ * if there is an inversion after it (i.e. it is
+ * the end of the first request list), or if
+ * the next request is a larger block than our request.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno ||
+ bp->b_pblkno < ap->av_forw->b_pblkno )
+ goto insert;
+ ap = ap->av_forw;
+ }
+
+insert:
+
+#ifndef NOBOUNCE
+ /*
+ * read clustering with new read-ahead disk drives hurts mostly, so
+ * we don't bother...
+ */
+ if( bp->b_flags & (B_READ|B_SYNC))
+ goto nocluster;
+ if( bp->b_bcount != bp->b_bufsize) {
+ goto nocluster;
+ }
+ /*
+ * we currently only cluster I/O transfers that are at page-aligned
+ * kvas and transfers that are multiples of page lengths.
+ */
+ if ((bp->b_flags & B_BAD) == 0 &&
+ ((bp->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) bp->b_un.b_addr & PAGE_MASK) == 0)) {
+ if( maxio > MAXCLSTATS*PAGE_SIZE)
+ maxio = MAXCLSTATS*PAGE_SIZE;
+ /*
+ * merge with previous?
+ * conditions:
+ * 1) We reside physically immediately after the previous block.
+ * 2) The previous block is not first on the device queue because
+ * such a block might be active.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The previous kva is page aligned and the previous transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ if( (ap->b_pblkno + (ap->b_bcount / DEV_BSIZE) == bp->b_pblkno) &&
+ (dp->b_actf != ap) &&
+ ((ap->b_flags & ~(B_CLUSTER|B_BOUNCE)) == (bp->b_flags & ~B_BOUNCE)) &&
+ ((ap->b_flags & B_BAD) == 0) &&
+ ((ap->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->b_bcount + bp->b_bcount < maxio)) {
+
+ /*
+ * something is majorly broken in the upper level
+ * fs code... blocks can overlap!!! this detects
+ * the overlap and does the right thing.
+ */
+ if( ap->av_forw &&
+ bp->b_pblkno + ((bp->b_bcount / DEV_BSIZE) > ap->av_forw->b_pblkno)) {
+ goto nocluster;
+ }
+
+ orig1begin = (vm_offset_t) ap->b_un.b_addr;
+ orig1pages = ap->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) bp->b_un.b_addr;
+ orig2pages = bp->b_bcount / PAGE_SIZE;
+
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+ if( (ap->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+
+ /*
+ * build the new bp to be handed off to the device
+ */
+
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = ap;
+ newbp->b_clusterl = bp;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ /*
+ * enter the new bp onto the device queue
+ */
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ /*
+ * enter the previous bps onto the cluster queue
+ */
+ ap->av_forw = bp;
+ bp->av_back = ap;
+
+ ap->av_back = NULL;
+ bp->av_forw = NULL;
+
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ /*
+ * free the old kva
+ */
+ vm_bounce_kva_free( orig1begin, ap->b_bufsize, 0);
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+
+ ap->b_clusterl->av_forw = bp;
+ bp->av_forw = NULL;
+ bp->av_back = ap->b_clusterl;
+ ap->b_clusterl = bp;
+
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+ }
+ return;
+ /*
+ * merge with next?
+ * conditions:
+ * 1) We reside physically before the next block.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The next kva is page aligned and the next transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ } else if( ap->av_forw &&
+ (bp->b_pblkno + (bp->b_bcount / DEV_BSIZE) == ap->av_forw->b_pblkno) &&
+ ((bp->b_flags & ~B_BOUNCE) == (ap->av_forw->b_flags & ~(B_CLUSTER|B_BOUNCE))) &&
+ ((ap->av_forw->b_flags & B_BAD) == 0) &&
+ ((ap->av_forw->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->av_forw->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->av_forw->b_bcount + bp->b_bcount < maxio)) {
+
+ /*
+ * something is majorly broken in the upper level
+ * fs code... blocks can overlap!!! this detects
+ * the overlap and does the right thing.
+ */
+ if( (ap->b_pblkno + (ap->b_bcount / DEV_BSIZE)) > bp->b_pblkno) {
+ goto nocluster;
+ }
+
+ orig1begin = (vm_offset_t) bp->b_un.b_addr;
+ orig1pages = bp->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) ap->av_forw->b_un.b_addr;
+ orig2pages = ap->av_forw->b_bcount / PAGE_SIZE;
+
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+ /*
+ * if next isn't a cluster we need to create one
+ */
+ if( (ap->av_forw->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_blkno = bp->b_blkno;
+ newbp->b_pblkno = bp->b_pblkno;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = bp;
+ newbp->b_clusterl = ap;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ bp->av_forw = ap;
+ ap->av_back = bp;
+
+ bp->av_back = NULL;
+ ap->av_forw = NULL;
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ vm_bounce_kva_free( orig2begin, ap->b_bufsize, 0);
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+ bp->av_forw = ap->b_clusterf;
+ ap->b_clusterf->av_back = bp;
+ ap->b_clusterf = bp;
+ bp->av_back = NULL;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_blkno = bp->b_blkno;
+ ap->b_pblkno = bp->b_pblkno;
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+
+ }
+ return;
+ }
+ }
+#endif
+ /*
+ * don't merge
+ */
+nocluster:
+ ++clstats[bp->b_bcount/PAGE_SIZE];
+ bp->av_forw = ap->av_forw;
+ if( bp->av_forw)
+ bp->av_forw->av_back = bp;
+ else
+ dp->b_actl = bp;
+
+ ap->av_forw = bp;
+ bp->av_back = ap;
+}
+
+/*
+ * quick version of vm_fault
+ */
+
+void
+vm_fault_quick( v, prot)
+ vm_offset_t v;
+ int prot;
+{
+ if( (cpu_class == CPUCLASS_386) &&
+ (prot & VM_PROT_WRITE))
+ vm_fault(&curproc->p_vmspace->vm_map, v,
+ VM_PROT_READ|VM_PROT_WRITE, FALSE);
+ else if( prot & VM_PROT_WRITE)
+ *(volatile char *)v += 0;
+ else
+ *(volatile char *)v;
+}
+
+
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the kernel stack and pcb, making the child
@@ -213,32 +1045,6 @@ setredzone(pte, vaddr)
}
/*
- * Move pages from one kernel virtual address to another.
- * Both addresses are assumed to reside in the Sysmap,
- * and size must be a multiple of CLSIZE.
- */
-void
-pagemove(from, to, size)
- register caddr_t from, to;
- int size;
-{
- register struct pte *fpte, *tpte;
-
- if (size % CLBYTES)
- panic("pagemove");
- fpte = kvtopte(from);
- tpte = kvtopte(to);
- while (size > 0) {
- *tpte++ = *fpte;
- *(int *)fpte++ = 0;
- from += NBPG;
- to += NBPG;
- size -= NBPG;
- }
- tlbflush();
-}
-
-/*
* Convert kernel VA to physical address
*/
u_long
@@ -246,7 +1052,7 @@ kvtop(void *addr)
{
vm_offset_t va;
- va = pmap_extract(kernel_pmap, (vm_offset_t)addr);
+ va = pmap_kextract((vm_offset_t)addr);
if (va == 0)
panic("kvtop: zero page frame");
return((int)va);
@@ -255,22 +1061,11 @@ kvtop(void *addr)
extern vm_map_t phys_map;
/*
- * Map an IO request into kernel virtual address space. Requests fall into
- * one of five catagories:
- *
- * B_PHYS|B_UAREA: User u-area swap.
- * Address is relative to start of u-area (p_addr).
- * B_PHYS|B_PAGET: User page table swap.
- * Address is a kernel VA in usrpt (Usrptmap).
- * B_PHYS|B_DIRTY: Dirty page push.
- * Address is a VA in proc2's address space.
- * B_PHYS|B_PGIN: Kernel pagein of user pages.
- * Address is VA in user's address space.
- * B_PHYS: User "raw" IO request.
- * Address is VA in user's address space.
+ * Map an IO request into kernel virtual address space.
*
- * All requests are (re)mapped into kernel VA space via the useriomap
- * (a name with only slightly more meaning than "kernelmap")
+ * All requests are (re)mapped into kernel VA space.
+ * Notice that we use b_bufsize for the size of the buffer
+ * to be mapped. b_bcount might be modified by the driver.
*/
void
vmapbuf(bp)
@@ -289,18 +1084,18 @@ vmapbuf(bp)
addr = bp->b_saveaddr = bp->b_un.b_addr;
off = (int)addr & PGOFSET;
p = bp->b_proc;
- npf = btoc(round_page(bp->b_bcount + off));
+ npf = btoc(round_page(bp->b_bufsize + off));
kva = kmem_alloc_wait(phys_map, ctob(npf));
bp->b_un.b_addr = (caddr_t) (kva + off);
while (npf--) {
pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
if (pa == 0)
panic("vmapbuf: null page frame");
- pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
- VM_PROT_READ|VM_PROT_WRITE, TRUE);
+ pmap_kenter(kva, trunc_page(pa));
addr += PAGE_SIZE;
kva += PAGE_SIZE;
}
+ pmap_update();
}
/*
@@ -317,7 +1112,7 @@ vunmapbuf(bp)
if ((bp->b_flags & B_PHYS) == 0)
panic("vunmapbuf");
- npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
+ npf = btoc(round_page(bp->b_bufsize + ((int)addr & PGOFSET)));
kva = (vm_offset_t)((int)addr & ~PGOFSET);
kmem_free_wakeup(phys_map, kva, ctob(npf));
bp->b_un.b_addr = bp->b_saveaddr;
diff --git a/sys/i386/include/ansi.h b/sys/i386/include/ansi.h
index 3a54968b1595..c932ba7a598b 100644
--- a/sys/i386/include/ansi.h
+++ b/sys/i386/include/ansi.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ansi.h 7.1 (Berkeley) 3/9/91
- * $Id: ansi.h,v 1.2 1993/10/16 14:39:05 rgrimes Exp $
+ * $Id: ansi.h,v 1.3 1994/04/04 21:11:11 wollman Exp $
*/
#ifndef _ANSI_H_
@@ -53,6 +53,23 @@
#define _SIZE_T_ unsigned int /* sizeof() */
#define _TIME_T_ long /* time() */
#define _VA_LIST_ char * /* va_list */
-#define _WCHAR_T_ unsigned short /* wchar_t */
+
+/*
+ * Runes (wchar_t) is declared to be an ``int'' instead of the more natural
+ * ``unsigned long'' or ``long''. Two things are happening here. It is not
+ * unsigned so that EOF (-1) can be naturally assigned to it and used. Also,
+ * it looks like 10646 will be a 31 bit standard. This means that if your
+ * ints cannot hold 32 bits, you will be in trouble. The reason an int was
+ * chosen over a long is that the is*() and to*() routines take ints (says
+ * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
+ * lose a bit of ANSI conformance, but your programs will still work.
+ *
+ * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
+ * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
+ * defined for ctype.h.
+ */
+#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_RUNE_T_ int /* rune_t */
+
#endif /* _ANSI_H_ */
diff --git a/sys/i386/include/asmacros.h b/sys/i386/include/asmacros.h
index f0f2c014178c..4af0b97a8abf 100644
--- a/sys/i386/include/asmacros.h
+++ b/sys/i386/include/asmacros.h
@@ -5,6 +5,11 @@
#define GEN_ENTRY(name) ALIGN_TEXT; .globl name; name:
#define NON_GPROF_ENTRY(name) GEN_ENTRY(_/**/name)
+/* These three are place holders for future changes to the profiling code */
+#define MCOUNT_LABEL(name)
+#define MEXITCOUNT
+#define FAKE_MCOUNT(caller)
+
#ifdef GPROF
/*
* ALTENTRY() must be before a corresponding ENTRY() so that it can jump
@@ -30,6 +35,7 @@
*/
#define ALTENTRY(name) GEN_ENTRY(_/**/name)
#define ENTRY(name) GEN_ENTRY(_/**/name)
+#define MCOUNT
#endif
diff --git a/sys/i386/include/console.h b/sys/i386/include/console.h
index 011889032ecc..c52a3943c764 100644
--- a/sys/i386/include/console.h
+++ b/sys/i386/include/console.h
@@ -14,7 +14,7 @@
* DK9210 Aalborg SO Phone: +45 9814 8076
*
* from:@(#)console.h 1.1 940105
- * $Id: console.h,v 1.7 1994/02/04 10:35:29 chmr Exp $
+ * $Id: console.h,v 1.9 1994/05/20 12:21:49 sos Exp $
*/
#ifndef _CONSOLE_H_
@@ -55,7 +55,7 @@
#define GIO_FONT8x14 _IOR('c', 67, fnt14_t)
#define PIO_FONT8x16 _IOW('c', 68, fnt16_t)
#define GIO_FONT8x16 _IOR('c', 69, fnt16_t)
-#define CONS_GETINFO _IOR('c', 73, vid_info_t)
+#define CONS_GETINFO _IOWR('c', 73, vid_info_t)
#define CONS_GETVERS _IOR('c', 74, long)
#define CONS_80x25TEXT _IO('c', 102)
#define CONS_80x50TEXT _IO('c', 103)
@@ -124,16 +124,19 @@ struct vt_mode {
#define NUM_STATES 8 /* states per key */
#define ALTGR_OFFSET 128 /* offset for altlock keys */
+struct key_t {
+ u_char map[NUM_STATES];
+ u_char spcl;
+ u_char flgs;
+};
+
struct keymap {
u_short n_keys;
- struct key_t {
- u_char map[NUM_STATES];
- u_char spcl;
- u_char flgs;
- } key[NUM_KEYS];
+ struct key_t key[NUM_KEYS];
};
#define MAXFK 16
+#define NUM_FKEYS 60
struct fkeytab {
u_char str[MAXFK];
@@ -190,6 +193,7 @@ typedef struct ssaver ssaver_t;
#define NLK 0x05 /* num lock key */
#define SLK 0x06 /* scroll lock key */
#define LALT 0x07 /* left alt key */
+#define BTAB 0x08 /* backwards tab */
#define LCTR 0x09 /* left control key */
#define NEXT 0x0a /* switch to next screen */
#define F_SCR 0x0b /* switch to first screen */
@@ -214,11 +218,14 @@ typedef struct ssaver ssaver_t;
#define KB_STAT 0x64 /* kbd status port */
#define KB_BUF_FULL 0x01 /* kbd has char pending */
#define KB_READY 0x02 /* kbd ready for command */
+#define KB_MODE 0x4D /* kbd mode (trans, ints enable)*/
#define KB_WRITE 0x60 /* kbd write command */
-#define KB_SETLEDS 0xed /* kbd set leds */
-#define KB_SETRAD 0xf3 /* kbd set repeat&delay command */
-#define KB_ACK 0xfa /* kbd acknowledge answer */
-#define KB_RESET_CPU 0xfe /* kbd reset main cpu command */
-#define KB_RESET 0xff /* kbd reset */
+#define KB_RESET_DONE 0xAA /* kbd reset command completed */
+#define KB_SETLEDS 0xED /* kbd set leds */
+#define KB_ECHO 0xEE /* kbd set leds */
+#define KB_SETRAD 0xF3 /* kbd set repeat&delay command */
+#define KB_ACK 0xFA /* kbd acknowledge answer */
+#define KB_RESEND 0xFE /* kbd resend cmd answer */
+#define KB_RESET 0xFF /* kbd reset */
#endif
diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h
index 184f5b86151d..82ab4c3734dc 100644
--- a/sys/i386/include/cpu.h
+++ b/sys/i386/include/cpu.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
- * $Id: cpu.h,v 1.4 1993/11/07 17:42:46 wollman Exp $
+ * $Id: cpu.h,v 1.5 1994/04/02 07:00:35 davidg Exp $
*/
#ifndef _MACHINE_CPU_H_
@@ -58,18 +58,21 @@
* Arguments to hardclock, softclock and gatherstats
* encapsulate the previous machine state in an opaque
* clockframe; for now, use generic intrframe.
+ * XXX softclock() has been fixed. It never needed a
+ * whole frame, only a usermode flag, at least on this
+ * machine. Fix the rest.
*/
typedef struct intrframe clockframe;
#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL)
-#define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0)
+#define CLKF_BASEPRI(framep) (((framep)->if_ppl & ~SWI_AST_MASK) == 0)
#define CLKF_PC(framep) ((framep)->if_eip)
/*
* Preempt the current process if in interrupt from user mode,
* or after the current trap/syscall if in system mode.
*/
-#define need_resched() { want_resched++; aston(); }
+#define need_resched() { want_resched = 1; aston(); }
/*
* Give a profiling tick to the current process from the softclock
@@ -84,7 +87,8 @@ typedef struct intrframe clockframe;
*/
#define signotify(p) aston()
-#define aston() (astpending++)
+#define aston() setsoftast()
+#define astoff()
/*
* pull in #defines for kinds of processors
@@ -97,7 +101,6 @@ struct cpu_nameclass {
};
#ifdef KERNEL
-extern int astpending; /* want a trap before returning to user mode */
extern int want_resched; /* resched was called */
extern int cpu;
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
index 65cc855793f0..16bb63b86a17 100644
--- a/sys/i386/include/cpufunc.h
+++ b/sys/i386/include/cpufunc.h
@@ -2,7 +2,7 @@
* Functions to provide access to special i386 instructions.
* XXX - bezillions more are defined in locore.s but are not declared anywhere.
*
- * $Id: cpufunc.h,v 1.9 1994/01/31 23:48:23 davidg Exp $
+ * $Id: cpufunc.h,v 1.11 1994/06/01 03:09:51 davidg Exp $
*/
#ifndef _MACHINE_CPUFUNC_H_
@@ -11,6 +11,8 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include "machine/spl.h"
+
#ifdef __GNUC__
static inline int bdb(void)
@@ -69,6 +71,14 @@ tlbflush()
__asm __volatile("movl %%cr3, %%eax; movl %%eax, %%cr3" : : : "ax");
}
+static inline u_long
+rcr2()
+{
+ u_long data;
+ __asm __volatile("movl %%cr2,%%eax" : "=a" (data));
+ return data;
+}
+
static inline
int
imin(a, b)
@@ -224,7 +234,6 @@ void load_cr0 __P((u_int cr0));
u_int rcr0 __P((void));
void load_cr3(u_long);
u_long rcr3(void);
-u_long rcr2(void);
void setidt __P((int, void (*)(), int, int));
extern u_long kvtop(void *);
diff --git a/sys/i386/include/ioctl_fd.h b/sys/i386/include/ioctl_fd.h
index 2e3ac3104726..a8c17f69ac4a 100644
--- a/sys/i386/include/ioctl_fd.h
+++ b/sys/i386/include/ioctl_fd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden
+ * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,17 +11,18 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
*/
#ifndef _IOCTL_FD_H
@@ -94,5 +95,11 @@ struct fd_type {
#define FD_FORM _IOW('F', 61, struct fd_formb) /* format a track */
#define FD_GTYPE _IOR('F', 62, struct fd_type) /* get drive type */
+#define FD_STYPE _IOW('F', 63, struct fd_type) /* set drive type */
+
+#define FD_GOPTS _IOR('F', 64, int) /* drive options, see below */
+#define FD_SOPTS _IOW('F', 65, int)
+
+#define FDOPT_NORETRY 0x0001 /* no retries on failure (cleared on close) */
#endif /* !def _IOCTL_FD_H */
diff --git a/sys/i386/include/limits.h b/sys/i386/include/limits.h
index 568ad40848a3..586d6e2f5a69 100644
--- a/sys/i386/include/limits.h
+++ b/sys/i386/include/limits.h
@@ -31,15 +31,14 @@
* SUCH DAMAGE.
*
* from: @(#)limits.h 7.2 (Berkeley) 6/28/90
- * $Id: limits.h,v 1.4 1993/12/19 05:14:46 alm Exp $
+ * $Id: limits.h,v 1.6 1994/04/04 21:11:12 wollman Exp $
*/
#ifndef _MACHINE_LIMITS_H_
#define _MACHINE_LIMITS_H_ 1
#define CHAR_BIT 8 /* number of bits in a char */
-#define CLK_TCK 60 /* ticks per second */
-#define MB_LEN_MAX 1 /* no multibyte characters */
+#define MB_LEN_MAX 6 /* allow 21-bit UTF2 */
#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
#define SCHAR_MAX 0x7f /* min value for a signed char */
@@ -61,6 +60,7 @@
#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define CLK_TCK 128 /* ticks per second */
#define UQUAD_MAX 0xffffffffffffffffLL /* max unsigned quad */
#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
diff --git a/sys/i386/include/lpt.h b/sys/i386/include/lpt.h
new file mode 100644
index 000000000000..87af5bcc5875
--- /dev/null
+++ b/sys/i386/include/lpt.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 1994 Geoffrey M. Rehmet
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Geoff Rehmet, Rhodes University, South Africa <csgr@cs.ru.ac.za>
+ *
+ */
+
+#ifndef _LPT_PRINTER_H_
+#define _LPT_PRINTER_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define LPT_IRQ _IOW('p', 1, long) /* set interrupt status */
+
+#endif
diff --git a/sys/i386/include/mouse.h b/sys/i386/include/mouse.h
new file mode 100644
index 000000000000..95a66e474c6d
--- /dev/null
+++ b/sys/i386/include/mouse.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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.
+ *
+ * $Id: mouse.h,v 1.1 1994/05/17 14:05:31 jkh Exp $
+ */
+
+struct mouseinfo {
+ unsigned char status;
+ char xmotion, ymotion;
+};
+
+#define BUTSTATMASK 0x07 /* Any mouse button down if any bit set */
+#define BUTCHNGMASK 0x38 /* Any mouse button changed if any bit set */
+
+#define BUT3STAT 0x01 /* Button 3 down if set */
+#define BUT2STAT 0x02 /* Button 2 down if set */
+#define BUT1STAT 0x04 /* Button 1 down if set */
+#define BUT3CHNG 0x08 /* Button 3 changed if set */
+#define BUT2CHNG 0x10 /* Button 2 changed if set */
+#define BUT1CHNG 0x20 /* Button 1 changed if set */
+#define MOVEMENT 0x40 /* Mouse movement detected */
+
+/* Ioctl definitions */
+
+#define MOUSEIOC ('M'<<8)
+#define MOUSEIOCREAD (MOUSEIOC|60)
diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h
index ec29bf4fa024..168ef19fadd2 100644
--- a/sys/i386/include/npx.h
+++ b/sys/i386/include/npx.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.h 5.3 (Berkeley) 1/18/91
- * $Id: npx.h,v 1.2 1993/10/16 14:39:22 rgrimes Exp $
+ * $Id: npx.h,v 1.3 1994/04/29 21:44:23 gclarkii Exp $
*/
/*
@@ -73,11 +73,13 @@ struct fpacc87 {
struct save87 {
struct env87 sv_env; /* floating point control/status */
struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
-#ifndef dontdef
u_long sv_ex_sw; /* status word for last exception (was pad) */
u_long sv_ex_tw; /* tag word for last exception (was pad) */
- u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
-#endif
+#ifdef GPL_MATH_EMULATE
+ u_char sv_pad[60];
+#else
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif /* GPL_MATH_EMULATE */
};
/* Cyrix EMC memory - mapped coprocessor context switch information */
diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h
index fe97ad809b25..953ebb9d36c4 100644
--- a/sys/i386/include/param.h
+++ b/sys/i386/include/param.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)param.h 5.8 (Berkeley) 6/28/91
- * $Id: param.h,v 1.13 1994/01/31 04:18:54 davidg Exp $
+ * $Id: param.h,v 1.14 1994/03/07 11:38:47 davidg Exp $
*/
#ifndef _MACHINE_PARAM_H_
@@ -62,7 +62,7 @@
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE-1)
#define PGOFSET (NBPG-1) /* byte offset into page */
-#define NPTEPG (NBPG/(sizeof (struct pte)))
+#define NPTEPG (NBPG/(sizeof (pt_entry_t)))
/* XXX PDRSHIFT and PD_SHIFT are two names for the same thing */
#define PDRSHIFT 22 /* LOG2(NBPDR) */
@@ -103,7 +103,7 @@
#endif /* MSIZE */
#ifndef MCLSHIFT
-#define MCLSHIFT 11 /* convert bytes to m_buf clusters */
+#define MCLSHIFT 12 /* convert bytes to m_buf clusters */
#endif /* MCLSHIFT */
#define MCLBYTES (1 << MCLSHIFT) /* size of an m_buf cluster */
#define MCLOFSET (MCLBYTES - 1) /* offset within an m_buf cluster */
diff --git a/sys/i386/include/pcaudioio.h b/sys/i386/include/pcaudioio.h
new file mode 100644
index 000000000000..71c7ebb4c226
--- /dev/null
+++ b/sys/i386/include/pcaudioio.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: pcaudioio.h,v 1.2 1994/05/20 12:22:40 sos Exp $
+ */
+
+#ifndef _PCAUDIOIO_H_
+#define _PCAUDIOIO_H_
+
+typedef struct audio_prinfo {
+ unsigned sample_rate; /* samples per second */
+ unsigned channels; /* # of channels (interleaved) */
+ unsigned precision; /* sample size in bits */
+ unsigned encoding; /* encoding method used */
+
+ unsigned gain; /* volume level: 0 - 255 */
+ unsigned port; /* input/output device */
+ unsigned _fill1[4];
+
+ unsigned samples; /* samples played */
+ unsigned eof; /* ?!? */
+ unsigned char pause; /* !=0 pause, ==0 continue */
+ unsigned char error; /* !=0 if overflow/underflow */
+ unsigned char waiting; /* !=0 if others wants access */
+ unsigned char _fill2[3];
+
+ unsigned char open; /* is device open */
+ unsigned char active; /* !=0 if sound hardware is active */
+} audio_prinfo_t;
+
+typedef struct audio_info {
+ audio_prinfo_t play;
+ audio_prinfo_t record;
+ unsigned monitor_gain;
+ unsigned _fill[4];
+} audio_info_t;
+
+#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */
+#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */
+#define AUDIO_ENCODING_RAW (3) /* linear encoding */
+
+#define AUDIO_MIN_GAIN (0) /* minimum volume value */
+#define AUDIO_MAX_GAIN (255) /* maximum volume value */
+
+#define AUDIO_INITINFO(i) memset((void*)i, 0xff, sizeof(audio_info_t))
+
+#define AUDIO_GETINFO _IOR('A', 1, audio_info_t)
+#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t)
+#define AUDIO_DRAIN _IO('A', 3)
+#define AUDIO_FLUSH _IO('A', 4)
+
+#endif /*!_PCAUDIOIO_H*/
diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h
index ba27f793735d..507baf94b356 100644
--- a/sys/i386/include/pmap.h
+++ b/sys/i386/include/pmap.h
@@ -42,7 +42,7 @@
*
* from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90
* from: @(#)pmap.h 7.4 (Berkeley) 5/12/91
- * $Id: pmap.h,v 1.10 1994/01/31 04:19:00 davidg Exp $
+ * $Id: pmap.h,v 1.16 1994/06/07 17:48:46 davidg Exp $
*/
#ifndef _PMAP_MACHINE_
@@ -58,7 +58,8 @@ struct pde
unsigned int
pd_v:1, /* valid bit */
pd_prot:2, /* access control */
- pd_mbz1:2, /* reserved, must be zero */
+ pd_ncpwt:1, /* page cache write through */
+ pd_ncpcd:1, /* page cache disable */
pd_u:1, /* hardware maintained 'used' bit */
:1, /* not used */
pd_mbz2:2, /* reserved, must be zero */
@@ -76,7 +77,8 @@ struct pte
unsigned int
pg_v:1, /* valid bit */
pg_prot:2, /* access control */
- pg_mbz1:2, /* reserved, must be zero */
+ pg_ncpwt:1, /* page cache write through */
+ pg_ncpcd:1, /* page cache disable */
pg_u:1, /* hardware maintained 'used' bit */
pg_m:1, /* hardware maintained modified bit */
pg_mbz2:2, /* reserved, must be zero */
@@ -91,10 +93,12 @@ unsigned int
#define PG_RW 0x00000002
#define PG_u 0x00000004
#define PG_PROT 0x00000006 /* all protection bits . */
-#define PG_W 0x00000200
-#define PG_N 0x00000800 /* Non-cacheable */
-#define PG_M 0x00000040
+#define PG_NC_PWT 0x00000008 /* page cache write through */
+#define PG_NC_PCD 0x00000010 /* page cache disable */
+#define PG_N 0x00000018 /* Non-cacheable */
#define PG_U 0x00000020
+#define PG_M 0x00000040
+#define PG_W 0x00000200
#define PG_FRAME 0xfffff000UL
#define PG_NOACC 0
@@ -115,8 +119,10 @@ unsigned int
#define PGEX_W 0x02 /* during a Write cycle */
#define PGEX_U 0x04 /* access from User mode (UPL) */
-typedef struct pde pd_entry_t; /* page directory entry */
-typedef struct pte pt_entry_t; /* Mach page table entry */
+/* typedef struct pde pd_entry_t; */ /* page directory entry */
+/* typedef struct pte pt_entry_t; */ /* Mach page table entry */
+typedef unsigned int *pd_entry_t;
+typedef unsigned int *pt_entry_t;
/*
* NKPDE controls the virtual space of the kernel, what ever is left, minus
@@ -145,18 +151,18 @@ typedef struct pte pt_entry_t; /* Mach page table entry */
#define KPTDI (APTDPTDI-NKPDE)/* start of kernel virtual pde's */
#define PTDPTDI (KPTDI-1) /* ptd entry that points to ptd! */
#define KSTKPTDI (PTDPTDI-1) /* ptd entry for u./kernel&user stack */
-#define KSTKPTEOFF (NBPG/sizeof(struct pde)-UPAGES) /* pte entry for kernel stack */
+#define KSTKPTEOFF (NBPG/sizeof(pd_entry_t)-UPAGES) /* pte entry for kernel stack */
-#define PDESIZE sizeof(struct pde) /* for assembly files */
-#define PTESIZE sizeof(struct pte) /* for assembly files */
+#define PDESIZE sizeof(pd_entry_t) /* for assembly files */
+#define PTESIZE sizeof(pt_entry_t) /* for assembly files */
/*
* Address of current and alternate address space page table maps
* and directories.
*/
#ifdef KERNEL
-extern struct pte PTmap[], APTmap[], Upte;
-extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde;
+extern pt_entry_t PTmap[], APTmap[], Upte;
+extern pd_entry_t PTD[], APTD[], PTDpde, APTDpde, Upde;
extern pt_entry_t *Sysmap;
extern int IdlePTD; /* physical address of "Idle" state directory */
@@ -171,12 +177,29 @@ extern int IdlePTD; /* physical address of "Idle" state directory */
#define vtopte(va) (PTmap + i386_btop(va))
#define kvtopte(va) vtopte(va)
#define ptetov(pt) (i386_ptob(pt - PTmap))
-#define vtophys(va) (i386_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+#define vtophys(va) (((int) (*vtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS)
#define avtopte(va) (APTmap + i386_btop(va))
#define ptetoav(pt) (i386_ptob(pt - APTmap))
-#define avtophys(va) (i386_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+#define avtophys(va) (((int) (*avtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
+
+#ifdef KERNEL
+/*
+ * Routine: pmap_kextract
+ * Function:
+ * Extract the physical page address associated
+ * kernel virtual address.
+ */
+static inline vm_offset_t
+pmap_kextract(va)
+ vm_offset_t va;
+{
+ vm_offset_t pa = *(int *)vtopte(va);
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+ return pa;
+}
+#endif
/*
* macros to generate page directory/table indicies
@@ -252,7 +275,7 @@ extern void pmap_remove(struct pmap *, vm_offset_t, vm_offset_t);
extern void pmap_protect(struct pmap *, vm_offset_t, vm_offset_t, vm_prot_t);
extern void pmap_enter(pmap_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t);
extern void pmap_change_wiring(pmap_t, vm_offset_t, boolean_t);
-extern inline struct pte *pmap_pte(pmap_t, vm_offset_t);
+extern inline pt_entry_t * const pmap_pte(pmap_t, vm_offset_t);
extern vm_offset_t pmap_extract(pmap_t, vm_offset_t);
extern void pmap_copy(pmap_t, pmap_t, vm_offset_t, vm_size_t, vm_offset_t);
extern void pmap_collect(pmap_t);
diff --git a/sys/i386/include/psl.h b/sys/i386/include/psl.h
index eb15d181b464..c877648ee796 100644
--- a/sys/i386/include/psl.h
+++ b/sys/i386/include/psl.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)psl.h 5.2 (Berkeley) 1/18/91
- * $Id: psl.h,v 1.3.2.1 1994/03/07 01:23:56 rgrimes Exp $
+ * $Id: psl.h,v 1.5 1994/06/07 23:53:52 phk Exp $
*/
#ifndef _MACHINE_PSL_H_
@@ -56,6 +56,10 @@
#define PSL_NT 0x00004000 /* nested task bit */
#define PSL_RF 0x00010000 /* restart flag bit */
#define PSL_VM 0x00020000 /* virtual 8086 mode bit */
+#define PSL_AC 0x00040000 /* alignment checking */
+#define PSL_VIF 0x00080000 /* virtual interrupt enable */
+#define PSL_VIP 0x00100000 /* virtual interrupt pending */
+#define PSL_ID 0x00200000 /* identification bit */
#define PSL_MBZ 0xffc08028 /* must be zero bits */
#define PSL_MBO 0x00000002 /* must be one bits */
diff --git a/sys/i386/include/pte.h b/sys/i386/include/pte.h
index ac0cb541de95..4b1f71091e2b 100644
--- a/sys/i386/include/pte.h
+++ b/sys/i386/include/pte.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)pte.h 5.5 (Berkeley) 5/9/91
- * $Id: pte.h,v 1.4 1994/01/31 06:52:41 davidg Exp $
+ * $Id: pte.h,v 1.5 1994/03/07 11:38:49 davidg Exp $
*/
#ifndef _MACHINE_PTE_H_
@@ -114,7 +114,7 @@ unsigned int
/*
* Pte related macros
*/
-#define dirty(pte) ((pte)->pg_m)
+#define dirty(pte) ((pte) & PG_M)
#ifndef LOCORE
#ifdef KERNEL
diff --git a/sys/i386/include/soundcard.h b/sys/i386/include/soundcard.h
index 23f20313d98a..ce28a144242d 100644
--- a/sys/i386/include/soundcard.h
+++ b/sys/i386/include/soundcard.h
@@ -1,5 +1,5 @@
#ifndef _SOUNDCARD_H_
-#define _SOUNDCARD_H_ 1
+#define _SOUNDCARD_H_
/*
* Copyright by Hannu Savolainen 1993
*
@@ -30,14 +30,15 @@
/*
* If you make modifications to this file, please contact me before
* distributing the modified version. There is already enough
- * diversity in the world.
+ * divercity in the world.
*
* Regards,
* Hannu Savolainen
- * hsavolai@cs.helsinki.fi
+ * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
*/
-#define SOUND_VERSION 200
+#define SOUND_VERSION 205
+#define VOXWARE
#include <sys/ioctl.h>
@@ -50,6 +51,8 @@
#define SNDCARD_PAS 3
#define SNDCARD_GUS 4
#define SNDCARD_MPU401 5
+#define SNDCARD_SB16 6
+#define SNDCARD_SB16MIDI 7
/***********************************
* IOCTL Commands for /dev/sequencer
@@ -66,9 +69,9 @@
*/
/* #define IOCTYPE (0xff<<8) */
#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
-#define IOC_VOID 0x20000000 /* no parameters */
-#define IOC_OUT 0x40000000 /* copy out parameters */
-#define IOC_IN 0x80000000 /* copy in parameters */
+#define IOC_VOID 0x00000000 /* no parameters */
+#define IOC_OUT 0x20000000 /* copy out parameters */
+#define IOC_IN 0x40000000 /* copy in parameters */
#define IOC_INOUT (IOC_IN|IOC_OUT)
/* the 0x20000000 is so we can distinguish new ioctl's from old */
#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
@@ -180,7 +183,7 @@ struct patch_info {
int volume;
int spare[4];
- char data[0]; /* The waveform data starts here */
+ char data[1]; /* The waveform data starts here */
};
@@ -307,6 +310,14 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
#define CTRL_EXPRESSION 253
#define CTRL_MAIN_VOLUME 252
#define SEQ_BALANCE 11
+#define SEQ_VOLMODE 12
+
+/*
+ * Volume mode decides how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO 1
+#define VOL_METHOD_LINEAR 2
/*
* Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
@@ -402,7 +413,8 @@ struct midi_info {
char name[30];
int device; /* 0-N. INITIALIZE BEFORE CALLING */
unsigned long capabilities; /* To be defined later */
- int dummies[19]; /* Reserve space */
+ int dev_type;
+ int dummies[18]; /* Reserve space */
};
/********************************************
@@ -418,6 +430,7 @@ struct midi_info {
#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
#define SNDCTL_DSP_POST _IO ('P', 8)
+#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
@@ -430,6 +443,7 @@ struct midi_info {
#define SOUND_PCM_POST SNDCTL_DSP_POST
#define SOUND_PCM_RESET SNDCTL_DSP_RESET
#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
+#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE
/*********************************************
* IOCTL commands for /dev/mixer
@@ -624,7 +638,8 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* }
*/
-#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len, _seqbufptr = 0
+#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0
+#define SEQ_DECLAREBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
#define SEQ_PM_DEFINES struct patmgr_info _pm_info
#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
#define _SEQ_ADVBUF(len) _seqbufptr += len
@@ -638,6 +653,17 @@ void seqbuf_dump(void); /* This function must be provided by programs */
_pm_info.parm1 = bank, _pm_info.parm2 = 128, \
ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (mode);\
+ _seqbuf[_seqbufptr+4] = 0;\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
@@ -728,8 +754,8 @@ void seqbuf_dump(void); /* This function must be provided by programs */
_seqbuf[_seqbufptr+2] = (device);\
_seqbuf[_seqbufptr+3] = 0;\
_SEQ_ADVBUF(4);}
-#define SEQ_WRPATCH(patch, len) {if (_seqbufptr) seqbuf_dump();\
- if (write(seqfd, (char*)(patch), len)==-1) \
+#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\
+ if (write(seqfd, (char*)(patchx), len)==-1) \
perror("Write patch: /dev/sequencer");}
#endif
diff --git a/sys/i386/include/spl.h b/sys/i386/include/spl.h
new file mode 100644
index 000000000000..0be93644a463
--- /dev/null
+++ b/sys/i386/include/spl.h
@@ -0,0 +1,104 @@
+#ifndef _MACHINE_IPL_H_
+#define _MACHINE_IPL_H_
+
+#include "machine/../isa/ipl.h" /* XXX "machine" means cpu for i386 */
+
+/*
+ * Software interrupt bit numbers in priority order. The priority only
+ * determines which swi will be dispatched next; a higher priority swi
+ * may be dispatched when a nested h/w interrupt handler returns.
+ */
+#define SWI_TTY (NHWI + 0)
+#define SWI_NET (NHWI + 1)
+#define SWI_CLOCK 30
+#define SWI_AST 31
+
+/*
+ * Corresponding interrupt-pending bits for ipending.
+ */
+#define SWI_TTY_PENDING (1 << SWI_TTY)
+#define SWI_NET_PENDING (1 << SWI_NET)
+#define SWI_CLOCK_PENDING (1 << SWI_CLOCK)
+#define SWI_AST_PENDING (1 << SWI_AST)
+
+/*
+ * Corresponding interrupt-disable masks for cpl. The ordering is now by
+ * inclusion (where each mask is considered as a set of bits). Everything
+ * except SWI_AST_MASK includes SWI_CLOCK_MASK so that softclock() doesn't
+ * run while other swi handlers are running and timeout routines can call
+ * swi handlers. Everything includes SWI_AST_MASK so that AST's are masked
+ * until just before return to user mode.
+ */
+#define SWI_TTY_MASK (SWI_TTY_PENDING | SWI_CLOCK_MASK)
+#define SWI_NET_MASK (SWI_NET_PENDING | SWI_CLOCK_MASK)
+#define SWI_CLOCK_MASK (SWI_CLOCK_PENDING | SWI_AST_MASK)
+#define SWI_AST_MASK SWI_AST_PENDING
+#define SWI_MASK (~HWI_MASK)
+
+#ifndef LOCORE
+
+extern unsigned bio_imask; /* group of interrupts masked with splbio() */
+extern unsigned cpl; /* current priority level mask */
+extern unsigned high_imask; /* group of interrupts masked with splhigh() */
+extern unsigned net_imask; /* group of interrupts masked with splimp() */
+extern volatile unsigned ipending; /* active interrupts masked by cpl */
+extern volatile unsigned netisr;
+extern unsigned tty_imask; /* group of interrupts masked with spltty() */
+
+/*
+ * ipending has to be volatile so that it is read every time it is accessed
+ * in splx() and spl0(), but we don't want it to be read nonatomically when
+ * it is changed. Pretending that ipending is a plain int happens to give
+ * suitable atomic code for "ipending |= constant;".
+ */
+#define setsoftast() (*(unsigned *)&ipending |= SWI_AST_PENDING)
+#define setsoftclock() (*(unsigned *)&ipending |= SWI_CLOCK_PENDING)
+#define setsoftnet() (*(unsigned *)&ipending |= SWI_NET_PENDING)
+#define setsofttty() (*(unsigned *)&ipending |= SWI_TTY_PENDING)
+
+void unpend_V __P((void));
+
+#ifdef __GNUC__
+
+void splz __P((void));
+
+#define GENSPL(name, set_cpl) \
+static __inline int name(void) \
+{ \
+ unsigned x; \
+ \
+ x = cpl; \
+ set_cpl; \
+ return (x); \
+}
+
+GENSPL(splbio, cpl |= bio_imask)
+GENSPL(splclock, cpl = HWI_MASK | SWI_MASK)
+GENSPL(splhigh, cpl = HWI_MASK | SWI_MASK)
+GENSPL(splimp, cpl |= net_imask)
+GENSPL(splnet, cpl |= SWI_NET_MASK)
+GENSPL(splsoftclock, cpl = SWI_CLOCK_MASK)
+GENSPL(splsofttty, cpl |= SWI_TTY_MASK)
+GENSPL(spltty, cpl |= tty_imask)
+
+static __inline void
+spl0(void)
+{
+ cpl = SWI_AST_MASK;
+ if (ipending & ~SWI_AST_MASK)
+ splz();
+}
+
+static __inline void
+splx(int ipl)
+{
+ cpl = ipl;
+ if (ipending & ~ipl)
+ splz();
+}
+
+#endif /* __GNUC__ */
+
+#endif /* LOCORE */
+
+#endif /* _MACHINE_IPL_H_ */
diff --git a/sys/i386/include/ultrasound.h b/sys/i386/include/ultrasound.h
index 9b6e78fbadce..40e2443e6f65 100644
--- a/sys/i386/include/ultrasound.h
+++ b/sys/i386/include/ultrasound.h
@@ -32,12 +32,6 @@
* and not portable.
*/
-#ifdef linux
-#include <linux/soundcard.h>
-#else
-#include <machine/soundcard.h>
-#endif
-
/*
* Private events for Gravis Ultrasound (GUS)
*
@@ -90,6 +84,7 @@
#define _GUS_VOICEFADE 0x0d
#define _GUS_VOLUME_SCALE 0x0e
#define _GUS_VOICEVOL2 0x0f
+#define _GUS_VOICE_POS 0x10
/*
* GUS API macros
@@ -120,5 +115,7 @@
#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0)
#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0)
#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2))
+#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \
+ (p) & 0xffff, ((p) >> 16) & 0xffff)
#endif
diff --git a/sys/i386/include/vmparam.h b/sys/i386/include/vmparam.h
index a5b657cd82c2..c5ed04dde346 100644
--- a/sys/i386/include/vmparam.h
+++ b/sys/i386/include/vmparam.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* from: @(#)vmparam.h 5.9 (Berkeley) 5/12/91
- * $Id: vmparam.h,v 1.11.2.1 1994/03/24 08:57:03 rgrimes Exp $
+ * $Id: vmparam.h,v 1.12 1994/03/21 09:35:24 davidg Exp $
*/
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c
index efeee385ba51..df1e3cada643 100644
--- a/sys/i386/isa/aha1542.c
+++ b/sys/i386/isa/aha1542.c
@@ -12,7 +12,7 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
- * $Id: aha1542.c,v 1.20.2.2 1994/05/03 05:16:50 rgrimes Exp $
+ * $Id: aha1542.c,v 1.27 1994/06/05 19:18:10 ats Exp $
*/
/*
@@ -299,8 +299,8 @@ struct aha_data {
struct aha_ccb *aha_ccb_free; /* the next free ccb */
struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */
int aha_int; /* our irq level */
- int aha_dma; /* out DMA req channel */
- int aha_scsi_dev; /* ourscsi bus address */
+ int aha_dma; /* our DMA req channel */
+ int aha_scsi_dev; /* our scsi bus address */
struct scsi_link sc_link; /* prototype for subdevs */
} *ahadata[NAHA];
@@ -589,6 +589,7 @@ ahaattach(dev)
aha->sc_link.adapter_targ = aha->aha_scsi_dev;
aha->sc_link.adapter = &aha_switch;
aha->sc_link.device = &aha_dev;
+ aha->sc_link.flags = SDEV_BOUNCE;
/*
* ask the adapter what subunits are present
@@ -741,7 +742,7 @@ aha_get_ccb(unit, flags)
* to come free
*/
while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) {
- sleep(&aha->aha_ccb_free, PRIBIO);
+ tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0);
}
if (rc) {
aha->aha_ccb_free = aha->aha_ccb_free->next;
@@ -916,7 +917,7 @@ aha_init(unit)
#ifdef AHADEBUG
printf("aha%d: extended bios flags %x\n", unit, extbios.flags);
#endif /* AHADEBUG */
- printf("aha%d: 1542C/CF detected, unlocking mailbox\n");
+ printf("aha%d: 1542C/CF detected, unlocking mailbox\n", unit);
aha_cmd(unit, 2, 0, 0, 0, AHA_MBX_ENABLE,
0, extbios.mailboxlock);
}
@@ -1006,7 +1007,7 @@ aha_init(unit)
return (EIO);
}
#else
- printf ("\n");
+ printf (" (bus speed defaulted)\n");
#endif /*TUNE_1542*/
/*
* Initialize mail box
diff --git a/sys/i386/isa/bt742a.c b/sys/i386/isa/bt742a.c
index e160e9167cb1..990344f28ea6 100644
--- a/sys/i386/isa/bt742a.c
+++ b/sys/i386/isa/bt742a.c
@@ -12,7 +12,7 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
- * $Id: bt742a.c,v 1.12 1993/12/19 00:50:29 wollman Exp $
+ * $Id: bt742a.c,v 1.22 1994/06/15 04:19:23 jkh Exp $
*/
/*
@@ -126,7 +126,7 @@ struct bt_cmd_buf {
* these could be bigger but we need the bt_data to fit on a single page..
*/
-#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */
+#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
/* don't need that many really */
#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
/* in bt742a H/W ( Not MAX ? ) */
@@ -299,6 +299,21 @@ struct bt_config {
u_char :5;
};
+/*
+ * Determin 32bit address/Data firmware functionality from Bus type
+ * Note: bt742a/747[s|d]/757/946/445s will return 'E'
+ * bt542b/545s/545d will be return 'A'
+ * 94/05/18 amurai@spec.co.jp
+ */
+#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */
+#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address bus type */
+#define BT_BUS_TYPE_MCA 'M' /* Micro chanel is ? forget it right now */
+struct bt_ext_info {
+ u_char bus_type; /* Host adapter bus type */
+ u_char bios_addr; /* Bios Address-Not use*/
+ u_short max_seg; /* Max segment List */
+};
+
#define INT9 0x01
#define INT10 0x02
#define INT11 0x04
@@ -568,7 +583,8 @@ btprobe(dev)
}
/*
* If it's there, put in it's interrupt vectors
- */ dev->id_unit = unit;
+ */
+ dev->id_unit = unit;
dev->id_irq = (1 << bt->bt_int);
dev->id_drq = bt->bt_dma;
@@ -593,6 +609,7 @@ btattach(dev)
bt->sc_link.adapter_targ = bt->bt_scsi_dev;
bt->sc_link.adapter = &bt_switch;
bt->sc_link.device = &bt_dev;
+ bt->sc_link.flags = SDEV_BOUNCE;
/*
* ask the adapter what subunits are present
@@ -818,7 +835,8 @@ bt_get_ccb(unit, flags)
goto gottit;
} else {
if (!(flags & SCSI_NOSLEEP)) {
- sleep(&bt->bt_ccb_free, PRIBIO);
+ tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO,
+ "btccb", 0);
}
}
}
@@ -987,6 +1005,7 @@ bt_init(unit)
unsigned char ad[4];
volatile int i, sts;
struct bt_config conf;
+ struct bt_ext_info info;
/*
* reset board, If it doesn't respond, assume
@@ -1008,6 +1027,32 @@ bt_init(unit)
return (ENXIO);
}
/*
+ * Make sure board has a capability of 32bit addressing.
+ * and Firmware also need a capability of 32bit addressing pointer
+ * in Extended mailbox and ccb structure.
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(info),0,&info, BT_INQUIRE_EXTENDED,sizeof(info));
+ switch (info.bus_type) {
+ case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */
+ printf("bt%d: bt54x-ISA(24bit) bus detected\n", unit);
+ break;
+ case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */
+ printf("bt%d: PCI/EISA/VLB(32bit) bus detected\n",unit);
+ break;
+ case BT_BUS_TYPE_MCA: /* forget it right now */
+ printf("bt%d: MCA bus architecture detected..", unit);
+ printf("[giving up]\n");
+ return (ENXIO);
+ break;
+ default:
+ printf("bt%d: Unknown state detected...", unit);
+ printf("[giving up]\n");
+ return (ENXIO);
+ break;
+ }
+
+ /*
* Assume we have a board at this stage
* setup dma channel from jumpers and save int
* level
@@ -1107,8 +1152,6 @@ bt_init(unit)
bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0];
bt_inquire_setup_information(unit);
- /* Enable round-robin scheme - appeared at firmware rev. 3.31 */
- bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
/*
* Note that we are going and return (to probe)
@@ -1122,9 +1165,14 @@ bt_inquire_setup_information(unit)
{
struct bt_data *bt = btdata[unit];
struct bt_setup setup;
+ char dummy[8];
struct bt_boardID bID;
int i;
+ /* Inquire Installed Devices */
+ bzero( &dummy[0], sizeof(dummy) );
+ bt_cmd(unit, 0, sizeof(dummy), 10, &dummy[0], BT_DEV_GET);
+
/* Inquire Board ID to Bt742 for firmware version */
bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE);
printf("bt%d: version %c.%c, ",
@@ -1143,19 +1191,37 @@ bt_inquire_setup_information(unit)
} else {
printf("no parity, ");
}
- printf("%d mbxs, %d ccbs\n", setup.num_mbx, bt->numccbs);
+ printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX);
+
+ /*
+ * Displaying SCSI negotiation value by each target.
+ * How can I determin FAST scsi value? XXX amurai@spec.co.jp
+ */
for (i = 0; i < 8; i++) {
- if (!setup.sync[i].offset &&
- !setup.sync[i].period &&
- !setup.sync[i].valid)
+ if (!setup.sync[i].valid)
continue;
+ if (!setup.sync[i].offset && !setup.sync[i].period )
+ printf("bt%d: targ %d async\n", unit, i);
+ else
+ printf("bt%d: targ %d offset=%02d, period=%dnsec\n",
+ unit, i,
+ setup.sync[i].offset,
+ 200 + setup.sync[i].period * 50 );
+ }
- printf("bt%d: dev%02d Offset=%d,Transfer period=%d, Synchronous? %s",
- unit, i,
- setup.sync[i].offset, setup.sync[i].period,
- setup.sync[i].valid ? "Yes" : "No");
+ /*
+ * Enable round-robin scheme - appeared at firmware rev. 3.31
+ * Below rev 2.XX firmware has a problem for issuing
+ * BT_ROUND_ROBIN command amurai@spec.co.jp
+ */
+ if ( bID.firm_revision != '2' ) {
+ printf("bt%d: Enabling Round robin scheme\n", unit);
+ bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
+ } else {
+ printf("bt%d: Not Enabling Round robin scheme\n", unit);
}
+
}
#ifndef min
@@ -1434,13 +1500,15 @@ bt_timeout(caddr_t arg1, int arg2)
struct bt_data *bt;
int s = splbio();
+ /*
+ * A timeout routine in kernel DONOT unlink
+ * Entry chains when time outed....So infinity Loop..
+ * 94/04/20 amurai@spec.co.jp
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+
unit = ccb->xfer->sc_link->adapter_unit;
bt = btdata[unit];
- printf("bt%d:%d:%d (%s%d) timed out ", unit
- ,ccb->xfer->sc_link->target
- ,ccb->xfer->sc_link->lun
- ,ccb->xfer->sc_link->device->name
- ,ccb->xfer->sc_link->dev_unit);
#ifdef UTEST
bt_print_active_ccbs(unit);
@@ -1467,13 +1535,14 @@ bt_timeout(caddr_t arg1, int arg2)
ccb->xfer->retries = 0; /* I MEAN IT ! */
ccb->host_stat = BT_ABORTED;
bt_done(unit, ccb);
- } else { /* abort the operation that has timed out */
+ } else {
+ /* abort the operation that has timed out */
printf("bt%d: Try to abort\n", unit);
bt_send_mbo(unit, ~SCSI_NOMASK,
BT_MBO_ABORT, ccb);
/* 2 secs for the abort */
- timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
ccb->flags = CCB_ABORTED;
+ timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
}
splx(s);
}
diff --git a/sys/i386/isa/bt742a_32.c b/sys/i386/isa/bt742a_32.c
new file mode 100644
index 000000000000..f8eabf4de61f
--- /dev/null
+++ b/sys/i386/isa/bt742a_32.c
@@ -0,0 +1,1694 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * $Id: bt742a_32.c,v 1.1 1994/06/17 19:05:57 jkh Exp $
+ */
+
+/*
+ * Bulogic/Bustek 32 bit Addressing Mode SCSI driver (Was bt742a.c)
+ *
+ * THIS DRIVER IS EXPERIMENTAL AND NOT ENABLED BY DEFAULT. It is
+ * provided here merely for reference purposes.
+ *
+ * NOTE: 1. Some bt5xx card can NOT handling 32 bit addressing mode.
+ * 2. OLD bt445s Revision A,B,C,D(nowired) + any firmware version
+ * has broken busmaster for handling 32 bit addressing on H/W bus side.
+ * 3. Extend probing still need to confirm by user base due to
+ * several H/W and firmware dependency. If you have a problem with
+ * extend probing, please contact to 'amurai@spec.co.jp'
+ *
+ * amurai@spec.co.jp 94/6/16
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. it compiles to a program too.. look */
+#include <bt.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#endif /* KERNEL */
+
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /*KERNEL */
+#define NBT 1
+#endif /*KERNEL */
+
+typedef unsigned long int physaddr;
+
+/*
+ * I/O Port Interface
+ */
+
+#define BT_BASE bt->bt_base
+#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */
+#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */
+#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */
+
+/*
+ * BT_CTRL_STAT bits (write)
+ */
+
+#define BT_HRST 0x80 /* Hardware reset */
+#define BT_SRST 0x40 /* Software reset */
+#define BT_IRST 0x20 /* Interrupt reset */
+#define BT_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * BT_CTRL_STAT bits (read)
+ */
+
+#define BT_STST 0x80 /* Self test in Progress */
+#define BT_DIAGF 0x40 /* Diagnostic Failure */
+#define BT_INIT 0x20 /* Mbx Init required */
+#define BT_IDLE 0x10 /* Host Adapter Idle */
+#define BT_CDF 0x08 /* cmd/data out port full */
+#define BT_DF 0x04 /* Data in port full */
+#define BT_INVDCMD 0x01 /* Invalid command */
+
+/*
+ * BT_CMD_DATA bits (write)
+ */
+
+#define BT_NOP 0x00 /* No operation */
+#define BT_MBX_INIT 0x01 /* Mbx initialization */
+#define BT_START_SCSI 0x02 /* start scsi command */
+#define BT_START_BIOS 0x03 /* start bios command */
+#define BT_INQUIRE 0x04 /* Adapter Inquiry */
+#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define BT_SPEED_SET 0x09 /* set transfer speed */
+#define BT_DEV_GET 0x0a /* return installed devices */
+#define BT_CONF_GET 0x0b /* return configuration data */
+#define BT_TARGET_EN 0x0c /* enable target mode */
+#define BT_SETUP_GET 0x0d /* return setup data */
+#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */
+#define BT_READ_CH2 0x1b /* read channel 2 buffer */
+#define BT_WRITE_FIFO 0x1c /* write fifo buffer */
+#define BT_READ_FIFO 0x1d /* read fifo buffer */
+#define BT_ECHO 0x1e /* Echo command data */
+#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
+#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */
+
+/* The following command appeared at FirmWare 3.31 */
+#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */
+#define BT_DISABLE 0x00 /* Parameter value for Disable */
+#define BT_ENABLE 0x01 /* Parameter value for Enable */
+
+struct bt_cmd_buf {
+ u_char byte[16];
+};
+
+/*
+ * BT_INTR_PORT bits (read)
+ */
+
+#define BT_ANY_INTR 0x80 /* Any interrupt */
+#define BT_SCRD 0x08 /* SCSI reset detected */
+#define BT_HACC 0x04 /* Command complete */
+#define BT_MBOA 0x02 /* MBX out empty */
+#define BT_MBIF 0x01 /* MBX in full */
+
+/*
+ * Mail box defs etc.
+ * these could be bigger but we need the bt_data to fit on a single page..
+ */
+
+#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
+ /* don't need that many really */
+#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
+ /* in bt742a H/W ( Not MAX ? ) */
+#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */
+ /* a ccb and need to find the ccb in */
+ /* space, look it up in the hash table */
+#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE)
+
+#define bt_nextmbx( wmb, mbx, mbio ) \
+ if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \
+ (wmb) = &((mbx)->mbio[0]); \
+ else \
+ (wmb)++;
+
+typedef struct bt_mbx_out {
+ physaddr ccb_addr;
+ unsigned char dummy[3];
+ unsigned char cmd;
+} BT_MBO;
+
+typedef struct bt_mbx_in {
+ physaddr ccb_addr;
+ unsigned char btstat;
+ unsigned char sdstat;
+ unsigned char dummy;
+ unsigned char stat;
+} BT_MBI;
+
+struct bt_mbx {
+ BT_MBO mbo[BT_MBX_SIZE];
+ BT_MBI mbi[BT_MBX_SIZE];
+ BT_MBO *tmbo; /* Target Mail Box out */
+ BT_MBI *tmbi; /* Target Mail Box in */
+};
+
+/*
+ * mbo.cmd values
+ */
+
+#define BT_MBO_FREE 0x0 /* MBO entry is free */
+#define BT_MBO_START 0x1 /* MBO activate entry */
+#define BT_MBO_ABORT 0x2 /* MBO abort entry */
+
+/*
+ * mbi.stat values
+ */
+
+#define BT_MBI_FREE 0x0 /* MBI entry is free */
+#define BT_MBI_OK 0x1 /* completed without error */
+#define BT_MBI_ABORT 0x2 /* aborted ccb */
+#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define BT_MBI_ERROR 0x4 /* Completed with error */
+
+#if defined(BIG_DMA)
+WARNING...THIS WON'T WORK(won't fit on 1 page)
+/* #define BT_NSEG 2048*/ /* Number of scatter gather segments - to much vm */
+#define BT_NSEG 128
+#else
+#define BT_NSEG 33
+#endif /* BIG_DMA */
+
+struct bt_scat_gath {
+ unsigned long seg_len;
+ physaddr seg_addr;
+};
+
+struct bt_ccb {
+ unsigned char opcode;
+ unsigned char:3, data_in:1, data_out:1,:3;
+ unsigned char scsi_cmd_length;
+ unsigned char req_sense_length;
+ /*------------------------------------longword boundary */
+ unsigned long data_length;
+ /*------------------------------------longword boundary */
+ physaddr data_addr;
+ /*------------------------------------longword boundary */
+ unsigned char dummy[2];
+ unsigned char host_stat;
+ unsigned char target_stat;
+ /*------------------------------------longword boundary */
+ unsigned char target;
+ unsigned char lun;
+ unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */
+ unsigned char dummy2[1];
+ unsigned char link_id;
+ /*------------------------------------4 longword boundary */
+ physaddr link_addr;
+ /*------------------------------------longword boundary */
+ physaddr sense_ptr;
+/*-----end of HW fields-------------------------------longword boundary */
+ struct scsi_sense_data scsi_sense;
+ /*------------------------------------longword boundary */
+ struct bt_scat_gath scat_gath[BT_NSEG];
+ /*------------------------------------longword boundary */
+ struct bt_ccb *next;
+ /*------------------------------------longword boundary */
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ /*------------------------------------longword boundary */
+ struct bt_mbx_out *mbx; /* pointer to mail box */
+ /*------------------------------------longword boundary */
+ int flags;
+#define CCB_FREE 0
+#define CCB_ACTIVE 1
+#define CCB_ABORTED 2
+ /*------------------------------------longword boundary */
+ struct bt_ccb *nexthash; /* if two hash the same */
+ /*------------------------------------longword boundary */
+ physaddr hashkey; /*physaddr of this ccb */
+ /*------------------------------------longword boundary */
+};
+
+/*
+ * opcode fields
+ */
+
+#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */
+#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
+
+/*
+ * bt_ccb.host_stat values
+ */
+
+#define BT_OK 0x00 /* cmd ok */
+#define BT_LINK_OK 0x0a /* Link cmd ok */
+#define BT_LINK_IT 0x0b /* Link cmd ok + int */
+#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
+#define BT_OVER_UNDER 0x12 /* Data over/under run */
+#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define BT_INV_TARGET 0x18 /* Invalid target direction */
+#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
+#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define BT_ABORTED 42 /* pseudo value from driver */
+
+struct bt_boardID {
+ u_char board_type;
+ u_char custom_feture;
+ char firm_revision;
+ u_char firm_version;
+};
+
+struct bt_setup {
+ u_char sync_neg:1;
+ u_char parity:1;
+ u_char :6;
+ u_char speed;
+ u_char bus_on;
+ u_char bus_off;
+ u_char num_mbx;
+ u_char mbx[3]; /* make a sense with back-word compatibility*/
+ struct {
+ u_char offset:4;
+ u_char period:3;
+ u_char valid:1;
+ } sync[8];
+ u_char disc_sts;
+};
+
+struct bt_config {
+ u_char chan;
+ u_char intr;
+ u_char scsi_dev:3;
+ u_char :5;
+};
+
+#define BT_INQUIRE_REV_THIRD 0x84 /* Get Adapter FirmWare version #3 */
+#define BT_INQUIRE_REV_FOURTH 0x85 /* Get Adapter FirmWare version #4 */
+
+/*
+ * Determine 32bit address/Data firmware functionality from the bus type
+ * Note: bt742a/747[s|d]/757/946/445s will return 'E'
+ * bt542b/545s/545d will return 'A'
+ * 94/05/18 amurai@spec.co.jp
+ */
+#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */
+#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address bus type */
+#define BT_BUS_TYPE_MCA 'M' /* Micro chanel is ? forget it right now */
+struct bt_ext_info {
+ u_char bus_type; /* Host adapter bus type */
+ u_char bios_addr; /* Bios Address-Not used */
+ u_short max_seg; /* Max segment List */
+ u_char num_mbx; /* Number of mailbox */
+ int32 mbx_base; /* mailbox base address */
+ struct {
+ u_char resv1:2; /* ??? */
+ u_char maxsync:1; /* ON: 10MB/s , OFF: 5MB/s */
+ u_char resv2:2; /* ??? */
+ u_char sync:1; /* ON: Sync, OFF: async ONLY!! */
+ u_char resv3:2; /* ??? */
+ } s;
+ u_char firmid[3]; /* Firmware ver. & rev. w/o last char */
+};
+
+#define BT_GET_BOARD_INFO 0x8b /* Get H/W ID and Revision */
+struct bt_board_info {
+ u_char id[4]; /* i.e bt742a -> '7','4','2','A' */
+ u_char ver[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */
+};
+
+#define BT_GET_SYNC_VALUE 0x8c /* Get Synchronous Value */
+struct bt_sync_value {
+ u_char value[8]; /* Synchrnous value (value * 10 nsec) */
+};
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define EISADMA 0x00
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
+
+#define KVTOPHYS(x) vtophys(x)
+#define PAGESIZ 4096
+#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
+
+u_char bt_scratch_buf[256];
+
+struct bt_data {
+ short bt_base; /* base port for each board */
+ struct bt_mbx bt_mbx; /* all our mailboxes */
+ struct bt_ccb *bt_ccb_free; /* list of free CCBs */
+ struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */
+ int bt_int; /* int. read off board */
+ int bt_dma; /* DMA channel read of board */
+ int bt_scsi_dev; /* adapters scsi id */
+ int numccbs; /* how many we have malloc'd */
+ struct scsi_link sc_link; /* prototype for devs */
+} *btdata[NBT];
+
+/***********debug values *************/
+#define BT_SHOWCCBS 0x01
+#define BT_SHOWINTS 0x02
+#define BT_SHOWCMDS 0x04
+#define BT_SHOWMISC 0x08
+int bt_debug = 0;
+
+#ifdef KERNEL
+int btprobe();
+int btattach();
+int btintr();
+int32 bt_scsi_cmd();
+void bt_timeout(caddr_t, int);
+void bt_inquire_setup_information();
+void bt_done();
+void btminphys();
+u_int32 bt_adapter_info();
+struct bt_ccb *bt_get_ccb();
+struct bt_ccb *bt_ccb_phys_kv();
+
+static int btunit = 0;
+
+struct isa_driver btdriver =
+{
+ btprobe,
+ btattach,
+ "bt"
+};
+
+struct scsi_adapter bt_switch =
+{
+ bt_scsi_cmd,
+ btminphys,
+ 0,
+ 0,
+ bt_adapter_info,
+ "bt",
+ 0, 0
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device bt_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "bt",
+ 0,
+ 0, 0
+};
+
+#endif /*KERNEL */
+
+#define BT_RESET_TIMEOUT 1000
+#ifndef KERNEL
+main()
+{
+ printf("bt_data is %d bytes\n", sizeof(struct bt_data));
+ printf("bt_ccb is %d bytes\n", sizeof(struct bt_ccb));
+ printf("bt_mbx is %d bytes\n", sizeof(struct bt_mbx));
+}
+
+#else /*KERNEL */
+
+/*
+ * bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
+ *
+ * Activate Adapter command
+ * icnt: number of args (outbound bytes written after opcode)
+ * ocnt: number of expected returned bytes
+ * wait: number of seconds to wait for response
+ * retval: buffer where to place returned bytes
+ * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ...
+ * args: parameters
+ *
+ * Performs an adapter command through the ports. Not to be confused with a
+ * scsi command, which is read in via the dma; one of the adapter commands
+ * tells it to read in a scsi command.
+ */
+int
+bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args)
+ int unit;
+ int icnt;
+ int ocnt;
+ int wait;
+ u_char *retval;
+ unsigned opcode;
+ u_char args;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned *ic = &opcode;
+ u_char oc;
+ register i;
+ int sts;
+
+ /*
+ * multiply the wait argument by a big constant
+ * zero defaults to 1
+ */
+ if (wait)
+ wait *= 100000;
+ else
+ wait = 100000;
+ /*
+ * Wait for the adapter to go idle, unless it's one of
+ * the commands which don't need this
+ */
+ if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) {
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_IDLE) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not idle(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ }
+ /*
+ * Now that it is idle, if we expect output, preflush the
+ * queue feeding to us.
+ */
+ if (ocnt) {
+ while ((inb(BT_CTRL_STAT_PORT)) & BT_DF)
+ inb(BT_CMD_DATA_PORT);
+ }
+ /*
+ * Output the command and the number of arguments given
+ * for each byte, first check the port is empty.
+ */
+ icnt++;
+ /* include the command */
+ while (icnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (!(sts & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return (ENXIO);
+ }
+ outb(BT_CMD_DATA_PORT, (u_char) (*ic++));
+ }
+ /*
+ * If we expect input, loop that many times, each time,
+ * looking for the data register to have valid data
+ */
+ while (ocnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_DF)
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port empty %d\n",
+ unit, ocnt);
+ return (ENXIO);
+ }
+ oc = inb(BT_CMD_DATA_PORT);
+ if (retval)
+ *retval++ = oc;
+ }
+ /*
+ * Wait for the board to report a finised instruction
+ */
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_INTR_PORT);
+ if (sts & BT_HACC) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not finished(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return (0);
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c
+ */
+int
+btprobe(dev)
+ struct isa_device *dev;
+{
+ /*
+ * find unit and check we have that many defined
+ */
+ int unit = btunit;
+ struct bt_data *bt;
+
+ if (unit >= NBT) {
+ printf("bt%d: unit number too high\n", unit);
+ return 0;
+ }
+ /*
+ * Allocate a storage area for us
+ */
+ if (btdata[unit]) {
+ printf("bt%d: memory already allocated\n", unit);
+ return 0;
+ }
+ bt = malloc(sizeof(struct bt_data), M_TEMP, M_NOWAIT);
+ if (!bt) {
+ printf("bt%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(bt, sizeof(struct bt_data));
+ btdata[unit] = bt;
+ bt->bt_base = dev->id_iobase;
+
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads bt->bt_int
+ */
+ if (bt_init(unit) != 0) {
+ btdata[unit] = NULL;
+ free(bt, M_TEMP);
+ return 0;
+ }
+ /*
+ * If it's there, put in it's interrupt vectors
+ */
+ dev->id_unit = unit;
+ dev->id_irq = (1 << bt->bt_int);
+ dev->id_drq = bt->bt_dma;
+
+ btunit++;
+ return 1;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+btattach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct bt_data *bt = btdata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ bt->sc_link.adapter_unit = unit;
+ bt->sc_link.adapter_targ = bt->bt_scsi_dev;
+ bt->sc_link.adapter = &bt_switch;
+ bt->sc_link.device = &bt_dev;
+
+ /*
+ * Forcely Bounce buffer mechanizum is ON for some broken busmaster
+ * chip with over 16Mbytes boundary for while...
+ * amurai@spec.co.jp 94/06/16
+ */
+ bt->sc_link.flags = SDEV_BOUNCE; /*XXX*/
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(bt->sc_link));
+ return 1;
+}
+
+/*
+ * Return some information to the caller about the adapter and its
+ * capabilities.
+ */
+u_int32
+bt_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+btintr(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ BT_MBI *wmbi;
+ struct bt_mbx *wmbx;
+ struct bt_ccb *ccb;
+ unsigned char stat;
+ int i, wait;
+ int found = 0;
+
+#ifdef UTEST
+ printf("btintr ");
+#endif
+ /*
+ * First acknowlege the interrupt, Then if it's
+ * not telling about a completed operation
+ * just return.
+ */
+ stat = inb(BT_INTR_PORT);
+
+ /* Mail Box out empty ? */
+ if (stat & BT_MBOA) {
+ printf("bt%d: Available Free mbo post\n", unit);
+ /* Disable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ wait = 100000; /* 1 sec enough? */
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_intr, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return 1;
+ }
+ outb(BT_CMD_DATA_PORT, 0x00); /* Disable */
+ wakeup((caddr_t)&bt->bt_mbx);
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ if (!(stat & BT_MBIF)) {
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ /*
+ * If it IS then process the competed operation
+ */
+ wmbx = &bt->bt_mbx;
+ wmbi = wmbx->tmbi;
+ AGAIN:
+ while (wmbi->stat != BT_MBI_FREE) {
+ ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr));
+ if (!ccb) {
+ wmbi->stat = BT_MBI_FREE;
+ printf("bt: BAD CCB ADDR!\n");
+ continue;
+ }
+ found++;
+ if ((stat = wmbi->stat) != BT_MBI_OK) {
+ switch (stat) {
+ case BT_MBI_ABORT:
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("abort ");
+#endif
+ ccb->host_stat = BT_ABORTED;
+ break;
+
+ case BT_MBI_UNKNOWN:
+ ccb = (struct bt_ccb *) 0;
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("unknown ccb for abort");
+#endif
+ break;
+
+ case BT_MBI_ERROR:
+ break;
+
+ default:
+ panic("Impossible mbxi status");
+
+ }
+#ifdef UTEST
+ if ((bt_debug & BT_SHOWCMDS) && ccb) {
+ u_char *cp;
+ cp = ccb->scsi_cmd;
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2],
+ cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi addr = 0x%08x\n"
+ ,wmbi->stat, wmbi);
+ printf("addr = 0x%x\n", ccb);
+ }
+#endif
+ }
+ wmbi->stat = BT_MBI_FREE;
+ if (ccb) {
+ untimeout(bt_timeout, (caddr_t)ccb);
+ bt_done(unit, ccb);
+ }
+ /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ if (wmbi->stat != BT_MBI_FREE) {
+ found++;
+ break;
+ }
+ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n",
+ unit, wmbi, stat);
+ } else {
+ found = 0;
+ goto AGAIN;
+ }
+ }
+ wmbx->tmbi = wmbi;
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+}
+
+/*
+ * A ccb is put onto the free list.
+ */
+void
+bt_free_ccb(unit, ccb, flags)
+ int unit;
+ struct bt_ccb *ccb;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned int opri = 0;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ccb->next = bt->bt_ccb_free;
+ bt->bt_ccb_free = ccb;
+ ccb->flags = CCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (!ccb->next) {
+ wakeup((caddr_t)&bt->bt_ccb_free);
+ }
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in
+ * the hash table too otherwise either return an error or sleep.
+ */
+struct bt_ccb *
+bt_get_ccb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ struct bt_ccb *ccbp;
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ BT_MBO *wmbo; /* Out Mail Box pointer */
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ while (!(ccbp = bt->bt_ccb_free)) {
+ if (bt->numccbs < BT_CCB_MAX) {
+ if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb),
+ M_TEMP,
+ M_NOWAIT)) {
+ bzero(ccbp, sizeof(struct bt_ccb));
+ bt->numccbs++;
+ ccbp->flags = CCB_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccbp->hashkey = KVTOPHYS(ccbp);
+ hashnum = CCB_HASH(ccbp->hashkey);
+ ccbp->nexthash = bt->ccbhash[hashnum];
+ bt->ccbhash[hashnum] = ccbp;
+ } else {
+ printf("bt%d: Can't malloc CCB\n", unit);
+ }
+ goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO,
+ "btccb", 0);
+ }
+ }
+ }
+ if (ccbp) {
+ /* Get CCB from from free list */
+ bt->bt_ccb_free = ccbp->next;
+ ccbp->flags = CCB_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (ccbp);
+}
+
+/*
+ * given a physical address, find the ccb that
+ * it corresponds to:
+ */
+struct bt_ccb *
+bt_ccb_phys_kv(bt, ccb_phys)
+ struct bt_data *bt;
+ physaddr ccb_phys;
+{
+ int hashnum = CCB_HASH(ccb_phys);
+ struct bt_ccb *ccbp = bt->ccbhash[hashnum];
+
+ while (ccbp) {
+ if (ccbp->hashkey == ccb_phys)
+ break;
+ ccbp = ccbp->nexthash;
+ }
+ return ccbp;
+}
+
+/*
+ * Get a MBO and then Send it
+ */
+BT_MBO *
+bt_send_mbo(int unit, int flags, int cmd, struct bt_ccb *ccb)
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ BT_MBO *wmbo; /* Mail Box Out pointer */
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ int i, wait;
+
+ wmbx = &bt->bt_mbx;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ /* Get the Target OUT mail Box pointer and move to Next */
+ wmbo = wmbx->tmbo;
+ wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ?
+ &(wmbx->mbo[0]) : wmbo + 1);
+
+ /*
+ * Check the outmail box is free or not.
+ * Note: Under the normal operation, it shuld NOT happen to wait.
+ */
+ while (wmbo->cmd != BT_MBO_FREE) {
+ wait = 100000; /* 1 sec enough? */
+ /* Enable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_send_mbo, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return ((BT_MBO *) 0);
+ }
+ outb(BT_CMD_DATA_PORT, 0x01); /* Enable */
+ tsleep((caddr_t)wmbx, PRIBIO, "btsend", 0);
+ /* XXX */ /*can't do this! */
+ /* May be servicing an int */
+ }
+ /* Link CCB to the Mail Box */
+ wmbo->ccb_addr = KVTOPHYS(ccb);
+ ccb->mbx = wmbo;
+ wmbo->cmd = cmd;
+
+ /* Send it! */
+ outb(BT_CMD_DATA_PORT, BT_START_SCSI);
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (wmbo);
+}
+
+/*
+ * We have a ccb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went. Wake up the owner if waiting
+ */
+void
+bt_done(unit, ccb)
+ int unit;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ccb->xfer;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK)
+ && (!(xs->flags & SCSI_ERR_OK))) {
+
+ s1 = &(ccb->scsi_sense);
+ s2 = &(xs->sense);
+
+ if (ccb->host_stat) {
+ switch (ccb->host_stat) {
+ case BT_ABORTED: /* No response */
+ case BT_SEL_TIMEOUT: /* No response */
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("timeout reported back\n"));
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected host_stat: %x\n",
+ ccb->host_stat));
+ }
+ } else {
+ switch (ccb->target_stat) {
+ case 0x02:
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case 0x08:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected target_stat: %x\n",
+ ccb->target_stat));
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ } else { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ }
+ xs->flags |= ITSDONE;
+ bt_free_ccb(unit, ccb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+bt_init(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned char ad[4];
+ volatile int i, sts;
+ struct bt_config conf;
+ struct bt_ext_info info;
+ struct bt_board_info binfo;
+
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+
+ outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST);
+
+ for (i = BT_RESET_TIMEOUT; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts == (BT_IDLE | BT_INIT))
+ break;
+ DELAY(1000);
+ }
+ if (i == 0) {
+#ifdef UTEST
+ printf("bt_init: No answer from board\n");
+#endif
+ return (ENXIO);
+ }
+
+ /*
+ * Displaying Board ID and Hardware Revision
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(binfo),0,&binfo,BT_GET_BOARD_INFO,sizeof(binfo));
+ printf("bt%d: Bt%c%c%c%c/%c%d-", unit,
+ binfo.id[0],
+ binfo.id[1],
+ binfo.id[2],
+ binfo.id[3],
+ binfo.ver[0],
+ (unsigned) binfo.ver[1]
+ );
+
+ /*
+ * Make sure board has a capability of 32bit addressing.
+ * and Firmware also need a capability of 32bit addressing pointer
+ * in Extended mailbox and ccb structure.
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(info),0,&info, BT_INQUIRE_EXTENDED,sizeof(info));
+ switch (info.bus_type) {
+ case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */
+ printf("ISA(24bit) bus\n");
+ break;
+ case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */
+ printf("PCI/EISA/VLB(32bit) bus\n");
+ break;
+ case BT_BUS_TYPE_MCA: /* forget it right now */
+ printf("MCA bus architecture...");
+ printf("giving up\n");
+ return (ENXIO);
+ break;
+ default:
+ printf("Unknown state...");
+ printf("giving up\n");
+ return (ENXIO);
+ break;
+ }
+ if ( binfo.id[0] == '5' ) {
+ printf("bt%d: This driver is designed for using 32 bit addressing\n",unit);
+ printf("bt%d: mode firmware and EISA/PCI/VLB bus architecture bus\n",unit);
+ printf("bt%d: WITHOUT any software trick/overhead (i.e.bounce buffer).\n",unit);
+ printf("bt%d: If you have more than 16MBytes memory\n",unit);
+ printf("bt%d: your filesystem will get a serious damage.\n",unit);
+ } else if ( info.bus_type == BT_BUS_TYPE_24bit ) {
+ printf("bt%d: Your board should report a 32bit bus architecture type..\n",unit);
+ printf("bt%d: A firmware on your board may have a problem with over\n",unit);
+ printf("bt%d: 16MBytes memory handling with this driver.\n",unit);
+ }
+
+ /*
+ * Assume we have a board at this stage
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("bt%d: reading board settings, ", unit);
+
+ bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET);
+ switch (conf.chan) {
+ case EISADMA:
+ bt->bt_dma = -1;
+ break;
+ case CHAN0:
+ outb(0x0b, 0x0c);
+ outb(0x0a, 0x00);
+ bt->bt_dma = 0;
+ break;
+ case CHAN5:
+ outb(0xd6, 0xc1);
+ outb(0xd4, 0x01);
+ bt->bt_dma = 5;
+ break;
+ case CHAN6:
+ outb(0xd6, 0xc2);
+ outb(0xd4, 0x02);
+ bt->bt_dma = 6;
+ break;
+ case CHAN7:
+ outb(0xd6, 0xc3);
+ outb(0xd4, 0x03);
+ bt->bt_dma = 7;
+ break;
+ default:
+ printf("illegal dma setting %x\n", conf.chan);
+ return (EIO);
+ }
+ if (bt->bt_dma == -1)
+ printf("busmastering, ");
+ else
+ printf("dma=%d, ", bt->bt_dma);
+
+ switch (conf.intr) {
+ case INT9:
+ bt->bt_int = 9;
+ break;
+ case INT10:
+ bt->bt_int = 10;
+ break;
+ case INT11:
+ bt->bt_int = 11;
+ break;
+ case INT12:
+ bt->bt_int = 12;
+ break;
+ case INT14:
+ bt->bt_int = 14;
+ break;
+ case INT15:
+ bt->bt_int = 15;
+ break;
+ default:
+ printf("illegal int setting\n");
+ return (EIO);
+ }
+ printf("int=%d\n", bt->bt_int);
+
+ /* who are we on the scsi bus */
+ bt->bt_scsi_dev = conf.scsi_dev;
+ /*
+ * Initialize mail box
+ */
+ *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx);
+ bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED
+ ,BT_MBX_SIZE
+ ,ad[0]
+ ,ad[1]
+ ,ad[2]
+ ,ad[3]);
+
+ /*
+ * Set Pointer chain null for just in case
+ * Link the ccb's into a free-list W/O mbox
+ * Initialize mail box status to free
+ */
+ if (bt->bt_ccb_free != (struct bt_ccb *) 0) {
+ printf("bt%d: bt_ccb_free is NOT initialized but init here\n",
+ unit);
+ bt->bt_ccb_free = (struct bt_ccb *) 0;
+ }
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE;
+ bt->bt_mbx.mbi[i].stat = BT_MBI_FREE;
+ }
+ /*
+ * Set up initial mail box for round-robin operation.
+ */
+ bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0];
+ bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0];
+ bt_inquire_setup_information(unit, &info);
+
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ return 0;
+}
+
+void
+bt_inquire_setup_information(
+ int unit,
+ struct bt_ext_info *info )
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_setup setup;
+ struct bt_sync_value sync;
+ char dummy[8];
+ char sub_ver[3];
+ struct bt_boardID bID;
+ int i;
+
+ /* Inquire Installed Devices */
+ bzero( &dummy[0], sizeof(dummy) );
+ bt_cmd(unit, 0, sizeof(dummy), 100, &dummy[0], BT_DEV_GET);
+
+ /*
+ * If board has a capbility of Syncrhonouse mode,
+ * Get a SCSI Synchronous value
+ */
+ if ( info->s.sync ) {
+ bt_cmd(unit, 1, sizeof(sync), 100,
+ &sync,BT_GET_SYNC_VALUE,sizeof(sync));
+ }
+
+ /*
+ * Inquire Board ID to board for firmware version
+ */
+ bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE);
+ bt_cmd(unit, 0, 1, 0, &sub_ver[0], BT_INQUIRE_REV_THIRD );
+ i = ((int)(bID.firm_revision-'0')) * 10 + (int)(bID.firm_version-'0');
+ if ( i >= 33 ) {
+ bt_cmd(unit, 0, 1, 0, &sub_ver[1], BT_INQUIRE_REV_FOURTH );
+ } else {
+ /*
+ * Below rev 3.3 firmware has a problem for issuing
+ * the BT_INQUIRE_REV_FOURTH command.
+ */
+ sub_ver[1]='\0';
+ }
+ sub_ver[2]='\0';
+ if (sub_ver[1]==' ')
+ sub_ver[1]='\0';
+ printf("bt%d: version %c.%c%s, ",
+ unit, bID.firm_revision, bID.firm_version, sub_ver );
+
+ /*
+ * Obtain setup information from board.
+ */
+ bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup));
+
+ if (setup.sync_neg && info->s.sync ) {
+ if ( info->s.maxsync ) {
+ printf("fast sync, "); /* Max 10MB/s */
+ } else {
+ printf("sync, "); /* Max 5MB/s */
+ }
+ } else {
+ if ( info->s.sync ) {
+ printf("async, "); /* Never try by board */
+ } else {
+ printf("async only, "); /* Doesn't has a capability on board */
+ }
+ }
+ if (setup.parity) {
+ printf("parity, ");
+ } else {
+ printf("no parity, ");
+ }
+ printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX);
+
+ /*
+ * Displayi SCSI negotiation value by each target.
+ * amurai@spec.co.jp
+ */
+ for (i = 0; i < 8; i++) {
+ if (!setup.sync[i].valid )
+ continue;
+ if ( (!setup.sync[i].offset && !setup.sync[i].period)
+ || !info->s.sync ) {
+ printf("bt%d: targ %d async\n", unit, i);
+ } else {
+ printf("bt%d: targ %d sync rate=%2d.%02dMB/s(%dns), offset=%02d\n",
+ unit, i,
+ 100 / sync.value[i],
+ (100 % sync.value[i]) * 100 / sync.value[i],
+ sync.value[i] * 10,
+ setup.sync[i].offset );
+ }
+ }
+
+ /*
+ * Enable round-robin scheme - appeared at firmware rev. 3.31
+ * Below rev 3.XX firmware has a problem for issuing
+ * BT_ROUND_ROBIN command amurai@spec.co.jp
+ */
+ if ( bID.firm_revision >= '3' ) {
+ printf("bt%d: Enabling Round robin scheme\n", unit);
+ bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
+ } else {
+ printf("bt%d: Not Enabling Round robin scheme\n", unit);
+ }
+
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+btminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and the data address. Also needs
+ * the unit, target and lu.
+ */
+int32
+bt_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct bt_ccb *ccb;
+ struct bt_scat_gath *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int c = 0;
+ int thiskv;
+ physaddr thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct iovec *iovp;
+ struct bt_data *bt = btdata[unit];
+ BT_MBO *mbo;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_scsi_cmd\n"));
+ /*
+ * get a ccb (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("bt%d: Already done?\n", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("bt%d: Not in use?\n", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(ccb = bt_get_ccb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("start ccb(%x)\n", ccb));
+ /*
+ * Put all the arguments for the xfer in the ccb
+ */
+ ccb->xfer = xs;
+ if (flags & SCSI_RESET) {
+ ccb->opcode = BT_RESET_CCB;
+ } else {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen ?
+ BT_INIT_SCAT_GATH_CCB
+ : BT_INITIATOR_CCB);
+ }
+ ccb->target = xs->sc_link->target;
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->lun = xs->sc_link->lun;
+ ccb->scsi_cmd_length = xs->cmdlen;
+ ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense));
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+
+ if ((xs->datalen) && (!(flags & SCSI_RESET))) { /* can use S/G only if not zero length */
+ ccb->data_addr = KVTOPHYS(ccb->scat_gath);
+ sg = ccb->scat_gath;
+ seg = 0;
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < BT_NSEG)) {
+ sg->seg_addr = (physaddr) iovp->iov_base;
+ xs->datalen += sg->seg_len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)"
+ ,iovp->iov_len, iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ } else
+#endif /* TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < BT_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->seg_addr = thisphys;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /*
+ * This page is contiguous (physically) with
+ * the the last, just extend the length
+ */
+ {
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->seg_len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ }
+ /* end of iov/kv decision */
+ ccb->data_length = seg * sizeof(struct bt_scat_gath);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) {
+ /*
+ * there's still data, must have run out of segs!
+ */
+ printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n",
+ unit, BT_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ ccb->data_addr = (physaddr) 0;
+ ccb->data_length = 0;
+ }
+ ccb->link_id = 0;
+ ccb->link_addr = (physaddr) 0;
+ /*
+ * Put the scsi command in the ccb and start it
+ */
+ if (!(flags & SCSI_RESET)) {
+ bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length);
+ }
+ if (bt_send_mbo(unit, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (TRY_AGAIN_LATER);
+ }
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ if (!(flags & SCSI_NOMASK)) {
+ timeout(bt_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000);
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ return (bt_poll(unit, xs, ccb));
+}
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+int
+bt_poll(unit, xs, ccb)
+ int unit;
+ struct scsi_xfer *xs;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ int done = 0;
+ int count = xs->timeout;
+ u_char stat;
+
+ /* timeouts are in msec, so we loop in 1000 usec cycles */
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out, so call the timeout handler manually,
+ * accounting for the fact that the clock is not running yet
+ * by taking out the clock queue entry it makes.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+
+ /*
+ * because we are polling, take out the timeout entry
+ * bt_timeout made
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+ count = 2000;
+ while (count) {
+ /*
+ * Once again, wait for the int bit
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out again... This is bad. Notice that
+ * this time there is no clock queue entry to remove.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+ }
+ }
+ if (xs->error)
+ return (HAD_ERROR);
+ return (COMPLETE);
+}
+
+void
+bt_timeout(caddr_t arg1, int arg2)
+{
+ struct bt_ccb * ccb = (struct bt_ccb *)arg1;
+ int unit;
+ struct bt_data *bt;
+ int s = splbio();
+
+ /*
+ * A timeout routine in kernel DONOT unlink
+ * Entry chains when time outed....So infinity Loop..
+ * 94/04/20 amurai@spec.co.jp
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+
+ unit = ccb->xfer->sc_link->adapter_unit;
+ bt = btdata[unit];
+
+#ifdef UTEST
+ bt_print_active_ccbs(unit);
+#endif
+
+ /*
+ * If the ccb's mbx is not free, then the board has gone Far East?
+ */
+ if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb &&
+ ccb->mbx->cmd != BT_MBO_FREE) {
+ printf("bt%d: not taking commands!\n", unit);
+ Debugger("bt742a");
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ccb->flags == CCB_ABORTED) {
+ /*
+ * abort timed out
+ */
+ printf("bt%d: Abort Operation has timed out\n", unit);
+ ccb->xfer->retries = 0; /* I MEAN IT ! */
+ ccb->host_stat = BT_ABORTED;
+ bt_done(unit, ccb);
+ } else {
+ /* abort the operation that has timed out */
+ printf("bt%d: Try to abort\n", unit);
+ bt_send_mbo(unit, ~SCSI_NOMASK,
+ BT_MBO_ABORT, ccb);
+ /* 2 secs for the abort */
+ ccb->flags = CCB_ABORTED;
+ timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
+ }
+ splx(s);
+}
+
+#ifdef UTEST
+void
+bt_print_ccb(ccb)
+ struct bt_ccb *ccb;
+{
+ printf("ccb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ccb
+ ,ccb->opcode
+ ,ccb->scsi_cmd_length
+ ,ccb->req_sense_length);
+ printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,ccb->data_length
+ ,ccb->host_stat
+ ,ccb->target_stat
+ ,ccb->flags);
+}
+
+void
+bt_print_active_ccbs(int unit)
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_ccb *ccb;
+ int i = 0;
+
+ while (i < CCB_HASH_SIZE) {
+ ccb = bt->ccbhash[i];
+ while (ccb) {
+ if (ccb->flags != CCB_FREE)
+ bt_print_ccb(ccb);
+ ccb = ccb->nexthash;
+ }
+ i++;
+ }
+}
+#endif /*UTEST */
+#endif /*KERNEL */
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index cd87b28b90e6..5832801d24ae 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ * $Id: clock.c,v 1.9 1994/05/02 09:41:24 sos Exp $
*/
/*
@@ -45,6 +45,7 @@
#include "time.h"
#include "kernel.h"
#include "machine/segments.h"
+#include "machine/frame.h"
#include "i386/isa/icu.h"
#include "i386/isa/isa.h"
#include "i386/isa/rtc.h"
@@ -55,22 +56,225 @@
#ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
-static void findcpuspeed(void);
void
startrtclock()
{
int s;
- findcpuspeed(); /* use the clock (while it's free)
- to find the cpu speed */
/* initialize 8253 clock */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
/* Correct rounding will buy us a better precision in timekeeping */
- outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
- outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA);
@@ -83,44 +287,18 @@ startrtclock()
printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
}
-unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
-
-#define FIRST_GUESS 0x2000
-static void
-findcpuspeed()
-{
- unsigned char low;
- unsigned int remainder;
-
- /* Put counter in count down mode */
- outb(IO_TIMER1+3, 0x34);
- outb(IO_TIMER1, 0xff);
- outb(IO_TIMER1, 0xff);
- delaycount = FIRST_GUESS;
- spinwait(1);
- /* Read the value left in the counter */
- low = inb(IO_TIMER1); /* least siginifcant */
- remainder = inb(IO_TIMER1); /* most significant */
- remainder = (remainder<<8) + low ;
- /* Formula for delaycount is :
- * (loopcount * timer clock speed)/ (counter ticks * 1000)
- */
- delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
-}
-
/* convert 2 digit BCD number */
int
-bcd(i)
- int i;
+bcd(int i)
{
return ((i/16)*10 + (i%16));
}
+
/* convert years to seconds (from 1970) */
unsigned long
-ytos(y)
-int y;
+ytos(int y)
{
int i;
unsigned long ret;
@@ -133,16 +311,16 @@ int y;
return ret;
}
+
/* convert months to seconds */
unsigned long
-mtos(m,leap)
-int m,leap;
+mtos(int m, int leap)
{
int i;
unsigned long ret;
ret = 0;
- for(i=1;i<m;i++) {
+ for(i=1; i<m; i++) {
switch(i){
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
ret += 31*24*60*60; break;
@@ -162,11 +340,10 @@ int m,leap;
* from a filesystem.
*/
void
-inittodr(base)
- time_t base;
+inittodr(time_t base)
{
unsigned long sec;
- int leap,day_week,t,yd;
+ int leap, day_week, t, yd;
int sa,s;
/* do we have a realtime clock present? (otherwise we loop below) */
@@ -180,26 +357,25 @@ inittodr(base)
sec = bcd(rtcin(RTC_YEAR)) + 1900;
if (sec < 1970)
sec += 100;
- leap = !(sec % 4); sec = ytos(sec); /* year */
- yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
- t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
day_week = rtcin(RTC_WDAY); /* day */
sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
sec += bcd(rtcin(RTC_SEC)); /* seconds */
-
sec += tz.tz_minuteswest * 60;
-
time.tv_sec = sec;
}
+
#ifdef garbage
/*
* Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem.
*/
-test_inittodr(base)
- time_t base;
+test_inittodr(time_t base)
{
outb(IO_RTC,9); /* year */
@@ -219,6 +395,7 @@ test_inittodr(base)
}
#endif
+
/*
* Restart the clock.
*/
@@ -227,12 +404,14 @@ resettodr()
{
}
+
/*
* Wire clock interrupt in.
*/
#define V(s) __CONCAT(V, s)
extern void V(clk)();
+
void
enablertclock()
{
@@ -240,12 +419,12 @@ enablertclock()
INTREN(IRQ0);
}
+
/*
* Delay for some number of milliseconds.
*/
void
-spinwait(millisecs)
- int millisecs;
+spinwait(int millisecs)
{
DELAY(1000 * millisecs);
}
diff --git a/sys/i386/isa/com.c b/sys/i386/isa/com.c
index dcaf878685be..25b4dee3238c 100644
--- a/sys/i386/isa/com.c
+++ b/sys/i386/isa/com.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: com.c,v 1.7 1993/12/19 00:50:32 wollman Exp $
+ * $Id: com.c,v 1.10 1994/05/30 03:14:13 ache Exp $
*/
#include "com.h"
@@ -86,7 +86,7 @@ int comconsinit;
int comdefaultrate = TTYDEF_SPEED;
int commajor;
short com_addr[NCOM];
-struct tty com_tty[NCOM];
+struct tty *com_tty[NCOM];
struct speedtab comspeedtab[] = {
0, 0,
@@ -199,12 +199,11 @@ comopen(int /*dev_t*/ dev, int flag, int mode, struct proc *p)
unit = UNIT(dev);
if (unit >= NCOM || (com_active & (1 << unit)) == 0)
return (ENXIO);
- tp = &com_tty[unit];
+ tp = com_tty[unit] = ttymalloc(com_tty[unit]);
tp->t_oproc = comstart;
tp->t_param = comparam;
tp->t_dev = dev;
if ((tp->t_state & TS_ISOPEN) == 0) {
- tp->t_state |= TS_WOPEN;
ttychars(tp);
if (tp->t_ispeed == 0) {
tp->t_iflag = TTYDEF_IFLAG;
@@ -223,9 +222,8 @@ comopen(int /*dev_t*/ dev, int flag, int mode, struct proc *p)
tp->t_state |= TS_CARR_ON;
while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
(tp->t_state & TS_CARR_ON) == 0) {
- tp->t_state |= TS_WOPEN;
- if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- ttopen, 0))
+ if (error = tsleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "comdcd", 0))
break;
}
(void) spl0();
@@ -247,7 +245,7 @@ comclose(dev, flag, mode, p)
unit = UNIT(dev);
com = com_addr[unit];
- tp = &com_tty[unit];
+ tp = com_tty[unit];
(*linesw[tp->t_line].l_close)(tp, flag);
outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
#ifdef KGDB
@@ -255,10 +253,16 @@ comclose(dev, flag, mode, p)
if (kgdb_dev != makedev(commajor, unit))
#endif
outb(com+com_ier, 0);
- if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
- (tp->t_state&TS_ISOPEN) == 0)
+ if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN) == 0)
(void) commctl(dev, 0, DMSET);
ttyclose(tp);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ ttyfree(tp);
+ com_tty[unit] = (struct tty *)NULL;
+#endif
+ return (0);
+
+
return(0);
}
@@ -268,7 +272,7 @@ comread(dev, uio, flag)
struct uio *uio;
int flag;
{
- register struct tty *tp = &com_tty[UNIT(dev)];
+ register struct tty *tp = com_tty[UNIT(dev)];
return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}
@@ -280,7 +284,7 @@ comwrite(dev, uio, flag)
int flag;
{
int unit = UNIT(dev);
- register struct tty *tp = &com_tty[unit];
+ register struct tty *tp = com_tty[unit];
/*
* (XXX) We disallow virtual consoles if the physical console is
@@ -309,7 +313,7 @@ comintr(unit)
return;
case IIR_RXTOUT:
case IIR_RXRDY:
- tp = &com_tty[unit];
+ tp = com_tty[unit];
/*
* Process received bytes. Inline for speed...
*/
@@ -340,7 +344,7 @@ comintr(unit)
}
break;
case IIR_TXRDY:
- tp = &com_tty[unit];
+ tp = com_tty[unit];
tp->t_state &=~ (TS_BUSY|TS_FLUSH);
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
@@ -371,7 +375,7 @@ comeint(unit, stat, com)
register struct tty *tp;
register int c;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
c = inb(com+com_data);
if ((tp->t_state & TS_ISOPEN) == 0) {
#ifdef KGDB
@@ -401,7 +405,7 @@ commint(unit, com)
register struct tty *tp;
register int stat;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
stat = inb(com+com_msr);
if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
if (stat & MSR_DCD)
@@ -432,7 +436,7 @@ comioctl(dev, cmd, data, flag)
register com;
register int error;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error >= 0)
return (error);
@@ -545,26 +549,17 @@ comstart(tp)
s = spltty();
if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
goto out;
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (RB_LEN(&tp->t_out) == 0)
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
+ if (RB_LEN(tp->t_out) == 0)
goto out;
if (inb(com+com_lsr) & LSR_TXRDY) {
- c = getc(&tp->t_out);
+ c = getc(tp->t_out);
tp->t_state |= TS_BUSY;
outb(com+com_data, c);
if (com_hasfifo & (1 << unit))
- for (c = 1; c < 16 && RB_LEN(&tp->t_out); ++c)
- outb(com+com_data, getc(&tp->t_out));
+ for (c = 1; c < 16 && RB_LEN(tp->t_out); ++c)
+ outb(com+com_data, getc(tp->t_out));
}
out:
splx(s);
@@ -647,7 +642,7 @@ comcnprobe(cp)
/* initialize required fields */
cp->cn_dev = makedev(commajor, unit);
- cp->cn_tp = &com_tty[unit];
+ cp->cn_tp = com_tty[unit];
#ifdef COMCONSOLE
cp->cn_pri = CN_REMOTE; /* Force a serial port console */
#else
@@ -747,43 +742,3 @@ comcnputc(dev, c)
splx(s);
}
#endif
-
-int
-comselect(dev, rw, p)
- dev_t dev;
- int rw;
- struct proc *p;
-{
- register struct tty *tp = &com_tty[UNIT(dev)];
- int nread;
- int s = spltty();
- struct proc *selp;
-
- switch (rw) {
-
- case FREAD:
- nread = ttnread(tp);
- if (nread > 0 ||
- ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
- goto win;
- if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_RCOLL;
- else
- tp->t_rsel = p->p_pid;
- break;
-
- case FWRITE:
- if (RB_LEN(&tp->t_out) <= tp->t_lowat)
- goto win;
- if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_WCOLL;
- else
- tp->t_wsel = p->p_pid;
- break;
- }
- splx(s);
- return (0);
- win:
- splx(s);
- return (1);
-}
diff --git a/sys/i386/isa/debug.h b/sys/i386/isa/debug.h
deleted file mode 100644
index 92ecbd67f0fd..000000000000
--- a/sys/i386/isa/debug.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * from: debug.h, part of Bruce Evans interrupt code
- * $Id: debug.h,v 1.3 1993/11/13 02:25:20 davidg Exp $
- */
-
-#define SHOW_A_LOT_NOT
-
-#define BDBTRAP(name) \
- ss ; \
- cmpb $0,_bdb_exists ; \
- je 1f ; \
- testb $SEL_RPL_MASK,4(%esp) ; \
- jne 1f ; \
- ss ; \
-bdb_/**/name/**/_ljmp: ; \
- ljmp $0,$0 ; \
-1:
-
-#if 1
-#define COUNT_EVENT(group, event) incl (group) + (event) * 4
-#else
-#define COUNT_EVENT(group, event)
-#endif
-
-#ifdef SHOW_A_LOT
-
-#define GREEN 0x27 /* 0x27 for true green, 0x07 for mono */
-#define CLI_STI_X 63
-#define CPL_X 46
-#define IMEN_X 64
-#define IPENDING_X 29
-#define RED 0x47 /* 0x47 for true red, 0x70 for mono */
-
-#define SHOW_BIT(bit) ; \
- movl %ecx,%eax ; \
- shr $bit,%eax ; \
- andl $1,%eax ; \
- movb bit_colors(%eax),%al ; \
- movb %al,bit * 2 + 1(%ebx)
-
-#define SHOW_BITS(var, screen_offset) ; \
- pushl %ebx ; \
- pushl %ecx ; \
- movl _Crtat,%ebx ; \
- addl $screen_offset * 2,%ebx ; \
- movl _/**/var,%ecx ; \
- call show_bits ; \
- popl %ecx ; \
- popl %ebx
-
-#define SHOW_CLI \
- COUNT_EVENT(_intrcnt_show, 0) ; \
- pushl %eax ; \
- movl _Crtat,%eax ; \
- movb $RED,CLI_STI_X * 2 + 1(%eax) ; \
- popl %eax
-
-#define SHOW_CPL \
- COUNT_EVENT(_intrcnt_show, 1) ; \
- SHOW_BITS(cpl, CPL_X) ; \
-
-#define SHOW_IMEN \
- COUNT_EVENT(_intrcnt_show, 2) ; \
- SHOW_BITS(imen, IMEN_X)
-
-#define SHOW_IPENDING \
- COUNT_EVENT(_intrcnt_show, 3) ; \
- SHOW_BITS(ipending, IPENDING_X)
-
-#define SHOW_STI \
- COUNT_EVENT(_intrcnt_show, 4) ; \
- pushl %eax ; \
- movl _Crtat,%eax ; \
- movb $GREEN,CLI_STI_X * 2 + 1(%eax) ; \
- popl %eax
-
-#else /* not SHOW_A_LOT */
-
-#define SHOW_CLI COUNT_EVENT(_intrcnt_show, 0)
-#define SHOW_CPL COUNT_EVENT(_intrcnt_show, 1)
-#define SHOW_IMEN COUNT_EVENT(_intrcnt_show, 2)
-#define SHOW_IPENDING COUNT_EVENT(_intrcnt_show, 3)
-#define SHOW_STI COUNT_EVENT(_intrcnt_show, 4)
-
-#endif /* SHOW_A_LOT */
diff --git a/sys/i386/isa/elink.c b/sys/i386/isa/elink.c
new file mode 100644
index 000000000000..cd0057644a89
--- /dev/null
+++ b/sys/i386/isa/elink.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1994 Charles Hannum. 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 Charles Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: elink.c,v 1.1 1994/05/25 20:06:40 ats Exp $
+ */
+
+/*
+ * Common code for dealing with 3COM ethernet cards.
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/pio.h>
+#include <i386/isa/elink.h>
+
+/*
+ * Issue a `global reset' to all cards. We have to be careful to do this only
+ * once during autoconfig, to prevent resetting boards that have already been
+ * configured.
+ */
+void
+elink_reset()
+{
+ static int x = 0;
+
+ if (x == 0) {
+ x = 1;
+ outb(ELINK_ID_PORT, ELINK_RESET);
+ }
+}
+
+/*
+ * The `ID sequence' is really just snapshots of an 8-bit CRC register as 0
+ * bits are shifted in. Different board types use different polynomials.
+ */
+void
+elink_idseq(p)
+ register u_char p;
+{
+ register int i;
+ register u_char c;
+
+ c = 0xff;
+ for (i = 255; i; i--) {
+ outb(ELINK_ID_PORT, c);
+ if (c & 0x80) {
+ c <<= 1;
+ c ^= p;
+ } else
+ c <<= 1;
+ }
+}
diff --git a/sys/i386/isa/elink.h b/sys/i386/isa/elink.h
new file mode 100644
index 000000000000..93a5dac6f5ce
--- /dev/null
+++ b/sys/i386/isa/elink.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1994 Charles Hannum. 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 Charles Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: elink.h,v 1.1 1994/05/25 20:06:43 ats Exp $
+ */
+
+#define ELINK_ID_PORT 0x100
+#define ELINK_RESET 0xc0
+
+#define ELINK_507_POLY 0xe7
+#define ELINK_509_POLY 0xcf
+
+void elink_reset __P((void));
+void elink_idseq __P((u_char p));
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
index 8f3e1dc9cc94..f4632b9f2cb1 100644
--- a/sys/i386/isa/fd.c
+++ b/sys/i386/isa/fd.c
@@ -6,6 +6,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Portions Copyright (c) 1993, 1994 by
+ * jc@irbs.UUCP (John Capo)
+ * vak@zebub.msk.su (Serge Vakulenko)
+ * ache@astral.msk.su (Andrew A. Chernov)
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.21.2.1 1994/03/07 02:08:43 rgrimes Exp $
+ * $Id: fd.c,v 1.26 1994/05/22 12:30:32 joerg Exp $
*
*/
@@ -59,28 +65,29 @@
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
#include <sys/syslog.h>
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/fdreg.h"
#include "i386/isa/fdc.h"
-#include "i386/isa/icu.h"
#include "i386/isa/rtc.h"
-#if NFT > 0
-extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
-#endif
-
#define b_cylin b_resid
-#define FDBLK 512
/* misuse a flag to identify format operation */
#define B_FORMAT B_XXX
+/*
+ * this biotab field doubles as a field for the physical unit number
+ * on the controller
+ */
+#define id_physid id_scsiid
+
#define NUMTYPES 14
#define NUMDENS (NUMTYPES - 6)
-/* This defines (-1) must match index for fd_types */
+/* These defines (-1) must match index for fd_types */
#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
#define FD_1720 1
@@ -132,16 +139,17 @@ struct fdc_data fdc_data[NFDC];
struct fd_data {
struct fdc_data *fdc; /* pointer to controller structure */
int fdsu; /* this units number on this controller */
- int type; /* Drive type (HD, DD */
+ int type; /* Drive type (FD_1440...) */
struct fd_type *ft; /* pointer to the type descriptor */
int flags;
#define FD_OPEN 0x01 /* it's open */
#define FD_ACTIVE 0x02 /* it's active */
#define FD_MOTOR 0x04 /* motor should be on */
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
- int skip;
- int hddrv;
- int track; /* where we think the head is */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+ int options; /* user configurable options, see ioctl_fd.h */
} fd_data[NFD];
/***********************************************************************\
@@ -153,10 +161,48 @@ struct fd_data {
* fdsu is the floppy drive unit number on that controller. (sub-unit) *
\***********************************************************************/
-#define id_physid id_scsiid /* this biotab field doubles as a field */
- /* for the physical unit number on the controller */
+#if NFT > 0
+int ftopen(dev_t, int);
+int ftintr(/* ftu_t */ int ftu);
+int ftclose(/* dev_t */ int, int);
+void ftstrategy(struct buf *);
+int ftioctl(/* dev_t */ int, int, caddr_t, int, struct proc *);
+int ftdump(/* dev_t */ int);
+int ftsize(/* dev_t */ int);
+int ftattach(struct isa_device *, struct isa_device *);
+#endif
+/* autoconfig functions */
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+/* exported functions */
+int fdsize (/* dev_t */ int);
+void fdintr(fdcu_t);
+int Fdopen(/* dev_t */int, int);
+int fdclose(/* dev_t */int, int);
+void fdstrategy(struct buf *);
+int fdioctl(/* dev_t */ int, int, caddr_t, int, struct proc *);
+
+/* needed for ft driver, thus exported */
+int in_fdc(fdcu_t);
+int out_fdc(fdcu_t, int);
+
+/* internal functions */
+static void set_motor(fdcu_t, int, int);
+# define TURNON 1
+# define TURNOFF 0
+static void fd_turnoff(caddr_t arg1, int arg2);
+static void fd_motor_on(caddr_t arg1, int arg2);
+static void fd_turnon(fdu_t);
+static void fdc_reset(fdc_p);
+static void fdstart(fdcu_t);
+static void fd_timeout(caddr_t, int);
+static void fd_pseudointr(caddr_t, int);
+static int fdstate(fdcu_t, fdc_p);
static int retrier(fdcu_t);
+static int fdformat(/* dev_t */ int, struct fd_formb *, struct proc *);
+
#define DEVIDLE 0
#define FINDWORK 1
@@ -188,25 +234,18 @@ char *fdstates[] =
"IOTIMEDOUT"
};
-
-int fd_debug = 1;
+/* CAUTION: fd_debug causes huge amounts of logging output */
+int fd_debug = 0;
#define TRACE0(arg) if(fd_debug) printf(arg)
-#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
#else /* DEBUG */
#define TRACE0(arg)
-#define TRACE1(arg1,arg2)
+#define TRACE1(arg1, arg2)
#endif /* DEBUG */
-static void fdstart(fdcu_t);
-void fdintr(fdcu_t);
-static void fd_turnoff(caddr_t, int);
-
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
-static int fdprobe(struct isa_device *);
-static int fdattach(struct isa_device *);
-
struct isa_driver fdcdriver = {
fdprobe, fdattach, "fdc",
};
@@ -214,56 +253,55 @@ struct isa_driver fdcdriver = {
/*
* probe for existance of controller
*/
-int
+static int
fdprobe(dev)
struct isa_device *dev;
{
fdcu_t fdcu = dev->id_unit;
if(fdc_data[fdcu].flags & FDC_ATTACHED)
{
- printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ printf("fdc: same unit (%d) used multiple times\n", fdcu);
return 0;
}
fdc_data[fdcu].baseport = dev->id_iobase;
/* First - lets reset the floppy controller */
-
- outb(dev->id_iobase+fdout,0);
+ outb(dev->id_iobase+FDOUT, 0);
DELAY(100);
- outb(dev->id_iobase+fdout,FDO_FRST);
+ outb(dev->id_iobase+FDOUT, FDO_FRST);
/* see if it can handle a command */
- if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0)
{
return(0);
}
- out_fdc(fdcu,0xDF);
- out_fdc(fdcu,2);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
return (IO_FDCSIZE);
}
/*
* wire controller into system, look for floppy units
*/
-int
+static int
fdattach(dev)
struct isa_device *dev;
{
- unsigned fdt,st0, cyl;
- int hdr;
+ unsigned fdt;
fdu_t fdu;
fdcu_t fdcu = dev->id_unit;
fdc_p fdc = fdc_data + fdcu;
fd_p fd;
- int fdsu;
+ int fdsu, st0;
struct isa_device *fdup;
fdc->fdcu = fdcu;
fdc->flags |= FDC_ATTACHED;
fdc->dmachan = dev->id_drq;
fdc->state = DEVIDLE;
- hdr = 0;
+ /* reset controller, turn motor off, clear fdout mirror reg */
+ outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
printf("fdc%d:", fdcu);
/* check for each floppy drive */
@@ -303,25 +341,33 @@ fdattach(dev)
continue;
}
-#ifdef notyet
/* select it */
- fd_turnon1(fdu);
- spinwait(1000); /* 1 sec */
- out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
- out_fdc(fdcu,fdsu);
+ set_motor(fdcu, fdsu, TURNON);
spinwait(1000); /* 1 sec */
+ out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */
+ out_fdc(fdcu, fdsu);
+ out_fdc(fdcu, 10);
+ spinwait(300); /* ...wait a moment... */
+ out_fdc(fdcu, NE7CMD_SENSEI); /* make controller happy */
+ (void)in_fdc(fdcu);
+ (void)in_fdc(fdcu);
+ out_fdc(fdcu, NE7CMD_RECAL); /* ...and go back to 0 */
+ out_fdc(fdcu, fdsu);
+ spinwait(1000); /* a second be enough for full stroke seek */
/* anything responding */
- out_fdc(fdcu,NE7CMD_SENSEI);
+ out_fdc(fdcu, NE7CMD_SENSEI);
st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- if (st0 & 0xd0)
+ (void)in_fdc(fdcu);
+ set_motor(fdcu, fdsu, TURNOFF);
+
+ if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
continue;
-#endif
fd->track = -2;
fd->fdc = fdc;
fd->fdsu = fdsu;
+ fd->options = 0;
printf(" [%d: fd%d: ", fdsu, fdu);
switch (fdt) {
@@ -346,15 +392,10 @@ fdattach(dev)
fd->type = NO_TYPE;
break;
}
-
- fd_turnoff((caddr_t)fdu, 0);
- hdr = 1;
}
printf("\n");
- /* Set transfer to 500kbps */
- outb(fdc->baseport+fdctl,0); /*XXX*/
- return 1;
+ return (1);
}
int
@@ -365,102 +406,47 @@ fdsize(dev)
}
/****************************************************************************/
-/* fdstrategy */
-/****************************************************************************/
-void fdstrategy(struct buf *bp)
-{
- register struct buf *dp,*dp0,*dp1;
- long nblocks,blknum;
- int s;
- fdcu_t fdcu;
- fdu_t fdu;
- fdc_p fdc;
- fd_p fd;
-
- fdu = FDUNIT(minor(bp->b_dev));
- fd = &fd_data[fdu];
- fdc = fd->fdc;
- fdcu = fdc->fdcu;
-
-#if NFT > 0
- /* check for controller already busy with tape */
- if (fdc->flags & FDC_TAPE_BUSY) {
- bp->b_error = EBUSY;
- bp->b_flags |= B_ERROR;
- return;
- }
-#endif
- if ((fdu >= NFD) || (bp->b_blkno < 0)) {
- printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
- fdu, bp->b_blkno, bp->b_bcount);
- pg("fd:error in fdstrategy");
- bp->b_error = EINVAL;
- bp->b_flags |= B_ERROR;
- goto bad;
- }
- /*
- * Set up block calculations.
- */
- blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
- nblocks = fd->ft->size;
- if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
- if (blknum == nblocks) {
- bp->b_resid = bp->b_bcount;
- } else {
- bp->b_error = ENOSPC;
- bp->b_flags |= B_ERROR;
- }
- goto bad;
- }
- bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
- dp = &(fdc->head);
- s = splbio();
- disksort(dp, bp);
- untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
- fdstart(fdcu);
- splx(s);
- return;
-
-bad:
- biodone(bp);
- return;
-}
-
-/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
/****************************************************************************/
-void
-set_motor(fdcu, fdu, reset)
+static void
+set_motor(fdcu, fdsu, turnon)
fdcu_t fdcu;
- fdu_t fdu;
- int reset;
+ int fdsu;
+ int turnon;
{
- int m0,m1;
- int selunit;
- fd_p fd;
- if(fd = fdc_data[fdcu].fd)/* yes an assign! */
- {
- selunit = fd->fdsu;
+ int fdout = fdc_data[fdcu].fdout;
+ int needspecify = 0;
+
+ if(turnon) {
+ fdout &= ~FDO_FDSEL;
+ fdout |= (FDO_MOEN0 << fdsu) + fdsu;
+ } else
+ fdout &= ~(FDO_MOEN0 << fdsu);
+
+ if(!turnon
+ && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
+ /* gonna turn off the last drive, put FDC to bed */
+ fdout &= ~ (FDO_FRST|FDO_FDMAEN);
+ else {
+ /* make sure controller is selected and specified */
+ if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
+ needspecify = 1;
+ fdout |= (FDO_FRST|FDO_FDMAEN);
}
- else
- {
- selunit = 0;
+
+ outb(fdc_data[fdcu].baseport+FDOUT, fdout);
+ fdc_data[fdcu].fdout = fdout;
+ TRACE1("[0x%x->FDOUT]", fdout);
+
+ if(needspecify) {
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
}
- m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
- m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
- outb(fdc_data[fdcu].baseport+fdout,
- selunit
- | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
- | (m0 ? FDO_MOEN0 : 0)
- | (m1 ? FDO_MOEN1 : 0));
- TRACE1("[0x%x->fdout]",(
- selunit
- | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
- | (m0 ? FDO_MOEN0 : 0)
- | (m1 ? FDO_MOEN1 : 0)));
}
+/* ARGSUSED */
static void
fd_turnoff(caddr_t arg1, int arg2)
{
@@ -470,11 +456,12 @@ fd_turnoff(caddr_t arg1, int arg2)
fd_p fd = fd_data + fdu;
s = splbio();
fd->flags &= ~FD_MOTOR;
- set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF);
splx(s);
}
-void
+/* ARGSUSED */
+static void
fd_motor_on(caddr_t arg1, int arg2)
{
fdu_t fdu = (fdu_t)arg1;
@@ -490,27 +477,39 @@ fd_motor_on(caddr_t arg1, int arg2)
splx(s);
}
-static void fd_turnon1(fdu_t);
-
-void
+static void
fd_turnon(fdu)
fdu_t fdu;
{
fd_p fd = fd_data + fdu;
if(!(fd->flags & FD_MOTOR))
{
- fd_turnon1(fdu);
- fd->flags |= FD_MOTOR_WAIT;
+ fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
+ set_motor(fd->fdc->fdcu, fd->fdsu, TURNON);
timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
}
}
static void
-fd_turnon1(fdu_t fdu)
+fdc_reset(fdc)
+ fdc_p fdc;
{
- fd_p fd = fd_data + fdu;
- fd->flags |= FD_MOTOR;
- set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ fdcu_t fdcu = fdc->fdcu;
+
+ /* Try a reset, keep motor on */
+ outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
+ TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
+ DELAY(100);
+ /* enable FDC, but defer interrupts a moment */
+ outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN);
+ TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
+ DELAY(100);
+ outb(fdc->baseport + FDOUT, fdc->fdout);
+ TRACE1("[0x%x->FDOUT]", fdc->fdout);
+
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
}
/****************************************************************************/
@@ -522,17 +521,17 @@ in_fdc(fdcu)
{
int baseport = fdc_data[fdcu].baseport;
int i, j = 100000;
- while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
!= (NE7_DIO|NE7_RQM) && j-- > 0)
if (i == NE7_RQM) return -1;
if (j <= 0)
return(-1);
#ifdef DEBUG
- i = inb(baseport+fddata);
- TRACE1("[fddata->0x%x]",(unsigned char)i);
+ i = inb(baseport+FDDATA);
+ TRACE1("[FDDATA->0x%x]", (unsigned char)i);
return(i);
#else
- return inb(baseport+fddata);
+ return inb(baseport+FDDATA);
#endif
}
@@ -546,17 +545,17 @@ out_fdc(fdcu, x)
/* Check that the direction bit is set */
i = 100000;
- while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
if (i <= 0) return (-1); /* Floppy timed out */
/* Check that the floppy controller is ready for a command */
i = 100000;
- while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
if (i <= 0) return (-1); /* Floppy timed out */
/* Send the command and return */
- outb(baseport+fddata,x);
- TRACE1("[0x%x->fddata]",x);
+ outb(baseport+FDDATA, x);
+ TRACE1("[0x%x->FDDATA]", x);
return (0);
}
@@ -647,17 +646,97 @@ fdclose(dev, flags)
int flags;
{
fdu_t fdu = FDUNIT(minor(dev));
- int type = FDTYPE(minor(dev));
#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
if (type & F_TAPE_TYPE)
- return ftclose(0);
+ return ftclose(dev, flags);
#endif
fd_data[fdu].flags &= ~FD_OPEN;
+ fd_data[fdu].options &= ~FDOPT_NORETRY;
return(0);
}
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void
+fdstrategy(struct buf *bp)
+{
+ register struct buf *dp;
+ long nblocks, blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+ size_t fdblk;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+ fdblk = 128 << (fd->ft->secsize);
+
+#if NFT > 0
+ if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
+ /* ft tapes do not (yet) support strategy i/o */
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+#endif
+ if (!(bp->b_flags & B_FORMAT)) {
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ if ((bp->b_bcount % fdblk) != 0) {
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ }
+
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/fdblk;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / fdblk) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
/***************************************************************\
* fdstart *
* We have just queued something.. if the controller is not busy *
@@ -671,9 +750,7 @@ static void
fdstart(fdcu)
fdcu_t fdcu;
{
- register struct buf *dp,*bp;
int s;
- fdu_t fdu;
s = splbio();
if(fdc_data[fdcu].state == DEVIDLE)
@@ -683,38 +760,43 @@ fdstart(fdcu)
splx(s);
}
+/* ARGSUSED */
static void
fd_timeout(caddr_t arg1, int arg2)
{
fdcu_t fdcu = (fdcu_t)arg1;
fdu_t fdu = fdc_data[fdcu].fdu;
- int st0, st3, cyl;
- struct buf *dp,*bp;
- int s;
+ int baseport = fdc_data[fdcu].baseport;
+ struct buf *dp, *bp;
+ int s;
dp = &fdc_data[fdcu].head;
- s = splbio();
bp = dp->b_actf;
- out_fdc(fdcu,NE7CMD_SENSED);
- out_fdc(fdcu,fd_data[fdu].hddrv);
- st3 = in_fdc(fdcu);
-
- out_fdc(fdcu,NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
- fdu,
- st0,
- NE7_ST0BITS,
- cyl,
- st3,
- NE7_ST3BITS);
+ /*
+ * Due to IBM's brain-dead design, the FDC has a faked ready
+ * signal, hardwired to ready == true. Thus, any command
+ * issued if there's no diskette in the drive will _never_
+ * complete, and must be aborted by resetting the FDC.
+ * Many thanks, Big Blue!
+ */
+
+ s = splbio();
+
+ TRACE1("fd%d[fd_timeout()]", fdu);
+ /* See if the controller is still busy (patiently awaiting data) */
+ if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB)
+ {
+ TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS));
+ /* yup, it is; kill it now */
+ fdc_reset(&fdc_data[fdcu]);
+ printf("fd%d: Operation timeout\n", fdu);
+ }
if (bp)
{
retrier(fdcu);
- fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].status[0] = NE7_ST0_IC_RC;
fdc_data[fdcu].state = IOTIMEDOUT;
if( fdc_data[fdcu].retry < 6)
fdc_data[fdcu].retry = 6;
@@ -730,11 +812,13 @@ fd_timeout(caddr_t arg1, int arg2)
}
/* just ensure it has the right spl */
+/* ARGSUSED */
static void
fd_pseudointr(caddr_t arg1, int arg2)
{
fdcu_t fdcu = (fdcu_t)arg1;
int s;
+
s = splbio();
fdintr(fdcu);
splx(s);
@@ -756,25 +840,26 @@ fdintr(fdcu_t fdcu)
(ftintr(fdu));
else
#endif
- while(fdstate(fdcu, fdc))
- ;
+ while(fdstate(fdcu, fdc))
+ ;
}
/***********************************************************************\
* The controller state machine. *
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
-int
+static int
fdstate(fdcu, fdc)
fdcu_t fdcu;
fdc_p fdc;
{
- int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3;
unsigned long blknum;
fdu_t fdu = fdc->fdu;
fd_p fd;
- register struct buf *dp,*bp;
+ register struct buf *dp, *bp;
struct fd_formb *finfo = NULL;
+ size_t fdblk;
dp = &(fdc->head);
bp = dp->b_actf;
@@ -787,16 +872,17 @@ fdstate(fdcu, fdc)
fdc->state = DEVIDLE;
if(fdc->fd)
{
- printf("unexpected valid fd pointer (fdu = %d)\n"
- ,fdc->fdu);
+ printf("unexpected valid fd pointer (fdu = %d)\n",
+ fdc->fdu);
fdc->fd = (fd_p) 0;
fdc->fdu = -1;
}
- TRACE1("[fdc%d IDLE]",fdcu);
+ TRACE1("[fdc%d IDLE]", fdcu);
return(0);
}
fdu = FDUNIT(minor(bp->b_dev));
fd = fd_data + fdu;
+ fdblk = 128 << fd->ft->secsize;
if (fdc->fd && (fd != fdc->fd))
{
printf("confused fd pointers\n");
@@ -805,9 +891,9 @@ fdstate(fdcu, fdc)
format = bp->b_flags & B_FORMAT;
if(format)
finfo = (struct fd_formb *)bp->b_un.b_addr;
- TRACE1("fd%d",fdu);
- TRACE1("[%s]",fdstates[fdc->state]);
- TRACE1("(0x%x)",fd->flags);
+ TRACE1("fd%d", fdu);
+ TRACE1("[%s]", fdstates[fdc->state]);
+ TRACE1("(0x%x)", fd->flags);
untimeout(fd_turnoff, (caddr_t)fdu);
timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
switch (fdc->state)
@@ -818,6 +904,8 @@ fdstate(fdcu, fdc)
fd->skip = 0;
fdc->fd = fd;
fdc->fdu = fdu;
+ outb(fdc->baseport+FDCTL, fd->ft->trans);
+ TRACE1("[0x%x->FDCTL]", fd->ft->trans);
/*******************************************************\
* If the next drive has a motor startup pending, then *
* it will start up in it's own good time *
@@ -838,7 +926,7 @@ fdstate(fdcu, fdc)
}
else /* at least make sure we are selected */
{
- set_motor(fdcu,fd->fdsu,0);
+ set_motor(fdcu, fd->fdsu, TURNON);
}
fdc->state = DOSEEK;
break;
@@ -848,33 +936,55 @@ fdstate(fdcu, fdc)
fdc->state = SEEKCOMPLETE;
break;
}
- out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
- out_fdc(fdcu,fd->fdsu); /* Drive number */
- out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ out_fdc(fdcu, NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu, fd->fdsu); /* Drive number */
+ out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac);
fd->track = -2;
fdc->state = SEEKWAIT;
- timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
return(0); /* will return later */
case SEEKWAIT:
- untimeout(fd_timeout, (caddr_t)fdcu);
/* allow heads to settle */
- timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32);
fdc->state = SEEKCOMPLETE;
return(0); /* will return later */
- break;
-
case SEEKCOMPLETE : /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
if(fd->track == -2)
{
int descyl = bp->b_cylin * fd->ft->steptrac;
- out_fdc(fdcu,NE7CMD_SENSEI);
- i = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
+ do {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ /*
+ * if this was a "ready changed" interrupt,
+ * fetch status again (can happen after
+ * enabling controller from reset state)
+ */
+ } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+ if (0 == descyl)
+ {
+ /*
+ * seek to cyl 0 requested; make sure we are
+ * really there
+ */
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, fdu);
+ st3 = in_fdc(fdcu);
+ if ((st3 & NE7_ST3_T0) == 0) {
+ printf(
+ "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
+ fdu, st3, NE7_ST3BITS);
+ if(fdc->retry < 3)
+ fdc->retry = 3;
+ return(retrier(fdcu));
+ }
+ }
if (cyl != descyl)
{
- printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
- fdu, descyl, cyl, i, NE7_ST0BITS);
+ printf(
+ "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, st0, NE7_ST0BITS);
return(retrier(fdcu));
}
}
@@ -884,46 +994,73 @@ fdstate(fdcu, fdc)
fd->skip = (char *)&(finfo->fd_formb_cylno(0))
- (char *)finfo;
isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
- format ? bp->b_bcount : FDBLK, fdc->dmachan);
- blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
- + fd->skip/FDBLK;
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
+ + fd->skip/fdblk;
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
sec = sec % sectrac + 1;
-/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format || !read)
+ {
+ /* make sure the drive is writable */
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, fdu);
+ st3 = in_fdc(fdcu);
+ if(st3 & NE7_ST3_WP)
+ {
+ /*
+ * XXX YES! this is ugly.
+ * in order to force the current operation
+ * to fail, we will have to fake an FDC
+ * error - all error handling is done
+ * by the retrier()
+ */
+ fdc->status[0] = NE7_ST0_IC_AT;
+ fdc->status[1] = NE7_ST1_NW;
+ fdc->status[2] = 0;
+ fdc->status[3] = fd->track;
+ fdc->status[4] = head;
+ fdc->status[5] = sec;
+ fdc->retry = 8; /* break out immediately */
+ fdc->state = IOTIMEDOUT; /* not really... */
+ return (1);
+ }
+ }
if(format)
{
/* formatting */
- out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
- out_fdc(fdcu,head << 2 | fdu);
- out_fdc(fdcu,finfo->fd_formb_secshift);
- out_fdc(fdcu,finfo->fd_formb_nsecs);
- out_fdc(fdcu,finfo->fd_formb_gaplen);
- out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ out_fdc(fdcu, NE7CMD_FORMAT);
+ out_fdc(fdcu, head << 2 | fdu);
+ out_fdc(fdcu, finfo->fd_formb_secshift);
+ out_fdc(fdcu, finfo->fd_formb_nsecs);
+ out_fdc(fdcu, finfo->fd_formb_gaplen);
+ out_fdc(fdcu, finfo->fd_formb_fillbyte);
}
else
{
if (read)
{
- out_fdc(fdcu,NE7CMD_READ); /* READ */
+ out_fdc(fdcu, NE7CMD_READ); /* READ */
}
else
{
- out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ out_fdc(fdcu, NE7CMD_WRITE); /* WRITE */
}
- out_fdc(fdcu,head << 2 | fdu); /* head & unit */
- out_fdc(fdcu,fd->track); /* track */
- out_fdc(fdcu,head);
- out_fdc(fdcu,sec); /* sector XXX +1? */
- out_fdc(fdcu,fd->ft->secsize); /* sector size */
- out_fdc(fdcu,sectrac); /* sectors/track */
- out_fdc(fdcu,fd->ft->gap); /* gap size */
- out_fdc(fdcu,fd->ft->datalen); /* data length */
+ out_fdc(fdcu, head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu, fd->track); /* track */
+ out_fdc(fdcu, head);
+ out_fdc(fdcu, sec); /* sector XXX +1? */
+ out_fdc(fdcu, fd->ft->secsize); /* sector size */
+ out_fdc(fdcu, sectrac); /* sectors/track */
+ out_fdc(fdcu, fd->ft->gap); /* gap size */
+ out_fdc(fdcu, fd->ft->datalen); /* data length */
}
fdc->state = IOCOMPLETE;
- timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ timeout(fd_timeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
case IOCOMPLETE: /* IO DONE, post-analyze */
untimeout(fd_timeout, (caddr_t)fdcu);
@@ -931,30 +1068,43 @@ fdstate(fdcu, fdc)
{
fdc->status[i] = in_fdc(fdcu);
}
- case IOTIMEDOUT: /*XXX*/
+ fdc->state = IOTIMEDOUT;
+ /* FALLTHROUGH */
+ case IOTIMEDOUT:
isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
- format ? bp->b_bcount : FDBLK, fdc->dmachan);
- if (fdc->status[0]&0xF8)
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
+ if (fdc->status[0] & NE7_ST0_IC)
{
- if (fdc->status[1] & 0x10) {
+ if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
+ && fdc->status[1] & NE7_ST1_OR) {
/*
- * Operation not completed in reasonable time.
- * Just restart it, don't increment retry count.
- * (vak)
+ * DMA overrun. Someone hogged the bus
+ * and didn't release it in time for the
+ * next FDC transfer.
+ * Just restart it, don't increment retry
+ * count. (vak)
*/
fdc->state = SEEKCOMPLETE;
return (1);
}
+ else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
+ && fdc->retry < 6)
+ fdc->retry = 6; /* force a reset */
+ else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
+ && fdc->status[2] & NE7_ST2_WC
+ && fdc->retry < 3)
+ fdc->retry = 3; /* force recalibrate */
return(retrier(fdcu));
}
/* All OK */
- fd->skip += FDBLK;
+ fd->skip += fdblk;
if (!format && fd->skip < bp->b_bcount)
{
/* set up next transfer */
- blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
- + fd->skip/FDBLK;
- bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
+ + fd->skip/fdblk;
+ bp->b_cylin =
+ (blknum / (fd->ft->sectrac * fd->ft->heads));
fdc->state = DOSEEK;
}
else
@@ -970,68 +1120,76 @@ fdstate(fdcu, fdc)
}
return(1);
case RESETCTLR:
- /* Try a reset, keep motor on */
- set_motor(fdcu,fd->fdsu,1);
- DELAY(100);
- set_motor(fdcu,fd->fdsu,0);
- outb(fdc->baseport+fdctl,fd->ft->trans);
- TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc_reset(fdc);
fdc->retry++;
fdc->state = STARTRECAL;
break;
case STARTRECAL:
- out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
- out_fdc(fdcu,0xDF);
- out_fdc(fdcu,2);
- out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
- out_fdc(fdcu,fdu);
+ out_fdc(fdcu, NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu, fdu);
fdc->state = RECALWAIT;
return(0); /* will return later */
case RECALWAIT:
/* allow heads to settle */
- timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32);
fdc->state = RECALCOMPLETE;
return(0); /* will return later */
case RECALCOMPLETE:
- out_fdc(fdcu,NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- if (cyl != 0)
+ do {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ /*
+ * if this was a "ready changed" interrupt,
+ * fetch status again (can happen after
+ * enabling controller from reset state)
+ */
+ } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+ if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
{
printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
st0, NE7_ST0BITS, cyl);
+ if(fdc->retry < 3) fdc->retry = 3;
return(retrier(fdcu));
}
fd->track = 0;
/* Seek (probably) necessary */
fdc->state = DOSEEK;
return(1); /* will return immediatly */
- case MOTORWAIT:
+ case MOTORWAIT:
if(fd->flags & FD_MOTOR_WAIT)
{
return(0); /* time's not up yet */
}
- fdc->state = DOSEEK;
+ /*
+ * since the controller was off, it has lost its
+ * idea about the current track it were; thus,
+ * recalibrate the bastard
+ */
+ fdc->state = STARTRECAL;
return(1); /* will return immediatly */
default:
printf("Unexpected FD int->");
- out_fdc(fdcu,NE7CMD_SENSEI);
+ out_fdc(fdcu, NE7CMD_SENSEI);
st0 = in_fdc(fdcu);
cyl = in_fdc(fdcu);
- printf("ST0 = %lx, PCN = %lx\n",i,sec);
- out_fdc(fdcu,0x4A);
- out_fdc(fdcu,fd->fdsu);
+ printf("ST0 = %x, PCN = %x\n", st0, cyl);
+ out_fdc(fdcu, NE7CMD_READID);
+ out_fdc(fdcu, fd->fdsu);
for(i=0;i<7;i++) {
fdc->status[i] = in_fdc(fdcu);
}
- printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
- fdc->status[0],
- fdc->status[1],
- fdc->status[2],
- fdc->status[3],
- fdc->status[4],
- fdc->status[5],
- fdc->status[6] );
+ if(fdc->status[0] != -1)
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ else
+ printf("FDC timed out\n");
return(0);
}
return(1); /* Come back immediatly to new state */
@@ -1042,11 +1200,13 @@ retrier(fdcu)
fdcu_t fdcu;
{
fdc_p fdc = fdc_data + fdcu;
- register struct buf *dp,*bp;
+ register struct buf *dp, *bp;
dp = &(fdc->head);
bp = dp->b_actf;
+ if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY)
+ goto fail;
switch(fdc->retry)
{
case 0: case 1: case 2:
@@ -1061,12 +1221,15 @@ retrier(fdcu)
case 7:
break;
default:
+ fail:
{
dev_t sav_b_dev = bp->b_dev;
/* Trick diskerr */
- bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ bp->b_dev = makedev(major(bp->b_dev),
+ (FDUNIT(minor(bp->b_dev))<<3)|3);
diskerr(bp, "fd", "hard error", LOG_PRINTF,
- fdc->fd->skip, (struct disklabel *)NULL);
+ fdc->fd->skip / DEV_BSIZE,
+ (struct disklabel *)NULL);
bp->b_dev = sav_b_dev;
printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
@@ -1101,9 +1264,11 @@ fdformat(dev, finfo, p)
struct buf *bp;
int rv = 0, s;
-
+ size_t fdblk;
+
fdu = FDUNIT(minor(dev));
fd = &fd_data[fdu];
+ fdblk = 128 << fd->ft->secsize;
/* set up a buffer header for fdstrategy() */
bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
@@ -1119,7 +1284,7 @@ fdformat(dev, finfo, p)
* seek to the requested cylinder
*/
bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
- + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+ + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
bp->b_un.b_addr = (caddr_t)finfo;
@@ -1138,41 +1303,39 @@ fdformat(dev, finfo, p)
splx(s);
if(rv == EWOULDBLOCK)
- {
/* timed out */
- biodone(bp);
rv = EIO;
- }
+ if(bp->b_flags & B_ERROR)
+ rv = bp->b_error;
+ biodone(bp);
free(bp, M_TEMP);
return rv;
}
/*
- * fdioctl() from jc@irbs.UUCP (John Capo)
- * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
- * defines fdioctl to be enxio.
*
- * TODO: Reformat.
- * Think about allocating buffer off stack.
+ * TODO: Think about allocating buffer off stack.
* Don't pass uncast 0's and NULL's to read/write/setdisklabel().
* Watch out for NetBSD's different *disklabel() interface.
*
- * Added functionality for floppy formatting
- * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
*/
int
-fdioctl (dev, cmd, addr, flag, p)
+fdioctl(dev, cmd, addr, flag, p)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
struct proc *p;
{
+ fdu_t fdu = FDUNIT(minor(dev));
+ fd_p fd = &fd_data[fdu];
+ size_t fdblk;
+
struct fd_type *fdt;
struct disklabel *dl;
char buffer[DEV_BSIZE];
- int error;
+ int error = 0;
#if NFT > 0
int type = FDTYPE(minor(dev));
@@ -1182,14 +1345,14 @@ fdioctl (dev, cmd, addr, flag, p)
return ftioctl(dev, cmd, addr, flag, p);
#endif
- error = 0;
+ fdblk = 128 << fd->ft->secsize;
switch (cmd)
{
case DIOCGDINFO:
bzero(buffer, sizeof (buffer));
dl = (struct disklabel *)buffer;
- dl->d_secsize = FDBLK;
+ dl->d_secsize = fdblk;
fdt = fd_data[FDUNIT(minor(dev))].ft;
dl->d_secpercyl = fdt->size / fdt->tracks;
dl->d_type = DTYPE_FLOPPY;
@@ -1221,12 +1384,12 @@ fdioctl (dev, cmd, addr, flag, p)
dl = (struct disklabel *)addr;
- if (error = setdisklabel ((struct disklabel *)buffer,
- dl, 0, NULL))
+ if ((error =
+ setdisklabel ((struct disklabel *)buffer, dl, 0, NULL)))
break;
error = writedisklabel(dev, fdstrategy,
- (struct disklabel *)buffer, NULL);
+ (struct disklabel *)buffer, NULL);
break;
case FD_FORM:
@@ -1243,11 +1406,42 @@ fdioctl (dev, cmd, addr, flag, p)
*(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
break;
+ case FD_STYPE: /* set drive type */
+ /* this is considered harmful; only allow for superuser */
+ if(suser(p->p_ucred, &p->p_acflag) != 0)
+ return EPERM;
+ *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr;
+ break;
+
+ case FD_GOPTS: /* get drive options */
+ *(int *)addr = fd_data[FDUNIT(minor(dev))].options;
+ break;
+
+ case FD_SOPTS: /* set drive options */
+ fd_data[FDUNIT(minor(dev))].options = *(int *)addr;
+ break;
+
default:
- error = EINVAL;
+ error = ENOTTY;
break;
}
return (error);
}
#endif
+/*
+ * Hello emacs, these are the
+ * Local Variables:
+ * c-indent-level: 8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * c-brace-offset: -8
+ * c-brace-imaginary-offset: 0
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c++-hanging-braces: 1
+ * c++-access-specifier-offset: -8
+ * c++-empty-arglist-indent: 8
+ * c++-friend-offset: 0
+ * End:
+ */
diff --git a/sys/i386/isa/fdc.h b/sys/i386/isa/fdc.h
index 7d75d5a81b48..ef81b11a8387 100644
--- a/sys/i386/isa/fdc.h
+++ b/sys/i386/isa/fdc.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fdc.h,v 1.2 1994/02/14 22:24:25 nate Exp $
+ * $Id: fdc.h,v 1.3 1994/05/22 12:35:38 joerg Exp $
*
*/
@@ -49,12 +49,12 @@ struct fdc_data
#define FDC_HASFTAPE 0x02
#define FDC_TAPE_BUSY 0x04
struct fd_data *fd;
- int fdu; /* the active drive */
+ int fdu; /* the active drive */
+ int state;
+ int retry;
+ int fdout; /* mirror of the w/o digital output reg */
+ int status[7]; /* copy of the registers */
struct buf head; /* Head of buf chain */
- struct buf rhead; /* Raw head of buf chain */
- int state;
- int retry;
- int status[7]; /* copy of the registers */
};
/***********************************************************************\
diff --git a/sys/i386/isa/fdreg.h b/sys/i386/isa/fdreg.h
index b0e9593a93c5..9b5be2b87b1c 100644
--- a/sys/i386/isa/fdreg.h
+++ b/sys/i386/isa/fdreg.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
- * $Id: fdreg.h,v 1.4 1994/02/07 22:12:42 alm Exp $
+ * $Id: fdreg.h,v 1.5 1994/05/22 12:35:40 joerg Exp $
*/
/*
@@ -42,24 +42,26 @@
#include "../i386/isa/ic/nec765.h"
/* registers */
-#define fdout 2 /* Digital Output Register (W) */
+#define FDOUT 2 /* Digital Output Register (W) */
#define FDO_FDSEL 0x03 /* floppy device select */
#define FDO_FRST 0x04 /* floppy controller reset */
#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
#define FDO_MOEN0 0x10 /* motor enable drive 0 */
#define FDO_MOEN1 0x20 /* motor enable drive 1 */
-#define FDO_MOEN2 0x30 /* motor enable drive 2 */
-#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+#define FDO_MOEN2 0x40 /* motor enable drive 2 */
+#define FDO_MOEN3 0x80 /* motor enable drive 3 */
-#define fdsts 4 /* NEC 765 Main Status Register (R) */
-#define fddata 5 /* NEC 765 Data Register (R/W) */
+#define FDSTS 4 /* NEC 765 Main Status Register (R) */
+#define FDDATA 5 /* NEC 765 Data Register (R/W) */
-#define fdctl 7 /* Control Register (W) */
+#define FDCTL 7 /* Control Register (W) */
#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+ /* for some controllers 1MPBS instead */
-#define fdin 7 /* Digital Input Register (R) */
+#define FDIN 7 /* Digital Input Register (R) */
#define FDI_DCHG 0x80 /* diskette has been changed */
-
+ /* requires drive and motor being selected */
+ /* is cleared by any step pulse to drive */
diff --git a/sys/i386/isa/ft.c b/sys/i386/isa/ft.c
index 09bc127090aa..1204613bcd8e 100644
--- a/sys/i386/isa/ft.c
+++ b/sys/i386/isa/ft.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Steve Gerakines
+ * Copyright (c) 1993, 1994 Steve Gerakines
*
* This is freely redistributable software. You may do anything you
* wish with it, so long as the above notice stays intact.
@@ -17,8 +17,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* ft.c - QIC-40/80 floppy tape driver
- * $Id: ft.c,v 1.4 1994/02/14 22:24:28 nate Exp $
+ * $Id: ft.c,v 1.7 1994/06/22 05:52:36 jkh Exp $
*
+ * 06/07/94 v0.9 ++sg
+ * Tape stuck on segment problem should be gone. Re-wrote buffering
+ * scheme. Added support for drives that do not automatically perform
+ * seek load point. Can handle more wakeup types now and should correctly
+ * report most manufacturer names. Fixed places where unit 0 was being
+ * sent to the fdc instead of the actual unit number. Added ioctl support
+ * for an in-core badmap.
*
* 01/26/94 v0.3b - Jim Babb
* Got rid of the hard coded device selection. Moved (some of) the
@@ -76,12 +83,13 @@
#include "ftreg.h"
/* Enable or disable debugging messages. */
-#define FTDBGALL 0 /* everything */
-/* #define DPRT(a) printf a */
-#define DPRT(a)
+#define FTDBGALL 0 /* 1 if you want everything */
+/*#define DPRT(a) printf a */
+#define DPRT(a)
/* Constants private to the driver */
#define FTPRI (PRIBIO) /* sleep priority */
+#define FTNBUFF 9 /* 8 for buffering, 1 for header */
/* The following items are needed from the fd driver. */
extern int in_fdc(int); /* read fdc registers */
@@ -92,11 +100,13 @@ extern int hz; /* system clock rate */
/* Type of tape attached */
/* use numbers that don't interfere with the possible floppy types */
#define NO_TYPE 0 /* (same as NO_TYPE in fd.c) */
- /* F_TAPE_TYPE must match value in fd.c */
-#define F_TAPE_TYPE 0x020 /* bit for ft->types to indicate tape */
-#define FT_MOUNTAIN (F_TAPE_TYPE | 1)
-#define FT_COLORADO (F_TAPE_TYPE | 2)
+/* F_TAPE_TYPE must match value in fd.c */
+#define F_TAPE_TYPE 0x020 /* bit for ft->types to indicate tape */
+#define FT_NONE (F_TAPE_TYPE | 0) /* no method required */
+#define FT_MOUNTAIN (F_TAPE_TYPE | 1) /* mountain */
+#define FT_COLORADO (F_TAPE_TYPE | 2) /* colorado */
+#define FT_INSIGHT (F_TAPE_TYPE | 3) /* insight */
/* Mode FDC is currently in: tape or disk */
enum { FDC_TAPE_MODE, FDC_DISK_MODE };
@@ -150,15 +160,25 @@ QIC_Geom *ftg = NULL; /* Current tape's geometry */
/*
* things relating to asynchronous commands
*/
-static int astk_depth; /* async_cmd stack depth */
static int awr_state; /* state of async write */
static int ard_state; /* state of async read */
static int arq_state; /* state of async request */
static int async_retries; /* retries, one per invocation */
static int async_func; /* function to perform */
static int async_state; /* state current function is at */
-static int async_arg[5]; /* up to 5 arguments for async cmds */
+static int async_arg0; /* up to 3 arguments for async cmds */
+static int async_arg1; /**/
+static int async_arg2; /**/
static int async_ret; /* return value */
+static struct _astk {
+ int over_func;
+ int over_state;
+ int over_retries;
+ int over_arg0;
+ int over_arg1;
+ int over_arg2;
+} astk[10];
+static struct _astk *astk_ptr = &astk[0]; /* Pointer to stack position */
/* List of valid async (interrupt driven) tape support functions. */
enum {
@@ -172,29 +192,36 @@ enum {
};
/* Call another asyncronous command from within async_cmd(). */
-#define CALL_ACMD(r,f,a,b,c,d,e) \
- astk[astk_depth].over_retries = async_retries; \
- astk[astk_depth].over_func = async_func; \
- astk[astk_depth].over_state = (r); \
- for (i = 0; i < 5; i++) \
- astk[astk_depth].over_arg[i] = async_arg[i]; \
+#define CALL_ACMD(r,f,a,b,c) \
+ astk_ptr->over_retries = async_retries; \
+ astk_ptr->over_func = async_func; \
+ astk_ptr->over_state = (r); \
+ astk_ptr->over_arg0 = async_arg0; \
+ astk_ptr->over_arg1 = async_arg1; \
+ astk_ptr->over_arg2 = async_arg2; \
async_func = (f); async_state = 0; async_retries = 0; \
- async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
- async_arg[3]=(d); async_arg[4]=(e); \
- astk_depth++; \
+ async_arg0=(a); async_arg1=(b); async_arg2=(c); \
+ astk_ptr++; \
goto restate
/* Perform an asyncronous command from outside async_cmd(). */
-#define ACMD_FUNC(r,f,a,b,c,d,e) over_async = (r); astk_depth = 0; \
+#define ACMD_FUNC(r,f,a,b,c) over_async = (r); astk_ptr = &astk[0]; \
async_func = (f); async_state = 0; async_retries = 0; \
- async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
- async_arg[3]=(d); async_arg[4]=(e); \
+ async_arg0=(a); async_arg1=(b); async_arg2=(c); \
async_cmd(ftu); \
return
/* Various wait channels */
+static char *wc_buff_avail = "bavail";
+static char *wc_buff_done = "bdone";
+static char *wc_iosts_change = "iochg";
+static char *wc_long_delay = "ldelay";
+static char *wc_intr_wait = "intrw";
+#define ftsleep(wc,to) tsleep((caddr_t)(wc),FTPRI,(wc),(to))
+
static struct {
int buff_avail;
+ int buff_done;
int iosts_change;
int long_delay;
int intr_wait;
@@ -223,8 +250,17 @@ struct ft_data {
unsigned char *xptr; /* pointer to buffer blk to xfer */
int xcnt; /* transfer count */
int xblk; /* block number to transfer */
- SegReq *curseg; /* Current segment to do I/O on */
- SegReq *bufseg; /* Buffered segment to r/w ahead */
+ int xseg; /* segment being transferred */
+ SegReq *segh; /* Current I/O request */
+ SegReq *segt; /* Tail of queued I/O requests */
+ SegReq *doneh; /* Completed I/O request queue */
+ SegReq *donet; /* Completed I/O request tail */
+ SegReq *segfree; /* Free segments */
+ SegReq *hdr; /* Current tape header */
+ int nsegq; /* Segments on request queue */
+ int ndoneq; /* Segments on completed queue */
+ int nfreelist; /* Segments on free list */
+
/* the next 3 should be defines in 'flags' */
int active; /* TRUE if transfer is active */
int rdonly; /* TRUE if tape is read-only */
@@ -261,85 +297,237 @@ void ftstrategy(struct buf *);
int ftioctl(dev_t, int, caddr_t, int, struct proc *);
int ftdump(dev_t);
int ftsize(dev_t);
-static void ft_timeout(caddr_t arg1, int arg2);
-void async_cmd(ftu_t);
-void async_req(ftu_t, int);
-void async_read(ftu_t, int);
-void async_write(ftu_t, int);
-void tape_start(ftu_t);
-void tape_end(ftu_t);
-void tape_inactive(ftu_t);
+static void ft_timeout(caddr_t, int);
+static void async_cmd(ftu_t);
+static void async_req(ftu_t, int);
+static void async_read(ftu_t, int);
+static void async_write(ftu_t, int);
+static void tape_start(ftu_t, int);
+static void tape_end(ftu_t);
+static void tape_inactive(ftu_t);
+static int tape_cmd(ftu_t, int);
+static int tape_status(ftu_t);
+static int qic_status(ftu_t, int, int);
+static int ftreq_rewind(ftu_t);
+static int ftreq_hwinfo(ftu_t, QIC_HWInfo *);
+
+/*****************************************************************************/
+
+
+/*
+ * Allocate a segment I/O buffer from the free list.
+ */
+static SegReq *
+segio_alloc(ft_p ft)
+{
+ SegReq *r;
+
+ /* Grab first item from free list */
+ if ((r = ft->segfree) != NULL) {
+ ft->segfree = ft->segfree->next;
+ ft->nfreelist--;
+ }
+ DPRT(("segio_alloc: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ return(r);
+}
+
+
+/*
+ * Queue a segment I/O request.
+ */
+static void
+segio_queue(ft_p ft, SegReq *sp)
+{
+ /* Put request on in process queue. */
+ if (ft->segt == NULL)
+ ft->segh = sp;
+ else
+ ft->segt->next = sp;
+ sp->next = NULL;
+ ft->segt = sp;
+ ft->nsegq++;
+ DPRT(("segio_queue: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+}
+/*
+ * Segment I/O completed, place on correct queue.
+ */
+static void
+segio_done(ft_p ft, SegReq *sp)
+{
+ /* First remove from current I/O queue */
+ ft->segh = sp->next;
+ if (ft->segh == NULL) ft->segt = NULL;
+ ft->nsegq--;
+
+ if (sp->reqtype == FTIO_WRITING) {
+ /* Place on free list */
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
+ wakeup((caddr_t)wc_buff_avail);
+ DPRT(("segio_done: (w) nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ } else {
+ /* Put on completed I/O queue */
+ if (ft->donet == NULL)
+ ft->doneh = sp;
+ else
+ ft->donet->next = sp;
+ sp->next = NULL;
+ ft->donet = sp;
+ ft->ndoneq++;
+ wakeup((caddr_t)wc_buff_done);
+ DPRT(("segio_done: (r) nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ }
+}
+/*
+ * Take I/O request from finished queue to free queue.
+ */
+static void
+segio_free(ft_p ft, SegReq *sp)
+{
+ /* First remove from done queue */
+ ft->doneh = sp->next;
+ if (ft->doneh == NULL) ft->donet = NULL;
+ ft->ndoneq--;
+
+ /* Place on free list */
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
+ wakeup((caddr_t)wc_buff_avail);
+ DPRT(("segio_free: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+}
+
/*
* Probe/attach floppy tapes.
*/
-int ftattach(isadev, fdup)
+int
+ftattach(isadev, fdup)
struct isa_device *isadev, *fdup;
{
- fdcu_t fdcu = isadev->id_unit; /* fdc active unit */
- fdc_p fdc = fdc_data + fdcu; /* pointer to controller structure */
- ftu_t ftu = fdup->id_unit;
- ft_p ft;
- ftsu_t ftsu = fdup->id_physid;
-
- if (ftu >= NFT)
- return 0;
- ft = &ft_data[ftu];
- /* Probe for tape */
- ft->attaching = 1;
- ft->type = NO_TYPE;
- ft->fdc = fdc;
- ft->ftsu = ftsu;
-
- tape_start(ftu); /* ready controller for tape */
- tape_cmd(ftu, QC_COL_ENABLE1);
- tape_cmd(ftu, QC_COL_ENABLE2);
- if (tape_status(ftu) >= 0) {
- ft->type = FT_COLORADO;
- fdc->flags |= FDC_HASFTAPE;
- printf(" [%d: ft%d: Colorado tape]",
- fdup->id_physid, fdup->id_unit );
- tape_cmd(ftu, QC_COL_DISABLE);
- goto out;
- }
+ fdcu_t fdcu = isadev->id_unit; /* fdc active unit */
+ fdc_p fdc = fdc_data + fdcu; /* pointer to controller structure */
+ ftu_t ftu = fdup->id_unit;
+ ft_p ft;
+ ftsu_t ftsu = fdup->id_physid;
+ QIC_HWInfo hw;
+ char *manu;
+
+ if (ftu >= NFT) return 0;
+ ft = &ft_data[ftu];
+
+ /* Probe for tape */
+ ft->attaching = 1;
+ ft->type = NO_TYPE;
+ ft->fdc = fdc;
+ ft->ftsu = ftsu;
- tape_start(ftu); /* ready controller for tape */
- tape_cmd(ftu, QC_MTN_ENABLE1);
- tape_cmd(ftu, QC_MTN_ENABLE2);
- if (tape_status(ftu) >= 0) {
- ft->type = FT_MOUNTAIN;
- fdc->flags |= FDC_HASFTAPE;
- printf(" [%d: ft%d: Mountain tape]",
- fdup->id_physid, fdup->id_unit );
- tape_cmd(ftu, QC_MTN_DISABLE);
- goto out;
- }
+ /*
+ * FT_NONE - no method, just do it
+ */
+ tape_start(ftu, 0);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_NONE;
+ ftreq_hwinfo(ftu, &hw);
+ goto out;
+ }
+
+ /*
+ * FT_COLORADO - colorado style
+ */
+ tape_start(ftu, 0);
+ tape_cmd(ftu, QC_COL_ENABLE1);
+ tape_cmd(ftu, QC_COL_ENABLE2 + ftu);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_COLORADO;
+ ftreq_hwinfo(ftu, &hw);
+ tape_cmd(ftu, QC_COL_DISABLE);
+ goto out;
+ }
+
+ /*
+ * FT_MOUNTAIN - mountain style
+ */
+ tape_start(ftu, 0);
+ tape_cmd(ftu, QC_MTN_ENABLE1);
+ tape_cmd(ftu, QC_MTN_ENABLE2);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_MOUNTAIN;
+ ftreq_hwinfo(ftu, &hw);
+ tape_cmd(ftu, QC_MTN_DISABLE);
+ goto out;
+ }
+
+ /*
+ * FT_INSIGHT - insight style
+ */
+ tape_start(ftu, 1);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_INSIGHT;
+ ftreq_hwinfo(ftu, &hw);
+ goto out;
+ }
out:
- tape_end(ftu);
- ft->attaching = 0;
- return(ft->type);
+ tape_end(ftu);
+ if (ft->type != NO_TYPE) {
+ fdc->flags |= FDC_HASFTAPE;
+ switch(hw.hw_make) {
+ case 0x0000:
+ if (ft->type == FT_COLORADO)
+ manu = "Colorado";
+ else if (ft->type == FT_INSIGHT)
+ manu = "Insight";
+ else if (ft->type == FT_MOUNTAIN && hw.hw_model == 0x05)
+ manu = "Archive";
+ else if (ft->type == FT_MOUNTAIN)
+ manu = "Mountain";
+ else
+ manu = "Unknown";
+ break;
+ case 0x0001:
+ manu = "Colorado";
+ break;
+ case 0x0005:
+ if (hw.hw_model >= 0x09)
+ manu = "Conner";
+ else
+ manu = "Archive";
+ break;
+ case 0x0006:
+ manu = "Mountain";
+ break;
+ case 0x0007:
+ manu = "Wangtek";
+ break;
+ case 0x0222:
+ manu = "IOMega";
+ break;
+ default:
+ manu = "Unknown";
+ break;
+ }
+ printf(" [%d: ft%d: %s tape]", fdup->id_physid, fdup->id_unit, manu);
+ }
+ ft->attaching = 0;
+ return(ft->type);
}
/*
* Perform common commands asynchronously.
*/
-void async_cmd(ftu_t ftu) {
+static void
+async_cmd(ftu_t ftu) {
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu;
int cmd, i, st0, st3, pcn;
static int bitn, retval, retpos, nbits, newcn;
- static struct {
- int over_func;
- int over_state;
- int over_retries;
- int over_arg[5];
- } astk[15];
static int wanttrk, wantblk, wantdir;
static int curpos, curtrk, curblk, curdir, curdiff;
static int errcnt = 0;
@@ -356,7 +544,7 @@ restate:
*/
switch (async_state) {
case 0:
- cmd = async_arg[0];
+ cmd = async_arg0;
#if FTDBGALL
DPRT(("===>async_seek cmd = %d\n", cmd));
#endif
@@ -364,7 +552,7 @@ restate:
async_state = 1;
i = 0;
if (out_fdc(fdcu, NE7CMD_SEEK) < 0) i = 1;
- if (!i && out_fdc(fdcu, 0x00) < 0) i = 1;
+ if (!i && out_fdc(fdcu, ftu) < 0) i = 1;
if (!i && out_fdc(fdcu, newcn) < 0) i = 1;
if (i) {
if (++async_retries >= 10) {
@@ -399,7 +587,7 @@ restate:
DPRT(("ft%d: async_seek error st0 = $%02x pcn = %d\n",
ftu, st0, pcn));
#endif
- if (async_arg[1]) goto complete;
+ if (async_arg1) goto complete;
async_state = 2;
timeout(ft_timeout, (caddr_t)ftu, hz/50);
break;
@@ -420,14 +608,14 @@ restate:
case 0:
bitn = 0;
retval = 0;
- cmd = async_arg[0];
- nbits = async_arg[1];
+ cmd = async_arg0;
+ nbits = async_arg1;
DPRT(("async_status got cmd = %d nbits = %d\n", cmd,nbits));
- CALL_ACMD(5, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_SEEK, QC_NEXTBIT, 0, 0);
/* NOTREACHED */
case 1:
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if (st3 < 0) {
DPRT(("ft%d: async_status timed out on bit %d r=$%02x\n",
@@ -440,7 +628,7 @@ restate:
if (bitn >= (nbits+2)) {
if ((retval & 1) && (retval & (1 << (nbits+1)))) {
async_ret = (retval & ~(1<<(nbits+1))) >> 1;
- if (async_arg[0] == QC_STATUS && async_arg[2] == 0 &&
+ if (async_arg0 == QC_STATUS && async_arg2 == 0 &&
(async_ret & (QS_ERROR|QS_NEWCART))) {
async_state = 2;
goto restate;
@@ -453,31 +641,31 @@ restate:
}
goto complete;
}
- CALL_ACMD(1, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEK, QC_NEXTBIT, 0, 0);
/* NOTREACHED */
case 2:
if (async_ret & QS_NEWCART) ft->newcart = 1;
- CALL_ACMD(3, ACMD_STATUS, QC_ERRCODE, 16, 1, 0, 0);
+ CALL_ACMD(3, ACMD_STATUS, QC_ERRCODE, 16, 1);
case 3:
ft->lasterr = async_ret;
if ((ft->lasterr & QS_NEWCART) == 0 && ft->lasterr) {
DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
ftu, ft->lasterr & 0xff, ft->lasterr >> 8));
}
- cmd = async_arg[0];
- nbits = async_arg[1];
- CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 1, 0, 0);
+ cmd = async_arg0;
+ nbits = async_arg1;
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 1);
case 4:
goto complete;
case 5:
- CALL_ACMD(6, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(6, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 6:
- CALL_ACMD(7, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(7, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 7:
- CALL_ACMD(8, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(8, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 8:
- cmd = async_arg[0];
- CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ cmd = async_arg0;
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0);
}
break;
@@ -488,9 +676,9 @@ restate:
*/
switch(async_state) {
case 0:
- CALL_ACMD(1, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(1, ACMD_STATUS, QC_STATUS, 8, 0);
case 1:
- if ((async_ret & async_arg[0]) != 0) goto complete;
+ if ((async_ret & async_arg0) != 0) goto complete;
async_state = 0;
if (++async_retries == 360) { /* 90 secs. */
DPRT(("ft%d: acmd_state exceeded retry count\n", ftu));
@@ -510,13 +698,13 @@ restate:
*/
switch(async_state) {
case 0:
- cmd = async_arg[0];
- async_retries = (async_arg[2]) ? (async_arg[2]*4) : 10;
- CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ cmd = async_arg0;
+ async_retries = (async_arg2) ? (async_arg2 * 4) : 10;
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0);
case 1:
- CALL_ACMD(2, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(2, ACMD_STATUS, QC_STATUS, 8, 0);
case 2:
- if ((async_ret & async_arg[1]) != 0) goto complete;
+ if ((async_ret & async_arg1) != 0) goto complete;
if (--async_retries == 0) {
DPRT(("ft%d: acmd_seeksts retries exceeded\n", ftu));
goto complete;
@@ -534,12 +722,12 @@ restate:
switch(async_state) {
case 0:
if (!ft->moving) {
- CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
/* NOTREACHED */
}
async_state = 1;
out_fdc(fdcu, 0x4a); /* READ_ID */
- out_fdc(fdcu, 0);
+ out_fdc(fdcu, ftu);
break;
case 1:
for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
@@ -548,25 +736,36 @@ restate:
DPRT(("readid st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d\n",
ft->rid[0], ft->rid[1], ft->rid[2], ft->rid[3],
ft->rid[4], ft->rid[5], async_ret));
- if ((ft->rid[0] & 0xc0) == 0x40) {
- if (++errcnt >= 10) {
+ if ((ft->rid[0] & 0xc0) != 0 || async_ret < 0) {
+ /*
+ * Method for retry:
+ * errcnt == 1 regular retry
+ * 2 microstep head 1
+ * 3 microstep head 2
+ * 4 microstep head back to 0
+ * 5 fail
+ */
+ if (++errcnt >= 5) {
DPRT(("ft%d: acmd_readid errcnt exceeded\n", fdcu));
- async_ret = ft->lastpos;
+ async_ret = -2;
errcnt = 0;
goto complete;
}
- if (errcnt > 2) {
+ if (errcnt == 1) {
+ ft->moving = 0;
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ } else {
ft->moving = 0;
- CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STPAUSE, QS_READY, 0);
}
- DPRT(("readid retry...\n"));
+ DPRT(("readid retry %d...\n", errcnt));
async_state = 0;
goto restate;
}
if ((async_ret % ftg->g_blktrk) == (ftg->g_blktrk-1)) {
DPRT(("acmd_readid detected last block on track\n"));
retpos = async_ret;
- CALL_ACMD(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ CALL_ACMD(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0);
/* NOTREACHED */
}
ft->lastpos = async_ret;
@@ -574,13 +773,13 @@ restate:
goto complete;
/* NOTREACHED */
case 2:
- CALL_ACMD(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ CALL_ACMD(3, ACMD_STATE, QS_READY, 0, 0);
case 3:
ft->moving = 0;
async_ret = retpos+1;
goto complete;
case 4:
- CALL_ACMD(5, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_SEEK, QC_FORWARD, 0, 0);
case 5:
ft->moving = 1;
async_state = 0;
@@ -598,27 +797,27 @@ restate:
*/
switch (async_state) {
case 0:
- wanttrk = async_arg[0] / ftg->g_blktrk;
- wantblk = async_arg[0] % ftg->g_blktrk;
+ wanttrk = async_arg0 / ftg->g_blktrk;
+ wantblk = async_arg0 % ftg->g_blktrk;
wantdir = wanttrk & 1;
ft->moving = 0;
- CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
case 1:
curtrk = wanttrk;
curdir = curtrk & 1;
DPRT(("Changing to track %d\n", wanttrk));
- CALL_ACMD(2, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ CALL_ACMD(2, ACMD_SEEK, QC_SEEKTRACK, 0, 0);
case 2:
cmd = wanttrk+2;
- CALL_ACMD(3, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ CALL_ACMD(3, ACMD_SEEKSTS, cmd, QS_READY, 0);
case 3:
- CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 0);
case 4:
ft->laststs = async_ret;
if (wantblk == 0) {
curblk = 0;
cmd = (wantdir) ? QC_SEEKEND : QC_SEEKSTART;
- CALL_ACMD(6, ACMD_SEEKSTS, cmd, QS_READY, 90, 0, 0);
+ CALL_ACMD(6, ACMD_SEEKSTS, cmd, QS_READY, 90);
}
if (ft->laststs & QS_BOT) {
DPRT(("Tape is at BOT\n"));
@@ -632,15 +831,23 @@ restate:
async_state = 6;
goto restate;
}
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
case 5:
+ if (async_ret < 0) {
+ ft->moving = 0;
+ ft->lastpos = -2;
+ if (async_ret == -2) {
+ CALL_ACMD(9, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ }
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ }
curtrk = (async_ret+1) / ftg->g_blktrk;
curblk = (async_ret+1) % ftg->g_blktrk;
DPRT(("gotid: curtrk=%d wanttrk=%d curblk=%d wantblk=%d\n",
curtrk, wanttrk, curblk, wantblk));
if (curtrk != wanttrk) { /* oops! */
DPRT(("oops!! wrong track!\n"));
- CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
}
async_state = 6;
goto restate;
@@ -650,22 +857,22 @@ restate:
ft->lastpos = curblk - 1;
async_ret = ft->lastpos;
if (ft->moving) goto complete;
- CALL_ACMD(7, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ CALL_ACMD(7, ACMD_STATE, QS_READY, 0, 0);
}
if (curblk > wantblk) { /* passed it */
ft->moving = 0;
- CALL_ACMD(10, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(10, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
}
- if ((wantblk - curblk) <= 96) { /* approaching it */
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ if ((wantblk - curblk) <= 256) { /* approaching it */
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
}
/* way up ahead */
ft->moving = 0;
- CALL_ACMD(14, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(14, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
break;
case 7:
ft->moving = 1;
- CALL_ACMD(8, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ CALL_ACMD(8, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 8:
async_state = 9;
@@ -677,26 +884,26 @@ restate:
curdiff = ((curblk - wantblk) / QCV_BLKSEG) + 2;
if (curdiff >= ftg->g_segtrk) curdiff = ftg->g_segtrk - 1;
DPRT(("pos %d past %d, reverse %d\n", curblk, wantblk, curdiff));
- CALL_ACMD(11, ACMD_SEEK, QC_SEEKREV, 0, 0, 0, 0);
+ CALL_ACMD(11, ACMD_SEEK, QC_SEEKREV, 0, 0);
case 11:
DPRT(("reverse 1 done\n"));
- CALL_ACMD(12, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ CALL_ACMD(12, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0);
case 12:
DPRT(("reverse 2 done\n"));
- CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90);
case 13:
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
case 14:
curdiff = ((wantblk - curblk) / QCV_BLKSEG) - 2;
if (curdiff < 0) curdiff = 0;
DPRT(("pos %d before %d, forward %d\n", curblk, wantblk, curdiff));
- CALL_ACMD(15, ACMD_SEEK, QC_SEEKFWD, 0, 0, 0, 0);
+ CALL_ACMD(15, ACMD_SEEK, QC_SEEKFWD, 0, 0);
case 15:
DPRT(("forward 1 done\n"));
- CALL_ACMD(16, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ CALL_ACMD(16, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0);
case 16:
DPRT(("forward 2 done\n"));
- CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90);
}
break;
}
@@ -704,13 +911,14 @@ restate:
return;
complete:
- if (astk_depth) {
- astk_depth--;
- async_retries = astk[astk_depth].over_retries;
- async_func = astk[astk_depth].over_func;
- async_state = astk[astk_depth].over_state;
- for(i = 0; i < 5; i++)
- async_arg[i] = astk[astk_depth].over_arg[i];
+ if (astk_ptr != &astk[0]) {
+ astk_ptr--;
+ async_retries = astk_ptr->over_retries;
+ async_func = astk_ptr->over_func;
+ async_state = astk_ptr->over_state;
+ async_arg0 = astk_ptr->over_arg0;
+ async_arg1 = astk_ptr->over_arg1;
+ async_arg2 = astk_ptr->over_arg2;
goto restate;
}
async_func = ACMD_NONE;
@@ -720,6 +928,7 @@ complete:
async_req(ftu, 2);
break;
case FTIO_READING:
+ case FTIO_RDAHEAD:
async_read(ftu, 2);
break;
case FTIO_WRITING:
@@ -735,10 +944,11 @@ complete:
/*
* Entry point for the async request processor.
*/
-void async_req(ftu_t ftu, int from)
+static void
+async_req(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
- SegReq *sp;
+ SegReq *nsp, *sp;
static int over_async, lastreq, domore;
int cmd;
@@ -747,56 +957,73 @@ void async_req(ftu_t ftu, int from)
restate:
switch (arq_state) {
case 0: /* Process segment */
- ft->io_sts = ft->curseg->reqtype;
+ sp = ft->segh;
+ ft->io_sts = (sp == NULL) ? FTIO_READY : sp->reqtype;
+
if (ft->io_sts == FTIO_WRITING)
async_write(ftu, from);
else
async_read(ftu, from);
if (ft->io_sts != FTIO_READY) return;
- /* Swap buffered and current segment */
- lastreq = ft->curseg->reqtype;
- ft->curseg->reqtype = FTIO_READY;
- sp = ft->curseg;
- ft->curseg = ft->bufseg;
- ft->bufseg = sp;
+ /* Pull buffer from current I/O queue */
+ if (sp != NULL) {
+ lastreq = sp->reqtype;
+ segio_done(ft, sp);
- wakeup((caddr_t)&ftsem.buff_avail);
+ /* If I/O cancelled, clear finished queue. */
+ if (sp->reqcan) {
+ while (ft->doneh != NULL)
+ segio_free(ft, ft->doneh);
+ lastreq = FTIO_READY;
+ }
+ } else
+ lastreq = FTIO_READY;
/* Detect end of track */
if (((ft->xblk / QCV_BLKSEG) % ftg->g_segtrk) == 0) {
- domore = (ft->curseg->reqtype != FTIO_READY);
- ACMD_FUNC(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ ACMD_FUNC(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0);
}
arq_state = 1;
goto restate;
case 1: /* Next request */
- if (ft->curseg->reqtype != FTIO_READY) {
- ft->curseg->reqcrc = 0;
+ /* If we have another request queued, start it running. */
+ if (ft->segh != NULL) {
+ sp = ft->segh;
+ sp->reqcrc = 0;
arq_state = ard_state = awr_state = 0;
- ft->xblk = ft->curseg->reqblk;
+ ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
- ft->xptr = ft->curseg->buff;
- DPRT(("I/O reqblk = %d\n", ft->curseg->reqblk));
+ ft->xptr = sp->buff;
+ DPRT(("I/O reqblk = %d\n", ft->xblk));
goto restate;
}
- if (lastreq == FTIO_READING) {
- ft->curseg->reqtype = FTIO_RDAHEAD;
- ft->curseg->reqblk = ft->xblk;
- ft->curseg->reqcrc = 0;
- ft->curseg->reqcan = 0;
- bzero(ft->curseg->buff, QCV_SEGSIZE);
+
+ /* If the last request was reading, do read ahead. */
+ if ((lastreq == FTIO_READING || lastreq == FTIO_RDAHEAD) &&
+ (sp = segio_alloc(ft)) != NULL) {
+ sp->reqtype = FTIO_RDAHEAD;
+ sp->reqblk = ft->xblk;
+ sp->reqseg = ft->xseg+1;
+ sp->reqcrc = 0;
+ sp->reqcan = 0;
+ segio_queue(ft, sp);
+ bzero(sp->buff, QCV_SEGSIZE);
arq_state = ard_state = awr_state = 0;
- ft->xblk = ft->curseg->reqblk;
+ ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
- ft->xptr = ft->curseg->buff;
- DPRT(("Processing readahead reqblk = %d\n", ft->curseg->reqblk));
+ ft->xptr = sp->buff;
+ DPRT(("Processing readahead reqblk = %d\n", ft->xblk));
goto restate;
}
+
if (ft->moving) {
DPRT(("No more I/O.. Stopping.\n"));
- ACMD_FUNC(7, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ ft->moving = 0;
+ ACMD_FUNC(7, ACMD_SEEKSTS, QC_PAUSE, QS_READY, 0);
break;
}
arq_state = 7;
@@ -804,26 +1031,26 @@ restate:
case 2: /* End of track */
ft->moving = 0;
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
break;
case 3:
DPRT(("async_req seek head to track %d\n", ft->xblk / ftg->g_blktrk));
- ACMD_FUNC(4, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_SEEKTRACK, 0, 0);
break;
case 4:
cmd = (ft->xblk / ftg->g_blktrk) + 2;
- if (domore) {
- ACMD_FUNC(5, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ if (ft->segh != NULL) {
+ ACMD_FUNC(5, ACMD_SEEKSTS, cmd, QS_READY, 0);
} else {
- ACMD_FUNC(7, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ ACMD_FUNC(7, ACMD_SEEKSTS, cmd, QS_READY, 0);
}
break;
case 5:
ft->moving = 1;
- ACMD_FUNC(6, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(6, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 6:
@@ -832,26 +1059,22 @@ restate:
break;
case 7:
- ft->moving = 0;
-
- /* Check one last time to see if a request came in. */
- if (ft->curseg->reqtype != FTIO_READY) {
- DPRT(("async_req: Never say no!\n"));
- arq_state = 1;
- goto restate;
- }
-
/* Time to rest. */
ft->active = 0;
- wakeup((caddr_t)&ftsem.iosts_change); /* wakeup those who want an i/o chg */
+ ft->lastpos = -2;
+
+ /* wakeup those who want an i/o chg */
+ wakeup((caddr_t)wc_iosts_change);
break;
}
}
+
/*
* Entry for async read.
*/
-void async_read(ftu_t ftu, int from)
+static void
+async_read(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
@@ -859,6 +1082,7 @@ void async_read(ftu_t ftu, int from)
int i, cmd, newcn, rddta[7];
int st0, pcn, where;
static int over_async;
+ static int retries = 0;
if (from == 2) ard_state = over_async;
@@ -872,13 +1096,13 @@ restate:
if (ft->lastpos != (ft->xblk-1)) {
DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
ftu, ft->lastpos, ft->xblk));
- ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0);
}
/* Tape is in position but stopped. */
if (!ft->moving) {
DPRT(("async_read ******STARTING TAPE\n"));
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
}
ard_state = 1;
goto restate;
@@ -887,8 +1111,8 @@ restate:
/* Tape is now moving and in position-- start DMA now! */
isa_dmastart(B_READ, ft->xptr, QCV_BLKSIZE, 2);
out_fdc(fdcu, 0x66); /* read */
- out_fdc(fdcu, 0x00); /* unit */
- out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ftu); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
out_fdc(fdcu, 0x03); /* 1K sectors */
@@ -905,7 +1129,8 @@ restate:
#if FTDBGALL
/* Compute where the controller thinks we are */
- where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside) + rddta[5]-1;
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
where, ft->xblk));
@@ -913,34 +1138,44 @@ restate:
/* Check for errors */
if ((rddta[0] & 0xc0) != 0x00) {
- if (rddta[1] & 0x04) {
+#if !FTDBGALL
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
+ DPRT(("xd: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+ if ((rddta[1] & 0x04) == 0x04 && retries < 2) {
/* Probably wrong position */
+ DPRT(("async_read: doing retry %d\n", retries));
ft->lastpos = ft->xblk;
ard_state = 0;
+ retries++;
goto restate;
} else {
/* CRC/Address-mark/Data-mark, et. al. */
DPRT(("ft%d: CRC error on block %d\n", fdcu, ft->xblk));
- ft->curseg->reqcrc |= (1 << ft->xcnt);
+ ft->segh->reqcrc |= (1 << ft->xcnt);
}
}
/* Otherwise, transfer completed okay. */
+ retries = 0;
ft->lastpos = ft->xblk;
ft->xblk++;
ft->xcnt++;
ft->xptr += QCV_BLKSIZE;
- if (ft->xcnt < QCV_BLKSEG && ft->curseg->reqcan == 0) {
+ if (ft->xcnt < QCV_BLKSEG && ft->segh->reqcan == 0) {
ard_state = 0;
goto restate;
}
- DPRT(("Read done.. Cancel = %d\n", ft->curseg->reqcan));
+ DPRT(("Read done.. Cancel = %d\n", ft->segh->reqcan));
ft->io_sts = FTIO_READY;
break;
case 3:
ft->moving = 1;
- ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 4:
@@ -960,7 +1195,8 @@ restate:
* routine, if it's 1 then it was a timeout, if it's 2, then an
* async_cmd completed.
*/
-void async_write(ftu_t ftu, int from)
+static void
+async_write(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
@@ -982,13 +1218,13 @@ restate:
if (ft->lastpos != (ft->xblk-1)) {
DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
ftu, ft->lastpos, ft->xblk));
- ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0);
}
/* Tape is in position but stopped. */
if (!ft->moving) {
DPRT(("async_write ******STARTING TAPE\n"));
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
}
awr_state = 1;
goto restate;
@@ -997,8 +1233,8 @@ restate:
/* Tape is now moving and in position-- start DMA now! */
isa_dmastart(B_WRITE, ft->xptr, QCV_BLKSIZE, 2);
out_fdc(fdcu, 0x45); /* write */
- out_fdc(fdcu, 0x00); /* unit */
- out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ftu); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cyl */
out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
out_fdc(fdcu, 0x03); /* 1K sectors */
@@ -1023,13 +1259,16 @@ restate:
/* Check for errors */
if ((rddta[0] & 0xc0) != 0x00) {
- if (rddta[1] & 0x04) {
- /* Probably wrong position */
- ft->lastpos = ft->xblk;
- awr_state = 0;
- goto restate;
- } else if (retries < 5) {
+#if !FTDBGALL
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
+ DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+ if (retries < 3) {
/* Something happened -- try again */
+ DPRT(("async_write: doing retry %d\n", retries));
ft->lastpos = ft->xblk;
awr_state = 0;
retries++;
@@ -1037,11 +1276,11 @@ restate:
} else {
/*
* Retries failed. Note the unrecoverable error.
- * Marking the block as bad is fairly useless.
+ * Marking the block as bad is useless right now.
*/
printf("ft%d: unrecoverable write error on block %d\n",
ftu, ft->xblk);
- ft->curseg->reqcrc |= (1 << ft->xcnt);
+ ft->segh->reqcrc |= (1 << ft->xcnt);
}
}
@@ -1063,7 +1302,7 @@ restate:
case 3:
ft->moving = 1;
- ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 4:
@@ -1081,11 +1320,14 @@ restate:
/*
* Interrupt handler for active tape. Bounced off of fdintr().
*/
-int ftintr(ftu_t ftu)
+int
+ftintr(ftu_t ftu)
{
int st0, pcn, i;
ft_p ft = &ft_data[ftu];
- fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ int s = splbio();
+
st0 = 0;
pcn = 0;
@@ -1093,12 +1335,14 @@ int ftintr(ftu_t ftu)
if (ft->active) {
if (async_func != ACMD_NONE) {
async_cmd(ftu);
+ splx(s);
return(1);
}
#if FTDBGALL
DPRT(("Got request interrupt\n"));
#endif
async_req(ftu, 0);
+ splx(s);
return(1);
}
@@ -1113,20 +1357,21 @@ int ftintr(ftu_t ftu)
huh_what:
printf("ft%d: unexpected interrupt; st0 = $%02x pcn = %d\n",
ftu, st0, pcn);
+ splx(s);
return(1);
}
switch (ft->cmd_wait) {
case FTCMD_RESET:
ft->sts_wait = FTSTS_INTERRUPT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
break;
case FTCMD_RECAL:
case FTCMD_SEEK:
if (st0 & 0x20) { /* seek done */
ft->sts_wait = FTSTS_INTERRUPT;
ft->pcn = pcn;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
}
#if FTDBGALL
else
@@ -1137,20 +1382,23 @@ huh_what:
case FTCMD_READID:
for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
ft->sts_wait = FTSTS_INTERRUPT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
break;
default:
goto huh_what;
}
+ splx(s);
return(1);
}
+
/*
* Interrupt timeout routine.
*/
-static void ft_timeout(caddr_t arg1, int arg2)
+static void
+ft_timeout(caddr_t arg1, int arg2)
{
int s;
ftu_t ftu = (ftu_t)arg1;
@@ -1166,17 +1414,19 @@ static void ft_timeout(caddr_t arg1, int arg2)
async_req(ftu, 1);
} else {
ft->sts_wait = FTSTS_TIMEOUT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
}
splx(s);
}
+
/*
* Wait for a particular interrupt to occur. ftintr() will wake us up
* if it sees what we want. Otherwise, time out and return error.
* Should always disable ints before trigger is sent and calling here.
*/
-int ftintr_wait(ftu_t ftu, int cmd, int ticks)
+static int
+ftintr_wait(ftu_t ftu, int cmd, int ticks)
{
int retries, st0, pcn;
ft_p ft = &ft_data[ftu];
@@ -1211,8 +1461,7 @@ int ftintr_wait(ftu_t ftu, int cmd, int ticks)
goto intrdone;
}
- if (ticks) timeout(ft_timeout, (caddr_t)ftu, ticks);
- sleep((caddr_t)&ftsem.intr_wait, FTPRI);
+ ftsleep(wc_intr_wait, ticks);
intrdone:
if (ft->sts_wait == FTSTS_TIMEOUT) { /* timeout */
@@ -1230,11 +1479,13 @@ intrdone:
return(0);
}
+
/*
* Recalibrate tape drive. Parameter totape is true, if we should
* recalibrate to tape drive settings.
*/
-int tape_recal(ftu_t ftu, int totape)
+static int
+tape_recal(ftu_t ftu, int totape)
{
int s;
ft_p ft = &ft_data[ftu];
@@ -1248,7 +1499,7 @@ int tape_recal(ftu_t ftu, int totape)
s = splbio();
out_fdc(fdcu, NE7CMD_RECAL);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
if (ftintr_wait(ftu, FTCMD_RECAL, hz)) {
splx(s);
@@ -1265,18 +1516,25 @@ int tape_recal(ftu_t ftu, int totape)
return(0);
}
-static void state_timeout(caddr_t arg1, int arg2)
+
+/*
+ * Timeout for long delays.
+ */
+static void
+state_timeout(caddr_t arg1, int arg2)
{
ftu_t ftu = (ftu_t)arg1;
- wakeup((caddr_t)&ftsem.long_delay);
+ wakeup((caddr_t)wc_long_delay);
}
+
/*
* Wait for a particular tape status to be met. If all is TRUE, then
* all states must be met, otherwise any state can be met.
*/
-int tape_state(ftu_t ftu, int all, int mask, int seconds)
+static int
+tape_state(ftu_t ftu, int all, int mask, int seconds)
{
int r, tries, maxtries;
@@ -1287,20 +1545,19 @@ int tape_state(ftu_t ftu, int all, int mask, int seconds)
if (all && (r & mask) == mask) return(r);
if ((r & mask) != 0) return(r);
}
- if (seconds) {
- timeout(state_timeout, (caddr_t)ftu, hz/4);
- sleep((caddr_t)&ftsem.long_delay, FTPRI);
- }
+ if (seconds) ftsleep(wc_long_delay, hz/4);
}
DPRT(("ft%d: tape_state failed on mask=$%02x maxtries=%d\n",
ftu, mask, maxtries));
return(-1);
}
+
/*
* Send a QIC command to tape drive, wait for completion.
*/
-int tape_cmd(ftu_t ftu, int cmd)
+static int
+tape_cmd(ftu_t ftu, int cmd)
{
int newcn;
int retries = 0;
@@ -1316,7 +1573,7 @@ retry:
/* Perform seek */
s = splbio();
out_fdc(fdcu, NE7CMD_SEEK);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
out_fdc(fdcu, newcn);
if (ftintr_wait(ftu, FTCMD_SEEK, hz)) {
@@ -1338,25 +1595,40 @@ redo:
return(0);
}
+
/*
* Return status of tape drive
*/
-int tape_status(ftu_t ftu)
+static int
+tape_status(ftu_t ftu)
{
int r, err, tries;
- ft_p ft = &ft_data[ftu];
+ ft_p ft = &ft_data[ftu];
+ int max = (ft->attaching) ? 2 : 3;
- for (r = -1, tries = 0; r < 0 && tries < 3; tries++)
+ for (r = -1, tries = 0; r < 0 && tries < max; tries++)
r = qic_status(ftu, QC_STATUS, 8);
- if (tries == 3) return(-1);
+ if (tries == max) return(-1);
+
+recheck:
DPRT(("tape_status got $%04x\n",r));
ft->laststs = r;
if (r & (QS_ERROR|QS_NEWCART)) {
- if (r & QS_NEWCART) ft->newcart = 1;
err = qic_status(ftu, QC_ERRCODE, 16);
ft->lasterr = err;
- if ((r & QS_NEWCART) == 0 && err && ft->attaching == 0) {
+ if (r & QS_NEWCART) {
+ ft->newcart = 1;
+ /* If tape not referenced, do a seek load point. */
+ if ((r & QS_FMTOK) == 0 && !ft->attaching) {
+ tape_cmd(ftu, QC_SEEKLP);
+ do {
+ ftsleep(wc_long_delay, hz);
+ } while ((r = qic_status(ftu, QC_STATUS, 8)) < 0 ||
+ (r & (QS_READY|QS_CART)) == QS_CART);
+ goto recheck;
+ }
+ } else if (err && !ft->attaching) {
DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
ftu, err & 0xff, err >> 8));
}
@@ -1364,29 +1636,36 @@ int tape_status(ftu_t ftu)
ft->laststs = r;
DPRT(("tape_status got error code $%04x new sts = $%02x\n",err,r));
}
+
ft->rdonly = (r & QS_RDONLY);
return(r);
}
+
/*
* Transfer control to tape drive.
*/
-void tape_start(ftu_t ftu)
+static void
+tape_start(ftu_t ftu, int motor)
{
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
- int s;
-
- DPRT(("tape_start start\n"));
+ int s, mbits;
s = splbio();
+ DPRT(("tape_start start\n"));
/* reset, dma disable */
- outb(fdc->baseport+fdout, 0x00);
+ outb(fdc->baseport+FDOUT, 0x00);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
- /* raise reset, enable DMA */
- outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ /* raise reset, enable DMA, motor on if needed */
+ if (motor)
+ mbits = (!ftu) ? FDO_MOEN0 : FDO_MOEN1;
+ else
+ mbits = 0;
+
+ outb(fdc->baseport+FDOUT, FDO_FRST | FDO_FDMAEN | mbits);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
splx(s);
@@ -1394,16 +1673,18 @@ void tape_start(ftu_t ftu)
tape_recal(ftu, 1);
/* set transfer speed */
- outb(fdc->baseport+fdctl, FDC_500KBPS);
+ outb(fdc->baseport+FDCTL, FDC_500KBPS);
DELAY(10);
DPRT(("tape_start end\n"));
}
+
/*
* Transfer control back to floppy disks.
*/
-void tape_end(ftu_t ftu)
+static void
+tape_end(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
@@ -1415,41 +1696,59 @@ void tape_end(ftu_t ftu)
s = splbio();
/* reset, dma disable */
- outb(fdc->baseport+fdout, 0x00);
+ outb(fdc->baseport+FDOUT, 0x00);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
/* raise reset, enable DMA */
- outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ outb(fdc->baseport+FDOUT, FDO_FRST | FDO_FDMAEN);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
splx(s);
/* set transfer speed */
- outb(fdc->baseport+fdctl, FDC_500KBPS);
+ outb(fdc->baseport+FDCTL, FDC_500KBPS);
DELAY(10);
fdc->flags &= ~FDC_TAPE_BUSY;
DPRT(("tape_end end\n"));
}
+
/*
* Wait for the driver to go inactive, cancel readahead if necessary.
*/
-void tape_inactive(ftu_t ftu)
+static void
+tape_inactive(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
-
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ int s = splbio();
+
+ if (ft->segh != NULL) {
+ if (ft->segh->reqtype == FTIO_RDAHEAD) {
+ /* cancel read-ahead */
+ ft->segh->reqcan = 1;
+ } else if (ft->segh->reqtype == FTIO_WRITING && !ft->active) {
+ /* flush out any remaining writes */
+ DPRT(("Flushing write I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->segh->reqblk;
+ ft->xseg = ft->segh->reqseg;
+ ft->xcnt = 0;
+ ft->xptr = ft->segh->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
+ }
}
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ while (ft->active) ftsleep(wc_iosts_change, 0);
+ splx(s);
}
+
/*
* Get the geometry of the tape currently in the drive.
*/
-int ftgetgeom(ftu_t ftu)
+static int
+ftgetgeom(ftu_t ftu)
{
int r, i, tries;
int cfg, qic80, ext;
@@ -1459,7 +1758,7 @@ int ftgetgeom(ftu_t ftu)
r = tape_status(ftu);
/* XXX fix me when format mode is finished */
- if ((r & QS_CART) == 0 || (r & QS_FMTOK) == 0) {
+ if (r < 0 || (r & QS_CART) == 0 || (r & QS_FMTOK) == 0) {
DPRT(("ftgetgeom: no cart or not formatted 0x%04x\n",r));
ftg = NULL;
ft->newcart = 1;
@@ -1539,20 +1838,21 @@ int ftgetgeom(ftu_t ftu)
return(0);
}
+
/*
* Switch between tape/floppy. This will send the tape enable/disable
* codes for this drive's manufacturer.
*/
-int set_fdcmode(dev_t dev, int newmode)
+static int
+set_fdcmode(dev_t dev, int newmode)
{
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
-
static int havebufs = 0;
void *buf;
int r, s, i;
- SegReq *sp;
+ SegReq *sp, *rsp;
if (newmode == FDC_TAPE_MODE) {
/* Wake up the tape drive */
@@ -1560,19 +1860,22 @@ int set_fdcmode(dev_t dev, int newmode)
case NO_TYPE:
fdc->flags &= ~FDC_TAPE_BUSY;
return(ENXIO);
+ case FT_NONE:
+ tape_start(ftu, 0);
+ break;
case FT_COLORADO:
- tape_start(ftu);
+ tape_start(ftu, 0);
if (tape_cmd(ftu, QC_COL_ENABLE1)) {
tape_end(ftu);
return(EIO);
}
- if (tape_cmd(ftu, QC_COL_ENABLE2)) {
+ if (tape_cmd(ftu, QC_COL_ENABLE2 + ftu)) {
tape_end(ftu);
return(EIO);
}
break;
case FT_MOUNTAIN:
- tape_start(ftu);
+ tape_start(ftu, 0);
if (tape_cmd(ftu, QC_MTN_ENABLE1)) {
tape_end(ftu);
return(EIO);
@@ -1582,56 +1885,93 @@ int set_fdcmode(dev_t dev, int newmode)
return(EIO);
}
break;
+ case FT_INSIGHT:
+ tape_start(ftu, 1);
+ break;
default:
DPRT(("ft%d: bad tape type\n", ftu));
return(ENXIO);
}
if (tape_status(ftu) < 0) {
- tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
tape_end(ftu);
return(EIO);
}
/* Grab buffers from memory. */
if (!havebufs) {
- ft->curseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
- if (ft->curseg == NULL) {
- printf("ft%d: not enough memory for buffers\n", ftu);
- return(ENOMEM);
- }
- ft->bufseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
- if (ft->bufseg == NULL) {
- free(ft->curseg, M_DEVBUF);
- printf("ft%d: not enough memory for buffers\n", ftu);
- return(ENOMEM);
+ ft->segh = ft->segt = NULL;
+ ft->doneh = ft->donet = NULL;
+ ft->segfree = NULL;
+ ft->hdr = NULL;
+ ft->nsegq = ft->ndoneq = ft->nfreelist = 0;
+ for (i = 0; i < FTNBUFF; i++) {
+ sp = malloc(sizeof(SegReq), M_DEVBUF, M_WAITOK);
+ if (sp == NULL) {
+ printf("ft%d: not enough memory for buffers\n", ftu);
+ for (sp=ft->segfree; sp != NULL; sp=sp->next)
+ free(sp, M_DEVBUF);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
+ tape_end(ftu);
+ return(ENOMEM);
+ }
+ sp->reqtype = FTIO_READY;
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
}
+ /* take one buffer for header */
+ ft->hdr = ft->segfree;
+ ft->segfree = ft->segfree->next;
+ ft->nfreelist--;
havebufs = 1;
}
- ft->curseg->reqtype = FTIO_READY;
- ft->bufseg->reqtype = FTIO_READY;
ft->io_sts = FTIO_READY; /* tape drive is ready */
ft->active = 0; /* interrupt driver not active */
ft->moving = 0; /* tape not moving */
ft->rdonly = 0; /* tape read only */
- ft->newcart = 0; /* a new cart was inserted */
+ ft->newcart = 0; /* new cartridge flag */
ft->lastpos = -1; /* tape is rewound */
+ async_func = ACMD_NONE; /* No async function */
tape_state(ftu, 0, QS_READY, 60);
tape_cmd(ftu, QC_RATE);
tape_cmd(ftu, QCF_RT500+2); /* 500K bps */
tape_state(ftu, 0, QS_READY, 60);
ft->mode = FTM_PRIMARY;
- tape_cmd(ftu, QC_PRIMARY); /* Make sure we're in primary mode */
+ tape_cmd(ftu, QC_PRIMARY); /* Make sure we're in primary mode */
tape_state(ftu, 0, QS_READY, 60);
ftg = NULL; /* No geometry yet */
ftgetgeom(ftu); /* Get tape geometry */
ftreq_rewind(ftu); /* Make sure tape is rewound */
} else {
- tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
tape_end(ftu);
ft->newcart = 0; /* clear new cartridge */
+ if (ft->hdr != NULL) free(ft->hdr, M_DEVBUF);
+ if (havebufs) {
+ for (sp = ft->segfree; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ for (sp = ft->segh; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ for (sp = ft->doneh; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ }
havebufs = 0;
- free(ft->curseg, M_DEVBUF);
- free(ft->bufseg, M_DEVBUF);
}
return(0);
}
@@ -1640,7 +1980,8 @@ int set_fdcmode(dev_t dev, int newmode)
/*
* Perform a QIC status function.
*/
-int qic_status(ftu_t ftu, int cmd, int nbits)
+static int
+qic_status(ftu_t ftu, int cmd, int nbits)
{
int st3, val, r, i;
ft_p ft = &ft_data[ftu];
@@ -1653,7 +1994,7 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
/* Sense drive status */
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if ((st3 & 0x10) == 0) { /* track 0 */
@@ -1668,7 +2009,7 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
}
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if (st3 < 0) {
DPRT(("ft%d: controller timed out on bit %d r=$%02x\n",
@@ -1690,11 +2031,13 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
return(r);
}
+
/*
* Open tape drive for use. Bounced off of Fdopen if tape minor is
* detected.
*/
-int ftopen(dev_t dev, int arg2) {
+int
+ftopen(dev_t dev, int arg2) {
ftu_t ftu = FDUNIT(minor(dev));
int type = FDTYPE(minor(dev));
fdc_p fdc;
@@ -1714,19 +2057,21 @@ int ftopen(dev_t dev, int arg2) {
return(set_fdcmode(dev, FDC_TAPE_MODE)); /* try to switch to tape */
}
+
/*
* Close tape and return floppy controller to disk mode.
*/
-int ftclose(dev_t dev, int flags)
+int
+ftclose(dev_t dev, int flags)
{
int s;
SegReq *sp;
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
+
/* Wait for any remaining I/O activity to complete. */
- if (ft->curseg->reqtype == FTIO_RDAHEAD) ft->curseg->reqcan = 1;
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
ft->mode = FTM_PRIMARY;
tape_cmd(ftu, QC_PRIMARY);
@@ -1735,94 +2080,124 @@ int ftclose(dev_t dev, int flags)
return(set_fdcmode(dev, FDC_DISK_MODE)); /* Otherwise, close tape */
}
+
/*
- * Perform strategy on a given buffer (not!). The driver was not
- * performing very efficiently using the buffering routines. After
- * support for error correction was added, this routine became
- * obsolete in favor of doing ioctl's. Ugly, yes.
+ * Perform strategy on a given buffer (not!). Changed so that the
+ * driver will at least return 'Operation not supported'.
*/
-void ftstrategy(struct buf *bp)
+void
+ftstrategy(struct buf *bp)
{
- return;
+ bp->b_error = ENODEV;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
}
-/* Read or write a segment. */
-int ftreq_rw(ftu_t ftu, int cmd, QIC_Segment *sr, struct proc *p)
+
+/*
+ * Read or write a segment.
+ */
+static int
+ftreq_rw(ftu_t ftu, int cmd, QIC_Segment *sr, struct proc *p)
{
int r, i, j;
SegReq *sp;
int s;
- long blk, bad;
+ long blk, bad, seg;
unsigned char *cp, *cp2;
ft_p ft = &ft_data[ftu];
- if (!ft->active) {
+ if (!ft->active && ft->segh == NULL) {
r = tape_status(ftu);
- if ((r & QS_CART) == 0) {
+ if ((r & QS_CART) == 0)
return(ENXIO); /* No cartridge */
- }
- if ((r & QS_FMTOK) == 0) {
+ if ((r & QS_FMTOK) == 0)
return(ENXIO); /* Not formatted */
- }
tape_state(ftu, 0, QS_READY, 90);
}
if (ftg == NULL || ft->newcart) {
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
tape_state(ftu, 0, QS_READY, 90);
- if (ftgetgeom(ftu) < 0) {
+ if (ftgetgeom(ftu) < 0)
return(ENXIO);
- }
}
/* Write not allowed on a read-only tape. */
- if (cmd == QIOWRITE && ft->rdonly) {
+ if (cmd == QIOWRITE && ft->rdonly)
return(EROFS);
- }
+
/* Quick check of request and buffer. */
- if (sr == NULL || sr->sg_data == NULL) {
+ if (sr == NULL || sr->sg_data == NULL)
return(EINVAL);
- }
- if (sr->sg_trk >= ftg->g_trktape ||
- sr->sg_seg >= ftg->g_segtrk) {
+
+ /* Make sure requested track and segment is in range. */
+ if (sr->sg_trk >= ftg->g_trktape || sr->sg_seg >= ftg->g_segtrk)
return(EINVAL);
- }
+
blk = sr->sg_trk * ftg->g_blktrk + sr->sg_seg * QCV_BLKSEG;
+ seg = sr->sg_trk * ftg->g_segtrk + sr->sg_seg;
s = splbio();
if (cmd == QIOREAD) {
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- if (blk == ft->curseg->reqblk) {
- sp = ft->curseg;
+ /*
+ * See if the driver is reading ahead.
+ */
+ if (ft->doneh != NULL ||
+ (ft->segh != NULL && ft->segh->reqtype == FTIO_RDAHEAD)) {
+ /*
+ * Eat the completion queue and see if the request
+ * is already there.
+ */
+ while (ft->doneh != NULL) {
+ if (blk == ft->doneh->reqblk) {
+ sp = ft->doneh;
+ sp->reqtype = FTIO_READING;
+ sp->reqbad = sr->sg_badmap;
+ goto rddone;
+ }
+ segio_free(ft, ft->doneh);
+ }
+
+ /*
+ * Not on the completed queue, in progress maybe?
+ */
+ if (ft->segh != NULL && ft->segh->reqtype == FTIO_RDAHEAD &&
+ blk == ft->segh->reqblk) {
+ sp = ft->segh;
sp->reqtype = FTIO_READING;
sp->reqbad = sr->sg_badmap;
goto rdwait;
- } else
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
+ }
}
/* Wait until we're ready. */
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
/* Set up a new read request. */
- sp = ft->curseg;
+ sp = segio_alloc(ft);
sp->reqcrc = 0;
sp->reqbad = sr->sg_badmap;
sp->reqblk = blk;
+ sp->reqseg = seg;
sp->reqcan = 0;
sp->reqtype = FTIO_READING;
+ segio_queue(ft, sp);
/* Start the read request off. */
DPRT(("Starting read I/O chain\n"));
arq_state = ard_state = awr_state = 0;
ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
ft->xptr = sp->buff;
ft->active = 1;
timeout(ft_timeout, (caddr_t)ftu, 1);
rdwait:
- sleep((caddr_t)&ftsem.buff_avail, FTPRI);
+ ftsleep(wc_buff_done, 0);
+
+rddone:
bad = sp->reqbad;
sr->sg_crcmap = sp->reqcrc & ~bad;
@@ -1833,17 +2208,29 @@ rdwait:
copyout(cp, cp2, QCV_BLKSIZE);
cp2 += QCV_BLKSIZE;
}
+ segio_free(ft, sp);
} else {
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
- while (ft->active)
- sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ if (ft->segh != NULL && ft->segh->reqtype != FTIO_WRITING)
+ tape_inactive(ftu);
+
+ /* Allocate a buffer and start tape if we're running low. */
+ sp = segio_alloc(ft);
+ if (!ft->active && (sp == NULL || ft->nfreelist <= 1)) {
+ DPRT(("Starting write I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->segh->reqblk;
+ ft->xseg = ft->segh->reqseg;
+ ft->xcnt = 0;
+ ft->xptr = ft->segh->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
}
/* Sleep until a buffer becomes available. */
- while (ft->bufseg->reqtype != FTIO_READY)
- sleep((caddr_t)&ftsem.buff_avail, FTPRI);
- sp = (ft->curseg->reqtype == FTIO_READY) ? ft->curseg : ft->bufseg;
+ while (sp == NULL) {
+ ftsleep(wc_buff_avail, 0);
+ sp = segio_alloc(ft);
+ }
/* Copy in segment and expand bad blocks. */
bad = sr->sg_badmap;
@@ -1853,28 +2240,22 @@ rdwait:
copyin(cp, cp2, QCV_BLKSIZE);
cp += QCV_BLKSIZE;
}
-
sp->reqblk = blk;
+ sp->reqseg = seg;
sp->reqcan = 0;
sp->reqtype = FTIO_WRITING;
-
- if (!ft->active) {
- DPRT(("Starting write I/O chain\n"));
- arq_state = ard_state = awr_state = 0;
- ft->xblk = sp->reqblk;
- ft->xcnt = 0;
- ft->xptr = sp->buff;
- ft->active = 1;
- timeout(ft_timeout, (caddr_t)ftu, 1);
- }
+ segio_queue(ft, sp);
}
splx(s);
return(0);
}
-/* Rewind to beginning of tape */
-int ftreq_rewind(ftu_t ftu)
+/*
+ * Rewind to beginning of tape
+ */
+static int
+ftreq_rewind(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
@@ -1891,8 +2272,12 @@ int ftreq_rewind(ftu_t ftu)
return(0);
}
-/* Move to logical beginning or end of track */
-int ftreq_trkpos(ftu_t ftu, int req)
+
+/*
+ * Move to logical beginning or end of track
+ */
+static int
+ftreq_trkpos(ftu_t ftu, int req)
{
int curtrk, r, cmd;
ft_p ft = &ft_data[ftu];
@@ -1919,8 +2304,12 @@ int ftreq_trkpos(ftu_t ftu, int req)
return(0);
}
-/* Seek tape head to a particular track. */
-int ftreq_trkset(ftu_t ftu, int *trk)
+
+/*
+ * Seek tape head to a particular track.
+ */
+static int
+ftreq_trkset(ftu_t ftu, int *trk)
{
int curtrk, r, cmd;
ft_p ft = &ft_data[ftu];
@@ -1942,27 +2331,45 @@ int ftreq_trkset(ftu_t ftu, int *trk)
return(0);
}
-/* Start tape moving forward. */
-int ftreq_lfwd(ftu_t ftu)
+
+/*
+ * Start tape moving forward.
+ */
+static int
+ftreq_lfwd(ftu_t ftu)
{
+ ft_p ft = &ft_data[ftu];
+
tape_inactive(ftu);
tape_cmd(ftu, QC_STOP);
tape_state(ftu, 0, QS_READY, 90);
tape_cmd(ftu, QC_FORWARD);
+ ft->moving = 1;
return(0);
}
-/* Stop the tape */
-int ftreq_stop(ftu_t ftu)
+
+/*
+ * Stop the tape
+ */
+static int
+ftreq_stop(ftu_t ftu)
{
+ ft_p ft = &ft_data[ftu];
+
tape_inactive(ftu);
tape_cmd(ftu, QC_STOP);
tape_state(ftu, 0, QS_READY, 90);
+ ft->moving = 0;
return(0);
}
-/* Set the particular mode the drive should be in. */
-int ftreq_setmode(ftu_t ftu, int cmd)
+
+/*
+ * Set the particular mode the drive should be in.
+ */
+static int
+ftreq_setmode(ftu_t ftu, int cmd)
{
int r;
ft_p ft = &ft_data[ftu];
@@ -1989,8 +2396,12 @@ int ftreq_setmode(ftu_t ftu, int cmd)
return(0);
}
-/* Return drive status bits */
-int ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
+
+/*
+ * Return drive status bits
+ */
+static int
+ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
{
ft_p ft = &ft_data[ftu];
@@ -2001,8 +2412,12 @@ int ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
return(0);
}
-/* Return drive configuration bits */
-int ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
+
+/*
+ * Return drive configuration bits
+ */
+static int
+ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
{
int r, tries;
ft_p ft = &ft_data[ftu];
@@ -2018,8 +2433,12 @@ int ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
return(0);
}
-/* Return current tape's geometry. */
-int ftreq_geom(ftu_t ftu, QIC_Geom *g)
+
+/*
+ * Return current tape's geometry.
+ */
+static int
+ftreq_geom(ftu_t ftu, QIC_Geom *g)
{
tape_inactive(ftu);
if (ftg == NULL && ftgetgeom(ftu) < 0) return(ENXIO);
@@ -2027,8 +2446,12 @@ int ftreq_geom(ftu_t ftu, QIC_Geom *g)
return(0);
}
-/* Return drive hardware information */
-int ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
+
+/*
+ * Return drive hardware information
+ */
+static int
+ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
{
int r, tries;
int rom, vend;
@@ -2053,10 +2476,31 @@ int ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
return(0);
}
+
+/*
+ * Receive or Send the in-core header segment.
+ */
+static int
+ftreq_hdr(ftu_t ftu, int cmd, QIC_Segment *sp)
+{
+ ft_p ft = &ft_data[ftu];
+ QIC_Header *h = (QIC_Header *)ft->hdr->buff;
+
+ if (sp == NULL || sp->sg_data == NULL) return(EINVAL);
+ if (cmd == QIOSENDHDR) {
+ copyin(sp->sg_data, ft->hdr->buff, QCV_SEGSIZE);
+ } else {
+ if (h->qh_sig != QCV_HDRMAGIC) return(EIO);
+ copyout(ft->hdr->buff, sp->sg_data, QCV_SEGSIZE);
+ }
+ return(0);
+}
+
/*
* I/O functions.
*/
-int ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+int
+ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
@@ -2104,20 +2548,30 @@ int ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case QIOHWINFO:
return(ftreq_hwinfo(ftu, (QIC_HWInfo *)data));
+
+ case QIOSENDHDR:
+ case QIORECVHDR:
+ return(ftreq_hdr(ftu, cmd, (QIC_Segment *)data));
}
badreq:
DPRT(("ft%d: unknown ioctl(%d) request\n", ftu, cmd));
return(ENXIO);
}
-/* Not implemented */
-int ftdump(dev_t dev)
+/*
+ * Not implemented
+ */
+int
+ftdump(dev_t dev)
{
return(EINVAL);
}
-/* Not implemented */
-int ftsize(dev_t dev)
+/*
+ * Not implemented
+ */
+int
+ftsize(dev_t dev)
{
return(EINVAL);
}
diff --git a/sys/i386/isa/ftreg.h b/sys/i386/isa/ftreg.h
index 7b4ca6a27236..c29540ce0a96 100644
--- a/sys/i386/isa/ftreg.h
+++ b/sys/i386/isa/ftreg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Steve Gerakines
+ * Copyright (c) 1993, 1994 Steve Gerakines
*
* This is freely redistributable software. You may do anything you
* wish with it, so long as the above notice stays intact.
@@ -17,6 +17,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* ftreg.h - QIC-40/80 floppy tape driver header
+ * 06/03/94 v0.9
+ * Changed seek load point to QC_SEEKLP, added reqseg to SegReq structure.
+ *
* 10/30/93 v0.3
* More things will end up here. QC_VENDORID and QC_VERSION now used.
*
@@ -42,7 +45,7 @@
#define QC_SEEKSTART 11 /* seek to track start */
#define QC_SEEKEND 12 /* seek to track end */
#define QC_SEEKTRACK 13 /* seek head to track */
-#define QC_SEEKLOAD 14 /* seek load point */
+#define QC_SEEKLP 14 /* seek load point */
#define QC_FORMAT 15 /* format mode */
#define QC_WRITEREF 16 /* write reference */
#define QC_VERIFY 17 /* verify mode */
@@ -62,7 +65,7 @@
/* Colorado enable/disable. */
#define QC_COL_ENABLE1 46 /* enable */
-#define QC_COL_ENABLE2 2 /* null-op */
+#define QC_COL_ENABLE2 2 /* unit+2 */
#define QC_COL_DISABLE 47 /* disable */
/* Mountain enable/disable. */
@@ -77,5 +80,7 @@ typedef struct segq {
long reqcrc; /* CRC Errors found */
long reqbad; /* Bad sector map */
long reqblk; /* Block request starts at */
+ long reqseg; /* Segment request is at */
int reqcan; /* Cancel read-ahead */
+ struct segq *next; /* Next request */
} SegReq;
diff --git a/sys/i386/isa/ic/i82365.h b/sys/i386/isa/ic/i82365.h
new file mode 100644
index 000000000000..ab381250ea72
--- /dev/null
+++ b/sys/i386/isa/ic/i82365.h
@@ -0,0 +1,190 @@
+#ifndef __83265_H__
+#define __83265_H__
+
+/***********************************************************************
+ * 82365.h -- information necessary for direct manipulation of PCMCIA
+ * cards and controllers
+ *
+ * Support is included for Intel 82365SL PCIC controllers and clones
+ * thereof.
+ *
+ * originally by Barry Jaspan; hacked over by Keith Moore
+ *
+ ***********************************************************************/
+
+/*
+ * PCIC Registers
+ * Each register is given a name, and most of the bits are named too.
+ * I should really name them all.
+ *
+ * Finally, since the banks can be addressed with a regular syntax,
+ * some macros are provided for that purpose.
+ */
+
+#define PCIC_BASE 0x03e0 /* base adddress of pcic register set */
+
+/* First, all the registers */
+#define PCIC_ID_REV 0x00 /* Identification and Revision */
+#define PCIC_STATUS 0x01 /* Interface Status */
+#define PCIC_POWER 0x02 /* Power and RESETDRV control */
+#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */
+#define PCIC_STAT_CHG 0x04 /* Card Status Change */
+#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */
+#define PCIC_ADDRWINE 0x06 /* Address Window Enable */
+#define PCIC_IOCTL 0x07 /* I/O Control */
+#define PCIC_IO0_STL 0x08 /* I/O Address 0 Start Low Byte */
+#define PCIC_IO0_STH 0x09 /* I/O Address 0 Start High Byte */
+#define PCIC_IO0_SPL 0x0a /* I/O Address 0 Stop Low Byte */
+#define PCIC_IO0_SPH 0x0b /* I/O Address 0 Stop High Byte */
+#define PCIC_IO1_STL 0x0c /* I/O Address 1 Start Low Byte */
+#define PCIC_IO1_STH 0x0d /* I/O Address 1 Start High Byte */
+#define PCIC_IO1_SPL 0x0e /* I/O Address 1 Stop Low Byte */
+#define PCIC_IO1_SPH 0x0f /* I/O Address 1 Stop High Byte */
+#define PCIC_SM0_STL 0x10 /* System Memory Address 0 Mapping Start Low Byte */
+#define PCIC_SM0_STH 0x11 /* System Memory Address 0 Mapping Start High Byte */
+#define PCIC_SM0_SPL 0x12 /* System Memory Address 0 Mapping Stop Low Byte */
+#define PCIC_SM0_SPH 0x13 /* System Memory Address 0 Mapping Stop High Byte */
+#define PCIC_CM0_L 0x14 /* Card Memory Offset Address 0 Low Byte */
+#define PCIC_CM0_H 0x15 /* Card Memory Offset Address 0 High Byte */
+#define PCIC_CDGC 0x16 /* Card Detect and General Control */
+#define PCIC_RES17 0x17 /* Reserved */
+#define PCIC_SM1_STL 0x18 /* System Memory Address 1 Mapping Start Low Byte */
+#define PCIC_SM1_STH 0x19 /* System Memory Address 1 Mapping Start High Byte */
+#define PCIC_SM1_SPL 0x1a /* System Memory Address 1 Mapping Stop Low Byte */
+#define PCIC_SM1_SPH 0x1b /* System Memory Address 1 Mapping Stop High Byte */
+#define PCIC_CM1_L 0x1c /* Card Memory Offset Address 1 Low Byte */
+#define PCIC_CM1_H 0x1d /* Card Memory Offset Address 1 High Byte */
+#define PCIC_GLO_CTRL 0x1e /* Global Control Register */
+#define PCIC_RES1F 0x1f /* Reserved */
+#define PCIC_SM2_STL 0x20 /* System Memory Address 2 Mapping Start Low Byte */
+#define PCIC_SM2_STH 0x21 /* System Memory Address 2 Mapping Start High Byte */
+#define PCIC_SM2_SPL 0x22 /* System Memory Address 2 Mapping Stop Low Byte */
+#define PCIC_SM2_SPH 0x23 /* System Memory Address 2 Mapping Stop High Byte */
+#define PCIC_CM2_L 0x24 /* Card Memory Offset Address 2 Low Byte */
+#define PCIC_CM2_H 0x25 /* Card Memory Offset Address 2 High Byte */
+#define PCIC_RES26 0x26 /* Reserved */
+#define PCIC_RES27 0x27 /* Reserved */
+#define PCIC_SM3_STL 0x28 /* System Memory Address 3 Mapping Start Low Byte */
+#define PCIC_SM3_STH 0x29 /* System Memory Address 3 Mapping Start High Byte */
+#define PCIC_SM3_SPL 0x2a /* System Memory Address 3 Mapping Stop Low Byte */
+#define PCIC_SM3_SPH 0x2b /* System Memory Address 3 Mapping Stop High Byte */
+#define PCIC_CM3_L 0x2c /* Card Memory Offset Address 3 Low Byte */
+#define PCIC_CM3_H 0x2d /* Card Memory Offset Address 3 High Byte */
+#define PCIC_RES2E 0x2e /* Reserved */
+#define PCIC_RES2F 0x2f /* Reserved */
+#define PCIC_SM4_STL 0x30 /* System Memory Address 4 Mapping Start Low Byte */
+#define PCIC_SM4_STH 0x31 /* System Memory Address 4 Mapping Start High Byte */
+#define PCIC_SM4_SPL 0x32 /* System Memory Address 4 Mapping Stop Low Byte */
+#define PCIC_SM4_SPH 0x33 /* System Memory Address 4 Mapping Stop High Byte */
+#define PCIC_CM4_L 0x34 /* Card Memory Offset Address 4 Low Byte */
+#define PCIC_CM4_H 0x35 /* Card Memory Offset Address 4 High Byte */
+#define PCIC_RES36 0x36 /* Reserved */
+#define PCIC_RES37 0x37 /* Reserved */
+#define PCIC_RES38 0x38 /* Reserved */
+#define PCIC_RES39 0x39 /* Reserved */
+#define PCIC_RES3A 0x3a /* Reserved */
+#define PCIC_RES3B 0x3b /* Reserved */
+#define PCIC_RES3C 0x3c /* Reserved */
+#define PCIC_RES3D 0x3d /* Reserved */
+#define PCIC_RES3E 0x3e /* Reserved */
+#define PCIC_RES3F 0x3f /* Reserved */
+
+/* Now register bits, ordered by reg # */
+
+/* For Identification and Revision (PCIC_ID_REV) */
+#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */
+#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */
+#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */
+#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */
+
+/* For Interface Status register (PCIC_STATUS) */
+#define PCIC_VPPV 0x80 /* Vpp_valid */
+#define PCIC_POW 0x40 /* PC Card power active */
+#define PCIC_READY 0x20 /* Ready/~Busy */
+#define PCIC_MWP 0x10 /* Memory Write Protect */
+#define PCIC_CD 0x0C /* Both card detect bits */
+#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */
+
+/* For the Power and RESETDRV register (PCIC_POWER) */
+#define PCIC_OUTENA 0x80 /* Output Enable */
+#define PCIC_DISRST 0x40 /* Disable RESETDRV */
+#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */
+#define PCIC_PCPWRE 0x10 /* PC Card Power Enable */
+
+/* For the Interrupt and General Control register (PCIC_INT_GEN) */
+#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */
+#define PCIC_IOCARD 0x20
+#define PCIC_MEMCARD 0x00
+#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */
+
+/* For the Card Status Change register (PCIC_STAT_CHG) */
+#define PCIC_CDTCH 0x08 /* Card Detect Change */
+#define PCIC_RDYCH 0x04 /* Ready Change */
+#define PCIC_BATWRN 0x02 /* Battery Warning */
+#define PCIC_BATDED 0x01 /* Battery Dead */
+
+/* For the Address Window Enable Register (PCIC_ADDRWINE) */
+#define PCIC_SM0_EN 0x01 /* Memory Window 0 Enable */
+#define PCIC_SM1_EN 0x02 /* Memory Window 1 Enable */
+#define PCIC_SM2_EN 0x04 /* Memory Window 2 Enable */
+#define PCIC_SM3_EN 0x08 /* Memory Window 3 Enable */
+#define PCIC_SM4_EN 0x10 /* Memory Window 4 Enable */
+#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */
+#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */
+#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */
+
+/* For the I/O Control Register (PCIC_IOCTL) */
+#define PCIC_IO0_16BIT 0x01 /* I/O to this segment is 16 bit */
+#define PCIC_IO0_CS16 0x02 /* I/O cs16 source is the card */
+#define PCIC_IO0_0WS 0x04 /* zero wait states added on 8 bit cycles */
+#define PCIC_IO0_WS 0x08 /* Wait states added for 16 bit cycles */
+#define PCIC_IO1_16BIT 0x10 /* I/O to this segment is 16 bit */
+#define PCIC_IO1_CS16 0x20 /* I/O cs16 source is the card */
+#define PCIC_IO1_0WS 0x04 /* zero wait states added on 8 bit cycles */
+#define PCIC_IO1_WS 0x80 /* Wait states added for 16 bit cycles */
+
+/* For the various I/O and Memory windows */
+#define PCIC_ADDR_LOW 0
+#define PCIC_ADDR_HIGH 1
+#define PCIC_START 0x00 /* Start of mapping region */
+#define PCIC_END 0x02 /* End of mapping region */
+#define PCIC_MOFF 0x04 /* Card Memory Mapping region offset */
+#define PCIC_IO0 0x08 /* I/O Address 0 */
+#define PCIC_IO1 0x0c /* I/O Address 1 */
+#define PCIC_SM0 0x10 /* System Memory Address 0 Mapping */
+#define PCIC_SM1 0x18 /* System Memory Address 1 Mapping */
+#define PCIC_SM2 0x20 /* System Memory Address 2 Mapping */
+#define PCIC_SM3 0x28 /* System Memory Address 3 Mapping */
+#define PCIC_SM4 0x30 /* System Memory Address 4 Mapping */
+
+/* For System Memory Window start registers
+ (PCIC_SMx|PCIC_START|PCIC_ADDR_HIGH) */
+#define PCIC_ZEROWS 0x40 /* Zero wait states */
+#define PCIC_DATA16 0x80 /* Data width is 16 bits */
+
+/* For System Memory Window stop registers
+ (PCIC_SMx|PCIC_END|PCIC_ADDR_HIGH) */
+#define PCIC_MW0 0x40 /* Wait state bit 0 */
+#define PCIC_MW1 0x80 /* Wait state bit 1 */
+
+/* For System Memory Window offset registers
+ (PCIC_SMx|PCIC_MOFF|PCIC_ADDR_HIGH) */
+#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */
+#define PCIC_WP 0x80 /* Write-protect this window */
+
+/* For Card Detect and General Control register (PCIC_CDGC) */
+#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */
+#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */
+#define PCIC_GPI_EN 0x04 /* GPI Enable */
+#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */
+#define PCIC_CDRES_EN 0x10 /* card detect resume enable */
+#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */
+
+/* For Global Control register (PCIC_GLO_CTRL) */
+#define PCIC_PWR_DOWN 0x01 /* power down */
+#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */
+#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */
+#define PCIC_IRQ14_PULSE 0x08 /* irq 14 pulse mode enable */
+
+/* DON'T ADD ANYTHING AFTER THIS #endif */
+#endif /* __83265_H__ */
diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h
index df6c337482aa..c02e6ef362ba 100644
--- a/sys/i386/isa/ic/nec765.h
+++ b/sys/i386/isa/ic/nec765.h
@@ -30,8 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
- * $Id: nec765.h,v 1.2 1993/10/16 13:48:50 rgrimes Exp $
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
*/
/*
@@ -47,26 +46,90 @@
#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
/* Status register ST0 */
-#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005equ_chck\004drive_notrdy\003top_head"
+
+#define NE7_ST0_IC 0xc0 /* interrupt completion code */
+
+#define NE7_ST0_IC_RC 0xc0 /* terminated due to ready changed, n/a */
+#define NE7_ST0_IC_IV 0x80 /* invalid command; must reset FDC */
+#define NE7_ST0_IC_AT 0x40 /* abnormal termination, check error stat */
+#define NE7_ST0_IC_NT 0x00 /* normal termination */
+
+#define NE7_ST0_SE 0x20 /* seek end */
+#define NE7_ST0_EC 0x10 /* equipment check, recalibrated but no trk0 */
+#define NE7_ST0_NR 0x08 /* not ready (n/a) */
+#define NE7_ST0_HD 0x04 /* upper head selected */
+#define NE7_ST0_DR 0x03 /* drive code */
/* Status register ST1 */
#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+#define NE7_ST1_EN 0x80 /* end of cylinder, access past last record */
+#define NE7_ST1_DE 0x20 /* data error, CRC fail in ID or data */
+#define NE7_ST1_OR 0x10 /* DMA overrun, DMA failed to do i/o quickly */
+#define NE7_ST1_ND 0x04 /* no data, sector not found or CRC in ID f. */
+#define NE7_ST1_NW 0x02 /* not writeable, attempt to violate WP */
+#define NE7_ST1_MA 0x01 /* missing address mark (in ID or data field)*/
+
/* Status register ST2 */
#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+#define NE7_ST2_CM 0x40 /* control mark; found deleted data */
+#define NE7_ST2_DD 0x20 /* data error in data field, CRC fail */
+#define NE7_ST2_WC 0x10 /* wrong cylinder, ID field mismatches cmd */
+#define NE7_ST2_SH 0x08 /* scan equal hit */
+#define NE7_ST2_SN 0x04 /* scan not satisfied */
+#define NE7_ST2_BC 0x02 /* bad cylinder, cylinder marked 0xff */
+#define NE7_ST2_MD 0x01 /* missing address mark in data field */
+
/* Status register ST3 */
#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+#define NE7_ST3_FT 0x80 /* fault; PC: n/a */
+#define NE7_ST3_WP 0x40 /* write protected */
+#define NE7_ST3_RD 0x20 /* ready; PC: always true */
+#define NE7_ST3_T0 0x10 /* track 0 */
+#define NE7_ST3_TS 0x08 /* two-sided; PC: n/a */
+#define NE7_ST3_HD 0x04 /* upper head select */
+#define NE7_ST3_US 0x03 /* unit select */
+
/* Commands */
+/*
+ * the top three bits -- where appropriate -- are set as follows:
+ *
+ * 0x80 - MT multi-track; allow both sides to be handled in single cmd
+ * 0x40 - MFM modified frequency modulation; use MFM encoding
+ * 0x20 - SK skip; skip sectors marked as "deleted"
+ */
+#define NE7CMD_READTRK 0x42 /* read whole track */
#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
parameters byte */
#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
-#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
#define NE7CMD_RECAL 7 /* recalibrate drive - requires
unit select byte */
#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
-#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+#define NE7CMD_WRITEDEL 0xc9 /* write deleted data */
+#define NE7CMD_READID 0x4a /* read ID field */
+#define NE7CMD_READDEL 0xec /* read deleted data */
+#define NE7CMD_FORMAT 0x4d /* format - requires five additional bytes */
+#define NE7CMD_SEEK 0x0f /* seek drive - requires unit select byte
and new cyl byte */
+#define NE7CMD_SCNEQU 0xf1 /* scan equal */
+#define NE7CMD_SCNLE 0xf9 /* scan less or equal */
+#define NE7CMD_SCNGE 0xfd /* scan greater or equal */
+
+
+/*
+ * "specify" definitions
+ *
+ * acronyms (times are relative to a FDC clock of 8 MHz):
+ * srt - step rate; PC usually 3 ms
+ * hut - head unload time; PC usually maximum of 240 ms
+ * hlt - head load time; PC usually minimum of 2 ms
+ * nd - no DMA flag; PC usually not set (0)
+ */
+
+#define NE7_SPEC_1(srt, hut) (((16 - (srt)) << 4) | (((hut) / 16)))
+#define NE7_SPEC_2(hlt, nd) (((hlt) & 0xFE) | ((nd) & 1))
diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h
index af50335f4468..523f3351a859 100644
--- a/sys/i386/isa/icu.h
+++ b/sys/i386/isa/icu.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)icu.h 5.6 (Berkeley) 5/9/91
- * $Id: icu.h,v 1.2 1993/10/16 13:45:51 rgrimes Exp $
+ * $Id: icu.h,v 1.3 1994/04/02 07:00:40 davidg Exp $
*/
/*
@@ -51,12 +51,6 @@
* Interrupt "level" mechanism variables, masks, and macros
*/
extern unsigned imen; /* interrupt mask enable */
-extern unsigned cpl; /* current priority level mask */
-
-extern unsigned highmask; /* group of interrupts masked with splhigh() */
-extern unsigned ttymask; /* group of interrupts masked with spltty() */
-extern unsigned biomask; /* group of interrupts masked with splbio() */
-extern unsigned netmask; /* group of interrupts masked with splimp() */
#define INTREN(s) (imen &= ~(s), SET_ICUS())
#define INTRDIS(s) (imen |= (s), SET_ICUS())
@@ -74,7 +68,7 @@ extern unsigned netmask; /* group of interrupts masked with splimp() */
#endif
/*
- * Interrupt enable bits -- in order of priority
+ * Interrupt enable bits - in normal order of priority (which we change)
*/
#define IRQ0 0x0001 /* highest priority - timer */
#define IRQ1 0x0002
@@ -88,7 +82,7 @@ extern unsigned netmask; /* group of interrupts masked with splimp() */
#define IRQ13 0x2000
#define IRQ14 0x4000
#define IRQ15 0x8000
-#define IRQ3 0x0008
+#define IRQ3 0x0008 /* this is highest after rotation */
#define IRQ4 0x0010
#define IRQ5 0x0020
#define IRQ6 0x0040
diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s
index d1c843951b83..9484e5cdbedd 100644
--- a/sys/i386/isa/icu.s
+++ b/sys/i386/isa/icu.s
@@ -36,7 +36,7 @@
*
* @(#)icu.s 7.2 (Berkeley) 5/21/91
*
- * $Id: icu.s,v 1.7 1993/12/20 14:58:21 wollman Exp $
+ * $Id: icu.s,v 1.8 1994/04/02 07:00:41 davidg Exp $
*/
/*
@@ -45,215 +45,131 @@
*/
/*
- * XXX - this file is now misnamed. All spls are now soft and the only thing
- * related to the hardware icu is that the bit numbering is the same in the
- * soft priority masks as in the hard ones.
+ * XXX this file should be named ipl.s. All spls are now soft and the
+ * only thing related to the hardware icu is that the h/w interrupt
+ * numbers are used without translation in the masks.
*/
-#include "sio.h"
-#define HIGHMASK 0xffff
-#define SOFTCLOCKMASK 0x8000
+#include "../net/netisr.h"
.data
-
.globl _cpl
-_cpl: .long 0xffff /* current priority (all off) */
-
+_cpl: .long HWI_MASK | SWI_MASK /* current priority (all off) */
.globl _imen
-_imen: .long 0xffff /* interrupt mask enable (all off) */
-
-/* .globl _highmask */
-_highmask: .long HIGHMASK
-
- .globl _ttymask, _biomask, _netmask
-_ttymask: .long 0
-_biomask: .long 0
-_netmask: .long 0
-
- .globl _ipending, _astpending
+_imen: .long HWI_MASK /* interrupt mask enable (all h/w off) */
+_high_imask: .long HWI_MASK | SWI_MASK
+ .globl _tty_imask
+_tty_imask: .long 0
+ .globl _bio_imask
+_bio_imask: .long 0
+ .globl _net_imask
+_net_imask: .long 0
+ .globl _ipending
_ipending: .long 0
+ .globl _astpending
_astpending: .long 0 /* tells us an AST needs to be taken */
-
.globl _netisr
_netisr: .long 0 /* set with bits for which queue to service */
-
vec:
.long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7
.long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15
-#define GENSPL(name, mask, event) \
- .globl _spl/**/name ; \
- ALIGN_TEXT ; \
-_spl/**/name: ; \
- COUNT_EVENT(_intrcnt_spl, event) ; \
- movl _cpl,%eax ; \
- movl %eax,%edx ; \
- orl mask,%edx ; \
- movl %edx,_cpl ; \
- SHOW_CPL ; \
- ret
-
-#define FASTSPL(mask) \
- movl mask,_cpl ; \
- SHOW_CPL
-
-#define FASTSPL_VARMASK(varmask) \
- movl varmask,%eax ; \
- movl %eax,_cpl ; \
- SHOW_CPL
-
.text
- ALIGN_TEXT
-unpend_v:
- COUNT_EVENT(_intrcnt_spl, 0)
- bsfl %eax,%eax # slow, but not worth optimizing
- btrl %eax,_ipending
- jnc unpend_v_next # some intr cleared the in-memory bit
- SHOW_IPENDING
- movl Vresume(,%eax,4),%eax
- testl %eax,%eax
- je noresume
- jmp %eax
-
- ALIGN_TEXT
-/*
- * XXX - must be some fastintr, need to register those too.
- */
-noresume:
-#if NSIO > 0
- call _softsio1
-#endif
-unpend_v_next:
- movl _cpl,%eax
- movl %eax,%edx
- notl %eax
- andl _ipending,%eax
- je none_to_unpend
- jmp unpend_v
-
/*
- * Handle return from interrupt after device handler finishes
- */
- ALIGN_TEXT
-doreti:
- COUNT_EVENT(_intrcnt_spl, 1)
- addl $4,%esp # discard unit arg
- popl %eax # get previous priority
-/*
- * Now interrupt frame is a trap frame!
- *
- * XXX - setting up the interrupt frame to be almost a stack frame is mostly
- * a waste of time.
+ * Handle return from interrupts, traps and syscalls.
*/
+ SUPERALIGN_TEXT
+_doreti:
+ FAKE_MCOUNT(_bintr) /* init "from" _bintr -> _doreti */
+ addl $4,%esp /* discard unit number */
+ popl %eax /* cpl to restore */
+doreti_next:
+ /*
+ * Check for pending HWIs and SWIs atomically with restoring cpl
+ * and exiting. The check has to be atomic with exiting to stop
+ * (ipending & ~cpl) changing from zero to nonzero while we're
+ * looking at it (this wouldn't be fatal but it would increase
+ * interrupt latency). Restoring cpl has to be atomic with exiting
+ * so that the stack cannot pile up (the nesting level of interrupt
+ * handlers is limited by the number of bits in cpl).
+ */
+ movl %eax,%ecx
+ notl %ecx
+ cli
+ andl _ipending,%ecx
+ jne doreti_unpend
+doreti_exit:
movl %eax,_cpl
- SHOW_CPL
- movl %eax,%edx
- notl %eax
- andl _ipending,%eax
- jne unpend_v
-none_to_unpend:
- testl %edx,%edx # returning to zero priority?
- jne 1f # nope, going to non-zero priority
- movl _netisr,%eax
- testl %eax,%eax # check for softint s/traps
- jne 2f # there are some
- jmp test_resched # XXX - schedule jumps better
- COUNT_EVENT(_intrcnt_spl, 2) # XXX
-
- ALIGN_TEXT # XXX
-1: # XXX
- COUNT_EVENT(_intrcnt_spl, 3)
+ MEXITCOUNT
popl %es
popl %ds
popal
addl $8,%esp
iret
-#include "../net/netisr.h"
-
-#define DONET(s, c, event) ; \
- .globl c ; \
- btrl $s,_netisr ; \
- jnc 1f ; \
- COUNT_EVENT(_intrcnt_spl, event) ; \
- call c ; \
-1:
-
ALIGN_TEXT
-2:
- COUNT_EVENT(_intrcnt_spl, 4)
-/*
- * XXX - might need extra locking while testing reg copy of netisr, but
- * interrupt routines setting it would not cause any new problems (since we
- * don't loop, fresh bits will not be processed until the next doreti or spl0).
- */
- testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),%eax
- je test_ASTs # no net stuff, just temporary AST's
- FASTSPL_VARMASK(_netmask)
-#if 0
- DONET(NETISR_RAW, _rawintr, 5)
-#endif
-
-#ifdef INET
- DONET(NETISR_IP, _ipintr, 6)
-#endif /* INET */
-
-#ifdef IMP
- DONET(NETISR_IMP, _impintr, 7)
-#endif /* IMP */
-
-#ifdef NS
- DONET(NETISR_NS, _nsintr, 8)
-#endif /* NS */
-
-#ifdef ISO
- DONET(NETISR_ISO, _clnlintr, 9)
-#endif /* ISO */
+doreti_unpend:
+ /*
+ * Enabling interrupts is safe because we haven't restored cpl yet.
+ * The locking from the "btrl" test is probably no longer necessary.
+ * We won't miss any new pending interrupts because we will check
+ * for them again.
+ */
+ sti
+ bsfl %ecx,%ecx /* slow, but not worth optimizing */
+ btrl %ecx,_ipending
+ jnc doreti_next /* some intr cleared memory copy */
+ movl ihandlers(,%ecx,4),%edx
+ testl %edx,%edx
+ je doreti_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae doreti_swi
+ cli
+ movl %eax,_cpl
+ MEXITCOUNT
+ jmp %edx
-#ifdef CCITT
- DONET(NETISR_X25, _pkintr, 29)
- DONET(NETISR_HDLC, _hdintr, 30)
-#endif /* CCITT */
+ ALIGN_TEXT
+doreti_swi:
+ pushl %eax
+ /*
+ * The SWI_AST handler has to run at cpl = SWI_AST_MASK and the
+ * SWI_CLOCK handler at cpl = SWI_CLOCK_MASK, so we have to restore
+ * all the h/w bits in cpl now and have to worry about stack growth.
+ * The worst case is currently (30 Jan 1994) 2 SWI handlers nested
+ * in dying interrupt frames and about 12 HWIs nested in active
+ * interrupt frames. There are only 4 different SWIs and the HWI
+ * and SWI masks limit the nesting further.
+ */
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ jmp doreti_next
- FASTSPL($0)
-test_ASTs:
- btrl $NETISR_SCLK,_netisr
- jnc test_resched
- COUNT_EVENT(_intrcnt_spl, 10)
- FASTSPL($SOFTCLOCKMASK)
-/*
- * Back to an interrupt frame for a moment.
- */
- pushl $0 # previous cpl (probably not used)
- pushl $0x7f # dummy unit number
- call _softclock
- addl $8,%esp # discard dummies
- FASTSPL($0)
-test_resched:
-#ifdef notused1
- btrl $NETISR_AST,_netisr
- jnc 2f
-#endif
-#ifdef notused2
- cmpl $0,_want_resched
- je 2f
-#endif
- cmpl $0,_astpending # XXX - put it back in netisr to
- je 2f # reduce the number of tests
+ ALIGN_TEXT
+swi_ast:
+ addl $8,%esp /* discard raddr & cpl to get trap frame */
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
- # to non-kernel (i.e., user)?
- je 2f # nope, leave
- COUNT_EVENT(_intrcnt_spl, 11)
- movl $0,_astpending
+ je swi_ast_phantom
+ movl $T_ASTFLT,(2+8+0)*4(%esp)
call _trap
-2:
- COUNT_EVENT(_intrcnt_spl, 12)
- popl %es
- popl %ds
- popal
- addl $8,%esp
- iret
+ subl %eax,%eax /* recover cpl */
+ jmp doreti_next
+
+ ALIGN_TEXT
+swi_ast_phantom:
+ /*
+ * These happen when there is an interrupt in a trap handler before
+ * ASTs can be masked or in an lcall handler before they can be
+ * masked or after they are unmasked. They could be avoided for
+ * trap entries by using interrupt gates, and for lcall exits by
+ * using by using cli, but they are unavoidable for lcall entries.
+ */
+ cli
+ orl $SWI_AST_PENDING,_ipending
+ jmp doreti_exit /* SWI_AST is highest so we must be done */
/*
* Interrupt priority mechanism
@@ -262,121 +178,84 @@ test_resched:
* -- ipending = active interrupts currently masked by cpl
*/
- GENSPL(bio, _biomask, 13)
- GENSPL(clock, $HIGHMASK, 14) /* splclock == splhigh ex for count */
- GENSPL(high, $HIGHMASK, 15)
- GENSPL(imp, _netmask, 16) /* splimp == splnet except for count */
- GENSPL(net, _netmask, 17)
- GENSPL(softclock, $SOFTCLOCKMASK, 18)
- GENSPL(tty, _ttymask, 19)
-
- .globl _splnone
- .globl _spl0
- ALIGN_TEXT
-_splnone:
-_spl0:
- COUNT_EVENT(_intrcnt_spl, 20)
-in_spl0:
+ENTRY(splz)
+ /*
+ * The caller has restored cpl and checked that (ipending & ~cpl)
+ * is nonzero. We have to repeat the check since if there is an
+ * interrupt while we're looking, _doreti processing for the
+ * interrupt will handle all the unmasked pending interrupts
+ * because we restored early. We're repeating the calculation
+ * of (ipending & ~cpl) anyway so that the caller doesn't have
+ * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx"
+ * is undefined when %ecx is 0 so we can't rely on the secondary
+ * btrl tests.
+ */
movl _cpl,%eax
- pushl %eax # save old priority
- testl $(1 << NETISR_RAW) | (1 << NETISR_IP),_netisr
- je over_net_stuff_for_spl0
- movl _netmask,%eax # mask off those network devices
- movl %eax,_cpl # set new priority
- SHOW_CPL
-/*
- * XXX - what about other net intrs?
- */
-#if 0
- DONET(NETISR_RAW, _rawintr, 21)
-#endif
-
-#ifdef INET
- DONET(NETISR_IP, _ipintr, 22)
-#endif /* INET */
-
-#ifdef IMP
- DONET(NETISR_IMP, _impintr, 23)
-#endif /* IMP */
-
-#ifdef NS
- DONET(NETISR_NS, _nsintr, 24)
-#endif /* NS */
-
-#ifdef ISO
- DONET(NETISR_ISO, _clnlintr, 25)
-#endif /* ISO */
-
-over_net_stuff_for_spl0:
- movl $0,_cpl # set new priority
- SHOW_CPL
- movl _ipending,%eax
- testl %eax,%eax
- jne unpend_V
- popl %eax # return old priority
+splz_next:
+ /*
+ * We don't need any locking here. (ipending & ~cpl) cannot grow
+ * while we're looking at it - any interrupt will shrink it to 0.
+ */
+ movl %eax,%ecx
+ notl %ecx
+ andl _ipending,%ecx
+ jne splz_unpend
ret
- .globl _splx
ALIGN_TEXT
-_splx:
- COUNT_EVENT(_intrcnt_spl, 26)
- movl 4(%esp),%eax # new priority
- testl %eax,%eax
- je in_spl0 # going to "zero level" is special
- COUNT_EVENT(_intrcnt_spl, 27)
- movl _cpl,%edx # save old priority
- movl %eax,_cpl # set new priority
- SHOW_CPL
- notl %eax
- andl _ipending,%eax
- jne unpend_V_result_edx
- movl %edx,%eax # return old priority
- ret
-
- ALIGN_TEXT
-unpend_V_result_edx:
- pushl %edx
-unpend_V:
- COUNT_EVENT(_intrcnt_spl, 28)
- bsfl %eax,%eax
- btrl %eax,_ipending
- jnc unpend_V_next
- SHOW_IPENDING
- movl Vresume(,%eax,4),%edx
+splz_unpend:
+ bsfl %ecx,%ecx
+ btrl %ecx,_ipending
+ jnc splz_next
+ movl ihandlers(,%ecx,4),%edx
testl %edx,%edx
- je noresumeV
-/*
- * We would prefer to call the intr handler directly here but that doesn't
- * work for badly behaved handlers that want the interrupt frame. Also,
- * there's a problem determining the unit number. We should change the
- * interface so that the unit number is not determined at config time.
- */
- jmp *vec(,%eax,4)
+ je splz_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae splz_swi
+ /*
+ * We would prefer to call the intr handler directly here but that
+ * doesn't work for badly behaved handlers that want the interrupt
+ * frame. Also, there's a problem determining the unit number.
+ * We should change the interface so that the unit number is not
+ * determined at config time.
+ */
+ jmp *vec(,%ecx,4)
ALIGN_TEXT
+splz_swi:
+ cmpl $SWI_AST,%ecx
+ je splz_next /* "can't happen" */
+ pushl %eax
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ movl %eax,_cpl
+ jmp splz_next
+
/*
- * XXX - must be some fastintr, need to register those too.
+ * Fake clock IRQ so that it appears to come from our caller and not from
+ * vec0, so that kernel profiling works.
+ * XXX do this more generally (for all vectors; look up the C entry point).
+ * XXX frame bogusness stops us from just jumping to the C entry point.
*/
-noresumeV:
-#if NSIO > 0
- call _softsio1
-#endif
-unpend_V_next:
- movl _cpl,%eax
- notl %eax
- andl _ipending,%eax
- jne unpend_V
- popl %eax
- ret
+ ALIGN_TEXT
+vec0:
+ popl %eax /* return address */
+ pushfl
+#define KCSEL 8
+ pushl $KCSEL
+ pushl %eax
+ cli
+ MEXITCOUNT
+ jmp _Vclk
#define BUILD_VEC(irq_num) \
ALIGN_TEXT ; \
vec/**/irq_num: ; \
int $ICU_OFFSET + (irq_num) ; \
- popl %eax ; \
ret
- BUILD_VEC(0)
BUILD_VEC(1)
BUILD_VEC(2)
BUILD_VEC(3)
@@ -392,3 +271,58 @@ vec/**/irq_num: ; \
BUILD_VEC(13)
BUILD_VEC(14)
BUILD_VEC(15)
+
+ ALIGN_TEXT
+swi_clock:
+ MCOUNT
+ subl %eax,%eax
+ cmpl $_splz,(%esp) /* XXX call from splz()? */
+ jae 1f /* yes, usermode = 0 */
+ movl 4+4+TRAPF_CS_OFF(%esp),%eax /* no, check trap frame */
+ andl $SEL_RPL_MASK,%eax
+1:
+ pushl %eax
+ call _softclock
+ addl $4,%esp
+ ret
+
+#define DONET(s, c, event) ; \
+ .globl c ; \
+ btrl $s,_netisr ; \
+ jnc 9f ; \
+ call c ; \
+9:
+
+ ALIGN_TEXT
+swi_net:
+ MCOUNT
+#if 0
+ DONET(NETISR_RAW, _rawintr,netisr_raw)
+#endif
+#ifdef INET
+ DONET(NETISR_IP, _ipintr,netisr_ip)
+#endif
+#ifdef IMP
+ DONET(NETISR_IMP, _impintr,netisr_imp)
+#endif
+#ifdef NS
+ DONET(NETISR_NS, _nsintr,netisr_ns)
+#endif
+#ifdef ISO
+ DONET(NETISR_ISO, _clnlintr,netisr_iso)
+#endif
+#ifdef CCITT
+ DONET(NETISR_X25, _pkintr, 29)
+ DONET(NETISR_HDLC, _hdintr, 30)
+#endif
+ ret
+
+ ALIGN_TEXT
+swi_tty:
+ MCOUNT
+#include "sio.h"
+#if NSIO > 0
+ jmp _siopoll
+#else
+ ret
+#endif
diff --git a/sys/i386/isa/if_ed.c b/sys/i386/isa/if_ed.c
index 079f09cc9d3b..e806b1e471f9 100644
--- a/sys/i386/isa/if_ed.c
+++ b/sys/i386/isa/if_ed.c
@@ -16,7 +16,7 @@
*/
/*
- * $Id: if_ed.c,v 1.33.2.2 1994/04/17 06:04:33 rgrimes Exp $
+ * $Id: if_ed.c,v 1.42 1994/06/16 08:27:21 davidg Exp $
*/
#include "ed.h"
@@ -65,65 +65,71 @@
#ifndef IFF_ALTPHYS
#define IFF_ALTPHYS IFF_LLC0
#endif
-
+
/*
* ed_softc: per line info and status
*/
-struct ed_softc {
- struct arpcom arpcom; /* ethernet common */
+struct ed_softc {
+ struct arpcom arpcom; /* ethernet common */
- char *type_str; /* pointer to type string */
- u_char vendor; /* interface vendor */
- u_char type; /* interface type code */
+ char *type_str; /* pointer to type string */
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
- u_short asic_addr; /* ASIC I/O bus address */
- u_short nic_addr; /* NIC (DS8390) I/O bus address */
+ u_short asic_addr; /* ASIC I/O bus address */
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
/*
* The following 'proto' variable is part of a work-around for 8013EBT asics
* being write-only. It's sort of a prototype/shadow of the real thing.
*/
- u_char wd_laar_proto;
- u_char isa16bit; /* width of access to card 0=8 or 1=16 */
- int is790; /* set by the probe code if the card is 790 based */
-
- caddr_t bpf; /* BPF "magic cookie" */
- caddr_t mem_start; /* NIC memory start address */
- caddr_t mem_end; /* NIC memory end address */
- u_long mem_size; /* total NIC memory size */
- caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
-
- u_char mem_shared; /* NIC memory is shared with host */
- u_char xmit_busy; /* transmitter is busy */
- u_char txb_cnt; /* number of transmit buffers */
- u_char txb_inuse; /* number of TX buffers currently in-use*/
-
- u_char txb_new; /* pointer to where new buffer will be added */
- u_char txb_next_tx; /* pointer to next buffer ready to xmit */
- u_short txb_len[8]; /* buffered xmit buffer lengths */
- u_char tx_page_start; /* first page of TX buffer area */
- u_char rec_page_start; /* first page of RX ring-buffer */
- u_char rec_page_stop; /* last page of RX ring-buffer */
- u_char next_packet; /* pointer to next unread RX packet */
-} ed_softc[NED];
-
-int ed_attach(struct isa_device *);
-void ed_init(int);
-void edintr(int);
-int ed_ioctl(struct ifnet *, int, caddr_t);
-int ed_probe(struct isa_device *);
-void ed_start(struct ifnet *);
-void ed_reset(int, int);
-void ed_watchdog(int);
-
-static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
+ u_char wd_laar_proto;
+ u_char isa16bit; /* width of access to card 0=8 or 1=16 */
+ int is790; /* set by the probe code if the card is 790
+ * based */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+ caddr_t mem_start; /* NIC memory start address */
+ caddr_t mem_end; /* NIC memory end address */
+ u_long mem_size; /* total NIC memory size */
+ caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
+
+ u_char mem_shared; /* NIC memory is shared with host */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* number of transmit buffers */
+ u_char txb_inuse; /* number of TX buffers currently in-use */
+
+ u_char txb_new; /* pointer to where new buffer will be added */
+ u_char txb_next_tx; /* pointer to next buffer ready to xmit */
+ u_short txb_len[8]; /* buffered xmit buffer lengths */
+ u_char tx_page_start; /* first page of TX buffer area */
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ed_softc[NED];
+
+int ed_attach(struct isa_device *);
+void ed_init(int);
+void edintr(int);
+int ed_ioctl(struct ifnet *, int, caddr_t);
+int ed_probe(struct isa_device *);
+void ed_start(struct ifnet *);
+void ed_reset(int, int);
+void ed_watchdog(int);
+
+#ifdef MULTICAST
+void ds_getmcaf();
+
+#endif
+
+static void ed_get_packet(struct ed_softc *, char *, int /* u_short */ );
static void ed_stop(int);
static inline void ed_rint();
static inline void ed_xmit();
static inline char *ed_ring_copy();
-void ed_pio_readmem(), ed_pio_writemem();
+void ed_pio_readmem(), ed_pio_writemem();
u_short ed_pio_write_mbufs();
extern int ether_output();
@@ -138,7 +144,8 @@ struct isa_driver eddriver = {
ed_attach,
"ed"
};
-/*
+
+/*
* Interrupt conversion table for WD/SMC ASIC
* (IRQ* are defined in icu.h)
*/
@@ -152,7 +159,7 @@ static unsigned short ed_intr_mask[] = {
IRQ15,
IRQ4
};
-
+
/*
* Interrupt conversion table for 585/790 Combo
*/
@@ -166,6 +173,7 @@ static unsigned short ed_790_intr_mask[] = {
IRQ11,
IRQ15
};
+
#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518
#define ETHER_ADDR_LEN 6
@@ -185,7 +193,7 @@ ed_probe(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int nports;
+ int nports;
if (nports = ed_probe_WD80x3(isa_dev))
return (nports);
@@ -196,7 +204,7 @@ ed_probe(isa_dev)
if (nports = ed_probe_Novell(isa_dev))
return (nports);
- return(0);
+ return (0);
}
/*
@@ -219,7 +227,7 @@ ed_probe(isa_dev)
* the others would require changing register pages (which would be
* intrusive if this isn't an 8390).
*
- * Return 1 if 8390 was found, 0 if not.
+ * Return 1 if 8390 was found, 0 if not.
*/
int
@@ -227,15 +235,15 @@ ed_probe_generic8390(sc)
struct ed_softc *sc;
{
if ((inb(sc->nic_addr + ED_P0_CR) &
- (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) !=
- (ED_CR_RD2|ED_CR_STP))
+ (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
+ (ED_CR_RD2 | ED_CR_STP))
return (0);
if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
return (0);
- return(1);
+ return (1);
}
-
+
/*
* Probe and vendor-specific initialization routine for SMC/WD80x3 boards
*/
@@ -244,9 +252,9 @@ ed_probe_WD80x3(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int i;
- u_int memsize;
- u_char iptr, isa16bit, sum;
+ int i;
+ u_int memsize;
+ u_char iptr, isa16bit, sum;
sc->asic_addr = isa_dev->id_iobase;
sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
@@ -256,26 +264,27 @@ ed_probe_WD80x3(isa_dev)
outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW);
DELAY(10000);
#endif
+
/*
- * Attempt to do a checksum over the station address PROM.
- * If it fails, it's probably not a SMC/WD board. There
- * is a problem with this, though: some clone WD boards
- * don't pass the checksum test. Danpex boards for one.
+ * Attempt to do a checksum over the station address PROM. If it
+ * fails, it's probably not a SMC/WD board. There is a problem with
+ * this, though: some clone WD boards don't pass the checksum test.
+ * Danpex boards for one.
*/
for (sum = 0, i = 0; i < 8; ++i)
sum += inb(sc->asic_addr + ED_WD_PROM + i);
if (sum != ED_WD_ROM_CHECKSUM_TOTAL) {
+
/*
- * Checksum is invalid. This often happens with cheap
- * WD8003E clones. In this case, the checksum byte
- * (the eighth byte) seems to always be zero.
+ * Checksum is invalid. This often happens with cheap WD8003E
+ * clones. In this case, the checksum byte (the eighth byte)
+ * seems to always be zero.
*/
if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
inb(sc->asic_addr + ED_WD_PROM + 7) != 0)
- return(0);
+ return (0);
}
-
/* reset card to force it into a known state. */
#ifdef TOSH_ETHER
outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
@@ -318,7 +327,7 @@ ed_probe_WD80x3(isa_dev)
memsize = 16384;
isa16bit = 1;
break;
- case ED_TYPE_WD8013EP: /* also WD8003EP */
+ case ED_TYPE_WD8013EP: /* also WD8003EP */
if (inb(sc->asic_addr + ED_WD_ICR)
& ED_WD_ICR_16BIT) {
isa16bit = 1;
@@ -371,33 +380,35 @@ ed_probe_WD80x3(isa_dev)
sc->type_str = "";
break;
}
+
/*
- * Make some adjustments to initial values depending on what is
- * found in the ICR.
+ * Make some adjustments to initial values depending on what is found
+ * in the ICR.
*/
if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
#ifdef TOSH_ETHER
- && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
+ && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
#endif
&& ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
isa16bit = 0;
memsize = 8192;
}
-
#if ED_DEBUG
printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n",
- sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize);
- for (i=0; i<8; i++)
+ sc->type, sc->type_str, isa16bit, memsize, isa_dev->id_msize);
+ for (i = 0; i < 8; i++)
printf("%x -> %x\n", i, inb(sc->asic_addr + i));
#endif
+
/*
* Allow the user to override the autoconfiguration
*/
if (isa_dev->id_msize)
memsize = isa_dev->id_msize;
+
/*
- * (note that if the user specifies both of the following flags
- * that '8bit' mode intentionally has precedence)
+ * (note that if the user specifies both of the following flags that
+ * '8bit' mode intentionally has precedence)
*/
if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
isa16bit = 1;
@@ -406,60 +417,66 @@ ed_probe_WD80x3(isa_dev)
/*
* Check 83C584 interrupt configuration register if this board has one
- * XXX - we could also check the IO address register. But why
- * bother...if we get past this, it *has* to be correct.
+ * XXX - we could also check the IO address register. But why
+ * bother...if we get past this, it *has* to be correct.
*/
if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) {
+
/*
* Assemble together the encoded interrupt number.
*/
iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
- ((inb(isa_dev->id_iobase + ED_WD_IRR) &
- (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+ ((inb(isa_dev->id_iobase + ED_WD_IRR) &
+ (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+
/*
- * Translate it using translation table, and check for correctness.
+ * Translate it using translation table, and check for
+ * correctness.
*/
if (ed_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
- ffs(ed_intr_mask[iptr]) - 1);
- return(0);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_intr_mask[iptr]) - 1);
+ return (0);
}
+
/*
* Enable the interrupt.
*/
outb(isa_dev->id_iobase + ED_WD_IRR,
- inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
+ inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
}
if (sc->is790) {
outb(isa_dev->id_iobase + ED_WD790_HWR,
- inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
+ inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
- (inb(isa_dev->id_iobase + ED_WD790_GCR) &
- (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2);
+ (inb(isa_dev->id_iobase + ED_WD790_GCR) &
+ (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2);
outb(isa_dev->id_iobase + ED_WD790_HWR,
- inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
+ inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
if (ed_790_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
- ffs(ed_790_intr_mask[iptr]) - 1, iptr);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_790_intr_mask[iptr]) - 1, iptr);
return 0;
}
+
/*
* Enable interrupts.
*/
outb(isa_dev->id_iobase + ED_WD790_ICR,
- inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
+ inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
}
-
sc->isa16bit = isa16bit;
-#ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+/* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+#ifdef notyet
+
/*
* The following allows the WD/SMC boards to be used in Programmed I/O
- * mode - without mapping the NIC memory shared. ...Not the prefered
- * way, but it might be the only way.
+ * mode - without mapping the NIC memory shared. ...Not the prefered
+ * way, but it might be the only way.
*/
if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) {
sc->mem_shared = 0;
@@ -472,7 +489,7 @@ ed_probe_WD80x3(isa_dev)
#endif
isa_dev->id_msize = memsize;
- sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_start = (caddr_t) isa_dev->id_maddr;
/*
* allocate one xmit buffer if < 16k, two buffers otherwise
@@ -498,27 +515,6 @@ ed_probe_WD80x3(isa_dev)
sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
if (sc->mem_shared) {
- /*
- * Set address and enable interface shared memory.
- */
- if(!sc->is790) {
-#ifdef TOSH_ETHER
- outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
- outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
-
-#else
- outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
- ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
-#endif
- } else {
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
- outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
- outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
- ((kvtop(sc->mem_start) >> 11) & 0x40) |
- (inb(sc->asic_addr + 0x0b) & 0xb0));
- outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
- }
/*
* Set upper address bits and 8/16 bit access to shared memory
@@ -530,57 +526,85 @@ ed_probe_WD80x3(isa_dev)
(void) inb(0x84);
} else {
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
- ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
- ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
- } else {
+ } else {
if ((sc->type & ED_WD_SOFTCONFIG) ||
#ifdef TOSH_ETHER
(sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) ||
#endif
(sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) {
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
- ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
}
/*
+ * Set address and enable interface shared memory.
+ */
+ if (!sc->is790) {
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
+ outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
+
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
+ ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
+#endif
+ } else {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
+ outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
+ ((kvtop(sc->mem_start) >> 11) & 0x40) |
+ (inb(sc->asic_addr + 0x0b) & 0xb0));
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
+ }
+
+ /*
* Now zero memory and verify that it is clear
*/
bzero(sc->mem_start, memsize);
for (i = 0; i < memsize; ++i)
if (sc->mem_start[i]) {
- printf("ed%d: failed to clear shared memory at %x - check configuration\n",
- isa_dev->id_unit, kvtop(sc->mem_start + i));
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
/*
* Disable 16 bit access to shared memory
*/
if (isa16bit) {
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
+ ~ED_WD_LAAR_M16EN));
(void) inb(0x84);
}
-
- return(0);
+ return (0);
}
-
+
/*
- * Disable 16bit access to shared memory - we leave it disabled so
- * that 1) machines reboot properly when the board is set
- * 16 bit mode and there are conflicting 8bit devices/ROMS
- * in the same 128k address space as this boards shared
- * memory. and 2) so that other 8 bit devices with shared
- * memory can be used in this 128k region, too.
+ * Disable 16bit access to shared memory - we leave it
+ * disabled so that 1) machines reboot properly when the board
+ * is set 16 bit mode and there are conflicting 8bit
+ * devices/ROMS in the same 128k address space as this boards
+ * shared memory. and 2) so that other 8 bit devices with
+ * shared memory can be used in this 128k region, too.
*/
if (isa16bit) {
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
+ ~ED_WD_LAAR_M16EN));
(void) inb(0x84);
}
}
-
return (ED_WD_IO_PORTS);
}
@@ -592,84 +616,84 @@ ed_probe_3Com(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int i;
- u_int memsize;
- u_char isa16bit, sum;
+ int i;
+ u_int memsize;
+ u_char isa16bit, sum;
sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
/*
* Verify that the kernel configured I/O address matches the board
- * configured address
+ * configured address
*/
switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
case ED_3COM_BCFR_300:
if (isa_dev->id_iobase != 0x300)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_310:
if (isa_dev->id_iobase != 0x310)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_330:
if (isa_dev->id_iobase != 0x330)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_350:
if (isa_dev->id_iobase != 0x350)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_250:
if (isa_dev->id_iobase != 0x250)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_280:
if (isa_dev->id_iobase != 0x280)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_2A0:
if (isa_dev->id_iobase != 0x2a0)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_2E0:
if (isa_dev->id_iobase != 0x2e0)
- return(0);
+ return (0);
break;
default:
- return(0);
+ return (0);
}
/*
- * Verify that the kernel shared memory address matches the
- * board configured address.
+ * Verify that the kernel shared memory address matches the board
+ * configured address.
*/
switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
case ED_3COM_PCFR_DC000:
if (kvtop(isa_dev->id_maddr) != 0xdc000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_D8000:
if (kvtop(isa_dev->id_maddr) != 0xd8000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_CC000:
if (kvtop(isa_dev->id_maddr) != 0xcc000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_C8000:
if (kvtop(isa_dev->id_maddr) != 0xc8000)
- return(0);
+ return (0);
break;
default:
- return(0);
+ return (0);
}
/*
* Reset NIC and ASIC. Enable on-board transceiver throughout reset
- * sequence because it'll lock up if the cable isn't connected
- * if we don't.
+ * sequence because it'll lock up if the cable isn't connected if we
+ * don't.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
@@ -677,10 +701,11 @@ ed_probe_3Com(isa_dev)
* Wait for a while, then un-reset it
*/
DELAY(50);
+
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
- * a reset - it's important to set it again after the following
- * outb (this is done when we map the PROM below).
+ * a reset - it's important to set it again after the following outb
+ * (this is done when we map the PROM below).
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@@ -695,17 +720,18 @@ ed_probe_3Com(isa_dev)
sc->mem_shared = 1;
/*
- * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k
- * window to it.
+ * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window
+ * to it.
*/
memsize = 8192;
/*
* Get station address from on-board ROM
*/
+
/*
* First, map ethernet address PROM over the top of where the NIC
- * registers normally appear.
+ * registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
@@ -714,9 +740,8 @@ ed_probe_3Com(isa_dev)
/*
* Unmap PROM - select NIC registers. The proper setting of the
- * tranceiver is set in ed_init so that the attach code
- * is given a chance to set the default based on a compile-time
- * config option
+ * tranceiver is set in ed_init so that the attach code is given a
+ * chance to set the default based on a compile-time config option
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@@ -727,18 +752,18 @@ ed_probe_3Com(isa_dev)
/*
* select page 0 registers
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
/*
- * Attempt to clear WTS bit. If it doesn't clear, then this is a
- * 16bit board.
+ * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit
+ * board.
*/
outb(sc->nic_addr + ED_P0_DCR, 0);
/*
* select page 2 registers
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP);
/*
* The 3c503 forces the WTS bit to a one if this is a 16bit board
@@ -751,24 +776,23 @@ ed_probe_3Com(isa_dev)
/*
* select page 0 registers
*/
- outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2 | ED_CR_STP);
- sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_start = (caddr_t) isa_dev->id_maddr;
sc->mem_size = memsize;
sc->mem_end = sc->mem_start + memsize;
/*
* We have an entire 8k window to put the transmit buffers on the
- * 16bit boards. But since the 16bit 3c503's shared memory
- * is only fast enough to overlap the loading of one full-size
- * packet, trying to load more than 2 buffers can actually
- * leave the transmitter idle during the load. So 2 seems
- * the best value. (Although a mix of variable-sized packets
- * might change this assumption. Nonetheless, we optimize for
- * linear transfers of same-size packets.)
+ * 16bit boards. But since the 16bit 3c503's shared memory is only
+ * fast enough to overlap the loading of one full-size packet, trying
+ * to load more than 2 buffers can actually leave the transmitter idle
+ * during the load. So 2 seems the best value. (Although a mix of
+ * variable-sized packets might change this assumption. Nonetheless,
+ * we optimize for linear transfers of same-size packets.)
*/
if (isa16bit) {
- if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
sc->txb_cnt = 1;
else
sc->txb_cnt = 2;
@@ -776,22 +800,22 @@ ed_probe_3Com(isa_dev)
sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
sc->rec_page_stop = memsize / ED_PAGE_SIZE +
- ED_3COM_RX_PAGE_OFFSET_16BIT;
+ ED_3COM_RX_PAGE_OFFSET_16BIT;
sc->mem_ring = sc->mem_start;
} else {
sc->txb_cnt = 1;
sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->rec_page_stop = memsize / ED_PAGE_SIZE +
- ED_3COM_TX_PAGE_OFFSET_8BIT;
+ ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
}
sc->isa16bit = isa16bit;
/*
- * Initialize GA page start/stop registers. Probably only needed
- * if doing DMA, but what the hell.
+ * Initialize GA page start/stop registers. Probably only needed if
+ * doing DMA, but what the hell.
*/
outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
@@ -814,21 +838,22 @@ ed_probe_3Com(isa_dev)
break;
default:
printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
- return(0);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
+ return (0);
}
/*
- * Initialize GA configuration register. Set bank and enable shared mem.
+ * Initialize GA configuration register. Set bank and enable shared
+ * mem.
*/
outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
- ED_3COM_GACFR_MBS0);
+ ED_3COM_GACFR_MBS0);
/*
- * Initialize "Vector Pointer" registers. These gawd-awful things
- * are compared to 20 bits of the address on ISA, and if they
- * match, the shared memory is disabled. We set them to
- * 0xffff0...allegedly the reset vector.
+ * Initialize "Vector Pointer" registers. These gawd-awful things are
+ * compared to 20 bits of the address on ISA, and if they match, the
+ * shared memory is disabled. We set them to 0xffff0...allegedly the
+ * reset vector.
*/
outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
@@ -841,13 +866,12 @@ ed_probe_3Com(isa_dev)
for (i = 0; i < memsize; ++i)
if (sc->mem_start[i]) {
- printf("ed%d: failed to clear shared memory at %x - check configuration\n",
- isa_dev->id_unit, kvtop(sc->mem_start + i));
- return(0);
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+ return (0);
}
-
isa_dev->id_msize = memsize;
- return(ED_3COM_IO_PORTS);
+ return (ED_3COM_IO_PORTS);
}
/*
@@ -858,10 +882,10 @@ ed_probe_Novell(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- u_int memsize, n;
- u_char romdata[16], isa16bit = 0, tmp;
+ u_int memsize, n;
+ u_char romdata[16], isa16bit = 0, tmp;
static char test_pattern[32] = "THIS is A memory TEST pattern";
- char test_buffer[32];
+ char test_buffer[32];
sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET;
sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET;
@@ -869,50 +893,54 @@ ed_probe_Novell(isa_dev)
/* XXX - do Novell-specific probe here */
/* Reset the board */
+#ifdef GWETHER
+ outb(sc->asic_addr + ED_NOVELL_RESET, 0);
+ DELAY(200);
+#endif /* GWETHER */
tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
/*
* I don't know if this is necessary; probably cruft leftover from
- * Clarkson packet driver code. Doesn't do a thing on the boards
- * I've tested. -DG [note that a outb(0x84, 0) seems to work
- * here, and is non-invasive...but some boards don't seem to reset
- * and I don't have complete documentation on what the 'right'
- * thing to do is...so we do the invasive thing for now. Yuck.]
+ * Clarkson packet driver code. Doesn't do a thing on the boards I've
+ * tested. -DG [note that a outb(0x84, 0) seems to work here, and is
+ * non-invasive...but some boards don't seem to reset and I don't have
+ * complete documentation on what the 'right' thing to do is...so we
+ * do the invasive thing for now. Yuck.]
*/
outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
DELAY(5000);
/*
* This is needed because some NE clones apparently don't reset the
- * NIC properly (or the NIC chip doesn't reset fully on power-up)
- * XXX - this makes the probe invasive! ...Done against my better
- * judgement. -DLG
+ * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
+ * - this makes the probe invasive! ...Done against my better
+ * judgement. -DLG
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
DELAY(5000);
/* Make sure that we really have an 8390 based board */
if (!ed_probe_generic8390(sc))
- return(0);
+ return (0);
sc->vendor = ED_VENDOR_NOVELL;
sc->mem_shared = 0;
isa_dev->id_maddr = 0;
/*
- * Test the ability to read and write to the NIC memory. This has
- * the side affect of determining if this is an NE1000 or an NE2000.
+ * Test the ability to read and write to the NIC memory. This has the
+ * side affect of determining if this is an NE1000 or an NE2000.
*/
/*
- * This prevents packets from being stored in the NIC memory when
- * the readmem routine turns on the start bit in the CR.
+ * This prevents packets from being stored in the NIC memory when the
+ * readmem routine turns on the start bit in the CR.
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
/* Temporarily initialize DCR for byte operations */
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE);
outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE);
@@ -921,8 +949,8 @@ ed_probe_Novell(isa_dev)
/*
* Write a test pattern in byte mode. If this fails, then there
- * probably isn't any memory at 8k - which likely means
- * that the board is an NE2000.
+ * probably isn't any memory at 8k - which likely means that the board
+ * is an NE2000.
*/
ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern));
ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern));
@@ -930,20 +958,21 @@ ed_probe_Novell(isa_dev)
if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
/* not an NE1000 - try NE2000 */
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE);
outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE);
sc->isa16bit = 1;
+
/*
* Write a test pattern in word mode. If this also fails, then
- * we don't know what this board is.
+ * we don't know what this board is.
*/
ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern));
ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern));
if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)))
- return(0); /* not an NE2000 either */
+ return (0); /* not an NE2000 either */
sc->type = ED_TYPE_NE2000;
sc->type_str = "NE2000";
@@ -951,11 +980,11 @@ ed_probe_Novell(isa_dev)
sc->type = ED_TYPE_NE1000;
sc->type_str = "NE1000";
}
-
+
/* 8k of memory plus an additional 8k if 16bit */
memsize = 8192 + sc->isa16bit * 8192;
-#if 0 /* probably not useful - NE boards only come two ways */
+#if 0 /* probably not useful - NE boards only come two ways */
/* allow kernel config file overrides */
if (isa_dev->id_msize)
memsize = isa_dev->id_msize;
@@ -969,9 +998,72 @@ ed_probe_Novell(isa_dev)
sc->mem_end = sc->mem_start + memsize;
sc->tx_page_start = memsize / ED_PAGE_SIZE;
+#ifdef GWETHER
+ {
+ int x, i, mstart = 0, msize = 0;
+ char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE];
+
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf0[i] = 0;
+
+ /* Clear all the memory. */
+ for (x = 1; x < 256; x++)
+ ed_pio_writemem(sc, pbuf0, x * 256, ED_PAGE_SIZE);
+
+ /* Search for the start of RAM. */
+ for (x = 1; x < 256; x++) {
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) {
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf[i] = 255 - x;
+ ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE);
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) {
+ mstart = x * ED_PAGE_SIZE;
+ msize = ED_PAGE_SIZE;
+ break;
+ }
+ }
+ }
+
+ if (mstart == 0) {
+ printf("ed%d: Cannot find start of RAM.\n", isa_dev->id_unit);
+ return 0;
+ }
+ /* Search for the start of RAM. */
+ for (x = (mstart / ED_PAGE_SIZE) + 1; x < 256; x++) {
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) {
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf[i] = 255 - x;
+ ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE);
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0)
+ msize += ED_PAGE_SIZE;
+ else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (msize == 0) {
+ printf("ed%d: Cannot find any RAM, start : %d, x = %d.\n", isa_dev->id_unit, mstart, x);
+ return 0;
+ }
+ printf("ed%d: RAM start at %d, size : %d.\n", isa_dev->id_unit, mstart, msize);
+
+ sc->mem_size = msize;
+ sc->mem_start = (char *) mstart;
+ sc->mem_end = (char *) (msize + mstart);
+ sc->tx_page_start = mstart / ED_PAGE_SIZE;
+ }
+#endif /* GWETHER */
+
/*
* Use one xmit buffer if < 16k, two buffers otherwise (if not told
- * otherwise).
+ * otherwise).
*/
if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING))
sc->txb_cnt = 1;
@@ -985,14 +1077,19 @@ ed_probe_Novell(isa_dev)
ed_pio_readmem(sc, 0, romdata, 16);
for (n = 0; n < ETHER_ADDR_LEN; n++)
- sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)];
+ sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)];
+
+#ifdef GWETHER
+ if (sc->arpcom.ac_enaddr[2] == 0x86)
+ sc->type_str = "Gateway AT";
+#endif /* GWETHER */
/* clear any pending interrupts that might have occurred above */
outb(sc->nic_addr + ED_P0_ISR, 0xff);
- return(ED_NOVELL_IO_PORTS);
+ return (ED_NOVELL_IO_PORTS);
}
-
+
/*
* Install interface into kernel networking data structures
*/
@@ -1004,7 +1101,7 @@ ed_attach(isa_dev)
struct ifnet *ifp = &sc->arpcom.ac_if;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
-
+
/*
* Set interface to stopped condition (reset)
*/
@@ -1014,7 +1111,7 @@ ed_attach(isa_dev)
* Initialize ifnet structure
*/
ifp->if_unit = isa_dev->id_unit;
- ifp->if_name = "ed" ;
+ ifp->if_name = "ed";
ifp->if_mtu = ETHERMTU;
ifp->if_init = ed_init;
ifp->if_output = ether_output;
@@ -1025,13 +1122,16 @@ ed_attach(isa_dev)
/*
* Set default state for ALTPHYS flag (used to disable the tranceiver
- * for AUI operation), based on compile-time config option.
+ * for AUI operation), based on compile-time config option.
*/
if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
ifp->if_flags =
(IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+#ifdef MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif
/*
* Attach the interface
@@ -1041,20 +1141,22 @@ ed_attach(isa_dev)
/*
* Search down the ifa address list looking for the AF_LINK type entry
*/
- ifa = ifp->if_addrlist;
+ ifa = ifp->if_addrlist;
while ((ifa != 0) && (ifa->ifa_addr != 0) &&
- (ifa->ifa_addr->sa_family != AF_LINK))
+ (ifa->ifa_addr->sa_family != AF_LINK))
ifa = ifa->ifa_next;
+
/*
* If we find an AF_LINK type entry we fill in the hardware address.
- * This is useful for netstat(1) to keep track of which interface
- * is which.
+ * This is useful for netstat(1) to keep track of which interface is
+ * which.
*/
if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+
/*
* Fill in the link-level address for this interface
*/
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ETHER_ADDR_LEN;
sdl->sdl_slen = 0;
@@ -1065,17 +1167,17 @@ ed_attach(isa_dev)
* Print additional info when attached
*/
printf("ed%d: address %s, ", isa_dev->id_unit,
- ether_sprintf(sc->arpcom.ac_enaddr));
+ ether_sprintf(sc->arpcom.ac_enaddr));
if (sc->type_str && (*sc->type_str != 0))
printf("type %s ", sc->type_str);
else
printf("type unknown (0x%x) ", sc->type);
- printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+ printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)");
printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
- (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
/*
* If BPF is in the kernel, call the attach for it
@@ -1085,16 +1187,16 @@ ed_attach(isa_dev)
#endif
return 1;
}
-
+
/*
* Reset interface.
*/
void
ed_reset(unit, uban)
- int unit;
- int uban; /* XXX */
+ int unit;
+ int uban; /* XXX */
{
- int s;
+ int s;
s = splimp();
@@ -1106,29 +1208,30 @@ ed_reset(unit, uban)
(void) splx(s);
}
-
+
/*
* Take interface offline.
*/
void
ed_stop(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
- int n = 5000;
-
+ int n = 5000;
+
/*
* Stop everything on the interface, and select page 0 registers.
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
}
+
/*
- * Wait for interface to enter stopped state, but limit # of checks
- * to 'n' (about 5ms). It shouldn't even take 5us on modern
- * DS8390's, but just in case it's an old one.
+ * Wait for interface to enter stopped state, but limit # of checks to
+ * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
+ * just in case it's an old one.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
@@ -1140,7 +1243,7 @@ ed_stop(unit)
*/
void
ed_watchdog(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
@@ -1151,25 +1254,26 @@ ed_watchdog(unit)
}
/*
- * Initialize device.
+ * Initialize device.
*/
void
ed_init(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
struct ifnet *ifp = &sc->arpcom.ac_if;
- int i, s;
- u_char command;
+ int i, s;
+ u_char command;
/* address not known */
- if (ifp->if_addrlist == (struct ifaddr *)0) return;
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
/*
* Initialize the NIC in the exact order outlined in the NS manual.
- * This init procedure is "mandatory"...don't change what or when
- * things happen.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
*/
s = splimp();
@@ -1190,19 +1294,21 @@ ed_init(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
}
if (sc->isa16bit) {
+
/*
- * Set FIFO threshold to 8, No auto-init Remote DMA,
- * byte order=80x86, word-wide DMA xfers,
+ * Set FIFO threshold to 8, No auto-init Remote DMA, byte
+ * order=80x86, word-wide DMA xfers,
*/
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
} else {
+
/*
* Same as above, but byte-wide DMA xfers
*/
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
}
/*
@@ -1210,11 +1316,19 @@ ed_init(unit)
*/
outb(sc->nic_addr + ED_P0_RBCR0, 0);
outb(sc->nic_addr + ED_P0_RBCR1, 0);
+#ifndef MULTICAST
/*
* Enable reception of broadcast packets
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+#else
+
+ /*
+ * Tell RCR to do nothing for now.
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+#endif
/*
* Place NIC in internal loopback mode
@@ -1238,41 +1352,62 @@ ed_init(unit)
/*
* Clear all interrupts. A '1' in each bit position clears the
- * corresponding flag.
+ * corresponding flag.
*/
outb(sc->nic_addr + ED_P0_ISR, 0xff);
/*
* Enable the following interrupts: receive/transmit complete,
- * receive/transmit error, and Receiver OverWrite.
- *
+ * receive/transmit error, and Receiver OverWrite.
+ *
* Counter overflow and Remote DMA complete are *not* enabled.
*/
outb(sc->nic_addr + ED_P0_IMR,
- ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
+ ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE);
/*
* Program Command Register for page 1
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STP);
}
+
/*
* Copy out our station address
*/
for (i = 0; i < ETHER_ADDR_LEN; ++i)
outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+#ifndef MULTICAST
#if NBPFILTER > 0
+
/*
- * Initialize multicast address hashing registers to accept
- * all multicasts (only used when in promiscuous mode)
+ * Initialize multicast address hashing registers to accept all
+ * multicasts (only used when in promiscuous mode)
*/
for (i = 0; i < 8; ++i)
outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
#endif
+#else
+ /* set up multicast addresses and filter modes */
+ if (sc != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) {
+ u_long mcaf[2];
+
+ if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
+ mcaf[0] = 0xffffffff;
+ mcaf[1] = 0xffffffff;
+ } else
+ ds_getmcaf(sc, mcaf);
+
+ /*
+ * Set multicast filter on chip.
+ */
+ for (i = 0; i < 8; i++)
+ outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *) mcaf)[i]);
+ }
+#endif
/*
* Set Current Page pointer to next_packet (initialized above)
@@ -1280,14 +1415,22 @@ ed_init(unit)
outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
/*
- * Set Command Register for page 0, Remote DMA complete,
- * and interface Start.
+ * Set Command Register for page 0, Remote DMA complete, and interface
+ * Start.
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P1_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2 | ED_CR_STA);
}
+#ifdef MULTICAST
+
+ /*
+ * Clear all interrupts
+ */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+#endif
+
/*
* Take interface out of loopback
*/
@@ -1295,7 +1438,7 @@ ed_init(unit)
/*
* If this is a 3Com board, the tranceiver must be software enabled
- * (there is no settable hardware default).
+ * (there is no settable hardware default).
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
@@ -1304,6 +1447,25 @@ ed_init(unit)
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
+#ifdef MULTICAST
+ i = ED_RCR_AB;
+ if (sc != 0) {
+ if ((ifp->if_flags & IFF_PROMISC) != 0) {
+
+ /*
+ * Set promiscuous mode. Also reconfigure the
+ * multicast filter.
+ */
+ int j;
+
+ i |= ED_RCR_PRO | ED_RCR_AM | ED_RCR_AR | ED_RCR_SEP;
+ for (j = 0; j < 8; j++)
+ outb(sc->nic_addr + ED_P1_MAR0 + j, 0xff);
+ }
+ i |= ED_RCR_AM;
+ }
+ outb(sc->nic_addr + ED_P0_RCR, i);
+#endif
/*
* Set 'running' flag, and clear output active flag.
@@ -1318,11 +1480,12 @@ ed_init(unit)
(void) splx(s);
}
-
+
/*
* This routine actually starts the transmission on the interface
*/
-static inline void ed_xmit(ifp)
+static inline void
+ed_xmit(ifp)
struct ifnet *ifp;
{
struct ed_softc *sc = &ed_softc[ifp->if_unit];
@@ -1336,13 +1499,14 @@ static inline void ed_xmit(ifp)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
* Set TX buffer start page
*/
outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
- sc->txb_next_tx * ED_TXBUF_SIZE);
+ sc->txb_next_tx * ED_TXBUF_SIZE);
/*
* Set TX length
@@ -1356,10 +1520,10 @@ static inline void ed_xmit(ifp)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_TXP | ED_CR_STA);
}
sc->xmit_busy = 1;
-
+
/*
* Point to next transmit buffer slot and wrap if necessary.
*/
@@ -1389,12 +1553,13 @@ ed_start(ifp)
struct ed_softc *sc = &ed_softc[ifp->if_unit];
struct mbuf *m0, *m;
caddr_t buffer;
- int len;
+ int len;
outloop:
+
/*
- * First, see if there are buffered packets and an idle
- * transmitter - should never happen at this point.
+ * First, see if there are buffered packets and an idle transmitter -
+ * should never happen at this point.
*/
if (sc->txb_inuse && (sc->xmit_busy == 0)) {
printf("ed: packets buffers, but transmitter idle\n");
@@ -1405,23 +1570,23 @@ outloop:
* See if there is room to put another packet in the buffer.
*/
if (sc->txb_inuse == sc->txb_cnt) {
+
/*
- * No room. Indicate this to the outside world
- * and exit.
+ * No room. Indicate this to the outside world and exit.
*/
ifp->if_flags |= IFF_OACTIVE;
return;
}
-
IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
if (m == 0) {
- /*
- * We are using the !OACTIVE flag to indicate to the outside
- * world that we can accept an additional packet rather than
- * that the transmitter is _actually_ active. Indeed, the
- * transmitter may be active, but if we haven't filled all
- * the buffers with data then we still want to accept more.
- */
+
+ /*
+ * We are using the !OACTIVE flag to indicate to the outside
+ * world that we can accept an additional packet rather than
+ * that the transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't filled all the
+ * buffers with data then we still want to accept more.
+ */
ifp->if_flags &= ~IFF_OACTIVE;
return;
}
@@ -1436,45 +1601,49 @@ outloop:
buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);
if (sc->mem_shared) {
+
/*
* Special case setup for 16 bit boards...
*/
if (sc->isa16bit) {
switch (sc->vendor) {
- /*
- * For 16bit 3Com boards (which have 16k of memory),
- * we have the xmit buffers in a different page
- * of memory ('page 0') - so change pages.
- */
+
+ /*
+ * For 16bit 3Com boards (which have 16k of
+ * memory), we have the xmit buffers in a
+ * different page of memory ('page 0') - so
+ * change pages.
+ */
case ED_VENDOR_3COM:
outb(sc->asic_addr + ED_3COM_GACFR,
- ED_3COM_GACFR_RSEL);
+ ED_3COM_GACFR_RSEL);
break;
- /*
- * Enable 16bit access to shared memory on WD/SMC boards
- * Don't update wd_laar_proto because we want to restore the
- * previous state (because an arp reply in the input code
- * may cause a call-back to ed_start)
- * XXX - the call-back to 'start' is a bug, IMHO.
- */
- case ED_VENDOR_WD_SMC: {
- outb(sc->asic_addr + ED_WD_LAAR,
- (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
- (void) inb(0x84);
- if (sc->is790) {
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+
+ /*
+ * Enable 16bit access to shared memory on
+ * WD/SMC boards Don't update wd_laar_proto
+ * because we want to restore the previous
+ * state (because an arp reply in the input
+ * code may cause a call-back to ed_start) XXX
+ * - the call-back to 'start' is a bug, IMHO.
+ */
+ case ED_VENDOR_WD_SMC:{
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
(void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ (void) inb(0x84);
+ break;
}
- (void) inb(0x84);
- break;
- }
}
}
-
for (len = 0; m != 0; m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
- len += m->m_len;
+ len += m->m_len;
}
/*
@@ -1484,23 +1653,23 @@ outloop:
switch (sc->vendor) {
case ED_VENDOR_3COM:
outb(sc->asic_addr + ED_3COM_GACFR,
- ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
+ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
break;
- case ED_VENDOR_WD_SMC: {
- outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
- (void) inb(0x84);
- if (sc->is790) {
- outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ case ED_VENDOR_WD_SMC:{
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
(void) inb(0x84);
+ break;
}
- break;
- }
}
}
} else {
len = ed_pio_write_mbufs(sc, m, buffer);
}
-
+
sc->txb_len[sc->txb_new] = MAX(len, ETHER_MIN_LEN);
sc->txb_inuse++;
@@ -1514,40 +1683,37 @@ outloop:
if (sc->xmit_busy == 0)
ed_xmit(ifp);
+
/*
- * If there is BPF support in the configuration, tap off here.
- * The following has support for converting trailer packets
- * back to normal.
- * XXX - support for trailer packets in BPF should be moved into
- * the bpf code proper to avoid code duplication in all of
- * the drivers.
+ * If there is BPF support in the configuration, tap off here. The
+ * following has support for converting trailer packets back to
+ * normal. XXX - support for trailer packets in BPF should be moved
+ * into the bpf code proper to avoid code duplication in all of the
+ * drivers.
*/
#if NBPFILTER > 0
if (sc->bpf) {
u_short etype;
- int off, datasize, resid;
+ int off, datasize, resid;
struct ether_header *eh;
struct trailer_header trailer_header;
- char ether_packet[ETHER_MAX_LEN];
- char *ep;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
ep = ether_packet;
/*
- * We handle trailers below:
- * Copy ether header first, then residual data,
- * then data. Put all this in a temporary buffer
- * 'ether_packet' and send off to bpf. Since the
- * system has generated this packet, we assume
- * that all of the offsets in the packet are
- * correct; if they're not, the system will almost
- * certainly crash in m_copydata.
- * We make no assumptions about how the data is
- * arranged in the mbuf chain (i.e. how much
- * data is in each mbuf, if mbuf clusters are
- * used, etc.), which is why we use m_copydata
- * to get the ether header rather than assume
- * that this is located in the first mbuf.
+ * We handle trailers below: Copy ether header first, then
+ * residual data, then data. Put all this in a temporary
+ * buffer 'ether_packet' and send off to bpf. Since the system
+ * has generated this packet, we assume that all of the
+ * offsets in the packet are correct; if they're not, the
+ * system will almost certainly crash in m_copydata. We make
+ * no assumptions about how the data is arranged in the mbuf
+ * chain (i.e. how much data is in each mbuf, if mbuf clusters
+ * are used, etc.), which is why we use m_copydata to get the
+ * ether header rather than assume that this is located in the
+ * first mbuf.
*/
/* copy ether header */
m_copydata(m0, 0, sizeof(struct ether_header), ep);
@@ -1555,17 +1721,17 @@ outloop:
ep += sizeof(struct ether_header);
etype = ntohs(eh->ether_type);
if (etype >= ETHERTYPE_TRAIL &&
- etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
datasize = ((etype - ETHERTYPE_TRAIL) << 9);
off = datasize + sizeof(struct ether_header);
/* copy trailer_header into a data structure */
m_copydata(m0, off, sizeof(struct trailer_header),
- (caddr_t)&trailer_header.ether_type);
+ (caddr_t) & trailer_header.ether_type);
/* copy residual data */
- m_copydata(m0, off+sizeof(struct trailer_header),
- resid = ntohs(trailer_header.ether_residual) -
+ m_copydata(m0, off + sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
sizeof(struct trailer_header), ep);
ep += resid;
@@ -1590,35 +1756,36 @@ outloop:
*/
goto outloop;
}
-
+
/*
* Ethernet interface receiver interrupt.
*/
static inline void
ed_rint(unit)
- int unit;
+ int unit;
{
register struct ed_softc *sc = &ed_softc[unit];
- u_char boundry, current;
+ u_char boundry, current;
u_short len;
struct ed_ring packet_hdr;
- char *packet_ptr;
+ char *packet_ptr;
/*
* Set NIC to page 1 registers to get 'current' pointer
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STA);
}
+
/*
- * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
- * it points to where new data has been buffered. The 'CURR'
- * (current) register points to the logical end of the ring-buffer
- * - i.e. it points to where additional new data will be added.
- * We loop here until the logical beginning equals the logical
- * end (or in other words, until the ring-buffer is empty).
+ * 'sc->next_packet' is the logical beginning of the ring-buffer -
+ * i.e. it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer -
+ * i.e. it points to where additional new data will be added. We loop
+ * here until the logical beginning equals the logical end (or in
+ * other words, until the ring-buffer is empty).
*/
while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
@@ -1628,25 +1795,28 @@ ed_rint(unit)
/*
* The byte count includes the FCS - Frame Check Sequence (a
- * 32 bit CRC).
+ * 32 bit CRC).
*/
if (sc->mem_shared)
- packet_hdr = *(struct ed_ring *)packet_ptr;
+ packet_hdr = *(struct ed_ring *) packet_ptr;
else
ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr,
- sizeof(packet_hdr));
+ sizeof(packet_hdr));
len = packet_hdr.count;
if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+
/*
* Go get packet. len - 4 removes CRC from length.
*/
ed_get_packet(sc, packet_ptr + 4, len - 4);
++sc->arpcom.ac_if.if_ipackets;
} else {
+
/*
- * Really BAD...probably indicates that the ring pointers
- * are corrupted. Also seen on early rev chips under
- * high load - the byte order of the length gets switched.
+ * Really BAD...probably indicates that the ring
+ * pointers are corrupted. Also seen on early rev
+ * chips under high load - the byte order of the
+ * length gets switched.
*/
log(LOG_ERR,
"ed%d: NIC memory corrupt - invalid packet length %d\n",
@@ -1662,8 +1832,8 @@ ed_rint(unit)
sc->next_packet = packet_hdr.next_packet;
/*
- * Update NIC boundry pointer - being careful to keep it
- * one buffer behind. (as recommended by NS databook)
+ * Update NIC boundry pointer - being careful to keep it one
+ * buffer behind. (as recommended by NS databook)
*/
boundry = sc->next_packet - 1;
if (boundry < sc->rec_page_start)
@@ -1675,18 +1845,18 @@ ed_rint(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
outb(sc->nic_addr + ED_P0_BNRY, boundry);
/*
- * Set NIC to page 1 registers before looping to top (prepare to
- * get 'CURR' current pointer)
+ * Set NIC to page 1 registers before looping to top (prepare
+ * to get 'CURR' current pointer)
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STA);
}
}
}
@@ -1696,10 +1866,10 @@ ed_rint(unit)
*/
void
edintr(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
- u_char isr;
+ u_char isr;
/*
* Set NIC to page 0 registers
@@ -1707,36 +1877,36 @@ edintr(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
* loop until there are no more new interrupts
*/
while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
/*
- * reset all the bits that we are 'acknowledging'
- * by writing a '1' to each bit position that was set
- * (writing a '1' *clears* the bit)
+ * reset all the bits that we are 'acknowledging' by writing a
+ * '1' to each bit position that was set (writing a '1'
+ * *clears* the bit)
*/
outb(sc->nic_addr + ED_P0_ISR, isr);
/*
- * Handle transmitter interrupts. Handle these first
- * because the receiver will reset the board under
- * some conditions.
+ * Handle transmitter interrupts. Handle these first because
+ * the receiver will reset the board under some conditions.
*/
- if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
- u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
+ if (isr & (ED_ISR_PTX | ED_ISR_TXE)) {
+ u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
/*
* Check for transmit error. If a TX completed with an
* error, we end up throwing the packet away. Really
* the only error that is possible is excessive
- * collisions, and in this case it is best to allow the
- * automatic mechanisms of TCP to backoff the flow. Of
- * course, with UDP we're screwed, but this is expected
- * when a network is heavily loaded.
+ * collisions, and in this case it is best to allow
+ * the automatic mechanisms of TCP to backoff the
+ * flow. Of course, with UDP we're screwed, but this
+ * is expected when a network is heavily loaded.
*/
(void) inb(sc->nic_addr + ED_P0_TSR);
if (isr & ED_ISR_TXE) {
@@ -1746,8 +1916,9 @@ edintr(unit)
*/
if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
&& (collisions == 0)) {
+
/*
- * When collisions total 16, the
+ * When collisions total 16, the
* P0_NCR will indicate 0, and the
* TSR_ABT is set.
*/
@@ -1759,9 +1930,10 @@ edintr(unit)
*/
++sc->arpcom.ac_if.if_oerrors;
} else {
+
/*
* Update total number of successfully
- * transmitted packets.
+ * transmitted packets.
*/
++sc->arpcom.ac_if.if_opackets;
}
@@ -1779,16 +1951,16 @@ edintr(unit)
/*
* Add in total number of collisions on last
- * transmission.
+ * transmission.
*/
sc->arpcom.ac_if.if_collisions += collisions;
/*
* Decrement buffer in-use count if not zero (can only
- * be zero if a transmitter interrupt occured while
- * not actually transmitting).
- * If data is ready to transmit, start it transmitting,
- * otherwise defer until after handling receiver
+ * be zero if a transmitter interrupt occured while
+ * not actually transmitting). If data is ready to
+ * transmit, start it transmitting, otherwise defer
+ * until after handling receiver
*/
if (sc->txb_inuse && --sc->txb_inuse)
ed_xmit(&sc->arpcom.ac_if);
@@ -1797,110 +1969,111 @@ edintr(unit)
/*
* Handle receiver interrupts
*/
- if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
- /*
- * Overwrite warning. In order to make sure that a lockup
- * of the local DMA hasn't occurred, we reset and
- * re-init the NIC. The NSC manual suggests only a
- * partial reset/re-init is necessary - but some
- * chips seem to want more. The DMA lockup has been
- * seen only with early rev chips - Methinks this
- * bug was fixed in later revs. -DG
- */
+ if (isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) {
+
+ /*
+ * Overwrite warning. In order to make sure that a
+ * lockup of the local DMA hasn't occurred, we reset
+ * and re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some chips
+ * seem to want more. The DMA lockup has been seen
+ * only with early rev chips - Methinks this bug was
+ * fixed in later revs. -DG
+ */
if (isr & ED_ISR_OVW) {
++sc->arpcom.ac_if.if_ierrors;
#ifdef DIAGNOSTIC
log(LOG_WARNING,
- "ed%d: warning - receiver ring buffer overrun\n",
- unit);
+ "ed%d: warning - receiver ring buffer overrun\n",
+ unit);
#endif
+
/*
* Stop/reset/re-init NIC
*/
ed_reset(unit, 0);
} else {
- /*
- * Receiver Error. One or more of: CRC error, frame
- * alignment error FIFO overrun, or missed packet.
- */
+ /*
+ * Receiver Error. One or more of: CRC error,
+ * frame alignment error FIFO overrun, or
+ * missed packet.
+ */
if (isr & ED_ISR_RXE) {
++sc->arpcom.ac_if.if_ierrors;
#ifdef ED_DEBUG
printf("ed%d: receive error %x\n", unit,
- inb(sc->nic_addr + ED_P0_RSR));
+ inb(sc->nic_addr + ED_P0_RSR));
#endif
}
/*
- * Go get the packet(s)
- * XXX - Doing this on an error is dubious
- * because there shouldn't be any data to
- * get (we've configured the interface to
- * not accept packets with errors).
+ * Go get the packet(s) XXX - Doing this on an
+ * error is dubious because there shouldn't be
+ * any data to get (we've configured the
+ * interface to not accept packets with
+ * errors).
*/
/*
* Enable 16bit access to shared memory first
- * on WD/SMC boards.
+ * on WD/SMC boards.
*/
if (sc->isa16bit &&
(sc->vendor == ED_VENDOR_WD_SMC)) {
outb(sc->asic_addr + ED_WD_LAAR,
(sc->wd_laar_proto |=
- ED_WD_LAAR_M16EN));
+ ED_WD_LAAR_M16EN));
(void) inb(0x84);
if (sc->is790) {
outb(sc->asic_addr + ED_WD_MSR,
- ED_WD_MSR_MENB);
+ ED_WD_MSR_MENB);
(void) inb(0x84);
}
}
-
- ed_rint (unit);
+ ed_rint(unit);
/* disable 16bit access */
if (sc->isa16bit &&
- (sc->vendor == ED_VENDOR_WD_SMC)) {
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
- outb(sc->asic_addr + ED_WD_LAAR,
- (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
- (void) inb(0x84);
if (sc->is790) {
outb(sc->asic_addr + ED_WD_MSR, 0x00);
(void) inb(0x84);
}
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
}
}
}
/*
* If it looks like the transmitter can take more data,
- * attempt to start output on the interface.
- * This is done after handling the receiver to
- * give the receiver priority.
+ * attempt to start output on the interface. This is done
+ * after handling the receiver to give the receiver priority.
*/
if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
ed_start(&sc->arpcom.ac_if);
/*
- * return NIC CR to standard state: page 0, remote DMA complete,
- * start (toggling the TXP bit off, even if was just set
- * in the transmit routine, is *okay* - it is 'edge'
- * triggered from low to high)
+ * return NIC CR to standard state: page 0, remote DMA
+ * complete, start (toggling the TXP bit off, even if was just
+ * set in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
- * If the Network Talley Counters overflow, read them to
- * reset them. It appears that old 8390's won't
- * clear the ISR flag otherwise - resulting in an
- * infinite loop.
+ * If the Network Talley Counters overflow, read them to reset
+ * them. It appears that old 8390's won't clear the ISR flag
+ * otherwise - resulting in an infinite loop.
*/
if (isr & ED_ISR_CNT) {
(void) inb(sc->nic_addr + ED_P0_CNTR0);
@@ -1909,7 +2082,7 @@ edintr(unit)
}
}
}
-
+
/*
* Process an ioctl request. This code needs some work - it looks
* pretty ugly.
@@ -1917,13 +2090,13 @@ edintr(unit)
int
ed_ioctl(ifp, command, data)
register struct ifnet *ifp;
- int command;
+ int command;
caddr_t data;
{
- register struct ifaddr *ifa = (struct ifaddr *)data;
+ register struct ifaddr *ifa = (struct ifaddr *) data;
struct ed_softc *sc = &ed_softc[ifp->if_unit];
- struct ifreq *ifr = (struct ifreq *)data;
- int s, error = 0;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
s = splimp();
@@ -1936,41 +2109,40 @@ ed_ioctl(ifp, command, data)
#ifdef INET
case AF_INET:
ed_init(ifp->if_unit); /* before arpwhohas */
+
/*
- * See if another station has *our* IP address.
- * i.e.: There is an address conflict! If a
- * conflict exists, a message is sent to the
- * console.
+ * See if another station has *our* IP address. i.e.:
+ * There is an address conflict! If a conflict exists,
+ * a message is sent to the console.
*/
- ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
- arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
break;
#endif
#ifdef NS
- /*
- * XXX - This code is probably wrong
- */
+
+ /*
+ * XXX - This code is probably wrong
+ */
case AF_NS:
- {
- register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
-
- if (ns_nullhost(*ina))
- ina->x_host =
- *(union ns_host *)(sc->arpcom.ac_enaddr);
- else {
- /*
- *
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *) (sc->arpcom.ac_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+
+ /*
+ * Set new address
*/
- bcopy((caddr_t)ina->x_host.c_host,
- (caddr_t)sc->arpcom.ac_enaddr,
- sizeof(sc->arpcom.ac_enaddr));
+ ed_init(ifp->if_unit);
+ break;
}
- /*
- * Set new address
- */
- ed_init(ifp->if_unit);
- break;
- }
#endif
default:
ed_init(ifp->if_unit);
@@ -1981,13 +2153,15 @@ ed_ioctl(ifp, command, data)
case SIOCGIFADDR:
{
struct sockaddr *sa;
- sa = (struct sockaddr *)&ifr->ifr_data;
- bcopy((caddr_t)sc->arpcom.ac_enaddr,
- (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+
+ sa = (struct sockaddr *) & ifr->ifr_data;
+ bcopy((caddr_t) sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
}
break;
case SIOCSIFFLAGS:
+
/*
* If interface is marked down and it is running, then stop it
*/
@@ -1996,37 +2170,42 @@ ed_ioctl(ifp, command, data)
ed_stop(ifp->if_unit);
ifp->if_flags &= ~IFF_RUNNING;
} else {
- /*
- * If interface is marked up and it is stopped, then start it
- */
+
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it
+ */
if ((ifp->if_flags & IFF_UP) &&
- ((ifp->if_flags & IFF_RUNNING) == 0))
+ ((ifp->if_flags & IFF_RUNNING) == 0))
ed_init(ifp->if_unit);
}
+#ifndef MULTICAST
#if NBPFILTER > 0
if (ifp->if_flags & IFF_PROMISC) {
+
/*
- * Set promiscuous mode on interface.
- * XXX - for multicasts to work, we would need to
- * write 1's in all bits of multicast
- * hashing array. For now we assume that
- * this was done in ed_init().
+ * Set promiscuous mode on interface. XXX - for
+ * multicasts to work, we would need to write 1's in
+ * all bits of multicast hashing array. For now we
+ * assume that this was done in ed_init().
*/
outb(sc->nic_addr + ED_P0_RCR,
- ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
+ ED_RCR_PRO | ED_RCR_AM | ED_RCR_AB);
} else {
+
/*
* XXX - for multicasts to work, we would need to
- * rewrite the multicast hashing array with the
- * proper hash (would have been destroyed above).
+ * rewrite the multicast hashing array with the proper
+ * hash (would have been destroyed above).
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
}
#endif
+
/*
- * An unfortunate hack to provide the (required) software control
- * of the tranceiver for 3Com boards. The ALTPHYS flag disables
- * the tranceiver if set.
+ * An unfortunate hack to provide the (required) software
+ * control of the tranceiver for 3Com boards. The ALTPHYS flag
+ * disables the tranceiver if set.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
@@ -2035,16 +2214,37 @@ ed_ioctl(ifp, command, data)
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
-
break;
+#else
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+
+ /*
+ * Update out multicast list.
+ */
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti((struct ifreq *) data, &sc->arpcom) :
+ ether_delmulti((struct ifreq *) data, &sc->arpcom);
+ if (error == ENETRESET) {
+
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ ed_stop(ifp->if_unit); /* XXX for ds_setmcaf? */
+ ed_init(ifp->if_unit);
+ error = 0;
+ }
+ break;
+#endif
default:
error = EINVAL;
}
(void) splx(s);
return (error);
}
-
+
/*
* Macro to calculate a new address within shared memory when given an offset
* from an address, taking into account ring-wrap.
@@ -2062,13 +2262,13 @@ ed_ioctl(ifp, command, data)
static void
ed_get_packet(sc, buf, len)
struct ed_softc *sc;
- char *buf;
+ char *buf;
u_short len;
{
struct ether_header *eh;
- struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
+ struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
u_short off;
- int resid;
+ int resid;
u_short etype;
struct trailer_header trailer_header;
@@ -2086,8 +2286,8 @@ ed_get_packet(sc, buf, len)
#define EOFF (EROUND - sizeof(struct ether_header))
/*
- * The following assumes there is room for
- * the ether header in the header mbuf
+ * The following assumes there is room for the ether header in the
+ * header mbuf
*/
head->m_data += EOFF;
eh = mtod(head, struct ether_header *);
@@ -2101,18 +2301,16 @@ ed_get_packet(sc, buf, len)
head->m_len += sizeof(struct ether_header);
len -= sizeof(struct ether_header);
- etype = ntohs((u_short)eh->ether_type);
+ etype = ntohs((u_short) eh->ether_type);
/*
- * Deal with trailer protocol:
- * If trailer protocol, calculate the datasize as 'off',
- * which is also the offset to the trailer header.
- * Set resid to the amount of packet data following the
- * trailer header.
- * Finally, copy residual data into mbuf chain.
+ * Deal with trailer protocol: If trailer protocol, calculate the
+ * datasize as 'off', which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the trailer
+ * header. Finally, copy residual data into mbuf chain.
*/
if (etype >= ETHERTYPE_TRAIL &&
- etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
off = (etype - ETHERTYPE_TRAIL) << 9;
if ((off + sizeof(struct trailer_header)) > len)
@@ -2120,14 +2318,15 @@ ed_get_packet(sc, buf, len)
/*
* If we have shared memory, we can get info directly from the
- * stored packet, otherwise we must get a local copy
- * of the trailer header using PIO.
+ * stored packet, otherwise we must get a local copy of the
+ * trailer header using PIO.
*/
if (sc->mem_shared) {
eh->ether_type = *ringoffset(sc, buf, off, u_short *);
- resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+ resid = ntohs(*ringoffset(sc, buf, off + 2, u_short *));
} else {
struct trailer_header trailer_header;
+
ed_pio_readmem(sc,
ringoffset(sc, buf, off, caddr_t),
(char *) &trailer_header,
@@ -2136,30 +2335,35 @@ ed_get_packet(sc, buf, len)
resid = trailer_header.ether_residual;
}
- if ((off + resid) > len) goto bad; /* insanity */
+ if ((off + resid) > len)
+ goto bad; /* insanity */
resid -= sizeof(struct trailer_header);
- if (resid < 0) goto bad; /* insanity */
+ if (resid < 0)
+ goto bad; /* insanity */
- m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *),
+ m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off + 4, char *),
head, resid);
- if (m == 0) goto bad;
+ if (m == 0)
+ goto bad;
len = off;
- head->m_pkthdr.len -= 4; /* subtract trailer header */
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
}
/*
- * Pull packet off interface. Or if this was a trailer packet,
- * the data portion is appended.
+ * Pull packet off interface. Or if this was a trailer packet, the
+ * data portion is appended.
*/
m = ed_ring_to_mbuf(sc, buf, m, len);
- if (m == 0) goto bad;
+ if (m == 0)
+ goto bad;
#if NBPFILTER > 0
+
/*
- * Check if there's a BPF listener on this interface.
- * If so, hand off the raw packet to bpf.
+ * Check if there's a BPF listener on this interface. If so, hand off
+ * the raw packet to bpf.
*/
if (sc->bpf) {
bpf_mtap(sc->bpf, head);
@@ -2168,17 +2372,17 @@ ed_get_packet(sc, buf, len)
* Note that the interface cannot be in promiscuous mode if
* there are no BPF listeners. And if we are in promiscuous
* mode, we have to check if this packet is really ours.
- *
+ *
* XXX This test does not support multicasts.
*/
if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- sizeof(eh->ether_dhost)) != 0 &&
+ sizeof(eh->ether_dhost)) != 0 &&
bcmp(eh->ether_dhost, etherbroadcastaddr,
sizeof(eh->ether_dhost)) != 0) {
- m_freem(head);
- return;
+ m_freem(head);
+ return;
}
}
#endif
@@ -2213,8 +2417,8 @@ bad: if (head)
* This routine is currently Novell-specific.
*/
void
-ed_pio_readmem(sc,src,dst,amount)
- struct ed_softc *sc;
+ed_pio_readmem(sc, src, dst, amount)
+ struct ed_softc *sc;
unsigned short src;
unsigned char *dst;
unsigned short amount;
@@ -2222,24 +2426,25 @@ ed_pio_readmem(sc,src,dst,amount)
unsigned short tmp_amount;
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* round up to a word */
tmp_amount = amount;
- if (amount & 1) ++amount;
+ if (amount & 1)
+ ++amount;
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, amount);
- outb(sc->nic_addr + ED_P0_RBCR1, amount>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, amount >> 8);
/* set up source address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, src);
- outb(sc->nic_addr + ED_P0_RSAR1, src>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, src >> 8);
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);
if (sc->isa16bit) {
- insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2);
+ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount / 2);
} else
insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount);
@@ -2251,41 +2456,42 @@ ed_pio_readmem(sc,src,dst,amount)
* be even.
*/
void
-ed_pio_writemem(sc,src,dst,len)
+ed_pio_writemem(sc, src, dst, len)
struct ed_softc *sc;
- char *src;
+ char *src;
unsigned short dst;
unsigned short len;
{
- int maxwait=100; /* about 120us */
+ int maxwait = 100; /* about 120us */
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* reset remote DMA complete flag */
outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, len);
- outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
/* set up destination address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, dst);
- outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
/* set remote DMA write */
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
if (sc->isa16bit)
- outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2);
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len / 2);
else
outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+
/*
* Wait for remote DMA complete. This is necessary because on the
- * transmit side, data is handled internally by the NIC in bursts
- * and we can't start another remote DMA until this one completes.
- * Not waiting causes really bad things to happen - like the NIC
- * irrecoverably jamming the ISA bus.
+ * transmit side, data is handled internally by the NIC in bursts and
+ * we can't start another remote DMA until this one completes. Not
+ * waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
}
@@ -2295,7 +2501,7 @@ ed_pio_writemem(sc,src,dst,len)
* programmed I/O.
*/
u_short
-ed_pio_write_mbufs(sc,m,dst)
+ed_pio_write_mbufs(sc, m, dst)
struct ed_softc *sc;
struct mbuf *m;
unsigned short dst;
@@ -2303,40 +2509,40 @@ ed_pio_write_mbufs(sc,m,dst)
unsigned short len, mb_offset;
struct mbuf *mp;
unsigned char residual[2];
- int maxwait=100; /* about 120us */
+ int maxwait = 100; /* about 120us */
/* First, count up the total number of bytes to copy */
for (len = 0, mp = m; mp; mp = mp->m_next)
len += mp->m_len;
-
+
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* reset remote DMA complete flag */
outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, len);
- outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
/* set up destination address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, dst);
- outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
/* set remote DMA write */
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
mb_offset = 0;
+
/*
- * Transfer the mbuf chain to the NIC memory.
- * The following code isn't too pretty. The problem is that we can only
- * transfer words to the board, and if an mbuf has an odd number
- * of bytes in it, this is a problem. It's not a simple matter of
- * just removing a byte from the next mbuf (adjusting data++ and
- * len--) because this will hose-over the mbuf chain which might
- * be needed later for BPF. Instead, we maintain an offset
- * (mb_offset) which let's us skip over the first byte in the
- * following mbuf.
+ * Transfer the mbuf chain to the NIC memory. The following code isn't
+ * too pretty. The problem is that we can only transfer words to the
+ * board, and if an mbuf has an odd number of bytes in it, this is a
+ * problem. It's not a simple matter of just removing a byte from the
+ * next mbuf (adjusting data++ and len--) because this will hose-over
+ * the mbuf chain which might be needed later for BPF. Instead, we
+ * maintain an offset (mb_offset) which let's us skip over the first
+ * byte in the following mbuf.
*/
while (m) {
if (m->m_len - mb_offset) {
@@ -2347,24 +2553,27 @@ ed_pio_write_mbufs(sc,m,dst)
(m->m_len - mb_offset) / 2);
/*
- * if odd number of bytes, get the odd byte from
- * the next mbuf with data
+ * if odd number of bytes, get the odd byte
+ * from the next mbuf with data
*/
if ((m->m_len - mb_offset) & 1) {
/* first the last byte in current mbuf */
residual[0] = *(mtod(m, caddr_t) +
- m->m_len - 1);
-
+ m->m_len - 1);
+
/* advance past any empty mbufs */
while (m->m_next && (m->m_next->m_len == 0))
m = m->m_next;
if (m->m_next) {
- /* remove first byte in next mbuf */
+
+ /*
+ * remove first byte in next
+ * mbuf
+ */
residual[1] = *(mtod(m->m_next, caddr_t));
mb_offset = 1;
}
-
outw(sc->asic_addr + ED_NOVELL_DATA,
*((unsigned short *) residual));
} else
@@ -2378,10 +2587,10 @@ ed_pio_write_mbufs(sc,m,dst)
/*
* Wait for remote DMA complete. This is necessary because on the
- * transmit side, data is handled internally by the NIC in bursts
- * and we can't start another remote DMA until this one completes.
- * Not waiting causes really bad things to happen - like the NIC
- * irrecoverably jamming the ISA bus.
+ * transmit side, data is handled internally by the NIC in bursts and
+ * we can't start another remote DMA until this one completes. Not
+ * waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
@@ -2390,23 +2599,22 @@ ed_pio_write_mbufs(sc,m,dst)
sc->arpcom.ac_if.if_unit);
ed_reset(sc->arpcom.ac_if.if_unit, 0);
}
-
- return(len);
+ return (len);
}
-
+
/*
* Given a source and destination address, copy 'amount' of a packet from
* the ring buffer into a linear destination buffer. Takes into account
* ring-wrap.
*/
static inline char *
-ed_ring_copy(sc,src,dst,amount)
+ed_ring_copy(sc, src, dst, amount)
struct ed_softc *sc;
- char *src;
- char *dst;
- u_short amount;
+ char *src;
+ char *dst;
+ u_short amount;
{
- u_short tmp_amount;
+ u_short tmp_amount;
/* does copy wrap to lower addr in ring buffer? */
if (src + amount > sc->mem_end) {
@@ -2414,21 +2622,20 @@ ed_ring_copy(sc,src,dst,amount)
/* copy amount up to end of NIC memory */
if (sc->mem_shared)
- bcopy(src,dst,tmp_amount);
+ bcopy(src, dst, tmp_amount);
else
- ed_pio_readmem(sc,src,dst,tmp_amount);
+ ed_pio_readmem(sc, src, dst, tmp_amount);
amount -= tmp_amount;
src = sc->mem_ring;
dst += tmp_amount;
}
-
if (sc->mem_shared)
bcopy(src, dst, amount);
else
ed_pio_readmem(sc, src, dst, amount);
- return(src + amount);
+ return (src + amount);
}
/*
@@ -2441,9 +2648,9 @@ ed_ring_copy(sc,src,dst,amount)
* amount = amount of data to copy
*/
struct mbuf *
-ed_ring_to_mbuf(sc,src,dst,total_len)
+ed_ring_to_mbuf(sc, src, dst, total_len)
struct ed_softc *sc;
- char *src;
+ char *src;
struct mbuf *dst;
u_short total_len;
{
@@ -2452,18 +2659,19 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
while (total_len) {
register u_short amount = min(total_len, M_TRAILINGSPACE(m));
- if (amount == 0) { /* no more data in this mbuf, alloc another */
+ if (amount == 0) { /* no more data in this mbuf, alloc
+ * another */
+
/*
- * If there is enough data for an mbuf cluster, attempt
- * to allocate one of those, otherwise, a regular
- * mbuf will do.
- * Note that a regular mbuf is always required, even if
- * we get a cluster - getting a cluster does not
- * allocate any mbufs, and one is needed to assign
- * the cluster to. The mbuf that has a cluster
- * extension can not be used to contain data - only
- * the cluster can contain data.
- */
+ * If there is enough data for an mbuf cluster,
+ * attempt to allocate one of those, otherwise, a
+ * regular mbuf will do. Note that a regular mbuf is
+ * always required, even if we get a cluster - getting
+ * a cluster does not allocate any mbufs, and one is
+ * needed to assign the cluster to. The mbuf that has
+ * a cluster extension can not be used to contain data
+ * - only the cluster can contain data.
+ */
dst = m;
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0)
@@ -2476,7 +2684,6 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
dst->m_next = m;
amount = min(total_len, M_TRAILINGSPACE(m));
}
-
src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
m->m_len += amount;
@@ -2485,4 +2692,62 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
}
return (m);
}
+#ifdef MULTICAST
+/*
+ * Compute crc for ethernet address
+ */
+u_long
+ds_crc(ep)
+ u_char *ep;
+{
+#define POLYNOMIAL 0x04c11db6
+ register u_long crc = 0xffffffffL;
+ register int carry, i, j;
+ register u_char b;
+
+ for (i = 6; --i >= 0;) {
+ b = *ep++;
+ for (j = 8; --j >= 0;) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry)
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ return crc;
+#undef POLYNOMIAL
+}
+
+/*
+ * Compute the multicast address filter from the
+ * list of multicast addresses we need to listen to.
+ */
+void
+ds_getmcaf(sc, mcaf)
+ struct ed_softc *sc;
+ u_long *mcaf;
+{
+ register u_int index;
+ register u_char *af = (u_char *) mcaf;
+ register struct ether_multi *enm;
+ register struct ether_multistep step;
+
+ mcaf[0] = 0;
+ mcaf[1] = 0;
+
+ ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ mcaf[0] = 0xffffffff;
+ mcaf[1] = 0xffffffff;
+ return;
+ }
+ index = ds_crc(enm->enm_addrlo, 6) >> 26;
+ af[index >> 3] |= 1 << (index & 7);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+}
+#endif
#endif
diff --git a/sys/i386/isa/if_edreg.h b/sys/i386/isa/if_edreg.h
index 49f7816a4d4e..d2a03f5b508b 100644
--- a/sys/i386/isa/if_edreg.h
+++ b/sys/i386/isa/if_edreg.h
@@ -1,7 +1,7 @@
/*
* National Semiconductor DS8390 NIC register definitions
*
- * $Id: if_edreg.h,v 1.13.2.1 1994/04/17 06:07:24 rgrimes Exp $
+ * $Id: if_edreg.h,v 1.14 1994/04/10 20:06:28 davidg Exp $
*
* Modification history
*
diff --git a/sys/i386/isa/if_el.c b/sys/i386/isa/if_el.c
new file mode 100644
index 000000000000..d0de274baf73
--- /dev/null
+++ b/sys/i386/isa/if_el.c
@@ -0,0 +1,800 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software provided that both
+ * the copyright notice and this permission notice appear in all copies
+ * of the software, derivative works or modified versions, and any
+ * portions thereof.
+ *
+ * Questions, comments, bug reports and fixes to kimmel@cs.umass.edu.
+ */
+/* Except of course for the portions of code lifted from other FreeBSD
+ * drivers (mainly elread, elget and el_ioctl)
+ */
+/* 3COM Etherlink 3C501 device driver for FreeBSD */
+/* Yeah, I know these cards suck, but you can also get them for free
+ * really easily...
+ */
+/* Bugs/possible improvements:
+ * - Does not currently support DMA
+ * - Does not currently support multicasts
+ */
+#include "el.h"
+#if NEL > 0
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_elreg.h"
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+
+/* For debugging convenience */
+#ifdef EL_DEBUG
+#define dprintf(x) printf x
+#else
+#define dprintf(x)
+#endif
+
+/* el_softc: per line info and status */
+struct el_softc {
+ struct arpcom arpcom; /* Ethernet common */
+ u_short el_base; /* Base I/O addr */
+ caddr_t bpf; /* BPF magic cookie */
+ char el_pktbuf[EL_BUFSIZ]; /* Frame buffer */
+} el_softc[NEL];
+
+/* Prototypes */
+int el_attach(struct isa_device *);
+void el_init(int);
+void elintr(int);
+int el_ioctl(struct ifnet *,int,caddr_t);
+int el_probe(struct isa_device *);
+void el_start(struct ifnet *);
+void el_reset(int,int);
+void el_watchdog(int);
+
+static void el_stop(int);
+static int el_xmit(struct el_softc *,int);
+static inline void elread(struct el_softc *,caddr_t,int);
+static struct mbuf *elget(caddr_t,int,int,struct ifnet *);
+static inline void el_hardreset(int);
+
+/* isa_driver structure for autoconf */
+struct isa_driver eldriver = {
+ el_probe, el_attach, "el"
+};
+
+/* Probe routine. See if the card is there and at the right place. */
+int el_probe(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ u_short base; /* Just for convenience */
+ u_char station_addr[ETHER_ADDR_LEN];
+ int i;
+
+ /* Grab some info for our structure */
+ sc = &el_softc[idev->id_unit];
+ sc->el_base = idev->id_iobase;
+ base = sc->el_base;
+
+ /* First check the base */
+ if((base < 0x280) || (base > 0x3f0)) {
+ printf("el%d: ioaddr must be between 0x280 and 0x3f0\n",
+ idev->id_unit);
+ return(0);
+ }
+
+ /* Now attempt to grab the station address from the PROM
+ * and see if it contains the 3com vendor code.
+ */
+ dprintf(("Probing 3c501 at 0x%x...\n",base));
+
+ /* Reset the board */
+ dprintf(("Resetting board...\n"));
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+ dprintf(("Reading station address...\n"));
+ /* Now read the address */
+ for(i=0;i<ETHER_ADDR_LEN;i++) {
+ outb(base+EL_GPBL,i);
+ station_addr[i] = inb(base+EL_EAW);
+ }
+ dprintf(("Address is %s\n",ether_sprintf(station_addr)));
+
+ /* If the vendor code is ok, return a 1. We'll assume that
+ * whoever configured this system is right about the IRQ.
+ */
+ if((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
+ || (station_addr[2] != 0x8c)) {
+ dprintf(("Bad vendor code.\n"));
+ return(0);
+ } else {
+ dprintf(("Vendor code ok.\n"));
+ /* Copy the station address into the arpcom structure */
+ bcopy(station_addr,sc->arpcom.ac_enaddr,ETHER_ADDR_LEN);
+ return(1);
+ }
+}
+
+/* Attach the interface to the kernel data structures. By the time
+ * this is called, we know that the card exists at the given I/O address.
+ * We still assume that the IRQ given is correct.
+ */
+int el_attach(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+ u_short base;
+ int t;
+
+ dprintf(("Attaching el%d...\n",idev->id_unit));
+
+ /* Get things pointing to the right places. */
+ sc = &el_softc[idev->id_unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* Now reset the board */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(idev->id_unit);
+
+ /* Initialize ifnet structure */
+ ifp->if_unit = idev->id_unit;
+ ifp->if_name = "el";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = el_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = el_start;
+ ifp->if_ioctl = el_ioctl;
+ ifp->if_reset = el_reset;
+ ifp->if_watchdog = el_watchdog;
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /* Now we can attach the interface */
+ dprintf(("Attaching interface...\n"));
+ if_attach(ifp);
+
+ /* Put the station address in the ifa address list's AF_LINK
+ * entry, if any.
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != NULL) && (ifa->ifa_addr != NULL) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ if((ifa != NULL) && (ifa->ifa_addr != NULL)) {
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr,LLADDR(sdl),ETHER_ADDR_LEN);
+ }
+
+ /* Print out some information for the user */
+ printf("el%d: 3c501 address %s\n",idev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ /* Finally, attach to bpf filter if it is present. */
+#if NBPFILTER > 0
+ dprintf(("Attaching to BPF...\n"));
+ bpfattach(&sc->bpf,ifp,DLT_EN10MB,sizeof(struct ether_header));
+#endif
+
+ dprintf(("el_attach() finished.\n"));
+ return(1);
+}
+
+/* This routine resets the interface. */
+void el_reset(int unit,int uban)
+{
+ int s;
+
+ dprintf(("elreset()\n"));
+ s = splimp();
+ el_stop(unit);
+ el_init(unit);
+ splx(s);
+}
+
+static void el_stop(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+ outb(sc->el_base+EL_AC,0);
+}
+
+/* Do a hardware reset of the 3c501. Do not call until after el_probe()! */
+static inline void el_hardreset(int unit)
+{
+ register struct el_softc *sc;
+ register int base;
+ register int j;
+
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ /* First reset the board */
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+
+ /* Then give it back its ethernet address. Thanks to the mach
+ * source code for this undocumented goodie...
+ */
+ for(j=0;j<ETHER_ADDR_LEN;j++)
+ outb(base+j,sc->arpcom.ac_enaddr[j]);
+}
+
+/* Initialize interface. */
+void el_init(int unit)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ int s;
+ u_short base;
+
+ /* Set up pointers */
+ sc = &el_softc[unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* If address not known, do nothing. */
+ if(ifp->if_addrlist == (struct ifaddr *)0)
+ return;
+
+ s = splimp();
+
+ /* First, reset the board. */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(unit);
+
+ /* Configure rx */
+ dprintf(("Configuring rx...\n"));
+ if(ifp->if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ outb(base+EL_RBC,0);
+
+ /* Configure TX */
+ dprintf(("Configuring tx...\n"));
+ outb(base+EL_TXC,0);
+
+ /* Start reception */
+ dprintf(("Starting reception...\n"));
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+
+ /* Set flags appropriately */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* And start output. */
+ el_start(ifp);
+
+ splx(s);
+}
+
+/* Start output on interface. Get datagrams from the queue and output
+ * them, giving the receiver a chance between datagrams. Call only
+ * from splimp or interrupt level!
+ */
+void el_start(struct ifnet *ifp)
+{
+ struct el_softc *sc;
+ u_short base;
+ struct mbuf *m, *m0;
+ int s, i, len, retries, done;
+
+ /* Get things pointing in the right directions */
+ sc = &el_softc[ifp->if_unit];
+ base = sc->el_base;
+
+ dprintf(("el_start()...\n"));
+ s = splimp();
+
+ /* Don't do anything if output is active */
+ if(sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
+ return;
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+
+ /* The main loop. They warned me against endless loops, but
+ * would I listen? NOOO....
+ */
+ while(1) {
+ /* Dequeue the next datagram */
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd,m0);
+
+ /* If there's nothing to send, return. */
+ if(m0 == NULL) {
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+
+ /* Disable the receiver */
+ outb(base+EL_AC,EL_AC_HOST);
+ outb(base+EL_RBC,0);
+
+ /* Copy the datagram to the buffer. */
+ len = 0;
+ for(m = m0; m != NULL; m = m->m_next) {
+ if(m->m_len == 0)
+ continue;
+ bcopy(mtod(m,caddr_t),sc->el_pktbuf+len,m->m_len);
+ len += m->m_len;
+ }
+ m_freem(m0);
+
+ len = MAX(len,ETHER_MIN_LEN);
+
+ /* Give the packet to the bpf, if any */
+#if NBPFILTER > 0
+ if(sc->bpf)
+ bpf_tap(sc->bpf,sc->el_pktbuf,len);
+#endif
+
+ /* Transfer datagram to board */
+ dprintf(("el: xfr pkt length=%d...\n",len));
+ i = EL_BUFSIZ - len;
+ outb(base+EL_GPBL,(i & 0xff));
+ outb(base+EL_GPBH,((i>>8)&0xff));
+ outsb(base+EL_BUF,sc->el_pktbuf,len);
+
+ /* Now transmit the datagram */
+ retries=0;
+ done=0;
+ while(!done) {
+ if(el_xmit(sc,len)) { /* Something went wrong */
+ done = -1;
+ break;
+ }
+ /* Check out status */
+ i = inb(base+EL_TXS);
+ dprintf(("tx status=0x%x\n",i));
+ if(!(i & EL_TXS_READY)) {
+ dprintf(("el: err txs=%x\n",i));
+ sc->arpcom.ac_if.if_oerrors++;
+ if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {
+ if((!(i & EL_TXC_DCOLL16)) && retries < 15) {
+ retries++;
+ outb(base+EL_AC,EL_AC_HOST);
+ }
+ }
+ else
+ done = 1;
+ }
+ else {
+ sc->arpcom.ac_if.if_opackets++;
+ done = 1;
+ }
+ }
+ if(done == -1) /* Packet not transmitted */
+ continue;
+
+ /* Now give the card a chance to receive.
+ * Gotta love 3c501s...
+ */
+ (void)inb(base+EL_AS);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ splx(s);
+ /* Interrupt here */
+ s = splimp();
+ }
+}
+
+/* This function actually attempts to transmit a datagram downloaded
+ * to the board. Call at splimp or interrupt, after downloading data!
+ * Returns 0 on success, non-0 on failure
+ */
+static int el_xmit(struct el_softc *sc,int len)
+{
+ int gpl;
+ int i;
+
+ gpl = EL_BUFSIZ - len;
+ dprintf(("el: xmit..."));
+ outb((sc->el_base)+EL_GPBL,(gpl & 0xff));
+ outb((sc->el_base)+EL_GPBH,((gpl>>8)&0xff));
+ outb((sc->el_base)+EL_AC,EL_AC_TXFRX);
+ i = 20000;
+ while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))
+ i--;
+ if(i == 0) {
+ dprintf(("tx not ready\n"));
+ sc->arpcom.ac_if.if_oerrors++;
+ return(-1);
+ }
+ dprintf(("%d cycles.\n",(20000-i)));
+ return(0);
+}
+
+/* controller interrupt */
+void elintr(int unit)
+{
+ register struct el_softc *sc;
+ register base;
+ int stat, rxstat, len, done;
+
+ /* Get things pointing properly */
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ dprintf(("elintr: "));
+
+ /* Check board status */
+ stat = inb(base+EL_AS);
+ if(stat & EL_AS_RXBUSY) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ done = 0;
+ while(!done) {
+ rxstat = inb(base+EL_RXS);
+ if(rxstat & EL_RXS_STALE) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* If there's an overflow, reinit the board. */
+ if(!(rxstat & EL_RXS_NOFLOW)) {
+ dprintf(("overflow.\n"));
+ el_hardreset(unit);
+ /* Put board back into receive mode */
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* Incoming packet */
+ len = inb(base+EL_RBL);
+ len |= inb(base+EL_RBH) << 8;
+ dprintf(("receive len=%d rxstat=%x ",len,rxstat));
+ outb(base+EL_AC,EL_AC_HOST);
+
+ /* If packet too short or too long, restore rx mode and return
+ */
+ if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) {
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ sc->arpcom.ac_if.if_ipackets++;
+
+ /* Copy the data into our buffer */
+ outb(base+EL_GPBL,0);
+ outb(base+EL_GPBH,0);
+ insb(base+EL_BUF,sc->el_pktbuf,len);
+ outb(base+EL_RBC,0);
+ outb(base+EL_AC,EL_AC_RX);
+ dprintf(("%s-->",ether_sprintf(sc->el_pktbuf+6)));
+ dprintf(("%s\n",ether_sprintf(sc->el_pktbuf)));
+
+ /* Pass data up to upper levels */
+ len -= sizeof(struct ether_header);
+ elread(sc,(caddr_t)(sc->el_pktbuf),len);
+
+ /* Is there another packet? */
+ stat = inb(base+EL_AS);
+
+ /* If so, do it all again (i.e. don't set done to 1) */
+ if(!(stat & EL_AS_RXBUSY))
+ dprintf(("<rescan> "));
+ else
+ done = 1;
+ }
+
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+}
+
+/* Pass a packet up to the higher levels. Deal with trailer protocol. */
+static inline void elread(struct el_softc *sc,caddr_t buf,int len)
+{
+ register struct ether_header *eh;
+ struct mbuf *m;
+ int off, resid;
+
+ /* Deal with trailer protocol: if type is trailer type
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+ eh = (struct ether_header *)buf;
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+#define eldataaddr(eh,off,type) ((type)(((caddr_t)((eh)+1)+(off))))
+ if(eh->ether_type >= ETHERTYPE_TRAIL &&
+ eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
+ if(off >= ETHERMTU)
+ return;
+ eh->ether_type = ntohs(*eldataaddr(eh,off,u_short *));
+ resid = ntohs(*(eldataaddr(eh,off+2,u_short *)));
+ if((off+resid) > len)
+ return;
+ len = off + resid;
+ }
+ else
+ off = 0;
+
+ if(len <= 0)
+ return;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a bpf filter listening on this interface.
+ * If so, hand off the raw packet to bpf, which must deal with
+ * trailers in its own way.
+ */
+ if(sc->bpf) {
+ eh->ether_type = htons((u_short)eh->ether_type);
+ bpf_tap(sc->bpf,buf,len+sizeof(struct ether_header));
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no bpf listeners. And if el are in promiscuous
+ * mode, el have to check if this packet is really ours.
+ *
+ * This test does not support multicasts.
+ */
+ if((sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ && bcmp(eh->ether_dhost,sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0
+ && bcmp(eh->ether_dhost,etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0)
+ return;
+ }
+#endif
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; neget will then force this header
+ * information to be at the front, but we still have to drop
+ * the type and length which are at the front of any trailer data.
+ */
+ m = elget(buf,len,off,&sc->arpcom.ac_if);
+ if(m == 0)
+ return;
+
+ ether_input(&sc->arpcom.ac_if,eh,m);
+}
+
+/*
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+struct mbuf *
+elget(buf, totlen, off0, ifp)
+ caddr_t buf;
+ int totlen, off0;
+ struct ifnet *ifp;
+{
+ struct mbuf *top, **mp, *m, *p;
+ int off = off0, len;
+ register caddr_t cp = buf;
+ char *epkt;
+
+ buf += sizeof(struct ether_header);
+ cp = buf;
+ epkt = cp + totlen;
+
+
+ if (off) {
+ cp += off + 2 * sizeof(u_short);
+ totlen -= 2 * sizeof(u_short);
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ m->m_len = MHLEN;
+ top = 0;
+ mp = &top;
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ m->m_len = MLEN;
+ }
+ len = min(totlen, epkt - cp);
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = len = min(len, MCLBYTES);
+ else
+ len = m->m_len;
+ } else {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (len < m->m_len) {
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+ }
+ bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ totlen -= len;
+ if (cp == epkt)
+ cp = buf;
+ }
+ return (top);
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+el_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct el_softc *sc = &el_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ el_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ el_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ el_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ el_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ el_init(ifp->if_unit);
+ }
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/* Device timeout routine */
+void el_watchdog(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+
+ log(LOG_ERR,"el%d: device timeout\n",unit);
+ sc->arpcom.ac_if.if_oerrors++;
+ el_reset(unit,0);
+}
+#endif
diff --git a/sys/i386/isa/if_elreg.h b/sys/i386/isa/if_elreg.h
new file mode 100644
index 000000000000..806d6ff68d1b
--- /dev/null
+++ b/sys/i386/isa/if_elreg.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software provided that both
+ * the copyright notice and this permission notice appear in all copies
+ * of the software, derivative works or modified versions, and any
+ * portions thereof.
+ */
+/* 3COM Etherlink 3C501 Register Definitions */
+
+/* I/O Ports */
+#define EL_RXS 0x6 /* Receive status register */
+#define EL_RXC 0x6 /* Receive command register */
+#define EL_TXS 0x7 /* Transmit status register */
+#define EL_TXC 0x7 /* Transmit command register */
+#define EL_GPBL 0x8 /* GP buffer ptr low byte */
+#define EL_GPBH 0x9 /* GP buffer ptr high byte */
+#define EL_RBL 0xa /* Receive buffer ptr low byte */
+#define EL_RBC 0xa /* Receive buffer clear */
+#define EL_RBH 0xb /* Receive buffer ptr high byte */
+#define EL_EAW 0xc /* Ethernet address window */
+#define EL_AS 0xe /* Auxillary status register */
+#define EL_AC 0xe /* Auxillary command register */
+#define EL_BUF 0xf /* Data buffer */
+
+/* Receive status register bits */
+#define EL_RXS_OFLOW 0x01 /* Overflow error */
+#define EL_RXS_FCS 0x02 /* FCS error */
+#define EL_RXS_DRIB 0x04 /* Dribble error */
+#define EL_RXS_SHORT 0x08 /* Short frame */
+#define EL_RXS_NOFLOW 0x10 /* No overflow */
+#define EL_RXS_GOOD 0x20 /* Received good frame */
+#define EL_RXS_STALE 0x80 /* Stale receive status */
+
+/* Receive command register bits */
+#define EL_RXC_DISABLE 0x00 /* Receiver disabled */
+#define EL_RXC_DOFLOW 0x01 /* Detect overflow */
+#define EL_RXC_DFCS 0x02 /* Detect FCS errs */
+#define EL_RXC_DDRIB 0x04 /* Detect dribble errors */
+#define EL_RXC_DSHORT 0x08 /* Detect short frames */
+#define EL_RXC_DNOFLOW 0x10 /* Detect frames w/o overflow ??? */
+#define EL_RXC_AGF 0x20 /* Accept Good Frames */
+#define EL_RXC_PROMISC 0x40 /* Promiscuous mode */
+#define EL_RXC_ABROAD 0x80 /* Accept address, broadcast */
+#define EL_RXC_AMULTI 0xc0 /* Accept address, multicast */
+
+/* Transmit status register bits */
+#define EL_TXS_UFLOW 0x01 /* Underflow */
+#define EL_TXS_COLL 0x02 /* Collision */
+#define EL_TXS_COLL16 0x04 /* Collision 16 */
+#define EL_TXS_READY 0x08 /* Ready for new frame */
+
+/* Transmit command register bits */
+#define EL_TXC_DUFLOW 0x01 /* Detect underflow */
+#define EL_TXC_DCOLL 0x02 /* Detect collisions */
+#define EL_TXC_DCOLL16 0x04 /* Detect collision 16 */
+#define EL_TXC_DSUCCESS 0x08 /* Detect success */
+
+/* Auxillary status register bits */
+#define EL_AS_RXBUSY 0x01 /* Receive busy */
+#define EL_AS_DMADONE 0x10 /* DMA finished */
+#define EL_AS_TXBUSY 0x80 /* Transmit busy */
+
+/* Auxillary command register bits */
+#define EL_AC_HOST 0x00 /* System bus can access buffer */
+#define EL_AC_IRQE 0x01 /* IRQ enable */
+#define EL_AC_TXBAD 0x02 /* Transmit frames with bad FCS */
+#define EL_AC_TXFRX 0x04 /* Transmit followed by receive */
+#define EL_AC_RX 0x08 /* Receive */
+#define EL_AC_LB 0x0c /* Loopback */
+#define EL_AC_DRQ 0x20 /* DMA request */
+#define EL_AC_RIDE 0x40 /* DRQ and IRQ enabled */
+#define EL_AC_RESET 0x80 /* Reset */
+
+/* Packet buffer size */
+#define EL_BUFSIZ 2048
+
+#define ETHER_ADDR_LEN 6
diff --git a/sys/i386/isa/if_ep.c b/sys/i386/isa/if_ep.c
index 43edd4529485..44e9c9fc0d58 100644
--- a/sys/i386/isa/if_ep.c
+++ b/sys/i386/isa/if_ep.c
@@ -8,7 +8,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -22,62 +22,56 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
- * $Id: if_ep.c,v 1.7 1994/02/03 11:51:06 davidg Exp $
- */
-/*
- * TODO:
- * Multi-509 configs.
- * don't pass unit into epstop.
- * epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows?
- * deallocate mbufs when ifconfig'd down.
+ * $Id: if_ep.c,v 1.9 1994/05/02 22:27:33 ats Exp $
*/
+
#include "ep.h"
#if NEP > 0
#include "bpfilter.h"
-#include "sys/param.h"
+#include <sys/param.h>
#if defined(__FreeBSD__)
-#include "sys/systm.h"
-#include "sys/kernel.h"
+#include <sys/systm.h>
+#include <sys/kernel.h>
#endif
-#include "sys/mbuf.h"
-#include "sys/socket.h"
-#include "sys/ioctl.h"
-#include "sys/errno.h"
-#include "sys/syslog.h"
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
#if defined(__NetBSD__)
-#include "sys/select.h"
+#include <sys/select.h>
#endif
-#include "net/if.h"
-#include "net/if_dl.h"
-#include "net/if_types.h"
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
#ifdef INET
-#include "netinet/in.h"
-#include "netinet/in_systm.h"
-#include "netinet/in_var.h"
-#include "netinet/ip.h"
-#include "netinet/if_ether.h"
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
#endif
#ifdef NS
-#include "netns/ns.h"
-#include "netns/ns_if.h"
+#include <netns/ns.h>
+#include <netns/ns_if.h>
#endif
#if NBPFILTER > 0
-#include "net/bpf.h"
-#include "net/bpfdesc.h"
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
#endif
-#include "machine/pio.h"
+#include <machine/pio.h>
-#include "i386/isa/isa.h"
-#include "i386/isa/isa_device.h"
-#include "i386/isa/icu.h"
-#include "i386/isa/if_epreg.h"
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/if_epreg.h>
#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518
@@ -90,12 +84,13 @@ struct ep_softc {
struct arpcom arpcom; /* Ethernet common part */
short ep_io_addr; /* i/o bus address */
char ep_connectors; /* Connectors on this card. */
-#define MAX_MBS 4 /* # of mbufs we keep around */
+#define MAX_MBS 8 /* # of mbufs we keep around */
struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
int next_mb; /* Which mbuf to use next. */
int last_mb; /* Last mbuf. */
int tx_start_thresh; /* Current TX_start_thresh. */
caddr_t bpf; /* BPF "magic cookie" */
+ char bus32bit; /* 32bit access possible */
} ep_softc[NEP];
static int epprobe __P((struct isa_device *));
@@ -104,7 +99,8 @@ static int epioctl __P((struct ifnet * ifp, int, caddr_t));
void epinit __P((int));
void epintr __P((int));
-void epmbufqueue __P((caddr_t, int));
+void epmbuffill __P((caddr_t, int));
+void epmbufempty __P((struct ep_softc *));
void epread __P((struct ep_softc *));
void epreset __P((int));
void epstart __P((struct ifnet *));
@@ -274,7 +270,7 @@ epinit(unit)
return;
s = splimp();
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
GO_WINDOW(0);
@@ -350,7 +346,7 @@ epinit(unit)
*/
sc->last_mb = 0;
sc->next_mb = 0;
- epmbufqueue((caddr_t)sc, 0);
+ epmbuffill((caddr_t)sc, 0);
epstart(ifp);
@@ -421,10 +417,19 @@ startagain:
outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
for (top = m; m != 0; m = m->m_next) {
- outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
- if (m->m_len & 1)
- outb(BASE + EP_W1_TX_PIO_WR_1,
- *(mtod(m, caddr_t) + m->m_len - 1));
+ if (sc->bus32bit) {
+ outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
+ m->m_len/4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + m->m_len/4,
+ m->m_len & 3);
+ } else {
+ outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
}
while (pad--)
outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
@@ -658,7 +663,7 @@ epread(sc)
if (m == 0)
goto out;
} else {
- timeout(epmbufqueue, (caddr_t)sc, 0);
+ timeout(epmbuffill, (caddr_t)sc, 0);
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
}
if (totlen >= MINCLSIZE)
@@ -667,11 +672,22 @@ epread(sc)
mcur->m_next = m;
lenthisone = min(totlen, M_TRAILINGSPACE(m));
}
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
- lenthisone / 2);
- m->m_len += lenthisone;
- if (lenthisone & 1)
- *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ if (sc->bus32bit) {
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
totlen -= lenthisone;
}
if (off) {
@@ -679,15 +695,17 @@ epread(sc)
sc->mb[sc->next_mb] = 0;
if (top == 0) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (top == 0)
+ if (top == 0) {
+ top = m0;
goto out;
+ }
} else {
/* Convert one of our saved mbuf's */
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
top->m_data = top->m_pktdat;
top->m_flags = M_PKTHDR;
}
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
sizeof(struct ether_header));
top->m_next = m0;
top->m_len = sizeof(struct ether_header);
@@ -700,7 +718,7 @@ epread(sc)
top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
++sc->arpcom.ac_if.if_ipackets;
#if NBPFILTER > 0
@@ -728,12 +746,11 @@ epread(sc)
return;
out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
if (top)
m_freem(top);
- return;
}
@@ -773,7 +790,7 @@ epioctl(ifp, cmd, data)
else {
ifp->if_flags &= ~IFF_RUNNING;
bcopy((caddr_t) ina->x_host.c_host,
- (caddr_t)sc->arpcom.ns_addr
+ (caddr_t)sc->arpcom.ac_enaddr,
sizeof(sc->arpcom.ac_enaddr));
}
epinit(ifp->if_unit);
@@ -789,6 +806,7 @@ epioctl(ifp, cmd, data)
if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
ifp->if_flags &= ~IFF_RUNNING;
epstop(ifp->if_unit);
+ epmbufempty(sc);
break;
}
if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
@@ -815,7 +833,6 @@ epreset(unit)
epstop(unit);
epinit(unit);
splx(s);
- return;
}
void
@@ -838,7 +855,7 @@ epstop(unit)
outw(BASE + EP_COMMAND, RX_DISABLE);
outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
outw(BASE + EP_COMMAND, TX_DISABLE);
outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
@@ -848,7 +865,6 @@ epstop(unit)
outw(BASE + EP_COMMAND, SET_RD_0_MASK);
outw(BASE + EP_COMMAND, SET_INTR_MASK);
outw(BASE + EP_COMMAND, SET_RX_FILTER);
- return;
}
@@ -937,24 +953,42 @@ is_eeprom_busy(is)
}
void
-epmbufqueue(sp, dummy_arg)
+epmbuffill(sp, dummy_arg)
caddr_t sp;
int dummy_arg;
{
struct ep_softc *sc = (struct ep_softc *)sp;
- int i;
+ int s, i;
- if (sc->mb[sc->last_mb])
- return;
+ s = splimp();
i = sc->last_mb;
do {
- MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
- if (!sc->mb[i])
+ if(sc->mb[i] == NULL)
+ MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
+ if(sc->mb[i] == NULL)
break;
i = (i + 1) % MAX_MBS;
} while (i != sc->next_mb);
sc->last_mb = i;
- return;
+ splx(s);
+}
+
+static void
+epmbufempty(sc)
+ struct ep_softc *sc;
+{
+ int s, i;
+
+ s = splimp();
+ for (i = 0; i<MAX_MBS; i++) {
+ if (sc->mb[i]) {
+ m_freem(sc->mb[i]);
+ sc->mb[i] = NULL;
+ }
+ }
+ sc->last_mb = sc->next_mb = 0;
+ untimeout(epmbuffill, sc);
+ splx(s);
}
#endif /* NEP > 0 */
diff --git a/sys/i386/isa/if_ie507.h b/sys/i386/isa/if_ie507.h
new file mode 100644
index 000000000000..4bf87fcbb597
--- /dev/null
+++ b/sys/i386/isa/if_ie507.h
@@ -0,0 +1,19 @@
+/*
+ * $Id: if_ie507.h,v 1.1 1994/05/25 20:06:49 ats Exp $
+ * Definitions for 3C507
+ */
+
+#define IE507_CTRL 6 /* control port */
+#define IE507_ICTRL 10 /* interrupt control */
+#define IE507_ATTN 11 /* any write here sends a chan attn */
+#define IE507_MADDR 14 /* shared memory configuration */
+#define IE507_IRQ 15 /* IRQ configuration */
+
+#define EL_CTRL_BNK1 0x01 /* register bank 1 */
+#define EL_CTRL_IEN 0x04 /* interrupt enable */
+#define EL_CTRL_INTL 0x08 /* interrupt active latch */
+#define EL_CTRL_16BIT 0x10 /* bus width; clear = 8-bit, set = 16-bit */
+#define EL_CTRL_LOOP 0x20 /* loopback mode */
+#define EL_CTRL_NRST 0x80 /* turn off to reset */
+#define EL_CTRL_RESET (EL_CTRL_LOOP)
+#define EL_CTRL_NORMAL (EL_CTRL_NRST | EL_CTRL_IEN | EL_CTRL_BNK1)
diff --git a/sys/i386/isa/if_is.c b/sys/i386/isa/if_is.c
index 341885f36ed1..234a0d937c1f 100644
--- a/sys/i386/isa/if_is.c
+++ b/sys/i386/isa/if_is.c
@@ -332,15 +332,15 @@ is_attach(isa_dev)
* are only 16 bits wide!
*/
-#define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) \
+#define ISMAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) \
+ sizeof(struct init_block) + 8)
- is->init_block = (struct init_block *)malloc(MAXMEM,M_TEMP,M_NOWAIT);
+ is->init_block = (struct init_block *)malloc(ISMAXMEM,M_TEMP,M_NOWAIT);
if (!is->init_block) {
printf("is%d : Couldn't allocate memory for card\n",unit);
}
/*
* XXX -- should take corrective action if not
- * quadword alilgned, the 8 byte slew factor in MAXMEM
+ * quadword alilgned, the 8 byte slew factor in ISMAXMEM
* allows for this.
*/
@@ -483,7 +483,7 @@ is_init(unit)
/* Address not known */
if (ifp->if_addrlist == (struct ifaddr *)0) return;
- s = splnet();
+ s = splimp();
/*
* Lance must be stopped
@@ -984,7 +984,7 @@ is_ioctl(ifp, cmd, data)
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
- s = splnet();
+ s = splimp();
switch (cmd) {
diff --git a/sys/i386/isa/if_ze.c b/sys/i386/isa/if_ze.c
new file mode 100644
index 000000000000..6ffb96c96dbc
--- /dev/null
+++ b/sys/i386/isa/if_ze.c
@@ -0,0 +1,1951 @@
+/*-
+ * TODO:
+ * [1] integrate into current if_ed.c
+ * [2] parse tuples to find out where to map the shared memory buffer,
+ * and what to write into the configuration register
+ * [3] move pcic-specific code into a separate module.
+ *
+ * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet,
+ * if_ze.c
+ *
+ * Based on the Device driver for National Semiconductor DS8390 ethernet
+ * adapters by David Greenman. Modifications for PCMCIA by Keith Moore.
+ * Adapted for FreeBSD 1.1.5 by Jordan Hubbard.
+ *
+ * Currently supports only the IBM Credit Card Adapter for Ethernet, but
+ * could probably work with other PCMCIA cards also, if it were modified
+ * to get the locations of the PCMCIA configuration option register (COR)
+ * by parsing the configuration tuples, rather than by hard-coding in
+ * the value expected by IBM's card.
+ *
+ * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver:
+ *
+ * [1] _Local Area Network Credit Card Adapters Technical Reference_,
+ * IBM Corp., SC30-3585-00, part # 33G9243.
+ * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan.
+ * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel
+ * Order Number 290423-002
+ * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network
+ * Interface Controller for Twisted Pair data sheet.
+ *
+ *
+ * Copyright (C) 1993, David Greenman. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided
+ * that the above copyright and these terms are retained. Under no
+ * circumstances is the author responsible for the proper functioning
+ * of this software, nor does the author assume any responsibility
+ * for damages incurred with its use.
+ */
+
+#include "ze.h"
+#if NZE > 0
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+#include "net/netisr.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_zereg.h"
+
+#include "i386/include/pio.h"
+
+
+
+/*****************************************************************************
+ * pcmcia controller chip (PCIC) support *
+ * (eventually, move this to a separate file) *
+ *****************************************************************************/
+#include "ic/i82365.h"
+
+/*
+ * Each PCIC chip (82365SL or clone) can handle two card slots, and there
+ * can be up to four PCICs in a system. (On some machines, not all of the
+ * address lines are decoded, so a card may appear to be in more than one
+ * slot.)
+ */
+#define MAXSLOT 8
+
+/*
+ * To access a register on the PCIC for a particular slot, you
+ * first write the correct OFFSET value for that slot in the
+ * INDEX register for the PCIC controller. You then read or write
+ * the value from or to the DATA register for that controller.
+ *
+ * The first pair of chips shares I/O addresss for DATA and INDEX,
+ * as does the second pair. (To the programmer, it looks like each
+ * pair is a single chip.) The i/o port addresses are hard-wired
+ * into the PCIC; so the following addresses should be valid for
+ * any machine that uses this chip.
+ */
+
+#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */
+#define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */
+#define PCIC_INDEX_1 0x3E2 /* index reg, chips 1 and 2 */
+#define PCIC_DATA_1 0x3E3 /* data register, chips 1 and 2 */
+
+/*
+ * Given a slot number, calculate the INDEX and DATA registers
+ * to talk to that slot. OFFSET is added to the register number
+ * to address the registers for a particular slot.
+ */
+#define INDEX(slot) ((slot) < 4 ? PCIC_INDEX_0 : PCIC_INDEX_1)
+#define DATA(slot) ((slot) < 4 ? PCIC_DATA_0 : PCIC_DATA_1)
+#define OFFSET(slot) ((slot) % 4 * 0x40)
+
+/*
+ * There are 5 sets (windows) of memory mapping registers on the PCIC chip
+ * for each slot, numbered 0..4.
+ *
+ * They start at 10/50 hex within the chip's register space (not system
+ * I/O space), and are eight addresses apart. These are actually pairs of
+ * 8-bit-wide registers (low byte first, then high byte) since the
+ * address fields are actually 12 bits long. The upper bits are used
+ * for other things like 8/16-bit select and wait states.
+ *
+ * Memory mapping registers include start/stop addresses to define the
+ * region to be mapped (in terms of system memory addresses), and
+ * an offset register to allow for translation from system space
+ * to card space. The lower 12 bits aren't included in these, so memory is
+ * mapped in 4K chunks.
+ */
+#define MEM_START_ADDR(window) (((window) * 0x08) + 0x10)
+#define MEM_STOP_ADDR(window) (((window) * 0x08) + 0x12)
+#define MEM_OFFSET(window) (((window) * 0x08) + 0x14)
+/*
+ * this bit gets set in the address window enable register (PCIC_ADDRWINE)
+ * to enable a particular address window.
+ */
+#define MEM_ENABLE_BIT(window) ((1) << (window))
+
+/*
+ * There are two i/o port addressing windows. I/O ports cannot be
+ * relocated within system i/o space (unless the card doesn't decode
+ * all of the address bits); unlike card memory, there is no address
+ * translation offset.
+ */
+#define IO_START_ADDR(window) ((window) ? PCIC_IO1_STL : PCIC_IO0_STL)
+#define IO_STOP_ADDR(window) ((window) ? PCIC_IO1_SPL : PCIC_IO0_SPL)
+#define IO_ENABLE_BIT(window) ((window) ? PCIC_IO1_EN : PCIC_IO0_EN)
+#define IO_CS16_BIT(window) ((window) ? PCIC_IO1_CS16 : PCIC_IO0_CS16)
+
+/*
+ * read a byte from a pcic register for a particular slot
+ */
+static inline unsigned char
+pcic_getb (int slot, int reg)
+{
+ outb (INDEX(slot), OFFSET (slot) + reg);
+ return inb (DATA (slot));
+}
+
+/*
+ * write a byte to a pcic register for a particular slot
+ */
+static inline void
+pcic_putb (int slot, int reg, unsigned char val)
+{
+ outb (INDEX(slot), OFFSET (slot) + reg);
+ outb (DATA (slot), val);
+}
+
+/*
+ * read a word from a pcic register for a particular slot
+ */
+static inline unsigned short
+pcic_getw (int slot, int reg)
+{
+ return pcic_getb (slot, reg) | (pcic_getb (slot, reg+1) << 8);
+}
+
+/*
+ * write a word to a pcic register at a particular slot
+ */
+static inline void
+pcic_putw (int slot, int reg, unsigned short val)
+{
+ pcic_putb (slot, reg, val & 0xff);
+ pcic_putb (slot, reg + 1, (val >> 8) & 0xff);
+}
+
+static void
+pcic_print_regs (int slot)
+{
+ int i, j;
+
+ for (i = 0; i < 0x40; i += 16) {
+ for (j = 0; j < 16; ++j)
+ printf ("%02x ", pcic_getb (slot, i + j));
+ printf ("\n");
+ }
+}
+
+/*
+ * map a portion of the card's memory space into system memory
+ * space.
+ *
+ * slot = # of the slot the card is plugged into
+ * window = which pcic memory map registers to use (0..4)
+ * sys_addr = base system PHYSICAL memory address where we want it. must
+ * be on an appropriate boundary (lower 12 bits are zero).
+ * card_addr = the base address of the card's memory to correspond
+ * to sys_addr
+ * length = length of the segment to map (may be rounded up as necessary)
+ * type = which card memory space to map (attribute or shared)
+ * width = 1 for byte-wide mapping; 2 for word (16-bit) mapping.
+ */
+
+enum memtype { COMMON, ATTRIBUTE };
+
+static void
+pcic_map_memory (int slot, int window, unsigned long sys_addr,
+ unsigned long card_addr, unsigned long length,
+ enum memtype type, int width)
+{
+ unsigned short offset;
+ unsigned short mem_start_addr;
+ unsigned short mem_stop_addr;
+
+ sys_addr >>= 12;
+ card_addr >>= 12;
+ length >>= 12;
+ /*
+ * compute an offset for the chip such that
+ * (sys_addr + offset) = card_addr
+ * but the arithmetic is done modulo 2^14
+ */
+ offset = (card_addr - sys_addr) & 0x3FFF;
+ /*
+ * now OR in the bit for "attribute memory" if necessary
+ */
+ if (type == ATTRIBUTE) {
+ offset |= (PCIC_REG << 8);
+ /* REG == "region active" pin on card */
+ }
+ /*
+ * okay, set up the chip memory mapping registers, and turn
+ * on the enable bit for this window.
+ * if we are doing 16-bit wide accesses (width == 2),
+ * turn on the appropriate bit.
+ *
+ * XXX for now, we set all of the wait state bits to zero.
+ * Not really sure how they should be set.
+ */
+ mem_start_addr = sys_addr & 0xFFF;
+ if (width == 2)
+ mem_start_addr |= (PCIC_DATA16 << 8);
+ mem_stop_addr = (sys_addr + length) & 0xFFF;
+
+ pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr);
+ pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr);
+ pcic_putw (slot, MEM_OFFSET(window), offset);
+ /*
+ * Assert the bit (PCIC_MEMCS16) that says to decode all of
+ * the address lines.
+ */
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) |
+ MEM_ENABLE_BIT(window) | PCIC_MEMCS16);
+}
+
+static void
+pcic_unmap_memory (int slot, int window)
+{
+ /*
+ * seems like we need to turn off the enable bit first, after which
+ * we can clear the registers out just to be sure.
+ */
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window));
+ pcic_putw (slot, MEM_START_ADDR(window), 0);
+ pcic_putw (slot, MEM_STOP_ADDR(window), 0);
+ pcic_putw (slot, MEM_OFFSET(window), 0);
+}
+
+/*
+ * map a range of addresses into system i/o space
+ * (no translation of i/o addresses is possible)
+ *
+ * 'width' is:
+ * + 0 to tell the PCIC to generate the ISA IOCS16* signal from
+ * the PCMCIA IOIS16* signal.
+ * + 1 to select 8-bit width
+ * + 2 to select 16-bit width
+ */
+
+static void
+pcic_map_io (int slot, int window, unsigned short base, unsigned short length,
+ unsigned short width)
+{
+ unsigned char x;
+
+ pcic_putw (slot, IO_START_ADDR(window), base);
+ pcic_putw (slot, IO_STOP_ADDR(window), base+length-1);
+ /*
+ * select the bits that determine whether
+ * an i/o operation is 8 or 16 bits wide
+ */
+ x = pcic_getb (slot, PCIC_IOCTL);
+ switch (width) {
+ case 0: /* PCMCIA card decides */
+ if (window)
+ x = (x & 0xf0) | PCIC_IO1_CS16;
+ else
+ x = (x & 0x0f) | PCIC_IO0_CS16;
+ break;
+ case 1: /* 8 bits wide */
+ break;
+ case 2: /* 16 bits wide */
+ if (window)
+ x = (x & 0xf0) | PCIC_IO1_16BIT;
+ else
+ x = (x & 0x0f) | PCIC_IO0_16BIT;
+ break;
+ }
+ pcic_putb (slot, PCIC_IOCTL, x);
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) | IO_ENABLE_BIT(window));
+}
+
+#ifdef TEST
+static void
+pcic_unmap_io (int slot, int window)
+{
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) & ~IO_ENABLE_BIT(window));
+ pcic_putw (slot, IO_START_ADDR(window), 0);
+ pcic_putw (slot, IO_STOP_ADDR(window), 0);
+}
+#endif /* TEST */
+
+/*
+ * tell the PCIC which irq we want to use. only the following are legal:
+ * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15
+ *
+ * NB: 'irq' is an interrupt NUMBER, not a MASK as in struct isa_device.
+ */
+
+static void
+pcic_map_irq (int slot, int irq)
+{
+ if (irq < 3 || irq == 6 || irq == 8 || irq == 13 || irq > 15) {
+ printf ("ze: pcic_map_irq (slot %d): illegal irq %d\n", slot, irq);
+ return;
+ }
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | (irq & 0x0F));
+}
+
+static void
+pcic_power_on (int slot)
+{
+ pcic_putb (slot, PCIC_POWER,
+ pcic_getb (slot, PCIC_POWER) | PCIC_DISRST | PCIC_PCPWRE);
+ DELAY (50000);
+ pcic_putb (slot, PCIC_POWER,
+ pcic_getb (slot, PCIC_POWER) | PCIC_OUTENA);
+}
+
+static void
+pcic_reset (int slot)
+{
+ /* assert RESET (by clearing a bit!), wait a bit, and de-assert it */
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) & ~PCIC_CARDRESET);
+ DELAY (50000);
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDRESET);
+}
+
+
+/*****************************************************************************
+ * Driver for Ethernet Adapter *
+ *****************************************************************************/
+/*
+ * ze_softc: per line info and status
+ */
+struct ze_softc {
+ struct arpcom arpcom; /* ethernet common */
+
+ char *type_str; /* pointer to type string */
+ char *mau; /* type of media access unit */
+#if 0
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
+#endif
+
+#if 0
+ u_short vector; /* interrupt vector */
+#endif
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
+
+ caddr_t smem_start; /* shared memory start address */
+ caddr_t smem_end; /* shared memory end address */
+ u_long smem_size; /* total shared memory size */
+ caddr_t smem_ring; /* start of RX ring-buffer (in smem) */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+
+ u_char memwidth; /* width of access to card mem 8 or 16 */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* Number of transmit buffers */
+ u_char txb_next; /* Pointer to next buffer ready to xmit */
+ u_short txb_next_len; /* next xmit buffer length */
+ u_char data_buffered; /* data has been buffered in interface memory */
+ u_char tx_page_start; /* first page of TX buffer area */
+
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ze_softc[NZE];
+
+int ze_attach(), ze_ioctl(), ze_probe();
+void ze_init(), ze_start(), ze_stop(), ze_intr();
+void ze_reset(), ze_watchdog(), ze_get_packet();
+
+static inline void ze_rint();
+static inline void ze_xmit();
+static inline char *ze_ring_copy();
+
+extern int ether_output();
+
+struct isa_driver zedriver = {
+ ze_probe,
+ ze_attach,
+ "ze"
+};
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+#define ETHER_HDR_SIZE 14
+
+static unsigned char enet_addr[6];
+static unsigned char card_info[256];
+
+#define CARD_INFO "IBM Corp.~Ethernet~0933495"
+
+/*
+ * scan the card information structure looking for the version/product info
+ * tuple. when we find it, compare it to the string we are looking for.
+ * return 1 if we find it, 0 otherwise.
+ */
+
+static int
+ze_check_cis (unsigned char *scratch)
+{
+ int i,j,k;
+
+ card_info[0] = '\0';
+ i = 0;
+ while (scratch[i] != 0xff && i < 1024) {
+ unsigned char link = scratch[i+2];
+
+#if 0
+ printf ("[%02x] %02x ", i, link);
+ for (j = 4; j < 2 * link + 4 && j < 32; j += 2)
+ printf ("%02x ", scratch[j + i]);
+ printf ("\n");
+#endif
+ if (scratch[i] == 0x15) {
+ /*
+ * level 1 version/product info
+ * copy to card_info, translating '\0' to '~'
+ */
+ k = 0;
+ for (j = i+8; scratch[j] != 0xff; j += 2)
+ card_info[k++] = scratch[j] == '\0' ? '~' : scratch[j];
+ card_info[k++] = '\0';
+ return (memcmp (card_info, CARD_INFO, sizeof(CARD_INFO)-1) == 0);
+ }
+ i += 4 + 2 * link;
+ }
+ return 0;
+}
+
+/*
+ * Probe each slot looking for an IBM Credit Card Adapter for Ethernet
+ * For each card that we find, map its card information structure
+ * into system memory at 'scratch' and see whether it's one of ours.
+ * Return the slot number if we find a card, or -1 otherwise.
+ *
+ * Side effects:
+ * + On success, leaves CIS mapped into memory at 'scratch';
+ * caller must free it.
+ * + On success, leaves ethernet address in enet_addr.
+ * + Leaves product/vendor id of last card probed in 'card_info'
+ */
+
+static int
+ze_find_adapter (unsigned char *scratch)
+{
+ int slot;
+
+ for (slot = 0; slot < MAXSLOT; ++slot) {
+ /*
+ * see if there's a PCMCIA controller here
+ * Intel PCMCIA controllers use 0x82 and 0x83
+ * IBM clone chips use 0x88 and 0x89, apparently
+ */
+ unsigned char idbyte = pcic_getb (slot, PCIC_ID_REV);
+
+ if (idbyte != 0x82 && idbyte != 0x83 &&
+ idbyte != 0x88 && idbyte != 0x89) {
+#if 0
+ printf ("ibmccae: pcic slot %d: wierd id/rev code 0x%02x\n",
+ slot, idbyte);
+#endif
+ continue;
+ }
+ if ((pcic_getb (slot, PCIC_STATUS) & PCIC_CD) != PCIC_CD) {
+ printf ("ze: slot %d: no card in slot\n", slot);
+ /* no card in slot */
+ continue;
+ }
+ pcic_power_on (slot);
+ pcic_reset (slot);
+ /*
+ * map the card's attribute memory and examine its
+ * card information structure tuples for something
+ * we recognize.
+ */
+ pcic_map_memory (slot, 0, kvtop (scratch), 0L,
+ 0xFFFL, ATTRIBUTE, 1);
+
+ if ((ze_check_cis (scratch)) > 0) {
+ /* found it */
+ printf ("ze: found card in slot %d\n", slot);
+ return slot;
+ }
+ else
+ printf ("ze: pcmcia slot %d: %s\n", slot, card_info);
+ pcic_unmap_memory (slot, 0);
+ }
+ return -1;
+}
+
+
+/*
+ * macros to handle casting unsigned long to (char *) so we can
+ * read/write into physical memory space.
+ */
+
+#define PEEK(addr) (*((unsigned char *)(addr)))
+#define POKE(addr,val) do { PEEK(addr) = (val); } while (0)
+
+/*
+ * Determine if the device is present
+ *
+ * on entry:
+ * a pointer to an isa_device struct
+ * on exit:
+ * NULL if device not found
+ * or # of i/o addresses used (if found)
+ */
+int
+ze_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ze_softc *sc = &ze_softc[isa_dev->id_unit];
+ int i, x;
+ u_int memsize;
+ u_char iptr, memwidth, sum, tmp;
+ int slot;
+
+ if ((slot = ze_find_adapter (isa_dev->id_maddr)) < 0)
+ return NULL;
+
+ /*
+ * okay, we found a card, so set it up
+ */
+ /*
+ * Inhibit 16 bit memory delay.
+ * POINTETH.SYS apparently does this, for what reason I don't know.
+ */
+ pcic_putb (slot, PCIC_CDGC,
+ pcic_getb (slot, PCIC_CDGC) | PCIC_16_DL_INH);
+ /*
+ * things to map
+ * (1) card's EEPROM is already mapped by the find_adapter routine
+ * but we still need to get the card's ethernet address.
+ * after that we unmap that part of attribute memory.
+ * (2) card configuration registers need to be mapped in so we
+ * can set the configuration and socket # registers.
+ * (3) shared memory packet buffer
+ * (4) i/o ports
+ * (5) IRQ
+ */
+ /*
+ * Sigh. Location of the ethernet address isn't documented in [1].
+ * It was derived by doing a hex dump of all of attribute memory
+ * and looking for the IBM vendor prefix.
+ */
+ enet_addr[0] = PEEK(isa_dev->id_maddr+0xff0);
+ enet_addr[1] = PEEK(isa_dev->id_maddr+0xff2);
+ enet_addr[2] = PEEK(isa_dev->id_maddr+0xff4);
+ enet_addr[3] = PEEK(isa_dev->id_maddr+0xff6);
+ enet_addr[4] = PEEK(isa_dev->id_maddr+0xff8);
+ enet_addr[5] = PEEK(isa_dev->id_maddr+0xffa);
+ pcic_unmap_memory (slot, 0);
+
+ /*
+ * (2) map card configuration registers. these are offset
+ * in card memory space by 0x20000. normally we could get
+ * this offset from the card information structure, but I'm
+ * too lazy and am not quite sure if I understand the CIS anyway.
+ *
+ * XXX IF YOU'RE TRYING TO PORT THIS DRIVER FOR A DIFFERENT
+ * PCMCIA CARD, the most likely thing to change is the constant
+ * 0x20000 in the next statement. Oh yes, also change the
+ * card id string that we probe for.
+ */
+ pcic_map_memory (slot, 0, kvtop (isa_dev->id_maddr), 0x20000, 8L,
+ ATTRIBUTE, 1);
+ POKE(isa_dev->id_maddr, 0x80); /* reset the card (how long?) */
+ DELAY (10000);
+ /*
+ * Set the configuration index. According to [1], the adapter won't
+ * respond to any i/o signals until we do this; it uses the
+ * Memory Only interface (whatever that is; it's not documented).
+ * Also turn on "level" (not pulse) interrupts.
+ *
+ * XXX probably should init the socket and copy register also,
+ * so that we can deal with multiple instances of the same card.
+ */
+ POKE(isa_dev->id_maddr, 0x41);
+ pcic_unmap_memory (slot, 0);
+
+ /*
+ * (3) now map in the shared memory buffer. This has to be mapped
+ * as words, not bytes, and on a 16k boundary. The offset value
+ * was derived by installing IBM's POINTETH.SYS under DOS and
+ * looking at the PCIC registers; it's not documented in IBM's
+ * tech ref manual ([1]).
+ */
+ pcic_map_memory (slot, 0, kvtop (isa_dev->id_maddr), 0x4000L, 0x4000L,
+ COMMON, 2);
+
+ /*
+ * (4) map i/o ports.
+ *
+ * XXX is it possible that the config file leaves this unspecified,
+ * in which case we have to pick one?
+ *
+ * At least one PCMCIA device driver I'v seen maps a block
+ * of 32 consecutive i/o ports as two windows of 16 ports each.
+ * Maybe some other pcic chips are restricted to 16-port windows;
+ * the 82365SL doesn't seem to have that problem. But since
+ * we have an extra window anyway...
+ */
+#ifdef SHARED_MEMORY
+ pcic_map_io (slot, 0, isa_dev->id_iobase, 32, 1);
+#else
+ pcic_map_io (slot, 0, isa_dev->id_iobase, 16, 1);
+ pcic_map_io (slot, 1, isa_dev->id_iobase+16, 16, 2);
+#endif /* SHARED_MEMORY */
+
+ /*
+ * (5) configure the card for the desired interrupt
+ *
+ * XXX is it possible that the config file leaves this unspecified?
+ */
+ pcic_map_irq (slot, ffs (isa_dev->id_irq) - 1);
+
+ /* tell the PCIC that this is an I/O card (not memory) */
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDTYPE);
+
+#if 0
+ /* tell the PCIC to use level-mode interrupts */
+ /* XXX this register may not be present on all controllers */
+ pcic_putb (slot, PCIC_GLO_CTRL,
+ pcic_getb (slot, PCIC_GLO_CTRL) | PCIC_LVL_MODE);
+#endif
+
+#if 0
+ pcic_print_regs (slot);
+#endif
+ /*
+ * Setup i/o addresses
+ */
+ sc->nic_addr = isa_dev->id_iobase;
+#if 0
+ sc->vector = isa_dev->id_irq;
+#endif
+ sc->smem_start = (caddr_t)isa_dev->id_maddr;
+
+#if 0
+ sc->vendor = ZE_VENDOR_IBM;
+ sc->type = xxx;
+#endif
+
+ /* reset card to force it into a known state */
+ tmp = inb (isa_dev->id_iobase + ZE_RESET);
+ DELAY(5000);
+ outb (isa_dev->id_iobase + ZE_RESET, tmp);
+ DELAY(5000);
+
+ /*
+ * query MAM bit in misc register for 10base2
+ */
+ tmp = inb (isa_dev->id_iobase + ZE_MISC);
+ sc->mau = tmp & 0x09 ? "10base2" : "10baseT";
+
+ /* set width/size */
+ sc->type_str = "IBM PCMCIA";
+ memsize = 16*1024;
+ sc->memwidth = 16;
+
+ /* allocate 1 xmit buffer */
+ sc->smem_ring = sc->smem_start + (ZE_PAGE_SIZE * ZE_TXBUF_SIZE);
+ sc->txb_cnt = 1;
+ sc->rec_page_start = ZE_TXBUF_SIZE + ZE_PAGE_OFFSET;
+ sc->smem_size = memsize;
+ sc->smem_end = sc->smem_start + memsize;
+ sc->rec_page_stop = memsize / ZE_PAGE_SIZE + ZE_PAGE_OFFSET;
+ sc->tx_page_start = ZE_PAGE_OFFSET;
+
+ /* get station address */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = enet_addr[i];
+
+ isa_dev->id_msize = memsize;
+ return 32;
+}
+
+/*
+ * Install interface into kernel networking data structures
+ */
+int
+ze_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ze_softc *sc = &ze_softc[isa_dev->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set interface to stopped condition (reset)
+ */
+ ze_stop(isa_dev->id_unit);
+
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_unit = isa_dev->id_unit;
+ ifp->if_name = "ze" ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = ze_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = ze_start;
+ ifp->if_ioctl = ze_ioctl;
+ ifp->if_reset = ze_reset;
+ ifp->if_watchdog = ze_watchdog;
+
+ /*
+ * Set default state for LLC0 flag (used to disable the tranceiver
+ * for AUI operation), based on compile-time config option.
+ */
+ if (isa_dev->id_flags & ZE_FLAGS_DISABLE_TRANCEIVER)
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
+ | IFF_LLC0);
+ else
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+
+ /*
+ * Search down the ifa address list looking for the AF_LINK type entry
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ /*
+ * If we find an AF_LINK type entry we fill in the hardware address.
+ * This is useful for netstat(1) to keep track of which interface
+ * is which.
+ */
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ /*
+ * Fill in the link-level address for this interface
+ */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Print additional info when attached
+ */
+ printf("ze%d: address %s, type %s (%dbit)%s, MAU %s\n",
+ isa_dev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
+ sc->memwidth,
+ (ifp->if_flags & IFF_LLC0 ? " [tranceiver disabled]" : ""),
+ sc->mau);
+
+ /*
+ * If BPF is in the kernel, call the attach for it
+ */
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+/*
+ * Reset interface.
+ */
+void
+ze_reset(unit)
+ int unit;
+{
+ int s;
+
+ s = splnet();
+
+ /*
+ * Stop interface and re-initialize.
+ */
+ ze_stop(unit);
+ ze_init(unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Take interface offline.
+ */
+void
+ze_stop(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ int n = 5000;
+
+ /*
+ * Stop everything on the interface, and select page 0 registers.
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STP);
+
+ /*
+ * Wait for interface to enter stopped state, but limit # of checks
+ * to 'n' (about 5ms). It shouldn't even take 5us on modern
+ * DS8390's, but just in case it's an old one.
+ */
+ while (((inb(sc->nic_addr + ZE_P0_ISR) & ZE_ISR_RST) == 0) && --n);
+
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+void
+ze_watchdog(unit)
+ int unit;
+{
+#if 1
+ struct ze_softc *sc = &ze_softc[unit];
+ u_char isr, imr;
+ u_short imask;
+
+ /* select page zero */
+ outb (sc->nic_addr + ZE_P0_CR,
+ (inb (sc->nic_addr + ZE_P0_CR) & 0x3f) | ZE_CR_PAGE_0);
+
+ /* read interrupt status register */
+ isr = inb (sc->nic_addr + ZE_P0_ISR) & 0xff;
+
+ /* select page two */
+ outb (sc->nic_addr + ZE_P0_CR,
+ (inb (sc->nic_addr + ZE_P0_CR) & 0x3f) | ZE_CR_PAGE_2);
+
+ /* read interrupt mask register */
+ imr = inb (sc->nic_addr + ZE_P2_IMR) & 0xff;
+
+ imask = inb(IO_ICU2) << 8 | inb(IO_ICU1);
+
+ log (LOG_ERR, "ze%d: device timeout, isr=%02x, imr=%02x, imask=%04x\n",
+ unit, isr, imr, imask);
+#else
+ log(LOG_ERR, "ze%d: device timeout\n", unit);
+#endif
+
+ ze_reset(unit);
+}
+
+/*
+ * Initialize device.
+ */
+void
+ze_init(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i, s;
+ u_char command;
+
+
+ /* address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ /*
+ * Initialize the NIC in the exact order outlined in the NS manual.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
+ */
+ s = splnet();
+
+ /* reset transmitter flags */
+ sc->data_buffered = 0;
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_timer = 0;
+
+ sc->txb_next = 0;
+
+ /* This variable is used below - don't move this assignment */
+ sc->next_packet = sc->rec_page_start + 1;
+
+ /*
+ * Set interface for page 0, Remote DMA complete, Stopped
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STP);
+
+ if (sc->memwidth == 16) {
+ /*
+ * Set FIFO threshold to 8, No auto-init Remote DMA,
+ * byte order=80x86, word-wide DMA xfers
+ */
+ outb(sc->nic_addr + ZE_P0_DCR, ZE_DCR_FT1|ZE_DCR_WTS);
+ } else {
+ /*
+ * Same as above, but byte-wide DMA xfers
+ */
+ outb(sc->nic_addr + ZE_P0_DCR, ZE_DCR_FT1);
+ }
+
+ /*
+ * Clear Remote Byte Count Registers
+ */
+ outb(sc->nic_addr + ZE_P0_RBCR0, 0);
+ outb(sc->nic_addr + ZE_P0_RBCR1, 0);
+
+ /*
+ * Enable reception of broadcast packets
+ */
+ outb(sc->nic_addr + ZE_P0_RCR, ZE_RCR_AB);
+
+ /*
+ * Place NIC in internal loopback mode
+ */
+ outb(sc->nic_addr + ZE_P0_TCR, ZE_TCR_LB0);
+
+ /*
+ * Initialize transmit/receive (ring-buffer) Page Start
+ */
+ outb(sc->nic_addr + ZE_P0_TPSR, sc->tx_page_start);
+ outb(sc->nic_addr + ZE_P0_PSTART, sc->rec_page_start);
+
+ /*
+ * Initialize Receiver (ring-buffer) Page Stop and Boundry
+ */
+ outb(sc->nic_addr + ZE_P0_PSTOP, sc->rec_page_stop);
+ outb(sc->nic_addr + ZE_P0_BNRY, sc->rec_page_start);
+
+ /*
+ * Clear all interrupts. A '1' in each bit position clears the
+ * corresponding flag.
+ */
+ outb(sc->nic_addr + ZE_P0_ISR, 0xff);
+
+ /*
+ * Enable the following interrupts: receive/transmit complete,
+ * receive/transmit error, and Receiver OverWrite.
+ *
+ * Counter overflow and Remote DMA complete are *not* enabled.
+ */
+ outb(sc->nic_addr + ZE_P0_IMR,
+ ZE_IMR_PRXE|ZE_IMR_PTXE|ZE_IMR_RXEE|ZE_IMR_TXEE|ZE_IMR_OVWE);
+
+ /*
+ * Program Command Register for page 1
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STP);
+
+ /*
+ * Copy out our station address
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ outb(sc->nic_addr + ZE_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+
+#if NBPFILTER > 0
+ /*
+ * Initialize multicast address hashing registers to accept
+ * all multicasts (only used when in promiscuous mode)
+ */
+ for (i = 0; i < 8; ++i)
+ outb(sc->nic_addr + ZE_P1_MAR0 + i, 0xff);
+#endif
+
+ /*
+ * Set Current Page pointer to next_packet (initialized above)
+ */
+ outb(sc->nic_addr + ZE_P1_CURR, sc->next_packet);
+
+ /*
+ * Set Command Register for page 0, Remote DMA complete,
+ * and interface Start.
+ */
+ outb(sc->nic_addr + ZE_P1_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * Take interface out of loopback
+ */
+ outb(sc->nic_addr + ZE_P0_TCR, 0);
+
+#if 0
+ /*
+ * If this is a 3Com board, the tranceiver must be software enabled
+ * (there is no settable hardware default).
+ */
+ if (sc->vendor == ZE_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_LLC0) {
+ outb(sc->asic_addr + ZE_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ZE_3COM_CR, ZE_3COM_CR_XSEL);
+ }
+ }
+#endif
+
+ /*
+ * Set 'running' flag, and clear output active flag.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * ...and attempt to start output
+ */
+ ze_start(ifp);
+
+ (void) splx(s);
+}
+
+/*
+ * This routine actually starts the transmission on the interface
+ */
+static inline void
+ze_xmit(ifp)
+ struct ifnet *ifp;
+{
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ u_short len = sc->txb_next_len;
+
+ /*
+ * Set NIC for page 0 register access
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * Set TX buffer start page
+ */
+ outb(sc->nic_addr + ZE_P0_TPSR, sc->tx_page_start +
+ sc->txb_next * ZE_TXBUF_SIZE);
+
+ /*
+ * Set TX length
+ */
+ outb(sc->nic_addr + ZE_P0_TBCR0, len & 0xff);
+ outb(sc->nic_addr + ZE_P0_TBCR1, len >> 8);
+
+ /*
+ * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_TXP|ZE_CR_STA);
+
+ sc->xmit_busy = 1;
+ sc->data_buffered = 0;
+
+ /*
+ * Switch buffers if we are doing double-buffered transmits
+ */
+ if ((sc->txb_next == 0) && (sc->txb_cnt > 1))
+ sc->txb_next = 1;
+ else
+ sc->txb_next = 0;
+
+ /*
+ * Set a timer just in case we never hear from the board again
+ */
+ ifp->if_timer = 2;
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splnet _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+ze_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ caddr_t buffer;
+ int len;
+ u_char laar_tmp;
+
+outloop:
+ /*
+ * See if there is room to send more data (i.e. one or both of the
+ * buffers is empty).
+ */
+ if (sc->data_buffered)
+ if (sc->xmit_busy) {
+ /*
+ * No room. Indicate this to the outside world
+ * and exit.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ } else {
+ /*
+ * Data is buffered, but we're not transmitting, so
+ * start the xmit on the buffered data.
+ * Note that ze_xmit() resets the data_buffered flag
+ * before returning.
+ */
+ ze_xmit(ifp);
+ }
+
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == NULL) {
+ /*
+ * The following isn't pretty; we are using the !OACTIVE flag to
+ * indicate to the outside world that we can accept an additional
+ * packet rather than that the transmitter is _actually_
+ * active. Indeed, the transmitter may be active, but if we haven't
+ * filled the secondary buffer with data then we still want to
+ * accept more.
+ * Note that it isn't necessary to test the data_buffered flag -
+ * we wouldn't have tried to de-queue the packet in the first place
+ * if it was set.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+#if 0
+ /*
+ * Enable 16bit access to shared memory on WD/SMC boards
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ laar_tmp = inb(sc->asic_addr + ZE_WD_LAAR);
+ outb(sc->asic_addr + ZE_WD_LAAR, laar_tmp | ZE_WD_LAAR_M16EN);
+ }
+#endif
+
+ buffer = sc->smem_start + (sc->txb_next * ZE_TXBUF_SIZE * ZE_PAGE_SIZE);
+ len = 0;
+ for (m0 = m; m != 0; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+#if 0
+ /*
+ * Restore previous shared mem access type
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR, laar_tmp);
+ }
+#endif
+
+ sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
+
+ if (sc->txb_cnt > 1)
+ /*
+ * only set 'buffered' flag if doing multiple buffers
+ */
+ sc->data_buffered = 1;
+
+ if (sc->xmit_busy == 0)
+ ze_xmit(ifp);
+ /*
+ * If there is BPF support in the configuration, tap off here.
+ * The following has support for converting trailer packets
+ * back to normal.
+ */
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+ } trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(m0, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(m0, off, sizeof(struct trailer_header),
+ &trailer_header.ether_type);
+
+ /* copy residual data */
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
+ sizeof(struct trailer_header), ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(m0, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, m0);
+ }
+#endif
+
+ m_freem(m0);
+
+ /*
+ * If we are doing double-buffering, a buffer might be free to
+ * fill with another packet, so loop back to the top.
+ */
+ if (sc->txb_cnt > 1)
+ goto outloop;
+ else {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ */
+static inline void /* only called from one place, so may as well integrate */
+ze_rint(unit)
+ int unit;
+{
+ register struct ze_softc *sc = &ze_softc[unit];
+ u_char boundry, current;
+ u_short len;
+ struct ze_ring *packet_ptr;
+
+ /*
+ * Set NIC to page 1 registers to get 'current' pointer
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
+ * it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer
+ * - i.e. it points to where additional new data will be added.
+ * We loop here until the logical beginning equals the logical
+ * end (or in other words, until the ring-buffer is empty).
+ */
+ while (sc->next_packet != inb(sc->nic_addr + ZE_P1_CURR)) {
+
+ /* get pointer to this buffer header structure */
+ packet_ptr = (struct ze_ring *)(sc->smem_ring +
+ (sc->next_packet - sc->rec_page_start) * ZE_PAGE_SIZE);
+
+ /*
+ * The byte count includes the FCS - Frame Check Sequence (a
+ * 32 bit CRC).
+ */
+ len = packet_ptr->count;
+ if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+ /*
+ * Go get packet. len - 4 removes CRC from length.
+ * (packet_ptr + 1) points to data just after the packet ring
+ * header (+4 bytes)
+ */
+ ze_get_packet(sc, (caddr_t)(packet_ptr + 1), len - 4);
+ ++sc->arpcom.ac_if.if_ipackets;
+ } else {
+ /*
+ * Really BAD...probably indicates that the ring pointers
+ * are corrupted. Also seen on early rev chips under
+ * high load - the byte order of the length gets switched.
+ */
+ log(LOG_ERR,
+ "ze%d: shared memory corrupt - invalid packet length %d\n",
+ unit, len);
+ ze_reset(unit);
+ return;
+ }
+
+ /*
+ * Update next packet pointer
+ */
+ sc->next_packet = packet_ptr->next_packet;
+
+ /*
+ * Update NIC boundry pointer - being careful to keep it
+ * one buffer behind. (as recommended by NS databook)
+ */
+ boundry = sc->next_packet - 1;
+ if (boundry < sc->rec_page_start)
+ boundry = sc->rec_page_stop - 1;
+
+ /*
+ * Set NIC to page 0 registers to update boundry register
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ outb(sc->nic_addr + ZE_P0_BNRY, boundry);
+
+ /*
+ * Set NIC to page 1 registers before looping to top (prepare to
+ * get 'CURR' current pointer)
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STA);
+ }
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+void
+zeintr(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ u_char isr;
+
+ /*
+ * Set NIC to page 0 registers
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * loop until there are no more new interrupts
+ */
+ while (isr = inb(sc->nic_addr + ZE_P0_ISR)) {
+
+ /*
+ * reset all the bits that we are 'acknowleging'
+ * by writing a '1' to each bit position that was set
+ * (writing a '1' *clears* the bit)
+ */
+ outb(sc->nic_addr + ZE_P0_ISR, isr);
+
+ /*
+ * Transmit error. If a TX completed with an error, we end up
+ * throwing the packet away. Really the only error that is
+ * possible is excessive collisions, and in this case it is
+ * best to allow the automatic mechanisms of TCP to backoff
+ * the flow. Of course, with UDP we're screwed, but this is
+ * expected when a network is heavily loaded.
+ */
+ if (isr & ZE_ISR_TXE) {
+ u_char tsr = inb(sc->nic_addr + ZE_P0_TSR);
+ u_char ncr = inb(sc->nic_addr + ZE_P0_NCR);
+
+ /*
+ * Excessive collisions (16)
+ */
+ if ((tsr & ZE_TSR_ABT) && (ncr == 0)) {
+ /*
+ * When collisions total 16, the P0_NCR will
+ * indicate 0, and the TSR_ABT is set.
+ */
+ sc->arpcom.ac_if.if_collisions += 16;
+ } else
+ sc->arpcom.ac_if.if_collisions += ncr;
+
+ /*
+ * update output errors counter
+ */
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+ }
+
+
+ /*
+ * Receiver Error. One or more of: CRC error, frame alignment error
+ * FIFO overrun, or missed packet.
+ */
+ if (isr & ZE_ISR_RXE) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ZE_DEBUG
+#if 0
+ printf("ze%d: receive error %x\n", unit,
+ inb(sc->nic_addr + ZE_P0_RSR));
+#else
+ printf("ze%d: receive error %b\n", unit,
+ inb(sc->nic_addr + ZE_P0_RSR),
+ "\20\8DEF\7REC DISAB\6PHY/MC\5MISSED\4OVR\3ALIGN\2FCS\1RCVD");
+#endif
+#endif
+ }
+
+ /*
+ * Overwrite warning. In order to make sure that a lockup
+ * of the local DMA hasn't occurred, we reset and
+ * re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some
+ * chips seem to want more. The DMA lockup has been
+ * seen only with early rev chips - Methinks this
+ * bug was fixed in later revs. -DG
+ */
+ if (isr & ZE_ISR_OVW) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#if 0
+ /* sigh. this happens too often on our net */
+ log(LOG_WARNING,
+ "ze%d: warning - receiver ring buffer overrun\n",
+ unit);
+#endif
+ /*
+ * Stop/reset/re-init NIC
+ */
+ ze_reset(unit);
+ }
+
+ /*
+ * Transmission completed normally.
+ */
+ if (isr & ZE_ISR_PTX) {
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+
+ /*
+ * Update total number of successfully transmitted
+ * packets.
+ */
+ ++sc->arpcom.ac_if.if_opackets;
+
+ /*
+ * Add in total number of collisions on last
+ * transmission.
+ */
+ sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
+ ZE_P0_TBCR0);
+ }
+
+ /*
+ * Receive Completion. Go and get the packet.
+ * XXX - Doing this on an error is dubious because there
+ * shouldn't be any data to get (we've configured the
+ * interface to not accept packets with errors).
+ */
+ if (isr & (ZE_ISR_PRX|ZE_ISR_RXE)) {
+#if 0
+ /*
+ * Enable access to shared memory on WD/SMC boards
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR,
+ inb(sc->asic_addr + ZE_WD_LAAR)
+ | ZE_WD_LAAR_M16EN);
+ }
+#endif
+ ze_rint (unit);
+
+#if 0
+ /*
+ * Disable access to shared memory
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR,
+ inb(sc->asic_addr + ZE_WD_LAAR)
+ & ~ZE_WD_LAAR_M16EN);
+ }
+#endif
+ }
+
+ /*
+ * If it looks like the transmitter can take more data,
+ * attempt to start output on the interface. If data is
+ * already buffered and ready to go, send it first.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) {
+ if (sc->data_buffered)
+ ze_xmit(&sc->arpcom.ac_if);
+ ze_start(&sc->arpcom.ac_if);
+ }
+
+ /*
+ * return NIC CR to standard state: page 0, remote DMA complete,
+ * start (toggling the TXP bit off, even if was just set
+ * in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * If the Network Talley Counters overflow, read them to
+ * reset them. It appears that old 8390's won't
+ * clear the ISR flag otherwise - resulting in an
+ * infinite loop.
+ */
+ if (isr & ZE_ISR_CNT) {
+ (void) inb(sc->nic_addr + ZE_P0_CNTR0);
+ (void) inb(sc->nic_addr + ZE_P0_CNTR1);
+ (void) inb(sc->nic_addr + ZE_P0_CNTR2);
+ }
+ }
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+ze_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ze_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ze_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ ze_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ze_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ ze_init(ifp->if_unit);
+ }
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Set promiscuous mode on interface.
+ * XXX - for multicasts to work, we would need to
+ * write 1's in all bits of multicast
+ * hashing array. For now we assume that
+ * this was done in ze_init().
+ */
+ outb(sc->nic_addr + ZE_P0_RCR,
+ ZE_RCR_PRO|ZE_RCR_AM|ZE_RCR_AB);
+ } else {
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ outb(sc->nic_addr + ZE_P0_RCR, ZE_RCR_AB);
+ }
+#endif
+#if 0
+ /*
+ * An unfortunate hack to provide the (required) software control
+ * of the tranceiver for 3Com boards. The LLC0 flag disables
+ * the tranceiver if set.
+ */
+ if (sc->vendor == ZE_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_LLC0) {
+ outb(sc->asic_addr + ZE_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ZE_3COM_CR, ZE_3COM_CR_XSEL);
+ }
+ }
+#endif
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * Macro to calculate a new address within shared memory when given an offset
+ * from an address, taking into account ring-wrap.
+ */
+#define ringoffset(sc, start, off, type) \
+ ((type)( ((caddr_t)(start)+(off) >= (sc)->smem_end) ? \
+ (((caddr_t)(start)+(off))) - (sc)->smem_end \
+ + (sc)->smem_ring: \
+ ((caddr_t)(start)+(off)) ))
+
+/*
+ * Retreive packet from shared memory and send to the next level up via
+ * ether_input(). If there is a BPF listener, give a copy to BPF, too.
+ */
+void
+ze_get_packet(sc, buf, len)
+ struct ze_softc *sc;
+ char *buf;
+ u_short len;
+{
+ struct ether_header *eh;
+ struct mbuf *m, *head = NULL, *ze_ring_to_mbuf();
+ u_short off;
+ int resid;
+ u_short etype;
+ struct trailer_header {
+ u_short trail_type;
+ u_short trail_residual;
+ } trailer_header;
+
+ /* Allocate a header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto bad;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+ head = m;
+
+ eh = (struct ether_header *)buf;
+
+ /* The following sillines is to make NFS happy */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+
+ /*
+ * The following assumes there is room for
+ * the ether header in the header mbuf
+ */
+ head->m_data += EOFF;
+ bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ buf += sizeof(struct ether_header);
+ head->m_len += sizeof(struct ether_header);
+ len -= sizeof(struct ether_header);
+
+ etype = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Deal with trailer protocol:
+ * If trailer protocol, calculate the datasize as 'off',
+ * which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the
+ * trailer header.
+ * Finally, copy residual data into mbuf chain.
+ */
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+
+ off = (etype - ETHERTYPE_TRAIL) << 9;
+ if ((off + sizeof(struct trailer_header)) > len)
+ goto bad; /* insanity */
+
+ eh->ether_type = *ringoffset(sc, buf, off, u_short *);
+ resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+
+ if ((off + resid) > len) goto bad; /* insanity */
+
+ resid -= sizeof(struct trailer_header);
+ if (resid < 0) goto bad; /* insanity */
+
+ m = ze_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
+ if (m == NULL) goto bad;
+
+ len = off;
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
+ }
+
+ /*
+ * Pull packet off interface. Or if this was a trailer packet,
+ * the data portion is appended.
+ */
+ m = ze_ring_to_mbuf(sc, buf, m, len);
+ if (m == NULL) goto bad;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, head);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ *
+ * XXX This test does not support multicasts.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(head);
+ return;
+ }
+ }
+#endif
+
+ /*
+ * Fix up data start offset in mbuf to point past ether header
+ */
+ m_adj(head, sizeof(struct ether_header));
+
+ /*
+ * silly ether_input routine needs 'type' in host byte order
+ */
+ eh->ether_type = ntohs(eh->ether_type);
+
+ ether_input(&sc->arpcom.ac_if, eh, head);
+ return;
+
+bad: if (head)
+ m_freem(head);
+ return;
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Given a source and destination address, copy 'amount' of a packet from
+ * the ring buffer into a linear destination buffer. Takes into account
+ * ring-wrap.
+ */
+static inline char *
+ze_ring_copy(sc,src,dst,amount)
+ struct ze_softc *sc;
+ char *src;
+ char *dst;
+ u_short amount;
+{
+ u_short tmp_amount;
+
+ /* does copy wrap to lower addr in ring buffer? */
+ if (src + amount > sc->smem_end) {
+ tmp_amount = sc->smem_end - src;
+ bcopy(src,dst,tmp_amount); /* copy amount up to end of smem */
+ amount -= tmp_amount;
+ src = sc->smem_ring;
+ dst += tmp_amount;
+ }
+
+ bcopy(src, dst, amount);
+
+ return(src + amount);
+}
+
+/*
+ * Copy data from receive buffer to end of mbuf chain
+ * allocate additional mbufs as needed. return pointer
+ * to last mbuf in chain.
+ * sc = ze info (softc)
+ * src = pointer in ze ring buffer
+ * dst = pointer to last mbuf in mbuf chain to copy to
+ * amount = amount of data to copy
+ */
+struct mbuf *
+ze_ring_to_mbuf(sc,src,dst,total_len)
+ struct ze_softc *sc;
+ char *src;
+ struct mbuf *dst;
+ u_short total_len;
+{
+ register struct mbuf *m = dst;
+
+ while (total_len) {
+ register u_short amount = min(total_len, M_TRAILINGSPACE(m));
+
+ if (amount == 0) { /* no more data in this mbuf, alloc another */
+ /*
+ * If there is enough data for an mbuf cluster, attempt
+ * to allocate one of those, otherwise, a regular
+ * mbuf will do.
+ * Note that a regular mbuf is always required, even if
+ * we get a cluster - getting a cluster does not
+ * allocate any mbufs, and one is needed to assign
+ * the cluster to. The mbuf that has a cluster
+ * extension can not be used to contain data - only
+ * the cluster can contain data.
+ */
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (0);
+
+ if (total_len >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = min(total_len, M_TRAILINGSPACE(m));
+ }
+
+ src = ze_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
+
+ m->m_len += amount;
+ total_len -= amount;
+
+ }
+ return (m);
+}
+#endif
+
diff --git a/sys/i386/isa/if_zereg.h b/sys/i386/isa/if_zereg.h
new file mode 100644
index 000000000000..3cd501f682cb
--- /dev/null
+++ b/sys/i386/isa/if_zereg.h
@@ -0,0 +1,859 @@
+/*
+ * National Semiconductor DS8390 NIC register definitions
+ *
+ * if_edreg.h,v
+ * Revision 1.1.2.1 1993/07/21 13:50:04 cgd
+ * from davidg:
+ * Added config file override for memory size and added flags to force
+ * 8bit or 16bit operation, and a flag to disable transmitter double buffering.
+ * See the updated "ed.relnotes" file for information about how to set
+ * the flags.
+ * This should be considered the first "production" release. It still
+ * needs a manual page, though.
+ *
+ * Revision 1.1 1993/07/03 12:21:07 cgd
+ * add support for David Greenman "ed" driver
+ *
+ * Revision 1.2 93/06/23 03:03:05 davidg
+ * added some additional definitions for the 83C584 bus interface
+ * chip (SMC/WD boards)
+ *
+ * Revision 1.1 93/06/23 03:01:07 davidg
+ * Initial revision
+ *
+ */
+
+/*
+ * Page 0 register offsets
+ */
+#define ZE_P0_CR 0x00 /* Command Register */
+
+#define ZE_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */
+#define ZE_P0_PSTART 0x01 /* Page Start register (write) */
+
+#define ZE_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */
+#define ZE_P0_PSTOP 0x02 /* Page Stop register (write) */
+
+#define ZE_P0_BNRY 0x03 /* Boundary Pointer */
+
+#define ZE_P0_TSR 0x04 /* Transmit Status Register (read) */
+#define ZE_P0_TPSR 0x04 /* Transmit Page Start (write) */
+
+#define ZE_P0_NCR 0x05 /* Number of Collisions Reg (read) */
+#define ZE_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */
+
+#define ZE_P0_FIFO 0x06 /* FIFO register (read) */
+#define ZE_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */
+
+#define ZE_P0_ISR 0x07 /* Interrupt Status Register */
+
+#define ZE_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */
+#define ZE_P0_RSAR0 0x08 /* Remote Start Address low (write) */
+
+#define ZE_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */
+#define ZE_P0_RSAR1 0x09 /* Remote Start Address high (write) */
+
+#define ZE_P0_RBCR0 0x0a /* Remote Byte Count low (write) */
+
+#define ZE_P0_RBCR1 0x0b /* Remote Byte Count high (write) */
+
+#define ZE_P0_RSR 0x0c /* Receive Status (read) */
+#define ZE_P0_RCR 0x0c /* Receive Configuration Reg (write) */
+
+#define ZE_P0_CNTR0 0x0d /* frame alignment error counter (read) */
+#define ZE_P0_TCR 0x0d /* Transmit Configuration Reg (write) */
+
+#define ZE_P0_CNTR1 0x0e /* CRC error counter (read) */
+#define ZE_P0_DCR 0x0e /* Data Configuration Reg (write) */
+
+#define ZE_P0_CNTR2 0x0f /* missed packet counter (read) */
+#define ZE_P0_IMR 0x0f /* Interrupt Mask Register (write) */
+
+/*
+ * Page 1 register offsets
+ */
+#define ZE_P1_CR 0x00 /* Command Register */
+#define ZE_P1_PAR0 0x01 /* Physical Address Register 0 */
+#define ZE_P1_PAR1 0x02 /* Physical Address Register 1 */
+#define ZE_P1_PAR2 0x03 /* Physical Address Register 2 */
+#define ZE_P1_PAR3 0x04 /* Physical Address Register 3 */
+#define ZE_P1_PAR4 0x05 /* Physical Address Register 4 */
+#define ZE_P1_PAR5 0x06 /* Physical Address Register 5 */
+#define ZE_P1_CURR 0x07 /* Current RX ring-buffer page */
+#define ZE_P1_MAR0 0x08 /* Multicast Address Register 0 */
+#define ZE_P1_MAR1 0x09 /* Multicast Address Register 1 */
+#define ZE_P1_MAR2 0x0a /* Multicast Address Register 2 */
+#define ZE_P1_MAR3 0x0b /* Multicast Address Register 3 */
+#define ZE_P1_MAR4 0x0c /* Multicast Address Register 4 */
+#define ZE_P1_MAR5 0x0d /* Multicast Address Register 5 */
+#define ZE_P1_MAR6 0x0e /* Multicast Address Register 6 */
+#define ZE_P1_MAR7 0x0f /* Multicast Address Register 7 */
+
+/*
+ * Page 2 register offsets
+ */
+#define ZE_P2_CR 0x00 /* Command Register */
+#define ZE_P2_PSTART 0x01 /* Page Start (read) */
+#define ZE_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */
+#define ZE_P2_PSTOP 0x02 /* Page Stop (read) */
+#define ZE_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */
+#define ZE_P2_RNPP 0x03 /* Remote Next Packet Pointer */
+#define ZE_P2_TPSR 0x04 /* Transmit Page Start (read) */
+#define ZE_P2_LNPP 0x05 /* Local Next Packet Pointer */
+#define ZE_P2_ACU 0x06 /* Address Counter Upper */
+#define ZE_P2_ACL 0x07 /* Address Counter Lower */
+#define ZE_P2_RCR 0x0c /* Receive Configuration Register (read) */
+#define ZE_P2_TCR 0x0d /* Transmit Configuration Register (read) */
+#define ZE_P2_DCR 0x0e /* Data Configuration Register (read) */
+#define ZE_P2_IMR 0x0f /* Interrupt Mask Register (read) */
+
+/*
+ * Command Register (CR) definitions
+ */
+
+/*
+ * STP: SToP. Software reset command. Takes the controller offline. No
+ * packets will be received or transmitted. Any reception or
+ * transmission in progress will continue to completion before
+ * entering reset state. To exit this state, the STP bit must
+ * reset and the STA bit must be set. The software reset has
+ * executed only when indicated by the RST bit in the ISR being
+ * set.
+ */
+#define ZE_CR_STP 0x01
+
+/*
+ * STA: STArt. This bit is used to activate the NIC after either power-up,
+ * or when the NIC has been put in reset mode by software command
+ * or error.
+ */
+#define ZE_CR_STA 0x02
+
+/*
+ * TXP: Transmit Packet. This bit must be set to indicate transmission of
+ * a packet. TXP is internally reset either after the transmission is
+ * completed or aborted. This bit should be set only after the Transmit
+ * Byte Count and Transmit Page Start register have been programmed.
+ */
+#define ZE_CR_TXP 0x04
+
+/*
+ * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation
+ * of the remote DMA channel. RD2 can be set to abort any remote DMA
+ * command in progress. The Remote Byte Count registers should be cleared
+ * when a remote DMA has been aborted. The Remote Start Addresses are not
+ * restored to the starting address if the remote DMA is aborted.
+ *
+ * RD2 RD1 RD0 function
+ * 0 0 0 not allowed
+ * 0 0 1 remote read
+ * 0 1 0 remote write
+ * 0 1 1 send packet
+ * 1 X X abort
+ */
+#define ZE_CR_RD0 0x08
+#define ZE_CR_RD1 0x10
+#define ZE_CR_RD2 0x20
+
+/*
+ * PS0, PS1: Page Select. The two bits select which register set or 'page' to
+ * access.
+ *
+ * PS1 PS0 page
+ * 0 0 0
+ * 0 1 1
+ * 1 0 2
+ * 1 1 reserved
+ */
+#define ZE_CR_PS0 0x40
+#define ZE_CR_PS1 0x80
+/* bit encoded aliases */
+#define ZE_CR_PAGE_0 0x00 /* (for consistency) */
+#define ZE_CR_PAGE_1 0x40
+#define ZE_CR_PAGE_2 0x80
+
+/*
+ * Interrupt Status Register (ISR) definitions
+ */
+
+/*
+ * PRX: Packet Received. Indicates packet received with no errors.
+ */
+#define ZE_ISR_PRX 0x01
+
+/*
+ * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
+ */
+#define ZE_ISR_PTX 0x02
+
+/*
+ * RXE: Receive Error. Indicates that a packet was received with one or more
+ * the following errors: CRC error, frame alignment error, FIFO overrun,
+ * missed packet.
+ */
+#define ZE_ISR_RXE 0x04
+
+/*
+ * TXE: Transmission Error. Indicates that an attempt to transmit a packet
+ * resulted in one or more of the following errors: excessive
+ * collisions, FIFO underrun.
+ */
+#define ZE_ISR_TXE 0x08
+
+/*
+ * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
+ * would exceed (has exceeded?) the boundry pointer, resulting in data
+ * that was previously received and not yet read from the buffer to be
+ * overwritten.
+ */
+#define ZE_ISR_OVW 0x10
+
+/*
+ * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
+ * Counters has been set.
+ */
+#define ZE_ISR_CNT 0x20
+
+/*
+ * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
+ */
+#define ZE_ISR_RDC 0x40
+
+/*
+ * RST: Reset status. Set when the NIC enters the reset state and cleared when a
+ * Start Command is issued to the CR. This bit is also set when a receive
+ * ring-buffer overrun (OverWrite) occurs and is cleared when one or more
+ * packets have been removed from the ring. This is a read-only bit.
+ */
+#define ZE_ISR_RST 0x80
+
+/*
+ * Interrupt Mask Register (IMR) definitions
+ */
+
+/*
+ * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
+ * an interrupt.
+ */
+#define ZE_IMR_PRXE 0x01
+
+/*
+ * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
+ * a packet transmission completes.
+ */
+#define ZE_IMR_PTXE 0x02
+
+/*
+ * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
+ * packet is received with an error.
+ */
+#define ZE_IMR_RXEE 0x04
+
+/*
+ * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
+ * a transmission results in an error.
+ */
+#define ZE_IMR_TXEE 0x08
+
+/*
+ * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
+ * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
+ */
+#define ZE_IMR_OVWE 0x10
+
+/*
+ * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever
+ * the MSB of one or more of the Network Statistics counters has been set.
+ */
+#define ZE_IMR_CNTE 0x20
+
+/*
+ * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
+ * when a remote DMA transfer has completed.
+ */
+#define ZE_IMR_RDCE 0x40
+
+/*
+ * bit 7 is unused/reserved
+ */
+
+/*
+ * Data Configuration Register (DCR) definitions
+ */
+
+/*
+ * WTS: Word Transfer Select. WTS establishes byte or word transfers for
+ * both remote and local DMA transfers
+ */
+#define ZE_DCR_WTS 0x01
+
+/*
+ * BOS: Byte Order Select. BOS sets the byte order for the host.
+ * Should be 0 for 80x86, and 1 for 68000 series processors
+ */
+#define ZE_DCR_BOS 0x02
+
+/*
+ * LAS: Long Address Select. When LAS is 1, the contents of the remote
+ * DMA registers RSAR0 and RSAR1 are used to provide A16-A31
+ */
+#define ZE_DCR_LAS 0x04
+
+/*
+ * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2
+ * of the TCR must also be programmed for loopback operation.
+ * When 1, normal operation is selected.
+ */
+#define ZE_DCR_LS 0x08
+
+/*
+ * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
+ * under program control. When 1, remote DMA is automatically initiated
+ * and the boundry pointer is automatically updated
+ */
+#define ZE_DCR_AR 0x10
+
+/*
+ * FT0, FT1: Fifo Threshold select.
+ * FT1 FT0 Word-width Byte-width
+ * 0 0 1 word 2 bytes
+ * 0 1 2 words 4 bytes
+ * 1 0 4 words 8 bytes
+ * 1 1 8 words 12 bytes
+ *
+ * During transmission, the FIFO threshold indicates the number of bytes
+ * or words that the FIFO has filled from the local DMA before BREQ is
+ * asserted. The transmission threshold is 16 bytes minus the receiver
+ * threshold.
+ */
+#define ZE_DCR_FT0 0x20
+#define ZE_DCR_FT1 0x40
+
+/*
+ * bit 7 (0x80) is unused/reserved
+ */
+
+/*
+ * Transmit Configuration Register (TCR) definitions
+ */
+
+/*
+ * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC
+ * is not appended by the transmitter.
+ */
+#define ZE_TCR_CRC 0x01
+
+/*
+ * LB0, LB1: Loopback control. These two bits set the type of loopback that is
+ * to be performed.
+ *
+ * LB1 LB0 mode
+ * 0 0 0 - normal operation (DCR_LS = 0)
+ * 0 1 1 - internal loopback (DCR_LS = 0)
+ * 1 0 2 - external loopback (DCR_LS = 1)
+ * 1 1 3 - external loopback (DCR_LS = 0)
+ */
+#define ZE_TCR_LB0 0x02
+#define ZE_TCR_LB1 0x04
+
+/*
+ * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows
+ * another station to disable the NIC's transmitter by transmitting to
+ * a multicast address hashing to bit 62. Reception of a multicast address
+ * hashing to bit 63 enables the transmitter.
+ */
+#define ZE_TCR_ATD 0x08
+
+/*
+ * OFST: Collision Offset enable. This bit when set modifies the backoff
+ * algorithm to allow prioritization of nodes.
+ */
+#define ZE_TCR_OFST 0x10
+
+/*
+ * bits 5, 6, and 7 are unused/reserved
+ */
+
+/*
+ * Transmit Status Register (TSR) definitions
+ */
+
+/*
+ * PTX: Packet Transmitted. Indicates successful transmission of packet.
+ */
+#define ZE_TSR_PTX 0x01
+
+/*
+ * bit 1 (0x02) is unused/reserved
+ */
+
+/*
+ * COL: Transmit Collided. Indicates that the transmission collided at least
+ * once with another station on the network.
+ */
+#define ZE_TSR_COL 0x04
+
+/*
+ * ABT: Transmit aborted. Indicates that the transmission was aborted due to
+ * excessive collisions.
+ */
+#define ZE_TSR_ABT 0x08
+
+/*
+ * CRS: Carrier Sense Lost. Indicates that carrier was lost during the
+ * transmission of the packet. (Transmission is not aborted because
+ * of a loss of carrier)
+ */
+#define ZE_TSR_CRS 0x10
+
+/*
+ * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/
+ * transmission memory before the FIFO emptied. Transmission of the
+ * packet was aborted.
+ */
+#define ZE_TSR_FU 0x20
+
+/*
+ * CDH: CD Heartbeat. Indicates that the collision detection circuitry
+ * isn't working correctly during a collision heartbeat test.
+ */
+#define ZE_TSR_CDH 0x40
+
+/*
+ * OWC: Out of Window Collision: Indicates that a collision occurred after
+ * a slot time (51.2us). The transmission is rescheduled just as in
+ * normal collisions.
+ */
+#define ZE_TSR_OWC 0x80
+
+/*
+ * Receiver Configuration Register (RCR) definitions
+ */
+
+/*
+ * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1,
+ * packets with CRC and frame errors are not discarded.
+ */
+#define ZE_RCR_SEP 0x01
+
+/*
+ * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded.
+ * If set to 1, packets with less than 64 byte are not discarded.
+ */
+#define ZE_RCR_AR 0x02
+
+/*
+ * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
+ * accepted.
+ */
+#define ZE_RCR_AB 0x04
+
+/*
+ * AM: Accept Multicast. If set, packets sent to a multicast address are checked
+ * for a match in the hashing array. If clear, multicast packets are ignored.
+ */
+#define ZE_RCR_AM 0x08
+
+/*
+ * PRO: Promiscuous Physical. If set, all packets with a physical addresses are
+ * accepted. If clear, a physical destination address must match this
+ * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM
+ * must also be set. In addition, the multicast hashing array must be set
+ * to all 1's so that all multicast addresses are accepted.
+ */
+#define ZE_RCR_PRO 0x10
+
+/*
+ * MON: Monitor Mode. If set, packets will be checked for good CRC and framing,
+ * but are not stored in the ring-buffer. If clear, packets are stored (normal
+ * operation).
+ */
+#define ZE_RCR_MON 0x20
+
+/*
+ * bits 6 and 7 are unused/reserved.
+ */
+
+/*
+ * Receiver Status Register (RSR) definitions
+ */
+
+/*
+ * PRX: Packet Received without error.
+ */
+#define ZE_RSR_PRX 0x01
+
+/*
+ * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
+ * alignment errors.
+ */
+#define ZE_RSR_CRC 0x02
+
+/*
+ * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
+ * a byte boundry and the CRC did not match at the last byte boundry.
+ */
+#define ZE_RSR_FAE 0x04
+
+/*
+ * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA)
+ * causing it to overrun. Reception of the packet is aborted.
+ */
+#define ZE_RSR_FO 0x08
+
+/*
+ * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
+ * the ring-buffer because of insufficient buffer space (exceeding the
+ * boundry pointer), or because the transfer to the ring-buffer was inhibited
+ * by RCR_MON - monitor mode.
+ */
+#define ZE_RSR_MPA 0x10
+
+/*
+ * PHY: Physical address. If 0, the packet received was sent to a physical address.
+ * If 1, the packet was accepted because of a multicast/broadcast address
+ * match.
+ */
+#define ZE_RSR_PHY 0x20
+
+/*
+ * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
+ * mode. Cleared when the receiver exits monitor mode.
+ */
+#define ZE_RSR_DIS 0x40
+
+/*
+ * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs
+ * are active, and the transceiver has set the CD line as a result of the
+ * jabber.
+ */
+#define ZE_RSR_DFR 0x80
+
+/*
+ * receive ring discriptor
+ *
+ * The National Semiconductor DS8390 Network interface controller uses
+ * the following receive ring headers. The way this works is that the
+ * memory on the interface card is chopped up into 256 bytes blocks.
+ * A contiguous portion of those blocks are marked for receive packets
+ * by setting start and end block #'s in the NIC. For each packet that
+ * is put into the receive ring, one of these headers (4 bytes each) is
+ * tacked onto the front.
+ */
+struct ze_ring {
+ struct edr_status { /* received packet status */
+ u_char rs_prx:1, /* packet received intack */
+ rs_crc:1, /* crc error */
+ rs_fae:1, /* frame alignment error */
+ rs_fo:1, /* fifo overrun */
+ rs_mpa:1, /* packet received intack */
+ rs_phy:1, /* packet received intack */
+ rs_dis:1, /* packet received intack */
+ rs_dfr:1; /* packet received intack */
+ } ze_rcv_status; /* received packet status */
+ u_char next_packet; /* pointer to next packet */
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ZE_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ZE_TXBUF_SIZE 6 /* Size of TX buffer in pages */
+#define ZE_PAGE_OFFSET 0x40 /* mem buffer starts at 0x4000 */
+
+/*
+ * Vendor types
+ */
+#define ZE_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */
+#define ZE_VENDOR_3COM 0x01 /* 3Com */
+
+/*
+ * Compile-time config flags
+ */
+/*
+ * this sets the default for enabling/disablng the tranceiver
+ */
+#define ZE_FLAGS_DISABLE_TRANCEIVER 0x01
+
+/*
+ * This forces the board to be used in 8/16bit mode even if it
+ * autoconfigs differently
+ */
+#define ZE_FLAGS_FORCE_8BIT_MODE 0x02
+#define ZE_FLAGS_FORCE_16BIT_MODE 0x04
+
+/*
+ * This disables the use of double transmit buffers.
+ */
+#define ZE_FLAGS_NO_DOUBLE_BUFFERING 0x08
+
+/*
+ * definitions for IBM credit card adapter for ethernet
+ */
+
+#define ZE_DATA_IO 0x10
+#define ZE_MISC 0x18
+#define ZE_RESET 0x1F
+
+#if 0
+/*
+ * Definitions for Western digital/SMC WD80x3 series ASIC
+ */
+/*
+ * Memory Select Register (MSR)
+ */
+#define ZE_WD_MSR 0
+
+#define ZE_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */
+#define ZE_WD_MSR_MENB 0x40 /* Memory enable */
+#define ZE_WD_MSR_RST 0x80 /* Reset board */
+
+/*
+ * Interface Configuration Register (ICR)
+ */
+#define ZE_WD_ICR 1
+
+#define ZE_WD_ICR_16BIT 0x01 /* 16-bit interface */
+#define ZE_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */
+#define ZE_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */
+#define ZE_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */
+#define ZE_WD_ICR_RLA 0x10 /* recall LAN address */
+#define ZE_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */
+#define ZE_WD_ICR_RIO 0x40 /* recall i/o address */
+#define ZE_WD_ICR_STO 0x80 /* store to non-volatile memory */
+
+/*
+ * IO Address Register (IAR)
+ */
+#define ZE_WD_IAR 2
+
+/*
+ * EEROM Address Register
+ */
+#define ZE_WD_EAR 3
+
+/*
+ * Interrupt Request Register (IRR)
+ */
+#define ZE_WD_IRR 4
+
+#define ZE_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */
+#define ZE_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */
+#define ZE_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */
+#define ZE_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */
+#define ZE_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */
+
+/*
+ * The three bit of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 2/9
+ * 0 0 1 3
+ * 0 1 0 5
+ * 0 1 1 7
+ * 1 0 0 10
+ * 1 0 1 11
+ * 1 1 0 15
+ * 1 1 1 4
+ */
+#define ZE_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
+#define ZE_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
+#define ZE_WD_IRR_IEN 0x80 /* Interrupt enable */
+
+/*
+ * LA Address Register (LAAR)
+ */
+#define ZE_WD_LAAR 5
+
+#define ZE_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */
+#define ZE_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */
+#define ZE_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */
+#define ZE_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */
+
+/* i/o base offset to station address/card-ID PROM */
+#define ZE_WD_PROM 8
+
+/* i/o base offset to CARD ID */
+#define ZE_WD_CARD_ID ZE_WD_PROM+6
+
+#define ZE_TYPE_WD8003S 0x02
+#define ZE_TYPE_WD8003E 0x03
+#define ZE_TYPE_WD8013EBT 0x05
+#define ZE_TYPE_WD8013EB 0x27
+#define ZE_TYPE_WD8013EBP 0x2c
+#define ZE_TYPE_WD8013EPC 0x29
+
+/* Bit definitions in card ID */
+#define ZE_WD_REV_MASK 0x1f /* Revision mask */
+#define ZE_WD_SOFTCONFIG 0x20 /* Soft config */
+#define ZE_WD_LARGERAM 0x40 /* Large RAM */
+#define ZE_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */
+
+/*
+ * Checksum total. All 8 bytes in station address PROM will add up to this
+ */
+#define ZE_WD_ROM_CHECKSUM_TOTAL 0xFF
+
+#define ZE_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */
+#define ZE_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */
+#define ZE_WD_IO_PORTS 32 /* # of i/o addresses used */
+
+#define ZE_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */
+
+/*
+ * Definitions for 3Com 3c503
+ */
+#define ZE_3COM_NIC_OFFSET 0
+#define ZE_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */
+
+/*
+ * XXX - The I/O address range is fragmented in the 3c503; this is the
+ * number of regs at iobase.
+ */
+#define ZE_3COM_IO_PORTS 16 /* # of i/o addresses used */
+
+#define ZE_3COM_PAGE_OFFSET 0x20 /* memory starts in second bank */
+
+/*
+ * Page Start Register. Must match PSTART in NIC
+ */
+#define ZE_3COM_PSTR 0
+
+/*
+ * Page Stop Register. Must match PSTOP in NIC
+ */
+#define ZE_3COM_PSPR 1
+
+/*
+ * Drq Timer Register. Determines number of bytes to be transfered during
+ * a DMA burst.
+ */
+#define ZE_3COM_DQTR 2
+
+/*
+ * Base Configuration Register. Read-only register which contains the
+ * board-configured I/O base address of the adapter. Bit encoded.
+ */
+#define ZE_3COM_BCFR 3
+
+#define ZE_3COM_BCFR_2E0 0x01
+#define ZE_3COM_BCFR_2A0 0x02
+#define ZE_3COM_BCFR_280 0x04
+#define ZE_3COM_BCFR_250 0x08
+#define ZE_3COM_BCFR_350 0x10
+#define ZE_3COM_BCFR_330 0x20
+#define ZE_3COM_BCFR_310 0x40
+#define ZE_3COM_BCFR_300 0x80
+
+/*
+ * EPROM Configuration Register. Read-only register which contains the
+ * board-configured memory base address. Bit encoded.
+ */
+#define ZE_3COM_PCFR 4
+
+#define ZE_3COM_PCFR_C8000 0x10
+#define ZE_3COM_PCFR_CC000 0x20
+#define ZE_3COM_PCFR_D8000 0x40
+#define ZE_3COM_PCFR_DC000 0x80
+
+/*
+ * GA Configuration Register. Gate-Array Configuration Register.
+ */
+#define ZE_3COM_GACFR 5
+
+/*
+ * mbs2 mbs1 mbs0 start address
+ * 0 0 0 0x0000
+ * 0 0 1 0x2000
+ * 0 1 0 0x4000
+ * 0 1 1 0x6000
+ *
+ * Note that with adapters with only 8K, the setting for 0x2000 must
+ * always be used.
+ */
+#define ZE_3COM_GACFR_MBS0 0x01
+#define ZE_3COM_GACFR_MBS1 0x02
+#define ZE_3COM_GACFR_MBS2 0x04
+
+#define ZE_3COM_GACFR_RSEL 0x08 /* enable shared memory */
+#define ZE_3COM_GACFR_TEST 0x10 /* for GA testing */
+#define ZE_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
+#define ZE_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
+#define ZE_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
+
+/*
+ * Control Register. Miscellaneous control functions.
+ */
+#define ZE_3COM_CR 6
+
+#define ZE_3COM_CR_RST 0x01 /* Reset GA and NIC */
+#define ZE_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
+#define ZE_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
+#define ZE_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
+#define ZE_3COM_CR_SHARE 0x10 /* select interrupt sharing option */
+#define ZE_3COM_CR_DBSEL 0x20 /* Double buffer select */
+#define ZE_3COM_CR_DDIR 0x40 /* DMA direction select */
+#define ZE_3COM_CR_START 0x80 /* Start DMA controller */
+
+/*
+ * Status Register. Miscellaneous status information.
+ */
+#define ZE_3COM_STREG 7
+
+#define ZE_3COM_STREG_REV 0x07 /* GA revision */
+#define ZE_3COM_STREG_DIP 0x08 /* DMA in progress */
+#define ZE_3COM_STREG_DTC 0x10 /* DMA terminal count */
+#define ZE_3COM_STREG_OFLW 0x20 /* Overflow */
+#define ZE_3COM_STREG_UFLW 0x40 /* Underflow */
+#define ZE_3COM_STREG_DPRDY 0x80 /* Data port ready */
+
+/*
+ * Interrupt/DMA Configuration Register
+ */
+#define ZE_3COM_IDCFR 8
+
+#define ZE_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
+#define ZE_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
+#define ZE_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
+#define ZE_3COM_IDCFR_UNUSED 0x08 /* not used */
+#define ZE_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
+#define ZE_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
+#define ZE_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
+#define ZE_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
+
+/*
+ * DMA Address Register MSB
+ */
+#define ZE_3COM_DAMSB 9
+
+/*
+ * DMA Address Register LSB
+ */
+#define ZE_3COM_DALSB 0x0a
+
+/*
+ * Vector Pointer Register 2
+ */
+#define ZE_3COM_VPTR2 0x0b
+
+/*
+ * Vector Pointer Register 1
+ */
+#define ZE_3COM_VPTR1 0x0c
+
+/*
+ * Vector Pointer Register 0
+ */
+#define ZE_3COM_VPTR0 0x0d
+
+/*
+ * Register File Access MSB
+ */
+#define ZE_3COM_RFMSB 0x0e
+
+/*
+ * Register File Access LSB
+ */
+#define ZE_3COM_RFLSB 0x0f
+#endif
diff --git a/sys/i386/isa/ipl.h b/sys/i386/isa/ipl.h
new file mode 100644
index 000000000000..248ca5666d67
--- /dev/null
+++ b/sys/i386/isa/ipl.h
@@ -0,0 +1,7 @@
+#ifndef _ISA_IPL_H_
+#define _ISA_IPL_H_
+
+#define NHWI 16 /* number of h/w interrupts */
+#define HWI_MASK 0xffff /* bits corresponding to h/w interrupts */
+
+#endif /* _ISA_IPL_H_ */
diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c
index 3dbc748d9d55..588be2cccc7f 100644
--- a/sys/i386/isa/isa.c
+++ b/sys/i386/isa/isa.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- * $Id: isa.c,v 1.14 1994/01/22 21:52:04 rgrimes Exp $
+ * $Id: isa.c,v 1.19 1994/06/22 05:52:39 jkh Exp $
*/
/*
@@ -124,9 +124,11 @@ haveseen(dvp, tmpdvp)
if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
(dvp->id_iobase <=
(tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
+#ifndef ALLOW_CONFLICT_IOADDR
conflict(dvp, tmpdvp, dvp->id_iobase,
"I/O address", "0x%x");
status = 1;
+#endif
}
}
/*
@@ -143,12 +145,14 @@ haveseen(dvp, tmpdvp)
if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
(KERNBASE + dvp->id_maddr <=
(tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
+#ifndef ALLOW_CONFLICT_MEMADDR
conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
"0x%x");
status = 1;
+#endif
}
}
-#ifndef COM_MULTIPORT
+#ifndef ALLOW_CONFLICT_IRQ
/*
* Check for IRQ conflicts.
*/
@@ -160,6 +164,7 @@ haveseen(dvp, tmpdvp)
}
}
#endif
+#ifndef ALLOW_CONFLICT_DRQ
/*
* Check for DRQ conflicts.
*/
@@ -170,6 +175,7 @@ haveseen(dvp, tmpdvp)
status = 1;
}
}
+#endif
}
return (status);
}
@@ -213,38 +219,45 @@ isa_configure() {
printf("Probing for devices on the ISA bus:\n");
for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&ttymask);
+ config_isadev(dvp,&tty_imask);
}
for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&biomask);
+ config_isadev(dvp,&bio_imask);
}
for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&netmask);
+ config_isadev(dvp,&net_imask);
}
for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
config_isadev(dvp,(u_int *) NULL);
}
+ bio_imask |= SWI_CLOCK_MASK;
+ net_imask |= SWI_NET_MASK;
+ tty_imask |= SWI_TTY_MASK;
+
/*
- * XXX We should really add the tty device to netmask when the line is
+ * XXX we should really add the tty device to net_imask when the line is
* switched to SLIPDISC, and then remove it when it is switched away from
- * SLIPDISC. No need to block out ALL ttys during a splnet when only one
+ * SLIPDISC. No need to block out ALL ttys during a splimp when only one
* of them is running slip.
+ *
+ * XXX actually, blocking all ttys during a splimp doesn't matter so much
+ * with sio because the serial interrupt layer doesn't use tty_imask. Only
+ * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked
+ * during spltty.
*/
#include "sl.h"
#if NSL > 0
- netmask |= ttymask;
- ttymask |= netmask;
+ net_imask |= tty_imask;
+ tty_imask = net_imask;
+#endif
+ /* bio_imask |= tty_imask ; can some tty devices use buffers? */
+#ifdef DIAGNOSTIC
+ printf("bio_imask %x tty_imask %x net_imask %x\n",
+ bio_imask, tty_imask, net_imask);
#endif
- /* if netmask == 0, then the loopback code can do some really
- * bad things.
- */
- if (netmask == 0)
- netmask = 0x10000;
- /* biomask |= ttymask ; can some tty devices use buffers? */
- printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
splnone();
}
@@ -337,15 +350,12 @@ extern inthand_t
IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
-static inthand_func_t defvec[16] = {
+static inthand_func_t defvec[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
-/* out of range default interrupt vector gate entry */
-extern inthand_t IDTVEC(intrdefault);
-
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
@@ -356,12 +366,8 @@ isa_defaultirq()
int i;
/* icu vectors */
- for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
- setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
-
- /* out of range vectors */
- for (i = NRSVIDT; i < NIDT; i++)
- setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
+ for (i = 0; i < ICU_LEN; i++)
+ setidt(ICU_OFFSET + i, defvec[i], SDT_SYS386IGT, SEL_KPL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
@@ -530,7 +536,7 @@ isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
#define ISARAM_END RAM_END
if (phys == 0)
panic("isa_dmacheck: no physical page present");
- if (phys > ISARAM_END)
+ if (phys >= ISARAM_END)
return (1);
if (priorpage) {
if (priorpage + NBPG != phys)
@@ -588,14 +594,18 @@ isa_freephysmem(caddr_t va, unsigned length) {
/*
* Handle a NMI, possibly a machine check.
+ * This is generally one of two things, either an memory parity error
+ * or a bus master timeout failure. A bus-master timeout is indicated
+ * by bit 4 of port 0x461 going high.
+ *
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
-
- log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x, port 461 %x\n",
+ inb(0x61), inb(0x70), inb(0x461));
return(0);
}
@@ -627,165 +637,6 @@ isa_strayintr(d)
}
/*
- * Wait "n" microseconds.
- * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
- * (1 * TIMER_FREQ) Hz.
- * Note: timer had better have been programmed before this is first used!
- * (The standard programming causes the timer to generate a square wave and
- * the counter is decremented twice every cycle.)
- */
-#define CF (1 * TIMER_FREQ)
-#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
-
-void
-DELAY(n)
- int n;
-{
- int counter_limit;
- int prev_tick;
- int tick;
- int ticks_left;
- int sec;
- int usec;
-
-#ifdef DELAYDEBUG
- int getit_calls = 1;
- int n1;
- static int state = 0;
-
- if (state == 0) {
- state = 1;
- for (n1 = 1; n1 <= 10000000; n1 *= 10)
- DELAY(n1);
- state = 2;
- }
- if (state == 1)
- printf("DELAY(%d)...", n);
-#endif
-
- /*
- * Read the counter first, so that the rest of the setup overhead is
- * counted. Guess the initial overhead is 20 usec (on most systems it
- * takes about 1.5 usec for each of the i/o's in getit(). The loop
- * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
- * multiplications and divisions to scale the count take a while).
- */
- prev_tick = getit(0, 0);
- n -= 20;
-
- /*
- * Calculate (n * (CF / 1e6)) without using floating point and without
- * any avoidable overflows.
- */
- sec = n / 1000000;
- usec = n - sec * 1000000;
- ticks_left = sec * CF
- + usec * (CF / 1000000)
- + usec * ((CF % 1000000) / 1000) / 1000
- + usec * (CF % 1000) / 1000000;
-
- counter_limit = TIMER_FREQ / hz;
- while (ticks_left > 0) {
- tick = getit(0, 0);
-#ifdef DELAYDEBUG
- ++getit_calls;
-#endif
- if (tick > prev_tick)
- ticks_left -= prev_tick - (tick - counter_limit);
- else
- ticks_left -= prev_tick - tick;
- prev_tick = tick;
- }
-#ifdef DELAYDEBUG
- if (state == 1)
- printf(" %d calls to getit() at %d usec each\n",
- getit_calls, (n + 5) / getit_calls);
-#endif
-}
-
-int
-getit(unit, timer)
- int unit;
- int timer;
-{
- int high;
- int low;
-
- /*
- * XXX - isa.h defines bogus timers. There's no such timer as
- * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
- * its interface is quite different. Neither timer is an 8252.
- * We actually only call this with unit = 0 and timer = 0. It
- * could be static...
- */
- /*
- * Protect ourself against interrupts.
- * XXX - sysbeep() and sysbeepstop() need protection.
- */
- disable_intr();
- /*
- * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
- */
- outb(IO_TIMER1 + 3, timer << 6);
-
- low = inb(IO_TIMER1 + timer);
- high = inb(IO_TIMER1 + timer);
- enable_intr();
- return ((high << 8) | low);
-}
-
-static int beeping;
-
-static void
-sysbeepstop(f, dummy)
- caddr_t f;
- int dummy;
-{
- /* disable counter 2 */
- outb(0x61, inb(0x61) & 0xFC);
- if (f)
- timeout(sysbeepstop, (caddr_t)0, (int)f);
- else
- beeping = 0;
-}
-
-void
-sysbeep(int pitch, int period)
-{
-
- outb(0x61, inb(0x61) | 3); /* enable counter 2 */
- /*
- * XXX - move timer stuff to clock.c.
- * Program counter 2:
- * ccaammmb, c counter, a = access, m = mode, b = BCD
- * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
- */
- outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
-
- outb(0x42, pitch);
- outb(0x42, (pitch>>8));
-
- if (!beeping) {
- beeping = period;
- timeout(sysbeepstop, (caddr_t)(period/2), period);
- }
-}
-
-/*
- * Pass command to keyboard controller (8042)
- */
-unsigned
-kbc_8042cmd(val)
- int val;
-{
-
- while (inb(KBSTATP)&KBS_IBF);
- if (val) outb(KBCMDP, val);
- while (inb(KBSTATP)&KBS_IBF);
- return (inb(KBDATAP));
-}
-
-/*
* find an ISA device in a given isa_devtab_* table, given
* the table to search, the expected id_driver entry, and the unit number.
*
diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h
index cb083fdcf4cb..32786e6008c1 100644
--- a/sys/i386/isa/isa.h
+++ b/sys/i386/isa/isa.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.h 5.7 (Berkeley) 5/9/91
- * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $
+ * $Id: isa.h,v 1.5 1994/04/21 14:20:54 sos Exp $
*/
#ifndef _I386_ISA_ISA_H_
@@ -47,12 +47,8 @@
#ifndef LOCORE
#include <sys/cdefs.h>
-unsigned char rtcin __P((int));
extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
-void sysbeep __P((int, int));
-unsigned kbd_8042cmd __P((int));
-struct isa_device;
-int isa_irq_pending __P((struct isa_device *dvp));
+unsigned char rtcin __P((int));
#endif
@@ -69,6 +65,7 @@ int isa_irq_pending __P((struct isa_device *dvp));
#define IO_TIMER1 0x040 /* 8253 Timer #1 */
#define IO_TIMER2 0x048 /* 8253 Timer #2 */
#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_PPI 0x061 /* Programmabel Peripheral Interface */
#define IO_RTC 0x070 /* RTC */
#define IO_NMI IO_RTC /* NMI Control */
#define IO_DMAPG 0x080 /* DMA Page Registers */
diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h
index 6299f89912a4..670dacf4dfa6 100644
--- a/sys/i386/isa/isa_device.h
+++ b/sys/i386/isa/isa_device.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
- * $Id: isa_device.h,v 1.5 1994/01/04 20:06:30 nate Exp $
+ * $Id: isa_device.h,v 1.7 1994/06/08 14:01:04 davidg Exp $
*/
#ifndef _I386_ISA_ISA_DEVICE_H_
@@ -46,7 +46,7 @@
*/
struct isa_device {
struct isa_driver *id_driver;
- short id_iobase; /* base i/o address */
+ int id_iobase; /* base i/o address */
u_short id_irq; /* interrupt request */
short id_drq; /* DMA request */
caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
diff --git a/sys/i386/isa/kbdtables.h b/sys/i386/isa/kbdtables.h
index 011bc2cd1879..1fbd3215f367 100644
--- a/sys/i386/isa/kbdtables.h
+++ b/sys/i386/isa/kbdtables.h
@@ -14,7 +14,7 @@
* DK9210 Aalborg SO Phone: +45 9814 8076
*
* @(#)kbdtables.h 1.3 940123
- * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ * $Id: kbdtables.h,v 1.13 1994/05/27 01:09:16 ache Exp $
*/
#define SET8 0x80 /* eight bit for emacs SET8-key */
@@ -374,17 +374,17 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00,
-/* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00,
-/* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00,
-/* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00,
-/* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00,
-/* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00,
-/* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00,
-/* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
-/* sc=0d */ 0xB4, '`', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
@@ -397,8 +397,8 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
-/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01,
-/* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 0x00,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
@@ -410,11 +410,11 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
-/* sc=27 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01,
-/* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01,
-/* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 0x00,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
-/* sc=2b */ '\'', '*', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
@@ -457,7 +457,7 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
-/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
@@ -569,7 +569,7 @@ keymap_t key_map = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
@@ -698,7 +698,7 @@ keymap_t key_map = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
diff --git a/sys/i386/isa/lpa.c b/sys/i386/isa/lpa.c
index 89434cbf3da7..8d4aa3f7470f 100644
--- a/sys/i386/isa/lpa.c
+++ b/sys/i386/isa/lpa.c
@@ -45,7 +45,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: lpa.c,v 1.5 1994/02/22 09:04:08 rgrimes Exp $
+ * $Id: lpa.c,v 1.6 1994/04/11 07:57:36 csgr Exp $
*/
/*
@@ -178,6 +178,18 @@ lpaprobe(struct isa_device *dvp)
u_char data;
u_char mask;
int i;
+ static int warned = 0;
+
+
+ /* Warn users that the lpa driver should no longer be used */
+ if(!warned) {
+ printf("*************************************************\n");
+ printf("WARNING: The lpa driver is now obsolete, and will\n");
+ printf("WARNING: be removed soon.\n");
+ printf("WARNING: Please change your config to use lpt\n");
+ printf("*************************************************\n");
+ warned = 1;
+ }
status = IO_LPTSIZE;
diff --git a/sys/i386/isa/lpt.c b/sys/i386/isa/lpt.c
index 42f92c74f8d0..2715ea8b193f 100644
--- a/sys/i386/isa/lpt.c
+++ b/sys/i386/isa/lpt.c
@@ -46,7 +46,7 @@
* SUCH DAMAGE.
*
* from: unknown origin, 386BSD 0.1
- * $Id: lpt.c,v 1.9 1994/02/22 09:05:13 rgrimes Exp $
+ * $Id: lpt.c,v 1.13 1994/06/08 14:34:54 davidg Exp $
*/
/*
@@ -66,11 +66,14 @@
#include "ioctl.h"
#include "tty.h"
#include "uio.h"
+#include "syslog.h"
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/lptreg.h"
+#include "i386/include/lpt.h"
+
#define LPINITRDY 4 /* wait up to 4 seconds for a ready */
#define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
#define LPPRI (PZERO+8)
@@ -90,15 +93,6 @@
int lptflag = 1;
#endif
-void lptout();
-
-int lptprobe(), lptattach();
-void lptintr();
-
-struct isa_driver lptdriver = {
- lptprobe, lptattach, "lpt"
-};
-
#define LPTUNIT(s) ((s)&0x03)
#define LPTFLAGS(s) ((s)&0xfc)
@@ -122,6 +116,8 @@ struct lpt_softc {
u_char sc_irq ; /* IRQ status of port */
#define LP_HAS_IRQ 0x01 /* we have an irq available */
#define LP_USE_IRQ 0x02 /* we are using our irq */
+#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */
+
} lpt_sc[NLPT] ;
/* bits for state */
@@ -149,12 +145,21 @@ struct lpt_softc {
#define MAX_SPIN 20 /* Max delay for device ready in usecs */
+static void lptout (struct lpt_softc * sc);
+int lptprobe (struct isa_device *dvp);
+int lptattach (struct isa_device *isdp);
+void lptintr (int unit);
+
+struct isa_driver lptdriver = {
+ lptprobe, lptattach, "lpt"
+};
+
/*
* Internal routine to lptprobe to do port tests of one byte value
*/
-int
+static int
lpt_port_test(short port, u_char data, u_char mask)
{
int temp, timeout;
@@ -279,8 +284,7 @@ end_probe:
/* XXX Todo - try and detect if interrupt is working */
int
-lptattach(isdp)
- struct isa_device *isdp;
+lptattach(struct isa_device *isdp)
{
struct lpt_softc *sc;
@@ -292,7 +296,7 @@ lptattach(isdp)
/* check if we can use interrupt */
lprintf("oldirq %x\n", sc->sc_irq);
if(isdp->id_irq) {
- sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ;
+ sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
printf("lpt%d: Interrupt-driven port\n", isdp->id_unit);
} else {
sc->sc_irq = 0;
@@ -308,9 +312,7 @@ lptattach(isdp)
*/
int
-lptopen(dev, flag)
- dev_t dev;
- int flag;
+lptopen(dev_t dev, int flag)
{
struct lpt_softc *sc;
int s;
@@ -321,7 +323,6 @@ lptopen(dev, flag)
if ((unit >= NLPT) || (sc->sc_port == 0))
return (ENXIO);
- /* Only check open bit */
if (sc->sc_state) {
lprintf("lp: still open\n") ;
lprintf("still open %x\n", sc->sc_state);
@@ -333,6 +334,13 @@ lptopen(dev, flag)
lprintf("lp flags 0x%x\n", sc->sc_flags);
port = sc->sc_port;
+ /* set IRQ status according to ENABLE_IRQ flag */
+ if(sc->sc_irq & LP_ENABLE_IRQ)
+ sc->sc_irq |= LP_USE_IRQ;
+ else
+ sc->sc_irq &= ~LP_USE_IRQ;
+
+
/* init printer */
if((sc->sc_flags & LP_NO_PRIME) == 0) {
if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
@@ -384,20 +392,19 @@ lptopen(dev, flag)
lprintf("irq %x\n", sc->sc_irq);
if(sc->sc_irq & LP_USE_IRQ) {
sc->sc_state |= TOUT;
- timeout (lptout, (caddr_t)sc, hz/2);
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
}
lprintf("opened.\n");
return(0);
}
-void
-lptout (sc)
- struct lpt_softc *sc;
+static void
+lptout (struct lpt_softc * sc)
{ int pl;
lprintf ("T %x ", inb(sc->sc_port+lpt_status));
if (sc->sc_state&OPEN)
- timeout (lptout, (caddr_t)sc, hz/2);
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
else sc->sc_state &= ~TOUT;
if (sc->sc_state & ERROR)
@@ -423,9 +430,7 @@ lptout (sc)
*/
int
-lptclose(dev, flag)
- dev_t dev;
- int flag;
+lptclose(dev_t dev, int flag)
{
struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
int port = sc->sc_port;
@@ -458,13 +463,13 @@ lptclose(dev, flag)
* This code is only used when we are polling the port
*/
static int
-pushbytes(sc)
- struct lpt_softc *sc;
+pushbytes(struct lpt_softc * sc)
{
int spin, err, tic;
char ch;
int port = sc->sc_port;
+ lprintf("p");
/* loop for every character .. */
while (sc->sc_xfercnt > 0) {
/* printer data */
@@ -518,9 +523,7 @@ pushbytes(sc)
*/
int
-lptwrite(dev, uio)
- dev_t dev;
- struct uio *uio;
+lptwrite(dev_t dev, struct uio * uio)
{
register unsigned n;
int pl, err;
@@ -531,26 +534,26 @@ lptwrite(dev, uio)
sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
uiomove(sc->sc_cp, n, uio);
sc->sc_xfercnt = n ;
- if(sc->sc_irq & LP_USE_IRQ)
- while (sc->sc_xfercnt > 0) {
- lprintf("i");
- /* if the printer is ready for a char, */
- /* give it one */
- if ((sc->sc_state & OBUSY) == 0){
- lprintf("\nC %d. ", sc->sc_xfercnt);
- pl = spltty();
- lptintr(sc - lpt_sc);
- (void) splx(pl);
- }
- lprintf("W ");
- if (sc->sc_state & OBUSY)
- if (err = tsleep ((caddr_t)sc,
- LPPRI|PCATCH, "lpwrite", 0)) {
- sc->sc_state |= INTERRUPTED;
- return(err);
- }
+ while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
+ lprintf("i");
+ /* if the printer is ready for a char, */
+ /* give it one */
+ if ((sc->sc_state & OBUSY) == 0){
+ lprintf("\nC %d. ", sc->sc_xfercnt);
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ (void) splx(pl);
}
- else { /* polled write */
+ lprintf("W ");
+ if (sc->sc_state & OBUSY)
+ if (err = tsleep ((caddr_t)sc,
+ LPPRI|PCATCH, "lpwrite", 0)) {
+ sc->sc_state |= INTERRUPTED;
+ return(err);
+ }
+ }
+ /* check to see if we must do a polled write */
+ if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
lprintf("p");
if((err = pushbytes(sc)))
return(err);
@@ -567,8 +570,7 @@ lptwrite(dev, uio)
*/
void
-lptintr(unit)
- int unit;
+lptintr(int unit)
{
struct lpt_softc *sc = lpt_sc + unit;
int port = sc->sc_port, sts;
@@ -607,22 +609,40 @@ lptintr(unit)
}
int
-lptioctl(dev, cmd, data, flag)
- dev_t dev;
- int cmd;
- caddr_t data;
- int flag;
+lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
{
- int error;
+ int error = 0;
+ struct lpt_softc *sc;
+ u_int unit = LPTUNIT(minor(dev));
+ u_char old_sc_irq; /* old printer IRQ status */
+
+ sc = lpt_sc + unit;
- error = 0;
switch (cmd) {
-#ifdef THISISASAMPLE
- case XXX:
- dothis; andthis; andthat;
- error=x;
- break;
-#endif /* THISISASAMPLE */
+ case LPT_IRQ :
+ if(sc->sc_irq & LP_HAS_IRQ) {
+ /*
+ * NOTE:
+ * If the IRQ status is changed,
+ * this will only be visible on the
+ * next open.
+ *
+ * If interrupt status changes,
+ * this gets syslog'd.
+ */
+ old_sc_irq = sc->sc_irq;
+ if(*(int*)data == 0)
+ sc->sc_irq &= (~LP_ENABLE_IRQ);
+ else
+ sc->sc_irq |= LP_ENABLE_IRQ;
+ if (old_sc_irq != sc->sc_irq )
+ log(LOG_NOTICE, "lpt%c switched to %s mode\n",
+ (char)unit+'0',
+ (sc->sc_irq & LP_ENABLE_IRQ)?
+ "interrupt-driven":"polled");
+ } else /* polled port */
+ error = EOPNOTSUPP;
+ break;
default:
error = ENODEV;
}
diff --git a/sys/i386/isa/mcd.c b/sys/i386/isa/mcd.c
index 190d42be3b75..3245dadc4097 100644
--- a/sys/i386/isa/mcd.c
+++ b/sys/i386/isa/mcd.c
@@ -39,7 +39,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: mcd.c,v 1.10.2.2 1994/03/23 23:51:39 rgrimes Exp $
+ * $Id: mcd.c,v 1.16 1994/04/30 17:03:33 gclarkii Exp $
*/
static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
@@ -350,6 +350,9 @@ MCD_TRACE("strategy: drive not valid\n",0,0,0,0);
if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
goto done;
}
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
}
/* queue it */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index 2979e0cfd7ab..e83a503feeed 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91
- * $Id: npx.c,v 1.6 1994/01/03 07:55:43 davidg Exp $
+ * $Id: npx.c,v 1.9 1994/06/11 02:36:32 davidg Exp $
*/
#include "npx.h"
@@ -114,7 +114,7 @@ struct isa_driver npxdriver = {
npxprobe, npxattach, "npx",
};
-u_int npx0mask;
+u_int npx0_imask = SWI_CLOCK_MASK;
struct proc *npxproc;
static bool_t npx_ex16;
@@ -292,7 +292,7 @@ npxprobe1(dvp)
* Bad, we are stuck with IRQ13.
*/
npx_irq13 = 1;
- npx0mask = dvp->id_irq; /* npxattach too late */
+ npx0_imask = dvp->id_irq; /* npxattach too late */
return (IO_NPXSIZE);
}
/*
@@ -321,10 +321,12 @@ npxattach(dvp)
struct isa_device *dvp;
{
if (!npx_ex16 && !npx_irq13) {
- if (npx_exists)
+ if (npx_exists) {
printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
- else
+ npx_exists = 0;
+ } else {
printf("npx%d: 387 Emulator\n",dvp->id_unit);
+ }
}
npxinit(__INITIAL_NPXCW__);
return (1); /* XXX unused */
@@ -528,8 +530,8 @@ npxsave(addr)
old_icu1_mask = inb(IO_ICU1 + 1);
old_icu2_mask = inb(IO_ICU2 + 1);
save_idt_npxintr = idt[npx_intrno];
- outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
- outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
idt[npx_intrno] = npx_idt_probeintr;
enable_intr();
stop_emulating();
@@ -541,10 +543,10 @@ npxsave(addr)
icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
icu2_mask = inb(IO_ICU2 + 1);
outb(IO_ICU1 + 1,
- (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
+ (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
outb(IO_ICU2 + 1,
- (icu2_mask & ~(npx0mask >> 8))
- | (old_icu2_mask & (npx0mask >> 8)));
+ (icu2_mask & ~(npx0_imask >> 8))
+ | (old_icu2_mask & (npx0_imask >> 8)));
idt[npx_intrno] = save_idt_npxintr;
enable_intr(); /* back to usual state */
}
diff --git a/sys/i386/isa/pcaudio.c b/sys/i386/isa/pcaudio.c
new file mode 100644
index 000000000000..0c48e407a7be
--- /dev/null
+++ b/sys/i386/isa/pcaudio.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: pcaudio.c,v 1.5 1994/05/27 08:51:03 sos Exp $
+ */
+
+#include "systm.h"
+#include "uio.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "file.h"
+#include "sound/ulaw.h"
+#include "machine/cpufunc.h"
+#include "machine/pio.h"
+#include "machine/pcaudioio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+
+#include "pca.h"
+#if NPCA > 0
+
+#define BUF_SIZE 4*8192
+#define SAMPLE_RATE 8000
+#define INTERRUPT_RATE 16000
+
+static struct pca_status {
+ char open; /* device open */
+ char queries; /* did others try opening */
+ unsigned char *buf[2]; /* double buffering */
+ unsigned char *buffer; /* current buffer ptr */
+ unsigned in_use[2]; /* buffers fill */
+ unsigned index; /* index in current buffer */
+ unsigned counter; /* sample counter */
+ unsigned scale; /* sample counter scale */
+ unsigned sample_rate; /* sample rate */
+ unsigned processed; /* samples processed */
+ unsigned volume; /* volume for pc-speaker */
+ char encoding; /* Ulaw, Alaw or linear */
+ char current; /* current buffer */
+ unsigned char oldval; /* old timer port value */
+ char timer_on; /* is playback running */
+ char coll; /* select collision */
+ pid_t wsel; /* pid of select'ing proc */
+} pca_status;
+
+static char buffer1[BUF_SIZE];
+static char buffer2[BUF_SIZE];
+static char volume_table[256];
+
+static int pca_sleep = 0;
+static int pca_initialized = 0;
+
+void pcaintr(int regs);
+int pcaprobe(struct isa_device *dvp);
+int pcaattach(struct isa_device *dvp);
+int pcaclose(dev_t dev, int flag);
+int pcaopen(dev_t dev, int flag);
+int pcawrite(dev_t dev, struct uio *uio, int flag);
+int pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+int pcaselect(dev_t dev, int rw, struct proc *p);
+
+struct isa_driver pcadriver = {
+ pcaprobe, pcaattach, "pca",
+};
+
+
+inline void conv(const void *table, void *buff, unsigned long n)
+{
+ __asm__("1:\tmovb (%2), %3\n"
+ "\txlatb\n"
+ "\tmovb %3, (%2)\n"
+ "\tinc %2\n"
+ "\tdec %1\n"
+ "\tjnz 1b\n"
+ :
+ :"b" ((long)table), "c" (n), "D" ((long)buff), "a" ((char)n)
+ :"bx","cx","di","ax");
+}
+
+
+static void
+pca_volume(int volume)
+{
+ int i, j;
+
+ for (i=0; i<256; i++) {
+ j = ((i-128)*volume)/100;
+ if (j<-128)
+ j = -128;
+ if (j>127)
+ j = 127;
+ volume_table[i] = (((255-(j + 128))/4)+1);
+ }
+}
+
+
+static void
+pca_init()
+{
+ pca_status.open = 0;
+ pca_status.queries = 0;
+ pca_status.timer_on = 0;
+ pca_status.buf[0] = (unsigned char *)&buffer1[0];
+ pca_status.buf[1] = (unsigned char *)&buffer2[0];
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.current = 0;
+ pca_status.sample_rate = SAMPLE_RATE;
+ pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ pca_status.encoding = AUDIO_ENCODING_ULAW;
+ pca_status.volume = 100;
+
+ pca_volume(pca_status.volume);
+}
+
+
+static int
+pca_start(void)
+{
+ /* use the first buffer */
+ pca_status.current = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ /* acquire the timers */
+ if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT)) {
+ return -1;
+ }
+ if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
+ release_timer2();
+ return -1;
+ }
+ pca_status.timer_on = 1;
+ return 0;
+}
+
+
+static void
+pca_stop(void)
+{
+ /* release the timers */
+ release_timer0();
+ release_timer2();
+ /* reset the buffer */
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.current = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_pause()
+{
+ release_timer0();
+ release_timer2();
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_continue()
+{
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
+ acquire_timer0(INTERRUPT_RATE, pcaintr);
+ pca_status.timer_on = 1;
+}
+
+
+static void
+pca_wait(void)
+{
+ while (pca_status.in_use[0] || pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
+ }
+}
+
+
+int
+pcaprobe(struct isa_device *dvp)
+{
+ return(-1);
+}
+
+
+int
+pcaattach(struct isa_device *dvp)
+{
+ printf(" PCM audio driver\n", dvp->id_unit);
+ pca_init();
+ return 1;
+}
+
+
+int
+pcaopen(dev_t dev, int flag)
+{
+ /* audioctl device can always be opened */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ if (!pca_initialized) {
+ pca_init();
+ pca_initialized = 1;
+ }
+
+ /* audio device can only be open by one process */
+ if (pca_status.open) {
+ pca_status.queries = 1;
+ return EBUSY;
+ }
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.timer_on = 0;
+ pca_status.open = 1;
+ pca_status.processed = 0;
+ return 0;
+}
+
+
+int
+pcaclose(dev_t dev, int flag)
+{
+ /* audioctl device can always be closed */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+ /* audio device close drains all output and restores timers */
+ pca_wait();
+ pca_stop();
+ pca_status.open = 0;
+ return 0;
+}
+
+
+int
+pcawrite(dev_t dev, struct uio *uio, int flag)
+{
+ int count, which;
+
+ /* only audio device can be written */
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
+ if (pca_status.in_use[0] && pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_wait",0);
+ }
+ which = pca_status.in_use[0] ? 1 : 0;
+ if (count && !pca_status.in_use[which]) {
+ uiomove(pca_status.buf[which], count, uio);
+ pca_status.processed += count;
+ switch (pca_status.encoding) {
+ case AUDIO_ENCODING_ULAW:
+ conv(ulaw_dsp, pca_status.buf[which], count);
+ break;
+
+ case AUDIO_ENCODING_ALAW:
+ break;
+
+ case AUDIO_ENCODING_RAW:
+ break;
+ }
+ pca_status.in_use[which] = count;
+ if (!pca_status.timer_on)
+ if (pca_start())
+ return EBUSY;
+ }
+ }
+ return 0;
+}
+
+
+int
+pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ audio_info_t *auptr;
+
+ switch(cmd) {
+
+ case AUDIO_GETINFO:
+ auptr = (audio_info_t *)data;
+ auptr->play.sample_rate = pca_status.sample_rate;
+ auptr->play.channels = 1;
+ auptr->play.precision = 8;
+ auptr->play.encoding = pca_status.encoding;
+
+ auptr->play.gain = pca_status.volume;
+ auptr->play.port = 0;
+
+ auptr->play.samples = pca_status.processed;
+ auptr->play.eof = 0;
+ auptr->play.pause = !pca_status.timer_on;
+ auptr->play.error = 0;
+ auptr->play.waiting = pca_status.queries;
+
+ auptr->play.open = pca_status.open;
+ auptr->play.active = pca_status.timer_on;
+ return 0;
+
+ case AUDIO_SETINFO:
+ auptr = (audio_info_t *)data;
+ if (auptr->play.sample_rate != (unsigned int)~0) {
+ pca_status.sample_rate = auptr->play.sample_rate;
+ pca_status.scale =
+ (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ }
+ if (auptr->play.encoding != (unsigned int)~0) {
+ pca_status.encoding = auptr->play.encoding;
+ }
+ if (auptr->play.gain != (unsigned int)~0) {
+ pca_status.volume = auptr->play.gain;
+ pca_volume(pca_status.volume);
+ }
+ if (auptr->play.pause != (unsigned char)~0) {
+ if (auptr->play.pause)
+ pca_pause();
+ else
+ pca_continue();
+ }
+
+ return 0;
+
+ case AUDIO_DRAIN:
+ pca_wait();
+ return 0;
+
+ case AUDIO_FLUSH:
+ pca_stop();
+ return 0;
+
+ }
+ return ENXIO;
+}
+
+
+void
+pcaintr(int regs)
+{
+ if (pca_status.index < pca_status.in_use[pca_status.current]) {
+ disable_intr();
+ __asm__("outb %0,$0x61\n"
+ "andb $0xFE,%0\n"
+ "outb %0,$0x61"
+ : : "a" ((char)pca_status.oldval) );
+ __asm__("xlatb\n"
+ "outb %0,$0x42"
+ : : "a" ((char)pca_status.buffer[pca_status.index]),
+ "b" ((long)volume_table) );
+ enable_intr();
+ pca_status.counter += pca_status.scale;
+ pca_status.index = (pca_status.counter >> 8);
+ }
+ if (pca_status.index >= pca_status.in_use[pca_status.current]) {
+ pca_status.index = pca_status.counter = 0;
+ pca_status.in_use[pca_status.current] = 0;
+ pca_status.current ^= 1;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ if (pca_sleep) {
+ wakeup((caddr_t)&pca_sleep);
+ pca_sleep = 0;
+ }
+ if (pca_status.wsel) {
+ selwakeup(pca_status.wsel, pca_status.coll);
+ pca_status.wsel = 0;
+ pca_status.coll = 0;
+ }
+ }
+}
+
+
+int
+pcaselect(dev_t dev, int rw, struct proc *p)
+{
+ int s = spltty();
+ struct proc *p1;
+
+ switch (rw) {
+
+ case FWRITE:
+ if (!pca_status.in_use[0] || !pca_status.in_use[1]) {
+ splx(s);
+ return(1);
+ }
+ if (pca_status.wsel && (p1 = pfind(pca_status.wsel))
+ && p1->p_wchan == (caddr_t)&selwait)
+ pca_status.coll = 1;
+ else
+ pca_status.wsel = p->p_pid;
+ splx(s);
+ return 0;
+ default:
+ splx(s);
+ return(0);
+ }
+}
+#endif
diff --git a/sys/i386/isa/pccons.c b/sys/i386/isa/pccons.c
index 43fba38b1552..3d729da6dc54 100644
--- a/sys/i386/isa/pccons.c
+++ b/sys/i386/isa/pccons.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)pccons.c 5.11 (Berkeley) 5/21/91
- * $Id: pccons.c,v 1.13.2.1 1994/05/04 05:09:30 rgrimes Exp $
+ * $Id: pccons.c,v 1.17 1994/05/30 03:15:09 ache Exp $
*/
/*
@@ -63,7 +63,7 @@
int pc_xmode;
#endif /* XSERVER */
-struct tty pccons;
+struct tty *pccons;
struct pcconsoftc {
char cs_flags;
@@ -289,13 +289,12 @@ pcopen(dev, flag, mode, p)
if (minor(dev) != 0)
return (ENXIO);
- tp = &pccons;
+ tp = pccons = ttymalloc(pccons);
tp->t_oproc = pcstart;
tp->t_param = pcparam;
tp->t_dev = dev;
openf++;
if ((tp->t_state & TS_ISOPEN) == 0) {
- tp->t_state |= TS_WOPEN;
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
@@ -316,8 +315,12 @@ pcclose(dev, flag, mode, p)
int flag, mode;
struct proc *p;
{
- (*linesw[pccons.t_line].l_close)(&pccons, flag);
- ttyclose(&pccons);
+ (*linesw[pccons->t_line].l_close)(pccons, flag);
+ ttyclose(pccons);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ ttyfree(pccons);
+ pccons = (struct tty *)NULL;
+#endif
return(0);
}
@@ -328,7 +331,7 @@ pcread(dev, uio, flag)
struct uio *uio;
int flag;
{
- return ((*linesw[pccons.t_line].l_read)(&pccons, uio, flag));
+ return ((*linesw[pccons->t_line].l_read)(pccons, uio, flag));
}
/*ARGSUSED*/
@@ -338,7 +341,7 @@ pcwrite(dev, uio, flag)
struct uio *uio;
int flag;
{
- return ((*linesw[pccons.t_line].l_write)(&pccons, uio, flag));
+ return ((*linesw[pccons->t_line].l_write)(pccons, uio, flag));
}
/*
@@ -347,10 +350,8 @@ pcwrite(dev, uio, flag)
* Catch the character, and see who it goes to.
*/
void
-pcrint(dev, irq, cpl)
- dev_t dev;
- int irq; /* XXX ??? */
- int cpl;
+pcrint(unit)
+ int unit;
{
int c;
char *cp;
@@ -361,7 +362,7 @@ pcrint(dev, irq, cpl)
if (pcconsoftc.cs_flags & CSF_POLLING)
return;
#ifdef KDB
- if (kdbrintr(c, &pccons))
+ if (kdbrintr(c, pccons))
return;
#endif
if (!openf)
@@ -369,11 +370,11 @@ pcrint(dev, irq, cpl)
#ifdef XSERVER /* 15 Aug 92*/
/* send at least one character, because cntl-space is a null */
- (*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
+ (*linesw[pccons->t_line].l_rint)(*cp++ & 0xff, pccons);
#endif /* XSERVER */
while (*cp)
- (*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
+ (*linesw[pccons->t_line].l_rint)(*cp++ & 0xff, pccons);
}
#ifdef XSERVER /* 15 Aug 92*/
@@ -389,7 +390,7 @@ pcioctl(dev, cmd, data, flag)
caddr_t data;
int flag;
{
- register struct tty *tp = &pccons;
+ register struct tty *tp = pccons;
register error;
#ifdef XSERVER /* 15 Aug 92*/
@@ -436,12 +437,12 @@ pcxint(dev)
if (!pcconsintr)
return;
- pccons.t_state &= ~TS_BUSY;
+ pccons->t_state &= ~TS_BUSY;
pcconsoftc.cs_timo = 0;
- if (pccons.t_line)
- (*linesw[pccons.t_line].l_start)(&pccons);
+ if (pccons->t_line)
+ (*linesw[pccons->t_line].l_start)(pccons);
else
- pcstart(&pccons);
+ pcstart(pccons);
}
void
@@ -454,20 +455,11 @@ pcstart(tp)
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
do {
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (RB_LEN(&tp->t_out) == 0)
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
+ if (RB_LEN(tp->t_out) == 0)
goto out;
- c = getc(&tp->t_out);
+ c = getc(tp->t_out);
tp->t_state |= TS_BUSY; /* 21 Aug 92*/
splx(s);
sput(c, 0);
@@ -491,7 +483,7 @@ pccnprobe(cp)
/* initialize required fields */
cp->cn_dev = makedev(maj, 0);
- cp->cn_tp = &pccons;
+ cp->cn_tp = pccons;
cp->cn_pri = CN_INTERNAL;
}
@@ -639,26 +631,13 @@ static u_char shift_down, ctrl_down, alt_down, caps, num, scroll;
/* translate ANSI color codes to standard pc ones */
static char fgansitopc[] =
{ FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
- FG_MAGENTA, FG_CYAN, FG_LIGHTGREY};
+ FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
+};
static char bgansitopc[] =
{ BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
- BG_MAGENTA, BG_CYAN, BG_LIGHTGREY};
-
-static void move_up(u_short *s, u_short *d, u_int len)
-{
- s += len;
- d += len;
- while (len-- > 0)
- *--d = *--s;
-}
-
-
-static void move_down(u_short *s, u_short *d, u_int len)
-{
- while (len-- > 0)
- *d++ = *s++;
-}
+ BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
+};
/*
* sput has support for emulation of the 'pc3' termcap entry.
@@ -872,7 +851,7 @@ sput(c, ka)
posy = (crtat - Crtat) / vs.ncol;
if (vs.cx > posy)
vs.cx = posy;
- bcopy(Crtat+vs.ncol*vs.cx, Crtat, vs.ncol*(vs.nrow-vs.cx)*CHR);
+ bcopyw(Crtat+vs.ncol*vs.cx, Crtat, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ',
(Crtat + vs.ncol * (vs.nrow - vs.cx)),
vs.ncol * vs.cx);
@@ -884,7 +863,7 @@ sput(c, ka)
posy = (crtat - Crtat) / vs.ncol;
if (vs.cx > vs.nrow - posy)
vs.cx = vs.nrow - posy;
- bcopy(Crtat, Crtat+vs.ncol*vs.cx, vs.ncol*(vs.nrow-vs.cx)*CHR);
+ bcopyw(Crtat, Crtat+vs.ncol*vs.cx, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ', Crtat, vs.ncol*vs.cx);
/* crtat += vs.ncol*vs.cx;*/ /* XXX */
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
@@ -897,7 +876,7 @@ sput(c, ka)
src = Crtat + posy * vs.ncol;
dst = src + vs.cx * vs.ncol;
count = vs.nrow - (posy + vs.cx);
- move_up(src, dst, count * vs.ncol);
+ bcopyw(src, dst, count * vs.ncol * CHR);
fillw((at <<8)+' ', src, vs.cx * vs.ncol);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
@@ -909,7 +888,7 @@ sput(c, ka)
dst = Crtat + posy * vs.ncol;
src = dst + vs.cx * vs.ncol;
count = vs.nrow - (posy + vs.cx);
- move_down(src, dst, count * vs.ncol);
+ bcopyw(src, dst, count * vs.ncol * CHR);
src = dst + count * vs.ncol;
fillw((at <<8)+' ', src, vs.cx * vs.ncol);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
@@ -999,7 +978,7 @@ sput(c, ka)
}
if (sc && crtat >= Crtat+vs.ncol*vs.nrow) { /* scroll check */
if (openf) do (void)sgetc(1); while (scroll);
- bcopy(Crtat+vs.ncol, Crtat, vs.ncol*(vs.nrow-1)*CHR);
+ bcopyw(Crtat+vs.ncol, Crtat, vs.ncol*(vs.nrow-1)*CHR);
fillw ((at << 8) + ' ', Crtat + vs.ncol*(vs.nrow-1),
vs.ncol);
crtat -= vs.ncol;
@@ -1557,6 +1536,12 @@ loop:
#endif /* !XSERVER*/
}
+ /*
+ * Check for cntl-alt-del
+ */
+ if ((dt == 83) && ctrl_down && alt_down)
+ cpu_reset();
+
#include "ddb.h"
#if NDDB > 0
/*
@@ -1564,7 +1549,7 @@ loop:
*/
if ((dt == 1) && ctrl_down && alt_down) {
Debugger("manual escape to debugger");
- dt |= 0x80; /* discard esc (ddb discarded ctrl-alt) */
+ goto loop;
}
#endif
@@ -1797,7 +1782,7 @@ void cons_normal()
int pcmmap(dev_t dev, int offset, int nprot)
{
- if (offset > 0x20000)
+ if (offset > 0x20000 - PAGE_SIZE)
return -1;
return i386_btop((0xa0000 + offset));
}
diff --git a/sys/i386/isa/psm.c b/sys/i386/isa/psm.c
new file mode 100644
index 000000000000..d12298727ca3
--- /dev/null
+++ b/sys/i386/isa/psm.c
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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.
+ */
+
+/*
+ * Ported to 386bsd Oct 17, 1992
+ * Sandi Donno, Computer Science, University of Cape Town, South Africa
+ * Please send bug reports to sandi@cs.uct.ac.za
+ *
+ * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
+ * although I was only partially successful in getting the alpha release
+ * of his "driver for the Logitech and ATI Inport Bus mice for use with
+ * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
+ * found his code to be an invaluable reference when porting this driver
+ * to 386bsd.
+ *
+ * Further modifications for latest 386BSD+patchkit and port to NetBSD,
+ * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
+ *
+ * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
+ * Andrew Herbert - 12 June 1993
+ *
+ * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
+ * - 13 June 1993
+ *
+ * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
+ * - 24 October 1993
+ */
+
+#include "psm.h"
+
+#if NPSM > 0
+
+#include "param.h"
+#include "kernel.h"
+#include "systm.h"
+#include "buf.h"
+#include "malloc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "file.h"
+#include "proc.h"
+#include "vnode.h"
+
+#include "i386/include/mouse.h"
+#include "i386/include/pio.h" /* Julian's fast IO macros */
+#include "i386/isa/isa_device.h"
+
+#ifdef 0
+#include "syslog.h" /* For debugging */
+#endif
+
+#define DATA 0 /* Offset for data port, read-write */
+#define CNTRL 4 /* Offset for control port, write-only */
+#define STATUS 4 /* Offset for status port, read-only */
+
+/* status bits */
+#define PSM_OUTPUT_ACK 0x02 /* output acknowledge */
+
+/* controller commands */
+#define PSM_ENABLE 0xa8 /* enable auxiliary port */
+#define PSM_DISABLE 0xa7 /* disable auxiliary port */
+#define PSM_INT_ENABLE 0x47 /* enable controller interrupts */
+#define PSM_INT_DISABLE 0x65 /* disable controller interrupts */
+
+/* m+use commands */
+#define PSM_SET_SCALE11 0xe6 /* set 1:1 scaling */
+#define PSM_SET_SCALE21 0xe7 /* set 2:1 scaling */
+#define PSM_SET_RES 0xe8 /* set resolution */
+#define PSM_GET_SCALE 0xe9 /* set scaling factor */
+#define PSM_SET_STREAM 0xea /* set streaming mode */
+#define PSM_SET_SAMPLE 0xf3 /* set sampling rate */
+#define PSM_DEV_ENABLE 0xf4 /* mouse on */
+#define PSM_DEV_DISABLE 0xf5 /* mouse off */
+#define PSM_RESET 0xff /* reset */
+
+#define PSMUNIT(dev) (minor(dev) >> 1)
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif min
+
+int psmprobe (struct isa_device *);
+int psmattach (struct isa_device *);
+void psm_poll_status(void);
+
+static int psmaddr[NPSM]; /* Base I/O port addresses per unit */
+
+#define MSBSZ 1024 /* Output queue size (pwr of 2 is best) */
+
+struct ringbuf {
+ int count, first, last;
+ char queue[MSBSZ];
+};
+
+static struct psm_softc { /* Driver status information */
+ struct ringbuf inq; /* Input queue */
+ pid_t rsel; /* Process selecting for Input */
+ unsigned char state; /* Mouse driver state */
+ unsigned char status; /* Mouse button status */
+ unsigned char button; /* Previous mouse button status bits */
+ int x, y; /* accumulated motion in the X,Y axis */
+} psm_softc[NPSM];
+
+#define OPEN 1 /* Device is open */
+#define ASLP 2 /* Waiting for mouse data */
+
+struct isa_driver psmdriver = { psmprobe, psmattach, "psm" };
+
+#define AUX_PORT 0x60 /* AUX_PORT base (S.Yuen) */
+
+static void psm_write_dev(int inport, u_char value)
+{
+ psm_poll_status();
+ outb(inport+CNTRL, 0xd4);
+ psm_poll_status();
+ outb(inport+DATA,value);
+}
+
+static inline void psm_command(int ioport, u_char value)
+{
+ psm_poll_status();
+ outb(ioport+CNTRL, 0x60);
+ psm_poll_status();
+ outb(ioport+DATA, value);
+}
+
+int psmprobe(struct isa_device *dvp)
+{
+ /* XXX: Needs a real probe routine. */
+
+ int ioport,c,unit;
+
+ ioport=dvp->id_iobase;
+ unit=dvp->id_unit;
+ psm_write_dev(ioport,0xff); /* Reset aux device */
+ psm_poll_status();
+ outb(ioport+CNTRL,0xa9);
+ psm_poll_status();
+ outb(ioport+CNTRL,0xaa);
+ c = inb(ioport+DATA);
+ if(c&0x04) {
+/* printf("PS/2 AUX mouse is not found\n");*/
+ psm_command(ioport,0x65);
+ psmaddr[unit] = 0; /* Device not found */
+ return(0);}
+/* printf("PS/2 AUX mouse found. Installing driver\n");*/
+ return (4);
+}
+
+int psmattach(struct isa_device *dvp)
+{
+ int unit = dvp->id_unit;
+ int ioport = dvp->id_iobase;
+ struct psm_softc *sc = &psm_softc[unit];
+
+ /* Save I/O base address */
+
+ psmaddr[unit] = ioport;
+
+ /* Disable mouse interrupts */
+
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_ENABLE);
+#ifdef 0
+ psm_write(ioport, PSM_SET_RES);
+ psm_write(ioport, 0x03); /* 8 counts/mm */
+ psm_write(ioport, PSM_SET_SCALE);
+ psm_write(ioport, 0x02); /* 2:1 */
+ psm_write(ioport, PSM_SET_SCALE21);
+ psm_write(ioport, PSM_SET_SAMPLE);
+ psm_write(ioport, 0x64); /* 100 samples/sec */
+ psm_write(ioport, PSM_SET_STREAM);
+#endif
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_DISABLE);
+ psm_command(ioport, PSM_INT_DISABLE);
+
+ /* Setup initial state */
+
+ sc->state = 0;
+
+ /* Done */
+
+ return(0);
+}
+
+int psmopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = PSMUNIT(dev);
+ struct psm_softc *sc;
+ int ioport;
+
+ /* Validate unit number */
+
+ if (unit >= NPSM)
+ return(ENXIO);
+
+ /* Get device data */
+
+ sc = &psm_softc[unit];
+ ioport = psmaddr[unit];
+
+ /* If device does not exist */
+
+ if (ioport == 0)
+ return(ENXIO);
+
+ /* Disallow multiple opens */
+ if (sc->state & OPEN)
+ return(EBUSY);
+
+ /* Initialize state */
+
+ sc->state |= OPEN;
+ sc->rsel = 0;
+ sc->status = 0;
+ sc->button = 0;
+ sc->x = 0;
+ sc->y = 0;
+
+ /* Allocate and initialize a ring buffer */
+
+ sc->inq.count = sc->inq.first = sc->inq.last = 0;
+
+ /* Enable Bus Mouse interrupts */
+
+ psm_write_dev(ioport, PSM_DEV_ENABLE);
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_ENABLE);
+ psm_command(ioport, PSM_INT_ENABLE);
+
+ /* Successful open */
+
+ return(0);
+}
+
+void psm_poll_status(void)
+{
+
+ while(inb(AUX_PORT+STATUS)&0x03) {
+ if(inb(AUX_PORT+STATUS) & 0x2 == 0x2)
+ inb(AUX_PORT+DATA);}
+ return;
+}
+
+
+int psmclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit, ioport;
+ struct psm_softc *sc;
+
+ /* Get unit and associated info */
+
+ unit = PSMUNIT(dev);
+ sc = &psm_softc[unit];
+ ioport = psmaddr[unit];
+
+ /* Disable further mouse interrupts */
+
+ psm_command(ioport,PSM_INT_DISABLE);
+ psm_poll_status();
+ outb(ioport+CNTRL,PSM_DISABLE );
+
+ /* Complete the close */
+
+ sc->state &= ~OPEN;
+
+ /* close is almost always successful */
+
+ return(0);
+}
+
+int psmread(dev_t dev, struct uio *uio, int flag)
+{
+ int s;
+ int error = 0; /* keep compiler quiet, even though initialisation
+ is unnecessary */
+ unsigned length;
+ struct psm_softc *sc;
+ unsigned char buffer[100];
+
+ /* Get device information */
+
+ sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Block until mouse activity occured */
+
+ s = spltty();
+ while (sc->inq.count == 0) {
+ if (minor(dev) & 0x1) {
+ splx(s);
+ return(EWOULDBLOCK);
+ }
+ sc->state |= ASLP;
+ error = tsleep((caddr_t)sc, PZERO | PCATCH, "psmrea", 0);
+ if (error != 0) {
+ splx(s);
+ return(error);
+ }
+ }
+
+ /* Transfer as many chunks as possible */
+
+ while (sc->inq.count > 0 && uio->uio_resid > 0) {
+ length = min(sc->inq.count, uio->uio_resid);
+ if (length > sizeof(buffer))
+ length = sizeof(buffer);
+
+ /* Remove a small chunk from input queue */
+
+ if (sc->inq.first + length >= MSBSZ) {
+ bcopy(&sc->inq.queue[sc->inq.first],
+ buffer, MSBSZ - sc->inq.first);
+ bcopy(sc->inq.queue, &buffer[MSBSZ-sc->inq.first],
+ length - (MSBSZ - sc->inq.first));
+ }
+ else
+ bcopy(&sc->inq.queue[sc->inq.first], buffer, length);
+
+ sc->inq.first = (sc->inq.first + length) % MSBSZ;
+ sc->inq.count -= length;
+
+ /* Copy data to user process */
+
+ error = uiomove(buffer, length, uio);
+ if (error)
+ break;
+ }
+
+ sc->x = sc->y = 0;
+
+ /* Allow interrupts again */
+
+ splx(s);
+ return(error);
+}
+
+int psmioctl(dev_t dev, caddr_t addr, int cmd, int flag, struct proc *p)
+{
+ struct psm_softc *sc;
+ struct mouseinfo info;
+ int s, error;
+
+ /* Get device information */
+
+ sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Perform IOCTL command */
+
+ switch (cmd) {
+
+ case MOUSEIOCREAD:
+
+ /* Don't modify info while calculating */
+
+ s = spltty();
+
+ /* Build mouse status octet */
+
+ info.status = sc->status;
+ if (sc->x || sc->y)
+ info.status |= MOVEMENT;
+
+ /* Encode X and Y motion as good as we can */
+
+ if (sc->x > 127)
+ info.xmotion = 127;
+ else if (sc->x < -128)
+ info.xmotion = -128;
+ else
+ info.xmotion = sc->x;
+
+ if (sc->y > 127)
+ info.ymotion = 127;
+ else if (sc->y < -128)
+ info.ymotion = -128;
+ else
+ info.ymotion = sc->y;
+
+ /* Reset historical information */
+
+ sc->x = 0;
+ sc->y = 0;
+ sc->status &= ~BUTCHNGMASK;
+
+ /* Allow interrupts and copy result buffer */
+
+ splx(s);
+ error = copyout(&info, addr, sizeof(struct mouseinfo));
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ /* Return error code */
+
+ return(error);
+}
+
+void psmintr(unit)
+ int unit;
+{
+ struct psm_softc *sc = &psm_softc[unit];
+ int ioport = psmaddr[unit];
+
+ sc->inq.queue[sc->inq.last++ % MSBSZ] = inb(ioport+DATA);
+ sc->inq.count++;
+ if (sc -> state & ASLP) {
+ sc->state &= ~ASLP;
+ wakeup((caddr_t)sc);
+ }
+ if (sc->rsel) {
+ selwakeup(sc->rsel, 0);
+ sc->rsel = 0;
+ }
+}
+
+int psmselect(dev_t dev, int rw, struct proc *p)
+{
+ int s, ret;
+ struct psm_softc *sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Silly to select for output */
+
+ if (rw == FWRITE)
+ return(0);
+
+ /* Return true if a mouse event available */
+
+ s = spltty();
+ if (sc->inq.count)
+ ret = 1;
+ else {
+ sc->rsel = p->p_pid;
+ ret = 0;
+ }
+ splx(s);
+
+ return(ret);
+}
+#endif
+
+
diff --git a/sys/i386/isa/seagate.c b/sys/i386/isa/seagate.c
new file mode 100644
index 000000000000..31c515166663
--- /dev/null
+++ b/sys/i386/isa/seagate.c
@@ -0,0 +1,2036 @@
+/*
+ * (Free/Net/386)BSD ST01/02, Future Domain TMC-885, TMC-950 SCSI driver for
+ * Julians SCSI-code
+ *
+ * Copyright 1994, Kent Palmkvist (kentp@isy.liu.se)
+ * Copyright 1994, Robert Knier (rknier@qgraph.com)
+ * Copyright 1992, 1994 Drew Eckhardt (drew@colorado.edu)
+ * Copyright 1994, Julian Elischer (julian@tfs.com)
+ *
+ * Others that has contributed by example code is
+ * Glen Overby (overby@cray.com)
+ * Tatu Yllnen
+ * Brian E Litzinger
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/*
+ *
+ * kentp 940307 alpha version based on newscsi-03 version of Julians SCSI-code
+ * kentp 940314 Added possibility to not use messages
+ * rknier 940331 Added fast transfer code
+ * rknier 940407 Added assembler coded data transfers
+ *
+ * $Id: seagate.c,v 1.3 1994/06/16 13:26:14 sean Exp $
+ */
+
+/*
+ * What should really be done:
+ *
+ * Add missing tests for timeouts
+ * Restructure interrupt enable/disable code (runs to long with int disabled)
+ * Find bug? giving problem with tape status
+ * Add code to handle Future Domain 840, 841, 880 and 881
+ * adjust timeouts (startup is very slow)
+ * add code to use tagged commands in SCSI2
+ * Add code to handle slow devices better (sleep if device not disconnecting)
+ * Fix unnecessary interrupts
+ */
+
+/* Note to users trying to share a disk between DOS and unix:
+ * The ST01/02 is a translating host-adapter. It is not giving DOS
+ * the same number of heads/tracks/sectors as specified by the disk.
+ * It is therefore important to look at what numbers DOS thinks the
+ * disk has. Use these to disklabel your disk in an appropriate manner
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. look for main() */
+#include <sea.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <i386/isa/isa_device.h>
+#endif /* KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /* KERNEL */
+#define NSEA 1
+#endif /* KERNEL */
+
+extern int hz;
+
+#define SEA_SCB_MAX 8 /* allow maximally 8 scsi control blocks */
+#define SCB_TABLE_SIZE 8 /* start with 8 scb entries in table */
+#define BLOCK_SIZE 512 /* size of READ/WRITE areas on SCSI card */
+
+/*
+ * defining PARITY causes parity data to be checked
+ */
+#define PARITY 1
+
+/*
+ * defining SEA_BLINDTRANSFER will make DATA IN and DATA OUT to be done with
+ * blind transfers, i.e. no check is done for scsi phase changes. This will
+ * result in data loss if the scsi device does not send its data using
+ * BLOCK_SIZE bytes at a time.
+ * If SEA_BLINDTRANSFER defined and SEA_ASSEMBLER also defined will result in
+ * the use of blind transfers coded in assembler. SEA_ASSEMBLER is no good
+ * without SEA_BLINDTRANSFER defined.
+ */
+#define SEA_BLINDTRANSFER 1 /* do blind transfers */
+#define SEA_ASSEMBLER 1 /* Use assembly code for fast transfers */
+
+/*
+ * defining SEANOMSGS causes messages not to be used (thereby disabling
+ * disconnects)
+ */
+/* #define SEANOMSGS 1 */
+
+/*
+ * defining SEA_NODATAOUT makes dataout phase being aborted
+ */
+/* #define SEA_NODATAOUT 1 */
+
+/*
+ * defining SEA_SENSEFIRST make REQUEST_SENSE opcode to be placed first
+ */
+/* #define SEA_SENSEFIRST 1 */
+
+#define SEA_FREEBSD11 1 /* intermediate def. for FreeBSD 1.1 BETA */
+ /* timeout function has changed */
+
+/* Debugging definitions. Should not be used unless you want a lot of
+ printouts even under normal conditions */
+
+/* #define SEADEBUG 1 */ /* General info about errors */
+/* #define SEADEBUG1 1 */ /* Info about internal results and errors */
+/* #define SEADEBUG2 1 */ /* Display a lot about timeouts etc */
+/* #define SEADEBUG3 1 */
+/* #define SEADEBUG4 1 */
+/* #define SEADEBUG5 1 */
+/* #define SEADEBUG6 1 */ /* Display info about queue-lengths */
+/* #define SEADEBUG7 1 */ /* Extra check on STATUS before phase check */
+/* #define SEADEBUG8 1 */ /* Disregard non-BSY state in
+ sea_information_transfer */
+/* #define SEADEBUG9 1 */ /* Enable printouts */
+/* #define SEADEBUG11 1 */ /* stop everything except access to scsi id 1 */
+/* #define SEADEBUG15 1 */ /* Display every byte sent/received */
+
+#define NUM_CONCURRENT 1 /* number of concurrent ops per board */
+
+/******************************* board definitions **************************/
+/*
+ * CONTROL defines
+ */
+
+#define CMD_RST 0x01 /* scsi reset */
+#define CMD_SEL 0x02 /* scsi select */
+#define CMD_BSY 0x04 /* scsi busy */
+#define CMD_ATTN 0x08 /* scsi attention */
+#define CMD_START_ARB 0x10 /* start arbitration bit */
+#define CMD_EN_PARITY 0x20 /* enable scsi parity generation */
+#define CMD_INTR 0x40 /* enable scsi interrupts */
+#define CMD_DRVR_ENABLE 0x80 /* scsi enable */
+
+/*
+ * STATUS
+ */
+
+#define STAT_BSY 0x01 /* scsi busy */
+#define STAT_MSG 0x02 /* scsi msg */
+#define STAT_IO 0x04 /* scsi I/O */
+#define STAT_CD 0x08 /* scsi C/D */
+#define STAT_REQ 0x10 /* scsi req */
+#define STAT_SEL 0x20 /* scsi select */
+#define STAT_PARITY 0x40 /* parity error bit */
+#define STAT_ARB_CMPL 0x80 /* arbitration complete bit */
+
+/*
+ * REQUESTS
+ */
+
+#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG)
+#define REQ_DATAOUT 0
+#define REQ_DATAIN STAT_IO
+#define REQ_CMDOUT STAT_CD
+#define REQ_STATIN (STAT_CD | STAT_IO)
+#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
+
+#define REQ_UNKNOWN 0xff
+
+#define SEAGATERAMOFFSET 0x00001800
+
+#ifdef PARITY
+ #define BASE_CMD (CMD_EN_PARITY | CMD_INTR)
+#else
+ #define BASE_CMD (CMD_INTR)
+#endif
+
+#define SEAGATE 1
+#define FD 2
+
+/******************************************************************************
+ * This should be placed in a more generic file (presume in /sys/scsi)
+ * Message codes:
+ */
+#define MSG_ABORT 0x06
+#define MSG_NOP 0x08
+#define MSG_COMMAND_COMPLETE 0x00
+#define MSG_DISCONNECT 0x04
+#define MSG_IDENTIFY 0x80
+#define MSG_BUS_DEV_RESET 0x0c
+#define MSG_MESSAGE_REJECT 0x07
+#define MSG_SAVE_POINTERS 0x02
+#define MSG_RESTORE_POINTERS 0x03
+/******************************************************************************/
+
+#define IDENTIFY(can_disconnect,lun) (MSG_IDENTIFY | ((can_disconnect) ? \
+ 0x40 : 0) | ((lun) & 0x07))
+
+/* scsi control block used to keep info about a scsi command */
+struct sea_scb
+{
+ int flags; /* status of the instruction */
+#define SCB_FREE 0
+#define SCB_ACTIVE 1
+#define SCB_ABORTED 2
+#define SCB_TIMEOUT 4
+#define SCB_ERROR 8
+#define SCB_TIMECHK 16 /* We have set a timeout on this one */
+ struct sea_scb *next; /* in free list */
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ u_char * data; /* position in data buffer so far */
+ int32 datalen; /* bytes remaining to transfer */;
+};
+
+/*
+ * data structure describing current status of the scsi bus. One for each
+ * controller card.
+ */
+struct sea_data
+{
+ caddr_t basemaddr; /* Base address for card */
+ char ctrl_type; /* FD or SEAGATE */
+ caddr_t st0x_cr_sr; /* Address of control and status register */
+ caddr_t st0x_dr; /* Address of data register */
+ u_short vect; /* interrupt vector for this card */
+ int our_id; /* our scsi id */
+ int numscb; /* number of scsi control blocks */
+ struct scsi_link sc_link; /* struct connecting different data */
+ struct sea_scb *connected; /* currently connected command */
+ struct sea_scb *issue_queue; /* waiting to be issued */
+ struct sea_scb *disconnected_queue; /* waiting to reconnect */
+ struct sea_scb scbs[SCB_TABLE_SIZE];
+ struct sea_scb *free_scb; /* free scb list */
+ volatile unsigned char busy[8]; /* index=target, bit=lun, Keep track of
+ busy luns at device target */
+} *seadata[NSEA];
+
+/* flag showing if main routine is running. */
+static volatile int main_running = 0;
+
+#define STATUS (*(volatile unsigned char *) sea->st0x_cr_sr)
+#define CONTROL STATUS
+#define DATA (*(volatile unsigned char *) sea->st0x_dr)
+
+/*
+ * These are "special" values for the tag parameter passed to sea_select
+ * Not implemented right now.
+ */
+
+#define TAG_NEXT -1 /* Use next free tag */
+#define TAG_NONE -2 /*
+ * Establish I_T_L nexus instead of I_T_L_Q
+ * even on SCSI-II devices.
+ */
+
+typedef struct {
+ char *signature ;
+ unsigned offset;
+ unsigned length;
+ unsigned char type;
+} BiosSignature;
+
+/*
+ * Signatures for automatic recognition of board type
+ */
+
+static const BiosSignature signatures[] = {
+{"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
+{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
+
+/*
+ * The following two lines are NOT mistakes. One detects ROM revision
+ * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter,
+ * and this is not going to change, the "SEAGATE" and "SCSI" together
+ * are probably "good enough"
+ */
+
+{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
+{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
+
+ /*
+ * However, future domain makes several incompatible SCSI boards, so specific
+ * signatures must be used.
+ */
+
+ {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 45, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90",5, 47, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
+ {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
+ {"FUTURE DOMAIN TMC-950", 5, 21, FD},
+ };
+
+#define NUM_SIGNATURES (sizeof(signatures) / sizeof(BiosSignature))
+
+static const char * seagate_bases[] = {
+ (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000,
+ (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000
+};
+
+#define NUM_BASES (sizeof(seagate_bases)/sizeof(char *))
+
+int sea_probe(struct isa_device *dev);
+int sea_attach(struct isa_device *dev);
+int seaintr(int unit);
+int32 sea_scsi_cmd(struct scsi_xfer *xs);
+#ifdef SEA_FREEBSD11
+void sea_timeout(caddr_t, int);
+#else
+void sea_timeout(struct sea_scb *scb);
+#endif
+void seaminphys(struct buf *bp);
+void sea_done(int unit, struct sea_scb *scb);
+u_int32 sea_adapter_info(int unit);
+struct sea_scb *sea_get_scb(int unit, int flags);
+void sea_free_scb(int unit, struct sea_scb *scb, int flags);
+static void sea_main(void);
+static void sea_information_transfer(struct sea_data *sea);
+int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb);
+int sea_init(int unit);
+int sea_send_scb(struct sea_data *sea, struct sea_scb *scb);
+int sea_reselect(struct sea_data *sea);
+int sea_select(struct sea_data *sea, struct sea_scb *scb);
+int sea_transfer_pio(struct sea_data *sea, u_char *phase, int32 *count,
+ u_char **data);
+int sea_abort(int unit, struct sea_scb *scb);
+
+static sea_unit = 0;
+static sea_slot = -1; /* last found board seagate_bases address index */
+#define FAIL 1
+#define SUCCESS 0
+
+#ifdef KERNEL
+struct scsi_adapter sea_switch =
+{
+ sea_scsi_cmd,
+ seaminphys,
+ 0,
+ 0,
+ sea_adapter_info,
+ "sea",
+ 0,0
+};
+
+/* the below structure is so we have a default dev struct for our link struct */
+struct scsi_device sea_dev =
+{
+ NULL, /* use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "sea",
+ 0,
+ 0,0
+};
+
+struct isa_driver seadriver =
+{
+ sea_probe,
+ sea_attach,
+ "sea"
+};
+
+#endif /* KERNEL */
+
+#ifdef SEADEBUG6
+void sea_queue_length()
+{
+ struct sea_scb *tmp;
+ int length = 0;
+
+ if(seadata[0]->connected)
+ length = 1;
+ for(tmp = seadata[0]->issue_queue; tmp != NULL; tmp = tmp->next, length++);
+ for(tmp = seadata[0]->disconnected_queue ; tmp != NULL; tmp->next, length++);
+ printf("length:%d ",length);
+}
+#endif
+
+/***********************************************************************\
+* Check if the device can be found at the port given and if so, detect *
+* the type of board. Set it up ready for further work. Takes the *
+* isa_dev structure from autoconf as an argument. *
+* Returns 1 if card recognized, 0 if errors *
+\***********************************************************************/
+int
+sea_probe(dev)
+struct isa_device *dev;
+{
+ int j;
+ int unit = sea_unit;
+ struct sea_data *sea;
+ dev->id_unit = unit;
+
+#ifdef SEADEBUG2
+ printf("sea_probe ");
+#endif
+
+ /* find unit and check we have that many defined */
+ if(unit >= NSEA) {
+ printf("sea%d: unit number too high\n",unit);
+ return(0);
+ }
+ dev->id_unit = unit;
+#ifdef SEADEBUG2
+ printf("unit: %d\n",unit);
+ printf("dev_addr: 0x%lx\n",dev->id_maddr);
+#endif
+ /* allocate a storage area for us */
+
+ if (seadata[unit]) {
+ printf("sea%d: memory already allocated\n", unit);
+ return(0);
+ }
+#ifdef SEADEBUG2
+ printf("Before malloc\n");
+#endif
+ sea = malloc(sizeof(struct sea_data), M_TEMP, M_NOWAIT);
+ if (!sea) {
+ printf("sea%d: cannot malloc!\n", unit);
+ return(0);
+ }
+
+#ifdef SEADEBUG2
+ printf("after malloc\n");
+ for(j=0;j<32767;j++);
+#endif
+ bzero(sea,sizeof(struct sea_data));
+ seadata[unit] = sea;
+
+ /* check for address if no one specified */
+ sea->basemaddr = NULL;
+
+ /* Could try to find a board by looking through all possible addresses */
+ /* This is not done the right way now, because I have not found a way */
+ /* to get a boards virtual memory address given its physical. There is */
+ /* a function that returns the physical address for a given virtual */
+ /* address, but not the other way around */
+
+ if(dev->id_maddr == 0) {
+/*
+ for(sea_slot++;sea_slot<NUM_BASES;sea_slot++)
+ for(j = 0; !sea->basemaddr && j < NUM_SIGNATURES; ++j)
+ if(!memcmp((void *)(seagate_bases[sea_slot]+signatures[j].offset),
+ (void *) signatures[j].signature, signatures[j].length)) {
+ sea->basemaddr = (void *)seagate_bases[sea_slot];
+ break;
+ }
+*/
+ } else {
+
+#ifdef SEADEBUG2
+ printf("id_maddr != 0\n");
+ for(j = 0; j < 32767 ; j++);
+ for(j = 0; j < 32767 ; j++);
+#endif
+ /* find sea_slot position for overridden memory address */
+ for(j = 0; ((char *)vtophys(dev->id_maddr) != seagate_bases[j]) &&
+ j<NUM_BASES; ++j);
+ if(j == NUM_BASES) {
+ printf("sea: board not expected at address 0x%lx\n",dev->id_maddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ } else if(sea_slot > j) {
+ printf("sea: board address 0x%lx already probed!\n", dev->id_maddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ } else {
+ sea->basemaddr = dev->id_maddr;
+ }
+
+ }
+#ifdef SEADEBUG2
+ printf("sea->basemaddr = %lx\n", sea->basemaddr);
+#endif
+
+ /* check board type */ /* No way to define this through config */
+ for(j = 0; j < NUM_SIGNATURES; j++)
+ if(!memcmp((void *) (sea->basemaddr + signatures[j].offset),
+ (void *) signatures[j].signature, signatures[j].length)) {
+ sea->ctrl_type = signatures[j].type;
+ break;
+ }
+ if(j == NUM_SIGNATURES) {
+ printf("sea: Board type unknown at address 0x%lx\n",
+ sea->basemaddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ }
+
+ /* Find controller and data memory addresses */
+ sea->st0x_cr_sr = (void *) (((unsigned char *) sea->basemaddr) +
+ ((sea->ctrl_type == SEAGATE) ? 0x1a00 : 0x1c00));
+ sea->st0x_dr = (void *) (((unsigned char *) sea->basemaddr) +
+ ((sea->ctrl_type == SEAGATE) ? 0x1c00 : 0x1e00));
+
+ /* Test controller RAM (works the same way on future domain cards?) */
+ *(sea->basemaddr + SEAGATERAMOFFSET) = 0xa5;
+ *(sea->basemaddr + SEAGATERAMOFFSET + 1) = 0x5a;
+
+ if((*(sea->basemaddr + SEAGATERAMOFFSET) != (char) 0xa5) ||
+ (*(sea->basemaddr + SEAGATERAMOFFSET + 1) != (char) 0x5a)) {
+ printf("sea%d: Board RAM failure\n",unit);
+ }
+
+ if(sea_init(unit) != 0) {
+ seadata[unit] = NULL;
+ free(sea,M_TEMP);
+ return(0);
+ }
+
+ /* if its there put in it's interrupt vector */
+ /* (Doesn't use dma, so no drq is set) */
+ sea->vect = dev->id_irq;
+
+ sea_unit++;
+ return(1);
+}
+
+/***********************************************\
+* Attach all sub-devices we can find *
+\***********************************************/
+int
+sea_attach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct sea_data *sea = seadata[unit];
+
+#ifdef SEADEBUG2
+ printf("sea_attach called\n");
+#endif
+
+ /* fill in the prototype scsi_link */
+ sea->sc_link.adapter_unit = unit;
+ sea->sc_link.adapter_targ = sea->our_id;
+ sea->sc_link.adapter = &sea_switch;
+ sea->sc_link.device = &sea_dev;
+
+ /*****************************************************\
+ * ask the adapter what subunits are present *
+ \*****************************************************/
+ scsi_attachdevs(&(sea->sc_link));
+ return 1;
+}
+
+/***********************************************\
+* Return some information to the caller about *
+* the adapter and its capabilities *
+\***********************************************/
+u_int32
+sea_adapter_info(unit)
+ int unit;
+{
+#ifdef SEADEBUG2
+ printf("sea_adapter_info called\n");
+#endif
+ return 1;
+}
+
+/***********************************************\
+* Catch an interrupt from the adaptor *
+\***********************************************/
+int
+seaintr(unit)
+ int unit;
+{
+ int done;
+ struct sea_data *sea = seadata[unit];
+ int oldpri;
+
+#if SEADEBUG2
+ printf(";");
+#endif
+
+ do {
+ done = 1;
+ /* dispatch to appropriate routine if found and done=0 */
+ /* should check to see that this card really caused the interrupt */
+ if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) {
+ /* Reselect interrupt */
+#ifdef SEADEBUG2
+ printf(";2");
+#endif
+ done = 0;
+/* enable_intr(); */ /* ?? How should this be done ?? */
+ sea_reselect(sea);
+ } else if (STATUS & STAT_PARITY) {
+ /* Parity error interrupt */
+#ifdef SEADEBUG2
+ printf(";3");
+#endif
+ printf("sea%d: PARITY interrupt\n", unit);
+ } else {
+#ifdef SEADEBUG2
+/* printf("sea%d: unknown interrupt\n",unit); */
+ printf(";4%x", STATUS);
+#endif
+ }
+ if (!done) {
+ oldpri = splbio(); /* disable_intr(); */
+ if (!main_running) {
+#ifdef SEADEBUG2
+ printf(";5");
+#endif
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri); /* enable_intr(); */
+ } else {
+ splx(oldpri); /* enable_intr(); */
+ }
+ }
+ } while (!done);
+ return 1;
+}
+
+/***********************************************\
+* Setup data structures, and reset the board *
+* and the scsi bus *
+\***********************************************/
+int
+sea_init(unit)
+ int unit;
+{
+ long l;
+ int i;
+ struct sea_data *sea = seadata[unit];
+
+#ifdef SEADEBUG2
+ printf("sea_init called\n");
+#endif
+/* Reset the scsi bus (I don't know if this is needed */
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_RST;
+ DELAY(25); /* hold reset for at least 25 microseconds */
+ CONTROL = BASE_CMD;
+ DELAY(10); /* wait a Bus Clear Delay (800 ns + bus free delay (800 ns) */
+ /* Set our id (don't know anything about this) */
+ if(sea->ctrl_type == SEAGATE)
+ sea->our_id = 7;
+ else
+ sea->our_id = 6;
+ /* init fields used by our routines */
+ sea->connected = NULL;
+ sea->issue_queue = NULL;
+ sea->disconnected_queue = NULL;
+ for (i=0; i<8 ; i++)
+ sea->busy[i] = 0;
+
+ /* link up the free list of scbs */
+ sea->numscb = SCB_TABLE_SIZE;
+ sea->free_scb = (struct sea_scb *) & (sea->scbs[0]);
+ for(i=1;i< SCB_TABLE_SIZE ; i++) {
+ sea->scbs[i-1].next = &(sea->scbs[i]);
+ }
+ sea->scbs[SCB_TABLE_SIZE - 1].next = NULL;
+
+ return(0);
+}
+
+/***********************************************\
+* *
+\***********************************************/
+void seaminphys(bp)
+ struct buf *bp;
+{
+#ifdef SEADEBUG2
+/* printf("seaminphys called\n"); */
+ printf(",");
+#endif
+}
+
+/***********************************************\
+* start a scsi operation given the command and *
+* the data address. Also needs the unit, target *
+* and lu *
+* get a free scb and set it up *
+* call send_scb *
+* either start timer or wait until done *
+\***********************************************/
+int32 sea_scsi_cmd(xs)
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct sea_scb *scb;
+ int i = 0;
+ int flags;
+ int unit = xs->sc_link->adapter_unit;
+ struct sea_data *sea = seadata[unit];
+ int s;
+ unsigned int stat;
+ int32 result;
+
+#ifdef SEADEBUG2
+ /* printf("scsi_cmd\n"); */
+ printf("=");
+#endif
+
+#ifdef SEADEBUG11
+ if(xs->sc_link->target != 1) {
+ xs->flags |= ITSDONE;
+ xs->error = XS_TIMEOUT;
+ return(HAD_ERROR);
+ }
+#endif
+
+ flags = xs->flags;
+ if(xs->bp) flags |= (SCSI_NOSLEEP);
+ if(flags & ITSDONE) {
+ printf("sea%d: Already done?", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if(!(flags & INUSE)) {
+ printf("sea%d: Not in use?", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(scb = sea_get_scb(unit, flags))) {
+#ifdef SEADEBUG2
+ printf("=2");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Put all the arguments for the xfer in the scb
+ */
+ scb->xfer = xs;
+ scb->datalen = xs->datalen;
+ scb->data = xs->data;
+
+ if(flags & SCSI_RESET) {
+ /* Try to send a reset command to the card. This is done by calling the
+ * Reset function. Should then return COMPLETE. Need to take care of the
+ * possible current connected command.
+ * Not implemented right now.
+ */
+ printf("sea%d: Got a SCSI_RESET!\n",unit);
+ }
+
+ /* setup the scb to contain necessary values */
+ /* The interresting values can be read from the xs that is saved */
+ /* I therefore think that the structure can be kept very small */
+ /* the driver doesn't use DMA so the scatter/gather is not needed ? */
+#ifdef SEADEBUG6
+ sea_queue_length();
+#endif
+ if (sea_send_scb(sea, scb) == 0) {
+#ifdef SEADEBUG2
+ printf("=3");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ sea_free_scb(unit, scb, flags);
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if (!(flags & SCSI_NOMASK)) {
+ if(xs->flags & ITSDONE) { /* timout timer not started, already finished */
+ /* Tried to return COMPLETE but the machine hanged with this */
+#ifdef SEADEBUG2
+ printf("=6");
+#endif
+ return(SUCCESSFULLY_QUEUED);
+ }
+#ifdef SEA_FREEBSD11
+ timeout(sea_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
+#else
+ timeout(sea_timeout, scb, (xs->timeout * hz) / 1000);
+#endif
+ scb->flags |= SCB_TIMECHK;
+#ifdef SEADEBUG2
+ printf("=4");
+#endif
+ return(SUCCESSFULLY_QUEUED);
+ }
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+
+ result = sea_poll(unit, xs, scb);
+#ifdef SEADEBUG2
+ printf("=5 %lx", result);
+#endif
+ return result;
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new one. If so,
+ * put it in the hash table too, otherwise return an error or sleep.
+ */
+
+struct sea_scb *
+sea_get_scb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct sea_data *sea = seadata[unit];
+ unsigned opri = 0;
+ struct sea_scb * scbp;
+ int hashnum;
+
+#ifdef SEADEBUG2
+/* printf("get_scb\n"); */
+ printf("(");
+#endif
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+#ifdef SEADEBUG3
+ printf("(2 %lx ", sea->free_scb);
+#endif
+
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we canŽt allocate a new one.
+ */
+ while (!(scbp = sea->free_scb)) {
+#ifdef SEADEBUG12
+ printf("(3");
+#endif
+ if (sea->numscb < SEA_SCB_MAX) {
+ printf("malloced new scbs\n");
+ if (scbp = (struct sea_scb *) malloc(sizeof(struct sea_scb),
+ M_TEMP, M_NOWAIT)) {
+ bzero(scbp, sizeof(struct sea_scb));
+ sea->numscb++;
+ scbp->flags = SCB_ACTIVE;
+ scbp->next = NULL;
+ } else {
+ printf("sea%d: Can't malloc SCB\n",unit);
+ }
+ goto gottit;
+ } else {
+#ifdef SEADEBUG12
+ printf("(4");
+#endif
+ if(!(flags & SCSI_NOSLEEP)) {
+#ifdef SEADEBUG2
+ printf("(5");
+#endif
+ tsleep(&sea->free_scb, PRIBIO, "seascb", 0);
+ }
+ }
+ }
+ if (scbp) {
+#ifdef SEADEBUG2
+ printf("(6");
+#endif
+ /* Get SCB from free list */
+ sea->free_scb = scbp->next;
+ scbp->next = NULL;
+ scbp->flags = SCB_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return(scbp);
+}
+
+/*
+ * sea_send_scb
+ *
+ * Try to send this command to the board. Because this board does not use any
+ * mailboxes, this routine simply adds the command to the queue held by the
+ * sea_data structure.
+ * A check is done to see if the command contains a REQUEST_SENSE command, and
+ * if so the command is put first in the queue, otherwise the command is added
+ * to the end of the queue. ?? Not correct ??
+ */
+int
+sea_send_scb(struct sea_data *sea, struct sea_scb *scb)
+{
+ struct sea_scb *tmp;
+ int oldpri = 0;
+
+#ifdef SEADEBUG2
+ printf("+");
+#endif
+
+ if(!(scb->xfer->flags & SCSI_NOSLEEP)) {
+ oldpri = splbio();
+ }
+
+ /* add to head of queue if queue empty or command is REQUEST_SENSE */
+
+ if (!(sea->issue_queue)
+#ifdef SEA_SENSEFIRST
+ || (scb->xfer->cmd->opcode == (u_char) REQUEST_SENSE)
+#endif
+ ) {
+#ifdef SEADEBUG2
+ printf("+2");
+#endif
+ scb->next = sea->issue_queue;
+ sea->issue_queue = scb;
+ } else {
+#ifdef SEADEBUG2
+ printf("+3");
+#endif
+ for (tmp = sea->issue_queue; tmp->next; tmp = tmp->next);
+ tmp->next = scb;
+ scb->next = NULL; /* placed at the end of the queue */
+ }
+ /* Try to do some work on the card */
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ }
+ if(!(scb->xfer->flags & SCSI_NOSLEEP)) {
+ splx(oldpri);
+ }
+ return (1); /* No possible errors right now */
+}
+
+/*
+ * sea_main(void)
+ *
+ * corroutine that runs as long as more work can be done on the seagate host
+ * adapter in a system. Both sea_scsi_cmd and sea_intr will try to start it in
+ * case it is not running.
+ */
+
+static void sea_main(void)
+{
+ struct sea_data *sea; /* This time we look at all cards */
+ struct sea_scb *tmp, *prev;
+ int done;
+ int unit;
+ int oldpri;
+
+#ifdef SEADEBUG2
+ printf(".");
+#endif
+
+ /*
+ * This should not be run with interrupts disabled, but use the splx code
+ * instead
+ */
+ do {
+ done = 1;
+ for (sea=seadata[unit=0]; (unit < NSEA) && seadata[unit] ;
+ sea=seadata[++unit]) {
+ oldpri = splbio();
+ if (!sea->connected) {
+#ifdef SEADEBUG2
+ printf(".2");
+#endif
+ /*
+ * Search through the issue_queue for a command destined for a
+ * target that's not busy.
+ */
+ for (tmp = sea->issue_queue, prev = NULL; tmp ;
+ prev = tmp, tmp = tmp->next)
+ /* When we find one, remove it from the issue queue. */
+ if (!(sea->busy[tmp->xfer->sc_link->target] &
+ (1 << tmp->xfer->sc_link->lun))) {
+ if (prev)
+ prev->next = tmp->next;
+ else
+ sea->issue_queue = tmp->next;
+ tmp->next = NULL;
+
+ /* re-enable interrupts after finding one */
+ splx(oldpri);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, sea->connected is set.
+ * On failure, we must add the command back to
+ * the issue queue so we can keep trying.
+ */
+#ifdef SEADEBUG2
+ printf(".3");
+#endif
+
+ /* REQUEST_SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent alligence condition exists for the
+ * entire unit.
+ */
+
+ /* First check that if any device has tried a reconnect while
+ * we have done other things with interrupts disabled
+ */
+
+ if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) {
+#ifdef SEADEBUG2
+ printf(".7");
+#endif
+ sea_reselect(sea);
+ break;
+ }
+ if (!sea_select(sea, tmp)) {
+#ifdef SEADEBUG2
+ /* printf("Select returned ok\n"); */
+ printf(".4");
+#endif
+ break;
+ } else {
+ oldpri = splbio();
+ tmp->next = sea->issue_queue;
+ sea->issue_queue = tmp;
+ splx(oldpri);
+ printf("sea_main: select failed\n");
+ }
+ } /* if target/lun is not busy */
+ } /* if (!sea->connected) */
+
+ if (sea->connected) { /* we are connected. Do the task */
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea_main: starting information transfer!\n"); */
+ printf(".5");
+#endif
+ sea_information_transfer(sea);
+#ifdef SEADEBUG2
+/* printf("sea_main: sea->connected:%lx\n", sea->connected); */
+ printf(".6%lx ", sea->connected);
+#endif
+ done = 0;
+ } else
+ break;
+ } /* for instance */
+ } while (!done);
+ main_running = 0;
+}
+
+void
+sea_free_scb(unit, scb, flags)
+ int unit;
+ struct sea_scb *scb;
+ int flags;
+{
+ struct sea_data *sea = seadata[unit];
+ unsigned int opri = 0;
+
+#ifdef SEADEBUG2
+/* printf("free_scb\n"); */
+ printf(")");
+#endif
+
+ if(!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ scb->next = sea->free_scb;
+ sea->free_scb = scb;
+ scb->flags = SCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if(!scb->next) {
+#ifdef SEADEBUG2
+/* printf("free_scb waking up sleep\n"); */
+ printf(")2");
+#endif
+#ifdef SEA_FREEBSD11
+ wakeup((caddr_t)&sea->free_scb);
+#else
+ wakeup(&sea->free_scb);
+#endif
+ }
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+#ifdef SEA_FREEBSD11
+void
+sea_timeout(caddr_t arg1, int arg2)
+#else
+void
+sea_timeout(struct sea_scb *scb)
+#endif
+{
+#ifdef SEA_FREEBSD11
+ struct sea_scb *scb = (struct sea_scb *)arg1;
+#endif
+ int unit;
+ struct sea_data *sea;
+ int s=splbio();
+
+#ifdef SEADEBUG2
+/* printf("sea_timeout called\n"); */
+ printf(":");
+#endif
+
+ unit = scb->xfer->sc_link->adapter_unit;
+ sea = seadata[unit];
+#ifndef SEADEBUG /* print message only if not waiting unless debug */
+ if(!(scb->xfer->flags & SCSI_NOMASK))
+#endif
+ printf("sea%d:%d:%d (%s%d) timed out ", unit,
+ scb->xfer->sc_link->target,
+ scb->xfer->sc_link->lun,
+ scb->xfer->sc_link->device->name,
+ scb->xfer->sc_link->dev_unit);
+
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (/* (sea_abort(unit, scb) != 1) ||*/ (scb->flags & SCB_ABORTED)) {
+ /*
+ * abort timed out
+ */
+#ifdef SEADEBUG2
+/* printf("sea%d: Abort Operation has timed out\n", unit); */
+ printf(":2");
+#endif
+ scb->xfer->retries = 0;
+ scb->flags |= SCB_ABORTED;
+ sea_done(unit, scb);
+ } else {
+ #ifdef SEADEBUG2
+ /* printf("sea%d: Try to abort\n", unit); */
+ printf(":3");
+ #endif
+ sea_abort(unit, scb);
+ /* sea_send_scb(sea, ~SCSI_NOMASK, SEA_SCB_ABORT, scb); */
+ /* 2 seconds for the abort */
+ #ifdef SEA_FREEBSD11
+ timeout(sea_timeout, (caddr_t)scb, 2*hz);
+ #else
+ timeout(sea_timeout, scb, 2*hz);
+ #endif
+ scb->flags |= (SCB_ABORTED | SCB_TIMECHK);
+ }
+ splx(s);
+}
+
+int
+sea_reselect(sea)
+ struct sea_data *sea;
+{
+ unsigned char target_mask;
+ long l;
+ unsigned char lun, phase;
+ unsigned char msg[3];
+ int32 len;
+ u_char *data;
+ struct sea_scb *tmp = 0, *prev = 0;
+ int abort = 0;
+
+#if SEADEBUG2
+/* printf("sea_reselect called\n"); */
+ printf("}");
+#endif
+
+ if (!((target_mask = STATUS) & STAT_SEL)) {
+ printf("sea: wrong state 0x%x\n", target_mask);
+ return(0);
+ }
+ /* wait for a device to win the reselection phase */
+ /* signals this by asserting the I/O signal */
+ for(l=10; l && (STATUS & (STAT_SEL | STAT_IO | STAT_BSY))
+ != (STAT_SEL | STAT_IO | 0);l--);
+ /* !! Check for timeout here */
+ /* the data bus contains original initiator id ORed with target id */
+ target_mask = DATA;
+ /* see that we really are the initiator */
+ if (!(target_mask & ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40))) {
+ printf("sea: polled reselection was not for me: %x\n",target_mask);
+ return(0);
+ }
+ /* find target who won */
+ target_mask &= ((sea->ctrl_type == SEAGATE) ? ~0x80 : ~0x40);
+ /* host responds by asserting the BSY signal */
+ CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
+ /* target should respond by deasserting the SEL signal */
+ for(l=50000;l && (STATUS & STAT_SEL);l++);
+ /* remove the busy status */
+ CONTROL = (BASE_CMD | CMD_DRVR_ENABLE);
+ /* we are connected. Now we wait for the MSGIN condition */
+ for(l=50000; l && !(STATUS & STAT_REQ);l--);
+ /* !! Add timeout check here */
+ /* hope we get an IDENTIFY message */
+ len = 3;
+ data = msg;
+ phase = REQ_MSGIN;
+ sea_transfer_pio(sea, &phase, &len, &data);
+
+ if (!(msg[0] & 0x80)) {
+ printf("sea: Expecting IDENTIFY message, got 0x%x\n", msg[0]);
+ abort = 1;
+ } else {
+ lun = (msg[0] & 0x07);
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just restablished, and remove it from the disconnected queue.
+ */
+
+ for(tmp = sea->disconnected_queue, prev = NULL;
+ tmp; prev=tmp, tmp = tmp->next)
+ if((target_mask == (1 << tmp->xfer->sc_link->target)) &&
+ (lun == tmp->xfer->sc_link->lun)) {
+ if(prev) {
+#ifdef SEADEBUG2
+ printf("}2");
+#endif
+ prev->next = tmp->next;
+ } else {
+#ifdef SEADEBUG2
+ printf("}3");
+#endif
+ sea->disconnected_queue = tmp->next;
+ }
+ tmp->next = NULL;
+ break;
+ }
+ if (!tmp) {
+ printf("sea: warning : target %02x lun %d not in disconnect_queue\n",
+ target_mask, lun);
+ /*
+ * Since we have an established nexus that we can't do anything with,
+ * we must abort it.
+ */
+ abort = 1;
+ }
+ }
+
+ if(abort) {
+#ifdef SEADEBUG2
+ printf("}4");
+#endif
+ msg[0] = MSG_ABORT;
+ len = 1;
+ data = msg;
+ phase = REQ_MSGOUT;
+ CONTROL = (BASE_CMD | CMD_ATTN);
+ sea_transfer_pio(sea, &phase, &len, &data);
+ } else {
+#ifdef SEADEBUG2
+ printf("}5");
+#endif
+ sea->connected = tmp;
+ }
+ /* return value not used yet */
+ return 0;
+}
+
+/* Transfer data in given phase using polled I/O
+*/
+
+int sea_transfer_pio(struct sea_data *sea, u_char *phase, int32 *count,
+ u_char **data)
+{
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+ unsigned long int timeout;
+
+#if SEADEBUG2
+/* printf("sea_transfer_pio called: len:%x\n",c); */
+ printf("-1 %x %x", c, p);
+#endif
+
+ do {
+ /* wait for assertion of REQ, after which the phase bits will be valid */
+ for(timeout = 0; timeout < 5000000L ; timeout++)
+ if ((tmp = STATUS) & STAT_REQ)
+ break;
+ if (!(tmp & STAT_REQ)) {
+ printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
+ break;
+ }
+
+ /* check for phase mismatch */
+ /* Reached if the target decides that it has finished the transfer */
+ if ((tmp & REQ_MASK) != p) {
+#ifdef SEADEBUG1
+/* printf("-2 %x", tmp); */
+ printf("sea:pio phase mismatch:%x, want:%x, len:%x\n",tmp,p,c);
+#endif
+ break;
+ }
+
+ /* Do actual transfer from SCSI bus to/from memory */
+ if (!(p & STAT_IO))
+ DATA = *d;
+ else
+ *d = DATA;
+#ifdef SEADEBUG15
+ printf("-7%x", *d);
+#endif
+ ++d;
+
+ /* The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ * Don't know how to accomplish this on the ST01/02
+ */
+ /* We don't mind right now. */
+
+ /* The st01 code doesn't wait for STAT_REQ to be deasserted. Is this ok? */
+/* for(timeout=0;timeout<200000L;timeout++)
+ if(!(STATUS & STAT_REQ))
+ break;
+ if(STATUS & STAT_REQ)
+ printf("timeout on wait for !STAT_REQ"); */
+/* printf("*"); */
+ } while (--c);
+
+ *count = c;
+ *data = d;
+ tmp = STATUS;
+ if (tmp & STAT_REQ) {
+#if SEADEBUG2
+ printf("-3%x", tmp);
+#endif
+ *phase = tmp & REQ_MASK;
+ } else {
+#if SEADEBUG2
+ printf("-4%x", tmp);
+#endif
+ *phase = REQ_UNKNOWN;
+ }
+ if (!c || (*phase == p)) {
+#if SEADEBUG2
+ printf("-5%x %x", c, *phase);
+#endif
+ return 0;
+ } else {
+#if SEADEBUG2
+ printf("-6");
+#endif
+ return -1;
+ }
+}
+
+/* sea_select
+ * establish I_T_L or I_T_L_Q nexus for new or existing command
+ * including ARBITRATION, SELECTION, and initial message out for IDENTIFY and
+ * queue messages.
+ * return -1 if selection could not execute for some reason, 0 if selection
+ * succeded or failed because the taget did not respond
+ */
+int sea_select(struct sea_data *sea, struct sea_scb *scb)
+{
+ unsigned char tmp[3], phase;
+ u_char *data;
+ int32 len;
+ unsigned long timeout;
+
+#ifdef SEADEBUG2
+/* printf("sea_select called\n"); */
+ printf("{");
+#endif
+
+ CONTROL = BASE_CMD;
+ DATA = ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40);
+ CONTROL = (BASE_CMD & ~CMD_INTR) | CMD_START_ARB;
+ /* wait for arbitration to complete */
+ for (timeout = 0; timeout < 3000000L ; timeout++) {
+ if (STATUS & STAT_ARB_CMPL)
+ break;
+ }
+ if (!(STATUS & STAT_ARB_CMPL)) {
+ if (STATUS & STAT_SEL) {
+ printf("sea: arbitration lost\n");
+ scb->flags |= SCB_ERROR;
+ } else {
+ printf("sea: arbitration timeout.\n");
+ scb->flags |=SCB_TIMEOUT;
+ }
+ CONTROL = BASE_CMD;
+ return(-1);
+ }
+ DELAY(2);
+
+#if SEADEBUG2
+/* printf("after arbitration: STATUS=%x\n", STATUS); */
+ printf("{2 %x", STATUS);
+#endif
+
+ DATA = (unsigned char)((1 << scb->xfer->sc_link->target) |
+ ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40));
+#ifdef SEANOMSGS
+ CONTROL = (BASE_CMD & (~CMD_INTR))| CMD_DRVR_ENABLE | CMD_SEL;
+#else
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE | CMD_SEL | CMD_ATTN;
+#endif
+ DELAY(1);
+ /* wait for a bsy from target */
+ for (timeout = 0; timeout < 2000000L; timeout++) {
+ if (STATUS & STAT_BSY)
+ break;
+ }
+
+#if SEADEBUG2
+/* printf("after wait for BSY: STATUS=%x,count=%lx\n", STATUS, timeout); */
+ printf("{3 %x %x", STATUS, timeout);
+#endif
+
+ if (!(STATUS & STAT_BSY)) {
+ /* should return some error to the higher level driver */
+ CONTROL = BASE_CMD;
+#if SEADEBUG2
+/* printf("sea: target did not respond\n"); */
+ printf("{4");
+#endif
+ scb->flags |= SCB_TIMEOUT;
+ return 0;
+ }
+
+ /* Try to make the target to take a message from us */
+#ifdef SEANOMSGS
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE;
+#else
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE | CMD_ATTN;
+#endif
+
+ DELAY(1);
+
+ /* should start a msg_out phase */
+ for (timeout = 0; timeout < 2000000L ; timeout++) {
+ if (STATUS & STAT_REQ)
+ break;
+ }
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+
+#if SEADEBUG2 || SEADEBUG9
+/* printf("after wait for STAT_REQ: STATUS=%x,count=%lx\n", STATUS, timeout);
+ printf("2:nd try after wait for STAT_REQ: STATUS=%x\n", STATUS); */
+ printf("{5%x", timeout);
+#endif
+
+ if (!(STATUS & STAT_REQ)) {
+ /* This should not be taken as an error, but more like an unsupported
+ * feature!
+ * Should set a flag indicating that the target don't support messages, and
+ * continue without failure. (THIS IS NOT AN ERROR!)
+ */
+#if SEADEBUG
+/* printf("{6"); */
+ printf("sea: WARNING: target %x don't support messages?\n",
+ scb->xfer->sc_link->target);
+#endif
+ } else {
+ tmp[0] = IDENTIFY(1, scb->xfer->sc_link->lun); /* allow disconnects */
+ len = 1;
+ data = tmp;
+ phase = REQ_MSGOUT;
+ /* Should do test on result of sea_transfer_pio */
+#if SEADEBUG2
+/* printf("Trying a msg out phase\n"); */
+ printf("{7");
+#endif
+ sea_transfer_pio(sea, &phase, &len, &data);
+ }
+ if (!(STATUS & STAT_BSY)) {
+ printf("sea: after successful arbitrate: No STAT_BSY!\n");
+ }
+
+#if SEADEBUG2
+ printf("{8");
+#endif
+ sea->connected = scb;
+ sea->busy[scb->xfer->sc_link->target] |= (1 << scb->xfer->sc_link->lun);
+ /* this assignment should depend on possibility to send a message to target */
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+ /* reset pointer in command ??? */
+ return 0;
+}
+
+/* sea_abort
+ send an abort to the target
+ return 1 success, 0 on failure
+ */
+int sea_abort(int unit, struct sea_scb *scb)
+{
+ struct sea_data *sea = seadata[unit];
+ struct sea_scb *tmp, **prev;
+ unsigned char msg, phase, *msgptr;
+ int32 len;
+ int oldpri;
+
+#ifdef SEADEBUG2
+/* printf("sea_abort called\n"); */
+ printf("\\");
+#endif
+
+ oldpri = splbio();
+
+ /* If the command hasn't been issued yet, we simply remove it from the
+ * issue queue
+ */
+ for (prev = (struct sea_scb **) &(sea->issue_queue),
+ tmp = sea->issue_queue; tmp;
+ prev = (struct sea_scb **) &(tmp->next), tmp = tmp->next)
+ if (scb == tmp) {
+ (*prev) = tmp->next;
+ tmp->next = NULL;
+ /* set some type of error result for this operation */
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("\\2");
+#endif
+ return 1;
+ }
+
+ /* If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or issue a
+ * reset
+ */
+
+ if(sea->connected) {
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea:abort error connected\n"); */
+ printf("\\3");
+#endif
+ return 0;
+ }
+
+ /* If the command is currently disconnected from the bus, and there are
+ * no connected commands, we reconnect the I_T_L or I_T_L_Q nexus
+ * associated with it, go into message out, and send an abort message.
+ */
+
+ for (tmp = sea->disconnected_queue; tmp; tmp = tmp->next)
+ if (scb == tmp) {
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("\\4");
+#endif
+ if (sea_select(sea,scb)) {
+#ifdef SEADEBUG2
+ printf("\\5");
+#endif
+ return 0;
+ }
+ msg = MSG_ABORT;
+ msgptr = &msg;
+ len = 1;
+ phase = REQ_MSGOUT;
+ CONTROL = BASE_CMD | CMD_ATTN;
+ sea_transfer_pio(sea, &phase, &len, &msgptr);
+
+ oldpri = splbio();
+ for (prev = (struct sea_scb **) &(sea->disconnected_queue),
+ tmp = sea->disconnected_queue; tmp ;
+ prev = (struct sea_scb **) &(tmp->next), tmp = tmp->next)
+ if (scb == tmp) {
+ *prev = tmp->next;
+ tmp->next = NULL;
+ /* set some type of error result for the operation */
+#ifdef SEADEBUG2
+ printf("\\6");
+#endif
+ splx(oldpri);
+ return 1;
+ }
+ }
+
+ /* command not found in any queue, race condition in the code ? */
+
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea: WARNING: SCSI command probably completed successfully\n"
+ " before abortion\n"); */
+ printf("\\7");
+#endif
+ return 1;
+
+}
+
+void sea_done(int unit, struct sea_scb *scb)
+{
+ struct sea_data *sea = seadata[unit];
+ struct scsi_xfer *xs = scb->xfer;
+
+
+#ifdef SEADEBUG2
+/* printf("sea_done called\n"); */
+ printf("&");
+#endif
+
+ if (scb->flags & SCB_TIMECHK) {
+#ifdef SEADEBUG2
+ printf("&2");
+#endif
+#ifdef SEA_FREEBSD11
+ untimeout(sea_timeout, (caddr_t)scb);
+#else
+ untimeout(sea_timeout, scb);
+#endif
+ }
+
+ xs->resid = scb->datalen; /* How much of the buffer was not touched */
+
+ if ((scb->flags == SCB_ACTIVE) || (xs->flags & SCSI_ERR_OK)) {
+#ifdef SEADEBUG2
+/* printf("sea_done:Report no err in xs\n"); */
+ printf("&3");
+#endif
+/* xs->resid = 0; */
+/* xs->error = 0; */
+ } else {
+
+ if (!(scb->flags == SCB_ACTIVE)) {
+ if ((scb->flags & SCB_TIMEOUT) || (scb->flags & SCB_ABORTED)) {
+#ifdef SEADEBUG2
+ printf("&6");
+#endif
+ xs->error = XS_TIMEOUT;
+ }
+ if (scb->flags & SCB_ERROR) {
+#ifdef SEADEBUG2
+ printf("&7");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ } else {
+
+ /* !!! Add code to check for target status */
+ /* say all error now */
+ xs->error = XS_DRIVER_STUFFUP;
+#ifdef SEADEBUG2
+ printf("&4");
+#endif
+ }
+ }
+ xs->flags |= ITSDONE;
+ sea_free_scb(unit, scb, xs->flags);
+ scsi_done(xs);
+#ifdef SEADEBUG2
+/* printf("Leaving sea_done\n"); */
+ printf("&5");
+#endif
+}
+
+/* wait for completion of command in polled mode */
+
+int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb)
+{
+ int count = 500; /* xs->timeout; */
+ int oldpri;
+
+#ifdef SEADEBUG2
+/* printf("sea_poll called\n"); */
+ printf("?");
+#endif
+
+ while (count) {
+ /* try to do something */
+ oldpri = splbio();
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri);
+ } else {
+ splx(oldpri);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(10);
+ count--;
+ }
+#ifdef SEADEBUG2
+ printf("?2 %x ", count);
+/* printf("sea_poll: count:%x\n",count); */
+#endif
+ if (count == 0) {
+ /* we timed out, so call the timeout handler manually,
+ * accounting for the fact that the clock is not running yet
+ * by taking out the clock queue entry it makes.
+ */
+#ifdef SEADEBUG2
+ printf("?3");
+#endif
+#ifdef SEA_FREEBSD11
+ sea_timeout((caddr_t)scb, 0);
+#else
+ sea_timeout(scb);
+#endif
+
+ /* because we are polling, take out the timeout entry
+ * sea_timeout made
+ */
+#ifdef SEADEBUG2
+ printf("?4");
+#endif
+#ifdef SEA_FREEBSD11
+ untimeout(sea_timeout, (caddr_t) scb);
+#else
+ untimeout(sea_timeout, scb);
+#endif
+ count = 50;
+ while (count) {
+ /* once again, wait for the int bit */
+ oldpri = splbio();
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared by sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri);
+ } else {
+ splx(oldpri);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(10);
+ count--;
+ }
+ if (count == 0) {
+ /* we timed out again... This is bad. Notice that
+ * this time there is no clock queue entry to remove
+ */
+#ifdef SEADEBUG2
+ printf("?5");
+#endif
+#ifdef SEA_FREEBSD11
+ sea_timeout((caddr_t)scb, 0);
+#else
+ sea_timeout(scb);
+#endif
+ }
+ }
+#ifdef SEADEBUG2
+/* printf("sea_poll: xs->error:%x\n",xs->error); */
+ printf("?6%x",xs->error);
+#endif
+ if (xs->error) {
+#ifdef SEADEBUG2
+/* printf("done return error\n"); */
+ printf("?7");
+#endif
+ return (HAD_ERROR);
+ }
+#ifdef SEADEBUG2
+/* printf("done return complete\n"); */
+ printf("?8");
+#endif
+ return (COMPLETE);
+}
+
+/*
+ * sea_information_transfer
+ * Do the transfer. We know we are connected. Update the flags,
+ * call sea_done when task accomplished. Dialog controlled by the
+ * target
+ */
+static void sea_information_transfer (struct sea_data *sea)
+{
+ long int timeout;
+ int unit = sea->sc_link.adapter_unit;
+ unsigned char msgout = MSG_NOP;
+ int32 len;
+ int oldpri;
+ u_char *data;
+ unsigned char phase, tmp, old_phase=REQ_UNKNOWN;
+ struct sea_scb *scb = sea->connected;
+ int loop;
+
+#if SEADEBUG2
+/* printf("sea_information_transfer called\n"); */
+ printf("!");
+#endif
+
+ for(timeout = 0; timeout < 10000000L ; timeout++) {
+ tmp = STATUS;
+ if (!(tmp & STAT_BSY)) {
+/* for(loop=0;loop < 20 ; loop++) {
+ if((tmp=STATUS) & STAT_BSY)
+ break;
+ } */
+#ifndef SEADEBUG8
+ if(!(tmp & STAT_BSY)) {
+ printf("sea: !STAT_BSY unit in data transfer!\n");
+ oldpri = splbio();
+ sea->connected = NULL;
+ scb->flags = SCB_ERROR;
+ splx(oldpri);
+ sea_done(unit, scb);
+ return;
+ }
+#endif
+ }
+
+ /* we only have a valid SCSI phase when REQ is asserted */
+ if (tmp & STAT_REQ) {
+ phase = (tmp & REQ_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ }
+
+#ifdef SEADEBUG7
+ printf("!2%x", phase);
+ for(loop=0;loop < 20; loop++) {
+ phase = STATUS;
+ printf("!6%x",phase);
+ phase = phase & REQ_MASK;
+ }
+#endif
+
+ switch (phase) {
+ case REQ_DATAOUT:
+#ifdef SEA_NODATAOUT
+ printf("sea: SEA_NODATAOUT set, attempted DATAOUT aborted\n");
+ msgout = MSG_ABORT;
+ CONTROL = BASE_CMD | CMD_ATTN;
+ break;
+#endif
+ case REQ_DATAIN:
+/* data = scb->xfer->data;
+ len = scb->xfer->datalen;
+*/ if(!(scb->data)) {
+ printf("no data address!\n");
+ }
+#ifdef SEA_BLINDTRANSFER
+ if (scb->datalen && !(scb->datalen % BLOCK_SIZE)) {
+ while (scb->datalen) {
+ for(timeout = 0; timeout < 5000000L ; timeout++)
+ if((tmp = STATUS) & STAT_REQ)
+ break;
+ if(!(tmp & STAT_REQ)) {
+ printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
+ /* getchar(); */
+ }
+ if((tmp & REQ_MASK) != phase) {
+#ifdef SEADEBUG1
+ printf("sea:infotransfer phase mismatch:%x, want:%x, len:%x\n",
+ tmp,phase,scb->datalen);
+ /* getchar(); */
+#endif
+ break;
+ }
+ if(!(phase & STAT_IO)) {
+#ifdef SEA_ASSEMBLER
+ asm("
+ shr $2, %%ecx;
+ cld;
+ rep;
+ movsl; " : :
+ "D" (sea->st0x_dr), "S" (scb->data), "c" (BLOCK_SIZE) :
+ "cx", "si", "di" );
+ scb->data += BLOCK_SIZE;
+#else
+ for(count=0; count < BLOCK_SIZE; count++) {
+ DATA = *(scb->data);
+ scb->data++;
+ }
+#endif
+ } else {
+#ifdef SEA_ASSEMBLER
+ asm("
+ shr $2, %%ecx;
+ cld;
+ rep;
+ movsl; " : :
+ "S" (sea->st0x_dr), "D" (scb->data), "c" (BLOCK_SIZE) :
+ "cx", "si", "di" );
+ scb->data += BLOCK_SIZE;
+#else
+ for(count=0; count < BLOCK_SIZE; count++) {
+ *scb->data = DATA;
+ scb->data++;
+ }
+#endif
+ }
+ scb->datalen -= BLOCK_SIZE;
+ }
+ }
+
+ /* save current position into the command structure */
+/* scb->xfer->data = data;
+ scb->xfer->datalen = len; */
+#endif
+
+ sea_transfer_pio(sea, &phase, &(scb->datalen), &(scb->data));
+/* scb->xfer->data = data;
+ scb->xfer->datalen = len;
+*/ break;
+
+ case REQ_MSGIN:
+ /* don't handle multi-byte messages here, because they
+ * should not be present here
+ */
+ len = 1;
+ data = &tmp;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ /* scb->MessageIn = tmp; */
+
+ switch (tmp) {
+
+ case MSG_ABORT:
+ scb->flags = SCB_ABORTED;
+ printf("sea:Command aborted by target\n");
+ CONTROL = BASE_CMD;
+ sea_done(unit, scb);
+ return;
+
+ case MSG_COMMAND_COMPLETE:
+ oldpri = splbio();
+ sea->connected = NULL;
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("!3");
+#endif
+ sea->busy[scb->xfer->sc_link->target] &=
+ ~(1 << scb->xfer->sc_link->lun);
+
+ CONTROL = BASE_CMD;
+ sea_done(unit, scb);
+ return;
+ case MSG_MESSAGE_REJECT:
+ /* printf("sea: message_reject recieved\n"); */
+ printf("!4");
+ break;
+ case MSG_DISCONNECT:
+ oldpri = splbio();
+ scb->next = sea->disconnected_queue;
+ sea->disconnected_queue = scb;
+ sea->connected = NULL;
+ CONTROL = BASE_CMD;
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("msg_disconnect\n"); */
+ printf("!5");
+#endif
+ return;
+ /* save/restore of pointers are ignored */
+ case MSG_SAVE_POINTERS:
+ case MSG_RESTORE_POINTERS:
+#if SEADEBUG2
+ printf("sea: rec save/restore ptrs\n");
+#endif
+ break;
+ default:
+ /* this should be handled in the pio data transfer phase, as the
+ * ATN should be raised before ACK goes false when rejecting a message
+ */
+#ifdef SEADEBUG
+ printf("sea: Unknown message in:%x\n", tmp);
+#endif
+ break;
+ } /* switch (tmp) */
+ break;
+ case REQ_MSGOUT:
+ len = 1;
+ data = &msgout;
+ /* sea->last_message = msgout; */
+ sea_transfer_pio(sea, &phase, &len, &data);
+ if (msgout == MSG_ABORT) {
+ printf("sea: sent message abort to target\n");
+ oldpri = splbio();
+ sea->busy[scb->xfer->sc_link->target] &=
+ ~(1 << scb->xfer->sc_link->lun);
+ sea->connected = NULL;
+ scb->flags = SCB_ABORTED;
+ splx(oldpri);
+ /* enable interrupt from scsi */
+ sea_done(unit, scb);
+ return;
+ }
+ msgout = MSG_NOP;
+ break;
+ case REQ_CMDOUT:
+ len = scb->xfer->cmdlen;
+ data = (char *) scb->xfer->cmd;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ break;
+ case REQ_STATIN:
+ len = 1;
+ data = &tmp;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ scb->xfer->status = tmp;
+ break;
+ default:
+ printf("sea: unknown phase\n");
+ } /* switch (phase) */
+ } /* if (tmp & STAT_REQ) */
+ } /* for (...) */
+ /* if we get here we have got a timeout! */
+ printf("sea: Timeout in data transfer\n");
+ scb->flags = SCB_TIMEOUT;
+ /* should I clear scsi-bus state? */
+ sea_done(unit, scb);
+}
+
+
diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c
index 4cee4fe8c60f..6fa09247e5f3 100644
--- a/sys/i386/isa/sio.c
+++ b/sys/i386/isa/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.28 1994/02/07 18:37:21 ache Exp $
+ * $Id: sio.c,v 1.56 1994/06/16 08:08:44 ache Exp $
*/
#include "sio.h"
@@ -49,17 +49,19 @@
#include "proc.h"
#include "user.h"
#include "conf.h"
+#include "dkstat.h"
#include "file.h"
#include "uio.h"
#include "kernel.h"
+#include "malloc.h"
#include "syslog.h"
+#include "i386/isa/icu.h" /* XXX */
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/comreg.h"
#include "i386/isa/ic/ns16550.h"
-#define FAKE_DCD(unit) ((unit) == comconsole)
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
@@ -67,38 +69,27 @@
#define TTY_BI TTY_FE /* XXX */
#define TTY_OE TTY_PE /* XXX */
-#ifndef COM_BIDIR
-#define UNIT(x) (minor(x)) /* XXX */
-#else /* COM_BIDIR */
-#define COM_UNITMASK 0x7f
-#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
-#define UNIT(x) (minor(x) & COM_UNITMASK)
-#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
-#endif /* COM_BIDIR */
+#define CALLOUT_MASK 0x80
+#define CONTROL_MASK 0x60
+#define CONTROL_INIT_STATE 0x20
+#define CONTROL_LOCK_STATE 0x40
+#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
+#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
+#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
#ifdef COM_MULTIPORT
/* checks in flags for multiport and which is multiport "master chip"
* for a given card
*/
-#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
-#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOTAST4(dev) ((dev)->id_flags & 0x04)
#endif /* COM_MULTIPORT */
-#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
-#ifndef FIFO_TRIGGER
-/*
- * This driver is fast enough to work with any value and for high values
- * to be only slightly more efficient. Low values may be better because
- * they give lower latency.
- * TODO: always use low values for low speeds. Mouse movements are jerky
- * if more than one packet arrives at once. The low speeds used for
- * serial mice help avoid this, but not if (large) fifos are enabled.
- */
-#define FIFO_TRIGGER FIFO_TRIGGER_14
-#endif
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+#define COM_VERBOSE(dev) ((dev)->id_flags & 0x80)
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
-#define setsofttty() (ipending |= 1 << 4) /* XXX */
/*
* Input buffer watermarks.
@@ -124,17 +115,19 @@
* CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
* CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
* TS_FLUSH is not used.
- * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
*/
#define CS_BUSY 0x80 /* output in progress */
#define CS_TTGO 0x40 /* output not stopped by XOFF */
#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
#define CS_CHECKMSR 1 /* check of MSR scheduled */
#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_DTR_OFF 0x10 /* DTR held off */
#define CS_ODONE 4 /* output completed */
#define CS_RTS_IFLOW 8 /* use RTS input flow control */
-static char *error_desc[] = {
+static char const * const error_desc[] = {
#define CE_OVERRUN 0
"silo overflow",
#define CE_INTERRUPT_BUF_OVERFLOW 1
@@ -153,20 +146,19 @@ typedef u_char bool_t; /* boolean */
/* com device structure */
struct com_s {
u_char state; /* miscellaneous flag bits */
+ bool_t active_out; /* nonzero if the callout device is open */
u_char cfcr_image; /* copy of value written to CFCR */
+ u_char ftl; /* current rx fifo trigger level */
+ u_char ftl_init; /* ftl_max for next open() */
+ u_char ftl_max; /* maximum ftl for curent open() */
bool_t hasfifo; /* nonzero for 16550 UARTs */
u_char mcr_image; /* copy of value written to MCR */
-#ifdef COM_BIDIR
- bool_t bidir; /* is this unit bidirectional? */
- bool_t active; /* is the port active _at all_? */
- bool_t active_in; /* is the incoming port in use? */
- bool_t active_out; /* is the outgoing port in use? */
-#endif /* COM_BIDIR */
#ifdef COM_MULTIPORT
bool_t multiport; /* is this unit part of a multiport device? */
#endif /* COM_MULTIPORT */
- int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
u_int tx_fifo_size;
+ u_int wopeners; /* # processes waiting for DCD in open() */
/*
* The high level of the driver never reads status registers directly
@@ -177,6 +169,7 @@ struct com_s {
u_char last_modem_status; /* last MSR read by intr handler */
u_char prev_modem_status; /* last MSR handled by high level */
+ u_char hotchar; /* ldisc-specific char to be handled ASAP */
u_char *ibuf; /* start of input buffer */
u_char *ibufend; /* end of input buffer */
u_char *ihighwater; /* threshold in input buffer */
@@ -195,6 +188,19 @@ struct com_s {
struct tty *tp; /* cross reference */
+ /* Initial state. */
+ struct termios it_in; /* should be in struct tty */
+ struct termios it_out;
+
+ /* Lock state. */
+ struct termios lt_in; /* should be in struct tty */
+ struct termios lt_out;
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
u_long bytes_in; /* statistics */
u_long bytes_out;
u_int delta_error_counts[CE_NTYPES];
@@ -210,48 +216,56 @@ struct com_s {
};
/*
- * These functions in the com module ought to be declared (with a prototype)
- * in a com-driver system header. The void ones may need to be int to match
- * ancient devswitch declarations, but they don't actually return anything.
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
*/
#define Dev_t int /* promoted dev_t */
-struct consdev;
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
int sioclose __P((Dev_t dev, int fflag, int devtype,
struct proc *p));
-void siointr __P((int unit));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((Dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
int siocngetc __P((Dev_t dev));
+struct consdev;
void siocninit __P((struct consdev *cp));
void siocnprobe __P((struct consdev *cp));
void siocnputc __P((Dev_t dev, int c));
-int sioopen __P((Dev_t dev, int oflags, int devtype,
- struct proc *p));
-void siopoll __P((void));
-int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
-int sioselect __P((Dev_t dev, int rw, struct proc *p));
-void siostop __P((struct tty *tp, int rw));
-int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
-void softsio1 __P((void));
static int sioattach __P((struct isa_device *dev));
+static void siodtrwakeup __P((caddr_t chan, int ticks));
static void comflush __P((struct com_s *com));
static void comhardclose __P((struct com_s *com));
-static void cominit __P((int unit, int rate));
-static void comintr1 __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
static void commctl __P((struct com_s *com, int bits, int how));
static int comparam __P((struct tty *tp, struct termios *t));
static int sioprobe __P((struct isa_device *dev));
-static void comstart __P((struct tty *tp));
-static void comwakeup __P((caddr_t chan, int ticks));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
static int tiocm_xxx2mcr __P((int tiocm_xxx));
/* table and macro for fast conversion from a unit number to its com struct */
static struct com_s *p_com_addr[NSIO];
#define com_addr(unit) (p_com_addr[unit])
-static struct com_s com_structs[NSIO];
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
struct isa_driver siodriver = {
sioprobe, sioattach, "sio"
@@ -262,15 +276,11 @@ static int comconsole = COMCONSOLE;
#else
static int comconsole = -1;
#endif
-static bool_t comconsinit;
static speed_t comdefaultrate = TTYDEF_SPEED;
static u_int com_events; /* input chars + weighted output completions */
static int commajor;
-struct tty sio_tty[NSIO];
-extern struct tty *constty;
-extern u_int ipending; /* XXX */
-extern int tk_nin; /* XXX */
-extern int tk_rawcc; /* XXX */
+struct tty *sio_tty[NSIO];
+extern struct tty *constty; /* XXX */
#ifdef KGDB
#include "machine/remote-sl.h"
@@ -311,7 +321,11 @@ sioprobe(dev)
{
static bool_t already_init;
Port_t *com_ptr;
+ bool_t failures[10];
+ int fn;
+ struct isa_device *idev;
Port_t iobase;
+ u_char mcr_image;
int result;
if (!already_init) {
@@ -319,6 +333,7 @@ sioprobe(dev)
* Turn off MCR_IENABLE for all likely serial ports. An unused
* port with its MCR_IENABLE gate open will inhibit interrupts
* from any used port that shares the interrupt vector.
+ * XXX the gate enable is elsewhere for some multiports.
*/
for (com_ptr = likely_com_ports;
com_ptr < &likely_com_ports[sizeof likely_com_ports
@@ -327,8 +342,45 @@ sioprobe(dev)
outb(*com_ptr + com_mcr, 0);
already_init = TRUE;
}
+
+ /*
+ * If the port is on a multiport card and has a master port,
+ * initialize the common interrupt control register in the
+ * master and prepare to leave MCR_IENABLE clear in the mcr.
+ * Otherwise, prepare to set MCR_IENABLE in the mcr.
+ * Point idev to the device struct giving the correct id_irq.
+ * This is the struct for the master device if there is one.
+ */
+ idev = dev;
+ mcr_image = MCR_IENABLE;
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(dev)) {
+ idev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(dev));
+ if (idev == NULL) {
+ printf("sio%d: master device %d not found\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (idev->id_irq == 0) {
+ printf("sio%d: master device %d irq not configured\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (!COM_NOTAST4(dev)) {
+ outb(idev->id_iobase + com_scr, 0x80);
+ mcr_image = 0;
+ }
+ }
+ else
+#endif /* COM_MULTIPORT */
+ if (idev->id_irq == 0) {
+ printf("sio%d: irq not configured\n", dev->id_unit);
+ return (0);
+ }
+
+ bzero(failures, sizeof failures);
iobase = dev->id_iobase;
- result = IO_COMSIZE;
/*
* We don't want to get actual interrupts, just masked ones.
@@ -339,55 +391,115 @@ sioprobe(dev)
disable_intr();
/*
- * Initialize the speed so that any junk in the THR or output fifo will
- * be transmitted in a known time. (There may be lots of junk after a
- * soft reboot, and output interrupts don't work right after a master
- * reset, at least for 16550s. (The speed is undefined after MR, but
- * MR empties the THR and the TSR so it's not clear why this matters)).
- * Enable output interrupts (only) and check the following:
+ * XXX DELAY() reenables CPU interrupts. This is a problem for
+ * shared interrupts after the first device using one has been
+ * successfully probed - config_isadev() has enabled the interrupt
+ * in the ICU.
+ */
+ outb(IO_ICU1 + 1, 0xff);
+
+ /*
+ * Initialize the speed and the word size and wait long enough to
+ * drain the maximum of 16 bytes of junk in device output queues.
+ * The speed is undefined after a master reset and must be set
+ * before relying on anything related to output. There may be
+ * junk after a (very fast) soft reboot and (apparently) after
+ * master reset.
+ * XXX what about the UART bug avoided by waiting in comparam()?
+ * We don't want to to wait long enough to drain at 2 bps.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ DELAY((16 + 1) * 9600 / 10);
+
+ /*
+ * Enable the interrupt gate and disable device interupts. This
+ * should leave the device driving the interrupt line low and
+ * guarantee an edge trigger if an interrupt can be generated.
+ */
+ outb(iobase + com_mcr, mcr_image);
+ outb(iobase + com_ier, 0);
+
+ /*
+ * Attempt to set loopback mode so that we can send a null byte
+ * without annoying any external device.
+ */
+ outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
+
+ /*
+ * Attempt to generate an output interrupt. On 8250's, setting
+ * IER_ETXRDY generates an interrupt independent of the current
+ * setting and independent of whether the THR is empty. On 16450's,
+ * setting IER_ETXRDY generates an interrupt independent of the
+ * current setting. On 16550A's, setting IER_ETXRDY only
+ * generates an interrupt when IER_ETXRDY is not already set.
+ */
+ outb(iobase + com_ier, IER_ETXRDY);
+
+ /*
+ * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
+ * an interrupt. They'd better generate one for actually doing
+ * output. Loopback may be broken on the same incompatibles but
+ * it's unlikely to do more than allow the null byte out.
+ */
+ outb(iobase + com_data, 0);
+ DELAY((2 + 1) * 9600 / 10);
+
+ /*
+ * Turn off loopback mode so that the interrupt gate works again
+ * (MCR_IENABLE was hidden). This should leave the device driving
+ * an interrupt line high. It doesn't matter if the interrupt
+ * line oscillates while we are not looking at it, since interrupts
+ * are disabled.
+ */
+ outb(iobase + com_mcr, mcr_image);
+
+ /*
+ * Check that
* o the CFCR, IER and MCR in UART hold the values written to them
* (the values happen to be all distinct - this is good for
* avoiding false positive tests from bus echoes).
* o an output interrupt is generated and its vector is correct.
* o the interrupt goes away when the IIR in the UART is read.
*/
- outb(iobase + com_cfcr, CFCR_DLAB);
- outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
- outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
- outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
- outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
- outb(iobase + com_ier, 0); /* ensure edge on next intr */
- outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
- DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
- if ( inb(iobase + com_cfcr) != CFCR_8BITS
- || inb(iobase + com_ier) != IER_ETXRDY
- || inb(iobase + com_mcr) != MCR_IENABLE
-#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
- || !isa_irq_pending(dev)
-#endif
- || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
- || isa_irq_pending(dev)
- || !(inb(iobase + com_iir) & IIR_NOPEND))
- result = 0;
+ failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
+ failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
+ failures[2] = inb(iobase + com_mcr) - mcr_image;
+ if (idev->id_irq != 0)
+ failures[3] = isa_irq_pending(idev) ? 0 : 1;
+ failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
+ failures[5] = isa_irq_pending(idev) ? 1 : 0;
+ failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
/*
* Turn off all device interrupts and check that they go off properly.
- * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * Leave MCR_IENABLE alone. For ports without a master port, it gates
+ * the OUT2 output of the UART to
* the ICU input. Closing the gate would give a floating ICU input
* (unless there is another device driving at) and spurious interrupts.
* (On the system that this was first tested on, the input floats high
* and gives a (masked) interrupt as soon as the gate is closed.)
*/
outb(iobase + com_ier, 0);
- outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
- if ( inb(iobase + com_ier) != 0
- || isa_irq_pending(dev)
- || !(inb(iobase + com_iir) & IIR_NOPEND))
- result = 0;
- if (result == 0)
- outb(iobase + com_mcr, 0);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */
+ failures[7] = inb(iobase + com_ier);
+ failures[8] = isa_irq_pending(idev) ? 1 : 0;
+ failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
+ outb(IO_ICU1 + 1, imen); /* XXX */
enable_intr();
+
+ result = IO_COMSIZE;
+ for (fn = 0; fn < sizeof failures; ++fn)
+ if (failures[fn]) {
+ outb(iobase + com_mcr, 0);
+ result = 0;
+ if (COM_VERBOSE(dev))
+ printf("sio%d: probe test %d failed\n",
+ dev->id_unit, fn);
+ }
return (result);
}
@@ -403,9 +515,9 @@ sioattach(isdp)
iobase = isdp->id_iobase;
unit = isdp->id_unit;
- if (unit == comconsole)
- DELAY(1000); /* XXX */
- s = spltty();
+ com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
+ if (com == NULL)
+ return (0);
/*
* sioprobe() has initialized the device registers as follows:
@@ -414,15 +526,13 @@ sioattach(isdp)
* data port is not hidden when we enable interrupts.
* o ier = 0.
* Interrupts are only enabled when the line is open.
- * o mcr = MCR_IENABLE.
+ * o mcr = MCR_IENABLE, or 0 if the port has a master port.
* Keeping MCR_DTR and MCR_RTS off might stop the external
* device from sending before we are ready.
*/
-
- com = &com_structs[unit];
+ bzero(com, sizeof *com);
com->cfcr_image = CFCR_8BITS;
- com->mcr_image = MCR_IENABLE;
- com->dtr_wait = 200;
+ com->dtr_wait = 3 * hz;
com->tx_fifo_size = 1;
com->iptr = com->ibuf = com->ibuf1;
com->ibufend = com->ibuf1 + RS_IBUFSIZE;
@@ -431,9 +541,30 @@ sioattach(isdp)
com->data_port = iobase + com_data;
com->int_id_port = iobase + com_iir;
com->modem_ctl_port = iobase + com_mcr;
+ com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + com_lsr;
com->modem_status_port = iobase + com_msr;
- com->tp = &sio_tty[unit];
+
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h> since they
+ * are only relevant for logins. It's important to have echo off
+ * initially so that the line doesn't start blathering before the
+ * echo flag can be turned off.
+ */
+ com->it_in.c_iflag = 0;
+ com->it_in.c_oflag = 0;
+ com->it_in.c_cflag = TTYDEF_CFLAG;
+ com->it_in.c_lflag = 0;
+ if (unit == comconsole) {
+ com->it_in.c_iflag = TTYDEF_IFLAG;
+ com->it_in.c_oflag = TTYDEF_OFLAG;
+ com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
+ com->it_in.c_lflag = TTYDEF_LFLAG;
+ com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
+ }
+ termioschars(&com->it_in);
+ com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
+ com->it_out = com->it_in;
/* attempt to determine UART type */
printf("sio%d: type", unit);
@@ -470,10 +601,11 @@ sioattach(isdp)
break;
case FIFO_TRIGGER_14:
printf(" 16550A");
- if (COM_NOFIFO(isdp)) {
- printf(" fifo software disabled");
- } else {
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
com->hasfifo = TRUE;
+ com->ftl_init = FIFO_TRIGGER_14;
com->tx_fifo_size = 16;
}
break;
@@ -483,31 +615,36 @@ determined_type: ;
#ifdef COM_MULTIPORT
if (COM_ISMULTIPORT(isdp)) {
- struct isa_device *masterdev;
-
com->multiport = TRUE;
- printf(" (multiport)");
-
- /* set the master's common-interrupt-enable reg.,
- * as appropriate. YYY See your manual
- */
- /* enable only common interrupt for port */
- outb(com->modem_ctl_port, com->mcr_image = 0);
-
- masterdev = find_isadev(isa_devtab_tty, &siodriver,
- COM_MPMASTER(isdp));
- outb(masterdev->id_iobase + com_scr, 0x80);
- } else
- com->multiport = FALSE;
+ printf(" (multiport");
+ if (unit == COM_MPMASTER(isdp))
+ printf(" master");
+ printf(")");
+ }
#endif /* COM_MULTIPORT */
printf("\n");
#ifdef KGDB
if (kgdb_dev == makedev(commajor, unit)) {
- if (comconsole == unit)
+ if (unit == comconsole)
kgdb_dev = -1; /* can't debug over console port */
else {
- cominit(unit, kgdb_rate);
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
if (kgdb_debug_init) {
/*
* Print prefix of device name,
@@ -521,16 +658,11 @@ determined_type: ;
}
#endif
- /*
- * Need to reset baud rate, etc. of next print so reset comconsinit.
- */
- if (unit == comconsole)
- comconsinit = FALSE;
-
+ s = spltty();
com_addr(unit) = com;
splx(s);
if (!comwakeup_started) {
- comwakeup((caddr_t) NULL, 0);
+ comwakeup((caddr_t)NULL, 0);
comwakeup_started = TRUE;
}
return (1);
@@ -544,207 +676,127 @@ sioopen(dev, flag, mode, p)
int mode;
struct proc *p;
{
-#ifdef COM_BIDIR
- bool_t callout;
-#endif /* COM_BIDIR */
struct com_s *com;
- int error = 0;
+ int error;
Port_t iobase;
+ int mynor;
int s;
struct tty *tp;
int unit;
- unit = UNIT(dev);
+ mynor = minor(dev);
+ unit = MINOR_TO_UNIT(mynor);
if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
return (ENXIO);
-#ifdef COM_BIDIR
- /* if it's a callout device, and bidir not possible on that dev, die */
- callout = CALLOUT(dev);
- if (callout && !(com->bidir))
- return (ENXIO);
-#endif /* COM_BIDIR */
-
- tp = com->tp;
+ if (mynor & CONTROL_MASK)
+ return (0);
+ tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
s = spltty();
-
-#ifdef COM_BIDIR
-
-bidir_open_top:
- /* if it's bidirectional, we've gotta deal with it... */
- if (com->bidir) {
- if (callout) {
- if (com->active_in) {
- /* it's busy. die */
- splx(s);
- return (EBUSY);
- } else {
- /* it's ours. lock it down, and set it up */
- com->active_out = TRUE;
+ /*
+ * We jump to this label after all non-interrupted sleeps to pick
+ * up any changes of the device state.
+ */
+open_top:
+ while (com->state & CS_DTR_OFF) {
+ error = tsleep((caddr_t)&com->dtr_wait, TTIPRI | PCATCH,
+ "siodtr", 0);
+ if (error != 0)
+ goto out;
+ }
+ if (tp->t_state & TS_ISOPEN) {
+ /*
+ * The device is open, so everything has been initialized.
+ * Handle conflicts.
+ */
+ if (mynor & CALLOUT_MASK) {
+ if (!com->active_out) {
+ error = EBUSY;
+ goto out;
}
} else {
if (com->active_out) {
- /* it's busy, outgoing. wait, if possible */
if (flag & O_NONBLOCK) {
- /* can't wait; bail */
- splx(s);
- return (EBUSY);
- } else {
- /* wait for it... */
- error = tsleep((caddr_t)&com->active_out,
- TTIPRI|PCATCH,
- "siooth",
- 0);
- /* if there was an error, take off. */
- if (error != 0) {
- splx(s);
- return (error);
- }
- /* else take it from the top */
- goto bidir_open_top;
- }
- } else if (com->prev_modem_status & MSR_DCD
- || FAKE_DCD(unit)) {
- /* there's a carrier on the line; we win */
- com->active_in = TRUE;
- } else {
- /* there is no carrier on the line */
- if (flag & O_NONBLOCK) {
- /* can't wait; let it open */
- com->active_in = TRUE;
- } else {
- /* put DTR & RTS up */
- /* XXX - bring up RTS earlier? */
- commctl(com, MCR_DTR | MCR_RTS, DMSET);
- outb(com->iobase + com_ier, IER_EMSC);
-
- /* wait for it... */
- error = tsleep((caddr_t)&com->active_in,
- TTIPRI|PCATCH,
- "siodcd",
- 0);
-
- /* if not active, turn intrs and DTR off */
- if (!com->active) {
- outb(com->iobase + com_ier, 0);
- commctl(com, MCR_DTR, DMBIC);
- }
-
- /* if there was an error, take off. */
- if (error != 0) {
- splx(s);
- return (error);
- }
- /* else take it from the top */
- goto bidir_open_top;
+ error = EBUSY;
+ goto out;
}
+ error = tsleep((caddr_t)&com->active_out,
+ TTIPRI | PCATCH, "siobi", 0);
+ if (error != 0)
+ goto out;
+ goto open_top;
}
}
- }
-
- com->active = TRUE;
-#endif /* COM_BIDIR */
-
- tp->t_oproc = comstart;
- tp->t_param = comparam;
- tp->t_dev = dev;
- if (!(tp->t_state & TS_ISOPEN)) {
- tp->t_state |= TS_WOPEN;
- ttychars(tp);
- if (tp->t_ispeed == 0) {
- /*
- * We no longer use the flags from <sys/ttydefaults.h>
- * since those are only relevant for logins. It's
- * important to have echo off initially so that the
- * line doesn't start blathering before the echo flag
- * can be turned off.
- */
- tp->t_iflag = 0;
- tp->t_oflag = 0;
-#ifdef COMCONSOLE
- if (unit == comconsole)
- tp->t_oflag = TTYDEF_OFLAG;
-#endif
- tp->t_cflag = CREAD | CS8 | HUPCL;
- tp->t_lflag = 0;
- tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ error = EBUSY;
+ goto out;
}
-
+ } else {
/*
- * XXX the full state after a first open() needs to be
- * programmable and separate for callin and callout.
+ * The device isn't open, so there are no conflicts.
+ * Initialize it. Initialization is done twice in many
+ * cases: to preempt sleeping callin opens if we are
+ * callout, and to complete a callin open after DCD rises.
*/
-#ifdef COM_BIDIR
- if (com->bidir) {
- if (callout)
- tp->t_cflag |= CLOCAL;
- else
- tp->t_cflag &= ~CLOCAL;
- }
-#endif
-
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ tp->t_termios = mynor & CALLOUT_MASK
+ ? com->it_out : com->it_in;
commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ com->ftl_max = com->ftl_init;
+ ++com->wopeners;
error = comparam(tp, &tp->t_termios);
+ --com->wopeners;
if (error != 0)
goto out;
+ /*
+ * XXX we should goto open_top if comparam() slept.
+ */
ttsetwater(tp);
iobase = com->iobase;
if (com->hasfifo) {
- /* (re)enable and drain FIFO */
- outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
- | FIFO_RCV_RST | FIFO_XMT_RST);
+ /* Drain fifo. */
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST
+ | com->ftl);
DELAY(100);
}
disable_intr();
(void) inb(com->line_status_port);
(void) inb(com->data_port);
- com->last_modem_status =
- com->prev_modem_status = inb(com->modem_status_port);
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
| IER_EMSC);
enable_intr();
- if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
- tp->t_state |= TS_CARR_ON;
- } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
- splx(s);
- return (EBUSY);
- }
- while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
-#ifdef COM_BIDIR
- /* We went through a lot of trouble to open it,
- * but it's certain we have a carrier now, so
- * don't spend any time on it now.
+ /*
+ * Handle initial DCD. Callout devices get a fake initial
+ * DCD (trapdoor DCD). If we are callout, then any sleeping
+ * callin opens get woken up and resume sleeping on "siobi"
+ * instead of "siodcd".
*/
- && !(com->bidir)
-#endif /* COM_BIDIR */
- && !(tp->t_state & TS_CARR_ON)) {
- tp->t_state |= TS_WOPEN;
- error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- ttopen, 0);
+ if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ }
+ /*
+ * Wait for DCD if necessary.
+ */
+ if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
+ && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
+ ++com->wopeners;
+ error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
+ --com->wopeners;
if (error != 0)
- break;
+ goto out;
+ goto open_top;
}
+ error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
+ if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
+ com->active_out = TRUE;
out:
splx(s);
- if (error == 0)
- error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
-
-#ifdef COM_BIDIR
- /* wakeup sleepers */
- wakeup((caddr_t) &com->active_in);
-#endif /* COM_BIDIR */
-
- /*
- * XXX - the next step was once not done, so interrupts, DTR and RTS
- * remained hot if the process was killed while it was sleeping
- * waiting for carrier. Now there is the opposite problem. If several
- * processes are sleeping waiting for carrier on the same line and one
- * is killed, interrupts are turned off so the other processes will
- * never see the carrier rise.
- */
- if (error != 0 && !(tp->t_state & TS_ISOPEN))
+ if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
comhardclose(com);
- tp->t_state &= ~TS_WOPEN;
-
return (error);
}
@@ -757,13 +809,21 @@ sioclose(dev, flag, mode, p)
struct proc *p;
{
struct com_s *com;
+ int mynor;
+ int s;
struct tty *tp;
- com = com_addr(UNIT(dev));
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (0);
+ com = com_addr(MINOR_TO_UNIT(mynor));
tp = com->tp;
+ s = spltty();
(*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
comhardclose(com);
ttyclose(tp);
+ splx(s);
return (0);
}
@@ -776,10 +836,13 @@ comhardclose(com)
struct tty *tp;
int unit;
- s = spltty();
+ unit = DEV_TO_UNIT(com->tp->t_dev);
iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
- unit = com - &com_structs[0];
#ifdef KGDB
/* do not disable interrupts or hang up if debugging */
if (kgdb_dev != makedev(commajor, unit))
@@ -787,29 +850,29 @@ comhardclose(com)
{
outb(iobase + com_ier, 0);
tp = com->tp;
- if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
- || !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
+ if (tp->t_cflag & HUPCL
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching.
+ */
+ || !com->active_out
+ && !(com->prev_modem_status & MSR_DCD)
+ && !(com->it_in.c_cflag & CLOCAL)
|| !(tp->t_state & TS_ISOPEN)) {
commctl(com, MCR_RTS, DMSET);
- if (com->dtr_wait != 0)
- /*
- * Uninterruptible sleep since we want to
- * wait a fixed time.
- * XXX - delay in open() (if necessary),
- * not here (always).
- */
- tsleep((caddr_t)&com->dtr_wait, TTIPRI,
- "sioclose", com->dtr_wait);
+ if (com->dtr_wait != 0) {
+ timeout(siodtrwakeup, (caddr_t)com,
+ com->dtr_wait);
+ com->state |= CS_DTR_OFF;
+ }
}
}
-
-#ifdef COM_BIDIR
- com->active = com->active_in = com->active_out = FALSE;
-
- /* wakeup sleepers who are waiting for out to finish */
- wakeup((caddr_t) &com->active_out);
-#endif /* COM_BIDIR */
-
+ com->active_out = FALSE;
+ wakeup((caddr_t)&com->active_out);
+ wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
splx(s);
}
@@ -819,8 +882,13 @@ sioread(dev, uio, flag)
struct uio *uio;
int flag;
{
- struct tty *tp = com_addr(UNIT(dev))->tp;
+ int mynor;
+ struct tty *tp;
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (ENODEV);
+ tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}
@@ -830,9 +898,15 @@ siowrite(dev, uio, flag)
struct uio *uio;
int flag;
{
- int unit = UNIT(dev);
- struct tty *tp = com_addr(unit)->tp;
+ int mynor;
+ struct tty *tp;
+ int unit;
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (ENODEV);
+ unit = MINOR_TO_UNIT(mynor);
+ tp = com_addr(unit)->tp;
/*
* (XXX) We disallow virtual consoles if the physical console is
* a serial port. This is in case there is a display attached that
@@ -844,17 +918,37 @@ siowrite(dev, uio, flag)
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}
+static void
+siodtrwakeup(chan, ticks)
+ caddr_t chan;
+ int ticks;
+{
+ struct com_s *com;
+
+ com = (struct com_s *)chan;
+ com->state &= ~CS_DTR_OFF;
+ wakeup((caddr_t)&com->dtr_wait);
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
void
siointr(unit)
int unit;
{
- struct com_s *com;
-
#ifndef COM_MULTIPORT
- com = com_addr(unit);
- if (com != NULL)
- comintr1(com);
+ siointr1(com_addr(unit));
#else /* COM_MULTIPORT */
+ struct com_s *com;
bool_t possibly_more_intrs;
/*
@@ -869,29 +963,30 @@ siointr(unit)
for (unit = 0; unit < NSIO; ++unit) {
com = com_addr(unit);
if (com != NULL
- && !(inb(com->int_id_port) & IIR_NOPEND)) {
- /*
- * XXX call comintr1() instead of here from
- * comwakeup(). The interrupt edge problem
- * only exists for real interrupts.
- */
- comintr1(com);
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
possibly_more_intrs = TRUE;
}
}
} while (possibly_more_intrs);
-#endif /* COM_MULTIPORT */
+#endif /* COM_MULTIPORT */
}
static void
-comintr1(com)
+siointr1(com)
struct com_s *com;
{
- u_char line_status;
- u_char modem_status;
- u_char *ioptr;
- u_char recv_data;
-
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
while (TRUE) {
line_status = inb(com->line_status_port);
@@ -903,6 +998,8 @@ comintr1(com)
else
recv_data = inb(com->data_port);
++com->bytes_in;
+ if (com->hotchar != 0 && recv_data == com->hotchar)
+ setsofttty();
#ifdef KGDB
/* trap into kgdb? (XXX - needs testing and optim) */
if (recv_data == FRAME_END
@@ -981,7 +1078,7 @@ if (com->iptr - com->ibuf == 8)
while (--ocount != 0);
} else {
outb(com->data_port, *ioptr++);
- ++com->bytes_out;
+ ++com->bytes_out;
}
com->optr = ioptr;
if (ioptr >= com->obufend) {
@@ -994,7 +1091,7 @@ if (com->iptr - com->ibuf == 8)
/* finished? */
#ifndef COM_MULTIPORT
- if (inb(com->int_id_port) & IIR_NOPEND)
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
#endif /* COM_MULTIPORT */
return;
}
@@ -1002,9 +1099,9 @@ if (com->iptr - com->ibuf == 8)
static int
tiocm_xxx2mcr(tiocm_xxx)
- int tiocm_xxx;
+ int tiocm_xxx;
{
- int mcr;
+ int mcr;
mcr = 0;
if (tiocm_xxx & TIOCM_DTR)
@@ -1027,26 +1124,75 @@ sioioctl(dev, cmd, data, flag, p)
Port_t iobase;
int mcr;
int msr;
+ int mynor;
int s;
int tiocm_xxx;
struct tty *tp;
- com = com_addr(UNIT(dev));
+ mynor = minor(dev);
+ com = com_addr(MINOR_TO_UNIT(mynor));
+ if (mynor & CONTROL_MASK) {
+ struct termios *ct;
+
+ switch (mynor & CONTROL_MASK) {
+ case CONTROL_INIT_STATE:
+ ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
+ break;
+ case CONTROL_LOCK_STATE:
+ ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
+ break;
+ default:
+ return (ENODEV); /* /dev/nodev */
+ }
+ switch (cmd) {
+ case TIOCSETA:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error)
+ return (error);
+ *ct = *(struct termios *)data;
+ return (0);
+ case TIOCGETA:
+ *(struct termios *)data = *ct;
+ return (0);
+ case TIOCGETD:
+ *(int *)data = TTYDISC;
+ return (0);
+ case TIOCGWINSZ:
+ bzero(data, sizeof(struct winsize));
+ return (0);
+ default:
+ return (ENOTTY);
+ }
+ }
tp = com->tp;
+ if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
+ int cc;
+ struct termios *dt = (struct termios *)data;
+ struct termios *lt = mynor & CALLOUT_MASK
+ ? &com->lt_out : &com->lt_in;
+
+ dt->c_iflag = (tp->t_iflag & lt->c_iflag)
+ | (dt->c_iflag & ~lt->c_iflag);
+ dt->c_oflag = (tp->t_oflag & lt->c_oflag)
+ | (dt->c_oflag & ~lt->c_oflag);
+ dt->c_cflag = (tp->t_cflag & lt->c_cflag)
+ | (dt->c_cflag & ~lt->c_cflag);
+ dt->c_lflag = (tp->t_lflag & lt->c_lflag)
+ | (dt->c_lflag & ~lt->c_lflag);
+ for (cc = 0; cc < NCCS; ++cc)
+ if (lt->c_cc[cc] != 0)
+ dt->c_cc[cc] = tp->t_cc[cc];
+ if (lt->c_ispeed != 0)
+ dt->c_ispeed = tp->t_ispeed;
+ if (lt->c_ospeed != 0)
+ dt->c_ospeed = tp->t_ospeed;
+ }
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error >= 0)
return (error);
error = ttioctl(tp, cmd, data, flag);
-
-#ifdef COM_BIDIR
- /* XXX: plug security hole while sticky bits not yet implemented */
- if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
- tp->t_cflag &= ~CLOCAL;
-#endif
-
if (error >= 0)
return (error);
-
iobase = com->iobase;
s = spltty();
switch (cmd) {
@@ -1094,57 +1240,24 @@ sioioctl(dev, cmd, data, flag, p)
tiocm_xxx |= TIOCM_RI;
*(int *)data = tiocm_xxx;
break;
-#ifdef COM_BIDIR
- case TIOCMSBIDIR:
- /* must be root to set bidir. capability */
- error = suser(p->p_ucred, &p->p_acflag);
- if (error != 0) {
- splx(s);
- return(EPERM);
- }
-
- /* if it's the console, can't do it (XXX why?) */
- if (UNIT(dev) == comconsole) {
- splx(s);
- return(ENOTTY);
- }
-
-#if 0
- /* XXX - can't do the next, for obvious reasons...
- * but there are problems to be looked at...
- */
- /* if the port is active, don't do it */
- if (com->active) {
- splx(s);
- return(EBUSY);
- }
-#endif
-
- com->bidir = *(int *)data;
- break;
- case TIOCMGBIDIR:
- *(int *)data = com->bidir;
- break;
-#endif /* COM_BIDIR */
case TIOCMSDTRWAIT:
/* must be root since the wait applies to following logins */
error = suser(p->p_ucred, &p->p_acflag);
if (error != 0) {
splx(s);
- return(EPERM);
+ return (EPERM);
}
-
- /* if it's the console, can't do it (XXX why?) */
- if (UNIT(dev) == comconsole) {
- splx(s);
- return(ENOTTY);
- }
-
- com->dtr_wait = *(int *)data;
+ com->dtr_wait = *(int *)data * 100 / hz;
break;
case TIOCMGDTRWAIT:
*(int *)data = com->dtr_wait;
break;
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
default:
splx(s);
return (ENOTTY);
@@ -1165,7 +1278,7 @@ comflush(com)
com_events -= LOTS_OF_EVENTS;
com->state &= ~(CS_ODONE | CS_BUSY);
enable_intr();
- rbp = &com->tp->t_out;
+ rbp = com->tp->t_out;
rbp->rb_hd += com->ocount;
rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
com->ocount = 0;
@@ -1175,24 +1288,14 @@ comflush(com)
void
siopoll()
{
- static bool_t awake = FALSE;
- int s;
int unit;
if (com_events == 0)
return;
- disable_intr();
- if (awake) {
- enable_intr();
- return;
- }
- awake = TRUE;
- enable_intr();
- s = spltty();
repeat:
for (unit = 0; unit < NSIO; ++unit) {
- u_char *buf;
- struct com_s *com;
+ u_char *buf;
+ struct com_s *com;
u_char *ibuf;
int incc;
struct tty *tp;
@@ -1201,12 +1304,25 @@ repeat:
if (com == NULL)
continue;
tp = com->tp;
+ if (tp == NULL)
+ continue;
/* switch the role of the low-level input buffers */
if (com->iptr == (ibuf = com->ibuf)) {
buf = NULL; /* not used, but compiler can't tell */
incc = 0;
} else {
+ /*
+ * Prepare to reduce input latency for packet
+ * discplines with a end of packet character.
+ * XXX should be elsewhere.
+ */
+ if (tp->t_line == SLIPDISC)
+ com->hotchar = 0xc0;
+ else if (tp->t_line == PPPDISC)
+ com->hotchar = 0x7e;
+ else
+ com->hotchar = 0;
buf = ibuf;
disable_intr();
incc = com->iptr - buf;
@@ -1224,7 +1340,15 @@ repeat:
* of input, so enable RTS if it is now disabled and
* there is room in the high-level buffer.
*/
- if (!(com->mcr_image & MCR_RTS)
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS)
&& !(tp->t_state & TS_RTS_IFLOW))
outb(com->modem_ctl_port,
com->mcr_image |= MCR_RTS);
@@ -1242,35 +1366,45 @@ repeat:
com_events -= LOTS_OF_EVENTS;
com->state &= ~CS_CHECKMSR;
enable_intr();
- if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
- if (com->prev_modem_status & MSR_DCD) {
- (*linesw[tp->t_line].l_modem)(tp, 1);
-#ifdef COM_BIDIR
- wakeup((caddr_t) &com->active_in);
-#endif /* COM_BIDIR */
- } else
- (*linesw[tp->t_line].l_modem)(tp, 0);
- }
+ if (delta_modem_status & MSR_DCD)
+ (*linesw[tp->t_line].l_modem)
+ (tp, com->prev_modem_status & MSR_DCD);
}
/* XXX */
if (TRUE) {
- u_int delta;
- int errnum;
- u_long total;
+ u_int delta;
+ int errnum;
+ u_long total;
for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
- disable_intr();
+ disable_intr();
delta = com->delta_error_counts[errnum];
com->delta_error_counts[errnum] = 0;
- enable_intr();
- if (delta != 0) {
- total =
- com->error_counts[errnum] += delta;
+ enable_intr();
+ if (delta == 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ total = com->error_counts[errnum] += delta;
log(LOG_WARNING,
"sio%d: %u more %s%s (total %lu)\n",
unit, delta, error_desc[errnum],
delta == 1 ? "" : "s", total);
+ if (errnum == CE_OVERRUN && com->hasfifo
+ && com->ftl > FIFO_TRIGGER_1) {
+ static u_char ftl_in_bytes[] =
+ { 1, 4, 8, 14, };
+
+ com->ftl_init = FIFO_TRIGGER_8;
+#define FIFO_TRIGGER_DELTA FIFO_TRIGGER_4
+ com->ftl_max =
+ com->ftl -= FIFO_TRIGGER_DELTA;
+ outb(com->iobase + com_fifo,
+ FIFO_ENABLE | com->ftl);
+ log(LOG_WARNING,
+ "sio%d: reduced fifo trigger level to %d\n",
+ unit,
+ ftl_in_bytes[com->ftl
+ / FIFO_TRIGGER_DELTA]);
}
}
}
@@ -1285,7 +1419,7 @@ repeat:
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
if (com->state & CS_RTS_IFLOW
- && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
+ && RB_LEN(tp->t_raw) + incc >= RB_I_HIGH_WATER
&& !(tp->t_state & TS_RTS_IFLOW)
/*
* XXX - need RTS flow control for all line disciplines.
@@ -1312,7 +1446,7 @@ repeat:
tk_rawcc += incc;
tp->t_rawcc += incc;
com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
- += incc - rb_write(&tp->t_raw, (char *) buf,
+ += incc - rb_write(tp->t_raw, (char *) buf,
incc);
ttwakeup(tp);
if (tp->t_state & TS_TTSTOP
@@ -1348,8 +1482,6 @@ repeat:
}
if (com_events >= LOTS_OF_EVENTS)
goto repeat;
- splx(s);
- awake = FALSE;
}
static int
@@ -1370,11 +1502,11 @@ comparam(tp, t)
divisor = ttspeedtab(t->c_ospeed, comspeedtab);
if (t->c_ispeed == 0)
t->c_ispeed = t->c_ospeed;
- if (divisor < 0 || t->c_ispeed != t->c_ospeed)
+ if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
return (EINVAL);
/* parameters are OK, convert them to the com struct and the device */
- unit = UNIT(tp->t_dev);
+ unit = DEV_TO_UNIT(tp->t_dev);
com = com_addr(unit);
iobase = com->iobase;
s = spltty();
@@ -1405,12 +1537,28 @@ comparam(tp, t)
if (cflag & CSTOPB)
cfcr |= CFCR_STOPB;
+ if (com->hasfifo) {
+ /*
+ * Use a fifo trigger level low enough so that the input
+ * latency from the fifo is less than about 16 msec and
+ * the total latency is less than about 30 msec. These
+ * latencies are reasonable for humans. Serial comms
+ * protocols shouldn't expect anything better since modem
+ * latencies are larger.
+ */
+ com->ftl = t->c_ospeed <= 4800
+ ? FIFO_TRIGGER_1 : FIFO_TRIGGER_14;
+ if (com->ftl > com->ftl_max)
+ com->ftl = com->ftl_max;
+ outb(iobase + com_fifo, FIFO_ENABLE | com->ftl);
+ }
+
/*
* Some UARTs lock up if the divisor latch registers are selected
* while the UART is doing output (they refuse to transmit anything
* more until given a hard reset). Fix this by stopping filling
* the device buffers and waiting for them to drain. Reading the
- * line status port outside of siointr() might lose some receiver
+ * line status port outside of siointr1() might lose some receiver
* error bits, but that is acceptable here.
*/
disable_intr();
@@ -1419,8 +1567,8 @@ retry:
enable_intr();
while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
!= (LSR_TSRE | LSR_TXRDY)) {
- error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- "sioparam", 1);
+ error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
+ "siotx", hz / 100);
if (error != 0 && error != EAGAIN) {
if (!(tp->t_state & TS_TTSTOP)) {
disable_intr();
@@ -1441,7 +1589,7 @@ retry:
* sufficient, for similar reasons.
*/
if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
- != (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
goto retry;
if (divisor != 0) {
@@ -1460,7 +1608,7 @@ retry:
/*
* Set up state to handle output flow control.
* XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
- * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ * Now has 10+ msec latency, while CTS flow has 50- usec latency.
*/
com->state &= ~CS_CTS_OFLOW;
com->state |= CS_ODEVREADY;
@@ -1471,15 +1619,12 @@ retry:
}
/*
- * Recover from fiddling with CS_TTGO. We used to call siointr()
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
* unconditionally, but that defeated the careful discarding of
* stale input in sioopen().
- *
- * XXX sioopen() is not careful waiting for carrier for the callout
- * case.
*/
if (com->state >= (CS_BUSY | CS_TTGO))
- comintr1(com);
+ siointr1(com);
enable_intr();
splx(s);
@@ -1494,7 +1639,7 @@ comstart(tp)
int s;
int unit;
- unit = UNIT(tp->t_dev);
+ unit = DEV_TO_UNIT(tp->t_dev);
com = com_addr(unit);
s = spltty();
disable_intr();
@@ -1506,35 +1651,31 @@ comstart(tp)
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
} else {
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
}
enable_intr();
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
goto out;
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state & TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
if (com->ocount != 0) {
disable_intr();
- comintr1(com);
+ siointr1(com);
enable_intr();
- } else if (RB_LEN(&tp->t_out) != 0) {
+ } else if (RB_LEN(tp->t_out) != 0) {
tp->t_state |= TS_BUSY;
- com->ocount = RB_CONTIGGET(&tp->t_out);
+ com->ocount = RB_CONTIGGET(tp->t_out);
disable_intr();
- com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
+ com->obufend = (com->optr = (u_char *)tp->t_out->rb_hd)
+ com->ocount;
com->state |= CS_BUSY;
- comintr1(com); /* fake interrupt to start output */
+ siointr1(com); /* fake interrupt to start output */
enable_intr();
}
out:
@@ -1548,7 +1689,7 @@ siostop(tp, rw)
{
struct com_s *com;
- com = com_addr(UNIT(tp->t_dev));
+ com = com_addr(DEV_TO_UNIT(tp->t_dev));
if (rw & FWRITE)
comflush(com);
disable_intr();
@@ -1569,11 +1710,9 @@ sioselect(dev, rw, p)
int rw;
struct proc *p;
{
-#ifdef COM_BIDIR
- return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
-#else
- return ttselect(dev, rw, p);
-#endif
+ if (minor(dev) & CONTROL_MASK)
+ return (ENODEV);
+ return (ttselect(dev & ~MINOR_MAGIC_MASK, rw, p));
}
static void
@@ -1600,15 +1739,20 @@ commctl(com, bits, how)
static void
comwakeup(chan, ticks)
- caddr_t chan;
- int ticks;
+ caddr_t chan;
+ int ticks;
{
- int unit;
+ int unit;
+
+ timeout(comwakeup, (caddr_t)NULL, hz / 100);
+
+ if (com_events != 0) {
+ int s;
- timeout(comwakeup, (caddr_t) NULL, hz / 100);
- if (com_events != 0)
- /* schedule siopoll() to run when the cpl allows */
- setsofttty();
+ s = splsofttty();
+ siopoll();
+ splx(s);
+ }
/* recover from lost output interrupts */
for (unit = 0; unit < NSIO; ++unit) {
@@ -1617,27 +1761,97 @@ comwakeup(chan, ticks)
com = com_addr(unit);
if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
disable_intr();
- comintr1(com);
+ siointr1(com);
enable_intr();
}
}
- return;
-}
-
-void
-softsio1()
-{
- siopoll();
}
/*
* Following are all routines needed for SIO to act as console
- * XXX - not tested in this version
- * XXX - i386/cons.c only knows about the com driver (NCOM and not NSIO)
- * XXX - check that the corresponding serial interrupts are never enabled
*/
#include "i386/i386/cons.h"
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void siocnclose __P((struct siocnstate *sp));
+static void siocnopen __P((struct siocnstate *sp));
+static void siocntxwait __P((void));
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp oscllations of MCR_DTR and MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
void
siocnprobe(cp)
struct consdev *cp;
@@ -1645,14 +1859,14 @@ siocnprobe(cp)
int unit;
/* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
for (commajor = 0; commajor < nchrdev; commajor++)
if (cdevsw[commajor].d_open == sioopen)
break;
/* XXX: ick */
- unit = UNIT(CONUNIT);
- com_addr(unit) = &com_structs[unit];
- com_addr(unit)->iobase = CONADDR;
+ unit = DEV_TO_UNIT(CONUNIT);
+ siocniobase = CONADDR;
/* make sure hardware exists? XXX */
@@ -1669,43 +1883,11 @@ void
siocninit(cp)
struct consdev *cp;
{
- int unit;
-
- unit = UNIT(cp->cn_dev);
- cominit(unit, comdefaultrate);
- comconsole = unit;
- comconsinit = TRUE;
-}
-
-static void
-cominit(unit, rate)
- int unit;
- int rate;
-{
- Port_t iobase;
- int s;
-
- iobase = com_addr(unit)->iobase;
- s = splhigh();
- outb(iobase + com_cfcr, CFCR_DLAB);
- rate = ttspeedtab(comdefaultrate, comspeedtab);
- outb(iobase + com_dlbl, rate & 0xFF);
- outb(iobase + com_dlbh, rate >> 8);
- outb(iobase + com_cfcr, CFCR_8BITS);
- outb(iobase + com_fifo,
- FIFO_ENABLE | FIFO_TRIGGER | FIFO_RCV_RST | FIFO_XMT_RST);
- DELAY(100);
- (void) inb(iobase + com_lsr);
- (void) inb(iobase + com_data);
- (void) inb(iobase + com_msr);
-
/*
- * XXX - fishy to enable interrupts and then poll.
- * It shouldn't be necessary to ready the iir.
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
*/
- outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
- (void) inb(iobase + com_iir);
- splx(s);
+ comconsole = DEV_TO_UNIT(cp->cn_dev);
}
int
@@ -1715,13 +1897,15 @@ siocngetc(dev)
int c;
Port_t iobase;
int s;
+ struct siocnstate sp;
- iobase = com_addr(UNIT(dev))->iobase;
- s = splhigh();
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
while (!(inb(iobase + com_lsr) & LSR_RXRDY))
;
c = inb(iobase + com_data);
- (void) inb(iobase + com_iir);
+ siocnclose(&sp);
splx(s);
return (c);
}
@@ -1731,30 +1915,14 @@ siocnputc(dev, c)
dev_t dev;
int c;
{
- Port_t iobase;
int s;
- int timo;
+ struct siocnstate sp;
- iobase = com_addr(UNIT(dev))->iobase;
- s = splhigh();
-#ifdef KGDB
- if (dev != kgdb_dev)
-#endif
- if (!comconsinit) {
- cominit(UNIT(dev), comdefaultrate);
- comconsinit = TRUE;
- }
- /* wait for any pending transmission to finish */
- timo = 50000;
- while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
- ;
- outb(iobase + com_data, c);
- /* wait for this transmission to complete */
- timo = 1500000;
- while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
- ;
- /* clear any interrupts generated by this transmission */
- (void) inb(iobase + com_iir);
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
splx(s);
}
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG
new file mode 100644
index 000000000000..6a9bef153ce3
--- /dev/null
+++ b/sys/i386/isa/sound/CHANGELOG
@@ -0,0 +1,75 @@
+Changelog for version 2.5
+-------------------------
+
+Since 2.5-beta2
+- Some fine tuning to the GUS v3.7 mixer code.
+- Fixed speed limits for the plain SB (1.0 to 2.0).
+
+Since 2.5-beta
+- Fixed OPL-3 detection with SB. Caused problems with PAS16.
+- GUS v3.7 mixer support.
+
+Since 2.4
+- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h).
+- Fixed truncated sound on /dev/dsp when the device is closed.
+- Linear volume mode for GUS
+- Pitch bends larger than +/- 2 octaves.
+- MIDI recording for SB and SB Pro. (Untested).
+- Some other fixes.
+- SB16 MIDI and DSP drivers only initialized if SB16 actually installed.
+- Implemented better detection for OPL-3. This should be usefull if you
+ have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3.
+- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested).
+
+Since 2.3b
+- Fixed bug which made it impossible to make long recordings to disk.
+ Recording was not restarted after a buffer overflow situation.
+- Limited mixer support for GUS.
+- Numerous improvements to the GUS driver by Andrew Robinson. Including
+ some click removal etc.
+
+Since 2.3
+- Fixed some minor bugs in the SB16 driver.
+
+Since 2.2b
+- Full SB16 DSP support. 8/16 bit, mono/stereo
+- The SCO and FreeBSD versions should be in sync now. There are some
+ problems with SB16 and GUS in the freebsd versions.
+ The DMA buffer allocation of the SCO version has been polished but
+ there could still be some problems. At least it hogs memory.
+ The DMA channel
+ configuration method used in the sco/System is a hack.
+- Support for the MPU emulation of the SB16.
+- Some big arrays are now allocated boot time. This makes the bss segment
+ smaller which makes it possible to use the full driver with
+ NetBSD. These arrays are not allocated if no suitable soundcard is available.
+- Fixed a bug in the compute_and_set_volume in gus_wave.c
+- Fixed the too fast mono playback problem of SB Pro and PAS16.
+
+Since 2.2
+- Stereo recording for SB Pro. Somehow it was missing and nobody
+ had noticed it earlier.
+- Minor polishing.
+- Interpreting of boot time arguments (sound=) for Linux.
+- Breakup of sb_dsp.c. Parts of the code has been moved to
+ sb_mixer.c and sb_midi.c
+
+Since 2.1
+- Preliminary support for SB16.
+ - The SB16 mixer is supported in it's native mode.
+ - Digitized voice capability up to 44.1 kHz/8 bit/mono
+ (16 bit and stereo support coming in the next release).
+- Fixed some bugs in the digitized voice driver for PAS16.
+- Proper initialization of the SB emulation of latest PAS16 models.
+
+- Significantly improved /dev/dsp and /dev/audio support.
+ - Now supports half duplex mode. It's now possible to record and
+ playback without closing and reopening the device.
+ - It's possible to use smaller buffers than earlier. There is a new
+ ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4.
+ This call instructs the driver to use smaller buffers. The default
+ buffer size (0.5 to 1.0 seconds) is divided by n. Should be called
+ immediately after opening the device.
+
+Since 2.0
+Just cosmetic changes.
diff --git a/sys/i386/isa/sound/RELNOTES.Linux b/sys/i386/isa/sound/RELNOTES.Linux
index 4082f4e255b0..ea57d0a950c4 100644
--- a/sys/i386/isa/sound/RELNOTES.Linux
+++ b/sys/i386/isa/sound/RELNOTES.Linux
@@ -1,67 +1,74 @@
-Release notes for the Linux Sound Driver 1.99.9
------------------------------------------------
-
-******** THIS IS A BETA TEST RELEASE ********
-which means that there can be some untested things. In theory
-there is a risk that this driver causes some trouble to your system.
-You should not use this driver before backing up your disks.
-
-
-
-
-Welcome to use the Gravis UltraSound driver for Linux. This
-driver still supports the same cards than version 1.0c
-(SoundBlaster, SB Pro, Pro Audio Spectrum 16 and AdLib).
-In addition there is rather limited support for MPU-401
+Release notes for the Linux Sound Driver 2.5
+--------------------------------------------
+There is also a version called 2.5-beta floating around the net. This
+version contains some fixes after it. Mainly to the SB and GUS code.
+
+CAUTION! The SVR4.2 port has not been tested much. Backup your system
+ carefully before trying it.
+
+This is mainly a bug fix release. There are couple of new things such as
+linear volume mode for GUS and MIDI recording for SB 2.0 and SB Pro.
+Also this version supports the mixer of GUS v3.7. (Support for GUS MAX and
+the 16-bit daughtercard is coming sooner or later).
+
+NOTE! The sound driver is a part of the Linux kernel distribution also.
+ Check that your kernel doesn't have more recent version than this
+ when installing a separately distributed sound driver. The
+ version number of this driver is defined in the makefile.
+
+This version contains a driver for the SB16 also.
+The SB16 driver requires separate DMA channels for the 8 and 16 bit
+modes. There should be a way to share the 8 bit DMA channels between
+these modes but this feature is not supported yet.
+The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de).
+
+The SB16 driver has also the Midi input capability even at the same
+time with the /dev/dsp. Also the WaveBlaster daughter board is supported.
+No support for the ASP chip yet (the ASP chip can be installed but it's
+not used by the driver).
+
+You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
+packages to use this driver. They should be in the same
+ftp site or BBS from where you got this driver. For
+example at nic.funet.fi:pub/OS/Linux/*.
+
+If you are looking for the installation instructions, please
+look at $OS/Readme.
+
+This version supports the following soundcards:
+GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
+In addition there is rather limited support for MPU-401.
(and compatible) midi cards. Also the OPL-3 synthesizer
-of the SB Pro and PAS16 cards is now supported in the 4 OP
-modes.
Most of the features of the /dev/sequencer device file are
available just for GUS owners.
-The SoundBlaster 16 and SB 16 ASP cards are not supported.
-They could work in mono mode with speeds < 22 kHz.
-The OPL-3 chicp of the SB 16 should work (without problems?).
-Is there anybody willing to implement the SB 16 support
-(have the SB 16 and the SDK for it)?
-
-
-This is the first version of the driver which has almost
-all of the features which I have planned to include into
-version 2.0. Some features are still missing and some ones
-doesn't work.
-
NOTE! There are separate driver for CD-ROMS supported by
some soundcards. The driver for CDU31A (Fusion 16) is
called cdu31a-0.6.diff.z. It will be contained in the
Linux version 0.99.12. The driver for the CD-ROM of SB Pro
is sbpcd0.4.tar.gz (these were the latest versions when I wrote
this). These files should be at least at sunsite.unc.edu.
- As far as I know, there is no driver for the SCSI interface of PAS16
- (yet).
+ Also the SCSI interface of the PAS16 should be supported by
+ Linux 0.99.13k and later.
There is also a driver for joystick. Look for file joystick-0.5.tar.gz
(sunsite).
- Since this driver is a sound driver, it will not contain support
- for SCSI/CD-ROM/Joystick -devices.
Compatibility with the earlier versions
---------------------------------------
-This is just like the version 1.99.7/1.99.8. There is just some minor
-enhancements. Most of them are portability fixes. If you are porting
-this driver to any OS, please look at the 386bsd/os.h. There is some
-new macros and some macros have more parameters. In addition this file
-contains some usefull comments.
+In this version the ultrasound.h no longer includes the sys/soundcard.h
+You have to change the gmod.c of the snd-util-2.0 package and to add an
+include for it.
-**** There is some ISC and 386bsd stuff in this driver. Please stay away ****
-This stuff is here just because I want to be in sync with the porters. These
-ports don't work yet.
+IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
+
+This version is not binary or source compatible with the version 1.0c.
The ioctl() interface has changed completely since version 1.0c. All
programs using this driver must be at least recompiled.
-The snd-util-1.99.6 package contains some utilities for this version.
+The snd-util-2.0 package contains some utilities for this version.
The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
where the input argument was passed by value and the output value was
@@ -78,59 +85,46 @@ After version 1.99.0 this must be done as the following:
If you have an application written for the version 1.0, you should search
for the strings SNDCTL_ and SOUND_ and to check the parameters.
+The following ioctl calls have changed:
+
+ SNDCTL_SEQ_GETOUTCOUNT
+ SNDCTL_SEQ_GETINCOUNT
+ SNDCTL_SEQ_TESTMIDI
+ SNDCTL_DSP_SPEED
+ SNDCTL_DSP_STEREO
+ SNDCTL_DSP_GETBLKSIZE
+ SNDCTL_DSP_SAMPLESIZE
+ SOUND_PCM_WRITE_CHANNELS
+ SOUND_PCM_WRITE_FILTER
+ SOUND_PCM_READ_RATE
+ SOUND_PCM_READ_CHANNELS
+ SOUND_PCM_READ_BITS
+ SOUND_PCM_READ_FILTER
+ SOUND_PCM_WRITE_BITS
+ SOUND_PCM_WRITE_RATE
+ SOUND_MIXER_READ_* (several ones)
+ SOUND_MIXER_WRITE_* (several ones)
Since the this version will support more than one synthesizer devices
at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
there is some new fields which must be initialized. Look at the sbiset.c in
-the snd-util-1.99.6 package for further info.
-
-The GUS patch format has changed since the version 1.99.3. You have to
-use latest versions of the programs in the sound/gustest directory. In
-addition the version 0.4g of the Adagio package supports this format.
-
-New features
-------------
-
-There is also some changes which make this version more usable than
-the version 1.0c.
-
-- /dev/dsp and /dev/audio
-
-The DMA buffering is now little bit more intelligent than earlier. The
-buffer size is selected run-time so that a buffer holds data for 0.5 to
-1.0 seconds of recording or playback. This makes recording more comfortable
-than with version 1.0. With the previous version there was sometimes more
-than 10 seconds of delay before the driver returned the first input byte.
-
-There is also support for more than one digitized voice devices. The device
-files /dev/dsp1 and /dev/audio1 (minor 19 and 20) are available with PAS16.
-The /dev/dsp (/dev/audio) is connected to the PCM circuit of the PAS16 itself
-and the /dev/dsp1 (/dev/audio1) to the SB emulation of PAS16 card. Two
-dsp/audio devices are available also if you have combination of SB and GUS.
-With GUS and PAS16 you will have even three dsp/audio devices. These devices
-can be used independently and can be active at the same time (3 channels
-at the same time propably don't work).
+the snd-util-2.0 package for further info.
-The dsp/audio support of PAS16 should be much cleaner now since the
-constant clicking sound between the DMA blocks (about once per second) has
-been eliminated.
+This version is almost 100% compatible with the alpha test version (1.99.9). The
+difference is in the installation procedure.
-The stereo playback of GUS doesn't work perfectly. There is lot of
-clicking in the output.
+Using this driver with other operating systems than Linux
+---------------------------------------------------------
-- /dev/mixer
+This package contains just the Linux version. The version 2.3
+for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound.
+The version 2.3 doesn't work well with xxxxxBSD. Use the version
+2.3 for them.
-No changes.
-
-There is no mixer for the GUS yet.
-
-- /dev/sequencer
-
-This part has the most changes. Mostly to support the rich
-features of the Gravis UltraSound. There is also the support
-for the OPL-3 synthesizer chip.
+/dev/sndstat
+------------
-- /dev/sndstat
+The /dev/sndstat is now available in the SCO and BSD versions also.
This is a new devicefile for debugging purposes. A better place for
it is in the /proc -directory but I was just too lazy to implement it
@@ -139,11 +133,13 @@ info about the current configuration (see the example below). If you
send me a error/problem report, please include a printout from this
device to your message (cat /dev/sndstat).
+Note! This device file is currently present only in the Linux version
+ of this driver.
+
------ cut here --- cat /dev/sndstat example --------
Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
Config options: 0x00000d4b
-Major number: 14
HW config:
Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6
Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3
@@ -166,12 +162,15 @@ Midi devices:
Mixer(s) installed
------ cut here ---- End of Example -----------
+Known bugs/limitations
+----------------------
-Known bugs
-----------
-
-- There was clicking during stereo playback to /dev/dsp with GUS.
- * Fixed in 1.99.9 *
+- High speed recording of long audio samples (>20 second) to disk
+ is not possible. Everything works until next sync() which delays the
+ recording process too much. A delay longer than 0.1 to 0.3 seconds is
+ too much.
+- The SB16 driver sometimes swaps the left and right channels together.
+- Midi input doesn't work with SB and SB Pro (SB16 works).
- It's not possible to open /dev/dsp (or /dev/audio) while the
/dev/sequencer is open for output and GUS is the only soundcard
installed. It's possible if /dev/dsp is opened before /dev/sequencer
@@ -180,12 +179,77 @@ Known bugs
- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
adapter.
+- There are some problems in midi input with MPU-401 and the SB16 midi
+ (MPU-401 emulation). This makes it impossible to read long sysex dumps
+ using these devices.
- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
^C and playing again should solve this problem. This is propably caused by
- incompatibilities between GUS and certain VLB motherboards. Try to avoid
+ incompatibilities between GUS and certain VLB motherboards (like mine).
+ Try to avoid
switching between VTs while patches are being loaded to the GUS.
-- There was some problems with GUS and Mitsumi CD in version 1.99.8. Fixed
- in 1.99.9.
-- /dev/audio sounded like stereo with GUS. Fixed in 1.99.9.
+ This problem disappears completely if you define GUS_PATCH_NO_DMA in the
+ local.h (after make config in linux). The drawback is that patch loading
+ without DMA takes several times longer than with DMA.
- There is a skeleton of the patch manager support. It don't work in
this version.
+
+
+Future development
+------------------
+
+- Since this driver is no longer just the Linux Sound Driver, it's time
+ to give it a new name. I have planned to use name VoxWare.
+- I'm writing a Hacker's guide to the VoxWare sound driver. Should
+ be ready within this(/next) year (alpha version).
+- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
+- I'm interested to implement/include support for new soundcards and
+ operating systems.
+
+ Hint for the soundcard and OS manufacturers:
+ I'm collecting soundcards (high end ones) and SDKs for them. In
+ addition I'm collecting PC operating systems. I will be happy if
+ somebody sends me such items. In addition such kind of donation
+ makes it easier to change the VoxWare driver to support your
+ soundcard or operating system. However, please contact me before
+ sending anything.
+
+I will propably release some fix versions within this and next year. At
+least when the non-Linux versions get ready. The next major release (3.0)
+will be quite complete rewrite and released after about a year (end of 94 or
+beginning of 95).
+
+
+Contributors
+------------
+
+This driver contains code by several contributors. In addition several other
+persons have given usefull suggestions. The following is a list of major
+contributors. (I could have forgotten some names.)
+
+ Craig Metz 1/2 of the PAS16 Mixer and PCM support
+ Rob Hooft Volume computation algorithm for the FM synth.
+ Mika Liljeberg uLaw encoding and decoding routines
+ Greg Lee Volume computation algorithm for the GUS and
+ lot's of valuable suggestions.
+ Andy Warner Initial ISC port
+ Jim Lowe Initial FreeBSD port
+ Anders Baekgaard Bughunting and valuable suggestions.
+ Joerg Schubert SB16 DSP support.
+ Andrew Robinson Improvements to the GUS driver
+ Megens SA MIDI recording for SB and SB Pro.
+ Mikael Nordqvist Linear volume support for GUS.
+ Ian Hartas SVR4.2 port
+ Markus Aroharju and
+ Risto Kankkunen Major contributions to the mixer support
+ of GUS v3.7.
+ Hunyue Yau Sound Galaxy NX Pro mixer support.
+
+Regards,
+
+Hannu Savolainen
+hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
+
+Snail mail: Hannu Savolainen
+ Pallaksentie 4 A 2
+ 00970 Helsinki
+ Finland
diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c
index 29e521e914d9..6365069384a5 100644
--- a/sys/i386/isa/sound/adlib_card.c
+++ b/sys/i386/isa/sound/adlib_card.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/adlib_card.c
- *
+ * sound/adlib_card.c
+ *
* Detection routine for the AdLib card.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -13,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -25,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
index 775e6abeb021..f27f9d5fa09f 100644
--- a/sys/i386/isa/sound/audio.c
+++ b/sys/i386/isa/sound/audio.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/audio.c
- *
+ * sound/audio.c
+ *
* Device file manager for /dev/audio
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -38,23 +38,45 @@
#define OFF 0
static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
+
* incomplete output block */
static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+
+static int audio_mode[MAX_DSP_DEV];
+
+#define AM_NONE 0
+#define AM_WRITE 1
+#define AM_READ 2
+
static char *wr_dma_buf[MAX_DSP_DEV];
int
audio_open (int dev, struct fileinfo *file)
{
- int mode;
int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+
+ if (dev_type == SND_DEV_DSP16)
+ bits = 16;
+ else
+ bits = 8;
if ((ret = DMAbuf_open (dev, mode)) < 0)
return ret;
+ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+ {
+ audio_release (dev, file);
+ return RET_ERROR (ENXIO);
+ }
+
wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+
return ret;
}
@@ -106,12 +128,20 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
int c, p, l;
int err;
+ int dev_type = dev & 0x0f;
dev = dev >> 4;
p = 0;
c = count;
+ if (audio_mode[dev] == AM_READ) /* Direction changed */
+ {
+ wr_buff_no[dev] = -1;
+ }
+
+ audio_mode[dev] = AM_WRITE;
+
if (!count) /* Flush output */
{
if (wr_buff_no[dev] >= 0)
@@ -136,15 +166,25 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+ if (!dsp_devs[dev]->copy_from_user)
+ { /* No device specific copy routine */
+ COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+ }
+ else
+ dsp_devs[dev]->copy_from_user (dev,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
+
/* Insert local processing here */
+ if (dev_type == SND_DEV_AUDIO)
+ {
#ifdef linux
- /* This just allows interrupts while the conversion is running */
- __asm__ ("sti");
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
#endif
- translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
c -= l;
p += l;
@@ -169,11 +209,24 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
int c, p, l;
char *dmabuf;
int buff_no;
+ int dev_type = dev & 0x0f;
dev = dev >> 4;
p = 0;
c = count;
+ if (audio_mode[dev] == AM_WRITE)
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ }
+
+ audio_mode[dev] = AM_READ;
+
while (c)
{
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
@@ -183,12 +236,16 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
l = c;
/* Insert any local processing here. */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
#ifdef linux
- /* This just allows interrupts while the conversion is running */
- __asm__ ("sti");
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
#endif
- translate_bytes (dsp_ulaw, dmabuf, l);
+ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
COPY_TO_USER (buf, p, dmabuf, l);
@@ -205,6 +262,8 @@ int
audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
{
+ int dev_type = dev & 0x0f;
+
dev = dev >> 4;
switch (cmd)
@@ -235,11 +294,10 @@ audio_ioctl (int dev, struct fileinfo *file,
break;
default:
-#if 1
- return RET_ERROR (EIO);
-#else
+ if (dev_type == SND_DEV_AUDIO)
+ return RET_ERROR (EIO);
+
return DMAbuf_ioctl (dev, cmd, arg, 0);
-#endif
}
}
@@ -266,14 +324,14 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
int
audio_open (int dev, struct fileinfo *file)
- {
- return RET_ERROR (ENXIO);
- }
+{
+ return RET_ERROR (ENXIO);
+}
void
audio_release (int dev, struct fileinfo *file)
- {
- };
+{
+};
int
audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
diff --git a/sys/i386/isa/sound/debug.h b/sys/i386/isa/sound/debug.h
deleted file mode 100644
index 79b4acdeba8f..000000000000
--- a/sys/i386/isa/sound/debug.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Kernel driver debugging stuff - cmetz@thor.tjhsst.edu */
-
-#ifndef _DEBUG_H_
-#define _DEBUG_H_
-
-#if defined (DEBUG_ME) && !defined(HALT_DEBUGGING)
-
-#define DEB(X) printk("%s %s: ", __FILE__, __FUNCTION__); X
-#define DEB1(X) printk("%s %s: ", __FILE__, __FUNCTION__); X
-#define RETURN_HEX(X, Y) { Y _foo; _foo = X; printk("%s %s: 0x%x\n", __FILE__, __FUNCTION__, ((int)_foo)); return(_foo); }
-#define RETURN_DEC(X, Y) { Y _foo; _foo = X; printk("%s %s: %d\n", __FILE__, __FUNCTION__, ((int)_foo)); return(_foo); }
-#define RETURN_PTR(X, Y) { Y _foo; _foo = X; printk("%s %s: 0x%08x\n", __FILE__, __FUNCTION__, ((void *)_foo)); return(_foo); }
-#define RETURN_ERR(X) { int _foo; _foo = X; printk("%s %s: ", __FILE__, __FUNCTION__); switch(_foo) { case 0: printk("No error"); break; case -ENODEV: printk("ENODEV"); break; case -EBUSY: printk("EBUSY"); break; default: printk("Error %d", _foo); } printk(".\n"); return(_foo); }
-#define DEB_OUTB OUTB
-#define DEB_INB INB
-
-#else
-
-#define DEB(X)
-#define DEB1(X)
-#define RETURN_HEX(X, Y) return(X)
-#define RETURN_DEC(X, Y) return(X)
-#define RETURN_PTR(X, Y) return(X)
-#define RETURN_ERR(X) return(X)
-#define DEB_OUTB OUTB
-#define DEB_INB INB
-
-#endif
-#endif
diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c
index 7eabad4ab8a0..7f7cae11d02e 100644
--- a/sys/i386/isa/sound/dev_table.c
+++ b/sys/i386/isa/sound/dev_table.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/dev_table.c
- *
+ * sound/dev_table.c
+ *
* Device call tables.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#define _DEV_TABLE_C_
@@ -38,21 +38,24 @@ sndtable_init (long mem_start)
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
for (i = 0; i < (n - 1); i++)
- if (supported_drivers[i].probe (&supported_drivers[i].config))
- {
+ if (supported_drivers[i].enabled)
+ if (supported_drivers[i].probe (&supported_drivers[i].config))
+ {
#ifndef SHORT_BANNERS
- printk ("snd%d",
- supported_drivers[i].card_type);
+ printk ("snd%d",
+ supported_drivers[i].card_type);
#endif
- mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+ mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
#ifndef SHORT_BANNERS
- printk (" at 0x%03x irq %d drq %d\n",
- supported_drivers[i].config.io_base,
- supported_drivers[i].config.irq,
- supported_drivers[i].config.dma);
+ printk (" at 0x%x irq %d drq %d\n",
+ supported_drivers[i].config.io_base,
+ supported_drivers[i].config.irq,
+ supported_drivers[i].config.dma);
#endif
- }
+ }
+ else
+ supported_drivers[i].enabled = 0; /* Mark as not detected */
return mem_start;
}
@@ -66,7 +69,15 @@ sndtable_probe (int unit, struct address_info *hw_config)
for (i = 0; i < (n - 1); i++)
if (supported_drivers[i].card_type == unit)
- return supported_drivers[i].probe (hw_config);
+ {
+ supported_drivers[i].config.io_base = hw_config->io_base;
+ supported_drivers[i].config.irq = hw_config->irq;
+ supported_drivers[i].config.dma = hw_config->dma;
+ if (supported_drivers[i].probe (hw_config))
+ return 1;
+ supported_drivers[i].enabled = 0; /* Mark as not detected */
+ return 0;
+ }
return FALSE;
}
@@ -86,6 +97,10 @@ sndtable_init_card (int unit, struct address_info *hw_config)
for (i = 0; i < (n - 1); i++)
if (supported_drivers[i].card_type == unit)
{
+ supported_drivers[i].config.io_base = hw_config->io_base;
+ supported_drivers[i].config.irq = hw_config->irq;
+ supported_drivers[i].config.dma = hw_config->dma;
+
if (supported_drivers[i].attach (0, hw_config) != 0)
panic ("snd#: Invalid memory allocation\n");
return TRUE;
@@ -100,4 +115,103 @@ sndtable_get_cardcount (void)
return num_dspdevs + num_mixers + num_synths + num_midis;
}
+#ifdef linux
+void
+sound_setup (char *str, int *ints)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ /*
+ * First disable all drivers
+ */
+
+ for (i = 0; i < n; i++)
+ supported_drivers[i].enabled = 0;
+
+ if (ints[0] == 0 || ints[1] == 0)
+ return;
+ /*
+ * Then enable them one by time
+ */
+
+ for (i = 1; i <= ints[0]; i++)
+ {
+ int card_type, ioaddr, irq, dma, ptr, j;
+ unsigned int val;
+
+ val = (unsigned int) ints[i];
+
+ card_type = (val & 0x0ff00000) >> 20;
+
+ if (card_type > 127)
+ {
+ /* Add any future extensions here */
+ return;
+ }
+
+ ioaddr = (val & 0x000fff00) >> 8;
+ irq = (val & 0x000000f0) >> 4;
+ dma = (val & 0x0000000f);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ printk ("Sound: Invalid setup parameter 0x%08x\n", val);
+ else
+ {
+ supported_drivers[ptr].enabled = 1;
+ supported_drivers[ptr].config.io_base = ioaddr;
+ supported_drivers[ptr].config.irq = irq;
+ supported_drivers[ptr].config.dma = dma;
+ }
+ }
+}
+
+#else
+void
+sound_chconf (int card_type, int ioaddr, int irq, int dma)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ int ptr, j;
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr != -1)
+ {
+ supported_drivers[ptr].enabled = 1;
+ if (ioaddr)
+ supported_drivers[ptr].config.io_base = ioaddr;
+ if (irq)
+ supported_drivers[ptr].config.irq = irq;
+ if (dma)
+ supported_drivers[ptr].config.dma = dma;
+ }
+}
+
+#endif
+
+struct address_info *
+sound_getconf (int card_type)
+{
+ int j, ptr;
+ int n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ return (struct address_info *) NULL;
+
+ return &supported_drivers[ptr].config;
+}
+
#endif
diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h
index 9bfd7847ecd2..4b656ba39c2b 100644
--- a/sys/i386/isa/sound/dev_table.h
+++ b/sys/i386/isa/sound/dev_table.h
@@ -46,6 +46,7 @@ struct card_info {
long (*attach) (long mem_start, struct address_info *hw_config);
int (*probe) (struct address_info *hw_config);
struct address_info config;
+ int enabled;
};
/** UWM -- new MIDI structure here.. **/
@@ -57,10 +58,15 @@ struct generic_midi_info{
struct audio_operations {
char name[32];
+ int flags;
+#define NOTHING_SPECIAL 0
+#define NEEDS_RESTART 1
int (*open) (int dev, int mode);
void (*close) (int dev);
- void (*output_block) (int dev, unsigned long buf, int count, int intrflag);
- void (*start_input) (int dev, unsigned long buf, int count, int intrflag);
+ void (*output_block) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
+ void (*start_input) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
int (*prepare_for_input) (int dev, int bufsize, int nbufs);
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
@@ -93,6 +99,7 @@ struct synth_operations {
void (*aftertouch) (int dev, int voice, int pressure);
void (*controller) (int dev, int voice, int ctrl_num, int value);
void (*panning) (int dev, int voice, int value);
+ void (*volume_method) (int dev, int mode);
int (*pmgr_interface) (int dev, struct patmgr_info *info);
};
@@ -159,31 +166,42 @@ struct generic_midi_operations {
*/
struct card_info supported_drivers[] = {
-#ifndef EXCLUDE_MPU401
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
{SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401,
- {MPU_BASE, MPU_IRQ, 0}},
-#endif
-
-#ifndef EXCLUDE_GUS
- {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
- {GUS_BASE, GUS_IRQ, GUS_DMA}},
+ {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_PAS
{SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas,
- {PAS_BASE, PAS_IRQ, PAS_DMA}},
+ {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_SB
{SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb,
- {SBC_BASE, SBC_IRQ, SBC_DMA}},
+ {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+#ifndef EXCLUDE_AUDIO
+ {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect,
+ {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+#endif
+#ifndef EXCLUDE_MIDI
+ {SNDCARD_SB16MIDI,"SB16 MPU-401", attach_sb16midi, probe_sb16midi,
+ {SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#endif
+
+#ifndef EXCLUDE_GUS
+ {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
+ {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_YM3812
{SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib,
- {FM_MONO, 0, 0}},
+ {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
#endif
- {0, "*?*", NULL}
+ {0, "*?*", NULL, 0}
};
int num_sound_drivers =
@@ -220,6 +238,8 @@ struct generic_midi_operations {
long sndtable_init(long mem_start);
int sndtable_get_cardcount (void);
long CMIDI_init(long mem_start); /* */
+struct address_info *sound_getconf(int card_type);
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
#endif
#endif
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
index ace02d149a41..851a70a16b1b 100644
--- a/sys/i386/isa/sound/dmabuf.c
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/dmabuf.c
- *
+ * sound/dmabuf.c
+ *
* The DMA buffer manager for digitized voice applications
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -35,7 +35,7 @@
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
-#define MAX_SUB_BUFFERS 16
+#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR)
/*
* The DSP channel can be used either for input or output. Variable
@@ -48,7 +48,6 @@
#define DMODE_NONE 0
#define DMODE_OUTPUT 1
#define DMODE_INPUT 2
-#define DMODE_INIT 3
DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
@@ -58,22 +57,6 @@ static int dma_mode[MAX_DSP_DEV] =
static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
{0};
-#ifdef ISC
-/* I don't like this. */
-#undef INTERRUPTIBLE_SLEEP_ON
-#define INTERRUPTIBLE_SLEEP_ON(A,F) { \
- A = F = 1; \
- if (sleep(&(A), (PZERO + 5) | PCATCH)) { \
- A = F = 0; \
- dmabuf_interrupted[dev] = 1; \
- dev_busy[dev] = 0; \
- dma_reset(dev); \
- dmabuf_interrupted[dev] = 0; \
- /* longjmp(u.u_qsav, 1); Where it goes??? */ \
- } \
- }
-#endif
-
/*
* Pointers to raw buffers
*/
@@ -89,7 +72,10 @@ int snd_raw_count[MAX_DSP_DEV];
*/
static int dev_busy[MAX_DSP_DEV];
+static int dev_needs_restart[MAX_DSP_DEV];
+static int dev_modes[MAX_DSP_DEV];
static int dev_active[MAX_DSP_DEV];
+static int dev_started[MAX_DSP_DEV];
static int dev_qlen[MAX_DSP_DEV];
static int dev_qhead[MAX_DSP_DEV];
static int dev_qtail[MAX_DSP_DEV];
@@ -102,8 +88,10 @@ static int bufferalloc_done[MAX_DSP_DEV] =
*/
static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >=
- * sound_buffcounts[dev] */
+
+ * sound_buffcounts[dev] */
static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static int dev_subdivision[MAX_DSP_DEV];
static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
{
@@ -117,8 +105,8 @@ reorganize_buffers (int dev)
* This routine breaks the physical device buffers to logical ones.
*/
- unsigned long i, p, n;
- unsigned long sr, nc, sz, bsz;
+ unsigned i, p, n;
+ unsigned sr, nc, sz, bsz;
sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
@@ -148,6 +136,17 @@ reorganize_buffers (int dev)
if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
bsz >>= 1; /* Need at least 2 buffers */
+ if (dev_subdivision[dev] == 0)
+ dev_subdivision[dev] = 1; /* Default value */
+
+ bsz /= dev_subdivision[dev]; /* Use smaller buffers */
+
+ if (bsz == 0)
+ bsz = 4096; /* Just a sanity check */
+
+ while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
+ bsz <<= 1; /* Too much buffers */
+
dev_buffsize[dev] = bsz;
n = 0;
@@ -178,6 +177,21 @@ reorganize_buffers (int dev)
bufferalloc_done[dev] = 1;
}
+static void
+dma_init_buffers (int dev)
+{
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+ dev_underrun[dev] = 0;
+
+ dev_busy[dev] = 1;
+
+ bufferalloc_done[dev] = 0;
+
+ dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
+ dev_needs_restart[dev] = dev_started[dev] = 0;
+ dma_mode[dev] = DMODE_NONE;
+}
+
int
DMAbuf_open (int dev, int mode)
{
@@ -198,20 +212,23 @@ DMAbuf_open (int dev, int mode)
return RET_ERROR (ENXIO);
}
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_malloc (dev);
+#endif
+
if (snd_raw_buf[dev][0] == NULL)
return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
return retval;
- dev_underrun[dev] = 0;
-
- dev_busy[dev] = 1;
+ dev_modes[dev] = mode;
+ dev_subdivision[dev] = 0;
- reorganize_buffers (dev);
- bufferalloc_done[dev] = 0;
-
- dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
+ dma_init_buffers (dev);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
return 0;
}
@@ -219,35 +236,37 @@ DMAbuf_open (int dev, int mode)
static void
dma_reset (int dev)
{
+ int retval;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
dsp_devs[dev]->reset (dev);
+ dsp_devs[dev]->close (dev);
- dev_qlen[dev] = 0;
- dev_qhead[dev] = 0;
- dev_qtail[dev] = 0;
- dev_active[dev] = 0;
+ if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
+ printk ("Sound: Reset failed - Can't reopen device\n");
+ RESTORE_INTR (flags);
+
+ dma_init_buffers (dev);
+ reorganize_buffers (dev);
}
static int
dma_sync (int dev)
{
unsigned long flags;
- unsigned long time;
- int timed_out;
if (dma_mode[dev] == DMODE_OUTPUT)
{
DISABLE_INTR (flags);
- timed_out = 0;
- time = GET_TIME ();
-
- while ((!(PROCESS_ABORTING || dmabuf_interrupted[dev]) && !timed_out)
+ while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev]))
&& dev_qlen[dev])
{
- REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
- if ((GET_TIME () - time) > (10 * HZ))
- timed_out = 1;
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ return dev_qlen[dev];
}
RESTORE_INTR (flags);
@@ -259,11 +278,11 @@ dma_sync (int dev)
DISABLE_INTR (flags);
if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */
{
- while (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
+ while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
&& !dsp_devs[dev]->has_output_drained (dev))
{
- REQUEST_TIMEOUT (HZ / 4, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
}
}
RESTORE_INTR (flags);
@@ -275,16 +294,20 @@ int
DMAbuf_release (int dev, int mode)
{
- if (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
+ if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
&& (dma_mode[dev] == DMODE_OUTPUT))
{
dma_sync (dev);
}
- dma_reset (dev);
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_free (dev);
+#endif
- if (!dev_active[dev])
- dsp_devs[dev]->close (dev);
+ dsp_devs[dev]->reset (dev);
+
+ dsp_devs[dev]->close (dev);
dma_mode[dev] = DMODE_NONE;
dev_busy[dev] = 0;
@@ -296,40 +319,65 @@ int
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
{
unsigned long flags;
+ int err = EIO;
- if (!bufferalloc_done[dev])
- reorganize_buffers (dev);
-
- if (!dma_mode[dev])
+ DISABLE_INTR (flags);
+ if (!dev_qlen[dev])
{
- int err;
+ if (dev_needs_restart[dev])
+ {
+ dma_reset (dev);
+ dev_needs_restart[dev] = 0;
+ }
- if ((err = dsp_devs[dev]->prepare_for_input (dev,
- dev_buffsize[dev], dev_nbufs[dev])) < 0)
- return err;
- dma_mode[dev] = DMODE_INPUT;
- }
+ if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
- if (dma_mode[dev] != DMODE_INPUT)
- return RET_ERROR (EBUSY); /* Can't change mode on fly */
+ if (!bufferalloc_done[dev])
+ reorganize_buffers (dev);
+
+ if (!dma_mode[dev])
+ {
+ int err;
+
+ if ((err = dsp_devs[dev]->prepare_for_input (dev,
+ dev_buffsize[dev], dev_nbufs[dev])) < 0)
+ {
+ RESTORE_INTR (flags);
+ return err;
+ }
+ dma_mode[dev] = DMODE_INPUT;
+ }
- DISABLE_INTR (flags);
- if (!dev_qlen[dev])
- {
if (!dev_active[dev])
{
- dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 0);
+ dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
+ dev_buffsize[dev], 0,
+ !sound_dma_automode[dev] ||
+ !dev_started[dev]);
dev_active[dev] = 1;
+ dev_started[dev] = 1;
}
/* Wait for the next block */
- REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else
+ err = EINTR;
}
RESTORE_INTR (flags);
if (!dev_qlen[dev])
- return RET_ERROR (EINTR);
+ return RET_ERROR (err);
*buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];
*len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];
@@ -391,6 +439,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
case SNDCTL_DSP_SYNC:
dma_sync (dev);
+ dma_reset (dev);
return 0;
break;
@@ -401,10 +450,37 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return IOCTL_OUT (arg, dev_buffsize[dev]);
break;
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = IOCTL_IN (arg);
+
+ if (fact == 0)
+ {
+ fact = dev_subdivision[dev];
+ if (fact == 0)
+ fact = 1;
+ return IOCTL_OUT (arg, fact);
+ }
+
+ if (dev_subdivision[dev] != 0) /* Too late to change */
+ return RET_ERROR (EINVAL);
+
+ if (fact > MAX_REALTIME_FACTOR)
+ return RET_ERROR (EINVAL);
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return RET_ERROR (EINVAL);
+
+ dev_subdivision[dev] = fact;
+ return IOCTL_OUT (arg, fact);
+ }
+ break;
+
default:
return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
}
+ /* NOTREACHED */
return RET_ERROR (EIO);
}
@@ -412,6 +488,20 @@ int
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
{
unsigned long flags;
+ int err = EIO;
+
+ if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */
+ {
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
+ else if (dev_needs_restart[dev]) /* Restart buffering */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ }
+
+ dev_needs_restart[dev] = 0;
if (!bufferalloc_done[dev])
reorganize_buffers (dev);
@@ -426,10 +516,11 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
return err;
}
- if (dma_mode[dev] != DMODE_OUTPUT)
- return RET_ERROR (EBUSY); /* Can't change mode on fly */
DISABLE_INTR (flags);
+
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+
if (dev_qlen[dev] == dev_nbufs[dev])
{
if (!dev_active[dev])
@@ -440,14 +531,20 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
}
/* Wait for free space */
- REQUEST_TIMEOUT (60 * HZ, dev_sleeper[dev]); /* GUS requires up to 60
- * sec */
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ err = EINTR;
}
RESTORE_INTR (flags);
if (dev_qlen[dev] == dev_nbufs[dev])
- return RET_ERROR (EIO); /* We have got signal (?) */
+ return RET_ERROR (err); /* We have got signal (?) */
*buf = dev_buf[dev][dev_qtail[dev]];
*size = dev_buffsize[dev];
@@ -466,12 +563,18 @@ DMAbuf_start_output (int dev, int buff_no, int l)
dev_counts[dev][dev_qtail[dev]] = l;
+ dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
+ (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
+
dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
if (!dev_active[dev])
{
dev_active[dev] = 1;
- dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 0);
+ dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
+ dev_counts[dev][dev_qhead[dev]], 0,
+ !sound_dma_automode[dev] || !dev_started[dev]);
+ dev_started[dev] = 1;
}
return 0;
@@ -504,27 +607,33 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
set_dma_count (chan, sound_buffsizes[dev]);
enable_dma (chan);
RESTORE_INTR (flags);
-#else
+#else /* linux */
#ifdef __386BSD__
printk ("sound: Invalid DMA mode for device %d\n", dev);
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)snd_raw_buf_phys[dev][0],
- (unsigned)sound_buffsizes[dev],
- (unsigned)chan);
-#else
-#ifdef ISC
+ sound_buffsizes[dev],
+ chan);
+#else /* __386BSD__ */
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+#ifndef DMAMODE_AUTO
printk ("sound: Invalid DMA mode for device %d\n", dev);
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) | DMAMODE_AUTO,
- snd_raw_buf_phys[dev][0], count - 1);
+#endif /* DMAMODE_AUTO */
+ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
+#ifdef DMAMODE_AUTO
+ | DMAMODE_AUTO
+#endif /* DMAMODE_AUTO */
+ ,
+ snd_raw_buf_phys[dev][0], count);
dma_enable (chan);
-#else
-# error This routine is not valid for this OS.
-#endif
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
-#endif
+#endif /* linux */
}
else
{
@@ -537,24 +646,24 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
set_dma_count (chan, count);
enable_dma (chan);
RESTORE_INTR (flags);
-#else
+#else /* linux */
#ifdef __386BSD__
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)physaddr,
count,
chan);
-#else
+#else /* __386BSD__ */
-#ifdef ISC
+#if defined(ISC) || defined(SCO) || defined(SVR42)
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count - 1);
+ physaddr, count);
dma_enable (chan);
-#else
-# error This routine is not valid for this OS.
-#endif /* !ISC */
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
-#endif
+#endif /* linux */
}
return count;
@@ -584,37 +693,33 @@ DMAbuf_init (long mem_start)
}
void
-DMAbuf_outputintr (int dev)
+DMAbuf_outputintr (int dev, int underrun_flag)
{
unsigned long flags;
- dev_active[dev] = 0;
dev_qlen[dev]--;
dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+ dev_active[dev] = 0;
if (dev_qlen[dev])
{
- dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 1);
+ dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
+ dev_counts[dev][dev_qhead[dev]], 1,
+ !sound_dma_automode[dev]);
dev_active[dev] = 1;
}
- else
+ else if (underrun_flag)
{
- if (dev_busy[dev])
- {
- dev_underrun[dev]++;
- dsp_devs[dev]->halt_xfer (dev);
- }
- else
- { /* Device has been closed */
- dsp_devs[dev]->close (dev);
- }
+ dev_underrun[dev]++;
+ dsp_devs[dev]->halt_xfer (dev);
+ dev_needs_restart[dev] = (sound_dma_automode[dev] ||
+ dsp_devs[dev]->flags & NEEDS_RESTART);
}
DISABLE_INTR (flags);
- if (dev_sleep_flag[dev])
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- dev_sleep_flag[dev] = 0;
- WAKE_UP (dev_sleeper[dev]);
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
}
@@ -624,30 +729,33 @@ DMAbuf_inputintr (int dev)
{
unsigned long flags;
- dev_active[dev] = 0;
if (!dev_busy[dev])
{
dsp_devs[dev]->close (dev);
}
else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
{
+ printk ("Sound: Recording overrun\n");
dev_underrun[dev]++;
dsp_devs[dev]->halt_xfer (dev);
+ dev_active[dev] = 0;
+ dev_needs_restart[dev] = sound_dma_automode[dev];
}
else
{
dev_qlen[dev]++;
dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
- dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 1);
+ dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
+ dev_buffsize[dev], 1,
+ !sound_dma_automode[dev]);
dev_active[dev] = 1;
}
DISABLE_INTR (flags);
- if (dev_sleep_flag[dev])
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- dev_sleep_flag[dev] = 0;
- WAKE_UP (dev_sleeper[dev]);
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
}
@@ -691,13 +799,13 @@ DMAbuf_reset_dma (int chan)
/*
* The sound_mem_init() is called by mem_init() immediately after mem_map is
* initialized and before free_page_list is created.
- *
+ *
* This routine allocates DMA buffers at the end of available physical memory (
* <16M) and marks pages reserved at mem_map.
*/
#else
-/* Stub versions if audio services not included */
+/* Stub versions if audio services not included */
int
DMAbuf_open (int dev, int mode)
@@ -784,7 +892,7 @@ DMAbuf_inputintr (int dev)
}
void
-DMAbuf_outputintr (int dev)
+DMAbuf_outputintr (int dev, int underrun_flag)
{
return;
}
diff --git a/sys/i386/isa/sound/dsp.c b/sys/i386/isa/sound/dsp.c
deleted file mode 100644
index fca931afab3e..000000000000
--- a/sys/i386/isa/sound/dsp.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * linux/kernel/chr_drv/sound/dsp.c
- *
- * Device file manager for /dev/dsp
- *
- * Copyright by Hannu Savolainen 1993
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- */
-
-#include "sound_config.h"
-
-#ifdef CONFIGURE_SOUNDCARD
-
-#ifndef EXCLUDE_AUDIO
-
-#define ON 1
-#define OFF 0
-
-static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
- * incomplete output block */
-static int wr_buff_size[MAX_DSP_DEV], wr_buf_ptr[MAX_DSP_DEV];
-static char *wr_dma_buf[MAX_DSP_DEV];
-
-int
-dsp_open (int dev, struct fileinfo *file, int bits)
-{
- int mode;
- int ret;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- return ret;
-
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
- {
- dsp_release (dev, file);
- return RET_ERROR (ENXIO);
- }
-
- wr_buff_no[dev] = -1;
-
- return ret;
-}
-
-void
-dsp_release (int dev, struct fileinfo *file)
-{
- int mode;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
-
- DMAbuf_release (dev, mode);
-}
-
-
-int
-dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- int c, p, l;
- int err;
-
- dev = dev >> 4;
-
- p = 0;
- c = count;
-
- if (!count) /* Flush output */
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- }
-
- while (c)
- { /* Perform output blocking */
- if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */
- {
- if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
- &wr_buff_size[dev])) < 0)
- return wr_buff_no[dev];
- wr_buf_ptr[dev] = 0;
- }
-
- l = c;
- if (l > (wr_buff_size[dev] - wr_buf_ptr[dev]))
- l = (wr_buff_size[dev] - wr_buf_ptr[dev]);
-
- if (!dsp_devs[dev]->copy_from_user)
- { /* No device specific copy routine */
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buf_ptr[dev]], buf, p, l);
- }
- else
- dsp_devs[dev]->copy_from_user (dev,
- wr_dma_buf[dev], wr_buf_ptr[dev], buf, p, l);
-
- c -= l;
- p += l;
- wr_buf_ptr[dev] += l;
-
- if (wr_buf_ptr[dev] >= wr_buff_size[dev])
- {
- if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev])) < 0)
- return err;
-
- wr_buff_no[dev] = -1;
- }
-
- }
-
- return count;
-}
-
-
-int
-dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- int c, p, l;
- char *dmabuf;
- int buff_no;
-
- dev = dev >> 4;
- p = 0;
- c = count;
-
- while (c)
- {
- if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
- return buff_no;
-
- if (l > c)
- l = c;
-
- /* Insert any local processing here. */
-
- COPY_TO_USER (buf, 0, dmabuf, l);
-
- DMAbuf_rmchars (dev, buff_no, l);
-
- p += l;
- c -= l;
- }
-
- return count - c;
-}
-
-int
-dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
-
- dev = dev >> 4;
-
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- case SNDCTL_DSP_POST:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- break;
-
- case SNDCTL_DSP_RESET:
- wr_buff_no[dev] = -1;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- default:
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- }
-}
-
-long
-dsp_init (long mem_start)
-{
- return mem_start;
-}
-
-#else
-/* Stub version */
-int
-dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_open (int dev, struct fileinfo *file, int bits)
-{
- return RET_ERROR (ENXIO);
-}
-
-void
-dsp_release (int dev, struct fileinfo *file)
- {
- };
-int
-dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
-{
- return RET_ERROR (EIO);
-}
-
-long
-dsp_init (long mem_start)
-{
- return mem_start;
-}
-
-#endif
-
-#endif
diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c
index 414034deef6f..c7cfc0a7ab6c 100644
--- a/sys/i386/isa/sound/gus_card.c
+++ b/sys/i386/isa/sound/gus_card.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/gus_card.c
- *
+ * sound/gus_card.c
+ *
* Detection routine for the Gravis Ultrasound.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -37,76 +37,12 @@ void gusintr (int);
int gus_base, gus_irq, gus_dma;
-static int
-set_gus_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = gusintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("GUS: IRQ%d already in use\n", interrupt_level);
- }
-
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
-}
-
-int
-gus_set_midi_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = gus_midi_interrupt;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("GUS: IRQ%d already in use\n", interrupt_level);
- }
-
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
-}
-
long
attach_gus_card (long mem_start, struct address_info *hw_config)
{
int io_addr;
- set_gus_irq (hw_config->irq);
+ snd_set_irq_handler (hw_config->irq, gusintr);
if (gus_wave_detect (hw_config->io_base)) /* Try first the default */
{
@@ -127,7 +63,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
if (io_addr != hw_config->io_base) /* Already tested */
if (gus_wave_detect (io_addr))
{
- printk (" WARNING! GUS found at %03x, config was %03x ", io_addr, hw_config->io_base);
+ printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
#ifndef EXCLUDE_MIDI
mem_start = gus_midi_init (mem_start);
@@ -168,7 +104,10 @@ void
gusintr (int unit)
{
unsigned char src;
- unsigned long flags;
+
+#ifdef linux
+ sti ();
+#endif
while (1)
{
@@ -195,9 +134,7 @@ gusintr (int unit)
if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
{
- DISABLE_INTR (flags);
gus_voice_irq ();
- RESTORE_INTR (flags);
}
}
}
diff --git a/sys/i386/isa/sound/gus_hw.h b/sys/i386/isa/sound/gus_hw.h
index 48233e7e1e32..f97a0b8670e3 100644
--- a/sys/i386/isa/sound/gus_hw.h
+++ b/sys/i386/isa/sound/gus_hw.h
@@ -24,6 +24,8 @@
#define u_Command (gus_base + 0x103)
#define u_DataLo (gus_base + 0x104)
#define u_DataHi (gus_base + 0x105)
+#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
+#define u_MixSelect (gus_base + 0x506) /* registers. */
#define u_IrqStatus u_Status
# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
@@ -32,4 +34,17 @@
# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
+
+#define ICS2101 1
+# define ICS_MIXDEVS 6
+# define DEV_MIC 0
+# define DEV_LINE 1
+# define DEV_CD 2
+# define DEV_GF1 3
+# define DEV_UNUSED 4
+# define DEV_VOL 5
+
+# define CHN_LEFT 0
+# define CHN_RIGHT 1
+#define CS4231 2
#define u_DRAMIO (gus_base + 0x107)
diff --git a/sys/i386/isa/sound/gus_linearvol.h b/sys/i386/isa/sound/gus_linearvol.h
new file mode 100644
index 000000000000..7ad0c30d4fd9
--- /dev/null
+++ b/sys/i386/isa/sound/gus_linearvol.h
@@ -0,0 +1,18 @@
+static unsigned short gus_linearvol[128] = {
+ 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
+ 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
+ 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
+ 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
+ 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
+ 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
+ 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
+ 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
+ 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
+ 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
+ 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
+ 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
+ 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
+ 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
+ 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
+ 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
+};
diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c
index b5cd6844cd1d..935c5c90b324 100644
--- a/sys/i386/isa/sound/gus_midi.c
+++ b/sys/i386/isa/sound/gus_midi.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/gus2_midi.c
- *
+ * sound/gus2_midi.c
+ *
* The low level driver for the GUS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -215,7 +215,7 @@ gus_midi_buffer_status (int dev)
static struct midi_operations gus_midi_operations =
{
- {"Gravis UltraSound", 0},
+ {"Gravis UltraSound", 0, 0, SNDCARD_GUS},
gus_midi_open,
gus_midi_close,
gus_midi_ioctl,
diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c
index b3f1e84060ad..055a1170e9fb 100644
--- a/sys/i386/isa/sound/gus_vol.c
+++ b/sys/i386/isa/sound/gus_vol.c
@@ -1,10 +1,11 @@
/*
* gus_vol.c - Compute volume for GUS.
- *
+ *
* Greg Lee 1993.
*/
#include "sound_config.h"
#ifndef EXCLUDE_GUS
+#include "gus_linearvol.h"
#define GUS_VOLUME gus_wave_volume
@@ -20,7 +21,7 @@ extern int gus_wave_volume;
* to expression controller messages, if they were found to be used for
* dynamic volume adjustments, so here, main volume can be assumed to be
* constant throughout a song.)
- *
+ *
* Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
* we can give a big boost to very weak voices like nylon guitar and the
* basses. The normal value is 64. Strings are assigned lower values.
@@ -38,24 +39,37 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
x = 256 + 6 * (voicev - 64);
- /* Boost expression by voice volume above neutral. */
+ /*
+ * Boost expression by voice volume above neutral.
+ */
if (voicev > 65)
xpn += voicev - 64;
xpn += (voicev - 64) / 2;
- /* Combine multiplicative and level components. */
+ /*
+ * Combine multiplicative and level components.
+ */
x = vel * xpn * 6 + (voicev / 4) * x;
#ifdef GUS_VOLUME
/*
* Further adjustment by installation-specific master volume control
- * (default 50).
+ * (default 60).
*/
x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
#endif
- if (x < (1 << 11))
- return (11 << 8);
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ /*
+ * Experimental support for the channel main volume
+ */
+
+ mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+ x = (x * mainv * mainv) / 16384;
+#endif
+
+ if (x < 2)
+ return (0);
else if (x >= 65535)
return ((15 << 8) | 255);
@@ -82,7 +96,9 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
m = x - (1 << i);
- /* Adjust mantissa to 8 bits. */
+ /*
+ * Adjust mantissa to 8 bits.
+ */
if (m > 0)
{
if (i > 8)
@@ -91,11 +107,41 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
m <<= 8 - i;
}
- /* low volumes give occasional sour notes */
- if (i < 11)
- return (11 << 8);
-
return ((i << 8) + m);
}
+/*
+ * Volume-values are interpreted as linear values. Volume is based on the
+ * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
+ * and the volume set by the mixer-device (default 60%).
+ */
+
+unsigned short
+gus_linear_vol (int vol, int mainvol)
+{
+ int mixer_mainvol;
+
+ if (vol <= 0)
+ vol = 0;
+ else if (vol >= 127)
+ vol = 127;
+
+#ifdef GUS_VOLUME
+ mixer_mainvol = GUS_VOLUME;
+#else
+ mixer_mainvol = 100;
+#endif
+
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ if (mainvol <= 0)
+ mainvol = 0;
+ else if (mainvol >= 127)
+ mainvol = 127;
+#else
+ mainvol = 128;
+#endif
+
+ return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
+}
+
#endif
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index deb3a1525991..9f6442e0fcff 100644
--- a/sys/i386/isa/sound/gus_wave.c
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/gus_wave.c
- *
+ * sound/gus_wave.c
+ *
* Driver for the Gravis UltraSound wave table synth.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -13,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -25,18 +24,20 @@
* 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.
- *
+ *
*/
-/* #define GUS_LINEAR_VOLUME */
-
#include "sound_config.h"
+#ifdef __FreeBSD__
#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
#include "gus_hw.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
-#define MAX_SAMPLE 256
+#define MAX_SAMPLE 128
#define MAX_PATCH 256
struct voice_info
@@ -57,6 +58,7 @@ struct voice_info
int volume_irq_mode, volume_irq_parm;
#define VMODE_HALT 1
#define VMODE_ENVELOPE 2
+#define VMODE_START_NOTE 3
int env_phase;
unsigned char env_rate[6];
@@ -67,6 +69,11 @@ struct voice_info
*/
int main_vol, expression_vol, patch_vol;
+ /* Variables for "Ultraclick" removal */
+ int dev_pending, note_pending, volume_pending, sample_pending;
+ char kill_pending;
+ long offset_pending;
+
};
extern int gus_base;
@@ -77,24 +84,30 @@ extern int snd_raw_count[MAX_DSP_DEV];
static long gus_mem_size = 0;
static long free_mem_ptr = 0;
static int gus_busy = 0;
-static int nr_voices = 0; /* Number of currently allowed voices */
+static int nr_voices = 0;
static int gus_devnum = 0;
static int volume_base, volume_scale, volume_method;
+static int gus_line_vol = 100, gus_mic_vol = 0;
+static int gus_recmask = SOUND_MASK_MIC;
+static int recording_active = 0;
-#define VOL_METHOD_ADAGIO 1
-int gus_wave_volume = 60; /* Master wolume for wave (0 to 100) */
+int gus_wave_volume = 60;
+int gus_pcm_volume = 80;
static unsigned char mix_image = 0x00;
/*
- * Current version of this_one driver doesn't allow synth and PCM functions
+ * Current version of this driver doesn't allow synth and PCM functions
* at the same time. The active_device specifies the active driver
*/
static int active_device = 0;
-#define GUS_DEV_WAVE 1 /* Wave table synth */
-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer the second
- * chn */
+#define GUS_DEV_WAVE 1 /*
+ * * * Wave table synth */
+#define GUS_DEV_PCM_DONE 2 /*
+ * * * PCM device, transfer done */
+#define GUS_DEV_PCM_CONTINUE 3 /*
+ * * * PCM device, transfer the
+ * second * * * chn */
static int gus_sampling_speed;
static int gus_sampling_channels;
@@ -105,13 +118,34 @@ DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
/*
* Variables and buffers for PCM output
*/
-#define MAX_PCM_BUFFERS 32 /* Don't change */
-static int pcm_bsize, /* Current blocksize */
- pcm_nblk, /* Current # of blocks */
- pcm_banksize; /* # bytes allocated for channels */
-static int pcm_datasize[MAX_PCM_BUFFERS]; /* Actual # of bytes in blk */
-static volatile int pcm_head, pcm_tail, pcm_qlen; /* DRAM queue */
+#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /*
+ * * * Don't
+ * * * change
+ *
+ */
+
+static int pcm_bsize, /*
+ * Current blocksize
+ */
+ pcm_nblk, /*
+ * Current # of blocks
+ */
+ pcm_banksize; /*
+
+
+ * * * * # bytes allocated for channels */
+static int pcm_datasize[MAX_PCM_BUFFERS]; /*
+
+
+ * * * * Actual # of bytes
+ * in blk * */
+static volatile int pcm_head, pcm_tail, pcm_qlen; /*
+
+
+ * * * * DRAM queue
+ * */
static volatile int pcm_active;
+static int pcm_opened = 0;
static int pcm_current_dev;
static int pcm_current_block;
static unsigned long pcm_current_buf;
@@ -122,28 +156,66 @@ struct voice_info voices[32];
static int freq_div_table[] =
{
- 44100, /* 14 */
- 41160, /* 15 */
- 38587, /* 16 */
- 36317, /* 17 */
- 34300, /* 18 */
- 32494, /* 19 */
- 30870, /* 20 */
- 29400, /* 21 */
- 28063, /* 22 */
- 26843, /* 23 */
- 25725, /* 24 */
- 24696, /* 25 */
- 23746, /* 26 */
- 22866, /* 27 */
- 22050, /* 28 */
- 21289, /* 29 */
- 20580, /* 30 */
- 19916, /* 31 */
- 19293 /* 32 */
+ 44100, /*
+ * 14
+ */
+ 41160, /*
+ * 15
+ */
+ 38587, /*
+ * 16
+ */
+ 36317, /*
+ * 17
+ */
+ 34300, /*
+ * 18
+ */
+ 32494, /*
+ * 19
+ */
+ 30870, /*
+ * 20
+ */
+ 29400, /*
+ * 21
+ */
+ 28063, /*
+ * 22
+ */
+ 26843, /*
+ * 23
+ */
+ 25725, /*
+ * 24
+ */
+ 24696, /*
+ * 25
+ */
+ 23746, /*
+ * 26
+ */
+ 22866, /*
+ * 27
+ */
+ 22050, /*
+ * 28
+ */
+ 21289, /*
+ * 29
+ */
+ 20580, /*
+ * 30
+ */
+ 19916, /*
+ * 31
+ */
+ 19293 /*
+ * 32
+ */
};
-static struct patch_info samples[MAX_SAMPLE + 1];
+static struct patch_info *samples;
static long sample_ptrs[MAX_SAMPLE + 1];
static int sample_map[32];
static int free_sample;
@@ -158,10 +230,15 @@ static struct synth_info gus_info =
static void gus_poke (long addr, unsigned char data);
static void compute_and_set_volume (int voice, int volume, int ramp_time);
extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
+extern unsigned short gus_linear_vol (int vol, int mainvol);
static void compute_volume (int voice, int volume);
+static void do_volume_irq (int voice);
+static void set_input_volumes (void);
-#define INSTANT_RAMP -1 /* Dont use ramping */
-#define FAST_RAMP 0 /* Fastest possible ramp */
+#define INSTANT_RAMP -1 /*
+ * * * Dont use ramping */
+#define FAST_RAMP 0 /*
+ * * * Fastest possible ramp */
static void
reset_sample_memory (void)
@@ -175,7 +252,9 @@ reset_sample_memory (void)
for (i = 0; i < 32; i++)
patch_map[i] = -1;
- gus_poke (0, 0); /* Put silence here */
+ gus_poke (0, 0); /*
+ * Put silence here
+ */
gus_poke (1, 0);
free_mem_ptr = 2;
@@ -230,14 +309,14 @@ gus_peek (long addr)
}
void
-gus_write8 (int reg, unsigned char data)
+gus_write8 (int reg, unsigned int data)
{
unsigned long flags;
DISABLE_INTR (flags);
OUTB (reg, u_Command);
- OUTB (data, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -271,7 +350,7 @@ gus_look8 (int reg)
}
void
-gus_write16 (int reg, unsigned short data)
+gus_write16 (int reg, unsigned int data)
{
unsigned long flags;
@@ -279,8 +358,8 @@ gus_write16 (int reg, unsigned short data)
OUTB (reg, u_Command);
- OUTB (data & 0xff, u_DataLo);
- OUTB ((data >> 8) & 0xff, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataLo);
+ OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -322,6 +401,10 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+ /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+ gus_delay ();
+ gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
+ gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
}
static void
@@ -347,11 +430,11 @@ gus_select_max_voices (int nvoices)
}
static void
-gus_voice_on (unsigned char mode)
+gus_voice_on (unsigned int mode)
{
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
gus_delay ();
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
}
static void
@@ -361,10 +444,18 @@ gus_voice_off (void)
}
static void
-gus_voice_mode (unsigned char mode)
-{
- gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * voice */
+gus_voice_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * voice
+ */
gus_delay ();
gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
}
@@ -382,44 +473,56 @@ gus_voice_freq (unsigned long freq)
}
static void
-gus_voice_volume (unsigned short vol)
+gus_voice_volume (unsigned int vol)
{
- gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16 (0x09, vol << 4);
+ gus_write8 (0x0d, 0x03); /*
+ * Stop ramp before setting volume
+ */
+ gus_write16 (0x09, (unsigned short) (vol << 4));
}
static void
-gus_voice_balance (unsigned char balance)
+gus_voice_balance (unsigned int balance)
{
- gus_write8 (0x0c, balance);
+ gus_write8 (0x0c, (unsigned char) (balance & 0xff));
}
static void
-gus_ramp_range (unsigned short low, unsigned short high)
+gus_ramp_range (unsigned int low, unsigned int high)
{
- gus_write8 (0x07, (low >> 4) & 0xff);
- gus_write8 (0x08, (high >> 4) & 0xff);
+ gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
+ gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
}
static void
-gus_ramp_rate (unsigned char scale, unsigned char rate)
+gus_ramp_rate (unsigned int scale, unsigned int rate)
{
- gus_write8 (0x06, ((scale & 0x03) << 6) | (rate & 0x3f));
+ gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
}
static void
-gus_rampon (unsigned char mode)
+gus_rampon (unsigned int m)
{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
gus_write8 (0x0d, mode & 0xfc);
gus_delay ();
gus_write8 (0x0d, mode & 0xfc);
}
static void
-gus_ramp_mode (unsigned char mode)
-{
- gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * ramping */
+gus_ramp_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * ramping
+ */
gus_delay ();
gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
}
@@ -431,6 +534,20 @@ gus_rampoff (void)
}
static void
+gus_set_voice_pos (int voice, long position)
+{
+ int sample_no;
+
+ if ((sample_no = sample_map[voice]) != -1)
+ if (position < samples[sample_no].len)
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].offset_pending = position;
+ else
+ gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
+ samples[sample_no].mode & WAVE_16_BITS);
+}
+
+static void
gus_voice_init (int voice)
{
unsigned long flags;
@@ -438,11 +555,22 @@ gus_voice_init (int voice)
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_volume (0);
- gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */
- gus_write8 (0x00, 0x03); /* Voice off */
- gus_write8 (0x0d, 0x03); /* Ramping off */
+ gus_write_addr (0x0a, 0, 0); /*
+ * Set current position to 0
+ */
+ gus_write8 (0x00, 0x03); /*
+ * Voice off
+ */
+ gus_write8 (0x0d, 0x03); /*
+ * Ramping off
+ */
RESTORE_INTR (flags);
+}
+
+static void
+gus_voice_init2 (int voice)
+{
voices[voice].panning = 0;
voices[voice].mode = 0;
voices[voice].orig_freq = 20000;
@@ -459,6 +587,7 @@ gus_voice_init (int voice)
voices[voice].main_vol = 127;
voices[voice].patch_vol = 127;
voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
}
static void
@@ -466,11 +595,17 @@ step_envelope (int voice)
{
unsigned vol, prev_vol, phase;
unsigned char rate;
+ long int flags;
if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
{
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
gus_rampoff ();
- return; /* Sustain */
+ RESTORE_INTR (flags);
+ return; /*
+ * Sustain
+ */
}
if (voices[voice].env_phase >= 5)
@@ -484,20 +619,31 @@ step_envelope (int voice)
}
prev_vol = voices[voice].current_volume;
- gus_voice_volume (prev_vol);
phase = ++voices[voice].env_phase;
-
compute_volume (voice, voices[voice].midi_volume);
-
vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
rate = voices[voice].env_rate[phase];
- gus_write8 (0x06, rate); /* Ramping rate */
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ gus_voice_volume (prev_vol);
+
+
+ gus_write8 (0x06, rate); /*
+ * Ramping rate
+ */
voices[voice].volume_irq_mode = VMODE_ENVELOPE;
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
+ if (((vol - prev_vol) / 64) == 0) /*
+ * No significant volume change
+ */
{
- step_envelope (voice); /* Continue with the next phase */
+ RESTORE_INTR (flags);
+ step_envelope (voice); /*
+ * Continue with the next phase
+ */
return;
}
@@ -506,16 +652,21 @@ step_envelope (int voice)
if (vol >= (4096 - 64))
vol = 4096 - 65;
gus_ramp_range (0, vol);
- gus_rampon (0x20); /* Increasing, irq */
+ gus_rampon (0x20); /*
+ * Increasing, irq
+ */
}
else
{
if (vol <= 64)
vol = 65;
- gus_ramp_range (vol, 4095);
- gus_rampon (0x60); /* Decreasing, irq */
+ gus_ramp_range (vol, 4030);
+ gus_rampon (0x60); /*
+ * Decreasing, irq
+ */
}
voices[voice].current_volume = vol;
+ RESTORE_INTR (flags);
}
static void
@@ -528,19 +679,26 @@ init_envelope (int voice)
}
static void
-start_release (int voice)
+start_release (int voice, long int flags)
{
if (gus_read8 (0x00) & 0x03)
- return; /* Voice already stopped */
+ return; /*
+ * Voice already stopped
+ */
- voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
+ voices[voice].env_phase = 2; /*
+ * Will be incremented by step_envelope
+ */
voices[voice].current_volume =
voices[voice].initial_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].mode &= ~WAVE_SUSTAIN_ON;
gus_rampoff ();
+ RESTORE_INTR (flags);
step_envelope (voice);
}
@@ -548,25 +706,38 @@ static void
gus_voice_fade (int voice)
{
int instr_no = sample_map[voice], is16bits;
+ long int flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
if (instr_no < 0 || instr_no > MAX_SAMPLE)
{
- gus_write8 (0x00, 0x03); /* Hard stop */
+ gus_write8 (0x00, 0x03); /*
+ * Hard stop
+ */
+ RESTORE_INTR (flags);
return;
}
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
if (voices[voice].mode & WAVE_ENVELOPES)
{
- start_release (voice);
+ start_release (voice, flags);
return;
}
/*
* Ramp the volume down but not too quickly.
*/
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
@@ -574,10 +745,13 @@ gus_voice_fade (int voice)
return;
}
- gus_ramp_range (65, 4095);
+ gus_ramp_range (65, 4030);
gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /* Down, once, irq */
+ gus_rampon (0x40 | 0x20); /*
+ * Down, once, irq
+ */
voices[voice].volume_irq_mode = VMODE_HALT;
+ RESTORE_INTR (flags);
}
static void
@@ -592,14 +766,25 @@ gus_reset (void)
for (i = 0; i < 32; i++)
{
- gus_voice_init (i); /* Turn voice off */
+ gus_voice_init (i); /*
+ * Turn voice off
+ */
+ gus_voice_init2 (i);
}
- INB (u_Status); /* Touch the status register */
+ INB (u_Status); /*
+ * Touch the status register
+ */
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
}
@@ -607,7 +792,7 @@ static void
gus_initialize (void)
{
unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
+ register unsigned char dma_image, irq_image, tmp;
static unsigned char gus_irq_map[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
@@ -617,11 +802,15 @@ gus_initialize (void)
DISABLE_INTR (flags);
- gus_write8 (0x4c, 0); /* Reset GF1 */
+ gus_write8 (0x4c, 0); /*
+ * Reset GF1
+ */
gus_delay ();
gus_delay ();
- gus_write8 (0x4c, 1); /* Release Reset */
+ gus_write8 (0x4c, 1); /*
+ * Release Reset
+ */
gus_delay ();
gus_delay ();
@@ -629,25 +818,49 @@ gus_initialize (void)
* Clear all interrupts
*/
- gus_write8 (0x41, 0); /* DMA control */
- gus_write8 (0x45, 0); /* Timer control */
- gus_write8 (0x49, 0); /* Sample control */
+ gus_write8 (0x41, 0); /*
+ * DMA control
+ */
+ gus_write8 (0x45, 0); /*
+ * Timer control
+ */
+ gus_write8 (0x49, 0); /*
+ * Sample control
+ */
gus_select_max_voices (24);
- INB (u_Status); /* Touch the status register */
-
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
-
- gus_reset (); /* Resets all voices */
-
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
-
- gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */
+ INB (u_Status); /*
+ * Touch the status register
+ */
+
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+ gus_reset (); /*
+ * Resets all voices
+ */
+
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+ gus_write8 (0x4c, 7); /*
+ * Master reset | DAC enable | IRQ enable
+ */
/*
* Set up for Digital ASIC
@@ -655,7 +868,9 @@ gus_initialize (void)
OUTB (0x05, gus_base + 0x0f);
- mix_image |= 0x02; /* Disable line out */
+ mix_image |= 0x02; /*
+ * Disable line out
+ */
OUTB (mix_image, u_Mixer);
OUTB (0x00, u_IRQDMAControl);
@@ -664,12 +879,9 @@ gus_initialize (void)
/*
* Now set up the DMA and IRQ interface
- *
+ *
* The GUS supports two IRQs and two DMAs.
- *
- * If GUS_MIDI_IRQ is defined and if it's != GUS_IRQ, separate Midi IRQ is set
- * up. Otherwise the same IRQ is shared by the both devices.
- *
+ *
* Just one DMA channel is used. This prevents simultaneous ADC and DAC.
* Adding this support requires significant changes to the dmabuf.c, dsp.c
* and audio.c also.
@@ -680,23 +892,13 @@ gus_initialize (void)
if (!tmp)
printk ("Warning! GUS IRQ not selected\n");
irq_image |= tmp;
+ irq_image |= 0x40; /*
+ * Combine IRQ1 (GF1) and IRQ2 (Midi)
+ */
- if (GUS_MIDI_IRQ != gus_irq)
- { /* The midi irq was defined and != wave irq */
- tmp = gus_irq_map[GUS_MIDI_IRQ];
- tmp <<= 3;
-
- if (!tmp)
- printk ("Warning! GUS Midi IRQ not selected\n");
- else
- gus_set_midi_irq (GUS_MIDI_IRQ);
-
- irq_image |= tmp;
- }
- else
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
-
- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+ dma_image = 0x40; /*
+ * Combine DMA1 (DRAM) and IRQ2 (ADC)
+ */
tmp = gus_dma_map[gus_dma];
if (!tmp)
printk ("Warning! GUS DMA not selected\n");
@@ -706,37 +908,73 @@ gus_initialize (void)
* For some reason the IRQ and DMA addresses must be written twice
*/
- /* Doing it first time */
-
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
-
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
-
- /* Doing it second time */
-
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
-
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ /*
+ * Doing it first time
+ */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image | 0x80, u_IRQDMAControl); /*
+ * Set DMA address
+ */
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- OUTB (mix_image, u_Mixer); /* Turn mixer channels on */
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ /*
+ * Doing it second time
+ */
- gusintr (0); /* Serve pending interrupts */
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image, u_IRQDMAControl); /*
+ * Set DMA address
+ */
+
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ mix_image &= ~0x02; /*
+ * Enable line out
+ */
+ mix_image |= 0x08; /*
+ * Enable IRQ
+ */
+ OUTB (mix_image, u_Mixer); /*
+ * Turn mixer channels on
+ * Note! Mic in is left off.
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ gusintr (0); /*
+ * Serve pending interrupts
+ */
RESTORE_INTR (flags);
}
int
gus_wave_detect (int baseaddr)
{
+ unsigned long i;
+ unsigned long loc;
+
gus_base = baseaddr;
gus_write8 (0x4c, 0); /* Reset GF1 */
@@ -747,31 +985,37 @@ gus_wave_detect (int baseaddr)
gus_delay ();
gus_delay ();
- gus_poke (0x000, 0xaa);
- gus_poke (0x100, 0x55);
+ /* See if there is first block there.... */
+ gus_poke (0L, 0xaa);
+ if (gus_peek (0L) != 0xaa)
+ return (0);
- if (gus_peek (0x000) != 0xaa)
- return 0;
- if (gus_peek (0x100) != 0x55)
- return 0;
-
- gus_mem_size = 0x40000; /* 256k */
- gus_poke (0x40000, 0xaa);
- if (gus_peek (0x40000) != 0xaa)
- return 1;
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke (0L, 0x00);
+ for (i = 1L; i < 1024L; i++)
+ {
+ int n, failed;
- gus_mem_size = 0x80000; /* 512k */
- gus_poke (0x80000, 0xaa);
- if (gus_peek (0x80000) != 0xaa)
- return 1;
+ /* check for mirroring ... */
+ if (gus_peek (0L) != 0)
+ break;
+ loc = i << 10;
- gus_mem_size = 0xc0000; /* 768k */
- gus_poke (0xc0000, 0xaa);
- if (gus_peek (0xc0000) != 0xaa)
- return 1;
+ for (n = loc - 1, failed = 0; n <= loc; n++)
+ {
+ gus_poke (loc, 0xaa);
+ if (gus_peek (loc) != 0xaa)
+ failed = 1;
- gus_mem_size = 0x100000; /* 1M */
+ gus_poke (loc, 0x55);
+ if (gus_peek (loc) != 0x55)
+ failed = 1;
+ }
+ if (failed)
+ break;
+ }
+ gus_mem_size = i << 10;
return 1;
}
@@ -816,16 +1060,26 @@ guswave_set_instr (int dev, int voice, int instr_no)
if (voice < 0 || voice > 31)
return RET_ERROR (EINVAL);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].sample_pending = instr_no;
+ return 0;
+ }
+
sample_no = patch_table[instr_no];
patch_map[voice] = -1;
if (sample_no < 0)
{
printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
- return RET_ERROR (EINVAL);/* Patch not defined */
+ return RET_ERROR (EINVAL);/*
+ * Patch not defined
+ */
}
- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
+ if (sample_ptrs[sample_no] == -1) /*
+ * Sample not loaded
+ */
{
printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);
return RET_ERROR (EINVAL);
@@ -837,14 +1091,25 @@ guswave_set_instr (int dev, int voice, int instr_no)
}
static int
+#ifdef FUTURE_VERSION
+guswave_kill_note (int dev, int voice, int note, int velocity)
+#else
guswave_kill_note (int dev, int voice, int velocity)
+#endif
{
unsigned long flags;
DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_fade (voice);
- RESTORE_INTR (flags);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].kill_pending = 1;
+ RESTORE_INTR (flags);
+ }
+ else
+ {
+ RESTORE_INTR (flags);
+ gus_voice_fade (voice);
+ }
return 0;
}
@@ -855,20 +1120,26 @@ guswave_aftertouch (int dev, int voice, int pressure)
short lo_limit, hi_limit;
unsigned long flags;
- return; /* Currently disabled */
+ return; /*
+ * Currently disabled
+ */
if (voice < 0 || voice > 31)
return;
if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
- return; /* Don't mix with envelopes */
+ return; /*
+ * Don't mix with envelopes
+ */
if (pressure < 32)
{
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
- compute_and_set_volume (voice, 255, 0); /* Back to original volume */
+ compute_and_set_volume (voice, 255, 0); /*
+ * Back to original volume
+ */
RESTORE_INTR (flags);
return;
}
@@ -887,7 +1158,9 @@ guswave_aftertouch (int dev, int voice, int pressure)
}
gus_ramp_range (lo_limit, hi_limit);
gus_ramp_rate (3, 8);
- gus_rampon (0x58); /* Bidirectional, Down, Loop */
+ gus_rampon (0x58); /*
+ * Bidirectional, Down, Loop
+ */
RESTORE_INTR (flags);
}
@@ -899,38 +1172,57 @@ guswave_panning (int dev, int voice, int value)
}
static void
+guswave_volume_method (int dev, int mode)
+{
+ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+ volume_method = mode;
+}
+
+static void
compute_volume (int voice, int volume)
{
if (volume < 128)
+ voices[voice].midi_volume = volume;
+
+ switch (volume_method)
{
- voices[voice].midi_volume = volume;
+ case VOL_METHOD_ADAGIO:
+ voices[voice].initial_volume =
+ gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
+ voices[voice].expression_vol,
+ voices[voice].patch_vol);
+ break;
- switch (volume_method)
- {
- case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol (volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
+ case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
+ voices[voice].initial_volume =
+ gus_linear_vol (volume, voices[voice].main_vol);
+ break;
- default:
- voices[voice].initial_volume = volume_base + (volume * volume_scale);
- }
+ default:
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
}
- if (voices[voice].initial_volume > 4095)
- voices[voice].initial_volume = 4095;
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
}
static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
int current, target, rate;
+ unsigned long flags;
compute_volume (voice, volume);
voices[voice].current_volume = voices[voice].initial_volume;
+ DISABLE_INTR (flags);
+ /*
+ * CAUTION! Interrupts disabled. Enable them before returning
+ */
+
+ gus_select_voice (voice);
+
current = gus_read16 (0x09) >> 4;
target = voices[voice].initial_volume;
@@ -938,6 +1230,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -947,10 +1240,13 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
rate = 16;
gus_ramp_rate (0, rate);
- if ((target - current) / 64 == 0) /* Too close */
+ if ((target - current) / 64 == 0) /*
+ * Too close
+ */
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -959,7 +1255,9 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
if (target > (4095 - 65))
target = 4095 - 65;
gus_ramp_range (current, target);
- gus_rampon (0x00); /* Ramp up, once, no irq */
+ gus_rampon (0x00); /*
+ * Ramp up, once, no irq
+ */
}
else
{
@@ -967,8 +1265,11 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
target = 65;
gus_ramp_range (target, current);
- gus_rampon (0x40); /* Ramp down, once, no irq */
+ gus_rampon (0x40); /*
+ * Ramp down, once, no irq
+ */
}
+ RESTORE_INTR (flags);
}
static void
@@ -979,11 +1280,15 @@ dynamic_volume_change (int voice)
DISABLE_INTR (flags);
gus_select_voice (voice);
- status = gus_read8 (0x00); /* Voice status */
+ status = gus_read8 (0x00); /*
+ * Voice status
+ */
RESTORE_INTR (flags);
if (status & 0x03)
- return; /* Voice not started */
+ return; /*
+ * Voice not started
+ */
if (!(voices[voice].mode & WAVE_ENVELOPES))
{
@@ -997,10 +1302,14 @@ dynamic_volume_change (int voice)
DISABLE_INTR (flags);
gus_select_voice (voice);
- status = gus_read8 (0x0d); /* Ramping status */
+ status = gus_read8 (0x0d); /*
+ * Ramping status
+ */
RESTORE_INTR (flags);
- if (status & 0x03) /* Sustain phase? */
+ if (status & 0x03) /*
+ * Sustain phase?
+ */
{
compute_and_set_volume (voice, voices[voice].midi_volume, 1);
return;
@@ -1011,9 +1320,12 @@ dynamic_volume_change (int voice)
compute_volume (voice, voices[voice].midi_volume);
-#if 0 /* Is this really required */
+#if 0 /*
+ * * * Is this really required */
voices[voice].current_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].env_phase--;
step_envelope (voice);
@@ -1033,38 +1345,59 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
{
case CTRL_PITCH_BENDER:
voices[voice].bender = value;
- freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
- voices[voice].current_freq = freq;
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ {
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+ }
break;
case CTRL_PITCH_BENDER_RANGE:
voices[voice].bender_range = value;
break;
-
+#ifdef FUTURE_VERSION
+ case CTL_EXPRESSION:
+ value /= 128;
+#endif
case CTRL_EXPRESSION:
- volume_method = VOL_METHOD_ADAGIO;
- voices[voice].expression_vol = value;
- dynamic_volume_change (voice);
+ if (volume_method == VOL_METHOD_ADAGIO)
+ {
+ voices[voice].expression_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
+ }
break;
+#ifdef FUTURE_VERSION
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+#endif
+
case CTRL_MAIN_VOLUME:
- volume_method = VOL_METHOD_ADAGIO;
voices[voice].main_vol = value;
- dynamic_volume_change (voice);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
break;
- default: /* Ignore */
+ default: /*
+ * Ignore
+ */
break;
}
}
static int
-guswave_start_note (int dev, int voice, int note_num, int volume)
+guswave_start_note2 (int dev, int voice, int note_num, int volume)
{
int sample, best_sample, best_delta, delta_freq;
int is16bits, samplep, patch, pan;
@@ -1123,7 +1456,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
sample = samplep;
else
- samplep = samples[samplep].key; /* Follow link */
+ samplep = samples[samplep].key; /*
+ * Follow link
+ */
}
if (sample == -1)
sample = best_sample;
@@ -1131,10 +1466,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (sample == -1)
{
printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
- return 0; /* Should play default patch ??? */
+ return 0; /*
+ * Should play default patch ???
+ */
}
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */
+ is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
voices[voice].mode = samples[sample].mode;
voices[voice].patch_vol = samples[sample].volume;
@@ -1151,7 +1492,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
sample_map[voice] = sample;
- base_note = samples[sample].base_note / 100; /* To avoid overflows */
+ base_note = samples[sample].base_note / 100; /*
+ * To avoid overflows
+ */
note_freq /= 100;
freq = samples[sample].base_freq * note_freq / base_note;
@@ -1175,20 +1518,27 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (samples[sample].mode & WAVE_16_BITS)
{
- mode |= 0x04; /* 16 bits */
+ mode |= 0x04; /*
+ * 16 bits
+ */
if ((sample_ptrs[sample] >> 18) !=
((sample_ptrs[sample] + samples[sample].len) >> 18))
printk ("GUS: Sample address error\n");
}
/*************************************************************************
- * CAUTION! Interrupts disabled. Don't return before enabling
- *************************************************************************/
+ * CAUTION! Interrupts disabled. Don't return before enabling
+ *************************************************************************/
DISABLE_INTR (flags);
gus_select_voice (voice);
- gus_voice_off (); /* It may still be running */
+ gus_voice_off (); /*
+ * It may still be running
+ */
gus_rampoff ();
+
+ RESTORE_INTR (flags);
+
if (voices[voice].mode & WAVE_ENVELOPES)
{
compute_volume (voice, volume);
@@ -1197,36 +1547,66 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
else
compute_and_set_volume (voice, volume, 0);
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len, is16bits); /* Sample start=end */
+ gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
+ voices[voice].offset_pending, is16bits); /* Sample
+ * start=end */
else
- gus_write_addr (0x0a, sample_ptrs[sample], is16bits); /* Sample start=begin */
+ gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
+ is16bits); /* Sample start=begin */
if (samples[sample].mode & WAVE_LOOPING)
{
- mode |= 0x08; /* Looping on */
+ mode |= 0x08; /*
+ * Looping on
+ */
if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10; /* Bidirectional looping on */
+ mode |= 0x10; /*
+ * Bidirectional looping on
+ */
if (samples[sample].mode & WAVE_LOOP_BACK)
{
- gus_write_addr (0x0a, /* Put the current location = loop_end */
- sample_ptrs[sample] + samples[sample].loop_end, is16bits);
- mode |= 0x40; /* Loop backwards */
+ gus_write_addr (0x0a,
+ sample_ptrs[sample] + samples[sample].loop_end -
+ voices[voice].offset_pending, is16bits);
+ mode |= 0x40;
}
- gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* Loop start location */
- gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* Loop end location */
+ gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /*
+ * Loop
+ * start
+ * location
+ */
+ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /*
+ * Loop
+ * end
+ * location
+ */
}
else
{
- mode |= 0x20; /* Loop irq at the end */
- voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp it down at the
- * end */
+ mode |= 0x20; /*
+ * Loop irq at the end
+ */
+ voices[voice].loop_irq_mode = LMODE_FINISH; /*
+ * Ramp it down at
+ * the * end
+ */
voices[voice].loop_irq_parm = 1;
- gus_write_addr (0x02, sample_ptrs[sample], is16bits); /* Loop start location */
- gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len, is16bits); /* Loop end location */
+ gus_write_addr (0x02, sample_ptrs[sample], is16bits); /*
+ * Loop start
+ * location
+ */
+ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, is16bits); /*
+ * Loop
+ * end
+ * location
+ */
}
gus_voice_freq (freq);
gus_voice_balance (pan);
@@ -1236,13 +1616,81 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
return 0;
}
+/*
+ * * New guswave_start_note by Andrew J. Robinson attempts to minimize
+ * clicking * when the note playing on the voice is changed. It uses volume
+ * ramping. */
+
+static int
+guswave_start_note (int dev, int voice, int note_num, int volume)
+{
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ DISABLE_INTR (flags);
+ if (note_num == 255)
+ {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].volume_pending = volume;
+ else
+ {
+ RESTORE_INTR (flags);
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ }
+ else
+ {
+ gus_select_voice (voice);
+ mode = gus_read8 (0x00);
+ if (mode & 0x20)
+ gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
+
+ voices[voice].offset_pending = 0;
+ voices[voice].kill_pending = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].loop_irq_mode = 0;
+
+ if (voices[voice].sample_pending >= 0)
+ {
+ RESTORE_INTR (flags);
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ DISABLE_INTR (flags);
+ }
+
+ if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+ {
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ else
+ {
+ voices[voice].dev_pending = dev;
+ voices[voice].note_pending = note_num;
+ voices[voice].volume_pending = volume;
+ voices[voice].volume_irq_mode = VMODE_START_NOTE;
+
+ gus_rampoff ();
+ gus_ramp_range (2000, 4065);
+ gus_ramp_rate (0, 63);/* Fastest possible rate */
+ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ RESTORE_INTR (flags);
+ }
+ }
+ return ret_val;
+}
+
static void
guswave_reset (int dev)
{
int i;
for (i = 0; i < 32; i++)
- gus_voice_init (i);
+ {
+ gus_voice_init (i);
+ gus_voice_init2 (i);
+ }
}
static int
@@ -1253,9 +1701,12 @@ guswave_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
if ((err = DMAbuf_open_dma (gus_devnum)))
return err;
+ RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
gus_busy = 1;
active_device = GUS_DEV_WAVE;
@@ -1280,22 +1731,29 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
{
struct patch_info patch;
int instr;
+ long sizeof_patch;
unsigned long blk_size, blk_end, left, src_offs, target;
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /*
+ * Size of
+ * the header
+ * * info
+ */
+
if (format != GUS_PATCH)
{
- printk ("GUS Error: Invalid patch format (key) 0x%04x\n", format);
+ printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
return RET_ERROR (EINVAL);
}
- if (count < sizeof (patch))
+ if (count < sizeof_patch)
{
printk ("GUS Error: Patch header too short\n");
return RET_ERROR (EINVAL);
}
- count -= sizeof (patch);
+ count -= sizeof_patch;
if (free_sample >= MAX_SAMPLE)
{
@@ -1308,7 +1766,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
* been transferred already.
*/
- COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof (patch) - offs);
+ COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
instr = patch.instr_no;
@@ -1321,13 +1779,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
if (count < patch.len)
{
printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, patch.len);
+ count, (int) patch.len);
patch.len = count;
}
if (patch.len <= 0 || patch.len > gus_mem_size)
{
- printk ("GUS: Invalid sample length %d\n", patch.len);
+ printk ("GUS: Invalid sample length %d\n", (int) patch.len);
return RET_ERROR (EINVAL);
}
@@ -1346,7 +1804,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
}
}
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* Alignment 32 bytes */
+ free_mem_ptr = (free_mem_ptr + 31) & ~31; /*
+ * Alignment 32 bytes
+ */
#define GUS_BANK_SIZE (256*1024)
@@ -1357,20 +1817,24 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
*/
if (patch.len >= GUS_BANK_SIZE)
{
- printk ("GUS: Sample (16 bit) too long %d\n", patch.len);
+ printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
return RET_ERROR (ENOSPC);
}
if ((free_mem_ptr / GUS_BANK_SIZE) !=
((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
{
- unsigned long tmp_mem = /* Align to 256K*N */
+ unsigned long tmp_mem = /*
+ * Align to 256K*N
+ */
((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
if ((tmp_mem + patch.len) > gus_mem_size)
return RET_ERROR (ENOSPC);
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+ free_mem_ptr = tmp_mem; /*
+ * This leaves unusable memory
+ */
}
}
@@ -1379,12 +1843,14 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
sample_ptrs[free_sample] = free_mem_ptr;
- /* Tremolo is not possible with envelopes */
+ /*
+ * Tremolo is not possible with envelopes
+ */
if (patch.mode & WAVE_ENVELOPES)
patch.mode &= ~WAVE_TREMOLO;
- memcpy ((char *) &samples[free_sample], &patch, sizeof (patch));
+ memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
/*
* Link this_one sample to the list of samples for patch 'instr'.
@@ -1401,7 +1867,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
src_offs = 0;
target = free_mem_ptr;
- while (left) /* Not all moved */
+ while (left) /*
+ * Not all moved
+ */
{
blk_size = sound_buffsizes[gus_devnum];
if (blk_size > left)
@@ -1413,13 +1881,15 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
blk_end = target + blk_size;
if ((target >> 18) != (blk_end >> 18))
- { /* Have to split the block */
+ { /*
+ * Have to split the block
+ */
blk_end &= ~(256 * 1024 - 1);
blk_size = blk_end - target;
}
-#ifdef GUS_NO_DMA
+#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
/*
* For some reason the DMA is not possible. We have to use PIO.
*/
@@ -1429,24 +1899,35 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
for (i = 0; i < blk_size; i++)
{
- GET_BYTE_FROM_USER (data, addr, sizeof (patch) + i);
+ GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
+ if (patch.mode & WAVE_UNSIGNED)
+
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /*
+ * Convert to signed
+ */
gus_poke (target + i, data);
}
}
-#else /* GUS_NO_DMA */
+#else /*
+ * * * GUS_NO_DMA */
{
unsigned long address, hold_address;
unsigned char dma_command;
+ unsigned long flags;
/*
* OK, move now. First in and then out.
*/
COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
- addr, sizeof (patch) + src_offs,
+ addr, sizeof_patch + src_offs,
blk_size);
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
+ DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
blk_size, DMA_MODE_WRITE);
@@ -1464,30 +1945,46 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
address |= (hold_address & 0x000c0000L);
}
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
/*
* Start the DMA transfer
*/
- dma_command = 0x21; /* IRQ enable, DMA start */
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
if (sound_dsp_dmachan[gus_devnum] > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Let's go luteet (=bugs) */
+ gus_write8 (0x41, dma_command); /*
+ * Let's go luteet (=bugs)
+ */
/*
* Sleep here until the DRAM DMA done interrupt is served
*/
active_device = GUS_DEV_WAVE;
- INTERRUPTIBLE_SLEEP_ON (dram_sleeper, dram_sleep_flag);
+ DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
+ if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
+ printk ("GUS: DMA Transfer timed out\n");
+ RESTORE_INTR (flags);
}
-#endif /* GUS_NO_DMA */
+#endif /*
+ * * * GUS_NO_DMA */
/*
* Now the next part
@@ -1497,7 +1994,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
src_offs += blk_size;
target += blk_size;
- gus_write8 (0x41, 0); /* Stop DMA */
+ gus_write8 (0x41, 0); /*
+ * Stop DMA
+ */
}
free_mem_ptr += patch.len;
@@ -1521,6 +2020,10 @@ guswave_hw_control (int dev, unsigned char *event)
p2 = *(unsigned short *) &event[6];
plong = *(unsigned long *) &event[4];
+ if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
+ (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
+ do_volume_irq (voice);
+
switch (cmd)
{
@@ -1538,7 +2041,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_VOICEON:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_on (p1);
RESTORE_INTR (flags);
break;
@@ -1551,16 +2056,15 @@ guswave_hw_control (int dev, unsigned char *event)
break;
case _GUS_VOICEFADE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
gus_voice_fade (voice);
- RESTORE_INTR (flags);
break;
case _GUS_VOICEMODE:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_mode (p1);
RESTORE_INTR (flags);
break;
@@ -1586,14 +2090,18 @@ guswave_hw_control (int dev, unsigned char *event)
RESTORE_INTR (flags);
break;
- case _GUS_VOICEVOL2: /* Just update the voice value */
+ case _GUS_VOICEVOL2: /*
+ * Just update the voice value
+ */
voices[voice].initial_volume =
voices[voice].current_volume = p1;
break;
case _GUS_RAMPRANGE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_range (p1, p2);
@@ -1602,7 +2110,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_RAMPRATE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_rate (p1, p2);
@@ -1611,27 +2121,37 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_RAMPMODE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_ramp_mode (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPON:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_rampon (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPOFF:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
@@ -1643,6 +2163,13 @@ guswave_hw_control (int dev, unsigned char *event)
volume_scale = p2;
break;
+ case _GUS_VOICE_POS:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_set_voice_pos (voice, plong);
+ RESTORE_INTR (flags);
+ break;
+
default:;
}
}
@@ -1710,6 +2237,8 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return gus_sampling_set_channels (arg);
return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
break;
@@ -1730,7 +2259,9 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return gus_sampling_bits;
return IOCTL_OUT (arg, gus_sampling_bits);
- case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ case SOUND_PCM_WRITE_FILTER: /*
+ * NOT YET IMPLEMENTED
+ */
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
@@ -1760,6 +2291,8 @@ gus_sampling_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
gus_busy = 1;
active_device = 0;
@@ -1767,10 +2300,13 @@ gus_sampling_open (int dev, int mode)
reset_sample_memory ();
gus_select_max_voices (14);
- gus_sampling_set_bits (8);
- gus_sampling_set_channels (1);
- gus_sampling_set_speed (DSP_DEFAULT_SPEED);
pcm_active = 0;
+ pcm_opened = 1;
+ if (mode & OPEN_READ)
+ {
+ recording_active = 1;
+ set_input_volumes ();
+ }
return 0;
}
@@ -1780,7 +2316,31 @@ gus_sampling_close (int dev)
{
gus_reset ();
gus_busy = 0;
+ pcm_opened = 0;
active_device = 0;
+
+ if (recording_active)
+ set_input_volumes ();
+
+ recording_active = 0;
+}
+
+static void
+gus_sampling_update_volume (void)
+{
+ unsigned long flags;
+ int voice;
+
+ DISABLE_INTR (flags);
+ if (pcm_active && pcm_opened)
+ for (voice = 0; voice < gus_sampling_channels; voice++)
+ {
+ gus_select_voice (voice);
+ gus_rampoff ();
+ gus_voice_volume (1530 + (25 * gus_pcm_volume));
+ gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
+ }
+ RESTORE_INTR (flags);
}
static void
@@ -1800,18 +2360,24 @@ play_next_pcm_block (void)
for (chn = 0; chn < gus_sampling_channels; chn++)
{
mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
+ ramp_mode[chn] = 0x03; /*
+ * Ramping and rollover off
+ */
if (chn == 0)
{
- mode[chn] |= 0x20; /* Loop irq */
+ mode[chn] |= 0x20; /*
+ * Loop irq
+ */
voices[chn].loop_irq_mode = LMODE_PCM;
}
if (gus_sampling_bits != 8)
{
is16bits = 1;
- mode[chn] |= 0x04; /* 16 bit data */
+ mode[chn] |= 0x04; /*
+ * 16 bit data
+ */
}
else
is16bits = 0;
@@ -1819,15 +2385,23 @@ play_next_pcm_block (void)
dram_loc = this_one * pcm_bsize;
dram_loc += chn * pcm_banksize;
- if (this_one == (pcm_nblk - 1)) /* Last of the DRAM buffers */
+ if (this_one == (pcm_nblk - 1)) /*
+ * Last of the DRAM buffers
+ */
{
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03;/* Disable rollover */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
+ ramp_mode[chn] = 0x03;/*
+ * Disable rollover
+ */
}
else
{
if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
+ ramp_mode[chn] = 0x04; /*
+ * Enable rollover bit
+ */
}
DISABLE_INTR (flags);
@@ -1835,13 +2409,21 @@ play_next_pcm_block (void)
gus_voice_freq (speed);
if (gus_sampling_channels == 1)
- gus_voice_balance (7); /* mono */
+ gus_voice_balance (7); /*
+ * mono
+ */
else if (chn == 0)
- gus_voice_balance (0); /* left */
+ gus_voice_balance (0); /*
+ * left
+ */
else
- gus_voice_balance (15); /* right */
+ gus_voice_balance (15); /*
+ * right
+ */
- if (!pcm_active) /* Voice not started yet */
+ if (!pcm_active) /*
+ * Voice not started yet
+ */
{
/*
* The playback was not started yet (or there has been a pause).
@@ -1850,38 +2432,67 @@ play_next_pcm_block (void)
* the normal loop with irq.
*/
- gus_voice_off (); /* It could already be running */
+ gus_voice_off (); /*
+ * It could already be running
+ */
gus_rampoff ();
- gus_voice_volume (4000);
- gus_ramp_range (65, 4030);
+ gus_voice_volume (1530 + (25 * gus_pcm_volume));
+ gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
- gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */
- gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start location */
+ gus_write_addr (0x0a, dram_loc, is16bits); /*
+ * Starting position
+ */
+ gus_write_addr (0x02, chn * pcm_banksize, is16bits); /*
+ * Loop start
+ * location
+ */
if (chn != 0)
gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
- is16bits); /* Loop end location */
+ is16bits); /*
+ * Loop end location
+ */
}
if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
else
- mode[chn] |= 0x08; /* Enable loop */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
if (pcm_datasize[this_one] != pcm_bsize)
{
- /* Incomplete block. Possibly the last one. */
+ /*
+ * Incomplete block. Possibly the last one.
+ */
if (chn == 0)
{
- mode[chn] &= ~0x08; /* Disable loop */
- mode[chn] |= 0x20;/* Enable loop IRQ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
+ mode[chn] |= 0x20;/*
+ * Enable loop IRQ
+ */
voices[0].loop_irq_mode = LMODE_PCM_STOP;
- ramp_mode[chn] = 0x03; /* No rollover bit */
+ ramp_mode[chn] = 0x03; /*
+ * No rollover bit
+ */
}
else
{
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */
- mode[chn] &= ~0x08; /* Disable loop */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
}
}
@@ -1908,7 +2519,7 @@ gus_transfer_output_block (int dev, unsigned long buf,
* This routine transfers one block of audio data to the DRAM. In mono mode
* it's called just once. When in stereo mode, this_one routine is called
* once for both channels.
- *
+ *
* The left/mono channel data is transferred to the beginning of dram and the
* right data to the area pointed by gus_page_size.
*/
@@ -1935,7 +2546,9 @@ gus_transfer_output_block (int dev, unsigned long buf,
else
this_one = pcm_current_block;
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
address = this_one * pcm_bsize;
@@ -1949,38 +2562,56 @@ gus_transfer_output_block (int dev, unsigned long buf,
address |= (hold_address & 0x000c0000L);
}
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
- dma_command = 0x21; /* IRQ enable, DMA start */
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
if (gus_sampling_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
else
- dma_command |= 0x80; /* Invert MSB */
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
if (sound_dsp_dmachan[dev] > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Kick on */
+ gus_write8 (0x41, dma_command); /*
+ * Kick on
+ */
- if (chn == (gus_sampling_channels - 1)) /* Last channel */
+ if (chn == (gus_sampling_channels - 1)) /*
+ * Last channel
+ */
{
- /* Last (right or mono) channel data */
+ /*
+ * Last (right or mono) channel data
+ */
active_device = GUS_DEV_PCM_DONE;
if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
{
play_next_pcm_block ();
}
}
- else /* Left channel data. The right channel is
- * transferred after DMA interrupt */
+ else /*
+ * * * Left channel data. The right channel
+ * is * * * transferred after DMA interrupt */
active_device = GUS_DEV_PCM_CONTINUE;
RESTORE_INTR (flags);
}
static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag)
+gus_sampling_output_block (int dev, unsigned long buf, int total_count,
+ int intrflag, int restart_dma)
{
pcm_current_buf = buf;
pcm_current_count = total_count;
@@ -1990,7 +2621,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intr
}
static void
-gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
+gus_sampling_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
unsigned char mode;
@@ -1999,13 +2631,21 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
- mode = 0xa0; /* DMA IRQ enable, invert MSB */
+ mode = 0xa0; /*
+ * DMA IRQ enable, invert MSB
+ */
if (sound_dsp_dmachan[dev] > 3)
- mode |= 0x04; /* 16 bit DMA channel */
+ mode |= 0x04; /*
+ * 16 bit DMA channel
+ */
if (gus_sampling_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
+ mode |= 0x02; /*
+ * Stereo
+ */
+ mode |= 0x01; /*
+ * DMA enable
+ */
gus_write8 (0x49, mode);
@@ -2019,7 +2659,9 @@ gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
rate = (9878400 / (gus_sampling_speed + 2)) / 16;
- gus_write8 (0x48, rate & 0xff); /* Set sampling frequency */
+ gus_write8 (0x48, rate & 0xff); /*
+ * Set sampling frequency
+ */
if (gus_sampling_bits != 8)
{
@@ -2072,7 +2714,9 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
snd_rw_buf * userbuf, int useroffs, int len)
{
if (gus_sampling_channels == 1)
- COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ {
+ COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ }
else if (gus_sampling_bits == 8)
{
int in_left = useroffs;
@@ -2119,19 +2763,39 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
static struct audio_operations gus_sampling_operations =
{
"Gravis UltraSound",
- gus_sampling_open, /* */
- gus_sampling_close, /* */
- gus_sampling_output_block, /* */
- gus_sampling_start_input, /* */
- gus_sampling_ioctl, /* */
- gus_sampling_prepare_for_input, /* */
- gus_sampling_prepare_for_output, /* */
- gus_sampling_reset, /* */
- gus_sampling_reset, /* halt_xfer */
+ NEEDS_RESTART,
+ gus_sampling_open,
+ gus_sampling_close,
+ gus_sampling_output_block,
+ gus_sampling_start_input,
+ gus_sampling_ioctl,
+ gus_sampling_prepare_for_input,
+ gus_sampling_prepare_for_output,
+ gus_sampling_reset,
+ gus_sampling_reset,
gus_has_output_drained,
gus_copy_from_user
};
+#ifdef FUTURE_VERSION
+static void
+guswave_bender (int dev, int voice, int value)
+{
+ int freq;
+ unsigned long flags;
+
+ voices[voice].bender = value - 8192;
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+}
+
+#endif
+
static int
guswave_patchmgr (int dev, struct patmgr_info *rec)
{
@@ -2161,7 +2825,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data8[i]++;
- ptr = samples[ptr].key; /* Follow link */
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
}
}
return 0;
@@ -2176,7 +2842,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data32[n++] = ptr;
- ptr = samples[ptr].key; /* Follow link */
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
}
}
rec->parm1 = n;
@@ -2196,8 +2864,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
pat = (struct patch_info *) rec->data.data8;
- pat->key = GUS_PATCH; /* Restore patch type */
- rec->parm1 = sample_ptrs[ptr]; /* DRAM address */
+ pat->key = GUS_PATCH; /*
+ * Restore patch type
+ */
+ rec->parm1 = sample_ptrs[ptr]; /*
+ * DRAM address
+ */
rec->parm2 = sizeof (struct patch_info);
}
return 0;
@@ -2213,10 +2885,14 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
pat = (struct patch_info *) rec->data.data8;
- if (pat->len > samples[ptr].len) /* Cannot expand sample */
+ if (pat->len > samples[ptr].len) /*
+ * Cannot expand sample
+ */
return RET_ERROR (EINVAL);
- pat->key = samples[ptr].key; /* Ensure the link is correct */
+ pat->key = samples[ptr].key; /*
+ * Ensure the link is correct
+ */
memcpy ((char *) &samples[ptr], rec->data.data8,
sizeof (struct patch_info));
@@ -2226,7 +2902,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return 0;
break;
- case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
+ case PM_READ_PATCH: /*
+ * Returns a block of wave data from the DRAM
+ */
{
int sample = rec->parm1;
int n;
@@ -2237,9 +2915,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
- n = samples[sample].len - offs; /* Nr of bytes left */
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2248,18 +2930,26 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
for (n = 0; n < l; n++)
rec->data.data8[n] = gus_peek (offs++);
- rec->parm1 = n; /* Nr of bytes copied */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
- case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */
+ case PM_WRITE_PATCH: /*
+ * Writes a block of wave data to the DRAM
+ */
{
int sample = rec->parm1;
int n;
@@ -2270,9 +2960,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
- n = samples[sample].len - offs; /* Nr of bytes left */
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2281,13 +2975,19 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
for (n = 0; n < l; n++)
gus_poke (offs++, rec->data.data8[n]);
- rec->parm1 = n; /* Nr of bytes copied */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
@@ -2300,6 +3000,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
static struct synth_operations guswave_operations =
{
&gus_info,
+#ifdef FUTURE_VERSION
+ 0,
+#endif
SYNTH_TYPE_SAMPLE,
SAMPLE_TYPE_GUS,
guswave_open,
@@ -2314,13 +3017,273 @@ static struct synth_operations guswave_operations =
guswave_aftertouch,
guswave_controller,
guswave_panning,
- guswave_patchmgr
+ guswave_volume_method,
+ guswave_patchmgr,
+#ifdef FUTURE_VERSION
+ guswave_bender
+#endif
+};
+
+static void
+set_input_volumes (void)
+{
+ unsigned long flags;
+ unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+
+ DISABLE_INTR (flags);
+
+ /*
+ * Enable channels having vol > 10%
+ * Note! bit 0x01 means line in DISABLED while 0x04 means
+ * mic in ENABLED.
+ */
+ if (gus_line_vol > 10)
+ mask &= ~0x01;
+ if (gus_mic_vol > 10)
+ mask |= 0x04;
+
+ if (recording_active)
+ {
+ /*
+ * Disable channel, if not selected for recording
+ */
+ if (!(gus_recmask & SOUND_MASK_LINE))
+ mask |= 0x01;
+ if (!(gus_recmask & SOUND_MASK_MIC))
+ mask &= ~0x04;
+ }
+
+ mix_image &= ~0x07;
+ mix_image |= mask & 0x07;
+ OUTB (mix_image, u_Mixer);
+
+ RESTORE_INTR (flags);
+}
+
+int
+gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH|SOUND_MASK_PCM)
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ gus_recmask = IOCTL_IN (arg) & MIX_DEVS;
+ if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+ gus_recmask = SOUND_MASK_MIC;
+ /* Note! Input volumes are updated during next open for recording */
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_MIC:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_mic_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_LINE:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_line_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_PCM:
+ gus_pcm_volume = IOCTL_IN (arg) & 0xff;
+ if (gus_pcm_volume < 0)
+ gus_pcm_volume = 0;
+ if (gus_pcm_volume > 100)
+ gus_pcm_volume = 100;
+ gus_sampling_update_volume ();
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = IOCTL_IN (arg) & 0xff;
+
+ if (gus_wave_volume < 0)
+ gus_wave_volume = 0;
+ if (gus_wave_volume > 100)
+ gus_wave_volume = 100;
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change (voice); /*
+ * Apply the new
+ * volume
+ */
+
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ }
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8));
+ break;
+
+ case SOUND_MIXER_PCM:
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations gus_mixer_operations =
+{
+ gus_default_mixer_ioctl
};
+static long
+gus_default_mixer_init (long mem_start)
+{
+ if (num_mixers < MAX_MIXER_DEV) /*
+ * Don't install if there is another
+ * mixer
+ */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
+
+ return mem_start;
+}
+
long
gus_wave_init (long mem_start, int irq, int dma)
{
- printk ("snd4: <Gravis UltraSound %dk>", gus_mem_size / 1024);
+ unsigned long flags;
+ unsigned char val;
+ char *model_num = "2.4";
+ int gus_type = 0x24; /* 2.4 */
+ int mixer_type = 0;
+
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
+
+ DISABLE_INTR (flags);
+ OUTB (0x20, gus_base + 0x0f);
+ val = INB (gus_base + 0x0f);
+ RESTORE_INTR (flags);
+
+ if (val != 0xff && (val & 0x06)) /* Should be 0x02? */
+ {
+ /*
+ * It has the digital ASIC so the card is at least v3.4.
+ * Next try to detect the true model.
+ */
+
+ val = INB (u_MixSelect);
+
+ /*
+ * Value 255 means pre-3.7 which don't have mixer.
+ * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+ * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+ *
+ * Sorry. No GUS max support yet but it should be available
+ * soon after the SDK for GUS MAX is available.
+ */
+
+ if (val == 255 || val < 5)
+ {
+ model_num = "3.4";
+ gus_type = 0x34;
+ }
+ else if (val < 10)
+ {
+ model_num = "3.7";
+ gus_type = 0x37;
+ mixer_type = ICS2101;
+ }
+ else
+ {
+ model_num = "MAX";
+ gus_type = 0x40;
+ mixer_type = CS4231;
+ }
+ }
+ else
+ {
+ /*
+ * ASIC not detected so the card must be 2.2 or 2.4.
+ * There could still be the 16-bit/mixer daughter card.
+ * It has the same codec/mixer than MAX.
+ * At this time there is no support for it but it will appear soon.
+ */
+ }
+
+
+#ifdef __FreeBSD__
+ printk ("snd4: <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#else
+ printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#endif
+
+#ifndef SCO
+ sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+#endif
if (irq < 0 || irq > 15)
{
@@ -2342,6 +3305,9 @@ gus_wave_init (long mem_start, int irq, int dma)
else
synth_devs[num_synths++] = &guswave_operations;
+ PERMANENT_MALLOC (struct patch_info *, samples,
+ (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+
reset_sample_memory ();
gus_initialize ();
@@ -2350,13 +3316,29 @@ gus_wave_init (long mem_start, int irq, int dma)
{
dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
sound_dsp_dmachan[gus_devnum] = dma;
- sound_buffcounts[gus_devnum] = 1;
+ sound_buffcounts[gus_devnum] = DSP_BUFFCOUNT;
sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
sound_dma_automode[gus_devnum] = 0;
}
else
printk ("GUS: Too many PCM devices available\n");
+ /*
+ * Mixer dependent initialization.
+ */
+
+ switch (mixer_type)
+ {
+ case ICS2101:
+ gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+ return ics2101_mixer_init (mem_start);
+
+ case CS4231:
+ /* Available soon */
+ default:
+ return gus_default_mixer_init (mem_start);
+ }
+
return mem_start;
}
@@ -2371,7 +3353,9 @@ do_loop_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x00);
- tmp &= ~0x20; /* Disable wave IRQ for this_one voice */
+ tmp &= ~0x20; /*
+ * Disable wave IRQ for this_one voice
+ */
gus_write8 (0x00, tmp);
mode = voices[voice].loop_irq_mode;
@@ -2381,23 +3365,33 @@ do_loop_irq (int voice)
switch (mode)
{
- case LMODE_FINISH: /* Final loop finished, shoot volume down */
+ case LMODE_FINISH: /*
+ * Final loop finished, shoot volume down
+ */
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
gus_voice_init (voice);
- return;
+ break;
}
gus_ramp_range (65, 4065);
- gus_ramp_rate (0, 63); /* Fastest possible rate */
- gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ gus_ramp_rate (0, 63); /*
+ * Fastest possible rate
+ */
+ gus_rampon (0x20 | 0x40); /*
+ * Ramp down, once, irq
+ */
voices[voice].volume_irq_mode = VMODE_HALT;
break;
case LMODE_PCM_STOP:
- pcm_active = 0; /* Requires extensive processing */
+ pcm_active = 0; /*
+ * Requires extensive processing
+ */
case LMODE_PCM:
{
int orig_qlen = pcm_qlen;
@@ -2409,7 +3403,9 @@ do_loop_irq (int voice)
play_next_pcm_block ();
}
else
- { /* Out of data. Just stop the voice */
+ { /*
+ * Out of data. Just stop the voice
+ */
gus_voice_off ();
gus_rampoff ();
pcm_active = 0;
@@ -2417,7 +3413,7 @@ do_loop_irq (int voice)
if (orig_qlen == pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, 0);
}
}
break;
@@ -2439,7 +3435,9 @@ do_volume_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /* Disable volume ramp IRQ */
+ tmp &= ~0x20; /*
+ * Disable volume ramp IRQ
+ */
gus_write8 (0x0d, tmp);
mode = voices[voice].volume_irq_mode;
@@ -2448,19 +3446,35 @@ do_volume_irq (int voice)
switch (mode)
{
- case VMODE_HALT: /* Decay phase finished */
+ case VMODE_HALT: /*
+ * Decay phase finished
+ */
+ RESTORE_INTR (flags);
gus_voice_init (voice);
break;
case VMODE_ENVELOPE:
gus_rampoff ();
+ RESTORE_INTR (flags);
step_envelope (voice);
break;
+ case VMODE_START_NOTE:
+ RESTORE_INTR (flags);
+ guswave_start_note2 (voices[voice].dev_pending, voice,
+ voices[voice].note_pending, voices[voice].volume_pending);
+ if (voices[voice].kill_pending)
+ guswave_kill_note (voices[voice].dev_pending, voice, 0);
+ if (voices[voice].sample_pending >= 0)
+ {
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ }
+ break;
+
default:;
}
-
- RESTORE_INTR (flags);
}
void
@@ -2473,24 +3487,38 @@ gus_voice_irq (void)
while (1)
{
- src = gus_read8 (0x0f); /* Get source info */
+ src = gus_read8 (0x0f); /*
+ * Get source info
+ */
voice = src & 0x1f;
src &= 0xc0;
if (src == (0x80 | 0x40))
- return; /* No interrupt */
+ return; /*
+ * No interrupt
+ */
voice_bit = 1 << voice;
- if (!(src & 0x80)) /* Wave IRQ pending */
- if (!(wave_ignore & voice_bit) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x80)) /*
+ * Wave IRQ pending
+ */
+ if (!(wave_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
{
wave_ignore |= voice_bit;
do_loop_irq (voice);
}
- if (!(src & 0x40)) /* Volume IRQ pending */
- if (!(volume_ignore & voice_bit) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x40)) /*
+ * Volume IRQ pending
+ */
+ if (!(volume_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
{
volume_ignore |= voice_bit;
do_volume_irq (voice);
@@ -2503,13 +3531,17 @@ guswave_dma_irq (void)
{
unsigned char status;
- status = gus_look8 (0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA Irq pending */
+ status = gus_look8 (0x41); /*
+ * Get DMA IRQ Status
+ */
+ if (status & 0x40) /*
+ * DMA Irq pending
+ */
switch (active_device)
{
case GUS_DEV_WAVE:
- if (dram_sleep_flag)
- WAKE_UP (dram_sleeper);
+ if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
+ WAKE_UP (dram_sleeper, dram_sleep_flag);
break;
case GUS_DEV_PCM_CONTINUE:
@@ -2521,15 +3553,19 @@ guswave_dma_irq (void)
case GUS_DEV_PCM_DONE:
if (pcm_qlen < pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
}
break;
default:;
}
- status = gus_look8 (0x49); /* Get Sampling IRQ Status */
- if (status & 0x40) /* Sampling Irq pending */
+ status = gus_look8 (0x49); /*
+ * Get Sampling IRQ Status
+ */
+ if (status & 0x40) /*
+ * Sampling Irq pending
+ */
{
DMAbuf_inputintr (gus_devnum);
}
diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c
new file mode 100644
index 000000000000..0e54c608de36
--- /dev/null
+++ b/sys/i386/isa/sound/ics2101.c
@@ -0,0 +1,265 @@
+/*
+ * sound/ics2101.c
+ *
+ * Driver for the ICS2101 mixer of GUS v3.7.
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include "sound_config.h"
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#ifdef __FreeBSD__
+#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
+#include "gus_hw.h"
+
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH| \
+ SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+extern int gus_base;
+static int volumes[ICS_MIXDEVS];
+static int left_fix[ICS_MIXDEVS] =
+{1, 1, 1, 2, 1, 2};
+static int right_fix[ICS_MIXDEVS] =
+{2, 2, 2, 1, 2, 1};
+
+static int
+scale_vol(int vol)
+{
+#if 1
+/*
+ * Experimental volume scaling by Risto Kankkunen.
+ * This should give smoother volume response than just
+ * a plain multiplication.
+ */
+ int e;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ vol = (31 * vol + 50) / 100;
+ e = 0;
+ if (vol) {
+ while (vol < 16) {
+ vol <<= 1;
+ e--;
+ }
+ vol -= 16;
+ e += 7;
+ }
+ return ((e << 4) + vol);
+#else
+ return ((vol*127)+50)/100;
+#endif
+}
+
+static void
+write_mix (int dev, int chn, int vol)
+{
+ int *selector;
+ unsigned long flags;
+ int ctrl_addr = dev << 3;
+ int attn_addr = dev << 3;
+
+ vol=scale_vol(vol);
+
+ if (chn == CHN_LEFT)
+ {
+ selector = left_fix;
+ ctrl_addr |= 0x00;
+ attn_addr |= 0x02;
+ }
+ else
+ {
+ selector = right_fix;
+ ctrl_addr |= 0x01;
+ attn_addr |= 0x03;
+ }
+
+ DISABLE_INTR (flags);
+ OUTB (ctrl_addr, u_MixSelect);
+ OUTB (selector[dev], u_MixData);
+ OUTB (attn_addr, u_MixSelect);
+ OUTB ((unsigned char) vol, u_MixData);
+ RESTORE_INTR (flags);
+}
+
+static int
+set_volumes (int dev, int vol)
+{
+ int left = vol & 0x00ff;
+ int right = (vol >> 8) & 0x00ff;
+
+ if (left < 0)
+ left = 0;
+ if (left > 100)
+ left = 100;
+ if (right < 0)
+ right = 0;
+ if (right > 100)
+ right = 100;
+
+ write_mix (dev, CHN_LEFT, left);
+ write_mix (dev, CHN_RIGHT, right);
+
+ vol = left + (right << 8);
+ volumes[dev] = vol;
+ return vol;
+}
+
+static int
+ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+ SOUND_MASK_MIC);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, volumes[DEV_MIC]);
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, volumes[DEV_LINE]);
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, volumes[DEV_CD]);
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, volumes[DEV_VOL]);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, volumes[DEV_GF1]);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations ics2101_mixer_operations =
+{
+ ics2101_mixer_ioctl
+};
+
+long
+ics2101_mixer_init (long mem_start)
+{
+ int i;
+
+ if (num_mixers < MAX_MIXER_DEV)
+ {
+ mixer_devs[num_mixers++] = &ics2101_mixer_operations;
+
+ /*
+ * Some GUS v3.7 cards had some channels flipped. Disable
+ * the flipping feature if the model id is other than 5.
+ */
+
+ if (INB (u_MixSelect) != 5)
+ {
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ left_fix[i] = 1;
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ right_fix[i] = 2;
+ }
+
+ set_volumes (DEV_GF1, 0x5a5a);
+ set_volumes (DEV_CD, 0x5a5a);
+ set_volumes (DEV_MIC, 0x0000);
+ set_volumes (DEV_LINE, 0x5a5a);
+ set_volumes (DEV_VOL, 0x5a5a);
+ set_volumes (DEV_UNUSED, 0x0000);
+ }
+
+ return mem_start;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h
index f81bd7821673..36092e37d978 100644
--- a/sys/i386/isa/sound/local.h
+++ b/sys/i386/isa/sound/local.h
@@ -1,10 +1,15 @@
-/* These few lines are used by FreeBSD (only??). */
-
+/* for FreeBSD */
#include "snd.h"
#if NSND > 0
-#define CONFIGURE_SOUNDCARD
+#define KERNEL_SOUNDCARD
#endif
-#define DSP_BUFFSIZE 32768
+#define DSP_BUFFSIZE 65536
+#define NO_AUTODMA /* still */
#define SELECTED_SOUND_OPTIONS 0xffffffff
+#define SOUND_VERSION_STRING "2.5"
+#define SOUND_CONFIG_DATE "Sat Apr 23 07:45:17 MSD 1994"
+#define SOUND_CONFIG_BY "ache"
+#define SOUND_CONFIG_HOST "dream.demos.su"
+#define SOUND_CONFIG_DOMAIN ""
diff --git a/sys/i386/isa/sound/midi.c b/sys/i386/isa/sound/midi.c
index 8d604a80abc2..6ea51b061b9c 100644
--- a/sys/i386/isa/sound/midi.c
+++ b/sys/i386/isa/sound/midi.c
@@ -31,24 +31,27 @@
#ifndef EXCLUDE_CHIP_MIDI
-static int generic_midi_busy[MAX_MIDI_DEV];
+static int generic_midi_busy[MAX_MIDI_DEV];
-long CMIDI_init (long mem_start)
+long
+CMIDI_init (long mem_start)
{
-
- int i;
- int n = num_midi_drivers;
- /* int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
- */
- for (i = 0; i < n; i++)
- {
- if ( midi_supported[i].attach (mem_start) )
+
+ int i;
+ int n = num_midi_drivers;
+
+ /*
+ * int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
+ */
+ for (i = 0; i < n; i++)
{
- printk("MIDI: Successfully attached %s\n",midi_supported[i].name);
- }
+ if (midi_supported[i].attach (mem_start))
+ {
+ printk ("MIDI: Successfully attached %s\n", midi_supported[i].name);
+ }
- }
- return (mem_start);
+ }
+ return (mem_start);
}
@@ -56,142 +59,143 @@ int
CMIDI_open (int dev, struct fileinfo *file)
{
- int mode, err, retval;
+ int mode, err, retval;
- dev = dev >> 4;
+ dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ mode = file->mode & O_ACCMODE;
- if (generic_midi_busy[dev])
- return (RET_ERROR(EBUSY));
+ if (generic_midi_busy[dev])
+ return (RET_ERROR (EBUSY));
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
return (ENXIO);
- }
+ }
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
- /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->open (dev, mode) ;
+ retval = generic_midi_devs[dev]->open (dev, mode);
- /* If everything ok, set device as busy */
+ /* If everything ok, set device as busy */
- if ( retval >= 0 )
- generic_midi_busy[dev] = 1;
-
- return ( retval );
+ if (retval >= 0)
+ generic_midi_busy[dev] = 1;
+
+ return (retval);
}
-int
-CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+int
+CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
- int retval;
-
- dev = dev >> 4;
+ int retval;
+
+ dev = dev >> 4;
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->write (dev, buf);
- return ( retval );
+ retval = generic_midi_devs[dev]->write (dev, buf);
-}
+ return (retval);
+
+}
int
-CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count)
+CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
- int retval;
-
- dev = dev >> 4;
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
-
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
-
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->read(dev,buf);
- return (retval);
+ retval = generic_midi_devs[dev]->read (dev, buf);
+
+ return (retval);
+
+}
-}
-
int
CMIDI_close (int dev, struct fileinfo *file)
{
- int retval;
- dev = dev >> 4;
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
-
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
-
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /* If all good and healthy, go ahead and issue call! */
- generic_midi_devs[dev]->close(dev);
+ generic_midi_devs[dev]->close (dev);
- generic_midi_busy[dev] = 0; /* Free the device */
+ generic_midi_busy[dev] = 0; /* Free the device */
- return (0) ;
+ return (0);
}
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c
index 0196f84876bf..7dadb3f8fa74 100644
--- a/sys/i386/isa/sound/midibuf.c
+++ b/sys/i386/isa/sound/midibuf.c
@@ -1,12 +1,12 @@
/*
- * linux/kernel/chr_drv/sound/midibuf.c
- *
+ * sound/midibuf.c
+ *
* Device file manager for /dev/midi
- *
+ *
* NOTE! This part of the driver is currently just a stub.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -14,7 +14,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -26,7 +26,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c
index e8c011bc7940..38ba486b142b 100644
--- a/sys/i386/isa/sound/mpu401.c
+++ b/sys/i386/isa/sound/mpu401.c
@@ -1,12 +1,12 @@
/*
- * linux/kernel/chr_drv/sound/mpu401.c
- *
+ * sound/mpu401.c
+ *
* The low level driver for Roland MPU-401 compatible Midi cards.
- *
+ *
* This version supports just the DUMB UART mode.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -14,7 +14,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -26,7 +26,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -61,102 +61,16 @@ static int my_dev;
static int reset_mpu401 (void);
static void (*midi_input_intr) (int dev, unsigned char data);
-static void
-mpu401_input_loop (void)
-{
- int count;
-
- count = 10;
-
- while (count) /* Not timed out */
- if (input_avail ())
- {
- unsigned char c = mpu401_read ();
-
- count = 100;
-
- if (mpu401_opened & OPEN_READ)
- midi_input_intr (my_dev, c);
- }
- else
- while (!input_avail () && count)
- count--;
-}
-
void
mpuintr (int unit)
{
- if (input_avail ())
- mpu401_input_loop ();
-}
-
-/*
- * It looks like there is no input interrupts in the UART mode. Let's try
- * polling.
- */
-
-/* XXX WARNING: FreeBSD doesn't seem to have timer_lists like this,
- * so until I figure out how to do the analogous thing in FreeBSD, I'm
- * not all that sure WHAT this driver will do! It might work, depending
- * on the condition taken, but then again it might not! -jkh
- * XXX WARNING
- */
-static void
-poll_mpu401 (unsigned long dummy)
-{
- unsigned long flags;
-
-#ifdef linux
- static struct timer_list mpu401_timer =
- {NULL, 0, 0, poll_mpu401};
-#endif
-
- if (!(mpu401_opened & OPEN_READ))
- return; /* No longer required */
-
- DISABLE_INTR (flags);
-
- if (input_avail ())
- mpu401_input_loop ();
-
-#ifdef linux
- mpu401_timer.expires = 1;
- add_timer (&mpu401_timer); /* Come back later */
-#endif
-
- RESTORE_INTR (flags);
-}
-
-static int
-set_mpu401_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = mpuintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
+ while (input_avail ())
{
- printk ("MPU-401: IRQ%d already in use\n", interrupt_level);
- }
+ unsigned char c = mpu401_read ();
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
+ if (mpu401_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
}
static int
@@ -171,11 +85,10 @@ mpu401_open (int dev, int mode,
return RET_ERROR (EBUSY);
}
- mpu401_input_loop ();
+ mpuintr (0);
midi_input_intr = input;
mpu401_opened = mode;
- poll_mpu401 (0); /* Enable input polling */
return 0;
}
@@ -199,7 +112,7 @@ mpu401_out (int dev, unsigned char midi_byte)
DISABLE_INTR (flags);
if (input_avail ())
- mpu401_input_loop ();
+ mpuintr (0);
RESTORE_INTR (flags);
@@ -257,7 +170,7 @@ mpu401_buffer_status (int dev)
static struct midi_operations mpu401_operations =
{
- {"MPU-401", 0},
+ {"MPU-401", 0, 0, SNDCARD_MPU401},
mpu401_open,
mpu401_close,
mpu401_ioctl,
@@ -294,12 +207,14 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
RESTORE_INTR (flags);
+#ifdef __FreeBSD__
printk ("snd5: <Roland MPU-401>");
+#else
+ printk (" <Roland MPU-401>");
+#endif
my_dev = num_midis;
-#ifdef linux
mpu401_dev = num_midis;
-#endif
midi_devs[num_midis++] = &mpu401_operations;
return mem_start;
}
@@ -311,7 +226,7 @@ reset_mpu401 (void)
int ok, timeout, n;
/*
- * Send the RESET command. Try twice if no success at the first time.
+ * Send the RESET command. Try again if no success at the first time.
*/
ok = 0;
@@ -337,7 +252,7 @@ reset_mpu401 (void)
mpu401_opened = 0;
if (ok)
- mpu401_input_loop (); /* Flush input before enabling interrupts */
+ mpuintr (0); /* Flush input before enabling interrupts */
RESTORE_INTR (flags);
@@ -353,7 +268,7 @@ probe_mpu401 (struct address_info *hw_config)
mpu401_base = hw_config->io_base;
mpu401_irq = hw_config->irq;
- if (set_mpu401_irq (mpu401_irq) < 0)
+ if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
return 0;
ok = reset_mpu401 ();
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c
index 2dbed1f96e00..6e3dccab8c43 100644
--- a/sys/i386/isa/sound/opl3.c
+++ b/sys/i386/isa/sound/opl3.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/opl3.c
- *
+ * sound/opl3.c
+ *
* A low level driver for Yamaha YM3812 and OPL-3 -chips
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
@@ -38,7 +38,7 @@
#define MAX_VOICE 18
#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4
- * begin here */
+ * begin here */
static int opl3_enabled = 0;
static int left_address = 0x388, right_address = 0x388, both_address = 0;
@@ -59,8 +59,7 @@ struct voice_info
static struct voice_info voices[MAX_VOICE];
-typedef struct sbi_instrument instr_array[SBFM_MAXINSTR];
-static instr_array instrmap;
+static struct sbi_instrument *instrmap;
static struct sbi_instrument *active_instrument[MAX_VOICE] =
{NULL};
@@ -71,17 +70,20 @@ static int already_initialized = 0;
static int opl3_ok = 0;
static int opl3_busy = 0;
-static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */
+static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */
static int store_instr (int instr_no, struct sbi_instrument *instr);
static void freq_to_fnum (int freq, int *block, int *fnum);
-static void opl3_command (int io_addr, const unsigned char addr, const unsigned char val);
+static void opl3_command (int io_addr, unsigned int addr, unsigned int val);
static int opl3_kill_note (int dev, int voice, int velocity);
static unsigned char connection_mask = 0x00;
void
enable_opl3_mode (int left, int right, int both)
{
+ if (opl3_enabled)
+ return;
+
opl3_enabled = 1;
left_address = left;
right_address = right;
@@ -112,7 +114,7 @@ enter_4op_mode (void)
for (i = 0; i < 12; i++)
logical_voices[i] = voices_4op[i];
- nr_voices = 6;
+ nr_voices = 12;
}
static int
@@ -140,7 +142,7 @@ opl3_ioctl (int dev,
break;
case SNDCTL_SYNTH_INFO:
- fm_info.nr_voices = nr_voices;
+ fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
return 0;
@@ -169,10 +171,10 @@ opl3_detect (int ioaddr)
* This function returns 1 if the FM chicp is present at the given I/O port
* The detection algorithm plays with the timer built in the FM chip and
* looks for a change in the status register.
- *
+ *
* Note! The timers of the FM chip are not connected to AdLib (and compatible)
* boards.
- *
+ *
* Note2! The chip is initialized if detected.
*/
@@ -184,6 +186,9 @@ opl3_detect (int ioaddr)
return 0; /* Do avoid duplicate initializations */
}
+ if (opl3_enabled)
+ ioaddr = left_address;
+
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM
* chicp */
@@ -192,7 +197,7 @@ opl3_detect (int ioaddr)
if ((stat1 & 0xE0) != 0x00)
{
- return 0; /* Should be 0x00 */
+ return 0; /* Should be 0x00 */
}
opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */
@@ -270,7 +275,7 @@ store_instr (int instr_no, struct sbi_instrument *instr)
{
if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
- printk ("FM warning: Invalid patch format field (key) 0x%04x\n", instr->key);
+ printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
return 0;
@@ -362,7 +367,7 @@ set_voice_volume (int voice, int volume)
vol2 = instr->operators[3];
if ((instr->operators[10] & 0x01))
- { /* Additive synthesis */
+ { /* Additive synthesis */
calc_vol (&vol1, volume);
calc_vol (&vol2, volume);
}
@@ -616,7 +621,7 @@ freq_to_fnum (int freq, int *block, int *fnum)
}
static void
-opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
+opl3_command (int io_addr, unsigned int addr, unsigned int val)
{
int i;
@@ -625,7 +630,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
* register. The OPL-3 survives with just two INBs
*/
- OUTB (addr, io_addr); /* Select register */
+ OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */
if (!opl3_enabled)
tenmicrosec ();
@@ -633,7 +638,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
for (i = 0; i < 2; i++)
INB (io_addr);
- OUTB (val, io_addr + 1); /* Write to register */
+ OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */
if (!opl3_enabled)
{
@@ -745,6 +750,11 @@ opl3_panning (int dev, int voice, int pressure)
{
}
+static void
+opl3_volume_method (int dev, int mode)
+{
+}
+
#define SET_VIBRATO(cell) { \
tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
if (pressure > 110) \
@@ -850,7 +860,7 @@ opl3_controller (int dev, int voice, int ctrl_num, int value)
opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits
- * of f-num */
+ * of f-num */
voices[voice].keyon_byte = data;
opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
break;
@@ -884,6 +894,7 @@ static struct synth_operations opl3_operations =
opl3_aftertouch,
opl3_controller,
opl3_panning,
+ opl3_volume_method,
opl3_patchmgr
};
@@ -892,17 +903,26 @@ opl3_init (long mem_start)
{
int i;
+ PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
+ SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
+
synth_devs[num_synths++] = &opl3_operations;
fm_model = 0;
opl3_ok = 1;
if (opl3_enabled)
{
+#ifdef __FreeBSD__
printk ("snd1: <Yamaha OPL-3 FM>");
+#else
+ printk (" <Yamaha OPL-3 FM>");
+#endif
fm_model = 2;
nr_voices = 18;
fm_info.nr_drums = 0;
fm_info.capabilities |= SYNTH_CAP_OPL3;
+#ifndef SCO
strcpy (fm_info.name, "Yamaha OPL-3");
+#endif
for (i = 0; i < 18; i++)
if (physical_voices[i].ioaddr == USE_LEFT)
@@ -917,7 +937,11 @@ opl3_init (long mem_start)
}
else
{
+#ifdef __FreeBSD__
printk ("snd1: <Yamaha 2-OP FM>");
+#else
+ printk (" <Yamaha 2-OP FM>");
+#endif
fm_model = 1;
nr_voices = 9;
fm_info.nr_drums = 0;
diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h
index fba20980c3f0..c6b688ac6aa9 100644
--- a/sys/i386/isa/sound/os.h
+++ b/sys/i386/isa/sound/os.h
@@ -3,7 +3,7 @@
/*
* OS specific settings for FreeBSD
*
- * Copyright by Hannu Savolainen 1993
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This should be used as an example when porting the driver to a new
+ * This chould be used as an example when porting the driver to a new
* operating systems.
*
* What you should do is to rewrite the soundcard.c and os.h (this file).
@@ -44,7 +44,6 @@
#include "param.h"
#include "systm.h"
-#include "kernel.h"
#include "ioctl.h"
#include "tty.h"
#include "proc.h"
@@ -52,6 +51,7 @@
#include "conf.h"
#include "file.h"
#include "uio.h"
+#include "kernel.h"
#include "syslog.h"
#include "errno.h"
#include "malloc.h"
@@ -63,10 +63,6 @@
*/
#ifdef CONFIGURE_SOUNDCARD
-/* lbolt is required by the FreeBSD version (only???) */
-extern int __timeout_val;
-extern int __process_aborting;
-
/*
* select() is currently implemented in Linux specific way. Don't enable.
* I don't remember what the SHORT_BANNERS means so forget it.
@@ -163,14 +159,25 @@ typedef struct uio snd_rw_buf;
* The following macros define an interface to the process management.
*/
+struct snd_wait {
+ int mode; int aborting;
+ };
+
/*
* DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
* a structure which can be passed as a parameter to a sleep(). The second
* parameter is name of a flag variable (must be defined as int).
*/
-#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; static int flag = 0
+#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
+ static volatile struct snd_wait flag = {0}
/* Like the above but defines an array of wait queues and flags */
-#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; static int flag = {0}
+#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
+ static volatile struct snd_wait flag = {{0}}
+
+#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
+#define SET_ABORT_FLAG(q, f) f.aborting = 1
+#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
+#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
/*
* This driver handles interrupts little bit nonstandard way. The following
* macro is used to test if the current process has received a signal which
@@ -179,34 +186,28 @@ typedef struct uio snd_rw_buf;
* 1 or 0 could be returned (1 should be better than 0).
* I'm not sure if the following is correct for FreeBSD.
*/
-#define PROCESS_ABORTING (__process_aborting | curproc->p_sig)
-/*
- * REQUEST_TIMEOUT is called before sleep. It shoud ensure that the
- * process is woken up after given number of ticks (1/HZ secs.).
- * The wqueue gives the wait queue.
- */
-#define REQUEST_TIMEOUT(nticks, wqueue) __timeout_val = nticks;
+#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig)
/*
* The following macro calls sleep. It should be implemented such that
* the process is resumed if it receives a signal. The following is propably
* not the way how it should be done on 386bsd.
- * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE()
- * The second parameter is a flag. It must be initialized to 1 before sleep
- * and to zero after proces continues.
+ * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
+ * and the second is a workarea parameter. The third is a timeout
+ * in ticks. Zero means no timeout.
*/
-#define INTERRUPTIBLE_SLEEP_ON(on_what, flag) \
+#define DO_SLEEP(q, f, time_limit) \
{ \
- flag = 1; \
- flag=tsleep((caddr_t)&(on_what), (PRIBIO-5)|PCATCH, "sndint", __timeout_val); \
- if(flag == ERESTART) __process_aborting = 1;\
- else __process_aborting = 0;\
- __timeout_val = 0; \
- flag = 0; \
+ int flag, chn; \
+ f.mode = WK_SLEEP; \
+ q = &chn; \
+ flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \
+ if(flag == ERESTART) f.aborting = 1;\
+ else f.aborting = 0;\
+ f.mode &= ~WK_SLEEP; \
}
-
/* An the following wakes up a process */
-#define WAKE_UP(who) wakeup((caddr_t)&(who))
+#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);}
/*
* Timing macros. This driver assumes that there is a timer running in the
@@ -215,6 +216,7 @@ typedef struct uio snd_rw_buf;
*/
#ifndef HZ
+extern int hz;
#define HZ hz
#endif
@@ -223,9 +225,9 @@ typedef struct uio snd_rw_buf;
* ticks. This can overflow, so the timeout might be real big...
*
*/
+extern unsigned long get_time(void);
#define GET_TIME() get_time()
-extern long get_time(void);
-/*#define GET_TIME() (lbolt)*/ /* Returns current time (1/HZ secs since boot) */
+/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
/*
* The following three macros are called before and after atomic
@@ -248,7 +250,11 @@ extern long get_time(void);
*/
#define INB inb
-#define OUTB(addr, data) outb(data, addr)
+/*
+ * The outb(0, 0x80) is just for slowdown. It's bit unsafe since
+ * this address could be used for something usefull.
+ */
+#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
/* memcpy() was not defined og 386bsd. Lets define it here */
#define memcpy(d, s, c) bcopy(s, d, c)
@@ -274,6 +280,32 @@ extern long get_time(void);
#define KERNEL_FREE(addr) free(addr, M_TEMP)
/*
+ * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr)
+ * returns size bytes of
+ * (kernel virtual) memory which will never get freed by the driver.
+ * This macro is called only during boot. The linux_ptr is a linux specific
+ * parameter which should be ignored in other operating systems.
+ * The mem_ptr is a pointer variable where the macro assigns pointer to the
+ * memory area. The type is the type of the mem_ptr.
+ */
+#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
+ (mem_ptr) = (typecast)malloc((size), M_TEMP, M_WAITOK)
+
+/*
+ * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
+ * required. The name is the variable/name to be used and the proc is
+ * the procedure to be called when the timer expires.
+ */
+
+#define DEFINE_TIMER(name, proc)
+
+/*
+ * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
+ */
+
+#define ACTIVATE_TIMER(name, proc, time) \
+ timeout((timeout_func_t)proc, 0, time);
+/*
* The rest of this file is not complete yet. The functions using these
* macros will not work
*/
diff --git a/sys/i386/isa/sound/pas.h b/sys/i386/isa/sound/pas.h
index 4dadea3713b8..55d83737b609 100644
--- a/sys/i386/isa/sound/pas.h
+++ b/sys/i386/isa/sound/pas.h
@@ -128,24 +128,26 @@
#define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */
#define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */
+#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
#define PAS_NONE 0
#define PAS_PLUS 1
#define PAS_CDPC 2
#define PAS_16 3
+#define PAS_16D 4
#ifdef DEFINE_TRANSLATIONS
char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
{ 4, 1, 2, 3, 0, 5, 6, 7 };
char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */
- { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
+ { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 };
char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
- { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 };
+ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
- { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38 };
+ { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
- { 0x00, 0x40, 0x80, 0xC0 };
+ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */
- { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 2, 3 };
+ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
#else
extern char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */
extern char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */
diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c
index 96fe651fbaac..a8b79df2c8cd 100644
--- a/sys/i386/isa/sound/pas2_card.c
+++ b/sys/i386/isa/sound/pas2_card.c
@@ -1,12 +1,12 @@
#define _PAS2_CARD_C_
#define SND_SA_INTERRUPT
/*
- * linux/kernel/chr_drv/sound/pas2_card.c
- *
+ * sound/pas2_card.c
+ *
* Detection routine for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -14,7 +14,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -26,7 +26,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -46,8 +46,9 @@ static int pas_intr_mask = 0;
static int pas_irq = 0;
static char pas_model;
+static unsigned char board_rev_id;
static char *pas_model_names[] =
-{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16"};
+{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
/* pas_read() and pas_write() are equivalents of INB() and OUTB() */
/* These routines perform the I/O address translation required */
@@ -65,6 +66,23 @@ pas_write (unsigned char data, int ioaddr)
OUTB (data, ioaddr ^ translat_code);
}
+/*
+ * The Revision D cards have a problem with their MVA508 interface. The
+ * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
+ * MSBs out of the output byte and to do a 16-bit out to the mixer port -
+ * 1.
+ */
+
+void
+mix_write (unsigned char data, int ioaddr)
+{
+ if (pas_model == PAS_16D) {
+ outw ((ioaddr ^ translat_code) - 1, data | (data << 8));
+ outb (0, 0x80);
+ } else
+ OUTB (data, ioaddr ^ translat_code);
+}
+
void
pas2_msg (char *foo)
{
@@ -100,39 +118,6 @@ pasintr (int unused)
}
-static int
-set_pas_irq (int interrupt_level)
-{
-#ifdef linux
- int retcode;
- struct sigaction sa;
-
- pas_write (0xff, INTERRUPT_STATUS); /* Reset pending interrupts */
-
- sa.sa_handler = pasintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("ProAudioSpectrum: IRQ%d already in use\n", interrupt_level);
- }
- return retcode;
-#else
- /* # error This routine does not work with this OS */
- return EINVAL;
-#endif
-}
-
int
pas_set_intr (int mask)
{
@@ -143,7 +128,7 @@ pas_set_intr (int mask)
if (!pas_intr_mask)
{
- if ((err = set_pas_irq (pas_irq)) < 0)
+ if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
return err;
}
pas_intr_mask |= mask;
@@ -163,7 +148,7 @@ pas_remove_intr (int mask)
if (!pas_intr_mask)
{
- RELEASE_IRQ (pas_irq);
+ snd_release_irq (pas_irq);
}
return 0;
}
@@ -230,36 +215,66 @@ config_pas_hw (struct address_info *hw_config)
}
}
+ /*
+ * This fixes the timing problems of the PAS due to the Symphony chipset
+ * as per Media Vision. Only define this if your PAS doesn't work correctly.
+ */
+#ifdef SYMPHONY_PAS
+ OUTB (0x05, 0xa8);
+ OUTB (0x60, 0xa9);
+#endif
+
#ifdef BROKEN_BUS_CLOCK
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
#else
/* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); */
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
#endif
- /* pas_write(S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); Don't do this */
pas_write (0x18, SYSTEM_CONFIGURATION_3); /* ??? */
pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and
* selects filter rate
* of 17.897 kHz */
- if (pas_model == PAS_16)
+ if (pas_model == PAS_16 || pas_model == PAS_16D)
pas_write (8, PRESCALE_DIVIDER);
else
pas_write (0, PRESCALE_DIVIDER);
- pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
- pas_write (5, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
+ mix_write (5, PARALLEL_MIXER);
#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
- /* Turn on Sound Blaster compatibility */
- /* bit 1 = SB emulation */
- /* bit 0 = MPU401 emulation (CDPC only :-( ) */
- pas_write (0x02, COMPATIBILITY_ENABLE);
+ {
+ struct address_info *sb_config;
+
+ if ((sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ unsigned char irq_dma;
- /* "Emulation address" */
- pas_write ((SBC_BASE >> 4) & 0x0f, EMULATION_ADDRESS);
+ /* Turn on Sound Blaster compatibility */
+ /* bit 1 = SB emulation */
+ /* bit 0 = MPU401 emulation (CDPC only :-( ) */
+ pas_write (0x02, COMPATIBILITY_ENABLE);
+
+ /* "Emulation address" */
+ pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+
+ if (!E_C_SB_DMA_translate[sb_config->dma])
+ printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
+ sb_config->dma);
+
+ if (!E_C_SB_IRQ_translate[sb_config->irq])
+ printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
+ sb_config->irq);
+
+ irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
+ E_C_SB_IRQ_translate[sb_config->irq];
+
+ pas_write (irq_dma, EMULATION_CONFIGURATION);
+ }
+ }
#endif
if (!ok)
@@ -305,7 +320,7 @@ detect_pas_hw (struct address_info *hw_config)
if (board_id != foo) /* Not a PAS2 */
return 0;
- if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]));
+ pas_model = pas_read (CHIP_REV);
return pas_model;
}
@@ -318,9 +333,14 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
if (detect_pas_hw (hw_config))
{
- if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
+ board_rev_id = pas_read (BOARD_REV_ID);
+ if (pas_model = pas_read (CHIP_REV))
{
- printk ("snd3: <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
+#ifdef __FreeBSD__
+ printk ("snd3: <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#else
+ printk (" <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#endif
}
if (config_pas_hw (hw_config))
@@ -330,11 +350,11 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
mem_start = pas_pcm_init (mem_start, hw_config);
#endif
-# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
sb_dsp_disable_midi (); /* The SB emulation don't support
* midi */
-# endif
+#endif
#ifndef EXCLUDE_YM3812
enable_opl3_mode (0x388, 0x38a, 0);
@@ -350,7 +370,6 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
}
}
- printk ("\n");
return mem_start;
}
diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c
index 1a605905420f..4a07b0b59bf8 100644
--- a/sys/i386/isa/sound/pas2_midi.c
+++ b/sys/i386/isa/sound/pas2_midi.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/pas2_midi.c
- *
+ * sound/pas2_midi.c
+ *
* The low level driver for the PAS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -212,7 +212,7 @@ pas_buffer_status (int dev)
static struct midi_operations pas_midi_operations =
{
- {"Pro Audio Spectrum", 0},
+ {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
pas_midi_open,
pas_midi_close,
pas_midi_ioctl,
@@ -283,7 +283,7 @@ pas_midi_interrupt (void)
if (stat & M_S_OUTPUT_OVERRUN)
{
- printk ("MIDI output overrun %02x,%02x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
+ printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
ofifo_bytes = 100;
}
diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c
index 33135d24e859..b3868773d64c 100644
--- a/sys/i386/isa/sound/pas2_mixer.c
+++ b/sys/i386/isa/sound/pas2_mixer.c
@@ -1,12 +1,12 @@
#define _PAS2_MIXER_C_
/*
- * linux/kernel/chr_drv/sound/pas2_mixer.c
- *
+ * sound/pas2_mixer.c
+ *
* Mixer routines for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -14,7 +14,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -26,7 +26,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -46,7 +46,7 @@ static int mode_control = 0;
SOUND_MASK_CD | SOUND_MASK_ALTPCM)
#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD /*|SOUND_MASK_ALTPCM*/ | SOUND_MASK_IMIX | \
+ SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
@@ -72,14 +72,6 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
int left = left_vol * div / 100;
int right = right_vol * div / 100;
- /*
- * The Revision D cards have a problem with their MVA508 interface. The
- * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
- * MSBs out of the output byte and to do a 16-bit out to the mixer port -
- * 1. We don't need to do this because the call to pas_write more than
- * compensates for the timing problems.
- */
-
if (bits & P_M_MV508_MIXER)
{ /* Select input or output mixer */
left |= mixer;
@@ -87,17 +79,17 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
}
if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
- { /* Bass and trebble are mono devices */
- pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
- pas_write (left, PARALLEL_MIXER);
+ { /* Bass and trebble are mono devices */
+ mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
right_vol = left_vol;
}
else
{
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
- pas_write (left, PARALLEL_MIXER);
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
- pas_write (right, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
+ mix_write (right, PARALLEL_MIXER);
}
return (left_vol | (right_vol << 8));
@@ -106,8 +98,8 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
void
set_mode (int new_mode)
{
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
- pas_write (new_mode, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
+ mix_write (new_mode, PARALLEL_MIXER);
mode_control = new_mode;
}
diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c
index 878de5aaca94..b6d53fbccd01 100644
--- a/sys/i386/isa/sound/pas2_pcm.c
+++ b/sys/i386/isa/sound/pas2_pcm.c
@@ -1,11 +1,11 @@
#define _PAS2_PCM_C_
/*
- * linux/kernel/chr_drv/sound/pas2_pcm.c
- *
+ * sound/pas2_pcm.c
+ *
* The low level driver for the Pro Audio Spectrum ADC/DAC.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -13,7 +13,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -25,7 +25,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
@@ -75,6 +75,31 @@ pcm_set_speed (int arg)
tmp = pas_read (FILTER_FREQUENCY);
+/*
+ * Set anti-aliasing filters according to sample rate. You reall *NEED*
+ * to enable this feature for all normal recording unless you want to
+ * experiment with aliasing effects.
+ * These filters apply to the selected "recording" source.
+ * I (pfw) don't know the encoding of these 5 bits. The values shown
+ * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
+*/
+#if !defined NO_AUTO_FILTER_SET
+ tmp &= 0xe0;
+ if(pcm_speed >= 2*17897)
+ tmp |= 0x21;
+ else if(pcm_speed >= 2*15909)
+ tmp |= 0x22;
+ else if(pcm_speed >= 2*11931)
+ tmp |= 0x29;
+ else if(pcm_speed >= 2*8948)
+ tmp |= 0x31;
+ else if(pcm_speed >= 2*5965)
+ tmp |= 0x39;
+ else if(pcm_speed >= 2*2982)
+ tmp |= 0x24;
+ pcm_filter = tmp;
+#endif
+
DISABLE_INTR (flags);
pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
@@ -148,6 +173,8 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return pcm_set_channels (arg);
return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
break;
@@ -200,12 +227,6 @@ pas_pcm_open (int dev, int mode)
TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
- if (mode != OPEN_READ && mode != OPEN_WRITE)
- {
- printk ("PAS2: Attempt to open PCM device for simultaneous read and write");
- return RET_ERROR (EINVAL);
- }
-
if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
return err;
@@ -217,10 +238,6 @@ pas_pcm_open (int dev, int mode)
pcm_count = 0;
- pcm_set_bits (8);
- pcm_set_channels (1);
- pcm_set_speed (DSP_DEFAULT_SPEED);
-
return 0;
}
@@ -242,7 +259,8 @@ pas_pcm_close (int dev)
}
static void
-pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
+pas_pcm_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags, cnt;
@@ -251,7 +269,6 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
cnt = count;
if (sound_dsp_dmachan[dev] > 3)
cnt >>= 1;
- cnt--;
if (sound_dma_automode[dev] &&
intrflag &&
@@ -263,11 +280,11 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
PCM_CONTROL);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
- count--;
if (count != pcm_count)
{
@@ -288,7 +305,8 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
}
static void
-pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
+pas_pcm_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
int cnt;
@@ -298,7 +316,6 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
cnt = count;
if (sound_dsp_dmachan[dev] > 3)
cnt >>= 1;
- cnt--;
if (sound_dma_automode[my_devnum] &&
intrflag &&
@@ -307,13 +324,12 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
DISABLE_INTR (flags);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
- count--;
-
if (count != pcm_count)
{
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
@@ -346,14 +362,15 @@ pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
static struct audio_operations pas_pcm_operations =
{
"Pro Audio Spectrum",
- pas_pcm_open, /* */
- pas_pcm_close, /* */
- pas_pcm_output_block, /* */
- pas_pcm_start_input, /* */
- pas_pcm_ioctl, /* */
- pas_pcm_prepare_for_input, /* */
- pas_pcm_prepare_for_output, /* */
- pas_pcm_reset, /* */
+ NOTHING_SPECIAL,
+ pas_pcm_open,
+ pas_pcm_close,
+ pas_pcm_output_block,
+ pas_pcm_start_input,
+ pas_pcm_ioctl,
+ pas_pcm_prepare_for_input,
+ pas_pcm_prepare_for_output,
+ pas_pcm_reset,
pas_pcm_reset, /* halt_xfer */
NULL, /* has_output_drained */
NULL /* copy_from_user */
@@ -374,6 +391,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
{
dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
sound_dsp_dmachan[my_devnum] = hw_config->dma;
+#ifndef NO_AUTODMA
if (hw_config->dma > 3)
{
sound_buffcounts[my_devnum] = 1;
@@ -386,6 +404,11 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
sound_dma_automode[my_devnum] = 1;
}
+#else
+ sound_buffcounts[my_devnum] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
+ sound_dma_automode[my_devnum] = 0;
+#endif
}
else
printk ("PAS2: Too many PCM devices available\n");
@@ -413,7 +436,7 @@ pas_pcm_interrupt (unsigned char status, int cause)
{
case PCM_DAC:
- DMAbuf_outputintr (my_devnum);
+ DMAbuf_outputintr (my_devnum, 1);
break;
case PCM_ADC:
diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c
index 140a42845e5b..042d42d4067c 100644
--- a/sys/i386/isa/sound/patmgr.c
+++ b/sys/i386/isa/sound/patmgr.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/patmgr.c
- *
+ * sound/patmgr.c
+ *
* The patch maneger interface for the /dev/sequencer
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#define PATMGR_C
@@ -58,6 +58,8 @@ pmgr_open (int dev)
return RET_ERROR (EBUSY);
pmgr_opened[dev] = 1;
+ RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
+
return 0;
}
@@ -71,8 +73,8 @@ pmgr_release (int dev)
mbox[dev]->key = PM_ERROR;
mbox[dev]->parm1 = RET_ERROR (EIO);
- if (appl_wait_flag)
- WAKE_UP (appl_proc);
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
+ WAKE_UP (appl_proc, appl_wait_flag);
}
pmgr_opened[dev] = 0;
@@ -90,13 +92,14 @@ pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
return RET_ERROR (EIO);
}
- while (!ok && !PROCESS_ABORTING)
+ while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
{
DISABLE_INTR (flags);
- while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && !PROCESS_ABORTING)
+ while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
+ !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
{
- INTERRUPTIBLE_SLEEP_ON (server_procs[dev], server_wait_flag[dev]);
+ DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
}
if (mbox[dev] && msg_direction[dev] == A_TO_S)
@@ -158,9 +161,9 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
msg_direction[dev] = S_TO_A;
- if (appl_wait_flag)
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
{
- WAKE_UP (appl_proc);
+ WAKE_UP (appl_proc, appl_wait_flag);
}
}
@@ -185,12 +188,12 @@ pmgr_access (int dev, struct patmgr_info *rec)
mbox[dev] = rec;
msg_direction[dev] = A_TO_S;
- if (server_wait_flag[dev])
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
{
- WAKE_UP (server_procs[dev]);
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
}
- INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
if (msg_direction[dev] != S_TO_A)
{
@@ -239,12 +242,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
mbox[dev]->parm3 = p3;
msg_direction[dev] = A_TO_S;
- if (server_wait_flag[dev])
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
{
- WAKE_UP (server_procs[dev]);
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
}
- INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
if (mbox[dev])
KERNEL_FREE (mbox[dev]);
mbox[dev] = NULL;
diff --git a/sys/i386/isa/sound/pro_midi.c b/sys/i386/isa/sound/pro_midi.c
index 606657d403da..b9ffa26a9ab2 100644
--- a/sys/i386/isa/sound/pro_midi.c
+++ b/sys/i386/isa/sound/pro_midi.c
@@ -1,5 +1,5 @@
/*
- * Copyright by UWM -- comments to soft-eng@cs.uwm.edu
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,140 +37,148 @@
/** Structure for handling operations **/
-static struct generic_midi_operations pro_midi_operations = {
+static struct generic_midi_operations pro_midi_operations =
+{
- {"Pro_Audio_Spectrum 16 MV101", 0},
- pro_midi_open,
- pro_midi_close,
- pro_midi_write,
- pro_midi_read
+ {"Pro_Audio_Spectrum 16 MV101", 0},
+ pro_midi_open,
+ pro_midi_close,
+ pro_midi_write,
+ pro_midi_read
};
/*
- * Note! Note! Note!
- * Follow the same model for any other attach function you
+ * Note! Note! Note! Follow the same model for any other attach function you
* may write
*/
-long pro_midi_attach( long mem_start)
+long
+pro_midi_attach (long mem_start)
{
pro_midi_dev = num_generic_midis;
generic_midi_devs[num_generic_midis++] = &pro_midi_operations;
return mem_start;
-}
+}
-int pro_midi_open(int dev, int mode)
+int
+pro_midi_open (int dev, int mode)
{
- int intr_mask, s;
+ int intr_mask, s;
- s = splhigh();
+ s = splhigh ();
- /* Reset the input and output FIFO pointers */
+ /* Reset the input and output FIFO pointers */
- outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
- /* Get the interrupt status */
+ /* Get the interrupt status */
- intr_mask = inb(INTERRUPT_MASK);
+ intr_mask = inb (INTERRUPT_MASK);
- /* Enable MIDI IRQ */
+ /* Enable MIDI IRQ */
- intr_mask |= I_M_MIDI_IRQ_ENABLE;
- outb(INTERRUPT_MASK, intr_mask);
+ intr_mask |= I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
/* Enable READ/WRITE on MIDI port. This part is quite unsure though */
- outb(MIDI_CONTROL,M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
+ outb (MIDI_CONTROL, M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
/* Acknowledge pending interrupts */
- outb(MIDI_STATUS,0xff);
+ outb (MIDI_STATUS, 0xff);
- splx(s);
+ splx (s);
- return(ESUCCESS);
+ return (ESUCCESS);
}
-void pro_midi_close(int dev)
+void
+pro_midi_close (int dev)
{
- int intr_mask;
+ int intr_mask;
- /* Clean up */
+ /* Clean up */
- outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
- intr_mask = inb(INTERRUPT_MASK);
- intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
- outb(INTERRUPT_MASK,intr_mask);
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+ intr_mask = inb (INTERRUPT_MASK);
+ intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
- return;
+ return;
}
-int pro_midi_write(int dev, struct uio *uio)
+int
+pro_midi_write (int dev, struct uio *uio)
{
- int s;
- unsigned char data;
+ int s;
+ unsigned char data;
- /* printf("midi: Going to do write routine..\n"); */
- while(uio->uio_resid) {
+ /* printf("midi: Going to do write routine..\n"); */
+ while (uio->uio_resid)
+ {
- if ( uiomove(&data,1,uio) ) return(ENOTTY);
+ if (uiomove (&data, 1, uio))
+ return (ENOTTY);
- s = splhigh();
+ s = splhigh ();
- DELAY(30);
- outb(MIDI_DATA,data);
- DELAY(70); /* Ze best pause.. find a better one if
- * you can :)
- */
- splx(s);
- }
+ DELAY (30);
+ outb (MIDI_DATA, data);
+ DELAY (70); /* Ze best pause.. find a better one if you
+ * can :) */
+ splx (s);
+ }
- return(ESUCCESS);
+ return (ESUCCESS);
}
-int pro_midi_read(int dev, struct uio *uio)
+int
+pro_midi_read (int dev, struct uio *uio)
{
- int s;
- unsigned char data;
+ int s;
+ unsigned char data;
- s = splhigh();
+ s = splhigh ();
- /* For each uio_iov[] entry .... */
+ /* For each uio_iov[] entry .... */
- while (uio->uio_resid) {
+ while (uio->uio_resid)
+ {
- if((( inb(MIDI_STATUS) & M_S_INPUT_AVAIL) == 0 ) &&
- ((inb(MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0 ) )
+ if (((inb (MIDI_STATUS) & M_S_INPUT_AVAIL) == 0) &&
+ ((inb (MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0))
- data = 0xfe;
- else
- data = inb(MIDI_DATA);
+ data = 0xfe;
+ else
+ data = inb (MIDI_DATA);
- if ( uiomove(&data, 1 , uio)) {
+ if (uiomove (&data, 1, uio))
+ {
- printf("midi: Bad copyout()!\n");
- return(ENOTTY);
+ printf ("midi: Bad copyout()!\n");
+ return (ENOTTY);
- }
+ }
- }
- splx(s);
- return(ESUCCESS);
+ }
+ splx (s);
+ return (ESUCCESS);
}
diff --git a/sys/i386/isa/sound/sb.h b/sys/i386/isa/sound/sb.h
new file mode 100644
index 000000000000..bb8ae12d7e60
--- /dev/null
+++ b/sys/i386/isa/sound/sb.h
@@ -0,0 +1,28 @@
+#define DSP_RESET (sbc_base + 0x6)
+#define DSP_READ (sbc_base + 0xA)
+#define DSP_WRITE (sbc_base + 0xC)
+#define DSP_COMMAND (sbc_base + 0xC)
+#define DSP_STATUS (sbc_base + 0xC)
+#define DSP_DATA_AVAIL (sbc_base + 0xE)
+#define DSP_DATA_AVL16 (sbc_base + 0xF)
+#define MIXER_ADDR (sbc_base + 0x4)
+#define MIXER_DATA (sbc_base + 0x5)
+#define OPL3_LEFT (sbc_base + 0x0)
+#define OPL3_RIGHT (sbc_base + 0x2)
+#define OPL3_BOTH (sbc_base + 0x8)
+/* DSP Commands */
+
+#define DSP_CMD_SPKON 0xD1
+#define DSP_CMD_SPKOFF 0xD3
+#define DSP_CMD_DMAON 0xD0
+#define DSP_CMD_DMAOFF 0xD4
+
+#define IMODE_NONE 0
+#define IMODE_OUTPUT 1
+#define IMODE_INPUT 2
+#define IMODE_INIT 3
+#define IMODE_MIDI 4
+
+#define NORMAL_MIDI 0
+#define UART_MIDI 1
+
diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c
new file mode 100644
index 000000000000..b545f8cac222
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_dsp.c
@@ -0,0 +1,627 @@
+/*
+ * sound/sb16_dsp.c
+ *
+ * The low level driver for the SoundBlaster DSP chip.
+ *
+ * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
+ *
+ * based on SB-driver by (C) Hannu Savolainen
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#define DEB(x)
+#define DEB1(x)
+/*
+ #define DEB_DMARES
+ */
+#include "sound_config.h"
+#include "sb.h"
+#include "sb_mixer.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
+
+extern int sbc_base, sbc_minor, sbc_major;
+
+static int sb16_dsp_ok = 0;/* Set to 1 after successful initialization */
+static int dsp_16bit = 0;
+static int dsp_stereo = 0;
+static int dsp_current_speed = 8000; /*DSP_DEFAULT_SPEED; */
+static int dsp_busy = 0;
+static int dma16, dma8;
+static unsigned long dsp_count = 0;
+
+static int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or
+
+ IMODE_NONE */
+static int my_dev = 0;
+
+static volatile int intr_active = 0;
+
+static int sb16_dsp_open (int dev, int mode);
+static void sb16_dsp_close (int dev);
+static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
+static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
+static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
+static void sb16_dsp_reset (int dev);
+static void sb16_dsp_halt (int dev);
+static int dsp_set_speed (int);
+static int dsp_set_stereo (int);
+static void dsp_cleanup (void);
+int sb_reset_dsp (void);
+
+static struct audio_operations sb16_dsp_operations =
+{
+ "SoundBlaster 16",
+ NOTHING_SPECIAL,
+ sb16_dsp_open,
+ sb16_dsp_close,
+ sb16_dsp_output_block,
+ sb16_dsp_start_input,
+ sb16_dsp_ioctl,
+ sb16_dsp_prepare_for_input,
+ sb16_dsp_prepare_for_output,
+ sb16_dsp_reset,
+ sb16_dsp_halt,
+ NULL,
+ NULL
+};
+
+static int
+sb_dsp_command01 (unsigned char val)
+{
+ int i = 1 << 16;
+
+ while (--i & (!INB (DSP_STATUS) & 0x80));
+ if (!i)
+ printk ("SB16 sb_dsp_command01 Timeout\n");
+ return sb_dsp_command (val);
+}
+
+static int
+wait_data_avail (unsigned long t)
+{
+ int loopc = 5000000;
+
+ t += GET_TIME ();
+ do
+ {
+ if (INB (DSP_DATA_AVAIL) & 0x80)
+ return 1;
+ }
+ while (--loopc && GET_TIME () < t);
+ printk ("!data_avail l=%d\n", loopc);
+ return 0;
+}
+
+static int
+read_dsp (int t)
+{
+ if (!wait_data_avail ((unsigned long) t))
+ return -1;
+ else
+ return INB (DSP_READ);
+}
+
+static int
+dsp_ini2 (void)
+{
+#if 0
+ /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03); */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x76); /* E0 ??? */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x30); /* A0 ??? */
+ sb_dsp_command (0xe4);
+ sb_dsp_command (0xaa);
+ sb_dsp_command (0xe8);
+ if (read_dsp (100) != 0xaa)
+ printk ("Error dsp_ini2\n");
+#endif
+ return 0;
+}
+
+/*
+ static char *dsp_getmessage(unsigned char command,int maxn)
+ {
+ static char buff[100];
+ int n=0;
+
+ sb_dsp_command(command);
+ while(n<maxn && wait_data_avail(2L)) {
+ buff[++n]=INB(DSP_READ);
+ if(!buff[n])
+ break;
+ }
+ buff[0]=n;
+ return buff;
+ }
+
+ static void dsp_showmessage(unsigned char command,int len)
+ {
+ int n;
+ unsigned char *c;
+ c=dsp_getmessage(command,len);
+ printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
+ for(n=1;n<=c[0];n++)
+ if(c[n]>=' ' & c[n]<='z')
+ printk("%c",c[n]);
+ else
+ printk("|%x|",c[n]);
+ printk("\n");
+ }
+ */
+static int
+dsp_set_speed (int mode)
+{
+ DEB (printk ("dsp_set_speed(%d)\n", mode));
+ if (mode)
+ {
+ if (mode < 5000)
+ mode = 5000;
+ if (mode > 44100)
+ mode = 44100;
+ dsp_current_speed = mode;
+ }
+ return mode;
+}
+
+static int
+dsp_set_stereo (int mode)
+{
+ DEB (printk ("dsp_set_stereo(%d)\n", mode));
+
+ dsp_stereo = mode;
+
+ return mode;
+}
+
+static int
+dsp_set_bits (int arg)
+{
+ DEB (printk ("dsp_set_bits(%d)\n", arg));
+
+ if (arg)
+ switch (arg)
+ {
+ case 8:
+ dsp_16bit = 0;
+ break;
+ case 16:
+ dsp_16bit = 1;
+ break;
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ return dsp_16bit ? 16 : 8;
+}
+
+static int
+sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return dsp_set_speed (arg);
+ return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return dsp_current_speed;
+ return IOCTL_OUT (arg, dsp_current_speed);
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return dsp_set_stereo (arg);
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return dsp_stereo + 1;
+ return IOCTL_OUT (arg, dsp_stereo + 1);
+
+ case SNDCTL_DSP_SAMPLESIZE:
+ if (local)
+ return dsp_set_bits (arg);
+ return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return dsp_16bit ? 16 : 8;
+ return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ if (IOCTL_IN (arg) > 1)
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static int
+sb16_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ DEB (printk ("sb16_dsp_open()\n"));
+ if (!sb16_dsp_ok)
+ {
+ printk ("SB16 Error: SoundBlaster board not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (intr_active)
+ return RET_ERROR (EBUSY);
+
+ retval = sb_get_irq ();
+ if (retval < 0)
+ return retval;
+
+ if (ALLOC_DMA_CHN (dma8))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma8);
+ sb_free_irq ();
+ return RET_ERROR (EBUSY);
+ }
+
+ if (dma16 != dma8)
+ if (ALLOC_DMA_CHN (dma16))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma16);
+ sb_free_irq ();
+ RELEASE_DMA_CHN (dma8);
+ return RET_ERROR (EBUSY);
+ }
+
+ dsp_ini2 ();
+
+ irq_mode = IMODE_NONE;
+ dsp_busy = 1;
+
+ return 0;
+}
+
+static void
+sb16_dsp_close (int dev)
+{
+ unsigned long flags;
+
+ DEB (printk ("sb16_dsp_close()\n"));
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+
+ DISABLE_INTR (flags);
+ RELEASE_DMA_CHN (dma8);
+
+ if (dma16 != dma8)
+ RELEASE_DMA_CHN (dma16);
+ sb_free_irq ();
+ dsp_cleanup ();
+ dsp_busy = 0;
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("output_block: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ }
+ sb_dsp_command (0x41);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+}
+
+static void
+sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("start_input: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ }
+
+ sb_dsp_command (0x42);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+}
+
+static int
+sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static int
+sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static void
+dsp_cleanup (void)
+{
+ irq_mode = IMODE_NONE;
+ intr_active = 0;
+}
+
+static void
+sb16_dsp_reset (int dev)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ sb_reset_dsp ();
+ dsp_cleanup ();
+
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_halt (int dev)
+{
+ if (dsp_16bit)
+ {
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+ }
+ else
+ {
+ sb_dsp_command01 (0xda);
+ sb_dsp_command01 (0xd0);
+ }
+}
+
+static void
+set_irq_hw (int level)
+{
+ int ival;
+
+ switch (level)
+ {
+ case 5:
+ ival = 2;
+ break;
+ case 7:
+ ival = 4;
+ break;
+ case 10:
+ ival = 8;
+ break;
+ default:
+ printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
+ return;
+ }
+ sb_setmixer (IRQ_NR, ival);
+}
+
+long
+sb16_dsp_init (long mem_start, struct address_info *hw_config)
+{
+ if (sbc_major < 4)
+ return mem_start;
+
+#ifndef SCO
+ sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
+#endif
+
+#ifdef __FreeBSD__
+ printk ("snd6: <%s>", sb16_dsp_operations.name);
+#else
+ printk (" <%s>", sb16_dsp_operations.name);
+#endif
+
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+#ifndef NO_AUTODMA
+ sound_buffcounts[my_dev] = 1;
+ sound_dma_automode[my_dev] = 1;
+#else
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_dma_automode[my_dev] = 0;
+#endif
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
+ sb16_dsp_ok = 1;
+ return mem_start;
+}
+
+int
+sb16_dsp_detect (struct address_info *hw_config)
+{
+ struct address_info *sb_config;
+
+ if (sb16_dsp_ok)
+ return 1; /* Already initialized */
+
+ if (!(sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ printk ("SB16 Error: Plain SB not configured\n");
+ return 0;
+ }
+
+ /* sb_setmixer(OPSW,0xf);
+ if(sb_getmixer(OPSW)!=0xf)
+ return 0; */
+
+ if (!sb_reset_dsp ())
+ return 0;
+
+ if (hw_config->dma < 4)
+ if (hw_config->dma != sb_config->dma)
+ {
+ printk ("SB16 Error: Invalid DMA channel %d/%d\n",
+ sb_config->dma, hw_config->dma);
+ return 0;
+ }
+
+ dma16 = hw_config->dma;
+ dma8 = sb_config->dma;
+ set_irq_hw (sb_config->irq);
+ sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+
+ DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+
+ /*
+ dsp_showmessage(0xe3,99);
+ */
+ sb16_dsp_ok = 1;
+ return 1;
+}
+
+void
+sb16_dsp_interrupt (int unused)
+{
+ int data;
+
+ data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */
+
+ if (intr_active)
+ switch (irq_mode)
+ {
+ case IMODE_OUTPUT:
+ intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
+ break;
+
+ case IMODE_INPUT:
+ intr_active = 0;
+ DMAbuf_inputintr (my_dev);
+ break;
+
+ default:
+ printk ("SoundBlaster: Unexpected interrupt\n");
+ }
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c
new file mode 100644
index 000000000000..39808c80fe0d
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_midi.c
@@ -0,0 +1,287 @@
+/*
+ * sound/sb16_midi.c
+ *
+ * The low level driver for the MPU-401 UART emulation of the SB16.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
+
+#define DATAPORT (sb16midi_base) /* MPU-401 Data I/O Port on IBM */
+#define COMDPORT (sb16midi_base+1) /* MPU-401 Command Port on IBM */
+#define STATPORT (sb16midi_base+1) /* MPU-401 Status Port on IBM */
+
+#define sb16midi_status() INB(STATPORT)
+#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
+#define output_ready() (!(sb16midi_status()&OUTPUT_READY))
+#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT)
+#define sb16midi_read() INB(DATAPORT)
+#define sb16midi_write(byte) OUTB(byte, DATAPORT)
+
+#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */
+#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */
+#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */
+#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */
+#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */
+
+static int sb16midi_opened = 0;
+static int sb16midi_base = 0x330;
+static int sb16midi_detected = 0;
+static int my_dev;
+
+static int reset_sb16midi (void);
+static void (*midi_input_intr) (int dev, unsigned char data);
+
+extern int sbc_major;
+
+static void
+sb16midi_input_loop (void)
+{
+
+ while (input_avail ())
+ {
+ unsigned char c = sb16midi_read ();
+
+ if (sb16midi_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
+}
+
+void
+sb16midiintr (int unit)
+{
+ if (input_avail ())
+ sb16midi_input_loop ();
+}
+
+static int
+sb16midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ if (sb16midi_opened)
+ {
+ return RET_ERROR (EBUSY);
+ }
+
+ sb16midi_input_loop ();
+
+ midi_input_intr = input;
+ sb16midi_opened = mode;
+
+ return 0;
+}
+
+static void
+sb16midi_close (int dev)
+{
+ sb16midi_opened = 0;
+}
+
+static int
+sb16midi_out (int dev, unsigned char midi_byte)
+{
+ int timeout;
+ unsigned long flags;
+
+ /*
+ * Test for input since pending input seems to block the output.
+ */
+
+ DISABLE_INTR (flags);
+
+ if (input_avail ())
+ sb16midi_input_loop ();
+
+ RESTORE_INTR (flags);
+
+ /*
+ * Sometimes it takes about 13000 loops before the output becomes ready
+ * (After reset). Normally it takes just about 10 loops.
+ */
+
+ for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */
+
+ if (!output_ready ())
+ {
+ printk ("MPU-401: Timeout\n");
+ return 0;
+ }
+
+ sb16midi_write (midi_byte);
+ return 1;
+}
+
+static int
+sb16midi_command (int dev, unsigned char midi_byte)
+{
+ return 1;
+}
+
+static int
+sb16midi_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+sb16midi_kick (int dev)
+{
+}
+
+static int
+sb16midi_buffer_status (int dev)
+{
+ return 0; /* No data in buffers */
+}
+
+static struct midi_operations sb16midi_operations =
+{
+ {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
+ sb16midi_open,
+ sb16midi_close,
+ sb16midi_ioctl,
+ sb16midi_out,
+ sb16midi_start_read,
+ sb16midi_end_read,
+ sb16midi_kick,
+ sb16midi_command,
+ sb16midi_buffer_status
+};
+
+
+long
+attach_sb16midi (long mem_start, struct address_info *hw_config)
+{
+ int ok, timeout;
+ unsigned long flags;
+
+ sb16midi_base = hw_config->io_base;
+
+ if (!sb16midi_detected)
+ return RET_ERROR (EIO);
+
+ DISABLE_INTR (flags);
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ sb16midi_cmd (UART_MODE_ON);
+
+ ok = 0;
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ RESTORE_INTR (flags);
+
+#ifdef __FreeBSD__
+ printk ("snd7: <SoundBlaster MPU-401>");
+#else
+ printk (" <SoundBlaster MPU-401>");
+#endif
+
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &sb16midi_operations;
+ return mem_start;
+}
+
+static int
+reset_sb16midi (void)
+{
+ unsigned long flags;
+ int ok, timeout, n;
+
+ /*
+ * Send the RESET command. Try again if no success at the first time.
+ */
+
+ ok = 0;
+
+ DISABLE_INTR (flags);
+
+ for (n = 0; n < 2 && !ok; n++)
+ {
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */
+
+ /*
+ * Wait at least 25 msec. This method is not accurate so let's make the
+ * loop bit longer. Cannot sleep since this is called during boot.
+ */
+
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ }
+
+ sb16midi_opened = 0;
+ if (ok)
+ sb16midi_input_loop (); /* Flush input before enabling interrupts */
+
+ RESTORE_INTR (flags);
+
+ return ok;
+}
+
+
+int
+probe_sb16midi (struct address_info *hw_config)
+{
+ int ok = 0;
+
+ sb16midi_base = hw_config->io_base;
+ if (sbc_major < 4)
+ return 0; /* SB16 not detected */
+
+ if (sb_get_irq () < 0)
+ return 0;
+
+ ok = reset_sb16midi ();
+
+ sb16midi_detected = ok;
+ return ok;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sb_card.c b/sys/i386/isa/sound/sb_card.c
index e2527c51a35e..f7588e1ca172 100644
--- a/sys/i386/isa/sound/sb_card.c
+++ b/sys/i386/isa/sound/sb_card.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/sb_card.c
- *
+ * sound/sb_card.c
+ *
* Detection routine for the SoundBlaster cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -13,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -25,7 +24,7 @@
* 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.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c
index 4c273646bdd3..17fb4b70dc6a 100644
--- a/sys/i386/isa/sound/sb_dsp.c
+++ b/sys/i386/isa/sound/sb_dsp.c
@@ -1,7 +1,7 @@
/*
- * linux/kernel/chr_drv/sound/sb_dsp.c
+ * sound/sb_dsp.c
*
- * The low level driver for the SoundBlaster DS chips.
+ * The low level driver for the SoundBlaster DSP chip.
*
* Copyright by Hannu Savolainen 1993
*
@@ -25,152 +25,81 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * The mixer support is based on the SB-BSD 1.5 driver by (C) Steve Haehnichen
- * <shaehnic@ucsd.edu>
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support Sound Galaxy NX Pro
+ *
*/
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
+#include "sb.h"
+#include "sb_mixer.h"
#undef SB_TEST_IRQ
-#define DSP_RESET (sbc_base + 0x6)
-#define DSP_READ (sbc_base + 0xA)
-#define DSP_WRITE (sbc_base + 0xC)
-#define DSP_COMMAND (sbc_base + 0xC)
-#define DSP_STATUS (sbc_base + 0xC)
-#define DSP_DATA_AVAIL (sbc_base + 0xE)
-#define MIXER_ADDR (sbc_base + 0x4)
-#define MIXER_DATA (sbc_base + 0x5)
-#define OPL3_LEFT (sbc_base + 0x0)
-#define OPL3_RIGHT (sbc_base + 0x2)
-#define OPL3_BOTH (sbc_base + 0x8)
-
-static int sbc_base = 0;
+int sbc_base = 0;
static int sbc_irq = 0;
-
-#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
-
-#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD | SOUND_MASK_VOLUME)
-
-/*
- * Mixer registers
- *
- * NOTE! RECORD_SRC == IN_FILTER
- */
-
-#define VOC_VOL 0x04
-#define MIC_VOL 0x0A
-#define MIC_MIX 0x0A
-#define RECORD_SRC 0x0C
-#define IN_FILTER 0x0C
-#define OUT_FILTER 0x0E
-#define MASTER_VOL 0x22
-#define FM_VOL 0x26
-#define CD_VOL 0x28
-#define LINE_VOL 0x2E
-
-#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
-#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
-#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
-#define FILT_OFF (1 << 5)
-
-/* Convenient byte masks */
-#define B1(x) ((x) & 0x01)
-#define B2(x) ((x) & 0x03)
-#define B3(x) ((x) & 0x07)
-#define B4(x) ((x) & 0x0f)
-#define B5(x) ((x) & 0x1f)
-#define B6(x) ((x) & 0x3f)
-#define B7(x) ((x) & 0x7f)
-#define B8(x) ((x) & 0xff)
-#define F(x) (!!(x)) /* 0 or 1 only */
-
-#define MONO_DAC 0x00
-#define STEREO_DAC 0x02
-
-/* DSP Commands */
-
-#define DSP_CMD_SPKON 0xD1
-#define DSP_CMD_SPKOFF 0xD3
+static int open_mode=0;
/*
* The DSP channel can be used either for input or output. Variable
- * 'irq_mode' will be set when the program calls read or write first time
+ * 'sb_irq_mode' will be set when the program calls read or write first time
* after open. Current version doesn't support mode changes without closing
* and reopening the device. Support for this feature may be implemented in a
* future version of this driver.
*/
-#define IMODE_NONE 0
-#define IMODE_OUTPUT 1
-#define IMODE_INPUT 2
-#define IMODE_INIT 3
-#define IMODE_MIDI 4
-
-#define NORMAL_MIDI 0
-#define UART_MIDI 1
-
-static int sb_dsp_ok = 0; /* Set to 1 after successful initialization */
+int sb_dsp_ok = 0; /* Set to 1 after successful initialization */
static int midi_disabled = 0;
-static int dsp_highspeed = 0, dsp_stereo = 0;
+int sb_dsp_highspeed = 0;
+int sbc_major = 1;
+int sbc_minor = 0; /* DSP version */
+static int dsp_stereo = 0;
static int dsp_current_speed = DSP_DEFAULT_SPEED;
+static int sb16 = 0;
+static int irq_verified = 0;
-#ifndef EXCLUDE_SBPRO
-static int rec_devices = SOUND_MASK_MIC;
-static int hi_filter = 0, filter_in = 0, filter_out = 0;
+int sb_midi_mode = NORMAL_MIDI;
+int sb_midi_busy = 0; /* 1 if the process has output to MIDI */
+int sb_dsp_busy = 0;
-#endif
+volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
-static int midi_mode = NORMAL_MIDI;
-static int midi_busy = 0; /* 1 if the process has output to MIDI */
-static int dsp_busy = 0;
-
-static volatile int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
* or IMODE_NONE */
static volatile int irq_ok = 0;
-static int dsp_model = 1; /* DSP version */
-static int dsp_mono = 1; /* 1 SB, 0 SB Pro */
-static int duplex_midi = 0;
+int sb_duplex_midi = 0;
static int my_dev = 0;
-static volatile int intr_active = 0;
+volatile int sb_intr_active = 0;
static int dsp_speed (int);
static int dsp_set_stereo (int mode);
-static int dsp_command (unsigned char val);
-
-#ifndef EXCLUDE_SBPRO
-static void setmixer (unsigned char port, unsigned char value);
-static int getmixer (unsigned char port);
-static void init_mixer (void);
-static int detect_mixer (void);
-
-#endif
+int sb_dsp_command (unsigned char val);
#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
/* Common code for the midi and pcm functions */
-static int
-dsp_command (unsigned char val)
+int
+sb_dsp_command (unsigned char val)
{
- int i, limit;
+ int i;
+ unsigned long limit;
- limit = GET_TIME () + 10; /* The timeout is 0.1 secods */
+ limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */
/*
- * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
+ * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
* disabled also. However the timeout situation is a abnormal condition.
* Normally the DSP should be ready to accept commands after just couple of
* loops.
*/
- for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
+ for (i = 0; i < 500000 && GET_TIME () < limit; i++)
{
if ((INB (DSP_STATUS) & 0x80) == 0)
{
@@ -179,42 +108,60 @@ dsp_command (unsigned char val)
}
}
- printk ("SoundBlaster: DSP Command(%02x) Timeout.\n", val);
+ printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
printk ("IRQ conflict???\n");
return 0;
}
void
-sbintr (int unused)
+sbintr (int unit)
{
- int status, data;
+ int status;
+
+#ifndef EXCLUDE_SBPRO
+ if (sb16)
+ {
+ unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */
+
+#ifndef EXCLUDE_SB16
+ if (src & 3)
+ sb16_dsp_interrupt (unit);
+
+#ifndef EXCLUDE_MIDI
+ if (src & 4)
+ sb16midiintr (unit); /* MPU401 interrupt */
+#endif
+
+#endif
+
+ if (!(src & 1))
+ return; /* Not a DSP interupt */
+ }
+#endif
status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
- if (intr_active)
- switch (irq_mode)
+ if (sb_intr_active)
+ switch (sb_irq_mode)
{
case IMODE_OUTPUT:
- intr_active = 0;
- DMAbuf_outputintr (my_dev);
+ sb_intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
break;
case IMODE_INPUT:
- intr_active = 0;
+ sb_intr_active = 0;
DMAbuf_inputintr (my_dev);
/* A complete buffer has been input. Let's start new one */
break;
case IMODE_INIT:
- intr_active = 0;
+ sb_intr_active = 0;
irq_ok = 1;
break;
case IMODE_MIDI:
- printk ("+");
- data = INB (DSP_READ);
- printk ("%02x", data);
-
+ sb_midi_interrupt (unit);
break;
default:
@@ -222,40 +169,36 @@ sbintr (int unused)
}
}
-static int
-set_dsp_irq (int interrupt_level)
-{
- int retcode = EINVAL;
+static int sb_irq_usecount = 0;
-#ifdef linux
- struct sigaction sa;
+int
+sb_get_irq (void)
+{
+ int ok;
- sa.sa_handler = sbintr;
+ if (!sb_irq_usecount)
+ if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+ return ok;
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
+ sb_irq_usecount++;
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
+ return 0;
+}
- retcode = irqaction (interrupt_level, &sa);
+void
+sb_free_irq (void)
+{
+ if (!sb_irq_usecount)
+ return;
- if (retcode < 0)
- {
- printk ("SoundBlaster: IRQ%d already in use\n", interrupt_level);
- }
+ sb_irq_usecount--;
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
+ if (!sb_irq_usecount)
+ snd_release_irq (sbc_irq);
}
-static int
-reset_dsp (void)
+int
+sb_reset_dsp (void)
{
int loopc;
@@ -283,9 +226,9 @@ static void
dsp_speaker (char state)
{
if (state)
- dsp_command (DSP_CMD_SPKON);
+ sb_dsp_command (DSP_CMD_SPKON);
else
- dsp_command (DSP_CMD_SPKOFF);
+ sb_dsp_command (DSP_CMD_SPKOFF);
}
static int
@@ -293,61 +236,81 @@ dsp_speed (int speed)
{
unsigned char tconst;
unsigned long flags;
-
+ int max_speed = 44100;
if (speed < 4000)
speed = 4000;
- if (speed > 44100)
- speed = 44100; /* Invalid speed */
+ /*
+ * Older SB models don't support higher speeds than 22050.
+ */
+
+ if (sbc_major < 2 ||
+ (sbc_major == 2 && sbc_minor == 0))
+ max_speed = 22050;
- if (dsp_model == 1 && speed > 22050)
- speed = 22050;
- /* SB Classic doesn't support higher speed */
+ /*
+ * SB models earlier than SB Pro have low limit for the input speed.
+ */
+ if (open_mode != OPEN_WRITE) /* Recording is possible */
+ if (sbc_major < 3) /* Limited input speed with these cards */
+ if (sbc_major == 2 && sbc_minor > 0)
+ max_speed = 15000;
+ else
+ max_speed = 13000;
+ if (speed > max_speed)
+ speed = max_speed; /* Invalid speed */
if (dsp_stereo && speed > 22050)
speed = 22050;
/* Max. stereo speed is 22050 */
- if ((speed > 22050) && midi_busy)
+ if ((speed > 22050) && sb_midi_busy)
{
printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
speed = 22050;
}
if (dsp_stereo)
- speed <<= 1;
+ speed *= 2;
/* Now the speed should be valid */
if (speed > 22050)
{ /* High speed mode */
- tconst = (unsigned char) ((65536 - (256000000 / speed)) >> 8);
- dsp_highspeed = 1;
+ int tmp;
+
+ tconst = (unsigned char) ((65536 -
+ ((256000000 + speed / 2) / speed)) >> 8);
+ sb_dsp_highspeed = 1;
DISABLE_INTR (flags);
- if (dsp_command (0x40))
- dsp_command (tconst);
+ if (sb_dsp_command (0x40))
+ sb_dsp_command (tconst);
RESTORE_INTR (flags);
- speed = (256000000 / (65536 - (tconst << 8)));
+ tmp = 65536 - (tconst << 8);
+ speed = (256000000 + tmp / 2) / tmp;
}
else
{
- dsp_highspeed = 0;
- tconst = (256 - (1000000 / speed)) & 0xff;
+ int tmp;
+
+ sb_dsp_highspeed = 0;
+ tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
DISABLE_INTR (flags);
- if (dsp_command (0x40)) /* Set time constant */
- dsp_command (tconst);
+ if (sb_dsp_command (0x40))/* Set time constant */
+ sb_dsp_command (tconst);
RESTORE_INTR (flags);
- speed = 1000000 / (256 - tconst);
+ tmp = 256 - tconst;
+ speed = (1000000 + tmp / 2) / tmp;
}
if (dsp_stereo)
- speed >>= 1;
+ speed /= 2;
dsp_current_speed = speed;
return speed;
@@ -358,49 +321,47 @@ dsp_set_stereo (int mode)
{
dsp_stereo = 0;
- if (dsp_mono == 1)
+#ifdef EXCLUDE_SBPRO
+ return 0;
+#else
+ if (sbc_major < 3 || sb16)
return 0; /* Sorry no stereo */
- if (mode && midi_busy)
+ if (mode && sb_midi_busy)
{
printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
return 0;
}
dsp_stereo = !!mode;
-
-#ifndef EXCLUDE_SBPRO
- setmixer (OUT_FILTER, ((getmixer (OUT_FILTER) & ~STEREO_DAC)
- | (mode ? STEREO_DAC : MONO_DAC)));
+ return dsp_stereo;
#endif
- dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
- * changes */
- return mode;
}
static void
-sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
+sb_dsp_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
- if (!irq_mode)
+ if (!sb_irq_mode)
dsp_speaker (ON);
- irq_mode = IMODE_OUTPUT;
+ sb_irq_mode = IMODE_OUTPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
- if (dsp_highspeed)
+ if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (dsp_command (0x48)) /* High speed size */
+ if (sb_dsp_command (0x48))/* High speed size */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
- dsp_command (0x91); /* High speed 8 bit DAC */
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x91);/* High speed 8 bit DAC */
}
else
printk ("SB Error: Unable to start (high speed) DAC\n");
@@ -409,43 +370,44 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
- if (dsp_command (0x14)) /* 8-bit DAC (DMA) */
+ if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
}
else
printk ("SB Error: Unable to start DAC\n");
RESTORE_INTR (flags);
}
- intr_active = 1;
+ sb_intr_active = 1;
}
static void
-sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
+sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
+ int restart_dma)
{
/* Start a DMA input to the buffer pointed by dmaqtail */
unsigned long flags;
- if (!irq_mode)
+ if (!sb_irq_mode)
dsp_speaker (OFF);
- irq_mode = IMODE_INPUT;
+ sb_irq_mode = IMODE_INPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
- if (dsp_highspeed)
+ if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (dsp_command (0x48)) /* High speed size */
+ if (sb_dsp_command (0x48))/* High speed size */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
- dsp_command (0x99); /* High speed 8 bit ADC */
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x99);/* High speed 8 bit ADC */
}
else
printk ("SB Error: Unable to start (high speed) ADC\n");
@@ -454,23 +416,23 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
- if (dsp_command (0x24)) /* 8-bit ADC (DMA) */
+ if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
}
else
printk ("SB Error: Unable to start ADC\n");
RESTORE_INTR (flags);
}
- intr_active = 1;
+ sb_intr_active = 1;
}
static void
dsp_cleanup (void)
{
- intr_active = 0;
+ sb_intr_active = 0;
}
static int
@@ -478,6 +440,17 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (OFF);
+
+ if (sbc_major == 3) /* SB Pro */
+ {
+ if (dsp_stereo)
+ sb_dsp_command (0xa8);
+ else
+ sb_dsp_command (0xa0);
+
+ dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels
+ * changes */
+ }
return 0;
}
@@ -486,6 +459,15 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (ON);
+
+#ifndef EXCLUDE_SBPRO
+ if (sbc_major == 3) /* SB Pro */
+ {
+ sb_mixer_set_stereo (dsp_stereo);
+ dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels
+ * changes */
+ }
+#endif
return 0;
}
@@ -495,50 +477,80 @@ sb_dsp_halt_xfer (int dev)
}
static int
-sb_dsp_open (int dev, int mode)
+verify_irq (void)
{
- int retval;
+#if 0
+ DEFINE_WAIT_QUEUE (testq, testf);
- if (!sb_dsp_ok)
+ irq_ok = 0;
+
+ if (sb_get_irq () == -1)
{
- printk ("SB Error: SoundBlaster board not installed\n");
- return RET_ERROR (ENXIO);
+ printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
+ return 0;
}
+
+ sb_irq_mode = IMODE_INIT;
+
+ sb_dsp_command (0xf2); /* This should cause immediate interrupt */
+
+ DO_SLEEP (testq, testf, HZ / 5);
+
+ sb_free_irq ();
+
if (!irq_ok)
{
- printk ("SB Error: Incorrect IRQ setting (%d)\n", sbc_irq);
+ printk ("SB Warning: IRQ%d test not passed!", sbc_irq);
+ irq_ok = 1;
+ }
+#else
+ irq_ok = 1;
+#endif
+ return irq_ok;
+}
+
+static int
+sb_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: SoundBlaster board not installed\n");
return RET_ERROR (ENXIO);
}
- if (intr_active || (midi_busy && midi_mode == UART_MIDI))
+ if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
{
printk ("SB: PCM not possible during MIDI input\n");
return RET_ERROR (EBUSY);
}
- if (mode != OPEN_READ && mode != OPEN_WRITE)
+ if (!irq_verified)
{
- printk ("SoundBlaster error: DAC and ACD not possible simultaneously\n");
- return RET_ERROR (EINVAL);
+ verify_irq ();
+ irq_verified = 1;
}
+ else if (!irq_ok)
+ printk ("SB Warning: Incorrect IRQ setting %d\n",
+ sbc_irq);
- retval = set_dsp_irq (sbc_irq);
+ retval = sb_get_irq ();
if (retval)
return retval;
if (!DMAbuf_open_dma (dev))
{
- RELEASE_IRQ (sbc_irq);
+ sb_free_irq ();
printk ("SB: DMA Busy\n");
return RET_ERROR (EBUSY);
}
- dsp_set_stereo (OFF);
- dsp_speed (DSP_DEFAULT_SPEED);
- irq_mode = IMODE_NONE;
+ sb_irq_mode = IMODE_NONE;
- dsp_busy = 1;
+ sb_dsp_busy = 1;
+ open_mode = mode;
return 0;
}
@@ -547,12 +559,12 @@ static void
sb_dsp_close (int dev)
{
DMAbuf_close_dma (dev);
- RELEASE_IRQ (sbc_irq);
+ sb_free_irq ();
dsp_cleanup ();
- dsp_speed (DSP_DEFAULT_SPEED);
- dsp_set_stereo (OFF);
dsp_speaker (OFF);
- dsp_busy = 0;
+ sb_dsp_busy = 0;
+ sb_dsp_highspeed = 0;
+ open_mode = 0;
}
static int
@@ -573,6 +585,8 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
break;
@@ -614,7 +628,8 @@ sb_dsp_reset (int dev)
DISABLE_INTR (flags);
- reset_dsp ();
+ sb_reset_dsp ();
+ dsp_speed (dsp_current_speed);
dsp_cleanup ();
RESTORE_INTR (flags);
@@ -631,542 +646,19 @@ sb_dsp_detect (struct address_info *hw_config)
if (sb_dsp_ok)
return 0; /* Already initialized */
- if (!reset_dsp ())
+ if (!sb_reset_dsp ())
return 0;
return 1; /* Detected */
}
-#ifndef EXCLUDE_SBPRO
-
-static void
-setmixer (unsigned char port, unsigned char value)
-{
- OUTB (port, MIXER_ADDR); /* Select register */
- tenmicrosec ();
- OUTB (value, MIXER_DATA);
- tenmicrosec ();
-}
-
-static int
-getmixer (unsigned char port)
-{
- int val;
-
- OUTB (port, MIXER_ADDR); /* Select register */
- tenmicrosec ();
- val = INB (MIXER_DATA);
- tenmicrosec ();
-
- return val;
-}
-
-static int
-detect_mixer (void)
-{
- /*
- * Detect the mixer by changing parameters of two volume channels. If the
- * values read back match with the values written, the mixer is there (is
- * it?)
- */
- setmixer (FM_VOL, 0xff);
- setmixer (VOC_VOL, 0x33);
-
- if (getmixer (FM_VOL) != 0xff)
- return 0; /* No match */
- if (getmixer (VOC_VOL) != 0x33)
- return 0;
-
- return 1;
-}
-
-static void
-init_mixer (void)
-{
- setmixer (MASTER_VOL, 0xbb);
- setmixer (VOC_VOL, 0x99);
- setmixer (LINE_VOL, 0xbb);
- setmixer (FM_VOL, 0x99);
- setmixer (CD_VOL, 0x11);
- setmixer (MIC_MIX, 0x11);
- setmixer (RECORD_SRC, 0x31);
- setmixer (OUT_FILTER, 0x31);
-}
-
-static void
-set_filter (int record_source, int hifreq_filter, int filter_input, int filter_output)
-{
- setmixer (RECORD_SRC, (record_source
- | (hifreq_filter ? FREQ_HI : FREQ_LOW)
- | (filter_input ? FILT_ON : FILT_OFF)));
-
- setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC)
- | (filter_output ? FILT_ON : FILT_OFF)));
-
- hi_filter = hifreq_filter;
- filter_in = filter_input;
- filter_out = filter_output;
-}
-
-static int
-mixer_output (int right_vol, int left_vol, int div, int device)
-{
- int left = ((left_vol * div) + 50) / 100;
- int right = ((right_vol * div) + 50) / 100;
-
- setmixer (device, ((left & 0xf) << 4) | (right & 0xf));
-
- return (left_vol | (right_vol << 8));
-}
-
-static int
-sbp_mixer_set (int whichDev, unsigned int level)
-{
- int left, right, devmask;
-
- left = level & 0x7f;
- right = (level & 0x7f00) >> 8;
-
- switch (whichDev)
- {
- case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
- return mixer_output (right, left, 15, MASTER_VOL);
- break;
- case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
- return mixer_output (right, left, 15, FM_VOL);
- break;
- case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
- return mixer_output (right, left, 15, VOC_VOL);
- break;
- case SOUND_MIXER_LINE: /* External line (0-15) */
- return mixer_output (right, left, 15, LINE_VOL);
- break;
- case SOUND_MIXER_CD: /* CD (0-15) */
- return mixer_output (right, left, 15, CD_VOL);
- break;
- case SOUND_MIXER_MIC: /* External microphone (0-7) */
- return mixer_output (right, left, 7, MIC_VOL);
- break;
-
- case SOUND_MIXER_RECSRC:
- devmask = level & POSSIBLE_RECORDING_DEVICES;
-
- if (devmask != SOUND_MASK_MIC &&
- devmask != SOUND_MASK_LINE &&
- devmask != SOUND_MASK_CD)
- { /* More than one devices selected. Drop the
- * previous selection */
- devmask &= ~rec_devices;
- }
-
- if (devmask != SOUND_MASK_MIC &&
- devmask != SOUND_MASK_LINE &&
- devmask != SOUND_MASK_CD)
- { /* More than one devices selected. Default to
- * mic */
- devmask = SOUND_MASK_MIC;
- }
-
- if (devmask ^ rec_devices)/* Input source changed */
- {
- switch (devmask)
- {
-
- case SOUND_MASK_MIC:
- set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
- break;
-
- case SOUND_MASK_LINE:
- set_filter (SRC_LINE, hi_filter, filter_in, filter_out);
- break;
-
- case SOUND_MASK_CD:
- set_filter (SRC_CD, hi_filter, filter_in, filter_out);
- break;
-
- default:
- set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
- }
- }
-
- rec_devices = devmask;
-
- return rec_devices;
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
-
-}
-
-static int
-mixer_input (int div, int device)
-{
- int level, left, right, half;
-
- level = getmixer (device);
- half = div / 2;
-
- left = ((((level & 0xf0) >> 4) * 100) + half) / div;
- right = (((level & 0x0f) * 100) + half) / div;
-
- return (right << 8) | left;
-}
-
-static int
-sbp_mixer_get (int whichDev)
-{
-
- switch (whichDev)
- {
- case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
- return mixer_input (15, MASTER_VOL);
- break;
- case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
- return mixer_input (15, FM_VOL);
- break;
- case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
- return mixer_input (15, VOC_VOL);
- break;
- case SOUND_MIXER_LINE: /* External line (0-15) */
- return mixer_input (15, LINE_VOL);
- break;
- case SOUND_MIXER_CD: /* CD (0-15) */
- return mixer_input (15, CD_VOL);
- break;
- case SOUND_MIXER_MIC: /* External microphone (0-7) */
- return mixer_input (7, MIC_VOL);
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
-
-}
-
-/*
- * Sets mixer volume levels. All levels except mic are 0 to 15, mic is 7. See
- * sbinfo.doc for details on granularity and such. Basically, the mixer
- * forces the lowest bit high, effectively reducing the possible settings by
- * one half. Yes, that's right, volume levels have 8 settings, and
- * microphone has four. Sucks.
- */
-static int
-mixer_set_levels (struct sb_mixer_levels *user_l)
-{
- struct sb_mixer_levels l;
-
- IOCTL_FROM_USER ((char *) &l, ((char *) user_l), 0, sizeof (l));
-
- if (l.master.l & ~0xF || l.master.r & ~0xF
- || l.line.l & ~0xF || l.line.r & ~0xF
- || l.voc.l & ~0xF || l.voc.r & ~0xF
- || l.fm.l & ~0xF || l.fm.r & ~0xF
- || l.cd.l & ~0xF || l.cd.r & ~0xF
- || l.mic & ~0x7)
- return (RET_ERROR (EINVAL));
-
- setmixer (MASTER_VOL, (l.master.l << 4) | l.master.r);
- setmixer (LINE_VOL, (l.line.l << 4) | l.line.r);
- setmixer (VOC_VOL, (l.voc.l << 4) | l.voc.r);
- setmixer (FM_VOL, (l.fm.l << 4) | l.fm.r);
- setmixer (CD_VOL, (l.cd.l << 4) | l.cd.r);
- setmixer (MIC_VOL, l.mic);
- return (0);
-}
-
-/*
- * This sets aspects of the Mixer that are not volume levels. (Recording
- * source, filter level, I/O filtering, and stereo.)
- */
-
-static int
-mixer_set_params (struct sb_mixer_params *user_p)
-{
- struct sb_mixer_params p;
-
- IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
-
- if (p.record_source != SRC_MIC
- && p.record_source != SRC_CD
- && p.record_source != SRC_LINE)
- return (EINVAL);
-
- /*
- * I'm not sure if this is The Right Thing. Should stereo be entirely
- * under control of DSP? I like being able to toggle it while a sound is
- * playing, so I do this... because I can.
- */
-
- dsp_stereo = !!p.dsp_stereo;
-
- set_filter (p.record_source, p.hifreq_filter, p.filter_input, p.filter_output);
-
- switch (p.record_source)
- {
-
- case SRC_MIC:
- rec_devices = SOUND_MASK_MIC;
- break;
-
- case SRC_LINE:
- rec_devices = SOUND_MASK_LINE;
- break;
-
- case SRC_CD:
- rec_devices = SOUND_MASK_CD;
- }
-
- return (0);
-}
-
-/* Read the current mixer level settings into the user's struct. */
-static int
-mixer_get_levels (struct sb_mixer_levels *user_l)
-{
- S_BYTE val;
- struct sb_mixer_levels l;
-
- val = getmixer (MASTER_VOL); /* Master */
- l.master.l = B4 (val >> 4);
- l.master.r = B4 (val);
-
- val = getmixer (LINE_VOL); /* FM */
- l.line.l = B4 (val >> 4);
- l.line.r = B4 (val);
-
- val = getmixer (VOC_VOL); /* DAC */
- l.voc.l = B4 (val >> 4);
- l.voc.r = B4 (val);
-
- val = getmixer (FM_VOL); /* FM */
- l.fm.l = B4 (val >> 4);
- l.fm.r = B4 (val);
-
- val = getmixer (CD_VOL); /* CD */
- l.cd.l = B4 (val >> 4);
- l.cd.r = B4 (val);
-
- val = getmixer (MIC_VOL); /* Microphone */
- l.mic = B3 (val);
-
- IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
-
- return (0);
-}
-
-/* Read the current mixer parameters into the user's struct. */
-static int
-mixer_get_params (struct sb_mixer_params *user_params)
-{
- S_BYTE val;
- struct sb_mixer_params params;
-
- val = getmixer (RECORD_SRC);
- params.record_source = val & 0x07;
- params.hifreq_filter = !!(val & FREQ_HI);
- params.filter_input = (val & FILT_OFF) ? OFF : ON;
- params.filter_output = (getmixer (OUT_FILTER) & FILT_OFF) ? OFF : ON;
- params.dsp_stereo = dsp_stereo;
-
- IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
- return (0);
-}
-
-static int
-sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
-{
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- return IOCTL_OUT (arg, sbp_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
- else
- { /* Read parameters */
-
- switch (cmd & 0xff)
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, rec_devices);
- break;
-
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~SOUND_MASK_MIC);
- break;
-
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES);
- break;
-
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);
- break;
-
- default:
- return IOCTL_OUT (arg, sbp_mixer_get (cmd & 0xff));
- }
- }
- }
- else
- {
- switch (cmd)
- {
- case MIXER_IOCTL_SET_LEVELS:
- return (mixer_set_levels ((struct sb_mixer_levels *) arg));
- case MIXER_IOCTL_SET_PARAMS:
- return (mixer_set_params ((struct sb_mixer_params *) arg));
- case MIXER_IOCTL_READ_LEVELS:
- return (mixer_get_levels ((struct sb_mixer_levels *) arg));
- case MIXER_IOCTL_READ_PARAMS:
- return (mixer_get_params ((struct sb_mixer_params *) arg));
- case MIXER_IOCTL_RESET:
- init_mixer ();
- return (0);
- default:
- return RET_ERROR (EINVAL);
- }
- }
-}
-
-/* End of mixer code */
-#endif
-
-#ifndef EXCLUDE_MIDI
-
-/* Midi code */
-
-static int
-sb_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
-)
-{
- int ret;
-
- if (!sb_dsp_ok)
- {
- printk ("SB Error: MIDI hardware not installed\n");
- return RET_ERROR (ENXIO);
- }
-
- if (mode != OPEN_WRITE && !duplex_midi)
- {
- if (num_midis == 1)
- printk ("SoundBlaster: Midi input not currently supported\n");
- return RET_ERROR (EPERM);
- }
-
- midi_mode = NORMAL_MIDI;
- if (mode != OPEN_WRITE)
- {
- if (dsp_busy || intr_active)
- return RET_ERROR (EBUSY);
- midi_mode = UART_MIDI;
- }
-
- if (dsp_highspeed || dsp_stereo)
- {
- printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
- return RET_ERROR (EBUSY);
- }
-
- if (midi_mode == UART_MIDI)
- {
- irq_mode = IMODE_MIDI;
-
- reset_dsp ();
- dsp_speaker (OFF);
-
- if (!dsp_command (0x35))
- return RET_ERROR (EIO); /* Enter the UART mode */
- intr_active = 1;
-
- if ((ret = set_dsp_irq (sbc_irq)) < 0)
- {
- reset_dsp ();
- return 0; /* IRQ not free */
- }
- }
-
- midi_busy = 1;
-
- return 0;
-}
-
-static void
-sb_midi_close (int dev)
-{
- if (midi_mode == UART_MIDI)
- {
- reset_dsp (); /* The only way to kill the UART mode */
- RELEASE_IRQ (sbc_irq);
- }
- intr_active = 0;
- midi_busy = 0;
-}
-
-static int
-sb_midi_out (int dev, unsigned char midi_byte)
-{
- unsigned long flags;
-
- midi_busy = 1; /* Kill all notes after close */
-
- if (midi_mode == NORMAL_MIDI)
- {
- DISABLE_INTR (flags);
- if (dsp_command (0x38))
- dsp_command (midi_byte);
- else
- printk ("SB Error: Unable to send a MIDI byte\n");
- RESTORE_INTR (flags);
- }
- else
- dsp_command (midi_byte); /* UART write */
-
- return 1;
-}
-
-static int
-sb_midi_start_read (int dev)
-{
- if (midi_mode != UART_MIDI)
- {
- printk ("SoundBlaster: MIDI input not implemented.\n");
- return RET_ERROR (EPERM);
- }
- return 0;
-}
-
-static int
-sb_midi_end_read (int dev)
-{
- if (midi_mode == UART_MIDI)
- {
- reset_dsp ();
- intr_active = 0;
- }
- return 0;
-}
-
-static int
-sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
-{
- return RET_ERROR (EPERM);
-}
-
-/* End of midi code */
-#endif
+static char card_name[32] = "SoundBlaster";
#ifndef EXCLUDE_AUDIO
static struct audio_operations sb_dsp_operations =
{
"SoundBlaster",
+ NOTHING_SPECIAL,
sb_dsp_open,
sb_dsp_close,
sb_dsp_output_block,
@@ -1182,132 +674,102 @@ static struct audio_operations sb_dsp_operations =
#endif
-#ifndef EXCLUDE_SBPRO
-static struct mixer_operations sb_mixer_operations =
-{
- sb_mixer_ioctl
-};
-
-#endif
-
-#ifndef EXCLUDE_MIDI
-static struct midi_operations sb_midi_operations =
-{
- {"SoundBlaster", 0},
- sb_midi_open,
- sb_midi_close,
- sb_midi_ioctl,
- sb_midi_out,
- sb_midi_start_read,
- sb_midi_end_read,
- NULL, /* Kick */
- NULL, /* command */
- NULL /* buffer_status */
-};
-
-#endif
-
-static int
-verify_irq (void)
-{
-#if 0
- unsigned long loop;
-
- irq_ok = 0;
-
- if (set_dsp_irq (sbc_irq) == -1)
- {
- printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
- return 0;
- }
-
-
- irq_mode = IMODE_INIT;
-
- dsp_command (0xf2); /* This should cause immediate interrupt */
-
- for (loop = 100000; loop > 0 && !irq_ok; loop--);
-
- RELEASE_IRQ (sbc_irq);
-
- if (!irq_ok)
- {
- printk ("SB Warning: IRQ test not passed!");
- irq_ok = 1;
- }
-#else
- irq_ok = 1;
-#endif
- return irq_ok;
-}
-
long
sb_dsp_init (long mem_start, struct address_info *hw_config)
{
- int i, major, minor;
+ int i;
+ int prostat = 0;
- major = minor = 0;
- dsp_command (0xe1); /* Get version */
+ sbc_major = sbc_minor = 0;
+ sb_dsp_command (0xe1); /* Get version */
for (i = 1000; i; i--)
{
- if (inb (DSP_DATA_AVAIL) & 0x80)
+ if (INB (DSP_DATA_AVAIL) & 0x80)
{ /* wait for Data Ready */
- if (major == 0)
- major = inb (DSP_READ);
+ if (sbc_major == 0)
+ sbc_major = INB (DSP_READ);
else
{
- minor = inb (DSP_READ);
+ sbc_minor = INB (DSP_READ);
break;
}
}
}
- dsp_model = major;
+
+ if (sbc_major == 2 || sbc_major == 3) /* SB 2.0 or SB Pro */
+ sb_duplex_midi = 1;
+
+ if (sbc_major == 4)
+ sb16 = 1;
#ifndef EXCLUDE_SBPRO
- if (detect_mixer ())
- {
- dsp_mono = 0;
- sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor);
- init_mixer ();
- mixer_devs[num_mixers++] = &sb_mixer_operations;
+ if (sbc_major >= 3 ||
+ (sbc_major == 2 && sbc_minor == 1)) /* Sound Galaxy ??? */
+ prostat = sb_mixer_init (sbc_major);
+#endif
- if (major >= 2)
- duplex_midi = 1;
+#ifndef EXCLUDE_YM3812
+ if (sbc_major > 3 ||
+ (sbc_major == 3 && INB (0x388) == 0x00)) /* Non OPL-3 should return 0x06 */
+ enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
+#endif
-#ifndef EXCLUDE_YM8312
- if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */
+ if (sbc_major >= 3)
+ {
+#ifndef SCO
+ if (prostat)
{
- enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+ }
+ else
+ {
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
}
#endif
}
else
+ {
+#ifndef SCO
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
#endif
- sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor);
-
- printk ("snd2: <%s>", sb_dsp_operations.name);
+ sprintf (card_name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
+#endif
+ }
- if (!verify_irq ())
- return mem_start;
+#ifdef __FreeBSD__
+ printk ("snd2: <%s>", card_name);
+#else
+ printk (" <%s>", card_name);
+#endif
#ifndef EXCLUDE_AUDIO
- if (num_dspdevs < MAX_DSP_DEV)
- {
- dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
- sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
- sound_buffsizes[my_dev] = DSP_BUFFSIZE;
- sound_dsp_dmachan[my_dev] = hw_config->dma;
- sound_dma_automode[my_dev] = 0;
- }
- else
- printk ("SB: Too many DSP devices available\n");
+#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+ if (!sb16) /* There is a better driver for SB16 */
+#endif
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+ sound_dma_automode[my_dev] = 0;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
#endif
#ifndef EXCLUDE_MIDI
- if (!midi_disabled) /* Midi don't work in the SB emulation mode
- * of PAS */
- midi_devs[num_midis++] = &sb_midi_operations;
+ if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode
+ * of PAS, SB16 has better midi interface */
+ sb_midi_init (sbc_major);
#endif
sb_dsp_ok = 1;
diff --git a/sys/i386/isa/sound/sb_midi.c b/sys/i386/isa/sound/sb_midi.c
new file mode 100644
index 000000000000..fed19aba3a08
--- /dev/null
+++ b/sys/i386/isa/sound/sb_midi.c
@@ -0,0 +1,224 @@
+/*
+ * sound/sb_dsp.c
+ *
+ * The low level driver for the SoundBlaster DS chips.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI)
+
+#include "sb.h"
+#undef SB_TEST_IRQ
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'sb_irq_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+extern int sb_dsp_ok; /* Set to 1 after successful initialization */
+
+extern int sb_midi_mode;
+extern int sb_midi_busy; /* 1 if the process has output to MIDI */
+extern int sb_dsp_busy;
+extern int sb_dsp_highspeed;
+
+extern volatile int sb_irq_mode;/* IMODE_INPUT, IMODE_OUTPUT
+
+ * or IMODE_NONE */
+extern int sb_duplex_midi;
+extern int sb_intr_active;
+extern int sbc_base;
+
+static int input_opened = 0;
+static void (*midi_input_intr) (int dev, unsigned char data);
+static int my_dev = 0;
+
+static int
+sb_midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ int ret;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: MIDI hardware not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (mode != OPEN_WRITE && !sb_duplex_midi)
+ {
+ if (num_midis == 1)
+ printk ("SoundBlaster: MIDI input not supported with plain SB\n");
+ return RET_ERROR (EPERM);
+ }
+
+ sb_midi_mode = NORMAL_MIDI;
+ if (mode != OPEN_WRITE)
+ {
+ if (sb_dsp_busy || sb_intr_active)
+ return RET_ERROR (EBUSY);
+ sb_midi_mode = UART_MIDI;
+ }
+
+ if (sb_dsp_highspeed)
+ {
+ printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_irq_mode = IMODE_MIDI;
+
+ sb_reset_dsp ();
+
+ if (!sb_dsp_command (0xf2)) /* This is undodumented, isn't it */
+ return RET_ERROR (EIO); /* be nice to DSP */
+
+ if (!sb_dsp_command (0x35))
+ return RET_ERROR (EIO); /* Enter the UART mode */
+ sb_intr_active = 1;
+
+ if ((ret = sb_get_irq ()) < 0)
+ {
+ sb_reset_dsp ();
+ return 0; /* IRQ not free */
+ }
+ input_opened = 1;
+ my_dev = dev;
+ midi_input_intr = input;
+ }
+
+ sb_midi_busy = 1;
+
+ return 0;
+}
+
+static void
+sb_midi_close (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp (); /* The only way to kill the UART mode */
+ sb_free_irq ();
+ }
+ sb_intr_active = 0;
+ sb_midi_busy = 0;
+ input_opened = 0;
+}
+
+static int
+sb_midi_out (int dev, unsigned char midi_byte)
+{
+ unsigned long flags;
+
+ sb_midi_busy = 1; /* Kill all notes after close */
+
+ if (sb_midi_mode == NORMAL_MIDI)
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x38))
+ sb_dsp_command (midi_byte);
+ else
+ printk ("SB Error: Unable to send a MIDI byte\n");
+ RESTORE_INTR (flags);
+ }
+ else
+ sb_dsp_command (midi_byte); /* UART write */
+
+ return 1;
+}
+
+static int
+sb_midi_start_read (int dev)
+{
+ if (sb_midi_mode != UART_MIDI)
+ {
+ printk ("SoundBlaster: MIDI input not implemented.\n");
+ return RET_ERROR (EPERM);
+ }
+ return 0;
+}
+
+static int
+sb_midi_end_read (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp ();
+ sb_intr_active = 0;
+ }
+ return 0;
+}
+
+static int
+sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EPERM);
+}
+
+void
+sb_midi_interrupt (int dummy)
+{
+ unsigned long flags;
+ unsigned char data;
+
+ DISABLE_INTR (flags);
+
+ data = INB (DSP_READ);
+ if (input_opened)
+ midi_input_intr (my_dev, data);
+
+ RESTORE_INTR (flags);
+}
+
+static struct midi_operations sb_midi_operations =
+{
+ {"SoundBlaster", 0, 0, SNDCARD_SB},
+ sb_midi_open,
+ sb_midi_close,
+ sb_midi_ioctl,
+ sb_midi_out,
+ sb_midi_start_read,
+ sb_midi_end_read,
+ NULL, /* Kick */
+ NULL, /* command */
+ NULL /* buffer_status */
+};
+
+void
+sb_midi_init (int model)
+{
+ midi_devs[num_midis++] = &sb_midi_operations;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.c b/sys/i386/isa/sound/sb_mixer.c
new file mode 100644
index 000000000000..39b97caf8cd7
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.c
@@ -0,0 +1,422 @@
+
+/*
+ * sound/sb_mixer.c
+ *
+ * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support the Sound Galaxy NX Pro mixer.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
+#define __SB_MIXER_C__
+
+#include "sb.h"
+#include "sb_mixer.h"
+#undef SB_TEST_IRQ
+
+extern int sbc_base;
+
+static int mixer_initialized = 0;
+
+static int supported_rec_devices;
+static int supported_devices;
+static int recmask = 0;
+static int mixer_model;
+static int mixer_caps;
+static mixer_tab *iomap;
+
+void
+sb_setmixer (unsigned int port, unsigned int value)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+}
+
+int
+sb_getmixer (unsigned int port)
+{
+ int val;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ val = INB (MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+
+ return val;
+}
+
+void
+sb_mixer_set_stereo (int mode)
+{
+ if (!mixer_initialized)
+ return;
+
+ sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
+ | (mode ? STEREO_DAC : MONO_DAC)));
+}
+
+/*
+ * Returns:
+ * 0 No mixer detected.
+ * 1 Only a plain Sound Blaster Pro style mixer detected.
+ * 2 The Sound Galaxy NX Pro mixer detected.
+ */
+static int
+detect_mixer (void)
+{
+#ifdef __SGNXPRO__
+ int oldbass, oldtreble;
+
+#endif
+ int retcode = 1;
+
+ /*
+ * Detect the mixer by changing parameters of two volume channels. If the
+ * values read back match with the values written, the mixer is there (is
+ * it?)
+ */
+ sb_setmixer (FM_VOL, 0xff);
+ sb_setmixer (VOC_VOL, 0x33);
+
+ if (sb_getmixer (FM_VOL) != 0xff)
+ return 0; /* No match */
+ if (sb_getmixer (VOC_VOL) != 0x33)
+ return 0;
+
+#ifdef __SGNXPRO__
+ /* Attempt to detect the SG NX Pro by check for valid bass/treble
+ * registers.
+ */
+ oldbass = sb_getmixer (BASS_LVL);
+ oldtreble = sb_getmixer (TREBLE_LVL);
+
+ sb_setmixer (BASS_LVL, 0xaa);
+ sb_setmixer (TREBLE_LVL, 0x55);
+
+ if ((sb_getmixer (BASS_LVL) != 0xaa) ||
+ (sb_getmixer (TREBLE_LVL) != 0x55))
+ {
+ retcode = 1; /* 1 == Only SB Pro detected */
+ }
+ else
+ retcode = 2; /* 2 == SG NX Pro detected */
+ /* Restore register in either case since SG NX Pro has EEPROM with
+ * 'preferred' values stored.
+ */
+ sb_setmixer (BASS_LVL, oldbass);
+ sb_setmixer (TREBLE_LVL, oldtreble);
+#endif
+ return retcode;
+}
+
+static void
+change_bits (unsigned char *regval, int dev, int chn, int newval)
+{
+ unsigned char mask;
+ int shift;
+
+ mask = (1 << (*iomap)[dev][chn].nbits) - 1;
+ newval = ((newval * mask) + 50) / 100; /* Scale it */
+
+ shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
+
+ *regval &= ~(mask << shift); /* Filter out the previous value */
+ *regval |= (newval & mask) << shift; /* Set the new value */
+}
+
+static int
+sb_mixer_get (int dev)
+{
+ if (!((1 << dev) & supported_devices))
+ return RET_ERROR (EINVAL);
+
+ return levels[dev];
+}
+
+static int
+sb_mixer_set (int dev, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+
+ int regoffs;
+ unsigned char val;
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ if (dev > 31)
+ return RET_ERROR (EINVAL);
+
+ if (!(supported_devices & (1 << dev))) /* Not supported */
+ return RET_ERROR (EINVAL);
+
+ regoffs = (*iomap)[dev][LEFT_CHN].regno;
+
+ if (regoffs == 0)
+ return RET_ERROR (EINVAL);
+
+ val = sb_getmixer (regoffs);
+ change_bits (&val, dev, LEFT_CHN, left);
+
+ levels[dev] = left | (left << 8);
+
+ if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
+ {
+ sb_setmixer (regoffs, val); /* Save the old one */
+ regoffs = (*iomap)[dev][RIGHT_CHN].regno;
+
+ if (regoffs == 0)
+ return left | (left << 8); /* Just left channel present */
+
+ val = sb_getmixer (regoffs); /* Read the new one */
+ }
+
+ change_bits (&val, dev, RIGHT_CHN, right);
+ sb_setmixer (regoffs, val);
+
+ levels[dev] = left | (right << 8);
+ return left | (right << 8);
+}
+
+static void
+set_recsrc (int src)
+{
+ sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
+}
+
+static int
+set_recmask (int mask)
+{
+ int devmask, i;
+ unsigned char regimageL, regimageR;
+
+ devmask = mask & supported_rec_devices;
+
+ switch (mixer_model)
+ {
+ case 3:
+
+ if (devmask != SOUND_MASK_MIC &&
+ devmask != SOUND_MASK_LINE &&
+ devmask != SOUND_MASK_CD)
+ { /* More than one devices selected. Drop the
+ * previous selection */
+ devmask &= ~recmask;
+ }
+
+ if (devmask != SOUND_MASK_MIC &&
+ devmask != SOUND_MASK_LINE &&
+ devmask != SOUND_MASK_CD)
+ { /* More than one devices selected. Default to
+ * mic */
+ devmask = SOUND_MASK_MIC;
+ }
+
+
+ if (devmask ^ recmask) /* Input source changed */
+ {
+ switch (devmask)
+ {
+
+ case SOUND_MASK_MIC:
+ set_recsrc (SRC_MIC);
+ break;
+
+ case SOUND_MASK_LINE:
+ set_recsrc (SRC_LINE);
+ break;
+
+ case SOUND_MASK_CD:
+ set_recsrc (SRC_CD);
+ break;
+
+ default:
+ set_recsrc (SRC_MIC);
+ }
+ }
+
+ break;
+
+ case 4:
+ if (!devmask)
+ devmask = SOUND_MASK_MIC;
+
+ regimageL = regimageR = 0;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if ((1 << i) & devmask)
+ {
+ regimageL |= sb16_recmasks_L[i];
+ regimageR |= sb16_recmasks_R[i];
+ }
+ sb_setmixer (SB16_IMASK_L, regimageL);
+ sb_setmixer (SB16_IMASK_R, regimageR);
+ break;
+ }
+
+ recmask = devmask;
+ return recmask;
+}
+
+static int
+sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
+ }
+ else
+ switch (cmd & 0xff) /* Return parameters */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, supported_devices);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, supported_devices &
+ ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, supported_rec_devices);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, mixer_caps);
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations sb_mixer_operations =
+{
+ sb_mixer_ioctl
+};
+
+static void
+sb_mixer_reset (void)
+{
+ int i;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ sb_mixer_set (i, levels[i]);
+ set_recmask (SOUND_MASK_MIC);
+}
+
+/*
+ * Returns a code depending on whether a SG NX Pro was detected.
+ * 0 == Plain SB 16 or SB Pro
+ * 1 == SG NX Pro detected.
+ *
+ * Used to update message.
+ */
+int
+sb_mixer_init (int major_model)
+{
+ int mixerstat;
+
+ sb_setmixer (0x00, 0); /* Reset mixer */
+
+ mixerstat = detect_mixer ();
+
+ if (!mixerstat)
+ return 0; /* No mixer. Why? */
+
+ mixer_initialized = 1;
+ mixer_model = major_model;
+
+ switch (major_model)
+ {
+ case 3:
+ mixer_caps = SOUND_CAP_EXCL_INPUT;
+#ifdef __SGNXPRO__
+ if (mixerstat == 2)
+ { /* A SGNXPRO was detected */
+ supported_devices = SGNXPRO_MIXER_DEVICES;
+ supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
+ iomap = &sgnxpro_mix;
+ }
+ else
+#endif
+ { /* Otherwise plain SB Pro */
+ supported_devices = SBPRO_MIXER_DEVICES;
+ supported_rec_devices = SBPRO_RECORDING_DEVICES;
+ iomap = &sbpro_mix;
+ }
+
+ break;
+
+ case 4:
+ mixer_caps = 0;
+ supported_devices = SB16_MIXER_DEVICES;
+ supported_rec_devices = SB16_RECORDING_DEVICES;
+ iomap = &sb16_mix;
+ break;
+
+ default:
+ printk ("SB Warning: Unsupported mixer type\n");
+ return 0;
+ }
+
+ mixer_devs[num_mixers++] = &sb_mixer_operations;
+ sb_mixer_reset ();
+ return (mixerstat == 2);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.h b/sys/i386/isa/sound/sb_mixer.h
new file mode 100644
index 000000000000..4caf7730226f
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.h
@@ -0,0 +1,212 @@
+/*
+ * sound/sb_mixer.h
+ *
+ * Definitions for the SB Pro and SB16 mixers
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added defines for the Sound Galaxy NX Pro mixer.
+ *
+ */
+
+#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
+
+/* Same as SB Pro, unless I find otherwise */
+#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+
+#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
+ * channel is the COVOX/DisneySoundSource emulation volume control
+ * on the mixer. It does NOT control speaker volume. Should have own
+ * mask eventually?
+ */
+#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
+ SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
+
+#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD)
+
+#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_RECLEV | \
+ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
+
+/*
+ * Mixer registers
+ *
+ * NOTE! RECORD_SRC == IN_FILTER
+ */
+
+/*
+ * Mixer registers of SB Pro
+ */
+#define VOC_VOL 0x04
+#define MIC_VOL 0x0A
+#define MIC_MIX 0x0A
+#define RECORD_SRC 0x0C
+#define IN_FILTER 0x0C
+#define OUT_FILTER 0x0E
+#define MASTER_VOL 0x22
+#define FM_VOL 0x26
+#define CD_VOL 0x28
+#define LINE_VOL 0x2E
+#define IRQ_NR 0x80
+#define DMA_NR 0x81
+#define IRQ_STAT 0x82
+#define OPSW 0x3c
+
+/*
+ * Additional registers on the SG NX Pro
+ */
+#define COVOX_VOL 0x42
+#define TREBLE_LVL 0x44
+#define BASS_LVL 0x46
+
+#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
+#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
+#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
+#define FILT_OFF (1 << 5)
+
+#define MONO_DAC 0x00
+#define STEREO_DAC 0x02
+
+/*
+ * Mixer registers of SB16
+ */
+#define SB16_IMASK_L 0x3d
+#define SB16_IMASK_R 0x3e
+
+#define LEFT_CHN 0
+#define RIGHT_CHN 1
+
+struct mixer_def {
+ unsigned int regno: 8;
+ unsigned int bitoffs:4;
+ unsigned int nbits:4;
+};
+
+
+typedef struct mixer_def mixer_tab[32][2];
+typedef struct mixer_def mixer_ent;
+
+#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \
+ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
+
+#ifdef __SB_MIXER_C__
+mixer_tab sbpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
+};
+
+#ifdef __SGNXPRO__
+mixer_tab sgnxpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
+};
+#endif
+
+mixer_tab sb16_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
+MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
+MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
+MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2)
+};
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+ 0x5a5a, /* Master Volume */
+ 0x3232, /* Bass */
+ 0x3232, /* Treble */
+ 0x4b4b, /* FM */
+ 0x4b4b, /* PCM */
+ 0x4b4b, /* PC Speaker */
+ 0x4b4b, /* Ext Line */
+ 0x0000, /* Mic */
+ 0x4b4b, /* CD */
+ 0x4b4b, /* Recording monitor */
+ 0x4b4b, /* SB PCM */
+ 0x4b4b}; /* Recording level */
+
+static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x40, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x10, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x04, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+
+static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x20, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x08, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x02, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+#endif
diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c
index 7df08120ebcc..1a3943289958 100644
--- a/sys/i386/isa/sound/sequencer.c
+++ b/sys/i386/isa/sound/sequencer.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/sequencer.c
- *
+ * sound/sequencer.c
+ *
* The sequencer personality manager.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* 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
@@ -12,7 +12,7 @@
* 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.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
#define SEQUENCER_C
@@ -37,20 +37,24 @@
static int sequencer_ok = 0;
DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
-DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
+#define midi_sleeper seq_sleeper
+#define midi_sleep_flag seq_sleep_flag
static int midi_opened[MAX_MIDI_DEV] =
{0}; /* 1 if the process has opened MIDI */
static int midi_written[MAX_MIDI_DEV] =
{0};
-long seq_time = 0; /* Reference point for the timer */
+unsigned long seq_time = 0; /* Reference point for the timer */
#include "tuning.h"
#define EV_SZ 8
-static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ];
-static unsigned char iqueue[SEQ_MAX_QUEUE][4];
+#define IEV_SZ 4
+static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */
+static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */
+
static volatile int qhead = 0, qtail = 0, qlen = 0;
static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
static volatile int seq_playing = 0;
@@ -83,13 +87,16 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
if (!iqlen)
{
- INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag);
+ if (c != count) /* Some data has been received */
+ return count - c; /* Return what we have */
+
+ DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
if (!iqlen)
return count - c;
}
- COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4);
+ COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
p += 4;
c -= 4;
@@ -114,14 +121,14 @@ copy_to_input (unsigned char *event)
if (iqlen >= (SEQ_MAX_QUEUE - 1))
return; /* Overflow */
- memcpy (iqueue[iqtail], event, 4);
+ memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
iqlen++;
iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
DISABLE_INTR (flags);
- if (midi_sleep_flag)
+ if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag))
{
- WAKE_UP (midi_sleeper);
+ WAKE_UP (midi_sleeper, midi_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -266,16 +273,16 @@ seq_queue (unsigned char *note)
if (!seq_playing)
seq_startplay (); /* Give chance to drain the queue */
- if (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag)
+ if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
/* Sleep until there is enough space on the queue */
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
}
if (qlen >= SEQ_MAX_QUEUE)
return 0; /* To be sure */
- memcpy (&queue[qtail][0], note, EV_SZ);
+ memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
qtail = (qtail + 1) % SEQ_MAX_QUEUE;
qlen++;
@@ -323,6 +330,10 @@ extended_event (unsigned char *q)
synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]);
break;
+ case SEQ_VOLMODE:
+ synth_devs[dev]->volume_method (dev, q[3]);
+ break;
+
default:
return RET_ERROR (EINVAL);
}
@@ -342,7 +353,7 @@ seq_startplay (void)
qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
qlen--;
- q = &queue[this_one][0];
+ q = &queue[this_one * EV_SZ];
switch (q[0])
{
@@ -378,10 +389,9 @@ seq_startplay (void)
unsigned long flags;
DISABLE_INTR (flags);
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
- seq_sleep_flag = 0;
- WAKE_UP (seq_sleeper);
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -449,10 +459,9 @@ seq_startplay (void)
unsigned long flags;
DISABLE_INTR (flags);
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
- seq_sleep_flag = 0;
- WAKE_UP (seq_sleeper);
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -461,86 +470,87 @@ seq_startplay (void)
int
sequencer_open (int dev, struct fileinfo *file)
- {
- int retval, mode, i;
+{
+ int retval, mode, i;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- DEB (printk ("sequencer_open(dev=%d)\n", dev));
+ DEB (printk ("sequencer_open(dev=%d)\n", dev));
- if (!sequencer_ok)
- {
- printk ("Soundcard: Sequencer not initialized\n");
- return RET_ERROR (ENXIO);
- }
+ if (!sequencer_ok)
+ {
+ printk ("Soundcard: Sequencer not initialized\n");
+ return RET_ERROR (ENXIO);
+ }
- if (dev) /* Patch manager device */
- {
- int err;
+ if (dev) /* Patch manager device */
+ {
+ int err;
- dev--;
- if (pmgr_present[dev])
- return RET_ERROR (EBUSY);
- if ((err = pmgr_open (dev)) < 0)
- return err; /* Failed */
+ dev--;
+ if (pmgr_present[dev])
+ return RET_ERROR (EBUSY);
+ if ((err = pmgr_open (dev)) < 0)
+ return err; /* Failed */
- pmgr_present[dev] = 1;
- return err;
- }
+ pmgr_present[dev] = 1;
+ return err;
+ }
- if (sequencer_busy)
- {
- printk ("Sequencer busy\n");
- return RET_ERROR (EBUSY);
- }
+ if (sequencer_busy)
+ {
+ printk ("Sequencer busy\n");
+ return RET_ERROR (EBUSY);
+ }
- if (!(num_synths + num_midis))
- return RET_ERROR (ENXIO);
+ if (!(num_synths + num_midis))
+ return RET_ERROR (ENXIO);
- synth_open_mask = 0;
+ synth_open_mask = 0;
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- for (i = 0; i < num_synths; i++) /* Open synth devices */
- if (synth_devs[i]->open (i, mode) < 0)
- printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
- else
- synth_open_mask |= (1 << i);
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++) /* Open synth devices */
+ if (synth_devs[i]->open (i, mode) < 0)
+ printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
+ else
+ synth_open_mask |= (1 << i);
- seq_time = GET_TIME ();
+ seq_time = GET_TIME ();
- for (i = 0; i < num_midis; i++)
- {
- midi_opened[i] = 0;
- midi_written[i] = 0;
- }
+ for (i = 0; i < num_midis; i++)
+ {
+ midi_opened[i] = 0;
+ midi_written[i] = 0;
+ }
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- { /* Initialize midi input devices */
- if (!num_midis)
- {
- printk ("Sequencer: No Midi devices. Input not possible\n");
- return RET_ERROR (ENXIO);
- }
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ { /* Initialize midi input devices */
+ if (!num_midis)
+ {
+ printk ("Sequencer: No Midi devices. Input not possible\n");
+ return RET_ERROR (ENXIO);
+ }
- for (i = 0; i < num_midis; i++)
- {
- if ((retval = midi_devs[i]->open (i, mode,
+ for (i = 0; i < num_midis; i++)
+ {
+ if ((retval = midi_devs[i]->open (i, mode,
sequencer_midi_input, sequencer_midi_output)) >= 0)
- midi_opened[i] = 1;
- }
- }
+ midi_opened[i] = 1;
+ }
+ }
- sequencer_busy = 1;
- seq_sleep_flag = midi_sleep_flag = 0;
- output_treshold = SEQ_MAX_QUEUE / 2;
+ sequencer_busy = 1;
+ RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+ RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+ output_treshold = SEQ_MAX_QUEUE / 2;
- for (i = 0; i < num_synths; i++)
- if (pmgr_present[i])
- pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
- return 0;
- }
+ return 0;
+}
void
seq_drain_midi_queues (void)
@@ -553,7 +563,7 @@ seq_drain_midi_queues (void)
n = 1;
- while (!PROCESS_ABORTING && n)
+ while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
{
n = 0;
@@ -568,70 +578,70 @@ seq_drain_midi_queues (void)
*/
if (n)
{
- REQUEST_TIMEOUT (HZ / 10, seq_sleeper);
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10);
}
}
}
void
sequencer_release (int dev, struct fileinfo *file)
- {
- int i;
- int mode = file->mode & O_ACCMODE;
+{
+ int i;
+ int mode = file->mode & O_ACCMODE;
- dev = dev >> 4;
+ dev = dev >> 4;
- DEB (printk ("sequencer_release(dev=%d)\n", dev));
+ DEB (printk ("sequencer_release(dev=%d)\n", dev));
- if (dev) /* Patch manager device */
- {
- dev--;
- pmgr_release (dev);
- pmgr_present[dev] = 0;
- return;
- }
+ if (dev) /* Patch manager device */
+ {
+ dev--;
+ pmgr_release (dev);
+ pmgr_present[dev] = 0;
+ return;
+ }
- /*
+ /*
* Wait until the queue is empty
- */
- while (!PROCESS_ABORTING && qlen)
- {
- seq_sync ();
- }
+ */
- if (mode != OPEN_READ)
- seq_drain_midi_queues (); /* Ensure the output queues are empty */
- seq_reset ();
- if (mode != OPEN_READ)
- seq_drain_midi_queues (); /* Flush the all notes off messages */
+ while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+ {
+ seq_sync ();
+ }
- for (i = 0; i < num_midis; i++)
- if (midi_opened[i])
- midi_devs[i]->close (i);
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Ensure the output queues are empty */
+ seq_reset ();
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Flush the all notes off messages */
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- for (i = 0; i < num_synths; i++)
- if (synth_open_mask & (1 << i)) /* Actually opened */
- if (synth_devs[i])
- synth_devs[i]->close (i);
+ for (i = 0; i < num_midis; i++)
+ if (midi_opened[i])
+ midi_devs[i]->close (i);
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
for (i = 0; i < num_synths; i++)
- if (pmgr_present[i])
- pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+ if (synth_open_mask & (1 << i)) /* Actually opened */
+ if (synth_devs[i])
+ synth_devs[i]->close (i);
- sequencer_busy = 0;
- }
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+
+ sequencer_busy = 0;
+}
static int
seq_sync (void)
{
- if (qlen && !seq_playing && !PROCESS_ABORTING)
+ if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
seq_startplay ();
- if (qlen && !seq_sleep_flag) /* Queue not empty */
+ if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */
{
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
}
return qlen;
@@ -654,8 +664,7 @@ midi_outc (int dev, unsigned char data)
while (n && !midi_devs[dev]->putc (dev, data))
{
- REQUEST_TIMEOUT (1, seq_sleeper);
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
n--;
}
}
@@ -684,7 +693,8 @@ seq_reset (void)
{
for (chn = 0; chn < 16; chn++)
{
- midi_outc (i, 0xb0 + chn); /* Channel message */
+ midi_outc (i,
+ (unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */
midi_outc (i, 0x7b);/* All notes off */
midi_outc (i, 0); /* Dummy parameter */
}
@@ -697,7 +707,7 @@ seq_reset (void)
seq_playing = 0;
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
printk ("Sequencer Warning: Unexpected sleeping process\n");
}
@@ -720,7 +730,7 @@ sequencer_ioctl (int dev, struct fileinfo *file,
if (mode == OPEN_READ)
return 0;
- while (qlen && !PROCESS_ABORTING)
+ while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
seq_sync ();
return 0;
break;
@@ -979,7 +989,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
case SEL_IN:
if (!iqlen)
{
- midi_sleep_flag = 1;
select_wait (&midi_sleeper, wait);
return 0;
}
@@ -990,7 +999,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
case SEL_OUT:
if (qlen >= SEQ_MAX_QUEUE)
{
- seq_sleep_flag = 1;
select_wait (&seq_sleeper, wait);
return 0;
}
@@ -1039,7 +1047,7 @@ note_to_freq (int note_num)
else if (octave > BASE_OCTAVE)
note_freq <<= (octave - BASE_OCTAVE);
- /* note_freq >>= 1; */
+ /* note_freq >>= 1; */
return note_freq;
}
@@ -1048,7 +1056,7 @@ unsigned long
compute_finetune (unsigned long base_freq, int bend, int range)
{
unsigned long amount;
- int negative, semitones, cents;
+ int negative, semitones, cents, multiplier = 1;
if (!bend)
return base_freq;
@@ -1072,13 +1080,20 @@ compute_finetune (unsigned long base_freq, int bend, int range)
if (bend > range)
bend = range;
- if (bend > 2399)
- bend = 2399;
+ /*
+ if (bend > 2399)
+ bend = 2399;
+ */
+ while (bend > 2399)
+ {
+ multiplier *= 4;
+ bend -= 2400;
+ }
semitones = bend / 100;
cents = bend % 100;
- amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000;
+ amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
if (negative)
return (base_freq * 10000) / amount; /* Bend down */
@@ -1092,6 +1107,9 @@ sequencer_init (long mem_start)
{
sequencer_ok = 1;
+ PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start);
+ PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start);
+
return mem_start;
}
@@ -1111,14 +1129,14 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
int
sequencer_open (int dev, struct fileinfo *file)
- {
- return RET_ERROR (ENXIO);
- }
+{
+ return RET_ERROR (ENXIO);
+}
void
sequencer_release (int dev, struct fileinfo *file)
- {
- }
+{
+}
int
sequencer_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
@@ -1138,11 +1156,14 @@ sequencer_init (long mem_start)
return mem_start;
}
+#ifdef ALLOW_SELECT
+
int
sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
return RET_ERROR (EIO);
}
+#endif /* ALLOW_SELECT */
#endif
diff --git a/sys/i386/isa/sound/sound_calls.h b/sys/i386/isa/sound/sound_calls.h
index 89bd79604359..abc82001b776 100644
--- a/sys/i386/isa/sound/sound_calls.h
+++ b/sys/i386/isa/sound/sound_calls.h
@@ -16,23 +16,10 @@ int DMAbuf_open_dma (int chan);
void DMAbuf_close_dma (int chan);
void DMAbuf_reset_dma (int chan);
void DMAbuf_inputintr(int dev);
-void DMAbuf_outputintr(int dev);
+void DMAbuf_outputintr(int dev, int underflow_flag);
/*
- * System calls for the /dev/dsp
- */
-
-int dsp_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
-int dsp_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
-int dsp_open (int dev, struct fileinfo *file, int bits);
-void dsp_release (int dev, struct fileinfo *file);
-int dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg);
-int dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-long dsp_init (long mem_start);
-
-/*
- * System calls for the /dev/audio
+ * System calls for /dev/dsp and /dev/audio
*/
int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
@@ -108,11 +95,47 @@ void tenmicrosec(void);
void request_sound_timer (int count);
void sound_stop_timer(void);
int snd_ioctl_return(int *addr, int value);
+int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int));
+void snd_release_irq(int vect);
+void sound_dma_malloc(int dev);
+void sound_dma_free(int dev);
+
+/* From sound_switch.c */
+int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_open_sw (int dev, struct fileinfo *file);
+void sound_release_sw (int dev, struct fileinfo *file);
+int sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg);
/* From sb_dsp.c */
int sb_dsp_detect (struct address_info *hw_config);
long sb_dsp_init (long mem_start, struct address_info *hw_config);
void sb_dsp_disable_midi(void);
+int sb_get_irq(void);
+void sb_free_irq(void);
+int sb_dsp_command (unsigned char val);
+int sb_reset_dsp (void);
+
+/* From sb16_dsp.c */
+void sb16_dsp_interrupt (int unused);
+long sb16_dsp_init(long mem_start, struct address_info *hw_config);
+int sb16_dsp_detect(struct address_info *hw_config);
+
+/* From sb16_midi.c */
+void sb16midiintr (int unit);
+long attach_sb16midi(long mem_start, struct address_info * hw_config);
+int probe_sb16midi(struct address_info *hw_config);
+
+/* From sb_midi.c */
+void sb_midi_init(int model);
+void sb_midi_interrupt(int dummy);
+
+/* From sb_mixer.c */
+void sb_setmixer (unsigned int port, unsigned int value);
+int sb_getmixer (unsigned int port);
+void sb_mixer_set_stereo(int mode);
+int sb_mixer_init(int major_model);
/* From opl3.c */
int opl3_detect (int ioaddr);
@@ -156,9 +179,10 @@ int gus_wave_detect(int baseaddr);
long gus_wave_init(long mem_start, int irq, int dma);
void gus_voice_irq(void);
unsigned char gus_read8 (int reg);
-void gus_write8(int reg, unsigned char data);
+void gus_write8(int reg, unsigned int data);
void guswave_dma_irq(void);
void gus_delay(void);
+int gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg);
/* From gus_midi.c */
long gus_midi_init(long mem_start);
@@ -179,3 +203,6 @@ int pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
int pmgr_access(int dev, struct patmgr_info *rec);
int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
unsigned long parm3, unsigned long parm4);
+
+/* From ics2101.c */
+long ics2101_mixer_init(long mem_start);
diff --git a/sys/i386/isa/sound/sound_config.h b/sys/i386/isa/sound/sound_config.h
index 9cbd8103b8f5..0d30c12aadc4 100644
--- a/sys/i386/isa/sound/sound_config.h
+++ b/sys/i386/isa/sound/sound_config.h
@@ -30,6 +30,16 @@
#include "local.h"
+
+#undef CONFIGURE_SOUNDCARD
+#undef DYNAMIC_BUFFER
+
+#ifdef KERNEL_SOUNDCARD
+#define CONFIGURE_SOUNDCARD
+#define DYNAMIC_BUFFER
+#undef LOADABLE_SOUNDCARD
+#endif
+
#ifdef EXCLUDE_SEQUENCER
#ifndef EXCLUDE_MIDI
#define EXCLUDE_MIDI
@@ -42,6 +52,10 @@
#endif
#endif
+#ifndef SND_DEFAULT_ENABLE
+#define SND_DEFAULT_ENABLE 1
+#endif
+
/** UWM - new MIDI stuff **/
#ifdef EXCLUDE_CHIP_MIDI
@@ -75,6 +89,14 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define SBC_DMA 1
#endif
+#ifndef SB16_DMA
+#define SB16_DMA 6
+#endif
+
+#ifndef SB16MIDI_BASE
+#define SB16MIDI_BASE 0x300
+#endif
+
#ifndef PAS_BASE
#define PAS_BASE 0x388
#endif
@@ -111,6 +133,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define MPU_IRQ 6
#endif
+#ifndef MAX_REALTIME_FACTOR
+#define MAX_REALTIME_FACTOR 4
+#endif
+
/************* PCM DMA buffer sizes *******************/
/* If you are using high playback or recording speeds, the default buffersize
@@ -132,8 +158,6 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define DMA_AUTOINIT 0x10
-#define SND_MAJOR 14
-
#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
@@ -178,10 +202,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define ON 1
#define OFF 0
-#define MAX_DSP_DEV 3
-#define MAX_MIXER_DEV 1
+#define MAX_DSP_DEV 4
+#define MAX_MIXER_DEV 2
#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 3
+#define MAX_MIDI_DEV 4
struct fileinfo {
int mode; /* Open mode */
@@ -193,6 +217,15 @@ struct address_info {
int dma;
};
+/*
+ * Process wakeup reasons
+ */
+#define WK_NONE 0x00
+#define WK_WAKEUP 0x01
+#define WK_TIMEOUT 0x02
+#define WK_SIGNAL 0x04
+#define WK_SLEEP 0x08
+
#define OPEN_READ 1
#define OPEN_WRITE 2
#define OPEN_READWRITE 3
diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c
new file mode 100644
index 000000000000..68c757586083
--- /dev/null
+++ b/sys/i386/isa/sound/sound_switch.c
@@ -0,0 +1,445 @@
+/*
+ * sound/sound_switch.c
+ *
+ * The system call switch
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+struct sbc_device
+ {
+ int usecount;
+ };
+
+static struct sbc_device sbc_devices[SND_NDEVS] =
+{
+ {0}};
+
+static int in_use = 0; /* Total # of open device files (excluding
+
+ * minor 0) */
+
+/*
+ * /dev/sndstatus -device
+ */
+static char *status_buf = NULL;
+static int status_len, status_ptr;
+static int status_busy = 0;
+
+static int
+put_status (char *s)
+{
+ int l;
+
+ for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], s, l);
+ status_len += l;
+
+ return 1;
+}
+
+static int
+put_status_int (unsigned int val, int radix)
+{
+ int l, v;
+
+ static char hx[] = "0123456789abcdef";
+ char buf[11];
+
+ if (!val)
+ return put_status ("0");
+
+ l = 0;
+ buf[10] = 0;
+
+ while (val)
+ {
+ v = val % radix;
+ val = val / radix;
+
+ buf[9 - l] = hx[v];
+ l++;
+ }
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], &buf[10 - l], l);
+ status_len += l;
+
+ return 1;
+}
+
+static void
+init_status (void)
+{
+ /*
+ * Write the status information to the status_buf and update status_len.
+ * There is a limit of 4000 bytes for the data.
+ */
+
+ int i;
+
+ status_ptr = 0;
+
+ put_status ("Sound Driver:" SOUND_VERSION_STRING
+ " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
+ SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
+ "\n");
+
+ if (!put_status ("Config options: "))
+ return;
+ if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
+ return;
+
+ if (!put_status ("\n\nHW config: \n"))
+ return;
+
+ for (i = 0; i < (num_sound_drivers - 1); i++)
+ {
+ if (!supported_drivers[i].enabled)
+ if (!put_status ("("))
+ return;
+
+ if (!put_status ("Type "))
+ return;
+ if (!put_status_int (supported_drivers[i].card_type, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (supported_drivers[i].name))
+ return;
+ if (!put_status (" at 0x"))
+ return;
+ if (!put_status_int (supported_drivers[i].config.io_base, 16))
+ return;
+ if (!put_status (" irq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.irq, 10))
+ return;
+ if (!put_status (" drq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.dma, 10))
+ return;
+
+ if (!supported_drivers[i].enabled)
+ if (!put_status (")"))
+ return;
+
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nPCM devices:\n"))
+ return;
+
+ for (i = 0; i < num_dspdevs; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (dsp_devs[i]->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nSynth devices:\n"))
+ return;
+
+ for (i = 0; i < num_synths; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (synth_devs[i]->info->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nMidi devices:\n"))
+ return;
+
+ for (i = 0; i < num_midis; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (midi_devs[i]->info.name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (num_mixers)
+ {
+ if (!put_status ("\nMixer(s) installed\n"))
+ return;
+ }
+ else
+ {
+ if (!put_status ("\nNo mixers installed\n"))
+ return;
+ }
+}
+
+static int
+read_status (snd_rw_buf * buf, int count)
+{
+ /*
+ * Return at most 'count' bytes from the status_buf.
+ */
+ int l, c;
+
+ l = count;
+ c = status_len - status_ptr;
+
+ if (l > c)
+ l = c;
+ if (l <= 0)
+ return 0;
+
+ COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
+ status_ptr += l;
+
+ return l;
+}
+
+int
+sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ return read_status (buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_read (dev, file, buf, count);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_read (dev, file, buf, count);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_read (dev, file, buf, count);
+#endif
+
+ default:
+ printk ("Sound: Undefined minor device %d\n", dev);
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+int
+sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+
+ DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_SEQ:
+ return sequencer_write (dev, file, buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_write (dev, file, buf, count);
+ break;
+
+ default:
+ return RET_ERROR (EPERM);
+ }
+
+ return count;
+}
+
+int
+sound_open_sw (int dev, struct fileinfo *file)
+{
+ int retval;
+
+ DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
+
+ if ((dev >= SND_NDEVS) || (dev < 0))
+ {
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_busy)
+ return RET_ERROR (EBUSY);
+ status_busy = 1;
+ if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL)
+ return RET_ERROR (EIO);
+ status_len = status_ptr = 0;
+ init_status ();
+ break;
+
+ case SND_DEV_CTL:
+ return 0;
+ break;
+
+ case SND_DEV_SEQ:
+ if ((retval = sequencer_open (dev, file)) < 0)
+ return retval;
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ if ((retval = MIDIbuf_open (dev, file)) < 0)
+ return retval;
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ if ((retval = audio_open (dev, file)) < 0)
+ return retval;
+ break;
+
+ default:
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ sbc_devices[dev].usecount++;
+ in_use++;
+
+ return 0;
+}
+
+void
+sound_release_sw (int dev, struct fileinfo *file)
+{
+
+ DEB (printk ("sound_release_sw(dev=%d)\n", dev));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_buf)
+ KERNEL_FREE (status_buf);
+ status_buf = NULL;
+ status_busy = 0;
+ break;
+
+ case SND_DEV_CTL:
+ break;
+
+ case SND_DEV_SEQ:
+ sequencer_release (dev, file);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ MIDIbuf_release (dev, file);
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ audio_release (dev, file);
+ break;
+
+ default:
+ printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
+ }
+
+ sbc_devices[dev].usecount--;
+ in_use--;
+}
+
+int
+sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg)
+{
+ DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_CTL:
+
+ if (!num_mixers)
+ return RET_ERROR (ENXIO);
+
+ if ((dev >> 4) >= num_mixers)
+ return RET_ERROR (ENXIO);
+
+ return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_ioctl (dev, file, cmd, arg);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_ioctl (dev, file, cmd, arg);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_ioctl (dev, file, cmd, arg);
+ break;
+#endif
+
+ default:
+ return RET_ERROR (EPERM);
+ break;
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c
index 79c9b09298d1..9691e4f07bec 100644
--- a/sys/i386/isa/sound/soundcard.c
+++ b/sys/i386/isa/sound/soundcard.c
@@ -34,28 +34,20 @@
#include "dev_table.h"
-int __timeout_val = 0;
-int __process_aborting = 0;
-
-u_int snd1mask;
-u_int snd2mask;
-u_int snd3mask;
-u_int snd4mask;
-u_int snd5mask;
-
-struct sbc_device
-{
- int usecount;
-};
+u_int snd1_imask;
+u_int snd2_imask;
+u_int snd3_imask;
+u_int snd4_imask;
+u_int snd5_imask;
+u_int snd6_imask;
+u_int snd7_imask;
+u_int snd8_imask;
+u_int snd9_imask;
#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
-static struct sbc_device sbc_devices[SND_NDEVS];
static int timer_running = 0;
-static int in_use = 0; /* Total # of open device files (excluding
- * minor 0) */
-
static int soundcards_installed = 0; /* Number of installed
* soundcards */
static int soundcard_configured = 0;
@@ -75,12 +67,19 @@ int sndwrite (int dev, struct uio *uio);
int sndselect (int dev, int rw);
static void sound_mem_init(void);
+unsigned
long
-get_time()
+get_time(void)
{
extern struct timeval time;
-
- return(time.tv_usec + (time.tv_sec*1000000));
+struct timeval timecopy;
+int x;
+
+ x = splclock();
+ timecopy = time;
+ splx(x);
+ return timecopy.tv_usec/(1000000/HZ) +
+ (unsigned long)timecopy.tv_sec*HZ;
}
@@ -91,41 +90,7 @@ sndread (int dev, struct uio *buf)
dev = minor (dev);
- DEB (printk ("sound_read(dev=%d, count=%d)\n", dev, count));
-
- switch (dev & 0x0f) /* It really has to be 0x0f */
- {
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_read (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_read (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_read (dev, &files[dev], buf, count));
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN (CMIDI_read (dev, &files[dev], buf, count));
-
- break;
-#endif
-
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- FIX_RETURN (MIDIbuf_read (dev, &files[dev], buf, count));
-#endif
-
- default:
- ;
- }
-
- FIX_RETURN (-EPERM);
+ FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count));
}
int
@@ -133,37 +98,9 @@ sndwrite (int dev, struct uio *buf)
{
int count = buf->uio_resid;
- DEB (printk ("sound_write(dev=%d, count=%d)\n", dev, count));
-
dev = minor (dev);
- switch (dev & 0x0f) /* It really has to be 0x0f */
- {
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_write (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_write (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_write (dev, &files[dev], buf, count));
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN (CMIDI_write (dev, &files[dev], buf, count));
- break;
-#endif
-
- default:
- FIX_RETURN (-EPERM);
- }
-
- FIX_RETURN (count);
+ FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count));
}
int
@@ -173,16 +110,6 @@ sndopen (dev_t dev, int flags)
dev = minor (dev);
- /* printf("SND: Minor number is now : %ld\n",dev); */
-
- DEB (printk ("sound_open(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
-
- if ((dev >= SND_NDEVS) || (dev < 0))
- {
- printk ("Invalid minor device %d\n", dev);
- FIX_RETURN (-ENODEV);
- }
-
if (!soundcard_configured && dev)
{
printk ("SoundCard Error: The soundcard system has not been configured\n");
@@ -198,62 +125,7 @@ sndopen (dev_t dev, int flags)
else if (flags & FWRITE)
files[dev].mode = OPEN_WRITE;
- switch (dev & 0x0f) /* It has to be 0x0f. Trust me */
- {
- case SND_DEV_CTL:
- if (!soundcards_installed)
- if (soundcard_configured)
- {
- printk ("Soundcard not installed\n");
- FIX_RETURN (-ENODEV);
- }
- break;
-
- case SND_DEV_SEQ:
- if ((retval = sequencer_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-
-/** UWM stuff **/
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN ( CMIDI_open (dev, &files[dev]) );
- break;
-#endif
-
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- if ((retval = MIDIbuf_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-#endif
-
- case SND_DEV_AUDIO:
- if ((retval = audio_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-
- case SND_DEV_DSP:
- if ((retval = dsp_open (dev, &files[dev], 8)) < 0)
- FIX_RETURN (retval);
- break;
-
- case SND_DEV_DSP16:
- if ((retval = dsp_open (dev, &files[dev], 16)) < 0)
- FIX_RETURN (retval);
- break;
-
- default:
- printk ("Invalid minor device %d\n", dev);
- FIX_RETURN (-ENODEV);
- }
-
- sbc_devices[dev].usecount++;
- in_use++;
-
- FIX_RETURN (0);
+ FIX_RETURN(sound_open_sw (dev, &files[dev]));
}
int
@@ -262,41 +134,7 @@ sndclose (dev_t dev, int flags)
dev = minor (dev);
- DEB (printk ("sound_release(dev=%d)\n", dev));
-
- switch (dev & 0x0f) /* Has to be 0x0f */
- {
- case SND_DEV_SEQ:
- sequencer_release (dev, &files[dev]);
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- CMIDI_close (dev, &files[dev]);
- break;
-#endif
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- MIDIbuf_release (dev, &files[dev]);
- break;
-#endif
-
- case SND_DEV_AUDIO:
- audio_release (dev, &files[dev]);
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- dsp_release (dev, &files[dev]);
- break;
-
- default:;
- }
-
- sbc_devices[dev].usecount--;
- in_use--; /* If not control port */
-
+ sound_release_sw(dev, &files[dev]);
FIX_RETURN (0);
}
@@ -305,46 +143,7 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
{
dev = minor (dev);
- DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
-
- switch (dev & 0x0f)
- {
-
- case SND_DEV_CTL:
- if (!num_mixers)
- FIX_RETURN (-ENODEV);
-
- if (dev >= num_mixers)
- FIX_RETURN (-ENODEV);
-
- FIX_RETURN (mixer_devs[dev]->ioctl (dev, cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- FIX_RETURN (MIDIbuf_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-#endif
-
- default:
- FIX_RETURN (-EPERM);
- break;
- }
-
- FIX_RETURN (-EPERM);
+ FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg));
}
int
@@ -380,7 +179,6 @@ sndprobe (struct isa_device *dev)
hw_config.io_base = dev->id_iobase;
hw_config.irq = ipri_to_irq (dev->id_irq);
hw_config.dma = dev->id_drq;
-
return sndtable_probe (dev->id_unit, &hw_config);
}
@@ -430,7 +228,6 @@ sndattach (struct isa_device *dev)
dsp_initialized = 1;
mem_start = DMAbuf_init (mem_start);
mem_start = audio_init (mem_start);
- mem_start = dsp_init (mem_start);
}
/** UWM stuff **/
@@ -459,11 +256,6 @@ sndattach (struct isa_device *dev)
mem_start = sequencer_init (mem_start);
}
- for (i = 0; i < SND_NDEVS; i++)
- {
- sbc_devices[i].usecount = 0;
- }
-
return TRUE;
}
@@ -514,7 +306,7 @@ void
sound_stop_timer (void)
{
if (timer_running)
- untimeout ((timeout_func_t)sequencer_timer, 0); /* XXX should fix */
+ untimeout ((timeout_func_t)sequencer_timer, 0);
timer_running = 0;
}
@@ -533,26 +325,12 @@ sound_mem_init (void)
dsp_init_mask |= (1 << dev);
if (sound_dma_automode[dev])
- {
- sound_dma_automode[dev] = 0; /* Not possible with FreeBSD */
- }
-
- if (sound_buffcounts[dev] == 1)
- {
- sound_buffcounts[dev] = 2;
- sound_buffsizes[dev] /= 2;
- }
-
- if (sound_buffsizes[dev] > 65536) /* Larger is not possible (yet) */
- sound_buffsizes[dev] = 65536;
+ sound_buffcounts[dev] = 1;
-#if 0
if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
dma_pagesize = 131072; /* 128k */
else
dma_pagesize = 65536;
-#endif
- dma_pagesize = 4096; /* use bounce buffer */
/* More sanity checks */
@@ -566,31 +344,17 @@ sound_mem_init (void)
for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
{
- /*
- * The DMA buffer allocation algorithm hogs memory. We allocate
- * a memory area which is two times the requires size. This
- * guarantees that it contains at least one valid DMA buffer.
- *
- * This really needs some kind of finetuning.
- */
- char *tmpbuf = malloc (2*sound_buffsizes[dev], M_DEVBUF, M_NOWAIT);
- unsigned long addr, rounded;
+ char *tmpbuf = contigmalloc (sound_buffsizes[dev], M_DEVBUF, M_NOWAIT,
+ 0xFFFFFFul, 0ul, dma_pagesize - 1);
if (tmpbuf == NULL)
{
printk ("snd: Unable to allocate %d bytes of buffer\n",
- 2 * sound_buffsizes[dev]);
+ sound_buffsizes[dev]);
return;
}
- addr = kvtop (tmpbuf);
- /*
- * Align the start address
- */
- rounded = (addr & ~(dma_pagesize - 1)) + dma_pagesize;
-
- snd_raw_buf[dev][snd_raw_count[dev]] =
- &tmpbuf[rounded - addr]; /* Compute offset */
+ snd_raw_buf[dev][snd_raw_count[dev]] = tmpbuf;
/*
* Use virtual address as the physical address, since
* isa_dmastart performs the phys address computation.
@@ -616,4 +380,15 @@ snd_ioctl_return (int *addr, int value)
return 0;
}
+int
+snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
+{
+ return 1;
+}
+
+void
+snd_release_irq(int vect)
+{
+}
+
#endif
diff --git a/sys/i386/isa/spkr.c b/sys/i386/isa/spkr.c
index 01c81f4b02a3..77bf59630243 100644
--- a/sys/i386/isa/spkr.c
+++ b/sys/i386/isa/spkr.c
@@ -4,7 +4,7 @@
* v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
* modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
*
- * $Id: spkr.c,v 1.7 1994/01/25 23:04:27 ache Exp $
+ * $Id: spkr.c,v 1.8 1994/04/21 14:21:50 sos Exp $
*/
#include "speaker.h"
@@ -17,7 +17,8 @@
#include "errno.h"
#include "buf.h"
#include "uio.h"
-
+#include "i386/isa/isa.h"
+#include "i386/isa/timerreg.h"
#include "machine/speaker.h"
/**************** MACHINE DEPENDENT PART STARTS HERE *************************
@@ -48,10 +49,7 @@
* Channel 2 LSB first, (Square Wave) Encoding
* MSB second
*/
-#define PPI 0x61 /* port of Programmable Peripheral Interface */
#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
-#define PIT_CTRL 0x43 /* PIT control address */
-#define PIT_COUNT 0x42 /* PIT count address */
#define PIT_MODE 0xB6 /* set timer mode for sound generation */
/*
@@ -75,13 +73,17 @@ unsigned int thz, ticks;
/* set timer to generate clicks at given frequency in Hertz */
sps = spltty();
- outb(PIT_CTRL, PIT_MODE); /* prepare timer */
- outb(PIT_COUNT, (divisor & 0xff)); /* send lo byte */
- outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */
+
+ if (acquire_timer2(PIT_MODE)) {
+ /* enter list of waiting procs ??? */
+ return;
+ }
+ outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */
+ outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
splx(sps);
/* turn the speaker on */
- outb(PPI, inb(PPI) | PPI_SPKR);
+ outb(IO_PPI, inb(IO_PPI) | PPI_SPKR);
/*
* Set timeout to endtone function, then give up the timeslice.
@@ -89,7 +91,8 @@ unsigned int thz, ticks;
* emitted.
*/
(void) tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
- outb(PPI, inb(PPI) & ~PPI_SPKR);
+ outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR);
+ release_timer2();
}
static void rest(ticks)
diff --git a/sys/i386/isa/syscons.c b/sys/i386/isa/syscons.c
index afd5f468fc54..21558dbaa872 100644
--- a/sys/i386/isa/syscons.c
+++ b/sys/i386/isa/syscons.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from:@(#)syscons.c 1.3 940129
- * $Id: syscons.c,v 1.35.2.2 1994/05/03 07:01:43 rgrimes Exp $
+ * $Id: syscons.c,v 1.50 1994/05/30 03:16:02 ache Exp $
*
*/
@@ -64,7 +64,6 @@
#include "machine/psl.h"
#include "machine/frame.h"
#include "machine/pc/display.h"
-#include "iso8859.font"
#include "kbdtables.h"
#include "sc.h"
@@ -74,6 +73,10 @@
#define NCONS 12
#endif
+#if !defined(NO_HARDFONTS)
+#include "i386/isa/iso8859.font"
+#endif
+
/* status flags */
#define LOCK_KEY_MASK 0x0000F
#define LED_MASK 0x00007
@@ -86,15 +89,21 @@
#define VIDEOMEM 0x000A0000
/* misc defines */
-#define MAX_ESC_PAR 3
+#define MAX_ESC_PAR 5
#define TEXT80x25 1
#define TEXT80x50 2
+#define LOAD 1
+#define SAVE 0
#define COL 80
#define ROW 25
#define BELL_DURATION 5
#define BELL_PITCH 800
#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define CONSOLE_BUFSIZE 1024
#define PCBURST 128
+#define FONT_8_LOADED 0x001
+#define FONT_14_LOADED 0x002
+#define FONT_16_LOADED 0x004
/* defines related to hardware addresses */
#define MONO_BASE 0x3B4 /* crt controller base mono */
@@ -163,33 +172,37 @@ static default_attr kernel_default = {
(FG_BLACK | BG_LIGHTGREY) << 8
};
-#define CONSOLE_BUFFER_SIZE 1024
-int console_buffer_count;
-char console_buffer[CONSOLE_BUFFER_SIZE];
-
static scr_stat console[NCONS];
static scr_stat *cur_console = &console[0];
static scr_stat *new_scp, *old_scp;
static term_stat kernel_console;
static default_attr *current_default;
+static int console_buffer_count;
+static char console_buffer[CONSOLE_BUFSIZE];
static int switch_in_progress = 0;
static u_short *crtat = 0;
static u_int crtc_addr = MONO_BASE;
static char crtc_vga = 0;
static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
+static int fonts_loaded = 0;
static char palette[3*256];
static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
static int cur_cursor_pos = -1;
static char in_putc = 0;
static char polling = 0;
+#if ASYNCH
+static u_char kbd_reply = 0;
+#endif
static int delayed_next_scr;
static char saved_console = -1; /* saved console number */
-static long scrn_blank_time = 0; /* screen saver timout value */
+static long scrn_blank_time = 0; /* screen saver timeout value */
static int scrn_blanked = 0; /* screen saver active flag */
static int scrn_saver = 0; /* screen saver routine */
static long scrn_time_stamp;
static u_char scr_map[256];
+
extern int hz;
extern struct timeval time;
@@ -233,18 +246,14 @@ static u_char *get_fstr(u_int c, u_int *len);
static void update_leds(int which);
static void kbd_wait(void);
static void kbd_cmd(u_char command);
-static void kbd_cmd2(u_char command, u_char arg);
-static int kbd_reply(void);
static void set_mode(scr_stat *scp);
static void set_border(int color);
-static void load_font(int segment, int size, char* font);
+static void copy_font(int direction, int segment, int size, char* font);
static void save_palette(void);
static void load_palette(void);
static void change_winsize(struct tty *tp, int x, int y);
-
/* available screen savers */
-
static void none_saver(int test);
static void blank_saver(int test);
static void fade_saver(int test);
@@ -269,42 +278,26 @@ static const struct {
#if defined(NetBSD)
#define VIRTUAL_TTY(x) pc_tty[x] ? (pc_tty[x]) : (pc_tty[x] = ttymalloc())
#define CONSOLE_TTY pc_tty[NCONS] ? (pc_tty[NCONS]) : (pc_tty[NCONS] = ttymalloc())
-#define frametype struct trapframe
-#define eflags tf_eflags
extern u_short *Crtat;
struct tty *pc_tty[NCONS+1];
int ttrstrt();
#endif
#if defined(__FreeBSD__)
-#define frametype struct trapframe
-#define eflags tf_eflags
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
#define timeout_t timeout_func_t
#define MONO_BUF (KERNBASE+0xB0000)
#define CGA_BUF (KERNBASE+0xB8000)
-#endif
-
-#if defined(__386BSD__) && !defined(__FreeBSD__)
-#define frametype struct syscframe
-#define eflags sf_eflags
-#define timeout_t caddr_t
-#define MONO_BUF (0xFE0B0000)
-#define CGA_BUF (0xFE0B8000)
-#endif
-
-#if defined(__386BSD__) || defined(__FreeBSD__)
-#define VIRTUAL_TTY(x) &pccons[x]
-#define CONSOLE_TTY &pccons[NCONS]
-u_short *Crtat = (u_short *)MONO_BUF;
-struct tty pccons[NCONS+1];
-void consinit(void) {scinit();}
#include "ddb.h"
#if NDDB > 0
#define DDB 1
#endif
+struct tty *pccons[NCONS+1];
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
#endif
-
struct isa_driver scdriver = {
pcprobe, pcattach, "sc",
};
@@ -312,18 +305,47 @@ struct isa_driver scdriver = {
int pcprobe(struct isa_device *dev)
{
+ int i, retries = 5;
+ unsigned char val;
+
/* Enable interrupts and keyboard controller */
kbd_wait();
outb(KB_STAT, KB_WRITE);
- kbd_cmd(0x4D);
+ kbd_wait();
+ outb(KB_DATA, KB_MODE);
- /* Start keyboard stuff RESET */
- for (;;) {
- kbd_cmd(KB_RESET);
- if (kbd_reply() == KB_ACK && /* command accepted */
- kbd_reply() == 0xaa) /* self test passed */
- break;
- printf("Keyboard reset failed\n");
+ /* flush any noise in the buffer */
+ while (inb(KB_STAT) & KB_BUF_FULL) {
+ DELAY(10);
+ (void) inb(KB_DATA);
+ }
+
+ /* Reset keyboard hardware */
+ while (retries--) {
+ kbd_wait();
+ outb(KB_DATA, KB_RESET);
+ for (i=0; i<100000; i++) {
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK || val == KB_ECHO)
+ goto gotres;
+ if (val == KB_RESEND)
+ break;
+ }
+ }
+gotres:
+ if (!retries)
+ printf("scprobe: keyboard won't accept RESET command\n");
+ else {
+gotack:
+ DELAY(10);
+ while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK)
+ goto gotack;
+ if (val != KB_RESET_DONE)
+ printf("scprobe: keyboard RESET failed %02x\n", val);
}
return (IO_KBDSIZE);
}
@@ -358,15 +380,28 @@ int pcattach(struct isa_device *dev)
if (crtc_vga) {
get_cursor_shape(&start, &end);
#endif
+#if defined(HARDFONTS)
+ font_8 = font_8x8;
+ font_14 = font_8x14;
+ font_16 = font_8x16;
+ fonts_loaded = FONT_8_LOADED|FONT_14_LOADED|FONT_16_LOADED;
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ copy_font(LOAD, 0, 16, font_16);
+#else
+ font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
+ font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
+ font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
+ copy_font(SAVE, 0, 16, font_16);
+ fonts_loaded = FONT_16_LOADED;
+#endif
save_palette();
- load_font(0, 16, font_8x16);
- load_font(1, 8, font_8x8);
- load_font(2, 14, font_8x14);
}
current_default = &user_default;
for (i = 0; i < NCONS; i++) {
scp = &console[i];
- scp->scr_buf = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT);
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2,
+ M_DEVBUF, M_NOWAIT);
scp->mode = TEXT80x25;
scp->term.esc = 0;
scp->term.std_attr = current_default->std_attr;
@@ -379,13 +414,14 @@ int pcattach(struct isa_device *dev)
scp->ysize = ROW;
scp->bell_pitch = BELL_PITCH;
scp->bell_duration = BELL_DURATION;
- scp->status = 0;
+ scp->status = NLKED;
scp->pid = 0;
scp->proc = NULL;
scp->smode.mode = VT_AUTO;
if (i > 0) {
scp->crt_base = scp->crtat = scp->scr_buf;
- fillw(scp->term.cur_attr|scr_map[0x20], scp->scr_buf, COL*ROW);
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->scr_buf, COL*ROW);
}
}
/* get cursor going */
@@ -394,6 +430,7 @@ int pcattach(struct isa_device *dev)
console[0].cursor_end);
#endif
cursor_pos(1);
+ update_leds(console[0].status);
return 0;
}
@@ -430,6 +467,7 @@ static int get_scr_num()
return i < NCONS ? i : 0;
}
+
int pcopen(dev_t dev, int flag, int mode, struct proc *p)
{
struct tty *tp = get_tty_ptr(dev);
@@ -441,7 +479,6 @@ int pcopen(dev_t dev, int flag, int mode, struct proc *p)
tp->t_param = pcparam;
tp->t_dev = dev;
if (!(tp->t_state & TS_ISOPEN)) {
- tp->t_state |= TS_WOPEN;
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
@@ -567,7 +604,7 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
int i, error;
struct tty *tp;
- frametype *fp;
+ struct trapframe *fp;
scr_stat *scp;
tp = get_tty_ptr(dev);
@@ -619,25 +656,32 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case CONS_80x50TEXT: /* set 80x50 text mode */
if (!crtc_vga)
return ENXIO;
- scp->mode = TEXT80x50;
- scp->ysize = 50;
- free(scp->scr_buf, M_DEVBUF);
- scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
- M_DEVBUF, M_NOWAIT);
- if (scp != cur_console)
- scp->crt_base = scp->scr_buf;
- set_mode(scp);
- clear_screen(scp);
- change_winsize(tp, scp->xsize, scp->ysize);
- return 0;
+ /* is there a 8x8 font loaded ? */
+ if (fonts_loaded & FONT_8_LOADED) {
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf =
+ (u_short *)malloc(scp->xsize * scp->ysize * 2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+ }
+ else
+ return EINVAL;
case CONS_GETVERS: /* get version number */
*(int*)data = 0x103; /* version 1.3 */
return 0;
case CONS_GETINFO: /* get current (virtual) console info */
- if (*data == sizeof(struct vid_info)) {
+ {
vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
ptr->m_num = get_scr_num();
ptr->mv_col = scp->xpos;
ptr->mv_row = scp->ypos;
@@ -654,6 +698,7 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
return 0;
}
return EINVAL;
+ }
case VT_SETMODE: /* set screen switcher mode */
bcopy(data, &scp->smode, sizeof(struct vt_mode));
@@ -740,13 +785,13 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
return 0;
case KDENABIO: /* allow io operations */
- fp = (frametype *)p->p_regs;
- fp->eflags |= PSL_IOPL;
+ fp = (struct trapframe *)p->p_regs;
+ fp->tf_eflags |= PSL_IOPL;
return 0;
case KDDISABIO: /* disallow io operations (default) */
- fp = (frametype *)p->p_regs;
- fp->eflags &= ~PSL_IOPL;
+ fp = (struct trapframe *)p->p_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
return 0;
case KDSETMODE: /* set current mode of this (virtual) console */
@@ -754,9 +799,9 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case KD_TEXT: /* switch to TEXT (known) mode */
/* restore fonts & palette ! */
if (crtc_vga) {
- load_font(0, 16, font_8x16);
- load_font(1, 8, font_8x8);
- load_font(2, 14, font_8x14);
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
load_palette();
}
/* FALL THROUGH */
@@ -793,7 +838,7 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
scp->status &= ~LOCK_KEY_MASK;
scp->status |= *data;
if (scp == cur_console)
- update_leds(scp->status & LED_MASK);
+ update_leds(scp->status);
return 0;
}
return EINVAL;
@@ -805,7 +850,10 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case KDSETRAD: /* set keyboard repeat & delay rates */
if (*data & 0x80)
return EINVAL;
- kbd_cmd2(KB_SETRAD, *data);
+ i = spltty();
+ kbd_cmd(KB_SETRAD);
+ kbd_cmd(*data);
+ splx(i);
return 0;
case KDSKBMODE: /* set keyboard mode */
@@ -837,18 +885,20 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
if (scp == cur_console) {
if (*(int*)data) {
int pitch = TIMER_FREQ/(*(int*)data);
- /* enable counter 2 */
- outb(0x61, inb(0x61) | 3);
/* set command for counter 2, 2 byte write */
- outb(TIMER_MODE,
- TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE);
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
/* set pitch */
outb(TIMER_CNTR2, pitch);
outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
}
else {
- /* disable counter 2 */
- outb(0x61, inb(0x61) & 0xFC);
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
}
}
return 0;
@@ -862,7 +912,7 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
scp->status &= ~LED_MASK;
scp->status |= *data;
if (scp == cur_console)
- update_leds(scp->status & LED_MASK);
+ update_leds(scp->status);
return 0;
}
return EINVAL;
@@ -914,48 +964,63 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case PIO_FONT8x8: /* set 8x8 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(data, &font_8x8, sizeof(font_8x8));
- load_font(1, 8, font_8x8);
+ bcopy(data, font_8, 8*256);
+ fonts_loaded |= FONT_8_LOADED;
+ copy_font(LOAD, 1, 8, font_8);
return 0;
case GIO_FONT8x8: /* get 8x8 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(&font_8x8, data, sizeof(font_8x8));
- return 0;
+ if (fonts_loaded & FONT_8_LOADED) {
+ bcopy(font_8, data, 8*256);
+ return 0;
+ }
+ else
+ return ENXIO;
case PIO_FONT8x14: /* set 8x14 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(data, &font_8x14, sizeof(font_8x14));
- load_font(2, 14, font_8x14);
+ bcopy(data, font_14, 14*256);
+ fonts_loaded |= FONT_14_LOADED;
+ copy_font(LOAD, 2, 14, font_14);
return 0;
case GIO_FONT8x14: /* get 8x14 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(&font_8x14, data, sizeof(font_8x14));
- return 0;
+ if (fonts_loaded & FONT_14_LOADED) {
+ bcopy(font_14, data, 14*256);
+ return 0;
+ }
+ else
+ return ENXIO;
case PIO_FONT8x16: /* set 8x16 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(data, &font_8x16, sizeof(font_8x16));
- load_font(0, 16, font_8x16);
+ bcopy(data, font_16, 16*256);
+ fonts_loaded |= FONT_16_LOADED;
+ copy_font(LOAD, 0, 16, font_16);
return 0;
case GIO_FONT8x16: /* get 8x16 dot font */
if (!crtc_vga)
return ENXIO;
- bcopy(&font_8x16, data, sizeof(font_8x16));
- return 0;
+ if (fonts_loaded & FONT_16_LOADED) {
+ bcopy(font_16, data, 16*256);
+ return 0;
+ }
+ else
+ return ENXIO;
case CONSOLE_X_MODE_ON: /* just to be compatible */
if (saved_console < 0) {
saved_console = get_scr_num();
switch_scr(minor(dev));
- fp = (frametype *)p->p_regs;
- fp->eflags |= PSL_IOPL;
+ fp = (struct trapframe *)p->p_regs;
+ fp->tf_eflags |= PSL_IOPL;
scp->status |= UNKNOWN_MODE;
scp->status |= KBD_RAW_MODE;
return 0;
@@ -963,12 +1028,12 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
return EAGAIN;
case CONSOLE_X_MODE_OFF:/* just to be compatible */
- fp = (frametype *)p->p_regs;
- fp->eflags &= ~PSL_IOPL;
+ fp = (struct trapframe *)p->p_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
if (crtc_vga) {
- load_font(0, 16, font_8x16);
- load_font(1, 8, font_8x8);
- load_font(2, 14, font_8x14);
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
load_palette();
}
scp->status &= ~UNKNOWN_MODE;
@@ -987,7 +1052,7 @@ int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
*/
if (data)
sysbeep(TIMER_FREQ/((int*)data)[0],
- ((int*)data)[1]*hz/3000);
+ ((int*)data)[1]*hz/1000);
else
sysbeep(scp->bell_pitch, scp->bell_duration);
return 0;
@@ -1054,7 +1119,7 @@ void pcstart(struct tty *tp)
}
splx(s);
-#else /* __FreeBSD__ & __386BSD__ */
+#else /* __FreeBSD__ */
int c, s, len, i;
scr_stat *scp = get_scr_stat(tp->t_dev);
@@ -1065,28 +1130,18 @@ void pcstart(struct tty *tp)
s = spltty();
if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
for (;;) {
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state & TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel,
- tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (RB_LEN(&tp->t_out) == 0)
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT)
+ || tp->t_wsel)
+ ttwwakeup(tp);
+ if (RB_LEN(tp->t_out) == 0)
break;
if (scp->status & SLKED)
break;
len = 0;
while( len < PCBURST) {
- c = getc(&tp->t_out);
- if (c == -1)
+ buf[len++] = getc(tp->t_out);
+ if( RB_LEN(tp->t_out) == 0)
break;
- buf[len++] = c;
}
tp->t_state |= TS_BUSY;
splx(s);
@@ -1122,9 +1177,6 @@ void pccnprobe(struct consdev *cp)
/* initialize required fields */
cp->cn_dev = makedev(maj, NCONS);
cp->cn_pri = CN_INTERNAL;
-#if defined(__FreeBSD__) || defined(__386BSD__)
- cp->cn_tp = CONSOLE_TTY;
-#endif
}
@@ -1161,10 +1213,12 @@ int pccngetc(dev_t dev)
return(c);
}
+
static void none_saver(int test)
{
}
+
static void fade_saver(int test)
{
static int count = 0;
@@ -1195,6 +1249,7 @@ static void fade_saver(int test)
}
}
+
static void blank_saver(int test)
{
u_char val;
@@ -1212,18 +1267,18 @@ static void blank_saver(int test)
static u_long rand_next = 1;
+
static int rand()
{
return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF);
}
+#define NUM_STARS 50
+
/*
* Alternate saver that got its inspiration from a well known utility
* package for an unfamous OS.
*/
-
-#define NUM_STARS 50
-
static void star_saver(int test)
{
scr_stat *scp = cur_console;
@@ -1331,6 +1386,7 @@ static void snake_saver(int test)
}
}
+
static void cursor_shape(int start, int end)
{
outb(crtc_addr, 10);
@@ -1381,10 +1437,6 @@ static void clear_screen(scr_stat *scp)
static int switch_scr(u_int next_scr)
{
- if (in_putc) { /* delay switch if in putc */
- delayed_next_scr = next_scr+1;
- return 0;
- }
if (switch_in_progress &&
(cur_console->proc != pfind(cur_console->pid)))
switch_in_progress = 0;
@@ -1402,7 +1454,10 @@ static int switch_scr(u_int next_scr)
return EINVAL;
}
}
-
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
switch_in_progress = 1;
old_scp = cur_console;
new_scp = &console[next_scr];
@@ -1448,7 +1503,13 @@ static void exchange_scr(void)
new_scp->crt_base = Crtat;
move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
- update_leds(new_scp->status & LED_MASK);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ load_palette();
+ }
if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
shfts = ctls = alts = agrs = metas = 0;
delayed_next_scr = 0;
@@ -1464,6 +1525,7 @@ static void move_crsr(scr_stat *scp, int x, int y)
scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
}
+
static void move_up(u_short *s, u_short *d, u_int len)
{
s += len;
@@ -1472,12 +1534,14 @@ static void move_up(u_short *s, u_short *d, u_int len)
*--d = *--s;
}
+
static void move_down(u_short *s, u_short *d, u_int len)
{
while (len-- > 0)
*d++ = *s++;
}
+
static void scan_esc(scr_stat *scp, u_char c)
{
static u_char ansi_col[16] =
@@ -1746,39 +1810,45 @@ static void scan_esc(scr_stat *scp, u_char c)
break;
case 'm': /* change attribute */
- if (scp->term.num_param == 0)
- n = 0;
- else
- n = scp->term.param[0];
- switch (n) {
- case 0: /* back to normal */
+ if (scp->term.num_param == 0) {
scp->term.cur_attr = scp->term.std_attr;
break;
- case 1: /* highlight (bold) */
- scp->term.cur_attr &= 0xFF00;
- scp->term.cur_attr |= 0x0800;
- break;
- case 4: /* highlight (underline) */
- scp->term.cur_attr &= 0x0F00;
- scp->term.cur_attr |= 0x0800;
- break;
- case 5: /* blink */
- scp->term.cur_attr &= 0xFF00;
- scp->term.cur_attr |= 0x8000;
- break;
- case 7: /* reverse video */
- scp->term.cur_attr = scp->term.rev_attr;
- break;
- case 30: case 31: case 32: case 33: /* set fg color */
- case 34: case 35: case 36: case 37:
- scp->term.cur_attr = (scp->term.cur_attr & 0xF0FF)
- | (ansi_col[(n - 30) & 7] << 8);
- break;
- case 40: case 41: case 42: case 43: /* set bg color */
- case 44: case 45: case 46: case 47:
- scp->term.cur_attr = (scp->term.cur_attr & 0x0FFF)
- | (ansi_col[(n - 40) & 7] << 12);
- break;
+ }
+ for (i = 0; i < scp->term.num_param; i++) {
+ switch (n = scp->term.param[i]) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: /* set fg color */
+ case 32: case 33: case 34:
+ case 35: case 36: case 37:
+ scp->term.cur_attr =
+ (scp->term.cur_attr & 0xF8FF)
+ | (ansi_col[(n-30) & 7] << 8);
+ break;
+ case 40: case 41: /* set bg color */
+ case 42: case 43: case 44:
+ case 45: case 46: case 47:
+ scp->term.cur_attr =
+ (scp->term.cur_attr & 0x8FFF)
+ | (ansi_col[(n-40) & 7] << 12);
+ break;
+ }
}
break;
@@ -1979,6 +2049,7 @@ static void ansi_put(scr_stat *scp, u_char c)
switch_scr(delayed_next_scr - 1);
}
+
static void scinit(void)
{
u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
@@ -2030,7 +2101,7 @@ static void scinit(void)
console[0].border = BG_BLACK;;
console[0].xsize = COL;
console[0].ysize = ROW;
- console[0].status = 0;
+ console[0].status = NLKED;
console[0].pid = 0;
console[0].proc = NULL;
console[0].smode.mode = VT_AUTO;
@@ -2065,7 +2136,7 @@ static void scput(u_char c)
scp->term = save;
--in_putc;
} else {
- if( console_buffer_count < CONSOLE_BUFFER_SIZE)
+ if( console_buffer_count < CONSOLE_BUFSIZE)
console_buffer[console_buffer_count++] = c;
}
}
@@ -2087,9 +2158,20 @@ static u_char *get_fstr(u_int c, u_int *len)
static void update_leds(int which)
{
+ int s;
static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
- kbd_cmd2(KB_SETLEDS, xlate_leds[which & LED_MASK]);
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ s = spltty();
+ kbd_cmd(KB_SETLEDS);
+ kbd_cmd(xlate_leds[which & LED_MASK]);
+ splx(s);
}
@@ -2099,7 +2181,7 @@ static void update_leds(int which)
*/
u_int scgetc(int noblock)
{
- u_char val, code, release;
+ u_char scancode, keycode;
u_int state, action;
struct key_t *key;
static u_char esc_flag = 0, compose = 0;
@@ -2109,132 +2191,136 @@ next_code:
kbd_wait();
/* First see if there is something in the keyboard port */
if (inb(KB_STAT) & KB_BUF_FULL)
- val = inb(KB_DATA);
+ scancode = inb(KB_DATA);
else if (noblock)
return(NOKEY);
else
goto next_code;
if (cur_console->status & KBD_RAW_MODE)
- return val;
-
- code = val & 0x7F;
- release = val & 0x80;
-
+ return scancode;
+#if ASYNCH
+ if (scancode == KB_ACK || scancode == KB_RESEND) {
+ kbd_reply = scancode;
+ if (noblock)
+ return(NOKEY);
+ goto next_code;
+ }
+#endif
+ keycode = scancode & 0x7F;
switch (esc_flag) {
case 0x00: /* normal scancode */
- switch(code) {
- case 0x38: /* left alt (compose key) */
- if (release && compose) {
+ switch(scancode) {
+ case 0xB8: /* left alt (compose key) */
+ if (compose) {
compose = 0;
if (chr > 255) {
sysbeep(BELL_PITCH, BELL_DURATION);
chr = 0;
}
}
- else {
- if (!compose) {
- compose = 1;
- chr = 0;
- }
+ break;
+ case 0x38:
+ if (!compose) {
+ compose = 1;
+ chr = 0;
}
break;
- case 0x60:
- case 0x61:
- esc_flag = code;
+ case 0xE0:
+ case 0xE1:
+ esc_flag = scancode;
goto next_code;
}
break;
- case 0x60: /* 0xE0 prefix */
+ case 0xE0: /* 0xE0 prefix */
esc_flag = 0;
- switch (code) {
- case 0x1c: /* right enter key */
- code = 0x59;
+ switch (keycode) {
+ case 0x1C: /* right enter key */
+ keycode = 0x59;
break;
- case 0x1d: /* right ctrl key */
- code = 0x5a;
+ case 0x1D: /* right ctrl key */
+ keycode = 0x5A;
break;
case 0x35: /* keypad divide key */
- code = 0x5b;
+ keycode = 0x5B;
break;
case 0x37: /* print scrn key */
- code = 0x5c;
+ keycode = 0x5C;
break;
case 0x38: /* right alt key (alt gr) */
- code = 0x5d;
+ keycode = 0x5D;
break;
case 0x47: /* grey home key */
- code = 0x5e;
+ keycode = 0x5E;
break;
case 0x48: /* grey up arrow key */
- code = 0x5f;
+ keycode = 0x5F;
break;
case 0x49: /* grey page up key */
- code = 0x60;
+ keycode = 0x60;
break;
- case 0x4b: /* grey left arrow key */
- code = 0x61;
+ case 0x4B: /* grey left arrow key */
+ keycode = 0x61;
break;
- case 0x4d: /* grey right arrow key */
- code = 0x62;
+ case 0x4D: /* grey right arrow key */
+ keycode = 0x62;
break;
- case 0x4f: /* grey end key */
- code = 0x63;
+ case 0x4F: /* grey end key */
+ keycode = 0x63;
break;
case 0x50: /* grey down arrow key */
- code = 0x64;
+ keycode = 0x64;
break;
case 0x51: /* grey page down key */
- code = 0x65;
+ keycode = 0x65;
break;
case 0x52: /* grey insert key */
- code = 0x66;
+ keycode = 0x66;
break;
case 0x53: /* grey delete key */
- code = 0x67;
+ keycode = 0x67;
break;
default: /* ignore everything else */
goto next_code;
}
break;
- case 0x61: /* 0xE1 prefix */
+ case 0xE1: /* 0xE1 prefix */
esc_flag = 0;
- if (code == 0x1D)
+ if (keycode == 0x1D)
esc_flag = 0x1D;
goto next_code;
/* NOT REACHED */
case 0x1D: /* pause / break */
esc_flag = 0;
- if (code != 0x45)
+ if (keycode != 0x45)
goto next_code;
- code = 0x68;
+ keycode = 0x68;
break;
}
if (compose) {
- switch (code) {
- case 0x47:
- case 0x48: /* keypad 7,8,9 */
- case 0x49:
- if (!release)
- chr = (code - 0x40) + chr*10;
+ switch (scancode) {
+ /* key pressed process it */
+ case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
+ chr = (scancode - 0x40) + chr*10;
goto next_code;
- case 0x4b:
- case 0x4c: /* keypad 4,5,6 */
- case 0x4d:
- if (!release)
- chr = (code - 0x47) + chr*10;
+ case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
+ chr = (scancode - 0x47) + chr*10;
goto next_code;
- case 0x4f:
- case 0x50: /* keypad 1,2,3 */
- case 0x51:
- if (!release)
- chr = (code - 0x4e) + chr*10;
+ case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
+ chr = (scancode - 0x4E) + chr*10;
goto next_code;
case 0x52: /* keypad 0 */
- if (!release)
- chr *= 10;
+ chr *= 10;
+ goto next_code;
+
+ /* key release, no interest here */
+ case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
+ case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
+ case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
+ case 0xD2: /* keypad 0 */
goto next_code;
+
case 0x38: /* left alt key */
break;
default:
@@ -2250,15 +2336,15 @@ next_code:
state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
if ((!agrs && (cur_console->status & ALKED))
|| (agrs && !(cur_console->status & ALKED)))
- code += ALTGR_OFFSET;
- key = &key_map.key[code];
+ keycode += ALTGR_OFFSET;
+ key = &key_map.key[keycode];
if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
|| ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
state ^= 1;
/* Check for make/break */
action = key->map[state];
- if (release) { /* key released */
+ if (scancode & 0x80) { /* key released */
if (key->spcl & 0x80) {
switch (action) {
case LSH:
@@ -2316,7 +2402,7 @@ next_code:
cur_console->status &= ~NLKED;
else
cur_console->status |= NLKED;
- update_leds(cur_console->status & LED_MASK);
+ update_leds(cur_console->status);
}
break;
case CLK:
@@ -2326,7 +2412,7 @@ next_code:
cur_console->status &= ~CLKED;
else
cur_console->status |= CLKED;
- update_leds(cur_console->status & LED_MASK);
+ update_leds(cur_console->status);
}
break;
case SLK:
@@ -2338,7 +2424,7 @@ next_code:
}
else
cur_console->status |= SLKED;
- update_leds(cur_console->status & LED_MASK);
+ update_leds(cur_console->status);
}
break;
case ALK:
@@ -2348,6 +2434,7 @@ next_code:
cur_console->status &= ~ALKED;
else
cur_console->status |= ALKED;
+ update_leds(cur_console->status);
}
break;
@@ -2455,6 +2542,7 @@ u_int sgetc(int noblock)
return (scgetc(noblock) & 0xff);
}
+
int pcmmap(dev_t dev, int offset, int nprot)
{
if (offset > 0x20000)
@@ -2465,9 +2553,9 @@ int pcmmap(dev_t dev, int offset, int nprot)
static void kbd_wait(void)
{
- int i;
+ int i = 1000;
- for (i=0; i<1000; i++) { /* up to 10 msec */
+ while (i--) {
if ((inb(KB_STAT) & KB_READY) == 0)
break;
DELAY (10);
@@ -2477,37 +2565,35 @@ static void kbd_wait(void)
static void kbd_cmd(u_char command)
{
- kbd_wait();
- outb(KB_DATA, command);
-}
-
-
-static void kbd_cmd2(u_char command, u_char arg)
-{
- int r, s = spltty();
+ int retry = 5;
do {
- kbd_cmd(command);
- r = kbd_reply();
- if (r == KB_ACK) {
- kbd_cmd(arg & 0x7f);
- r = kbd_reply();
+ int i = 100000;
+
+ kbd_wait();
+#if ASYNCH
+ kbd_reply = 0;
+ outb(KB_DATA, command);
+ while (i--) {
+ if (kbd_reply == KB_ACK)
+ return;
+ if (kbd_reply == KB_RESEND)
+ break;
}
- } while (r != KB_ACK);
- splx(s);
-}
-
-
-static int kbd_reply()
-{
- int i;
-
- kbd_wait();
- for (i=0; i<60000; i++) { /* at least 300 msec, 600 msec enough */
- if (inb(KB_STAT) & KB_BUF_FULL)
- return ((u_char) inb(KB_DATA));
- DELAY (10);
- }
- return(-1);
+#else
+ outb(KB_DATA, command);
+ while (i--) {
+ if (inb(KB_STAT) & KB_BUF_FULL) {
+ int val;
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK)
+ return;
+ if (val == KB_RESEND)
+ break;
+ }
+ }
+#endif
+ } while (retry--);
}
@@ -2560,10 +2646,11 @@ static void set_border(int color)
inb(crtc_addr+6); /* reset flip-flop */
outb(ATC, 0x11); outb(ATC, color);
inb(crtc_addr+6); /* reset flip-flop */
- outb(ATC, 0x20); /* enable Palette */
+ outb(ATC, 0x20); /* enable Palette */
}
-static void load_font(int segment, int size, char* font)
+
+static void copy_font(int direction, int segment, int size, char* font)
{
int ch, line, s;
u_char val;
@@ -2582,9 +2669,14 @@ static void load_font(int segment, int size, char* font)
outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */
splx(s);
for (ch=0; ch < 256; ch++)
- for (line=0; line < size; line++)
- *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
- font[(ch*size)+line];
+ for (line=0; line < size; line++)
+ if (direction)
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
+ font[(ch*size)+line];
+ else
+ font[(ch*size)+line] =
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line);
+
/* setup vga for text mode again */
s = splhigh();
inb(crtc_addr+6); /* reset flip/flop */
@@ -2617,6 +2709,7 @@ static void load_palette(void)
outb(ATC, 0x20); /* enable palette */
}
+
static void save_palette(void)
{
int i;
diff --git a/sys/i386/isa/tw.c b/sys/i386/isa/tw.c
new file mode 100644
index 000000000000..0a90aa3ace1c
--- /dev/null
+++ b/sys/i386/isa/tw.c
@@ -0,0 +1,997 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+#include "tw.h"
+#if NTW > 0
+
+/*
+ * Driver configuration parameters
+ */
+
+/*
+ * Time for 1/2 of a power line cycle, in microseconds.
+ * Change this to 10000 for 50Hz power. Phil Sampson
+ * (vk2jnt@gw.vk2jnt.ampr.org OR sampson@gidday.enet.dec.com)
+ * reports that this works (at least in Australia) using a
+ * TW7223 module (a local version of the TW523).
+ */
+#define HALFCYCLE 8333 /* 1/2 cycle = 8333us at 60Hz */
+
+/*
+ * Undefine the following if you don't have the high-resolution "microtime"
+ * routines (leave defined for FreeBSD, which has them).
+ */
+#define HIRESTIME
+
+/*
+ * End of driver configuration parameters
+ */
+
+/*
+ * 386BSD Device Driver for X-10 POWERHOUSE (tm)
+ * Two-Way Power Line Interface, Model #TW523
+ *
+ * written by Eugene W. Stark (stark@cs.sunysb.edu)
+ * December 2, 1992
+ *
+ * REVISION HISTORY
+ *
+ * Date Who What
+ * 12/2/92 stark Initial Release
+ * 2/7/93 stark Minor upgrades to timing code
+ * 3/4/93 stark Updated to use high-res. "microtime" routines
+ * 5/9/93 stark Minor changes to console error reporting
+ * 10/30/93 stark Clean-up for FreeBSD release
+ * 3/14/93 stark Clean-up for FreeBSD-1.1 release
+ *
+ * NOTES:
+ *
+ * The TW523 is a carrier-current modem for home control/automation purposes.
+ * It is made by:
+ *
+ * X-10 Inc.
+ * 185A LeGrand Ave.
+ * Northvale, NJ 07647
+ * USA
+ * (201) 784-9700 or 1-800-526-0027
+ *
+ * X-10 Home Controls Inc.
+ * 1200 Aerowood Drive, Unit 20
+ * Mississauga, Ontario
+ * (416) 624-4446 or 1-800-387-3346
+ *
+ * The TW523 is designed for communications using the X-10 protocol,
+ * which is compatible with a number of home control systems, including
+ * Radio Shack "Plug 'n Power(tm)" and Stanley "Lightmaker(tm)."
+ * I bought my TW523 from:
+ *
+ * Home Control Concepts
+ * 9353-C Activity Road
+ * San Diego, CA 92126
+ * (619) 693-8887
+ *
+ * They supplied me with the TW523 (which has an RJ-11 four-wire modular
+ * telephone connector), a modular cable, an RJ-11 to DB-25 connector with
+ * internal wiring, documentation from X-10 on the TW523 (very good),
+ * an instruction manual by Home Control Concepts (not very informative),
+ * and a floppy disk containing binary object code of some demonstration/test
+ * programs and of a C function library suitable for controlling the TW523
+ * by an IBM PC under MS-DOS (not useful to me other than to verify that
+ * the unit worked). I suggest saving money and buying the bare TW523
+ * rather than the TW523 development kit (what I bought), because if you
+ * are running 386BSD you don't really care about the DOS binaries.
+ *
+ * The interface to the TW-523 consists of four wires on the RJ-11 connector,
+ * which are jumpered to somewhat more wires on the DB-25 connector, which
+ * in turn is intended to plug into the PC parallel printer port. I dismantled
+ * the DB-25 connector to find out what they had done:
+ *
+ * Signal RJ-11 pin DB-25 pin(s) Parallel Port
+ * Transmit TX 4 (Y) 2, 4, 6, 8 Data out
+ * Receive RX 3 (G) 10, 14 -ACK, -AutoFeed
+ * Common 2 (R) 25 Common
+ * Zero crossing 1 (B) 17 -Select Input
+ *
+ * The zero crossing signal is used to synchronize transmission to the
+ * zero crossings of the AC line, as detailed in the X-10 documentation.
+ * It would be nice if one could generate interrupts with this signal,
+ * however one needs interrupts on both the rising and falling edges,
+ * and the -ACK signal to the parallel port interrupts only on the falling
+ * edge, so it can't be done without additional hardware.
+ *
+ * In this driver, the transmit function is performed in a non-interrupt-driven
+ * fashion, by polling the zero crossing signal to determine when a transition
+ * has occurred. This wastes CPU time during transmission, but it seems like
+ * the best that can be done without additional hardware. One problem with
+ * the scheme is that preemption of the CPU during transmission can cause loss
+ * of sync. The driver tries to catch this, by noticing that a long delay
+ * loop has somehow become foreshortened, and the transmission is aborted with
+ * an error return. It is up to the user level software to handle this
+ * situation (most likely by retrying the transmission).
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+#include "syslog.h"
+
+#ifdef HIRESTIME
+#include "time.h"
+#endif /* HIRESTIME */
+
+#include "i386/isa/isa_device.h"
+
+void twdelay25();
+void twdelayn(int n);
+void twsetuptimes(int *a);
+int twprobe();
+int twattach();
+void twintr(int unit);
+
+/*
+ * Transmission is done by calling write() to send three byte packets of data.
+ * The first byte contains a four bit house code (0=A to 15=P).
+ * The second byte contains five bit unit/key code (0=unit 1 to 15=unit 16,
+ * 16=All Units Off to 31 = Status Request). The third byte specifies
+ * the number of times the packet is to be transmitted without any
+ * gaps between successive transmissions. Normally this is 2, as per
+ * the X-10 documentation, but sometimes (e.g. for bright and dim codes)
+ * it can be another value. Each call to write can specify an arbitrary
+ * number of data bytes. An incomplete packet is buffered until a subsequent
+ * call to write() provides data to complete it. At most one packet will
+ * actually be processed in any call to write(). Successive calls to write()
+ * leave a three-cycle gap between transmissions, per the X-10 documentation.
+ *
+ * Reception is done using read().
+ * The driver produces a series of three-character packets.
+ * In each packet, the first character consists of flags,
+ * the second character is a four bit house code (0-15),
+ * and the third character is a five bit key/function code (0-31).
+ * The flags are the following:
+ */
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
+/*
+ * IBM PC parallel port definitions relevant to TW523
+ */
+
+#define tw_data 0 /* Data to tw523 (R/W) */
+
+#define tw_status 1 /* Status of tw523 (R) */
+#define TWS_RDATA 0x40 /* tw523 receive data */
+
+#define tw_control 2 /* Control tw523 (R/W) */
+#define TWC_SYNC 0x08 /* tw523 sync (pin 17) */
+#define TWC_ENA 0x10 /* tw523 interrupt enable */
+
+/*
+ * Miscellaneous defines
+ */
+
+#define TWUNIT(dev) (minor(dev)) /* Extract unit number from device */
+#define TWPRI (PZERO+8) /* I don't know any better, so let's */
+ /* use the same as the line printer */
+
+struct isa_driver twdriver = {
+ twprobe, twattach, "tw"
+};
+
+/*
+ * Software control structure for TW523
+ */
+
+#define TWS_XMITTING 1 /* Transmission in progress */
+#define TWS_RCVING 2 /* Reception in progress */
+#define TWS_WANT 4 /* A process wants received data */
+#define TWS_OPEN 8 /* Is it currently open? */
+#define TWS_COLL 16 /* Collision in select */
+
+#define TW_SIZE 3*60 /* Enough for about 10 sec. of input */
+
+struct tw_sc {
+ u_int sc_port; /* I/O Port */
+ u_int sc_state; /* Current software control state */
+ pid_t sc_selp; /* Process sleeping on select */
+ u_char sc_xphase; /* Current state of sync (for transmitter) */
+ u_char sc_rphase; /* Current state of sync (for receiver) */
+ u_char sc_flags; /* Flags for current reception */
+ short sc_rcount; /* Number of bits received so far */
+ int sc_bits; /* Bits received so far */
+ u_char sc_pkt[3]; /* Packet not yet transmitted */
+ short sc_pktsize; /* How many bytes in the packet? */
+ u_char sc_buf[TW_SIZE]; /* We buffer our own input */
+ int sc_nextin; /* Next free slot in circular buffer */
+ int sc_nextout; /* First used slot in circular buffer */
+#ifdef HIRESTIME
+ int sc_xtimes[22]; /* Times for bits in current xmit packet */
+ int sc_rtimes[22]; /* Times for bits in current rcv packet */
+#endif /* HIRESTIME */
+} tw_sc[NTW];
+
+/*
+ * Counter value for delay loop.
+ * It is adjusted by twprobe so that the delay loop takes about 25us.
+ */
+
+#define TWDELAYCOUNT 161 /* Works on my 486DX/33 */
+int twdelaycount;
+
+/*
+ * Twdelay25 is used for very short delays of about 25us.
+ * It is implemented with a calibrated delay loop, and should be
+ * fairly accurate ... unless we are preempted by an interrupt.
+ *
+ * We use this to wait for zero crossings because the X-10 specs say we
+ * are supposed to assert carrier within 25us when one happens.
+ * I don't really believe we can do this, but the X-10 devices seem to be
+ * fairly forgiving.
+ */
+
+void twdelay25()
+{
+ int cnt;
+ for(cnt = twdelaycount; cnt; cnt--); /* Should take about 25us */
+}
+
+/*
+ * Twdelayn is used to time the length of the 1ms carrier pulse.
+ * This is not very critical, but if we have high-resolution time-of-day
+ * we check it every apparent 200us to make sure we don't get too far off
+ * if we happen to be interrupted during the delay.
+ */
+
+void twdelayn(int n)
+{
+#ifdef HIRESTIME
+ int t, d;
+ struct timeval tv;
+ microtime(&tv);
+ t = tv.tv_usec;
+ t += n;
+#endif /* HIRESTIME */
+ while(n > 0) {
+ twdelay25();
+ n -= 25;
+#ifdef HIRESTIME
+ if((n & 0x7) == 0) {
+ microtime(&tv);
+ d = tv.tv_usec - t;
+ if(d >= 0 && d < 1000000) return;
+ }
+#endif /* HIRESTIME */
+ }
+}
+
+int twprobe(idp)
+ struct isa_device *idp;
+{
+ struct tw_sc sc;
+ int d;
+ int tries;
+
+ sc.sc_port = idp->id_iobase;
+ /*
+ * Iteratively check the timing of a few sync transitions, and adjust
+ * the loop delay counter, if necessary, to bring the timing reported
+ * by wait_for_zero() close to HALFCYCLE. Give up if anything
+ * ridiculous happens.
+ */
+ if(twdelaycount == 0) { /* Only adjust timing for first unit */
+ twdelaycount = TWDELAYCOUNT;
+ for(tries = 0; tries < 10; tries++) {
+ sc.sc_xphase = inb(idp->id_iobase + tw_control) & TWC_SYNC;
+ if(wait_for_zero(&sc) >= 0) {
+ d = wait_for_zero(&sc);
+ if(d <= HALFCYCLE/100 || d >= HALFCYCLE*100) {
+ twdelaycount = 0;
+ return(0);
+ }
+ twdelaycount = (twdelaycount * d)/HALFCYCLE;
+ }
+ }
+ }
+ /*
+ * Now do a final check, just to make sure
+ */
+ sc.sc_xphase = inb(idp->id_iobase + tw_control) & TWC_SYNC;
+ if(wait_for_zero(&sc) >= 0) {
+ d = wait_for_zero(&sc);
+ if(d <= (HALFCYCLE * 110)/100 && d >= (HALFCYCLE * 90)/100) return(1);
+ }
+ return(0);
+}
+
+int twattach(idp)
+ struct isa_device *idp;
+{
+ struct tw_sc *sc;
+
+ sc = &tw_sc[idp->id_unit];
+ sc->sc_port = idp->id_iobase;
+ sc->sc_state = 0;
+ return (1);
+}
+
+int twopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
+ int s;
+ int port;
+
+ s = spltty();
+ if(sc->sc_state == 0) {
+ sc->sc_state = TWS_OPEN;
+ sc->sc_nextin = sc->sc_nextout = 0;
+ sc->sc_pktsize = 0;
+ sc->sc_selp = 0;
+ outb(sc->sc_port+tw_control, TWC_ENA);
+ }
+ splx(s);
+ return(0);
+}
+
+int twclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
+ int s;
+ int port = sc->sc_port;
+
+ s = spltty();
+ sc->sc_state = 0;
+ outb(sc->sc_port+tw_control, 0);
+ splx(s);
+ return(0);
+}
+
+int twread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ u_char buf[3];
+ struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
+ int error, cnt, s;
+
+ s = spltty();
+ cnt = MIN(uio->uio_resid, 3);
+ if((error = twgetbytes(sc, buf, cnt)) == 0) {
+ error = uiomove(buf, cnt, uio);
+ }
+ splx(s);
+ return(error);
+}
+
+int twwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ struct tw_sc *sc;
+ int house, key, reps;
+ int s, error;
+ int cnt;
+
+ sc = &tw_sc[TWUNIT(dev)];
+ /*
+ * Note: Although I had intended to allow concurrent transmitters,
+ * there is a potential problem here if two processes both write
+ * into the sc_pkt buffer at the same time. The following code
+ * is an additional critical section that needs to be synchronized.
+ */
+ s = spltty();
+ cnt = MIN(3 - sc->sc_pktsize, uio->uio_resid);
+ if(error = uiomove(&(sc->sc_pkt[sc->sc_pktsize]), cnt, uio)) {
+ splx(s);
+ return(error);
+ }
+ sc->sc_pktsize += cnt;
+ if(sc->sc_pktsize < 3) { /* Only transmit 3-byte packets */
+ splx(s);
+ return(0);
+ }
+ sc->sc_pktsize = 0;
+ /*
+ * Collect house code, key code, and rep count, and check for sanity.
+ */
+ house = sc->sc_pkt[0];
+ key = sc->sc_pkt[1];
+ reps = sc->sc_pkt[2];
+ if(house >= 16 || key >= 32) {
+ splx(s);
+ return(ENODEV);
+ }
+ /*
+ * Synchronize with the receiver operating in the bottom half, and
+ * also with concurrent transmitters.
+ * We don't want to interfere with a packet currently being received,
+ * and we would like the receiver to recognize when a packet has
+ * originated locally.
+ */
+ while(sc->sc_state & (TWS_RCVING | TWS_XMITTING)) {
+ if(error = tsleep((caddr_t)sc, TWPRI|PCATCH, "twwrite", 0)) {
+ splx(s);
+ return(error);
+ }
+ }
+ sc->sc_state |= TWS_XMITTING;
+ /*
+ * Everything looks OK, let's do the transmission.
+ */
+ splx(s); /* Enable interrupts because this takes a LONG time */
+ error = twsend(sc, house, key, reps);
+ s = spltty();
+ sc->sc_state &= ~TWS_XMITTING;
+ wakeup((caddr_t)sc);
+ splx(s);
+ if(error) return(EIO);
+ else return(0);
+}
+
+/*
+ * Determine if there is data available for reading
+ */
+
+int twselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ struct tw_sc *sc;
+ struct proc *pp;
+ int s, i;
+
+ sc = &tw_sc[TWUNIT(dev)];
+ s = spltty();
+ if(sc->sc_nextin != sc->sc_nextout) {
+ splx(s);
+ return(1);
+ }
+ if(sc->sc_selp && (pp = pfind(sc->sc_selp))
+ && pp->p_wchan == (caddr_t)&selwait) {
+ sc->sc_state |= TWS_COLL;
+ } else {
+ sc->sc_selp = p->p_pid;
+ }
+ splx(s);
+ return(0);
+}
+
+/*
+ * X-10 Protocol
+ */
+
+#define X10_START_LENGTH 4
+char X10_START[] = { 1, 1, 1, 0 };
+
+/*
+ * Each bit of the 4-bit house code and 5-bit key code
+ * is transmitted twice, once in true form, and then in
+ * complemented form. This is already taken into account
+ * in the following tables.
+ */
+
+#define X10_HOUSE_LENGTH 8
+char X10_HOUSE[16][8] = {
+ 0, 1, 1, 0, 1, 0, 0, 1, /* A = 0110 */
+ 1, 0, 1, 0, 1, 0, 0, 1, /* B = 1110 */
+ 0, 1, 0, 1, 1, 0, 0, 1, /* C = 0010 */
+ 1, 0, 0, 1, 1, 0, 0, 1, /* D = 1010 */
+ 0, 1, 0, 1, 0, 1, 1, 0, /* E = 0001 */
+ 1, 0, 0, 1, 0, 1, 1, 0, /* F = 1001 */
+ 0, 1, 1, 0, 0, 1, 1, 0, /* G = 0101 */
+ 1, 0, 1, 0, 0, 1, 1, 0, /* H = 1101 */
+ 0, 1, 1, 0, 1, 0, 1, 0, /* I = 0111 */
+ 1, 0, 1, 0, 1, 0, 1, 0, /* J = 1111 */
+ 0, 1, 0, 1, 1, 0, 1, 0, /* K = 0011 */
+ 1, 0, 0, 1, 1, 0, 1, 0, /* L = 1011 */
+ 0, 1, 0, 1, 0, 1, 0, 1, /* M = 0000 */
+ 1, 0, 0, 1, 0, 1, 0, 1, /* N = 1000 */
+ 0, 1, 1, 0, 0, 1, 0, 1, /* O = 0100 */
+ 1, 0, 1, 0, 0, 1, 0, 1 /* P = 1100 */
+};
+
+#define X10_KEY_LENGTH 10
+char X10_KEY[32][10] = {
+ 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, /* 01100 => 1 */
+ 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, /* 11100 => 2 */
+ 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, /* 00100 => 3 */
+ 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, /* 10100 => 4 */
+ 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, /* 00010 => 5 */
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, /* 10010 => 6 */
+ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 01010 => 7 */
+ 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, /* 11010 => 8 */
+ 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, /* 01110 => 9 */
+ 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, /* 11110 => 10 */
+ 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, /* 00110 => 11 */
+ 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 10110 => 12 */
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, /* 00000 => 13 */
+ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 10000 => 14 */
+ 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, /* 01000 => 15 */
+ 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, /* 11000 => 16 */
+ 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, /* 00001 => All Units Off */
+ 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, /* 00011 => All Units On */
+ 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, /* 00101 => On */
+ 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, /* 00111 => Off */
+ 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 01001 => Dim */
+ 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, /* 01011 => Bright */
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, /* 01101 => All LIGHTS Off */
+ 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, /* 01111 => Extended Code */
+ 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, /* 10001 => Hail Request */
+ 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, /* 10011 => Hail Acknowledge */
+ 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, /* 10101 => Preset Dim 0 */
+ 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, /* 10111 => Preset Dim 1 */
+ 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, /* 11000 => Extended Data (analog) */
+ 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, /* 11011 => Status = on */
+ 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, /* 11101 => Status = off */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 /* 11111 => Status request */
+};
+
+/*
+ * Tables for mapping received X-10 code back to house/key number.
+ */
+
+short X10_HOUSE_INV[16] = { 12, 4, 2, 10, 14, 6, 0, 8,
+ 13, 5, 3, 11, 15, 7, 1, 9 };
+
+short X10_KEY_INV[32] = { 12, 16, 4, 17, 2, 18, 10, 19,
+ 14, 20, 6, 21, 0, 22, 8, 23,
+ 13, 24, 5, 25, 3, 26, 11, 27,
+ 15, 28, 7, 29, 1, 30, 9, 31 };
+
+/*
+ * Transmit a packet containing house code h and key code k
+ */
+
+#define TWRETRY 10 /* Try 10 times to sync with AC line */
+
+int twsend(sc, h, k, cnt)
+struct tw_sc *sc;
+int h, k, cnt;
+{
+ int i;
+ int port = sc->sc_port;
+
+ /*
+ * Make sure we get a reliable sync with a power line zero crossing
+ */
+ for(i = 0; i < TWRETRY; i++) {
+ if(wait_for_zero(sc) > 100) goto insync;
+ }
+ log(LOG_ERR, "TWXMIT: failed to sync.\n");
+ return(-1);
+
+ insync:
+ /*
+ * Be sure to leave 3 cycles space between transmissions
+ */
+ for(i = 6; i > 0; i--)
+ if(next_zero(sc) < 0) return(-1);
+ /*
+ * The packet is transmitted cnt times, with no gaps.
+ */
+ while(cnt--) {
+ /*
+ * Transmit the start code
+ */
+ for(i = 0; i < X10_START_LENGTH; i++) {
+ outb(port+tw_data, X10_START[i] ? 0xff : 0x00); /* Waste no time! */
+#ifdef HIRESTIME
+ if(i == 0) twsetuptimes(sc->sc_xtimes);
+ if(twchecktime(sc->sc_xtimes[i], HALFCYCLE/20) == 0) {
+ outb(port+tw_data, 0);
+ return(-1);
+ }
+#endif /* HIRESTIME */
+ twdelayn(1000); /* 1ms pulse width */
+ outb(port+tw_data, 0);
+ if(next_zero(sc) < 0) return(-1);
+ }
+ /*
+ * Transmit the house code
+ */
+ for(i = 0; i < X10_HOUSE_LENGTH; i++) {
+ outb(port+tw_data, X10_HOUSE[h][i] ? 0xff : 0x00); /* Waste no time! */
+#ifdef HIRESTIME
+ if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH], HALFCYCLE/20) == 0) {
+ outb(port+tw_data, 0);
+ return(-1);
+ }
+#endif /* HIRESTIME */
+ twdelayn(1000); /* 1ms pulse width */
+ outb(port+tw_data, 0);
+ if(next_zero(sc) < 0) return(-1);
+ }
+ /*
+ * Transmit the unit/key code
+ */
+ for(i = 0; i < X10_KEY_LENGTH; i++) {
+ outb(port+tw_data, X10_KEY[k][i] ? 0xff : 0x00);
+#ifdef HIRESTIME
+ if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH+X10_HOUSE_LENGTH],
+ HALFCYCLE/20) == 0) {
+ outb(port+tw_data, 0);
+ return(-1);
+ }
+#endif /* HIRESTIME */
+ twdelayn(1000); /* 1ms pulse width */
+ outb(port+tw_data, 0);
+ if(next_zero(sc) < 0) return(-1);
+ }
+ }
+ return(0);
+}
+
+/*
+ * Waste CPU cycles to get in sync with a power line zero crossing.
+ * The value returned is roughly how many microseconds we wasted before
+ * seeing the transition. To avoid wasting time forever, we give up after
+ * waiting patiently for 1/4 sec (15 power line cycles at 60 Hz),
+ * which is more than the 11 cycles it takes to transmit a full
+ * X-10 packet.
+ */
+
+int wait_for_zero(sc)
+struct tw_sc *sc;
+{
+ int i, old, new, max, cnt;
+ int port = sc->sc_port + tw_control;
+
+ old = sc->sc_xphase;
+ max = 10000; /* 10000 * 25us = 0.25 sec */
+ i = 0;
+ while(max--) {
+ new = inb(port) & TWC_SYNC;
+ if(new != old) {
+ sc->sc_xphase = new;
+ return(i*25);
+ }
+ i++;
+ twdelay25();
+ }
+ return(-1);
+}
+
+/*
+ * Wait for the next zero crossing transition, and if we don't have
+ * high-resolution time-of-day, check to see that the zero crossing
+ * appears to be arriving on schedule.
+ * We expect to be waiting almost a full half-cycle (8.333ms-1ms = 7.333ms).
+ * If we don't seem to wait very long, something is wrong (like we got
+ * preempted!) and we should abort the transmission because
+ * there's no telling how long it's really been since the
+ * last bit was transmitted.
+ */
+
+int next_zero(sc)
+struct tw_sc *sc;
+{
+ int d;
+#ifdef HIRESTIME
+ if((d = wait_for_zero(sc)) < 0) {
+#else
+ if((d = wait_for_zero(sc)) < 6000 || d > 8500) {
+ /* No less than 6.0ms, no more than 8.5ms */
+#endif /* HIRESTIME */
+ log(LOG_ERR, "TWXMIT framing error: %d\n", d);
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * Put a three-byte packet into the circular buffer
+ * Should be called at priority spltty()
+ */
+
+int twputpkt(sc, p)
+struct tw_sc *sc;
+u_char *p;
+{
+ int i, next;
+
+ for(i = 0; i < 3; i++) {
+ next = sc->sc_nextin+1;
+ if(next >= TW_SIZE) next = 0;
+ if(next == sc->sc_nextout) { /* Buffer full */
+/*
+ log(LOG_ERR, "TWRCV: Buffer overrun\n");
+ */
+ return(1);
+ }
+ sc->sc_buf[sc->sc_nextin] = *p++;
+ sc->sc_nextin = next;
+ }
+ if(sc->sc_state & TWS_WANT) {
+ sc->sc_state &= ~TWS_WANT;
+ wakeup((caddr_t)(&sc->sc_buf));
+ }
+ if(sc->sc_selp) {
+ selwakeup(sc->sc_selp, sc->sc_state & TWS_COLL);
+ sc->sc_selp = 0;
+ sc->sc_state &= ~TWS_COLL;
+ }
+ return(0);
+}
+
+/*
+ * Get bytes from the circular buffer
+ * Should be called at priority spltty()
+ */
+
+int twgetbytes(sc, p, cnt)
+struct tw_sc *sc;
+u_char *p;
+int cnt;
+{
+ int error;
+
+ while(cnt--) {
+ while(sc->sc_nextin == sc->sc_nextout) { /* Buffer empty */
+ sc->sc_state |= TWS_WANT;
+ if(error = tsleep((caddr_t)(&sc->sc_buf), TWPRI|PCATCH, "twread", 0)) {
+ return(error);
+ }
+ }
+ *p++ = sc->sc_buf[sc->sc_nextout++];
+ if(sc->sc_nextout >= TW_SIZE) sc->sc_nextout = 0;
+ }
+ return(0);
+}
+
+/*
+ * Abort reception that has failed to complete in the required time.
+ */
+
+void twabortrcv(sc)
+struct tw_sc *sc;
+{
+ int s;
+ u_char pkt[3];
+
+ s = spltty();
+ sc->sc_state &= ~TWS_RCVING;
+ sc->sc_flags |= TW_RCV_ERROR;
+ pkt[0] = sc->sc_flags;
+ pkt[1] = pkt[2] = 0;
+ twputpkt(sc, pkt);
+ log(LOG_ERR, "TWRCV: aborting (%x, %d)\n", sc->sc_bits, sc->sc_rcount);
+ wakeup((caddr_t)sc);
+ splx(s);
+}
+
+/*
+ * This routine handles interrupts that occur when there is a falling
+ * transition on the RX input. There isn't going to be a transition
+ * on every bit (some are zero), but if we are smart and keep track of
+ * how long it's been since the last interrupt (via the zero crossing
+ * detect line and/or high-resolution time-of-day routine), we can
+ * reconstruct the transmission without having to poll.
+ */
+
+void twintr(unit)
+int unit;
+{
+ struct tw_sc *sc = &tw_sc[unit];
+ int port;
+ int newphase;
+ u_char pkt[3];
+
+ port = sc->sc_port;
+ /*
+ * Ignore any interrupts that occur if the device is not open.
+ */
+ if(sc->sc_state == 0) return;
+ newphase = inb(port + tw_control) & TWC_SYNC;
+ /*
+ * NEW PACKET:
+ * If we aren't currently receiving a packet, set up a new packet
+ * and put in the first "1" bit that has just arrived.
+ * Arrange for the reception to be aborted if too much time goes by.
+ */
+ if((sc->sc_state & TWS_RCVING) == 0) {
+#ifdef HIRESTIME
+ twsetuptimes(sc->sc_rtimes);
+#endif /* HIRESTIME */
+ sc->sc_state |= TWS_RCVING;
+ sc->sc_rcount = 1;
+ if(sc->sc_state & TWS_XMITTING) sc->sc_flags = TW_RCV_LOCAL;
+ else sc->sc_flags = 0;
+ sc->sc_bits = 0;
+ sc->sc_rphase = newphase;
+ timeout((timeout_func_t)twabortrcv, (caddr_t)sc, hz/4);
+ return;
+ }
+ /*
+ * START CODE:
+ * The second and third bits are a special case.
+ */
+ if(sc->sc_rcount < 3) {
+#ifdef HIRESTIME
+ if(twchecktime(sc->sc_rtimes[sc->sc_rcount], HALFCYCLE/3)
+ && newphase != sc->sc_rphase) {
+#else
+ if(newphase != sc->sc_rphase) {
+#endif
+ sc->sc_rcount++;
+ } else {
+ /*
+ * Invalid start code -- abort reception.
+ */
+ sc->sc_state &= ~TWS_RCVING;
+ sc->sc_flags |= TW_RCV_ERROR;
+/*
+ pkt[0] = sc->sc_flags;
+ pkt[1] = pkt[2] = 0;
+ twputpkt(sc, pkt);
+ wakeup((caddr_t)sc);
+ */
+ untimeout((timeout_func_t)twabortrcv, (caddr_t)sc);
+ log(LOG_ERR, "TWRCV: Invalid start code\n");
+ return;
+ }
+ if(sc->sc_rcount == 3) {
+ /*
+ * We've gotten three "1" bits in a row. The start code
+ * is really 1110, but this might be followed by a zero
+ * bit from the house code, so if we wait any longer we
+ * might be confused about the first house code bit.
+ * So, we guess that the start code is correct and insert
+ * the trailing zero without actually having seen it.
+ * We don't change sc_rphase in this case, because two
+ * bit arrivals in a row preserve parity.
+ */
+ sc->sc_rcount++;
+ return;
+ }
+ /*
+ * Update sc_rphase to the current phase before returning.
+ */
+ sc->sc_rphase = newphase;
+ return;
+ }
+ /*
+ * GENERAL CASE:
+ * Now figure out what the current bit is that just arrived.
+ * The X-10 protocol transmits each data bit twice: once in
+ * true form and once in complemented form on the next half
+ * cycle. So, there will be at least one interrupt per bit.
+ * By comparing the phase we see at the time of the interrupt
+ * with the saved sc_rphase, we can tell on which half cycle
+ * the interrupt occrred. This assumes, of course, that the
+ * packet is well-formed. We do the best we can at trying to
+ * catch errors by aborting if too much time has gone by, and
+ * by tossing out a packet if too many bits arrive, but the
+ * whole scheme is probably not as robust as if we had a nice
+ * interrupt on every half cycle of the power line.
+ * If we have high-resolution time-of-day routines, then we
+ * can do a bit more sanity checking.
+ */
+
+ /*
+ * A complete packet is 22 half cycles.
+ */
+ if(sc->sc_rcount <= 20) {
+#ifdef HIRESTIME
+ if((newphase == sc->sc_rphase &&
+ twchecktime(sc->sc_rtimes[sc->sc_rcount+1], HALFCYCLE/3) == 0)
+ || (newphase != sc->sc_rphase &&
+ twchecktime(sc->sc_rtimes[sc->sc_rcount], HALFCYCLE/3) == 0)) {
+ sc->sc_flags |= TW_RCV_ERROR;
+ } else {
+#endif /* HIRESTIME */
+ sc->sc_bits = (sc->sc_bits << 1)
+ | ((newphase == sc->sc_rphase) ? 0x0 : 0x1);
+ sc->sc_rcount += 2;
+#ifdef HIRESTIME
+ }
+#endif /* HIRESTIME */
+ }
+ if(sc->sc_rcount >= 22 || sc->sc_flags & TW_RCV_ERROR) {
+ if(sc->sc_rcount != 22) {
+ sc->sc_flags |= TW_RCV_ERROR;
+ pkt[0] = sc->sc_flags;
+ pkt[1] = pkt[2] = 0;
+ } else {
+ pkt[0] = sc->sc_flags;
+ pkt[1] = X10_HOUSE_INV[(sc->sc_bits & 0x1e0) >> 5];
+ pkt[2] = X10_KEY_INV[sc->sc_bits & 0x1f];
+ }
+ sc->sc_state &= ~TWS_RCVING;
+ twputpkt(sc, pkt);
+ untimeout((timeout_func_t)twabortrcv, (caddr_t)sc);
+ if(sc->sc_flags & TW_RCV_ERROR)
+ log(LOG_ERR, "TWRCV: invalid packet: (%d, %x)\n",
+ sc->sc_rcount, sc->sc_bits);
+ wakeup((caddr_t)sc);
+ }
+}
+
+#ifdef HIRESTIME
+/*
+ * Initialize an array of 22 times, starting from the current
+ * microtime and continuing for the next 21 half cycles.
+ * We use the times as a reference to make sure transmission
+ * or reception is on schedule.
+ */
+
+void twsetuptimes(int *a)
+{
+ struct timeval tv;
+ int i, t;
+
+ microtime(&tv);
+ t = tv.tv_usec;
+ for(i = 0; i < 22; i++) {
+ *a++ = t;
+ t += HALFCYCLE;
+ if(t >= 1000000) t -= 1000000;
+ }
+}
+
+/*
+ * Check the current time against a slot in a previously set up
+ * timing array, and make sure that it looks like we are still
+ * on schedule.
+ */
+
+int twchecktime(int target, int tol)
+{
+ struct timeval tv;
+ int t, d;
+
+ microtime(&tv);
+ t = tv.tv_usec;
+ d = (target - t) >= 0 ? (target - t) : (t - target);
+ if(d > 500000) d = 1000000-d;
+ if(d <= tol && d >= -tol) {
+ return(1);
+ } else {
+ log(LOG_ERR, "TWCHK: timing off by %dus (>= %dus)\n", d, tol);
+ return(0);
+ }
+}
+#endif /* HIRESTIME */
+
+#endif NTW
diff --git a/sys/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c
index 230868b33746..d2bc4c39b171 100644
--- a/sys/i386/isa/ultra14f.c
+++ b/sys/i386/isa/ultra14f.c
@@ -19,7 +19,7 @@
* commenced: Sun Sep 27 18:14:01 PDT 1992
* slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993
*
- * $Id: ultra14f.c,v 1.15 1994/01/29 10:29:14 rgrimes Exp $
+ * $Id: ultra14f.c,v 1.17 1994/03/24 02:23:00 davidg Exp $
*/
#include <sys/types.h>
@@ -465,6 +465,7 @@ uha_attach(dev)
uha->sc_link.adapter_targ = uha->our_id;
uha->sc_link.adapter = &uha_switch;
uha->sc_link.device = &uha_dev;
+ uha->sc_link.flags = SDEV_BOUNCE;
/*
* ask the adapter what subunits are present
@@ -675,7 +676,8 @@ uha_get_mscp(unit, flags)
goto gottit;
} else {
if (!(flags & SCSI_NOSLEEP)) {
- sleep(&uha->free_mscp, PRIBIO);
+ tsleep((caddr_t)&uha->free_mscp, PRIBIO,
+ "uhamscp", 0);
}
}
}
diff --git a/sys/i386/isa/vector.s b/sys/i386/isa/vector.s
index f6bb78fce97a..835da9cdf320 100644
--- a/sys/i386/isa/vector.s
+++ b/sys/i386/isa/vector.s
@@ -1,6 +1,6 @@
/*
* from: vector.s, 386BSD 0.1 unknown origin
- * $Id: vector.s,v 1.6 1994/01/10 23:15:09 ache Exp $
+ * $Id: vector.s,v 1.7 1994/04/02 07:00:50 davidg Exp $
*/
#include "i386/isa/icu.h"
@@ -12,24 +12,44 @@
#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+#ifdef AUTO_EOI_1
+#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
+#else
#define ENABLE_ICU1 \
movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
FASTER_NOP ; /* ... ASAP ... */ \
outb %al,$IO_ICU1 /* ... to clear in service bit */
-#ifdef AUTO_EOI_1
-#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */
-#define ENABLE_ICU1
#endif
+#ifdef AUTO_EOI_2
+/*
+ * The data sheet says no auto-EOI on slave, but it sometimes works.
+ */
+#define ENABLE_ICU1_AND_2 ENABLE_ICU1
+#else
#define ENABLE_ICU1_AND_2 \
movb $ICU_EOI,%al ; /* as above */ \
FASTER_NOP ; \
outb %al,$IO_ICU2 ; /* but do second icu first */ \
FASTER_NOP ; \
outb %al,$IO_ICU1 /* then first icu */
-#ifdef AUTO_EOI_2
-#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */
-#define ENABLE_ICU1_AND_2 /* ... but it works */
+#endif
+
+#ifdef FAST_INTR_HANDLER_USES_ES
+#define ACTUALLY_PUSHED 1
+#define MAYBE_MOVW_AX_ES movl %ax,%es
+#define MAYBE_POPL_ES popl %es
+#define MAYBE_PUSHL_ES pushl %es
+#else
+/*
+ * We can usually skip loading %es for fastintr handlers. %es should
+ * only be used for string instructions, and fastintr handlers shouldn't
+ * do anything slow enough to justify using a string instruction.
+ */
+#define ACTUALLY_PUSHED 0
+#define MAYBE_MOVW_AX_ES
+#define MAYBE_POPL_ES
+#define MAYBE_PUSHL_ES
#endif
/*
@@ -82,39 +102,63 @@
pushl %ecx ; \
pushl %edx ; \
pushl %ds ; \
- /* pushl %es ; know compiler doesn't do string insns */ \
+ MAYBE_PUSHL_ES ; \
movl $KDSEL,%eax ; \
movl %ax,%ds ; \
- /* movl %ax,%es ; */ \
- SHOW_CLI ; /* although it interferes with "ASAP" */ \
+ MAYBE_MOVW_AX_ES ; \
+ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \
pushl $unit ; \
call handler ; /* do the work ASAP */ \
enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
addl $4,%esp ; \
incl _cnt+V_INTR ; /* book-keeping can wait */ \
- COUNT_EVENT(_intrcnt_actv, id_num) ; \
- SHOW_STI ; \
- /* popl %es ; */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \
+ notl %eax ; \
+ andl _ipending,%eax ; \
+ jne 1f ; /* yes, handle them */ \
+ MEXITCOUNT ; \
+ MAYBE_POPL_ES ; \
popl %ds ; \
- popl %edx; \
- popl %ecx; \
- popl %eax; \
- iret
+ popl %edx ; \
+ popl %ecx ; \
+ popl %eax ; \
+ iret ; \
+; \
+ ALIGN_TEXT ; \
+1: ; \
+ movl _cpl,%eax ; \
+ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \
+ sti ; /* ... to do this as early as possible */ \
+ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \
+ popl %ecx ; /* ... original %ds ... */ \
+ popl %edx ; \
+ xchgl %eax,(1+ACTUALLY_PUSHED)*4(%esp) ; /* orig %eax; save cpl */ \
+ pushal ; /* build fat frame (grrr) ... */ \
+ pushl %ecx ; /* ... actually %ds ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%es ; \
+ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \
+ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \
+ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \
+ pushl %eax ; \
+ subl $4,%esp ; /* junk for unit number */ \
+ MEXITCOUNT ; \
+ jmp _doreti
#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
- pushl $0 ; /* dummy error code */ \
- pushl $T_ASTFLT ; \
+ pushl $0 ; /* dumby error code */ \
+ pushl $0 ; /* dumby trap type */ \
pushal ; \
- pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %ds ; /* save our data and extra segments ... */ \
pushl %es ; \
movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
- movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \
+ movl %ax,%ds ; /* ... early for obsolete reasons */ \
movl %ax,%es ; \
- SHOW_CLI ; /* interrupt did an implicit cli */ \
movb _imen + IRQ_BYTE(irq_num),%al ; \
orb $IRQ_BIT(irq_num),%al ; \
movb %al,_imen + IRQ_BYTE(irq_num) ; \
- SHOW_IMEN ; \
FASTER_NOP ; \
outb %al,$icu+1 ; \
enable_icus ; \
@@ -123,32 +167,32 @@
testb $IRQ_BIT(irq_num),%reg ; \
jne 2f ; \
1: ; \
- COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
movl _cpl,%eax ; \
pushl %eax ; \
pushl $unit ; \
orl mask,%eax ; \
movl %eax,_cpl ; \
- SHOW_CPL ; \
- SHOW_STI ; \
sti ; \
call handler ; \
movb _imen + IRQ_BYTE(irq_num),%al ; \
andb $~IRQ_BIT(irq_num),%al ; \
movb %al,_imen + IRQ_BYTE(irq_num) ; \
- SHOW_IMEN ; \
FASTER_NOP ; \
outb %al,$icu+1 ; \
- jmp doreti ; \
+ MEXITCOUNT ; \
+ /* We could usually avoid the following jmp by inlining some of */ \
+ /* _doreti, but it's probably better to use less cache. */ \
+ jmp _doreti ; \
; \
ALIGN_TEXT ; \
2: ; \
- COUNT_EVENT(_intrcnt_pend, id_num) ; \
+ /* XXX skip mcounting here to avoid double count */ \
movl $1b,%eax ; /* register resume address */ \
/* XXX - someday do it at attach time */ \
- movl %eax,Vresume + (irq_num) * 4 ; \
+ movl %eax,ihandlers + (irq_num) * 4 ; \
orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
- SHOW_IPENDING ; \
popl %es ; \
popl %ds ; \
popal ; \
@@ -191,7 +235,7 @@
.globl _V/**/name ; \
SUPERALIGN_TEXT ; \
_V/**/name: ; \
- FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables)
+ FAST_INTR(unit, irq_num,id_num, handler, ENABLE_ICU/**/icu_enables)
#undef BUILD_VECTOR
#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
@@ -201,9 +245,10 @@ _V/**/name: ; \
.globl _V/**/name ; \
SUPERALIGN_TEXT ; \
_V/**/name: ; \
- INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \
+ INTR(unit,irq_num, id_num, mask, handler, IO_ICU/**/icu_num, \
ENABLE_ICU/**/icu_enables, reg,)
+MCOUNT_LABEL(bintr)
BUILD_VECTORS
/* hardware interrupt catcher (IDT 32 - 47) */
@@ -211,7 +256,7 @@ _V/**/name: ; \
#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
IDTVEC(intr/**/irq_num) ; \
- INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \
+ INTR(irq_num,irq_num,irq_num, _high_imask, _isa_strayintr, \
IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
/*
@@ -241,6 +286,7 @@ IDTVEC(intr/**/irq_num) ; \
STRAYINTR(4,1,1, al)
STRAYINTR(5,1,1, al)
STRAYINTR(6,1,1, al)
+ STRAYINTR(7,1,1, al)
STRAYINTR(8,2,1_AND_2, ah)
STRAYINTR(9,2,1_AND_2, ah)
STRAYINTR(10,2,1_AND_2, ah)
@@ -249,11 +295,11 @@ IDTVEC(intr/**/irq_num) ; \
STRAYINTR(13,2,1_AND_2, ah)
STRAYINTR(14,2,1_AND_2, ah)
STRAYINTR(15,2,1_AND_2, ah)
-IDTVEC(intrdefault)
- STRAYINTR(7,1,1, al) /* XXX */
#if 0
INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
#endif
+MCOUNT_LABEL(eintr)
+
/*
* These are the interrupt counters, I moved them here from icu.s so that
* they are with the name table. rgrimes
@@ -263,7 +309,15 @@ IDTVEC(intrdefault)
* work with vmstat.
*/
.data
-Vresume: .space 32 * 4 /* where to resume intr handler after unpend */
+ihandlers: /* addresses of interrupt handlers */
+ .space NHWI*4 /* actually resumption addresses for HWI's */
+ .long swi_tty, swi_net, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, swi_clock, swi_ast
+imasks: /* masks for interrupt handlers */
+ .space NHWI*4 /* padding; HWI masks are elsewhere */
+ .long SWI_TTY_MASK, SWI_NET_MASK, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK
+
.globl _intrcnt
_intrcnt: /* used by vmstat to calc size of table */
.globl _intrcnt_bad7
@@ -274,14 +328,8 @@ _intrcnt_bad15: .space 4 /* glitches on irq 15 */
_intrcnt_stray: .space 4 /* total count of stray interrupts */
.globl _intrcnt_actv
_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
- .globl _intrcnt_pend
-_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */
.globl _eintrcnt
_eintrcnt: /* used by vmstat to calc size of table */
- .globl _intrcnt_spl
-_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */
- .globl _intrcnt_show
-_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */
/*
* Build the interrupt name table for vmstat
@@ -296,8 +344,9 @@ _intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */
.ascii "name irq" ; \
.asciz "irq_num"
/*
- * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize
- * and concatenate names above and elsewhere.
+ * XXX - use the __STRING and __CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere. Note that __CONCAT doesn't
+ * work when nested.
*/
.text
@@ -308,61 +357,4 @@ _intrnames:
BUILD_VECTOR(stray,,,,,,,,)
BUILD_VECTORS
-#undef BUILD_FAST_VECTOR
-#define BUILD_FAST_VECTOR BUILD_VECTOR
-
-#undef BUILD_VECTOR
-#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
- icu_num, icu_enables, reg) \
- .asciz "name pend"
-
- BUILD_VECTORS
_eintrnames:
-
-/*
- * now the spl names
- */
- .asciz "unpend_v"
- .asciz "doreti"
- .asciz "p0!ni"
- .asciz "!p0!ni"
- .asciz "p0ni"
- .asciz "netisr_raw"
- .asciz "netisr_ip"
- .asciz "netisr_imp"
- .asciz "netisr_ns"
- .asciz "netisr_iso"
- .asciz "softclock" /* 10 */
- .asciz "trap"
- .asciz "doreti_exit2"
- .asciz "splbio"
- .asciz "splclock"
- .asciz "splhigh"
- .asciz "splimp"
- .asciz "splnet"
- .asciz "splsoftclock"
- .asciz "spltty"
- .asciz "spl0" /* 20 */
- .asciz "netisr_raw2"
- .asciz "netisr_ip2"
- .asciz "netisr_imp2"
- .asciz "netisr_ns2"
- .asciz "netisr_iso2"
- .asciz "splx"
- .asciz "splx!0"
- .asciz "unpend_V"
- .asciz "netisr_x25"
- .asciz "netisr_hdlc"
- .asciz "spl31"
-/*
- * now the mask names
- */
- .asciz "cli"
- .asciz "cpl"
- .asciz "imen"
- .asciz "ipending"
- .asciz "sti"
- .asciz "mask5" /* mask5-mask7 are spares */
- .asciz "mask6"
- .asciz "mask7"
-
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index cb22340349e5..d141f040f0e0 100644
--- a/sys/i386/isa/wd.c
+++ b/sys/i386/isa/wd.c
@@ -37,7 +37,7 @@ static int wdtest = 0;
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
- * $Id: wd.c,v 1.33.2.1 1994/03/07 01:42:55 rgrimes Exp $
+ * $Id: wd.c,v 1.40 1994/06/17 16:57:03 pst Exp $
*/
/* TODO:
@@ -83,11 +83,11 @@ static int wdtest = 0;
#include "syslog.h"
#include "vm/vm.h"
-#define TIMEOUT 10000 /* XXX? WDCC_DIAGNOSE can take > 1.1 sec */
-
+#define TIMEOUT 10000
#define RETRIES 5 /* number of retries before giving up */
#define RECOVERYTIME 500000 /* usec for controller to recover after err */
#define MAXTRANSFER 256 /* max size of transfer in sectors */
+#define BAD144_NO_CYL 0xffff /* XXX should be in dkbad.h; bad144.c uses -1 */
#ifdef notyet
#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
@@ -149,6 +149,7 @@ struct disk {
struct dos_partition
dk_dospartitions[NDOSPART]; /* DOS view of disk */
struct dkbad dk_bad; /* bad sector table */
+ long dk_badsect[127]; /* 126 plus trailing -1 marker */
};
static struct disk *wddrives[NWD]; /* table of units */
@@ -159,6 +160,8 @@ static struct buf rwdbuf[NWD]; /* buffers for raw IO */
#endif
static long wdxfer[NWD]; /* count of transfers */
+
+static void bad144intern(struct disk *);
static int wdprobe(struct isa_device *dvp);
static int wdattach(struct isa_device *dvp);
static void wdustart(struct disk *du);
@@ -209,9 +212,46 @@ wdprobe(struct isa_device *dvp)
/* execute a controller only command */
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
- || wdwait(du, 0, TIMEOUT) != 0)
+ || wdwait(du, 0, TIMEOUT) < 0)
goto nodevice;
+ /*
+ * drive(s) did not time out during diagnostic :
+ * Get error status and check that both drives are OK.
+ * Table 9-2 of ATA specs suggests that we must check for
+ * a value of 0x01
+ *
+ * Strangely, some controllers will return a status of
+ * 0x81 (drive 0 OK, drive 1 failure), and then when
+ * the DRV bit is set, return status of 0x01 (OK) for
+ * drive 2. (This seems to contradict the ATA spec.)
+ */
+ du->dk_error = inb(du->dk_port + wd_error);
+ /* printf("Error : %x\n", du->dk_error); */
+ if(du->dk_error != 0x01) {
+ if(du->dk_error & 0x80) { /* drive 1 failure */
+
+ /* first set the DRV bit */
+ u_int sdh;
+ sdh = inb(du->dk_port+ wd_sdh);
+ sdh = sdh | 0x10;
+ outb(du->dk_port+ wd_sdh, sdh);
+
+ /* Wait, to make sure drv 1 has completed diags */
+ if ( wdwait(du, 0, TIMEOUT) < 0)
+ goto nodevice;
+
+ /* Get status for drive 1 */
+ du->dk_error = inb(du->dk_port + wd_error);
+ /* printf("Error (drv 1) : %x\n", du->dk_error); */
+
+ if(du->dk_error != 0x01)
+ goto nodevice;
+ } else /* drive 0 fail */
+ goto nodevice;
+ }
+
+
free(du, M_TEMP);
return (IO_WDCSIZE);
@@ -318,13 +358,14 @@ wdstrategy(register struct buf *bp)
goto done;
}
+#if !defined(DISKLABEL_UNPROTECTED)
/* "soft" write protect check */
if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
bp->b_error = EROFS;
bp->b_flags |= B_ERROR;
goto done;
}
-
+#endif /* !defined(DISKLABEL_UNPROTECTED) */
/*
* Do bounds checking, adjust transfer, and set b_cylin.
*/
@@ -333,10 +374,32 @@ wdstrategy(register struct buf *bp)
du->dk_wlabel) <= 0)
goto done;
+ /*
+ * Check for *any* block on this transfer being on the bad block list
+ * if it is, then flag the block as a transfer that requires
+ * bad block handling. Also, used as a hint for low level disksort
+ * clustering code to keep from coalescing a bad transfer into
+ * a normal transfer. Single block transfers for a large number of
+ * blocks associated with a cluster I/O are undersirable.
+ */
+ if( du->dk_flags & DKFL_BADSECT) {
+ int i;
+ int nsecs = howmany(bp->b_bcount, DEV_BSIZE);
+ int blkend = bp->b_pblkno + nsecs;
+ for(i=0;du->dk_badsect[i] != -1 && du->dk_badsect[i] < blkend;i++) {
+ if( du->dk_badsect[i] >= bp->b_pblkno) {
+ bp->b_flags |= B_BAD;
+ break;
+ }
+ }
+ }
+
/* queue transfer on drive, activate drive and controller if idle */
dp = &wdutab[lunit];
s = splbio();
- disksort(dp, bp);
+
+ cldisksort(dp, bp, 254*DEV_BSIZE);
+
if (dp->b_active == 0)
wdustart(du); /* start drive */
@@ -352,8 +415,10 @@ wdstrategy(register struct buf *bp)
return;
done:
+ s = splbio();
/* toss transfer, we're done early */
biodone(bp);
+ splx(s);
}
/*
@@ -440,7 +505,7 @@ loop:
}
/* calculate transfer details */
- blknum = bp->b_blkno + du->dk_skip;
+ blknum = bp->b_pblkno + du->dk_skip;
#ifdef WDDEBUG
if (du->dk_skip == 0)
printf("wd%d: wdstart: %s %d@%d; map ", lunit,
@@ -449,67 +514,49 @@ loop:
else
printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts));
#endif
- if (du->dk_skip == 0)
- du->dk_bc = bp->b_bcount;
lp = &du->dk_dd;
secpertrk = lp->d_nsectors;
secpercyl = lp->d_secpercyl;
- if (wddospart(bp->b_dev))
- blknum += du->dk_dd2.d_partitions[wdpart(bp->b_dev)].p_offset;
- else
- blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
- cylin = blknum / secpercyl;
- head = (blknum % secpercyl) / secpertrk;
- sector = blknum % secpertrk;
- /*
- * See if the current block is in the bad block list.
- * (If we have one, and not formatting.)
- */
- if ((du->dk_flags & (DKFL_SINGLE | DKFL_BADSECT))
- == (DKFL_SINGLE | DKFL_BADSECT))
-#define BAD144_NO_CYL 0xffff /* XXX should be in dkbad.h; bad144.c uses -1 */
- for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != BAD144_NO_CYL;
- bt_ptr++) {
- if (bt_ptr->bt_cyl > cylin)
- /* Sorted list, and we passed our cylinder. quit. */
- break;
- if (bt_ptr->bt_cyl == cylin &&
- bt_ptr->bt_trksec == (head << 8) + sector) {
- /*
- * Found bad block. Calculate new block number.
- * This starts at the end of the disk (skip the
- * last track which is used for the bad block list),
- * and works backwards to the front of the disk.
- */
-#ifdef WDDEBUG
- printf("--- badblock code -> Old = %ld; ", blknum);
-#endif
+ if (du->dk_skip == 0) {
+ du->dk_bc = bp->b_bcount;
+ if (bp->b_flags & B_BAD) {
+ du->dk_flags |= DKFL_SINGLE;
+ }
+ }
+
+ if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/
+ == (DKFL_SINGLE|DKFL_BADSECT)) {
+ int i;
+ for(i=0;
+ du->dk_badsect[i] != -1 && du->dk_badsect[i] <= blknum;
+ i++) {
+
+ if( du->dk_badsect[i] == blknum) {
/*
* XXX the offset of the bad sector table ought
* to be stored in the in-core copy of the table.
*/
#define BAD144_PART 2 /* XXX scattered magic numbers */
#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
- if (lp->d_partitions[BSD_PART].p_offset != 0)
- blknum = lp->d_partitions[BAD144_PART].p_offset
- + lp->d_partitions[BAD144_PART].p_size;
- else
- blknum = lp->d_secperunit;
- blknum -= lp->d_nsectors + (bt_ptr - du->dk_bad.bt_bad)
- + 1;
-
- cylin = blknum / secpercyl;
- head = (blknum % secpercyl) / secpertrk;
- sector = blknum % secpertrk;
-#ifdef WDDEBUG
- printf("new = %ld\n", blknum);
-#endif
- break;
+ if (lp->d_partitions[BSD_PART].p_offset != 0)
+ blknum = lp->d_partitions[BAD144_PART].p_offset
+ + lp->d_partitions[BAD144_PART].p_size;
+ else
+ blknum = lp->d_secperunit;
+ blknum -= lp->d_nsectors + i + 1;
+
+ break;
+ }
}
}
+
+
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
wdtab[ctrlr].b_active = 1; /* mark controller active */
@@ -643,7 +690,7 @@ wdintr(int unit)
return;
case 1:
wdstart(unit);
- return;
+ return;
case 2:
goto done;
}
@@ -690,6 +737,9 @@ oops:
chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
/* ready to receive data? */
+ if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+ != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+ wderror(bp, du, "wdintr: read intr arrived early");
if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
wderror(bp, du, "wdintr: read error detected late");
goto oops;
@@ -840,8 +890,10 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
du->dk_flags |= DKFL_BSDLABEL;
du->dk_flags &= ~DKFL_WRITEPROT;
- if (du->dk_dd.d_flags & D_BADSECT)
+ if (du->dk_dd.d_flags & D_BADSECT) {
du->dk_flags |= DKFL_BADSECT;
+ bad144intern(du);
+ }
/*
* Force WDRAW partition to be the whole disk.
@@ -1008,6 +1060,7 @@ wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
static int
wdsetctlr(struct disk *du)
{
+ int error = 0;
#ifdef WDDEBUG
printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
du->dk_ctrlr, du->dk_unit,
@@ -1028,8 +1081,18 @@ wdsetctlr(struct disk *du)
}
else {
printf("(truncating to 16)\n");
- du->dk_dd.d_ntracks = 16;
+ du->dk_dd.d_ntracks = 16;
+ }
}
+
+ if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
+ printf("wd%d: cannot handle %lu sectors (max 255)\n",
+ du->dk_lunit, du->dk_dd.d_nsectors);
+ error = 1;
+ }
+ if (error) {
+ wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
+ return (1);
}
if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
du->dk_dd.d_nsectors, WDCC_IDC) != 0
@@ -1215,8 +1278,10 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
case DIOCSBAD:
if ((flag & FWRITE) == 0)
error = EBADF;
- else
+ else {
du->dk_bad = *(struct dkbad *)addr;
+ bad144intern(du);
+ }
break;
case DIOCGDINFO:
@@ -1735,4 +1800,27 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout)
return (-1);
}
+/*
+ * Internalize the bad sector table.
+ */
+void bad144intern(struct disk *du) {
+ int i;
+ if (du->dk_flags & DKFL_BADSECT) {
+ for (i = 0; i < 127; i++) {
+ du->dk_badsect[i] = -1;
+ }
+ for (i = 0; i < 126; i++) {
+ if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) {
+ break;
+ } else {
+ du->dk_badsect[i] =
+ du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
+ (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors
++
+ (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff);
+ }
+ }
+ }
+}
+
#endif /* NWDC > 0 */
diff --git a/sys/i386/isa/wt.c b/sys/i386/isa/wt.c
index 307c5062b2be..783df59433bd 100644
--- a/sys/i386/isa/wt.c
+++ b/sys/i386/isa/wt.c
@@ -19,7 +19,7 @@
* the original CMU copyright notice.
*
* Version 1.3, Thu Nov 11 12:09:13 MSK 1993
- * $Id: wt.c,v 1.5 1993/12/19 00:50:50 wollman Exp $
+ * $Id: wt.c,v 1.6 1994/06/29 06:11:20 jkh Exp $
*
*/
@@ -895,6 +895,7 @@ static int wtstatus (wtinfo_t *t)
outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
wtpoll (t, t->BUSY, 0); /* wait for not ready */
+ DELAY(30);
outb (t->CTLPORT, t->ONLINE); /* unset request */
}
return (1);
diff --git a/sys/i386/isa/wt.c.orig b/sys/i386/isa/wt.c.orig
new file mode 100644
index 000000000000..572802a6fa9b
--- /dev/null
+++ b/sys/i386/isa/wt.c.orig
@@ -0,0 +1,902 @@
+/*
+ * Streamer tape driver for 386bsd and FreeBSD.
+ * Supports Archive and Wangtek compatible QIC-02/QIC-36 boards.
+ *
+ * Copyright (C) 1993 by:
+ * Sergey Ryzhkov <sir@kiae.su>
+ * Serge Vakulenko <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * This driver is derived from the old 386bsd Wangtek streamer tape driver,
+ * made by Robert Baron at CMU, based on Intel sources.
+ * Authors thank Robert Baron, CMU and Intel and retain here
+ * the original CMU copyright notice.
+ *
+ * Version 1.3, Thu Nov 11 12:09:13 MSK 1993
+ * $Id: wt.c,v 1.6 1994/06/29 06:11:20 jkh Exp $
+ *
+ */
+
+/*
+ * Copyright (c) 1989 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Robert Baron
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "wt.h"
+#if NWT > 0
+
+#include "sys/param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "sys/buf.h"
+#include "sys/fcntl.h"
+#include "sys/malloc.h"
+#include "sys/ioctl.h"
+#include "sys/mtio.h"
+#include "vm/vm_param.h"
+#include "i386/include/pio.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/wtreg.h"
+
+/*
+ * Uncomment this to enable internal device tracing.
+ */
+#define DEBUG(s) /* printf s */
+
+#define WTPRI (PZERO+10) /* sleep priority */
+
+/*
+ * Wangtek controller ports
+ */
+#define WT_CTLPORT(base) ((base)+0) /* control, write only */
+#define WT_STATPORT(base) ((base)+0) /* status, read only */
+#define WT_CMDPORT(base) ((base)+1) /* command, write only */
+#define WT_DATAPORT(base) ((base)+1) /* data, read only */
+#define WT_NPORT 2 /* 2 i/o ports */
+
+/* status port bits */
+#define WT_BUSY 0x01 /* not ready bit define */
+#define WT_NOEXCEP 0x02 /* no exception bit define */
+#define WT_RESETMASK 0x07 /* to check after reset */
+#define WT_RESETVAL 0x05 /* state after reset */
+
+/* control port bits */
+#define WT_ONLINE 0x01 /* device selected */
+#define WT_RESET 0x02 /* reset command */
+#define WT_REQUEST 0x04 /* request command */
+#define WT_IEN 0x08 /* enable dma */
+
+/*
+ * Archive controller ports
+ */
+#define AV_DATAPORT(base) ((base)+0) /* data, read only */
+#define AV_CMDPORT(base) ((base)+0) /* command, write only */
+#define AV_STATPORT(base) ((base)+1) /* status, read only */
+#define AV_CTLPORT(base) ((base)+1) /* control, write only */
+#define AV_SDMAPORT(base) ((base)+2) /* start dma */
+#define AV_RDMAPORT(base) ((base)+3) /* reset dma */
+#define AV_NPORT 4 /* 4 i/o ports */
+
+/* status port bits */
+#define AV_BUSY 0x40 /* not ready bit define */
+#define AV_NOEXCEP 0x20 /* no exception bit define */
+#define AV_RESETMASK 0xf8 /* to check after reset */
+#define AV_RESETVAL 0x50 /* state after reset */
+
+/* control port bits */
+#define AV_RESET 0x80 /* reset command */
+#define AV_REQUEST 0x40 /* request command */
+#define AV_IEN 0x20 /* enable interrupts */
+
+enum wttype {
+ UNKNOWN = 0, /* unknown type, driver disabled */
+ ARCHIVE, /* Archive Viper SC499, SC402 etc */
+ WANGTEK, /* Wangtek */
+};
+
+typedef struct {
+ unsigned short err; /* code for error encountered */
+ unsigned short ercnt; /* number of error blocks */
+ unsigned short urcnt; /* number of underruns */
+} wtstatus_t;
+
+typedef struct {
+ enum wttype type; /* type of controller */
+ unsigned unit; /* unit number */
+ unsigned port; /* base i/o port */
+ unsigned chan; /* dma channel number, 1..3 */
+ unsigned flags; /* state of tape drive */
+ unsigned dens; /* tape density */
+ int bsize; /* tape block size */
+ void *buf; /* internal i/o buffer */
+
+ void *dmavaddr; /* virtual address of dma i/o buffer */
+ unsigned dmatotal; /* size of i/o buffer */
+ unsigned dmaflags; /* i/o direction, B_READ or B_WRITE */
+ unsigned dmacount; /* resulting length of dma i/o */
+
+ wtstatus_t error; /* status of controller */
+
+ unsigned short DATAPORT, CMDPORT, STATPORT, CTLPORT, SDMAPORT, RDMAPORT;
+ unsigned char BUSY, NOEXCEP, RESETMASK, RESETVAL;
+ unsigned char ONLINE, RESET, REQUEST, IEN;
+} wtinfo_t;
+
+wtinfo_t wttab[NWT]; /* tape info by unit number */
+
+static int wtwait (wtinfo_t *t, int catch, char *msg);
+static int wtcmd (wtinfo_t *t, int cmd);
+static int wtstart (wtinfo_t *t, unsigned mode, void *vaddr, unsigned len);
+static void wtdma (wtinfo_t *t);
+static void wtimer (caddr_t, int);
+static void wtclock (wtinfo_t *t);
+static int wtreset (wtinfo_t *t);
+static int wtsense (wtinfo_t *t, int verb, int ignor);
+static int wtstatus (wtinfo_t *t);
+static void wtrewind (wtinfo_t *t);
+static int wtreadfm (wtinfo_t *t);
+static int wtwritefm (wtinfo_t *t);
+static int wtpoll (wtinfo_t *t, int mask, int bits);
+
+/* XXX */
+extern void DELAY (int usec);
+
+/*
+ * Probe for the presence of the device.
+ */
+int wtprobe (struct isa_device *id)
+{
+ wtinfo_t *t = wttab + id->id_unit;
+
+ t->unit = id->id_unit;
+ t->chan = id->id_drq;
+ t->port = id->id_iobase;
+ if (t->chan<1 || t->chan>3) {
+ printf ("wt%d: Bad drq=%d, should be 1..3\n", t->unit, t->chan);
+ return (0);
+ }
+
+ /* Try Wangtek. */
+ t->type = WANGTEK;
+ t->CTLPORT = WT_CTLPORT (t->port); t->STATPORT = WT_STATPORT (t->port);
+ t->CMDPORT = WT_CMDPORT (t->port); t->DATAPORT = WT_DATAPORT (t->port);
+ t->SDMAPORT = 0; t->RDMAPORT = 0;
+ t->BUSY = WT_BUSY; t->NOEXCEP = WT_NOEXCEP;
+ t->RESETMASK = WT_RESETMASK; t->RESETVAL = WT_RESETVAL;
+ t->ONLINE = WT_ONLINE; t->RESET = WT_RESET;
+ t->REQUEST = WT_REQUEST; t->IEN = WT_IEN;
+ if (wtreset (t))
+ return (WT_NPORT);
+
+ /* Try Archive. */
+ t->type = ARCHIVE;
+ t->CTLPORT = AV_CTLPORT (t->port); t->STATPORT = AV_STATPORT (t->port);
+ t->CMDPORT = AV_CMDPORT (t->port); t->DATAPORT = AV_DATAPORT (t->port);
+ t->SDMAPORT = AV_SDMAPORT (t->port); t->RDMAPORT = AV_RDMAPORT (t->port);
+ t->BUSY = AV_BUSY; t->NOEXCEP = AV_NOEXCEP;
+ t->RESETMASK = AV_RESETMASK; t->RESETVAL = AV_RESETVAL;
+ t->ONLINE = 0; t->RESET = AV_RESET;
+ t->REQUEST = AV_REQUEST; t->IEN = AV_IEN;
+ if (wtreset (t))
+ return (AV_NPORT);
+
+ /* Tape controller not found. */
+ t->type = UNKNOWN;
+ return (0);
+}
+
+/*
+ * Device is found, configure it.
+ */
+int wtattach (struct isa_device *id)
+{
+ wtinfo_t *t = wttab + id->id_unit;
+
+ if (t->type == ARCHIVE) {
+ printf ("wt%d: type <Archive>\n", t->unit);
+ outb (t->RDMAPORT, 0); /* reset dma */
+ } else
+ printf ("wt%d: type <Wangtek>\n", t->unit);
+ t->flags = TPSTART; /* tape is rewound */
+ t->dens = -1; /* unknown density */
+ return (1);
+}
+
+struct isa_driver wtdriver = { wtprobe, wtattach, "wt", };
+
+int wtdump (int dev)
+{
+ /* Not implemented */
+ return (EINVAL);
+}
+
+int wtsize (int dev)
+{
+ /* Not implemented */
+ return (-1);
+}
+
+/*
+ * Open routine, called on every device open.
+ */
+int wtopen (int dev, int flag)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int error;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ /* Check that device is not in use */
+ if (t->flags & TPINUSE)
+ return (EBUSY);
+
+ /* If the tape is in rewound state, check the status and set density. */
+ if (t->flags & TPSTART) {
+ /* If rewind is going on, wait */
+ if (error = wtwait (t, PCATCH, "wtrew"))
+ return (error);
+
+ /* Check the controller status */
+ if (! wtsense (t, 0, (flag & FWRITE) ? 0 : TP_WRP)) {
+ /* Bad status, reset the controller */
+ if (! wtreset (t))
+ return (EIO);
+ if (! wtsense (t, 1, (flag & FWRITE) ? 0 : TP_WRP))
+ return (EIO);
+ }
+
+ /* Set up tape density. */
+ if (t->dens != (minor (dev) & WT_DENSEL)) {
+ int d = 0;
+
+ switch (minor (dev) & WT_DENSEL) {
+ case WT_DENSDFLT: default: break; /* default density */
+ case WT_QIC11: d = QIC_FMT11; break; /* minor 010 */
+ case WT_QIC24: d = QIC_FMT24; break; /* minor 020 */
+ case WT_QIC120: d = QIC_FMT120; break; /* minor 030 */
+ case WT_QIC150: d = QIC_FMT150; break; /* minor 040 */
+ case WT_QIC300: d = QIC_FMT300; break; /* minor 050 */
+ case WT_QIC600: d = QIC_FMT600; break; /* minor 060 */
+ }
+ if (d) {
+ /* Change tape density. */
+ if (! wtcmd (t, d))
+ return (EIO);
+ if (! wtsense (t, 1, TP_WRP | TP_ILL))
+ return (EIO);
+
+ /* Check the status of the controller. */
+ if (t->error.err & TP_ILL) {
+ printf ("wt%d: invalid tape density\n", t->unit);
+ return (ENODEV);
+ }
+ }
+ t->dens = minor (dev) & WT_DENSEL;
+ }
+ t->flags &= ~TPSTART;
+ } else if (t->dens != (minor (dev) & WT_DENSEL))
+ return (ENXIO);
+
+ t->bsize = (minor (dev) & WT_BSIZE) ? 1024 : 512;
+ t->buf = malloc (t->bsize, M_TEMP, M_WAITOK);
+ if (! t->buf)
+ return (EAGAIN);
+
+ t->flags = TPINUSE;
+ if (flag & FREAD)
+ t->flags |= TPREAD;
+ if (flag & FWRITE)
+ t->flags |= TPWRITE;
+ return (0);
+}
+
+/*
+ * Close routine, called on last device close.
+ */
+int wtclose (int dev)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ /* If rewind is pending, do nothing */
+ if (t->flags & TPREW)
+ goto done;
+
+ /* If seek forward is pending and no rewind on close, do nothing */
+ if (t->flags & TPRMARK) {
+ if (minor (dev) & T_NOREWIND)
+ goto done;
+
+ /* If read file mark is going on, wait */
+ wtwait (t, 0, "wtrfm");
+ }
+
+ if (t->flags & TPWANY)
+ /* Tape was written. Write file mark. */
+ wtwritefm (t);
+
+ if (! (minor (dev) & T_NOREWIND)) {
+ /* Rewind tape to beginning of tape. */
+ /* Don't wait until rewind, though. */
+ wtrewind (t);
+ goto done;
+ }
+ if ((t->flags & TPRANY) && ! (t->flags & (TPVOL | TPWANY)))
+ /* Space forward to after next file mark if no writing done. */
+ /* Don't wait for completion. */
+ wtreadfm (t);
+done:
+ t->flags &= TPREW | TPRMARK | TPSTART | TPTIMER;
+ free (t->buf, M_TEMP);
+ return (0);
+}
+
+/*
+ * Ioctl routine. Compatible with BSD ioctls.
+ * Direct QIC-02 commands ERASE and RETENSION added.
+ * There are three possible ioctls:
+ * ioctl (int fd, MTIOCGET, struct mtget *buf) -- get status
+ * ioctl (int fd, MTIOCTOP, struct mtop *buf) -- do BSD-like op
+ * ioctl (int fd, WTQICMD, int qicop) -- do QIC op
+ */
+int wtioctl (int dev, int cmd, void *arg, int mode)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int error, count, op;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ switch (cmd) {
+ default:
+ return (EINVAL);
+ case WTQICMD: /* direct QIC command */
+ op = (int) *(void**)arg;
+ switch (op) {
+ default:
+ return (EINVAL);
+ case QIC_ERASE: /* erase the whole tape */
+ if (! (t->flags & TPWRITE) || (t->flags & TPWP))
+ return (EACCES);
+ if (error = wtwait (t, PCATCH, "wterase"))
+ return (error);
+ break;
+ case QIC_RETENS: /* retension the tape */
+ if (error = wtwait (t, PCATCH, "wtretens"))
+ return (error);
+ break;
+ }
+ /* Both ERASE and RETENS operations work like REWIND. */
+ /* Simulate the rewind operation here. */
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ if (! wtcmd (t, op))
+ return (EIO);
+ t->flags |= TPSTART | TPREW;
+ if (op == QIC_ERASE)
+ t->flags |= TPWANY;
+ wtclock (t);
+ return (0);
+ case MTIOCIEOT: /* ignore EOT errors */
+ case MTIOCEEOT: /* enable EOT errors */
+ return (0);
+ case MTIOCGET:
+ ((struct mtget*)arg)->mt_type =
+ t->type == ARCHIVE ? MT_ISVIPER1 : 0x11;
+ ((struct mtget*)arg)->mt_dsreg = t->flags; /* status */
+ ((struct mtget*)arg)->mt_erreg = t->error.err; /* errors */
+ ((struct mtget*)arg)->mt_resid = 0;
+ ((struct mtget*)arg)->mt_fileno = 0; /* file */
+ ((struct mtget*)arg)->mt_blkno = 0; /* block */
+ return (0);
+ case MTIOCTOP:
+ break;
+ }
+ switch ((short) ((struct mtop*)arg)->mt_op) {
+ default:
+ case MTFSR: /* forward space record */
+ case MTBSR: /* backward space record */
+ case MTBSF: /* backward space file */
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ return (0);
+ case MTREW: /* rewind */
+ case MTOFFL: /* rewind and put the drive offline */
+ if (t->flags & TPREW) /* rewind is running */
+ return (0);
+ if (error = wtwait (t, PCATCH, "wtorew"))
+ return (error);
+ wtrewind (t);
+ return (0);
+ case MTFSF: /* forward space file */
+ for (count=((struct mtop*)arg)->mt_count; count>0; --count) {
+ if (error = wtwait (t, PCATCH, "wtorfm"))
+ return (error);
+ if (error = wtreadfm (t))
+ return (error);
+ }
+ return (0);
+ case MTWEOF: /* write an end-of-file record */
+ if (! (t->flags & TPWRITE) || (t->flags & TPWP))
+ return (EACCES);
+ if (error = wtwait (t, PCATCH, "wtowfm"))
+ return (error);
+ if (error = wtwritefm (t))
+ return (error);
+ return (0);
+ }
+ return (EINVAL);
+}
+
+/*
+ * Strategy routine.
+ */
+void wtstrategy (struct buf *bp)
+{
+ int u = minor (bp->b_dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int s;
+
+ bp->b_resid = bp->b_bcount;
+ if (u >= NWT || t->type == UNKNOWN)
+ goto errxit;
+
+ /* at file marks and end of tape, we just return '0 bytes available' */
+ if (t->flags & TPVOL)
+ goto xit;
+
+ if (bp->b_flags & B_READ) {
+ /* Check read access and no previous write to this tape. */
+ if (! (t->flags & TPREAD) || (t->flags & TPWANY))
+ goto errxit;
+
+ /* For now, we assume that all data will be copied out */
+ /* If read command outstanding, just skip down */
+ if (! (t->flags & TPRO)) {
+ if (! wtsense (t, 1, TP_WRP)) /* clear status */
+ goto errxit;
+ if (! wtcmd (t, QIC_RDDATA)) { /* sed read mode */
+ wtsense (t, 1, TP_WRP);
+ goto errxit;
+ }
+ t->flags |= TPRO | TPRANY;
+ }
+ } else {
+ /* Check write access and write protection. */
+ /* No previous read from this tape allowed. */
+ if (! (t->flags & TPWRITE) || (t->flags & (TPWP | TPRANY)))
+ goto errxit;
+
+ /* If write command outstanding, just skip down */
+ if (! (t->flags & TPWO)) {
+ if (! wtsense (t, 1, 0)) /* clear status */
+ goto errxit;
+ if (! wtcmd (t, QIC_WRTDATA)) { /* set write mode */
+ wtsense (t, 1, 0);
+ goto errxit;
+ }
+ t->flags |= TPWO | TPWANY;
+ }
+ }
+
+ if (! bp->b_bcount)
+ goto xit;
+
+ t->flags &= ~TPEXCEP;
+ s = splbio ();
+ if (wtstart (t, bp->b_flags, bp->b_un.b_addr, bp->b_bcount)) {
+ wtwait (t, 0, (bp->b_flags & B_READ) ? "wtread" : "wtwrite");
+ bp->b_resid -= t->dmacount;
+ }
+ splx (s);
+
+ if (t->flags & TPEXCEP) {
+errxit: bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+xit: biodone (bp);
+ return;
+}
+
+/*
+ * Interrupt routine.
+ */
+void wtintr (int u)
+{
+ wtinfo_t *t = wttab + u;
+ unsigned char s;
+
+ if (u >= NWT || t->type == UNKNOWN) {
+ DEBUG (("wtintr() -- device not configured\n"));
+ return;
+ }
+
+ s = inb (t->STATPORT); /* get status */
+ DEBUG (("wtintr() status=0x%x -- ", s));
+ if ((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP)) {
+ DEBUG (("busy\n"));
+ return; /* device is busy */
+ }
+
+ /*
+ * Check if rewind finished.
+ */
+ if (t->flags & TPREW) {
+ DEBUG (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
+ "rewind busy?\n" : "rewind finished\n"));
+ t->flags &= ~TPREW; /* Rewind finished. */
+ wtsense (t, 1, TP_WRP);
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ /*
+ * Check if writing/reading of file mark finished.
+ */
+ if (t->flags & (TPRMARK | TPWMARK)) {
+ DEBUG (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
+ "marker r/w busy?\n" : "marker r/w finished\n"));
+ if (! (s & t->NOEXCEP)) /* operation failed */
+ wtsense (t, 1, (t->flags & TPRMARK) ? TP_WRP : 0);
+ t->flags &= ~(TPRMARK | TPWMARK); /* operation finished */
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ /*
+ * Do we started any i/o? If no, just return.
+ */
+ if (! (t->flags & TPACTIVE)) {
+ DEBUG (("unexpected interrupt\n"));
+ return;
+ }
+ t->flags &= ~TPACTIVE;
+ t->dmacount += t->bsize; /* increment counter */
+
+ /*
+ * Clean up dma.
+ */
+ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize) {
+ /* If reading short block, copy the internal buffer
+ * to the user memory. */
+ isa_dmadone (t->dmaflags, t->buf, t->bsize, t->chan);
+ bcopy (t->buf, t->dmavaddr, t->dmatotal - t->dmacount);
+ } else
+ isa_dmadone (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
+
+ /*
+ * On exception, check for end of file and end of volume.
+ */
+ if (! (s & t->NOEXCEP)) {
+ DEBUG (("i/o exception\n"));
+ wtsense (t, 1, (t->dmaflags & B_READ) ? TP_WRP : 0);
+ if (t->error.err & (TP_EOM | TP_FIL))
+ t->flags |= TPVOL; /* end of file */
+ else
+ t->flags |= TPEXCEP; /* i/o error */
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ if (t->dmacount < t->dmatotal) { /* continue i/o */
+ t->dmavaddr += t->bsize;
+ wtdma (t);
+ DEBUG (("continue i/o, %d\n", t->dmacount));
+ return;
+ }
+ if (t->dmacount > t->dmatotal) /* short last block */
+ t->dmacount = t->dmatotal;
+ wakeup ((caddr_t)t); /* wake up user level */
+ DEBUG (("i/o finished, %d\n", t->dmacount));
+}
+
+/* start the rewind operation */
+static void wtrewind (wtinfo_t *t)
+{
+ int rwmode = (t->flags & (TPRO | TPWO));
+
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ /*
+ * Wangtek strictly follows QIC-02 standard:
+ * clearing ONLINE in read/write modes causes rewind.
+ * REWIND command is not allowed in read/write mode
+ * and gives `illegal command' error.
+ */
+ if (t->type==WANGTEK && rwmode) {
+ outb (t->CTLPORT, 0);
+ } else if (! wtcmd (t, QIC_REWIND))
+ return;
+ t->flags |= TPSTART | TPREW;
+ wtclock (t);
+}
+
+/* start the `read marker' operation */
+static int wtreadfm (wtinfo_t *t)
+{
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ if (! wtcmd (t, QIC_READFM)) {
+ wtsense (t, 1, TP_WRP);
+ return (EIO);
+ }
+ t->flags |= TPRMARK | TPRANY;
+ wtclock (t);
+ /* Don't wait for completion here. */
+ return (0);
+}
+
+/* write marker to the tape */
+static int wtwritefm (wtinfo_t *t)
+{
+ tsleep ((caddr_t)wtwritefm, WTPRI, "wtwfm", hz); /* timeout: 1 second */
+ t->flags &= ~(TPRO | TPWO);
+ if (! wtcmd (t, QIC_WRITEFM)) {
+ wtsense (t, 1, 0);
+ return (EIO);
+ }
+ t->flags |= TPWMARK | TPWANY;
+ wtclock (t);
+ return (wtwait (t, 0, "wtwfm"));
+}
+
+/* while controller status & mask == bits continue waiting */
+static int wtpoll (wtinfo_t *t, int mask, int bits)
+{
+ int s, i;
+
+ /* Poll status port, waiting for specified bits. */
+ for (i=0; i<1000; ++i) { /* up to 1 msec */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ DELAY (1);
+ }
+ for (i=0; i<100; ++i) { /* up to 10 msec */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ DELAY (100);
+ }
+ for (;;) { /* forever */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ tsleep ((caddr_t)wtpoll, WTPRI, "wtpoll", 1); /* timeout: 1 tick */
+ }
+}
+
+/* execute QIC command */
+static int wtcmd (wtinfo_t *t, int cmd)
+{
+ int s;
+
+ DEBUG (("wtcmd() cmd=0x%x\n", cmd));
+ s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ if (! (s & t->NOEXCEP)) /* error */
+ return (0);
+
+ outb (t->CMDPORT, cmd); /* output the command */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
+ outb (t->CTLPORT, t->IEN | t->ONLINE); /* reset request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+ return (1);
+}
+
+/* wait for the end of i/o, seeking marker or rewind operation */
+static int wtwait (wtinfo_t *t, int catch, char *msg)
+{
+ int error;
+
+ DEBUG (("wtwait() `%s'\n", msg));
+ while (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
+ if (error = tsleep ((caddr_t)t, WTPRI | catch, msg, 0))
+ return (error);
+ return (0);
+}
+
+/* initialize dma for the i/o operation */
+static void wtdma (wtinfo_t *t)
+{
+ t->flags |= TPACTIVE;
+ wtclock (t);
+
+ if (t->type == ARCHIVE)
+ outb (t->SDMAPORT, 0); /* set dma */
+
+ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize)
+ /* Reading short block. Do it through the internal buffer. */
+ isa_dmastart (t->dmaflags, t->buf, t->bsize, t->chan);
+ else
+ isa_dmastart (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
+}
+
+/* start i/o operation */
+static int wtstart (wtinfo_t *t, unsigned flags, void *vaddr, unsigned len)
+{
+ int s;
+
+ DEBUG (("wtstart()\n"));
+ s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ if (! (s & t->NOEXCEP)) {
+ t->flags |= TPEXCEP; /* error */
+ return (0);
+ }
+ t->flags &= ~TPEXCEP; /* clear exception flag */
+ t->dmavaddr = vaddr;
+ t->dmatotal = len;
+ t->dmacount = 0;
+ t->dmaflags = flags;
+ wtdma (t);
+ return (1);
+}
+
+/* start timer */
+static void wtclock (wtinfo_t *t)
+{
+ if (! (t->flags & TPTIMER)) {
+ t->flags |= TPTIMER;
+ /* Some controllers seem to lose dma interrupts too often.
+ * To make the tape stream we need 1 tick timeout. */
+ timeout (wtimer, (caddr_t)t, (t->flags & TPACTIVE) ? 1 : hz);
+ }
+}
+
+/*
+ * Simulate an interrupt periodically while i/o is going.
+ * This is necessary in case interrupts get eaten due to
+ * multiple devices on a single IRQ line.
+ */
+static void wtimer (caddr_t xt, int dummy)
+{
+ wtinfo_t *t = (wtinfo_t *)xt;
+ int s;
+
+ t->flags &= ~TPTIMER;
+ if (! (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)))
+ return;
+
+ /* If i/o going, simulate interrupt. */
+ s = splbio ();
+ if ((inb (t->STATPORT) & (t->BUSY | t->NOEXCEP)) != (t->BUSY | t->NOEXCEP)) {
+ DEBUG (("wtimer() -- "));
+ wtintr (t->unit);
+ }
+ splx (s);
+
+ /* Restart timer if i/o pending. */
+ if (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
+ wtclock (t);
+}
+
+/* reset the controller */
+static int wtreset (wtinfo_t *t)
+{
+ /* Perform QIC-02 and QIC-36 compatible reset sequence. */
+ /* Thanks to Mikael Hybsch <micke@dynas.se>. */
+ int s, i;
+
+ outb (t->CTLPORT, t->RESET | t->ONLINE); /* send reset */
+ DELAY (30);
+ outb (t->CTLPORT, t->ONLINE); /* turn off reset */
+ DELAY (30);
+
+ /* Read the controller status. */
+ s = inb (t->STATPORT);
+ if (s == 0xff) /* no port at this address? */
+ return (0);
+
+ /* Wait 3 sec for reset to complete. Needed for QIC-36 boards? */
+ for (i=0; i<3000; ++i) {
+ if (! (s & t->BUSY) || ! (s & t->NOEXCEP))
+ break;
+ DELAY (1000);
+ s = inb (t->STATPORT);
+ }
+ return ((s & t->RESETMASK) == t->RESETVAL);
+}
+
+/* get controller status information */
+/* return 0 if user i/o request should receive an i/o error code */
+static int wtsense (wtinfo_t *t, int verb, int ignor)
+{
+ char *msg = 0;
+ int err;
+
+ DEBUG (("wtsense() ignor=0x%x\n", ignor));
+ t->flags &= ~(TPRO | TPWO);
+ if (! wtstatus (t))
+ return (0);
+ if (! (t->error.err & TP_ST0))
+ t->error.err &= ~TP_ST0MASK;
+ if (! (t->error.err & TP_ST1))
+ t->error.err &= ~TP_ST1MASK;
+ t->error.err &= ~ignor; /* ignore certain errors */
+ err = t->error.err & (TP_FIL | TP_BNL | TP_UDA | TP_EOM | TP_WRP |
+ TP_USL | TP_CNI | TP_MBD | TP_NDT | TP_ILL);
+ if (! err)
+ return (1);
+ if (! verb)
+ return (0);
+
+ /* lifted from tdriver.c from Wangtek */
+ if (err & TP_USL) msg = "Drive not online";
+ else if (err & TP_CNI) msg = "No cartridge";
+ else if ((err & TP_WRP) && !(t->flags & TPWP)) {
+ msg = "Tape is write protected";
+ t->flags |= TPWP;
+ }
+ else if (err & TP_FIL) msg = 0 /*"Filemark detected"*/;
+ else if (err & TP_EOM) msg = 0 /*"End of tape"*/;
+ else if (err & TP_BNL) msg = "Block not located";
+ else if (err & TP_UDA) msg = "Unrecoverable data error";
+ else if (err & TP_NDT) msg = "No data detected";
+ else if (err & TP_ILL) msg = "Illegal command";
+ if (msg)
+ printf ("wt%d: %s\n", t->unit, msg);
+ return (0);
+}
+
+/* get controller status information */
+static int wtstatus (wtinfo_t *t)
+{
+ char *p;
+
+ wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ outb (t->CMDPORT, QIC_RDSTAT); /* send `read status' command */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
+ outb (t->CTLPORT, t->ONLINE); /* reset request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+
+ p = (char*) &t->error;
+ while (p < (char*)&t->error + 6) {
+ int s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP);
+ if (! (s & t->NOEXCEP)) /* error */
+ return (0);
+
+ *p++ = inb (t->DATAPORT); /* read status byte */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+ outb (t->CTLPORT, t->ONLINE); /* unset request */
+ }
+ return (1);
+}
+#endif /* NWT */
diff --git a/sys/i386/netboot/Makefile b/sys/i386/netboot/Makefile
index 550cd7be44cd..b7b2b442e557 100644
--- a/sys/i386/netboot/Makefile
+++ b/sys/i386/netboot/Makefile
@@ -5,13 +5,18 @@
# -DSMALL_ROM - Compile for 8K ROMS
# -DROMSIZE - Size of EPROM - Must be set (even for .COM files)
# -DRELOC - Relocation address (usually 0x90000)
+# -DINCLUDE_WD - Include Western Digital/SMC support
+# -DINCLUDE_NE - Include NE1000/NE2000 support
+# -DNE_BASE - Base I/O address for NE1000/NE2000
+# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
#
ROMSIZE=16384
RELOCADDR=0x90000
-CFLAGS=-O2 -DNFS -DROMSIZE=$(ROMSIZE) -DRELOC=$(RELOCADDR)
+CFLAGS= -O2 -DNFS -DINCLUDE_WD -DINCLUDE_NE -DROMSIZE=$(ROMSIZE) \
+ -DRELOC=$(RELOCADDR) -DNE_BASE=0x320 -DWD_DEFAULT_MEM=0xD0000
HDRS=netboot.h
-COBJS=main.o misc.o wd80x3.o bootmenu.o
+COBJS=main.o misc.o ether.o bootmenu.o
SSRCS=start2.S
SOBJS=start2.o
diff --git a/sys/i386/netboot/bootmenu.c b/sys/i386/netboot/bootmenu.c
index c6b7e79d99b4..d77e7efc773e 100644
--- a/sys/i386/netboot/bootmenu.c
+++ b/sys/i386/netboot/bootmenu.c
@@ -86,7 +86,7 @@ CMD_BOOTFILE - set boot filename
cmd_bootfile(p)
char *p;
{
- char *q = bootname;
+ char *q = bootfile = bootname;
if (*p) {
while(*p)
*(q++) = *(p++);
diff --git a/sys/i386/netboot/ether.c b/sys/i386/netboot/ether.c
new file mode 100644
index 000000000000..69448026c4e4
--- /dev/null
+++ b/sys/i386/netboot/ether.c
@@ -0,0 +1,479 @@
+
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+
+**************************************************************************/
+
+#include "netboot.h"
+#include "ether.h"
+
+unsigned short eth_nic_base;
+unsigned short eth_asic_base;
+unsigned char eth_tx_start;
+unsigned char eth_laar;
+unsigned char eth_flags;
+unsigned char eth_vendor;
+unsigned char eth_memsize;
+unsigned char *eth_bmem;
+unsigned char *eth_node_addr;
+
+/**************************************************************************
+The following two variables are used externally
+**************************************************************************/
+char packet[ETH_MAX_PACKET];
+int packetlen;
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+**************************************************************************/
+eth_probe()
+{
+ int i;
+ struct wd_board *brd;
+ char *name;
+ unsigned short chksum;
+ unsigned char c;
+
+ eth_vendor = VENDOR_NONE;
+
+#ifdef INCLUDE_WD
+ /******************************************************************
+ Search for WD/SMC cards
+ ******************************************************************/
+ for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
+ eth_asic_base += 0x20) {
+ chksum = 0;
+ for (i=8; i<16; i++)
+ chksum += inb(i+eth_asic_base);
+ if ((chksum & 0x00FF) == 0x00FF)
+ break;
+ }
+ if (eth_asic_base <= WD_HIGH_BASE) { /* We've found a board */
+ eth_vendor = VENDOR_WD;
+ eth_nic_base = eth_asic_base + WD_NIC_ADDR;
+ c = inb(eth_asic_base+WD_BID); /* Get board id */
+ for (brd = wd_boards; brd->name; brd++)
+ if (brd->id == c) break;
+ if (!brd->name) {
+ printf("\r\nUnknown Ethernet type %x\r\n", c);
+ return(0); /* Unknown type */
+ }
+ eth_flags = brd->flags;
+ eth_memsize = brd->memsize;
+ eth_tx_start = 0;
+ if ((c == TYPE_WD8013EP) &&
+ (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
+ eth_flags = FLAG_16BIT;
+ eth_memsize = MEM_16384;
+ }
+ if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
+ eth_bmem = (char *)(0x80000 |
+ ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
+ } else
+ eth_bmem = (char *)WD_DEFAULT_MEM;
+ outb(eth_asic_base + WD_MSR, 0x80); /* Reset */
+ printf("\r\n%s base 0x%x, memory 0x%X, addr ",
+ brd->name, eth_asic_base, eth_bmem);
+ for (i=0; i<6; i++)
+ printhb((int)(arptable[ARP_CLIENT].node[i] =
+ inb(i+eth_asic_base+WD_LAR)));
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base+WD_MSR, WD_MSR_MENB);
+ outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) |
+ 0x80));
+ outb(eth_asic_base+0x0B,
+ (((unsigned)eth_bmem >> 13) & 0x0F) |
+ (((unsigned)eth_bmem >> 11) & 0x40) |
+ (inb(eth_asic_base+0x0B) & 0x0B));
+ outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) &
+ ~0x80));
+ } else {
+ outb(eth_asic_base+WD_MSR,
+ (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ if (eth_flags & FLAG_790) {
+ eth_laar = inb(eth_asic_base + WD_LAAR);
+ outb(eth_asic_base + WD_LAAR, WD_LAAR_M16EN);
+ inb(0x84);
+ } else {
+ outb(eth_asic_base + WD_LAAR, (eth_laar =
+ WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
+ }
+ }
+ printf("\r\n");
+
+ }
+#endif
+#ifdef INCLUDE_NE
+ /******************************************************************
+ Search for NE1000/2000 if no WD/SMC cards
+ ******************************************************************/
+ if (eth_vendor != VENDOR_WD) {
+ char romdata[16], testbuf[32];
+ char test[] = "NE1000/2000 memory";
+ eth_bmem = (char *)0; /* No shared memory */
+ eth_asic_base = NE_BASE + NE_ASIC_OFFSET;
+ eth_nic_base = NE_BASE;
+ eth_vendor = VENDOR_NOVELL;
+ eth_flags = FLAG_PIO;
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+ c = inb(eth_asic_base + NE_RESET);
+ outb(eth_asic_base + NE_RESET, c);
+ inb(0x84);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_STP |
+ D8390_COMMAND_RD2);
+ outb(eth_nic_base + D8390_P0_RCR, D8390_RCR_MON);
+ outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_FT1 | D8390_DCR_LS);
+ outb(eth_nic_base + D8390_P0_PSTART, MEM_8192);
+ outb(eth_nic_base + D8390_P0_PSTOP, MEM_16384);
+ eth_pio_write(test, 8192, sizeof(test));
+ eth_pio_read(8192, testbuf, sizeof(test));
+ if (!bcompare(test, testbuf, sizeof(test))) {
+ eth_flags |= FLAG_16BIT;
+ eth_memsize = MEM_32768;
+ eth_tx_start = 64;
+ outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_WTS |
+ D8390_DCR_FT1 | D8390_DCR_LS);
+ outb(eth_nic_base + D8390_P0_PSTART, MEM_16384);
+ outb(eth_nic_base + D8390_P0_PSTOP, MEM_32768);
+ eth_pio_write(test, 16384, sizeof(test));
+ eth_pio_read(16384, testbuf, sizeof(test));
+ if (!bcompare(testbuf, test, sizeof(test))) return(0);
+ }
+ eth_pio_read(0, romdata, 16);
+ printf("\r\nNE1000/NE2000 base 0x%x, addr ", eth_nic_base);
+ for (i=0; i<6; i++)
+ printhb((int)(arptable[ARP_CLIENT].node[i] = romdata[i
+ + ((eth_flags & FLAG_16BIT) ? i : 0)]));
+ printf("\r\n");
+ }
+#endif
+ if (eth_vendor == VENDOR_NONE) return(0);
+
+ eth_node_addr = arptable[ARP_CLIENT].node;
+ eth_reset();
+ return(eth_vendor);
+}
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+**************************************************************************/
+eth_reset()
+{
+ int i;
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND,
+ D8390_COMMAND_PS0 | D8390_COMMAND_STP);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND,
+ D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP);
+ if (eth_flags & FLAG_16BIT)
+ outb(eth_nic_base+D8390_P0_DCR, 0x49);
+ else
+ outb(eth_nic_base+D8390_P0_DCR, 0x48);
+ outb(eth_nic_base+D8390_P0_RBCR0, 0);
+ outb(eth_nic_base+D8390_P0_RBCR1, 0);
+ outb(eth_nic_base+D8390_P0_RCR, 4); /* allow broadcast frames */
+ outb(eth_nic_base+D8390_P0_TCR, 2);
+ outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start);
+ outb(eth_nic_base+D8390_P0_PSTART, eth_tx_start + D8390_TXBUF_SIZE);
+ if (eth_flags & FLAG_790) outb(eth_nic_base + 0x09, 0);
+ outb(eth_nic_base+D8390_P0_PSTOP, eth_memsize);
+ outb(eth_nic_base+D8390_P0_BOUND, eth_tx_start + D8390_TXBUF_SIZE);
+ outb(eth_nic_base+D8390_P0_ISR, 0xFF);
+ outb(eth_nic_base+D8390_P0_IMR, 0);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
+ D8390_COMMAND_STP);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP);
+ for (i=0; i<6; i++)
+ outb(eth_nic_base+D8390_P1_PAR0+i, eth_node_addr[i]);
+ for (i=0; i<6; i++)
+ outb(eth_nic_base+D8390_P1_MAR0+i, 0xFF);
+ outb(eth_nic_base+D8390_P1_CURR, eth_tx_start + D8390_TXBUF_SIZE+1);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ outb(eth_nic_base+D8390_P0_ISR, 0xFF);
+ outb(eth_nic_base+D8390_P0_TCR, 0);
+ return(1);
+}
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+**************************************************************************/
+eth_transmit(d,t,s,p)
+ char *d; /* Destination */
+ unsigned short t; /* Type */
+ unsigned short s; /* size */
+ char *p; /* Packet */
+{
+ unsigned char c;
+#ifdef INCLUDE_WD
+ if (eth_vendor == VENDOR_WD) { /* Memory interface */
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, WD_MSR_MENB);
+ inb(0x84);
+ }
+ inb(0x84);
+ bcopy(d, eth_bmem, 6); /* dst */
+ bcopy(eth_node_addr, eth_bmem+6, ETHER_ADDR_SIZE); /* src */
+ *(eth_bmem+12) = t>>8; /* type */
+ *(eth_bmem+13) = t;
+ bcopy(p, eth_bmem+14, s);
+ s += 14;
+ while (s < ETH_MIN_PACKET) *(eth_bmem+(s++)) = 0;
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, 0);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar & ~WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ }
+#endif
+#ifdef INCLUDE_NE
+ if (eth_vendor == VENDOR_NOVELL) { /* Programmed I/O */
+ unsigned short type;
+ type = (t >> 8) | (t << 8);
+ eth_pio_write(d, eth_tx_start<<8, 6);
+ eth_pio_write(eth_node_addr, (eth_tx_start<<8)+6, 6);
+ eth_pio_write(&type, (eth_tx_start<<8)+12, 2);
+ eth_pio_write(p, (eth_tx_start<<8)+14, s);
+ s += 14;
+ if (s < ETH_MIN_PACKET) s = ETH_MIN_PACKET;
+ }
+#endif
+ twiddle();
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start);
+ outb(eth_nic_base+D8390_P0_TBCR0, s);
+ outb(eth_nic_base+D8390_P0_TBCR1, s>>8);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_TXP | D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ return(0);
+}
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+**************************************************************************/
+eth_poll()
+{
+ int ret = 0;
+ unsigned short type = 0;
+ unsigned char bound,curr,rstat;
+ unsigned short len;
+ unsigned short pktoff;
+ unsigned char *p;
+ struct ringbuffer pkthdr;
+ rstat = inb(eth_nic_base+D8390_P0_RSR);
+ if (rstat & D8390_RSTAT_OVER) {
+ eth_reset();
+ return(0);
+ }
+ if (!(rstat & D8390_RSTAT_PRX)) return(0);
+ bound = inb(eth_nic_base+D8390_P0_BOUND)+1;
+ if (bound == eth_memsize) bound = eth_tx_start + D8390_TXBUF_SIZE;
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1);
+ curr = inb(eth_nic_base+D8390_P1_CURR);
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0);
+ if (curr == eth_memsize) curr=eth_tx_start + D8390_TXBUF_SIZE;
+ if (curr == bound) return(0);
+ if (eth_vendor == VENDOR_WD) {
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, WD_MSR_MENB);
+ inb(0x84);
+ }
+ inb(0x84);
+ }
+ pktoff = (bound << 8);
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, &pkthdr, 4);
+ else
+ bcopy(eth_bmem + pktoff, &pkthdr, 4);
+ len = pkthdr.len - 4; /* sub CRC */
+ pktoff += 4;
+ if (len > 1514) len = 1514;
+ bound = pkthdr.bound; /* New bound ptr */
+ if ( (pkthdr.status & D8390_RSTAT_PRX) && (len > 14) && (len < 1518)) {
+ p = packet;
+ packetlen = len;
+ len = (eth_memsize << 8) - pktoff;
+ if (packetlen > len) { /* We have a wrap-around */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, len);
+ else
+ bcopy(eth_bmem + pktoff, p, len);
+ pktoff = (eth_tx_start + D8390_TXBUF_SIZE) << 8;
+ p += len;
+ packetlen -= len;
+ }
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, packetlen);
+ else
+ bcopy(eth_bmem + pktoff, p, packetlen);
+
+ type = (packet[12]<<8) | packet[13];
+ ret = 1;
+ }
+ if (eth_vendor == VENDOR_WD) {
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, 0);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar &
+ ~WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ inb(0x84);
+ }
+ if (bound == (eth_tx_start + D8390_TXBUF_SIZE))
+ bound = eth_memsize;
+ outb(eth_nic_base+D8390_P0_BOUND, bound-1);
+ if (ret && (type == ARP)) {
+ struct arprequest *arpreq;
+ unsigned long reqip;
+ arpreq = (struct arprequest *)&packet[ETHER_HDR_SIZE];
+ convert_ipaddr(&reqip, arpreq->tipaddr);
+ if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
+ (reqip == arptable[ARP_CLIENT].ipaddr)) {
+ arpreq->opcode = htons(ARP_REPLY);
+ bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
+ bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
+ bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
+ convert_ipaddr(arpreq->sipaddr, &reqip);
+ eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
+ arpreq);
+ return(0);
+ }
+ }
+ return(ret);
+}
+
+#ifdef INCLUDE_NE
+/**************************************************************************
+NE1000/NE2000 Support Routines
+**************************************************************************/
+static inline unsigned short inw(unsigned short a)
+{
+ unsigned short d;
+ asm volatile( "inw %1, %0" : "=a" (d) : "d" (a));
+ return d;
+}
+
+static inline void outw(unsigned short a, unsigned short d)
+{
+ asm volatile( "outw %0, %1" : : "a" (d), "d" (a));
+}
+
+/**************************************************************************
+ETH_PIO_READ - Read a frame via Programmed I/O
+**************************************************************************/
+eth_pio_read(src, dst, cnt, init)
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short cnt;
+ int init;
+{
+ if (cnt & 1) cnt++;
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ outb(eth_nic_base + D8390_P0_RBCR0, cnt);
+ outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
+ outb(eth_nic_base + D8390_P0_RSAR0, src);
+ outb(eth_nic_base + D8390_P0_RSAR1, src>>8);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD0 |
+ D8390_COMMAND_STA);
+ if (eth_flags & FLAG_16BIT) {
+ while (cnt) {
+ *((unsigned short *)dst) = inw(eth_asic_base + NE_DATA);
+ dst += 2;
+ cnt -= 2;
+ }
+ }
+ else {
+ while (cnt--)
+ *(dst++) = inb(eth_asic_base + NE_DATA);
+ }
+}
+
+/**************************************************************************
+ETH_PIO_WRITE - Write a frame via Programmed I/O
+**************************************************************************/
+eth_pio_write(src, dst, cnt, init)
+ unsigned char *src;
+ unsigned short dst;
+ unsigned short cnt;
+ int init;
+{
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ outb(eth_nic_base + D8390_P0_ISR, D8390_ISR_RDC);
+ outb(eth_nic_base + D8390_P0_RBCR0, cnt);
+ outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
+ outb(eth_nic_base + D8390_P0_RSAR0, dst);
+ outb(eth_nic_base + D8390_P0_RSAR1, dst>>8);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD1 |
+ D8390_COMMAND_STA);
+ if (eth_flags & FLAG_16BIT) {
+ if (cnt & 1) cnt++; /* Round up */
+ while (cnt) {
+ outw(eth_asic_base + NE_DATA, *((unsigned short *)src));
+ src += 2;
+ cnt -= 2;
+ }
+ }
+ else {
+ while (cnt--)
+ outb(eth_asic_base + NE_DATA, *(src++));
+ }
+ while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
+ != D8390_ISR_RDC);
+}
+#else
+/**************************************************************************
+ETH_PIO_READ - Dummy routine when NE2000 not compiled in
+**************************************************************************/
+eth_pio_read() {}
+#endif
diff --git a/sys/i386/netboot/ether.h b/sys/i386/netboot/ether.h
new file mode 100644
index 000000000000..586a35cb963b
--- /dev/null
+++ b/sys/i386/netboot/ether.h
@@ -0,0 +1,178 @@
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: Jun/94
+
+**************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+#define ETH_MIN_PACKET 64
+#define ETH_MAX_PACKET 1518
+
+#define VENDOR_NONE 0
+#define VENDOR_WD 1
+#define VENDOR_NOVELL 2
+
+#define FLAG_PIO 0x01
+#define FLAG_16BIT 0x02
+#define FLAG_790 0x04
+
+#define MEM_8192 32
+#define MEM_16384 64
+#define MEM_32768 128
+
+/**************************************************************************
+Western Digital/SMC Board Definitions
+**************************************************************************/
+#define WD_LOW_BASE 0x200
+#define WD_HIGH_BASE 0x3e0
+#ifndef WD_DEFAULT_MEM
+#define WD_DEFAULT_MEM 0xD0000
+#endif
+#define WD_NIC_ADDR 0x10
+
+/**************************************************************************
+Western Digital/SMC ASIC Addresses
+**************************************************************************/
+#define WD_MSR 0x00
+#define WD_ICR 0x01
+#define WD_IAR 0x02
+#define WD_BIO 0x03
+#define WD_IRR 0x04
+#define WD_LAAR 0x05
+#define WD_IJR 0x06
+#define WD_GP2 0x07
+#define WD_LAR 0x08
+#define WD_BID 0x0E
+
+#define WD_ICR_16BIT 0x01
+
+#define WD_MSR_MENB 0x40
+
+#define WD_LAAR_L16EN 0x40
+#define WD_LAAR_M16EN 0x80
+
+#define WD_SOFTCONFIG 0x20
+
+/**************************************************************************
+Western Digital/SMC Board Types
+**************************************************************************/
+#define TYPE_WD8003S 0x02
+#define TYPE_WD8003E 0x03
+#define TYPE_WD8013EBT 0x05
+#define TYPE_WD8003W 0x24
+#define TYPE_WD8003EB 0x25
+#define TYPE_WD8013W 0x26
+#define TYPE_WD8013EP 0x27
+#define TYPE_WD8013WC 0x28
+#define TYPE_WD8013EPC 0x29
+#define TYPE_SMC8216T 0x2a
+#define TYPE_SMC8216C 0x2b
+#define TYPE_SMC8013EBP 0x2c
+
+#ifdef INCLUDE_WD
+struct wd_board {
+ char *name;
+ char id;
+ char flags;
+ char memsize;
+} wd_boards[] = {
+ {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
+ {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
+ {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
+ {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
+ {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
+ {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
+ {"WD8003EP/WD8013EP",
+ TYPE_WD8013EP, 0, MEM_8192},
+ {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
+ {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
+ {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
+ {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
+ {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
+ {NULL, 0, 0}
+};
+#endif
+
+/**************************************************************************
+NE1000/2000 definitions
+**************************************************************************/
+#ifndef NE_BASE
+#define NE_BASE 0x320
+#endif
+#define NE_ASIC_OFFSET 0x10
+#define NE_RESET 0x0F /* Used to reset card */
+#define NE_DATA 0x00 /* Used to read/write NIC mem */
+
+/**************************************************************************
+8390 Register Definitions
+**************************************************************************/
+#define D8390_P0_COMMAND 0x00
+#define D8390_P0_PSTART 0x01
+#define D8390_P0_PSTOP 0x02
+#define D8390_P0_BOUND 0x03
+#define D8390_P0_TSR 0x04
+#define D8390_P0_TPSR 0x04
+#define D8390_P0_TBCR0 0x05
+#define D8390_P0_TBCR1 0x06
+#define D8390_P0_ISR 0x07
+#define D8390_P0_RSAR0 0x08
+#define D8390_P0_RSAR1 0x09
+#define D8390_P0_RBCR0 0x0A
+#define D8390_P0_RBCR1 0x0B
+#define D8390_P0_RSR 0x0C
+#define D8390_P0_RCR 0x0C
+#define D8390_P0_TCR 0x0D
+#define D8390_P0_DCR 0x0E
+#define D8390_P0_IMR 0x0F
+#define D8390_P1_COMMAND 0x00
+#define D8390_P1_PAR0 0x01
+#define D8390_P1_PAR1 0x02
+#define D8390_P1_PAR2 0x03
+#define D8390_P1_PAR3 0x04
+#define D8390_P1_PAR4 0x05
+#define D8390_P1_PAR5 0x06
+#define D8390_P1_CURR 0x07
+#define D8390_P1_MAR0 0x08
+
+#define D8390_COMMAND_PS0 0x0 /* Page 0 select */
+#define D8390_COMMAND_PS1 0x40 /* Page 1 select */
+#define D8390_COMMAND_PS2 0x80 /* Page 2 select */
+#define D8390_COMMAND_RD2 0x20 /* Remote DMA control */
+#define D8390_COMMAND_RD1 0x10
+#define D8390_COMMAND_RD0 0x08
+#define D8390_COMMAND_TXP 0x04 /* transmit packet */
+#define D8390_COMMAND_STA 0x02 /* start */
+#define D8390_COMMAND_STP 0x01 /* stop */
+
+#define D8390_RCR_MON 0x20 /* monitor mode */
+
+#define D8390_DCR_FT1 0x40
+#define D8390_DCR_LS 0x08 /* Loopback select */
+#define D8390_DCR_WTS 0x01 /* Word transfer select */
+
+#define D8390_ISR_PRX 0x01 /* successful recv */
+#define D8390_ISR_PTX 0x02 /* successful xmit */
+#define D8390_ISR_RXE 0x04 /* receive error */
+#define D8390_ISR_TXE 0x08 /* transmit error */
+#define D8390_ISR_OVW 0x10 /* Overflow */
+#define D8390_ISR_CNT 0x20 /* Counter overflow */
+#define D8390_ISR_RDC 0x40 /* Remote DMA complete */
+#define D8390_ISR_RST 0x80 /* reset */
+
+#define D8390_RSTAT_PRX 0x01 /* successful recv */
+#define D8390_RSTAT_CRC 0x02 /* CRC error */
+#define D8390_RSTAT_FAE 0x04 /* Frame alignment error */
+#define D8390_RSTAT_OVER 0x08 /* overflow */
+
+#define D8390_TXBUF_SIZE 6
+#define D8390_RXBUF_END 32
+
+struct ringbuffer {
+ unsigned char status;
+ unsigned char bound;
+ unsigned short len;
+};
diff --git a/sys/i386/netboot/wd80x3.c b/sys/i386/netboot/wd80x3.c
deleted file mode 100644
index a68dc44c1f18..000000000000
--- a/sys/i386/netboot/wd80x3.c
+++ /dev/null
@@ -1,240 +0,0 @@
-
-/**************************************************************************
-NETBOOT - BOOTP/TFTP Bootstrap Program
-
-Author: Martin Renters
- Date: Dec/93
-
-**************************************************************************/
-
-#include "netboot.h"
-
-unsigned short we_base;
-unsigned char *we_bmem;
-
-#define WE_LOW_BASE 0x200
-#define WE_HIGH_BASE 0x3e0
-#define WE_DEFAULT_MEM 0xD0000
-#define WE_MIN_PACKET 64
-#define WE_TXBUF_SIZE 6
-#define WE_RXBUF_END 32
-
-#define WE_MSR 0x00
-#define WE_ICR 0x01
-#define WE_IAR 0x02
-#define WE_BIO 0x03
-#define WE_IRR 0x04
-#define WE_LAAR 0x05
-#define WE_IJR 0x06
-#define WE_GP2 0x07
-#define WE_LAR 0x08
-#define WE_BID 0x0E
-#define WE_P0_COMMAND 0x10
-#define WE_P0_PSTART 0x11
-#define WE_P0_PSTOP 0x12
-#define WE_P0_BOUND 0x13
-#define WE_P0_TSR 0x14
-#define WE_P0_TPSR 0x14
-#define WE_P0_TBCR0 0x15
-#define WE_P0_TBCR1 0x16
-#define WE_P0_ISR 0x17
-#define WE_P0_RBCR0 0x1A
-#define WE_P0_RBCR1 0x1B
-#define WE_P0_RSR 0x1C
-#define WE_P0_RCR 0x1C
-#define WE_P0_TCR 0x1D
-#define WE_P0_DCR 0x1E
-#define WE_P0_IMR 0x1F
-#define WE_P1_COMMAND 0x10
-#define WE_P1_PAR0 0x11
-#define WE_P1_PAR1 0x12
-#define WE_P1_PAR2 0x13
-#define WE_P1_PAR3 0x14
-#define WE_P1_PAR4 0x15
-#define WE_P1_PAR5 0x16
-#define WE_P1_CURR 0x17
-#define WE_P1_MAR0 0x18
-
-#define WE_COMMAND_PS0 0x0 /* Page 0 select */
-#define WE_COMMAND_PS1 0x40 /* Page 1 select */
-#define WE_COMMAND_PS2 0x80 /* Page 2 select */
-#define WE_COMMAND_TXP 0x04 /* transmit packet */
-#define WE_COMMAND_STA 0x02 /* start */
-#define WE_COMMAND_STP 0x01 /* stop */
-
-#define WE_ISR_PRX 0x01 /* successful recv */
-#define WE_ISR_PTX 0x02 /* successful xmit */
-#define WE_ISR_RXE 0x04 /* receive error */
-#define WE_ISR_TXE 0x08 /* transmit error */
-#define WE_ISR_OVW 0x10 /* Overflow */
-#define WE_ISR_CNT 0x20 /* Counter overflow */
-#define WE_ISR_RST 0x80 /* reset */
-
-#define WE_RSTAT_PRX 0x01 /* successful recv */
-#define WE_RSTAT_CRC 0x02 /* CRC error */
-#define WE_RSTAT_FAE 0x04 /* Frame alignment error */
-#define WE_RSTAT_OVER 0x08 /* overflow */
-
-char packet[1600];
-int packetlen;
-int bit16;
-
-/**************************************************************************
-ETH_PROBE - Look for an adapter
-**************************************************************************/
-eth_probe()
-{
- unsigned short base;
- unsigned short chksum;
- unsigned char c;
- int i;
- for (we_base = WE_LOW_BASE; we_base <= WE_HIGH_BASE; we_base += 0x20) {
- chksum = 0;
- for (i=8; i<16; i++)
- chksum += inb(i+we_base);
- if ((chksum & 0x00FF) == 0x00FF)
- break;
- }
- if (we_base > WE_HIGH_BASE) return(0); /* No adapter found */
-
- for (i = 1; i<6; i++) /* Look for aliased registers */
- if (inb(we_base+i) != inb(we_base+i+WE_LAR)) break;
- if (i == 6) { /* Aliased */
- we_bmem = (char *)WE_DEFAULT_MEM;
- bit16 = 0;
- } else {
- we_bmem = (char *)(0x80000 | ((inb(we_base+WE_MSR) & 0x3F) << 13));
- bit16 = 1;
- }
- outb(we_base+WE_MSR, 0x80); /* Reset */
- printf("\r\nSMC80x3 base 0x%x, memory 0x%X, etheraddr ",we_base, we_bmem);
- for (i=0; i<6; i++)
- printhb((int)(arptable[ARP_CLIENT].node[i] = inb(i+we_base+WE_LAR)));
- printf("\r\n");
- outb(we_base+WE_MSR,(((unsigned)we_bmem >> 13) & 0x3F) | 0x40);
- iskey(); /* Kill some time while device resets */
- eth_reset();
-}
-
-/**************************************************************************
-ETH_RESET - Reset adapter
-**************************************************************************/
-eth_reset()
-{
- int i;
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS0 | WE_COMMAND_STP);
- outb(we_base+WE_P0_DCR, 0x48);
- outb(we_base+WE_P0_RBCR0, 0);
- outb(we_base+WE_P0_RBCR1, 0);
- outb(we_base+WE_P0_RCR, 4); /* allow broadcast frames */
- outb(we_base+WE_P0_TCR, 0);
- outb(we_base+WE_P0_TPSR, 0);
- outb(we_base+WE_P0_PSTART, WE_TXBUF_SIZE);
- outb(we_base+WE_P0_PSTOP, WE_RXBUF_END); /* All cards have 8K */
- outb(we_base+WE_P0_BOUND, WE_TXBUF_SIZE);
- outb(we_base+WE_P0_IMR, 0);
- outb(we_base+WE_P0_ISR, 0xFF);
- if (bit16) outb(we_base+WE_LAAR, 1); /* Turn off 16bit mode */
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS1);
- for (i=0; i<6; i++)
- outb(we_base+WE_P1_PAR0+i, inb(we_base+WE_LAR+i));
- for (i=0; i<6; i++)
- outb(we_base+WE_P1_MAR0+i, 0xFF);
- outb(we_base+WE_P1_CURR, WE_TXBUF_SIZE+1);
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS0 | WE_COMMAND_STA);
- return(1);
-}
-
-/**************************************************************************
-ETH_TRANSMIT - Transmit a frame
-**************************************************************************/
-eth_transmit(d,t,s,p)
- char *d; /* Destination */
- unsigned short t; /* Type */
- unsigned short s; /* size */
- char *p; /* Packet */
-{
- unsigned char c;
- bcopy(d, we_bmem, 6); /* Copy destination */
- bcopy(arptable[ARP_CLIENT].node, we_bmem+6, ETHER_ADDR_SIZE); /* My ether addr */
- *(we_bmem+12) = t>>8; /* Type field */
- *(we_bmem+13) = t;
- bcopy(p, we_bmem+14, s);
- s += 14;
- while (s < WE_MIN_PACKET) *(we_bmem+(s++)) = 0;
- twiddle();
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS0);
- outb(we_base+WE_P0_TPSR, 0);
- outb(we_base+WE_P0_TBCR0, s);
- outb(we_base+WE_P0_TBCR1, s>>8);
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS0 | WE_COMMAND_TXP);
- return(0);
-}
-
-/**************************************************************************
-ETH_POLL - Wait for a frame
-**************************************************************************/
-eth_poll()
-{
- int ret = 0;
- unsigned short type = 0;
- unsigned char bound,curr,rstat;
- unsigned short len;
- unsigned char *pkt, *p;
- rstat = inb(we_base+WE_P0_RSR);
- if (rstat & WE_RSTAT_OVER) {
- eth_reset();
- return(0);
- }
- if (!(rstat & WE_RSTAT_PRX)) return(0);
- bound = inb(we_base+WE_P0_BOUND)+1;
- if (bound == WE_RXBUF_END) bound = WE_TXBUF_SIZE;
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS1);
- curr = inb(we_base+WE_P1_CURR);
- outb(we_base+WE_P0_COMMAND, WE_COMMAND_PS0);
- if (curr == WE_RXBUF_END) curr=WE_TXBUF_SIZE;
- if (curr == bound) return(0);
- pkt = we_bmem + (bound << 8);
- len = *((unsigned short *)(pkt+2)) - 4; /* sub CRC */
- if (len > 1514) len = 1514;
-#ifdef DEBUG
-printf("[R%dS%dC%dB%dN%d]",len, rstat, curr,bound,*(pkt+1));
-#endif
- bound = *(pkt+1); /* New bound ptr */
- p = packet;
- if ( (*pkt & WE_RSTAT_PRX) && (len > 14) && (len < 1518)) {
- pkt += 4;
- packetlen = len;
- while (len) {
- while (len && (pkt < (we_bmem + 8192))) {
- *(p++) = *(pkt++);
- len--;
- }
- pkt = we_bmem + (WE_TXBUF_SIZE << 8);
- }
- type = (packet[12]<<8) | packet[13];
- ret = 1;
- }
- if (bound == WE_TXBUF_SIZE)
- bound = WE_RXBUF_END;
- outb(we_base+WE_P0_BOUND, bound-1);
- if (ret && (type == ARP)) {
- struct arprequest *arpreq;
- unsigned long reqip;
- arpreq = (struct arprequest *)&packet[ETHER_HDR_SIZE];
- convert_ipaddr(&reqip, arpreq->tipaddr);
- if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
- (reqip == arptable[ARP_CLIENT].ipaddr)) {
- arpreq->opcode = htons(ARP_REPLY);
- bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
- bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
- bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
- convert_ipaddr(arpreq->sipaddr, &reqip);
- eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
- arpreq);
- return(0);
- }
- }
- return(ret);
-}
-
diff --git a/sys/i386/pci/ncr.c b/sys/i386/pci/ncr.c
new file mode 100644
index 000000000000..0c094afcf609
--- /dev/null
+++ b/sys/i386/pci/ncr.c
@@ -0,0 +1,5507 @@
+/**************************************************************************
+**
+** $Id: ncr.c,v 2.0.0.3 94/07/24 09:02:42 wolf Exp $
+**
+** Device driver for the NCR 53C810 PCI-SCSI-Controller.
+**
+** 386bsd / FreeBSD
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: ncr.c,v $
+** Revision 2.0.0.3 94/07/24 09:02:42 wolf
+** sstat0 used to calculate residue in int_ma.
+** log messages extended.
+**
+** Revision 2.0.0.2 94/07/22 19:04:26 wolf
+** ncr_int_ma: byte count corrected with dfifo.
+** script: dispatch and no_data changed.
+**
+** Revision 2.0.0.1 94/07/19 21:42:02 wolf
+** New debug value: DEBUG_FREEZE
+** M_REJECT log entry includes rejected message.
+** Phase change in command/status/msg phase logged.
+** Timeout exception handler locked.
+**
+** Revision 2.0 94/07/10 15:53:22 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:16 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#ifdef KERNEL
+#include <ncr.h>
+#else /* KERNEL */
+#define NNCR 1
+#endif /* KERNEL */
+
+#if NNCR > 0
+
+#define NCR_VERSION (2)
+
+
+/*==========================================================
+**
+** Configuration and Debugging
+**
+** May be overwritten in <i386/conf/XXXXX>
+**
+**==========================================================
+*/
+
+/*
+** Enable/Disable debug messages.
+** Can be changed at runtime too.
+*/
+
+#ifndef SCSI_NCR_DEBUG
+#define SCSI_NCR_DEBUG (0)
+#endif /* SCSI_NCR_DEBUG */
+
+/*
+** SCSI address of this device.
+** The boot routines should have set it.
+** If not, use this.
+*/
+
+#ifndef SCSI_NCR_MYADDR
+#define SCSI_NCR_MYADDR (7)
+#endif /* SCSI_NCR_MYADDR */
+
+/*
+** The maximal synchronous frequency in kHz.
+** (0=asynchronous)
+*/
+
+#ifndef SCSI_NCR_MAX_SYNC
+#define SCSI_NCR_MAX_SYNC (0)
+#endif /* SCSI_NCR_MAX_SYNC */
+
+/*
+** The maximum number of tags per logic unit.
+** Used only for disk devices that support tags.
+*/
+
+#ifndef SCSI_NCR_MAX_TAGS
+#define SCSI_NCR_MAX_TAGS (8)
+#endif /* SCSI_NCR_MAX_TAGS */
+
+/*==========================================================
+**
+** Configuration and Debugging
+**
+**==========================================================
+*/
+
+/*
+** Number of targets supported by the driver.
+** n permits target numbers 0..n-1.
+** Default is 7, meaning targets #0..#6.
+** #7 .. is myself.
+*/
+
+#define MAX_TARGET (7)
+
+/*
+** Number of logic units supported by the driver.
+** n enables logic unit numbers 0..n-1.
+** The common SCSI devices require only
+** one lun, so take 1 as the default.
+*/
+
+#define MAX_LUN (1)
+
+/*
+** The maximum number of jobs scheduled for starting.
+** There should be one slot per target, and one slot
+** for each tag of each target.
+*/
+
+#define MAX_START (20)
+
+/*
+** The maximum number of segments a transfer is split into.
+*/
+
+#define MAX_SCATTER (33)
+
+/*
+** The maximum transfer length (should be >= 64k).
+** MUST NOT be greater than (MAX_SCATTER-1) * NBPG.
+*/
+
+#define MAX_SIZE ((MAX_SCATTER-1) * NBPG)
+
+/*
+** Enable some processor/os dependent functions.
+*/
+
+#define DIRTY 1
+
+/*
+** Write disk status information to dkstat ?
+*/
+
+#define DK 1
+
+/*==========================================================
+**
+** Include files
+**
+**==========================================================
+*/
+
+#ifdef KERNEL
+#include <types.h>
+#include <param.h>
+#include <time.h>
+#include <systm.h>
+#include <malloc.h>
+#include <buf.h>
+#include <kernel.h>
+#include <vm/vm.h>
+
+#ifdef DK
+#include <dkstat.h>
+#endif /* DK */
+
+#else /* KERNEL */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#endif /* KERNEL */
+
+#include <i386/pci/ncr_reg.h>
+#include <i386/pci/pci.h>
+#include <i386/pci/pci_device.h>
+
+#ifdef __NetBSD__
+#include <sys/device.h>
+#include <i386/isa/isavar.h>
+#endif
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+
+/*==========================================================
+**
+** Debugging tags
+**
+**==========================================================
+*/
+
+#ifdef SCSI_NCR_DEBUG
+
+#define DEBUG_ALLOC (0x0001)
+#define DEBUG_PHASE (0x0002)
+#define DEBUG_POLL (0x0004)
+#define DEBUG_QUEUE (0x0008)
+#define DEBUG_RESULT (0x0010)
+#define DEBUG_SCATTER (0x0020)
+#define DEBUG_SCRIPT (0x0040)
+#define DEBUG_TINY (0x0080)
+#define DEBUG_TIMING (0x0100)
+#define DEBUG_SDTR (0x0200)
+#define DEBUG_TAGS (0x0400)
+#define DEBUG_FREEZE (0x0800)
+#define DEBUG_NODUMP (0x1000)
+
+int ncr_debug = SCSI_NCR_DEBUG;
+
+#else /* SCSI_NCR_DEBUG */
+int ncr_debug = 0;
+#endif /* SCSI_NCR_DEBUG */
+
+
+/*==========================================================
+**
+** assert ()
+**
+**==========================================================
+**
+** modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
+
+#define assert(expression) { \
+ if (!(expression)) { \
+ (void)printf(\
+ "assertion \"%s\" failed: file \"%s\", line %d\n", \
+ #expression, \
+ __FILE__, __LINE__); \
+ } \
+}
+
+/*==========================================================
+**
+** Access to the controller chip.
+**
+**==========================================================
+*/
+
+#define INB(r) (np->reg->r)
+#define INW(r) (np->reg->r)
+#define INL(r) (np->reg->r)
+
+#define OUTB(r, val) np->reg->r = val
+#define OUTW(r, val) np->reg->r = val
+#define OUTL(r, val) np->reg->r = val
+
+/*==========================================================
+**
+** Command control block states.
+**
+**==========================================================
+*/
+
+#define HS_IDLE (0)
+#define HS_BUSY (1)
+#define HS_NEGOTIATE (2) /* sync. data transfer */
+#define HS_DISCONNECT (3) /* Disconnected by target */
+
+#define HS_COMPLETE (4)
+#define HS_SEL_TIMEOUT (5) /* Selection timeout */
+#define HS_RESET (6) /* SCSI reset */
+#define HS_ABORTED (7) /* Transfer aborted */
+#define HS_TIMEOUT (8) /* Software timeout */
+#define HS_FAIL (9) /* SCSI or PCI bus errors */
+#define HS_UNEXPECTED (10) /* Unexpected disconnect */
+
+/*==========================================================
+**
+** Misc.
+**
+**==========================================================
+*/
+
+#define ILLEGAL_ADDR (0xefffffff)
+#define CCB_MAGIC (0xf2691ad2)
+
+/*==========================================================
+**
+** Capability bits in Inquire response byte #7.
+**
+**==========================================================
+*/
+
+#define INQ7_SYNC (0x10)
+#define INQ7_QUEUE (0x02)
+
+/*==========================================================
+**
+** OS dependencies.
+**
+**==========================================================
+*/
+
+#ifndef __FreeBSD__
+#ifndef __NetBSD__
+ #define ANCIENT
+#endif /*__NetBSD__*/
+#endif /*__FreeBSD__*/
+
+#ifdef ANCIENT
+ #define LUN lu
+ #define TARGET targ
+ #define INT32 int
+ #define U_INT32 long
+ #define TIMEOUT
+#else /* ANCIENT */
+ #define LUN sc_link->lun
+ #define TARGET sc_link->target
+#ifdef __NetBSD__
+ #define INT32 int
+ #define U_INT32 u_int
+ #define TIMEOUT (void*)
+#else /*__NetBSD__*/
+ #define INT32 int32
+ #define U_INT32 u_int32
+ #define TIMEOUT (timeout_func_t)
+#endif /*__NetBSD__*/
+#endif /* ANCIENT */
+
+/*==========================================================
+**
+** Declaration of structs.
+**
+**==========================================================
+*/
+
+struct tcb;
+struct lcb;
+struct ccb;
+struct ncb;
+struct script;
+
+typedef struct ncb * ncb_p;
+typedef struct tcb * tcb_p;
+typedef struct lcb * lcb_p;
+typedef struct ccb * ccb_p;
+
+struct link {
+ u_long l_cmd;
+ u_long l_paddr;
+};
+
+struct usrcmd {
+ u_long target;
+ u_long lun;
+ u_long data;
+ u_long cmd;
+};
+
+#define UC_SETSYNC 10
+#define UC_SETTAGS 11
+#define UC_SETDEBUG 12
+#define UC_SETORDER 13
+
+/*==========================================================
+**
+** Access to fields of structs.
+**
+**==========================================================
+*/
+
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+
+/*---------------------------------------
+**
+** Timestamps for profiling
+**
+**---------------------------------------
+*/
+
+struct tstamp {
+ struct timeval start;
+ struct timeval end;
+ struct timeval select;
+ struct timeval command;
+ struct timeval data;
+ struct timeval status;
+ struct timeval disconnect;
+ struct timeval reselect;
+};
+
+/*
+** profiling data (per device)
+*/
+
+struct profile {
+ u_long num_trans;
+ u_long num_bytes;
+ u_long num_disc;
+ u_long num_break;
+ u_long num_int;
+ u_long num_fly;
+ u_long ms_setup;
+ u_long ms_data;
+ u_long ms_disc;
+ u_long ms_post;
+};
+
+/*==========================================================
+**
+** Declaration of structs: TARGET control block
+**
+**==========================================================
+*/
+
+struct tcb {
+ /*
+ ** during reselection the ncr jumps to this point
+ ** with SFBR set to the encoded TARGET number
+ ** with bit 7 set.
+ ** if it's not this target, jump to the next.
+ **
+ ** JUMP IF (SFBR != #TARGET#)
+ ** @(next tcb)
+ */
+
+ struct link jump_tcb;
+
+ /*
+ ** load the actual synchronous mode
+ ** for this target to the sxfer register
+ **
+ ** SCR_COPY (1);
+ ** @(sval field of this tcb)
+ ** @(sxfer register)
+ */
+
+ ncrcmd getscr[3];
+
+ /*
+ ** if next message is "identify"
+ ** then load the message to SFBR,
+ ** else load 0 to SFBR.
+ **
+ ** CALL
+ ** <RESEL_LUN>
+ */
+
+ struct link call_lun;
+
+ /*
+ ** now look for the right lun.
+ **
+ ** JUMP
+ ** @(first ccb of this lun)
+ */
+
+ struct link jump_lcb;
+
+ /*
+ ** pointer to interrupted getcc ccb
+ */
+
+ ccb_p hold_cp;
+
+ /*
+ ** statistical data
+ */
+
+ u_long transfers;
+ u_long bytes;
+
+ /*
+ ** user settable limits for sync transfer
+ ** and tagged commands.
+ */
+
+ u_char usrsync;
+ u_char usrtags;
+
+ /*
+ ** negotiation of synch transfer and tagged commands
+ */
+
+ u_short period;
+ u_char _1;
+ u_char sval;
+ u_char minsync;
+ u_char maxoffs;
+
+ /*
+ ** inquire data
+ */
+#define MAX_INQUIRE 36
+ u_char inqdata[MAX_INQUIRE];
+
+ /*
+ ** the lcb's of this tcb
+ */
+
+ lcb_p lp[MAX_LUN];
+};
+
+/*==========================================================
+**
+** Declaration of structs: LUN control block
+**
+**==========================================================
+*/
+
+struct lcb {
+ /*
+ ** during reselection the ncr jumps to this point
+ ** with SFBR set to the "Identify" message.
+ ** if it's not this lun, jump to the next.
+ **
+ ** JUMP IF (SFBR == #LUN#)
+ ** @(next lcb of this target)
+ */
+
+ struct link jump_lcb;
+
+ /*
+ ** if next message is "simple tag",
+ ** then load the tag to SFBR,
+ ** else load 0 to SFBR.
+ **
+ ** CALL
+ ** <RESEL_TAG>
+ */
+
+ struct link call_tag;
+
+ /*
+ ** now look for the right ccb.
+ **
+ ** JUMP
+ ** @(first ccb of this lun)
+ */
+
+ struct link jump_ccb;
+
+ /*
+ ** start of the ccb chain
+ */
+
+ ccb_p next_ccb;
+
+ /*
+ ** Control of tagged queueing
+ */
+
+ u_char reqccbs;
+ u_char actccbs;
+ u_char reqlink;
+ u_char actlink;
+ u_char usetags;
+ u_char lasttag;
+};
+
+/*==========================================================
+**
+** Declaration of structs: COMMAND control block
+**
+**==========================================================
+**
+** This substructure is copied from the ccb to a
+** global address after selection (or reselection)
+** and copied back before disconnect.
+**
+** These fields are accessible to the script processor.
+**
+**----------------------------------------------------------
+*/
+
+struct head {
+ /*
+ ** Execution of a ccb starts at this point.
+ ** It's a jump to the "SELECT" label
+ ** of the script.
+ **
+ ** After successful selection the script
+ ** processor overwrites it with a jump to
+ ** the IDLE label of the script.
+ */
+
+ struct link launch;
+
+ /*
+ ** Saved data pointer.
+ ** Points to the position in the script
+ ** responsible for the actual transfer
+ ** of data.
+ ** It's written after reception of a
+ ** "SAVE_DATA_POINTER" message.
+ */
+
+ u_long savep;
+
+ /*
+ ** The virtual address of the ccb
+ ** containing this header.
+ */
+
+ ccb_p cp;
+
+ /*
+ ** space for some timestamps to gather
+ ** profiling data about devices and this driver.
+ */
+
+ struct tstamp stamp;
+
+ /*
+ ** status fields.
+ */
+
+ u_char status[8];
+
+#define host_status phys.header.status[0]
+#define scsi_status phys.header.status[1]
+#define scs2_status phys.header.status[2]
+#define sync_status phys.header.status[3]
+#define parity_errs phys.header.status[4]
+};
+
+/*==========================================================
+**
+** Declaration of structs: Data structure block
+**
+**==========================================================
+**
+** During execution of a ccb by the script processor,
+** the DSA (data structure address) register points
+** to this substructure of the ccb.
+** This substructure contains the header with
+** the script-processor-changable data and
+** data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+struct dsb {
+
+ /*
+ ** Header.
+ ** Has to be the first entry,
+ ** because it's jumped to by the
+ ** script processor
+ */
+
+ struct head header;
+
+ /*
+ ** Table data for Script
+ */
+
+ struct scr_tblsel select;
+ struct scr_tblmove smsg ;
+ struct scr_tblmove smsg2 ;
+ struct scr_tblmove cmd ;
+ struct scr_tblmove sense ;
+ struct scr_tblmove data [MAX_SCATTER];
+};
+
+/*==========================================================
+**
+** Declaration of structs: Command control block.
+**
+**==========================================================
+**
+** During execution of a ccb by the script processor,
+** the DSA (data structure address) register points
+** to this substructure of the ccb.
+** This substructure contains the header with
+** the script-processor-changable data and then
+** data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+
+struct ccb {
+ /*
+ ** during reselection the ncr jumps to this point.
+ ** If a "SIMPLE_TAG" message was received,
+ ** then SFBR is set to the tag.
+ ** else SFBR is set to 0
+ ** If looking for another tag, jump to the next ccb.
+ **
+ ** JUMP IF (SFBR != #TAG#)
+ ** @(next ccb of this lun)
+ */
+
+ struct link jump_ccb;
+
+ /*
+ ** After execution of this call, the return address
+ ** (in the TEMP register) points to the following
+ ** data structure block.
+ ** So copy it to the DSA register, and start
+ ** processing of this data structure.
+ **
+ ** CALL
+ ** <RESEL_TMP>
+ */
+
+ struct link call_tmp;
+
+ /*
+ ** This is the data structure which is
+ ** to be executed by the script processor.
+ */
+
+ struct dsb phys;
+
+ /*
+ ** If a data transfer phase is terminated too early
+ ** (after reception of a message (i.e. DISCONNECT)),
+ ** we have to prepare a mini script to transfer
+ ** the rest of the data.
+ */
+
+ u_long patch[8];
+
+ /*
+ ** The general SCSI driver provides a
+ ** pointer to a control block.
+ */
+
+ struct scsi_xfer *xfer;
+
+#ifdef ANCIENT
+ /*
+ ** We copy the SCSI command, because it
+ ** may be volatile (on the stack).
+ **
+ */
+ struct scsi_generic cmd;
+#endif /* ANCIENT */
+
+ /*
+ ** We prepare a message to be sent after selection,
+ ** and a second one to be sent after getcc selection.
+ ** Contents are IDENTIFY and SIMPLE_TAG.
+ ** And sdtr .. (if negotiating sync transfers)
+ */
+
+ u_char scsi_smsg [8];
+ u_char scsi_smsg2[8];
+
+ /*
+ ** Lock this ccb.
+ ** Flag is used while looking for a free ccb.
+ */
+
+ u_long magic;
+ u_long tlimit;
+
+ /*
+ ** All ccbs of one hostadapter are linked.
+ */
+
+ ccb_p link_ccb;
+
+ /*
+ ** All ccbs of one target/lun are linked.
+ */
+
+ ccb_p next_ccb;
+
+ /*
+ ** Tag for this transfer.
+ ** It's patched into jump_ccb.
+ ** If it's not zero, a SIMPLE_TAG
+ ** message is included in smsg.
+ */
+
+ u_char tag;
+};
+
+/*==========================================================
+**
+** Declaration of structs: NCR device descriptor
+**
+**==========================================================
+*/
+
+struct ncb {
+ /*-----------------------------------------------
+ ** Scripts ..
+ **-----------------------------------------------
+ **
+ ** During reselection the ncr jumps to this point.
+ ** The SFBR register is loaded with the encoded target id.
+ **
+ ** Jump to the first target.
+ **
+ ** JUMP
+ ** @(next tcb)
+ */
+ struct link jump_tcb;
+
+ /*-----------------------------------------------
+ ** Configuration ..
+ **-----------------------------------------------
+ **
+ ** virtual and physical addresses
+ ** of the 53c810 chip.
+ */
+ vm_offset_t vaddr;
+ vm_offset_t paddr;
+
+ /*
+ ** pointer to the chip's registers.
+ */
+ volatile
+ struct ncr_reg* reg;
+
+ /*
+ ** virtual and physical addresses
+ ** of the script.
+ */
+ struct script* v_script;
+ u_long p_script;
+
+ /*
+ ** The SCSI address of the host adapter.
+ */
+ u_char myaddr;
+
+ /*
+ ** timing parameters
+ */
+ u_char ns_async;
+ u_char ns_sync;
+ u_char rv_scntl3;
+
+#ifndef ANCIENT
+ /*-----------------------------------------------
+ ** Link to the generic SCSI driver
+ **-----------------------------------------------
+ */
+
+ struct scsi_link sc_link;
+#endif /* ANCIENT */
+
+ /*-----------------------------------------------
+ ** Job control
+ **-----------------------------------------------
+ **
+ ** Commands from user
+ */
+ struct usrcmd user;
+ u_char order;
+
+ /*
+ ** Target data
+ */
+ struct tcb target[MAX_TARGET];
+
+ /*
+ ** Start queue.
+ */
+ u_long squeue [MAX_START];
+ u_short squeueput;
+ u_short actccbs;
+
+ /*
+ ** Timeout handler
+ */
+ u_long heartbeat;
+ u_short ticks;
+ u_short latetime;
+ u_long lasttime;
+ u_short imask;
+ u_short mcount;
+
+ /*-----------------------------------------------
+ ** Debug and profiling
+ **-----------------------------------------------
+ **
+ ** register dump
+ */
+ struct ncr_reg regdump;
+ struct timeval regtime;
+
+ /*
+ ** Profiling data
+ */
+ struct profile profile;
+ u_long disc_phys;
+ u_long disc_ref;
+
+ /*-----------------------------------------------
+ ** Working areas
+ **-----------------------------------------------
+ **
+ ** The global header.
+ ** Accessible to both the host and the
+ ** script-processor.
+ */
+
+ struct head header;
+
+ /*
+ ** The global control block.
+ ** It's used only during the configuration phase.
+ ** A target control block will be created
+ ** after the first successful transfer.
+ */
+
+ struct ccb ccb;
+
+ /*
+ ** message buffers.
+ ** Should be longword aligned,
+ ** because they're written with a
+ ** COPY script command.
+ */
+
+ u_char msgout[8];
+ u_char msgin [8];
+
+ /*
+ ** Buffer for STATUS_IN phase.
+ */
+
+ u_char scratch;
+ u_char lock; /* @DEBUG@ */
+
+#ifdef __NetBSD__
+ /*-----------------------------------------------
+ ** Interrupt handler.
+ **-----------------------------------------------
+ **
+ ** Only for NetBSD
+ */
+
+ struct intrhand ihand;
+#endif
+
+};
+
+/*==========================================================
+**
+**
+** Script for NCR-Processor.
+**
+** Use ncr_script_fill() to create the variable parts.
+** Use ncr_script_bind() to bind to physical addresses.
+**
+**
+**==========================================================
+**
+** We have to know the offsets of all labels before
+** we reach them (for forward jumps).
+** Therefore we declare a struct here.
+** If you make changes inside the script,
+** DONT FORGET TO CHANGE THE LENGTHS HERE!
+**
+**----------------------------------------------------------
+*/
+
+struct script {
+ ncrcmd start [ 2];
+ ncrcmd start1 [ 10];
+ ncrcmd startpos [ 1];
+ ncrcmd tryloop [MAX_START*5+2];
+ ncrcmd trysel [ 8];
+ ncrcmd skip [ 8];
+ ncrcmd skip2 [ 3];
+ ncrcmd idle [ 2];
+ ncrcmd select [ 22];
+ ncrcmd prepare [ 4];
+ ncrcmd loadpos [ 24];
+ ncrcmd prepare2 [ 20];
+ ncrcmd setmsg [ 5];
+ ncrcmd clrack [ 6];
+ ncrcmd dispatch [ 22];
+ ncrcmd no_data [ 19];
+ ncrcmd checkatn [ 16];
+ ncrcmd command [ 15];
+ ncrcmd status [ 25];
+ ncrcmd msg_in [ 22];
+ ncrcmd msg_bad [ 6];
+ ncrcmd msg_parity [ 12];
+ ncrcmd msg_reject [ 6];
+ ncrcmd msg_extended [ 34];
+ ncrcmd msg_sdtr [ 39];
+ ncrcmd complete [ 6];
+ ncrcmd cleanup [ 12];
+ ncrcmd savepos [ 11];
+ ncrcmd signal [ 10];
+ ncrcmd save_dp [ 5];
+ ncrcmd restore_dp [ 5];
+ ncrcmd disconnect [ 21];
+ ncrcmd msg_out [ 9];
+ ncrcmd msg_out_done [ 7];
+ ncrcmd msg_out_abort [ 10];
+ ncrcmd getcc [ 4];
+ ncrcmd getcc1 [ 5];
+ ncrcmd getcc2 [ 33];
+ ncrcmd badgetcc [ 2];
+ ncrcmd reselect [ 12];
+ ncrcmd reselect2 [ 6];
+ ncrcmd resel_tmp [ 5];
+ ncrcmd resel_lun [ 18];
+ ncrcmd resel_tag [ 24];
+ ncrcmd data_in [MAX_SCATTER * 4 + 7];
+ ncrcmd data_out [MAX_SCATTER * 4 + 7];
+ ncrcmd aborttag [ 4];
+ ncrcmd abort [ 20];
+};
+
+/*==========================================================
+**
+**
+** Function Headers.
+**
+**
+**==========================================================
+*/
+
+#ifdef KERNEL
+#ifdef ANCIENT
+extern int splbio(void);
+extern void splx(int level);
+extern int wakeup(void* channel);
+extern int tsleep();
+extern int DELAY();
+extern int scsi_attachdevs();
+extern void timeout();
+extern void untimeout();
+#endif /* ANCIENT */
+
+static void ncr_alloc_ccb (ncb_p np, struct scsi_xfer * xp);
+static int ncr_attach (pcici_t config_id);
+static void ncr_complete (ncb_p np, ccb_p cp);
+static int ncr_delta (struct timeval * from, struct timeval * to);
+static void ncr_exception (ncb_p np);
+static void ncr_free_ccb (ncb_p np, ccb_p cp, int flags);
+static void ncr_getclock (ncb_p np);
+static ccb_p ncr_get_ccb (ncb_p np, u_long flags, u_long t,u_long l);
+static U_INT32 ncr_info (int unit);
+static void ncr_init (ncb_p np, char * msg, u_long code);
+static void ncr_int_ma (ncb_p np);
+static void ncr_int_sir (ncb_p np);
+static void ncr_int_sto (ncb_p np);
+static int ncr_intr (int dev);
+static void ncr_min_phys (struct buf *bp);
+static void ncr_opennings (ncb_p np, lcb_p lp, struct scsi_xfer * xp);
+static int ncb_probe (pcici_t config_id);
+static void ncb_profile (ncb_p np, ccb_p cp);
+static void ncr_script_bind (ncb_p np);
+static void ncr_script_copy (ncb_p oldnp, ncb_p np);
+static void ncr_script_fill (struct script * scr);
+static u_long ncr_scatter (struct dsb* phys,u_long vaddr,u_long datalen);
+static void ncr_setmaxtags (tcb_p tp, u_long usrtags);
+static void ncr_setsync (ncb_p np, ccb_p xxxcp, u_char sxfer);
+static void ncr_settags (tcb_p tp, lcb_p lp);
+static INT32 ncr_start (struct scsi_xfer *xp);
+static void ncr_timeout (ncb_p np);
+static void ncr_usercmd (ncb_p np);
+static void ncr_wakeup (ncb_p np, u_long code);
+
+/*==========================================================
+**
+**
+** Access to processor ports.
+**
+**
+**==========================================================
+*/
+
+#ifdef DIRTY
+#include <i386/isa/isa.h>
+#ifdef ANCIENT
+/*
+** Doch das ist alles nur geklaut ..
+** aus: 386bsd:/sys/i386/include/pio.h
+**
+** Mach Operating System
+** Copyright (c) 1990 Carnegie-Mellon University
+** All rights reserved. The CMU software License Agreement specifies
+** the terms and conditions for use and redistribution.
+*/
+
+#undef inb
+#define inb(port) \
+({ unsigned char data; \
+ __asm __volatile("inb %1, %0": "=a" (data): "d" ((u_short)(port))); \
+ data; })
+
+#undef outb
+#define outb(port, data) \
+{__asm __volatile("outb %0, %1"::"a" ((u_char)(data)), "d" ((u_short)(port)));}
+
+#define disable_intr() \
+{__asm __volatile("cli");}
+
+#define enable_intr() \
+{__asm __volatile("sti");}
+#endif /* ANCIENT */
+
+/*------------------------------------------------------------------
+**
+** getirr: get a bit vector of the pending interrupts.
+**
+** NOTE: this is HIGHLY hardware dependant :-(
+**
+**------------------------------------------------------------------
+*/
+
+
+static u_long getirr (void)
+{
+ u_long mask;
+
+ disable_intr();
+
+ outb (IO_ICU2, 0x0a);
+ mask = inb (IO_ICU2);
+ outb (IO_ICU2, 0x0b);
+
+ mask <<= 8;
+
+ outb (IO_ICU1, 0x0a);
+ mask|= inb (IO_ICU1);
+ outb (IO_ICU1, 0x0b);
+
+ enable_intr();
+
+ return (mask);
+}
+
+#else /* DIRTY */
+ #define getirr() (0)
+#endif /* DIRTY */
+#endif /* KERNEL */
+
+/*==========================================================
+**
+**
+** Global static data.
+**
+**
+**==========================================================
+*/
+
+
+static char ident[] =
+ "\n$Id: ncr.c,v 2.0.0.3 94/07/24 09:02:42 wolf Exp $\n"
+ "Copyright (c) 1994, Wolfgang Stanglmeier\n";
+
+
+int ncr_version = NCR_VERSION
+ + sizeof (struct ncb) * sizeof (struct ccb)
+ * sizeof (struct lcb) * sizeof (struct tcb);
+
+#ifdef KERNEL
+
+u_long ncr_units;
+u_long nncr=NNCR;
+struct ncb ncr0;
+ncb_p (ncrp [NNCR]) = {&ncr0};
+u_long ncr_msgout; /* @DEBUG@ */
+
+/*
+** SCSI cmd to get the SCSI sense data
+*/
+
+static u_char rs_cmd [6] =
+ { 0x03, 0, 0, 0, sizeof (struct scsi_sense_data), 0 };
+
+/*==========================================================
+**
+**
+** Global static data: auto configure
+**
+**
+**==========================================================
+*/
+
+struct pci_driver ncrdevice = {
+ ncb_probe,
+ ncr_attach,
+ 0x00011000ul,
+ "ncr",
+ "ncr 53c810 scsi",
+ ncr_intr
+};
+
+
+#ifndef ANCIENT
+struct scsi_adapter ncr_switch =
+{
+ ncr_start,
+ ncr_min_phys,
+ 0,
+ 0,
+ ncr_info,
+ "ncr",
+};
+
+struct scsi_device ncr_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "ncr",
+};
+#else /* ANCIENT */
+struct scsi_switch ncr_switch =
+{
+ ncr_start,
+ ncr_min_phys,
+ 0,
+ 0,
+ ncr_info,
+ 0,0,0
+};
+#endif /* ANCIENT */
+
+/*==========================================================
+**
+**
+** Scripts for NCR-Processor.
+**
+** Use ncr_script_bind for binding to physical addresses.
+**
+**
+**==========================================================
+**
+**
+**
+** PADDR generates a reference to another part of the script.
+** REG generates a reference to a script processor register.
+**
+**
+**----------------------------------------------------------
+*/
+
+#define PADDR(label) ((ncrcmd) &script0.label)
+
+static struct script script0 = {
+/*--------------------------< START >-----------------------*/ {
+ /*
+ ** Hook for interrupted GetConditionCode.
+ ** Will be patched to ... IFTRUE by
+ ** the interrupt handler.
+ */
+ SCR_INT ^ IFFALSE (0),
+ 1,
+}/*-------------------------< START1 >----------------------*/,{
+ /*
+ ** Hook for stalled start queue.
+ ** Will be patched to IFTRUE by the interrupt handler.
+ */
+ SCR_INT ^ IFFALSE (0),
+ 7,
+ /*
+ ** Claim to be still alive ...
+ */
+ SCR_COPY (sizeof (ncr0.heartbeat)),
+ (ncrcmd) &time.tv_sec,
+ (ncrcmd) &ncr0.heartbeat,
+ /*
+ ** Make data structure address invalid.
+ ** clear SIGP.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_FROM_REG (ctest2),
+ 0,
+ /*
+ ** Then jump to a certain point in tryloop.
+ ** Due to the lack of indirect addressing the code
+ ** is self modifying here.
+ */
+ SCR_JUMP,
+}/*-------------------------< STARTPOS >--------------------*/,{
+ PADDR(tryloop),
+
+}/*-------------------------< TRYLOOP >---------------------*/,{
+/*
+** Load an entry of the start queue into dsa
+** and try to start it by jumping to TRYSEL.
+**
+** Because the size depends on the
+** #define MAX_START parameter, it is filled
+** in at runtime.
+**
+**-----------------------------------------------------------
+**
+** ##===========< I=0; i<MAX_START >===========
+** || SCR_COPY (4),
+** || (ncrcmd) &ncr0.squeue[i],
+** || REG (dsa),
+** || SCR_CALL,
+** || PADDR (trysel),
+** ##==========================================
+**
+** SCR_JUMP,
+** PADDR(tryloop),
+**
+**-----------------------------------------------------------
+*/
+0
+
+}/*-------------------------< TRYSEL >----------------------*/,{
+ /*
+ ** Now:
+ ** DSA: Address of a Data Structure
+ ** or Address of the IDLE-Label.
+ **
+ ** TEMP: Address of a script, which tries to
+ ** start the NEXT entry.
+ **
+ ** Save the TEMP register into the SCRATCHA register.
+ ** Then copy the DSA to TEMP and RETURN.
+ ** This is kind of an indirect jump.
+ ** (The script processor has NO stack, so the
+ ** CALL is actually a jump and link, and the
+ ** RETURN is an indirect jump.)
+ **
+ ** If the slot was empty, DSA contains the address
+ ** of the IDLE part of this script. The processor
+ ** jumps to IDLE and waits for a reselect.
+ ** It will wake up and try the same slot again
+ ** after the SIGP bit becomes set by the host.
+ **
+ ** If the slot was not empty, DSA contains
+ ** the address of the phys-part of a ccb.
+ ** The processor jumps to this address.
+ ** phys starts with head,
+ ** head starts with launch,
+ ** so actually the processor jumps to
+ ** the lauch part.
+ ** If the entry is scheduled to be executed,
+ ** then launch contains a jump to SELECT.
+ ** If it's not scheduled, it contains a jump to IDLE.
+ */
+ SCR_COPY (4),
+ REG (temp),
+ REG (scratcha),
+ SCR_COPY (4),
+ REG (dsa),
+ REG (temp),
+ SCR_RETURN,
+ 0
+
+}/*-------------------------< SKIP >------------------------*/,{
+ /*
+ ** This entry has been canceled.
+ ** Next time use the next slot.
+ */
+ SCR_COPY (4),
+ REG (scratcha),
+ PADDR (startpos),
+ /*
+ ** patch the launch field.
+ ** should look like an idle process.
+ */
+ SCR_COPY (4),
+ REG (dsa),
+ PADDR (skip2),
+ SCR_COPY (8),
+ PADDR (idle),
+}/*-------------------------< SKIP2 >-----------------------*/,{
+ 0,
+ SCR_JUMP,
+ PADDR(start),
+}/*-------------------------< IDLE >------------------------*/,{
+ /*
+ ** Nothing to do?
+ ** Wait for reselect.
+ */
+ SCR_JUMP,
+ PADDR(reselect),
+
+}/*-------------------------< SELECT >----------------------*/,{
+ /*
+ ** DSA contains the address of a scheduled
+ ** data structure.
+ **
+ ** SCRATCHA contains the address of the script,
+ ** which starts the next entry.
+ **
+ ** Set Initiator mode.
+ **
+ ** (Target mode is left as an exercise for the student)
+ */
+
+ SCR_CLR (SCR_TRG),
+ 0,
+ SCR_LOAD_REG (scr0, 0xff),
+ 0,
+
+ /*
+ ** And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+ PADDR (reselect),
+
+ /*
+ ** Now there are 4 possibilities:
+ **
+ ** (1) The ncr looses arbitration.
+ ** This is ok, because it will try again,
+ ** when the bus becomes idle.
+ ** (But beware of the timeout function!)
+ **
+ ** (2) The ncr is reselected.
+ ** Then the script processor takes the jump
+ ** to the RESELECT label.
+ **
+ ** (3) The ncr completes the selection.
+ ** Then it will execute the next statement.
+ **
+ ** (4) There is a selection timeout.
+ ** Then the ncr should interrupt the host and stop.
+ ** Unfortunately, it seems to continue execution
+ ** of the script. But it will fail with an
+ ** IID-interrupt on the next WHEN.
+ */
+
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ 0,
+
+ /*
+ ** Save target id to ctest0 register
+ */
+
+ SCR_FROM_REG (sdid),
+ 0,
+ SCR_TO_REG (ctest0),
+ 0,
+ /*
+ ** Send the IDENTIFY and SIMPLE_TAG messages
+ ** (and the M_X_SDTR message)
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct dsb, smsg),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ -16,
+ SCR_COPY (1),
+ REG (sfbr),
+ (ncrcmd) &ncr_msgout,
+ /*
+ ** Selection complete.
+ ** Next time use the next slot.
+ */
+ SCR_COPY (4),
+ REG (scratcha),
+ PADDR (startpos),
+}/*-------------------------< PREPARE >----------------------*/,{
+ /*
+ ** The ncr doesn't have an indirect load
+ ** or store command. So we have to
+ ** copy part of the control block to a
+ ** fixed place, where we can access it.
+ **
+ ** We patch the address part of a
+ ** COPY command with the DSA-register.
+ */
+ SCR_COPY (4),
+ REG (dsa),
+ PADDR (loadpos),
+ /*
+ ** then we do the actual copy.
+ */
+ SCR_COPY (sizeof (struct head)),
+ /*
+ ** continued after the next label ...
+ */
+
+}/*-------------------------< LOADPOS >---------------------*/,{
+ 0,
+ (ncrcmd) &ncr0.header,
+ /*
+ ** Mark this ccb as not scheduled.
+ */
+ SCR_COPY (8),
+ PADDR (idle),
+ (ncrcmd) &ncr0.header.launch,
+ /*
+ ** Set a time stamp for this selection
+ */
+ SCR_COPY (sizeof (struct timeval)),
+ (ncrcmd) &time,
+ (ncrcmd) &ncr0.header.stamp.select,
+ /*
+ ** load the savep (saved pointer) into
+ ** the TEMP register (actual pointer)
+ */
+ SCR_COPY (4),
+ (ncrcmd) &ncr0.header.savep,
+ REG (temp),
+ /*
+ ** Initialize the status registers
+ */
+ SCR_COPY (4),
+ (ncrcmd) &ncr0.header.status,
+ REG (scr0),
+ /*
+ ** Set carry according to host_status
+ */
+ SCR_CLR (SCR_CARRY),
+ 0,
+ SCR_FROM_REG (scr0),
+ 0,
+ SCR_JUMPR ^ IFFALSE (DATA (HS_NEGOTIATE)),
+ 16,
+ SCR_LOAD_REG (scr0, HS_BUSY),
+ 0,
+ SCR_SET (SCR_CARRY),
+ 0,
+
+}/*-------------------------< PREPARE2 >---------------------*/,{
+ /*
+ ** <Carry set iff SDTM message sent>
+ **
+ ** Load the synchronous mode register
+ */
+ SCR_FROM_REG (scr3),
+ 0,
+ SCR_TO_REG (sxfer),
+ 0,
+ /*
+ ** Initialize the msgout buffer with a NOOP message.
+ */
+ SCR_LOAD_REG (scratcha, M_NOOP),
+ 0,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgout,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgin,
+ /*
+ ** If M_X_SDTR sent, but no MSG_IN phase, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR (msg_in),
+ SCR_JUMP ^ IFFALSE (CARRYSET),
+ PADDR (dispatch),
+ /*
+ ** no answer is an answer, too.
+ */
+ SCR_INT,
+ 3,
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< SETMSG >----------------------*/,{
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgout,
+ SCR_SET (SCR_ATN),
+ 0,
+}/*-------------------------< CLRACK >----------------------*/,{
+ /*
+ ** Terminate sdtr mode.
+ ** Terminate possible pending message phase.
+ */
+ SCR_FROM_REG (scr0),
+ 0,
+ SCR_LOAD_REG (scr0, HS_BUSY),
+ 0,
+ SCR_CLR (SCR_ACK | SCR_CARRY),
+ 0,
+
+}/*-----------------------< DISPATCH >----------------------*/,{
+ SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ 0,
+ SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)),
+ 0,
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+ PADDR (msg_out),
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
+ PADDR (msg_in),
+ SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+ PADDR (command),
+ SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+ PADDR (status),
+ /*
+ ** Discard one illegal phase byte, if required.
+ */
+ SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+ (ncrcmd) &ncr0.scratch,
+ SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+ (ncrcmd) &ncr0.scratch,
+ SCR_JUMP,
+ PADDR (dispatch),
+}/*-------------------------< NO_DATA >--------------------*/,{
+ /*
+ ** The target wants to tranfer too much data
+ ** or in the wrong direction.
+ ** Prepare an abort message and set ATN.
+ */
+ SCR_LOAD_REG (scratcha, M_ABORT),
+ 0,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgout,
+ SCR_SET (SCR_ATN),
+ 0,
+ /*
+ ** Discard one data byte, if required.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
+ (ncrcmd) &ncr0.scratch,
+ SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+ (ncrcmd) &ncr0.scratch,
+ /*
+ ** .. and repeat as required.
+ */
+ SCR_CALL,
+ PADDR (dispatch),
+ SCR_JUMP,
+ PADDR (no_data),
+
+}/*-------------------------< CHECKATN >--------------------*/,{
+ /*
+ ** If AAP (bit 1 of scntl0 register) is set
+ ** and a parity error is detected,
+ ** the script processor asserts ATN.
+ **
+ ** The target should switch to a MSG_OUT phase
+ ** to get the message.
+ */
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)),
+ PADDR (dispatch),
+ /*
+ ** count it
+ */
+ SCR_COPY (1),
+ (ncrcmd) &ncr0.header.status[4],
+ REG (scratcha),
+ SCR_REG_REG (scratcha, SCR_ADD, 0x01),
+ 0,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.header.status[4],
+ /*
+ ** Prepare a M_ID_ERROR message
+ ** (initiator detected error).
+ ** The target should retry the transfer.
+ */
+ SCR_LOAD_REG (scratcha, M_ID_ERROR),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+
+}/*-------------------------< COMMAND >--------------------*/,{
+ /*
+ ** If this is not a GETCC transfer ...
+ */
+ SCR_FROM_REG (scr1),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (S_CHECK_COND)),
+ 28,
+ /*
+ ** ... set a timestamp ...
+ */
+ SCR_COPY (sizeof (struct timeval)),
+ (ncrcmd) &time,
+ (ncrcmd) &ncr0.header.stamp.command,
+ /*
+ ** ... and send the command
+ */
+ SCR_MOVE_TBL ^ SCR_COMMAND,
+ offsetof (struct dsb, cmd),
+ SCR_JUMP,
+ PADDR (dispatch),
+ /*
+ ** Send the GETCC command
+ */
+/*>>>*/ SCR_MOVE_ABS (6) ^ SCR_COMMAND,
+ (ncrcmd) &rs_cmd,
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< STATUS >--------------------*/,{
+ /*
+ ** set the timestamp.
+ */
+ SCR_COPY (sizeof (struct timeval)),
+ (ncrcmd) &time,
+ (ncrcmd) &ncr0.header.stamp.status,
+ /*
+ ** If this is a GETCC transfer,
+ */
+ SCR_FROM_REG (scr1),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (S_CHECK_COND)),
+ 32,
+ /*
+ ** get the status
+ */
+ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ (ncrcmd) &ncr0.scratch,
+ /*
+ ** Save status to scs2_status.
+ ** Mark as complete.
+ ** And wait for disconnect.
+ */
+ SCR_TO_REG (scr2),
+ 0,
+ SCR_LOAD_REG (scr0, HS_COMPLETE),
+ 0,
+ SCR_JUMP,
+ PADDR (checkatn),
+ /*
+ ** If it was no GETCC transfer,
+ ** save the status to scsi_status.
+ */
+/*>>>*/ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ (ncrcmd) &ncr0.scratch,
+ SCR_TO_REG (scr1),
+ 0,
+ /*
+ ** if it was no check condition ...
+ */
+ SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
+ PADDR (checkatn),
+ /*
+ ** ... mark as complete.
+ */
+ SCR_LOAD_REG (scr0, HS_COMPLETE),
+ 0,
+ SCR_JUMP,
+ PADDR (checkatn),
+
+}/*-------------------------< MSG_IN >--------------------*/,{
+ /*
+ ** Get the first byte of the message
+ ** and save it to SCRATCHA.
+ **
+ ** The script processor doesn't negate the
+ ** ACK signal after this transfer.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin[0],
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDR (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ ** Parity was ok, handle this message.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+ PADDR (complete),
+ SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+ PADDR (save_dp),
+ SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+ PADDR (restore_dp),
+ SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+ PADDR (disconnect),
+ SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+ PADDR (msg_extended),
+ SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
+ PADDR (msg_reject),
+ /*
+ ** Rest of the messages left as
+ ** an exercise ...
+ **
+ ** Unimplemented messages:
+ ** fall through to MSG_BAD.
+ */
+}/*-------------------------< MSG_BAD >------------------*/,{
+ /*
+ ** unimplemented message - reject it.
+ */
+ SCR_INT,
+ 6,
+ SCR_LOAD_REG (scratcha, M_REJECT),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+
+}/*-------------------------< MSG_PARITY >---------------*/,{
+ /*
+ ** count it
+ */
+ SCR_COPY (1),
+ (ncrcmd) &ncr0.header.status[4],
+ REG (scratcha),
+ SCR_REG_REG (scratcha, SCR_ADD, 0x01),
+ 0,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.header.status[4],
+ /*
+ ** send a "message parity error" message.
+ */
+ SCR_LOAD_REG (scratcha, M_PARITY),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+}/*-------------------------< MSG_REJECT >---------------*/,{
+ /*
+ ** If a M_X_SDTR message was sent,
+ ** negotiate synchronous mode.
+ */
+ SCR_INT ^ IFTRUE (CARRYSET),
+ 3,
+ /*
+ ** make host log this message
+ */
+ SCR_INT ^ IFFALSE (CARRYSET),
+ 5,
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< MSG_EXTENDED >-------------*/,{
+ /*
+ ** Terminate cycle
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get length.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin[1],
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDR (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ */
+ SCR_JUMP ^ IFFALSE (DATA (3)),
+ PADDR (msg_bad),
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get extended message code.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin[2],
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDR (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (M_X_SDTR)),
+ PADDR (msg_sdtr),
+ /*
+ ** unknown extended message
+ */
+ SCR_JUMP,
+ PADDR (msg_bad)
+
+}/*-------------------------< MSG_SDTR >-----------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get period and offset
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin[3],
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDR (msg_parity),
+ /*
+ ** let the host do the real work.
+ */
+ SCR_INT ^ IFTRUE (CARRYSET),
+ 3,
+ SCR_INT ^ IFFALSE (CARRYSET),
+ 4,
+ /*
+ ** let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+
+/*<<<*/ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ 16,
+ SCR_INT,
+ 4,
+ SCR_JUMP,
+ PADDR (dispatch),
+ /*
+ ** Sent the M_X_SDTR
+ */
+/*>>>*/ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ (ncrcmd) &ncr0.msgout,
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ -16,
+ SCR_COPY (1),
+ REG (sfbr),
+ (ncrcmd) &ncr_msgout,
+ /*
+ ** If rejected, cancel sync transfer.
+ */
+ SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)),
+ PADDR (msg_out_done),
+ SCR_FROM_REG (sbdl),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (M_REJECT)),
+ 4,
+ SCR_JUMP,
+ PADDR (msg_out_done),
+
+}/*-------------------------< COMPLETE >-----------------*/,{
+ /*
+ ** Complete message.
+ **
+ ** When we terminate the cycle by clearing ACK,
+ ** the target may disconnect immediately.
+ **
+ ** We don't want to be told of an
+ ** "unexpected disconnect",
+ ** so we disable this feature.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ /*
+ ** Terminate cycle ...
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** ... and wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+}/*-------------------------< CLEANUP >-------------------*/,{
+ /*
+ ** dsa: Pointer to ccb
+ ** or xxxxxxFF (no ccb)
+ **
+ ** scr0: Host-Status (<>0!)
+ */
+ SCR_FROM_REG (dsa),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (0xff)),
+ PADDR (signal),
+ /*
+ ** dsa is valid.
+ ** save the status registers
+ */
+ SCR_COPY (4),
+ REG (scr0),
+ (ncrcmd) &ncr0.header.status,
+ /*
+ ** and copy back the header to the ccb.
+ */
+ SCR_COPY (4),
+ REG (dsa),
+ PADDR (savepos),
+ SCR_COPY (sizeof (struct head)),
+ (ncrcmd) &ncr0.header,
+}/*-------------------------< SAVEPOS >---------------------*/,{
+ 0,
+
+ /*
+ ** If command resulted in "check condition"
+ ** status and is not yet completed,
+ ** try to get the condition code.
+ */
+ SCR_FROM_REG (scr0),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0x00, 0xfc)),
+ 16,
+ SCR_FROM_REG (scr1),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
+ PADDR(getcc2),
+ /*
+ ** And make the DSA register invalid.
+ */
+/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */
+ 0,
+}/*-------------------------< SIGNAL >----------------------*/,{
+ /*
+ ** if status = queue full,
+ ** reinsert in startqueue and stall queue.
+ */
+ SCR_FROM_REG (scr1),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
+ 8,
+ /*
+ ** if job completed ...
+ */
+ SCR_FROM_REG (scr0),
+ 0,
+ /*
+ ** ... signal completion to the host
+ */
+ SCR_INT_FLY ^ IFFALSE (MASK (0x00, 0xfc)),
+ 0,
+ /*
+ ** Auf zu neuen Schandtaten!
+ */
+ SCR_JUMP,
+ PADDR(start),
+
+}/*-------------------------< SAVE_DP >------------------*/,{
+ /*
+ ** SAVE_DP message:
+ ** Copy TEMP register to SAVEP in header.
+ */
+ SCR_COPY (4),
+ REG (temp),
+ (ncrcmd) &ncr0.header.savep,
+ SCR_JUMP,
+ PADDR (clrack),
+}/*-------------------------< RESTORE_DP >---------------*/,{
+ /*
+ ** RESTORE_DP message:
+ ** Copy SAVEP in header to TEMP register.
+ */
+ SCR_COPY (4),
+ (ncrcmd) &ncr0.header.savep,
+ REG (temp),
+ SCR_JUMP,
+ PADDR (clrack),
+}/*-------------------------< DISCONNECT >---------------*/,{
+ /*
+ ** Disable the "unexpected disconnect" feature.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** Profiling:
+ ** Set a time stamp,
+ ** and count the disconnects.
+ */
+ SCR_COPY (sizeof (struct timeval)),
+ (ncrcmd) &time,
+ (ncrcmd) &ncr0.header.stamp.disconnect,
+ SCR_COPY (4),
+ (ncrcmd) &ncr0.disc_phys,
+ REG (temp),
+ SCR_REG_REG (temp, SCR_ADD, 0x01),
+ 0,
+ SCR_COPY (4),
+ REG (temp),
+ (ncrcmd) &ncr0.disc_phys,
+ /*
+ ** Status is: DISCONNECTED.
+ */
+ SCR_LOAD_REG (scr0, HS_DISCONNECT),
+ 0,
+ SCR_JUMP,
+ PADDR (cleanup),
+
+}/*-------------------------< MSG_OUT >-------------------*/,{
+ /*
+ ** The target requests a message.
+ ** First remove ATN so the target will
+ ** not continue fetching messages.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ (ncrcmd) &ncr0.msgout,
+ SCR_COPY (1),
+ REG (sfbr),
+ (ncrcmd) &ncr_msgout,
+ /*
+ ** If it was no ABORT message ...
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
+ PADDR (msg_out_abort),
+ /*
+ ** ... wait for the next phase
+ ** if it's a message out, send it again, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR (msg_out),
+}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+ /*
+ ** ... else clear the message ...
+ */
+ SCR_LOAD_REG (scratcha, M_NOOP),
+ 0,
+ SCR_COPY (4),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgout,
+ /*
+ ** ... and process the next phase
+ */
+ SCR_JUMP,
+ PADDR (dispatch),
+}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
+ /*
+ ** After ABORT message,
+ **
+ ** expect an immediate disconnect, ...
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** ... and set the status to "ABORTED"
+ */
+ SCR_LOAD_REG (scr0, HS_ABORTED),
+ 0,
+ SCR_JUMP,
+ PADDR (cleanup),
+
+}/*-------------------------< GETCC >-----------------------*/,{
+ /*
+ ** The ncr doesn't have an indirect load
+ ** or store command. So we have to
+ ** copy part of the control block to a
+ ** fixed place, where we can modify it.
+ **
+ ** We patch the address part of a COPY command
+ ** with the address of the dsa register ...
+ */
+ SCR_COPY (4),
+ REG (dsa),
+ PADDR (getcc1),
+ /*
+ ** ... then we do the actual copy.
+ */
+ SCR_COPY (sizeof (struct head)),
+}/*-------------------------< GETCC1 >----------------------*/,{
+ 0,
+ (ncrcmd) &ncr0.header,
+ /*
+ ** Initialize the status registers
+ */
+ SCR_COPY (4),
+ (ncrcmd) &ncr0.header.status,
+ REG (scr0),
+}/*-------------------------< GETCC2 >----------------------*/,{
+ /*
+ ** Get the condition code from a target.
+ **
+ ** DSA points to a data structure.
+ ** Set TEMP to the script location
+ ** that receives the condition code.
+ **
+ ** Because there is no script command
+ ** to load a longword into a register,
+ ** we use a CALL command.
+ */
+/*<<<*/ SCR_CALLR,
+ 24,
+ /*
+ ** Get the condition code.
+ */
+ SCR_MOVE_TBL ^ SCR_DATA_IN,
+ offsetof (struct dsb, sense),
+ /*
+ ** No data phase may follow!
+ */
+ SCR_CALL,
+ PADDR (checkatn),
+ SCR_JUMP,
+ PADDR (no_data),
+/*>>>*/
+
+ /*
+ ** The CALL jumps to this point.
+ ** Prepare for a RESTORE_POINTER message.
+ ** Save the TEMP register into the saved pointer.
+ */
+ SCR_COPY (4),
+ REG (temp),
+ (ncrcmd) &ncr0.header.savep,
+ /*
+ ** Load scratcha, because in case of a selection timeout,
+ ** the host will expect a new value for startpos in
+ ** the scratcha register.
+ */
+ SCR_COPY (4),
+ PADDR (startpos),
+ REG (scratcha),
+ /*
+ ** Then try to connect to the target.
+ ** If we are reselected, special treatment
+ ** of the current job is required before
+ ** accepting the reselection.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+ PADDR(badgetcc),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ 0,
+ SCR_FROM_REG (sdid),
+ 0,
+ SCR_TO_REG (ctest0),
+ 0,
+ /*
+ ** and send the IDENTIFY and a SDTM message.
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct dsb, smsg2),
+ SCR_JUMPR ^ IFTRUE ( WHEN (SCR_MSG_OUT) ),
+ -16,
+ SCR_COPY (1),
+ REG (sfbr),
+ (ncrcmd) &ncr_msgout,
+ /*
+ ** Handle synch negotiation.
+ */
+ SCR_SET (SCR_CARRY),
+ 0,
+ SCR_JUMP,
+ PADDR (prepare2),
+
+}/*------------------------< BADGETCC >---------------------*/,{
+ SCR_INT,
+ 2,
+}/*-------------------------< RESELECT >--------------------*/,{
+ /*
+ ** make the DSA invalid.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ ** Sleep waiting for a reselection.
+ ** If SIGP is set, special treatment.
+ **
+ ** Zu allem bereit ..
+ */
+ SCR_WAIT_RESEL,
+ PADDR(reselect2),
+ /*
+ ** ... zu nichts zu gebrauchen ?
+ **
+ ** load the target id into the SFBR
+ ** and jump to the control block.
+ **
+ ** Look at the declarations of
+ ** - struct ncb
+ ** - struct tcb
+ ** - struct lcb
+ ** - struct ccb
+ ** to understand what's going on.
+ */
+ SCR_REG_SFBR (ssid, SCR_AND, 0x87),
+ 0,
+ SCR_TO_REG (ctest0),
+ 0,
+ SCR_JUMP,
+ (ncrcmd) &ncr0.jump_tcb,
+}/*-------------------------< RESELECT2 >-------------------*/,{
+ /*
+ ** If it's not connected :(
+ ** -> interrupted by SIGP bit.
+ ** Jump to start.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+ PADDR (start),
+ SCR_JUMP,
+ PADDR (reselect),
+
+}/*-------------------------< RESEL_TMP >-------------------*/,{
+ /*
+ ** The return address in TEMP
+ ** is in fact the data structure address,
+ ** so copy it to the DSA register.
+ */
+ SCR_COPY (4),
+ REG (temp),
+ REG (dsa),
+ SCR_JUMP,
+ PADDR (prepare),
+
+}/*-------------------------< RESEL_LUN >-------------------*/,{
+ /*
+ ** come back to this point
+ ** to get an IDENTIFY message
+ ** Wait for a msg_in phase.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 48,
+ /*
+ ** message phase
+ ** It's not a sony, it's a trick:
+ ** read the data without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)),
+ 32,
+ /*
+ ** It WAS an Identify message.
+ ** get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Mask out the LUN.
+ */
+ SCR_REG_REG (sfbr, SCR_AND, 0x07),
+ 0,
+ SCR_RETURN,
+ 0,
+ /*
+ ** No message phase or no IDENTIFY message:
+ ** return 0.
+ */
+/*>>>*/ SCR_LOAD_SFBR (0),
+ 0,
+ SCR_RETURN,
+ 0,
+
+}/*-------------------------< RESEL_TAG >-------------------*/,{
+ /*
+ ** come back to this point
+ ** to get a SIMPLE_TAG message
+ ** Wait for a MSG_IN phase.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 64,
+ /*
+ ** message phase
+ ** It's a trick - read the data
+ ** without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
+ 48,
+ /*
+ ** It WAS a SIMPLE_TAG message.
+ ** get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Wait for the second byte (the tag)
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 24,
+ /*
+ ** Get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ (ncrcmd) &ncr0.msgin,
+ SCR_CLR (SCR_ACK|SCR_CARRY),
+ 0,
+ SCR_RETURN,
+ 0,
+ /*
+ ** No message phase or no SIMPLE_TAG message
+ ** or no second byte: return 0.
+ */
+/*>>>*/ SCR_LOAD_SFBR (0),
+ 0,
+ SCR_SET (SCR_CARRY),
+ 0,
+ SCR_RETURN,
+ 0,
+
+}/*-------------------------< DATA_IN >--------------------*/,{
+/*
+** Because the size depends on the
+** #define MAX_SCATTER parameter,
+** it is filled in at runtime.
+**
+** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** PADDR (no_data),
+** SCR_COPY (sizeof (struct timeval)),
+** (ncrcmd) &time,
+** (ncrcmd) &ncr0.header.stamp.data,
+** SCR_MOVE_TBL ^ SCR_DATA_IN,
+** offsetof (struct dsb, data[ 0]),
+**
+** ##===========< i=1; i<MAX_SCATTER >=========
+** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** || PADDR (checkatn),
+** || SCR_MOVE_TBL ^ SCR_DATA_IN,
+** || offsetof (struct dsb, data[ i]),
+** ##==========================================
+**
+** SCR_CALL,
+** PADDR (checkatn),
+** SCR_JUMP,
+** PADDR (no_data),
+*/
+0
+}/*-------------------------< DATA_OUT >-------------------*/,{
+/*
+** Because the size depends on the
+** #define MAX_SCATTER parameter,
+** it is filled in at runtime.
+**
+** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** PADDR (no_data),
+** SCR_COPY (sizeof (struct timeval)),
+** (ncrcmd) &time,
+** (ncrcmd) &ncr0.header.stamp.data,
+** SCR_MOVE_TBL ^ SCR_DATA_OUT,
+** offsetof (struct dsb, data[ 0]),
+**
+** ##===========< i=1; i<MAX_SCATTER >=========
+** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+** || PADDR (dispatch),
+** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
+** || offsetof (struct dsb, data[ i]),
+** ##==========================================
+**
+** SCR_CALL,
+** PADDR (dispatch),
+** SCR_JUMP,
+** PADDR (no_data),
+**
+**---------------------------------------------------------
+*/
+(u_long)&ident
+
+}/*-------------------------< ABORTTAG >-------------------*/,{
+ /*
+ ** Abort a bad reselection.
+ ** Set the message to ABORT vs. ABORT_TAG
+ */
+ SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+ 0,
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+}/*-------------------------< ABORT >----------------------*/,{
+ SCR_LOAD_REG (scratcha, M_ABORT),
+ 0,
+ SCR_COPY (1),
+ REG (scratcha),
+ (ncrcmd) &ncr0.msgout,
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** and send it.
+ ** we expect an immediate disconnect
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ (ncrcmd) &ncr0.msgout,
+ SCR_COPY (1),
+ REG (sfbr),
+ (ncrcmd) &ncr_msgout,
+ SCR_WAIT_DISC,
+ 0,
+ SCR_JUMP,
+ PADDR (start),
+}/*--------------------------------------------------------*/
+};
+
+/*==========================================================
+**
+**
+** Fill in #define dependent parts of the script
+**
+**
+**==========================================================
+*/
+
+void ncr_script_fill (struct script * scr)
+{
+ int i;
+ ncrcmd *p;
+
+ p = scr->tryloop;
+ for (i=0; i<MAX_START; i++) {
+ *p++ =SCR_COPY (4);
+ *p++ =(ncrcmd) &ncr0.squeue[i];
+ *p++ =REG (dsa);
+ *p++ =SCR_CALL;
+ *p++ =PADDR (trysel);
+ };
+ *p++ =SCR_JUMP;
+ *p++ =PADDR(tryloop);
+
+ assert ((u_long)p == (u_long)&scr->tryloop + sizeof (scr->tryloop));
+
+ p = scr->data_in;
+
+ *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
+ *p++ =PADDR (no_data);
+ *p++ =SCR_COPY (sizeof (struct timeval));
+ *p++ =(ncrcmd) &time;
+ *p++ =(ncrcmd) &ncr0.header.stamp.data;
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+ *p++ =offsetof (struct dsb, data[ 0]);
+
+ for (i=1; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+ *p++ =PADDR (checkatn);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+ *p++ =offsetof (struct dsb, data[i]);
+ };
+
+ *p++ =SCR_CALL;
+ *p++ =PADDR (checkatn);
+ *p++ =SCR_JUMP;
+ *p++ =PADDR (no_data);
+
+ assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
+
+ p = scr->data_out;
+
+ *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
+ *p++ =PADDR (no_data);
+ *p++ =SCR_COPY (sizeof (struct timeval));
+ *p++ =(ncrcmd) &time;
+ *p++ =(ncrcmd) &ncr0.header.stamp.data;
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+ *p++ =offsetof (struct dsb, data[ 0]);
+
+ for (i=1; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+ *p++ =PADDR (dispatch);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+ *p++ =offsetof (struct dsb, data[i]);
+ };
+
+ *p++ =SCR_CALL;
+ *p++ =PADDR (dispatch);
+ *p++ =SCR_JUMP;
+ *p++ =PADDR (no_data);
+
+ assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
+}
+
+/*==========================================================
+**
+**
+** Bind the script to its physical address.
+**
+**
+**==========================================================
+*/
+
+static int ncr_unit (ncb_p np)
+{
+ int idx;
+ for (idx=0;idx<NNCR; idx++)
+ if (ncrp[idx]==np)
+ return (idx);
+ return (-1);
+}
+
+static void ncr_script_bind (ncb_p np)
+{
+ ncrcmd *p = (ncrcmd*) np->v_script;
+ ncrcmd opcode, arg, a1;
+ ncrcmd *end, *start;
+
+ start = p;
+ for (end=p+(sizeof(struct script)/4);p<end;) {
+
+ /*
+ ** If we forget to change the length
+ ** in struct script, a field will be
+ ** padded with 0. This is an illegal
+ ** command.
+ */
+
+ if (!(opcode=*p++))
+ printf ("ncr%d: ERROR0 IN SCRIPT at %d.\n",
+ ncr_unit(np), p-start-1);
+ arg=*p;
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SCRIPT)
+ printf ("%x: <%x>\n",
+ (u_long)(p-1), opcode);
+#endif /* SCSI_NCR_DEBUG */
+ /*
+ ** We don't have to decode ALL commands
+ */
+ switch (opcode >> 28) {
+
+ case 0xc:
+ /*
+ ** COPY has TWO arguments.
+ */
+ a1 = arg;
+ if (a1 >= 256) *p = vtophys (a1);
+ else *p = np->paddr + a1;
+ arg = *++p;
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SCRIPT)
+ printf ("%x: <%x>\n", (u_long)p, *p);
+#endif /* SCSI_NCR_DEBUG */
+ if ((a1 ^ arg) & 3)
+ printf ("ncr%d: script: ERROR1 IN SCRIPT at %d.\n",
+ ncr_unit (np), p-start-1);
+ /* pass */
+ case 0x0:
+ /*
+ ** MOVE (absolute address)
+ */
+ if (arg >= 256) *p = vtophys (arg);
+ else *p = np->paddr + arg;
+ break;
+ case 0x8:
+ /*
+ ** JUMP / CALL
+ ** dont't relocate if relative :-)
+ */
+ if (opcode & 0x00800000) break;
+ *p = vtophys (arg);
+ break;
+ /*
+ ** don't relocate 0 arguments.
+ */
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ if (arg) *p = vtophys (arg);
+ break;
+ default:
+ break;
+ };
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SCRIPT)
+ printf ("%x: <%x>\n", (u_long)p, *p);
+#endif /* SCSI_NCR_DEBUG */
+ p++;
+ };
+}
+
+/*==========================================================
+**
+**
+** Copy and rebind a script.
+**
+**
+**==========================================================
+*/
+
+static void ncr_script_copy (ncb_p oldnp, ncb_p np)
+{
+ ncrcmd *src = (ncrcmd*) oldnp->v_script;
+ ncrcmd *end = (ncrcmd*) oldnp->v_script + sizeof (struct script)/4;
+ ncrcmd *dst = (ncrcmd*) np->v_script;
+
+ u_long oldbase = vtophys (oldnp);
+ u_long newbase = vtophys (np);
+
+ ncrcmd opcode, old, new;
+ u_long d;
+
+ printf ("ncr%d: script_copy from ncr%d..\n",
+ ncr_unit (np), ncr_unit (oldnp));
+ while (src < end) {
+
+ *dst++ = opcode = *src++;
+
+ new=old=*src++;
+
+ /*
+ ** We don't have to decode ALL commands
+ */
+ switch (opcode >> 28) {
+
+ case 0xc:
+ /*
+ ** COPY has TWO arguments.
+ */
+
+ d = old - oldnp->paddr;
+ if (d<sizeof (struct ncr_reg))
+ new = np->paddr + d;
+
+ d = old - oldnp->p_script;
+ if (d<sizeof (struct script))
+ new = np->p_script + d;
+
+ d = old - oldbase;
+ if (d<sizeof (struct ncb))
+ new = newbase + d;
+
+ *dst++ = new;
+ new=old=*src++;
+
+ /*
+ ** fall through
+ */
+
+ case 0x0:
+ /*
+ ** MOVE (absolute address)
+ */
+ d = old - oldnp->paddr;
+ if (d<sizeof (struct ncr_reg))
+ new = np->paddr + d;
+
+ d = old - oldnp->p_script;
+ if (d<sizeof (struct script))
+ new = np->p_script + d;
+
+ d = old - oldbase;
+ if (d<sizeof (struct ncb))
+ new = newbase + d;
+
+ break;
+ case 0x8:
+ /*
+ ** JUMP / CALL
+ ** dont't relocate if relative :-)
+ */
+ if (opcode & 0x00800000) break;
+ /*
+ ** fall through
+ */
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ d = old - oldnp->paddr;
+ if (d<sizeof (struct ncr_reg))
+ new = np->paddr + d;
+
+ d = old - oldnp->p_script;
+ if (d<sizeof (struct script))
+ new = np->p_script + d;
+
+ d = old - oldbase;
+ if (d<sizeof (struct ncb))
+ new = newbase + d;
+
+ default:
+ break;
+ };
+ *dst++ = new;
+ };
+ assert ((char*)src == ((char*)oldnp->v_script)+sizeof(struct script));
+ assert ((char*)dst == ((char*) np->v_script)+sizeof(struct script));
+}
+
+/*==========================================================
+**
+**
+** Auto configuration.
+**
+**
+**==========================================================
+*/
+
+/*----------------------------------------------------------
+**
+** Reduce the transfer length to the max value
+** we can transfer safely.
+**
+** Reading a block greater then MAX_SIZE from the
+** raw (character) device exercises a memory leak
+** in the vm subsystem. This is common to ALL devices.
+** We have submitted a description of this bug to
+** <FreeBSD-bugs@freefall.cdrom.com>.
+** It should be fixed in the current release.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_min_phys (struct buf *bp)
+{
+ if (bp->b_bcount > MAX_SIZE) bp->b_bcount = MAX_SIZE;
+}
+
+/*----------------------------------------------------------
+**
+** Maximal number of outstanding requests per target.
+**
+**----------------------------------------------------------
+*/
+
+U_INT32 ncr_info (int unit)
+{
+ return (1); /* may be changed later */
+}
+
+/*----------------------------------------------------------
+**
+** Probe the hostadapter.
+**
+**----------------------------------------------------------
+*/
+
+static int ncb_probe(pcici_t config_id)
+{
+ if (ncr_units >= NNCR) return (-1);
+ return (ncr_units);
+}
+
+/*==========================================================
+**
+**
+** Auto configuration: attach and init a host adapter.
+**
+**
+**==========================================================
+*/
+
+#define MIN_ASYNC_PD 40
+#define MIN_SYNC_PD 20
+
+static int ncr_attach (pcici_t config_id)
+{
+ int retval;
+ ncb_p np = ncrp[ncr_units];
+
+ /*
+ ** allocate structure
+ */
+
+ if (!np) {
+ np = (ncb_p) malloc (sizeof (struct ncb),
+ M_DEVBUF, M_NOWAIT);
+ if (!np) return (0);
+ ncrp[ncr_units]=np;
+ }
+
+ /*
+ ** initialize structure.
+ */
+
+ bzero (np, sizeof (*np));
+
+ /*
+ ** Try to map the controller chip to
+ ** virtual and physical memory.
+ */
+
+ retval = pci_map_mem (config_id, 0x14, &np->vaddr, &np->paddr);
+
+ if (retval) {
+ printf ("ncr%d: pci_map_mem failed.\n",ncr_unit (np));
+ return (retval);
+ };
+
+ /*
+ ** Patch script to physical addresses
+ */
+
+ if (np==&ncr0) {
+ np->v_script = &script0;
+ np->p_script = vtophys (np->v_script);
+ ncr_script_fill (&script0);
+ ncr_script_bind (np);
+ } else {
+ /*
+ ** allocate space for script
+ */
+ np->v_script = (struct script *)
+ malloc (sizeof (struct ncb), M_DEVBUF, M_NOWAIT);
+ if (!np->v_script) return (0);
+ np->p_script = vtophys (np->v_script);
+ ncr_script_copy (&ncr0, np);
+ };
+
+ /*
+ ** init data structure
+ */
+
+ np -> jump_tcb.l_cmd = SCR_JUMP ;
+ np -> jump_tcb.l_paddr = vtophys (&np->v_script->abort);
+
+ /*
+ ** Make the controller's registers available.
+ ** Now the INB INW INL OUTB OUTW OUTL macros
+ ** can be used safely.
+ */
+
+ np->reg = (struct ncr_reg*) np->vaddr;
+
+ /*
+ ** Get SCSI addr of host adapter (set by bios?).
+ */
+
+ np->myaddr = INB(nc_scid) & 0x07;
+ if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
+
+ /*
+ ** Get the value of the chip's clock.
+ ** Find the right value for scntl3.
+ */
+
+ ncr_getclock (np);
+
+ /*
+ ** Reset chip.
+ */
+
+ OUTB (nc_istat, SRST);
+ OUTB (nc_istat, 0 );
+
+ /*
+ ** After SCSI devices have been opened, we cannot
+ ** reset the bus safely, so we do it here.
+ ** Interrupt handler does the real work.
+ */
+
+ OUTB (nc_scntl1, CRST);
+
+ /*
+ ** process the reset exception,
+ ** if interrupts are not enabled yet.
+ */
+ ncr_exception (np);
+
+#ifdef ANCIENT
+ printf ("ncr%d waiting for scsi devices to settle\n",
+ ncr_unit (np));
+ DELAY (1000000);
+#endif
+
+ /*
+ ** Now let the generic SCSI driver
+ ** look for the SCSI devices on the bus ..
+ */
+
+#ifndef ANCIENT
+#ifdef __NetBSD__
+ np->sc_link.adapter_softc = np;
+#else/*__NetBSD__*/
+ np->sc_link.adapter_unit = ncr_units;
+#endif /*__NetBSD__*/
+ np->sc_link.adapter_targ = np->myaddr;
+ np->sc_link.adapter = &ncr_switch;
+ np->sc_link.device = &ncr_dev;
+
+ scsi_attachdevs (&np->sc_link);
+#else /* ANCIENT */
+ scsi_attachdevs (ncr_units, np->myaddr, &ncr_switch);
+#endif /* ANCIENT */
+
+ /*
+ ** start the timeout daemon
+ */
+ ncr_timeout (np);
+ np->lasttime=0;
+
+ /*
+ ** Done.
+ */
+
+ ncr_units++;
+
+ return(1);
+}
+
+/*==========================================================
+**
+**
+** Process pending device interrupts.
+**
+**
+**==========================================================
+*/
+
+static int ncr_intr (int dev)
+{
+ ncb_p np;
+ int n=0;
+
+ /*
+ ** Sanity check
+ */
+
+ if (dev >= ncr_units) return (0);
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("[");
+#endif /* SCSI_NCR_DEBUG */
+
+ assert (dev<NNCR);
+
+ /*
+ ** Repeat until no outstanding ints
+ */
+
+ np = ncrp[dev];
+ while (INB(nc_istat) & (INTF|SIP|DIP)) {
+ ncr_exception (np);
+ n=1;
+ };
+
+ /*
+ ** Switch timeout function to slow.
+ */
+
+ if (n) np->ticks = 100;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("]\n");
+#endif /* SCSI_NCR_DEBUG */
+
+ return (n);
+}
+
+/*==========================================================
+**
+**
+** Start execution of a SCSI command.
+** This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+static INT32 ncr_start (struct scsi_xfer * xp)
+{
+#ifndef ANCIENT
+#ifdef __NetBSD__
+ ncb_p np = xp->sc_link->adapter_softc;
+#else /*__NetBSD__*/
+ ncb_p np = ncrp[xp->sc_link->adapter_unit];
+#endif/*__NetBSD__*/
+#else /* ANCIENT */
+ ncb_p np = ncrp[xp->adapter];
+#endif /* ANCIENT */
+
+ struct scsi_generic * cmd = xp->cmd;
+ ccb_p cp;
+ lcb_p lp;
+ tcb_p tp;
+
+ int i, oldspl, flags = xp->flags;
+ u_char ptr, startcode, idmsg;
+ u_long msglen, msglen2;
+
+ /*---------------------------------------------
+ **
+ ** Reset SCSI bus
+ **
+ ** Interrupt handler does the real work.
+ **
+ **---------------------------------------------
+ */
+
+ if (flags & SCSI_RESET) {
+ OUTB (nc_scntl1, CRST);
+ return(COMPLETE);
+ };
+
+ /*---------------------------------------------
+ **
+ ** Some shortcuts ...
+ **
+ **---------------------------------------------
+ */
+
+ if ((xp->TARGET == np->myaddr ) ||
+ (xp->TARGET >= MAX_TARGET) ||
+ (xp->LUN >= MAX_LUN ) ||
+ (flags & SCSI_DATA_UIO)) {
+ xp->error = XS_DRIVER_STUFFUP;
+ return(HAD_ERROR);
+ };
+
+#ifdef ANCIENT
+ /*---------------------------------------------
+ ** Ancient version of <sys/scsi/sd.c>
+ ** doesn't set the DATA_IN/DATA_OUT bits.
+ ** So we have to fix it ..
+ **---------------------------------------------
+ */
+
+ switch (cmd->opcode) {
+ case 0x1a: /* MODE_SENSE */
+ case 0x25: /* READ_CAPACITY */
+ case 0x28: /* READ_BIG (10) */
+ xp->flags |= SCSI_DATA_IN;
+ break;
+ case 0x2a: /* WRITE_BIG(10) */
+ xp->flags |= SCSI_DATA_OUT;
+ break;
+ };
+#endif /* ANCIENT */
+
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_TINY)
+ printf("ncr%d targ %d: CMD=%x F=%x L=%x ",
+ ncr_unit (np), xp->TARGET, cmd->opcode,
+ xp->flags, xp->datalen);
+#endif /* SCSI_NCR_DEBUG */
+
+ /*--------------------------------------------
+ **
+ ** Sanity checks ...
+ ** copied from Elischer's Adaptec driver.
+ **
+ **--------------------------------------------
+ */
+
+ flags = xp->flags;
+ if (!(flags & INUSE)) {
+ printf("ncr%d: ?INUSE?\n", ncr_unit (np));
+ xp->flags |= INUSE;
+ };
+
+ if(flags & ITSDONE) {
+ printf("ncr%d: ?ITSDONE?\n", ncr_unit (np));
+ xp->flags &= ~ITSDONE;
+ };
+
+ if (xp->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+
+ /*---------------------------------------------------
+ **
+ ** Assign a ccb
+ **
+ **----------------------------------------------------
+ */
+
+ if (!(cp=ncr_get_ccb (np, flags, xp->TARGET, xp->LUN))) {
+ printf ("ncr%d: no ccb.\n", ncr_unit (np));
+ xp->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ };
+
+ /*---------------------------------------------------
+ **
+ ** timestamp
+ **
+ **----------------------------------------------------
+ */
+
+ bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
+ cp->phys.header.stamp.start = time;
+
+ /*---------------------------------------------------
+ **
+ ** sync negotiation required?
+ **
+ **----------------------------------------------------
+ */
+
+ tp = &np->target[xp->TARGET];
+
+ if ((cmd->opcode!=0x12) && (tp->period)) {
+
+ startcode = HS_BUSY;
+
+ } else if (!(tp->inqdata[7] & INQ7_SYNC)) {
+
+ tp->minsync = 255;
+ tp->maxoffs = 8 ;
+ tp->period =0xffff;
+ startcode = HS_BUSY;
+
+ } else {
+ /*
+ ** minsync unit is 4ns !
+ */
+
+ u_long minsync = tp->usrsync;
+
+ if (minsync < 25) minsync=25;
+
+ /*
+ ** if not scsi 2
+ ** don't believe FAST!
+ */
+
+ if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2)
+ minsync=50;
+
+ /*
+ ** our limit ..
+ */
+
+ if (minsync < np->ns_sync)
+ minsync = np->ns_sync;
+
+ /*
+ ** divider limit
+ */
+
+ if (minsync > (np->ns_sync * 11) / 4)
+ minsync = 255;
+
+ tp->minsync = minsync;
+ tp->maxoffs = (minsync<255 ? 8 : 0);
+
+ startcode = HS_NEGOTIATE;
+ };
+
+ /*---------------------------------------------------
+ **
+ ** choose a new tag ...
+ **
+ **----------------------------------------------------
+ */
+
+ if ((lp = tp->lp[xp->LUN]) && (lp->usetags)) {
+ /*
+ ** assign a tag to this ccb!
+ */
+ while (!cp->tag) {
+ ccb_p cp2 = lp->next_ccb;
+ lp->lasttag = lp->lasttag % 255 + 1;
+ while (cp2 && cp2->tag != lp->lasttag)
+ cp2 = cp2->next_ccb;
+ if (cp2) continue;
+ cp->tag=lp->lasttag;
+ printf ("ncr%d targ %d lun %d: using tag #%d.\n",
+ ncr_unit (np), xp->TARGET, xp->LUN, cp->tag);
+ };
+ } else cp->tag=0;
+
+
+ /*----------------------------------------------------
+ **
+ ** Build the identify / tag / sdtr message
+ **
+ **----------------------------------------------------
+ */
+
+ idmsg = (cp==&np->ccb ? 0x80 : 0xc0) | xp->LUN;
+
+ cp -> scsi_smsg [0] = idmsg;
+ msglen=1;
+
+ if (cp->tag) {
+
+ /*
+ ** Ordered write ops, unordered read ops.
+ */
+ switch (cmd->opcode) {
+ case 0x08: /* READ_SMALL (6) */
+ case 0x28: /* READ_BIG (10) */
+ case 0xa8: /* READ_HUGE (12) */
+ cp -> scsi_smsg [msglen] = M_SIMPLE_TAG;
+ break;
+ default:
+ cp -> scsi_smsg [msglen] = M_ORDERED_TAG;
+ }
+
+ /*
+ ** can be overwritten by ncrstat
+ */
+ switch (np->order) {
+
+ case M_SIMPLE_TAG:
+ cp -> scsi_smsg [msglen] = M_SIMPLE_TAG;
+ break;
+
+ case M_ORDERED_TAG:
+ cp -> scsi_smsg [msglen] = M_ORDERED_TAG;
+ break;
+ };
+ msglen++;
+
+ cp -> scsi_smsg [msglen++] = cp -> tag;
+ }
+ if (startcode==HS_NEGOTIATE) {
+ cp -> scsi_smsg [msglen++] = M_EXTENDED;
+ cp -> scsi_smsg [msglen++] = 3;
+ cp -> scsi_smsg [msglen++] = M_X_SDTR;
+ cp -> scsi_smsg [msglen++] = np->target[xp->TARGET].minsync;
+ cp -> scsi_smsg [msglen++] = np->target[xp->TARGET].maxoffs;
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Build the identify / sdtr message for getcc
+ **
+ **----------------------------------------------------
+ */
+
+ cp -> scsi_smsg2 [0] = idmsg;
+ msglen2 = 1;
+ if (np->target[xp->TARGET].inqdata[7]&INQ7_SYNC) {
+ cp -> scsi_smsg2 [1] = M_EXTENDED;
+ cp -> scsi_smsg2 [2] = 3;
+ cp -> scsi_smsg2 [3] = M_X_SDTR;
+ cp -> scsi_smsg2 [4] = np->target[xp->TARGET].minsync;
+ cp -> scsi_smsg2 [5] = np->target[xp->TARGET].maxoffs;
+ msglen2 = 6;
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Build the data descriptors
+ **
+ **----------------------------------------------------
+ */
+
+ if (ncr_scatter (&cp->phys,
+ (vm_offset_t) xp->data,
+ (vm_size_t) xp->datalen)) {
+ xp->error = XS_DRIVER_STUFFUP;
+ ncr_free_ccb(np, cp, flags);
+ return(HAD_ERROR);
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Set the SAVED_POINTER.
+ **
+ **----------------------------------------------------
+ */
+
+ if (flags & SCSI_DATA_IN) {
+ cp->phys.header.savep = vtophys (&np->v_script->data_in);
+ } else if (flags & SCSI_DATA_OUT) {
+ cp->phys.header.savep = vtophys (&np->v_script->data_out);
+ } else {
+ cp->phys.header.savep = vtophys (&np->v_script->no_data);
+ };
+
+ /*----------------------------------------------------
+ **
+ ** fill ccb
+ **
+ **----------------------------------------------------
+ */
+
+ /*
+ ** physical -> virtual translation
+ */
+ cp->phys.header.cp = cp;
+ /*
+ ** Generic SCSI command
+ */
+ cp->xfer = xp;
+ /*
+ ** Startqueue
+ */
+ cp->phys.header.launch.l_paddr = vtophys (&np->v_script->select);
+ cp->phys.header.launch.l_cmd = SCR_JUMP;
+ /*
+ ** select
+ */
+ cp->phys.select.sel_id = xp->TARGET;
+ cp->phys.select.sel_scntl3 = np->rv_scntl3;
+ cp->phys.select.sel_sxfer = np->target[xp->TARGET].sval;
+ /*
+ ** message
+ */
+ cp->phys.smsg.addr = vtophys (&cp->scsi_smsg );
+ cp->phys.smsg.size = msglen;
+ cp->phys.smsg2.addr = vtophys (&cp->scsi_smsg2);
+ cp->phys.smsg2.size = msglen2;
+ /*
+ ** command
+ */
+#ifdef ANCIENT
+ bcopy (cmd, &cp->cmd, sizeof (cp->cmd));
+ cp->phys.cmd.addr = vtophys (&cp->cmd);
+#else /* ANCIENT */
+ cp->phys.cmd.addr = vtophys (cmd);
+#endif /* ANCIENT */
+ cp->phys.cmd.size = xp->cmdlen;
+ /*
+ ** sense data
+ */
+ cp->phys.sense.addr = vtophys (&cp->xfer->sense);
+ cp->phys.sense.size = sizeof(struct scsi_sense_data);
+ /*
+ ** status
+ */
+ cp->scs2_status = S_ILLEGAL;
+ cp->scsi_status = S_ILLEGAL;
+ cp->sync_status = np->target[xp->TARGET].sval;
+ cp->host_status = startcode;
+ cp->parity_errs = 0;
+
+ /*----------------------------------------------------
+ **
+ ** Critical region: starting this job.
+ **
+ **----------------------------------------------------
+ */
+
+ oldspl = 0; /* for the sake of gcc */
+ if (!(flags & SCSI_NOMASK)) oldspl = splbio();
+ np->lock++;
+
+ /*
+ ** reselect pattern and activate this job.
+ */
+
+ cp->jump_ccb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (cp->tag)));
+ cp->tlimit = time.tv_sec + xp->timeout / 1000 + 2;
+ cp->magic = CCB_MAGIC;
+
+ /*
+ ** insert into startqueue.
+ */
+
+ ptr = np->squeueput + 1;
+ if (ptr >= MAX_START) ptr=0;
+ np->squeue [ptr ] = vtophys(&np->v_script->idle);
+ np->squeue [np->squeueput] = vtophys(&cp->phys);
+ np->squeueput = ptr;
+
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_QUEUE)
+ printf ("ncr%d: queuepos=%d tryoffset=%d.\n", ncr_unit (np),
+ np->squeueput, np->v_script->startpos[0]-(vtophys(&np->v_script->tryloop)));
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** Script processor may be waiting for reconnect.
+ ** Wake it up.
+ */
+ OUTB (nc_istat, SIGP);
+
+ /*
+ ** If interrupts are enabled, return now.
+ ** Command is successfully queued.
+ */
+
+ np->lock--;
+ if (!(flags & SCSI_NOMASK)) {
+ splx (oldspl);
+ if (np->lasttime) {
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_TINY) printf ("Q");
+#endif /* SCSI_NCR_DEBUG */
+ return(SUCCESSFULLY_QUEUED);
+ };
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Interrupts not yet enabled - have to poll.
+ **
+ **----------------------------------------------------
+ */
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_POLL) printf("P");
+#endif /* SCSI_NCR_DEBUG */
+
+ for (i=xp->timeout; i && !(xp->flags & ITSDONE);i--) {
+#ifdef SCSI_NCR_DEBUG
+ if ((ncr_debug & DEBUG_POLL) && (cp->host_status))
+ printf ("%c", (cp->host_status & 0xf) + '0');
+#endif /* SCSI_NCR_DEBUG */
+ DELAY (1000);
+ ncr_exception (np);
+ };
+
+ /*
+ ** Abort if command not done.
+ */
+ if (!(xp->flags & ITSDONE)) {
+ printf ("ncr%d: aborting job ...\n", ncr_unit (np));
+ OUTB (nc_istat, CABRT);
+ DELAY (100000);
+ OUTB (nc_istat, SIGP);
+ ncr_exception (np);
+ };
+
+ if (!(xp->flags & ITSDONE)) {
+ printf ("ncr%d: abortion failed at %x.\n",
+ ncr_unit (np), INL(nc_dsp));
+ ncr_init (np, "timeout", HS_TIMEOUT);
+ };
+
+ if (!(xp->flags & ITSDONE)) {
+ cp-> host_status = HS_SEL_TIMEOUT;
+ ncr_complete (np, cp);
+ };
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_RESULT) {
+ printf ("ncr%d: result: %x %x %x.\n",
+ ncr_unit (np), cp->host_status,
+ cp->scsi_status, cp->scs2_status);
+ };
+#endif /* SCSI_NCR_DEBUG */
+ if (!(flags & SCSI_NOMASK))
+ return (SUCCESSFULLY_QUEUED);
+ switch (xp->error) {
+ case 0 : return (COMPLETE);
+ case XS_BUSY: return (TRY_AGAIN_LATER);
+ };
+ return (HAD_ERROR);
+}
+
+/*==========================================================
+**
+**
+** Complete execution of a SCSI command.
+** Signal completion to the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+void ncr_complete (ncb_p np, ccb_p cp)
+{
+ struct scsi_xfer * xp;
+ tcb_p tp;
+ lcb_p lp;
+
+ /*
+ ** Sanity check
+ */
+
+ if (!cp || !cp->magic || !cp->xfer) return;
+ cp->magic = 1;
+ cp->tlimit= 0;
+
+ /*
+ ** No Reselect anymore.
+ */
+ cp->jump_ccb.l_cmd = (SCR_JUMP);
+
+ /*
+ ** No starting.
+ */
+ cp->phys.header.launch.l_paddr= vtophys (&np->v_script->idle);
+
+ /*
+ ** timestamp
+ */
+ ncb_profile (np, cp);
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY)
+ printf ("CCB=%x STAT=%x/%x/%x\n", (u_long)cp & 0xfff,
+ cp->host_status,cp->scsi_status,cp->scs2_status);
+#endif /* SCSI_NCR_DEBUG */
+
+ xp = cp->xfer;
+ cp->xfer = NULL;
+ tp = &np->target[xp->TARGET];
+ lp = tp->lp[xp->LUN];
+
+ /*
+ ** @PARITY@
+ ** Check for parity errors.
+ */
+
+ if (cp->parity_errs) {
+ printf ("ncr%d targ %d: %d parity error(s), fallback.\n",
+ ncr_unit (np), xp->TARGET, cp->parity_errs);
+ /*
+ ** fallback to asynch transfer.
+ */
+ tp->usrsync=255;
+ tp->period = 0;
+ };
+
+ /*
+ ** Check the status.
+ */
+ if ( (cp->host_status == HS_COMPLETE)
+ && (cp->scsi_status == S_GOOD)) {
+
+ /*
+ ** All went well.
+ */
+ xp->resid = 0;
+
+ /*
+ ** Try to assign a ccb to this nexus
+ */
+ ncr_alloc_ccb (np, xp);
+
+ /*
+ ** On inquire cmd (0x12) save some data.
+ */
+#ifdef ANCIENT
+ if (cp->cmd.opcode == 0x12) {
+#else /* ANCIENT */
+ if (xp->cmd->opcode == 0x12) {
+#endif /* ANCIENT */
+ bcopy ( xp->data,
+ &tp->inqdata,
+ sizeof (tp->inqdata));
+ ncr_setmaxtags (tp, tp->usrtags);
+ tp->period=0;
+ };
+
+ if (!tp->sval) {
+ printf ("ncr%d targ %d: asynchronous.\n",
+ ncr_unit (np), xp->TARGET);
+ tp->sval = 0xe0;
+ };
+
+ /*
+ ** Announce changes to the generic driver
+ */
+ if (lp) {
+ ncr_settags (tp, lp);
+ if (lp->reqlink != lp->actlink)
+ ncr_opennings (np, lp, xp);
+ };
+
+#ifdef DK
+ dk_xfer[DK] ++;
+ dk_wds [DK] += xp->datalen/64;
+ dk_wpms[DK] = 1000000;
+#endif /* DK */
+
+ tp->bytes += xp->datalen;
+ tp->transfers ++;
+
+ } else if (xp->flags & SCSI_ERR_OK) {
+
+ /*
+ ** Not correct, but errors expected.
+ */
+ xp->resid = 0;
+
+ } else if ((cp->host_status == HS_COMPLETE)
+ && (cp->scsi_status == S_CHECK_COND)
+ && (cp->scs2_status == S_GOOD)) {
+
+ /*
+ ** Check condition code
+ */
+ xp->error = XS_SENSE;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & (DEBUG_RESULT|DEBUG_TINY)) {
+ u_char * p = (u_char*) & xp->sense;
+ int i;
+ printf ("\nncr%d: sense data:", ncr_unit (np));
+ for (i=0; i<14; i++) printf (" %x", *p++);
+ printf (".\n");
+ };
+#endif /* SCSI_NCR_DEBUG */
+
+ } else if ((cp->host_status == HS_COMPLETE)
+ && (cp->scsi_status == S_BUSY)) {
+
+ /*
+ ** Target is busy.
+ */
+ xp->error = XS_BUSY;
+
+ } else if ((cp->host_status == HS_SEL_TIMEOUT)
+ || (cp->host_status == HS_TIMEOUT)) {
+
+ /*
+ ** No response
+ */
+ xp->error = XS_TIMEOUT;
+
+ } else {
+
+ /*
+ ** Other protocol messes
+ */
+ printf ("ncr%d targ %d: COMMAND FAILED (%x %x %x) @%x.\n",
+ ncr_unit (np), xp->TARGET,
+ cp->host_status, cp->scsi_status, cp->scs2_status,
+ cp);
+
+ xp->error = XS_DRIVER_STUFFUP;
+ }
+
+ xp->flags |= ITSDONE;
+
+ /*
+ ** Free this ccb
+ */
+ ncr_free_ccb (np, cp, xp->flags);
+
+ /*
+ ** signal completion to generic driver.
+ */
+#ifdef ANCIENT
+ if (xp->when_done)
+ (*(xp->when_done))(xp->done_arg,xp->done_arg2);
+#else /* ANCIENT */
+ scsi_done (xp);
+#endif /* ANCIENT */
+}
+
+/*==========================================================
+**
+**
+** Signal all (or one) control block done.
+**
+**
+**==========================================================
+*/
+
+void ncr_wakeup (ncb_p np, u_long code)
+{
+ /*
+ ** Starting at the default ccb and following
+ ** the links, complete all jobs with a
+ ** host_status greater than "disconnect".
+ **
+ ** If the "code" parameter is not zero,
+ ** complete all jobs that are not IDLE.
+ */
+
+ ccb_p cp = &np->ccb;
+ while (cp) {
+ switch (cp->host_status) {
+
+ case HS_IDLE:
+ break;
+
+ case HS_DISCONNECT:
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_TINY) printf ("D");
+#endif /* SCSI_NCR_DEBUG */
+ /* fall through */
+
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ if (!code) break;
+ cp->host_status = code;
+
+ /* fall through */
+
+ default:
+ ncr_complete (np, cp);
+ break;
+ };
+ cp = cp -> link_ccb;
+ };
+}
+
+/*==========================================================
+**
+**
+** Start NCR chip.
+**
+**
+**==========================================================
+*/
+
+void ncr_init (ncb_p np, char * msg, u_long code)
+{
+ int i;
+ u_long usrsync;
+
+ /*
+ ** Reset chip.
+ */
+
+ OUTB (nc_istat, SRST );
+
+ /*
+ ** Message.
+ */
+
+ if (msg) printf ("ncr%d: restart (%s).\n", ncr_unit (np), msg);
+
+ /*
+ ** Clear Start Queue
+ */
+
+ for (i=0;i<MAX_START;i++)
+ np -> squeue [i] = vtophys (&np->v_script->idle);
+
+ /*
+ ** Start at first entry.
+ */
+
+ np->squeueput = 0;
+ np->v_script->startpos[0] = vtophys (&np->v_script->tryloop);
+ np->v_script->start [0] = SCR_INT ^ IFFALSE (0);
+
+ /*
+ ** Wakeup all pending jobs.
+ */
+
+ ncr_wakeup (np, code);
+
+ /*
+ ** Init chip.
+ */
+
+ OUTB (nc_istat, 0 ); /* Remove Reset, abort ... */
+ OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */
+ OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */
+ OUTB (nc_scntl3, np->rv_scntl3);/* timing prescaler */
+ OUTB (nc_scid , 0x40|np->myaddr); /* host adapter SCSI address */
+ OUTB (nc_respid, 1<<np->myaddr);/* id to respond to */
+ OUTB (nc_istat , SIGP ); /* Signal Process */
+ OUTB (nc_dmode , 0xc ); /* Burst length = 16 transfer */
+ OUTB (nc_dcntl , NOCOM ); /* no single step mode, protect SFBR*/
+ OUTB (nc_ctest4, 0x08 ); /* enable master parity checking */
+ OUTB (nc_stest3, TE ); /* TolerANT enable */
+ OUTB (nc_stime0, 0xfb ); /* HTH = 1.6sec STO = 0.1 sec. */
+
+ /*
+ ** Reinitialize usrsync.
+ ** Have to renegotiate synch mode.
+ */
+
+ usrsync = 255;
+ if (SCSI_NCR_MAX_SYNC) {
+ u_long period;
+ period =1000000/SCSI_NCR_MAX_SYNC; /* ns = 10e6 / kHz */
+ if (period <= 11 * np->ns_sync) {
+ if (period < 4 * np->ns_sync)
+ usrsync = np->ns_sync;
+ else
+ usrsync = period / 4;
+ };
+ };
+
+ for (i=0;i<MAX_TARGET;i++) {
+ tcb_p tp = &np->target[i];
+ tp->period = 0;
+ tp->sval = 0;
+ tp->usrsync = usrsync;
+ }
+
+ /*
+ ** enable ints
+ */
+
+ OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
+ OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
+
+ /*
+ ** Start script processor.
+ */
+
+ OUTL (nc_dsp, vtophys (&np->v_script->start));
+}
+
+/*==========================================================
+**
+** Switch sync mode for current job and it's target
+** @CHECKOUT@ xxxcp only for assert - may delete it.
+**
+**==========================================================
+*/
+
+static void ncr_setsync (ncb_p np, ccb_p xxxcp, u_char sxfer)
+{
+ u_short target = INB (nc_ctest0)&7;
+ u_short period;
+ tcb_p tp;
+ ccb_p cp;
+
+ assert (xxxcp);
+ if (!xxxcp) return;
+ assert (xxxcp->xfer);
+ if (!xxxcp->xfer) return;
+ assert (target==xxxcp->xfer->TARGET & 7);
+
+ tp = &np->target[target];
+ tp->period= sxfer&0xf ? ((sxfer>>5)+4) * np->ns_sync : 0xffff;
+ if (tp->sval == sxfer) return;
+ tp->sval = sxfer;
+
+ /*
+ ** Bells and whistles ;-)
+ */
+ if (sxfer & 0x0f) {
+ period = np->ns_sync * ((sxfer>>5)+4);
+ printf ("ncr%d targ %d: %s%dns (%d Mb/sec) offset %d.\n",
+ ncr_unit (np), target, period<200 ? "FAST SCSI-2 ":"",
+ period, (1000+period/2)/period, sxfer & 0x0f);
+ } else{
+ printf ("ncr%d targ %d: asynchronous.\n",
+ ncr_unit (np), target);
+ }
+
+ /*
+ ** set actual value and sync_status
+ */
+ OUTB (nc_scr3 , sxfer);
+ OUTB (nc_sxfer, sxfer);
+
+ /*
+ ** patch ALL ccbs of this target.
+ */
+ for (cp = &np->ccb; cp; cp = cp -> link_ccb) {
+ if (!cp->xfer) continue;
+ if (cp->xfer->TARGET != target) continue;
+ cp->sync_status = sxfer;
+ };
+}
+
+/*==========================================================
+**
+** Switch tagged mode for a target.
+**
+**==========================================================
+*/
+
+static void ncr_setmaxtags (tcb_p tp, u_long usrtags)
+{
+ int l;
+ tp->usrtags = usrtags;
+ for (l=0; l<MAX_LUN; l++) {
+ lcb_p lp;
+ if (!tp) break;
+ lp=tp->lp[l];
+ if (!lp) continue;
+ ncr_settags (tp, lp);
+ };
+}
+
+static void ncr_settags (tcb_p tp, lcb_p lp)
+{
+ u_char reqtags, tmp;
+
+ if ((!tp) || (!lp)) return;
+
+ /*
+ ** only devices capable of tagges commands
+ ** only disk devices
+ ** only if enabled by user ..
+ */
+ if (( tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00)
+ && tp->usrtags) {
+ reqtags = tp->usrtags;
+ if (lp->actlink <= 1)
+ lp->usetags=reqtags;
+ } else {
+ reqtags = 1;
+ if (lp->actlink <= 1)
+ lp->usetags=0;
+ };
+
+ /*
+ ** don't announce more than available.
+ */
+ tmp = lp->actccbs;
+ if (tmp > reqtags) tmp = reqtags;
+ lp->reqlink = tmp;
+
+ /*
+ ** don't discard if announced.
+ */
+ tmp = lp->actlink;
+ if (tmp < reqtags) tmp = reqtags;
+ lp->reqccbs = tmp;
+}
+
+/*----------------------------------------------------
+**
+** handle user commands
+**
+**----------------------------------------------------
+*/
+
+static void ncr_usercmd (ncb_p np)
+{
+ u_char t;
+ tcb_p tp;
+
+ switch (np->user.cmd) {
+
+ case 0: return;
+
+ case UC_SETSYNC:
+ for (t=0; t<MAX_TARGET; t++) {
+ if (!((np->user.target>>t)&1)) continue;
+ tp = &np->target[t];
+ tp->usrsync = np->user.data;
+ tp->period = 0;
+ };
+ break;
+
+ case UC_SETTAGS:
+ if (np->user.data > SCSI_NCR_MAX_TAGS)
+ break;
+ for (t=0; t<MAX_TARGET; t++) {
+ if (!((np->user.target>>t)&1)) continue;
+ ncr_setmaxtags (&np->target[t], np->user.data);
+ };
+ break;
+
+ case UC_SETDEBUG:
+ ncr_debug = np->user.data;
+ break;
+
+ case UC_SETORDER:
+ np->order = np->user.data;
+ break;
+
+ }
+ np->user.cmd=0;
+}
+
+/*==========================================================
+**
+**
+** ncr timeout handler.
+**
+**
+**==========================================================
+**
+** Misused to keep the driver running when
+** interrupts are not configured correctly.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_timeout (ncb_p np)
+{
+ u_long thistime = time.tv_sec;
+ u_long step = np->ticks;
+ u_long count = 0;
+ long signed t;
+ ccb_p cp;
+
+ if (np->lasttime != thistime) {
+ np->lasttime = thistime;
+
+ ncr_usercmd (np);
+
+ /*----------------------------------------------------
+ **
+ ** handle ncr chip timeouts
+ **
+ ** Assumption:
+ ** We have a chance to arbitrate for the
+ ** SCSI bus at least every 10 seconds.
+ **
+ **----------------------------------------------------
+ */
+
+ t = thistime - np->heartbeat;
+
+ if (t<2) np->latetime=0; else np->latetime++;
+
+ if (np->latetime>2) {
+ /*
+ ** If there are no requests, the script
+ ** processor will sleep on SEL_WAIT_RESEL.
+ ** But we have to check whether it died.
+ ** Let's wake it up.
+ */
+ OUTB (nc_istat, SIGP);
+ };
+
+ if (np->latetime>10) {
+ /*
+ ** Although we tried to wakeup it,
+ ** the script processor didn't answer.
+ **
+ ** May be a target is hanging,
+ ** or another initator lets a tape device
+ ** rewind with disconnect disabled :-(
+ **
+ ** We won't accept that.
+ */
+ printf ("ncr%d: reset by timeout.\n", ncr_unit (np));
+ OUTB (nc_istat, SRST);
+ OUTB (nc_istat, 0);
+ if (INB (nc_sbcl) & CBSY)
+ OUTB (nc_scntl1, CRST);
+ ncr_init (np, NULL, HS_TIMEOUT);
+ np->heartbeat = thistime;
+ };
+
+ /*----------------------------------------------------
+ **
+ ** handle ccb timeouts
+ **
+ **----------------------------------------------------
+ */
+
+ for (cp=&np->ccb; cp; cp=cp->link_ccb) {
+ /*
+ ** look for timed out ccbs.
+ */
+ if (!cp->host_status) continue;
+ count++;
+ if (cp->tlimit > thistime) continue;
+
+ /*
+ ** Disable reselect.
+ ** Remove it from startqueue.
+ */
+ cp->jump_ccb.l_cmd = (SCR_JUMP);
+ if (cp->phys.header.launch.l_paddr ==
+ vtophys (&np->v_script->select)) {
+ printf ("ncr%d: timeout ccb=%x (skip)\n",
+ ncr_unit (np), cp);
+ cp->phys.header.launch.l_paddr
+ = vtophys (&np->v_script->skip);
+ };
+
+ switch (cp->host_status) {
+
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ /*
+ ** still in start queue ?
+ */
+ if (cp->phys.header.launch.l_paddr ==
+ vtophys (&np->v_script->skip))
+ continue;
+
+ /* fall through */
+ case HS_DISCONNECT:
+ cp->host_status=HS_TIMEOUT;
+ };
+ cp->tag = 0;
+
+ /*
+ ** wakeup this ccb.
+ */
+ {
+ int oldspl = splbio();
+ ncr_complete (np, cp);
+ splx (oldspl);
+ };
+ };
+ }
+
+ timeout (TIMEOUT ncr_timeout, (caddr_t) np, step ? step : 1);
+
+ if ((INB(nc_istat) & (INTF|SIP|DIP)) && !np->lock) {
+
+ /*
+ ** Process pending interrupts.
+ */
+
+ int oldspl = splbio ();
+ u_long imask = getirr();
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("{");
+#endif /* SCSI_NCR_DEBUG */
+ ncr_exception (np);
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("}");
+#endif /* SCSI_NCR_DEBUG */
+ imask &=~getirr();
+ splx (oldspl);
+
+ /*
+ ** automagically find int vector.
+ */
+ if (imask) {
+ if ((imask != np->imask) && (np->mcount<100))
+ np->mcount=0;
+ np->imask = imask;
+ np->mcount ++;
+ };
+
+ /*
+ ** a hint to the user :-)
+ */
+ if (np->mcount==100) {
+ if (np->imask & (np->imask-1)) {
+ printf ("ncr%d: please configure intr mask %x.\n",
+ ncr_unit (np), np->imask);
+ } else {
+#ifdef __NetBSD__
+ if (!np->ihand.ih_fun) {
+ np->ihand.ih_fun = ncr_intr;
+ np->ihand.ih_arg = (void*)ncr_unit (np);
+ np->ihand.ih_level = IPL_BIO;
+ intr_establish(ffs (np->imask)-1,
+ &np->ihand);
+ }
+#else
+ printf ("ncr%d: please configure intr %d.\n",
+ ncr_unit (np), ffs (np->imask)-1);
+#endif
+ };
+ np->mcount++;
+ };
+ };
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler.
+**
+**
+**==========================================================
+**
+** @RECOVER@ this function is not yet complete.
+**
+** there should be better ways to handle
+** unexpected exceptions than to restart the
+** script processor.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_exception (ncb_p np)
+{
+ u_char istat, dstat;
+ u_short sist;
+ u_long dsp;
+
+ /*
+ ** interrupt on the fly ?
+ */
+ while ((istat = INB (nc_istat)) & INTF) {
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("F");
+#endif /* SCSI_NCR_DEBUG */
+ OUTB (nc_istat, INTF);
+ np->profile.num_fly++;
+ ncr_wakeup (np, 0);
+ };
+
+ if (!(istat & (SIP|DIP))) return;
+ dstat = INB (nc_dstat);
+ sist = INW (nc_sist) ;
+ np->profile.num_int++;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY)
+ printf ("<%d|%x:%x|%x:%x>",
+ INB(nc_scr0),
+ dstat,sist,
+ INL(nc_dsp),INL(nc_dbc));
+#endif /* SCSI_NCR_DEBUG */
+
+/*==========================================================
+**
+** First the normal cases.
+**
+**==========================================================
+*/
+ /*-------------------------------------------
+ ** SCSI reset
+ **-------------------------------------------
+ */
+
+ if (sist & RST) {
+ ncr_init (np, "scsi reset", HS_RESET);
+ return;
+ };
+
+ /*-------------------------------------------
+ ** selection timeout
+ **
+ ** IID excluded from dstat mask!
+ ** (chip bug)
+ **-------------------------------------------
+ */
+
+ if ((sist & STO) &&
+ !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR))) {
+ ncr_int_sto (np);
+ return;
+ };
+
+ /*-------------------------------------------
+ ** Phase mismatch.
+ **-------------------------------------------
+ */
+
+ if ((sist & MA) &&
+ !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ ncr_int_ma (np);
+ return;
+ };
+
+ /*-------------------------------------------
+ ** Programmed interrupt
+ **-------------------------------------------
+ */
+
+ if ((dstat & SIR) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|IID)) &&
+ (INB(nc_dsps) <= 8)) {
+ ncr_int_sir (np);
+ return;
+ };
+
+ /*========================================
+ ** do the register dump
+ **========================================
+ */
+
+#ifdef SCSI_NCR_DEBUG
+ if (!(ncr_debug & DEBUG_NODUMP)) /* @DEBUG@ */
+#endif
+ if (time.tv_sec - np->regtime.tv_sec>10) {
+ int i;
+ np->regtime = time;
+ for (i=0; i<sizeof(np->regdump); i++)
+ ((char*)&np->regdump)[i] = ((char*)np->reg)[i];
+ np->regdump.nc_dstat = dstat;
+ np->regdump.nc_sist = sist;
+ };
+
+ printf ("ncr%d targ %d?: ERROR (%x:%x:%x) (%x/%x) @ (%x:%x).\n",
+ ncr_unit (np), INB (nc_ctest0)&7, dstat, sist,
+ INB (nc_sbcl),
+ INB (nc_sxfer),INB (nc_scr3),
+ dsp = INL (nc_dsp), INL (nc_dbc));
+
+ /*----------------------------------------
+ ** clean up the dma fifo
+ **----------------------------------------
+ */
+
+ if ((INB(nc_sstat0)&(ILF|ORF|OLF)) ||
+ (INB(nc_sstat1)&0xf0) || !(dstat & DFE)) {
+ printf ("ncr%d: have to clear fifos.\n", ncr_unit (np));
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+ OUTB (nc_ctest3, CLF); /* clear dma fifo */
+ }
+
+ /*----------------------------------------
+ ** unexpected disconnect
+ **----------------------------------------
+ */
+
+ if ((sist & UDC) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ OUTB (nc_scr0, HS_UNEXPECTED);
+ OUTL (nc_dsp, vtophys(&np->v_script->cleanup));
+ return;
+ };
+
+ /*----------------------------------------
+ ** cannot disconnect
+ **----------------------------------------
+ */
+
+ if ((dstat & IID) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR)) &&
+ ((INL(nc_dbc) & 0xf8000000) == 0x18000000)) {
+ /*
+ ** Data cycles while waiting for disconnect.
+ ** Force disconnect.
+ */
+ OUTB (nc_scntl1, 0);
+ /*
+ ** System may hang, but timeout will handle that.
+ ** In fact, timeout can handle ALL problems :-)
+ */
+ OUTB (nc_dcntl, (STD|NOCOM));
+ return;
+ };
+
+ /*----------------------------------------
+ ** single step
+ **----------------------------------------
+ */
+
+ if ((dstat & SSI) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ OUTB (nc_dcntl, (STD|NOCOM));
+ return;
+ };
+
+/*
+** @RECOVER@ HTH, SGE, ABRT.
+**
+** We should try to recover from these interrupts.
+** They may occur if there are problems with synch transfers,
+** or if targets are powerswitched while the driver is running.
+*/
+
+ if (sist & SGE) {
+ OUTB (nc_ctest3, CLF); /* clear scsi offsets */
+ }
+
+#ifdef SCSI_NCR_DEBUG
+ /*
+ ** Freeze controller to be able to read the messages.
+ */
+
+ if (ncr_debug & DEBUG_FREEZE) {
+ int i;
+ unsigned char val;
+ for (i=0; i<0x60; i++) {
+ switch (i%16) {
+
+ case 0:
+ printf ("ncr%d: reg[%d0]: ",
+ ncr_unit(np),i/16);
+ break;
+ case 4:
+ case 8:
+ case 12:
+ printf (" ");
+ break;
+ };
+ val = ((unsigned char*) np->vaddr) [i];
+ printf (" %x%x", val/16, val%16);
+ if (i%16==15) printf (".\n");
+ };
+
+ untimeout (TIMEOUT ncr_timeout, (caddr_t) np);
+
+ printf ("ncr%d: halted!\n", ncr_unit(np));
+ /*
+ ** don't restart controller ...
+ */
+ OUTB (nc_istat, SRST);
+ return;
+ };
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** sorry, have to kill ALL jobs ...
+ */
+
+ ncr_init (np, "fatal error", HS_FAIL);
+}
+
+/*==========================================================
+**
+** ncr chip exception handler for selection timeout
+**
+**==========================================================
+**
+** There seems to be a bug in the 53c810.
+** Although a STO-Interupt is pending,
+** it continues executing script commands.
+** But it will fail and interrupt (IID) on
+** the next instruction where it's looking
+** for a valid phase.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_int_sto (ncb_p np)
+{
+ u_long dsa, scratcha, diff;
+ ccb_p cp;
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TINY) printf ("T");
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** look for ccb and set the status.
+ */
+
+ dsa= INL (nc_dsa);
+ cp = &np->ccb;
+ while (cp && (vtophys(&cp->phys)!=dsa)) cp = cp -> link_ccb;
+
+ if (cp) {
+ cp-> host_status = HS_SEL_TIMEOUT;
+ ncr_complete (np, cp);
+ };
+
+ /*
+ ** repair start queue
+ */
+
+ scratcha = INL (nc_scratcha);
+ diff = scratcha-(np->p_script + offsetof (struct script, tryloop));
+
+ assert ((diff <= MAX_START * 20) && !(diff % 20));
+
+ if ((diff <= MAX_START * 20) && !(diff % 20)) {
+ np->v_script->startpos[0] = scratcha;
+ OUTL (nc_dsp, vtophys (&np->v_script->start));
+ return;
+ };
+ ncr_init (np, "selection timeout", HS_FAIL);
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler for phase errors.
+**
+**
+**==========================================================
+**
+** We have to construct a new transfer descriptor,
+** to transfer the rest of the current block.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_int_ma (ncb_p np)
+{
+ u_long dbc;
+ u_long rest;
+ u_long dsa;
+ u_long dsp;
+ u_long nxtdsp;
+ u_long *vdsp;
+ u_long oadr;
+ u_long olen;
+ u_long *tblp;
+ u_long *newcmd;
+ u_char cmd;
+ u_char sbcl;
+ u_char delta;
+ u_char ss0;
+ ccb_p cp,cp2;
+
+ dsp = INL (nc_dsp);
+ dsa = INL (nc_dsa);
+ dbc = INL (nc_dbc);
+ ss0 = INB (nc_sstat0);
+ sbcl= INB (nc_sbcl);
+
+ cmd = dbc >> 24;
+ rest= dbc & 0xffffff;
+ delta=(INB (nc_dfifo) - rest) & 0x7f;
+
+ /*
+ ** The data in the dma fifo has not been transfered to
+ ** the target -> add the amount to the rest ..
+ */
+
+ if (! (INB(nc_dstat) & DFE)) rest += delta;
+ if (ss0 & OLF) rest++;
+ if (ss0 & ORF) rest++;
+
+ /*
+ ** and clear it.
+ */
+
+ OUTB (nc_ctest3, CLF ); /* clear dma fifo */
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+
+ cp2 = np->header.cp;
+
+ cp = &np->ccb;
+ while (cp && (vtophys(&cp->phys)!=dsa)) cp = cp -> link_ccb;
+
+ assert (cp == cp2);
+
+ if (dsp == vtophys (&cp->patch[2])) {
+ vdsp = &cp->patch[0];
+ nxtdsp = vdsp[3];
+ } else if (dsp == vtophys (&cp->patch[6])) {
+ vdsp = &cp->patch[4];
+ nxtdsp = vdsp[3];
+ } else {
+ vdsp = (u_long*) ((char*)np->v_script + dsp - np->p_script -8);
+ nxtdsp = dsp;
+ };
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & (DEBUG_TINY|DEBUG_PHASE)) {
+ printf ("P%d%d ",cmd&7, sbcl&7);
+ printf ("RL=%d D=%d SS0=%x ",rest,delta,ss0);
+ };
+ if (ncr_debug & DEBUG_PHASE) {
+ printf ("\nCP=%x CP2=%x DSP=%x NXT=%x VDSP=%x CMD=%x ",
+ cp, cp2, dsp, nxtdsp, vdsp, cmd);
+ };
+#endif /* SCSI_NCR_DEBUG */
+
+ oadr = vdsp[1];
+
+ if (cmd & 0x10) { /* Table indirect */
+ tblp = (u_long*) ((char*) &cp->phys + oadr);
+ olen = tblp[0];
+ oadr = tblp[1];
+ } else {
+ tblp = (u_long*) 0;
+ olen = vdsp[0] & 0xffffff;
+ };
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_PHASE) {
+ printf ("OCMD=%x\nTBLP=%x OLEN=%x OADR=%x\n",
+ vdsp[0] >> 24, tblp, olen, oadr);
+ };
+#endif /* SCSI_NCR_DEBUG */
+ assert (cmd == (vdsp[0] >> 24));
+
+ if (cmd & 0x06) {
+
+ printf ("ncr%d: targ %d: phase change %d-%d %d@%x resid=%d.\n",
+ ncr_unit (np), INB(nc_ctest0) & 7,
+ cmd&7, sbcl&7, olen, oadr, rest);
+
+ OUTB (nc_dcntl, (STD|NOCOM));
+ return;
+ };
+
+ newcmd = cp->patch;
+ if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4;
+
+ newcmd[0] = ((cmd & 0x0f) << 24) | rest;
+ newcmd[1] = oadr + olen - rest;
+ newcmd[2] = SCR_JUMP;
+ newcmd[3] = nxtdsp;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_PHASE)
+ printf ("ncr%d targ %d: newcmd[%d] %x %x %x %x.\n",
+ ncr_unit (np), INB(nc_ctest0) & 7,
+ newcmd - cp->patch,
+ newcmd[0], newcmd[1], newcmd[2], newcmd[3]);
+#endif /* SCSI_NCR_DEBUG */
+ np->profile.num_break++;
+ OUTL (nc_temp, vtophys (newcmd));
+ OUTL (nc_dsp, vtophys (&np->v_script->dispatch));
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler for programmed interrupts.
+**
+**
+**==========================================================
+*/
+
+static void ncr_show_msg (u_char * msg)
+{
+ u_char i;
+ printf ("%x",*msg);
+ if (*msg==M_EXTENDED) {
+ for (i=1;i<8;i++) {
+ if (i-1>msg[1]) break;
+ printf ("-%x",msg[i]);
+ };
+ } else if ((*msg & 0xf0) == 0x20) {
+ printf ("-%x",msg[1]);
+ }
+}
+
+void ncr_int_sir (ncb_p np)
+{
+ u_char chg, ofs, per, fak;
+ u_char num = INB (nc_dsps);
+ ccb_p cp;
+ tcb_p tp;
+ u_long dsa;
+ u_char target = INB (nc_ctest0) & 7;
+ int i;
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_TINY) printf ("I#%d", num);
+#endif /* SCSI_NCR_DEBUG */
+
+ switch (num) {
+
+/*--------------------------------------------------------------------
+**
+** Processing of interrupted getcc selects
+**
+**--------------------------------------------------------------------
+*/
+
+ case 1: /*
+ ** Script processor is idle.
+ ** Look for interrupted "check cond"
+ */
+
+ printf ("ncr%d: int#%d",ncr_unit (np),num);
+ cp = (ccb_p) 0;
+ for (i=0; i<MAX_TARGET; i++) {
+ printf (" t%d", i);
+ tp = &np->target[i];
+ printf ("+");
+ cp = tp->hold_cp;
+ if (!cp) continue;
+ printf ("+");
+ if ((cp->host_status==HS_BUSY) &&
+ (cp->scsi_status==S_CHECK_COND) &&
+ (cp->scs2_status==S_ILLEGAL))
+ break;
+ printf ("- (remove)");
+ tp->hold_cp = cp = (ccb_p) 0;
+ };
+
+ if (cp) {
+ printf ("+ restart job ..\n");
+ OUTL (nc_dsa, vtophys (&cp->phys));
+ OUTL (nc_dsp, vtophys (&np->v_script->getcc));
+ return;
+ };
+
+ /*
+ ** no job, resume normal processing
+ */
+ printf (" -- remove trap\n");
+ np->v_script->start[0] = SCR_INT ^ IFFALSE (0);
+ break;
+
+ case 2: /*
+ ** While trying to reselect for
+ ** getting the condition code,
+ ** a target reselected us.
+ */
+
+ dsa= INL (nc_dsa);
+ printf ("ncr%d targ %d: in getcc reselect by t%d (dsa=%x).\n",
+ ncr_unit (np), target, INB(nc_ssid)&7, dsa);
+
+ /*
+ ** lookup the ccb
+ */
+ cp = &np->ccb;
+ while (cp && (vtophys(&cp->phys)!=dsa))
+ cp = cp -> link_ccb;
+ assert (cp==np->header.cp);
+
+ /*
+ ** can't happen
+ */
+
+ assert (cp);
+ if (!cp) break;
+
+ /*
+ ** Mark this job
+ */
+ cp->host_status = HS_BUSY;
+ cp->scsi_status = S_CHECK_COND;
+ cp->scs2_status = S_ILLEGAL;
+ np->target[target].hold_cp = cp;
+
+ /*
+ ** And patch code to restart it.
+ */
+ np->v_script->start[0] = SCR_INT;
+ break;
+
+/*--------------------------------------------------------------------
+**
+** Negotiation of synch mode.
+**
+** Possible cases: int msg_in[0] sxfer send goto
+** We try try to negotiate:
+** -> target doesnt't msgin (3) noop ASYNC - -
+** -> target rejected our msg (3) reject ASYNC - -
+** -> target answered (ok) (3) sdtr set - clrack
+** -> target answered (!ok) (3) sdtr ASYNC REJ--->msg_bad
+** -> any other msgin -
+**
+** Target tries to negotiate:
+** -> incoming message (4) sdtr set SDTR -
+** We sent our answer:
+** -> target doesn't msgout (4) reject* ASYNC - -
+** -> target rejected our msg (4) reject ASYNC - -
+** -> target negotiates again (4) sdtr set SDTR -
+**
+**--------------------------------------------------------------------
+*/
+ case 3:
+ case 4:
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SDTR) {
+ printf ("ncr%d targ %d: sync msg in: ",
+ ncr_unit (np), target);
+ ncr_show_msg (np->msgin);
+ printf (".\n");
+ };
+#endif /* SCSI_NCR_DEBUG */
+ /*
+ ** @CHECKOUT@
+ */
+ dsa= INL (nc_dsa);
+ cp = &np->ccb;
+ while (cp && (vtophys(&cp->phys)!=dsa)) cp = cp -> link_ccb;
+ assert (cp==np->header.cp);
+ tp = &np->target[target];
+
+ /*
+ ** any error in negotiation:
+ ** fall back to asynch.
+ */
+
+ if ((np->msgin[0]!=M_EXTENDED) ||
+ (np->msgin[1]!=3) ||
+ (np->msgin[2]!=M_X_SDTR)) {
+ np->msgin [0] = M_NOOP;
+ ncr_setsync (np, cp, 0xe0);
+ break;
+ }
+
+ per = np->msgin[3];
+ ofs = np->msgin[4];
+
+ /*
+ ** if target sends SDTR message,
+ ** it CAN transfer synch.
+ */
+
+ if (ofs)
+ tp->inqdata[7] |= INQ7_SYNC;
+
+ /*------------------------------------------------
+ ** do actual computation.
+ **------------------------------------------------
+ */
+ chg = 0;
+
+ if (ofs==0) per=255;
+ if (per < np->ns_sync) {chg = 1; per = np->ns_sync;}
+ if (per < tp->minsync)
+ {chg = 1; per = tp->minsync;}
+ if (ofs > tp->maxoffs)
+ {chg = 1; ofs = 8;}
+ fak = (4ul * per - 1) / np->ns_sync - 3;
+
+ if (ofs && (fak>7)) {chg = 1; ofs = 0;}
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SDTR)
+ printf ("ncr%d targ %d: sync: per=%d ofs=%d fak=%d chg=%d.\n",
+ ncr_unit (np), target, per, ofs, fak, chg);
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** if the answer had bad values,
+ ** we will use asynch mode.
+ */
+
+ if ((num == 3) && chg) ofs = 0;
+ if (!ofs) fak=7;
+
+ /*
+ ** Set synchronous mode now.
+ */
+ ncr_setsync (np, cp, (fak<<5)|ofs);
+
+ if (num == 3) {
+ if (chg) OUTL (nc_dsp,vtophys (&np->v_script->msg_bad));
+ else OUTL (nc_dsp,vtophys (&np->v_script->clrack));
+ return;
+ };
+
+ /*------------------------------------------------
+ ** prepare an answer message
+ **------------------------------------------------
+ */
+
+ np->msgout[0] = M_EXTENDED;
+ np->msgout[1] = 3;
+ np->msgout[2] = M_X_SDTR;
+ np->msgout[3] = per;
+ np->msgout[4] = ofs;
+
+ np->msgin [0] = M_NOOP;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_SDTR) {
+ printf ("ncr%d targ %d: sync msgout: ",
+ ncr_unit (np), target);
+ ncr_show_msg (np->msgin);
+ printf (".\n");
+ }
+#endif /* SCSI_NCR_DEBUG */
+ break;
+
+
+/*--------------------------------------------------------------------
+**
+** Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+ case 5: /*
+ ** We received a M_REJECT message.
+ */
+ printf ("ncr%d targ %d: M_REJECT received (%x:%x).\n",
+ ncr_unit (np), target, ncr_msgout, np->msgout[0]);
+ break;
+
+ case 6: /*
+ ** We received an unknown message
+ */
+ printf ("ncr%d targ %d: M_REJECT sent for ",
+ ncr_unit (np), target);
+ ncr_show_msg (np->msgin);
+ printf (".\n");
+ break;
+
+/*--------------------------------------------------------------------
+**
+** Processing of a "S_QUEUE_FULL" status.
+**
+** The current command has been rejected.
+** We have started too many commands for that target.
+**
+** If possible, reinsert at head of queue.
+** Stall queue until there are no disconnected jobs
+** (ncr REALLY idle). Then restart processing.
+**
+**--------------------------------------------------------------------
+*/
+ case 8: /*
+ ** Stall the start queue.
+ */
+
+ printf ("ncr%d targ %d: queue full.\n",
+ ncr_unit (np), target);
+ np->v_script->start1[0] = SCR_INT;
+
+ /*
+ ** Try to disable tagged transfers.
+ */
+ ncr_setmaxtags (&np->target[target], 0);
+
+ /*
+ ** @QUEUE@ reinsert current job in queue.
+ */
+
+ /* fall through */
+
+ case 7: /*
+ ** Look for a disconnected job.
+ */
+
+ cp = &np->ccb;
+ while (cp && cp->host_status != HS_DISCONNECT)
+ cp = cp -> link_ccb;
+
+ /*
+ ** if there is one, ...
+ */
+ if (cp) {
+ /*
+ ** wait for reselection
+ */
+ OUTL (nc_dsp,vtophys (&np->v_script->reselect));
+ return;
+ };
+
+ /*
+ ** else remove the interrupt.
+ */
+
+ printf ("ncr%d: queue empty.\n", ncr_unit (np));
+ np->v_script->start1[0] = SCR_INT ^ IFFALSE (0);
+ break;
+
+ };
+ OUTB (nc_dcntl, (STD|NOCOM));
+}
+
+/*==========================================================
+**
+**
+** Aquire a control block
+**
+**
+**==========================================================
+*/
+
+static ccb_p ncr_get_ccb
+ (ncb_p np, u_long flags, u_long target, u_long lun)
+{
+ lcb_p lp;
+ ccb_p cp = (ccb_p ) 0;
+
+ /*
+ ** Lun structure available ?
+ */
+
+ lp = np->target[target].lp[lun];
+ if (lp)
+ cp = lp->next_ccb;
+
+ /*
+ ** Look for free CCB
+ */
+
+ while (cp && cp->magic) cp = cp->next_ccb;
+
+ /*
+ ** if nothing available, take the default.
+ */
+
+ if (!cp) cp = &np->ccb;
+
+ /*
+ ** Wait until available.
+ */
+
+ while (cp->magic) {
+ if (flags & SCSI_NOSLEEP) break;
+ if (tsleep ((caddr_t)cp, PZERO|PCATCH, "ncr", 0))
+ break;
+ };
+
+ if (cp->magic)
+ return ((ccb_p) 0);
+
+ cp->magic = 1;
+ return (cp);
+}
+
+/*==========================================================
+**
+**
+** Release one control block
+**
+**
+**==========================================================
+*/
+
+void ncr_free_ccb (ncb_p np, ccb_p cp, int flags)
+{
+ /*
+ ** sanity
+ */
+
+ if (!cp) return;
+
+ cp -> host_status = HS_IDLE;
+ cp -> magic = 0;
+ if (cp == &np->ccb)
+ wakeup ((caddr_t) cp);
+}
+
+/*==========================================================
+**
+**
+** Allocation of resources for Targets/Luns/Tags.
+**
+**
+**==========================================================
+*/
+
+static void ncr_alloc_ccb (ncb_p np, struct scsi_xfer * xp)
+{
+ tcb_p tp;
+ lcb_p lp;
+ ccb_p cp;
+
+ u_long target;
+ u_long lun;
+
+ if (!np) return;
+ if (!xp) return;
+
+ target = xp->TARGET;
+ lun = xp->LUN;
+
+ if (target>=MAX_TARGET) return;
+ if (lun >=MAX_LUN ) return;
+
+ /*
+ ** target control block ?
+ */
+ tp=&np->target[target];
+
+ if (!tp->jump_tcb.l_cmd) {
+
+ /*
+ ** initialize it.
+ */
+ tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
+ tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
+
+ tp->getscr[0] = SCR_COPY (1);
+ tp->getscr[1] = vtophys (&tp->sval);
+ tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
+
+ assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
+ offsetof(struct tcb , sval )) &3) == 0);
+
+ tp->call_lun.l_cmd = (SCR_CALL);
+ tp->call_lun.l_paddr = vtophys (&np->v_script->resel_lun);
+
+ tp->jump_lcb.l_cmd = (SCR_JUMP);
+ tp->jump_lcb.l_paddr = vtophys (&np->v_script->abort);
+
+ np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
+ }
+
+ /*
+ ** Logic unit control block
+ */
+ lp = tp->lp[lun];
+ if (!lp) {
+ /*
+ ** Allocate a lcb
+ */
+ lp = (lcb_p) malloc (sizeof (struct lcb), M_DEVBUF, M_NOWAIT);
+ if (!lp) return;
+
+ /*
+ ** Initialize it
+ */
+ bzero (lp, sizeof (*lp));
+ lp->jump_lcb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (lun)));
+ lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
+
+ lp->call_tag.l_cmd = (SCR_CALL);
+ lp->call_tag.l_paddr = vtophys (&np->v_script->resel_tag);
+
+ lp->jump_ccb.l_cmd = (SCR_JUMP);
+ lp->jump_ccb.l_paddr = vtophys (&np->v_script->aborttag);
+
+ lp->actlink = 1;
+ /*
+ ** Link into Lun-Chain
+ */
+
+ tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb);
+ tp->lp[lun] = lp;
+
+ }
+
+ /*
+ ** Limit possible number of ccbs.
+ **
+ ** If tagged command queueing is enabled,
+ ** can use more than one ccb.
+ */
+
+ if (np->actccbs >= MAX_START-2) return;
+ if (lp->actccbs && (lp->actccbs >= lp->reqccbs))
+ return;
+
+ /*
+ ** Allocate a ccb
+ */
+ cp = (ccb_p) malloc (sizeof (struct ccb), M_DEVBUF, M_NOWAIT);
+
+ if (!cp)
+ return;
+
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_ALLOC)
+ printf ("ncr%d targ %d lun %d: new ccb @%x.\n",
+ ncr_unit (np), target, lun, cp);
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** Count it
+ */
+ lp->actccbs++;
+ np->actccbs++;
+
+ /*
+ ** Initialize it.
+ */
+ bzero (cp, sizeof (*cp));
+
+ /*
+ ** link in reselect chain.
+ */
+ cp->jump_ccb.l_cmd = SCR_JUMP;
+ cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
+ lp->jump_ccb.l_paddr = vtophys(&cp->jump_ccb);
+ cp->call_tmp.l_cmd = SCR_CALL;
+ cp->call_tmp.l_paddr = vtophys(&np->v_script->resel_tmp);
+
+ /*
+ ** link in wakeup chain
+ */
+ cp->link_ccb = np->ccb.link_ccb;
+ np->ccb.link_ccb = cp;
+
+ /*
+ ** Link into CCB-Chain
+ */
+ cp->next_ccb = lp->next_ccb;
+ lp->next_ccb = cp;
+}
+
+/*==========================================================
+**
+**
+** Announce the number of ccbs/tags to the scsi driver.
+**
+**
+**==========================================================
+*/
+
+static void ncr_opennings (ncb_p np, lcb_p lp, struct scsi_xfer * xp)
+{
+#ifndef ANCIENT
+ /*
+ ** want to reduce the number ...
+ */
+ if (lp->actlink > lp->reqlink) {
+
+ /*
+ ** Try to reduce the count.
+ ** We assumed to run at splbio ..
+ */
+ u_char diff = lp->actlink - lp->reqlink;
+
+ if (!diff) return;
+
+ if (diff > xp->sc_link->opennings)
+ diff = xp->sc_link->opennings;
+
+ /*
+ ** reduce it.
+ */
+
+ xp->sc_link->opennings -= diff;
+ lp->actlink -= diff;
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TAGS)
+ printf ("ncr%d: actlink: diff=%d, new=%d, req=%d\n",
+ ncr_unit(np), diff, lp->actlink, lp->reqlink);
+#endif /* SCSI_NCR_DEBUG */
+ return;
+ };
+
+ /*
+ ** want to increase the number ?
+ */
+ if (lp->reqlink > lp->actlink) {
+ u_char diff = lp->reqlink - lp->actlink;
+
+ xp->sc_link->opennings += diff;
+ lp->actlink += diff;
+ wakeup ((caddr_t) xp->sc_link);
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TAGS)
+ printf ("ncr: actlink: diff=%d, new=%d, req=%d\n",
+ ncr_unit(np), diff, lp->actlink, lp->reqlink);
+#endif
+ };
+#endif
+}
+
+/*==========================================================
+**
+**
+** Build Scatter Gather Block
+**
+**
+**==========================================================
+**
+** The transfer area may be scattered among
+** several non adjacent physical pages.
+**
+** We may use MAX_SCATTER blocks.
+**
+**----------------------------------------------------------
+*/
+
+static u_long ncr_scatter
+ (struct dsb* phys, vm_offset_t vaddr, vm_size_t datalen)
+{
+ u_long paddr, pnext;
+
+ u_short segment = 0;
+ u_long segsize, segaddr;
+ u_long size, csize = 0;
+ u_long chunk = MAX_SIZE;
+ int free;
+
+ bzero (&phys->data, sizeof (phys->data));
+ if (!datalen) return (0);
+
+ paddr = vtophys (vaddr);
+
+ /*
+ ** insert extra break points at a distance of chunk.
+ ** We try to reduce the number of interrupts due to
+ ** unexpected phase changes due to disconnects.
+ ** A typical harddisk may disconnect before ANY block.
+ ** If we want to avoid unexpected phase changes at all
+ ** we have to use a break point every 512 bytes.
+ ** Of course the number of scatter/gather blocks is
+ ** limited.
+ */
+
+ free = MAX_SCATTER - 1;
+
+ if (vaddr & (NBPG-1)) free -= datalen / NBPG;
+
+ if (free>1)
+ while ((chunk * free >= 2 * datalen) && (chunk>=1024))
+ chunk /= 2;
+
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_SCATTER)
+ printf("ncr?:\tscattering virtual=0x%x size=%d chunk=%d.\n",
+ (u_long) vaddr, (u_long) datalen, chunk);
+#endif /* SCSI_NCR_DEBUG */
+
+ /*
+ ** Build data descriptors.
+ */
+ while (datalen && (segment < MAX_SCATTER)) {
+
+ /*
+ ** this segment is empty
+ */
+ segsize = 0;
+ segaddr = paddr;
+ pnext = paddr;
+
+ if (!csize) csize = chunk;
+
+ while ((datalen) && (paddr == pnext) && (csize)) {
+
+ /*
+ ** continue this segment
+ */
+ pnext = (paddr & (~(NBPG - 1))) + NBPG;
+
+ /*
+ ** Compute max size
+ */
+
+ size = pnext - paddr; /* page size */
+ if (size > datalen) size = datalen; /* data size */
+ if (size > csize ) size = csize ; /* chunksize */
+
+ segsize += size;
+ vaddr += size;
+ csize -= size;
+ datalen -= size;
+ paddr = vtophys (vaddr);
+ };
+
+#ifdef SCSI_NCR_DEBUG
+ if(ncr_debug & DEBUG_SCATTER)
+ printf ("\tseg #%d addr=%x size=%d (rest=%d).\n",
+ segment, segaddr, segsize, datalen);
+#endif /* SCSI_NCR_DEBUG */
+
+ phys->data[segment].addr = segaddr;
+ phys->data[segment].size = segsize;
+ segment++;
+ }
+
+ if (datalen)
+ printf("ncr?: scatter/gather failed (residue=%d).\n",
+ datalen);
+
+ return (datalen);
+}
+
+/*==========================================================
+**
+**
+** Profiling the drivers and targets performance.
+**
+**
+**==========================================================
+*/
+
+/*
+** Compute the difference in milliseconds.
+**/
+
+static int ncr_delta (struct timeval * from, struct timeval * to)
+{
+ if (!from->tv_sec) return (-1);
+ if (!to ->tv_sec) return (-2);
+ return ( (to->tv_sec - from->tv_sec - 2)*1000+
+ +(to->tv_usec - from->tv_usec + 2000000)/1000);
+}
+
+#define PROFILE cp->phys.header.stamp
+static void ncb_profile (ncb_p np, ccb_p cp)
+{
+ int co, da, st, en, di, se, post,work,disc;
+ u_long diff;
+
+ PROFILE.end = time;
+
+ st = ncr_delta (&PROFILE.start,&PROFILE.status);
+ if (st<0) return; /* status not reached */
+
+ da = ncr_delta (&PROFILE.start,&PROFILE.data);
+ if (da<0) return; /* No data transfer phase */
+
+ co = ncr_delta (&PROFILE.start,&PROFILE.command);
+ if (co<0) return; /* command not executed */
+
+ en = ncr_delta (&PROFILE.start,&PROFILE.end),
+ di = ncr_delta (&PROFILE.start,&PROFILE.disconnect),
+ se = ncr_delta (&PROFILE.start,&PROFILE.select);
+ post = en - st;
+
+ /*
+ ** @PROFILE@ Disconnect time invalid if multiple disconnects
+ */
+
+ if (di>=0) disc = se-di; else disc = 0;
+
+ work = (st - co) - disc;
+
+ diff = (np->disc_phys - np->disc_ref) & 0xff;
+ np->disc_ref += diff;
+
+ np->profile.num_trans += 1;
+ if (cp->xfer)
+ np->profile.num_bytes += cp->xfer->datalen;
+ np->profile.num_disc += diff;
+ np->profile.ms_setup += co;
+ np->profile.ms_data += work;
+ np->profile.ms_disc += disc;
+ np->profile.ms_post += post;
+}
+#undef PROFILE
+
+/*==========================================================
+**
+** Determine the ncr's clock frequency.
+** This is important for the negotiation
+** of the synchronous transfer rate.
+**
+**==========================================================
+**
+** Note: we have to return the correct value.
+** THERE IS NO SAVE DEFAULT VALUE.
+**
+** We assume that all NCR based boards are delivered
+** with a 40Mhz clock. Because we have to divide
+** by an integer value greater than 3, only clock
+** frequencies of 40Mhz (/4) or 50MHz (/5) permit
+** the FAST-SCSI rate of 10MHz.
+**
+**----------------------------------------------------------
+*/
+
+#ifndef NCR_CLOCK
+# define NCR_CLOCK 40
+#endif /* NCR_CLOCK */
+
+
+static void ncr_getclock (ncb_p np)
+{
+ u_char tbl[5] = {6,2,3,4,6};
+ u_char f;
+ u_char ns_clock = (1000/NCR_CLOCK);
+
+ /*
+ ** Compute the best value for scntl3.
+ */
+
+ f = (2 * MIN_SYNC_PD - 1) / ns_clock;
+ if (!f ) f=1;
+ if (f>4) f=4;
+ np -> ns_sync = (ns_clock * tbl[f]) / 2;
+ np -> rv_scntl3 = f<<4;
+
+ f = (2 * MIN_ASYNC_PD - 1) / ns_clock;
+ if (!f ) f=1;
+ if (f>4) f=4;
+ np -> ns_async = (ns_clock * tbl[f]) / 2;
+ np -> rv_scntl3 |= f;
+#ifdef SCSI_NCR_DEBUG
+ if (ncr_debug & DEBUG_TIMING)
+ printf ("ncr%d: sclk=%d async=%d sync=%d (ns) scntl3=0x%x\n",
+ ncr_unit (np), ns_clock, np->ns_async, np->ns_sync, np->rv_scntl3);
+#endif /* SCSI_NCR_DEBUG */
+}
+
+/*=========================================================================*/
+#endif /* KERNEL */
+#endif /* NNCR */
diff --git a/sys/i386/pci/ncr_reg.h b/sys/i386/pci/ncr_reg.h
new file mode 100644
index 000000000000..917dc14ab097
--- /dev/null
+++ b/sys/i386/pci/ncr_reg.h
@@ -0,0 +1,489 @@
+/**************************************************************************
+**
+** $Id: ncr_reg.h,v 2.0.0.3 94/07/24 08:59:19 wolf Exp $
+**
+** #define the NCR 53 C 810 Register Structure
+** #define the NCR 53 C 810 Scripts Language
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: ncr_reg.h,v $
+** Revision 2.0.0.3 94/07/24 08:59:19 wolf
+** bits of sstat0 defined.
+**
+** Revision 2.0 94/07/10 15:53:27 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:21 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#ifndef __NCR_REG_H__
+#define __NCR_REG_H__
+
+
+/*-----------------------------------------------------------------
+**
+** The ncr 53c810 register structure.
+**
+**-----------------------------------------------------------------
+*/
+
+struct ncr_reg {
+/*00*/ u_char nc_scntl0; /* full arb., ena parity, par->ATN */
+/*01*/ u_char nc_scntl1; /* no reset */
+ #define ISCON 0x10 /* connected to scsi */
+ #define CRST 0x08 /* force reset */
+/*02*/ u_char nc_scntl2; /* no disconnect expected */
+/*03*/ u_char nc_scntl3; /* cnf system clock dependent */
+/*04*/ u_char nc_scid; /* cnf host adapter scsi address */
+ #define RRE 0x40 /* r/w:e enable response to resel. */
+ #define SRE 0x20 /* r/w:e enable response to select */
+/*05*/ u_char nc_sxfer; /* ### Sync speed and count */
+/*06*/ u_char nc_sdid; /* ### Destination-ID */
+/*07*/ u_char nc_gpreg; /* ??? IO-Pins */
+/*08*/ u_char nc_sfbr; /* ### First byte in phase */
+/*09*/ u_char nc_socl;
+ #define CREQ 0x80 /* r/w: SCSI-REQ */
+ #define CACK 0x40 /* r/w: SCSI-ACK */
+ #define CBSY 0x20 /* r/w: SCSI-BSY */
+ #define CSEL 0x10 /* r/w: SCSI-SEL */
+ #define CATN 0x08 /* r/w: SCSI-ATN */
+ #define CMSG 0x04 /* r/w: SCSI-MSG */
+ #define CC_D 0x02 /* r/w: SCSI-C_D */
+ #define CI_O 0x01 /* r/w: SCSI-I_O */
+/*0a*/ u_char nc_ssid;
+/*0b*/ u_char nc_sbcl;
+/*0c*/ u_char nc_dstat;
+ #define DFE 0x80 /* sta: dma fifo empty */
+ #define MDPE 0x40 /* int: master data parity error */
+ #define BF 0x20 /* int: script: bus fault */
+ #define ABRT 0x10 /* int: script: command aborted */
+ #define SSI 0x08 /* int: script: single step */
+ #define SIR 0x04 /* int: script: interrupt instruct. */
+ #define IID 0x01 /* int: script: illegal instruct. */
+/*0d*/ u_char nc_sstat0;
+ #define ILF 0x80 /* sta: data in SIDL register */
+ #define ORF 0x40 /* sta: data in SODR register */
+ #define OLF 0x20 /* sta: data in SODL register */
+ #define AIP 0x10 /* sta: arbitration in progress */
+ #define LOA 0x08 /* sta: arbitration lost */
+ #define WOA 0x04 /* sta: arbitration won */
+ #define IRST 0x02 /* sta: scsi reset signal */
+ #define SDP 0x01 /* sta: scsi parity signal */
+/*0e*/ u_char nc_sstat1;
+/*0f*/ u_char nc_sstat2;
+
+/*10*/ u_long nc_dsa; /* --> Base page */
+/*14*/ u_char nc_istat; /* --> Main Command and status */
+ #define CABRT 0x80 /* cmd: abort current operation */
+ #define SRST 0x40 /* mod: reset chip */
+ #define SIGP 0x20 /* r/w: message from host to ncr */
+ #define SEM 0x10 /* r/w: message between host + ncr */
+ #define CON 0x08 /* sta: connected to scsi */
+ #define INTF 0x04 /* sta: int on the fly (reset by wr)*/
+ #define SIP 0x02 /* sta: scsi-interupt */
+ #define DIP 0x01 /* sta: host/script interupt */
+/*15*/ u_char nc_15_;
+/*16*/ u_char nc_16_;
+/*17*/ u_char nc_17_;
+/*18*/ u_char nc_ctest0;
+/*19*/ u_char nc_ctest1;
+/*1a*/ u_char nc_ctest2;
+ #define CSIGP 0x40
+/*1b*/ u_char nc_ctest3;
+ #define CLF 0x04 /* clear scsi fifo */
+/*1c*/ u_long nc_temp; /* ### Temporary stack */
+/*20*/ u_char nc_dfifo;
+/*21*/ u_char nc_ctest4;
+/*22*/ u_char nc_ctest5;
+/*23*/ u_char nc_ctest6;
+/*24*/ u_long nc_dbc; /* ### Byte count and command */
+/*28*/ u_long nc_dnad; /* ### Next command register */
+/*2c*/ u_long nc_dsp; /* --> Script Pointer */
+/*30*/ u_long nc_dsps; /* --> Script pointer save/opcode#2 */
+/*34*/ u_long nc_scratcha; /* ??? Temporary register a */
+/*38*/ u_char nc_dmode;
+/*39*/ u_char nc_dien;
+/*3a*/ u_char nc_dwt;
+/*3b*/ u_char nc_dcntl; /* --> Script execution control */
+ #define SSM 0x10 /* mod: single step mode */
+ #define STD 0x04 /* cmd: start dma mode */
+ #define NOCOM 0x01 /* cmd: protect sfbr while reselect */
+/*3c*/ u_long nc_adder;
+
+/*40*/ u_short nc_sien; /* -->: interupt enable */
+/*42*/ u_short nc_sist; /* <--: interupt status */
+ #define STO 0x0400/* sta: timeout (select) */
+ #define GEN 0x0200/* sta: timeout (general) */
+ #define HTH 0x0100/* sta: timeout (handshake) */
+ #define MA 0x80 /* sta: phase mismatch */
+ #define CMP 0x40 /* sta: arbitration complete */
+ #define SEL 0x20 /* sta: selected by another device */
+ #define RSL 0x10 /* sta: reselected by another device*/
+ #define SGE 0x08 /* sta: gross error (over/underflow)*/
+ #define UDC 0x04 /* sta: unexpected disconnect */
+ #define RST 0x02 /* sta: scsi bus reset detected */
+ #define PAR 0x01 /* sta: scsi parity error */
+/*44*/ u_char nc_slpar;
+/*45*/ u_char nc_45_;
+/*46*/ u_char nc_macntl;
+/*47*/ u_char nc_gpcntl;
+/*48*/ u_char nc_stime0; /* cmd: timeout for select&handshake*/
+/*49*/ u_char nc_stime1; /* cmd: timeout user defined */
+/*4a*/ u_char nc_respid; /* sta: Reselect-IDs */
+/*4b*/ u_char nc_4b_;
+/*4c*/ u_char nc_stest0;
+/*4d*/ u_char nc_stest1;
+/*4e*/ u_char nc_stest2;
+ #define ROF 0x40 /* reset scsi offset (after gross error!) */
+ #define EXT 0x02 /* extended filtering */
+/*4f*/ u_char nc_stest3;
+ #define TE 0x80 /* c: tolerAnt enable */
+ #define CSF 0x02 /* c: clear scsi fifo */
+/*50*/ u_char nc_sidl; /* Lowlevel: latched from scsi data */
+/*51*/ u_char nc_51_;
+/*52*/ u_char nc_52_;
+/*53*/ u_char nc_53_;
+/*54*/ u_char nc_sodl; /* Lowlevel: data out to scsi data */
+/*55*/ u_char nc_55_;
+/*56*/ u_char nc_56_;
+/*57*/ u_char nc_57_;
+/*58*/ u_char nc_sbdl; /* Lowlevel: data from scsi data */
+/*59*/ u_char nc_59_;
+/*5a*/ u_char nc_5a_;
+/*5b*/ u_char nc_5b_;
+/*5c*/ u_char nc_scr0; /* Working register B */
+/*5d*/ u_char nc_scr1; /* */
+/*5e*/ u_char nc_scr2; /* */
+/*5f*/ u_char nc_scr3; /* */
+/*60*/
+};
+
+/*-----------------------------------------------------------
+**
+** Utility macros for the script.
+**
+**-----------------------------------------------------------
+*/
+
+#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
+#define REG(r) REGJ (nc_, r)
+
+#ifndef TARGET_MODE
+#define TARGET_MODE 0
+#endif
+
+typedef unsigned long ncrcmd;
+
+/*-----------------------------------------------------------
+**
+** SCSI phases
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_DATA_OUT 0x00000000
+#define SCR_DATA_IN 0x01000000
+#define SCR_COMMAND 0x02000000
+#define SCR_STATUS 0x03000000
+#define SCR_ILG_OUT 0x04000000
+#define SCR_ILG_IN 0x05000000
+#define SCR_MSG_OUT 0x06000000
+#define SCR_MSG_IN 0x07000000
+
+/*-----------------------------------------------------------
+**
+** Data transfer via SCSI.
+**
+**-----------------------------------------------------------
+**
+** MOVE_ABS (LEN)
+** <<start address>>
+**
+** MOVE_IND (LEN)
+** <<dnad_offset>>
+**
+** MOVE_TBL
+** <<dnad_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul))
+
+struct scr_tblmove {
+ u_long size;
+ u_long addr;
+};
+
+/*-----------------------------------------------------------
+**
+** Selection
+**
+**-----------------------------------------------------------
+**
+** SEL_ABS | SCR_ID (0..7) [ | REL_JMP]
+** <<alternate_address>>
+**
+** SEL_TBL | << dnad_offset>> [ | REL_JMP]
+** <<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SEL_ABS 0x40000000
+#define SCR_SEL_ABS_ATN 0x41000000
+#define SCR_SEL_TBL 0x42000000
+#define SCR_SEL_TBL_ATN 0x43000000
+
+struct scr_tblsel {
+ u_char sel_0;
+ u_char sel_sxfer;
+ u_char sel_id;
+ u_char sel_scntl3;
+};
+
+#define SCR_JMP_REL 0x04000000
+#define SCR_ID(id) (((u_long)(id)) << 16)
+
+/*-----------------------------------------------------------
+**
+** Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+** WAIT_DISC
+** dummy: <<alternate_address>>
+**
+** WAIT_RESEL
+** <<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_WAIT_DISC 0x48000000
+#define SCR_WAIT_RESEL 0x50000000
+
+/*-----------------------------------------------------------
+**
+** Bit Set / Reset
+**
+**-----------------------------------------------------------
+**
+** SET (flags {|.. })
+**
+** CLR (flags {|.. })
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SET(f) (0x58000000 | (f))
+#define SCR_CLR(f) (0x60000000 | (f))
+
+#define SCR_CARRY 0x00000400
+#define SCR_TRG 0x00000200
+#define SCR_ACK 0x00000040
+#define SCR_ATN 0x00000008
+
+
+
+
+/*-----------------------------------------------------------
+**
+** Memory to memory move
+**
+**-----------------------------------------------------------
+**
+** COPY (bytecount)
+** << source_address >>
+** << destination_address >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_COPY(n) (0xc0000000 | (n))
+
+/*-----------------------------------------------------------
+**
+** Register move and binary operations
+**
+**-----------------------------------------------------------
+**
+** SFBR_REG (reg, op, data) reg = SFBR op data
+** << 0 >>
+**
+** REG_SFBR (reg, op, data) SFBR = reg op data
+** << 0 >>
+**
+** REG_REG (reg, op, data) reg = reg op data
+** << 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SFBR_REG(reg,op,data) \
+ (0x68000000 | (REG(reg) << 16ul) | (op) | ((data)<<8ul))
+
+#define SCR_REG_SFBR(reg,op,data) \
+ (0x70000000 | (REG(reg) << 16ul) | (op) | ((data)<<8ul))
+
+#define SCR_REG_REG(reg,op,data) \
+ (0x78000000 | (REG(reg) << 16ul) | (op) | ((data)<<8ul))
+
+#define SCR_LOAD 0x00000000
+#define SCR_SHL 0x01000000
+#define SCR_OR 0x02000000
+#define SCR_XOR 0x03000000
+#define SCR_AND 0x04000000
+#define SCR_SHR 0x05000000
+#define SCR_ADD 0x06000000
+#define SCR_ADDC 0x07000000
+
+/*-----------------------------------------------------------
+**
+** FROM_REG (reg) reg = SFBR
+** << 0 >>
+**
+** TO_REG (reg) SFBR = reg
+** << 0 >>
+**
+** LOAD_REG (reg, data) reg = <data>
+** << 0 >>
+**
+** LOAD_SFBR(data) SFBR = <data>
+** << 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_FROM_REG(reg) \
+ SCR_REG_SFBR(reg,SCR_OR,0)
+
+#define SCR_TO_REG(reg) \
+ SCR_SFBR_REG(reg,SCR_OR,0)
+
+#define SCR_LOAD_REG(reg,data) \
+ SCR_REG_REG(reg,SCR_LOAD,data)
+
+#define SCR_LOAD_SFBR(data) \
+ (SCR_REG_SFBR (gpreg, SCR_LOAD, data))
+
+/*-----------------------------------------------------------
+**
+** Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+** JUMP [ | IFTRUE/IFFALSE ( ... ) ]
+** <<address>>
+**
+** JUMPR [ | IFTRUE/IFFALSE ( ... ) ]
+** <<distance>>
+**
+** CALL [ | IFTRUE/IFFALSE ( ... ) ]
+** <<address>>
+**
+** CALLR [ | IFTRUE/IFFALSE ( ... ) ]
+** <<distance>>
+**
+** RETURN [ | IFTRUE/IFFALSE ( ... ) ]
+** <<dummy>>
+**
+** INT [ | IFTRUE/IFFALSE ( ... ) ]
+** <<ident>>
+**
+** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ]
+** <<ident>>
+**
+** Conditions:
+** WHEN (phase)
+** IF (phase)
+** CARRY
+** DATA (data, mask)
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_JUMP 0x80080000
+#define SCR_JUMPR 0x80880000
+#define SCR_CALL 0x88080000
+#define SCR_CALLR 0x88880000
+#define SCR_RETURN 0x90080000
+#define SCR_INT 0x98080000
+#define SCR_INT_FLY 0x98180000
+
+#define IFFALSE(arg) (0x00080000 | (arg))
+#define IFTRUE(arg) (0x00000000 | (arg))
+
+#define WHEN(phase) (0x00030000 | (phase))
+#define IF(phase) (0x00020000 | (phase))
+
+#define DATA(D) (0x00040000 | ((D) & 0xff))
+#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
+
+#define CARRYSET (0x00200000)
+
+/*-----------------------------------------------------------
+**
+** SCSI constants.
+**
+**-----------------------------------------------------------
+*/
+
+/*
+** Messages
+*/
+
+#define M_COMPLETE (0x00)
+#define M_EXTENDED (0x01)
+#define M_SAVE_DP (0x02)
+#define M_RESTORE_DP (0x03)
+#define M_DISCONNECT (0x04)
+#define M_ID_ERROR (0x05)
+#define M_ABORT (0x06)
+#define M_REJECT (0x07)
+#define M_NOOP (0x08)
+#define M_PARITY (0x09)
+#define M_LCOMPLETE (0x0a)
+#define M_FCOMPLETE (0x0b)
+#define M_RESET (0x0c)
+#define M_ABORT_TAG (0x0d)
+#define M_CLEAR_QUEUE (0x0e)
+#define M_INIT_REC (0x0f)
+#define M_REL_REC (0x10)
+#define M_TERMINATE (0x11)
+#define M_SIMPLE_TAG (0x20)
+#define M_HEAD_TAG (0x21)
+#define M_ORDERED_TAG (0x22)
+#define M_IDENTIFY (0x80)
+
+#define M_X_SDTR (0x01)
+
+/*
+** Status
+*/
+
+#define S_GOOD (0x00)
+#define S_CHECK_COND (0x02)
+#define S_COND_MET (0x04)
+#define S_BUSY (0x08)
+#define S_INT (0x10)
+#define S_INT_COND_MET (0x14)
+#define S_CONFLICT (0x18)
+#define S_TERMINATED (0x20)
+#define S_QUEUE_FULL (0x28)
+#define S_ILLEGAL (0xff)
+
+#endif /*__NCR_REG_H__*/
diff --git a/sys/i386/pci/pci.c b/sys/i386/pci/pci.c
new file mode 100644
index 000000000000..878c97c68165
--- /dev/null
+++ b/sys/i386/pci/pci.c
@@ -0,0 +1,494 @@
+/**************************************************************************
+**
+** $Id: pci.c,v 2.0.0.1 94/07/19 19:06:44 wolf Exp $
+**
+** General subroutines for the PCI bus on 80*86 systems.
+** pci_configure ()
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pci.c,v $
+** Revision 2.0.0.1 94/07/19 19:06:44 wolf
+** New vendor entry: MATROX
+**
+** Revision 2.0 94/07/10 15:53:29 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:19 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#include <pci.h>
+#if NPCI > 0
+
+/*========================================================
+**
+** Configuration
+**
+**========================================================
+*/
+
+/*
+** maximum number of devices which share one interrupt line
+*/
+
+#define PCI_MAX_DPI 1
+
+/*
+** there may be up to 255 busses on pci.
+** don't probe them all :-)
+*/
+
+#define FIRST_BUS 0
+#define LAST_BUS 0
+
+/*
+** there may be up to 32 devices per bus.
+** do probe them all ;-)
+*/
+
+#define FIRST_DEVICE 0
+#define LAST_DEVICE 31
+
+/*========================================================
+**
+** #includes and declarations
+**
+**========================================================
+*/
+
+#include <types.h>
+#include <cdefs.h>
+#include <errno.h>
+#include <param.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <i386/isa/icu.h>
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+
+#include <i386/pci/pci.h>
+#include <i386/pci/pci_device.h>
+#include <i386/pci/pcibios.h>
+
+
+static char ident[] =
+ "\n$Id: pci.c,v 2.0.0.1 94/07/19 19:06:44 wolf Exp $\n"
+ "Copyright (c) 1994, Wolfgang Stanglmeier\n";
+
+/*
+** Function prototypes missing in system headers
+*/
+
+extern int printf();
+extern int ffs();
+extern pmap_t pmap_kernel(void);
+
+/*
+** function prototypes
+*/
+
+int pci_map_mem
+ (pcici_t tag, u_long reg, u_long *va, vm_offset_t *pa);
+int pci_map_port (pcici_t tag, u_long reg, u_short* pa);
+void pci_configure (void);
+
+/*========================================================
+**
+** Autoconfiguration (of isa bus) (Free/386)
+**
+**========================================================
+*/
+
+/*
+** per device (interrupt) data structure.
+*/
+
+static struct {
+ u_short number;
+ u_short isanum;
+ struct {
+ int (*proc)(int dev);
+ dev_t unit;
+ } vector[PCI_MAX_DPI];
+} pcidata [NPCI];
+
+#ifndef __NetBSD__
+
+/*
+** check device ready
+*/
+static int pciprobe (struct isa_device *dev)
+{
+ if (dev->id_unit >= NPCI)
+ return (0);
+
+ if (!pci_conf_mode())
+ return (0);
+
+ return (1);
+}
+
+/*
+** initialize the driver structure
+*/
+static int pciattach (struct isa_device *isdp)
+{
+ pcidata[isdp->id_unit].number = 0;
+ pcidata[isdp->id_unit].isanum = ffs(isdp->id_irq)-1;
+ return (1);
+}
+
+/*
+** ISA driver structure
+*/
+
+struct isa_driver pcidriver = {
+ pciprobe,
+ pciattach,
+ "pci"
+};
+
+/*========================================================
+**
+** Interrupt forward from isa to pci devices.
+**
+**========================================================
+*/
+
+
+void pciintr (int unit)
+{
+ u_short i;
+ if (unit >= NPCI) return;
+
+#if defined (GENERICAH) || defined (GENERICBT) || defined (GENERICNCR) \
+ || defined (GENERICAHA) || defined (GENERICISA)
+ for (unit=0; unit < NPCI; unit++)
+#endif
+
+ for (i=0; i<pcidata[unit].number; i++) {
+ (void)(*pcidata[unit].vector[i].proc)(pcidata[unit].vector[i].unit);
+ };
+}
+
+#endif /* __NetBSD__ */
+
+/*========================================================
+**
+** Autoconfiguration of pci devices.
+**
+** This is reverse to the isa configuration.
+** (1) find a pci device.
+** (2) look for a driver.
+**
+**========================================================
+*/
+
+/*--------------------------------------------------------
+**
+** The pci devices can be mapped to any address.
+** As default we start at the last gigabyte.
+**
+**--------------------------------------------------------
+*/
+
+#ifndef PCI_PMEM_START
+#define PCI_PMEM_START 0xc0000000
+#endif
+
+static vm_offset_t pci_paddr = PCI_PMEM_START;
+
+/*---------------------------------------------------------
+**
+** pci_configure ()
+**
+**---------------------------------------------------------
+*/
+
+void pci_configure()
+{
+ u_char bus, device, reg;
+ pcici_t tag;
+ pcidi_t type;
+ u_long data;
+ int unit;
+ int intpin;
+ int pci_mode;
+
+ struct pci_driver *drp;
+ struct pci_device *dvp;
+
+ /*
+ ** check pci bus present
+ */
+
+ pci_mode = pci_conf_mode ();
+ if (!pci_mode) return;
+
+ /*
+ ** hello world ..
+ */
+
+ printf ("PCI configuration mode %d.\n", pci_mode);
+
+ for (bus=FIRST_BUS;bus<=LAST_BUS; bus++)
+ for (device=FIRST_DEVICE; device<=LAST_DEVICE; device ++) {
+ tag = pcitag (bus, device, 0);
+ type = pci_conf_read (tag, 0);
+
+ if ((!type) || (type==0xfffffffful)) continue;
+ printf ("on pci%d:%d ", bus, device);
+
+ /*
+ ** lookup device in ioconfiguration:
+ */
+
+ for (dvp = pci_devtab; drp=dvp->pd_driver; dvp++) {
+ if (drp->device_id == type) break;
+ };
+
+ if (!drp) {
+
+ /*
+ ** not found
+ */
+
+ switch (type & 0xffff) {
+
+ case 0x1002:
+ printf ("ATI TECHNOLOGIES INC");
+ break;
+ case 0x101A:
+ printf ("NCR");
+ break;
+ case 0x102B:
+ printf ("MATROX");
+ break;
+ case 0x1045:
+ printf ("OPTI");
+ break;
+ case 0x8086:
+ printf ("INTEL CORPORATION");
+ break;
+
+ default:
+ printf ("vendor=%x", type & 0xffff);
+ };
+
+ switch (type) {
+
+ case 0x04848086:
+ printf (" 82378IB pci-isa bridge");
+ break;
+ case 0x04838086:
+ printf (" 82424ZX cache dram controller");
+ break;
+ case 0x04828086:
+ printf (" 82375EB pci-eisa bridge");
+ break;
+ case 0x04A38086:
+ printf (" 82434LX pci cache memory controller");
+ break;
+ default:
+ printf (", device=%x", type >> 16);
+ };
+ printf (" [not supported]\n");
+
+ for (reg=0x10; reg<=0x20; reg+=4) {
+ data = pci_conf_read (tag, reg);
+ if (!data) continue;
+ switch (data&7) {
+
+ case 1:
+ case 5:
+ printf (" map(%x): io(%x)\n",
+ reg, data & ~3);
+ break;
+ case 0:
+ printf (" map(%x): mem32(%x)\n",
+ reg, data & ~7);
+ break;
+ case 2:
+ printf (" map(%x): mem20(%x)\n",
+ reg, data & ~7);
+ break;
+ case 4:
+ printf (" map(%x): mem64(%x)\n",
+ reg, data & ~7);
+ break;
+ };
+ };
+ continue;
+ };
+
+ /*
+ ** found it.
+ ** probe returns the device unit.
+ */
+
+ printf ("<%s>", drp -> vendor);
+
+ unit = (*drp->probe) (tag);
+
+ if (unit<0) {
+ printf (" probe failed.\n");
+ continue;
+ };
+
+ /*
+ ** install interrupts
+ */
+
+ intpin = (pci_conf_read (tag, 0x3c) >> 8) & 0xff;
+ if (intpin) {
+ printf (" irq %c", 0x60+intpin);
+ intpin--;
+ if (intpin < NPCI) {
+ u_short entry = pcidata[intpin].number;
+ if (entry < PCI_MAX_DPI) {
+ pcidata[intpin].vector[entry].proc = drp->intr;
+ pcidata[intpin].vector[entry].unit = unit;
+ entry++;
+ };
+ printf (" isa=%d [%d]",pcidata[intpin].isanum, entry);
+ pcidata[intpin].number=entry;
+ } else printf (" not installed");
+ };
+
+ /*
+ ** enable memory access
+ */
+ data = pci_conf_read (tag, 0x04) & 0xffff | 0x0002;
+ pci_conf_write (tag, (u_char) 0x04, data);
+
+ /*
+ ** attach device
+ ** may produce additional log messages,
+ ** i.e. when installing subdevices.
+ */
+
+ printf (" as %s%d\n", drp->name,unit);
+ (void) (*drp->attach) (tag);
+
+ };
+
+ printf ("pci uses physical addresses from %x to %x\n",
+ PCI_PMEM_START, pci_paddr);
+}
+
+/*-----------------------------------------------------------------------
+**
+** Map device into virtual and physical space
+**
+**-----------------------------------------------------------------------
+*/
+
+extern vm_map_t kernel_map;
+
+int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
+{
+ /*
+ ** @MAPIO@ not yet implemented.
+ */
+ return (ENOSYS);
+}
+
+
+int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
+{
+ u_long data, result;
+ vm_size_t vsize;
+ vm_offset_t vaddr;
+
+ /*
+ ** sanity check
+ */
+
+ if (reg <= 0x10 || reg >= 0x20 || (reg & 3))
+ return (EINVAL);
+
+ /*
+ ** get size and type of memory
+ */
+
+ pci_conf_write (tag, reg, 0xfffffffful);
+ data = pci_conf_read (tag, reg);
+
+ switch (data & 0x0f) {
+
+ case 0x0: /* 32 bit non cachable */
+ break;
+
+ default: /* unknown */
+ return (EINVAL);
+ };
+
+ vsize = round_page (-(data & 0xfffffff0));
+
+ printf (" memory size=0x%x", vsize);
+
+ if (!vsize) return (EINVAL);
+
+ /*
+ ** try to map device to virtual space
+ */
+
+ vaddr = vm_map_min (kernel_map);
+
+ result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
+ &vaddr, vsize, TRUE);
+
+ if (result != KERN_SUCCESS) {
+ printf (" vm_map_find failed(%d)\n", result);
+ return (ENOMEM);
+ };
+
+ /*
+ ** align physical address to virtual size
+ */
+
+ if (data = pci_paddr % vsize)
+ pci_paddr += vsize - data;
+
+ /*
+ ** display values.
+ */
+
+ printf (" virtual=0x%x physical=0x%x\n", vaddr, pci_paddr);
+
+ *va = vaddr;
+ *pa = pci_paddr;
+
+ /*
+ ** set device address
+ */
+
+ pci_conf_write (tag, reg, pci_paddr);
+
+ /*
+ ** map physical
+ */
+
+ while (vsize >= NBPG) {
+ pmap_enter (pmap_kernel(), vaddr, pci_paddr,
+ VM_PROT_READ|VM_PROT_WRITE, TRUE);
+ vaddr += NBPG;
+ pci_paddr += NBPG;
+ vsize -= NBPG;
+ };
+
+ return (0);
+}
+#endif
diff --git a/sys/i386/pci/pci.h b/sys/i386/pci/pci.h
new file mode 100644
index 000000000000..703144d1eb8f
--- /dev/null
+++ b/sys/i386/pci/pci.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+**
+** $Id: pci.h,v 2.0 94/07/10 15:53:30 wolf Rel $
+**
+** #define for pci bus device drivers
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pci.h,v $
+** Revision 2.0 94/07/10 15:53:30 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:21 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#ifndef __PCI_H__
+#define __PCI_H__
+
+/*
+** main pci initialization function.
+** called at boot time from autoconf.c
+*/
+
+void pci_configure(void);
+
+/*
+** pci configuration id
+**
+** is constructed from: bus, device & function numbers.
+*/
+
+typedef union {
+ u_long cfg1;
+ struct {
+ u_char enable;
+ u_char forward;
+ u_short port;
+ } cfg2;
+ } pcici_t;
+
+/*
+** Each pci device has an unique device id.
+** It is used to find a matching driver.
+*/
+
+typedef u_long pcidi_t;
+
+#endif /*__PCI_H__*/
diff --git a/sys/i386/pci/pci_config.c b/sys/i386/pci/pci_config.c
new file mode 100644
index 000000000000..d1e2332191f2
--- /dev/null
+++ b/sys/i386/pci/pci_config.c
@@ -0,0 +1,45 @@
+/**************************************************************************
+**
+** $Id: pci_config.c,v 2.0 94/07/10 15:53:30 wolf Rel $
+**
+** @PCI@ this should be part of "ioconf.c".
+**
+** The config-utility should build it!
+** When struct pci_driver has become stable
+** I'll extend the config utility.
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pci_config.c,v $
+** Revision 2.0 94/07/10 15:53:30 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:04:37 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#include "types.h"
+#include "i386/pci/pci.h"
+#include "i386/pci/pci_device.h"
+
+#include "ncr.h"
+#if NNCR>0
+extern struct pci_driver ncrdevice;
+#endif
+
+struct pci_device pci_devtab[] = {
+
+#if NNCR>0
+ {&ncrdevice},
+#endif
+ {0}
+};
diff --git a/sys/i386/pci/pci_device.h b/sys/i386/pci/pci_device.h
new file mode 100644
index 000000000000..5fc33216a5a5
--- /dev/null
+++ b/sys/i386/pci/pci_device.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** $Id: pci_device.h,v 2.0 94/07/10 15:53:31 wolf Rel $
+**
+** #define for pci based device drivers
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pci_device.h,v $
+** Revision 2.0 94/07/10 15:53:31 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:22 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#ifndef __PCI_DEVICE_H__
+#define __PCI_DEVICE_H__
+
+/*------------------------------------------------------------
+**
+** Per driver structure.
+**
+**------------------------------------------------------------
+*/
+
+struct pci_driver {
+ int (*probe )(pcici_t pci_ident); /* test whether device is present */
+ int (*attach)(pcici_t pci_ident); /* setup driver for a device */
+ pcidi_t device_id; /* device pci id */
+ char *name; /* device name */
+ char *vendor; /* device long name */
+ int (*intr)(int); /* interupt handler */
+};
+
+/*-----------------------------------------------------------
+**
+** Per device structure.
+**
+** It is initialized by the config utility and should live in
+** "ioconf.c". At the moment there is only one field.
+**
+** This is a first attempt to include the pci bus to 386bsd.
+** So this structure may grow ..
+**
+**-----------------------------------------------------------
+*/
+
+struct pci_device {
+ struct pci_driver * pd_driver;
+};
+
+/*-----------------------------------------------------------
+**
+** This table should be generated in file "ioconf.c"
+** by the config program.
+** It is used at boot time by the configuration function
+** pci_configure()
+**
+**-----------------------------------------------------------
+*/
+
+extern struct pci_device pci_devtab[];
+
+/*-----------------------------------------------------------
+**
+** This functions may be used by drivers to map devices
+** to virtual and physical addresses. The va and pa
+** addresses are "in/out" parameters. If they are 0
+** on entry, the mapping function assigns an address.
+**
+**-----------------------------------------------------------
+*/
+
+int pci_map_mem (pcici_t tag, u_long entry, u_long * va, u_long * pa);
+
+int pci_map_port(pcici_t tag, u_long entry, u_short * pa);
+
+#endif /*__PCI_DEVICE_H__*/
diff --git a/sys/i386/pci/pcibios.c b/sys/i386/pci/pcibios.c
new file mode 100644
index 000000000000..049d6e77a057
--- /dev/null
+++ b/sys/i386/pci/pcibios.c
@@ -0,0 +1,261 @@
+/**************************************************************************
+**
+** $Id: pcibios.c,v 2.0 94/07/10 15:53:31 wolf Rel $
+**
+** #define for pci-bus bios functions.
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pcibios.c,v $
+** Revision 2.0 94/07/10 15:53:31 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:20 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+
+#include "types.h"
+#include "i386/isa/isa.h"
+#include "i386/pci/pci.h"
+#include "i386/pci/pcibios.h"
+
+
+extern int printf();
+
+static char pci_mode;
+
+static char ident[] =
+ "\n$Id: pcibios.c,v 2.0 94/07/10 15:53:31 wolf Rel $\n"
+ "Copyright (c) 1994, Wolfgang Stanglmeier\n";
+
+
+/*--------------------------------------------------------------------
+**
+** Port access
+**
+**--------------------------------------------------------------------
+**
+** @FREEBSD@ inl() and outl() functions are not defined
+*/
+
+#define DIRTY
+
+#ifdef DIRTY
+
+#undef inl
+#define inl(port) \
+({ u_long data; \
+ __asm __volatile("inl %1, %0": "=a" (data): "d" ((u_short)(port))); \
+ data; })
+
+
+#undef outl
+#define outl(port, data) \
+{__asm __volatile("outl %0, %1"::"a" ((u_long)(data)), "d" ((u_short)(port)));}
+
+
+#undef inb
+#define inb(port) \
+({ u_char data; \
+ __asm __volatile("inb %1, %0": "=a" (data): "d" ((u_short)(port))); \
+ data; })
+
+
+#undef outb
+#define outb(port, data) \
+{__asm __volatile("outb %0, %1"::"a" ((u_char)(data)), "d" ((u_short)(port)));}
+
+#endif
+
+/*--------------------------------------------------------------------
+**
+** Determine configuration mode
+**
+**--------------------------------------------------------------------
+*/
+
+
+#define CONF1_ENABLE 0x80000000ul
+#define CONF1_ADDR_PORT 0x0cf8
+#define CONF1_DATA_PORT 0x0cfc
+
+
+#define CONF2_ENABLE_PORT 0x0cf8
+#define CONF2_FORWARD_PORT 0x0cfa
+
+
+int pci_conf_mode (void)
+{
+ u_long result, oldval;
+
+ /*---------------------------------------
+ ** Configuration mode 1 ?
+ **---------------------------------------
+ */
+
+ oldval = inl (CONF1_ADDR_PORT);
+ outl (CONF1_ADDR_PORT, CONF1_ENABLE);
+ result = inl (CONF1_ADDR_PORT);
+ outl (CONF1_ADDR_PORT, oldval);
+
+ if (result == CONF1_ENABLE) {
+ pci_mode = 1;
+ return (1);
+ };
+
+ /*---------------------------------------
+ ** Configuration mode 2 ?
+ **---------------------------------------
+ */
+
+ outb (CONF2_ENABLE_PORT, 0);
+ outb (CONF2_FORWARD_PORT, 0);
+ if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) {
+ pci_mode = 2;
+ return (2);
+ };
+
+ /*---------------------------------------
+ ** No PCI bus available.
+ **---------------------------------------
+ */
+ return (0);
+}
+
+/*--------------------------------------------------------------------
+**
+** Build a pcitag from bus, device and function number
+**
+**--------------------------------------------------------------------
+*/
+
+
+pcici_t pcitag (unsigned char bus,
+ unsigned char device,
+ unsigned char func)
+{
+ pcici_t tag;
+
+ tag.cfg1 = 0;
+ if (device >= 32) return tag;
+ if (func >= 8) return tag;
+
+ switch (pci_mode) {
+
+ case 1:
+ tag.cfg1 = CONF1_ENABLE
+ | (((u_long) bus ) << 16ul)
+ | (((u_long) device) << 11ul)
+ | (((u_long) func ) << 8ul);
+ break;
+ case 2:
+ if (device >= 16) break;
+ tag.cfg2.port = 0xc000 | (device << 8ul);
+ tag.cfg2.enable = 0xf1 | (func << 1ul);
+ tag.cfg2.forward = bus;
+ break;
+ };
+ return tag;
+}
+
+/*--------------------------------------------------------------------
+**
+** Read register from configuration space.
+**
+**--------------------------------------------------------------------
+*/
+
+
+u_long pci_conf_read (pcici_t tag, u_long reg)
+{
+ u_long addr, data = 0;
+
+ if (!tag.cfg1) return (0xfffffffful);
+
+ switch (pci_mode) {
+
+ case 1:
+ addr = tag.cfg1 | reg & 0xfc;
+#ifdef PCI_DEBUG
+ printf ("pci_conf_read(1): addr=%x ", addr);
+#endif
+ outl (CONF1_ADDR_PORT, addr);
+ data = inl (CONF1_DATA_PORT);
+ outl (CONF1_ADDR_PORT, 0 );
+ break;
+
+ case 2:
+ addr = tag.cfg2.port | reg & 0xfc;
+#ifdef PCI_DEBUG
+ printf ("pci_conf_read(2): addr=%x ", addr);
+#endif
+ outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
+ outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
+
+ data = inl ((u_short) addr);
+
+ outb (CONF2_ENABLE_PORT, 0);
+ outb (CONF2_FORWARD_PORT, 0);
+ break;
+ };
+
+#ifdef PCI_DEBUG
+ printf ("data=%x\n", data);
+#endif
+
+ return (data);
+}
+
+/*--------------------------------------------------------------------
+**
+** Write register into configuration space.
+**
+**--------------------------------------------------------------------
+*/
+
+
+void pci_conf_write (pcici_t tag, u_long reg, u_long data)
+{
+ u_long addr;
+
+ if (!tag.cfg1) return;
+
+ switch (pci_mode) {
+
+ case 1:
+ addr = tag.cfg1 | reg & 0xfc;
+#ifdef PCI_DEBUG
+ printf ("pci_conf_write(1): addr=%x data=%x\n",
+ addr, data);
+#endif
+ outl (CONF1_ADDR_PORT, addr);
+ outl (CONF1_DATA_PORT, data);
+ outl (CONF1_ADDR_PORT, 0 );
+ break;
+
+ case 2:
+ addr = tag.cfg2.port | reg & 0xfc;
+#ifdef PCI_DEBUG
+ printf ("pci_conf_write(2): addr=%x data=%x\n",
+ addr, data);
+#endif
+ outb (CONF2_ENABLE_PORT, tag.cfg2.enable);
+ outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
+
+ outl ((u_short) addr, data);
+
+ outb (CONF2_ENABLE_PORT, 0);
+ outb (CONF2_FORWARD_PORT, 0);
+ break;
+ };
+}
diff --git a/sys/i386/pci/pcibios.h b/sys/i386/pci/pcibios.h
new file mode 100644
index 000000000000..5e82d2f27b34
--- /dev/null
+++ b/sys/i386/pci/pcibios.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+**
+** $Id: pcibios.h,v 2.0 94/07/10 15:53:32 wolf Rel $
+**
+** #define for pci-bus bios functions.
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany
+** <wolf@dentaro.GUN.de>
+**
+** This is a beta version - use with care.
+**
+**-------------------------------------------------------------------------
+**
+** $Log: pcibios.h,v $
+** Revision 2.0 94/07/10 15:53:32 wolf
+** FreeBSD release.
+**
+** Revision 1.0 94/06/07 20:02:23 wolf
+** Beta release.
+**
+***************************************************************************
+*/
+
+#ifndef __PCIBIOS_H__
+#define __PCIBIOS_H__
+
+/*
+** the availability of a pci bus.
+** configuration mode (1 or 2)
+** 0 if no pci bus found.
+*/
+
+int pci_conf_mode (void);
+
+/*
+** get a "ticket" for accessing a pci device
+** configuration space.
+*/
+
+pcici_t pcitag (unsigned char bus,
+ unsigned char device,
+ unsigned char func);
+
+/*
+** read or write the configuration space.
+*/
+
+u_long pci_conf_read (pcici_t tag, u_long reg );
+void pci_conf_write (pcici_t tag, u_long reg, u_long data);
+
+#endif
diff --git a/sys/isofs/isofs_rrip.c b/sys/isofs/isofs_rrip.c
index 2ed6d50bc297..5568f024e566 100644
--- a/sys/isofs/isofs_rrip.c
+++ b/sys/isofs/isofs_rrip.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: isofs_rrip.c,v 1.5 1993/12/19 00:51:05 wollman Exp $
+ * $Id: isofs_rrip.c,v 1.6 1994/06/13 20:19:35 jkh Exp $
*/
#include "param.h"
@@ -193,7 +193,8 @@ struct timeval *pu;
if (year < 0) {
crtime = 0;
} else {
- int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+ static int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+
days = year * 365;
if (year > 2)
days += (year+2) / 4;
@@ -211,7 +212,7 @@ struct timeval *pu;
/* timezone offset is unreliable on some disks */
if (-48 <= tz && tz <= 52)
- crtime += tz * 15 * 60;
+ crtime -= tz * 15 * 60;
}
pu->tv_sec = crtime;
pu->tv_usec = 0;
diff --git a/sys/isofs/isofs_vfsops.c b/sys/isofs/isofs_vfsops.c
index 77bf963fb34b..bc9b337b87e8 100644
--- a/sys/isofs/isofs_vfsops.c
+++ b/sys/isofs/isofs_vfsops.c
@@ -1,5 +1,5 @@
/*
- * $Id: isofs_vfsops.c,v 1.5 1993/12/19 00:51:07 wollman Exp $
+ * $Id: isofs_vfsops.c,v 1.6 1994/06/02 06:48:34 swallace Exp $
*/
#include "param.h"
@@ -521,7 +521,7 @@ isofs_fhtovp(mp, fhp, vpp)
return (EINVAL);
if (ifhp->ifid_offset + sizeof (struct iso_directory_record)
- >= imp->im_bsize)
+ > imp->im_bsize)
return (EINVAL);
if (error = bread (imp->im_devvp,
@@ -534,7 +534,7 @@ isofs_fhtovp(mp, fhp, vpp)
dirp = (struct iso_directory_record *)
(bp->b_un.b_addr + ifhp->ifid_offset);
- if (ifhp->ifid_offset + isonum_711 (dirp->length) >= imp->im_bsize) {
+ if (ifhp->ifid_offset + isonum_711 (dirp->length) > imp->im_bsize) {
brelse (bp);
return (EINVAL);
}
diff --git a/sys/isofs/isofs_vnops.c b/sys/isofs/isofs_vnops.c
index b3034881b8d2..bcb5e99e6c00 100644
--- a/sys/isofs/isofs_vnops.c
+++ b/sys/isofs/isofs_vnops.c
@@ -1,5 +1,5 @@
/*
- * $Id: isofs_vnops.c,v 1.4 1993/12/19 00:51:08 wollman Exp $
+ * $Id: isofs_vnops.c,v 1.6 1994/06/12 04:05:29 davidg Exp $
*/
#include "param.h"
#include "systm.h"
@@ -82,10 +82,13 @@ isofs_getattr(vp, vap, cred, p)
vap->va_fsid = ip->i_dev;
vap->va_fileid = ip->i_number;
- if (vp->v_type == VDIR)
- vap->va_nlink = 2;
- else
- vap->va_nlink = 1;
+ /*
+ * This should be set properly if a RR filesystem, but this is
+ * the safest value for now. Note that previously this was conditionally
+ * set to 2 if the file is a directory, but this causes problems
+ * with find.
+ */
+ vap->va_nlink = 1;
vap->va_mode = ip->inode.iso_mode;
vap->va_uid = ip->inode.iso_uid;
@@ -162,8 +165,6 @@ isofs_read(vp, uio, ioflag, cred)
}
error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
- if (n + on == imp->im_bsize || uio->uio_offset == ip->i_size)
- bp->b_flags |= B_AGE;
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
return (error);
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
index 8bfb19cfe28d..8837764c2735 100644
--- a/sys/kern/imgact_aout.c
+++ b/sys/kern/imgact_aout.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: imgact_aout.c,v 1.3 1993/12/30 01:39:29 davidg Exp $
+ * $Id: imgact_aout.c,v 1.4 1994/03/17 22:21:02 davidg Exp $
*/
#include "param.h"
@@ -151,9 +151,7 @@ exec_aout_imgact(iparams)
&vmaddr,
a_out->a_data,
VM_PROT_READ | VM_PROT_WRITE | (a_out->a_text ? 0 : VM_PROT_EXECUTE),
- VM_PROT_READ | VM_PROT_WRITE | (a_out->a_text ? 0 : VM_PROT_EXECUTE),
- MAP_FILE | MAP_PRIVATE | MAP_FIXED,
- iparams->vnodep,
+ VM_PROT_ALL, MAP_FILE | MAP_PRIVATE | MAP_FIXED, iparams->vnodep,
file_offset + a_out->a_text);
if (error)
return (error);
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index ce2f1bf8065f..9624bb3482b3 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)init_main.c 7.41 (Berkeley) 5/15/91
- * $Id: init_main.c,v 1.14 1994/01/14 16:24:45 davidg Exp $
+ * $Id: init_main.c,v 1.18 1994/06/16 02:55:28 davidg Exp $
*/
#include "param.h"
@@ -77,7 +77,7 @@ struct filedesc0 filedesc0;
struct plimit limit0;
struct vmspace vmspace0;
struct proc *curproc = &proc0;
-struct proc *initproc, *pageproc;
+struct proc *initproc, *pageproc, *pagescanproc, *updateproc;
int cmask = CMASK;
extern struct user *proc0paddr;
@@ -86,8 +86,6 @@ extern int (*mountroot)();
struct vnode *rootvp, *swapdev_vp;
int boothowto;
-struct proc *updateproc;
-
#if __GNUC__ >= 2
void __main() {}
#endif
@@ -96,6 +94,10 @@ void __main() {}
* This table is filled in by the linker with functions that need to be
* called to initialize various pseudo-devices and whatnot.
*/
+
+static void dummyinit() {}
+TEXT_SET(pseudo_set, dummyinit);
+
typedef void (*pseudo_func_t)(void);
extern const struct linker_set pseudo_set;
static const pseudo_func_t *pseudos =
@@ -351,7 +353,7 @@ main()
* Start up pageout daemon (process 2).
*/
if (fork(p, (void *) NULL, rval))
- panic("fork pager");
+ panic("failed fork pageout daemon");
if (rval[1]) {
/*
* Now in process 2.
@@ -364,11 +366,28 @@ main()
/*NOTREACHED*/
}
+#if 0
+ /*
+ * Start page scanner daemon (process 3).
+ */
+ if (fork(p, (void *) NULL, rval))
+ panic("failed fork page scanner daemon");
+ if (rval[1]) {
+ p = curproc;
+ pagescanproc = p;
+ p->p_flag |= SLOAD|SSYS;
+ bcopy("pagescan", p->p_comm, sizeof("pagescan"));
+ vm_pagescan();
+ /*NOTREACHED*/
+ }
+#endif
+
/*
- * Start update daemon (process 3).
+ * Start update daemon (process 4).
*/
+#ifndef LAPTOP
if (fork(p, (void *) NULL, rval))
- panic("fork update");
+ panic("failed fork update daemon");
if (rval[1]) {
p = curproc;
updateproc = p;
@@ -377,6 +396,7 @@ main()
vfs_update();
/*NOTREACHED*/
}
+#endif
/*
* enter scheduling loop
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 97056b0c3bbc..55a5b1e3263f 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -2,7 +2,7 @@
* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $
+ * created from $Id: syscalls.master,v 1.9 1994/03/15 01:58:33 wollman Exp $
*/
#include "param.h"
@@ -174,6 +174,8 @@ int msgsys();
int shmsys();
#else
#endif
+int ntp_gettime();
+int ntp_adjtime();
#ifdef MACHVMCOMPAT
int svm_allocate();
int svm_deallocate();
@@ -453,8 +455,8 @@ struct sysent sysent[] = {
0, nosys, /* 172 = nosys */
0, nosys, /* 173 = nosys */
0, nosys, /* 174 = nosys */
- 0, nosys, /* 175 = nosys */
- 0, nosys, /* 176 = nosys */
+ 1, ntp_gettime, /* 175 = ntp_gettime */
+ 1, ntp_adjtime, /* 176 = ntp_adjtime */
#ifdef MACHVMCOMPAT
4, svm_allocate, /* 177 = vm_allocate */
3, svm_deallocate, /* 178 = vm_deallocate */
diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c
index 6d2c0e6536c7..386886e9926a 100644
--- a/sys/kern/kern_acct.c
+++ b/sys/kern/kern_acct.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_acct.c 7.18 (Berkeley) 5/11/91
- * $Id: kern_acct.c,v 1.9.2.1 1994/05/04 07:54:32 rgrimes Exp $
+ * $Id: kern_acct.c,v 1.10 1994/05/04 08:26:46 rgrimes Exp $
*/
#include "param.h"
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 44a334e00ebc..8df606e4dc72 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -31,9 +31,27 @@
* SUCH DAMAGE.
*
* from: @(#)kern_clock.c 7.16 (Berkeley) 5/9/91
- * $Id: kern_clock.c,v 1.11 1993/12/19 00:51:20 wollman Exp $
+ * $Id: kern_clock.c,v 1.16 1994/04/21 20:39:30 wollman Exp $
*/
+/* Portions of this software are covered by the following: */
+/******************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993, 1994 *
+ * *
+ * 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, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ *****************************************************************************/
+
+
#include "param.h"
#include "systm.h"
#include "dkstat.h"
@@ -42,6 +60,7 @@
#include "proc.h"
#include "signalvar.h"
#include "resourcevar.h"
+#include "timex.h"
#include "machine/cpu.h"
@@ -93,6 +112,238 @@ int ncallout;
}
/*
+ * Phase-lock loop (PLL) definitions
+ *
+ * The following variables are read and set by the ntp_adjtime() system
+ * call.
+ *
+ * time_state shows the state of the system clock, with values defined
+ * in the timex.h header file.
+ *
+ * time_status shows the status of the system clock, with bits defined
+ * in the timex.h header file.
+ *
+ * time_offset is used by the PLL to adjust the system time in small
+ * increments.
+ *
+ * time_constant determines the bandwidth or "stiffness" of the PLL.
+ *
+ * time_tolerance determines maximum frequency error or tolerance of the
+ * CPU clock oscillator and is a property of the architecture; however,
+ * in principle it could change as result of the presence of external
+ * discipline signals, for instance.
+ *
+ * time_precision is usually equal to the kernel tick variable; however,
+ * in cases where a precision clock counter or external clock is
+ * available, the resolution can be much less than this and depend on
+ * whether the external clock is working or not.
+ *
+ * time_maxerror is initialized by a ntp_adjtime() call and increased by
+ * the kernel once each second to reflect the maximum error
+ * bound growth.
+ *
+ * time_esterror is set and read by the ntp_adjtime() call, but
+ * otherwise not used by the kernel.
+ */
+int time_status = STA_UNSYNC; /* clock status bits */
+int time_state = TIME_OK; /* clock state */
+long time_offset = 0; /* time offset (us) */
+long time_constant = 0; /* pll time constant */
+long time_tolerance = MAXFREQ; /* frequency tolerance (scaled ppm) */
+long time_precision = 1; /* clock precision (us) */
+long time_maxerror = MAXPHASE; /* maximum error (us) */
+long time_esterror = MAXPHASE; /* estimated error (us) */
+
+/*
+ * The following variables establish the state of the PLL and the
+ * residual time and frequency offset of the local clock. The scale
+ * factors are defined in the timex.h header file.
+ *
+ * time_phase and time_freq are the phase increment and the frequency
+ * increment, respectively, of the kernel time variable at each tick of
+ * the clock.
+ *
+ * time_freq is set via ntp_adjtime() from a value stored in a file when
+ * the synchronization daemon is first started. Its value is retrieved
+ * via ntp_adjtime() and written to the file about once per hour by the
+ * daemon.
+ *
+ * time_adj is the adjustment added to the value of tick at each timer
+ * interrupt and is recomputed at each timer interrupt.
+ *
+ * time_reftime is the second's portion of the system time on the last
+ * call to ntp_adjtime(). It is used to adjust the time_freq variable
+ * and to increase the time_maxerror as the time since last update
+ * increases.
+ */
+long time_phase = 0; /* phase offset (scaled us) */
+long time_freq = 0; /* frequency offset (scaled ppm) */
+long time_adj = 0; /* tick adjust (scaled 1 / hz) */
+long time_reftime = 0; /* time at last adjustment (s) */
+
+#ifdef PPS_SYNC
+/*
+ * The following variables are used only if the if the kernel PPS
+ * discipline code is configured (PPS_SYNC). The scale factors are
+ * defined in the timex.h header file.
+ *
+ * pps_time contains the time at each calibration interval, as read by
+ * microtime().
+ *
+ * pps_offset is the time offset produced by the time median filter
+ * pps_tf[], while pps_jitter is the dispersion measured by this
+ * filter.
+ *
+ * pps_freq is the frequency offset produced by the frequency median
+ * filter pps_ff[], while pps_stabil is the dispersion measured by
+ * this filter.
+ *
+ * pps_usec is latched from a high resolution counter or external clock
+ * at pps_time. Here we want the hardware counter contents only, not the
+ * contents plus the time_tv.usec as usual.
+ *
+ * pps_valid counts the number of seconds since the last PPS update. It
+ * is used as a watchdog timer to disable the PPS discipline should the
+ * PPS signal be lost.
+ *
+ * pps_glitch counts the number of seconds since the beginning of an
+ * offset burst more than tick/2 from current nominal offset. It is used
+ * mainly to suppress error bursts due to priority conflicts between the
+ * PPS interrupt and timer interrupt.
+ *
+ * pps_count counts the seconds of the calibration interval, the
+ * duration of which is pps_shift in powers of two.
+ *
+ * pps_intcnt counts the calibration intervals for use in the interval-
+ * adaptation algorithm. It's just too complicated for words.
+ */
+struct timeval pps_time; /* kernel time at last interval */
+long pps_offset = 0; /* pps time offset (us) */
+long pps_jitter = MAXTIME; /* pps time dispersion (jitter) (us) */
+long pps_tf[] = {0, 0, 0}; /* pps time offset median filter (us) */
+long pps_freq = 0; /* frequency offset (scaled ppm) */
+long pps_stabil = MAXFREQ; /* frequency dispersion (scaled ppm) */
+long pps_ff[] = {0, 0, 0}; /* frequency offset median filter */
+long pps_usec = 0; /* microsec counter at last interval */
+long pps_valid = PPS_VALID; /* pps signal watchdog counter */
+int pps_glitch = 0; /* pps signal glitch counter */
+int pps_count = 0; /* calibration interval counter (s) */
+int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */
+int pps_intcnt = 0; /* intervals at current duration */
+
+/*
+ * PPS signal quality monitors
+ *
+ * pps_jitcnt counts the seconds that have been discarded because the
+ * jitter measured by the time median filter exceeds the limit MAXTIME
+ * (100 us).
+ *
+ * pps_calcnt counts the frequency calibration intervals, which are
+ * variable from 4 s to 256 s.
+ *
+ * pps_errcnt counts the calibration intervals which have been discarded
+ * because the wander exceeds the limit MAXFREQ (100 ppm) or where the
+ * calibration interval jitter exceeds two ticks.
+ *
+ * pps_stbcnt counts the calibration intervals that have been discarded
+ * because the frequency wander exceeds the limit MAXFREQ / 4 (25 us).
+ */
+long pps_jitcnt = 0; /* jitter limit exceeded */
+long pps_calcnt = 0; /* calibration intervals */
+long pps_errcnt = 0; /* calibration errors */
+long pps_stbcnt = 0; /* stability limit exceeded */
+#endif /* PPS_SYNC */
+
+/* XXX none of this stuff works under FreeBSD */
+#ifdef EXT_CLOCK
+/*
+ * External clock definitions
+ *
+ * The following definitions and declarations are used only if an
+ * external clock (HIGHBALL or TPRO) is configured on the system.
+ */
+#define CLOCK_INTERVAL 30 /* CPU clock update interval (s) */
+
+/*
+ * The clock_count variable is set to CLOCK_INTERVAL at each PPS
+ * interrupt and decremented once each second.
+ */
+int clock_count = 0; /* CPU clock counter */
+
+#ifdef HIGHBALL
+/*
+ * The clock_offset and clock_cpu variables are used by the HIGHBALL
+ * interface. The clock_offset variable defines the offset between
+ * system time and the HIGBALL counters. The clock_cpu variable contains
+ * the offset between the system clock and the HIGHBALL clock for use in
+ * disciplining the kernel time variable.
+ */
+extern struct timeval clock_offset; /* Highball clock offset */
+long clock_cpu = 0; /* CPU clock adjust */
+#endif /* HIGHBALL */
+#endif /* EXT_CLOCK */
+
+/*
+ * hardupdate() - local clock update
+ *
+ * This routine is called by ntp_adjtime() to update the local clock
+ * phase and frequency. This is used to implement an adaptive-parameter,
+ * first-order, type-II phase-lock loop. The code computes new time and
+ * frequency offsets each time it is called. The hardclock() routine
+ * amortizes these offsets at each tick interrupt. If the kernel PPS
+ * discipline code is configured (PPS_SYNC), the PPS signal itself
+ * determines the new time offset, instead of the calling argument.
+ * Presumably, calls to ntp_adjtime() occur only when the caller
+ * believes the local clock is valid within some bound (+-128 ms with
+ * NTP). If the caller's time is far different than the PPS time, an
+ * argument will ensue, and it's not clear who will lose.
+ *
+ * For default SHIFT_UPDATE = 12, the offset is limited to +-512 ms, the
+ * maximum interval between updates is 4096 s and the maximum frequency
+ * offset is +-31.25 ms/s.
+ *
+ * Note: splclock() is in effect.
+ */
+void
+hardupdate(offset)
+ long offset;
+{
+ long ltemp, mtemp;
+
+ if (!(time_status & STA_PLL) && !(time_status & STA_PPSTIME))
+ return;
+ ltemp = offset;
+#ifdef PPS_SYNC
+ if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
+ ltemp = pps_offset;
+#endif /* PPS_SYNC */
+ if (ltemp > MAXPHASE)
+ time_offset = MAXPHASE << SHIFT_UPDATE;
+ else if (ltemp < -MAXPHASE)
+ time_offset = -(MAXPHASE << SHIFT_UPDATE);
+ else
+ time_offset = ltemp << SHIFT_UPDATE;
+ mtemp = time.tv_sec - time_reftime;
+ time_reftime = time.tv_sec;
+ if (mtemp > MAXSEC)
+ mtemp = 0;
+
+ /* ugly multiply should be replaced */
+ if (ltemp < 0)
+ time_freq -= (-ltemp * mtemp) >> (time_constant +
+ time_constant + SHIFT_KF - SHIFT_USEC);
+ else
+ time_freq += (ltemp * mtemp) >> (time_constant +
+ time_constant + SHIFT_KF - SHIFT_USEC);
+ if (time_freq > time_tolerance)
+ time_freq = time_tolerance;
+ else if (time_freq < -time_tolerance)
+ time_freq = -time_tolerance;
+}
+
+
+
+/*
* The hz hardware interval timer.
* We update the events relating to real time.
* If this timer is also being used to gather statistics,
@@ -111,6 +362,7 @@ hardclock(frame)
int needsoft = 0;
extern int tickdelta;
extern long timedelta;
+ long ltemp, time_update = 0;
/*
* Update real-time timeout queue.
@@ -234,49 +486,164 @@ hardclock(frame)
* so we don't keep the relatively high clock interrupt
* priority any longer than necessary.
*/
- if (timedelta == 0)
- BUMPTIME(&time, tick)
- else {
- register delta;
-
- if (timedelta < 0) {
- delta = tick - tickdelta;
- timedelta += tickdelta;
+ {
+ int time_update;
+ if (timedelta == 0) {
+ time_update = tick;
} else {
- delta = tick + tickdelta;
- timedelta -= tickdelta;
+ if (timedelta < 0) {
+ time_update = tick - tickdelta;
+ timedelta += tickdelta;
+ } else {
+ time_update = tick + tickdelta;
+ timedelta -= tickdelta;
+ }
+ }
+ /*
+ * Compute the phase adjustment. If the low-order bits
+ * (time_phase) of the update overflow, bump the high-order bits
+ * (time_update).
+ */
+ time_phase += time_adj;
+ if (time_phase <= -FINEUSEC) {
+ ltemp = -time_phase >> SHIFT_SCALE;
+ time_phase += ltemp << SHIFT_SCALE;
+ time_update -= ltemp;
+ }
+ else if (time_phase >= FINEUSEC) {
+ ltemp = time_phase >> SHIFT_SCALE;
+ time_phase -= ltemp << SHIFT_SCALE;
+ time_update += ltemp;
+ }
+
+ time.tv_usec += time_update;
+ /*
+ * On rollover of the second the phase adjustment to be used for
+ * the next second is calculated. Also, the maximum error is
+ * increased by the tolerance. If the PPS frequency discipline
+ * code is present, the phase is increased to compensate for the
+ * CPU clock oscillator frequency error.
+ *
+ * With SHIFT_SCALE = 23, the maximum frequency adjustment is
+ * +-256 us per tick, or 25.6 ms/s at a clock frequency of 100
+ * Hz. The time contribution is shifted right a minimum of two
+ * bits, while the frequency contribution is a right shift.
+ * Thus, overflow is prevented if the frequency contribution is
+ * limited to half the maximum or 15.625 ms/s.
+ */
+ if (time.tv_usec >= 1000000) {
+ time.tv_usec -= 1000000;
+ time.tv_sec++;
+ time_maxerror += time_tolerance >> SHIFT_USEC;
+ if (time_offset < 0) {
+ ltemp = -time_offset >>
+ (SHIFT_KG + time_constant);
+ time_offset += ltemp;
+ time_adj = -ltemp <<
+ (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ } else {
+ ltemp = time_offset >>
+ (SHIFT_KG + time_constant);
+ time_offset -= ltemp;
+ time_adj = ltemp <<
+ (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ }
+#ifdef PPS_SYNC
+ /*
+ * Gnaw on the watchdog counter and update the frequency
+ * computed by the pll and the PPS signal.
+ */
+ pps_valid++;
+ if (pps_valid == PPS_VALID) {
+ pps_jitter = MAXTIME;
+ pps_stabil = MAXFREQ;
+ time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+ STA_PPSWANDER | STA_PPSERROR);
+ }
+ ltemp = time_freq + pps_freq;
+#else
+ ltemp = time_freq;
+#endif /* PPS_SYNC */
+ if (ltemp < 0)
+ time_adj -= -ltemp >>
+ (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
+ else
+ time_adj += ltemp >>
+ (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
+
+ /*
+ * When the CPU clock oscillator frequency is not a
+ * power of two in Hz, the SHIFT_HZ is only an
+ * approximate scale factor. In the SunOS kernel, this
+ * results in a PLL gain factor of 1/1.28 = 0.78 what it
+ * should be. In the following code the overall gain is
+ * increased by a factor of 1.25, which results in a
+ * residual error less than 3 percent.
+ */
+ /* Same thing applies for FreeBSD --GAW */
+ if (hz == 100) {
+ if (time_adj < 0)
+ time_adj -= -time_adj >> 2;
+ else
+ time_adj += time_adj >> 2;
+ }
+
+ /* XXX - this is really bogus, but can't be fixed until
+ xntpd's idea of the system clock is fixed to know how
+ the user wants leap seconds handled; in the mean time,
+ we assume that users of NTP are running without proper
+ leap second support (this is now the default anyway) */
+ /*
+ * Leap second processing. If in leap-insert state at
+ * the end of the day, the system clock is set back one
+ * second; if in leap-delete state, the system clock is
+ * set ahead one second. The microtime() routine or
+ * external clock driver will insure that reported time
+ * is always monotonic. The ugly divides should be
+ * replaced.
+ */
+ switch (time_state) {
+
+ case TIME_OK:
+ if (time_status & STA_INS)
+ time_state = TIME_INS;
+ else if (time_status & STA_DEL)
+ time_state = TIME_DEL;
+ break;
+
+ case TIME_INS:
+ if (time.tv_sec % 86400 == 0) {
+ time.tv_sec--;
+ time_state = TIME_OOP;
+ }
+ break;
+
+ case TIME_DEL:
+ if ((time.tv_sec + 1) % 86400 == 0) {
+ time.tv_sec++;
+ time_state = TIME_WAIT;
+ }
+ break;
+
+ case TIME_OOP:
+ time_state = TIME_WAIT;
+ break;
+
+ case TIME_WAIT:
+ if (!(time_status & (STA_INS | STA_DEL)))
+ time_state = TIME_OK;
+ }
}
- BUMPTIME(&time, delta);
}
-#ifdef DCFCLK
- /*
- * This is lousy, but until I can get the $&^%&^(!!! signal onto one
- * of the interrupt's I'll have to poll it. No, it will not work if
- * you attempt -DHZ=1000, things break.
- * But keep the NDCFCLK low, to avoid waste of cycles...
- * phk@data.fls.dk
- */
- dcfclk_worker();
-#endif
if (needsoft) {
-#if 0
-/*
- * XXX - hardclock runs at splhigh, so the splsoftclock is useless and
- * softclock runs at splhigh as well if we do this. It is not much of
- * an optimization, since the "software interrupt" is done with a call
- * from doreti, and the overhead of checking there is sometimes less
- * than checking here. Moreover, the whole %$$%$^ frame is passed by
- * value here.
- */
if (CLKF_BASEPRI(&frame)) {
/*
* Save the overhead of a software interrupt;
* it will happen as soon as we return, so do it now.
*/
(void) splsoftclock();
- softclock(frame);
+ softclock(CLKF_USERMODE(&frame));
} else
-#endif
setsoftclock();
}
}
@@ -322,7 +689,7 @@ gatherstats(framep)
cpstate = CP_SYS;
if (curproc == NULL && CLKF_BASEPRI(framep))
cpstate = CP_IDLE;
-#ifdef GPROF
+#if defined(GPROF) && !defined(GUPROF)
s = (u_long) CLKF_PC(framep) - (u_long) s_lowpc;
if (profiling < 2 && s < s_textsize)
kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
@@ -343,10 +710,9 @@ gatherstats(framep)
* Software priority level clock interrupt.
* Run periodic events from timeout queue.
*/
-/*ARGSUSED*/
void
-softclock(frame)
- clockframe frame;
+softclock(usermode)
+ int usermode;
{
for (;;) {
@@ -377,11 +743,11 @@ softclock(frame)
* If trapped user-mode and profiling, give it
* a profiling tick.
*/
- if (CLKF_USERMODE(&frame)) {
+ if (usermode) {
register struct proc *p = curproc;
if (p->p_stats->p_prof.pr_scale)
- profile_tick(p, &frame);
+ profile_tick(p, unused was &frame);
/*
* Check to see if process has accumulated
* more than 10 minutes of user time. If so
@@ -515,3 +881,167 @@ hzto(tv)
ticks = CLOCK_T_MAX;
return (ticks);
}
+
+#ifdef PPS_SYNC
+/*
+ * hardpps() - discipline CPU clock oscillator to external pps signal
+ *
+ * This routine is called at each PPS interrupt in order to discipline
+ * the CPU clock oscillator to the PPS signal. It integrates successive
+ * phase differences between the two oscillators and calculates the
+ * frequency offset. This is used in hardclock() to discipline the CPU
+ * clock oscillator so that intrinsic frequency error is cancelled out.
+ * The code requires the caller to capture the time and hardware
+ * counter value at the designated PPS signal transition.
+ */
+void
+hardpps(tvp, usec)
+ struct timeval *tvp; /* time at PPS */
+ long usec; /* hardware counter at PPS */
+{
+ long u_usec, v_usec, bigtick;
+ long cal_sec, cal_usec;
+
+ /*
+ * During the calibration interval adjust the starting time when
+ * the tick overflows. At the end of the interval compute the
+ * duration of the interval and the difference of the hardware
+ * counters at the beginning and end of the interval. This code
+ * is deliciously complicated by the fact valid differences may
+ * exceed the value of tick when using long calibration
+ * intervals and small ticks. Note that the counter can be
+ * greater than tick if caught at just the wrong instant, but
+ * the values returned and used here are correct.
+ */
+ bigtick = (long)tick << SHIFT_USEC;
+ pps_usec -= ntp_pll.ybar;
+ if (pps_usec >= bigtick)
+ pps_usec -= bigtick;
+ if (pps_usec < 0)
+ pps_usec += bigtick;
+ pps_time.tv_sec++;
+ pps_count++;
+ if (pps_count < (1 << pps_shift))
+ return;
+ pps_count = 0;
+ ntp_pll.calcnt++;
+ u_usec = usec << SHIFT_USEC;
+ v_usec = pps_usec - u_usec;
+ if (v_usec >= bigtick >> 1)
+ v_usec -= bigtick;
+ if (v_usec < -(bigtick >> 1))
+ v_usec += bigtick;
+ if (v_usec < 0)
+ v_usec = -(-v_usec >> ntp_pll.shift);
+ else
+ v_usec = v_usec >> ntp_pll.shift;
+ pps_usec = u_usec;
+ cal_sec = tvp->tv_sec;
+ cal_usec = tvp->tv_usec;
+ cal_sec -= pps_time.tv_sec;
+ cal_usec -= pps_time.tv_usec;
+ if (cal_usec < 0) {
+ cal_usec += 1000000;
+ cal_sec--;
+ }
+ pps_time = *tvp;
+
+ /*
+ * Check for lost interrupts, noise, excessive jitter and
+ * excessive frequency error. The number of timer ticks during
+ * the interval may vary +-1 tick. Add to this a margin of one
+ * tick for the PPS signal jitter and maximum frequency
+ * deviation. If the limits are exceeded, the calibration
+ * interval is reset to the minimum and we start over.
+ */
+ u_usec = (long)tick << 1;
+ if (!((cal_sec == -1 && cal_usec > (1000000 - u_usec))
+ || (cal_sec == 0 && cal_usec < u_usec))
+ || v_usec > ntp_pll.tolerance || v_usec < -ntp_pll.tolerance) {
+ ntp_pll.jitcnt++;
+ ntp_pll.shift = NTP_PLL.SHIFT;
+ pps_dispinc = PPS_DISPINC;
+ ntp_pll.intcnt = 0;
+ return;
+ }
+
+ /*
+ * A three-stage median filter is used to help deglitch the pps
+ * signal. The median sample becomes the offset estimate; the
+ * difference between the other two samples becomes the
+ * dispersion estimate.
+ */
+ pps_mf[2] = pps_mf[1];
+ pps_mf[1] = pps_mf[0];
+ pps_mf[0] = v_usec;
+ if (pps_mf[0] > pps_mf[1]) {
+ if (pps_mf[1] > pps_mf[2]) {
+ u_usec = pps_mf[1]; /* 0 1 2 */
+ v_usec = pps_mf[0] - pps_mf[2];
+ } else if (pps_mf[2] > pps_mf[0]) {
+ u_usec = pps_mf[0]; /* 2 0 1 */
+ v_usec = pps_mf[2] - pps_mf[1];
+ } else {
+ u_usec = pps_mf[2]; /* 0 2 1 */
+ v_usec = pps_mf[0] - pps_mf[1];
+ }
+ } else {
+ if (pps_mf[1] < pps_mf[2]) {
+ u_usec = pps_mf[1]; /* 2 1 0 */
+ v_usec = pps_mf[2] - pps_mf[0];
+ } else if (pps_mf[2] < pps_mf[0]) {
+ u_usec = pps_mf[0]; /* 1 0 2 */
+ v_usec = pps_mf[1] - pps_mf[2];
+ } else {
+ u_usec = pps_mf[2]; /* 1 2 0 */
+ v_usec = pps_mf[1] - pps_mf[0];
+ }
+ }
+
+ /*
+ * Here the dispersion average is updated. If it is less than
+ * the threshold pps_dispmax, the frequency average is updated
+ * as well, but clamped to the tolerance.
+ */
+ v_usec = (v_usec >> 1) - ntp_pll.disp;
+ if (v_usec < 0)
+ ntp_pll.disp -= -v_usec >> PPS_AVG;
+ else
+ ntp_pll.disp += v_usec >> PPS_AVG;
+ if (ntp_pll.disp > pps_dispmax) {
+ ntp_pll.discnt++;
+ return;
+ }
+ if (u_usec < 0) {
+ ntp_pll.ybar -= -u_usec >> PPS_AVG;
+ if (ntp_pll.ybar < -ntp_pll.tolerance)
+ ntp_pll.ybar = -ntp_pll.tolerance;
+ u_usec = -u_usec;
+ } else {
+ ntp_pll.ybar += u_usec >> PPS_AVG;
+ if (ntp_pll.ybar > ntp_pll.tolerance)
+ ntp_pll.ybar = ntp_pll.tolerance;
+ }
+
+ /*
+ * Here the calibration interval is adjusted. If the maximum
+ * time difference is greater than tick/4, reduce the interval
+ * by half. If this is not the case for four consecutive
+ * intervals, double the interval.
+ */
+ if (u_usec << ntp_pll.shift > bigtick >> 2) {
+ ntp_pll.intcnt = 0;
+ if (ntp_pll.shift > NTP_PLL.SHIFT) {
+ ntp_pll.shift--;
+ pps_dispinc <<= 1;
+ }
+ } else if (ntp_pll.intcnt >= 4) {
+ ntp_pll.intcnt = 0;
+ if (ntp_pll.shift < NTP_PLL.SHIFTMAX) {
+ ntp_pll.shift++;
+ pps_dispinc >>= 1;
+ }
+ } else
+ ntp_pll.intcnt++;
+}
+#endif /* PPS_SYNC */
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d28faac16cbe..7ad2e2946f6a 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_descrip.c 7.28 (Berkeley) 6/25/91
- * $Id: kern_descrip.c,v 1.6.2.1 1994/05/04 07:54:36 rgrimes Exp $
+ * $Id: kern_descrip.c,v 1.8 1994/05/04 08:26:49 rgrimes Exp $
*/
#include "param.h"
@@ -100,10 +100,12 @@ dup(p, uap, retval)
struct file *fp;
int fd, error;
+#if 0
/*
* XXX Compatibility
*/
if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
+#endif
if ((unsigned)uap->i >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[uap->i]) == NULL)
diff --git a/sys/kern/kern_execve.c b/sys/kern/kern_execve.c
index 5e0aa6565d3d..f72948400f1e 100644
--- a/sys/kern/kern_execve.c
+++ b/sys/kern/kern_execve.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kern_execve.c,v 1.15.2.2 1994/03/24 08:57:16 rgrimes Exp $
+ * $Id: kern_execve.c,v 1.20 1994/03/26 12:24:27 davidg Exp $
*/
#include "param.h"
@@ -78,9 +78,6 @@ execve(p, uap, retval)
char *stringbase, *stringp;
int *stack_base;
int error, resid, len, i;
-#if 0
- char image_header[256];
-#endif
struct image_params image_params, *iparams;
struct vnode *vnodep;
struct vattr attr;
@@ -147,33 +144,13 @@ interpret:
if (error)
goto exec_fail_dealloc;
-#if 0
- /*
- * Read the image header from the file.
- */
- error = vn_rdwr(UIO_READ,
- vnodep,
- image_header,
- sizeof(image_header),
- 0,
- UIO_SYSSPACE, IO_NODELOCKED,
- p->p_ucred,
- &resid,
- p);
- if (error)
- goto exec_fail_dealloc;
-
- /* Clear out junk in image_header if a partial read (small file) */
- if (resid)
- bzero(image_header + (sizeof(image_header) - resid), resid);
-#endif
/*
* Map the image header (first page) of the file into
* kernel address space
*/
error = vm_mmap(kernel_map, /* map */
(vm_offset_t *)&image_header, /* address */
- NBPG, /* size */
+ PAGE_SIZE, /* size */
VM_PROT_READ, /* protection */
VM_PROT_READ, /* max protection */
MAP_FILE, /* flags */
@@ -208,7 +185,7 @@ interpret:
vput(ndp->ni_vp);
FREE(ndp->ni_pnbuf, M_NAMEI);
if (vm_deallocate(kernel_map,
- (vm_offset_t)image_header, NBPG))
+ (vm_offset_t)image_header, PAGE_SIZE))
panic("execve: header dealloc failed (1)");
/* set new name to that of the interpreter */
@@ -231,14 +208,15 @@ interpret:
stack_base = exec_copyout_strings(iparams);
p->p_vmspace->vm_minsaddr = (char *)stack_base;
-
/*
* Stuff argument count as first item on stack
*/
*(--stack_base) = iparams->argc;
- /* close files on exec, fixup signals */
+ /* close files on exec */
fdcloseexec(p);
+
+ /* reset caught signals */
execsigs(p);
/* name this process - nameiexec(p, ndp) */
@@ -269,12 +247,12 @@ interpret:
vrele(p->p_tracep);
p->p_tracep = 0;
}
- if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) {
+ if ((attr.va_mode & VSUID) && (p->p_flag & STRC) == 0) {
p->p_ucred = crcopy(p->p_ucred);
p->p_ucred->cr_uid = attr.va_uid;
p->p_flag |= SUGID;
}
- if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) {
+ if ((attr.va_mode & VSGID) && (p->p_flag & STRC) == 0) {
p->p_ucred = crcopy(p->p_ucred);
p->p_ucred->cr_groups[0] = attr.va_gid;
p->p_flag |= SUGID;
@@ -305,10 +283,9 @@ interpret:
/*
* free various allocated resources
*/
- if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase,
- ARG_MAX))
+ if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, ARG_MAX))
panic("execve: string buffer dealloc failed (1)");
- if (vm_deallocate(kernel_map, (vm_offset_t)image_header, NBPG))
+ if (vm_deallocate(kernel_map, (vm_offset_t)image_header, PAGE_SIZE))
panic("execve: header dealloc failed (2)");
vput(ndp->ni_vp);
FREE(ndp->ni_pnbuf, M_NAMEI);
@@ -322,7 +299,7 @@ exec_fail_dealloc:
panic("execve: string buffer dealloc failed (2)");
if (iparams->image_header && iparams->image_header != (char *)-1)
if (vm_deallocate(kernel_map,
- (vm_offset_t)iparams->image_header, NBPG))
+ (vm_offset_t)iparams->image_header, PAGE_SIZE))
panic("execve: header dealloc failed (3)");
vput(ndp->ni_vp);
FREE(ndp->ni_pnbuf, M_NAMEI);
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index e1deb4d855fe..a6cf4c732390 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_exit.c 7.35 (Berkeley) 6/27/91
- * $Id: kern_exit.c,v 1.14 1994/01/29 04:04:23 davidg Exp $
+ * $Id: kern_exit.c,v 1.15 1994/03/14 21:54:13 davidg Exp $
*/
#include "param.h"
@@ -353,6 +353,9 @@ loop:
continue;
nfound++;
if (p->p_stat == SZOMB) {
+ /* charge childs cpu usage to parent */
+ if( curproc->p_pid != 1)
+ curproc->p_cpu += p->p_cpu;
retval[0] = p->p_pid;
#ifdef COMPAT_43
if (uap->compat)
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 5ca1d910f937..b9088766dd8b 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_fork.c 7.29 (Berkeley) 5/15/91
- * $Id: kern_fork.c,v 1.6.2.1 1994/05/04 07:54:38 rgrimes Exp $
+ * $Id: kern_fork.c,v 1.8 1994/05/04 08:26:54 rgrimes Exp $
*/
#include "param.h"
@@ -246,6 +246,11 @@ again:
#endif
/*
+ * set priority of child to be that of parent
+ */
+ p2->p_cpu = p1->p_cpu;
+
+ /*
* This begins the section where we must prevent the parent
* from being swapped.
*/
@@ -268,6 +273,9 @@ again:
p2->p_stats->p_start = time;
(void) spl0();
p2->p_acflag = AFORK;
+/*
+ vm_map_init_pmap(&p2->p_vmspace->vm_map);
+*/
return (0);
}
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index 6841827446d0..ce3243a30367 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_malloc.c 7.25 (Berkeley) 5/8/91
- * $Id: kern_malloc.c,v 1.8 1994/02/10 08:04:07 davidg Exp $
+ * $Id: kern_malloc.c,v 1.9 1994/04/13 00:54:59 ache Exp $
*/
#include "param.h"
@@ -259,3 +259,75 @@ kmeminit()
kmemstats[M_MBUF].ks_limit = (vm_page_count * NBPG) / 16;
#endif
}
+
+void *
+contigmalloc(size, type, flags, maxpa, alignmask, boundarymask)
+ unsigned long size;
+ int type;
+ int flags;
+ unsigned long maxpa; /* e.g. 16M - 1 for isa dma */
+ unsigned long alignmask; /* e.g. 1M - 1 for M boundary */
+ unsigned long boundarymask; /* e.g. 64K - 1 for 8-bit isa dma */
+{
+ unsigned long skipsize;
+ void *skipva;
+
+ size = round_page(size);
+ if (size == 0 || size > boundarymask + 1)
+ return (NULL);
+
+ /*
+ * Attempt to push the physical address to a suitable boundary by
+ * skipping some memory. We could be cleverer here. E.g., mallocate
+ * lots of single pages and then free the ones that we hope to use.
+ * flags == M_WAIT is likely to hang the system.
+ */
+ for (skipsize = 0, skipva = NULL; ; skipsize += NBPG) {
+ unsigned long off;
+ unsigned long pa;
+ unsigned long prevpa;
+ void *va;
+
+ if (skipsize != 0) {
+ skipva = malloc(skipsize, type, flags);
+ if (skipva == NULL) {
+#ifdef DEBUG
+ printf("contigmalloc: skipva NULL on try %d\n",
+ 1 + skipsize / NBPG);
+#endif
+ return (NULL);
+ }
+ }
+ va = malloc(size, type, flags);
+ if (skipsize != 0)
+ free(skipva, type);
+ if (va == NULL) {
+#ifdef DEBUG
+ printf("contigmalloc: va NULL on try %d\n",
+ 1 + skipsize / NBPG);
+#endif
+ return (NULL);
+ }
+ for (off = 0, prevpa = 0; off < size; off += NBPG, prevpa = pa)
+ {
+ pa = pmap_extract(pmap_kernel(), (vm_offset_t)va + off);
+ if (pa + NBPG - 1 > maxpa
+ || off == 0 && pa & alignmask
+ || off != 0
+ && (pa != prevpa + NBPG
+ || (pa & boundarymask) == 0))
+ goto fail;
+ }
+#ifdef DEBUG
+ printf("contigmalloc: success at va %lx pa %lx on try %d\n",
+ (unsigned long)va,
+ pmap_extract(pmap_kernel(), (unsigned long)va),
+ 1 + skipsize / NBPG);
+#endif
+ return (va);
+fail:
+ free(va, type);
+ }
+}
+
+
diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c
new file mode 100644
index 000000000000..9e50a42df282
--- /dev/null
+++ b/sys/kern/kern_ntptime.c
@@ -0,0 +1,267 @@
+/******************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993, 1994 *
+ * *
+ * 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, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ ******************************************************************************/
+
+/*
+ * Modification history kern_ntptime.c
+ *
+ * 24 Mar 94 David L. Mills
+ * Revised syscall interface to include new variables for PPS
+ * time discipline.
+ *
+ * 14 Feb 94 David L. Mills
+ * Added code for external clock
+ *
+ * 28 Nov 93 David L. Mills
+ * Revised frequency scaling to conform with adjusted parameters
+ *
+ * 17 Sep 93 David L. Mills
+ * Created file
+ */
+/*
+ * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS
+ * 4.1.1 and 4.1.3
+ *
+ * These routines consitute the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. The ntp_gettime() routine
+ * provides the time, maximum error (synch distance) and estimated error
+ * (dispersion) to client user application programs. The ntp_adjtime()
+ * routine is used by the NTP daemon to adjust the system clock to an
+ * externally derived time. The time offset and related variables set by
+ * this routine are used by hardclock() to adjust the phase and
+ * frequency of the phase-lock loop which controls the system clock.
+ */
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "proc.h"
+#include "timex.h"
+
+/*
+ * The following variables are used by the hardclock() routine in the
+ * kern_clock.c module and are described in that module.
+ */
+extern struct timeval time; /* kernel time variable */
+extern int time_state; /* clock state */
+extern int time_status; /* clock status bits */
+extern long time_offset; /* time adjustment (us) */
+extern long time_freq; /* frequency offset (scaled ppm) */
+extern long time_maxerror; /* maximum error (us) */
+extern long time_esterror; /* estimated error (us) */
+extern long time_constant; /* pll time constant */
+extern long time_precision; /* clock precision (us) */
+extern long time_tolerance; /* frequency tolerance (scaled ppm) */
+
+#ifdef PPS_SYNC
+/*
+ * The following variables are used only if the PPS signal discipline
+ * is configured in the kernel.
+ */
+extern int pps_shift; /* interval duration (s) (shift) */
+extern long pps_freq; /* pps frequency offset (scaled ppm) */
+extern long pps_jitter; /* pps jitter (us) */
+extern long pps_stabil; /* pps stability (scaled ppm) */
+extern long pps_jitcnt; /* jitter limit exceeded */
+extern long pps_calcnt; /* calibration intervals */
+extern long pps_errcnt; /* calibration errors */
+extern long pps_stbcnt; /* stability limit exceeded */
+#endif /* PPS_SYNC */
+
+/*
+ * ntp_gettime() - NTP user application interface
+ */
+struct ntp_gettime_args {
+ struct ntptimeval *tp;
+};
+
+int
+ntp_gettime(struct proc *p, struct ntp_gettime_args *uap, int *retval)
+{
+ struct timeval atv;
+ struct ntptimeval ntv;
+ int s;
+ int error = 0;
+
+ if (uap->tp) {
+ s = splclock();
+#ifdef EXT_CLOCK
+ /*
+ * The microtime() external clock routine returns a
+ * status code. If less than zero, we declare an error
+ * in the clock status word and return the kernel
+ * (software) time variable. While there are other
+ * places that call microtime(), this is the only place
+ * that matters from an application point of view.
+ */
+ if (microtime(&atv) < 0) {
+ time_status |= STA_CLOCKERR;
+ ntv.time = time;
+ } else
+ time_status &= ~STA_CLOCKERR;
+#else /* EXT_CLOCK */
+ microtime(&atv);
+#endif /* EXT_CLOCK */
+ ntv.time = atv;
+ ntv.maxerror = time_maxerror;
+ ntv.esterror = time_esterror;
+ (void) splx(s);
+
+ error = copyout((caddr_t)&ntv, (caddr_t)uap->tp,
+ sizeof (ntv));
+ }
+ if (!error) {
+ *retval = time_state;
+
+ /*
+ * Status word error decode. If any of these conditions
+ * occur, an error is returned, instead of the status
+ * word. Most applications will care only about the fact
+ * the system clock may not be trusted, not about the
+ * details.
+ *
+ * Hardware or software error
+ */
+ if (time_status & (STA_UNSYNC | STA_CLOCKERR))
+ *retval = TIME_ERROR;
+
+ /*
+ * PPS signal lost when either time or frequency
+ * synchronization requested
+ */
+ if (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
+ !(time_status & STA_PPSSIGNAL))
+ *retval = TIME_ERROR;
+
+ /*
+ * PPS jitter exceeded when time synchronization
+ * requested
+ */
+ if (time_status & STA_PPSTIME &&
+ time_status & STA_PPSJITTER)
+ *retval = TIME_ERROR;
+
+ /*
+ * PPS wander exceeded or calibration error when
+ * frequency synchronization requested
+ */
+ if (time_status & STA_PPSFREQ &&
+ time_status & (STA_PPSWANDER | STA_PPSERROR))
+ *retval = TIME_ERROR;
+ }
+ return error;
+}
+
+/*
+ * ntp_adjtime() - NTP daemon application interface
+ */
+struct ntp_adjtime_args {
+ struct timex *tp;
+};
+
+int
+ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap, int *retval)
+{
+ struct timex ntv;
+ int modes;
+ int s;
+ int error;
+
+ error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv));
+ if (error)
+ return error;
+
+ /*
+ * Update selected clock variables - only the superuser can
+ * change anything. Note that there is no error checking here on
+ * the assumption the superuser should know what it is doing.
+ */
+ modes = ntv.modes;
+ if ((modes != 0)
+ && (error = suser(p->p_cred->pc_ucred, &p->p_acflag)))
+ return error;
+
+ s = splclock();
+ if (modes & MOD_FREQUENCY)
+#ifdef PPS_SYNC
+ time_freq = ntv.freq - pps_freq;
+#else /* PPS_SYNC */
+ time_freq = ntv.freq;
+#endif /* PPS_SYNC */
+ if (modes & MOD_MAXERROR)
+ time_maxerror = ntv.maxerror;
+ if (modes & MOD_ESTERROR)
+ time_esterror = ntv.esterror;
+ if (modes & MOD_STATUS) {
+ time_status &= STA_RONLY;
+ time_status |= ntv.status & ~STA_RONLY;
+ }
+ if (modes & MOD_TIMECONST)
+ time_constant = ntv.constant;
+ if (modes & MOD_OFFSET)
+ hardupdate(ntv.offset);
+
+ /*
+ * Retrieve all clock variables
+ */
+ if (time_offset < 0)
+ ntv.offset = -(-time_offset >> SHIFT_UPDATE);
+ else
+ ntv.offset = time_offset >> SHIFT_UPDATE;
+#ifdef PPS_SYNC
+ ntv.freq = time_freq + pps_freq;
+#else /* PPS_SYNC */
+ ntv.freq = time_freq;
+#endif /* PPS_SYNC */
+ ntv.maxerror = time_maxerror;
+ ntv.esterror = time_esterror;
+ ntv.status = time_status;
+ ntv.constant = time_constant;
+ ntv.precision = time_precision;
+ ntv.tolerance = time_tolerance;
+#ifdef PPS_SYNC
+ ntv.shift = pps_shift;
+ ntv.ppsfreq = pps_freq;
+ ntv.jitter = pps_jitter >> PPS_AVG;
+ ntv.stabil = pps_stabil;
+ ntv.calcnt = pps_calcnt;
+ ntv.errcnt = pps_errcnt;
+ ntv.jitcnt = pps_jitcnt;
+ ntv.stbcnt = pps_stbcnt;
+#endif /* PPS_SYNC */
+ (void)splx(s);
+
+ error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv));
+ if (!error) {
+ /*
+ * Status word error decode. See comments in
+ * ntp_gettime() routine.
+ */
+ retval[0] = time_state;
+ if (time_status & (STA_UNSYNC | STA_CLOCKERR))
+ retval[0] = TIME_ERROR;
+ if (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
+ !(time_status & STA_PPSSIGNAL))
+ retval[0] = TIME_ERROR;
+ if (time_status & STA_PPSTIME &&
+ time_status & STA_PPSJITTER)
+ retval[0] = TIME_ERROR;
+ if (time_status & STA_PPSFREQ &&
+ time_status & (STA_PPSWANDER | STA_PPSERROR))
+ retval[0] = TIME_ERROR;
+ }
+ return error;
+}
+
+
diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c
index cf76f80ae202..bc02348f73a9 100644
--- a/sys/kern/kern_physio.c
+++ b/sys/kern/kern_physio.c
@@ -45,7 +45,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kern_physio.c,v 1.1.2.2 1994/05/01 18:59:48 rgrimes Exp $
+ * $Id: kern_physio.c,v 1.7 1994/04/25 23:48:29 davidg Exp $
*/
#include "param.h"
@@ -56,8 +56,11 @@
#include "malloc.h"
#include "vnode.h"
#include "vm/vm.h"
+#include "vm/vm_page.h"
#include "specdev.h"
+#define HOLD_WORKS_FOR_SHARING
+
/*
* Driver interface to do "raw" I/O in the address space of a
* user process directly for read and write operations..
@@ -79,6 +82,13 @@ rawwrite(dev, uio)
(caddr_t) (u_long) dev, uio));
}
+static void
+physwakeup(bp)
+ struct buf *bp;
+{
+ wakeup((caddr_t) bp);
+ bp->b_flags &= ~B_CALL;
+}
int physio(strat, dev, bp, off, rw, base, len, p)
d_strategy_t strat;
@@ -92,7 +102,7 @@ int physio(strat, dev, bp, off, rw, base, len, p)
int amttodo = *len;
int error, amtdone;
vm_prot_t ftype;
- vm_offset_t v, lastv;
+ vm_offset_t v, lastv, pa;
caddr_t adr;
int oldflags;
int s;
@@ -122,7 +132,6 @@ int physio(strat, dev, bp, off, rw, base, len, p)
splx(s);
}
- bp->b_flags = B_BUSY | B_PHYS | rw;
bp->b_proc = p;
bp->b_dev = dev;
bp->b_error = 0;
@@ -131,17 +140,25 @@ int physio(strat, dev, bp, off, rw, base, len, p)
/* iteratively do I/O on as large a chunk as possible */
do {
- bp->b_flags &= ~B_DONE;
+ bp->b_flags = B_BUSY | B_PHYS | B_CALL | rw;
+ bp->b_iodone = physwakeup;
bp->b_un.b_addr = base;
- /* XXX limit */
+ /*
+ * Notice that b_bufsize is more owned by the buffer
+ * allocating entity, while b_bcount might be modified
+ * by the called I/O routines. So after I/O is complete
+ * the only thing guaranteed to be unchanged is
+ * b_bufsize.
+ */
bp->b_bcount = min (256*1024, amttodo);
+ bp->b_bufsize = bp->b_bcount;
/* first, check if accessible */
- if (rw == B_READ && !useracc(base, bp->b_bcount, B_WRITE)) {
+ if (rw == B_READ && !useracc(base, bp->b_bufsize, B_WRITE)) {
error = EFAULT;
goto errrtn;
}
- if (rw == B_WRITE && !useracc(base, bp->b_bcount, B_READ)) {
+ if (rw == B_WRITE && !useracc(base, bp->b_bufsize, B_READ)) {
error = EFAULT;
goto errrtn;
}
@@ -153,16 +170,17 @@ int physio(strat, dev, bp, off, rw, base, len, p)
ftype = VM_PROT_READ;
lastv = 0;
- for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount;
+ for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bufsize;
adr += NBPG) {
/*
- * make sure that the pde is valid and wired
+ * make sure that the pde is valid and held
*/
v = trunc_page(((vm_offset_t)vtopte(adr)));
if (v != lastv) {
- vm_map_pageable(&p->p_vmspace->vm_map, v,
- round_page(v+1), FALSE);
+ vm_fault_quick(v, VM_PROT_READ);
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, v);
+ vm_page_hold(PHYS_TO_VM_PAGE(pa));
lastv = v;
}
@@ -170,65 +188,48 @@ int physio(strat, dev, bp, off, rw, base, len, p)
* do the vm_fault if needed, do the copy-on-write thing when
* reading stuff off device into memory.
*/
- if (ftype & VM_PROT_WRITE) {
- /*
- * properly handle copy-on-write
- */
-#if 0
- *(volatile int *) adr += 0;
-#endif
- vm_fault(&curproc->p_vmspace->vm_map,
- (vm_offset_t) adr,
- VM_PROT_READ|VM_PROT_WRITE, FALSE);
- }
-#if 0
- else {
- /*
- * this clause is not really necessary because
- * vslock does a vm_map_pageable FALSE.
- * It is not optimally efficient to reference the
- * page with the possiblity of it being paged out, but
- * if this page is faulted here, it will be placed on the
- * active queue, with the probability of it being paged
- * out being very very low. This is here primarily for
- * "symmetry".
- */
- *(volatile int *) adr;
- }
-#endif
- }
+ vm_fault_quick(adr, ftype);
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t) adr);
/*
- * if the process has been blocked by the wiring of the page table pages
- * above or faults of other pages, then the vm_map_pageable contained in the
- * vslock will fault the pages back in if they have been paged out since
- * being referenced in the loop above. (vm_map_pageable calls vm_fault_wire
- * which calls vm_fault to get the pages if needed.)
+ * hold the data page
*/
+ vm_page_hold(PHYS_TO_VM_PAGE(pa));
+ }
- /* lock in core (perform vm_map_pageable, FALSE) */
- vslock (base, bp->b_bcount);
+ vmapbuf(bp);
/* perform transfer */
- physstrat(bp, strat, PRIBIO);
+ (*strat)(bp);
- /* unlock (perform vm_map_pageable, TRUE) */
- vsunlock (base, bp->b_bcount, 0);
+ /* pageout daemon doesn't wait for pushed pages */
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0)
+ tsleep((caddr_t)bp, PRIBIO, "physstr", 0);
+ splx(s);
- lastv = 0;
+ vunmapbuf(bp);
/*
- * unwire the pde
+ * unhold the pde, and data pages
*/
- for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount;
+ lastv = 0;
+ for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bufsize;
adr += NBPG) {
v = trunc_page(((vm_offset_t)vtopte(adr)));
if (v != lastv) {
- vm_map_pageable(&p->p_vmspace->vm_map, v, round_page(v+1), TRUE);
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, v);
+ vm_page_unhold(PHYS_TO_VM_PAGE(pa));
lastv = v;
}
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t) adr);
+ vm_page_unhold(PHYS_TO_VM_PAGE(pa));
}
+ /*
+ * in this case, we need to use b_bcount instead of
+ * b_bufsize.
+ */
amtdone = bp->b_bcount - bp->b_resid;
amttodo -= amtdone;
base += amtdone;
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 2d1d7db1ce4e..48ea1cc33d06 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_prot.c 7.21 (Berkeley) 5/3/91
- * $Id: kern_prot.c,v 1.5.2.2 1994/05/04 07:54:41 rgrimes Exp $
+ * $Id: kern_prot.c,v 1.7 1994/05/04 08:26:59 rgrimes Exp $
*/
/*
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index 941ead222a34..caaf6a5953a5 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_resource.c 7.13 (Berkeley) 5/9/91
- * $Id: kern_resource.c,v 1.7.2.1 1994/05/04 07:54:43 rgrimes Exp $
+ * $Id: kern_resource.c,v 1.8 1994/05/04 08:27:01 rgrimes Exp $
*/
#include "param.h"
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 8450e1c2f588..f57966f8fbb6 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_sig.c 7.35 (Berkeley) 6/28/91
- * $Id: kern_sig.c,v 1.9 1993/12/19 00:51:30 wollman Exp $
+ * $Id: kern_sig.c,v 1.12 1994/05/25 19:49:38 csgr Exp $
*/
#define SIGPROP /* include signal properties table */
@@ -43,6 +43,7 @@
#include "mount.h"
#include "filedesc.h"
#include "proc.h"
+#include "ucred.h"
#include "systm.h"
#include "timeb.h"
#include "times.h"
@@ -52,6 +53,7 @@
#include "kernel.h"
#include "wait.h"
#include "ktrace.h"
+#include "syslog.h"
#include "machine/cpu.h"
@@ -1044,6 +1046,14 @@ sigexit(p, sig)
p->p_acflag |= AXSIG;
if (sigprop[sig] & SA_CORE) {
p->p_sigacts->ps_sig = sig;
+ /*
+ * Log signals which would cause core dumps
+ * (Log as LOG_INFO to appease those who don't want
+ * these messages.)
+ * XXX : Todo, as well as euid, write out ruid too
+ */
+ log(LOG_INFO, "pid %d: %s: uid %d: exited on signal %d\n",
+ p->p_pid, p->p_comm, p->p_ucred->cr_uid, sig);
if (coredump(p) == 0)
sig |= WCOREFLAG;
}
diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c
index bb860d2ca6bd..47af2d75b472 100644
--- a/sys/kern/kern_subr.c
+++ b/sys/kern/kern_subr.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_subr.c 7.7 (Berkeley) 4/15/91
- * $Id: kern_subr.c,v 1.5.2.1 1994/05/04 07:54:46 rgrimes Exp $
+ * $Id: kern_subr.c,v 1.6 1994/05/04 08:27:05 rgrimes Exp $
*/
#include "param.h"
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 554d38b004c4..67bd7e4786d8 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_synch.c 7.18 (Berkeley) 6/27/91
- * $Id: kern_synch.c,v 1.4 1994/02/11 21:14:28 guido Exp $
+ * $Id: kern_synch.c,v 1.5 1994/03/20 00:33:06 wollman Exp $
*/
#include "param.h"
@@ -381,7 +381,7 @@ endtsleep(arg1, dummy)
splx(s);
}
-#if 1 /* XXX this should go away... */
+#if 0 /* This is obsolete, use tsleep(). */
/*
* Short-term, non-interruptable sleep.
*/
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index a0c4a117bb2f..3be34ee22d8e 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)kern_time.c 7.15 (Berkeley) 3/17/91
- * $Id: kern_time.c,v 1.4 1993/11/25 01:33:14 wollman Exp $
+ * $Id: kern_time.c,v 1.5 1994/06/22 05:52:47 jkh Exp $
*/
#include "param.h"
@@ -103,7 +103,9 @@ settimeofday(p, uap, retval)
return (error);
/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
boottime.tv_sec += atv.tv_sec - time.tv_sec;
- s = splhigh(); time = atv; splx(s);
+ s = splclock();
+ time.tv_sec = atv.tv_sec; /* XXX avoid skew in tv_usec */
+ splx(s);
resettodr();
}
if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh
index 77f61280c1bd..60826dfc4106 100644
--- a/sys/kern/makesyscalls.sh
+++ b/sys/kern/makesyscalls.sh
@@ -1,6 +1,6 @@
#! /bin/sh -
# from: @(#)makesyscalls.sh 7.6 (Berkeley) 4/20/91
-# $Id: makesyscalls.sh,v 1.3 1993/11/07 21:22:30 wollman Exp $
+# $Id: makesyscalls.sh,v 1.4 1994/06/01 21:13:53 phk Exp $
set -e
@@ -162,7 +162,7 @@ awk < $1 "
printf("\n#else /* %s */\n", compat) > syscompat
printf("#define compat(n, name) 0, nosys\n") > syscompat
printf("#endif /* %s */\n\n", compat) > syscompat
- printf("#endif /* _SYS_SYSCALL_H_ */") > syshdr
+ printf("#endif /* _SYS_SYSCALL_H_ */\n") > syshdr
printf("};\n\n") > sysent
printf("int\tnsysent = sizeof(sysent) / sizeof(sysent[0]);\n") > sysent
diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c
index dd7a7c8be283..13ea715bef69 100644
--- a/sys/kern/spec_vnops.c
+++ b/sys/kern/spec_vnops.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)spec_vnops.c 7.37 (Berkeley) 5/30/91
- * $Id: spec_vnops.c,v 1.3 1993/11/25 01:33:15 wollman Exp $
+ * $Id: spec_vnops.c,v 1.4 1994/05/30 03:20:08 ache Exp $
*/
#include "param.h"
@@ -137,7 +137,9 @@ spec_open(vp, mode, cred, p)
if ((u_int)maj >= nchrdev)
return (ENXIO);
VOP_UNLOCK(vp);
+ vp->v_opencount++;
error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p);
+ --vp->v_opencount;
VOP_LOCK(vp);
return (error);
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index 6d4a61735965..afe2ddc99f36 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)subr_prf.c 7.30 (Berkeley) 6/29/91
- * $Id: subr_prf.c,v 1.6.2.1 1994/05/04 07:54:49 rgrimes Exp $
+ * $Id: subr_prf.c,v 1.8 1994/05/04 08:27:06 rgrimes Exp $
*/
#include "param.h"
@@ -87,7 +87,6 @@ static void logpri __P((int level));
static void putchar __P((int ch, int flags, struct tty *tp));
static char *ksprintn __P((u_long num, int base, int *len));
void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list));
-volatile void boot(int bootopt);
/*
* Variable panicstr contains argument to first call to panic; used
@@ -106,14 +105,8 @@ int msgbufmapped;
* and then reboots. If we are called twice, then we avoid trying to sync
* the disks as this often leads to recursive panics.
*/
-#ifdef __STDC__
-volatile void
-panic(const char *msg)
-#else
void
-panic(msg)
- char *msg;
-#endif
+panic(const char *msg)
{
int bootopt = RB_AUTOBOOT | RB_DUMP;
diff --git a/sys/kern/subr_rand.c b/sys/kern/subr_rand.c
new file mode 100644
index 000000000000..09f36a7d630a
--- /dev/null
+++ b/sys/kern/subr_rand.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1993 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+
+/*
+ * LBL BSD kernel random number generator (used by statclock).
+ *
+ * Written by Steve McCanne & Chris Torek (mccanne@ee.lbl.gov,
+ * torek@ee.lbl.gov), November, 1992.
+ *
+ * This implementation is based on ``Two Fast Implementations of
+ * the "Minimal Standard" Random Number Generator", David G. Carta,
+ * Communications of the ACM, Jan 1990, Vol 33 No 1.
+ */
+
+#ifdef sparc
+asm("\
+ .global _kernrand ;\
+_kernrand: ;\
+ sethi %hi(16807), %o1 ;\
+ wr %o1, %lo(16807), %y ;\
+ set 0xffff, %o4 ;\
+ andcc %g0, 0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %o0, %o2 ;\
+ mulscc %o2, %g0, %o2 ;\
+ rd %y, %o3 ;\
+ srl %o2, 16, %o1 ;\
+ and %o4, %o2, %o0 ;\
+ sll %o0, 15, %o0 ;\
+ srl %o3, 17, %o3 ;\
+ or %o3, %o0, %o0 ;\
+ addcc %o0, %o1, %o0 ;\
+ bl 1f ;\
+ sethi %hi(0x7fffffff), %o1 ;\
+ retl ;\
+ nop ;\
+1: ;\
+ or %o1, %lo(0x7fffffff), %o1 ;\
+ add %o0, 1, %o0 ;\
+ retl ;\
+ and %o1, %o0, %o0 ");
+#else
+long
+kernrand(x)
+ register long x;
+{
+ register long hi, lo, t;
+
+ hi = x / 127773;
+ lo = x % 127773;
+ t = 16807 * lo - 2836 * hi;
+ if (t > 0)
+ return (t);
+ else
+ return (t + 0x7fffffff);
+}
+#endif
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index b129f4f4d5bd..43f036c62568 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)sys_process.c 7.22 (Berkeley) 5/11/91
- * $Id: sys_process.c,v 1.9.2.2 1994/05/03 20:44:01 rgrimes Exp $
+ * $Id: sys_process.c,v 1.11 1994/04/02 23:03:01 jkh Exp $
*/
#include "param.h"
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 2f624acebcf7..1a65f4f70a44 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -2,7 +2,7 @@
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $
+ * created from $Id: syscalls.master,v 1.9 1994/03/15 01:58:33 wollman Exp $
*/
char *syscallnames[] = {
@@ -218,8 +218,8 @@ char *syscallnames[] = {
"#172", /* 172 = nosys */
"#173", /* 173 = nosys */
"#174", /* 174 = nosys */
- "#175", /* 175 = nosys */
- "#176", /* 176 = nosys */
+ "ntp_gettime", /* 175 = ntp_gettime */
+ "ntp_adjtime", /* 176 = ntp_adjtime */
#ifdef MACHVMCOMPAT
"vm_allocate", /* 177 = vm_allocate */
"vm_deallocate", /* 178 = vm_deallocate */
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index a43845ebd1a4..db30a9330979 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
- $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $
+ $Id: syscalls.master,v 1.9 1994/03/15 01:58:33 wollman Exp $
; from: @(#)syscalls.master 7.26 (Berkeley) 3/25/91
; System call name/number master file.
; Processed to created init_sysent.c, syscalls.c and syscall.h.
@@ -243,8 +243,8 @@
172 UNIMPL 0 nosys
173 UNIMPL 0 nosys
174 UNIMPL 0 nosys
-175 UNIMPL 0 nosys
-176 UNIMPL 0 nosys
+175 STD 1 ntp_gettime
+176 STD 1 ntp_adjtime
#ifdef MACHVMCOMPAT
177 STD 4 svm_allocate vm_allocate
178 STD 3 svm_deallocate vm_deallocate
diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c
index f861f53ece52..ff442d05b2cb 100644
--- a/sys/kern/sysv_msg.c
+++ b/sys/kern/sysv_msg.c
@@ -149,7 +149,7 @@ struct msgctl_args {
struct msqid_ds *user_msqptr;
};
-int
+static int
msgctl(p, uap, retval)
struct proc *p;
register struct msgctl_args *uap;
@@ -309,7 +309,7 @@ struct msgget_args {
int msgflg;
};
-int
+static int
msgget(p, uap, retval)
struct proc *p;
register struct msgget_args *uap;
@@ -766,7 +766,7 @@ struct msgrcv_args {
int msgflg;
};
-int
+static int
msgrcv(p, uap, retval)
struct proc *p;
register struct msgrcv_args *uap;
diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
index 6344018d9514..dbada0d09aad 100644
--- a/sys/kern/sysv_sem.c
+++ b/sys/kern/sysv_sem.c
@@ -62,7 +62,7 @@ semsys(p, uap, retval)
{
while ( semlock_holder != NULL && semlock_holder != p ) {
/* printf("semaphore facility locked - sleeping ...\n"); */
- sleep( (caddr_t)&semlock_holder, (PZERO - 4) );
+ tsleep( (caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0 );
}
if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
@@ -89,7 +89,7 @@ struct semconfig_args {
semconfig_ctl_t flag;
};
-int
+static int
semconfig(p, uap, retval)
struct proc *p;
struct semconfig_args *uap;
@@ -324,7 +324,7 @@ struct semctl_args {
union semun *arg;
};
-int
+static int
semctl(p, uap, retval)
struct proc *p;
register struct semctl_args *uap;
@@ -556,7 +556,7 @@ struct semget_args {
int semflg;
};
-int
+static int
semget(p, uap, retval)
struct proc *p;
register struct semget_args *uap;
@@ -676,7 +676,7 @@ struct semop_args {
int nsops;
};
-int
+static int
semop(p, uap, retval)
struct proc *p;
register struct semop_args *uap;
@@ -1007,7 +1007,7 @@ semexit(p)
#ifdef SEM_DEBUG
printf("semaphore facility locked - sleeping ...\n");
#endif
- sleep( (caddr_t)&semlock_holder, (PZERO - 4) );
+ tsleep( (caddr_t)&semlock_holder, (PZERO - 4), "semexit", 0 );
}
did_something = 0;
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index 00f123f529c5..3c7a45749583 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -37,7 +37,7 @@
*
* from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$
* from: @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91
- * $Id: sysv_shm.c,v 1.9 1994/01/21 09:56:31 davidg Exp $
+ * $Id: sysv_shm.c,v 1.12 1994/03/08 14:08:14 ats Exp $
*/
/*
@@ -69,7 +69,7 @@
struct shmid_ds *shmsegs;
struct shminfo shminfo;
-int shmat(), shmctl(), shmdt(), shmget(); /* XXX */
+static int shmat(), shmctl(), shmdt(), shmget(); /* XXX */
int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget }; /* XXX */
int shmtot = 0;
@@ -90,7 +90,7 @@ struct shmhandle {
caddr_t shmh_id;
};
-static int ipcaccess(struct ipc_perm *, int, struct ucred *);
+extern int ipcaccess(struct ipc_perm *, int, struct ucred *);
static void shmufree(struct proc *, struct shmdesc *);
static void shmfree(struct shmid_ds *);
static int shmvalid(int);
@@ -146,7 +146,7 @@ struct shmget_args {
int shmflg;
};
-int
+static int
shmget(p, uap, retval)
struct proc *p;
register struct shmget_args *uap;
@@ -244,7 +244,7 @@ struct shmctl_args {
};
/* ARGSUSED */
-int
+static int
shmctl(p, uap, retval)
struct proc *p;
register struct shmctl_args *uap;
@@ -316,7 +316,7 @@ struct shmat_args {
int shmflg;
};
-int
+static int
shmat(p, uap, retval)
struct proc *p;
register struct shmat_args *uap;
@@ -402,7 +402,7 @@ struct shmdt_args {
};
/* ARGSUSED */
-int
+static int
shmdt(p, uap, retval)
struct proc *p;
struct shmdt_args *uap;
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 519b910ccfdb..146aa1545efe 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -32,7 +32,22 @@
* SUCH DAMAGE.
*
* from: @(#)tty.c 7.44 (Berkeley) 5/28/91
- * $Id: tty.c,v 1.19.2.1 1994/03/24 08:19:44 rgrimes Exp $
+ * $Id: tty.c,v 1.32 1994/05/30 21:53:17 ache Exp $
+ */
+
+/*-
+ * TODO:
+ * o Fix races for sending the start char in ttyflush().
+ * o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttselect().
+ * With luck, there will be MIN chars before select() returns().
+ * o Handle CLOCAL consistently for ptys. Perhaps disallow setting it.
+ * o Don't allow input in TS_ZOMBIE case. It would be visible through
+ * FIONREAD.
+ * o Do the new sio locking stuff here and use it to avoid special
+ * case for EXTPROC?
+ * o Lock PENDIN too?
+ * o Move EXTPROC and/or PENDIN to t_state?
+ * o Wrap most of ttioctl in spltty/splx.
*/
#include "param.h"
@@ -47,6 +62,7 @@
#include "dkstat.h"
#include "uio.h"
#include "kernel.h"
+#include "malloc.h"
#include "vnode.h"
#include "syslog.h"
#include "signalvar.h"
@@ -64,11 +80,12 @@
#define I_LOW_WATER ((TTYHOG - 2 * 256) * 7 / 8) /* XXX */
/* XXX RB_LEN() is too slow. */
-#define INPUT_LEN(tp) (RB_LEN(&(tp)->t_can) + RB_LEN(&(tp)->t_raw))
+#define INPUT_LEN(tp) (RB_LEN((tp)->t_can) + RB_LEN((tp)->t_raw))
#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */
#define MAX_INPUT TTYHOG
static int proc_compare __P((struct proc *p1, struct proc *p2));
+static int ttnread(struct tty *tp);
static void ttyblock __P((struct tty *tp));
static void ttyecho __P((int c, struct tty *tp));
static int ttyoutput __P((int c, register struct tty *tp));
@@ -79,14 +96,6 @@ static void ttyrub __P((int c, struct tty *tp));
static void ttyrubo __P((struct tty *tp, int cnt));
static void ttyunblock __P((struct tty *tp));
-/* symbolic sleep message strings */
-const char ttyin[] = "ttyin";
-const char ttyout[] = "ttyout";
-const char ttopen[] = "ttyopn";
-const char ttclos[] = "ttycls";
-const char ttybg[] = "ttybg";
-const char ttybuf[] = "ttybuf";
-
/*
* Table giving parity for characters and indicating
* character classes to tty driver. The 8th bit
@@ -172,11 +181,19 @@ extern int nldisp;
(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
void
+termioschars(t)
+ struct termios *t;
+{
+
+ bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
+}
+
+void
ttychars(tp)
struct tty *tp;
{
- bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
+ termioschars(&tp->t_termios);
}
/*
@@ -202,36 +219,18 @@ ttywait(tp)
{
int error = 0, s = spltty();
- while ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
- (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
- tp->t_oproc) {
- /*
- * XXX temporary fix for deadlock.
- *
- * If two processes wait for output to drain from the same
- * tty, and the amount of output to drain is > 0 and
- * <= tp->t_lowat, then the processes will take turns
- * uselessly waking each other up until the output drains,
- * with cpl higher than spltty() throughout.
- *
- * The sleep address and TS_ASLEEP flag ought to be different
- * for the different events (output done) and (output almost
- * done).
- */
- tp->t_lowat = 0;
-
+ while ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+ CAN_DO_IO(tp) && tp->t_oproc) {
(*tp->t_oproc)(tp);
- if ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
- (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL)) {
- tp->t_state |= TS_ASLEEP;
- if (error = ttysleep(tp, (caddr_t)&tp->t_out,
+ if ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+ CAN_DO_IO(tp)) {
+ tp->t_state |= TS_SO_OCOMPLETE;
+ if (error = ttysleep(tp, TSA_OCOMPLETE(tp),
TTOPRI | PCATCH, "ttywai", 0))
break;
} else
break;
}
- if (tp->t_lowat == 0)
- ttsetwater(tp);
splx(s);
return (error);
}
@@ -257,21 +256,17 @@ ttyflush(tp, rw)
tp->t_state &= ~TS_TTSTOP;
(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
if (rw & FREAD) {
- flushq(&tp->t_can);
- flushq(&tp->t_raw);
+ flushq(tp->t_can);
+ flushq(tp->t_raw);
+ tp->t_lflag &= ~PENDIN;
tp->t_rocount = 0;
tp->t_rocol = 0;
tp->t_state &= ~TS_LOCAL;
ttwakeup(tp);
}
if (rw & FWRITE) {
- flushq(&tp->t_out);
- wakeup((caddr_t)&tp->t_out);
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
+ flushq(tp->t_out);
+ ttwwakeup(tp);
}
if (rw & FREAD) {
if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW)
@@ -286,16 +281,19 @@ ttyflush(tp, rw)
* is still tricky because we don't want to add a
* new obstruction to draining the output queue.
*/
- out_cc = RB_LEN(&tp->t_out);
+ out_cc = RB_LEN(tp->t_out);
t_state = tp->t_state;
ttyunblock(tp);
tp->t_state &= ~TS_TBLOCK;
- if (t_state & TS_TBLOCK && RB_LEN(&tp->t_out) != 0)
- ttysleep(tp, (caddr_t)&tp->t_out, TTIPRI,
+ if (t_state & TS_TBLOCK && RB_LEN(tp->t_out) != 0) {
+ tp->t_state |= TS_SO_OCOMPLETE;
+ ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI,
"ttyfls", hz / 10);
- if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) {
+ }
+ if (out_cc != 0 && RB_LEN(tp->t_out) != 0) {
(*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE);
- flushq(&tp->t_out);
+ flushq(tp->t_out);
+ ttwwakeup(tp);
}
}
}
@@ -314,7 +312,7 @@ ttyblock(tp)
if ((tp->t_state & TS_TBLOCK) == 0
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
- && putc(tp->t_cc[VSTOP], &tp->t_out) == 0)
+ && putc(tp->t_cc[VSTOP], tp->t_out) == 0)
tp->t_state |= TS_TBLOCK;
if (tp->t_cflag & CDTR_IFLOW)
tp->t_state |= TS_DTR_IFLOW;
@@ -334,7 +332,7 @@ ttyunblock(tp)
if (tp->t_state & TS_TBLOCK
&& tp->t_cc[VSTART] != _POSIX_VDISABLE
- && putc(tp->t_cc[VSTART], &tp->t_out) == 0)
+ && putc(tp->t_cc[VSTART], tp->t_out) == 0)
tp->t_state &= ~TS_TBLOCK;
tp->t_state &= ~TS_HW_IFLOW;
ttstart(tp);
@@ -413,7 +411,7 @@ ttioctl(tp, com, data, flag)
(p->p_sigmask & sigmask(SIGTTOU)) == 0) {
pgsignal(p->p_pgrp, SIGTTOU, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt,
- TTOPRI | PCATCH, ttybg, 0))
+ TTOPRI | PCATCH, "ttybg1", 0))
return (error);
}
break;
@@ -490,11 +488,15 @@ ttioctl(tp, com, data, flag)
/* return number of characters immediately available */
case FIONREAD:
+ s = spltty();
*(off_t *)data = ttnread(tp);
+ splx(s);
break;
case TIOCOUTQ:
- *(int *)data = RB_LEN(&tp->t_out);
+ s = spltty();
+ *(int *)data = RB_LEN(tp->t_out);
+ splx(s);
break;
case TIOCSTOP:
@@ -555,47 +557,27 @@ ttioctl(tp, com, data, flag)
if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
splx(s);
return (error);
- } else {
- /*
- * XXX doubtful. We mostly check both CLOCAL
- * and TS_CARR_ON before doing anything, and
- * changing TS_ISOPEN here just give another
- * flag to worry about, and is probably
- * inconsistent with not changing TS_ISOPEN
- * when carrier drops or CLOCAL rises. OTOH
- * we should maintain a flag to keep track
- * of the combination of CLOCAL and TS_CARR_ON.
- * This could be just TS_CARR_ON (if we don't
- * need to
- *
- * XXX ttselect() doesn't worry about
- * TS_ISOPEN, so it is inconsistent with
- * ttread() after TS_ISOPEN gets cleared here.
- */
- if ((tp->t_state&TS_CARR_ON) == 0 &&
- (tp->t_cflag&CLOCAL) &&
- (t->c_cflag&CLOCAL) == 0) {
- tp->t_state &= ~TS_ISOPEN;
- tp->t_state |= TS_WOPEN;
- ttwakeup(tp);
- }
- tp->t_cflag = t->c_cflag;
- tp->t_ispeed = t->c_ispeed;
- tp->t_ospeed = t->c_ospeed;
}
+ if (t->c_cflag & CLOCAL && !(tp->t_cflag & CLOCAL)) {
+ wakeup(TSA_CARR_ON(tp));
+ ttwakeup(tp);
+ ttwwakeup(tp);
+ }
+ tp->t_cflag = t->c_cflag;
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
ttsetwater(tp);
}
- if (com != TIOCSETAF) {
- if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
- if (t->c_lflag&ICANON) {
- tp->t_lflag |= PENDIN;
- ttwakeup(tp);
- }
+ if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON) &&
+ com != TIOCSETAF) {
+ if (t->c_lflag&ICANON)
+ t->c_lflag |= PENDIN;
else {
- catb(&tp->t_raw, &tp->t_can);
- catb(&tp->t_can, &tp->t_raw);
+ catb(tp->t_raw, tp->t_can);
+ catb(tp->t_can, tp->t_raw);
}
- }
+ ttwakeup(tp);
+ }
tp->t_iflag = t->c_iflag;
tp->t_oflag = t->c_oflag;
/*
@@ -606,6 +588,9 @@ ttioctl(tp, com, data, flag)
else
t->c_lflag &= ~EXTPROC;
tp->t_lflag = t->c_lflag;
+ if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
+ t->c_cc[VTIME] != tp->t_cc[VTIME])
+ ttwakeup(tp);
bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
splx(s);
break;
@@ -640,7 +625,13 @@ ttioctl(tp, com, data, flag)
case TIOCSPGRP: {
register struct pgrp *pgrp = pgfind(*(int *)data);
+#ifdef broken_for_F_SETOWN
+ if (!suser(p->p_ucred, &p->p_acflag))
+ ;
+ else if (!isctty(p, tp))
+#else
if (!isctty(p, tp))
+#endif
return (ENOTTY);
else if (pgrp == NULL || pgrp->pg_session != p->p_session)
return (EPERM);
@@ -668,9 +659,7 @@ ttioctl(tp, com, data, flag)
case TIOCCONS:
if (*(int *)data) {
- if (constty && constty != tp &&
- (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
- (TS_CARR_ON|TS_ISOPEN))
+ if (constty && constty != tp && CAN_DO_IO(constty))
return (EBUSY);
#ifndef UCONSOLE
if (error = suser(p->p_ucred, &p->p_acflag))
@@ -696,19 +685,21 @@ ttioctl(tp, com, data, flag)
return (0);
}
-int
+/*
+ * Call at spltty().
+ */
+static int
ttnread(tp)
struct tty *tp;
{
int nread = 0;
- /* XXX races. */
if (tp->t_lflag & PENDIN)
ttypend(tp);
- nread = RB_LEN(&tp->t_can);
+ nread = RB_LEN(tp->t_can);
if ((tp->t_lflag & ICANON) == 0) {
- nread += RB_LEN(&tp->t_raw);
- if (nread < tp->t_cc[VMIN])
+ nread += RB_LEN(tp->t_raw);
+ if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
nread = 0;
}
return (nread);
@@ -720,17 +711,14 @@ ttselect(dev, rw, p)
int rw;
struct proc *p;
{
- register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
- int nread;
+ register struct tty *tp = cdevsw[major(dev)].d_ttys[minor(dev)];
int s = spltty();
struct proc *selp;
switch (rw) {
case FREAD:
- nread = ttnread(tp);
- if (nread > 0 ||
- ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+ if (ttnread(tp) > 0 || tp->t_state & TS_ZOMBIE)
goto win;
if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_RCOLL;
@@ -739,7 +727,8 @@ ttselect(dev, rw, p)
break;
case FWRITE:
- if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+ if (RB_LEN(tp->t_out) <= tp->t_lowat && CAN_DO_IO(tp)
+ || tp->t_state & TS_ZOMBIE)
goto win;
if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_WCOLL;
@@ -766,12 +755,11 @@ ttyopen(dev, tp, dummy)
tp->t_dev = dev;
- tp->t_state &= ~TS_WOPEN;
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_state |= TS_ISOPEN;
- initrb(&tp->t_raw);
- initrb(&tp->t_can);
- initrb(&tp->t_out);
+ initrb(tp->t_raw);
+ initrb(tp->t_can);
+ initrb(tp->t_out);
bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
}
return (0);
@@ -793,7 +781,7 @@ ttylclose(tp, flag)
}
/*
- * Handle close() on a tty line: flush and set to initial state,
+ * Handle close() on a tty line: set to initial state,
* bumping generation number so that pending read/write calls
* can detect recycling of the tty.
*/
@@ -803,7 +791,6 @@ ttyclose(tp)
{
if (constty == tp)
constty = NULL;
- ttyflush(tp, FREAD|FWRITE);
tp->t_session = NULL;
tp->t_pgrp = NULL;
tp->t_state = 0;
@@ -822,7 +809,7 @@ ttymodem(tp, flag)
int flag;
{
- if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
+ if (tp->t_state & TS_CARR_ON && tp->t_lflag & MDMBUF) {
/*
* MDMBUF: do flow control according to carrier flag
*/
@@ -839,6 +826,7 @@ ttymodem(tp, flag)
*/
tp->t_state &= ~TS_CARR_ON;
if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
+ tp->t_state |= TS_ZOMBIE;
if (tp->t_session && tp->t_session->s_leader)
psignal(tp->t_session->s_leader, SIGHUP);
ttyflush(tp, FREAD|FWRITE);
@@ -849,30 +837,9 @@ ttymodem(tp, flag)
* Carrier now on.
*/
tp->t_state |= TS_CARR_ON;
+ wakeup(TSA_CARR_ON(tp));
ttwakeup(tp);
- }
- return (1);
-}
-
-/*
- * Default modem control routine (for other line disciplines).
- * Return argument flag, to turn off device on carrier drop.
- */
-int
-nullmodem(tp, flag)
- register struct tty *tp;
- int flag;
-{
-
- if (flag)
- tp->t_state |= TS_CARR_ON;
- else {
- tp->t_state &= ~TS_CARR_ON;
- if ((tp->t_cflag&CLOCAL) == 0) {
- if (tp->t_session && tp->t_session->s_leader)
- psignal(tp->t_session->s_leader, SIGHUP);
- return (0);
- }
+ ttwwakeup(tp);
}
return (1);
}
@@ -889,12 +856,12 @@ ttypend(tp)
tp->t_lflag &= ~PENDIN;
tp->t_state |= TS_TYPEN;
- hd = tp->t_raw.rb_hd;
- tl = tp->t_raw.rb_tl;
- flushq(&tp->t_raw);
+ hd = tp->t_raw->rb_hd;
+ tl = tp->t_raw->rb_tl;
+ flushq(tp->t_raw);
while (hd != tl) {
ttyinput(*hd, tp);
- hd = RB_SUCC(&tp->t_raw, hd);
+ hd = RB_SUCC(tp->t_raw, hd);
}
tp->t_state &= ~TS_TYPEN;
}
@@ -937,7 +904,7 @@ ttyinput(c, tp)
if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0
|| tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0)
&& INPUT_LEN(tp) > I_HIGH_WATER - 3
- && ((lflag & ICANON) == 0 || RB_LEN(&tp->t_can) != 0))
+ && ((lflag & ICANON) == 0 || RB_LEN(tp->t_can) != 0))
ttyblock(tp);
/*
* Handle exceptional conditions (break, parity, framing).
@@ -959,9 +926,9 @@ ttyinput(c, tp)
parmrk:
if (INPUT_LEN(tp) > MAX_INPUT - 3)
goto input_overflow;
- putc(0377|TTY_QUOTE, &tp->t_raw);
- putc(0|TTY_QUOTE, &tp->t_raw);
- putc(c|TTY_QUOTE, &tp->t_raw);
+ putc(0377|TTY_QUOTE, tp->t_raw);
+ putc(0|TTY_QUOTE, tp->t_raw);
+ putc(c|TTY_QUOTE, tp->t_raw);
goto endcase;
} else
c = 0;
@@ -1074,23 +1041,23 @@ parmrk:
* erase (^H / ^?)
*/
if (CCEQ(cc[VERASE], c)) {
- if (RB_LEN(&tp->t_raw))
- ttyrub(unputc(&tp->t_raw), tp);
+ if (RB_LEN(tp->t_raw))
+ ttyrub(unputc(tp->t_raw), tp);
goto endcase;
}
/*
* kill (^U)
*/
if (CCEQ(cc[VKILL], c)) {
- if (lflag&ECHOKE && RB_LEN(&tp->t_raw) == tp->t_rocount &&
+ if (lflag&ECHOKE && RB_LEN(tp->t_raw) == tp->t_rocount &&
(lflag&ECHOPRT) == 0) {
- while (RB_LEN(&tp->t_raw))
- ttyrub(unputc(&tp->t_raw), tp);
+ while (RB_LEN(tp->t_raw))
+ ttyrub(unputc(tp->t_raw), tp);
} else {
ttyecho(c, tp);
if (lflag&ECHOK || lflag&ECHOKE)
ttyecho('\n', tp);
- while (getc(&tp->t_raw) > 0)
+ while (getc(tp->t_raw) > 0)
;
tp->t_rocount = 0;
}
@@ -1106,7 +1073,7 @@ parmrk:
/*
* erase whitespace
*/
- while ((c = unputc(&tp->t_raw)) == ' ' || c == '\t')
+ while ((c = unputc(tp->t_raw)) == ' ' || c == '\t')
ttyrub(c, tp);
if (c == -1)
goto endcase;
@@ -1115,14 +1082,14 @@ parmrk:
* next chars type (for ALTWERASE)
*/
ttyrub(c, tp);
- c = unputc(&tp->t_raw);
+ c = unputc(tp->t_raw);
if (c == -1)
goto endcase;
/*
* Handle one-letter word cases.
*/
if (c == ' ' || c == '\t') {
- putc(c, &tp->t_raw);
+ putc(c, tp->t_raw);
goto endcase;
}
ctype = ISALPHA(c);
@@ -1131,13 +1098,13 @@ parmrk:
*/
do {
ttyrub(c, tp);
- c = unputc(&tp->t_raw);
+ c = unputc(tp->t_raw);
if (c == -1)
goto endcase;
} while (c != ' ' && c != '\t' &&
((lflag & ALTWERASE) == 0
|| ISALPHA(c) == ctype));
- (void) putc(c, &tp->t_raw);
+ (void) putc(c, tp->t_raw);
goto endcase;
}
/*
@@ -1163,7 +1130,7 @@ parmrk:
if (INPUT_LEN(tp) >= MAX_INPUT) {
input_overflow:
if (iflag&IMAXBEL) {
- if (RB_LEN(&tp->t_out) < tp->t_hiwat)
+ if (RB_LEN(tp->t_out) < tp->t_hiwat)
(void) ttyoutput(CTRL('g'), tp);
} else
ttyflush(tp, FREAD);
@@ -1173,7 +1140,7 @@ input_overflow:
* Put data char in q for user and
* wakeup on seeing a line delimiter.
*/
- if (putc(c, &tp->t_raw) >= 0) {
+ if (putc(c, tp->t_raw) >= 0) {
if ((lflag&ICANON) == 0) {
ttwakeup(tp);
ttyecho(c, tp);
@@ -1181,7 +1148,7 @@ input_overflow:
}
if (ttbreakc(c)) {
tp->t_rocount = 0;
- catb(&tp->t_raw, &tp->t_can);
+ catb(tp->t_raw, tp->t_can);
ttwakeup(tp);
} else if (tp->t_rocount++ == 0)
tp->t_rocol = tp->t_col;
@@ -1236,7 +1203,7 @@ ttyoutput(c, tp)
if ((oflag&OPOST) == 0) {
if (tp->t_lflag&FLUSHO)
return (-1);
- if (putc(c, &tp->t_out))
+ if (putc(c, tp->t_out))
return (c);
tk_nout++;
tp->t_outcc++;
@@ -1261,17 +1228,17 @@ ttyoutput(c, tp)
#ifdef was
c -= b_to_q(" ", c, &tp->t_outq);
#else
- i = imin(c, RB_CONTIGPUT(&tp->t_out));
- bcopy(" ", tp->t_out.rb_tl, i);
- tp->t_out.rb_tl =
- RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
- i = imin(c - i, RB_CONTIGPUT(&tp->t_out));
+ i = imin(c, RB_CONTIGPUT(tp->t_out));
+ bcopy(" ", tp->t_out->rb_tl, i);
+ tp->t_out->rb_tl =
+ RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
+ i = imin(c - i, RB_CONTIGPUT(tp->t_out));
/* off end and still have space? */
if (i) {
- bcopy(" ", tp->t_out.rb_tl, i);
- tp->t_out.rb_tl =
- RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
+ bcopy(" ", tp->t_out->rb_tl, i);
+ tp->t_out->rb_tl =
+ RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
}
#endif
tk_nout += c;
@@ -1291,7 +1258,7 @@ ttyoutput(c, tp)
*/
if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
return (c);
- if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_out))
+ if ((tp->t_lflag&FLUSHO) == 0 && putc(c, tp->t_out))
return (c);
col = tp->t_col;
@@ -1342,8 +1309,8 @@ ttread(tp, uio, flag)
long slp = 0; /* XXX this should be renamed `timo'. */
loop:
- lflag = tp->t_lflag;
s = spltty();
+ lflag = tp->t_lflag;
/*
* take pending input first
*/
@@ -1351,6 +1318,7 @@ loop:
ttypend(tp);
splx(s); /* reduce latency */
s = spltty();
+ lflag = tp->t_lflag; /* XXX ttypend() clobbers it */
}
/*
@@ -1364,18 +1332,32 @@ loop:
return (EIO);
pgsignal(p->p_pgrp, SIGTTIN, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
- ttybg, 0))
+ "ttybg2", 0))
return (error);
goto loop;
}
+ if (tp->t_state & TS_ZOMBIE) {
+ splx(s);
+ return (0); /* EOF */
+ }
+
/*
* If canonical, use the canonical queue,
* else use the raw queue.
*/
- qp = lflag&ICANON ? &tp->t_can : &tp->t_raw;
+ qp = lflag&ICANON ? tp->t_can : tp->t_raw;
rblen = RB_LEN(qp);
-
+ if (flag & IO_NDELAY) {
+ if (rblen > 0)
+ goto read;
+ if ((lflag & ICANON) == 0 && cc[VMIN] == 0) {
+ splx(s);
+ return (0);
+ }
+ splx(s);
+ return (EWOULDBLOCK);
+ }
if ((lflag & ICANON) == 0) {
int m = cc[VMIN];
long t = cc[VTIME];
@@ -1460,45 +1442,24 @@ loop:
goto sleep;
}
if (rblen <= 0) {
- int carrier;
-
sleep:
/*
- * If there is no input, sleep on rawq
- * awaiting hardware receipt and notification.
- * If we have data, we don't need to check for carrier.
+ * There is no input, or not enough input and we can block.
*/
- carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
- if (!carrier && tp->t_state&TS_ISOPEN) {
- splx(s);
- return (0); /* EOF */
- }
- if (flag & IO_NDELAY) {
- splx(s);
- return (EWOULDBLOCK);
- }
- if (slp) {
- /*
- * Use plain wakeup() not ttwakeup().
- * XXX why not use the timeout built into tsleep?
- */
- timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp);
- }
- error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- carrier ? ttyin : ttopen, 0);
- if (slp) {
- slp = 0;
- untimeout((timeout_func_t)wakeup, (caddr_t)qp);
- }
+ error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
+ CAN_DO_IO(tp) ? "ttyin" : "ttyhup", (int)slp);
splx(s);
- if (error)
+ if (error == EWOULDBLOCK)
+ error = 0;
+ else if (error)
return (error);
/*
- * XXX what happens if ICANON, MIN or TIME changes or
- * another process eats some input while we are asleep
- * (not just here)? It would be safest to detect changes
- * and reset our state variables (has_stime and last_cc).
+ * XXX what happens if another process eats some input
+ * while we are asleep (not just here)? It would be
+ * safest to detect changes and reset our state variables
+ * (has_stime and last_cc).
*/
+ slp = 0;
goto loop;
}
@@ -1548,7 +1509,8 @@ slowcase:
pgsignal(tp->t_pgrp, SIGTSTP, 1);
if (first) {
if (error = ttysleep(tp, (caddr_t)&lbolt,
- TTIPRI | PCATCH, ttybg, 0))
+ TTIPRI | PCATCH, "ttybg3",
+ 0))
break;
goto loop;
}
@@ -1612,17 +1574,17 @@ ttycheckoutq(tp, wait)
oldsig = curproc->p_sig;
else
oldsig = 0;
- if (RB_LEN(&tp->t_out) > hiwat + 200)
- while (RB_LEN(&tp->t_out) > hiwat) {
+ if (RB_LEN(tp->t_out) > hiwat + 200)
+ while (RB_LEN(tp->t_out) > hiwat) {
ttstart(tp);
+ if (RB_LEN(tp->t_out) <= hiwat)
+ break;
if (wait == 0 || (curproc && curproc->p_sig != oldsig)) {
splx(s);
return (0);
}
- timeout((timeout_func_t)wakeup, (caddr_t)&tp->t_out,
- hz); /* XXX */
- tp->t_state |= TS_ASLEEP;
- tsleep((caddr_t)&tp->t_out, PZERO - 1, "ttchout", 0);
+ tp->t_state |= TS_SO_OLOWAT;
+ tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttchout", hz);
}
splx(s);
return (1);
@@ -1648,20 +1610,20 @@ ttwrite(tp, uio, flag)
error = 0;
loop:
s = spltty();
- if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
- if (tp->t_state&TS_ISOPEN) {
- splx(s);
- return (EIO);
- } else if (flag & IO_NDELAY) {
+ if (tp->t_state & TS_ZOMBIE) {
+ splx(s);
+ if (uio->uio_resid == cnt)
+ error = EIO;
+ goto out;
+ }
+ if (!CAN_DO_IO(tp)) {
+ if (flag & IO_NDELAY) {
splx(s);
error = EWOULDBLOCK;
goto out;
} else {
- /*
- * sleep awaiting carrier
- */
- error = ttysleep(tp, (caddr_t)&tp->t_raw,
- TTIPRI | PCATCH,ttopen, 0);
+ error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "ttydcd", 0);
splx(s);
if (error)
goto out;
@@ -1679,7 +1641,7 @@ loop:
p->p_pgrp->pg_jobc) {
pgsignal(p->p_pgrp, SIGTTOU, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
- ttybg, 0))
+ "ttybg4", 0))
goto out;
goto loop;
}
@@ -1704,7 +1666,7 @@ loop:
* to fix this is messy because of all the gotos.
*/
s = spltty();
- if (RB_LEN(&tp->t_out) > hiwat) {
+ if (RB_LEN(tp->t_out) > hiwat) {
splx(s);
goto ovhiwat;
}
@@ -1748,14 +1710,14 @@ loop:
ttstart(tp);
if (error = ttysleep(tp,
(caddr_t)&lbolt,
- TTOPRI | PCATCH, ttybuf, 0))
+ TTOPRI | PCATCH, "ttybf1", 0))
break;
goto loop;
}
cp++, cc--;
s = spltty();
if ((tp->t_lflag&FLUSHO) ||
- RB_LEN(&tp->t_out) > hiwat) {
+ RB_LEN(tp->t_out) > hiwat) {
splx(s);
goto ovhiwat;
}
@@ -1778,18 +1740,18 @@ loop:
#else
i = ce;
s = spltty();
- ce = imin(ce, RB_CONTIGPUT(&tp->t_out));
- bcopy(cp, tp->t_out.rb_tl, ce);
- tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
- tp->t_out.rb_tl + ce);
+ ce = imin(ce, RB_CONTIGPUT(tp->t_out));
+ bcopy(cp, tp->t_out->rb_tl, ce);
+ tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+ tp->t_out->rb_tl + ce);
i -= ce;
if (i > 0) {
int ii;
- ii = imin(i, RB_CONTIGPUT(&tp->t_out));
- bcopy(cp + ce, tp->t_out.rb_tl, ii);
- tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
- tp->t_out.rb_tl + ii);
+ ii = imin(i, RB_CONTIGPUT(tp->t_out));
+ bcopy(cp + ce, tp->t_out->rb_tl, ii);
+ tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+ tp->t_out->rb_tl + ii);
i -= ii;
ce += ii;
}
@@ -1801,14 +1763,15 @@ loop:
if (i > 0) {
ttstart(tp);
s = spltty();
- if (RB_CONTIGPUT(&tp->t_out) > 0) {
+ if (RB_CONTIGPUT(tp->t_out) > 0) {
splx(s);
goto loop; /* synchronous/fast */
}
/* out of space, wait a bit */
- tp->t_state |= TS_ASLEEP;
- if (error = ttysleep(tp, (caddr_t)&tp->t_out,
- TTOPRI | PCATCH, ttybuf, 0)) {
+ tp->t_state |= TS_SO_OLOWAT;
+ if (error = ttysleep(tp, TSA_OLOWAT(tp),
+ TTOPRI | PCATCH, "ttybf2",
+ 0)) {
splx(s);
break;
}
@@ -1816,7 +1779,7 @@ loop:
goto loop;
}
s = spltty();
- if (tp->t_lflag&FLUSHO || RB_LEN(&tp->t_out) > hiwat) {
+ if (tp->t_lflag&FLUSHO || RB_LEN(tp->t_out) > hiwat) {
splx(s);
break;
}
@@ -1841,7 +1804,7 @@ ovhiwat:
* This can only occur if FLUSHO is set in t_lflag,
* or if ttstart/oproc is synchronous (or very fast).
*/
- if (RB_LEN(&tp->t_out) <= hiwat) {
+ if (RB_LEN(tp->t_out) <= hiwat) {
splx(s);
goto loop;
}
@@ -1852,8 +1815,8 @@ ovhiwat:
return (EWOULDBLOCK);
return (0);
}
- tp->t_state |= TS_ASLEEP;
- error = ttysleep(tp, (caddr_t)&tp->t_out, TTOPRI | PCATCH, ttyout, 0);
+ tp->t_state |= TS_SO_OLOWAT;
+ error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttyout", 0);
splx(s);
if (error)
goto out;
@@ -1904,7 +1867,7 @@ ttyrub(c, tp)
case TAB: {
int c;
- if (tp->t_rocount < RB_LEN(&tp->t_raw)) {
+ if (tp->t_rocount < RB_LEN(tp->t_raw)) {
ttyretype(tp);
return;
}
@@ -1913,9 +1876,9 @@ ttyrub(c, tp)
tp->t_state |= TS_CNTTB;
tp->t_lflag |= FLUSHO;
tp->t_col = tp->t_rocol;
- cp = tp->t_raw.rb_hd;
- for (c = nextc(&cp, &tp->t_raw); c ;
- c = nextc(&cp, &tp->t_raw))
+ cp = tp->t_raw->rb_hd;
+ for (c = nextc(&cp, tp->t_raw); c ;
+ c = nextc(&cp, tp->t_raw))
ttyecho(c, tp);
tp->t_lflag &= ~FLUSHO;
tp->t_state &= ~TS_CNTTB;
@@ -1979,16 +1942,16 @@ ttyretype(tp)
(void) ttyoutput('\n', tp);
s = spltty();
- cp = tp->t_can.rb_hd;
- for (c = nextc(&cp, &tp->t_can); c ; c = nextc(&cp, &tp->t_can))
+ cp = tp->t_can->rb_hd;
+ for (c = nextc(&cp, tp->t_can); c ; c = nextc(&cp, tp->t_can))
ttyecho(c, tp);
- cp = tp->t_raw.rb_hd;
- for (c = nextc(&cp, &tp->t_raw); c ; c = nextc(&cp, &tp->t_raw))
+ cp = tp->t_raw->rb_hd;
+ for (c = nextc(&cp, tp->t_raw); c ; c = nextc(&cp, tp->t_raw))
ttyecho(c, tp);
tp->t_state &= ~TS_ERASE;
splx(s);
- tp->t_rocount = RB_LEN(&tp->t_raw);
+ tp->t_rocount = RB_LEN(tp->t_raw);
tp->t_rocol = 0;
}
@@ -2049,7 +2012,31 @@ ttwakeup(tp)
}
if (tp->t_state & TS_ASYNC)
pgsignal(tp->t_pgrp, SIGIO, 1);
- wakeup((caddr_t)&tp->t_raw);
+ wakeup(TSA_HUP_OR_INPUT(tp));
+}
+
+/*
+ * Wake up any writers on a tty.
+ */
+void
+ttwwakeup(tp)
+ register struct tty *tp;
+{
+ if (RB_LEN(tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_SO_OCOMPLETE && RB_LEN(tp->t_out) == 0) {
+ tp->t_state &= ~TS_SO_OCOMPLETE;
+ wakeup(TSA_OCOMPLETE(tp));
+ }
+ if (tp->t_state & TS_SO_OLOWAT) {
+ tp->t_state &= ~TS_SO_OLOWAT;
+ wakeup(TSA_OLOWAT(tp));
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
}
/*
@@ -2099,7 +2086,7 @@ ttyinfo(tp)
{
register struct proc *p, *pick;
struct timeval utime, stime;
- int loadtmp;
+ int loadtmp, tmp;
if (ttycheckoutq(tp,0) == 0)
return;
@@ -2152,8 +2139,13 @@ ttyinfo(tp)
* Lock out clock if process is running; get user/system
* cpu time.
*/
+ tmp = 0;
+ if (curproc == pick)
+ tmp = splclock();
utime = pick->p_utime;
stime = pick->p_stime;
+ if (curproc == pick)
+ splx(tmp);
ttyprintf(tp, " cmd: %s %d [%s] ", comm, pid, wmesg);
@@ -2258,7 +2250,7 @@ tputchar(c, tp)
{
register s = spltty();
- if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
+ if (CAN_DO_IO(tp)) {
if (c == '\n')
(void) ttyoutput('\r', tp);
(void) ttyoutput(c, tp);
@@ -2293,3 +2285,56 @@ ttysleep(tp, chan, pri, wmesg, timo)
return (ERESTART);
return (0);
}
+
+/*
+ * Allocate a tty structure and its associated buffers.
+ */
+struct tty *
+ttymalloc(itp)
+ struct tty *itp;
+{
+ struct tty *tp;
+
+#ifndef broken
+ /*
+ * Note that the itp input is not necessary when we can dealloc
+ * the struct tty.
+ */
+ if(itp == NULL) {
+ MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
+ bzero(tp, sizeof *tp);
+ } else {
+ tp = itp;
+ }
+#endif
+ if(tp->t_raw == NULL) {
+ MALLOC(tp->t_raw, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_raw, sizeof *tp->t_raw);
+ }
+ if(tp->t_can == NULL) {
+ MALLOC(tp->t_can, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_can, sizeof *tp->t_can);
+ }
+ if(tp->t_out == NULL) {
+ MALLOC(tp->t_out, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_out, sizeof *tp->t_out);
+ }
+ return(tp);
+}
+
+/*
+ * Free a tty structure and its buffers.
+ */
+void
+ttyfree(tp)
+struct tty *tp;
+{
+ FREE(tp->t_raw, M_TTYS);
+ FREE(tp->t_can, M_TTYS);
+ FREE(tp->t_out, M_TTYS);
+ tp->t_raw = tp->t_can = tp->t_out = NULL;
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ /* also set tp to NULL when this isn't broken anymore */
+ FREE(tp, M_TTYS);
+#endif
+}
diff --git a/sys/kern/tty_conf.c b/sys/kern/tty_conf.c
index 6b9ad4917460..ce7016415a5c 100644
--- a/sys/kern/tty_conf.c
+++ b/sys/kern/tty_conf.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)tty_conf.c 7.6 (Berkeley) 5/9/91
- * $Id: tty_conf.c,v 1.6.2.1 1994/05/04 07:54:52 rgrimes Exp $
+ * $Id: tty_conf.c,v 1.9 1994/05/30 03:23:14 ache Exp $
*/
#include "param.h"
@@ -85,14 +85,14 @@ struct linesw linesw[] =
#if NTB > 0
tbopen, tbclose, tbread, IE(enodev), tbioctl,
- tbinput, enodev, nullop, ttstart, nullmodem, /* 3- TABLDISC */
+ tbinput, enodev, nullop, ttstart, ttymodem, /* 3- TABLDISC */
#else
IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev),
VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev),
#endif
#if NSL > 0
slopen, VE(slclose), IE(enodev), IE(enodev), sltioctl,
- VE(slinput), enodev, nullop, VE(slstart), nullmodem, /* 4- SLIPDISC */
+ VE(slinput), enodev, nullop, VE(slstart), ttymodem, /* 4- SLIPDISC */
#else
IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev),
VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev),
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index 0e99e9329e0a..8039fa952b94 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)tty_pty.c 7.21 (Berkeley) 5/30/91
- * $Id: tty_pty.c,v 1.9 1994/01/29 04:04:26 davidg Exp $
+ * $Id: tty_pty.c,v 1.14 1994/05/30 03:22:34 ache Exp $
*/
/*
@@ -66,7 +66,7 @@ static void ptcwakeup(struct tty *, int);
* pts == /dev/tty[pqrs]?
* ptc == /dev/pty[pqrs]?
*/
-struct tty pt_tty[NPTY];
+struct tty *pt_tty[NPTY];
struct pt_ioctl {
int pt_flags;
pid_t pt_selr, pt_selw;
@@ -75,13 +75,15 @@ struct pt_ioctl {
} pt_ioctl[NPTY];
int npty = NPTY; /* for pstat -t */
-#define PF_RCOLL 0x01
-#define PF_WCOLL 0x02
-#define PF_PKT 0x08 /* packet mode */
-#define PF_STOPPED 0x10 /* user told stopped */
-#define PF_REMOTE 0x20 /* remote and flow controlled input */
-#define PF_NOSTOP 0x40
-#define PF_UCNTL 0x80 /* user control mode */
+#define PF_RCOLL 0x0001
+#define PF_WCOLL 0x0002
+#define PF_PKT 0x0008 /* packet mode */
+#define PF_STOPPED 0x0010 /* user told stopped */
+#define PF_REMOTE 0x0020 /* remote and flow controlled input */
+#define PF_NOSTOP 0x0040
+#define PF_UCNTL 0x0080 /* user control mode */
+#define PF_COPEN 0x0100 /* master open */
+#define PF_SOPEN 0x0200 /* slave open */
/*ARGSUSED*/
int
@@ -99,9 +101,8 @@ ptsopen(dev, flag, devtype, p)
#endif
if (minor(dev) >= NPTY)
return (ENXIO);
- tp = &pt_tty[minor(dev)];
+ tp = pt_tty[minor(dev)] = ttymalloc(pt_tty[minor(dev)]);
if ((tp->t_state & TS_ISOPEN) == 0) {
- tp->t_state |= TS_WOPEN;
ttychars(tp); /* Set up default chars */
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
@@ -114,15 +115,17 @@ ptsopen(dev, flag, devtype, p)
if (tp->t_oproc) /* Ctrlr still around. */
tp->t_state |= TS_CARR_ON;
while ((tp->t_state & TS_CARR_ON) == 0) {
- tp->t_state |= TS_WOPEN;
if (flag&FNONBLOCK)
break;
- if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- ttopen, 0))
+ if (error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "ptsopn", 0))
return (error);
}
error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
- ptcwakeup(tp, FREAD|FWRITE);
+ if (error == 0) {
+ ptcwakeup(tp, FREAD|FWRITE);
+ pt_ioctl[minor(dev)].pt_flags |= PF_SOPEN;
+ }
return (error);
}
@@ -134,10 +137,17 @@ ptsclose(dev, flag, mode, p)
{
register struct tty *tp;
- tp = &pt_tty[minor(dev)];
+ tp = pt_tty[minor(dev)];
+ ptcwakeup(tp, FREAD|FWRITE);
(*linesw[tp->t_line].l_close)(tp, flag);
ttyclose(tp);
- ptcwakeup(tp, FREAD|FWRITE);
+ pt_ioctl[minor(dev)].pt_flags &= ~PF_SOPEN;
+ if ((pt_ioctl[minor(dev)].pt_flags & PF_COPEN) == 0) {
+ ttyfree(tp);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ pt_tty[minor(dev)] = (struct tty *)NULL;
+#endif
+ }
return(0);
}
@@ -148,7 +158,7 @@ ptsread(dev, uio, flag)
int flag;
{
struct proc *p = curproc;
- register struct tty *tp = &pt_tty[minor(dev)];
+ register struct tty *tp = pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
@@ -162,25 +172,25 @@ again:
return (EIO);
pgsignal(p->p_pgrp, SIGTTIN, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt,
- TTIPRI | PCATCH, ttybg, 0))
+ TTIPRI | PCATCH, "ptsbg", 0))
return (error);
}
- if (RB_LEN(&tp->t_can) == 0) {
+ if (RB_LEN(tp->t_can) == 0) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
- if (error = ttysleep(tp, (caddr_t)&tp->t_can,
- TTIPRI | PCATCH, ttyin, 0))
+ if (error = ttysleep(tp, (caddr_t)tp->t_can,
+ TTIPRI | PCATCH, "ptsin", 0))
return (error);
goto again;
}
- while (RB_LEN(&tp->t_can) > 1 && uio->uio_resid > 0)
- if (ureadc(getc(&tp->t_can), uio) < 0) {
+ while (RB_LEN(tp->t_can) > 1 && uio->uio_resid > 0)
+ if (ureadc(getc(tp->t_can), uio) < 0) {
error = EFAULT;
break;
}
- if (RB_LEN(&tp->t_can) == 1)
- (void) getc(&tp->t_can);
- if (RB_LEN(&tp->t_can))
+ if (RB_LEN(tp->t_can) == 1)
+ (void) getc(tp->t_can);
+ if (RB_LEN(tp->t_can))
return (error);
} else
if (tp->t_oproc)
@@ -202,7 +212,7 @@ ptswrite(dev, uio, flag)
{
register struct tty *tp;
- tp = &pt_tty[minor(dev)];
+ tp = pt_tty[minor(dev)];
if (tp->t_oproc == 0)
return (EIO);
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
@@ -240,7 +250,7 @@ ptcwakeup(tp, flag)
pti->pt_selr = 0;
pti->pt_flags &= ~PF_RCOLL;
}
- wakeup((caddr_t)&tp->t_out.rb_tl);
+ wakeup(TSA_PTC_READ(tp));
}
if (flag & FWRITE) {
if (pti->pt_selw) {
@@ -248,7 +258,7 @@ ptcwakeup(tp, flag)
pti->pt_selw = 0;
pti->pt_flags &= ~PF_WCOLL;
}
- wakeup((caddr_t)&tp->t_raw.rb_hd);
+ wakeup(TSA_PTC_WRITE(tp));
}
}
@@ -268,14 +278,15 @@ ptcopen(dev, flag, devtype, p)
if (minor(dev) >= NPTY)
return (ENXIO);
- tp = &pt_tty[minor(dev)];
+ tp = pt_tty[minor(dev)] = ttymalloc(pt_tty[minor(dev)]);
if (tp->t_oproc)
return (EIO);
tp->t_oproc = ptsstart;
(void)(*linesw[tp->t_line].l_modem)(tp, 1);
tp->t_lflag &= ~EXTPROC;
pti = &pt_ioctl[minor(dev)];
- pti->pt_flags = 0;
+ pti->pt_flags &= PF_SOPEN;
+ pti->pt_flags |= PF_COPEN;
pti->pt_send = 0;
pti->pt_ucntl = 0;
return (0);
@@ -289,7 +300,7 @@ ptcclose(dev)
{
register struct tty *tp;
- tp = &pt_tty[minor(dev)];
+ tp = pt_tty[minor(dev)];
(void)(*linesw[tp->t_line].l_modem)(tp, 0);
tp->t_state &= ~TS_CARR_ON;
tp->t_oproc = 0; /* mark closed */
@@ -298,6 +309,13 @@ ptcclose(dev)
if (constty==tp)
constty = 0;
+ pt_ioctl[minor(dev)].pt_flags &= ~PF_COPEN;
+ if ((pt_ioctl[minor(dev)].pt_flags & PF_SOPEN) == 0) {
+ ttyfree(tp);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ pt_tty[minor(dev)] = (struct tty *)NULL;
+#endif
+ }
return (0);
}
@@ -307,7 +325,7 @@ ptcread(dev, uio, flag)
struct uio *uio;
int flag;
{
- register struct tty *tp = &pt_tty[minor(dev)];
+ register struct tty *tp = pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
char buf[BUFSIZ];
int error = 0, cc;
@@ -339,15 +357,15 @@ ptcread(dev, uio, flag)
pti->pt_ucntl = 0;
return (0);
}
- if (RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0)
+ if (RB_LEN(tp->t_out) && (tp->t_state&TS_TTSTOP) == 0)
break;
}
if ((tp->t_state&TS_CARR_ON) == 0)
return (0); /* EOF */
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
- if (error = tsleep((caddr_t)&tp->t_out.rb_tl, TTIPRI | PCATCH,
- ttyin, 0))
+ if (error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH,
+ "ptcin", 0))
return (error);
}
if (pti->pt_flags & (PF_PKT|PF_UCNTL))
@@ -356,28 +374,19 @@ ptcread(dev, uio, flag)
#ifdef was
cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
#else
- cc = min(MIN(uio->uio_resid, BUFSIZ), RB_CONTIGGET(&tp->t_out));
+ cc = min(MIN(uio->uio_resid, BUFSIZ), RB_CONTIGGET(tp->t_out));
if (cc) {
- bcopy(tp->t_out.rb_hd, buf, cc);
- tp->t_out.rb_hd =
- RB_ROLLOVER(&tp->t_out, tp->t_out.rb_hd+cc);
+ bcopy(tp->t_out->rb_hd, buf, cc);
+ tp->t_out->rb_hd =
+ RB_ROLLOVER(tp->t_out, tp->t_out->rb_hd+cc);
}
#endif
if (cc <= 0)
break;
error = uiomove(buf, cc, uio);
}
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
return (error);
}
@@ -411,7 +420,7 @@ ptcselect(dev, rw, p)
int rw;
struct proc *p;
{
- register struct tty *tp = &pt_tty[minor(dev)];
+ register struct tty *tp = pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
struct proc *prev;
int s;
@@ -426,7 +435,7 @@ ptcselect(dev, rw, p)
*/
s = spltty();
if ((tp->t_state&TS_ISOPEN) &&
- RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0) {
+ RB_LEN(tp->t_out) && (tp->t_state&TS_TTSTOP) == 0) {
splx(s);
return (1);
}
@@ -448,12 +457,12 @@ ptcselect(dev, rw, p)
case FWRITE:
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags & PF_REMOTE) {
- if (RB_LEN(&tp->t_can) == 0)
+ if (RB_LEN(tp->t_can) == 0)
return (1);
} else {
- if (RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can) < TTYHOG-2)
+ if (RB_LEN(tp->t_raw) + RB_LEN(tp->t_can) < TTYHOG-2)
return (1);
- if (RB_LEN(&tp->t_can) == 0 && (tp->t_iflag&ICANON))
+ if (RB_LEN(tp->t_can) == 0 && (tp->t_iflag&ICANON))
return (1);
}
}
@@ -473,7 +482,7 @@ ptcwrite(dev, uio, flag)
register struct uio *uio;
int flag;
{
- register struct tty *tp = &pt_tty[minor(dev)];
+ register struct tty *tp = pt_tty[minor(dev)];
register u_char *cp = 0;
register int cc = 0;
u_char locbuf[BUFSIZ];
@@ -485,12 +494,12 @@ again:
if ((tp->t_state&TS_ISOPEN) == 0)
goto block;
if (pti->pt_flags & PF_REMOTE) {
- if (RB_LEN(&tp->t_can))
+ if (RB_LEN(tp->t_can))
goto block;
- while (uio->uio_resid > 0 && RB_LEN(&tp->t_can) < TTYHOG - 1) {
+ while (uio->uio_resid > 0 && RB_LEN(tp->t_can) < TTYHOG - 1) {
if (cc == 0) {
cc = min(uio->uio_resid, BUFSIZ);
- cc = min(cc, RB_CONTIGPUT(&tp->t_can));
+ cc = min(cc, RB_CONTIGPUT(tp->t_can));
cp = locbuf;
error = uiomove((caddr_t)cp, cc, uio);
if (error)
@@ -504,16 +513,16 @@ again:
(void) b_to_q((char *)cp, cc, &tp->t_canq);
#else
if (cc) {
- bcopy(cp, tp->t_can.rb_tl, cc);
- tp->t_can.rb_tl =
- RB_ROLLOVER(&tp->t_can, tp->t_can.rb_tl+cc);
+ bcopy(cp, tp->t_can->rb_tl, cc);
+ tp->t_can->rb_tl =
+ RB_ROLLOVER(tp->t_can, tp->t_can->rb_tl+cc);
}
#endif
cc = 0;
}
- (void) putc(0, &tp->t_can);
+ (void) putc(0, tp->t_can);
ttwakeup(tp);
- wakeup((caddr_t)&tp->t_can);
+ wakeup((caddr_t)tp->t_can);
return (0);
}
while (uio->uio_resid > 0) {
@@ -528,9 +537,9 @@ again:
return (EIO);
}
while (cc > 0) {
- if ((RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can)) >= TTYHOG - 2 &&
- (RB_LEN(&tp->t_can) > 0 || !(tp->t_iflag&ICANON))) {
- wakeup((caddr_t)&tp->t_raw);
+ if ((RB_LEN(tp->t_raw) + RB_LEN(tp->t_can)) >= TTYHOG - 2 &&
+ (RB_LEN(tp->t_can) > 0 || !(tp->t_iflag&ICANON))) {
+ wakeup(TSA_HUP_OR_INPUT(tp));
goto block;
}
(*linesw[tp->t_line].l_rint)(*cp++, tp);
@@ -554,8 +563,8 @@ block:
return (EWOULDBLOCK);
return (0);
}
- if (error = tsleep((caddr_t)&tp->t_raw.rb_hd, TTOPRI | PCATCH,
- ttyout, 0)) {
+ if (error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH,
+ "ptcout", 0)) {
/* adjust for data copied in but not written */
uio->uio_resid += cc;
return (error);
@@ -571,7 +580,7 @@ ptyioctl(dev, cmd, data, flag)
dev_t dev;
int flag;
{
- register struct tty *tp = &pt_tty[minor(dev)];
+ register struct tty *tp = pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
register u_char *cc = tp->t_cc;
int stop, error;
@@ -648,7 +657,7 @@ ptyioctl(dev, cmd, data, flag)
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF:
- while (getc(&tp->t_out) >= 0)
+ while (getc(tp->t_out) >= 0)
;
break;
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index c0cf7a4c68cd..b735b0269666 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91
- * $Id: uipc_mbuf.c,v 1.6 1993/12/19 00:51:44 wollman Exp $
+ * $Id: uipc_mbuf.c,v 1.9 1994/06/11 23:06:35 paul Exp $
*/
#include "param.h"
@@ -312,7 +312,8 @@ m_copym(m, off0, len, wait)
n->m_len = MIN(len, m->m_len - off);
if (m->m_flags & M_EXT) {
n->m_data = m->m_data + off;
- mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
+ if (m->m_ext.ext_free == (void (*)())0)
+ mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
n->m_ext = m->m_ext;
n->m_flags |= M_EXT;
} else
@@ -441,8 +442,8 @@ m_adj(mp, req_len)
}
if (m->m_len >= len) {
m->m_len -= len;
- if ((mp = m)->m_flags & M_PKTHDR)
- m->m_pkthdr.len -= len;
+ if (mp->m_flags & M_PKTHDR)
+ mp->m_pkthdr.len -= len;
return;
}
count -= len;
@@ -639,7 +640,8 @@ extpacket:
if (m -> m_flags & M_EXT) {
n -> m_flags |= M_EXT;
n -> m_ext = m -> m_ext;
- mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
+ if (m->m_ext.ext_free == (void (*)())0)
+ mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
n -> m_data = m -> m_data + len;
} else {
bcopy (mtod (m, caddr_t) + len, mtod (n, caddr_t), remain);
@@ -724,11 +726,6 @@ m_compress(in, out)
(*out)->m_act = 0;
while (in) {
- if (in->m_flags & M_EXT) {
-#ifdef DEBUG
- ASSERT(in->m_len == 0);
-#endif
- }
if ( in->m_len == 0) {
in = in->m_next;
continue;
diff --git a/sys/kern/vfs__bio.c b/sys/kern/vfs__bio.c
index 2ccf2e6126b7..6868618e9293 100644
--- a/sys/kern/vfs__bio.c
+++ b/sys/kern/vfs__bio.c
@@ -45,7 +45,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: vfs__bio.c,v 1.15 1994/01/31 05:57:45 davidg Exp $
+ * $Id: vfs__bio.c,v 1.21 1994/05/29 18:06:31 ats Exp $
*/
#include "param.h"
@@ -73,7 +73,13 @@ struct buf bswlist; /* head of free swap header list */
struct buf *bclnlist; /* head of cleaned page list */
static struct buf *getnewbuf(int);
-extern vm_map_t buffer_map;
+extern vm_map_t buffer_map, io_map;
+
+/*
+ * Internel update daemon, process 3
+ * The variable vfs_update_wakeup allows for internal syncs.
+ */
+int vfs_update_wakeup;
/*
* Initialize buffer headers and related structures.
@@ -353,18 +359,8 @@ start:
&& bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) {
caddr_t addr;
-/*#define notyet*/
-#ifndef notyet
- if ((addr = malloc (sz, M_IOBUF, M_WAITOK)) == 0) goto tryfree;
-#else /* notyet */
- /* get new memory buffer */
- if (round_page(sz) == sz)
- addr = (caddr_t) kmem_alloc_wired_wait(buffer_map, sz);
- else
- addr = (caddr_t) malloc (sz, M_IOBUF, M_WAITOK);
- /*if ((addr = malloc (sz, M_IOBUF, M_NOWAIT)) == 0) goto tryfree;*/
- bzero(addr, sz);
-#endif /* notyet */
+ if ((addr = malloc (sz, M_IOBUF, M_NOWAIT)) == 0)
+ goto tryfree;
freebufspace -= sz;
allocbufspace += sz;
@@ -476,7 +472,14 @@ loop:
/* if (bp->b_bufsize != size) allocbuf(bp, size); */
} else {
- if ((bp = getnewbuf(size)) == 0) goto loop;
+ if ((bp = getnewbuf(size)) == 0)
+ goto loop;
+ if ( incore(vp, blkno)) {
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ goto loop;
+ }
+
bp->b_blkno = bp->b_lblkno = blkno;
bgetvp(vp, bp);
bh = BUFHASH(vp, blkno);
@@ -521,27 +524,13 @@ allocbuf(register struct buf *bp, int size)
caddr_t newcontents;
/* get new memory buffer */
-#ifndef notyet
newcontents = (caddr_t) malloc (size, M_IOBUF, M_WAITOK);
-#else /* notyet */
- if (round_page(size) == size)
- newcontents = (caddr_t) kmem_alloc_wired_wait(buffer_map, size);
- else
- newcontents = (caddr_t) malloc (size, M_IOBUF, M_WAITOK);
-#endif /* notyet */
/* copy the old into the new, up to the maximum that will fit */
bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size));
/* return old contents to free heap */
-#ifndef notyet
free (bp->b_un.b_addr, M_IOBUF);
-#else /* notyet */
- if (round_page(bp->b_bufsize) == bp->b_bufsize)
- kmem_free_wakeup(buffer_map, bp->b_un.b_addr, bp->b_bufsize);
- else
- free (bp->b_un.b_addr, M_IOBUF);
-#endif /* notyet */
/* adjust buffer cache's idea of memory allocated to buffer contents */
freebufspace -= size - bp->b_bufsize;
@@ -593,6 +582,39 @@ biowait(register struct buf *bp)
void
biodone(register struct buf *bp)
{
+ int s;
+ s = splbio();
+ if (bp->b_flags & B_CLUSTER) {
+ struct buf *tbp;
+ bp->b_resid = bp->b_bcount;
+ while ( tbp = bp->b_clusterf) {
+ bp->b_clusterf = tbp->av_forw;
+ bp->b_resid -= tbp->b_bcount;
+ tbp->b_resid = 0;
+ if( bp->b_resid <= 0) {
+ tbp->b_error = bp->b_error;
+ tbp->b_flags |= (bp->b_flags & B_ERROR);
+ tbp->b_resid = -bp->b_resid;
+ bp->b_resid = 0;
+ }
+/*
+ printf("rdc (%d,%d,%d) ", tbp->b_blkno, tbp->b_bcount, tbp->b_resid);
+*/
+
+ biodone(tbp);
+ }
+#ifndef NOBOUNCE
+ vm_bounce_kva_free( bp->b_un.b_addr, bp->b_bufsize, 0);
+#endif
+ relpbuf(bp);
+ splx(s);
+ return;
+ }
+
+#ifndef NOBOUNCE
+ if (bp->b_flags & B_BOUNCE)
+ vm_bounce_free(bp);
+#endif
bp->b_flags |= B_DONE;
if ((bp->b_flags & B_READ) == 0) {
@@ -603,6 +625,7 @@ biodone(register struct buf *bp)
if (bp->b_flags & B_CALL) {
bp->b_flags &= ~B_CALL;
(*bp->b_iodone)(bp);
+ splx(s);
return;
}
@@ -618,19 +641,21 @@ biodone(register struct buf *bp)
bp->b_flags &= ~B_WANTED;
wakeup((caddr_t) bp);
}
+ splx(s);
}
-/*
- * Internel update daemon, process 3
- * The variable vfs_update_wakeup allows for internal syncs.
- */
-int vfs_update_wakeup;
+#ifndef UPDATE_INTERVAL
+int vfs_update_interval = 30;
+#else
+int vfs_update_interval = UPDATE_INTERVAL;
+#endif
void
vfs_update() {
(void) spl0();
while(1) {
- tsleep((caddr_t)&vfs_update_wakeup, PRIBIO, "update", hz*30);
+ tsleep((caddr_t)&vfs_update_wakeup, PRIBIO, "update",
+ hz * vfs_update_interval);
vfs_update_wakeup = 0;
sync(curproc, NULL, NULL);
}
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index f35002a9460f..37a406d6651e 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)vfs_lookup.c 7.32 (Berkeley) 5/21/91
- * $Id: vfs_lookup.c,v 1.5.2.1 1994/05/04 07:54:56 rgrimes Exp $
+ * $Id: vfs_lookup.c,v 1.9 1994/06/02 06:53:37 ache Exp $
*/
#include "param.h"
@@ -106,6 +106,13 @@ namei(ndp, p)
else
error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
MAXPATHLEN, (u_int *)&ndp->ni_pathlen);
+#if 0
+ /*
+ * Don't allow empty pathname.
+ */
+ if (!error && *ndp->ni_pnbuf == '\0')
+ error = ENOENT;
+#endif
if (error) {
free(ndp->ni_pnbuf, M_NAMEI);
ndp->ni_vp = NULL;
@@ -284,10 +291,10 @@ dirloop:
* responsibility for freeing the pathname buffer.
*/
ndp->ni_hash = 0;
- for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
+ for (cp = ndp->ni_ptr; *cp != '\0' && *cp != '/'; cp++)
ndp->ni_hash += (unsigned char)*cp;
ndp->ni_namelen = cp - ndp->ni_ptr;
- if (ndp->ni_namelen >= NAME_MAX) {
+ if (ndp->ni_namelen > NAME_MAX) {
error = ENAMETOOLONG;
goto bad;
}
@@ -367,7 +374,7 @@ dirloop:
printf("not found\n");
#endif
if (flag == LOOKUP || flag == DELETE ||
- error != ENOENT || *cp != 0)
+ error != ENOENT || *cp != '\0')
goto bad;
/*
* If creating and at end of pathname, then can consider
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 024c5679000b..5525022e9811 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)vfs_subr.c 7.60 (Berkeley) 6/21/91
- * $Id: vfs_subr.c,v 1.7.2.2 1994/05/04 07:55:00 rgrimes Exp $
+ * $Id: vfs_subr.c,v 1.13 1994/06/14 03:41:00 davidg Exp $
*/
/*
@@ -57,6 +57,9 @@
#include "buf.h"
#include "errno.h"
#include "malloc.h"
+#include "vm/vm.h"
+#include "vm/vm_object.h"
+#include "vm/vm_pager.h"
static void insmntque(struct vnode *, struct mount *);
@@ -441,6 +444,8 @@ vinvalbuf(vp, save)
register struct buf *bp;
struct buf *nbp, *blist;
int s, dirty = 0;
+ vm_pager_t pager;
+ vm_object_t object;
for (;;) {
if (blist = vp->v_dirtyblkhd)
@@ -473,6 +478,20 @@ vinvalbuf(vp, save)
brelse(bp);
}
}
+
+ pager = (vm_pager_t)vp->v_vmdata;
+ if (pager != NULL) {
+ object = vm_object_lookup(pager);
+ if (object) {
+ vm_object_lock(object);
+ if (save)
+ vm_object_page_clean(object, 0, 0);
+ vm_object_page_remove(object, 0, object->size);
+ vm_object_unlock(object);
+ vm_object_deallocate(object);
+ }
+ }
+
if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
panic("vinvalbuf: flush failed");
return (dirty);
@@ -645,6 +664,7 @@ loop:
nvp->v_hashchain = vpp;
nvp->v_specnext = *vpp;
nvp->v_specflags = 0;
+ nvp->v_opencount = 0;
*vpp = nvp;
if (vp != NULL) {
nvp->v_flag |= VALIASED;
@@ -1068,6 +1088,7 @@ vfinddev(dev, type, vpp)
/*
* Calculate the total number of references to a special device.
+ * Not counting sleeping openers.
*/
int
vcount(vp)
@@ -1089,7 +1110,7 @@ loop:
vgone(vq);
goto loop;
}
- count += vq->v_usecount;
+ count += vq->v_usecount - vq->v_opencount;
}
return (count);
}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 396bd6326f98..b218ab6dd380 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)vfs_syscalls.c 7.74 (Berkeley) 6/21/91
- * $Id: vfs_syscalls.c,v 1.10 1994/01/19 21:09:13 jtc Exp $
+ * $Id: vfs_syscalls.c,v 1.17 1994/05/26 05:32:05 ache Exp $
*/
#include "param.h"
@@ -841,9 +841,10 @@ link(p, uap, retval)
if (error = namei(ndp, p))
return (error);
vp = ndp->ni_vp;
- if (vp->v_type == VDIR &&
- (error = suser(p->p_ucred, &p->p_acflag)))
+ if (vp->v_type == VDIR) {
+ error = EPERM;
goto out1;
+ }
ndp->ni_nameiop = CREATE | LOCKPARENT;
ndp->ni_dirp = (caddr_t)uap->linkname;
if (error = namei(ndp, p))
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index b273dc8b3604..a9c03b99d6ad 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)vfs_vnops.c 7.33 (Berkeley) 6/27/91
- * $Id: vfs_vnops.c,v 1.4.2.2 1994/05/04 07:55:04 rgrimes Exp $
+ * $Id: vfs_vnops.c,v 1.7 1994/05/04 08:27:20 rgrimes Exp $
*/
#include "param.h"
@@ -388,6 +388,7 @@ vn_ioctl(fp, com, data, p)
default:
return (ENOTTY);
+ case VPROC:
case VFIFO:
case VCHR:
case VBLK:
diff --git a/sys/net/if.c b/sys/net/if.c
index fc51448e9ef5..42a7a5de4a70 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if.c 7.14 (Berkeley) 4/20/91
- * $Id: if.c,v 1.7 1993/12/19 00:52:00 wollman Exp $
+ * $Id: if.c,v 1.9 1994/06/10 11:10:24 ache Exp $
*/
#include "param.h"
@@ -204,7 +204,7 @@ ifa_ifwithdstaddr(addr)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
continue;
- if (equal(addr, ifa->ifa_dstaddr))
+ if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
return (ifa);
}
return ((struct ifaddr *)0);
@@ -506,7 +506,8 @@ ifioctl(so, cmd, data, p)
return (EOPNOTSUPP);
#ifndef COMPAT_43
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
- cmd, data, ifp));
+ (struct mbuf *)cmd, (struct mbuf *)data,
+ (struct mbuf *)ifp, (struct mbuf *)0));
#else
{
int ocmd = cmd;
diff --git a/sys/net/if.h b/sys/net/if.h
index e1d7f316b04a..b434f795a59f 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if.h 7.11 (Berkeley) 3/19/91
- * $Id: if.h,v 1.11 1993/12/19 00:52:02 wollman Exp $
+ * $Id: if.h,v 1.12 1994/05/17 22:30:53 jkh Exp $
*/
#ifndef _NET_IF_H_
@@ -81,7 +81,7 @@ struct ifnet {
char *if_name; /* name, e.g. ``en'' or ``lo'' */
short if_unit; /* sub-unit for lower level driver */
u_short if_mtu; /* maximum transmission unit */
- short if_flags; /* up/down, broadcast, etc. */
+ u_int if_flags; /* up/down, broadcast, etc. */
short if_timer; /* time 'til if_watchdog called */
int if_metric; /* routing metric (external only) */
struct ifaddr *if_addrlist; /* linked list of addresses per if */
@@ -143,12 +143,18 @@ struct ifnet {
#define IFF_LLC2 0x4000 /* IEEE 802.2 LLC class 2 */
#define IFF_ALTPHYS 0x8000 /* alternative physical connection */
#define IFF_MULTICAST 0x10000 /* i'face supports multicast */
+#ifdef notdef
#define IFF_VIRTUAL 0x20000 /* i'face is really a VIF */
/* flags set internally only: */
#define IFF_CANTCHANGE \
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX\
|IFF_MULTICAST|IFF_VIRTUAL)
+#else
+#define IFF_CANTCHANGE \
+ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX\
+ |IFF_MULTICAST)
+#endif
/*
* Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
@@ -222,7 +228,7 @@ struct ifreq {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
- short ifru_flags;
+ u_int ifru_flags;
int ifru_metric;
caddr_t ifru_data;
} ifr_ifru;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 348d51dd148f..9d7e897c32cb 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1982, 1989 Regents of the University of California.
+ * Copyright (c) 1982, 1989, 1993 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91
- * $Id: if_ethersubr.c,v 1.4 1993/11/25 01:34:02 wollman Exp $
+ * $Id: if_ethersubr.c,v 1.5 1994/05/17 22:30:54 jkh Exp $
*/
#include "param.h"
@@ -110,22 +110,12 @@ ether_output(ifp, m0, dst, rt)
idst = ((struct sockaddr_in *)dst)->sin_addr;
if (!arpresolve(ac, m, &idst, edst, &usetrailers))
return (0); /* if not yet resolved */
- if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
mcopy = m_copy(m, 0, (int)M_COPYALL);
off = m->m_pkthdr.len - m->m_len;
- if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
- (m->m_flags & M_EXT) == 0 &&
- m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
- type = ETHERTYPE_TRAIL + (off>>9);
- m->m_data -= 2 * sizeof (u_short);
- m->m_len += 2 * sizeof (u_short);
- len += 2 * sizeof (u_short);
- *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
- *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
- goto gottrailertype;
- }
type = ETHERTYPE_IP;
- goto gottype;
+ break;
#endif
#ifdef NS
case AF_NS:
@@ -134,9 +124,10 @@ ether_output(ifp, m0, dst, rt)
(caddr_t)edst, sizeof (edst));
if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
return (looutput(ifp, m, dst, rt));
- if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
mcopy = m_copy(m, 0, (int)M_COPYALL);
- goto gottype;
+ break;
#endif
#ifdef ISO
case AF_ISO: {
@@ -165,7 +156,8 @@ ether_output(ifp, m0, dst, rt)
(char *)edst, &snpalen)) > 0)
goto bad; /* Not Resolved */
iso_resolved:
- if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)
(mcopy = m_copy(m, 0, (int)M_COPYALL))) {
M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
if (mcopy) {
@@ -191,7 +183,8 @@ ether_output(ifp, m0, dst, rt)
printf("%x ", edst[i] & 0xff);
printf("\n");
ENDDEBUG
- } goto gottype;
+ }
+ break;
#endif ISO
#ifdef RMP
case AF_RMP:
@@ -208,7 +201,7 @@ ether_output(ifp, m0, dst, rt)
eh = (struct ether_header *)dst->sa_data;
bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
type = eh->ether_type;
- goto gottype;
+ break;
default:
printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
@@ -217,18 +210,6 @@ ether_output(ifp, m0, dst, rt)
goto bad;
}
-gottrailertype:
- /*
- * Packet to be sent as trailer: move first packet
- * (control information) to end of chain.
- */
- while (m->m_next)
- m = m->m_next;
- m->m_next = m0;
- m = m0->m_next;
- m0->m_next = 0;
-
-gottype:
if (mcopy)
(void) looutput(ifp, mcopy, dst, rt);
/*
@@ -266,7 +247,7 @@ gottype:
(*ifp->if_start)(ifp);
splx(s);
ifp->if_obytes += len + sizeof (struct ether_header);
- if (edst[0] & 1)
+ if (m->m_flags & M_MCAST)
ifp->if_omcasts++;
return (error);
@@ -293,11 +274,13 @@ ether_input(ifp, eh, m)
ifp->if_lastchange = time;
ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
+ if (eh->ether_dhost[0] & 1) {
if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
sizeof(etherbroadcastaddr)) == 0)
m->m_flags |= M_BCAST;
- else if (eh->ether_dhost[0] & 1)
+ else
m->m_flags |= M_MCAST;
+ }
if (m->m_flags & (M_BCAST|M_MCAST))
ifp->if_imcasts++;
@@ -421,3 +404,178 @@ ether_sprintf(ap)
*--cp = 0;
return (etherbuf);
}
+
+#ifdef MULTICAST
+u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
+u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
+
+/* XXX */
+#undef ac
+/*
+ * Add an Ethernet multicast address or range of addresses to the list for a
+ * given interface.
+ */
+int
+ether_addmulti(ifr, ac)
+ struct ifreq *ifr;
+ register struct arpcom *ac;
+{
+ register struct ether_multi *enm;
+ struct sockaddr_in *sin;
+ u_char addrlo[6];
+ u_char addrhi[6];
+ int s = splimp();
+
+ switch (ifr->ifr_addr.sa_family) {
+
+ case AF_UNSPEC:
+ bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
+ bcopy(addrlo, addrhi, 6);
+ break;
+
+#ifdef INET
+ case AF_INET:
+ sin = (struct sockaddr_in *)&(ifr->ifr_addr);
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ /*
+ * An IP address of INADDR_ANY means listen to all
+ * of the Ethernet multicast addresses used for IP.
+ * (This is for the sake of IP multicast routers.)
+ */
+ bcopy(ether_ipmulticast_min, addrlo, 6);
+ bcopy(ether_ipmulticast_max, addrhi, 6);
+ }
+ else {
+ ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
+ bcopy(addrlo, addrhi, 6);
+ }
+ break;
+#endif
+
+ default:
+ splx(s);
+ return (EAFNOSUPPORT);
+ }
+
+ /*
+ * Verify that we have valid Ethernet multicast addresses.
+ */
+ if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
+ splx(s);
+ return (EINVAL);
+ }
+ /*
+ * See if the address range is already in the list.
+ */
+ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
+ if (enm != NULL) {
+ /*
+ * Found it; just increment the reference count.
+ */
+ ++enm->enm_refcount;
+ splx(s);
+ return (0);
+ }
+ /*
+ * New address or range; malloc a new multicast record
+ * and link it into the interface's multicast list.
+ */
+ enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
+ if (enm == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+ bcopy(addrlo, enm->enm_addrlo, 6);
+ bcopy(addrhi, enm->enm_addrhi, 6);
+ enm->enm_ac = ac;
+ enm->enm_refcount = 1;
+ enm->enm_next = ac->ac_multiaddrs;
+ ac->ac_multiaddrs = enm;
+ ac->ac_multicnt++;
+ splx(s);
+ /*
+ * Return ENETRESET to inform the driver that the list has changed
+ * and its reception filter should be adjusted accordingly.
+ */
+ return (ENETRESET);
+}
+
+/*
+ * Delete a multicast address record.
+ */
+int
+ether_delmulti(ifr, ac)
+ struct ifreq *ifr;
+ register struct arpcom *ac;
+{
+ register struct ether_multi *enm;
+ register struct ether_multi **p;
+ struct sockaddr_in *sin;
+ u_char addrlo[6];
+ u_char addrhi[6];
+ int s = splimp();
+
+ switch (ifr->ifr_addr.sa_family) {
+
+ case AF_UNSPEC:
+ bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
+ bcopy(addrlo, addrhi, 6);
+ break;
+
+#ifdef INET
+ case AF_INET:
+ sin = (struct sockaddr_in *)&(ifr->ifr_addr);
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ /*
+ * An IP address of INADDR_ANY means stop listening
+ * to the range of Ethernet multicast addresses used
+ * for IP.
+ */
+ bcopy(ether_ipmulticast_min, addrlo, 6);
+ bcopy(ether_ipmulticast_max, addrhi, 6);
+ }
+ else {
+ ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
+ bcopy(addrlo, addrhi, 6);
+ }
+ break;
+#endif
+
+ default:
+ splx(s);
+ return (EAFNOSUPPORT);
+ }
+
+ /*
+ * Look up the address in our list.
+ */
+ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
+ if (enm == NULL) {
+ splx(s);
+ return (ENXIO);
+ }
+ if (--enm->enm_refcount != 0) {
+ /*
+ * Still some claims to this record.
+ */
+ splx(s);
+ return (0);
+ }
+ /*
+ * No remaining claims to this record; unlink and free it.
+ */
+ for (p = &enm->enm_ac->ac_multiaddrs;
+ *p != enm;
+ p = &(*p)->enm_next)
+ continue;
+ *p = (*p)->enm_next;
+ free(enm, M_IFMADDR);
+ ac->ac_multicnt--;
+ splx(s);
+ /*
+ * Return ENETRESET to inform the driver that the list has changed
+ * and its reception filter should be adjusted accordingly.
+ */
+ return (ENETRESET);
+}
+#endif
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 163712a66fd1..d9f5028b7e1d 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if_loop.c 7.13 (Berkeley) 4/26/91
- * $Id: if_loop.c,v 1.6 1993/12/20 19:31:29 wollman Exp $
+ * $Id: if_loop.c,v 1.7 1994/05/17 22:30:55 jkh Exp $
*/
/*
@@ -95,7 +95,11 @@ loattach(void)
ifp->if_name = "lo";
ifp->if_mtu = LOMTU;
+#ifdef MULTICAST
+ ifp->if_flags = IFF_LOOPBACK|IFF_MULTICAST;
+#else
ifp->if_flags = IFF_LOOPBACK;
+#endif
ifp->if_ioctl = loioctl;
ifp->if_output = looutput;
ifp->if_type = IFT_LOOP;
@@ -216,6 +220,9 @@ loioctl(ifp, cmd, data)
caddr_t data;
{
register struct ifaddr *ifa;
+#ifdef MULTICAST
+ register struct ifreq *ifr;
+#endif
int error = 0;
switch (cmd) {
@@ -230,6 +237,27 @@ loioctl(ifp, cmd, data)
*/
break;
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+#endif
default:
error = EINVAL;
}
diff --git a/sys/net/if_ppp.c b/sys/net/if_ppp.c
index efda46dbe54a..18beb9a345cd 100644
--- a/sys/net/if_ppp.c
+++ b/sys/net/if_ppp.c
@@ -70,7 +70,7 @@
*/
/*
- * $Id: if_ppp.c,v 1.7 1993/12/20 19:31:30 wollman Exp $
+ * $Id: if_ppp.c,v 1.13 1994/05/30 03:37:47 ache Exp $
* From: if_ppp.c,v 1.22 1993/08/31 23:20:40 paulus Exp
* From: if_ppp.c,v 1.21 1993/08/29 11:22:37 paulus Exp
* From: if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp
@@ -92,6 +92,7 @@
#include "kernel.h"
#include "conf.h"
#include "dkstat.h"
+#include "pppdefs.h"
#include "if.h"
#include "if_types.h"
@@ -117,11 +118,11 @@
#ifndef RB_LEN
/* NetBSD, 4.3-Reno or similar */
#define CCOUNT(q) ((q)->c_cc)
+#define TSA_HUP_OR_INPUT(tp) ((caddr_t)&tp->t_rawq)
#else
/* 386BSD, Jolitz-style ring buffers */
#define t_outq t_out
-#define t_rawq t_raw
#define t_canq t_can
#define CCOUNT(q) (RB_LEN(q))
#endif
@@ -249,7 +250,7 @@ pppopen(dev, tp)
if (sc->sc_ttyp == NULL)
break;
if (nppp >= NPPP)
- return ENXIO;
+ return (ENXIO);
sc->sc_flags = 0;
sc->sc_ilen = 0;
@@ -344,33 +345,40 @@ pppread(tp, uio, flag)
{
register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
struct mbuf *m, *m0;
- register int s;
- int error = 0;
+ int s;
+ int error;
- if ((tp->t_state & TS_CARR_ON)==0)
- return (EIO);
s = splimp();
- while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) {
+ for (;;) {
+ if (tp->t_line != PPPDISC) {
+ splx(s);
+ return (ENXIO);
+ }
+ if (!CAN_DO_IO(tp)) {
+ splx(s);
+ return (EIO);
+ }
+ if (sc->sc_inq.ifq_head != NULL)
+ break;
if (tp->t_state & TS_ASYNC) {
splx(s);
return (EWOULDBLOCK);
}
- error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
- if (error)
- return error;
- }
- if (tp->t_line != PPPDISC) {
- splx(s);
- return (-1);
+ error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0);
+ if (error) {
+ splx(s);
+ return (error);
+ }
}
/* Pull place-holder byte out of canonical queue */
- getc(&tp->t_canq);
+ getc(tp->t_canq);
/* Get the packet from the input queue */
IF_DEQUEUE(&sc->sc_inq, m0);
splx(s);
+ error = 0;
for (m = m0; m && uio->uio_resid; m = m->m_next)
if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
break;
@@ -391,19 +399,33 @@ pppwrite(tp, uio, flag)
struct mbuf *m, *m0, **mp;
struct sockaddr dst;
struct ppp_header *ph1, *ph2;
- int len, error;
+ int len, error, s;
- if ((tp->t_state & TS_CARR_ON)==0)
- return (EIO);
if (tp->t_line != PPPDISC)
- return (EINVAL);
+ return (ENXIO);
+
+ /*
+ * XXX the locking is probably too strong, and/or the order of checking
+ * for errors requires an inconvenient number of splx()'s. pppoutput()
+ * does its own locking, but we must hold at least an spltty() lock to
+ * preserve the validity of the test of TS_CARR_ON in CAN_DO_IO().
+ */
+ s = splimp();
+
+ if (!CAN_DO_IO(tp)) {
+ splx(s);
+ return (EIO);
+ }
if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HEADER_LEN ||
- uio->uio_resid < PPP_HEADER_LEN)
+ uio->uio_resid < PPP_HEADER_LEN) {
+ splx(s);
return (EMSGSIZE);
+ }
for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
MGET(m, M_WAIT, MT_DATA);
if ((*mp = m) == NULL) {
m_freem(m0);
+ splx(s);
return (ENOBUFS);
}
if (uio->uio_resid >= MCLBYTES / 2)
@@ -411,6 +433,7 @@ pppwrite(tp, uio, flag)
len = MIN(M_TRAILINGSPACE(m), uio->uio_resid);
if (error = uiomove(mtod(m, u_char *), len, uio)) {
m_freem(m0);
+ splx(s);
return (error);
}
m->m_len = len;
@@ -421,7 +444,9 @@ pppwrite(tp, uio, flag)
*ph1 = *ph2;
m0->m_data += PPP_HEADER_LEN;
m0->m_len -= PPP_HEADER_LEN;
- return (pppoutput(&sc->sc_if, m0, &dst, 0));
+ error = pppoutput(&sc->sc_if, m0, &dst, 0);
+ splx(s);
+ return (error);
}
/*
@@ -589,7 +614,7 @@ pppoutput(ifp, m0, dst, rt)
error = ENETDOWN; /* sort of */
goto bad;
}
- if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
+ if (!CAN_DO_IO(sc->sc_ttyp)) {
error = EHOSTUNREACH;
goto bad;
}
@@ -711,15 +736,14 @@ pppstart(tp)
for (;;) {
/*
- * If there is more in the output queue, just send it now.
+ * Call output process whether or not there is any output.
* We are being called in lieu of ttstart and must do what
* it would.
*/
- if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
- (*tp->t_oproc)(tp);
- if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
- return;
- }
+ (*tp->t_oproc)(tp);
+ if (CCOUNT(tp->t_outq) > PPP_HIWAT)
+ return;
+
/*
* This happens briefly when the line shuts down.
*/
@@ -809,9 +833,9 @@ pppstart(tp)
* will flush any accumulated garbage. We do this whenever
* the line may have been idle for some time.
*/
- if (CCOUNT(&tp->t_outq) == 0) {
+ if (CCOUNT(tp->t_outq) == 0) {
++sc->sc_bytessent;
- (void) putc(PPP_FLAG, &tp->t_outq);
+ (void) putc(PPP_FLAG, tp->t_outq);
}
/* Calculate the FCS for the first mbuf's worth. */
@@ -834,7 +858,7 @@ pppstart(tp)
if (n) {
#ifndef RB_LEN
/* NetBSD (0.9 or later), 4.3-Reno or similar. */
- ndone = n - b_to_q(start, n, &tp->t_outq);
+ ndone = n - b_to_q(start, n, tp->t_outq);
#else
#ifdef NetBSD
/* NetBSD with 2-byte ring buffer entries */
@@ -843,12 +867,12 @@ pppstart(tp)
/* 386BSD, FreeBSD */
int cc, nleft;
for (nleft = n; nleft > 0; nleft -= cc) {
- if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0)
+ if ((cc = RB_CONTIGPUT(tp->t_out)) == 0)
break;
cc = min (cc, nleft);
- bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc);
- tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
- tp->t_out.rb_tl + cc);
+ bcopy((char *)start + n - nleft, tp->t_out->rb_tl, cc);
+ tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+ tp->t_out->rb_tl + cc);
}
ndone = n - nleft;
#endif /* NetBSD */
@@ -866,10 +890,10 @@ pppstart(tp)
* Put it out in a different form.
*/
if (len) {
- if (putc(PPP_ESCAPE, &tp->t_outq))
+ if (putc(PPP_ESCAPE, tp->t_outq))
break;
- if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
- (void) unputc(&tp->t_outq);
+ if (putc(*start ^ PPP_TRANS, tp->t_outq)) {
+ (void) unputc(tp->t_outq);
break;
}
sc->sc_bytessent += 2;
@@ -912,10 +936,10 @@ pppstart(tp)
* don't all fit, back out.
*/
for (q = endseq; q < p; ++q)
- if (putc(*q, &tp->t_outq)) {
+ if (putc(*q, tp->t_outq)) {
done = 0;
for (; q > endseq; --q)
- unputc(&tp->t_outq);
+ unputc(tp->t_outq);
break;
}
}
@@ -1213,7 +1237,7 @@ pppinput(c, tp)
* Some other protocol - place on input queue for read().
* Put a placeholder byte in canq for ttselect()/ttnread().
*/
- putc(0, &tp->t_canq);
+ putc(0, tp->t_canq);
ttwakeup(tp);
inq = &sc->sc_inq;
break;
diff --git a/sys/net/if_sl.c b/sys/net/if_sl.c
index 223281337a53..60376b28e1bf 100644
--- a/sys/net/if_sl.c
+++ b/sys/net/if_sl.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if_sl.c 7.22 (Berkeley) 4/20/91
- * $Id: if_sl.c,v 1.7 1993/12/20 19:31:32 wollman Exp $
+ * $Id: if_sl.c,v 1.12 1994/06/07 13:02:36 davidg Exp $
*/
/*
@@ -65,7 +65,7 @@
* interrupts and network activity; thus, splimp must be >= spltty.
*/
-/* $Id: if_sl.c,v 1.7 1993/12/20 19:31:32 wollman Exp $ */
+/* $Id: if_sl.c,v 1.12 1994/06/07 13:02:36 davidg Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "sl.h"
@@ -170,8 +170,10 @@
#ifndef SLRMTU
#define SLRMTU 296 /* for good latency */
#endif
-#else
+#else /* (not) experimental */
+#ifndef SLMTU
#define SLMTU 296
+#endif
#define SLRMTU SLMTU
#endif
@@ -445,7 +447,7 @@ sloutput(ifp, m, dst, rt)
}
IF_ENQUEUE(ifq, m);
sc->sc_if.if_lastchange = time;
- if (RB_LEN(&sc->sc_ttyp->t_out) == 0)
+ if (RB_LEN(sc->sc_ttyp->t_out) == 0)
slstart(sc->sc_ttyp);
splx(s);
return (0);
@@ -478,7 +480,7 @@ slstart(tp)
* it would.
*/
(*tp->t_oproc)(tp);
- if (RB_LEN(&tp->t_out) > SLIP_HIWAT)
+ if (RB_LEN(tp->t_out) > SLIP_HIWAT)
return;
/*
@@ -495,7 +497,7 @@ slstart(tp)
* of RBSZ in tty.h also has to be upped to be at least
* SLMTU*2.
*/
- if (min(RBSZ, 4 * SLMTU + 4) - RB_LEN(&tp->t_out) < 2 * SLMTU + 2)
+ if (min(RBSZ, 4 * SLMTU + 4) - RB_LEN(tp->t_out) < 2 * SLMTU + 2)
return;
/*
@@ -558,9 +560,9 @@ slstart(tp)
* will flush any accumulated garbage. We do this whenever
* the line may have been idle for some time.
*/
- if (RB_LEN(&tp->t_out) == 0) {
+ if (RB_LEN(tp->t_out) == 0) {
++sc->sc_bytessent;
- (void) putc(FRAME_END, &tp->t_out);
+ (void) putc(FRAME_END, tp->t_out);
}
while (m) {
@@ -589,7 +591,7 @@ slstart(tp)
* into the tty output queue.
*/
sc->sc_bytessent += rb_write(
- &tp->t_out,
+ tp->t_out,
(char *) bp,
cp - bp);
}
@@ -599,12 +601,12 @@ slstart(tp)
* Put it out in a different form.
*/
if (cp < ep) {
- if (putc(FRAME_ESCAPE, &tp->t_out))
+ if (putc(FRAME_ESCAPE, tp->t_out))
break;
if (putc(*cp++ == FRAME_ESCAPE ?
TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
- &tp->t_out)) {
- (void) unputc(&tp->t_out);
+ tp->t_out)) {
+ (void) unputc(tp->t_out);
break;
}
sc->sc_bytessent += 2;
@@ -614,7 +616,7 @@ slstart(tp)
m = m2;
}
- if (putc(FRAME_END, &tp->t_out)) {
+ if (putc(FRAME_END, tp->t_out)) {
/*
* Not enough room. Remove a char to make room
* and end the packet normally.
@@ -622,8 +624,8 @@ slstart(tp)
* a day) you probably do not have enough clists
* and you should increase "nclist" in param.c.
*/
- (void) unputc(&tp->t_out);
- (void) putc(FRAME_END, &tp->t_out);
+ (void) unputc(tp->t_out);
+ (void) putc(FRAME_END, tp->t_out);
sc->sc_if.if_collisions++;
} else {
++sc->sc_bytessent;
@@ -869,6 +871,9 @@ slioctl(ifp, cmd, data)
caddr_t data;
{
register struct ifaddr *ifa = (struct ifaddr *)data;
+#ifdef MULTICAST
+ register struct ifreq *ifr;
+#endif
int s = splimp(), error = 0;
switch (cmd) {
@@ -890,6 +895,25 @@ slioctl(ifp, cmd, data)
error = EAFNOSUPPORT;
break;
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+#endif
default:
error = EINVAL;
}
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
index b543791db6fb..372388b69ded 100644
--- a/sys/net/netisr.h
+++ b/sys/net/netisr.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)netisr.h 7.8 (Berkeley) 5/7/91
- * $Id: netisr.h,v 1.5 1993/12/20 14:58:31 wollman Exp $
+ * $Id: netisr.h,v 1.6 1994/04/02 07:01:00 davidg Exp $
*/
#ifndef _NET_NETISR_H_
@@ -65,20 +65,9 @@
#define schednetisr(anisr) { netisr |= 1<<(anisr); setsoftnet(); }
-#ifdef i386
-/* XXX Temporary -- soon to vanish - wfj */
-#define NETISR_SCLK 11 /* softclock */
-#define NETISR_AST 12 /* ast -- resched */
-
-#undef schednetisr
-#define schednetisr(anisr) {\
- netisr |= 1<<(anisr); \
-}
-#endif /* i386 */
-
#ifndef LOCORE
#ifdef KERNEL
-extern int netisr; /* scheduling bits for network */
+extern volatile unsigned netisr; /* scheduling bits for network */
#endif
#endif
#endif /* _NET_NETISR_H_ */
diff --git a/sys/net/ppp.h b/sys/net/ppp.h
deleted file mode 100644
index c2d4a79c4baa..000000000000
--- a/sys/net/ppp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * ppp.h - PPP global declarations.
- *
- * Copyright (c) 1989 Carnegie Mellon University.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * from: unknown
- * $Id: ppp.h,v 1.2 1993/10/16 17:43:29 rgrimes Exp $
- */
-
-#ifndef __PPP_H__
-#define __PPP_H__
-
-#define NPPP 1 /* One PPP interface supported (per process) */
-
-/*
- * Data Link Layer header = Address, Control, Protocol.
- */
-#define ALLSTATIONS 0xff /* All-Stations Address */
-#define UI 0x03 /* Unnumbered Information */
-#define LCP 0xc021 /* Link Control Protocol */
-#define IPCP 0x8021 /* IP Control Protocol */
-#define UPAP 0xc023 /* User/Password Authentication Protocol */
-#define CHAP 0xc223 /* Crytpographic Handshake Protocol */
-#define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */
-#define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
-#define MTU 1500 /* Default MTU */
-
-#endif /* __PPP_H__ */
diff --git a/sys/net/pppdefs.h b/sys/net/pppdefs.h
new file mode 100644
index 000000000000..a0b5bc5d5b4f
--- /dev/null
+++ b/sys/net/pppdefs.h
@@ -0,0 +1,41 @@
+/*
+ * pppdefs.h - PPP global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pppdefs.h,v 1.1 1994/04/01 10:13:22 jkh Exp $
+ */
+
+#ifndef __PPP_H__
+#define __PPP_H__
+
+#define _NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Data Link Layer header = Address, Control, Protocol.
+ */
+#define ALLSTATIONS 0xff /* All-Stations Address */
+#define UI 0x03 /* Unnumbered Information */
+#define LCP 0xc021 /* Link Control Protocol */
+#define IPCP 0x8021 /* IP Control Protocol */
+#define UPAP 0xc023 /* User/Password Authentication Protocol */
+#define CHAP 0xc223 /* Crytpographic Handshake Protocol */
+#define LQR 0xc025 /* Link Quality Report protocol */
+#define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */
+#define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+#define MTU 1500 /* Default MTU */
+
+#endif /* __PPP_H__ */
diff --git a/sys/net/raw_cb.h b/sys/net/raw_cb.h
index 5d64b60d9d9a..0eda56573de6 100644
--- a/sys/net/raw_cb.h
+++ b/sys/net/raw_cb.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)raw_cb.h 7.6 (Berkeley) 6/28/90
- * $Id: raw_cb.h,v 1.4 1993/12/19 00:52:05 wollman Exp $
+ * $Id: raw_cb.h,v 1.5 1994/05/17 22:30:57 jkh Exp $
*/
#ifndef _NET_RAW_CB_H_
@@ -48,6 +48,7 @@ struct rawcb {
struct sockaddr *rcb_faddr; /* destination address */
struct sockaddr *rcb_laddr; /* socket's address */
struct sockproto rcb_proto; /* protocol family, protocol */
+ struct mbuf *rcb_moptions; /* proto specific multicast options */
};
#define sotorawcb(so) ((struct rawcb *)(so)->so_pcb)
diff --git a/sys/net/route.c b/sys/net/route.c
index 5cf0cb72d556..ccb1cf63d097 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)route.c 7.22 (Berkeley) 6/27/91
- * $Id: route.c,v 1.5.2.1 1994/03/24 07:42:12 rgrimes Exp $
+ * $Id: route.c,v 1.6 1994/03/22 02:02:25 davidg Exp $
*/
#include "param.h"
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index ebad56b12dcf..47efad34eaed 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if_ether.c 7.13 (Berkeley) 10/31/90
- * $Id: if_ether.c,v 1.4 1993/11/25 01:34:57 wollman Exp $
+ * $Id: if_ether.c,v 1.5 1994/05/17 22:31:00 jkh Exp $
*/
/*
@@ -197,6 +197,12 @@ arpresolve(ac, m, destip, desten, usetrailers)
sizeof(etherbroadcastaddr));
return (1);
}
+#ifdef MULTICAST
+ if (m->m_flags & M_MCAST) { /* multicast */
+ ETHER_MAP_IP_MULTICAST(destip, desten);
+ return(1);
+ }
+#endif
lna = in_lnaof(*destip);
/* if for us, use software loopback driver if up */
for (ia = in_ifaddr; ia; ia = ia->ia_next)
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index 787b561e6fdf..fdf595924c43 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)if_ether.h 7.5 (Berkeley) 6/28/90
- * $Id: if_ether.h,v 1.4 1993/11/25 01:35:01 wollman Exp $
+ * $Id: if_ether.h,v 1.5 1994/05/17 22:31:02 jkh Exp $
*/
#ifndef _NETINET_IF_ETHER_H_
@@ -61,6 +61,25 @@ struct ether_header {
#define ETHERMTU 1500
#define ETHERMIN (60-14)
+#ifdef KERNEL
+/*
+ * Macro to map an IP multicast address to an Ethernet multicast address.
+ * The high-order 25 bites of the Ethernet address are staticall assigned,
+ * and the low-rder 23 bites are taken from the low end of the IP address.
+ */
+#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \
+ /* struct in_addr *ipaddr; */ \
+ /* u_char enaddr[6]; */ \
+{ \
+ (enaddr)[0] = 0x01; \
+ (enaddr)[1] = 0x00; \
+ (enaddr)[2] = 0x5e; \
+ (enaddr)[3] = ((u_char *)ipaddr)[1] & 0x7f; \
+ (enaddr)[4] = ((u_char *)ipaddr)[2]; \
+ (enaddr)[5] = ((u_char *)ipaddr)[3]; \
+}
+#endif
+
/*
* Ethernet Address Resolution Protocol.
*
@@ -91,8 +110,11 @@ struct arpcom {
struct ifnet ac_if; /* network-visible interface */
u_char ac_enaddr[6]; /* ethernet hardware address */
struct in_addr ac_ipaddr; /* copy of ip address- XXX */
+ struct ether_multi *ac_multiaddrs; /* list of ether m'cast addrs */
+ int ac_multicnt; /* length of ac_multiaddrs list */
};
+
/*
* Internet to ethernet address resolution table.
*/
@@ -106,10 +128,84 @@ struct arptab {
#ifdef KERNEL
extern u_char etherbroadcastaddr[6]; /* defined in net/if_ethersubr.c */
+#if defined(ISO) && !defined(MULTICAST)
+#define MULTICAST 1
+#endif
+#ifdef MULTICAST
+u_char ether_ipmulticast_min[6];
+u_char ether_ipmulticast_max[6];
+#endif
struct arptab *arptnew();
extern void ether_input(struct ifnet *, struct ether_header *, struct mbuf *);
extern char *ether_sprintf(u_char *);
-#endif
+#ifdef MULTICAST
+/*
+ * Ethernet multicast address structure. There is one of these for each
+ * multicast address or range of multicast addresses that we are supposed
+ * to listen to on a particular interface. They are kept in a linked list,
+ * rooted in the interface's arpcom structure. (This really has nothing to
+ * do with ARP, or with the Internet address family, but this appears to be
+ * the minimally-disrupting place to put it.)
+ */
+struct ether_multi {
+ u_char enm_addrlo[6]; /* low or only address of range */
+ u_char enm_addrhi[6]; /* high or only address of range */
+ struct arpcom *enm_ac; /* back point to arpcom */
+ u_int enm_refcount; /* no. claims to this addr/range */
+ struct ether_multi *enm_next; /* ptr to next ether_multi */
+} ;
+
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the ether_multi records.
+ */
+struct ether_multistep {
+ struct ether_multi *e_enm;
+};
+
+/*
+ * Macro for looking up the ether_multi record for a given range of Ethernet
+ * multicast addresses connected to a given arpcom structure. If no matching
+ * record is found, "enm" returns NULL.
+ */
+#define ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm) \
+ /* u_char addrlo[6]; */ \
+ /* u_char addrhi[6]; */ \
+ /* struct arpcom *ac; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ for ((enm) = (ac)->ac_multiaddrs; \
+ (enm) != NULL && \
+ (bcmp((enm)->enm_addrlo, (addrlo), 6) != 0 || \
+ bcmp((enm)->enm_addrhi, (addrhi), 6) != 0); \
+ (enm) = (enm)->enm_next); \
+}
+
+/*
+ * Macro to step through all of the ether_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide. ETHER_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record. Both macros return a NULL "enm" when there
+ * are no remaining records.
+ */
+#define ETHER_NEXT_MULTI(step, enm) \
+ /* struct ether_multistep step; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ if (((enm) = (step).e_enm) != NULL) \
+ (step).e_enm = (enm)->enm_next; \
+}
+
+#define ETHER_FIRST_MULTI(step, ac, enm) \
+ /* struct ether_multistep step; */ \
+ /* struct arpcom *ac; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ (step).e_enm = (ac)->ac_multiaddrs; \
+ ETHER_NEXT_MULTI((step), (enm)); \
+}
+#endif /* _MULTICAST */
+#endif /* KERNEL */
#endif /* _NETINET_IF_ETHER_H_ */
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
new file mode 100644
index 000000000000..d3bdd933730a
--- /dev/null
+++ b/sys/netinet/igmp.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1988 Stephen Deering.
+ * Copyright (c) 1992, 1993 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * @(#)igmp.c 7.2 (Berkeley) 10/11/92
+ */
+
+/* Internet Group Management Protocol (IGMP) routines. */
+
+#ifdef MULTICAST
+
+#include "param.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "protosw.h"
+
+#include "net/if.h"
+#include "net/route.h"
+
+#include "in.h"
+#include "in_var.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "ip_var.h"
+#include "igmp.h"
+#include "igmp_var.h"
+#include "machine/cpufunc.h"
+
+extern struct ifnet loif;
+
+static int igmp_timers_are_running = 0;
+static u_long igmp_all_hosts_group;
+
+static void igmp_sendreport __P((struct in_multi *));
+
+void
+igmp_init()
+{
+ /*
+ * To avoid byte-swapping the same value over and over again.
+ */
+ igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP);
+}
+
+void
+igmp_input(m, iphlen)
+ register struct mbuf *m;
+ register int iphlen;
+{
+ register struct igmp *igmp;
+ register struct ip *ip;
+ register int igmplen;
+ register struct ifnet *ifp = m->m_pkthdr.rcvif;
+ register int minlen;
+ register struct in_multi *inm;
+ register struct in_ifaddr *ia;
+ struct in_multistep step;
+
+ ++igmpstat.igps_rcv_total;
+
+ ip = mtod(m, struct ip *);
+ igmplen = ip->ip_len;
+
+ /*
+ * Validate lengths
+ */
+ if (igmplen < IGMP_MINLEN) {
+ ++igmpstat.igps_rcv_tooshort;
+ m_freem(m);
+ return;
+ }
+ minlen = iphlen + IGMP_MINLEN;
+ if ((m->m_flags & M_EXT || m->m_len < minlen) &&
+ (m = m_pullup(m, minlen)) == 0) {
+ ++igmpstat.igps_rcv_tooshort;
+ return;
+ }
+
+ /*
+ * Validate checksum
+ */
+ m->m_data += iphlen;
+ m->m_len -= iphlen;
+ igmp = mtod(m, struct igmp *);
+ if (in_cksum(m, igmplen)) {
+ ++igmpstat.igps_rcv_badsum;
+ m_freem(m);
+ return;
+ }
+ m->m_data -= iphlen;
+ m->m_len += iphlen;
+ ip = mtod(m, struct ip *);
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ ++igmpstat.igps_rcv_queries;
+
+ if (ifp == &loif)
+ break;
+
+ if (ip->ip_dst.s_addr != igmp_all_hosts_group) {
+ ++igmpstat.igps_rcv_badqueries;
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * Start the timers in all of our membership records for
+ * the interface on which the query arrived, except those
+ * that are already running and those that belong to the
+ * "all-hosts" group.
+ */
+ IN_FIRST_MULTI(step, inm);
+ while (inm != NULL) {
+ if (inm->inm_ifp == ifp && inm->inm_timer == 0 &&
+ inm->inm_addr.s_addr != igmp_all_hosts_group) {
+ inm->inm_timer =
+ IGMP_RANDOM_DELAY(inm->inm_addr);
+ igmp_timers_are_running = 1;
+ }
+ IN_NEXT_MULTI(step, inm);
+ }
+
+ break;
+
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ ++igmpstat.igps_rcv_reports;
+
+ if (ifp == &loif)
+ break;
+
+ if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
+ igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
+ ++igmpstat.igps_rcv_badreports;
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * KLUDGE: if the IP source address of the report has an
+ * unspecified (i.e., zero) subnet number, as is allowed for
+ * a booting host, replace it with the correct subnet number
+ * so that a process-level multicast routing demon can
+ * determine which subnet it arrived from. This is necessary
+ * to compensate for the lack of any way for a process to
+ * determine the arrival interface of an incoming packet.
+ */
+ if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {
+ IFP_TO_IA(ifp, ia);
+ if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);
+ }
+
+ /*
+ * If we belong to the group being reported, stop
+ * our timer for that group.
+ */
+ IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
+ if (inm != NULL) {
+ inm->inm_timer = 0;
+ ++igmpstat.igps_rcv_ourreports;
+ }
+
+ break;
+ }
+
+ /*
+ * Pass all valid IGMP packets up to any process(es) listening
+ * on a raw IGMP socket.
+ */
+ rip_input(m);
+}
+
+void
+igmp_joingroup(inm)
+ struct in_multi *inm;
+{
+ register int s = splnet();
+
+ if (inm->inm_addr.s_addr == igmp_all_hosts_group ||
+ inm->inm_ifp == &loif)
+ inm->inm_timer = 0;
+ else {
+ igmp_sendreport(inm);
+ inm->inm_timer = IGMP_RANDOM_DELAY(inm->inm_addr);
+ igmp_timers_are_running = 1;
+ }
+ splx(s);
+}
+
+void
+igmp_leavegroup(inm)
+ struct in_multi *inm;
+{
+ /*
+ * No action required on leaving a group.
+ */
+}
+
+void
+igmp_fasttimo()
+{
+ register struct in_multi *inm;
+ register int s;
+ struct in_multistep step;
+
+ /*
+ * Quick check to see if any work needs to be done, in order
+ * to minimize the overhead of fasttimo processing.
+ */
+ if (!igmp_timers_are_running)
+ return;
+
+ s = splnet();
+ igmp_timers_are_running = 0;
+ IN_FIRST_MULTI(step, inm);
+ while (inm != NULL) {
+ if (inm->inm_timer == 0) {
+ /* do nothing */
+ } else if (--inm->inm_timer == 0) {
+ igmp_sendreport(inm);
+ } else {
+ igmp_timers_are_running = 1;
+ }
+ IN_NEXT_MULTI(step, inm);
+ }
+ splx(s);
+}
+
+static void
+igmp_sendreport(inm)
+ register struct in_multi *inm;
+{
+ register struct mbuf *m;
+ register struct igmp *igmp;
+ register struct ip *ip;
+ register struct ip_moptions *imo;
+ struct ip_moptions simo;
+ extern struct socket *ip_mrouter;
+
+ MGETHDR(m, M_DONTWAIT, MT_HEADER);
+ if (m == NULL)
+ return;
+ /*
+ * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
+ * is smaller than mbuf size returned by MGETHDR.
+ */
+ m->m_data += max_linkhdr;
+ m->m_len = sizeof(struct ip) + IGMP_MINLEN;
+ m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_tos = 0;
+ ip->ip_len = sizeof(struct ip) + IGMP_MINLEN;
+ ip->ip_off = 0;
+ ip->ip_p = IPPROTO_IGMP;
+ ip->ip_src.s_addr = INADDR_ANY;
+ ip->ip_dst = inm->inm_addr;
+
+ m->m_data += sizeof(struct ip);
+ m->m_len -= sizeof(struct ip);
+ igmp = mtod(m, struct igmp *);
+ igmp->igmp_type = IGMP_HOST_MEMBERSHIP_REPORT;
+ igmp->igmp_code = 0;
+ igmp->igmp_group = inm->inm_addr;
+ igmp->igmp_cksum = 0;
+ igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
+ m->m_data -= sizeof(struct ip);
+ m->m_len += sizeof(struct ip);
+
+ imo = &simo;
+ bzero((caddr_t)imo, sizeof(*imo));
+ imo->imo_multicast_ifp = inm->inm_ifp;
+ imo->imo_multicast_ttl = 1;
+ /*
+ * Request loopback of the report if we are acting as a multicast
+ * router, so that the process-level routing demon can hear it.
+ */
+#ifdef MROUTING
+ imo->imo_multicast_loop = (ip_mrouter != NULL);
+#else
+ imo->imo_multicast_loop = 0;
+#endif
+
+ ip_output(m, NULL, NULL, IP_MULTICASTOPTS, imo);
+
+ ++igmpstat.igps_snd_reports;
+}
+#endif
diff --git a/sys/netinet/igmp.h b/sys/netinet/igmp.h
new file mode 100644
index 000000000000..176941914de7
--- /dev/null
+++ b/sys/netinet/igmp.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1988 Stephen Deering.
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * @(#)igmp.h 7.1 (Berkeley) 7/8/92
+ */
+
+/* Internet Group Management Protocol (IGMP) definitions. */
+
+/*
+ * IGMP packet format.
+ */
+struct igmp {
+ u_char igmp_type; /* version & type of IGMP message */
+ u_char igmp_code; /* unused, should be zero */
+ u_short igmp_cksum; /* IP-style checksum */
+ struct in_addr igmp_group; /* group address being reported */
+}; /* (zero for queries) */
+
+#define IGMP_MINLEN 8
+
+#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* message types, incl. version */
+#define IGMP_HOST_MEMBERSHIP_REPORT 0x12
+#define IGMP_DVMRP 0x13 /* for experimental multicast */
+ /* routing protocol */
+
+#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */
+ /* query (in seconds) */
diff --git a/sys/netinet/igmp_var.h b/sys/netinet/igmp_var.h
new file mode 100644
index 000000000000..01e967f99ea2
--- /dev/null
+++ b/sys/netinet/igmp_var.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1988 Stephen Deering.
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * @(#)igmp_var.h 7.1 (Berkeley) 7/8/92
+ */
+
+/*
+ * Internet Group Management Protocol (IGMP),
+ * implementation-specific definitions.
+ *
+ * Written by Steve Deering, Stanford, May 1988.
+ *
+ * MULTICAST 1.1
+ */
+
+struct igmpstat {
+ u_int igps_rcv_total; /* total IGMP messages received */
+ u_int igps_rcv_tooshort; /* received with too few bytes */
+ u_int igps_rcv_badsum; /* received with bad checksum */
+ u_int igps_rcv_queries; /* received membership queries */
+ u_int igps_rcv_badqueries; /* received invalid queries */
+ u_int igps_rcv_reports; /* received membership reports */
+ u_int igps_rcv_badreports; /* received invalid reports */
+ u_int igps_rcv_ourreports; /* received reports for our groups */
+ u_int igps_snd_reports; /* sent membership reports */
+};
+
+#ifdef KERNEL
+struct igmpstat igmpstat;
+
+/*
+ * Macro to compute a random timer value between 1 and (IGMP_MAX_REPORTING_
+ * DELAY * countdown frequency). We assume that the routine random()
+ * is defined somewhere (and that it returns a positive number).
+ */
+#define IGMP_RANDOM_DELAY(multiaddr) \
+ /* struct in_addr multiaddr; */ \
+ (random() % (IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ) + 1)
+
+
+void igmp_init __P(());
+void igmp_input __P((struct mbuf *, int));
+void igmp_joingroup __P((struct in_multi *));
+void igmp_leavegroup __P((struct in_multi *));
+void igmp_fasttimo __P(());
+#endif
+
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 2c662e2d6336..46f423b71bbd 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in.c 7.17 (Berkeley) 4/20/91
- * $Id: in.c,v 1.8 1994/01/15 14:29:21 davidg Exp $
+ * $Id: in.c,v 1.9 1994/05/17 22:31:03 jkh Exp $
*/
#include "param.h"
@@ -93,6 +93,10 @@ in_netof(in)
net = i & IN_CLASSB_NET;
else if (IN_CLASSC(i))
net = i & IN_CLASSC_NET;
+#ifdef MULTICAST
+ else if (IN_CLASSD(i))
+ net = i & IN_CLASSD_NET;
+#endif
else
return (0);
@@ -174,6 +178,11 @@ in_lnaof(in)
} else if (IN_CLASSC(i)) {
net = i & IN_CLASSC_NET;
host = i & IN_CLASSC_HOST;
+#ifdef MULTICAST
+ } else if (IN_CLASSD(i)) {
+ net = i & IN_CLASSD_NET;
+ host = i & IN_CLASSD_HOST;
+#endif
} else
return (i);
@@ -557,6 +566,18 @@ in_ifinit(ifp, ia, sin, scrub)
}
if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
ia->ia_flags |= IFA_ROUTE;
+#ifdef MULTICAST
+ /*
+ * If the interface supports multicast, join the "all hosts"
+ * multicast group on that interface.
+ */
+ if (ifp->if_flags & IFF_MULTICAST) {
+ struct in_addr addr;
+
+ addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
+ in_addmulti(&addr, ifp);
+ }
+#endif
return (error);
}
@@ -603,4 +624,113 @@ in_broadcast(in)
return (1);
return (0);
}
+
+#ifdef MULTICAST
+/*
+ * Add an address to the list of IP multicast addresses for a given interface.
+ */
+struct in_multi *
+in_addmulti(ap, ifp)
+ register struct in_addr *ap;
+ register struct ifnet *ifp;
+{
+ register struct in_multi *inm;
+ struct ifreq ifr;
+ struct in_ifaddr *ia;
+ int s = splnet();
+
+ /*
+ * See if address already in list.
+ */
+ IN_LOOKUP_MULTI(*ap, ifp, inm);
+ if (inm != NULL) {
+ /*
+ * Found it; just increment the reference count.
+ */
+ ++inm->inm_refcount;
+ }
+ else {
+ /*
+ * New address; allocate a new multicast record
+ * and link it into the interface's multicast list.
+ */
+ inm = (struct in_multi *)malloc(sizeof(*inm),
+ M_IPMADDR, M_NOWAIT);
+ if (inm == NULL) {
+ splx(s);
+ return (NULL);
+ }
+ inm->inm_addr = *ap;
+ inm->inm_ifp = ifp;
+ inm->inm_refcount = 1;
+ IFP_TO_IA(ifp, ia);
+ if (ia == NULL) {
+ free(inm, M_IPMADDR);
+ splx(s);
+ return (NULL);
+ }
+ inm->inm_ia = ia;
+ inm->inm_next = ia->ia_multiaddrs;
+ ia->ia_multiaddrs = inm;
+ /*
+ * Ask the network driver to update its multicast reception
+ * filter appropriately for the new address.
+ */
+ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
+ if (ifp->if_ioctl == NULL ||
+ (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
+ ia->ia_multiaddrs = inm->inm_next;
+ free(inm, M_IPMADDR);
+ splx(s);
+ return (NULL);
+ }
+ /*
+ * Let IGMP know that we have joined a new IP multicast group.
+ */
+ igmp_joingroup(inm);
+ }
+ splx(s);
+ return (inm);
+}
+
+/*
+ * Delete a multicast address record.
+ */
+int
+in_delmulti(inm)
+ register struct in_multi *inm;
+{
+ register struct in_multi **p;
+ struct ifreq ifr;
+ int s = splnet();
+
+ if (--inm->inm_refcount == 0) {
+ /*
+ * No remaining claims to this record; let IGMP know that
+ * we are leaving the multicast group.
+ */
+ igmp_leavegroup(inm);
+ /*
+ * Unlink from list.
+ */
+ for (p = &inm->inm_ia->ia_multiaddrs;
+ *p != inm;
+ p = &(*p)->inm_next)
+ continue;
+ *p = (*p)->inm_next;
+ /*
+ * Notify the network driver to update its multicast reception
+ * filter.
+ */
+ ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
+ ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
+ inm->inm_addr;
+ (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
+ (caddr_t)&ifr);
+ free(inm, M_IPMADDR);
+ }
+ splx(s);
+}
+#endif
#endif
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 48f24b39ede4..96a9f88cea77 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in.h 7.11 (Berkeley) 4/20/91
- * $Id: in.h,v 1.4 1993/12/19 00:52:35 wollman Exp $
+ * $Id: in.h,v 1.8 1994/05/26 22:42:14 jkh Exp $
*/
#ifndef _NETINET_IN_H_
@@ -47,6 +47,7 @@
*/
#define IPPROTO_IP 0 /* dummy for IP */
#define IPPROTO_ICMP 1 /* control message protocol */
+#define IPPROTO_IGMP 2 /* ground control protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
#define IPPROTO_TCP 6 /* tcp */
#define IPPROTO_EGP 8 /* exterior gateway protocol */
@@ -100,20 +101,37 @@ struct in_addr {
#define IN_CLASSC_HOST 0x000000ffUL
#define IN_CLASSD(i) (((u_long)(i) & 0xf0000000UL) == 0xe0000000UL)
+#define IN_CLASSD_NET 0xf0000000UL /* These ones aren't really */
+#define IN_CLASSD_NSHIFT 28 /* net and host fields, bit */
+#define IN_CLASSD_HOST 0x0fffffffUL /* routing needn't know. */
#define IN_MULTICAST(i) IN_CLASSD(i)
#define IN_EXPERIMENTAL(i) (((u_long)(i) & 0xe0000000UL) == 0xe0000000UL)
#define IN_BADCLASS(i) (((u_long)(i) & 0xf0000000UL) == 0xf0000000UL)
#define INADDR_ANY 0x00000000UL
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
#define INADDR_BROADCAST 0xffffffffUL /* must be masked */
#ifndef KERNEL
#define INADDR_NONE 0xffffffffUL /* -1 return */
#endif
+#define INADDR_UNSPEC_GROUP 0xe0000000UL /* 224.0.0.0 */
+#define INADDR_ALLHOSTS_GROUP 0xe0000001UL /* 244.0.0.1 */
+#define INADDR_MAX_LOCAL_GROUP 0xe00000ffUL /* 244.0.0.255 */
+
#define IN_LOOPBACKNET 127 /* official! */
/*
+ * Define a macro to stuff the loopback address into an Internet address.
+ */
+#define IN_SET_LOOPBACK_ADDR(a) { \
+ (a)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); \
+ (a)->sin_family = AF_INET; }
+
+/*
* Socket address, internet style.
*/
struct sockaddr_in {
@@ -148,6 +166,23 @@ struct ip_opts {
#define IP_RECVRETOPTS 6 /* bool; receive IP options for response */
#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/datagram */
#define IP_RETOPTS 8 /* ip_opts; set/get IP per-packet options */
+#define IP_MULTICAST_IF 9 /* set/get IP multicast interfcae */
+#define IP_MULTICAST_TTL 10 /* set/get IP multicast timetolive */
+#define IP_MULTICAST_LOOP 11 /* set/get IP m'cast loopback */
+#define IP_ADD_MEMBERSHIP 12 /* add an IP group membership */
+#define IP_DROP_MEMBERSHIP 13 /* drop an IP group membership */
+
+#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */
+#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sens if a member */
+#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */
+
+/*
+ * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+ */
+struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+} ;
#ifdef KERNEL
/* From in.c: */
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index cc404e6f1510..af5d742f1bac 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in_pcb.c 7.14 (Berkeley) 4/20/91
- * $Id: in_pcb.c,v 1.5 1993/12/19 00:52:37 wollman Exp $
+ * $Id: in_pcb.c,v 1.6 1994/05/17 22:31:05 jkh Exp $
*/
#include "param.h"
@@ -51,6 +51,9 @@
#include "ip.h"
#include "in_pcb.h"
#include "in_var.h"
+#ifdef MULTICAST
+#include "ip_var.h"
+#endif
int
in_pcballoc(so, head)
@@ -70,6 +73,53 @@ in_pcballoc(so, head)
so->so_pcb = (caddr_t)inp;
return (0);
}
+/*
+ * return 1 if there's a pcb whose addresses 'confict' with the
+ * supplied addresses. Only exact matches (address with address
+ * or wildcard with wildcard) are considered to be in conflict
+ * since in_pcblookup will resolve anything else via 'best match'.
+ */
+int
+in_pcbconflict(head, faddr, laddr, fport, lport)
+ register struct inpcb *head;
+ register u_long faddr, laddr;
+ register u_short fport, lport;
+{
+ register struct inpcb *inp = head;
+
+ while ((inp = inp->inp_next) != head)
+ if (inp->inp_lport == lport &&
+ (fport == 0 || inp->inp_fport == fport) &&
+ (faddr == 0 || inp->inp_faddr.s_addr == faddr) &&
+ (laddr == 0 || inp->inp_laddr.s_addr == laddr))
+ return (1);
+ return (0);
+}
+
+/*
+ * Chose a unique (non-conflicting) local port for the inpcb list
+ * starting at 'head'. (A 'rover' is kept in the lport field of
+ * the list head to make N calls to this routine O(N^2) instead of
+ * O(N^3)). The port will always be
+ * IPPORT_RESERVED <= lport <= IPPORT_USERRESERVED
+ */
+u_short
+in_uniqueport(head, faddr, laddr, fport)
+ register struct inpcb *head;
+ register u_long faddr, laddr;
+ register u_short fport;
+{
+ register u_short lport = head->inp_lport;
+
+ do {
+ ++lport;
+ if (lport < IPPORT_RESERVED || lport > IPPORT_USERRESERVED)
+ lport = IPPORT_RESERVED;
+ } while (in_pcbconflict(head, faddr, laddr, fport, htons(lport)));
+ head->inp_lport = lport;
+ return (htons(lport));
+}
+
int
in_pcbbind(inp, nam)
@@ -107,6 +157,7 @@ in_pcbbind(inp, nam)
if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
return (EACCES);
/* even GROSSER, but this is the Internet */
+#ifdef notdef
if ((so->so_options & SO_REUSEADDR) == 0 &&
((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
(so->so_options & SO_ACCEPTCONN) == 0))
@@ -114,10 +165,16 @@ in_pcbbind(inp, nam)
if (in_pcblookup(head,
zeroin_addr, 0, sin->sin_addr, lport, wild))
return (EADDRINUSE);
+#else
+ if ((inp->inp_socket->so_options & SO_REUSEADDR) == 0 &&
+ in_pcbconflict(head, 0, sin->sin_addr.s_addr, 0, lport))
+ return (EADDRINUSE);
+#endif
}
inp->inp_laddr = sin->sin_addr;
noname:
if (lport == 0)
+#ifdef notdef
do {
if (head->inp_lport++ < IPPORT_RESERVED ||
head->inp_lport > IPPORT_USERRESERVED)
@@ -125,6 +182,10 @@ noname:
lport = htons(head->inp_lport);
} while (in_pcblookup(head,
zeroin_addr, 0, inp->inp_laddr, lport, 0));
+#else
+ lport = in_uniqueport(head, inp->inp_faddr.s_addr,
+ inp->inp_laddr, inp->inp_fport);
+#endif
inp->inp_lport = lport;
return (0);
}
@@ -148,8 +209,13 @@ in_pcbconnect(inp, nam)
return (EINVAL);
if (sin->sin_family != AF_INET)
return (EAFNOSUPPORT);
+#ifdef MULTICAST
+ if (sin->sin_port == 0 && !IN_MULTICAST(sin->sin_addr.s_addr))
+ return(EADDRNOTAVAIL);
+#else
if (sin->sin_port == 0)
return (EADDRNOTAVAIL);
+#endif
if (in_ifaddr) {
/*
* If the destination address is INADDR_ANY,
@@ -217,6 +283,28 @@ in_pcbconnect(inp, nam)
if (ia == 0)
return (EADDRNOTAVAIL);
}
+#ifdef MULTICAST
+ /*
+ * If the destination address is multicast and an outgoing
+ * interface has been set as a multicast option, use the
+ * address of that interface as our source address.
+ */
+ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
+ inp->inp_moptions != NULL) {
+ struct ip_moptions *imo;
+ struct ifnet *ifp;
+
+ imo = inp->inp_moptions;
+ if (imo->imo_multicast_ifp != NULL) {
+ ifp = imo->imo_multicast_ifp;
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+ }
+#endif
ifaddr = (struct sockaddr_in *)&ia->ia_addr;
}
if (in_pcblookup(inp->inp_head,
@@ -269,6 +357,9 @@ in_pcbdetach(inp)
(void)m_free(inp->inp_options);
if (inp->inp_route.ro_rt)
rtfree(inp->inp_route.ro_rt);
+#ifdef MULTICAST
+ ip_freemoptions(inp->inp_moptions);
+#endif
remque(inp);
(void) m_free(dtom(inp));
}
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index e4adb614e6d4..dd4527e768d1 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * 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
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in_pcb.h 7.6 (Berkeley) 6/28/90
- * $Id: in_pcb.h,v 1.5 1993/11/25 01:35:06 wollman Exp $
+ * $Id: in_pcb.h,v 1.6 1994/05/17 22:31:06 jkh Exp $
*/
#ifndef _NETINET_IN_PCB_H_
@@ -67,6 +67,7 @@ struct inpcb {
/* function to call when MTU may have
* changed */
#endif /* MTUDISC */
+ struct ip_moptions *inp_moptions; /* IP multicast options */
};
/* flags in inp_flags: */
diff --git a/sys/netinet/in_pcb.old.c b/sys/netinet/in_pcb.old.c
new file mode 100644
index 000000000000..1946b9edb34a
--- /dev/null
+++ b/sys/netinet/in_pcb.old.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1982, 1986, 1991 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: @(#)in_pcb.c 7.14 (Berkeley) 4/20/91
+ * $Id: in_pcb.old.c,v 1.1 1994/05/17 23:16:40 jkh Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "ioctl.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+#ifdef MULTICAST
+#include "ip_var.h"
+#endif
+
+int
+in_pcballoc(so, head)
+ struct socket *so;
+ struct inpcb *head;
+{
+ struct mbuf *m;
+ register struct inpcb *inp;
+
+ m = m_getclr(M_DONTWAIT, MT_PCB);
+ if (m == NULL)
+ return (ENOBUFS);
+ inp = mtod(m, struct inpcb *);
+ inp->inp_head = head;
+ inp->inp_socket = so;
+ insque(inp, head);
+ so->so_pcb = (caddr_t)inp;
+ return (0);
+}
+
+int
+in_pcbbind(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct socket *so = inp->inp_socket;
+ register struct inpcb *head = inp->inp_head;
+ register struct sockaddr_in *sin;
+ u_short lport = 0;
+
+ if (in_ifaddr == 0)
+ return (EADDRNOTAVAIL);
+ if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
+ return (EINVAL);
+ if (nam == 0)
+ goto noname;
+ sin = mtod(nam, struct sockaddr_in *);
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ if (sin->sin_addr.s_addr != INADDR_ANY) {
+ int tport = sin->sin_port;
+
+ sin->sin_port = 0; /* yech... */
+ if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+ return (EADDRNOTAVAIL);
+ sin->sin_port = tport;
+ }
+ lport = sin->sin_port;
+ if (lport) {
+ u_short aport = ntohs(lport);
+ int wild = 0;
+
+ /* GROSS */
+ if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
+ return (EACCES);
+ /* even GROSSER, but this is the Internet */
+ if ((so->so_options & SO_REUSEADDR) == 0 &&
+ ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
+ (so->so_options & SO_ACCEPTCONN) == 0))
+ wild = INPLOOKUP_WILDCARD;
+ if (in_pcblookup(head,
+ zeroin_addr, 0, sin->sin_addr, lport, wild))
+ return (EADDRINUSE);
+ }
+ inp->inp_laddr = sin->sin_addr;
+noname:
+ if (lport == 0)
+ do {
+ if (head->inp_lport++ < IPPORT_RESERVED ||
+ head->inp_lport > IPPORT_USERRESERVED)
+ head->inp_lport = IPPORT_RESERVED;
+ lport = htons(head->inp_lport);
+ } while (in_pcblookup(head,
+ zeroin_addr, 0, inp->inp_laddr, lport, 0));
+ inp->inp_lport = lport;
+ return (0);
+}
+
+/*
+ * Connect from a socket to a specified address.
+ * Both address and port must be specified in argument sin.
+ * If don't have a local address for this socket yet,
+ * then pick one.
+ */
+int
+in_pcbconnect(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ struct in_ifaddr *ia;
+ struct sockaddr_in *ifaddr = 0;
+ register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ if (sin->sin_family != AF_INET)
+ return (EAFNOSUPPORT);
+#ifdef MULTICAST
+ if (sin->sin_port == 0 && !IN_MULTICAST(sin->sin_addr.s_addr))
+ return (EADDRNOTAVAIL);
+#else
+ if (sin->sin_port == 0)
+ return (EADDRNOTAVAIL);
+#endif
+ if (in_ifaddr) {
+ /*
+ * If the destination address is INADDR_ANY,
+ * use the primary local address.
+ * If the supplied address is INADDR_BROADCAST,
+ * and the primary interface supports broadcast,
+ * choose the broadcast address for that interface.
+ */
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ if (sin->sin_addr.s_addr == INADDR_ANY)
+ sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
+ else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
+ (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
+ sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
+ }
+ if (inp->inp_laddr.s_addr == INADDR_ANY) {
+ register struct route *ro;
+ struct ifnet *ifp;
+
+ ia = (struct in_ifaddr *)0;
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+ ro = &inp->inp_route;
+ if (ro->ro_rt &&
+ (satosin(&ro->ro_dst)->sin_addr.s_addr !=
+ sin->sin_addr.s_addr ||
+ inp->inp_socket->so_options & SO_DONTROUTE)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+ (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+ /* No route yet, so try to acquire one */
+ ro->ro_dst.sa_family = AF_INET;
+ ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
+ ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
+ sin->sin_addr;
+ rtalloc(ro);
+ }
+ /*
+ * If we found a route, use the address
+ * corresponding to the outgoing interface
+ * unless it is the loopback (in case a route
+ * to our address on another net goes to loopback).
+ */
+ if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
+ (ifp->if_flags & IFF_LOOPBACK) == 0)
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0) {
+ int fport = sin->sin_port;
+
+ sin->sin_port = 0;
+ ia = (struct in_ifaddr *)
+ ifa_ifwithdstaddr((struct sockaddr *)sin);
+ sin->sin_port = fport;
+ if (ia == 0)
+ ia = in_iaonnetof(in_netof(sin->sin_addr));
+ if (ia == 0)
+ ia = in_ifaddr;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+#ifdef MULTICAST
+ /*
+ * If the destination address is multicast and an outgoing
+ * interface has been set as a multicast option, use the
+ * address of that interface as our source address.
+ */
+ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
+ inp->inp_moptions != NULL) {
+ struct ip_moptions *imo;
+ struct ifnet *ifp;
+
+ imo = inp->inp_moptions;
+ if (imo->imo_multicast_ifp != NULL) {
+ ifp = imo->imo_multicast_ifp;
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+ }
+#endif
+ ifaddr = (struct sockaddr_in *)&ia->ia_addr;
+ }
+ if (in_pcblookup(inp->inp_head,
+ sin->sin_addr,
+ sin->sin_port,
+ inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
+ inp->inp_lport,
+ 0))
+ return (EADDRINUSE);
+ if (inp->inp_laddr.s_addr == INADDR_ANY) {
+ if (inp->inp_lport == 0)
+ (void)in_pcbbind(inp, (struct mbuf *)0);
+ inp->inp_laddr = ifaddr->sin_addr;
+ }
+ inp->inp_faddr = sin->sin_addr;
+ inp->inp_fport = sin->sin_port;
+#ifdef MTUDISC
+ /*
+ * If the upper layer asked for PMTU discovery services, see
+ * if we can get an idea of what the MTU should be...
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ return (0);
+}
+
+void
+in_pcbdisconnect(inp)
+ struct inpcb *inp;
+{
+
+ inp->inp_faddr.s_addr = INADDR_ANY;
+ inp->inp_fport = 0;
+#ifdef MTUDISC
+ inp->inp_flags &= ~INP_MTUDISCOVERED;
+#endif
+ if (inp->inp_socket->so_state & SS_NOFDREF)
+ in_pcbdetach(inp);
+}
+
+void
+in_pcbdetach(inp)
+ struct inpcb *inp;
+{
+ struct socket *so = inp->inp_socket;
+
+ so->so_pcb = 0;
+ sofree(so);
+ if (inp->inp_options)
+ (void)m_free(inp->inp_options);
+ if (inp->inp_route.ro_rt)
+ rtfree(inp->inp_route.ro_rt);
+#ifdef MULTICAST
+ ip_freemoptions(inp->inp_moptions);
+#endif
+ remque(inp);
+ (void) m_free(dtom(inp));
+}
+
+void
+in_setsockaddr(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_in *sin;
+
+ nam->m_len = sizeof (*sin);
+ sin = mtod(nam, struct sockaddr_in *);
+ bzero((caddr_t)sin, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_port = inp->inp_lport;
+ sin->sin_addr = inp->inp_laddr;
+}
+
+void
+in_setpeeraddr(inp, nam)
+ struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_in *sin;
+
+ nam->m_len = sizeof (*sin);
+ sin = mtod(nam, struct sockaddr_in *);
+ bzero((caddr_t)sin, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_port = inp->inp_fport;
+ sin->sin_addr = inp->inp_faddr;
+}
+
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst. The local address and/or port numbers
+ * may be specified to limit the search. The "usual action" will be
+ * taken, depending on the ctlinput cmd. The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splnet.
+ */
+void
+in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
+ struct inpcb *head;
+ struct sockaddr *dst;
+ u_short fport, lport;
+ struct in_addr laddr;
+ int cmd;
+ void (*notify)(struct inpcb *, int);
+{
+ register struct inpcb *inp, *oinp;
+ struct in_addr faddr;
+ int errno;
+
+ if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
+ return;
+ faddr = ((struct sockaddr_in *)dst)->sin_addr;
+ if (faddr.s_addr == INADDR_ANY)
+ return;
+
+ /*
+ * Redirects go to all references to the destination,
+ * and use in_rtchange to invalidate the route cache.
+ * Dead host indications: notify all references to the destination.
+ * MTU change indications: same thing.
+ * Otherwise, if we have knowledge of the local port and address,
+ * deliver only to that socket.
+ */
+ if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD
+ || cmd == PRC_MTUCHANGED) {
+ fport = 0;
+ lport = 0;
+ laddr.s_addr = 0;
+ if (cmd != PRC_HOSTDEAD && cmd != PRC_MTUCHANGED)
+ notify = in_rtchange;
+ }
+ errno = inetctlerrmap[cmd];
+ for (inp = head->inp_next; inp != head;) {
+ if (inp->inp_faddr.s_addr != faddr.s_addr ||
+ inp->inp_socket == 0 ||
+ (lport && inp->inp_lport != lport) ||
+ (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
+ (fport && inp->inp_fport != fport)) {
+ inp = inp->inp_next;
+ continue;
+ }
+ oinp = inp;
+ inp = inp->inp_next;
+ if (notify)
+ (*notify)(oinp, errno);
+ }
+}
+
+/*
+ * Check for alternatives when higher level complains
+ * about service problems. For now, invalidate cached
+ * routing information. If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+void
+in_losing(inp)
+ struct inpcb *inp;
+{
+ register struct rtentry *rt;
+
+ if ((rt = inp->inp_route.ro_rt)) {
+ rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
+ rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
+ (struct sockaddr *)0, rt->rt_flags, 0);
+ if (rt->rt_flags & RTF_DYNAMIC)
+ (void) rtrequest(RTM_DELETE, rt_key(rt),
+ rt->rt_gateway, rt_mask(rt), rt->rt_flags,
+ (struct rtentry **)0);
+ inp->inp_route.ro_rt = 0;
+ rtfree(rt);
+
+#ifdef MTUDISC
+ /*
+ * When doing MTU discovery, we want to find out as
+ * quickly as possible what the MTU of the new route is.
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ }
+}
+
+/*
+ * After a routing change, flush old routing
+ * and allocate a (hopefully) better one.
+ */
+void
+in_rtchange(inp, errno)
+ register struct inpcb *inp;
+ int errno;
+{
+ if (inp->inp_route.ro_rt) {
+ rtfree(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = 0;
+#ifdef MTUDISC
+ /*
+ * A new route can be allocated the next time
+ * output is attempted, but make sure to let
+ * MTU discovery know about it.
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ }
+}
+
+struct inpcb *
+in_pcblookup(head, faddr, fport, laddr, lport, flags)
+ struct inpcb *head;
+ struct in_addr faddr, laddr;
+ u_short fport, lport;
+ int flags;
+{
+ register struct inpcb *inp, *match = 0;
+ int matchwild = 3, wildcard;
+
+ for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
+ if (inp->inp_lport != lport)
+ continue;
+ wildcard = 0;
+ if (inp->inp_laddr.s_addr != INADDR_ANY) {
+ if (laddr.s_addr == INADDR_ANY)
+ wildcard++;
+ else if (inp->inp_laddr.s_addr != laddr.s_addr)
+ continue;
+ } else {
+ if (laddr.s_addr != INADDR_ANY)
+ wildcard++;
+ }
+ if (inp->inp_faddr.s_addr != INADDR_ANY) {
+ if (faddr.s_addr == INADDR_ANY)
+ wildcard++;
+ else if (inp->inp_faddr.s_addr != faddr.s_addr ||
+ inp->inp_fport != fport)
+ continue;
+ } else {
+ if (faddr.s_addr != INADDR_ANY)
+ wildcard++;
+ }
+ if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
+ continue;
+ if (wildcard < matchwild) {
+ match = inp;
+ matchwild = wildcard;
+ if (matchwild == 0)
+ break;
+ }
+ }
+ return (match);
+}
diff --git a/sys/netinet/in_pcb.orig.c b/sys/netinet/in_pcb.orig.c
new file mode 100644
index 000000000000..badedf559fda
--- /dev/null
+++ b/sys/netinet/in_pcb.orig.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1982, 1986, 1991 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: @(#)in_pcb.c 7.14 (Berkeley) 4/20/91
+ * $Id: in_pcb.orig.c,v 1.1 1994/05/17 23:16:41 jkh Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "ioctl.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+#ifdef MULTICAST
+#include "ip_var.h"
+#endif
+
+int
+in_pcballoc(so, head)
+ struct socket *so;
+ struct inpcb *head;
+{
+ struct mbuf *m;
+ register struct inpcb *inp;
+
+ m = m_getclr(M_DONTWAIT, MT_PCB);
+ if (m == NULL)
+ return (ENOBUFS);
+ inp = mtod(m, struct inpcb *);
+ inp->inp_head = head;
+ inp->inp_socket = so;
+ insque(inp, head);
+ so->so_pcb = (caddr_t)inp;
+ return (0);
+}
+
+int
+in_pcbbind(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct socket *so = inp->inp_socket;
+ register struct inpcb *head = inp->inp_head;
+ register struct sockaddr_in *sin;
+ u_short lport = 0;
+
+ if (in_ifaddr == 0)
+ return (EADDRNOTAVAIL);
+ if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
+ return (EINVAL);
+ if (nam == 0)
+ goto noname;
+ sin = mtod(nam, struct sockaddr_in *);
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ if (sin->sin_addr.s_addr != INADDR_ANY) {
+ int tport = sin->sin_port;
+
+ sin->sin_port = 0; /* yech... */
+ if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+ return (EADDRNOTAVAIL);
+ sin->sin_port = tport;
+ }
+ lport = sin->sin_port;
+ if (lport) {
+ u_short aport = ntohs(lport);
+ int wild = 0;
+
+ /* GROSS */
+ if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
+ return (EACCES);
+ /* even GROSSER, but this is the Internet */
+ if ((so->so_options & SO_REUSEADDR) == 0 &&
+ ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
+ (so->so_options & SO_ACCEPTCONN) == 0))
+ wild = INPLOOKUP_WILDCARD;
+ if (in_pcblookup(head,
+ zeroin_addr, 0, sin->sin_addr, lport, wild))
+ return (EADDRINUSE);
+ }
+ inp->inp_laddr = sin->sin_addr;
+noname:
+ if (lport == 0)
+ do {
+ if (head->inp_lport++ < IPPORT_RESERVED ||
+ head->inp_lport > IPPORT_USERRESERVED)
+ head->inp_lport = IPPORT_RESERVED;
+ lport = htons(head->inp_lport);
+ } while (in_pcblookup(head,
+ zeroin_addr, 0, inp->inp_laddr, lport, 0));
+ inp->inp_lport = lport;
+ return (0);
+}
+
+/*
+ * Connect from a socket to a specified address.
+ * Both address and port must be specified in argument sin.
+ * If don't have a local address for this socket yet,
+ * then pick one.
+ */
+int
+in_pcbconnect(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ struct in_ifaddr *ia;
+ struct sockaddr_in *ifaddr = 0;
+ register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ if (sin->sin_family != AF_INET)
+ return (EAFNOSUPPORT);
+ if (sin->sin_port == 0)
+ return (EADDRNOTAVAIL);
+ if (in_ifaddr) {
+ /*
+ * If the destination address is INADDR_ANY,
+ * use the primary local address.
+ * If the supplied address is INADDR_BROADCAST,
+ * and the primary interface supports broadcast,
+ * choose the broadcast address for that interface.
+ */
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ if (sin->sin_addr.s_addr == INADDR_ANY)
+ sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
+ else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
+ (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
+ sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
+ }
+ if (inp->inp_laddr.s_addr == INADDR_ANY) {
+ register struct route *ro;
+ struct ifnet *ifp;
+
+ ia = (struct in_ifaddr *)0;
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+ ro = &inp->inp_route;
+ if (ro->ro_rt &&
+ (satosin(&ro->ro_dst)->sin_addr.s_addr !=
+ sin->sin_addr.s_addr ||
+ inp->inp_socket->so_options & SO_DONTROUTE)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+ (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+ /* No route yet, so try to acquire one */
+ ro->ro_dst.sa_family = AF_INET;
+ ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
+ ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
+ sin->sin_addr;
+ rtalloc(ro);
+ }
+ /*
+ * If we found a route, use the address
+ * corresponding to the outgoing interface
+ * unless it is the loopback (in case a route
+ * to our address on another net goes to loopback).
+ */
+ if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
+ (ifp->if_flags & IFF_LOOPBACK) == 0)
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0) {
+ int fport = sin->sin_port;
+
+ sin->sin_port = 0;
+ ia = (struct in_ifaddr *)
+ ifa_ifwithdstaddr((struct sockaddr *)sin);
+ sin->sin_port = fport;
+ if (ia == 0)
+ ia = in_iaonnetof(in_netof(sin->sin_addr));
+ if (ia == 0)
+ ia = in_ifaddr;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+#ifdef MULTICAST
+ /*
+ * If the destination address is multicast and an outgoing
+ * interface has been set as a multicast option, use the
+ * address of that interface as our source address.
+ */
+ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
+ inp->inp_moptions != NULL) {
+ struct ip_moptions *imo;
+ struct ifnet *ifp;
+
+ imo = inp->inp_moptions;
+ if (imo->imo_multicast_ifp != NULL) {
+ ifp = imo->imo_multicast_ifp;
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+ }
+#endif
+ ifaddr = (struct sockaddr_in *)&ia->ia_addr;
+ }
+ if (in_pcblookup(inp->inp_head,
+ sin->sin_addr,
+ sin->sin_port,
+ inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
+ inp->inp_lport,
+ 0))
+ return (EADDRINUSE);
+ if (inp->inp_laddr.s_addr == INADDR_ANY) {
+ if (inp->inp_lport == 0)
+ (void)in_pcbbind(inp, (struct mbuf *)0);
+ inp->inp_laddr = ifaddr->sin_addr;
+ }
+ inp->inp_faddr = sin->sin_addr;
+ inp->inp_fport = sin->sin_port;
+#ifdef MTUDISC
+ /*
+ * If the upper layer asked for PMTU discovery services, see
+ * if we can get an idea of what the MTU should be...
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ return (0);
+}
+
+void
+in_pcbdisconnect(inp)
+ struct inpcb *inp;
+{
+
+ inp->inp_faddr.s_addr = INADDR_ANY;
+ inp->inp_fport = 0;
+#ifdef MTUDISC
+ inp->inp_flags &= ~INP_MTUDISCOVERED;
+#endif
+ if (inp->inp_socket->so_state & SS_NOFDREF)
+ in_pcbdetach(inp);
+}
+
+void
+in_pcbdetach(inp)
+ struct inpcb *inp;
+{
+ struct socket *so = inp->inp_socket;
+
+ so->so_pcb = 0;
+ sofree(so);
+ if (inp->inp_options)
+ (void)m_free(inp->inp_options);
+ if (inp->inp_route.ro_rt)
+ rtfree(inp->inp_route.ro_rt);
+#ifdef MULTICAST
+ ip_freemoptions(inp->inp_moptions);
+#endif
+ remque(inp);
+ (void) m_free(dtom(inp));
+}
+
+void
+in_setsockaddr(inp, nam)
+ register struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_in *sin;
+
+ nam->m_len = sizeof (*sin);
+ sin = mtod(nam, struct sockaddr_in *);
+ bzero((caddr_t)sin, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_port = inp->inp_lport;
+ sin->sin_addr = inp->inp_laddr;
+}
+
+void
+in_setpeeraddr(inp, nam)
+ struct inpcb *inp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_in *sin;
+
+ nam->m_len = sizeof (*sin);
+ sin = mtod(nam, struct sockaddr_in *);
+ bzero((caddr_t)sin, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_port = inp->inp_fport;
+ sin->sin_addr = inp->inp_faddr;
+}
+
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst. The local address and/or port numbers
+ * may be specified to limit the search. The "usual action" will be
+ * taken, depending on the ctlinput cmd. The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splnet.
+ */
+void
+in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
+ struct inpcb *head;
+ struct sockaddr *dst;
+ u_short fport, lport;
+ struct in_addr laddr;
+ int cmd;
+ void (*notify)(struct inpcb *, int);
+{
+ register struct inpcb *inp, *oinp;
+ struct in_addr faddr;
+ int errno;
+
+ if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
+ return;
+ faddr = ((struct sockaddr_in *)dst)->sin_addr;
+ if (faddr.s_addr == INADDR_ANY)
+ return;
+
+ /*
+ * Redirects go to all references to the destination,
+ * and use in_rtchange to invalidate the route cache.
+ * Dead host indications: notify all references to the destination.
+ * MTU change indications: same thing.
+ * Otherwise, if we have knowledge of the local port and address,
+ * deliver only to that socket.
+ */
+ if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD
+ || cmd == PRC_MTUCHANGED) {
+ fport = 0;
+ lport = 0;
+ laddr.s_addr = 0;
+ if (cmd != PRC_HOSTDEAD && cmd != PRC_MTUCHANGED)
+ notify = in_rtchange;
+ }
+ errno = inetctlerrmap[cmd];
+ for (inp = head->inp_next; inp != head;) {
+ if (inp->inp_faddr.s_addr != faddr.s_addr ||
+ inp->inp_socket == 0 ||
+ (lport && inp->inp_lport != lport) ||
+ (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
+ (fport && inp->inp_fport != fport)) {
+ inp = inp->inp_next;
+ continue;
+ }
+ oinp = inp;
+ inp = inp->inp_next;
+ if (notify)
+ (*notify)(oinp, errno);
+ }
+}
+
+/*
+ * Check for alternatives when higher level complains
+ * about service problems. For now, invalidate cached
+ * routing information. If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+void
+in_losing(inp)
+ struct inpcb *inp;
+{
+ register struct rtentry *rt;
+
+ if ((rt = inp->inp_route.ro_rt)) {
+ rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
+ rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
+ (struct sockaddr *)0, rt->rt_flags, 0);
+ if (rt->rt_flags & RTF_DYNAMIC)
+ (void) rtrequest(RTM_DELETE, rt_key(rt),
+ rt->rt_gateway, rt_mask(rt), rt->rt_flags,
+ (struct rtentry **)0);
+ inp->inp_route.ro_rt = 0;
+ rtfree(rt);
+
+#ifdef MTUDISC
+ /*
+ * When doing MTU discovery, we want to find out as
+ * quickly as possible what the MTU of the new route is.
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ }
+}
+
+/*
+ * After a routing change, flush old routing
+ * and allocate a (hopefully) better one.
+ */
+void
+in_rtchange(inp, errno)
+ register struct inpcb *inp;
+ int errno;
+{
+ if (inp->inp_route.ro_rt) {
+ rtfree(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = 0;
+#ifdef MTUDISC
+ /*
+ * A new route can be allocated the next time
+ * output is attempted, but make sure to let
+ * MTU discovery know about it.
+ */
+ in_pcbmtu(inp);
+#endif /* MTUDISC */
+ }
+}
+
+struct inpcb *
+in_pcblookup(head, faddr, fport, laddr, lport, flags)
+ struct inpcb *head;
+ struct in_addr faddr, laddr;
+ u_short fport, lport;
+ int flags;
+{
+ register struct inpcb *inp, *match = 0;
+ int matchwild = 3, wildcard;
+
+ for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
+ if (inp->inp_lport != lport)
+ continue;
+ wildcard = 0;
+ if (inp->inp_laddr.s_addr != INADDR_ANY) {
+ if (laddr.s_addr == INADDR_ANY)
+ wildcard++;
+ else if (inp->inp_laddr.s_addr != laddr.s_addr)
+ continue;
+ } else {
+ if (laddr.s_addr != INADDR_ANY)
+ wildcard++;
+ }
+ if (inp->inp_faddr.s_addr != INADDR_ANY) {
+ if (faddr.s_addr == INADDR_ANY)
+ wildcard++;
+ else if (inp->inp_faddr.s_addr != faddr.s_addr ||
+ inp->inp_fport != fport)
+ continue;
+ } else {
+ if (faddr.s_addr != INADDR_ANY)
+ wildcard++;
+ }
+ if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
+ continue;
+ if (wildcard < matchwild) {
+ match = inp;
+ matchwild = wildcard;
+ if (matchwild == 0)
+ break;
+ }
+ }
+ return (match);
+}
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index dc147f090b51..c94cdd0a101b 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in_proto.c 7.5 (Berkeley) 6/28/90
- * $Id: in_proto.c,v 1.3 1993/12/19 00:52:38 wollman Exp $
+ * $Id: in_proto.c,v 1.4 1994/05/17 22:31:07 jkh Exp $
*/
#include "param.h"
@@ -55,6 +55,9 @@
#include "udp.h"
#include "udp_var.h" /* UDP prototypes */
+#include "igmp.h"
+#include "igmp_var.h" /* IGMP prototypes */
+
#include "tcp.h"
#include "tcp_fsm.h"
#include "tcp_seq.h"
@@ -160,6 +163,13 @@ struct in_protosw inetsw[] = {
eonprotoinit, 0, 0, 0,
},
#endif
+#ifdef MULTICAST
+{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
+ igmp_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq,
+ igmp_init, igmp_fasttimo, 0, 0,
+},
+#endif
#ifdef NSIP
{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
idpip_input, rip_output, nsip_ctlinput, 0,
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index 9e03a296adb4..70d7a8185f01 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)in_var.h 7.6 (Berkeley) 6/28/90
- * $Id: in_var.h,v 1.6 1993/12/19 21:43:26 wollman Exp $
+ * $Id: in_var.h,v 1.7 1994/05/17 22:31:08 jkh Exp $
*/
#ifndef _NETINET_IN_VAR_H_
@@ -58,6 +58,7 @@ struct in_ifaddr {
struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
#define ia_broadaddr ia_dstaddr
struct sockaddr_in ia_sockmask; /* reserve space for general netmask */
+ struct in_multi *ia_multiaddrs; /* list of multicast addresses */
};
struct in_aliasreq {
@@ -144,5 +145,119 @@ extern int in_routemtu(struct route *);
extern void in_mtureduce(struct in_addr, unsigned);
extern void in_mtutimer(caddr_t, int);
#endif /* MTUDISC */
+
+/*
+ * Macro for finding the interface (ifnet structure) corresponding to one
+ * of our IP addresses.
+ */
+#define INADDR_TO_IFP(addr, ifp) \
+ /* struct in_addr addr; */ \
+ /* struct ifnet *ifp; */ \
+{ \
+ register struct in_ifaddr *ia; \
+\
+ for (ia = in_ifaddr; \
+ ia != NULL && IA_SIN(ia)->sin_addr.s_addr != (addr).s_addr; \
+ ia = ia->ia_next) \
+ continue; \
+ (ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
+}
+
+/*
+ * Macro for finding the internet address structure (in_ifaddr) corresponding
+ * to a given interface (ifnet structure).
+ */
+#define IFP_TO_IA(ifp, ia) \
+ /* struct ifnet *ifp; */ \
+ /* struct in_ifaddr *ia; */ \
+{ \
+ for ((ia) = in_ifaddr; \
+ (ia) != NULL && (ia)->ia_ifp != (ifp); \
+ (ia) = (ia)->ia_next) \
+ continue; \
+}
+#endif
+
+/*
+ * Internet multicast address structure. There is one of these for each IP
+ * multicast group to which this host belongs on a given network interface.
+ * They are kept in a linked list, rooted in the interface's in_ifaddr
+ * structure.
+ */
+struct in_multi {
+ struct in_addr inm_addr; /* IP multicast address */
+ struct ifnet *inm_ifp; /* back pointer to ifnet */
+ struct in_ifaddr *inm_ia; /* back pointer to in_ifaddr */
+ u_int inm_refcount; /* no. membership claims by sockets */
+ u_int inm_timer; /* IGMP membership report timer */
+ struct in_multi *inm_next; /* ptr to next multicast address */
+};
+
+#ifdef KERNEL
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the in_multi records.
+ */
+struct in_multistep {
+ struct in_ifaddr *i_ia;
+ struct in_multi *i_inm;
+};
+
+/*
+ * Macro for looking up the in_multi record for a given IP multicast address
+ * on a given interface. If no matching record is found, "inm" returns NULL.
+ */
+#define IN_LOOKUP_MULTI(addr, ifp, inm) \
+ /* struct in_addr addr; */ \
+ /* struct ifnet *ifp; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ register struct in_ifaddr *ia; \
+\
+ IFP_TO_IA((ifp), ia); \
+ if (ia == NULL) \
+ (inm) = NULL; \
+ else \
+ for ((inm) = ia->ia_multiaddrs; \
+ (inm) != NULL && (inm)->inm_addr.s_addr != (addr).s_addr; \
+ (inm) = inm->inm_next) \
+ continue; \
+}
+
+/*
+ * Macro to step through all of the in_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide. IN_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record. Both macros return a NULL "inm" when there
+ * are no remaining records.
+ */
+#define IN_NEXT_MULTI(step, inm) \
+ /* struct in_multistep step; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ if (((inm) = (step).i_inm) != NULL) \
+ (step).i_inm = (inm)->inm_next; \
+ else \
+ while ((step).i_ia != NULL) { \
+ (inm) = (step).i_ia->ia_multiaddrs; \
+ (step).i_ia = (step).i_ia->ia_next; \
+ if ((inm) != NULL) { \
+ (step).i_inm = (inm)->inm_next; \
+ break; \
+ } \
+ } \
+}
+
+#define IN_FIRST_MULTI(step, inm) \
+ /* struct in_multistep step; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ (step).i_ia = in_ifaddr; \
+ (step).i_inm = NULL; \
+ IN_NEXT_MULTI((step), (inm)); \
+}
+
+struct in_multi *in_addmulti __P((struct in_addr *, struct ifnet *));
+int in_delmulti __P((struct in_multi *));
#endif /* KERNEL */
#endif /* _NETINET_IN_VAR_H_ */
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index ed9b199e1db4..c192ef2d908b 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ip_icmp.c 7.15 (Berkeley) 4/20/91
- * $Id: ip_icmp.c,v 1.6 1993/12/19 00:52:42 wollman Exp $
+ * $Id: ip_icmp.c,v 1.7 1994/05/17 22:31:09 jkh Exp $
*/
#include "param.h"
@@ -156,6 +156,11 @@ icmp_error(n, type, code, dest, mtu)
icmpstat.icps_oldicmp++;
goto freeit;
}
+#ifdef MULTICAST
+ /* Don't send error in response to a multicast or broadcast packet */
+ if(n->m_flags & (M_MCAST | M_BCAST))
+ goto freeit;
+#endif
/*
* First, formulate icmp message
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 6c45aed63234..426e757824d5 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * 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
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ip_input.c 7.19 (Berkeley) 5/25/91
- * $Id: ip_input.c,v 1.8 1994/01/04 17:47:13 ache Exp $
+ * $Id: ip_input.c,v 1.9 1994/05/17 22:31:10 jkh Exp $
*/
#include "param.h"
@@ -240,6 +240,53 @@ next:
goto ours;
}
}
+#ifdef MULTICAST
+ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ struct in_multi *inm;
+#ifdef MROUTING
+ extern struct socket *ip_mrouter;
+
+ if (ip_mrouter) {
+ /*
+ * If we are acting as a multicast router, all
+ * incoming multicast packets are passed to the
+ * kernel-level multicast forwarding function.
+ * The packet is returned (relatively) intact; if
+ * ip_mforward() returns a non-zero value, the packet
+ * must be discarded, else it may be accepted below.
+ *
+ * (The IP ident field is put in the same byte order
+ * as expected when ip_mforward() is called from
+ * ip_output().)
+ */
+ ip->ip_id = htons(ip->ip_id);
+ if (ip_mforward(ip, m->m_pkthdr.rcvif, m) != 0) {
+ m_freem(m);
+ goto next;
+ }
+ ip->ip_id = ntohs(ip->ip_id);
+
+ /*
+ * The process-level routing demon needs to receive
+ * all multicast IGMP packets, whether or not this
+ * host belongs to their destination groups.
+ */
+ if (ip->ip_p == IPPROTO_IGMP)
+ goto ours;
+ }
+#endif
+ /*
+ * See if we belong to the destination multicast group on the
+ * arrival interface.
+ */
+ IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
+ if (inm == NULL) {
+ m_freem(m);
+ goto next;
+ }
+ goto ours;
+ }
+#endif
if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
goto ours;
if (ip->ip_dst.s_addr == INADDR_ANY)
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
new file mode 100644
index 000000000000..7ce8361ea3b9
--- /dev/null
+++ b/sys/netinet/ip_mroute.c
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (c) 1989 Stephen Deering
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * @(#)ip_mroute.c 7.4 (Berkeley) 11/19/92
+ */
+
+/*
+ * Procedures for the kernel part of DVMRP,
+ * a Distance-Vector Multicast Routing Protocol.
+ * (See RFC-1075.)
+ *
+ * Written by David Waitzman, BBN Labs, August 1988.
+ * Modified by Steve Deering, Stanford, February 1989.
+ *
+ * MROUTING 1.1
+ */
+
+#ifndef MROUTING
+int ip_mrtproto; /* for netstat only */
+#else
+
+#include "param.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "time.h"
+
+#ifndef __FreeBSD__
+#include "net/af.h"
+#else
+#include "systm.h"
+#endif
+#include "net/if.h"
+#include "net/route.h"
+#include "net/raw_cb.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+#include "ip_var.h"
+
+#include "igmp.h"
+#include "igmp_var.h"
+#include "ip_mroute.h"
+
+/* Static forwards */
+static int ip_mrouter_init __P((struct socket *));
+static int add_vif __P((struct vifctl *));
+static int del_vif __P((vifi_t *vifip));
+static int add_lgrp __P((struct lgrplctl *));
+static int del_lgrp __P((struct lgrplctl *));
+static int grplst_member __P((struct vif *, struct in_addr));
+static u_long nethash __P((u_long in));
+static int add_mrt __P((struct mrtctl *));
+static int del_mrt __P((struct in_addr *));
+static struct mrt *mrtfind __P((u_long));
+static void phyint_send __P((struct ip *, struct vif *, struct mbuf *));
+static void srcrt_send __P((struct ip *, struct vif *, struct mbuf *));
+static void encap_send __P((struct ip *, struct vif *, struct mbuf *));
+static void multiencap_decap __P((struct mbuf *, int hlen));
+
+#define INSIZ sizeof(struct in_addr)
+#define same(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+
+/*
+ * Globals. All but ip_mrouter and ip_mrtproto could be static,
+ * except for netstat or debugging purposes.
+ */
+struct socket *ip_mrouter = NULL;
+int ip_mrtproto = IGMP_DVMRP; /* for netstat only */
+
+struct mrt *mrttable[MRTHASHSIZ];
+struct vif viftable[MAXVIFS];
+struct mrtstat mrtstat;
+
+/*
+ * 'Interfaces' associated with decapsulator (so we can tell
+ * packets that went through it from ones that get reflected
+ * by a broken gateway). These interfaces are never linked into
+ * the system ifnet list & no routes point to them. I.e., packets
+ * can't be sent this way. They only exist as a placeholder for
+ * multicast source verification.
+ */
+struct ifnet multicast_decap_if[MAXVIFS];
+
+#define ENCAP_TTL 64
+#define ENCAP_PROTO 4
+
+/* prototype IP hdr for encapsulated packets */
+struct ip multicast_encap_iphdr = {
+#if defined(ultrix) || defined(i386)
+ sizeof(struct ip) >> 2, IPVERSION,
+#else
+ IPVERSION, sizeof(struct ip) >> 2,
+#endif
+ 0, /* tos */
+ sizeof(struct ip), /* total length */
+ 0, /* id */
+ 0, /* frag offset */
+ ENCAP_TTL, ENCAP_PROTO,
+ 0, /* checksum */
+};
+
+/*
+ * Private variables.
+ */
+static vifi_t numvifs = 0;
+static struct mrt *cached_mrt = NULL;
+static u_long cached_origin;
+static u_long cached_originmask;
+
+static void (*encap_oldrawip)();
+
+/*
+ * one-back cache used by multiencap_decap to locate a tunnel's vif
+ * given a datagram's src ip address.
+ */
+static u_long last_encap_src;
+static struct vif *last_encap_vif;
+
+/*
+ * A simple hash function: returns MRTHASHMOD of the low-order octet of
+ * the argument's network or subnet number.
+ */
+static u_long
+nethash(n)
+ u_long n;
+{
+ struct in_addr in;
+
+ in.s_addr = n;
+ n = in_netof(in);
+ while ((n & 0xff) == 0)
+ n >>= 8;
+ return (MRTHASHMOD(n));
+}
+
+/*
+ * this is a direct-mapped cache used to speed the mapping from a
+ * datagram source address to the associated multicast route. Note
+ * that unlike mrttable, the hash is on IP address, not IP net number.
+ */
+#define MSRCHASHSIZ 1024
+#define MSRCHASH(a) ((((a) >> 20) ^ ((a) >> 10) ^ (a)) & (MSRCHASHSIZ - 1))
+struct mrt *mrtsrchash[MSRCHASHSIZ];
+
+/*
+ * Find a route for a given origin IP address.
+ */
+#define MRTFIND(o, rt) { \
+ register u_int _mrhash = o; \
+ _mrhash = MSRCHASH(_mrhash); \
+ ++mrtstat.mrts_mrt_lookups; \
+ rt = mrtsrchash[_mrhash]; \
+ if (rt == NULL || \
+ (o & rt->mrt_originmask.s_addr) != rt->mrt_origin.s_addr) \
+ if ((rt = mrtfind(o)) != NULL) \
+ mrtsrchash[_mrhash] = rt; \
+}
+
+static struct mrt *
+mrtfind(origin)
+ u_long origin;
+{
+ register struct mrt *rt;
+ register u_int hash;
+
+ mrtstat.mrts_mrt_misses++;
+
+ hash = nethash(origin);
+ for (rt = mrttable[hash]; rt; rt = rt->mrt_next) {
+ if ((origin & rt->mrt_originmask.s_addr) ==
+ rt->mrt_origin.s_addr)
+ return (rt);
+ }
+ return (NULL);
+}
+
+/*
+ * Handle DVMRP setsockopt commands to modify the multicast routing tables.
+ */
+int
+ip_mrouter_cmd(cmd, so, m)
+ register int cmd;
+ register struct socket *so;
+ register struct mbuf *m;
+{
+ register int error = 0;
+
+ if (cmd != DVMRP_INIT && so != ip_mrouter)
+ error = EACCES;
+ else switch (cmd) {
+
+ case DVMRP_INIT:
+ error = ip_mrouter_init(so);
+ break;
+
+ case DVMRP_DONE:
+ error = ip_mrouter_done();
+ break;
+
+ case DVMRP_ADD_VIF:
+ if (m == NULL || m->m_len < sizeof(struct vifctl))
+ error = EINVAL;
+ else
+ error = add_vif(mtod(m, struct vifctl *));
+ break;
+
+ case DVMRP_DEL_VIF:
+ if (m == NULL || m->m_len < sizeof(short))
+ error = EINVAL;
+ else
+ error = del_vif(mtod(m, vifi_t *));
+ break;
+
+ case DVMRP_ADD_LGRP:
+ if (m == NULL || m->m_len < sizeof(struct lgrplctl))
+ error = EINVAL;
+ else
+ error = add_lgrp(mtod(m, struct lgrplctl *));
+ break;
+
+ case DVMRP_DEL_LGRP:
+ if (m == NULL || m->m_len < sizeof(struct lgrplctl))
+ error = EINVAL;
+ else
+ error = del_lgrp(mtod(m, struct lgrplctl *));
+ break;
+
+ case DVMRP_ADD_MRT:
+ if (m == NULL || m->m_len < sizeof(struct mrtctl))
+ error = EINVAL;
+ else
+ error = add_mrt(mtod(m, struct mrtctl *));
+ break;
+
+ case DVMRP_DEL_MRT:
+ if (m == NULL || m->m_len < sizeof(struct in_addr))
+ error = EINVAL;
+ else
+ error = del_mrt(mtod(m, struct in_addr *));
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
+/*
+ * Enable multicast routing
+ */
+static int
+ip_mrouter_init(so)
+ register struct socket *so;
+{
+ if (so->so_type != SOCK_RAW ||
+ so->so_proto->pr_protocol != IPPROTO_IGMP)
+ return (EOPNOTSUPP);
+
+ if (ip_mrouter != NULL)
+ return (EADDRINUSE);
+
+ ip_mrouter = so;
+
+ return (0);
+}
+
+/*
+ * Disable multicast routing
+ */
+int
+ip_mrouter_done()
+{
+ register vifi_t vifi;
+ register int i;
+ register struct ifnet *ifp;
+ register int s;
+ struct ifreq ifr;
+
+ s = splnet();
+
+ /*
+ * For each phyint in use, free its local group list and
+ * disable promiscuous reception of all IP multicasts.
+ */
+ for (vifi = 0; vifi < numvifs; vifi++) {
+ if (viftable[vifi].v_lcl_addr.s_addr != 0 &&
+ !(viftable[vifi].v_flags & VIFF_TUNNEL)) {
+ if (viftable[vifi].v_lcl_grps)
+ free(viftable[vifi].v_lcl_grps, M_MRTABLE);
+ satosin(&ifr.ifr_addr)->sin_family = AF_INET;
+ satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
+ ifp = viftable[vifi].v_ifp;
+ (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
+ }
+ }
+ bzero((caddr_t)viftable, sizeof(viftable));
+ numvifs = 0;
+
+ /*
+ * Free any multicast route entries.
+ */
+ for (i = 0; i < MRTHASHSIZ; i++)
+ if (mrttable[i])
+ free(mrttable[i], M_MRTABLE);
+ bzero((caddr_t)mrttable, sizeof(mrttable));
+ bzero((caddr_t)mrtsrchash, sizeof(mrtsrchash));
+
+ ip_mrouter = NULL;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Add a vif to the vif table
+ */
+static int
+add_vif(vifcp)
+ register struct vifctl *vifcp;
+{
+ register struct vif *vifp = viftable + vifcp->vifc_vifi;
+ register struct ifaddr *ifa;
+ register struct ifnet *ifp;
+ struct ifreq ifr;
+ register int error, s;
+ static struct sockaddr_in sin = { sizeof(sin), AF_INET };
+
+ if (vifcp->vifc_vifi >= MAXVIFS)
+ return (EINVAL);
+ if (vifp->v_lcl_addr.s_addr != 0)
+ return (EADDRINUSE);
+
+ /* Find the interface with an address in AF_INET family */
+ sin.sin_addr = vifcp->vifc_lcl_addr;
+ ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
+ if (ifa == 0)
+ return (EADDRNOTAVAIL);
+ ifp = ifa->ifa_ifp;
+
+ if (vifcp->vifc_flags & VIFF_TUNNEL) {
+ if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) {
+ /*
+ * An encapsulating tunnel is wanted. If we
+ * haven't done so already, put our decap routine
+ * in front of raw_input so we have a chance to
+ * decapsulate incoming packets. Then set the
+ * arrival 'interface' to be the decapsulator.
+ */
+ if (encap_oldrawip == 0) {
+ register int pr = ip_protox[ENCAP_PROTO];
+
+ encap_oldrawip = inetsw[pr].pr_input;
+ inetsw[pr].pr_input = multiencap_decap;
+ for (s = 0; s < MAXVIFS; ++s) {
+ multicast_decap_if[s].if_name =
+ "mdecap";
+ multicast_decap_if[s].if_unit = s;
+ }
+ }
+ ifp = &multicast_decap_if[vifcp->vifc_vifi];
+ } else {
+ ifp = 0;
+ }
+ } else {
+ /* Make sure the interface supports multicast */
+ if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ return EOPNOTSUPP;
+
+ /*
+ * Enable promiscuous reception of all
+ * IP multicasts from the if
+ */
+ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
+ INADDR_ANY;
+ s = splnet();
+ error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
+ splx(s);
+ if (error)
+ return error;
+ }
+
+ s = splnet();
+ vifp->v_flags = vifcp->vifc_flags;
+ vifp->v_threshold = vifcp->vifc_threshold;
+ vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
+ vifp->v_ifp = ifa->ifa_ifp;
+ vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
+ splx(s);
+
+ /* Adjust numvifs up if the vifi is higher than numvifs */
+ if (numvifs <= vifcp->vifc_vifi)
+ numvifs = vifcp->vifc_vifi + 1;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Delete a vif from the vif table
+ */
+static int
+del_vif(vifip)
+ register vifi_t *vifip;
+{
+ register struct vif *vifp = viftable + *vifip;
+ register struct ifnet *ifp;
+ register int i, s;
+ struct ifreq ifr;
+
+ if (*vifip >= numvifs)
+ return (EINVAL);
+ if (vifp->v_lcl_addr.s_addr == 0)
+ return (EADDRNOTAVAIL);
+
+ s = splnet();
+
+ if (!(vifp->v_flags & VIFF_TUNNEL)) {
+ if (vifp->v_lcl_grps)
+ free(vifp->v_lcl_grps, M_MRTABLE);
+ satosin(&ifr.ifr_addr)->sin_family = AF_INET;
+ satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
+ ifp = vifp->v_ifp;
+ (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
+ }
+ if (vifp == last_encap_vif) {
+ last_encap_vif = 0;
+ last_encap_src = 0;
+ }
+ bzero((caddr_t)vifp, sizeof (*vifp));
+
+ /* Adjust numvifs down */
+ for (i = numvifs - 1; i >= 0; i--)
+ if (viftable[i].v_lcl_addr.s_addr != 0)
+ break;
+ numvifs = i + 1;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Add the multicast group in the lgrpctl to the list of local multicast
+ * group memberships associated with the vif indexed by gcp->lgc_vifi.
+ */
+static int
+add_lgrp(gcp)
+ register struct lgrplctl *gcp;
+{
+ register struct vif *vifp;
+ register int s;
+
+ if (gcp->lgc_vifi >= numvifs)
+ return (EINVAL);
+
+ vifp = viftable + gcp->lgc_vifi;
+ if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
+ return (EADDRNOTAVAIL);
+
+ /* If not enough space in existing list, allocate a larger one */
+ s = splnet();
+ if (vifp->v_lcl_grps_n + 1 >= vifp->v_lcl_grps_max) {
+ register int num;
+ register struct in_addr *ip;
+
+ num = vifp->v_lcl_grps_max;
+ if (num <= 0)
+ num = 32; /* initial number */
+ else
+ num += num; /* double last number */
+ ip = (struct in_addr *)malloc(num * sizeof(*ip),
+ M_MRTABLE, M_NOWAIT);
+ if (ip == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+
+ bzero((caddr_t)ip, num * sizeof(*ip)); /* XXX paranoid */
+ bcopy((caddr_t)vifp->v_lcl_grps, (caddr_t)ip,
+ vifp->v_lcl_grps_n * sizeof(*ip));
+
+ vifp->v_lcl_grps_max = num;
+ if (vifp->v_lcl_grps)
+ free(vifp->v_lcl_grps, M_MRTABLE);
+ vifp->v_lcl_grps = ip;
+ }
+
+ vifp->v_lcl_grps[vifp->v_lcl_grps_n++] = gcp->lgc_gaddr;
+
+ if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
+ vifp->v_cached_result = 1;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Delete the the local multicast group associated with the vif
+ * indexed by gcp->lgc_vifi.
+ */
+
+static int
+del_lgrp(gcp)
+ register struct lgrplctl *gcp;
+{
+ register struct vif *vifp;
+ register int i, error, s;
+
+ if (gcp->lgc_vifi >= numvifs)
+ return (EINVAL);
+ vifp = viftable + gcp->lgc_vifi;
+ if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
+ return (EADDRNOTAVAIL);
+
+ s = splnet();
+
+ if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
+ vifp->v_cached_result = 0;
+
+ error = EADDRNOTAVAIL;
+ for (i = 0; i < vifp->v_lcl_grps_n; ++i)
+ if (same(&gcp->lgc_gaddr, &vifp->v_lcl_grps[i])) {
+ error = 0;
+ --vifp->v_lcl_grps_n;
+ for (; i < vifp->v_lcl_grps_n; ++i)
+ vifp->v_lcl_grps[i] = vifp->v_lcl_grps[i + 1];
+ error = 0;
+ break;
+ }
+
+ splx(s);
+ return (error);
+}
+
+/*
+ * Return 1 if gaddr is a member of the local group list for vifp.
+ */
+static int
+grplst_member(vifp, gaddr)
+ register struct vif *vifp;
+ struct in_addr gaddr;
+{
+ register int i, s;
+ register u_long addr;
+
+ mrtstat.mrts_grp_lookups++;
+
+ addr = gaddr.s_addr;
+ if (addr == vifp->v_cached_group)
+ return (vifp->v_cached_result);
+
+ mrtstat.mrts_grp_misses++;
+
+ for (i = 0; i < vifp->v_lcl_grps_n; ++i)
+ if (addr == vifp->v_lcl_grps[i].s_addr) {
+ s = splnet();
+ vifp->v_cached_group = addr;
+ vifp->v_cached_result = 1;
+ splx(s);
+ return (1);
+ }
+ s = splnet();
+ vifp->v_cached_group = addr;
+ vifp->v_cached_result = 0;
+ splx(s);
+ return (0);
+}
+
+/*
+ * Add an mrt entry
+ */
+static int
+add_mrt(mrtcp)
+ register struct mrtctl *mrtcp;
+{
+ struct mrt *rt;
+ u_long hash;
+ int s;
+
+ if (rt = mrtfind(mrtcp->mrtc_origin.s_addr)) {
+ /* Just update the route */
+ s = splnet();
+ rt->mrt_parent = mrtcp->mrtc_parent;
+ VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
+ VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
+ splx(s);
+ return (0);
+ }
+
+ s = splnet();
+
+ rt = (struct mrt *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
+ if (rt == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+
+ /*
+ * insert new entry at head of hash chain
+ */
+ rt->mrt_origin = mrtcp->mrtc_origin;
+ rt->mrt_originmask = mrtcp->mrtc_originmask;
+ rt->mrt_parent = mrtcp->mrtc_parent;
+ VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
+ VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
+ /* link into table */
+ hash = nethash(mrtcp->mrtc_origin.s_addr);
+ rt->mrt_next = mrttable[hash];
+ mrttable[hash] = rt;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Delete an mrt entry
+ */
+static int
+del_mrt(origin)
+ register struct in_addr *origin;
+{
+ register struct mrt *rt, *prev_rt;
+ register u_long hash = nethash(origin->s_addr);
+ register struct mrt **cmrt, **cmrtend;
+ register int s;
+
+ for (prev_rt = rt = mrttable[hash]; rt; prev_rt = rt, rt = rt->mrt_next)
+ if (origin->s_addr == rt->mrt_origin.s_addr)
+ break;
+ if (!rt)
+ return (ESRCH);
+
+ s = splnet();
+
+ cmrt = mrtsrchash;
+ cmrtend = cmrt + MSRCHASHSIZ;
+ for ( ; cmrt < cmrtend; ++cmrt)
+ if (*cmrt == rt)
+ *cmrt = 0;
+
+ if (prev_rt == rt)
+ mrttable[hash] = rt->mrt_next;
+ else
+ prev_rt->mrt_next = rt->mrt_next;
+ free(rt, M_MRTABLE);
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * IP multicast forwarding function. This function assumes that the packet
+ * pointed to by "ip" has arrived on (or is about to be sent to) the interface
+ * pointed to by "ifp", and the packet is to be relayed to other networks
+ * that have members of the packet's destination IP multicast group.
+ *
+ * The packet is returned unscathed to the caller, unless it is tunneled
+ * or erroneous, in which case a non-zero return value tells the caller to
+ * discard it.
+ */
+
+#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */
+#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */
+
+int
+ip_mforward(ip, ifp, m)
+ register struct ip *ip;
+ register struct ifnet *ifp;
+ register struct mbuf *m;
+{
+ register struct mrt *rt;
+ register struct vif *vifp;
+ register int vifi;
+ register u_char *ipoptions;
+ u_long tunnel_src;
+
+ if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
+ (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
+ /*
+ * Packet arrived via a physical interface.
+ */
+ tunnel_src = 0;
+ } else {
+ /*
+ * Packet arrived through a tunnel.
+ *
+ * A tunneled packet has a single NOP option and a
+ * two-element loose-source-and-record-route (LSRR)
+ * option immediately following the fixed-size part of
+ * the IP header. At this point in processing, the IP
+ * header should contain the following IP addresses:
+ *
+ * original source - in the source address field
+ * destination group - in the destination address field
+ * remote tunnel end-point - in the first element of LSRR
+ * one of this host's addrs - in the second element of LSRR
+ *
+ * NOTE: RFC-1075 would have the original source and
+ * remote tunnel end-point addresses swapped. However,
+ * that could cause delivery of ICMP error messages to
+ * innocent applications on intermediate routing
+ * hosts! Therefore, we hereby change the spec.
+ */
+
+ /*
+ * Verify that the tunnel options are well-formed.
+ */
+ if (ipoptions[0] != IPOPT_NOP ||
+ ipoptions[2] != 11 || /* LSRR option length */
+ ipoptions[3] != 12 || /* LSRR address pointer */
+ (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) {
+ mrtstat.mrts_bad_tunnel++;
+ return (1);
+ }
+
+ /*
+ * Delete the tunnel options from the packet.
+ */
+ ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions,
+ (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN)));
+ m->m_len -= TUNNEL_LEN;
+ ip->ip_len -= TUNNEL_LEN;
+ ip->ip_hl -= TUNNEL_LEN >> 2;
+ }
+
+ /*
+ * Don't forward a packet with time-to-live of zero or one,
+ * or a packet destined to a local-only group.
+ */
+ if (ip->ip_ttl <= 1 ||
+ ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP)
+ return ((int)tunnel_src);
+
+ /*
+ * Don't forward if we don't have a route for the packet's origin.
+ */
+ MRTFIND(ip->ip_src.s_addr, rt)
+ if (rt == NULL) {
+ mrtstat.mrts_no_route++;
+ return ((int)tunnel_src);
+ }
+
+ /*
+ * Don't forward if it didn't arrive from the
+ * parent vif for its origin.
+ *
+ * Notes: v_ifp is zero for src route tunnels, multicast_decap_if
+ * for encapsulated tunnels and a real ifnet for non-tunnels so
+ * the first part of the if catches wrong physical interface or
+ * tunnel type; v_rmt_addr is zero for non-tunneled packets so
+ * the 2nd part catches both packets that arrive via a tunnel
+ * that shouldn't and packets that arrive via the wrong tunnel.
+ */
+ vifi = rt->mrt_parent;
+ if (viftable[vifi].v_ifp != ifp ||
+ (ifp == 0 && viftable[vifi].v_rmt_addr.s_addr != tunnel_src)) {
+ /* came in the wrong interface */
+ ++mrtstat.mrts_wrong_if;
+ return (int)tunnel_src;
+ }
+
+ /*
+ * For each vif, decide if a copy of the packet should be forwarded.
+ * Forward if:
+ * - the ttl exceeds the vif's threshold AND
+ * - the vif is a child in the origin's route AND
+ * - ( the vif is not a leaf in the origin's route OR
+ * the destination group has members on the vif )
+ *
+ * (This might be speeded up with some sort of cache -- someday.)
+ */
+ for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) {
+ if (ip->ip_ttl > vifp->v_threshold &&
+ VIFM_ISSET(vifi, rt->mrt_children) &&
+ (!VIFM_ISSET(vifi, rt->mrt_leaves) ||
+ grplst_member(vifp, ip->ip_dst))) {
+ if (vifp->v_flags & VIFF_SRCRT)
+ srcrt_send(ip, vifp, m);
+ else if (vifp->v_flags & VIFF_TUNNEL)
+ encap_send(ip, vifp, m);
+ else
+ phyint_send(ip, vifp, m);
+ }
+ }
+ return ((int)tunnel_src);
+}
+
+static void
+phyint_send(ip, vifp, m)
+ register struct ip *ip;
+ register struct vif *vifp;
+ register struct mbuf *m;
+{
+ register struct mbuf *mb_copy;
+ register struct ip_moptions *imo;
+ register int error;
+ struct ip_moptions simo;
+
+ mb_copy = m_copy(m, 0, M_COPYALL);
+ if (mb_copy == NULL)
+ return;
+
+ imo = &simo;
+ imo->imo_multicast_ifp = vifp->v_ifp;
+ imo->imo_multicast_ttl = ip->ip_ttl - 1;
+ imo->imo_multicast_loop = 1;
+
+ error = ip_output(mb_copy, NULL, NULL,
+ IP_FORWARDING|IP_MULTICASTOPTS, imo);
+}
+
+static void
+srcrt_send(ip, vifp, m)
+ register struct ip *ip;
+ register struct vif *vifp;
+ register struct mbuf *m;
+{
+ register struct mbuf *mb_copy, *mb_opts;
+ register struct ip *ip_copy;
+ register int error;
+ register u_char *cp;
+
+ /*
+ * Make sure that adding the tunnel options won't exceed the
+ * maximum allowed number of option bytes.
+ */
+ if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) {
+ mrtstat.mrts_cant_tunnel++;
+ return;
+ }
+
+ mb_copy = m_copy(m, 0, M_COPYALL);
+ if (mb_copy == NULL)
+ return;
+ ip_copy = mtod(mb_copy, struct ip *);
+ ip_copy->ip_ttl--;
+ ip_copy->ip_dst = vifp->v_rmt_addr; /* remote tunnel end-point */
+ /*
+ * Adjust the ip header length to account for the tunnel options.
+ */
+ ip_copy->ip_hl += TUNNEL_LEN >> 2;
+ ip_copy->ip_len += TUNNEL_LEN;
+ MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
+ if (mb_opts == NULL) {
+ m_freem(mb_copy);
+ return;
+ }
+ /*
+ * 'Delete' the base ip header from the mb_copy chain
+ */
+ mb_copy->m_len -= IP_HDR_LEN;
+ mb_copy->m_data += IP_HDR_LEN;
+ /*
+ * Make mb_opts be the new head of the packet chain.
+ * Any options of the packet were left in the old packet chain head
+ */
+ mb_opts->m_next = mb_copy;
+ mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;
+ mb_opts->m_data += MSIZE - mb_opts->m_len;
+ /*
+ * Copy the base ip header from the mb_copy chain to the new head mbuf
+ */
+ bcopy((caddr_t)ip_copy, mtod(mb_opts, caddr_t), IP_HDR_LEN);
+ /*
+ * Add the NOP and LSRR after the base ip header
+ */
+ cp = mtod(mb_opts, u_char *) + IP_HDR_LEN;
+ *cp++ = IPOPT_NOP;
+ *cp++ = IPOPT_LSRR;
+ *cp++ = 11; /* LSRR option length */
+ *cp++ = 8; /* LSSR pointer to second element */
+ *(u_long*)cp = vifp->v_lcl_addr.s_addr; /* local tunnel end-point */
+ cp += 4;
+ *(u_long*)cp = ip->ip_dst.s_addr; /* destination group */
+
+ error = ip_output(mb_opts, NULL, NULL, IP_FORWARDING, NULL);
+}
+
+static void
+encap_send(ip, vifp, m)
+ register struct ip *ip;
+ register struct vif *vifp;
+ register struct mbuf *m;
+{
+ register struct mbuf *mb_copy;
+ register struct ip *ip_copy;
+ register int i, len = ip->ip_len;
+
+ /*
+ * copy the old packet & pullup it's IP header into the
+ * new mbuf so we can modify it. Try to fill the new
+ * mbuf since if we don't the ethernet driver will.
+ */
+ MGETHDR(mb_copy, M_DONTWAIT, MT_HEADER);
+ if (mb_copy == NULL)
+ return;
+ mb_copy->m_data += 16;
+ mb_copy->m_len = sizeof(multicast_encap_iphdr);
+ if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
+ m_freem(mb_copy);
+ return;
+ }
+ i = MHLEN - 16;
+ if (i > len)
+ i = len;
+ mb_copy = m_pullup(mb_copy, i);
+ if (mb_copy == NULL)
+ return;
+
+ /*
+ * fill in the encapsulating IP header.
+ */
+ ip_copy = mtod(mb_copy, struct ip *);
+ *ip_copy = multicast_encap_iphdr;
+ ip_copy->ip_id = htons(ip_id++);
+ ip_copy->ip_len += len;
+ ip_copy->ip_src = vifp->v_lcl_addr;
+ ip_copy->ip_dst = vifp->v_rmt_addr;
+
+ /*
+ * turn the encapsulated IP header back into a valid one.
+ */
+ ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr));
+ --ip->ip_ttl;
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+#if defined(LBL) && !defined(ultrix) && !defined(i386)
+ ip->ip_sum = ~oc_cksum((caddr_t)ip, ip->ip_hl << 2, 0);
+#else
+ mb_copy->m_data += sizeof(multicast_encap_iphdr);
+ ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2);
+ mb_copy->m_data -= sizeof(multicast_encap_iphdr);
+#endif
+ ip_output(mb_copy, (struct mbuf *)0, (struct route *)0,
+ IP_FORWARDING, (struct mbuf *)0);
+}
+
+/*
+ * De-encapsulate a packet and feed it back through ip input (this
+ * routine is called whenever IP gets a packet with proto type
+ * ENCAP_PROTO and a local destination address).
+ */
+static void
+multiencap_decap(m, hlen)
+ register struct mbuf *m;
+ int hlen;
+{
+ struct ifnet *ifp;
+ register struct ip *ip = mtod(m, struct ip *);
+ register int s;
+ register struct ifqueue *ifq;
+ register struct vif *vifp;
+
+ if (ip->ip_p != ENCAP_PROTO) {
+ (*encap_oldrawip)(m, hlen);
+ return;
+ }
+ /*
+ * dump the packet if it's not to a multicast destination or if
+ * we don't have an encapsulating tunnel with the source.
+ * Note: This code assumes that the remote site IP address
+ * uniquely identifies the tunnel (i.e., that this site has
+ * at most one tunnel with the remote site).
+ */
+ if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) {
+ ++mrtstat.mrts_bad_tunnel;
+ m_freem(m);
+ return;
+ }
+ if (ip->ip_src.s_addr != last_encap_src) {
+ register struct vif *vife;
+
+ vifp = viftable;
+ vife = vifp + numvifs;
+ last_encap_src = ip->ip_src.s_addr;
+ last_encap_vif = 0;
+ for ( ; vifp < vife; ++vifp)
+ if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) {
+ if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT))
+ == VIFF_TUNNEL)
+ last_encap_vif = vifp;
+ break;
+ }
+ }
+ if ((vifp = last_encap_vif) == 0) {
+ mrtstat.mrts_cant_tunnel++; /*XXX*/
+ m_freem(m);
+ return;
+ }
+ ifp = vifp->v_ifp;
+ m->m_data += hlen;
+ m->m_len -= hlen;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len -= hlen;
+ ifq = &ipintrq;
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ m_freem(m);
+ } else {
+ IF_ENQUEUE(ifq, m);
+ /*
+ * normally we would need a "schednetisr(NETISR_IP)"
+ * here but we were called by ip_input and it is going
+ * to loop back & try to dequeue the packet we just
+ * queued as soon as we return so we avoid the
+ * unnecessary software interrrupt.
+ */
+ }
+ splx(s);
+}
+#endif
diff --git a/sys/netinet/ip_mroute.h b/sys/netinet/ip_mroute.h
new file mode 100644
index 000000000000..4b3c753998df
--- /dev/null
+++ b/sys/netinet/ip_mroute.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1989 Stephen Deering.
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * @(#)ip_mroute.h 7.2 (Berkeley) 7/8/92
+ */
+
+/*
+ * Definitions for the kernel part of DVMRP,
+ * a Distance-Vector Multicast Routing Protocol.
+ * (See RFC-1075.)
+ *
+ * Written by David Waitzman, BBN Labs, August 1988.
+ * Modified by Steve Deering, Stanford, February 1989.
+ *
+ * MROUTING 1.0
+ */
+
+
+/*
+ * DVMRP-specific setsockopt commands.
+ */
+#define DVMRP_INIT 100
+#define DVMRP_DONE 101
+#define DVMRP_ADD_VIF 102
+#define DVMRP_DEL_VIF 103
+#define DVMRP_ADD_LGRP 104
+#define DVMRP_DEL_LGRP 105
+#define DVMRP_ADD_MRT 106
+#define DVMRP_DEL_MRT 107
+
+
+/*
+ * Types and macros for handling bitmaps with one bit per virtual interface.
+ */
+#define MAXVIFS 32
+typedef u_long vifbitmap_t;
+typedef u_short vifi_t; /* type of a vif index */
+
+#define VIFM_SET(n, m) ((m) |= (1 << (n)))
+#define VIFM_CLR(n, m) ((m) &= ~(1 << (n)))
+#define VIFM_ISSET(n, m) ((m) & (1 << (n)))
+#define VIFM_CLRALL(m) ((m) = 0x00000000)
+#define VIFM_COPY(mfrom, mto) ((mto) = (mfrom))
+#define VIFM_SAME(m1, m2) ((m1) == (m2))
+
+
+/*
+ * Agument structure for DVMRP_ADD_VIF.
+ * (DVMRP_DEL_VIF takes a single vifi_t argument.)
+ */
+struct vifctl {
+ vifi_t vifc_vifi; /* the index of the vif to be added */
+ u_char vifc_flags; /* VIFF_ flags defined below */
+ u_char vifc_threshold; /* min ttl required to forward on vif */
+ struct in_addr vifc_lcl_addr; /* local interface address */
+ struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */
+};
+
+#define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */
+#define VIFF_SRCRT 0x2 /* tunnel uses IP src routing */
+
+
+/*
+ * Argument structure for DVMRP_ADD_LGRP and DVMRP_DEL_LGRP.
+ */
+struct lgrplctl {
+ vifi_t lgc_vifi;
+ struct in_addr lgc_gaddr;
+};
+
+
+/*
+ * Argument structure for DVMRP_ADD_MRT.
+ * (DVMRP_DEL_MRT takes a single struct in_addr argument, containing origin.)
+ */
+struct mrtctl {
+ struct in_addr mrtc_origin; /* subnet origin of multicasts */
+ struct in_addr mrtc_originmask; /* subnet mask for origin */
+ vifi_t mrtc_parent; /* incoming vif */
+ vifbitmap_t mrtc_children; /* outgoing children vifs */
+ vifbitmap_t mrtc_leaves; /* subset of outgoing children vifs */
+};
+
+
+#ifdef KERNEL
+
+/*
+ * The kernel's virtual-interface structure.
+ */
+struct vif {
+ u_char v_flags; /* VIFF_ flags defined above */
+ u_char v_threshold; /* min ttl required to forward on vif */
+ struct in_addr v_lcl_addr; /* local interface address */
+ struct in_addr v_rmt_addr; /* remote address (tunnels only) */
+ struct ifnet *v_ifp; /* pointer to interface */
+ struct in_addr *v_lcl_grps; /* list of local grps (phyints only) */
+ int v_lcl_grps_max; /* malloc'ed number of v_lcl_grps */
+ int v_lcl_grps_n; /* used number of v_lcl_grps */
+ u_long v_cached_group; /* last grp looked-up (phyints only) */
+ int v_cached_result; /* last look-up result (phyints only) */
+};
+
+/*
+ * The kernel's multicast route structure.
+ */
+struct mrt {
+ struct in_addr mrt_origin; /* subnet origin of multicasts */
+ struct in_addr mrt_originmask; /* subnet mask for origin */
+ vifi_t mrt_parent; /* incoming vif */
+ vifbitmap_t mrt_children; /* outgoing children vifs */
+ vifbitmap_t mrt_leaves; /* subset of outgoing children vifs */
+ struct mrt *mrt_next; /* forward link */
+};
+
+
+#define MRTHASHSIZ 256
+#if (MRTHASHSIZ & (MRTHASHSIZ - 1)) == 0 /* from sys:route.h */
+#define MRTHASHMOD(h) ((h) & (MRTHASHSIZ - 1))
+#else
+#define MRTHASHMOD(h) ((h) % MRTHASHSIZ)
+#endif
+
+/*
+ * The kernel's multicast routing statistics.
+ */
+struct mrtstat {
+ u_long mrts_mrt_lookups; /* # multicast route lookups */
+ u_long mrts_mrt_misses; /* # multicast route cache misses */
+ u_long mrts_grp_lookups; /* # group address lookups */
+ u_long mrts_grp_misses; /* # group address cache misses */
+ u_long mrts_no_route; /* no route for packet's origin */
+ u_long mrts_bad_tunnel; /* malformed tunnel options */
+ u_long mrts_cant_tunnel; /* no room for tunnel options */
+ u_long mrts_wrong_if; /* arrived on wrong interface */
+};
+
+int ip_mrouter_cmd __P((int, struct socket *, struct mbuf *));
+int ip_mrouter_done __P(());
+
+#endif /* KERNEL */
+
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index e9b459e870b8..f1b9975133a8 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ * 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
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ip_output.c 7.23 (Berkeley) 11/12/90
- * $Id: ip_output.c,v 1.5 1993/12/19 00:52:45 wollman Exp $
+ * $Id: ip_output.c,v 1.7 1994/05/26 22:42:15 jkh Exp $
*/
#include "param.h"
@@ -58,6 +58,7 @@
#endif
struct mbuf *ip_insertoptions();
+void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
/*
* IP output. The packet in mbuf chain m contains a skeletal IP
@@ -66,11 +67,18 @@ struct mbuf *ip_insertoptions();
* The mbuf opt, if present, will not be freed.
*/
int
-ip_output(m0, opt, ro, flags)
+ip_output(m0, opt, ro, flags
+#ifdef MULTICAST
+ , imo
+#endif
+ )
struct mbuf *m0;
struct mbuf *opt;
struct route *ro;
int flags;
+#ifdef MULTICAST
+ struct ip_moptions *imo;
+#endif
{
register struct ip *ip, *mhip;
register struct ifnet *ifp;
@@ -152,6 +160,97 @@ ip_output(m0, opt, ro, flags)
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
}
+#ifdef MULTICAST
+ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ struct in_multi *inm;
+ extern struct ifnet loif;
+ extern struct socket *ip_mrouter;
+
+ m->m_flags |= M_MCAST;
+ /*
+ * IP destination address is multicast. Make sure "dst"
+ * still points to the address in "ro". (It may have been
+ * changed to point to a gateway address, above.)
+ */
+ dst = (struct sockaddr_in *)&ro->ro_dst;
+ /*
+ * See if the caller provided any multicast options
+ */
+ if ((flags & IP_MULTICASTOPTS) && imo != NULL) {
+ ip->ip_ttl = imo->imo_multicast_ttl;
+ if (imo->imo_multicast_ifp != NULL)
+ ifp = imo->imo_multicast_ifp;
+ } else {
+ imo = NULL;
+ ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
+ }
+ /*
+ * Confirm that the outgoing interface supports multicast.
+ */
+ if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ error = ENETUNREACH;
+ goto bad;
+ }
+ /*
+ * If source address not specified yet, use address
+ * of outgoing interface.
+ */
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ register struct in_ifaddr *ia;
+
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp) {
+ ip->ip_src = IA_SIN(ia)->sin_addr;
+ break;
+ }
+ }
+
+ IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
+ if (inm != NULL &&
+ (imo == NULL || imo->imo_multicast_loop)) {
+ /*
+ * If we belong to the destination multicast group
+ * on the outgoing interface, and the caller did not
+ * forbid loopback, loop back a copy.
+ */
+ ip_mloopback(ifp, m, dst);
+ }
+#ifdef MROUTING
+ else if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
+ /*
+ * If we are acting as a multicast router, perform
+ * multicast forwarding as if the packet had just
+ * arrived on the interface to which we are about
+ * to send. The multicast forwarding function
+ * recursively calls this function, using the
+ * IP_FORWARDING flag to prevent infinite recursion.
+ *
+ * Multicasts that are looped back by ip_mloopback(),
+ * above, will be forwarded by the ip_input() routine,
+ * if necessary.
+ */
+ if (ip_mforward(ip, ifp, m) != 0) {
+ m_freem(m);
+ goto done;
+ }
+ }
+#endif
+ /*
+ * Multicasts with a time-to-live of zero may be looped-
+ * back, above, but must not be transmitted on a network.
+ * Also, multicasts addressed to the loopback interface
+ * are not sent -- the above call to ip_mloopback() will
+ * loop back a copy if this host actually belongs to the
+ * destination group on the loopback interface.
+ */
+ if (ip->ip_ttl == 0 || ifp == &loif) {
+ m_freem(m);
+ goto done;
+ }
+
+ goto sendit;
+ }
+#endif
#ifndef notdef
/*
* If source address not specified yet, use address
@@ -192,7 +291,9 @@ ip_output(m0, opt, ro, flags)
}
m->m_flags |= M_BCAST;
}
-
+#ifdef MULTICAST
+sendit:
+#endif
/*
* If small enough for interface, can just send directly.
*/
@@ -413,7 +514,24 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_RECVRETOPTS:
case IP_RECVDSTADDR:
if (m->m_len != sizeof(int))
+#if defined(MULTICAST) && defined(OLD_VAT_COMPAT)
+ {
+ optname += IP_RETOPTS-IP_OPTIONS;
+ switch(optname) {
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_LOOP:
+ if (m->m_len == sizeof(char))
+ goto multicast_setopt;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ if (m->m_len == sizeof(struct ip_mreq))
+ goto multicast_setopt;
+ }
+ error = EINVAL;
+ }
+#else
error = EINVAL;
+#endif
else {
optval = *mtod(m, int *);
switch (optname) {
@@ -446,7 +564,25 @@ ip_ctloutput(op, so, level, optname, mp)
}
break;
#undef OPTSET
-
+#ifdef MULTICAST
+#ifdef OLD_VAT_COMPAT
+ case IP_HDRINCL:
+ if (m->m_len != sizeof(struct in_addr)) {
+ error = EINVAL;
+ break;
+ }
+ optname = IP_MULTICAST_IF;
+ /* FALLTHRU */
+multicast_setopt:
+#endif
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_LOOP:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ error = ip_setmoptions(optname, &inp->inp_moptions, m);
+ break;
+#endif
default:
error = EINVAL;
break;
@@ -501,7 +637,15 @@ ip_ctloutput(op, so, level, optname, mp)
}
*mtod(m, int *) = optval;
break;
-
+#ifdef MULTICAST
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_LOOP:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ error = ip_getmoptions(optname, inp->inp_moptions, mp);
+ break;
+#endif
default:
error = EINVAL;
break;
@@ -617,3 +761,339 @@ bad:
(void)m_free(m);
return (EINVAL);
}
+
+#ifdef MULTICAST
+/*
+ * Set the IP multicast options in response to user setsockopt().
+ */
+int
+ip_setmoptions(optname, imop, m)
+ int optname;
+ struct ip_moptions **imop;
+ struct mbuf *m;
+{
+ register int error = 0;
+ u_char loop;
+ register int i;
+ struct in_addr addr;
+ register struct ip_mreq *mreq;
+ register struct ifnet *ifp;
+ register struct ip_moptions *imo = *imop;
+ struct route ro;
+ register struct sockaddr_in *dst;
+
+ if (imo == NULL) {
+ /*
+ * No multicast option buffer attached to the pcb;
+ * allocate one and initialize to default values.
+ */
+ imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
+ M_WAITOK);
+
+ if (imo == NULL)
+ return (ENOBUFS);
+ *imop = imo;
+ imo->imo_multicast_ifp = NULL;
+ imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
+ imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
+ imo->imo_num_memberships = 0;
+ }
+
+ switch (optname) {
+
+ case IP_MULTICAST_IF:
+ /*
+ * Select the interface for outgoing multicast packets.
+ */
+ if (m == NULL || m->m_len != sizeof(struct in_addr)) {
+ error = EINVAL;
+ break;
+ }
+ addr = *(mtod(m, struct in_addr *));
+ /*
+ * INADDR_ANY is used to remove a previous selection.
+ * When no interface is selected, a default one is
+ * chosen every time a multicast packet is sent.
+ */
+ if (addr.s_addr == INADDR_ANY) {
+ imo->imo_multicast_ifp = NULL;
+ break;
+ }
+ /*
+ * The selected interface is identified by its local
+ * IP address. Find the interface and confirm that
+ * it supports multicasting.
+ */
+ INADDR_TO_IFP(addr, ifp);
+ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ imo->imo_multicast_ifp = ifp;
+ break;
+
+ case IP_MULTICAST_TTL:
+ /*
+ * Set the IP time-to-live for outgoing multicast packets.
+ */
+ if (m == NULL || m->m_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ imo->imo_multicast_ttl = *(mtod(m, u_char *));
+ break;
+
+ case IP_MULTICAST_LOOP:
+ /*
+ * Set the loopback flag for outgoing multicast packets.
+ * Must be zero or one.
+ */
+ if (m == NULL || m->m_len != 1 ||
+ (loop = *(mtod(m, u_char *))) > 1) {
+ error = EINVAL;
+ break;
+ }
+ imo->imo_multicast_loop = loop;
+ break;
+
+ case IP_ADD_MEMBERSHIP:
+ /*
+ * Add a multicast group membership.
+ * Group must be a valid IP multicast address.
+ */
+ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+ error = EINVAL;
+ break;
+ }
+ mreq = mtod(m, struct ip_mreq *);
+ if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+ error = EINVAL;
+ break;
+ }
+ /*
+ * If no interface address was provided, use the interface of
+ * the route to the given multicast address.
+ */
+ if (mreq->imr_interface.s_addr == INADDR_ANY) {
+ ro.ro_rt = NULL;
+ dst = (struct sockaddr_in *)&ro.ro_dst;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_family = AF_INET;
+ dst->sin_addr = mreq->imr_multiaddr;
+ rtalloc(&ro);
+ if (ro.ro_rt == NULL) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ ifp = ro.ro_rt->rt_ifp;
+ rtfree(ro.ro_rt);
+ }
+ else {
+ INADDR_TO_IFP(mreq->imr_interface, ifp);
+ }
+ /*
+ * See if we found an interface, and confirm that it
+ * supports multicast.
+ */
+ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ /*
+ * See if the membership already exists or if all the
+ * membership slots are full.
+ */
+ for (i = 0; i < imo->imo_num_memberships; ++i) {
+ if (imo->imo_membership[i]->inm_ifp == ifp &&
+ imo->imo_membership[i]->inm_addr.s_addr
+ == mreq->imr_multiaddr.s_addr)
+ break;
+ }
+ if (i < imo->imo_num_memberships) {
+ error = EADDRINUSE;
+ break;
+ }
+ if (i == IP_MAX_MEMBERSHIPS) {
+ error = ETOOMANYREFS;
+ break;
+ }
+ /*
+ * Everything looks good; add a new record to the multicast
+ * address list for the given interface.
+ */
+ if ((imo->imo_membership[i] =
+ in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
+ error = ENOBUFS;
+ break;
+ }
+ ++imo->imo_num_memberships;
+ break;
+
+ case IP_DROP_MEMBERSHIP:
+ /*
+ * Drop a multicast group membership.
+ * Group must be a valid IP multicast address.
+ */
+ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+ error = EINVAL;
+ break;
+ }
+ mreq = mtod(m, struct ip_mreq *);
+ if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+ error = EINVAL;
+ break;
+ }
+ /*
+ * If an interface address was specified, get a pointer
+ * to its ifnet structure.
+ */
+ if (mreq->imr_interface.s_addr == INADDR_ANY)
+ ifp = NULL;
+ else {
+ INADDR_TO_IFP(mreq->imr_interface, ifp);
+ if (ifp == NULL) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ }
+ /*
+ * Find the membership in the membership array.
+ */
+ for (i = 0; i < imo->imo_num_memberships; ++i) {
+ if ((ifp == NULL ||
+ imo->imo_membership[i]->inm_ifp == ifp) &&
+ imo->imo_membership[i]->inm_addr.s_addr ==
+ mreq->imr_multiaddr.s_addr)
+ break;
+ }
+ if (i == imo->imo_num_memberships) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ /*
+ * Give up the multicast address record to which the
+ * membership points.
+ */
+ in_delmulti(imo->imo_membership[i]);
+ /*
+ * Remove the gap in the membership array.
+ */
+ for (++i; i < imo->imo_num_memberships; ++i)
+ imo->imo_membership[i-1] = imo->imo_membership[i];
+ --imo->imo_num_memberships;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ /*
+ * If all options have default values, no need to keep the mbuf.
+ */
+ if (imo->imo_multicast_ifp == NULL &&
+ imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
+ imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
+ imo->imo_num_memberships == 0) {
+ free(*imop, M_IPMOPTS);
+ *imop = NULL;
+ }
+
+ return (error);
+}
+
+/*
+ * Return the IP multicast options in response to user getsockopt().
+ */
+int
+ip_getmoptions(optname, imo, mp)
+ int optname;
+ register struct ip_moptions *imo;
+ register struct mbuf **mp;
+{
+ u_char *ttl;
+ u_char *loop;
+ struct in_addr *addr;
+ struct in_ifaddr *ia;
+
+ *mp = m_get(M_WAIT, MT_SOOPTS);
+
+ switch (optname) {
+
+ case IP_MULTICAST_IF:
+ addr = mtod(*mp, struct in_addr *);
+ (*mp)->m_len = sizeof(struct in_addr);
+ if (imo == NULL || imo->imo_multicast_ifp == NULL)
+ addr->s_addr = INADDR_ANY;
+ else {
+ IFP_TO_IA(imo->imo_multicast_ifp, ia);
+ addr->s_addr = (ia == NULL) ? INADDR_ANY
+ : IA_SIN(ia)->sin_addr.s_addr;
+ }
+ return (0);
+
+ case IP_MULTICAST_TTL:
+ ttl = mtod(*mp, u_char *);
+ (*mp)->m_len = 1;
+ *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
+ : imo->imo_multicast_ttl;
+ return (0);
+
+ case IP_MULTICAST_LOOP:
+ loop = mtod(*mp, u_char *);
+ (*mp)->m_len = 1;
+ *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
+ : imo->imo_multicast_loop;
+ return (0);
+
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+/*
+ * Discard the IP multicast options.
+ */
+void
+ip_freemoptions(imo)
+ register struct ip_moptions *imo;
+{
+ register int i;
+
+ if (imo != NULL) {
+ for (i = 0; i < imo->imo_num_memberships; ++i)
+ in_delmulti(imo->imo_membership[i]);
+ free(imo, M_IPMOPTS);
+ }
+}
+
+/*
+ * Routine called from ip_output() to loop back a copy of an IP multicast
+ * packet to the input queue of a specified interface. Note that this
+ * calls the output routine of the loopback "driver", but with an interface
+ * pointer that might NOT be &loif -- easier than replicating that code here.
+ */
+void
+ip_mloopback(ifp, m, dst)
+ struct ifnet *ifp;
+ register struct mbuf *m;
+ register struct sockaddr_in *dst;
+{
+ register struct ip *ip;
+ struct mbuf *copym;
+
+ copym = m_copy(m, 0, M_COPYALL);
+ if (copym != NULL) {
+ /*
+ * We don't bother to fragment if the IP length is greater
+ * than the interface's MTU. Can this possibly matter?
+ */
+ ip = mtod(copym, struct ip *);
+ ip->ip_len = htons((u_short)ip->ip_len);
+ ip->ip_off = htons((u_short)ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
+ (void) looutput(ifp, copym, (struct sockaddr *)dst, 0);
+ }
+}
+#endif
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 47d76fe01b5a..9452d8c9a5d5 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1993 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ip_var.h 7.7 (Berkeley) 6/28/90
- * $Id: ip_var.h,v 1.3 1993/11/07 17:48:00 wollman Exp $
+ * $Id: ip_var.h,v 1.4 1994/05/17 22:31:12 jkh Exp $
*/
#ifndef _NETINET_IP_VAR_H_
@@ -103,6 +103,18 @@ struct ipoption {
char ipopt_list[MAX_IPOPTLEN]; /* options proper */
};
+/*
+ * Structure attached to inpcb.ip_moptions and
+ * passed to ip_output when IP multicast options are in use.
+ */
+struct ip_moptions {
+ struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */
+ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */
+ u_char imo_multicast_loop; /* 1 => hear sends if a member */
+ u_short imo_num_memberships; /* no. memberships this socket */
+ struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS];
+};
+
struct ipstat {
long ips_total; /* total packets received */
long ips_badsum; /* checksum bad */
@@ -129,6 +141,7 @@ struct ipstat {
#ifdef KERNEL
/* flags passed to ip_output as last parameter */
#define IP_FORWARDING 0x1 /* most of ip header exists */
+#define IP_MULTICASTOPTS 0x2 /* multicast opts present */
#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */
#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 1618339176ae..a98cc1a71efe 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * 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
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)raw_ip.c 7.8 (Berkeley) 7/25/90
- * $Id: raw_ip.c,v 1.4 1993/12/19 00:52:46 wollman Exp $
+ * $Id: raw_ip.c,v 1.5 1994/05/17 22:31:13 jkh Exp $
*/
#include "param.h"
@@ -118,7 +118,11 @@ rip_output(m, so)
return (ip_output(m,
(rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
&rp->rinp_route,
- (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
+#ifdef MULTICAST
+ | IP_MULTICASTOPTS, rp->rinp_rcb.rcb_moptions
+#endif
+ ));
}
/*
@@ -154,10 +158,27 @@ rip_ctloutput(op, so, level, optname, m)
else
rp->rinp_flags &= ~RINPF_HDRINCL;
break;
-
+#ifdef MULTICAST
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_LOOP:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ error = ip_setmoptions(optname,
+ &rp->rinp_rcb.rcb_moptions, *m);
+ break;
+ default:
+#ifdef MROUTING
+ error = ip_mrouter_cmd(optname, so, *m);
+#else
+ error = EINVAL;
+#endif
+ break;
+#else
default:
error = EINVAL;
break;
+#endif
}
break;
@@ -178,7 +199,16 @@ rip_ctloutput(op, so, level, optname, m)
(*m)->m_len = sizeof (int);
*mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
break;
-
+#ifdef MULTICAST
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_LOOP:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ error = ip_getmoptions(optname,
+ rp->rinp_rcb.rcb_moptions, m);
+ break;
+#endif
default:
error = EINVAL;
m_freem(*m);
@@ -201,7 +231,9 @@ rip_usrreq(so, req, m, nam, control)
{
register int error = 0;
register struct raw_inpcb *rp = sotorawinpcb(so);
-
+#if defined(MULTICAST) && defined(MROUTING)
+ extern struct socket *ip_mrouter;
+#endif
switch (req) {
case PRU_ATTACH:
@@ -217,8 +249,16 @@ rip_usrreq(so, req, m, nam, control)
case PRU_DETACH:
if (rp == 0)
panic("rip_detach");
+#if defined(MULTICAST) && defined(MROUTING)
+ if (so == ip_mrouter)
+ ip_mrouter_done();
+#endif
if (rp->rinp_options)
m_freem(rp->rinp_options);
+#ifdef MULTICAST
+ if (rp->rinp_rcb.rcb_moptions)
+ ip_freemoptions(rp->rinp_rcb.rcb_moptions);
+#endif
if (rp->rinp_route.ro_rt)
RTFREE(rp->rinp_route.ro_rt);
if (rp->rinp_rcb.rcb_laddr)
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index b6f377690856..e258f5f6d022 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)tcp_usrreq.c 7.15 (Berkeley) 6/28/90
- * $Id: tcp_usrreq.c,v 1.5 1994/01/24 05:12:36 davidg Exp $
+ * $Id: tcp_usrreq.c,v 1.6 1994/05/22 23:18:40 ache Exp $
*/
#include "param.h"
@@ -351,12 +351,15 @@ tcp_ctloutput(op, so, level, optname, mp)
{
int error = 0;
struct inpcb *inp = sotoinpcb(so);
- register struct tcpcb *tp = intotcpcb(inp);
+ register struct tcpcb *tp;
register struct mbuf *m;
if (level != IPPROTO_TCP)
return (ip_ctloutput(op, so, level, optname, mp));
+ if (!inp || !(tp = intotcpcb(inp)))
+ return (EINVAL);
+
switch (op) {
case PRCO_SETOPT:
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 44e244c31c95..12b5b3ece29e 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ * 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
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91
- * $Id: udp_usrreq.c,v 1.7 1994/02/07 19:53:25 ache Exp $
+ * $Id: udp_usrreq.c,v 1.8 1994/05/17 22:31:14 jkh Exp $
*/
#include "param.h"
@@ -145,6 +145,93 @@ udp_input(m, iphlen)
return;
}
}
+#ifdef MULTICAST
+ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
+ in_broadcast(ip->ip_dst)) {
+ struct socket *last;
+ /*
+ * Deliver a multicast or broadcast datagram to *all* sockets
+ * for which the local and remote addresses and ports match
+ * those of the incoming datagram. This allows more than
+ * one process to receive multi/broadcasts on the same port.
+ * (This really ought to be done for unicast datagrams as
+ * well, but that would cause problems with existing
+ * applications that open both address-specific sockets and
+ * a wildcard socket listening to the same port -- they would
+ * end up receiving duplicates of every unicast datagram.
+ * Those applications open the multiple sockets to overcome an
+ * inadequacy of the UDP socket interface, but for backwards
+ * compatibility we avoid the problem here rather than
+ * fixing the interface. Maybe 4.4BSD will remedy this?)
+ */
+
+ /*
+ * Construct sockaddr format source address.
+ */
+ udp_in.sin_port = uh->uh_sport;
+ udp_in.sin_addr = ip->ip_src;
+ m->m_len -= sizeof (struct udpiphdr);
+ m->m_data += sizeof (struct udpiphdr);
+ /*
+ * Locate pcb(s) for datagram.
+ * (Algorithm copied from raw_intr().)
+ */
+ last = NULL;
+ for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
+ if (inp->inp_lport != uh->uh_dport)
+ continue;
+ if (inp->inp_laddr.s_addr != INADDR_ANY) {
+ if (inp->inp_laddr.s_addr !=
+ ip->ip_dst.s_addr)
+ continue;
+ }
+ if (inp->inp_faddr.s_addr != INADDR_ANY) {
+ if (inp->inp_faddr.s_addr !=
+ ip->ip_src.s_addr ||
+ inp->inp_fport != uh->uh_sport)
+ continue;
+ }
+
+ if (last != NULL) {
+ struct mbuf *n;
+
+ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+ if (sbappendaddr(&last->so_rcv,
+ (struct sockaddr *)&udp_in,
+ n, (struct mbuf *)0) == 0)
+ m_freem(n);
+ else
+ sorwakeup(last);
+ }
+ }
+ last = inp->inp_socket;
+ /*
+ * Don't look for additional matches if this one
+ * does not have the SO_REUSEADDR socket option set.
+ * This heuristic avoids searching through all pcbs
+ * in the common case of a non-shared port. It
+ * assumes that an application will never clear
+ * the SO_REUSEADDR option after setting it.
+ */
+ if ((last->so_options & SO_REUSEADDR) == 0)
+ break;
+ }
+
+ if (last == NULL) {
+ /*
+ * No matching pcb found; discard datagram.
+ * (No need to send an ICMP Port Unreachable
+ * for a broadcast or multicast datgram.)
+ */
+ goto bad;
+ }
+ if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
+ m, (struct mbuf *)0) == 0)
+ goto bad;
+ sorwakeup(last);
+ return;
+ }
+#endif
/*
* Locate pcb for datagram.
@@ -163,10 +250,13 @@ udp_input(m, iphlen)
if (inp == 0) {
/* don't send ICMP response for broadcast packet */
udpstat.udps_noport++;
- if (m->m_flags & M_BCAST) {
+#ifndef MULTICAST
+ /* XXX why don't we do this with MULTICAST? */
+ if (m->m_flags & (M_BCAST | M_MCAST)) {
udpstat.udps_noportbcast++;
goto bad;
}
+#endif
*ip = save_ip;
ip->ip_len += iphlen;
{
@@ -355,7 +445,11 @@ udp_output(inp, m, addr, control)
((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
udpstat.udps_opackets++;
error = ip_output(m, inp->inp_options, &inp->inp_route,
- inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
+ inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)
+#ifdef MULTICAST
+ | IP_MULTICASTOPTS, inp->inp_moptions
+#endif
+ );
if (addr) {
in_pcbdisconnect(inp);
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index 3a422dc184d4..e10649d08b3d 100644
--- a/sys/nfs/nfs_bio.c
+++ b/sys/nfs/nfs_bio.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* From: @(#)nfs_bio.c 7.19 (Berkeley) 4/16/91
- * $Id: nfs_bio.c,v 1.5 1994/02/06 22:20:09 davidg Exp $
+ * $Id: nfs_bio.c,v 1.6 1994/06/12 04:05:39 davidg Exp $
*/
#include "param.h"
@@ -175,8 +175,6 @@ nfs_bioread(vp, uio, ioflag, cred)
error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
switch (vp->v_type) {
case VREG:
- if (n+on == biosize || uio->uio_offset == np->n_size)
- bp->b_flags |= B_AGE;
break;
case VLNK:
n = 0;
@@ -298,12 +296,10 @@ again:
brelse(bp);
return (error);
}
+ bp->b_proc = (struct proc *)0;
if ((n+on) == biosize) {
- bp->b_flags |= B_AGE;
- bp->b_proc = (struct proc *)0;
bawrite(bp);
} else {
- bp->b_proc = (struct proc *)0;
bdwrite(bp);
}
} while (error == 0 && uio->uio_resid > 0 && n != 0);
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c
index 6205a268448e..20f7015c1f26 100644
--- a/sys/nfs/nfs_serv.c
+++ b/sys/nfs/nfs_serv.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* From: @(#)nfs_serv.c 7.40 (Berkeley) 5/15/91
- * $Id: nfs_serv.c,v 1.5 1993/12/19 00:54:12 wollman Exp $
+ * $Id: nfs_serv.c,v 1.6 1994/06/11 23:33:53 karl Exp $
*/
/*
@@ -667,10 +667,16 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
vput(nd.ni_dvp);
VOP_ABORTOP(&nd);
vap->va_size = fxdr_unsigned(long, *(tl+3)); /* 28 Aug 92*/
-/* 08 Sep 92*/ if (vap->va_size != -1 && (error = VOP_SETATTR(vp, vap, cred, p))) {
- vput(vp);
- nfsm_reply(0);
- }
+ if (vap->va_size != -1) {
+ if (error = nfsrv_access(vp, VWRITE, cred, p)) {
+ vput(vp);
+ nfsm_reply(0);
+ }
+ if (error = VOP_SETATTR(vp, vap, cred, p)) {
+ vput(vp);
+ nfsm_reply(0);
+ }
+ }
}
bzero((caddr_t)fhp, sizeof(nfh));
fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c
index 41b386d70dfc..f3c3c880785b 100644
--- a/sys/nfs/nfs_socket.c
+++ b/sys/nfs/nfs_socket.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* From: @(#)nfs_socket.c 7.23 (Berkeley) 4/20/91
- * $Id: nfs_socket.c,v 1.4.2.1 1994/05/03 21:04:53 rgrimes Exp $
+ * $Id: nfs_socket.c,v 1.5 1994/05/03 17:49:16 davidg Exp $
*/
/*
diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c
index 14e011882160..d512bde223bf 100644
--- a/sys/nfs/nfs_subs.c
+++ b/sys/nfs/nfs_subs.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* From: @(#)nfs_subs.c 7.41 (Berkeley) 5/15/91
- * $Id: nfs_subs.c,v 1.5 1993/12/19 00:54:15 wollman Exp $
+ * $Id: nfs_subs.c,v 1.6 1994/04/14 07:50:11 davidg Exp $
*/
/*
@@ -262,6 +262,12 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos)
return (error);
}
+void nfsm_nullfree()
+{
+ /* Nothing to do here */
+}
+
+
/*
* copies a uio scatter/gather list to an mbuf chain...
*/
@@ -278,7 +284,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
int uiosiz, clflg, rem;
char *cp;
- if (siz > MLEN) /* or should it >= MCLBYTES ?? */
+ if (siz > MLEN && uiop->uio_segflg != UIO_SYSSPACE)
clflg = 1;
else
clflg = 0;
@@ -292,31 +298,43 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
if (left > siz)
left = siz;
uiosiz = left;
- while (left > 0) {
+ if (uiop->uio_segflg == UIO_SYSSPACE) {
MGET(mp, M_WAIT, MT_DATA);
- if (clflg)
- MCLGET(mp, M_WAIT);
- mp->m_len = NFSMSIZ(mp);
+ mp->m_flags |= M_EXT;
+ mp->m_data = mp->m_ext.ext_buf = uiocp;
+ mp->m_len = mp->m_ext.ext_size = uiosiz;
+ mp->m_ext.ext_free = nfsm_nullfree;
mp2->m_next = mp;
mp2 = mp;
- xfer = (left > mp->m_len) ? mp->m_len : left;
+ uiop->uio_offset += uiosiz;
+ uiop->uio_resid -= uiosiz;
+ } else {
+ while (left > 0) {
+ MGET(mp, M_WAIT, MT_DATA);
+ if (clflg)
+ MCLGET(mp, M_WAIT);
+ mp->m_len = NFSMSIZ(mp);
+ mp2->m_next = mp;
+ mp2 = mp;
+ xfer = (left > mp->m_len) ? mp->m_len : left;
#ifdef notdef
- /* Not Yet.. */
- if (uiop->uio_iov->iov_op != NULL)
- (*(uiop->uio_iov->iov_op))
- (uiocp, mtod(mp, caddr_t), xfer);
- else
+ /* Not Yet.. */
+ if (uiop->uio_iov->iov_op != NULL)
+ (*(uiop->uio_iov->iov_op))
+ (uiocp, mtod(mp, caddr_t), xfer);
+ else
+ if (uiop->uio_segflg == UIO_SYSSPACE)
+ bcopy(uiocp, mtod(mp, caddr_t), xfer);
+ else
#endif
- if (uiop->uio_segflg == UIO_SYSSPACE)
- bcopy(uiocp, mtod(mp, caddr_t), xfer);
- else
copyin(uiocp, mtod(mp, caddr_t), xfer);
- len = mp->m_len;
- mp->m_len = xfer;
- left -= xfer;
- uiocp += xfer;
- uiop->uio_offset += xfer;
- uiop->uio_resid -= xfer;
+ len = mp->m_len;
+ mp->m_len = xfer;
+ left -= xfer;
+ uiocp += xfer;
+ uiop->uio_offset += xfer;
+ uiop->uio_resid -= xfer;
+ }
}
if (uiop->uio_iov->iov_len <= siz) {
uiop->uio_iovcnt--;
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index b5548e751576..0066b77b13b6 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* From: @(#)nfs_vnops.c 7.60 (Berkeley) 5/24/91
- * $Id: nfs_vnops.c,v 1.7 1994/01/31 23:40:50 martin Exp $
+ * $Id: nfs_vnops.c,v 1.8 1994/06/14 03:41:10 davidg Exp $
*/
/*
@@ -278,9 +278,19 @@ nfs_open(vp, mode, cred, p)
register enum vtype vtyp;
vtyp = vp->v_type;
- if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
+ if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) {
+ struct nfsnode *np;
+ struct vattr vattr;
+ np = VTONFS(vp);
+ if (nfs_dogetattr(vp, &vattr, cred, 1, p) == 0) {
+ if (np->n_mtime != vattr.va_mtime.tv_sec) {
+ np->n_direofoffset = 0;
+ vinvalbuf(vp, TRUE);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ }
+ }
return (0);
- else
+ } else
return (EACCES);
}
diff --git a/sys/pcfs/pcfs_conv.c b/sys/pcfs/pcfs_conv.c
index 66fbba06216f..4fb706f0d81e 100644
--- a/sys/pcfs/pcfs_conv.c
+++ b/sys/pcfs/pcfs_conv.c
@@ -15,7 +15,7 @@
*
* October 1992
*
- * $Id: pcfs_conv.c,v 1.4 1993/12/19 00:54:27 wollman Exp $
+ * $Id: pcfs_conv.c,v 1.5 1994/04/07 00:30:35 ache Exp $
*/
/*
@@ -297,11 +297,11 @@ unix2dosfn(un, dn, unlen)
* The filenames "." and ".." are handled specially,
* since they don't follow dos filename rules.
*/
- if (un[0] == '.' && un[1] == '\0') {
+ if (un[0] == '.' && unlen == 1) {
dn[0] = '.';
return;
}
- if (un[0] == '.' && un[1] == '.' && un[2] == '\0') {
+ if (un[0] == '.' && un[1] == '.' && unlen == 2) {
dn[0] = '.';
dn[1] = '.';
return;
diff --git a/sys/pcfs/pcfs_fat.c b/sys/pcfs/pcfs_fat.c
index 3e66739e2618..dadcd6add6a7 100644
--- a/sys/pcfs/pcfs_fat.c
+++ b/sys/pcfs/pcfs_fat.c
@@ -15,7 +15,7 @@
*
* October 1992
*
- * $Id: pcfs_fat.c,v 1.3 1993/11/25 01:37:11 wollman Exp $
+ * $Id: pcfs_fat.c,v 1.4 1994/06/22 05:52:53 jkh Exp $
*/
/*
@@ -340,8 +340,14 @@ printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n",
*/
-extern inline void
-usemap_alloc (struct pcfsmount *pmp, u_long cn)
+#ifndef __GNUC__
+#define inline
+#endif
+
+static inline void
+usemap_alloc (pmp, cn)
+ struct pcfsmount *pmp;
+ u_long cn;
{
pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8);
pmp->pm_freeclustercount--;
@@ -349,8 +355,10 @@ usemap_alloc (struct pcfsmount *pmp, u_long cn)
pmp->pm_lookhere = cn + 1;
}
-extern inline void
-usemap_free (struct pcfsmount *pmp, u_long cn)
+static inline void
+usemap_free (pmp, cn)
+ struct pcfsmount *pmp;
+ u_long cn;
{
pmp->pm_freeclustercount++;
pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8));
diff --git a/sys/pcfs/pcfs_vfsops.c b/sys/pcfs/pcfs_vfsops.c
index 2fac8237dfe3..4d698e74c92d 100644
--- a/sys/pcfs/pcfs_vfsops.c
+++ b/sys/pcfs/pcfs_vfsops.c
@@ -15,7 +15,7 @@
*
* October 1992
*
- * $Id: pcfs_vfsops.c,v 1.5 1993/12/19 02:07:58 ache Exp $
+ * $Id: pcfs_vfsops.c,v 1.6 1994/05/21 01:25:30 sean Exp $
*/
#include "param.h"
@@ -367,8 +367,7 @@ mountpcfs(devvp, mp, p)
* Finish up.
*/
pmp->pm_ronly = ronly;
- if (ronly == 0)
- pmp->pm_fmod = 1;
+ pmp->pm_fmod = !ronly;
mp->mnt_data = (qaddr_t)pmp;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS;
diff --git a/sys/pcfs/pcfs_vnops.c b/sys/pcfs/pcfs_vnops.c
index b3975f6face3..15c023472f01 100644
--- a/sys/pcfs/pcfs_vnops.c
+++ b/sys/pcfs/pcfs_vnops.c
@@ -15,7 +15,7 @@
*
* October 1992
*
- * $Id: pcfs_vnops.c,v 1.4 1993/12/19 00:54:32 wollman Exp $
+ * $Id: pcfs_vnops.c,v 1.7 1994/06/12 04:05:44 davidg Exp $
*/
#include "param.h"
@@ -95,6 +95,8 @@ printf("pcfs_create(ndp %08x, vap %08x, p %08x\n", ndp, vap, p);
(union dostime *)&ndirp->deTime);
unix2dosfn((u_char *)ndp->ni_ptr, ndirp->deName, ndp->ni_namelen);
ndirp->deAttributes = (vap->va_mode & VWRITE) ? 0 : ATTR_READONLY;
+ if (vap->va_mode & VEXEC)
+ ndirp->deAttributes |= ATTR_HIDDEN;
ndirp->deStartCluster = 0;
ndirp->deFileSize = 0;
ndirent.de_pmp = pdep->de_pmp;
@@ -219,7 +221,11 @@ pcfs_getattr(vp, vap, cred, p)
cn = (cn << 16) | (dep->de_diroffset & 0xffff);
}
vap->va_fileid = cn;
- vap->va_mode = (dep->de_Attributes & ATTR_READONLY) ? 0555 : 0777;
+ vap->va_mode = (dep->de_Attributes & ATTR_READONLY) ? 0444 : 0666;
+ if ( dep->de_Attributes & ATTR_HIDDEN
+ || dep->de_Attributes & ATTR_DIRECTORY
+ )
+ vap->va_mode |= 0111;
if (dep->de_Attributes & ATTR_DIRECTORY)
vap->va_mode |= S_IFDIR;
vap->va_nlink = 1;
@@ -300,7 +306,11 @@ printf(" va_uid %x, va_gid %x, va_atime.tv_sec %x\n",
* write bit to set the readonly attribute.
*/
if (vap->va_mode != (u_short)VNOVAL) {
- /* We ignore the read and execute bits */
+ /* We ignore the read bits */
+ if (vap->va_mode & VEXEC && vp->v_type != VDIR)
+ dep->de_Attributes |= ATTR_HIDDEN;
+ else
+ dep->de_Attributes &= ~ATTR_HIDDEN;
if (vap->va_mode & VWRITE)
dep->de_Attributes &= ~ATTR_READONLY;
else
@@ -393,17 +403,6 @@ pcfs_read(vp, uio, ioflag, cred)
return error;
}
error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
-/*
- * If we have read everything from this block or
- * have read to end of file then we are done with
- * this block. Mark it to say the buffer can be reused if
- * need be.
- */
-#if 0
- if (n + on == pmp->pm_bpcluster ||
- uio->uio_offset == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
return error;
@@ -558,7 +557,6 @@ printf("pcfs_write(): diroff %d, dirclust %d, startcluster %d\n",
(void) bwrite(bp);
else
if (n + croffset == pmp->pm_bpcluster) {
- bp->b_flags |= B_AGE;
bawrite(bp);
} else
bdwrite(bp);
@@ -1450,17 +1448,6 @@ printf("pcfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
uio);
}
-/*
- * If we have read everything from this block or
- * have read to end of file then we are done with
- * this block. Mark it to say the buffer can be reused if
- * need be.
- */
-#if 0
- if (n + on == pmp->pm_bpcluster ||
- (uio->uio_offset-bias) == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
out:;
@@ -1550,7 +1537,7 @@ pcfs_bmap(vp, bn, vpp, bnp)
*vpp = dep->de_devvp;
if (bnp == NULL)
return 0;
- return pcbmap(dep, bn << (pmp->pm_cnshift - pmp->pm_bnshift), bnp, 0);
+ return pcbmap(dep, bn, bnp, 0);
}
int
diff --git a/sys/procfs/procfs_subr.c b/sys/procfs/procfs_subr.c
index 94f5e8e5e253..6639f6498c8b 100644
--- a/sys/procfs/procfs_subr.c
+++ b/sys/procfs/procfs_subr.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: procfs_subr.c,v 1.4 1994/01/14 16:25:04 davidg Exp $
+ * $Id: procfs_subr.c,v 1.5 1994/03/07 11:38:57 davidg Exp $
*/
#include "param.h"
#include "systm.h"
@@ -40,9 +40,9 @@
#include "file.h"
#include "resourcevar.h"
#include "vm/vm.h"
-#include "vm/vm_page.h"
#include "vm/vm_kern.h"
#include "vm/vm_user.h"
+#include "vm/vm_page.h"
#include "kinfo.h"
#include "kinfo_proc.h"
#include "machine/pmap.h"
@@ -53,6 +53,164 @@
#include "machine/vmparam.h"
/*
+ * Get process address map (PIOCGVMINFO)
+ */
+int
+pfs_vminfo(procp, pfsp, pmapp)
+struct proc *procp;
+struct nfsnode *pfsp;
+struct procvminfo *pmapp;
+{
+ int error = 0;
+ vm_map_t map;
+ vm_map_entry_t entry;
+ struct procvminfo prmap;
+
+ map = &procp->p_vmspace->vm_map;
+ if( procp != curproc)
+ vm_map_lock(map);
+ entry = map->header.next;
+
+ while (entry != &map->header) {
+ if (entry->is_a_map) {
+ vm_map_t submap = entry->object.share_map;
+ vm_map_entry_t subentry;
+
+ if( procp != curproc)
+ vm_map_lock(submap);
+ subentry = submap->header.next;
+ while (subentry != &submap->header) {
+ prmap.entrytype = PFS_PRMAP;
+ prmap.u.pm.vaddr = subentry->start;
+ prmap.u.pm.size = subentry->end - subentry->start;
+ prmap.u.pm.offset = subentry->offset;
+ prmap.u.pm.prot = subentry->protection;
+ error = copyout(&prmap, pmapp, sizeof(struct procvminfo));
+ if (error)
+ break;
+ pmapp++;
+ subentry = subentry->next;
+ }
+ if( procp != curproc)
+ vm_map_unlock(submap);
+ if (error)
+ break;
+ }
+
+ prmap.entrytype = PFS_PRMAP;
+ prmap.u.pm.vaddr = entry->start;
+ prmap.u.pm.size = entry->end - entry->start;
+ prmap.u.pm.offset = entry->offset;
+ prmap.u.pm.prot = entry->protection;
+ error = copyout(&prmap, pmapp, sizeof(struct procvminfo));
+ if (error)
+ break;
+ pmapp++;
+ if( !entry->is_a_map && !entry->is_sub_map) {
+ vm_object_t obj;
+ vm_offset_t off = entry->offset;
+ obj = entry->object.vm_object;
+ while( obj) {
+ vm_page_t pdata, p;
+ vm_offset_t addr, pmapent, *procpmapent;
+ struct vm_page zeropage;
+ prmap.entrytype = PFS_OBJINFO;
+ prmap.u.oi.ref_count = obj->ref_count;
+ prmap.u.oi.rss_map = obj->resident_page_count;
+ prmap.u.oi.persist = obj->can_persist;
+ prmap.u.oi.internal = obj->internal;
+ prmap.u.oi.offset = off;
+ prmap.u.oi.size = obj->size;
+ error = copyout(&prmap, pmapp, sizeof(struct procvminfo));
+ if (error)
+ break;
+ pmapp++;
+ pdata = (vm_page_t) pmapp;
+ bzero(&zeropage, sizeof zeropage);
+ for(addr=0; addr < obj->size; addr += NBPG) {
+ p = vm_page_lookup( obj, addr);
+ if( !p) {
+ p = &zeropage;
+ }
+ error = copyout( p, pdata++, sizeof( struct vm_page));
+ if( error)
+ goto errorfin;
+
+ }
+ procpmapent = (vm_offset_t *) pdata;
+
+ for(addr=0; addr < obj->size; addr += NBPG) {
+ pmapent = pmap_extract( vm_map_pmap( map), addr + entry->start);
+ error = copyout( &pmapent, procpmapent++, sizeof( vm_offset_t));
+ if( error)
+ goto errorfin;
+ }
+
+ pmapp = (struct procvminfo *) procpmapent;
+
+ if( obj->shadow) {
+ off += obj->shadow_offset;
+ obj = obj->shadow;
+ } else {
+ break;
+ }
+ }
+ }
+
+ entry = entry->next;
+ }
+errorfin:
+
+ if( procp != curproc)
+ vm_map_unlock(map);
+ if( !error) {
+ bzero(&prmap, sizeof prmap);
+ prmap.entrytype = PFS_END;
+ error = copyout(&prmap, pmapp, sizeof(struct procvminfo));
+ }
+
+ return error;
+}
+
+/*
+ * Count number of VM entries of process (PIOCGNVMINFO)
+ */
+int
+pfs_vminfo_nentries(procp, pfsp)
+struct proc *procp;
+struct nfsnode *pfsp;
+{
+ int count = 0;
+ vm_map_t map;
+ vm_map_entry_t entry;
+
+ map = &procp->p_vmspace->vm_map;
+ if( procp != curproc)
+ vm_map_lock(map);
+ entry = map->header.next;
+
+ while (entry != &map->header) {
+ if (entry->is_a_map)
+ count += entry->object.share_map->nentries;
+ else if( !entry->is_a_map && !entry->is_sub_map) {
+ vm_object_t obj;
+ obj = entry->object.vm_object;
+ while( obj) {
+ count += 2*sizeof( struct procvminfo) +
+ (obj->size / NBPG) * (sizeof (struct vm_page) + sizeof(vm_offset_t));
+ obj = obj->shadow;
+ }
+ } else {
+ count += sizeof( struct procvminfo);
+ }
+ entry = entry->next;
+ }
+
+ if( procp != curproc)
+ vm_map_unlock(map);
+ return count;
+}
+/*
* Get process address map (PIOCGMAP)
*/
int
@@ -67,7 +225,7 @@ struct procmap *pmapp;
struct procmap prmap;
map = &procp->p_vmspace->vm_map;
- vm_map_lock(map);
+ if( procp != curproc) vm_map_lock(map);
entry = map->header.next;
while (entry != &map->header) {
@@ -75,7 +233,7 @@ struct procmap *pmapp;
vm_map_t submap = entry->object.share_map;
vm_map_entry_t subentry;
- vm_map_lock(submap);
+ if( procp != curproc) vm_map_lock(submap);
subentry = submap->header.next;
while (subentry != &submap->header) {
prmap.vaddr = subentry->start;
@@ -88,7 +246,7 @@ struct procmap *pmapp;
pmapp++;
subentry = subentry->next;
}
- vm_map_unlock(submap);
+ if( procp != curproc) vm_map_unlock(submap);
if (error)
break;
}
@@ -103,7 +261,7 @@ struct procmap *pmapp;
entry = entry->next;
}
- vm_map_unlock(map);
+ if( procp != curproc) vm_map_unlock(map);
return error;
}
@@ -120,7 +278,7 @@ struct nfsnode *pfsp;
vm_map_entry_t entry;
map = &procp->p_vmspace->vm_map;
- vm_map_lock(map);
+ if( procp != curproc) vm_map_lock(map);
entry = map->header.next;
while (entry != &map->header) {
@@ -131,7 +289,7 @@ struct nfsnode *pfsp;
entry = entry->next;
}
- vm_map_unlock(map);
+ if( procp != curproc) vm_map_unlock(map);
return count;
}
diff --git a/sys/procfs/procfs_vnops.c b/sys/procfs/procfs_vnops.c
index 90d524cb474f..8c93a1481c85 100644
--- a/sys/procfs/procfs_vnops.c
+++ b/sys/procfs/procfs_vnops.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: procfs_vnops.c,v 1.6 1994/01/31 04:19:20 davidg Exp $
+ * $Id: procfs_vnops.c,v 1.7 1994/03/07 11:38:59 davidg Exp $
*/
/*
@@ -46,6 +46,7 @@
#include "namei.h"
#include "resourcevar.h"
#include "vm/vm.h"
+#include "vm/vm_page.h"
#include "kinfo.h"
#include "kinfo_proc.h"
@@ -213,6 +214,13 @@ pfs_ioctl(vp, com, data, fflag, cred, p)
error = pfs_vmmap(procp, pfsp, *(struct procmap *)data);
break;
+ case PIOCGNVMINFO:
+ *(int *)data = pfs_vminfo_nentries(procp, pfsp);
+ break;
+
+ case PIOCGVMINFO:
+ error = pfs_vminfo(procp, pfsp, *(struct procvminfo *)data);
+ break;
default:
error = EIO;
break;
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c
index e2c174e84b1a..31c0f48d6fc1 100644
--- a/sys/scsi/cd.c
+++ b/sys/scsi/cd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: cd.c,v 1.16 1994/02/05 09:08:46 swallace Exp $
+ * $Id: cd.c,v 1.18 1994/04/20 07:06:51 davidg Exp $
*/
#define SPLCD splbio
@@ -415,11 +415,22 @@ cdstrategy(bp)
if (bounds_check_with_label(bp, &cd->disklabel, 1) <= 0)
goto done;
/* otherwise, process transfer request */
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
}
opri = SPLCD();
dp = &cd->buf_queue;
/*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (cd->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
+ /*
* Place it in the queue of disk activities for this disk
*/
disksort(dp, bp);
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 53bf097d63bf..fbd02cab57b3 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -8,7 +8,7 @@
* file.
*
* Written by Julian Elischer (julian@dialix.oz.au)
- * $Id: scsi_base.c,v 1.6 1994/02/07 02:15:01 rgrimes Exp $
+ * $Id: scsi_base.c,v 1.8 1994/05/19 22:21:05 jkh Exp $
*/
#define SPLSD splbio
@@ -293,7 +293,7 @@ scsi_start_unit(sc_link, flags)
0,
0,
2,
- 6000,
+ 10000,
NULL,
flags));
}
@@ -321,7 +321,7 @@ scsi_stop_unit(sc_link, eject, flags)
0,
0,
2,
- 6000,
+ 10000,
NULL,
flags));
}
@@ -455,7 +455,11 @@ scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
retval = EFAULT;
goto bad;
}
- xs->data = malloc(datalen, M_TEMP, M_WAITOK);
+#ifdef NOBOUNCE
+ xs->data = malloc(datalen, M_TEMP, M_WAITOK);
+#else
+ xs->data = (caddr_t) vm_bounce_kva_alloc( (datalen + PAGE_SIZE - 1)/PAGE_SIZE);
+#endif
/* I think waiting is ok *//*XXX */
switch ((int)(flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) {
case 0:
@@ -538,7 +542,11 @@ retry:
bcopy(xs->data, data_addr, datalen);
break;
}
+#ifdef NOBOUNCE
free(xs->data, M_TEMP);
+#else
+ vm_bounce_kva_alloc_free(xs->data, (datalen + PAGE_SIZE - 1)/PAGE_SIZE, 0);
+#endif
}
/*
* we have finished with the xfer stuct, free it and
diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c
index 08d8a3ab5db3..a52b3a5eebd6 100644
--- a/sys/scsi/scsi_ioctl.c
+++ b/sys/scsi/scsi_ioctl.c
@@ -199,7 +199,7 @@ void scsistrategy(struct buf *bp)
s = splbio();
while(!(bp->b_flags & B_DONE))
{
- sleep(bp,PRIBIO);
+ tsleep((caddr_t)bp, PRIBIO, "scsistrat", 0);
}
splx(s);
SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n"));
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index ed5a12e9887e..1c3de17b71d8 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsiconf.h,v 1.8 1993/12/19 00:54:55 wollman Exp $
+ * $Id: scsiconf.h,v 1.9 1994/03/23 09:15:55 davidg Exp $
*/
#ifndef SCSI_SCSICONF_H
#define SCSI_SCSICONF_H 1
@@ -134,6 +134,7 @@ struct scsi_link
#define SDEV_MEDIA_LOADED 0x01 /* device figures are still valid */
#define SDEV_WAITING 0x02 /* a process is waiting for this */
#define SDEV_OPEN 0x04 /* at least 1 open session */
+#define SDEV_BOUNCE 0x08 /* unit requires DMA bounce buffer */
#define SDEV_DBX 0xF0 /* debuging flags (scsi_debug.h) */
/*
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 20d10e376f3e..37eab6f09e28 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
*
- * $Id: sd.c,v 1.18.2.2 1994/03/16 04:03:48 rgrimes Exp $
+ * $Id: sd.c,v 1.27 1994/06/22 05:52:59 jkh Exp $
*/
#define SPLSD splbio
@@ -415,14 +415,25 @@ sdstrategy(bp)
if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0)
goto done;
/* otherwise, process transfer request */
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
}
opri = SPLSD();
dp = &sd->buf_queue;
+ /*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (sd->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
/*
* Place it in the queue of disk activities for this disk
*/
- disksort(dp, bp);
+ cldisksort(dp, bp, 64*1024);
/*
* Tell the device to get going on the transfer if it's
@@ -883,10 +894,13 @@ sd_get_parms(unit, flags)
}
else {
/* set it to something reasonable */
- sectors = 32;
disk_parms->heads = 64;
disk_parms->cyls = sectors / (64 * 32);
+ sectors = 32;
}
+ /* keep secsiz sane too - we may divide by it later */
+ if(disk_parms->secsiz == 0)
+ disk_parms->secsiz = SECSIZE;
disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
}
sd->sc_link->flags |= SDEV_MEDIA_LOADED;
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
index 2bc6e494e013..4a6674718bf3 100644
--- a/sys/scsi/st.c
+++ b/sys/scsi/st.c
@@ -21,13 +21,13 @@
* 16 Feb 93 Julian Elischer ADDED for SCSI system
* 1.15 is the last version to support MACH and OSF/1
*/
-/* $Revision: 1.15 $ */
+/* $Revision: 1.17 $ */
/*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
* major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
*
- * $Id: st.c,v 1.15 1994/01/29 10:30:41 rgrimes Exp $
+ * $Id: st.c,v 1.17 1994/06/22 05:53:02 jkh Exp $
*/
/*
@@ -307,6 +307,7 @@ stattach(sc_link)
* the drive. We cannot use interrupts yet, so the
* request must specify this.
*/
+ st_rd_blk_lim(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
printf("st%d: drive offline\n", unit);
} else {
@@ -315,7 +316,7 @@ stattach(sc_link)
if (st->media_blksiz) {
printf("%d-byte", st->media_blksiz);
} else {
- printf("variable");
+ printf("variable(%d->%d)",st->blkmin,st->blkmax);
}
printf(" blocks, write-%s\n",
(st->flags & ST_READONLY) ? "protected" : "enabled");
@@ -324,6 +325,13 @@ stattach(sc_link)
}
}
/*
+ * Forget if we've loaded the media,
+ * because sometimes things are unstable at boot time.
+ * We'll get it all again at the first open.
+ */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+
+ /*
* Set up the buf queue for this device
*/
st->buf_queue = 0;
@@ -911,6 +919,14 @@ ststrategy(bp)
stminphys(bp);
opri = splbio();
+ /*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (st->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
/*
* Place it in the queue of activities for this tape
* at the end (a bit silly because we only have on user..
diff --git a/sys/sys/acct.h b/sys/sys/acct.h
index a152907c8840..46ef5c3548b8 100644
--- a/sys/sys/acct.h
+++ b/sys/sys/acct.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)acct.h 7.3 (Berkeley) 2/15/91
- * $Id: acct.h,v 1.3.2.1 1994/05/04 07:57:00 rgrimes Exp $
+ * $Id: acct.h,v 1.4 1994/05/04 08:30:10 rgrimes Exp $
*/
#ifndef _SYS_ACCT_H_
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index ab5685893f3f..502d20fa2a61 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)buf.h 7.11 (Berkeley) 5/9/90
- * $Id: buf.h,v 1.7 1993/12/22 12:51:48 davidg Exp $
+ * $Id: buf.h,v 1.10 1994/04/20 07:07:01 davidg Exp $
*/
#ifndef _SYS_BUF_H_
@@ -79,6 +79,7 @@ struct buf
struct buf *b_forw, *b_back; /* hash chain (2 way street) */
struct buf *av_forw, *av_back; /* position on free list if not BUSY */
struct buf *b_blockf, **b_blockb;/* associated vnode */
+ struct buf *b_clusterf, *b_clusterl;/* cluster list */
#define b_actf av_forw /* alternate names for driver queue */
#define b_actl av_back /* head - isn't history wonderful */
long b_bcount; /* transfer count */
@@ -96,6 +97,7 @@ struct buf
daddr_t *b_daddr; /* indirect block */
} b_un;
daddr_t b_lblkno; /* logical block number */
+ daddr_t b_pblkno; /* physical block number */
daddr_t b_blkno; /* block # on device */
long b_resid; /* words not transferred after error */
#define b_errcnt b_resid /* while i/o in progress: # retries */
@@ -107,6 +109,7 @@ struct buf
struct ucred *b_wcred; /* ref to write credendtials */
int b_dirtyoff; /* offset in buffer of dirty region */
int b_dirtyend; /* offset of end of dirty region */
+ caddr_t b_savekva; /* saved kva for transfer while bouncing */
caddr_t b_saveaddr; /* original b_addr for PHYSIO */
void * b_driver1; /* for private use by the driver */
void * b_driver2; /* for private use by the driver */
@@ -186,7 +189,7 @@ extern int physio(void (*)(struct buf *), int, struct buf *, int, int,
#define B_VMPAGE 0x000800 /* buffer from virtual memory */
#define B_MALLOC 0x001000 /* buffer from malloc space */
#define B_DIRTY 0x002000 /* dirty page to be pushed out async */
-#define B_PGIN 0x004000 /* pagein op, so swap() can count it */
+#define B_CLUSTER 0x004000 /* pagein op, so swap() can count it */
#define B_CACHE 0x008000 /* did bread find us in the cache ? */
#define B_INVAL 0x010000 /* does not contain valid info */
#define B_LOCKED 0x020000 /* locked in core (not reusable) */
@@ -200,6 +203,7 @@ extern int physio(void (*)(struct buf *), int, struct buf *, int, int,
#define B_DRIVER2 0x2000000 /* bits for the driver to use */
#define B_DRIVER4 0x3000000 /* bits for the driver to use */
#define B_DRIVER8 0x4000000 /* bits for the driver to use */
+#define B_BOUNCE 0x8000000 /* bounce buffer flag */
/*
* Insq/Remq for the buffer hash lists.
diff --git a/sys/sys/callout.h b/sys/sys/callout.h
index d23e152c0f76..cdc1b8e94586 100644
--- a/sys/sys/callout.h
+++ b/sys/sys/callout.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)callout.h 7.2 (Berkeley) 2/15/91
- * $Id: callout.h,v 1.4.2.1 1994/05/04 07:57:02 rgrimes Exp $
+ * $Id: callout.h,v 1.5 1994/05/04 08:30:18 rgrimes Exp $
*/
#ifndef _SYS_CALLOUT_H_
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 0dcfe9796ad5..7280962373ca 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)conf.h 7.9 (Berkeley) 5/5/91
- * $Id: conf.h,v 1.4.2.1 1994/05/04 07:57:05 rgrimes Exp $
+ * $Id: conf.h,v 1.6 1994/05/04 08:30:22 rgrimes Exp $
*/
#ifndef _SYS_CONF_H_
@@ -88,7 +88,7 @@ struct cdevsw {
d_ioctl_t *d_ioctl;
d_stop_t *d_stop;
d_reset_t *d_reset;
- struct tty *d_ttys;
+ struct tty **d_ttys;
d_select_t *d_select;
d_mmap_t *d_mmap;
d_strategy_t *d_strategy;
diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h
index 32da62f94e28..0db4d3ffb79f 100644
--- a/sys/sys/disklabel.h
+++ b/sys/sys/disklabel.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)disklabel.h 7.19 (Berkeley) 5/7/91
- * $Id: disklabel.h,v 1.6 1993/12/19 00:55:13 wollman Exp $
+ * $Id: disklabel.h,v 1.7 1994/04/05 03:23:38 davidg Exp $
*/
#ifndef _SYS_DISKLABEL_H_
@@ -355,6 +355,7 @@ char *readdisklabel(int, d_strategy_t *, struct disklabel *,
struct dos_partition *, struct dkbad *, struct buf **);
void disksort(struct buf *, struct buf *);
+void cldisksort(struct buf *, struct buf *, vm_offset_t);
int writedisklabel(int, d_strategy_t *, struct disklabel *,
struct dos_partition *);
diff --git a/sys/sys/dkstat.h b/sys/sys/dkstat.h
index bbaffb27332d..2e374e584d8b 100644
--- a/sys/sys/dkstat.h
+++ b/sys/sys/dkstat.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)dkstat.h 7.5 (Berkeley) 2/15/91
- * $Id: dkstat.h,v 1.3.2.1 1994/05/04 07:57:07 rgrimes Exp $
+ * $Id: dkstat.h,v 1.4 1994/05/04 08:30:25 rgrimes Exp $
*/
#ifndef _SYS_DKSTAT_H_
diff --git a/sys/sys/errno.h b/sys/sys/errno.h
index fe26b1b732bd..1842041c86d2 100644
--- a/sys/sys/errno.h
+++ b/sys/sys/errno.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)errno.h 7.13 (Berkeley) 2/19/91
- * $Id: errno.h,v 1.3.2.1 1994/05/04 07:57:09 rgrimes Exp $
+ * $Id: errno.h,v 1.4 1994/05/04 08:30:30 rgrimes Exp $
*/
#ifndef _SYS_ERRNO_H_
diff --git a/sys/sys/exec.h b/sys/sys/exec.h
index 783bea504e2a..e3e94005b7de 100644
--- a/sys/sys/exec.h
+++ b/sys/sys/exec.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)exec.h 7.5 (Berkeley) 2/15/91
- * $Id: exec.h,v 1.4.2.1 1994/05/04 07:57:10 rgrimes Exp $
+ * $Id: exec.h,v 1.6 1994/05/04 08:30:34 rgrimes Exp $
*/
#ifndef _EXEC_H_
@@ -66,7 +66,7 @@ unsigned long a_drsize; /* data relocation size */
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
-#define QMAGIC 0314 /* "compact" demand load format -- DEPRICATE */
+#define QMAGIC 0314 /* "compact" demand load format */
/* a_mid */
#define MID_ZERO 0 /* unknown - implementation dependent */
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 6e3acd7d8550..0990a7e4af62 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)fcntl.h 5.14 (Berkeley) 7/1/91
- * $Id: fcntl.h,v 1.2.4.1 1994/05/04 07:57:14 rgrimes Exp $
+ * $Id: fcntl.h,v 1.3 1994/05/04 08:30:37 rgrimes Exp $
*/
#ifndef _FCNTL_H_
diff --git a/sys/sys/ftape.h b/sys/sys/ftape.h
index 67fd33d0803b..79a644276ad0 100644
--- a/sys/sys/ftape.h
+++ b/sys/sys/ftape.h
@@ -40,6 +40,9 @@
#define QCV_ECCBLKS 3 /* Blocks ecc eats */
#define QCV_NFMT 3 /* Number of tape formats */
#define QCV_NLEN 5 /* Number of tape lengths */
+#define QCV_HDRMAGIC 0xaa55aa55 /* Magic for header segment */
+#define QCV_FSMAGIC 0x33cc33cc /* Magic for fileset */
+
#define UCHAR unsigned char
#define USHORT unsigned short
#define ULONG unsigned long
@@ -92,6 +95,8 @@ typedef struct qic_hwinfo {
#define QIOCONFIG _IOR('q', 15, int) /* Get tape config */
#define QIOGEOM _IOR('q', 16, QIC_Geom) /* Get geometry */
#define QIOHWINFO _IOR('q', 17, QIC_HWInfo) /* Get hardware inf */
+#define QIOSENDHDR _IOW('q', 18, QIC_Segment) /* Send header */
+#define QIORECVHDR _IOWR('q', 19, QIC_Segment) /* Receive header */
/* QIC drive status bits. */
#define QS_READY 0x01 /* Drive ready */
diff --git a/sys/sys/ioctl.h b/sys/sys/ioctl.h
index 57d812b27ea6..103cd12f39bc 100644
--- a/sys/sys/ioctl.h
+++ b/sys/sys/ioctl.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)ioctl.h 7.19 (Berkeley) 6/26/91
- * $Id: ioctl.h,v 1.6.2.1 1994/05/04 07:57:16 rgrimes Exp $
+ * $Id: ioctl.h,v 1.10 1994/05/30 03:29:53 ache Exp $
*/
#ifndef _IOCTL_H_
@@ -154,10 +154,10 @@ struct ttysize {
#define TIOCEXT _IOW('t', 96, int) /* pty: external processing */
#define TIOCSIG _IO('t', 95) /* pty: generate signal */
#define TIOCDRAIN _IO('t', 94) /* wait till output drained */
-#define TIOCMSBIDIR _IOW('t', 93, int) /* modem: set bidir cap. */
-#define TIOCMGBIDIR _IOR('t', 92, int) /* modem: get bidir cap. */
#define TIOCMSDTRWAIT _IOW('t', 91, int) /* modem: set wait on close */
#define TIOCMGDTRWAIT _IOR('t', 90, int) /* modem: get wait on close */
+#define TIOCTIMESTAMP _IOR('t', 89, struct timeval) /* get timestamp of
+ last interrupt for xntp. */
#define TTYDISC 0 /* termios tty line discipline */
#define NETLDISC 1 /* line discip for berk net */
@@ -220,6 +220,9 @@ struct ttysize {
#define SIOCSIFASYNCMAP _IOW('i', 125, struct ifreq) /* set ppp asyncmap */
#define SIOCGIFASYNCMAP _IOWR('i',124, struct ifreq) /* get ppp asyncmap */
+#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */
+#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */
+
#ifndef KERNEL
#include <sys/cdefs.h>
diff --git a/sys/sys/ioctl_compat.h b/sys/sys/ioctl_compat.h
index f9e05b6a1be5..92bbc6e3a4eb 100644
--- a/sys/sys/ioctl_compat.h
+++ b/sys/sys/ioctl_compat.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)ioctl_compat.h 7.4 (Berkeley) 2/5/91
- * $Id: ioctl_compat.h,v 1.3.2.1 1994/05/04 07:57:20 rgrimes Exp $
+ * $Id: ioctl_compat.h,v 1.4 1994/05/04 08:30:45 rgrimes Exp $
*/
#ifndef _IOCTL_COMPAT_H_
diff --git a/sys/sys/ipc.h b/sys/sys/ipc.h
index 8083cf60a390..afa286111614 100644
--- a/sys/sys/ipc.h
+++ b/sys/sys/ipc.h
@@ -43,7 +43,7 @@
* SUCH DAMAGE.
*
* from: @(#)ipc.h 7.2 (Berkeley) 2/5/91
- * $Id: ipc.h,v 1.3.2.1 1994/05/04 07:57:23 rgrimes Exp $
+ * $Id: ipc.h,v 1.4 1994/05/04 08:30:48 rgrimes Exp $
*/
/*
diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h
index d1bb596d0997..5b90b62db202 100644
--- a/sys/sys/kernel.h
+++ b/sys/sys/kernel.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)kernel.h 7.4 (Berkeley) 2/15/91
- * $Id: kernel.h,v 1.8.2.1 1994/05/04 07:57:25 rgrimes Exp $
+ * $Id: kernel.h,v 1.11 1994/05/04 08:30:51 rgrimes Exp $
*/
#ifndef _SYS_KERNEL_H_
@@ -78,7 +78,12 @@ extern char *s_lowpc;
extern const char *panicstr; /* panic message */
extern const char version[]; /* system version */
-extern const char copyright[]; /* system copyright */
+extern const char ostype[]; /* operating system type */
+extern const char osrelease[]; /* operating system release */
+extern const int osbuild; /* operating system build number */
+extern const char osconfig[]; /* operating system configuration name */
+extern const char machine[]; /* machine type */
+extern const char *cpu_model; /* CPU model */
extern int nblkdev; /* number of entries in bdevsw */
extern int nchrdev; /* number of entries in cdevsw */
@@ -109,7 +114,7 @@ extern u_char curpri; /* priority of current process */
* are collected by the linker into a `struct linker_set' as defined below.
*
* NB: the constants defined below must match those defined in
- * /usr/src/gnu/ld/ld.h. Since their calculation requires arithmetic, we
+ * ld/ld.h. Since their calculation requires arithmetic, we
* can't name them symbolically (e.g., 23 is N_SETT | N_EXT).
*/
#define MAKE_SET(set, sym, type) \
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index e1fbf7752fc4..d9d45921f9c3 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)malloc.h 7.25 (Berkeley) 5/15/91
- * $Id: malloc.h,v 1.4 1993/11/07 17:52:43 wollman Exp $
+ * $Id: malloc.h,v 1.7 1994/05/17 22:31:21 jkh Exp $
*/
#ifndef _MALLOC_H_
@@ -91,6 +91,11 @@
#define M_LOCKF 40 /* Byte-range locking structures */
#define M_PROC 41 /* Proc structures */
#define M_SUBPROC 42 /* Proc sub-structures */
+#define M_IPMOPTS 43 /* Internet multicast options */
+#define M_IPMADDR 44 /* Internet multicast address */
+#define M_IFMADDR 45 /* link-level multicast address */
+#define M_MRTABLE 46 /* multicast routing tables */
+#define M_TTYS 47 /* allocated tty structures */
#define M_ISOFSMNT 48 /* isofs mount structures */
#define M_TEMP 49 /* misc temporary data buffers */
#define M_PCFSMNT 50 /* PCFS mount structure */
@@ -141,8 +146,12 @@
"file desc", /* 39 M_FILEDESC */ \
"lockf", /* 40 M_LOCKF */ \
"proc", /* 41 M_PROC */ \
- "subproc", /* 42 M_PROC */ \
- 0, 0, 0, 0, 0, \
+ "subproc", /* 42 M_SUBPROC */ \
+ "mcast opts", /* 43 M_IPMOPTS */ \
+ "ip mcast", /* 44 M_IPMADDR */ \
+ "if mcast", /* 45 M_IFMADDR */ \
+ "mcast route", /* 46 M_MRTABLE */ \
+ "ttys", /* 47 M_TTYS */ \
"isofs mount", /* 48 M_ISOFSMNT */ \
"temp", /* 49 M_TEMP */ \
"PCFS mount", /* 50 M_PCFSMNT */ \
@@ -270,5 +279,7 @@ extern char *kmembase;
extern struct kmembuckets bucket[];
extern void *malloc __P((unsigned long size, int type, int flags));
extern void free __P((void *addr, int type));
+extern void *contigmalloc __P((unsigned long size, int type, int flags, unsigned long maxpa,
+ unsigned long alignmask, unsigned long boundarymask));
#endif /* KERNEL */
#endif /* !_MALLOC_H_ */
diff --git a/sys/sys/map.h b/sys/sys/map.h
index b0a4dc2ce8ce..e1ac4e5eefa0 100644
--- a/sys/sys/map.h
+++ b/sys/sys/map.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)map.h 7.5 (Berkeley) 5/7/91
- * $Id: map.h,v 1.2.2.1 1994/05/04 07:57:29 rgrimes Exp $
+ * $Id: map.h,v 1.3 1994/05/04 08:30:54 rgrimes Exp $
*/
#ifndef _SYS_MAP_H_
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index ea36d4cced01..e36d6357fca0 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)mbuf.h 7.14 (Berkeley) 12/5/90
- * $Id: mbuf.h,v 1.6 1993/12/19 00:55:19 wollman Exp $
+ * $Id: mbuf.h,v 1.10 1994/06/01 03:06:27 davidg Exp $
*/
#ifndef _SYS_MBUF_H_
@@ -65,7 +65,7 @@
#define mtod(m,t) ((t)((m)->m_data))
#define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1)))
#define mtocl(x) (((u_int)(x) - (u_int)mbutl) >> MCLSHIFT)
-#define cltom(x) ((caddr_t)((u_int)mbutl + ((u_int)(x) >> MCLSHIFT)))
+#define cltom(x) ((caddr_t)((u_int)mbutl + ((u_int)(x) << MCLSHIFT)))
/* header at beginning of each mbuf: */
struct m_hdr {
@@ -158,8 +158,21 @@ struct mbuf {
* allocates an mbuf and initializes it to contain a packet header
* and internal data.
*/
+
+
+struct mbuf *mbuffree;
+int mbuffreecnt;
#define MGET(m, how, type) { \
- MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+ int s = splimp(); \
+ if( mbuffree == 0) { \
+ splx(s); \
+ MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+ } else { \
+ --mbuffreecnt; \
+ (m) = mbuffree; \
+ mbuffree = (m)->m_next; \
+ splx(s); \
+ } \
if (m) { \
(m)->m_type = (type); \
mbstat.m_mtypes[type]++; \
@@ -172,7 +185,16 @@ struct mbuf {
}
#define MGETHDR(m, how, type) { \
- MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+ disable_intr(); \
+ if( mbuffree == 0) { \
+ enable_intr(); \
+ MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+ } else { \
+ --mbuffreecnt; \
+ (m) = mbuffree; \
+ mbuffree = (m)->m_next; \
+ enable_intr(); \
+ } \
if (m) { \
(m)->m_type = (type); \
mbstat.m_mtypes[type]++; \
@@ -219,6 +241,7 @@ union mcluster {
(m)->m_data = (m)->m_ext.ext_buf; \
(m)->m_flags |= M_EXT; \
(m)->m_ext.ext_size = MCLBYTES; \
+ (m)->m_ext.ext_free = (void (*)())0; \
} \
}
@@ -237,8 +260,7 @@ union mcluster {
* Free a single mbuf and associated external storage.
* Place the successor, if any, in n.
*/
-#ifdef notyet
-#define MFREE(m, n) \
+#define MFREE(m, nn) \
{ mbstat.m_mtypes[(m)->m_type]--; \
if ((m)->m_flags & M_EXT) { \
if ((m)->m_ext.ext_free) \
@@ -247,19 +269,17 @@ union mcluster {
else \
MCLFREE((m)->m_ext.ext_buf); \
} \
- (n) = (m)->m_next; \
- FREE((m), mbtypes[(m)->m_type]); \
- }
-#else /* notyet */
-#define MFREE(m, nn) \
- { mbstat.m_mtypes[(m)->m_type]--; \
- if ((m)->m_flags & M_EXT) { \
- MCLFREE((m)->m_ext.ext_buf); \
- } \
(nn) = (m)->m_next; \
- FREE((m), mbtypes[(m)->m_type]); \
+ if( mbuffreecnt < 256) { \
+ ++mbuffreecnt; \
+ disable_intr(); \
+ (m)->m_next = mbuffree; \
+ mbuffree = (m); \
+ enable_intr(); \
+ } else { \
+ FREE((m), mbtypes[(m)->m_type]); \
+ } \
}
-#endif
/*
* Copy mbuf pkthdr from from to to.
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index bdbfa9901518..889fb58a9771 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)mount.h 7.22 (Berkeley) 6/3/91
- * $Id: mount.h,v 1.10 1993/12/19 22:54:02 alm Exp $
+ * $Id: mount.h,v 1.11 1994/03/07 11:39:02 davidg Exp $
*/
#ifndef _SYS_MOUNT_H_
@@ -86,7 +86,8 @@ struct statfs {
#define MOUNT_MSDOS 4 /* MSDOS Filesystem */
#define MOUNT_ISOFS 5 /* iso9660 cdrom */
#define MOUNT_PROCFS 6 /* proc filesystem */
-#define MOUNT_MAXTYPE 6
+#define MOUNT_DEVFS 7 /* device filesystem */
+#define MOUNT_MAXTYPE 7
/*
* Structure per mounted file system.
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index 11320d89a9c5..0e48cb227752 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)namei.h 7.15 (Berkeley) 5/15/91
- * $Id: namei.h,v 1.3 1993/11/07 17:52:53 wollman Exp $
+ * $Id: namei.h,v 1.5 1994/05/26 04:29:54 ache Exp $
*/
#ifndef _NAMEI_H_
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 727689567734..bf27fbb53196 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)param.h 7.23 (Berkeley) 5/6/91
- * $Id: param.h,v 1.3.4.1 1994/05/04 07:57:31 rgrimes Exp $
+ * $Id: param.h,v 1.4 1994/05/04 08:30:58 rgrimes Exp $
*/
#ifndef _SYS_PARAM_H_
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index dcee5115b656..83ec20800764 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)proc.h 7.28 (Berkeley) 5/30/91
- * $Id: proc.h,v 1.6.2.1 1994/03/24 08:38:44 rgrimes Exp $
+ * $Id: proc.h,v 1.7 1994/03/15 02:48:51 wollman Exp $
*/
#ifndef _PROC_H_
diff --git a/sys/sys/procfs.h b/sys/sys/procfs.h
index 368226781adc..520734071385 100644
--- a/sys/sys/procfs.h
+++ b/sys/sys/procfs.h
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: procfs.h,v 1.1 1993/12/12 12:27:03 davidg Exp $
+ * $Id: procfs.h,v 1.2 1994/03/07 11:39:04 davidg Exp $
*/
#ifndef _SYS_PROCFS_H_
#define _SYS_PROCFS_H_
@@ -44,6 +44,26 @@ struct vmfd { /* Mapped file descriptor */
int fd; /* OUT */
};
+enum vmet { PFS_END, PFS_PRMAP, PFS_OBJINFO };
+
+struct objinfo {
+ int ref_count; /* ref_count for object */
+ int rss_map; /* rss within the map entry */
+ int persist; /* persist flag */
+ int internal; /* internal flag */
+ vm_offset_t offset; /* offset into object */
+ vm_offset_t size; /* total size of object */
+ struct vm_page pages[0]; /* pages */
+};
+
+struct procvminfo { /* Full proc VM info */
+ enum vmet entrytype; /* type of entry */
+ union {
+ struct procmap pm; /* proc map entry */
+ struct objinfo oi; /* object info entry */
+ } u;
+};
+
typedef unsigned long fltset_t;
#define PIOCGPINFO _IOR('P', 0, struct kinfo_proc)
@@ -54,5 +74,7 @@ typedef unsigned long fltset_t;
#define PIOCGNMAP _IOR('P', 5, int)
#define PIOCGMAP _IO ('P', 6)
#define PIOCGMAPFD _IOWR('P', 7, struct vmfd)
+#define PIOCGNVMINFO _IOR('P', 8, int)
+#define PIOCGVMINFO _IO ('P', 9)
#endif /* _SYS_PROCFS_H_ */
diff --git a/sys/sys/signal.h b/sys/sys/signal.h
index 348ccb28c632..6a4676f58e9c 100644
--- a/sys/sys/signal.h
+++ b/sys/sys/signal.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)signal.h 7.16 (Berkeley) 3/17/91
- * $Id: signal.h,v 1.7.2.1 1994/05/04 07:57:33 rgrimes Exp $
+ * $Id: signal.h,v 1.8 1994/05/04 08:31:02 rgrimes Exp $
*/
#ifndef _SIGNAL_H_
diff --git a/sys/sys/specdev.h b/sys/sys/specdev.h
index 119cc5388a63..15c8788854b3 100644
--- a/sys/sys/specdev.h
+++ b/sys/sys/specdev.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)specdev.h 7.4 (Berkeley) 4/19/91
- * $Id: specdev.h,v 1.4 1993/11/25 01:38:04 wollman Exp $
+ * $Id: specdev.h,v 1.5 1994/05/30 03:30:29 ache Exp $
*/
#ifndef _SYS_SPECDEV_H_
@@ -47,6 +47,7 @@ struct specinfo {
struct vnode *si_specnext;
long si_flags;
dev_t si_rdev;
+ short si_opencount; /* count of sleeping openers */
};
/*
* Exported shorthand
@@ -55,6 +56,7 @@ struct specinfo {
#define v_hashchain v_specinfo->si_hashchain
#define v_specnext v_specinfo->si_specnext
#define v_specflags v_specinfo->si_flags
+#define v_opencount v_specinfo->si_opencount
/*
* Flags for specinfo
diff --git a/sys/sys/stat.h b/sys/sys/stat.h
index fe4f8f19321d..0c661950ed21 100644
--- a/sys/sys/stat.h
+++ b/sys/sys/stat.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)stat.h 7.11 (Berkeley) 3/3/91
- * $Id: stat.h,v 1.4.4.1 1994/05/04 07:57:35 rgrimes Exp $
+ * $Id: stat.h,v 1.5 1994/05/04 08:31:05 rgrimes Exp $
*/
#ifndef _SYS_STAT_H_
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 491ccd5d6f1a..6b2c63a13ece 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -4,7 +4,7 @@
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $
+ * created from $Id: syscalls.master,v 1.9 1994/03/15 01:58:33 wollman Exp $
*/
#define SYS_exit 1
@@ -169,6 +169,8 @@
#define SYS_semsys 169
#define SYS_msgsys 170
#define SYS_shmsys 171
+#define SYS_ntp_gettime 175
+#define SYS_ntp_adjtime 176
#define SYS_vm_allocate 177
#define SYS_vm_deallocate 178
#define SYS_vm_inherit 179
@@ -176,4 +178,4 @@
#define SYS_setgid 181
#define SYS_setegid 182
#define SYS_seteuid 183
-#endif /* _SYS_SYSCALL_H_ */ \ No newline at end of file
+#endif /* _SYS_SYSCALL_H_ */
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index b7ca8af23b5c..fce5b1755c89 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -38,15 +38,24 @@
* SUCH DAMAGE.
*
* from: @(#)systm.h 7.17 (Berkeley) 5/25/91
- * $Id: systm.h,v 1.9.2.1 1994/05/04 07:57:37 rgrimes Exp $
+ * $Id: systm.h,v 1.11 1994/05/04 08:31:08 rgrimes Exp $
*/
#ifndef _SYS_SYSTM_H_
#define _SYS_SYSTM_H_
-#include "sys/param.h"
+#include "sys/param.h" /* XXX */
#include "sys/sysent.h" /* XXX */
+/*
+ * Machine-dependent function declarations.
+ * These must be first in case a machine-dependent function is static
+ * [inline]. ANSI C's linkage scope rules require the static version
+ * to be visible first. However, if the machine-dependent functions
+ * were actually macros, they would have to be defined last.
+ */
+#include <machine/cpufunc.h>
+
/* Initialize the world */
void startrtclock __P((void));
void consinit __P((void));
@@ -78,17 +87,18 @@ void selwakeup __P((int /*pid_t*/, int));
extern int selwait; /* select timeout address */
-/* SPL Levels */
-extern int splbio(void);
-extern int splclock(void);
-extern int splhigh(void);
-extern int splimp(void);
-extern int splnet(void);
-extern int splsoftclock(void);
-extern int spltty(void);
-extern int splnone(void);
-extern int splx(int);
-#define spl0 splnone
+/* Interrupt masking. */
+void spl0 __P((void));
+int splbio __P((void));
+int splclock __P((void));
+int splhigh __P((void));
+int splimp __P((void));
+int splnet __P((void));
+#define splnone spl0 /* XXX traditional; the reverse is better */
+int splsoftclock __P((void));
+int splsofttty __P((void));
+int spltty __P((void));
+void splx __P((int));
/* Scheduling */
@@ -181,7 +191,6 @@ void boot __P((int));
/* string functions */
-size_t strlen __P((const char *));
int strcmp __P((const char *, const char *));
char *strncpy __P((char *, const char *, int));
char *strcat __P((char *, const char *));
@@ -195,13 +204,8 @@ int bcmp __P((const void *str1, const void *str2, u_int len));
int scanc __P((unsigned size, u_char *cp, u_char *table, int mask));
int skpc __P((int, u_int, u_char *));
int locc __P((int, unsigned, u_char *));
-int ffs __P((long));
/* Debugger entry points */
void Debugger __P((const char *));
-/*
- * Machine-dependent function declarations.
- */
-#include <machine/cpufunc.h>
#endif /* _SYS_SYSTM_H_ */
diff --git a/sys/sys/termios.h b/sys/sys/termios.h
index d8be611142d3..a49f7e7d3a6f 100644
--- a/sys/sys/termios.h
+++ b/sys/sys/termios.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)termios.h 7.22 (Berkeley) 5/7/91
- * $Id: termios.h,v 1.8 1994/01/31 07:38:18 ache Exp $
+ * $Id: termios.h,v 1.9 1994/05/30 03:31:04 ache Exp $
*/
/*
@@ -181,7 +181,7 @@
typedef unsigned long tcflag_t;
typedef unsigned char cc_t;
-typedef long speed_t;
+typedef long speed_t; /* XXX should be unsigned long */
struct termios {
tcflag_t c_iflag; /* input flags */
@@ -189,8 +189,8 @@ struct termios {
tcflag_t c_cflag; /* control flags */
tcflag_t c_lflag; /* local flags */
cc_t c_cc[NCCS]; /* control chars */
- long c_ispeed; /* input speed */
- long c_ospeed; /* output speed */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
};
/*
diff --git a/sys/sys/timeb.h b/sys/sys/timeb.h
index 1ada939b0cf7..e846ee2e08a4 100644
--- a/sys/sys/timeb.h
+++ b/sys/sys/timeb.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)timeb.h 7.2 (Berkeley) 5/5/91
- * $Id: timeb.h,v 1.3.2.1 1994/05/04 07:57:40 rgrimes Exp $
+ * $Id: timeb.h,v 1.4 1994/05/04 08:31:12 rgrimes Exp $
*/
#ifndef _SYS_TIMEB_H_
diff --git a/sys/sys/times.h b/sys/sys/times.h
index 29a73f82e5c2..2bb24632ed9c 100644
--- a/sys/sys/times.h
+++ b/sys/sys/times.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)times.h 7.6 (Berkeley) 3/9/91
- * $Id: times.h,v 1.3.2.1 1994/05/04 07:57:42 rgrimes Exp $
+ * $Id: times.h,v 1.4 1994/05/04 08:31:16 rgrimes Exp $
*/
#ifndef _SYS_TIMES_H_
diff --git a/sys/sys/timex.h b/sys/sys/timex.h
new file mode 100644
index 000000000000..8390ceddca6c
--- /dev/null
+++ b/sys/sys/timex.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993, 1994 *
+ * *
+ * 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, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ ******************************************************************************/
+
+/*
+ * Modification history timex.h
+ *
+ * 19 Mar 94 David L. Mills
+ * Moved defines from kernel routines to header file and added new
+ * defines for PPS phase-lock loop.
+ *
+ * 20 Feb 94 David L. Mills
+ * Revised status codes and structures for external clock and PPS
+ * signal discipline.
+ *
+ * 28 Nov 93 David L. Mills
+ * Adjusted parameters to improve stability and increase poll
+ * interval.
+ *
+ * 17 Sep 93 David L. Mills
+ * Created file
+ */
+/*
+ * This header file defines the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. These are implemented using
+ * private syscalls and data structures and require specific kernel
+ * support.
+ *
+ * NAME
+ * ntp_gettime - NTP user application interface
+ *
+ * SYNOPSIS
+ * #include <sys/timex.h>
+ *
+ * int syscall(SYS_ntp_gettime, tptr)
+ *
+ * int SYS_ntp_gettime defined in syscall.h header file
+ * struct ntptimeval *tptr pointer to ntptimeval structure
+ *
+ * NAME
+ * ntp_adjtime - NTP daemon application interface
+ *
+ * SYNOPSIS
+ * #include <sys/timex.h>
+ *
+ * int syscall(SYS_ntp_adjtime, mode, tptr)
+ *
+ * int SYS_ntp_adjtime defined in syscall.h header file
+ * struct timex *tptr pointer to timex structure
+ *
+ */
+#ifndef _SYS_TIMEX_H_
+#define _SYS_TIMEX_H_ 1
+
+#ifndef MSDOS /* Microsoft specific */
+#include <sys/syscall.h>
+#endif /* MSDOS */
+
+/*
+ * The following defines establish the engineering parameters of the
+ * phase-lock loop (PLL) model used in the kernel implementation. These
+ * parameters have been carefully chosen by analysis for good stability
+ * and wide dynamic range.
+ *
+ * The hz variable is defined in the kernel build environment. It
+ * establishes the timer interrupt frequency, 100 Hz for the SunOS
+ * kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the OSF/1
+ * kernel. SHIFT_HZ expresses the same value as the nearest power of two
+ * in order to avoid hardware multiply operations.
+ *
+ * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
+ * for a slightly underdamped convergence characteristic.
+ *
+ * MAXTC establishes the maximum time constant of the PLL. With the
+ * SHIFT_KG and SHIFT_KF values given and a time constant range from
+ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
+ * respectively.
+ */
+#define SHIFT_HZ 7 /* log2(hz) */
+#define SHIFT_KG 6 /* phase factor (shift) */
+#define SHIFT_KF 16 /* frequency factor (shift) */
+#define MAXTC 6 /* maximum time constant (shift) */
+
+/*
+ * The following defines establish the scaling of the various variables
+ * used by the PLL. They are chosen to allow the greatest precision
+ * possible without overflow of a 32-bit word.
+ *
+ * SHIFT_SCALE defines the scaling (shift) of the time_phase variable,
+ * which serves as a an extension to the low-order bits of the system
+ * clock variable time.tv_usec.
+ *
+ * SHIFT_UPDATE defines the scaling (shift) of the time_offset variable,
+ * which represents the current time offset with respect to standard
+ * time.
+ *
+ * SHIFT_USEC defines the scaling (shift) of the time_freq and
+ * time_tolerance variables, which represent the current frequency
+ * offset and maximum frequency tolerance.
+ *
+ * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
+ */
+#define SHIFT_SCALE 23 /* phase scale (shift) */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
+#define SHIFT_USEC 16 /* frequency offset scale (shift) */
+#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
+
+/*
+ * The following defines establish the performance envelope of the PLL.
+ * They insure it operates within predefined limits, in order to satisfy
+ * correctness assertions. An excursion which exceeds these bounds is
+ * clamped to the bound and operation proceeds accordingly. In practice,
+ * this can occur only if something has failed or is operating out of
+ * tolerance, but otherwise the PLL continues to operate in a stable
+ * mode.
+ *
+ * MAXPHASE must be set greater than or equal to CLOCK.MAX (128 ms), as
+ * defined in the NTP specification. CLOCK.MAX establishes the maximum
+ * time offset allowed before the system time is reset, rather than
+ * incrementally adjusted. Here, the maximum offset is clamped to
+ * MAXPHASE only in order to prevent overflow errors due to defective
+ * protocol implementations.
+ *
+ * MAXFREQ is the maximum frequency tolerance of the CPU clock
+ * oscillator plus the maximum slew rate allowed by the protocol. It
+ * should be set to at least the frequency tolerance of the oscillator
+ * plus 100 ppm for vernier frequency adjustments. If the kernel
+ * PPS discipline code is configured (PPS_SYNC), the oscillator time and
+ * frequency are disciplined to an external source, presumably with
+ * negligible time and frequency error relative to UTC, and MAXFREQ can
+ * be reduced.
+ *
+ * MAXTIME is the maximum jitter tolerance of the PPS signal if the
+ * kernel PPS discipline code is configured (PPS_SYNC).
+ *
+ * MINSEC and MAXSEC define the lower and upper bounds on the interval
+ * between protocol updates.
+ */
+#define MAXPHASE 128000L /* max phase error (us) */
+#ifdef PPS_SYNC
+#define MAXFREQ (100L << SHIFT_USEC) /* max freq error (100 ppm) */
+#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
+#else
+#define MAXFREQ (200L << SHIFT_USEC) /* max freq error (200 ppm) */
+#endif /* PPS_SYNC */
+#define MINSEC 16L /* min interval between updates (s) */
+#define MAXSEC 1200L /* max interval between updates (s) */
+
+#ifdef PPS_SYNC
+/*
+ * The following defines are used only if a pulse-per-second (PPS)
+ * signal is available and connected via a modem control lead, such as
+ * produced by the optional ppsclock feature incorporated in the Sun
+ * asynch driver. They establish the design parameters of the frequency-
+ * lock loop used to discipline the CPU clock oscillator to the PPS
+ * signal.
+ *
+ * PPS_AVG is the averaging factor for the frequency loop, as well as
+ * the time and frequency dispersion.
+ *
+ * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
+ * calibration intervals, respectively, in seconds as a power of two.
+ *
+ * PPS_VALID is the maximum interval before the PPS signal is considered
+ * invalid and protocol updates used directly instead.
+ *
+ * MAXGLITCH is the maximum interval before a time offset of more than
+ * MAXTIME is believed.
+ */
+#define PPS_AVG 2 /* pps averaging constant (shift) */
+#define PPS_SHIFT 2 /* min interval duration (s) (shift) */
+#define PPS_SHIFTMAX 8 /* max interval duration (s) (shift) */
+#define PPS_VALID 120 /* pps signal watchdog max (s) */
+#define MAXGLITCH 30 /* pps signal glitch max (s) */
+#endif /* PPS_SYNC */
+
+/*
+ * The following defines and structures define the user interface for
+ * the ntp_gettime() and ntp_adjtime() system calls.
+ *
+ * Control mode codes (timex.modes)
+ */
+#define MOD_OFFSET 0x0001 /* set time offset */
+#define MOD_FREQUENCY 0x0002 /* set frequency offset */
+#define MOD_MAXERROR 0x0004 /* set maximum time error */
+#define MOD_ESTERROR 0x0008 /* set estimated time error */
+#define MOD_STATUS 0x0010 /* set clock status bits */
+#define MOD_TIMECONST 0x0020 /* set pll time constant */
+#define MOD_CLKB 0x4000 /* set clock B */
+#define MOD_CLKA 0x8000 /* set clock A */
+
+/*
+ * Status codes (timex.status)
+ */
+#define STA_PLL 0x0001 /* enable PLL updates (rw) */
+#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
+#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
+
+#define STA_INS 0x0010 /* insert leap (rw) */
+#define STA_DEL 0x0020 /* delete leap (rw) */
+#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
+
+#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
+#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
+#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
+#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
+
+#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
+
+#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
+ STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+
+/*
+ * Clock states (time_state)
+ */
+#define TIME_OK 0 /* no leap second warning */
+#define TIME_INS 1 /* insert leap second warning */
+#define TIME_DEL 2 /* delete leap second warning */
+#define TIME_OOP 3 /* leap second in progress */
+#define TIME_WAIT 4 /* leap second has occured */
+#define TIME_ERROR 5 /* clock not synchronized */
+
+/*
+ * NTP user interface (ntp_gettime()) - used to read kernel clock values
+ *
+ * Note: maximum error = NTP synch distance = dispersion + delay / 2;
+ * estimated error = NTP dispersion.
+ */
+struct ntptimeval {
+ struct timeval time; /* current time (ro) */
+ long maxerror; /* maximum error (us) (ro) */
+ long esterror; /* estimated error (us) (ro) */
+};
+
+/*
+ * NTP daemon interface - (ntp_adjtime()) used to discipline CPU clock
+ * oscillator
+ */
+struct timex {
+ unsigned int modes; /* clock mode bits (wo) */
+ long offset; /* time offset (us) (rw) */
+ long freq; /* frequency offset (scaled ppm) (rw) */
+ long maxerror; /* maximum error (us) (rw) */
+ long esterror; /* estimated error (us) (rw) */
+ int status; /* clock status bits (rw) */
+ long constant; /* pll time constant (rw) */
+ long precision; /* clock precision (us) (ro) */
+ long tolerance; /* clock frequency tolerance (scaled
+ * ppm) (ro) */
+ /*
+ * The following read-only structure members are implemented
+ * only if the PPS signal discipline is configured in the
+ * kernel.
+ */
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+
+};
+#ifdef __FreeBSD__
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int ntp_gettime __P((struct ntptimeval *));
+extern int ntp_adjtime __P((struct timex *));
+__END_DECLS
+
+#endif /* not KERNEL */
+
+#endif /* __FreeBSD__ */
+#endif /* _SYS_TIMEX_H_ */
diff --git a/sys/sys/tty.h b/sys/sys/tty.h
index 9c8f11dfc621..9b0417b74e2f 100644
--- a/sys/sys/tty.h
+++ b/sys/sys/tty.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)tty.h 7.10 (Berkeley) 6/26/91
- * $Id: tty.h,v 1.8 1994/01/28 23:15:17 ache Exp $
+ * $Id: tty.h,v 1.12 1994/05/30 21:56:22 ache Exp $
*/
#ifndef _SYS_TTY_H_
@@ -42,8 +42,11 @@
/*
* Ring buffers provide a contiguous, dense storage for
* character data used by the tty driver.
+ *
+ * Make sizeof(struct ringb) be such that it fits exactly in
+ * a malloc bucket.
*/
-#define RBSZ 1024
+#define RBSZ 2040
struct ringb {
char *rb_hd; /* head of buffer segment to be read */
@@ -117,9 +120,9 @@ struct tty {
#if 0
int t_mask; /* interrupt mask */
#endif
- struct ringb t_raw; /* ring buffers */
- struct ringb t_can;
- struct ringb t_out;
+ struct ringb *t_raw; /* ring buffers */
+ struct ringb *t_can;
+ struct ringb *t_out;
};
#define TTIPRI 25 /* sleep priority for tty reads */
@@ -127,30 +130,29 @@ struct tty {
#define TTMASK 15
#define OBUFSIZ 100
-#define TTYHOG 1024
+#define TTYHOG RBSZ
#ifdef KERNEL
#define TTMAXHIWAT (RBSZ/2) /* XXX */
#define TTMINHIWAT 128
#define TTMAXLOWAT 256
#define TTMINLOWAT 32
-extern struct ttychars ttydefaults;
#endif /* KERNEL */
/* internal state bits */
#define TS_TIMEOUT 0x000001UL /* delay timeout in progress */
-#define TS_WOPEN 0x000002UL /* waiting for open to complete */
#define TS_ISOPEN 0x000004UL /* device is open */
#define TS_FLUSH 0x000008UL /* outq has been flushed during DMA */
#define TS_CARR_ON 0x000010UL /* software copy of carrier-present */
#define TS_BUSY 0x000020UL /* output in progress */
-#define TS_ASLEEP 0x000040UL /* wakeup when output done */
+#define TS_SO_OLOWAT 0x000040UL /* wake up when output <= low water */
#define TS_XCLUDE 0x000080UL /* exclusive-use flag against open */
#define TS_TTSTOP 0x000100UL /* output stopped by ctl-s */
-/* was TS_HUPCLS 0x000200UL * hang up upon last close */
+#define TS_ZOMBIE 0x000200UL /* carrier dropped */
#define TS_TBLOCK 0x000400UL /* tandem queue blocked */
#define TS_RCOLL 0x000800UL /* collision in read select */
#define TS_WCOLL 0x001000UL /* collision in write select */
+#define TS_SO_OCOMPLETE 0x002000UL /* wake up when output complete */
#define TS_ASYNC 0x004000UL /* tty in async i/o mode */
/* state for intra-line fancy editing work */
#define TS_BKSL 0x010000UL /* state for lowercase \ work */
@@ -166,6 +168,13 @@ extern struct ttychars ttydefaults;
#define TS_HW_IFLOW (TS_DTR_IFLOW | TS_RTS_IFLOW)
#define TS_LOCAL (TS_BKSL|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
+/*
+ * XXX maintain a single flag to keep track of this combination and fix all
+ * the places that check TS_CARR_ON without checking CLOCAL or TS_ZOMBIE.
+ */
+#define CAN_DO_IO(tp) (((tp)->t_state & (TS_CARR_ON | TS_ZOMBIE)) \
+ == TS_CARR_ON || (tp)->t_cflag & CLOCAL)
+
/* define partab character types */
#define ORDINARY 0
#define CONTROL 1
@@ -206,21 +215,31 @@ struct speedtab {
#define DMBIC 2
#define DMGET 3
-#ifdef KERNEL
-/* symbolic sleep message strings */
-extern const char ttyin[], ttyout[], ttopen[], ttclos[], ttybg[], ttybuf[];
+/*
+ * Sleep addresses.
+ */
+#define TSA_CARR_ON(tp) ((caddr_t)(tp) + 0)
+#define TSA_HUP_OR_INPUT(tp) ((caddr_t)(tp) + 1)
+#define TSA_OCOMPLETE(tp) ((caddr_t)(tp) + 2)
+#define TSA_OLOWAT(tp) ((caddr_t)(tp) + 3)
+#define TSA_PTC_READ(tp) ((caddr_t)(tp) + 4)
+#define TSA_PTC_WRITE(tp) ((caddr_t)(tp) + 5)
+#ifdef KERNEL
+struct proc;
struct uio;
/* From tty.c: */
+extern void termioschars(struct termios *);
extern void ttychars(struct tty *);
-extern int ttwflush(struct tty *);
+extern int ttywflush(struct tty *);
extern int ttywait(struct tty *);
extern void ttyflush(struct tty *, int);
extern void ttstart(struct tty *);
+#if 0 /* XXX not used */
extern void ttrstrt(struct tty *);
+#endif
extern int ttioctl(struct tty *, int, caddr_t, int);
-extern int ttnread(struct tty *);
extern int ttselect(int /*dev_t*/, int, struct proc *);
extern int ttyopen(int /*dev_t*/, struct tty *, int);
extern void ttylclose(struct tty *, int);
@@ -232,17 +251,22 @@ extern int ttread(struct tty *, struct uio *, int);
extern int ttycheckoutq(struct tty *, int);
extern int ttwrite(struct tty *, struct uio *, int);
extern void ttwakeup(struct tty *);
+extern void ttwwakeup(struct tty *);
extern int ttspeedtab(int, struct speedtab *);
extern void ttsetwater(struct tty *);
extern void ttyinfo(struct tty *);
extern int tputchar(int, struct tty *);
extern int ttysleep(struct tty *, caddr_t, int, const char *, int);
+extern struct tty *ttymalloc(struct tty *);
+extern void ttyfree(struct tty *);
/* From tty_ring.c: */
extern int putc(int, struct ringb *);
extern int getc(struct ringb *);
extern int nextc(char **, struct ringb *);
+#if 0 /* XXX not used */
extern int ungetc(int, struct ringb *);
+#endif
extern int unputc(struct ringb *);
extern void initrb(struct ringb *);
extern void catb(struct ringb *, struct ringb *);
@@ -252,4 +276,5 @@ extern size_t rb_write(struct ringb *, char *, size_t);
extern int ttcompat(struct tty *, int, caddr_t, int);
#endif /* KERNEL */
+
#endif /* _SYS_TTY_H_ */
diff --git a/sys/sys/ttydefaults.h b/sys/sys/ttydefaults.h
index 2ce0c9990ea3..cce2c86353db 100644
--- a/sys/sys/ttydefaults.h
+++ b/sys/sys/ttydefaults.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)ttydefaults.h 7.9 (Berkeley) 5/9/91
- * $Id: ttydefaults.h,v 1.3.2.1 1994/05/04 07:57:44 rgrimes Exp $
+ * $Id: ttydefaults.h,v 1.5 1994/05/30 03:32:26 ache Exp $
*/
/*
@@ -61,10 +61,10 @@
*/
#define CTRL(x) (x&037)
#define CEOF CTRL('d')
-#define CEOL ((unsigned)'\377') /* XXX avoid _POSIX_VDISABLE */
+#define CEOL 0xFF /* XXX avoid _POSIX_VDISABLE */
#define CERASE 0177
#define CINTR CTRL('c')
-#define CSTATUS ((unsigned)'\377') /* XXX avoid _POSIX_VDISABLE */
+#define CSTATUS 0xFF /* XXX avoid _POSIX_VDISABLE */
#define CKILL CTRL('u')
#define CMIN 1
#define CQUIT 034 /* FS, ^\ */
@@ -90,7 +90,7 @@
* #define TTYDEFCHARS to include an array of default control characters.
*/
#ifdef TTYDEFCHARS
-cc_t ttydefchars[NCCS] = {
+static cc_t ttydefchars[NCCS] = {
CEOF, CEOL, CEOL, CERASE, CWERASE, CKILL, CREPRINT,
_POSIX_VDISABLE, CINTR, CQUIT, CSUSP, CDSUSP, CSTART, CSTOP, CLNEXT,
CDISCARD, CMIN, CTIME, CSTATUS, _POSIX_VDISABLE
diff --git a/sys/sys/types.h b/sys/sys/types.h
index 53aa680a38e2..c69398ba373d 100644
--- a/sys/sys/types.h
+++ b/sys/sys/types.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)types.h 7.17 (Berkeley) 5/6/91
- * $Id: types.h,v 1.8.2.1 1994/05/04 07:57:47 rgrimes Exp $
+ * $Id: types.h,v 1.12 1994/05/04 08:31:24 rgrimes Exp $
*/
#ifndef _TYPES_H_
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
index fb12c87c9f26..76b4c56d8c4b 100644
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -31,22 +31,22 @@
* SUCH DAMAGE.
*
* from: @(#)unistd.h 5.14 (Berkeley) 4/1/91
- * $Id: unistd.h,v 1.4 1994/01/31 07:38:20 ache Exp $
+ * $Id: unistd.h,v 1.7 1994/05/07 20:05:24 wollman Exp $
*/
#ifndef _SYS_UNISTD_H_
#define _SYS_UNISTD_H_
/* compile-time symbolic constants */
-#define _POSIX_JOB_CONTROL /* implementation supports job control */
-#ifdef _NOTYET
-#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#define _POSIX_JOB_CONTROL 1 /* implementation supports job control */
+#if 0
+#define _POSIX_SAVED_IDS 1 /* saved set-user-ID and set-group-ID */
#endif
#define _POSIX_VERSION 198808L
/* execution-time symbolic constants */
-#define _POSIX_CHOWN_RESTRICTED /* chown requires appropriate privileges */
-#define _POSIX_NO_TRUNC /* too-long path components generate errors */
+#define _POSIX_CHOWN_RESTRICTED 0 /* chown requires appropriate privileges */
+#define _POSIX_NO_TRUNC 0 /* too-long path components generate errors */
/* may disable terminal special characters */
#define _POSIX_VDISABLE 0xFF
diff --git a/sys/ufs/dir.h b/sys/ufs/dir.h
index 963ead42dec9..00e91e9d0d8f 100644
--- a/sys/ufs/dir.h
+++ b/sys/ufs/dir.h
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)dir.h 7.10 (Berkeley) 3/25/91
- * $Id: dir.h,v 1.2.4.1 1994/05/04 07:59:08 rgrimes Exp $
+ * $Id: dir.h,v 1.3 1994/05/04 08:33:04 rgrimes Exp $
*/
#ifndef _DIR_H_
diff --git a/sys/ufs/ufs_disksubr.c b/sys/ufs/ufs_disksubr.c
index e80b67e371b1..5c155992e592 100644
--- a/sys/ufs/ufs_disksubr.c
+++ b/sys/ufs/ufs_disksubr.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
- * $Id: ufs_disksubr.c,v 1.5 1993/12/19 00:55:43 wollman Exp $
+ * $Id: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
*/
#include "param.h"
@@ -493,6 +493,7 @@ bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel)
int maxsz = p->p_size,
sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
+#if !defined(DISKLABEL_UNPROTECTED)
/* overwriting disk label ? */
/* XXX should also protect bootstrap in first 8K */
if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
@@ -503,6 +504,7 @@ bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel)
bp->b_error = EROFS;
goto bad;
}
+#endif /* !defined(DISKLABEL_UNPROTECTED) */
#if defined(DOSBBSECTOR) && defined(notyet)
/* overwriting master boot record? */
@@ -530,7 +532,8 @@ bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel)
}
/* calculate cylinder for disksort to order transfers with */
- bp->b_cylin = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
+ bp->b_pblkno = bp->b_blkno + p->p_offset;
+ bp->b_cylin = bp->b_pblkno / lp->d_secpercyl;
return(1);
bad:
diff --git a/sys/ufs/ufs_lookup.c b/sys/ufs/ufs_lookup.c
index 06c1cb27314d..aa4c13ebfb0c 100644
--- a/sys/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs_lookup.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)ufs_lookup.c 7.33 (Berkeley) 5/19/91
- * $Id: ufs_lookup.c,v 1.6.2.1 1994/05/04 07:59:10 rgrimes Exp $
+ * $Id: ufs_lookup.c,v 1.7 1994/05/04 08:33:11 rgrimes Exp $
*/
#include "param.h"
diff --git a/sys/ufs/ufs_vfsops.c b/sys/ufs/ufs_vfsops.c
index 5eaaf387e572..d7d5de227260 100644
--- a/sys/ufs/ufs_vfsops.c
+++ b/sys/ufs/ufs_vfsops.c
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
* from: @(#)ufs_vfsops.c 7.56 (Berkeley) 6/28/91
- * $Id: ufs_vfsops.c,v 1.6.2.1 1994/05/04 07:59:13 rgrimes Exp $
+ * $Id: ufs_vfsops.c,v 1.7 1994/05/04 08:33:15 rgrimes Exp $
*/
#include "param.h"
diff --git a/sys/ufs/ufs_vnops.c b/sys/ufs/ufs_vnops.c
index 096cb1f3a338..39fad0e55885 100644
--- a/sys/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs_vnops.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)ufs_vnops.c 7.64 (Berkeley) 5/16/91
- * $Id: ufs_vnops.c,v 1.14 1994/01/19 21:09:26 jtc Exp $
+ * $Id: ufs_vnops.c,v 1.16 1994/06/12 04:05:53 davidg Exp $
*/
#include "param.h"
@@ -524,10 +524,6 @@ ufs_read(vp, uio, ioflag, cred)
return (error);
}
error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
-#if OMIT /* 20 Aug 92*/
- if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
- bp->b_flags |= B_AGE;
-#endif /* OMIT*/
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
return (error);
@@ -617,7 +613,6 @@ ufs_write(vp, uio, ioflag, cred)
if (ioflag & IO_SYNC)
(void) bwrite(bp);
else if (n + on == fs->fs_bsize) {
- bp->b_flags |= B_AGE;
bawrite(bp);
} else
bdwrite(bp);
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
index 01ce7305d5a1..12c113615ce4 100644
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -86,6 +86,7 @@ struct pagerops devicepagerops = {
dev_pager_getpage,
0,
dev_pager_putpage,
+ 0,
dev_pager_haspage
};
diff --git a/sys/vm/queue.h b/sys/vm/queue.h
index 8eaa42a0328e..7010951bbfc3 100644
--- a/sys/vm/queue.h
+++ b/sys/vm/queue.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)queue.h 7.3 (Berkeley) 4/21/91
- * $Id: queue.h,v 1.2 1993/10/16 16:20:18 rgrimes Exp $
+ * $Id: queue.h,v 1.3 1994/04/14 07:50:17 davidg Exp $
*/
/*
@@ -111,6 +111,30 @@ typedef struct queue_entry *queue_entry_t;
} \
}
+#define queue_enter_head(head, elt, type, field) { \
+ if (queue_empty((head))) { \
+ (head)->next = (queue_entry_t) elt; \
+ (head)->prev = (queue_entry_t) elt; \
+ (elt)->field.next = head; \
+ (elt)->field.prev = head; \
+ } else { \
+ register queue_entry_t next = (head)->next; \
+ (elt)->field.prev = head; \
+ (elt)->field.next = next; \
+ (head)->next = (queue_entry_t)(elt); \
+ ((type)next)->field.prev = (queue_entry_t)(elt);\
+ } \
+}
+
+/* insert 'item' after 'position' using field 'field' */
+/* XXX might be broken - BEWARE */
+#define queue_insert(position, item, type, field) { \
+ ((type) position->field.next)->field.prev = (queue_entry_t)(item); \
+ (item)->field.next = (position)->field.next; \
+ (position)->field.next = (queue_entry_t)(item); \
+ (item)->field.prev = (queue_entry_t) position; \
+}
+
#define queue_field(head, thing, type, field) \
(((head) == (thing)) ? (head) : &((type)(thing))->field)
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index bf3f38f9ce8d..e7c350b01502 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 1994 John S. Dyson
* Copyright (c) 1990 University of Utah.
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
@@ -38,7 +39,7 @@
* from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
* from: @(#)swap_pager.c 7.4 (Berkeley) 5/7/91
*
- * $Id: swap_pager.c,v 1.17.2.1 1994/03/07 02:07:06 rgrimes Exp $
+ * $Id: swap_pager.c,v 1.27 1994/05/25 11:06:48 davidg Exp $
*/
/*
@@ -68,7 +69,7 @@
#include "vm_map.h"
#ifndef NPENDINGIO
-#define NPENDINGIO 96
+#define NPENDINGIO 16
#endif
extern int nswbuf;
@@ -79,6 +80,9 @@ extern int hz;
int swap_pager_full;
extern vm_map_t pager_map;
extern int vm_pageout_pages_needed;
+extern int vm_swap_size;
+
+#define MAX_PAGEOUT_CLUSTER 8
struct swpagerclean {
queue_head_t spc_list;
@@ -86,7 +90,9 @@ struct swpagerclean {
struct buf *spc_bp;
sw_pager_t spc_swp;
vm_offset_t spc_kva;
- vm_page_t spc_m;
+ vm_offset_t spc_altkva;
+ int spc_count;
+ vm_page_t spc_m[MAX_PAGEOUT_CLUSTER];
} swcleanlist [NPENDINGIO] ;
typedef struct swpagerclean *swp_clean_t;
@@ -105,11 +111,14 @@ queue_head_t swap_pager_list; /* list of "named" anon regions */
queue_head_t swap_pager_un_list; /* list of "unnamed" anon pagers */
#define SWAP_FREE_NEEDED 0x1 /* need a swap block */
int swap_pager_needflags;
+struct rlist *swapfrag;
static queue_head_t *swp_qs[]={
&swap_pager_list, &swap_pager_un_list, (queue_head_t *) 0
};
+int swap_pager_putmulti();
+
struct pagerops swappagerops = {
swap_pager_init,
swap_pager_alloc,
@@ -117,6 +126,7 @@ struct pagerops swappagerops = {
swap_pager_getpage,
swap_pager_getmulti,
swap_pager_putpage,
+ swap_pager_putmulti,
swap_pager_haspage
};
@@ -132,10 +142,18 @@ extern int vm_page_count;
struct buf * getpbuf() ;
void relpbuf(struct buf *bp) ;
+static inline void swapsizecheck() {
+ if( vm_swap_size < 128*btodb(NBPG)) {
+ if( swap_pager_full)
+ printf("swap_pager: out of space\n");
+ swap_pager_full = 1;
+ } else if( vm_swap_size > 192*btodb(NBPG))
+ swap_pager_full = 0;
+}
+
void
swap_pager_init()
{
- register int i;
extern int dmmin, dmmax;
dfltpagerops = &swappagerops;
@@ -189,7 +207,7 @@ swap_pager_alloc(handle, size, prot, offset)
if (!spc->spc_kva) {
break;
}
- spc->spc_bp = malloc(sizeof( *bp), M_TEMP,
+ spc->spc_bp = malloc( sizeof( *bp), M_TEMP,
M_NOWAIT);
if (!spc->spc_bp) {
kmem_free_wakeup(pager_map, spc->spc_kva, NBPG);
@@ -199,6 +217,8 @@ swap_pager_alloc(handle, size, prot, offset)
queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
}
require_swap_init = 0;
+ if( size == 0)
+ return(NULL);
}
/*
@@ -219,8 +239,9 @@ swap_pager_alloc(handle, size, prot, offset)
}
}
- if (swap_pager_full)
+ if (swap_pager_full) {
return(NULL);
+ }
/*
* Pager doesn't exist, allocate swap management resources
@@ -246,10 +267,10 @@ swap_pager_alloc(handle, size, prot, offset)
free((caddr_t)pager, M_VMPAGER);
return(NULL);
}
- bzero((caddr_t)swp->sw_blocks,
- swp->sw_nblocks * sizeof(*swp->sw_blocks));
for (i = 0; i < swp->sw_nblocks; i++) {
+ swp->sw_blocks[i].swb_valid = 0;
+ swp->sw_blocks[i].swb_locked = 0;
for (j = 0; j < SWB_NPAGES; j++)
swp->sw_blocks[i].swb_block[j] = SWB_EMPTY;
}
@@ -336,30 +357,87 @@ swap_pager_setvalid(swp, offset, valid)
}
/*
+ * this routine allocates swap space with a fragmentation
+ * minimization policy.
+ */
+int
+swap_pager_getswapspace( unsigned amount, unsigned *rtval) {
+ unsigned tmpalloc;
+ unsigned nblocksfrag = btodb(SWB_NPAGES*NBPG);
+ if( amount < nblocksfrag) {
+ if( rlist_alloc(&swapfrag, amount, rtval))
+ return 1;
+ if( !rlist_alloc(&swapmap, nblocksfrag, &tmpalloc))
+ return 0;
+ rlist_free( &swapfrag, tmpalloc+amount, tmpalloc + nblocksfrag - 1);
+ *rtval = tmpalloc;
+ return 1;
+ }
+ if( !rlist_alloc(&swapmap, amount, rtval))
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * this routine frees swap space with a fragmentation
+ * minimization policy.
+ */
+void
+swap_pager_freeswapspace( unsigned from, unsigned to) {
+ unsigned nblocksfrag = btodb(SWB_NPAGES*NBPG);
+ unsigned tmpalloc;
+ if( ((to + 1) - from) >= nblocksfrag) {
+ while( (from + nblocksfrag) <= to + 1) {
+ rlist_free(&swapmap, from, from + nblocksfrag - 1);
+ from += nblocksfrag;
+ }
+ }
+ if( from >= to)
+ return;
+ rlist_free(&swapfrag, from, to);
+ while( rlist_alloc(&swapfrag, nblocksfrag, &tmpalloc)) {
+ rlist_free(&swapmap, tmpalloc, tmpalloc + nblocksfrag-1);
+ }
+}
+/*
* this routine frees swap blocks from a specified pager
*/
void
-swap_pager_freespace(pager, start, size)
- vm_pager_t pager;
+_swap_pager_freespace(swp, start, size)
+ sw_pager_t swp;
vm_offset_t start;
vm_offset_t size;
{
- sw_pager_t swp = (sw_pager_t) pager->pg_data;
vm_offset_t i;
int s;
s = splbio();
for (i = start; i < round_page(start + size - 1); i += NBPG) {
- int *addr = swap_pager_diskaddr(swp, i, 0);
+ int valid;
+ int *addr = swap_pager_diskaddr(swp, i, &valid);
if (addr && *addr != SWB_EMPTY) {
- rlist_free(&swapmap, *addr, *addr + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(*addr, *addr+btodb(NBPG) - 1);
+ if( valid) {
+ vm_swap_size += btodb(NBPG);
+ swap_pager_setvalid(swp, i, 0);
+ }
*addr = SWB_EMPTY;
- swap_pager_full = 0;
}
}
+ swapsizecheck();
splx(s);
}
+void
+swap_pager_freespace(pager, start, size)
+ vm_pager_t pager;
+ vm_offset_t start;
+ vm_offset_t size;
+{
+ _swap_pager_freespace((sw_pager_t) pager->pg_data, start, size);
+}
+
/*
* swap_pager_reclaim frees up over-allocated space from all pagers
* this eliminates internal fragmentation due to allocation of space
@@ -410,6 +488,8 @@ swap_pager_reclaim()
swp = (sw_pager_t) p->pg_data;
for (i = 0; i < swp->sw_nblocks; i++) {
sw_blk_t swb = &swp->sw_blocks[i];
+ if( swb->swb_locked)
+ continue;
for (j = 0; j < SWB_NPAGES; j++) {
if (swb->swb_block[j] != SWB_EMPTY &&
(swb->swb_valid & (1 << j)) == 0) {
@@ -430,9 +510,9 @@ rfinished:
* free the blocks that have been added to the reclaim list
*/
for (i = 0; i < reclaimcount; i++) {
- rlist_free(&swapmap, reclaims[i], reclaims[i] + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(reclaims[i], reclaims[i]+btodb(NBPG) - 1);
+ swapsizecheck();
wakeup((caddr_t) &in_reclaim);
- swap_pager_full = 0;
}
splx(s);
@@ -480,7 +560,7 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset)
/*
* clean all of the pages that are currently active and finished
*/
- (void) swap_pager_clean(NULL, B_WRITE);
+ (void) swap_pager_clean();
s = splbio();
/*
@@ -488,11 +568,14 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset)
* (release allocated space)
*/
for (i = 0; i < offset + srcoffset; i += NBPG) {
- int *addr = swap_pager_diskaddr(srcswp, i, 0);
+ int valid;
+ int *addr = swap_pager_diskaddr(srcswp, i, &valid);
if (addr && *addr != SWB_EMPTY) {
- rlist_free(&swapmap, *addr, *addr + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(*addr, *addr+btodb(NBPG) - 1);
+ if( valid)
+ vm_swap_size += btodb(NBPG);
+ swapsizecheck();
*addr = SWB_EMPTY;
- swap_pager_full = 0;
}
}
/*
@@ -518,23 +601,24 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset)
* source block without copying.
*/
if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) {
- rlist_free(&swapmap, *dstaddrp, *dstaddrp + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(*dstaddrp, *dstaddrp+btodb(NBPG) - 1);
*dstaddrp = SWB_EMPTY;
- swap_pager_full = 0;
}
if (dstaddrp && *dstaddrp == SWB_EMPTY) {
*dstaddrp = *srcaddrp;
*srcaddrp = SWB_EMPTY;
swap_pager_setvalid(dstswp, i + dstoffset, 1);
- }
- }
+ vm_swap_size -= btodb(NBPG);
+ }
+ }
/*
* if the source is not empty at this point, then deallocate the space.
*/
if (*srcaddrp != SWB_EMPTY) {
- rlist_free(&swapmap, *srcaddrp, *srcaddrp + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(NBPG) - 1);
+ if( srcvalid)
+ vm_swap_size += btodb(NBPG);
*srcaddrp = SWB_EMPTY;
- swap_pager_full = 0;
}
}
}
@@ -543,14 +627,17 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset)
* deallocate the rest of the source object
*/
for (i = dstswp->sw_osize + offset + srcoffset; i < srcswp->sw_osize; i += NBPG) {
- int *srcaddrp = swap_pager_diskaddr(srcswp, i, 0);
+ int valid;
+ int *srcaddrp = swap_pager_diskaddr(srcswp, i, &valid);
if (srcaddrp && *srcaddrp != SWB_EMPTY) {
- rlist_free(&swapmap, *srcaddrp, *srcaddrp + btodb(NBPG) - 1);
+ swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(NBPG) - 1);
+ if( valid)
+ vm_swap_size += btodb(NBPG);
*srcaddrp = SWB_EMPTY;
- swap_pager_full = 0;
}
}
+ swapsizecheck();
splx(s);
free((caddr_t)srcswp->sw_blocks, M_VMPGDATA);
@@ -595,7 +682,7 @@ swap_pager_dealloc(pager)
splx(s);
- (void) swap_pager_clean(NULL, B_WRITE);
+ (void) swap_pager_clean();
/*
* Free left over swap blocks
@@ -604,13 +691,15 @@ swap_pager_dealloc(pager)
for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) {
for (j = 0; j < SWB_NPAGES; j++)
if (bp->swb_block[j] != SWB_EMPTY) {
- rlist_free(&swapmap, (unsigned)bp->swb_block[j],
+ swap_pager_freeswapspace((unsigned)bp->swb_block[j],
(unsigned)bp->swb_block[j] + btodb(NBPG) - 1);
+ if( bp->swb_valid & (1<<j))
+ vm_swap_size += btodb(NBPG);
bp->swb_block[j] = SWB_EMPTY;
- swap_pager_full = 0;
}
}
splx(s);
+ swapsizecheck();
/*
* Free swap management resources
@@ -633,7 +722,9 @@ swap_pager_getmulti(pager, m, count, reqpage, sync)
int reqpage;
boolean_t sync;
{
- return swap_pager_io((sw_pager_t) pager->pg_data, m, count, reqpage, B_READ);
+ if( reqpage >= count)
+ panic("swap_pager_getmulti: reqpage >= count\n");
+ return swap_pager_input((sw_pager_t) pager->pg_data, m, count, reqpage);
}
/*
@@ -648,7 +739,29 @@ swap_pager_getpage(pager, m, sync)
vm_page_t marray[1];
marray[0] = m;
- return swap_pager_io((sw_pager_t)pager->pg_data, marray, 1, 0, B_READ);
+ return swap_pager_input((sw_pager_t)pager->pg_data, marray, 1, 0);
+}
+
+int
+swap_pager_putmulti(pager, m, c, sync, rtvals)
+ vm_pager_t pager;
+ vm_page_t *m;
+ int c;
+ boolean_t sync;
+ int *rtvals;
+{
+ int flags;
+
+ if (pager == NULL) {
+ (void) swap_pager_clean();
+ return VM_PAGER_OK;
+ }
+
+ flags = B_WRITE;
+ if (!sync)
+ flags |= B_ASYNC;
+
+ return swap_pager_output((sw_pager_t)pager->pg_data, m, c, flags, rtvals);
}
/*
@@ -662,10 +775,11 @@ swap_pager_putpage(pager, m, sync)
{
int flags;
vm_page_t marray[1];
+ int rtvals[1];
if (pager == NULL) {
- (void) swap_pager_clean(NULL, B_WRITE);
+ (void) swap_pager_clean();
return VM_PAGER_OK;
}
@@ -673,11 +787,14 @@ swap_pager_putpage(pager, m, sync)
flags = B_WRITE;
if (!sync)
flags |= B_ASYNC;
- return(swap_pager_io((sw_pager_t)pager->pg_data, marray, 1, 0, flags));
+
+ swap_pager_output((sw_pager_t)pager->pg_data, marray, 1, flags, rtvals);
+
+ return rtvals[0];
}
static inline int
-swap_pager_block_index(swp, offset)
+const swap_pager_block_index(swp, offset)
sw_pager_t swp;
vm_offset_t offset;
{
@@ -685,11 +802,11 @@ swap_pager_block_index(swp, offset)
}
static inline int
-swap_pager_block_offset(swp, offset)
+const swap_pager_block_offset(swp, offset)
sw_pager_t swp;
vm_offset_t offset;
{
- return (offset % (SWB_NPAGES*NBPG));
+ return ((offset % (NBPG*SWB_NPAGES)) / NBPG);
}
/*
@@ -755,8 +872,6 @@ swap_pager_ridpages(m, count, reqpage)
int reqpage;
{
int i;
- int s;
-
for (i = 0; i < count; i++)
if (i != reqpage)
swap_pager_freepage(m[i]);
@@ -774,35 +889,33 @@ swap_pager_iodone1(bp)
bp->b_flags |= B_DONE;
bp->b_flags &= ~B_ASYNC;
wakeup((caddr_t)bp);
+/*
if ((bp->b_flags & B_READ) == 0)
vwakeup(bp);
+*/
}
-/*
- * Scaled down version of swap().
- * BOGUS: lower level IO routines expect a KVA so we have to map our
- * provided physical page into the KVA to keep them happy.
- */
+
+
int
-swap_pager_io(swp, m, count, reqpage, flags)
+swap_pager_input(swp, m, count, reqpage)
register sw_pager_t swp;
vm_page_t *m;
int count, reqpage;
- int flags;
{
register struct buf *bp;
- register sw_blk_t swb;
+ sw_blk_t swb[count];
register int s;
- int i, ix;
+ int i;
boolean_t rv;
- vm_offset_t kva, off;
+ vm_offset_t kva, off[count];
swp_clean_t spc;
- int cluster;
vm_offset_t paging_offset;
vm_object_t object;
- int reqaddr, mydskregion;
- extern int dmmin, dmmax;
+ int reqaddr[count];
- spc = NULL;
+ int first, last;
+ int failed;
+ int reqdskregion;
object = m[reqpage]->object;
paging_offset = object->paging_offset;
@@ -812,89 +925,89 @@ swap_pager_io(swp, m, count, reqpage, flags)
* following shadow chains looking for the top level object
* with the page.
*/
- off = m[reqpage]->offset + paging_offset;
- ix = swap_pager_block_index(swp, off);
- if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
- /* printf("swap pager: out of range\n"); */
+ if (swp->sw_blocks == NULL) {
swap_pager_ridpages(m, count, reqpage);
return(VM_PAGER_FAIL);
}
+
+ for(i = 0; i < count; i++) {
+ vm_offset_t foff = m[i]->offset + paging_offset;
+ int ix = swap_pager_block_index(swp, foff);
+ if (ix >= swp->sw_nblocks) {
+ int j;
+ if( i <= reqpage) {
+ swap_pager_ridpages(m, count, reqpage);
+ return(VM_PAGER_FAIL);
+ }
+ for(j = i; j < count; j++) {
+ swap_pager_freepage(m[j]);
+ }
+ count = i;
+ break;
+ }
+ swb[i] = &swp->sw_blocks[ix];
+ off[i] = swap_pager_block_offset(swp, foff);
+ reqaddr[i] = swb[i]->swb_block[off[i]];
+ }
- swb = &swp->sw_blocks[ix];
- off = swap_pager_block_offset(swp, off) / NBPG;
- reqaddr = swb->swb_block[off];
-
- /* make sure that our I/O request is contiguous */
- if (flags & B_READ) {
- int first = 0, last = count;
- int failed = 0;
- int reqdskregion = reqaddr / dmmax;
- int valid;
+ /* make sure that our required input request is existant */
- if (reqaddr == SWB_EMPTY ||
- (swb->swb_valid & (1 << off)) == 0) {
- swap_pager_ridpages(m, count, reqpage);
- return(VM_PAGER_FAIL);
- }
-
- /*
- * search backwards for the first contiguous page to transfer
- */
- for (i = reqpage - 1; i >= 0; --i) {
- int *tmpaddr = swap_pager_diskaddr(swp,
- m[i]->offset + paging_offset,&valid);
- if (tmpaddr == 0 || failed || !valid ||
- *tmpaddr != reqaddr + btodb((i - reqpage) * NBPG)) {
+ if (reqaddr[reqpage] == SWB_EMPTY ||
+ (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) {
+ swap_pager_ridpages(m, count, reqpage);
+ return(VM_PAGER_FAIL);
+ }
+
+
+ reqdskregion = reqaddr[reqpage] / dmmax;
+
+ /*
+ * search backwards for the first contiguous page to transfer
+ */
+ failed = 0;
+ first = 0;
+ for (i = reqpage - 1; i >= 0; --i) {
+ if ( failed || (reqaddr[i] == SWB_EMPTY) ||
+ (swb[i]->swb_valid & (1 << off[i])) == 0 ||
+ (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(NBPG))) ||
+ ((reqaddr[i] / dmmax) != reqdskregion)) {
failed = 1;
swap_pager_freepage(m[i]);
- m[i] = 0;
if (first == 0)
first = i + 1;
- } else {
- mydskregion = *tmpaddr / dmmax;
- if (mydskregion != reqdskregion) {
- failed = 1;
- swap_pager_freepage(m[i]);
- m[i] = 0;
- first = i + 1;
- }
- }
- }
- /*
- * search forwards for the last contiguous page to transfer
- */
- failed = 0;
- for (i = reqpage + 1; i < count; i++) {
- int *tmpaddr = swap_pager_diskaddr(swp, m[i]->offset + paging_offset,&valid);
- if (tmpaddr == 0 || failed || !valid ||
- *tmpaddr != reqaddr + btodb((i - reqpage) * NBPG) ) {
+ }
+ }
+ /*
+ * search forwards for the last contiguous page to transfer
+ */
+ failed = 0;
+ last = count;
+ for (i = reqpage + 1; i < count; i++) {
+ if ( failed || (reqaddr[i] == SWB_EMPTY) ||
+ (swb[i]->swb_valid & (1 << off[i])) == 0 ||
+ (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(NBPG))) ||
+ ((reqaddr[i] / dmmax) != reqdskregion)) {
failed = 1;
swap_pager_freepage(m[i]);
- m[i] = 0;
if (last == count)
last = i;
- } else {
- mydskregion = *tmpaddr / dmmax;
- if (mydskregion != reqdskregion) {
- failed = 1;
- swap_pager_freepage(m[i]);
- m[i] = 0;
- if (last == count)
- last = i;
- }
- }
- }
- count = last;
- if (first != 0) {
- for (i = first; i < count; i++) {
- m[i - first] = m[i];
- }
- count -= first;
- reqpage -= first;
+ }
+ }
+
+ count = last;
+ if (first != 0) {
+ for (i = first; i < count; i++) {
+ m[i-first] = m[i];
+ reqaddr[i-first] = reqaddr[i];
+ off[i-first] = off[i];
}
+ count -= first;
+ reqpage -= first;
}
+ ++swb[reqpage]->swb_locked;
+
/*
* at this point:
* "m" is a pointer to the array of vm_page_t for paging I/O
@@ -903,24 +1016,6 @@ swap_pager_io(swp, m, count, reqpage, flags)
* "reqpage" is the index into "m" for the page actually faulted
*/
- /*
- * For reads (pageins) and synchronous writes, we clean up
- * all completed async pageouts.
- */
- if ((flags & B_ASYNC) == 0) {
- swap_pager_clean(NULL, flags);
- }
- /*
- * For async writes (pageouts), we cleanup completed pageouts so
- * that all available resources are freed. Also tells us if this
- * page is already being cleaned. If it is, or no resources
- * are available, we try again later.
- */
- else if (swap_pager_clean(m[reqpage], B_WRITE)) {
- swap_pager_ridpages(m, count, reqpage);
- return VM_PAGER_TRYAGAIN;
- }
-
spc = NULL; /* we might not use an spc data structure */
kva = 0;
@@ -929,44 +1024,38 @@ swap_pager_io(swp, m, count, reqpage, flags)
* but for transfers == 1 page, the swap_pager_free list contains
* entries that have pre-allocated kva's (for efficiency).
*/
- if ((flags & B_READ) && count > 1) {
+ if (count > 1) {
kva = kmem_alloc_pageable(pager_map, count*NBPG);
}
-
+
if (!kva) {
/*
* if a kva has not been allocated, we can only do a one page transfer,
- * so we free the other pages that might have been allocated by vm_fault.
+ * so we free the other pages that might have been allocated by
+ * vm_fault.
*/
- for (i = 0; i < count; i++) {
- if (i != reqpage) {
- swap_pager_freepage(m[i]);
- m[i] = 0;
- }
- }
- count = 1;
+ swap_pager_ridpages(m, count, reqpage);
m[0] = m[reqpage];
+ reqaddr[0] = reqaddr[reqpage];
+
+ count = 1;
reqpage = 0;
/*
* get a swap pager clean data structure, block until we get it
*/
if (queue_empty(&swap_pager_free)) {
-/*
- if ((flags & (B_ASYNC|B_READ)) == B_ASYNC)
- return VM_PAGER_TRYAGAIN;
-*/
s = splbio();
if( curproc == pageproc)
- (void) swap_pager_clean(NULL, B_WRITE);
+ (void) swap_pager_clean();
else
wakeup((caddr_t) &vm_pages_needed);
while (queue_empty(&swap_pager_free)) {
swap_pager_needflags |= SWAP_FREE_NEEDED;
tsleep((caddr_t)&swap_pager_free,
PVM, "swpfre", 0);
- if (curproc == pageproc)
- (void) swap_pager_clean(NULL, B_WRITE);
+ if( curproc == pageproc)
+ (void) swap_pager_clean();
else
wakeup((caddr_t) &vm_pages_needed);
}
@@ -978,35 +1067,214 @@ swap_pager_io(swp, m, count, reqpage, flags)
/*
- * Determine swap block and allocate as necessary.
- * We try to get SWB_NPAGES first, but then we punt and try
- * to get one page. If that fails, we look at the allocation
- * data structures to find unused but allocated pages in other
- * pagers allocations.
+ * map our page(s) into kva for input
*/
- if (reqaddr == SWB_EMPTY) {
- int blk;
- int tries;
- int ntoget;
+ for (i = 0; i < count; i++) {
+ pmap_kenter( kva + NBPG * i, VM_PAGE_TO_PHYS(m[i]));
+ }
+ pmap_update();
+
- tries = 0;
- s = splbio();
+ /*
+ * Get a swap buffer header and perform the IO
+ */
+ if( spc) {
+ bp = spc->spc_bp;
+ bzero(bp, sizeof *bp);
+ bp->b_spc = spc;
+ } else {
+ bp = getpbuf();
+ }
+
+ s = splbio();
+ bp->b_flags = B_BUSY | B_READ | B_CALL;
+ bp->b_iodone = swap_pager_iodone1;
+ bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ bp->b_un.b_addr = (caddr_t) kva;
+ bp->b_blkno = reqaddr[0];
+ bp->b_bcount = NBPG*count;
+ bp->b_bufsize = NBPG*count;
+
+ VHOLD(swapdev_vp);
+ bp->b_vp = swapdev_vp;
+ if (swapdev_vp->v_type == VBLK)
+ bp->b_dev = swapdev_vp->v_rdev;
+
+ swp->sw_piip++;
+
+ /*
+ * perform the I/O
+ */
+ VOP_STRATEGY(bp);
+
+ /*
+ * wait for the sync I/O to complete
+ */
+ while ((bp->b_flags & B_DONE) == 0) {
+ tsleep((caddr_t)bp, PVM, "swread", 0);
+ }
+ rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
+ bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE);
+
+ --swp->sw_piip;
+ if (swp->sw_piip == 0)
+ wakeup((caddr_t) swp);
+
+ if (bp->b_vp)
+ brelvp(bp);
+
+ splx(s);
+ --swb[reqpage]->swb_locked;
+
+ /*
+ * remove the mapping for kernel virtual
+ */
+ pmap_remove(vm_map_pmap(pager_map), kva, kva + count * NBPG);
+
+ if (spc) {
/*
- * if any other pages have been allocated in this block, we
- * only try to get one page.
+ * if we have used an spc, we need to free it.
*/
- for (i = 0; i < SWB_NPAGES; i++) {
- if (swb->swb_block[i] != SWB_EMPTY)
- break;
+ queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
+ if (swap_pager_needflags & SWAP_FREE_NEEDED) {
+ swap_pager_needflags &= ~SWAP_FREE_NEEDED;
+ wakeup((caddr_t)&swap_pager_free);
}
+ } else {
+ /*
+ * free the kernel virtual addresses
+ */
+ kmem_free_wakeup(pager_map, kva, count * NBPG);
+ /*
+ * release the physical I/O buffer
+ */
+ relpbuf(bp);
+ /*
+ * finish up input if everything is ok
+ */
+ if( rv == VM_PAGER_OK) {
+ for (i = 0; i < count; i++) {
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
+ m[i]->flags |= PG_CLEAN;
+ m[i]->flags &= ~PG_LAUNDRY;
+ if (i != reqpage) {
+ /*
+ * whether or not to leave the page activated
+ * is up in the air, but we should put the page
+ * on a page queue somewhere. (it already is in
+ * the object).
+ * After some emperical results, it is best
+ * to deactivate the readahead pages.
+ */
+ vm_page_deactivate(m[i]);
+
+ /*
+ * just in case someone was asking for this
+ * page we now tell them that it is ok to use
+ */
+ m[i]->flags &= ~PG_FAKE;
+ PAGE_WAKEUP(m[i]);
+ }
+ }
+ if( swap_pager_full) {
+ _swap_pager_freespace( swp, m[0]->offset+paging_offset, count*NBPG);
+ }
+ } else {
+ swap_pager_ridpages(m, count, reqpage);
+ }
+ }
+ return(rv);
+}
+
+int
+swap_pager_output(swp, m, count, flags, rtvals)
+ register sw_pager_t swp;
+ vm_page_t *m;
+ int count;
+ int flags;
+ int *rtvals;
+{
+ register struct buf *bp;
+ sw_blk_t swb[count];
+ register int s;
+ int i, j, ix;
+ boolean_t rv;
+ vm_offset_t kva, off, foff;
+ swp_clean_t spc;
+ vm_offset_t paging_offset;
+ vm_object_t object;
+ int reqaddr[count];
+ int failed;
- ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1;
+/*
+ if( count > 1)
+ printf("off: 0x%x, count: %d\n", m[0]->offset, count);
+*/
+ spc = NULL;
+
+ object = m[0]->object;
+ paging_offset = object->paging_offset;
+
+ failed = 0;
+ for(j=0;j<count;j++) {
+ foff = m[j]->offset + paging_offset;
+ ix = swap_pager_block_index(swp, foff);
+ swb[j] = 0;
+ if( swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
+ rtvals[j] = VM_PAGER_FAIL;
+ failed = 1;
+ continue;
+ } else {
+ rtvals[j] = VM_PAGER_OK;
+ }
+ swb[j] = &swp->sw_blocks[ix];
+ ++swb[j]->swb_locked;
+ if( failed) {
+ rtvals[j] = VM_PAGER_FAIL;
+ continue;
+ }
+ off = swap_pager_block_offset(swp, foff);
+ reqaddr[j] = swb[j]->swb_block[off];
+ if( reqaddr[j] == SWB_EMPTY) {
+ int blk;
+ int tries;
+ int ntoget;
+ tries = 0;
+ s = splbio();
+
+ /*
+ * if any other pages have been allocated in this block, we
+ * only try to get one page.
+ */
+ for (i = 0; i < SWB_NPAGES; i++) {
+ if (swb[j]->swb_block[i] != SWB_EMPTY)
+ break;
+ }
+
+
+ ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1;
+ /*
+ * this code is alittle conservative, but works
+ * (the intent of this code is to allocate small chunks
+ * for small objects)
+ */
+ if( (m[j]->offset == 0) && (ntoget*NBPG > object->size)) {
+ ntoget = (object->size + (NBPG-1))/NBPG;
+ }
+
retrygetspace:
- if (ntoget == SWB_NPAGES &&
- rlist_alloc(&swapmap, btodb(ntoget * NBPG),&blk)) {
- for (i = 0; i < ntoget; i++)
- swb->swb_block[i] = blk + btodb(NBPG) * i;
- } else if (!rlist_alloc(&swapmap, btodb(NBPG), &swb->swb_block[off])) {
+ if (!swap_pager_full && ntoget > 1 &&
+ swap_pager_getswapspace(ntoget * btodb(NBPG), &blk)) {
+
+ for (i = 0; i < ntoget; i++) {
+ swb[j]->swb_block[i] = blk + btodb(NBPG) * i;
+ swb[j]->swb_valid = 0;
+ }
+
+ reqaddr[j] = swb[j]->swb_block[off];
+ } else if (!swap_pager_getswapspace(btodb(NBPG),
+ &swb[j]->swb_block[off])) {
/*
* if the allocation has failed, we try to reclaim space and
* retry.
@@ -1015,74 +1283,183 @@ retrygetspace:
swap_pager_reclaim();
goto retrygetspace;
}
- /*
- * here on swap space full.
- */
- if (spc)
- queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
- if (swap_pager_full == 0)
- printf("swap_pager: out of swap space !!!\n");
- swap_pager_full = 1;
- swap_pager_ridpages(m, count, reqpage);
- splx(s);
- return(VM_PAGER_TRYAGAIN);
+ rtvals[j] = VM_PAGER_TRYAGAIN;
+ failed = 1;
+ } else {
+ reqaddr[j] = swb[j]->swb_block[off];
+ swb[j]->swb_valid &= ~(1<<off);
+ }
+ splx(s);
+ }
+ }
+
+ /*
+ * search forwards for the last contiguous page to transfer
+ */
+ failed = 0;
+ for (i = 0; i < count; i++) {
+ if( failed || (reqaddr[i] != reqaddr[0] + i*btodb(NBPG)) ||
+ (reqaddr[i] / dmmax) != (reqaddr[0] / dmmax) ||
+ (rtvals[i] != VM_PAGER_OK)) {
+ failed = 1;
+ if( rtvals[i] == VM_PAGER_OK)
+ rtvals[i] = VM_PAGER_TRYAGAIN;
+ }
+ }
+
+ for(i = 0; i < count; i++) {
+ if( rtvals[i] != VM_PAGER_OK) {
+ if( swb[i])
+ --swb[i]->swb_locked;
+ }
+ }
+
+ for(i = 0; i < count; i++)
+ if( rtvals[i] != VM_PAGER_OK)
+ break;
+
+ if( i == 0) {
+ return VM_PAGER_TRYAGAIN;
+ }
+
+ count = i;
+ for(i=0;i<count;i++) {
+ if( reqaddr[i] == SWB_EMPTY)
+ printf("I/O to empty block????\n");
+ }
+
+ /*
+ */
+
+ /*
+ * For synchronous writes, we clean up
+ * all completed async pageouts.
+ */
+ if ((flags & B_ASYNC) == 0) {
+ swap_pager_clean();
+ }
+
+ kva = 0;
+
+ /*
+ * we allocate a new kva for transfers > 1 page
+ * but for transfers == 1 page, the swap_pager_free list contains
+ * entries that have pre-allocated kva's (for efficiency).
+ */
+ if ( count > 1) {
+ kva = kmem_alloc_pageable(pager_map, count*NBPG);
+ if( !kva) {
+ for (i = 0; i < count; i++) {
+ if( swb[i])
+ --swb[i]->swb_locked;
+ rtvals[i] = VM_PAGER_TRYAGAIN;
+ }
+ return VM_PAGER_TRYAGAIN;
+ }
+ }
+
+ /*
+ * get a swap pager clean data structure, block until we get it
+ */
+ if (queue_empty(&swap_pager_free)) {
+/*
+ if (flags & B_ASYNC) {
+ for(i=0;i<count;i++) {
+ rtvals[i] = VM_PAGER_TRYAGAIN;
+ if( swb[i])
+ --swb[i]->swb_locked;
+ }
+ return VM_PAGER_TRYAGAIN;
+ }
+*/
+
+ s = splbio();
+ if( curproc == pageproc)
+ (void) swap_pager_clean();
+ else
+ wakeup((caddr_t) &vm_pages_needed);
+ while (queue_empty(&swap_pager_free)) {
+ swap_pager_needflags |= SWAP_FREE_NEEDED;
+ tsleep((caddr_t)&swap_pager_free,
+ PVM, "swpfre", 0);
+ if( curproc == pageproc)
+ (void) swap_pager_clean();
+ else
+ wakeup((caddr_t) &vm_pages_needed);
}
splx(s);
- swap_pager_full = 0;
+ }
+
+ queue_remove_first(&swap_pager_free, spc, swp_clean_t, spc_list);
+ if( !kva) {
+ kva = spc->spc_kva;
+ spc->spc_altkva = 0;
+ } else {
+ spc->spc_altkva = kva;
}
/*
* map our page(s) into kva for I/O
*/
for (i = 0; i < count; i++) {
- pmap_enter(vm_map_pmap(pager_map), kva + NBPG * i,
- VM_PAGE_TO_PHYS(m[i]), VM_PROT_ALL, TRUE);
+ pmap_kenter( kva + NBPG * i, VM_PAGE_TO_PHYS(m[i]));
}
-
+ pmap_update();
/*
* get the base I/O offset into the swap file
*/
- off = swap_pager_block_offset(swp, m[0]->offset + paging_offset) / NBPG;
-
-#ifdef DEBUG
- if (flags & B_READ && count > 1)
- printf("obj: 0x%x off: 0x%x poff: 0x%x off: 0x%x, sz: %d blk: %d op: %s\n",
- object, m[0]->offset, paging_offset, off, count, swb->swb_block[off], flags&B_READ?"r":"w");
-#endif
+ for(i=0;i<count;i++) {
+ foff = m[i]->offset + paging_offset;
+ off = swap_pager_block_offset(swp, foff);
+ /*
+ * if we are setting the valid bit anew,
+ * then diminish the swap free space
+ */
+ if( (swb[i]->swb_valid & (1 << off)) == 0)
+ vm_swap_size -= btodb(NBPG);
+
+ /*
+ * set the valid bit
+ */
+ swb[i]->swb_valid |= (1 << off);
+ /*
+ * and unlock the data structure
+ */
+ --swb[i]->swb_locked;
+ }
s = splbio();
/*
* Get a swap buffer header and perform the IO
*/
- if (spc) {
- bp = spc->spc_bp;
- bzero(bp, sizeof *bp);
- bp->b_spc = spc;
- } else {
- bp = getpbuf();
- }
- bp->b_flags = B_BUSY | (flags & B_READ);
+ bp = spc->spc_bp;
+ bzero(bp, sizeof *bp);
+ bp->b_spc = spc;
+
+ bp->b_flags = B_BUSY;
bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */
bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
bp->b_un.b_addr = (caddr_t) kva;
- bp->b_blkno = swb->swb_block[off];
+ bp->b_blkno = reqaddr[0];
VHOLD(swapdev_vp);
bp->b_vp = swapdev_vp;
if (swapdev_vp->v_type == VBLK)
bp->b_dev = swapdev_vp->v_rdev;
bp->b_bcount = NBPG*count;
- if ((bp->b_flags & B_READ) == 0)
- swapdev_vp->v_numoutput++;
+ bp->b_bufsize = NBPG*count;
+ swapdev_vp->v_numoutput++;
/*
* If this is an async write we set up additional buffer fields
* and place a "cleaning" entry on the inuse queue.
*/
- if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
+ if ( flags & B_ASYNC ) {
spc->spc_flags = 0;
spc->spc_swp = swp;
- spc->spc_m = m[reqpage];
+ for(i=0;i<count;i++)
+ spc->spc_m[i] = m[i];
+ spc->spc_count = count;
/*
* the completion routine for async writes
*/
@@ -1092,27 +1469,8 @@ retrygetspace:
bp->b_dirtyend = bp->b_bcount;
swp->sw_poip++;
queue_enter(&swap_pager_inuse, spc, swp_clean_t, spc_list);
- /*
- * we remember that we have used a block for paging.
- */
- swb->swb_valid |= (1 << off);
} else {
- /*
- * here for sync write or any read
- */
- if ((flags & B_READ) == 0) {
- /*
- * if we are writing, we remember that we have
- * actually used a block for paging.
- */
- swb->swb_valid |= (1 << off);
- swp->sw_poip++;
- } else {
- swp->sw_piip++;
- }
- /*
- * the completion routine for reads and sync writes
- */
+ swp->sw_poip++;
bp->b_flags |= B_CALL;
bp->b_iodone = swap_pager_iodone1;
}
@@ -1122,40 +1480,31 @@ retrygetspace:
VOP_STRATEGY(bp);
if ((flags & (B_READ|B_ASYNC)) == B_ASYNC ) {
if ((bp->b_flags & B_DONE) == B_DONE) {
- swap_pager_clean(NULL, flags);
+ swap_pager_clean();
}
splx(s);
- return(VM_PAGER_PEND);
+ for(i=0;i<count;i++) {
+ rtvals[i] = VM_PAGER_PEND;
+ }
+ return VM_PAGER_PEND;
}
/*
* wait for the sync I/O to complete
*/
while ((bp->b_flags & B_DONE) == 0) {
- tsleep((caddr_t)bp, PVM, (flags & B_READ)?"swread":"swwrt", 0);
+ tsleep((caddr_t)bp, PVM, "swwrt", 0);
}
rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE);
- if (bp->b_flags & B_READ) {
- --swp->sw_piip;
- if (swp->sw_piip == 0)
- wakeup((caddr_t) swp);
- } else {
- --swp->sw_poip;
- if (swp->sw_poip == 0)
- wakeup((caddr_t) swp);
- }
+ --swp->sw_poip;
+ if (swp->sw_poip == 0)
+ wakeup((caddr_t) swp);
if (bp->b_vp)
brelvp(bp);
- /*
- * release the physical I/O buffer
- */
- if (!spc)
- relpbuf(bp);
-
splx(s);
/*
@@ -1167,59 +1516,42 @@ retrygetspace:
* if we have written the page, then indicate that the page
* is clean.
*/
- if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
- m[reqpage]->flags |= PG_CLEAN;
- pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage]));
- /*
- * optimization, if a page has been read during the
- * pageout process, we activate it.
- */
- if ( (m[reqpage]->flags & PG_ACTIVE) == 0 &&
- pmap_is_referenced(VM_PAGE_TO_PHYS(m[reqpage])))
- vm_page_activate(m[reqpage]);
- }
-
- if (spc) {
- /*
- * if we have used an spc, we need to free it.
- */
- queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
- } else {
- for (i = 0; i < count; i++) {
- pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
- m[i]->flags |= PG_CLEAN;
- m[i]->flags &= ~PG_LAUNDRY;
- if (i != reqpage) {
+ if (rv == VM_PAGER_OK) {
+ for(i=0;i<count;i++) {
+ if( rtvals[i] == VM_PAGER_OK) {
+ m[i]->flags |= PG_CLEAN;
+ m[i]->flags &= ~PG_LAUNDRY;
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
/*
- * whether or not to leave the page activated
- * is up in the air, but we should put the page
- * on a page queue somewhere. (it already is in
- * the object).
- * After some emperical results, it is best
- * to deactivate the readahead pages.
+ * optimization, if a page has been read during the
+ * pageout process, we activate it.
*/
- vm_page_deactivate(m[i]);
-
- /*
- * just in case someone was asking for this
- * page we now tell them that it is ok to use
- */
- m[i]->flags &= ~PG_FAKE;
- PAGE_WAKEUP(m[i]);
+ if ( (m[i]->flags & PG_ACTIVE) == 0 &&
+ pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))
+ vm_page_activate(m[i]);
}
}
-/*
- * and free the kernel virtual addresses
- */
+ } else {
+ for(i=0;i<count;i++) {
+ rtvals[i] = rv;
+ m[i]->flags |= PG_LAUNDRY;
+ }
+ }
+
+ if( spc->spc_altkva)
kmem_free_wakeup(pager_map, kva, count * NBPG);
+
+ queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
+ if (swap_pager_needflags & SWAP_FREE_NEEDED) {
+ swap_pager_needflags &= ~SWAP_FREE_NEEDED;
+ wakeup((caddr_t)&swap_pager_free);
}
+
return(rv);
}
boolean_t
-swap_pager_clean(m, rw)
- vm_page_t m;
- int rw;
+swap_pager_clean()
{
register swp_clean_t spc, tspc;
register int s;
@@ -1235,7 +1567,13 @@ swap_pager_clean(m, rw)
*/
spc = (swp_clean_t) queue_first(&swap_pager_done);
while (!queue_end(&swap_pager_done, (queue_entry_t)spc)) {
- pmap_remove(vm_map_pmap(pager_map), spc->spc_kva, ((vm_offset_t) spc->spc_kva) + NBPG);
+ if( spc->spc_altkva) {
+ pmap_remove(vm_map_pmap(pager_map), spc->spc_altkva, spc->spc_altkva + spc->spc_count * NBPG);
+ kmem_free_wakeup(pager_map, spc->spc_altkva, spc->spc_count * NBPG);
+ spc->spc_altkva = 0;
+ } else {
+ pmap_remove(vm_map_pmap(pager_map), spc->spc_kva, spc->spc_kva + NBPG);
+ }
swap_pager_finish(spc);
queue_remove(&swap_pager_done, spc, swp_clean_t, spc_list);
goto doclean;
@@ -1258,6 +1596,10 @@ doclean:
}
spc->spc_flags = 0;
queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
+ if (swap_pager_needflags & SWAP_FREE_NEEDED) {
+ swap_pager_needflags &= ~SWAP_FREE_NEEDED;
+ wakeup((caddr_t)&swap_pager_free);
+ }
++cleandone;
splx(s);
}
@@ -1269,11 +1611,10 @@ void
swap_pager_finish(spc)
register swp_clean_t spc;
{
- vm_page_t m = spc->spc_m;
- vm_object_t object = m->object;
- extern int vm_pageout_free_min;
+ vm_object_t object = spc->spc_m[0]->object;
+ int i;
- if (--object->paging_in_progress == 0)
+ if ((object->paging_in_progress -= spc->spc_count) == 0)
thread_wakeup((int) object);
/*
@@ -1282,36 +1623,27 @@ swap_pager_finish(spc)
* (XXX could get stuck doing this, should give up after awhile)
*/
if (spc->spc_flags & SPC_ERROR) {
- printf("swap_pager_finish: clean of page %x failed\n",
- VM_PAGE_TO_PHYS(m));
- m->flags |= PG_LAUNDRY;
+ for(i=0;i<spc->spc_count;i++) {
+ printf("swap_pager_finish: clean of page %x failed\n",
+ VM_PAGE_TO_PHYS(spc->spc_m[i]));
+ spc->spc_m[i]->flags |= PG_LAUNDRY;
+ }
} else {
- pmap_clear_modify(VM_PAGE_TO_PHYS(m));
- m->flags |= PG_CLEAN;
+ for(i=0;i<spc->spc_count;i++) {
+ pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i]));
+ spc->spc_m[i]->flags |= PG_CLEAN;
+ }
}
- /*
- * if a page has been read during pageout, then
- * we activate the page.
- */
- if ((m->flags & PG_ACTIVE) == 0 &&
- pmap_is_referenced(VM_PAGE_TO_PHYS(m)))
- vm_page_activate(m);
- /*
- * we wakeup any processes that are waiting on
- * this page.
- */
- PAGE_WAKEUP(m);
- /*
- * if we need memory desperately, then free it now
- */
- if (vm_page_free_count < vm_page_free_reserved &&
- (m->flags & PG_CLEAN) && m->wire_count == 0) {
- pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
- vm_page_free(m);
+ for(i=0;i<spc->spc_count;i++) {
+ /*
+ * we wakeup any processes that are waiting on
+ * these pages.
+ */
+ PAGE_WAKEUP(spc->spc_m[i]);
}
- --nswiodone;
+ nswiodone -= spc->spc_count;
return;
}
@@ -1324,7 +1656,6 @@ swap_pager_iodone(bp)
register struct buf *bp;
{
register swp_clean_t spc;
- daddr_t blk;
int s;
s = splbio();
@@ -1337,15 +1668,17 @@ swap_pager_iodone(bp)
bp->b_error, bp->b_blkno, bp->b_bcount);
}
+/*
if ((bp->b_flags & B_READ) == 0)
vwakeup(bp);
+*/
bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_ASYNC);
if (bp->b_vp) {
brelvp(bp);
}
- nswiodone++;
+ nswiodone += spc->spc_count;
if (--spc->spc_swp->sw_poip == 0) {
wakeup((caddr_t)spc->spc_swp);
}
@@ -1393,6 +1726,27 @@ getpbuf() {
}
/*
+ * allocate a physical buffer, if one is available
+ */
+struct buf *
+trypbuf() {
+ int s;
+ struct buf *bp;
+
+ s = splbio();
+ if( bswlist.av_forw == NULL) {
+ splx(s);
+ return NULL;
+ }
+ bp = bswlist.av_forw;
+ bswlist.av_forw = bp->av_forw;
+ splx(s);
+
+ bzero(bp, sizeof *bp);
+ return bp;
+}
+
+/*
* release a physical buffer
*/
void
@@ -1416,8 +1770,8 @@ relpbuf(bp)
*/
int
swap_pager_ready() {
- if( queue_empty( &swap_pager_free))
- return 0;
- else
+ if( !queue_empty( &swap_pager_free))
return 1;
+ else
+ return 0;
}
diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h
index e505e436d1ce..853edd5d1b16 100644
--- a/sys/vm/swap_pager.h
+++ b/sys/vm/swap_pager.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* from: @(#)swap_pager.h 7.1 (Berkeley) 12/5/90
- * $Id: swap_pager.h,v 1.7 1994/01/17 09:33:25 davidg Exp $
+ * $Id: swap_pager.h,v 1.9 1994/03/14 21:54:23 davidg Exp $
*/
/*
@@ -48,7 +48,7 @@
#define _SWAP_PAGER_ 1
/*
- * SWB_NPAGES can be set to any value from 1 to 32 pages per allocation,
+ * SWB_NPAGES can be set to any value from 1 to 16 pages per allocation,
* however, due to the allocation spilling into non-swap pager backed memory,
* suggest keeping SWB_NPAGES small (1-4). If high performance is manditory
* perhaps up to 8 pages might be in order????
@@ -57,7 +57,8 @@
*/
#define SWB_NPAGES 8
struct swblock {
- unsigned int swb_valid; /* bitmask for valid pages */
+ unsigned short swb_valid; /* bitmask for valid pages */
+ unsigned short swb_locked; /* block locked */
int swb_block[SWB_NPAGES]; /* unfortunately int instead of daddr_t */
};
typedef struct swblock *sw_blk_t;
@@ -89,7 +90,7 @@ boolean_t swap_pager_getmulti(vm_pager_t, vm_page_t *, int, int, boolean_t);
boolean_t swap_pager_haspage(vm_pager_t, vm_offset_t);
int swap_pager_io(sw_pager_t, vm_page_t *, int, int, int);
void swap_pager_iodone(struct buf *);
-boolean_t swap_pager_clean(vm_page_t, int);
+boolean_t swap_pager_clean();
extern struct pagerops swappagerops;
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index c7254bce4c51..1cf99e068e9e 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -66,7 +66,7 @@
* rights to redistribute these changes.
*/
/*
- * $Id: vm_fault.c,v 1.14.2.1 1994/03/24 07:20:29 rgrimes Exp $
+ * $Id: vm_fault.c,v 1.18 1994/05/25 11:06:49 davidg Exp $
*/
/*
@@ -82,9 +82,9 @@
#include "resource.h"
#include "resourcevar.h"
-#define VM_FAULT_READ_AHEAD 3
+#define VM_FAULT_READ_AHEAD 4
#define VM_FAULT_READ_AHEAD_MIN 1
-#define VM_FAULT_READ_BEHIND 2
+#define VM_FAULT_READ_BEHIND 3
#define VM_FAULT_READ (VM_FAULT_READ_AHEAD+VM_FAULT_READ_BEHIND+1)
extern int swap_pager_full;
extern int vm_pageout_proc_limit;
@@ -133,6 +133,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
vm_page_t marray[VM_FAULT_READ];
int reqpage;
int spl;
+ int hardfault=0;
vm_stat.faults++; /* needs lock XXX */
/*
@@ -284,13 +285,12 @@ vm_fault(map, vaddr, fault_type, change_wiring)
*/
vm_page_lock_queues();
- spl = vm_disable_intr();
+ spl = splimp();
if (m->flags & PG_INACTIVE) {
queue_remove(&vm_page_queue_inactive, m,
vm_page_t, pageq);
m->flags &= ~PG_INACTIVE;
vm_page_inactive_count--;
- vm_stat.reactivations++;
}
if (m->flags & PG_ACTIVE) {
@@ -299,7 +299,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
m->flags &= ~PG_ACTIVE;
vm_page_active_count--;
}
- vm_set_intr(spl);
+ splx(spl);
vm_page_unlock_queues();
/*
@@ -328,10 +328,11 @@ vm_fault(map, vaddr, fault_type, change_wiring)
(object->pager && object->pager->pg_type == PG_SWAP &&
!vm_pager_has_page(object->pager, offset+object->paging_offset)))) {
if (vaddr < VM_MAXUSER_ADDRESS && curproc && curproc->p_pid >= 48) /* XXX */ {
- UNLOCK_AND_DEALLOCATE;
printf("Process %d killed by vm_fault -- out of swap\n", curproc->p_pid);
psignal(curproc, SIGKILL);
- return KERN_RESOURCE_SHORTAGE;
+ curproc->p_cpu = 0;
+ curproc->p_nice = PRIO_MIN;
+ setpri(curproc);
}
}
@@ -403,6 +404,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
vm_stat.pageins++;
m->flags &= ~PG_FAKE;
pmap_clear_modify(VM_PAGE_TO_PHYS(m));
+ hardfault++;
break;
}
@@ -895,8 +897,16 @@ vm_fault(map, vaddr, fault_type, change_wiring)
}
else {
vm_page_activate(m);
- vm_pageout_deact_bump(m);
}
+
+ if( curproc && curproc->p_stats) {
+ if (hardfault) {
+ curproc->p_stats->p_ru.ru_majflt++;
+ } else {
+ curproc->p_stats->p_ru.ru_minflt++;
+ }
+ }
+
vm_page_unlock_queues();
/*
diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c
index bd2fd07a5445..482f968f652a 100644
--- a/sys/vm/vm_glue.c
+++ b/sys/vm/vm_glue.c
@@ -75,6 +75,7 @@
#include "vm_page.h"
#include "vm_kern.h"
#include "machine/stdarg.h"
+#include "machine/vmparam.h"
extern char kstack[];
int avefree = 0; /* XXX */
@@ -115,19 +116,16 @@ useracc(addr, len, rw)
vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
/*
- * XXX - specially disallow access to user page tables - they are
- * in the map.
- *
- * XXX - don't specially disallow access to the user area - treat
- * it as incorrectly as elsewhere.
+ * XXX - check separately to disallow access to user area and user
+ * page tables - they are in the map.
*
* XXX - VM_MAXUSER_ADDRESS is an end address, not a max. It was
- * only used (as an end address) in trap.c. Use it as an end
- * address here too.
+ * once only used (as an end address) in trap.c. Use it as an end
+ * address here too. This bogusness has spread. I just fixed
+ * where it was used as a max in vm_mmap.c.
*/
- if ((vm_offset_t) addr >= VM_MAXUSER_ADDRESS
- || (vm_offset_t) addr + len > VM_MAXUSER_ADDRESS
- || (vm_offset_t) addr + len <= (vm_offset_t) addr) {
+ if ((vm_offset_t) addr + len > /* XXX */ VM_MAXUSER_ADDRESS
+ || (vm_offset_t) addr + len < (vm_offset_t) addr) {
printf("address wrap\n");
return (FALSE);
}
@@ -213,7 +211,6 @@ vm_fork(p1, p2, isvfork)
* Allocate a wired-down (for now) pcb and kernel stack for the process
*/
- /* addr = UPT_MIN_ADDRESS - UPAGES*NBPG; */
addr = (vm_offset_t) kstack;
vp = &p2->p_vmspace->vm_map;
@@ -281,23 +278,24 @@ void
vm_init_limits(p)
register struct proc *p;
{
- int tmp;
+ int rss_limit;
/*
* Set up the initial limits on process VM.
- * Set the maximum resident set size to be all
- * of (reasonably) available memory. This causes
- * any single, large process to start random page
- * replacement once it fills memory.
+ * Set the maximum resident set size to be half
+ * of (reasonably) available memory. Since this
+ * is a soft limit, it comes into effect only
+ * when the system is out of memory - half of
+ * main memory helps to favor smaller processes,
+ * and reduces thrashing of the object cache.
*/
p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
- tmp = ((2 * vm_page_free_count) / 3) - 32;
- if (vm_page_free_count < 512)
- tmp = vm_page_free_count;
- p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(tmp);
+ /* limit the limit to no less than 128K */
+ rss_limit = max(vm_page_free_count / 2, 32);
+ p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(rss_limit);
p->p_rlimit[RLIMIT_RSS].rlim_max = RLIM_INFINITY;
}
@@ -425,7 +423,7 @@ noswap:
(void) splhigh();
if (((vm_page_free_count + vm_page_inactive_count) >=
(vm_page_inactive_target + vm_page_free_reserved)) ||
- (vm_page_free_count >= vm_page_free_min)) {
+ (vm_page_free_count > vm_page_free_reserved)) {
spl0();
faultin(p);
p->p_time = 0;
@@ -485,8 +483,6 @@ swapout_threads()
continue;
switch (p->p_stat) {
case SRUN:
- if (p->p_pri < PUSER)
- continue;
if ((tpri = p->p_time + p->p_nice * 8) > outpri2) {
outp2 = p;
outpri2 = tpri;
@@ -495,7 +491,7 @@ swapout_threads()
case SSLEEP:
case SSTOP:
- if (p->p_pri <= PRIBIO)
+ if (p->p_pri <= PVM)
continue;
if (p->p_slptime > maxslp) {
swapout(p);
@@ -511,12 +507,12 @@ swapout_threads()
* If we didn't get rid of any real duds, toss out the next most
* likely sleeping/stopped or running candidate. We only do this
* if we are real low on memory since we don't gain much by doing
- * it (UPAGES pages).
+ * it (UPAGES+1 pages).
*/
if (didswap == 0 && (swapinreq &&
- vm_page_free_count <= vm_pageout_free_min)) {
+ (vm_page_free_count + vm_page_inactive_count) <= (vm_page_free_min + vm_page_inactive_target))) {
if ((p = outp) == 0 &&
- (vm_page_free_count <= vm_pageout_free_min))
+ (vm_page_free_count <= vm_page_free_reserved))
p = outp2;
#ifdef DEBUG
if (swapdebug & SDB_SWAPOUT)
@@ -552,6 +548,8 @@ swapout(p)
p->p_slptime, vm_page_free_count);
#endif
+ ++p->p_stats->p_ru.ru_nswap;
+
(void) splhigh();
p->p_flag &= ~SLOAD;
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index e6759a756844..0a753040bf4e 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -37,7 +37,7 @@
*
* from: Utah $Hdr: vm_mmap.c 1.3 90/01/21$
* from: @(#)vm_mmap.c 7.5 (Berkeley) 6/28/91
- * $Id: vm_mmap.c,v 1.21 1994/01/31 04:20:26 davidg Exp $
+ * $Id: vm_mmap.c,v 1.23 1994/06/22 05:53:10 jkh Exp $
*/
/*
@@ -59,6 +59,7 @@
#include "vm_prot.h"
#include "vm_statistics.h"
#include "vm_user.h"
+#include "vm_page.h"
static boolean_t vm_map_is_allocated(vm_map_t, vm_offset_t, vm_offset_t,
boolean_t);
@@ -181,9 +182,7 @@ smmap(p, uap, retval)
/*
* Check address range for validity
*/
- if (addr + size >= VM_MAXUSER_ADDRESS)
- return(EINVAL);
- if (addr > addr + size)
+ if (addr + size > /* XXX */ VM_MAXUSER_ADDRESS || addr + size < addr)
return(EINVAL);
/*
@@ -255,8 +254,8 @@ smmap(p, uap, retval)
handle = NULL;
}
- error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
- flags, handle, (vm_offset_t)uap->pos);
+ error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot,
+ maxprot, flags, handle, (vm_offset_t)uap->pos);
if (error == 0)
*retval = (int) addr;
return(error);
@@ -363,9 +362,7 @@ munmap(p, uap, retval)
size = (vm_size_t) round_page(uap->len);
if (size == 0)
return(0);
- if (addr + size >= VM_MAXUSER_ADDRESS)
- return(EINVAL);
- if (addr >= addr + size)
+ if (addr + size > /* XXX */ VM_MAXUSER_ADDRESS || addr + size < addr)
return(EINVAL);
if (!vm_map_is_allocated(&p->p_vmspace->vm_map, addr, addr+size,
FALSE))
@@ -475,6 +472,7 @@ mincore(p, uap, retval)
return (EOPNOTSUPP);
}
+void pmap_object_init_pt();
/*
* Internal version of mmap.
* Currently used by mmap, exec, and sys5 shared memory.
@@ -493,9 +491,9 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
caddr_t handle; /* XXX should be vp */
vm_offset_t foff;
{
- register vm_pager_t pager;
+ register vm_pager_t pager = 0;
boolean_t fitit;
- vm_object_t object;
+ vm_object_t object = 0;
struct vnode *vp = 0;
int type;
int rv = KERN_SUCCESS;
@@ -508,7 +506,10 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
*addr = round_page(*addr);
} else {
fitit = FALSE;
- (void) vm_deallocate(map, *addr, size);
+ /*
+ * Defer deallocating address space until
+ * after a reference is gained to the object
+ */
}
/*
@@ -516,48 +517,64 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
* gain a reference to ensure continued existance of the object.
* (XXX the exception is to appease the pageout daemon)
*/
- if ((flags & MAP_TYPE) == MAP_ANON)
- type = PG_DFLT;
- else {
- vp = (struct vnode *)handle;
- if (vp->v_type == VCHR) {
- type = PG_DEVICE;
- handle = (caddr_t)(u_long)vp->v_rdev;
- } else
- type = PG_VNODE;
- }
- pager = vm_pager_allocate(type, handle, size, prot, foff);
- if (pager == NULL)
- return (type == PG_DEVICE ? EINVAL : ENOMEM);
+ if ((((flags & MAP_TYPE) != MAP_ANON) || (handle != NULL))) {
+ if ((flags & MAP_TYPE) == MAP_ANON)
+ type = PG_DFLT;
+ else {
+ vp = (struct vnode *)handle;
+ if (vp->v_type == VCHR) {
+ type = PG_DEVICE;
+ handle = (caddr_t)(u_long)vp->v_rdev;
+ } else
+ type = PG_VNODE;
+ }
+ pager = vm_pager_allocate(type, handle, size, prot, foff);
+ if (pager == NULL) {
+ /* on failure, don't leave anything mapped */
+ if (!fitit)
+ (void) vm_deallocate(map, *addr, size);
+ return (type == PG_DEVICE ? EINVAL : ENOMEM);
+ }
/*
* Find object and release extra reference gained by lookup
*/
- object = vm_object_lookup(pager);
- vm_object_deallocate(object);
+ object = vm_object_lookup(pager);
+ vm_object_deallocate(object);
+ }
+
+ /* blow away anything that might be mapped here already */
+ if (!fitit)
+ (void) vm_deallocate(map, *addr, size);
/*
* Anonymous memory.
*/
- if ((flags & MAP_TYPE) == MAP_ANON) {
- rv = vm_allocate_with_pager(map, addr, size, fitit,
+ if (((flags & MAP_TYPE) == MAP_ANON)) {
+ if (handle != NULL) {
+ rv = vm_allocate_with_pager(map, addr, size, fitit,
pager, (vm_offset_t)foff, TRUE);
- if (rv != KERN_SUCCESS) {
- if (handle == NULL)
- vm_pager_deallocate(pager);
- else
+ if (rv != KERN_SUCCESS) {
vm_object_deallocate(object);
- goto out;
- }
+ goto out;
+ }
+#if 1
/*
* Don't cache anonymous objects.
* Loses the reference gained by vm_pager_allocate.
*/
- (void) pager_cache(object, FALSE);
+ (void) pager_cache(object, FALSE);
+#endif
#ifdef DEBUG
- if (mmapdebug & MDB_MAPIT)
- printf("vm_mmap(%d): ANON *addr %x size %x pager %x\n",
- curproc->p_pid, *addr, size, pager);
+ if (mmapdebug & MDB_MAPIT)
+ printf("vm_mmap(%d): ANON *addr %x size %x pager %x\n",
+ curproc->p_pid, *addr, size, pager);
#endif
+ } else {
+ rv = vm_map_find(map, NULL, (vm_offset_t) 0, addr, size, fitit);
+ if(rv != KERN_SUCCESS) {
+ goto out;
+ }
+ }
}
/*
* Must be type MAP_FILE.
@@ -610,6 +627,9 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
pager_cache(object, FALSE);
else
vm_object_deallocate(object);
+
+ if( map->pmap)
+ pmap_object_init_pt(map->pmap, *addr, object, foff, size);
}
/*
* Copy-on-write of file. Two flavors.
@@ -683,6 +703,8 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
*/
vm_object_pmap_copy(object, (vm_offset_t)foff,
(vm_offset_t)foff+size);
+ if( map->pmap)
+ pmap_object_init_pt(map->pmap, *addr, object, foff, size);
vm_object_deallocate(object);
vm_map_deallocate(tmap);
if (rv != KERN_SUCCESS)
@@ -866,6 +888,7 @@ vm_allocate_with_pager(map, addr, size, fitit, pager, poffset, internal)
vm_stat.lookups++;
if (object == NULL) {
object = vm_object_allocate(size);
+ /* don't put internal objects in the hash table */
if (!internal)
vm_object_enter(object, pager);
} else
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 5c463f64d6c5..3dea7601b5ba 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_object.c 7.4 (Berkeley) 5/7/91
- * $Id: vm_object.c,v 1.21.2.1 1994/03/07 02:22:13 rgrimes Exp $
+ * $Id: vm_object.c,v 1.25 1994/04/14 07:50:21 davidg Exp $
*
*
* Copyright (c) 1987, 1990 Carnegie-Mellon University.
@@ -401,7 +401,7 @@ vm_object_terminate(object)
VM_PAGE_CHECK(p);
vm_page_lock_queues();
- s = vm_disable_intr();
+ s = splimp();
if (p->flags & PG_ACTIVE) {
queue_remove(&vm_page_queue_active, p, vm_page_t,
pageq);
@@ -415,7 +415,7 @@ vm_object_terminate(object)
p->flags &= ~PG_INACTIVE;
vm_page_inactive_count--;
}
- vm_set_intr(s);
+ splx(s);
vm_page_unlock_queues();
p = (vm_page_t) queue_next(&p->listq);
}
@@ -514,15 +514,7 @@ again:
vm_page_deactivate(p);
if ((p->flags & PG_CLEAN) == 0) {
- p->flags |= PG_BUSY;
- object->paging_in_progress++;
- vm_object_unlock(object);
- (void) vm_pager_put(object->pager, p, TRUE);
- vm_object_lock(object);
- object->paging_in_progress--;
- if (object->paging_in_progress == 0)
- wakeup((caddr_t) object);
- PAGE_WAKEUP(p);
+ vm_pageout_clean(p,1);
goto again;
}
}
@@ -551,7 +543,7 @@ vm_object_deactivate_pages(object)
next = (vm_page_t) queue_next(&p->listq);
vm_page_lock_queues();
if ((p->flags & (PG_INACTIVE|PG_BUSY)) == 0 &&
- p->wire_count == 0)
+ (p->wire_count == 0 && p->hold_count == 0))
vm_page_deactivate(p); /* optimisation from mach 3.0 -
* andrew@werple.apana.org.au,
* Feb '93
@@ -658,14 +650,14 @@ vm_object_pmap_copy(object, start, end)
register vm_page_t p;
vm_offset_t amount;
+ if (object == NULL)
+ return;
+
start = trunc_page(start);
end = round_page(end);
amount = ((end - start) + PAGE_SIZE - 1) / PAGE_SIZE;
- if (object == NULL)
- return;
-
vm_object_lock(object);
p = (vm_page_t) queue_first(&object->memq);
while (!queue_end(&object->memq, (queue_entry_t) p)) {
diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h
index 60e7677b27ed..b1b82bcda8e9 100644
--- a/sys/vm/vm_object.h
+++ b/sys/vm/vm_object.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_object.h 7.3 (Berkeley) 4/21/91
- * $Id: vm_object.h,v 1.6 1994/01/14 16:27:25 davidg Exp $
+ * $Id: vm_object.h,v 1.7 1994/03/14 21:54:27 davidg Exp $
*/
/*
@@ -100,7 +100,8 @@ struct vm_object {
/* Paging (in or out) - don't
collapse or destroy */
/* boolean_t */ can_persist:1, /* allow to persist */
- /* boolean_t */ internal:1; /* internally created object */
+ /* boolean_t */ internal:1, /* internally created object */
+ read_only:1; /* entire obj is read only */
queue_chain_t cached_list; /* for persistence */
};
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 31a99382a7d6..409438163be6 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91
- * $Id: vm_page.c,v 1.12 1994/02/09 07:03:10 davidg Exp $
+ * $Id: vm_page.c,v 1.18 1994/06/17 13:29:13 davidg Exp $
*/
/*
@@ -311,6 +311,7 @@ vm_page_startup(starta, enda, vaddr)
m->flags = 0;
m->object = 0;
m->phys_addr = pa;
+ m->hold_count = 0;
queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
pa += PAGE_SIZE;
}
@@ -469,7 +470,7 @@ vm_page_lookup(object, offset)
*/
bucket = &vm_page_buckets[vm_page_hash(object, offset)];
- spl = vm_disable_intr();
+ spl = splimp();
simple_lock(&bucket_lock);
mem = (vm_page_t) queue_first(bucket);
@@ -477,14 +478,14 @@ vm_page_lookup(object, offset)
VM_PAGE_CHECK(mem);
if ((mem->object == object) && (mem->offset == offset)) {
simple_unlock(&bucket_lock);
- vm_set_intr(spl);
+ splx(spl);
return(mem);
}
mem = (vm_page_t) queue_next(&mem->hashq);
}
simple_unlock(&bucket_lock);
- vm_set_intr(spl);
+ splx(spl);
return(NULL);
}
@@ -508,10 +509,10 @@ vm_page_rename(mem, new_object, new_offset)
vm_page_lock_queues(); /* keep page from moving out from
under pageout daemon */
- spl = vm_disable_intr();
+ spl = splimp();
vm_page_remove(mem);
vm_page_insert(mem, new_object, new_offset);
- vm_set_intr(spl);
+ splx(spl);
vm_page_unlock_queues();
}
@@ -531,7 +532,7 @@ vm_page_alloc(object, offset)
register vm_page_t mem;
int spl;
- spl = vm_disable_intr();
+ spl = splimp();
simple_lock(&vm_page_queue_free_lock);
if ( object != kernel_object &&
object != kmem_object &&
@@ -539,7 +540,7 @@ vm_page_alloc(object, offset)
vm_page_free_count < vm_page_free_reserved) {
simple_unlock(&vm_page_queue_free_lock);
- vm_set_intr(spl);
+ splx(spl);
/*
* this wakeup seems unnecessary, but there is code that
* might just check to see if there are free pages, and
@@ -552,7 +553,7 @@ vm_page_alloc(object, offset)
}
if (queue_empty(&vm_page_queue_free)) {
simple_unlock(&vm_page_queue_free_lock);
- vm_set_intr(spl);
+ splx(spl);
/*
* comment above re: wakeups applies here too...
*/
@@ -569,8 +570,9 @@ vm_page_alloc(object, offset)
mem->flags = PG_BUSY|PG_CLEAN|PG_FAKE;
vm_page_insert(mem, object, offset);
mem->wire_count = 0;
- mem->deact = 0;
- vm_set_intr(spl);
+ mem->hold_count = 0;
+ mem->act_count = 0;
+ splx(spl);
/*
* don't wakeup too often, so we wakeup the pageout daemon when
@@ -597,10 +599,9 @@ vm_page_free(mem)
{
int spl;
- spl = vm_disable_intr();
+ spl = splimp();
vm_page_remove(mem);
- mem->deact = 0;
if (mem->flags & PG_ACTIVE) {
queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
mem->flags &= ~PG_ACTIVE;
@@ -624,7 +625,7 @@ vm_page_free(mem)
vm_page_free_count++;
simple_unlock(&vm_page_queue_free_lock);
- vm_set_intr(spl);
+ splx(spl);
/*
* if pageout daemon needs pages, then tell it that there
@@ -650,7 +651,7 @@ vm_page_free(mem)
}
} else {
- vm_set_intr(spl);
+ splx(spl);
}
wakeup((caddr_t) mem);
}
@@ -670,7 +671,7 @@ vm_page_wire(mem)
{
int spl;
VM_PAGE_CHECK(mem);
- spl = vm_disable_intr();
+ spl = splimp();
if (mem->wire_count == 0) {
if (mem->flags & PG_ACTIVE) {
@@ -688,7 +689,7 @@ vm_page_wire(mem)
vm_page_wire_count++;
}
mem->wire_count++;
- vm_set_intr(spl);
+ splx(spl);
}
/*
@@ -706,7 +707,7 @@ vm_page_unwire(mem)
int spl;
VM_PAGE_CHECK(mem);
- spl = vm_disable_intr();
+ spl = splimp();
if (mem->wire_count != 0)
mem->wire_count--;
if (mem->wire_count == 0) {
@@ -714,9 +715,8 @@ vm_page_unwire(mem)
vm_page_active_count++;
mem->flags |= PG_ACTIVE;
vm_page_wire_count--;
- vm_pageout_deact_bump(mem);
}
- vm_set_intr(spl);
+ splx(spl);
}
/*
@@ -745,9 +745,8 @@ vm_page_deactivate(m)
* Paul Mackerras (paulus@cs.anu.edu.au) 9-Jan-93.
*/
- spl = splhigh();
- m->deact = 0;
- if (!(m->flags & PG_INACTIVE) && m->wire_count == 0) {
+ spl = splimp();
+ if (!(m->flags & PG_INACTIVE) && m->wire_count == 0 && m->hold_count == 0) {
pmap_clear_reference(VM_PAGE_TO_PHYS(m));
if (m->flags & PG_ACTIVE) {
queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
@@ -757,7 +756,13 @@ vm_page_deactivate(m)
queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
m->flags |= PG_INACTIVE;
vm_page_inactive_count++;
+#define NOT_DEACTIVATE_PROTECTS
+#ifndef NOT_DEACTIVATE_PROTECTS
pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
+#else
+ if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
+ m->flags &= ~PG_CLEAN;
+#endif
if ((m->flags & PG_CLEAN) == 0)
m->flags |= PG_LAUNDRY;
}
@@ -789,32 +794,42 @@ void
vm_page_activate(m)
register vm_page_t m;
{
- int spl;
+ int spl, target, shortage, maxscan;
+ vm_page_t actm, next;
+
VM_PAGE_CHECK(m);
- vm_pageout_deact_bump(m);
+ spl = splimp();
- spl = vm_disable_intr();
+ if (m->wire_count) {
+ splx(spl);
+ return;
+ }
+
+ if ((m->flags & (PG_INACTIVE|PG_ACTIVE)) ==
+ (PG_INACTIVE|PG_ACTIVE)) {
+ panic("vm_page_activate: on both queues?");
+ }
if (m->flags & PG_INACTIVE) {
- queue_remove(&vm_page_queue_inactive, m, vm_page_t,
- pageq);
+ queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
vm_page_inactive_count--;
m->flags &= ~PG_INACTIVE;
+ vm_stat.reactivations++;
}
- if (m->wire_count == 0) {
- if (m->flags & PG_ACTIVE)
- panic("vm_page_activate: already active");
-
- m->flags |= PG_ACTIVE;
- queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
- queue_remove(&m->object->memq, m, vm_page_t, listq);
- queue_enter(&m->object->memq, m, vm_page_t, listq);
- vm_page_active_count++;
- }
+ if (m->flags & PG_ACTIVE)
+ panic("vm_page_activate: already active");
+
+ m->flags |= PG_ACTIVE;
+ queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_remove(&m->object->memq, m, vm_page_t, listq);
+ queue_enter(&m->object->memq, m, vm_page_t, listq);
+ vm_page_active_count++;
+ /* m->act_count = 10; */
+ m->act_count = 1;
- vm_set_intr(spl);
+ splx(spl);
}
/*
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 33ada305990b..5a3be88adf23 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_page.h 7.3 (Berkeley) 4/21/91
- * $Id: vm_page.h,v 1.8 1994/01/31 04:21:19 davidg Exp $
+ * $Id: vm_page.h,v 1.14 1994/04/14 07:50:24 davidg Exp $
*/
/*
@@ -71,6 +71,9 @@
#ifndef _VM_PAGE_
#define _VM_PAGE_
+#ifdef KERNEL
+#include <systm.h>
+#endif
/*
* Management of resident (logical) pages.
*
@@ -121,18 +124,14 @@ struct vm_page {
unsigned int wire_count; /* how many wired down maps use me? */
unsigned short flags; /* bit encoded flags */
- unsigned short deact; /* deactivation count */
+ unsigned short act_count; /* active count */
+ int hold_count; /* page hold count -- don't pageout */
vm_offset_t phys_addr; /* physical address of page */
};
typedef struct vm_page *vm_page_t;
-#define DEACT_START 5
-#define DEACT_DELAY 2
-#define DEACT_CLEAN 1
-#define DEACT_FREE 0
-
#if VM_PAGE_DEBUG
#define VM_PAGE_CHECK(mem) { \
if ((((unsigned int) mem) < ((unsigned int) &vm_page_array[0])) || \
@@ -226,10 +225,10 @@ void vm_page_replace();
boolean_t vm_page_zero_fill();
void vm_page_copy();
-
+#if 0
void vm_page_wire();
void vm_page_unwire();
-
+#endif
/*
* Functions implemented as macros
@@ -272,12 +271,25 @@ extern vm_offset_t pmap_phys_ddress(int);
/*
- * these macros are *MUCH* faster on a 386/486 type machine
- * eventually they need to be implemented correctly and put
- * somewhere in the machine dependant stuff.
+ * Keep page from being freed by the page daemon
+ * much of the same effect as wiring, except much lower
+ * overhead and should be used only for *very* temporary
+ * holding ("wiring").
*/
-#define vm_disable_intr() (disable_intr(), 0)
-#define vm_set_intr(spl) enable_intr()
+static inline void
+vm_page_hold(mem)
+ vm_page_t mem;
+{
+ mem->hold_count++;
+}
+
+static inline void
+vm_page_unhold(mem)
+ vm_page_t mem;
+{
+ if( --mem->hold_count < 0)
+ panic("vm_page_unhold: hold count < 0!!!");
+}
#endif /* KERNEL */
#endif /* _VM_PAGE_ */
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index 229a4090922c..c6817768c2bb 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -65,7 +65,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
- * $Id: vm_pageout.c,v 1.13 1994/02/10 08:08:37 davidg Exp $
+ * $Id: vm_pageout.c,v 1.24 1994/06/17 13:29:15 davidg Exp $
*/
/*
@@ -85,22 +85,35 @@
extern vm_map_t kmem_map;
int vm_pages_needed; /* Event on which pageout daemon sleeps */
+int vm_pagescanner; /* Event on which pagescanner sleeps */
int vm_pageout_free_min = 0; /* Stop pageout to wait for pagers at this free level */
int vm_pageout_pages_needed = 0; /* flag saying that the pageout daemon needs pages */
int vm_page_pagesfreed;
+extern int vm_page_count;
extern int npendingio;
extern int hz;
int vm_pageout_proc_limit;
extern int nswiodone;
+extern int swap_pager_full;
+extern int swap_pager_ready();
#define MAXREF 32767
-#define DEACT_MAX (DEACT_START * 4)
-#define MINSCAN 512 /* minimum number of pages to scan in active queue */
- /* set the "clock" hands to be (MINSCAN * 4096) Bytes */
-static int minscan;
-void vm_pageout_deact_bump(vm_page_t m) ;
+
+#define MAXSCAN 512 /* maximum number of pages to scan in active queue */
+ /* set the "clock" hands to be (MAXSCAN * 4096) Bytes */
+#define ACT_DECLINE 1
+#define ACT_ADVANCE 3
+#define ACT_MAX 300
+
+#define LOWATER ((2048*1024)/NBPG)
+
+#define VM_PAGEOUT_PAGE_COUNT 8
+int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT;
+static vm_offset_t vm_space_needed;
+int vm_pageout_req_do_stats;
+int vm_pageout_do_stats;
/*
@@ -108,9 +121,9 @@ void vm_pageout_deact_bump(vm_page_t m) ;
* cleans a vm_page
*/
int
-vm_pageout_clean(m, wait)
+vm_pageout_clean(m, sync)
register vm_page_t m;
- int wait;
+ int sync;
{
/*
* Clean the page and remove it from the
@@ -130,7 +143,12 @@ vm_pageout_clean(m, wait)
register vm_object_t object;
register vm_pager_t pager;
- int pageout_status;
+ int pageout_status[VM_PAGEOUT_PAGE_COUNT];
+ vm_page_t ms[VM_PAGEOUT_PAGE_COUNT];
+ int pageout_count;
+ int anyok=0;
+ int i;
+ vm_offset_t offset = m->offset;
object = m->object;
if (!object) {
@@ -153,37 +171,60 @@ vm_pageout_clean(m, wait)
vm_page_free_count < vm_pageout_free_min)
return 0;
-collapseagain:
if (!object->pager &&
object->shadow &&
object->shadow->paging_in_progress)
return 0;
- if (object->shadow) {
- vm_offset_t offset = m->offset;
- vm_object_collapse(object);
- if (!vm_page_lookup(object, offset))
+ if( !sync) {
+ if (object->shadow) {
+ vm_object_collapse(object);
+ if (!vm_page_lookup(object, offset))
+ return 0;
+ }
+
+ if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
return 0;
+ }
}
-waitagain:
- if (!wait && (m->flags & PG_BUSY)) {
- return 0;
- } else if (m->flags & PG_BUSY) {
- int s = splhigh();
- m->flags |= PG_WANTED;
- tsleep((caddr_t)m, PVM, "clnslp", 0);
- splx(s);
- goto waitagain;
- }
+ pageout_count = 1;
+ ms[0] = m;
- m->flags |= PG_BUSY;
+ if( pager = object->pager) {
+ for(i=1;i<vm_pageout_page_count;i++) {
+ if( ms[i] = vm_page_lookup( object, offset+i*NBPG)) {
+ if( ((ms[i]->flags & (PG_CLEAN|PG_INACTIVE|PG_BUSY)) == PG_INACTIVE)
+ && (ms[i]->wire_count == 0)
+ && (ms[i]->hold_count == 0))
+ pageout_count++;
+ else
+ break;
+ } else
+ break;
+ }
+ for(i=0;i<pageout_count;i++) {
+ ms[i]->flags |= PG_BUSY;
+ pmap_page_protect(VM_PAGE_TO_PHYS(ms[i]), VM_PROT_READ);
+ }
+ object->paging_in_progress += pageout_count;
+ vm_stat.pageouts += pageout_count;
+ } else {
+
+ m->flags |= PG_BUSY;
- pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ);
+ pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ);
- vm_stat.pageouts++;
+ vm_stat.pageouts++;
- object->paging_in_progress++;
+ object->paging_in_progress++;
+
+ pager = vm_pager_allocate(PG_DFLT, (caddr_t)0,
+ object->size, VM_PROT_ALL, 0);
+ if (pager != NULL) {
+ vm_object_setpager(object, pager, 0, FALSE);
+ }
+ }
/*
* If there is no pager for the page,
@@ -194,160 +235,83 @@ waitagain:
* later.
*/
- if ((pager = object->pager) == NULL) {
- pager = vm_pager_allocate(PG_DFLT, (caddr_t)0,
- object->size, VM_PROT_ALL, 0);
- if (pager != NULL) {
- vm_object_setpager(object, pager, 0, FALSE);
- }
- }
if ((pager && pager->pg_type == PG_SWAP) ||
vm_page_free_count >= vm_pageout_free_min) {
- pageout_status = pager ?
- vm_pager_put(pager, m, (((object == kernel_object) || wait) ? TRUE: FALSE)) :
- VM_PAGER_FAIL;
- } else
- pageout_status = VM_PAGER_FAIL;
-
- switch (pageout_status) {
- case VM_PAGER_OK:
- m->flags &= ~PG_LAUNDRY;
- break;
- case VM_PAGER_PEND:
- m->flags &= ~PG_LAUNDRY;
- break;
- case VM_PAGER_BAD:
- /*
- * Page outside of range of object.
- * Right now we essentially lose the
- * changes by pretending it worked.
- */
- m->flags &= ~PG_LAUNDRY;
- m->flags |= PG_CLEAN;
- pmap_clear_modify(VM_PAGE_TO_PHYS(m));
- break;
- case VM_PAGER_FAIL:
- /*
- * If page couldn't be paged out, then
- * reactivate the page so it doesn't
- * clog the inactive list. (We will
- * try paging out it again later).
- */
- if ((m->flags & PG_ACTIVE) == 0)
- vm_page_activate(m);
- break;
- case VM_PAGER_TRYAGAIN:
- break;
- }
-
-
- /*
- * If the operation is still going, leave
- * the page busy to block all other accesses.
- * Also, leave the paging in progress
- * indicator set so that we don't attempt an
- * object collapse.
- */
- if (pageout_status != VM_PAGER_PEND) {
- if ((m->flags & PG_ACTIVE) == 0 &&
- pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
- vm_page_activate(m);
+ if( pageout_count == 1) {
+ pageout_status[0] = pager ?
+ vm_pager_put(pager, m,
+ ((sync || (object == kernel_object)) ? TRUE: FALSE)) :
+ VM_PAGER_FAIL;
+ } else {
+ if( !pager) {
+ for(i=0;i<pageout_count;i++)
+ pageout_status[i] = VM_PAGER_FAIL;
+ } else {
+ vm_pager_putmulti(pager, ms, pageout_count,
+ ((sync || (object == kernel_object)) ? TRUE : FALSE),
+ pageout_status);
+ }
}
- PAGE_WAKEUP(m);
- if (--object->paging_in_progress == 0)
- wakeup((caddr_t) object);
+
+ } else {
+ for(i=0;i<pageout_count;i++)
+ pageout_status[i] = VM_PAGER_FAIL;
}
- return (pageout_status == VM_PAGER_PEND ||
- pageout_status == VM_PAGER_OK) ? 1 : 0;
-}
-int
-vm_fault_object_deactivate_pages(map, object, dummy)
- vm_map_t map;
- vm_object_t object;
- int dummy;
-{
- register vm_page_t p, next;
- int rcount;
- int s;
- int dcount;
- int count;
-
- dcount = 0;
- /*
- * deactivate the pages in the objects shadow
- */
+ for(i=0;i<pageout_count;i++) {
+ switch (pageout_status[i]) {
+ case VM_PAGER_OK:
+ ms[i]->flags &= ~PG_LAUNDRY;
+ ++anyok;
+ break;
+ case VM_PAGER_PEND:
+ ms[i]->flags &= ~PG_LAUNDRY;
+ ++anyok;
+ break;
+ case VM_PAGER_BAD:
+ /*
+ * Page outside of range of object.
+ * Right now we essentially lose the
+ * changes by pretending it worked.
+ */
+ ms[i]->flags &= ~PG_LAUNDRY;
+ ms[i]->flags |= PG_CLEAN;
+ pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i]));
+ break;
+ case VM_PAGER_FAIL:
+ /*
+ * If page couldn't be paged out, then
+ * reactivate the page so it doesn't
+ * clog the inactive list. (We will
+ * try paging out it again later).
+ */
+ if (ms[i]->flags & PG_INACTIVE)
+ vm_page_activate(ms[i]);
+ break;
+ case VM_PAGER_TRYAGAIN:
+ break;
+ }
- if (object->shadow)
- dcount += vm_fault_object_deactivate_pages(map, object->shadow, 0);
- /*
- * scan the objects memory queue and remove 20% of the active pages
- */
- rcount = object->resident_page_count;
- count = rcount;
- if (count == 0)
- return dcount;
-#define MINOBJWRITE 10
-#define OBJDIVISOR 5
- if (count > MINOBJWRITE) {
- count = MINOBJWRITE + ((count - MINOBJWRITE) / OBJDIVISOR);
- }
- p = (vm_page_t) queue_first(&object->memq);
- while ((rcount-- > 0) && !queue_end(&object->memq, (queue_entry_t) p) ) {
- next = (vm_page_t) queue_next(&p->listq);
- vm_page_lock_queues();
/*
- * if a page is active, not wired and is in the processes pmap,
- * then deactivate the page.
+ * If the operation is still going, leave
+ * the page busy to block all other accesses.
+ * Also, leave the paging in progress
+ * indicator set so that we don't attempt an
+ * object collapse.
*/
- if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE &&
- p->wire_count == 0 &&
- pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) {
- if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) {
- vm_page_deactivate(p);
- if ((p->flags & PG_CLEAN) == 0) {
- vm_pageout_clean(p, 0);
- }
- ++dcount;
- if (--count <= 0) {
- vm_page_unlock_queues();
- s = splbio();
- while (object->paging_in_progress) {
- tsleep((caddr_t) object,PVM,"vmfobw",0);
- }
- splx(s);
- return dcount;
- }
- } else {
- vm_pageout_deact_bump(p);
- pmap_clear_reference(VM_PAGE_TO_PHYS(p));
- queue_remove(&object->memq, p, vm_page_t, listq);
- queue_enter(&object->memq, p, vm_page_t, listq);
- queue_remove(&vm_page_queue_active, p, vm_page_t, pageq);
- queue_enter(&vm_page_queue_active, p, vm_page_t, pageq);
+ if (pageout_status[i] != VM_PAGER_PEND) {
+ PAGE_WAKEUP(ms[i]);
+ if (--object->paging_in_progress == 0)
+ wakeup((caddr_t) object);
+ if (pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) {
+ pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i]));
+ if( ms[i]->flags & PG_INACTIVE)
+ vm_page_activate(ms[i]);
}
- /*
- * if a page is inactive and has been modified, clean it now
- */
- } else if ((p->flags & (PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) {
- if ((p->flags & PG_CLEAN) &&
- pmap_is_modified(VM_PAGE_TO_PHYS(p)))
- p->flags &= ~PG_CLEAN;
-
- if ((p->flags & PG_CLEAN) == 0)
- vm_pageout_clean(p, 0);
}
-
- vm_page_unlock_queues();
- p = next;
- }
- s = splbio();
- while (object->paging_in_progress) {
- tsleep((caddr_t)object,PVM,"vmfobw",0);
}
- splx(s);
- return dcount;
+ return anyok;
}
/*
@@ -376,7 +340,11 @@ vm_pageout_object_deactivate_pages(map, object, count)
count = 1;
if (object->shadow) {
- dcount += vm_pageout_object_deactivate_pages(map, object->shadow, count);
+ int scount = count;
+ if( object->shadow->ref_count > 1)
+ scount /= object->shadow->ref_count;
+ if( scount)
+ dcount += vm_pageout_object_deactivate_pages(map, object->shadow, scount);
}
if (object->paging_in_progress)
@@ -396,15 +364,28 @@ vm_pageout_object_deactivate_pages(map, object, count)
*/
if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE &&
p->wire_count == 0 &&
+ p->hold_count == 0 &&
pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) {
if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) {
- if (object->ref_count <= 1)
+ p->act_count -= min(p->act_count, ACT_DECLINE);
+ /*
+ * if the page act_count is zero -- then we deactivate
+ */
+ if (!p->act_count) {
vm_page_deactivate(p);
- else
- vm_page_pageout_deactivate(p);
- if (((p->flags & PG_INACTIVE)) &&
- (p->flags & PG_CLEAN) == 0)
- vm_pageout_clean(p, 0);
+ pmap_page_protect(VM_PAGE_TO_PHYS(p),
+ VM_PROT_NONE);
+ /*
+ * else if on the next go-around we will deactivate the page
+ * we need to place the page on the end of the queue to age
+ * the other pages in memory.
+ */
+ } else {
+ queue_remove(&vm_page_queue_active, p, vm_page_t, pageq);
+ queue_enter(&vm_page_queue_active, p, vm_page_t, pageq);
+ queue_remove(&object->memq, p, vm_page_t, listq);
+ queue_enter(&object->memq, p, vm_page_t, listq);
+ }
/*
* see if we are done yet
*/
@@ -419,23 +400,18 @@ vm_pageout_object_deactivate_pages(map, object, count)
}
} else {
- vm_pageout_deact_bump(p);
+ /*
+ * Move the page to the bottom of the queue.
+ */
pmap_clear_reference(VM_PAGE_TO_PHYS(p));
+ if (p->act_count < ACT_MAX)
+ p->act_count += ACT_ADVANCE;
+
queue_remove(&object->memq, p, vm_page_t, listq);
queue_enter(&object->memq, p, vm_page_t, listq);
queue_remove(&vm_page_queue_active, p, vm_page_t, pageq);
queue_enter(&vm_page_queue_active, p, vm_page_t, pageq);
}
- /*
- * if a page is inactive and has been modified, clean it now
- */
- } else if ((p->flags & (PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) {
- if ((p->flags & PG_CLEAN) &&
- pmap_is_modified(VM_PAGE_TO_PHYS(p)))
- p->flags &= ~PG_CLEAN;
-
- if ((p->flags & PG_CLEAN) == 0)
- vm_pageout_clean(p, 0);
}
vm_page_unlock_queues();
@@ -488,50 +464,28 @@ vm_pageout_map_deactivate_pages(map, entry, count, freeer)
return;
}
-void
-vm_fault_free_pages(p)
- struct proc *p;
-{
- int overage = 1;
- vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map,
- (vm_map_entry_t) 0, &overage, vm_fault_object_deactivate_pages);
-}
-
/*
* vm_pageout_scan does the dirty work for the pageout daemon.
*/
-void
+int
vm_pageout_scan()
{
vm_page_t m;
int page_shortage, maxscan, maxlaunder;
- int pages_freed, free, nproc, nbusy;
+ int pages_freed, free, nproc;
+ int desired_free;
vm_page_t next;
struct proc *p;
vm_object_t object;
int s;
+ int force_wakeup = 0;
+morefree:
/*
- * deactivate objects with ref_counts == 0
- */
- object = (vm_object_t) queue_first(&vm_object_list);
- while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
- if (object->ref_count == 0)
- vm_object_deactivate_pages(object);
- object = (vm_object_t) queue_next(&object->object_list);
- }
-
-rerun:
-#if 1
- /*
- * next scan the processes for exceeding their rlimits or if process
+ * scan the processes for exceeding their rlimits or if process
* is swapped out -- deactivate pages
*/
-rescanproc1a:
- for (p = allproc; p != NULL; p = p->p_nxt)
- p->p_flag &= ~SPAGEDAEMON;
-
rescanproc1:
for (p = allproc; p != NULL; p = p->p_nxt) {
vm_offset_t size;
@@ -572,22 +526,17 @@ rescanproc1:
overage = (size - limit) / NBPG;
vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map,
(vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages);
- p->p_flag |= SPAGEDAEMON;
- goto rescanproc1;
}
- p->p_flag |= SPAGEDAEMON;
+
}
-#if 0
if (((vm_page_free_count + vm_page_inactive_count) >=
(vm_page_inactive_target + vm_page_free_target)) &&
(vm_page_free_count >= vm_page_free_target))
- return;
-#endif
-
-#endif
+ return force_wakeup;
pages_freed = 0;
+ desired_free = vm_page_free_target;
/*
* Start scanning the inactive queue for pages we can free.
@@ -597,26 +546,37 @@ rescanproc1:
*/
maxlaunder = (vm_page_free_target - vm_page_free_count);
-rescan:
- m = (vm_page_t) queue_first(&vm_page_queue_inactive);
maxscan = vm_page_inactive_count;
+rescan1:
+ m = (vm_page_t) queue_first(&vm_page_queue_inactive);
while (maxscan-- > 0) {
vm_page_t next;
-
if (queue_end(&vm_page_queue_inactive, (queue_entry_t) m)
- || (vm_page_free_count >= vm_page_free_target)) {
+ || (vm_page_free_count >= desired_free)) {
break;
}
next = (vm_page_t) queue_next(&m->pageq);
+ if( (m->flags & PG_INACTIVE) == 0) {
+ printf("vm_pageout_scan: page not inactive?");
+ continue;
+ }
+
+ /*
+ * activate held pages
+ */
+ if (m->hold_count != 0) {
+ vm_page_activate(m);
+ m = next;
+ continue;
+ }
+
/*
* dont mess with busy pages
*/
if (m->flags & PG_BUSY) {
- queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
- queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
m = next;
continue;
}
@@ -628,34 +588,25 @@ rescan:
* vm system.
*/
if (m->flags & PG_CLEAN) {
- if ((vm_page_free_count > vm_pageout_free_min)
+ if ((vm_page_free_count > vm_pageout_free_min) /* XXX */
&& pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
vm_page_activate(m);
- ++vm_stat.reactivations;
- m = next;
- continue;
- }
- else {
+ } else if (!m->act_count) {
pmap_page_protect(VM_PAGE_TO_PHYS(m),
VM_PROT_NONE);
vm_page_free(m);
++pages_freed;
- m = next;
- continue;
+ } else {
+ m->act_count -= min(m->act_count, ACT_DECLINE);
}
} else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) {
- /*
- * if a page has been used even if it is in the laundry,
- * activate it.
- */
-
+ int written;
if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+ pmap_clear_reference(VM_PAGE_TO_PHYS(m));
vm_page_activate(m);
- m->flags &= ~PG_LAUNDRY;
m = next;
continue;
}
-
/*
* If a page is dirty, then it is either
* being washed (but not yet cleaned)
@@ -664,17 +615,18 @@ rescan:
* cleaning operation.
*/
- if (vm_pageout_clean(m,0)) {
- --maxlaunder;
- /*
- * if the next page has been re-activated, start scanning again
- */
- if ((next->flags & PG_INACTIVE) == 0)
- goto rescan;
+ if (written = vm_pageout_clean(m,0)) {
+ maxlaunder -= written;
}
- } else if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+ /*
+ * if the next page has been re-activated, start scanning again
+ */
+ if (!next || (next->flags & PG_INACTIVE) == 0)
+ goto rescan1;
+ } else if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+ pmap_clear_reference(VM_PAGE_TO_PHYS(m));
vm_page_activate(m);
- }
+ }
m = next;
}
@@ -682,42 +634,11 @@ rescan:
* now check malloc area or swap processes out if we are in low
* memory conditions
*/
- free = vm_page_free_count;
- if (free <= vm_page_free_min) {
- /*
- * Be sure the pmap system is updated so
- * we can scan the inactive queue.
- */
- pmap_update();
-
+ if (vm_page_free_count < vm_page_free_min) {
/*
* swap out inactive processes
*/
swapout_threads();
-
-#if 0
- /*
- * see if malloc has anything for us
- */
- if (free <= vm_page_free_reserved)
- malloc_gc();
-#endif
- }
-
-skipfree:
- /*
- * If we did not free any pages, but we need to do so, we grow the
- * inactive target. But as we successfully free pages, then we
- * shrink the inactive target.
- */
- if (pages_freed == 0 && vm_page_free_count < vm_page_free_min) {
- vm_page_inactive_target += (vm_page_free_min - vm_page_free_count);
- if (vm_page_inactive_target > vm_page_free_target*5)
- vm_page_inactive_target = vm_page_free_target*5;
- } else if (pages_freed > 0) {
- vm_page_inactive_target -= vm_page_free_min/2;
- if (vm_page_inactive_target < vm_page_free_target*2)
- vm_page_inactive_target = vm_page_free_target*2;
}
/*
@@ -726,35 +647,27 @@ skipfree:
* to inactive.
*/
-restart_inactivate_all:
-
- page_shortage = vm_page_inactive_target - vm_page_inactive_count;
- page_shortage -= vm_page_free_count;
+ page_shortage = vm_page_inactive_target -
+ (vm_page_free_count + vm_page_inactive_count);
if (page_shortage <= 0) {
- if (pages_freed == 0 &&
- ((vm_page_free_count + vm_page_inactive_count) <
+ if (pages_freed == 0) {
+ if( vm_page_free_count < vm_page_free_min) {
+ page_shortage = vm_page_free_min - vm_page_free_count;
+ } else if(((vm_page_free_count + vm_page_inactive_count) <
(vm_page_free_min + vm_page_inactive_target))) {
- page_shortage = 1;
- } else {
- page_shortage = 0;
+ page_shortage = 1;
+ } else {
+ page_shortage = 0;
+ }
}
+
}
- maxscan = vm_page_active_count;
-
- /*
- * deactivate pages that are active, but have not been used
- * for a while.
- */
-restart_inactivate:
m = (vm_page_t) queue_first(&vm_page_queue_active);
- while (maxscan-- > 0) {
+ maxscan = vm_page_active_count;
+ while (maxscan-- && (page_shortage > 0)) {
- if (page_shortage <= 0 &&
- maxscan < (vm_page_active_count - minscan) )
- break;
-
if (queue_end(&vm_page_queue_active, (queue_entry_t) m)) {
break;
}
@@ -762,109 +675,156 @@ restart_inactivate:
next = (vm_page_t) queue_next(&m->pageq);
/*
- * dont mess with pages that are busy
+ * Don't deactivate pages that are busy.
*/
- if (m->flags & PG_BUSY) {
+ if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
m = next;
continue;
}
- /*
- * Move some more pages from active to inactive.
- */
+ if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+ pmap_clear_reference(VM_PAGE_TO_PHYS(m));
+ if (m->act_count < ACT_MAX)
+ m->act_count += ACT_ADVANCE;
+ queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_remove(&m->object->memq, m, vm_page_t, listq);
+ queue_enter(&m->object->memq, m, vm_page_t, listq);
+ } else {
+ m->act_count -= min(m->act_count, ACT_DECLINE);
- /*
- * see if there are any pages that are able to be deactivated
- */
- /*
- * the referenced bit is the one that say that the page
- * has been used.
- */
- if (!pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
/*
- * if the page has not been referenced, call the
- * vm_page_pageout_deactivate routine. It might
- * not deactivate the page every time. There is
- * a policy associated with it.
+ * if the page act_count is zero -- then we deactivate
*/
- if (page_shortage > 0) {
- if (vm_page_pageout_deactivate(m)) {
- /*
- * if the page was really deactivated, then
- * decrement the page_shortage
- */
- if ((m->flags & PG_ACTIVE) == 0) {
- --page_shortage;
- }
- }
- }
- } else {
+ if (!m->act_count) {
+ vm_page_deactivate(m);
+ --page_shortage;
/*
- * if the page was recently referenced, set our
- * deactivate count and clear reference for a future
- * check for deactivation.
+ * else if on the next go-around we will deactivate the page
+ * we need to place the page on the end of the queue to age
+ * the other pages in memory.
*/
- vm_pageout_deact_bump(m);
- if (page_shortage > 0 || m->deact >= (DEACT_MAX/2))
- pmap_clear_reference(VM_PAGE_TO_PHYS(m));
- queue_remove(&m->object->memq, m, vm_page_t, listq);
- queue_enter(&m->object->memq, m, vm_page_t, listq);
- queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
- queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ } else {
+ queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_remove(&m->object->memq, m, vm_page_t, listq);
+ queue_enter(&m->object->memq, m, vm_page_t, listq);
+ }
}
+
m = next;
}
- vm_page_pagesfreed += pages_freed;
-}
+ /*
+ * if we have not freed any pages and we are desparate for memory
+ * then we keep trying until we get some (any) memory.
+ */
-/*
- * this code maintains a dynamic reference count per page
- */
-void
-vm_pageout_deact_bump(vm_page_t m) {
- if( m->deact >= DEACT_START) {
- m->deact += 1;
- if( m->deact > DEACT_MAX)
- m->deact = DEACT_MAX;
- } else {
- m->deact += DEACT_START;
+ if( !force_wakeup && (swap_pager_full || !force_wakeup ||
+ (pages_freed == 0 && (vm_page_free_count < vm_page_free_min)))){
+ vm_pager_sync();
+ force_wakeup = 1;
+ goto morefree;
}
+ vm_page_pagesfreed += pages_freed;
+ return force_wakeup;
}
-/*
- * optionally do a deactivate if the deactivate has been done
- * enough to justify it.
- */
-int
-vm_page_pageout_deactivate(m)
- vm_page_t m;
+void
+vm_pagescan()
{
+ int maxscan, pages_scanned, pages_referenced, nextscan, scantick = hz/20;
+ int m_ref, next_ref;
+ vm_page_t m, next;
+
+ (void) splnone();
+
+ nextscan = scantick;
- switch (m->deact) {
-case DEACT_FREE:
- vm_page_deactivate(m);
- return 1;
-case DEACT_CLEAN:
- break;
-case DEACT_DELAY:
- vm_page_makefault(m);
-case DEACT_START:
- break;
+scanloop:
+
+ pages_scanned = 0;
+ pages_referenced = 0;
+ maxscan = min(vm_page_active_count, MAXSCAN);
+
+ /*
+ * Gather statistics on page usage.
+ */
+ m = (vm_page_t) queue_first(&vm_page_queue_active);
+ while (maxscan-- > 0) {
+
+ if (queue_end(&vm_page_queue_active, (queue_entry_t) m)) {
+ break;
+ }
+
+ ++pages_scanned;
+
+ next = (vm_page_t) queue_next(&m->pageq);
+
+ /*
+ * Dont mess with pages that are busy.
+ */
+ if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
+ m = next;
+ continue;
+ }
+
+ /*
+ * Advance pages that have been referenced, decline pages that
+ * have not.
+ */
+ if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+ pmap_clear_reference(VM_PAGE_TO_PHYS(m));
+ pages_referenced++;
+ if (m->act_count < ACT_MAX)
+ m->act_count += ACT_ADVANCE;
+ queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_remove(&m->object->memq, m, vm_page_t, listq);
+ queue_enter(&m->object->memq, m, vm_page_t, listq);
+ } else {
+ m->act_count -= min(m->act_count, ACT_DECLINE);
+ /*
+ * if the page act_count is zero, and we are low on mem -- then we deactivate
+ */
+ if (!m->act_count &&
+ (vm_page_free_count+vm_page_inactive_count < vm_page_free_target+vm_page_inactive_target )) {
+ vm_page_deactivate(m);
+ /*
+ * else if on the next go-around we will deactivate the page
+ * we need to place the page on the end of the queue to age
+ * the other pages in memory.
+ */
+ } else {
+ queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
+ queue_remove(&m->object->memq, m, vm_page_t, listq);
+ queue_enter(&m->object->memq, m, vm_page_t, listq);
+ }
+ }
+ m = next;
}
- --m->deact;
- return 0;
+
+ if (pages_referenced) {
+ nextscan = (pages_scanned / pages_referenced) * scantick;
+ nextscan = max(nextscan, scantick);
+ nextscan = min(nextscan, hz);
+ } else
+ nextscan = hz;
+ tsleep((caddr_t) &vm_pagescanner, PVM, "scanw", nextscan);
+
+ goto scanloop;
}
/*
* vm_pageout is the high level pageout daemon.
*/
-
void
vm_pageout()
{
extern npendingio, swiopend;
extern int vm_page_count;
+ static nowakeup;
(void) spl0();
/*
@@ -872,49 +832,42 @@ vm_pageout()
*/
vmretry:
- vm_page_free_min = npendingio/3;
-#ifdef VSMALL
- vm_page_free_min = 8;
-#endif
+ vm_page_free_min = 12;
vm_page_free_reserved = 8;
if (vm_page_free_min < 8)
vm_page_free_min = 8;
if (vm_page_free_min > 32)
vm_page_free_min = 32;
- vm_pageout_free_min = 3;
+ vm_pageout_free_min = 4;
vm_page_free_target = 2*vm_page_free_min + vm_page_free_reserved;
- vm_page_inactive_target = 3*vm_page_free_min + vm_page_free_reserved;
+ vm_page_inactive_target = vm_page_free_count / 12;
vm_page_free_min += vm_page_free_reserved;
- minscan = MINSCAN;
- if (minscan > vm_page_count/3)
- minscan = vm_page_count/3;
+
+ (void) swap_pager_alloc(0, 0, 0, 0);
/*
* The pageout daemon is never done, so loop
* forever.
*/
-
-
while (TRUE) {
+ int force_wakeup;
- splhigh();
- if (vm_page_free_count > vm_page_free_min) {
- wakeup((caddr_t) &vm_page_free_count);
- tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0);
- } else {
- if (nswiodone) {
- spl0();
- goto dosync;
- }
- tsleep((caddr_t) &vm_pages_needed, PVM, "pslp1", 5);
- }
- spl0();
-
+ tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0);
+
vm_pager_sync();
- vm_pageout_scan();
- dosync:
+ /*
+ * The force wakeup hack added to eliminate delays and potiential
+ * deadlock. It was possible for the page daemon to indefintely
+ * postpone waking up a process that it might be waiting for memory
+ * on. The putmulti stuff seems to have aggravated the situation.
+ */
+ force_wakeup = vm_pageout_scan();
vm_pager_sync();
+ if( force_wakeup)
+ wakeup( (caddr_t) &vm_page_free_count);
+ vm_pageout_do_stats = 0;
cnt.v_scan++;
wakeup((caddr_t) kmem_map);
}
}
+
diff --git a/sys/vm/vm_pageout.h b/sys/vm/vm_pageout.h
index d975d8006fd3..a80605967ec8 100644
--- a/sys/vm/vm_pageout.h
+++ b/sys/vm/vm_pageout.h
@@ -86,6 +86,8 @@ simple_lock_data_t vm_pages_needed_lock;
inline static void vm_wait() {
extern struct proc *curproc, *pageproc;
extern int vm_pageout_pages_needed;
+ int s;
+ s = splhigh();
if (curproc == pageproc) {
vm_pageout_pages_needed = 1;
tsleep((caddr_t) &vm_pageout_pages_needed, PSWP, "vmwait", 0);
@@ -94,6 +96,7 @@ inline static void vm_wait() {
wakeup((caddr_t) &vm_pages_needed);
tsleep((caddr_t) &vm_page_free_count, PVM, "vmwait", 0);
}
+ splx(s);
}
diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c
index d31be45a430f..f1138e1db3f3 100644
--- a/sys/vm/vm_pager.c
+++ b/sys/vm/vm_pager.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_pager.c 7.4 (Berkeley) 5/7/91
- * $Id: vm_pager.c,v 1.10 1994/01/31 04:21:43 davidg Exp $
+ * $Id: vm_pager.c,v 1.11 1994/03/07 11:39:16 davidg Exp $
*/
/*
@@ -167,6 +167,26 @@ vm_pager_getmulti(pager, m, count, reqpage, sync)
}
int
+vm_pager_putmulti(pager, m, count, sync, rtvals)
+ vm_pager_t pager;
+ vm_page_t *m;
+ int count;
+ boolean_t sync;
+ int *rtvals;
+{
+ int i;
+
+ if( pager->pg_ops->pgo_putmulti)
+ return(VM_PAGER_PUT_MULTI(pager, m, count, sync, rtvals));
+ else {
+ for(i=0;i<count;i++) {
+ rtvals[i] = VM_PAGER_PUT( pager, m[i], sync);
+ }
+ return 1;
+ }
+}
+
+int
vm_pager_get(pager, m, sync)
vm_pager_t pager;
vm_page_t m;
diff --git a/sys/vm/vm_pager.h b/sys/vm/vm_pager.h
index 699881ab51a3..2cf52674fab2 100644
--- a/sys/vm/vm_pager.h
+++ b/sys/vm/vm_pager.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_pager.h 7.2 (Berkeley) 4/20/91
- * $Id: vm_pager.h,v 1.6 1994/01/31 04:21:50 davidg Exp $
+ * $Id: vm_pager.h,v 1.7 1994/03/07 11:39:17 davidg Exp $
*/
/*
@@ -69,6 +69,7 @@ struct pagerops {
int (*pgo_getpage)(); /* get (read) page */
int (*pgo_getmulti)(); /* get (read) multiple pages */
int (*pgo_putpage)(); /* put (write) page */
+ int (*pgo_putmulti)(); /* get (read) multiple pages */
boolean_t (*pgo_haspage)(); /* does pager have page? */
};
@@ -91,6 +92,7 @@ struct pagerops {
#define VM_PAGER_GET(pg, m, s) (*(pg)->pg_ops->pgo_getpage)(pg, m, s)
#define VM_PAGER_GET_MULTI(pg, m, c, r, s) (*(pg)->pg_ops->pgo_getmulti)(pg, m, c, r, s)
#define VM_PAGER_PUT(pg, m, s) (*(pg)->pg_ops->pgo_putpage)(pg, m, s)
+#define VM_PAGER_PUT_MULTI(pg, m, c, s, rtval) (*(pg)->pg_ops->pgo_putmulti)(pg, m, c, s, rtval)
#define VM_PAGER_HASPAGE(pg, o) (*(pg)->pg_ops->pgo_haspage)(pg, o)
#ifdef KERNEL
diff --git a/sys/vm/vm_swap.c b/sys/vm/vm_swap.c
index 0a8a57457101..462948c8703b 100644
--- a/sys/vm/vm_swap.c
+++ b/sys/vm/vm_swap.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_swap.c 7.18 (Berkeley) 5/6/91
- * $Id: vm_swap.c,v 1.7 1993/12/19 00:56:15 wollman Exp $
+ * $Id: vm_swap.c,v 1.8 1994/03/14 21:54:32 davidg Exp $
*/
#include "param.h"
@@ -48,6 +48,7 @@
#include "kernel.h"
static int swfree(struct proc *, int);
+int vm_swap_size;
/*
* Indirect driver for multi-controller paging.
@@ -264,6 +265,7 @@ swfree(p, index)
if (blk > dmmax)
blk = dmmax;
rlist_free(&swapmap, vsbase, vsbase + blk - 1);
+ vm_swap_size += blk;
}
return (0);
}
diff --git a/sys/vm/vm_unix.c b/sys/vm/vm_unix.c
index 169bf376357b..f1127e2b07de 100644
--- a/sys/vm/vm_unix.c
+++ b/sys/vm/vm_unix.c
@@ -37,7 +37,7 @@
*
* from: Utah $Hdr: vm_unix.c 1.1 89/11/07$
* from: @(#)vm_unix.c 7.2 (Berkeley) 4/20/91
- * $Id: vm_unix.c,v 1.5 1993/12/12 12:27:26 davidg Exp $
+ * $Id: vm_unix.c,v 1.6 1994/03/14 21:54:33 davidg Exp $
*/
/*
@@ -50,6 +50,8 @@
#include "vm.h"
+extern int swap_pager_full;
+
struct obreak_args {
char *nsiz;
};
@@ -73,9 +75,11 @@ obreak(p, uap, retval)
old = round_page(old + ctob(vm->vm_dsize));
diff = new - old;
if (diff > 0) {
+ if (swap_pager_full) {
+ return(ENOMEM);
+ }
rv = vm_allocate(&vm->vm_map, &old, diff, FALSE);
if (rv != KERN_SUCCESS) {
- uprintf("sbrk: grow failed, return = %d\n", rv);
return(ENOMEM);
}
vm->vm_dsize += btoc(diff);
@@ -83,7 +87,6 @@ obreak(p, uap, retval)
diff = -diff;
rv = vm_deallocate(&vm->vm_map, new, diff);
if (rv != KERN_SUCCESS) {
- uprintf("sbrk: shrink failed, return = %d\n", rv);
return(ENOMEM);
}
vm->vm_dsize -= btoc(diff);
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index c35971ba67e0..d44e12e22ac6 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -2,7 +2,7 @@
* Copyright (c) 1990 University of Utah.
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
- * Copyright (c) 1993 John S. Dyson
+ * Copyright (c) 1993,1994 John S. Dyson
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
@@ -37,7 +37,7 @@
* SUCH DAMAGE.
*
* from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91
- * $Id: vnode_pager.c,v 1.11.2.3 1994/04/18 04:57:49 rgrimes Exp $
+ * $Id: vnode_pager.c,v 1.21 1994/06/22 05:53:12 jkh Exp $
*/
/*
@@ -57,7 +57,7 @@
*
* 1) Supports multiple - block reads
* 2) Bypasses buffer cache for reads
- *
+ *
* TODO:
*
* 1) Totally bypass buffer cache for reads
@@ -86,6 +86,8 @@
#include "buf.h"
#include "specdev.h"
+int vnode_pager_putmulti();
+
struct pagerops vnodepagerops = {
vnode_pager_init,
vnode_pager_alloc,
@@ -93,35 +95,24 @@ struct pagerops vnodepagerops = {
vnode_pager_getpage,
vnode_pager_getmulti,
vnode_pager_putpage,
+ vnode_pager_putmulti,
vnode_pager_haspage
};
-static int vnode_pager_io(vn_pager_t vnp, vm_page_t *m, int count, int reqpage,
- enum uio_rw rw);
-struct buf * getpbuf() ;
-void relpbuf(struct buf *bp) ;
+static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage);
+static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals);
+struct buf * getpbuf();
+void relpbuf(struct buf * bp);
extern vm_map_t pager_map;
-queue_head_t vnode_pager_list; /* list of managed vnodes */
+queue_head_t vnode_pager_list; /* list of managed vnodes */
-#ifdef DEBUG
-int vpagerdebug = 0x00;
-#define VDB_FOLLOW 0x01
-#define VDB_INIT 0x02
-#define VDB_IO 0x04
-#define VDB_FAIL 0x08
-#define VDB_ALLOC 0x10
-#define VDB_SIZE 0x20
-#endif
+#define MAXBP (NBPG/DEV_BSIZE);
void
vnode_pager_init()
{
-#ifdef DEBUG
- if (vpagerdebug & VDB_FOLLOW)
- printf("vnode_pager_init()\n");
-#endif
queue_init(&vnode_pager_list);
}
@@ -143,34 +134,32 @@ vnode_pager_alloc(handle, size, prot, offset)
struct vnode *vp;
struct proc *p = curproc; /* XXX */
-#ifdef DEBUG
- if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC))
- printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot);
-#endif
/*
* Pageout to vnode, no can do yet.
*/
if (handle == NULL)
- return(NULL);
+ return (NULL);
/*
- * Vnodes keep a pointer to any associated pager so no need to
- * lookup with vm_pager_lookup.
+ * Vnodes keep a pointer to any associated pager so no need to lookup
+ * with vm_pager_lookup.
*/
- vp = (struct vnode *)handle;
- pager = (vm_pager_t)vp->v_vmdata;
+ vp = (struct vnode *) handle;
+ pager = (vm_pager_t) vp->v_vmdata;
if (pager == NULL) {
+
/*
* Allocate pager structures
*/
- pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
+ pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
if (pager == NULL)
- return(NULL);
- vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
+ return (NULL);
+ vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
if (vnp == NULL) {
- free((caddr_t)pager, M_VMPAGER);
- return(NULL);
+ free((caddr_t) pager, M_VMPAGER);
+ return (NULL);
}
+
/*
* And an object of the appropriate size
*/
@@ -179,10 +168,11 @@ vnode_pager_alloc(handle, size, prot, offset)
vm_object_enter(object, pager);
vm_object_setpager(object, pager, 0, TRUE);
} else {
- free((caddr_t)vnp, M_VMPGDATA);
- free((caddr_t)pager, M_VMPAGER);
- return(NULL);
+ free((caddr_t) vnp, M_VMPGDATA);
+ free((caddr_t) pager, M_VMPAGER);
+ return (NULL);
}
+
/*
* Hold a reference to the vnode and initialize pager data.
*/
@@ -190,42 +180,32 @@ vnode_pager_alloc(handle, size, prot, offset)
vnp->vnp_flags = 0;
vnp->vnp_vp = vp;
vnp->vnp_size = vattr.va_size;
+
queue_enter(&vnode_pager_list, pager, vm_pager_t, pg_list);
pager->pg_handle = handle;
pager->pg_type = PG_VNODE;
pager->pg_ops = &vnodepagerops;
- pager->pg_data = (caddr_t)vnp;
- vp->v_vmdata = (caddr_t)pager;
+ pager->pg_data = (caddr_t) vnp;
+ vp->v_vmdata = (caddr_t) pager;
} else {
+
/*
- * vm_object_lookup() will remove the object from the
- * cache if found and also gain a reference to the object.
+ * vm_object_lookup() will remove the object from the cache if
+ * found and also gain a reference to the object.
*/
object = vm_object_lookup(pager);
-#ifdef DEBUG
- vnp = (vn_pager_t)pager->pg_data;
-#endif
}
-#ifdef DEBUG
- if (vpagerdebug & VDB_ALLOC)
- printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n",
- vp, vnp->vnp_size, pager, object);
-#endif
- return(pager);
+ return (pager);
}
void
vnode_pager_dealloc(pager)
vm_pager_t pager;
{
- register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
+ register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
register struct vnode *vp;
- struct proc *p = curproc; /* XXX */
+ struct proc *p = curproc; /* XXX */
-#ifdef DEBUG
- if (vpagerdebug & VDB_FOLLOW)
- printf("vnode_pager_dealloc(%x)\n", pager);
-#endif
if (vp = vnp->vnp_vp) {
vp->v_vmdata = NULL;
vp->v_flag &= ~VTEXT;
@@ -236,22 +216,21 @@ vnode_pager_dealloc(pager)
vrele(vp);
}
queue_remove(&vnode_pager_list, pager, vm_pager_t, pg_list);
- free((caddr_t)vnp, M_VMPGDATA);
- free((caddr_t)pager, M_VMPAGER);
+ free((caddr_t) vnp, M_VMPGDATA);
+ free((caddr_t) pager, M_VMPAGER);
}
int
vnode_pager_getmulti(pager, m, count, reqpage, sync)
vm_pager_t pager;
vm_page_t *m;
- int count;
- int reqpage;
+ int count;
+ int reqpage;
boolean_t sync;
{
-
- return vnode_pager_io((vn_pager_t) pager->pg_data, m, count, reqpage, UIO_READ);
-}
+ return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage);
+}
int
vnode_pager_getpage(pager, m, sync)
@@ -260,17 +239,14 @@ vnode_pager_getpage(pager, m, sync)
boolean_t sync;
{
- int err;
+ int err;
vm_page_t marray[1];
-#ifdef DEBUG
- if (vpagerdebug & VDB_FOLLOW)
- printf("vnode_pager_getpage(%x, %x)\n", pager, m);
-#endif
+
if (pager == NULL)
return FALSE;
marray[0] = m;
- return vnode_pager_io((vn_pager_t)pager->pg_data, marray, 1, 0, UIO_READ);
+ return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0);
}
boolean_t
@@ -279,69 +255,61 @@ vnode_pager_putpage(pager, m, sync)
vm_page_t m;
boolean_t sync;
{
- int err;
+ int err;
vm_page_t marray[1];
+ int rtvals[1];
-#ifdef DEBUG
- if (vpagerdebug & VDB_FOLLOW)
- printf("vnode_pager_putpage(%x, %x)\n", pager, m);
-#endif
if (pager == NULL)
return FALSE;
marray[0] = m;
- err = vnode_pager_io((vn_pager_t)pager->pg_data, marray, 1, 0, UIO_WRITE);
- return err;
+ vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals);
+ return rtvals[0];
+}
+
+int
+vnode_pager_putmulti(pager, m, c, sync, rtvals)
+ vm_pager_t pager;
+ vm_page_t *m;
+ int c;
+ boolean_t sync;
+ int *rtvals;
+{
+ return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals);
}
+
boolean_t
vnode_pager_haspage(pager, offset)
vm_pager_t pager;
vm_offset_t offset;
{
- register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
+ register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
daddr_t bn;
- int err;
-
-#ifdef DEBUG
- if (vpagerdebug & VDB_FOLLOW)
- printf("vnode_pager_haspage(%x, %x)\n", pager, offset);
-#endif
+ int err;
/*
* Offset beyond end of file, do not have the page
*/
if (offset >= vnp->vnp_size) {
-#ifdef DEBUG
- if (vpagerdebug & (VDB_FAIL|VDB_SIZE))
- printf("vnode_pager_haspage: pg %x, off %x, size %x\n",
- pager, offset, vnp->vnp_size);
-#endif
- return(FALSE);
+ return (FALSE);
}
/*
- * Read the index to find the disk block to read
- * from. If there is no block, report that we don't
- * have this data.
- *
+ * Read the index to find the disk block to read from. If there is no
+ * block, report that we don't have this data.
+ *
* Assumes that the vnode has whole page or nothing.
*/
err = VOP_BMAP(vnp->vnp_vp,
offset / vnp->vnp_vp->v_mount->mnt_stat.f_bsize,
- (struct vnode **)0, &bn);
+ (struct vnode **) 0, &bn);
if (err) {
-#ifdef DEBUG
- if (vpagerdebug & VDB_FAIL)
- printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n",
- err, pager, offset);
-#endif
- return(TRUE);
+ return (TRUE);
}
- return((long)bn < 0 ? FALSE : TRUE);
+ return ((long) bn < 0 ? FALSE : TRUE);
}
/*
- * (XXX)
* Lets the VM system know about a change in size for a file.
* If this vnode is mapped into some address space (i.e. we have a pager
* for it) we adjust our own internal size and flush any cached pages in
@@ -353,7 +321,7 @@ vnode_pager_haspage(pager, offset)
void
vnode_pager_setsize(vp, nsize)
struct vnode *vp;
- u_long nsize;
+ u_long nsize;
{
register vn_pager_t vnp;
register vm_object_t object;
@@ -364,42 +332,73 @@ vnode_pager_setsize(vp, nsize)
*/
if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
return;
+
/*
* Hasn't changed size
*/
- pager = (vm_pager_t)vp->v_vmdata;
- vnp = (vn_pager_t)pager->pg_data;
+ pager = (vm_pager_t) vp->v_vmdata;
+ vnp = (vn_pager_t) pager->pg_data;
if (nsize == vnp->vnp_size)
return;
+
/*
- * No object.
- * This can happen during object termination since
- * vm_object_page_clean is called after the object
- * has been removed from the hash table, and clean
- * may cause vnode write operations which can wind
- * up back here.
+ * No object. This can happen during object termination since
+ * vm_object_page_clean is called after the object has been removed
+ * from the hash table, and clean may cause vnode write operations
+ * which can wind up back here.
*/
object = vm_object_lookup(pager);
if (object == NULL)
return;
-#ifdef DEBUG
- if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE))
- printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n",
- vp, object, vnp->vnp_size, nsize);
-#endif
-
/*
- * File has shrunk.
- * Toss any cached pages beyond the new EOF.
+ * File has shrunk. Toss any cached pages beyond the new EOF.
*/
- if (round_page(nsize) < round_page(vnp->vnp_size)) {
+ if (nsize < vnp->vnp_size) {
vm_object_lock(object);
vm_object_page_remove(object,
- (vm_offset_t)round_page(nsize), round_page(vnp->vnp_size));
+ round_page((vm_offset_t) nsize), vnp->vnp_size);
vm_object_unlock(object);
+
+ /*
+ * this gets rid of garbage at the end of a page that is now
+ * only partially backed by the vnode...
+ */
+ if (nsize & PAGE_MASK) {
+ vm_offset_t kva;
+ vm_page_t m;
+
+ m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize));
+ if (m) {
+ kva = vm_pager_map_page(m);
+ bzero((caddr_t) kva + (nsize & PAGE_MASK),
+ round_page(nsize) - nsize);
+ vm_pager_unmap_page(kva);
+ }
+ }
+ } else {
+
+ /*
+ * this allows the filesystem and VM cache to stay in sync if
+ * the VM page hasn't been modified... After the page is
+ * removed -- it will be faulted back in from the filesystem
+ * cache.
+ */
+ if (vnp->vnp_size & PAGE_MASK) {
+ vm_page_t m;
+
+ m = vm_page_lookup(object, trunc_page(vnp->vnp_size));
+ if (m && (m->flags & PG_CLEAN)) {
+ vm_object_lock(object);
+ vm_object_page_remove(object,
+ vnp->vnp_size, vnp->vnp_size);
+ vm_object_unlock(object);
+ }
+ }
}
- vnp->vnp_size = (vm_offset_t)nsize;
+ vnp->vnp_size = (vm_offset_t) nsize;
+ object->size = round_page(nsize);
+
vm_object_deallocate(object);
}
@@ -411,14 +410,15 @@ vnode_pager_umount(mp)
struct vnode *vp;
pager = (vm_pager_t) queue_first(&vnode_pager_list);
- while (!queue_end(&vnode_pager_list, (queue_entry_t)pager)) {
+ while (!queue_end(&vnode_pager_list, (queue_entry_t) pager)) {
+
/*
- * Save the next pointer now since uncaching may
- * terminate the object and render pager invalid
+ * Save the next pointer now since uncaching may terminate the
+ * object and render pager invalid
*/
- vp = ((vn_pager_t)pager->pg_data)->vnp_vp;
+ vp = ((vn_pager_t) pager->pg_data)->vnp_vp;
npager = (vm_pager_t) queue_next(&pager->pg_list);
- if (mp == (struct mount *)0 || vp->v_mount == mp)
+ if (mp == (struct mount *) 0 || vp->v_mount == mp)
(void) vnode_pager_uncache(vp);
pager = npager;
}
@@ -441,21 +441,22 @@ vnode_pager_uncache(vp)
/*
* Not a mapped vnode
*/
- pager = (vm_pager_t)vp->v_vmdata;
+ pager = (vm_pager_t) vp->v_vmdata;
if (pager == NULL)
return (TRUE);
+
/*
- * Unlock the vnode if it is currently locked.
- * We do this since uncaching the object may result
- * in its destruction which may initiate paging
- * activity which may necessitate locking the vnode.
+ * Unlock the vnode if it is currently locked. We do this since
+ * uncaching the object may result in its destruction which may
+ * initiate paging activity which may necessitate locking the vnode.
*/
locked = VOP_ISLOCKED(vp);
if (locked)
VOP_UNLOCK(vp);
+
/*
- * Must use vm_object_lookup() as it actually removes
- * the object from the cache list.
+ * Must use vm_object_lookup() as it actually removes the object from
+ * the cache list.
*/
object = vm_object_lookup(pager);
if (object) {
@@ -465,7 +466,7 @@ vnode_pager_uncache(vp)
uncached = TRUE;
if (locked)
VOP_LOCK(vp);
- return(uncached);
+ return (uncached);
}
@@ -486,20 +487,23 @@ vnode_pager_addr(vp, address)
struct vnode *vp;
vm_offset_t address;
{
- int rtaddress;
- int bsize;
+ int rtaddress;
+ int bsize;
vm_offset_t block;
struct vnode *rtvp;
- int err;
- int vblock, voffset;
+ int err;
+ int vblock, voffset;
bsize = vp->v_mount->mnt_stat.f_bsize;
vblock = address / bsize;
voffset = address % bsize;
- err = VOP_BMAP(vp,vblock,&rtvp,&block);
+ err = VOP_BMAP(vp, vblock, &rtvp, &block);
- rtaddress = block * DEV_BSIZE + voffset;
+ if (err)
+ rtaddress = -1;
+ else
+ rtaddress = block * DEV_BSIZE + voffset;
return rtaddress;
}
@@ -512,411 +516,540 @@ vnode_pager_iodone(bp)
struct buf *bp;
{
bp->b_flags |= B_DONE;
- wakeup((caddr_t)bp);
+ wakeup((caddr_t) bp);
}
/*
- * vnode_pager_io:
- * Perform read or write operation for vnode_paging
- *
- * args:
- * vnp -- pointer to vnode pager data structure
- * containing size and vnode pointer, etc
- *
- * m -- pointer to array of vm_page_t entries to
- * do I/O to. It is not necessary to fill any
- * pages except for the reqpage entry. If a
- * page is not filled, it needs to be removed
- * from its object...
- *
- * count -- number of pages for I/O
- *
- * reqpage -- fault requested page for I/O
- * (index into vm_page_t entries above)
- *
- * rw -- UIO_READ or UIO_WRITE
- *
- * NOTICE!!!! direct writes look like that they are close to being
- * implemented. They are not really, several things need
- * to be done to make it work (subtile things.) Hack at
- * your own risk (direct writes are scarey).
- *
- * ANOTHER NOTICE!!!!
- * we currently only support direct I/O to filesystems whose
- * contiguously allocated blocksize is at least a vm page.
- * changes will be made in the future to support more flexibility.
+ * small block file system vnode pager input
+ */
+int
+vnode_pager_input_smlfs(vnp, m)
+ vn_pager_t vnp;
+ vm_page_t m;
+{
+ int i;
+ int s;
+ vm_offset_t paging_offset;
+ struct vnode *dp, *vp;
+ struct buf *bp;
+ vm_offset_t mapsize;
+ vm_offset_t foff;
+ vm_offset_t kva;
+ int fileaddr;
+ int block;
+ vm_offset_t bsize;
+ int error = 0;
+
+ paging_offset = m->object->paging_offset;
+ vp = vnp->vnp_vp;
+ bsize = vp->v_mount->mnt_stat.f_bsize;
+ foff = m->offset + paging_offset;
+
+ VOP_BMAP(vp, foff, &dp, 0);
+
+ kva = vm_pager_map_page(m);
+
+ for (i = 0; i < NBPG / bsize; i++) {
+
+ /*
+ * calculate logical block and offset
+ */
+ block = foff / bsize + i;
+ s = splbio();
+ while (bp = incore(vp, block)) {
+ int amount;
+
+ /*
+ * wait until the buffer is avail or gone
+ */
+ if (bp->b_flags & B_BUSY) {
+ bp->b_flags |= B_WANTED;
+ tsleep((caddr_t) bp, PVM, "vnwblk", 0);
+ continue;
+ }
+ amount = bsize;
+ if ((foff + bsize) > vnp->vnp_size)
+ amount = vnp->vnp_size - foff;
+
+ /*
+ * make sure that this page is in the buffer
+ */
+ if ((amount > 0) && amount <= bp->b_bcount) {
+ bp->b_flags |= B_BUSY;
+ splx(s);
+
+ /*
+ * copy the data from the buffer
+ */
+ bcopy(bp->b_un.b_addr, (caddr_t) kva + i * bsize, amount);
+ if (amount < bsize) {
+ bzero((caddr_t) kva + amount, bsize - amount);
+ }
+ bp->b_flags &= ~B_BUSY;
+ wakeup((caddr_t) bp);
+ goto nextblock;
+ }
+ break;
+ }
+ splx(s);
+ fileaddr = vnode_pager_addr(vp, foff + i * bsize);
+ if (fileaddr != -1) {
+ VHOLD(vp);
+ bp = getpbuf();
+
+ /* build a minimal buffer header */
+ bp->b_flags = B_BUSY | B_READ | B_CALL;
+ bp->b_iodone = vnode_pager_iodone;
+ bp->b_proc = curproc;
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ bp->b_un.b_addr = (caddr_t) kva + i * bsize;
+ bp->b_blkno = fileaddr / DEV_BSIZE;
+ bp->b_vp = dp;
+
+ /*
+ * Should be a BLOCK or character DEVICE if we get
+ * here
+ */
+ bp->b_dev = dp->v_rdev;
+ bp->b_bcount = bsize;
+ bp->b_bufsize = bsize;
+
+ /* do the input */
+ VOP_STRATEGY(bp);
+
+ /* we definitely need to be at splbio here */
+
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0) {
+ tsleep((caddr_t) bp, PVM, "vnsrd", 0);
+ }
+ splx(s);
+ if ((bp->b_flags & B_ERROR) != 0)
+ error = EIO;
+
+ HOLDRELE(vp);
+
+ /*
+ * free the buffer header back to the swap buffer pool
+ */
+ relpbuf(bp);
+ if (error)
+ break;
+ } else {
+ bzero((caddr_t) kva + i * bsize, bsize);
+ }
+nextblock:
+ }
+ vm_pager_unmap_page(kva);
+ if (error) {
+ return VM_PAGER_FAIL;
+ }
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m));
+ m->flags |= PG_CLEAN;
+ m->flags &= ~PG_LAUNDRY;
+ return VM_PAGER_OK;
+
+}
+
+
+/*
+ * old style vnode pager output routine
*/
+int
+vnode_pager_input_old(vnp, m)
+ vn_pager_t vnp;
+ vm_page_t m;
+{
+ int i;
+ struct uio auio;
+ struct iovec aiov;
+ int error;
+ int size;
+ vm_offset_t foff;
+ vm_offset_t kva;
+
+ error = 0;
+ foff = m->offset + m->object->paging_offset;
+ /*
+ * Return failure if beyond current EOF
+ */
+ if (foff >= vnp->vnp_size) {
+ return VM_PAGER_BAD;
+ } else {
+ size = NBPG;
+ if (foff + size > vnp->vnp_size)
+ size = vnp->vnp_size - foff;
+/*
+ * Allocate a kernel virtual address and initialize so that
+ * we can use VOP_READ/WRITE routines.
+ */
+ kva = vm_pager_map_page(m);
+ aiov.iov_base = (caddr_t) kva;
+ aiov.iov_len = size;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = foff;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_resid = size;
+ auio.uio_procp = (struct proc *) 0;
+
+ error = VOP_READ(vnp->vnp_vp, &auio, IO_PAGER, curproc->p_ucred);
+ if (!error) {
+ register int count = size - auio.uio_resid;
+
+ if (count == 0)
+ error = EINVAL;
+ else if (count != NBPG)
+ bzero((caddr_t) kva + count, NBPG - count);
+ }
+ vm_pager_unmap_page(kva);
+ }
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m));
+ m->flags |= PG_CLEAN;
+ m->flags &= ~PG_LAUNDRY;
+ return error ? VM_PAGER_FAIL : VM_PAGER_OK;
+}
+
+/*
+ * generic vnode pager input routine
+ */
int
-vnode_pager_io(vnp, m, count, reqpage, rw)
+vnode_pager_input(vnp, m, count, reqpage)
register vn_pager_t vnp;
vm_page_t *m;
- int count, reqpage;
- enum uio_rw rw;
+ int count, reqpage;
{
- int i,j;
- struct uio auio;
- struct iovec aiov;
+ int i, j;
vm_offset_t kva, foff;
- int size;
- struct proc *p = curproc; /* XXX */
+ int size;
+ struct proc *p = curproc; /* XXX */
vm_object_t object;
vm_offset_t paging_offset;
struct vnode *dp, *vp;
vm_offset_t mapsize;
- int bsize;
- int errtype=0; /* 0 is file type otherwise vm type */
- int error = 0;
- int trimmed;
+ int bsize;
+
+ int first, last;
+ int reqaddr, firstaddr;
+ int block, offset;
- object = m[reqpage]->object; /* all vm_page_t items are in same object */
+ int nbp;
+ struct buf *bp;
+ int s;
+ int failflag;
+
+ int errtype = 0; /* 0 is file type otherwise vm type */
+ int error = 0;
+
+ object = m[reqpage]->object; /* all vm_page_t items are in same
+ * object */
paging_offset = object->paging_offset;
vp = vnp->vnp_vp;
bsize = vp->v_mount->mnt_stat.f_bsize;
/* get the UNDERLYING device for the file with VOP_BMAP() */
+
/*
- * originally, we did not check for an error return
- * value -- assuming an fs always has a bmap entry point
- * -- that assumption is wrong!!!
- */
- /*
- * we only do direct I/O if the file is on a local
- * BLOCK device and currently if it is a read operation only.
+ * originally, we did not check for an error return value -- assuming
+ * an fs always has a bmap entry point -- that assumption is wrong!!!
*/
kva = 0;
mapsize = 0;
- if (!VOP_BMAP(vp, m[reqpage]->offset+paging_offset, &dp, 0) &&
- rw == UIO_READ && ((dp->v_type == VBLK &&
- (vp->v_mount->mnt_stat.f_type == MOUNT_UFS)) ||
- (vp->v_mount->mnt_stat.f_type == MOUNT_NFS))) {
+ foff = m[reqpage]->offset + paging_offset;
+ if (!VOP_BMAP(vp, foff, &dp, 0)) {
+
/*
* we do not block for a kva, notice we default to a kva
* conservative behavior
*/
- kva = kmem_alloc_pageable(pager_map,
- (mapsize = count*NBPG));
- if( !kva) {
+ kva = kmem_alloc_pageable(pager_map, (mapsize = count * NBPG));
+ if (!kva) {
for (i = 0; i < count; i++) {
if (i != reqpage) {
vnode_pager_freepage(m[i]);
- m[i] = 0;
}
}
m[0] = m[reqpage];
- kva = vm_pager_map_page(m[0]);
+ kva = kmem_alloc_wait(pager_map, mapsize = NBPG);
reqpage = 0;
count = 1;
- mapsize = count*NBPG;
}
}
+ /*
+ * if we can't get a kva or we can't bmap, use old VOP code
+ */
if (!kva) {
+ for (i = 0; i < count; i++) {
+ if (i != reqpage) {
+ vnode_pager_freepage(m[i]);
+ }
+ }
+ return vnode_pager_input_old(vnp, m[reqpage]);
+
/*
- * here on I/O through VFS
+ * if the blocksize is smaller than a page size, then use
+ * special small filesystem code. NFS sometimes has a small
+ * blocksize, but it can handle large reads itself.
*/
+ } else if ((NBPG / bsize) > 1 &&
+ (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
+
+ kmem_free_wakeup(pager_map, kva, mapsize);
+
for (i = 0; i < count; i++) {
if (i != reqpage) {
vnode_pager_freepage(m[i]);
- m[i] = 0;
}
}
- m[0] = m[reqpage];
- foff = m[0]->offset + paging_offset;
- reqpage = 0;
- count = 1;
- /*
- * Return failure if beyond current EOF
- */
- if (foff >= vnp->vnp_size) {
- errtype = 1;
- error = VM_PAGER_BAD;
- } else {
- if (foff + NBPG > vnp->vnp_size)
- size = vnp->vnp_size - foff;
- else
- size = NBPG;
+ return vnode_pager_input_smlfs(vnp, m[reqpage]);
+ }
/*
- * Allocate a kernel virtual address and initialize so that
- * we can use VOP_READ/WRITE routines.
+ * here on direct device I/O
*/
- kva = vm_pager_map_page(m[0]);
- aiov.iov_base = (caddr_t)kva;
- aiov.iov_len = size;
- auio.uio_iov = &aiov;
- auio.uio_iovcnt = 1;
- auio.uio_offset = foff;
- auio.uio_segflg = UIO_SYSSPACE;
- auio.uio_rw = rw;
- auio.uio_resid = size;
- auio.uio_procp = (struct proc *)0;
- if (rw == UIO_READ) {
- error = VOP_READ(vp, &auio, IO_PAGER, p->p_ucred);
- } else {
- error = VOP_WRITE(vp, &auio, IO_PAGER, p->p_ucred);
- }
- if (!error) {
- register int count = size - auio.uio_resid;
- if (count == 0)
- error = EINVAL;
- else if (count != NBPG && rw == UIO_READ)
- bzero((caddr_t)kva + count, NBPG - count);
- }
- vm_pager_unmap_page(kva);
- }
- } else {
- /*
- * here on direct device I/O
- */
- int first=0, last=count;
- int reqaddr, firstaddr;
- int block, offset;
-
- struct buf *bp;
- int s;
- int failflag;
+ /*
+ * This pathetic hack gets data from the buffer cache, if it's there.
+ * I believe that this is not really necessary, and the ends can be
+ * gotten by defaulting to the normal vfs read behavior, but this
+ * might be more efficient, because the will NOT invoke read-aheads
+ * and one of the purposes of this code is to bypass the buffer cache
+ * and keep from flushing it by reading in a program.
+ */
- foff = m[reqpage]->offset + paging_offset;
+ /*
+ * calculate logical block and offset
+ */
+ block = foff / bsize;
+ offset = foff % bsize;
+ s = splbio();
+
+ /*
+ * if we have a buffer in core, then try to use it
+ */
+ while (bp = incore(vp, block)) {
+ int amount;
/*
- * This pathetic hack gets data from the buffer cache, if it's there.
- * I believe that this is not really necessary, and the ends can
- * be gotten by defaulting to the normal vfs read behavior, but this
- * might be more efficient, because the will NOT invoke read-aheads
- * and one of the purposes of this code is to bypass the buffer
- * cache and keep from flushing it by reading in a program.
- */
- /*
- * calculate logical block and offset
+ * wait until the buffer is avail or gone
*/
- block = foff / bsize;
- offset = foff % bsize;
- s = splbio();
+ if (bp->b_flags & B_BUSY) {
+ bp->b_flags |= B_WANTED;
+ tsleep((caddr_t) bp, PVM, "vnwblk", 0);
+ continue;
+ }
+ amount = NBPG;
+ if ((foff + amount) > vnp->vnp_size)
+ amount = vnp->vnp_size - foff;
/*
- * if we have a buffer in core, then try to use it
+ * make sure that this page is in the buffer
*/
- while (bp = incore(vp, block)) {
- int amount;
-
+ if ((amount > 0) && (offset + amount) <= bp->b_bcount) {
+ bp->b_flags |= B_BUSY;
+ splx(s);
+
/*
- * wait until the buffer is avail or gone
+ * map the requested page
*/
- if (bp->b_flags & B_BUSY) {
- bp->b_flags |= B_WANTED;
- tsleep ((caddr_t)bp, PVM, "vnwblk", 0);
- continue;
+ pmap_kenter(kva, VM_PAGE_TO_PHYS(m[reqpage]));
+ pmap_update();
+
+ /*
+ * copy the data from the buffer
+ */
+ bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount);
+ if (amount < NBPG) {
+ bzero((caddr_t) kva + amount, NBPG - amount);
}
- amount = NBPG;
- if ((foff + amount) > vnp->vnp_size)
- amount = vnp->vnp_size - foff;
+ /*
+ * unmap the page and free the kva
+ */
+ pmap_remove(vm_map_pmap(pager_map), kva, kva + NBPG);
+ kmem_free_wakeup(pager_map, kva, mapsize);
/*
- * make sure that this page is in the buffer
+ * release the buffer back to the block subsystem
*/
- if ((amount > 0) && (offset + amount) <= bp->b_bcount) {
- bp->b_flags |= B_BUSY;
- splx(s);
+ bp->b_flags &= ~B_BUSY;
+ wakeup((caddr_t) bp);
- /*
- * map the requested page
- */
- pmap_enter(vm_map_pmap(pager_map),
- kva, VM_PAGE_TO_PHYS(m[reqpage]),
- VM_PROT_DEFAULT, TRUE);
- /*
- * copy the data from the buffer
- */
- bcopy(bp->b_un.b_addr + offset, (caddr_t)kva, amount);
- if (amount < NBPG) {
- bzero((caddr_t)kva + amount, NBPG - amount);
- }
- /*
- * unmap the page and free the kva
- */
- pmap_remove(vm_map_pmap(pager_map), kva, kva + NBPG);
- kmem_free_wakeup(pager_map, kva, mapsize);
- /*
- * release the buffer back to the block subsystem
- */
- bp->b_flags &= ~B_BUSY;
- wakeup((caddr_t)bp);
- /*
- * we did not have to do any work to get the requested
- * page, the read behind/ahead does not justify a read
- */
- for (i = 0; i < count; i++) {
- if (i != reqpage) {
- vnode_pager_freepage(m[i]);
- m[i] = 0;
- }
+ /*
+ * we did not have to do any work to get the requested
+ * page, the read behind/ahead does not justify a read
+ */
+ for (i = 0; i < count; i++) {
+ if (i != reqpage) {
+ vnode_pager_freepage(m[i]);
}
- /*
- * sorry for the goto
- */
- goto finishup;
}
+ count = 1;
+ reqpage = 0;
+ m[0] = m[reqpage];
+
/*
- * buffer is nowhere to be found, read from the disk
+ * sorry for the goto
*/
- break;
+ goto finishup;
}
- foff = m[reqpage]->offset + paging_offset;
- reqaddr = vnode_pager_addr(vp, foff);
/*
- * Make sure that our I/O request is contiguous.
- * Scan backward and stop for the first discontiguous
- * entry or stop for a page being in buffer cache.
+ * buffer is nowhere to be found, read from the disk
*/
- failflag = 0;
- for (i = reqpage - 1; i >= 0; --i) {
- int myaddr;
- if (failflag ||
- incore(vp, (foff + (i - reqpage) * NBPG) / bsize) ||
- (myaddr = vnode_pager_addr(vp, m[i]->offset + paging_offset))
- != reqaddr + (i - reqpage) * NBPG) {
- vnode_pager_freepage(m[i]);
- m[i] = 0;
- if (first == 0)
- first = i + 1;
- failflag = 1;
- }
- }
+ break;
+ }
+ splx(s);
- /*
- * Scan forward and stop for the first non-contiguous
- * entry or stop for a page being in buffer cache.
- */
- failflag = 0;
- for (i = reqpage + 1; i < count; i++) {
- int myaddr;
- if (failflag ||
- incore(vp, (foff + (i - reqpage) * NBPG) / bsize) ||
- (myaddr = vnode_pager_addr(vp, m[i]->offset + paging_offset))
- != reqaddr + (i - reqpage) * NBPG) {
- vnode_pager_freepage(m[i]);
- m[i] = 0;
- if (last == count)
- last = i;
- failflag = 1;
- }
+ reqaddr = vnode_pager_addr(vp, foff);
+
+ /*
+ * Make sure that our I/O request is contiguous. Scan backward and
+ * stop for the first discontiguous entry or stop for a page being in
+ * buffer cache.
+ */
+ failflag = 0;
+ first = reqpage;
+ for (i = reqpage - 1; i >= 0; --i) {
+ if (failflag ||
+ incore(vp, (foff + (i - reqpage) * NBPG) / bsize) ||
+ (vnode_pager_addr(vp, m[i]->offset + paging_offset))
+ != reqaddr + (i - reqpage) * NBPG) {
+ vnode_pager_freepage(m[i]);
+ failflag = 1;
+ } else {
+ first = i;
}
+ }
- /*
- * the first and last page have been calculated now, move input
- * pages to be zero based...
- */
- count = last;
- if (first != 0) {
- for (i = first; i < count; i++) {
- m[i - first] = m[i];
- }
- count -= first;
- reqpage -= first;
+ /*
+ * Scan forward and stop for the first non-contiguous entry or stop
+ * for a page being in buffer cache.
+ */
+ failflag = 0;
+ last = reqpage + 1;
+ for (i = reqpage + 1; i < count; i++) {
+ if (failflag ||
+ incore(vp, (foff + (i - reqpage) * NBPG) / bsize) ||
+ (vnode_pager_addr(vp, m[i]->offset + paging_offset))
+ != reqaddr + (i - reqpage) * NBPG) {
+ vnode_pager_freepage(m[i]);
+ failflag = 1;
+ } else {
+ last = i + 1;
}
+ }
+ /*
+ * the first and last page have been calculated now, move input pages
+ * to be zero based...
+ */
+ count = last;
+ if (first != 0) {
+ for (i = first; i < count; i++) {
+ m[i - first] = m[i];
+ }
+ count -= first;
+ reqpage -= first;
+ }
- /*
- * calculate the file virtual address for the transfer
- */
- foff = m[0]->offset + paging_offset;
- /*
- * and get the disk physical address (in bytes)
- */
- firstaddr = vnode_pager_addr(vp, foff);
+ /*
+ * calculate the file virtual address for the transfer
+ */
+ foff = m[0]->offset + paging_offset;
- /*
- * calculate the size of the transfer
- */
- if ((m[count - 1]->offset + paging_offset) + NBPG > vnp->vnp_size)
- size = vnp->vnp_size - foff;
- else
- size = count * NBPG;
+ /*
+ * and get the disk physical address (in bytes)
+ */
+ firstaddr = vnode_pager_addr(vp, foff);
+ /*
+ * calculate the size of the transfer
+ */
+ size = count * NBPG;
+ if ((foff + size) > vnp->vnp_size)
+ size = vnp->vnp_size - foff;
- /*
- * and map the pages to be read into the kva
- */
- for (i = 0; i < count; i++)
- pmap_enter(vm_map_pmap(pager_map),
- kva + NBPG * i, VM_PAGE_TO_PHYS(m[i]),
- VM_PROT_DEFAULT, TRUE);
- VHOLD(vp);
- bp = getpbuf();
-
- /* build a minimal buffer header */
- bzero((caddr_t)bp, sizeof(struct buf));
- bp->b_flags = B_BUSY | B_READ | B_CALL;
- bp->b_iodone = vnode_pager_iodone;
- /* B_PHYS is not set, but it is nice to fill this in */
- /* bp->b_proc = &proc0; */
- bp->b_proc = curproc;
- bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
- bp->b_un.b_addr = (caddr_t) kva;
- bp->b_blkno = firstaddr / DEV_BSIZE;
- bp->b_vp = dp;
-
- /* Should be a BLOCK or character DEVICE if we get here */
- bp->b_dev = dp->v_rdev;
- bp->b_bcount = NBPG * count;
-
- /* do the input */
- VOP_STRATEGY(bp);
-
- /* we definitely need to be at splbio here */
-
- while ((bp->b_flags & B_DONE) == 0) {
- tsleep((caddr_t)bp, PVM, "vnread", 0);
- }
- splx(s);
- if ((bp->b_flags & B_ERROR) != 0)
- error = EIO;
+ /*
+ * round up physical size for real devices
+ */
+ if (dp->v_type == VBLK || dp->v_type == VCHR)
+ size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
- if (!error) {
- if (size != count * NBPG)
- bzero((caddr_t)kva + size, NBPG * count - size);
- }
- HOLDRELE(vp);
+ /*
+ * and map the pages to be read into the kva
+ */
+ for (i = 0; i < count; i++)
+ pmap_kenter(kva + NBPG * i, VM_PAGE_TO_PHYS(m[i]));
+
+ pmap_update();
+ VHOLD(vp);
+ bp = getpbuf();
+
+ /* build a minimal buffer header */
+ bp->b_flags = B_BUSY | B_READ | B_CALL;
+ bp->b_iodone = vnode_pager_iodone;
+ /* B_PHYS is not set, but it is nice to fill this in */
+ bp->b_proc = curproc;
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ bp->b_un.b_addr = (caddr_t) kva;
+ bp->b_blkno = firstaddr / DEV_BSIZE;
+ bp->b_vp = dp;
+
+ /* Should be a BLOCK or character DEVICE if we get here */
+ bp->b_dev = dp->v_rdev;
+ bp->b_bcount = size;
+ bp->b_bufsize = size;
+
+ /* do the input */
+ VOP_STRATEGY(bp);
+
+ s = splbio();
+ /* we definitely need to be at splbio here */
+
+ while ((bp->b_flags & B_DONE) == 0) {
+ tsleep((caddr_t) bp, PVM, "vnread", 0);
+ }
+ splx(s);
+ if ((bp->b_flags & B_ERROR) != 0)
+ error = EIO;
- pmap_remove(vm_map_pmap(pager_map), kva, kva + NBPG * count);
- kmem_free_wakeup(pager_map, kva, mapsize);
+ if (!error) {
+ if (size != count * NBPG)
+ bzero((caddr_t) kva + size, NBPG * count - size);
+ }
+ HOLDRELE(vp);
- /*
- * free the buffer header back to the swap buffer pool
- */
- relpbuf(bp);
+ pmap_remove(vm_map_pmap(pager_map), kva, kva + NBPG * count);
+ kmem_free_wakeup(pager_map, kva, mapsize);
- }
+ /*
+ * free the buffer header back to the swap buffer pool
+ */
+ relpbuf(bp);
finishup:
- if (rw == UIO_READ)
for (i = 0; i < count; i++) {
- /*
- * we dont mess with pages that have been already
- * deallocated....
- */
- if (!m[i])
- continue;
pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
m[i]->flags |= PG_CLEAN;
m[i]->flags &= ~PG_LAUNDRY;
if (i != reqpage) {
+
/*
- * whether or not to leave the page activated
- * is up in the air, but we should put the page
- * on a page queue somewhere. (it already is in
- * the object).
- * Result: It appears that emperical results show
- * that deactivating pages is best.
+ * whether or not to leave the page activated is up in
+ * the air, but we should put the page on a page queue
+ * somewhere. (it already is in the object). Result:
+ * It appears that emperical results show that
+ * deactivating pages is best.
*/
+
/*
- * just in case someone was asking for this
- * page we now tell them that it is ok to use
+ * just in case someone was asking for this page we
+ * now tell them that it is ok to use
*/
if (!error) {
vm_page_deactivate(m[i]);
@@ -927,15 +1060,380 @@ finishup:
}
}
}
- if (!error && rw == UIO_WRITE) {
- pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage]));
- m[reqpage]->flags |= PG_CLEAN;
- m[reqpage]->flags &= ~PG_LAUNDRY;
- }
if (error) {
- printf("vnode pager error: %d\n", error);
+ printf("vnode pager read error: %d\n", error);
}
if (errtype)
return error;
return (error ? VM_PAGER_FAIL : VM_PAGER_OK);
}
+
+/*
+ * old-style vnode pager output routine
+ */
+int
+vnode_pager_output_old(vnp, m)
+ register vn_pager_t vnp;
+ vm_page_t m;
+{
+ vm_offset_t foff;
+ vm_offset_t kva;
+ vm_offset_t size;
+ struct iovec aiov;
+ struct uio auio;
+ struct vnode *vp;
+ int error;
+
+ vp = vnp->vnp_vp;
+ foff = m->offset + m->object->paging_offset;
+
+ /*
+ * Return failure if beyond current EOF
+ */
+ if (foff >= vnp->vnp_size) {
+ return VM_PAGER_BAD;
+ } else {
+ size = NBPG;
+ if (foff + size > vnp->vnp_size)
+ size = vnp->vnp_size - foff;
+/*
+ * Allocate a kernel virtual address and initialize so that
+ * we can use VOP_WRITE routines.
+ */
+ kva = vm_pager_map_page(m);
+ aiov.iov_base = (caddr_t) kva;
+ aiov.iov_len = size;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = foff;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_WRITE;
+ auio.uio_resid = size;
+ auio.uio_procp = (struct proc *) 0;
+
+ error = VOP_WRITE(vp, &auio, IO_PAGER, curproc->p_ucred);
+
+ if (!error) {
+ if ((size - auio.uio_resid) == 0) {
+ error = EINVAL;
+ }
+ }
+ vm_pager_unmap_page(kva);
+ return error ? VM_PAGER_FAIL : VM_PAGER_OK;
+ }
+}
+
+/*
+ * vnode pager output on a small-block file system
+ */
+int
+vnode_pager_output_smlfs(vnp, m)
+ vn_pager_t vnp;
+ vm_page_t m;
+{
+ int i;
+ int s;
+ vm_offset_t paging_offset;
+ struct vnode *dp, *vp;
+ struct buf *bp;
+ vm_offset_t mapsize;
+ vm_offset_t foff;
+ vm_offset_t kva;
+ int fileaddr;
+ int block;
+ vm_offset_t bsize;
+ int error = 0;
+
+ paging_offset = m->object->paging_offset;
+ vp = vnp->vnp_vp;
+ bsize = vp->v_mount->mnt_stat.f_bsize;
+ foff = m->offset + paging_offset;
+
+ VOP_BMAP(vp, foff, &dp, 0);
+ kva = vm_pager_map_page(m);
+ for (i = 0; !error && i < (NBPG / bsize); i++) {
+
+ /*
+ * calculate logical block and offset
+ */
+ fileaddr = vnode_pager_addr(vp, foff + i * bsize);
+ if (fileaddr != -1) {
+ s = splbio();
+ if (bp = incore(vp, (foff / bsize) + i)) {
+ bp = getblk(vp, (foff / bsize) + i, bp->b_bufsize);
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ }
+ splx(s);
+
+ VHOLD(vp);
+ bp = getpbuf();
+
+ /* build a minimal buffer header */
+ bp->b_flags = B_BUSY | B_CALL | B_WRITE;
+ bp->b_iodone = vnode_pager_iodone;
+ bp->b_proc = curproc;
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ bp->b_un.b_addr = (caddr_t) kva + i * bsize;
+ bp->b_blkno = fileaddr / DEV_BSIZE;
+ bp->b_vp = dp;
+ ++dp->v_numoutput;
+ /* for NFS */
+ bp->b_dirtyoff = 0;
+ bp->b_dirtyend = bsize;
+
+ /*
+ * Should be a BLOCK or character DEVICE if we get
+ * here
+ */
+ bp->b_dev = dp->v_rdev;
+ bp->b_bcount = bsize;
+ bp->b_bufsize = bsize;
+
+ /* do the input */
+ VOP_STRATEGY(bp);
+
+ /* we definitely need to be at splbio here */
+
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0) {
+ tsleep((caddr_t) bp, PVM, "vnswrt", 0);
+ }
+ splx(s);
+ if ((bp->b_flags & B_ERROR) != 0)
+ error = EIO;
+
+ HOLDRELE(vp);
+
+ /*
+ * free the buffer header back to the swap buffer pool
+ */
+ relpbuf(bp);
+ }
+ }
+ vm_pager_unmap_page(kva);
+ if (error)
+ return VM_PAGER_FAIL;
+ else
+ return VM_PAGER_OK;
+}
+
+/*
+ * generic vnode pager output routine
+ */
+int
+vnode_pager_output(vnp, m, count, rtvals)
+ vn_pager_t vnp;
+ vm_page_t *m;
+ int count;
+ int *rtvals;
+{
+ int i, j;
+ vm_offset_t kva, foff;
+ int size;
+ struct proc *p = curproc; /* XXX */
+ vm_object_t object;
+ vm_offset_t paging_offset;
+ struct vnode *dp, *vp;
+ struct buf *bp;
+ vm_offset_t mapsize;
+ vm_offset_t reqaddr;
+ int bsize;
+ int s;
+
+ int error = 0;
+
+retryoutput:
+ object = m[0]->object; /* all vm_page_t items are in same object */
+ paging_offset = object->paging_offset;
+
+ vp = vnp->vnp_vp;
+ bsize = vp->v_mount->mnt_stat.f_bsize;
+
+ for (i = 0; i < count; i++)
+ rtvals[i] = VM_PAGER_TRYAGAIN;
+
+ /*
+ * if the filesystem does not have a bmap, then use the old code
+ */
+ if (VOP_BMAP(vp, m[0]->offset + paging_offset, &dp, 0)) {
+
+ rtvals[0] = vnode_pager_output_old(vnp, m[0]);
+
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m[0]));
+ m[0]->flags |= PG_CLEAN;
+ m[0]->flags &= ~PG_LAUNDRY;
+ return rtvals[0];
+ }
+
+ /*
+ * if the filesystem has a small blocksize, then use the small block
+ * filesystem output code
+ */
+ if ((bsize < NBPG) &&
+ (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
+
+ for (i = 0; i < count; i++) {
+ rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]);
+ if (rtvals[i] == VM_PAGER_OK) {
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
+ m[i]->flags |= PG_CLEAN;
+ m[i]->flags &= ~PG_LAUNDRY;
+ }
+ }
+ return rtvals[0];
+ }
+
+ /*
+ * get some kva for the output
+ */
+ kva = kmem_alloc_pageable(pager_map, (mapsize = count * NBPG));
+ if (!kva) {
+ kva = kmem_alloc_pageable(pager_map, (mapsize = NBPG));
+ count = 1;
+ if (!kva)
+ return rtvals[0];
+ }
+ for (i = 0; i < count; i++) {
+ foff = m[i]->offset + paging_offset;
+ if (foff >= vnp->vnp_size) {
+ for (j = i; j < count; j++)
+ rtvals[j] = VM_PAGER_BAD;
+ count = i;
+ break;
+ }
+ }
+ if (count == 0) {
+ return rtvals[0];
+ }
+ foff = m[0]->offset + paging_offset;
+ reqaddr = vnode_pager_addr(vp, foff);
+
+ /*
+ * Scan forward and stop for the first non-contiguous entry or stop
+ * for a page being in buffer cache.
+ */
+ for (i = 1; i < count; i++) {
+ if (vnode_pager_addr(vp, m[i]->offset + paging_offset)
+ != reqaddr + i * NBPG) {
+ count = i;
+ break;
+ }
+ }
+
+ /*
+ * calculate the size of the transfer
+ */
+ size = count * NBPG;
+ if ((foff + size) > vnp->vnp_size)
+ size = vnp->vnp_size - foff;
+
+ /*
+ * round up physical size for real devices
+ */
+ if (dp->v_type == VBLK || dp->v_type == VCHR)
+ size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
+
+ /*
+ * and map the pages to be read into the kva
+ */
+ for (i = 0; i < count; i++)
+ pmap_kenter(kva + NBPG * i, VM_PAGE_TO_PHYS(m[i]));
+ pmap_update();
+/*
+ printf("vnode: writing foff: %d, devoff: %d, size: %d\n",
+ foff, reqaddr, size);
+*/
+
+ /*
+ * next invalidate the incore vfs_bio data
+ */
+ for (i = 0; i < count; i++) {
+ int filblock = (foff + i * NBPG) / bsize;
+ struct buf *fbp;
+
+ s = splbio();
+ if (fbp = incore(vp, filblock)) {
+ fbp = getblk(vp, filblock, fbp->b_bufsize);
+ if (fbp->b_flags & B_DELWRI) {
+ if (fbp->b_bufsize <= NBPG)
+ fbp->b_flags &= ~B_DELWRI;
+ else {
+ bwrite(fbp);
+ fbp = getblk(vp, filblock,
+ fbp->b_bufsize);
+ }
+ }
+ fbp->b_flags |= B_INVAL;
+ brelse(fbp);
+ }
+ splx(s);
+ }
+
+
+ VHOLD(vp);
+ bp = getpbuf();
+
+ /* build a minimal buffer header */
+ bp->b_flags = B_BUSY | B_WRITE | B_CALL;
+ bp->b_iodone = vnode_pager_iodone;
+ /* B_PHYS is not set, but it is nice to fill this in */
+ /* bp->b_proc = &proc0; */
+ bp->b_proc = curproc;
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ bp->b_un.b_addr = (caddr_t) kva;
+ bp->b_blkno = reqaddr / DEV_BSIZE;
+ bp->b_vp = dp;
+ ++dp->v_numoutput;
+
+ /* Should be a BLOCK or character DEVICE if we get here */
+ bp->b_dev = dp->v_rdev;
+ /* for NFS */
+ bp->b_dirtyoff = 0;
+ bp->b_dirtyend = size;
+
+ bp->b_bcount = size;
+ bp->b_bufsize = size;
+
+ /* do the output */
+ VOP_STRATEGY(bp);
+
+ s = splbio();
+
+ /* we definitely need to be at splbio here */
+
+ while ((bp->b_flags & B_DONE) == 0) {
+ tsleep((caddr_t) bp, PVM, "vnwrite", 0);
+ }
+ splx(s);
+
+ if ((bp->b_flags & B_ERROR) != 0)
+ error = EIO;
+
+ HOLDRELE(vp);
+
+ pmap_remove(vm_map_pmap(pager_map), kva, kva + NBPG * count);
+ kmem_free_wakeup(pager_map, kva, mapsize);
+
+ /*
+ * free the buffer header back to the swap buffer pool
+ */
+ relpbuf(bp);
+
+ if (!error) {
+ for (i = 0; i < count; i++) {
+ pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
+ m[i]->flags |= PG_CLEAN;
+ m[i]->flags &= ~PG_LAUNDRY;
+ rtvals[i] = VM_PAGER_OK;
+ }
+ } else if (count != 1) {
+ error = 0;
+ count = 1;
+ goto retryoutput;
+ }
+ if (error) {
+ printf("vnode pager write error: %d\n", error);
+ }
+ return (error ? VM_PAGER_FAIL : VM_PAGER_OK);
+}
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index ba0d7cb35eca..0b1f5add2823 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -1,19 +1,20 @@
# @(#)Makefile 5.8.1.1 (Berkeley) 5/8/91
#
-SUBDIR= ar at basename bdes biff cal calendar checknr chat chpass cksum cmp \
- col colcrt colrm column comm compress crontab ctags cut dirname \
- du elvis elvisrecover env error expand f2c false file find finger fmt \
- fold fpr from fsplit fstat ftp getopt gprof groups head hexdump \
- id indent ipcrm ipcs join ktrace last lastcomm leave lex locate lock \
- logger login logname look lorder m4 machine mail make mesg mkdep \
- mkfifo mkstr more msgs mt netstat nfsstat nice nm nohup pagesize \
- passwd paste printenv printf quota ranlib rdist ref renice rev rlogin \
- rpcgen rpcinfo rsh rup ruptime rusers rwall rwho script sed shar \
- showmount size soelim split strings strip su symorder syscons tail \
- talk tcopy tee telnet tftp time tip tn3270 touch tput tr true tset \
- tsort tty ul uname unexpand unifdef uniq unvis users uudecode uuencode \
- vacation vgrind vi vis vmstat w wall wc what whereis which who whoami \
- whois window write xargs xinstall xstr yacc yes
+SUBDIR= ar at basename bdes biff cal calendar cap_mkdb checknr chat chpass \
+ cksum cmp col colcrt colrm column comm compress crontab ctags cut \
+ dirname du elvis elvisrecover env error expand f2c false file find \
+ finger fmt fold fpr from fsplit fstat ftp getopt gprof groups head \
+ hexdump id indent ipcrm ipcs join key keyinfo keyinit \
+ ktrace last lastcomm leave lex locate lock logger login logname \
+ look lorder m4 machine mail make mesg mkdep mkfifo mkstr more msgs \
+ mt netstat nfsstat nice nm nohup pagesize passwd paste printenv printf \
+ quota ranlib rdist ref renice rev rlogin rpcgen rpcinfo rsh rup \
+ ruptime rusers rwall rwho script sed shar showmount size soelim split \
+ strings strip su symorder tail talk tcopy tee telnet \
+ tftp time tip tn3270 touch tput tr true tset tsort tty ul \
+ uname unexpand unifdef uniq unvis users uudecode uuencode \
+ vacation vgrind vi vis vmstat w wall wc what whereis which \
+ who whoami whois window write xargs xinstall xstr yacc yes
.include <bsd.subdir.mk>
diff --git a/usr.bin/ar/replace.c b/usr.bin/ar/replace.c
index 9f56a937759c..5055186c69ed 100644
--- a/usr.bin/ar/replace.c
+++ b/usr.bin/ar/replace.c
@@ -107,8 +107,10 @@ replace(argv)
goto useold;
}
(void)fstat(sfd, &sb);
- if (options & AR_U && sb.st_mtime <= chdr.date)
+ if (options & AR_U && sb.st_mtime <= chdr.date) {
+ (void)close(sfd);
goto useold;
+ }
if (options & AR_V)
(void)printf("r - %s\n", file);
diff --git a/usr.bin/basename/basename.1 b/usr.bin/basename/basename.1
index 8f332628817f..a1b8d5f818a9 100644
--- a/usr.bin/basename/basename.1
+++ b/usr.bin/basename/basename.1
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)basename.1 6.7 (Berkeley) 6/27/91
-.\" $Id: basename.1,v 1.2.2.1 1994/05/01 16:08:06 jkh Exp $
+.\" $Id: basename.1,v 1.3 1994/04/24 01:22:43 jkh Exp $
.\"
.Dd June 27, 1991
.Dt BASENAME 1
diff --git a/usr.bin/cap_mkdb/Makefile b/usr.bin/cap_mkdb/Makefile
new file mode 100644
index 000000000000..33cdfe3eeb9d
--- /dev/null
+++ b/usr.bin/cap_mkdb/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 5.1 (Berkeley) 9/2/92
+
+PROG= cap_mkdb
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/cap_mkdb/cap_mkdb.1 b/usr.bin/cap_mkdb/cap_mkdb.1
new file mode 100644
index 000000000000..6d1a18385895
--- /dev/null
+++ b/usr.bin/cap_mkdb/cap_mkdb.1
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1992 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.
+.\"
+.\" @(#)cap_mkdb.1 5.4 (Berkeley) 3/6/93
+.\"
+.Dd "March 6, 1993"
+.Dt CAP_MKDB 1
+.Os
+.Sh NAME
+.Nm cap_mkdb
+.Nd create capability database
+.Pp
+.Sh SYNOPSIS
+.Nm cap_mkdb
+.Op Fl v
+.Op Fl f Ar outfile
+.Ar file1
+.Op Ar file2 ...
+.Pp
+.Sh DESCRIPTION
+.Nm Cap_mkdb
+builds a hashed database out of the
+.Xr getcap 3
+logical database constructed by the concatenation of the specified
+files .
+.Pp
+The database is named by the basename of the first file argument and
+the string
+.Dq .db .
+The
+.Xr getcap 3
+routines can access the database in this form much more quickly
+than they can the original text file(s).
+.Pp
+The ``tc'' capabilities of the records are expanded before the
+record is stored into the database.
+.Pp
+The options as as follows:
+.Bl -tag -width XXXXXX -indent
+.It Fl f Ar outfile
+Specify a different database basename.
+.It Fl v
+Print out the number of capability records in the database.
+.El
+.Pp
+.Sh FORMAT
+Each record is stored in the database using two different types of keys.
+.Pp
+The first type is a key which consists of the first capability of
+the record (not including the trailing colon (``:'')) with a data
+field consisting of a special byte followed by the rest of the record.
+The special byte is either a 0 or 1, where a 0 means that the record
+is okay, and a 1 means that there was a ``tc'' capability in the record
+that couldn't be expanded.
+.Pp
+The second type is a key which consists of one of the names from the
+first capability of the record with a data field consisting a special
+byte followed by the the first capability of the record.
+The special byte is a 2.
+.Pp
+In normal operation names are looked up in the database, resulting
+in a key/data pair of the second type.
+The data field of this key/data pair is used to look up a key/data
+pair of the first type which has the real data associated with the
+name.
+.Sh RETURN VALUE
+The
+.Nm cap_mkdb
+utility exits 0 on success and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr dbopen 3 ,
+.Xr getcap 3 ,
+.Xr termcap 5
diff --git a/usr.bin/cap_mkdb/cap_mkdb.c b/usr.bin/cap_mkdb/cap_mkdb.c
new file mode 100644
index 000000000000..11f5898777ff
--- /dev/null
+++ b/usr.bin/cap_mkdb/cap_mkdb.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 1992 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] = "$Id: cap_mkdb.c,v 1.1.1.1 1994/04/17 10:21:25 alm Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void db_build __P((char **));
+void dounlink __P((void));
+void usage __P((void));
+
+DB *capdbp;
+int verbose;
+char *capdb, *capname, buf[8 * 1024];
+
+/*
+ * Mkcapdb creates a capability hash database for quick retrieval of capability
+ * records. The database contains 2 types of entries: records and references
+ * marked by the first byte in the data. A record entry contains the actual
+ * capability record whereas a reference contains the name (key) under which
+ * the correct record is stored.
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ capname = NULL;
+ while ((c = getopt(argc, argv, "f:v")) != EOF) {
+ switch(c) {
+ case 'f':
+ capname = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+
+ /*
+ * The database file is the first argument if no name is specified.
+ * Make arrangements to unlink it if exit badly.
+ */
+ (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
+ if ((capname = strdup(buf)) == NULL)
+ err(1, "");
+ if ((capdbp = dbopen(capname,
+ O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL)
+ err(1, "%s", buf);
+
+ if (atexit(dounlink))
+ err(1, "atexit");
+
+ db_build(argv);
+
+ if (capdbp->close(capdbp) < 0)
+ err(1, "%s", capname);
+ capname = NULL;
+ exit(0);
+}
+
+void
+dounlink()
+{
+ if (capname != NULL)
+ (void)unlink(capname);
+}
+
+/*
+ * Any changes to these definitions should be made also in the getcap(3)
+ * library routines.
+ */
+#define RECOK (char)0
+#define TCERR (char)1
+#define SHADOW (char)2
+
+/*
+ * Db_build() builds the name and capabilty databases according to the
+ * details above.
+ */
+void
+db_build(ifiles)
+ char **ifiles;
+{
+ DBT key, data;
+ recno_t reccnt;
+ size_t len, bplen;
+ int st;
+ char *bp, *p, *t;
+
+ data.data = NULL;
+ key.data = NULL;
+ for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
+
+ /*
+ * Allocate enough memory to store record, terminating
+ * NULL and one extra byte.
+ */
+ len = strlen(bp);
+ if (bplen <= len + 2) {
+ bplen += MAX(256, len + 2);
+ if ((data.data = realloc(data.data, bplen)) == NULL)
+ err(1, "");
+ }
+
+ /* Find the end of the name field. */
+ if ((p = strchr(bp, ':')) == NULL) {
+ warnx("no name field: %.*s", MIN(len, 20), bp);
+ continue;
+ }
+
+ /* First byte of stored record indicates status. */
+ switch(st) {
+ case 1:
+ ((char *)(data.data))[0] = RECOK;
+ break;
+ case 2:
+ ((char *)(data.data))[0] = TCERR;
+ warnx("Record not tc expanded: %.*s", p - bp, bp);
+ break;
+ }
+
+ /* Create the stored record. */
+ memmove(&((u_char *)(data.data))[1], bp, len + 1);
+ data.size = len + 2;
+
+ /* Store the record under the name field. */
+ key.data = bp;
+ key.size = p - bp;
+
+ switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ continue;
+ }
+ ++reccnt;
+
+ /* If only one name, ignore the rest. */
+ if ((p = strchr(bp, '|')) == NULL)
+ continue;
+
+ /* The rest of the names reference the entire name. */
+ ((char *)(data.data))[0] = SHADOW;
+ memmove(&((u_char *)(data.data))[1], key.data, key.size);
+ data.size = key.size + 1;
+
+ /* Store references for other names. */
+ for (p = t = bp;; ++p) {
+ if (p > t && (*p == ':' || *p == '|')) {
+ key.size = p - t;
+ key.data = t;
+ switch(capdbp->put(capdbp,
+ &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ }
+ t = p + 1;
+ }
+ if (*p == ':')
+ break;
+ }
+ }
+
+ switch(st) {
+ case -1:
+ err(1, "file argument");
+ /* NOTREACHED */
+ case -2:
+ errx(1, "potential reference loop detected");
+ /* NOTREACHED */
+ }
+
+ if (verbose)
+ (void)printf("cap_mkdb: %d capability records\n", reccnt);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
+ exit(1);
+}
diff --git a/usr.bin/chat/chat.c b/usr.bin/chat/chat.c
index 553b7d46759d..6c85882e7129 100644
--- a/usr.bin/chat/chat.c
+++ b/usr.bin/chat/chat.c
@@ -78,7 +78,7 @@ extern int strlen();
# ifdef HDB
# define LOCK_DIR "/usr/spool/locks"
# else /* HDB */
-# define LOCK_DIR "/usr/spool/uucp"
+# define LOCK_DIR "/var/spool/lock"
# endif /* HDB */
#endif /* LOCK_DIR */
@@ -361,7 +361,7 @@ lock()
sysfatal("Can't get lock file '%s'", s);
}
-# ifdef HDB
+# if defined(HDB) || defined(__FreeBSD__)
sprintf(hdb_lock_buffer, "%10d\n", getpid());
write(fd, hdb_lock_buffer, 11);
# else /* HDB */
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index 573781ba3339..76eb09174306 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/chpass/Makefile
@@ -1,11 +1,17 @@
# @(#)Makefile 5.5 (Berkeley) 2/19/91
PROG= chpass
-SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c table.c util.c
+SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c table.c util.c \
+ pw_fastmkdb.c
BINOWN= root
BINMODE=4555
-.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw
+.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw \
+ ${.CURDIR}/../../usr.bin/passwd
LINKS= ${BINDIR}/chpass ${BINDIR}/chfn ${BINDIR}/chpass ${BINDIR}/chsh
MLINKS= chpass.1 chfn.1 chpass.1 chsh.1
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c
index 4cf13e2032dc..4073706aa704 100644
--- a/usr.bin/chpass/chpass.c
+++ b/usr.bin/chpass/chpass.c
@@ -59,6 +59,11 @@ char *progname = "chpass";
char *tempname;
uid_t uid;
+#define INSECURE 1
+#define SECURE 2
+#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
main(argc, argv)
int argc;
char **argv;
@@ -151,7 +156,7 @@ main(argc, argv)
* Pw_copy() closes its fp, flushing the data and closing the
* underlying file descriptor. We can't close the master
* password fp, or we'd lose the lock.
- * 7: Call pw_mkdb() (which renames the temporary file) and exit.
+ * 7: Call pw_fastmkdb() (which renames the temporary file) and exit.
* The exit closes the master passwd fp/fd.
*/
pw_init();
@@ -164,11 +169,35 @@ main(argc, argv)
(void)unlink(tempname);
tfd = pw_tmp();
}
-
+
pw_copy(pfd, tfd, pw);
- if (!pw_mkdb())
- pw_error((char *)NULL, 0, 1);
+ /*
+ * Attempt a recovery if the incremental database update failed by
+ * handing off to the real password hashing program to remake the
+ * whole mess. Even though this costs lots of time it's better than
+ * having the password databases out of sync with the master pw file.
+ */
+ if (pw_fastmkdb(pw) < 0) {
+ rebuild:
+ fprintf(stderr,"%s: WARNING!! Password database mangled, recreating it from scratch\n", progname);
+ if(!pw_mkdb())
+ pw_error((char *)NULL, 0, 1);
+ }
+ else {
+ tfd = pw_tmp();
+ fchmod(tfd, PERM_INSECURE);
+ pfd = open(_PATH_PASSWD, O_RDONLY, PERM_INSECURE);
+ if (pfd < 0) {
+ (void)fprintf(stderr,
+ "%s: %s: %s\n", progname, _PATH_PASSWD, strerror(errno));
+ goto rebuild;
+ }
+ pw->pw_passwd = "*";
+ pw_copy_insecure(pfd, tfd, pw);
+ mv(tempname, _PATH_PASSWD);
+
+ }
exit(0);
}
diff --git a/usr.bin/chpass/pw_copy.c b/usr.bin/chpass/pw_copy.c
index 9b7ab9025d5c..6bfcc6b6b851 100644
--- a/usr.bin/chpass/pw_copy.c
+++ b/usr.bin/chpass/pw_copy.c
@@ -46,21 +46,36 @@ static char sccsid[] = "@(#)pw_copy.c 5.3 (Berkeley) 5/2/91";
extern char *progname, *tempname;
-pw_copy(ffd, tfd, pw)
+int globcnt;
+
+/*
+ * NB: Use of pw_copy() to update the insecure passwd file
+ * necessitates that this routine be wrapperized
+ * so that it can handle the formats used by both
+ * /etc/master.passwd and /etc/passwd
+ *
+ * pw_copy() and pw_copy_insecure() both call pw_copy_drv(), which
+ * does the work.
+ */
+static pw_copy_drv(ffd, tfd, pw, secure_format)
int ffd, tfd;
struct passwd *pw;
+ int secure_format;
{
register FILE *from, *to;
register int done;
register char *p;
char buf[8192];
+ int tmpcnt;
if (!(from = fdopen(ffd, "r")))
pw_error(_PATH_MASTERPASSWD, 1, 1);
if (!(to = fdopen(tfd, "w")))
pw_error(tempname, 1, 1);
+ tmpcnt=0;
for (done = 0; fgets(buf, sizeof(buf), from);) {
+ tmpcnt++;
if (!index(buf, '\n')) {
(void)fprintf(stderr, "%s: %s: line too long\n",
progname, _PATH_MASTERPASSWD);
@@ -85,21 +100,69 @@ pw_copy(ffd, tfd, pw)
goto err;
continue;
}
- (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
- pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
- pw->pw_dir, pw->pw_shell);
+ globcnt = tmpcnt;
+ /*
+ * NB: /etc/passwd: insecure format does not have
+ * class, change and expire fields !
+ */
+ if(secure_format)
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid,
+ pw->pw_gid, pw->pw_class, pw->pw_change,
+ pw->pw_expire, pw->pw_gecos, pw->pw_dir,
+ pw->pw_shell);
+ else
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid,
+ pw->pw_gid, pw->pw_gecos, pw->pw_dir,
+ pw->pw_shell);
done = 1;
if (ferror(to))
goto err;
}
if (!done)
- (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
- pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
- pw->pw_dir, pw->pw_shell);
+ {
+ globcnt = tmpcnt+1;
+ /*
+ * NB: /etc/passwd: insecure format does not have
+ * class, change and expire fields !
+ */
+ if(secure_format)
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid,
+ pw->pw_gid, pw->pw_class, pw->pw_change,
+ pw->pw_expire, pw->pw_gecos, pw->pw_dir,
+ pw->pw_shell);
+ else
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid,
+ pw->pw_gid, pw->pw_gecos, pw->pw_dir,
+ pw->pw_shell);
+ }
if (ferror(to))
err: pw_error(NULL, 1, 1);
(void)fclose(to);
}
+
+
+/*
+ * Standard pw_copy routine - used to update master.passwd
+ */
+pw_copy(ffd, tfd, pw)
+ int ffd, tfd;
+ struct passwd *pw;
+{
+ pw_copy_drv(ffd, tfd, pw, 1);
+}
+
+
+/*
+ * Special pw_copy routine used to update insecure passwd file
+ */
+pw_copy_insecure(ffd, tfd, pw)
+ int ffd, tfd;
+ struct passwd *pw;
+{
+ pw_copy_drv(ffd, tfd, pw, 0);
+}
diff --git a/usr.bin/crontab/crontab.1 b/usr.bin/crontab/crontab.1
index b4601e58df5b..0f3c91a154a5 100644
--- a/usr.bin/crontab/crontab.1
+++ b/usr.bin/crontab/crontab.1
@@ -15,7 +15,7 @@
.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
.\" */
.\"
-.\" $Header: /home/cvs/386BSD/src/usr.bin/crontab/crontab.1,v 1.2.2.1 1994/05/01 16:08:10 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/usr.bin/crontab/crontab.1,v 1.2 1994/01/22 20:41:08 guido Exp $
.\"
.\" From Id: crontab.1,v 2.4 1993/12/31 10:47:33 vixie Exp
.\"
diff --git a/usr.bin/crontab/crontab.5 b/usr.bin/crontab/crontab.5
index e8e683428aee..dc72b678ff0b 100644
--- a/usr.bin/crontab/crontab.5
+++ b/usr.bin/crontab/crontab.5
@@ -15,7 +15,7 @@
.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
.\" */
.\"
-.\" $Header: /home/cvs/386BSD/src/usr.bin/crontab/crontab.5,v 1.3.2.1 1994/05/01 16:08:13 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/usr.bin/crontab/crontab.5,v 1.3 1994/01/27 19:06:15 nate Exp $
.\"
.\" From Id: crontab.5,v 2.4 1994/01/15 20:43:43 vixie Exp
.\"
diff --git a/usr.bin/crontab/crontab.c b/usr.bin/crontab/crontab.c
index a325aa0d02f0..eb35fb687a1d 100644
--- a/usr.bin/crontab/crontab.c
+++ b/usr.bin/crontab/crontab.c
@@ -17,7 +17,7 @@
*/
#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /home/cvs/386BSD/src/usr.bin/crontab/crontab.c,v 1.3 1994/01/27 19:06:16 nate Exp $";
+static char rcsid[] = "$Id: crontab.c,v 1.4 1994/04/13 21:57:55 wollman Exp $";
#endif
/* crontab - install and manage per-user crontab files
diff --git a/usr.bin/elvis/input.c b/usr.bin/elvis/input.c
index ca5b11581b91..55bf9fc10acd 100644
--- a/usr.bin/elvis/input.c
+++ b/usr.bin/elvis/input.c
@@ -542,9 +542,9 @@ MARK input(from, to, when, delta)
ChangeText
{
cut(from, to);
+ cursor = from;
delete(from, to);
}
- cursor = from;
break;
#ifndef NO_POPUP
diff --git a/usr.bin/elvis/tmp.c b/usr.bin/elvis/tmp.c
index 46d29ec81daa..c7196df47a67 100644
--- a/usr.bin/elvis/tmp.c
+++ b/usr.bin/elvis/tmp.c
@@ -779,6 +779,7 @@ SIGTYPE deathtrap(sig)
if (tmpnum > 0 && tmpfd >= 0)
{
close(tmpfd);
+ tmpfd = -1;
sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname);
system(tmpblk.c);
}
diff --git a/usr.bin/env/env.1 b/usr.bin/env/env.1
index 8631f3fce2e1..11fdeb68947f 100644
--- a/usr.bin/env/env.1
+++ b/usr.bin/env/env.1
@@ -32,7 +32,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)printenv.1 6.7 (Berkeley) 7/28/91
-.\" $Id: env.1,v 1.2.2.1 1994/05/01 16:08:19 jkh Exp $
+.\" $Id: env.1,v 1.3 1994/04/24 01:22:54 jkh Exp $
.\"
.Dd August 27, 1993
.Dt ENV 1
diff --git a/usr.bin/finger/sprint.c b/usr.bin/finger/sprint.c
index 784237017d9c..9676de113773 100644
--- a/usr.bin/finger/sprint.c
+++ b/usr.bin/finger/sprint.c
@@ -88,8 +88,9 @@ sflag_print()
'*' : ' ');
if (*w->tty)
(void)printf("%-2.2s ",
- w->tty[0] != 't' || w->tty[1] != 't' ||
- w->tty[2] != 'y' ? w->tty : w->tty + 3);
+ strncmp(w->tty, "tty", 3) &&
+ strncmp(w->tty, "cua", 3) ?
+ w->tty : w->tty + 3);
else
(void)printf(" ");
if (w->info == LOGGEDIN) {
diff --git a/usr.bin/finger/util.c b/usr.bin/finger/util.c
index a2b6dd3e2dcb..30e996511188 100644
--- a/usr.bin/finger/util.c
+++ b/usr.bin/finger/util.c
@@ -55,7 +55,9 @@ find_idle_and_ttywrite(w)
struct stat sb;
char *strerror();
- (void)sprintf(tbuf, "%s/%s", _PATH_DEV, w->tty);
+ if (!strncmp(w->tty, "uu", 2))
+ return;
+ (void)sprintf(tbuf, "%s%s", _PATH_DEV, w->tty);
if (stat(tbuf, &sb) < 0) {
(void)fprintf(stderr,
"finger: %s: %s\n", tbuf, strerror(errno));
diff --git a/usr.bin/ftp/glob.c b/usr.bin/ftp/glob.c
index e09648f8295c..c4bdea7dd91f 100644
--- a/usr.bin/ftp/glob.c
+++ b/usr.bin/ftp/glob.c
@@ -184,7 +184,7 @@ expand(as)
if (*cs == 0) {
if (!globbed)
Gcat(gpath, "");
- else if (stat(gpath, &stb) >= 0) {
+ else if (stat(*gpath ? gpath : ".", &stb) >= 0) {
Gcat(gpath, "");
globcnt++;
}
@@ -216,7 +216,8 @@ matchdir(pattern)
register struct dirent *dp;
DIR *dirp;
- dirp = opendir(gpath);
+ /* Note: "" is not equivalent to "." for opendir(2) now! */
+ dirp = opendir(*gpath ? gpath : ".");
if (dirp == NULL) {
if (globbed)
return;
@@ -420,7 +421,7 @@ slash:
while (*s)
addpath(*s++);
addpath('/');
- if (stat(gpath, &stb) == 0 && isdir(stb))
+ if (stat(*gpath ? gpath : ".", &stb) == 0 && isdir(stb))
if (*p == 0) {
Gcat(gpath, "");
globcnt++;
diff --git a/usr.bin/groups/groups.c b/usr.bin/groups/groups.c
index 6c1660575fcc..4ac8ae9a970b 100644
--- a/usr.bin/groups/groups.c
+++ b/usr.bin/groups/groups.c
@@ -46,33 +46,24 @@ static char sccsid[] = "@(#)groups.c 5.4 (Berkeley) 6/1/90";
*/
#include <sys/param.h>
+#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
-int groups[NGROUPS];
main(argc, argv)
int argc;
char *argv[];
{
- int ngroups, i;
- char *sep = "";
- struct group *gr;
+ register struct passwd *pw;
if (argc > 1)
showgroups(argv[1]);
- ngroups = getgroups(NGROUPS, groups);
- for (i = 0; i < ngroups; i++) {
- gr = getgrgid(groups[i]);
- if (gr == NULL)
- printf("%s%d", sep, groups[i]);
- else
- printf("%s%s", sep, gr->gr_name);
- sep = " ";
- }
- printf("\n");
- exit(0);
+ else if((pw = getpwuid(getuid())) != NULL)
+ showgroups(pw->pw_name);
+ fprintf(stderr, "groups: no such user.\n");
+ exit(1);
}
showgroups(user)
@@ -83,6 +74,10 @@ showgroups(user)
register char **cp;
char *sep = "";
+ if (!user) {
+ fprintf(stderr, "groups: no user name.\n");
+ exit(1);
+ }
if ((pw = getpwnam(user)) == NULL) {
fprintf(stderr, "groups: no such user.\n");
exit(1);
diff --git a/usr.bin/ipcs/Makefile b/usr.bin/ipcs/Makefile
index 0854bca423d5..6bb74748268d 100644
--- a/usr.bin/ipcs/Makefile
+++ b/usr.bin/ipcs/Makefile
@@ -2,5 +2,7 @@
PROG= ipcs
NOMAN= noman
+BINMODE = 2555
+BINGRP = kmem
.include <bsd.prog.mk>
diff --git a/usr.bin/join/join.c b/usr.bin/join/join.c
index bfe526f67889..21973a8a0efe 100644
--- a/usr.bin/join/join.c
+++ b/usr.bin/join/join.c
@@ -42,15 +42,16 @@ char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)join.c 5.1 (Berkeley) 11/18/91";
+/*static char sccsid[] = "from: @(#)join.c 5.1 (Berkeley) 11/18/91";*/
+static char rcsid[] = "$Id: join.c,v 1.4 1994/04/17 09:35:20 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
-#include <errno.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
/*
* There's a structure per input file which encapsulates the state of the
@@ -270,7 +271,7 @@ slurp(F)
LINE tmp;
size_t len;
int cnt;
- char *bp, *fieldp, *token;
+ char *bp, *fieldp;
/*
* Read all of the lines from an input file that have the same
@@ -307,20 +308,30 @@ slurp(F)
F->pushback = -1;
continue;
}
- if ((bp = fgetline(F->fp, &len)) == NULL)
+ if ((bp = fgetln(F->fp, &len)) == NULL)
return;
- while (lp->linealloc <= len) {
- lp->linealloc += 100;
+ if (lp->linealloc <= len + 1) {
+ if (lp->linealloc == 0)
+ lp->linealloc = 128;
+ while (lp->linealloc <= len + 1)
+ lp->linealloc *= 2;
+
if ((lp->line = realloc(lp->line,
lp->linealloc * sizeof(char))) == NULL)
enomem();
}
bcopy(bp, lp->line, len+1);
+ /* Replace trailing newline, if it exists. */
+ if (bp[len - 1] == '\n')
+ lp->line[len - 1] = '\0';
+ else
+ lp->line[len] = '\0';
+ bp = lp->line;
+
/* Split the line into fields, allocate space as necessary. */
- token = lp->line;
lp->fieldcnt = 0;
- while ((fieldp = strsep(&token, tabchar)) != NULL) {
+ while ((fieldp = strsep(&bp, tabchar)) != NULL) {
if (spans && *fieldp == '\0')
continue;
if (lp->fieldcnt == lp->fieldalloc) {
diff --git a/usr.bin/key/Makefile b/usr.bin/key/Makefile
new file mode 100644
index 000000000000..b8553abe3879
--- /dev/null
+++ b/usr.bin/key/Makefile
@@ -0,0 +1,21 @@
+
+# @(#)Makefile 5.6 (Berkeley) 3/5/91
+#
+
+PROG= key
+MAN1= key.1 skey.1
+CFLAGS+=-I${.CURDIR}/../../lib
+
+
+DPADD= /usr/bin/libskey.a
+LDADD= -lskey
+
+.if exists(/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+
+SRCS= skey.c
+
+.include <bsd.prog.mk>
+
diff --git a/usr.bin/key/README.WZV b/usr.bin/key/README.WZV
new file mode 100644
index 000000000000..a13f3b5824c6
--- /dev/null
+++ b/usr.bin/key/README.WZV
@@ -0,0 +1,100 @@
+One of the nice things of S/Key is that it still leaves you the option
+to use regular UNIX passwords. In fact, the presence of S/Key support
+is completely invisible for a user until she has set up a password with
+the keyinit command. You can permit regular UNIX passwords for local
+logins, while at the same time insisting on S/Key passwords for logins
+from outside.
+
+ORIGIN
+
+These files are modified versions of the s/key files found on
+thumper.bellcore.com at 21 oct 1993. They have been fixed to
+run on top of SunOS 4.1.3 and Solaris 2.3.
+
+Installation is described at the end of this file.
+
+USAGE
+
+Use the keyinit command to set up a new series of s/key passwords.
+
+ wzv_6% keyinit
+ Updating wietse:
+ Old key: wz173500
+ Reminder - Only use this method if you are direct connected.
+ If you are using telnet or dial-in exit with no password and use keyinit -s.
+ Enter secret password:
+ Again secret password:
+
+ ID wietse s/key is 99 wz173501
+ BLAH BLA BLAH BLAH BLAH BLA
+
+Be sure to make your secret password sufficiently long. Try using a
+full sentence instead of just one single word.
+
+You will have to do a "keyinit" on every system that you want to login
+on using one-time passwords.
+
+Whenever you log into an s/key protected system you will see
+something like:
+
+ login: wietse
+ s/key 98 wz173501
+ Password:
+
+In this case you can either enter your regular UNIX password or
+your one-time s/key password. For example, I open a local window
+to compute the password:
+
+ local% key 98 wz173501
+ Reminder - Do not use key while logged in via telnet or rlogin.
+ Enter secret password:
+ BLAH BLA BLAH BLAH BLAH BLA
+
+The "BLAH BLA BLAH BLAH BLAH BLA" is the one-time s/key password.
+
+If you have to type the one-time password in by hand, it is convenient
+to have echo turned on so that you can correct typing errors. Just type
+a newline at the "Password:" prompt:
+
+ login: wietse
+ s/key 98 wz173501
+ Password: (turning echo on)
+ Password:BLAH BLA BLAH BLAH BLAH BLA
+
+The 98 in the challenge will be 97 the next time, and so on. You'll get
+a warning when you are about to run out of s/key passwords, so that you
+will have to run the keyinit command again.
+
+Sometimes it is more practical to carry a piece of paper with a small
+series of one-time passwords. You can generate the list with:
+
+ % key -n 10 98 wz173501
+ 98: BLAH BLA BLAH BLAH BLAH BLA
+ 97: ...
+ 96: ...
+
+Be careful when printing material like this!
+
+INSTALLATION
+
+To install, do: make sunos4 (or whatever), then: make install.
+
+The UNIX password is always permitted with non-network logins. By
+default, UNIX passwords are always permitted (the Bellcore code by
+default disallows UNIX passwords but I think that is too painful). In
+order to permit UNIX passwords only with logins from specific networks,
+create a file /etc/skey.access. For example,
+
+ # First word says if UNIX passwords are to be permitted or denied.
+ # remainder of the rule is a networknumber and mask. A rule matches a
+ # host if any of its addresses satisfies:
+ #
+ # network = (address & mask)
+ #
+ #what network mask
+ permit 131.155.210.0 255.255.255.0
+ deny 0.0.0.0 0.0.0.0
+
+This particular example will permit UNIX passwords with logins from any
+host on network 131.155.210, but will insist on one-time passwords in
+all other cases.
diff --git a/usr.bin/key/key.1 b/usr.bin/key/key.1
new file mode 100644
index 000000000000..d9da463712e5
--- /dev/null
+++ b/usr.bin/key/key.1
@@ -0,0 +1,49 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)key.1 1.0 (Bellcore) 12/2/91
+.\"
+.lt 6.0i
+.TH KEY 1 "2 December 1991"
+.AT 3
+.SH NAME
+key \- Stand\-alone program for computing responses to S/Key challenges.
+.SH SYNOPSIS
+.B key [\-n <count>] <Sequence> <key>
+.SH DESCRIPTION
+.I key
+Takes the optional count of the number of one time access
+passwords to print
+along with a (maximum) sequence number and key as command line args,
+it prompts for the user's secret password, and produces both word
+and hex format responses.
+.SH EXAMPLE
+.sh
+ Usage example:
+.sp 0
+ >key \-n 5 99 th91334
+.sp 0
+ Enter password: <your secret password is entered here>
+.sp 0
+ OMEN US HORN OMIT BACK AHOY
+.sp 0
+ .... 4 more passwords.
+.sp 0
+ >
+.LP
+.SH OPTIONS
+.LP
+.B \-n <count>
+the number of one time access passwords to print.
+The default is one.
+.SH DIAGNOSTICS
+.SH BUGS
+.LP
+.SH SEE ALSO
+.BR skey(1),
+.BR keyinit(1),
+.BR keysu(1),
+.BR keyinfo(1)
+.SH AUTHOR
+Command by Phil Karn, Neil M. Haller, John S. Walden
+.SH CONTACT
+staff@thumper.bellcore.com
diff --git a/usr.bin/key/skey.1 b/usr.bin/key/skey.1
new file mode 100644
index 000000000000..0a8b1b668a9e
--- /dev/null
+++ b/usr.bin/key/skey.1
@@ -0,0 +1,59 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)skey.1 1.1 10/28/93
+.\"
+.lt 6.0i
+.TH KEY 1 "28 October 1993"
+.AT 3
+.SH NAME
+S/key \- A proceedure to use one time passwords for accessing computer systems.
+.SH DESCRIPTION
+.I S/key
+is a proceedure for using one time password to authenticate access to
+compter systems. It uses 64 bits of information transformed by the
+MD4 algorithm. The user supplies the 64 bits in the form of 6 English
+words that are generated by a secure computer.
+Example use of the S/key program
+.I key
+.sp
+ Usage example:
+.sp 0
+ >key 99 th91334
+.sp 0
+ Enter password: <your secret password is intered here>
+.sp 0
+ OMEN US HORN OMIT BACK AHOY
+.sp 0
+ >
+.sp
+The programs that are part of the S/Key system are keyinit, key, and
+keyinfo. Keyinit is used to get your ID set up, key is
+used to get the one time password each time,
+keyinfo is used to extract information from the S/Key database.
+.sp
+When you run "keyinit" you inform the system of your
+secret password. Running "key" then generates the
+one-time passwords, and also requires your secret
+password. If however, you misspell your password
+while running "key", you will get a list of passwords
+that will not work, and no indication about the problem.
+.sp
+Password sequence numbers count backward from 99. If you
+don't know this, the syntax for "key" will be confusing.
+.sp
+You can enter the passwords using small letters, even
+though the "key" program gives them in caps.
+.sp
+Macintosh and a general purpose PC use
+are available.
+.sp
+Under FreeBSD, you can control, with /etc/skey.access, from which
+hosts and/or networks the use of S/Key passwords is obligated.
+.LP
+.SH SEE ALSO
+.BR keyinit(1),
+.BR key(1),
+.BR keyinfo(1)
+.BR skey.access(5)
+.SH AUTHOR
+Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin
diff --git a/usr.bin/key/skey.c b/usr.bin/key/skey.c
new file mode 100644
index 000000000000..d1bc239bed99
--- /dev/null
+++ b/usr.bin/key/skey.c
@@ -0,0 +1,128 @@
+/* Stand-alone program for computing responses to S/Key challenges.
+ * Takes the iteration count and seed as command line args, prompts
+ * for the user's key, and produces both word and hex format responses.
+ *
+ * Usage example:
+ * >skey 88 ka9q2
+ * Enter password:
+ * OMEN US HORN OMIT BACK AHOY
+ * C848 666B 6435 0A93
+ * >
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __MSDOS__
+#include <dos.h>
+#else /* Assume BSD unix */
+#include <fcntl.h>
+#endif
+#include "libskey/md4.h"
+#include <skey.h>
+
+char *readpass();
+void usage();
+int getopt();
+extern int optind;
+extern char *optarg;
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int n,cnt,i;
+ char passwd[256],passwd2[256];
+ char key[8];
+ char *seed;
+ char buf[33];
+ char *slash;
+
+ cnt = 1;
+ while((i = getopt(argc,argv,"n:")) != EOF){
+ switch(i){
+ case 'n':
+ cnt = atoi(optarg);
+ break;
+ }
+ }
+ /* could be in the form <number>/<seed> */
+ if(argc <= optind + 1){
+ /*look for / in it */
+ if(argc <= optind){
+ usage(argv[0]);
+ return 1;
+ }
+
+ slash = strchr(argv[optind], '/');
+ if(slash == NULL){
+ usage(argv[0]);
+ return 1;
+ }
+ *slash++ = '\0';
+ seed = slash;
+
+ if((n = atoi(argv[optind])) < 0){
+ fprintf(stderr,"%s not positive\n",argv[optind]);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ else {
+
+ if((n = atoi(argv[optind])) < 0){
+ fprintf(stderr,"%s not positive\n",argv[optind]);
+ usage(argv[0]);
+ return 1;
+ }
+ seed = argv[++optind];
+ }
+ fprintf(stderr,"Reminder - Do not use this program while logged in via telnet or rlogin.\n");
+
+ /* Get user's secret password */
+ for(;;){
+ fprintf(stderr,"Enter secret password: ");
+ readpass(passwd,sizeof(passwd));
+ break;
+ /************
+ fprintf(stderr,"Again secret password: ");
+ readpass(passwd2,sizeof(passwd));
+ if(strcmp(passwd,passwd2) == 0) break;
+ fprintf(stderr, "Sorry no match\n");
+ **************/
+
+ }
+
+ /* Crunch seed and password into starting key */
+ if(keycrunch(key,seed,passwd) != 0){
+ fprintf(stderr,"%s: key crunch failed\n",argv[0]);
+ return 1;
+ }
+ if(cnt == 1){
+ while(n-- != 0)
+ f(key);
+ printf("%s\n",btoe(buf,key));
+#ifdef HEXIN
+ printf("%s\n",put8(buf,key));
+#endif
+ } else {
+ for(i=0;i<=n-cnt;i++)
+ f(key);
+ for(;i<=n;i++){
+#ifdef HEXIN
+ printf("%d: %-29s %s\n",i,btoe(buf,key),put8(buf,key));
+#else
+ printf("%d: %-29s\n",i,btoe(buf,key));
+#endif
+ f(key);
+ }
+ }
+ return 0;
+}
+void
+usage(s)
+char *s;
+{
+ fprintf(stderr,"Usage: %s [-n count] <sequence #>[/] <key> \n",s);
+}
+
diff --git a/usr.bin/keyinfo/Makefile b/usr.bin/keyinfo/Makefile
new file mode 100644
index 000000000000..41baee6e1d5f
--- /dev/null
+++ b/usr.bin/keyinfo/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 5.5 (Berkeley) 7/1/90
+
+MAN1= keyinfo.1
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/keyinfo.sh ${DESTDIR}${BINDIR}/keyinfo
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keyinfo/keyinfo.1 b/usr.bin/keyinfo/keyinfo.1
new file mode 100644
index 000000000000..b12aa962b990
--- /dev/null
+++ b/usr.bin/keyinfo/keyinfo.1
@@ -0,0 +1,40 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)keyinfo.1 1.1 (Bellcore) 7/20/93
+.\"
+.lt 6.0i
+.TH KEYINFO 1 "20 July 1993"
+.AT 3
+.SH NAME
+keyinfo \- display current S/Key sequence number and seed
+.SH SYNOPSIS
+.B keyinfo [username]
+.SH DESCRIPTION
+.I keyinfo
+takes an optional user name and displays the user\'s current sequence
+number and seed found in the S/Key database /etc/skeykeys.
+.sp 1
+The command can be useful when generating a list of passwords for use
+on a field trip, by combining with the command
+.I key
+in the form:
+.sp
+ >key \-n <number of passwords to print> `keyinfo`|lpr
+.SH EXAMPLE
+.sh
+Usage example:
+.sp 0
+ >keyinfo
+.sp 0
+ 0098 ws91340
+.LP
+.SH ARGUMENTS
+.TP
+.B username
+The S/key user to display the information for. The default is
+to display S/Key information on the user who invokes the command.
+.SH SEE ALSO
+.BR keyinit(1),
+.BR key(1)
+.SH AUTHOR
+Command by Phil Karn, Neil M. Haller, John S. Walden
diff --git a/usr.bin/keyinfo/keyinfo.sh b/usr.bin/keyinfo/keyinfo.sh
new file mode 100644
index 000000000000..5879442db188
--- /dev/null
+++ b/usr.bin/keyinfo/keyinfo.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# search /etc/skeykeys for the skey string for this user OR user specified
+# in 1st parameter
+
+PATH=/bin:/usr/bin
+
+test -f /etc/skeykeys && {
+ WHO=${1-`id | sed 's/^[^(]*(\([^)]*\).*/\1/'`}
+ awk '/^'${WHO}'[ ]/ { print $2-1, $3 }' /etc/skeykeys
+}
diff --git a/usr.bin/keyinit/Makefile b/usr.bin/keyinit/Makefile
new file mode 100644
index 000000000000..a716f14cb3d9
--- /dev/null
+++ b/usr.bin/keyinit/Makefile
@@ -0,0 +1,20 @@
+
+# @(#)Makefile 5.6 (Berkeley) 3/5/91
+#
+
+PROG= keyinit
+MAN1= keyinit.1
+DPADD= /usr/bin/libskey.a
+LDADD= -lskey
+
+.if exists(/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+
+SRCS= skeyinit.c
+
+BINOWN= root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keyinit/keyinit.1 b/usr.bin/keyinit/keyinit.1
new file mode 100644
index 000000000000..2fe2d03944db
--- /dev/null
+++ b/usr.bin/keyinit/keyinit.1
@@ -0,0 +1,64 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)keyinit.1 1.0 (Bellcore) 7/20/93
+.\"
+.lt 6.0i
+.TH KEYINIT 1 "20 July 1993"
+.AT 3
+.SH NAME
+keyinit \- Change password or add user to S/Key authentication system.
+.SH SYNOPSIS
+.B keyinit [\-s] [<user ID >]
+.SH DESCRIPTION
+.I keyinit
+initializes the system so you can use S/Key one-time passwords to
+login. The program will ask you to enter a secret pass phrase; enter a
+phrase of several words in response. After the S/Key database has been
+updated you can login using either your regular UNIX password or using
+S/Key one-time passwords.
+.PP
+When logging in from another machine you can avoid typing a real
+password over the network, by typing your S/Key pass phrase to the
+\fIkey\fR command on the local machine: the program will respond with
+the one-time password that you should use to log into the remote
+machine. This is most conveniently done with cut-and-paste operations
+using a mouse. Alternatively, you can pre-compute one-time passwords
+using the \fIkey\fR command and carry them with you on a piece of paper.
+.PP
+\fIkeyinit\fR requires you to type your secret password, so it should
+be used only on a secure terminal. For example, on the console of a
+workstation. If you are using \fIkeyinit\fR while logged in over an
+untrusted network, follow the instructions given below with the \-s
+option.
+.SH OPTIONS
+.IP \-s
+Set secure mode where the user is expected to have used a secure
+machine to generate the first one time password. Without the \-s the
+system will assume you are direct connected over secure communications
+and prompt you for your secret password.
+The \-s option also allows one to set the seed and count for complete
+control of the parameters. You can use keyinit -s in compination with
+the
+.I key
+command to set the seed and count if you do not like the defaults.
+To do this run keyinit in one window and put in your count and seed
+then run key in another window to generate the correct 6 english words
+for that count and seed. You can then
+"cut" and "paste" them or copy them into the keyinit window.
+.sp
+.LP
+.B <user ID>
+the ID for the user to be changed/added
+.SH DIAGNOSTICS
+.SH FILES
+.TP
+/etc/skeykeys data base of information for S/Key system.
+.SH BUGS
+.LP
+.SH SEE ALSO
+.BR skey(1),
+.BR key(1),
+.BR keysu(1),
+.BR keyinfo(1)
+.SH AUTHOR
+Command by Phil Karn, Neil M. Haller, John S. Walden
diff --git a/usr.bin/keyinit/skeyinit.c b/usr.bin/keyinit/skeyinit.c
new file mode 100644
index 000000000000..7c8e5d6f1c6d
--- /dev/null
+++ b/usr.bin/keyinit/skeyinit.c
@@ -0,0 +1,194 @@
+/* change password or add user to S/KEY authentication system.
+ * S/KEY is a tradmark of Bellcore */
+
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <skey.h>
+#include <time.h>
+
+extern int optind;
+extern char *optarg;
+
+char * readpass();
+
+int skeylookup __P((struct skey *mp,char *name));
+
+#define NAMELEN 2
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ struct skey skey;
+ int rval,n,nn,i,defaultsetup;
+ char seed[18],tmp[80],key[8];
+ struct passwd *ppuser,*pp;
+ char defaultseed[17], passwd[256],passwd2[256] ;
+
+
+ time_t now;
+ struct tm *tm;
+ char tbuf[27],buf[60];
+ char lastc, me[80];
+ int l;
+
+ time(&now);
+#if 0 /* Choose a more random seed */
+ tm = localtime(&now);
+ strftime(tbuf, sizeof(tbuf), "%M%j", tm);
+#else
+ sprintf(tbuf, "%05ld", (long) (now % 100000));
+#endif
+ gethostname(defaultseed,NAMELEN);
+ strcpy(&defaultseed[NAMELEN],tbuf);
+
+ pp = ppuser = getpwuid(getuid());
+ strcpy(me,pp->pw_name);
+ defaultsetup = 1;
+ if( argc > 1){
+ if(strcmp("-s", argv[1]) == 0)
+ defaultsetup = 0;
+ else
+ pp = getpwnam(argv[1]);
+ if(argc > 2)
+ pp = getpwnam(argv[2]);
+
+ }
+ if(pp == NULL){
+ printf("User unknown\n");
+ return 1;
+ }
+ if(strcmp( pp->pw_name,me) != 0){
+ if(getuid() != 0){
+ /* Only root can change other's passwds */
+ printf("Permission denied.\n");
+ return(1);
+ }
+ }
+
+
+
+ rval = skeylookup(&skey,pp->pw_name);
+ switch(rval){
+ case -1:
+ perror("error in opening database");
+ return 1;
+ case 0:
+ printf("Updating %s:\n",pp->pw_name);
+ printf("Old key: %s\n",skey.seed);
+ /* lets be nice if they have a skey.seed that ends in 0-8 just add one*/
+ l = strlen(skey.seed);
+ if( l > 0){
+ lastc = skey.seed[l-1];
+ if( isdigit(lastc) && lastc != '9' ){
+ strcpy(defaultseed, skey.seed);
+ defaultseed[l-1] = lastc + 1;
+ }
+ if( isdigit(lastc) && lastc == '9' && l < 16){
+ strcpy(defaultseed, skey.seed);
+ defaultseed[l-1] = '0';
+ defaultseed[l] = '0';
+ defaultseed[l+1] = '\0';
+ }
+ }
+ break;
+ case 1:
+ skey.val = 0; /* XXX */
+ printf("Adding %s:\n",pp->pw_name);
+ break;
+ }
+ n = 99;
+ if( ! defaultsetup){
+ printf("Reminder you need the 6 english words from the skey command.\n");
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ printf("Enter sequence count from 1 to 10000: ");
+ fgets(tmp,sizeof(tmp),stdin);
+ n = atoi(tmp);
+ if(n > 0 && n < 10000)
+ break; /* Valid range */
+ printf("Count must be > 0 and < 10000\n");
+ }
+ }
+ if( !defaultsetup){
+ printf("Enter new key [default %s]: ", defaultseed);
+ fflush(stdout);
+ fgets(seed,sizeof(seed),stdin);
+ rip(seed);
+ if(strlen(seed) > 16){
+ printf("Seed truncated to 16 chars\n");
+ seed[16] = '\0';
+ }
+ if( seed[0] == '\0') strcpy(seed,defaultseed);
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ printf("s/key %d %s\ns/key access password: ",n,seed);
+ fgets(tmp,sizeof(tmp),stdin);
+ rip(tmp);
+ backspace(tmp);
+ if(tmp[0] == '?'){
+ printf("Enter 6 English words from secure S/Key calculation.\n");
+ continue;
+ }
+ if(tmp[0] == '\0'){
+ exit(1);
+ }
+ if(etob(key,tmp) == 1 || atob8(key,tmp) == 0)
+ break; /* Valid format */
+ printf("Invalid format, try again with 6 English words.\n");
+ }
+ } else {
+ /* Get user's secret password */
+ fprintf(stderr,"Reminder - Only use this method if you are directly connected.\n");
+ fprintf(stderr,"If you are using telnet or rlogin exit with no password and use keyinit -s.\n");
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ fprintf(stderr,"Enter secret password: ");
+ readpass(passwd,sizeof(passwd));
+ if(passwd[0] == '\0'){
+ exit(1);
+ }
+ fprintf(stderr,"Again secret password: ");
+ readpass(passwd2,sizeof(passwd));
+ if(passwd2[0] == '\0'){
+ exit(1);
+ }
+ if(strlen(passwd) < 4 && strlen(passwd2) < 4) {
+ fprintf(stderr, "Sorry your password must be longer\n\r");
+ exit(1);
+ }
+ if(strcmp(passwd,passwd2) == 0) break;
+ fprintf(stderr, "Sorry no match\n");
+
+
+ }
+ strcpy(seed,defaultseed);
+
+ /* Crunch seed and password into starting key */
+ if(keycrunch(key,seed,passwd) != 0){
+ fprintf(stderr,"%s: key crunch failed\n",argv[0]);
+ return 1;
+ }
+ nn = n;
+ while(nn-- != 0)
+ f(key);
+ }
+ time(&now);
+ tm = localtime(&now);
+ strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
+ if (skey.val == NULL)
+ skey.val = (char *) malloc(16+1);
+
+
+ btoa8(skey.val,key);
+ fprintf(skey.keyfile,"%s %04d %-16s %s %-21s\n",pp->pw_name,n,
+ seed,skey.val, tbuf);
+ fclose(skey.keyfile);
+ printf("\nID %s s/key is %d %s\n",pp->pw_name,n,seed);
+ printf("%s\n",btoe(buf,key));
+#ifdef HEXIN
+ printf("%s\n",put8(buf,key));
+#endif
+ return 0;
+}
diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c
index 99a46527b6a2..36e7280fbba8 100644
--- a/usr.bin/last/last.c
+++ b/usr.bin/last/last.c
@@ -264,8 +264,8 @@ want(bp, check)
*/
if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
bp->ut_line[3] = '\0';
- else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
- bp->ut_line[4] = '\0';
+ else if (!strncmp(bp->ut_line, "uu", sizeof("uu") - 1))
+ bp->ut_line[2] = '\0';
if (!arglist)
return(YES);
diff --git a/usr.bin/lex/lib/Makefile b/usr.bin/lex/lib/Makefile
index a1d0fb427853..ac9d285893c3 100644
--- a/usr.bin/lex/lib/Makefile
+++ b/usr.bin/lex/lib/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 5.1 (Berkeley) 6/18/90
SHLIB_MAJOR=1
-SHLIB_MINOR=0
+SHLIB_MINOR=1
LIB= ln
SRCS= libmain.c
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
index 9b496a38fb10..f181a7ae8442 100644
--- a/usr.bin/login/Makefile
+++ b/usr.bin/login/Makefile
@@ -1,16 +1,24 @@
# @(#)Makefile 5.6 (Berkeley) 6/24/90
PROG= login
-SRCS= klogin.c login.c
-DPADD= ${LIBUTIL}
-LDADD= -lutil
+MAN5= login.access.5
+MAN1= login.1
+SRCS= klogin.c login.c login_access.c login_skey.c
+DPADD= ${LIBUTIL} ${LIBSKEY}
+LDADD= -lutil -lskey
BINOWN= root
BINMODE=4555
+#CFLAGS+=-DLOGIN_ACCESS -DSKEY -DLOGALL -I${.CURDIR}/../../lib
+CFLAGS+=-DLOGIN_ACCESS -DSKEY
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS
.endif
.include <bsd.prog.mk>
diff --git a/usr.bin/login/README b/usr.bin/login/README
new file mode 100644
index 000000000000..6ad7a10d4796
--- /dev/null
+++ b/usr.bin/login/README
@@ -0,0 +1,10 @@
+This login has additional functionalities. They are all based on (part of)
+Wietse Venema's logdaemon package.
+
+
+The following defines can be used:
+1) LOGIN_ACCESS to allow access control on a per tty/user combination
+2) SKEY to allow the use of s/key one time passwords
+3) LOGALL to log all logins
+
+-Guido
diff --git a/usr.bin/login/klogin.c b/usr.bin/login/klogin.c
index faf5aa63adfb..4063611520fe 100644
--- a/usr.bin/login/klogin.c
+++ b/usr.bin/login/klogin.c
@@ -171,7 +171,7 @@ klogin(pw, instance, localhost, password)
}
/* undecipherable: probably didn't have a srvtab on the local host */
- if (kerror = RD_AP_UNDEC) {
+ if (kerror == RD_AP_UNDEC) {
syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]);
dest_tkt();
return(1);
diff --git a/usr.bin/login/login.access.5 b/usr.bin/login/login.access.5
new file mode 100644
index 000000000000..28d423c9156c
--- /dev/null
+++ b/usr.bin/login/login.access.5
@@ -0,0 +1,50 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt SKEY.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm login.access
+.Nd Login access control table
+.Sh DESCRIPTION
+The
+.Nm login.access
+file specifies (user, host) combinations and/or (user, tty)
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the
+.Nm login.access
+is scanned for the first entry that
+matches the (user, host) combination, or, in case of non-networked
+logins, the first entry that matches the (user, tty) combination. The
+permissions field of that table entry determines whether the login will
+be accepted or refused.
+.Pp
+Each line of the login access control table has three fields separated by a
+":" character: permission : users : origins
+
+The first field should be a "+" (access granted) or "-" (access denied)
+character. The second field should be a list of one or more login names,
+group names, or ALL (always matches). The third field should be a list
+of one or more tty names (for non-networked logins), host names, domain
+names (begin with "."), host addresses, internet network numbers (end
+with "."), ALL (always matches) or LOCAL (matches any string that does
+not contain a "." character). If you run NIS you can use @netgroupname
+in host or user patterns.
+
+The EXCEPT operator makes it possible to write very compact rules.
+
+The group file is searched only when a name does not match that of the
+logged-in user. Only groups are matched in which users are explicitly
+listed: the program does not look at a user's primary group id value.
+.Sh FILES
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+The
+.Nm login.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr login 1
+.Sh AUTHOR
+Guido van Rooij
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
index ad1d4d60ad57..ab0adf8280dc 100644
--- a/usr.bin/login/login.c
+++ b/usr.bin/login/login.c
@@ -117,6 +117,10 @@ main(argc, argv)
char *domain, *salt, *ttyn;
char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
char localhost[MAXHOSTNAMELEN];
+#ifdef SKEY
+ int permit_passwd = 0;
+ char *skey_getpass(), *skey_crypt();
+#endif /* SKEY */
(void)signal(SIGALRM, timedout);
(void)alarm((u_int)timeout);
@@ -152,9 +156,11 @@ main(argc, argv)
exit(1);
}
hflag = 1;
+#ifndef SKEY
if (domain && (p = index(optarg, '.')) &&
strcasecmp(p, domain) == 0)
*p = 0;
+#endif /* SKEY */
hostname = optarg;
break;
case 'p':
@@ -190,6 +196,10 @@ main(argc, argv)
else
tty = ttyn;
+#ifdef SKEY
+ permit_passwd = (hostname == 0 || authfile(hostname) != 0);
+#endif
+
for (cnt = 0;; ask = 1) {
if (ask) {
fflag = 0;
@@ -248,7 +258,11 @@ main(argc, argv)
(void)setpriority(PRIO_PROCESS, 0, -4);
+#ifdef SKEY
+ p = skey_getpass("Password:", pwd, permit_passwd);
+#else
p = getpass("Password:");
+#endif /* SKEY */
if (pwd) {
#ifdef KERBEROS
@@ -256,9 +270,19 @@ main(argc, argv)
if (rval == 0)
authok = 1;
else if (rval == 1)
+#ifdef SKEY
+ rval = strcmp(skey_crypt(p, salt, pwd, permit_passwd),
+ pwd->pw_passwd);
+#else
rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+#endif /* SKEY */
+#else
+#ifdef SKEY
+ rval = strcmp(skey_crypt(p, salt, pwd, permit_passwd),
+ pwd->pw_passwd);
#else
rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+#endif /* SKEY */
#endif
}
bzero(p, strlen(p));
@@ -393,6 +417,18 @@ main(argc, argv)
(void)printf("Warning: no Kerberos tickets issued.\n");
#endif
+#ifdef LOGALL
+ /*
+ * Syslog each successful login, so we don't have to watch hundreds
+ * of wtmp or lastlogin files.
+ */
+ if (hostname) {
+ syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name);
+ } else {
+ syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name);
+ }
+#endif
+
if (!quietlog) {
(void)printf(
"Copyright (c) 1980,1983,1986,1988,1990,1991 The Regents of the University\n%s",
@@ -405,6 +441,19 @@ main(argc, argv)
(st.st_mtime > st.st_atime) ? "new " : "");
}
+#ifdef LOGIN_ACCESS
+ if (login_access(pwd->pw_name, hostname ? hostname : tty) == 0) {
+ printf("Permission denied\n");
+ if (hostname)
+ syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s",
+ pwd->pw_name, hostname);
+ else
+ syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s",
+ pwd->pw_name, tty);
+ sleepexit(1);
+ }
+#endif
+
(void)signal(SIGALRM, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
diff --git a/usr.bin/login/login_access.c b/usr.bin/login/login_access.c
new file mode 100644
index 000000000000..90de8e0ae368
--- /dev/null
+++ b/usr.bin/login/login_access.c
@@ -0,0 +1,236 @@
+ /*
+ * This module implements a simple but effective form of login access
+ * control based on login names and on host (or domain) names, internet
+ * addresses (or network numbers), or on terminal line names in case of
+ * non-networked logins. Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifdef LOGIN_ACCESS
+#ifndef lint
+static char sccsid[] = "%Z% %M% %I% %E% %U%";
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pathnames.h"
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":"; /* field separator */
+static char sep[] = ", \t"; /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES 1
+#define NO 0
+
+static int list_match();
+static int user_match();
+static int from_match();
+static int string_match();
+
+/* login_access - match username/group and host/tty with access control file */
+
+login_access(user, from)
+char *user;
+char *from;
+{
+ FILE *fp;
+ char line[BUFSIZ];
+ char *perm; /* becomes permission field */
+ char *users; /* becomes list of login names */
+ char *froms; /* becomes list of terminals or hosts */
+ int match = NO;
+ int end;
+ int lineno = 0; /* for diagnostics */
+
+ /*
+ * Process the table one line at a time and stop at the first match.
+ * Blank lines and lines that begin with a '#' character are ignored.
+ * Non-comment lines are broken at the ':' character. All fields are
+ * mandatory. The first field should be a "+" or "-" character. A
+ * non-existing table means no access control.
+ */
+
+ if (fp = fopen(_PATH_LOGACCESS, "r")) {
+ while (!match && fgets(line, sizeof(line), fp)) {
+ lineno++;
+ if (line[end = strlen(line) - 1] != '\n') {
+ syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+ _PATH_LOGACCESS, lineno);
+ continue;
+ }
+ if (line[0] == '#')
+ continue; /* comment line */
+ while (end > 0 && isspace(line[end - 1]))
+ end--;
+ line[end] = 0; /* strip trailing whitespace */
+ if (line[0] == 0) /* skip blank lines */
+ continue;
+ if (!(perm = strtok(line, fs))
+ || !(users = strtok((char *) 0, fs))
+ || !(froms = strtok((char *) 0, fs))
+ || strtok((char *) 0, fs)) {
+ syslog(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ if (perm[0] != '+' && perm[0] != '-') {
+ syslog(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ match = (list_match(froms, from, from_match)
+ && list_match(users, user, user_match));
+ }
+ (void) fclose(fp);
+ } else if (errno != ENOENT) {
+ syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS);
+ }
+ return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int list_match(list, item, match_fn)
+char *list;
+char *item;
+int (*match_fn) ();
+{
+ char *tok;
+ int match = NO;
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+ if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ break;
+ if (match = (*match_fn) (tok, item)) /* YES */
+ break;
+ }
+ /* Process exceptions to matches. */
+
+ if (match != NO) {
+ while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+ /* VOID */ ;
+ if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+ return (match);
+ }
+ return (NO);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int netgroup_match(group, machine, user)
+char *machine;
+char *user;
+{
+#ifdef NIS
+ static char *mydomain = 0;
+
+ if (mydomain == 0)
+ yp_get_default_domain(&mydomain);
+ return (innetgr(group, machine, user, mydomain));
+#else
+ syslog(LOG_ERR, "NIS netgroup support not configured");
+#endif
+}
+
+/* user_match - match a username against one token */
+
+static int user_match(tok, string)
+char *tok;
+char *string;
+{
+ struct group *group;
+ int i;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the username, or if
+ * the token is a group that contains the username.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (group = getgrnam(tok)) { /* try group membership */
+ for (i = 0; group->gr_mem[i]; i++)
+ if (strcasecmp(string, group->gr_mem[i]) == 0)
+ return (YES);
+ }
+ return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int from_match(tok, string)
+char *tok;
+char *string;
+{
+ int tok_len;
+ int str_len;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds. Return
+ * YES if the token fully matches the string. If the token is a domain
+ * name, return YES if it matches the last fields of the string. If the
+ * token has the magic value "LOCAL", return YES if the string does not
+ * contain a "." character. If the token is a network number, return YES
+ * if it matches the head of the string.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, string, (char *) 0));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return (YES);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == 0)
+ return (YES);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+ && strncmp(tok, string, tok_len) == 0) {
+ return (YES);
+ }
+ return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int string_match(tok, string)
+char *tok;
+char *string;
+{
+
+ /*
+ * If the token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the string.
+ */
+
+ if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
+ return (YES);
+ } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+ return (YES);
+ }
+ return (NO);
+}
+#endif /* LOGIN_ACCES */
diff --git a/usr.bin/login/login_skey.c b/usr.bin/login/login_skey.c
new file mode 100644
index 000000000000..b94bd28ad9cb
--- /dev/null
+++ b/usr.bin/login/login_skey.c
@@ -0,0 +1,105 @@
+ /* Portions taken from the skey distribution on Oct 21 1993 */
+#ifdef SKEY
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <termios.h>
+#include <pwd.h>
+#include <syslog.h>
+
+#include <skey.h>
+
+/* skey_getpass - read regular or s/key password */
+
+char *skey_getpass(prompt, pwd, pwok)
+char *prompt;
+struct passwd *pwd;
+int pwok;
+{
+ static char buf[128];
+ struct skey skey;
+ char *cp;
+ void rip();
+ struct termios saved_ttymode;
+ struct termios noecho_ttymode;
+ char *username = pwd ? pwd->pw_name : "nope";
+ int sflag;
+
+ /* Attempt an s/key challenge. */
+
+ if ((sflag = skeychallenge(&skey, username, buf)) == 0) {
+ printf("%s\n", buf);
+ }
+ if (!pwok) {
+ printf("(s/key required)\n");
+ }
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ /* Save current input modes and turn echo off. */
+
+ tcgetattr(0, &saved_ttymode);
+ tcgetattr(0, &noecho_ttymode);
+ noecho_ttymode.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSANOW, &noecho_ttymode);
+
+ /* Read password. */
+
+ buf[0] = 0;
+ fgets(buf, sizeof(buf), stdin);
+ rip(buf);
+
+ /* Restore previous input modes. */
+
+ tcsetattr(0, TCSANOW, &saved_ttymode);
+
+ /* Give S/Key users a chance to do it with echo on. */
+
+ if (sflag == 0 && feof(stdin) == 0 && buf[0] == 0) {
+ fputs(" (turning echo on)\n", stdout);
+ fputs(prompt, stdout);
+ fflush(stdout);
+ fgets(buf, sizeof(buf), stdin);
+ rip(buf);
+ } else {
+ putchar('\n');
+ }
+ return (buf);
+}
+
+/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */
+
+char *skey_crypt(pp, salt, pwd, pwok)
+char *pp;
+char *salt;
+struct passwd *pwd;
+int pwok;
+{
+ struct skey skey;
+ char *p;
+ char *crypt();
+
+ /* Try s/key authentication even when the UNIX password is permitted. */
+
+ if (pwd != 0 && skeylookup(&skey, pwd->pw_name) == 0
+ && skeyverify(&skey, pp) == 0) {
+ /* s/key authentication succeeded */
+ if (skey.n < 5)
+ printf("Warning! Change s/key password soon\n");
+ return (pwd->pw_passwd);
+ }
+
+ /* When s/key authentication does not work, always invoke crypt(). */
+
+ p = crypt(pp, salt);
+ if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0)
+ return (pwd->pw_passwd);
+
+ /* The user does not exist or entered bad input. */
+
+ return (":");
+}
+#endif SKEY
diff --git a/usr.bin/login/pathnames.h b/usr.bin/login/pathnames.h
index 1c8ff9dd07b3..22e579cf7ef0 100644
--- a/usr.bin/login/pathnames.h
+++ b/usr.bin/login/pathnames.h
@@ -37,3 +37,4 @@
#define _PATH_HUSHLOGIN ".hushlogin"
#define _PATH_MOTDFILE "/etc/motd"
+#define _PATH_LOGACCESS "/etc/login.access"
diff --git a/usr.bin/mail/Makefile b/usr.bin/mail/Makefile
index 884825ef3ced..d5601414346d 100644
--- a/usr.bin/mail/Makefile
+++ b/usr.bin/mail/Makefile
@@ -6,7 +6,6 @@ SRCS= version.c aux.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c edit.c fio.c \
getname.c head.c v7.local.c lex.c list.c main.c names.c popen.c \
quit.c send.c strings.c temp.c tty.c vars.c
SFILES= mail.help mail.tildehelp
-EFILES= mail.rc
LINKS= ${BINDIR}/mail ${BINDIR}/Mail
MLINKS= mail.1 Mail.1
@@ -14,6 +13,6 @@ beforeinstall:
cd ${.CURDIR}/misc; install -c -o ${BINOWN} -g ${BINGRP} \
-m 444 ${SFILES} ${DESTDIR}/usr/share/misc
cd ${.CURDIR}/misc; install -c -o ${BINOWN} -g ${BINGRP} \
- -m 444 ${EFILES} ${DESTDIR}/etc
+ -m 444 mail.rc ${DESTDIR}/etc/mail.rc.sample
.include <bsd.prog.mk>
diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1
index 7b70e4666573..1f17f1052b0b 100644
--- a/usr.bin/mail/mail.1
+++ b/usr.bin/mail/mail.1
@@ -833,6 +833,9 @@ of a message you are sending.
.It Ar hold
This option is used to hold messages in the system mailbox
by default.
+.It Ar keep
+With this option, the system mailbox will never be removed, even when
+it has zero length.
.It Ar ignore
Causes interrupt signals from your terminal to be ignored and echoed as
@'s.
diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c
index bb746dcecd12..b46d187466ba 100644
--- a/usr.bin/make/str.c
+++ b/usr.bin/make/str.c
@@ -137,8 +137,14 @@ brk_string(str, store_argc)
inquote = NULL;
else
break;
- else
+ else {
inquote = ch;
+ /* Don't miss "" or '' */
+ if (start == NULL && p[1] == inquote) {
+ start = t + 1;
+ break;
+ }
+ }
continue;
case ' ':
case '\t':
diff --git a/usr.bin/mesg/mesg.c b/usr.bin/mesg/mesg.c
index 308dc6f48aff..8ef873c581c2 100644
--- a/usr.bin/mesg/mesg.c
+++ b/usr.bin/mesg/mesg.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: mesg.c,v 1.3.2.1 1994/05/04 08:00:52 rgrimes Exp $
+ * $Id: mesg.c,v 1.4 1994/05/04 08:34:33 rgrimes Exp $
*/
/*
* Copyright (c) 1987 Regents of the University of California.
diff --git a/usr.bin/more/output.c b/usr.bin/more/output.c
index 0f805036cfb3..01c9aa8d836c 100644
--- a/usr.bin/more/output.c
+++ b/usr.bin/more/output.c
@@ -226,7 +226,7 @@ error(s)
}
lower_left();
- if (strlen(s) + sizeof(return_to_continue) +
+ if ((s==NULL)?0:(strlen(s)) + sizeof(return_to_continue) +
so_width + se_width + 1 > sc_width)
/*
* Printing the message has probably scrolled the screen.
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index e2db444a1835..8f0933dac7d1 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 5.14 (Berkeley) 6/18/90
PROG= netstat
-SRCS= inet.c if.c main.c mbuf.c route.c unix.c
+SRCS= inet.c if.c main.c mbuf.c route.c unix.c mroute.c
#SRCS+= host.c
#CFLAGS+= -DIMP
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 8e75e41c7c1e..e7942115dad2 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -34,7 +34,7 @@
#ifndef lint
/* From: static char sccsid[] = "@(#)if.c 5.15 (Berkeley) 3/1/91"; */
static const char if_c_rcsid[] =
- "$Id: if.c,v 1.3 1994/02/21 11:35:23 rgrimes Exp $";
+ "$Id: if.c,v 1.4 1994/05/17 21:10:14 jkh Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -61,6 +61,7 @@ static const char if_c_rcsid[] =
#define YES 1
#define NO 0
+extern int aflag;
extern int tflag;
extern int dflag;
extern int nflag;
@@ -70,6 +71,21 @@ extern char *routename(), *netname(), *ns_phost();
char *index();
/*
+ * Return a printable string representation of an Ethernet address.
+ */
+char *etherprint(enaddr)
+ char enaddr[6];
+{
+ static char string[18];
+ unsigned char *en = (unsigned char *)enaddr;
+
+ sprintf(string, "%02x:%02x:%02x:%02x:%02x:%02x",
+ en[0], en[1], en[2], en[3], en[4], en[5] );
+ string[17] = '\0';
+ return(string);
+}
+
+/*
* Print a description of the network interfaces.
*/
intpr(interval, ifnetaddr)
@@ -87,7 +103,7 @@ intpr(interval, ifnetaddr)
struct iso_ifaddr iso;
#endif
} ifaddr;
- off_t ifaddraddr;
+ off_t ifaddraddr, ifaddrfound, ifnetfound;
struct sockaddr *sa;
char name[16];
@@ -110,12 +126,14 @@ intpr(interval, ifnetaddr)
printf(" %s", "Drop");
putchar('\n');
ifaddraddr = 0;
+ ifnetfound = 0;
while (ifnetaddr || ifaddraddr) {
struct sockaddr_in *sin;
register char *cp;
int n, m;
struct in_addr inet_makeaddr();
+ ifnetfound = ifnetaddr;
if (ifaddraddr == 0) {
kvm_read(ifnetaddr, (char *)&ifnet, sizeof ifnet);
kvm_read((off_t)ifnet.if_name, name, 16);
@@ -132,6 +150,7 @@ intpr(interval, ifnetaddr)
ifaddraddr = (off_t)ifnet.if_addrlist;
}
printf("%-5.5s %-5d ", name, ifnet.if_mtu);
+ ifaddrfound = ifaddraddr;
if (ifaddraddr == 0) {
printf("%-11.11s ", "none");
printf("%-15.15s ", "none");
@@ -213,6 +232,75 @@ intpr(interval, ifnetaddr)
if (dflag)
printf(" %3d", ifnet.if_snd.ifq_drops);
putchar('\n');
+
+ /*XXX this needs work for bsdi */
+ if (aflag && ifaddrfound) {
+ /*
+ * print any internet multicast addresses
+ */
+ switch (sa->sa_family) {
+ case AF_INET:
+ {
+ off_t multiaddr;
+ struct in_multi inm;
+
+ multiaddr = (off_t)ifaddr.in.ia_multiaddrs;
+ while (multiaddr != 0) {
+ kvm_read(multiaddr, (char *)&inm,
+ sizeof inm);
+ multiaddr = (off_t)inm.inm_next;
+ printf("%23s %-19.19s\n", "",
+ routename(inm.inm_addr.s_addr));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+#ifdef notyet
+ if (aflag && ifaddraddr == 0) {
+ /*
+ * print link-level addresses
+ * (Is there a better way to determine
+ * the type of network??)
+ */
+ if (strncmp(name, "qe", 2) == 0 || /* Ethernet */
+ strncmp(name, "de", 2) == 0 ||
+ strncmp(name, "ex", 2) == 0 ||
+ strncmp(name, "il", 2) == 0 ||
+ strncmp(name, "le", 2) == 0 ||
+ strncmp(name, "se", 2) == 0 ||
+ strncmp(name, "ie", 2) == 0) {
+ strncmp(name, "we", 2) == 0) {
+ strncmp(name, "el", 2) == 0) {
+ /* "ec", the 3Com interface for Suns, is not */
+ /* included, although it does handle multicast, */
+ /* because it does not filter specific ethernet */
+ /* multicast addresses, but just accepts all. */
+ off_t multiaddr;
+ struct arpcom ac;
+ struct ether_multi enm;
+
+ kvm_read(ifnetfound, (char *)&ac, sizeof ac);
+ printf("%23s %s\n", "",
+ etherprint(&ac.ac_enaddr));
+ multiaddr = (off_t)ac.ac_multiaddrs;
+ while (multiaddr != 0) {
+ kvm_read(multiaddr, (char *)&enm,
+ sizeof enm);
+ multiaddr = (off_t)enm.enm_next;
+ printf("%23s %s", "",
+ etherprint(&enm.enm_addrlo));
+ if (bcmp(&enm.enm_addrlo,
+ &enm.enm_addrhi, 6) != 0)
+ printf(" to %s",
+ etherprint(&enm.enm_addrhi));
+ printf("\n");
+ }
+ }
+ }
+#endif
}
}
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index ed80baea14c5..cb7a29eeb1c5 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -34,7 +34,7 @@
#ifndef lint
/* From: static char sccsid[] = "@(#)inet.c 5.15 (Berkeley) 6/18/90"; */
static const char inet_c_rcsid[] =
- "$Id: inet.c,v 1.2 1993/11/17 20:19:20 wollman Exp $";
+ "$Id: inet.c,v 1.3 1994/05/17 21:10:15 jkh Exp $";
#endif /* not lint */
@@ -51,6 +51,7 @@ static const char inet_c_rcsid[] =
#include <netinet/in_pcb.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
+#include <netinet/igmp_var.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
@@ -342,6 +343,47 @@ icmp_stats(off, name)
printf("\t%u message response%s generated\n",
icmpstat.icps_reflect, plural(icmpstat.icps_reflect));
}
+
+char*
+pluraly(n)
+{
+ return (n == 1? "y" : "ies");
+}
+
+/*
+ * Dump IGMP statistics.
+ */
+void
+igmp_stats(off, name)
+ off_t off;
+ char *name;
+{
+ struct igmpstat igmpstat;
+ register int i, first;
+
+ if (off == 0)
+ return;
+ kvm_read(off, (char *)&igmpstat, sizeof (igmpstat));
+ printf("%s:\n", name );
+ printf("\t%u message%s received\n",
+ igmpstat.igps_rcv_total, plural(igmpstat.igps_rcv_total));
+ printf("\t%u message%s received with too few bytes\n",
+ igmpstat.igps_rcv_tooshort, plural(igmpstat.igps_rcv_tooshort));
+ printf("\t%u message%s received with bad checksum\n",
+ igmpstat.igps_rcv_badsum, plural(igmpstat.igps_rcv_badsum));
+ printf("\t%u membership quer%s received\n",
+ igmpstat.igps_rcv_queries, pluraly(igmpstat.igps_rcv_queries));
+ printf("\t%u membership quer%s received with invalid field(s)\n",
+ igmpstat.igps_rcv_badqueries, pluraly(igmpstat.igps_rcv_badqueries));
+ printf("\t%u membership report%s received\n",
+ igmpstat.igps_rcv_reports, plural(igmpstat.igps_rcv_reports));
+ printf("\t%u membership report%s received with invalid field(s)\n",
+ igmpstat.igps_rcv_badreports, plural(igmpstat.igps_rcv_badreports));
+ printf("\t%u membership report%s received for groups to which we belong\n",
+ igmpstat.igps_rcv_ourreports, plural(igmpstat.igps_rcv_ourreports));
+ printf("\t%u membership report%s sent\n",
+ igmpstat.igps_snd_reports, plural(igmpstat.igps_snd_reports));
+}
/*
* Pretty print an Internet address (net address + port).
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 6809f4c0475c..09d984c8118b 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -40,7 +40,7 @@ char copyright[] =
#ifndef lint
/* From: static char sccsid[] = "@(#)main.c 5.23 (Berkeley) 7/1/91"; */
const char main_c_rcsid[] =
- "$Id: main.c,v 1.2 1993/11/17 20:19:22 wollman Exp $";
+ "$Id: main.c,v 1.5 1994/05/17 21:50:41 wollman Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -115,12 +115,23 @@ struct nlist nl[] = {
{ "_cltb"},
#define N_CLTPSTAT 28
{ "_cltpstat"},
+#define N_IGMPSTAT 29
+ { "_igmpstat" },
+#define N_MRTPROTO 30
+ { "_ip_mrtproto" },
+#define N_MRTSTAT 31
+ { "_mrtstat" },
+#define N_MRTTABLE 32
+ { "_mrttable" },
+#define N_VIFTABLE 33
+ { "_viftable" },
"",
};
/* internet protocols */
extern int protopr();
extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
+extern int igmp_stats();
#ifdef NS
/* ns protocols */
extern int nsprotopr();
@@ -152,6 +163,8 @@ struct protox {
ip_stats, "ip" },
{ -1, N_ICMPSTAT, 1, 0,
icmp_stats, "icmp" },
+ { -1, N_IGMPSTAT, 1, 0,
+ igmp_stats, "igmp"},
{ -1, -1, 0, 0,
0, 0 }
};
@@ -208,6 +221,7 @@ int mflag;
int nflag;
int pflag;
int rflag;
+int Rflag; /* Multicast routing stats */
int sflag;
int tflag;
int dflag;
@@ -229,7 +243,7 @@ main(argc, argv)
int ch;
void usage();
- while ((ch = getopt(argc, argv, "Aadf:hI:iM:mN:np:rstuw")) != EOF)
+ while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
switch((char)ch) {
case 'A':
Aflag = 1;
@@ -295,6 +309,9 @@ main(argc, argv)
case 'r':
rflag = 1;
break;
+ case 'g':
+ Rflag = 1;
+ break;
case 's':
sflag = 1;
break;
@@ -381,6 +398,16 @@ main(argc, argv)
(off_t)nl[N_RTREE].n_value);
exit(0);
}
+ if (Rflag) {
+ if (sflag)
+ mrt_stats((off_t)nl[N_MRTPROTO].n_value,
+ (off_t)nl[N_MRTSTAT].n_value);
+ else
+ mroutepr((off_t)nl[N_MRTPROTO].n_value,
+ (off_t)nl[N_MRTTABLE].n_value,
+ (off_t)nl[N_VIFTABLE].n_value);
+ exit(0);
+ }
if (af == AF_INET || af == AF_UNSPEC) {
setprotoent(1);
setservent(1);
@@ -500,7 +527,7 @@ usage()
(void)fprintf(stderr,
"usage: netstat [-Aan] [-f address_family] [-M core] [-N system]\n");
(void)fprintf(stderr,
-" [-himnrs] [-f address_family] [-M core] [-N system]\n");
+" [-himnrRs] [-f address_family] [-M core] [-N system]\n");
(void)fprintf(stderr,
" [-n] [-I interface] [-M core] [-N system] [-w wait]\n");
(void)fprintf(stderr,
diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c
new file mode 100644
index 000000000000..33a5d00f9f0f
--- /dev/null
+++ b/usr.bin/netstat/mroute.c
@@ -0,0 +1,211 @@
+/*
+ * Print DVMRP multicast routing structures and statistics.
+ *
+ * MROUTING 1.0
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <netinet/in.h>
+#include <netinet/igmp.h>
+#define KERNEL 1
+#include <sys/socketvar.h>
+#include <netinet/ip_mroute.h>
+#undef KERNEL
+
+extern int kmem;
+extern int nflag;
+extern char *routename();
+extern char *netname();
+extern char *plural();
+
+char *plurales(n)
+ int n;
+{
+ return (n == 1? "" : "es");
+}
+
+mroutepr(mrpaddr, mrtaddr, vifaddr)
+ off_t mrpaddr, mrtaddr, vifaddr;
+{
+ u_int mrtproto;
+#if BSD >= 199006
+ struct mrt *mrttable[MRTHASHSIZ];
+ struct mrt *mp;
+ struct mrt mb;
+ struct mrt *mrt = &mb;
+#else
+ struct mbuf *mrttable[MRTHASHSIZ];
+ struct mbuf *mp;
+ struct mbuf mb;
+ struct mrt *mrt = mtod(&mb, struct mrt *);
+#endif
+ struct vif viftable[MAXVIFS];
+ register struct vif *v;
+ register vifi_t vifi;
+ struct in_addr *grp;
+ int i, n;
+ int banner_printed;
+ int saved_nflag;
+
+ if(mrpaddr == 0) {
+ printf("ip_mrtproto: symbol not in namelist\n");
+ return;
+ }
+
+ kvm_read(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+ case 0:
+ printf("no multicast routing compiled into this system\n");
+ return;
+
+ case IGMP_DVMRP:
+ break;
+
+ default:
+ printf("multicast routing protocol %u, unknown\n", mrtproto);
+ return;
+ }
+
+ if (mrtaddr == 0) {
+ printf("mrttable: symbol not in namelist\n");
+ return;
+ }
+ if (vifaddr == 0) {
+ printf("viftable: symbol not in namelist\n");
+ return;
+ }
+
+ saved_nflag = nflag;
+ nflag = 1;
+
+ kvm_read(vifaddr, (char *)viftable, sizeof(viftable));
+ banner_printed = 0;
+ for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
+ struct in_addr v_lcl_grps[1024];
+
+ if (v->v_lcl_addr.s_addr == 0) continue;
+
+ if (!banner_printed) {
+ printf("\nVirtual Interface Table\n%s%s",
+ " Vif Threshold Local-Address ",
+ "Remote-Address Groups\n");
+ banner_printed = 1;
+ }
+
+ printf(" %2u %3u %-15.15s",
+ vifi, v->v_threshold, routename(v->v_lcl_addr));
+ printf(" %-15.15s\n",
+ (v->v_flags & VIFF_TUNNEL) ?
+ routename(v->v_rmt_addr) : "");
+
+ n = v->v_lcl_grps_n;
+ if (n == 0)
+ continue;
+ if (n < 0 || n > 1024)
+ printf("[v_lcl_grps_n = %d!]\n", n);
+
+ kvm_read(v->v_lcl_grps, (char *)v_lcl_grps,
+ n * sizeof(struct in_addr));
+ for (i = 0; i < n; ++i)
+ printf("%51s %-15.15s\n", "",
+ routename(v_lcl_grps[i]));
+ }
+ if (!banner_printed) printf("\nVirtual Interface Table is empty\n");
+
+ kvm_read(mrtaddr, (char *)mrttable, sizeof(mrttable));
+ banner_printed = 0;
+ for (i = 0; i < MRTHASHSIZ; ++i) {
+ for (mp = mrttable[i]; mp != NULL;
+#if BSD >= 199006
+ mp = mb.mrt_next
+#else
+ mp = mb.m_next
+#endif
+ ) {
+
+ if (!banner_printed) {
+ printf("\nMulticast Routing Table\n%s",
+ " Hash Origin-Subnet In-Vif Out-Vifs\n");
+ banner_printed = 1;
+ }
+ kvm_read(mp, (char *)&mb, sizeof(mb));
+
+
+ printf(" %3u %-15.15s %2u ",
+ i,
+ netname(mrt->mrt_origin.s_addr,
+ ntohl(mrt->mrt_originmask.s_addr)),
+ mrt->mrt_parent);
+ for (vifi = 0; vifi < MAXVIFS; ++vifi) {
+ if (viftable[vifi].v_lcl_addr.s_addr) {
+ if (VIFM_ISSET(vifi, mrt->mrt_children)) {
+ printf(" %u%c",
+ vifi,
+ VIFM_ISSET(vifi,
+ mrt->mrt_leaves) ?
+ '*' : ' ');
+ } else
+ printf(" ");
+ }
+ }
+ printf("\n");
+ }
+ }
+ if (!banner_printed) printf("\nMulticast Routing Table is empty\n");
+
+ printf("\n");
+ nflag = saved_nflag;
+}
+
+
+mrt_stats(mrpaddr, mstaddr)
+ off_t mrpaddr, mstaddr;
+{
+ u_int mrtproto;
+ struct mrtstat mrtstat;
+
+ if(mrpaddr == 0) {
+ printf("ip_mrtproto: symbol not in namelist\n");
+ return;
+ }
+
+ kvm_read(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+ case 0:
+ printf("no multicast routing compiled into this system\n");
+ return;
+
+ case IGMP_DVMRP:
+ break;
+
+ default:
+ printf("multicast routing protocol %u, unknown\n", mrtproto);
+ return;
+ }
+
+ if (mstaddr == 0) {
+ printf("mrtstat: symbol not in namelist\n");
+ return;
+ }
+
+ kvm_read(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
+ printf("multicast routing:\n");
+ printf(" %10u multicast route lookup%s\n",
+ mrtstat.mrts_mrt_lookups, plural(mrtstat.mrts_mrt_lookups));
+ printf(" %10u multicast route cache miss%s\n",
+ mrtstat.mrts_mrt_misses, plurales(mrtstat.mrts_mrt_misses));
+ printf(" %10u group address lookup%s\n",
+ mrtstat.mrts_grp_lookups, plural(mrtstat.mrts_grp_lookups));
+ printf(" %10u group address cache miss%s\n",
+ mrtstat.mrts_grp_misses, plurales(mrtstat.mrts_grp_misses));
+ printf(" %10u datagram%s with no route for origin\n",
+ mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route));
+ printf(" %10u datagram%s with malformed tunnel options\n",
+ mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel));
+ printf(" %10u datagram%s with no room for tunnel options\n",
+ mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel));
+ printf(" %10u datagram%s arrived on wrong interface\n",
+ mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if));
+}
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 25c3943ac35b..62c553a75583 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -44,7 +44,7 @@
.Op Ar system
.Op Ar core
.Nm netstat
-.Op Fl himnrs
+.Op Fl himnrRs
.Op Fl f Ar address_family
.Op Fl M Ar core
.Op Fl N Ar system
@@ -92,6 +92,10 @@ With either interface display (option
.Fl i
or an interval, as described below),
show the number of dropped packets.
+.It Fl g
+Show multicast routing statistics. When
+.Fl s
+is also present, show multicast routing statistics instead.
.It Fl h
Show the state of the
.Tn IMP
diff --git a/usr.bin/nice/nice.1 b/usr.bin/nice/nice.1
index 8795342cdefb..e3fa9e5dc87c 100644
--- a/usr.bin/nice/nice.1
+++ b/usr.bin/nice/nice.1
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)nice.1 6.7 (Berkeley) 7/24/91
-.\" $Id: nice.1,v 1.2.2.1 1994/05/01 16:08:39 jkh Exp $
+.\" $Id: nice.1,v 1.3 1994/04/24 01:23:11 jkh Exp $
.\"
.Dd July 24, 1991
.Dt NICE 1
diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile
index 25f20f2c3f4a..85a23ca64b59 100644
--- a/usr.bin/passwd/Makefile
+++ b/usr.bin/passwd/Makefile
@@ -1,19 +1,27 @@
# @(#)Makefile 5.11 (Berkeley) 2/19/91
PROG= passwd
-SRCS= local_passwd.c passwd.c pw_copy.c pw_util.c yp_passwd.c getpwent.c
+SRCS= local_passwd.c passwd.c pw_copy.c pw_util.c yp_passwd.c getpwent.c \
+ krb_passwd.c pw_fastmkdb.c
CFLAGS+=-I${.CURDIR} -DYP
.PATH: ${.CURDIR}/../../usr.bin/chpass ${.CURDIR}/../../usr.sbin/vipw \
${.CURDIR}/../rlogin ${.CURDIR}/../../lib/libc/gen
-DPADD+= ${LIBRPCSVC} #${LIBKRB}
-LDADD+= -lrpcsvc #-lkrb
+DPADD+= ${LIBRPCSVC}
+LDADD+= -lrpcsvc
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DKERBEROS
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+CFLAGS+= -DKERBEROS
+DPADD+= ${LIBKRB}
+LDADD+= -lkrb -ldes
+.endif
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
getpwent.o: getpwent.c
${CC} ${CFLAGS} -UYP -c ${.IMPSRC}
diff --git a/usr.bin/passwd/kpasswd_proto.h b/usr.bin/passwd/kpasswd_proto.h
new file mode 100644
index 000000000000..9c76fd40ce4e
--- /dev/null
+++ b/usr.bin/passwd/kpasswd_proto.h
@@ -0,0 +1,54 @@
+/*-
+ * 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.
+ *
+ * @(#)kpasswd_proto.h 5.1 (Berkeley) 2/3/91
+ */
+
+/*
+ * kpasswd_proto
+ *
+ * definitions for the kpasswd "protocol"
+ * (We hope this to be temporary until a real admin protocol is worked out.)
+ */
+
+struct kpasswd_data {
+ des_cblock random_key;
+ char secure_msg[_PASSWORD_LEN];
+};
+
+struct update_data {
+ char pw[_PASSWORD_LEN];
+ char secure_msg[_PASSWORD_LEN];
+};
+#define SERVICE "kpasswd"
+#define SECURE_STRING \
+ "Kerberos password update program -- 12/9/88 UC Berkeley"
diff --git a/usr.bin/passwd/krb_passwd.c b/usr.bin/passwd/krb_passwd.c
new file mode 100644
index 000000000000..56de10b99fd9
--- /dev/null
+++ b/usr.bin/passwd/krb_passwd.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (c) 1990 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)krb_passwd.c 5.4 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+#ifdef KERBEROS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#include <netdb.h>
+#include <signal.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include "kpasswd_proto.h"
+#include <string.h>
+#include <stdlib.h>
+
+#define PROTO "tcp"
+
+static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 };
+static struct kpasswd_data proto_data;
+static des_cblock okey;
+static Key_schedule osched;
+KTEXT_ST ticket;
+Key_schedule random_schedule;
+long authopts;
+char realm[REALM_SZ], krbhst[MAX_HSTNM];
+int sock;
+
+krb_passwd()
+{
+ struct servent *se;
+ struct hostent *host;
+ struct sockaddr_in sin;
+ CREDENTIALS cred;
+ fd_set readfds;
+ int rval;
+ char pass[_PASSWORD_LEN], password[_PASSWORD_LEN];
+ static void finish();
+
+ static struct rlimit rl = { 0, 0 };
+
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGTSTP, SIG_IGN);
+
+ if (setrlimit(RLIMIT_CORE, &rl) < 0) {
+ (void)fprintf(stderr,
+ "passwd: setrlimit: %s\n", strerror(errno));
+ return(1);
+ }
+
+ if ((se = getservbyname(SERVICE, PROTO)) == NULL) {
+ (void)fprintf(stderr,
+ "passwd: couldn't find entry for service %s/%s\n",
+ SERVICE, PROTO);
+ return(1);
+ }
+
+ if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) {
+ (void)fprintf(stderr,
+ "passwd: couldn't get local Kerberos realm: %s\n",
+ krb_err_txt[rval]);
+ return(1);
+ }
+
+ if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) {
+ (void)fprintf(stderr,
+ "passwd: couldn't get Kerberos host: %s\n",
+ krb_err_txt[rval]);
+ return(1);
+ }
+
+ if ((host = gethostbyname(krbhst)) == NULL) {
+ (void)fprintf(stderr,
+ "passwd: couldn't get host entry for krb host %s\n",
+ krbhst);
+ return(1);
+ }
+
+ sin.sin_family = host->h_addrtype;
+ bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length);
+ sin.sin_port = se->s_port;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ (void)fprintf(stderr, "passwd: socket: %s\n", strerror(errno));
+ return(1);
+ }
+
+ if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ (void)fprintf(stderr, "passwd: connect: %s\n", strerror(errno));
+ (void)close(sock);
+ return(1);
+ }
+
+ rval = krb_sendauth(
+ authopts, /* NOT mutual */
+ sock,
+ &ticket, /* (filled in) */
+ SERVICE,
+ krbhst, /* instance (krbhst) */
+ realm, /* dest realm */
+ (u_long) getpid(), /* checksum */
+ NULL, /* msg data */
+ NULL, /* credentials */
+ NULL, /* schedule */
+ NULL, /* local addr */
+ NULL, /* foreign addr */
+ "KPWDV0.1"
+ );
+
+ if (rval != KSUCCESS) {
+ (void)fprintf(stderr, "passwd: Kerberos sendauth error: %s\n",
+ krb_err_txt[rval]);
+ return(1);
+ }
+
+ krb_get_cred("krbtgt", realm, realm, &cred);
+
+ (void)printf("Changing Kerberos password for %s.%s@%s.\n",
+ cred.pname, cred.pinst, realm);
+
+ if (des_read_pw_string(pass,
+ sizeof(pass)-1, "Old Kerberos password:", 0)) {
+ (void)fprintf(stderr,
+ "passwd: error reading old Kerberos password\n");
+ return(1);
+ }
+
+ (void)des_string_to_key(pass, okey);
+ (void)des_key_sched(okey, osched);
+ (void)des_set_key(okey, osched);
+
+ /* wait on the verification string */
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+
+ rval =
+ select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
+
+ if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
+ if(rval == 0) {
+ (void)fprintf(stderr, "passwd: timed out (aborted)\n");
+ cleanup();
+ return(1);
+ }
+ (void)fprintf(stderr, "passwd: select failed (aborted)\n");
+ cleanup();
+ return(1);
+ }
+
+ /* read verification string */
+
+ if (des_read(sock, &proto_data, sizeof(proto_data)) !=
+ sizeof(proto_data)) {
+ (void)fprintf(stderr,
+ "passwd: couldn't read verification string (aborted)\n");
+ cleanup();
+ return(1);
+ }
+
+ (void)signal(SIGHUP, finish);
+ (void)signal(SIGINT, finish);
+
+ if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) {
+ cleanup();
+ /* don't complain loud if user just hit return */
+ if (pass == NULL || (!*pass))
+ return(0);
+ (void)fprintf(stderr, "Sorry\n");
+ return(1);
+ }
+
+ (void)des_key_sched(proto_data.random_key, random_schedule);
+ (void)des_set_key(proto_data.random_key, random_schedule);
+ (void)bzero(pass, sizeof(pass));
+
+ if (des_read_pw_string(pass,
+ sizeof(pass)-1, "New Kerberos password:", 0)) {
+ (void)fprintf(stderr,
+ "passwd: error reading new Kerberos password (aborted)\n");
+ cleanup();
+ return(1);
+ }
+
+ if (des_read_pw_string(password,
+ sizeof(password)-1, "Retype new Kerberos password:", 0)) {
+ (void)fprintf(stderr,
+ "passwd: error reading new Kerberos password (aborted)\n");
+ cleanup();
+ return(1);
+ }
+
+ if (strcmp(password, pass) != 0) {
+ (void)fprintf(stderr,
+ "passwd: password mismatch (aborted)\n");
+ cleanup();
+ return(1);
+ }
+
+ if (strlen(pass) == 0)
+ (void)printf("using NULL password\n");
+
+ send_update(sock, password, SECURE_STRING);
+
+ /* wait for ACK */
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+
+ rval =
+ select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
+ if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
+ if(rval == 0) {
+ (void)fprintf(stderr,
+ "passwd: timed out reading ACK (aborted)\n");
+ cleanup();
+ exit(1);
+ }
+ (void)fprintf(stderr, "passwd: select failed (aborted)\n");
+ cleanup();
+ exit(1);
+ }
+ recv_ack(sock);
+ cleanup();
+ exit(0);
+}
+
+send_update(dest, pwd, str)
+ int dest;
+ char *pwd, *str;
+{
+ static struct update_data ud;
+
+ (void)strncpy(ud.secure_msg, str, _PASSWORD_LEN);
+ (void)strncpy(ud.pw, pwd, sizeof(ud.pw));
+ if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) {
+ (void)fprintf(stderr,
+ "passwd: couldn't write pw update (abort)\n");
+ bzero((char *)&ud, sizeof(ud));
+ cleanup();
+ exit(1);
+ }
+}
+
+recv_ack(remote)
+ int remote;
+{
+ int cc;
+ char buf[BUFSIZ];
+
+ cc = des_read(remote, buf, sizeof(buf));
+ if (cc <= 0) {
+ (void)fprintf(stderr,
+ "passwd: error reading acknowledgement (aborted)\n");
+ cleanup();
+ exit(1);
+ }
+ (void)printf("%s", buf);
+}
+
+cleanup()
+{
+ (void)bzero((char *)&proto_data, sizeof(proto_data));
+ (void)bzero((char *)okey, sizeof(okey));
+ (void)bzero((char *)osched, sizeof(osched));
+ (void)bzero((char *)random_schedule, sizeof(random_schedule));
+}
+
+static void
+finish()
+{
+ (void)close(sock);
+ exit(1);
+}
+
+#endif /* KERBEROS */
diff --git a/usr.bin/passwd/local_passwd.c b/usr.bin/passwd/local_passwd.c
index 0a81ab1dce18..7eec89289c0f 100644
--- a/usr.bin/passwd/local_passwd.c
+++ b/usr.bin/passwd/local_passwd.c
@@ -33,7 +33,7 @@
#ifndef lint
/*static char sccsid[] = "from: @(#)local_passwd.c 5.5 (Berkeley) 5/6/91";*/
-static char rcsid[] = "$Id: local_passwd.c,v 1.4 1994/01/11 19:01:13 nate Exp $";
+static char rcsid[] = "$Id: local_passwd.c,v 1.7 1994/05/20 00:29:19 ache Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -81,8 +81,17 @@ local_passwd(uname)
pw->pw_change = 0;
pw_copy(pfd, tfd, pw);
- if (!pw_mkdb())
- pw_error((char *)NULL, 0, 1);
+ /*
+ * Attempt a recovery if the incremental database update failed by
+ * handing off to the real password hashing program to remake the
+ * whole mess. Even though this costs lots of time it's better than
+ * having the password databases out of sync with the master pw file.
+ */
+ if (pw_fastmkdb(pw) < 0) {
+ fprintf(stderr,"%s: WARNING!! Password database mangled, recreating it from scratch\n", progname);
+ if(!pw_mkdb())
+ pw_error((char *)NULL, 0, 1);
+ }
return(0);
}
diff --git a/usr.bin/passwd/passwd.c b/usr.bin/passwd/passwd.c
index 4ffaeb050e22..f1cbbdfda48a 100644
--- a/usr.bin/passwd/passwd.c
+++ b/usr.bin/passwd/passwd.c
@@ -39,7 +39,7 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)passwd.c 5.5 (Berkeley) 7/6/91";*/
-static char rcsid[] = "$Id: passwd.c,v 1.2 1994/01/11 19:01:15 nate Exp $";
+static char rcsid[] = "$Id: passwd.c,v 1.3 1994/05/14 19:40:58 ache Exp $";
#endif /* not lint */
#include <stdio.h>
@@ -128,7 +128,7 @@ main(argc, argv)
break;
case 1:
#ifdef KERBEROS
- if (use_kerberos && strcmp(argv[1], uname)) {
+ if (use_kerberos && strcmp(argv[0], uname)) {
(void)fprintf(stderr, "passwd: %s\n\t%s\n%s\n",
"to change another user's Kerberos password, do",
"\"kinit user; passwd; kdestroy\";",
diff --git a/usr.bin/passwd/pw_fastmkdb.c b/usr.bin/passwd/pw_fastmkdb.c
new file mode 100644
index 000000000000..eaa986a08c4e
--- /dev/null
+++ b/usr.bin/passwd/pw_fastmkdb.c
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 1991 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.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <db.h>
+#include <pwd.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+/* #define PW_COMPACT */
+/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
+#ifdef PW_COMPACT
+# define HI_BSIZE 1024
+# define HI_NELEM 4500
+# define HI_CACHE (1024 * 1024)
+#else
+# define HI_BSIZE 2048
+# define HI_NELEM 4500
+# define HI_CACHE (4000 * 1024)
+#endif
+
+#define INSECURE 1
+#define SECURE 2
+#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
+static struct passwd pwd; /* password structure */
+
+extern char *tempname;
+extern char *progname;
+extern int globcnt;
+
+pw_fastmkdb(new_pwd)
+ struct passwd *new_pwd;
+{
+ register int len;
+ register char *p, *t;
+ DB *dp, *edp;
+ sigset_t set;
+ DBT data, key;
+#ifdef PW_COMPACT
+ DBT pdata, sdata;
+#endif
+ char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
+ char buf2[MAX(MAXPATHLEN, LINE_MAX * 2)];
+ int uid;
+ int gid;
+ HASHINFO openinfo;
+
+ /* Hash database parameters */
+ openinfo.bsize=HI_BSIZE;
+ openinfo.ffactor=32;
+ openinfo.nelem=HI_NELEM; /* Default value was 300 */
+ openinfo.cachesize=HI_CACHE; /* Default value was 512 */
+ openinfo.hash=NULL;
+ openinfo.lorder=0;
+
+ /*
+ * This could be done to allow the user to interrupt. Probably
+ * not worth the effort.
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTSTP);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
+
+ /* Open the insecure password database. */
+ dp = dbopen(_PATH_MP_DB, O_RDWR, PERM_INSECURE, DB_HASH, &openinfo);
+ if (!dp)
+ error(_PATH_MP_DB);
+ /*
+ * The databases actually contain three copies of the original data.
+ * Each password file entry is converted into a rough approximation
+ * of a ``struct passwd'', with the strings placed inline. This
+ * object is then stored as the data for three separate keys. The
+ * first key * is the pw_name field prepended by the _PW_KEYBYNAME
+ * character. The second key is the pw_uid field prepended by the
+ * _PW_KEYBYUID character. The third key is the line number in the
+ * original file prepended by the _PW_KEYBYNUM character. (The special
+ * characters are prepended to ensure that the keys do not collide.)
+ */
+ bcopy((char *)new_pwd, (char *)&pwd, sizeof(struct passwd));
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+#ifdef PW_COMPACT
+ pdata.data = (u_char *)&globcnt;
+ pdata.size = sizeof(int);
+ sdata.data = (u_char *)pwd.pw_passwd;
+ sdata.size = strlen(pwd.pw_passwd) + 1;
+#endif
+#define COMPACT(e) t = e; while (*p++ = *t++);
+
+ /* Create insecure data. */
+ uid = pwd.pw_uid; /* force a particular size */
+ gid = pwd.pw_gid;
+ p = buf;
+ COMPACT(pwd.pw_name);
+#ifndef PW_COMPACT
+ COMPACT("*");
+#endif
+ bcopy((char *)&uid, p, sizeof(uid));
+ p += sizeof(int);
+ bcopy((char *)&gid, p, sizeof(gid));
+ p += sizeof(int);
+ bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
+ p += sizeof(time_t);
+ data.size = p - buf;
+
+ /* Store insecure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ bcopy(pwd.pw_name, tbuf + 1, len);
+ key.size = len + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, 0) == -1)
+#else
+ if ((dp->put)(dp, &key, &data, 0) == -1)
+#endif
+ error("put");
+
+ /* Store insecure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ bcopy((char *)&uid, tbuf + 1, sizeof(uid));
+ key.size = sizeof(uid) + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, 0) == -1)
+#else
+ if ((dp->put)(dp, &key, &data, 0) == -1)
+#endif
+ error("put");
+
+ /* Store insecure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ bcopy((char *)&globcnt, tbuf + 1, sizeof(globcnt));
+ key.size = sizeof(globcnt) + 1;
+ if ((dp->put)(dp, &key, &data, 0) == -1)
+ error("put");
+
+ (void)(dp->close)(dp);
+
+ /* Open the encrypted password database. */
+ edp = dbopen(_PATH_SMP_DB, O_RDWR, PERM_SECURE, DB_HASH, &openinfo);
+ if (!edp)
+ error(_PATH_SMP_DB);
+#ifdef PW_COMPACT
+ /* Store secure. */
+ if ((edp->put)(edp, &key, &sdata, 0) == -1)
+ error("put");
+#else
+
+ /* Create secure data. */
+ p = buf;
+ COMPACT(pwd.pw_name);
+ COMPACT(pwd.pw_passwd);
+ bcopy((char *)&uid, p, sizeof(uid));
+ p += sizeof(int);
+ bcopy((char *)&gid, p, sizeof(gid));
+ p += sizeof(int);
+ bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
+ p += sizeof(time_t);
+ data.size = p - buf;
+
+ /* Store secure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ bcopy(pwd.pw_name, tbuf + 1, len);
+ key.size = len + 1;
+ if ((edp->put)(edp, &key, &data, 0) == -1)
+ error("put");
+
+ /* Store secure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ bcopy((char *)&globcnt, tbuf + 1, sizeof(globcnt));
+ key.size = sizeof(globcnt) + 1;
+ if ((edp->put)(edp, &key, &data, 0) == -1)
+ error("put");
+
+ /* Store secure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ bcopy((char *)&uid, tbuf + 1, sizeof(uid));
+ key.size = sizeof(uid) + 1;
+ if ((edp->put)(edp, &key, &data, 0) == -1)
+ error("put");
+#endif
+
+ (void)(edp->close)(edp);
+
+ /*
+ * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
+ * all use flock(2) on it to block other incarnations of themselves.
+ * The rename means that everything is unlocked, as the original file
+ * can no longer be accessed.
+ */
+ mv(tempname, _PATH_MASTERPASSWD);
+ return(0);
+}
+
+mv(from, to)
+ char *from, *to;
+{
+ int sverrno;
+ char buf[MAXPATHLEN];
+
+ if (rename(from, to)) {
+ sverrno = errno;
+ (void)sprintf(buf, "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+error(name)
+ char *name;
+{
+ (void)fprintf(stderr, "%s: %s: %s\n", progname, name, strerror(errno));
+ return(-1);
+}
diff --git a/usr.bin/passwd/yp_passwd.c b/usr.bin/passwd/yp_passwd.c
index 01cac298223a..db6cd29a5439 100644
--- a/usr.bin/passwd/yp_passwd.c
+++ b/usr.bin/passwd/yp_passwd.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
/*static char sccsid[] = "from: @(#)yp_passwd.c 1.0 2/2/93";*/
-static char rcsid[] = "$Id: yp_passwd.c,v 1.1 1994/01/11 19:01:16 nate Exp $";
+static char rcsid[] = "$Id: yp_passwd.c,v 1.2 1994/05/18 00:40:02 jkh Exp $";
#endif /* not lint */
#ifdef YP
@@ -162,9 +162,8 @@ getnewpasswd(pw, old_pass)
(void)printf("Changing YP password for %s.\n", pw->pw_name);
- if (uid && old_pass) {
- *old_pass = NULL;
-
+ *old_pass = "*";
+ if (uid) {
if (pw->pw_passwd &&
#ifdef DES
strcmp(crypt(p = getpass("Old password:"), pw->pw_passwd),
diff --git a/usr.bin/ranlib/build.c b/usr.bin/ranlib/build.c
index 6d57268ae438..737cc66a28d7 100644
--- a/usr.bin/ranlib/build.c
+++ b/usr.bin/ranlib/build.c
@@ -63,6 +63,9 @@ typedef struct _rlib {
RLIB *rhead, **pnext;
FILE *fp;
+long symcnt; /* symbol count */
+long tsymlen; /* total string length */
+
static void rexec(), symobj();
build()
@@ -74,6 +77,8 @@ build()
afd = open_archive(O_RDWR);
fp = fdopen(afd, "r+");
tfd = tmp();
+ symcnt = 0;
+ tsymlen = 0;
SETCF(afd, archive, tfd, tname, RPAD|WPAD);
@@ -106,9 +111,6 @@ build()
return(0);
}
-long symcnt; /* symbol count */
-long tsymlen; /* total string length */
-
/*
* rexec
* Read the exec structure; ignore any files that don't look
diff --git a/usr.bin/rdist/defs.h b/usr.bin/rdist/defs.h
index d39da0f6bfe2..f1b42c2b8dc8 100644
--- a/usr.bin/rdist/defs.h
+++ b/usr.bin/rdist/defs.h
@@ -44,6 +44,7 @@
#include <errno.h>
#include <pwd.h>
#include <grp.h>
+#include <stdlib.h>
#include "pathnames.h"
/*
@@ -153,6 +154,5 @@ struct subcmd *makesubcmd();
struct namelist *lookup();
struct namelist *expand();
char *exptilde();
-char *malloc();
char *rindex();
char *index();
diff --git a/usr.bin/rev/rev.c b/usr.bin/rev/rev.c
index bdbf3f4bcab2..66be64aacb1a 100644
--- a/usr.bin/rev/rev.c
+++ b/usr.bin/rev/rev.c
@@ -38,7 +38,8 @@ char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rev.c 5.2 (Berkeley) 3/21/92";
+/*static char sccsid[] = "from: @(#)rev.c 5.2 (Berkeley) 3/21/92";*/
+static char rcsid[] = "$Id: rev.c,v 1.2 1994/04/17 09:36:50 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -83,7 +84,9 @@ main(argc, argv)
}
filename = *argv++;
}
- while (p = fgetline(fp, &len)) {
+ while (p = fgetln(fp, &len)) {
+ if (p[len-1] == '\n')
+ --len;
t = p + len - 1;
for (t = p + len - 1; t >= p; --t)
putchar(*t);
diff --git a/usr.bin/rlogin/Makefile b/usr.bin/rlogin/Makefile
index c4da477ed0d8..465ef8abca55 100644
--- a/usr.bin/rlogin/Makefile
+++ b/usr.bin/rlogin/Makefile
@@ -1,14 +1,19 @@
-# @(#)Makefile 5.6 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.6 1994/05/03 19:20:35 wollman Exp $
+# From: @(#)Makefile 5.6 (Berkeley) 9/27/90
PROG= rlogin
-SRCS= rlogin.c
+SRCS= rlogin.c krcmd.c kcmd.c
BINOWN= root
BINMODE=4555
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS -DCRYPT
.endif
.include <bsd.prog.mk>
diff --git a/usr.bin/rlogin/kcmd.c b/usr.bin/rlogin/kcmd.c
new file mode 100644
index 000000000000..b7c155953233
--- /dev/null
+++ b/usr.bin/rlogin/kcmd.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1983 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.
+ */
+
+#ifndef lint
+static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88";
+static char sccsid[] = "From: @(#)kcmd.c 5.6 (Berkeley) 6/1/90";
+static const char rcsid[] =
+ "$Id: kcmd.c,v 1.1 1994/05/03 19:20:37 wollman Exp $";
+#endif /* not lint */
+
+/*
+ * $Source: /home/cvs/386BSD/src/usr.bin/rlogin/kcmd.c,v $
+ * $Header: /home/cvs/386BSD/src/usr.bin/rlogin/kcmd.c,v 1.1 1994/05/03 19:20:37 wollman Exp $
+ *
+ * static char *rcsid_kcmd_c =
+ * "Header: kcmd.c,v 4.16 89/05/17 10:54:31 jtkohl Exp";
+ */
+
+#ifdef KERBEROS
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#include <kerberosIV/kparse.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+extern errno;
+char *index(), *malloc(), *krb_realmofhost();
+
+#define START_PORT 5120 /* arbitrary */
+
+kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
+ cred, schedule, msg_data, laddr, faddr, authopts)
+int *sock;
+char **ahost;
+u_short rport;
+char *locuser, *remuser, *cmd;
+int *fd2p;
+KTEXT ticket;
+char *service;
+char *realm;
+CREDENTIALS *cred;
+Key_schedule schedule;
+MSG_DAT *msg_data;
+struct sockaddr_in *laddr, *faddr;
+long authopts;
+{
+ int s, timo = 1, pid;
+ long oldmask;
+ struct sockaddr_in sin, from;
+ char c;
+#ifdef ATHENA_COMPAT
+ int lport = IPPORT_RESERVED - 1;
+#else
+ int lport = START_PORT;
+#endif ATHENA_COMPAT
+ struct hostent *hp;
+ int rc;
+ char *host_save;
+ int status;
+
+ pid = getpid();
+ hp = gethostbyname(*ahost);
+ if (hp == 0) {
+ /* fprintf(stderr, "%s: unknown host\n", *ahost); */
+ return (-1);
+ }
+
+ host_save = malloc(strlen(hp->h_name) + 1);
+ strcpy(host_save, hp->h_name);
+ *ahost = host_save;
+
+ /* If realm is null, look up from table */
+ if ((realm == NULL) || (realm[0] == '\0')) {
+ realm = krb_realmofhost(host_save);
+ }
+
+ oldmask = sigblock(sigmask(SIGURG));
+ for (;;) {
+ s = getport(&lport);
+ if (s < 0) {
+ if (errno == EAGAIN)
+ fprintf(stderr,
+ "kcmd(socket): All ports in use\n");
+ else
+ perror("kcmd: socket");
+ sigsetmask(oldmask);
+ return (-1);
+ }
+ fcntl(s, F_SETOWN, pid);
+ sin.sin_family = hp->h_addrtype;
+#if defined(ultrix) || defined(sun)
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+#else
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
+#endif /* defined(ultrix) || defined(sun) */
+ sin.sin_port = rport;
+ if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+ break;
+ (void) close(s);
+ if (errno == EADDRINUSE) {
+ lport--;
+ continue;
+ }
+ /*
+ * don't wait very long for Kerberos rcmd.
+ */
+ if (errno == ECONNREFUSED && timo <= 4) {
+ /* sleep(timo); don't wait at all here */
+ timo *= 2;
+ continue;
+ }
+#if !(defined(ultrix) || defined(sun))
+ if (hp->h_addr_list[1] != NULL) {
+ int oerrno = errno;
+
+ fprintf(stderr,
+ "kcmd: connect to address %s: ",
+ inet_ntoa(sin.sin_addr));
+ errno = oerrno;
+ perror(0);
+ hp->h_addr_list++;
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
+ hp->h_length);
+ fprintf(stderr, "Trying %s...\n",
+ inet_ntoa(sin.sin_addr));
+ continue;
+ }
+#endif /* !(defined(ultrix) || defined(sun)) */
+ if (errno != ECONNREFUSED)
+ perror(hp->h_name);
+ sigsetmask(oldmask);
+ return (-1);
+ }
+ lport--;
+ if (fd2p == 0) {
+ write(s, "", 1);
+ lport = 0;
+ } else {
+ char num[8];
+ int s2 = getport(&lport), s3;
+ int len = sizeof (from);
+
+ if (s2 < 0) {
+ status = -1;
+ goto bad;
+ }
+ listen(s2, 1);
+ (void) sprintf(num, "%d", lport);
+ if (write(s, num, strlen(num)+1) != strlen(num)+1) {
+ perror("kcmd(write): setting up stderr");
+ (void) close(s2);
+ status = -1;
+ goto bad;
+ }
+ s3 = accept(s2, (struct sockaddr *)&from, &len);
+ (void) close(s2);
+ if (s3 < 0) {
+ perror("kcmd:accept");
+ lport = 0;
+ status = -1;
+ goto bad;
+ }
+ *fd2p = s3;
+ from.sin_port = ntohs((u_short)from.sin_port);
+ if (from.sin_family != AF_INET ||
+ from.sin_port >= IPPORT_RESERVED) {
+ fprintf(stderr,
+ "kcmd(socket): protocol failure in circuit setup.\n");
+ goto bad2;
+ }
+ }
+ /*
+ * Kerberos-authenticated service. Don't have to send locuser,
+ * since its already in the ticket, and we'll extract it on
+ * the other side.
+ */
+ /* (void) write(s, locuser, strlen(locuser)+1); */
+
+ /* set up the needed stuff for mutual auth, but only if necessary */
+ if (authopts & KOPT_DO_MUTUAL) {
+ int sin_len;
+ *faddr = sin;
+
+ sin_len = sizeof (struct sockaddr_in);
+ if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
+ perror("kcmd(getsockname)");
+ status = -1;
+ goto bad2;
+ }
+ }
+ if ((status = krb_sendauth(authopts, s, ticket, service, *ahost,
+ realm, (unsigned long) getpid(), msg_data,
+ cred, schedule,
+ laddr,
+ faddr,
+ "KCMDV0.1")) != KSUCCESS)
+ goto bad2;
+
+ (void) write(s, remuser, strlen(remuser)+1);
+ (void) write(s, cmd, strlen(cmd)+1);
+
+ if ((rc=read(s, &c, 1)) != 1) {
+ if (rc==-1) {
+ perror(*ahost);
+ } else {
+ fprintf(stderr,"kcmd: bad connection with remote host\n");
+ }
+ status = -1;
+ goto bad2;
+ }
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ status = -1;
+ goto bad2;
+ }
+ sigsetmask(oldmask);
+ *sock = s;
+ return (KSUCCESS);
+bad2:
+ if (lport)
+ (void) close(*fd2p);
+bad:
+ (void) close(s);
+ sigsetmask(oldmask);
+ return (status);
+}
+
+getport(alport)
+ int *alport;
+{
+ struct sockaddr_in sin;
+ int s;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+ for (;;) {
+ sin.sin_port = htons((u_short)*alport);
+ if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void) close(s);
+ return (-1);
+ }
+ (*alport)--;
+#ifdef ATHENA_COMPAT
+ if (*alport == IPPORT_RESERVED/2) {
+#else
+ if (*alport == IPPORT_RESERVED) {
+#endif ATHENA_COMPAT
+ (void) close(s);
+ errno = EAGAIN; /* close */
+ return (-1);
+ }
+ }
+}
+
+#endif /* KERBEROS */
diff --git a/usr.bin/rlogin/krcmd.c b/usr.bin/rlogin/krcmd.c
new file mode 100644
index 000000000000..b219d66125f6
--- /dev/null
+++ b/usr.bin/rlogin/krcmd.c
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)krcmd.c 1.6 (Berkeley) 9/27/90";
+#endif /* not lint */
+
+/*
+ * $Source: /home/cvs/386BSD/src/usr.bin/rlogin/krcmd.c,v $
+ * $Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1
+ * 89/07/25 15:38:44 kfall Exp Locker: kfall $
+ * static char *rcsid_kcmd_c =
+ * "$Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1 89/07/25 15:38:44
+ * kfall Exp Locker: kfall $";
+ */
+
+#ifdef KERBEROS
+#include <sys/types.h>
+#include <stdio.h>
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#define SERVICE_NAME "rcmd"
+
+/*
+ * krcmd: simplified version of Athena's "kcmd"
+ * returns a socket attached to the destination, -1 or krb error on error
+ * if fd2p is non-NULL, another socket is filled in for it
+ */
+
+int
+krcmd(ahost, rport, remuser, cmd, fd2p, realm)
+ char **ahost;
+ u_short rport;
+ char *remuser, *cmd;
+ int *fd2p;
+ char *realm;
+{
+ int sock = -1, err = 0;
+ KTEXT_ST ticket;
+ long authopts = 0L;
+
+ err = kcmd(
+ &sock,
+ ahost,
+ rport,
+ NULL, /* locuser not used */
+ remuser,
+ cmd,
+ fd2p,
+ &ticket,
+ SERVICE_NAME,
+ realm,
+ (CREDENTIALS *) NULL, /* credentials not used */
+ (bit_64 *) NULL, /* key schedule not used */
+ (MSG_DAT *) NULL, /* MSG_DAT not used */
+ (struct sockaddr_in *) NULL, /* local addr not used */
+ (struct sockaddr_in *) NULL, /* foreign addr not used */
+ authopts
+ );
+
+ if (err > KSUCCESS && err < MAX_KRB_ERRORS) {
+ fprintf(stderr, "krcmd: %s\n", krb_err_txt[err]);
+ return(-1);
+ }
+ if (err < 0)
+ return(-1);
+ return(sock);
+}
+
+#ifdef CRYPT
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+krcmd_mutual(ahost, rport, remuser, cmd, fd2p, realm, cred, sched)
+ char **ahost;
+ u_short rport;
+ char *remuser, *cmd;
+ int *fd2p;
+ char *realm;
+ CREDENTIALS *cred;
+ Key_schedule sched;
+{
+ int sock, err;
+ KTEXT_ST ticket;
+ MSG_DAT msg_dat;
+ struct sockaddr_in laddr, faddr;
+ long authopts = KOPT_DO_MUTUAL;
+
+ err = kcmd(
+ &sock,
+ ahost,
+ rport,
+ NULL, /* locuser not used */
+ remuser,
+ cmd,
+ fd2p,
+ &ticket,
+ SERVICE_NAME,
+ realm,
+ cred, /* filled in */
+ sched, /* filled in */
+ &msg_dat, /* filled in */
+ &laddr, /* filled in */
+ &faddr, /* filled in */
+ authopts
+ );
+
+ if (err > KSUCCESS && err < MAX_KRB_ERRORS) {
+ fprintf(stderr, "krcmd_mutual: %s\n", krb_err_txt[err]);
+ return(-1);
+ }
+
+ if (err < 0)
+ return (-1);
+ return(sock);
+}
+#endif /* CRYPT */
+#endif /* KERBEROS */
diff --git a/usr.bin/rsh/Makefile b/usr.bin/rsh/Makefile
index 434e8d1aa6e1..c7ad98e444a4 100644
--- a/usr.bin/rsh/Makefile
+++ b/usr.bin/rsh/Makefile
@@ -1,15 +1,21 @@
-# @(#)Makefile 5.6 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.6 1994/05/03 20:56:17 wollman Exp $
+# From: @(#)Makefile 5.6 (Berkeley) 9/27/90
PROG= rsh
-SRCS= rsh.c
+SRCS= rsh.c krcmd.c kcmd.c
BINOWN= root
BINMODE=4555
.PATH: ${.CURDIR}/../rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS -DCRYPT
.endif
.include <bsd.prog.mk>
diff --git a/usr.bin/rup/rup.c b/usr.bin/rup/rup.c
index 8ac9c1af12ff..0ae1be14ddde 100644
--- a/usr.bin/rup/rup.c
+++ b/usr.bin/rup/rup.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: rup.c,v 1.2 1993/09/23 18:45:57 jtc Exp $";
+static char rcsid[] = "$Id: rup.c,v 1.3 1994/04/10 10:42:28 csgr Exp $";
#endif /* not lint */
#include <stdio.h>
@@ -106,6 +106,10 @@ rstat_reply(char *replyp, struct sockaddr_in *raddrp)
else
host = inet_ntoa(raddrp->sin_addr);
+ /* truncate hostname to fit nicely into field */
+ if (strlen(host) > HOST_WIDTH)
+ host[HOST_WIDTH] = '\0';
+
printf("%-*s\t", HOST_WIDTH, host);
tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec);
diff --git a/usr.bin/sed/Makefile b/usr.bin/sed/Makefile
index 52f0fb5f3e5d..9a6871df40b5 100644
--- a/usr.bin/sed/Makefile
+++ b/usr.bin/sed/Makefile
@@ -1,7 +1,7 @@
-# @(#)Makefile 5.1 (Berkeley) 8/24/92
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= sed
-SRCS= compile.c main.c misc.c process.c
-CFLAGS+=-I${.CURDIR} -DHISTORIC_PRACTICE
+SRCS= compile.c main.c misc.c process.c
+CFLAGS+=-I${.CURDIR}
.include <bsd.prog.mk>
diff --git a/usr.bin/sed/POSIX b/usr.bin/sed/POSIX
index 467b31db3e96..fcd557f72800 100644
--- a/usr.bin/sed/POSIX
+++ b/usr.bin/sed/POSIX
@@ -97,10 +97,7 @@ All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2.
did not produce any output. POSIX does not specify this behavior.
This implementation follows historic practice.
-10. POSIX does not specify that the q command causes all lines that
- have been appended to be output and that the pattern space is
- printed before exiting. This implementation follows historic
- practice.
+10. Deleted.
11. Historical implementations do not output the change text of a c
command in the case of an address range whose first line number
@@ -175,11 +172,7 @@ All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2.
string1 or string2 of the y command. This is not specified by
POSIX. This implementation follows historic practice.
-21. POSIX does not specify if the "Nth occurrence" of an RE in a
- substitute command is an overlapping or a non-overlapping one,
- i.e. what is the result of s/a*/A/2 on the pattern "aaaaa aaaaa".
- Historical practice is to drop core or only do non-overlapping
- RE's. This implementation only does non-overlapping RE's.
+21. Deleted.
22. Historic implementations of sed ignore the RE delimiter characters
within character classes. This is not specified in POSIX. This
diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c
index 526f21c89f7e..72cb93fcd3f4 100644
--- a/usr.bin/sed/compile.c
+++ b/usr.bin/sed/compile.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92";
+/* from: static char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93"; */
+static char *rcsid = "$Id: compile.c,v 1.5 1994/04/17 09:41:36 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -54,6 +55,15 @@ static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92";
#include "defs.h"
#include "extern.h"
+#define LHSZ 128
+#define LHMASK (LHSZ - 1)
+static struct labhash {
+ struct labhash *lh_next;
+ u_int lh_hash;
+ struct s_command *lh_cmd;
+ int lh_ref;
+} *labels[LHSZ];
+
static char *compile_addr __P((char *, struct s_addr *));
static char *compile_ccl __P((char **, char *));
static char *compile_delimited __P((char *, char *));
@@ -64,11 +74,12 @@ static char *compile_text __P((void));
static char *compile_tr __P((char *, char **));
static struct s_command
**compile_stream __P((char *, struct s_command **, char *));
-static char *duptoeol __P((char *));
+static char *duptoeol __P((char *, char *));
+static void enterlabel __P((struct s_command *));
static struct s_command
- *findlabel __P((struct s_command *, struct s_command *));
-static void fixuplabel __P((struct s_command *, struct s_command *,
- struct s_command *));
+ *findlabel __P((char *));
+static void fixuplabel __P((struct s_command *, struct s_command *));
+static void uselabel __P((void));
/*
* Command specification. This is used to drive the command parser.
@@ -121,7 +132,8 @@ void
compile()
{
*compile_stream(NULL, &prog, NULL) = NULL;
- fixuplabel(prog, prog, NULL);
+ fixuplabel(prog, NULL);
+ uselabel();
appends = xmalloc(sizeof(struct s_appends) * appendnum);
match = xmalloc((maxnsub + 1) * sizeof(regmatch_t));
}
@@ -208,8 +220,6 @@ nonsel: /* Now parse the command */
p = NULL;
cmd2 = xmalloc(sizeof(struct s_command));
cmd2->code = '}';
- cmd2->a1 = cmd2->a2 = NULL;
- cmd2->nonsel = 0;
*compile_stream("}", &cmd->u.c, p) = cmd2;
cmd->next = cmd2;
link = &cmd2->next;
@@ -246,7 +256,7 @@ nonsel: /* Now parse the command */
EATSPACE();
if (*p == '\0')
err(COMPILE, "filename expected");
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "w command");
if (aflag)
cmd->u.fd = -1;
else if ((cmd->u.fd = open(p,
@@ -260,7 +270,7 @@ nonsel: /* Now parse the command */
if (*p == '\0')
err(COMPILE, "filename expected");
else
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "read command");
break;
case BRANCH: /* b t */
p++;
@@ -268,14 +278,15 @@ nonsel: /* Now parse the command */
if (*p == '\0')
cmd->t = NULL;
else
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "branch");
break;
case LABEL: /* : */
p++;
EATSPACE();
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "label");
if (strlen(p) == 0)
err(COMPILE, "empty label");
+ enterlabel(cmd);
break;
case SUBST: /* s */
p++;
@@ -340,6 +351,8 @@ compile_delimited(p, d)
if ((d = compile_ccl(&p, d)) == NULL)
err(COMPILE, "unbalanced brackets ([])");
continue;
+ } else if (*p == '\\' && p[1] == '[') {
+ *d++ = *p++;
} else if (*p == '\\' && p[1] == c)
p++;
else if (*p == '\\' && p[1] == 'n') {
@@ -664,77 +677,129 @@ compile_addr(p, a)
}
/*
- * Return a copy of all the characters up to \n or \0
+ * duptoeol --
+ * Return a copy of all the characters up to \n or \0.
*/
static char *
-duptoeol(s)
+duptoeol(s, ctype)
register char *s;
+ char *ctype;
{
size_t len;
+ int ws;
char *start;
- for (start = s; *s != '\0' && *s != '\n'; ++s);
+ ws = 0;
+ for (start = s; *s != '\0' && *s != '\n'; ++s)
+ ws = isspace(*s);
*s = '\0';
+ if (ws)
+ err(WARNING, "whitespace after %s", ctype);
len = s - start + 1;
return (memmove(xmalloc(len), start, len));
}
/*
- * Find the label contained in the command l in the command linked list cp.
- * L is excluded from the search. Return NULL if not found.
- */
-static struct s_command *
-findlabel(l, cp)
- struct s_command *l, *cp;
-{
- struct s_command *r;
-
- for (; cp; cp = cp->next)
- if (cp->code == ':' && cp != l && strcmp(l->t, cp->t) == 0)
- return (cp);
- else if (cp->code == '{' && (r = findlabel(l, cp->u.c)))
- return (r);
- return (NULL);
-}
-
-/*
- * Convert goto label names to addresses.
- * Detect duplicate labels.
- * Set appendnum to the number of a and r commands in the script.
- * Free the memory used by labels in b and t commands (but not by :)
- * Root is a pointer to the script linked list; cp points to the
- * search start.
+ * Convert goto label names to addresses, and count a and r commands, in
+ * the given subset of the script. Free the memory used by labels in b
+ * and t commands (but not by :).
+ *
* TODO: Remove } nodes
*/
static void
-fixuplabel(root, cp, end)
- struct s_command *root, *cp, *end;
+fixuplabel(cp, end)
+ struct s_command *cp, *end;
{
- struct s_command *cp2;
for (; cp != end; cp = cp->next)
switch (cp->code) {
- case ':':
- if (findlabel(cp, root))
- err(COMPILE2, "duplicate label %s", cp->t);
- break;
case 'a':
case 'r':
appendnum++;
break;
case 'b':
case 't':
+ /* Resolve branch target. */
if (cp->t == NULL) {
cp->u.c = NULL;
break;
}
- if ((cp2 = findlabel(cp, root)) == NULL)
+ if ((cp->u.c = findlabel(cp->t)) == NULL)
err(COMPILE2, "undefined label '%s'", cp->t);
free(cp->t);
- cp->u.c = cp2;
break;
case '{':
- fixuplabel(root, cp->u.c, cp->next);
+ /* Do interior commands. */
+ fixuplabel(cp->u.c, cp->next);
break;
}
}
+
+/*
+ * Associate the given command label for later lookup.
+ */
+static void
+enterlabel(cp)
+ struct s_command *cp;
+{
+ register struct labhash **lhp, *lh;
+ register u_char *p;
+ register u_int h, c;
+
+ for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ lhp = &labels[h & LHMASK];
+ for (lh = *lhp; lh != NULL; lh = lh->lh_next)
+ if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0)
+ err(COMPILE2, "duplicate label '%s'", cp->t);
+ lh = xmalloc(sizeof *lh);
+ lh->lh_next = *lhp;
+ lh->lh_hash = h;
+ lh->lh_cmd = cp;
+ lh->lh_ref = 0;
+ *lhp = lh;
+}
+
+/*
+ * Find the label contained in the command l in the command linked
+ * list cp. L is excluded from the search. Return NULL if not found.
+ */
+static struct s_command *
+findlabel(name)
+ char *name;
+{
+ register struct labhash *lh;
+ register u_char *p;
+ register u_int h, c;
+
+ for (h = 0, p = (u_char *)name; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
+ if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
+ lh->lh_ref = 1;
+ return (lh->lh_cmd);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Warn about any unused labels. As a side effect, release the label hash
+ * table space.
+ */
+static void
+uselabel()
+{
+ register struct labhash *lh, *next;
+ register int i;
+
+ for (i = 0; i < LHSZ; i++) {
+ for (lh = labels[i]; lh != NULL; lh = next) {
+ next = lh->lh_next;
+ if (!lh->lh_ref)
+ err(WARNING, "unused label '%s'",
+ lh->lh_cmd->t);
+ free(lh);
+ }
+ }
+}
diff --git a/usr.bin/sed/defs.h b/usr.bin/sed/defs.h
index 948ba4454811..b4d775fda30a 100644
--- a/usr.bin/sed/defs.h
+++ b/usr.bin/sed/defs.h
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -34,7 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)defs.h 5.3 (Berkeley) 8/28/92
+ * from: @(#)defs.h 8.1 (Berkeley) 6/6/93
+ * $Id: defs.h,v 1.2 1994/04/17 09:41:38 alm Exp $
*/
/*
@@ -74,7 +75,7 @@ struct s_subst {
/*
* An internally compiled command.
- * Initialy, label references are stored in u.t, on a second pass they
+ * Initialy, label references are stored in t, on a second pass they
* are updated to pointers.
*/
struct s_command {
@@ -115,11 +116,11 @@ enum e_args {
struct s_appends {
enum {AP_STRING, AP_FILE} type;
char *s;
+ size_t len;
};
enum e_spflag {
APPEND, /* Append to the contents. */
- APPENDNL, /* Append, with newline. */
REPLACE, /* Replace the contents. */
};
diff --git a/usr.bin/sed/extern.h b/usr.bin/sed/extern.h
index 32b68a1ee9bf..ed0c9bd3bb2a 100644
--- a/usr.bin/sed/extern.h
+++ b/usr.bin/sed/extern.h
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -34,7 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)extern.h 5.5 (Berkeley) 8/30/92
+ * from: @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $Id: extern.h,v 1.2 1994/04/17 09:41:41 alm Exp $
*/
extern struct s_command *prog;
@@ -47,7 +48,9 @@ extern int lastline;
extern int aflag, eflag, nflag;
extern char *fname;
+void cfclose __P((struct s_command *, struct s_command *));
void compile __P((void));
+void cspace __P((SPACE *, char *, size_t, enum e_spflag));
char *cu_fgets __P((char *, int));
void err __P((int, const char *, ...));
int mf_fgets __P((SPACE *, enum e_spflag));
@@ -55,5 +58,3 @@ void process __P((void));
char *strregerror __P((int, regex_t *));
void *xmalloc __P((u_int));
void *xrealloc __P((void *, u_int));
-void cfclose __P((struct s_command *, struct s_command *));
-void cspace __P((SPACE *, char *, size_t, enum e_spflag));
diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c
index f4fc96f7026a..276ff4c59007 100644
--- a/usr.bin/sed/main.c
+++ b/usr.bin/sed/main.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -36,13 +36,14 @@
*/
#ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1992 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 5.6 (Berkeley) 8/30/92";
+/* from: static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; */
+static char *rcsid = "$Id: main.c,v 1.2 1994/04/17 09:41:44 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -286,11 +287,11 @@ mf_fgets(sp, spflag)
}
/*
- * Use fgetline so that we can handle essentially infinite input
- * data. Can't use the pointer into the stdio buffer as the process
- * space because the ungetc() can cause it to move.
+ * Use fgetln so that we can handle essentially infinite input data.
+ * Can't use the pointer into the stdio buffer as the process space
+ * because the ungetc() can cause it to move.
*/
- p = fgetline(f, &len);
+ p = fgetln(f, &len);
if (ferror(f))
err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
cspace(sp, p, len, spflag);
diff --git a/usr.bin/sed/misc.c b/usr.bin/sed/misc.c
index 807821334cee..41e923e82e22 100644
--- a/usr.bin/sed/misc.c
+++ b/usr.bin/sed/misc.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)misc.c 5.3 (Berkeley) 8/26/92";
+/* from: static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; */
+static char *rcsid = "$Id: misc.c,v 1.2 1994/04/17 09:41:49 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c
index f1a4e9e9f2c2..ef6bc71b6d26 100644
--- a/usr.bin/sed/process.c
+++ b/usr.bin/sed/process.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)process.c 5.10 (Berkeley) 12/2/92";
+/* from: static char sccsid[] = "@(#)process.c 8.1 (Berkeley) 6/6/93"; */
+static char *rcsid = "$Id: process.c,v 1.5 1994/04/17 09:41:52 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -57,7 +58,7 @@ static char sccsid[] = "@(#)process.c 5.10 (Berkeley) 12/2/92";
#include "defs.h"
#include "extern.h"
-static SPACE HS = {""}, PS, SS;
+static SPACE HS, PS, SS;
#define pd PS.deleted
#define ps PS.space
#define psl PS.len
@@ -67,7 +68,7 @@ static SPACE HS = {""}, PS, SS;
static inline int applies __P((struct s_command *));
static void flush_appends __P((void));
static void lputs __P((char *));
-static inline int regexec_e __P((regex_t *, const char *, int, int));
+static inline int regexec_e __P((regex_t *, const char *, int, int, size_t));
static void regsub __P((SPACE *, char *, char *));
static int substitute __P((struct s_command *));
@@ -78,12 +79,12 @@ int appendnum; /* Size of appends array. */
static int lastaddr; /* Set by applies if last address of a range. */
static int sdone; /* If any substitutes since last line input. */
/* Iov structure for 'w' commands. */
-static struct iovec iov[2] = { NULL, 0, "\n", 1 };
-
static regex_t *defpreg;
size_t maxnsub;
regmatch_t *match;
+#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); }
+
void
process()
{
@@ -113,6 +114,7 @@ redirect:
(appendnum *= 2));
appends[appendx].type = AP_STRING;
appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
appendx++;
break;
case 'b':
@@ -130,10 +132,10 @@ redirect:
case 'D':
if (pd)
goto new;
- if ((p = strchr(ps, '\n')) == NULL)
+ if ((p = memchr(ps, '\n', psl)) == NULL)
pd = 1;
else {
- psl -= (p - ps) - 1;
+ psl -= (p + 1) - ps;
memmove(ps, p + 1, psl);
}
goto new;
@@ -141,13 +143,13 @@ redirect:
cspace(&PS, hs, hsl, REPLACE);
break;
case 'G':
- cspace(&PS, hs, hsl, APPENDNL);
+ cspace(&PS, hs, hsl, 0);
break;
case 'h':
cspace(&HS, ps, psl, REPLACE);
break;
case 'H':
- cspace(&HS, ps, psl, APPENDNL);
+ cspace(&HS, ps, psl, 0);
break;
case 'i':
(void)printf("%s", cp->t);
@@ -157,10 +159,10 @@ redirect:
break;
case 'n':
if (!nflag && !pd)
- (void)printf("%s\n", ps);
+ OUT(ps)
flush_appends();
r = mf_fgets(&PS, REPLACE);
-#ifdef HISTORIC_PRACTICE
+#ifndef NONHISTORIC_PRACTICE
if (!r)
exit(0);
#endif
@@ -168,31 +170,31 @@ redirect:
break;
case 'N':
flush_appends();
- if (!mf_fgets(&PS, APPENDNL)) {
+ if (!mf_fgets(&PS, 0)) {
if (!nflag && !pd)
- (void)printf("%s\n", ps);
+ OUT(ps)
exit(0);
}
break;
case 'p':
if (pd)
break;
- (void)printf("%s\n", ps);
+ OUT(ps)
break;
case 'P':
if (pd)
break;
- if ((p = strchr(ps, '\n')) != NULL) {
+ if ((p = memchr(ps, '\n', psl)) != NULL) {
oldc = *p;
*p = '\0';
}
- (void)printf("%s\n", ps);
+ OUT(ps)
if (p != NULL)
*p = oldc;
break;
case 'q':
if (!nflag && !pd)
- (void)printf("%s\n", ps);
+ OUT(ps)
flush_appends();
exit(0);
case 'r':
@@ -202,6 +204,7 @@ redirect:
(appendnum *= 2));
appends[appendx].type = AP_FILE;
appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
appendx++;
break;
case 's':
@@ -222,13 +225,13 @@ redirect:
DEFFILEMODE)) == -1)
err(FATAL, "%s: %s\n",
cp->t, strerror(errno));
- iov[0].iov_base = ps;
- iov[0].iov_len = psl;
- if (writev(cp->u.fd, iov, 2) != psl + 1)
+ if (write(cp->u.fd, ps, psl) != psl)
err(FATAL, "%s: %s\n",
cp->t, strerror(errno));
break;
case 'x':
+ if (hs == NULL)
+ cspace(&HS, "", 0, REPLACE);
tspace = PS;
PS = HS;
HS = tspace;
@@ -236,7 +239,7 @@ redirect:
case 'y':
if (pd)
break;
- for (p = ps, len = psl; len--; ++p)
+ for (p = ps, len = psl; --len; ++p)
*p = cp->u.y[*p];
break;
case ':':
@@ -249,7 +252,7 @@ redirect:
} /* for all cp */
new: if (!nflag && !pd)
- (void)printf("%s\n", ps);
+ OUT(ps)
flush_appends();
} /* for all lines */
}
@@ -258,8 +261,8 @@ new: if (!nflag && !pd)
* TRUE if the address passed matches the current program state
* (lastline, linenumber, ps).
*/
-#define MATCH(a) \
- (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1) : \
+#define MATCH(a) \
+ (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \
(a)->type == AT_LINE ? linenum == (a)->u.l : lastline
/*
@@ -314,14 +317,11 @@ substitute(cp)
{
SPACE tspace;
regex_t *re;
- size_t re_off;
- size_t re_eoff;
- int n;
+ size_t re_off, slen;
+ int n, lastempty;
char *s;
- char *eos;
s = ps;
- eos = s + strlen(s);
re = cp->u.s->re;
if (re == NULL) {
if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
@@ -330,33 +330,52 @@ substitute(cp)
cp->u.s->maxbref);
}
}
- if (!regexec_e(re, s, 0, 0))
+ if (!regexec_e(re, s, 0, 0, psl))
return (0);
SS.len = 0; /* Clean substitute space. */
+ slen = psl;
n = cp->u.s->n;
+ lastempty = 1;
+
switch (n) {
case 0: /* Global */
do {
- /* Locate start of replaced string. */
- re_off = match[0].rm_so;
- re_eoff = match[0].rm_eo;
- /* Copy leading retained string. */
- cspace(&SS, s, re_off, APPEND);
- /* Add in regular expression. */
- regsub(&SS, s, cp->u.s->new);
+ if (lastempty || match[0].rm_so != match[0].rm_eo) {
+ /* Locate start of replaced string. */
+ re_off = match[0].rm_so;
+ /* Copy leading retained string. */
+ cspace(&SS, s, re_off, APPEND);
+ /* Add in regular expression. */
+ regsub(&SS, s, cp->u.s->new);
+ }
+
/* Move past this match. */
- s += match[0].rm_eo;
- } while(*s && re_eoff && regexec_e(re, s, REG_NOTBOL, 0));
- if (eos - s > 0 && !re_eoff)
- err(FATAL, "infinite substitution loop");
+ if (match[0].rm_so != match[0].rm_eo) {
+ s += match[0].rm_eo;
+ slen -= match[0].rm_eo;
+ lastempty = 0;
+ } else {
+ if (match[0].rm_so == 0)
+ cspace(&SS, s, match[0].rm_so + 1,
+ APPEND);
+ else
+ cspace(&SS, s + match[0].rm_so, 1,
+ APPEND);
+ s += match[0].rm_so + 1;
+ slen -= match[0].rm_so + 1;
+ lastempty = 1;
+ }
+ } while (slen > 0 && regexec_e(re, s, REG_NOTBOL, 0, slen));
/* Copy trailing retained string. */
- cspace(&SS, s, strlen(s), APPEND);
+ if (slen > 0)
+ cspace(&SS, s, slen, APPEND);
break;
default: /* Nth occurrence */
while (--n) {
s += match[0].rm_eo;
- if (!regexec_e(re, s, REG_NOTBOL, 0))
+ slen -= match[0].rm_eo;
+ if (!regexec_e(re, s, REG_NOTBOL, 0, slen))
return (0);
}
/* FALLTHROUGH */
@@ -369,7 +388,8 @@ substitute(cp)
regsub(&SS, s, cp->u.s->new);
/* Copy trailing retained string. */
s += match[0].rm_eo;
- cspace(&SS, s, strlen(s), APPEND);
+ slen -= match[0].rm_eo;
+ cspace(&SS, s, slen, APPEND);
break;
}
@@ -384,16 +404,14 @@ substitute(cp)
/* Handle the 'p' flag. */
if (cp->u.s->p)
- (void)printf("%s\n", ps);
+ OUT(ps)
/* Handle the 'w' flag. */
if (cp->u.s->wfile && !pd) {
if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile,
O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1)
err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno));
- iov[0].iov_base = ps;
- iov[0].iov_len = psl;
- if (writev(cp->u.s->wfd, iov, 2) != psl + 1)
+ if (write(cp->u.s->wfd, ps, psl) != psl)
err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno));
}
return (1);
@@ -413,7 +431,8 @@ flush_appends()
for (i = 0; i < appendx; i++)
switch (appends[i].type) {
case AP_STRING:
- (void)printf("%s", appends[i].s);
+ fwrite(appends[i].s, sizeof(char), appends[i].len,
+ stdout);
break;
case AP_FILE:
/*
@@ -426,8 +445,8 @@ flush_appends()
*/
if ((f = fopen(appends[i].s, "r")) == NULL)
break;
- while (count = fread(buf, 1, sizeof(buf), f))
- (void)fwrite(buf, 1, count, stdout);
+ while (count = fread(buf, sizeof(char), sizeof(buf), f))
+ (void)fwrite(buf, sizeof(char), count, stdout);
(void)fclose(f);
break;
}
@@ -469,7 +488,7 @@ lputs(s)
(void)putchar("\\abfnrtv"[p - escapes]);
count += 2;
} else {
- (void)printf("%03o", (u_char)*s);
+ (void)printf("%03o", *(u_char *)s);
count += 4;
}
}
@@ -481,21 +500,28 @@ lputs(s)
}
static inline int
-regexec_e(preg, string, eflags, nomatch)
+regexec_e(preg, string, eflags, nomatch, slen)
regex_t *preg;
const char *string;
int eflags, nomatch;
+ size_t slen;
{
int eval;
-
+
if (preg == NULL) {
if (defpreg == NULL)
err(FATAL, "first RE may not be empty");
} else
defpreg = preg;
+ /* Set anchors, discounting trailing newline (if any). */
+ if (slen > 0 && string[slen - 1] == '\n')
+ slen--;
+ match[0].rm_so = 0;
+ match[0].rm_eo = slen;
+
eval = regexec(defpreg, string,
- nomatch ? 0 : maxnsub + 1, match, eflags);
+ nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
switch(eval) {
case 0:
return (1);
@@ -565,24 +591,18 @@ cspace(sp, p, len, spflag)
{
size_t tlen;
- /*
- * Make sure SPACE has enough memory and ramp up quickly. Appends
- * need two extra bytes, one for the newline, one for a terminating
- * NULL.
- */
-/* tlen = sp->len + len + spflag == APPENDNL ? 2 : 1; */
- tlen = sp->len + len + (spflag == APPENDNL ? 2 : 1); /* XXX */
+ /* Make sure SPACE has enough memory and ramp up quickly. */
+ tlen = sp->len + len + 1;
if (tlen > sp->blen) {
sp->blen = tlen + 1024;
sp->space = sp->back = xrealloc(sp->back, sp->blen);
}
- if (spflag == APPENDNL)
- sp->space[sp->len++] = '\n';
- else if (spflag == REPLACE)
+ if (spflag == REPLACE)
sp->len = 0;
memmove(sp->space + sp->len, p, len);
+
sp->space[sp->len += len] = '\0';
}
diff --git a/usr.bin/split/split.c b/usr.bin/split/split.c
index 698f5c29a8c6..f54916f8d305 100644
--- a/usr.bin/split/split.c
+++ b/usr.bin/split/split.c
@@ -77,7 +77,7 @@ main(argc, argv)
ifd = 0;
break;
case 'b': /* byte count split */
- if (numlines)
+ if (numlines || ((argc-1) <= cnt))
usage();
if (!argv[cnt][2])
bytecnt = atol(argv[++cnt]);
diff --git a/usr.bin/strings/strings.c b/usr.bin/strings/strings.c
index 966a83db3f9e..d89902a3e1f7 100644
--- a/usr.bin/strings/strings.c
+++ b/usr.bin/strings/strings.c
@@ -84,7 +84,7 @@ main(argc, argv)
*/
asdata = exitcode = fflg = oflg = 0;
minlen = -1;
- while ((ch = getopt(argc, argv, "-0123456789anof")) != EOF)
+ while ((ch = getopt(argc, argv, "-0123456789an:of")) != EOF)
switch((char)ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
diff --git a/usr.bin/su/Makefile b/usr.bin/su/Makefile
index f86450c37c64..cdd63aa9050a 100644
--- a/usr.bin/su/Makefile
+++ b/usr.bin/su/Makefile
@@ -1,14 +1,19 @@
-# @(#)Makefile 5.5 (Berkeley) 5/11/90
-
-
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
-.endif
+# $Id: Makefile,v 1.8 1994/06/23 05:46:59 jkh Exp $
+# From: @(#)Makefile 5.5 (Berkeley) 5/11/90
PROG= su
BINOWN= root
BINMODE=4555
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/su/su.1 b/usr.bin/su/su.1
index e0de965bd1e4..5f80e085db38 100644
--- a/usr.bin/su/su.1
+++ b/usr.bin/su/su.1
@@ -41,7 +41,6 @@
.Nm su
.Op Fl Kflm
.Op Ar login
-.Op Ar -c cmd
.Sh DESCRIPTION
.Nm Su
requests the Kerberos password for
@@ -120,9 +119,6 @@ and the caller's real uid is
non-zero,
.Nm su
will fail.
-.It Fl "c cmd"
-Execute command as the nominated user. The user's shell is invoked
-to execute the command. It is assumed that the shell supports a -c switch.
.El
.Pp
The
diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c
index 76648e65cb1d..fb24c15a549a 100644
--- a/usr.bin/su/su.c
+++ b/usr.bin/su/su.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)su.c 5.26 (Berkeley) 7/6/91";
#include <string.h>
#include <unistd.h>
#include <paths.h>
+#include <stdlib.h>
#ifdef KERBEROS
#include <kerberosIV/des.h>
@@ -76,39 +77,57 @@ main(argc, argv)
uid_t ruid, getuid();
int asme, ch, asthem, fastlogin, prio;
enum { UNSET, YES, NO } iscsh = UNSET;
- char *user, *shell, *username, *cleanenv[20], *nargv[4], **np;
+ char *user, *shell, *username, *cleanenv[20], **nargv, **np;
char shellbuf[MAXPATHLEN];
char avshellbuf[MAXPATHLEN];
char *crypt(), *getpass(), *getenv(), *getlogin(), *ontty();
+ int i;
- np = &nargv[3];
- *np-- = NULL;
asme = asthem = fastlogin = 0;
- while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
- switch((char)ch) {
+
+ user = "root";
+ while ( optind < argc )
+ if ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+ switch((char)ch) {
#ifdef KERBEROS
- case 'K':
- use_kerberos = 0;
- break;
+ case 'K':
+ use_kerberos = 0;
+ break;
#endif
- case 'f':
- fastlogin = 1;
- break;
- case '-':
- case 'l':
- asme = 0;
- asthem = 1;
- break;
- case 'm':
- asme = 1;
- asthem = 0;
+ case 'f':
+ fastlogin = 1;
+ break;
+ case '-':
+ case 'l':
+ asme = 0;
+ asthem = 1;
+ break;
+ case 'm':
+ asme = 1;
+ asthem = 0;
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: su [%s] [login]\n",
+ ARGSTR);
+ exit(1);
+ }
+ else
+ {
+ user = argv[optind++];
break;
- case '?':
- default:
- (void)fprintf(stderr, "usage: su [%s] [login]\n",
- ARGSTR);
- exit(1);
}
+
+ if ((nargv = malloc (sizeof (char *) * (argc + 4))) == NULL) {
+ (void)fprintf(stderr, "su: alloc failure\n" );
+ exit(1);
+ }
+
+ nargv[argc + 3] = NULL;
+ for (i = argc; i >= optind; i--)
+ nargv[i + 3] = argv[i];
+ np = &nargv[i + 3];
+
argv += optind;
errno = 0;
@@ -128,7 +147,12 @@ main(argc, argv)
fprintf(stderr, "su: who are you?\n");
exit(1);
}
- username = strdup(pwd->pw_name);
+ if ((username = strdup(pwd->pw_name)) == NULL ) {
+ (void)fprintf(stderr, "su: alloc failure\n" );
+ exit(1);
+ }
+
+
if (asme)
if (pwd->pw_shell && *pwd->pw_shell)
shell = strcpy(shellbuf, pwd->pw_shell);
@@ -138,7 +162,6 @@ main(argc, argv)
}
/* get target login information, default to root */
- user = *argv ? *argv : "root";
if ((pwd = getpwnam(user)) == NULL) {
fprintf(stderr, "su: unknown login %s\n", user);
exit(1);
diff --git a/usr.bin/syscons/Makefile b/usr.bin/syscons/Makefile
deleted file mode 100644
index f50f5a4ed066..000000000000
--- a/usr.bin/syscons/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-PROG = syscons
-CFLAGS += -Wall -I${.CURDIR}
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/syscons/syscons.1 b/usr.bin/syscons/syscons.1
deleted file mode 100644
index e8a40b14104a..000000000000
--- a/usr.bin/syscons/syscons.1
+++ /dev/null
@@ -1,103 +0,0 @@
-.\"
-.\" syscons - a utility for manipulating the syscons driver
-.\"
-.\" 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.
-.\"
-.\" @(#)syscons.1
-.\"
-.TH syscons 1 "August 24, 1993" "" "FreeBSD"
-
-.SH NAME
-syscons - a utility for manipulating the syscons VTY driver.
-.SH SYNOPSIS
-.na
-.B syscons
-.RB [options]
-.SH DESCRIPTION
-The
-.B syscons
-command is used to set various options for the syscons console driver,
-such as font, keymap, current screen, etc.
-.SH OPTIONS
-.TP
-The following command line options are supported.
-.TP
-.B \-v
-Turns on verbose output.
-.TP
-.BI "\-s\ " N|off
-Sets the screensaver timeout to
-.I N
-seconds, or turns it
-.I off
-.TP
-.BI "\-V\ " NAME|list
-Sets the screensaver appearance to
-.I NAME .
-Use \-V list to list the available
-.I NAMEs .
-.TP
-.BI "\-m\ " 80x25|80x50
-Set screen size to 80x25 or 80x50 chars.
-.TP
-.BI "\-r\ " [ delay.repeat | slow | fast | normal ]
-Set keyboard
-.I delay
-and
-.I repeat
-rates, or use presets for
-.I slow,
-.I fast
-or
-.I normal.
-.TP
-.BI "\-S\ " scrmap
-Install screen output map file from
-.I scrmap
-.TP
-.BI "\-k\ " mapfile
-Install keyboard map file from
-.I mapfile
-.TP
-.BI "\-f\ " size\ file
-Load font
-.I file
-for
-.I size
-(currently, only 8, 14 or 16).
-.TP
-.BI "\-t\ " scr#
-Set current virtual screen to be
-.I scr#
-.TP
-.BI "\-F\ " FN#\ string
-Set function key
-.I FN#
-to send
-.I string
-.
-.PP
-.SH FILES
-/usr/share/syscons/fonts
-/usr/share/syscons/keymaps
-/usr/share/syscons/scrnmaps
-.PP
-.SH BUGS
-Sure to be some.
-.SH "SEE ALSO"
-.BR keyboard (4) ,
-.BR screen (4) ,
-.BR /sys/i386/conf/SYSCONS
-.SH AUTHORS
-Christoph M. Robitschko
-.TP
-Sxren Schmidt (syscons driver & original code).
-.TP
-Jordan Hubbard (this man page).
diff --git a/usr.bin/syscons/syscons.c b/usr.bin/syscons/syscons.c
deleted file mode 100644
index 9637d7b6add3..000000000000
--- a/usr.bin/syscons/syscons.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Copyright (c) 1993 Christoph M. Robitschko
- * 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 Christoph M. Robitschko
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <machine/console.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/errno.h>
-
-#include "syscons.h"
-
-int verbose = 0;
-char *prgname;
-
-
-__BEGIN_DECLS
-int is_syscons __P((int));
-void screensaver __P((char *));
-void screensavertype __P((char *));
-void linemode __P((char *));
-void keyrate __P((char *));
-void keymap __P((char *));
-void mapscr __P((char *));
-void loadfont __P((char *, char *));
-void switchto __P((char *));
-void setfkey __P((char *, char *));
-void displayit __P((void));
-void usage __P((void));
-char *mkfullname __P((const char *, const char *, const char *));
-char *nextarg __P((int, char **, int *, int));
-__END_DECLS
-
-
-
-void
-main(argc, argv)
-int argc;
-char **argv;
-{
-extern char *optarg;
-extern int optind;
-int opt;
-
-
- prgname = argv[0];
- if (!is_syscons(0))
- exit(1);
- while((opt = getopt(argc, argv, "s:S:m:r:k:f:t:F:V:vd")) != -1)
- switch(opt) {
- case 's':
- screensaver(optarg);
- break;
- case 'V':
- screensavertype(optarg);
- break;
- case 'm':
- linemode(optarg);
- break;
- case 'r':
- keyrate(optarg);
- break;
- case 'k':
- keymap(optarg);
- break;
- case 'S':
- mapscr(optarg);
- break;
- case 'f':
- loadfont(optarg, nextarg(argc, argv, &optind, 'f'));
- break;
- case 't':
- switchto(optarg);
- break;
- case 'F':
- setfkey(optarg, nextarg(argc, argv, &optind, 'F'));
- break;
- case 'v':
- verbose ++;
- break;
- case 'd':
- displayit();
- break;
- default:
- usage();
- exit(1);
- }
- if ((optind != argc) || (argc == 1)) {
- usage();
- exit(1);
- }
- exit(0);
-}
-
-
-int
-is_syscons(fd)
-int fd;
-{
-vtmode_t mode;
-
- /* Try to find out if we are running on a syscons VT */
- if (ioctl(fd, VT_GETMODE, &mode) == 0)
- return(1);
- if (errno == ENOTTY) {
- printf("You must be running this from a syscons vty for it to work.\n\n");
- printf("If you are currently using pccons (default) and wish to have virtual\n");
- printf("consoles, then rebuild your kernel after replacing the line:\n\n");
- printf("\tdevice pc0 at isa? port \042IO_KBD\042 tty irq 1 vector pcrint\n");
- printf("\nwith:\n\n");
- printf("\tdevice sc0 at isa? port \042IO_KBD\042 tty irq 1 vector scintr\n");
- printf("\n(Then install the new kernel and reboot your system)\n");
- }
- else
- perror("getting console state");
- return(0);
-}
-
-
-
-void
-usage(void)
-{
-const char usagestr[] = {"\
-Usage: syscons -v (be verbose)\n\
- -s {TIME|off} (set screensaver timeout to TIME seconds)\n\
- -V {NAME|list} (set screensaver type or list available types\n\
- -m {80x25|80x50} (set screen to 25 or 50 lines)\n\
- -r DELAY.REPEAT (set keyboard delay & repeat rate)\n\
- -r fast (set keyboard delay & repeat to fast)\n\
- -r slow (set keyboard delay & repeat to slow)\n\
- -r normal (set keyboard delay & repeat to normal)\n\
- -k MAPFILE (load keyboard map file)\n\
- -f SIZE FILE (load font file of size 8, 14 or 16)\n\
- -t SCRNUM (switch to specified VT)\n\
- -F NUM STRING (set function key NUM to send STRING)\n\
- -S SCRNMAP (load screen map file)\n\
-"};
- fprintf(stderr, usagestr);
-}
-
-
-char *
-nextarg(ac, av, indp, oc)
-int ac;
-char **av;
-int *indp;
-int oc;
-{
- if (*indp < ac)
- return(av[(*indp)++]);
- fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
- usage();
- exit(1);
- return("");
-}
-
-
-
-char *
-mkfullname(s1, s2, s3)
-const char *s1, *s2, *s3;
-{
-static char *buf = NULL;
-static int bufl = 0;
-int f;
-
-
- f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
- if (f > bufl)
- if (buf)
- buf = (char *)realloc(buf, f);
- else
- buf = (char *)malloc(f);
- if (!buf) {
- bufl = 0;
- return(NULL);
- }
-
- bufl = f;
- strcpy(buf, s1);
- strcat(buf, s2);
- strcat(buf, s3);
- return(buf);
-}
-
-
-void
-screensaver(opt)
-char *opt;
-{
-int nsec;
-char *s1;
-
-
- if (!strcmp(opt, "off"))
- nsec = 0;
- else {
- nsec = strtol(opt, &s1, 0);
- if ((nsec < 0) || (*opt == '\0') || (*s1 != '\0')) {
- fprintf(stderr, "argument to -s must be a positive integer.\n");
- return;
- }
- }
-
- if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
- perror("setting screensaver period");
-}
-
-
-void
-screensavertype(opt)
-char *opt;
-{
-ssaver_t shaver;
-int i, e;
-
-
- if (!strcmp(opt, "list")) {
- i = 0;
- printf("available screen saver types:\n");
- do {
- shaver.num = i;
- e = ioctl(0, CONS_GSAVER, &shaver);
- i ++;
- if (e == 0)
- printf("\t%d\t%s\n", shaver.num, shaver.name);
- } while (e == 0);
- if (e == -1 && errno != EIO)
- perror("getting screensaver info");
- } else {
- i = 0;
- do {
- shaver.num = i;
- e = ioctl(0, CONS_GSAVER, &shaver);
- i ++;
- if (e == 0 && !strcmp(opt, shaver.name)) {
- if (ioctl(0, CONS_SSAVER, &shaver) == -1)
- perror("setting screensaver type");
- return;
- }
- } while (e == 0);
- if (e == -1 && errno != EIO)
- perror("getting screensaver info");
- else
- fprintf(stderr, "%s: No such screensaver\n", opt);
- }
-}
-
-
-void
-linemode(opt)
-char *opt;
-{
-unsigned long req;
-
- if (!strcmp(opt, "80x25"))
- req = CONS_80x25TEXT;
- else if (!strcmp(opt, "80x50"))
- req = CONS_80x50TEXT;
- else {
- fprintf(stderr, "Unknown mode to -m: %s\n", opt);
- return;
- }
-
- if (ioctl(0, req, NULL) == -1)
- perror("Setting line mode");
-}
-
-
-void
-keyrate(opt)
-char *opt;
-{
-const int delays[] = {250, 500, 750, 1000};
-const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63,
- 68, 76, 84, 92, 100, 110, 118, 126,
- 136, 152, 168, 184, 200, 220, 236, 252,
- 272, 304, 336, 368, 400, 440, 472, 504};
-const int ndelays = (sizeof(delays) / sizeof(int));
-const int nrepeats = (sizeof(repeats) / sizeof(int));
-struct {
- int rep:5;
- int del:2;
- int pad:1;
- } rate;
-
- if (!strcmp(opt, "slow"))
- rate.del = 3, rate.rep = 31;
- else if (!strcmp(opt, "normal"))
- rate.del = 1, rate.rep = 15;
- else if (!strcmp(opt, "fast"))
- rate.del = rate.rep = 0;
- else {
- int n;
- int delay, repeat;
- char *v1;
-
-
- delay = strtol(opt, &v1, 0);
- if ((delay < 0) || (*v1 != '.'))
- goto badopt;
- opt = ++v1;
- repeat = strtol(opt, &v1, 0);
- if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
-badopt:
- fprintf(stderr, "argument to -r must be DELAY.REPEAT\n");
- return;
- }
- for (n = 0; n < ndelays - 1; n++)
- if (delay <= delays[n])
- break;
- rate.del = n;
- for (n = 0; n < nrepeats - 1; n++)
- if (repeat <= repeats[n])
- break;
- rate.rep = n;
- }
-
- if (verbose)
- fprintf(stderr, "setting keyboard rate to %d.%d\n", delays[rate.del], repeats[rate.rep]);
- if (ioctl(0, KDSETRAD, rate) == -1)
- perror("setting keyboard rate");
-}
-
-
-void
-keymap(opt)
-char *opt;
-{
-char *mapfn;
-int mapfd;
-keymap_t map;
-int f;
-const char *prefix[] = {"", "", KEYMAP_PATH, NULL};
-const char *postfix[] = {"", ".map", ".map"};
-
-
- mapfd = -1;
- for (f = 0; prefix[f]; f++) {
- mapfn = mkfullname(prefix[f], opt, postfix[f]);
- mapfd = open(mapfn, O_RDONLY, 0);
- if (verbose)
- fprintf(stderr, "trying to open keymap file %s ... %s\n", mapfn, (mapfd==-1?"failed":"OK"));
- if (mapfd >= 0)
- break;
- }
- if (mapfd == -1) {
- perror("Keymap file not found");
- return;
- }
- if ((read(mapfd, &map, sizeof(map)) != sizeof(map)) ||
- (read(mapfd, &map, 1) != 0)) {
- fprintf(stderr, "\"%s\" is not in keymap format.\n", opt);
- (void) close(mapfd);
- return;
- }
- (void) close(mapfd);
- if (ioctl(0, PIO_KEYMAP, &map) == -1)
- perror("setting keyboard map");
-}
-
-void
-mapscr(opt)
-char *opt;
-{
-char *mapfn;
-int mapfd;
-scrmap_t map;
-int f;
-const char *prefix[] = {"", "", SCRNMAP_PATH, NULL};
-const char *postfix[] = {"", ".scr", ".scr"};
-
-
- mapfd = -1;
- for (f = 0; prefix[f]; f++) {
- mapfn = mkfullname(prefix[f], opt, postfix[f]);
- mapfd = open(mapfn, O_RDONLY, 0);
- if (verbose)
- fprintf(stderr, "trying to open scrnmap file %s ... %s\n", mapfn, (mapfd==-1?"failed":"OK"));
- if (mapfd >= 0)
- break;
- }
- if (mapfd == -1) {
- perror("Scrnmap file not found");
- return;
- }
- if ((read(mapfd, &map, sizeof(map)) != sizeof(map)) ||
- (read(mapfd, &map, 1) != 0)) {
- fprintf(stderr, "\"%s\" is not in scrnmap format.\n", opt);
- (void) close(mapfd);
- return;
- }
- (void) close(mapfd);
- if (ioctl(0, PIO_SCRNMAP, &map) == -1)
- perror("setting screen map");
-}
-
-void
-loadfont(sizec, fname)
-char *sizec;
-char *fname;
-{
-char *fontfn;
-int fontfd;
-void *font;
-char *v1;
-int ind, f;
-const struct {
- int fsize;
- int msize;
- unsigned long req;
- } fontinfo[] = {
- { 8, sizeof(fnt8_t), PIO_FONT8x8},
- { 14, sizeof(fnt14_t), PIO_FONT8x14},
- { 16, sizeof(fnt16_t), PIO_FONT8x16},
- { 0 }};
-const char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL};
-const char *postfix[] = {"", ".fnt", "", ".fnt"};
-
-
-
- f = strtol(sizec, &v1, 0);
- for (ind = 0; fontinfo[ind].fsize; ind++)
- if (fontinfo[ind].fsize == f)
- break;
- if ((fontinfo[ind].fsize == 0) || (*v1 != '\0')) {
- fprintf(stderr, "%s is an unsupported font size.\n", sizec);
- return;
- }
- font = (void *)malloc(fontinfo[ind].msize);
- if (!font) {
- fprintf(stderr, "loading font: Out of memory.\n");
- return;
- }
-
- fontfd = -1; fontfn = "";
- for (f = 0; prefix[f]; f++) {
- fontfn = mkfullname(prefix[f], fname, postfix[f]);
- fontfd = open(fontfn, O_RDONLY, 0);
- if (verbose)
- fprintf(stderr, "trying to open font file %s ... %s\n", fontfn, (fontfd==-1?"failed":"OK"));
- if (fontfd >= 0)
- break;
- }
- if (fontfd == -1) {
- perror("Font file not found");
- return;
- }
- if ((read(fontfd, font, fontinfo[ind].msize) != fontinfo[ind].msize) ||
- (read(fontfd, font, 1) != 0)) {
- fprintf(stderr, "\"%s\" is not a font with size %s.\n", fontfn, sizec);
- (void) close(fontfd);
- return;
- }
-
- if (ioctl(0, fontinfo[ind].req, font) == -1)
- perror("Setting font");
-}
-
-
-void
-switchto(opt)
-char *opt;
-{
-int scrno;
-char *v1;
-
-
- scrno = strtol(opt, &v1, 0);
- if ((scrno < 1) || (scrno > 12) || (*v1 != '\0')) {
- fprintf(stderr, "argument to -t must be between 1 and 12.\n");
- return;
- }
- if (ioctl(0, VT_ACTIVATE, scrno) == -1)
- perror("switching to new VT");
-}
-
-
-void
-setfkey(knumc, str)
-char *knumc;
-char *str;
-{
-fkeyarg_t fkey;
-char *v1;
-long keynum;
-
- keynum = strtol(knumc, &v1, 0);
- if (keynum < 0 || keynum > 59 || *v1 != '\0') {
- fprintf(stderr, "function key number must be between 0 and 59.\n");
- return;
- }
- fkey.keynum = keynum;
- if ((fkey.flen = strlen(str)) > MAXFK) {
- fprintf(stderr, "function key string too long (%d > %d)\n", fkey.flen, MAXFK);
- return;
- }
- strcpy(fkey.keydef, str);
- if (verbose)
- fprintf(stderr, "setting F%d to \"%s\"\n", fkey.keynum, str);
- fkey.keynum--;
- if (ioctl(0, SETFKEY, &fkey) == -1)
- perror("setting function key");
-}
-
-
-
-void
-displayit(void)
-{
- if (verbose)
- printf("absolutely ");
- printf("nothing to display.\n");
-}
diff --git a/usr.bin/syscons/syscons.h b/usr.bin/syscons/syscons.h
deleted file mode 100644
index c8949281328e..000000000000
--- a/usr.bin/syscons/syscons.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* Where everything goes by default - ALL PATHS MUST END WITH A '/'! */
-
-#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
-#define FONT_PATH "/usr/share/syscons/fonts/"
-#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
-
diff --git a/usr.bin/telnet/Makefile b/usr.bin/telnet/Makefile
index 80f52d9c97c6..4eafca588985 100644
--- a/usr.bin/telnet/Makefile
+++ b/usr.bin/telnet/Makefile
@@ -5,6 +5,12 @@
PROG= telnet
CFLAGS+=-DTERMCAP -DUSE_TERMIO
+.ifdef KLUDGE
+.undef KLUDGE
+PROG= otelnet
+NOMAN=
+CFLAGS+=-DKLUDGELINEMODE
+.endif
CFLAGS+=-I${.CURDIR}/../../lib
.if exists(/usr/lib/libcrypt.a)
diff --git a/usr.bin/telnet/commands.c b/usr.bin/telnet/commands.c
index c5e175bfec95..d14a448df2e9 100644
--- a/usr.bin/telnet/commands.c
+++ b/usr.bin/telnet/commands.c
@@ -2084,7 +2084,7 @@ status(argc, argv)
printf("No connection.\n");
}
# if !defined(TN3270)
- printf("Escape character is '%s'.\n", control(escape));
+ printf("Escape character is '%s'.\n", control(escape));
(void) fflush(stdout);
# else /* !defined(TN3270) */
if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
diff --git a/usr.bin/telnet/telnet.1 b/usr.bin/telnet/telnet.1
index 84c55c529e66..2d4f1da898e3 100644
--- a/usr.bin/telnet/telnet.1
+++ b/usr.bin/telnet/telnet.1
@@ -41,12 +41,17 @@
protocol
.Sh SYNOPSIS
.Nm telnet
+.Op Fl 8
+.Op Fl E
+.Op Fl L
+.Op Fl K
.Op Fl d
.Op Fl a
.Op Fl n Ar tracefile
.Op Fl e Ar escapechar
.Oo
.Op Fl l Ar user
+.Op Fl r
.Ar host
.Op port
.Oc
@@ -71,6 +76,27 @@ command with those arguments.
.Pp
Options:
.Bl -tag -width indent
+.It Fl 8
+The
+.Fl 8
+option allows the telnet session to be run in binary input/output
+mode.
+.It Fl E
+The
+.Fl E
+option stops any character from being recognized as an escape character.
+When used with the
+.Fl 8
+option, this provides a completely transparent connection.
+.It Fl K
+The
+.Fl K
+option turns off all Kerberos authentication.
+.It Fl L
+The
+.Fl L
+option allows the telnet session to be run in binary output
+mode.
.It Fl d
Sets the initial value of the
.Ic debug
@@ -110,14 +136,15 @@ This option may also be used with the
command.
.It Fl e Ar escape char
Sets the initial
-.Nm
.Nm telnet
escape character to
.Ar escape char.
-If
-.Ar escape char
-is ommitted, then
-there will be no escape character.
+.It Fl r
+The
+.Fl r
+option allows the telnet session to simulate
+.Xr rlogin 1
+session.
.It Ar host
Indicates the official name, an alias, or the Internet address
of a remote host.
diff --git a/usr.bin/telnet/telnet.c b/usr.bin/telnet/telnet.c
index 386295261d4e..0ba7a29d3bcf 100644
--- a/usr.bin/telnet/telnet.c
+++ b/usr.bin/telnet/telnet.c
@@ -1936,7 +1936,7 @@ telsnd()
command(0, "z\n", 2);
continue;
}
- if (sc == escape) {
+ if (escape != _POSIX_VDISABLE && sc == escape) {
command(0, (char *)tbp, tcc);
bol = 1;
count += tcc;
@@ -1953,7 +1953,7 @@ telsnd()
}
if ((sc == '\n') || (sc == '\r'))
bol = 1;
- } else if (sc == escape) {
+ } else if (escape != _POSIX_VDISABLE && sc == escape) {
/*
* Double escape is a pass through of a single escape character.
*/
@@ -1973,7 +1973,8 @@ telsnd()
} else
bol = 0;
#ifdef KLUDGELINEMODE
- if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
+ if (kludgelinemode && (globalmode&MODE_EDIT) &&
+ echoc != _POSIX_VDISABLE && (sc == echoc)) {
if (tcc > 0 && *tbp == echoc) {
tcc--; tbp++; count++;
} else {
diff --git a/usr.bin/tn3270/tools/mkhits/dohits.c b/usr.bin/tn3270/tools/mkhits/dohits.c
index 1ca1ebeffd52..769888d93b12 100644
--- a/usr.bin/tn3270/tools/mkhits/dohits.c
+++ b/usr.bin/tn3270/tools/mkhits/dohits.c
@@ -257,7 +257,7 @@ char *aidfile, *fcnfile;
}
scanwhite(fcnfile, "FCN_");
- while (gets(line) != NULL) {
+ while (fgets(line, sizeof line - 1, stdin) != NULL) {
if (!isdigit(line[0])) {
continue;
}
diff --git a/usr.bin/tput/tput.c b/usr.bin/tput/tput.c
index 72b05a33d311..ddf5c0c2b130 100644
--- a/usr.bin/tput/tput.c
+++ b/usr.bin/tput/tput.c
@@ -88,9 +88,11 @@ main(argc, argv)
p = "is";
break;
case 'l':
- if (!strcmp(p, "longname"))
+ if (!strcmp(p, "longname")) {
prlongname(tbuf);
- continue;
+ continue;
+ }
+ break;
case 'r':
if (!strcmp(p, "reset"))
p = "rs";
diff --git a/usr.bin/tset/tset.c b/usr.bin/tset/tset.c
index 4966b049dd87..62745f0b250d 100644
--- a/usr.bin/tset/tset.c
+++ b/usr.bin/tset/tset.c
@@ -180,10 +180,15 @@ main(argc, argv)
tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
}
- /* Get the terminal name from the entry. */
- p = tcapbuf;
- if (p != NULL && *p != ':') {
- t = p;
+ /*
+ * The termcap file generally has a two-character name first in each
+ * entry followed by more descriptive names. If we ended up with the
+ * first one, we switch to the second one for setting or reporting
+ * information.
+ */
+ p = strpbrk(tcapbuf, "|:");
+ if (p != NULL && *p != ':' && !strncmp(ttype, tcapbuf, p - tcapbuf)) {
+ t = ++p;
if (p = strpbrk(p, "|:")) {
savech = *p;
*p = '\0';
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile
index fbb1588cebd8..b1ed449041d8 100644
--- a/usr.bin/vi/Makefile
+++ b/usr.bin/vi/Makefile
@@ -1,21 +1,24 @@
-# @(#)Makefile 8.26 (Berkeley) 1/12/94
-
-PROG= vi
-MAN1= vi.1
-BINDIR?= /usr/bin
+# @(#)Makefile 8.30 (Berkeley) 3/22/94
+# $Id: Makefile,v 1.17 1994/06/02 00:27:52 phk Exp $
+PROG= nvi
#CFLAGS=-g -DDEBUG
#CFLAGS+=-pg
-CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/obj -I${.CURDIR}/include -I${.CURDIR}/nex -I${.CURDIR}/nvi
+CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/ex -I${.CURDIR}/vi
#STRIP=
-.PATH: ${.CURDIR}/nex ${.CURDIR}/sex ${.CURDIR}/nvi ${.CURDIR}/svi \
- ${.CURDIR}/xaw
-CLEANFILES+=ex
+.PATH: ${.CURDIR}/ex ${.CURDIR}/sex ${.CURDIR}/vi \
+ ${.CURDIR}/svi ${.CURDIR}/xaw
+#CLEANFILES+=ex
+CLEANFILES+=vi.1 vi-ref.1
+MANSRC= `pwd`
+MAN1+= vi.1 vi-ref.1
+
+MLINKS+=vi.1 nvi.1
# General sources.
-SRCS= ascii.c cut.c delete.c exf.c line.c log.c main.c mark.c \
- options.c options_f.c screen.c search.c seq.c recover.c \
- term.c timer.c trace.c util.c
+SRCS= ascii.c cut.c delete.c exf.c intr.c line.c log.c main.c \
+ mark.c options.c options_f.c put.c screen.c search.c seq.c \
+ recover.c term.c timer.c trace.c util.c
# Ex source.
SRCS+= ex.c ex_abbrev.c ex_append.c ex_args.c ex_argv.c ex_at.c \
@@ -32,13 +35,13 @@ SRCS+= sex_confirm.c sex_get.c sex_refresh.c sex_screen.c sex_term.c \
sex_util.c
# Vi source.
-SRCS+= getc.c v_again.c v_at.c v_ch.c v_delete.c v_ex.c v_exit.c \
- v_exmode.c v_filter.c v_increment.c v_init.c v_join.c v_left.c \
- v_mark.c v_match.c v_ntext.c v_paragraph.c v_put.c v_redraw.c \
- v_replace.c v_right.c v_screen.c v_scroll.c v_search.c v_section.c \
- v_sentence.c v_shift.c v_status.c v_stop.c v_switch.c v_tag.c \
- v_text.c v_ulcase.c v_undo.c v_util.c v_word.c v_xchar.c v_yank.c \
- v_z.c vcmd.c vi.c
+SRCS+= getc.c v_again.c v_at.c v_ch.c v_delete.c v_ex.c v_filter.c \
+ v_increment.c v_init.c v_join.c v_left.c v_mark.c v_match.c \
+ v_ntext.c v_paragraph.c v_put.c v_redraw.c v_replace.c v_right.c \
+ v_screen.c v_scroll.c v_search.c v_section.c v_sentence.c \
+ v_shift.c v_status.c v_stop.c v_switch.c v_tag.c v_text.c \
+ v_ulcase.c v_undo.c v_util.c v_word.c v_xchar.c v_yank.c \
+ v_z.c v_zexit.c vcmd.c vi.c
# Vi curses screen source.
SRCS+= svi_confirm.c svi_ex.c svi_get.c svi_line.c svi_refresh.c \
@@ -49,17 +52,21 @@ SRCS+= xaw_screen.c
#LDADD+=-pg
DPADD+= ${LIBCURSES} ${LIBTERM} ${LIBUTIL}
-LDADD+= -lcurses -ltermlib -lutil
+LDADD+= -lcurses -ltermlib -lutil
SPECHDR=excmd.h options.h
CLEANFILES+=${SPECHDR}
-DPSRCS+=${SPECHDR}
-LINKS= ${BINDIR}/vi ${BINDIR}/ex ${BINDIR}/vi ${BINDIR}/view
+LINKS= ${BINDIR}/nvi ${BINDIR}/vi ${BINDIR}/nvi ${BINDIR}/ex \
+ ${BINDIR}/nvi ${BINDIR}/view
-all: vi vi.1
+all: excmd.h options.h nvi vi.1 vi-ref.1
+ - rm -f vi
+ - rm -f ex
+ - if [ ! -d vi ]; then ln nvi vi; fi
+ - if [ ! -d ex ]; then ln nvi ex; fi
warn:: ${SRCS}
-(cd ${.CURDIR} && \
- gcc -Wall -O -DDEBUG -Iobj -Invi -Inex -I. ${.ALLSRC} \
+ gcc -Wall -O -DDEBUG -Iobj -Ivi -Iex -I. ${.ALLSRC} \
-lcurses -ltermlib 2>&1 | \
sed -e "/warning: .*sccsid.*defined but not used/d" \
-e "/warning: suggest parentheses around/d" \
@@ -85,15 +92,34 @@ options.h: options.h.stub options.c # Makefile
excmd.h: excmd.h.stub excmd.c # Makefile
rm -f excmd.h
- cp ${.CURDIR}/nex/excmd.h.stub excmd.h
+ cp ${.CURDIR}/ex/excmd.h.stub excmd.h
chmod 664 excmd.h
(echo '/^\/\* C_[0-9A-Z_]* \*\/$$/ {'; \
echo 'printf("#define %s %d\n", $$2, cnt++)'; \
echo 'next'; \
echo '}') > /tmp/__vi.excmd.h
- awk -f /tmp/__vi.excmd.h ${.CURDIR}/nex/excmd.c >> excmd.h
+ awk -f /tmp/__vi.excmd.h ${.CURDIR}/ex/excmd.c >> excmd.h
rm -f /tmp/__vi.excmd.h
+docs: vi.0.txt vi.0.ps vi.ref.txt vi.ref.ps
+vi.0.txt: vi.1 set.opt.roff
+ cpp -DMANUAL -I${.CURDIR}/docs ${.CURDIR}/docs/vi.1 | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man -Tascii > $@
+vi.0.ps: vi.1 set.opt.roff
+ cpp -DMANUAL -I${.CURDIR}/docs ${.CURDIR}/docs/vi.1 | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man > $@
+vi.ref.txt: vi.ref set.opt.roff
+ cpp -DREFERENCE -I${.CURDIR}/docs ${.CURDIR}/docs/vi.ref | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man -Tascii > $@
+vi.ref.ps: vi.ref set.opt.roff
+ cpp -DREFERENCE -I${.CURDIR}/docs ${.CURDIR}/docs/vi.ref | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man > $@
+
+vi.1: $(.CURDIR)/docs/vi.1 $(.CURDIR)/docs/set.opt.roff
+ cpp -DMANUAL -P -I$(.CURDIR)/docs $(.CURDIR)/docs/vi.1 > vi.1
+
+vi-ref.1: $(.CURDIR)/docs/vi.ref $(.CURDIR)/docs/set.opt.roff
+ cpp -DREFERENCE -P -I$(.CURDIR)/docs $(.CURDIR)/docs/vi.ref > vi-ref.1
.include <bsd.prog.mk>
-.depend: ${SPECHDR}
+.depend: compat.h ${SPECHDR}
diff --git a/usr.bin/vi/README b/usr.bin/vi/README
index a33bfc6f04c3..e46f4de58bd1 100644
--- a/usr.bin/vi/README
+++ b/usr.bin/vi/README
@@ -1,12 +1,13 @@
-# @(#)README 8.40 (Berkeley) 1/12/94
+# @(#)README 8.54 (Berkeley) 3/24/94
-This is the README for version 1.01 of nvi, a freely redistributable
-replacement for the vi and ex text editors. It can be retrieved via
-anonymous ftp from ftp.uu.net, or from ftp.cs.berkeley.edu. In the
-latter, it is in the directory ucb/4bsd, and is named nvi.tar.Z.
+This is the README for version 1.11 of nex/nvi, a freely redistributable
+replacement for the Berkeley ex and vi text editors. The compressed tar
+archive can be retrieved by anonymous ftp from ftp.cs.berkeley.edu, from
+the file ucb/4bsd/nvi.tar.Z. There is a gzip'd tar archive, nvi.tar.z,
+in the same directory.
-If you have any questions or problems with nvi, please send them to
-me by electronic mail at one of the following addresses:
+If you have any questions about nvi, or problems making it work, please
+contact me by electronic mail at one of the following addresses:
uunet!bostic
bostic@cs.berkeley.edu
@@ -16,12 +17,12 @@ Keith Bostic
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
o Redistribution:
-Nvi is copyrighted by the The Regents of the University of California,
-but may be freely redistributed (or used to line your birdcage) under
-the following conditions:
+This software is copyrighted by the The Regents of the University of
+California, but may be freely redistributed (or sold, or used to line
+your birdcage) under the following conditions:
/*-
- * Copyright (c) 1994
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,99 +78,82 @@ o From the original vi acknowledgements, by William Joy and Mark Horton:
work on a large number of terminals and Unix systems.
o And...
-
The financial support of UUNET Communications Services is gratefully
acknowledged.
=-=-=-=-=-=-=-=-=-=-=
-o Comments:
-
-This software is beta software, although it's pretty stable. Almost
-of the necessary functionality for ex/vi is in it, the only missing
-pieces are fairly obscure.
+o Status:
-Code fixes are very much appreciated, of course, but if you can't
-provide them, please send me as much information as you can as to how
-to reproduce the bug, and I'll try to fix it here. In particular, the
-screen routines are nasty stuff, and you probably don't want to mess
-with them. Stack traces of core dumps are sometimes helpful, but an
-example file with a set of keystrokes that causes the problem is far
-better.
+This software is in beta test, and it's believed to be pretty stable.
+Almost all of the historic functionality in ex/vi is there, the missing
+pieces are fairly obscure. In particular, the edcompatible, hardtabs*,
+lisp*, optimize*, redraw*, and slowopen* options are recognized, but not
+implemented.
Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left in
during initial development to make things easier. Wide character support
will be integrated at the same time it is made fully 8-bit clean.
-=-=-=-=-=-=-=-=-=-=-=
-o New features:
-
There aren't a lot of new features in nex/nvi, but there are a few things
-you might like:
-
- o 8-bit clean data, practically infinite lines/files.
- ^Vx[0-9A-Fa-f]* in input mode will insert any
- legal character value.
- o Split screens:
- :sp[lit] [file ...] splits the screen.
- ^W switches between screens.
- :resize count grows/shrinks the current screen.
- o Background/foreground screens
- :bg backgrounds the current screen.
- :di[splay] s[creens] lists the hidden screens.
- :fg [file] foregrounds the specified (or next) screen.
- o Shell screens:
- :sc[ript] [file ...] runs a shell in the screen.
- Carriage return sends a line to the shell.
- o Buffer, screens, tags display:
- :di[splay] b[uffers] displays the current cut buffers.
- :di[splay] s[creens] displays the hidden screen names.
- :di[splay] t[ags] displays the current tags stack.
- o Tag stacks:
- ^T returns to previous tag location.
- :tagpop [number | file] returns to previous tag location,
- or, optionally tag #N, or the tag in a specific file.
- :tagtop returns to first tag location.
- o Infinite undo:
- A '.' command immediately after a 'u' command continues
- either forward or backward depending on whether the 'u'
- command was an undo or a redo.
- o Usage information:
- :exu[sage] [cmd] for ex commands.
- :viu[sage] [key] for vi commands.
- :help
- o Extended RE expressions:
- :set extended turns on extended RE's, so you can
- do "/in|or" and search for the next occurrence of
- more than one expression.
- o Word search:
- ^A searches for the word referenced by the cursor.
- o Number increment:
- # increments the number referenced by the cursor.
- o Previous file:
- :prev[ious][!] edits the previous file from the
- argument list.
+you might like. See the "ADDITIONAL FEATURES" section of the manual page
+(docs/vi.0.txt, docs/vi.0.ps) for a list.
=-=-=-=-=-=-=-=-=-=-=
o Porting information:
-The directory PORT has directories per machine/OS combination, with
-V7-style Makefiles which build nvi. See the file PORT/README for
-more detailed information.
+The directory PORT has directories per OS/machine combination, with
+V7-style Makefiles which build nex/nvi. See the file PORT/README for
+detailed information.
=-=-=-=-=-=-=-=-=-=-=
-o Directories:
+o Bug reports:
+
+Code fixes are appreciated, of course, but if you can't provide them,
+please email me as much information as you can as to how to reproduce
+the bug, and I'll try to fix it locally. In particular, the screen
+routines are nasty stuff, and you probably don't want to mess with them.
+Stack traces of core dumps are sometimes helpful, but an example file
+with a set of keystrokes that causes the problem is far better. Also,
+make sure that you include the dimensions of the screen on which the
+problem occurred, your startup files (.exrc, .nexrc), and the environment
+variable (EXINIT, NEXINIT) values.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Layout:
+
+nvi:
+ Source files for pieces of code that are shared by all the
+ editors, like searching and logging code or code translating
+ line numbers into requests to the dbopen(3) database code.
+ It also has the code for adding, deleting, and changing "records"
+ in the underlying database.
-The main directory, nvi, contains source files for pieces of code that
-are shared by all the editors, like searching and logging code or code
-translating line numbers into requests to the dbopen(3) database code.
-It also has the code for adding, deleting, and changing "records" in
-the underlying database.
+nvi/PORT:
+ Porting directories, one per OS/architecture combination. See
+ nvi/PORT/README for porting information.
nvi/docs:
- The nvi/docs directory has technical information about data
- structures and some of the trickier parts of vi like quoting,
- key mapping, input queues, and executing buffers, and a
- description of how nvi does edit session recovery.
+ The nvi/docs directory has all of the nvi documentation:
+
+ README -- Nvi main README file.
+ USD.doc -- Historic vi documentation (in roff source form).
+ bugs.current -- Known bugs in the current nvi implementation.
+ changelog -- Log of changes from version to version.
+ features -- Todo list, suggested features list.
+ internals/
+ autowrite -- Vi autowrite option discussion.
+ gdb.script -- GDB debugging scripts.
+ input -- Vi maps, executable buffers, and input discussion.
+ quoting -- Vi quoting discussion.
+ structures -- Nvi internal structure description.
+ spell.ok -- Misspellings list for README, vi.1.
+ tutorial -- Historic vi tutorial
+ vi.0.ps -- PostScript of vi.1.
+ vi.0.txt -- Flat text of vi.1.
+ vi.1 -- Nvi man page (in roff source form).
+ vi.ref -- Nvi reference (in roff source form).
+ vi.ref.ps -- PostScript of vi.ref.
+ vi.ref.txt -- Flat text of vi.ref.
nvi/ex:
The nvi/ex directory is the ex source code. Because vi has the
diff --git a/usr.bin/vi/args.h b/usr.bin/vi/args.h
index 4d437442d866..01ce4cec831d 100644
--- a/usr.bin/vi/args.h
+++ b/usr.bin/vi/args.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)args.h 8.3 (Berkeley) 12/19/93
+ * @(#)args.h 8.4 (Berkeley) 3/16/94
*/
/*
diff --git a/usr.bin/vi/ascii.c b/usr.bin/vi/ascii.c
index 7a7102574165..9f6089b93563 100644
--- a/usr.bin/vi/ascii.c
+++ b/usr.bin/vi/ascii.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,44 +32,55 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ascii.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)ascii.c 8.7 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
CHNAME const asciiname[UCHAR_MAX + 1] = {
{"^@", 2}, {"^A", 2}, {"^B", 2}, {"^C", 2},
- {"^D", 2}, {"^E", 2}, {"^F", 2}, {"^G", 2},
+ {"^D", 2}, {"^E", 2}, {"^F", 2}, {"^G", 2},
{"^H", 2}, {"^I", 2}, {"^J", 2}, {"^K", 2},
- {"^L", 2}, {"^M", 2}, {"^N", 2}, {"^O", 2},
+ {"^L", 2}, {"^M", 2}, {"^N", 2}, {"^O", 2},
{"^P", 2}, {"^Q", 2}, {"^R", 2}, {"^S", 2},
- {"^T", 2}, {"^U", 2}, {"^V", 2}, {"^W", 2},
+ {"^T", 2}, {"^U", 2}, {"^V", 2}, {"^W", 2},
{"^X", 2}, {"^Y", 2}, {"^Z", 2}, {"^[", 2},
- {"^\\", 2}, {"^]", 2}, {"^^", 2}, {"^_", 2},
+ {"^\\", 2}, {"^]", 2}, {"^^", 2}, {"^_", 2},
{" ", 1}, {"!", 1}, {"\"", 1}, {"#", 1},
- {"$", 1}, {"%", 1}, {"&", 1}, {"'", 1},
+ {"$", 1}, {"%", 1}, {"&", 1}, {"'", 1},
{"(", 1}, {")", 1}, {"*", 1}, {"+", 1},
- {",", 1}, {"-", 1}, {".", 1}, {"/", 1},
+ {",", 1}, {"-", 1}, {".", 1}, {"/", 1},
{"0", 1}, {"1", 1}, {"2", 1}, {"3", 1},
- {"4", 1}, {"5", 1}, {"6", 1}, {"7", 1},
+ {"4", 1}, {"5", 1}, {"6", 1}, {"7", 1},
{"8", 1}, {"9", 1}, {":", 1}, {";", 1},
- {"<", 1}, {"=", 1}, {">", 1}, {"?", 1},
+ {"<", 1}, {"=", 1}, {">", 1}, {"?", 1},
{"@", 1}, {"A", 1}, {"B", 1}, {"C", 1},
- {"D", 1}, {"E", 1}, {"F", 1}, {"G", 1},
+ {"D", 1}, {"E", 1}, {"F", 1}, {"G", 1},
{"H", 1}, {"I", 1}, {"J", 1}, {"K", 1},
- {"L", 1}, {"M", 1}, {"N", 1}, {"O", 1},
+ {"L", 1}, {"M", 1}, {"N", 1}, {"O", 1},
{"P", 1}, {"Q", 1}, {"R", 1}, {"S", 1},
- {"T", 1}, {"U", 1}, {"V", 1}, {"W", 1},
+ {"T", 1}, {"U", 1}, {"V", 1}, {"W", 1},
{"X", 1}, {"Y", 1}, {"Z", 1}, {"[", 1},
- {"\\", 1}, {"]", 1}, {"^", 1}, {"_", 1},
+ {"\\", 1}, {"]", 1}, {"^", 1}, {"_", 1},
{"`", 1}, {"a", 1}, {"b", 1}, {"c", 1},
- {"d", 1}, {"e", 1}, {"f", 1}, {"g", 1},
+ {"d", 1}, {"e", 1}, {"f", 1}, {"g", 1},
{"h", 1}, {"i", 1}, {"j", 1}, {"k", 1},
- {"l", 1}, {"m", 1}, {"n", 1}, {"o", 1},
+ {"l", 1}, {"m", 1}, {"n", 1}, {"o", 1},
{"p", 1}, {"q", 1}, {"r", 1}, {"s", 1},
- {"t", 1}, {"u", 1}, {"v", 1}, {"w", 1},
+ {"t", 1}, {"u", 1}, {"v", 1}, {"w", 1},
{"x", 1}, {"y", 1}, {"z", 1}, {"{", 1},
{"|", 1}, {"}", 1}, {"~", 1}, {"^?", 2},
{"0x80", 4}, {"0x81", 4}, {"0x82", 4}, {"0x83", 4},
@@ -80,30 +91,30 @@ CHNAME const asciiname[UCHAR_MAX + 1] = {
{"0x94", 4}, {"0x95", 4}, {"0x96", 4}, {"0x97", 4},
{"0x98", 4}, {"0x99", 4}, {"0x9a", 4}, {"0x9b", 4},
{"0x9c", 4}, {"0x9d", 4}, {"0x9e", 4}, {"0x9f", 4},
- {"\xa0", 1}, {"\xa1", 1}, {"\xa2", 1}, {"\xa3", 1},
- {"\xa4", 1}, {"\xa5", 1}, {"\xa6", 1}, {"\xa7", 1},
- {"\xa8", 1}, {"\xa9", 1}, {"\xaa", 1}, {"\xab", 1},
- {"\xac", 1}, {"\xad", 1}, {"\xae", 1}, {"\xaf", 1},
- {"\xb0", 1}, {"\xb1", 1}, {"\xb2", 1}, {"\xb3", 1},
- {"\xb4", 1}, {"\xb5", 1}, {"\xb6", 1}, {"\xb7", 1},
- {"\xb8", 1}, {"\xb9", 1}, {"\xba", 1}, {"\xbb", 1},
- {"\xbc", 1}, {"\xbd", 1}, {"\xbe", 1}, {"\xbf", 1},
- {"\xc0", 1}, {"\xc1", 1}, {"\xc2", 1}, {"\xc3", 1},
- {"\xc4", 1}, {"\xc5", 1}, {"\xc6", 1}, {"\xc7", 1},
- {"\xc8", 1}, {"\xc9", 1}, {"\xca", 1}, {"\xcb", 1},
- {"\xcc", 1}, {"\xcd", 1}, {"\xce", 1}, {"\xcf", 1},
- {"\xd0", 1}, {"\xd1", 1}, {"\xd2", 1}, {"\xd3", 1},
- {"\xd4", 1}, {"\xd5", 1}, {"\xd6", 1}, {"\xd7", 1},
- {"\xd8", 1}, {"\xd9", 1}, {"\xda", 1}, {"\xdb", 1},
- {"\xdc", 1}, {"\xdd", 1}, {"\xde", 1}, {"\xdf", 1},
- {"\xe0", 1}, {"\xe1", 1}, {"\xe2", 1}, {"\xe3", 1},
- {"\xe4", 1}, {"\xe5", 1}, {"\xe6", 1}, {"\xe7", 1},
- {"\xe8", 1}, {"\xe9", 1}, {"\xea", 1}, {"\xeb", 1},
- {"\xec", 1}, {"\xed", 1}, {"\xee", 1}, {"\xef", 1},
- {"\xf0", 1}, {"\xf1", 1}, {"\xf2", 1}, {"\xf3", 1},
- {"\xf4", 1}, {"\xf5", 1}, {"\xf6", 1}, {"\xf7", 1},
- {"\xf8", 1}, {"\xf9", 1}, {"\xfa", 1}, {"\xfb", 1},
- {"\xfc", 1}, {"\xfd", 1}, {"\xfe", 1}, {"\xff", 1},
+ {"0xa0", 4}, {"0xa1", 4}, {"0xa2", 4}, {"0xa3", 4},
+ {"0xa4", 4}, {"0xa5", 4}, {"0xa6", 4}, {"0xa7", 4},
+ {"0xa8", 4}, {"0xa9", 4}, {"0xaa", 4}, {"0xab", 4},
+ {"0xac", 4}, {"0xad", 4}, {"0xae", 4}, {"0xaf", 4},
+ {"0xb0", 4}, {"0xb1", 4}, {"0xb2", 4}, {"0xb3", 4},
+ {"0xb4", 4}, {"0xb5", 4}, {"0xb6", 4}, {"0xb7", 4},
+ {"0xb8", 4}, {"0xb9", 4}, {"0xba", 4}, {"0xbb", 4},
+ {"0xbc", 4}, {"0xbd", 4}, {"0xbe", 4}, {"0xbf", 4},
+ {"0xc0", 4}, {"0xc1", 4}, {"0xc2", 4}, {"0xc3", 4},
+ {"0xc4", 4}, {"0xc5", 4}, {"0xc6", 4}, {"0xc7", 4},
+ {"0xc8", 4}, {"0xc9", 4}, {"0xca", 4}, {"0xcb", 4},
+ {"0xcc", 4}, {"0xcd", 4}, {"0xce", 4}, {"0xcf", 4},
+ {"0xd0", 4}, {"0xd1", 4}, {"0xd2", 4}, {"0xd3", 4},
+ {"0xd4", 4}, {"0xd5", 4}, {"0xd6", 4}, {"0xd7", 4},
+ {"0xd8", 4}, {"0xd9", 4}, {"0xda", 4}, {"0xdb", 4},
+ {"0xdc", 4}, {"0xdd", 4}, {"0xde", 4}, {"0xdf", 4},
+ {"0xe0", 4}, {"0xe1", 4}, {"0xe2", 4}, {"0xe3", 4},
+ {"0xe4", 4}, {"0xe5", 4}, {"0xe6", 4}, {"0xe7", 4},
+ {"0xe8", 4}, {"0xe9", 4}, {"0xea", 4}, {"0xeb", 4},
+ {"0xec", 4}, {"0xed", 4}, {"0xee", 4}, {"0xef", 4},
+ {"0xf0", 4}, {"0xf1", 4}, {"0xf2", 4}, {"0xf3", 4},
+ {"0xf4", 4}, {"0xf5", 4}, {"0xf6", 4}, {"0xf7", 4},
+ {"0xf8", 4}, {"0xf9", 4}, {"0xfa", 4}, {"0xfb", 4},
+ {"0xfc", 4}, {"0xfd", 4}, {"0xfe", 4}, {"0xff", 4},
};
char *
diff --git a/usr.bin/vi/compat.h b/usr.bin/vi/compat.h
new file mode 100644
index 000000000000..bea07ad84259
--- /dev/null
+++ b/usr.bin/vi/compat.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * 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.
+ *
+ * @(#)compat.h 8.16 (Berkeley) 3/8/94
+ */
+
+#ifndef _COMPAT_H_
+#define _COMPAT_H_
+
+#include <sys/types.h>
+
+/*
+ * If your system doesn't typedef the following basic integral types,
+ * change the 0 to a 1, and change the values as necessary.
+ */
+typedef char int8_t;
+typedef unsigned char u_int8_t;
+typedef short int16_t;
+typedef unsigned short u_int16_t;
+typedef int int32_t;
+typedef unsigned int u_int32_t;
+#ifdef WE_DONT_NEED_QUADS
+typedef long long int64_t;
+typedef unsigned long long u_int64_t;
+#endif
+
+#endif /* !_COMPAT_H_ */
diff --git a/usr.bin/vi/cut.c b/usr.bin/vi/cut.c
index 5a9b292ce175..a4e277a10228 100644
--- a/usr.bin/vi/cut.c
+++ b/usr.bin/vi/cut.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)cut.c 8.20 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)cut.c 8.26 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
-static int cb_line __P((SCR *, EXF *, recno_t, size_t, size_t, TEXT **));
+static int cb_line __P((SCR *, EXF *, recno_t, size_t, size_t, CB *));
static int cb_rotate __P((SCR *));
-/*
+/*
* cut --
* Put a range of lines/columns into a buffer.
*
@@ -57,7 +67,7 @@ static int cb_rotate __P((SCR *));
* default buffer storage. There is a pointer, too, which is the current
* default buffer, i.e. it may point to the default buffer or a named buffer
* depending on into what buffer the last text was cut. In both delete and
- * yank operations, text is cut into either the buffer named by the user, or
+ * yank operations, text is cut into either the buffer named by the user or
* the default buffer. If it's a delete of information on more than a single
* line, the contents of the numbered buffers are rotated up one, the contents
* of the buffer named '9' are discarded, and the text is also cut into the
@@ -68,14 +78,15 @@ static int cb_rotate __P((SCR *));
* of replaced.
*
* !!!
- * The contents of the default buffer would disappear after most operations in
- * historic vi. It's unclear that this is useful, so we don't bother.
+ * The contents of the default buffer would disappear after most operations
+ * in historic vi. It's unclear that this is useful, so we don't bother.
*
* When users explicitly cut text into the numeric buffers, historic vi became
* genuinely strange. I've never been able to figure out what was supposed to
* happen. It behaved differently if you deleted text than if you yanked text,
* and, in the latter case, the text was appended to the buffer instead of
- * replacing the contents. Hopefully it's not worth getting right.
+ * replacing the contents. Hopefully it's not worth getting right, and here
+ * we just treat the numeric buffers like any other named buffer.
*/
int
cut(sp, ep, cbp, namep, fm, tm, flags)
@@ -87,33 +98,26 @@ cut(sp, ep, cbp, namep, fm, tm, flags)
MARK *fm, *tm;
{
CHAR_T name;
- TEXT *tp;
recno_t lno;
- size_t len;
int append, namedbuffer, setdefcb;
-#if defined(DEBUG) && 0
- TRACE(sp, "cut: from {%lu, %d}, to {%lu, %d}%s\n",
- fm->lno, fm->cno, tm->lno, tm->cno,
- LF_ISSET(CUT_LINEMODE) ? " LINE MODE" : "");
-#endif
if (cbp == NULL) {
- if (LF_ISSET(CUT_DELETE) &&
- (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
- (void)cb_rotate(sp);
- name = '1';
- goto defcb;
- }
if (namep == NULL) {
+ if (LF_ISSET(CUT_DELETE) &&
+ (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
+ (void)cb_rotate(sp);
+ name = '1';
+ goto defcb;
+ }
cbp = sp->gp->dcb_store;
append = namedbuffer = 0;
- setdefcb = 1;
} else {
name = *namep;
defcb: CBNAME(sp, cbp, name);
append = isupper(name);
- namedbuffer = setdefcb = 1;
+ namedbuffer = 1;
}
+ setdefcb = 1;
} else
append = namedbuffer = setdefcb = 0;
@@ -135,45 +139,35 @@ defcb: CBNAME(sp, cbp, name);
cbp->flags = 0;
}
+#define ENTIRE_LINE 0
/* In line mode, it's pretty easy, just cut the lines. */
if (LF_ISSET(CUT_LINEMODE)) {
- for (lno = fm->lno; lno <= tm->lno; ++lno) {
- if (cb_line(sp, ep, lno, 0, 0, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
- }
cbp->flags |= CB_LMODE;
+ for (lno = fm->lno; lno <= tm->lno; ++lno)
+ if (cb_line(sp, ep, lno, 0, 0, cbp))
+ goto cb_line_fail;
} else {
- /* Get the first line. */
- len = fm->lno < tm->lno ? 0 : tm->cno - fm->cno;
- if (cb_line(sp, ep, fm->lno, fm->cno, len, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
+ /*
+ * Get the first line. A length of 0 causes cb_line
+ * to cut from the MARK to the end of the line.
+ */
+ if (cb_line(sp, ep, fm->lno, fm->cno,
+ fm->lno != tm->lno ? ENTIRE_LINE : (tm->cno - fm->cno) + 1,
+ cbp))
+ goto cb_line_fail;
/* Get the intermediate lines. */
- for (lno = fm->lno; ++lno < tm->lno;) {
- if (cb_line(sp, ep, lno, 0, 0, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
- }
+ for (lno = fm->lno; ++lno < tm->lno;)
+ if (cb_line(sp, ep, lno, 0, ENTIRE_LINE, cbp))
+ goto cb_line_fail;
/* Get the last line. */
- if (tm->lno > fm->lno && tm->cno > 0) {
- if (cb_line(sp, ep, lno, 0, tm->cno, &tp)) {
-mem: if (append)
- msgq(sp, M_ERR,
- "Contents of %s buffer lost.",
- charname(sp, name));
- text_lfree(&cbp->textq);
- cbp->len = 0;
- cbp->flags = 0;
- return (1);
- }
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
+ if (tm->lno != fm->lno &&
+ cb_line(sp, ep, lno, 0, tm->cno + 1, cbp)) {
+cb_line_fail: text_lfree(&cbp->textq);
+ cbp->len = 0;
+ cbp->flags = 0;
+ return (1);
}
}
if (setdefcb)
@@ -235,28 +229,30 @@ cb_rotate(sp)
* Cut a portion of a single line.
*/
static int
-cb_line(sp, ep, lno, fcno, clen, newp)
+cb_line(sp, ep, lno, fcno, clen, cbp)
SCR *sp;
EXF *ep;
recno_t lno;
size_t fcno, clen;
- TEXT **newp;
+ CB *cbp;
{
TEXT *tp;
size_t len;
char *p;
+ /* Get the line. */
if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
GETLINE_ERR(sp, lno);
return (1);
}
- if ((*newp = tp = text_init(sp, NULL, 0, len)) == NULL)
+ /* Create a TEXT structure that can hold the entire line. */
+ if ((tp = text_init(sp, NULL, 0, len)) == NULL)
return (1);
/*
- * A length of zero means to cut from the MARK to the end
- * of the line.
+ * If the line isn't empty and it's not the entire line,
+ * copy the portion we want, and reset the TEXT length.
*/
if (len != 0) {
if (clen == 0)
@@ -264,6 +260,11 @@ cb_line(sp, ep, lno, fcno, clen, newp)
memmove(tp->lb, p + fcno, clen);
tp->len = clen;
}
+
+ /* Append to the end of the cut buffer. */
+ CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
+ cbp->len += tp->len;
+
return (0);
}
@@ -279,11 +280,11 @@ text_init(sp, p, len, total_len)
{
TEXT *tp;
- MALLOC(sp, tp, TEXT *, sizeof(TEXT));
+ CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT));
if (tp == NULL)
return (NULL);
/* ANSI C doesn't define a call to malloc(2) for 0 bytes. */
- if (tp->lb_len = total_len) {
+ if ((tp->lb_len = total_len) != 0) {
MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
if (tp->lb == NULL) {
free(tp);
@@ -291,12 +292,8 @@ text_init(sp, p, len, total_len)
}
if (p != NULL && len != 0)
memmove(tp->lb, p, len);
- } else
- tp->lb = NULL;
+ }
tp->len = len;
- tp->ai = tp->insert = tp->offset = tp->owrite = 0;
- tp->wd = NULL;
- tp->wd_len = 0;
return (tp);
}
@@ -330,197 +327,3 @@ text_free(tp)
FREE(tp->wd, tp->wd_len);
FREE(tp, sizeof(TEXT));
}
-
-/*
- * put --
- * Put text buffer contents into the file.
- *
- * !!!
- * Historically, pasting into a file with no lines in vi would preserve
- * the single blank line. This is almost certainly a result of the fact
- * that historic vi couldn't deal with a file that had no lines in it.
- * This implementation treats that as a bug, and does not retain the
- * blank line.
- */
-int
-put(sp, ep, cbp, namep, cp, rp, append)
- SCR *sp;
- EXF *ep;
- CB *cbp;
- CHAR_T *namep;
- MARK *cp, *rp;
- int append;
-{
- CHAR_T name;
- TEXT *ltp, *tp;
- recno_t lno;
- size_t blen, clen, len;
- char *bp, *p, *t;
-
- if (cbp == NULL)
- if (namep == NULL) {
- cbp = sp->gp->dcbp;
- if (cbp == NULL) {
- msgq(sp, M_ERR, "The default buffer is empty.");
- return (1);
- }
- } else {
- name = *namep;
- CBNAME(sp, cbp, name);
- if (cbp == NULL) {
- msgq(sp, M_ERR,
- "Buffer %s is empty.", charname(sp, name));
- return (1);
- }
- }
- tp = cbp->textq.cqh_first;
-
- /*
- * It's possible to do a put into an empty file, meaning that the
- * cut buffer simply becomes the file. It's a special case so
- * that we can ignore it in general.
- *
- * Historical practice is that the cursor ends up on the first
- * non-blank character of the first line inserted.
- */
- if (cp->lno == 1) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0) {
- for (; tp != (void *)&cbp->textq;
- ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- return (1);
- rp->lno = 1;
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- goto ret;
- }
- }
-
- /* If a line mode buffer, append each new line into the file. */
- if (F_ISSET(cbp, CB_LMODE)) {
- lno = append ? cp->lno : cp->lno - 1;
- rp->lno = lno + 1;
- for (; tp != (void *)&cbp->textq; ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- return (1);
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- goto ret;
- }
-
- /*
- * If buffer was cut in character mode, replace the current line with
- * one built from the portion of the first line to the left of the
- * split plus the first line in the CB. Append each intermediate line
- * in the CB. Append a line built from the portion of the first line
- * to the right of the split plus the last line in the CB.
- *
- * Get the first line.
- */
- lno = cp->lno;
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- GET_SPACE_RET(sp, bp, blen, tp->len + len + 1);
- t = bp;
-
- /* Original line, left of the split. */
- if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
- memmove(bp, p, clen);
- p += clen;
- t += clen;
- }
-
- /* First line from the CB. */
- memmove(t, tp->lb, tp->len);
- t += tp->len;
-
- /* Calculate length left in original line. */
- clen = len ? len - cp->cno - (append ? 1 : 0) : 0;
-
- /*
- * If no more lines in the CB, append the rest of the original
- * line and quit. Otherwise, build the last line before doing
- * the intermediate lines, because the line changes will lose
- * the cached line.
- */
- if (tp->q.cqe_next == (void *)&cbp->textq) {
- /*
- * Historical practice is that if a non-line mode put
- * is inside a single line, the cursor ends up on the
- * last character inserted.
- */
- rp->lno = lno;
- rp->cno = (t - bp) - 1;
-
- if (clen > 0) {
- memmove(t, p, clen);
- t += clen;
- }
- if (file_sline(sp, ep, lno, bp, t - bp))
- goto mem;
- } else {
- /*
- * Have to build both the first and last lines of the
- * put before doing any sets or we'll lose the cached
- * line. Build both the first and last lines in the
- * same buffer, so we don't have to have another buffer
- * floating around.
- *
- * Last part of original line; check for space, reset
- * the pointer into the buffer.
- */
- ltp = cbp->textq.cqh_last;
- len = t - bp;
- ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
- t = bp + len;
-
- /* Add in last part of the CB. */
- memmove(t, ltp->lb, ltp->len);
- if (clen)
- memmove(t + ltp->len, p, clen);
- clen += ltp->len;
-
- /*
- * Now: bp points to the first character of the first
- * line, t points to the last character of the last
- * line, t - bp is the length of the first line, and
- * clen is the length of the last. Just figured you'd
- * want to know.
- *
- * Output the line replacing the original line.
- */
- if (file_sline(sp, ep, lno, bp, t - bp))
- goto mem;
-
- /*
- * Historical practice is that if a non-line mode put
- * covers multiple lines, the cursor ends up on the
- * first character inserted. (Of course.)
- */
- rp->lno = lno;
- rp->cno = (t - bp) - 1;
-
- /* Output any intermediate lines in the CB. */
- for (tp = tp->q.cqe_next;
- tp->q.cqe_next != (void *)&cbp->textq;
- ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- goto mem;
-
- if (file_aline(sp, ep, 1, lno, t, clen)) {
-mem: FREE_SPACE(sp, bp, blen);
- return (1);
- }
- }
- FREE_SPACE(sp, bp, blen);
-
- /* Reporting... */
-ret: sp->rptlines[L_PUT] += lno - cp->lno;
-
- return (0);
-}
diff --git a/usr.bin/vi/cut.h b/usr.bin/vi/cut.h
index 8ade88f05633..7be20b77ffbd 100644
--- a/usr.bin/vi/cut.h
+++ b/usr.bin/vi/cut.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)cut.h 8.11 (Berkeley) 1/11/94
+ * @(#)cut.h 8.13 (Berkeley) 3/16/94
*/
typedef struct _texth TEXTH; /* TEXT list head structure. */
@@ -46,7 +46,7 @@ struct _cb {
#define CB_LMODE 0x01 /* Cut was in line mode. */
u_char flags;
};
-
+
/* Lines/blocks of text. */
struct _text { /* Text: a linked list of lines. */
CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */
diff --git a/usr.bin/vi/delete.c b/usr.bin/vi/delete.c
index e8c0a5d80e1f..4a46ba75d9eb 100644
--- a/usr.bin/vi/delete.c
+++ b/usr.bin/vi/delete.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)delete.c 8.7 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)delete.c 8.9 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
@@ -59,10 +69,6 @@ delete(sp, ep, fm, tm, lmode)
char *bp, *p;
int eof;
-#if defined(DEBUG) && 0
- TRACE(sp, "delete: from %lu/%d to %lu/%d%s\n",
- fm->lno, fm->cno, tm->lno, tm->cno, lmode ? " (LINE MODE)" : "");
-#endif
bp = NULL;
/* Case 1 -- delete in line mode. */
@@ -113,9 +119,11 @@ delete(sp, ep, fm, tm, lmode)
return (1);
}
GET_SPACE_RET(sp, bp, blen, len);
- memmove(bp, p, fm->cno);
- memmove(bp + fm->cno, p + tm->cno, len - tm->cno);
- if (file_sline(sp, ep, fm->lno, bp, len - (tm->cno - fm->cno)))
+ if (fm->cno != 0)
+ memmove(bp, p, fm->cno);
+ memmove(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1));
+ if (file_sline(sp, ep, fm->lno,
+ bp, len - ((tm->cno - fm->cno) + 1)))
goto err;
goto done;
}
@@ -162,8 +170,8 @@ delete(sp, ep, fm, tm, lmode)
GETLINE_ERR(sp, tm->lno);
goto err;
}
- memmove(bp + tlen, p + tm->cno, len - tm->cno);
- tlen += len - tm->cno;
+ memmove(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
+ tlen += len - (tm->cno + 1);
/* Set the current line. */
if (file_sline(sp, ep, fm->lno, bp, tlen))
diff --git a/usr.bin/vi/docs/README b/usr.bin/vi/docs/README
new file mode 100644
index 000000000000..e46f4de58bd1
--- /dev/null
+++ b/usr.bin/vi/docs/README
@@ -0,0 +1,177 @@
+# @(#)README 8.54 (Berkeley) 3/24/94
+
+This is the README for version 1.11 of nex/nvi, a freely redistributable
+replacement for the Berkeley ex and vi text editors. The compressed tar
+archive can be retrieved by anonymous ftp from ftp.cs.berkeley.edu, from
+the file ucb/4bsd/nvi.tar.Z. There is a gzip'd tar archive, nvi.tar.z,
+in the same directory.
+
+If you have any questions about nvi, or problems making it work, please
+contact me by electronic mail at one of the following addresses:
+
+ uunet!bostic
+ bostic@cs.berkeley.edu
+
+Keith Bostic
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+o Redistribution:
+
+This software is copyrighted by the The Regents of the University of
+California, but may be freely redistributed (or sold, or used to line
+your birdcage) under the following conditions:
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * 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.
+ */
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+o Credit where it's due:
+
+ This software was originally derived from software contributed
+ to the University of California, Berkeley by Steve Kirkendall,
+ the author of the vi clone elvis. Without his work, this work
+ would have been far more difficult.
+
+ POSIX 1003.2 style regular expression support is courtesy of
+ Henry Spencer, for which I am *very* grateful.
+
+ The curses library was originally done by Ken Arnold. Scrolling
+ and general reworking for 4.4BSD was done by Elan Amir.
+
+o From the original vi acknowledgements, by William Joy and Mark Horton:
+
+ Bruce Englar encouraged the early development of this display
+ editor. Peter Kessler helped bring sanity to version 2's
+ command layout. Bill Joy wrote versions 1 and 2.0 through 2.7,
+ and created the framework that users see in the present editor.
+ Mark Horton added macros and other features and made the editor
+ work on a large number of terminals and Unix systems.
+
+o And...
+ The financial support of UUNET Communications Services is gratefully
+ acknowledged.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Status:
+
+This software is in beta test, and it's believed to be pretty stable.
+Almost all of the historic functionality in ex/vi is there, the missing
+pieces are fairly obscure. In particular, the edcompatible, hardtabs*,
+lisp*, optimize*, redraw*, and slowopen* options are recognized, but not
+implemented.
+
+Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left in
+during initial development to make things easier. Wide character support
+will be integrated at the same time it is made fully 8-bit clean.
+
+There aren't a lot of new features in nex/nvi, but there are a few things
+you might like. See the "ADDITIONAL FEATURES" section of the manual page
+(docs/vi.0.txt, docs/vi.0.ps) for a list.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Porting information:
+
+The directory PORT has directories per OS/machine combination, with
+V7-style Makefiles which build nex/nvi. See the file PORT/README for
+detailed information.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Bug reports:
+
+Code fixes are appreciated, of course, but if you can't provide them,
+please email me as much information as you can as to how to reproduce
+the bug, and I'll try to fix it locally. In particular, the screen
+routines are nasty stuff, and you probably don't want to mess with them.
+Stack traces of core dumps are sometimes helpful, but an example file
+with a set of keystrokes that causes the problem is far better. Also,
+make sure that you include the dimensions of the screen on which the
+problem occurred, your startup files (.exrc, .nexrc), and the environment
+variable (EXINIT, NEXINIT) values.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Layout:
+
+nvi:
+ Source files for pieces of code that are shared by all the
+ editors, like searching and logging code or code translating
+ line numbers into requests to the dbopen(3) database code.
+ It also has the code for adding, deleting, and changing "records"
+ in the underlying database.
+
+nvi/PORT:
+ Porting directories, one per OS/architecture combination. See
+ nvi/PORT/README for porting information.
+
+nvi/docs:
+ The nvi/docs directory has all of the nvi documentation:
+
+ README -- Nvi main README file.
+ USD.doc -- Historic vi documentation (in roff source form).
+ bugs.current -- Known bugs in the current nvi implementation.
+ changelog -- Log of changes from version to version.
+ features -- Todo list, suggested features list.
+ internals/
+ autowrite -- Vi autowrite option discussion.
+ gdb.script -- GDB debugging scripts.
+ input -- Vi maps, executable buffers, and input discussion.
+ quoting -- Vi quoting discussion.
+ structures -- Nvi internal structure description.
+ spell.ok -- Misspellings list for README, vi.1.
+ tutorial -- Historic vi tutorial
+ vi.0.ps -- PostScript of vi.1.
+ vi.0.txt -- Flat text of vi.1.
+ vi.1 -- Nvi man page (in roff source form).
+ vi.ref -- Nvi reference (in roff source form).
+ vi.ref.ps -- PostScript of vi.ref.
+ vi.ref.txt -- Flat text of vi.ref.
+
+nvi/ex:
+ The nvi/ex directory is the ex source code. Because vi has the
+ colon command, lots of this code is used by vi. Generally, if
+ functionality is shared by both ex and vi, it's in nvi/ex, if
+ it's vi only, it's in nvi/vi. Files are generally named by the
+ command(s) they support, but occasionally with a name that
+ describes their functionality.
+
+nvi/sex:
+ The nvi/sex directory is the screen support for the ex editor.
+
+nvi/svi:
+ The nvi/svi directory is the screen support for a curses based
+ vi editor.
+
+nvi/vi:
+ The nvi/vi directory is the vi source code.
+
+nvi/xaw:
+ Place reserved for an X11 (Athena Widget) screen.
diff --git a/usr.bin/vi/docs/USD.doc/edit/Makefile b/usr.bin/vi/docs/USD.doc/edit/Makefile
new file mode 100644
index 000000000000..e9b8d3c5610a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/Makefile
@@ -0,0 +1,18 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/11.edit
+SRCS= edittut.ms
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+# index for versatec is different from the one in edit.tut
+# because the fonts are different and entries reference page
+# rather than section numbers. if you have a typesetter
+# you should just use the index in edit.tut, and ignore editvindex.
+
+editvindex:
+ ${TROFF} ${MACROS} -n22 edit.vindex
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/edit/edit.vindex b/usr.bin/vi/docs/USD.doc/edit/edit.vindex
new file mode 100644
index 000000000000..2098f14ea190
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/edit.vindex
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)edit.vindex 8.1 (Berkeley) 6/8/93
+.\"
+.bd I
+.ND
+.TL
+Index
+.sp 3
+.2C
+.nf
+addressing, \fIsee\fR line numbers
+append mode, 4
+backslash (\\), 18
+buffer, 2
+command mode, 4
+context search, 8, 10, 13, 18
+control characters (``^'' notation), 8
+control-d, 6
+current filename, 19, 20
+current line (.), 9, 15
+diagnostic messages, 4
+disk, 2
+documentation, 21
+edit (to begin editing session), 3, 7
+editing commands:
+.in +2
+append (a), 4, 7
+change (c), 16
+copy (co), 13
+delete (d), 13-14
+edit (e), 12
+file (f), 19
+global (g), 18-19
+move (m), 12-13
+number (nu), 9
+preserve (pre), 20-21
+print (p), 8
+quit (q), 5, 11
+quit! (q!), 11
+read (r), 20
+recover (rec), 20
+substitute (s), 9-10, 17, 18
+undo (u), 14, 17
+write (w), 5-6, 11, 19-20
+z, 11
+.sp 10i
+! (shell escape), 19
+$= , 15
++, 15
+\-, 15
+//, 8, 18
+??, 18
+\&\fB.\fR, 9, 15
+\&\fB.\fR=, 9, 15
+.in -2
+erasing
+.ti +2
+characters (#), 8
+.ti +2
+lines (@), 8
+ex (text editor), 21
+\fIEx Reference Manual\fR, 21
+file, 1
+file recovery, 20
+filename, 2
+Interrupt (message), 7
+line numbers, \fIsee also\fR current line
+.ti +2
+dollar sign ($), 8, 12-13, 15
+.ti +2
+dot (.), 9, 15
+.ti +2
+relative (+ and \-), 15, 16
+logging out, 6
+login procedure, 2
+``magic'' characters, 21
+non-printing characters, 8
+``not found'' (message), 3
+program, 1
+recovery \fIsee\fR file recovery
+shell, 18
+shell escape (!), 19
+special characters (^, $, \e), 18
+text input mode, 4
+UNIX, 1
diff --git a/usr.bin/vi/docs/USD.doc/edit/edittut.ms b/usr.bin/vi/docs/USD.doc/edit/edittut.ms
new file mode 100644
index 000000000000..5f4c28cb6d2a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/edittut.ms
@@ -0,0 +1,2322 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)edittut.ms 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:11-%''Edit: A Tutorial'
+.OH 'Edit: A Tutorial''USD:11-%'
+.LP
+.ds u \s-2UNIX\s0
+.ll 5i
+.nr LL 5i
+.ND
+.sp 4
+.ce
+\f3\s+2Edit: A Tutorial\s0\f1
+.sp
+.ce 3
+.I
+Ricki Blau
+.sp
+James Joyce
+.R
+.sp
+.ce 3
+Computing Services
+University of California
+Berkeley, California 94720
+.sp 3
+.ce
+.I
+ABSTRACT
+.R
+.sp
+.LP
+This narrative introduction to the use of the text editor
+.I edit
+assumes no prior familiarity with computers or with text editing.
+Its aim is to lead the beginning \s-2UNIX\(dg\s+2 user through the
+.FS
+\(dgUNIX is a trademark of Bell Laboratories.
+.FE
+fundamental steps of writing and revising a file of text.
+Edit,
+a version of the text editor
+.I ex,
+was designed to provide an informative environment
+for new and casual users.
+.PP
+We welcome comments and suggestions about this tutorial
+and the \s-2UNIX\s+2 documentation in general.
+.sp .5v
+September 1981
+.bp
+.ll 6.5i
+.nr LL 6.5i
+.nr LT 6.5i
+.ds u \s-2UNIX\s0
+.ce
+\s+2\f3Contents\f1\s0
+.LP
+.nf
+Introduction\ \ \ 3
+.sp
+Session 1\ \ \4
+.in +.5i
+Making contact with \s-2UNIX\s+2\ \ \ 4
+Logging in\ \ \4
+Asking for \fIedit\fR\ \ \ 4
+The ``Command not found'' message\ \ \ 5
+A summary\ \ \5
+Entering text\ \ \ 5
+Messages from \fIedit\fR\ \ \ 5
+Text input mode\ \ \ 6
+Making corrections\ \ \ 6
+Writing text to disk\ \ \ 7
+Signing off\ \ \7
+.in -.5i
+.sp
+Session 2\ \ \ 8
+.in +.5i
+Adding more text to the file\ \ \ 8
+Interrupt\ \ \ 8
+Making corrections\ \ \ 8
+Listing what's in the buffer (p)\ \ \ 9
+Finding things in the buffer\ \ \ 9
+The current line\ \ \ 10
+Numbering lines (nu)\ \ \ 10
+Substitute command (s)\ \ \ 10
+Another way to list what's in the buffer (z)\ \ \ 11
+Saving the modified text\ \ \ 12
+.in -.5i
+.sp
+Session 3\ \ \ 13
+.in +.5i
+Bringing text into the buffer (e)\ \ \ 13
+Moving text in the buffer (m)\ \ \ 13
+Copying lines (copy)\ \ \ 14
+Deleting lines (d)\ \ \ 14
+A word or two of caution\ \ \ 15
+Undo (u) to the rescue\ \ \ 15
+More about the dot (.) and buffer end ($)\ \ \ 16
+Moving around in the buffer (+ and \-)\ \ \ 16
+Changing lines (c)\ \ \ 17
+.in -.5i
+.sp
+Session 4\ \ \ 18
+.in +.5i
+Making commands global (g)\ \ \ 18
+More about searching and substituting\ \ \ 19
+Special characters\ \ \ 19
+Issuing \s-2UNIX\s+2 commands from the editor\ \ \ 20
+Filenames and file manipulation\ \ \ 20
+The file (f) command\ \ \ 20
+Reading additional files (r)\ \ \ 21
+Writing parts of the buffer\ \ \ 21
+Recovering files\ \ \ 21
+Other recovery techniques\ \ \ 21
+Further reading and other information\ \ \ 22
+Using \fIex\fR\ \ \ 22
+.in -.5i
+.sp
+Index\ \ \ 23
+.bp
+.SH
+.ce
+\s+2Introduction\s0
+.PP
+Text editing using a terminal connected to a computer
+allows you to create, modify, and print text
+easily.
+A
+.I
+text editor
+.R
+is a program
+that assists you
+as you create and modify text.
+The text editor you will learn here is named
+.I edit.
+Creating text using edit is as easy as typing it
+on an electric typewriter.
+Modifying text involves telling the text editor
+what you want to add, change, or delete.
+You can review your text
+by typing a command
+to print the file contents
+as they are currently.
+Another program (which we do not discuss in this
+document), a text formatter,
+rearranges your text
+for you into ``finished form.''
+.PP
+These lessons assume no prior familiarity with computers
+or with text editing.
+They consist of a series of text editing sessions
+which lead you through the fundamental steps
+of creating and revising text.
+After scanning each lesson and before beginning the next,
+you should try the examples at a terminal to get a feeling
+for the actual process of text editing.
+If you set aside some time for experimentation,
+you will soon become familiar with using the
+computer to write and modify text.
+In addition to the actual use of the text editor,
+other features of \s-2UNIX\s0 will be very important to your work.
+You can begin to
+learn about these other features by
+reading one of the other tutorials
+that provide a general introduction to the system.
+You will be ready to proceed with this lesson as soon as
+you are familiar with (1) your terminal and its special keys,
+(2) how to login,
+(3) and the ways of correcting typing errors.
+Let's first define some terms:
+.sp .5
+.IP program 12
+A set of instructions, given to the computer,
+describing the sequence of steps the computer performs
+in order to accomplish a specific task.
+The task must be specific,
+such as balancing your checkbook
+or editing your text.
+A general task,
+such as working for world peace,
+is something we can all do,
+but not something we can currently write programs to do.
+.IP UNIX
+\s-2UNIX\s0 is a special type of program,
+called an operating system, that supervises the machinery
+and all other programs comprising the total
+computer system.
+.IP edit
+.I edit
+is the name of the \s-2UNIX\s0 text editor you will be learning to use,
+and is a program that aids you in writing or revising text.
+Edit was designed for beginning users,
+and is a simplified version of an editor named
+.I ex.
+.IP file
+Each \s-2UNIX\s0 account is allotted
+space for the permanent storage of information,
+such as programs, data or text.
+A file is a logical unit of data,
+for example, an essay, a program,
+or a chapter from a book,
+which is stored on a computer system.
+Once you create a file,
+it is kept until you instruct the system to remove it.
+You may create a file during one \s-2UNIX\s0 session,
+end the session,
+and return to use it at a later time.
+Files contain anything you choose to write and store in them.
+The sizes of files vary to suit your needs;
+one file might hold only a single number,
+yet another might contain
+a very long document or program.
+The only way to save
+information from one session to the next is to store it in a file,
+which you will learn in Session 1.
+.IP filename
+Filenames are used to distinguish one file from another,
+serving the same purpose as the labels of manila
+folders in a file cabinet.
+In order to write or access information in a file,
+you use the name of that file in a \s-2UNIX\s0 command,
+and the system will automatically locate the file.
+.IP disk
+Files are stored on an input/output device called a disk,
+which looks something like a stack of phonograph records.
+Each surface is coated with a material similar to that
+on magnetic recording tape,
+and information is recorded on it.
+.IP buffer
+A temporary work space, made available to the user
+for the duration of a session of text editing
+and used for creating and modifying
+the text file.
+We can think of the buffer as a blackboard that is
+erased after each class, where each session with the editor
+is a class.
+.bp
+.SH
+.ce 1
+\s+2Session 1\s0
+.sp 1
+.SH
+Making contact with \s-1UNIX\s0
+.PP
+To use the editor you must first make contact with the computer
+by logging in to \s-2UNIX\s0.
+We'll quickly review the standard \s-2UNIX\s0 login procedure
+for the two ways you can make contact:
+on a terminal that is directly linked to the computer,
+or over a telephone line where the computer answers your call.
+.SH
+Directly-linked terminals
+.PP
+Turn on your terminal and press the \s-1RETURN\s0 key.
+You are now ready to login.
+.SH
+Dial-up terminals
+.PP
+If your terminal connects with the computer over a telephone line,
+turn on the terminal, dial the system access number,
+and, when you hear a high-pitched tone, place the
+telephone handset in the acoustic coupler, if you are using one.
+You are now ready to login.
+.SH
+Logging in
+.PP
+The message inviting you to login is:
+.DS I 1i
+login:
+.DE
+.LP
+Type your login name, which identifies you to \s-2UNIX\s0,
+on the same line as the login message,
+and press \s-2RETURN\s+2.
+If the terminal you are using
+has both upper and lower case,
+.B
+be sure you enter your login name in lower case;
+.R
+otherwise \s-2UNIX\s0 assumes your terminal
+has only upper case and will not recognize lower case
+letters you may type.
+\s-2UNIX\s0 types ``login:'' and you reply
+with your login name, for example ``susan'':
+.DS I 1i
+login: \fBsusan\fR \fI(and press the \s-2RETURN\s0 key)\fR
+.DE
+(In the examples, input you would type appears in
+.B "bold face"
+to distinguish it from the responses from \s-2UNIX\s0.)
+.PP
+\s-2UNIX\s0 will next respond with a request for a password
+as an additional precaution to prevent
+unauthorized people from using your account.
+The password will not appear when you type it,
+to prevent others from seeing it.
+The message is:
+.DS I 1i
+Password: \fI(type your password and press \s-2RETURN\s+2)\fR
+.DE
+If any of the information you gave during the login
+sequence was mistyped or incorrect,
+\s-2UNIX\s0 will respond with
+.DS I 1i
+Login incorrect.
+.if t .sp .2v
+.if n .sp 1
+login:
+.DE
+in which case you should start the login process anew.
+Assuming that you have successfully
+logged in, \s-2UNIX\s0
+will print the message of the day and eventually will present
+you with a % at the beginning of a fresh line.
+The % is the \s-2UNIX\s0 prompt symbol
+which tells you that \s-2UNIX\s0 is ready to accept a command.
+.bd I 3
+.SH
+Asking for \fIedit\fP
+.fl
+.bd I
+.PP
+You are ready to tell \s-2UNIX\s0 that you
+want to work with edit, the text editor.
+Now is a convenient time to choose
+a name for the file of text you are about to create.
+To begin your editing session,
+type
+.B edit
+followed by a space and then the filename
+you have selected; for example, ``text''.
+After that,
+press the \s-2RETURN\s0 key and wait for edit's response:
+.DS I 1i
+% \fBedit text\fP \fI(followed by a \s-2RETURN\s+2)\fR
+"text" No such file or directory
+:
+.DE
+If you typed the command correctly,
+you will now be in communication with edit.
+Edit has set aside a buffer for use as
+a temporary working space during your current editing session.
+Since ``text'' is a new file we are about to create
+the editor was unable to find that file, which it
+confirms by saying:
+.DS I 1i
+"text" No such file or directory
+.DE
+On the next line appears edit's prompt ``:'',
+announcing that you are in \f2command mode\f1 and
+edit expects a command from you.
+You may now begin to create the new file.
+.SH
+The ``Command not found'' message
+.PP
+If you misspelled edit by typing, say, ``editor'',
+this might appear:
+.DS I 1i
+% \fBeditor\fP
+editor: Command not found
+%
+.DE
+Your mistake in calling edit ``editor'' was
+treated by \s-2UNIX\s0 as a request
+for a program named ``editor''.
+Since there is no program
+named ``editor'',
+\s-2UNIX\s0 reported that the program was ``not found''.
+A new % indicates that \s-2UNIX\s0 is ready for another command,
+and you may then enter the correct command.
+.SH
+A summary
+.PP
+Your exchange with \s-2UNIX\s0 as you logged in and made contact with edit
+should look something like this:
+.DS I 1i
+login: \fBsusan\fP
+Password:
+\&... A Message of General Interest ...
+% \fBedit text\fP
+"text" No such file or directory
+:
+.DE
+.SH
+Entering text
+.PP
+You may now begin entering text into the buffer.
+This is done by \fIappending\fP (or adding) text to whatever
+is currently in the buffer.
+Since there is nothing in the buffer at the moment,
+you are appending text to nothing;
+in effect,
+since you are adding text to nothing
+you are creating text.
+Most edit commands have two equivalent forms:
+a word that suggests what the command does,
+and a shorter abbreviation of that word.
+Many beginners find the full command names
+easier to remember at first,
+but once you are familiar with editing you may
+prefer to type the shorter abbreviations.
+The command to input text is ``append''.
+(It may be abbreviated ``a''.)
+Type
+.B append
+and press the \s-2RETURN\s0 key.
+.DS I 1i
+% \fBedit text
+\fR:\|\fBappend
+.R
+.DE
+.SH
+.bd I 3
+Messages from
+.I edit
+.fl
+.bd I
+.PP
+If you make a mistake in entering a command and
+type something that edit does not recognize,
+edit will respond with a message
+intended to help you diagnose your error.
+For example, if you misspell the command to input text by typing,
+perhaps, ``add'' instead of ``append'' or ``a'',
+you will receive this message:
+.DS I 1i
+:\|\fBadd\fR
+add: Not an editor command
+:
+.DE
+When you receive a diagnostic message,
+check what you typed in order to determine what
+part of your command confused edit.
+The message above means that edit
+was unable to recognize your mistyped command
+and, therefore, did not execute it.
+Instead, a new ``:''
+appeared to let you know that
+edit is again ready to execute a command.
+.SH
+Text input mode
+.PP
+By giving the command ``append'' (or using the abbreviation ``a''),
+you entered
+.I
+text input mode,
+.R
+also known as
+.I
+append mode.
+.R
+When you enter text input mode,
+edit stops sending you a prompt.
+You will not receive any prompts
+or error messages
+while in text input mode.
+You can enter
+pretty much anything you want on the lines.
+The lines are transmitted one by one to the buffer
+and held there during the editing session.
+You may append as much text as you want, and
+.I
+when you wish to stop entering text lines you should
+type a period as the only character on the line
+and press the \s-2RETURN\s0 key.
+.R
+When you type the period and press \s-2RETURN\s0,
+you signal that you want to stop appending text,
+and edit responds by allowing
+you to exit text input mode and reenter command mode.
+Edit will again
+prompt you for a command by printing ``:''.
+.PP
+Leaving append mode does not destroy the text in
+the buffer.
+You have to leave append
+mode to do any of the other kinds of editing,
+such as changing, adding, or printing text.
+If you type a period as the first character and
+type any other character on the same line,
+edit will believe you want to remain in append mode
+and will not let you out.
+As this can be very frustrating,
+be sure to type
+.B only
+the period and the \s-2RETURN\s0 key.
+.PP
+This is a good place to learn an important
+lesson about computers and text: a blank space is
+a character as far as a computer is concerned.
+If you so much as type a period followed by a blank
+(that is, type a period and then the space bar on the keyboard),
+you will remain in append mode with the last line of text
+being:
+.DS I 1i
+.B
+.ps +2
+\&.
+.ps -2
+.R
+.DE
+Let's say that you enter the lines
+(try to type
+.B exactly
+what you see, including ``thiss''):
+.DS I 1i
+.B
+This is some sample text.
+And thiss is some more text.
+Text editing is strange, but nice.
+\&.
+.R
+.DE
+The last line is the period followed by a \s-2RETURN\s0
+that gets you out of append mode.
+.SH
+Making corrections
+.PP
+If you have read a general introduction to \s-2UNIX\s0,
+you will recall that it is possible to erase individual
+letters that you have typed.
+This is done by typing the designated erase character
+as many times as there are characters
+you want to erase.
+.PP
+The usual erase character varies from place to place and
+user to user. Often it
+is the backspace (control-H),
+so you can correct typing errors
+in the line you are typing
+by holding down the \s-1CTRL\s+1 key
+and typing the ``H'' key. (Sometimes it is the DEL key.)
+If you type the erase character
+you will notice
+that the terminal backspaces in the line you are on.
+You can backspace over your error,
+and then type what you want to be the rest of the line.
+.PP
+If you make a bad start
+in a line
+and would like to begin again,
+you can either backspace to the beginning of the line
+or you can use the at-sign ``@'' to erase everything on the line:
+.DS I 1i
+.B
+Text edtiing is strange, but@
+Text editing is strange, but nice.
+.R
+.fl
+.bd S
+.DE
+When you type the at-sign (@), you erase
+the entire line typed so far
+and are given a fresh line to type on.
+You may immediately begin to retype the line.
+This, unfortunately, does not work after you type the
+line and press \s-2RETURN\s+2.
+To make corrections in lines that have been completed,
+it is necessary to use the editing commands
+covered in the next sessions.
+.SH
+Writing text to disk
+.PP
+You are now ready to edit the text. One common operation
+is to write the text to disk as a file for safekeeping
+after the session is over.
+This is the only way to save information from one session to the next,
+since the editor's buffer is temporary and will last only until the
+end of the editing session.
+Learning how to write a file to disk is second in
+importance only to entering the text.
+To write the contents of the buffer to a disk
+file, use the command ``write''
+(or its abbreviation ``w''):
+.DS I 1i
+:\|\fBwrite
+.R
+.DE
+Edit will copy the contents of the buffer to a disk file.
+If the file does not yet exist,
+a new file will be created automatically
+and the presence of a ``[New file]'' will be noted.
+The newly-created file will be given the name specified when
+you entered the editor, in this case ``text''.
+To confirm that the disk file has been successfully written,
+edit will repeat the filename and give
+the number of lines and the total
+number of characters in the file.
+The buffer remains unchanged by the ``write'' command.
+All of the lines that were written to disk will still be
+in the buffer,
+should you want to modify or add to them.
+.PP
+Edit must have a name for the file to be written.
+If you forgot to indicate the name of the file
+when you began to edit,
+edit will print in response to your write command:
+.DS I 1i
+No current filename
+.DE
+If this happens, you can specify the filename in a new write command:
+.DS I 1i
+:\|\fBwrite text
+.R
+.DE
+After the ``write'' (or ``w''), type a space and then the name of the file.
+.SH
+Signing off
+.PP
+We have done enough for this first lesson on using the
+\s-2UNIX\s0 text editor, and are ready to quit the session with edit.
+To do this we type ``quit'' (or ``q'') and press \s-2RETURN\s+2:
+.DS I 1i
+:\|\fBwrite
+.R
+"text" [New file] 3 lines, 90 characters
+:\|\fBquit\fR
+%
+.DE
+The % is from \s-2UNIX\s0 to tell you that your session with edit is
+over and you may command \s-2UNIX\s0 further.
+Since we want
+to end the entire session at the terminal, we also need to
+exit from \s-2UNIX\s0.
+In response to the \s-2UNIX\s0 prompt of ``\|%\|''
+type the command
+.DS I 1i
+%\|\fBlogout\fR
+.DE
+This will end your session with \s-2UNIX\s0, and will ready the
+terminal for the next user.
+It is always important to type \fBlogout\fR at the end of a session
+to make absolutely sure no one
+could accidentally stumble into your abandoned
+session and thus gain access to your files,
+tempting even the most honest of souls.
+.sp 1
+.PP
+This is the end of the first session on \s-2UNIX\s0 text editing.
+.bp
+.TL
+Session 2
+.sp
+.PP
+Login with \s-2UNIX\s0 as in the first session:
+.DS I 1i
+login: \fBsusan\fP \fI(carriage return)\fR
+Password: \fI(give password and carriage return)\fR
+.if t .sp .2v
+.if n .sp 1
+\&... A Message of General Interest ...
+%
+.DE
+When you indicate you want to edit,
+you can specify the name of the file you worked on last time.
+This will
+start edit working, and it will fetch the contents of the
+file into the buffer, so that you can resume editing the same file.
+When edit has copied the file into the buffer, it
+will repeat its name and tell
+you the number of lines and characters it contains.
+Thus,
+.DS I 1i
+.B
+% edit text
+.R
+"text" 3 lines, 90 characters
+:
+.DE
+means you asked edit to fetch
+the file named ``text'' for editing,
+causing it to copy the
+90 characters of text into the buffer.
+Edit awaits
+your further instructions,
+and indicates this by its prompt character, the colon (:).
+In this session, we will append more text to our file,
+print the contents of the buffer, and learn to change the text of a line.
+.SH
+Adding more text to the file
+.PP
+If you want to add more to the end of your
+text you may do so by using the append command to enter text input mode.
+When ``append'' is the first command
+of your editing session,
+the lines you enter
+are placed at the end of the buffer.
+Here we'll use the abbreviation for the append command, ``a'':
+.DS I 1i
+:\|\fBa
+This is text added in Session 2.
+It doesn't mean much here, but
+it does illustrate the editor.
+\|\fB\s+2\&.\s-2
+.R
+.DE
+You may recall that once you enter append mode
+using the ``a'' (or ``append'') command,
+you need to type a line containing only a period (.)
+to exit append mode.
+.SH
+Interrupt
+.PP
+Should you press the \s-2RUB\s+2 key (sometimes labelled \s-2DELETE\s+2)
+while working with edit,
+it will send this message to you:
+.DS I 1i
+Interrupt
+:
+.DE
+Any command that edit might be executing
+is terminated by rub or delete,
+causing edit to prompt you for a new command.
+If you are appending text at the time,
+you will exit from append mode
+and be expected to give another command.
+The line of text you were typing
+when the append command was interrupted
+will not be entered into the buffer.
+.SH
+Making corrections
+.PP
+If while typing the line you hit an incorrect key,
+recall that
+you may delete the incorrect character
+or cancel the entire line of input by erasing in the usual way.
+Refer either
+to the last few pages of Session 1
+if you need to review
+the procedures for making a correction.
+The most important idea to remember is that
+erasing a character or cancelling a line must be done
+before you press the \s-2RETURN\s+2 key.
+.SH
+Listing what's in the buffer (p)
+.PP
+Having appended text to what you wrote in Session 1,
+you might want to see all the lines in the buffer.
+To print the contents of the buffer, type the command:
+.DS I 1i
+:\|\fB1,$p
+.R
+.DE
+The ``1''\(dg
+.FS
+\(dgThe numeral ``one'' is the top left-most key,
+and should not be confused with the letter ``el''.
+.FE
+stands for line 1 of the buffer,
+the ``$'' is a special symbol designating the last line
+of the buffer,
+and ``p'' (or \fBprint\fR) is the command to print from line 1
+to the end of the buffer.
+The command ``1,$p'' gives you:
+.DS I 1i
+This is some sample text.
+And thiss is some more text.
+Text editing is strange, but nice.
+This is text added in Session 2.
+It doesn't mean much here, but
+it does illustrate the editor.
+.DE
+Occasionally, you may accidentally
+type a character that can't be printed,
+which can be done by striking a key
+while the \s-2CTRL\s0 key is pressed.
+In printing lines, edit uses a special notation to
+show the existence of non-printing characters.
+Suppose you had introduced the non-printing character ``control-A''
+into the word ``illustrate''
+by accidently pressing the \s-2CTRL\s0 key while
+typing ``a''.
+This can happen on many terminals
+because the \s-2CTRL\s+2 key and the ``A'' key
+are beside each other.
+If your finger presses between the two keys,
+control-A results.
+When asked to print the contents of the buffer,
+edit would display
+.DS I 1i
+it does illustr^Ate the editor.
+.DE
+To represent the control-A, edit shows ``^A''.
+The sequence ``^'' followed by a capital
+letter stands for the one character
+entered by holding down the \s-2CTRL\s0 key and typing the letter
+which appears after the ``^''.
+We'll soon discuss the commands that can be used
+to correct this typing error.
+.PP
+In looking over the text we see that
+``this'' is typed as ``thiss'' in the second line,
+a deliberate error so we can learn to make corrections.
+Let's correct the spelling.
+.SH
+Finding things in the buffer
+.PP
+In order to change something in the buffer we first need to
+find it.
+We can find ``thiss'' in the text we have
+entered by looking at a listing
+of the lines.
+Physically speaking, we search the lines
+of text looking for ``thiss'' and stop searching when
+we have found it.
+The way to tell edit to search for something
+is to type it inside slash marks:
+.DS I 1i
+:\|\fB/thiss/
+.R
+.DE
+By typing
+.B /thiss/
+and pressing \s-1RETURN\s0,
+you instruct edit to search for ``thiss''.
+If you ask edit to look for a pattern of characters
+which it cannot find in the buffer,
+it will respond ``Pattern not found''.
+When edit finds
+the characters ``thiss'', it will print the line of text
+for your inspection:
+.DS I 1i
+And thiss is some more text.
+.DE
+Edit is now positioned in the buffer at the
+line it just printed,
+ready to make a change in the line.
+.bp
+.SH
+The current line
+.PP
+Edit keeps track of the line in the buffer where it is located
+at all times during an editing session.
+In general, the line that has been most recently
+printed, entered, or changed
+is the current location in the buffer.
+The editor is prepared to make changes
+at the current location in the buffer,
+unless you direct it to another location.
+.PP
+In particular,
+when you bring a file into the buffer,
+you will be located at the last line in the file,
+where the editor left off copying the lines
+from the file to the buffer.
+If your first editing command is ``append'',
+the lines you enter are added
+to the end of the file,
+after the current line \(em
+the last line in the file.
+.PP
+You can refer to your current location in the buffer by the
+symbol
+period (.) usually known by the name ``dot''.
+If you type ``.'' and carriage
+return you will be instructing edit to print the current line:
+.DS I 1i
+:\|\fB\s+2\&.\s-2
+.R
+And thiss is some more text.
+.DE
+.PP
+If you want to know the number of the current line,
+you can type
+.B \&.=
+and press \s-2RETURN\s+2,
+and edit will respond with the line number:
+.DS I 1i
+:\|\fB\s+2.\s-2=
+.R
+2
+.DE
+If you type the number of any line and press \s-2RETURN\s+2,
+edit will position you at that line and
+print its contents:
+.DS I 1i
+:\|\fB2
+.R
+And thiss is some more text.
+.DE
+You should experiment with these commands
+to gain experience in using them to make changes.
+.SH
+Numbering lines (nu)
+.PP
+The
+.B
+number (nu)
+.R
+command is similar to print,
+giving both the number and the text of each printed line.
+To see the number and the text of the current line type
+.DS I 1i
+:\|\fBnu
+.R
+\0\0\0\0\02\0\0And thiss is some more text.
+.DE
+Note that the shortest abbreviation for the number command is
+``nu'' (and not ``n'', which is used for a different command).
+You may specify a range of lines
+to be listed by the number command in the same way that lines
+are specified for print.
+For example, \f31,$nu\f1 lists all lines in the buffer with their
+corresponding line numbers.
+.SH
+Substitute command (s)
+.PP
+Now that you have found the misspelled word,
+you can change it from ``thiss'' to ``this''.
+As far as edit is concerned,
+changing things is a matter of
+substituting one thing for another.
+As
+.I a
+stood for
+.I append,
+so
+.I s
+stands for
+.I substitute.
+We will use the abbreviation ``s'' to reduce the chance
+of mistyping the substitute command.
+This command will instruct edit to make the change:
+.DS I 1i
+\f32s/thiss/this/\f1
+.DE
+We first indicate the line to be changed, line 2,
+and then
+type an ``s'' to indicate we want
+edit to make a substitution.
+Inside the first set of slashes
+are the characters that we want to change,
+followed by the characters to replace them,
+and then a closing slash mark.
+To summarize:
+.DS I 1i
+2s/ \fIwhat is to be changed\fR / \fIwhat to change it to \fR/
+.DE
+If edit finds an exact match of the characters to be
+changed it will make the change
+.B only
+in the first occurrence of the characters.
+If it does not find the characters
+to be changed, it will respond:
+.DS I 1i
+Substitute pattern match failed
+.DE
+indicating that your instructions could not be carried out.
+When edit does find the characters that you want to change,
+it will make the substitution and automatically print
+the changed line, so that you can check that the correct substitution
+was made.
+In the example,
+.DS I 1i
+:\|\fB2s/thiss/this/
+.R
+And this is some more text.
+.DE
+line 2 (and line 2 only) will be searched for the characters
+``thiss'', and when the first exact match is found, ``thiss''
+will be changed to ``this''.
+Strictly speaking, it was not necessary above to
+specify the number of the line to be changed.
+In
+.DS I 1i
+:\|\fBs/thiss/this/
+.R
+.DE
+edit will assume that we mean to change
+the line where we are currently located (``.'').
+In this case,
+the command without a line number would have produced the same result
+because we were already located
+at the line we wished to change.
+.PP
+For another illustration of the substitute command,
+let us choose the line:
+.DS I 1i
+Text editing is strange, but nice.
+.DE
+You can make this line a bit more positive
+by taking out the characters ``strange, but\ '' so the line
+reads:
+.DS I 1i
+Text editing is nice.
+.DE
+A command that will first position edit at the desired line
+and then make the substitution is:
+.DS I 1i
+:\|\fB/strange/s/strange, but //
+.R
+.DE
+.LP
+What we have done here is combine our search with
+our substitution.
+Such combinations are perfectly legal,
+and speed up editing quite a bit
+once you get used to them.
+That is, you do not necessarily have to use
+line numbers to identify a line to edit.
+Instead, you may identify the line you want to change
+by asking edit to search for a specified pattern of letters
+that occurs in that line.
+The parts of the above command are:
+.TS
+.in +1i
+.nr 35 \n(.u
+.nf
+.ds #d .d
+.if \(ts\n(.z\(ts\(ts .ds #d nl
+.nr 80 0
+.nr 38 \w\f3/strange/\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 38 \w\f3s\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 38 \w\f3/strange, but //\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 81 0
+.nr 38 \wtells edit to find the characters ``strange'' in the text
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 \wtells edit to make a substitution
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 \wsubstitutes nothing at all for the characters ``strange, but ''
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 1n
+.nr 79 0
+.nr 40 \n(79+(0*\n(38)
+.nr 80 +\n(40
+.nr 41 \n(80+(3*\n(38)
+.nr 81 +\n(41
+.nr TW \n(81
+.if t .if (\n(TW+\n(.o)>7.75i .tm Table at line 307 file ed2.tbl is too wide - \n(TW units
+.fc  
+.nr #T 0
+.eo
+.de T#
+.ds #d .d
+.if \(ts\n(.z\(ts\(ts .ds #d nl
+.mk ##
+.nr ## -1v
+..
+.ec
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3/strange/\fP\h'|\n(41u'tells edit to find the characters ``strange'' in the text
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3s\fP\h'|\n(41u'tells edit to make a substitution
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3/strange, but //\fP\h'|\n(41u'substitutes nothing at all for the characters ``strange, but ''
+.fc
+.nr T. 1
+.T# 1
+.if \n(35>0 .fi
+.in -1i
+.TE
+.PP
+You should note the space after ``but'' in ``/strange, but /''.
+If you do not indicate that the space is to be taken out,
+your line will read:
+.DS I 1i
+.if t Text editing is nice.
+.if n Text editing is nice.
+.DE
+which looks a little funny
+because of the extra space between ``is'' and ``nice''.
+Again, we realize from this that a blank space
+is a real character to a computer, and in editing text
+we need to be aware of spaces
+within a line just as we would be aware of an ``a'' or
+a ``4''.
+.SH
+Another way to list what's in the buffer (z)
+.PP
+Although the print command is useful for looking at specific lines
+in the buffer,
+other commands may be more convenient for
+viewing large sections of text.
+You can ask to see a screen full of text at a time
+by using the command
+.B z.
+If you type
+.DS I 1i
+:\|\fB1z
+.R
+.DE
+edit will start with line 1 and continue printing lines,
+stopping either when the screen of
+your terminal is full
+or when the last line in the buffer has been printed.
+If you want to read the next segment of text, type the command
+.DS I 1i
+:\|\fBz
+.DE
+If no starting line number is given for the z command,
+printing will start at the ``current'' line, in this case the
+last line printed.
+Viewing lines in the buffer one screen full at a time
+is known as \fIpaging\fR.
+Paging can also be used to print
+a section of text on a hard-copy terminal.
+.SH
+Saving the modified text
+.PP
+This seems to be a good place to pause in our work,
+and so we should end the second session.
+If you (in haste) type ``q'' to quit the session
+your dialogue with edit will be:
+.DS I 1i
+:\|\fBq
+.R
+No write since last change (:quit! overrides)
+:
+.DE
+This is edit's warning that you have not written
+the modified contents of the buffer to disk.
+You run the risk of losing the work you did
+during the editing session since you typed the latest write
+command.
+Because in this lesson we have not written
+to disk at all, everything we have done
+would have been lost
+if edit had obeyed the \fBq\fR command.
+If you did not want to save the work done during
+this editing session, you would have to type ``q!''
+or (``quit!'')
+to confirm that you indeed wanted to end the session
+immediately,
+leaving the file as it was
+after the most recent ``write'' command.
+However,
+since you want to save what
+you have edited, you need to type:
+.DS I 1i
+:\|\fBw
+.R
+"text" 6 lines, 171 characters
+.DE
+and then follow with the commands to quit and logout:
+.DS I 1i
+:\|\fBq
+% \fBlogout\fR
+.DE
+and hang up the phone or turn off the terminal when
+\s-2UNIX\s0 asks for a name.
+Terminals connected to the port selector
+will stop after the logout command,
+and pressing keys on the keyboard will do nothing.
+.sp 1
+.PP
+This is the end of the second session on \s-2UNIX\s0 text editing.
+.bp
+.TL
+Session 3
+.SH
+Bringing text into the buffer (e)
+.PP
+Login to \s-2UNIX\s0 and make contact with edit.
+You should try to login without
+looking at the notes, but if you must
+then by all means do.
+.PP
+Did you remember to give the name of the file
+you wanted to edit?
+That is, did you type
+.DS I 1i
+% \fBedit text\fR
+.DE
+or simply
+.DS I 1i
+% \fBedit\fR
+.DE
+Both ways get you in contact with edit, but the first way
+will bring a copy of the file named ``text'' into
+the buffer.
+If you did forget to tell edit the name of your file,
+you can get it into the buffer by
+typing:
+.DS I 1i
+:\|\fBe text
+.R
+"text" 6 lines, 171 characters
+.DE
+The command
+.B edit,
+which may be abbreviated \fBe\fR,
+tells edit that you want
+to erase anything that might already be in
+the buffer and bring a copy of the file ``text'' into the buffer
+for editing.
+You may also use the edit (e) command to change files in
+the middle of an editing session,
+or to give edit the name of a new file that you want to create.
+Because the edit command clears the buffer,
+you will receive a warning if you try to edit a new file without
+having saved a copy of the old file.
+This gives you a chance to write the contents of the buffer to disk
+before editing the next file.
+.SH
+Moving text in the buffer (m)
+.PP
+Edit allows you to move lines of text
+from one location in the buffer to another
+by means of the
+.B move
+(\fBm\fR) command.
+The first two examples are for illustration only,
+though after you have read this Session
+you are welcome to return to them for practice.
+The command
+.DS I 1i
+:\|\fB2,4m$
+.R
+.DE
+directs edit to move lines 2, 3, and 4
+to the end of the buffer ($).
+The format for the move command is that you specify
+the first line to be moved, the last line to be moved,
+the move command ``m'', and the line after which
+the moved text is to be placed.
+So,
+.DS I 1i
+:\|\fB1,3m6
+.R
+.DE
+would instruct edit to move lines 1 through 3 (inclusive)
+to a location after line 6 in the buffer.
+To move only one line, say, line 4,
+to a location in the buffer after line 5,
+the command would be ``4m5''.
+.PP
+Let's move some text using the command:
+.DS I 1i
+:\|\fB5,$m1
+.R
+2 lines moved
+it does illustrate the editor.
+.DE
+After executing a command that moves more than one line of the buffer,
+edit tells how many lines were affected by the move
+and prints the last moved line for your inspection.
+If you want to see more than just the last line,
+you can then
+use the print (p), z, or number (nu) command to view more text.
+The buffer should now contain:
+.DS I 1i
+This is some sample text.
+It doesn't mean much here, but
+it does illustrate the editor.
+And this is some more text.
+Text editing is nice.
+This is text added in Session 2.
+.DE
+You can restore the original order by typing:
+.DS I 1i
+:\|\fB4,$m1
+.R
+.DE
+or, combining context searching and the move command:
+.DS I 1i
+:\|\fB/And this is some/,/This is text/m/This is some sample/
+.R
+.DE
+(Do not type both examples here!)
+The problem with combining context searching
+with the move command
+is that your chance of making a typing error
+in such a long command is greater than
+if you type line numbers.
+.SH
+Copying lines (copy)
+.PP
+The
+.B copy
+command
+is used to make a second copy of specified lines,
+leaving the original lines where they were.
+Copy
+has the same format as the move command, for example:
+.DS I 1i
+:\|\fB2,5copy $
+.R
+.DE
+makes a copy of lines 2 through 5,
+placing the added lines after the buffer's end ($).
+Experiment with the copy command
+so that you can become familiar with how it works.
+Note that the shortest abbreviation for copy is
+\f3co\f1 (and
+not the letter ``c'', which has another meaning).
+.SH
+Deleting lines (d)
+.PP
+Suppose you want to delete
+the line
+.DS I 1i
+This is text added in Session 2.
+.DE
+from the buffer.
+If you know the number of the line to be deleted,
+you can type
+that number followed by
+\fBdelete\fR or \fBd\fR.
+This example deletes line 4,
+which is ``This is text added in Session 2.''
+if you typed the commands
+suggested so far.
+.DS I 1i
+:\|\fB4d
+.R
+It doesn't mean much here, but
+.DE
+Here ``4'' is the number of the line to be deleted,
+and ``delete'' or ``d'' is the command to delete the line.
+After executing the delete command,
+edit prints the line that has become the current line (``.'').
+.PP
+If you do not happen to know the line number
+you can search for the line and then delete it using this
+sequence of commands:
+.DS I 1i
+:\|\fB/added in Session 2./
+.R
+This is text added in Session 2.
+:\|\fBd
+.R
+It doesn't mean much here, but
+.DE
+The ``/added in Session 2./''
+asks edit to locate and print
+the line containing the indicated text,
+starting its search at the current line
+and moving line by line
+until it finds the text.
+Once you are sure that you have correctly specified the line
+you want to delete,
+you can enter the delete (d) command.
+In this case it is not necessary to
+specify a line number before the ``d''.
+If no line number is given,
+edit deletes the current line (``.''),
+that is, the line found by our search.
+After the deletion, your buffer should contain:
+.DS I 1i
+This is some sample text.
+And this is some more text.
+Text editing is nice.
+It doesn't mean much here, but
+it does illustrate the editor.
+And this is some more text.
+Text editing is nice.
+This is text added in Session 2.
+It doesn't mean much here, but
+.DE
+To delete both lines 2 and 3:
+.DS I 1i
+And this is some more text.
+Text editing is nice.
+.DE
+you type
+.DS I 1i
+:\|\f32,3d\f1
+2 lines deleted
+.DE
+which specifies the range of lines from 2 to 3,
+and the operation on those lines \(em ``d'' for delete.
+If you delete more than one line
+you will receive a message
+telling you the number of lines deleted,
+as indicated in the example above.
+.PP
+The previous example assumes that you know the line numbers for
+the lines to be deleted.
+If you do not you might combine the search command
+with the delete command:
+.DS I 1i
+:\|\fB/And this is some/,/Text editing is nice./d
+.R
+.DE
+.SH
+A word or two of caution
+.PP
+In using the search function to locate lines to
+be deleted you should be
+.B
+absolutely sure
+.R
+the characters you give as the basis for the search
+will take edit to the line you want deleted.
+Edit will search for the first
+occurrence of the characters starting from where
+you last edited \-
+that is, from the line you see printed if you type dot (.).
+.PP
+A search based on too few
+characters may result in the wrong lines being deleted,
+which edit will do as easily as if you had meant it.
+For this reason, it is usually safer
+to specify the search and then delete in two separate steps,
+at least until you become familiar enough with using the editor
+that you understand how best to specify searches.
+For a beginner it is not a bad idea to double-check
+each command before pressing \s-2RETURN\s+2 to send the command on its way.
+.SH
+Undo (u) to the rescue
+.PP
+The
+.B
+undo (u)
+.R
+command has the ability to
+reverse the effects of the last command that changed the buffer.
+To undo the previous command, type
+``u'' or ``undo''.
+Undo can rescue
+the contents of the buffer from many an unfortunate mistake.
+However, its powers are not unlimited,
+so it is still wise to be reasonably
+careful about the commands you give.
+.PP
+It is possible to undo only commands which
+have the power to change the buffer \(em for example,
+delete, append, move, copy, substitute, and even undo itself.
+The commands write (w) and edit (e), which interact with disk files,
+cannot be undone, nor can commands that do not change
+the buffer, such as print.
+Most importantly,
+the
+.B only
+command that can be reversed by undo
+is the
+last ``undo-able'' command you typed.
+You can use control-H and @ to change
+commands while you are typing them,
+and undo to reverse the effect of the commands
+after you have typed them and pressed \s-2RETURN\s+2.
+.PP
+To illustrate,
+let's issue an undo command.
+Recall that the last buffer-changing command we gave deleted
+the lines formerly numbered 2 and 3.
+Typing undo at this moment will reverse the effects
+of the deletion, causing those two lines to be
+replaced in the buffer.
+.DS I 1i
+:\|\fBu
+.R
+2 more lines in file after undo
+And this is some more text.
+.DE
+Here again, edit informs you if the command affects more
+than one line,
+and prints
+the text of the line which is now ``dot'' (the current line).
+.SH
+More about the dot (.) and buffer end ($)
+.PP
+The function assumed by the symbol dot depends on its context.
+It can be used:
+.IP
+1. to exit from append mode; we type dot (and only a dot) on
+a line and press \s-2RETURN\s+2;
+.IP
+2. to refer to the line we are at in the buffer.
+.LP
+Dot can also be combined with the equal sign to get
+the number of the line currently being edited:
+.DS I 1i
+:\|\fB\&.=
+.R
+.DE
+If we type ``\fB.\fR='' we are asking for the number of the line,
+and if we type ``\fB.\fR'' we are asking for the text of the line.
+.PP
+In this editing session and the last, we used the dollar
+sign to indicate the end of the buffer
+in commands such as print, copy, and move.
+The dollar sign as a command asks edit to print the last
+line in the buffer.
+If the dollar sign is combined with the equal sign (\f3$=\f1)
+edit will print the line number corresponding to the
+last line in the buffer.
+.PP
+``\fB.\fR'' and ``$'', then, represent line numbers.
+Whenever appropriate, these symbols can be used in
+place of line numbers in commands.
+For example
+.DS I 1i
+:\|\fB\s+2.\s-2,$d
+.R
+.DE
+instructs edit to delete all lines from the current line (\fB.\fR)
+to the end of the buffer.
+.SH
+Moving around in the buffer (+ and \-)
+.PP
+When you are editing
+you often want
+to go back and re-read a previous line.
+You could specify a context search for a line you want to
+read if you remember some of its text,
+but if you simply want to see what was written a few, say 3, lines
+ago, you can type
+.DS I 1i
+\-3p
+.DE
+This tells edit to move back to a position 3 lines
+before the current line (.)
+and print that line.
+You can move forward in the buffer similarly:
+.DS I 1i
++2p
+.DE
+instructs edit to print the line that is 2
+ahead of your current position.
+.PP
+You may use ``+'' and ``\-'' in any command where edit
+accepts line numbers.
+Line numbers specified with ``+'' or ``\-''
+can be combined to print a range of lines.
+The command
+.DS I 1i
+:\|\fB\-1,+2copy$
+.R
+.DE
+makes a copy of 4 lines: the current line, the line before it,
+and the two after it.
+The copied lines will be placed after the last line
+in the buffer ($),
+and the original lines referred to by ``\-1'' and ``+2''
+remain where they are.
+.PP
+Try typing only ``\-''; you will move back one line just as
+if you had typed ``\-1p''.
+Typing the command ``+'' works similarly.
+You might also try typing a few plus or minus signs in a row
+(such as ``+++'') to see edit's response.
+Typing \s-2RETURN\s+2 alone on a line is the equivalent
+of typing ``+1p''; it will move you one line ahead in the buffer
+and print that line.
+.PP
+If you are at the last line of the buffer and try
+to move further ahead, perhaps by typing a ``+'' or
+a carriage return alone on the line,
+edit will remind you that you are at the end of the buffer:
+.sp
+.nf
+.ti 1i
+At end-of-file
+.br
+or
+.ti 1i
+Not that many lines in buffer
+.fi
+.LP
+Similarly, if you try to move to a position before the first line,
+edit will print one of these messages:
+.sp
+.nf
+.ti 1i
+Nonzero address required on this command
+.br
+or
+.ti 1i
+Negative address \- first buffer line is 1
+.fi
+.LP
+The number associated with a buffer line is the line's ``address'',
+in that it can be used to locate the line.
+.SH
+Changing lines (c)
+.PP
+You can also delete certain lines and
+insert new text in their place.
+This can be accomplished easily with the
+.B "change (c)"
+command.
+The change command instructs edit to delete specified lines
+and then switch to text input mode to
+accept the text that will replace them.
+Let's say you want to change the first two lines in the buffer:
+.DS I 1i
+This is some sample text.
+And this is some more text.
+.DE
+to read
+.DS I 1i
+This text was created with the \s-2UNIX\s0 text editor.
+.DE
+To do so, you type:
+.DS I 1i
+:\|\fB1,2c
+.R
+2 lines changed
+.B
+This text was created with the \s-2UNIX\s0 text editor.
+\s+2\&.\s-2
+.R
+:
+.DE
+In the command
+.B 1,2c
+we specify that we want to change
+the range of lines beginning with 1 and ending with 2
+by giving line numbers as with the print command.
+These lines will be deleted.
+After you type \s-2RETURN\s+2 to end the change command,
+edit notifies you if more than one line will be changed
+and places you in text input mode.
+Any text typed on the following lines will be inserted into
+the position where lines were deleted by the change command.
+.B
+You will remain in text input mode until you exit in the usual way,
+by typing a period alone on a line.
+.R
+Note that the number of lines added to the buffer need not be
+the same as the number of lines deleted.
+.sp 1
+.PP
+This is the end of the third session on text editing with \s-2UNIX\s0.
+.bp
+.SH
+.ce 1
+\s+2Session 4\s0
+.sp
+.PP
+This lesson covers several topics, starting with
+commands that apply throughout the buffer,
+characters with special meanings,
+and how to issue \s-2UNIX\s0 commands while in the editor.
+The next topics deal with files:
+more on reading and writing,
+and methods of recovering files lost in a crash.
+The final section suggests sources of further information.
+.SH
+Making commands global (g)
+.PP
+One disadvantage to the commands we have used for
+searching or substituting is that if you
+have a number of instances of a word to change
+it appears that you have to type the command
+repeatedly, once for
+each time the change needs to be made.
+Edit, however, provides a way to make commands
+apply to the entire contents of the buffer \-
+the
+.B
+global (g)
+.R
+command.
+.PP
+To print all lines
+containing a certain sequence of characters
+(say, ``text'')
+the command is:
+.DS I 1i
+:\|\fBg/text/p
+.R
+.DE
+The ``g'' instructs edit to
+make a global search for all lines
+in the buffer containing the characters ``text''.
+The ``p'' prints the lines found.
+.PP
+To issue a global command, start by typing a ``g'' and then a search
+pattern identifying
+the lines to be affected.
+Then, on the same line, type the command to be
+executed for the identified lines.
+Global substitutions are frequently useful.
+For example,
+to change all instances of the word ``text'' to the word ``material''
+the command would be a combination of the global search and the
+substitute command:
+.DS I 1i
+:\|\fBg/text/s/text/material/g
+.R
+.DE
+Note the ``g'' at the end of the global command,
+which instructs edit to change
+each and every instance of ``text'' to ``material''.
+If you do not type the ``g'' at the end of the command
+only the
+.I first
+instance of ``text'' \fIin each line\fR will be changed
+(the normal result of the substitute command).
+The ``g'' at the end of the command is independent of the ``g''
+at the beginning.
+You may give a command such as:
+.DS I 1i
+:\|\fB5s/text/material/g
+.R
+.DE
+to change every instance of ``text'' in line 5 alone.
+Further, neither command will change ``text'' to ``material''
+if ``Text'' begins with a capital rather than a lower-case
+.I t.
+.PP
+Edit does not automatically print the lines modified by a
+global command.
+If you want the lines to be printed, type a ``p''
+at the end of the global command:
+.DS I 1i
+:\|\fBg/text/s/text/material/gp
+.R
+.DE
+You should be careful
+about using the global command in combination with any other \-
+in essence, be sure of what you are telling edit to do
+to the entire buffer.
+For example,
+.DS I 1i
+:\|\fBg/ /d
+.R
+72 less lines in file after global
+.DE
+will delete every line containing a blank anywhere in it.
+This could adversely affect
+your document, since most lines have spaces between words
+and thus would be deleted.
+After executing the global command,
+edit will print a warning if the command added or deleted more than one line.
+Fortunately, the undo command can reverse
+the effects of a global command.
+You should experiment with the global command
+on a small file of text to see what it can do for you.
+.SH
+More about searching and substituting
+.PP
+In using slashes to identify a character string
+that we want to search for or change,
+we have always specified the exact characters.
+There is a less tedious way to
+repeat the same string of characters.
+To change ``text'' to ``texts'' we may type either
+.DS I 1i
+:\|\fB/text/s/text/texts/
+.R
+.DE
+as we have done in the past,
+or a somewhat abbreviated command:
+.DS I 1i
+:\|\fB/text/s//texts/
+.R
+.DE
+In this example, the characters to be changed
+are not specified \-
+there are no characters, not even a space,
+between the two slash marks
+that indicate what is to be changed.
+This lack of characters between the slashes
+is taken by the editor to mean
+``use the characters we last searched for as the characters to be changed.''
+.PP
+Similarly, the last context search may be repeated
+by typing a pair of slashes with nothing between them:
+.DS I 1i
+:\|\fB/does/
+.R
+It doesn't mean much here, but
+:\|\fB//
+.R
+it does illustrate the editor.
+.DE
+(You should note that the search command found the characters ``does''
+in the word ``doesn't'' in the first search request.)
+Because no characters are specified for the second search,
+the editor scans the buffer for the next occurrence of the
+characters ``does''.
+.PP
+Edit normally searches forward through the buffer,
+wrapping around from the end of the buffer to the beginning,
+until the specified character string is found.
+If you want to search in the reverse direction,
+use question marks (?) instead of slashes
+to surround the characters you are searching for.
+.PP
+It is also possible
+to repeat the last substitution
+without having to retype the entire command.
+An ampersand (&) used as a command
+repeats the most recent substitute command,
+using the same search and replacement patterns.
+After altering the current line by typing
+.DS I 1i
+:\|\fBs/text/texts/
+.R
+.DE
+you type
+.DS I 1i
+:\|\fB/text/&
+.R
+.DE
+or simply
+.DS I 1i
+:\|\fB//&
+.R
+.DE
+to make the same change on the next line in the buffer
+containing the characters ``text''.
+.SH
+Special characters
+.PP
+Two characters have special meanings when
+used in specifying searches: ``$'' and ``^''.
+``$'' is taken by the editor to mean ``end of the line''
+and is used to identify strings
+that occur at the end of a line.
+.DS I 1i
+:\|\fBg/text.$/s//material./p
+.R
+.DE
+tells the editor to search for all lines ending in ``text.''
+(and nothing else, not even a blank space),
+to change each final ``text.'' to ``material.'',
+and print the changed lines.
+.PP
+The symbol ``^'' indicates the beginning of a line.
+Thus,
+.DS I 1i
+:\|\fBs/^/1. /
+.R
+.DE
+instructs the editor to insert ``1.'' and a space at the beginning
+of the current line.
+.PP
+The characters ``$'' and ``^'' have special meanings only in the context
+of searching.
+At other times, they are ordinary characters.
+If you ever need to search for a character that has a special meaning,
+you must indicate that the
+character is to lose temporarily
+its special significance by typing another special character,
+the backslash (\\), before it.
+.DS I 1i
+:\|\fBs/\\\\\&$/dollar/
+.R
+.DE
+looks for the character ``$'' in the current
+line and replaces it by the word ``dollar''.
+Were it not for the backslash, the ``$'' would have represented
+``the end of the line'' in your search
+rather than the character ``$''.
+The backslash retains its special significance
+unless it is preceded by another backslash.
+.SH
+Issuing \s-2UNIX\s0 commands from the editor
+.PP
+After creating several files with the editor,
+you may want to delete files
+no longer useful to you or ask for a list of your files.
+Removing and listing files are not functions of the editor,
+and so they require the use of \s-2UNIX\s0 system commands
+(also referred to as ``shell'' commands, as
+``shell'' is the name of the program that processes \s-2UNIX\s0 commands).
+You do not need to quit the editor to execute a \s-2UNIX\s0 command
+as long as you indicate that it
+is to be sent to the shell for execution.
+To use the \s-2UNIX\s0 command
+.B rm
+to remove the file named ``junk'' type:
+.DS I 1i
+:\|\fB!rm junk
+.R
+!
+:
+.DE
+The exclamation mark (!)
+indicates that the rest of the line is to be processed as a shell command.
+If the buffer contents have not been written since the last change,
+a warning will be printed before the command is executed:
+.DS I 1i
+[No write since last change]
+.DE
+The editor prints a ``!'' when the command is completed.
+Other tutorials describe useful features of the system,
+of which an editor is only one part.
+.SH
+Filenames and file manipulation
+.PP
+Throughout each editing session,
+edit keeps track of the name of the file being edited as the
+.I "current filename."
+Edit remembers as the current filename the name given
+when you entered the editor.
+The current filename changes whenever the edit (e) command
+is used to specify a new file.
+Once edit has recorded a current filename,
+it inserts that name into any command where a filename has been omitted.
+If a write command does not specify a file,
+edit, as we have seen, supplies the current filename.
+If you are editing a file named ``draft3'' having 283 lines in it,
+you can have the editor write onto a different file
+by including its name in the write command:
+.DS I 1i
+:\fB\|w chapter3
+.R
+"chapter3" [new file] 283 lines, 8698 characters
+.DE
+The current filename remembered by the editor
+.I
+will not be changed as a result of the write command.
+.R
+Thus, if the next write command
+does not specify a name,
+edit will write onto the current file (``draft3'')
+and not onto the file ``chapter3''.
+.SH
+The file (f) command
+.PP
+To ask for the current filename, type
+.B file
+(or
+.B f ).
+In response, the editor provides current information about the buffer,
+including the filename, your current position, the number of
+lines in the buffer,
+and the percent of the distance through the file
+your current location is.
+.DS I 1i
+:\|\fBf
+.R
+"text" [Modified] line 3 of 4 --75%--
+.DE
+.\"The expression ``[Edited]'' indicates that the buffer contains
+.\"either the editor's copy of the existing file ``text''
+.\"or a file which you are just now creating.
+If the contents of the buffer have changed
+since the last time the file was written,
+the editor will tell you that the file has been ``[Modified]''.
+After you save the changes by writing onto a disk file,
+the buffer will no longer be considered modified:
+.DS I 1i
+:\|\fBw
+.R
+"text" 4 lines, 88 characters
+:\|\fBf
+.R
+"text" line 3 of 4 --75%--
+.DE
+.SH
+Reading additional files (r)
+.PP
+The
+\f3read (r)\f1 command allows you to add the contents of a file
+to the buffer
+at a specified location,
+essentially copying new lines
+between two existing lines.
+To use it, specify the line after which the new text will be placed,
+the \f3read (r)\f1 command,
+and then the name of the file.
+If you have a file named ``example'', the command
+.DS I 1i
+:\|\fB$r example
+.R
+"example" 18 lines, 473 characters
+.DE
+reads the file ``example''
+and adds it to the buffer after the last line.
+The current filename is not changed by the read command.
+.SH
+Writing parts of the buffer
+.PP
+The
+.B
+write (w)
+.R
+command can write all or part of the buffer
+to a file you specify.
+We are already familiar with
+writing the entire contents of the
+buffer to a disk file.
+To write only part of the buffer onto a file,
+indicate the beginning and ending lines before the write command,
+for example
+.DS I 1i
+:\|\fB45,$w ending
+.R
+.DE
+Here all lines from 45 through the end of the buffer
+are written onto the file named
+.I ending.
+The lines remain in the buffer
+as part of the document you are editing,
+and you may continue to edit the entire buffer.
+Your original file is unaffected
+by your command to write part of the buffer
+to another file.
+Edit still remembers whether you have saved changes to the buffer
+in your original file or not.
+.SH
+Recovering files
+.PP
+Although it does not happen very often,
+there are times \s-2UNIX\s+2 stops working
+because of some malfunction.
+This situation is known as a \fIcrash\fR.
+Under most circumstances,
+edit's crash recovery feature
+is able to save work to within a few lines of changes
+before a crash (or an accidental phone hang up).
+If you lose the contents of an editing buffer in a system crash,
+you will normally receive mail when you login that gives
+the name of the recovered file.
+To recover the file,
+enter the editor and type the command
+.B recover
+(\fBrec\fR),
+followed by the name of the lost file.
+For example,
+to recover the buffer for an edit session
+involving the file ``chap6'', the command is:
+.DS I 1i
+.R
+:\|\fBrecover chap6
+.R
+.DE
+Recover is sometimes unable to save the entire buffer successfully,
+so always check the contents of the saved buffer carefully
+before writing it back onto the original file.
+For best results,
+write the buffer to a new file temporarily
+so you can examine it without risk to the original file.
+Unfortunately,
+you cannot use the recover command
+to retrieve a file you removed
+using the shell command \f3rm\f1.
+.SH
+Other recovery techniques
+.PP
+If something goes wrong when you are using the editor,
+it may be possible to save your work by using the command
+.B preserve
+(\fBpre\fR),
+which saves the buffer as if the system had crashed.
+If you are writing a file and you get the message
+``Quota exceeded'', you have tried to use more disk storage
+than is allotted to your account.
+.I
+Proceed with caution
+.R
+because it is likely that only a part
+of the editor's buffer is now present in the file you tried to write.
+In this case you should use the shell escape from the editor (!)
+to remove some files you don't need and try to write
+the file again.
+If this is not possible and you cannot find someone to help you,
+enter the command
+.DS I 1i
+:\|\fBpreserve
+.R
+.DE
+and wait for the reply,
+.DS I 1i
+File preserved.
+.DE
+If you do not receive this reply,
+seek help immediately.
+Do not simply leave the editor.
+If you do, the buffer will be lost,
+and you may not be able to save your file.
+If the reply is ``File preserved.''
+you can leave the editor
+(or logout)
+to remedy the situation.
+After a preserve, you can use the recover command
+once the problem has been corrected,
+or the \fB\-r\fR option of the edit command
+if you leave the editor and want to return.
+.PP
+If you make an undesirable change to the buffer
+and type a write command before discovering your mistake,
+the modified version will replace any previous version of the file.
+Should you ever lose a good version of a document in this way,
+do not panic and leave the editor.
+As long as you stay in the editor,
+the contents of the buffer remain accessible.
+Depending on the nature of the problem,
+it may be possible
+to restore the buffer to a more complete
+state with the undo command.
+After fixing the damaged buffer, you can again write the file
+to disk.
+.SH
+Further reading and other information
+.PP
+Edit is an editor designed for beginning and casual users.
+It is actually a version of a more powerful editor called
+.I ex.
+These lessons are intended to introduce you to the editor
+and its more commonly-used commands.
+We have not covered all of the editor's commands,
+but a selection of commands
+that should be sufficient to accomplish most of your editing tasks.
+You can find out more about the editor in the
+.I
+Ex Reference Manual,
+.R
+which is applicable to both
+.I ex
+and
+.I edit.
+One way to become familiar with the manual is to begin by reading
+the description of commands that you already know.
+.bd I 3
+.SH
+Using
+.I ex
+.fl
+.bd I
+.PP
+As you become more experienced with using the editor,
+you may still find that edit continues to meet your needs.
+However, should you become interested in using
+.I ex,
+it is easy to switch.
+To begin an editing session with
+.I ex,
+use the name
+.B ex
+in your command instead of
+.B edit.
+.PP
+Edit commands also work in
+.I ex,
+but the editing environment is somewhat different.
+You should be aware of a few differences
+between
+.I ex
+and
+.I edit.
+In edit, only the characters ``^'', ``$'', and ``\\'' have
+special meanings in searching the buffer
+or indicating characters to be changed by a substitute command.
+Several additional characters have special
+meanings in ex, as described in the
+.I
+Ex Reference Manual.
+.R
+Another feature of the edit environment prevents users from
+accidently entering two alternative modes of editing,
+.I open
+and
+.I visual,
+in which
+the editor behaves quite differently from normal command mode.
+If you are using ex and you encounter strange behavior,
+you may have accidently entered open mode by typing ``o''.
+Type the \s-2ESC\s0 key and then a ``Q''
+to get out of open or visual mode and back into
+the regular editor command mode.
+The document
+.I
+An Introduction to Display Editing with Vi\|\|
+.R
+provide full details of visual mode.
+.bp
+.SH
+.ce 1
+\s+2Index\s0
+.LP
+.sp 2
+.2C
+.nf
+addressing, \fIsee\fR line numbers
+ampersand, 20
+append mode, 6-7
+append (a) command, 6, 7, 9
+``At end of file'' (message), 18
+backslash (\\), 21
+buffer, 3
+caret (^), 10, 20
+change (c) command, 18
+command mode, 5-6
+``Command not found'' (message), 6
+context search, 10-12, 19-21
+control characters (``^'' notation), 10
+control-H, 7
+copy (co) command, 15
+corrections, 7, 16
+current filename, 21
+current line (\|.\|), 11, 17
+delete (d) command, 15-16
+dial-up, 5
+disk, 3
+documentation, 3, 23
+dollar ($), 10, 11, 17, 20-21
+dot (\f3\|.\|\f1) 11, 17
+edit (text editor), 3, 5, 23
+edit (e) command, 5, 9, 14
+editing commands:
+.in +.25i
+append (a), 6, 7, 9
+change (c), 18
+copy (co), 15
+delete (d), 15-16
+edit (text editor), 3, 5, 23
+edit (e), 5, 9, 14
+file (f), 21-22
+global (g), 19
+move (m), 14-15
+number (nu), 11
+preserve (pre), 22-23
+print (p), 10
+quit (q), 8, 13
+read (r), 22
+recover (rec), 22, 23
+substitute (s), 11-12, 19, 20
+undo (u), 16-17, 23
+write (w), 8, 13, 21, 22
+z, 12-13
+! (shell escape), 21
+$=, 17
++, 17
+\-, 17
+//, 12, 20
+??, 20
+\&., 11, 17
+\&.=, 11, 17
+.in -.25i
+entering text, 3, 6-7
+erasing
+.in +.25i
+characters (^H), 7
+lines (@), 7
+.in -.25i
+error corrections, 7, 16
+ex (text editor), 23
+\fIEx Reference Manual\fR, 23
+exclamation (!), 21
+file, 3
+file (f) command, 21-22
+file recovery, 22-23
+filename, 3, 21
+global (g) command, 19
+input mode, 6-7
+Interrupt (message), 9
+line numbers, \fIsee also\fR current line
+.in +.25i
+dollar sign ($), 10, 11, 17
+dot (\|.\|), 11, 17
+relative (+ and \-), 17
+.in -.25i
+list, 10
+logging in, 4-6
+logging out, 8
+``Login incorrect'' (message), 5
+minus (\-), 17
+move (m) command, 14-15
+``Negative address\(emfirst buffer line is 1'' (message), 18
+``No current filename'' (message), 8
+``No such file or directory'' (message), 5, 6
+``No write since last change'' (message), 21
+non-printing characters, 10
+``Nonzero address required'' (message), 18
+``Not an editor command'' (message), 6
+``Not that many lines in buffer'' (message), 18
+number (nu) command, 11
+password, 5
+period (\|.\|), 11, 17
+plus (+), 17
+preserve (pre) command, 22-23
+print (p) command, 10
+program, 3
+prompts
+.in .25i
+% (\s-2UNIX\s0), 5
+: (edit), 5, 6, 7
+\0 (append), 7
+.in -.25i
+question (?), 20
+quit (q) command, 8, 13
+read (r) command, 22
+recover (rec) command, 22, 23
+recovery, \fIsee\fR\| file recovery
+references, 3, 23
+remove (rm) command, 21, 22
+reverse command effects (undo), 16-17, 23
+searching, 10-12, 19-21
+shell, 21
+shell escape (!), 21
+slash (/), 11-12, 20
+special characters (^, $, \\), 10, 11, 17, 20-21
+substitute (s) command, 11-12, 19, 20
+terminals, 4-5
+text input mode, 7
+undo (u) command, 16-17, 23
+\s-1UNIX\s0, 3
+write (w) command, 8, 13, 21, 22
+z command, 12-13
+
diff --git a/usr.bin/vi/docs/USD.doc/ex/Makefile b/usr.bin/vi/docs/USD.doc/ex/Makefile
new file mode 100644
index 000000000000..33ab77080f4a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/13.ex
+SRCS= ex.rm
+MACROS= -ms
+CLEANFILES=summary.*
+
+paper.ps: ${SRCS} summary.ps
+ ${ROFF} ${SRCS} > ${.TARGET}
+
+summary.ps: ex.summary
+ ${TBL} ex.summary | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/ex/ex.rm b/usr.bin/vi/docs/USD.doc/ex/ex.rm
new file mode 100644
index 000000000000..79670c2cf66b
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/ex.rm
@@ -0,0 +1,2230 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)ex.rm 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:13-%''Ex Reference Manual'
+.OH 'Ex Reference Manual''USD:13-%'
+.de ZP
+.nr pd \\n()P
+.nr )P 0
+.if \\n(.$=0 .IP
+.if \\n(.$=1 .IP "\\$1"
+.if \\n(.$>=2 .IP "\\$1" "\\$2"
+.nr )P \\n(pd
+.rm pd
+..
+.de LC
+.br
+.sp .1i
+.ne 4
+.LP
+.ta 4.0i
+..
+.bd S B 3
+.\".RP
+.TL
+Ex Reference Manual
+.br
+Version 3.7
+.AU
+William Joy
+.AU
+Mark Horton
+.AI
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, Ca. 94720
+.AB
+.I Ex
+a line oriented text editor, which supports both command and display
+oriented editing.
+This reference manual describes the command oriented part of
+.I ex;
+the display editing features of
+.I ex
+are described in
+.I "An Introduction to Display Editing with Vi."
+Other documents about the editor include the introduction
+.I "Edit: A tutorial",
+the
+.I "Ex/edit Command Summary",
+and a
+.I "Vi Quick Reference"
+card.
+.AE
+.NH 1
+Starting ex
+.PP
+.FS
+The financial support of an \s-2IBM\s0 Graduate Fellowship and the National
+Science Foundation under grants MCS74-07644-A03 and MCS78-07291 is gratefully
+acknowledged.
+.FE
+Each instance of the editor has a set of options,
+which can be set to tailor it to your liking.
+The command
+.I edit
+invokes a version of
+.I ex
+designed for more casual or beginning
+users by changing the default settings of some of these options.
+To simplify the description which follows we
+assume the default settings of the options.
+.PP
+When invoked,
+.I ex
+determines the terminal type from the \s-2TERM\s0 variable in the environment.
+It there is a \s-2TERMCAP\s0 variable in the environment, and the type
+of the terminal described there matches the \s-2TERM\s0 variable,
+then that description
+is used. Also if the \s-2TERMCAP\s0 variable contains a pathname (beginning
+with a \fB/\fR) then the editor will seek the description of the terminal
+in that file (rather than the default /etc/termcap).
+If there is a variable \s-2EXINIT\s0 in the environment, then the editor
+will execute the commands in that variable,
+otherwise if there is a file
+.I \&.exrc
+in your \s-2HOME\s0 directory
+.I ex
+reads commands from that file, simulating a
+.I source
+command.
+Option setting commands placed in
+\s-2EXINIT\s0 or
+.I \&.exrc
+will be executed before each editor session.
+.PP
+A command to enter
+.I ex
+has the following prototype:\(dg
+.FS
+\(dg Brackets `[' `]' surround optional parameters here.
+.FE
+.DS
+\fBex\fP [ \fB\-\fP ] [ \fB\-v\fP ] [ \fB\-t\fP \fItag\fP ] [ \fB\-r\fP ] [ \fB\-l\fP ] [ \fB\-w\fP\fIn\fP ] [ \fB\-x\fP ] [ \fB\-R\fP ] [ \fB+\fP\fIcommand\fP ] name ...
+.DE
+The most common case edits a single file with no options, i.e.:
+.DS
+\fBex\fR name
+.DE
+The
+.B \-
+command line option
+option suppresses all interactive-user feedback
+and is useful in processing editor scripts in command files.
+The
+.B \-v
+option is equivalent to using
+.I vi
+rather than
+.I ex.
+The
+.B \-t
+option is equivalent to an initial
+.I tag
+command, editing the file containing the
+.I tag
+and positioning the editor at its definition.
+The
+.B \-r
+option is used in recovering after an editor or system crash,
+retrieving the last saved version of the named file or,
+if no file is specified,
+typing a list of saved files.
+The
+.B \-l
+option sets up for editing \s-2LISP\s0, setting the
+.I showmatch
+and
+.I lisp
+options.
+The
+.B \-w
+option sets the default window size to
+.I n,
+and is useful on dialups to start in small windows.
+The
+.B \-x
+option causes
+.I ex
+to prompt for a
+.I key ,
+which is used to encrypt and decrypt the contents of the file,
+which should already be encrypted using the same key,
+see
+.I crypt (1).
+The
+.B \-R
+option sets the
+.I readonly
+option at the start.
+.I Name
+arguments indicate files to be edited.
+An argument of the form
+\fB+\fIcommand\fR
+indicates that the editor should begin by executing the specified command.
+If
+.I command
+is omitted, then it defaults to ``$'', positioning the editor at the last
+line of the first file initially. Other useful commands here are scanning
+patterns of the form ``/pat'' or line numbers, e.g. ``+100'' starting
+at line 100.
+.NH 1
+File manipulation
+.NH 2
+Current file
+.PP
+.I Ex
+is normally editing the contents of a single file,
+whose name is recorded in the
+.I current
+file name.
+.I Ex
+performs all editing actions in a buffer
+(actually a temporary file)
+into which the text of the file is initially read.
+Changes made to the buffer have no effect on the file being
+edited unless and until the buffer contents are written out to the
+file with a
+.I write
+command.
+After the buffer contents are written,
+the previous contents of the written file are no longer accessible.
+When a file is edited,
+its name becomes the current file name,
+and its contents are read into the buffer.
+.PP
+The current file is almost always considered to be
+.I edited.
+This means that the contents of the buffer are logically
+connected with the current file name,
+so that writing the current buffer contents onto that file,
+even if it exists,
+is a reasonable action.
+If the current file is not
+.I edited
+then
+.I ex
+will not normally write on it if it already exists.*
+.FS
+* The
+.I file
+command will say ``[Not edited]'' if the current file is not considered
+edited.
+.FE
+.NH 2
+Alternate file
+.PP
+Each time a new value is given to the current file name,
+the previous current file name is saved as the
+.I alternate
+file name.
+Similarly if a file is mentioned but does not become the current file,
+it is saved as the alternate file name.
+.NH 2
+Filename expansion
+.PP
+Filenames within the editor may be specified using the normal
+shell expansion conventions.
+In addition,
+the character `%' in filenames is replaced by the
+.I current
+file name and the character
+`#' by the
+.I alternate
+file name.\(dg
+.FS
+\(dg This makes it easy to deal alternately with
+two files and eliminates the need for retyping the
+name supplied on an
+.I edit
+command after a
+.I "No write since last change"
+diagnostic is received.
+.FE
+.NH 2
+Multiple files and named buffers
+.PP
+If more than one file is given on the command line,
+then the first file is edited as described above.
+The remaining arguments are placed with the first file in the
+.I "argument list."
+The current argument list may be displayed with the
+.I args
+command.
+The next file in the argument list may be edited with the
+.I next
+command.
+The argument list may also be respecified by specifying
+a list of names to the
+.I next
+command.
+These names are expanded,
+the resulting list of names becomes the new argument list,
+and
+.I ex
+edits the first file on the list.
+.PP
+For saving blocks of text while editing, and especially when editing
+more than one file,
+.I ex
+has a group of named buffers.
+These are similar to the normal buffer, except that only a limited number
+of operations are available on them.
+The buffers have names
+.I a
+through
+.I z.\(dd
+.FS
+\(dd It is also possible to refer to
+.I A
+through
+.I Z;
+the upper case buffers are the same as the lower but commands
+append to named buffers rather than replacing
+if upper case names are used.
+.FE
+.NH 2
+Read only
+.PP
+It is possible to use
+.I ex
+in
+.I "read only"
+mode to look at files that you have no intention of modifying.
+This mode protects you from accidently overwriting the file.
+Read only mode is on when the
+.I readonly
+option is set.
+It can be turned on with the
+.B \-R
+command line option,
+by the
+.I view
+command line invocation,
+or by setting the
+.I readonly
+option.
+It can be cleared by setting
+.I noreadonly .
+It is possible to write, even while in read only mode, by indicating
+that you really know what you are doing.
+You can write to a different file, or can use the ! form of write,
+even while in read only mode.
+.NH 1
+Exceptional Conditions
+.NH 2
+Errors and interrupts
+.PP
+When errors occur
+.I ex
+(optionally) rings the terminal bell and, in any case, prints an error
+diagnostic. If the primary input is from a file, editor processing
+will terminate. If an interrupt signal is received,
+.I ex
+prints ``Interrupt'' and returns to its command level. If the primary
+input is a file, then
+.I ex
+will exit when this occurs.
+.NH 2
+Recovering from hangups and crashes
+.PP
+If a hangup signal is received and the buffer has been modified since
+it was last written out, or if the system crashes, either the editor
+(in the first case) or the system (after it reboots in the second) will
+attempt to preserve the buffer. The next time you log in you should be
+able to recover the work you were doing, losing at most a few lines of
+changes from the last point before the hangup or editor crash. To
+recover a file you can use the
+.B \-r
+option. If you were editing the file
+.I resume,
+then you should change
+to the directory where you were when the crash occurred, giving the command
+.DS
+\fBex \-r\fP\fI resume\fP
+.DE
+After checking that the retrieved file is indeed ok, you can
+.I write
+it over the previous contents of that file.
+.PP
+You will normally get mail from the system telling you when a file has
+been saved after a crash. The command
+.DS
+\fBex\fP \-\fBr\fP
+.DE
+will print a list of the files which have been saved for you.
+(In the case of a hangup,
+the file will not appear in the list,
+although it can be recovered.)
+.NH 1
+Editing modes
+.PP
+.I Ex
+has five distinct modes. The primary mode is
+.I command
+mode. Commands are entered in command mode when a `:' prompt is
+present, and are executed each time a complete line is sent. In
+.I "text input"
+mode
+.I ex
+gathers input lines and places them in the file. The
+.I append,
+.I insert,
+and
+.I change
+commands use text input mode.
+No prompt is printed when you are in text input mode.
+This mode is left by typing a `.' alone at the beginning of a line, and
+.I command
+mode resumes.
+.PP
+The last three modes are
+.I open
+and
+.I visual
+modes, entered by the commands of the same name, and, within open and
+visual modes
+.I "text insertion"
+mode.
+.I Open
+and
+.I visual
+modes allow local editing operations to be performed on the text in the
+file. The
+.I open
+command displays one line at a time on any terminal while
+.I visual
+works on \s-2CRT\s0 terminals with random positioning cursors, using the
+screen as a (single) window for file editing changes.
+These modes are described (only) in
+.I "An Introduction to Display Editing with Vi."
+.NH
+Command structure
+.PP
+Most command names are English words,
+and initial prefixes of the words are acceptable abbreviations.
+The ambiguity of abbreviations is resolved in favor of the more commonly
+used commands.*
+.FS
+* As an example, the command
+.I substitute
+can be abbreviated `s'
+while the shortest available abbreviation for the
+.I set
+command is `se'.
+.FE
+.NH 2
+Command parameters
+.PP
+Most commands accept prefix addresses specifying the lines in the file
+upon which they are to have effect.
+The forms of these addresses will be discussed below.
+A number of commands also may take a trailing
+.I count
+specifying the number of lines to be involved in the command.\(dg
+.FS
+\(dg Counts are rounded down if necessary.
+.FE
+Thus the command ``10p'' will print the tenth line in the buffer while
+``delete 5'' will delete five lines from the buffer,
+starting with the current line.
+.PP
+Some commands take other information or parameters,
+this information always being given after the command name.\(dd
+.FS
+\(dd Examples would be option names in a
+.I set
+command i.e. ``set number'',
+a file name in an
+.I edit
+command,
+a regular expression in a
+.I substitute
+command,
+or a target address for a
+.I copy
+command, i.e. ``1,5 copy 25''.
+.FE
+.NH 2
+Command variants
+.PP
+A number of commands have two distinct variants.
+The variant form of the command is invoked by placing an
+`!' immediately after the command name.
+Some of the default variants may be controlled by options;
+in this case, the `!' serves to toggle the default.
+.NH 2
+Flags after commands
+.PP
+The characters `#', `p' and `l' may be placed after many commands.**
+.FS
+**
+A `p' or `l' must be preceded by a blank or tab
+except in the single special case `dp'.
+.FE
+In this case, the command abbreviated by these characters
+is executed after the command completes.
+Since
+.I ex
+normally prints the new current line after each change, `p' is rarely necessary.
+Any number of `+' or `\-' characters may also be given with these flags.
+If they appear, the specified offset is applied to the current line
+value before the printing command is executed.
+.NH 2
+Comments
+.PP
+It is possible to give editor commands which are ignored.
+This is useful when making complex editor scripts
+for which comments are desired.
+The comment character is the double quote: ".
+Any command line beginning with " is ignored.
+Comments beginning with " may also be placed at the ends
+of commands, except in cases where they could be confused as part
+of text (shell escapes and the substitute and map commands).
+.NH 2
+Multiple commands per line
+.PP
+More than one command may be placed on a line by separating each pair
+of commands by a `|' character.
+However the
+.I global
+commands,
+comments,
+and the shell escape `!'
+must be the last command on a line, as they are not terminated by a `|'.
+.NH 2
+Reporting large changes
+.PP
+Most commands which change the contents of the editor buffer give
+feedback if the scope of the change exceeds a threshold given by the
+.I report
+option.
+This feedback helps to detect undesirably large changes so that they may
+be quickly and easily reversed with an
+.I undo.
+After commands with more global effect such as
+.I global
+or
+.I visual,
+you will be informed if the net change in the number of lines
+in the buffer during this command exceeds this threshold.
+.NH 1
+Command addressing
+.NH 2
+Addressing primitives
+.IP \fB.\fR 20
+The current line.
+Most commands leave the current line as the last line which they affect.
+The default address for most commands is the current line,
+thus `\fB.\fR' is rarely used alone as an address.
+.IP \fIn\fR 20
+The \fIn\fRth line in the editor's buffer, lines being numbered
+sequentially from 1.
+.IP \fB$\fR 20
+The last line in the buffer.
+.IP \fB%\fR 20
+An abbreviation for ``1,$'', the entire buffer.
+.IP \fI+n\fR\ \fI\-n\fR 20
+An offset relative to the current buffer line.\(dg
+.FS
+\(dg
+The forms `.+3' `+3' and `+++' are all equivalent;
+if the current line is line 100 they all address line 103.
+.FE
+.IP \fB/\fIpat\fR\fB/\fR\ \fB?\fIpat\fR\fB?\fR 20
+Scan forward and backward respectively for a line containing \fIpat\fR, a
+regular expression (as defined below). The scans normally wrap around the end
+of the buffer.
+If all that is desired is to print the next line containing \fIpat\fR, then
+the trailing \fB/\fR or \fB?\fR may be omitted.
+If \fIpat\fP is omitted or explicitly empty, then the last
+regular expression specified is located.\(dd
+.FS
+\(dd The forms \fB\e/\fP and \fB\e?\fP scan
+using the last regular expression used in a scan; after a substitute
+\fB//\fP and \fB??\fP would scan using the substitute's regular expression.
+.FE
+.IP \fB\(aa\(aa\fP\ \fB\(aa\fP\fIx\fP 20
+Before each non-relative motion of the current line `\fB.\fP',
+the previous current line is marked with a tag, subsequently referred to as
+`\(aa\(aa'.
+This makes it easy to refer or return to this previous context.
+Marks may also be established by the
+.I mark
+command, using single lower case letters
+.I x
+and the marked lines referred to as
+`\(aa\fIx\fR'.
+.NH 2
+Combining addressing primitives
+.PP
+Addresses to commands consist of a series of addressing primitives,
+separated by `,' or `;'.
+Such address lists are evaluated left-to-right.
+When addresses are separated by `;' the current line `\fB.\fR'
+is set to the value of the previous addressing expression
+before the next address is interpreted.
+If more addresses are given than the command requires,
+then all but the last one or two are ignored.
+If the command takes two addresses, the first addressed line must
+precede the second in the buffer.\(dg
+.FS
+\(dg Null address specifications are permitted in a list of addresses,
+the default in this case is the current line `.';
+thus `,100' is equivalent to `\fB.\fR,100'.
+It is an error to give a prefix address to a command which expects none.
+.FE
+.NH 1
+Command descriptions
+.PP
+The following form is a prototype for all
+.I ex
+commands:
+.DS
+\fIaddress\fR \fBcommand\fR \fI! parameters count flags\fR
+.DE
+All parts are optional; the degenerate case is the empty command which prints
+the next line in the file. For sanity with use from within
+.I visual
+mode,
+.I ex
+ignores a ``:'' preceding any command.
+.PP
+In the following command descriptions, the
+default addresses are shown in parentheses,
+which are
+.I not,
+however,
+part of the command.
+.LC
+\fBabbreviate\fR \fIword rhs\fP abbr: \fBab\fP
+.ZP
+Add the named abbreviation to the current list.
+When in input mode in visual, if
+.I word
+is typed as a complete word, it will be changed to
+.I rhs .
+.LC
+( \fB.\fR ) \fBappend\fR abbr: \fBa\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+Reads the input text and places it after the specified line.
+After the command, `\fB.\fR'
+addresses the last line input or the
+specified line if no lines were input.
+If address `0' is given,
+text is placed at the beginning of the buffer.
+.LC
+\fBa!\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+The variant flag to
+.I append
+toggles the setting for the
+.I autoindent
+option during the input of
+.I text.
+.LC
+\fBargs\fR
+.ZP
+The members of the argument list are printed, with the current argument
+delimited by `[' and `]'.
+.ig
+.PP
+\fBcd\fR \fIdirectory\fR
+.ZP
+The
+.I cd
+command is a synonym for
+.I chdir.
+..
+.LC
+( \fB.\fP , \fB.\fP ) \fBchange\fP \fIcount\fP abbr: \fBc\fP
+.br
+\fItext\fP
+.br
+\&\fB.\fP
+.ZP
+Replaces the specified lines with the input \fItext\fP.
+The current line becomes the last line input;
+if no lines were input it is left as for a
+\fIdelete\fP.
+.LC
+\fBc!\fP
+.br
+\fItext\fP
+.br
+\&\fB.\fP
+.ZP
+The variant toggles
+.I autoindent
+during the
+.I change.
+.ig
+.LC
+\fBchdir\fR \fIdirectory\fR
+.ZP
+The specified \fIdirectory\fR becomes the current directory.
+If no directory is specified, the current value of the
+.I home
+option is used as the target directory.
+After a
+.I chdir
+the current file is not considered to have been
+edited so that write restrictions on pre-existing files apply.
+..
+.LC
+( \fB.\fP , \fB.\fP )\|\fBcopy\fP \fIaddr\fP \fIflags\fP abbr: \fBco\fP
+.ZP
+A
+.I copy
+of the specified lines is placed after
+.I addr,
+which may be `0'.
+The current line
+`\fB.\fR'
+addresses the last line of the copy.
+The command
+.I t
+is a synonym for
+.I copy.
+.LC
+( \fB.\fR , \fB.\fR )\|\fBdelete\fR \fIbuffer\fR \fIcount\fR \fIflags\fR abbr: \fBd\fR
+.ZP
+Removes the specified lines from the buffer.
+The line after the last line deleted becomes the current line;
+if the lines deleted were originally at the end,
+the new last line becomes the current line.
+If a named
+.I buffer
+is specified by giving a letter,
+then the specified lines are saved in that buffer,
+or appended to it if an upper case letter is used.
+.LC
+\fBedit\fR \fIfile\fR abbr: \fBe\fR
+.br
+\fBex\fR \fIfile\fR
+.ZP
+Used to begin an editing session on a new file.
+The editor
+first checks to see if the buffer has been modified since the last
+.I write
+command was issued.
+If it has been,
+a warning is issued and the
+command is aborted.
+The
+command otherwise deletes the entire contents of the editor buffer,
+makes the named file the current file and prints the new filename.
+After insuring that this file is sensible\(dg
+.FS
+\(dg I.e., that it is not a binary file such as a directory,
+a block or character special file other than
+.I /dev/tty,
+a terminal,
+or a binary or executable file
+(as indicated by the first word).
+.FE
+the editor reads the file into its buffer.
+.IP
+If the read of the file completes without error,
+the number of lines and characters read is typed.
+If there were any non-\s-2ASCII\s0 characters
+in the file they are stripped of their non-\s-2ASCII\s0
+high bits,
+and any null characters in the file are discarded.
+If none of these errors occurred, the file is considered
+.I edited.
+If the last line of the input file is missing the trailing
+newline character, it will be supplied and a complaint will be issued.
+This command leaves the current line `\fB.\fR' at the last line read.\(dd
+.FS
+\(dd If executed from within
+.I open
+or
+.I visual,
+the current line is initially the first line of the file.
+.FE
+.LC
+\fBe!\fR \fIfile\fR
+.ZP
+The variant form suppresses the complaint about modifications having
+been made and not written from the editor buffer, thus
+discarding all changes which have been made before editing the new file.
+.LC
+\fBe\fR \fB+\fIn\fR \fIfile\fR
+.ZP
+Causes the editor to begin at line
+.I n
+rather than at the last line;
+\fIn\fR may also be an editor command containing no spaces, e.g.: ``+/pat''.
+.LC
+\fBfile\fR abbr: \fBf\fR
+.ZP
+Prints the current file name,
+whether it has been `[Modified]' since the last
+.I write
+command,
+whether it is
+.I "read only" ,
+the current line,
+the number of lines in the buffer,
+and the percentage of the way through the buffer of the current line.*
+.FS
+* In the rare case that the current file is `[Not edited]' this is
+noted also; in this case you have to use the form \fBw!\fR to write to
+the file, since the editor is not sure that a \fBwrite\fR will not
+destroy a file unrelated to the current contents of the buffer.
+.FE
+.LC
+\fBfile\fR \fIfile\fR
+.ZP
+The current file name is changed to
+.I file
+which is considered
+`[Not edited]'.
+.LC
+( 1 , $ ) \fBglobal\fR /\fIpat\|\fR/ \fIcmds\fR abbr: \fBg\fR
+.ZP
+First marks each line among those specified which matches
+the given regular expression.
+Then the given command list is executed with `\fB.\fR' initially
+set to each marked line.
+.IP
+The command list consists of the remaining commands on the current
+input line and may continue to multiple lines by ending all but the
+last such line with a `\e'.
+If
+.I cmds
+(and possibly the trailing \fB/\fR delimiter) is omitted, each line matching
+.I pat
+is printed.
+.I Append,
+.I insert,
+and
+.I change
+commands and associated input are permitted;
+the `\fB.\fR' terminating input may be omitted if it would be on the
+last line of the command list.
+.I Open
+and
+.I visual
+commands are permitted in the command list and take input from the terminal.
+.IP
+The
+.I global
+command itself may not appear in
+.I cmds.
+The
+.I undo
+command is also not permitted there,
+as
+.I undo
+instead can be used to reverse the entire
+.I global
+command.
+The options
+.I autoprint
+and
+.I autoindent
+are inhibited during a
+.I global,
+(and possibly the trailing \fB/\fR delimiter) and the value of the
+.I report
+option is temporarily infinite,
+in deference to a \fIreport\fR for the entire global.
+Finally, the context mark `\'\'' is set to the value of
+`.' before the global command begins and is not changed during a global
+command,
+except perhaps by an
+.I open
+or
+.I visual
+within the
+.I global.
+.LC
+\fBg!\fR \fB/\fIpat\fB/\fR \fIcmds\fR abbr: \fBv\fR
+.IP
+The variant form of \fIglobal\fR runs \fIcmds\fR at each line not matching
+\fIpat\fR.
+.LC
+( \fB.\fR )\|\fBinsert\fR abbr: \fBi\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+Places the given text before the specified line.
+The current line is left at the last line input;
+if there were none input it is left at the line before the addressed line.
+This command differs from
+.I append
+only in the placement of text.
+.KS
+.LC
+\fBi!\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+The variant toggles
+.I autoindent
+during the
+.I insert.
+.KE
+.LC
+( \fB.\fR , \fB.\fR+1 ) \fBjoin\fR \fIcount\fR \fIflags\fR abbr: \fBj\fR
+.ZP
+Places the text from a specified range of lines
+together on one line.
+White space is adjusted at each junction to provide at least
+one blank character, two if there was a `\fB.\fR' at the end of the line,
+or none if the first following character is a `)'.
+If there is already white space at the end of the line,
+then the white space at the start of the next line will be discarded.
+.LC
+\fBj!\fR
+.ZP
+The variant causes a simpler
+.I join
+with no white space processing; the characters in the lines are simply
+concatenated.
+.LC
+( \fB.\fR ) \fBk\fR \fIx\fR
+.ZP
+The
+.I k
+command is a synonym for
+.I mark.
+It does not require a blank or tab before the following letter.
+.LC
+( \fB.\fR , \fB.\fR ) \fBlist\fR \fIcount\fR \fIflags\fR
+.ZP
+Prints the specified lines in a more unambiguous way:
+tabs are printed as `^I'
+and the end of each line is marked with a trailing `$'.
+The current line is left at the last line printed.
+.LC
+\fBmap\fR \fIlhs\fR \fIrhs\fR
+.ZP
+The
+.I map
+command is used to define macros for use in
+.I visual
+mode.
+.I Lhs
+should be a single character, or the sequence ``#n'', for n a digit,
+referring to function key \fIn\fR. When this character or function key
+is typed in
+.I visual
+mode, it will be as though the corresponding \fIrhs\fR had been typed.
+On terminals without function keys, you can type ``#n''.
+See section 6.9 of the ``Introduction to Display Editing with Vi''
+for more details.
+.LC
+( \fB.\fR ) \fBmark\fR \fIx\fR
+.ZP
+Gives the specified line mark
+.I x,
+a single lower case letter.
+The
+.I x
+must be preceded by a blank or a tab.
+The addressing form `\'x' then addresses this line.
+The current line is not affected by this command.
+.LC
+( \fB.\fR , \fB.\fR ) \fBmove\fR \fIaddr\fR abbr: \fBm\fR
+.ZP
+The
+.I move
+command repositions the specified lines to be after
+.I addr .
+The first of the moved lines becomes the current line.
+.LC
+\fBnext\fR abbr: \fBn\fR
+.ZP
+The next file from the command line argument list is edited.
+.LC
+\fBn!\fR
+.ZP
+The variant suppresses warnings about the modifications to the buffer not
+having been written out, discarding (irretrievably) any changes which may
+have been made.
+.LC
+\fBn\fR \fIfilelist\fR
+.br
+\fBn\fR \fB+\fIcommand\fR \fIfilelist\fR
+.ZP
+The specified
+.I filelist
+is expanded and the resulting list replaces the
+current argument list;
+the first file in the new list is then edited.
+If
+.I command
+is given (it must contain no spaces), then it is executed after editing the first such file.
+.LC
+( \fB.\fR , \fB.\fR ) \fBnumber\fR \fIcount\fR \fIflags\fR abbr: \fB#\fR or \fBnu\fR
+.ZP
+Prints each specified line preceded by its buffer line
+number.
+The current line is left at the last line printed.
+.KS
+.LC
+( \fB.\fR ) \fBopen\fR \fIflags\fR abbr: \fBo\fR
+.br
+( \fB.\fR ) \fBopen\fR /\fIpat\|\fR/ \fIflags\fR
+.ZP
+Enters intraline editing \fIopen\fR mode at each addressed line.
+If
+.I pat
+is given,
+then the cursor will be placed initially at the beginning of the
+string matched by the pattern.
+To exit this mode use Q.
+See
+.I "An Introduction to Display Editing with Vi"
+for more details.
+.KE
+.LC
+\fBpreserve\fR
+.ZP
+The current editor buffer is saved as though the system had just crashed.
+This command is for use only in emergencies when a
+.I write
+command has resulted in an error and you don't know how to save your work.
+After a
+.I preserve
+you should seek help.
+.LC
+( \fB.\fR , \fB.\fR )\|\fBprint\fR \fIcount\fR abbr: \fBp\fR or \fBP\fR
+.ZP
+Prints the specified lines
+with non-printing characters printed as control characters `^\fIx\fR\|';
+delete (octal 177) is represented as `^?'.
+The current line is left at the last line printed.
+.LC
+( \fB.\fR )\|\fBput\fR \fIbuffer\fR abbr: \fBpu\fR
+.ZP
+Puts back
+previously
+.I deleted
+or
+.I yanked
+lines.
+Normally used with
+.I delete
+to effect movement of lines,
+or with
+.I yank
+to effect duplication of lines.
+If no
+.I buffer
+is specified, then the last
+.I deleted
+or
+.I yanked
+text is restored.*
+.FS
+* But no modifying commands may intervene between the
+.I delete
+or
+.I yank
+and the
+.I put,
+nor may lines be moved between files without using a named buffer.
+.FE
+By using a named buffer, text may be restored that was saved there at any
+previous time.
+.LC
+\fBquit\fR abbr: \fBq\fR
+.ZP
+Causes
+.I ex
+to terminate.
+No automatic write of the editor buffer to a file is performed.
+However,
+.I ex
+issues a warning message if the file has changed
+since the last
+.I write
+command was issued, and does not
+.I quit.\(dg
+.FS
+\(dg \fIEx\fR
+will also issue a diagnostic if there are more files in the argument
+list.
+.FE
+Normally, you will wish to save your changes, and you
+should give a \fIwrite\fR command;
+if you wish to discard them, use the \fBq!\fR command variant.
+.LC
+\fBq!\fR
+.ZP
+Quits from the editor, discarding changes to the buffer without complaint.
+.LC
+( \fB.\fR ) \fBread\fR \fIfile\fR abbr: \fBr\fR
+.ZP
+Places a copy of the text of the given file in the
+editing buffer after the specified line.
+If no
+.I file
+is given the current file name is used.
+The current file name is not changed unless there is none in which
+case
+.I file
+becomes the current name.
+The sensibility restrictions for the
+.I edit
+command apply here also.
+If the file buffer is empty and there is no current name then
+.I ex
+treats this as an
+.I edit
+command.
+.IP
+Address `0' is legal for this command and causes the file to be read at
+the beginning of the buffer.
+Statistics are given as for the
+.I edit
+command when the
+.I read
+successfully terminates.
+After a
+.I read
+the current line is the last line read.\(dd
+.FS
+\(dd Within
+.I open
+and
+.I visual
+the current line is set to the first line read rather than the last.
+.FE
+.LC
+( \fB.\fR ) \fBread\fR \fB!\fR\fIcommand\fR
+.ZP
+Reads the output of the command
+.I command
+into the buffer after the specified line.
+This is not a variant form of the command, rather a read
+specifying a
+.I command
+rather than a
+.I filename;
+a blank or tab before the \fB!\fR is mandatory.
+.LC
+\fBrecover \fIfile\fR
+.ZP
+Recovers
+.I file
+from the system save area.
+Used after a accidental hangup of the phone**
+.FS
+** The system saves a copy of the file you were editing only if you
+have made changes to the file.
+.FE
+or a system crash** or
+.I preserve
+command.
+Except when you use
+.I preserve
+you will be notified by mail when a file is saved.
+.LC
+\fBrewind\fR abbr: \fBrew\fR
+.ZP
+The argument list is rewound, and the first file in the list is edited.
+.LC
+\fBrew!\fR
+.ZP
+Rewinds the argument list discarding any changes made to the current buffer.
+.LC
+\fBset\fR \fIparameter\fR
+.ZP
+With no arguments, prints those options whose values have been
+changed from their defaults;
+with parameter
+.I all
+it prints all of the option values.
+.IP
+Giving an option name followed by a `?'
+causes the current value of that option to be printed.
+The `?' is unnecessary unless the option is Boolean valued.
+Boolean options are given values either by the form
+`set \fIoption\fR' to turn them on or
+`set no\fIoption\fR' to turn them off;
+string and numeric options are assigned via the form
+`set \fIoption\fR=value'.
+.IP
+More than one parameter may be given to
+.I set \|;
+they are interpreted left-to-right.
+.LC
+\fBshell\fR abbr: \fBsh\fR
+.IP
+A new shell is created.
+When it terminates, editing resumes.
+.LC
+\fBsource\fR \fIfile\fR abbr: \fBso\fR
+.IP
+Reads and executes commands from the specified file.
+.I Source
+commands may be nested.
+.LC
+( \fB.\fR , \fB.\fR ) \fBsubstitute\fR /\fIpat\fR\|/\fIrepl\fR\|/ \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR
+.IP
+On each specified line, the first instance of pattern
+.I pat
+is replaced by replacement pattern
+.I repl.
+If the
+.I global
+indicator option character `g'
+appears, then all instances are substituted;
+if the
+.I confirm
+indication character `c' appears,
+then before each substitution the line to be substituted
+is typed with the string to be substituted marked
+with `\(ua' characters.
+By typing an `y' one can cause the substitution to be performed,
+any other input causes no change to take place.
+After a
+.I substitute
+the current line is the last line substituted.
+.IP
+Lines may be split by substituting
+new-line characters into them.
+The newline in
+.I repl
+must be escaped by preceding it with a `\e'.
+Other metacharacters available in
+.I pat
+and
+.I repl
+are described below.
+.LC
+.B stop
+.ZP
+Suspends the editor, returning control to the top level shell.
+If
+.I autowrite
+is set and there are unsaved changes,
+a write is done first unless the form
+.B stop !
+is used.
+This commands is only available where supported by the teletype driver
+and operating system.
+.LC
+( \fB.\fR , \fB.\fR ) \fBsubstitute\fR \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR
+.ZP
+If
+.I pat
+and
+.I repl
+are omitted, then the last substitution is repeated.
+This is a synonym for the
+.B &
+command.
+.LC
+( \fB.\fR , \fB.\fR ) \fBt\fR \fIaddr\fR \fIflags\fR
+.ZP
+The
+.I t
+command is a synonym for
+.I copy .
+.LC
+\fBta\fR \fItag\fR
+.ZP
+The focus of editing switches to the location of
+.I tag,
+switching to a different line in the current file where it is defined,
+or if necessary to another file.\(dd
+.FS
+\(dd If you have modified the current file before giving a
+.I tag
+command, you must write it out; giving another
+.I tag
+command, specifying no
+.I tag
+will reuse the previous tag.
+.FE
+.IP
+The tags file is normally created by a program such as
+.I ctags,
+and consists of a number of lines with three fields separated by blanks
+or tabs. The first field gives the name of the tag,
+the second the name of the file where the tag resides, and the third
+gives an addressing form which can be used by the editor to find the tag;
+this field is usually a contextual scan using `/\fIpat\fR/' to be immune
+to minor changes in the file. Such scans are always performed as if
+.I nomagic
+was set.
+.PP
+The tag names in the tags file must be sorted alphabetically.
+.LC
+\fBunabbreviate\fR \fIword\fP abbr: \fBuna\fP
+.ZP
+Delete
+.I word
+from the list of abbreviations.
+.LC
+\fBundo\fR abbr: \fBu\fR
+.ZP
+Reverses the changes made in the buffer by the last
+buffer editing command.
+Note that
+.I global
+commands are considered a single command for the purpose of
+.I undo
+(as are
+.I open
+and
+.I visual.)
+Also, the commands
+.I write
+and
+.I edit
+which interact with the
+file system cannot be undone.
+.I Undo
+is its own inverse.
+.IP
+.I Undo
+always marks the previous value of the current line `\fB.\fR'
+as `\'\''.
+After an
+.I undo
+the current line is the first line restored
+or the line before the first line deleted if no lines were restored.
+For commands with more global effect
+such as
+.I global
+and
+.I visual
+the current line regains it's pre-command value after an
+.I undo.
+.LC
+\fBunmap\fR \fIlhs\fR
+.ZP
+The macro expansion associated by
+.I map
+for
+.I lhs
+is removed.
+.LC
+( 1 , $ ) \fBv\fR /\fIpat\fR\|/ \fIcmds\fR
+.ZP
+A synonym for the
+.I global
+command variant \fBg!\fR, running the specified \fIcmds\fR on each
+line which does not match \fIpat\fR.
+.LC
+\fBversion\fR abbr: \fBve\fR
+.ZP
+Prints the current version number of the editor
+as well as the date the editor was last changed.
+.LC
+( \fB.\fR ) \fBvisual\fR \fItype\fR \fIcount\fR \fIflags\fR abbr: \fBvi\fR
+.ZP
+Enters visual mode at the specified line.
+.I Type
+is optional and may be `\-' , `\(ua' or `\fB.\fR'
+as in the
+.I z
+command to specify the placement of the specified line on the screen.
+By default, if
+.I type
+is omitted, the specified line is placed as the first on the screen.
+A
+.I count
+specifies an initial window size; the default is the value of the option
+.I window.
+See the document
+.I "An Introduction to Display Editing with Vi"
+for more details.
+To exit this mode, type Q.
+.LC
+\fBvisual\fP file
+.br
+\fBvisual\fP +\fIn\fP file
+.ZP
+From visual mode,
+this command is the same as edit.
+.LC
+( 1 , $ ) \fBwrite\fR \fIfile\fR abbr: \fBw\fR
+.ZP
+Writes changes made back to \fIfile\fR, printing the number of lines and
+characters written.
+Normally \fIfile\fR is omitted and the text goes back where it came from.
+If a \fIfile\fR is specified, then text will be written to that file.*
+.FS
+* The editor writes to a file only if it is
+the current file and is
+.I edited ,
+if the file does not exist,
+or if the file is actually a teletype,
+.I /dev/tty,
+.I /dev/null.
+Otherwise, you must give the variant form \fBw!\fR to force the write.
+.FE
+If the file does not exist it is created.
+The current file name is changed only if there is no current file
+name; the current line is never changed.
+.IP
+If an error occurs while writing the current and
+.I edited
+file, the editor
+considers that there has been ``No write since last change''
+even if the buffer had not previously been modified.
+.LC
+( 1 , $ ) \fBwrite>>\fR \fIfile\fR abbr: \fBw>>\fR
+.ZP
+Writes the buffer contents at the end of
+an existing file.
+.IP
+.LC
+\fBw!\fR \fIname\fR
+.ZP
+Overrides the checking of the normal \fIwrite\fR command,
+and will write to any file which the system permits.
+.LC
+( 1 , $ ) \fBw\fR \fB!\fR\fIcommand\fR
+.ZP
+Writes the specified lines into
+.I command.
+Note the difference between \fBw!\fR which overrides checks and
+\fBw\ \ !\fR which writes to a command.
+.LC
+\fBwq\fR \fIname\fR
+.ZP
+Like a \fIwrite\fR and then a \fIquit\fR command.
+.LC
+\fBwq!\fR \fIname\fR
+.ZP
+The variant overrides checking on the sensibility of the
+.I write
+command, as \fBw!\fR does.
+.LC
+\fBxit\fP \fIname\fR
+.ZP
+If any changes have been made and not written, writes the buffer out.
+Then, in any case, quits.
+.LC
+( \fB.\fR , \fB.\fR )\|\fByank\fR \fIbuffer\fR \fIcount\fR abbr: \fBya\fR
+.ZP
+Places the specified lines in the named
+.I buffer,
+for later retrieval via
+.I put.
+If no buffer name is specified, the lines go to a more volatile place;
+see the \fIput\fR command description.
+.LC
+( \fB.+1\fR ) \fBz\fR \fIcount\fR
+.ZP
+Print the next \fIcount\fR lines, default \fIwindow\fR.
+.LC
+( \fB.\fR ) \fBz\fR \fItype\fR \fIcount\fR
+.ZP
+Prints a window of text with the specified line at the top.
+If \fItype\fR is `\-' the line is placed at the bottom; a `\fB.\fR' causes
+the line to be placed in the center.*
+A count gives the number of lines to be displayed rather than
+double the number specified by the \fIscroll\fR option.
+On a \s-2CRT\s0 the screen is cleared before display begins unless a
+count which is less than the screen size is given.
+The current line is left at the last line printed.
+.FS
+* Forms `z=' and `z\(ua' also exist; `z=' places the current line in the
+center, surrounds it with lines of `\-' characters and leaves the current
+line at this line. The form `z\(ua' prints the window before `z\-'
+would. The characters `+', `\(ua' and `\-' may be repeated for cumulative
+effect.
+On some v2 editors, no
+.I type
+may be given.
+.FE
+.LC
+\fB!\fR \fIcommand\fR\fR
+.ZP
+The remainder of the line after the `!' character is sent to a shell
+to be executed.
+Within the text of
+.I command
+the characters
+`%' and `#' are expanded as in filenames and the character
+`!' is replaced with the text of the previous command.
+Thus, in particular,
+`!!' repeats the last such shell escape.
+If any such expansion is performed, the expanded line will be echoed.
+The current line is unchanged by this command.
+.IP
+If there has been ``[No\ write]'' of the buffer contents since the last
+change to the editing buffer, then a diagnostic will be printed
+before the command is executed as a warning.
+A single `!' is printed when the command completes.
+.LC
+( \fIaddr\fR , \fIaddr\fR ) \fB!\fR \fIcommand\fR\fR
+.ZP
+Takes the specified address range and supplies it as
+standard input to
+.I command;
+the resulting output then replaces the input lines.
+.LC
+( $ ) \fB=\fR
+.ZP
+Prints the line number of the
+addressed line.
+The current line is unchanged.
+.KS
+.LC
+( \fB.\fR , \fB.\fR ) \fB>\fR \fIcount\fR \fIflags\fR
+.br
+( \fB.\fR , \fB.\fR ) \fB<\fR \fIcount\fR \fIflags\fR
+.IP
+Perform intelligent shifting on the specified lines;
+\fB<\fR shifts left and \fB>\fR shift right.
+The quantity of shift is determined by the
+.I shiftwidth
+option and the repetition of the specification character.
+Only white space (blanks and tabs) is shifted;
+no non-white characters are discarded in a left-shift.
+The current line becomes the last line which changed due to the
+shifting.
+.KE
+.LC
+\fB^D\fR
+.ZP
+An end-of-file from a terminal input scrolls through the file.
+The
+.I scroll
+option specifies the size of the scroll, normally a half screen of text.
+.LC
+( \fB.\fR+1 , \fB.\fR+1 )
+.br
+( \fB.\fR+1 , \fB.\fR+1 ) |
+.ZP
+An address alone causes the addressed lines to be printed.
+A blank line prints the next line in the file.
+.LC
+( \fB.\fR , \fB.\fR ) \fB&\fR \fIoptions\fR \fIcount\fR \fIflags\fR
+.ZP
+Repeats the previous
+.I substitute
+command.
+.LC
+( \fB.\fR , \fB.\fR ) \fB\s+2~\s0\fR \fIoptions\fR \fIcount\fR \fIflags\fR
+.ZP
+Replaces the previous regular expression with the previous
+replacement pattern from a substitution.
+.NH 1
+Regular expressions and substitute replacement patterns
+.NH 2
+Regular expressions
+.PP
+A regular expression specifies a set of strings of characters.
+A member of this set of strings is said to be
+.I matched
+by the regular expression.
+.I Ex
+remembers two previous regular expressions:
+the previous regular expression used in a
+.I substitute
+command
+and the previous regular expression used elsewhere
+(referred to as the previous \fIscanning\fR regular expression.)
+The previous regular expression
+can always be referred to by a null \fIre\fR, e.g. `//' or `??'.
+.NH 2
+Magic and nomagic
+.PP
+The regular expressions allowed by
+.I ex
+are constructed in one of two ways depending on the setting of
+the
+.I magic
+option.
+The
+.I ex
+and
+.I vi
+default setting of
+.I magic
+gives quick access to a powerful set of regular expression
+metacharacters.
+The disadvantage of
+.I magic
+is that the user must remember that these metacharacters are
+.I magic
+and precede them with the character `\e'
+to use them as ``ordinary'' characters.
+With
+.I nomagic,
+the default for
+.I edit,
+regular expressions are much simpler,
+there being only two metacharacters.
+The power of the other metacharacters is still available by preceding
+the (now) ordinary character with a `\e'.
+Note that `\e' is thus always a metacharacter.
+.PP
+The remainder of the discussion of regular expressions assumes
+that
+that the setting of this option is
+.I magic.\(dg
+.FS
+\(dg To discern what is true with
+.I nomagic
+it suffices to remember that the only
+special characters in this case will be `\(ua' at the beginning
+of a regular expression,
+`$' at the end of a regular expression,
+and `\e'.
+With
+.I nomagic
+the characters `\s+2~\s0' and `&' also lose their special meanings
+related to the replacement pattern of a substitute.
+.FE
+.NH 2
+Basic regular expression summary
+.PP
+The following basic constructs are used to construct
+.I magic
+mode regular expressions.
+.IP \fIchar\fR 15
+An ordinary character matches itself.
+The characters `\(ua' at the beginning of a line,
+`$' at the end of line,
+`*' as any character other than the first,
+`.', `\e', `[', and `\s+2~\s0' are not ordinary characters and
+must be escaped (preceded) by `\e' to be treated as such.
+.IP \fB\(ua\fR
+At the beginning of a pattern
+forces the match to succeed only at the beginning of a line.
+.IP \fB$\fR
+At the end of a regular expression forces the match to
+succeed only at the end of the line.
+.IP \&\fB.\fR
+Matches any single character except
+the new-line character.
+.IP \fB\e<\fR
+Forces the match
+to occur only at the beginning of a ``variable'' or ``word'';
+that is, either at the beginning of a line, or just before
+a letter, digit, or underline and after a character not one of
+these.
+.IP \fB\e>\fR
+Similar to `\e<', but matching the end of a ``variable''
+or ``word'', i.e. either the end of the line or before character
+which is neither a letter, nor a digit, nor the underline character.
+.IP \fB[\fIstring\fR]\fR
+Matches any (single) character in the class defined by
+.I string.
+Most characters in
+.I string
+define themselves.
+A pair of characters separated by `\-' in
+.I string
+defines the set of characters collating between the specified lower and upper
+bounds, thus `[a\-z]' as a regular expression matches
+any (single) lower-case letter.
+If the first character of
+.I string
+is an `\(ua' then the construct
+matches those characters which it otherwise would not;
+thus `[\(uaa\-z]' matches anything but a lower-case letter (and of course a
+newline).
+To place any of the characters
+`\(ua', `[', or `\-' in
+.I string
+you must escape them with a preceding `\e'.
+.NH 2
+Combining regular expression primitives
+.PP
+The concatenation of two regular expressions matches the leftmost and
+then longest string
+which can be divided with the first piece matching the first regular
+expression and the second piece matching the second.
+Any of the (single character matching) regular expressions mentioned
+above may be followed by the character `*' to form a regular expression
+which matches any number of adjacent occurrences (including 0) of characters
+matched by the regular expression it follows.
+.PP
+The character `\s+2~\s0' may be used in a regular expression,
+and matches the text which defined the replacement part
+of the last
+.I substitute
+command.
+A regular expression may be enclosed between the sequences
+`\e(' and `\e)' with side effects in the
+.I substitute
+replacement patterns.
+.NH 2
+Substitute replacement patterns
+.PP
+The basic metacharacters for the replacement pattern are
+`&' and `~'; these are
+given as `\e&' and `\e~' when
+.I nomagic
+is set.
+Each instance of `&' is replaced by the characters
+which the regular expression matched.
+The metacharacter `~' stands, in the replacement pattern,
+for the defining text of the previous replacement pattern.
+.PP
+Other metasequences possible in the replacement pattern
+are always introduced by the escaping character `\e'.
+The sequence `\e\fIn\fR' is replaced by the text matched
+by the \fIn\fR-th regular subexpression enclosed between
+`\e(' and `\e)'.\(dg
+.FS
+\(dg When nested, parenthesized subexpressions are present,
+\fIn\fR is determined by counting occurrences of `\e(' starting from the left.
+.FE
+The sequences `\eu' and `\el' cause the immediately following character in
+the replacement to be converted to upper- or lower-case respectively
+if this character is a letter.
+The sequences `\eU' and `\eL' turn such conversion on, either until
+`\eE' or `\ee' is encountered, or until the end of the replacement pattern.
+.de LC
+.br
+.sp .1i
+.ne 4
+.LP
+.ta 3i
+..
+.NH 1
+Option descriptions
+.PP
+.LC
+\fBautoindent\fR, \fBai\fR default: noai
+.ZP
+Can be used to ease the preparation of structured program text.
+At the beginning of each
+.I append ,
+.I change
+or
+.I insert
+command
+or when a new line is
+.I opened
+or created by an
+.I append ,
+.I change ,
+.I insert ,
+or
+.I substitute
+operation within
+.I open
+or
+.I visual
+mode,
+.I ex
+looks at the line being appended after,
+the first line changed
+or the line inserted before and calculates the amount of white space
+at the start of the line.
+It then aligns the cursor at the level of indentation so determined.
+.IP
+If the user then types lines of text in,
+they will continue to be justified at the displayed indenting level.
+If more white space is typed at the beginning of a line,
+the following line will start aligned with the first non-white character
+of the previous line.
+To back the cursor up to the preceding tab stop one can hit
+\fB^D\fR.
+The tab stops going backwards are defined at multiples of the
+.I shiftwidth
+option.
+You
+.I cannot
+backspace over the indent,
+except by sending an end-of-file with a \fB^D\fR.
+.IP
+Specially processed in this mode is a line with no characters added
+to it, which turns into a completely blank line (the white
+space provided for the
+.I autoindent
+is discarded.)
+Also specially processed in this mode are lines beginning with
+an `\(ua' and immediately followed by a \fB^D\fR.
+This causes the input to be repositioned at the beginning of the line,
+but retaining the previous indent for the next line.
+Similarly, a `0' followed by a \fB^D\fR
+repositions at the beginning but without
+retaining the previous indent.
+.IP
+.I Autoindent
+doesn't happen in
+.I global
+commands or when the input is not a terminal.
+.LC
+\fBautoprint\fR, \fBap\fR default: ap
+.ZP
+Causes the current line to be printed after each
+.I delete ,
+.I copy ,
+.I join ,
+.I move ,
+.I substitute ,
+.I t ,
+.I undo
+or
+shift command.
+This has the same effect as supplying a trailing `p'
+to each such command.
+.I Autoprint
+is suppressed in globals,
+and only applies to the last of many commands on a line.
+.LC
+\fBautowrite\fR, \fBaw\fR default: noaw
+.ZP
+Causes the contents of the buffer to be written to the current file
+if you have modified it and give a
+.I next,
+.I rewind,
+.I stop,
+.I tag,
+or
+.I !
+command, or a \fB^\(ua\fR (switch files) or \fB^]\fR (tag goto) command
+in
+.I visual.
+Note, that the
+.I edit
+and
+.I ex
+commands do
+.B not
+autowrite.
+In each case, there is an equivalent way of switching when autowrite
+is set to avoid the
+.I autowrite
+(\fIedit\fR
+for
+.I next ,
+.I rewind!
+for .I rewind ,
+.I stop!
+for
+.I stop ,
+.I tag!
+for
+.I tag ,
+.I shell
+for
+.I ! ,
+and
+\fB:e\ #\fR and a \fB:ta!\fR command from within
+.I visual).
+.LC
+\fBbeautify\fR, \fBbf\fR default: nobeautify
+.ZP
+Causes all control characters except tab, newline and form-feed
+to be discarded from the input.
+A complaint is registered the first time a
+backspace character is discarded.
+.I Beautify
+does not apply to command input.
+.LC
+\fBdirectory\fR, \fBdir\fR default: dir=/tmp
+.ZP
+Specifies the directory in which
+.I ex
+places its buffer file.
+If this directory in not
+writable, then the editor will exit abruptly when it fails to be
+able to create its buffer there.
+.LC
+\fBedcompatible\fR default: noedcompatible
+.ZP
+Causes the presence of absence of
+.B g
+and
+.B c
+suffixes on substitute commands to be remembered, and to be toggled
+by repeating the suffices. The suffix
+.B r
+makes the substitution be as in the
+.I ~
+command, instead of like
+.I &.
+.LC
+\fBerrorbells\fR, \fBeb\fR default: noeb
+.ZP
+Error messages are preceded by a bell.*
+.FS
+* Bell ringing in
+.I open
+and
+.I visual
+on errors is not suppressed by setting
+.I noeb.
+.FE
+If possible the editor always places the error message in a standout mode of the
+terminal (such as inverse video) instead of ringing the bell.
+.LC
+\fBhardtabs\fR, \fBht\fR default: ht=8
+.ZP
+Gives the boundaries on which terminal hardware tabs are set (or
+on which the system expands tabs).
+.LC
+\fBignorecase\fR, \fBic\fR default: noic
+.ZP
+All upper case characters in the text are mapped to lower case in regular
+expression matching.
+In addition, all upper case characters in regular expressions are mapped
+to lower case except in character class specifications.
+.LC
+\fBlisp\fR default: nolisp
+.ZP
+\fIAutoindent\fR indents appropriately for
+.I lisp
+code, and the \fB( ) { } [[\fR and \fB]]\fR commands in
+.I open
+and
+.I visual
+are modified to have meaning for \fIlisp\fR.
+.LC
+\fBlist\fR default: nolist
+.ZP
+All printed lines will be displayed (more) unambiguously,
+showing tabs and end-of-lines as in the
+.I list
+command.
+.LC
+\fBmagic\fR default: magic for \fIex\fR and \fIvi\fR\(dg
+.FS
+\(dg \fINomagic\fR for \fIedit\fR.
+.FE
+.ZP
+If
+.I nomagic
+is set, the number of regular expression metacharacters is greatly reduced,
+with only `\(ua' and `$' having special effects.
+In addition the metacharacters
+`~'
+and
+`&'
+of the replacement pattern are treated as normal characters.
+All the normal metacharacters may be made
+.I magic
+when
+.I nomagic
+is set by preceding them with a `\e'.
+.LC
+\fBmesg\fR default: mesg
+.ZP
+Causes write permission to be turned off to the terminal
+while you are in visual mode, if
+.I nomesg
+is set.
+.LC
+\fBmodeline\fR default: nomodeline
+.ZP
+If
+.I modeline
+is set, then the first 5 lines and the last five lines of the file
+will be checked for ex command lines and the comands issued.
+To be recognized as a command line, the line must have the string
+.B ex:
+or
+.B vi:
+preceeded by a tab or a space. This string may be anywhere in the
+line and anything after the
+.I :
+is interpeted as editor commands. This option defaults to off because
+of unexpected behavior when editting files such as
+.I /etc/passwd.
+.LC
+\fBnumber, nu\fR default: nonumber
+.ZP
+Causes all output lines to be printed with their
+line numbers.
+In addition each input line will be prompted for by supplying the line number
+it will have.
+.LC
+\fBopen\fR default: open
+.ZP
+If \fInoopen\fR, the commands
+.I open
+and
+.I visual
+are not permitted.
+This is set for
+.I edit
+to prevent confusion resulting from accidental entry to
+open or visual mode.
+.LC
+\fBoptimize, opt\fR default: optimize
+.ZP
+Throughput of text is expedited by setting the terminal
+to not do automatic carriage returns
+when printing more than one (logical) line of output,
+greatly speeding output on terminals without addressable
+cursors when text with leading white space is printed.
+.LC
+\fBparagraphs,\ para\fR default: para=IPLPPPQPP\0LIbp
+.ZP
+Specifies the paragraphs for the \fB{\fR and \fB}\fR operations in
+.I open
+and
+.I visual.
+The pairs of characters in the option's value are the names
+of the macros which start paragraphs.
+.LC
+\fBprompt\fR default: prompt
+.ZP
+Command mode input is prompted for with a `:'.
+.LC
+\fBredraw\fR default: noredraw
+.ZP
+The editor simulates (using great amounts of output), an intelligent
+terminal on a dumb terminal (e.g. during insertions in
+.I visual
+the characters to the right of the cursor position are refreshed
+as each input character is typed.)
+Useful only at very high speed.
+.LC
+\fBremap\fP default: remap
+.ZP
+If on, macros are repeatedly tried until they are unchanged.
+For example, if
+.B o
+is mapped to
+.B O ,
+and
+.B O
+is mapped to
+.B I ,
+then if
+.I remap
+is set,
+.B o
+will map to
+.B I ,
+but if
+.I noremap
+is set, it will map to
+.B O .
+.LC
+\fBreport\fR default: report=5\(dg
+.FS
+\(dg 2 for \fIedit\fR.
+.FE
+.ZP
+Specifies a threshold for feedback from commands.
+Any command which modifies more than the specified number of lines
+will provide feedback as to the scope of its changes.
+For commands such as
+.I global ,
+.I open ,
+.I undo ,
+and
+.I visual
+which have potentially more far reaching scope,
+the net change in the number of lines in the buffer is
+presented at the end of the command, subject to this same threshold.
+Thus notification is suppressed during a
+.I global
+command on the individual commands performed.
+.LC
+\fBscroll\fR default: scroll=\(12 window
+.ZP
+Determines the number of logical lines scrolled when an end-of-file
+is received from a terminal input in command mode,
+and the number of lines printed by a command mode
+.I z
+command (double the value of
+.I scroll ).
+.LC
+\fBsections\fR default: sections=SHNHH\0HU
+.ZP
+Specifies the section macros for the \fB[[\fR and \fB]]\fR operations
+in
+.I open
+and
+.I visual.
+The pairs of characters in the options's value are the names
+of the macros which start paragraphs.
+.LC
+\fBshell\fR, \fBsh\fR default: sh=/bin/sh
+.ZP
+Gives the path name of the shell forked for
+the shell escape command `!', and by the
+.I shell
+command.
+The default is taken from SHELL in the environment, if present.
+.LC
+\fBshiftwidth\fR, \fBsw\fR default: sw=8
+.ZP
+Gives the width a software tab stop,
+used in reverse tabbing with \fB^D\fR when using
+.I autoindent
+to append text,
+and by the shift commands.
+.LC
+\fBshowmatch, sm\fR default: nosm
+.ZP
+In
+.I open
+and
+.I visual
+mode, when a \fB)\fR or \fB}\fR is typed, move the cursor to the matching
+\fB(\fR or \fB{\fR for one second if this matching character is on the
+screen. Extremely useful with
+.I lisp.
+.LC
+\fBslowopen, slow\fR terminal dependent
+.ZP
+Affects the display algorithm used in
+.I visual
+mode, holding off display updating during input of new text to improve
+throughput when the terminal in use is both slow and unintelligent.
+See
+.I "An Introduction to Display Editing with Vi"
+for more details.
+.LC
+\fBtabstop,\ ts\fR default: ts=8
+.ZP
+The editor expands tabs in the input file to be on
+.I tabstop
+boundaries for the purposes of display.
+.LC
+\fBtaglength,\ tl\fR default: tl=0
+.ZP
+Tags are not significant beyond this many characters.
+A value of zero (the default) means that all characters are significant.
+.LC
+\fBtags\fR default: tags=tags /usr/lib/tags
+.ZP
+A path of files to be used as tag files for the
+.I tag
+command.
+A requested tag is searched for in the specified files, sequentially.
+By default, files called
+.B tags
+are searched for in the current directory and in /usr/lib
+(a master file for the entire system).
+.LC
+\fBterm\fR from environment TERM
+.ZP
+The terminal type of the output device.
+.LC
+\fBterse\fR default: noterse
+.ZP
+Shorter error diagnostics are produced for the experienced user.
+.LC
+\fBwarn\fR default: warn
+.ZP
+Warn if there has been `[No write since last change]' before a `!'
+command escape.
+.LC
+\fBwindow\fR default: window=speed dependent
+.ZP
+The number of lines in a text window in the
+.I visual
+command.
+The default is 8 at slow speeds (600 baud or less),
+16 at medium speed (1200 baud),
+and the full screen (minus one line) at higher speeds.
+.LC
+\fBw300,\ w1200\, w9600\fR
+.ZP
+These are not true options but set
+.B window
+only if the speed is slow (300), medium (1200), or high (9600),
+respectively.
+They are suitable for an EXINIT
+and make it easy to change the 8/16/full screen rule.
+.LC
+\fBwrapscan\fR, \fBws\fR default: ws
+.ZP
+Searches using the regular expressions in addressing
+will wrap around past the end of the file.
+.LC
+\fBwrapmargin\fR, \fBwm\fR default: wm=0
+.ZP
+Defines a margin for automatic wrapover of text during input in
+.I open
+and
+.I visual
+modes. See
+.I "An Introduction to Text Editing with Vi"
+for details.
+.LC
+\fBwriteany\fR, \fBwa\fR default: nowa
+.IP
+Inhibit the checks normally made before
+.I write
+commands, allowing a write to any file which the system protection
+mechanism will allow.
+.NH 1
+Limitations
+.PP
+Editor limits that the user is likely to encounter are as follows:
+1024 characters per line,
+256 characters per global command list,
+128 characters per file name,
+128 characters in the previous inserted and deleted text in
+.I open
+or
+.I visual,
+100 characters in a shell escape command,
+63 characters in a string valued option,
+and 30 characters in a tag name, and
+a limit of 250000 lines in the file is silently enforced.
+.PP
+The
+.I visual
+implementation limits the number of macros defined with map to
+32, and the total number of characters in macros to be less than 512.
+.LP
+.LP
+.I Acknowledgments.
+Chuck Haley contributed greatly to the early development of
+.I ex.
+Bruce Englar encouraged the redesign which led to
+.I ex
+version 1.
+Bill Joy wrote versions 1 and 2.0 through 2.7,
+and created the framework that users see in the present editor.
+Mark Horton added macros and other features and made the
+editor work on a large number of terminals and Unix systems.
diff --git a/usr.bin/vi/docs/USD.doc/ex/ex.summary b/usr.bin/vi/docs/USD.doc/ex/ex.summary
new file mode 100644
index 000000000000..618da07c7420
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/ex.summary
@@ -0,0 +1,734 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)ex.summary 8.1 (Berkeley) 6/8/93
+.\"
+.ds p \v'-0.2'.\v'+0.2'
+.ds U \s-2UNIX\s+2
+.ds c \v'-0.2':\v'+0.2'
+.nr PO .25i
+.nr LL 6.75i
+.lt 6.75i
+.ll 6.75i
+.ds CH
+.ds LF Computing Services, U.C. Berkeley
+.ds RF April 3, 1979
+.de SP
+.sp 1v
+..
+.nr PI 3n
+.nr PD 0
+.ND
+.ps 12
+.ft B
+.ce 1
+Ex/Edit Command Summary (Version 2.0)
+.ft R
+.nr VS 11
+.nr PS 9
+.nr HM 0.5i
+.nr CW
+.2C
+.PP
+.I Ex
+and
+.I edit
+are text editors, used for creating
+and modifying files of text on the \*U
+computer system.
+.I Edit
+is a variant of
+.I ex
+with features designed to
+make it less complicated
+to learn and use.
+In terms of command syntax and effect
+the editors are essentially identical,
+and this command summary applies to both.
+.PP
+The summary is meant as a quick reference
+for users already acquainted
+with
+.I edit
+or \fIex\fP.
+Fuller explanations of the editors are available
+in the documents
+.I
+Edit: A Tutorial
+.R
+(a self-teaching introduction) and the
+.I
+Ex Reference Manual
+.R
+(the comprehensive reference source for
+both \fIedit\fP and \fIex\fP).
+Both of these writeups are available in the
+Computing Services Library.
+.PP
+In the examples included with the
+summary, commands and text entered by
+the user are printed in \fBboldface\fR to
+distinguish them from responses printed
+by the computer.
+.sp 0.45v
+.LP
+.B
+The Editor Buffer
+.PP
+In order to perform its tasks
+the editor sets aside a temporary
+work space,
+called a \fIbuffer\fR,
+separate from the user's permanent
+file.
+Before starting to work on an existing
+file the editor makes a copy of it in the
+buffer, leaving the original untouched.
+All editing changes are made to the
+buffer copy, which must then
+be written back to the permanent
+file in order to update the
+old version.
+The buffer disappears
+at the end of the editing session.
+.sp 0.45v
+.LP
+.B
+Editing: Command and Text Input Modes
+.PP
+.R
+During an editing session there are
+two usual modes of operation:
+\fIcommand\fP mode and \fItext input\fP
+mode.
+(This disregards, for the moment,
+.I open
+and
+.I visual
+modes, discussed below.)
+In command mode, the editor issues a
+colon prompt (:)
+to show that it is ready to
+accept and execute a command.
+In text input mode, on the other hand, there is
+no prompt and the editor merely accepts text to
+be added to the buffer.
+Text input mode is initiated by the commands
+\fIappend\fP, \fIinsert\fP, and \fIchange\fP,
+and is terminated by typing a period as the
+first and only character on a line.
+.sp 0.45v
+.LP
+.B
+Line Numbers and Command Syntax
+.PP
+.R
+The editor keeps track of lines of text
+in the buffer by numbering them consecutively
+starting with 1 and renumbering
+as lines are added or deleted.
+At any given time the editor is positioned
+at one of these lines; this position is
+called the \fIcurrent line\fP.
+Generally, commands that change the
+contents of the buffer print the
+new current line at the end of their
+execution.
+.PP
+Most commands can be preceded by one or two
+line-number addresses which indicate the lines
+to be affected.
+If one number is given the command operates on
+that line only; if two, on an inclusive range
+of lines.
+Commands that can take line-number prefixes also
+assume default prefixes if none are given.
+The default assumed by each command is designed
+to make it convenient to use in many instances
+without any line-number prefix.
+For the most part, a command used without a
+prefix operates on the current line,
+though exceptions to this rule should be noted.
+The \fIprint\fP command
+by itself, for instance, causes
+one line, the current line, to be
+printed at the terminal.
+.PP
+The summary shows the number of line addresses
+that can be
+prefixed to each command as well as
+the defaults assumed if they are omitted.
+For example,
+.I (.,.)
+means that up to 2 line-numbers may be given,
+and that if none is given the
+command operates on the current line.
+(In the address prefix notation, ``.'' stands
+for the current line and ``$'' stands for
+the last line of the buffer.)
+If no such notation appears, no
+line-number prefix may be used.
+.PP
+Some commands take trailing
+information;
+only
+the more important instances of this
+are mentioned in the summary.
+.sp 0.25v
+.LP
+.B
+Open and Visual Modes
+.PP
+.R
+Besides command and text input modes,
+.I ex
+and
+.I edit
+provide on some CRT terminals other modes of editing,
+.I open
+and
+.I visual .
+In these modes the cursor can
+be moved to individual words
+or characters in a line.
+The commands then given are very different
+from the standard editor commands; most do not appear on the screen when
+typed.
+.I
+An Introduction to Display Editing with Vi
+.R
+provides a full discussion.
+.sp 0.25v
+.LP
+.B
+Special Characters
+.PP
+.R
+.fi
+Some characters take on special meanings
+when used in context searches
+and in patterns given to the \fIsubstitute\fP command.
+For \fIedit\fR, these are ``^'' and ``$'',
+meaning the beginning and end of a line,
+respectively.
+.I Ex
+has the following additional special characters:
+.B
+.ce 1
+\&. & * [ ] ~
+.R
+To use one of the special characters as its
+simple graphic representation
+rather than with its special meaning,
+precede it by a backslash (\\).
+The backslash always has a special meaning.
+.1C
+.rm LF
+.rm RF
+.rm CF
+.nr FM 0.4
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+(.)\fBappend a T{
+Begins text input mode,
+adding lines to the buffer after
+the line specified. Appending continues
+until ``.'' is typed alone at the
+beginning of a new line, followed by
+a carriage return. \fI0a\fR places
+lines at the beginning of the buffer.
+T} T{
+.nf
+\fR:\fBa
+Three lines of text
+are added to the buffer
+after the current line.
+\*p
+.R
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBchange c T{
+Deletes indicated line(s) and
+initiates text input mode to
+replace them with new text which follows.
+New text is terminated the same way
+as with \fIappend\fR.
+T} T{
+.nf
+:\fB5,6c
+Lines 5 and 6 are
+deleted and replaced by
+these three lines.
+\*p
+.R
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBcopy \fIaddr co T{
+Places a copy of the specified lines
+after the line indicated by \fIaddr\fR.
+The example places a copy of lines 8 through
+12, inclusive, after line 25.
+T} T{
+.nf
+\fR:\fB8,12co 25
+\fRLast line copied is printed
+\fR\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBdelete d T{
+Removes lines from the buffer
+and prints the current line after the deletion.
+T} T{
+.nf
+\fR:\fB13,15d
+\fRNew current line is printed
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+T{
+\fBedit \fIfile\fP
+.br
+\fBedit! \fIfile\fP
+T} T{
+e
+.br
+e!
+T} T{
+.fi
+\fRClears the editor buffer and then
+copies into it the named \fIfile\fR,
+which becomes the current file.
+This is a way of shifting to a different
+file
+without leaving the editor.
+The editor issues a warning
+message if this command is used before
+saving changes
+made to the file already in the buffer;
+using the form \fBe!\fR overrides this protective mechanism.
+T} T{
+.nf
+\fR:\fBe ch10\fR
+No write since last change
+:\fBe! ch10\fR
+"ch10" 3 lines, 62 characters
+\*c
+.fi
+T}
+.SP
+\fBfile \fIname\fR f T{
+\fRIf followed by a \fIname\fR, renames
+the current file to \fIname\fR.
+If used without \fIname\fR, prints
+the name of the current file.
+T} T{
+.nf
+\fR:\fBf ch9
+\fR"ch9" [Modified] 3 lines ...
+:\fBf
+\fR"ch9" [Modified] 3 lines ...
+\*c
+.fi
+T}
+.SP
+(1,$)\fBglobal g \fBglobal/\fIpattern\fB/\fIcommands T{
+.nf
+:\fBg/nonsense/d
+\fR\*c
+.fi
+T}
+\fR(1,$)\fBglobal! g!\fR or \fBv T{
+Searches the entire buffer (unless a smaller
+range is specified by line-number prefixes) and
+executes \fIcommands\fR on every line with
+an expression matching \fIpattern\fR.
+The second form, abbreviated
+either \fBg!\fR or \fBv\fR,
+executes \fIcommands\fR on lines that \fIdo
+not\fR contain the expression \fIpattern\fR.
+T} \^
+.SP
+\fR(.)\fBinsert i T{
+Inserts new lines of text immediately before the specified line.
+Differs from
+.I append
+only in that text is placed before, rather than after, the indicated line.
+In other words, \fB1i\fR has the same effect as \fB0a\fR.
+T} T{
+.nf
+:\fB1i
+These lines of text will
+be added prior to line 1.
+\&.
+\fR:
+.fi
+T} \^
+.SP
+\fR(.,.+1)\fBjoin j T{
+Join lines together, adjusting white space (spaces
+and tabs) as necessary.
+T} T{
+.nf
+:\fB2,5j\fR
+Resulting line is printed
+:
+.fi
+T} \^
+.TE
+.bp
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+\fR(.,.)\fBlist l T{
+\fRPrints lines in a more
+unambiguous way than the \fIprint\fR
+command does. The end of a line,
+for example, is marked with a ``$'',
+and tabs printed as ``^I''.
+T} T{
+.nf
+:\fB9l
+\fRThis is line 9$
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fR(.,.)\fBmove \fIaddr\fB m T{
+\fRMoves the specified lines
+to a position after the line
+indicated by \fIaddr\fR.
+T} T{
+.nf
+\fR:\fB12,15m 25\fR
+New current line is printed
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBnumber nu T{
+Prints each line preceded
+by its buffer line number.
+T} T{
+.nf
+\fR:\fBnu
+\0\0\fR10\0 This is line 10
+\*c
+.fi
+T}
+.SP
+\fR(.)\fBopen o T{
+Too involved to discuss here,
+but if you enter open mode
+accidentally, press
+the \s-2ESC\s0 key followed by
+\fBq\fR to
+get back into normal editor
+command mode.
+\fIEdit\fP is designed to
+prevent accidental use of
+the open command.
+T}
+.SP
+\fBpreserve pre T{
+Saves a copy of the current buffer contents as though the system had
+just crashed. This is for use in an emergency when a
+.I write
+command has failed and you don't know how else to save your work.\(dg
+T} T{
+.nf
+:\fBpreserve\fR
+File preserved.
+:
+.fi
+T}
+.SP
+\fR(.,.)\fBprint p Prints the text of line(s). T{
+.nf
+:\fB+2,+3p\fR
+The second and third lines
+after the current line
+:
+.fi
+T}
+.TE
+.FS
+\(dg Seek assistance from a consultant as soon as possible
+after saving a file with the
+.I preserve
+command, because the file is saved on system storage space for only one week.
+.FE
+.SP
+.nf
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+T{
+.nf
+\fBquit
+quit!
+.fi
+T} T{
+.nf
+q
+q!
+T} T{
+.fi
+\fREnds the editing session.
+You will receive a
+warning if you have changed the buffer
+since last writing its contents
+to the file. In this event you
+must either type \fBw\fR to write,
+or type \fBq!\fR to exit from
+the editor without saving your changes.
+T} T{
+.nf
+\fR:\fBq
+\fRNo write since last change
+:\fBq!
+\fR%
+.fi
+T}
+.SP
+\fR(.)\fBread \fIfile\fP r T{
+.fi
+\fRPlaces a copy of \fIfile\fR in the
+buffer after the specified line.
+Address 0 is permissible and causes
+the copy of \fIfile\fR to be placed
+at the beginning of the buffer.
+The \fIread\fP command does not
+erase any text already in the buffer.
+If no line number is specified,
+\fIfile\fR is placed after the
+current line.
+T} T{
+.nf
+\fR:\fB0r newfile
+\fR"newfile" 5 lines, 86 characters
+\*c
+.fi
+T}
+.SP
+\fBrecover \fIfile\fP rec T{
+.fi
+Retrieves a copy of the editor buffer
+after a system crash, editor crash,
+phone line disconnection, or
+\fIpreserve\fR command.
+T}
+.SP
+\fR(.,.)\fBsubstitute s T{
+.nf
+\fBsubstitute/\fIpattern\fB/\fIreplacement\fB/
+substitute/\fIpattern\fB/\fIreplacement\fB/gc
+.fi
+\fRReplaces the first occurrence of \fIpattern\fR
+on a line
+with \fIreplacement\fP.
+Including a \fBg\fR after the command
+changes all occurrences of \fIpattern\fP
+on the line.
+The \fBc\fR option allows the user to
+confirm each substitution before it is
+made; see the manual for details.
+T} T{
+.nf
+:\fB3p
+\fRLine 3 contains a misstake
+:\fBs/misstake/mistake/
+\fRLine 3 contains a mistake
+\*c
+.fi
+T}
+.TE
+.bp
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+\fBundo u T{
+.fi
+\fRReverses the changes made in
+the buffer by the last buffer-editing
+command.
+Note that this example contains
+a notification about the number of
+lines affected.
+T} T{
+.nf
+\fR:\fB1,15d
+\fR15 lines deleted
+new line number 1 is printed
+:\fBu
+\fR15 more lines in file ...
+old line number 1 is printed
+\*c
+.fi
+T}
+.SP
+\fR(1,$)\fBwrite \fIfile\fR w T{
+.fi
+\fRCopies data from the buffer onto
+a permanent file. If no \fIfile\fR
+is named, the current filename
+is used.
+The file is automatically created
+if it does not yet exist.
+A response containing the number of
+lines and characters in the file
+indicates that the write
+has been completed successfully.
+The editor's built-in protections
+against overwriting existing files
+will in some circumstances
+inhibit a write.
+The form \fBw!\fR forces the
+write, confirming that
+an existing file is to be overwritten.
+T} T{
+.nf
+\fR:\fBw
+\fR"file7" 64 lines, 1122 characters
+:\fBw file8
+\fR"file8" File exists ...
+:\fBw! file8
+\fR"file8" 64 lines, 1122 characters
+\*c
+.fi
+T}
+\fR(1,$)\fBwrite! \fIfile\fP w! \^ \^
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fR(.)\fBz \fIcount\fP z T{
+.fi
+\fRPrints a screen full of text starting
+with the line indicated;
+or, if \fIcount\fR is specified,
+prints that number of lines.
+Variants of the \fIz\fR command
+are described in the manual.
+T}
+.SP
+\fB!\fIcommand T{
+.fi
+Executes the remainder of the line
+after \fB!\fR as a \*U command.
+The buffer is unchanged by this, and
+control is returned to the editor when
+the execution of \fIcommand\fR is complete.
+T} T{
+.nf
+\fR:\fB!date
+\fRFri Jun 9 12:15:11 PDT 1978
+!
+\*c
+.fi
+T}
+.SP
+\fRcontrol-d T{
+.fi
+Prints the next \fIscroll\fR of text,
+normally half of a screen. See the
+manual for details of the \fIscroll\fR
+option.
+T}
+.SP
+\fR(.+1)<cr> T{
+.fi
+An address alone followed by a carriage
+return causes the line to be printed.
+A carriage return by itself prints the
+line following the current line.
+T} T{
+.nf
+:\fR<cr>
+the line after the current line
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fB/\fIpattern\fB/ T{
+.fi
+\fRSearches for the next line in which
+\fIpattern\fR occurs and prints it.
+T} T{
+.nf
+\fR:\fB/This pattern/
+\fRThis pattern next occurs here.
+\*c
+.fi
+T}
+.SP
+\fB// T{
+Repeats the most recent search.
+T} T{
+.nf
+\fR:\fB//
+\fRThis pattern also occurs here.
+\*c
+.fi
+T}
+.SP
+\fB?\fIpattern\fB? T{
+Searches in the reverse direction
+for \fIpattern\fP.
+T}
+.SP
+\fB?? T{
+Repeats the most recent search,
+moving in the reverse direction
+through the buffer.
+T}
+.TE
+
diff --git a/usr.bin/vi/docs/USD.doc/vi/Makefile b/usr.bin/vi/docs/USD.doc/vi/Makefile
new file mode 100644
index 000000000000..c6131af77971
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/Makefile
@@ -0,0 +1,17 @@
+# @(#)Makefile 8.1 (Berkeley) 8/14/93
+
+DIR= usd/12.vi
+SRCS= vi.in vi.chars
+MACROS= -ms
+CLEANFILES+=summary.* viapwh.*
+
+paper.ps: ${SRCS} summary.ps viapwh.ps
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+summary.ps: vi.summary
+ ${TBL} vi.summary | ${ROFF} > ${.TARGET}
+
+viapwh.ps: vi.apwh.ms
+ ${ROFF} vi.apwh.ms > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms b/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms
new file mode 100644
index 000000000000..d0b62611c701
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms
@@ -0,0 +1,1079 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)vi.apwh.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+Vi Command & Function Reference
+.AU CB 2675
+Alan P.W. Hewett
+.sp
+Revised for version 2.12 by Mark Horton
+.CB
+.NH 1
+Author's Disclaimer
+.LP
+This document does not claim to be 100% complete. There are a
+few commands listed in the original document that I was unable
+to test either because I do not speak \fBlisp\fR, because they
+required programs we don't have, or because I wasn't able to make
+them work. In these cases I left the command out. The commands
+listed in this document have been tried and are known to work.
+It is expected that prospective users of this document will read
+it once to get the flavor of everything that \fBvi\fR can do
+and then use it as a reference document. Experimentation is
+recommended. If you don't understand a command, try it and
+see what happens.
+.LP
+[Note: In revising this document, I have attempted to make it
+completely reflect version 2.12 of
+.B vi .
+It does not attempt to document the VAX version (version 3),
+but with one or two exceptions (wrapmargin, arrow keys)
+everything said about 2.12 should apply to 3.1.
+.I "Mark Horton" ]
+.NH 1
+Notation
+.LP
+\fB[option]\fR is used to denote optional parts of a command.
+Many \fBvi\fR commands have an optional count. \fB[cnt]\fR
+means that an optional number may precede the command to
+multiply or iterate the command.
+\fB{variable item}\fR is used to denote parts of the command
+which must appear, but can take a number of different values.
+\fB<character [-character]>\fR means that the character or
+one of the characters in the range described between the
+two angle brackets is to be typed.
+For example \fB<esc>\fR means
+the \fBescape\fR key is to be typed. \fB<a-z>\fR means that a
+lower case letter is to be typed. \fB^<character>\fR means that
+the character is to be typed as a \fBcontrol\fR character, that is,
+with the \fB<cntl>\fR key held down while simultaneously typing
+the specified character. In this document control characters will
+be denoted using the \fIupper case\fR character, but
+^<uppercase chr> and ^<lowercase chr> are equivalent. That is, for
+example, \fB<^D>\fR is equal to \fB<^d>\fR.
+The most common character abbreviations
+used in this list are as follows:
+.VL 8
+.IP <esc> 8
+escape, octal 033
+.IP <cr> 8
+carriage return, ^M, octal 015
+.IP <lf> 8
+linefeed ^J, octal 012
+.IP <nl> 8
+newline, ^J, octal 012 (same as linefeed)
+.IP <bs> 8
+backspace, ^H, octal 010
+.IP <tab> 8
+tab, ^I, octal 011
+.IP <bell> 8
+bell, ^G, octal 07
+.IP <ff> 8
+formfeed, ^L, octal 014
+.IP <sp> 8
+space, octal 040
+.IP <del> 8
+delete, octal 0177
+.LE
+.sp 1
+.NH 1
+Basics
+.LP
+To run \fBvi\fR the shell variable \fBTERM\fR must be defined and
+exported to your environment.
+How you do this depends on which shell you are using.
+You can tell which shell you have by the character it
+prompts you for commands with.
+The Bourne shell prompts with `$', and the C shell prompts with `%'.
+For these examples, we will suppose
+that you are using an HP 2621 terminal, whose termcap name is ``2621''.
+.NH 2
+Bourne Shell
+.LP
+To manually set your terminal type to 2621 you would type:
+.DS
+TERM=2621
+export TERM
+.DE
+.PP
+There are various ways of having this automatically or
+semi-automatically done when you log in.
+Suppose you usually dial in on a 2621.
+You want to tell this to the machine, but still have it
+work when you use a hardwired terminal.
+The recommended way, if you have the
+.B tset
+program, is to use the sequence
+.DS
+tset \-s \-d 2621 > tset$$
+\&. tset$$
+rm tset$$
+.DE
+in your .login (for csh) or the same thing using `.' instead of `source'
+in your .profile (for sh).
+The above line says that if you are dialing in you are on a 2621,
+but if you are on a hardwired terminal it figures out your terminal
+type from an on-line list.
+.NH 2
+The C Shell
+.LP
+To manually set your terminal type to 2621 you would type:
+.DS
+setenv TERM 2621
+.DE
+.PP
+There are various ways of having this automatically or
+semi-automatically done when you log in.
+Suppose you usually dial in on a 2621.
+You want to tell this to the machine, but still have it
+work when you use a hardwired terminal.
+The recommended way, if you have the
+.B tset
+program, is to use the sequence
+.DS
+tset \-s \-d 2621 > tset$$
+source tset$$
+rm tset$$
+.DE
+in your .login.*
+.FS
+* On a version 6 system
+without environments, the invocation of tset
+is simpler, just add the line ``tset \-d 2621''
+to your .login or .profile.
+.FE
+The above line says that if you are dialing in you are on a 2621,
+but if you are on a hardwired terminal it figures out your terminal
+type from an on-line list.
+.NH 1
+Normal Commands
+.LP
+\fBVi\fR is a visual editor with a window on the file. What
+you see on the screen is \fBvi\fR's current notion of
+what your file will contain,
+(at this point in the file),
+when it is written out.
+Most commands do not cause any change in the screen until the
+complete command is typed. Should you get confused while
+typing a command, you can abort the command by typing an
+<del> character. You will know you are back to command level
+when you hear a <bell>. Usually typing an <esc> will produce the
+same result. When \fBvi\fR gets an improperly formatted command
+it rings the <bell>.
+Following are the \fBvi\fR commands broken down by function.
+.NH 2
+Entry and Exit
+.LP
+To enter
+.B vi
+on a particular
+.I file ,
+type
+.DS
+\fBvi\fP \fIfile\fP
+.DE
+The file will be read in and the cursor will be placed at the beginning
+of the first line.
+The first screenfull of the file will be displayed on the terminal.
+.PP
+To get out of the editor, type
+.DS
+ZZ
+.DE
+If you are in some special mode, such as input mode
+or the middle of a multi-keystroke command, it may
+be necessary to type <esc> first.
+.NH 2
+Cursor and Page Motion
+.LP
+.VL 16
+.B NOTE:
+The arrow keys (see the next four commands)
+on certain kinds of terminals will not work with the
+PDP-11 version of vi. The control versions or the hjkl versions will
+work on any terminal. Experienced users prefer the hjkl keys because
+they are always right under their fingers. Beginners often prefer
+the arrow keys, since they do not require memorization of which hjkl
+key is which.
+The mnemonic value of hjkl is clear from looking at the keyboard of an adm3a.
+.sp
+.IP "[cnt]<bs> or [cnt]h or [cnt]\(<-" 16
+.br
+Move the cursor to the left one character. Cursor stops at the left
+margin of the page.
+If cnt is given, these commands move that many spaces.
+.IP "[cnt]^N or [cnt]j or [cnt]\(da or [cnt]<lf>" 16
+.br
+Move down one line.
+Moving off the screen scrolls the window to force a new line
+onto the screen.
+Mnemonic: \fBN\fRext
+.IP "[cnt]^P or [cnt]k or [cnt]\(ua" 16
+.br
+Move up one line.
+Moving off the top of the screen forces new text onto the screen.
+Mnemonic: \fBP\fRrevious
+.IP "[cnt]<sp> or [cnt]l or [cnt]\(->" 16
+.br
+Move to the right one character.
+Cursor will not go beyond the end of the line.
+.IP [cnt]- 16
+Move the cursor up the screen to the beginning of the next line.
+Scroll if necessary.
+.IP "[cnt]+ or [cnt]<cr>" 16
+.sp 1
+Move the cursor down the screen to the beginning of the next line.
+Scroll up if necessary.
+.IP "[cnt]$" 16
+Move the cursor to the end of the line.
+If there is a count, move to the end of the line "cnt" lines
+forward in the file.
+.IP "^" 16
+Move the cursor to the beginning of the first word on the line.
+.IP "0" 16
+Move the cursor to the left margin of the current line.
+.IP "[cnt]|" 16
+Move the cursor to the column specified by the count. The default is
+column zero.
+.IP "[cnt]w" 16
+Move the cursor to the beginning of the next word. If there
+is a count, then move forward that many words and
+position the cursor at the beginning of the word.
+Mnemonic: next-\fBw\fRord
+.IP "[cnt]W" 16
+Move the cursor to the beginning of the next word which follows
+a "white space" (<sp>,<tab>, or <nl>). Ignore other punctuation.
+.IP "[cnt]b" 16
+Move the cursor to the preceding word. Mnemonic: \fBb\fRackup-word
+.IP "[cnt]B" 16
+Move the cursor to the preceding word that is separated from the
+current word by a "white space" (<sp>,<tab>, or <nl>).
+.IP "[cnt]e" 16
+Move the cursor to the end of the current word or the end of the
+"cnt"'th word hence. Mnemonic: \fBe\fRnd-of-word
+.IP "[cnt]E" 16
+Move the cursor to the end of the current word which is delimited by
+"white space" (<sp>,<tab>, or <nl>).
+.IP "[line number]G" 16
+.br
+Move the cursor to the line specified. Of particular use are the
+sequences "1G" and "G", which move the cursor to the beginning and
+the end of the file respectively. Mnemonic: \fBG\fRo-to
+.LP
+.B NOTE:
+The next four commands (^D, ^U, ^F, ^B)
+are not true motion commands, in that they
+cannot be used as the object of commands such as delete or change.
+.IP "[cnt]^D" 16
+Move the cursor down in the file by "cnt" lines (or the last "cnt"
+if a new count isn't given. The initial default is half a page.) The
+screen is simultaneously scrolled up. Mnemonic: \fBD\fRown
+.IP "[cnt]^U" 16
+Move the cursor up in the file by "cnt" lines. The screen is simultaneously
+scrolled down. Mnemonic: \fBU\fRp
+.IP "[cnt]^F" 16
+Move the cursor to the next page. A count moves that many pages.
+Two lines of the previous page are kept on the screen for continuity if
+possible. Mnemonic: \fBF\fRorward-a-page
+.IP "[cnt]^B" 16
+Move the cursor to the previous page. Two lines of the current page
+are kept if possible. Mnemonic: \fBB\fRackup-a-page
+.IP "[cnt](" 16
+Move the cursor to the beginning of the next sentence.
+A sentence is defined as ending with a ".", "!", or "?"
+followed by two spaces or a <nl>.
+.IP "[cnt])" 16
+Move the cursor backwards to the beginning of a sentence.
+.IP "[cnt]}" 16
+Move the cursor to the beginning of the next paragraph. This command
+works best inside \fBnroff\fR documents. It understands two sets of
+\fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, for which the
+commands ".IP", ".LP", ".PP", ".QP", "P", as well as the nroff command ".bp"
+are considered to be paragraph delimiters.
+A blank line also delimits a paragraph.
+The \fBnroff\fR macros that it accepts as paragraph delimiters is
+adjustable. See \fBparagraphs\fR under the \fBSet Commands\fR section.
+.IP "[cnt]{" 16
+Move the cursor backwards to the beginning of a paragraph.
+.IP "]]" 16
+Move the cursor to the next "section", where a section is defined by
+two sets of \fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, in which
+".NH", ".SH", and ".H" delimit a section. A line beginning with a <ff><nl>
+sequence, or a line beginning with a "{" are also considered to
+be section delimiters. The last option makes it
+useful for finding the beginnings of C functions.
+The \fBnroff\fR macros that are used for section delimiters can be adjusted.
+See \fBsections\fR under the \fBSet Commands\fR section.
+.IP "[[" 16
+Move the cursor backwards to the beginning of a section.
+.IP "%" 16
+Move the cursor to the matching parenthesis
+or brace. This is very useful in C or lisp code. If the
+cursor is sitting on a \fB( ) {\fR or \fB}\fR the cursor
+is moved to the matching character at the other end of the
+section. If the cursor is not sitting on a brace or a
+parenthesis, \fBvi\fR searches forward until it finds one
+and then jumps to the match mate.
+.IP "[cnt]H" 16
+If there is no count move the cursor to the top left position on the screen.
+If there is a count, then move the cursor to the beginning of the line
+"cnt" lines from the top of the screen. Mnemonic: \fBH\fRome
+.IP "[cnt]L" 16
+If there is no count move the cursor to the beginning
+of the last line on the screen.
+If there is a count, then move the cursor to the beginning of the line
+"cnt" lines from the bottom of the screen. Mnemonic: \fBL\fRast
+.IP "M" 16
+Move the cursor to the beginning of the middle line on the screen.
+Mnemonic: \fBM\fRiddle
+.IP "m<a-z>" 16
+This command does not move the cursor, but it \fBmarks\fR the place
+in the file and the character "<a-z>" becomes the label for referring
+to this location in the file. See the next two commands. Mnemonic:
+\fBm\fRark
+.B NOTE:
+The mark command is not a motion, and cannot be used as the target
+of commands such as delete.
+.IP "\(aa<a-z>" 16
+Move the cursor to the beginning of the line that is marked with the label
+"<a-z>".
+.IP "\(ga<a-z>" 16
+Move the cursor to the exact position on the line that was marked with
+with the label "<a-z>".
+.IP "\(aa\(aa" 16
+Move the cursor back to the beginning of the line where it was before the
+last "non-relative" move. A "non-relative" move is something such as a
+search or a jump to a specific line in the file, rather than moving the
+cursor or scrolling the screen.
+.IP "\(ga\(ga" 16
+Move the cursor back to the exact spot on the line where it was located
+before the last "non-relative" move.
+.LE
+.NH 2
+Searches
+.LP
+The following commands allow you to search for items in a file.
+.VL 16
+.IP [cnt]f{chr} 16
+.sp 1
+Search forward on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBat\fR the character
+of interest. Mnemonic: \fBf\fRind character
+.IP [cnt]F{chr} 16
+.sp 1
+Search backwards on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBat\fR the character
+of interest.
+.IP [cnt]t{chr} 16
+.sp 1
+Search forward on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBjust preceding\fR
+the character of interest. Mnemonic: move cursor up \fBt\fRo character
+.IP [cnt]T{chr} 16
+.sp 1
+Search backwards on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBjust preceding\fR
+the character of interest.
+.IP "[cnt];" 16
+Repeat the last "f", "F", "t" or "T" command.
+.IP "[cnt]," 16
+Repeat the last "f", "F", "t" or "T" command, but in the opposite
+search direction. This is useful if you overshoot.
+.IP "[cnt]/[string]/<nl>" 16
+.br
+Search forward for the next occurrence of "string".
+Wrap around at the end of the file
+does occur.
+The final \fB</>\fR is not required.
+.IP "[cnt]?[string]?<nl>" 16
+.br
+Search backwards for the next occurrence of "string". If a count is
+specified, the count becomes the new window size. Wrap around at the beginning
+of the file does occur.
+The final \fB<?>\fR is not required.
+.IP n 16
+Repeat the last /[string]/ or ?[string]? search. Mnemonic: \fBn\fRext
+occurrence.
+.IP N 16
+Repeat the last /[string]/ or ?[string]? search, but in the reverse
+direction.
+.IP ":g/[string]/[editor command]<nl>" 16
+.sp 1
+Using the \fB:\fR syntax it is possible to do global searches ala the
+standard UNIX "ed" editor.
+.LE
+.NH 2
+Text Insertion
+.LP
+The following commands allow for the insertion of text. All multicharacter
+text insertions are terminated with an <esc> character.
+The last change
+can always be \fBundone\fR by typing a \fBu\fR.
+The text insert in insertion mode can contain newlines.
+.VL 16
+.IP a{text}<esc> 16
+Insert text immediately following the cursor position.
+Mnemonic: \fBa\fRppend
+.IP A{text}<esc> 16
+Insert text at the end of the current line.
+Mnemonic: \fBA\fRppend
+.IP i{text}<esc> 16
+Insert text immediately preceding the cursor position.
+Mnemonic: \fBi\fRnsert
+.IP I{text}<esc> 16
+Insert text at the beginning of the current line.
+.IP o{text}<esc> 16
+Insert a new line after the line on which the cursor appears and
+insert text there. Mnemonic: \fBo\fRpen new line
+.IP O{text}<esc> 16
+Insert a new line preceding the line on which the cursor appears
+and insert text there.
+.LE
+.NH 2
+Text Deletion
+.LP
+The following commands allow the user to delete text in various ways.
+All changes can always be \fBundone\fR by typing the \fBu\fR command.
+.VL 16
+.IP "[cnt]x" 16
+Delete the character or characters starting at the cursor position.
+.IP "[cnt]X" 16
+Delete the character or characters starting at the character preceding
+the cursor position.
+.IP "D" 16
+Deletes the remainder of the line starting at the cursor.
+Mnemonic: \fBD\fRelete the rest of line
+.IP "[cnt]d{motion}" 16
+.br
+Deletes one or more occurrences of the specified motion.
+Any motion from sections 4.1 and 4.2 can be used here.
+The d can be stuttered (e.g. [cnt]dd) to delete cnt lines.
+.LE
+.NH 2
+Text Replacement
+.LP
+The following commands allow the user to simultaneously delete and
+insert new text. All such actions can be \fBundone\fR by typing
+\fBu\fR following the command.
+.VL 16
+.IP "r<chr>" 16
+Replaces the character at the current cursor position with <chr>. This
+is a one character replacement. No <esc> is required for termination.
+Mnemonic: \fBr\fReplace character
+.IP "R{text}<esc>" 16
+Starts overlaying the characters on the screen with whatever you type.
+It does not stop until an <esc> is typed.
+.IP "[cnt]s{text}<esc>" 16
+Substitute for "cnt" characters beginning at the current cursor
+position. A "$" will appear at the position in the text where the
+"cnt"'th character appears so you will know how much you are erasing.
+Mnemonic: \fBs\fRubstitute
+.IP "[cnt]S{text}<esc>" 16
+Substitute for the entire current line (or lines). If no count is given,
+a "$" appears at the end of the current line. If a count of more than
+1 is given, all the lines to be replaced are deleted before the insertion
+begins.
+.IP "[cnt]c{motion}{text}<esc>" 16
+.br
+Change the specified "motion" by replacing it with the
+insertion text. A "$" will appear at the end of the last item
+that is being deleted unless the deletion involves whole lines.
+Motion's can be any motion from sections 4.1 or 4.2.
+Stuttering the c (e.g. [cnt]cc) changes cnt lines.
+.LE
+.NH 2
+Moving Text
+.LP
+\fBVi\fR provides a number of ways of moving chunks of text around.
+There are nine buffers into which each piece of text which is deleted
+or "yanked" is put in addition to the "undo" buffer.
+The most recent deletion or yank is in the "undo" buffer and also
+usually in buffer
+1, the next most recent in buffer 2, and so forth. Each new deletion
+pushes down all the older deletions. Deletions older than 9
+disappear. There is also
+a set of named registers, a-z, into which text can optionally
+be placed. If any delete or replacement type command is preceded
+by \fB"<a-z>\fR, that named buffer will contain the text deleted
+after the command is executed. For example, \fB"a3dd\fR will delete
+three lines starting at the current line and put them in buffer \fB"a\fR.*
+.FS
+* Referring to an upper case letter as a buffer name (A-Z) is the
+same as referring to the lower case letter, except that text placed
+in such a buffer is appended to it instead of replacing it.
+.FE
+There are two more basic commands and
+some variations useful in getting and putting text into a file.
+.VL 16
+.IP ["<a-z>][cnt]y{motion} 16
+.sp 1
+Yank the specified item or "cnt" items and put in the "undo" buffer or
+the specified buffer. The variety of "items" that can be yanked
+is the same as those that can be deleted with the "d" command or
+changed with the "c" command. In the same way that "dd" means
+delete the current line and "cc" means replace the current line,
+"yy" means yank the current line.
+.IP ["<a-z>][cnt]Y 16
+Yank the current line or the "cnt" lines starting from the current
+line. If no buffer is specified, they will go into the "undo" buffer,
+like any delete would. It is equivalent to "yy".
+Mnemonic: \fBY\fRank
+.IP ["<a-z>]p 16
+Put "undo" buffer or the specified buffer down \fBafter\fR the cursor.
+If whole lines were yanked or deleted into the buffer, then they will be
+put down on the line following the line the cursor is on. If
+something else was deleted, like a word or sentence, then it will
+be inserted immediately following the cursor.
+Mnemonic: \fBp\fRut buffer
+.IP
+It should be noted that text in the named buffers remains there when you
+start editing a new file with the \fB:e file<esc>\fR command. Since
+this is so, it is possible to copy or delete text from one file and
+carry it over to another file in the buffers.
+However, the undo buffer and the ability to undo are lost when
+changing files.
+.IP ["<a-z>]P 16
+Put "undo" buffer or the specified buffer down \fBbefore\fR the cursor.
+If whole lines where yanked or deleted into the buffer, then they will be
+put down on the line preceding the line the cursor is on. If
+something else was deleted, like a word or sentence, then it will
+be inserted immediately preceding the cursor.
+.IP [cnt]>{motion} 16
+The shift operator will right shift all the text from the line on which
+the cursor is located to the line where the \fBmotion\fR is located.
+The text is shifted by one \fBshiftwidth\fR. (See section 6.)
+\fB>>\fR means right shift the current line or lines.
+.IP [cnt]<{motion} 16
+The shift operator will left shift all the text from the line on which
+the cursor is located to the line where the \fBitem\fR is located.
+The text is shifted by one \fBshiftwidth\fR. (See section 6.)
+\fB<<\fR means left shift the current line or lines.
+Once the line has reached the left margin it is not further affected.
+.IP [cnt]={motion} 16
+Prettyprints the indicated area according to
+.B lisp
+conventions.
+The area should be a lisp s-expression.
+.LE
+.NH 2
+Miscellaneous Commands
+.LP
+\fBVi\fR has a number of miscellaneous commands that are very
+useful. They are:
+.VL 16
+.IP ZZ 16
+This is the normal way to exit from vi.
+If any changes have been made, the file is written out.
+Then you are returned to the shell.
+.IP ^L 16
+Redraw the current screen. This is useful if someone "write"s you
+while you are in "vi" or if for any reason garbage gets onto the
+screen.
+.IP ^R 16
+On dumb terminals, those not having the "delete line" function
+(the vt100 is such a terminal), \fBvi\fR saves redrawing the
+screen when you delete a line by just marking the line with an
+"@" at the beginning and blanking the line. If you want to
+actually get rid of the lines marked with "@" and see what the
+page looks like, typing a ^R will do this.
+.IP \s+4.\s0 16
+"Dot" is a particularly useful command. It repeats the last
+text modifying command. Therefore you can type a command once and
+then to another place and repeat it by just typing ".".
+.IP u 16
+Perhaps the most important command in the editor,
+u undoes the last command that changed the buffer.
+Mnemonic: \fBu\fRndo
+.IP U 16
+Undo all the text modifying commands performed on the current line
+since the last time you moved onto it.
+.IP [cnt]J 16
+Join the current line and the following line. The <nl> is deleted
+and the two lines joined, usually with a space between the
+end of the first line and the beginning of what was the second
+line. If the first line ended with a "period", then two spaces
+are inserted.
+A count joins the next cnt lines.
+Mnemonic: \fBJ\fRoin lines
+.IP Q 16
+Switch to \fBex\fR editing mode.
+In this mode \fBvi\fR will behave very much like \fBed\fR.
+The editor in this mode will operate on single lines normally and
+will not attempt to keep the "window" up to date.
+Once in this mode it is also possible to switch to the \fBopen\fR
+mode of editing. By entering the command \fB[line number]open<nl>\fR
+you enter this mode. It is similar to the normal visual mode
+except the window is only \fBone\fR line long.
+Mnemonic: \fBQ\fRuit visual mode
+.IP ^] 16
+An abbreviation for a tag command.
+The cursor should be positioned at the beginning of a word.
+That word is taken as a tag name, and the tag with that
+name is found as if it had been typed in a :tag command.
+.IP [cnt]!{motion}{UNIX\ cmd}<nl> 16
+.br
+Any UNIX filter
+(e.g. command that reads the standard input and outputs something
+to the standard output) can be sent a section of the current file and
+have the output of the command replace the original text. Useful
+examples are programs like \fBcb\fR, \fBsort\fR, and
+\fBnroff\fR. For instance, using \fBsort\fR it would be possible to
+sort a section of the current file into a new list.
+Using \fB!!\fR means take a line or lines starting at the line the
+cursor is currently on and pass them to the UNIX command.
+.B NOTE:
+To just escape to the shell for one command,
+use :!{cmd}<nl>, see section 5.
+.IP z{cnt}<nl> 16
+This resets the current window size to "cnt" lines and redraws the screen.
+.LE
+.NH 2
+Special Insert Characters
+.LP
+There are some characters that have special meanings during
+insert modes. They are:
+.VL 16
+.IP ^V 16
+During inserts, typing a ^V allows you to quote control characters
+into the file. Any character typed after the ^V will be inserted
+into the file.
+.IP [^]^D\ or\ [0]^D 16
+<^D> without any argument backs up one \fBshiftwidth\fR. This is necessary
+to remove indentation that was inserted by the \fBautoindent\fR feature.
+^<^D> temporarily removes all the autoindentation, thus placing the cursor
+at the left margin. On the next line, the previous indent level will be
+restored. This is useful for putting "labels" at the left margin.
+0<^D> says remove all autoindents and stay that way. Thus the cursor
+moves to the left margin and stays there on successive lines until
+<tab>'s are typed. As with the <tab>, the <^D> is only effective before
+any other "non-autoindent" controlling characters are typed.
+Mnemonic: \fBD\fRelete a shiftwidth
+.IP ^W 16
+If the cursor is sitting on a word, <^W> moves the cursor back to the beginning
+of the word, thus erasing the word from the insert.
+Mnemonic: erase \fBW\fRord
+.IP <bs> 16
+The backspace always serves as an erase during insert modes in addition
+to your normal "erase" character. To insert a <bs> into your file, use
+the <^V> to quote it.
+.LE
+.NH 1
+\fB:\fR Commands
+.LP
+Typing a ":" during command mode causes \fBvi\fR to put the cursor at
+the bottom on the screen in preparation for a command. In the
+":" mode, \fBvi\fR can be given most \fBed\fR commands. It is
+also from this mode that you exit from \fBvi\fR or switch to different
+files. All commands of this variety are terminated by a <nl>, <cr>,
+or <esc>.
+.VL 16
+.IP ":w[!] [file]" 16
+Causes \fBvi\fR to write out the current text to the disk. It is
+written to the file you are editing unless "file" is supplied. If
+"file" is supplied, the write is directed to that file instead. If
+that file already exists, \fBvi\fR will not perform the write unless
+the "!" is supplied indicating you
+.I really
+want to destroy the older copy of the file.
+.IP :q[!] 16
+Causes \fBvi\fR to exit. If you have modified the file you are
+looking at currently and haven't written it out, \fBvi\fR will
+refuse to exit unless the "!" is supplied.
+.IP ":e[!] [+[cmd]] [file]" 16
+.sp 1
+Start editing a new file called "file" or start editing the current
+file over again. The command ":e!" says "ignore the changes I've made
+to this file and start over from the beginning". It is useful if
+you really mess up the file. The optional "+" says instead of starting
+at the beginning, start at the "end", or,
+if "cmd" is supplied, execute "cmd" first.
+Useful cases of this are where cmd is "n" (any integer) which starts
+at line number n,
+and "/text", which searches for "text" and starts at the line where
+it is found.
+.IP "^^" 16
+Switch back to the place you were before your last tag command.
+If your last tag command stayed within the file, ^^ returns to that tag.
+If you have no recent tag command, it will return to the
+same place in the previous file that it was showing when you switched
+to the current file.
+.IP ":n[!]" 16
+Start editing the next file in the argument list. Since \fBvi\fR
+can be called with multiple file names, the ":n" command tells it to
+stop work on the current file and switch to the next file. If the
+current file was modifies, it has to be written out before the ":n"
+will work or else the "!" must be supplied, which says discard the
+changes I made to the current file.
+.IP ":n[!] file [file file ...]" 16
+.sp
+Replace the current argument list with a new list of files and start
+editing the first file in this new list.
+.IP ":r file" 16
+Read in a copy of "file" on the line after the cursor.
+.IP ":r !cmd" 16
+Execute the "cmd" and take its output and put it into the file after
+the current line.
+.IP ":!cmd" 16
+Execute any UNIX shell command.
+.IP ":ta[!] tag" 16
+.B Vi
+looks in the file named
+.B tags
+in the current directory.
+.B Tags
+is a file of lines in the format:
+.sp 1
+.ti +8
+tag filename \fBvi\fR-search-command
+.sp 1
+If \fBvi\fR finds the tag you specified in the \fB:ta\fR command,
+it stops editing the current file if necessary and if the current file is
+up to date on the disk and switches to the file specified and uses the
+search pattern specified to find the "tagged" item of interest. This
+is particularly useful when editing multi-file C programs such as the
+operating system. There is a program called \fBctags\fR which will
+generate an appropriate \fBtags\fR file for C and f77
+programs so that by saying
+\fB:ta function<nl>\fR you will be switched to that function.
+It could also be useful when editing multi-file documents, though the
+\fBtags\fR file would have to be generated manually.
+.LE
+.NH 1
+Special Arrangements for Startup
+.PP
+\fBVi\fR takes the value of \fB$TERM\fR and looks up the characteristics
+of that terminal in the file \fB/etc/termcap\fR.
+If you don't know \fBvi\fR's name for the terminal you are working
+on, look in \fB/etc/termcap\fR.
+.PP
+When \fBvi\fR starts, it attempts to read the variable EXINIT
+from your environment.*
+If that exists, it takes the values in it as the default values
+for certain of its internal constants. See the section on "Set Values"
+for further details.
+If EXINIT doesn't exist you will get all the normal defaults.
+.FS
+* On version 6 systems
+Instead of EXINIT, put the startup commands in the file .exrc
+in your home directory.
+.FE
+.PP
+Should you inadvertently hang up the phone while inside
+.B vi ,
+or should the computer crash,
+all may not be lost.
+Upon returning to the system, type:
+.DS
+vi \-r file
+.DE
+This will normally recover the file. If there is more than one
+temporary file for a specific file name, \fBvi\fR recovers the
+newest one. You can get an older version by recovering the
+file more than once.
+The command "vi -r" without a file name gives you the list of files
+that were saved in the last system crash
+(but
+.I not
+the file just saved when the phone was hung up).
+.NH 1
+Set Commands
+.LP
+\fBVi\fR has a number of internal variables and switches which can be
+set to achieve special affects.
+These options come in three forms, those that are switches, which toggle
+from off to on and back, those that require a numeric value, and those
+that require an alphanumeric string value.
+The toggle options are set by a command of the form:
+.DS
+:set option<nl>
+.DE
+and turned off with the command:
+.DS
+:set nooption<nl>
+.DE
+Commands requiring a value are set with a command of the form:
+.DS
+:set option=value<nl>
+.DE
+To display the value of a specific option type:
+.DS
+:set option?<nl>
+.DE
+To display only those that you have changed type:
+.DS
+:set<nl>
+.DE
+and to display the long table of all the settable parameters and
+their current values type:
+.DS
+:set all<nl>
+.DE
+.PP
+Most of the options have a long form and an abbreviation. Both are
+listed in the following table as well as the normal default value.
+.PP
+To arrange to have values other than the default used every time you
+enter
+.B vi ,
+place the appropriate
+.B set
+command in EXINIT in your environment, e.g.
+.DS
+EXINIT='set ai aw terse sh=/bin/csh'
+export EXINIT
+.DE
+or
+.DS
+setenv EXINIT 'set ai aw terse sh=/bin/csh'
+.DE
+for
+.B sh
+and
+.B csh ,
+respectively.
+These are usually placed in your .profile or .login.
+If you are running a system without environments (such as version 6)
+you can place the set command in the file .exrc in your home
+directory.
+.VL 16
+.IP autoindent\ ai 16
+Default: noai Type: toggle
+.br
+When in autoindent mode, vi helps you indent code by starting each
+line in the same column as the preceding line.
+Tabbing to the right with <tab> or <^T> will move this boundary to
+the right, and it can be moved to the left with <^D>.
+.IP autoprint\ ap 16
+Default: ap Type: toggle
+.br
+Causes the current line to be printed after each ex text modifying command.
+This is not of much interest in the normal \fBvi\fR visual mode.
+.IP autowrite\ aw 16
+Default: noaw type: toggle
+.br
+Autowrite causes an automatic write to be done if there are unsaved
+changes before certain commands which change files or otherwise
+interact with the outside world.
+These commands are :!, :tag, :next, :rewind, ^^, and ^].
+.IP beautify\ bf 16
+Default: nobf Type: toggle
+.br
+Causes all control characters except <tab>, <nl>, and <ff> to be discarded.
+.IP directory\ dir 16
+Default: dir=/tmp Type: string
+.br
+This is the directory in which \fBvi\fR puts its temporary file.
+.IP errorbells\ eb 16
+Default: noeb Type: toggle
+.br
+Error messages are preceded by a <bell>.
+.IP hardtabs\ ht 16
+Default: hardtabs=8 Type: numeric
+.br
+This option contains the value of hardware tabs in your terminal, or
+of software tabs expanded by the Unix system.
+.IP ignorecase\ ic 16
+Default: noic Type: toggle
+.br
+All upper case characters are mapped to lower case in regular expression
+matching.
+.IP lisp 16
+Default: nolisp Type: toggle
+.br
+Autoindent for \fBlisp\fR code. The commands \fB( ) [[\fR and \fB]]\fR
+are modified appropriately to affect s-expressions and functions.
+.IP list 16
+Default: nolist Type: toggle
+.br
+All printed lines have the <tab> and <nl> characters displayed visually.
+.IP magic 16
+Default: magic Type: toggle
+.br
+Enable the metacharacters for matching. These include \fB. * < > [string]
+[^string]\fR and \fB[<chr>-<chr>]\fR.
+.IP number\ nu 16
+Default: nonu Type: toggle
+.br
+Each line is displayed with its line number.
+.IP open 16
+Default: open Type: toggle
+.br
+When set, prevents entering open or visual modes from ex or edit.
+Not of interest from vi.
+.IP optimize\ opt 16
+Default: opt Type: toggle
+.br
+Basically of use only when using the \fBex\fR capabilities. This
+option prevents automatic <cr>s from taking place,
+and speeds up output of indented lines,
+at the expense of losing typeahead on some versions of UNIX.
+.IP paragraphs\ para 16
+Default: para=IPLPPPQPP\ bp Type: string
+.br
+Each pair of characters in the string indicate \fBnroff\fR macros
+which are to be treated as the beginning of a paragraph for the
+\fB{\fR and \fB}\fR commands. The default string is for the \fB-ms\fR
+and \fB-mm\fR macros.
+To indicate one letter \fBnroff\fR macros, such as \fB.P\fR or \fB.H\fR,
+quote a space in for the second character position. For example:
+.sp 1
+.ti +8
+:set paragraphs=P\e bp<nl>
+.sp 1
+would cause \fBvi\fR to consider \fB.P\fR and \fB.bp\fR as paragraph
+delimiters.
+.IP prompt 16
+Default: prompt Type: toggle
+.br
+In
+.B ex
+command mode the prompt character \fB:\fR will be printed when
+\fBex\fR is waiting for a command. This is not of interest from vi.
+.IP redraw 16
+Default: noredraw Type: toggle
+.br
+On dumb terminals, force the screen to always be up to date,
+by sending great amounts of output. Useful only at high speeds.
+.IP report 16
+Default: report=5 Type: numeric
+.br
+This sets the threshold for the number of lines modified. When
+more than this number of lines are modified, removed, or yanked,
+\fBvi\fR will report the number of lines changed at the bottom of
+the screen.
+.IP scroll 16
+Default: scroll={1/2 window} Type: numeric
+.br
+This is the number of lines that the screen scrolls up or down when
+using the <^U> and <^D> commands.
+.IP sections 16
+Default: sections=SHNHH HU Type: string
+.br
+Each two character pair of this string specify \fBnroff\fR macro names
+which are to be treated as the beginning of a section by the
+\fB]]\fR and \fB[[\fR commands. The default string is for the \fB-ms\fR
+and \fB-mm\fR macros.
+To enter one letter \fBnroff\fR macros, use a quoted space as the
+second character.
+See \fBparagraphs\fR for a fuller explanation.
+.IP shell\ sh 16
+Default: sh=from environment SHELL or /bin/sh Type: string
+.br
+This is the name of the \fBsh\fR to be used for "escaped" commands.
+.IP shiftwidth\ sw 16
+Default: sw=8 Type: numeric
+.br
+This is the number of spaces that a <^T> or <^D> will move over for
+indenting, and the amount < and > shift by.
+.IP showmatch\ sm 16
+Default: nosm Type: toggle
+.br
+When a \fB)\fR or \fB}\fR is typed, show the matching \fB(\fR or \fB{\fR
+by moving the cursor to it for one second if it is on the current screen.
+.IP slowopen\ slow 16
+Default: terminal dependent Type: toggle
+.br
+On terminals that are slow and unintelligent, this option prevents the
+updating of the screen some of the time to improve speed.
+.IP tabstop\ ts 16
+Default: ts=8 Type: numeric
+.br
+<tab>s are expanded to boundaries that are multiples of this value.
+.IP taglength\ tl 16
+Default: tl=0 Type: numeric
+.br
+If nonzero, tag names are only significant to this many characters.
+.IP term 16
+Default: (from environment \fBTERM\fP, else dumb) Type: string
+.br
+This is the terminal and controls the visual displays. It cannot be
+changed when in "visual" mode,
+you have to Q to command mode, type a
+set term command, and do ``vi.'' to get back into visual.
+Or exit vi, fix $TERM, and reenter.
+The definitions that drive a particular
+terminal type are found in the file \fB/etc/termcap\fR.
+.IP terse 16
+Default: terse Type: toggle
+.br
+When set, the error diagnostics are short.
+.IP warn 16
+Default: warn Type: toggle
+.br
+The user is warned if she/he tries to escape to
+the shell without writing out the current changes.
+.IP window 16
+Default: window={8 at 600 baud or less, 16 at 1200 baud, and screen
+size \- 1 at 2400 baud or more} Type: numeric
+.br
+This is the number of lines in the window whenever \fBvi\fR must redraw
+an entire screen. It is useful to make this size smaller if you are
+on a slow line.
+.IP w300,\ w1200,\ w9600
+.br
+These set window, but only within the corresponding speed ranges.
+They are useful in an EXINIT to fine tune window sizes.
+For example,
+.DS
+set w300=4 w1200=12
+.DE
+causes a 4 lines window at speed up to 600 baud, a 12 line window at 1200
+baud, and a full screen (the default) at over 1200 baud.
+.IP wrapscan\ ws 16
+Default: ws Type: toggle
+.br
+Searches will wrap around the end of the file when is option is set. When
+it is off, the search will terminate when it reaches the end or the
+beginning of the file.
+.IP wrapmargin\ wm 16
+Default: wm=0 Type: numeric
+.br
+\fBVi\fR will automatically insert a <nl> when it finds a natural
+break point (usually a <sp> between words) that occurs within
+"wm" spaces of the right margin.
+Therefore with "wm=0" the option is off. Setting it to 10 would
+mean that any time you are within 10 spaces of the right margin
+\fBvi\fR would be looking for a <sp> or <tab> which it could
+replace with a <nl>. This is convenient for people who forget
+to look at the screen while they type.
+(In version 3, wrapmargin behaves more like nroff, in that the
+boundary specified by the distance from the right edge of the screen
+is taken as the rightmost edge of the area where a break is allowed,
+instead of the leftmost edge.)
+.IP writeany\ wa 16
+Default: nowa Type: toggle
+.br
+\fBVi\fR normally makes a number of checks before it writes out a file.
+This prevents the user from inadvertently destroying a file. When the
+"writeany" option is enabled, \fBvi\fR no longer makes these checks.
+.LE
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.chars b/usr.bin/vi/docs/USD.doc/vi/vi.chars
new file mode 100644
index 000000000000..147c4ff7f2d8
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.chars
@@ -0,0 +1,644 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)vi.chars 8.1 (Berkeley) 6/8/93
+.\"
+.bd S 3
+..pn 21
+.de iP
+.IP "\fB\\$1\fR" \\$2
+..
+.SH
+Appendix: character functions
+.PP
+This appendix gives the uses the editor makes of each character. The
+characters are presented in their order in the \s-2ASCII\s0 character
+set: Control characters come first, then most special characters, then
+the digits, upper and then lower case characters.
+.PP
+For each character we tell a meaning it has as a command and any meaning it
+has during an insert.
+If it has only meaning as a command, then only this is discussed.
+Section numbers in parentheses indicate where the character is discussed;
+a `f' after the section number means that the character is mentioned
+in a footnote.
+.iP "^@" 15
+Not a command character.
+If typed as the first character of an insertion it is replaced with the
+last text inserted, and the insert terminates. Only 128 characters are
+saved from the last insert; if more characters were inserted the mechanism
+is not available.
+A \fB^@\fR cannot be part of the file due to the editor implementation
+(7.5f).
+.iP "^A" 15
+Unused.
+.iP "^B" 15
+Backward window.
+A count specifies repetition.
+Two lines of continuity are kept if possible (2.1, 6.1, 7.2).
+.iP "^C" 15
+Unused.
+.iP "^D" 15
+As a command, scrolls down a half-window of text.
+A count gives the number of (logical) lines to scroll, and is remembered
+for future \fB^D\fR and \fB^U\fR commands (2.1, 7.2).
+During an insert, backtabs over \fIautoindent\fR white space at the beginning
+of a line (6.6, 7.5); this white space cannot be backspaced over.
+.iP "^E" 15
+Exposes one more line below the current screen in the file, leaving
+the cursor where it is if possible.
+(Version 3 only.)
+.iP "^F" 15
+Forward window. A count specifies repetition.
+Two lines of continuity are kept if possible (2.1, 6.1, 7.2).
+.iP "^G" 15
+Equivalent to \fB:f\fR\s-2CR\s0, printing the current file, whether
+it has been modified, the current line number and the number of lines
+in the file, and the percentage of the way through the file that you
+are.
+.iP "^H (\fR\s-2BS\s0\fP)" 15
+Same as
+.B "left arrow" .
+(See
+.B h ).
+During an insert, eliminates the last input character, backing over it
+but not erasing it; it remains so you can see what you typed if you
+wish to type something only slightly different (3.1, 7.5).
+.iP "^I\ (\fR\s-2TAB\s0\fP)" 15
+Not a command character.
+When inserted it prints as some
+number of spaces.
+When the cursor is at a tab character it rests at the last of the spaces
+which represent the tab.
+The spacing of tabstops is controlled by the \fItabstop\fR option (4.1, 6.6).
+.iP "^J\ (\fR\s-2LF\s0\fP)" 15
+Same as
+.B "down arrow"
+(see
+.B j ).
+.iP "^K" 15
+Unused.
+.iP "^L" 15
+The \s-2ASCII\s0 formfeed character, this causes the screen to be cleared
+and redrawn. This is useful after a transmission error, if characters
+typed by a program other than the editor scramble the screen,
+or after output is stopped by an interrupt (5.4, 7.2f).
+.iP "^M\ (\fR\s-2CR\s0\fP)" 15
+A carriage return advances to the next line, at the first non-white position
+in the line. Given a count, it advances that many lines (2.3).
+During an insert, a \s-2CR\s0 causes the insert to continue onto
+another line (3.1).
+.iP "^N" 15
+Same as
+.B "down arrow"
+(see
+.B j ).
+.iP "^O" 15
+Unused.
+.iP "^P" 15
+Same as
+.B "up arrow"
+(see
+.B k ).
+.iP "^Q" 15
+Not a command character.
+In input mode,
+.B ^Q
+quotes the next character, the same as
+.B ^V ,
+except that some teletype drivers will eat the
+.B ^Q
+so that the editor never sees it.
+.iP "^R" 15
+Redraws the current screen, eliminating logical lines not corresponding
+to physical lines (lines with only a single @ character on them).
+On hardcopy terminals in \fIopen\fR mode, retypes the current line
+(5.4, 7.2, 7.8).
+.iP "^S" 15
+Unused. Some teletype drivers use
+.B ^S
+to suspend output until
+.B ^Q is pressed.
+.iP "^T" 15
+Not a command character.
+During an insert, with \fIautoindent\fR set and at the beginning of the
+line, inserts \fIshiftwidth\fR white space.
+.iP "^U" 15
+Scrolls the screen up, inverting \fB^D\fR which scrolls down. Counts work as
+they do for \fB^D\fR, and the previous scroll amount is common to both.
+On a dumb terminal, \fB^U\fR will often necessitate clearing and redrawing
+the screen further back in the file (2.1, 7.2).
+.iP "^V" 15
+Not a command character.
+In input mode, quotes the next character so that it is possible
+to insert non-printing and special characters into the file (4.2, 7.5).
+.iP "^W" 15
+Not a command character.
+During an insert, backs up as \fBb\fR would in command mode; the deleted
+characters remain on the display (see \fB^H\fR) (7.5).
+.iP "^X" 15
+Unused.
+.iP "^Y" 15
+Exposes one more line above the current screen, leaving the cursor where
+it is if possible. (No mnemonic value for this key; however, it is next
+to \fB^U\fR which scrolls up a bunch.)
+(Version 3 only.)
+.iP "^Z" 15
+If supported by the Unix system,
+stops the editor, exiting to the top level shell.
+Same as \fB:stop\fP\s-2CR\s0.
+Otherwise, unused.
+.iP "^[\ (\fR\s-2ESC\s0\fP)" 15
+Cancels a partially formed command, such as a \fBz\fR when no following
+character has yet been given; terminates inputs on the last line (read
+by commands such as \fB: /\fR and \fB?\fR); ends insertions of new text
+into the buffer.
+If an \s-2ESC\s0 is given when quiescent in command state, the editor
+rings the bell or flashes the screen. You can thus hit \s-2ESC\s0 if
+you don't know what is happening till the editor rings the bell.
+If you don't know if you are in insert mode you can type \s-2ESC\s0\fBa\fR,
+and then material to be input; the material will be inserted correctly
+whether or not you were in insert mode when you started (1.5, 3.1, 7.5).
+.iP "^\e" 15
+Unused.
+.iP "^]" 15
+Searches for the word which is after the cursor as a tag. Equivalent
+to typing \fB:ta\fR, this word, and then a \s-2CR\s0.
+Mnemonically, this command is ``go right to'' (7.3).
+.iP "^\(ua" 15
+Equivalent to \fB:e #\fR\s-2CR\s0, returning to the previous position
+in the last edited file, or editing a file which you specified if you
+got a `No write since last change diagnostic' and do not want to have
+to type the file name again (7.3).
+(You have to do a \fB:w\fR before \fB^\(ua\fR
+will work in this case. If you do not wish to write the file you should
+do \fB:e!\ #\fR\s-2CR\s0 instead.)
+.iP "^_" 15
+Unused.
+Reserved as the command character for the
+Tektronix 4025 and 4027 terminal.
+.iP "\fR\s-2SPACE\s0\fP" 15
+Same as
+.B "right arrow"
+(see
+.B l ).
+.iP "!" 15
+An operator, which processes lines from the buffer with reformatting commands.
+Follow \fB!\fR with the object to be processed, and then the command name
+terminated by \s-2CR\s0. Doubling \fB!\fR and preceding it by a count
+causes count lines to be filtered; otherwise the count
+is passed on to the object after the \fB!\fR. Thus \fB2!}\fR\fIfmt\fR\s-2CR\s0
+reformats the next two paragraphs by running them through the program
+\fIfmt\fR. If you are working on \s-2LISP\s0,
+the command \fB!%\fR\fIgrind\fR\s-2CR\s0,*
+.FS
+*Both
+.I fmt
+and
+.I grind
+are Berkeley programs and may not be present at all installations.
+.FE
+given at the beginning of a
+function, will run the text of the function through the \s-2LISP\s0 grinder
+(6.7, 7.3).
+To read a file or the output of a command into the buffer use \fB:r\fR (7.3).
+To simply execute a command use \fB:!\fR (7.3).
+.tr "
+.iP  15
+Precedes a named buffer specification. There are named buffers \fB1\-9\fR
+used for saving deleted text and named buffers \fBa\-z\fR into which you can
+place text (4.3, 6.3)
+.tr 
+.iP "#" 15
+The macro character which, when followed by a number, will substitute
+for a function key on terminals without function keys (6.9).
+In input mode,
+if this is your erase character, it will delete the last character
+you typed in input mode, and must be preceded with a \fB\e\fR to insert
+it, since it normally backs over the last input character you gave.
+.iP "$" 15
+Moves to the end of the current line. If you \fB:se list\fR\s-2CR\s0,
+then the end of each line will be shown by printing a \fB$\fR after the
+end of the displayed text in the line. Given a count, advances to the
+count'th following end of line; thus \fB2$\fR advances to the end of the
+following line.
+.iP "%" 15
+Moves to the parenthesis or brace \fB{ }\fR which balances the parenthesis
+or brace at the current cursor position.
+.iP "&" 15
+A synonym for \fB:&\fR\s-2CR\s0, by analogy with the
+.I ex
+.B &
+command.
+.iP "\(aa" 15
+When followed by a \fB\(aa\fR returns to the previous context at the
+beginning of a line. The previous context is set whenever the current
+line is moved in a non-relative way.
+When followed by a letter \fBa\fR\-\fBz\fR, returns to the line which
+was marked with this letter with a \fBm\fR command, at the first non-white
+character in the line. (2.2, 5.3).
+When used with an operator such as \fBd\fR, the operation takes place
+over complete lines; if you use \fB\(ga\fR, the operation takes place
+from the exact marked place to the current cursor position within the
+line.
+.iP "(" 15
+Retreats to the beginning of a
+sentence, or to the beginning of a \s-2LISP\s0 s-expression
+if the \fIlisp\fR option is set.
+A sentence ends at a \fB. !\fR or \fB?\fR which is followed by either
+the end of a line or by two spaces. Any number of closing \fB) ] "\fR
+and \fB\(aa\fR characters may appear after the \fB. !\fR or \fB?\fR,
+and before the spaces or end of line. Sentences also begin
+at paragraph and section boundaries
+(see \fB{\fR and \fB[[\fR below).
+A count advances that many sentences (4.2, 6.8).
+.iP ")" 15
+Advances to the beginning of a sentence.
+A count repeats the effect.
+See \fB(\fR above for the definition of a sentence (4.2, 6.8).
+.iP "*" 15
+Unused.
+.iP "+" 15
+Same as \s-2CR\s0 when used as a command.
+.iP "," 15
+Reverse of the last \fBf F t\fR or \fBT\fR command, looking the other way
+in the current line. Especially useful after hitting too many \fB;\fR
+characters. A count repeats the search.
+.iP "\-" 15
+Retreats to the previous line at the first non-white character.
+This is the inverse of \fB+\fR and \s-2RETURN\s0.
+If the line moved to is not on the screen, the screen is scrolled, or
+cleared and redrawn if this is not possible.
+If a large amount of scrolling would be required the screen is also cleared
+and redrawn, with the current line at the center (2.3).
+.iP "\&." 15
+Repeats the last command which changed the buffer. Especially useful
+when deleting words or lines; you can delete some words/lines and then
+hit \fB.\fR to delete more and more words/lines.
+Given a count, it passes it on to the command being repeated. Thus after
+a \fB2dw\fR, \fB3.\fR deletes three words (3.3, 6.3, 7.2, 7.4).
+.iP "/" 15
+Reads a string from the last line on the screen, and scans forward for
+the next occurrence of this string. The normal input editing sequences may
+be used during the input on the bottom line; an returns to command state
+without ever searching.
+The search begins when you hit \s-2CR\s0 to terminate the pattern;
+the cursor moves to the beginning of the last line to indicate that the search
+is in progress; the search may then
+be terminated with a \s-2DEL\s0 or \s-2RUB\s0, or by backspacing when
+at the beginning of the bottom line, returning the cursor to
+its initial position.
+Searches normally wrap end-around to find a string
+anywhere in the buffer.
+.IP
+When used with an operator the enclosed region is normally affected.
+By mentioning an
+offset from the line matched by the pattern you can force whole lines
+to be affected. To do this give a pattern with a closing
+a closing \fB/\fR and then an offset \fB+\fR\fIn\fR or \fB\-\fR\fIn\fR.
+.IP
+To include the character \fB/\fR in the search string, you must escape
+it with a preceding \fB\e\fR.
+A \fB\(ua\fR at the beginning of the pattern forces the match to occur
+at the beginning of a line only; this speeds the search. A \fB$\fR at
+the end of the pattern forces the match to occur at the end of a line
+only.
+More extended pattern matching is available, see section 7.4;
+unless you set \fBnomagic\fR in your \fI\&.exrc\fR file you will have
+to preceed the characters \fB. [ *\fR and \fB~\fR in the search pattern
+with a \fB\e\fR to get them to work as you would naively expect (1.5, 2,2,
+6.1, 7.2, 7.4).
+.iP "0" 15
+Moves to the first character on the current line.
+Also used, in forming numbers, after an initial \fB1\fR\-\fB9\fR.
+.iP "1\-9" 15
+Used to form numeric arguments to commands (2.3, 7.2).
+.iP ":" 15
+A prefix to a set of commands for file and option manipulation and escapes
+to the system. Input is given on the bottom line and terminated with
+an \s-2CR\s0, and the command then executed. You can return to where
+you were by hitting \s-2DEL\s0 or \s-2RUB\s0 if you hit \fB:\fR accidentally
+(see primarily 6.2 and 7.3).
+.iP ";" 15
+Repeats the last single character find which used \fBf F t\fR or \fBT\fR.
+A count iterates the basic scan (4.1).
+.iP "<" 15
+An operator which shifts lines left one \fIshiftwidth\fR, normally 8
+spaces. Like all operators, affects lines when repeated, as in
+\fB<<\fR. Counts are passed through to the basic object, thus \fB3<<\fR
+shifts three lines (6.6, 7.2).
+.iP "=" 15
+Reindents line for \s-2LISP\s0, as though they were typed in with \fIlisp\fR
+and \fIautoindent\fR set (6.8).
+.iP ">" 15
+An operator which shifts lines right one \fIshiftwidth\fR, normally 8
+spaces. Affects lines when repeated as in \fB>>\fR. Counts repeat the
+basic object (6.6, 7.2).
+.iP "?" 15
+Scans backwards, the opposite of \fB/\fR. See the \fB/\fR description
+above for details on scanning (2.2, 6.1, 7.4).
+.iP "@" 15
+A macro character (6.9). If this is your kill character, you must escape it with a \e
+to type it in during input mode, as it normally backs over the input you
+have given on the current line (3.1, 3.4, 7.5).
+.iP "A" 15
+Appends at the end of line, a synonym for \fB$a\fR (7.2).
+.iP "B" 15
+Backs up a word, where words are composed of non-blank sequences, placing
+the cursor at the beginning of the word. A count repeats the effect
+(2.4).
+.iP "C" 15
+Changes the rest of the text on the current line; a synonym for \fBc$\fR.
+.iP "D" 15
+Deletes the rest of the text on the current line; a synonym for \fBd$\fR.
+.iP "E" 15
+Moves forward to the end of a word, defined as blanks and non-blanks,
+like \fBB\fR and \fBW\fR. A count repeats the effect.
+.iP "F" 15
+Finds a single following character, backwards in the current line.
+A count repeats this search that many times (4.1).
+.iP "G" 15
+Goes to the line number given as preceding argument, or the end of the
+file if no preceding count is given. The screen is redrawn with the
+new current line in the center if necessary (7.2).
+.iP "H" 15
+.B "Home arrow" .
+Homes the cursor to the top line on the screen. If a count is given,
+then the cursor is moved to the count'th line on the screen.
+In any case the cursor is moved to the first non-white character on the
+line. If used as the target of an operator, full lines are affected
+(2.3, 3.2).
+.iP "I" 15
+Inserts at the beginning of a line; a synonym for \fB\(uai\fR.
+.iP "J" 15
+Joins together lines, supplying appropriate white space: one space between
+words, two spaces after a \fB.\fR, and no spaces at all if the first
+character of the joined on line is \fB)\fR. A count causes that many
+lines to be joined rather than the default two (6.5, 7.1f).
+.iP "K" 15
+Unused.
+.iP "L" 15
+Moves the cursor to the first non-white character of the last line on
+the screen. With a count, to the first non-white of the count'th line
+from the bottom. Operators affect whole lines when used with \fBL\fR
+(2.3).
+.iP "M" 15
+Moves the cursor to the middle line on the screen, at the first non-white
+position on the line (2.3).
+.iP "N" 15
+Scans for the next match of the last pattern given to
+\fB/\fR or \fB?\fR, but in the reverse direction; this is the reverse
+of \fBn\fR.
+.iP "O" 15
+Opens a new line above the current line and inputs text there up to an
+\s-2ESC\s0. A count can be used on dumb terminals to specify a number
+of lines to be opened; this is generally obsolete, as the \fIslowopen\fR
+option works better (3.1).
+.iP "P" 15
+Puts the last deleted text back before/above the cursor. The text goes
+back as whole lines above the cursor if it was deleted as whole lines.
+Otherwise the text is inserted between the characters before and at the
+cursor. May be preceded by a named buffer specification \fB"\fR\fIx\fR
+to retrieve the contents of the buffer; buffers \fB1\fR\-\fB9\fR contain
+deleted material, buffers \fBa\fR\-\fBz\fR are available for general
+use (6.3).
+.iP "Q" 15
+Quits from \fIvi\fR to \fIex\fR command mode. In this mode, whole lines
+form commands, ending with a \s-2RETURN\s0. You can give all the \fB:\fR
+commands; the editor supplies the \fB:\fR as a prompt (7.7).
+.iP "R" 15
+Replaces characters on the screen with characters you type (overlay fashion).
+Terminates with an \s-2ESC\s0.
+.iP "S" 15
+Changes whole lines, a synonym for \fBcc\fR. A count substitutes for
+that many lines. The lines are saved in the numeric buffers, and erased
+on the screen before the substitution begins.
+.iP "T" 15
+Takes a single following character, locates the character before the
+cursor in the current line, and places the cursor just after that character.
+A count repeats the effect. Most useful with operators such as \fBd\fR
+(4.1).
+.iP "U" 15
+Restores the current line to its state before you started changing it
+(3.5).
+.iP "V" 15
+Unused.
+.iP "W" 15
+Moves forward to the beginning of a word in the current line,
+where words are defined as sequences of blank/non-blank characters.
+A count repeats the effect (2.4).
+.iP "X" 15
+Deletes the character before the cursor. A count repeats the effect,
+but only characters on the current line are deleted.
+.iP "Y" 15
+Yanks a copy of the current line into the unnamed buffer, to be put back
+by a later \fBp\fR or \fBP\fR; a very useful synonym for \fByy\fR.
+A count yanks that many lines. May be preceded by a buffer name to put
+lines in that buffer (7.4).
+.iP "ZZ" 15
+Exits the editor.
+(Same as \fB:x\fP\s-2CR\s0.)
+If any changes have been made, the buffer is written out to the current file.
+Then the editor quits.
+.iP "[[" 15
+Backs up to the previous section boundary. A section begins at each
+macro in the \fIsections\fR option,
+normally a `.NH' or `.SH' and also at lines which which start
+with a formfeed \fB^L\fR. Lines beginning with \fB{\fR also stop \fB[[\fR;
+this makes it useful for looking backwards, a function at a time, in C
+programs. If the option \fIlisp\fR is set, stops at each \fB(\fR at the
+beginning of a line, and is thus useful for moving backwards at the top
+level \s-2LISP\s0 objects. (4.2, 6.1, 6.6, 7.2).
+.iP "\e" 15
+Unused.
+.iP "]]" 15
+Forward to a section boundary, see \fB[[\fR for a definition (4.2, 6.1,
+6.6, 7.2).
+.iP "\(ua" 15
+Moves to the first non-white position on the current line (4.4).
+.iP "_" 15
+Unused.
+.iP "\(ga" 15
+When followed by a \fB\(ga\fR returns to the previous context.
+The previous context is set whenever the current
+line is moved in a non-relative way.
+When followed by a letter \fBa\fR\-\fBz\fR, returns to the position which
+was marked with this letter with a \fBm\fR command.
+When used with an operator such as \fBd\fR, the operation takes place
+from the exact marked place to the current position within the line;
+if you use \fB\(aa\fR, the operation takes place over complete lines
+(2.2, 5.3).
+.iP "a" 15
+Appends arbitrary text after the current cursor position; the insert
+can continue onto multiple lines by using \s-2RETURN\s0 within the insert.
+A count causes the inserted text to be replicated, but only if the inserted
+text is all on one line.
+The insertion terminates with an \s-2ESC\s0 (3.1, 7.2).
+.iP "b" 15
+Backs up to the beginning of a word in the current line. A word is a
+sequence of alphanumerics, or a sequence of special characters.
+A count repeats the effect (2.4).
+.iP "c" 15
+An operator which changes the following object, replacing it with the
+following input text up to an \s-2ESC\s0. If more than part of a single
+line is affected, the text which is changed away is saved in the numeric named
+buffers. If only part of the current line is affected, then the last
+character to be changed away is marked with a \fB$\fR.
+A count causes that many objects to be affected, thus both
+\fB3c)\fR and \fBc3)\fR change the following three sentences (7.4).
+.iP "d" 15
+An operator which deletes the following object. If more than part of
+a line is affected, the text is saved in the numeric buffers.
+A count causes that many objects to be affected; thus \fB3dw\fR is the
+same as \fBd3w\fR (3.3, 3.4, 4.1, 7.4).
+.iP "e" 15
+Advances to the end of the next word, defined as for \fBb\fR and \fBw\fR.
+A count repeats the effect (2.4, 3.1).
+.iP "f" 15
+Finds the first instance of the next character following the cursor on
+the current line. A count repeats the find (4.1).
+.iP "g" 15
+Unused.
+.sp
+Arrow keys
+.B h ,
+.B j ,
+.B k ,
+.B l ,
+and
+.B H .
+.iP "h" 15
+.B "Left arrow" .
+Moves the cursor one character to the left.
+Like the other arrow keys, either
+.B h ,
+the
+.B "left arrow"
+key, or one of the synonyms (\fB^H\fP) has the same effect.
+On v2 editors, arrow keys on certain kinds of terminals
+(those which send escape sequences, such as vt52, c100, or hp)
+cannot be used.
+A count repeats the effect (3.1, 7.5).
+.iP "i" 15
+Inserts text before the cursor, otherwise like \fBa\fR (7.2).
+.iP "j" 15
+.B "Down arrow" .
+Moves the cursor one line down in the same column.
+If the position does not exist,
+.I vi
+comes as close as possible to the same column.
+Synonyms include
+.B ^J
+(linefeed) and
+.B ^N .
+.iP "k" 15
+.B "Up arrow" .
+Moves the cursor one line up.
+.B ^P
+is a synonym.
+.iP "l" 15
+.B "Right arrow" .
+Moves the cursor one character to the right.
+\s-2SPACE\s0 is a synonym.
+.iP "m" 15
+Marks the current position of the cursor in the mark register which is
+specified by the next character \fBa\fR\-\fBz\fR. Return to this position
+or use with an operator using \fB\(ga\fR or \fB\(aa\fR (5.3).
+.iP "n" 15
+Repeats the last \fB/\fR or \fB?\fR scanning commands (2.2).
+.iP "o" 15
+Opens new lines below the current line; otherwise like \fBO\fR (3.1).
+.iP "p" 15
+Puts text after/below the cursor; otherwise like \fBP\fR (6.3).
+.iP "q" 15
+Unused.
+.iP "r" 15
+Replaces the single character at the cursor with a single character you
+type. The new character may be a \s-2RETURN\s0; this is the easiest
+way to split lines. A count replaces each of the following count characters
+with the single character given; see \fBR\fR above which is the more
+usually useful iteration of \fBr\fR (3.2).
+.iP "s" 15
+Changes the single character under the cursor to the text which follows
+up to an \s-2ESC\s0; given a count, that many characters from the current
+line are changed. The last character to be changed is marked with \fB$\fR
+as in \fBc\fR (3.2).
+.iP "t" 15
+Advances the cursor upto the character before the next character typed.
+Most useful with operators such as \fBd\fR and \fBc\fR to delete the
+characters up to a following character. You can use \fB.\fR to delete
+more if this doesn't delete enough the first time (4.1).
+.iP "u" 15
+Undoes the last change made to the current buffer. If repeated, will
+alternate between these two states, thus is its own inverse. When used
+after an insert which inserted text on more than one line, the lines are
+saved in the numeric named buffers (3.5).
+.iP "v" 15
+Unused.
+.iP "w" 15
+Advances to the beginning of the next word, as defined by \fBb\fR (2.4).
+.iP "x" 15
+Deletes the single character under the cursor. With a count deletes
+deletes that many characters forward from the cursor position, but only
+on the current line (6.5).
+.iP "y" 15
+An operator, yanks the following object into the unnamed temporary buffer.
+If preceded by a named buffer specification, \fB"\fR\fIx\fR, the text
+is placed in that buffer also. Text can be recovered by a later \fBp\fR
+or \fBP\fR (7.4).
+.iP "z" 15
+Redraws the screen with the current line placed as specified by the following
+character: \s-2RETURN\s0 specifies the top of the screen, \fB.\fR the
+center of the screen, and \fB\-\fR at the bottom of the screen.
+A count may be given after the \fBz\fR and before the following character
+to specify the new screen size for the redraw.
+A count before the \fBz\fR gives the number of the line to place in the
+center of the screen instead of the default current line. (5.4)
+.iP "{" 15
+Retreats to the beginning of the beginning of the preceding paragraph.
+A paragraph begins at each macro in the \fIparagraphs\fR option, normally
+`.IP', `.LP', `.PP', `.QP' and `.bp'.
+A paragraph also begins after a completely
+empty line, and at each section boundary (see \fB[[\fR above) (4.2, 6.8,
+7.6).
+.iP "|" 15
+Places the cursor on the character in the column specified
+by the count (7.1, 7.2).
+.iP "}" 15
+Advances to the beginning of the next paragraph. See \fB{\fR for the
+definition of paragraph (4.2, 6.8, 7.6).
+.iP "~" 15
+Unused.
+.iP "^?\ (\s-2\fRDEL\fP\s0)" 15
+Interrupts the editor, returning it to command accepting state (1.5,
+7.5)
+.bp
+\&.
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.in b/usr.bin/vi/docs/USD.doc/vi/vi.in
new file mode 100644
index 000000000000..3bdfeb95b65e
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.in
@@ -0,0 +1,2064 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)vi.in 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:12-%''An Introduction to Display Editing with Vi'
+.OH 'An Introduction to Display Editing with Vi''USD:12-%'
+.bd S 3
+.if t .ds dg \(dg
+.if n .ds dg +
+.if t .ds dd \(dd
+.if n .ds dd ++
+.\".RP
+.TL
+An Introduction to Display Editing with Vi
+.AU
+William Joy
+.AU
+Mark Horton
+.AI
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, Ca. 94720
+.AB
+.PP
+.I Vi
+(visual) is a display oriented interactive text editor.
+When using
+.I vi
+the screen of your terminal acts as a window into the file which you
+are editing. Changes which you make to the file are reflected
+in what you see.
+.PP
+Using
+.I vi
+you can insert new text any place in the file quite easily.
+Most of the commands to
+.I vi
+move the cursor around in the file.
+There are commands to move the cursor
+forward and backward in units of characters, words,
+sentences and paragraphs.
+A small set of operators, like
+.B d
+for delete and
+.B c
+for change, are combined with the motion commands to form operations
+such as delete word or change paragraph, in a simple and natural way.
+This regularity and the mnemonic assignment of commands to keys makes the
+editor command set easy to remember and to use.
+.PP
+.I Vi
+will work on a large number of display terminals,
+and new terminals are easily driven after editing a terminal description file.
+While it is advantageous to have an intelligent terminal which can locally
+insert and delete lines and characters from the display, the editor will
+function quite well on dumb terminals over slow phone lines.
+The editor makes allowance for the low bandwidth in these situations
+and uses smaller window sizes and
+different display updating algorithms to make best use of the
+limited speed available.
+.PP
+It is also possible to use the command set of
+.I vi
+on hardcopy terminals, storage tubes and ``glass tty's'' using a one line
+editing window; thus
+.I vi's
+command set is available on all terminals.
+The full command set of the more traditional, line
+oriented editor
+.I ex
+is available within
+.I vi;
+it is quite simple to switch between the two modes of editing.
+.AE
+.NH 1
+Getting started
+.PP
+.FS
+The financial support of an \s-2IBM\s0 Graduate Fellowship and the
+National Science Foundation under grants MCS74-07644-A03 and MCS78-07291
+is gratefully acknowledged.
+.FE
+This document provides a quick introduction to
+.I vi.
+(Pronounced \fIvee-eye\fP.)
+You should be running
+.I vi
+on a file you are familiar with while you are reading this.
+The first part of this document (sections 1 through 5)
+describes the basics of using
+.I vi.
+Some topics of special interest are presented in section 6, and
+some nitty-gritty details of how the editor functions are saved for section
+7 to avoid cluttering the presentation here.
+.PP
+There is also a short appendix here, which gives for each character the
+special meanings which this character has in \fIvi\fR. Attached to
+this document should be a quick reference card.
+This card summarizes the commands of
+.I vi
+in a very compact format. You should have the card handy while you are
+learning
+.I vi.
+.NH 2
+Specifying terminal type
+.PP
+Before you can start
+.I vi
+you must tell the system what kind of terminal you are using.
+Here is a (necessarily incomplete) list of terminal type codes.
+If your terminal does not appear here, you should consult with one of
+the staff members on your system to find out the code for your terminal.
+If your terminal does not have a code, one can be assigned and a description
+for the terminal can be created.
+.LP
+.TS
+center;
+ab ab ab
+a a a.
+Code Full name Type
+_
+2621 Hewlett-Packard 2621A/P Intelligent
+2645 Hewlett-Packard 264x Intelligent
+act4 Microterm ACT-IV Dumb
+act5 Microterm ACT-V Dumb
+adm3a Lear Siegler ADM-3a Dumb
+adm31 Lear Siegler ADM-31 Intelligent
+c100 Human Design Concept 100 Intelligent
+dm1520 Datamedia 1520 Dumb
+dm2500 Datamedia 2500 Intelligent
+dm3025 Datamedia 3025 Intelligent
+fox Perkin-Elmer Fox Dumb
+h1500 Hazeltine 1500 Intelligent
+h19 Heathkit h19 Intelligent
+i100 Infoton 100 Intelligent
+mime Imitating a smart act4 Intelligent
+t1061 Teleray 1061 Intelligent
+vt52 Dec VT-52 Dumb
+.TE
+.PP
+Suppose for example that you have a Hewlett-Packard HP2621A
+terminal. The code used by the system for this terminal is `2621'.
+In this case you can use one of the following commands to tell the system
+the type of your terminal:
+.DS
+% \fBsetenv TERM\fP 2621
+.DE
+This command works with the
+.I csh
+shell.
+If you are using the standard Bourne shell
+.I sh
+then you should give the commands
+.DS
+$ \fBTERM=\fP2621
+$ \fBexport TERM\fP
+.DE
+.PP
+If you want to arrange to have your terminal type set up automatically
+when you log in, you can use the
+.I tset
+program.
+If you dial in on a
+.I mime ,
+but often use hardwired ports, a typical line for your
+.I .login
+file (if you use csh) would be
+.DS
+\fBsetenv TERM \(gatset\fP \- \-d mime\(ga
+.DE
+or for your
+.I .profile
+file (if you use sh)
+.DS
+\fBTERM=\(gatse\fPt \- \-d mime\(ga
+.DE
+.I Tset
+knows which terminals are hardwired to each port
+and needs only to be told that when you dial in you
+are probably on a
+.I mime .
+.I Tset
+is usually used to change the erase and kill characters, too.
+.NH 2
+Editing a file
+.PP
+After telling the system which kind of terminal you have, you should
+make a copy of a file you are familiar with, and run
+.I vi
+on this file, giving the command
+.DS
+% \fBvi\fR \fIname\fR
+.DE
+replacing \fIname\fR with the name of the copy file you just created.
+The screen should clear and the text of your file should appear on the
+screen. If something else happens refer to the footnote.\*(dd
+.FS
+\*(dd If you gave the system an incorrect terminal type code then the
+editor may have just made a mess out of your screen. This happens when
+it sends control codes for one kind of terminal to some other
+kind of terminal. In this case hit
+the keys \fB:q\fR (colon and the q key) and then hit the \s-2RETURN\s0 key.
+This should get you back to the command level interpreter.
+Figure out what you did wrong (ask someone else if necessary) and try again.
+ Another thing which can go wrong is that you typed the wrong file name and
+the editor just printed an error diagnostic. In this case you should
+follow the above procedure for getting out of the editor, and try again
+this time spelling the file name correctly.
+ If the editor doesn't seem to respond to the commands which you type
+here, try sending an interrupt to it by hitting the \s-2DEL\s0 or \s-2RUB\s0
+key on your terminal, and then hitting the \fB:q\fR command again followed
+by a carriage return.
+.sp
+.FE
+.NH 2
+The editor's copy: the buffer
+.PP
+The editor does not directly modify the file which you are editing.
+Rather, the editor makes a copy of this file, in a place called the
+.I buffer,
+and remembers the file's
+name. You do not affect the contents of the file unless and until you
+write the changes you make back into the original file.
+.NH 2
+Notational conventions
+.PP
+In our examples, input which must be typed as is will be presented in
+\fBbold face\fR. Text which should be replaced with appropriate input
+will be given in \fIitalics\fR. We will represent special characters
+in \s-2SMALL CAPITALS\s0.
+.NH 2
+Arrow keys
+.PP
+The editor command set is independent of the terminal
+you are using. On most terminals with cursor positioning keys, these keys
+will also work within the editor.
+If you don't have cursor positioning keys, or even if you do, you can use
+the \fBh j k\fR and \fBl\fR keys as cursor positioning
+keys (these are labelled with arrows on an
+.I adm3a).*
+.PP
+(Particular note for the HP2621: on this terminal the function keys
+must be \fIshifted\fR (ick) to send to the machine, otherwise they
+only act locally. Unshifted use will leave the cursor positioned
+incorrectly.)
+.FS
+* As we will see later,
+.I h
+moves back to the left (like control-h which is a backspace),
+.I j
+moves down (in the same column),
+.I k
+moves up (in the same column),
+and
+.I l
+moves to the right.
+.FE
+.NH 2
+Special characters: \s-2ESC\s0, \s-2CR\s0 and \s-2DEL\s0
+.PP
+Several of these special characters are very important, so be sure to
+find them right now. Look on your keyboard for a key labelled \s-2ESC\s0
+or \s-2ALT\s0. It should be near the upper left corner of your terminal.
+Try hitting this key a few times. The editor will ring the bell
+to indicate that it is in a quiescent state.\*(dd
+.FS
+\*(dd On smart terminals where it is possible, the editor will quietly
+flash the screen rather than ringing the bell.
+.FE
+Partially formed commands are cancelled by \s-2ESC\s0, and when you insert
+text in the file you end the text insertion
+with \s-2ESC\s0. This key is a fairly
+harmless one to hit, so you can just hit it if you don't know
+what is going on until the editor rings the bell.
+.PP
+The \s-2CR\s0 or \s-2RETURN\s0 key is important because it is used
+to terminate certain commands.
+It is usually at the right side of the keyboard,
+and is the same command used at the end of each shell command.
+.PP
+Another very useful key is the \s-2DEL\s0 or \s-2RUB\s0 key, which generates
+an interrupt, telling the editor to stop what it is doing.
+It is a forceful way of making the editor listen
+to you, or to return it to the quiescent state if you don't know or don't
+like what is going on. Try hitting the `/' key on your terminal. This
+key is used when you want to specify a string to be searched for. The
+cursor should now be positioned at the bottom line of the terminal after
+a `/' printed as a prompt. You can get the cursor back to the current
+position by hitting the \s-2DEL\s0 or \s-2RUB\s0 key; try this now.*
+.FS
+* Backspacing over the `/' will also cancel the search.
+.FE
+From now on we will simply refer to hitting the \s-2DEL\s0 or \s-2RUB\s0
+key as ``sending an interrupt.''**
+.FS
+** On some systems, this interruptibility comes at a price: you cannot type
+ahead when the editor is computing with the cursor on the bottom line.
+.FE
+.PP
+The editor often echoes your commands on the last line of the terminal.
+If the cursor is on the first position of this last line, then the editor
+is performing a computation, such as computing a new position in the
+file after a search or running a command to reformat part of the buffer.
+When this is happening you can stop the editor by
+sending an interrupt.
+.NH 2
+Getting out of the editor
+.PP
+After you have worked with this introduction for a while, and you wish
+to do something else, you can give the command \fBZZ\fP
+to the editor.
+This will write the contents of the editor's buffer back into
+the file you are editing, if you made any changes, and then quit from
+the editor. You can also end an editor
+session by giving the command \fB:q!\fR\s-2CR\s0;\*(dg
+.FS
+\*(dg All commands which read from the last display line can also be
+terminated with a \s-2ESC\s0 as well as an \s-2CR\s0.
+.FE
+this is a dangerous but occasionally essential
+command which ends the editor session and discards all your changes.
+You need to know about this command in case you change the editor's
+copy of a file you wish only to look at. Be very careful
+not to give this command when you really want to save
+the changes you have made.
+.NH 1
+Moving around in the file
+.NH 2
+Scrolling and paging
+.PP
+The editor has a number of commands for moving around in the file.
+The most useful of these is generated by hitting the control and D keys
+at the same time, a control-D or `^D'. We will use this two character
+notation for referring to these control keys from now on. You may have
+a key labelled `^' on your terminal. This key will be represented as `\(ua'
+in this document; `^' is exclusively used as part of the `^x' notation
+for control characters.\*(dd
+.FS
+\*(dd If you don't have a `^' key on your terminal
+then there is probably a key labelled `\(ua'; in any case these characters
+are one and the same.
+.FE
+.PP
+As you know now if you tried hitting \fB^D\fR, this command scrolls down in
+the file. The \fBD\fR thus stands for down. Many editor commands are mnemonic
+and this makes them much easier to remember. For instance the command
+to scroll up is \fB^U\fR. Many dumb terminals can't scroll up at all, in which
+case hitting \fB^U\fR clears the screen and refreshes it
+with a line which is farther back in the file at the top.
+.PP
+If you want to see more of the file below where you are, you can
+hit \fB^E\fR to expose one more line at the bottom of the screen,
+leaving the cursor where it is.
+The command \fB^Y\fR (which is hopelessly non-mnemonic, but next to \fB^U\fR
+on the keyboard) exposes one more line at the top of the screen.
+.PP
+There are other ways to move around in the file; the keys \fB^F\fR and \fB^B\fR
+move forward and backward a page,
+keeping a couple of lines of continuity between screens
+so that it is possible to read through a file using these rather than
+\fB^D\fR and \fB^U\fR if you wish.
+.PP
+Notice the difference between scrolling and paging. If you are trying
+to read the text in a file, hitting \fB^F\fR to move forward a page
+will leave you only a little context to look back at. Scrolling on the
+other hand leaves more context, and happens more smoothly. You can continue
+to read the text as scrolling is taking place.
+.NH 2
+Searching, goto, and previous context
+.PP
+Another way to position yourself in the file is by giving the editor a string
+to search for. Type the character \fB/\fR followed by a string of characters
+terminated by \s-2CR\s0. The editor will position the cursor
+at the next occurrence of this string.
+Try hitting \fBn\fR to then go to the next occurrence of this string.
+The character \fB?\fR will search backwards from where you are, and is
+otherwise like \fB/\fR.\*(dg
+.FS
+\*(dg These searches will normally wrap around the end of the file, and thus
+find the string even if it is not on a line in the direction you search
+provided it is anywhere else in the file. You can disable this wraparound
+in scans by giving the command \fB:se nowrapscan\fR\s-2CR\s0,
+or more briefly \fB:se nows\fR\s-2CR\s0.
+.FE
+.PP
+If the search string you give the editor is not present in the
+file the editor will print
+a diagnostic on the last line of the screen, and the cursor will be returned
+to its initial position.
+.PP
+If you wish the search to match only at the beginning of a line, begin
+the search string with an \fB\(ua\fR. To match only at the end of
+a line, end the search string with a \fB$\fR.
+Thus \fB/\(uasearch\fR\s-2CR\s0 will search for the word `search' at
+the beginning of a line, and \fB/last$\fR\s-2CR\s0 searches for the
+word `last' at the end of a line.*
+.FS
+*Actually, the string you give to search for here can be a
+.I "regular expression"
+in the sense of the editors
+.I ex (1)
+and
+.I ed (1).
+If you don't wish to learn about this yet, you can disable this more
+general facility by doing
+\fB:se\ nomagic\fR\s-2CR\s0;
+by putting this command in
+EXINIT
+in your environment, you can have this always be in effect (more
+about
+.I EXINIT
+later.)
+.FE
+.PP
+The command \fBG\fR, when preceded by a number will position the cursor
+at that line in the file.
+Thus \fB1G\fR will move the cursor to
+the first line of the file. If you give \fBG\fR no count, then it moves
+to the end of the file.
+.PP
+If you are near the end of the file, and the last line is not at the bottom
+of the screen, the editor will place only the character `~' on each remaining
+line. This indicates that the last line in the file is on the screen;
+that is, the `~' lines are past the end of the file.
+.PP
+You can find out the state of the file you are editing by typing a \fB^G\fR.
+The editor will show you the name of the file you are editing, the number
+of the current line, the number of lines in the buffer, and the percentage
+of the way through the buffer which you are.
+Try doing this now, and remember the number of the line you are on.
+Give a \fBG\fR command to get to the end and then another \fBG\fR command
+to get back where you were.
+.PP
+You can also get back to a previous position by using the command
+\fB\(ga\(ga\fR (two back quotes).
+This is often more convenient than \fBG\fR because it requires no advance
+preparation.
+Try giving a \fBG\fR or a search with \fB/\fR or \fB?\fR and then a
+\fB\(ga\(ga\fR to get back to where you were. If you accidentally hit
+\fBn\fR or any command which moves you far away from a context of interest, you
+can quickly get back by hitting \fB\(ga\(ga\fR.
+.NH 2
+Moving around on the screen
+.PP
+Now try just moving the cursor around on the screen.
+If your terminal has arrow keys (4 or 5 keys with arrows
+going in each direction) try them and convince yourself
+that they work.
+If you don't have working arrow keys, you can always use
+.B h ,
+.B j ,
+.B k ,
+and
+.B l .
+Experienced users of
+.I vi
+prefer these keys to arrow keys,
+because they are usually right underneath their fingers.
+.PP
+Hit the \fB+\fR key. Each time you do, notice that the cursor
+advances to the next line in the file, at the first non-white position
+on the line. The \fB\-\fR key is like \fB+\fR but goes the other way.
+.PP
+These are very common keys for moving up and down lines in the file.
+Notice that if you go off the bottom or top with these keys then the
+screen will scroll down (and up if possible) to bring a line at a time
+into view. The \s-2RETURN\s0 key has the same effect as the \fB+\fR
+key.
+.PP
+.I Vi
+also has commands to take you to the top, middle and bottom of the screen.
+\fBH\fR will take you to the top (home) line on the screen.
+Try preceding it with a
+number as in \fB3H\fR.
+This will take you to the third line on the screen.
+Many
+.I vi
+commands take preceding numbers and do interesting things with them.
+Try \fBM\fR,
+which takes you to the middle line on the screen,
+and \fBL\fR,
+which takes you to the last line on the screen.
+\fBL\fR also takes counts, thus
+\fB5L\fR will take you to the fifth line from the bottom.
+.NH 2
+Moving within a line
+.PP
+Now try picking a word on some line on the screen, not the
+first word on the line.
+move the cursor using \s-2RETURN\s0 and \fB\-\fR to be on the line where
+the word is.
+Try hitting the \fBw\fR key. This will advance the cursor to the
+next word on the line.
+Try hitting the \fBb\fR key to back up words
+in the line.
+Also try the \fBe\fR key which advances you to the end of the current
+word rather than to the beginning of the next word.
+Also try \s-2SPACE\s0 (the space bar) which moves right one character
+and the \s-2BS\s0 (backspace or \fB^H\fR) key which moves left one character.
+The key \fBh\fR works as \fB^H\fR does and is useful if you don't have
+a \s-2BS\s0 key.
+(Also, as noted just above, \fBl\fR will move to the right.)
+.PP
+If the line had punctuation in it you may have noticed that
+that the \fBw\fR and \fBb\fR
+keys stopped at each group of punctuation. You can also go back and
+forwards words without stopping at punctuation by using \fBW\fR and \fBB\fR
+rather than the lower case equivalents. Think of these as bigger words.
+Try these on a few lines with punctuation to see how they differ from
+the lower case \fBw\fR and \fBb\fR.
+.PP
+The word keys wrap around the end of line,
+rather than stopping at the end. Try moving to a word on a line below
+where you are by repeatedly hitting \fBw\fR.
+.NH 2
+Summary
+.IP
+.TS
+lw(.50i)b a.
+\fR\s-2SPACE\s0\fP advance the cursor one position
+^B backwards to previous page
+^D scrolls down in the file
+^E exposes another line at the bottom
+^F forward to next page
+^G tell what is going on
+^H backspace the cursor
+^N next line, same column
+^P previous line, same column
+^U scrolls up in the file
+^Y exposes another line at the top
++ next line, at the beginning
+\- previous line, at the beginning
+/ scan for a following string forwards
+? scan backwards
+B back a word, ignoring punctuation
+G go to specified line, last default
+H home screen line
+M middle screen line
+L last screen line
+W forward a word, ignoring punctuation
+b back a word
+e end of current word
+n scan for next instance of \fB/\fR or \fB?\fR pattern
+w word after this word
+.TE
+.NH 2
+View
+.PP
+If you want to use the editor to look at a file,
+rather than to make changes,
+invoke it as
+.I view
+instead of
+.I vi .
+This will set the
+.I readonly
+option which will prevent you from
+accidently overwriting the file.
+.NH 1
+Making simple changes
+.NH 2
+Inserting
+.PP
+One of the most useful commands is the
+\fBi\fR (insert) command.
+After you type \fBi\fR, everything you type until you hit \s-2ESC\s0
+is inserted into the file.
+Try this now; position yourself to some word in the file and try inserting
+text before this word.
+If you are on an dumb terminal it will seem, for a minute,
+that some of the characters in your line have been overwritten, but they will
+reappear when you hit \s-2ESC\s0.
+.PP
+Now try finding a word which can, but does not, end in an `s'.
+Position yourself at this word and type \fBe\fR (move to end of word), then
+\fBa\fR for append and then `s\s-2ESC\s0' to terminate the textual insert.
+This sequence of commands can be used to easily pluralize a word.
+.PP
+Try inserting and appending a few times to make sure you understand how
+this works; \fBi\fR placing text to the left of the cursor, \fBa\fR to
+the right.
+.PP
+It is often the case that you want to add new lines to the file you are
+editing, before or after some specific line in the file. Find a line
+where this makes sense and then give the command \fBo\fR to create a
+new line after the line you are on, or the command \fBO\fR to create
+a new line before the line you are on. After you create a new line in
+this way, text you type up to an \s-2ESC\s0 is inserted on the new line.
+.PP
+Many related editor commands
+are invoked by the same letter key and differ only in that one is given
+by a lower
+case key and the other is given by
+an upper case key. In these cases, the
+upper case key often differs from the lower case key in its sense of
+direction, with
+the upper case key working backward and/or up, while the lower case
+key moves forward and/or down.
+.PP
+Whenever you are typing in text, you can give many lines of input or
+just a few characters.
+To type in more than one line of text,
+hit a \s-2RETURN\s0 at the middle of your input. A new line will be created
+for text, and you can continue to type. If you are on a slow
+and dumb terminal the editor may choose to wait to redraw the
+tail of the screen, and will let you type over the existing screen lines.
+This avoids the lengthy delay which would occur if the editor attempted
+to keep the tail of the screen always up to date. The tail of the screen will
+be fixed up, and the missing lines will reappear, when you hit \s-2ESC\s0.
+.PP
+While you are inserting new text, you can use the characters you normally use
+at the system command level (usually \fB^H\fR or \fB#\fR) to backspace
+over the last
+character which you typed, and the character which you use to kill input lines
+(usually \fB@\fR, \fB^X\fR, or \fB^U\fR)
+to erase the input you have typed on the current line.\*(dg
+.FS
+\*(dg In fact, the character \fB^H\fR (backspace) always works to erase the
+last input character here, regardless of what your erase character is.
+.FE
+The character \fB^W\fR
+will erase a whole word and leave you after the space after the previous
+word; it is useful for quickly backing up in an insert.
+.PP
+Notice that when you backspace during an insertion the characters you
+backspace over are not erased; the cursor moves backwards, and the characters
+remain on the display. This is often useful if you are planning to type
+in something similar. In any case the characters disappear when when
+you hit \s-2ESC\s0; if you want to get rid of them immediately, hit an
+\s-2ESC\s0 and then \fBa\fR again.
+.PP
+Notice also that you can't erase characters which you didn't insert, and that
+you can't backspace around the end of a line. If you need to back up
+to the previous line to make a correction, just hit \s-2ESC\s0 and move
+the cursor back to the previous line. After making the correction you
+can return to where you were and use the insert or append command again.
+.NH 2
+Making small corrections
+.PP
+You can make small corrections in existing text quite easily.
+Find a single character which is wrong or just pick any character.
+Use the arrow keys to find the character, or
+get near the character with the word motion keys and then either
+backspace (hit the \s-2BS\s0 key or \fB^H\fR or even just \fBh\fR) or
+\s-2SPACE\s0 (using the space bar)
+until the cursor is on the character which is wrong.
+If the character is not needed then hit the \fBx\fP key; this deletes
+the character from the file. It is analogous to the way you \fBx\fP
+out characters when you make mistakes on a typewriter (except it's not
+as messy).
+.PP
+If the character
+is incorrect, you can replace it with the correct character by giving
+the command \fBr\fR\fIc\fR,
+where \fIc\fR is replaced by the correct character.
+Finally if the character which is incorrect should be replaced
+by more than one character, give the command \fBs\fR which substitutes
+a string of characters, ending with \s-2ESC\s0, for it.
+If there are a small number of characters
+which are wrong you can precede \fBs\fR with a count of the number of
+characters to be replaced. Counts are also useful with \fBx\fR to specify
+the number of characters to be deleted.
+.NH 2
+More corrections: operators
+.PP
+You already know almost enough to make changes at a higher level.
+All you need to know now is that the
+.B d
+key acts as a delete operator. Try the command
+.B dw
+to delete a word.
+Try hitting \fB.\fR a few times. Notice that this repeats the effect
+of the \fBdw\fR. The command \fB.\fR repeats the last command which
+made a change. You can remember it by analogy with an ellipsis `\fB...\fR'.
+.PP
+Now try
+\fBdb\fR.
+This deletes a word backwards, namely the preceding word.
+Try
+\fBd\fR\s-2SPACE\s0. This deletes a single character, and is equivalent
+to the \fBx\fR command.
+.PP
+Another very useful operator is
+.B c
+or change. The command
+.B cw
+thus changes the text of a single word.
+You follow it by the replacement text ending with an \s-2ESC\s0.
+Find a word which you can change to another, and try this
+now.
+Notice that the end of the text to be changed was marked with the character
+`$' so that you can see this as you are typing in the new material.
+.NH 2
+Operating on lines
+.PP
+It is often the case that you want to operate on lines.
+Find a line which you want to delete, and type
+\fBdd\fR,
+the
+.B d
+operator twice. This will delete the line.
+If you are on a dumb terminal, the editor may just erase the line on
+the screen, replacing it with a line with only an @ on it. This line
+does not correspond to any line in your file, but only acts as a place
+holder. It helps to avoid a lengthy redraw of the rest of the screen
+which would be necessary to close up the hole created by the deletion
+on a terminal without a delete line capability.
+.PP
+Try repeating the
+.B c
+operator twice; this will change a whole line, erasing its previous contents and
+replacing them with text you type up to an \s-2ESC\s0.\*(dg
+.FS
+\*(dg The command \fBS\fR is a convenient synonym for for \fBcc\fR, by
+analogy with \fBs\fR. Think of \fBS\fR as a substitute on lines, while
+\fBs\fR is a substitute on characters.
+.FE
+.PP
+You can delete or change more than one line by preceding the
+.B dd
+or
+.B cc
+with a count, i.e. \fB5dd\fR deletes 5 lines.
+You can also give a command like \fBdL\fR to delete all the lines up to
+and including
+the last line on the screen, or \fBd3L\fR to delete through the third from
+the bottom line. Try some commands like this now.*
+.FS
+* One subtle point here involves using the \fB/\fR search after a \fBd\fR.
+This will normally delete characters from the current position to the
+point of the match. If what is desired is to delete whole lines
+including the two points, give the pattern as \fB/pat/+0\fR, a line address.
+.FE
+Notice that the editor lets you know when you change a large number of
+lines so that you can see the extent of the change.
+The editor will also always tell you when a change you make affects text which
+you cannot see.
+.NH 2
+Undoing
+.PP
+Now suppose that the last change which you made was incorrect;
+you could use the insert, delete and append commands to put the correct
+material back. However, since it is often the case that we regret a
+change or make a change incorrectly, the editor provides a
+.B u
+(undo) command to reverse the last change which you made.
+Try this a few times, and give it twice in a row to notice that an
+.B u
+also undoes a
+.B u.
+.PP
+The undo command lets you reverse only a single change. After you make
+a number of changes to a line, you may decide that you would rather have
+the original state of the line back. The
+.B U
+command restores the current line to the state before you started changing
+it.
+.PP
+You can recover text which you delete, even if
+undo will not bring it back; see the section on recovering lost text
+below.
+.NH 2
+Summary
+.IP
+.TS
+lw(.50i)b a.
+\fR\s-2SPACE\s0\fP advance the cursor one position
+^H backspace the cursor
+^W erase a word during an insert
+\fRerase\fP your erase (usually ^H or #), erases a character during an insert
+\fRkill\fP your kill (usually @, ^X, or ^U), kills the insert on this line
+\&\fB.\fP repeats the changing command
+O opens and inputs new lines, above the current
+U undoes the changes you made to the current line
+a appends text after the cursor
+c changes the object you specify to the following text
+d deletes the object you specify
+i inserts text before the cursor
+o opens and inputs new lines, below the current
+u undoes the last change
+.TE
+.NH 1
+Moving about; rearranging and duplicating text
+.NH 2
+Low level character motions
+.PP
+Now move the cursor to a line where there is a punctuation or a bracketing
+character such as a parenthesis or a comma or period. Try the command
+\fBf\fR\fIx\fR where \fIx\fR is this character. This command finds
+the next \fIx\fR character to the right of the cursor in the current
+line. Try then hitting a \fB;\fR, which finds the next instance of the
+same character. By using the \fBf\fR command and then a sequence of
+\fB;\fR's you can often
+get to a particular place in a line much faster than with a sequence
+of word motions or \s-2SPACE\s0s.
+There is also a \fBF\fR command, which is like \fBf\fR, but searches
+backward. The \fB;\fR command repeats \fBF\fR also.
+.PP
+When you are operating on the text in a line it is often desirable to
+deal with the characters up to, but not including, the first instance of
+a character. Try \fBdf\fR\fIx\fR for some \fIx\fR now and
+notice that the \fIx\fR character is deleted. Undo this with \fBu\fR
+and then try \fBdt\fR\fIx\fR; the \fBt\fR here stands for to, i.e.
+delete up to the next \fIx\fR, but not the \fIx\fR. The command \fBT\fR
+is the reverse of \fBt\fR.
+.PP
+When working with the text of a single line, an \fB\(ua\fR moves the
+cursor to the first non-white position on the line, and a
+\fB$\fR moves it to the end of the line. Thus \fB$a\fR will append new
+text at the end of the current line.
+.PP
+Your file may have tab (\fB^I\fR) characters in it. These
+characters are represented as a number of spaces expanding to a tab stop,
+where tab stops are every 8 positions.*
+.FS
+* This is settable by a command of the form \fB:se ts=\fR\fIx\fR\s-2CR\s0,
+where \fIx\fR is 4 to set tabstops every four columns. This has
+effect on the screen representation within the editor.
+.FE
+When the cursor is at a tab, it sits on the last of the several spaces
+which represent that tab. Try moving the cursor back and forth over
+tabs so you understand how this works.
+.PP
+On rare occasions, your file may have nonprinting characters in it.
+These characters are displayed in the same way they are represented in
+this document, that is with a two character code, the first character
+of which is `^'. On the screen non-printing characters resemble a `^'
+character adjacent to another, but spacing or backspacing over the character
+will reveal that the two characters are, like the spaces representing
+a tab character, a single character.
+.PP
+The editor sometimes discards control characters,
+depending on the character and the setting of the
+.I beautify
+option,
+if you attempt to insert them in your file.
+You can get a control character in the file by beginning
+an insert and then typing a \fB^V\fR before the control
+character. The
+\fB^V\fR quotes the following character, causing it to be
+inserted directly into the file.
+.PP
+.NH 2
+Higher level text objects
+.PP
+In working with a document it is often advantageous to work in terms
+of sentences, paragraphs, and sections. The operations \fB(\fR and \fB)\fR
+move to the beginning of the previous and next sentences respectively.
+Thus the command \fBd)\fR will delete the rest of the current sentence;
+likewise \fBd(\fR will delete the previous sentence if you are at the
+beginning of the current sentence, or the current sentence up to where
+you are if you are not at the beginning of the current sentence.
+.PP
+A sentence is defined to end at a `.', `!' or `?' which is followed by
+either the end of a line, or by two spaces. Any number of closing `)',
+`]', `"' and `\(aa' characters may appear after the `.', `!' or `?' before
+the spaces or end of line.
+.PP
+The operations \fB{\fR and \fB}\fR move over paragraphs and the operations
+\fB[[\fR and \fB]]\fR move over sections.\*(dg
+.FS
+\*(dg The \fB[[\fR and \fB]]\fR operations
+require the operation character to be doubled because they can move the
+cursor far from where it currently is. While it is easy to get back
+with the command \fB\(ga\(ga\fP,
+these commands would still be frustrating
+if they were easy to hit accidentally.
+.FE
+.PP
+A paragraph begins after each empty line, and also
+at each of a set of paragraph macros, specified by the pairs of characters
+in the definition of the string valued option \fIparagraphs\fR.
+The default setting for this option defines the paragraph macros of the
+\fI\-ms\fR and \fI\-mm\fR macro packages, i.e. the `.IP', `.LP', `.PP'
+and `.QP', `.P' and `.LI' macros.\*(dd
+.FS
+\*(dd You can easily change or extend this set of macros by assigning a
+different string to the \fIparagraphs\fR option in your EXINIT.
+See section 6.2 for details.
+The `.bp' directive is also considered to start a paragraph.
+.FE
+Each paragraph boundary is also a sentence boundary. The sentence
+and paragraph commands can
+be given counts to operate over groups of sentences and paragraphs.
+.PP
+Sections in the editor begin after each macro in the \fIsections\fR option,
+normally `.NH', `.SH', `.H' and `.HU', and each line with a formfeed \fB^L\fR
+in the first column.
+Section boundaries are always line and paragraph boundaries also.
+.PP
+Try experimenting with the sentence and paragraph commands until you are
+sure how they work. If you have a large document, try looking through
+it using the section commands.
+The section commands interpret a preceding count as a different window size in
+which to redraw the screen at the new location, and this window size
+is the base size for newly drawn windows until another size is specified.
+This is very useful
+if you are on a slow terminal and are looking for a particular section.
+You can give the first section command a small count to then see each successive
+section heading in a small window.
+.NH 2
+Rearranging and duplicating text
+.PP
+The editor has a single unnamed buffer where the last deleted or
+changed away text is saved, and a set of named buffers \fBa\fR\-\fBz\fR
+which you can use to save copies of text and to move text around in
+your file and between files.
+.PP
+The operator
+.B y
+yanks a copy of the object which follows into the unnamed buffer.
+If preceded by a buffer name, \fB"\fR\fIx\fR\|\fBy\fR, where
+\fIx\fR here is replaced by a letter \fBa\-z\fR, it places the text in the named
+buffer. The text can then be put back in the file with the commands
+.B p
+and
+.B P;
+\fBp\fR puts the text after or below the cursor, while \fBP\fR puts the text
+before or above the cursor.
+.PP
+If the text which you
+yank forms a part of a line, or is an object such as a sentence which
+partially spans more than one line, then when you put the text back,
+it will be placed after the cursor (or before if you
+use \fBP\fR). If the yanked text forms whole lines, they will be put
+back as whole lines, without changing the current line. In this case,
+the put acts much like a \fBo\fR or \fBO\fR command.
+.PP
+Try the command \fBYP\fR. This makes a copy of the current line and
+leaves you on this copy, which is placed before the current line.
+The command \fBY\fR is a convenient abbreviation for \fByy\fR.
+The command \fBYp\fR will also make a copy of the current line, and place
+it after the current line. You can give \fBY\fR a count of lines to
+yank, and thus duplicate several lines; try \fB3YP\fR.
+.PP
+To move text within the buffer, you need to delete it in one place, and
+put it back in another. You can precede a delete operation by the
+name of a buffer in which the text is to be stored as in \fB"a5dd\fR
+deleting 5 lines into the named buffer \fIa\fR. You can then move the
+cursor to the eventual resting place of the these lines and do a \fB"ap\fR
+or \fB"aP\fR to put them back.
+In fact, you can switch and edit another file before you put the lines
+back, by giving a command of the form \fB:e \fR\fIname\fR\s-2CR\s0 where
+\fIname\fR is the name of the other file you want to edit. You will
+have to write back the contents of the current editor buffer (or discard
+them) if you have made changes before the editor will let you switch
+to the other file.
+An ordinary delete command saves the text in the unnamed buffer,
+so that an ordinary put can move it elsewhere.
+However, the unnamed buffer is lost when you change files,
+so to move text from one file to another you should use an unnamed buffer.
+.NH 2
+Summary.
+.IP
+.TS
+lw(.50i)b a.
+\(ua first non-white on line
+$ end of line
+) forward sentence
+} forward paragraph
+]] forward section
+( backward sentence
+{ backward paragraph
+[[ backward section
+f\fIx\fR find \fIx\fR forward in line
+p put text back, after cursor or below current line
+y yank operator, for copies and moves
+t\fIx\fR up to \fIx\fR forward, for operators
+F\fIx\fR f backward in line
+P put text back, before cursor or above current line
+T\fIx\fR t backward in line
+.TE
+.NH 1
+High level commands
+.NH 2
+Writing, quitting, editing new files
+.PP
+So far we have seen how to enter
+.I vi
+and to write out our file using either
+\fBZZ\fR or \fB:w\fR\s-2CR\s0. The first exits from
+the editor,
+(writing if changes were made),
+the second writes and stays in the editor.
+.PP
+If you have changed the editor's copy of the file but do not wish to
+save your changes, either because you messed up the file or decided that the
+changes are not an improvement to the file, then you can give the command
+\fB:q!\fR\s-2CR\s0 to quit from the editor without writing the changes.
+You can also reedit the same file (starting over) by giving the command
+\fB:e!\fR\s-2CR\s0. These commands should be used only rarely, and with
+caution, as it is not possible to recover the changes you have made after
+you discard them in this manner.
+.PP
+You can edit a different file without leaving the editor by giving the
+command \fB:e\fR\ \fIname\fR\s-2CR\s0. If you have not written out
+your file before you try to do this, then the editor will tell you this,
+and delay editing the other file. You can then give the command
+\fB:w\fR\s-2CR\s0 to save your work and then the \fB:e\fR\ \fIname\fR\s-2CR\s0
+command again, or carefully give the command \fB:e!\fR\ \fIname\fR\s-2CR\s0,
+which edits the other file discarding the changes you have made to the
+current file.
+To have the editor automatically save changes,
+include
+.I "set autowrite"
+in your EXINIT,
+and use \fB:n\fP instead of \fB:e\fP.
+.NH 2
+Escaping to a shell
+.PP
+You can get to a shell to execute a single command by giving a
+.I vi
+command of the form \fB:!\fIcmd\fR\s-2CR\s0.
+The system will run the single command
+.I cmd
+and when the command finishes, the editor will ask you to hit a \s-2RETURN\s0
+to continue. When you have finished looking at the output on the screen,
+you should hit \s-2RETURN\s0 and the editor will clear the screen and
+redraw it. You can then continue editing.
+You can also give another \fB:\fR command when it asks you for a \s-2RETURN\s0;
+in this case the screen will not be redrawn.
+.PP
+If you wish to execute more than one command in the shell, then you can
+give the command \fB:sh\fR\s-2CR\s0.
+This will give you a new shell, and when you finish with the shell, ending
+it by typing a \fB^D\fR, the editor will clear the screen and continue.
+.PP
+On systems which support it, \fB^Z\fP will suspend the editor
+and return to the (top level) shell.
+When the editor is resumed, the screen will be redrawn.
+.NH 2
+Marking and returning
+.PP
+The command \fB\(ga\(ga\fR returned to the previous place
+after a motion of the cursor by a command such as \fB/\fR, \fB?\fR or
+\fBG\fR. You can also mark lines in the file with single letter tags
+and return to these marks later by naming the tags. Try marking the
+current line with the command \fBm\fR\fIx\fR, where you should pick some
+letter for \fIx\fR, say `a'. Then move the cursor to a different line
+(any way you like) and hit \fB\(gaa\fR. The cursor will return to the
+place which you marked.
+Marks last only until you edit another file.
+.PP
+When using operators such as
+.B d
+and referring to marked lines, it is often desirable to delete whole lines
+rather than deleting to the exact position in the line marked by \fBm\fR.
+In this case you can use the form \fB\(aa\fR\fIx\fR rather than
+\fB\(ga\fR\fIx\fR. Used without an operator, \fB\(aa\fR\fIx\fR will move to
+the first non-white character of the marked line; similarly \fB\(aa\(aa\fR
+moves to the first non-white character of the line containing the previous
+context mark \fB\(ga\(ga\fR.
+.NH 2
+Adjusting the screen
+.PP
+If the screen image is messed up because of a transmission error to your
+terminal, or because some program other than the editor wrote output
+to your terminal, you can hit a \fB^L\fR, the \s-2ASCII\s0 form-feed
+character, to cause the screen to be refreshed.
+.PP
+On a dumb terminal, if there are @ lines in the middle of the screen
+as a result of line deletion, you may get rid of these lines by typing
+\fB^R\fR to cause the editor to retype the screen, closing up these holes.
+.PP
+Finally, if you wish to place a certain line on the screen at the top
+middle or bottom of the screen, you can position the cursor to that line,
+and then give a \fBz\fR command.
+You should follow the \fBz\fR command with a \s-2RETURN\s0 if you want
+the line to appear at the top of the window, a \fB.\fR if you want it
+at the center, or a \fB\-\fR if you want it at the bottom.
+.NH 1
+Special topics
+.NH 2
+Editing on slow terminals
+.PP
+When you are on a slow terminal, it is important to limit the amount
+of output which is generated to your screen so that you will not suffer
+long delays, waiting for the screen to be refreshed. We have already
+pointed out how the editor optimizes the updating of the screen during
+insertions on dumb terminals to limit the delays, and how the editor erases
+lines to @ when they are deleted on dumb terminals.
+.PP
+The use of the slow terminal insertion mode is controlled by the
+.I slowopen
+option. You can force the editor to use this mode even on faster terminals
+by giving the command \fB:se slow\fR\s-2CR\s0. If your system is sluggish
+this helps lessen the amount of output coming to your terminal.
+You can disable this option by \fB:se noslow\fR\s-2CR\s0.
+.PP
+The editor can simulate an intelligent terminal on a dumb one. Try
+giving the command \fB:se redraw\fR\s-2CR\s0. This simulation generates
+a great deal of output and is generally tolerable only on lightly loaded
+systems and fast terminals. You can disable this by giving the command
+ \fB:se noredraw\fR\s-2CR\s0.
+.PP
+The editor also makes editing more pleasant at low speed by starting
+editing in a small window, and letting the window expand as you edit.
+This works particularly well on intelligent terminals. The editor can
+expand the window easily when you insert in the middle of the screen
+on these terminals. If possible, try the editor on an intelligent terminal
+to see how this works.
+.PP
+You can control the size of the window which is redrawn each time the
+screen is cleared by giving window sizes as argument to the commands
+which cause large screen motions:
+.DS
+.B ": / ? [[ ]] \(ga \(aa"
+.DE
+Thus if you are searching for a particular instance of a common string
+in a file you can precede the first search command by a small number,
+say 3, and the editor will draw three line windows around each instance
+of the string which it locates.
+.PP
+You can easily expand or contract the window, placing the current line
+as you choose, by giving a number on a \fBz\fR command, after the \fBz\fR
+and before the following \s-2RETURN\s0, \fB.\fR or \fB\-\fR. Thus the
+command \fBz5.\fR redraws the screen with the current line in the center
+of a five line window.\*(dg
+.FS
+\*(dg Note that the command \fB5z.\fR has an entirely different effect,
+placing line 5 in the center of a new window.
+.FE
+.PP
+If the editor is redrawing or otherwise updating large portions of the
+display, you can interrupt this updating by hitting a \s-2DEL\s0 or \s-2RUB\s0
+as usual. If you do this you may partially confuse the editor about
+what is displayed on the screen. You can still edit the text on
+the screen if you wish; clear up the confusion
+by hitting a \fB^L\fR; or move or search again, ignoring the
+current state of the display.
+.PP
+See section 7.8 on \fIopen\fR mode for another way to use the
+.I vi
+command set on slow terminals.
+.NH 2
+Options, set, and editor startup files
+.PP
+The editor has a set of options, some of which have been mentioned above.
+The most useful options are given in the following table.
+.KF
+.TS
+lb lb lb lb
+l l l a.
+Name Default Description
+_
+autoindent noai Supply indentation automatically
+autowrite noaw Automatic write before \fB:n\fR, \fB:ta\fR, \fB^\(ua\fR, \fB!\fR
+ignorecase noic Ignore case in searching
+lisp nolisp \fB( { ) }\fR commands deal with S-expressions
+list nolist Tabs print as ^I; end of lines marked with $
+magic nomagic The characters . [ and * are special in scans
+number nonu Lines are displayed prefixed with line numbers
+paragraphs para=IPLPPPQPbpP LI Macro names which start paragraphs
+redraw nore Simulate a smart terminal on a dumb one
+sections sect=NHSHH HU Macro names which start new sections
+shiftwidth sw=8 Shift distance for <, > and input \fB^D\fP and \fB^T\fR
+showmatch nosm Show matching \fB(\fP or \fB{\fP as \fB)\fP or \fB}\fR is typed
+slowopen slow Postpone display updates during inserts
+term dumb The kind of terminal you are using.
+.TE
+.KE
+.PP
+The options are of three kinds: numeric options, string options, and
+toggle options. You can set numeric and string options by a statement
+of the form
+.DS
+\fBset\fR \fIopt\fR\fB=\fR\fIval\fR
+.DE
+and toggle options can be set or unset by statements of one of the forms
+.DS
+\fBset\fR \fIopt\fR
+\fBset\fR \fBno\fR\fIopt\fR
+.DE
+These statements can be placed in your EXINIT in your environment,
+or given while you are running
+.I vi
+by preceding them with a \fB:\fR and following them with a \s-2CR\s0.
+.PP
+You can get a list of all options which you have changed by the
+command \fB:set\fR\s-2CR\s0, or the value of a single option by the
+command \fB:set\fR \fIopt\fR\fB?\fR\s-2CR\s0.
+A list of all possible options and their values is generated by
+\fB:set all\fP\s-2CR\s0.
+Set can be abbreviated \fBse\fP.
+Multiple options can be placed on one line, e.g.
+\fB:se ai aw nu\fP\s-2CR\s0.
+.PP
+Options set by the \fBset\fP command only last
+while you stay in the editor.
+It is common to want to have certain options set whenever you
+use the editor.
+This can be accomplished by creating a list of \fIex\fP commands\*(dg
+.FS
+\*(dg
+All commands which start with
+.B :
+are \fIex\fP commands.
+.FE
+which are to be run every time you start up \fIex\fP, \fIedit\fP,
+or \fIvi\fP.
+A typical list includes a \fBset\fP command, and possibly a few
+\fBmap\fP commands.
+Since it is advisable to get these commands on one line, they can
+be separated with the | character, for example:
+.DS
+\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x
+.DE
+which sets the options \fIautoindent\fP, \fIautowrite\fP, \fIterse\fP,
+(the
+.B set
+command),
+makes @ delete a line,
+(the first
+.B map ),
+and makes # delete a character,
+(the second
+.B map ).
+(See section 6.9 for a description of the \fBmap\fP command)
+This string should be placed in the variable EXINIT in your environment.
+If you use the shell \fIcsh\fP,
+put this line in the file
+.I .login
+in your home directory:
+.DS
+setenv EXINIT \(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa
+.DE
+If you use the standard shell \fIsh\fP,
+put these lines in the file
+.I .profile
+in your home directory:
+.DS
+EXINIT=\(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa
+export EXINIT
+.DE
+Of course, the particulars of the line would depend on which options
+you wanted to set.
+.NH 2
+Recovering lost lines
+.PP
+You might have a serious problem if you delete a number of lines and then
+regret that they were deleted. Despair not, the editor saves the last
+9 deleted blocks of text in a set of numbered registers 1\-9.
+You can get the \fIn\fR'th previous deleted text back in your file by
+the command
+"\fR\fIn\fR\|\fBp\fR.
+The "\fR here says that a buffer name is to follow,
+\fIn\fR is the number of the buffer you wish to try
+(use the number 1 for now),
+and
+.B p
+is the put command, which puts text in the buffer after the cursor.
+If this doesn't bring back the text you wanted, hit
+.B u
+to undo this and then
+\fB\&.\fR
+(period)
+to repeat the put command.
+In general the
+\fB\&.\fR
+command will repeat the last change you made.
+As a special case, when the last command refers to a numbered text buffer,
+the \fB.\fR command increments the number of the buffer before repeating
+the command. Thus a sequence of the form
+.DS
+\fB"1pu.u.u.\fR
+.DE
+will, if repeated long enough, show you all the deleted text which has
+been saved for you.
+You can omit the
+.B u
+commands here to gather up all this text in the buffer, or stop after any
+\fB\&.\fR command to keep just the then recovered text.
+The command
+.B P
+can also be used rather than
+.B p
+to put the recovered text before rather than after the cursor.
+.NH 2
+Recovering lost files
+.PP
+If the system crashes, you can recover the work you were doing
+to within a few changes. You will normally receive mail when you next
+login giving you the name of the file which has been saved for you.
+You should then change to the directory where you were when the system
+crashed and give a command of the form:
+.DS
+% \fBvi \-r\fR \fIname\fR
+.DE
+replacing \fIname\fR with the name of the file which you were editing.
+This will recover your work to a point near where you left off.\*(dg
+.FS
+\*(dg In rare cases, some of the lines of the file may be lost. The
+editor will give you the numbers of these lines and the text of the lines
+will be replaced by the string `LOST'. These lines will almost always
+be among the last few which you changed. You can either choose to discard
+the changes which you made (if they are easy to remake) or to replace
+the few lost lines by hand.
+.FE
+.PP
+You can get a listing of the files which are saved for you by giving
+the command:
+.DS
+% \fBvi \-r\fR
+.DE
+If there is more than one instance of a particular file saved, the editor
+gives you the newest instance each time you recover it. You can thus
+get an older saved copy back by first recovering the newer copies.
+.PP
+For this feature to work,
+.I vi
+must be correctly installed by a super user on your system,
+and the
+.I mail
+program must exist to receive mail.
+The invocation ``\fIvi -r\fP'' will not always list all saved files,
+but they can be recovered even if they are not listed.
+.NH 2
+Continuous text input
+.PP
+When you are typing in large amounts of text it is convenient to have
+lines broken near the right margin automatically. You can cause this
+to happen by giving the command
+\fB:se wm=10\fR\s-2CR\s0.
+This causes all lines to be broken at a space at least 10 columns
+from the right hand edge of the screen.
+.PP
+If the editor breaks an input line and you wish to put it back together
+you can tell it to join the lines with \fBJ\fR. You can give \fBJ\fR
+a count of the number of lines to be joined as in \fB3J\fR to join 3
+lines. The editor supplies white space, if appropriate,
+at the juncture of the joined
+lines, and leaves the cursor at this white space.
+You can kill the white space with \fBx\fR if you don't want it.
+.NH 2
+Features for editing programs
+.PP
+The editor has a number of commands for editing programs.
+The thing that most distinguishes editing of programs from editing of text
+is the desirability of maintaining an indented structure to the body of
+the program. The editor has a
+.I autoindent
+facility for helping you generate correctly indented programs.
+.PP
+To enable this facility you can give the command \fB:se ai\fR\s-2CR\s0.
+Now try opening a new line with \fBo\fR and type some characters on the
+line after a few tabs. If you now start another line, notice that the
+editor supplies white space at the beginning of the line to line it up
+with the previous line. You cannot backspace over this indentation,
+but you can use \fB^D\fR key to backtab over the supplied indentation.
+.PP
+Each time you type \fB^D\fR you back up one position, normally to an
+8 column boundary. This amount is settable; the editor has an option
+called
+.I shiftwidth
+which you can set to change this value.
+Try giving the command \fB:se sw=4\fR\s-2CR\s0
+and then experimenting with autoindent again.
+.PP
+For shifting lines in the program left and right, there are operators
+.B <
+and
+.B >.
+These shift the lines you specify right or left by one
+.I shiftwidth.
+Try
+.B <<
+and
+.B >>
+which shift one line left or right, and
+.B <L
+and
+.B >L
+shifting the rest of the display left and right.
+.PP
+If you have a complicated expression and wish to see how the parentheses
+match, put the cursor at a left or right parenthesis and hit \fB%\fR.
+This will show you the matching parenthesis.
+This works also for braces { and }, and brackets [ and ].
+.PP
+If you are editing C programs, you can use the \fB[[\fR and \fB]]\fR keys
+to advance or retreat to a line starting with a \fB{\fR, i.e. a function
+declaration at a time. When \fB]]\fR is used with an operator it stops
+after a line which starts with \fB}\fR; this is sometimes useful with
+\fBy]]\fR.
+.NH 2
+Filtering portions of the buffer
+.PP
+You can run system commands over portions of the buffer using the operator
+\fB!\fR.
+You can use this to sort lines in the buffer, or to reformat portions
+of the buffer with a pretty-printer.
+Try typing in a list of random words, one per line and ending them
+with a blank line. Back up to the beginning of the list, and then give
+the command \fB!}sort\fR\s-2CR\s0. This says to sort the next paragraph
+of material, and the blank line ends a paragraph.
+.NH 2
+Commands for editing \s-2LISP\s0
+.PP
+If you are editing a \s-2LISP\s0 program you should set the option
+.I lisp
+by doing
+\fB:se\ lisp\fR\s-2CR\s0.
+This changes the \fB(\fR and \fB)\fR commands to move backward and forward
+over s-expressions.
+The \fB{\fR and \fB}\fR commands are like \fB(\fR and \fB)\fR but don't
+stop at atoms. These can be used to skip to the next list, or through
+a comment quickly.
+.PP
+The
+.I autoindent
+option works differently for \s-2LISP\s0, supplying indent to align at
+the first argument to the last open list. If there is no such argument
+then the indent is two spaces more than the last level.
+.PP
+There is another option which is useful for typing in \s-2LISP\s0, the
+.I showmatch
+option.
+Try setting it with
+\fB:se sm\fR\s-2CR\s0
+and then try typing a `(' some words and then a `)'. Notice that the
+cursor shows the position of the `(' which matches the `)' briefly.
+This happens only if the matching `(' is on the screen, and the cursor
+stays there for at most one second.
+.PP
+The editor also has an operator to realign existing lines as though they
+had been typed in with
+.I lisp
+and
+.I autoindent
+set. This is the \fB=\fR operator.
+Try the command \fB=%\fR at the beginning of a function. This will realign
+all the lines of the function declaration.
+.PP
+When you are editing \s-2LISP\s0,, the \fB[[\fR and \fR]]\fR advance
+and retreat to lines beginning with a \fB(\fR, and are useful for dealing
+with entire function definitions.
+.NH 2
+Macros
+.PP
+.I Vi
+has a parameterless macro facility, which lets you set it up so that
+when you hit a single keystroke, the editor will act as though
+you had hit some longer sequence of keys. You can set this up if
+you find yourself typing the same sequence of commands repeatedly.
+.PP
+Briefly, there are two flavors of macros:
+.IP a)
+Ones where you put the macro body in a buffer register, say \fIx\fR.
+You can then type \fB@x\fR to invoke the macro. The \fB@\fR may be followed
+by another \fB@\fR to repeat the last macro.
+.IP b)
+You can use the
+.I map
+command from
+.I vi
+(typically in your
+.I EXINIT )
+with a command of the form:
+.DS
+:map \fIlhs\fR \fIrhs\fR\s-2CR\f0
+.DE
+mapping
+.I lhs
+into
+.I rhs.
+There are restrictions:
+.I lhs
+should be one keystroke (either 1 character or one function key)
+since it must be entered within one second
+(unless
+.I notimeout
+is set, in which case you can type it as slowly as you wish,
+and
+.I vi
+will wait for you to finish it before it echoes anything).
+The
+.I lhs
+can be no longer than 10 characters, the
+.I rhs
+no longer than 100.
+To get a space, tab or newline into
+.I lhs
+or
+.I rhs
+you should escape them with a \fB^V\fR.
+(It may be necessary to double the \fB^V\fR if the map
+command is given inside
+.I vi,
+rather than in
+.I ex.)
+Spaces and tabs inside the
+.I rhs
+need not be escaped.
+.PP
+Thus to make the \fBq\fR key write and exit the editor, you can give
+the command
+.DS
+:map q :wq\fB^V^V\fP\s-2CR CR\s0
+.DE
+which means that whenever you type \fBq\fR, it will be as though you
+had typed the four characters \fB:wq\fR\s-2CR\s0.
+A \fB^V\fR's is needed because without it the \s-2CR\s0 would end the
+\fB:\fR command, rather than becoming part of the
+.I map
+definition.
+There are two
+.B ^V 's
+because from within
+.I vi ,
+two
+.B ^V 's
+must be typed to get one.
+The first \s-2CR\s0 is part of the
+.I rhs ,
+the second terminates the : command.
+.PP
+Macros can be deleted with
+.DS
+unmap lhs
+.DE
+.PP
+If the
+.I lhs
+of a macro is ``#0'' through ``#9'', this maps the particular function key
+instead of the 2 character ``#'' sequence. So that terminals without
+function keys can access such definitions, the form ``#x'' will mean function
+key
+.I x
+on all terminals (and need not be typed within one second.)
+The character ``#'' can be changed by using a macro in the usual way:
+.DS
+:map \fB^V^V^I\fP #
+.DE
+to use tab, for example. (This won't affect the
+.I map
+command, which still uses
+.B #,
+but just the invocation from visual mode.
+.PP
+The undo command reverses an entire macro call as a unit,
+if it made any changes.
+.PP
+Placing a `!' after the word
+.B map
+causes the mapping to apply
+to input mode, rather than command mode.
+Thus, to arrange for \fB^T\fP to be the same as 4 spaces in input mode,
+you can type:
+.DS
+:map \fB^T\fP \fB^V\fP\o'b/'\o'b/'\o'b/'\o'b/'
+.DE
+where
+.B \o'b/'
+is a blank.
+The \fB^V\fP is necessary to prevent the blanks from being taken as
+white space between the
+.I lhs
+and
+.I rhs .
+.NH
+Word Abbreviations
+.PP
+A feature similar to macros in input mode is word abbreviation.
+This allows you to type a short word and have it expanded into
+a longer word or words.
+The commands are
+.B :abbreviate
+and
+.B :unabbreviate
+(\fB:ab\fP
+and
+.B :una )
+and have the same syntax as
+.B :map .
+For example:
+.DS
+:ab eecs Electrical Engineering and Computer Sciences
+.DE
+causes the word `eecs' to always be changed into the
+phrase `Electrical Engineering and Computer Sciences'.
+Word abbreviation is different from macros in that
+only whole words are affected.
+If `eecs' were typed as part of a larger word, it would
+be left alone.
+Also, the partial word is echoed as it is typed.
+There is no need for an abbreviation to be a single keystroke,
+as it should be with a macro.
+.NH 2
+Abbreviations
+.PP
+The editor has a number of short
+commands which abbreviate longer commands which we
+have introduced here. You can find these commands easily
+on the quick reference card.
+They often save a bit of typing and you can learn them as convenient.
+.NH 1
+Nitty-gritty details
+.NH 2
+Line representation in the display
+.PP
+The editor folds long logical lines onto many physical lines in the display.
+Commands which advance lines advance logical lines and will skip
+over all the segments of a line in one motion. The command \fB|\fR moves
+the cursor to a specific column, and may be useful for getting near the
+middle of a long line to split it in half. Try \fB80|\fR on a line which
+is more than 80 columns long.\*(dg
+.FS
+\*(dg You can make long lines very easily by using \fBJ\fR to join together
+short lines.
+.FE
+.PP
+The editor only puts full lines on the display; if there is not enough
+room on the display to fit a logical line, the editor leaves the physical
+line empty, placing only an @ on the line as a place holder. When you
+delete lines on a dumb terminal, the editor will often just clear the
+lines to @ to save time (rather than rewriting the rest of the screen.)
+You can always maximize the information on the screen by giving the \fB^R\fR
+command.
+.PP
+If you wish, you can have the editor place line numbers before each line
+on the display. Give the command \fB:se nu\fR\s-2CR\s0 to enable
+this, and the command \fB:se nonu\fR\s-2CR\s0 to turn it off.
+You can have tabs represented as \fB^I\fR and the ends of lines indicated
+with `$' by giving the command \fB:se list\fR\s-2CR\s0;
+\fB:se nolist\fR\s-2CR\s0 turns this off.
+.PP
+Finally, lines consisting of only the character `~' are displayed when
+the last line in the file is in the middle of the screen. These represent
+physical lines which are past the logical end of file.
+.NH 2
+Counts
+.PP
+Most
+.I vi
+commands will use a preceding count to affect their behavior in some way.
+The following table gives the common ways in which the counts are used:
+.DS
+.TS
+l lb.
+new window size : / ? [[ ]] \` \'
+scroll amount ^D ^U
+line/column number z G |
+repeat effect \fRmost of the rest\fP
+.TE
+.DE
+.PP
+The editor maintains a notion of the current default window size.
+On terminals which run at speeds greater than 1200 baud
+the editor uses the full terminal screen.
+On terminals which are slower than 1200 baud
+(most dialup lines are in this group)
+the editor uses 8 lines as the default window size.
+At 1200 baud the default is 16 lines.
+.PP
+This size is the size used when the editor clears and refills the screen
+after a search or other motion moves far from the edge of the current window.
+The commands which take a new window size as count all often cause the
+screen to be redrawn. If you anticipate this, but do not need as large
+a window as you are currently using, you may wish to change the screen
+size by specifying the new size before these commands.
+In any case, the number of lines used on the screen will expand if you
+move off the top with a \fB\-\fR or similar command or off the bottom
+with a command such as \s-2RETURN\s0 or \fB^D\fR.
+The window will revert to the last specified size the next time it is
+cleared and refilled.\*(dg
+.FS
+\*(dg But not by a \fB^L\fR which just redraws the screen as it is.
+.FE
+.PP
+The scroll commands \fB^D\fR and \fB^U\fR likewise remember the amount
+of scroll last specified, using half the basic window size initially.
+The simple insert commands use a count to specify a repetition of the
+inserted text. Thus \fB10a+\-\-\-\-\fR\s-2ESC\s0 will insert a grid-like
+string of text.
+A few commands also use a preceding count as a line or column number.
+.PP
+Except for a few commands which ignore any counts (such as \fB^R\fR),
+the rest of the editor commands use a count to indicate a simple repetition
+of their effect. Thus \fB5w\fR advances five words on the current line,
+while \fB5\fR\s-2RETURN\s0 advances five lines. A very useful instance
+of a count as a repetition is a count given to the \fB.\fR command, which
+repeats the last changing command. If you do \fBdw\fR and then \fB3.\fR,
+you will delete first one and then three words. You can then delete
+two more words with \fB2.\fR.
+.NH 2
+More file manipulation commands
+.PP
+The following table lists the file manipulation commands which you can
+use when you are in
+.I vi.
+.KF
+.DS
+.TS
+lb l.
+:w write back changes
+:wq write and quit
+:x write (if necessary) and quit (same as ZZ).
+:e \fIname\fP edit file \fIname\fR
+:e! reedit, discarding changes
+:e + \fIname\fP edit, starting at end
+:e +\fIn\fP edit, starting at line \fIn\fP
+:e # edit alternate file
+:w \fIname\fP write file \fIname\fP
+:w! \fIname\fP overwrite file \fIname\fP
+:\fIx,y\fPw \fIname\fP write lines \fIx\fP through \fIy\fP to \fIname\fP
+:r \fIname\fP read file \fIname\fP into buffer
+:r !\fIcmd\fP read output of \fIcmd\fP into buffer
+:n edit next file in argument list
+:n! edit next file, discarding changes to current
+:n \fIargs\fP specify new argument list
+:ta \fItag\fP edit file containing tag \fItag\fP, at \fItag\fP
+.TE
+.DE
+.KE
+All of these commands are followed by a \s-2CR\s0 or \s-2ESC\s0.
+The most basic commands are \fB:w\fR and \fB:e\fR.
+A normal editing session on a single file will end with a \fBZZ\fR command.
+If you are editing for a long period of time you can give \fB:w\fR commands
+occasionally after major amounts of editing, and then finish
+with a \fBZZ\fR. When you edit more than one file, you can finish
+with one with a \fB:w\fR and start editing a new file by giving a \fB:e\fR
+command,
+or set
+.I autowrite
+and use \fB:n\fP <file>.
+.PP
+If you make changes to the editor's copy of a file, but do not wish to
+write them back, then you must give an \fB!\fR after the command you
+would otherwise use; this forces the editor to discard any changes
+you have made. Use this carefully.
+.PP
+The \fB:e\fR command can be given a \fB+\fR argument to start at the
+end of the file, or a \fB+\fR\fIn\fR argument to start at line \fIn\fR\^.
+In actuality, \fIn\fR may be any editor command not containing a space,
+usefully a scan like \fB+/\fIpat\fR or \fB+?\fIpat\fR.
+In forming new names to the \fBe\fR command, you can use the character
+\fB%\fR which is replaced by the current file name, or the character
+\fB#\fR which is replaced by the alternate file name.
+The alternate file name is generally the last name you typed other than
+the current file. Thus if you try to do a \fB:e\fR and get a diagnostic
+that you haven't written the file, you can give a \fB:w\fR command and
+then a \fB:e #\fR command to redo the previous \fB:e\fR.
+.PP
+You can write part of the buffer to a file by finding out the lines
+that bound the range to be written using \fB^G\fR, and giving these
+numbers after the \fB:\fR
+and before the \fBw\fP, separated by \fB,\fR's.
+You can also mark these lines with \fBm\fR and
+then use an address of the form \fB\(aa\fR\fIx\fR\fB,\fB\(aa\fR\fIy\fR
+on the \fBw\fR command here.
+.PP
+You can read another file into the buffer after the current line by using
+the \fB:r\fR command.
+You can similarly read in the output from a command, just use \fB!\fR\fIcmd\fR
+instead of a file name.
+.PP
+If you wish to edit a set of files in succession, you can give all the
+names on the command line, and then edit each one in turn using the command
+\fB:n\fR. It is also possible to respecify the list of files to be edited
+by giving the \fB:n\fR command a list of file names, or a pattern to
+be expanded as you would have given it on the initial
+.I vi
+command.
+.PP
+If you are editing large programs, you will find the \fB:ta\fR command
+very useful. It utilizes a data base of function names and their locations,
+which can be created by programs such as
+.I ctags,
+to quickly find a function whose name you give.
+If the \fB:ta\fR command will require the editor to switch files, then
+you must \fB:w\fR or abandon any changes before switching. You can repeat
+the \fB:ta\fR command without any arguments to look for the same tag
+again.
+.NH 2
+More about searching for strings
+.PP
+When you are searching for strings in the file with \fB/\fR and \fB?\fR,
+the editor normally places you at the next or previous occurrence
+of the string. If you are using an operator such as \fBd\fR,
+\fBc\fR or \fBy\fR, then you may well wish to affect lines up to the
+line before the line containing the pattern. You can give a search of
+the form \fB/\fR\fIpat\fR\fB/\-\fR\fIn\fR to refer to the \fIn\fR'th line
+before the next line containing \fIpat\fR, or you can use \fB\+\fR instead
+of \fB\-\fR to refer to the lines after the one containing \fIpat\fR.
+If you don't give a line offset, then the editor will affect characters
+up to the match place, rather than whole lines; thus use ``+0'' to affect
+to the line which matches.
+.PP
+You can have the editor ignore the case of words in the searches it does
+by giving the command \fB:se ic\fR\s-2CR\s0.
+The command \fB:se noic\fR\s-2CR\s0 turns this off.
+.PP
+Strings given to searches may actually be regular expressions.
+If you do not want or need this facility, you should
+.DS
+set nomagic
+.DE
+in your EXINIT.
+In this case,
+only the characters \fB\(ua\fR and \fB$\fR are special in patterns.
+The character \fB\e\fR is also then special (as it is most everywhere in
+the system), and may be used to get at the
+an extended pattern matching facility.
+It is also necessary to use a \e before a
+\fB/\fR in a forward scan or a \fB?\fR in a backward scan, in any case.
+The following table gives the extended forms when \fBmagic\fR is set.
+.DS
+.TS
+bl l.
+\(ua at beginning of pattern, matches beginning of line
+$ at end of pattern, matches end of line
+\fB\&.\fR matches any character
+\e< matches the beginning of a word
+\e> matches the end of a word
+[\fIstr\fP] matches any single character in \fIstr\fP
+[\(ua\fIstr\fP] matches any single character not in \fIstr\fP
+[\fIx\fP\-\fIy\fP] matches any character between \fIx\fP and \fIy\fP
+* matches any number of the preceding pattern
+.TE
+.DE
+If you use \fBnomagic\fR mode, then
+the \fB. [\fR and \fB*\fR primitives are given with a preceding
+\e.
+.NH 2
+More about input mode
+.PP
+There are a number of characters which you can use to make corrections
+during input mode. These are summarized in the following table.
+.DS
+.TS
+lb l.
+^H deletes the last input character
+^W deletes the last input word, defined as by \fBb\fR
+erase your erase character, same as \fB^H\fP
+kill your kill character, deletes the input on this line
+\e escapes a following \fB^H\fP and your erase and kill
+\s-2ESC\s0 ends an insertion
+\s-2DEL\s0 interrupts an insertion, terminating it abnormally
+\s-2CR\s0 starts a new line
+^D backtabs over \fIautoindent\fP
+0^D kills all the \fIautoindent\fP
+\(ua^D same as \fB0^D\fP, but restores indent next line
+^V quotes the next non-printing character into the file
+.TE
+.DE
+.PP
+The most usual way of making corrections to input is by typing \fB^H\fR
+to correct a single character, or by typing one or more \fB^W\fR's to
+back over incorrect words. If you use \fB#\fR as your erase character
+in the normal system, it will work like \fB^H\fR.
+.PP
+Your system kill character, normally \fB@\fR, \fB^X\fP or \fB^U\fR,
+will erase all
+the input you have given on the current line.
+In general, you can neither
+erase input back around a line boundary nor can you erase characters
+which you did not insert with this insertion command. To make corrections
+on the previous line after a new line has been started you can hit \s-2ESC\s0
+to end the insertion, move over and make the correction, and then return
+to where you were to continue. The command \fBA\fR which appends at the
+end of the current line is often useful for continuing.
+.PP
+If you wish to type in your erase or kill character (say # or @) then
+you must precede it with a \fB\e\fR, just as you would do at the normal
+system command level. A more general way of typing non-printing characters
+into the file is to precede them with a \fB^V\fR. The \fB^V\fR echoes
+as a \fB\(ua\fR character on which the cursor rests. This indicates that
+the editor expects you to type a control character. In fact you may
+type any character and it will be inserted into the file at that point.*
+.FS
+* This is not quite true. The implementation of the editor does
+not allow the \s-2NULL\s0 (\fB^@\fR) character to appear in files. Also
+the \s-2LF\s0 (linefeed or \fB^J\fR) character is used by the editor
+to separate lines in the file, so it cannot appear in the middle of a
+line. You can insert any other character, however, if you wait for the
+editor to echo the \fB\(ua\fR before you type the character. In fact,
+the editor will treat a following letter as a request for the corresponding
+control character. This is the only way to type \fB^S\fR or \fB^Q\fP,
+since the system normally uses them to suspend and resume output
+and never gives them to the editor to process.
+.FE
+.PP
+If you are using \fIautoindent\fR you can backtab over the indent which
+it supplies by typing a \fB^D\fR. This backs up to a \fIshiftwidth\fR
+boundary.
+This only works immediately after the supplied \fIautoindent\fR.
+.PP
+When you are using \fIautoindent\fR you may wish to place a label at
+the left margin of a line. The way to do this easily is to type \fB\(ua\fR
+and then \fB^D\fR. The editor will move the cursor to the left margin
+for one line, and restore the previous indent on the next. You can also
+type a \fB0\fR followed immediately by a \fB^D\fR if you wish to kill
+all the indent and not have it come back on the next line.
+.NH 2
+Upper case only terminals
+.PP
+If your terminal has only upper case, you can still use
+.I vi
+by using the normal
+system convention for typing on such a terminal.
+Characters which you normally type are converted to lower case, and you
+can type upper case letters by preceding them with a \e.
+The characters { ~ } | \(ga are not available on such terminals, but you
+can escape them as \e( \e\(ua \e) \e! \e\(aa.
+These characters are represented on the display in the same way they
+are typed.\*(dd
+.FS
+\*(dd The \e character you give will not echo until you type another
+key.
+.FE
+.NH 2
+Vi and ex
+.PP
+.I Vi
+is actually one mode of editing within the editor
+.I ex.
+When you are running
+.I vi
+you can escape to the line oriented editor of
+.I ex
+by giving the command
+\fBQ\fR.
+All of the
+.B :
+commands which were introduced above are available in
+.I ex.
+Likewise, most
+.I ex
+commands can be invoked from
+.I vi
+using :.
+Just give them without the \fB:\fR and follow them with a \s-2CR\s0.
+.PP
+In rare instances, an internal error may occur in
+.I vi.
+In this case you will get a diagnostic and be left in the command mode of
+.I ex.
+You can then save your work and quit if you wish by giving a command
+\fBx\fR after the \fB:\fR which \fIex\fR prompts you with, or you can
+reenter \fIvi\fR by giving
+.I ex
+a
+.I vi
+command.
+.PP
+There are a number of things which you can do more easily in
+.I ex
+than in
+.I vi.
+Systematic changes in line oriented material are particularly easy.
+You can read the advanced editing documents for the editor
+.I ed
+to find out a lot more about this style of editing.
+Experienced
+users often mix their use of
+.I ex
+command mode and
+.I vi
+command mode to speed the work they are doing.
+.NH 2
+Open mode: vi on hardcopy terminals and ``glass tty's''
+\(dd
+.PP
+If you are on a hardcopy terminal or a terminal which does not have a cursor
+which can move off the bottom line, you can still use the command set of
+.I vi,
+but in a different mode.
+When you give a
+.I vi
+command, the editor will tell you that it is using
+.I open
+mode.
+This name comes from the
+.I open
+command in
+.I ex,
+which is used to get into the same mode.
+.PP
+The only difference between
+.I visual
+mode
+and
+.I open
+mode is the way in which the text is displayed.
+.PP
+In
+.I open
+mode the editor uses a single line window into the file, and moving backward
+and forward in the file causes new lines to be displayed, always below the
+current line.
+Two commands of
+.I vi
+work differently in
+.I open:
+.B z
+and
+\fB^R\fR.
+The
+.B z
+command does not take parameters, but rather draws a window of context around
+the current line and then returns you to the current line.
+.PP
+If you are on a hardcopy terminal,
+the
+.B ^R
+command will retype the current line.
+On such terminals, the editor normally uses two lines to represent the
+current line.
+The first line is a copy of the line as you started to edit it, and you work
+on the line below this line.
+When you delete characters, the editor types a number of \e's to show
+you the characters which are deleted. The editor also reprints the current
+line soon after such changes so that you can see what the line looks
+like again.
+.PP
+It is sometimes useful to use this mode on very slow terminals which
+can support
+.I vi
+in the full screen mode.
+You can do this by entering
+.I ex
+and using an
+.I open
+command.
+.LP
+.SH
+Acknowledgements
+.PP
+Bruce Englar encouraged the early development of this display editor.
+Peter Kessler helped bring sanity to version 2's command layout.
+Bill Joy wrote versions 1 and 2.0 through 2.7,
+and created the framework that users see in the present editor.
+Mark Horton added macros and other features and made the
+editor work on a large number of terminals and Unix systems.
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.summary b/usr.bin/vi/docs/USD.doc/vi/vi.summary
new file mode 100644
index 000000000000..a7d99384dc86
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.summary
@@ -0,0 +1,468 @@
+.\" Copyright (c) 1980, 1993
+.\" 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.
+.\"
+.\" @(#)vi.summary 8.1 (Berkeley) 6/8/93
+.\"
+.ds CH
+.ds CF
+.de TS
+.br
+.if !\\n(1T .RT
+.ul 0
+.ti \\n(.iu
+.if t .sp 0.25
+.if n .sp
+.if \\$1H .TQ
+.nr IX 1
+..
+.nr PS 9
+.ps 9
+.nr VS 11
+.vs 11
+.nr HM .50i
+.nr FM .25i
+.nr PO 0
+.po 0
+.nr LL 3.5i
+.ll 3.5i
+.de nc
+.bp
+..
+.de h
+.LG
+.B
+\\$1
+.R
+.NL
+..
+.LG
+.LG
+.B
+.ce
+Ex Quick Reference
+.R
+.NL
+.LP
+.LP
+.h "Entering/leaving ex"
+.TS
+aw(1.4i)b aw(1.8i).
+% ex \fIname\fP edit \fIname\fP, start at end
+% ex +\fIn\fP \fIname\fP ... at line \fIn\fP
+% ex \-t \fItag\fP start at \fItag\fP
+% ex \-r list saved files
+% ex \-r \fIname\fP recover file \fIname\fP
+% ex \fIname\fP ... edit first; rest via \fB:n\fP
+% ex \-R \fIname\fP read only mode
+: x exit, saving changes
+: q! exit, discarding changes
+.TE
+.h "Ex states"
+.TS
+lw(1i) lw(2.0i).
+Command T{
+Normal and initial state. Input prompted for by \fB:\fP.
+Your kill character cancels partial command.
+T}
+Insert T{
+Entered by \fBa\fP \fBi\fP and \fBc\fP.
+Arbitrary text then terminates with line having only \fB.\fP
+character on it or abnormally with interrupt.
+T}
+Open/visual T{
+Entered by \fBopen\fP or \fBvi\fP, terminates with \fBQ\fP
+or ^\e.
+T}
+.TE
+.h "Ex commands"
+.TS
+lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b.
+abbrev ab next n unabbrev una
+append a number nu undo u
+args ar open o unmap unm
+change c preserve pre version ve
+copy co print p visual vi
+delete d put pu write w
+edit e quit q xit x
+file f read re yank ya
+global g recover rec \fIwindow\fP z
+insert i rewind rew \fIescape\fP !
+join j set se \fIlshift\fP <
+list l shell sh \fIprint next\fP \fRCR\fP
+map source so \fIresubst\fP &
+mark ma stop st \fIrshift\fP >
+move m substitute s \fIscroll\fP ^D
+.TE
+.h "Ex command addresses"
+.TS
+lw(.3i)b lw(0.8i) lw(.3i)b lw(0.8i).
+\fIn\fP line \fIn\fP /\fIpat\fP next with \fIpat\fP
+\&. current ?\fIpat\fP previous with \fIpat\fP
+$ last \fIx\fP-\fIn\fP \fIn\fP before \fIx\fP
++ next \fIx\fP,\fIy\fP \fIx\fP through \fIy\fP
+\- previous \(aa\fIx\fP marked with \fIx\fP
++\fIn\fP \fIn\fP forward \(aa\(aa previous context
+% 1,$
+.TE
+.nc
+.h "Specifying terminal type"
+.TS
+aw(1.7i)b aw(1.5i).
+% setenv TERM \fItype\fP \fIcsh\fP and all version 6
+$ TERM=\fItype\fP; export TERM \fIsh\fP in Version 7
+See also \fItset\fR(1)
+.TE
+.h "Some terminal types"
+.TS
+lw(.4i) lw(.4i) lw(.4i) lw(.4i) lw(.4i).
+2621 43 adm31 dw1 h19
+2645 733 adm3a dw2 i100
+300s 745 c100 gt40 mime
+33 act4 dm1520 gt42 owl
+37 act5 dm2500 h1500 t1061
+4014 adm3 dm3025 h1510 vt52
+.TE
+.h "Initializing options"
+.TS
+lw(.9i)b aw(1.5i).
+EXINIT place \fBset\fP's here in environment var.
+set \fIx\fP enable option
+set no\fIx\fP disable option
+set \fIx\fP=\fIval\fP give value \fIval\fP
+set show changed options
+set all show all options
+set \fIx\fP? show value of option \fIx\fP
+.TE
+.h "Useful options"
+.TS
+lw(.9i)b lw(.3i) lw(1.0i).
+autoindent ai supply indent
+autowrite aw write before changing files
+ignorecase ic in scanning
+lisp \fB( ) { }\fP are s-exp's
+list print ^I for tab, $ at end
+magic \fB. [ *\fP special in patterns
+number nu number lines
+paragraphs para macro names which start ...
+redraw simulate smart terminal
+scroll command mode lines
+sections sect macro names ...
+shiftwidth sw for \fB< >\fP, and input \fB^D\fP
+showmatch sm to \fB)\fP and \fB}\fP as typed
+slowopen slow choke updates during insert
+window visual mode lines
+wrapscan ws around end of buffer?
+wrapmargin wm automatic line splitting
+.TE
+.LP
+.h "Scanning pattern formation"
+.TS
+aw(.9i)b aw(1.0i).
+\(ua beginning of line
+$ end of line
+\fB.\fR any character
+\e< beginning of word
+\e> end of word
+[\fIstr\fP] any char in \fIstr\fP
+[\(ua\fIstr\fP] ... not in \fIstr\fP
+[\fIx\-y\fP] ... between \fIx\fP and \fIy\fP
+* any number of preceding
+.TE
+.nc
+.LP
+.LG
+.LG
+.B
+.ce
+Vi Quick Reference
+.NL
+.R
+.LP
+.LP
+.h "Entering/leaving vi"
+.TS
+aw(1.4i)b aw(1.8i).
+% vi \fIname\fP edit \fIname\fP at top
+% vi +\fIn\fP \fIname\fP ... at line \fIn\fP
+% vi + \fIname\fP ... at end
+% vi \-r list saved files
+% vi \-r \fIname\fP recover file \fIname\fP
+% vi \fIname\fP ... edit first; rest via \fB:n\fP
+% vi \-t \fItag\fP start at \fItag\fP
+% vi +/\fIpat\fP \fIname\fP search for \fIpat\fP
+% view \fIname\fP read only mode
+ZZ exit from vi, saving changes
+^Z stop vi for later resumption
+.TE
+.h "The display"
+.TS
+lw(.75i) lw(2.2i).
+Last line T{
+Error messages, echoing input to \fB: / ?\fP and \fB!\fR,
+feedback about i/o and large changes.
+T}
+@ lines On screen only, not in file.
+~ lines Lines past end of file.
+^\fIx\fP Control characters, ^? is delete.
+tabs Expand to spaces, cursor at last.
+.TE
+.LP
+.h "Vi states"
+.TS
+lw(.75i) lw(2.2i).
+Command T{
+Normal and initial state. Others return here.
+ESC (escape) cancels partial command.
+T}
+Insert T{
+Entered by \fBa i A I o O c C s S\fP \fBR\fP.
+Arbitrary text then terminates with ESC character,
+or abnormally with interrupt.
+T}
+Last line T{
+Reading input for \fB: / ?\fP or \fB!\fP; terminate
+with ESC or CR to execute, interrupt to cancel.
+T}
+.TE
+.h "Counts before vi commands"
+.TS
+lw(1.5i) lw(1.7i)b.
+line/column number z G |
+scroll amount ^D ^U
+replicate insert a i A I
+repeat effect \fRmost rest\fP
+.TE
+.h "Simple commands"
+.TS
+lw(1.5i)b lw(1.7i).
+dw delete a word
+de ... leaving punctuation
+dd delete a line
+3dd ... 3 lines
+i\fItext\fP\fRESC\fP insert text \fIabc\fP
+cw\fInew\fP\fRESC\fP change word to \fInew\fP
+ea\fIs\fP\fRESC\fP pluralize word
+xp transpose characters
+.TE
+.nc
+.h "Interrupting, cancelling"
+.TS
+aw(0.75i)b aw(1.6i).
+ESC end insert or incomplete cmd
+^? (delete or rubout) interrupts
+^L reprint screen if \fB^?\fR scrambles it
+.TE
+.h "File manipulation"
+.TS
+aw(0.75i)b aw(1.6i).
+:w write back changes
+:wq write and quit
+:q quit
+:q! quit, discard changes
+:e \fIname\fP edit file \fIname\fP
+:e! reedit, discard changes
+:e + \fIname\fP edit, starting at end
+:e +\fIn\fR edit starting at line \fIn\fR
+:e # edit alternate file
+^\(ua synonym for \fB:e #\fP
+:w \fIname\fP write file \fIname\fP
+:w! \fIname\fP overwrite file \fIname\fP
+:sh run shell, then return
+:!\fIcmd\fP run \fIcmd\fR, then return
+:n edit next file in arglist
+:n \fIargs\fP specify new arglist
+:f show current file and line
+^G synonym for \fB:f\fP
+:ta \fItag\fP to tag file entry \fItag\fP
+^] \fB:ta\fP, following word is \fItag\fP
+.TE
+.h "Positioning within file"
+.TS
+aw(0.75i)b aw(1.6i).
+^F forward screenfull
+^B backward screenfull
+^D scroll down half screen
+^U scroll up half screen
+G goto line (end default)
+/\fIpat\fR next line matching \fIpat\fR
+?\fIpat\fR prev line matching \fIpat\fR
+n repeat last \fB/\fR or \fB?\fR
+N reverse last \fB/\fR or \fB?\fR
+/\fIpat\fP/+\fIn\fP n'th line after \fIpat\fR
+?\fIpat\fP?\-\fIn\fP n'th line before \fIpat\fR
+]] next section/function
+[[ previous section/function
+% find matching \fB( ) {\fP or \fB}\fP
+.TE
+.h "Adjusting the screen"
+.TS
+aw(0.75i)b aw(1.6i).
+^L clear and redraw
+^R retype, eliminate @ lines
+z\fRCR\fP redraw, current at window top
+z\- ... at bottom
+z\|. ... at center
+/\fIpat\fP/z\- \fIpat\fP line at bottom
+z\fIn\fP\|. use \fIn\fP line window
+^E scroll window down 1 line
+^Y scroll window up 1 line
+.TE
+.nc
+.h "Marking and returning
+.TS
+aw(0.5i)b aw(2.0i).
+\(ga\(ga previous context
+\(aa\(aa ... at first non-white in line
+m\fIx\fP mark position with letter \fIx\fP
+\(ga\fIx\fP to mark \fIx\fP
+\(aa\fIx\fP ... at first non-white in line
+.TE
+.h "Line positioning"
+.TS
+aw(0.5i)b aw(2.0i).
+H home window line
+L last window line
+M middle window line
++ next line, at first non-white
+\- previous line, at first non-white
+\fRCR\fP return, same as +
+\(da \fRor\fP j next line, same column
+\(ua \fRor\fP k previous line, same column
+.TE
+.h "Character positioning"
+.TS
+aw(0.5i)b aw(2.0i).
+\(ua first non white
+0 beginning of line
+$ end of line
+h \fRor\fP \(-> forward
+l \fRor\fP \(<- backwards
+^H same as \fB\(<-\fP
+\fRspace\fP same as \fB\(->\fP
+f\fIx\fP find \fIx\fP forward
+F\fIx\fP \fBf\fR backward
+t\fIx\fP upto \fIx\fP forward
+T\fIx\fP back upto \fIx\fP
+; repeat last \fBf F t\fP or \fBT\fP
+, inverse of \fB;\fP
+| to specified column
+% find matching \fB( { )\fP or \fB}\fR
+.TE
+.h "Words, sentences, paragraphs"
+.TS
+aw(0.5i)b aw(2.0i).
+w word forward
+b back word
+e end of word
+) to next sentence
+} to next paragraph
+( back sentence
+{ back paragraph
+W blank delimited word
+B back \fBW\fP
+E to end of \fBW\fP
+.TE
+.h "Commands for \s-2LISP\s0"
+.TS
+aw(0.5i)b aw(2.0i).
+) Forward s-expression
+} ... but don't stop at atoms
+( Back s-expression
+{ ... but don't stop at atoms
+.TE
+.nc
+.h "Corrections during insert"
+.TS
+aw(.5i)b aw(2.0i).
+^H erase last character
+^W erases last word
+\fRerase\fP your erase, same as \fB^H\fP
+\fRkill\fP your kill, erase input this line
+\e escapes \fB^H\fR, your erase and kill
+\fRESC\fP ends insertion, back to command
+^? interrupt, terminates insert
+^D backtab over \fIautoindent\fP
+\(ua^D kill \fIautoindent\fP, save for next
+0^D ... but at margin next also
+^V quote non-printing character
+.TE
+.h "Insert and replace"
+.TS
+aw(.5i)b aw(2.0i).
+a append after cursor
+i insert before
+A append at end of line
+I insert before first non-blank
+o open line below
+O open above
+r\fIx\fP replace single char with \fIx\fP
+R replace characters
+.TE
+.h "Operators (double to affect lines)"
+.TS
+aw(0.5i)b aw(2.0i).
+d delete
+c change
+< left shift
+> right shift
+! filter through command
+\&\= indent for \s-2LISP\s0
+y yank lines to buffer
+.TE
+.h "Miscellaneous operations"
+.TS
+aw(0.5i)b aw(2.0i).
+C change rest of line
+D delete rest of line
+s substitute chars
+S substitute lines
+J join lines
+x delete characters
+X ... before cursor
+Y yank lines
+.TE
+.h "Yank and put"
+.TS
+aw(0.5i)b aw(2.0i).
+p put back lines
+P put before
+"\fIx\fPp put from buffer \fIx\fP
+"\fIx\fPy yank to buffer \fIx\fP
+"\fIx\fPd delete into buffer \fIx\fP
+.TE
+.h "Undo, redo, retrieve"
+.TS
+aw(0.5i)b aw(2.0i).
+u undo last change
+U restore current line
+\fB.\fP repeat last change
+"\fId\fP\|p retrieve \fId\fP'th last delete
+.TE
diff --git a/usr.bin/vi/docs/bugs.current b/usr.bin/vi/docs/bugs.current
new file mode 100644
index 000000000000..de2b01a6891d
--- /dev/null
+++ b/usr.bin/vi/docs/bugs.current
@@ -0,0 +1,48 @@
+List of known bugs:
+
++ Large numbers of matches (e.g. %, g or v commands), with the
+ ignorecase option set, triggers a memory corruption bug in the
+ regex routines.
+
++ Autoindent doesn't work in the ex editor.
+
++ ^C isn't passed to the shell in the script windows as an interrupt
+ character.
+
++ The command ":ab foo^J bar" prints a usage message -- non-word
+ characters should be quoted in the underlying terminal engine
+ so that the upper-level knows they're quoted and doesn't use them
+ as delimiters. (Note, this isn't historical practice, vi didn't
+ permit escaping of ^J in this type of command.)
+
++ The options edcompatible, hardtabs*, lisp*, optimize*, redraw*,
+ and slowopen* are recognized, but not implemented. Options with
+ an asterisk are unlikely to ever be implemented, so if you want
+ them you might want to say something! I will implement lisp if
+ anyone ever documents how it really worked.
+
++ Screen repainting over slow lines, for some screen changes, is not
+ as good as the historic vi's.
+
++ If an error results during input in ex, it is not displayed until
+ after input mode is exited.
+
++ If the ex append command is used from vi, the input command buffer
+ is overwritten by the ex_append function, causing random errors.
+
++ Colon commands longer than a single line cause the display to be
+ incorrect.
+
++ When switching files in a small screen (O_WINDOW) with :e, the status
+ message isn't displayed.
+
++ The usages of S_{REDRAW,REFORMAT,REFRESH,RENUMBER,RESIZE} are
+ inconsistent, and should be reviewed. In particular, S_REFRESH
+ in any screen redraws all screens.
+
++ Historic vi permitted :g/xxx/vi, i.e. you could execute ex/vi as
+ global commands. Need to review all of the old commands to verify
+ which ones could/could not be used as global commands.
+
++ If you run out of space in the recovery directory, the recovery
+ file is left in place.
diff --git a/usr.bin/vi/docs/changelog b/usr.bin/vi/docs/changelog
new file mode 100644
index 000000000000..5f1e7fded0ca
--- /dev/null
+++ b/usr.bin/vi/docs/changelog
@@ -0,0 +1,138 @@
+1.10 -> 1.11: Thu Mar 24 16:07:45 EST 1994
+ + Change H, M, and L to set the absolute mark, historical practice.
+ + Fix bug in stepping through multiple tags files.
+ + Add "remapmax" option that turns off map counts so you can remap
+ infinitely. If it's off, term_key() can be interrupted from the
+ keyboard, which will cause the buffers to flush. I also dropped
+ the default max number of remaps to 50. (Only Dave Hitz's TM
+ macros and maze appear to go over that limit.)
+ + Change :mkexrc to not dump w{300,1200,9600}, lisp options.
+ + Fix backward search within a line bug.
+ + Change all the includes of "pathnames.h" to use <>'s so that the
+ PORT versions can use -I. to replace it with their own versions.
+ + Make reads and writes interruptible. Rework code that enters and
+ leaves ex for '!' and filter commands, rework all interrupt and
+ timer code.
+ + Fix core dump when user displayed option in .exrc file.
+ + Fix bug where writing empty files didn't update the saved
+ modification time.
+ + Fix bug where /pattern/ addressing was always a backward search.
+ + Fix bug triggered by autoindent of more than 32 characters, where
+ nvi wasn't checking the right TEXT length.
+ + Fix bug where joining only empty lines caused a core dump.
+1.09 -> 1.10: Sat Mar 19 15:40:29 EST 1994
+ + Fix "set all" core dump.
+1.08 -> 1.09: Sat Mar 19 10:11:14 EST 1994
+ + If the tag's file path is relative, and it doesn't exist, check
+ relative to the tag file location.
+ + Fix ~ command to free temporary buffer on error return.
+ + Create vi.ref, a first cut at a reference document for vi.
+ The manual page and the reference document only document the
+ set options, so far.
+ + Fix 1G bug not always going to the first non-blank.
+ + Upgrade PORT/regex to release alpha3.4, from Henry Spencer.
+ + Add MKS vi's "cdpath" option, supporting a cd search path.
+ + Handle if search as a motion was discarded, i.e. "d/<erase>".
+ + Change nvi to not create multiple recovery files if modifying
+ a recovered file.
+ + Decide to ignore that the cursor is before the '$' when inserting
+ in list mode. It's too hard to fix.
+1.07 -> 1.08: Wed Mar 16 07:37:36 EST 1994
+ + Leftright and big line scrolling fixes. This meant more changes
+ to the screen display code, so there may be new problems.
+ + Don't permit search-style addresses until a file has been read.
+ + "c[Ww]" command incorrectly handled the "in whitespace" case.
+ + Fix key space allocation bug triggered by cut/paste under SunOS.
+ + Ex move command got the final cursor position wrong.
+ + Delete "optimize option not implemented" message.
+ + Make the literal-next character turn off mapping for the next
+ character in text input mode.
+1.06 -> 1.07: Mon Mar 14 11:10:33 EST 1994
+ + The "wire down" change in 1.05 broke ex command parsing, there
+ wasn't a corresponding change to handle multiple K_VLNEXT chars.
+ + Fix final position for vi's 't' command.
+1.05 -> 1.06: Sun Mar 13 16:12:52 EST 1994
+ + Wire down ^D, ^H, ^W, and ^V, regardless of the user's termios
+ values.
+ + Add ^D as the ex scroll command.
+ + Support ^Q as a literal-next character.
+ + Rework abbreviations to be delimited by any !inword() character.
+ + Add options description to the manual page.
+ + Minor screen cache fix for svi_get.c.
+ + Rework beautify option support to match historical practice.
+ + Exit immediately if not reading from a tty and a command fails.
+ + Default the SunOS 4.* ports to the distributed curses, not SMI's.
+1.04 -> 1.05: Thu Mar 24 16:07:45 EST 1994
+ + Make cursor keys work in input mode.
+ + Rework screen column code in vi curses screen. MAJOR CHANGE --
+ after this, we'll be debugging curses screen presentation from
+ scratch.
+ + Explode include files in vi.h into the source files.
+1.03 -> 1.04: Sun Mar 6 14:14:16 EST 1994
+ + Make the ex move command keep the marks on the moved lines.
+ + Change resize semantics so you can set the screen size to a
+ specific value. A couple of screen fixes for the resize code.
+ + Fixes for foreground/background due to SIGWINCH.
+ + Complete rework of all of vi's cursor movements. The underlying
+ assumption in the old code was that the starting cursor position
+ was part of the range of lines cut or deleted. The command
+ "d[[" is an example where this isn't true. Change it so that all
+ motion component commands set the final cursor position separately
+ from the range, as it can't be done correctly later. This is a
+ MAJOR CHANGE -- after this change, we'll be debugging the cursor
+ positioning from scratch.
+ + Rewrite the B, b, E, e commands to use vi's getc() interface
+ instead of rolling their own.
+ + Add a second MARK structure, LMARK, which is the larger mark
+ needed by the logging and mark queue code. Everything else uses
+ the reworked MARK structure, which is simply a line/column pair.
+ + Rework cut/delete to not expect 1-past-the-end in the range, but
+ to act on text to the end of the range, inclusive.
+ + Sync on write's, to force NFS to flush.
+1.01 -> 1.03: Sun Jan 23 17:50:35 EST 1994 (PUBLICLY AVAILABLE VERSION)
+ + Tag stack fixes, was returning to the tag, not the position from
+ which the user tagged.
+ + Only use from the cursor to the end of the word in cursor word
+ searches and tags. (Matches historical vi behavior.)
+ + Fix delete-last-line bug when line number option set.
+ + Fix usage line for :split command.
+ + If O_NUMBER set, long input lines would eventually fail, the column
+ count for the second screen of long lines wasn't set correctly.
+ + Fix for [[ reaching SOF with a column longer than the first line.
+ + Fix for multiple error messages if no screen displayed.
+ + Fix :read to set alternate file name as in historical practice.
+ + Fix cut to rotate the numeric buffers if line mode flag set.
+1.00 -> 1.01: Wed Jan 12 13:37:18 EST 1994
+ + Don't put cut items into numeric buffers if cutting less than
+ parts of two lines.
+0.94 -> 1.00: Mon Jan 10 02:27:27 EST 1994
+ + Read-ahead not there; BSD tty driver problem, SunOS curses
+ problem.
+ + Global command could error if it deleted the last line of
+ the file.
+ + Change '.' to only apply to the 'u' if entered immediately
+ after the 'u' command. "1pu.u.u. is still broken, but I
+ expect that it's going to be sacrificed for multiple undo.
+ + If backward motion on a command, now move to the point; get
+ yank cursor positioning correct.
+ + Rework cut buffers to match historic practice -- yank/delete
+ numeric buffers redone sensibly, ignoring historic practice.
+0.92 -> 0.93: Mon Dec 20 19:52:14 EST 1993
+ + Christos Zoulas reimplemented the script windows using pty's,
+ which means that they now work reasonably. The down side of
+ this is that almost all ports other than 4.4BSD need to include
+ two new files, login_tty.c and pty.c from the PORT/clib directory.
+ I've added them to the Makefiles.
+ + All calloc/malloc/realloc functions now cast their pointers, for
+ SunOS -- there should be far fewer warning messages, during the
+ build. The remaining messages are where CHAR_T's meet char *'s,
+ i.e. where 8-bit clean meets strcmp.
+ + The user's argument list handling has been reworked so that there
+ is always a single consistent position for use by :next, :prev and
+ :rewind.
+ + All of the historical options are now at least accepted, although
+ not all of them are implemented. (Edcompatible, hardtabs, lisp,
+ optimize, redraw, and slowopen aren't implemented.)
+ + The RE's have been reworked so that matches of length 0 are handled
+ in the same way as vi used to handle them.
+ + Several more mapping fixes and ex parser addressing fixes.
diff --git a/usr.bin/vi/docs/features b/usr.bin/vi/docs/features
new file mode 100644
index 000000000000..ee07857fdab1
--- /dev/null
+++ b/usr.bin/vi/docs/features
@@ -0,0 +1,47 @@
+List of things that should be added at some point:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
++ X11 interface.
+
++ Forms editing package; use RE's to verify field contents.
+
++ Internationalization, including wide character support.
+
++ Make db, curses real libraries that we load against instead of
+ compiling directly.
+
++ Add a ":resize =N" command, that sets the window to a specific
+ size.
+
+List of suggested features:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
++ Change tags to also attempt to find the file using the directory
+ where it found the tags file.
+
++ Add versioning based on a "set version" variable, that would
+ create backup copies when the file was written back, i.e. the
+ ":w" and autowrite's would copy the original.
+
++ Add "set searchdir" for a list of directories to look in for
+ files to edit. The semantic is that ":e foo" is replaced with
+ the file name that is found, so there's no confusion as to
+ which file is written.
+
++ Change
+ :di[splay] tags -> :tags
+ :di[splay] screens -> :screens
+ :di[splay] buffers -> :buffers
+
++ A macro record function. Add the ability to record a sequence
+ of keystrokes into a named buffer for later use. Handy when
+ you're trying to build a semi-complex macro.
+
++ Put multiple messages on a single line if they fit in their entirety,
+ so that ":n" with autowrite set doesn't force users to hit return to
+ get see both the "written" and "new file status" messages.
+
++ The semantics of :split, :bg, and :fg aren't right. Someone needs to
+ rethink how they should interact. The main problem arises when users
+ want to get a window into a new file. Currently, the necessary sequence
+ is ":split newfile|^W|:bg". It would be nice if you could simply
+ background the current screen and edit a new one.
diff --git a/usr.bin/vi/docs/internals/autowrite b/usr.bin/vi/docs/internals/autowrite
new file mode 100644
index 000000000000..55cd13b8f72e
--- /dev/null
+++ b/usr.bin/vi/docs/internals/autowrite
@@ -0,0 +1,88 @@
+# @(#)autowrite 8.2 (Berkeley) 9/28/93
+
+Vi autowrite behavior, the fields with *'s are "don't cares".
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that are affected only by autowrite:
+
+Command File Autowrite? Action:
+ modified?
+-----------------------------------------------
+^Z Y Y Write file and suspend.
+^Z Y N Suspend.
+^Z N * Suspend.
+
+# This behavior is NOT identical to :edit.
+^ Y Y Write file and jump.
+^ Y N Error.
+^ N * Jump.
+
+# The new nvi command ^T (:tagpop) behaves identically to ^].
+# This behavior is identical to :tag, :tagpop, and :tagpush with
+# force always set to N.
+^] Y Y Write file and jump.
+^] Y N Error.
+^] N * Jump.
+
+# There's no way to specify a force flag to the '!' command.
+:! Y Y Write file and execute.
+:! Y N Warn (if warn option) and execute.
+:! N * Execute.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that are affected by both autowrite and force:
+
+NOTE: the "force" flag is never passed on, i.e. the write
+to the file caused by the autowrite flag is never forced.
+
+Command File Autowrite? Force? Action:
+ modified? (!)
+-------------------------------------------------------
+# The first rule (YYY) is historic practice, but seems wrong.
+# In nvi, :next and :prev commands behave identically to :rewind.
+:next Y Y Y Write changes and jump.
+:next Y Y N Write changes and jump.
+:next Y N Y Abandon changes and jump.
+:next Y N N Error.
+:next N * * Jump.
+
+:rewind Y Y Y Abandon changes and jump.
+:rewind Y Y N Write changes and jump.
+:rewind Y N Y Abandon changes and jump.
+:rewind Y N N Error.
+:rewind N * * Jump.
+
+# The new nvi commands, :tagpop and :tagtop, behave identically to :tag.
+# Note, this behavior is the same as :rewind and friends, as well.
+:tag Y Y Y Abandon changes and jump.
+:tag Y Y N Write changes and jump.
+:tag Y N Y Abandon changes and jump.
+:tag Y N N Error.
+:tag N * * Jump.
+
+# The command :suspend behaves identically to :stop.
+:stop Y Y Y Suspend.
+:stop Y Y N Write changes and suspend.
+:stop Y N Y Suspend.
+:stop Y N N Suspend.
+:stop N * * Suspend.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that might be affected by autowrite, but aren't:
+
+Command File Autowrite? Force? Action:
+ modified? (!)
+-------------------------------------------------------
+#:ex, and :vi (executed while in vi mode) behave identically to :edit.
+:edit Y * Y Abandon changes and jump.
+:edit Y * N Error.
+:edit N * * Jump.
+
+:quit Y * Y Quit.
+:quit Y * N Error.
+:quit N * * Quit.
+
+:shell * * * Execute shell.
+
+:xit Y * * Write changes and exit.
+:xit N * * Exit.
diff --git a/usr.bin/vi/docs/internals/gdb.script b/usr.bin/vi/docs/internals/gdb.script
new file mode 100644
index 000000000000..5f180edcd642
--- /dev/null
+++ b/usr.bin/vi/docs/internals/gdb.script
@@ -0,0 +1,68 @@
+# @(#)gdb.script 8.2 (Berkeley) 9/29/93
+
+# display the SVI screen map
+# usage dmap(sp)
+define dmap
+ set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap
+ set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap
+ while ($h <= $t)
+ printf "lno: %d; off %d ", (int)$h->lno, (int)$h->off
+ if ($h->c_ecsize == 0)
+ printf "flushed\n"
+ else
+ printf "\n\tsboff %d; scoff %d\n", \
+ (int)$h->c_sboff, (int)$h->c_scoff
+ printf "\teboff %d; eclen %d; ecsize %d\n", \
+ (int)$h->c_eboff, (int)$h->c_eclen, \
+ (int)$h->c_ecsize
+ end
+ set $h = $h + 1
+ end
+end
+
+# display the tail of the SVI screen map
+define tmap
+ set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap
+ set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap
+ while ($t >= $h)
+ printf "lno: %d; off %d ", (int)$t->lno, (int)$t->off
+ if ($t->c_ecsize == 0)
+ printf "flushed\n"
+ else
+ printf "\n\tsboff %d; scoff %d\n", \
+ (int)$t->c_sboff, (int)$t->c_scoff
+ printf "\teboff %d; eclen %d; ecsize %d\n", \
+ (int)$t->c_eboff, (int)$t->c_eclen, \
+ (int)$t->c_ecsize
+ end
+ set $t = $t - 1
+ end
+end
+
+# display the SVI private structure
+define svp
+ print *((SVI_PRIVATE *)sp->svi_private)
+end
+
+# display the marks
+define markp
+ set $h = sp->ep->marks.next
+ set $t = &sp->ep->marks
+ while ($h != 0 && $h != $t)
+ printf "key %c lno: %d cno: %d flags: %x\n", \
+ ((MARK *)$h)->name, ((MARK *)$h)->lno, \
+ ((MARK *)$h)->cno, ((MARK *)$h)->flags
+ set $h = ((MARK *)$h)->next
+ end
+end
+
+# display the tags
+define tagp
+ set $h = sp->taghdr.next
+ set $t = &sp->taghdr
+ while ($h != 0 && $h != $t)
+ printf "tag: %s lno %d cno %d\n", ((TAG *)$h)->frp->fname, \
+ ((TAG *)$h)->lno, ((TAG *)$h)->cno
+ set $h= ((TAG *)$h)->next
+ end
+end
diff --git a/usr.bin/vi/docs/internals/input b/usr.bin/vi/docs/internals/input
new file mode 100644
index 000000000000..f5aa80c7aa8e
--- /dev/null
+++ b/usr.bin/vi/docs/internals/input
@@ -0,0 +1,314 @@
+# @(#)input 5.4 (Berkeley) 8/26/93
+
+MAPS, EXECUTABLE BUFFERS AND INPUT IN EX/VI:
+
+The basic rule is that input in ex/vi is a stack. Every time a key which
+gets expanded is encountered, it is expanded and the expansion is treated
+as if it were input from the user. So, maps and executable buffers are
+simply pushed onto the stack from which keys are returned. The exception
+is that if the "remap" option is turned off, only a single map expansion
+is done. I intend to be fully backward compatible with this.
+
+Historically, if the mode of the editor changed (ex to vi or vice versa),
+any queued input was silently discarded. I don't see any reason to either
+support or not support this semantic. I intend to retain the queued input,
+mostly because it's simpler than throwing it away.
+
+Historically, neither the initial command on the command line (the + flag)
+or the +cmd associated with the ex and edit commands was subject to mapping.
+Also, while the +cmd appears to be subject to "@buffer" expansion, once
+expanded it doesn't appear to work correctly. I don't see any reason to
+either support or not support these semantics, so, for consistency, I intend
+to pass both the initial command and the command associated with ex and edit
+commands through the standard mapping and @ buffer expansion.
+
+One other difference between the historic ex/vi and nex/nvi is that nex
+displays the executed buffers as it executes them. This means that if
+the file is:
+
+ set term=xterm
+ set term=yterm
+ set term=yterm
+
+the user will see the following during a typical edit session:
+
+ nex testfile
+ testfile: unmodified: line 3
+ :1,$yank a
+ :@a
+ :set term=zterm
+ :set term=yterm
+ :set term=xterm
+ :q!
+
+This seems like a feature and unlikely to break anything, so I don't
+intend to match historic practice in this area.
+
+The rest of this document is a set of conclusions as to how I believe
+the historic maps and @ buffers work. The summary is as follows:
+
+1: For buffers that are cut in "line mode", or buffers that are not cut
+ in line mode but which contain portions of more than a single line, a
+ trailing <newline> character appears in the input for each line in the
+ buffer when it is executed. For buffers not cut in line mode and which
+ contain portions of only a single line, no additional characters
+ appear in the input.
+2: Executable buffers that execute other buffers don't load their
+ contents until they execute them.
+3: Maps and executable buffers are copied when they are executed --
+ they can be modified by the command but that does not change their
+ actions.
+4: Historically, executable buffers are discarded if the editor
+ switches between ex and vi modes.
+5: Executable buffers inside of map commands are expanded normally.
+ Maps inside of executable buffers are expanded normally.
+6: If an error is encountered while executing a mapped command or buffer,
+ the rest of the mapped command/buffer is discarded. No user input
+ characters are discarded.
+
+Individual test cases follow. Note, in the test cases, control characters
+are not literal and will have to be replaced to make the test cases work.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+1: For buffers that are cut in "line mode", or buffers that are not cut
+ in line mode but which contain portions of more than a single line, a
+ trailing <newline> character appears in the input for each line in the
+ buffer when it is executed. For buffers not cut in line mode and which
+ contain portions of only a single line, no additional characters
+ appear in the input.
+
+=== test file ===
+3Gw
+w
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+=== end test file ===
+
+ If the first line is loaded into 'a' and executed:
+
+1G"ayy@a
+
+ The cursor ends up on the '2', a result of pushing "3Gw^J" onto
+ the stack.
+
+ If the first two lines are loaded into 'a' and executed:
+
+1G2"ayy@a
+
+ The cursor ends up on the 'f' in "foo" in the fifth line of the
+ file, a result of pushing "3Gw^Jw^J" onto the stack.
+
+ If the first line is loaded into 'a', but not using line mode,
+ and executed:
+
+1G"ay$@a
+
+ The cursor ends up on the '1', a result of pushing "3Gw" onto
+ the stack
+
+ If the first two lines are loaded into 'a', but not using line mode,
+ and executed:
+
+1G2"ay$@a
+
+ The cursor ends up on the 'f' in "foo" in the fifth line of the
+ file, a result of pushing "3Gw^Jw^J" onto the stack.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+2: Executable buffers that execute other buffers don't load their
+ contents until they execute them.
+
+=== test file ===
+cwLOAD B^[
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"byy
+=== end test file ===
+
+ The command is loaded into 'e', and then executed. 'e' executes
+ 'a', which loads 'b', then 'e' executes 'b'.
+
+5G"eyy6G"ayy1G@e
+
+ The output should be:
+
+=== output file ===
+cwLOAD B^[
+LOAD B 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"byy
+=== end output file ===
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+3: Maps and executable buffers are copied when they are executed --
+ they can be modified by the command but that does not change their
+ actions.
+
+ Executable buffers:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"eyy
+cwEXECUTE B^[
+=== end test file ===
+
+4G"eyy5G"ayy6G"byy1G@eG"ep
+
+ The command is loaded into 'e', and then executed. 'e' executes
+ 'a', which loads 'e', then 'e' executes 'b' anyway.
+
+ The output should be:
+
+=== output file ===
+line 1 foo bar baz
+EXECUTE B 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"eyy
+cwEXECUTE B^[
+line 1 foo bar baz
+=== end output file ===
+
+ Maps:
+
+=== test file ===
+Cine 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+=== end test file ===
+
+ Entering the command ':map = :map = rB^V^MrA^M1G==' shows that
+ the first time the '=' is entered the '=' map is set and the
+ character is changed to 'A', the second time the character is
+ changed to 'B'.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+4: Historically, executable buffers are discarded if the editor
+ switches between ex and vi modes.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwCHANGE^[Q:set
+set|visual|1Gwww
+=== end test file ===
+
+vi testfile
+4G"ayy@a
+
+ex testfile
+$p
+yank a
+@a
+
+ In vi, the command is loaded into 'a' and then executed. The command
+ subsequent to the 'Q' is (historically, silently) discarded.
+
+ In ex, the command is loaded into 'a' and then executed. The command
+ subsequent to the 'visual' is (historically, silently) discarded. The
+ first set command is output by ex, although refreshing the screen usually
+ causes it not to be seen.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+5: Executable buffers inside of map commands are expanded normally.
+ Maps inside of executable buffers are expanded normally.
+
+ Buffers inside of map commands:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwREPLACE BY A^[
+=== end test file ===
+
+4G"ay$:map x @a
+1Gx
+
+ The output should be:
+
+=== output file ===
+REPLACE BY A 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwREPLACE BY A^[
+=== end output file ===
+
+ Maps commands inside of executable buffers:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+=== end test file ===
+
+:map X cwREPLACE BY XMAP^[
+4G"ay$1G@a
+
+ The output should be:
+
+=== output file ===
+REPLACE BY XMAP 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+=== end output file ===
+
+ Here's a test that does both, repeatedly.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+Y
+cwREPLACED BY C^[
+blank line
+=== end test file ===
+
+:map x @a
+4G"ay$
+:map X @b
+5G"by$
+:map Y @c
+6G"cy$
+1Gx
+
+ The output should be:
+
+=== output file ===
+REPLACED BY C 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+Y
+cwREPLACED BY C^[
+blank line
+=== end output file ===
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+6: If an error is encountered while executing a mapped command or
+ a buffer, the rest of the mapped command/buffer is discarded. No
+ user input characters are discarded.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+:map = 10GcwREPLACMENT^V^[^[
+=== end test file ===
+
+ The above mapping fails, however, if the 10G is changed to 1, 2,
+ or 3G, it will succeed.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
diff --git a/usr.bin/vi/docs/internals/quoting b/usr.bin/vi/docs/internals/quoting
new file mode 100644
index 000000000000..f20bd3f2b1e9
--- /dev/null
+++ b/usr.bin/vi/docs/internals/quoting
@@ -0,0 +1,219 @@
+# @(#)quoting 5.4 (Berkeley) 8/20/93
+
+QUOTING IN EX/VI:
+
+There are two escape characters in historic ex/vi, ^V (or whatever
+character the user specified as their literal next character) and
+backslashes. There are two different areas in ex/vi where escaping
+is interesting: the command and text input modes, and within the ex
+commands themselves. In the examples below, ^V is used as the
+typical literal next character.
+
+1: Escaping characters in ex and vi command and text input modes.
+ The set of characters that users might want to escape are as
+ follows:
+
+ vi text input mode (a, i, o, etc.):
+
+ carriage return (^M)
+ escape (^[)
+ autoindent characters
+ (^D, 0, ^, ^T)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z) (not historic practice)
+ repaint (^L) (not historic practice)
+
+ vi command line (:colon commands):
+
+ carriage return (^M)
+ escape (^[)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z) (not historic practice)
+ repaint (^L) (not historic practice)
+
+ ex text input mode (a, i, o, etc.):
+
+ carriage return (^M)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+
+ ex command line:
+
+ carriage return (^M)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z)
+
+ I intend to follow historic practice for all of these cases, which
+ was that ^V was the only way to escape any of these characters, and
+ that whatever character followed the ^V was taken literally, i.e.
+ ^V^V is a single ^V.
+
+ The historic ex/vi disallowed the insertion of various control
+ characters (^D, ^T, whatever) during various different modes, or,
+ permitted the insertion of only a single one, or lots of other random
+ behaviors (you can use ^D to enter a command in ex). I have
+ regularized this behavior in nvi, there are no characters that cannot
+ be entered or which have special meaning other than the ones listed
+ above.
+
+ One comment regarding the autoindent characters. In historic vi,
+ if you entered "^V0^D" autoindent erasure was still triggered,
+ although it wasn't if you entered "0^V^D". In nvi, if you escape
+ either character, autoindent erasure is not triggered.
+
+ This doesn't permit whitespace in command names, but that wasn't
+ historic practice and doesn't seem worth doing.
+
+ Fun facts to know and tell:
+ The historic vi implementation for the 'r' command requires
+ *three* ^V's to replace a single character with ^V.
+
+2: Ex commands:
+
+ Ex commands are delimited by '|' or newline characters. Within
+ the commands, whitespace characters delimit the arguments.
+
+ I intend to treat ^V, followed by any character, as that literal
+ character.
+
+ This is historic behavior in vi, although there are special
+ cases where it's impossible to escape a character, generally
+ a whitespace character.
+
+3: Escaping characters in file names in ex commands:
+
+ :cd [directory] (directory)
+ :chdir [directory] (directory)
+ :edit [+cmd] [file] (file)
+ :ex [+cmd] [file] (file)
+ :file [file] (file)
+ :next [file ...] (file ...)
+ :read [!cmd | file] (file)
+ :source [file] (file)
+ :write [!cmd | file] (file)
+ :wq [file] (file)
+ :xit [file] (file)
+
+ I intend to treat a backslash in a file name, followed by any
+ character, as that literal character.
+
+ This is historic behavior in vi.
+
+ In addition, since file names are also subject to word expansion,
+ the rules for escape characters in section 3 of this document also
+ apply. This is NOT historic behavior in vi, making it impossible
+ to insert a whitespace, newline or carriage return character into
+ a file name. This change could cause a problem if there were files
+ with ^V's in their names, but I think that's unlikely.
+
+4: Escaping characters in non-file arguments in ex commands:
+
+ :abbreviate word string (word, string)
+* :edit [+cmd] [file] (+cmd)
+* :ex [+cmd] [file] (+cmd)
+ :k key (key)
+ :map word string (word, string)
+ :mark key (key)
+* :set [option ...] (option)
+* :tag string (string)
+ :unabbreviate word (word)
+ :unmap word (word)
+
+ These commands use whitespace to delimit their arguments, and use
+ ^V to escape those characters. The exceptions are starred in the
+ above list, and are discussed below.
+
+ In general, I intend to treat a ^V in any argument, followed by
+ any character, as that literal character. This will permit
+ editing of files name "foo|", for example, by using the string
+ "foo\^V|", where the literal next character protects the pipe
+ from the ex command parser and the backslash protects it from the
+ shell expansion.
+
+ This is backward compatible with historical vi, although there
+ were a number of special cases where vi wasn't consistent.
+
+4.1: The edit/ex commands:
+
+ The edit/ex commands are a special case because | symbols may
+ occur in the "+cmd" field, for example:
+
+ :edit +10|s/abc/ABC/ file.c
+
+ In addition, the edit and ex commands have historically ignored
+ literal next characters in the +cmd string, so that the following
+ command won't work.
+
+ :edit +10|s/X/^V / file.c
+
+ I intend to handle the literal next character in edit/ex consistently
+ with how it is handled in other commands.
+
+ More fun facts to know and tell:
+ The acid test for the ex/edit commands:
+
+ date > file1; date > file2
+ vi
+ :edit +1|s/./XXX/|w file1| e file2|1 | s/./XXX/|wq
+
+ No version of vi, of which I'm aware, handles it.
+
+4.2: The set command:
+
+ The set command treats ^V's as literal characters, so the following
+ command won't work. Backslashes do work in this case, though, so
+ the second version of the command does work.
+
+ set tags=tags_file1^V tags_file2
+ set tags=tags_file1\ tags_file2
+
+ I intend to continue permitting backslashes in set commands, but
+ to also permit literal next characters to work as well. This is
+ backward compatible, but will also make set consistent with the
+ other commands. I think it's unlikely to break any historic
+ .exrc's, given that there are probably very few files with ^V's
+ in their name.
+
+4.3: The tag command:
+
+ The tag command ignores ^V's and backslashes; there's no way to
+ get a space into a tag name.
+
+ I think this is a don't care, and I don't intend to fix it.
+
+5: Regular expressions:
+
+ :global /pattern/ command
+ :substitute /pattern/replace/
+ :vglobal /pattern/ command
+
+ I intend to treat a backslash in the pattern, followed by the
+ delimiter character or a backslash, as that literal character.
+
+ This is historic behavior in vi. It would get rid of a fairly
+ hard-to-explain special case if we could just use the character
+ immediately following the backslash in all cases, or, if we
+ changed nvi to permit using the literal next character as a
+ pattern escape character, but that would probably break historic
+ scripts.
+
+ There is an additional escaping issue for regular expressions.
+ Within the pattern and replacement, the '|' character did not
+ delimit ex commands. For example, the following is legal.
+
+ :substitute /|/PIPE/|s/P/XXX/
+
+ This is a special case that I will support.
+
+6: Ending anything with an escape character:
+
+ In all of the above rules, an escape character (either ^V or a
+ backslash) at the end of an argument or file name is not handled
+ specially, but used as a literal character.
diff --git a/usr.bin/vi/docs/internals/structures b/usr.bin/vi/docs/internals/structures
new file mode 100644
index 000000000000..d49ab65cbeed
--- /dev/null
+++ b/usr.bin/vi/docs/internals/structures
@@ -0,0 +1,61 @@
+# @(#)structures 5.2 (Berkeley) 11/1/93
+
+There are three major data structures in this package. The first is a
+single global structure (named GS) which contains information common to
+all files and screens. It's really pretty tiny, and functions more as a
+single place to hang things than anything else.
+
+The second and third structures are the file structures (named EXF) and
+the screen structures (named SCR). They contain information theoretically
+unique to a screen or file, respectively. Each SCR structure has a set
+of functions which update the screen and/or return information about the
+screen from the underlying screen package.
+
+The GS structure contains linked lists SCR structures. The structures
+can also be classed by persistence. The GS structure never goes away
+and the SCR structure persists over instances of files.
+
+File names have different properties than files themselves, so the name
+information for a file is held in an FREF structure which is chained from
+the SCR structure.
+
+In general, functions are always passed an SCR structure and often an EXF
+structure as well. The SCR structure is necessary for any routine that
+wishes to talk to the screen, the EXF structure is necessary for any
+routine that wants to modify the file. The relationship between an SCR
+structure and its underlying EXF structure is not fixed, and although you
+can translate from an SCR to the underlying EXF, it is discouraged. If
+this becomes too onerous, I suspect I'll just stop passing around the EXF
+in the future.
+
+The naming of the structures is consistent across the program. (Macros
+even depend on it, so don't try and change it!) The global structure is
+"gp", the screen structure is "sp", and the file structure is "ep".
+
+A few other data structures:
+
+TEXT In nvi/cut.h. This structure describes a portion of a line,
+ and is used by the input routines and as the "line" part of a
+ cut buffer.
+
+CB In nvi/cut.h. A cut buffer. A cut buffer is a place to
+ hang a list of TEXT structures.
+
+MARK In nvi/mark.h. A cursor position, consisting of a line number
+ and a column number.
+
+MSG In nvi/msg.h. A chain of messages for the user.
+
+SEQ In nvi/seq.h. An abbreviation or a map entry.
+
+EXCMDARG
+ In nvi/ex/excmd.h.stub. The structure that gets passed around
+ to the functions that implement the ex commands. (The main
+ ex command loop (see nvi/ex/ex.c) builds this up and then passes
+ it to the ex functions.)
+
+VICMDARG
+ In nvi/vi/vcmd.h. The structure that gets passed around to the
+ functions that implement the vi commands. (The main vi command
+ loop (see nvi/vi/vi.c) builds this up and then passes it to the
+ vi functions.)
diff --git a/usr.bin/vi/docs/set.opt.roff b/usr.bin/vi/docs/set.opt.roff
new file mode 100644
index 000000000000..e39dc810d1d7
--- /dev/null
+++ b/usr.bin/vi/docs/set.opt.roff
@@ -0,0 +1,1065 @@
+.\" Copyright (c) 1994
+.\" 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.
+.\"
+.\" @(#)set.opt.roff 8.5 (Berkeley) 3/22/94
+.\"
+There are a large number of options that may be set (or unset) to
+change the editor's behavior.
+This section describes the options, their abbreviations and their
+default values.
+.Pp
+In each entry below, the first part of the tag line is the full name
+of the option, followed by any equivalent abbreviations.
+#ifdef REFERENCE
+(Regardless of the abbreviations, it is only necessary to use the
+minimum number of characters necessary to distinguish an abbreviation
+from all other commands for it to be accepted, in
+.Nm nex/nvi .
+Historically, only the full name and the official abbreviations
+were accepted by
+.Nm ex/vi .
+Using full names in your startup files and environmental variables will
+probably make them more portable.)
+#endif
+The part in square brackets is the default value of the option.
+Most of the options are boolean, i.e. they are either on or off,
+and do not have an associated value.
+.Pp
+Options apply to both
+.Nm \&ex
+and
+.Nm \&vi
+modes, unless otherwise specified.
+#ifdef REFERENCE
+.Pp
+For information on modifying the options or to display the options and
+their current values, see the
+.Dq set
+command in the Ex Commands section.
+#endif
+.Bl -tag -width "XXXX" -compact
+.It Li "altwerase [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Select an alternate word erase algorithm.
+#endif
+#ifdef REFERENCE
+Change how
+.Nm \&vi
+does word erase during text input.
+When this option is set, text is broken up into three classes:
+alphabetic, numeric and underscore characters, other non-blank
+characters, and blank characters.
+Changing from one class to another marks the end of a word.
+In addition, the class of the first character erased is ignored
+(which is exactly what you want when erasing pathname components).
+#endif
+.It Li "autoindent, ai [off]"
+#ifdef MANUAL
+Automatically indent new lines.
+#endif
+#ifdef REFERENCE
+If this option is set, whenever you create a new line (using the
+.Nm \&vi
+.Sy \&A ,
+.Sy \&a ,
+.Sy \&C ,
+.Sy \&c ,
+.Sy \&I ,
+.Sy \&i ,
+.Sy \&O ,
+.Sy \&o ,
+.Sy \&R ,
+.Sy \&r ,
+.Sy \&S ,
+and
+.Sy \&s
+commands, or the
+.Nm \&ex
+.Sy append ,
+.Sy change ,
+and
+.Sy insert
+commands) the new line is automatically indented to align the cursor with
+the first non-blank character of the line from which you created it.
+Lines are indented using tab characters to the extent possible (based on
+the value of the
+.Sy tabstop
+option) and then using space characters as necessary.
+For commands inserting text into the middle of a line, any blank characters
+to the right of the cursor are discarded, and the first non-blank character
+to the right of the cursor is aligned as described above.
+.Pp
+The indent characters are themselves somewhat special.
+If you do not enter more characters on the new line before moving moving to
+another line, or entering <escape>, the indent character will be deleted and
+the line will be empty.
+For example, if you enter <carriage-return> twice in succession, the line
+created by the first <carriage-return> will not have any characters in it,
+regardless of the indentation of the previous or subsequent line.
+.Pp
+Indent characters also require that you enter additional erase characters
+to delete them.
+For example, if you have an indented line, containing only blanks, the first
+<word-erase> character you enter will erase up to end of the indent characters,
+and the second will erase back to the beginning of the line.
+(Historically, only the
+.Sy \&^D
+key would erase the indent characters.
+Both the
+.Sy \&^D
+key and the usual erase keys work in
+.Nm nvi .)
+In addition, if the cursor is positioned at the end of the indent
+characters, the keys
+.Dq 0^D
+will erase all of the indent characters for the current line,
+resetting the indentation level to 0.
+Similarly, the keys
+.Dq ^^D
+(i.e. a carat followed by a <control-D>) will erase all of the indent
+characters for the current line, leaving the indentation level for
+future created lines unaffected.
+.Pp
+Finally, if
+.Sy autoindent
+is set, the
+.Sy \&S
+and
+.Sy \&cc
+commands change from the first non-blank of the line to the end of the
+line, instead of from the beginning of the line to the end of the line.
+#endif
+.It Li "autoprint, ap [off]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Display the current line automatically.
+.
+#endif
+#ifdef REFERENCE
+.Nm \&Ex
+only.
+Cause the current line to be automatically displayed after the
+.Nm \&ex
+commands
+.Sy \&< ,
+.Sy \&> ,
+.Sy copy ,
+.Sy delete ,
+.Sy join ,
+.Sy move ,
+.Sy put ,
+.Sy \&t ,
+.Sy Undo ,
+and
+.Sy undo .
+This automatic display is suppressed during
+.Sy global
+and
+.Sy vglobal
+commands, and for any command where optional flags are used to explicitly
+display the line.
+#endif
+.It Li "autowrite, aw [off]"
+#ifdef MANUAL
+Write modified files automatically when changing files.
+#endif
+#ifdef REFERENCE
+If this option is set, the
+.Nm \&vi
+.Sy \&!
+.Sy \&^^
+.Sy \&^]
+and
+.Sy \&^Z
+commands, and the
+.Nm \&ex
+.Sy edit ,
+.Sy next ,
+.Sy rewind ,
+.Sy stop ,
+.Sy suspend ,
+.Sy tag ,
+.Sy tagpop ,
+and
+.Sy tagtop
+commands automatically write the current file back to the current file name
+if it has been modified since it was last written.
+If the write fails, the command fails and goes no further.
+.Pp
+Appending the optional force flag
+.Dq \&!
+to the
+.Nm \&ex
+commands
+.Sy next ,
+.Sy rewind ,
+.Sy stop ,
+.Sy suspend ,
+.Sy tag ,
+.Sy tagpop ,
+and
+.Sy tagtop
+stops the automatic write from being attempted.
+.Pp
+(Historically, the
+.Sy next
+command ignored the optional force flag.)
+Note, the
+.Nm \&ex
+commands
+.Sy edit ,
+.Sy quit ,
+.Sy shell ,
+and
+.Sy xit
+are
+.Em not
+affected by the
+.Sy autowrite
+option.
+#endif
+.It Li "beautify, bf [off]"
+#ifdef MANUAL
+Discard control characters.
+#endif
+#ifdef REFERENCE
+If this option is set, all control characters that are not currently being
+specially interpreted, other than <tab>, <newline>, and <form-feed>, are
+discarded from commands read in by
+.Nm \&ex
+from command files, and from input text entered to
+.Nm \&vi
+(either into the file or to the colon command line).
+Text files read by
+.Nm ex/vi
+are
+.Em not
+affected by the
+.Sy beautify
+option.
+#endif
+.It Li "cdpath [environment variable CDPATH, or ``.'']"
+#ifdef MANUAL
+The directory paths used as path prefixes for the
+.Sy cd
+command.
+#endif
+#ifdef REFERENCE
+This option is used to specify a colon separated list of directories
+which are used as path prefixes for any relative path names used as
+arguments for the
+.Sy cd
+command.
+The value of this option defaults to the value of the environmental
+variable
+.Ev CDPATH
+if it is set, otherwise to the current directory.
+For compatibility with the POSIX 1003.2 shell, the
+.Sy cd
+command does
+.Em not
+check the current directory as a path prefix for relative path names
+unless it is explicitly specified.
+It may be so specified by entering an empty string or a
+.Dq \&.
+into the
+.Ev CDPATH
+variable or the option value.
+#endif
+.It Li "columns, co [80]"
+#ifdef MANUAL
+Set the number of columns in the screen.
+#endif
+#ifdef REFERENCE
+The number of columns in the screen.
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev COLUMNS .
+See the SCREEN SIZING section for more information.
+#endif
+.It Li "comment [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Skip leading comments in files.
+#endif
+#ifdef REFERENCE
+If the first non-empty line of the file begins with the string
+.Dq \&/\&* ,
+this option causes
+.Nm \&vi
+to skip to the end of that C comment (probably a terribly boring
+legal notice) before displaying the file.
+#endif
+.It Li "directory, dir [environment variable TMPDIR, or /tmp]"
+#ifdef MANUAL
+The directory where temporary files are created.
+#endif
+#ifdef REFERENCE
+The directory where temporary files are created.
+The environmental variable
+.Ev TMPDIR
+is used as the default value if it exists, otherwise
+.Pa /tmp
+is used.
+#endif
+.It Li "edcompatible, ed [off]"
+#ifdef MANUAL
+Modify the behavior of certain suffices for the
+.Nm ex
+.Sy substitute
+command.
+#endif
+#ifdef REFERENCE
+This option causes the presence or absence of
+.Sy \&g
+and
+.Sy \&c
+suffixes on
+.Sy substitute
+commands to be remembered,
+and to be toggled by repeating the suffices.
+The suffix
+.Sy \&r
+makes the substitution be as in the
+.Sy \&~
+command, instead of like the
+.Sy \&&
+command.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "errorbells, eb [off]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Precede error messages with a bell.
+#endif
+#ifdef REFERENCE
+Causes
+.Nm \&ex
+error messages to be preceded by a bell.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "exrc, ex [off]"
+#ifdef MANUAL
+Never read startup files in the local directory.
+#endif
+#ifdef REFERENCE
+If this option is turned off in the system or $HOME startup files,
+the local startup files are never read (unless they are the same
+as the system or $HOME startup files).
+Turning it on has no effect, i.e. the normal checks for local startup
+files are performed, regardless.
+See the STARTUP INFORMATION section for more information.
+#endif
+.It Li "extended [off]"
+#ifdef MANUAL
+Regular expressions are extended (i.e.
+.Xr egrep 1
+style) expressions.
+#endif
+#ifdef REFERENCE
+This option causes all regular expressions to be treated as POSIX
+1003.2 extended regular expressions (which are similar to historic
+.Xr egrep 1
+style expressions).
+#endif
+.It Li "flash [on]"
+#ifdef MANUAL
+Flash the screen instead of beeping the keyboard on error.
+#endif
+#ifdef REFERENCE
+This option causes the screen to flash instead of beeping the keyboard,
+on error, if the terminal has the capability.
+#endif
+.It Li "hardtabs, ht [8]"
+#ifdef MANUAL
+Set the spacing between hardware tab settings.
+#endif
+#ifdef REFERENCE
+This option defines the spacing between hardware tab settings, i.e.
+the tab expansion done by the operating system and/or the terminal
+itself.
+As
+.Nm nex/nvi
+never writes tabs to the terminal, unlike historic versions of
+.Nm ex/vi ,
+this option does not currently have any affect.
+#endif
+.It Li "ignorecase, ic [off]"
+#ifdef MANUAL
+Ignore case differences in regular expressions.
+#endif
+#ifdef REFERENCE
+This option causes regular expressions, both in
+.Nm \&ex
+commands and in searches,
+to be evaluated in a case-insensitive manner.
+#endif
+.It Li "keytime [6]"
+The 10th's of a second
+.Nm ex/vi
+waits for a subsequent key to complete a key mapping.
+.It Li "leftright [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Do left-right scrolling.
+#endif
+#ifdef REFERENCE
+This option causes the screen to be scrolled left-right to view
+lines longer than the screen, instead of the traditional
+.Nm \&vi
+screen interface which folds long lines at the right-hand margin
+of the terminal.
+#endif
+.It Li "lines, li [24]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Set the number of lines in the screen.
+#endif
+#ifdef REFERENCE
+The number of lines in the screen.
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev LINES .
+See the Screen Sizing section for more information.
+#endif
+.It Li "lisp [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Modify various search commands and options to work with Lisp.
+#endif
+#ifdef REFERENCE
+This option changes the behavior of the
+.Nm \&vi
+.Sy \&( ,
+.Sy \&) ,
+.Sy \&{ ,
+.Sy \&} ,
+.Sy \&[[
+and
+.Sy \&]]
+commands to match the Lisp language.
+Also, the
+.Sy autoindent
+option's behavior is changed to be appropriate for Lisp.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "list [off]"
+#ifdef MANUAL
+Display lines in an unambiguous fashion.
+#endif
+#ifdef REFERENCE
+This option causes lines to be displayed in an unambiguous fashion.
+Specifically, tabs are displayed as control characters, i.e.
+.Dq \&^I ,
+and the ends of lines are marked with a
+.Dq \&$
+character.
+#endif
+.It Li "magic [on]"
+#ifdef MANUAL
+Treat certain characters specially in regular expressions.
+#endif
+#ifdef REFERENCE
+This option is on by default.
+Turning the
+.Sy magic
+option off causes all regular expression characters except for
+.Dq \&^
+and
+.Dq \&$ ,
+to be treated as ordinary characters.
+To re-enable characters individually, when the
+.Sy magic
+option is off,
+precede them with an
+.Dq \&\e .
+See the REGULAR EXPRESSIONS AND REPLACEMENT STRINGS section for
+more information.
+#endif
+.It Li "matchtime [7]"
+.Nm \&Vi
+only.
+The 10th's of a second
+.Nm ex/vi
+pauses on the matching character when the
+.Sy showmatch
+option is set.
+.It Li "mesg [on]"
+#ifdef MANUAL
+Permit messages from other users.
+#endif
+#ifdef REFERENCE
+This option allows other users to contact you using the
+.Xr talk 1
+and
+.Xr write 1
+utilities, while you are editing.
+.Nm Ex/vi
+does not turn message on, i.e. if messages were turned off when the
+editor was invoked, they will stay turned off.
+This option only permits you to disallow messages for the edit session.
+See the
+.Xr mesg 1
+utility for more information.
+#endif
+.It Li "modelines, modeline [off]"
+#ifdef MANUAL
+Read the first and last few lines of each file for
+.Nm ex
+commands.
+#endif
+#ifdef REFERENCE
+If the
+.Sy modelines
+option is set,
+.Nm ex/vi
+has historically scanned the first and last five lines of each file as
+it is read for editing, looking for any
+.Nm \&ex
+commands that have been placed in those lines.
+After the startup information has been processed, and before the user
+starts editing the file, any commands embedded in the file are executed.
+Commands are recognized by the letters
+.Dq \&e
+or
+.Dq \&v
+followed by
+.Dq \&x
+or
+.Dq \&i ,
+at the beginning of a line or following a tab or space character,
+and followed by a
+.Dq \&: ,
+an
+.Nm \&ex
+command, and another
+.Dq \&: .
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+#endif
+.br
+.Em "This option will never be implemented."
+.It Li "number, nu [off]"
+Precede each line displayed with its current line number.
+.It Li "open [on]"
+.Nm \&Ex
+only.
+If this option is not set, the
+.Sy open
+and
+.Sy visual
+commands are disallowed.
+.It Li "optimize, opt [on]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Optimize text throughput to dumb terminals.
+#endif
+#ifdef REFERENCE
+Throughput of text is expedited by setting the terminal to no do automatic
+carriage returns when printing more than one (logical) line of output,
+greatly speeding output on terminals without addressable cursors when text
+with leading white space is printed.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "paragraphs, para [IPLPPPQPP LIpplpipbp]"
+.Nm \&Vi
+only.
+Define additional paragraph boundaries for the
+.Sy \&{
+and
+.Sy \&}
+commands.
+#ifdef REFERENCE
+The value of this option must be a character string consisting
+of zero or more character pairs.
+.Pp
+In the text to be edited, the character string <newline>.<char-pair>,
+(where <char-pair> is one of the character pairs in the option's value)
+defines a paragraph boundary.
+For example, if the option were set to
+.Dq "LaA ##" ,
+then all of the following additional paragraph boundaries would be
+recognized:
+.Bd -literal -offset indent -compact
+<newline>.La
+<newline>.A<space>
+<newline>.##
+.Ed
+#endif
+.It Li "prompt [on]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Display a command prompt.
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&ex
+to prompt for command input with a
+.Dq \&:
+character; when it's not set, no prompt is displayed.
+#endif
+.It Li "readonly, ro [off]"
+#ifdef MANUAL
+Mark the file as read-only.
+#endif
+#ifdef REFERENCE
+This option causes a force flag to be required to attempt to write
+the file back to the original file name.
+Setting this option is equivalent to using the
+.Fl R
+command line option, or editing a file which lacks write permission.
+#endif
+.It Li "recdir [/var/tmp/vi.recover]"
+The directory where recovery files are stored.
+.It Li "redraw, re [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Simulate an intelligent terminal on a dumb one.
+#endif
+#ifdef REFERENCE
+The editor simulates (using great amounts of output), an intelligent
+terminal on a dumb terminal (e.g. during insertions in visual mode
+the characters to the right of the cursor are refreshed as each input
+character is typed).
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "remap [on]"
+#ifdef MANUAL
+Remap keys until resolved.
+#endif
+#ifdef REFERENCE
+If this option is set,
+it's possible to define macros in terms of other macros.
+Otherwise, each key is only remapped up to one time.
+For example, if
+.Dq \&A
+is mapped to
+.Dq \&B ,
+and
+.Dq \&B
+is mapped to
+.Dq \&C ,
+The keystroke
+.Dq \&A
+will be mapped to
+.Dq \&C
+if
+.Sy remap
+is set, and to
+.Dq \&B
+if it is not set.
+#endif
+.It Li "remapmax [on]"
+#ifdef MANUAL
+Limit the number of times a key may be remapped.
+#endif
+#ifdef REFERENCE
+If this option is set, a key may only be remapped 50 times.
+If it is not set, a key may be remapped an infinite number of times,
+and the editor can be placed into infinite loops.
+#endif
+.It Li "report [5]"
+#ifdef MANUAL
+Set the number of lines about which the editor reports changes.
+#endif
+#ifdef REFERENCE
+Set the threshold of the number of lines that need to be changed
+before a message will be displayed to the user.
+The value is the largest value about which the editor is silent,
+i.e. by default, 6 lines must change before the user is notified.
+#endif
+.It Li "ruler [off]"
+.Nm \&Vi
+only.
+Display a row/column ruler on the colon command line.
+.It Li "scroll, scr [window / 2]"
+#ifdef MANUAL
+Set the number of lines scrolled.
+#endif
+#ifdef REFERENCE
+Set the number of lines scrolled by the
+.Nm \&vi
+commands
+.Sy \&^D
+and
+.Sy \&^U .
+.Pp
+Historically, the
+.Nm ex
+.Sy z
+command, when specified without a count, used two times the size of the
+scroll value; the POSIX 1003.2 standard specified the window size, which
+is a better choice.
+#endif
+.It Li "sections, sect [NHSHH HUnhsh]"
+.Nm \&Vi
+only.
+Define additional section boundaries for the
+.Sy \&[[
+and
+.Sy \&]]
+commands.
+#ifdef REFERENCE
+The
+.Sy sections
+option should be set to a character string consisting of zero or
+more character pairs.
+In the text to be edited, the character string <newline>.<char-pair>,
+(where <char-pair> is one of the character pairs in the option's value),
+defines a section boundary in the same manner that
+.Sy paragraph
+option boundaries are defined.
+#endif
+.It Li "shell, sh [environment variable SHELL, or /bin/sh]"
+Select the shell used by the editor.
+#ifdef REFERENCE
+The specified path is the pathname of the shell invoked by the
+.Nm \&vi
+.Sy \&!
+shell escape command and by the
+.Nm \&ex
+.Sy shell
+command.
+This program is also used to resolve any shell meta-characters in
+.Nm \&ex
+commands.
+#endif
+.It Li "shiftwidth, sw [8]"
+Set the autoindent and shift command indentation width.
+#ifdef REFERENCE
+This width is used by the
+.Sy autoindent
+option and by the
+.Sy \&< ,
+.Sy \&> ,
+and
+.Sy shift
+commands.
+#endif
+.It Li "showdirty [off]"
+.Nm \&Vi
+only.
+Display an asterisk on the colon command line if the file has been modified.
+.It Li "showmatch, sm [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Note matching
+.Dq \&{
+and
+.Dq \&(
+for
+.Dq \&}
+and
+.Dq \&)
+characters.
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&vi ,
+when a
+.Dq \&}
+or
+.Dq \&)
+is entered, to briefly move the cursor the matching
+.Dq \&{
+or
+.Dq \&( .
+See the
+.Sy matchtime
+option for more information.
+#endif
+.It Li "showmode [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Display the current editor mode (command or input).
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&vi
+to display the strings
+.Dq Command
+or
+.Dq Input
+on the colon command line, based on the current mode of the editor.
+#endif
+.It Li "sidescroll [16]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Set the amount a left-right scroll will shift.
+#endif
+#ifdef REFERENCE
+Sets the number of columns that are shifted to the left or right,
+when
+.Nm \&vi
+is doing left-right scrolling and the left or right margin is
+crossed.
+See the
+.Sy leftright
+option for more information.
+#endif
+.It Li "slowopen, slow [off]"
+#ifdef MANUAL
+Delay display updating during text input.
+#endif
+#ifdef REFERENCE
+This option affects the display algorithm used by
+.Nm \&vi ,
+holding off display updating during input of new text to improve
+throughput when the terminal in use is slow and unintelligent.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "sourceany [off]"
+#ifdef MANUAL
+Read startup files not owned by the current user.
+#endif
+#ifdef REFERENCE
+If this option is turned on,
+.Nm \&vi
+historically read startup files that were owned by someone other than
+the editor user.
+See the STARTUP INFORMATION section for more information.
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+#endif
+.br
+.Em "This option will never be implemented."
+.It Li "tabstop, ts [8]"
+This option sets tab widths for the editor display.
+.It Li "taglength, tl [0]"
+#ifdef MANUAL
+Set the number of significant characters in tag names.
+#endif
+#ifdef REFERENCE
+This option sets the maximum number of characters that are considered
+significant in a tag name.
+Setting the value to 0 makes all of the characters in the tag name
+significant.
+#endif
+.It Li "tags, tag [tags /var/db/libc.tags /sys/kern/tags]"
+#ifdef MANUAL
+Set the list of tags files.
+#endif
+#ifdef REFERENCE
+Sets the list of tags files, in search order,
+which are used when the editor searches for a tag.
+#endif
+.It Li "term, ttytype, tty [environment variable TERM]"
+Set the terminal type.
+#ifdef REFERENCE
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev TERM .
+#endif
+.It Li "terse [off]"
+This option has historically made editor messages less verbose.
+It has no effect in this implementation.
+#ifdef REFERENCE
+See the
+.Sy verbose
+option for more information.
+#endif
+.It Li "timeout, to [on]"
+#ifdef MANUAL
+Time out on keys which may be mapped.
+#endif
+#ifdef REFERENCE
+If this option is set,
+.Nm ex/vi
+waits for a specific period for a subsequent key to complete a key
+mapping (see the
+.Sy keytime
+option).
+If the option is not set, the editor waits until enough keys are
+entered to resolve the ambiguity, regardless of how long it takes.
+#endif
+.It Li "ttywerase [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Select an alternate erase algorithm.
+#endif
+#ifdef REFERENCE
+This option changes how
+.Nm \&vi
+does word erase during text input.
+If this option is set, text is broken up into two classes,
+blank characters and non-blank characters.
+Changing from one class to another marks the end of a word.
+#endif
+.It Li "verbose [off]"
+.NM \&Vi
+only.
+#ifdef MANUAL
+Display an error message for every error.
+#endif
+#ifdef REFERENCE
+.Nm \&Vi
+historically bells the terminal for many obvious mistakes, e.g. trying
+to move past the left-hand margin, or past the end of the file.
+If this option is set, an error message is displayed for all errors.
+#endif
+.It Li "w300 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is less than 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "w1200 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is equal to 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "w9600 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is greater than 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "warn [on]"
+.Nm \&Ex
+only.
+This option causes a warning message to the terminal if the file has
+been modified, since it was last written, before a
+.Sy \&!
+command.
+.It Li "window, w, wi [environment variable LINES]"
+#ifdef MANUAL
+Set the window size for the screen.
+#endif
+#ifdef REFERENCE
+This option determines the default number of lines in a screenful,
+as written by the
+.Sy \&z
+command.
+It also determines the number of lines scrolled by the
+.Nm \&vi
+commands
+.Sy \&^F
+and
+.Sy \&^B .
+The value of window can be unrelated to the real screen size,
+although it starts out as the number of lines on the screen (see
+the SCREEN SIZING section).
+Setting the value of the
+.Sy window
+option is the same as using the
+.Fl w
+command line option.
+.Pp
+If the value of
+.Sy window
+(as set by the
+.Sy window ,
+.Sy w300 ,
+.Sy w1200
+or
+.Sy w9600
+options) is smaller than the actual size of the screen, large screen
+movements will result in displaying only that smaller number of lines
+on the screen.
+(Further movements in that same area will result in the screen being
+filled.)
+This can provide a performance improvement when viewing different
+places in one or more files over a slow link.
+#endif
+.It Li "wrapmargin, wm [0]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Break lines automatically when they reach the right-hand margin.
+#endif
+#ifdef REFERENCE
+If the value of wrapmargin is non-zero,
+.Nm \&vi
+will break lines, that are more than that number of characters long,
+into two lines at the blank character closest to the value.
+If wrapmargin is 0,
+or if there is no blank character upon which to break the line,
+the line will not be broken.
+#endif
+.It Li "wrapscan, ws [on]"
+#ifdef MANUAL
+Set searches to wrap around the end or beginning of the file.
+#endif
+#ifdef REFERENCE
+This option causes searches to wrap around the end or the beginning
+of the file, and back to the starting point.
+Otherwise, the end or beginning of the file terminates the search.
+#endif
+.It Li "writeany, wa [off]"
+#ifdef MANUAL
+Turn off file-overwriting checks.
+#endif
+#ifdef REFERENCE
+If this option is set, file-overwriting checks that would usually be
+made before the
+.Sy write
+and
+.Sy xit
+commands, or before an automatic write (see the
+.Sy autowrite
+option), are not made.
+This allows a write to any file, provided the file permissions allow it.
+#endif
+.El
diff --git a/usr.bin/vi/docs/spell.ok b/usr.bin/vi/docs/spell.ok
new file mode 100644
index 000000000000..fce3673fac73
--- /dev/null
+++ b/usr.bin/vi/docs/spell.ok
@@ -0,0 +1,163 @@
+Amir
+Autoprint
+BRE's
+Bostic
+Ds
+ERE's
+EXINIT
+Englar
+Ev
+Fa
+Fl
+HUnhsh
+IPLPPPQPP
+Kirkendall
+LIpplpipbp
+LaA
+Li
+Makefiles
+NEXINIT
+NHSHH
+Nex
+Nvi
+OS
+POSIX
+PostScript
+RE's
+README
+SIGHUP
+SIGWINCH
+Se
+Std1003.2
+Sy
+TANDARDS
+TIOCGWINSZ
+TMPDIR
+Todo
+USD.doc
+UUNET
+Vx
+XXCOLUMNS
+XXXX
+ags
+ai
+altwerase
+autoindent
+autoprint
+autowrite
+aw
+bf
+bostic
+bugs.current
+carat
+changelog
+cmd
+creens
+cs.berkeley.edu
+db
+dbopen
+def
+di
+dir
+docs
+eFlRsv
+eFlRv
+eb
+edcompatible
+elvis
+email
+enum
+errorbells
+esc
+exrc
+exu
+fi
+ftp.cs.berkeley.edu
+ftp.uu.net
+gdb
+gdb.script
+gzip'd
+hangup
+hardtabs
+ht
+ic
+ifdef
+ignorecase
+ious
+keystroke
+keystrokes
+keytime
+leftright
+li
+libc.tags
+lowercase
+matchtime
+meta
+modeful
+modeline
+modelines
+nex
+nexrc
+nomagic
+nvi
+nvi.tar.Z
+nvi.tar.z
+para
+pathname
+rc.local
+readonly
+recdir
+recover.XXXX
+recover.c
+ript
+ro
+roff
+sc
+scr
+screeen
+set.opt.roff
+shiftwidth
+showmatch
+showmode
+sidescroll
+slowopen
+sm
+sourceany
+sp
+spell.ok
+svi
+sw
+tabstop
+taglength
+tagpop
+tagtop
+th
+tl
+tmp
+ts
+ttytype
+ttywerase
+ucb
+uffers
+uppercase
+uunet
+var
+vglobal
+vi.0.ps
+vi.0.txt
+vi.1
+vi.XXXX
+vi.exrc
+vi.recover
+virecovery
+viu
+wa
+wi
+wm
+wrapmargin
+wrapscan
+writeany
+ws
+xaw
+xit
+yy
diff --git a/usr.bin/vi/docs/tutorial/vi.advanced b/usr.bin/vi/docs/tutorial/vi.advanced
new file mode 100644
index 000000000000..f757ad19c44a
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.advanced
@@ -0,0 +1,1458 @@
+Section 26: Index to the rest of the tutorial
+
+The remainder of the tutorial can be perused at your leisure. Simply find the
+topic of interest in the following list, and {/Section xx:/^M} to get to the
+appropriate section. (Remember that ^M means the return key)
+
+The material in the following sections is not necessarily in a bottom up
+order. It should be fairly obvious that if a section mentions something with
+which you are not familiar, say, buffers, you might {/buffer/^M} followed by
+several {n} to do a keyword search of the file for more details on that item.
+Another point to remember is that commands are surrounded by curly-braces and
+can therefore be found rather easily. To see where, say, the X command is
+used try {/{X}/^M}. Subsequent {n} will show you other places the command was
+used. We have tried to maintain the convention of placing the command letter
+surrounded by curly-braces on the section line where that command is
+mentioned.
+
+Finally, you should have enough 'savvy' at this point to be able to do your
+own experimentation with commands without too much hand-holding on the part of
+the tutorial. Experimentation is the best way to learn the effects of the
+commands.
+
+ Section Topic - description
+ ------- -------------------
+(Sections 1 through 25 are located in the file vi.beginner.)
+ 1 introduction: {^F} {ZZ}
+ 2 introduction (con't) and positioning: {^F} {^B}
+ 3 introduction (con't) and positioning: {^F} {^B}
+ 4 positioning: {^F} {^B} ^M (return key)
+ 5 quitting: {:q!} ^M key
+ 6 marking, cursor and screen positioning: {m} {G} {'} {z}
+ 7 marking, cursor and screen positioning: {m} {G} {'} {z}
+ 8 marking, cursor and screen positioning: {z} {m} {'}
+ 9 marking and positioning: {m} {''}
+ 10 line positioning: {^M} {-}
+ 11 scrolling with {^M}
+ 12 scrolling with {-} and screen adjustment {z}
+ 13 notes on use of tutorial
+ 14 other scrolling and postioning commands: {^E} {^Y} {^D} {^U}
+ 15 searching: {/ .. /^M}
+ 16 searching: {? .. ?^M} {n} (in search strings ^ $)
+ 17 searching: \ and magic-characters in search strings
+ 18 colon commands, exiting: {:} {ZZ}
+ 19 screen positioning: {H} {M} {L}
+ 20 character positioning: {w} {b} {0} {W} {B} {e} {E} {'} {`}
+ 21 cursor positioning: {l} {k} {j} {h}
+ 22 adding text: {i} {a} {I} {A} {o} {O} ^[ (escape key)
+ 23 character manipulation: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
+ 24 undo: {u} {U}
+ 25 review
+(The following sections are in this file.)
+ 26 Index to the rest of the tutorial ******** YOU ARE HERE *******
+ 27 discussion of repeat counts and the repeat command: {.}
+ 28 more on low-level character motions: {t} {T} {|}
+ 29 advanced correction operators: {d} {c}
+ 30 updating the screen: {^R}
+ 31 text buffers: {"}
+ 32 rearranging and duplicating text: {p} {P} {y} {Y}
+ 33 recovering lost lines
+ 34 advanced file manipulation with vi
+ 34.1 more than one file at a time: {:n}
+ 34.2 reading files and command output: {:r}
+ 34.3 invoking vi from within vi: {:e} {:vi}
+ 34.4 escaping to a shell: {:sh} {:!}
+ 34.5 writing parts of a file: {:w}
+ 34.6 filtering portions of text: {!}
+ 35 advanced searching: magic patterns
+ 36 advanced substitution: {:s}
+ 37 advanced line addressing: {:p} {:g} {:v}
+ 38 higher level text objects and nroff: ( ) { } [[ ]]
+ 39 more about inserting text
+ 40 more on operators: {d} {c} {<} {>} {!} {=} {y}
+ 41 abbreviations: {:ab}
+ 42 vi's relationship with the ex editor: {:}
+ 43 vi on hardcopy terminals and dumb terminals: open mode
+ 44 options: {:set} {setenv EXINIT}
+ 44.1 autoindent
+ 44.2 autoprint
+ 44.3 autowrite
+ 44.4 beautify
+ 44.5 directory
+ 44.6 edcompatible
+ 44.7 errorbells
+ 44.8 hardtabs
+ 44.9 ignorecase
+ 44.10 lisp
+ 44.11 list
+ 44.12 magic
+ 44.13 mesg
+ 44.14 number
+ 44.15 open
+ 44.16 optimize
+ 44.17 paragraphs
+ 44.18 prompt
+ 44.19 readonly
+ 44.20 redraw
+ 44.21 remap
+ 44.22 report
+ 44.23 scroll
+ 44.24 sections
+ 44.25 shell
+ 44.26 shiftwidth
+ 44.27 showmatch
+ 44.28 slowopen
+ 44.29 tabstop
+ 44.30 tags
+ 44.31 taglength
+ 44.32 term
+ 44.33 terse
+ 44.34 timeout
+ 44.35 ttytype
+ 44.36 warn
+ 44.37 window
+ 44.38 wrapscan
+ 44.39 wrapmargin
+ 44.40 writeany
+ 44.41 w300, w1200, w9600
+
+Section 27: repetition counts and the repeat command {.}
+
+Most vi commands will use a preceding count to affect their behavior in some
+way. We have already seen how {3x} deletes three characters, and {22G} moves
+us to line 22 of the file. For almost all of the commands, one can survive by
+thinking of these leading numbers as a 'repeat count' specifying that the
+command is to be repeated so many number of times.
+
+Other commands use the repeat count slightly differently, like the {G} command
+which use it as a line number.
+
+For example:
+
+{3^D} means scroll down in the file three lines. Subsequent {^D} OR {^U} will
+scroll only three lines in their respective directions!
+
+{3z^M} says put line three of the file at the top of the screen, while {3z.}
+says put line three as close to the middle of the screen as possible.
+
+{50|} moves the cursor to column fifty in the current line.
+
+{3^F} says move forward 3 screenfulls. This is a repetition count. The
+documents advertise that {3^B} should move BACK three screenfulls, but I
+can't get it to work.
+
+Position the cursor on some text and try {3r.}. This replaces three characters
+with '...'. However, {3s.....^[} is the same as {3xi.....^[}.
+
+Try {10a+----^[}.
+
+A very useful instance of a repetition count is one given to the '.' command,
+which repeats the last 'change' command. If you {dw} and then {3.}, you will
+delete first one and then three words. You can then delete two more words with
+{2.}. If you {3dw}, you will delete three words. A subsequent {.} will delete
+three more words. But a subsequent {2.} will delete only two words, not three
+times two words.
+
+Caveat: The author has noticed that any repetition count with {^B} will NOT
+work: indeed, if you are at the end of your file and try {3^B} sufficiently
+often, the editor will hang you in an infinite loop. Please don't try it:
+take my word for it.
+
+Section 28: {t} {T} {|}
+
+Position the cursor on line 13 below:
+
+Line 13: Four score and seven years ago, our forefathers brought ...
+
+Note that {fv} moves the cursor on/over the 'v' in 'seven'. Do a {0} to return
+to the beginning of the line and try a {tv}. The cursor is now on/over the
+first 'e' in 'seven'. The {f} command finds the next occurrence of the
+specified letter and moves the cursor to it. The {t} command finds the
+specified letter and moves the cursor to the character immediately preceding
+it. {T} searches backwards, as does {F}.
+
+Now try {60|}: the cursor is now on the 'o' in 'brought', which is the
+sixtieth character on the line.
+
+Section 29: {d} {c}
+
+Due to their complexity we have delayed discussion of two of the most powerful
+operators in vi until now. Effective use of these operators requires more
+explanation than was deemed appropriate for the first half of the tutorial.
+
+{d} and {c} are called operators instead of commands because they consist of
+three parts: a count specification or a buffer specification (see section
+#BUFFERS), the {d} or {c}, and the object or range description. We will not
+discuss buffers at this stage, but will limit ourselves to count
+specifications. Examples speak louder than words: position the cursor at the
+beginning of line 14:
+
+Line 14: Euclid alone has looked on beauty bear.
+
+Obviously, there is something wrong with this quotation. Type {2fb} to
+position the cursor on the 'b' of 'bear'. Now, type {cwbare^[}
+and observe the results. The {cw} specifies that the change command {c} is to
+operate on a word object. More accurately, it specifies that the range of the
+change command includes the next word.
+
+Position the cursor on the period in Line 14. (one way is to use {f.})
+Now, type {cbbeast^[}. This specifies the range of the change command to be the
+previous word (the 'b' reminiscent of the {b} command). If we had wished to
+delete the word rather than change it, we would have used the {d} operator,
+rather than the {c} operator.
+
+Position the cursor at the beginning of the line with {0}. Type
+{d/look/^M}. The search string specified the range of the delete.
+Everything UP TO the word 'looking' was deleted from the line.
+
+In general, almost any command that would move the cursor will specify a range
+for these commands. The most confusing exception to this rule is when {dd} or
+{cc} is entered: they refer to the whole line. Following is a summary of the
+suffixes (suffices? suffici?) and the ranges they specify:
+
+ suffix will delete{d}/change{c}
+ ------ ------------------------
+ ^[ cancels the command
+ w the word to the right of the cursor
+ W ditto, but ignoring punctuation
+ b the word to the left of the cursor
+ B ditto, but ignoring punctuation
+ e see below.
+ E ditto
+ (space) a character
+ $ to the end of the line
+ ^ to the beginning of the line
+ / .. / up to, but not including, the string
+ ? .. ? back to and including the string
+ fc up to and including the occurrence of c
+ Fc back to and including the occurrence of c
+ tc up to but not including the occurrence of c
+ Tc back to but not including the occurrence of c
+ ^M TWO lines (that's right: two)
+ (number)^M that many lines plus one
+ (number)G up to and including line (number)
+ ( the previous sentence if you are at the beginning of
+ the current sentence, or the current sentence up to where
+ you are if you are not at the beginning of the current
+ sentence. Here, 'sentence' refers to the intuitive
+ notion of an English sentence, ending with '!', '?',
+ or '.' and followed by an end of line or two spaces.
+ ) the rest of the current sentence
+ { analogous to '(', but in reference to paragraphs:
+ sections of text surrounded by blank lines
+ } analogous to ')', but in reference to paragraphs
+ [[ analogous to '(', but in reference to sections
+ ]] analogous to ')', but in reference to sections
+ H the first line on the screen
+ M the middle line on the screen
+ L the last line on the screen
+ 3L through the third line from the bottom of the screen
+ ^F forward a screenful
+ ^B backward a screenful
+ :
+ : etc. etc. etc.
+
+This list is not exhaustive, but it should be sufficient to get the idea
+across: after the {c} or {d} operator, you can specify a range with another
+move-the-cursor command, and that is the region of text over which the command
+will be effective.
+
+Section 30: updating the screen {^R}
+
+Vi tries to be very intelligent about the type of terminal you are working on
+and tries to use the in-terminal computing power (if any) of your terminal.
+Also if the terminal is running at a low baud rate (say 1200 or below), vi sets
+various parameters to make things easier for you. For example, if you were
+running on a 300 baud terminal (that's 30 characters per second transmission
+rate) not all 24 lines of the screen would be used by vi. In addition, there
+is a large portion of the editor keeping track of what your screen currently
+looks like, and what it would look like after a command has been executed. Vi
+then compares the two, and updates only those portions of the screen that have
+changed.
+
+Furthermore, some of you may have noticed (it depends on your terminal) that
+deleting lines or changing large portions of text may leave some lines on the
+screen looking like:
+@
+meaning that this line of the screen does not correspond to any line in your
+file. It would cost more to update the line than to leave it blank for the
+moment. If you would like to see your screen fully up-to-date with the
+contents of your file, type {^R}.
+
+To see it in action, delete several lines with {5dd}, type {^R}, and then type
+{u} to get the lines back.
+
+Here is as good a place as any to mention that if the editor is displaying the
+end of your file, there may be lines on the screen that look like:
+~
+indicating that that screen line would not be affected by {^R}. These lines
+simply indicate the end of the file.
+
+Section 31: text buffers {"}
+
+Vi gives you the ability to store text away in "buffers". This feature is very
+convenient for moving text around in your file. There are a total of thirty-
+five buffers available in vi. There is the "unnamed" buffer that is used by all
+commands that delete text, including the change operator {c}, the substitute
+and replace commands {s} and {r}, as well as the delete operator {d} and delete
+commands {x} and {X}. This buffer is filled each time any of these commands
+are used. However, the undo command {u} has no effect on the unnamed buffer.
+
+There are twenty-six buffers named 'a' through 'z' which are available for the
+user. If the name of the buffer is capitalized, then the buffer is not
+overwritten but appended to. For example, the command {"qdd} will delete one
+line and store that line in the 'q' buffer, destroying the previous contents of
+the buffer. However, {"Qdd} will delete one line of text and append that line
+to the current contents of the 'q' buffer.
+
+Finally, there are nine buffers named '1' through '9' in which the last nine
+deletes are stored. Buffer 1 is the default buffer for the modify commands and
+is sometimes called the unnamed buffer.
+
+To reference a specific buffer, use the double-quote command {"} followed by
+the name of the buffer. The next two sections show how buffers can be used to
+advantage.
+
+Section 32: rearranging and duplicating text: {y} {Y} {p} {P}
+
+Position yourself on line 15 below and {z^M}:
+
+Line 15: A tree as lovely as a poem ...
+Line 16: I think that I shall never see
+
+Type {dd}. Line 15 has disappeared and been replaced with the empty line (one
+with the single character @ on it) or (again depending on your terminal) Line
+16 has moved up and taken its place. We could recover Line 15 with an undo
+{u} but that would simply return it to its original location. Obviously, the
+two lines are reversed, so we want to put line 15 AFTER line 16. This is
+simply done with the put command {p}, which you should type now. What has
+happened is that {dd} put Line 15 into the unnamed buffer, and the {p} command
+retrieved the line from the unnamed buffer.
+
+Now type {u} and observe that Line 15 disappears again (the put was undone
+without affecting the unnamed buffer). Type {P} and see that the capital {P}
+puts the line BEFORE the cursor.
+
+To get Line 15 where it belongs again type {dd}{p}.
+
+Also in Line 15 note that the words 'tree' and 'poem' are reversed. Using the
+unnamed buffer again: {ft}{dw}{ma}{fp}{P}{w}{dw}{`aP} will set things aright
+(note the use of the reverse quote).
+
+The put commands {p} and {P} do not affect the contents of the buffer.
+Therefore, multiple {p} or {P} will put multiple copies of the unnamed buffer
+into your file.
+
+Experiment with {d} and {p} on words, paragraphs, etc. Whatever {d}
+deletes, {p} can put.
+
+Position the cursor on Line 17 and {z^M}:
+
+Line 17: interest apple cat elephant boy dog girl hay farmer
+
+Our task is to alphabetize the words on line 17. With the named buffers (and a
+contrived example) it is quite easy:
+
+{"idw}{"adw}{"cdw}{"edw}{"bdw}{"ddw}{"gdw}{"hdw}{"fdw}
+
+stores each of the words in the named buffer corresponding to the first letter
+of each of the words ('interest' goes in buffer "i, 'apple' goes in buffer "a,
+etc.). Now to put the words in order type:
+
+{"ap$}{"bp$}{"cp$}{"dp$}{"ep$}{"fp$}{"gp$}{"hp$}{"ip$}
+
+Notice that, because 'farmer' was at the end of the line, {dw} did not include
+a space after it, and that, therefore, there is no space between 'farmer' and
+'girl'. This is corrected with {Fg}{i ^[}.
+
+This example could have been done just as easily with lines as with
+words.
+
+You do not have to delete the text in order to put it into a buffer. If all
+you wish to do is to copy the text somewhere else, don't use {d}, rather use
+the yank commands {y} or {Y}. {y} is like {d} and {c} - an operator rather
+than a command. It, too, takes a buffer specification and a range
+specification. Therefore, instead of {dw}{P} to load the unnamed buffer with a
+word without deleting the word, use {yw} (yank a word).
+
+{Y} is designed yank lines, and not arbitrary ranges. That is, {Y} is
+equivalent to {yy} (remember that operators doubled means the current line),
+and {3Y} is equivalent to {3yy}.
+
+If the text you yank or modify forms a part of a line, or is an object such as
+a sentence which partially spans more than one line, then when you put the text
+back, it will be placed after the cursor (or before if you use {P}). If the
+yanked text forms whole lines, they will be put back as whole lines, without
+changing the current line. In this case, the put acts much like the {o} or {O}
+command.
+
+The named buffers "a through "z are not affected by changing edit files.
+However, the unnamed buffer is lost when you change files, so to move text from
+one file to another you should use a named buffer.
+
+Section 33: recovering lost lines
+
+Vi also keeps track of the last nine deletes, whether you ask for it or not.
+This is very convenient if you would like to recover some text that was
+accidentally deleted or modified. Position the cursor on line 18 following,
+and {z^M}.
+
+
+Line 18: line 1
+Line 19: line 2
+Line 20: line 3
+Line 21: line 4
+Line 22: line 5
+Line 23: line 6
+Line 24: line 7
+Line 25: line 8
+Line 26: line 9
+Type {dd} nine times: now don't cheat with {9dd}! That is totally different.
+
+The command {"1p} will retrieve the last delete. Furthermore, when the
+numbered buffers are used, the repeat-command command {.} will increment the
+buffer numbers before executing, so that subsequent {.} will recover all nine
+of the deleted lines, albeit in reverse order. If you would like to review the
+last nine deletes without affecting the buffers or your file, do an undo {u}
+after each put {p} and {.}:
+
+{"1p}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}
+
+will show you all the buffers and leave them and your file intact.
+
+If you had cheated above and deleted the nine lines with {9dd}, all nine lines
+would have been stored in both the unnamed buffer and in buffer number 1.
+(Obviously, buffer number 1 IS the unnamed buffer and is just the default
+buffer for the modify commands.)
+
+Section 34: advanced file manipulation: {:r} {:e} {:n} {:w} {!} {:!}
+
+We've already looked at writing out the file you are editing with the
+{:w} command. Now let's look at some other vi commands to make editing
+more efficient.
+
+Section 34.1: more than one file at a time {:n} {:args}
+
+Many times you will want to edit more than one file in an editing session.
+Instead of entering vi and editing the first file, exiting, entering vi and
+editing the second, etc., vi will allow you to specify ALL files that you wish
+to edit on the invocation line. Therefore, if you wanted to edit file1 and
+file2:
+
+% vi file1 file2
+
+will set up file1 for editing. When you are done editing file one, write it
+out {:w^M} and then type {:n^M} to get the next file on the list. On large
+programming projects with many source files, it is often convenient just to
+specify all source files with, say:
+
+% vi *.c
+
+If {:n^M} brings in a file that does not need any editing, another {:n^M}
+will bring in the next file.
+
+If you have made changes to the first file, but decide to discard these changes
+and proceed to the next file, {:n!^M} forces the editor to discard the current
+contents of the editor.
+
+You can specify a new list of files after {:n}; e.g., {:n f1 f2 f3^M}. This
+will replace the current list of files (if any).
+
+You can see the current list of files being edited with {:args^M}.
+
+Section 34.2: reading files and command output: {:r}
+
+Typing {:r fname^M} will read the contents of file fname into the editor and
+put the contents AFTER the cursor line.
+
+Typing {:r !cmd^M} will read the output of the command cmd and place that
+output after the cursor line.
+
+Section 34.3: invoking vi from within vi: {:e} {:vi}
+
+To edit another file not mentioned on the invocation line, type {:e filename^M}
+or {:vi filename^M}. If you wish to discard the changes to the current file,
+use the exclamation point after the command, e.g. {:e! filename^M}.
+
+Section 34.4: escaping to a shell: {:sh} {:!} {^Z}
+
+Occasionally, it is useful to interrupt the current editing session to perform
+a UNIX task. However, there is no need to write the current file out, exit
+the editor, perform the task, and then reinvoke the editor on the same file.
+One thing to do is to spin off another process. If there are several UNIX
+commands you will need to execute, simply create another shell with {:sh^M}.
+At this point, the editor is put to sleep and will be reawakened when you log
+out of the shell.
+
+If it is a single command that you want to execute, type {:!cmd^M}, where cmd
+is the command that you wish to run. The output of the command will come to
+the terminal as normal, and will not be made part of your file. The message
+"[Hit return to continue]" will be displayed by vi after the command is
+finished. Hitting return will then repaint the screen. Typing another
+{:!cmd^M} at this point is also acceptable.
+
+However, there is a quicker, easier way: type {^Z}. Now this is a little
+tricky, but hang in there. When you logged into UNIX, the first program you
+began communicating with was a program that is called a "shell" (i.e. it 'lays
+over' the operating system protecting you from it, sort of like a considerate
+porcupine). When you got your first prompt on the terminal (probably a '%'
+character) this was the shell telling you to type your first command. When
+you typed {vi filename} for some file, the shell did not go away, it just went
+to sleep. The shell is now the parent of vi. When you type {^Z} the editor
+goes to sleep, the shell wakes up and says "you rang?" in the form of another
+prompt (probably '%'). At this point you are talking to the shell again and
+you can do anything that you could before including edit another file! (The
+only thing you can't do is log out: you will get the message "There are
+stopped jobs.")
+
+When your business with the shell is done, type {fg} for 'foreground' and the
+last process which you ^Z'd out of will be reawakened and the shell will go
+back to sleep. I will refer you to the documentation for the Berkeley shell
+'csh' for more information on this useful capability.
+
+Section 34.5: writing parts of a file: {:w}
+
+The {:w} command will accept a range specifier that will then write only a
+selected range of lines to a file. To write this section to a file, position
+the cursor on the section line (e.g. {/^Section 34.5:/^M}) and {z^M}. Now type
+{^G} to find out the line number (it will be something like "line 513"). Now
+{/^Section 34.6:/-1^M} to find the last line of this section, and {^G} to find
+its line number (it will be something like 542). To write out this section of
+text by itself to a separate file which we will call "sepfile", type
+{:510,542w sepfile^M}. If sepfile already exists, you will have to use the
+exclamation point: {:1147,1168w! sepfile^M} or write to a different, non-
+existent file.
+
+{:!cat sepfile^M} will display the file just written, and it should be the
+contents of this section.
+
+There is an alternate method of determining the line numbers for the write.
+{:set number^M} will repaint the screen with each line numbered. When the file
+is written and the numbers no longer needed, {:set nonumber^M} will remove the
+numbers, and {^R} will adjust the screen.
+
+Or, if you remember your earlier lessons about marking lines of text,
+mark the beginning and ending lines. Suppose we had used {ma} to mark the
+first line of the section and {mb} to mark the last. Then the command
+{:'a,'bw sepfile^M} will write the section into "sepfile". In general,
+you can replace a line number with the 'name' of a marked line (a single-quote
+followed by the letter used to mark the line)
+
+
+Section 34.6: filtering portions of text: {!}
+
+{!} is an operator like {c} and {d}. That is, it consists of a repetition
+count, {!}, and a range specifier. Once the {!} operator is entered in its
+entirety, a prompt will be given at the bottom of the screen for a UNIX
+command. The text specified by the {!} operator is then deleted and
+passed/filtered/piped to the UNIX command you type. The output of the UNIX
+command is then placed in your file. For example, place the cursor at the
+beginning of the following line and {z^M}:
+
+ls -l vi.tutorial
+********* marks the bottom of the output from the ls command **********
+
+Now type {!!csh^M}. The line will be replaced with the output from the ls
+command. The {u} command works on {!}, also.
+
+Here is an extended exercise to display some of these capabilities. When this
+tutorial was prepared, certain auxiliary programs were created to aid in its
+development. Of major concern was the formatting of sections of the tutorial
+to fit on a single screen, particularly the first few sections. What was
+needed was a vi command that would 'format' a paragraph; that is, fill out
+lines with as many words as would fit in eighty columns. There is no such vi
+command. Therefore, another method had to be found.
+
+Of course, nroff was designed to do text formatting. However, it produces a
+'page'; meaning that there may be many blank lines at the end of a formatted
+paragraph from nroff. The awk program was used to strip these blank lines from
+the output from nroff. Below are the two files used for this purpose: I refer
+you to documentation on nroff and awk for a full explanation of their function.
+Position the cursor on the next line and {z^M}.
+
+******** contents of file f **********
+#
+nroff -i form.mac | awk "length != 0 { print }"
+***** contents of file form.mac ******
+.na
+.nh
+.ll 79
+.ec 
+.c2 
+.cc 
+**************************************
+
+Determine the line numbers of the two lines of file f. They should be
+something like 574 and 575, although you better double check: this file is
+under constant revision and the line numbers may change inadvertently. Then
+{:574,575w f^M}. Do the same for the lines of file form.mac. They will be
+approximately 577 and 582. Then {:577,582w form.mac^M}. File f must have
+execute privileges as a shell file: {:!chmod 744 f^M}.
+
+Observe that this paragraph is
+rather ratty in appearance. With our newly created files we can
+clean it up dramatically. Position the cursor at the beginning
+of this paragraph and type the following sequence of
+characters
+(note that we must abandon temporarily our convention
+of curly braces since the command itself contains a curly brace - we
+will use square brackets for the nonce): [!}f^M].
+
+Here is a brief explanation of what has happened. By typing [!}f^M] we
+specified that the paragraph (all text between the cursor and the first blank
+line) will be removed from the edit file and piped to a UNIX program called
+"f". This is a shell command file that we have created. This shell file runs
+nroff, pipes its output to awk to remove blank lines, and the output from awk
+is then read back into our file in the place of the old, ratty paragraph. The
+file form.mac is a list of commands to nroff to get it to produce paragraphs
+to our taste (the right margin is not justified, the line is 79 characters
+long, words are not hyphenated, and three nroff characters are renamed to
+avoid conflict: note that in this file, the {^G} you see there is vi's display
+of the control-G character, and not the two separate characters ^ up-arrow and
+G upper-case g).
+
+This example was created before the existence of the fmt program. I now type
+[!}fmt^M] to get the same effect much faster. Actually, I don't type those
+six keys each time: I have an abbreviation (which see).
+
+Section 35: searching with magic patterns
+
+The documentation available for "magic patterns" (i.e. regular expressions) is
+very scanty. The following should explain this possibly very confusing feature
+of the editor. This section assumes that the magic option is on. To make
+sure, you might want to type {:set magic^M}.
+
+By "magic pattern" we mean a general description of a piece of text that the
+editor attempts to find during a search. Most search patterns consist of
+strings of characters that must be matched exactly, e.g. {/card/^M} searches
+for a specific string of four characters. Let us suppose that you have
+discovered that you consistently have mistyped this simple word as either ccrd
+or czrd (this is not so far-fetched for touch typists). You could {/ccrd/^M}
+and {n} until there are no more of this spelling, followed by {/czrd/^M} and
+{n} until there are no more of these. Or you could {/c.rd/^M} and catch all of
+them on the first pass. Try typing {/c.rd/^M} followed by several {n} and
+observe the effect.
+
+Line 27: card cord curd ceard
+
+When '.' is used in a search string, it has the effect of matching any single
+character.
+
+The character '^' (up-arrow) used at the beginning of a search string means
+the beginning of the line. {/^Line 27/^M} will find the example line above,
+while {/Line 27/^M} will find an occurrence of this string anywhere in the
+line.
+
+Similarly, {/ the$/^M} will find all occurrences of the word 'the' occurring
+at the end of a line. There are several of them in this file.
+
+Note that {:set nomagic^M} will turn off the special meaning of these magic
+characters EXCEPT for '^' and '$' which retain their special meanings at the
+beginning and end of a search string. Within the search string they hold no
+special meaning. Try {/\/ the$\//^M} and note that the dollar-sign is not the
+last character in the search string. Let the dollar-sign be the last
+character in the search string, as in {/\/ the$/^M} and observe the result.
+
+Observe the result of {/back.*file/^M}. This command, followed by sufficient
+{n}, will show you all lines in the file that contain both the words 'back'
+and 'file' on the same line. The '*' magic character specifies that the
+previous regular expression (the '.' in our example) is to be repeatedly
+matched zero or more times. In our example we specified that the words 'back'
+and 'file' must appear on the same line (they may be parts of words such as
+'backwards' or 'workfile') separated by any number (including zero) of
+characters.
+
+We could have specified that 'back' and 'file' are to be words by themselves by
+using the magic sequences '\<' or '\>'. E.g. {/\<back\>.*\<file\>/^M}. The
+sequence '\<' specifies that this point of the search string must match the
+beginning of a word, while '\>' specifies a match at the end of a word. By
+surrounding a string with these characters we have specified that they must be
+words.
+
+To find all words that begin with an 'l' or a 'w', followed by an 'a' or an
+'e', and ending in 'ing', try {/\<[lw][ea][a-z]*ing\>/^M}. This will match
+words like 'learning', 'warning', and 'leading'. The '[..]' notation matches
+exactly ONE character. The character matched will be one of the characters
+enclosed in the square brackets. The characters may be specified individually
+as in [abcd] or a '-' may be used to specify a range of characters as in [a-d].
+That is, [az] will match the letter 'a' OR the letter 'z', while [a-z] will
+match any of the lower case letters from 'a' through 'z'. If you would like to
+match either an 'a', a '-', or a 'z', then the '-' must be escaped: [a\-z] will
+match ONE of the three characters 'a', '-', or 'z'.
+
+If you wish to find all Capitalized words, try {/\<[A-Z][a-z]*\>/^M}. The
+following will find all character sequences that do NOT begin with an
+uncapitalized letter by applying a special meaning to the '^' character in
+square brackets: {/\<[^a-z][a-z]*\>/^M}. When '^' is the first character of a
+square-bracket expression, it specifies "all but these characters". (No
+one claimed vi was consistent.)
+
+To find all variable names (the first character is alphabetic, the remaining
+characters are alphanumeric): try {/\<[A-Za-z][A-Za-z0-9]*\>/^M}.
+
+In summary, here are the primitives for building regular expressions:
+
+ ^ at beginning of pattern, matches beginning of line
+ $ at end of pattern, matches end of line
+ . matches any single character
+ \< matches the beginning of a word
+ \> matches the end of a word
+ [str] matches any single character in str
+ [^str] matches any single character NOT in str
+ [x-y] matches any character in the ASCII range between x and y
+ * matches any number (including zero) of the preceding pattern
+
+Section 36: advanced substitution: {:s}
+
+The straightforward colon-substitute command looks like the substitute
+command of most line-oriented editors. Indeed, vi is nothing more than a
+superstructure on the line-oriented editor ex and the colon commands are
+simply a way of accessing commands within ex (see section #EX). This gives us
+a lot of global file processing not usually found in visual oriented editors.
+
+The colon-substitute command looks like: {:s/ .. / .. /^M} and will find the
+pattern specified after the first slash (this is called the search pattern),
+and replace it with the pattern specified after the second slash (called,
+obviously enough, the replacement pattern). E.g. position the cursor on line
+28 below and {:s/esample/example/^M}:
+
+Line 28: This is an esample.
+
+The {u} and {U} commands work for {:s}. The first pattern (the search pattern)
+may be a regular expression just as for the search command (after all, it IS a
+search, albeit limited to the current line). Do an {u} on the above line, and
+try the following substitute, which will do almost the same thing:
+{:s/s[^ ]/x/^M}.
+Better undo it with {u}. The first pattern {s[^ ]} matches an 's'
+NOT followed by a blank: the search therefore ignores the 's'es in 'This' and
+'is'. However, the character matched by {[^ ]} must appear in the replacement
+pattern. But, in general, we do not know what that character is! (In this
+particular example we obviously do, but more complicated examples will follow.)
+Therefore, vi (really ex) has a duplication mechanism to copy patterns matched
+in the search string into the replacement string. Line 29 below is a copy of
+line 28 above so you can adjust your screen.
+
+Line 29: This is an esample.
+
+In general, you can nest parts of the search pattern in \( .. \) and refer to
+it in the replacement pattern as \n, where n is a digit. The problem outlined
+in the previous paragraph is solved with {:s/s\([^ ]\)/x\1/^M}: try it. Here
+\1 refers to the first pattern grouping \( .. \) in the search string.
+
+Obviously, for a single line, this is rather tedious. Where it becomes
+powerful, if not necessary, is in colon-substitutes that cover a range of
+lines. (See the next section for a particularly comprehensive example.)
+
+If the entire character sequence matched by the search pattern is needed in
+the replacement pattern, then the unescaped character '&' can be used. On
+Line 29 above, try {:s/an e.ample/not &/^M}. If another line is to have the
+word 'not' prepended to a pattern, then '~' can save you from re-typing the
+replacement pattern. E.g. {:s/some pattern/~/^M} after the previous example
+would be equivalent to {:s/some pattern/not &/^M}.
+
+One other useful replacement pattern allows you to change the case of
+individual letters. The sequences {\u} and {\l} cause the immediately
+following character in the replacement to be converted to upper- or lower-case,
+respectively, if this character is a letter. The sequences {\U} and {\L} turn
+such conversion on, either until {\E} or {\e} is encountered, or until the end
+of the replacement pattern.
+
+For example, position the cursor on a line: pick a line, any line. Type
+{:s/.*/\U&/^M} and observe the result. You can undo it with {u}.
+
+The search pattern may actually match more than once on a single line.
+However, only the first pattern is substituted. If you would like ALL
+patterns matched on the line to be substituted, append a 'g' after the
+replacement pattern: {:s/123/456/g^M} will substitute EVERY occurrence
+on the line of 123 with 456.
+
+Section 37: advanced line addressing: {:p} {:g} {:v}
+
+Ex (available through the colon command in vi) offers several methods for
+specifying the lines on which a set of commands will act. For example, if you
+would like to see lines 50 through 100 of your file: {:50,100p^M} will display
+them, wait for you to [Hit return to continue], and leave you on line 100.
+Obviously, it would be easier just to do {100G} from within vi. But
+what if you would like to make changes to just those lines? Then the
+addressing is important and powerful.
+
+Line 30: This is a text.
+Line 31: Here is another text.
+Line 32: One more text line.
+
+The lines above contain a typing error that the author of this tutorial tends
+to make every time he attempts to type the word 'test'. To change all of these
+'text's into 'test's, try the following:
+{:/^Line 30/,/^Line 32/s/text/test/^M}. This finds the beginning and end of
+the portion of text to be changed, and limits the substitution to each of the
+lines in that range. The {u} command applies to ALL of the substitutions as
+a group.
+
+This provides a mechanism for powerful text manipulations.
+And very complicated examples.
+
+Line 33: This test is a.
+Line 34: Here test is another.
+Line 35: One line more test.
+
+The above three lines have the second word out of order. The following command
+string will put things right. Be very careful when typing this: it is very
+long, full of special characters, and easy to mess up. You may want to
+consider reading the following section to understand it before trying the
+experiment. Don't worry about messing up the rest of the file, though: the
+address range is specified.
+
+{:/^Line 33/,/^Line 35/s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/^M}
+
+There are several things to note about this command string. First of all, the
+range of the substitute was limited by the address specification {/^Line
+33/,/^Line 35/^M}. It might have been simpler to do {:set number^M} to see the
+line numbers directly, and then, in place of the two searches, typed
+the line numbers, e.g. {1396,1398}. Or to mark the lines with {ma} and {mb}
+and use {'a,'b}.
+
+Then follows the substitute pattern itself. To make it easier to understand
+what the substitute is doing, the command is duplicated below with the various
+patterns named for easier reference:
+
+ s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/
+ |--\1---| |--\2---| |--\3---| |--\4---|
+ |--------search pattern------------------|-replacement|
+ |--pattern---|
+
+In overview, the substitute looks for a particular pattern made up of
+sub-patterns, which are named \1, \2, \3, and \4. These patterns are specified
+by stating what they are NOT. Pattern \1 is the sequence of characters that
+are NOT colons: in the search string, {[^:]} will match exactly one character
+that is not a colon, while appending the asterisk {[^:]*} specifies that the
+'not a colon' pattern is to be repeated until no longer satisfied, and
+{\([^:]*\)} then gives the pattern its name, in this case \1. Outside of the
+specification of \1 comes {: }, specifying that the next two characters must be
+a colon followed by a blank.
+
+Patterns \2 and \3 are similar, specifying character sequences that are
+not blanks. Pattern \4 matches up to the period at the end of the line.
+
+The replacement pattern then consists of specifying the new order of the
+patterns.
+
+This is a particularly complicated example, perhaps the most complicated
+in this tutorial/reference. For our small examples, it is obviously
+tedious and error prone. For large files, however, it may be the most
+efficient way to make the desired modifications.
+
+(The reader is advised to look at the documentation for awk. This tool is very
+powerful and slightly simpler to use than vi for this kind of file
+manipulation. But, it is another command language to learn.)
+
+Many times, you will not want to operate on every line in a certain
+range. Rather you will want to make changes on lines that satisfy
+certain patterns; e.g. for every line that has the string 'NPS' on it,
+change 'NPS' to 'Naval Postgraduate School'. The {:g} addressing
+command was designed for this purpose. The example of this paragraph
+could be typed as {:g/NPS/s//Naval Postgraduate School/^M}.
+
+The general format of the command is {:g/(pattern)/cmds^M} and it
+works in the following way: all lines that match the pattern
+following the {:g} are 'tagged' in a special way. Then each of these
+lines have the commands following the pattern executed over them.
+
+Line 36: ABC rhino george farmer Dick jester lest
+Line 37: george farmer rhino lest jester ABC
+Line 38: rhino lest george Dick farmer ABC jester
+
+Type:
+
+{:g/^Line.*ABC/s/Dick/Harry Binswanger/|s/george farmer/gentleman george/p^M}
+
+There are several things of note here. First, lines 36, 37, and 38 above are
+tagged by the {:g}. Type {:g/^Line.*ABC/p^M} to verify this. Second, there
+are two substitutes on the same line separated by '|'. In general, any colon
+commands can be strung together with '|'. Third, both substitutes operate on
+all three lines, even though the first stubstitute works on only two of the
+lines (36 and 38). Fourth, the second substitute works on only two lines (36
+and 37) and those are the two lines printed by the trailing 'p'.
+
+The {:v} command works similarly to the {:g} command, except that the sense of
+the test for 'tagging' the lines is reversed: all lines NOT matching the search
+pattern are tagged and operated on by the commands.
+
+Using {^V} to quote carriage return (see section 39) can be used in global
+substitutions to split two lines. For example, the command
+{:g/\. /s//.^V^M/g^M} will change your file so that each sentence is on a
+separate line. (Note that we have to 'escape' the '.', because '.' by itself
+matches any character. Our command says to find any line which contains a
+period followed by 2 spaces, and inserts a carriage return after the period.)
+
+Caveat: In some of the documentation for ex and vi you may find the
+comment to the effect that {\^M} can be used between commands following
+{:g}. The author of this tutorial has never gotten this to work and has
+crashed the editor trying.
+
+Section 38: higher level text objects and nroff: {(} {)} [{] [}] {[[} {]]}
+
+(Note: this section may be a little confusing because of our command
+notation. Using curly braces to surround command strings works fine as
+long as the command string does not contain any curly braces itself.
+However, the curly braces are legitimate commands in vi. Therefore, for
+any command sequence that contains curly braces, we will surround that
+sequence with SQUARE braces, as on the previous Section line.)
+
+In working with a document, particularly if using the text formatting
+programs nroff or troff, it is often advantageous to work in terms of
+sentences, paragraphs, and sections. The operations {(} and {)} move to
+the beginning of the previous and next sentences, respectively. Thus
+the command {d)} will delete the rest of the current sentence; likewise
+{d(} will delete the previous sentence if you are at the beginning of
+the current sentence, or, if you are not at the beginning of a sentence,
+it will delete the current sentence from the beginning
+up to where you are.
+
+A sentence is defined to end at a '.', '!', or '?' which is followed
+by either the end of a line, or by two spaces. Any number of closing
+')', ']', '"', and ''' characters may appear after the '.', '!', or '?'
+before the spaces or end of line. Therefore, the {(} and {)} commands
+would recognize only one sentence in the following line, but two
+sentences on the second following line.
+
+Line 39: This is one sentence. Even though it looks like two.
+Line 40: This is two sentences. Because it has two spaces after the '.'.
+
+The operations [{] and [}] move over paragraphs and the operations {[[}
+and {]]} move over sections.
+
+A paragraph begins after each empty line, and also at each of a set of nroff
+paragraph macros. A section begins after each line with a form-feed ^L in the
+first column, and at each of a set of nroff section macros. When preparing a
+text file as input to nroff, you will probably be using a set of nroff macros
+to make the formatting specifications easier, or more to your taste. These
+macros are invoked by beginning a line with a period followed by the one or two
+letter macro name. Vi has been programmed to recognize these nroff macros, and
+if it doesn't recognize your particular macro you can use the {:set paragraphs}
+or {:set sections} commands so that it will.
+
+Section 39: more about inserting text
+
+There are a number of characters which you can use to make correnctions
+during input mode. These are summarized in the following table.
+
+ ^H deletes the last input character
+ ^W deletes the last input word
+ (erase) same as ^H; each terminal can define its own erase character;
+ for some it is ^H, for others it is the DELETE key, and for
+ others it is '@'.
+ (kill) deletes the input on this line; each terminal can define its
+ own line-kill character; for some it is ^U, for others it is
+ '@'; you will need to experiment on your terminal to find
+ out what your line-kill and erase characters are.
+ \ escapes a following ^H, (kill), and (erase) characters: i.e.
+ this is how to put these characters in your file.
+ ^[ escape key; ends insertion mode
+ ^? the delete key; interrupts an insertion, terminating it
+ abnormally.
+ ^M the return key; starts a new line.
+ ^D backtabs over the indentation set by the autoindent option
+ 0^D backtabs over all indentation back to the beginning of the line
+ ^^D (up-arrow followed by control-d)same as 0^D, except the indentation
+ will be restored at the beginning of the next line.
+ ^V quotes the next non-printing character into the file
+
+If you wish to type in your erase or kill character (say # or @ or ^U) then you
+must precede it with a \, just as you would do at the normal system command
+level. A more general way of typing non-printing characters into the file is
+to precede them with a ^V. The ^V echoes as a ^ character on which the cursor
+rests. This indicates that the editor expects you to type a control character
+and it will be inserted into the file at that point. There are a few
+exceptions to note. The implementation of the editor does not allow the null
+character ^@ to appear in files. Also the linefeed character ^J is used by the
+editor to separate lines in the file, so it cannot appear in the middle of a
+line. (Trying to insert a ^M into a file, or putting it in the replacement
+part of a substitution string will result in the matched line being split in
+two. This, in effect, is how to split lines by using a substitution.) You can
+insert any other character, however, if you wait for the editor to echo the ^
+before you type the character. In fact, the editor will treat a following
+letter as a request for the corresponding control character. This is the only
+way to type ^S or ^Q, since the system normally uses them to suspend and resume
+output and never gives them to the editor to process.
+
+If you are using the autoindent option you can backtab over the indent which it
+supplies by typing a ^D. This backs up to the boundary specified by the
+shiftwidth option. This only works immediately after the supplied autoindent.
+
+When you are using the autoindent option you may wish to place a label at the
+left margin of a line. The way to do this easily is to type ^ (up-arrow) and
+then ^D. The editor will move the cursor to the left margin for one line, and
+restore the previous indent on the next. You can also type a 0 followed
+immediately by a ^D if you wish to kill all indentation and not have it resume
+on the next line.
+
+Section 40: more on operators: {d} {c} {<} {>} {!} {=} {y}
+
+Below is a non-exhaustive list of commands that can follow the operators
+to affect the range over which the operators will work. However, note
+that the operators {<}, {>}, {!}, and {=} do not operate on any object
+less than a line. Try {!w} and you will get a beep. To get the
+operator to work on just the current line, double it. E.g. {<<}.
+
+ suffix will operate on
+ ------ ------------------------
+ ^[ cancels the command
+ w the word to the right of the cursor
+ W ditto, but ignoring punctuation
+ b the word to the left of the cursor
+ B ditto, but ignoring punctuation
+ e see below.
+ E ditto
+ (space) a character
+ $ to the end of the line
+ ^ to the beginning of the line
+ / .. / up to, but not including, the string
+ ? .. ? back to and including the string
+ fc up to and including the occurrence of c
+ Fc back to and including the occurrence of c
+ tc up to but not including the occurrence of c
+ Tc back to but not including the occurrence of c
+ ^M TWO lines (that's right: two)
+ (number)^M that many lines plus one
+ (number)G up to and including line (number)
+ ( the previous sentence if you are at the beginning of
+ the current sentence, or the current sentence up to where
+ you are if you are not at the beginning of the current
+ sentence. Here, 'sentence' refers to the intuitive
+ notion of an English sentence, ending with '!', '?',
+ or '.' and followed by an end of line or two spaces.
+ ) the rest of the current sentence
+ { analogous to '(', but in reference to paragraphs:
+ sections of text surrounded by blank lines
+ } analogous to ')', but in reference to paragraphs
+ [[ analogous to '(', but in reference to sections
+ ]] analogous to ')', but in reference to sections
+ H the first line on the screen
+ M the middle line on the screen
+ L the last line on the screen
+ 3L through the third line from the bottom of the screen
+ ^F forward a screenful
+ ^B backward a screenful
+ :
+ : etc. etc. etc.
+
+This list is not exhaustive, but it should be sufficient to get the idea
+across: after the operator, you can specify a range with a move-the-cursor
+command, and that is the region of text over which the operator will be
+effective.
+
+Section 41: abbreviations: {:ab}
+
+When typing large documents you may find yourself typing a large phrase
+over and over. Vi gives you the ability to specify an abbreviation for
+a long string such that typing the abbreviation will automatically
+expand into the longer phrase.
+
+Type {:ab nps Naval Postgraduate School^M}. Now type:
+
+{iThis is to show off the nps's UNIX editor.^M^[}
+
+Section 42: vi's relationship with the ex editor: {:}
+
+Vi is actually one mode of editing within the editor ex. When you are
+running vi you can escape to the line oriented editor of ex by giving
+the command {Q}. All of the colon-commands which were introduced above
+are available in ex. Likewise, most ex commands can be invoked from vi
+using {:}.
+
+In rare instances, an internal error may occur in vi. In this case you
+will get a diagnostic and will be left in the command mode of ex. You can
+then save your work and quit if you wish by giving the command {x} after
+the colon prompt of ex. Or you can reenter vi (if you are brave) by
+giving ex the command {vi}.
+
+Section 43: vi on hardcopy terminals and dumb terminals: open mode
+
+(The author has not checked the following documentation for accuracy. It is
+abstracted from the Introduction to Vi Editing document.)
+
+If you are on a hardcopy terminal or a terminal which does not have a cursor
+which can move off the bottom line, you can still use the command set of vi,
+but in a different mode. When you give the vi command to UNIX, the editor will
+tell you that it is using open mode. This name comes from the open command in
+ex, which is used to get into the same mode.
+
+The only difference between visual mode (normal vi) and open mode is the way in
+which the text is displayed.
+
+In open mode the editor uses a single line window into the file, and moving
+backward and forward in the file causes new lines to be displayed, always below
+the current line. Two commands of vi work differently in open: {z} and {^R}.
+The {z} command does not take parameters, but rather draws a window of context
+around the current line and then returns you to the current line.
+
+If you are on a hardcopy terminal, the {^R} command will retype the current
+line. On such terminals, the editor normally uses two lines to represent the
+current line. The first line is a copy of the line as you started to edit it,
+and you work on the line below this line. When you delete characters, the
+editor types a number of \'s to show you the characters which are deleted. The
+editor also reprints the current line soon after such changes so that you can
+see what the line looks like again.
+
+It is sometimes useful to use this mode on very slow terminals which can
+support vi in the full screen mode. You can do this by entering ex and using
+an {open} command.
+
+*********************************************************************
+Section 44: options: {:set} {setenv EXINIT}
+
+You will discover options as you need them. Do not worry about them very much
+on the first pass through this document. My advice is to glance through them,
+noting the ones that look interesting, ignoring the ones you don't understand,
+and try re-scanning them in a couple of weeks.
+
+If you decide that you have a favorite set of options and would like to change
+the default values for the editor, place a {setenv EXINIT} command in your
+.login file. When you are given an account under UNIX your directory has
+placed in it a file that is executed each time you log in. If one of the
+commands in this file sets the environment variable EXINIT to a string of vi
+commands, you can have many things done for you each time you invoke vi. For
+example, if you decide that you don't like tabstops placed every eight columns
+but prefer every four columns, and that you wish the editor to insert linefeeds
+for you when your typing gets you close to column 72, and you want
+autoindentation, then include the following line in your .login file:
+
+setenv EXINIT='set tabstop=4 wrapmargin=8 autoindent'
+
+or equivalently
+
+setenv EXINIT='se ts=4 wm=8 ai'
+
+Each time you bring up vi, this command will be executed and the options set.
+
+There are forty options in the vi/ex editor that the user can set for his/her
+own convenience. They are described in more detail in individual sections
+below. The section line will show the full spelling of the option name, the
+abbreviation, and the default value of the option. The text itself
+comes from the ex reference manual and is not the epitome of clarity.
+
+Section 44.1: {autoindent}, {ai} default: noai
+
+Can be used to ease the preparation of structured program text. At the
+beginning of each append, change or insert command or when a new line is opened
+or created by an append, change, insert, or substitute operation within open or
+visual mode, ex looks at the line being appended after, the first line changed
+or the line inserted before and calculates the amount of white space at the
+start of the line. It then aligns the cursor at the level of indentation so
+determined.
+
+If the user then types lines of text in, they will continue to be justified at
+the displayed indenting level. If more white space is typed at the beginning
+of a line, the following line will start aligned with the first non-white
+character of the previous line. To back the cursor up to the preceding tab
+stop one can hit {^D}. The tab stops going backwards are defined at multiples
+of the shiftwidth option. You cannot backspace over the indent, except by
+sending an end-of-file with a {^D}. A line with no characters added to it
+turns into a completely blank line (the white space provided for the autoindent
+is discarded). Also specially processed in this mode are lines beginning with
+an up-arrow `^' and immediately followed by a {^D}. This causes the input to
+be repositioned at the beginning of the line, but retaining the previous indent
+for the next line. Similarly, a `0' followed by a {^D} repositions at the
+beginning but without retaining the previous indent. Autoindent doesn't happen
+in global commands or when the input is not a terminal.
+
+Section 44.2: {autoprint}, {ap} default: ap
+
+Causes the current line to be printed after each delete, copy, join, move,
+substitute, t, undo or shift command. This has the same effect as supplying a
+trailing `p' to each such command. Autoprint is suppressed in globals, and
+only applies to the last of many commands on a line.
+
+Section 44.3: {autowrite}, {aw} default: noaw
+
+Causes the contents of the buffer to be written to the current file if you have
+modified it and give a next, rewind, stop, tag, or {!} command, or a control-
+up-arrow {^^} (switch files) or {^]} (tag goto) command in visual. Note, that
+the edit and ex commands do not autowrite. In each case, there is an
+equivalent way of switching when autowrite is set to avoid the autowrite
+({edit} for next, rewind! for rewind, stop! for stop, tag! for tag, shell
+for {!}, and {:e #} and a {:ta!} command from within visual).
+
+Section 44.4: {beautify}, {bf} default: nobeautify
+
+Causes all control characters except tab ^I, newline ^M and form-feed ^L to be
+discarded from the input. A complaint is registered the first time a backspace
+character is discarded. Beautify does not apply to command input.
+
+Section 44.5: {directory}, {dir} default: dir=/tmp
+
+Specifies the directory in which ex places its buffer file. If this directory
+in not writable, then the editor will exit abruptly when it fails to be able to
+create its buffer there.
+
+Section 44.6: {edcompatible} default: noedcompatible
+
+Causes the presence or absence of g and c suffixes on substitute commands to be
+remembered, and to be toggled by repeating the suffices. The suffix r makes
+the substitution be as in the {~} command, instead of like {&}.
+
+[Author's note: this should not concern users of vi.]
+
+Section 44.7: {errorbells}, {eb} default: noeb
+
+Error messages are preceded by a bell. However, bell ringing in open and
+visual modes on errors is not suppressed by setting noeb. If possible the
+editor always places the error message in a standout mode of the terminal (such
+as inverse video) instead of ringing the bell.
+
+Section 44.8: {hardtabs}, {ht} default: ht=8
+
+Gives the boundaries on which terminal hardware tabs are set (or on which the
+system expands tabs).
+
+Section 44.9: {ignorecase}, {ic} default: noic
+
+All upper case characters in the text are mapped to lower case in regular
+expression matching. In addition, all upper case characters in regular
+expressions are mapped to lower case except in character class specifications
+(that is, character in square brackets).
+
+Section 44.10: {lisp} default: nolisp
+
+Autoindent indents appropriately for lisp code, and the {(}, {)}, [{], [}],
+{[[}, and {]]} commands in open and visual modes are modified in a
+striaghtforward, intuitive fashion to have meaning for lisp.
+
+[Author's note: but don't ask me to define them precisely.]
+
+Section 44.11: {list} default: nolist
+
+All printed lines will be displayed (more) unambiguously, showing tabs as ^I
+and end-of-lines with `$'. This is the same as in the ex command {list}.
+
+Section 44.12: {magic} default: magic for {ex} and {vi}, nomagic for edit.
+
+If nomagic is set, the number of regular expression metacharacters is greatly
+reduced, with only up-arrow `^' and `$' having special effects. In addition
+the metacharacters `~' and `&' of the replacement pattern are treated as normal
+characters. All the normal metacharacters may be made magic when nomagic is
+set by preceding them with a `\'.
+
+[Author's note: In other words, if magic is set a back-slant turns the magic
+off for the following character, and if nomagic is set a back-slant turns the
+magic ON for the following character. And, no, we are not playing Dungeons and
+Dragons, although I think the writers of these option notes must have played it
+all the time.]
+
+Section 44.13: {mesg} default: mesg
+
+Causes write permission to be turned off to the terminal while you are in
+visual mode, if nomesg is set.
+
+[Author's note: I don't know if anyone could have made any one sentence
+paragraph more confusing than this one. What it says is: mesg allows people to
+write to you even if you are in visual or open mode; nomesg locks your terminal
+so they can't write to you and mess up your screen.]
+
+Section 44.14: {number, nu} default: nonumber
+
+Causes all output lines to be printed with their line numbers. In addition
+each input line will be prompted with its line number.
+
+Section 44.15: {open} default: open
+
+If {noopen}, the commands open and visual are not permitted. This is set for
+edit to prevent confusion resulting from accidental entry to open or visual
+mode.
+
+[Author's note: As you may have guessed by now, there are actually three
+editors available under Berkeley UNIX that are in reality the same
+program, ex, with different options set: ex itself, vi, and edit.]
+
+Section 44.16: {optimize, opt} default: optimize
+
+Throughput of text is expedited by setting the terminal to not do automatic
+carriage returns when printing more than one (logical) line of output, greatly
+speeding output on terminals without addressable cursors when text with leading
+white space is printed.
+
+[Author's note: I still don't know what this option does.]
+
+Section 44.17: {paragraphs, para} default: para=IPLPPPQPP LIbp
+
+Specifies the paragraphs for the [{] and [}] operations in open and visual.
+The pairs of characters in the option's value are the names of the nroff macros
+which start paragraphs.
+
+Section 44.18: {prompt} default: prompt
+
+Command mode input is prompted for with a `:'.
+
+[Author's note: Doesn't seem to have any effect on vi.]
+
+Section 44.19: {readonly}, {ro} default: noro, unless invoked with -R
+ or insufficient privileges on file
+
+This option allows you to guarantee that you won't clobber your file by
+accident. You can set the option and writes will fail unless you use an `!'
+after the write. Commands such as {x}, {ZZ}, the autowrite option, and in
+general anything that writes is affected. This option is turned on if you
+invoke the editor with the -R flag.
+
+Section 44.20: {redraw} default: noredraw
+
+The editor simulates (using great amounts of output), an intelligent terminal
+on a dumb terminal (e.g. during insertions in visual the characters to the
+right of the cursor position are refreshed as each input character is typed).
+Useful only at very high baud rates, and should be used only if the system is
+not heavily loaded: you will notice the performance degradation yourself.
+
+Section 44.21: {remap} default: remap
+
+If on, macros are repeatedly tried until they are unchanged. For example, if o
+is mapped to O, and O is mapped to I, then if remap is set, o will map to I,
+but if noremap is set, it will map to O .
+
+Section 44.22: {report} default: report=5 for ex and vi, 2 for edit
+
+Specifies a threshold for feedback from commands. Any command which modifies
+more than the specified number of lines will provide feedback as to the scope
+of its changes. For commands such as global, open, undo, and visual which have
+potentially more far reaching scope, the net change in the number of lines in
+the buffer is presented at the end of the command, subject to this same
+threshold. Thus notification is suppressed during a global command on the
+individual commands performed.
+
+Section 44.23: {scroll} default: scroll=1/2 window
+
+Determines the number of logical lines scrolled when a {^D} is received from a
+terminal in command mode, and determines the number of lines printed by a
+command mode z command (double the value of scroll).
+
+[Author's note: Doesn't seem to affect {^D} and {z} in visual (vi) mode.]
+
+Section 44.24: sections {sections} default: sections=SHNHH HU
+
+Specifies the section macros from nroff for the {[[} and {]]} operations in
+open and visual. The pairs of characters in the options's value are the names
+of the macros which start paragraphs.
+
+Section 44.25: {shell}, {sh} default: sh=/bin/sh
+
+Gives the path name of the shell forked for the shell escape command `!', and
+by the shell command. The default is taken from SHELL in the environment, if
+present.
+
+[Editor's note: I would suggest that you place the following line in
+your .login file:
+setenv SHELL '/bin/csh'
+]
+
+Section 44.26: {shiftwidth}, {sw} default: sw=8
+
+Used in reverse tabbing with {^D} when using autoindent to append text, and
+used by the shift commands. Should probably be the same value as the tabstop
+option.
+
+Section 44.27: {showmatch}, {sm} default: nosm
+
+In open and visual mode, when a `)' or `}' is typed, if the matching `(' or `{'
+is on the screen, move the cursor to it for one second. Extremely useful with
+complicated nested expressions, or with lisp.
+
+Section 44.28: {slowopen}, {slow} default: terminal dependent
+
+Affects the display algorithm used in visual mode, holding off display updating
+during input of new text to improve throughput when the terminal in use is both
+slow and unintelligent. See "An Introduction to Display Editing with Vi" for
+more details.
+
+Section 44.29: {tabstop}, {ts} default: ts=8
+
+The editor expands tabs ^I to tabstop boundaries in the display.
+
+Section 44.30: {taglength}, {tl} default: tl=0
+
+Tags are not significant beyond this many characters.
+A value of zero (the default) means that all characters are significant.
+
+Section 44.31: {tags} default: tags=tags /usr/lib/tags
+
+A path of files to be used as tag files for the tag command. A requested tag
+is searched for in the specified files, sequentially. By default files called
+tags are searched for in the current directory and in /usr/lib (a master file
+for the entire system).
+
+[Author's note: The author of this tutorial has never used this option, nor
+seen it used. I'm not even sure I know what they are talking about.]
+
+Section 44.32: {term} default: from environment variable TERM
+
+The terminal type of the output device.
+
+Section 44.33: {terse} default: noterse
+
+Shorter error diagnostics are produced for the experienced user.
+
+Section 44.34: {timeout} default: timeout
+
+Causes macros to time out after one second. Turn it off and they will
+wait forever. This is useful if you want multi-character macros, but if
+your terminal sends escape sequences for arrow keys, it will be
+necessary to hit escape twice to get a beep.
+
+[Editor's note: Another paragraph which requires a cryptographer.]
+
+Section 44.35: ttytype
+
+[Editor's note: I have found no documentation for this option at all.]
+
+Section 44.36: {warn} default: warn
+
+Warn if there has been `[No write since last change]' before a `!' command
+escape.
+
+Section 44.37: {window} default: window=speed dependent
+
+The number of lines in a text window in the visual command. The default is 8
+at slow speeds (600 baud or less), 16 at medium speed (1200 baud), and the full
+screen (minus one line) at higher speeds.
+
+Section 44.38: {wrapscan}, {ws} default: ws
+
+Searches using the regular expressions in addressing will wrap around past the
+end of the file.
+
+Section 44.39: {wrapmargin}, {wm} default: wm=0
+
+Defines a margin for automatic wrapover of text during input in open and visual
+modes. The numeric value is the number of columns from the right edge of the
+screen around which vi looks for a convenient place to insert a new-line
+character (wm=0 is OFF). This is very convenient for touch typists.
+Wrapmargin behaves much like fill/nojustify mode does in nroff.
+
+Section 44.40: {writeany}, {wa} default: nowa
+
+Inhibit the checks normally made before write commands, allowing a write to any
+file which the system protection mechanism will allow.
+
+Section 44.41: {w300}, {w1200}, {w9600} defaults: w300=8
+ w1200=16
+ w9600=full screen minus one
+
+These are not true options but set the default size of the window for when the
+speed is slow (300), medium (1200), or high (9600), respectively. They are
+suitable for an EXINIT and make it easy to change the 8/16/full screen rule.
+
+Section 45: Limitations
+
+Here are some editor limits that the user is likely to encounter:
+ 1024 characters per line
+ 256 characters per global command list
+ 128 characters per file name
+ 128 characters in the previous inserted and deleted text in open or
+ visual
+ 100 characters in a shell escape command
+ 63 characters in a string valued option
+ 30 characters in a tag name
+ 250000 lines in the file (this is silently enforced).
+
+The visual implementation limits the number of macros defined with map to 32,
+and the total number of characters in macros to be less than 512.
+
+[Editor's note: these limits may not apply to versions after 4.1BSD.]
diff --git a/usr.bin/vi/docs/tutorial/vi.beginner b/usr.bin/vi/docs/tutorial/vi.beginner
new file mode 100644
index 000000000000..3bf35ac939f8
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.beginner
@@ -0,0 +1,741 @@
+Section 1: {^F} {ZZ}
+
+To get out of this tutorial, type: ZZ (two capital Z's).
+
+Learning a new computer system implies learning a new text editor. These
+tutorial lessons were created by Dain Samples to help you come to grips with
+UC Berkeley's screen oriented editor called vi (for VIsual). This tutorial
+uses the vi editor itself as the means of presentation.
+
+For best use of this tutorial, read all of a screen before performing any of
+the indicated actions. This tutorial (or, at least, the first half of it) has
+been designed to systematically present the vi commands IF THE INSTRUCTIONS
+ARE FOLLOWED! If you are too adventuresome, you may find yourself lost. If
+you ever find yourself stuck, remember the first line of this section.
+
+OK, now find the control key on your keyboard; it usually has CTL or CTRL
+written on its upper surface. Your first assignment is to hold the control
+key down while you press the 'F' key on your keyboard. Please do so now.
+
+
+
+Section 2: {^F} {^B}
+Many of vi's commands use the control key and some other key in combination,
+as with the control and the 'F' key above. This is abbreviated CTL-F, or ^F.
+
+As you have probably guessed by now, ^F (CTL-F) moves you forward a fixed
+number of lines in the file. Throughout the remainder of the tutorial when
+you are ready to advance to the next section of text, hit ^F.
+
+The opposite command is ^B. Just for fun, you might want to try a ^B to see
+the previous section again. Be sure to do a ^F to return you here.
+
+Determine what the cursor looks like on your screen. Whatever it is (a box,
+an underscore, blinking, flashing, inverse, etc.) it should now be positioned
+in the upper left-hand corner of your screen under or on the S of Section.
+Become familiar with your cursor: to use vi correctly it is important to
+always know where the cursor is.
+
+Did you notice that when you do a ^F the cursor is left at the top of the
+screen, and a ^B leaves the cursor near the bottom of the screen? Try the two
+commands ^B^F again. And now do another ^F to see the next section.
+
+Section 3: {^F} {^B}
+You now have two basic commands for examining a file, both forwards (^F) and
+backwards (^B).
+
+Note that these are vi text editing commands: they are not commands for the
+tutorial. Indeed, this tutorial is nothing but a text file which you are now
+editing. Everything you do and learn in this tutorial will be applicable to
+editing text files.
+
+Therefore, when you are editing a file and are ready to see more of the text,
+entering ^F will get you to the next section of the file. Entering ^B will
+show you the previous section.
+
+Time for you to do another ^F.
+
+
+
+
+
+
+
+Section 4: {^F} {^B} {^M} (return key)
+We will adopt the notation of putting commands in curly braces so we can write
+them unambiguously. For example, if you are to type the command sequence
+"control B control F" (as we asked you to do above) it would appear as {^B^F}.
+This allows clear delineation of the command strings from the text. Remember
+that the curly braces are NOT part of the command string you are to type. Do
+NOT type the curly braces.
+
+Sometimes, the command string in the curly braces will be rather long, and may
+be such that the first couple of characters of the command will erase from
+the screen the string you are trying to read and type. It is suggested that
+you write down the longer commands BEFORE you type them so you won't forget
+them once they disappear.
+
+Now locate the return key on your keyboard: it is usually marked 'RETURN',
+indicate hitting the return key. In fact, the control-M key sequence is
+exactly the same as if you hit the return key, and vice versa.
+
+Now type {^F}.
+
+
+Section 5: {:q!} {ZZ} {^M} (return key)
+Recognize that this tutorial is nothing more than a text file that you
+are editing. This means that if you do something wrong, it is possible
+for you to destroy the information in this file. Don't worry. If this
+happens, type {ZZ} (two capital Z's) or {:q!^M} to leave the tutorial.
+Restart the tutorial. Once in the tutorial, you can then page forward
+with {^F} until you are back to where you want to be. (There are
+easier ways to do this, some of which will be discussed later, but this
+is the most straightforward.)
+
+You may want to write these commands down in a convenient place for quick
+reference: {:q!^M} and {ZZ}
+
+We will assume that you now know to do a {^F} to advance the file
+
+
+
+
+
+
+
+Section 6: {m} {G} {'} {z}
+Now that you know how to get around in the file via ^F and ^B let's look at
+other ways of examining a text file. Sometimes it is necessary, in the midst
+of editing a file, to examine another part of the file. You are then faced
+with the problem of remembering your place in the file, looking at the other
+text, and then getting back to your original location. Vi has a 'mark'
+command, m. Type {mp}. You have just 'marked' your current location in the
+file and given it the name 'p'. The command string below will do three
+things: position you at the beginning of the file (line 1), then return you to
+the location 'p' that you just marked with the 'm' command, and, since the
+screen will not look exactly the same as it does right now, the 'z' command
+will reposition the screen. (You may want to write the string down before
+typing it: once you type {1G} it will no longer be on the screen.)
+
+So now type {1G'pz^M} - a one followed by a capital G, followed by the quote
+mark, followed by a lower case 'p', then a lower case 'z', then a return
+(which is the same as a ^M). The {1G} moves you to line 1, i.e. the beginning
+of the file. The {'p} moves you to the location you marked with {mp}. The
+{z^M} command will repaint the screen putting the cursor at the top of the
+screen. (Now {^F}.)
+
+Section 7: {m} {G} {'} {z}
+Let's look at some variations on those commands. If you wanted to look at
+line 22 in the file and return to this location you could type {mp22G'p}. Do
+so now, observing that {22G} puts your cursor at the beginning of section 2 in
+the middle of the screen.
+
+Also note that, without the {z^M} command, the line with 'Section 7' on it is
+now in the MIDDLE of the screen, and not at the top. Our cursor is on the
+correct line (where we did the {mp} command) but the line is not where we
+might like it to be on the screen. That is the function of the {z^M} command.
+(Remember, ^M is the same as the 'return' key on your keyboard.) Type {z^M}
+now and observe the effect.
+
+As you can see, the 'Section 7' line is now at the top of the screen with the
+cursor happily under the capital S. If you would like the cursor line (i.e.
+the line which the cursor is on) in the middle of the screen again, you would
+type {z.}. If you wanted the cursor line to be at the BOTTOM of the screen,
+type {z-}. Try typing {z-z.z^M} and watch what happens.
+
+{^F}
+
+Section 8: {z} {m} {'}
+
+Note that the z command does not change the position of our cursor in the file
+itself, it simply moves the cursor around on the screen by moving the contents
+of the file around on the screen. The cursor stays on the same line of the
+file when using the z command.
+
+This brings up an important point. There are two questions that the users of
+vi continually need to know the answer to: "Where am I in the file?" and
+"Where am I on the screen?" The cursor on your terminal shows the answer to
+both questions. Some commands will move you around in the file, usually
+changing the location of the cursor on the screen as well. Other commands
+move the cursor around on the screen without changing your location in the
+file.
+
+Now type {ma}. Your location in the file has been given the name 'a'. If you
+type {'p'a} you will see the previous location we marked in section 7, and
+then will be returned to the current location. (You will want to do a {z^M}
+to repaint the screen afterwards.) Try it.
+{^F}
+
+Section 9: {m} {''}
+Now we can move about in our file pretty freely. By using the {m} command we
+can give the current cursor position a lower-case-character name, like 'p',
+'a', 'e', 'm', or 'b'. Using the {G} command preceded by a line number we can
+look at any line in the file we like. Using the single quote command {'}
+followed by a character used in an {m} command, we can return to any location
+in the file we have marked.
+
+However, try {m3}, or {mM}. You should hear a beep, or bell. Only lower-case
+letters are acceptable to the {m} and {'} commands: numbers, upper-case
+letters, and special characters are not acceptable.
+
+If you type the {'} command with a character that is lower-case alphabetic but
+that has not been used in an {m} command, or for which the 'marked' text has
+been deleted, you will also get a beep. Try {'i}. You should get a beep
+because the command {mi} has never been issued. (Unless you've been
+experimenting.)
+
+The command {''} attempts to return you to the location at which you last
+modified some part of your file. However, my experience has been that it is
+difficult to predict exactly where you will end up.
+Section 10: {^M} {-}
+Now do {ma}, marking your position at the top of the screen. Now hit {^M} (or
+return) until the cursor is right ...
+* <- here, over/under the asterisk. Now
+type {mb'a'b} and watch the cursor move from the asterisk to the top of the
+screen and back again.
+
+The {^M} command moves the cursor to the beginning of the next line. Now type
+{^M} until the cursor is right ...
+* <- here. The command to move the cursor to the beginning of the
+previous line is {-}. Practice moving the cursor around on the screen by using
+{^M} and {-}. BE CAREFUL to not move the cursor OFF the screen just yet. If
+you do, type {'az^M}.
+
+Now we can move to any line within the screen. Practice moving around in the
+file using the {^F}, {^B}, {-}, {^M}, {z}, and {'} commands. When you are
+fairly confident that you can get to where you need to be in the file, and
+position the cursor on the screen where you want it type {'az^M^F} (which, of
+course, moves you back to the beginning of this section, repositions the
+cursor at the top of the screen, and advances you to the next section).
+
+Section 11: scrolling: {^M}
+The cursor should now be on the S of 'Section 11', and this should be on the
+first line of the screen. If it is not, do {^M} or {-} as appropriate to put
+the cursor on the section line, and type {z^M}.
+
+Type {mc} to mark your place.
+
+Now type {^M} until the cursor is on the last line of this screen. Now do one
+more {^M} and observe the result. This is called scrolling. When you
+attempted to move to a line not displayed on the screen, the line at the top of
+the screen was 'scrolled off', and a line at the bottom of the screen was
+'scrolled on'. The top line with 'Section 11' should no longer be visible.
+
+Now type {'cz^M} to reset the screen and type {^F} for the next section.
+
+
+
+
+
+
+
+Section 12: {-} {z}
+
+The {-} command moves the cursor to the previous line in the file. Now type
+{-}, which attempts to move the cursor to the previous line in this file.
+However, that line is not on the screen. The resulting action will depend on
+your terminal. (Do a {^Mz^M} to reposition the file). On intelligent
+terminals (e.g. VT100s, Z19s, Concept 100s), a top line is 'scrolled on' and
+the bottom line is 'scrolled off'. Other terminals, however, may not have
+this 'reverse scrolling' feature. They will simply repaint the screen with
+the cursor line in the middle of the screen. On such terminals it is
+necessary to type {z^M} to get the cursor line back to the top of the screen.
+
+
+
+
+
+
+
+
+
+
+Section 13:
+Up until this point, the tutorial has always tried to make sure that the first
+line of each screen has on it the section number and a list of the commands
+covered in that section. This will no longer be strictly maintained. If you
+want the section line at the top of the screen, you now know enough commands to
+do it easily: do {^M} or {-} until the cursor is on the section line and
+then {z^M}. Also, from this point on, it may not be the case that a {^F} will
+put you at the beginning of the next section. Therefore, be aware of where you
+are in the file as we look at other commands. You may have to find your way
+back to a particular section without any help from the tutorial. If you do not
+feel comfortable with this, then it is suggested that you practice moving from
+section 1 to section 13, back and forth, using {^M}, {-}, {^F}, and {^B}
+commands for a while.
+
+Also make liberal use of the mark command {m}: if, for example, you make a
+habit of using {mz} to mark your current location in the file, then you will
+always be able to return to that location with {'z} if the editor does
+something strange and you have no idea where you are or what happened.
+
+And finally, the proscription against experimentation is hereby lifted: play
+with the editor. Feel free to try out variations on the commands and move
+around in the file. By this time you should be able to recover from any gross
+errors.
+
+Section 14: {^E} {^Y} {^D} {^U}
+Let us now look at a few other commands for moving around in the file, and
+moving the file around on the screen. Note that the commands we have already
+looked at are sufficient: you really don't need any more commands for looking
+in a file. The following commands are not absolutely necessary. However,
+they can make editing more convenient, and you should take note of their
+existence. But it would be perfectly valid to decide to ignore them on this
+first pass: you can learn them later when you see a need for them, if you ever
+do.
+
+First, let's clear up some potentially confusing language. In at least one
+place in the official document ('An Introduction to Display Editing with Vi'
+by William Joy, and Mark Horton, September 1980), the expression "to scroll
+down text" means that the cursor is moved down in your file. However, note
+that this may result in the text on the screen moving UP. This use of the
+word 'scroll' refers to the action of the cursor within the file. However,
+another legitimate use of the word refers to the action of the text on the
+screen. That is, if the lines on your screen move up toward the top of the
+screen, this would be 'scrolling the screen up'. If the lines move down
+toward the bottom of the screen, this would be refered to as scrolling down.
+
+I have tried to maintain the following jargon: 'scrolling' refers to what the
+text does on the screen, not to what the cursor does within the file. For the
+latter I will refer to the cursor 'moving', or to 'moving the cursor'. I
+realize that this is not necessarily consistent with Joy and Horton, but they
+were wrong.
+
+{^E} scrolls the whole screen up one line, keeping the cursor on the same line,
+if possible. However, if the cursor line is the first line on the screen, then
+the cursor is moved to the next line in the file. Try typing {^E}.
+
+{^Y} scrolls the screen down one line, keeping the cursor on the same line, if
+possible. However, if the cursor line is the last line on the screen, then the
+cursor is moved to the previous line in the file. Try it.
+
+{^D} moves the cursor down into the file, scrolling the screen up.
+
+{^U} moves the cursor up into the file, also scrolling the screen if the
+terminal you are on has the reverse scroll capability. Otherwise the
+screen is repainted.
+
+Note that {^E} and {^Y} move the cursor on the screen while trying to keep the
+cursor at the same place in the file (if possible: however, the cursor can
+never move off screen), while {^D} and {^U} keep the cursor at the same place
+on the screen while moving the cursor within the file.
+
+Section 15: {/ .. /^M}
+
+Another way to position yourself in the file is by giving the editor a string
+to search for. Type the following: {/Here 1/^M} and the cursor should end up
+right ...........................here ^. Now type {/Section 15:/^M} and the
+cursor will end up over/on .....................here ^. Now type {//^M} and
+observe that the cursor is now over the capital S five lines above this line.
+Typing {//^M} several more times will bounce the cursor back and forth between
+the two occurrences of the string. In other words, when you type a string
+between the two slashes, it is searched for. Typing the slashes with nothing
+between them acts as if you had typed the previous string again.
+
+Observe that the string you type between the two slashes is entered on the
+bottom line of the screen. Now type {/Search for x /^M} except replace the 'x'
+in the string with some other character, say 'b'. The message "Pattern not
+found" should appear on the bottom of the screen. If you hadn't replaced the
+'x', then you would have found the string. Try it.
+
+Section 16: {? .. ?^M} {n} (search strings: ^ $)
+
+When you surround the sought-for string with slashes as in {/Search/}, the
+file is searched beginning from your current position in the file. If the
+string is not found by the end of the file, searching is restarted at the
+beginning of the file. However, if you do want the search to find the
+PREVIOUS rather than the NEXT occurrence of the string, surround the string
+with question marks instead of slash marks.
+
+Below are several occurrences of the same string.
+Here 2 Here 2 Here 2
+ Here 2 Here 2.
+Observe the effect of the following search commands (try them in the
+sequence shown):
+{/Here 2/^M} {//^M} {??^M}
+{/^Here 2/^M} {//^M} {??^M}
+{/Here 2$/^M} {//^M} {??^M}
+
+The first command looks for the next occurrence of the string 'Here 2'.
+However the second line of commands looks for an occurrence of 'Here 2' that
+is at the beginning of the line. When the up-arrow is the first character of
+a search string it stands for the beginning of the line. When the dollar-sign
+is the last character of the search string it stands for the end of the line.
+Therefore, the third line of commands searches for the string only when it is
+at the end of the line. Since there is only one place the string begins a
+line, and only one place the string ends the line, subsequent {//^M} and
+{??^M} will find those same strings over and over.
+
+The {n} command will find the next occurrence of the / or ? search
+string. Try {/Here 2/^M} followed by several {n} and observe the
+effect. Then try {??^M} followed by several {n}. The {n} command
+remembers the direction of the last search. It is just a way to save a
+few keystrokes.
+
+Section 17: \ and magic-characters in search strings
+
+Now type {/Here 3$/^M}. You might expect the cursor to end up
+right......^ here. However, you will get "Pattern not found" at the bottom of
+the screen. Remember that the dollar-sign stands for the end of the line.
+Somehow, you must tell vi that you do not want the end of the line, but a
+dollar-sign. In other words, you must take away the special meaning that the
+dollar-sign has for the search mechanism. You do this (for any special
+character, including the up-arrow ^) by putting a back-slash ('\', not '/') in
+front of the character.
+
+Now try {/Here 3\$/^M} and you should end up nine lines above this one. Try
+{//^M} and note that it returns you to the same place, and not to the first
+line of this paragraph: the back-slash character is not part of the search
+string and will not be found. To find the string in the first line of this
+paragraph, type {/Here 3\\\$/^M}. There are three back-slashes: the first takes
+away the special meaning from the second, and the third takes away the special
+meaning from the dollar-sign.
+
+Following is a list of the characters that have special meanings in search
+strings. If you wish to find a string containing one of these characters, you
+will have to be precede the character with a backslash. These characters are
+called magic characters because of the fun and games you can have with them
+and they can have with you, if you aren't aware of what they do.
+
+ ^ - (up-arrow) beginning of a line
+ $ - (dollar-sign) end of a line
+ . - (period) matches any character
+ \ - (backslant) the escape character itself
+ [ - (square bracket) for finding patterns (see section #SEARCH)
+ ] - (square bracket) ditto
+ * - (asterisk) ditto
+
+Without trying to explain it here, note that {:set nomagic^M} turns off the
+special meanings of all but the ^ up-arrow, $ dollar-sign, and backslash
+characters.
+
+Section 18: {: (colon commands)} {ZZ}
+
+In this section we will discuss getting into and out of the editor in more
+detail. If you are editing a file and wish to save the results the command
+sequence {:w^M} writes the current contents of the file out to disk, using the
+file name you used when you invoked the editor. That is, if you are at the
+command level in Unix, and you invoke vi with {vi foo} where foo is the name
+of the file you wish to edit, then foo is the name of the file used by the
+{:w^M} command.
+
+If you are done, the write and quit commands can be combined into a single
+command {:wq^M}. An even simpler way is the command {ZZ} (two capital Z's).
+
+If, for some reason, you wish to exit without saving any changes you have made,
+{:q!^M} does the trick. If you have not made any changes, the exclamation
+point is not necessary: {:q^M}. Vi is pretty good about not letting you
+get out without warning you that you haven't saved your file.
+
+We have mentioned before that you are currently in the vi editor, editing a
+file. If you wish to start the tutorial over from the very beginning, you
+could {ZZ}, and then type {vi.tut beginner} in response to the Unix prompt.
+This will create a fresh copy of this file for you, which might be necessary
+if you accidentally destroyed the copy you were working with. Just do a
+search for the last section you were in: e.g. {/Section 18:/^Mz^M}.
+
+Section 19: {H} {M} {L}
+
+Here are a few more commands that will move you around on the screen. Again,
+they are not absolutely necessary, but they can make screen positioning easier:
+
+{H} - puts the cursor at the top of the screen (the 'home' position)
+
+{M} - puts the cursor in the middle of the screen
+
+{L} - puts the cursor at the bottom of the screen.
+
+Try typing {HML} and watch the cursor.
+
+Try typing {5HM5L} and note that 5H puts you five lines from the top of the
+screen, and 5L puts you five lines from the bottom of the screen.
+
+Section 20: {w} {b} {0} {W} {B} {e} {E} {'} {`}
+
+Up to this point we have concentrated on positioning in the file, and
+positioning on the screen. Now let's look at positioning in a line. Put the
+cursor at the beginning of the following line and type {z^M}:
+
+This is a test line: your cursor should initially be at its beginning.
+
+The test line should now be at the top of your screen. Type {w} several times.
+Note that it moves you forward to the beginning of the next word. Now type
+{b} (back to the beginning of the word) several times till you are at the
+beginning of the line. (If you accidentally type too many {b}, type {w} until
+you are on the beginning of the line again.) Type {wwwww} (five w's) and note
+that the cursor is now on the colon in the sentence. The lower-case w command
+moves you forward one word, paying attention to certain characters such as
+colon and period as delimiters and counting them as words themselves. Now
+type {0} (zero, not o 'oh'): this moves you to the beginning of the current
+line. Now type {5w} and notice that this has the effect of repeating {w} five
+times and that you are now back on the colon. Type {0} (zero) again. To
+ignore the delimiters and to move to the beginning of the next word using only
+blanks, tabs and carriage-returns (these are called white-space characters) to
+delimit the words, use the {W} command: upper-case W. {B} takes you back a
+word using white-space characters as word delimiters.
+
+Note that the commands {wbWB} do not stop at the beginning or end of a line:
+they will continue to the next word on the next line in the direction specified
+(a blank line counts as a word).
+
+If you are interested in the END of the word, and not the BEGINNING, then use
+the {e} and {E} commands. These commands only move forward and there are no
+corresponding 'reverse search' commands for the end of a word.
+
+Also, we have been using the {'} command to move the cursor to a position that
+we have previously marked with the {m} command. However, position the cursor
+in the middle of a line (any line, just pick one) and type {mk}, marking that
+position with the letter k. Now type a few returns {^M} and type {'k}.
+Observe that the cursor is now at the beginning of the line that you marked.
+Now try {`k}: note that this is the reverse apostrophe, or back-quote, or grave
+accent, or whatever you want to call it. Also note that it moves you to the
+character that was marked, not just to the line that was marked.
+
+In addition, the {``} command works just like the {''} command except that you
+are taken to the exact character, not just to the line. (I'm still not
+sure which exact character, just as I'm still not sure which line.)
+
+Section 21: {l} {k} {j} {h}
+
+There are several commands to move around on the screen on a character by
+character basis:
+
+l - moves the cursor one character to the RIGHT
+k - moves the cursor UP one line
+j - moves the cursor DOWN one line
+h - moves the cursor one character to the LEFT
+
+Section 22: {i} {a} {I} {A} {o} {O} ^[ (escape key)
+
+For this and following sections you will need to use the ESCAPE key on your
+terminal. It is usually marked ESC. Since the escape key is the same as
+typing {^[} we will use ^[ for the escape key.
+
+Probably the most often used command in an editor is the insert command. Below
+are two lines of text, the first correct, the second incorrect. Position your
+cursor at the beginning of Line 1 and type {z^M}.
+
+Line 1: This is an example of the insert command.
+Line 2: This is an of the insert command.
+
+To make line 2 look like line 1, we are going to insert the characters
+'example ' before the word 'of'. So, now move the cursor so that it is
+positioned on the 'o' of 'of'. (You can do this by typing {^M} to move
+to the beginning of line 2, followed by {6w} or {wwwwww} to position the cursor
+on the word 'of'.)
+
+Now carefully type the following string and observe the effects:
+ {iexample ^[} (remember: ^[ is the escape key)}
+The {i} begins the insert mode, and 'example ' is inserted into the line:
+be sure to notice the blank in 'example '. The ^[ ends insertion mode,
+and the line is updated to include the new string. Line 1 should look exactly
+like Line 2.
+
+Move the cursor to the beginning of Line 3 below and type {z^M}:
+
+Line 3: These lines are examples for the 'a' command.
+Line 4: These line are examples for the '
+
+We will change line four to look like line three by using the append command.
+We need to append an 's' to the word 'line'. Position the cursor on the 'e'
+of 'line'. You can do this in several ways, one way is the following:
+First, type {/line /^M}. This puts us on the word 'line' in Line 4
+(the blank in the search string is important!). Next, type {e}. The 'e' puts
+us at the end of the word. Now, type {as^[ (^[ is the escape character)}.
+The 'a' puts us in insert mode, AFTER the current character. We appended the
+'s', and the escape ^[ ended the insert mode.
+
+The difference between {i} (insert) and {a} (append) is that {i} begins
+inserting text BEFORE the cursor, and {a} begins inserting AFTER the cursor.
+
+Now type {Aa' command.^[}. The cursor is moved to the end of the line and the
+string following {A} is inserted into the text. Line 4 should now look like
+line 3.
+
+Just as {A} moves you to the end of the line to begin inserting, {I} would
+begin inserting at the FRONT of the line.
+
+To begin the insertion of a line after the cursor line, type {o}. To insert a
+line before the cursor line, type {O}. In other words {o123^[} is equivalent
+to {A^M123^[}, and {O123^[} is equivalent to {I123^M^[}. The text after the
+{o} or {O} is ended with an escape ^[.
+
+This paragraph contains information that is terminal dependent: you will just
+have to experiment to discover what your terminal does. Once in the insert
+mode, if you make a mistake in the typing, ^H will delete the previous
+character up to the beginning of the current insertion. ^W will delete the
+previous word, and one of ^U, @, or ^X will delete the current line (up to the
+beginning of the current insertion). You will need to experiment with ^U, @,
+and ^X to determine which works for your terminal.
+
+Section 23: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
+
+Position the cursor at the beginning of line 5 and {z^M}:
+
+Line 5: The line as it should be.
+Line 6: The line as it shouldn't be.
+
+To make Line 6 like Line 5, we have to delete the 'n', the apostrophe, and the
+'t'. There are several ways to position ourselves at the 'n'. Choose
+whichever one suits your fancy:
+
+{/n't/^M}
+{^M7w6l} or {^M7w6 } (note the space)
+{^M3fn} (finds the 3rd 'n' on the line)
+
+Now {xxx} will delete the three characters, as will {3x}.
+
+Note that {X} deletes the character just BEFORE the cursor, as opposed
+to the character AT the cursor.
+
+Position the cursor at line 7 and {z^M}:
+
+Line 7: The line as it would be.
+Line 8: The line as it could be.
+
+To change line 8 into line 7 we need to change the 'c' in 'could' into a 'w'.
+The 'r' (replace) command was designed for this. Typing {rc} is the same as
+typing {xic^[} (i.e. delete the 'bad' character and insert the correct
+new character). Therefore, assuming that you have positioned the cursor on the
+'c' of 'could', the easiest way to change 'could' into 'would' is {rw}.
+
+If you would like to now change the 'would' into 'should', use the substitute
+command, 's': {ssh^[}. The difference between 'r' and 's' is that 'r'
+(replace) replaces the current character with another character, while 's'
+(substitute) substitutes the current character with a string, ended with an
+escape.
+
+The capital letter version of replace {R} replaces each character by a
+character one at a time until you type an escape, ^[. The 'S' command
+substitutes the whole line.
+
+Position your cursor at the beginning of line 9 and {z^M}.
+
+Line 9: Love is a many splendored thing.
+Line 10: Love is a most splendored thing.
+
+To change line 10 into line 9, position the cursor at the beginning of 'most',
+and type {Rmany^[}.
+
+You may have noticed that, when inserting text, a new line is formed by typing
+{^M}. When changing, replacing, or substituting text you can make a new line
+by typing {^M}. However, neither {x} nor {X} will remove ^M to make two lines
+into one line. To do this, position the cursor on the first of the two lines
+you wish to make into a single line and type {J} (uppercase J for 'Join').
+
+Section 24: {u} {U}
+
+Finally, before we review, let's look at the undo command. Position
+your cursor on line 11 below and {z^M}.
+
+Line 11: The quick brown fox jumped over the lazy hound dog.
+Line 12: the qwick black dog dumped over the laxy poune fox.
+
+Type the following set of commands, and observe carefully the effect of each
+of the commands:
+
+{/^Line 12:/^M} {ft} {rT} {fw} {ru} {w} {Rbrown fox^[} {w} {rj}
+{fx} {rz} {w} {Rhound dog^[}
+
+Line 12 now matches line 11. Now type {U} - capital 'U'. And line 12 now
+looks like it did before you typed in the command strings. Now type:
+
+{ft} {rT} {fw} {ru} {^M} {^M}
+
+and then type {u}: the cursor jumps back to the line containing the second
+change you made and 'undoes' it. That is, {U} 'undoes' all the changes on the
+line, and {u} 'undoes' only the last change. Type {u} several times and
+observe what happens: {u} can undo a previous {u}!
+
+Caveat: {U} only works as long as the cursor is still on the line. Move the
+cursor off the line and {U} will have no effect, except to possibly beep at
+you. However, {u} will undo the last change, no matter where it occurred.
+
+Section 25: review
+
+At this point, you have all the commands you need in order to make use of vi.
+The remainder of this tutorial will discuss variations on these commands as
+well as introduce new commands that make the job of editing more efficient.
+Here is a brief review of the basic commands we have covered. They are listed
+in the order of increasing complexity and/or decreasing necessity (to say that
+a command is less necessary is not to say that it is less useful!). These
+commands allow you to comfortably edit any text file. There are other
+commands that will make life easier but will require extra time to learn,
+obviously. You may want to consider setting this tutorial aside for several
+weeks and returning to it later after gaining experience with vi and getting
+comfortable with it. The convenience of some of the more exotic commands may
+then be apparent and worth the extra investment of time and effort
+required to master them.
+
+to get into the editor from Unix: {vi filename}
+to exit the editor
+ saving all changes {ZZ} or {:wq^M}
+ throwing away all changes {:q!^M}
+ when no changes have been made {:q^M}
+save a file without exiting the editor {:w^M}
+write the file into another file {:w filename^M}
+insert text
+ before the cursor {i ...text... ^[}
+ at the beginning of the line {I ...text... ^[}
+ after the cursor (append) {a ...text... ^[}
+ at the end of the line {A ...text... ^[}
+ after the current line {o ...text... ^[}
+ before the current line {O ...text... ^[}
+delete the character ...
+ under the cursor {x}
+ to the left of the cursor {X}
+delete n characters {nx} or {nX} (for n a number)
+make two lines into one line (Join) {J}
+find a string in the file ...
+ searching forward {/ ...string... /^M}
+ searching backwards {? ...string... ?^M}
+repeat the last search command {n}
+repeat the last search command in the
+ opposite direction {N}
+find the character c on this line ...
+ searching forward {fc}
+ searching backward {Fc}
+repeat the last 'find character' command {;}
+replace a character with character x {rx}
+substitute a single character with text {s ...text... ^[}
+substitute n characters with text {ns ...text... ^[}
+replace characters one-by-one with text {R ...text... ^[}
+undo all changes to the current line {U}
+undo the last single change {u}
+move forward in the file a "screenful" {^F}
+move back in the file a "screenful" {^B}
+move forward in the file one line {^M} or {+}
+move backward in the file one line {-}
+move to the beginning of the line {0}
+move to the end of the line {$}
+move forward one word {w}
+move forward one word, ignoring punctuation {W}
+move forward to the end of the next word {e}
+to the end of the word, ignoring punctuation{E}
+move backward one word {b}
+move back one word, ignoring punctuation {B}
+return to the last line modified {''}
+scroll a line onto the top of the screen {^Y}
+scroll a line onto the bottom of the screen {^E}
+move "up" in the file a half-screen {^U}
+move "down" in the file a half-screen {^D}
+move the cursor to the top screen line {H}
+move the cursor to the bottom screen line {L}
+move the cursor to the middle line {M}
+move LEFT one character position {h} or {^H}
+move RIGHT one character position {l} or { }
+move UP in the same column {k} or {^P}
+move DOWN in the same column {j} or {^N}
+mark the current position, name it x {mx}
+move to the line marked/named x {'x}
+move to the character position named x {`x}
+move to the beginning of the file {1G}
+move to the end of the file {G}
+move to line 23 in the file {23G}
+repaint the screen with the cursor line
+ at the top of the screen {z^M}
+ in the middle of the screen {z.}
+ at the bottom of the screen {z-}
+
+More information on vi can be found in the file vi.advanced, which you can
+peruse at your leisure. From UNIX, type {vi.tut advanced^M}.
diff --git a/usr.bin/vi/docs/tutorial/vi.tut.csh b/usr.bin/vi/docs/tutorial/vi.tut.csh
new file mode 100644
index 000000000000..01554bc4e5fd
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.tut.csh
@@ -0,0 +1,24 @@
+#!/bin/csh -f
+#
+# This makes the user's EXINIT variable set to the 'correct' things.
+# I don't know what will happen if they also have a .exrc file!
+#
+# XXX
+# Make sure that user is using a 24 line window!!!
+#
+if ($1 != "beginner" && $1 != "advanced") then
+ echo Usage: $0 beginner or $0 advanced
+ exit
+endif
+
+if ($?EXINIT) then
+ set oexinit="$EXINIT"
+ setenv EXINIT 'se ts=4 wm=8 sw=4'
+endif
+
+vi vi.{$1}
+
+onintr:
+ if ($?oexinit) then
+ setenv EXINIT "$oexinit"
+endif
diff --git a/usr.bin/vi/docs/vi.1 b/usr.bin/vi/docs/vi.1
new file mode 100644
index 000000000000..d13042c7f17e
--- /dev/null
+++ b/usr.bin/vi/docs/vi.1
@@ -0,0 +1,452 @@
+.\" Copyright (c) 1994
+.\" 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.
+.\"
+.\" @(#)vi.1 8.3 (Berkeley) 3/19/94
+.\"
+.Dd "March 19, 1994"
+.Dt EX/VI 1
+.Os
+.Sh NAME
+.Nm ex, vi, view
+.Nd text editors
+.Sh SYNOPSIS
+.Nm \&ex
+.Op Fl eFlRsv
+.Op Fl c Ar cmd
+.Op Fl r Ar file
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Fl x Ar \&aw
+.Op Ar "file ..."
+.Nm \&vi
+.Op Fl eFlRv
+.Op Fl c Ar cmd
+.Op Fl r Ar file
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Fl x Ar \&aw
+.Op Ar "file ..."
+.Nm view
+.Op Fl eFlRv
+.Op Fl c Ar cmd
+.Op Fl r Ar file
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Fl x Ar \&aw
+.Op Ar "file ..."
+.Sh DESCRIPTION
+.Nm \&Vi
+is a screen oriented text editor.
+.Nm \&Ex
+is a line-oriented text editor.
+.Nm \&Ex
+and
+.Nm \&vi
+are different interfaces to the same program,
+and it is possible to switch back and forth during an edit session.
+.Nm View
+is the equivalent of using the
+.Fl R
+(read-only) option of
+.Nm \&vi .
+.Pp
+This manual page is the one provided with the
+.Nm ex/vi
+versions of the
+.Nm ex/vi
+text editors.
+.Nm Ex/vi
+are intended as bug-for-bug compatible replacements for the original
+Fourth Berkeley Software Distribution (4BSD)
+.Nm \&ex
+and
+.Nm \&vi
+programs.
+For the rest of this manual page,
+.Nm ex/vi
+is used only when it's necessary to distinguish it from the historic
+implementations of
+.Nm ex/vi .
+.Pp
+This manual page is intended for users already familiar with
+.Nm ex/vi .
+Anyone else should almost certainly read a good tutorial on the
+editor before this manual page.
+If you're in an unfamiliar environment, and you absolutely have to
+get work done immediately, read the section near the end of this
+manual page, entitled FAST STARTUP.
+It's probably enough to get you going.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Execute
+.Ar cmd
+immediately after starting the edit session.
+Particularly useful for initial positioning in the file, however
+.Ar cmd
+is not limited to positioning commands.
+This is the POSIX 1003.2 interface for the historic
+.Dq "+cmd"
+syntax.
+.Nm Ex/vi
+supports both the old and new syntax.
+.It Fl e
+Start editing in ex mode, as if the command name were
+.Nm \&ex .
+.It Fl F
+Don't copy the entire file when first starting to edit.
+(The default is to make a copy in case someone else modifies
+the file during your edit session.)
+.It Fl l
+List the files that may be recovered using the
+.Fl r
+option of
+.Nm \&vi .
+This is the new interface for the historic syntax of the
+.Fl r
+option without a file argument.
+.Nm Ex/vi
+supports both the old and new syntax.
+.It Fl R
+Start editing in read-only mode, as if the command name was
+.Nm view ,
+or the readonly option was set.
+.It Fl r
+Recover the specified file.
+.It Fl s
+Enter batch mode; applicable only to
+.Nm \&ex
+edit sessions.
+Batch mode is useful when running
+.Nm \&ex
+scripts.
+Prompts, informative messages and other user oriented message
+are turned off,
+and no startup files or environmental variables are read.
+This is the POSIX 1003.2 interface for the historic
+.Dq \&\-
+argument.
+.Nm \&Ex/vi
+supports both the old and new syntax.
+.It Fl t
+Start editing at the specified tag.
+(See
+.Xr ctags 1 ).
+.It Fl w
+Set the initial window size to the specified number of lines.
+.It Fl v
+Start editing in vi mode, as if the command name was
+.Nm \&vi
+or
+.Nm view .
+.It Fl x
+Reserved for X11 interfaces.
+.Em "No X11 support is currently implemented."
+.El
+.Pp
+.Nm Ex/vi
+exit 0 on success, and greater than 0 if an error occurs.
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width XXXX -compact
+.It Ev COLUMNS
+The number of columns on the screen.
+This value overrides any system or terminal specific values.
+If the COLUMNS environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy columns
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev EXINIT
+A list of
+.Nm \&ex
+startup commands.
+.It Ev HOME
+The user's home directory, used as the initial directory path
+for the startup
+.Pa $HOME/.exrc
+file.
+This value is also used as the default directory for the
+.Nm \&vi
+.Sy \&cd
+command.
+.It Ev LINES
+The number of rows on the screen.
+This value overrides any system or terminal specific values.
+If the LINES environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy lines
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev SHELL
+The user's shell of choice (see also the
+.Sy shell
+option).
+.It Ev TERM
+The user's terminal type.
+The default is the type
+.Dq unknown .
+If the TERM environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy term
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev TMPDIR
+The location used to stored temporary files (see also the
+.Sy directory
+option).
+.El
+.Sh SET OPTIONS
+#include <set.opt.roff>
+.Sh FAST STARTUP
+This section will tell you the minimum amount that you need to
+do simple editing tasks using
+.Nm \&vi .
+If you've never used any screen editor before, you're likely to have
+problems even with this simple introduction.
+In that case you should find someone that already knows
+.Nm \&vi
+and have them walk you through this section.
+.Pp
+.Nm \&Vi
+is a screen editor.
+This means that it takes up almost the entire screen, displaying part
+of the file on each screen line, except for the last line of the screen.
+The last line of the screen is used for you to give commands to
+.Nm \&vi ,
+and for
+.Nm \&vi
+to give information to you.
+.Pp
+The other fact that you need to understand is that
+.Nm \&vi
+is a modeful editor, i.e. you are either entering text or you
+are executing commands, and you have to be in the right mode
+to do one or the other.
+You will be in command mode when you first start editing a file.
+There are commands that switch you into input mode.
+There is only one key that takes you out of input mode,
+and that is the <escape> key.
+(Key names are written using less-than and greater-than signs, e.g.
+<escape> means the
+.Dq escape
+key, usually labeled
+.Dq esc
+on your terminal's keyboard.)
+If you're ever confused as to which mode you're in,
+keep entering the <escape> key until
+.Nm \&vi
+beeps at you.
+(Generally,
+.Nm \&vi
+will beep at you if you try and do something that's not allowed.
+It will also display error messages.)
+.Pp
+To start editing a file, enter the command
+.Dq Li "vi file_name<carriage-return>" .
+The command you should enter as soon as you start editing is
+.Dq Li ":set verbose showmode<carriage-return>" .
+This will make the editor give you verbose error messages and display
+the current mode at the bottom of the screen.
+.Pp
+The commands to move around the file are:
+.Bl -tag -width XXXX -compact
+.It Sy h
+Move the cursor left one character.
+.It Sy j
+Move the cursor down one line.
+.It Sy k
+Move the cursor up one line.
+.It Sy l
+Move the cursor right one character.
+.It Sy <cursor-arrows>
+The cursor arrow keys should work, too.
+.It Sy /text<carriage-return>
+Search for the string
+.Dq text
+in the file, and move the cursor to its first character.
+.El
+.Pp
+The commands to enter new text are:
+.Bl -tag -width XXXX -compact
+.It Sy a
+Append new text,
+.Em after
+the cursor.
+.It Sy i
+Insert new text,
+.Em before
+the cursor.
+.It Sy o
+Open a new line below the line the cursor is on, and start
+entering text.
+.It Sy O
+Open a new line above the line the cursor is on, and start
+entering text.
+.It Sy <escape>
+Once you've entered input mode using the one of the
+.Sy \&a ,
+.Sy \&i ,
+.Sy \&O ,
+or
+.Sy \&o
+commands, use
+.Sy <escape>
+to quit entering text and return to command mode.
+.El
+.Pp
+The commands to copy text are:
+.Bl -tag -width XXXX -compact
+.It Sy yy
+Copy the line the cursor is on.
+.It Sy p
+Append the copied line after the line the cursor is on.
+.El
+.Pp
+The commands to delete text are:
+.Bl -tag -width XXXX -compact
+.It Sy dd
+Delete the line the cursor is on.
+.It Sy x
+Delete the character the cursor is on.
+.El
+.Pp
+The commands to write the file are:
+.Bl -tag -width XXXX -compact
+.It Sy :w<carriage-return>
+Write the file back to the file with the name that you originally used
+as an argument on the
+.Nm \&vi
+command line.
+.It Sy :w file_name<carriage-return>
+Write the file back to the file with the name
+.Dq file_name .
+.El
+.Pp
+The commands to quit editing and exit the editor are:
+.Bl -tag -width XXXX -compact
+.It Sy :q<carriage-return>
+Quit editing and leave vi (if you've modified the file, but not
+saved your changes,
+.Nm \&vi
+will refuse to quit).
+.It Sy :q!<carriage-return>
+Quit, discarding any modifications that you may have made.
+.El
+.Pp
+One final caution.
+Unusual characters can take up more than one column on the screen,
+and long lines can take up more than a single screen line.
+The above commands work on
+.Dq physical
+characters and lines, i.e. they affect the entire line no matter
+how many screen lines it takes up and the entire character no matter
+how many screen columns it takes up.
+.Sh BUGS
+See the file
+.Pa vi/docs/bugs.current
+for a list of the known bugs in this version.
+.Sh FILES
+.Bl -tag -width /var/tmp/vi.recover -compact
+.It Pa /bin/sh
+The default user shell.
+.It Pa /etc/vi.exrc
+System-wide vi startup file.
+.It Pa /tmp
+Temporary file directory.
+.It Pa /var/tmp/vi.recover
+Recovery file directory.
+.It Pa $HOME/.exrc
+user's home directory startup file.
+.It Pa .exrc
+local directory startup file.
+.El
+.Sh SEE ALSO
+.Xr ctags 1 ,
+.Xr vi-ref 1 ,
+.Xr more 1 ,
+.Xr curses 3 ,
+.Xr dbopen 3
+.sp
+The
+.Dq "Vi Quick Reference"
+card.
+.sp
+.Dq "An Introduction to Display Editing with Vi" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents" .
+.sp
+.Dq "Edit: A tutorial" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents" .
+.sp
+.Dq "\&Ex Reference Manual (Version 3.7)" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents" .
+.Pp
+.Nm Nroff/troff
+source for the previous three documents are distributed with
+.Nm ex/vi
+in the
+.Pa vi/docs/USD.doc
+directory of the
+.Nm ex/vi
+source code.
+.sp
+The files
+.Dq autowrite ,
+.Dq input ,
+.Dq quoting ,
+and
+.Dq structures ,
+found in the
+.Pa vi/docs/internals
+directory of the
+.Nm ex/vi
+source code.
+.Sh HISTORY
+The
+.Nm ex/vi
+replacements for the
+.Nm ex/vi
+editor first appeared in 4.4BSD.
+.Sh STANDARDS
+.Nm \&Ex/vi
+is close to IEEE Std1003.2 (``POSIX'').
+That document differs from historical
+.Nm ex/vi
+practice in several places; there are changes to be made on both sides.
diff --git a/usr.bin/vi/docs/vi.ref b/usr.bin/vi/docs/vi.ref
new file mode 100644
index 000000000000..d2d79bd204ed
--- /dev/null
+++ b/usr.bin/vi/docs/vi.ref
@@ -0,0 +1,523 @@
+.\" Copyright (c) 1994
+.\" 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.
+.\"
+.\" @(#)vi.ref 8.19 (Berkeley) 3/18/94
+.\"
+.Dd "March 18, 1994"
+.Dt "EX/VI REFERENCE MANUAL" 1
+.Os
+.Sh NAME
+.Nm ex, vi, view
+.Nd text editors
+.Sh DESCRIPTION
+.Nm \&Vi
+is a screen oriented text editor.
+.Nm \&Ex
+is a line-oriented text editor.
+.Nm \&Ex
+and
+.Nm \&vi
+are different interfaces to the same program,
+and it is possible to switch back and forth during an edit session.
+.Nm View
+is the equivalent of using the
+.Fl R
+(read-only) option of
+.Nm \&vi .
+.Pp
+This reference manual is the one provided with the
+.Nm ex/vi
+versions of the
+.Nm ex/vi
+text editors.
+.Nm Ex/vi
+are intended as bug-for-bug compatible replacements for the original
+Fourth Berkeley Software Distribution (4BSD)
+.Nm \&ex
+and
+.Nm \&vi
+programs.
+This reference manual is accompanied by a traditional-style manual page.
+That manual page describes the functionality found in
+.Nm ex/vi
+in far less detail than the description here.
+In addition, it describes the system interface to
+.Nm ex/vi ,
+e.g. command line options, environmental variables, and similar things.
+.Pp
+This reference is intended for users already familiar with
+.Nm ex/vi .
+Anyone else should almost certainly read a good tutorial on the
+editor first.
+If you're in an unfamiliar environment, and you absolutely have to
+get work done immediately, see the section entitled FAST STARTUP
+in the manual page.
+It's probably enough to get you going.
+.Pp
+For the rest of this reference,
+.Nm ex/vi
+is used only when it's necessary to distinguish it from the historic
+implementations of
+.Nm ex/vi .
+.Sh ADDITIONAL FEATURES
+There are a few features in
+.Nm ex/vi
+that are not found in historic versions of
+.Nm ex/vi .
+A list of those features is as follows:
+.Bl -tag -width indent
+.It "8-bit clean data, large lines, files"
+.Nm \&Vi/ex
+will edit any format file.
+Line lengths are limited by available memory,
+and file sizes are limited by available disk space.
+The command
+.Dq "^Vx[0-9A-Fa-f]* ,"
+in input mode, will insert any
+legal character value into the text.
+.It "Split screens"
+The command
+.Dq ":sp[lit] [file ...]"
+splits the screen in vi mode.
+The key
+.Dq "^W"
+switches between the foreground screens,
+and the
+.Dq ":resize count"
+command can be used to grow or shrink a particular screen.
+.It "Background and foreground screens"
+The command
+.Dq ":bg"
+backgrounds the current screen,
+and the command
+.Dq ":fg [file]"
+foregrounds the backgrounded screen
+that is editing the specified file, or, by default, the first background
+screen on the queue.
+The command
+.Dq ":di[splay] s[creens]"
+lists the background screens.
+.It "Shell screens"
+The command
+.Dq ":sc[ript] [file ...]"
+runs a shell in the screen.
+Editing is unchanged, with the exception that a <carriage-return>
+enters the current line (stripped of any prompt) as input to the
+shell.
+.It "Tag stacks"
+Tags are now maintained in a stack.
+The command
+.Dq "^T"
+returns to the previous tag location.
+The command
+.Dq ":tagpop [number \| file]"
+returns to the most recent tag
+location by default, or, optionally to a specific tag number in the
+tag stack, or the most recent tag from the specified file.
+Use the command
+.Dq ":di[splay] t[ags]"
+to view the tags stack.
+The command
+.Dq ":tagtop"
+returns to the top of the tag stack.
+.It "New displays"
+The command
+.Dq ":di[splay] b[uffers] \| s[creens] \| t[ags]"
+can be
+used to display, respectively, the current cut buffers,
+the backgrounded screens, and the tags stack.
+.It "Infinite undo"
+The changes made during an edit session may be rolled backward and
+forward.
+A '.' command immediately after a 'u' command continues either forward
+or backward depending on whether the 'u' command was an undo or a redo.
+.It "Usage information"
+The command
+.Dq ":exu[sage] [cmd]"
+and
+.Dq "viu[sage] [key]"
+provide usage
+information for all of the ex and vi commands by default, or, optionally,
+for a specific command or key.
+.It "Extended regular expressions"
+The
+.Dq ":set extended"
+command treats search and other command regular
+expressions as extended (egrep(1) style) regular expressions.
+.It "Word search"
+The command
+.Dq "^A"
+searches for the word referenced by the cursor.
+.It "Number increment"
+The command
+.Dq "#"
+increments the number referenced by the cursor.
+.It "Previous file"
+The command
+.Dq ":prev[ious][!]"
+edits the previous file from the
+argument list.
+.It "Left-Right scrolling"
+The command
+.Dq ":set leftright"
+makes
+.Nm vi
+do left-right screen scrolling, instead of the traditional
+.Nm \&vi
+line wrapping.
+.Sh RECOVERY
+There is no recovery program for
+.Nm vi ,
+nor does
+.Nm vi
+run setuid.
+Users may recover any file which they may read, and the superuser
+may recover any edit session.
+.Pp
+Edit sessions are backed by files in
+.Pa /var/tmp/vi.recover ,
+and are named
+.Dq "vi.XXXX" ,
+where
+.Dq "XXXX"
+is a number related to the process id.
+When a file is first modified, a second file, which contains an
+email message for the user, is created, and is named
+.Dq "recover.XXXX" ,
+where, again,
+.Dq "XXXX"
+is associated with the process id.
+Both files are removed at the end of a normal edit session,
+but will remain if the edit session is abnormally terminated
+or the user enters the ex/vi
+.Dq "preserve"
+command.
+The use of the
+.Pa /var/tmp
+directory may be changed setting the
+.Sy recdir
+option in the user's or system startup information.
+.Pp
+The recovery directory should have the
+.Dq "sticky-bit"
+set so that only the owners of files may remove them.
+If this is not possible on the system, then a pseudo-user should
+own the recovery directory.
+The recovery directory must be both read and write-able by
+any user.
+.Pp
+The recovery file has all of the necessary information in it to enable the
+user to recover the edit session.
+In addition, it has all of the necessary email headers for sendmail.
+When the system is rebooted, all of the files in
+.Pa /var/tmp/vi.recover
+named
+.Dq "recover.XXXX"
+should be sent by email,
+using the
+.Fl t
+flag of sendmail (or a similar mechanism in other mailers).
+A simple way to do this is to insert the following script into your
+.Pa /etc/rc.local
+(or other startup) file:
+.ne 7v
+.Bd -literal -offset indent -compact
+# Recover vi editor files.
+virecovery=`echo /var/tmp/vi.recover/recover.*`
+if [ "$virecovery" != "/var/tmp/vi.recover/recover.*" ]; then
+ echo 'Recovering vi editor sessions'
+ for i in $virecovery; do
+ sendmail -t < $i
+ done
+fi
+.Ed
+.Pp
+If
+.Nm ex/vi
+receives a hangup (SIGHUP) signal, it will email the recovery
+information to the user itself.
+.Pp
+If you don't have the sendmail program on your system, the source file
+.Pa vi/recover.c
+will have to be modified to use your local mail delivery programs.
+.Sh STARTUP INFORMATION
+.Nm Ex/vi
+interprets one of two possible environmental variables and reads up
+to three of five possible files during startup.
+The variables and files are expected to contain
+.Nm \&ex
+commands, not
+.Nm \&vi
+commands.
+In addition, they are interpreted
+.Em before
+the file to be edited is read, and therefore many
+.Nm \&ex
+commands may not be used.
+Generally, any command that requires output to the screen or that
+needs a file upon which to operate, will cause an error if included
+in a startup file or environmental variable.
+.Pp
+First, the file
+.Pa /etc/vi.exrc
+is read.
+Second, the environmental variable
+.Ev EXINIT
+is interpreted.
+Third, if
+.Ev EXINIT
+was not set, the file
+.Pa $HOME/.exrc
+is read.
+Fourth, the file
+.Pa .exrc
+is read.
+.Pp
+Startup files will not be read if they are owned by anyone other
+than the real user-id of the user running
+.Nm \&vi ,
+(or by
+.Dq root
+in the case of the file
+.Pa /etc/vi.exrc )
+or if they are writable by anyone other than the owner.
+Home directory startup file (i.e.
+.Pa $HOME/.exrc )
+will not be read if the
+.Dq HOME
+environmental variable is not set.
+The local startup file (i.e.
+.Pa .exrc )
+will not be read if the
+.Sy exrc
+option is turned off in the
+.Pa /etc/vi.exrc
+or
+.Pa $HOME/.exrc
+files, or in the
+.Ev EXINIT
+environmental variable.
+It is not an error for any of the startup environmental variables
+or files not to exist.
+.Pp
+Because the
+.Nm \&ex
+command set supported by
+.Nm ex/vi
+is a superset of the command set supported by most historical implementations
+of
+.Nm \&ex ,
+.Nm ex/vi
+can use the startup files created for the historical implementations,
+but the converse is often not true.
+.Sh SIZING THE SCREEN
+The size of the screen can be set in a number of ways.
+.Nm Ex/vi
+takes the following steps until values are obtained for both the
+number of rows and number of columns in the screen.
+.sp
+.Bl -enum -compact
+.It
+If the environmental variable
+.Ev LINES
+exists, it is used to specify the number of rows in the screen.
+.It
+If the environmental variable
+.Ev COLUMNS
+exists, it is used to specify the number of columns in the screen.
+.It
+The TIOCGWINSZ
+.Xr ioctl 2
+is attempted on the standard error file descriptor.
+.It
+The termcap entry is checked for the
+.Dq \&li
+entry (rows) and the
+.Dq \&co
+entry (columns).
+.It
+The number of rows is set to 24, and the number of columns is set
+to 80.
+.El
+.Pp
+If a window change size signal (SIGWINCH) is received,
+the same steps are taken with the exception that the first two steps
+are skipped.
+.Sh REGULAR EXPRESSIONS AND REPLACEMENT STRINGS
+Regular expressions are used in line addresses,
+as the first part of
+.Sy substitute ,
+.Sy global ,
+and
+.Sy vglobal
+commands,
+and in search patterns.
+.Pp
+The regular expressions supported by
+.Nm \&ex
+and
+.Nm \&vi
+are, by default, the Basic Regular Expressions (BRE's) described in the
+IEEE POSIX Standard 1003.2.
+The
+.Sy extended
+option causes all regular expressions to be interpreted as the Extended
+Regular Expressions (ERE's) described by the same standard.
+(See
+.Xr re_format 7
+for more information.
+Generally speaking, BRE's are
+.Xr ed 1
+and
+.Xr grep 1
+style regular expressions, and ERE's are
+.Xr egrep 1
+style regular expressions.)
+.Pp
+There are some special strings and characters that can be used in
+RE's:
+.Bl -enum -compact
+.It
+An empty RE (e.g.
+.Dq \&// )
+is equivalent to the last RE used.
+.It
+The construct
+.Dq \e<
+matches the beginning of a word.
+.It
+The construct
+.Dq \e>
+matches the end of a word.
+.It
+The character
+.Dq \&~
+matches the replacement part of the last
+.Sy substitute
+command.
+.El
+.Pp
+When the
+.Sy magic
+option is
+.Em not
+set,
+the only characters with special meanings are
+.Dq \&^
+at the beginning of an RE,
+.Dq \&$
+at the end of an RE, and the escaping character
+.Dq \&\e .
+The characters
+.Dq \&. ,
+.Dq \&* ,
+.Dq \&[ ,
+and
+.Dq \&~
+are treated as ordinary characters unless preceded by a
+.Dq \&\e ;
+when preceded by a
+.Dq \&\e
+they regain their special meaning.
+.Pp
+Replacement strings are the second part of a
+.Sy substitute
+command.
+.Pp
+The character
+.Dq \&&
+(or
+.Dq \e&
+if the
+.Sy magic
+option is
+.Em not
+set) in the replacement string stands for the text matched by the RE
+that's being replaced.
+The character
+.Dq \&~
+(or
+.Dq \e~
+if the
+.Sy magic
+option is
+.Em not
+set) stands for the replacement part of the previous
+.Sy substitute
+command.
+.Pp
+The string
+.Dq \e# ,
+where
+.Dq \&#
+is an integer value from 1 to 9, stands for the text matched by
+the portion of the RE enclosed in the #'th set of escaped parentheses,
+e.g.
+.Dq \e(
+and
+.Dq \e) .
+For example,
+.Dq "s/abc\e(.*\e)def/\e1/"
+deletes the strings
+.Dq abc
+and
+.Dq def
+from the matched pattern.
+.Pp
+The strings
+.Dq \el ,
+.Dq \eu ,
+.Dq \eL ,
+and
+.Dq \eU
+can be used to modify the case of elements in the replacement string.
+The string
+.Dq \el
+causes the next character to be converted to lowercase; the string
+.Dq \eu
+behaves similarly, but converts to uppercase.
+The strings
+.Dq \eL
+causes characters up to the end of the string or the next occurrence of
+the strings
+.Dq \ee
+or
+.Dq \eE
+to be converted to lowercase; the string
+.Dq \eU
+behaves similarly, but converts to uppercase.
+.Pp
+In
+.Nm \&vi ,
+inserting a <control-M> into the replacement string will cause the
+matched line to be split into two lines at that point.
+.Sh SET OPTIONS
+#include <set.opt.roff>
diff --git a/usr.bin/vi/docs/vi.ref.txt b/usr.bin/vi/docs/vi.ref.txt
new file mode 100644
index 000000000000..e5fc627072db
--- /dev/null
+++ b/usr.bin/vi/docs/vi.ref.txt
@@ -0,0 +1,634 @@
+EX/VI REFERENCE MANUAL(1) BSD Reference Manual EX/VI REFERENCE MANUAL(1)
+
+NNAAMMEE
+ eexx,, vvii,, vviieeww - text editors
+
+DDEESSCCRRIIPPTTIIOONN
+ VVii is a screen oriented text editor. EExx is a line-oriented text editor.
+ EExx and vvii are different interfaces to the same program, and it is possi-
+ ble to switch back and forth during an edit session. VViieeww is the equiva-
+ lent of using the --RR (read-only) option of vvii.
+
+ This reference manual is the one provided with the nneexx//nnvvii versions of
+ the eexx//vvii text editors. NNeexx//nnvvii are intended as bug-for-bug compatible
+ replacements for the original Fourth Berkeley Software Distribution
+ (4BSD) eexx and vvii programs. This reference manual is accompanied by a
+ traditional-style manual page. That manual page describes the function-
+ ality found in eexx//vvii in far less detail than the description here. In
+ addition, it describes the system interface to eexx//vvii, e.g. command line
+ options, environmental variables, and similar things.
+
+ This reference is intended for users already familiar with eexx//vvii. Anyone
+ else should almost certainly read a good tutorial on the editor first.
+ If you're in an unfamiliar environment, and you absolutely have to get
+ work done immediately, see the section entitled FAST STARTUP in the manu-
+ al page. It's probably enough to get you going.
+
+ For the rest of this reference, nneexx//nnvvii is used only when it's necessary
+ to distinguish it from the historic implementations of eexx//vvii.
+
+AADDDDIITTIIOONNAALL FFEEAATTUURREESS
+ There are a few features in nneexx//nnvvii that are not found in historic ver-
+ sions of eexx//vvii. A list of those features is as follows:
+
+ 8-bit clean data, large lines, files
+ NNvvii//nneexx will edit any format file. Line lengths are limited by
+ available memory, and file sizes are limited by available disk
+ space. The command ``^Vx[0-9A-Fa-f]*'', in input mode, will in-
+ sert any legal character value into the text.
+
+ Split screens
+ The command ``:sp[lit] [file ...]'' splits the screen in vi mode.
+ The key ``^W'' switches between the foreground screens, and the
+ ``:resize count'' command can be used to grow or shrink a partic-
+ ular screen.
+
+ Background and foreground screens
+ The command ``:bg'' backgrounds the current screen, and the com-
+ mand ``:fg [file]'' foregrounds the backgrounded screen that is
+ editing the specified file, or, by default, the first background
+ screen on the queue. The command ``:di[splay] s[creens]'' lists
+ the background screens.
+
+ Shell screens
+ The command ``:sc[ript] [file ...]'' runs a shell in the screen.
+ Editing is unchanged, with the exception that a <carriage-return>
+ enters the current line (stripped of any prompt) as input to the
+ shell.
+
+ Tag stacks
+ Tags are now maintained in a stack. The command ``^T'' returns
+ to the previous tag location. The command ``:tagpop [number
+ file]'' returns to the most recent tag location by default, or,
+ optionally to a specific tag number in the tag stack, or the most
+ recent tag from the specified file. Use the command ``:di[splay]
+ t[ags]'' to view the tags stack. The command ``:tagtop'' returns
+
+ to the top of the tag stack.
+
+ New displays
+ The command ``:di[splay] b[uffers] s[creens] t[ags]'' can be
+ used to display, respectively, the current cut buffers, the back-
+ grounded screens, and the tags stack.
+
+ Infinite undo
+ The changes made during an edit session may be rolled backward
+ and forward. A '.' command immediately after a 'u' command con-
+ tinues either forward or backward depending on whether the 'u'
+ command was an undo or a redo.
+
+ Usage information
+ The command ``:exu[sage] [cmd]'' and ``viu[sage] [key]'' provide
+ usage information for all of the ex and vi commands by default,
+ or, optionally, for a specific command or key.
+
+ Extended regular expressions
+ The ``:set extended'' command treats search and other command
+ regular expressions as extended (egrep(1) style) regular expres-
+ sions.
+
+ Word search
+ The command ``^A'' searches for the word referenced by the cur-
+ sor.
+
+ Number increment
+ The command ``#'' increments the number referenced by the cursor.
+
+ Previous file
+ The command ``:prev[ious][!]'' edits the previous file from the
+ argument list.
+
+ Left-Right scrolling
+ The command ``:set leftright'' makes nnvvii do left-right screen
+ scrolling, instead of the traditional vvii line wrapping.
+
+RREECCOOVVEERRYY
+ There is no recovery program for nnvvii, nor does nnvvii run setuid. Users may
+ recover any file which they may read, and the superuser may recover any
+ edit session.
+
+ Edit sessions are backed by files in _/_v_a_r_/_t_m_p_/_v_i_._r_e_c_o_v_e_r, and are named
+ ``vi.XXXX'', where ``XXXX'' is a number related to the process id. When
+ a file is first modified, a second file, which contains an email message
+ for the user, is created, and is named ``recover.XXXX'', where, again,
+ ``XXXX'' is associated with the process id. Both files are removed at
+ the end of a normal edit session, but will remain if the edit session is
+ abnormally terminated or the user enters the ex/vi ``preserve'' command.
+ The use of the _/_v_a_r_/_t_m_p directory may be changed setting the rreeccddiirr op-
+ tion in the user's or system startup information.
+
+ The recovery directory should have the ``sticky-bit'' set so that only
+ the owners of files may remove them. If this is not possible on the sys-
+ tem, then a pseudo-user should own the recovery directory. The recovery
+ directory must be both read and write-able by any user.
+
+ The recovery file has all of the necessary information in it to enable
+ the user to recover the edit session. In addition, it has all of the
+ necessary email headers for sendmail. When the system is rebooted, all
+ of the files in _/_v_a_r_/_t_m_p_/_v_i_._r_e_c_o_v_e_r named ``recover.XXXX'' should be sent
+ by email, using the --tt flag of sendmail (or a similar mechanism in other
+ mailers). A simple way to do this is to insert the following script into
+
+ your _/_e_t_c_/_r_c_._l_o_c_a_l (or other startup) file:
+ virecovery=`echo /var/tmp/vi.recover/recover.*`
+ if [ "$virecovery" != "/var/tmp/vi.recover/recover.*" ]; then
+ echo 'Recovering vi editor sessions'
+ for i in $virecovery; do
+ sendmail -t < $i
+ done
+ fi
+
+ If eexx//vvii receives a hangup (SIGHUP) signal, it will email the recovery
+ information to the user itself.
+
+ If you don't have the sendmail program on your system, the source file
+ _n_v_i_/_r_e_c_o_v_e_r_._c will have to be modified to use your local mail delivery
+ programs.
+
+SSTTAARRTTUUPP IINNFFOORRMMAATTIIOONN
+ EExx//vvii interprets one of two possible environmental variables and reads up
+ to three of five possible files during startup. The variables and files
+ are expected to contain eexx commands, not vvii commands. In addition, they
+ are interpreted _b_e_f_o_r_e the file to be edited is read, and therefore many
+ eexx commands may not be used. Generally, any command that requires output
+ to the screen or that needs a file upon which to operate, will cause an
+ error if included in a startup file or environmental variable.
+
+ First, the file _/_e_t_c_/_v_i_._e_x_r_c is read. Second, the environmental variable
+ NEXINIT (or the variable EXINIT, if NEXINIT isn't set) is interpreted.
+ Third, if neither NEXINIT or EXINIT was set, the file _$_H_O_M_E_/_._n_e_x_r_c (or
+ the file _$_H_O_M_E_/_._e_x_r_c, if _$_H_O_M_E_/_._n_e_x_r_c doesn't exist) is read. Fourth,
+ the file _._n_e_x_r_c (or the file _._e_x_r_c, if _._n_e_x_r_c doesn't exist) is read.
+
+ Startup files will not be read if they are owned by anyone other than the
+ real user-id of the user running vvii, (or by ``root'' in the case of the
+ file _/_e_t_c_/_v_i_._e_x_r_c) or if they are writable by anyone other than the own-
+ er. Home directory startup files (i.e. _$_H_O_M_E_/_._n_e_x_r_c and _$_H_O_M_E_/_._e_x_r_c)
+ will not be read if the ``HOME'' environmental variable is not set. Lo-
+ cal startup files (i.e. _._n_e_x_r_c and _._e_x_r_c) will not be read if the eexxrrcc
+ option is turned off in the _/_e_t_c_/_v_i_._e_x_r_c, _$_H_O_M_E_/_._n_e_x_r_c, or _$_H_O_M_E_/_._e_x_r_c
+ files, or in the NEXINIT or EXINIT environmental variables. It is not an
+ error for any of the startup environmental variables or files not to ex-
+ ist.
+
+ Because the eexx command set supported by nneexx//nnvvii is a superset of the com-
+ mand set supported by most historical implementations of eexx, nneexx//nnvvii can
+ use the startup files created for the historical implementations, but the
+ converse is often not true.
+
+SSIIZZIINNGG TTHHEE SSCCRREEEENN
+ The size of the screen can be set in a number of ways. EExx//vvii takes the
+ following steps until values are obtained for both the number of rows and
+ number of columns in the screen.
+
+ 1. If the environmental variable LINES exists, it is used to specify
+ the number of rows in the screen.
+ 2. If the environmental variable COLUMNS exists, it is used to specify
+ the number of columns in the screen.
+ 3. The TIOCGWINSZ ioctl(2) is attempted on the standard error file de-
+ scriptor.
+ 4. The termcap entry is checked for the ``li'' entry (rows) and the
+ ``co'' entry (columns).
+ 5. The number of rows is set to 24, and the number of columns is set to
+ 80.
+
+ If a window change size signal (SIGWINCH) is received, the same steps are
+ taken with the exception that the first two steps are skipped.
+
+RREEGGUULLAARR EEXXPPRREESSSSIIOONNSS AANNDD RREEPPLLAACCEEMMEENNTT SSTTRRIINNGGSS
+ Regular expressions are used in line addresses, as the first part of
+ ssuubbssttiittuuttee, gglloobbaall, and vvgglloobbaall commands, and in search patterns.
+
+ The regular expressions supported by eexx and vvii are, by default, the Basic
+ Regular Expressions (BRE's) described in the IEEE POSIX Standard 1003.2.
+ The eexxtteennddeedd option causes all regular expressions to be interpreted as
+ the Extended Regular Expressions (ERE's) described by the same standard.
+ (See re_format(7) for more information. Generally speaking, BRE's are
+ ed(1) and grep(1) style regular expressions, and ERE's are egrep(1) style
+ regular expressions.)
+
+ There are some special strings and characters that can be used in RE's:
+ 1. An empty RE (e.g. ``//'') is equivalent to the last RE used.
+ 2. The construct ``\<'' matches the beginning of a word.
+ 3. The construct ``\>'' matches the end of a word.
+ 4. The character ``~'' matches the replacement part of the last
+ ssuubbssttiittuuttee command.
+
+ When the mmaaggiicc option is _n_o_t set, the only characters with special mean-
+ ings are ``^'' at the beginning of an RE, ``$'' at the end of an RE, and
+ the escaping character ``\''. The characters ``.'', ``*'', ``['', and
+ ``~'' are treated as ordinary characters unless preceded by a ``\''; when
+ preceded by a ``\'' they regain their special meaning.
+
+ Replacement strings are the second part of a ssuubbssttiittuuttee command.
+
+ The character ``&'' (or ``\&'' if the mmaaggiicc option is _n_o_t set) in the re-
+ placement string stands for the text matched by the RE that's being re-
+ placed. The character ``~'' (or ``\~'' if the mmaaggiicc option is _n_o_t set)
+ stands for the replacement part of the previous ssuubbssttiittuuttee command.
+
+ The string ``\#'', where ``#'' is an integer value from 1 to 9, stands
+ for the text matched by the portion of the RE enclosed in the #'th set of
+ escaped parentheses, e.g. ``\('' and ``\)''. For example,
+ ``s/abc\(.*\)def/\1/'' deletes the strings ``abc'' and ``def'' from the
+ matched pattern.
+
+ The strings ``\l'', ``\u'', ``\L'', and ``\U'' can be used to modify the
+ case of elements in the replacement string. The string ``\l'' causes the
+ next character to be converted to lowercase; the string ``\u'' behaves
+ similarly, but converts to uppercase. The strings ``\L'' causes charac-
+ ters up to the end of the string or the next occurrence of the strings
+ ``\e'' or ``\E'' to be converted to lowercase; the string ``\U'' behaves
+ similarly, but converts to uppercase.
+
+ In vvii, inserting a <control-M> into the replacement string will cause the
+ matched line to be split into two lines at that point.
+
+SSEETT OOPPTTIIOONNSS
+ There are a large number of options that may be set (or unset) to change
+ the editor's behavior. This section describes the options, their abbre-
+ viations and their default values.
+
+ In each entry below, the first part of the tag line is the full name of
+ the option, followed by any equivalent abbreviations. (Regardless of the
+ abbreviations, it is only necessary to use the minimum number of charac-
+ ters necessary to distinguish an abbreviation from all other commands for
+ it to be accepted, in nneexx//nnvvii. Historically, only the full name and the
+ official abbreviations were accepted by eexx//vvii. Using full names in your
+ startup files and environmental variables will probably make them more
+ portable.) The part in square brackets is the default value of the op-
+ tion. Most of the options are boolean, i.e. they are either on or off,
+ and do not have an associated value.
+
+
+ Options apply to both eexx and vvii modes, unless otherwise specified.
+
+ For information on modifying the options or to display the options and
+ their current values, see the ``set'' command in the Ex Commands section.
+ altwerase [off]
+ VVii only. Change how vvii does word erase during text input. When
+ this option is set, text is broken up into three classes: alphabet-
+ ic, numeric and underscore characters, other non-blank characters,
+ and blank characters. Changing from one class to another marks the
+ end of a word. In addition, the class of the first character
+ erased is ignored (which is exactly what you want when erasing
+ pathname components).
+ autoindent, ai [off]
+ If this option is set, whenever you create a new line (using the vvii
+ AA, aa, CC, cc, II, ii, OO, oo, RR, rr, SS, and ss commands, or the eexx aappppeenndd,
+ cchhaannggee, and iinnsseerrtt commands) the new line is automatically indented
+ to align the cursor with the first non-blank character of the line
+ from which you created it. Lines are indented using tab characters
+ to the extent possible (based on the value of the ttaabbssttoopp option)
+ and then using space characters as necessary. For commands insert-
+ ing text into the middle of a line, any blank characters to the
+ right of the cursor are discarded, and the first non-blank charac-
+ ter to the right of the cursor is aligned as described above.
+
+ The indent characters are themselves somewhat special. If you do
+ not enter more characters on the new line before moving moving to
+ another line, or entering <escape>, the indent character will be
+ deleted and the line will be empty. For example, if you enter
+ <carriage-return> twice in succession, the line created by the
+ first <carriage-return> will not have any characters in it, regard-
+ less of the indentation of the previous or subsequent line.
+
+ Indent characters also require that you enter additional erase
+ characters to delete them. For example, if you have an indented
+ line, containing only blanks, the first <word-erase> character you
+ enter will erase up to end of the indent characters, and the second
+ will erase back to the beginning of the line. (Historically, only
+ the ^^DD key would erase the indent characters. Both the ^^DD key and
+ the usual erase keys work in nnvvii ..)) In addition, if the cursor is
+ positioned at the end of the indent characters, the keys ``0^D''
+ will erase all of the indent characters for the current line, re-
+ setting the indentation level to 0. Similarly, the keys ``^^D''
+ (i.e. a carat followed by a <control-D>) will erase all of the in-
+ dent characters for the current line, leaving the indentation level
+ for future created lines unaffected.
+
+ Finally, if aauuttooiinnddeenntt is set, the SS and cccc commands change from
+ the first non-blank of the line to the end of the line, instead of
+ from the beginning of the line to the end of the line.
+ autoprint, ap [off]
+ EExx only. EExx only. Cause the current line to be automatically dis-
+ played after the eexx commands <<, >>, ccooppyy, ddeelleettee, jjooiinn, mmoovvee, ppuutt,
+ tt, UUnnddoo, and uunnddoo. This automatic display is suppressed during
+ gglloobbaall and vvgglloobbaall commands, and for any command where optional
+ flags are used to explicitly display the line.
+ autowrite, aw [off]
+ If this option is set, the vvii !! ^^^^ ^^]] and ^^ZZ commands, and the eexx
+ eeddiitt, nneexxtt, rreewwiinndd, ssttoopp, ssuussppeenndd, ttaagg, ttaaggppoopp, and ttaaggttoopp commands
+ automatically write the current file back to the current file name
+ if it has been modified since it was last written. If the write
+ fails, the command fails and goes no further.
+
+ Appending the optional force flag ``!'' to the eexx commands nneexxtt,
+ rreewwiinndd, ssttoopp, ssuussppeenndd, ttaagg, ttaaggppoopp, and ttaaggttoopp stops the automatic
+ write from being attempted.
+
+
+ (Historically, the nneexxtt command ignored the optional force flag.)
+ Note, the eexx commands eeddiitt, qquuiitt, sshheellll, and xxiitt are _n_o_t affected
+ by the aauuttoowwrriittee option.
+ beautify, bf [off]
+ If this option is set, all control characters that are not current-
+ ly being specially interpreted, other than <tab>, <newline>, and
+ <form-feed>, are discarded from commands read in by eexx from command
+ files, and from input text entered to vvii (either into the file or
+ to the colon command line). Text files read by eexx//vvii are _n_o_t af-
+ fected by the bbeeaauuttiiffyy option.
+ cdpath [environment variable CDPATH, or ``.'']
+ This option is used to specify a colon separated list of directo-
+ ries which are used as path prefixes for any relative path names
+ used as arguments for the ccdd command. The value of this option de-
+ faults to the value of the environmental variable CDPATH if it is
+ set, otherwise to the current directory. For compatibility with
+ the POSIX 1003.2 shell, the ccdd command does _n_o_t check the current
+ directory as a path prefix for relative path names unless it is ex-
+ plicitly specified. It may be so specified by entering an empty
+ string or a ``.'' into the CDPATH variable or the option value.
+ columns, co [80]
+ The number of columns in the screen. Setting this option causes
+ eexx//vvii to set (or reset) the environmental variable COLUMNS. See the
+ SCREEN SIZING section for more information.
+ comment [off]
+ VVii only. If the first non-empty line of the file begins with the
+ string ``/*'', this option causes vvii to skip to the end of that C
+ comment (probably a terribly boring legal notice) before displaying
+ the file.
+ directory, dir [environment variable TMPDIR, or /tmp]
+ The directory where temporary files are created. The environmental
+ variable TMPDIR is used as the default value if it exists, other-
+ wise _/_t_m_p is used.
+ edcompatible, ed [off]
+ This option causes the presence or absence of gg and cc suffixes on
+ ssuubbssttiittuuttee commands to be remembered, and to be toggled by repeat-
+ ing the suffices. The suffix rr makes the substitution be as in the
+ ~~ command, instead of like the && command.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ errorbells, eb [off]
+ EExx only. Causes eexx error messages to be preceded by a bell.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ exrc, ex [off]
+ If this option is turned off in the system or $HOME startup files,
+ the local startup files are never read (unless they are the same as
+ the system or $HOME startup files). Turning it on has no effect,
+ i.e. the normal checks for local startup files are performed, re-
+ gardless. See the STARTUP INFORMATION section for more informa-
+ tion.
+ extended [off]
+ This option causes all regular expressions to be treated as POSIX
+ 1003.2 extended regular expressions (which are similar to historic
+ egrep(1) style expressions).
+ flash [on]
+ This option causes the screen to flash instead of beeping the key-
+ board, on error, if the terminal has the capability.
+ hardtabs, ht [8]
+ This option defines the spacing between hardware tab settings, i.e.
+ the tab expansion done by the operating system and/or the terminal
+ itself. As nneexx//nnvvii never writes tabs to the terminal, unlike his-
+ toric versions of eexx//vvii, this option does not currently have any
+ affect.
+ ignorecase, ic [off]
+ This option causes regular expressions, both in eexx commands and in
+
+ searches, to be evaluated in a case-insensitive manner.
+ keytime [6]
+ The 10th's of a second eexx//vvii waits for a subsequent key to complete
+ a key mapping.
+ leftright [off]
+ VVii only. This option causes the screen to be scrolled left-right
+ to view lines longer than the screen, instead of the traditional vvii
+ screen interface which folds long lines at the right-hand margin of
+ the terminal.
+ lines, li [24]
+ VVii only. The number of lines in the screen. Setting this option
+ causes eexx//vvii to set (or reset) the environmental variable LINES.
+ See the Screen Sizing section for more information.
+ lisp [off]
+ VVii only. This option changes the behavior of the vvii ((, )), {{, }}, [[[[
+ and ]]]] commands to match the Lisp language. Also, the aauuttooiinnddeenntt
+ option's behavior is changed to be appropriate for Lisp.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ list [off]
+ This option causes lines to be displayed in an unambiguous fashion.
+ Specifically, tabs are displayed as control characters, i.e.
+ ``^I'', and the ends of lines are marked with a ``$'' character.
+ magic [on]
+ This option is on by default. Turning the mmaaggiicc option off causes
+ all regular expression characters except for ``^'' and ``$'', to be
+ treated as ordinary characters. To re-enable characters individu-
+ ally, when the mmaaggiicc option is off, precede them with an ``\''. See
+ the REGULAR EXPRESSIONS AND REPLACEMENT STRINGS section for more
+ information.
+ matchtime [7]
+ VVii only. The 10th's of a second eexx//vvii pauses on the matching char-
+ acter when the sshhoowwmmaattcchh option is set.
+ mesg [on]
+ This option allows other users to contact you using the talk(1) and
+ write(1) utilities, while you are editing. EExx//vvii does not turn
+ message on, i.e. if messages were turned off when the editor was
+ invoked, they will stay turned off. This option only permits you
+ to disallow messages for the edit session. See the mesg(1) utility
+ for more information.
+ modelines, modeline [off]
+ If the mmooddeelliinneess option is set, eexx//vvii has historically scanned the
+ first and last five lines of each file as it is read for editing,
+ looking for any eexx commands that have been placed in those lines.
+ After the startup information has been processed, and before the
+ user starts editing the file, any commands embedded in the file are
+ executed. Commands are recognized by the letters ``e'' or ``v''
+ followed by ``x'' or ``i'', at the beginning of a line or following
+ a tab or space character, and followed by a ``:'', an eexx command,
+ and another ``:''. This option is a security problem of immense
+ proportions, and should not be used under any circumstances.
+ _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_.
+ number, nu [off]
+ Precede each line displayed with its current line number.
+ open [on]
+ EExx only. If this option is not set, the ooppeenn and vviissuuaall commands
+ are disallowed.
+ optimize, opt [on]
+ VVii only. Throughput of text is expedited by setting the terminal
+ to no do automatic carriage returns when printing more than one
+ (logical) line of output, greatly speeding output on terminals
+ without addressable cursors when text with leading white space is
+ printed.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ paragraphs, para [IPLPPPQPP LIpplpipbp]
+ VVii only. Define additional paragraph boundaries for the {{ and }}
+ commands. The value of this option must be a character string con-
+ sisting of zero or more character pairs.
+
+ In the text to be edited, the character string <newline>.<char-
+ pair>, (where <char-pair> is one of the character pairs in the op-
+ tion's value) defines a paragraph boundary. For example, if the
+ option were set to ``LaA ##'', then all of the following additional
+ paragraph boundaries would be recognized:
+ <newline>.La
+ <newline>.A<space>
+ <newline>.##
+ prompt [on]
+ EExx only. This option causes eexx to prompt for command input with a
+ ``:'' character; when it's not set, no prompt is displayed.
+ readonly, ro [off]
+ This option causes a force flag to be required to attempt to write
+ the file back to the original file name. Setting this option is
+ equivalent to using the --RR command line option, or editing a file
+ which lacks write permission.
+ recdir [/var/tmp/vi.recover]
+ The directory where recovery files are stored.
+ redraw, re [off]
+ VVii only. The editor simulates (using great amounts of output), an
+ intelligent terminal on a dumb terminal (e.g. during insertions in
+ visual mode the characters to the right of the cursor are refreshed
+ as each input character is typed).
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ remap [on]
+ If this option is set, it's possible to define macros in terms of
+ other macros. Otherwise, each key is only remapped up to one time.
+ For example, if ``A'' is mapped to ``B'', and ``B'' is mapped to
+ ``C'', The keystroke ``A'' will be mapped to ``C'' if rreemmaapp is set,
+ and to ``B'' if it is not set.
+ remapmax [on]
+ If this option is set, a key may only be remapped 50 times. If it
+ is not set, a key may be remapped an infinite number of times, and
+ the editor can be placed into infinite loops.
+ report [5]
+ Set the threshold of the number of lines that need to be changed
+ before a message will be displayed to the user. The value is the
+ largest value about which the editor is silent, i.e. by default, 6
+ lines must change before the user is notified.
+ ruler [off]
+ VVii only. Display a row/column ruler on the colon command line.
+ scroll, scr [window / 2]
+ Set the number of lines scrolled by the vvii commands ^^DD and ^^UU.
+
+ Historically, the eexx zz command, when specified without a count,
+ used two times the size of the scroll value; the POSIX 1003.2 stan-
+ dard specified the window size, which is a better choice.
+ sections, sect [NHSHH HUnhsh]
+ VVii only. Define additional section boundaries for the [[[[ and ]]]]
+ commands. The sseeccttiioonnss option should be set to a character string
+ consisting of zero or more character pairs. In the text to be
+ edited, the character string <newline>.<char-pair>, (where <char-
+ pair> is one of the character pairs in the option's value), defines
+ a section boundary in the same manner that ppaarraaggrraapphh option bound-
+ aries are defined.
+ shell, sh [environment variable SHELL, or /bin/sh]
+ Select the shell used by the editor. The specified path is the
+ pathname of the shell invoked by the vvii !! shell escape command and
+ by the eexx sshheellll command. This program is also used to resolve any
+ shell meta-characters in eexx commands.
+ shiftwidth, sw [8]
+ Set the autoindent and shift command indentation width. This width
+ is used by the aauuttooiinnddeenntt option and by the <<, >>, and sshhiifftt com-
+
+ mands.
+ showdirty [off]
+ VVii only. Display an asterisk on the colon command line if the file
+ has been modified.
+ showmatch, sm [off]
+ VVii only. This option causes vvii, when a ``}'' or ``)'' is entered,
+ to briefly move the cursor the matching ``{'' or ``(''. See the
+ mmaattcchhttiimmee option for more information.
+ showmode [off]
+ VVii only. This option causes vvii to display the strings ``Command''
+ or ``Input'' on the colon command line, based on the current mode
+ of the editor.
+ sidescroll [16]
+ VVii only. Sets the number of columns that are shifted to the left
+ or right, when vvii is doing left-right scrolling and the left or
+ right margin is crossed. See the lleeffttrriigghhtt option for more infor-
+ mation.
+ slowopen, slow [off]
+ This option affects the display algorithm used by vvii, holding off
+ display updating during input of new text to improve throughput
+ when the terminal in use is slow and unintelligent.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ sourceany [off]
+ If this option is turned on, vvii historically read startup files
+ that were owned by someone other than the editor user. See the
+ STARTUP INFORMATION section for more information. This option is a
+ security problem of immense proportions, and should not be used un-
+ der any circumstances.
+ _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_.
+ tabstop, ts [8]
+ This option sets tab widths for the editor display.
+ taglength, tl [0]
+ This option sets the maximum number of characters that are consid-
+ ered significant in a tag name. Setting the value to 0 makes all
+ of the characters in the tag name significant.
+ tags, tag [tags /var/db/libc.tags /sys/kern/tags]
+ Sets the list of tags files, in search order, which are used when
+ the editor searches for a tag.
+ term, ttytype, tty [environment variable TERM]
+ Set the terminal type. Setting this option causes eexx//vvii to set (or
+ reset) the environmental variable TERM.
+ terse [off]
+ This option has historically made editor messages less verbose. It
+ has no effect in this implementation. See the vveerrbboossee option for
+ more information.
+ timeout, to [on]
+ If this option is set, eexx//vvii waits for a specific period for a sub-
+ sequent key to complete a key mapping (see the kkeeyyttiimmee option). If
+ the option is not set, the editor waits until enough keys are en-
+ tered to resolve the ambiguity, regardless of how long it takes.
+ ttywerase [off]
+ VVii only. This option changes how vvii does word erase during text
+ input. If this option is set, text is broken up into two classes,
+ blank characters and non-blank characters. Changing from one class
+ to another marks the end of a word.
+ verbose [off]
+ only. VVii historically bells the terminal for many obvious mis-
+ takes, e.g. trying to move past the left-hand margin, or past the
+ end of the file. If this option is set, an error message is dis-
+ played for all errors.
+ w300 [no default]
+ VVii only. Set the window size if the baud rate is less than 1200
+ baud. See the wwiinnddooww option for more information.
+ w1200 [no default]
+ VVii only. Set the window size if the baud rate is equal to 1200
+
+ baud. See the wwiinnddooww option for more information.
+ w9600 [no default]
+ VVii only. Set the window size if the baud rate is greater than 1200
+ baud. See the wwiinnddooww option for more information.
+ warn [on]
+ EExx only. This option causes a warning message to the terminal if
+ the file has been modified, since it was last written, before a !!
+ command.
+ window, w, wi [environment variable LINES]
+ This option determines the default number of lines in a screenful,
+ as written by the zz command. It also determines the number of
+ lines scrolled by the vvii commands ^^FF and ^^BB. The value of window
+ can be unrelated to the real screen size, although it starts out as
+ the number of lines on the screen (see the SCREEN SIZING section).
+ Setting the value of the wwiinnddooww option is the same as using the --ww
+ command line option.
+
+ If the value of wwiinnddooww (as set by the wwiinnddooww, ww330000, ww11220000 or ww99660000
+ options) is smaller than the actual size of the screen, large
+ screen movements will result in displaying only that smaller number
+ of lines on the screen. (Further movements in that same area will
+ result in the screen being filled.) This can provide a performance
+ improvement when viewing different places in one or more files over
+ a slow link.
+ wrapmargin, wm [0]
+ VVii only. If the value of wrapmargin is non-zero, vvii will break
+ lines, that are more than that number of characters long, into two
+ lines at the blank character closest to the value. If wrapmargin
+ is 0, or if there is no blank character upon which to break the
+ line, the line will not be broken.
+ wrapscan, ws [on]
+ This option causes searches to wrap around the end or the beginning
+ of the file, and back to the starting point. Otherwise, the end or
+ beginning of the file terminates the search.
+ writeany, wa [off]
+ If this option is set, file-overwriting checks that would usually
+ be made before the wwrriittee and xxiitt commands, or before an automatic
+ write (see the aauuttoowwrriittee option), are not made. This allows a
+ write to any file, provided the file permissions allow it.
+
+4.4BSD March 18, 1994 10
diff --git a/usr.bin/vi/ex/ex.c b/usr.bin/vi/ex/ex.c
new file mode 100644
index 000000000000..5b27de36fa98
--- /dev/null
+++ b/usr.bin/vi/ex/ex.c
@@ -0,0 +1,1608 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex.c 8.106 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static inline EXCMDLIST const *
+ ex_comm_search __P((char *, size_t));
+static int ep_line __P((SCR *, EXF *, MARK *, char **, size_t *, int *));
+static int ep_range __P((SCR *, EXF *, EXCMDARG *, char **, size_t *));
+
+#define DEFCOM ".+1"
+
+/*
+ * ex --
+ * Read an ex command and execute it.
+ */
+int
+ex(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ TEXT *tp;
+ u_int flags, saved_mode;
+ int eval;
+ char defcom[sizeof(DEFCOM)];
+
+ if (ex_init(sp, ep))
+ return (1);
+
+ if (sp->s_refresh(sp, ep))
+ return (ex_end(sp));
+
+ /* If reading from a file, messages should have line info. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY)) {
+ sp->if_lno = 1;
+ sp->if_name = strdup("input");
+ }
+
+ /*
+ * !!!
+ * Historically, the beautify option applies to ex command input read
+ * from a file. In addition, the first time a ^H was discarded from
+ * the input, a message "^H discarded" was displayed. We don't bother.
+ */
+ LF_INIT(TXT_CNTRLD | TXT_CR | TXT_PROMPT);
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+
+ for (eval = 0;; ++sp->if_lno) {
+ /* Get the next command. */
+ switch (sp->s_get(sp, ep, &sp->tiq, ':', flags)) {
+ case INP_OK:
+ break;
+ case INP_EOF:
+ case INP_ERR:
+ F_SET(sp, S_EXIT_FORCE);
+ goto ret;
+ }
+
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+ tp = sp->tiq.cqh_first;
+ if (tp->len == 0) {
+ if (F_ISSET(sp->gp, G_STDIN_TTY)) {
+ /* Special case \r command. */
+ (void)fputc('\r', stdout);
+ (void)fflush(stdout);
+ }
+ memmove(defcom, DEFCOM, sizeof(DEFCOM));
+ if (ex_icmd(sp, ep, defcom, sizeof(DEFCOM) - 1) &&
+ !F_ISSET(sp->gp, G_STDIN_TTY))
+ F_SET(sp, S_EXIT_FORCE);
+ } else {
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
+ /* Special case ^D command. */
+ if (tp->len == 1 && tp->lb[0] == '\004') {
+ (void)fputc('\r', stdout);
+ (void)fflush(stdout);
+ } else
+ (void)fputc('\n', stdout);
+ if (ex_icmd(sp, ep, tp->lb, tp->len) &&
+ !F_ISSET(sp->gp, G_STDIN_TTY))
+ F_SET(sp, S_EXIT_FORCE);
+ }
+ (void)msg_rpt(sp, 0);
+ if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
+ break;
+
+ if (sp->s_refresh(sp, ep)) {
+ eval = 1;
+ break;
+ }
+ }
+ret: if (sp->if_name != NULL) {
+ FREE(sp->if_name, strlen(sp->if_name) + 1);
+ sp->if_name = NULL;
+ }
+ return (ex_end(sp) || eval);
+}
+
+/*
+ * ex_cfile --
+ * Execute ex commands from a file.
+ */
+int
+ex_cfile(sp, ep, filename)
+ SCR *sp;
+ EXF *ep;
+ char *filename;
+{
+ struct stat sb;
+ int fd, len, rval;
+ char *bp;
+
+ bp = NULL;
+ if ((fd = open(filename, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
+ goto err;
+
+ /*
+ * XXX
+ * We'd like to test if the file is too big to malloc. Since we don't
+ * know what size or type off_t's or size_t's are, what the largest
+ * unsigned integral type is, or what random insanity the local C
+ * compiler will perpetrate, doing the comparison in a portable way
+ * is flatly impossible. Hope that malloc fails if the file is too
+ * large.
+ */
+ MALLOC(sp, bp, char *, (size_t)sb.st_size + 1);
+ if (bp == NULL)
+ goto err;
+
+ len = read(fd, bp, (int)sb.st_size);
+ if (len == -1 || len != sb.st_size) {
+ if (len != sb.st_size)
+ errno = EIO;
+err: rval = 1;
+ msgq(sp, M_SYSERR, filename);
+ } else {
+ bp[sb.st_size] = '\0'; /* XXX */
+
+ /*
+ * Run the command. Messages include file/line information,
+ * but we don't care if we can't get space.
+ */
+ sp->if_lno = 1;
+ sp->if_name = strdup(filename);
+ F_SET(sp, S_VLITONLY);
+ rval = ex_icmd(sp, ep, bp, len);
+ F_CLR(sp, S_VLITONLY);
+ free(sp->if_name);
+ sp->if_name = NULL;
+ }
+
+ /*
+ * !!!
+ * THE UNDERLYING EXF MAY HAVE CHANGED.
+ */
+ if (bp != NULL)
+ FREE(bp, sb.st_size);
+ if (fd >= 0)
+ (void)close(fd);
+ return (rval);
+}
+
+/*
+ * ex_icmd --
+ * Call ex_cmd() after turning off interruptible bits.
+ */
+int
+ex_icmd(sp, ep, cmd, len)
+ SCR *sp;
+ EXF *ep;
+ char *cmd;
+ size_t len;
+{
+ /*
+ * Ex goes through here for each vi :colon command and for each ex
+ * command, however, globally executed commands don't go through
+ * here, instead, they call ex_cmd directly. So, reset all of the
+ * interruptible flags now.
+ */
+ F_CLR(sp, S_INTERRUPTED | S_INTERRUPTIBLE);
+
+ return (ex_cmd(sp, ep, cmd, len));
+}
+
+/* Special command structure for :s as a repeat substitution command. */
+static EXCMDLIST const cmd_subagain =
+ {"s", ex_subagain, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] s [cgr] [count] [#lp]",
+ "repeat the last subsitution"};
+
+/*
+ * ex_cmd --
+ * Parse and execute a string containing ex commands.
+ */
+int
+ex_cmd(sp, ep, cmd, cmdlen)
+ SCR *sp;
+ EXF *ep;
+ char *cmd;
+ size_t cmdlen;
+{
+ EX_PRIVATE *exp;
+ EXCMDARG exc;
+ EXCMDLIST const *cp;
+ MARK cur;
+ recno_t lno, num;
+ size_t arg1_len, len, save_cmdlen;
+ long flagoff;
+ u_int saved_mode;
+ int ch, cnt, delim, flags, namelen, nl, uselastcmd, tmp;
+ char *arg1, *save_cmd, *p, *t;
+
+ /* Init. */
+ nl = 0;
+loop: if (nl) {
+ nl = 0;
+ ++sp->if_lno;
+ }
+ arg1 = NULL;
+ save_cmdlen = 0;
+
+ /*
+ * It's possible that we've been interrupted during a
+ * command.
+ */
+ if (F_ISSET(sp, S_INTERRUPTED))
+ return (0);
+
+ /* Skip whitespace, separators, newlines. */
+ for (; cmdlen > 0; ++cmd, --cmdlen)
+ if ((ch = *cmd) == '\n')
+ ++sp->if_lno;
+ else if (!isblank(ch))
+ break;
+ if (cmdlen == 0)
+ return (0);
+
+ /* Command lines that start with a double-quote are comments. */
+ if (ch == '"') {
+ while (--cmdlen > 0 && *++cmd != '\n');
+ if (*cmd == '\n') {
+ ++cmd;
+ --cmdlen;
+ ++sp->if_lno;
+ }
+ goto loop;
+ }
+
+ /*
+ * !!!
+ * Permit extra colons at the start of the line. Historically,
+ * ex/vi allowed a single extra one. It's simpler not to count.
+ * The stripping is done here because, historically, any command
+ * could have preceding colons, e.g. ":g/pattern/:p" worked.
+ */
+ if (ch == ':')
+ while (--cmdlen > 0 && *++cmd == ':');
+
+ /* Skip whitespace. */
+ for (; cmdlen > 0; ++cmd, --cmdlen) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+
+ /* The last point at which an empty line means do nothing. */
+ if (cmdlen == 0)
+ return (0);
+
+ /* Initialize the structure passed to underlying functions. */
+ memset(&exc, 0, sizeof(EXCMDARG));
+ exp = EXP(sp);
+ if (argv_init(sp, ep, &exc))
+ goto err;
+
+ /* Parse command addresses. */
+ if (ep_range(sp, ep, &exc, &cmd, &cmdlen))
+ goto err;
+
+ /* Skip whitespace. */
+ for (; cmdlen > 0; ++cmd, --cmdlen) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * If no command, ex does the last specified of p, l, or #, and vi
+ * moves to the line. Otherwise, determine the length of the command
+ * name by looking for the first non-alphabetic character. (There
+ * are a few non-alphabetic characters in command names, but they're
+ * all single character commands.) This isn't a great test, because
+ * it means that, for the command ":e +cut.c file", we'll report that
+ * the command "cut" wasn't known. However, it makes ":e+35 file" work
+ * correctly.
+ */
+#define SINGLE_CHAR_COMMANDS "\004!#&<=>@~"
+ if (cmdlen != 0 && cmd[0] != '|' && cmd[0] != '\n') {
+ if (strchr(SINGLE_CHAR_COMMANDS, *cmd)) {
+ p = cmd;
+ ++cmd;
+ --cmdlen;
+ namelen = 1;
+ } else {
+ for (p = cmd; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isalpha(*cmd))
+ break;
+ if ((namelen = cmd - p) == 0) {
+ msgq(sp, M_ERR, "Unknown command name.");
+ goto err;
+ }
+ }
+
+ /*
+ * Search the table for the command.
+ *
+ * !!!
+ * Historic vi permitted the mark to immediately follow the
+ * 'k' in the 'k' command. Make it work.
+ *
+ * !!!
+ * Historic vi permitted pretty much anything to follow the
+ * substitute command, e.g. "s/e/E/|s|sgc3p" was fine. Make
+ * it work.
+ */
+ if ((cp = ex_comm_search(p, namelen)) == NULL)
+ if (p[0] == 'k' && p[1] && !p[2]) {
+ cmd -= namelen - 1;
+ cmdlen += namelen - 1;
+ cp = &cmds[C_K];
+ } else if (p[0] == 's') {
+ cmd -= namelen - 1;
+ cmdlen += namelen - 1;
+ cp = &cmd_subagain;
+ } else {
+ msgq(sp, M_ERR,
+ "The %.*s command is unknown.", namelen, p);
+ goto err;
+ }
+
+ /* Some commands are either not implemented or turned off. */
+ if (F_ISSET(cp, E_NOPERM)) {
+ msgq(sp, M_ERR,
+ "The %s command is not currently supported.",
+ cp->name);
+ goto err;
+ }
+
+ /* Some commands aren't okay in globals. */
+ if (F_ISSET(sp, S_GLOBAL) && F_ISSET(cp, E_NOGLOBAL)) {
+ msgq(sp, M_ERR,
+ "The %s command can't be used as part of a global command.",
+ cp->name);
+ goto err;
+ }
+
+ /*
+ * Multiple < and > characters; another "feature". Note,
+ * The string passed to the underlying function may not be
+ * nul terminated in this case.
+ */
+ if ((cp == &cmds[C_SHIFTL] && *p == '<') ||
+ (cp == &cmds[C_SHIFTR] && *p == '>')) {
+ for (ch = *p; cmdlen > 0; --cmdlen, ++cmd)
+ if (*cmd != ch)
+ break;
+ if (argv_exp0(sp, ep, &exc, p, cmd - p))
+ goto err;
+ }
+
+ /*
+ * The visual command has a different syntax when called
+ * from ex than when called from a vi colon command. FMH.
+ */
+ if (cp == &cmds[C_VISUAL_EX] && IN_VI_MODE(sp))
+ cp = &cmds[C_VISUAL_VI];
+
+ uselastcmd = 0;
+ } else {
+ cp = exp->lastcmd;
+ uselastcmd = 1;
+ }
+
+ /* Initialize local flags to the command flags. */
+ LF_INIT(cp->flags);
+
+ /*
+ * File state must be checked throughout this code, because it is
+ * called when reading the .exrc file and similar things. There's
+ * this little chicken and egg problem -- if we read the file first,
+ * we won't know how to display it. If we read/set the exrc stuff
+ * first, we can't allow any command that requires file state. We
+ * don't have a "reading an rc" bit, because we want the commands
+ * to work when the user source's the rc file later. Historic vi
+ * generally took the easy way out and dropped core.
+ */
+ if (LF_ISSET(E_NORC) && ep == NULL) {
+ msgq(sp, M_ERR,
+ "The %s command requires that a file have already been read in.",
+ cp->name);
+ goto err;
+ }
+
+ /*
+ * There are three normal termination cases for an ex command. They
+ * are the end of the string (cmdlen), or unescaped (by literal next
+ * characters) newline or '|' characters. As we're past any addresses,
+ * we can now determine how long the command is, so we don't have to
+ * look for all the possible terminations. There are three exciting
+ * special cases:
+ *
+ * 1: The bang, global, vglobal and the filter versions of the read and
+ * write commands are delimited by newlines (they can contain shell
+ * pipes).
+ * 2: The ex, edit and visual in vi mode commands take ex commands as
+ * their first arguments.
+ * 3: The substitute command takes an RE as its first argument, and
+ * wants it to be specially delimited.
+ *
+ * Historically, '|' characters in the first argument of the ex, edit,
+ * and substitute commands did not delimit the command. And, in the
+ * filter cases for read and write, and the bang, global and vglobal
+ * commands, they did not delimit the command at all.
+ *
+ * For example, the following commands were legal:
+ *
+ * :edit +25|s/abc/ABC/ file.c
+ * :substitute s/|/PIPE/
+ * :read !spell % | columnate
+ * :global/pattern/p|l
+ *
+ * It's not quite as simple as it sounds, however. The command:
+ *
+ * :substitute s/a/b/|s/c/d|set
+ *
+ * was also legal, i.e. the historic ex parser (using the word loosely,
+ * since "parser" implies some regularity) delimited the RE's based on
+ * its delimiter and not anything so irretrievably vulgar as a command
+ * syntax.
+ *
+ * One thing that makes this easier is that we can ignore most of the
+ * command termination conditions for the commands that want to take
+ * the command up to the next newline. None of them are legal in .exrc
+ * files, so if we're here, we only dealing with a single line, and we
+ * can just eat it.
+ *
+ * Anyhow, the following code makes this all work. First, for the
+ * special cases we move past their special argument. Then, we do
+ * normal command processing on whatever is left. Barf-O-Rama.
+ */
+ arg1_len = 0;
+ save_cmd = cmd;
+ if (cp == &cmds[C_EDIT] ||
+ cp == &cmds[C_EX] || cp == &cmds[C_VISUAL_VI]) {
+ /*
+ * Move to the next non-whitespace character. As '+' must
+ * be the character after the command name, if there isn't
+ * one, we're done.
+ */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ /*
+ * QUOTING NOTE:
+ *
+ * The historic implementation ignored all escape characters
+ * so there was no way to put a space or newline into the +cmd
+ * field. We do a simplistic job of fixing it by moving to the
+ * first whitespace character that isn't escaped by a literal
+ * next character. The literal next characters are stripped
+ * as they're no longer useful.
+ */
+ if (cmdlen > 0 && ch == '+') {
+ ++cmd;
+ --cmdlen;
+ for (arg1 = p = cmd; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ ch = *++cmd;
+ } else if (isblank(ch))
+ break;
+ *p++ = ch;
+ }
+ arg1_len = cmd - arg1;
+
+ /* Reset, so the first argument isn't reparsed. */
+ save_cmd = cmd;
+ }
+ } else if (cp == &cmds[C_BANG] ||
+ cp == &cmds[C_GLOBAL] || cp == &cmds[C_VGLOBAL]) {
+ cmd += cmdlen;
+ cmdlen = 0;
+ } else if (cp == &cmds[C_READ] || cp == &cmds[C_WRITE]) {
+ /*
+ * Move to the next character. If it's a '!', it's a filter
+ * command and we want to eat it all, otherwise, we're done.
+ */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen > 0 && ch == '!') {
+ cmd += cmdlen;
+ cmdlen = 0;
+ }
+ } else if (cp == &cmds[C_SUBSTITUTE]) {
+ /*
+ * Move to the next non-whitespace character, we'll use it as
+ * the delimiter. If the character isn't an alphanumeric or
+ * a '|', it's the delimiter, so parse it. Otherwise, we're
+ * into something like ":s g", so use the special substitute
+ * command.
+ */
+ for (; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isblank(cmd[0]))
+ break;
+
+ if (isalnum(cmd[0]) || cmd[0] == '|')
+ cp = &cmd_subagain;
+ else if (cmdlen > 0) {
+ /*
+ * QUOTING NOTE:
+ *
+ * Backslashes quote delimiter characters for RE's.
+ * The backslashes are NOT removed since they'll be
+ * used by the RE code. Move to the third delimiter
+ * that's not escaped (or the end of the command).
+ */
+ delim = *cmd;
+ ++cmd;
+ --cmdlen;
+ for (cnt = 2; cmdlen > 0 && cnt; --cmdlen, ++cmd)
+ if (cmd[0] == '\\' && cmdlen > 1) {
+ ++cmd;
+ --cmdlen;
+ } else if (cmd[0] == delim)
+ --cnt;
+ }
+ }
+ /*
+ * Use normal quoting and termination rules to find the end
+ * of this command.
+ *
+ * QUOTING NOTE:
+ *
+ * Historically, vi permitted ^V's to escape <newline>'s in the .exrc
+ * file. It was almost certainly a bug, but that's what bug-for-bug
+ * compatibility means, Grasshopper. Also, ^V's escape the command
+ * delimiters. Literal next quote characters in front of the newlines,
+ * '|' characters or literal next characters are stripped as as they're
+ * no longer useful.
+ */
+ for (p = cmd, cnt = 0; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = cmd[0];
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ tmp = cmd[1];
+ if (tmp == '\n' || tmp == '|') {
+ if (tmp == '\n')
+ ++sp->if_lno;
+ --cmdlen;
+ ++cmd;
+ ++cnt;
+ ch = tmp;
+ }
+ } else if (ch == '\n' || ch == '|') {
+ if (ch == '\n')
+ nl = 1;
+ --cmdlen;
+ break;
+ }
+ *p++ = ch;
+ }
+
+ /*
+ * Save off the next command information, go back to the
+ * original start of the command.
+ */
+ p = cmd + 1;
+ cmd = save_cmd;
+ save_cmd = p;
+ save_cmdlen = cmdlen;
+ cmdlen = ((save_cmd - cmd) - 1) - cnt;
+
+ /*
+ * !!!
+ * The "set tags" command historically used a backslash, not the
+ * user's literal next character, to escape whitespace. Handle
+ * it here instead of complicating the argv_exp3() code. Note,
+ * this isn't a particularly complex trap, and if backslashes were
+ * legal in set commands, this would have to be much more complicated.
+ */
+ if (cp == &cmds[C_SET])
+ for (p = cmd, len = cmdlen; len > 0; --len, ++p)
+ if (*p == '\\')
+ *p = LITERAL_CH;
+
+ /*
+ * Set the default addresses. It's an error to specify an address for
+ * a command that doesn't take them. If two addresses are specified
+ * for a command that only takes one, lose the first one. Two special
+ * cases here, some commands take 0 or 2 addresses. For most of them
+ * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one
+ * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines.
+ *
+ * Also, if the file is empty, some commands want to use an address of
+ * 0, i.e. the entire file is 0 to 0, and the default first address is
+ * 0. Otherwise, an entire file is 1 to N and the default line is 1.
+ * Note, we also add the E_ZERO flag to the command flags, for the case
+ * where the 0 address is only valid if it's a default address.
+ *
+ * Also, set a flag if we set the default addresses. Some commands
+ * (ex: z) care if the user specified an address of if we just used
+ * the current cursor.
+ */
+ switch (LF_ISSET(E_ADDR1|E_ADDR2|E_ADDR2_ALL|E_ADDR2_NONE)) {
+ case E_ADDR1: /* One address: */
+ switch (exc.addrcnt) {
+ case 0: /* Default cursor/empty file. */
+ exc.addrcnt = 1;
+ F_SET(&exc, E_ADDRDEF);
+ if (LF_ISSET(E_ZERODEF)) {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno == 0) {
+ exc.addr1.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = sp->lno;
+ } else
+ exc.addr1.lno = sp->lno;
+ exc.addr1.cno = sp->cno;
+ break;
+ case 1:
+ break;
+ case 2: /* Lose the first address. */
+ exc.addrcnt = 1;
+ exc.addr1 = exc.addr2;
+ }
+ break;
+ case E_ADDR2_NONE: /* Zero/two addresses: */
+ if (exc.addrcnt == 0) /* Default to nothing. */
+ break;
+ goto two;
+ case E_ADDR2_ALL: /* Zero/two addresses: */
+ if (exc.addrcnt == 0) { /* Default entire/empty file. */
+ exc.addrcnt = 2;
+ F_SET(&exc, E_ADDRDEF);
+ if (file_lline(sp, ep, &exc.addr2.lno))
+ goto err;
+ if (LF_ISSET(E_ZERODEF) && exc.addr2.lno == 0) {
+ exc.addr1.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = 1;
+ exc.addr1.cno = exc.addr2.cno = 0;
+ F_SET(&exc, E_ADDR2_ALL);
+ break;
+ }
+ /* FALLTHROUGH */
+ case E_ADDR2: /* Two addresses: */
+two: switch (exc.addrcnt) {
+ case 0: /* Default cursor/empty file. */
+ exc.addrcnt = 2;
+ F_SET(&exc, E_ADDRDEF);
+ if (LF_ISSET(E_ZERODEF) && sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno == 0) {
+ exc.addr1.lno = exc.addr2.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ } else
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ break;
+ case 1: /* Default to first address. */
+ exc.addrcnt = 2;
+ exc.addr2 = exc.addr1;
+ break;
+ case 2:
+ break;
+ }
+ break;
+ default:
+ if (exc.addrcnt) /* Error. */
+ goto usage;
+ }
+
+ /*
+ * !!!
+ * The ^D scroll command historically scrolled half the screen size
+ * rows down, rounded down, or to EOF. It was an error if the cursor
+ * was already at EOF. (Leading addresses were permitted, but were
+ * then ignored.)
+ */
+ if (cp == &cmds[C_SCROLL]) {
+ exc.addrcnt = 2;
+ exc.addr1.lno = sp->lno + 1;
+ exc.addr2.lno = sp->lno + 1 + (O_VAL(sp, O_LINES) + 1) / 2;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno != 0 && lno > sp->lno && exc.addr2.lno > lno)
+ exc.addr2.lno = lno;
+ }
+
+ flagoff = 0;
+ for (p = cp->syntax; *p != '\0'; ++p) {
+ /*
+ * The write command is sensitive to leading whitespace, e.g.
+ * "write !" is different from "write!". If not the write
+ * command, skip leading whitespace.
+ */
+ if (cp != &cmds[C_WRITE])
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * Quit when reach the end of the command, unless it's a
+ * command that does its own parsing, in which case we want
+ * to build a reasonable argv for it. This code guarantees
+ * that there will be an argv when the function gets called,
+ * so the correct test is for a length of 0, not for the
+ * argc > 0.
+ */
+ if (cmdlen == 0 && *p != '!' && *p != 'S' && *p != 's')
+ break;
+
+ switch (*p) {
+ case '!': /* ! */
+ if (*cmd == '!') {
+ ++cmd;
+ --cmdlen;
+ F_SET(&exc, E_FORCE);
+ }
+ break;
+ case '1': /* +, -, #, l, p */
+ /*
+ * !!!
+ * Historically, some flags were ignored depending
+ * on where they occurred in the command line. For
+ * example, in the command, ":3+++p--#", historic vi
+ * acted on the '#' flag, but ignored the '-' flags.
+ * It's unambiguous what the flags mean, so we just
+ * handle them regardless of the stupidity of their
+ * location.
+ */
+ for (; cmdlen; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '+':
+ ++flagoff;
+ break;
+ case '-':
+ --flagoff;
+ break;
+ case '#':
+ F_SET(&exc, E_F_HASH);
+ break;
+ case 'l':
+ F_SET(&exc, E_F_LIST);
+ break;
+ case 'p':
+ F_SET(&exc, E_F_PRINT);
+ break;
+ default:
+ goto end1;
+ }
+end1: break;
+ case '2': /* -, ., +, ^ */
+ case '3': /* -, ., +, ^, = */
+ for (; cmdlen; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '-':
+ F_SET(&exc, E_F_DASH);
+ break;
+ case '.':
+ F_SET(&exc, E_F_DOT);
+ break;
+ case '+':
+ F_SET(&exc, E_F_PLUS);
+ break;
+ case '^':
+ F_SET(&exc, E_F_CARAT);
+ break;
+ case '=':
+ if (*p == '3') {
+ F_SET(&exc, E_F_EQUAL);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ goto end2;
+ }
+end2: break;
+ case 'b': /* buffer */
+ /*
+ * Digits can't be buffer names in ex commands, or the
+ * command "d2" would be a delete into buffer '2', and
+ * not a two-line deletion.
+ */
+ if (!isdigit(cmd[0])) {
+ exc.buffer = *cmd;
+ ++cmd;
+ --cmdlen;
+ F_SET(&exc, E_BUFFER);
+ }
+ break;
+ case 'c': /* count [01+a] */
+ ++p;
+ /* Validate any signed value. */
+ if (!isdigit(*cmd) &&
+ (*p != '+' || (*cmd != '+' && *cmd != '-')))
+ break;
+ /* If a signed value, set appropriate flags. */
+ if (*cmd == '-')
+ F_SET(&exc, E_COUNT_NEG);
+ else if (*cmd == '+')
+ F_SET(&exc, E_COUNT_POS);
+/* 8-bit XXX */ if ((lno = strtol(cmd, &t, 10)) == 0 && *p != '0') {
+ msgq(sp, M_ERR, "Count may not be zero.");
+ goto err;
+ }
+ cmdlen -= (t - cmd);
+ cmd = t;
+ /*
+ * Count as address offsets occur in commands taking
+ * two addresses. Historic vi practice was to use
+ * the count as an offset from the *second* address.
+ *
+ * Set a count flag; some underlying commands (see
+ * join) do different things with counts than with
+ * line addresses.
+ */
+ if (*p == 'a') {
+ exc.addr1 = exc.addr2;
+ exc.addr2.lno = exc.addr1.lno + lno - 1;
+ } else
+ exc.count = lno;
+ F_SET(&exc, E_COUNT);
+ break;
+ case 'f': /* file */
+ if (argv_exp2(sp, ep,
+ &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
+ goto err;
+ goto countchk;
+ case 'l': /* line */
+ if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
+ goto err;
+ /* Line specifications are always required. */
+ if (!tmp) {
+ msgq(sp, M_ERR,
+ "%s: bad line specification", cmd);
+ goto err;
+ }
+ exc.lineno = cur.lno;
+ break;
+ case 'S': /* string, file exp. */
+ if (argv_exp1(sp, ep,
+ &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
+ goto err;
+ goto addr2;
+ case 's': /* string */
+ if (argv_exp0(sp, ep, &exc, cmd, cmdlen))
+ goto err;
+ goto addr2;
+ case 'W': /* word string */
+ /*
+ * QUOTING NOTE:
+ *
+ * Literal next characters escape the following
+ * character. Quoting characters are stripped
+ * here since they are no longer useful.
+ *
+ * First there was the word.
+ */
+ for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ *p++ = *++cmd;
+ } else if (isblank(ch)) {
+ ++cmd;
+ --cmdlen;
+ break;
+ } else
+ *p++ = ch;
+ }
+ if (argv_exp0(sp, ep, &exc, t, p - t))
+ goto err;
+
+ /* Delete intervening whitespace. */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen == 0)
+ goto usage;
+
+ /* Followed by the string. */
+ for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd, ++p) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ *p = *++cmd;
+ } else
+ *p = ch;
+ }
+ if (argv_exp0(sp, ep, &exc, t, p - t))
+ goto err;
+ goto addr2;
+ case 'w': /* word */
+ if (argv_exp3(sp, ep, &exc, cmd, cmdlen))
+ goto err;
+countchk: if (*++p != 'N') { /* N */
+ /*
+ * If a number is specified, must either be
+ * 0 or that number, if optional, and that
+ * number, if required.
+ */
+ num = *p - '0';
+ if ((*++p != 'o' || exp->argsoff != 0) &&
+ exp->argsoff != num)
+ goto usage;
+ }
+ goto addr2;
+ default:
+ msgq(sp, M_ERR,
+ "Internal syntax table error (%s: %c).",
+ cp->name, *p);
+ }
+ }
+
+ /* Skip trailing whitespace. */
+ for (; cmdlen; --cmdlen) {
+ ch = *cmd++;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * There shouldn't be anything left, and no more required
+ * fields, i.e neither 'l' or 'r' in the syntax string.
+ */
+ if (cmdlen || strpbrk(p, "lr")) {
+usage: msgq(sp, M_ERR, "Usage: %s.", cp->usage);
+ goto err;
+ }
+
+ /* Verify that the addresses are legal. */
+addr2: switch (exc.addrcnt) {
+ case 2:
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ /*
+ * Historic ex/vi permitted commands with counts to go past
+ * EOF. So, for example, if the file only had 5 lines, the
+ * ex command "1,6>" would fail, but the command ">300"
+ * would succeed. Since we don't want to have to make all
+ * of the underlying commands handle random line numbers,
+ * fix it here.
+ */
+ if (exc.addr2.lno > lno)
+ if (F_ISSET(&exc, E_COUNT))
+ exc.addr2.lno = lno;
+ else {
+ if (lno == 0)
+ msgq(sp, M_ERR, "The file is empty.");
+ else
+ msgq(sp, M_ERR,
+ "Only %lu line%s in the file",
+ lno, lno > 1 ? "s" : "");
+ goto err;
+ }
+ /* FALLTHROUGH */
+ case 1:
+ num = exc.addr1.lno;
+ /*
+ * If it's a "default vi command", zero is okay. Historic
+ * vi allowed this, note, it's also the hack that allows
+ * "vi + nonexistent_file" to work.
+ */
+ if (num == 0 && (!IN_VI_MODE(sp) || uselastcmd != 1) &&
+ !LF_ISSET(E_ZERO)) {
+ msgq(sp, M_ERR,
+ "The %s command doesn't permit an address of 0.",
+ cp->name);
+ goto err;
+ }
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (num > lno) {
+ if (lno == 0)
+ msgq(sp, M_ERR, "The file is empty.");
+ else
+ msgq(sp, M_ERR, "Only %lu line%s in the file",
+ lno, lno > 1 ? "s" : "");
+ goto err;
+ }
+ break;
+ }
+
+ /* If doing a default command, vi just moves to the line. */
+ if (IN_VI_MODE(sp) && uselastcmd) {
+ switch (exc.addrcnt) {
+ case 2:
+ sp->lno = exc.addr2.lno ? exc.addr2.lno : 1;
+ sp->cno = exc.addr2.cno;
+ break;
+ case 1:
+ sp->lno = exc.addr1.lno ? exc.addr1.lno : 1;
+ sp->cno = exc.addr1.cno;
+ break;
+ }
+ cmd = save_cmd;
+ cmdlen = save_cmdlen;
+ goto loop;
+ }
+
+ /* Reset "last" command. */
+ if (LF_ISSET(E_SETLAST))
+ exp->lastcmd = cp;
+
+ /* Final setup for the command. */
+ exc.cmd = cp;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "ex_cmd: %s", exc.cmd->name);
+ if (exc.addrcnt > 0) {
+ TRACE(sp, "\taddr1 %d", exc.addr1.lno);
+ if (exc.addrcnt > 1)
+ TRACE(sp, " addr2: %d", exc.addr2.lno);
+ TRACE(sp, "\n");
+ }
+ if (exc.lineno)
+ TRACE(sp, "\tlineno %d", exc.lineno);
+ if (exc.flags)
+ TRACE(sp, "\tflags %0x", exc.flags);
+ if (F_ISSET(&exc, E_BUFFER))
+ TRACE(sp, "\tbuffer %c", exc.buffer);
+ TRACE(sp, "\n");
+ if (exc.argc) {
+ for (cnt = 0; cnt < exc.argc; ++cnt)
+ TRACE(sp, "\targ %d: {%s}", cnt, exc.argv[cnt]);
+ TRACE(sp, "\n");
+ }
+#endif
+ /* Clear autoprint flag. */
+ F_CLR(exp, EX_AUTOPRINT);
+
+ /* Increment the command count if not called from vi. */
+ if (!IN_VI_MODE(sp))
+ ++sp->ccnt;
+
+ /*
+ * If file state and not doing a global command, log the start of
+ * an action.
+ */
+ if (ep != NULL && !F_ISSET(sp, S_GLOBAL))
+ (void)log_cursor(sp, ep);
+
+ /* Save the current mode. */
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+
+ /* Do the command. */
+ if ((cp->fn)(sp, ep, &exc))
+ goto err;
+
+#ifdef DEBUG
+ /* Make sure no function left the temporary space locked. */
+ if (F_ISSET(sp->gp, G_TMP_INUSE)) {
+ F_CLR(sp->gp, G_TMP_INUSE);
+ msgq(sp, M_ERR, "Error: ex: temporary buffer not released.");
+ goto err;
+ }
+#endif
+ if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) {
+ /*
+ * Only here if the mode of the underlying file changed, e.g.
+ * the user switched files or is exiting. There are two things
+ * that we might have to save. First, any "+cmd" field set up
+ * for an ex/edit command will have to be saved for later, also,
+ * any not yet executed part of the current ex command.
+ *
+ * :edit +25 file.c|s/abc/ABC/|1
+ *
+ * for example.
+ *
+ * The historic vi just hung, of course; we handle by
+ * pushing the keys onto the tty queue. If we're
+ * switching modes to vi, since the commands are intended
+ * as ex commands, add the extra characters to make it
+ * work.
+ *
+ * For the fun of it, if you want to see if a vi clone got
+ * the ex argument parsing right, try:
+ *
+ * echo 'foo|bar' > file1; echo 'foo/bar' > file2;
+ * vi
+ * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq
+ */
+ if (arg1_len == NULL && save_cmdlen == 0)
+ return (0);
+ if (IN_VI_MODE(sp) && term_push(sp, "\n", 1, 0, 0))
+ goto err;
+ if (save_cmdlen != 0)
+ if (term_push(sp, save_cmd, save_cmdlen, 0, 0))
+ goto err;
+ if (arg1 != NULL) {
+ if (IN_VI_MODE(sp) && save_cmdlen != 0 &&
+ term_push(sp, "|", 1, 0, 0))
+ goto err;
+ if (term_push(sp, arg1, arg1_len, 0, 0))
+ goto err;
+ }
+ if (IN_VI_MODE(sp) && term_push(sp, ":", 1, 0, 0))
+ goto err;
+ return (0);
+ }
+
+ if (IN_EX_MODE(sp) && ep != NULL) {
+ /*
+ * The print commands have already handled the `print' flags.
+ * If so, clear them. Don't return, autoprint may still have
+ * stuff to print out.
+ */
+ if (LF_ISSET(E_F_PRCLEAR))
+ F_CLR(&exc, E_F_HASH | E_F_LIST | E_F_PRINT);
+
+ /*
+ * If the command was successful, and there was an explicit
+ * flag to display the new cursor line, or we're in ex mode,
+ * autoprint is set, and a change was made, display the line.
+ */
+ if (flagoff) {
+ if (flagoff < 0) {
+ if (sp->lno < -flagoff) {
+ msgq(sp, M_ERR,
+ "Flag offset before line 1.");
+ goto err;
+ }
+ } else {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (sp->lno + flagoff > lno) {
+ msgq(sp, M_ERR,
+ "Flag offset past end-of-file.");
+ goto err;
+ }
+ }
+ sp->lno += flagoff;
+ }
+
+ if (O_ISSET(sp, O_AUTOPRINT) &&
+ (F_ISSET(exp, EX_AUTOPRINT) || F_ISSET(cp, E_AUTOPRINT)))
+ LF_INIT(E_F_PRINT);
+ else
+ LF_INIT(F_ISSET(&exc, E_F_HASH | E_F_LIST | E_F_PRINT));
+
+ memset(&exc, 0, sizeof(EXCMDARG));
+ exc.addrcnt = 2;
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ switch (LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT)) {
+ case E_F_HASH:
+ exc.cmd = &cmds[C_HASH];
+ ex_number(sp, ep, &exc);
+ break;
+ case E_F_LIST:
+ exc.cmd = &cmds[C_LIST];
+ ex_list(sp, ep, &exc);
+ break;
+ case E_F_PRINT:
+ exc.cmd = &cmds[C_PRINT];
+ ex_pr(sp, ep, &exc);
+ break;
+ }
+ }
+
+ cmd = save_cmd;
+ cmdlen = save_cmdlen;
+ goto loop;
+ /* NOTREACHED */
+
+ /*
+ * On error, we discard any keys we have left, as well as any keys
+ * that were mapped. The test of save_cmdlen isn't necessarily
+ * correct. If we fail early enough we don't know if the entire
+ * string was a single command or not. Try and guess, it's useful
+ * to know if part of the command was discarded.
+ */
+err: if (save_cmdlen == 0)
+ for (; cmdlen; --cmdlen) {
+ ch = *cmd++;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ ++cmd;
+ } else if (ch == '\n' || ch == '|') {
+ if (cmdlen > 1)
+ save_cmdlen = 1;
+ break;
+ }
+ }
+ if (save_cmdlen != 0)
+ msgq(sp, M_ERR,
+ "Ex command failed: remaining command input discarded.");
+ term_map_flush(sp, "Ex command failed");
+ return (1);
+}
+
+/*
+ * ep_range --
+ * Get a line range for ex commands.
+ */
+static int
+ep_range(sp, ep, excp, cmdp, cmdlenp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char **cmdp;
+ size_t *cmdlenp;
+{
+ MARK cur, savecursor;
+ size_t cmdlen;
+ int savecursor_set, tmp;
+ char *cmd;
+
+ /* Percent character is all lines in the file. */
+ cmd = *cmdp;
+ cmdlen = *cmdlenp;
+ if (*cmd == '%') {
+ excp->addr1.lno = 1;
+ if (file_lline(sp, ep, &excp->addr2.lno))
+ return (1);
+
+ /* If an empty file, then the first line is 0, not 1. */
+ if (excp->addr2.lno == 0)
+ excp->addr1.lno = 0;
+ excp->addr1.cno = excp->addr2.cno = 0;
+ excp->addrcnt = 2;
+
+ ++*cmdp;
+ --*cmdlenp;
+ return (0);
+ }
+
+ /* Parse comma or semi-colon delimited line specs. */
+ for (savecursor_set = 0, excp->addrcnt = 0; cmdlen > 0;)
+ switch (*cmd) {
+ case ';': /* Semi-colon delimiter. */
+ /*
+ * Comma delimiters delimit; semi-colon delimiters
+ * change the current address for the 2nd address
+ * to be the first address. Trailing or multiple
+ * delimiters are discarded.
+ */
+ if (excp->addrcnt == 0)
+ goto done;
+ if (!savecursor_set) {
+ savecursor.lno = sp->lno;
+ savecursor.cno = sp->cno;
+ sp->lno = excp->addr1.lno;
+ sp->cno = excp->addr1.cno;
+ savecursor_set = 1;
+ }
+ ++cmd;
+ --cmdlen;
+ break;
+ case ',': /* Comma delimiter. */
+ /* If no addresses yet, defaults to ".". */
+ if (excp->addrcnt == 0) {
+ excp->addr1.lno = sp->lno;
+ excp->addr1.cno = sp->cno;
+ excp->addrcnt = 1;
+ }
+ /* FALLTHROUGH */
+ case ' ': /* Whitespace. */
+ case '\t': /* Whitespace. */
+ ++cmd;
+ --cmdlen;
+ break;
+ default:
+ if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
+ return (1);
+ if (!tmp)
+ goto done;
+
+ /*
+ * Extra addresses are discarded, starting with
+ * the first.
+ */
+ switch (excp->addrcnt) {
+ case 0:
+ excp->addr1 = cur;
+ excp->addrcnt = 1;
+ break;
+ case 1:
+ excp->addr2 = cur;
+ excp->addrcnt = 2;
+ break;
+ case 2:
+ excp->addr1 = excp->addr2;
+ excp->addr2 = cur;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * XXX
+ * This is probably not right behavior for savecursor -- need
+ * to figure out what the historical ex did for ";,;,;5p" or
+ * similar stupidity.
+ */
+done: if (savecursor_set) {
+ sp->lno = savecursor.lno;
+ sp->cno = savecursor.cno;
+ }
+ if (excp->addrcnt == 2 &&
+ (excp->addr2.lno < excp->addr1.lno ||
+ excp->addr2.lno == excp->addr1.lno &&
+ excp->addr2.cno < excp->addr1.cno)) {
+ msgq(sp, M_ERR,
+ "The second address is smaller than the first.");
+ return (1);
+ }
+ *cmdp = cmd;
+ *cmdlenp = cmdlen;
+ return (0);
+}
+
+/*
+ * Get a single line address specifier.
+ */
+static int
+ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
+ SCR *sp;
+ EXF *ep;
+ MARK *cur;
+ char **cmdp;
+ size_t *cmdlenp;
+ int *addr_found;
+{
+ MARK m;
+ long total;
+ u_int flags;
+ size_t cmdlen;
+ int (*sf) __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
+ char *cmd, *endp;
+
+ *addr_found = 0;
+
+ cmd = *cmdp;
+ cmdlen = *cmdlenp;
+ switch (*cmd) {
+ case '$': /* Last line in the file. */
+ *addr_found = 1;
+ cur->cno = 0;
+ if (file_lline(sp, ep, &cur->lno))
+ return (1);
+ ++cmd;
+ --cmdlen;
+ break; /* Absolute line number. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ *addr_found = 1;
+ /*
+ * The way the vi "previous context" mark worked was that
+ * "non-relative" motions set it. While vi wasn't totally
+ * consistent about this, ANY numeric address was considered
+ * non-relative, and set the value. Which is why we're
+ * hacking marks down here.
+ */
+ if (IN_VI_MODE(sp)) {
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ if (mark_set(sp, ep, ABSMARK1, &m, 1))
+ return (1);
+ }
+ cur->cno = 0;
+/* 8-bit XXX */ cur->lno = strtol(cmd, &endp, 10);
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ break;
+ case '\'': /* Use a mark. */
+ *addr_found = 1;
+ if (cmdlen == 1) {
+ msgq(sp, M_ERR, "No mark name supplied.");
+ return (1);
+ }
+ if (mark_get(sp, ep, cmd[1], cur))
+ return (1);
+ cmd += 2;
+ cmdlen -= 2;
+ break;
+ case '\\': /* Search: forward/backward. */
+ /*
+ * !!!
+ * I can't find any difference between // and \/ or
+ * between ?? and \?. Mark Horton doesn't remember
+ * there being any difference. C'est la vie.
+ */
+ if (cmdlen < 2 || cmd[1] != '/' && cmd[1] != '?') {
+ msgq(sp, M_ERR, "\\ not followed by / or ?.");
+ return (1);
+ }
+ ++cmd;
+ --cmdlen;
+ sf = cmd[0] == '/' ? f_search : b_search;
+ goto search;
+ case '/': /* Search forward. */
+ sf = f_search;
+ goto search;
+ case '?': /* Search backward. */
+ sf = b_search;
+search: if (ep == NULL) {
+ msgq(sp, M_ERR,
+ "A search address requires that a file have already been read in.");
+ return (1);
+ }
+ *addr_found = 1;
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET;
+ if (sf(sp, ep, &m, &m, cmd, &endp, &flags))
+ return (1);
+ cur->lno = m.lno;
+ cur->cno = m.cno;
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ break;
+ case '.': /* Current position. */
+ *addr_found = 1;
+ cur->cno = sp->cno;
+
+ /* If an empty file, then '.' is 0, not 1. */
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &cur->lno))
+ return (1);
+ if (cur->lno != 0)
+ cur->lno = 1;
+ } else
+ cur->lno = sp->lno;
+ ++cmd;
+ --cmdlen;
+ break;
+ }
+
+ /*
+ * Evaluate any offset. Offsets are +/- any number, or any number
+ * of +/- signs, or any combination thereof. If no address found
+ * yet, offset is relative to ".".
+ */
+ for (total = 0; cmdlen > 0 && (cmd[0] == '-' || cmd[0] == '+');) {
+ if (!*addr_found) {
+ cur->lno = sp->lno;
+ cur->cno = sp->cno;
+ *addr_found = 1;
+ }
+
+ if (cmdlen > 1 && isdigit(cmd[1])) {
+/* 8-bit XXX */ total += strtol(cmd, &endp, 10);
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ } else {
+ total += cmd[0] == '-' ? -1 : 1;
+ --cmdlen;
+ ++cmd;
+ }
+ }
+
+ if (*addr_found) {
+ if (total < 0 && -total > cur->lno) {
+ msgq(sp, M_ERR,
+ "Reference to a line number less than 0.");
+ return (1);
+ }
+ cur->lno += total;
+
+ *cmdp = cmd;
+ *cmdlenp = cmdlen;
+ }
+ return (0);
+}
+
+/*
+ * ex_is_abbrev -
+ * The vi text input routine needs to know if ex thinks this is
+ * an [un]abbreviate command, so it can turn off abbreviations.
+ * Usual ranting in the vi/v_ntext:txt_abbrev() routine.
+ */
+int
+ex_is_abbrev(name, len)
+ char *name;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ return ((cp = ex_comm_search(name, len)) != NULL &&
+ (cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE]));
+}
+
+/*
+ * ex_is_unmap -
+ * The vi text input routine needs to know if ex thinks this is
+ * an unmap command, so it can turn off input mapping. Usual
+ * ranting in the vi/v_ntext:txt_unmap() routine.
+ */
+int
+ex_is_unmap(name, len)
+ char *name;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ /*
+ * The command the vi input routines are really interested in
+ * is "unmap!", not just unmap.
+ */
+ if (name[len - 1] != '!')
+ return (0);
+ --len;
+ return ((cp = ex_comm_search(name, len)) != NULL &&
+ cp == &cmds[C_UNMAP]);
+}
+
+static inline EXCMDLIST const *
+ex_comm_search(name, len)
+ char *name;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ for (cp = cmds; cp->name != NULL; ++cp) {
+ if (cp->name[0] > name[0])
+ return (NULL);
+ if (cp->name[0] != name[0])
+ continue;
+ if (!memcmp(name, cp->name, len))
+ return (cp);
+ }
+ return (NULL);
+}
diff --git a/usr.bin/vi/ex/ex_abbrev.c b/usr.bin/vi/ex/ex_abbrev.c
new file mode 100644
index 000000000000..9db3ce148761
--- /dev/null
+++ b/usr.bin/vi/ex/ex_abbrev.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_abbrev.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "seq.h"
+#include "excmd.h"
+
+/*
+ * ex_abbr -- :abbreviate [key replacement]
+ * Create an abbreviation or display abbreviations.
+ */
+int
+ex_abbr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ switch (cmdp->argc) {
+ case 0:
+ if (seq_dump(sp, SEQ_ABBREV, 0) == 0)
+ msgq(sp, M_INFO, "No abbreviations to display.");
+ return (0);
+ case 2:
+ break;
+ default:
+ abort();
+ }
+
+ if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, S_USERDEF))
+ return (1);
+ F_SET(sp->gp, G_ABBREV);
+ return (0);
+}
+
+/*
+ * ex_unabbr -- :unabbreviate key
+ * Delete an abbreviation.
+ */
+int
+ex_unabbr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+
+ ap = cmdp->argv[0];
+ if (!F_ISSET(sp->gp, G_ABBREV) ||
+ seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) {
+ msgq(sp, M_ERR, "\"%s\" is not an abbreviation.", ap->bp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * abbr_save --
+ * Save the abbreviation sequences to a file.
+ */
+int
+abbr_save(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ return (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV));
+}
diff --git a/usr.bin/vi/ex/ex_append.c b/usr.bin/vi/ex/ex_append.c
new file mode 100644
index 000000000000..f75b22fa31af
--- /dev/null
+++ b/usr.bin/vi/ex/ex_append.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_append.c 8.9 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {APPEND, CHANGE, INSERT};
+
+static int aci __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_append -- :[line] a[ppend][!]
+ * Append one or more lines of new text after the specified line,
+ * or the current line if no address is specified.
+ */
+int
+ex_append(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, APPEND));
+}
+
+/*
+ * ex_change -- :[line[,line]] c[hange][!] [count]
+ * Change one or more lines to the input text.
+ */
+int
+ex_change(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, CHANGE));
+}
+
+/*
+ * ex_insert -- :[line] i[nsert][!]
+ * Insert one or more lines of new text before the specified line,
+ * or the current line if no address is specified.
+ */
+int
+ex_insert(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, INSERT));
+}
+
+static int
+aci(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ MARK m;
+ TEXT *tp;
+ recno_t cnt;
+ u_int flags;
+ int rval, aiset;
+
+ /*
+ * The ! flag turns off autoindent for append, change and
+ * insert.
+ */
+ if (F_ISSET(cmdp, E_FORCE)) {
+ aiset = O_ISSET(sp, O_AUTOINDENT);
+ O_CLR(sp, O_AUTOINDENT);
+ } else
+ aiset = 0;
+
+ /*
+ * If doing a change, replace lines as long as possible.
+ * Then, append more lines or delete remaining lines.
+ * Inserts are the same as appends to the previous line.
+ */
+ rval = 0;
+ m = cmdp->addr1;
+ if (cmd == INSERT) {
+ --m.lno;
+ cmd = APPEND;
+ }
+
+ LF_INIT(TXT_CR | TXT_NLECHO);
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+
+ if (cmd == CHANGE)
+ for (;; ++m.lno) {
+ if (m.lno > cmdp->addr2.lno) {
+ cmd = APPEND;
+ --m.lno;
+ break;
+ }
+ switch (sp->s_get(sp, ep, &sp->tiq, 0, flags)) {
+ case INP_OK:
+ break;
+ case INP_EOF:
+ case INP_ERR:
+ rval = 1;
+ goto done;
+ }
+ tp = sp->tiq.cqh_first;
+ if (tp->len == 1 && tp->lb[0] == '.') {
+ for (cnt =
+ (cmdp->addr2.lno - m.lno) + 1; cnt--;)
+ if (file_dline(sp, ep, m.lno)) {
+ rval = 1;
+ goto done;
+ }
+ goto done;
+ }
+ if (file_sline(sp, ep, m.lno, tp->lb, tp->len)) {
+ rval = 1;
+ goto done;
+ }
+ }
+
+ if (cmd == APPEND)
+ for (;; ++m.lno) {
+ switch (sp->s_get(sp, ep, &sp->tiq, 0, flags)) {
+ case INP_OK:
+ break;
+ case INP_EOF:
+ case INP_ERR:
+ rval = 1;
+ goto done;
+ }
+ tp = sp->tiq.cqh_first;
+ if (tp->len == 1 && tp->lb[0] == '.')
+ break;
+ if (file_aline(sp, ep, 1, m.lno, tp->lb, tp->len)) {
+ rval = 1;
+ goto done;
+ }
+ }
+
+done: if (rval == 0)
+ sp->lno = m.lno;
+
+ if (aiset)
+ O_SET(sp, O_AUTOINDENT);
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_args.c b/usr.bin/vi/ex/ex_args.c
new file mode 100644
index 000000000000..e035704a4a29
--- /dev/null
+++ b/usr.bin/vi/ex/ex_args.c
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_args.c 8.16 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_next -- :next [files]
+ * Edit the next file, optionally setting the list of files.
+ *
+ * !!!
+ * The :next command behaved differently from the :rewind command in
+ * historic vi. See nvi/docs/autowrite for details, but the basic
+ * idea was that it ignored the force flag if the autowrite flag was
+ * set. This implementation handles them all identically.
+ */
+int
+ex_next(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS **argv;
+ FREF *frp;
+ char *name;
+
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
+
+ if (cmdp->argc) {
+ /* Mark all the current files as ignored. */
+ for (frp = sp->frefq.cqh_first;
+ frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)
+ F_SET(frp, FR_IGNORE);
+
+ /* Add the new files into the file list. */
+ for (argv = cmdp->argv; argv[0]->len != 0; ++argv)
+ if (file_add(sp, NULL, argv[0]->bp, 0) == NULL)
+ return (1);
+
+ if ((frp = file_first(sp)) == NULL)
+ return (1);
+ } else if ((frp = file_next(sp, sp->a_frp)) == NULL) {
+ msgq(sp, M_ERR, "No more files to edit.");
+ return (1);
+ }
+
+ /*
+ * There's a tricky sequence, where the user edits two files, e.g.
+ * "x" and "y". While in "x", they do ":e y|:f foo", which changes
+ * the name of that FRP entry. Then, the :n command finds the file
+ * "y" with a name change. If the file name has been changed, get
+ * a new FREF for the original file name, and make it be the one that
+ * is displayed in the argument list, not the one with the name change.
+ */
+ if (frp->cname != NULL) {
+ F_SET(frp, FR_IGNORE);
+ name = frp->name == NULL ? frp->tname : frp->name;
+ if ((frp = file_add(sp, sp->a_frp, name, 0)) == NULL)
+ return (1);
+ }
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ sp->a_frp = frp;
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_prev -- :prev
+ * Edit the previous file.
+ */
+int
+ex_prev(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp;
+ char *name;
+
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
+
+ if ((frp = file_prev(sp, sp->a_frp)) == NULL) {
+ msgq(sp, M_ERR, "No previous files to edit.");
+ return (1);
+ }
+
+ /* See comment in ex_next(). */
+ if (frp->cname != NULL) {
+ F_SET(frp, FR_IGNORE);
+ name = frp->name == NULL ? frp->tname : frp->name;
+ if ((frp = file_add(sp, frp, name, 0)) == NULL)
+ return (1);
+ }
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ sp->a_frp = frp;
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_rew -- :rew
+ * Re-edit the list of files.
+ */
+int
+ex_rew(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp, *tfrp;
+
+ /*
+ * !!!
+ * Historic practice -- you can rewind to the current file.
+ */
+ if ((frp = file_first(sp)) == NULL) {
+ msgq(sp, M_ERR, "No previous files to rewind.");
+ return (1);
+ }
+
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
+
+ /*
+ * !!!
+ * Historic practice, turn off the edited bit. The :next and :prev
+ * code will discard any name changes, so ignore them here. Start
+ * at the beginning of the file, too.
+ */
+ for (tfrp = sp->frefq.cqh_first;
+ tfrp != (FREF *)&sp->frefq; tfrp = tfrp->q.cqe_next)
+ F_CLR(tfrp, FR_CHANGEWRITE | FR_CURSORSET | FR_EDITED);
+
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ sp->a_frp = frp;
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_args -- :args
+ * Display the list of files.
+ */
+int
+ex_args(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp;
+ int cnt, col, iscur, len, nlen, sep;
+ char *name;
+
+ /*
+ * !!!
+ * Ignore files that aren't in the "argument" list unless they are the
+ * one we're currently editing. I'm not sure this is right, but the
+ * historic vi behavior of not showing the current file if it was the
+ * result of a ":e" command, or if the file name was changed was wrong.
+ * This is actually pretty tricky, don't modify it without thinking it
+ * through. There have been a lot of problems in here.
+ *
+ * Also, historic practice was to display the original name of the file
+ * even if the user had used a file command to change the file name.
+ * Confusing, at best. We show both names: the original as that's what
+ * the user will get in a next, prev or rewind, and the new one since
+ * that's what the user is actually editing now.
+ *
+ * When we find the "argument" FREF, i.e. the current location in the
+ * user's argument list, if it's not the same as the current FREF, we
+ * display the current FREF as following the argument in the list.
+ * This means that if the user edits three files, "x", "y" and "z", and
+ * then does a :e command in the file "x" to edit "z", "z" will appear
+ * in the list twice.
+ */
+ col = len = sep = 0;
+ for (cnt = 1, frp = sp->frefq.cqh_first;
+ frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next) {
+ iscur = 0;
+ /*
+ * If the last argument FREF structure, and we're editing
+ * it, set the current bit. Otherwise, we'll display it,
+ * then the file we're editing, and the latter will have
+ * the current bit set.
+ */
+ if (frp == sp->a_frp) {
+ if (frp == sp->frp && frp->cname == NULL)
+ iscur = 1;
+ } else if (F_ISSET(frp, FR_IGNORE))
+ continue;
+ name = frp->name == NULL ? frp->tname : frp->name;
+ /*
+ * Mistake. The user edited a temporary file (vi /tmp), then
+ * switched to another file (:e file). The argument FREF is
+ * pointing to the temporary file, but it doesn't have a name.
+ * Gracefully recover through the creative use of goto's.
+ */
+ if (name == NULL)
+ goto testcur;
+extra: nlen = strlen(name);
+ col += len = nlen + sep + (iscur ? 2 : 0);
+ if (col >= sp->cols - 1) {
+ col = len;
+ sep = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ } else if (cnt != 1) {
+ sep = 1;
+ (void)ex_printf(EXCOOKIE, " ");
+ }
+ ++cnt;
+
+ if (iscur)
+ (void)ex_printf(EXCOOKIE, "[%s]", name);
+ else {
+ (void)ex_printf(EXCOOKIE, "%s", name);
+testcur: if (frp == sp->a_frp) {
+ if (frp != sp->frp)
+ name = FILENAME(sp->frp);
+ else
+ name = frp->cname;
+ iscur = 1;
+ goto extra;
+ }
+ }
+ }
+ /* This should never happen; left in because it's been known to. */
+ if (cnt == 1)
+ (void)ex_printf(EXCOOKIE, "No files.\n");
+ else
+ (void)ex_printf(EXCOOKIE, "\n");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_argv.c b/usr.bin/vi/ex/ex_argv.c
new file mode 100644
index 000000000000..de2f6d5340aa
--- /dev/null
+++ b/usr.bin/vi/ex/ex_argv.c
@@ -0,0 +1,585 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_argv.c 8.28 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static int argv_alloc __P((SCR *, size_t));
+static int argv_fexp __P((SCR *, EXCMDARG *,
+ char *, size_t, char *, size_t *, char **, size_t *, int));
+static int argv_sexp __P((SCR *, char **, size_t *, size_t *));
+
+/*
+ * argv_init --
+ * Build a prototype arguments list.
+ */
+int
+argv_init(sp, ep, excp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+{
+ EX_PRIVATE *exp;
+
+ exp = EXP(sp);
+ exp->argsoff = 0;
+ argv_alloc(sp, 1);
+
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+ return (0);
+}
+
+/*
+ * argv_exp0 --
+ * Put a string into an argv.
+ */
+int
+argv_exp0(sp, ep, excp, cmd, cmdlen)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+{
+ EX_PRIVATE *exp;
+
+ exp = EXP(sp);
+ argv_alloc(sp, cmdlen);
+ memmove(exp->args[exp->argsoff]->bp, cmd, cmdlen);
+ exp->args[exp->argsoff]->bp[cmdlen] = '\0';
+ exp->args[exp->argsoff]->len = cmdlen;
+ ++exp->argsoff;
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+ return (0);
+}
+
+/*
+ * argv_exp1 --
+ * Do file name expansion on a string, and leave it in a string.
+ */
+int
+argv_exp1(sp, ep, excp, cmd, cmdlen, is_bang)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+ int is_bang;
+{
+ EX_PRIVATE *exp;
+ size_t blen, len;
+ char *bp;
+
+ GET_SPACE_RET(sp, bp, blen, 512);
+
+ len = 0;
+ exp = EXP(sp);
+ if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) {
+ FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+
+ argv_alloc(sp, len);
+ memmove(exp->args[exp->argsoff]->bp, bp, len);
+ exp->args[exp->argsoff]->bp[len] = '\0';
+ exp->args[exp->argsoff]->len = len;
+ ++exp->argsoff;
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+
+ FREE_SPACE(sp, bp, blen);
+ return (0);
+}
+
+/*
+ * argv_exp2 --
+ * Do file name and shell expansion on a string, and break
+ * it up into an argv.
+ */
+int
+argv_exp2(sp, ep, excp, cmd, cmdlen, is_bang)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+ int is_bang;
+{
+ size_t blen, len, n;
+ int rval;
+ char *bp, *p;
+
+ GET_SPACE_RET(sp, bp, blen, 512);
+
+#define SHELLECHO "echo "
+#define SHELLOFFSET (sizeof(SHELLECHO) - 1)
+ memmove(bp, SHELLECHO, SHELLOFFSET);
+ p = bp + SHELLOFFSET;
+ len = SHELLOFFSET;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd);
+#endif
+
+ if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, is_bang)) {
+ rval = 1;
+ goto err;
+ }
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "before shell: %d: {%s}\n", len, bp);
+#endif
+
+ /*
+ * Do shell word expansion -- it's very, very hard to figure out
+ * what magic characters the user's shell expects. If it's not
+ * pure vanilla, don't even try.
+ */
+ for (p = bp, n = len; n > 0; --n, ++p)
+ if (!isalnum(*p) && !isblank(*p) && *p != '/' && *p != '.')
+ break;
+ if (n > 0) {
+ if (argv_sexp(sp, &bp, &blen, &len)) {
+ rval = 1;
+ goto err;
+ }
+ p = bp;
+ } else {
+ p = bp + SHELLOFFSET;
+ len -= SHELLOFFSET;
+ }
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "after shell: %d: {%s}\n", len, bp);
+#endif
+
+ rval = argv_exp3(sp, ep, excp, p, len);
+
+err: FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * argv_exp3 --
+ * Take a string and break it up into an argv.
+ */
+int
+argv_exp3(sp, ep, excp, cmd, cmdlen)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+{
+ EX_PRIVATE *exp;
+ size_t len;
+ int ch, off;
+ char *ap, *p;
+
+ for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
+ /* Skip any leading whitespace. */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen == 0)
+ break;
+
+ /*
+ * Determine the length of this whitespace delimited
+ * argument.
+ *
+ * QUOTING NOTE:
+ *
+ * Skip any character preceded by the user's quoting
+ * character.
+ */
+ for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ ++cmd;
+ --cmdlen;
+ } else if (isblank(ch))
+ break;
+ }
+
+ /*
+ * Copy the argument into place.
+ *
+ * QUOTING NOTE:
+ *
+ * Lose quote chars.
+ */
+ argv_alloc(sp, len);
+ off = exp->argsoff;
+ exp->args[off]->len = len;
+ for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++)
+ if (IS_ESCAPE(sp, *ap)) {
+ ++ap;
+ --exp->args[off]->len;
+ }
+ *p = '\0';
+ }
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+
+#if defined(DEBUG) && 0
+ for (cnt = 0; cnt < exp->argsoff; ++cnt)
+ TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]);
+#endif
+ return (0);
+}
+
+/*
+ * argv_fexp --
+ * Do file name and bang command expansion.
+ */
+static int
+argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang)
+ SCR *sp;
+ EXCMDARG *excp;
+ char *cmd, *p, **bpp;
+ size_t cmdlen, *lenp, *blenp;
+ int is_bang;
+{
+ EX_PRIVATE *exp;
+ char *bp, *t;
+ size_t blen, len, tlen;
+
+ /* Replace file name characters. */
+ for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '!':
+ if (!is_bang)
+ goto ins_ch;
+ exp = EXP(sp);
+ if (exp->lastbcomm == NULL) {
+ msgq(sp, M_ERR,
+ "No previous command to replace \"!\".");
+ return (1);
+ }
+ len += tlen = strlen(exp->lastbcomm);
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, exp->lastbcomm, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '%':
+ if (sp->frp->cname == NULL && sp->frp->name == NULL) {
+ msgq(sp, M_ERR,
+ "No filename to substitute for %%.");
+ return (1);
+ }
+ tlen = strlen(t = FILENAME(sp->frp));
+ len += tlen;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, t, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '#':
+ /*
+ * Try the alternate file name first, then the
+ * previously edited file.
+ */
+ if (sp->alt_name == NULL && (sp->p_frp == NULL ||
+ sp->frp->cname == NULL && sp->frp->name == NULL)) {
+ msgq(sp, M_ERR,
+ "No filename to substitute for #.");
+ return (1);
+ }
+ if (sp->alt_name != NULL)
+ t = sp->alt_name;
+ else
+ t = FILENAME(sp->frp);
+ len += tlen = strlen(t);
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, t, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '\\':
+ /*
+ * QUOTING NOTE:
+ *
+ * Strip any backslashes that protected the file
+ * expansion characters.
+ */
+ if (cmdlen > 1 && cmd[1] == '%' || cmd[1] == '#')
+ ++cmd;
+ /* FALLTHROUGH */
+ default:
+ins_ch: ++len;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ *p++ = *cmd;
+ }
+
+ /* Nul termination. */
+ ++len;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ *p = '\0';
+
+ /* Return the new string length, buffer, buffer length. */
+ *lenp = len - 1;
+ *bpp = bp;
+ *blenp = blen;
+ return (0);
+}
+
+/*
+ * argv_alloc --
+ * Make more space for arguments.
+ */
+static int
+argv_alloc(sp, len)
+ SCR *sp;
+ size_t len;
+{
+ ARGS *ap;
+ EX_PRIVATE *exp;
+ int cnt, off;
+
+ /*
+ * Allocate room for another argument, always leaving
+ * enough room for an ARGS structure with a length of 0.
+ */
+#define INCREMENT 20
+ exp = EXP(sp);
+ off = exp->argsoff;
+ if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) {
+ cnt = exp->argscnt + INCREMENT;
+ REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *));
+ if (exp->args == NULL) {
+ (void)argv_free(sp);
+ goto mem;
+ }
+ memset(&exp->args[off], 0, INCREMENT * sizeof(ARGS *));
+ exp->argscnt = cnt;
+ }
+
+ /* First argument. */
+ if (exp->args[off] == NULL) {
+ CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
+ if (exp->args[off] == NULL)
+ goto mem;
+ }
+
+ /* First argument buffer. */
+ ap = exp->args[off];
+ ap->len = 0;
+ if (ap->blen < len + 1) {
+ ap->blen = len + 1;
+ REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T));
+ if (ap->bp == NULL) {
+ ap->bp = NULL;
+ ap->blen = 0;
+ F_CLR(ap, A_ALLOCATED);
+mem: msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ F_SET(ap, A_ALLOCATED);
+ }
+
+ /* Second argument. */
+ if (exp->args[++off] == NULL) {
+ CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
+ if (exp->args[off] == NULL)
+ goto mem;
+ }
+ /* 0 length serves as end-of-argument marker. */
+ exp->args[off]->len = 0;
+ return (0);
+}
+
+/*
+ * argv_free --
+ * Free up argument structures.
+ */
+int
+argv_free(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ int off;
+
+ exp = EXP(sp);
+ if (exp->args != NULL) {
+ for (off = 0; off < exp->argscnt; ++off) {
+ if (exp->args[off] == NULL)
+ continue;
+ if (F_ISSET(exp->args[off], A_ALLOCATED))
+ free(exp->args[off]->bp);
+ FREE(exp->args[off], sizeof(ARGS));
+ }
+ FREE(exp->args, exp->argscnt * sizeof(ARGS *));
+ }
+ exp->args = NULL;
+ exp->argscnt = 0;
+ exp->argsoff = 0;
+ return (0);
+}
+
+/*
+ * argv_sexp --
+ * Fork a shell, pipe a command through it, and read the output into
+ * a buffer.
+ */
+static int
+argv_sexp(sp, bpp, blenp, lenp)
+ SCR *sp;
+ char **bpp;
+ size_t *blenp, *lenp;
+{
+ FILE *ifp;
+ pid_t pid;
+ size_t blen, len;
+ int ch, rval, output[2];
+ char *bp, *p, *sh, *sh_path;
+
+ bp = *bpp;
+ blen = *blenp;
+
+ sh_path = O_STR(sp, O_SHELL);
+ if ((sh = strrchr(sh_path, '/')) == NULL)
+ sh = sh_path;
+ else
+ ++sh;
+
+ /*
+ * There are two different processes running through this code.
+ * They are named the utility and the parent. The utility reads
+ * from standard input and writes to the parent. The parent reads
+ * from the utility and writes into the buffer. The parent reads
+ * from output[0], and the utility writes to output[1].
+ */
+ if (pipe(output) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ return (1);
+ }
+ if ((ifp = fdopen(output[0], "r")) == NULL) {
+ msgq(sp, M_SYSERR, "fdopen");
+ goto err;
+ }
+
+ /*
+ * Do the minimal amount of work possible, the shell is going
+ * to run briefly and then exit. Hopefully.
+ */
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ msgq(sp, M_SYSERR, "vfork");
+err: (void)close(output[0]);
+ (void)close(output[1]);
+ return (1);
+ case 0: /* Utility. */
+ /* Redirect stdout/stderr to the write end of the pipe. */
+ (void)dup2(output[1], STDOUT_FILENO);
+ (void)dup2(output[1], STDERR_FILENO);
+
+ /* Close the utility's file descriptors. */
+ (void)close(output[0]);
+ (void)close(output[1]);
+
+ /* Assumes that all shells have -c. */
+ execl(sh_path, sh, "-c", bp, NULL);
+ msgq(sp, M_ERR,
+ "Error: execl: %s: %s", sh_path, strerror(errno));
+ _exit(127);
+ default:
+ /* Close the pipe end the parent won't use. */
+ (void)close(output[1]);
+ break;
+ }
+
+ rval = 0;
+
+ /*
+ * Copy process output into a buffer.
+ *
+ * !!!
+ * Historic vi apparently discarded leading \n and \r's from
+ * the shell output stream. We don't on the grounds that any
+ * shell that does that is broken.
+ */
+ for (p = bp, len = 0, ch = EOF;
+ (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len)
+ if (blen < 5) {
+ ADD_SPACE_GOTO(sp, bp, blen, *blenp * 2);
+ p = bp + len;
+ blen = *blenp - len;
+ }
+
+ /* Delete the final newline, nul terminate the string. */
+ if (p > bp && p[-1] == '\n' || p[-1] == '\r') {
+ --len;
+ *--p = '\0';
+ } else
+ *p = '\0';
+ *lenp = len;
+
+ if (ferror(ifp)) {
+ msgq(sp, M_ERR, "I/O error: %s", sh);
+binc_err: rval = 1;
+ }
+ (void)fclose(ifp);
+
+ *bpp = bp; /* *blenp is already updated. */
+
+ /* Wait for the process. */
+ return (proc_wait(sp, (long)pid, sh, 0) | rval);
+}
diff --git a/usr.bin/vi/ex/ex_at.c b/usr.bin/vi/ex/ex_at.c
new file mode 100644
index 000000000000..9b3da3fdb1cb
--- /dev/null
+++ b/usr.bin/vi/ex/ex_at.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_at.c 8.18 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_at -- :@[@ | buffer]
+ * :*[* | buffer]
+ *
+ * Execute the contents of the buffer.
+ */
+int
+ex_at(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CB *cbp;
+ EX_PRIVATE *exp;
+ TEXT *tp;
+ int name, lmode;
+
+ exp = EXP(sp);
+
+ /* Historically, @@ and ** execute the last buffer. */
+ name = cmdp->buffer;
+ if (name == cmdp->cmd->name[0]) {
+ if (!exp->at_lbuf_set) {
+ msgq(sp, M_ERR, "No previous buffer to execute.");
+ return (1);
+ }
+ name = exp->at_lbuf;
+ }
+
+ CBNAME(sp, cbp, name);
+ if (cbp == NULL) {
+ msgq(sp, M_ERR, "Buffer %s is empty.", charname(sp, name));
+ return (1);
+ }
+
+ /* Save for reuse. */
+ exp->at_lbuf = name;
+ exp->at_lbuf_set = 1;
+
+ /*
+ * If the buffer was cut in line mode or had portions of more
+ * than one line, <newlines> are appended to each line as it
+ * is pushed onto the stack.
+ */
+ tp = cbp->textq.cqh_last;
+ lmode = F_ISSET(cbp, CB_LMODE) || tp->q.cqe_prev != (void *)&cbp->textq;
+ for (; tp != (void *)&cbp->textq; tp = tp->q.cqe_prev)
+ if ((lmode || tp->q.cqe_prev != (void *)&cbp->textq) &&
+ term_push(sp, "\n", 1, 0, 0) ||
+ term_push(sp, tp->lb, tp->len, 0, CH_QUOTED))
+ return (1);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_bang.c b/usr.bin/vi/ex/ex_bang.c
new file mode 100644
index 000000000000..34b477a0d97a
--- /dev/null
+++ b/usr.bin/vi/ex/ex_bang.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_bang.c 8.24 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "sex/sex_screen.h"
+
+/*
+ * ex_bang -- :[line [,line]] ! command
+ *
+ * Pass the rest of the line after the ! character to the program named by
+ * the O_SHELL option.
+ *
+ * Historical vi did NOT do shell expansion on the arguments before passing
+ * them, only file name expansion. This means that the O_SHELL program got
+ * "$t" as an argument if that is what the user entered. Also, there's a
+ * special expansion done for the bang command. Any exclamation points in
+ * the user's argument are replaced by the last, expanded ! command.
+ *
+ * There's some fairly amazing slop in this routine to make the different
+ * ways of getting here display the right things. It took a long time to
+ * get get right (wrong?), so be careful.
+ */
+int
+ex_bang(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum filtertype ftype;
+ ARGS *ap;
+ EX_PRIVATE *exp;
+ MARK rm;
+ recno_t lno;
+ size_t blen;
+ int rval;
+ char *bp, *msg;
+
+ ap = cmdp->argv[0];
+ if (ap->len == 0) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ /* Swap commands. */
+ exp = EXP(sp);
+ if (exp->lastbcomm != NULL)
+ FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1);
+ if ((exp->lastbcomm = strdup(ap->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /*
+ * If the command was modified by the expansion, we redisplay it.
+ * Redisplaying it in vi mode is tricky, and handled separately
+ * in each case below. If we're in ex mode, it's easy, so we just
+ * do it here.
+ */
+ bp = NULL;
+ if (F_ISSET(cmdp, E_MODIFY)) {
+ if (IN_EX_MODE(sp)) {
+ (void)ex_printf(EXCOOKIE, "!%s\n", ap->bp);
+ (void)ex_fflush(EXCOOKIE);
+ }
+ /*
+ * Vi: Display the command if modified. Historic vi displayed
+ * the command if it was modified due to file name and/or bang
+ * expansion. If piping lines, it was immediately overwritten
+ * by any error or line change reporting. We don't the user to
+ * have to page through the responses, so we only post it until
+ * it's erased by something else. Otherwise, pass it on to the
+ * ex_exec_proc routine to display after the screen has been
+ * cleaned up.
+ */
+ if (IN_VI_MODE(sp)) {
+ GET_SPACE_RET(sp, bp, blen, ap->len + 2);
+ bp[0] = '!';
+ memmove(bp + 1, ap->bp, ap->len + 1);
+ }
+ }
+
+ /*
+ * If addresses were specified, pipe lines from the file through
+ * the command.
+ */
+ if (cmdp->addrcnt != 0) {
+ if (bp != NULL) {
+ (void)sp->s_busy(sp, bp);
+ FREE_SPACE(sp, bp, blen);
+ }
+ /*
+ * !!!
+ * Historical vi permitted "!!" in an empty file. When it
+ * happens, we get called with two addresses of 1,1 and a
+ * bad attitude.
+ */
+ ftype = FILTER;
+ if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ cmdp->addr1.lno = cmdp->addr2.lno = 0;
+ ftype = FILTER_READ;
+ }
+ }
+ if (filtercmd(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype))
+ return (1);
+ sp->lno = rm.lno;
+ F_SET(exp, EX_AUTOPRINT);
+ return (0);
+ }
+
+ /*
+ * If no addresses were specified, run the command. If the file
+ * has been modified and autowrite is set, write the file back.
+ * If the file has been modified, autowrite is not set and the
+ * warn option is set, tell the user about the file.
+ */
+ msg = "\n";
+ if (F_ISSET(ep, F_MODIFIED))
+ if (O_ISSET(sp, O_AUTOWRITE)) {
+ if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) {
+ rval = 1;
+ goto ret;
+ }
+ } else if (O_ISSET(sp, O_WARN))
+ if (IN_VI_MODE(sp) && F_ISSET(cmdp, E_MODIFY))
+ msg = "\nFile modified since last write.\n";
+ else
+ msg = "File modified since last write.\n";
+
+ /* Run the command. */
+ rval = ex_exec_proc(sp, ap->bp, bp, msg);
+
+ /* Ex terminates with a bang. */
+ if (IN_EX_MODE(sp))
+ (void)write(STDOUT_FILENO, "!\n", 2);
+
+ /* Vi requires user permission to continue. */
+ if (IN_VI_MODE(sp))
+ F_SET(sp, S_CONTINUE);
+
+ /* Free the extra space. */
+ret: if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_cd.c b/usr.bin/vi/ex/ex_cd.c
new file mode 100644
index 000000000000..098af534f676
--- /dev/null
+++ b/usr.bin/vi/ex/ex_cd.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_cd.c 8.10 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_cd -- :cd[!] [directory]
+ * Change directories.
+ */
+int
+ex_cd(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CDPATH *cdp;
+ EX_PRIVATE *exp;
+ char *dir, buf[MAXPATHLEN];
+
+ switch (cmdp->argc) {
+ case 0:
+ if ((dir = getenv("HOME")) == NULL) {
+ msgq(sp, M_ERR,
+ "Environment variable HOME not set.");
+ return (1);
+ }
+ break;
+ case 1:
+ dir = cmdp->argv[0]->bp;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * If the user has a CDPATH variable, we use it, otherwise
+ * we use the current directory.
+ *
+ * !!!
+ * This violates historic practice. Historic vi didn't consider
+ * CDPATH, and therefore always used the current directory. This
+ * is probably correct; if user's have set CDPATH to not include
+ * the current directory, they probably had a reason.
+ */
+ exp = EXP(sp);
+ if (dir[0] == '/') {
+ if (chdir(dir) < 0)
+ goto err;
+ } else {
+ for (cdp = exp->cdq.tqh_first;
+ cdp != NULL; cdp = cdp->q.tqe_next) {
+ (void)snprintf(buf,
+ sizeof(buf), "%s/%s", cdp->path, dir);
+ if (!chdir(buf))
+ break;
+ }
+ if (cdp == NULL) {
+err: msgq(sp, M_SYSERR, dir);
+ return (1);
+ }
+ }
+ if (getcwd(buf, sizeof(buf)) != NULL)
+ msgq(sp, M_INFO, "New directory: %s", buf);
+ return (0);
+}
+
+#define FREE_CDPATH(cdp) { \
+ TAILQ_REMOVE(&exp->cdq, (cdp), q); \
+ free((cdp)->path); \
+ FREE((cdp), sizeof(CDPATH)); \
+}
+/*
+ * ex_cdalloc --
+ * Create a new list of cd paths.
+ */
+int
+ex_cdalloc(sp, str)
+ SCR *sp;
+ char *str;
+{
+ EX_PRIVATE *exp;
+ CDPATH *cdp;
+ size_t len;
+ int founddot;
+ char *p, *t;
+
+ /* Free current queue. */
+ exp = EXP(sp);
+ while ((cdp = exp->cdq.tqh_first) != NULL)
+ FREE_CDPATH(cdp);
+
+ /*
+ * Create new queue. The CDPATH environmental variable (and the
+ * user's manual entry) are delimited by colon characters.
+ */
+ for (p = t = str, founddot = 0;; ++p) {
+ if (*p == '\0' || *p == ':') {
+ /*
+ * Empty strings specify ".". The only way to get an
+ * empty string is a leading colon, colons in a row,
+ * or a trailing colon. Or, to put it the other way,
+ * if the the length is zero, then it's either ":XXX",
+ * "XXX::XXXX" , "XXX:", or "", and the only failure
+ * mode is the last one. Note, the string ":" gives
+ * us two entries of '.', so we only include one of
+ * them.
+ */
+ if ((len = p - t) == 0) {
+ if (p == str && *p == '\0')
+ break;
+ if (founddot) {
+ if (*p == '\0')
+ break;
+ continue;
+ }
+ len = 1;
+ t = ".";
+ founddot = 1;
+ }
+ MALLOC_RET(sp, cdp, CDPATH *, sizeof(CDPATH));
+ MALLOC(sp, cdp->path, char *, len + 1);
+ if (cdp->path == NULL) {
+ free(cdp);
+ return (1);
+ }
+ memmove(cdp->path, t, len);
+ cdp->path[len] = '\0';
+ TAILQ_INSERT_TAIL(&exp->cdq, cdp, q);
+ t = p + 1;
+ }
+ if (*p == '\0')
+ break;
+ }
+ return (0);
+}
+ /* Free previous queue. */
+/*
+ * ex_cdfree --
+ * Free the cd path list.
+ */
+int
+ex_cdfree(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ CDPATH *cdp;
+
+ /* Free up cd path information. */
+ exp = EXP(sp);
+ while ((cdp = exp->cdq.tqh_first) != NULL)
+ FREE_CDPATH(cdp);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_delete.c b/usr.bin/vi/ex/ex_delete.c
new file mode 100644
index 000000000000..78512699c202
--- /dev/null
+++ b/usr.bin/vi/ex/ex_delete.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_delete.c 8.7 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags]
+ *
+ * Delete lines from the file.
+ */
+int
+ex_delete(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ /* Yank the lines. */
+ if (cut(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &cmdp->addr2, CUT_DELETE | CUT_LINEMODE))
+ return (1);
+
+ /* Delete the lines. */
+ if (delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1))
+ return (1);
+
+ /* Set the cursor to the line after the last line deleted. */
+ sp->lno = cmdp->addr1.lno;
+
+ /* Or the last line in the file if deleted to the end of the file. */
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (sp->lno > lno)
+ sp->lno = lno;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_digraph.c b/usr.bin/vi/ex/ex_digraph.c
new file mode 100644
index 000000000000..0b80cd01a333
--- /dev/null
+++ b/usr.bin/vi/ex/ex_digraph.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_digraph.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#ifndef NO_DIGRAPH
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static void do_digraph __P((SCR *, EXF *, int, u_char *));
+
+/* This stuff is used to build the default digraphs table. */
+static u_char digtable[][4] = {
+# ifdef CS_IBMPC
+ "C,\200", "u\"\1", "e'\2", "a^\3",
+ "a\"\4", "a`\5", "a@\6", "c,\7",
+ "e^\10", "e\"\211", "e`\12", "i\"\13",
+ "i^\14", "i`\15", "A\"\16", "A@\17",
+ "E'\20", "ae\21", "AE\22", "o^\23",
+ "o\"\24", "o`\25", "u^\26", "u`\27",
+ "y\"\30", "O\"\31", "U\"\32", "a'\240",
+ "i'!", "o'\"", "u'#", "n~$",
+ "N~%", "a-&", "o-'", "~?(",
+ "~!-", "\"<.", "\">/",
+# ifdef CS_SPECIAL
+ "2/+", "4/,", "^+;", "^q<",
+ "^c=", "^r>", "^t?", "pp]",
+ "^^^", "oo_", "*a`", "*ba",
+ "*pc", "*Sd", "*se", "*uf",
+ "*tg", "*Ph", "*Ti", "*Oj",
+ "*dk", "*Hl", "*hm", "*En",
+ "*No", "eqp", "pmq", "ger",
+ "les", "*It", "*iu", "*/v",
+ "*=w", "sq{", "^n|", "^2}",
+ "^3~", "^_\377",
+# endif /* CS_SPECIAL */
+# endif /* CS_IBMPC */
+# ifdef CS_LATIN1
+ "~!!", "a-*", "\">+", "o-:",
+ "\"<>", "~??",
+
+ "A`@", "A'A", "A^B", "A~C",
+ "A\"D", "A@E", "AEF", "C,G",
+ "E`H", "E'I", "E^J", "E\"K",
+ "I`L", "I'M", "I^N", "I\"O",
+ "-DP", "N~Q", "O`R", "O'S",
+ "O^T", "O~U", "O\"V", "O/X",
+ "U`Y", "U'Z", "U^[", "U\"\\",
+ "Y'_",
+
+ "a``", "a'a", "a^b", "a~c",
+ "a\"d", "a@e", "aef", "c,g",
+ "e`h", "e'i", "e^j", "e\"k",
+ "i`l", "i'm", "i^n", "i\"o",
+ "-dp", "n~q", "o`r", "o's",
+ "o^t", "o~u", "o\"v", "o/x",
+ "u`y", "u'z", "u^{", "u\"|",
+ "y'~",
+# endif /* CS_LATIN1 */
+ ""
+};
+
+int
+digraph_init(sp)
+ SCR *sp;
+{
+ int i;
+
+ for (i = 0; *digtable[i]; i++)
+ do_digraph(sp, NULL, 0, digtable[i]);
+ do_digraph(sp, NULL, 0, NULL);
+ return (0);
+}
+
+int
+ex_digraph(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ do_digraph(sp, ep, F_ISSET(cmdp, E_FORCE), cmdp->argv[0]->bp);
+ return (0);
+}
+
+static struct _DIG
+{
+ struct _DIG *next;
+ char key1;
+ char key2;
+ char dig;
+ char save;
+} *digs;
+
+int
+digraph(sp, key1, key2)
+ SCR *sp;
+ char key1; /* the underlying character */
+ char key2; /* the second character */
+{
+ int new_key;
+ register struct _DIG *dp;
+
+ /* if digraphs are disabled, then just return the new char */
+ if (O_ISSET(sp, O_DIGRAPH))
+ {
+ return key2;
+ }
+
+ /* remember the new key, so we can return it if this isn't a digraph */
+ new_key = key2;
+
+ /* sort key1 and key2, so that their original order won't matter */
+ if (key1 > key2)
+ {
+ key2 = key1;
+ key1 = new_key;
+ }
+
+ /* scan through the digraph chart */
+ for (dp = digs;
+ dp && (dp->key1 != key1 || dp->key2 != key2);
+ dp = dp->next)
+ {
+ }
+
+ /* if this combination isn't in there, just use the new key */
+ if (!dp)
+ {
+ return new_key;
+ }
+
+ /* else use the digraph key */
+ return dp->dig;
+}
+
+/* this function lists or defines digraphs */
+static void
+do_digraph(sp, ep, bang, extra)
+ SCR *sp;
+ EXF *ep;
+ int bang;
+ u_char *extra;
+{
+ int dig;
+ register struct _DIG *dp;
+ struct _DIG *prev;
+ static int user_defined = 0; /* boolean: are all later digraphs user-defined? */
+ char listbuf[8];
+
+ /* if "extra" is NULL, then we've reached the end of the built-ins */
+ if (!extra)
+ {
+ user_defined = 1;
+ return;
+ }
+
+ /* if no args, then display the existing digraphs */
+ if (*extra < ' ')
+ {
+ listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
+ listbuf[7] = '\0';
+ for (dig = 0, dp = digs; dp; dp = dp->next)
+ {
+ if (dp->save || bang)
+ {
+ dig += 7;
+ if (dig >= sp->cno)
+ {
+ addch('\n');
+ refresh();
+ dig = 7;
+ }
+ listbuf[3] = dp->key1;
+ listbuf[4] = dp->key2;
+ listbuf[6] = dp->dig;
+ addstr(listbuf);
+ }
+ }
+ addch('\n');
+ refresh();
+ return;
+ }
+
+ /* make sure we have at least two characters */
+ if (!extra[1])
+ {
+ msgq(sp, M_ERR,
+ "Digraphs must be composed of two characters");
+ return;
+ }
+
+ /* sort key1 and key2, so that their original order won't matter */
+ if (extra[0] > extra[1])
+ {
+ dig = extra[0];
+ extra[0] = extra[1];
+ extra[1] = dig;
+ }
+
+ /* locate the new digraph character */
+ for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
+ {
+ }
+ dig = extra[dig];
+ if (!bang && dig)
+ {
+ dig |= 0x80;
+ }
+
+ /* search for the digraph */
+ for (prev = (struct _DIG *)0, dp = digs;
+ dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
+ prev = dp, dp = dp->next)
+ {
+ }
+
+ /* deleting the digraph? */
+ if (!dig)
+ {
+ if (!dp)
+ {
+#ifndef CRUNCH
+ msgq(sp, M_ERR,
+ "%c%c not a digraph", extra[0], extra[1]);
+#endif
+ return;
+ }
+ if (prev)
+ prev->next = dp->next;
+ else
+ digs = dp->next;
+ free(dp);
+ return;
+ }
+
+ /* if necessary, create a new digraph struct for the new digraph */
+ if (dig && !dp)
+ {
+ MALLOC(sp, dp, struct _DIG *, sizeof(struct _DIG));
+ if (dp == NULL)
+ return;
+ if (prev)
+ prev->next = dp;
+ else
+ digs = dp;
+ dp->next = (struct _DIG *)0;
+ }
+
+ /* assign it the new digraph value */
+ dp->key1 = extra[0];
+ dp->key2 = extra[1];
+ dp->dig = dig;
+ dp->save = user_defined;
+}
+
+void
+digraph_save(sp, fd)
+ SCR *sp;
+ int fd;
+{
+ static char buf[] = "digraph! XX Y\n";
+ register struct _DIG *dp;
+
+ for (dp = digs; dp; dp = dp->next)
+ {
+ if (dp->save)
+ {
+ buf[9] = dp->key1;
+ buf[10] = dp->key2;
+ buf[12] = dp->dig;
+ write(fd, buf, (unsigned)14);
+ }
+ }
+}
+#endif
diff --git a/usr.bin/vi/ex/ex_display.c b/usr.bin/vi/ex/ex_display.c
new file mode 100644
index 000000000000..2f4f65bdca62
--- /dev/null
+++ b/usr.bin/vi/ex/ex_display.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_display.c 8.15 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "tag.h"
+#include "excmd.h"
+
+static int bdisplay __P((SCR *, EXF *));
+static void db __P((SCR *, CB *, char *));
+
+/*
+ * ex_display -- :display b[uffers] | s[creens] | t[ags]
+ *
+ * Display buffers, tags or screens.
+ */
+int
+ex_display(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ switch (cmdp->argv[0]->bp[0]) {
+ case 'b':
+ return (bdisplay(sp, ep));
+ case 's':
+ return (ex_sdisplay(sp, ep));
+ case 't':
+ return (ex_tagdisplay(sp, ep));
+ }
+ msgq(sp, M_ERR,
+ "Unknown display argument %s, use b[uffers], s[creens], or t[ags].",
+ cmdp->argv[0]);
+ return (1);
+}
+
+/*
+ * bdisplay --
+ *
+ * Display buffers.
+ */
+static int
+bdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ CB *cbp;
+
+ if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) {
+ (void)ex_printf(EXCOOKIE, "No cut buffers to display.");
+ return (0);
+ }
+
+ /* Buffers can be infinitely long, make it interruptible. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ /* Display regular cut buffers. */
+ for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+ if (isdigit(cbp->name))
+ continue;
+ if (cbp->textq.cqh_first != (void *)&cbp->textq)
+ db(sp, cbp, NULL);
+ if (F_ISSET(sp, S_INTERRUPTED))
+ return (0);
+ }
+ /* Display numbered buffers. */
+ for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+ if (!isdigit(cbp->name))
+ continue;
+ if (cbp->textq.cqh_first != (void *)&cbp->textq)
+ db(sp, cbp, NULL);
+ if (F_ISSET(sp, S_INTERRUPTED))
+ return (0);
+ }
+ /* Display default buffer. */
+ if ((cbp = sp->gp->dcbp) != NULL)
+ db(sp, cbp, "default buffer");
+ return (0);
+}
+
+/*
+ * db --
+ * Display a buffer.
+ */
+static void
+db(sp, cbp, name)
+ SCR *sp;
+ CB *cbp;
+ char *name;
+{
+ TEXT *tp;
+ size_t len;
+ char *p;
+
+ (void)ex_printf(EXCOOKIE, "********** %s%s\n",
+ name == NULL ? charname(sp, cbp->name) : name,
+ F_ISSET(cbp, CB_LMODE) ? " (line mode)" : "");
+ for (tp = cbp->textq.cqh_first;
+ tp != (void *)&cbp->textq; tp = tp->q.cqe_next) {
+ for (len = tp->len, p = tp->lb; len--;) {
+ (void)ex_printf(EXCOOKIE, "%s", charname(sp, *p++));
+ if (F_ISSET(sp, S_INTERRUPTED))
+ return;
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+}
diff --git a/usr.bin/vi/ex/ex_edit.c b/usr.bin/vi/ex/ex_edit.c
new file mode 100644
index 000000000000..03629bf7309f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_edit.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_edit.c 8.15 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_edit -- :e[dit][!] [+cmd] [file]
+ * :vi[sual][!] [+cmd] [file]
+ *
+ * Edit a file; if none specified, re-edit the current file. The second
+ * form of the command can only be executed while in vi mode. See the
+ * hack in ex.c:ex_cmd().
+ *
+ * !!!
+ * Historic vi didn't permit the '+' command form without specifying
+ * a file name as well.
+ */
+int
+ex_edit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+ FREF *frp;
+
+ frp = sp->frp;
+ switch (cmdp->argc) {
+ case 0:
+ /*
+ * If the name has been changed, we edit that file, not the
+ * original name. If the user was editing a temporary file,
+ * create another one. The reason for this is that we do
+ * special exit processing of temporary files, and reusing
+ * them is tricky.
+ */
+ if (frp->cname != NULL) {
+ if ((frp = file_add(sp, frp, frp->cname, 1)) == NULL)
+ return (1);
+ set_alt_name(sp, sp->frp->cname);
+ } else if (frp->name == NULL)
+ if ((frp = file_add(sp, frp, NULL, 1)) == NULL)
+ return (1);
+ break;
+ case 1:
+ ap = cmdp->argv[0];
+ if ((frp = file_add(sp, sp->frp, ap->bp, 1)) == NULL)
+ return (1);
+ set_alt_name(sp, ap->bp);
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * Check for modifications.
+ *
+ * !!!
+ * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit.
+ */
+ if (F_ISSET(ep, F_MODIFIED) &&
+ ep->refcnt <= 1 && !F_ISSET(cmdp, E_FORCE)) {
+ msgq(sp, M_ERR,
+ "Modified since last write; write or use ! to override.");
+ return (1);
+ }
+
+ /* Switch files. */
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_equal.c b/usr.bin/vi/ex/ex_equal.c
new file mode 100644
index 000000000000..0caf0051ec2f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_equal.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_equal.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_equal -- :address =
+ * Print out the line number matching the specified address, or the
+ * last line number in the file if no address specified.
+ */
+int
+ex_equal(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ if (F_ISSET(cmdp, E_ADDRDEF)) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ (void)ex_printf(EXCOOKIE, "%ld\n", lno);
+ } else
+ (void)ex_printf(EXCOOKIE, "%ld\n", cmdp->addr1.lno);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_exit.c b/usr.bin/vi/ex/ex_exit.c
new file mode 100644
index 000000000000..ebfc9d03bca2
--- /dev/null
+++ b/usr.bin/vi/ex/ex_exit.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_exit.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_quit -- :quit[!]
+ * Quit.
+ */
+int
+ex_quit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ force = F_ISSET(cmdp, E_FORCE);
+
+ /* Check for modifications. */
+ if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) {
+ msgq(sp, M_ERR,
+ "Modified since last write; write or use ! to override.");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historic practice: quit! or two quit's done in succession
+ * (where ZZ counts as a quit) didn't check for other files.
+ *
+ * Also check for related screens; if they exist, quit, the
+ * user will get the message on the last screen.
+ */
+ if (!force && sp->ccnt != sp->q_ccnt + 1 &&
+ ep->refcnt <= 1 && file_unedited(sp) != NULL) {
+ sp->q_ccnt = sp->ccnt;
+ msgq(sp, M_ERR,
+ "More files; use \":n\" to go to the next file, \":q!\" to quit.");
+ return (1);
+ }
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_file.c b/usr.bin/vi/ex/ex_file.c
new file mode 100644
index 000000000000..57923db350c1
--- /dev/null
+++ b/usr.bin/vi/ex/ex_file.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_file.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_file -- :f[ile] [name]
+ * Status line and change the file's name.
+ */
+int
+ex_file(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp;
+ char *p, *t;
+
+ switch (cmdp->argc) {
+ case 0:
+ break;
+ case 1:
+ frp = sp->frp;
+
+ /* Make sure can allocate enough space. */
+ if ((p = strdup(cmdp->argv[0]->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /* If already have a file name, it becomes the alternate. */
+ if ((t = FILENAME(frp)) != NULL)
+ set_alt_name(sp, t);
+
+ /* Free any previously changed name. */
+ if (frp->cname != NULL)
+ free(frp->cname);
+ frp->cname = p;
+
+ /* The read-only bit follows the file name; clear it. */
+ F_CLR(frp, FR_RDONLY);
+
+ /* Have to force a write if the file exists, next time. */
+ F_CLR(frp, FR_CHANGEWRITE);
+ break;
+ default:
+ abort();
+ }
+ status(sp, ep, sp->lno, 1);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_global.c b/usr.bin/vi/ex/ex_global.c
new file mode 100644
index 000000000000..ea770a6c3c07
--- /dev/null
+++ b/usr.bin/vi/ex/ex_global.c
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_global.c 8.32 (Berkeley) 3/22/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {GLOBAL, VGLOBAL};
+
+static int global __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
+ * Exec on lines matching a pattern.
+ */
+int
+ex_global(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (global(sp, ep,
+ cmdp, F_ISSET(cmdp, E_FORCE) ? VGLOBAL : GLOBAL));
+}
+
+/*
+ * ex_vglobal -- [line [,line]] v[global] /pattern/ [commands]
+ * Exec on lines not matching a pattern.
+ */
+int
+ex_vglobal(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (global(sp, ep, cmdp, VGLOBAL));
+}
+
+static int
+global(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ RANGE *rp;
+ EX_PRIVATE *exp;
+ recno_t elno, lno;
+ regmatch_t match[1];
+ regex_t *re, lre;
+ size_t clen, len;
+ int delim, eval, reflags, replaced, rval, teardown;
+ char *cb, *ptrn, *p, *t;
+
+ /*
+ * Skip leading white space. Historic vi allowed any non-
+ * alphanumeric to serve as the global command delimiter.
+ */
+ for (p = cmdp->argv[0]->bp; isblank(*p); ++p);
+ if (*p == '\0' || isalnum(*p)) {
+ msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
+ return (1);
+ }
+ delim = *p++;
+
+ /*
+ * Get the pattern string, toss escaped characters.
+ *
+ * QUOTING NOTE:
+ * Only toss an escaped character if it escapes a delimiter.
+ */
+ for (ptrn = t = p;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ /*
+ * !!!
+ * Nul terminate the pattern string -- it's passed
+ * to regcomp which doesn't understand anything else.
+ */
+ *t = '\0';
+ break;
+ }
+ if (p[0] == '\\' && p[1] == delim)
+ ++p;
+ *t++ = *p++;
+ }
+
+ /* If the pattern string is empty, use the last one. */
+ if (*ptrn == '\0') {
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression.");
+ return (1);
+ }
+ re = &sp->sre;
+ } else {
+ /* Set RE flags. */
+ reflags = 0;
+ if (O_ISSET(sp, O_EXTENDED))
+ reflags |= REG_EXTENDED;
+ if (O_ISSET(sp, O_IGNORECASE))
+ reflags |= REG_ICASE;
+
+ /* Convert vi-style RE's to POSIX 1003.2 RE's. */
+ if (re_conv(sp, &ptrn, &replaced))
+ return (1);
+
+ /* Compile the RE. */
+ re = &lre;
+ eval = regcomp(re, ptrn, reflags);
+
+ /* Free up any allocated memory. */
+ if (replaced)
+ free(ptrn);
+
+ if (eval) {
+ re_error(sp, eval, re);
+ return (1);
+ }
+
+ /*
+ * Set saved RE. Historic practice is that
+ * globals set direction as well as the RE.
+ */
+ sp->sre = lre;
+ sp->searchdir = FORWARD;
+ F_SET(sp, S_SRE_SET);
+ }
+
+ /* Get a copy of the command string. */
+ if ((clen = strlen(p)) == 0) {
+ msgq(sp, M_ERR, "No command string specified.");
+ return (1);
+ }
+ MALLOC_RET(sp, cb, char *, clen);
+ memmove(cb, p, clen);
+
+ /*
+ * The global commands sets the substitute RE as well as
+ * the everything-else RE.
+ */
+ sp->subre = sp->sre;
+ F_SET(sp, S_SUBRE_SET);
+
+ /* Set the global flag, and set up interrupts. */
+ F_SET(sp, S_GLOBAL);
+ teardown = !intr_init(sp);
+
+ /*
+ * For each line... The semantics of global matching are that we first
+ * have to decide which lines are going to get passed to the command,
+ * and then pass them to the command, ignoring other changes. There's
+ * really no way to do this in a single pass, since arbitrary line
+ * creation, deletion and movement can be done in the ex command. For
+ * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d".
+ * What we do is create linked list of lines that are tracked through
+ * each ex command. There's a callback routine which the DB interface
+ * routines call when a line is created or deleted. This doesn't help
+ * the layering much.
+ */
+ exp = EXP(sp);
+ for (rval = 0, lno = cmdp->addr1.lno,
+ elno = cmdp->addr2.lno; lno <= elno; ++lno) {
+ /* Someone's unhappy, time to stop. */
+ if (F_ISSET(sp, S_INTERRUPTED))
+ goto interrupted;
+
+ /* Get the line and search for a match. */
+ if ((t = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ goto err;
+ }
+ match[0].rm_so = 0;
+ match[0].rm_eo = len;
+ switch(eval = regexec(re, t, 1, match, REG_STARTEND)) {
+ case 0:
+ if (cmd == VGLOBAL)
+ continue;
+ break;
+ case REG_NOMATCH:
+ if (cmd == GLOBAL)
+ continue;
+ break;
+ default:
+ re_error(sp, eval, re);
+ goto err;
+ }
+
+ /* If follows the last entry, extend the last entry's range. */
+ if ((rp = exp->rangeq.cqh_last) != (void *)&exp->rangeq &&
+ rp->stop == lno - 1) {
+ ++rp->stop;
+ continue;
+ }
+
+ /* Allocate a new range, and append it to the list. */
+ CALLOC(sp, rp, RANGE *, 1, sizeof(RANGE));
+ if (rp == NULL)
+ goto err;
+ rp->start = rp->stop = lno;
+ CIRCLEQ_INSERT_TAIL(&exp->rangeq, rp, q);
+ }
+
+ exp = EXP(sp);
+ exp->range_lno = OOBLNO;
+ for (;;) {
+ /*
+ * Start at the beginning of the range each time, it may have
+ * been changed (or exhausted) if lines were inserted/deleted.
+ */
+ if ((rp = exp->rangeq.cqh_first) == (void *)&exp->rangeq)
+ break;
+ if (rp->start > rp->stop) {
+ CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
+ free(rp);
+ continue;
+ }
+
+ /*
+ * Execute the command, setting the cursor to the line so that
+ * relative addressing works. This means that the cursor moves
+ * to the last line sent to the command, by default, even if
+ * the command fails.
+ */
+ exp->range_lno = sp->lno = rp->start++;
+ if (ex_cmd(sp, ep, cb, clen))
+ goto err;
+
+ /* Someone's unhappy, time to stop. */
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+interrupted: msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+ }
+
+ /* Set the cursor to the new value, making sure it exists. */
+ if (exp->range_lno != OOBLNO) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ sp->lno =
+ lno < exp->range_lno ? (lno ? lno : 1) : exp->range_lno;
+ }
+ if (0) {
+err: rval = 1;
+ }
+
+ F_CLR(sp, S_GLOBAL);
+ if (teardown)
+ intr_end(sp);
+
+ /* Free any remaining ranges and the command buffer. */
+ while ((rp = exp->rangeq.cqh_first) != (void *)&exp->rangeq) {
+ CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
+ free(rp);
+ }
+ free(cb);
+ return (rval);
+}
+
+/*
+ * global_insdel --
+ * Update the ranges based on an insertion or deletion.
+ */
+void
+global_insdel(sp, ep, op, lno)
+ SCR *sp;
+ EXF *ep;
+ enum operation op;
+ recno_t lno;
+{
+ EX_PRIVATE *exp;
+ RANGE *nrp, *rp;
+
+ exp = EXP(sp);
+
+ switch (op) {
+ case LINE_APPEND:
+ return;
+ case LINE_DELETE:
+ for (rp = exp->rangeq.cqh_first;
+ rp != (void *)&exp->rangeq; rp = nrp) {
+ nrp = rp->q.cqe_next;
+ /* If range less than the line, ignore it. */
+ if (rp->stop < lno)
+ continue;
+ /* If range greater than the line, decrement range. */
+ if (rp->start > lno) {
+ --rp->start;
+ --rp->stop;
+ continue;
+ }
+ /* Lno is inside the range, decrement the end point. */
+ if (rp->start > --rp->stop) {
+ CIRCLEQ_REMOVE(&exp->rangeq, rp, q);
+ free(rp);
+ }
+ }
+ break;
+ case LINE_INSERT:
+ for (rp = exp->rangeq.cqh_first;
+ rp != (void *)&exp->rangeq; rp = rp->q.cqe_next) {
+ /* If range less than the line, ignore it. */
+ if (rp->stop < lno)
+ continue;
+ /* If range greater than the line, increment range. */
+ if (rp->start >= lno) {
+ ++rp->start;
+ ++rp->stop;
+ continue;
+ }
+ /*
+ * Lno is inside the range, so the range must be split.
+ * Since we're inserting a new element, neither range
+ * can be exhausted.
+ */
+ CALLOC(sp, nrp, RANGE *, 1, sizeof(RANGE));
+ if (nrp == NULL) {
+ F_SET(sp, S_INTERRUPTED);
+ return;
+ }
+ nrp->start = lno + 1;
+ nrp->stop = rp->stop + 1;
+ rp->stop = lno - 1;
+ CIRCLEQ_INSERT_AFTER(&exp->rangeq, rp, nrp, q);
+ rp = nrp;
+ }
+ break;
+ case LINE_RESET:
+ return;
+ }
+ /*
+ * If the command deleted/inserted lines, the cursor moves to
+ * the line after the deleted/inserted line.
+ */
+ exp->range_lno = lno;
+}
diff --git a/usr.bin/vi/ex/ex_init.c b/usr.bin/vi/ex/ex_init.c
new file mode 100644
index 000000000000..cef766757303
--- /dev/null
+++ b/usr.bin/vi/ex/ex_init.c
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_init.c 8.14 (Berkeley) 3/18/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "tag.h"
+
+/*
+ * ex_screen_copy --
+ * Copy ex screen.
+ */
+int
+ex_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ EX_PRIVATE *oexp, *nexp;
+
+ /* Create the private ex structure. */
+ CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE));
+ sp->ex_private = nexp;
+
+ /* Initialize queues. */
+ TAILQ_INIT(&nexp->tagq);
+ TAILQ_INIT(&nexp->tagfq);
+ TAILQ_INIT(&nexp->cdq);
+ CIRCLEQ_INIT(&nexp->rangeq);
+
+ if (orig == NULL) {
+ nexp->at_lbuf_set = 0;
+ } else {
+ oexp = EXP(orig);
+
+ nexp->at_lbuf = oexp->at_lbuf;
+ nexp->at_lbuf_set = oexp->at_lbuf_set;
+
+ if (oexp->lastbcomm != NULL &&
+ (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return(1);
+ }
+
+ if (ex_tagcopy(orig, sp))
+ return (1);
+ }
+
+ nexp->lastcmd = &cmds[C_PRINT];
+ return (0);
+}
+
+/*
+ * ex_screen_end --
+ * End a vi screen.
+ */
+int
+ex_screen_end(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ int rval;
+
+ rval = 0;
+ exp = EXP(sp);
+
+ if (argv_free(sp))
+ rval = 1;
+
+ if (exp->ibp != NULL)
+ FREE(exp->ibp, exp->ibp_len);
+
+ if (exp->lastbcomm != NULL)
+ FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1);
+
+ if (ex_tagfree(sp))
+ rval = 1;
+
+ if (ex_cdfree(sp))
+ rval = 1;
+
+ /* Free private memory. */
+ FREE(exp, sizeof(EX_PRIVATE));
+ sp->ex_private = NULL;
+
+ return (rval);
+}
+
+/*
+ * ex_init --
+ * Initialize ex.
+ */
+int
+ex_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ size_t len;
+
+ /*
+ * The default address is the last line of the file. If the address
+ * set bit is on for this file, load the address, ensuring that it
+ * exists.
+ */
+ if (F_ISSET(sp->frp, FR_CURSORSET)) {
+ sp->lno = sp->frp->lno;
+ sp->cno = sp->frp->cno;
+
+ if (file_gline(sp, ep, sp->lno, &len) == NULL) {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ } else if (sp->cno >= len)
+ sp->cno = 0;
+ } else {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ }
+
+ /* Display the status line. */
+ return (status(sp, ep, sp->lno, 0));
+}
+
+/*
+ * ex_end --
+ * End ex session.
+ */
+int
+ex_end(sp)
+ SCR *sp;
+{
+ return (0);
+}
+
+/*
+ * ex_optchange --
+ * Handle change of options for vi.
+ */
+int
+ex_optchange(sp, opt)
+ SCR *sp;
+ int opt;
+{
+ switch (opt) {
+ case O_CDPATH:
+ return (ex_cdalloc(sp, O_STR(sp, O_CDPATH)));
+ case O_TAGS:
+ return (ex_tagalloc(sp, O_STR(sp, O_TAGS)));
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_join.c b/usr.bin/vi/ex/ex_join.c
new file mode 100644
index 000000000000..97946952cd6f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_join.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_join.c 8.11 (Berkeley) 3/24/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_join -- :[line [,line]] j[oin][!] [count] [flags]
+ * Join lines.
+ */
+int
+ex_join(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t from, to;
+ size_t blen, clen, len, tlen;
+ int echar, extra, first;
+ char *bp, *p, *tbp;
+
+ from = cmdp->addr1.lno;
+ to = cmdp->addr2.lno;
+
+ /* Check for no lines to join. */
+ if ((p = file_gline(sp, ep, from + 1, &len)) == NULL) {
+ msgq(sp, M_ERR, "No following lines to join.");
+ return (1);
+ }
+
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ /*
+ * The count for the join command was off-by-one,
+ * historically, to other counts for other commands.
+ */
+ if (F_ISSET(cmdp, E_COUNT))
+ ++cmdp->addr2.lno;
+
+ /*
+ * If only a single address specified, or, the same address
+ * specified twice, the from/two addresses will be the same.
+ */
+ if (cmdp->addr1.lno == cmdp->addr2.lno)
+ ++cmdp->addr2.lno;
+
+ clen = tlen = 0;
+ for (first = 1,
+ from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
+ /*
+ * Get next line. Historic versions of vi allowed "10J" while
+ * less than 10 lines from the end-of-file, so we do too.
+ */
+ if ((p = file_gline(sp, ep, from, &len)) == NULL) {
+ cmdp->addr2.lno = from - 1;
+ break;
+ }
+
+ /* Empty lines just go away. */
+ if (len == 0)
+ continue;
+
+ /*
+ * Get more space if necessary. Note, tlen isn't the length
+ * of the new line, it's roughly the amount of space needed.
+ * tbp - bp is the length of the new line.
+ */
+ tlen += len + 2;
+ ADD_SPACE_RET(sp, bp, blen, tlen);
+ tbp = bp + clen;
+
+ /*
+ * Historic practice:
+ *
+ * If force specified, join without modification.
+ * If the current line ends with whitespace, strip leading
+ * whitespace from the joined line.
+ * If the next line starts with a ), do nothing.
+ * If the current line ends with ., ? or !, insert two spaces.
+ * Else, insert one space.
+ *
+ * Echar is the last character in the last line joined.
+ */
+ extra = 0;
+ if (!first && !F_ISSET(cmdp, E_FORCE)) {
+ if (isblank(echar))
+ for (; len && isblank(*p); --len, ++p);
+ else if (p[0] != ')') {
+ if (strchr(".?!", echar)) {
+ *tbp++ = ' ';
+ ++clen;
+ extra = 1;
+ }
+ *tbp++ = ' ';
+ ++clen;
+ for (; len && isblank(*p); --len, ++p);
+ }
+ }
+
+ if (len != 0) {
+ memmove(tbp, p, len);
+ tbp += len;
+ clen += len;
+ echar = p[len - 1];
+ } else
+ echar = ' ';
+
+ /*
+ * Historic practice for vi was to put the cursor at the first
+ * inserted whitespace character, if there was one, or the
+ * first character of the joined line, if there wasn't, or the
+ * last character of the line if joined to an empty line. If
+ * a count was specified, the cursor was moved as described
+ * for the first line joined, ignoring subsequent lines. If
+ * the join was a ':' command, the cursor was placed at the
+ * first non-blank character of the line unless the cursor was
+ * "attracted" to the end of line when the command was executed
+ * in which case it moved to the new end of line. There are
+ * probably several more special cases, but frankly, my dear,
+ * I don't give a damn. This implementation puts the cursor
+ * on the first inserted whitespace character, the first
+ * character of the joined line, or the last character of the
+ * line regardless. Note, if the cursor isn't on the joined
+ * line (possible with : commands), it is reset to the starting
+ * line.
+ */
+ if (first) {
+ sp->cno = (tbp - bp) - (1 + extra);
+ first = 0;
+ } else
+ sp->cno = (tbp - bp) - len - (1 + extra);
+ }
+ sp->lno = cmdp->addr1.lno;
+
+ /* Delete the joined lines. */
+ for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
+ if (file_dline(sp, ep, to))
+ goto err;
+
+ /* If the original line changed, reset it. */
+ if (!first && file_sline(sp, ep, from, bp, tbp - bp)) {
+err: FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_map.c b/usr.bin/vi/ex/ex_map.c
new file mode 100644
index 000000000000..1d754941c1a6
--- /dev/null
+++ b/usr.bin/vi/ex/ex_map.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_map.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "seq.h"
+#include "excmd.h"
+
+/*
+ * ex_map -- :map[!] [input] [replacement]
+ * Map a key/string or display mapped keys.
+ *
+ * Historical note:
+ * Historic vi maps were fairly bizarre, and likely to differ in
+ * very subtle and strange ways from this implementation. Two
+ * things worth noting are that vi would often hang or drop core
+ * if the map was strange enough (ex: map X "xy$@x^V), or, simply
+ * not work. One trick worth remembering is that if you put a
+ * mark at the start of the map, e.g. map X mx"xy ...), or if you
+ * put the map in a .exrc file, things would often work much better.
+ * No clue why.
+ */
+int
+ex_map(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum seqtype stype;
+ CHAR_T *input;
+ size_t nlen;
+ int key;
+ char *name, buf[10];
+
+ stype = F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND;
+
+ switch (cmdp->argc) {
+ case 0:
+ if (seq_dump(sp, stype, 1) == 0)
+ msgq(sp, M_INFO, "No %s map entries.",
+ stype == SEQ_INPUT ? "input" : "command");
+ return (0);
+ case 2:
+ input = cmdp->argv[0]->bp;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * If the mapped string is #[0-9] (and wasn't quoted in any
+ * way, then map to a function key.
+ */
+ nlen = 0;
+ if (input[0] == '#' && isdigit(input[1]) && !input[2]) {
+ key = atoi(input + 1);
+ nlen = snprintf(buf, sizeof(buf), "f%d", key);
+#ifdef notdef
+ if (FKEY[key]) { /* CCC */
+ input = FKEY[key];
+ name = buf;
+ } else {
+ msgq(sp, M_ERR, "This terminal has no %s key.", buf);
+ return (1);
+ }
+#else
+ name = NULL;
+#endif
+ } else {
+ name = NULL;
+
+ /* Some single keys may not be remapped in command mode. */
+ if (stype == SEQ_COMMAND && input[1] == '\0')
+ switch (term_key_val(sp, input[0])) {
+ case K_COLON:
+ case K_CR:
+ case K_ESCAPE:
+ case K_NL:
+ msgq(sp, M_ERR,
+ "The %s character may not be remapped.",
+ charname(sp, input[0]));
+ return (1);
+ }
+ }
+ return (seq_set(sp, name, nlen, input, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, S_USERDEF));
+}
+
+/*
+ * ex_unmap -- (:unmap[!] key)
+ * Unmap a key.
+ */
+int
+ex_unmap(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len,
+ F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) {
+ msgq(sp, M_INFO, "\"%s\" isn't mapped.", cmdp->argv[0]->bp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * map_save --
+ * Save the mapped sequences to a file.
+ */
+int
+map_save(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ if (seq_save(sp, fp, "map ", SEQ_COMMAND))
+ return (1);
+ return (seq_save(sp, fp, "map! ", SEQ_INPUT));
+}
diff --git a/usr.bin/vi/ex/ex_mark.c b/usr.bin/vi/ex/ex_mark.c
new file mode 100644
index 000000000000..50174a38d0f2
--- /dev/null
+++ b/usr.bin/vi/ex/ex_mark.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_mark.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+int
+ex_mark(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (cmdp->argv[0]->len != 1) {
+ msgq(sp, M_ERR, "Mark names must be a single character.");
+ return (1);
+ }
+ return (mark_set(sp, ep, cmdp->argv[0]->bp[0], &cmdp->addr1, 1));
+}
diff --git a/usr.bin/vi/ex/ex_mkexrc.c b/usr.bin/vi/ex/ex_mkexrc.c
new file mode 100644
index 000000000000..0fa5450b78c4
--- /dev/null
+++ b/usr.bin/vi/ex/ex_mkexrc.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_mkexrc.c 8.10 (Berkeley) 3/22/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "seq.h"
+
+/*
+ * ex_mkexrc -- :mkexrc[!] [file]
+ *
+ * Create (or overwrite) a .exrc file with the current info.
+ */
+int
+ex_mkexrc(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ struct stat sb;
+ FILE *fp;
+ int fd, sverrno;
+ char *fname;
+
+ switch (cmdp->argc) {
+ case 0:
+ fname = _PATH_EXRC;
+ break;
+ case 1:
+ fname = cmdp->argv[0]->bp;
+ set_alt_name(sp, fname);
+ break;
+ default:
+ abort();
+ }
+
+ if (!F_ISSET(cmdp, E_FORCE) && !stat(fname, &sb)) {
+ msgq(sp, M_ERR,
+ "%s exists, not written; use ! to override.", fname);
+ return (1);
+ }
+
+ /* Create with max permissions of rw-r--r--. */
+ if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ msgq(sp, M_SYSERR, fname);
+ return (1);
+ }
+
+ if ((fp = fdopen(fd, "w")) == NULL) {
+ sverrno = errno;
+ (void)close(fd);
+ errno = sverrno;
+ goto e2;
+ }
+
+ if (abbr_save(sp, fp) || ferror(fp))
+ goto e1;
+ if (map_save(sp, fp) || ferror(fp))
+ goto e1;
+ if (opts_save(sp, fp) || ferror(fp))
+ goto e1;
+#ifndef NO_DIGRAPH
+ digraph_save(sp, fd);
+#endif
+ if (fclose(fp))
+ goto e2;
+
+ msgq(sp, M_INFO, "New .exrc file: %s. ", fname);
+ return (0);
+
+e1: sverrno = errno;
+ (void)fclose(fp);
+ errno = sverrno;
+e2: msgq(sp, M_ERR, "%s: incomplete: %s", fname, strerror(errno));
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_move.c b/usr.bin/vi/ex/ex_move.c
new file mode 100644
index 000000000000..dbda992a190a
--- /dev/null
+++ b/usr.bin/vi/ex/ex_move.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_move.c 8.11 (Berkeley) 3/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_copy -- :[line [,line]] co[py] line [flags]
+ * Copy selected lines.
+ */
+int
+ex_copy(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CB cb;
+ MARK fm1, fm2, m, tm;
+ recno_t cnt;
+ int rval;
+
+ /*
+ * It's possible to copy things into the area that's being
+ * copied, e.g. "2,5copy3" is legitimate. Save the text to
+ * a cut buffer.
+ */
+ fm1 = cmdp->addr1;
+ fm2 = cmdp->addr2;
+ memset(&cb, 0, sizeof(cb));
+ CIRCLEQ_INIT(&cb.textq);
+ if (cut(sp, ep, &cb, NULL, &fm1, &fm2, CUT_LINEMODE))
+ return (1);
+
+ /* Put the text into place. */
+ tm.lno = cmdp->lineno;
+ tm.cno = 0;
+ if (put(sp, ep, &cb, NULL, &tm, &m, 1))
+ rval = 1;
+ else {
+ /*
+ * Copy puts the cursor on the last line copied. The cursor
+ * returned by the put routine is the first line put, not the
+ * last, because that's the historic semantic of vi.
+ */
+ cnt = (fm2.lno - fm1.lno) + 1;
+ sp->lno = m.lno + (cnt - 1);
+ sp->cno = 0;
+
+ sp->rptlines[L_COPIED] += cnt;
+ rval = 0;
+ }
+ text_lfree(&cb.textq);
+ return (rval);
+}
+
+/*
+ * ex_move -- :[line [,line]] mo[ve] line
+ * Move selected lines.
+ */
+int
+ex_move(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ LMARK *lmp;
+ MARK fm1, fm2;
+ recno_t cnt, diff, fl, tl, mfl, mtl;
+ size_t len;
+ int mark_reset;
+ char *p;
+
+ /*
+ * It's not possible to move things into the area that's being
+ * moved.
+ */
+ fm1 = cmdp->addr1;
+ fm2 = cmdp->addr2;
+ if (cmdp->lineno >= fm1.lno && cmdp->lineno < fm2.lno) {
+ msgq(sp, M_ERR, "Destination line is inside move range.");
+ return (1);
+ }
+
+ /*
+ * Log the positions of any marks in the to-be-deleted lines. This
+ * has to work with the logging code. What happens is that we log
+ * the old mark positions, make the changes, then log the new mark
+ * positions. Then the marks end up in the right positions no matter
+ * which way the log is traversed.
+ *
+ * XXX
+ * Reset the MARK_USERSET flag so that the log can undo the mark.
+ * This isn't very clean, and should probably be fixed.
+ */
+ fl = fm1.lno;
+ tl = cmdp->lineno;
+
+ /* Log the old positions of the marks. */
+ mark_reset = 0;
+ for (lmp = ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno >= fl && lmp->lno <= tl) {
+ mark_reset = 1;
+ F_CLR(lmp, MARK_USERSET);
+ (void)log_mark(sp, ep, lmp);
+ }
+
+ /* Move the lines. */
+ diff = (fm2.lno - fm1.lno) + 1;
+ if (tl > fl) { /* Destination > source. */
+ mfl = tl - diff;
+ mtl = tl;
+ for (cnt = diff; cnt--;) {
+ if ((p = file_gline(sp, ep, fl, &len)) == NULL)
+ return (1);
+ if (file_aline(sp, ep, 1, tl, p, len))
+ return (1);
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno == fl)
+ lmp->lno = tl + 1;
+ if (file_dline(sp, ep, fl))
+ return (1);
+ }
+ } else { /* Destination < source. */
+ mfl = tl;
+ mtl = tl + diff;
+ for (cnt = diff; cnt--;) {
+ if ((p = file_gline(sp, ep, fl, &len)) == NULL)
+ return (1);
+ if (file_aline(sp, ep, 1, tl++, p, len))
+ return (1);
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno == fl)
+ lmp->lno = tl;
+ ++fl;
+ if (file_dline(sp, ep, fl))
+ return (1);
+ }
+ }
+ sp->lno = tl; /* Last line moved. */
+ sp->cno = 0;
+
+ /* Log the new positions of the marks. */
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno >= mfl && lmp->lno <= mtl)
+ (void)log_mark(sp, ep, lmp);
+
+
+ sp->rptlines[L_MOVED] += diff;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_open.c b/usr.bin/vi/ex/ex_open.c
new file mode 100644
index 000000000000..c727be985d53
--- /dev/null
+++ b/usr.bin/vi/ex/ex_open.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_open.c 8.3 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_open -- :[line] o[pen] [/pattern/] [flags]
+ *
+ * Switch to single line "open" mode.
+ */
+int
+ex_open(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* If open option off, disallow open command. */
+ if (!O_ISSET(sp, O_OPEN)) {
+ msgq(sp, M_ERR,
+ "The open command requires that the open option be set.");
+ return (1);
+ }
+
+ msgq(sp, M_ERR, "The open command is not yet implemented.");
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_preserve.c b/usr.bin/vi/ex/ex_preserve.c
new file mode 100644
index 000000000000..fd765a7d20ea
--- /dev/null
+++ b/usr.bin/vi/ex/ex_preserve.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_preserve.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_preserve -- :pre[serve]
+ * Push the file to recovery.
+ */
+int
+ex_preserve(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ if (!F_ISSET(ep, F_RCV_ON)) {
+ msgq(sp, M_ERR, "Preservation of this file not possible.");
+ return (1);
+ }
+
+ /* If recovery not initialized, do so. */
+ if (F_ISSET(ep, F_FIRSTMODIFY) && rcv_init(sp, ep))
+ return (1);
+
+ /* Force the file to be read in, in case it hasn't yet. */
+ if (file_lline(sp, ep, &lno))
+ return (1);
+
+ /* Sync to disk. */
+ if (rcv_sync(sp, ep))
+ return (1);
+
+ /* Preserve the recovery files. */
+ F_SET(ep, F_RCV_NORM);
+
+ msgq(sp, M_INFO, "File preserved.");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_print.c b/usr.bin/vi/ex/ex_print.c
new file mode 100644
index 000000000000..ad37c2b2235c
--- /dev/null
+++ b/usr.bin/vi/ex/ex_print.c
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_print.c 8.8 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_list -- :[line [,line]] l[ist] [count] [flags]
+ *
+ * Display the addressed lines such that the output is unambiguous.
+ */
+int
+ex_list(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_LIST))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_number -- :[line [,line]] nu[mber] [count] [flags]
+ *
+ * Display the addressed lines with a leading line number.
+ */
+int
+ex_number(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_HASH))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_pr -- :[line [,line]] p[rint] [count] [flags]
+ *
+ * Display the addressed lines.
+ */
+int
+ex_pr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep, &cmdp->addr1, &cmdp->addr2, cmdp->flags))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_print --
+ * Print the selected lines.
+ */
+int
+ex_print(sp, ep, fp, tp, flags)
+ SCR *sp;
+ EXF *ep;
+ MARK *fp, *tp;
+ register int flags;
+{
+ register int ch, col, rlen;
+ recno_t from, to;
+ size_t len;
+ int cnt;
+ char *p, buf[10];
+
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (from = fp->lno, to = tp->lno; from <= to; ++from) {
+ /* Display the line number. */
+ if (LF_ISSET(E_F_HASH))
+ col = ex_printf(EXCOOKIE, "%7ld ", from);
+ else
+ col = 0;
+
+ /*
+ * Display the line. The format for E_F_PRINT isn't very good,
+ * especially in handling end-of-line tabs, but they're almost
+ * backward compatible.
+ */
+ if ((p = file_gline(sp, ep, from, &len)) == NULL) {
+ GETLINE_ERR(sp, from);
+ return (1);
+ }
+
+#define WCHECK(ch) { \
+ if (col == sp->cols) { \
+ (void)ex_printf(EXCOOKIE, "\n"); \
+ col = 0; \
+ } \
+ (void)ex_printf(EXCOOKIE, "%c", ch); \
+ ++col; \
+}
+ for (rlen = len; rlen--;) {
+ ch = *p++;
+ if (LF_ISSET(E_F_LIST))
+ if (ch != '\t' && isprint(ch)) {
+ WCHECK(ch);
+ } else if (ch & 0x80) {
+ (void)snprintf(buf,
+ sizeof(buf), "\\%03o", ch);
+ len = strlen(buf);
+ for (cnt = 0; cnt < len; ++cnt)
+ WCHECK(buf[cnt]);
+ } else {
+ WCHECK('^');
+ WCHECK(ch + 0x40);
+ }
+ else {
+ ch &= 0x7f;
+ if (ch == '\t') {
+ while (col < sp->cols &&
+ ++col % O_VAL(sp, O_TABSTOP))
+ (void)ex_printf(EXCOOKIE, " ");
+ if (col == sp->cols) {
+ col = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+ } else if (isprint(ch)) {
+ WCHECK(ch);
+ } else if (ch == '\n') {
+ col = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ } else {
+ WCHECK('^');
+ WCHECK(ch + 0x40);
+ }
+ }
+ }
+ if (LF_ISSET(E_F_LIST)) {
+ WCHECK('$');
+ } else if (len == 0) {
+ /*
+ * If the line is empty, output a space
+ * to overwrite the colon prompt.
+ */
+ WCHECK(' ');
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+
+ if (F_ISSET(sp, S_INTERRUPTED))
+ break;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_put.c b/usr.bin/vi/ex/ex_put.c
new file mode 100644
index 000000000000..e56199d4fe68
--- /dev/null
+++ b/usr.bin/vi/ex/ex_put.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_put.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_put -- [line] pu[t] [buffer]
+ *
+ * Append a cut buffer into the file.
+ */
+int
+ex_put(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ MARK m;
+
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ if (put(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &m, 1))
+ return (1);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_read.c b/usr.bin/vi/ex/ex_read.c
new file mode 100644
index 000000000000..724c7e9fd407
--- /dev/null
+++ b/usr.bin/vi/ex/ex_read.c
@@ -0,0 +1,249 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_read.c 8.26 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_read -- :read [file]
+ * :read [! cmd]
+ * Read from a file or utility.
+ */
+int
+ex_read(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ struct stat sb;
+ FILE *fp;
+ MARK rm;
+ recno_t nlines;
+ size_t blen, len;
+ int btear, itear, rval;
+ char *bp, *name;
+
+ /*
+ * If "read !", it's a pipe from a utility.
+ *
+ * !!!
+ * Historical vi wouldn't undo a filter read, for no apparent
+ * reason.
+ */
+ if (F_ISSET(cmdp, E_FORCE)) {
+ /* Expand the user's argument. */
+ if (argv_exp1(sp, ep,
+ cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
+ return (1);
+
+ /* If argc still 1, there wasn't anything to expand. */
+ if (cmdp->argc == 1) {
+ msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
+ return (1);
+ }
+
+ /* Redisplay the user's argument if it's changed. */
+ if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
+ len = cmdp->argv[1]->len;
+ GET_SPACE_RET(sp, bp, blen, len + 2);
+ bp[0] = '!';
+ memmove(bp + 1, cmdp->argv[1], cmdp->argv[1]->len + 1);
+ (void)sp->s_busy(sp, bp);
+ FREE_SPACE(sp, bp, blen);
+ }
+
+ if (filtercmd(sp, ep,
+ &cmdp->addr1, NULL, &rm, cmdp->argv[1]->bp, FILTER_READ))
+ return (1);
+ sp->lno = rm.lno;
+ return (0);
+ }
+
+ /* Expand the user's argument. */
+ if (argv_exp2(sp, ep,
+ cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
+ return (1);
+
+ switch (cmdp->argc) {
+ case 1:
+ /*
+ * No arguments, read the current file.
+ * Doesn't set the alternate file name.
+ */
+ name = FILENAME(sp->frp);
+ break;
+ case 2:
+ /*
+ * One argument, read it.
+ * Sets the alternate file name.
+ */
+ name = cmdp->argv[1]->bp;
+ set_alt_name(sp, name);
+ break;
+ default:
+ /* If expanded to more than one argument, object. */
+ msgq(sp, M_ERR,
+ "%s expanded into too many file names", cmdp->argv[0]->bp);
+ msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historically, vi did not permit reads from non-regular files,
+ * nor did it distinguish between "read !" and "read!", so there
+ * was no way to "force" it.
+ */
+ if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
+ msgq(sp, M_SYSERR, name);
+ return (1);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ (void)fclose(fp);
+ msgq(sp, M_ERR, "Only regular files may be read.");
+ return (1);
+ }
+
+ /*
+ * Nvi handles the interrupt when reading from a file, but not
+ * when reading from a filter, since the terminal settings have
+ * been reset.
+ */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
+ itear = !intr_init(sp);
+ rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
+ if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
+
+ /*
+ * Set the cursor to the first line read in, if anything read
+ * in, otherwise, the address. (Historic vi set it to the
+ * line after the address regardless, but since that line may
+ * not exist we don't bother.)
+ */
+ sp->lno = cmdp->addr1.lno;
+ if (nlines)
+ ++sp->lno;
+
+ F_SET(EXP(sp), EX_AUTOPRINT);
+ return (rval);
+}
+
+/*
+ * ex_readfp --
+ * Read lines into the file.
+ */
+int
+ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
+ SCR *sp;
+ EXF *ep;
+ char *name;
+ FILE *fp;
+ MARK *fm;
+ recno_t *nlinesp;
+ int success_msg;
+{
+ EX_PRIVATE *exp;
+ recno_t lcnt, lno;
+ size_t len;
+ u_long ccnt; /* XXX: can't print off_t portably. */
+ int rval;
+
+ rval = 0;
+ exp = EXP(sp);
+
+ /*
+ * Add in the lines from the output. Insertion starts at the line
+ * following the address.
+ */
+ ccnt = 0;
+ lcnt = 0;
+ for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+ if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
+ rval = 1;
+ break;
+ }
+ ccnt += len;
+ }
+
+ if (ferror(fp)) {
+ msgq(sp, M_SYSERR, name);
+ rval = 1;
+ }
+
+ if (fclose(fp)) {
+ msgq(sp, M_SYSERR, name);
+ return (1);
+ }
+
+ if (rval)
+ return (1);
+
+ /* Return the number of lines read in. */
+ if (nlinesp != NULL)
+ *nlinesp = lcnt;
+
+ if (success_msg)
+ msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
+ name, lcnt, lcnt == 1 ? "" : "s", ccnt);
+
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_screen.c b/usr.bin/vi/ex/ex_screen.c
new file mode 100644
index 000000000000..de0f946621af
--- /dev/null
+++ b/usr.bin/vi/ex/ex_screen.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_screen.c 8.12 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_split -- :s[plit] [file ...]
+ * Split the screen, optionally setting the file list.
+ */
+int
+ex_split(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_split(sp, cmdp->argc ? cmdp->argv : NULL));
+}
+
+/*
+ * ex_bg -- :bg
+ * Hide the screen.
+ */
+int
+ex_bg(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_bg(sp));
+}
+
+/*
+ * ex_fg -- :fg [file]
+ * Show the screen.
+ */
+int
+ex_fg(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_fg(sp, cmdp->argc ? cmdp->argv[0]->bp : NULL));
+}
+
+/*
+ * ex_resize -- :resize [+-]rows
+ * Change the screen size.
+ */
+int
+ex_resize(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum adjust adj;
+
+ if (!F_ISSET(cmdp, E_COUNT)) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+ if (F_ISSET(cmdp, E_COUNT_NEG))
+ adj = A_DECREASE;
+ else if (F_ISSET(cmdp, E_COUNT_POS))
+ adj = A_INCREASE;
+ else
+ adj = A_SET;
+ return (sp->s_rabs(sp, cmdp->count, adj));
+}
+
+/*
+ * ex_sdisplay --
+ * Display the list of screens.
+ */
+int
+ex_sdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCR *tsp;
+ int cnt, col, len, sep;
+
+ if ((tsp = sp->gp->hq.cqh_first) == (void *)&sp->gp->hq) {
+ (void)ex_printf(EXCOOKIE,
+ "No backgrounded screens to display.\n");
+ return (0);
+ }
+
+ col = len = sep = 0;
+ for (cnt = 1; tsp != (void *)&sp->gp->hq; tsp = tsp->q.cqe_next) {
+ col += len = strlen(FILENAME(tsp->frp)) + sep;
+ if (col >= sp->cols - 1) {
+ col = len;
+ sep = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ } else if (cnt != 1) {
+ sep = 1;
+ (void)ex_printf(EXCOOKIE, " ");
+ }
+ (void)ex_printf(EXCOOKIE, "%s", FILENAME(tsp->frp));
+ ++cnt;
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_script.c b/usr.bin/vi/ex/ex_script.c
new file mode 100644
index 000000000000..e8e3b0e0a4db
--- /dev/null
+++ b/usr.bin/vi/ex/ex_script.c
@@ -0,0 +1,580 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_script.c 8.12 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "script.h"
+
+/*
+ * XXX
+ */
+int openpty __P((int *, int *, char *, struct termios *, struct winsize *));
+
+static int sscr_getprompt __P((SCR *, EXF *));
+static int sscr_init __P((SCR *, EXF *));
+static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *));
+static int sscr_setprompt __P((SCR *, char *, size_t));
+
+/*
+ * ex_script -- : sc[ript][!] [file]
+ *
+ * Switch to script mode.
+ */
+int
+ex_script(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* Vi only command. */
+ if (!IN_VI_MODE(sp)) {
+ msgq(sp, M_ERR,
+ "The script command is only available in vi mode.");
+ return (1);
+ }
+
+ /* Switch to the new file. */
+ if (cmdp->argc != 0 && ex_edit(sp, ep, cmdp))
+ return (1);
+
+ /*
+ * Create the shell, figure out the prompt.
+ *
+ * !!!
+ * The files just switched, use sp->ep.
+ */
+ if (sscr_init(sp, sp->ep))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * sscr_init --
+ * Create a pty setup for a shell.
+ */
+static int
+sscr_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCRIPT *sc;
+ char *sh, *sh_path;
+
+ MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT));
+ sp->script = sc;
+ sc->sh_prompt = NULL;
+ sc->sh_prompt_len = 0;
+
+ /*
+ * There are two different processes running through this code.
+ * They are the shell and the parent.
+ */
+ sc->sh_master = sc->sh_slave = -1;
+
+ if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+
+ /*
+ * Turn off output postprocessing and echo.
+ */
+ sc->sh_term.c_oflag &= ~OPOST;
+ sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK);
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+
+ if (openpty(&sc->sh_master,
+ &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) {
+ msgq(sp, M_SYSERR, "openpty");
+ goto err;
+ }
+
+ /*
+ * Don't use vfork() here, because the signal semantics
+ * differ from implementation to implementation.
+ */
+ switch (sc->sh_pid = fork()) {
+ case -1: /* Error. */
+ msgq(sp, M_SYSERR, "fork");
+err: if (sc->sh_master != -1)
+ (void)close(sc->sh_master);
+ if (sc->sh_slave != -1)
+ (void)close(sc->sh_slave);
+ return (1);
+ case 0: /* Utility. */
+ /*
+ * The utility has default signal behavior. Don't bother
+ * using sigaction(2) 'cause we want the default behavior.
+ */
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+
+ /*
+ * XXX
+ * So that shells that do command line editing turn it off.
+ */
+ (void)putenv("TERM=emacs");
+ (void)putenv("TERMCAP=emacs:");
+ (void)putenv("EMACS=t");
+
+ (void)setsid();
+#ifdef TIOCSCTTY
+ /*
+ * 4.4BSD allocates a controlling terminal using the TIOCSCTTY
+ * ioctl, not by opening a terminal device file. POSIX 1003.1
+ * doesn't define a portable way to do this. If TIOCSCTTY is
+ * not available, hope that the open does it.
+ */
+ (void)ioctl(sc->sh_slave, TIOCSCTTY, 0);
+#endif
+ (void)close(sc->sh_master);
+ (void)dup2(sc->sh_slave, STDIN_FILENO);
+ (void)dup2(sc->sh_slave, STDOUT_FILENO);
+ (void)dup2(sc->sh_slave, STDERR_FILENO);
+ (void)close(sc->sh_slave);
+
+ /* Assumes that all shells have -i. */
+ sh_path = O_STR(sp, O_SHELL);
+ if ((sh = strrchr(sh_path, '/')) == NULL)
+ sh = sh_path;
+ else
+ ++sh;
+ execl(sh_path, sh, "-i", NULL);
+ msgq(sp, M_ERR,
+ "Error: execl: %s: %s", sh_path, strerror(errno));
+ _exit(127);
+ default:
+ break;
+ }
+
+ if (sscr_getprompt(sp, ep))
+ return (1);
+
+ F_SET(sp, S_REDRAW | S_SCRIPT);
+ return (0);
+
+}
+
+/*
+ * sscr_getprompt --
+ * Eat lines printed by the shell until a line with no trailing
+ * carriage return comes; set the prompt from that line.
+ */
+static int
+sscr_getprompt(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct timeval tv;
+ SCRIPT *sc;
+ fd_set fdset;
+ recno_t lline;
+ size_t llen, len;
+ u_int value;
+ int nr;
+ char *endp, *p, *t, buf[1024];
+
+ FD_ZERO(&fdset);
+ endp = buf;
+ len = sizeof(buf);
+
+ /* Wait up to a second for characters to read. */
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ sc = sp->script;
+ FD_SET(sc->sh_master, &fdset);
+ switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "select");
+ goto prompterr;
+ case 0: /* Timeout */
+ msgq(sp, M_ERR, "Error: timed out.");
+ goto prompterr;
+ case 1: /* Characters to read. */
+ break;
+ }
+
+ /* Read the characters. */
+more: len = sizeof(buf) - (endp - buf);
+ switch (nr = read(sc->sh_master, endp, len)) {
+ case 0: /* EOF. */
+ msgq(sp, M_ERR, "Error: shell: EOF");
+ goto prompterr;
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "shell");
+ goto prompterr;
+ default:
+ endp += nr;
+ break;
+ }
+
+ /* If any complete lines, push them into the file. */
+ for (p = t = buf; p < endp; ++p) {
+ value = term_key_val(sp, *p);
+ if (value == K_CR || value == K_NL) {
+ if (file_lline(sp, ep, &lline) ||
+ file_aline(sp, ep, 0, lline, t, p - t))
+ goto prompterr;
+ t = p + 1;
+ }
+ }
+ if (p > buf) {
+ memmove(buf, t, endp - t);
+ endp = buf + (endp - t);
+ }
+ if (endp == buf)
+ goto more;
+
+ /* Wait up 1/10 of a second to make sure that we got it all. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "select");
+ goto prompterr;
+ case 0: /* Timeout */
+ break;
+ case 1: /* Characters to read. */
+ goto more;
+ }
+
+ /* Timed out, so theoretically we have a prompt. */
+ llen = endp - buf;
+ endp = buf;
+
+ /* Append the line into the file. */
+ if (file_lline(sp, ep, &lline) ||
+ file_aline(sp, ep, 0, lline, buf, llen)) {
+prompterr: sscr_end(sp);
+ return (1);
+ }
+
+ return (sscr_setprompt(sp, buf, llen));
+}
+
+/*
+ * sscr_exec --
+ * Take a line and hand it off to the shell.
+ */
+int
+sscr_exec(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ SCRIPT *sc;
+ recno_t last_lno;
+ size_t blen, len, last_len, tlen;
+ int matchprompt, nw, rval;
+ char *bp, *p;
+
+ /* If there's a prompt on the last line, append the command. */
+ if (file_lline(sp, ep, &last_lno))
+ return (1);
+ if ((p = file_gline(sp, ep, last_lno, &last_len)) == NULL) {
+ GETLINE_ERR(sp, last_lno);
+ return (1);
+ }
+ if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) {
+ matchprompt = 1;
+ GET_SPACE_RET(sp, bp, blen, last_len + 128);
+ memmove(bp, p, last_len);
+ } else
+ matchprompt = 0;
+
+ /* Get something to execute. */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ goto err1;
+ if (lno == 0)
+ goto empty;
+ else
+ GETLINE_ERR(sp, lno);
+ goto err1;
+ }
+
+ /* Empty lines aren't interesting. */
+ if (len == 0)
+ goto empty;
+
+ /* Delete any prompt. */
+ if (sscr_matchprompt(sp, p, len, &tlen)) {
+ if (tlen == len) {
+empty: msgq(sp, M_BERR, "Nothing to execute.");
+ goto err1;
+ }
+ p += (len - tlen);
+ len = tlen;
+ }
+
+ /* Push the line to the shell. */
+ sc = sp->script;
+ if ((nw = write(sc->sh_master, p, len)) != len)
+ goto err2;
+ rval = 0;
+ if (write(sc->sh_master, "\n", 1) != 1) {
+err2: if (nw == 0)
+ errno = EIO;
+ msgq(sp, M_SYSERR, "shell");
+ goto err1;
+ }
+
+ if (matchprompt) {
+ ADD_SPACE_RET(sp, bp, blen, last_len + len);
+ memmove(bp + last_len, p, len);
+ if (file_sline(sp, ep, last_lno, bp, last_len + len))
+err1: rval = 1;
+ }
+ if (matchprompt)
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * sscr_input --
+ * Take a line from the shell and insert it into the file.
+ */
+int
+sscr_input(sp)
+ SCR *sp;
+{
+ struct timeval tv;
+ SCRIPT *sc;
+ EXF *ep;
+ recno_t lno;
+ size_t blen, len, tlen;
+ u_int value;
+ int nr, rval;
+ char *bp, *endp, *p, *t;
+
+ /* Find out where the end of the file is. */
+ ep = sp->ep;
+ if (file_lline(sp, ep, &lno))
+ return (1);
+
+#define MINREAD 1024
+ GET_SPACE_RET(sp, bp, blen, MINREAD);
+ endp = bp;
+
+ /* Read the characters. */
+ rval = 1;
+ sc = sp->script;
+more: switch (nr = read(sc->sh_master, endp, MINREAD)) {
+ case 0: /* EOF; shell just exited. */
+ sscr_end(sp);
+ F_CLR(sp, S_SCRIPT);
+ rval = 0;
+ goto ret;
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "shell");
+ goto ret;
+ default:
+ endp += nr;
+ break;
+ }
+
+ /* Append the lines into the file. */
+ for (p = t = bp; p < endp; ++p) {
+ value = term_key_val(sp, *p);
+ if (value == K_CR || value == K_NL) {
+ len = p - t;
+ if (file_aline(sp, ep, 1, lno++, t, len))
+ goto ret;
+ t = p + 1;
+ }
+ }
+ if (p > t) {
+ len = p - t;
+ /*
+ * If the last thing from the shell isn't another prompt, wait
+ * up to 1/10 of a second for more stuff to show up, so that
+ * we don't break the output into two separate lines. Don't
+ * want to hang indefinitely because some program is hanging,
+ * confused the shell, or whatever.
+ */
+ if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ FD_SET(sc->sh_master, &sp->rdfd);
+ FD_CLR(STDIN_FILENO, &sp->rdfd);
+ if (select(sc->sh_master + 1,
+ &sp->rdfd, NULL, NULL, &tv) == 1) {
+ memmove(bp, t, len);
+ endp = bp + len;
+ goto more;
+ }
+ }
+ if (sscr_setprompt(sp, t, len))
+ return (1);
+ if (file_aline(sp, ep, 1, lno++, t, len))
+ goto ret;
+ }
+
+ /* The cursor moves to EOF. */
+ sp->lno = lno;
+ sp->cno = len ? len - 1 : 0;
+ rval = sp->s_refresh(sp, ep);
+
+ret: FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * sscr_setprompt --
+ *
+ * Set the prompt to the last line we got from the shell.
+ *
+ */
+static int
+sscr_setprompt(sp, buf, len)
+ SCR *sp;
+ char* buf;
+ size_t len;
+{
+ SCRIPT *sc;
+
+ sc = sp->script;
+ if (sc->sh_prompt)
+ FREE(sc->sh_prompt, sc->sh_prompt_len);
+ MALLOC(sp, sc->sh_prompt, char *, len + 1);
+ if (sc->sh_prompt == NULL) {
+ sscr_end(sp);
+ return (1);
+ }
+ memmove(sc->sh_prompt, buf, len);
+ sc->sh_prompt_len = len;
+ sc->sh_prompt[len] = '\0';
+ return (0);
+}
+
+/*
+ * sscr_matchprompt --
+ * Check to see if a line matches the prompt. Nul's indicate
+ * parts that can change, in both content and size.
+ */
+static int
+sscr_matchprompt(sp, lp, line_len, lenp)
+ SCR *sp;
+ char *lp;
+ size_t line_len, *lenp;
+{
+ SCRIPT *sc;
+ size_t prompt_len;
+ char *pp;
+
+ sc = sp->script;
+ if (line_len < (prompt_len = sc->sh_prompt_len))
+ return (0);
+
+ for (pp = sc->sh_prompt;
+ prompt_len && line_len; --prompt_len, --line_len) {
+ if (*pp == '\0') {
+ for (; prompt_len && *pp == '\0'; --prompt_len, ++pp);
+ if (!prompt_len)
+ return (0);
+ for (; line_len && *lp != *pp; --line_len, ++lp);
+ if (!line_len)
+ return (0);
+ }
+ if (*pp++ != *lp++)
+ break;
+ }
+
+ if (prompt_len)
+ return (0);
+ if (lenp != NULL)
+ *lenp = line_len;
+ return (1);
+}
+
+/*
+ * sscr_end --
+ * End the pipe to a shell.
+ */
+int
+sscr_end(sp)
+ SCR *sp;
+{
+ SCRIPT *sc;
+ int rval;
+
+ if ((sc = sp->script) == NULL)
+ return (0);
+
+ /* Turn off the script flag. */
+ F_CLR(sp, S_SCRIPT);
+
+ /* Close down the parent's file descriptors. */
+ if (sc->sh_master != -1)
+ (void)close(sc->sh_master);
+ if (sc->sh_slave != -1)
+ (void)close(sc->sh_slave);
+
+ /* This should have killed the child. */
+ rval = proc_wait(sp, (long)sc->sh_pid, "script-shell", 0);
+
+ /* Free memory. */
+ FREE(sc->sh_prompt, sc->sh_prompt_len);
+ FREE(sc, sizeof(SCRIPT));
+ sp->script = NULL;
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_set.c b/usr.bin/vi/ex/ex_set.c
new file mode 100644
index 000000000000..ac6994cf5f0e
--- /dev/null
+++ b/usr.bin/vi/ex/ex_set.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_set.c 8.3 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+int
+ex_set(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ switch(cmdp->argc) {
+ case 0:
+ opts_dump(sp, CHANGED_DISPLAY);
+ break;
+ default:
+ opts_set(sp, cmdp->argv);
+ break;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_shell.c b/usr.bin/vi/ex/ex_shell.c
new file mode 100644
index 000000000000..08e0a3e5bbff
--- /dev/null
+++ b/usr.bin/vi/ex/ex_shell.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_shell.c 8.21 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../svi/svi_screen.h"
+
+/*
+ * ex_shell -- :sh[ell]
+ * Invoke the program named in the SHELL environment variable
+ * with the argument -i.
+ */
+int
+ex_shell(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ char buf[MAXPATHLEN];
+
+ (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
+ return (ex_exec_proc(sp, buf, "\n", NULL));
+}
+
+/*
+ * ex_exec_proc --
+ * Run a separate process.
+ */
+int
+ex_exec_proc(sp, cmd, p1, p2)
+ SCR *sp;
+ char *cmd, *p1, *p2;
+{
+ const char *name;
+ pid_t pid;
+ int rval, teardown;
+
+ /* Clear the rest of the screen. */
+ if (sp->s_clear(sp))
+ return (1);
+
+ /* Save ex/vi terminal settings, and restore the original ones. */
+ teardown = !ex_sleave(sp);
+
+ /* Put out various messages. */
+ if (p1 != NULL)
+ (void)write(STDOUT_FILENO, p1, strlen(p1));
+ if (p2 != NULL)
+ (void)write(STDOUT_FILENO, p2, strlen(p2));
+
+
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ msgq(sp, M_SYSERR, "vfork");
+ rval = 1;
+ goto err;
+ case 0: /* Utility. */
+ /*
+ * The utility has default signal behavior. Don't bother
+ * using sigaction(2) 'cause we want the default behavior.
+ */
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+
+ if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
+ name = O_STR(sp, O_SHELL);
+ else
+ ++name;
+ execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+ msgq(sp, M_ERR, "Error: execl: %s: %s",
+ O_STR(sp, O_SHELL), strerror(errno));
+ _exit(127);
+ /* NOTREACHED */
+ }
+
+ rval = proc_wait(sp, (long)pid, cmd, 0);
+
+ /* Restore ex/vi terminal settings. */
+err: if (teardown)
+ ex_rleave(sp);
+
+ /*
+ * XXX
+ * Stat of the tty structures (see ex_sleave, ex_rleave) only give
+ * us 1-second resolution on the tty changes. A fast '!' command,
+ * e.g. ":!pwd" can beat us to the refresh. When there's better
+ * resolution from the stat(2) timers, this can go away.
+ */
+ F_SET(sp, S_REFRESH);
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_shift.c b/usr.bin/vi/ex/ex_shift.c
new file mode 100644
index 000000000000..fb12432f6517
--- /dev/null
+++ b/usr.bin/vi/ex/ex_shift.c
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_shift.c 8.14 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {LEFT, RIGHT};
+static int shift __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+int
+ex_shiftl(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (shift(sp, ep, cmdp, LEFT));
+}
+
+int
+ex_shiftr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (shift(sp, ep, cmdp, RIGHT));
+}
+
+static int
+shift(sp, ep, cmdp, rl)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which rl;
+{
+ recno_t from, to;
+ size_t blen, len, newcol, newidx, oldcol, oldidx, sw;
+ int curset;
+ char *p, *bp, *tbp;
+
+ if (O_VAL(sp, O_SHIFTWIDTH) == 0) {
+ msgq(sp, M_INFO, "shiftwidth option set to 0");
+ return (0);
+ }
+
+ /*
+ * The historic version of vi permitted the user to string any number
+ * of '>' or '<' characters together, resulting in an indent of the
+ * appropriate levels. There's a special hack in ex_cmd() so that
+ * cmdp->argv[0] points to the string of '>' or '<' characters.
+ *
+ * Q: What's the difference between the people adding features
+ * to vi and the Girl Scouts?
+ * A: The Girl Scouts have mint cookies and adult supervision.
+ */
+ for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p)
+ sw += O_VAL(sp, O_SHIFTWIDTH);
+
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ curset = 0;
+ for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
+ if ((p = file_gline(sp, ep, from, &len)) == NULL)
+ goto err;
+ if (!len) {
+ if (sp->lno == from)
+ curset = 1;
+ continue;
+ }
+
+ /*
+ * Calculate the old indent amount and the number of
+ * characters it used.
+ */
+ for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx)
+ if (p[oldidx] == ' ')
+ ++oldcol;
+ else if (p[oldidx] == '\t')
+ oldcol += O_VAL(sp, O_TABSTOP) -
+ oldcol % O_VAL(sp, O_TABSTOP);
+ else
+ break;
+
+ /* Calculate the new indent amount. */
+ if (rl == RIGHT)
+ newcol = oldcol + sw;
+ else {
+ newcol = oldcol < sw ? 0 : oldcol - sw;
+ if (newcol == oldcol) {
+ if (sp->lno == from)
+ curset = 1;
+ continue;
+ }
+ }
+
+ /* Get a buffer that will hold the new line. */
+ ADD_SPACE_RET(sp, bp, blen, newcol + len);
+
+ /*
+ * Build a new indent string and count the number of
+ * characters it uses.
+ */
+ for (tbp = bp, newidx = 0;
+ newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
+ *tbp++ = '\t';
+ newcol -= O_VAL(sp, O_TABSTOP);
+ }
+ for (; newcol > 0; --newcol, ++newidx)
+ *tbp++ = ' ';
+
+ /* Add the original line. */
+ memmove(tbp, p + oldidx, len - oldidx);
+
+ /* Set the replacement line. */
+ if (file_sline(sp, ep, from, bp, (tbp + (len - oldidx)) - bp)) {
+err: FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * The shift command in historic vi had the usual bizarre
+ * collection of cursor semantics. If called from vi, the
+ * cursor was repositioned to the first non-blank character
+ * of the lowest numbered line shifted. If called from ex,
+ * the cursor was repositioned to the first non-blank of the
+ * highest numbered line shifted. Here, if the cursor isn't
+ * part of the set of lines that are moved, move it to the
+ * first non-blank of the last line shifted. (This makes
+ * ":3>>" in vi work reasonably.) If the cursor is part of
+ * the shifted lines, it doesn't get moved at all. This
+ * permits shifting of marked areas, i.e. ">'a." shifts the
+ * marked area twice, something that couldn't be done with
+ * historic vi.
+ */
+ if (sp->lno == from) {
+ curset = 1;
+ if (newidx > oldidx)
+ sp->cno += newidx - oldidx;
+ else if (sp->cno >= oldidx - newidx)
+ sp->cno -= oldidx - newidx;
+ }
+ }
+ if (!curset) {
+ sp->lno = to;
+ sp->cno = 0;
+ (void)nonblank(sp, ep, to, &sp->cno);
+ }
+
+ FREE_SPACE(sp, bp, blen);
+
+ sp->rptlines[rl == RIGHT ? L_RSHIFT : L_LSHIFT] +=
+ cmdp->addr2.lno - cmdp->addr1.lno + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_source.c b/usr.bin/vi/ex/ex_source.c
new file mode 100644
index 000000000000..4aba34ae0373
--- /dev/null
+++ b/usr.bin/vi/ex/ex_source.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_source.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_source -- :source file
+ * Execute ex commands from a file.
+ */
+int
+ex_source(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (ex_cfile(sp, ep, cmdp->argv[0]->bp));
+}
diff --git a/usr.bin/vi/ex/ex_stop.c b/usr.bin/vi/ex/ex_stop.c
new file mode 100644
index 000000000000..1ed01f2c8757
--- /dev/null
+++ b/usr.bin/vi/ex/ex_stop.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_stop.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "sex/sex_screen.h"
+
+/*
+ * ex_stop -- :stop[!]
+ * :suspend[!]
+ * Suspend execution.
+ */
+int
+ex_stop(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* For some strange reason, the force flag turns off autowrite. */
+ if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE) &&
+ !F_ISSET(cmdp, E_FORCE)) {
+ if (file_write((sp), (ep), NULL, NULL, NULL, FS_ALL))
+ return (1);
+ if (sex_refresh(sp, ep))
+ return (1);
+ }
+ return (sp->s_suspend(sp));
+}
diff --git a/usr.bin/vi/ex/ex_subst.c b/usr.bin/vi/ex/ex_subst.c
new file mode 100644
index 000000000000..c8c03a4a2e79
--- /dev/null
+++ b/usr.bin/vi/ex/ex_subst.c
@@ -0,0 +1,972 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_subst.c 8.39 (Berkeley) 3/22/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
+#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
+
+static int checkmatchsize __P((SCR *, regex_t *));
+static inline int regsub __P((SCR *,
+ char *, char **, size_t *, size_t *));
+static int substitute __P((SCR *, EXF *,
+ EXCMDARG *, char *, regex_t *, u_int));
+
+/*
+ * ex_substitute --
+ * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
+ *
+ * Substitute on lines matching a pattern.
+ */
+int
+ex_substitute(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ regex_t *re, lre;
+ size_t blen, len;
+ u_int flags;
+ int delim, eval, reflags, replaced;
+ char *bp, *ptrn, *rep, *p, *t;
+
+ /*
+ * Skip leading white space.
+ *
+ * !!!
+ * Historic vi allowed any non-alphanumeric to serve as the
+ * substitution command delimiter.
+ *
+ * !!!
+ * If the arguments are empty, it's the same as &, i.e. we
+ * repeat the last substitution.
+ */
+ for (p = cmdp->argv[0]->bp,
+ len = cmdp->argv[0]->len; len > 0; --len, ++p) {
+ if (!isblank(*p))
+ break;
+ }
+ if (len == 0)
+ return (ex_subagain(sp, ep, cmdp));
+ delim = *p++;
+ if (isalnum(delim))
+ return (substitute(sp, ep,
+ cmdp, p, &sp->subre, SUB_MUSTSETR));
+
+ /*
+ * Get the pattern string, toss escaped characters.
+ *
+ * !!!
+ * Historic vi accepted any of the following forms:
+ *
+ * :s/abc/def/ change "abc" to "def"
+ * :s/abc/def change "abc" to "def"
+ * :s/abc/ delete "abc"
+ * :s/abc delete "abc"
+ *
+ * QUOTING NOTE:
+ *
+ * Only toss an escape character if it escapes a delimiter.
+ * This means that "s/A/\\\\f" replaces "A" with "\\f". It
+ * would be nice to be more regular, i.e. for each layer of
+ * escaping a single escape character is removed, but that's
+ * not how the historic vi worked.
+ */
+ for (ptrn = t = p;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ /*
+ * !!!
+ * Nul terminate the pattern string -- it's passed
+ * to regcomp which doesn't understand anything else.
+ */
+ *t = '\0';
+ break;
+ }
+ if (p[0] == '\\')
+ if (p[1] == delim)
+ ++p;
+ else if (p[1] == '\\')
+ *t++ = *p++;
+ *t++ = *p++;
+ }
+
+ /* If the pattern string is empty, use the last one. */
+ if (*ptrn == NULL) {
+ if (!F_ISSET(sp, S_SUBRE_SET)) {
+ msgq(sp, M_ERR,
+ "No previous regular expression.");
+ return (1);
+ }
+ re = &sp->subre;
+ flags = 0;
+ } else {
+ /* Set RE flags. */
+ reflags = 0;
+ if (O_ISSET(sp, O_EXTENDED))
+ reflags |= REG_EXTENDED;
+ if (O_ISSET(sp, O_IGNORECASE))
+ reflags |= REG_ICASE;
+
+ /* Convert vi-style RE's to POSIX 1003.2 RE's. */
+ if (re_conv(sp, &ptrn, &replaced))
+ return (1);
+
+ /* Compile the RE. */
+ eval = regcomp(&lre, (char *)ptrn, reflags);
+
+ /* Free up any allocated memory. */
+ if (replaced)
+ FREE_SPACE(sp, ptrn, 0);
+
+ if (eval) {
+ re_error(sp, eval, &lre);
+ return (1);
+ }
+
+ /*
+ * Set saved RE.
+ *
+ * !!!
+ * Historic practice is that substitutes set the search
+ * direction as well as both substitute and search RE's.
+ */
+ sp->searchdir = FORWARD;
+ sp->sre = lre;
+ F_SET(sp, S_SRE_SET);
+ sp->subre = lre;
+ F_SET(sp, S_SUBRE_SET);
+
+ re = &lre;
+ flags = SUB_FIRST;
+ }
+
+ /*
+ * Get the replacement string.
+ *
+ * The special character & (\& if O_MAGIC not set) matches the
+ * entire RE. No handling of & is required here, it's done by
+ * regsub().
+ *
+ * The special character ~ (\~ if O_MAGIC not set) inserts the
+ * previous replacement string into this replacement string.
+ * Count ~'s to figure out how much space we need. We could
+ * special case nonexistent last patterns or whether or not
+ * O_MAGIC is set, but it's probably not worth the effort.
+ *
+ * QUOTING NOTE:
+ *
+ * Only toss an escape character if it escapes a delimiter or
+ * if O_MAGIC is set and it escapes a tilde.
+ */
+ if (*p == '\0') {
+ if (sp->repl != NULL)
+ FREE(sp->repl, sp->repl_len);
+ sp->repl = NULL;
+ sp->repl_len = 0;
+ } else {
+ for (rep = p, len = 0;
+ p[0] != '\0' && p[0] != delim; ++p, ++len)
+ if (p[0] == '~')
+ len += sp->repl_len;
+ GET_SPACE_RET(sp, bp, blen, len);
+ for (t = bp, len = 0, p = rep;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ break;
+ }
+ if (p[0] == '\\') {
+ if (p[1] == delim)
+ ++p;
+ else if (p[1] == '\\') {
+ *t++ = *p++;
+ ++len;
+ } else if (p[1] == '~') {
+ ++p;
+ if (!O_ISSET(sp, O_MAGIC))
+ goto tilde;
+ }
+ } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) {
+tilde: ++p;
+ memmove(t, sp->repl, sp->repl_len);
+ t += sp->repl_len;
+ len += sp->repl_len;
+ continue;
+ }
+ *t++ = *p++;
+ ++len;
+ }
+ if (sp->repl != NULL)
+ FREE(sp->repl, sp->repl_len);
+ if ((sp->repl = malloc(len)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+ memmove(sp->repl, bp, len);
+ sp->repl_len = len;
+ FREE_SPACE(sp, bp, blen);
+ }
+
+ if (checkmatchsize(sp, &sp->subre))
+ return (1);
+ return (substitute(sp, ep, cmdp, p, re, flags));
+}
+
+/*
+ * ex_subagain --
+ * [line [,line]] & [cgr] [count] [#lp]]
+ *
+ * Substitute using the last substitute RE and replacement pattern.
+ */
+int
+ex_subagain(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (!F_ISSET(sp, S_SUBRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression.");
+ return (1);
+ }
+ return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->subre, 0));
+}
+
+/*
+ * ex_subtilde --
+ * [line [,line]] ~ [cgr] [count] [#lp]]
+ *
+ * Substitute using the last RE and last substitute replacement pattern.
+ */
+int
+ex_subtilde(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression.");
+ return (1);
+ }
+ return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->sre, 0));
+}
+
+/*
+ * The nasty part of the substitution is what happens when the replacement
+ * string contains newlines. It's a bit tricky -- consider the information
+ * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is
+ * to build a set of newline offsets which we use to break the line up later,
+ * when the replacement is done. Don't change it unless you're pretty damned
+ * confident.
+ */
+#define NEEDNEWLINE(sp) { \
+ if (sp->newl_len == sp->newl_cnt) { \
+ sp->newl_len += 25; \
+ REALLOC(sp, sp->newl, size_t *, \
+ sp->newl_len * sizeof(size_t)); \
+ if (sp->newl == NULL) { \
+ sp->newl_len = 0; \
+ return (1); \
+ } \
+ } \
+}
+
+#define BUILD(sp, l, len) { \
+ if (lbclen + (len) > lblen) { \
+ lblen += MAX(lbclen + (len), 256); \
+ REALLOC(sp, lb, char *, lblen); \
+ if (lb == NULL) { \
+ lbclen = 0; \
+ return (1); \
+ } \
+ } \
+ memmove(lb + lbclen, l, len); \
+ lbclen += len; \
+}
+
+#define NEEDSP(sp, len, pnt) { \
+ if (lbclen + (len) > lblen) { \
+ lblen += MAX(lbclen + (len), 256); \
+ REALLOC(sp, lb, char *, lblen); \
+ if (lb == NULL) { \
+ lbclen = 0; \
+ return (1); \
+ } \
+ pnt = lb + lbclen; \
+ } \
+}
+
+/*
+ * substitute --
+ * Do the substitution. This stuff is *really* tricky. There are
+ * lots of special cases, and general nastiness. Don't mess with it
+ * unless you're pretty confident.
+ */
+static int
+substitute(sp, ep, cmdp, s, re, flags)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ char *s;
+ regex_t *re;
+ u_int flags;
+{
+ MARK from, to;
+ recno_t elno, lno;
+ size_t blen, cnt, last, lbclen, lblen, len, llen, offset, saved_offset;
+ int cflag, gflag, lflag, nflag, pflag, rflag;
+ int didsub, do_eol_match, eflags, empty_ok, eval;
+ int linechanged, matched, quit, rval, teardown;
+ char *bp, *lb;
+
+ /*
+ * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
+ * it only displayed the last change. I'd disallow them, but they are
+ * useful in combination with the [v]global commands. In the current
+ * model the problem is combining them with the 'c' flag -- the screen
+ * would have to flip back and forth between the confirm screen and the
+ * ex print screen, which would be pretty awful. We do display all
+ * changes, though, for what that's worth.
+ *
+ * !!!
+ * Historic vi was fairly strict about the order of "options", the
+ * count, and "flags". I'm somewhat fuzzy on the difference between
+ * options and flags, anyway, so this is a simpler approach, and we
+ * just take it them in whatever order the user gives them. (The ex
+ * usage statement doesn't reflect this.)
+ */
+ cflag = gflag = lflag = nflag = pflag = rflag = 0;
+ for (lno = OOBLNO; *s != '\0'; ++s)
+ switch (*s) {
+ case ' ':
+ case '\t':
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (lno != OOBLNO)
+ goto usage;
+ errno = 0;
+ lno = strtoul(s, &s, 10);
+ if (*s == '\0') /* Loop increment correction. */
+ --s;
+ if (errno == ERANGE) {
+ if (lno == LONG_MAX)
+ msgq(sp, M_ERR, "Count overflow.");
+ else if (lno == LONG_MIN)
+ msgq(sp, M_ERR, "Count underflow.");
+ else
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ /*
+ * In historic vi, the count was inclusive from the
+ * second address.
+ */
+ cmdp->addr1.lno = cmdp->addr2.lno;
+ cmdp->addr2.lno += lno - 1;
+ break;
+ case '#':
+ nflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ if (LF_ISSET(SUB_FIRST)) {
+ msgq(sp, M_ERR,
+ "Regular expression specified; r flag meaningless.");
+ return (1);
+ }
+ if (!F_ISSET(sp, S_SUBRE_SET)) {
+ msgq(sp, M_ERR,
+ "No previous regular expression.");
+ return (1);
+ }
+ rflag = 1;
+ break;
+ default:
+ goto usage;
+ }
+
+ if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) {
+usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ if (IN_VI_MODE(sp) && cflag && (lflag || nflag || pflag)) {
+ msgq(sp, M_ERR,
+ "The #, l and p flags may not be combined with the c flag in vi mode.");
+ return (1);
+ }
+
+ /* Set up interrupts. */
+ teardown = !intr_init(sp);
+
+ /*
+ * bp: if interactive, line cache
+ * blen: if interactive, line cache length
+ * lb: build buffer pointer.
+ * lbclen: current length of built buffer.
+ * lblen; length of build buffer.
+ */
+ bp = lb = NULL;
+ blen = lbclen = lblen = 0;
+
+ /* For each line... */
+ for (matched = quit = 0, lno = cmdp->addr1.lno,
+ elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
+
+ /* Someone's unhappy, time to stop. */
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+ if (!F_ISSET(sp, S_GLOBAL))
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+
+ /* Get the line. */
+ if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+
+ /*
+ * Make a local copy if doing confirmation -- when calling
+ * the confirm routine we're likely to lose the cached copy.
+ */
+ if (cflag) {
+ if (bp == NULL) {
+ GET_SPACE_RET(sp, bp, blen, llen);
+ } else
+ ADD_SPACE_RET(sp, bp, blen, llen);
+ memmove(bp, s, llen);
+ s = bp;
+ }
+
+ /* Start searching from the beginning. */
+ offset = 0;
+ len = llen;
+
+ /* Reset the build buffer offset. */
+ lbclen = 0;
+
+ /* Reset empty match flag. */
+ empty_ok = 1;
+
+ /*
+ * We don't want to have to do a setline if the line didn't
+ * change -- keep track of whether or not this line changed.
+ * If doing confirmations, don't want to keep setting the
+ * line if change is refused -- keep track of substitutions.
+ */
+ didsub = linechanged = 0;
+
+ /* New line, do an EOL match. */
+ do_eol_match = 1;
+
+ /* It's not nul terminated, but we pretend it is. */
+ eflags = REG_STARTEND;
+
+ /*
+ * The search area is from s + offset to the EOL.
+ *
+ * Generally, sp->match[0].rm_so is the offset of the start
+ * of the match from the start of the search, and offset is
+ * the offset of the start of the last search.
+ */
+nextmatch: sp->match[0].rm_so = 0;
+ sp->match[0].rm_eo = len;
+
+ /* Get the next match. */
+ eval = regexec(re,
+ (char *)s + offset, re->re_nsub + 1, sp->match, eflags);
+
+ /*
+ * There wasn't a match or if there was an error, deal with
+ * it. If there was a previous match in this line, resolve
+ * the changes into the database. Otherwise, just move on.
+ */
+ if (eval == REG_NOMATCH)
+ goto endmatch;
+ if (eval != 0) {
+ re_error(sp, eval, re);
+ goto ret1;
+ }
+ matched = 1;
+
+ /* Only the first search can match an anchored expression. */
+ eflags |= REG_NOTBOL;
+
+ /*
+ * !!!
+ * It's possible to match 0-length strings -- for example, the
+ * command s;a*;X;, when matched against the string "aabb" will
+ * result in "XbXbX", i.e. the matches are "aa", the space
+ * between the b's and the space between the b's and the end of
+ * the string. There is a similar space between the beginning
+ * of the string and the a's. The rule that we use (because vi
+ * historically used it) is that any 0-length match, occurring
+ * immediately after a match, is ignored. Otherwise, the above
+ * example would have resulted in "XXbXbX". Another example is
+ * incorrectly using " *" to replace groups of spaces with one
+ * space.
+ *
+ * The way we do this is that if we just had a successful match,
+ * the starting offset does not skip characters, and the match
+ * is empty, ignore the match and move forward. If there's no
+ * more characters in the string, we were attempting to match
+ * after the last character, so quit.
+ */
+ if (!empty_ok &&
+ sp->match[0].rm_so == 0 && sp->match[0].rm_eo == 0) {
+ empty_ok = 1;
+ if (len == 0)
+ goto endmatch;
+ BUILD(sp, s + offset, 1)
+ ++offset;
+ --len;
+ goto nextmatch;
+ }
+
+ /* Confirm change. */
+ if (cflag) {
+ /*
+ * Set the cursor position for confirmation. Note,
+ * if we matched on a '$', the cursor may be past
+ * the end of line.
+ *
+ * XXX
+ * We may want to "fix" this in the confirm routine,
+ * if the confirm routine should be able to display
+ * a cursor past EOL.
+ */
+ from.lno = to.lno = lno;
+ from.cno = sp->match[0].rm_so + offset;
+ to.cno = sp->match[0].rm_eo;
+ if (llen == 0)
+ from.cno = to.cno = 0;
+ else {
+ if (to.cno >= llen)
+ to.cno = llen - 1;
+ if (from.cno >= llen)
+ from.cno = llen - 1;
+ }
+ switch (sp->s_confirm(sp, ep, &from, &to)) {
+ case CONF_YES:
+ break;
+ case CONF_NO:
+ didsub = 0;
+ BUILD(sp, s +offset, sp->match[0].rm_eo);
+ goto skip;
+ case CONF_QUIT:
+ /* Set the quit flag. */
+ quit = 1;
+
+ /* If interruptible, pass the info back. */
+ if (F_ISSET(sp, S_INTERRUPTIBLE))
+ F_SET(sp, S_INTERRUPTED);
+
+ /*
+ * If any changes, resolve them, otherwise
+ * return to the main loop.
+ */
+ goto endmatch;
+ }
+ }
+
+ /* Copy the bytes before the match into the build buffer. */
+ BUILD(sp, s + offset, sp->match[0].rm_so);
+
+ /*
+ * Cursor moves to last line changed, unless doing confirm,
+ * in which case don't move it.
+ *
+ * !!!
+ * Historic vi just put the cursor on the first non-blank
+ * of the last line changed. We move to the beginning of
+ * the next substitution.
+ */
+ if (!cflag) {
+ sp->lno = lno;
+ sp->cno = lbclen;
+ }
+
+ /* Substitute the matching bytes. */
+ didsub = 1;
+ if (regsub(sp, s + offset, &lb, &lbclen, &lblen))
+ goto ret1;
+
+ /* Set the change flag so we know this line was modified. */
+ linechanged = 1;
+
+ /* Move past the matched bytes. */
+skip: offset += sp->match[0].rm_eo;
+ len -= sp->match[0].rm_eo;
+
+ /* A match cannot be followed by an empty pattern. */
+ empty_ok = 0;
+
+ /*
+ * If doing a global change with confirmation, we have to
+ * update the screen. The basic idea is to store the line
+ * so the screen update routines can find it, and restart.
+ */
+ if (didsub && cflag && gflag) {
+ /*
+ * The new search offset will be the end of the
+ * modified line.
+ */
+ saved_offset = lbclen;
+
+ /* Copy the rest of the line. */
+ if (len)
+ BUILD(sp, s + offset, len)
+
+ /* Set the new offset. */
+ offset = saved_offset;
+
+ /* Store inserted lines, adjusting the build buffer. */
+ last = 0;
+ if (sp->newl_cnt) {
+ for (cnt = 0;
+ cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
+ if (file_iline(sp, ep, lno,
+ lb + last, sp->newl[cnt] - last))
+ goto ret1;
+ last = sp->newl[cnt] + 1;
+ ++sp->rptlines[L_ADDED];
+ }
+ lbclen -= last;
+ offset -= last;
+ sp->newl_cnt = 0;
+ }
+
+ /* Store and retrieve the line. */
+ if (file_sline(sp, ep, lno, lb + last, lbclen))
+ goto ret1;
+ if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ goto ret1;
+ }
+ ADD_SPACE_RET(sp, bp, blen, llen)
+ memmove(bp, s, llen);
+ s = bp;
+ len = llen - offset;
+
+ /* Restart the build. */
+ lbclen = 0;
+ BUILD(sp, s, offset);
+
+ /*
+ * If we haven't already done the after-the-string
+ * match, do one. Set REG_NOTEOL so the '$' pattern
+ * only matches once.
+ */
+ if (!do_eol_match)
+ goto endmatch;
+ if (offset == len) {
+ do_eol_match = 0;
+ eflags |= REG_NOTEOL;
+ }
+ goto nextmatch;
+ }
+
+ /*
+ * If it's a global:
+ *
+ * If at the end of the string, do a test for the after
+ * the string match. Set REG_NOTEOL so the '$' pattern
+ * only matches once.
+ */
+ if (gflag && do_eol_match) {
+ if (len == 0) {
+ do_eol_match = 0;
+ eflags |= REG_NOTEOL;
+ }
+ goto nextmatch;
+ }
+
+endmatch: if (!linechanged)
+ continue;
+
+ /* Copy any remaining bytes into the build buffer. */
+ if (len)
+ BUILD(sp, s + offset, len)
+
+ /* Store inserted lines, adjusting the build buffer. */
+ last = 0;
+ if (sp->newl_cnt) {
+ for (cnt = 0;
+ cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
+ if (file_iline(sp, ep,
+ lno, lb + last, sp->newl[cnt] - last))
+ goto ret1;
+ last = sp->newl[cnt] + 1;
+ ++sp->rptlines[L_ADDED];
+ }
+ lbclen -= last;
+ sp->newl_cnt = 0;
+ }
+
+ /* Store the changed line. */
+ if (file_sline(sp, ep, lno, lb + last, lbclen))
+ goto ret1;
+
+ /* Update changed line counter. */
+ ++sp->rptlines[L_CHANGED];
+
+ /* Display as necessary. */
+ if (lflag || nflag || pflag) {
+ from.lno = to.lno = lno;
+ from.cno = to.cno = 0;
+ if (lflag)
+ ex_print(sp, ep, &from, &to, E_F_LIST);
+ if (nflag)
+ ex_print(sp, ep, &from, &to, E_F_HASH);
+ if (pflag)
+ ex_print(sp, ep, &from, &to, E_F_PRINT);
+ }
+ }
+
+ /*
+ * If not in a global command, and nothing matched, say so.
+ * Else, if none of the lines displayed, put something up.
+ */
+ if (!matched) {
+ if (!F_ISSET(sp, S_GLOBAL))
+ msgq(sp, M_INFO, "No match found.");
+ } else if (!lflag && !nflag && !pflag)
+ F_SET(EXP(sp), EX_AUTOPRINT);
+
+ rval = 0;
+ if (0) {
+ret1: rval = 1;
+ }
+
+ if (teardown)
+ intr_end(sp);
+
+ if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * regsub --
+ * Do the substitution for a regular expression.
+ */
+static inline int
+regsub(sp, ip, lbp, lbclenp, lblenp)
+ SCR *sp;
+ char *ip; /* Input line. */
+ char **lbp;
+ size_t *lbclenp, *lblenp;
+{
+ enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv;
+ size_t lbclen, lblen; /* Local copies. */
+ size_t mlen; /* Match length. */
+ size_t rpl; /* Remaining replacement length. */
+ char *rp; /* Replacement pointer. */
+ int ch;
+ int no; /* Match replacement offset. */
+ char *p, *t; /* Buffer pointers. */
+ char *lb; /* Local copies. */
+
+ lb = *lbp; /* Get local copies. */
+ lbclen = *lbclenp;
+ lblen = *lblenp;
+
+ /*
+ * QUOTING NOTE:
+ *
+ * There are some special sequences that vi provides in the
+ * replacement patterns.
+ * & string the RE matched (\& if nomagic set)
+ * \# n-th regular subexpression
+ * \E end \U, \L conversion
+ * \e end \U, \L conversion
+ * \l convert the next character to lower-case
+ * \L convert to lower-case, until \E, \e, or end of replacement
+ * \u convert the next character to upper-case
+ * \U convert to upper-case, until \E, \e, or end of replacement
+ *
+ * Otherwise, since this is the lowest level of replacement, discard
+ * all escape characters. This (hopefully) follows historic practice.
+ */
+#define ADDCH(ch) { \
+ CHAR_T __ch = (ch); \
+ u_int __value = term_key_val(sp, __ch); \
+ if (__value == K_CR || __value == K_NL) { \
+ NEEDNEWLINE(sp); \
+ sp->newl[sp->newl_cnt++] = lbclen; \
+ } else if (conv != C_NOTSET) { \
+ switch (conv) { \
+ case C_ONELOWER: \
+ conv = C_NOTSET; \
+ /* FALLTHROUGH */ \
+ case C_LOWER: \
+ if (isupper(__ch)) \
+ __ch = tolower(__ch); \
+ break; \
+ case C_ONEUPPER: \
+ conv = C_NOTSET; \
+ /* FALLTHROUGH */ \
+ case C_UPPER: \
+ if (islower(__ch)) \
+ __ch = toupper(__ch); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ } \
+ NEEDSP(sp, 1, p); \
+ *p++ = __ch; \
+ ++lbclen; \
+}
+ conv = C_NOTSET;
+ for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
+ switch (ch = *rp++) {
+ case '&':
+ if (O_ISSET(sp, O_MAGIC)) {
+ no = 0;
+ goto subzero;
+ }
+ break;
+ case '\\':
+ if (rpl == 0)
+ break;
+ --rpl;
+ switch (ch = *rp) {
+ case '&':
+ if (!O_ISSET(sp, O_MAGIC)) {
+ ++rp;
+ no = 0;
+ goto subzero;
+ }
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ no = *rp++ - '0';
+subzero: if (sp->match[no].rm_so == -1 ||
+ sp->match[no].rm_eo == -1)
+ continue;
+ mlen =
+ sp->match[no].rm_eo - sp->match[no].rm_so;
+ for (t = ip + sp->match[no].rm_so; mlen--; ++t)
+ ADDCH(*t);
+ continue;
+ case 'e':
+ case 'E':
+ ++rp;
+ conv = C_NOTSET;
+ continue;
+ case 'l':
+ ++rp;
+ conv = C_ONELOWER;
+ continue;
+ case 'L':
+ ++rp;
+ conv = C_LOWER;
+ continue;
+ case 'u':
+ ++rp;
+ conv = C_ONEUPPER;
+ continue;
+ case 'U':
+ ++rp;
+ conv = C_UPPER;
+ continue;
+ default:
+ ++rp;
+ break;
+ }
+ }
+ ADDCH(ch);
+ }
+
+ *lbp = lb; /* Update caller's information. */
+ *lbclenp = lbclen;
+ *lblenp = lblen;
+ return (0);
+}
+
+static int
+checkmatchsize(sp, re)
+ SCR *sp;
+ regex_t *re;
+{
+ /* Build nsub array as necessary. */
+ if (sp->matchsize < re->re_nsub + 1) {
+ sp->matchsize = re->re_nsub + 1;
+ REALLOC(sp, sp->match,
+ regmatch_t *, sp->matchsize * sizeof(regmatch_t));
+ if (sp->match == NULL) {
+ sp->matchsize = 0;
+ return (1);
+ }
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_tag.c b/usr.bin/vi/ex/ex_tag.c
new file mode 100644
index 000000000000..64ef4cbb4966
--- /dev/null
+++ b/usr.bin/vi/ex/ex_tag.c
@@ -0,0 +1,898 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems, Inc.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_tag.c 8.40 (Berkeley) 3/22/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "tag.h"
+
+static char *binary_search __P((char *, char *, char *));
+static int compare __P((char *, char *, char *));
+static char *linear_search __P((char *, char *, char *));
+static int search __P((SCR *, char *, char *, char **));
+static int tag_get __P((SCR *, char *, char **, char **, char **));
+
+/*
+ * ex_tagfirst --
+ * The tag code can be entered from main, i.e. "vi -t tag".
+ */
+int
+ex_tagfirst(sp, tagarg)
+ SCR *sp;
+ char *tagarg;
+{
+ FREF *frp;
+ MARK m;
+ long tl;
+ u_int flags;
+ int sval;
+ char *p, *tag, *name, *search;
+
+ /* Taglength may limit the number of characters. */
+ if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(tagarg) > tl)
+ tagarg[tl] = '\0';
+
+ /* Get the tag information. */
+ if (tag_get(sp, tagarg, &tag, &name, &search))
+ return (1);
+
+ /* Create the file entry. */
+ if ((frp = file_add(sp, NULL, name, 0)) == NULL)
+ return (1);
+ if (file_init(sp, frp, NULL, 0))
+ return (1);
+
+ /*
+ * !!!
+ * The historic tags file format (from a long, long time ago...)
+ * used a line number, not a search string. I got complaints, so
+ * people are still using the format.
+ */
+ if (isdigit(search[0])) {
+ m.lno = atoi(search);
+ m.cno = 0;
+ } else {
+ /*
+ * Search for the tag; cheap fallback for C functions if
+ * the name is the same but the arguments have changed.
+ */
+ m.lno = 1;
+ m.cno = 0;
+ flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
+ sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
+ if (sval && (p = strrchr(search, '(')) != NULL) {
+ p[1] = '\0';
+ sval = f_search(sp, sp->ep,
+ &m, &m, search, NULL, &flags);
+ }
+ if (sval)
+ msgq(sp, M_ERR, "%s: search pattern not found.", tag);
+ }
+
+ /* Set up the screen. */
+ frp->lno = m.lno;
+ frp->cno = m.cno;
+ F_SET(frp, FR_CURSORSET);
+
+ /* Might as well make this the default tag. */
+ if ((EXP(sp)->tlast = strdup(tagarg)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ return (0);
+}
+
+/* Free a tag or tagf structure from a queue. */
+#define FREETAG(tp) { \
+ TAILQ_REMOVE(&exp->tagq, (tp), q); \
+ if ((tp)->search != NULL) \
+ free((tp)->search); \
+ FREE((tp), sizeof(TAGF)); \
+}
+#define FREETAGF(tfp) { \
+ TAILQ_REMOVE(&exp->tagfq, (tfp), q); \
+ free((tfp)->name); \
+ FREE((tfp), sizeof(TAGF)); \
+}
+
+/*
+ * ex_tagpush -- :tag [file]
+ * Move to a new tag.
+ *
+ * The tags stacks in nvi are a bit tricky. Each tag contains a file name,
+ * search string, and line/column numbers. The search string is only used
+ * for the first access and for user display. The first record on the stack
+ * is the place where we first did a tag, so it has no search string. The
+ * second record is the first tag, and so on. Note, this means that the
+ * "current" tag is always on the stack. Each tag has a line/column which is
+ * the location from which the user tagged the following TAG entry, and which
+ * is used as the return location.
+ */
+int
+ex_tagpush(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum {TC_CHANGE, TC_CURRENT} which;
+ EX_PRIVATE *exp;
+ FREF *frp;
+ MARK m;
+ TAG *tp;
+ u_int flags;
+ int sval;
+ long tl;
+ char *name, *p, *search, *tag;
+
+ exp = EXP(sp);
+ switch (cmdp->argc) {
+ case 1:
+ if (exp->tlast != NULL)
+ FREE(exp->tlast, strlen(exp->tlast) + 1);
+ if ((exp->tlast = strdup(cmdp->argv[0]->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ break;
+ case 0:
+ if (exp->tlast == NULL) {
+ msgq(sp, M_ERR, "No previous tag entered.");
+ return (1);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Taglength may limit the number of characters. */
+ if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tlast) > tl)
+ exp->tlast[tl] = '\0';
+
+ /* Get the tag information. */
+ if (tag_get(sp, exp->tlast, &tag, &name, &search))
+ return (1);
+
+ /* Get the (possibly new) FREF structure. */
+ if ((frp = file_add(sp, sp->frp, name, 1)) == NULL)
+ goto modify_err;
+
+ if (sp->frp == frp)
+ which = TC_CURRENT;
+ else {
+ MODIFY_GOTO(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
+ which = TC_CHANGE;
+ }
+
+ /*
+ * Get a tag structure -- if this is the first tag, push it on the
+ * stack as a placeholder and get another tag structure. Set the
+ * line/column of the most recent element on the stack to be the
+ * current values, including the file pointer. Then push the new
+ * TAG onto the stack with the new file and search string for user
+ * display.
+ */
+ CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
+ if (tp != NULL && exp->tagq.tqh_first == NULL) {
+ TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
+ CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
+ }
+ if (exp->tagq.tqh_first != NULL) {
+ exp->tagq.tqh_first->frp = sp->frp;
+ exp->tagq.tqh_first->lno = sp->lno;
+ exp->tagq.tqh_first->cno = sp->cno;
+ }
+ if (tp != NULL) {
+ if ((tp->search = strdup(search)) == NULL)
+ msgq(sp, M_SYSERR, NULL);
+ else
+ tp->slen = strlen(search);
+ tp->frp = frp;
+ TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
+ }
+
+ /* Switch files. */
+ if (which == TC_CHANGE && file_init(sp, frp, NULL, 0)) {
+ if (tp != NULL)
+ FREETAG(tp);
+ /* Handle special, first-tag case. */
+ if (exp->tagq.tqh_first->q.tqe_next == NULL)
+ TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);
+modify_err: free(tag);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historic vi accepted a line number as well as a search
+ * string, and people are apparently still using the format.
+ */
+ if (isdigit(search[0])) {
+ m.lno = atoi(search);
+ m.cno = 0;
+ sval = 0;
+ } else {
+ /*
+ * Search for the tag; cheap fallback for C functions
+ * if the name is the same but the arguments have changed.
+ */
+ m.lno = 1;
+ m.cno = 0;
+ flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
+ sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
+ if (sval && (p = strrchr(search, '(')) != NULL) {
+ p[1] = '\0';
+ sval = f_search(sp, sp->ep,
+ &m, &m, search, NULL, &flags);
+ p[1] = '(';
+ }
+ if (sval)
+ msgq(sp, M_ERR, "%s: search pattern not found.", tag);
+ }
+ free(tag);
+
+ switch (which) {
+ case TC_CHANGE:
+ frp->lno = m.lno;
+ frp->cno = m.cno;
+ F_SET(frp, FR_CURSORSET);
+ F_SET(sp, S_FSWITCH);
+ break;
+ case TC_CURRENT:
+ if (sval)
+ return (1);
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * ex_tagpop -- :tagp[op][!] [number | file]
+ * Pop the tag stack.
+ */
+int
+ex_tagpop(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ EX_PRIVATE *exp;
+ TAG *ntp, *tp;
+ long off;
+ size_t arglen;
+ char *arg, *p, *t;
+
+ /* Check for an empty stack. */
+ exp = EXP(sp);
+ if (exp->tagq.tqh_first == NULL) {
+ msgq(sp, M_INFO, "The tags stack is empty.");
+ return (1);
+ }
+
+ switch (cmdp->argc) {
+ case 0: /* Pop one tag. */
+ ntp = exp->tagq.tqh_first;
+ break;
+ case 1: /* Name or number. */
+ arg = cmdp->argv[0]->bp;
+ off = strtol(arg, &p, 10);
+ if (*p == '\0') {
+ if (off < 1)
+ return (0);
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL && --off > 1; tp = tp->q.tqe_next);
+ if (tp == NULL) {
+ msgq(sp, M_ERR,
+"Less than %s entries on the tags stack; use :display to see the tags stack.",
+ arg);
+ return (1);
+ }
+ ntp = tp;
+ } else {
+ arglen = strlen(arg);
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL; ntp = tp, tp = tp->q.tqe_next) {
+ /* Use the user's original file name. */
+ p = tp->frp->name;
+ if ((t = strrchr(p, '/')) == NULL)
+ t = p;
+ else
+ ++t;
+ if (!strncmp(arg, t, arglen))
+ break;
+ }
+ if (tp == NULL) {
+ msgq(sp, M_ERR,
+"No file named %s on the tags stack; use :display to see the tags stack.",
+ arg);
+ return (1);
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Update the cursor from the saved TAG information. */
+ tp = ntp->q.tqe_next;
+ if (tp->frp == sp->frp) {
+ sp->lno = tp->lno;
+ sp->cno = tp->cno;
+ } else {
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
+ if (file_init(sp, tp->frp, NULL, 0))
+ return (1);
+
+ tp->frp->lno = tp->lno;
+ tp->frp->cno = tp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ F_SET(sp, S_FSWITCH);
+ }
+
+ /* Pop entries off the queue up to ntp. */
+ for (;;) {
+ tp = exp->tagq.tqh_first;
+ FREETAG(tp);
+ if (tp == ntp)
+ break;
+ }
+
+ /* If returning to the first tag, the stack is now empty. */
+ if (exp->tagq.tqh_first->q.tqe_next == NULL)
+ TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);
+ return (0);
+}
+
+/*
+ * ex_tagtop -- :tagt[op][!]
+ * Clear the tag stack.
+ */
+int
+ex_tagtop(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+
+ /* Find oldest saved information. */
+ exp = EXP(sp);
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL && tp->q.tqe_next != NULL; tp = tp->q.tqe_next);
+ if (tp == NULL) {
+ msgq(sp, M_INFO, "The tags stack is empty.");
+ return (1);
+ }
+
+ /* If not switching files, it's easy; else do the work. */
+ if (tp->frp == sp->frp) {
+ sp->lno = tp->lno;
+ sp->cno = tp->cno;
+ } else {
+ MODIFY_RET(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
+ if (file_init(sp, tp->frp, NULL, 0))
+ return (1);
+
+ tp->frp->lno = tp->lno;
+ tp->frp->cno = tp->cno;
+
+ F_SET(sp->frp, FR_CURSORSET);
+ F_SET(sp, S_FSWITCH);
+ }
+
+ /* Empty out the queue. */
+ while ((tp = exp->tagq.tqh_first) != NULL)
+ FREETAG(tp);
+ return (0);
+}
+
+/*
+ * ex_tagdisplay --
+ * Display the list of tags.
+ */
+int
+ex_tagdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+ size_t len, maxlen;
+ int cnt;
+ char *name;
+
+ exp = EXP(sp);
+ if ((tp = exp->tagq.tqh_first) == NULL) {
+ (void)ex_printf(EXCOOKIE, "No tags to display.\n");
+ return (0);
+ }
+
+ /*
+ * Figure out the formatting. MNOC is the maximum
+ * number of file name columns before we split the line.
+ */
+#define MNOC 15
+ for (maxlen = 0,
+ tp = exp->tagq.tqh_first; tp != NULL; tp = tp->q.tqe_next) {
+ len = strlen(name = tp->frp->name); /* The original name. */
+ if (maxlen < len && len < MNOC)
+ maxlen = len;
+ }
+
+ for (cnt = 1, tp = exp->tagq.tqh_first; tp != NULL;
+ ++cnt, tp = tp->q.tqe_next) {
+ len = strlen(name = tp->frp->name); /* The original name. */
+ if (len > maxlen || len + tp->slen > sp->cols)
+ if (tp == NULL || tp->search == NULL)
+ (void)ex_printf(EXCOOKIE,
+ "%2d %s\n", cnt, name);
+ else
+ (void)ex_printf(EXCOOKIE,
+ "%2d %s\n** %*.*s %s\n", cnt, name,
+ (int)maxlen, (int)maxlen, "", tp->search);
+ else
+ if (tp == NULL || tp->search == NULL)
+ (void)ex_printf(EXCOOKIE, "%2d %*.*s\n",
+ cnt, (int)maxlen, (int)len, name);
+ else
+ (void)ex_printf(EXCOOKIE, "%2d %*.*s %s\n",
+ cnt, (int)maxlen, (int)len, name,
+ tp->search);
+ }
+ return (0);
+}
+
+/*
+ * ex_tagalloc --
+ * Create a new list of tag files.
+ */
+int
+ex_tagalloc(sp, str)
+ SCR *sp;
+ char *str;
+{
+ EX_PRIVATE *exp;
+ TAGF *tp;
+ size_t len;
+ char *p, *t;
+
+ /* Free current queue. */
+ exp = EXP(sp);
+ while ((tp = exp->tagfq.tqh_first) != NULL)
+ FREETAGF(tp);
+
+ /* Create new queue. */
+ for (p = t = str;; ++p) {
+ if (*p == '\0' || isblank(*p)) {
+ if ((len = p - t) > 1) {
+ MALLOC_RET(sp, tp, TAGF *, sizeof(TAGF));
+ MALLOC(sp, tp->name, char *, len + 1);
+ if (tp->name == NULL) {
+ FREE(tp, sizeof(TAGF));
+ return (1);
+ }
+ memmove(tp->name, t, len);
+ tp->name[len] = '\0';
+ tp->flags = 0;
+ TAILQ_INSERT_TAIL(&exp->tagfq, tp, q);
+ }
+ t = p + 1;
+ }
+ if (*p == '\0')
+ break;
+ }
+ return (0);
+}
+ /* Free previous queue. */
+/*
+ * ex_tagfree --
+ * Free the tags file list.
+ */
+int
+ex_tagfree(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+ TAGF *tfp;
+
+ /* Free up tag information. */
+ exp = EXP(sp);
+ while ((tp = exp->tagq.tqh_first) != NULL)
+ FREETAG(tp);
+ while ((tfp = exp->tagfq.tqh_first) != NULL)
+ FREETAGF(tfp);
+ if (exp->tlast != NULL)
+ free(exp->tlast);
+ return (0);
+}
+
+/*
+ * ex_tagcopy --
+ * Copy a screen's tag structures.
+ */
+int
+ex_tagcopy(orig, sp)
+ SCR *orig, *sp;
+{
+ EX_PRIVATE *oexp, *nexp;
+ TAG *ap, *tp;
+ TAGF *atfp, *tfp;
+
+ /* Copy tag stack. */
+ oexp = EXP(orig);
+ nexp = EXP(sp);
+ for (ap = oexp->tagq.tqh_first; ap != NULL; ap = ap->q.tqe_next) {
+ MALLOC(sp, tp, TAG *, sizeof(TAG));
+ if (tp == NULL)
+ goto nomem;
+ *tp = *ap;
+ if (ap->search != NULL &&
+ (tp->search = strdup(ap->search)) == NULL)
+ goto nomem;
+ TAILQ_INSERT_TAIL(&nexp->tagq, tp, q);
+ }
+
+ /* Copy list of tag files. */
+ for (atfp = oexp->tagfq.tqh_first;
+ atfp != NULL; atfp = atfp->q.tqe_next) {
+ MALLOC(sp, tfp, TAGF *, sizeof(TAGF));
+ if (tfp == NULL)
+ goto nomem;
+ *tfp = *atfp;
+ if ((tfp->name = strdup(atfp->name)) == NULL)
+ goto nomem;
+ TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);
+ }
+
+ /* Copy the last tag. */
+ if (oexp->tlast != NULL &&
+ (nexp->tlast = strdup(oexp->tlast)) == NULL) {
+nomem: msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * tag_get --
+ * Get a tag from the tags files.
+ */
+static int
+tag_get(sp, tag, tagp, filep, searchp)
+ SCR *sp;
+ char *tag, **tagp, **filep, **searchp;
+{
+ struct stat sb;
+ EX_PRIVATE *exp;
+ TAGF *tfp;
+ size_t plen, slen, tlen;
+ int dne;
+ char *p, pbuf[MAXPATHLEN];
+
+ /*
+ * Find the tag, only display missing file messages once, and
+ * then only if we didn't find the tag.
+ */
+ dne = 0;
+ exp = EXP(sp);
+ for (p = NULL, tfp = exp->tagfq.tqh_first;
+ tfp != NULL && p == NULL; tfp = tfp->q.tqe_next) {
+ errno = 0;
+ F_CLR(tfp, TAGF_DNE);
+ if (search(sp, tfp->name, tag, &p))
+ if (errno == ENOENT) {
+ if (!F_ISSET(tfp, TAGF_DNE_WARN)) {
+ dne = 1;
+ F_SET(tfp, TAGF_DNE);
+ }
+ } else
+ msgq(sp, M_SYSERR, tfp->name);
+ else
+ if (p != NULL)
+ break;
+ }
+
+ if (p == NULL) {
+ msgq(sp, M_ERR, "%s: tag not found.", tag);
+ if (dne)
+ for (tfp = exp->tagfq.tqh_first;
+ tfp != NULL; tfp = tfp->q.tqe_next)
+ if (F_ISSET(tfp, TAGF_DNE)) {
+ errno = ENOENT;
+ msgq(sp, M_SYSERR, tfp->name);
+ F_SET(tfp, TAGF_DNE_WARN);
+ }
+ return (1);
+ }
+
+ /*
+ * Set the return pointers; tagp points to the tag, and, incidentally
+ * the allocated string, filep points to the file name, and searchp
+ * points to the search string. All three are nul-terminated.
+ */
+ for (*tagp = p; *p && !isblank(*p); ++p);
+ if (*p == '\0')
+ goto malformed;
+ for (*p++ = '\0'; isblank(*p); ++p);
+ for (*filep = p; *p && !isblank(*p); ++p);
+ if (*p == '\0')
+ goto malformed;
+ for (*p++ = '\0'; isblank(*p); ++p);
+ *searchp = p;
+ if (*p == '\0') {
+malformed: free(*tagp);
+ msgq(sp, M_ERR, "%s: corrupted tag in %s.", tag, tfp->name);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * If the tag file path is a relative path, see if it exists. If it
+ * doesn't, look relative to the tags file path. It's okay for a tag
+ * file to not exist, and, historically, vi simply displayed a "new"
+ * file. However, if the path exists relative to the tag file, it's
+ * pretty clear what's happening, so we may as well do it right.
+ */
+ if ((*filep)[0] != '/'
+ && stat(*filep, &sb) && (p = strrchr(tfp->name, '/')) != NULL) {
+ *p = '\0';
+ plen = snprintf(pbuf, sizeof(pbuf), "%s/%s", tfp->name, *filep);
+ *p = '/';
+ if (stat(pbuf, &sb) == 0) {
+ slen = strlen(*searchp);
+ tlen = strlen(*tagp);
+ MALLOC(sp, p, char *, plen + slen + tlen + 5);
+ if (p != NULL) {
+ memmove(p, *tagp, tlen);
+ free(*tagp);
+ *tagp = p;
+ *(p += tlen) = '\0';
+ memmove(++p, pbuf, plen);
+ *filep = p;
+ *(p += plen) = '\0';
+ memmove(++p, *searchp, slen);
+ *searchp = p;
+ *(p += slen) = '\0';
+ }
+ }
+ }
+ return (0);
+}
+
+#define EQUAL 0
+#define GREATER 1
+#define LESS (-1)
+
+/*
+ * search --
+ * Search a file for a tag.
+ */
+static int
+search(sp, name, tname, tag)
+ SCR *sp;
+ char *name, *tname, **tag;
+{
+ struct stat sb;
+ int fd, len;
+ char *endp, *back, *front, *map, *p;
+
+ if ((fd = open(name, O_RDONLY, 0)) < 0)
+ return (1);
+
+ /*
+ * XXX
+ * We'd like to test if the file is too big to mmap. Since we don't
+ * know what size or type off_t's or size_t's are, what the largest
+ * unsigned integral type is, or what random insanity the local C
+ * compiler will perpetrate, doing the comparison in a portable way
+ * is flatly impossible. Hope that malloc fails if the file is too
+ * large.
+ */
+ if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size,
+ PROT_READ, MAP_FILE|MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
+ (void)close(fd);
+ return (1);
+ }
+ front = map;
+ back = front + sb.st_size;
+
+ front = binary_search(tname, front, back);
+ front = linear_search(tname, front, back);
+
+ if (front == NULL || (endp = strchr(front, '\n')) == NULL) {
+ *tag = NULL;
+ goto done;
+ }
+
+ len = endp - front;
+ MALLOC(sp, p, char *, len + 1);
+ if (p == NULL) {
+ *tag = NULL;
+ goto done;
+ }
+ memmove(p, front, len);
+ p[len] = '\0';
+ *tag = p;
+
+done: if (munmap(map, (size_t)sb.st_size))
+ msgq(sp, M_SYSERR, "munmap");
+ if (close(fd))
+ msgq(sp, M_SYSERR, "close");
+ return (0);
+}
+
+/*
+ * Binary search for "string" in memory between "front" and "back".
+ *
+ * This routine is expected to return a pointer to the start of a line at
+ * *or before* the first word matching "string". Relaxing the constraint
+ * this way simplifies the algorithm.
+ *
+ * Invariants:
+ * front points to the beginning of a line at or before the first
+ * matching string.
+ *
+ * back points to the beginning of a line at or after the first
+ * matching line.
+ *
+ * Base of the Invariants.
+ * front = NULL;
+ * back = EOF;
+ *
+ * Advancing the Invariants:
+ *
+ * p = first newline after halfway point from front to back.
+ *
+ * If the string at "p" is not greater than the string to match,
+ * p is the new front. Otherwise it is the new back.
+ *
+ * Termination:
+ *
+ * The definition of the routine allows it return at any point,
+ * since front is always at or before the line to print.
+ *
+ * In fact, it returns when the chosen "p" equals "back". This
+ * implies that there exists a string is least half as long as
+ * (back - front), which in turn implies that a linear search will
+ * be no more expensive than the cost of simply printing a string or two.
+ *
+ * Trying to continue with binary search at this point would be
+ * more trouble than it's worth.
+ */
+#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n');
+
+static char *
+binary_search(string, front, back)
+ register char *string, *front, *back;
+{
+ register char *p;
+
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+
+ while (p != back) {
+ if (compare(string, p, back) == GREATER)
+ front = p;
+ else
+ back = p;
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+ }
+ return (front);
+}
+
+/*
+ * Find the first line that starts with string, linearly searching from front
+ * to back.
+ *
+ * Return NULL for no such line.
+ *
+ * This routine assumes:
+ *
+ * o front points at the first character in a line.
+ * o front is before or at the first line to be printed.
+ */
+static char *
+linear_search(string, front, back)
+ char *string, *front, *back;
+{
+ while (front < back) {
+ switch (compare(string, front, back)) {
+ case EQUAL: /* Found it. */
+ return (front);
+ case LESS: /* No such string. */
+ return (NULL);
+ case GREATER: /* Keep going. */
+ break;
+ }
+ SKIP_PAST_NEWLINE(front, back);
+ }
+ return (NULL);
+}
+
+/*
+ * Return LESS, GREATER, or EQUAL depending on how the string1 compares
+ * with string2 (s1 ??? s2).
+ *
+ * o Matches up to len(s1) are EQUAL.
+ * o Matches up to len(s2) are GREATER.
+ *
+ * The string "s1" is null terminated. The string s2 is '\t', space, (or
+ * "back") terminated.
+ *
+ * !!!
+ * Reasonably modern ctags programs use tabs as separators, not spaces.
+ * However, historic programs did use spaces, and, I got complaints.
+ */
+static int
+compare(s1, s2, back)
+ register char *s1, *s2, *back;
+{
+ for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? LESS : GREATER);
+ return (*s1 ? GREATER : s2 < back &&
+ (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL);
+}
diff --git a/usr.bin/vi/ex/ex_undo.c b/usr.bin/vi/ex/ex_undo.c
new file mode 100644
index 000000000000..cb9e9a808b0f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_undo.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_undo.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_undol -- U
+ * Undo changes to this line.
+ */
+int
+ex_undol(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (log_setline(sp, ep))
+ return (1);
+
+ sp->cno = 0;
+ return (0);
+}
+
+/*
+ * ex_undo -- u
+ * Undo the last change.
+ */
+int
+ex_undo(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ MARK m;
+
+ /*
+ * !!!
+ * Multiple undo isn't available in ex, as there's no '.' command.
+ * Whether 'u' is undo or redo is toggled each time, unless there
+ * was a change since the last undo, in which case it's an undo.
+ */
+ if (!F_ISSET(ep, F_UNDO)) {
+ F_SET(ep, F_UNDO);
+ ep->lundo = FORWARD;
+ }
+ switch (ep->lundo) {
+ case BACKWARD:
+ if (log_forward(sp, ep, &m))
+ return (1);
+ ep->lundo = FORWARD;
+ break;
+ case FORWARD:
+ if (log_backward(sp, ep, &m))
+ return (1);
+ ep->lundo = BACKWARD;
+ break;
+ case NOTSET:
+ abort();
+ }
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_usage.c b/usr.bin/vi/ex/ex_usage.c
new file mode 100644
index 000000000000..251c7df85937
--- /dev/null
+++ b/usr.bin/vi/ex/ex_usage.c
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_usage.c 8.14 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * ex_help -- :help
+ * Display help message.
+ */
+int
+ex_help(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ (void)ex_printf(EXCOOKIE,
+ "To see the list of vi commands, enter \":viusage<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "To see the list of ex commands, enter \":exusage<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "For a vi key usage statement enter \":viusage [key]<CR>\"\n");
+ (void)ex_printf(EXCOOKIE, "To exit, enter \":q!\"\n");
+ return (0);
+}
+
+/*
+ * ex_usage -- :exusage [cmd]
+ * Display ex usage strings.
+ */
+int
+ex_usage(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+ EXCMDLIST const *cp;
+ char *name;
+
+ switch (cmdp->argc) {
+ case 1:
+ ap = cmdp->argv[0];
+ for (cp = cmds; cp->name != NULL &&
+ memcmp(ap->bp, cp->name, ap->len); ++cp);
+ if (cp->name == NULL)
+ (void)ex_printf(EXCOOKIE,
+ "The %.*s command is unknown.",
+ (int)ap->len, ap->bp);
+ else {
+ (void)ex_printf(EXCOOKIE,
+ "Command: %s\n Usage: %s\n", cp->help, cp->usage);
+ /*
+ * !!!
+ * The "visual" command has two modes, one from ex,
+ * one from the vi colon line. Don't ask.
+ */
+ if (cp != &cmds[C_VISUAL_EX] &&
+ cp != &cmds[C_VISUAL_VI])
+ break;
+ if (cp == &cmds[C_VISUAL_EX])
+ cp = &cmds[C_VISUAL_VI];
+ else
+ cp = &cmds[C_VISUAL_EX];
+ (void)ex_printf(EXCOOKIE,
+ "Command: %s\n Usage: %s\n", cp->help, cp->usage);
+ }
+ break;
+ case 0:
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (cp = cmds; cp->name != NULL; ++cp) {
+ /* The ^D command has an unprintable name. */
+ if (cp == &cmds[C_SCROLL])
+ name = "^D";
+ else
+ name = cp->name;
+ (void)ex_printf(EXCOOKIE,
+ "%*s: %s\n", MAXCMDNAMELEN, name, cp->help);
+ }
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
+
+/*
+ * ex_viusage -- :viusage [key]
+ * Display vi usage strings.
+ */
+int
+ex_viusage(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ VIKEYS const *kp;
+ int key;
+
+ switch (cmdp->argc) {
+ case 1:
+ key = cmdp->argv[0]->bp[0];
+ if (key > MAXVIKEY)
+ goto nokey;
+
+ /* Special case: '[' and ']' commands. */
+ if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key)
+ goto nokey;
+
+ kp = &vikeys[key];
+ if (kp->func == NULL)
+nokey: (void)ex_printf(EXCOOKIE,
+ "The %s key has no current meaning",
+ charname(sp, key));
+ else
+ (void)ex_printf(EXCOOKIE,
+ " Key:%s%s\nUsage: %s\n",
+ isblank(*kp->help) ? "" : " ", kp->help, kp->usage);
+ break;
+ case 0:
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (key = 0; key <= MAXVIKEY; ++key) {
+ kp = &vikeys[key];
+ if (kp->help != NULL)
+ (void)ex_printf(EXCOOKIE, "%s\n", kp->help);
+ }
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_util.c b/usr.bin/vi/ex/ex_util.c
new file mode 100644
index 000000000000..05bf9bd85c86
--- /dev/null
+++ b/usr.bin/vi/ex/ex_util.c
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_util.c 8.6 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_getline --
+ * Return a line from the terminal.
+ */
+int
+ex_getline(sp, fp, lenp)
+ SCR *sp;
+ FILE *fp;
+ size_t *lenp;
+{
+ EX_PRIVATE *exp;
+ size_t off;
+ int ch;
+ char *p;
+
+ exp = EXP(sp);
+ for (off = 0, p = exp->ibp;; ++off) {
+ ch = getc(fp);
+ if (off >= exp->ibp_len) {
+ BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
+ p = exp->ibp + off;
+ }
+ if (ch == EOF || ch == '\n') {
+ if (ch == EOF && !off)
+ return (1);
+ *lenp = off;
+ return (0);
+ }
+ *p++ = ch;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * ex_sleave --
+ * Save the terminal/signal state, not screen modification time.
+ * Specific to ex/filter.c and ex/ex_shell.c.
+ */
+int
+ex_sleave(sp)
+ SCR *sp;
+{
+ struct sigaction act;
+ struct stat sb;
+ EX_PRIVATE *exp;
+
+ /* Ignore sessions not using tty's. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY))
+ return (1);
+
+ /*
+ * The old terminal values almost certainly turn on VINTR, VQUIT and
+ * VSUSP. We don't want to interrupt the parent(s), so we ignore
+ * VINTR. VQUIT is ignored by main() because nvi never wants to catch
+ * it. A VSUSP handler have been installed by the screen code.
+ */
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ exp = EXP(sp);
+ if (sigaction(SIGINT, &act, &exp->leave_act)) {
+ msgq(sp, M_SYSERR, "sigaction");
+ return (1);
+ }
+ if (tcgetattr(STDIN_FILENO, &exp->leave_term)) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+ if (tcsetattr(STDIN_FILENO,
+ TCSANOW | TCSASOFT, &sp->gp->original_termios)) {
+ msgq(sp, M_SYSERR, "tcsetattr");
+ /*
+ * If an error occurs, back out the changes and run
+ * without interrupts.
+ */
+err: (void)sigaction(SIGINT, &exp->leave_act, NULL);
+ return (1);
+ }
+ /*
+ * The process may write to the terminal. Save the access time
+ * (read) and modification time (write) of the tty; if they have
+ * changed when we restore the modes, will have to refresh the
+ * screen.
+ */
+ if (fstat(STDIN_FILENO, &sb)) {
+ msgq(sp, M_SYSERR, "stat: stdin");
+ exp->leave_atime = exp->leave_mtime = 0;
+ } else {
+ exp->leave_atime = sb.st_atime;
+ exp->leave_mtime = sb.st_mtime;
+ }
+ return (0);
+}
+
+/*
+ * ex_rleave --
+ * Return the terminal/signal state, not screen modification time.
+ * Specific to ex/filter.c and ex/ex_shell.c.
+ */
+void
+ex_rleave(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ struct stat sb;
+
+ exp = EXP(sp);
+
+ /* Turn off interrupts. */
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &exp->leave_term))
+ msgq(sp, M_SYSERR, "tcsetattr");
+
+ /* Reset the signal state. */
+ if (sigaction(SIGINT, &exp->leave_act, NULL))
+ msgq(sp, M_SYSERR, "sigaction");
+
+ /* If the terminal was used, refresh the screen. */
+ if (fstat(STDIN_FILENO, &sb) || exp->leave_atime == 0 ||
+ exp->leave_atime != sb.st_atime || exp->leave_mtime != sb.st_mtime)
+ F_SET(sp, S_REFRESH);
+}
diff --git a/usr.bin/vi/ex/ex_version.c b/usr.bin/vi/ex/ex_version.c
new file mode 100644
index 000000000000..648d323ed681
--- /dev/null
+++ b/usr.bin/vi/ex/ex_version.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_version.c 8.41 (Berkeley) 3/24/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_version -- :version
+ * Display the program version.
+ */
+int
+ex_version(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ static time_t then = 764543281;
+
+ (void)ex_printf(EXCOOKIE,
+"Version 1.11, %sThe CSRG, University of California, Berkeley.\n",
+ ctime(&then));
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_visual.c b/usr.bin/vi/ex/ex_visual.c
new file mode 100644
index 000000000000..66ffb2ba0b7f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_visual.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_visual.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
+ *
+ * Switch to visual mode.
+ */
+int
+ex_visual(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ size_t len;
+ int pos;
+ char buf[256];
+
+ /* If open option off, disallow visual command. */
+ if (!O_ISSET(sp, O_OPEN)) {
+ msgq(sp, M_ERR,
+ "The visual command requires that the open option be set.");
+ return (1);
+ }
+
+ /* If a line specified, move to that line. */
+ if (cmdp->addrcnt)
+ sp->lno = cmdp->addr1.lno;
+
+ /*
+ * Push a command based on the line position flags. If no
+ * flag specified, the line goes at the top of the screen.
+ */
+ switch (F_ISSET(cmdp, E_F_CARAT | E_F_DASH | E_F_DOT | E_F_PLUS)) {
+ case E_F_CARAT:
+ pos = '^';
+ break;
+ case E_F_DASH:
+ pos = '-';
+ break;
+ case E_F_DOT:
+ pos = '.';
+ break;
+ case E_F_PLUS:
+ default:
+ pos = '+';
+ break;
+ }
+
+ if (F_ISSET(cmdp, E_COUNT))
+ len = snprintf(buf, sizeof(buf),
+ "%luz%c%lu", sp->lno, pos, cmdp->count);
+ else
+ len = snprintf(buf, sizeof(buf), "%luz%c", sp->lno, pos);
+ (void)term_push(sp, buf, len, 0, CH_NOMAP | CH_QUOTED);
+
+ /*
+ * !!!
+ * Historically, if no line address was specified, the [p#l] flags
+ * caused the cursor to be moved to the last line of the file, which
+ * was then positioned as described above. This seems useless, so
+ * I haven't implemented it.
+ */
+ switch (F_ISSET(cmdp, E_F_HASH | E_F_LIST | E_F_PRINT)) {
+ case E_F_HASH:
+ O_SET(sp, O_NUMBER);
+ break;
+ case E_F_LIST:
+ O_SET(sp, O_LIST);
+ break;
+ case E_F_PRINT:
+ break;
+ }
+
+ /* Switch modes. */
+ F_CLR(sp, S_SCREENS);
+ F_SET(sp, sp->saved_vi_mode);
+
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_write.c b/usr.bin/vi/ex/ex_write.c
new file mode 100644
index 000000000000..049e0bba1289
--- /dev/null
+++ b/usr.bin/vi/ex/ex_write.c
@@ -0,0 +1,306 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_write.c 8.27 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {WQ, WRITE, XIT};
+
+static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_wq -- :wq[!] [>>] [file]
+ * Write to a file.
+ */
+int
+ex_wq(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ if (exwr(sp, ep, cmdp, WQ))
+ return (1);
+
+ force = F_ISSET(cmdp, E_FORCE);
+ if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
+ msgq(sp, M_ERR,
+ "More files to edit; use \":n\" to go to the next file");
+ return (1);
+ }
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
+
+/*
+ * ex_write -- :write[!] [>>] [file]
+ * :write [!] [cmd]
+ * Write to a file.
+ */
+int
+ex_write(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (exwr(sp, ep, cmdp, WRITE));
+}
+
+
+/*
+ * ex_xit -- :x[it]! [file]
+ *
+ * Write out any modifications and quit.
+ */
+int
+ex_xit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
+ return (1);
+
+ force = F_ISSET(cmdp, E_FORCE);
+ if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
+ msgq(sp, M_ERR,
+ "More files to edit; use \":n\" to go to the next file");
+ return (1);
+ }
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
+
+/*
+ * exwr --
+ * The guts of the ex write commands.
+ */
+static int
+exwr(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ EX_PRIVATE *exp;
+ MARK rm;
+ int flags;
+ char *name, *p;
+
+ /* All write commands can have an associated '!'. */
+ LF_INIT(FS_POSSIBLE);
+ if (F_ISSET(cmdp, E_FORCE))
+ LF_SET(FS_FORCE);
+
+ /* Skip any leading whitespace. */
+ if (cmdp->argc != 0)
+ for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);
+
+ /* If no arguments, just write the file back. */
+ if (cmdp->argc == 0 || *p == '\0') {
+ if (F_ISSET(cmdp, E_ADDR2_ALL))
+ LF_SET(FS_ALL);
+ return (file_write(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, NULL, flags));
+ }
+
+ /* If "write !" it's a pipe to a utility. */
+ exp = EXP(sp);
+ if (cmd == WRITE && *p == '!') {
+ for (++p; *p && isblank(*p); ++p);
+ if (*p == '\0') {
+ msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
+ return (1);
+ }
+ /* Expand the argument. */
+ if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
+ return (1);
+ if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
+ &rm, cmdp->argv[1]->bp, FILTER_WRITE))
+ return (1);
+ sp->lno = rm.lno;
+ return (0);
+ }
+
+ /* If "write >>" it's an append to a file. */
+ if (cmd != XIT && p[0] == '>' && p[1] == '>') {
+ LF_SET(FS_APPEND);
+
+ /* Skip ">>" and whitespace. */
+ for (p += 2; *p && isblank(*p); ++p);
+ }
+
+ /* Build an argv so we get an argument count and file expansion. */
+ if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
+ return (1);
+
+ switch (cmdp->argc) {
+ case 1:
+ /*
+ * Nothing to expand, write the current file.
+ * XXX
+ * Should never happen, already checked this case.
+ */
+ name = NULL;
+ break;
+ case 2:
+ /* One new argument, write it. */
+ name = cmdp->argv[exp->argsoff - 1]->bp;
+ set_alt_name(sp, name);
+ break;
+ default:
+ /* If expanded to more than one argument, object. */
+ msgq(sp, M_ERR, "%s expanded into too many file names",
+ cmdp->argv[0]->bp);
+ msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
+ return (1);
+ }
+
+ if (F_ISSET(cmdp, E_ADDR2_ALL))
+ LF_SET(FS_ALL);
+ return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
+}
+
+/*
+ * ex_writefp --
+ * Write a range of lines to a FILE *.
+ */
+int
+ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
+ SCR *sp;
+ EXF *ep;
+ char *name;
+ FILE *fp;
+ MARK *fm, *tm;
+ u_long *nlno, *nch;
+{
+ struct stat sb;
+ u_long ccnt; /* XXX: can't print off_t portably. */
+ recno_t fline, tline, lcnt;
+ size_t len;
+ int sv_errno;
+ char *p;
+
+ fline = fm->lno;
+ tline = tm->lno;
+
+ if (nlno != NULL) {
+ *nch = 0;
+ *nlno = 0;
+ }
+
+ /*
+ * The vi filter code has multiple processes running simultaneously,
+ * and one of them calls ex_writefp(). The "unsafe" function calls
+ * in this code are to file_gline() and msgq(). File_gline() is safe,
+ * see the comment in filter.c:filtercmd() for details. We don't call
+ * msgq if the multiple process bit in the EXF is set.
+ *
+ * !!!
+ * Historic vi permitted files of 0 length to be written. However,
+ * since the way vi got around dealing with "empty" files was to
+ * always have a line in the file no matter what, it wrote them as
+ * files of a single, empty line. We write empty files.
+ *
+ * "Alex, I'll take vi trivia for $1000."
+ */
+ ccnt = 0;
+ lcnt = 0;
+ if (tline != 0) {
+ for (; fline <= tline; ++fline, ++lcnt) {
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+ if ((p = file_gline(sp, ep, fline, &len)) == NULL)
+ break;
+ if (fwrite(p, 1, len, fp) != len) {
+ msgq(sp, M_SYSERR, name);
+ (void)fclose(fp);
+ return (1);
+ }
+ ccnt += len;
+ if (putc('\n', fp) != '\n')
+ break;
+ ++ccnt;
+ }
+ }
+
+ /* If it's a regular file, sync it so that NFS is forced to flush. */
+ if (!fstat(fileno(fp), &sb) &&
+ S_ISREG(sb.st_mode) && fsync(fileno(fp))) {
+ sv_errno = errno;
+ (void)fclose(fp);
+ errno = sv_errno;
+ goto err;
+ }
+ if (fclose(fp))
+ goto err;
+ if (nlno != NULL) {
+ *nch = ccnt;
+ *nlno = lcnt;
+ }
+ return (0);
+
+err: if (!F_ISSET(ep, F_MULTILOCK))
+ msgq(sp, M_SYSERR, name);
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_yank.c b/usr.bin/vi/ex/ex_yank.c
new file mode 100644
index 000000000000..e37b8362fdde
--- /dev/null
+++ b/usr.bin/vi/ex/ex_yank.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_yank.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_yank -- :[line [,line]] ya[nk] [buffer] [count]
+ *
+ * Yank the lines into a buffer.
+ */
+int
+ex_yank(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (cut(sp, ep, NULL,
+ F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE));
+}
diff --git a/usr.bin/vi/ex/ex_z.c b/usr.bin/vi/ex/ex_z.c
new file mode 100644
index 000000000000..45eef1423d4c
--- /dev/null
+++ b/usr.bin/vi/ex/ex_z.c
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_z.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_z -- :[line] z [^-.+=] [count] [flags]
+ *
+ * Adjust window.
+ */
+int
+ex_z(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t cnt, equals, lno;
+ int eofcheck;
+
+ /*
+ * !!!
+ * If no count specified, use either two times the size of the
+ * scrolling region, or the size of the window option. POSIX
+ * 1003.2 claims that the latter is correct, but historic ex/vi
+ * documentation and practice appear to use the scrolling region.
+ * I'm using the window size as it means that the entire screen
+ * is used instead of losing a line to roundoff. Note, we drop
+ * a line from the cnt if using the window size to leave room for
+ * the next ex prompt.
+ */
+ if (F_ISSET(cmdp, E_COUNT))
+ cnt = cmdp->count;
+ else
+#ifdef HISTORIC_PRACTICE
+ cnt = O_VAL(sp, O_SCROLL) * 2;
+#else
+ cnt = O_VAL(sp, O_WINDOW) - 1;
+#endif
+
+ equals = 0;
+ eofcheck = 0;
+ lno = cmdp->addr1.lno;
+
+ switch (F_ISSET(cmdp,
+ E_F_CARAT | E_F_DASH | E_F_DOT | E_F_EQUAL | E_F_PLUS)) {
+ case E_F_CARAT: /* Display cnt * 2 before the line. */
+ eofcheck = 1;
+ if (lno > cnt * 2)
+ cmdp->addr1.lno = (lno - cnt * 2) + 1;
+ else
+ cmdp->addr1.lno = 1;
+ cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1;
+ break;
+ case E_F_DASH: /* Line goes at the bottom of the screen. */
+ cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1;
+ cmdp->addr2.lno = lno;
+ break;
+ case E_F_DOT: /* Line goes in the middle of the screen. */
+ /*
+ * !!!
+ * Historically, the "middleness" of the line overrode the
+ * count, so that "3z.19" or "3z.20" would display the first
+ * 12 lines of the file, i.e. (N - 1) / 2 lines before and
+ * after the specified line.
+ */
+ eofcheck = 1;
+ cnt = (cnt - 1) / 2;
+ cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
+ cmdp->addr2.lno = lno + cnt;
+ break;
+ case E_F_EQUAL: /* Center with hyphens. */
+ /*
+ * !!!
+ * Strangeness. The '=' flag is like the '.' flag (see the
+ * above comment, it applies here as well) but with a special
+ * little hack. Print out lines of hyphens before and after
+ * the specified line. Additionally, the cursor remains set
+ * on that line.
+ */
+ eofcheck = 1;
+ cnt = (cnt - 1) / 2;
+ cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
+ cmdp->addr2.lno = lno - 1;
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ (void)ex_printf(EXCOOKIE,
+ "%s", "----------------------------------------\n");
+ cmdp->addr2.lno = cmdp->addr1.lno = equals = lno;
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ (void)ex_printf(EXCOOKIE,
+ "%s", "----------------------------------------\n");
+ cmdp->addr1.lno = lno + 1;
+ cmdp->addr2.lno = (lno + cnt) - 1;
+ break;
+ default:
+ /* If no line specified, move to the next one. */
+ if (F_ISSET(cmdp, E_ADDRDEF))
+ ++lno;
+ /* FALLTHROUGH */
+ case E_F_PLUS: /* Line goes at the top of the screen. */
+ eofcheck = 1;
+ cmdp->addr1.lno = lno;
+ cmdp->addr2.lno = (lno + cnt) - 1;
+ break;
+ }
+
+ if (eofcheck) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (cmdp->addr2.lno > lno)
+ cmdp->addr2.lno = lno;
+ }
+
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ if (equals)
+ sp->lno = equals;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/excmd.c b/usr.bin/vi/ex/excmd.c
new file mode 100644
index 000000000000..b4016ccb37d1
--- /dev/null
+++ b/usr.bin/vi/ex/excmd.c
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)excmd.c 8.41 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * This array maps ex command names to command functions.
+ *
+ * The order in which command names are listed below is important --
+ * ambiguous abbreviations are resolved to be the first possible match,
+ * e.g. "r" means "read", not "rewind", because "read" is listed before
+ * "rewind".
+ *
+ * The syntax of the ex commands is unbelievably irregular, and a special
+ * case from beginning to end. Each command has an associated "syntax
+ * script" which describes the "arguments" that are possible. The script
+ * syntax is as follows:
+ *
+ * ! -- ! flag
+ * 1 -- flags: [+-]*[pl#][+-]*
+ * 2 -- flags: [-.+^]
+ * 3 -- flags: [-.+^=]
+ * b -- buffer
+ * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset)
+ * f[N#][or] -- file (a number or N, optional or required)
+ * l -- line
+ * S -- string with file name expansion
+ * s -- string
+ * W -- word string
+ * w[N#][or] -- word (a number or N, optional or required)
+ */
+EXCMDLIST const cmds[] = {
+/* C_SCROLL */
+ {"\004", ex_pr, E_ADDR2|E_NORC,
+ "",
+ "^D",
+ "scroll lines"},
+/* C_BANG */
+ {"!", ex_bang, E_ADDR2_NONE|E_NORC,
+ "S",
+ "[line [,line]] ! command",
+ "filter lines through commands or run commands"},
+/* C_HASH */
+ {"#", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
+ "ca1",
+ "[line [,line]] # [count] [l]",
+ "display numbered lines"},
+/* C_SUBAGAIN */
+ {"&", ex_subagain, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] & [cgr] [count] [#lp]",
+ "repeat the last subsitution"},
+/* C_STAR */
+ {"*", ex_at, 0,
+ "b",
+ "* [buffer]",
+ "execute a buffer"},
+/* C_SHIFTL */
+ {"<", ex_shiftl, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "ca1",
+ "[line [,line]] <[<...] [count] [flags]",
+ "shift lines left"},
+/* C_EQUAL */
+ {"=", ex_equal, E_ADDR1|E_NORC,
+ "1",
+ "[line] = [flags]",
+ "display line number"},
+/* C_SHIFTR */
+ {">", ex_shiftr, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "ca1",
+ "[line [,line]] >[>...] [count] [flags]",
+ "shift lines right"},
+/* C_AT */
+ {"@", ex_at, 0,
+ "b",
+ "@ [buffer]",
+ "execute a buffer"},
+/* C_APPEND */
+ {"append", ex_append, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
+ "!",
+ "[line] a[ppend][!]",
+ "append input to a line"},
+/* C_ABBR */
+ {"abbreviate", ex_abbr, E_NOGLOBAL,
+ "W",
+ "ab[brev] word replace",
+ "specify an input abbreviation"},
+/* C_ARGS */
+ {"args", ex_args, E_NOGLOBAL|E_NORC,
+ "",
+ "ar[gs]",
+ "display file argument list"},
+/* C_BG */
+ {"bg", ex_bg, E_NOGLOBAL|E_NORC,
+ "",
+ "bg",
+ "background the current screen"},
+/* C_CHANGE */
+ {"change", ex_change, E_ADDR2|E_NORC|E_ZERODEF,
+ "!ca",
+ "[line [,line]] c[hange][!] [count]",
+ "change lines to input"},
+/* C_CD */
+ {"cd", ex_cd, E_NOGLOBAL,
+ "!f1o",
+ "cd[!] [directory]",
+ "change the current directory"},
+/* C_CHDIR */
+ {"chdir", ex_cd, E_NOGLOBAL,
+ "!f1o",
+ "chd[ir][!] [directory]",
+ "change the current directory"},
+/* C_COPY */
+ {"copy", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l1",
+ "[line [,line]] co[py] line [flags]",
+ "copy lines elsewhere in the file"},
+/* C_DELETE */
+ {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "bca1",
+ "[line [,line]] d[elete] [buffer] [count] [flags]",
+ "delete lines from the file"},
+/* C_DISPLAY */
+ {"display", ex_display, E_NOGLOBAL|E_NORC,
+ "w1r",
+ "display b[uffers] | s[creens] | t[ags]",
+ "display buffers, screens or tags"},
+/* C_DIGRAPH */
+ {"digraph", ex_digraph, E_NOGLOBAL|E_NOPERM|E_NORC,
+ "",
+ "digraph",
+ "specify digraphs (not implemented)"},
+/* C_EDIT */
+ {"edit", ex_edit, E_NOGLOBAL|E_NORC,
+ "!f1o",
+ "e[dit][!] [+cmd] [file]",
+ "begin editing another file"},
+/* C_EX */
+ {"ex", ex_edit, E_NOGLOBAL|E_NORC,
+ "!f1o",
+ "ex[!] [+cmd] [file]",
+ "begin editing another file"},
+/* C_EXUSAGE */
+ {"exusage", ex_usage, E_NOGLOBAL|E_NORC,
+ "w1o",
+ "[exu]sage [command]",
+ "display ex command usage statement"},
+/* C_FILE */
+ {"file", ex_file, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "f[ile] [name]",
+ "display (and optionally set) file name"},
+/* C_FG */
+ {"fg", ex_fg, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "fg [file]",
+ "switch the current screen and a backgrounded screen"},
+/* C_GLOBAL */
+ {"global", ex_global, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
+ "!s",
+ "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
+ "execute a global command on lines matching an RE"},
+/* C_HELP */
+ {"help", ex_help, E_NOGLOBAL|E_NORC,
+ "",
+ "he[lp]",
+ "display help statement"},
+/* C_INSERT */
+ {"insert", ex_insert, E_ADDR1|E_NORC,
+ "!",
+ "[line] i[nsert][!]",
+ "insert input before a line"},
+/* C_JOIN */
+ {"join", ex_join, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "!ca1",
+ "[line [,line]] j[oin][!] [count] [flags]",
+ "join lines into a single line"},
+/* C_K */
+ {"k", ex_mark, E_ADDR1|E_NORC,
+ "w1r",
+ "[line] k key",
+ "mark a line position"},
+/* C_LIST */
+ {"list", ex_list, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
+ "ca1",
+ "[line [,line]] l[ist] [count] [#]",
+ "display lines in an unambiguous form"},
+/* C_MOVE */
+ {"move", ex_move, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l",
+ "[line [,line]] m[ove] line",
+ "move lines elsewhere in the file"},
+/* C_MARK */
+ {"mark", ex_mark, E_ADDR1|E_NORC,
+ "w1r",
+ "[line] ma[rk] key",
+ "mark a line position"},
+/* C_MAP */
+ {"map", ex_map, 0,
+ "!W",
+ "map[!] [keys replace]",
+ "map input or commands to one or more keys"},
+/* C_MKEXRC */
+ {"mkexrc", ex_mkexrc, E_NOGLOBAL|E_NORC,
+ "!f1r",
+ "mkexrc[!] file",
+ "write a .exrc file"},
+/* C_NEXT */
+ {"next", ex_next, E_NOGLOBAL|E_NORC,
+ "!fN",
+ "n[ext][!] [file ...]",
+ "edit (and optionally specify) the next file"},
+/* C_NUMBER */
+ {"number", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
+ "ca1",
+ "[line [,line]] nu[mber] [count] [l]",
+ "change display to number lines"},
+/* C_OPEN */
+ {"open", ex_open, E_ADDR1,
+ "s",
+ "[line] o[pen] [/RE/] [flags]",
+ "enter \"open\" mode (not implemented)"},
+/* C_PRINT */
+ {"print", ex_pr, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
+ "ca1",
+ "[line [,line]] p[rint] [count] [#l]",
+ "display lines"},
+/* C_PRESERVE */
+ {"preserve", ex_preserve, E_NOGLOBAL|E_NORC,
+ "",
+ "pre[serve]",
+ "preserve an edit session for recovery"},
+/* C_PREVIOUS */
+ {"previous", ex_prev, E_NOGLOBAL|E_NORC,
+ "!",
+ "prev[ious][!]",
+ "edit the previous file in the file argument list"},
+/* C_PUT */
+ {"put", ex_put, E_ADDR1|E_AUTOPRINT|E_NORC|E_ZERO,
+ "b",
+ "[line] pu[t] [buffer]",
+ "append a cut buffer to the line"},
+/* C_QUIT */
+ {"quit", ex_quit, E_NOGLOBAL,
+ "!",
+ "q[uit][!]",
+ "exit ex/vi"},
+/* C_READ */
+ {"read", ex_read, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
+ "!s",
+ "[line] r[ead] [!cmd | [file]]",
+ "append input from a command or file to the line"},
+/* C_RESIZE */
+ {"resize", ex_resize, E_NOGLOBAL|E_NORC,
+ "c+",
+ "resize [+-]rows",
+ "grow or shrink the current screen"},
+/* C_REWIND */
+ {"rewind", ex_rew, E_NOGLOBAL|E_NORC,
+ "!",
+ "rew[ind][!]",
+ "re-edit all the files in the file argument list"},
+/* C_SUBSTITUTE */
+ {"substitute", ex_substitute, E_ADDR2|E_NORC,
+ "s",
+"[line [,line]] s[ubstitute] [[/;]RE[/;]/repl[/;] [cgr] [count] [#lp]]",
+ "substitute on lines matching an RE"},
+/* C_SCRIPT */
+ {"script", ex_script, E_NOGLOBAL|E_NORC,
+ "!f1o",
+ "sc[ript][!] [file]",
+ "run a shell in a screen"},
+/* C_SET */
+ {"set", ex_set, E_NOGLOBAL,
+ "wN",
+ "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
+ "set options (use \":set all\" to see all options)"},
+/* C_SHELL */
+ {"shell", ex_shell, E_NOGLOBAL|E_NORC,
+ "",
+ "sh[ell]",
+ "suspend editing and run a shell"},
+/* C_SOURCE */
+ {"source", ex_source, E_NOGLOBAL,
+ "f1r",
+ "so[urce] file",
+ "read a file of ex commands"},
+/* C_SPLIT */
+ {"split", ex_split, E_NOGLOBAL|E_NORC,
+ "fNo",
+ "sp[lit] [file ...]",
+ "split the current screen into two screens"},
+/* C_STOP */
+ {"stop", ex_stop, E_NOGLOBAL|E_NORC,
+ "!",
+ "st[op][!]",
+ "suspend the edit session"},
+/* C_SUSPEND */
+ {"suspend", ex_stop, E_NOGLOBAL|E_NORC,
+ "!",
+ "su[spend][!]",
+ "suspend the edit session"},
+/* C_T */
+ {"t", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l1",
+ "[line [,line]] t line [flags]",
+ "move lines elsewhere in the file"},
+/* C_TAG */
+ {"tag", ex_tagpush, E_NOGLOBAL,
+ "!w1o",
+ "ta[g][!] [string]",
+ "edit the file containing the tag"},
+/* C_TAGPOP */
+ {"tagpop", ex_tagpop, E_NOGLOBAL|E_NORC,
+ "!w1o",
+ "tagp[op][!] [number | file]",
+ "return to a previous tag"},
+/* C_TAGTOP */
+ {"tagtop", ex_tagtop, E_NOGLOBAL|E_NORC,
+ "!",
+ "tagt[op][!]",
+ "return to the first tag"},
+/* C_UNDOL */
+ {"Undo", ex_undol, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
+ "",
+ "U[ndo]",
+ "undo all the changes to this line"},
+/* C_UNDO */
+ {"undo", ex_undo, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
+ "",
+ "u[ndo]",
+ "undo the most recent change"},
+/* C_UNABBREVIATE */
+ {"unabbreviate",ex_unabbr, E_NOGLOBAL,
+ "w1r",
+ "una[bbrev] word",
+ "delete an abbreviation"},
+/* C_UNMAP */
+ {"unmap", ex_unmap, E_NOGLOBAL,
+ "!w1r",
+ "unm[ap][!] word",
+ "delete an input or command map"},
+/* C_VGLOBAL */
+ {"vglobal", ex_vglobal, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
+ "s",
+ "[line [,line]] v[global] [;/]RE[;/] [commands]",
+ "execute a global command on lines NOT matching an RE"},
+/* C_VERSION */
+ {"version", ex_version, E_NOGLOBAL|E_NORC,
+ "",
+ "version",
+ "display the program version information"},
+/* C_VISUAL_EX */
+ {"visual", ex_visual, E_ADDR1|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "2c11",
+ "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
+ "enter visual (vi) mode from ex mode"},
+/* C_VISUAL_VI */
+ {"visual", ex_edit, E_NOGLOBAL|E_NORC,
+ "!f1o",
+ "vi[sual][!] [+cmd] [file]",
+ "edit another file (from vi mode only)"},
+/* C_VIUSAGE */
+ {"viusage", ex_viusage, E_NOGLOBAL|E_NORC,
+ "w1o",
+ "[viu]sage [key]",
+ "display vi key usage statement"},
+/* C_WRITE */
+ {"write", ex_write, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!s",
+ "[line [,line]] w[rite][!] [!cmd | [>>] [file]]",
+ "write the file"},
+/* C_WQ */
+ {"wq", ex_wq, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!s",
+ "[line [,line]] wq[!] [>>] [file]",
+ "write the file and exit"},
+/* C_XIT */
+ {"xit", ex_xit, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!f1o",
+ "[line [,line]] x[it][!] [file]",
+ "exit"},
+/* C_YANK */
+ {"yank", ex_yank, E_ADDR2|E_NORC,
+ "bca",
+ "[line [,line]] ya[nk] [buffer] [count]",
+ "copy lines to a cut buffer"},
+/* C_Z */
+ {"z", ex_z, E_ADDR1|E_NOGLOBAL|E_NORC,
+ "3c01",
+ "[line] z [-|.|+|^|=] [count] [flags]",
+ "display different screens of the file"},
+/* C_SUBTILDE */
+ {"~", ex_subtilde, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] ~ [cgr] [count] [#lp]",
+ "replace previous RE with previous replacement string,"},
+ {NULL},
+};
diff --git a/usr.bin/vi/ex/excmd.h.stub b/usr.bin/vi/ex/excmd.h.stub
new file mode 100644
index 000000000000..99c81a844503
--- /dev/null
+++ b/usr.bin/vi/ex/excmd.h.stub
@@ -0,0 +1,320 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * 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.
+ *
+ * @(#)excmd.h.stub 8.54 (Berkeley) 3/23/94
+ */
+
+/* Ex command structure. */
+typedef struct _excmdlist {
+ char *name; /* Command name. */
+ /* Underlying function. */
+ int (*fn) __P((SCR *, EXF *, EXCMDARG *));
+
+#define E_ADDR1 0x0000001 /* One address. */
+#define E_ADDR2 0x0000002 /* Two address. */
+#define E_ADDR2_ALL 0x0000004 /* Zero/two addresses; zero == all. */
+#define E_ADDR2_NONE 0x0000008 /* Zero/two addresses; zero == none. */
+#define E_ADDRDEF 0x0000010 /* Default addresses used. */
+#define E_AUTOPRINT 0x0000020 /* Command always sets autoprint. */
+#define E_BUFFER 0x0000040 /* Buffer name supplied. */
+#define E_COUNT 0x0000080 /* Count supplied. */
+#define E_COUNT_NEG 0x0000100 /* Count was signed negative. */
+#define E_COUNT_POS 0x0000200 /* Count was signed positive. */
+#define E_FORCE 0x0000400 /* ! */
+
+#define E_F_CARAT 0x0000800 /* ^ flag. */
+#define E_F_DASH 0x0001000 /* - flag. */
+#define E_F_DOT 0x0002000 /* . flag. */
+#define E_F_EQUAL 0x0004000 /* = flag. */
+#define E_F_HASH 0x0008000 /* # flag. */
+#define E_F_LIST 0x0010000 /* l flag. */
+#define E_F_PLUS 0x0020000 /* + flag. */
+#define E_F_PRINT 0x0040000 /* p flag. */
+
+#define E_F_PRCLEAR 0x0080000 /* Clear the print (#, l, p) flags. */
+#define E_MODIFY 0x0100000 /* File name expansion modified arg. */
+#define E_NOGLOBAL 0x0200000 /* Not in a global. */
+#define E_NOPERM 0x0400000 /* Permission denied for now. */
+#define E_NORC 0x0800000 /* Not from a .exrc or EXINIT. */
+#define E_SETLAST 0x1000000 /* Reset last command. */
+#define E_ZERO 0x2000000 /* 0 is a legal addr1. */
+#define E_ZERODEF 0x4000000 /* 0 is default addr1 of empty files. */
+ u_long flags;
+ char *syntax; /* Syntax script. */
+ char *usage; /* Usage line. */
+ char *help; /* Help line. */
+} EXCMDLIST;
+#define MAXCMDNAMELEN 12 /* Longest command name. */
+extern EXCMDLIST const cmds[]; /* List of ex commands. */
+
+/* Structure passed around to functions implementing ex commands. */
+struct _excmdarg {
+ EXCMDLIST const *cmd; /* Command entry in command table. */
+ CHAR_T buffer; /* Named buffer. */
+ recno_t lineno; /* Line number. */
+ long count; /* Signed, specified count. */
+ int addrcnt; /* Number of addresses (0, 1 or 2). */
+ MARK addr1; /* 1st address. */
+ MARK addr2; /* 2nd address. */
+ ARGS **argv; /* Array of arguments. */
+ int argc; /* Count of arguments. */
+ u_int flags; /* Selected flags from EXCMDLIST. */
+};
+
+/* Global ranges. */
+typedef struct _range RANGE;
+struct _range {
+ CIRCLEQ_ENTRY(_range) q; /* Linked list of ranges. */
+ recno_t start, stop; /* Start/stop of the range. */
+};
+
+/* Cd paths. */
+typedef struct _cdpath CDPATH;
+struct _cdpath {
+ TAILQ_ENTRY(_cdpath) q; /* Linked list of cd paths. */
+ char *path; /* Path. */
+};
+
+/* Ex private, per-screen memory. */
+typedef struct _ex_private {
+ ARGS **args; /* Arguments. */
+ int argscnt; /* Argument count. */
+ int argsoff; /* Offset into arguments. */
+
+ CHAR_T at_lbuf; /* Last executed at buffer's name. */
+ int at_lbuf_set; /* If at_lbuf is set. */
+
+ char *ibp; /* Line input buffer. */
+ size_t ibp_len; /* Line input buffer length. */
+
+ EXCMDLIST const *lastcmd; /* Last command. */
+
+ CHAR_T *lastbcomm; /* Last bang command. */
+
+ struct sigaction leave_act; /* ex_[sr]leave signal state. */
+ struct termios leave_term; /* ex_[sr]leave tty state. */
+ /* XXX: Should be struct timespec's, but time_t is more portable. */
+ time_t leave_atime; /* ex_[sr]leave old access time. */
+ time_t leave_mtime; /* ex_[sr]leave old mod time. */
+
+ TAILQ_HEAD(_tagh, _tag) tagq; /* Tag list (stack). */
+ TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag file list. */
+ char *tlast; /* Saved last tag. */
+
+ TAILQ_HEAD(_cdh, _cdpath) cdq; /* Cd path list. */
+
+ /* Linked list of ranges. */
+ CIRCLEQ_HEAD(_rangeh, _range) rangeq;
+ recno_t range_lno; /* Range set line number. */
+
+#define EX_AUTOPRINT 0x01 /* Autoprint flag. */
+ u_int flags;
+} EX_PRIVATE;
+#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private))
+
+/* Macro to set up a command structure. */
+#define SETCMDARG(s, cmd_id, naddr, lno1, lno2, force, arg) { \
+ ARGS *__ap[2], __a; \
+ memset(&s, 0, sizeof(EXCMDARG)); \
+ s.cmd = &cmds[cmd_id]; \
+ s.addrcnt = (naddr); \
+ s.addr1.lno = (lno1); \
+ s.addr2.lno = (lno2); \
+ s.addr1.cno = s.addr2.cno = 1; \
+ if (force) \
+ s.flags |= E_FORCE; \
+ if ((__a.bp = arg) == NULL) { \
+ s.argc = 0; \
+ __a.len = 0; \
+ } else { \
+ s.argc = 1; \
+ __a.len = strlen(arg); \
+ } \
+ __ap[0] = &__a; \
+ __ap[1] = NULL; \
+ s.argv = __ap; \
+}
+
+/*
+ * !!!
+ * Historically, .exrc files and EXINIT variables could only use ^V
+ * as an escape character, neither ^Q or a user specified character
+ * worked. We enforce that here, just in case someone depends on it.
+ */
+#define IS_ESCAPE(sp, ch) \
+ (F_ISSET(sp, S_VLITONLY) ? \
+ (ch) == LITERAL_CH : term_key_val(sp, ch) == K_VLNEXT)
+
+/*
+ * :next, :prev, :rewind, :tag, :tagpush, :tagpop modifications check.
+ * If force is set, the autowrite is skipped.
+ */
+#define MODIFY_GOTO(sp, ep, force) { \
+ if (F_ISSET((ep), F_MODIFIED)) \
+ if (O_ISSET((sp), O_AUTOWRITE)) { \
+ if (!(force) && \
+ file_write((sp), (ep), NULL, NULL, NULL, \
+ FS_ALL | FS_POSSIBLE)) \
+ goto modify_err; \
+ } else if (ep->refcnt <= 1 && !(force)) { \
+ msgq(sp, M_ERR, \
+ "Modified since last write; write or use ! to override."); \
+ goto modify_err; \
+ } \
+}
+#define MODIFY_RET(sp, ep, force) { \
+ MODIFY_GOTO(sp, ep, force); \
+ if (0) { \
+modify_err: return (1); \
+ } \
+}
+
+/*
+ * Filter actions:
+ *
+ * FILTER Filter text through the utility.
+ * FILTER_READ Read from the utility into the file.
+ * FILTER_WRITE Write to the utility, display its output.
+ */
+enum filtertype { FILTER, FILTER_READ, FILTER_WRITE };
+int filtercmd __P((SCR *, EXF *,
+ MARK *, MARK *, MARK *, char *, enum filtertype));
+
+/* Argument expansion routines. */
+int argv_init __P((SCR *, EXF *, EXCMDARG *));
+int argv_exp0 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
+int argv_exp1 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
+int argv_exp2 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
+int argv_exp3 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
+int argv_free __P((SCR *));
+
+/* Ex function prototypes. */
+int ex __P((SCR *, EXF *));
+int ex_cfile __P((SCR *, EXF *, char *));
+int ex_cmd __P((SCR *, EXF *, char *, size_t));
+int ex_cdalloc __P((SCR *, char *));
+int ex_cdfree __P((SCR *));
+int ex_end __P((SCR *));
+int ex_exec_proc __P((SCR *, char *, char *, char *));
+int ex_gb __P((SCR *, EXF *, TEXTH *, int, u_int));
+int ex_getline __P((SCR *, FILE *, size_t *));
+int ex_icmd __P((SCR *, EXF *, char *, size_t));
+int ex_init __P((SCR *, EXF *));
+int ex_is_abbrev __P((char *, size_t));
+int ex_is_unmap __P((char *, size_t));
+int ex_optchange __P((SCR *, int));
+int ex_print __P((SCR *, EXF *, MARK *, MARK *, int));
+int ex_readfp __P((SCR *, EXF *, char *, FILE *, MARK *, recno_t *, int));
+void ex_refresh __P((SCR *, EXF *));
+void ex_rleave __P((SCR *));
+int ex_screen_copy __P((SCR *, SCR *));
+int ex_screen_end __P((SCR *));
+int ex_sdisplay __P((SCR *, EXF *));
+int ex_sleave __P((SCR *));
+int ex_suspend __P((SCR *));
+int ex_tdisplay __P((SCR *, EXF *));
+int ex_writefp __P((SCR *, EXF *,
+ char *, FILE *, MARK *, MARK *, u_long *, u_long *));
+void global_insdel __P((SCR *, EXF *, enum operation, recno_t));
+int proc_wait __P((SCR *, long, const char *, int));
+int sscr_end __P((SCR *));
+int sscr_exec __P((SCR *, EXF *, recno_t));
+int sscr_input __P((SCR *));
+
+#define EXPROTO(name) int name __P((SCR *, EXF *, EXCMDARG *))
+EXPROTO(ex_abbr);
+EXPROTO(ex_append);
+EXPROTO(ex_args);
+EXPROTO(ex_at);
+EXPROTO(ex_bang);
+EXPROTO(ex_bg);
+EXPROTO(ex_cd);
+EXPROTO(ex_change);
+EXPROTO(ex_color);
+EXPROTO(ex_copy);
+EXPROTO(ex_debug);
+EXPROTO(ex_delete);
+EXPROTO(ex_digraph);
+EXPROTO(ex_display);
+EXPROTO(ex_edit);
+EXPROTO(ex_equal);
+EXPROTO(ex_fg);
+EXPROTO(ex_file);
+EXPROTO(ex_global);
+EXPROTO(ex_help);
+EXPROTO(ex_insert);
+EXPROTO(ex_join);
+EXPROTO(ex_list);
+EXPROTO(ex_map);
+EXPROTO(ex_mark);
+EXPROTO(ex_mkexrc);
+EXPROTO(ex_move);
+EXPROTO(ex_next);
+EXPROTO(ex_number);
+EXPROTO(ex_open);
+EXPROTO(ex_pr);
+EXPROTO(ex_preserve);
+EXPROTO(ex_prev);
+EXPROTO(ex_put);
+EXPROTO(ex_quit);
+EXPROTO(ex_read);
+EXPROTO(ex_resize);
+EXPROTO(ex_rew);
+EXPROTO(ex_script);
+EXPROTO(ex_set);
+EXPROTO(ex_shell);
+EXPROTO(ex_shiftl);
+EXPROTO(ex_shiftr);
+EXPROTO(ex_source);
+EXPROTO(ex_split);
+EXPROTO(ex_stop);
+EXPROTO(ex_subagain);
+EXPROTO(ex_substitute);
+EXPROTO(ex_subtilde);
+EXPROTO(ex_tagpop);
+EXPROTO(ex_tagpush);
+EXPROTO(ex_tagtop);
+EXPROTO(ex_unabbr);
+EXPROTO(ex_undo);
+EXPROTO(ex_undol);
+EXPROTO(ex_unmap);
+EXPROTO(ex_usage);
+EXPROTO(ex_validate);
+EXPROTO(ex_version);
+EXPROTO(ex_vglobal);
+EXPROTO(ex_visual);
+EXPROTO(ex_viusage);
+EXPROTO(ex_wq);
+EXPROTO(ex_write);
+EXPROTO(ex_xit);
+EXPROTO(ex_yank);
+EXPROTO(ex_z);
diff --git a/usr.bin/vi/ex/filter.c b/usr.bin/vi/ex/filter.c
new file mode 100644
index 000000000000..16d879ea686d
--- /dev/null
+++ b/usr.bin/vi/ex/filter.c
@@ -0,0 +1,400 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)filter.c 8.31 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static int filter_ldisplay __P((SCR *, FILE *));
+
+/*
+ * filtercmd --
+ * Run a range of lines through a filter utility and optionally
+ * replace the original text with the stdout/stderr output of
+ * the utility.
+ */
+int
+filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *tm, *rp;
+ char *cmd;
+ enum filtertype ftype;
+{
+ FILE *ifp, *ofp; /* GCC: can't be uninitialized. */
+ pid_t parent_writer_pid, utility_pid;
+ recno_t lno, nread;
+ int input[2], output[2], rval, teardown;
+ char *name;
+
+ /* Set return cursor position; guard against a line number of zero. */
+ *rp = *fm;
+ if (fm->lno == 0)
+ rp->lno = 1;
+
+ /*
+ * There are three different processes running through this code.
+ * They are the utility, the parent-writer and the parent-reader.
+ * The parent-writer is the process that writes from the file to
+ * the utility, the parent reader is the process that reads from
+ * the utility.
+ *
+ * Input and output are named from the utility's point of view.
+ * The utility reads from input[0] and the parent(s) write to
+ * input[1]. The parent(s) read from output[0] and the utility
+ * writes to output[1].
+ *
+ * In the FILTER_READ case, the utility isn't expected to want
+ * input. Redirect its input from /dev/null. Otherwise open
+ * up utility input pipe.
+ */
+ teardown = 0;
+ ifp = ofp = NULL;
+ input[0] = input[1] = output[0] = output[1] = -1;
+ if (ftype == FILTER_READ) {
+ if ((input[0] = open(_PATH_DEVNULL, O_RDONLY, 0)) < 0) {
+ msgq(sp, M_ERR,
+ "filter: %s: %s", _PATH_DEVNULL, strerror(errno));
+ return (1);
+ }
+ } else {
+ if (pipe(input) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ goto err;
+ }
+ if ((ifp = fdopen(input[1], "w")) == NULL) {
+ msgq(sp, M_SYSERR, "fdopen");
+ goto err;
+ }
+ }
+
+ /* Open up utility output pipe. */
+ if (pipe(output) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ goto err;
+ }
+ if ((ofp = fdopen(output[0], "r")) == NULL) {
+ msgq(sp, M_SYSERR, "fdopen");
+ goto err;
+ }
+
+ /*
+ * Save ex/vi terminal settings, and restore the original ones.
+ * Restoration so that users can do things like ":r! cat /dev/tty".
+ */
+ teardown = !ex_sleave(sp);
+
+ /* Fork off the utility process. */
+ switch (utility_pid = vfork()) {
+ case -1: /* Error. */
+ msgq(sp, M_SYSERR, "vfork");
+err: if (input[0] != -1)
+ (void)close(input[0]);
+ if (ifp != NULL)
+ (void)fclose(ifp);
+ else if (input[1] != -1)
+ (void)close(input[1]);
+ if (ofp != NULL)
+ (void)fclose(ofp);
+ else if (output[0] != -1)
+ (void)close(output[0]);
+ if (output[1] != -1)
+ (void)close(output[1]);
+ rval = 1;
+ goto ret;
+ case 0: /* Utility. */
+ /*
+ * The utility has default signal behavior. Don't bother
+ * using sigaction(2) 'cause we want the default behavior.
+ */
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+
+ /*
+ * Redirect stdin from the read end of the input pipe,
+ * and redirect stdout/stderr to the write end of the
+ * output pipe.
+ */
+ (void)dup2(input[0], STDIN_FILENO);
+ (void)dup2(output[1], STDOUT_FILENO);
+ (void)dup2(output[1], STDERR_FILENO);
+
+ /* Close the utility's file descriptors. */
+ (void)close(input[0]);
+ (void)close(input[1]);
+ (void)close(output[0]);
+ (void)close(output[1]);
+
+ if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
+ name = O_STR(sp, O_SHELL);
+ else
+ ++name;
+
+ execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+ msgq(sp, M_ERR, "Error: execl: %s: %s",
+ O_STR(sp, O_SHELL), strerror(errno));
+ _exit (127);
+ /* NOTREACHED */
+ default: /* Parent-reader, parent-writer. */
+ /* Close the pipe ends neither parent will use. */
+ (void)close(input[0]);
+ (void)close(output[1]);
+ break;
+ }
+
+ /*
+ * FILTER_READ:
+ *
+ * Reading is the simple case -- we don't need a parent writer,
+ * so the parent reads the output from the read end of the output
+ * pipe until it finishes, then waits for the child. Ex_readfp
+ * appends to the MARK, and closes ofp.
+ *
+ * !!!
+ * Set the return cursor to the last line read in. Historically,
+ * this behaves differently from ":r file" command, which leaves
+ * the cursor at the first line read in. Check to make sure that
+ * it's not past EOF because we were reading into an empty file.
+ */
+ if (ftype == FILTER_READ) {
+ rval = ex_readfp(sp, ep, "filter", ofp, fm, &nread, 0);
+ sp->rptlines[L_ADDED] += nread;
+ if (fm->lno == 0)
+ rp->lno = nread;
+ else
+ rp->lno += nread;
+ goto uwait;
+ }
+
+ /*
+ * FILTER, FILTER_WRITE
+ *
+ * Here we need both a reader and a writer. Temporary files are
+ * expensive and we'd like to avoid disk I/O. Using pipes has the
+ * obvious starvation conditions. It's done as follows:
+ *
+ * fork
+ * child
+ * write lines out
+ * exit
+ * parent
+ * FILTER:
+ * read lines into the file
+ * delete old lines
+ * FILTER_WRITE
+ * read and display lines
+ * wait for child
+ *
+ * XXX
+ * We get away without locking the underlying database because we know
+ * that none of the records that we're reading will be modified until
+ * after we've read them. This depends on the fact that the current
+ * B+tree implementation doesn't balance pages or similar things when
+ * it inserts new records. When the DB code has locking, we should
+ * treat vi as if it were multiple applications sharing a database, and
+ * do the required locking. If necessary a work-around would be to do
+ * explicit locking in the line.c:file_gline() code, based on the flag
+ * set here.
+ */
+ rval = 0;
+ F_SET(ep, F_MULTILOCK);
+ switch (parent_writer_pid = fork()) {
+ case -1: /* Error. */
+ rval = 1;
+ msgq(sp, M_SYSERR, "fork");
+ (void)close(input[1]);
+ (void)close(output[0]);
+ break;
+ case 0: /* Parent-writer. */
+ /*
+ * Write the selected lines to the write end of the
+ * input pipe. Ifp is closed by ex_writefp.
+ */
+ (void)close(output[0]);
+ _exit(ex_writefp(sp, ep, "filter", ifp, fm, tm, NULL, NULL));
+
+ /* NOTREACHED */
+ default: /* Parent-reader. */
+ (void)close(input[1]);
+ if (ftype == FILTER_WRITE)
+ /*
+ * Read the output from the read end of the output
+ * pipe and display it. Filter_ldisplay closes ofp.
+ */
+ rval = filter_ldisplay(sp, ofp);
+ else {
+ /*
+ * Read the output from the read end of the output
+ * pipe. Ex_readfp appends to the MARK and closes
+ * ofp.
+ */
+ rval = ex_readfp(sp, ep, "filter", ofp, tm, &nread, 0);
+ sp->rptlines[L_ADDED] += nread;
+ }
+
+ /* Wait for the parent-writer. */
+ rval |= proc_wait(sp,
+ (long)parent_writer_pid, "parent-writer", 1);
+
+ /* Delete any lines written to the utility. */
+ if (ftype == FILTER && rval == 0) {
+ for (lno = tm->lno; lno >= fm->lno; --lno)
+ if (file_dline(sp, ep, lno)) {
+ rval = 1;
+ break;
+ }
+ if (rval == 0)
+ sp->rptlines[L_DELETED] +=
+ (tm->lno - fm->lno) + 1;
+ }
+ /*
+ * If the filter had no output, we may have just deleted
+ * the cursor. Don't do any real error correction, we'll
+ * try and recover later.
+ */
+ if (rp->lno > 1 && file_gline(sp, ep, rp->lno, NULL) == NULL)
+ --rp->lno;
+ break;
+ }
+ F_CLR(ep, F_MULTILOCK);
+
+uwait: rval |= proc_wait(sp, (long)utility_pid, cmd, 0);
+
+ /* Restore ex/vi terminal settings. */
+ret: if (teardown)
+ ex_rleave(sp);
+ return (rval);
+}
+
+/*
+ * proc_wait --
+ * Wait for one of the processes.
+ *
+ * !!!
+ * The pid_t type varies in size from a short to a long depending on the
+ * system. It has to be cast into something or the standard promotion
+ * rules get you. I'm using a long based on the belief that nobody is
+ * going to make it unsigned and it's unlikely to be a quad.
+ */
+int
+proc_wait(sp, pid, cmd, okpipe)
+ SCR *sp;
+ long pid;
+ const char *cmd;
+ int okpipe;
+{
+ extern char *sys_siglist[];
+ size_t len;
+ int pstat;
+
+ /* Wait for the utility to finish. */
+ (void)waitpid((pid_t)pid, &pstat, 0);
+
+ /*
+ * Display the utility's exit status. Ignore SIGPIPE from the
+ * parent-writer, as that only means that the utility chose to
+ * exit before reading all of its input.
+ */
+ if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
+ for (; isblank(*cmd); ++cmd);
+ len = strlen(cmd);
+ msgq(sp, M_ERR, "%.*s%s: received signal: %s%s.",
+ MIN(len, 20), cmd, len > 20 ? "..." : "",
+ sys_siglist[WTERMSIG(pstat)],
+ WCOREDUMP(pstat) ? "; core dumped" : "");
+ return (1);
+ }
+ if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
+ for (; isblank(*cmd); ++cmd);
+ len = strlen(cmd);
+ msgq(sp, M_ERR, "%.*s%s: exited with status %d",
+ MIN(len, 20), cmd, len > 20 ? "..." : "",
+ WEXITSTATUS(pstat));
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * filter_ldisplay --
+ * Display a line output from a utility.
+ *
+ * XXX
+ * This should probably be combined with some of the ex_print()
+ * routines into a single display routine.
+ */
+static int
+filter_ldisplay(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ EX_PRIVATE *exp;
+ size_t len;
+
+ exp = EXP(sp);
+ while (!ex_getline(sp, fp, &len)) {
+ (void)ex_printf(EXCOOKIE, "%.*s\n", (int)len, exp->ibp);
+ if (ferror(sp->stdfp)) {
+ msgq(sp, M_SYSERR, NULL);
+ (void)fclose(fp);
+ return (1);
+ }
+ }
+ if (fclose(fp)) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/nex/script.h b/usr.bin/vi/ex/script.h
index a04f14459165..a04f14459165 100644
--- a/usr.bin/vi/nex/script.h
+++ b/usr.bin/vi/ex/script.h
diff --git a/usr.bin/vi/nex/tag.h b/usr.bin/vi/ex/tag.h
index f75d9b3fd466..f75d9b3fd466 100644
--- a/usr.bin/vi/nex/tag.h
+++ b/usr.bin/vi/ex/tag.h
diff --git a/usr.bin/vi/exf.c b/usr.bin/vi/exf.c
index 0f9ac4ba0e4b..7d0c104d4a15 100644
--- a/usr.bin/vi/exf.c
+++ b/usr.bin/vi/exf.c
@@ -32,11 +32,13 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)exf.c 8.65 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)exf.c 8.71 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
/*
* We include <sys/file.h>, because the flock(2) #defines were
@@ -45,15 +47,23 @@ static char sccsid[] = "@(#)exf.c 8.65 (Berkeley) 1/11/94";
*/
#include <sys/file.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
/*
* file_add --
@@ -262,7 +272,7 @@ file_init(sp, frp, rcv_name, force)
msgq(sp, M_ERR,
"Warning: %s is not a regular file.", oname);
}
-
+
/* Set up recovery. */
memset(&oinfo, 0, sizeof(RECNOINFO));
oinfo.bval = '\n'; /* Always set. */
@@ -524,7 +534,7 @@ file_write(sp, ep, fm, tm, name, flags)
FREF *frp;
MARK from, to;
u_long nlno, nch;
- int fd, oflags, rval;
+ int btear, fd, itear, oflags, rval;
char *msg;
/*
@@ -655,17 +665,22 @@ exists: if (LF_ISSET(FS_POSSIBLE))
tm = &to;
}
- /* Write the file. */
+ /* Write the file, allowing interrupts. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Writing...");
+ itear = !intr_init(sp);
rval = ex_writefp(sp, ep, name, fp, fm, tm, &nlno, &nch);
+ if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
/*
* Save the new last modification time -- even if the write fails
- * we re-init the time if we wrote anything. That way the user can
- * clean up the disk and rewrite without having to force it.
+ * we re-init the time. That way the user can clean up the disk
+ * and rewrite without having to force it.
*/
- if (nlno || nch)
- frp->mtime = stat(name, &sb) ? 0 : sb.st_mtime;
-
+ frp->mtime = stat(name, &sb) ? 0 : sb.st_mtime;
+
/* If the write failed, complain loudly. */
if (rval) {
if (!LF_ISSET(FS_APPEND))
diff --git a/usr.bin/vi/exf.h b/usr.bin/vi/exf.h
index 5049f3ea2418..b9874dae2dc5 100644
--- a/usr.bin/vi/exf.h
+++ b/usr.bin/vi/exf.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)exf.h 8.20 (Berkeley) 12/28/93
+ * @(#)exf.h 8.23 (Berkeley) 3/23/94
*/
/* Undo direction. */
/*
@@ -55,7 +55,7 @@ struct _exf {
MARK l_cursor; /* Log cursor position. */
enum direction lundo; /* Last undo direction. */
- LIST_HEAD(_markh, _mark) marks; /* Linked list of file MARK's. */
+ LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */
/*
* Paths for the recovery mail file and the vi recovery file and
@@ -74,6 +74,7 @@ struct _exf {
char *rcv_path; /* Recover file name. */
char *rcv_mpath; /* Recover mail file name. */
int rcv_fd; /* Locked mail file descriptor. */
+ struct timeval rcv_tod; /* ITIMER_REAL: recovery time-of-day. */
#define F_FIRSTMODIFY 0x001 /* File not yet modified. */
#define F_MODIFIED 0x002 /* File is currently dirty. */
diff --git a/usr.bin/vi/gs.h b/usr.bin/vi/gs.h
index 86af7299b3c7..a10f16f3da5b 100644
--- a/usr.bin/vi/gs.h
+++ b/usr.bin/vi/gs.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)gs.h 8.26 (Berkeley) 1/9/94
+ * @(#)gs.h 8.29 (Berkeley) 3/16/94
*/
struct _gs {
CIRCLEQ_HEAD(_dqh, _scr) dq; /* Displayed screens. */
CIRCLEQ_HEAD(_hqh, _scr) hq; /* Hidden screens. */
-
+
mode_t origmode; /* Original terminal mode. */
struct termios
original_termios; /* Original terminal values. */
@@ -75,16 +75,18 @@ struct _gs {
#define G_BELLSCHED 0x00002 /* Bell scheduled. */
#define G_CURSES_INIT 0x00004 /* Curses: initialized. */
#define G_CURSES_S5CB 0x00008 /* Curses: s5_curses_botch set. */
-#define G_ISFROMTTY 0x00010 /* Reading from a tty. */
-#define G_RECOVER_SET 0x00020 /* Recover system initialized. */
-#define G_SETMODE 0x00040 /* Tty mode changed. */
-#define G_SIGALRM 0x00080 /* SIGALRM arrived. */
-#define G_SIGHUP 0x00100 /* SIGHUP arrived. */
-#define G_SIGTERM 0x00200 /* SIGTERM arrived. */
-#define G_SIGWINCH 0x00400 /* SIGWINCH arrived. */
-#define G_SLEEPING 0x00800 /* Asleep (die on signal). */
-#define G_SNAPSHOT 0x01000 /* Always snapshot files. */
-#define G_TMP_INUSE 0x02000 /* Temporary buffer in use. */
+#define G_RECOVER_SET 0x00010 /* Recover system initialized. */
+#define G_SETMODE 0x00020 /* Tty mode changed. */
+#define G_SIGALRM 0x00040 /* SIGALRM arrived. */
+#define G_SIGHUP 0x00080 /* SIGHUP arrived. */
+#define G_SIGTERM 0x00100 /* SIGTERM arrived. */
+#define G_SIGWINCH 0x00200 /* SIGWINCH arrived. */
+#define G_SLEEPING 0x00400 /* Asleep (die on signal). */
+#define G_SNAPSHOT 0x00800 /* Always snapshot files. */
+#define G_STDIN_TTY 0x01000 /* Standard input is a tty. */
+#define G_TERMIOS_SET 0x02000 /* Termios structure is valid. */
+#define G_TMP_INUSE 0x04000 /* Temporary buffer in use. */
+
u_int flags;
};
diff --git a/usr.bin/vi/include/bitstring.h b/usr.bin/vi/include/bitstring.h
deleted file mode 100644
index 88437e7fb9f7..000000000000
--- a/usr.bin/vi/include/bitstring.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Paul Vixie.
- *
- * 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.
- *
- * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
- */
-
-#ifndef _BITSTRING_H_
-#define _BITSTRING_H_
-
-typedef unsigned char bitstr_t;
-
-/* internal macros */
- /* byte of the bitstring bit is in */
-#define _bit_byte(bit) \
- ((bit) >> 3)
-
- /* mask for the bit within its byte */
-#define _bit_mask(bit) \
- (1 << ((bit)&0x7))
-
-/* external macros */
- /* bytes in a bitstring of nbits bits */
-#define bitstr_size(nbits) \
- ((((nbits) - 1) >> 3) + 1)
-
- /* allocate a bitstring */
-#define bit_alloc(nbits) \
- (bitstr_t *)calloc(1, \
- (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
-
- /* allocate a bitstring on the stack */
-#define bit_decl(name, nbits) \
- (name)[bitstr_size(nbits)]
-
- /* is bit N of bitstring name set? */
-#define bit_test(name, bit) \
- ((name)[_bit_byte(bit)] & _bit_mask(bit))
-
- /* set bit N of bitstring name */
-#define bit_set(name, bit) \
- (name)[_bit_byte(bit)] |= _bit_mask(bit)
-
- /* clear bit N of bitstring name */
-#define bit_clear(name, bit) \
- (name)[_bit_byte(bit)] &= ~_bit_mask(bit)
-
- /* clear bits start ... stop in bitstring */
-#define bit_nclear(name, start, stop) { \
- register bitstr_t *_name = name; \
- register int _start = start, _stop = stop; \
- register int _startbyte = _bit_byte(_start); \
- register int _stopbyte = _bit_byte(_stop); \
- if (_startbyte == _stopbyte) { \
- _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
- (0xff << ((_stop&0x7) + 1))); \
- } else { \
- _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
- while (++_startbyte < _stopbyte) \
- _name[_startbyte] = 0; \
- _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
- } \
-}
-
- /* set bits start ... stop in bitstring */
-#define bit_nset(name, start, stop) { \
- register bitstr_t *_name = name; \
- register int _start = start, _stop = stop; \
- register int _startbyte = _bit_byte(_start); \
- register int _stopbyte = _bit_byte(_stop); \
- if (_startbyte == _stopbyte) { \
- _name[_startbyte] |= ((0xff << (_start&0x7)) & \
- (0xff >> (7 - (_stop&0x7)))); \
- } else { \
- _name[_startbyte] |= 0xff << ((_start)&0x7); \
- while (++_startbyte < _stopbyte) \
- _name[_startbyte] = 0xff; \
- _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
- } \
-}
-
- /* find first bit clear in name */
-#define bit_ffc(name, nbits, value) { \
- register bitstr_t *_name = name; \
- register int _byte, _nbits = nbits; \
- register int _stopbyte = _bit_byte(_nbits), _value = -1; \
- for (_byte = 0; _byte <= _stopbyte; ++_byte) \
- if (_name[_byte] != 0xff) { \
- _value = _byte << 3; \
- for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
- ++_value, _stopbyte >>= 1); \
- break; \
- } \
- *(value) = _value; \
-}
-
- /* find first bit set in name */
-#define bit_ffs(name, nbits, value) { \
- register bitstr_t *_name = name; \
- register int _byte, _nbits = nbits; \
- register int _stopbyte = _bit_byte(_nbits), _value = -1; \
- for (_byte = 0; _byte <= _stopbyte; ++_byte) \
- if (_name[_byte]) { \
- _value = _byte << 3; \
- for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
- ++_value, _stopbyte >>= 1); \
- break; \
- } \
- *(value) = _value; \
-}
-
-#endif /* !_BITSTRING_H_ */
diff --git a/usr.bin/vi/include/cdefs.h b/usr.bin/vi/include/cdefs.h
deleted file mode 100644
index c4157bcd1a8d..000000000000
--- a/usr.bin/vi/include/cdefs.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- * 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.
- *
- * @(#)cdefs.h 8.2 (Berkeley) 10/4/93
- */
-
-#ifndef _CDEFS_H_
-#define _CDEFS_H_
-
-#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS };
-#else
-#define __BEGIN_DECLS
-#define __END_DECLS
-#endif
-
-/*
- * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
- * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
- * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
- * in between its arguments. __CONCAT can also concatenate double-quoted
- * strings produced by the __STRING macro, but this only works with ANSI C.
- */
-#if defined(__STDC__) || defined(__cplusplus)
-#define __P(protos) protos /* full-blown ANSI C */
-#define __CONCAT(x,y) x ## y
-#define __STRING(x) #x
-
-#if !defined(__GNUC__) && !defined(__cplusplus)
-#define inline
-#endif
-
-#else /* !(__STDC__ || __cplusplus) */
-#define __P(protos) () /* traditional C preprocessor */
-#define __CONCAT(x,y) x/**/y
-#define __STRING(x) "x"
-
-#ifdef __GNUC__
-#define const __const /* GCC: ANSI C with -traditional */
-#define inline __inline
-#define signed __signed
-#define volatile __volatile
-
-#else /* !__GNUC__ */
-#define const /* delete ANSI C keywords */
-#define inline
-#define signed
-#define volatile
-#endif /* !__GNUC__ */
-#endif /* !(__STDC__ || __cplusplus) */
-
-/*
- * GCC has extensions for declaring functions as `pure' (always returns
- * the same value given the same inputs, i.e., has no external state and
- * no side effects) and `dead' (nonreturning). These mainly affect
- * optimization and warnings. Unfortunately, GCC complains if these are
- * used under strict ANSI mode (`gcc -ansi -pedantic'), hence we need to
- * define them only if compiling without this.
- */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define __dead __volatile
-#define __pure __const
-#else
-#define __dead
-#define __pure
-#endif
-
-#endif /* !_CDEFS_H_ */
diff --git a/usr.bin/vi/include/compat.h b/usr.bin/vi/include/compat.h
deleted file mode 100644
index 10406993014b..000000000000
--- a/usr.bin/vi/include/compat.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- *
- * @(#)compat.h 8.10 (Berkeley) 1/11/94
- */
-
-#ifndef _COMPAT_H_
-#define _COMPAT_H_
-
-#include <sys/types.h>
-#include <machine/limits.h>
-#include <termios.h>
-#include <errno.h>
-
-/*
- * If your system doesn't typedef u_long, u_short, or u_char, change
- * the 0 to a 1.
- */
-#if 0
-typedef unsigned char u_char; /* 4.[34]BSD names. */
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short u_short;
-#endif
-
-/* If your system doesn't typedef size_t, change the 0 to a 1. */
-#if 0
-typedef unsigned int size_t; /* 4.[34]BSD names. */
-#endif
-
-/*
- * If your system doesn't have the POSIX type for a signal mask,
- * change the 0 to a 1.
- */
-#if 0 /* POSIX 1003.1 signal mask type. */
-typedef unsigned int sigset_t;
-#endif
-
-/*
- * If your system's vsprintf returns a char *, not an int,
- * change the 0 to a 1.
- */
-#if 0
-#define VSPRINTF_CHARSTAR
-#endif
-
-/*
- * If you don't have POSIX 1003.1 signals, the signal code surrounding the
- * temporary file creation is intended to block all of the possible signals
- * long enough to create the file and unlink it. All of this stuff is
- * intended to use old-style BSD calls to fake POSIX 1003.1 calls.
- */
-#ifdef NO_POSIX_SIGNALS
-#define sigemptyset(set) (*(set) = 0)
-#define sigfillset(set) (*(set) = ~(sigset_t)0, 0)
-#define sigaddset(set,signo) (*(set) |= sigmask(signo), 0)
-#define sigdelset(set,signo) (*(set) &= ~sigmask(signo), 0)
-#define sigismember(set,signo) ((*(set) & sigmask(signo)) != 0)
-
-#define SIG_BLOCK 1
-#define SIG_UNBLOCK 2
-#define SIG_SETMASK 3
-
-static int __sigtemp; /* For the use of sigprocmask */
-
-/* Repeated test of oset != NULL is to avoid "*0". */
-#define sigprocmask(how, set, oset) \
- ((__sigtemp = \
- (((how) == SIG_BLOCK) ? \
- sigblock(0) | *(set) : \
- (((how) == SIG_UNBLOCK) ? \
- sigblock(0) & ~(*(set)) : \
- ((how) == SIG_SETMASK ? \
- *(set) : sigblock(0))))), \
- ((oset) ? (*(oset ? oset : set) = sigsetmask(__sigtemp)) : \
- sigsetmask(__sigtemp)), 0)
-#endif
-
-/*
- * If realloc(3) of a NULL pointer on your system isn't the same as
- * a malloc(3) call, change the 0 to a 1, and add realloc.o to the
- * MISC line in your Makefile.
- */
-#if 0
-#define realloc __fix_realloc
-#endif
-
-/*
- * If your system doesn't have an include file with the appropriate
- * byte order set, make sure you specify the correct one.
- */
-#ifndef BYTE_ORDER
-#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
-#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
-#define BYTE_ORDER LITTLE_ENDIAN /* Set for your system. */
-#endif
-
-#if defined(SYSV) || defined(SYSTEM5)
-#define index(a, b) strchr(a, b)
-#define rindex(a, b) strrchr(a, b)
-#define bzero(a, b) memset(a, 0, b)
-#define bcmp(a, b, n) memcmp(a, b, n)
-#define bcopy(a, b, n) memmove(b, a, n)
-#endif
-
-#if defined(BSD) || defined(BSD4_3)
-#define strchr(a, b) index(a, b)
-#define strrchr(a, b) rindex(a, b)
-#define memcmp(a, b, n) bcmp(a, b, n)
-#define memmove(a, b, n) bcopy(b, a, n)
-#endif
-
-/*
- * 32-bit machine. The db routines are theoretically independent of
- * the size of u_shorts and u_longs, but I don't know that anyone has
- * ever actually tried it. At a minimum, change the following #define's
- * if you are trying to compile on a different type of system.
- */
-#ifndef USHRT_MAX
-#define USHRT_MAX 0xFFFF
-#define ULONG_MAX 0xFFFFFFFF
-#endif
-
-#ifndef O_ACCMODE /* POSIX 1003.1 access mode mask. */
-#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
-
-#ifndef _POSIX2_RE_DUP_MAX /* POSIX 1003.2 RE limit. */
-#define _POSIX2_RE_DUP_MAX 255
-#endif
-
-/*
- * If you can't provide lock values in the open(2) call. Note, this
- * allows races to happen.
- */
-#ifndef O_EXLOCK /* 4.4BSD extension. */
-#define O_EXLOCK 0
-#endif
-
-#ifndef O_SHLOCK /* 4.4BSD extension. */
-#define O_SHLOCK 0
-#endif
-
-#ifndef EFTYPE
-#define EFTYPE EINVAL /* POSIX 1003.1 format errno. */
-#endif
-
-#ifndef WCOREDUMP /* 4.4BSD extension */
-#define WCOREDUMP(a) 0
-#endif
-
-#ifndef STDERR_FILENO
-#define STDIN_FILENO 0 /* ANSI C #defines */
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-#endif
-
-#ifndef SEEK_END
-#define SEEK_SET 0 /* POSIX 1003.1 seek values */
-#define SEEK_CUR 1
-#define SEEK_END 2
-#endif
-
-#ifndef _POSIX_VDISABLE /* POSIX 1003.1 disabling char. */
-#define _POSIX_VDISABLE 0 /* Some systems used 0. */
-#endif
-
-#ifndef S_ISLNK /* BSD POSIX 1003.1 extensions */
-#define S_ISLNK(m) ((m & 0170000) == 0120000)
-#define S_ISSOCK(m) ((m & 0170000) == 0140000)
-#endif
-
-#ifndef TCSASOFT /* 4.4BSD extension. */
-#define TCSASOFT 0
-#endif
-
-#ifndef _POSIX2_RE_DUP_MAX /* POSIX 1003.2 values. */
-#define _POSIX2_RE_DUP_MAX 255
-#endif
-
-#ifndef NULL /* ANSI C #defines NULL everywhere. */
-#define NULL 0
-#endif
-
-#ifndef MAX /* Usually found in <sys/param.h>. */
-#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a))
-#endif
-#ifndef MIN /* Usually found in <sys/param.h>. */
-#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
-#endif
-
-/* Default file permissions. */
-#ifndef DEFFILEMODE /* 4.4BSD extension. */
-#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
-#endif
-
-#ifndef S_ISDIR /* POSIX 1003.1 file type tests. */
-#define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */
-#define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */
-#define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */
-#define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */
-#define S_ISFIFO(m) ((m & 0170000) == 0010000) /* fifo */
-#define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */
-#define S_ISSOCK(m) ((m & 0170000) == 0140000) /* socket */
-#endif
-
-/* The type of a va_list. */
-#ifndef _BSD_VA_LIST_ /* 4.4BSD #define. */
-#define _BSD_VA_LIST_ char *
-#endif
-
-#endif /* !_COMPAT_H_ */
diff --git a/usr.bin/vi/include/err.h b/usr.bin/vi/include/err.h
deleted file mode 100644
index b6d7e5f94b87..000000000000
--- a/usr.bin/vi/include/err.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <sys/cdefs.h>
-
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void err __P((int, const char *, ...));
-void verr __P((int, const char *, va_list));
-void errx __P((int, const char *, ...));
-void verrx __P((int, const char *, va_list));
-void warn __P((const char *, ...));
-void vwarn __P((const char *, va_list));
-void warnx __P((const char *, ...));
-void vwarnx __P((const char *, va_list));
diff --git a/usr.bin/vi/include/file.h b/usr.bin/vi/include/file.h
deleted file mode 100644
index 680797fa6a52..000000000000
--- a/usr.bin/vi/include/file.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * If we're doing flock(2) emulation, we need to get the LOCK_* #defines.
- * This stub <sys/file.h> includes the real one, and, if they're not in
- * it, we #define them here.
- */
-
-#include </usr/include/sys/file.h>
-
-#ifndef LOCK_SH
-/* lock operations for flock(2) */
-#define LOCK_SH 0x01 /* shared file lock */
-#define LOCK_EX 0x02 /* exclusive file lock */
-#define LOCK_NB 0x04 /* don't block when locking */
-#define LOCK_UN 0x08 /* unlock file */
-#endif
diff --git a/usr.bin/vi/include/glob.h b/usr.bin/vi/include/glob.h
deleted file mode 100644
index b679f6aef62a..000000000000
--- a/usr.bin/vi/include/glob.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * 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.
- *
- * @(#)glob.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _GLOB_H_
-#define _GLOB_H_
-
-#include <sys/cdefs.h>
-
-#include "compat.h"
-
-struct stat;
-typedef struct {
- int gl_pathc; /* Count of total paths so far. */
- int gl_matchc; /* Count of paths matching pattern. */
- int gl_offs; /* Reserved at beginning of gl_pathv. */
- int gl_flags; /* Copy of flags parameter to glob. */
- char **gl_pathv; /* List of paths matching pattern. */
- /* Copy of errfunc parameter to glob. */
- int (*gl_errfunc) __P((const char *, int));
-
- /*
- * Alternate filesystem access methods for glob; replacement
- * versions of closedir(3), readdir(3), opendir(3), stat(2)
- * and lstat(2).
- */
- void (*gl_closedir) __P((void *));
- struct dirent *(*gl_readdir) __P((void *));
- void *(*gl_opendir) __P((const char *));
- int (*gl_lstat) __P((const char *, struct stat *));
- int (*gl_stat) __P((const char *, struct stat *));
-} glob_t;
-
-#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
-#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
-#define GLOB_ERR 0x0004 /* Return on error. */
-#define GLOB_MARK 0x0008 /* Append / to matching directories. */
-#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
-#define GLOB_NOSORT 0x0020 /* Don't sort. */
-
-#ifndef _POSIX_SOURCE
-#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
-#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */
-#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
-#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
-#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */
-#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */
-#endif
-
-#define GLOB_NOSPACE (-1) /* Malloc call failed. */
-#define GLOB_ABEND (-2) /* Unignored error. */
-
-__BEGIN_DECLS
-int glob __P((const char *, int, int (*)(const char *, int), glob_t *));
-void globfree __P((glob_t *));
-__END_DECLS
-
-#endif /* !_GLOB_H_ */
diff --git a/usr.bin/vi/include/mpool.h b/usr.bin/vi/include/mpool.h
deleted file mode 100644
index 910e0782aa9d..000000000000
--- a/usr.bin/vi/include/mpool.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- *
- * @(#)mpool.h 8.1 (Berkeley) 6/2/93
- */
-
-/*
- * The memory pool scheme is a simple one. Each in memory page is referenced
- * by a bucket which is threaded in three ways. All active pages are threaded
- * on a hash chain (hashed by the page number) and an lru chain. Inactive
- * pages are threaded on a free chain. Each reference to a memory pool is
- * handed an MPOOL which is the opaque cookie passed to all of the memory
- * routines.
- */
-#define HASHSIZE 128
-#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE)
-
-/* The BKT structures are the elements of the lists. */
-typedef struct BKT {
- struct BKT *hnext; /* next hash bucket */
- struct BKT *hprev; /* previous hash bucket */
- struct BKT *cnext; /* next free/lru bucket */
- struct BKT *cprev; /* previous free/lru bucket */
- void *page; /* page */
- pgno_t pgno; /* page number */
-
-#define MPOOL_DIRTY 0x01 /* page needs to be written */
-#define MPOOL_PINNED 0x02 /* page is pinned into memory */
- unsigned long flags; /* flags */
-} BKT;
-
-/* The BKTHDR structures are the heads of the lists. */
-typedef struct BKTHDR {
- struct BKT *hnext; /* next hash bucket */
- struct BKT *hprev; /* previous hash bucket */
- struct BKT *cnext; /* next free/lru bucket */
- struct BKT *cprev; /* previous free/lru bucket */
-} BKTHDR;
-
-typedef struct MPOOL {
- BKTHDR free; /* The free list. */
- BKTHDR lru; /* The LRU list. */
- BKTHDR hashtable[HASHSIZE]; /* Hashed list by page number. */
- pgno_t curcache; /* Current number of cached pages. */
- pgno_t maxcache; /* Max number of cached pages. */
- pgno_t npages; /* Number of pages in the file. */
- u_long pagesize; /* File page size. */
- int fd; /* File descriptor. */
- /* Page in conversion routine. */
- void (*pgin) __P((void *, pgno_t, void *));
- /* Page out conversion routine. */
- void (*pgout) __P((void *, pgno_t, void *));
- void *pgcookie; /* Cookie for page in/out routines. */
-#ifdef STATISTICS
- unsigned long cachehit;
- unsigned long cachemiss;
- unsigned long pagealloc;
- unsigned long pageflush;
- unsigned long pageget;
- unsigned long pagenew;
- unsigned long pageput;
- unsigned long pageread;
- unsigned long pagewrite;
-#endif
-} MPOOL;
-
-#ifdef __MPOOLINTERFACE_PRIVATE
-/* Macros to insert/delete into/from hash chain. */
-#define rmhash(bp) { \
- (bp)->hprev->hnext = (bp)->hnext; \
- (bp)->hnext->hprev = (bp)->hprev; \
-}
-#define inshash(bp, pg) { \
- hp = &mp->hashtable[HASHKEY(pg)]; \
- (bp)->hnext = hp->hnext; \
- (bp)->hprev = (struct BKT *)hp; \
- hp->hnext->hprev = (bp); \
- hp->hnext = (bp); \
-}
-
-/* Macros to insert/delete into/from lru and free chains. */
-#define rmchain(bp) { \
- (bp)->cprev->cnext = (bp)->cnext; \
- (bp)->cnext->cprev = (bp)->cprev; \
-}
-#define inschain(bp, dp) { \
- (bp)->cnext = (dp)->cnext; \
- (bp)->cprev = (struct BKT *)(dp); \
- (dp)->cnext->cprev = (bp); \
- (dp)->cnext = (bp); \
-}
-#endif
-
-__BEGIN_DECLS
-MPOOL *mpool_open __P((DBT *, int, pgno_t, pgno_t));
-void mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *),
- void (*)(void *, pgno_t, void *), void *));
-void *mpool_new __P((MPOOL *, pgno_t *));
-void *mpool_get __P((MPOOL *, pgno_t, u_int));
-int mpool_put __P((MPOOL *, void *, u_int));
-int mpool_sync __P((MPOOL *));
-int mpool_close __P((MPOOL *));
-#ifdef STATISTICS
-void mpool_stat __P((MPOOL *));
-#endif
-__END_DECLS
diff --git a/usr.bin/vi/include/ndbm.h b/usr.bin/vi/include/ndbm.h
deleted file mode 100644
index a545bca1326e..000000000000
--- a/usr.bin/vi/include/ndbm.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Margo Seltzer.
- *
- * 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.
- *
- * @(#)ndbm.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _NDBM_H_
-#define _NDBM_H_
-
-#include <db.h>
-
-/* Map dbm interface onto db(3). */
-#define DBM_RDONLY O_RDONLY
-
-/* Flags to dbm_store(). */
-#define DBM_INSERT 0
-#define DBM_REPLACE 1
-
-/*
- * The db(3) support for ndbm(3) always appends this suffix to the
- * file name to avoid overwriting the user's original database.
- */
-#define DBM_SUFFIX ".db"
-
-typedef struct {
- char *dptr;
- int dsize;
-} datum;
-
-typedef DB DBM;
-#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE
-
-__BEGIN_DECLS
-void dbm_close __P((DBM *));
-int dbm_delete __P((DBM *, datum));
-datum dbm_fetch __P((DBM *, datum));
-datum dbm_firstkey __P((DBM *));
-long dbm_forder __P((DBM *, datum));
-datum dbm_nextkey __P((DBM *));
-DBM *dbm_open __P((const char *, int, int));
-int dbm_store __P((DBM *, datum, datum, int));
-int dbm_dirfno __P((DBM *));
-__END_DECLS
-
-#endif /* !_NDBM_H_ */
diff --git a/usr.bin/vi/include/queue.h b/usr.bin/vi/include/queue.h
deleted file mode 100644
index 40d32ccb6e29..000000000000
--- a/usr.bin/vi/include/queue.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- * 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.
- *
- * @(#)queue.h 8.3 (Berkeley) 12/13/93
- */
-
-#ifndef _QUEUE_H_
-#define _QUEUE_H_
-
-/*
- * This file defines three types of data structures: lists, tail queues,
- * and circular queues.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element or at the head of the list. A list may only be
- * traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element, at the head of the list, or at the end of the
- * list. A tail queue may only be traversed in the forward direction.
- *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- */
-
-/*
- * List definitions.
- */
-#define LIST_HEAD(name, type) \
-struct name { \
- struct type *lh_first; /* first element */ \
-}
-
-#define LIST_ENTRY(type) \
-struct { \
- struct type *le_next; /* next element */ \
- struct type **le_prev; /* address of previous next element */ \
-}
-
-/*
- * List functions.
- */
-#define LIST_INIT(head) { \
- (head)->lh_first = NULL; \
-}
-
-#define LIST_INSERT_AFTER(listelm, elm, field) { \
- if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
- (listelm)->field.le_next->field.le_prev = \
- &(elm)->field.le_next; \
- (listelm)->field.le_next = (elm); \
- (elm)->field.le_prev = &(listelm)->field.le_next; \
-}
-
-#define LIST_INSERT_HEAD(head, elm, field) { \
- if (((elm)->field.le_next = (head)->lh_first) != NULL) \
- (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
- (head)->lh_first = (elm); \
- (elm)->field.le_prev = &(head)->lh_first; \
-}
-
-#define LIST_REMOVE(elm, field) { \
- if ((elm)->field.le_next != NULL) \
- (elm)->field.le_next->field.le_prev = \
- (elm)->field.le_prev; \
- *(elm)->field.le_prev = (elm)->field.le_next; \
-}
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type) \
-struct name { \
- struct type *tqh_first; /* first element */ \
- struct type **tqh_last; /* addr of last next element */ \
-}
-
-#define TAILQ_ENTRY(type) \
-struct { \
- struct type *tqe_next; /* next element */ \
- struct type **tqe_prev; /* address of previous next element */ \
-}
-
-/*
- * Tail queue functions.
- */
-#define TAILQ_INIT(head) { \
- (head)->tqh_first = NULL; \
- (head)->tqh_last = &(head)->tqh_first; \
-}
-
-#define TAILQ_INSERT_HEAD(head, elm, field) { \
- if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (head)->tqh_first = (elm); \
- (elm)->field.tqe_prev = &(head)->tqh_first; \
-}
-
-#define TAILQ_INSERT_TAIL(head, elm, field) { \
- (elm)->field.tqe_next = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- *(head)->tqh_last = (elm); \
- (head)->tqh_last = &(elm)->field.tqe_next; \
-}
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \
- if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (listelm)->field.tqe_next = (elm); \
- (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
-}
-
-#define TAILQ_REMOVE(head, elm, field) { \
- if (((elm)->field.tqe_next) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- (elm)->field.tqe_prev; \
- else \
- (head)->tqh_last = (elm)->field.tqe_prev; \
- *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
-}
-
-/*
- * Circular queue definitions.
- */
-#define CIRCLEQ_HEAD(name, type) \
-struct name { \
- struct type *cqh_first; /* first element */ \
- struct type *cqh_last; /* last element */ \
-}
-
-#define CIRCLEQ_ENTRY(type) \
-struct { \
- struct type *cqe_next; /* next element */ \
- struct type *cqe_prev; /* previous element */ \
-}
-
-/*
- * Circular queue functions.
- */
-#define CIRCLEQ_INIT(head) { \
- (head)->cqh_first = (void *)(head); \
- (head)->cqh_last = (void *)(head); \
-}
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \
- (elm)->field.cqe_next = (listelm)->field.cqe_next; \
- (elm)->field.cqe_prev = (listelm); \
- if ((listelm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (listelm)->field.cqe_next->field.cqe_prev = (elm); \
- (listelm)->field.cqe_next = (elm); \
-}
-
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \
- (elm)->field.cqe_next = (listelm); \
- (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
- if ((listelm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (listelm)->field.cqe_prev->field.cqe_next = (elm); \
- (listelm)->field.cqe_prev = (elm); \
-}
-
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \
- (elm)->field.cqe_next = (head)->cqh_first; \
- (elm)->field.cqe_prev = (void *)(head); \
- if ((head)->cqh_last == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (head)->cqh_first->field.cqe_prev = (elm); \
- (head)->cqh_first = (elm); \
-}
-
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \
- (elm)->field.cqe_next = (void *)(head); \
- (elm)->field.cqe_prev = (head)->cqh_last; \
- if ((head)->cqh_first == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (head)->cqh_last->field.cqe_next = (elm); \
- (head)->cqh_last = (elm); \
-}
-
-#define CIRCLEQ_REMOVE(head, elm, field) { \
- if ((elm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm)->field.cqe_prev; \
- else \
- (elm)->field.cqe_next->field.cqe_prev = \
- (elm)->field.cqe_prev; \
- if ((elm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm)->field.cqe_next; \
- else \
- (elm)->field.cqe_prev->field.cqe_next = \
- (elm)->field.cqe_next; \
-}
-#endif /* !_QUEUE_H_ */
diff --git a/usr.bin/vi/interrupt.h b/usr.bin/vi/interrupt.h
deleted file mode 100644
index baa75fef2ca9..000000000000
--- a/usr.bin/vi/interrupt.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * Copyright (c) 1994
- * 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.
- *
- * @(#)interrupt.h 8.1 (Berkeley) 1/9/94
- */
-
-/*
- * Macros to declare the variables and then turn on and off interrupts.
- */
-#define DECLARE_INTERRUPTS \
- struct sigaction __act, __oact; \
- struct termios __nterm, __term; \
- u_int __istate; \
- int __isig, __termreset
-
-/*
- * Search, global, and substitute interruptions.
- *
- * ISIG turns on VINTR, VQUIT and VSUSP. We want VINTR to interrupt the
- * search, so we install a handler. VQUIT is ignored by main() because
- * nvi never wants to catch it. A handler for VSUSP should have been
- * installed by the screen code.
- */
-#define SET_UP_INTERRUPTS(handler) { \
- if (F_ISSET(sp->gp, G_ISFROMTTY)) { \
- __act.sa_handler = handler; \
- sigemptyset(&__act.sa_mask); \
- __act.sa_flags = 0; \
- if (__isig = !sigaction(SIGINT, &__act, &__oact)) { \
- __termreset = 0; \
- __istate = F_ISSET(sp, S_INTERRUPTIBLE); \
- F_CLR(sp, S_INTERRUPTED); \
- F_SET(sp, S_INTERRUPTIBLE); \
- if (tcgetattr(STDIN_FILENO, &__term)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcgetattr"); \
- goto interrupt_err; \
- } \
- __nterm = __term; \
- __nterm.c_lflag |= ISIG; \
- if (tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &__nterm)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- goto interrupt_err; \
- } \
- __termreset = 1; \
- } \
- } \
-}
-
-#define TEAR_DOWN_INTERRUPTS { \
- if (F_ISSET(sp->gp, G_ISFROMTTY) && __isig) { \
- if (sigaction(SIGINT, &__oact, NULL)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "signal"); \
- } \
- if (__termreset && tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &__term)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- } \
- F_CLR(sp, S_INTERRUPTED); \
- if (!__istate) \
- F_CLR(sp, S_INTERRUPTIBLE); \
- } \
-}
diff --git a/usr.bin/vi/intr.c b/usr.bin/vi/intr.c
new file mode 100644
index 000000000000..512e3ae025c8
--- /dev/null
+++ b/usr.bin/vi/intr.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)intr.c 8.1 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * There's a count of how deep the interrupt level in the SCR structure
+ * has gone. Each routine that wants to be interrupted increments this
+ * level, and decrements it when it tears the interrupts down. There are
+ * two simplifying assumptions:
+ *
+ * 1: All interruptible areas want the same handler (we don't have
+ * to save/restore the old handler).
+ * 2: This is the only way to turn on interrupts (we don't have to
+ * worry about them already being turned on if the interrupt
+ * level is 0).
+ *
+ * We do it this way because interrupts have to be very fast -- if the
+ * O_REMAPMAX option is turned off, we are setting interrupts per key
+ * stroke.
+ *
+ * If an interrupt arrives, the S_INTERRUPTED bit is set in any SCR that
+ * has the S_INTERRUPTIBLE bit set. In the future this may be a problem.
+ * The user should be able to move to another screen and keep typing while
+ * another screen runs. Currently, if the user does this and the user has
+ * more than one interruptible thing running, there will be no way to know
+ * which one to stop.
+ */
+
+static void intr_def __P((int));
+
+/*
+ * intr_init --
+ * Set up a interrupts.
+ */
+int
+intr_init(sp)
+ SCR *sp;
+{
+ struct sigaction act;
+ struct termios nterm;
+
+ /* You can never interrupt sessions not using tty's. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY))
+ return (1);
+
+ /* If interrupts already set up, just increase the level. */
+ if (sp->intr_level++)
+ return (0);
+
+ /* Turn interrupts on in this screen. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ /* Install a handler. */
+ act.sa_handler = intr_def;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGINT, &act, &sp->intr_act)) {
+ msgq(sp, M_SYSERR, "sigaction");
+ goto err1;
+ }
+
+ /*
+ * Turn on interrupts. ISIG turns on VINTR, VQUIT and VSUSP. We
+ * want VINTR to interrupt, so we install a handler. VQUIT is
+ * ignored by main() because nvi never wants to catch it. A handler
+ * for VSUSP should have been installed by the screen code.
+ */
+ if (tcgetattr(STDIN_FILENO, &sp->intr_term)) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err2;
+ }
+ nterm = sp->intr_term;
+ nterm.c_lflag |= ISIG;
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &nterm)) {
+ msgq(sp, M_SYSERR, "tcsetattr");
+ /*
+ * If an error occurs, back out the changes and run
+ * without interrupts.
+ */
+err2: (void)sigaction(SIGINT, &sp->intr_act, NULL);
+err1: sp->intr_level = 0;
+ F_CLR(sp, S_INTERRUPTIBLE);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * intr_end --
+ * Tear down interrupts.
+ */
+void
+intr_end(sp)
+ SCR *sp;
+{
+ /* If not the bottom level of interrupts, just return. */
+ if (--sp->intr_level)
+ return;
+
+ /* Turn off interrupts. */
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &sp->intr_term))
+ msgq(sp, M_SYSERR, "tcsetattr");
+
+ /* Reset the signal state. */
+ if (sigaction(SIGINT, &sp->intr_act, NULL))
+ msgq(sp, M_SYSERR, "sigaction");
+
+ /* Clear interrupt bits in this screen. */
+ F_CLR(sp, S_INTERRUPTED | S_INTERRUPTIBLE);
+}
+
+/*
+ * intr_def --
+ * Default interrupt handler.
+ */
+static void
+intr_def(signo)
+ int signo;
+{
+ SCR *sp;
+
+ for (sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
+ if (F_ISSET(sp, S_INTERRUPTIBLE))
+ F_SET(sp, S_INTERRUPTED);
+}
diff --git a/usr.bin/vi/line.c b/usr.bin/vi/line.c
index a7473491cf17..1842b161dfbb 100644
--- a/usr.bin/vi/line.c
+++ b/usr.bin/vi/line.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)line.c 8.20 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)line.c 8.23 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -270,7 +280,7 @@ file_aline(sp, ep, update, lno, p, len)
* updated/scrolled as each line was entered. So, when this routine
* is called to copy the new lines from the cut buffer into the file,
* it has to know not to update the screen again.
- */
+ */
return (scr_update(sp, ep, lno, LINE_APPEND, update));
}
@@ -385,7 +395,7 @@ file_sline(sp, ep, lno, p, len)
/* Log after change. */
log_line(sp, ep, lno, LOG_LINE_RESET_F);
-
+
/* Update screen. */
return (scr_update(sp, ep, lno, LINE_RESET, 1));
}
@@ -422,18 +432,19 @@ file_lline(sp, ep, lnop)
*lnop = 0;
return (1);
case 1:
- lno = 0;
- break;
+ *lnop = 0;
+ return (0);
default:
- memmove(&lno, key.data, sizeof(lno));
break;
}
/* Fill the cache. */
+ memmove(&lno, key.data, sizeof(lno));
ep->c_nlines = ep->c_lno = lno;
ep->c_len = data.size;
ep->c_lp = data.data;
-
+
+ /* Return the value. */
*lnop = (F_ISSET(sp, S_INPUT) &&
((TEXT *)sp->tiq.cqh_last)->lno > lno ?
((TEXT *)sp->tiq.cqh_last)->lno : lno);
diff --git a/usr.bin/vi/log.c b/usr.bin/vi/log.c
index fdf959f4d8a9..07d617ef92b1 100644
--- a/usr.bin/vi/log.c
+++ b/usr.bin/vi/log.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)log.c 8.9 (Berkeley) 12/28/93";
+static char sccsid[] = "@(#)log.c 8.14 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
@@ -56,7 +66,7 @@ static char sccsid[] = "@(#)log.c 8.9 (Berkeley) 12/28/93";
* LOG_LINE_INSERT recno_t char *
* LOG_LINE_RESET_F recno_t char *
* LOG_LINE_RESET_B recno_t char *
- * LOG_MARK MARK
+ * LOG_MARK LMARK
*
* We do before image physical logging. This means that the editor layer
* MAY NOT modify records in place, even if simply deleting or overwriting
@@ -149,7 +159,7 @@ log_end(sp, ep)
ep->l_high = ep->l_cur = 1;
return (0);
}
-
+
/*
* log_cursor --
* Log the current cursor position, starting an event.
@@ -239,7 +249,7 @@ log_line(sp, ep, lno, action)
return (1);
ep->l_cursor.lno = OOBLNO;
}
-
+
/*
* Put out the changes. If it's a LOG_LINE_RESET_B call, it's a
* special case, avoid the caches. Also, if it fails and it's
@@ -311,10 +321,10 @@ log_line(sp, ep, lno, action)
* cause any other change.
*/
int
-log_mark(sp, ep, mp)
+log_mark(sp, ep, lmp)
SCR *sp;
EXF *ep;
- MARK *mp;
+ LMARK *lmp;
{
DBT data, key;
@@ -329,17 +339,21 @@ log_mark(sp, ep, mp)
}
BINC_RET(sp, ep->l_lp,
- ep->l_len, sizeof(u_char) + sizeof(MARK));
+ ep->l_len, sizeof(u_char) + sizeof(LMARK));
ep->l_lp[0] = LOG_MARK;
- memmove(ep->l_lp + sizeof(u_char), mp, sizeof(MARK));
+ memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
key.data = &ep->l_cur;
key.size = sizeof(recno_t);
data.data = ep->l_lp;
- data.size = sizeof(u_char) + sizeof(MARK);
+ data.size = sizeof(u_char) + sizeof(LMARK);
if (ep->log->put(ep->log, &key, &data, 0) == -1)
LOG_ERR;
+#if defined(DEBUG) && 0
+ TRACE(sp, "%lu: mark %c: %lu/%u\n",
+ ep->l_cur, lmp->name, lmp->lno, lmp->cno);
+#endif
/* Reset high water mark. */
ep->l_high = ++ep->l_cur;
return (0);
@@ -356,6 +370,7 @@ log_backward(sp, ep, rp)
MARK *rp;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
int didop;
@@ -423,8 +438,10 @@ log_backward(sp, ep, rp)
break;
case LOG_MARK:
didop = 1;
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -452,6 +469,7 @@ log_setline(sp, ep)
EXF *ep;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
u_char *p;
@@ -507,8 +525,10 @@ log_setline(sp, ep)
goto err;
++sp->rptlines[L_CHANGED];
case LOG_MARK:
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -531,6 +551,7 @@ log_forward(sp, ep, rp)
MARK *rp;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
int didop;
@@ -599,8 +620,10 @@ log_forward(sp, ep, rp)
break;
case LOG_MARK:
didop = 1;
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -620,6 +643,7 @@ log_trace(sp, msg, rno, p)
recno_t rno;
u_char *p;
{
+ LMARK lm;
MARK m;
recno_t lno;
@@ -653,8 +677,9 @@ log_trace(sp, msg, rno, p)
TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
break;
case LOG_MARK:
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- TRACE(sp, "%lu: %s: MARK: %u/%u\n", rno, msg, m.lno, m.cno);
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ TRACE(sp,
+ "%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
break;
default:
abort();
diff --git a/usr.bin/vi/log.h b/usr.bin/vi/log.h
index 840cf8532c0c..2974df4d14b6 100644
--- a/usr.bin/vi/log.h
+++ b/usr.bin/vi/log.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)log.h 8.3 (Berkeley) 12/28/93
+ * @(#)log.h 8.5 (Berkeley) 3/16/94
*/
#define LOG_NOTYPE 0
@@ -49,5 +49,5 @@ int log_end __P((SCR *, EXF *));
int log_forward __P((SCR *, EXF *, MARK *));
int log_init __P((SCR *, EXF *));
int log_line __P((SCR *, EXF *, recno_t, u_int));
-int log_mark __P((SCR *, EXF *, MARK *));
+int log_mark __P((SCR *, EXF *, LMARK *));
int log_setline __P((SCR *, EXF *));
diff --git a/usr.bin/vi/main.c b/usr.bin/vi/main.c
index 3413a475ddf8..cb74a051d460 100644
--- a/usr.bin/vi/main.c
+++ b/usr.bin/vi/main.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,16 +38,22 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 8.65 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)main.c 8.76 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
@@ -59,12 +65,17 @@ static char sccsid[] = "@(#)main.c 8.65 (Berkeley) 1/23/94";
#include <varargs.h>
#endif
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
#include "tag.h"
-static int exrc_isok __P((SCR *, char *, int));
+enum rc { NOEXIST, NOPERM, OK };
+
+static enum rc exrc_isok __P((SCR *, struct stat *, char *, int));
static void gs_end __P((GS *));
static GS *gs_init __P((void));
static void h_hup __P((int));
@@ -84,6 +95,7 @@ main(argc, argv)
extern char *optarg;
static int reenter; /* STATIC: Re-entrancy check. */
struct sigaction act;
+ struct stat hsb, lsb;
GS *gp;
FREF *frp;
SCR *sp;
@@ -196,7 +208,7 @@ main(argc, argv)
/* Build and initialize the GS structure. */
__global_list = gp = gs_init();
-
+
if (snapshot)
F_SET(gp, G_SNAPSHOT);
@@ -263,8 +275,8 @@ main(argc, argv)
#endif
/*
- * Source the system, environment, ~user and local .exrc values.
- * Vi historically didn't check ~user/.exrc if the environment
+ * Source the system, environment, $HOME and local .exrc values.
+ * Vi historically didn't check $HOME/.exrc if the environment
* variable EXINIT was set. This is all done before the file is
* read in because things in the .exrc information can set, for
* example, the recovery directory.
@@ -273,52 +285,75 @@ main(argc, argv)
* While nvi can handle any of the options settings of historic vi,
* the converse is not true. Since users are going to have to have
* files and environmental variables that work with both, we use nvi
- * versions if they exist, otherwise the historic ones.
+ * versions of both the $HOME and local startup files if they exist,
+ * otherwise the historic ones.
+ *
+ * !!!
+ * According to O'Reilly ("Learning the VI Editor", Fifth Ed., May
+ * 1992, page 106), System V release 3.2 and later, has an option
+ * "[no]exrc", causing vi to not "read .exrc files in the current
+ * directory unless the exrc option in the home directory's .exrc
+ * file" was set. The problem that this (hopefully) solves is that
+ * on System V you can give away files, so there's no possible test
+ * we can make to determine that the file is safe.
+ *
+ * We initialize the exrc variable to off. If it's explicitly turned
+ * off by the user, then we never read the local .exrc file. If the
+ * user didn't initialize it or initialized it to on, we make all of
+ * the standard checks of the file before reading it.
+ *
+ * !!!
+ * If the user started the historic of vi in $HOME, vi read the user's
+ * .exrc file twice, as $HOME/.exrc and as ./.exrc. We don't since
+ * it's going to make some commands behave oddly, and I can't imagine
+ * anyone depending on it.
*/
if (!silent) {
- if (exrc_isok(sp, _PATH_SYSEXRC, 1))
+ switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1)) {
+ case NOEXIST:
+ case NOPERM:
+ break;
+ case OK:
(void)ex_cfile(sp, NULL, _PATH_SYSEXRC);
+ break;
+ }
- /* Source the {N,}EXINIT environment variable. */
- if ((p = getenv("NEXINIT")) != NULL ||
- (p = getenv("EXINIT")) != NULL)
+ if ((p = getenv("EXINIT")) != NULL)
if ((p = strdup(p)) == NULL) {
msgq(sp, M_SYSERR, NULL);
goto err;
} else {
+ F_SET(sp, S_VLITONLY);
(void)ex_icmd(sp, NULL, p, strlen(p));
+ F_CLR(sp, S_VLITONLY);
free(p);
}
else if ((p = getenv("HOME")) != NULL && *p) {
(void)snprintf(path,
- sizeof(path), "%s/%s", p, _PATH_NEXRC);
- if (exrc_isok(sp, path, 0))
+ sizeof(path), "%s/%s", p, _PATH_EXRC);
+ switch (exrc_isok(sp, &hsb, path, 0)) {
+ case NOEXIST:
+ break;
+ case NOPERM:
+ break;
+ case OK:
(void)ex_cfile(sp, NULL, path);
- else {
- (void)snprintf(path,
- sizeof(path), "%s/%s", p, _PATH_EXRC);
- if (exrc_isok(sp, path, 0))
- (void)ex_cfile(sp, NULL, path);
+ break;
}
}
- /*
- * !!!
- * According to O'Reilly ("Learning the VI Editor", Fifth Ed.,
- * May 1992, page 106), System V release 3.2 and later, has an
- * option "[no]exrc", causing vi to not "read .exrc files in
- * the current directory unless you first set the exrc option
- * in your home directory's .exrc file". Yeah, right. Did
- * someone actually believe that users would change their home
- * .exrc file based on whether or not they wanted to source the
- * current local .exrc? Or that users would want ALL the local
- * .exrc files on some systems, and none of them on others?
- * I think not.
- *
- * Apply the same tests to local .exrc files that are applied
- * to any other .exrc file.
- */
- if (exrc_isok(sp, _PATH_EXRC, 0))
- (void)ex_cfile(sp, NULL, _PATH_EXRC);
+
+ if (!F_ISSET(&sp->opts[O_EXRC], OPT_SET) || O_ISSET(sp, O_EXRC))
+ switch (exrc_isok(sp, &lsb, _PATH_EXRC, 0)) {
+ case NOEXIST:
+ break;
+ case NOPERM:
+ break;
+ case OK:
+ if (lsb.st_dev != hsb.st_dev ||
+ lsb.st_ino != hsb.st_ino)
+ (void)ex_cfile(sp, NULL, _PATH_EXRC);
+ break;
+ }
}
/* List recovery files if -l specified. */
@@ -358,9 +393,20 @@ main(argc, argv)
* would be nice in some cases to restart system calls, but SA_RESTART
* is a 4BSD extension so we can't use it.
*
- * SIGWINCH, SIGHUP, SIGTERM:
+ * SIGALRM:
+ * Walk structures and call handling routines.
+ * SIGHUP, SIGTERM, SIGWINCH:
* Catch and set a global bit.
+ * SIGQUIT:
+ * Always ignore.
*/
+ act.sa_handler = h_alrm;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGALRM, &act, NULL)) {
+ msgq(sp, M_SYSERR, "timer: sigaction");
+ goto err;
+ }
act.sa_handler = h_hup;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
@@ -373,11 +419,6 @@ main(argc, argv)
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
(void)sigaction(SIGWINCH, &act, NULL);
-
- /*
- * SIGQUIT:
- * Always ignore.
- */
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
@@ -400,9 +441,9 @@ main(argc, argv)
if (term_push(sp, ":", 1, 0, 0))
goto err;
}
-
+
/* Vi reads from the terminal. */
- if (!F_ISSET(gp, G_ISFROMTTY) && !F_ISSET(sp, S_EX)) {
+ if (!F_ISSET(gp, G_STDIN_TTY) && !F_ISSET(sp, S_EX)) {
msgq(sp, M_ERR, "Vi's standard input must be a terminal.");
goto err;
}
@@ -472,7 +513,7 @@ err: eval = 1;
* other systems mess up characters typed after the quit command to
* vi but before vi actually exits.
*/
- if (F_ISSET(gp, G_ISFROMTTY))
+ if (F_ISSET(gp, G_TERMIOS_SET))
(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &gp->original_termios);
exit(eval);
}
@@ -505,26 +546,27 @@ gs_init()
/* Set a flag if we're reading from the tty. */
if (isatty(STDIN_FILENO))
- F_SET(gp, G_ISFROMTTY);
+ F_SET(gp, G_STDIN_TTY);
/*
- * XXX
- * Set a flag and don't do terminal sets/resets if the input isn't
- * from a tty. Under all circumstances put reasonable things into
- * the original_termios field, as some routines (seq.c:seq_save()
- * and term.c:term_init()) want values for special characters.
+ * Set the G_STDIN_TTY flag. It's purpose is to avoid setting and
+ * resetting the tty if the input isn't from there.
+ *
+ * Set the G_TERMIOS_SET flag. It's purpose is to avoid using the
+ * original_termios information (mostly special character values)
+ * if it's not valid. We expect that if we've lost our controlling
+ * terminal that the open() (but not the tcgetattr()) will fail.
*/
- if (F_ISSET(gp, G_ISFROMTTY)) {
- if (tcgetattr(STDIN_FILENO, &gp->original_termios))
+ if (F_ISSET(gp, G_STDIN_TTY)) {
+ if (tcgetattr(STDIN_FILENO, &gp->original_termios) == -1)
err(1, "tcgetattr");
- } else {
- if ((fd = open(_PATH_TTY, O_RDONLY, 0)) == -1)
- err(1, "%s", _PATH_TTY);
- if (tcgetattr(fd, &gp->original_termios))
+ F_SET(gp, G_TERMIOS_SET);
+ } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
+ if (tcgetattr(fd, &gp->original_termios) == -1)
err(1, "tcgetattr");
+ F_SET(gp, G_TERMIOS_SET);
(void)close(fd);
}
-
return (gp);
}
@@ -556,16 +598,16 @@ gs_end(gp)
for (sp = __global_list->dq.cqh_first;
sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
for (mp = sp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
for (sp = __global_list->hq.cqh_first;
sp != (void *)&__global_list->hq; sp = sp->q.cqe_next)
for (mp = sp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
/* Flush messages on the global queue. */
for (mp = gp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
if (gp->special_key != NULL)
@@ -632,19 +674,19 @@ h_winch(signo)
* exrc_isok --
* Check a .exrc for source-ability.
*/
-static int
-exrc_isok(sp, path, rootok)
+static enum rc
+exrc_isok(sp, sbp, path, rootok)
SCR *sp;
+ struct stat *sbp;
char *path;
int rootok;
{
- struct stat sb;
uid_t uid;
char *emsg, buf[MAXPATHLEN];
/* Check for the file's existence. */
- if (stat(path, &sb))
- return (0);
+ if (stat(path, sbp))
+ return (NOEXIST);
/*
* !!!
@@ -658,29 +700,29 @@ exrc_isok(sp, path, rootok)
/* Owned by the user or root. */
uid = getuid();
if (rootok) {
- if (sb.st_uid != uid && sb.st_uid != 0) {
+ if (sbp->st_uid != uid && sbp->st_uid != 0) {
emsg = "not owned by you or root";
- goto err;
+ goto denied;
}
} else
- if (sb.st_uid != uid) {
+ if (sbp->st_uid != uid) {
emsg = "not owned by you";
- goto err;
+ goto denied;
}
/* Not writeable by anyone but the owner. */
- if (sb.st_mode & (S_IWGRP | S_IWOTH)) {
+ if (sbp->st_mode & (S_IWGRP | S_IWOTH)) {
emsg = "writeable by a user other than the owner";
-err: if (strchr(path, '/') == NULL &&
+denied: if (strchr(path, '/') == NULL &&
getcwd(buf, sizeof(buf)) != NULL)
msgq(sp, M_ERR,
"%s/%s: not sourced: %s.", buf, path, emsg);
else
msgq(sp, M_ERR,
"%s: not sourced: %s.", path, emsg);
- return (0);
+ return (NOPERM);
}
- return (1);
+ return (OK);
}
static void
@@ -688,7 +730,7 @@ obsolete(argv)
char *argv[];
{
size_t len;
- char *p, *myname;
+ char *p;
/*
* Translate old style arguments into something getopt will like.
@@ -699,7 +741,7 @@ obsolete(argv)
* Change "-" into "-s"
* Change "-r" into "-l"
*/
- for (myname = argv[0]; *++argv;)
+ while (*++argv)
if (argv[0][0] == '+') {
if (argv[0][1] == '\0') {
MALLOC_NOMSG(NULL, argv[0], char *, 4);
diff --git a/usr.bin/vi/mark.c b/usr.bin/vi/mark.c
index c510a22002fc..26c02afb4226 100644
--- a/usr.bin/vi/mark.c
+++ b/usr.bin/vi/mark.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)mark.c 8.12 (Berkeley) 12/27/93";
+static char sccsid[] = "@(#)mark.c 8.17 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
-static MARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
+static LMARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
/*
* Marks are maintained in a key sorted doubly linked list. We can't
@@ -69,7 +79,7 @@ static MARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
* deleted, we delete (and log) any marks on that line. An undo will create
* the mark. Any mark creations are noted as to whether the user created
* it or if it was created by an undo. The former cannot be reset by another
- * undo, but the latter may.
+ * undo, but the latter may.
*
* All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
* the absolute mark locations sets both, so that "m'" and "m`" work like
@@ -85,18 +95,18 @@ mark_init(sp, ep)
SCR *sp;
EXF *ep;
{
- MARK *mp;
+ LMARK *lmp;
/*
* Make sure the marks have been set up. If they
* haven't, do so, and create the absolute mark.
*/
- MALLOC_RET(sp, mp, MARK *, sizeof(MARK));
- mp->lno = 1;
- mp->cno = 0;
- mp->name = ABSMARK1;
- mp->flags = 0;
- LIST_INSERT_HEAD(&ep->marks, mp, q);
+ MALLOC_RET(sp, lmp, LMARK *, sizeof(LMARK));
+ lmp->lno = 1;
+ lmp->cno = 0;
+ lmp->name = ABSMARK1;
+ lmp->flags = 0;
+ LIST_INSERT_HEAD(&ep->marks, lmp, q);
return (0);
}
@@ -109,11 +119,11 @@ mark_end(sp, ep)
SCR *sp;
EXF *ep;
{
- MARK *mp;
+ LMARK *lmp;
- while ((mp = ep->marks.lh_first) != NULL) {
- LIST_REMOVE(mp, q);
- FREE(mp, sizeof(MARK));
+ while ((lmp = ep->marks.lh_first) != NULL) {
+ LIST_REMOVE(lmp, q);
+ FREE(lmp, sizeof(LMARK));
}
return (0);
}
@@ -122,36 +132,38 @@ mark_end(sp, ep)
* mark_get --
* Get the location referenced by a mark.
*/
-MARK *
-mark_get(sp, ep, key)
+int
+mark_get(sp, ep, key, mp)
SCR *sp;
EXF *ep;
ARG_CHAR_T key;
-{
MARK *mp;
+{
+ LMARK *lmp;
size_t len;
- char *p;
if (key == ABSMARK2)
key = ABSMARK1;
- mp = mark_find(sp, ep, key);
- if (mp == NULL || mp->name != key) {
+ lmp = mark_find(sp, ep, key);
+ if (lmp == NULL || lmp->name != key) {
msgq(sp, M_BERR, "Mark %s: not set.", charname(sp, key));
- return (NULL);
+ return (1);
}
- if (F_ISSET(mp, MARK_DELETED)) {
+ if (F_ISSET(lmp, MARK_DELETED)) {
msgq(sp, M_BERR,
"Mark %s: the line was deleted.", charname(sp, key));
- return (NULL);
+ return (1);
}
- if ((p = file_gline(sp, ep, mp->lno, &len)) == NULL ||
- mp->cno > len || mp->cno == len && len != 0) {
+ if (file_gline(sp, ep, lmp->lno, &len) == NULL ||
+ lmp->cno > len || lmp->cno == len && len != 0) {
msgq(sp, M_BERR, "Mark %s: cursor position no longer exists.",
charname(sp, key));
- return (NULL);
+ return (1);
}
- return (mp);
+ mp->lno = lmp->lno;
+ mp->cno = lmp->cno;
+ return (0);
}
/*
@@ -166,7 +178,7 @@ mark_set(sp, ep, key, value, userset)
MARK *value;
int userset;
{
- MARK *mp, *mt;
+ LMARK *lmp, *lmt;
if (key == ABSMARK2)
key = ABSMARK1;
@@ -177,22 +189,22 @@ mark_set(sp, ep, key, value, userset)
* an undo, and we set it if it's not already set or if it was set
* by a previous undo.
*/
- mp = mark_find(sp, ep, key);
- if (mp == NULL || mp->name != key) {
- MALLOC_RET(sp, mt, MARK *, sizeof(MARK));
- if (mp == NULL) {
- LIST_INSERT_HEAD(&ep->marks, mt, q);
+ lmp = mark_find(sp, ep, key);
+ if (lmp == NULL || lmp->name != key) {
+ MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK));
+ if (lmp == NULL) {
+ LIST_INSERT_HEAD(&ep->marks, lmt, q);
} else
- LIST_INSERT_AFTER(mp, mt, q);
- mp = mt;
+ LIST_INSERT_AFTER(lmp, lmt, q);
+ lmp = lmt;
} else if (!userset &&
- !F_ISSET(mp, MARK_DELETED) && F_ISSET(mp, MARK_USERSET))
+ !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET))
return (0);
- mp->lno = value->lno;
- mp->cno = value->cno;
- mp->name = key;
- mp->flags = userset ? MARK_USERSET : 0;
+ lmp->lno = value->lno;
+ lmp->cno = value->cno;
+ lmp->name = key;
+ lmp->flags = userset ? MARK_USERSET : 0;
return (0);
}
@@ -201,23 +213,23 @@ mark_set(sp, ep, key, value, userset)
* Find the requested mark, or, the slot immediately before
* where it would go.
*/
-static MARK *
+static LMARK *
mark_find(sp, ep, key)
SCR *sp;
EXF *ep;
ARG_CHAR_T key;
{
- MARK *mp, *lastmp;
+ LMARK *lmp, *lastlmp;
/*
* Return the requested mark or the slot immediately before
* where it should go.
*/
- for (lastmp = NULL, mp = ep->marks.lh_first;
- mp != NULL; lastmp = mp, mp = mp->q.le_next)
- if (mp->name >= key)
- return (mp->name == key ? mp : lastmp);
- return (lastmp);
+ for (lastlmp = NULL, lmp = ep->marks.lh_first;
+ lmp != NULL; lastlmp = lmp, lmp = lmp->q.le_next)
+ if (lmp->name >= key)
+ return (lmp->name == key ? lmp : lastlmp);
+ return (lastlmp);
}
/*
@@ -231,24 +243,26 @@ mark_insdel(sp, ep, op, lno)
enum operation op;
recno_t lno;
{
- MARK *mp;
+ LMARK *lmp;
switch (op) {
case LINE_APPEND:
return;
case LINE_DELETE:
- for (mp = ep->marks.lh_first; mp != NULL; mp = mp->q.le_next)
- if (mp->lno >= lno)
- if (mp->lno == lno) {
- F_SET(mp, MARK_DELETED);
- (void)log_mark(sp, ep, mp);
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->lno >= lno)
+ if (lmp->lno == lno) {
+ F_SET(lmp, MARK_DELETED);
+ (void)log_mark(sp, ep, lmp);
} else
- --mp->lno;
+ --lmp->lno;
return;
case LINE_INSERT:
- for (mp = ep->marks.lh_first; mp != NULL; mp = mp->q.le_next)
- if (mp->lno >= lno)
- ++mp->lno;
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->lno >= lno)
+ ++lmp->lno;
return;
case LINE_RESET:
return;
diff --git a/usr.bin/vi/mark.h b/usr.bin/vi/mark.h
index 9c28151314b9..04b445298a7e 100644
--- a/usr.bin/vi/mark.h
+++ b/usr.bin/vi/mark.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,22 +30,31 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)mark.h 8.5 (Berkeley) 12/27/93
+ * @(#)mark.h 8.8 (Berkeley) 3/16/94
*/
/*
- * The MARK structure defines a position in the file. Because of the different
- * interfaces used by the db(3) package, curses, and users, the line number is
- * 1 based, while the column number is 0 based. Additionally, it is known that
- * the out-of-band line number is less than any legal line number. The line
- * number is of type recno_t, as that's the underlying type of the database.
- * The column number is of type size_t, guaranteeing that we can malloc a line.
+ * The MARK and LMARK structures define positions in the file. There are
+ * two structures because the mark subroutines are the only places where
+ * anything cares about something other than line and column.
+ *
+ * Because of the different interfaces used by the db(3) package, curses,
+ * and users, the line number is 1 based and the column number is 0 based.
+ * Additionally, it is known that the out-of-band line number is less than
+ * any legal line number. The line number is of type recno_t, as that's
+ * the underlying type of the database. The column number is of type size_t,
+ * guaranteeing that we can malloc a line.
*/
struct _mark {
- LIST_ENTRY(_mark) q; /* Linked list of marks. */
#define OOBLNO 0 /* Out-of-band line number. */
recno_t lno; /* Line number. */
size_t cno; /* Column number. */
+};
+
+struct _lmark {
+ LIST_ENTRY(_lmark) q; /* Linked list of marks. */
+ recno_t lno; /* Line number. */
+ size_t cno; /* Column number. */
CHAR_T name; /* Mark name. */
#define MARK_DELETED 0x01 /* Mark was deleted. */
@@ -57,8 +66,8 @@ struct _mark {
#define ABSMARK2 '`' /* Absolute mark name. */
/* Mark routines. */
-int mark_end __P((SCR *, EXF *));
-MARK *mark_get __P((SCR *, EXF *, ARG_CHAR_T));
-int mark_init __P((SCR *, EXF *));
-void mark_insdel __P((SCR *, EXF *, enum operation, recno_t));
-int mark_set __P((SCR *, EXF *, ARG_CHAR_T, MARK *, int));
+int mark_end __P((SCR *, EXF *));
+int mark_get __P((SCR *, EXF *, ARG_CHAR_T, MARK *));
+int mark_init __P((SCR *, EXF *));
+void mark_insdel __P((SCR *, EXF *, enum operation, recno_t));
+int mark_set __P((SCR *, EXF *, ARG_CHAR_T, MARK *, int));
diff --git a/usr.bin/vi/mem.h b/usr.bin/vi/mem.h
index 0f8fac4b8f39..f604cbd0aeed 100644
--- a/usr.bin/vi/mem.h
+++ b/usr.bin/vi/mem.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)mem.h 8.2 (Berkeley) 12/19/93
+ * @(#)mem.h 8.5 (Berkeley) 3/16/94
*/
/* Increase the size of a malloc'd buffer. Two versions, one that
@@ -163,4 +163,11 @@
msgq(sp, M_SYSERR, NULL); \
}
+/*
+ * Versions of memmove(3) and memset(3) that use the size of the
+ * initial pointer to figure out how much memory to manipulate.
+ */
+#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p)))
+#define MEMSET(p, value, len) memset(p, value, (len) * sizeof(*(p)))
+
int binc __P((SCR *, void *, size_t *, size_t));
diff --git a/usr.bin/vi/msg.h b/usr.bin/vi/msg.h
index 6b20bb4bb63b..15eaf356ef4f 100644
--- a/usr.bin/vi/msg.h
+++ b/usr.bin/vi/msg.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,21 +30,23 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)msg.h 8.8 (Berkeley) 11/18/93
+ * @(#)msg.h 8.10 (Berkeley) 3/16/94
*/
/*
- * M_BERR -- Error: ring a bell if O_VERBOSE not set, else
- * display in inverse video.
- * M_ERR -- Error: display in inverse video.
- * M_INFO -- Info: display in normal video.
- * M_SYSERR -- M_ERR, but use standard error message.
- * M_VINFO -- Info: display only if O_VERBOSE set.
+ * Message types.
*
- * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the
- * error messages shorter. In this version, O_TERSE has no effect
- * and O_VERBOSE results in informational displays about common
- * errors.
+ * !!!
+ * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the error
+ * messages shorter. In this implementation, O_TERSE has no effect and
+ * O_VERBOSE results in informational displays about common errors for
+ * naive users.
+ *
+ * M_BERR Error: M_ERR if O_VERBOSE, else bell.
+ * M_ERR Error: Display in inverse video.
+ * M_INFO Info: Display in normal video.
+ * M_SYSERR Error: M_ERR, using strerror(3) message.
+ * M_VINFO Info: M_INFO if O_VERBOSE, else ignore.
*/
enum msgtype { M_BERR, M_ERR, M_INFO, M_SYSERR, M_VINFO };
diff --git a/usr.bin/vi/nex/ex.c b/usr.bin/vi/nex/ex.c
deleted file mode 100644
index 3f5beac4a734..000000000000
--- a/usr.bin/vi/nex/ex.c
+++ /dev/null
@@ -1,1523 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex.c 8.90 (Berkeley) 1/23/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-static inline EXCMDLIST const *
- ex_comm_search __P((char *, size_t));
-static int ep_line __P((SCR *, EXF *, MARK *, char **, size_t *, int *));
-static int ep_range __P((SCR *, EXF *, EXCMDARG *, char **, size_t *));
-
-#define DEFCOM ".+1"
-
-/*
- * ex --
- * Read an ex command and execute it.
- */
-int
-ex(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- TEXT *tp;
- u_int saved_mode;
- int eval;
- char defcom[sizeof(DEFCOM)];
-
- if (ex_init(sp, ep))
- return (1);
-
- if (sp->s_refresh(sp, ep))
- return (ex_end(sp));
-
- /* If reading from a file, messages should have line info. */
- if (!F_ISSET(sp->gp, G_ISFROMTTY)) {
- sp->if_lno = 1;
- sp->if_name = strdup("input");
- }
- for (eval = 0;; ++sp->if_lno) {
- /* Get the next command. */
- switch (sp->s_get(sp, ep, &sp->tiq, ':', TXT_CR | TXT_PROMPT)) {
- case INP_OK:
- break;
- case INP_EOF:
- F_SET(sp, S_EXIT_FORCE);
- goto ret;
- case INP_ERR:
- continue;
- }
-
- saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
- tp = sp->tiq.cqh_first;
- if (tp->len == 0) {
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
- (void)fputc('\r', stdout);
- (void)fflush(stdout);
- }
- memmove(defcom, DEFCOM, sizeof(DEFCOM));
- (void)ex_icmd(sp, ep, defcom, sizeof(DEFCOM) - 1);
- } else {
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- (void)fputc('\n', stdout);
- (void)ex_icmd(sp, ep, tp->lb, tp->len);
- }
- (void)msg_rpt(sp, 0);
-
- if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
- break;
-
- if (sp->s_refresh(sp, ep)) {
- eval = 1;
- break;
- }
- }
-ret: if (sp->if_name != NULL) {
- FREE(sp->if_name, strlen(sp->if_name) + 1);
- sp->if_name = NULL;
- }
- return (ex_end(sp) || eval);
-}
-
-/*
- * ex_cfile --
- * Execute ex commands from a file.
- */
-int
-ex_cfile(sp, ep, filename)
- SCR *sp;
- EXF *ep;
- char *filename;
-{
- struct stat sb;
- int fd, len, rval;
- char *bp;
-
- bp = NULL;
- if ((fd = open(filename, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
- goto err;
-
- /*
- * XXX
- * We'd like to test if the file is too big to malloc. Since we don't
- * know what size or type off_t's or size_t's are, what the largest
- * unsigned integral type is, or what random insanity the local C
- * compiler will perpetrate, doing the comparison in a portable way
- * is flatly impossible. Hope that malloc fails if the file is too
- * large.
- */
- MALLOC(sp, bp, char *, (size_t)sb.st_size + 1);
- if (bp == NULL)
- goto err;
-
- len = read(fd, bp, (int)sb.st_size);
- if (len == -1 || len != sb.st_size) {
- if (len != sb.st_size)
- errno = EIO;
-err: rval = 1;
- msgq(sp, M_SYSERR, filename);
- } else {
- bp[sb.st_size] = '\0'; /* XXX */
-
- /* Run the command. Messages include file/line information. */
- sp->if_lno = 1;
- sp->if_name = strdup(filename);
- rval = ex_icmd(sp, ep, bp, len);
- FREE(sp->if_name, strlen(sp->if_name) + 1);
- sp->if_name = NULL;
- }
-
- /*
- * !!!
- * THE UNDERLYING EXF MAY HAVE CHANGED.
- */
- if (bp != NULL)
- FREE(bp, sb.st_size);
- if (fd >= 0)
- (void)close(fd);
- return (rval);
-}
-
-/*
- * ex_icmd --
- * Call ex_cmd() after turning off interruptible bits.
- */
-int
-ex_icmd(sp, ep, cmd, len)
- SCR *sp;
- EXF *ep;
- char *cmd;
- size_t len;
-{
- /*
- * Ex goes through here for each vi :colon command and for each ex
- * command, however, globally executed commands don't go through
- * here, instead, they call ex_cmd directly. So, reset all of the
- * interruptible flags now.
- */
- F_CLR(sp, S_INTERRUPTED | S_INTERRUPTIBLE);
-
- return (ex_cmd(sp, ep, cmd, len));
-}
-
-/* Special command structure for :s as a repeat substitution command. */
-static EXCMDLIST const cmd_subagain =
- {"s", ex_subagain, E_ADDR2|E_NORC,
- "s",
- "[line [,line]] s [cgr] [count] [#lp]",
- "repeat the last subsitution"};
-
-/*
- * ex_cmd --
- * Parse and execute a string containing ex commands.
- */
-int
-ex_cmd(sp, ep, cmd, cmdlen)
- SCR *sp;
- EXF *ep;
- char *cmd;
- size_t cmdlen;
-{
- CHAR_T vlit;
- EX_PRIVATE *exp;
- EXCMDARG exc;
- EXCMDLIST const *cp;
- MARK cur;
- recno_t lno, num;
- size_t arg1_len, len, save_cmdlen;
- long flagoff;
- u_int saved_mode;
- int ch, cnt, delim, flags, namelen, nl, uselastcmd, tmp;
- char *arg1, *save_cmd, *p, *t;
-
- /* Init. */
- nl = 0;
-loop: if (nl) {
- nl = 0;
- ++sp->if_lno;
- }
- arg1 = NULL;
- save_cmdlen = 0;
-
- /*
- * It's possible that we've been interrupted during a
- * command.
- */
- if (F_ISSET(sp, S_INTERRUPTED))
- return (0);
-
- /* Skip whitespace, separators, newlines. */
- for (; cmdlen > 0; ++cmd, --cmdlen)
- if ((ch = *cmd) == '\n')
- ++sp->if_lno;
- else if (!isblank(ch))
- break;
- if (cmdlen == 0)
- return (0);
-
- /* Command lines that start with a double-quote are comments. */
- if (ch == '"') {
- while (--cmdlen > 0 && *++cmd != '\n');
- if (*cmd == '\n') {
- ++cmd;
- --cmdlen;
- ++sp->if_lno;
- }
- goto loop;
- }
-
- /*
- * !!!
- * Permit extra colons at the start of the line. Historically,
- * ex/vi allowed a single extra one. It's simpler not to count.
- * The stripping is done here because, historically, any command
- * could have preceding colons, e.g. ":g/pattern/:p" worked.
- */
- if (ch == ':')
- while (--cmdlen > 0 && *++cmd == ':');
-
- /* Skip whitespace. */
- for (; cmdlen > 0; ++cmd, --cmdlen) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
-
- /* The last point at which an empty line means do nothing. */
- if (cmdlen == 0)
- return (0);
-
- /* Initialize the structure passed to underlying functions. */
- memset(&exc, 0, sizeof(EXCMDARG));
- exp = EXP(sp);
- if (argv_init(sp, ep, &exc))
- goto err;
-
- /* Parse command addresses. */
- if (ep_range(sp, ep, &exc, &cmd, &cmdlen))
- goto err;
-
- /* Skip whitespace. */
- for (; cmdlen > 0; ++cmd, --cmdlen) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
-
- /*
- * If no command, ex does the last specified of p, l, or #, and vi
- * moves to the line. Otherwise, determine the length of the command
- * name by looking for the first non-alphabetic character. (There
- * are a few non-alphabetic characters in command names, but they're
- * all single character commands.) This isn't a great test, because
- * it means that, for the command ":e +cut.c file", we'll report that
- * the command "cut" wasn't known. However, it makes ":e+35 file" work
- * correctly.
- */
-#define SINGLE_CHAR_COMMANDS "!#&<=>@~"
- if (cmdlen != 0 && cmd[0] != '|' && cmd[0] != '\n') {
- if (strchr(SINGLE_CHAR_COMMANDS, *cmd)) {
- p = cmd;
- ++cmd;
- --cmdlen;
- namelen = 1;
- } else {
- for (p = cmd; cmdlen > 0; --cmdlen, ++cmd)
- if (!isalpha(*cmd))
- break;
- if ((namelen = cmd - p) == 0) {
- msgq(sp, M_ERR, "Unknown command name.");
- goto err;
- }
- }
-
- /*
- * Search the table for the command.
- *
- * !!!
- * Historic vi permitted the mark to immediately follow the
- * 'k' in the 'k' command. Make it work.
- *
- * !!!
- * Historic vi permitted pretty much anything to follow the
- * substitute command, e.g. "s/e/E/|s|sgc3p" was fine. Make
- * it work.
- *
- * Use of msgq below is safe, command names are all alphabetics.
- */
- if ((cp = ex_comm_search(p, namelen)) == NULL)
- if (p[0] == 'k' && p[1] && !p[2]) {
- cmd -= namelen - 1;
- cmdlen += namelen - 1;
- cp = &cmds[C_K];
- } else if (p[0] == 's') {
- cmd -= namelen - 1;
- cmdlen += namelen - 1;
- cp = &cmd_subagain;
- } else {
- msgq(sp, M_ERR,
- "The %.*s command is unknown.", namelen, p);
- goto err;
- }
-
- /* Some commands are either not implemented or turned off. */
- if (F_ISSET(cp, E_NOPERM)) {
- msgq(sp, M_ERR,
- "The %s command is not currently supported.",
- cp->name);
- goto err;
- }
-
- /* Some commands aren't okay in globals. */
- if (F_ISSET(sp, S_GLOBAL) && F_ISSET(cp, E_NOGLOBAL)) {
- msgq(sp, M_ERR,
- "The %s command can't be used as part of a global command.",
- cp->name);
- goto err;
- }
-
- /*
- * Multiple < and > characters; another "feature". Note,
- * The string passed to the underlying function may not be
- * nul terminated in this case.
- */
- if ((cp == &cmds[C_SHIFTL] && *p == '<') ||
- (cp == &cmds[C_SHIFTR] && *p == '>')) {
- for (ch = *p; cmdlen > 0; --cmdlen, ++cmd)
- if (*cmd != ch)
- break;
- if (argv_exp0(sp, ep, &exc, p, cmd - p))
- goto err;
- }
-
- /*
- * The visual command has a different syntax when called
- * from ex than when called from a vi colon command. FMH.
- */
- if (cp == &cmds[C_VISUAL_EX] && IN_VI_MODE(sp))
- cp = &cmds[C_VISUAL_VI];
-
- uselastcmd = 0;
- } else {
- cp = exp->lastcmd;
- uselastcmd = 1;
- }
-
- /* Initialize local flags to the command flags. */
- LF_INIT(cp->flags);
-
- /*
- * File state must be checked throughout this code, because it is
- * called when reading the .exrc file and similar things. There's
- * this little chicken and egg problem -- if we read the file first,
- * we won't know how to display it. If we read/set the exrc stuff
- * first, we can't allow any command that requires file state.
- * Historic vi generally took the easy way out and dropped core.
- */
- if (LF_ISSET(E_NORC) && ep == NULL) {
- msgq(sp, M_ERR,
- "The %s command requires that a file already have been read in.",
- cp->name);
- goto err;
- }
-
- /*
- * There are three normal termination cases for an ex command. They
- * are the end of the string (cmdlen), or unescaped (by literal next
- * characters) newline or '|' characters. As we're past any addresses,
- * we can now determine how long the command is, so we don't have to
- * look for all the possible terminations. There are three exciting
- * special cases:
- *
- * 1: The bang, global, vglobal and the filter versions of the read and
- * write commands are delimited by newlines (they can contain shell
- * pipes).
- * 2: The ex, edit and visual in vi mode commands take ex commands as
- * their first arguments.
- * 3: The substitute command takes an RE as its first argument, and
- * wants it to be specially delimited.
- *
- * Historically, '|' characters in the first argument of the ex, edit,
- * and substitute commands did not delimit the command. And, in the
- * filter cases for read and write, and the bang, global and vglobal
- * commands, they did not delimit the command at all.
- *
- * For example, the following commands were legal:
- *
- * :edit +25|s/abc/ABC/ file.c
- * :substitute s/|/PIPE/
- * :read !spell % | columnate
- * :global/pattern/p|l
- *
- * It's not quite as simple as it sounds, however. The command:
- *
- * :substitute s/a/b/|s/c/d|set
- *
- * was also legal, i.e. the historic ex parser (using the word loosely,
- * since "parser" implies some regularity) delimited the RE's based on
- * its delimiter and not anything so irretrievably vulgar as a command
- * syntax.
- *
- * One thing that makes this easier is that we can ignore most of the
- * command termination conditions for the commands that want to take
- * the command up to the next newline. None of them are legal in .exrc
- * files, so if we're here, we only dealing with a single line, and we
- * can just eat it.
- *
- * Anyhow, the following code makes this all work. First, for the
- * special cases we move past their special argument. Then, we do
- * normal command processing on whatever is left. Barf-O-Rama.
- */
- arg1_len = 0;
- save_cmd = cmd;
- (void)term_key_ch(sp, K_VLNEXT, &vlit);
- if (cp == &cmds[C_EDIT] ||
- cp == &cmds[C_EX] || cp == &cmds[C_VISUAL_VI]) {
- /*
- * Move to the next non-whitespace character. As '+' must
- * be the character after the command name, if there isn't
- * one, we're done.
- */
- for (; cmdlen > 0; --cmdlen, ++cmd) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
- /*
- * QUOTING NOTE:
- *
- * The historic implementation ignored all escape characters
- * so there was no way to put a space or newline into the +cmd
- * field. We do a simplistic job of fixing it by moving to the
- * first whitespace character that isn't escaped by a literal
- * next character. The literal next characters are stripped
- * as they're no longer useful.
- */
- if (cmdlen > 0 && ch == '+') {
- ++cmd;
- --cmdlen;
- for (arg1 = p = cmd; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = *cmd) == vlit && cmdlen > 1) {
- --cmdlen;
- ch = *++cmd;
- } else if (isblank(ch))
- break;
- *p++ = ch;
- }
- arg1_len = cmd - arg1;
-
- /* Reset, so the first argument isn't reparsed. */
- save_cmd = cmd;
- }
- } else if (cp == &cmds[C_BANG] ||
- cp == &cmds[C_GLOBAL] || cp == &cmds[C_VGLOBAL]) {
- cmd += cmdlen;
- cmdlen = 0;
- } else if (cp == &cmds[C_READ] || cp == &cmds[C_WRITE]) {
- /*
- * Move to the next character. If it's a '!', it's a filter
- * command and we want to eat it all, otherwise, we're done.
- */
- for (; cmdlen > 0; --cmdlen, ++cmd) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
- if (cmdlen > 0 && ch == '!') {
- cmd += cmdlen;
- cmdlen = 0;
- }
- } else if (cp == &cmds[C_SUBSTITUTE]) {
- /*
- * Move to the next non-whitespace character, we'll use it as
- * the delimiter. If the character isn't an alphanumeric or
- * a '|', it's the delimiter, so parse it. Otherwise, we're
- * into something like ":s g", so use the special substitute
- * command.
- */
- for (; cmdlen > 0; --cmdlen, ++cmd)
- if (!isblank(cmd[0]))
- break;
-
- if (isalnum(cmd[0]) || cmd[0] == '|')
- cp = &cmd_subagain;
- else if (cmdlen > 0) {
- /*
- * QUOTING NOTE:
- *
- * Backslashes quote delimiter characters for RE's.
- * The backslashes are NOT removed since they'll be
- * used by the RE code. Move to the third delimiter
- * that's not escaped (or the end of the command).
- */
- delim = *cmd;
- ++cmd;
- --cmdlen;
- for (cnt = 2; cmdlen > 0 && cnt; --cmdlen, ++cmd)
- if (cmd[0] == '\\' && cmdlen > 1) {
- ++cmd;
- --cmdlen;
- } else if (cmd[0] == delim)
- --cnt;
- }
- }
- /*
- * Use normal quoting and termination rules to find the end
- * of this command.
- *
- * QUOTING NOTE:
- *
- * Historically, vi permitted ^V's to escape <newline>'s in the .exrc
- * file. It was almost certainly a bug, but that's what bug-for-bug
- * compatibility means, Grasshopper. Also, ^V's escape the command
- * delimiters. Literal next quote characters in front of the newlines,
- * '|' characters or literal next characters are stripped as as they're
- * no longer useful.
- */
- for (p = cmd, cnt = 0; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = cmd[0]) == vlit && cmdlen > 1) {
- ch = cmd[1];
- if (ch == '\n' || ch == '|') {
- if (ch == '\n')
- ++sp->if_lno;
- --cmdlen;
- ++cmd;
- ++cnt;
- } else
- ch = vlit;
- } else if (ch == '\n' || ch == '|') {
- if (ch == '\n')
- nl = 1;
- --cmdlen;
- break;
- }
- *p++ = ch;
- }
-
- /*
- * Save off the next command information, go back to the
- * original start of the command.
- */
- p = cmd + 1;
- cmd = save_cmd;
- save_cmd = p;
- save_cmdlen = cmdlen;
- cmdlen = ((save_cmd - cmd) - 1) - cnt;
-
- /*
- * !!!
- * The "set tags" command historically used a backslash, not the
- * user's literal next character, to escape whitespace. Handle
- * it here instead of complicating the argv_exp3() code. Note,
- * this isn't a particularly complex trap, and if backslashes were
- * legal in set commands, this would have to be much more complicated.
- */
- if (cp == &cmds[C_SET])
- for (p = cmd, len = cmdlen; len > 0; --len, ++p)
- if (*p == '\\')
- *p = vlit;
-
- /*
- * Set the default addresses. It's an error to specify an address for
- * a command that doesn't take them. If two addresses are specified
- * for a command that only takes one, lose the first one. Two special
- * cases here, some commands take 0 or 2 addresses. For most of them
- * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one
- * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines.
- *
- * Also, if the file is empty, some commands want to use an address of
- * 0, i.e. the entire file is 0 to 0, and the default first address is
- * 0. Otherwise, an entire file is 1 to N and the default line is 1.
- * Note, we also add the E_ZERO flag to the command flags, for the case
- * where the 0 address is only valid if it's a default address.
- *
- * Also, set a flag if we set the default addresses. Some commands
- * (ex: z) care if the user specified an address of if we just used
- * the current cursor.
- */
- switch (LF_ISSET(E_ADDR1|E_ADDR2|E_ADDR2_ALL|E_ADDR2_NONE)) {
- case E_ADDR1: /* One address: */
- switch (exc.addrcnt) {
- case 0: /* Default cursor/empty file. */
- exc.addrcnt = 1;
- F_SET(&exc, E_ADDRDEF);
- if (LF_ISSET(E_ZERODEF)) {
- if (file_lline(sp, ep, &lno))
- goto err;
- if (lno == 0) {
- exc.addr1.lno = 0;
- LF_SET(E_ZERO);
- } else
- exc.addr1.lno = sp->lno;
- } else
- exc.addr1.lno = sp->lno;
- exc.addr1.cno = sp->cno;
- break;
- case 1:
- break;
- case 2: /* Lose the first address. */
- exc.addrcnt = 1;
- exc.addr1 = exc.addr2;
- }
- break;
- case E_ADDR2_NONE: /* Zero/two addresses: */
- if (exc.addrcnt == 0) /* Default to nothing. */
- break;
- goto two;
- case E_ADDR2_ALL: /* Zero/two addresses: */
- if (exc.addrcnt == 0) { /* Default entire/empty file. */
- exc.addrcnt = 2;
- F_SET(&exc, E_ADDRDEF);
- if (file_lline(sp, ep, &exc.addr2.lno))
- goto err;
- if (LF_ISSET(E_ZERODEF) && exc.addr2.lno == 0) {
- exc.addr1.lno = 0;
- LF_SET(E_ZERO);
- } else
- exc.addr1.lno = 1;
- exc.addr1.cno = exc.addr2.cno = 0;
- F_SET(&exc, E_ADDR2_ALL);
- break;
- }
- /* FALLTHROUGH */
- case E_ADDR2: /* Two addresses: */
-two: switch (exc.addrcnt) {
- case 0: /* Default cursor/empty file. */
- exc.addrcnt = 2;
- F_SET(&exc, E_ADDRDEF);
- if (LF_ISSET(E_ZERODEF) && sp->lno == 1) {
- if (file_lline(sp, ep, &lno))
- goto err;
- if (lno == 0) {
- exc.addr1.lno = exc.addr2.lno = 0;
- LF_SET(E_ZERO);
- } else
- exc.addr1.lno = exc.addr2.lno = sp->lno;
- } else
- exc.addr1.lno = exc.addr2.lno = sp->lno;
- exc.addr1.cno = exc.addr2.cno = sp->cno;
- break;
- case 1: /* Default to first address. */
- exc.addrcnt = 2;
- exc.addr2 = exc.addr1;
- break;
- case 2:
- break;
- }
- break;
- default:
- if (exc.addrcnt) /* Error. */
- goto usage;
- }
-
- flagoff = 0;
- for (p = cp->syntax; *p != '\0'; ++p) {
- /*
- * The write command is sensitive to leading whitespace, e.g.
- * "write !" is different from "write!". If not the write
- * command, skip leading whitespace.
- */
- if (cp != &cmds[C_WRITE])
- for (; cmdlen > 0; --cmdlen, ++cmd) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
-
- /*
- * Quit when reach the end of the command, unless it's a
- * command that does its own parsing, in which case we want
- * to build a reasonable argv for it. This code guarantees
- * that there will be an argv when the function gets called,
- * so the correct test is for a length of 0, not for the
- * argc > 0.
- */
- if (cmdlen == 0 && *p != '!' && *p != 'S' && *p != 's')
- break;
-
- switch (*p) {
- case '!': /* ! */
- if (*cmd == '!') {
- ++cmd;
- --cmdlen;
- F_SET(&exc, E_FORCE);
- }
- break;
- case '1': /* +, -, #, l, p */
- /*
- * !!!
- * Historically, some flags were ignored depending
- * on where they occurred in the command line. For
- * example, in the command, ":3+++p--#", historic vi
- * acted on the '#' flag, but ignored the '-' flags.
- * It's unambiguous what the flags mean, so we just
- * handle them regardless of the stupidity of their
- * location.
- */
- for (; cmdlen; --cmdlen, ++cmd)
- switch (*cmd) {
- case '+':
- ++flagoff;
- break;
- case '-':
- --flagoff;
- break;
- case '#':
- F_SET(&exc, E_F_HASH);
- break;
- case 'l':
- F_SET(&exc, E_F_LIST);
- break;
- case 'p':
- F_SET(&exc, E_F_PRINT);
- break;
- default:
- goto end1;
- }
-end1: break;
- case '2': /* -, ., +, ^ */
- case '3': /* -, ., +, ^, = */
- for (; cmdlen; --cmdlen, ++cmd)
- switch (*cmd) {
- case '-':
- F_SET(&exc, E_F_DASH);
- break;
- case '.':
- F_SET(&exc, E_F_DOT);
- break;
- case '+':
- F_SET(&exc, E_F_PLUS);
- break;
- case '^':
- F_SET(&exc, E_F_CARAT);
- break;
- case '=':
- if (*p == '3') {
- F_SET(&exc, E_F_EQUAL);
- break;
- }
- /* FALLTHROUGH */
- default:
- goto end2;
- }
-end2: break;
- case 'b': /* buffer */
- /*
- * Digits can't be buffer names in ex commands, or the
- * command "d2" would be a delete into buffer '2', and
- * not a two-line deletion.
- */
- if (!isdigit(cmd[0])) {
- exc.buffer = *cmd;
- ++cmd;
- --cmdlen;
- F_SET(&exc, E_BUFFER);
- }
- break;
- case 'c': /* count [01+a] */
- ++p;
- if (!isdigit(*cmd) &&
- (*p != '+' || (*cmd != '+' && *cmd != '-')))
- break;
-/* 8-bit XXX */ if ((lno = strtol(cmd, &t, 10)) == 0 && *p != '0') {
- msgq(sp, M_ERR, "Count may not be zero.");
- goto err;
- }
- cmdlen -= (t - cmd);
- cmd = t;
- /*
- * Count as address offsets occur in commands taking
- * two addresses. Historic vi practice was to use
- * the count as an offset from the *second* address.
- *
- * Set a count flag; some underlying commands (see
- * join) do different things with counts than with
- * line addresses.
- */
- if (*p == 'a') {
- exc.addr1 = exc.addr2;
- exc.addr2.lno = exc.addr1.lno + lno - 1;
- } else
- exc.count = lno;
- F_SET(&exc, E_COUNT);
- break;
- case 'f': /* file */
- if (argv_exp2(sp, ep,
- &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
- goto err;
- goto countchk;
- case 'l': /* line */
- if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
- goto err;
- /* Line specifications are always required. */
- if (!tmp) {
- msgq(sp, M_ERR,
- "%s: bad line specification", cmd);
- goto err;
- }
- exc.lineno = cur.lno;
- break;
- case 'S': /* string, file exp. */
- if (argv_exp1(sp, ep,
- &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
- goto err;
- goto addr2;
- case 's': /* string */
- if (argv_exp0(sp, ep, &exc, cmd, cmdlen))
- goto err;
- goto addr2;
- case 'W': /* word string */
- /*
- * QUOTING NOTE:
- *
- * Literal next characters escape the following
- * character. Quoting characters are stripped
- * here since they are no longer useful.
- *
- * First there was the word.
- */
- for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = *cmd) == vlit && cmdlen > 1) {
- --cmdlen;
- *p++ = *++cmd;
- } else if (isblank(ch)) {
- ++cmd;
- --cmdlen;
- break;
- } else
- *p++ = ch;
- }
- if (argv_exp0(sp, ep, &exc, t, p - t))
- goto err;
-
- /* Delete intervening whitespace. */
- for (; cmdlen > 0; --cmdlen, ++cmd) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
- if (cmdlen == 0)
- goto usage;
-
- /* Followed by the string. */
- for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd, ++p)
- if ((ch = *cmd) == vlit && cmdlen > 1) {
- --cmdlen;
- *p = *++cmd;
- } else
- *p = ch;
- if (argv_exp0(sp, ep, &exc, t, p - t))
- goto err;
- goto addr2;
- case 'w': /* word */
- if (argv_exp3(sp, ep, &exc, cmd, cmdlen))
- goto err;
-countchk: if (*++p != 'N') { /* N */
- /*
- * If a number is specified, must either be
- * 0 or that number, if optional, and that
- * number, if required.
- */
- num = *p - '0';
- if ((*++p != 'o' || exp->argsoff != 0) &&
- exp->argsoff != num)
- goto usage;
- }
- goto addr2;
- default:
- msgq(sp, M_ERR,
- "Internal syntax table error (%s: %c).",
- cp->name, *p);
- }
- }
-
- /* Skip trailing whitespace. */
- for (; cmdlen; --cmdlen) {
- ch = *cmd++;
- if (!isblank(ch))
- break;
- }
-
- /*
- * There shouldn't be anything left, and no more required
- * fields, i.e neither 'l' or 'r' in the syntax string.
- */
- if (cmdlen || strpbrk(p, "lr")) {
-usage: msgq(sp, M_ERR, "Usage: %s.", cp->usage);
- goto err;
- }
-
- /* Verify that the addresses are legal. */
-addr2: switch (exc.addrcnt) {
- case 2:
- if (file_lline(sp, ep, &lno))
- goto err;
- /*
- * Historic ex/vi permitted commands with counts to go past
- * EOF. So, for example, if the file only had 5 lines, the
- * ex command "1,6>" would fail, but the command ">300"
- * would succeed. Since we don't want to have to make all
- * of the underlying commands handle random line numbers,
- * fix it here.
- */
- if (exc.addr2.lno > lno)
- if (F_ISSET(&exc, E_COUNT))
- exc.addr2.lno = lno;
- else {
- if (lno == 0)
- msgq(sp, M_ERR, "The file is empty.");
- else
- msgq(sp, M_ERR,
- "Only %lu line%s in the file",
- lno, lno > 1 ? "s" : "");
- goto err;
- }
- /* FALLTHROUGH */
- case 1:
- num = exc.addr1.lno;
- /*
- * If it's a "default vi command", zero is okay. Historic
- * vi allowed this, note, it's also the hack that allows
- * "vi + nonexistent_file" to work.
- */
- if (num == 0 && (!IN_VI_MODE(sp) || uselastcmd != 1) &&
- !LF_ISSET(E_ZERO)) {
- msgq(sp, M_ERR,
- "The %s command doesn't permit an address of 0.",
- cp->name);
- goto err;
- }
- if (file_lline(sp, ep, &lno))
- goto err;
- if (num > lno) {
- if (lno == 0)
- msgq(sp, M_ERR, "The file is empty.");
- else
- msgq(sp, M_ERR, "Only %lu line%s in the file",
- lno, lno > 1 ? "s" : "");
- goto err;
- }
- break;
- }
-
- /* If doing a default command, vi just moves to the line. */
- if (IN_VI_MODE(sp) && uselastcmd) {
- switch (exc.addrcnt) {
- case 2:
- sp->lno = exc.addr2.lno ? exc.addr2.lno : 1;
- sp->cno = exc.addr2.cno;
- break;
- case 1:
- sp->lno = exc.addr1.lno ? exc.addr1.lno : 1;
- sp->cno = exc.addr1.cno;
- break;
- }
- cmd = save_cmd;
- cmdlen = save_cmdlen;
- goto loop;
- }
-
- /* Reset "last" command. */
- if (LF_ISSET(E_SETLAST))
- exp->lastcmd = cp;
-
- /* Final setup for the command. */
- exc.cmd = cp;
-
-#if defined(DEBUG) && 0
- TRACE(sp, "ex_cmd: %s", exc.cmd->name);
- if (exc.addrcnt > 0) {
- TRACE(sp, "\taddr1 %d", exc.addr1.lno);
- if (exc.addrcnt > 1)
- TRACE(sp, " addr2: %d", exc.addr2.lno);
- TRACE(sp, "\n");
- }
- if (exc.lineno)
- TRACE(sp, "\tlineno %d", exc.lineno);
- if (exc.flags)
- TRACE(sp, "\tflags %0x", exc.flags);
- if (F_ISSET(&exc, E_BUFFER))
- TRACE(sp, "\tbuffer %c", exc.buffer);
- TRACE(sp, "\n");
- if (exc.argc) {
- for (cnt = 0; cnt < exc.argc; ++cnt)
- TRACE(sp, "\targ %d: {%s}", cnt, exc.argv[cnt]);
- TRACE(sp, "\n");
- }
-#endif
- /* Clear autoprint flag. */
- F_CLR(exp, EX_AUTOPRINT);
-
- /* Increment the command count if not called from vi. */
- if (!IN_VI_MODE(sp))
- ++sp->ccnt;
-
- /*
- * If file state and not doing a global command, log the start of
- * an action.
- */
- if (ep != NULL && !F_ISSET(sp, S_GLOBAL))
- (void)log_cursor(sp, ep);
-
- /* Save the current mode. */
- saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
-
- /* Do the command. */
- if ((cp->fn)(sp, ep, &exc))
- goto err;
-
-#ifdef DEBUG
- /* Make sure no function left the temporary space locked. */
- if (F_ISSET(sp->gp, G_TMP_INUSE)) {
- F_CLR(sp->gp, G_TMP_INUSE);
- msgq(sp, M_ERR, "Error: ex: temporary buffer not released.");
- goto err;
- }
-#endif
- if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) {
- /*
- * Only here if the mode of the underlying file changed, e.g.
- * the user switched files or is exiting. There are two things
- * that we might have to save. First, any "+cmd" field set up
- * for an ex/edit command will have to be saved for later, also,
- * any not yet executed part of the current ex command.
- *
- * :edit +25 file.c|s/abc/ABC/|1
- *
- * for example.
- *
- * The historic vi just hung, of course; we handle by
- * pushing the keys onto the tty queue. If we're
- * switching modes to vi, since the commands are intended
- * as ex commands, add the extra characters to make it
- * work.
- *
- * For the fun of it, if you want to see if a vi clone got
- * the ex argument parsing right, try:
- *
- * echo 'foo|bar' > file1; echo 'foo/bar' > file2;
- * vi
- * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq
- */
- if (arg1_len == NULL && save_cmdlen == 0)
- return (0);
- if (IN_VI_MODE(sp) && term_push(sp, "\n", 1, 0, 0))
- goto err;
- if (save_cmdlen != 0)
- if (term_push(sp, save_cmd, save_cmdlen, 0, 0))
- goto err;
- if (arg1 != NULL) {
- if (IN_VI_MODE(sp) && save_cmdlen != 0 &&
- term_push(sp, "|", 1, 0, 0))
- goto err;
- if (term_push(sp, arg1, arg1_len, 0, 0))
- goto err;
- }
- if (IN_VI_MODE(sp) && term_push(sp, ":", 1, 0, 0))
- goto err;
- return (0);
- }
-
- if (IN_EX_MODE(sp) && ep != NULL) {
- /*
- * The print commands have already handled the `print' flags.
- * If so, clear them. Don't return, autoprint may still have
- * stuff to print out.
- */
- if (LF_ISSET(E_F_PRCLEAR))
- F_CLR(&exc, E_F_HASH | E_F_LIST | E_F_PRINT);
-
- /*
- * If the command was successful, and there was an explicit
- * flag to display the new cursor line, or we're in ex mode,
- * autoprint is set, and a change was made, display the line.
- */
- if (flagoff) {
- if (flagoff < 0) {
- if (sp->lno < -flagoff) {
- msgq(sp, M_ERR,
- "Flag offset before line 1.");
- goto err;
- }
- } else {
- if (file_lline(sp, ep, &lno))
- goto err;
- if (sp->lno + flagoff > lno) {
- msgq(sp, M_ERR,
- "Flag offset past end-of-file.");
- goto err;
- }
- }
- sp->lno += flagoff;
- }
-
- if (O_ISSET(sp, O_AUTOPRINT) &&
- (F_ISSET(exp, EX_AUTOPRINT) || F_ISSET(cp, E_AUTOPRINT)))
- LF_INIT(E_F_PRINT);
- else
- LF_INIT(F_ISSET(&exc, E_F_HASH | E_F_LIST | E_F_PRINT));
-
- memset(&exc, 0, sizeof(EXCMDARG));
- exc.addrcnt = 2;
- exc.addr1.lno = exc.addr2.lno = sp->lno;
- exc.addr1.cno = exc.addr2.cno = sp->cno;
- switch (LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT)) {
- case E_F_HASH:
- exc.cmd = &cmds[C_HASH];
- ex_number(sp, ep, &exc);
- break;
- case E_F_LIST:
- exc.cmd = &cmds[C_LIST];
- ex_list(sp, ep, &exc);
- break;
- case E_F_PRINT:
- exc.cmd = &cmds[C_PRINT];
- ex_pr(sp, ep, &exc);
- break;
- }
- }
-
- cmd = save_cmd;
- cmdlen = save_cmdlen;
- goto loop;
- /* NOTREACHED */
-
- /*
- * On error, we discard any keys we have left, as well as any keys
- * that were mapped. The test of save_cmdlen isn't necessarily
- * correct. If we fail early enough we don't know if the entire
- * string was a single command or not. Try and guess, it's useful
- * to know if part of the command was discarded.
- */
-err: if (save_cmdlen == 0)
- for (; cmdlen; --cmdlen)
- if ((ch = *cmd++) == vlit && cmdlen > 1) {
- --cmdlen;
- ++cmd;
- } else if (ch == '\n' || ch == '|') {
- if (cmdlen > 1)
- save_cmdlen = 1;
- break;
- }
- if (save_cmdlen != 0)
- msgq(sp, M_ERR,
- "Ex command failed: remaining command input discarded.");
- term_map_flush(sp, "Ex command failed");
- return (1);
-}
-
-/*
- * ep_range --
- * Get a line range for ex commands.
- */
-static int
-ep_range(sp, ep, excp, cmdp, cmdlenp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
- char **cmdp;
- size_t *cmdlenp;
-{
- MARK cur, savecursor;
- size_t cmdlen;
- int savecursor_set, tmp;
- char *cmd;
-
- /* Percent character is all lines in the file. */
- cmd = *cmdp;
- cmdlen = *cmdlenp;
- if (*cmd == '%') {
- excp->addr1.lno = 1;
- if (file_lline(sp, ep, &excp->addr2.lno))
- return (1);
-
- /* If an empty file, then the first line is 0, not 1. */
- if (excp->addr2.lno == 0)
- excp->addr1.lno = 0;
- excp->addr1.cno = excp->addr2.cno = 0;
- excp->addrcnt = 2;
-
- ++*cmdp;
- --*cmdlenp;
- return (0);
- }
-
- /* Parse comma or semi-colon delimited line specs. */
- for (savecursor_set = 0, excp->addrcnt = 0; cmdlen > 0;)
- switch (*cmd) {
- case ';': /* Semi-colon delimiter. */
- /*
- * Comma delimiters delimit; semi-colon delimiters
- * change the current address for the 2nd address
- * to be the first address. Trailing or multiple
- * delimiters are discarded.
- */
- if (excp->addrcnt == 0)
- goto done;
- if (!savecursor_set) {
- savecursor.lno = sp->lno;
- savecursor.cno = sp->cno;
- sp->lno = excp->addr1.lno;
- sp->cno = excp->addr1.cno;
- savecursor_set = 1;
- }
- ++cmd;
- --cmdlen;
- break;
- case ',': /* Comma delimiter. */
- /* If no addresses yet, defaults to ".". */
- if (excp->addrcnt == 0) {
- excp->addr1.lno = sp->lno;
- excp->addr1.cno = sp->cno;
- excp->addrcnt = 1;
- }
- /* FALLTHROUGH */
- case ' ': /* Whitespace. */
- case '\t': /* Whitespace. */
- ++cmd;
- --cmdlen;
- break;
- default:
- if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
- return (1);
- if (!tmp)
- goto done;
-
- /*
- * Extra addresses are discarded, starting with
- * the first.
- */
- switch (excp->addrcnt) {
- case 0:
- excp->addr1 = cur;
- excp->addrcnt = 1;
- break;
- case 1:
- excp->addr2 = cur;
- excp->addrcnt = 2;
- break;
- case 2:
- excp->addr1 = excp->addr2;
- excp->addr2 = cur;
- break;
- }
- break;
- }
-
- /*
- * XXX
- * This is probably not right behavior for savecursor -- need
- * to figure out what the historical ex did for ";,;,;5p" or
- * similar stupidity.
- */
-done: if (savecursor_set) {
- sp->lno = savecursor.lno;
- sp->cno = savecursor.cno;
- }
- if (excp->addrcnt == 2 &&
- (excp->addr2.lno < excp->addr1.lno ||
- excp->addr2.lno == excp->addr1.lno &&
- excp->addr2.cno < excp->addr1.cno)) {
- msgq(sp, M_ERR,
- "The second address is smaller than the first.");
- return (1);
- }
- *cmdp = cmd;
- *cmdlenp = cmdlen;
- return (0);
-}
-
-/*
- * Get a single line address specifier.
- */
-static int
-ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
- SCR *sp;
- EXF *ep;
- MARK *cur;
- char **cmdp;
- size_t *cmdlenp;
- int *addr_found;
-{
- MARK m, *mp;
- long total;
- u_int flags;
- size_t cmdlen;
- char *cmd, *endp;
-
- *addr_found = 0;
-
- cmd = *cmdp;
- cmdlen = *cmdlenp;
- switch (*cmd) {
- case '$': /* Last line in the file. */
- *addr_found = 1;
- cur->cno = 0;
- if (file_lline(sp, ep, &cur->lno))
- return (1);
- ++cmd;
- --cmdlen;
- break; /* Absolute line number. */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- *addr_found = 1;
- /*
- * The way the vi "previous context" mark worked was that
- * "non-relative" motions set it. While vi wasn't totally
- * consistent about this, ANY numeric address was considered
- * non-relative, and set the value. Which is why we're
- * hacking marks down here.
- */
- if (IN_VI_MODE(sp)) {
- m.lno = sp->lno;
- m.cno = sp->cno;
- if (mark_set(sp, ep, ABSMARK1, &m, 1))
- return (1);
- }
- cur->cno = 0;
-/* 8-bit XXX */ cur->lno = strtol(cmd, &endp, 10);
- cmdlen -= (endp - cmd);
- cmd = endp;
- break;
- case '\'': /* Use a mark. */
- *addr_found = 1;
- if (cmdlen == 1) {
- msgq(sp, M_ERR, "No mark name supplied.");
- return (1);
- }
- if ((mp = mark_get(sp, ep, cmd[1])) == NULL)
- return (1);
- *cur = *mp;
- cmd += 2;
- cmdlen -= 2;
- break;
- case '\\': /* Search: forward/backward. */
- /*
- * !!!
- * I can't find any difference between // and \/ or
- * between ?? and \?. Mark Horton doesn't remember
- * there being any difference. C'est la vie.
- */
- if (cmdlen < 2 || cmd[1] != '/' && cmd[1] != '?') {
- msgq(sp, M_ERR, "\\ not followed by / or ?.");
- return (1);
- }
- ++cmd;
- --cmdlen;
- if (cmd[0] == '/')
- goto forward;
- if (cmd[0] == '?')
- goto backward;
- /* NOTREACHED */
- case '/': /* Search forward. */
-forward: *addr_found = 1;
- m.lno = sp->lno;
- m.cno = sp->cno;
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET;
- if (f_search(sp, ep, &m, &m, cmd, &endp, &flags))
- return (1);
- cur->lno = m.lno;
- cur->cno = m.cno;
- cmdlen -= (endp - cmd);
- cmd = endp;
- break;
- case '?': /* Search backward. */
-backward: *addr_found = 1;
- m.lno = sp->lno;
- m.cno = sp->cno;
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET;
- if (b_search(sp, ep, &m, &m, cmd, &endp, &flags))
- return (1);
- cur->lno = m.lno;
- cur->cno = m.cno;
- cmdlen -= (endp - cmd);
- cmd = endp;
- break;
- case '.': /* Current position. */
- *addr_found = 1;
- cur->cno = sp->cno;
-
- /* If an empty file, then '.' is 0, not 1. */
- if (sp->lno == 1) {
- if (file_lline(sp, ep, &cur->lno))
- return (1);
- if (cur->lno != 0)
- cur->lno = 1;
- } else
- cur->lno = sp->lno;
- ++cmd;
- --cmdlen;
- break;
- }
-
- /*
- * Evaluate any offset. Offsets are +/- any number, or any number
- * of +/- signs, or any combination thereof. If no address found
- * yet, offset is relative to ".".
- */
- for (total = 0; cmdlen > 0 && (cmd[0] == '-' || cmd[0] == '+');) {
- if (!*addr_found) {
- cur->lno = sp->lno;
- cur->cno = sp->cno;
- *addr_found = 1;
- }
-
- if (cmdlen > 1 && isdigit(cmd[1])) {
-/* 8-bit XXX */ total += strtol(cmd, &endp, 10);
- cmdlen -= (endp - cmd);
- cmd = endp;
- } else {
- total += cmd[0] == '-' ? -1 : 1;
- --cmdlen;
- ++cmd;
- }
- }
- if (total < 0 && -total > cur->lno) {
- msgq(sp, M_ERR, "Reference to a line number less than 0.");
- return (1);
- }
- cur->lno += total;
-
- *cmdp = cmd;
- *cmdlenp = cmdlen;
- return (0);
-}
-
-/*
- * ex_is_abbrev -
- * The vi text input routine needs to know if ex thinks this is
- * an [un]abbreviate command, so it can turn off abbreviations.
- * Usual ranting in the vi/v_ntext:txt_abbrev() routine.
- */
-int
-ex_is_abbrev(name, len)
- char *name;
- size_t len;
-{
- EXCMDLIST const *cp;
-
- return ((cp = ex_comm_search(name, len)) != NULL &&
- (cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE]));
-}
-
-static inline EXCMDLIST const *
-ex_comm_search(name, len)
- char *name;
- size_t len;
-{
- EXCMDLIST const *cp;
-
- for (cp = cmds; cp->name != NULL; ++cp) {
- if (cp->name[0] > name[0])
- return (NULL);
- if (cp->name[0] != name[0])
- continue;
- if (!memcmp(name, cp->name, len))
- return (cp);
- }
- return (NULL);
-}
diff --git a/usr.bin/vi/nex/ex_abbrev.c b/usr.bin/vi/nex/ex_abbrev.c
deleted file mode 100644
index f28cbe45e490..000000000000
--- a/usr.bin/vi/nex/ex_abbrev.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_abbrev.c 8.6 (Berkeley) 12/22/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-
-#include "vi.h"
-#include "seq.h"
-#include "excmd.h"
-
-/*
- * ex_abbr -- :abbreviate [key replacement]
- * Create an abbreviation or display abbreviations.
- */
-int
-ex_abbr(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- switch (cmdp->argc) {
- case 0:
- if (seq_dump(sp, SEQ_ABBREV, 0) == 0)
- msgq(sp, M_INFO, "No abbreviations to display.");
- return (0);
- case 2:
- break;
- default:
- abort();
- }
-
- if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len,
- cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, 1))
- return (1);
- F_SET(sp->gp, G_ABBREV);
- return (0);
-}
-
-/*
- * ex_unabbr -- :unabbreviate key
- * Delete an abbreviation.
- */
-int
-ex_unabbr(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- ARGS *ap;
-
- ap = cmdp->argv[0];
- if (!F_ISSET(sp->gp, G_ABBREV) ||
- seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) {
- msgq(sp, M_ERR, "\"%s\" is not an abbreviation.", ap->bp);
- return (1);
- }
- return (0);
-}
-
-/*
- * abbr_save --
- * Save the abbreviation sequences to a file.
- */
-int
-abbr_save(sp, fp)
- SCR *sp;
- FILE *fp;
-{
- return (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV));
-}
diff --git a/usr.bin/vi/nex/ex_append.c b/usr.bin/vi/nex/ex_append.c
deleted file mode 100644
index c6edfd57db3b..000000000000
--- a/usr.bin/vi/nex/ex_append.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_append.c 8.6 (Berkeley) 11/23/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-enum which {APPEND, CHANGE, INSERT};
-
-static int aci __P((SCR *, EXF *, EXCMDARG *, enum which));
-
-/*
- * ex_append -- :[line] a[ppend][!]
- * Append one or more lines of new text after the specified line,
- * or the current line if no address is specified.
- */
-int
-ex_append(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (aci(sp, ep, cmdp, APPEND));
-}
-
-/*
- * ex_change -- :[line[,line]] c[hange][!] [count]
- * Change one or more lines to the input text.
- */
-int
-ex_change(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (aci(sp, ep, cmdp, CHANGE));
-}
-
-/*
- * ex_insert -- :[line] i[nsert][!]
- * Insert one or more lines of new text before the specified line,
- * or the current line if no address is specified.
- */
-int
-ex_insert(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (aci(sp, ep, cmdp, INSERT));
-}
-
-static int
-aci(sp, ep, cmdp, cmd)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which cmd;
-{
- MARK m;
- TEXT *tp;
- recno_t cnt;
- int rval, aiset;
-
- /*
- * The ! flag turns off autoindent for append, change and
- * insert.
- */
- if (F_ISSET(cmdp, E_FORCE)) {
- aiset = O_ISSET(sp, O_AUTOINDENT);
- O_CLR(sp, O_AUTOINDENT);
- } else
- aiset = 0;
-
- /*
- * If doing a change, replace lines as long as possible.
- * Then, append more lines or delete remaining lines.
- * Inserts are the same as appends to the previous line.
- */
- rval = 0;
- m = cmdp->addr1;
- if (cmd == INSERT) {
- --m.lno;
- cmd = APPEND;
- }
- if (cmd == CHANGE)
- for (;; ++m.lno) {
- if (m.lno > cmdp->addr2.lno) {
- cmd = APPEND;
- --m.lno;
- break;
- }
- switch (sp->s_get(sp, ep, &sp->tiq, 0,
- TXT_BEAUTIFY | TXT_CR | TXT_NLECHO)) {
- case INP_OK:
- break;
- case INP_EOF:
- case INP_ERR:
- rval = 1;
- goto done;
- }
- tp = sp->tiq.cqh_first;
- if (tp->len == 1 && tp->lb[0] == '.') {
- for (cnt =
- (cmdp->addr2.lno - m.lno) + 1; cnt--;)
- if (file_dline(sp, ep, m.lno)) {
- rval = 1;
- goto done;
- }
- goto done;
- }
- if (file_sline(sp, ep, m.lno, tp->lb, tp->len)) {
- rval = 1;
- goto done;
- }
- }
-
- if (cmd == APPEND)
- for (;; ++m.lno) {
- switch (sp->s_get(sp, ep, &sp->tiq, 0,
- TXT_BEAUTIFY | TXT_CR | TXT_NLECHO)) {
- case INP_OK:
- break;
- case INP_EOF:
- case INP_ERR:
- rval = 1;
- goto done;
- }
- tp = sp->tiq.cqh_first;
- if (tp->len == 1 && tp->lb[0] == '.')
- break;
- if (file_aline(sp, ep, 1, m.lno, tp->lb, tp->len)) {
- rval = 1;
- goto done;
- }
- }
-
-done: if (rval == 0)
- sp->lno = m.lno;
-
- if (aiset)
- O_SET(sp, O_AUTOINDENT);
-
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_args.c b/usr.bin/vi/nex/ex_args.c
deleted file mode 100644
index 2f96df727dd8..000000000000
--- a/usr.bin/vi/nex/ex_args.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_args.c 8.13 (Berkeley) 12/20/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_next -- :next [files]
- * Edit the next file, optionally setting the list of files.
- *
- * !!!
- * The :next command behaved differently from the :rewind command in
- * historic vi. See nvi/docs/autowrite for details, but the basic
- * idea was that it ignored the force flag if the autowrite flag was
- * set. This implementation handles them all identically.
- */
-int
-ex_next(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- ARGS **argv;
- FREF *frp;
- char *name;
-
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
-
- if (cmdp->argc) {
- /* Mark all the current files as ignored. */
- for (frp = sp->frefq.cqh_first;
- frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)
- F_SET(frp, FR_IGNORE);
-
- /* Add the new files into the file list. */
- for (argv = cmdp->argv; argv[0]->len != 0; ++argv)
- if (file_add(sp, NULL, argv[0]->bp, 0) == NULL)
- return (1);
-
- if ((frp = file_first(sp)) == NULL)
- return (1);
- } else if ((frp = file_next(sp, sp->a_frp)) == NULL) {
- msgq(sp, M_ERR, "No more files to edit.");
- return (1);
- }
-
- /*
- * There's a tricky sequence, where the user edits two files, e.g.
- * "x" and "y". While in "x", they do ":e y|:f foo", which changes
- * the name of that FRP entry. Then, the :n command finds the file
- * "y" with a name change. If the file name has been changed, get
- * a new FREF for the original file name, and make it be the one that
- * is displayed in the argument list, not the one with the name change.
- */
- if (frp->cname != NULL) {
- F_SET(frp, FR_IGNORE);
- name = frp->name == NULL ? frp->tname : frp->name;
- if ((frp = file_add(sp, sp->a_frp, name, 0)) == NULL)
- return (1);
- }
- if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
- return (1);
- sp->a_frp = frp;
- F_SET(sp, S_FSWITCH);
- return (0);
-}
-
-/*
- * ex_prev -- :prev
- * Edit the previous file.
- */
-int
-ex_prev(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- FREF *frp;
- char *name;
-
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
-
- if ((frp = file_prev(sp, sp->a_frp)) == NULL) {
- msgq(sp, M_ERR, "No previous files to edit.");
- return (1);
- }
-
- /* See comment in ex_next(). */
- if (frp->cname != NULL) {
- F_SET(frp, FR_IGNORE);
- name = frp->name == NULL ? frp->tname : frp->name;
- if ((frp = file_add(sp, frp, name, 0)) == NULL)
- return (1);
- }
- if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
- return (1);
- sp->a_frp = frp;
- F_SET(sp, S_FSWITCH);
- return (0);
-}
-
-/*
- * ex_rew -- :rew
- * Re-edit the list of files.
- */
-int
-ex_rew(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- FREF *frp, *tfrp;
-
- /*
- * !!!
- * Historic practice -- you can rewind to the current file.
- */
- if ((frp = file_first(sp)) == NULL) {
- msgq(sp, M_ERR, "No previous files to rewind.");
- return (1);
- }
-
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
-
- /*
- * !!!
- * Historic practice, turn off the edited bit. The :next and :prev
- * code will discard any name changes, so ignore them here. Start
- * at the beginning of the file, too.
- */
- for (tfrp = sp->frefq.cqh_first;
- tfrp != (FREF *)&sp->frefq; tfrp = tfrp->q.cqe_next)
- F_CLR(tfrp, FR_CHANGEWRITE | FR_CURSORSET | FR_EDITED);
-
- if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
- return (1);
- sp->a_frp = frp;
- F_SET(sp, S_FSWITCH);
- return (0);
-}
-
-/*
- * ex_args -- :args
- * Display the list of files.
- */
-int
-ex_args(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- FREF *frp;
- int cnt, col, iscur, len, nlen, sep;
- char *name;
-
- /*
- * !!!
- * Ignore files that aren't in the "argument" list unless they are the
- * one we're currently editing. I'm not sure this is right, but the
- * historic vi behavior of not showing the current file if it was the
- * result of a ":e" command, or if the file name was changed was wrong.
- * This is actually pretty tricky, don't modify it without thinking it
- * through. There have been a lot of problems in here.
- *
- * Also, historic practice was to display the original name of the file
- * even if the user had used a file command to change the file name.
- * Confusing, at best. We show both names: the original as that's what
- * the user will get in a next, prev or rewind, and the new one since
- * that's what the user is actually editing now.
- *
- * When we find the "argument" FREF, i.e. the current location in the
- * user's argument list, if it's not the same as the current FREF, we
- * display the current FREF as following the argument in the list.
- * This means that if the user edits three files, "x", "y" and "z", and
- * then does a :e command in the file "x" to edit "z", "z" will appear
- * in the list twice.
- */
- col = len = sep = 0;
- for (cnt = 1, frp = sp->frefq.cqh_first;
- frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next) {
- iscur = 0;
- /*
- * If the last argument FREF structure, and we're editing
- * it, set the current bit. Otherwise, we'll display it,
- * then the file we're editing, and the latter will have
- * the current bit set.
- */
- if (frp == sp->a_frp) {
- if (frp == sp->frp && frp->cname == NULL)
- iscur = 1;
- } else if (F_ISSET(frp, FR_IGNORE))
- continue;
- name = frp->name == NULL ? frp->tname : frp->name;
- /*
- * Mistake. The user edited a temporary file (vi /tmp), then
- * switched to another file (:e file). The argument FREF is
- * pointing to the temporary file, but it doesn't have a name.
- * Gracefully recover through the creative use of goto's.
- */
- if (name == NULL)
- goto testcur;
-extra: nlen = strlen(name);
- col += len = nlen + sep + (iscur ? 2 : 0);
- if (col >= sp->cols - 1) {
- col = len;
- sep = 0;
- (void)ex_printf(EXCOOKIE, "\n");
- } else if (cnt != 1) {
- sep = 1;
- (void)ex_printf(EXCOOKIE, " ");
- }
- ++cnt;
-
- if (iscur)
- (void)ex_printf(EXCOOKIE, "[%s]", name);
- else {
- (void)ex_printf(EXCOOKIE, "%s", name);
-testcur: if (frp == sp->a_frp) {
- if (frp != sp->frp)
- name = FILENAME(sp->frp);
- else
- name = frp->cname;
- iscur = 1;
- goto extra;
- }
- }
- }
- /* This should never happen; left in because it's been known to. */
- if (cnt == 1)
- (void)ex_printf(EXCOOKIE, "No files.\n");
- else
- (void)ex_printf(EXCOOKIE, "\n");
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_argv.c b/usr.bin/vi/nex/ex_argv.c
deleted file mode 100644
index 6ad76c61dfbc..000000000000
--- a/usr.bin/vi/nex/ex_argv.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_argv.c 8.26 (Berkeley) 1/2/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-static int argv_alloc __P((SCR *, size_t));
-static int argv_fexp __P((SCR *, EXCMDARG *,
- char *, size_t, char *, size_t *, char **, size_t *, int));
-static int argv_sexp __P((SCR *, char **, size_t *, size_t *));
-
-/*
- * argv_init --
- * Build a prototype arguments list.
- */
-int
-argv_init(sp, ep, excp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
-{
- EX_PRIVATE *exp;
-
- exp = EXP(sp);
- exp->argsoff = 0;
- argv_alloc(sp, 1);
-
- excp->argv = exp->args;
- excp->argc = exp->argsoff;
- return (0);
-}
-
-/*
- * argv_exp0 --
- * Put a string into an argv.
- */
-int
-argv_exp0(sp, ep, excp, cmd, cmdlen)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
- char *cmd;
- size_t cmdlen;
-{
- EX_PRIVATE *exp;
-
- exp = EXP(sp);
- argv_alloc(sp, cmdlen);
- memmove(exp->args[exp->argsoff]->bp, cmd, cmdlen);
- exp->args[exp->argsoff]->bp[cmdlen] = '\0';
- exp->args[exp->argsoff]->len = cmdlen;
- ++exp->argsoff;
- excp->argv = exp->args;
- excp->argc = exp->argsoff;
- return (0);
-}
-
-/*
- * argv_exp1 --
- * Do file name expansion on a string, and leave it in a string.
- */
-int
-argv_exp1(sp, ep, excp, cmd, cmdlen, is_bang)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
- char *cmd;
- size_t cmdlen;
- int is_bang;
-{
- EX_PRIVATE *exp;
- size_t blen, len;
- char *bp;
-
- GET_SPACE_RET(sp, bp, blen, 512);
-
- len = 0;
- exp = EXP(sp);
- if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) {
- FREE_SPACE(sp, bp, blen);
- return (1);
- }
-
- argv_alloc(sp, len);
- memmove(exp->args[exp->argsoff]->bp, bp, len);
- exp->args[exp->argsoff]->bp[len] = '\0';
- exp->args[exp->argsoff]->len = len;
- ++exp->argsoff;
- excp->argv = exp->args;
- excp->argc = exp->argsoff;
-
- FREE_SPACE(sp, bp, blen);
- return (0);
-}
-
-/*
- * argv_exp2 --
- * Do file name and shell expansion on a string, and break
- * it up into an argv.
- */
-int
-argv_exp2(sp, ep, excp, cmd, cmdlen, is_bang)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
- char *cmd;
- size_t cmdlen;
- int is_bang;
-{
- size_t blen, len, n;
- int rval;
- char *bp, *p;
-
- GET_SPACE_RET(sp, bp, blen, 512);
-
-#define SHELLECHO "echo "
-#define SHELLOFFSET (sizeof(SHELLECHO) - 1)
- memmove(bp, SHELLECHO, SHELLOFFSET);
- p = bp + SHELLOFFSET;
- len = SHELLOFFSET;
-
-#if defined(DEBUG) && 0
- TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd);
-#endif
-
- if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, is_bang)) {
- rval = 1;
- goto err;
- }
-
-#if defined(DEBUG) && 0
- TRACE(sp, "before shell: %d: {%s}\n", len, bp);
-#endif
-
- /*
- * Do shell word expansion -- it's very, very hard to figure out
- * what magic characters the user's shell expects. If it's not
- * pure vanilla, don't even try.
- */
- for (p = bp, n = len; n > 0; --n, ++p)
- if (!isalnum(*p) && !isblank(*p) && *p != '/' && *p != '.')
- break;
- if (n > 0) {
- if (argv_sexp(sp, &bp, &blen, &len)) {
- rval = 1;
- goto err;
- }
- p = bp;
- } else {
- p = bp + SHELLOFFSET;
- len -= SHELLOFFSET;
- }
-
-#if defined(DEBUG) && 0
- TRACE(sp, "after shell: %d: {%s}\n", len, bp);
-#endif
-
- rval = argv_exp3(sp, ep, excp, p, len);
-
-err: FREE_SPACE(sp, bp, blen);
- return (rval);
-}
-
-/*
- * argv_exp3 --
- * Take a string and break it up into an argv.
- */
-int
-argv_exp3(sp, ep, excp, cmd, cmdlen)
- SCR *sp;
- EXF *ep;
- EXCMDARG *excp;
- char *cmd;
- size_t cmdlen;
-{
- CHAR_T vlit;
- EX_PRIVATE *exp;
- size_t len;
- int ch, off;
- char *ap, *p;
-
- (void)term_key_ch(sp, K_VLNEXT, &vlit);
- for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
- /* Skip any leading whitespace. */
- for (; cmdlen > 0; --cmdlen, ++cmd) {
- ch = *cmd;
- if (!isblank(ch))
- break;
- }
- if (cmdlen == 0)
- break;
-
- /*
- * Determine the length of this whitespace delimited
- * argument.
- *
- * QUOTING NOTE:
- *
- * Skip any character preceded by the user's quoting
- * character.
- */
- for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len)
- if ((ch = *cmd) == vlit && cmdlen > 1) {
- ++cmd;
- --cmdlen;
- } else if (isblank(ch))
- break;
-
- /*
- * Copy the argument into place.
- *
- * QUOTING NOTE:
- *
- * Lose quote chars.
- */
- argv_alloc(sp, len);
- off = exp->argsoff;
- exp->args[off]->len = len;
- for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++)
- if (*ap == vlit) {
- ++ap;
- --exp->args[off]->len;
- }
- *p = '\0';
- }
- excp->argv = exp->args;
- excp->argc = exp->argsoff;
-
-#if defined(DEBUG) && 0
- for (cnt = 0; cnt < exp->argsoff; ++cnt)
- TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]);
-#endif
- return (0);
-}
-
-/*
- * argv_fexp --
- * Do file name and bang command expansion.
- */
-static int
-argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang)
- SCR *sp;
- EXCMDARG *excp;
- char *cmd, *p, **bpp;
- size_t cmdlen, *lenp, *blenp;
- int is_bang;
-{
- EX_PRIVATE *exp;
- char *bp, *t;
- size_t blen, len, tlen;
-
- /* Replace file name characters. */
- for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd)
- switch (*cmd) {
- case '!':
- if (!is_bang)
- goto ins_ch;
- exp = EXP(sp);
- if (exp->lastbcomm == NULL) {
- msgq(sp, M_ERR,
- "No previous command to replace \"!\".");
- return (1);
- }
- len += tlen = strlen(exp->lastbcomm);
- ADD_SPACE_RET(sp, bp, blen, len);
- memmove(p, exp->lastbcomm, tlen);
- p += tlen;
- F_SET(excp, E_MODIFY);
- break;
- case '%':
- if (sp->frp->cname == NULL && sp->frp->name == NULL) {
- msgq(sp, M_ERR,
- "No filename to substitute for %%.");
- return (1);
- }
- tlen = strlen(t = FILENAME(sp->frp));
- len += tlen;
- ADD_SPACE_RET(sp, bp, blen, len);
- memmove(p, t, tlen);
- p += tlen;
- F_SET(excp, E_MODIFY);
- break;
- case '#':
- /*
- * Try the alternate file name first, then the
- * previously edited file.
- */
- if (sp->alt_name == NULL && (sp->p_frp == NULL ||
- sp->frp->cname == NULL && sp->frp->name == NULL)) {
- msgq(sp, M_ERR,
- "No filename to substitute for #.");
- return (1);
- }
- if (sp->alt_name != NULL)
- t = sp->alt_name;
- else
- t = FILENAME(sp->frp);
- len += tlen = strlen(t);
- ADD_SPACE_RET(sp, bp, blen, len);
- memmove(p, t, tlen);
- p += tlen;
- F_SET(excp, E_MODIFY);
- break;
- case '\\':
- /*
- * QUOTING NOTE:
- *
- * Strip any backslashes that protected the file
- * expansion characters.
- */
- if (cmdlen > 1 && cmd[1] == '%' || cmd[1] == '#')
- ++cmd;
- /* FALLTHROUGH */
- default:
-ins_ch: ++len;
- ADD_SPACE_RET(sp, bp, blen, len);
- *p++ = *cmd;
- }
-
- /* Nul termination. */
- ++len;
- ADD_SPACE_RET(sp, bp, blen, len);
- *p = '\0';
-
- /* Return the new string length, buffer, buffer length. */
- *lenp = len - 1;
- *bpp = bp;
- *blenp = blen;
- return (0);
-}
-
-/*
- * argv_alloc --
- * Make more space for arguments.
- */
-static int
-argv_alloc(sp, len)
- SCR *sp;
- size_t len;
-{
- ARGS *ap;
- EX_PRIVATE *exp;
- int cnt, off;
-
- /*
- * Allocate room for another argument, always leaving
- * enough room for an ARGS structure with a length of 0.
- */
-#define INCREMENT 20
- exp = EXP(sp);
- off = exp->argsoff;
- if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) {
- cnt = exp->argscnt + INCREMENT;
- REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *));
- if (exp->args == NULL) {
- (void)argv_free(sp);
- goto mem;
- }
- memset(&exp->args[off], 0, INCREMENT * sizeof(ARGS *));
- exp->argscnt = cnt;
- }
-
- /* First argument. */
- if (exp->args[off] == NULL) {
- CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
- if (exp->args[off] == NULL)
- goto mem;
- }
-
- /* First argument buffer. */
- ap = exp->args[off];
- ap->len = 0;
- if (ap->blen < len + 1) {
- ap->blen = len + 1;
- REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T));
- if (ap->bp == NULL) {
- ap->bp = NULL;
- ap->blen = 0;
- F_CLR(ap, A_ALLOCATED);
-mem: msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(ap, A_ALLOCATED);
- }
-
- /* Second argument. */
- if (exp->args[++off] == NULL) {
- CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
- if (exp->args[off] == NULL)
- goto mem;
- }
- /* 0 length serves as end-of-argument marker. */
- exp->args[off]->len = 0;
- return (0);
-}
-
-/*
- * argv_free --
- * Free up argument structures.
- */
-int
-argv_free(sp)
- SCR *sp;
-{
- EX_PRIVATE *exp;
- int off;
-
- exp = EXP(sp);
- if (exp->args != NULL) {
- for (off = 0; off < exp->argscnt; ++off) {
- if (exp->args[off] == NULL)
- continue;
- if (F_ISSET(exp->args[off], A_ALLOCATED))
- free(exp->args[off]->bp);
- FREE(exp->args[off], sizeof(ARGS));
- }
- FREE(exp->args, exp->argscnt * sizeof(ARGS *));
- }
- exp->args = NULL;
- exp->argscnt = 0;
- exp->argsoff = 0;
- return (0);
-}
-
-/*
- * argv_sexp --
- * Fork a shell, pipe a command through it, and read the output into
- * a buffer.
- */
-static int
-argv_sexp(sp, bpp, blenp, lenp)
- SCR *sp;
- char **bpp;
- size_t *blenp, *lenp;
-{
- FILE *ifp;
- pid_t pid;
- size_t blen, len;
- int ch, rval, output[2];
- char *bp, *p, *sh, *sh_path;
-
- bp = *bpp;
- blen = *blenp;
-
- sh_path = O_STR(sp, O_SHELL);
- if ((sh = strrchr(sh_path, '/')) == NULL)
- sh = sh_path;
- else
- ++sh;
-
- /*
- * There are two different processes running through this code.
- * They are named the utility and the parent. The utility reads
- * from standard input and writes to the parent. The parent reads
- * from the utility and writes into the buffer. The parent reads
- * from output[0], and the utility writes to output[1].
- */
- if (pipe(output) < 0) {
- msgq(sp, M_SYSERR, "pipe");
- return (1);
- }
- if ((ifp = fdopen(output[0], "r")) == NULL) {
- msgq(sp, M_SYSERR, "fdopen");
- goto err;
- }
-
- /*
- * Do the minimal amount of work possible, the shell is going
- * to run briefly and then exit. Hopefully.
- */
- switch (pid = vfork()) {
- case -1: /* Error. */
- msgq(sp, M_SYSERR, "vfork");
-err: (void)close(output[0]);
- (void)close(output[1]);
- return (1);
- case 0: /* Utility. */
- /* Redirect stdout/stderr to the write end of the pipe. */
- (void)dup2(output[1], STDOUT_FILENO);
- (void)dup2(output[1], STDERR_FILENO);
-
- /* Close the utility's file descriptors. */
- (void)close(output[0]);
- (void)close(output[1]);
-
- /* Assumes that all shells have -c. */
- execl(sh_path, sh, "-c", bp, NULL);
- msgq(sp, M_ERR,
- "Error: execl: %s: %s", sh_path, strerror(errno));
- _exit(127);
- default:
- /* Close the pipe end the parent won't use. */
- (void)close(output[1]);
- break;
- }
-
- rval = 0;
-
- /*
- * Copy process output into a buffer.
- *
- * !!!
- * Historic vi apparently discarded leading \n and \r's from
- * the shell output stream. We don't on the grounds that any
- * shell that does that is broken.
- */
- for (p = bp, len = 0, ch = EOF;
- (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len)
- if (blen < 5) {
- ADD_SPACE_GOTO(sp, bp, blen, *blenp * 2);
- p = bp + len;
- blen = *blenp - len;
- }
-
- /* Delete the final newline, nul terminate the string. */
- if (p > bp && p[-1] == '\n' || p[-1] == '\r') {
- --len;
- *--p = '\0';
- } else
- *p = '\0';
- *lenp = len;
-
- if (ferror(ifp)) {
- msgq(sp, M_ERR, "I/O error: %s", sh);
-binc_err: rval = 1;
- }
- (void)fclose(ifp);
-
- *bpp = bp; /* *blenp is already updated. */
-
- /* Wait for the process. */
- return (proc_wait(sp, (long)pid, sh, 0) | rval);
-}
diff --git a/usr.bin/vi/nex/ex_at.c b/usr.bin/vi/nex/ex_at.c
deleted file mode 100644
index 51d001f304a7..000000000000
--- a/usr.bin/vi/nex/ex_at.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_at.c 8.16 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_at -- :@[@ | buffer]
- * :*[* | buffer]
- *
- * Execute the contents of the buffer.
- */
-int
-ex_at(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- CB *cbp;
- EX_PRIVATE *exp;
- TEXT *tp;
- int name, lmode;
-
- exp = EXP(sp);
-
- /* Historically, @@ and ** execute the last buffer. */
- name = cmdp->buffer;
- if (name == cmdp->cmd->name[0]) {
- if (!exp->at_lbuf_set) {
- msgq(sp, M_ERR, "No previous buffer to execute.");
- return (1);
- }
- name = exp->at_lbuf;
- }
-
- CBNAME(sp, cbp, name);
- if (cbp == NULL) {
- msgq(sp, M_ERR, "Buffer %s is empty.", charname(sp, name));
- return (1);
- }
-
- /* Save for reuse. */
- exp->at_lbuf = name;
- exp->at_lbuf_set = 1;
-
- /*
- * If the buffer was cut in line mode or had portions of more
- * than one line, <newlines> are appended to each line as it
- * is pushed onto the stack.
- */
- tp = cbp->textq.cqh_last;
- lmode = F_ISSET(cbp, CB_LMODE) || tp->q.cqe_prev != (void *)&cbp->textq;
- for (; tp != (void *)&cbp->textq; tp = tp->q.cqe_prev)
- if ((lmode || tp->q.cqe_prev != (void *)&cbp->textq) &&
- term_push(sp, "\n", 1, 0, 0) ||
- term_push(sp, tp->lb, tp->len, 0, CH_QUOTED))
- return (1);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_bang.c b/usr.bin/vi/nex/ex_bang.c
deleted file mode 100644
index 4f7222b4e78c..000000000000
--- a/usr.bin/vi/nex/ex_bang.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_bang.c 8.22 (Berkeley) 12/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "sex/sex_screen.h"
-
-/*
- * ex_bang -- :[line [,line]] ! command
- *
- * Pass the rest of the line after the ! character to the program named by
- * the O_SHELL option.
- *
- * Historical vi did NOT do shell expansion on the arguments before passing
- * them, only file name expansion. This means that the O_SHELL program got
- * "$t" as an argument if that is what the user entered. Also, there's a
- * special expansion done for the bang command. Any exclamation points in
- * the user's argument are replaced by the last, expanded ! command.
- *
- * There's some fairly amazing slop in this routine to make the different
- * ways of getting here display the right things. It took a long time to
- * get get right (wrong?), so be careful.
- */
-int
-ex_bang(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- enum filtertype ftype;
- ARGS *ap;
- EX_PRIVATE *exp;
- MARK rm;
- recno_t lno;
- size_t blen;
- int rval;
- char *bp, *msg;
-
-
- ap = cmdp->argv[0];
- if (ap->len == 0) {
- msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
- return (1);
- }
-
- /* Swap commands. */
- exp = EXP(sp);
- if (exp->lastbcomm != NULL)
- FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1);
- if ((exp->lastbcomm = strdup(ap->bp)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
-
- /*
- * If the command was modified by the expansion, we redisplay it.
- * Redisplaying it in vi mode is tricky, and handled separately
- * in each case below. If we're in ex mode, it's easy, so we just
- * do it here.
- */
- bp = NULL;
- if (F_ISSET(cmdp, E_MODIFY)) {
- if (IN_EX_MODE(sp)) {
- (void)ex_printf(EXCOOKIE, "!%s\n", ap->bp);
- (void)ex_fflush(EXCOOKIE);
- }
- /*
- * Vi: Display the command if modified. Historic vi displayed
- * the command if it was modified due to file name and/or bang
- * expansion. If piping lines, it was immediately overwritten
- * by any error or line change reporting. We don't the user to
- * have to page through the responses, so we only post it until
- * it's erased by something else. Otherwise, pass it on to the
- * ex_exec_proc routine to display after the screen has been
- * cleaned up.
- */
- if (IN_VI_MODE(sp)) {
- GET_SPACE_RET(sp, bp, blen, ap->len + 2);
- bp[0] = '!';
- memmove(bp + 1, ap->bp, ap->len + 1);
- }
- }
-
- /*
- * If addresses were specified, pipe lines from the file through
- * the command.
- */
- if (cmdp->addrcnt != 0) {
- if (bp != NULL) {
- (void)sp->s_busy(sp, bp);
- FREE_SPACE(sp, bp, blen);
- }
- /*
- * !!!
- * Historical vi permitted "!!" in an empty file. When it
- * happens, we get called with two addresses of 1,1 and a
- * bad attitude.
- */
- ftype = FILTER;
- if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0) {
- cmdp->addr1.lno = cmdp->addr2.lno = 0;
- ftype = FILTER_READ;
- }
- }
- if (filtercmd(sp, ep,
- &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype))
- return (1);
- sp->lno = rm.lno;
- F_SET(exp, EX_AUTOPRINT);
- return (0);
- }
-
- /*
- * If no addresses were specified, run the command. If the file
- * has been modified and autowrite is set, write the file back.
- * If the file has been modified, autowrite is not set and the
- * warn option is set, tell the user about the file.
- */
- msg = "\n";
- if (F_ISSET(ep, F_MODIFIED))
- if (O_ISSET(sp, O_AUTOWRITE)) {
- if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) {
- rval = 1;
- goto ret;
- }
- } else if (O_ISSET(sp, O_WARN))
- if (IN_VI_MODE(sp) && F_ISSET(cmdp, E_MODIFY))
- msg = "\nFile modified since last write.\n";
- else
- msg = "File modified since last write.\n";
-
- /* Run the command. */
- rval = ex_exec_proc(sp, ap->bp, bp, msg);
-
- /* Ex terminates with a bang. */
- if (IN_EX_MODE(sp))
- (void)write(STDOUT_FILENO, "!\n", 2);
-
- /* Vi requires user permission to continue. */
- if (IN_VI_MODE(sp))
- F_SET(sp, S_CONTINUE);
-
- /* Free the extra space. */
-ret: if (bp != NULL)
- FREE_SPACE(sp, bp, blen);
-
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_cd.c b/usr.bin/vi/nex/ex_cd.c
deleted file mode 100644
index 6b51bc51c15e..000000000000
--- a/usr.bin/vi/nex/ex_cd.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_cd.c 8.3 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_cd -- :cd[!] [directory]
- * Change directories.
- */
-int
-ex_cd(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- char *dir, buf[MAXPATHLEN];
-
- switch (cmdp->argc) {
- case 0:
- if ((dir = getenv("HOME")) == NULL) {
- msgq(sp, M_ERR,
- "Environment variable HOME not set.");
- return (1);
- }
- break;
- case 1:
- dir = cmdp->argv[0]->bp;
- break;
- default:
- abort();
- }
-
- if (chdir(dir) < 0) {
- msgq(sp, M_SYSERR, dir);
- return (1);
- }
- if (getcwd(buf, sizeof(buf)) != NULL)
- msgq(sp, M_INFO, "New directory: %s", buf);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_delete.c b/usr.bin/vi/nex/ex_delete.c
deleted file mode 100644
index 5b737e8f547d..000000000000
--- a/usr.bin/vi/nex/ex_delete.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_delete.c 8.6 (Berkeley) 1/11/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags]
- *
- * Delete lines from the file.
- */
-int
-ex_delete(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- recno_t lno;
-
- /* Yank the lines. */
- if (cut(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
- &cmdp->addr1, &cmdp->addr2, CUT_DELETE | CUT_LINEMODE))
- return (1);
-
- /* Delete the lines. */
- if (delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1))
- return (1);
-
- /* Set the cursor to the line after the last line deleted. */
- sp->lno = cmdp->addr1.lno;
-
- /* Or the last line in the file if deleted to the end of the file. */
- if (file_lline(sp, ep, &lno))
- return (1);
- if (sp->lno > lno)
- sp->lno = lno;
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_digraph.c b/usr.bin/vi/nex/ex_digraph.c
deleted file mode 100644
index 20f1bf327ded..000000000000
--- a/usr.bin/vi/nex/ex_digraph.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_digraph.c 8.4 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#ifndef NO_DIGRAPH
-#include <sys/types.h>
-
-#include <curses.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-static void do_digraph __P((SCR *, EXF *, int, u_char *));
-
-/* This stuff is used to build the default digraphs table. */
-static u_char digtable[][4] = {
-# ifdef CS_IBMPC
- "C,\200", "u\"\1", "e'\2", "a^\3",
- "a\"\4", "a`\5", "a@\6", "c,\7",
- "e^\10", "e\"\211", "e`\12", "i\"\13",
- "i^\14", "i`\15", "A\"\16", "A@\17",
- "E'\20", "ae\21", "AE\22", "o^\23",
- "o\"\24", "o`\25", "u^\26", "u`\27",
- "y\"\30", "O\"\31", "U\"\32", "a'\240",
- "i'!", "o'\"", "u'#", "n~$",
- "N~%", "a-&", "o-'", "~?(",
- "~!-", "\"<.", "\">/",
-# ifdef CS_SPECIAL
- "2/+", "4/,", "^+;", "^q<",
- "^c=", "^r>", "^t?", "pp]",
- "^^^", "oo_", "*a`", "*ba",
- "*pc", "*Sd", "*se", "*uf",
- "*tg", "*Ph", "*Ti", "*Oj",
- "*dk", "*Hl", "*hm", "*En",
- "*No", "eqp", "pmq", "ger",
- "les", "*It", "*iu", "*/v",
- "*=w", "sq{", "^n|", "^2}",
- "^3~", "^_\377",
-# endif /* CS_SPECIAL */
-# endif /* CS_IBMPC */
-# ifdef CS_LATIN1
- "~!!", "a-*", "\">+", "o-:",
- "\"<>", "~??",
-
- "A`@", "A'A", "A^B", "A~C",
- "A\"D", "A@E", "AEF", "C,G",
- "E`H", "E'I", "E^J", "E\"K",
- "I`L", "I'M", "I^N", "I\"O",
- "-DP", "N~Q", "O`R", "O'S",
- "O^T", "O~U", "O\"V", "O/X",
- "U`Y", "U'Z", "U^[", "U\"\\",
- "Y'_",
-
- "a``", "a'a", "a^b", "a~c",
- "a\"d", "a@e", "aef", "c,g",
- "e`h", "e'i", "e^j", "e\"k",
- "i`l", "i'm", "i^n", "i\"o",
- "-dp", "n~q", "o`r", "o's",
- "o^t", "o~u", "o\"v", "o/x",
- "u`y", "u'z", "u^{", "u\"|",
- "y'~",
-# endif /* CS_LATIN1 */
- ""
-};
-
-int
-digraph_init(sp)
- SCR *sp;
-{
- int i;
-
- for (i = 0; *digtable[i]; i++)
- do_digraph(sp, NULL, 0, digtable[i]);
- do_digraph(sp, NULL, 0, NULL);
- return (0);
-}
-
-int
-ex_digraph(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- do_digraph(sp, ep, F_ISSET(cmdp, E_FORCE), cmdp->argv[0]->bp);
- return (0);
-}
-
-static struct _DIG
-{
- struct _DIG *next;
- char key1;
- char key2;
- char dig;
- char save;
-} *digs;
-
-int
-digraph(sp, key1, key2)
- SCR *sp;
- char key1; /* the underlying character */
- char key2; /* the second character */
-{
- int new_key;
- register struct _DIG *dp;
-
- /* if digraphs are disabled, then just return the new char */
- if (O_ISSET(sp, O_DIGRAPH))
- {
- return key2;
- }
-
- /* remember the new key, so we can return it if this isn't a digraph */
- new_key = key2;
-
- /* sort key1 and key2, so that their original order won't matter */
- if (key1 > key2)
- {
- key2 = key1;
- key1 = new_key;
- }
-
- /* scan through the digraph chart */
- for (dp = digs;
- dp && (dp->key1 != key1 || dp->key2 != key2);
- dp = dp->next)
- {
- }
-
- /* if this combination isn't in there, just use the new key */
- if (!dp)
- {
- return new_key;
- }
-
- /* else use the digraph key */
- return dp->dig;
-}
-
-/* this function lists or defines digraphs */
-static void
-do_digraph(sp, ep, bang, extra)
- SCR *sp;
- EXF *ep;
- int bang;
- u_char *extra;
-{
- int dig;
- register struct _DIG *dp;
- struct _DIG *prev;
- static int user_defined = 0; /* boolean: are all later digraphs user-defined? */
- char listbuf[8];
-
- /* if "extra" is NULL, then we've reached the end of the built-ins */
- if (!extra)
- {
- user_defined = 1;
- return;
- }
-
- /* if no args, then display the existing digraphs */
- if (*extra < ' ')
- {
- listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
- listbuf[7] = '\0';
- for (dig = 0, dp = digs; dp; dp = dp->next)
- {
- if (dp->save || bang)
- {
- dig += 7;
- if (dig >= sp->cno)
- {
- addch('\n');
- refresh();
- dig = 7;
- }
- listbuf[3] = dp->key1;
- listbuf[4] = dp->key2;
- listbuf[6] = dp->dig;
- addstr(listbuf);
- }
- }
- addch('\n');
- refresh();
- return;
- }
-
- /* make sure we have at least two characters */
- if (!extra[1])
- {
- msgq(sp, M_ERR,
- "Digraphs must be composed of two characters");
- return;
- }
-
- /* sort key1 and key2, so that their original order won't matter */
- if (extra[0] > extra[1])
- {
- dig = extra[0];
- extra[0] = extra[1];
- extra[1] = dig;
- }
-
- /* locate the new digraph character */
- for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
- {
- }
- dig = extra[dig];
- if (!bang && dig)
- {
- dig |= 0x80;
- }
-
- /* search for the digraph */
- for (prev = (struct _DIG *)0, dp = digs;
- dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
- prev = dp, dp = dp->next)
- {
- }
-
- /* deleting the digraph? */
- if (!dig)
- {
- if (!dp)
- {
-#ifndef CRUNCH
- msgq(sp, M_ERR,
- "%c%c not a digraph", extra[0], extra[1]);
-#endif
- return;
- }
- if (prev)
- prev->next = dp->next;
- else
- digs = dp->next;
- free(dp);
- return;
- }
-
- /* if necessary, create a new digraph struct for the new digraph */
- if (dig && !dp)
- {
- MALLOC(sp, dp, struct _DIG *, sizeof(struct _DIG));
- if (dp == NULL)
- return;
- if (prev)
- prev->next = dp;
- else
- digs = dp;
- dp->next = (struct _DIG *)0;
- }
-
- /* assign it the new digraph value */
- dp->key1 = extra[0];
- dp->key2 = extra[1];
- dp->dig = dig;
- dp->save = user_defined;
-}
-
-void
-digraph_save(sp, fd)
- SCR *sp;
- int fd;
-{
- static char buf[] = "digraph! XX Y\n";
- register struct _DIG *dp;
-
- for (dp = digs; dp; dp = dp->next)
- {
- if (dp->save)
- {
- buf[9] = dp->key1;
- buf[10] = dp->key2;
- buf[12] = dp->dig;
- write(fd, buf, (unsigned)14);
- }
- }
-}
-#endif
diff --git a/usr.bin/vi/nex/ex_display.c b/usr.bin/vi/nex/ex_display.c
deleted file mode 100644
index 0cfef42f675b..000000000000
--- a/usr.bin/vi/nex/ex_display.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_display.c 8.14 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <string.h>
-
-#include "vi.h"
-#include "tag.h"
-#include "excmd.h"
-
-static int bdisplay __P((SCR *, EXF *));
-static void db __P((SCR *, CB *, char *));
-
-/*
- * ex_display -- :display b[uffers] | s[creens] | t[ags]
- *
- * Display buffers, tags or screens.
- */
-int
-ex_display(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- switch (cmdp->argv[0]->bp[0]) {
- case 'b':
- return (bdisplay(sp, ep));
- case 's':
- return (ex_sdisplay(sp, ep));
- case 't':
- return (ex_tagdisplay(sp, ep));
- }
- msgq(sp, M_ERR,
- "Unknown display argument %s, use b[uffers], s[creens], or t[ags].",
- cmdp->argv[0]);
- return (1);
-}
-
-/*
- * bdisplay --
- *
- * Display buffers.
- */
-static int
-bdisplay(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- CB *cbp;
-
- if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) {
- (void)ex_printf(EXCOOKIE, "No cut buffers to display.");
- return (0);
- }
-
- /* Buffers can be infinitely long, make it interruptible. */
- F_SET(sp, S_INTERRUPTIBLE);
-
- /* Display regular cut buffers. */
- for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
- if (isdigit(cbp->name))
- continue;
- if (cbp->textq.cqh_first != (void *)&cbp->textq)
- db(sp, cbp, NULL);
- if (F_ISSET(sp, S_INTERRUPTED))
- return (0);
- }
- /* Display numbered buffers. */
- for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
- if (!isdigit(cbp->name))
- continue;
- if (cbp->textq.cqh_first != (void *)&cbp->textq)
- db(sp, cbp, NULL);
- if (F_ISSET(sp, S_INTERRUPTED))
- return (0);
- }
- /* Display default buffer. */
- if ((cbp = sp->gp->dcbp) != NULL)
- db(sp, cbp, "default buffer");
- return (0);
-}
-
-/*
- * db --
- * Display a buffer.
- */
-static void
-db(sp, cbp, name)
- SCR *sp;
- CB *cbp;
- char *name;
-{
- TEXT *tp;
- size_t len;
- char *p;
-
- (void)ex_printf(EXCOOKIE, "********** %s%s\n",
- name == NULL ? charname(sp, cbp->name) : name,
- F_ISSET(cbp, CB_LMODE) ? " (line mode)" : "");
- for (tp = cbp->textq.cqh_first;
- tp != (void *)&cbp->textq; tp = tp->q.cqe_next) {
- for (len = tp->len, p = tp->lb; len--;) {
- (void)ex_printf(EXCOOKIE, "%s", charname(sp, *p++));
- if (F_ISSET(sp, S_INTERRUPTED))
- return;
- }
- (void)ex_printf(EXCOOKIE, "\n");
- }
-}
diff --git a/usr.bin/vi/nex/ex_edit.c b/usr.bin/vi/nex/ex_edit.c
deleted file mode 100644
index eeafedaed778..000000000000
--- a/usr.bin/vi/nex/ex_edit.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_edit.c 8.14 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_edit -- :e[dit][!] [+cmd] [file]
- * :vi[sual][!] [+cmd] [file]
- *
- * Edit a file; if none specified, re-edit the current file. The second
- * form of the command can only be executed while in vi mode. See the
- * hack in ex.c:ex_cmd().
- *
- * !!!
- * Historic vi didn't permit the '+' command form without specifying
- * a file name as well.
- */
-int
-ex_edit(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- ARGS *ap;
- FREF *frp;
-
- frp = sp->frp;
- switch (cmdp->argc) {
- case 0:
- /*
- * If the name has been changed, we edit that file, not the
- * original name. If the user was editing a temporary file,
- * create another one. The reason for this is that we do
- * special exit processing of temporary files, and reusing
- * them is tricky.
- */
- if (frp->cname != NULL) {
- if ((frp = file_add(sp, frp, frp->cname, 1)) == NULL)
- return (1);
- set_alt_name(sp, sp->frp->cname);
- } else if (frp->name == NULL)
- if ((frp = file_add(sp, frp, NULL, 1)) == NULL)
- return (1);
- break;
- case 1:
- ap = cmdp->argv[0];
- if ((frp = file_add(sp, sp->frp, ap->bp, 1)) == NULL)
- return (1);
- set_alt_name(sp, ap->bp);
- break;
- default:
- abort();
- }
-
- /*
- * Check for modifications.
- *
- * !!!
- * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit.
- */
- if (F_ISSET(ep, F_MODIFIED) &&
- ep->refcnt <= 1 && !F_ISSET(cmdp, E_FORCE)) {
- msgq(sp, M_ERR,
- "Modified since last write; write or use ! to override.");
- return (1);
- }
-
- /* Switch files. */
- if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
- return (1);
- F_SET(sp, S_FSWITCH);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_equal.c b/usr.bin/vi/nex/ex_equal.c
deleted file mode 100644
index f0a18bef41f4..000000000000
--- a/usr.bin/vi/nex/ex_equal.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_equal.c 8.4 (Berkeley) 11/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_equal -- :address =
- * Print out the line number matching the specified address, or the
- * last line number in the file if no address specified.
- */
-int
-ex_equal(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- recno_t lno;
-
- if (F_ISSET(cmdp, E_ADDRDEF)) {
- if (file_lline(sp, ep, &lno))
- return (1);
- (void)ex_printf(EXCOOKIE, "%ld\n", lno);
- } else
- (void)ex_printf(EXCOOKIE, "%ld\n", cmdp->addr1.lno);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_exit.c b/usr.bin/vi/nex/ex_exit.c
deleted file mode 100644
index b0f929a5bbe3..000000000000
--- a/usr.bin/vi/nex/ex_exit.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_exit.c 8.7 (Berkeley) 12/10/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_quit -- :quit[!]
- * Quit.
- */
-int
-ex_quit(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- int force;
-
- force = F_ISSET(cmdp, E_FORCE);
-
- /* Check for modifications. */
- if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) {
- msgq(sp, M_ERR,
- "Modified since last write; write or use ! to override.");
- return (1);
- }
-
- /*
- * !!!
- * Historic practice: quit! or two quit's done in succession
- * (where ZZ counts as a quit) didn't check for other files.
- *
- * Also check for related screens; if they exist, quit, the
- * user will get the message on the last screen.
- */
- if (!force && sp->ccnt != sp->q_ccnt + 1 &&
- ep->refcnt <= 1 && file_unedited(sp) != NULL) {
- sp->q_ccnt = sp->ccnt;
- msgq(sp, M_ERR,
- "More files; use \":n\" to go to the next file, \":q!\" to quit.");
- return (1);
- }
-
- F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_file.c b/usr.bin/vi/nex/ex_file.c
deleted file mode 100644
index d556d5214e0e..000000000000
--- a/usr.bin/vi/nex/ex_file.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_file.c 8.7 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_file -- :f[ile] [name]
- * Status line and change the file's name.
- */
-int
-ex_file(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- FREF *frp;
- char *p, *t;
-
- switch (cmdp->argc) {
- case 0:
- break;
- case 1:
- frp = sp->frp;
-
- /* Make sure can allocate enough space. */
- if ((p = strdup(cmdp->argv[0]->bp)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
-
- /* If already have a file name, it becomes the alternate. */
- if ((t = FILENAME(frp)) != NULL)
- set_alt_name(sp, t);
-
- /* Free any previously changed name. */
- if (frp->cname != NULL)
- free(frp->cname);
- frp->cname = p;
-
- /* The read-only bit follows the file name; clear it. */
- F_CLR(frp, FR_RDONLY);
-
- /* Have to force a write if the file exists, next time. */
- F_CLR(frp, FR_CHANGEWRITE);
- break;
- default:
- abort();
- }
- status(sp, ep, sp->lno, 1);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_global.c b/usr.bin/vi/nex/ex_global.c
deleted file mode 100644
index 4f942a39f680..000000000000
--- a/usr.bin/vi/nex/ex_global.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_global.c 8.29 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "interrupt.h"
-
-enum which {GLOBAL, VGLOBAL};
-
-static int global __P((SCR *, EXF *, EXCMDARG *, enum which));
-static void global_intr __P((int));
-
-/*
- * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
- * Exec on lines matching a pattern.
- */
-int
-ex_global(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (global(sp, ep,
- cmdp, F_ISSET(cmdp, E_FORCE) ? VGLOBAL : GLOBAL));
-}
-
-/*
- * ex_vglobal -- [line [,line]] v[global] /pattern/ [commands]
- * Exec on lines not matching a pattern.
- */
-int
-ex_vglobal(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (global(sp, ep, cmdp, VGLOBAL));
-}
-
-static int
-global(sp, ep, cmdp, cmd)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which cmd;
-{
- DECLARE_INTERRUPTS;
- RANGE *rp;
- EX_PRIVATE *exp;
- recno_t elno, lno;
- regmatch_t match[1];
- regex_t *re, lre;
- size_t clen, len;
- int delim, eval, reflags, replaced, rval;
- char *cb, *ptrn, *p, *t;
-
- /*
- * Skip leading white space. Historic vi allowed any non-
- * alphanumeric to serve as the global command delimiter.
- */
- for (p = cmdp->argv[0]->bp; isblank(*p); ++p);
- if (*p == '\0' || isalnum(*p)) {
- msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
- return (1);
- }
- delim = *p++;
-
- /*
- * Get the pattern string, toss escaped characters.
- *
- * QUOTING NOTE:
- * Only toss an escaped character if it escapes a delimiter.
- */
- for (ptrn = t = p;;) {
- if (p[0] == '\0' || p[0] == delim) {
- if (p[0] == delim)
- ++p;
- /*
- * !!!
- * Nul terminate the pattern string -- it's passed
- * to regcomp which doesn't understand anything else.
- */
- *t = '\0';
- break;
- }
- if (p[0] == '\\' && p[1] == delim)
- ++p;
- *t++ = *p++;
- }
-
- /* If the pattern string is empty, use the last one. */
- if (*ptrn == '\0') {
- if (!F_ISSET(sp, S_SRE_SET)) {
- msgq(sp, M_ERR, "No previous regular expression.");
- return (1);
- }
- re = &sp->sre;
- } else {
- /* Set RE flags. */
- reflags = 0;
- if (O_ISSET(sp, O_EXTENDED))
- reflags |= REG_EXTENDED;
- if (O_ISSET(sp, O_IGNORECASE))
- reflags |= REG_ICASE;
-
- /* Convert vi-style RE's to POSIX 1003.2 RE's. */
- if (re_conv(sp, &ptrn, &replaced))
- return (1);
-
- /* Compile the RE. */
- re = &lre;
- eval = regcomp(re, ptrn, reflags);
-
- /* Free up any allocated memory. */
- if (replaced)
- free(ptrn);
-
- if (eval) {
- re_error(sp, eval, re);
- return (1);
- }
-
- /*
- * Set saved RE. Historic practice is that
- * globals set direction as well as the RE.
- */
- sp->sre = lre;
- sp->searchdir = FORWARD;
- F_SET(sp, S_SRE_SET);
- }
-
- /* Get a copy of the command string. */
- if ((clen = strlen(p)) == 0) {
- msgq(sp, M_ERR, "No command string specified.");
- return (1);
- }
- MALLOC_RET(sp, cb, char *, clen);
- memmove(cb, p, clen);
-
- /*
- * The global commands sets the substitute RE as well as
- * the everything-else RE.
- */
- sp->subre = sp->sre;
- F_SET(sp, S_SUBRE_SET);
-
- /* Set the global flag, and set up interrupts. */
- F_SET(sp, S_GLOBAL);
- SET_UP_INTERRUPTS(global_intr);
-
- /*
- * For each line... The semantics of global matching are that we first
- * have to decide which lines are going to get passed to the command,
- * and then pass them to the command, ignoring other changes. There's
- * really no way to do this in a single pass, since arbitrary line
- * creation, deletion and movement can be done in the ex command. For
- * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d".
- * What we do is create linked list of lines that are tracked through
- * each ex command. There's a callback routine which the DB interface
- * routines call when a line is created or deleted. This doesn't help
- * the layering much.
- */
- exp = EXP(sp);
- for (rval = 0, lno = cmdp->addr1.lno,
- elno = cmdp->addr2.lno; lno <= elno; ++lno) {
- /* Someone's unhappy, time to stop. */
- if (F_ISSET(sp, S_INTERRUPTED))
- goto interrupted;
-
- /* Get the line and search for a match. */
- if ((t = file_gline(sp, ep, lno, &len)) == NULL) {
- GETLINE_ERR(sp, lno);
- goto err;
- }
- match[0].rm_so = 0;
- match[0].rm_eo = len;
- switch(eval = regexec(re, t, 1, match, REG_STARTEND)) {
- case 0:
- if (cmd == VGLOBAL)
- continue;
- break;
- case REG_NOMATCH:
- if (cmd == GLOBAL)
- continue;
- break;
- default:
- re_error(sp, eval, re);
- goto err;
- }
-
- /* If follows the last entry, extend the last entry's range. */
- if ((rp = exp->rangeq.cqh_last) != (void *)&exp->rangeq &&
- rp->stop == lno - 1) {
- ++rp->stop;
- continue;
- }
-
- /* Allocate a new range, and append it to the list. */
- CALLOC(sp, rp, RANGE *, 1, sizeof(RANGE));
- if (rp == NULL)
- goto err;
- rp->start = rp->stop = lno;
- CIRCLEQ_INSERT_TAIL(&exp->rangeq, rp, q);
- }
-
- exp = EXP(sp);
- exp->range_lno = OOBLNO;
- for (;;) {
- /*
- * Start at the beginning of the range each time, it may have
- * been changed (or exhausted) if lines were inserted/deleted.
- */
- if ((rp = exp->rangeq.cqh_first) == (void *)&exp->rangeq)
- break;
- if (rp->start > rp->stop) {
- CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
- free(rp);
- continue;
- }
-
- /*
- * Execute the command, setting the cursor to the line so that
- * relative addressing works. This means that the cursor moves
- * to the last line sent to the command, by default, even if
- * the command fails.
- */
- exp->range_lno = sp->lno = rp->start++;
- if (ex_cmd(sp, ep, cb, clen))
- goto err;
-
- /* Someone's unhappy, time to stop. */
- if (F_ISSET(sp, S_INTERRUPTED)) {
-interrupted: msgq(sp, M_INFO, "Interrupted.");
- break;
- }
- }
-
- /* Set the cursor to the new value, making sure it exists. */
- if (exp->range_lno != OOBLNO) {
- if (file_lline(sp, ep, &lno))
- return (1);
- sp->lno =
- lno < exp->range_lno ? (lno ? lno : 1) : exp->range_lno;
- }
- if (0) {
-err: rval = 1;
- }
-
-interrupt_err:
- F_CLR(sp, S_GLOBAL);
- TEAR_DOWN_INTERRUPTS;
-
- /* Free any remaining ranges and the command buffer. */
- while ((rp = exp->rangeq.cqh_first) != (void *)&exp->rangeq) {
- CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
- free(rp);
- }
- free(cb);
- return (rval);
-}
-
-/*
- * global_insdel --
- * Update the ranges based on an insertion or deletion.
- */
-void
-global_insdel(sp, ep, op, lno)
- SCR *sp;
- EXF *ep;
- enum operation op;
- recno_t lno;
-{
- EX_PRIVATE *exp;
- RANGE *nrp, *rp;
-
- exp = EXP(sp);
-
- switch (op) {
- case LINE_APPEND:
- return;
- case LINE_DELETE:
- for (rp = exp->rangeq.cqh_first;
- rp != (void *)&exp->rangeq; rp = nrp) {
- nrp = rp->q.cqe_next;
- /* If range less than the line, ignore it. */
- if (rp->stop < lno)
- continue;
- /* If range greater than the line, decrement range. */
- if (rp->start > lno) {
- --rp->start;
- --rp->stop;
- continue;
- }
- /* Lno is inside the range, decrement the end point. */
- if (rp->start > --rp->stop) {
- CIRCLEQ_REMOVE(&exp->rangeq, rp, q);
- free(rp);
- }
- }
- break;
- case LINE_INSERT:
- for (rp = exp->rangeq.cqh_first;
- rp != (void *)&exp->rangeq; rp = rp->q.cqe_next) {
- /* If range less than the line, ignore it. */
- if (rp->stop < lno)
- continue;
- /* If range greater than the line, increment range. */
- if (rp->start >= lno) {
- ++rp->start;
- ++rp->stop;
- continue;
- }
- /*
- * Lno is inside the range, so the range must be split.
- * Since we're inserting a new element, neither range
- * can be exhausted.
- */
- CALLOC(sp, nrp, RANGE *, 1, sizeof(RANGE));
- if (nrp == NULL) {
- F_SET(sp, S_INTERRUPTED);
- return;
- }
- nrp->start = lno + 1;
- nrp->stop = rp->stop + 1;
- rp->stop = lno - 1;
- CIRCLEQ_INSERT_AFTER(&exp->rangeq, rp, nrp, q);
- rp = nrp;
- }
- break;
- case LINE_RESET:
- return;
- }
- /*
- * If the command deleted/inserted lines, the cursor moves to
- * the line after the deleted/inserted line.
- */
- exp->range_lno = lno;
-}
-
-/*
- * global_intr --
- * Set the interrupt bit in any screen that is running an interruptible
- * global.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one global running, it will be hard to decide which one to
- * stop.
- */
-static void
-global_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_GLOBAL) && F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
diff --git a/usr.bin/vi/nex/ex_init.c b/usr.bin/vi/nex/ex_init.c
deleted file mode 100644
index 26acf2f44c92..000000000000
--- a/usr.bin/vi/nex/ex_init.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_init.c 8.11 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "tag.h"
-
-/*
- * ex_screen_copy --
- * Copy ex screen.
- */
-int
-ex_screen_copy(orig, sp)
- SCR *orig, *sp;
-{
- EX_PRIVATE *oexp, *nexp;
-
- /* Create the private ex structure. */
- CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE));
- sp->ex_private = nexp;
-
- /* Initialize queues. */
- TAILQ_INIT(&nexp->tagq);
- TAILQ_INIT(&nexp->tagfq);
- CIRCLEQ_INIT(&nexp->rangeq);
-
- if (orig == NULL) {
- nexp->at_lbuf_set = 0;
- } else {
- oexp = EXP(orig);
-
- nexp->at_lbuf = oexp->at_lbuf;
- nexp->at_lbuf_set = oexp->at_lbuf_set;
-
- if (oexp->lastbcomm != NULL &&
- (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return(1);
- }
-
- if (ex_tagcopy(orig, sp))
- return (1);
- }
-
- nexp->lastcmd = &cmds[C_PRINT];
- return (0);
-}
-
-/*
- * ex_screen_end --
- * End a vi screen.
- */
-int
-ex_screen_end(sp)
- SCR *sp;
-{
- EX_PRIVATE *exp;
- int rval;
-
- rval = 0;
- exp = EXP(sp);
-
- if (argv_free(sp))
- rval = 1;
-
- if (exp->ibp != NULL)
- FREE(exp->ibp, exp->ibp_len);
-
- if (exp->lastbcomm != NULL)
- FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1);
-
- /* Free private memory. */
- FREE(exp, sizeof(EX_PRIVATE));
- sp->ex_private = NULL;
-
- return (rval);
-}
-
-/*
- * ex_init --
- * Initialize ex.
- */
-int
-ex_init(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- size_t len;
-
- /*
- * The default address is the last line of the file. If the address
- * set bit is on for this file, load the address, ensuring that it
- * exists.
- */
- if (F_ISSET(sp->frp, FR_CURSORSET)) {
- sp->lno = sp->frp->lno;
- sp->cno = sp->frp->cno;
-
- if (file_gline(sp, ep, sp->lno, &len) == NULL) {
- if (file_lline(sp, ep, &sp->lno))
- return (1);
- if (sp->lno == 0)
- sp->lno = 1;
- sp->cno = 0;
- } else if (sp->cno >= len)
- sp->cno = 0;
- } else {
- if (file_lline(sp, ep, &sp->lno))
- return (1);
- if (sp->lno == 0)
- sp->lno = 1;
- sp->cno = 0;
- }
-
- /* Display the status line. */
- return (status(sp, ep, sp->lno, 0));
-}
-
-/*
- * ex_end --
- * End ex session.
- */
-int
-ex_end(sp)
- SCR *sp;
-{
- /* Save the cursor location. */
- sp->frp->lno = sp->lno;
- sp->frp->cno = sp->cno;
- F_SET(sp->frp, FR_CURSORSET);
-
- return (0);
-}
-
-/*
- * ex_optchange --
- * Handle change of options for vi.
- */
-int
-ex_optchange(sp, opt)
- SCR *sp;
- int opt;
-{
- switch (opt) {
- case O_TAGS:
- return (ex_tagalloc(sp, O_STR(sp, O_TAGS)));
- }
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_join.c b/usr.bin/vi/nex/ex_join.c
deleted file mode 100644
index 33bace97500e..000000000000
--- a/usr.bin/vi/nex/ex_join.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_join.c 8.8 (Berkeley) 12/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_join -- :[line [,line]] j[oin][!] [count] [flags]
- * Join lines.
- */
-int
-ex_join(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- recno_t from, to;
- size_t blen, clen, len, tlen;
- int echar, extra, first;
- char *bp, *p, *tbp;
-
- from = cmdp->addr1.lno;
- to = cmdp->addr2.lno;
-
- /* Check for no lines to join. */
- if ((p = file_gline(sp, ep, from + 1, &len)) == NULL) {
- msgq(sp, M_ERR, "No following lines to join.");
- return (1);
- }
-
- GET_SPACE_RET(sp, bp, blen, 256);
-
- /*
- * The count for the join command was off-by-one,
- * historically, to other counts for other commands.
- */
- if (F_ISSET(cmdp, E_COUNT))
- ++cmdp->addr2.lno;
-
- /*
- * If only a single address specified, or, the same address
- * specified twice, the from/two addresses will be the same.
- */
- if (cmdp->addr1.lno == cmdp->addr2.lno)
- ++cmdp->addr2.lno;
-
- clen = tlen = 0;
- for (first = 1, from = cmdp->addr1.lno,
- to = cmdp->addr2.lno; from <= to; ++from) {
- /*
- * Get next line. Historic versions of vi allowed "10J" while
- * less than 10 lines from the end-of-file, so we do too.
- */
- if ((p = file_gline(sp, ep, from, &len)) == NULL) {
- cmdp->addr2.lno = from - 1;
- break;
- }
-
- /* Empty lines just go away. */
- if (len == 0)
- continue;
-
- /*
- * Get more space if necessary. Note, tlen isn't the length
- * of the new line, it's roughly the amount of space needed.
- * tbp - bp is the length of the new line.
- */
- tlen += len + 2;
- ADD_SPACE_RET(sp, bp, blen, tlen);
- tbp = bp + clen;
-
- /*
- * Historic practice:
- *
- * If force specified, join without modification.
- * If the current line ends with whitespace, strip leading
- * whitespace from the joined line.
- * If the next line starts with a ), do nothing.
- * If the current line ends with ., ? or !, insert two spaces.
- * Else, insert one space.
- *
- * Echar is the last character in the last line joined.
- */
- extra = 0;
- if (!first && !F_ISSET(cmdp, E_FORCE)) {
- if (isblank(echar))
- for (; len && isblank(*p); --len, ++p);
- else if (p[0] != ')') {
- if (strchr(".?!", echar)) {
- *tbp++ = ' ';
- ++clen;
- extra = 1;
- }
- *tbp++ = ' ';
- ++clen;
- for (; len && isblank(*p); --len, ++p);
- }
- }
-
- if (len != 0) {
- memmove(tbp, p, len);
- tbp += len;
- clen += len;
- echar = p[len - 1];
- } else
- echar = ' ';
-
- /*
- * Historic practice for vi was to put the cursor at the first
- * inserted whitespace character, if there was one, or the
- * first character of the joined line, if there wasn't, or the
- * last character of the line if joined to an empty line. If
- * a count was specified, the cursor was moved as described
- * for the first line joined, ignoring subsequent lines. If
- * the join was a ':' command, the cursor was placed at the
- * first non-blank character of the line unless the cursor was
- * "attracted" to the end of line when the command was executed
- * in which case it moved to the new end of line. There are
- * probably several more special cases, but frankly, my dear,
- * I don't give a damn. This implementation puts the cursor
- * on the first inserted whitespace character, the first
- * character of the joined line, or the last character of the
- * line regardless. Note, if the cursor isn't on the joined
- * line (possible with : commands), it is reset to the starting
- * line.
- */
- if (first) {
- sp->cno = (tbp - bp) - (1 + extra);
- first = 0;
- } else
- sp->cno = (tbp - bp) - len - (1 + extra);
- }
- sp->lno = cmdp->addr1.lno;
-
- /* Delete the joined lines. */
- for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
- if (file_dline(sp, ep, to))
- goto err;
-
- /* Reset the original line. */
- if (file_sline(sp, ep, from, bp, tbp - bp)) {
-err: FREE_SPACE(sp, bp, blen);
- return (1);
- }
- FREE_SPACE(sp, bp, blen);
-
- sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1;
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_map.c b/usr.bin/vi/nex/ex_map.c
deleted file mode 100644
index 0154c34699be..000000000000
--- a/usr.bin/vi/nex/ex_map.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_map.c 8.6 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "seq.h"
-#include "excmd.h"
-
-/*
- * ex_map -- :map[!] [input] [replacement]
- * Map a key/string or display mapped keys.
- *
- * Historical note:
- * Historic vi maps were fairly bizarre, and likely to differ in
- * very subtle and strange ways from this implementation. Two
- * things worth noting are that vi would often hang or drop core
- * if the map was strange enough (ex: map X "xy$@x^V), or, simply
- * not work. One trick worth remembering is that if you put a
- * mark at the start of the map, e.g. map X mx"xy ...), or if you
- * put the map in a .exrc file, things would often work much better.
- * No clue why.
- */
-int
-ex_map(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- enum seqtype stype;
- CHAR_T *input;
- size_t nlen;
- int key;
- char *name, buf[10];
-
- stype = F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND;
-
- switch (cmdp->argc) {
- case 0:
- if (seq_dump(sp, stype, 1) == 0)
- msgq(sp, M_INFO, "No %s map entries.",
- stype == SEQ_INPUT ? "input" : "command");
- return (0);
- case 2:
- input = cmdp->argv[0]->bp;
- break;
- default:
- abort();
- }
-
- /*
- * If the mapped string is #[0-9] (and wasn't quoted in any
- * way, then map to a function key.
- */
- nlen = 0;
- if (input[0] == '#' && isdigit(input[1]) && !input[2]) {
- key = atoi(input + 1);
- nlen = snprintf(buf, sizeof(buf), "f%d", key);
-#ifdef notdef
- if (FKEY[key]) { /* CCC */
- input = FKEY[key];
- name = buf;
- } else {
- msgq(sp, M_ERR, "This terminal has no %s key.", buf);
- return (1);
- }
-#else
- name = NULL;
-#endif
- } else {
- name = NULL;
-
- /* Some single keys may not be remapped in command mode. */
- if (stype == SEQ_COMMAND && input[1] == '\0')
- switch (term_key_val(sp, input[0])) {
- case K_COLON:
- case K_CR:
- case K_ESCAPE:
- case K_NL:
- msgq(sp, M_ERR,
- "The %s character may not be remapped.",
- charname(sp, input[0]));
- return (1);
- }
- }
- return (seq_set(sp, name, nlen, input, cmdp->argv[0]->len,
- cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, 1));
-}
-
-/*
- * ex_unmap -- (:unmap[!] key)
- * Unmap a key.
- */
-int
-ex_unmap(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len,
- F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) {
- msgq(sp, M_INFO, "\"%s\" isn't mapped.", cmdp->argv[0]->bp);
- return (1);
- }
- return (0);
-}
-
-/*
- * map_save --
- * Save the mapped sequences to a file.
- */
-int
-map_save(sp, fp)
- SCR *sp;
- FILE *fp;
-{
- if (seq_save(sp, fp, "map ", SEQ_COMMAND))
- return (1);
- return (seq_save(sp, fp, "map! ", SEQ_INPUT));
-}
diff --git a/usr.bin/vi/nex/ex_mark.c b/usr.bin/vi/nex/ex_mark.c
deleted file mode 100644
index 34efe21648b1..000000000000
--- a/usr.bin/vi/nex/ex_mark.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_mark.c 8.4 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-int
-ex_mark(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (cmdp->argv[0]->len != 1) {
- msgq(sp, M_ERR, "Mark names must be a single character.");
- return (1);
- }
- return (mark_set(sp, ep, cmdp->argv[0]->bp[0], &cmdp->addr1, 1));
-}
diff --git a/usr.bin/vi/nex/ex_mkexrc.c b/usr.bin/vi/nex/ex_mkexrc.c
deleted file mode 100644
index b26c7f814532..000000000000
--- a/usr.bin/vi/nex/ex_mkexrc.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_mkexrc.c 8.8 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "seq.h"
-#include "pathnames.h"
-
-/*
- * ex_mkexrc -- :mkexrc[!] [file]
- *
- * Create (or overwrite) a .exrc file with the current info.
- */
-int
-ex_mkexrc(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- struct stat sb;
- FILE *fp;
- int fd, sverrno;
- char *fname;
-
- switch (cmdp->argc) {
- case 0:
- fname = _PATH_EXRC;
- break;
- case 1:
- fname = cmdp->argv[0]->bp;
- set_alt_name(sp, fname);
- break;
- default:
- abort();
- }
-
- if (!F_ISSET(cmdp, E_FORCE) && !stat(fname, &sb)) {
- msgq(sp, M_ERR,
- "%s exists, not written; use ! to override.", fname);
- return (1);
- }
-
- /* Create with max permissions of rw-r--r--. */
- if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
- msgq(sp, M_SYSERR, fname);
- return (1);
- }
-
- if ((fp = fdopen(fd, "w")) == NULL) {
- sverrno = errno;
- (void)close(fd);
- errno = sverrno;
- goto e2;
- }
-
- if (abbr_save(sp, fp) || ferror(fp))
- goto e1;
- if (map_save(sp, fp) || ferror(fp))
- goto e1;
- if (opts_save(sp, fp) || ferror(fp))
- goto e1;
-#ifndef NO_DIGRAPH
- digraph_save(sp, fd);
-#endif
- if (fclose(fp))
- goto e2;
-
- msgq(sp, M_INFO, "New .exrc file: %s. ", fname);
- return (0);
-
-e1: sverrno = errno;
- (void)fclose(fp);
- errno = sverrno;
-e2: msgq(sp, M_ERR, "%s: incomplete: %s", fname, strerror(errno));
- return (1);
-}
diff --git a/usr.bin/vi/nex/ex_move.c b/usr.bin/vi/nex/ex_move.c
deleted file mode 100644
index 965618b0834f..000000000000
--- a/usr.bin/vi/nex/ex_move.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_move.c 8.6 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-enum which {COPY, MOVE};
-static int cm __P((SCR *, EXF *, EXCMDARG *, enum which));
-
-/*
- * ex_copy -- :[line [,line]] co[py] line [flags]
- * Copy selected lines.
- */
-int
-ex_copy(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (cm(sp, ep, cmdp, COPY));
-}
-
-/*
- * ex_move -- :[line [,line]] co[py] line
- * Move selected lines.
- */
-int
-ex_move(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (cm(sp, ep, cmdp, MOVE));
-}
-
-static int
-cm(sp, ep, cmdp, cmd)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which cmd;
-{
- CB cb;
- MARK fm1, fm2, m, tm;
- recno_t diff;
- int rval;
-
- fm1 = cmdp->addr1;
- fm2 = cmdp->addr2;
- tm.lno = cmdp->lineno;
- tm.cno = 0;
-
- /* Make sure the destination is valid. */
- if (cmd == MOVE && tm.lno >= fm1.lno && tm.lno < fm2.lno) {
- msgq(sp, M_ERR, "Destination line is inside move range.");
- return (1);
- }
-
- /* Save the text to a cut buffer. */
- memset(&cb, 0, sizeof(cb));
- CIRCLEQ_INIT(&cb.textq);
- if (cut(sp, ep, &cb, NULL, &fm1, &fm2, CUT_LINEMODE))
- return (1);
-
- /* If we're not copying, delete the old text and adjust tm. */
- if (cmd == MOVE) {
- if (delete(sp, ep, &fm1, &fm2, 1)) {
- rval = 1;
- goto err;
- }
- if (tm.lno >= fm1.lno)
- tm.lno -= (fm2.lno - fm1.lno) + 1;
- }
-
- /* Add the new text. */
- if (put(sp, ep, &cb, NULL, &tm, &m, 1)) {
- rval = 1;
- goto err;
- }
-
- /*
- * Move and copy put the cursor on the last line moved or copied.
- * The returned cursor from the put routine is the first line put,
- * not the last, because that's the semantics of vi.
- */
- diff = (fm2.lno - fm1.lno) + 1;
- sp->lno = m.lno + (diff - 1);
- sp->cno = 0;
-
- sp->rptlines[cmd == COPY ? L_COPIED : L_MOVED] += diff;
- rval = 0;
-
-err: (void)text_lfree(&cb.textq);
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_open.c b/usr.bin/vi/nex/ex_open.c
deleted file mode 100644
index 77b418a41d6f..000000000000
--- a/usr.bin/vi/nex/ex_open.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_open.c 8.2 (Berkeley) 10/3/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_open -- :[line] o[pen] [/pattern/] [flags]
- *
- * Switch to single line "open" mode.
- */
-int
-ex_open(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- /* If open option off, disallow open command. */
- if (!O_ISSET(sp, O_OPEN)) {
- msgq(sp, M_ERR,
- "The open command requires that the open option be set.");
- return (1);
- }
-
- msgq(sp, M_ERR, "The open command is not yet implemented.");
- return (1);
-}
diff --git a/usr.bin/vi/nex/ex_preserve.c b/usr.bin/vi/nex/ex_preserve.c
deleted file mode 100644
index a7f35485698d..000000000000
--- a/usr.bin/vi/nex/ex_preserve.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_preserve.c 8.4 (Berkeley) 11/8/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_preserve -- :pre[serve]
- * Push the file to recovery.
- */
-int
-ex_preserve(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- recno_t lno;
-
- if (!F_ISSET(ep, F_RCV_ON)) {
- msgq(sp, M_ERR, "Preservation of this file not possible.");
- return (1);
- }
-
- /* If recovery not initialized, do so. */
- if (F_ISSET(ep, F_FIRSTMODIFY) && rcv_init(sp, ep))
- return (1);
-
- /* Force the file to be read in, in case it hasn't yet. */
- if (file_lline(sp, ep, &lno))
- return (1);
-
- /* Sync to disk. */
- if (rcv_sync(sp, ep))
- return (1);
-
- /* Preserve the recovery files. */
- F_SET(ep, F_RCV_NORM);
-
- msgq(sp, M_INFO, "File preserved.");
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_print.c b/usr.bin/vi/nex/ex_print.c
deleted file mode 100644
index d25e9ff563b1..000000000000
--- a/usr.bin/vi/nex/ex_print.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_print.c 8.6 (Berkeley) 11/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_list -- :[line [,line]] l[ist] [count] [flags]
- *
- * Display the addressed lines such that the output is unambiguous.
- */
-int
-ex_list(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (ex_print(sp, ep,
- &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_LIST))
- return (1);
- sp->lno = cmdp->addr2.lno;
- sp->cno = cmdp->addr2.cno;
- return (0);
-}
-
-/*
- * ex_number -- :[line [,line]] nu[mber] [count] [flags]
- *
- * Display the addressed lines with a leading line number.
- */
-int
-ex_number(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (ex_print(sp, ep,
- &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_HASH))
- return (1);
- sp->lno = cmdp->addr2.lno;
- sp->cno = cmdp->addr2.cno;
- return (0);
-}
-
-/*
- * ex_pr -- :[line [,line]] p[rint] [count] [flags]
- *
- * Display the addressed lines.
- */
-int
-ex_pr(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (ex_print(sp, ep, &cmdp->addr1, &cmdp->addr2, cmdp->flags))
- return (1);
- sp->lno = cmdp->addr2.lno;
- sp->cno = cmdp->addr2.cno;
- return (0);
-}
-
-/*
- * ex_print --
- * Print the selected lines.
- */
-int
-ex_print(sp, ep, fp, tp, flags)
- SCR *sp;
- EXF *ep;
- MARK *fp, *tp;
- register int flags;
-{
- register int ch, col, rlen;
- recno_t from, to;
- size_t len;
- int cnt;
- char *p, buf[10];
-
- F_SET(sp, S_INTERRUPTIBLE);
- for (from = fp->lno, to = tp->lno; from <= to; ++from) {
- /* Display the line number. */
- if (LF_ISSET(E_F_HASH))
- col = ex_printf(EXCOOKIE, "%7ld ", from);
- else
- col = 0;
-
- /*
- * Display the line. The format for E_F_PRINT isn't very good,
- * especially in handling end-of-line tabs, but they're almost
- * backward compatible.
- */
- if ((p = file_gline(sp, ep, from, &len)) == NULL) {
- GETLINE_ERR(sp, from);
- return (1);
- }
-
-#define WCHECK(ch) { \
- if (col == sp->cols) { \
- (void)ex_printf(EXCOOKIE, "\n"); \
- col = 0; \
- } \
- (void)ex_printf(EXCOOKIE, "%c", ch); \
- ++col; \
-}
- for (rlen = len; rlen--;) {
- ch = *p++;
- if (LF_ISSET(E_F_LIST))
- if (ch != '\t' && isprint(ch)) {
- WCHECK(ch);
- } else if (ch & 0x80) {
- (void)snprintf(buf,
- sizeof(buf), "\\%03o", ch);
- len = strlen(buf);
- for (cnt = 0; cnt < len; ++cnt)
- WCHECK(buf[cnt]);
- } else {
- WCHECK('^');
- WCHECK(ch + 0x40);
- }
- else {
- ch &= 0x7f;
- if (ch == '\t') {
- while (col < sp->cols &&
- ++col % O_VAL(sp, O_TABSTOP))
- (void)ex_printf(EXCOOKIE, " ");
- if (col == sp->cols) {
- col = 0;
- (void)ex_printf(EXCOOKIE, "\n");
- }
- } else if (isprint(ch)) {
- WCHECK(ch);
- } else if (ch == '\n') {
- col = 0;
- (void)ex_printf(EXCOOKIE, "\n");
- } else {
- WCHECK('^');
- WCHECK(ch + 0x40);
- }
- }
- }
- if (LF_ISSET(E_F_LIST)) {
- WCHECK('$');
- } else if (len == 0) {
- /*
- * If the line is empty, output a space
- * to overwrite the colon prompt.
- */
- WCHECK(' ');
- }
- (void)ex_printf(EXCOOKIE, "\n");
-
- if (F_ISSET(sp, S_INTERRUPTED))
- break;
- }
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_put.c b/usr.bin/vi/nex/ex_put.c
deleted file mode 100644
index 3bc687fd1496..000000000000
--- a/usr.bin/vi/nex/ex_put.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_put.c 8.4 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_put -- [line] pu[t] [buffer]
- *
- * Append a cut buffer into the file.
- */
-int
-ex_put(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- MARK m;
-
- m.lno = sp->lno;
- m.cno = sp->cno;
- if (put(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
- &cmdp->addr1, &m, 1))
- return (1);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_read.c b/usr.bin/vi/nex/ex_read.c
deleted file mode 100644
index 9328b93c329a..000000000000
--- a/usr.bin/vi/nex/ex_read.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_read.c 8.21 (Berkeley) 1/23/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_read -- :read [file]
- * :read [! cmd]
- * Read from a file or utility.
- */
-int
-ex_read(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- struct stat sb;
- FILE *fp;
- MARK rm;
- recno_t nlines;
- size_t blen, len;
- int rval;
- char *bp, *name;
-
- /*
- * If "read !", it's a pipe from a utility.
- *
- * !!!
- * Historical vi wouldn't undo a filter read, for no apparent
- * reason.
- */
- if (F_ISSET(cmdp, E_FORCE)) {
- /* Expand the user's argument. */
- if (argv_exp1(sp, ep,
- cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
- return (1);
-
- /* If argc still 1, there wasn't anything to expand. */
- if (cmdp->argc == 1) {
- msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
- return (1);
- }
-
- /* Redisplay the user's argument if it's changed. */
- if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
- len = cmdp->argv[1]->len;
- GET_SPACE_RET(sp, bp, blen, len + 2);
- bp[0] = '!';
- memmove(bp + 1, cmdp->argv[1], cmdp->argv[1]->len + 1);
- (void)sp->s_busy(sp, bp);
- FREE_SPACE(sp, bp, blen);
- }
-
- if (filtercmd(sp, ep,
- &cmdp->addr1, NULL, &rm, cmdp->argv[1]->bp, FILTER_READ))
- return (1);
- sp->lno = rm.lno;
- return (0);
- }
-
- /* Expand the user's argument. */
- if (argv_exp2(sp, ep,
- cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
- return (1);
-
- switch (cmdp->argc) {
- case 1:
- /*
- * No arguments, read the current file.
- * Doesn't set the alternate file name.
- */
- name = FILENAME(sp->frp);
- break;
- case 2:
- /*
- * One argument, read it.
- * Sets the alternate file name.
- */
- name = cmdp->argv[1]->bp;
- set_alt_name(sp, name);
- break;
- default:
- /* If expanded to more than one argument, object. */
- msgq(sp, M_ERR,
- "%s expanded into too many file names", cmdp->argv[0]->bp);
- msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
- return (1);
- }
-
- /*
- * !!!
- * Historically, vi did not permit reads from non-regular files,
- * nor did it distinguish between "read !" and "read!", so there
- * was no way to "force" it.
- */
- if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
- msgq(sp, M_SYSERR, name);
- return (1);
- }
- if (!S_ISREG(sb.st_mode)) {
- (void)fclose(fp);
- msgq(sp, M_ERR, "Only regular files may be read.");
- return (1);
- }
-
- rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
-
- /*
- * Set the cursor to the first line read in, if anything read
- * in, otherwise, the address. (Historic vi set it to the
- * line after the address regardless, but since that line may
- * not exist we don't bother.)
- */
- sp->lno = cmdp->addr1.lno;
- if (nlines)
- ++sp->lno;
-
- F_SET(EXP(sp), EX_AUTOPRINT);
- return (rval);
-}
-
-/*
- * ex_readfp --
- * Read lines into the file.
- */
-int
-ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
- SCR *sp;
- EXF *ep;
- char *name;
- FILE *fp;
- MARK *fm;
- recno_t *nlinesp;
- int success_msg;
-{
- EX_PRIVATE *exp;
- u_long ccnt;
- size_t len;
- recno_t lno, nlines;
- int rval;
-
- /*
- * Add in the lines from the output. Insertion starts at the line
- * following the address.
- */
- ccnt = 0;
- rval = 0;
- exp = EXP(sp);
- for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
- if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
- rval = 1;
- break;
- }
- ccnt += len;
- }
-
- if (ferror(fp)) {
- msgq(sp, M_SYSERR, name);
- rval = 1;
- }
-
- if (fclose(fp)) {
- msgq(sp, M_SYSERR, name);
- return (1);
- }
-
- if (rval)
- return (1);
-
- /* Return the number of lines read in. */
- nlines = lno - fm->lno;
- if (nlinesp != NULL)
- *nlinesp = nlines;
-
- if (success_msg)
- msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
- name, nlines, nlines == 1 ? "" : "s", ccnt);
-
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_screen.c b/usr.bin/vi/nex/ex_screen.c
deleted file mode 100644
index 0fd000d4898a..000000000000
--- a/usr.bin/vi/nex/ex_screen.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_screen.c 8.10 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_split -- :s[plit] [file ...]
- * Split the screen, optionally setting the file list.
- */
-int
-ex_split(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (sp->s_split(sp, cmdp->argc ? cmdp->argv : NULL));
-}
-
-/*
- * ex_bg -- :bg
- * Hide the screen.
- */
-int
-ex_bg(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (sp->s_bg(sp));
-}
-
-/*
- * ex_fg -- :fg [file]
- * Show the screen.
- */
-int
-ex_fg(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (sp->s_fg(sp, cmdp->argc ? cmdp->argv[0]->bp : NULL));
-}
-
-/*
- * ex_resize -- :resize [change]
- * Change the screen size.
- */
-int
-ex_resize(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (!F_ISSET(cmdp, E_COUNT))
- cmdp->count = 1;
- return (sp->s_rabs(sp, cmdp->count));
-}
-
-/*
- * ex_sdisplay --
- * Display the list of screens.
- */
-int
-ex_sdisplay(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- SCR *tsp;
- int cnt, col, len, sep;
-
- if ((tsp = sp->gp->hq.cqh_first) == (void *)&sp->gp->hq) {
- (void)ex_printf(EXCOOKIE,
- "No backgrounded screens to display.\n");
- return (0);
- }
-
- col = len = sep = 0;
- for (cnt = 1; tsp != (void *)&sp->gp->hq; tsp = tsp->q.cqe_next) {
- col += len = strlen(FILENAME(tsp->frp)) + sep;
- if (col >= sp->cols - 1) {
- col = len;
- sep = 0;
- (void)ex_printf(EXCOOKIE, "\n");
- } else if (cnt != 1) {
- sep = 1;
- (void)ex_printf(EXCOOKIE, " ");
- }
- (void)ex_printf(EXCOOKIE, "%s", FILENAME(tsp->frp));
- ++cnt;
- }
- (void)ex_printf(EXCOOKIE, "\n");
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_script.c b/usr.bin/vi/nex/ex_script.c
deleted file mode 100644
index 606e479d6af4..000000000000
--- a/usr.bin/vi/nex/ex_script.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_script.c 8.10 (Berkeley) 12/22/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "script.h"
-
-/*
- * XXX
- */
-int openpty __P((int *, int *, char *, struct termios *, struct winsize *));
-
-static int sscr_getprompt __P((SCR *, EXF *));
-static int sscr_init __P((SCR *, EXF *));
-static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *));
-static int sscr_setprompt __P((SCR *, char *, size_t));
-
-/*
- * ex_script -- : sc[ript][!] [file]
- *
- * Switch to script mode.
- */
-int
-ex_script(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- /* Vi only command. */
- if (!IN_VI_MODE(sp)) {
- msgq(sp, M_ERR,
- "The script command is only available in vi mode.");
- return (1);
- }
-
- /* Switch to the new file. */
- if (cmdp->argc != 0 && ex_edit(sp, ep, cmdp))
- return (1);
-
- /*
- * Create the shell, figure out the prompt.
- *
- * !!!
- * The files just switched, use sp->ep.
- */
- if (sscr_init(sp, sp->ep))
- return (1);
-
- return (0);
-}
-
-/*
- * sscr_init --
- * Create a pty setup for a shell.
- */
-static int
-sscr_init(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- SCRIPT *sc;
- char *sh, *sh_path;
-
- MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT));
- sp->script = sc;
- sc->sh_prompt = NULL;
- sc->sh_prompt_len = 0;
-
- /*
- * There are two different processes running through this code.
- * They are the shell and the parent.
- */
- sc->sh_master = sc->sh_slave = -1;
-
- if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) {
- msgq(sp, M_SYSERR, "tcgetattr");
- goto err;
- }
-
- /*
- * Turn off output postprocessing and echo.
- */
- sc->sh_term.c_oflag &= ~OPOST;
- sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK);
-
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) {
- msgq(sp, M_SYSERR, "tcgetattr");
- goto err;
- }
-
- if (openpty(&sc->sh_master,
- &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) {
- msgq(sp, M_SYSERR, "openpty");
- goto err;
- }
-
- /*
- * Don't use vfork() here, because the signal semantics
- * differ from implementation to implementation.
- */
- switch (sc->sh_pid = fork()) {
- case -1: /* Error. */
- msgq(sp, M_SYSERR, "fork");
-err: if (sc->sh_master != -1)
- (void)close(sc->sh_master);
- if (sc->sh_slave != -1)
- (void)close(sc->sh_slave);
- return (1);
- case 0: /* Utility. */
- /*
- * The utility has default signal behavior. Don't bother
- * using sigaction(2) 'cause we want the default behavior.
- */
- (void)signal(SIGINT, SIG_DFL);
- (void)signal(SIGQUIT, SIG_DFL);
-
- /*
- * XXX
- * So that shells that do command line editing turn it off.
- */
- (void)putenv("TERM=emacs");
- (void)putenv("TERMCAP=emacs:");
- (void)putenv("EMACS=t");
-
- (void)setsid();
-#ifdef TIOCSCTTY
- /*
- * 4.4BSD allocates a controlling terminal using the TIOCSCTTY
- * ioctl, not by opening a terminal device file. POSIX 1003.1
- * doesn't define a portable way to do this. If TIOCSCTTY is
- * not available, hope that the open does it.
- */
- (void)ioctl(sc->sh_slave, TIOCSCTTY, 0);
-#endif
- (void)close(sc->sh_master);
- (void)dup2(sc->sh_slave, STDIN_FILENO);
- (void)dup2(sc->sh_slave, STDOUT_FILENO);
- (void)dup2(sc->sh_slave, STDERR_FILENO);
- (void)close(sc->sh_slave);
-
- /* Assumes that all shells have -i. */
- sh_path = O_STR(sp, O_SHELL);
- if ((sh = strrchr(sh_path, '/')) == NULL)
- sh = sh_path;
- else
- ++sh;
- execl(sh_path, sh, "-i", NULL);
- msgq(sp, M_ERR,
- "Error: execl: %s: %s", sh_path, strerror(errno));
- _exit(127);
- default:
- break;
- }
-
- if (sscr_getprompt(sp, ep))
- return (1);
-
- F_SET(sp, S_REDRAW | S_SCRIPT);
- return (0);
-
-}
-
-/*
- * sscr_getprompt --
- * Eat lines printed by the shell until a line with no trailing
- * carriage return comes; set the prompt from that line.
- */
-static int
-sscr_getprompt(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- struct timeval tv;
- SCRIPT *sc;
- fd_set fdset;
- recno_t lline;
- size_t llen, len;
- u_int value;
- int nr;
- char *endp, *p, *t, buf[1024];
-
- FD_ZERO(&fdset);
- endp = buf;
- len = sizeof(buf);
-
- /* Wait up to a second for characters to read. */
- tv.tv_sec = 5;
- tv.tv_usec = 0;
- sc = sp->script;
- FD_SET(sc->sh_master, &fdset);
- switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
- case -1: /* Error or interrupt. */
- msgq(sp, M_SYSERR, "select");
- goto prompterr;
- case 0: /* Timeout */
- msgq(sp, M_ERR, "Error: timed out.");
- goto prompterr;
- case 1: /* Characters to read. */
- break;
- }
-
- /* Read the characters. */
-more: len = sizeof(buf) - (endp - buf);
- switch (nr = read(sc->sh_master, endp, len)) {
- case 0: /* EOF. */
- msgq(sp, M_ERR, "Error: shell: EOF");
- goto prompterr;
- case -1: /* Error or interrupt. */
- msgq(sp, M_SYSERR, "shell");
- goto prompterr;
- default:
- endp += nr;
- break;
- }
-
- /* If any complete lines, push them into the file. */
- for (p = t = buf; p < endp; ++p) {
- value = term_key_val(sp, *p);
- if (value == K_CR || value == K_NL) {
- if (file_lline(sp, ep, &lline) ||
- file_aline(sp, ep, 0, lline, t, p - t))
- goto prompterr;
- t = p + 1;
- }
- }
- if (p > buf) {
- memmove(buf, t, endp - t);
- endp = buf + (endp - t);
- }
- if (endp == buf)
- goto more;
-
- /* Wait up 1/10 of a second to make sure that we got it all. */
- tv.tv_sec = 0;
- tv.tv_usec = 100000;
- switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
- case -1: /* Error or interrupt. */
- msgq(sp, M_SYSERR, "select");
- goto prompterr;
- case 0: /* Timeout */
- break;
- case 1: /* Characters to read. */
- goto more;
- }
-
- /* Timed out, so theoretically we have a prompt. */
- llen = endp - buf;
- endp = buf;
-
- /* Append the line into the file. */
- if (file_lline(sp, ep, &lline) ||
- file_aline(sp, ep, 0, lline, buf, llen)) {
-prompterr: sscr_end(sp);
- return (1);
- }
-
- return (sscr_setprompt(sp, buf, llen));
-}
-
-/*
- * sscr_exec --
- * Take a line and hand it off to the shell.
- */
-int
-sscr_exec(sp, ep, lno)
- SCR *sp;
- EXF *ep;
- recno_t lno;
-{
- SCRIPT *sc;
- recno_t last_lno;
- size_t blen, len, last_len, tlen;
- int matchprompt, nw, rval;
- char *bp, *p;
-
- /* If there's a prompt on the last line, append the command. */
- if (file_lline(sp, ep, &last_lno))
- return (1);
- if ((p = file_gline(sp, ep, last_lno, &last_len)) == NULL) {
- GETLINE_ERR(sp, last_lno);
- return (1);
- }
- if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) {
- matchprompt = 1;
- GET_SPACE_RET(sp, bp, blen, last_len + 128);
- memmove(bp, p, last_len);
- } else
- matchprompt = 0;
-
- /* Get something to execute. */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- goto err1;
- if (lno == 0)
- goto empty;
- else
- GETLINE_ERR(sp, lno);
- goto err1;
- }
-
- /* Empty lines aren't interesting. */
- if (len == 0)
- goto empty;
-
- /* Delete any prompt. */
- if (sscr_matchprompt(sp, p, len, &tlen)) {
- if (tlen == len) {
-empty: msgq(sp, M_BERR, "Nothing to execute.");
- goto err1;
- }
- p += (len - tlen);
- len = tlen;
- }
-
- /* Push the line to the shell. */
- sc = sp->script;
- if ((nw = write(sc->sh_master, p, len)) != len)
- goto err2;
- rval = 0;
- if (write(sc->sh_master, "\n", 1) != 1) {
-err2: if (nw == 0)
- errno = EIO;
- msgq(sp, M_SYSERR, "shell");
- goto err1;
- }
-
- if (matchprompt) {
- ADD_SPACE_RET(sp, bp, blen, last_len + len);
- memmove(bp + last_len, p, len);
- if (file_sline(sp, ep, last_lno, bp, last_len + len))
-err1: rval = 1;
- }
- if (matchprompt)
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
-
-/*
- * sscr_input --
- * Take a line from the shell and insert it into the file.
- */
-int
-sscr_input(sp)
- SCR *sp;
-{
- struct timeval tv;
- SCRIPT *sc;
- EXF *ep;
- recno_t lno;
- size_t blen, len, tlen;
- u_int value;
- int nr, rval;
- char *bp, *endp, *p, *t;
-
- /* Find out where the end of the file is. */
- ep = sp->ep;
- if (file_lline(sp, ep, &lno))
- return (1);
-
-#define MINREAD 1024
- GET_SPACE_RET(sp, bp, blen, MINREAD);
- endp = bp;
-
- /* Read the characters. */
- rval = 1;
- sc = sp->script;
-more: switch (nr = read(sc->sh_master, endp, MINREAD)) {
- case 0: /* EOF; shell just exited. */
- sscr_end(sp);
- F_CLR(sp, S_SCRIPT);
- rval = 0;
- goto ret;
- case -1: /* Error or interrupt. */
- msgq(sp, M_SYSERR, "shell");
- goto ret;
- default:
- endp += nr;
- break;
- }
-
- /* Append the lines into the file. */
- for (p = t = bp; p < endp; ++p) {
- value = term_key_val(sp, *p);
- if (value == K_CR || value == K_NL) {
- len = p - t;
- if (file_aline(sp, ep, 1, lno++, t, len))
- goto ret;
- t = p + 1;
- }
- }
- if (p > t) {
- len = p - t;
- /*
- * If the last thing from the shell isn't another prompt, wait
- * up to 1/10 of a second for more stuff to show up, so that
- * we don't break the output into two separate lines. Don't
- * want to hang indefinitely because some program is hanging,
- * confused the shell, or whatever.
- */
- if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 100000;
- FD_SET(sc->sh_master, &sp->rdfd);
- FD_CLR(STDIN_FILENO, &sp->rdfd);
- if (select(sc->sh_master + 1,
- &sp->rdfd, NULL, NULL, &tv) == 1) {
- memmove(bp, t, len);
- endp = bp + len;
- goto more;
- }
- }
- if (sscr_setprompt(sp, t, len))
- return (1);
- if (file_aline(sp, ep, 1, lno++, t, len))
- goto ret;
- }
-
- /* The cursor moves to EOF. */
- sp->lno = lno;
- sp->cno = len ? len - 1 : 0;
- rval = sp->s_refresh(sp, ep);
-
-ret: FREE_SPACE(sp, bp, blen);
- return (rval);
-}
-
-/*
- * sscr_setprompt --
- *
- * Set the prompt to the last line we got from the shell.
- *
- */
-static int
-sscr_setprompt(sp, buf, len)
- SCR *sp;
- char* buf;
- size_t len;
-{
- SCRIPT *sc;
-
- sc = sp->script;
- if (sc->sh_prompt)
- FREE(sc->sh_prompt, sc->sh_prompt_len);
- MALLOC(sp, sc->sh_prompt, char *, len + 1);
- if (sc->sh_prompt == NULL) {
- sscr_end(sp);
- return (1);
- }
- memmove(sc->sh_prompt, buf, len);
- sc->sh_prompt_len = len;
- sc->sh_prompt[len] = '\0';
- return (0);
-}
-
-/*
- * sscr_matchprompt --
- * Check to see if a line matches the prompt. Nul's indicate
- * parts that can change, in both content and size.
- */
-static int
-sscr_matchprompt(sp, lp, line_len, lenp)
- SCR *sp;
- char *lp;
- size_t line_len, *lenp;
-{
- SCRIPT *sc;
- size_t prompt_len;
- char *pp;
-
- sc = sp->script;
- if (line_len < (prompt_len = sc->sh_prompt_len))
- return (0);
-
- for (pp = sc->sh_prompt;
- prompt_len && line_len; --prompt_len, --line_len) {
- if (*pp == '\0') {
- for (; prompt_len && *pp == '\0'; --prompt_len, ++pp);
- if (!prompt_len)
- return (0);
- for (; line_len && *lp != *pp; --line_len, ++lp);
- if (!line_len)
- return (0);
- }
- if (*pp++ != *lp++)
- break;
- }
-
- if (prompt_len)
- return (0);
- if (lenp != NULL)
- *lenp = line_len;
- return (1);
-}
-
-/*
- * sscr_end --
- * End the pipe to a shell.
- */
-int
-sscr_end(sp)
- SCR *sp;
-{
- SCRIPT *sc;
- int rval;
-
- if ((sc = sp->script) == NULL)
- return (0);
-
- /* Turn off the script flag. */
- F_CLR(sp, S_SCRIPT);
-
- /* Close down the parent's file descriptors. */
- if (sc->sh_master != -1)
- (void)close(sc->sh_master);
- if (sc->sh_slave != -1)
- (void)close(sc->sh_slave);
-
- /* This should have killed the child. */
- rval = proc_wait(sp, (long)sc->sh_pid, "script-shell", 0);
-
- /* Free memory. */
- FREE(sc->sh_prompt, sc->sh_prompt_len);
- FREE(sc, sizeof(SCRIPT));
- sp->script = NULL;
-
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_set.c b/usr.bin/vi/nex/ex_set.c
deleted file mode 100644
index a463524e5fa9..000000000000
--- a/usr.bin/vi/nex/ex_set.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_set.c 8.2 (Berkeley) 10/3/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-int
-ex_set(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- switch(cmdp->argc) {
- case 0:
- opts_dump(sp, CHANGED_DISPLAY);
- break;
- default:
- opts_set(sp, cmdp->argv);
- break;
- }
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_shell.c b/usr.bin/vi/nex/ex_shell.c
deleted file mode 100644
index 282cc8f4fbdc..000000000000
--- a/usr.bin/vi/nex/ex_shell.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_shell.c 8.17 (Berkeley) 12/23/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <curses.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "../svi/svi_screen.h"
-
-/*
- * ex_shell -- :sh[ell]
- * Invoke the program named in the SHELL environment variable
- * with the argument -i.
- */
-int
-ex_shell(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- char buf[MAXPATHLEN];
-
- (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
- return (ex_exec_proc(sp, buf, "\n", NULL));
-}
-
-/*
- * ex_exec_proc --
- * Run a separate process.
- */
-int
-ex_exec_proc(sp, cmd, p1, p2)
- SCR *sp;
- char *cmd, *p1, *p2;
-{
- struct sigaction act, oact;
- struct stat osb, sb;
- struct termios term;
- const char *name;
- pid_t pid;
- int isig, rval;
-
- /* Clear the rest of the screen. */
- if (sp->s_clear(sp))
- return (1);
-
- /* Save ex/vi terminal settings, and restore the original ones. */
- EX_LEAVE(sp, isig, act, oact, sb, osb, term);
-
- /* Put out various messages. */
- if (p1 != NULL)
- (void)write(STDOUT_FILENO, p1, strlen(p1));
- if (p2 != NULL)
- (void)write(STDOUT_FILENO, p2, strlen(p2));
-
-
- switch (pid = vfork()) {
- case -1: /* Error. */
- msgq(sp, M_SYSERR, "vfork");
- rval = 1;
- goto err;
- case 0: /* Utility. */
- /*
- * The utility has default signal behavior. Don't bother
- * using sigaction(2) 'cause we want the default behavior.
- */
- (void)signal(SIGINT, SIG_DFL);
- (void)signal(SIGQUIT, SIG_DFL);
-
- if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
- name = O_STR(sp, O_SHELL);
- else
- ++name;
- execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
- msgq(sp, M_ERR, "Error: execl: %s: %s",
- O_STR(sp, O_SHELL), strerror(errno));
- _exit(127);
- /* NOTREACHED */
- }
-
- rval = proc_wait(sp, (long)pid, cmd, 0);
-
- /* Restore ex/vi terminal settings. */
-err: EX_RETURN(sp, isig, act, oact, sb, osb, term);
-
- /*
- * XXX
- * EX_LEAVE/EX_RETURN only give us 1-second resolution on the tty
- * changes. A fast '!' command, e.g. ":!pwd" can beat us to the
- * refresh. When there's better resolution from the stat(2) timers,
- * this can go away.
- */
- F_SET(sp, S_REFRESH);
-
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_shift.c b/usr.bin/vi/nex/ex_shift.c
deleted file mode 100644
index 8a0b858cbb6f..000000000000
--- a/usr.bin/vi/nex/ex_shift.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_shift.c 8.12 (Berkeley) 12/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-enum which {LEFT, RIGHT};
-static int shift __P((SCR *, EXF *, EXCMDARG *, enum which));
-
-int
-ex_shiftl(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (shift(sp, ep, cmdp, LEFT));
-}
-
-int
-ex_shiftr(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (shift(sp, ep, cmdp, RIGHT));
-}
-
-static int
-shift(sp, ep, cmdp, rl)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which rl;
-{
- recno_t from, to;
- size_t blen, len, newcol, newidx, oldcol, oldidx, sw;
- int curset;
- char *p, *bp, *tbp;
-
- if (O_VAL(sp, O_SHIFTWIDTH) == 0) {
- msgq(sp, M_INFO, "shiftwidth option set to 0");
- return (0);
- }
-
- /*
- * The historic version of vi permitted the user to string any number
- * of '>' or '<' characters together, resulting in an indent of the
- * appropriate levels. There's a special hack in ex_cmd() so that
- * cmdp->argv[0] points to the string of '>' or '<' characters.
- *
- * Q: What's the difference between the people adding features
- * to vi and the Girl Scouts?
- * A: The Girl Scouts have mint cookies and adult supervision.
- */
- for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p)
- sw += O_VAL(sp, O_SHIFTWIDTH);
-
- GET_SPACE_RET(sp, bp, blen, 256);
-
- curset = 0;
- for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
- if ((p = file_gline(sp, ep, from, &len)) == NULL)
- goto err;
- if (!len) {
- if (sp->lno == from)
- curset = 1;
- continue;
- }
-
- /*
- * Calculate the old indent amount and the number of
- * characters it used.
- */
- for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx)
- if (p[oldidx] == ' ')
- ++oldcol;
- else if (p[oldidx] == '\t')
- oldcol += O_VAL(sp, O_TABSTOP) -
- oldcol % O_VAL(sp, O_TABSTOP);
- else
- break;
-
- /* Calculate the new indent amount. */
- if (rl == RIGHT)
- newcol = oldcol + sw;
- else {
- newcol = oldcol < sw ? 0 : oldcol - sw;
- if (newcol == oldcol) {
- if (sp->lno == from)
- curset = 1;
- continue;
- }
- }
-
- /* Get a buffer that will hold the new line. */
- ADD_SPACE_RET(sp, bp, blen, newcol + len);
-
- /*
- * Build a new indent string and count the number of
- * characters it uses.
- */
- for (tbp = bp, newidx = 0;
- newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
- *tbp++ = '\t';
- newcol -= O_VAL(sp, O_TABSTOP);
- }
- for (; newcol > 0; --newcol, ++newidx)
- *tbp++ = ' ';
-
- /* Add the original line. */
- memmove(tbp, p + oldidx, len - oldidx);
-
- /* Set the replacement line. */
- if (file_sline(sp, ep, from, bp, (tbp + (len - oldidx)) - bp)) {
-err: FREE_SPACE(sp, bp, blen);
- return (1);
- }
-
- /*
- * !!!
- * The shift command in historic vi had the usual bizarre
- * collection of cursor semantics. If called from vi, the
- * cursor was repositioned to the first non-blank character
- * of the lowest numbered line shifted. If called from ex,
- * the cursor was repositioned to the first non-blank of the
- * highest numbered line shifted. Here, if the cursor isn't
- * part of the set of lines that are moved, move it to the
- * first non-blank of the last line shifted. (This makes
- * ":3>>" in vi work reasonably.) If the cursor is part of
- * the shifted lines, it doesn't get moved at all. This
- * permits shifting of marked areas, i.e. ">'a." shifts the
- * marked area twice, something that couldn't be done with
- * historic vi.
- */
- if (sp->lno == from) {
- curset = 1;
- if (newidx > oldidx)
- sp->cno += newidx - oldidx;
- else if (sp->cno >= oldidx - newidx)
- sp->cno -= oldidx - newidx;
- }
- }
- if (!curset) {
- sp->lno = to;
- sp->cno = 0;
- (void)nonblank(sp, ep, to, &sp->cno);
- }
-
- FREE_SPACE(sp, bp, blen);
-
- sp->rptlines[rl == RIGHT ? L_RSHIFT : L_LSHIFT] +=
- cmdp->addr2.lno - cmdp->addr1.lno + 1;
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_source.c b/usr.bin/vi/nex/ex_source.c
deleted file mode 100644
index bf2a9f1b275e..000000000000
--- a/usr.bin/vi/nex/ex_source.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_source.c 8.3 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_source -- :source file
- * Execute ex commands from a file.
- */
-int
-ex_source(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (ex_cfile(sp, ep, cmdp->argv[0]->bp));
-}
diff --git a/usr.bin/vi/nex/ex_stop.c b/usr.bin/vi/nex/ex_stop.c
deleted file mode 100644
index 26ec067c622a..000000000000
--- a/usr.bin/vi/nex/ex_stop.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_stop.c 8.4 (Berkeley) 10/28/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "sex/sex_screen.h"
-
-/*
- * ex_stop -- :stop[!]
- * :suspend[!]
- * Suspend execution.
- */
-int
-ex_stop(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- /* For some strange reason, the force flag turns off autowrite. */
- if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE) &&
- !F_ISSET(cmdp, E_FORCE)) {
- if (file_write((sp), (ep), NULL, NULL, NULL, FS_ALL))
- return (1);
- if (sex_refresh(sp, ep))
- return (1);
- }
- return (sp->s_suspend(sp));
-}
diff --git a/usr.bin/vi/nex/ex_subst.c b/usr.bin/vi/nex/ex_subst.c
deleted file mode 100644
index 6d132c56dd24..000000000000
--- a/usr.bin/vi/nex/ex_subst.c
+++ /dev/null
@@ -1,984 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_substitute.c 8.33 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "interrupt.h"
-
-#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
-#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
-
-static int checkmatchsize __P((SCR *, regex_t *));
-static inline int regsub __P((SCR *,
- char *, char **, size_t *, size_t *));
-static void subst_intr __P((int));
-static int substitute __P((SCR *, EXF *,
- EXCMDARG *, char *, regex_t *, u_int));
-
-/*
- * ex_substitute --
- * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
- *
- * Substitute on lines matching a pattern.
- */
-int
-ex_substitute(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- regex_t *re, lre;
- size_t blen, len;
- u_int flags;
- int delim, eval, reflags, replaced;
- char *bp, *ptrn, *rep, *p, *t;
-
- /*
- * Skip leading white space.
- *
- * !!!
- * Historic vi allowed any non-alphanumeric to serve as the
- * substitution command delimiter.
- *
- * !!!
- * If the arguments are empty, it's the same as &, i.e. we
- * repeat the last substitution.
- */
- for (p = cmdp->argv[0]->bp,
- len = cmdp->argv[0]->len; len > 0; --len, ++p) {
- if (!isblank(*p))
- break;
- }
- if (len == 0)
- return (ex_subagain(sp, ep, cmdp));
- delim = *p++;
- if (isalnum(delim))
- return (substitute(sp, ep,
- cmdp, p, &sp->subre, SUB_MUSTSETR));
-
- /*
- * Get the pattern string, toss escaped characters.
- *
- * !!!
- * Historic vi accepted any of the following forms:
- *
- * :s/abc/def/ change "abc" to "def"
- * :s/abc/def change "abc" to "def"
- * :s/abc/ delete "abc"
- * :s/abc delete "abc"
- *
- * QUOTING NOTE:
- *
- * Only toss an escape character if it escapes a delimiter.
- * This means that "s/A/\\\\f" replaces "A" with "\\f". It
- * would be nice to be more regular, i.e. for each layer of
- * escaping a single escape character is removed, but that's
- * not how the historic vi worked.
- */
- for (ptrn = t = p;;) {
- if (p[0] == '\0' || p[0] == delim) {
- if (p[0] == delim)
- ++p;
- /*
- * !!!
- * Nul terminate the pattern string -- it's passed
- * to regcomp which doesn't understand anything else.
- */
- *t = '\0';
- break;
- }
- if (p[0] == '\\' && p[1] == delim)
- ++p;
- *t++ = *p++;
- }
-
- /* If the pattern string is empty, use the last one. */
- if (*ptrn == NULL) {
- if (!F_ISSET(sp, S_SUBRE_SET)) {
- msgq(sp, M_ERR,
- "No previous regular expression.");
- return (1);
- }
- re = &sp->subre;
- flags = 0;
- } else {
- /* Set RE flags. */
- reflags = 0;
- if (O_ISSET(sp, O_EXTENDED))
- reflags |= REG_EXTENDED;
- if (O_ISSET(sp, O_IGNORECASE))
- reflags |= REG_ICASE;
-
- /* Convert vi-style RE's to POSIX 1003.2 RE's. */
- if (re_conv(sp, &ptrn, &replaced))
- return (1);
-
- /* Compile the RE. */
- eval = regcomp(&lre, (char *)ptrn, reflags);
-
- /* Free up any allocated memory. */
- if (replaced)
- FREE_SPACE(sp, ptrn, 0);
-
- if (eval) {
- re_error(sp, eval, &lre);
- return (1);
- }
-
- /*
- * Set saved RE.
- *
- * !!!
- * Historic practice is that substitutes set the search
- * direction as well as both substitute and search RE's.
- */
- sp->searchdir = FORWARD;
- sp->sre = lre;
- F_SET(sp, S_SRE_SET);
- sp->subre = lre;
- F_SET(sp, S_SUBRE_SET);
-
- re = &lre;
- flags = SUB_FIRST;
- }
-
- /*
- * Get the replacement string.
- *
- * The special character ~ (\~ if O_MAGIC not set) inserts the
- * previous replacement string into this replacement string.
- *
- * The special character & (\& if O_MAGIC not set) matches the
- * entire RE. No handling of & is required here, it's done by
- * regsub().
- *
- * QUOTING NOTE:
- *
- * Only toss an escape character if it escapes a delimiter or
- * an escape character, or if O_MAGIC is set and it escapes a
- * tilde.
- */
- if (*p == '\0') {
- if (sp->repl != NULL)
- FREE(sp->repl, sp->repl_len);
- sp->repl = NULL;
- sp->repl_len = 0;
- } else {
- /*
- * Count ~'s to figure out how much space we need. We could
- * special case nonexistent last patterns or whether or not
- * O_MAGIC is set, but it's probably not worth the effort.
- */
- for (rep = p, len = 0;
- p[0] != '\0' && p[0] != delim; ++p, ++len)
- if (p[0] == '~')
- len += sp->repl_len;
- GET_SPACE_RET(sp, bp, blen, len);
- for (t = bp, len = 0, p = rep;;) {
- if (p[0] == '\0' || p[0] == delim) {
- if (p[0] == delim)
- ++p;
- break;
- }
- if (p[0] == '\\') {
- if (p[1] == '\\' || p[1] == delim)
- ++p;
- else if (p[1] == '~') {
- ++p;
- if (!O_ISSET(sp, O_MAGIC))
- goto tilde;
- }
- } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) {
-tilde: ++p;
- memmove(t, sp->repl, sp->repl_len);
- t += sp->repl_len;
- len += sp->repl_len;
- continue;
- }
- *t++ = *p++;
- ++len;
- }
- if (sp->repl != NULL)
- FREE(sp->repl, sp->repl_len);
- if ((sp->repl = malloc(len)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- FREE_SPACE(sp, bp, blen);
- return (1);
- }
- memmove(sp->repl, bp, len);
- sp->repl_len = len;
- FREE_SPACE(sp, bp, blen);
- }
-
- if (checkmatchsize(sp, &sp->subre))
- return (1);
- return (substitute(sp, ep, cmdp, p, re, flags));
-}
-
-/*
- * ex_subagain --
- * [line [,line]] & [cgr] [count] [#lp]]
- *
- * Substitute using the last substitute RE and replacement pattern.
- */
-int
-ex_subagain(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (!F_ISSET(sp, S_SUBRE_SET)) {
- msgq(sp, M_ERR, "No previous regular expression.");
- return (1);
- }
- return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->subre, 0));
-}
-
-/*
- * ex_subtilde --
- * [line [,line]] ~ [cgr] [count] [#lp]]
- *
- * Substitute using the last RE and last substitute replacement pattern.
- */
-int
-ex_subtilde(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (!F_ISSET(sp, S_SRE_SET)) {
- msgq(sp, M_ERR, "No previous regular expression.");
- return (1);
- }
- return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->sre, 0));
-}
-
-/*
- * The nasty part of the substitution is what happens when the replacement
- * string contains newlines. It's a bit tricky -- consider the information
- * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is
- * to build a set of newline offsets which we use to break the line up later,
- * when the replacement is done. Don't change it unless you're pretty damned
- * confident.
- */
-#define NEEDNEWLINE(sp) { \
- if (sp->newl_len == sp->newl_cnt) { \
- sp->newl_len += 25; \
- REALLOC(sp, sp->newl, size_t *, \
- sp->newl_len * sizeof(size_t)); \
- if (sp->newl == NULL) { \
- sp->newl_len = 0; \
- return (1); \
- } \
- } \
-}
-
-#define BUILD(sp, l, len) { \
- if (lbclen + (len) > lblen) { \
- lblen += MAX(lbclen + (len), 256); \
- REALLOC(sp, lb, char *, lblen); \
- if (lb == NULL) { \
- lbclen = 0; \
- return (1); \
- } \
- } \
- memmove(lb + lbclen, l, len); \
- lbclen += len; \
-}
-
-#define NEEDSP(sp, len, pnt) { \
- if (lbclen + (len) > lblen) { \
- lblen += MAX(lbclen + (len), 256); \
- REALLOC(sp, lb, char *, lblen); \
- if (lb == NULL) { \
- lbclen = 0; \
- return (1); \
- } \
- pnt = lb + lbclen; \
- } \
-}
-
-/*
- * substitute --
- * Do the substitution. This stuff is *really* tricky. There are
- * lots of special cases, and general nastiness. Don't mess with it
- * unless you're pretty confident.
- */
-static int
-substitute(sp, ep, cmdp, s, re, flags)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- char *s;
- regex_t *re;
- u_int flags;
-{
- DECLARE_INTERRUPTS;
- MARK from, to;
- recno_t elno, lno;
- size_t blen, cnt, last, lbclen, lblen, len, llen, offset, saved_offset;
- int didsub, do_eol_match, eflags, empty_ok, eval;
- int linechanged, matched, quit, rval;
- int cflag, gflag, lflag, nflag, pflag, rflag;
- char *bp, *lb;
-
- /*
- * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
- * it only displayed the last change. I'd disallow them, but they are
- * useful in combination with the [v]global commands. In the current
- * model the problem is combining them with the 'c' flag -- the screen
- * would have to flip back and forth between the confirm screen and the
- * ex print screen, which would be pretty awful. We do display all
- * changes, though, for what that's worth.
- *
- * !!!
- * Historic vi was fairly strict about the order of "options", the
- * count, and "flags". I'm somewhat fuzzy on the difference between
- * options and flags, anyway, so this is a simpler approach, and we
- * just take it them in whatever order the user gives them. (The ex
- * usage statement doesn't reflect this.)
- */
- cflag = gflag = lflag = nflag = pflag = rflag = 0;
- for (lno = OOBLNO; *s != '\0'; ++s)
- switch (*s) {
- case ' ':
- case '\t':
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (lno != OOBLNO)
- goto usage;
- errno = 0;
- lno = strtoul(s, &s, 10);
- if (*s == '\0') /* Loop increment correction. */
- --s;
- if (errno == ERANGE) {
- if (lno == LONG_MAX)
- msgq(sp, M_ERR, "Count overflow.");
- else if (lno == LONG_MIN)
- msgq(sp, M_ERR, "Count underflow.");
- else
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- /*
- * In historic vi, the count was inclusive from the
- * second address.
- */
- cmdp->addr1.lno = cmdp->addr2.lno;
- cmdp->addr2.lno += lno - 1;
- break;
- case '#':
- nflag = 1;
- break;
- case 'c':
- cflag = 1;
- break;
- case 'g':
- gflag = 1;
- break;
- case 'l':
- lflag = 1;
- break;
- case 'p':
- pflag = 1;
- break;
- case 'r':
- if (LF_ISSET(SUB_FIRST)) {
- msgq(sp, M_ERR,
- "Regular expression specified; r flag meaningless.");
- return (1);
- }
- if (!F_ISSET(sp, S_SUBRE_SET)) {
- msgq(sp, M_ERR,
- "No previous regular expression.");
- return (1);
- }
- rflag = 1;
- break;
- default:
- goto usage;
- }
-
- if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) {
-usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
- return (1);
- }
-
- if (IN_VI_MODE(sp) && cflag && (lflag || nflag || pflag)) {
- msgq(sp, M_ERR,
- "The #, l and p flags may not be combined with the c flag in vi mode.");
- return (1);
- }
-
- if (!F_ISSET(sp, S_GLOBAL))
- SET_UP_INTERRUPTS(subst_intr);
-
- /*
- * bp: if interactive, line cache
- * blen: if interactive, line cache length
- * lb: build buffer pointer.
- * lbclen: current length of built buffer.
- * lblen; length of build buffer.
- */
- bp = lb = NULL;
- blen = lbclen = lblen = 0;
-
- /* For each line... */
- for (matched = quit = 0, lno = cmdp->addr1.lno,
- elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
-
- /* Someone's unhappy, time to stop. */
- if (F_ISSET(sp, S_INTERRUPTED)) {
- if (!F_ISSET(sp, S_GLOBAL))
- msgq(sp, M_INFO, "Interrupted.");
- break;
- }
-
- /* Get the line. */
- if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- /*
- * Make a local copy if doing confirmation -- when calling
- * the confirm routine we're likely to lose the cached copy.
- */
- if (cflag) {
- if (bp == NULL) {
- GET_SPACE_RET(sp, bp, blen, llen);
- } else
- ADD_SPACE_RET(sp, bp, blen, llen);
- memmove(bp, s, llen);
- s = bp;
- }
-
- /* Start searching from the beginning. */
- offset = 0;
- len = llen;
-
- /* Reset the build buffer offset. */
- lbclen = 0;
-
- /* Reset empty match flag. */
- empty_ok = 1;
-
- /*
- * We don't want to have to do a setline if the line didn't
- * change -- keep track of whether or not this line changed.
- * If doing confirmations, don't want to keep setting the
- * line if change is refused -- keep track of substitutions.
- */
- didsub = linechanged = 0;
-
- /* New line, do an EOL match. */
- do_eol_match = 1;
-
- /* It's not nul terminated, but we pretend it is. */
- eflags = REG_STARTEND;
-
- /*
- * The search area is from s + offset to the EOL.
- *
- * Generally, sp->match[0].rm_so is the offset of the start
- * of the match from the start of the search, and offset is
- * the offset of the start of the last search.
- */
-nextmatch: sp->match[0].rm_so = 0;
- sp->match[0].rm_eo = len;
-
- /* Get the next match. */
- eval = regexec(re,
- (char *)s + offset, re->re_nsub + 1, sp->match, eflags);
-
- /*
- * There wasn't a match or if there was an error, deal with
- * it. If there was a previous match in this line, resolve
- * the changes into the database. Otherwise, just move on.
- */
- if (eval == REG_NOMATCH)
- goto endmatch;
- if (eval != 0) {
- re_error(sp, eval, re);
- goto ret1;
- }
- matched = 1;
-
- /* Only the first search can match an anchored expression. */
- eflags |= REG_NOTBOL;
-
- /*
- * !!!
- * It's possible to match 0-length strings -- for example, the
- * command s;a*;X;, when matched against the string "aabb" will
- * result in "XbXbX", i.e. the matches are "aa", the space
- * between the b's and the space between the b's and the end of
- * the string. There is a similar space between the beginning
- * of the string and the a's. The rule that we use (because vi
- * historically used it) is that any 0-length match, occurring
- * immediately after a match, is ignored. Otherwise, the above
- * example would have resulted in "XXbXbX". Another example is
- * incorrectly using " *" to replace groups of spaces with one
- * space.
- *
- * The way we do this is that if we just had a successful match,
- * the starting offset does not skip characters, and the match
- * is empty, ignore the match and move forward. If there's no
- * more characters in the string, we were attempting to match
- * after the last character, so quit.
- */
- if (!empty_ok &&
- sp->match[0].rm_so == 0 && sp->match[0].rm_eo == 0) {
- empty_ok = 1;
- if (len == 0)
- goto endmatch;
- BUILD(sp, s + offset, 1)
- ++offset;
- --len;
- goto nextmatch;
- }
-
- /* Confirm change. */
- if (cflag) {
- /*
- * Set the cursor position for confirmation. Note,
- * if we matched on a '$', the cursor may be past
- * the end of line.
- *
- * XXX
- * We may want to "fix" this in the confirm routine,
- * if the confirm routine should be able to display
- * a cursor past EOL.
- */
- from.lno = to.lno = lno;
- from.cno = sp->match[0].rm_so + offset;
- to.cno = sp->match[0].rm_eo;
- if (llen == 0)
- from.cno = to.cno = 0;
- else {
- if (to.cno >= llen)
- to.cno = llen - 1;
- if (from.cno >= llen)
- from.cno = llen - 1;
- }
- switch (sp->s_confirm(sp, ep, &from, &to)) {
- case CONF_YES:
- break;
- case CONF_NO:
- didsub = 0;
- BUILD(sp, s +offset, sp->match[0].rm_eo);
- goto skip;
- case CONF_QUIT:
- /* Set the quit flag. */
- quit = 1;
-
- /* If interruptible, pass the info back. */
- if (F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-
- /*
- * If any changes, resolve them, otherwise
- * return to the main loop.
- */
- goto endmatch;
- }
- }
-
- /* Copy the bytes before the match into the build buffer. */
- BUILD(sp, s + offset, sp->match[0].rm_so);
-
- /*
- * Cursor moves to last line changed, unless doing confirm,
- * in which case don't move it.
- *
- * !!!
- * Historic vi just put the cursor on the first non-blank
- * of the last line changed. This might be better.
- */
- if (!cflag) {
- sp->lno = lno;
- sp->cno = sp->match[0].rm_so + offset;
- }
-
- /* Substitute the matching bytes. */
- didsub = 1;
- if (regsub(sp, s + offset, &lb, &lbclen, &lblen))
- goto ret1;
-
- /* Set the change flag so we know this line was modified. */
- linechanged = 1;
-
- /* Move past the matched bytes. */
-skip: offset += sp->match[0].rm_eo;
- len -= sp->match[0].rm_eo;
-
- /* A match cannot be followed by an empty pattern. */
- empty_ok = 0;
-
- /*
- * If doing a global change with confirmation, we have to
- * update the screen. The basic idea is to store the line
- * so the screen update routines can find it, and restart.
- */
- if (didsub && cflag && gflag) {
- /*
- * The new search offset will be the end of the
- * modified line.
- */
- saved_offset = lbclen;
-
- /* Copy the rest of the line. */
- if (len)
- BUILD(sp, s + offset, len)
-
- /* Set the new offset. */
- offset = saved_offset;
-
- /* Store inserted lines, adjusting the build buffer. */
- last = 0;
- if (sp->newl_cnt) {
- for (cnt = 0;
- cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
- if (file_iline(sp, ep, lno,
- lb + last, sp->newl[cnt] - last))
- goto ret1;
- last = sp->newl[cnt] + 1;
- ++sp->rptlines[L_ADDED];
- }
- lbclen -= last;
- offset -= last;
- sp->newl_cnt = 0;
- }
-
- /* Store and retrieve the line. */
- if (file_sline(sp, ep, lno, lb + last, lbclen))
- goto ret1;
- if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
- GETLINE_ERR(sp, lno);
- goto ret1;
- }
- ADD_SPACE_RET(sp, bp, blen, llen)
- memmove(bp, s, llen);
- s = bp;
- len = llen - offset;
-
- /* Restart the build. */
- lbclen = 0;
- BUILD(sp, s, offset);
-
- /*
- * If we haven't already done the after-the-string
- * match, do one. Set REG_NOTEOL so the '$' pattern
- * only matches once.
- */
- if (!do_eol_match)
- goto endmatch;
- if (offset == len) {
- do_eol_match = 0;
- eflags |= REG_NOTEOL;
- }
- goto nextmatch;
- }
-
- /*
- * If it's a global:
- *
- * If at the end of the string, do a test for the after
- * the string match. Set REG_NOTEOL so the '$' pattern
- * only matches once.
- */
- if (gflag && do_eol_match) {
- if (len == 0) {
- do_eol_match = 0;
- eflags |= REG_NOTEOL;
- }
- goto nextmatch;
- }
-
-endmatch: if (!linechanged)
- continue;
-
- /* Copy any remaining bytes into the build buffer. */
- if (len)
- BUILD(sp, s + offset, len)
-
- /* Store inserted lines, adjusting the build buffer. */
- last = 0;
- if (sp->newl_cnt) {
- for (cnt = 0;
- cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
- if (file_iline(sp, ep,
- lno, lb + last, sp->newl[cnt] - last))
- goto ret1;
- last = sp->newl[cnt] + 1;
- ++sp->rptlines[L_ADDED];
- }
- lbclen -= last;
- sp->newl_cnt = 0;
- }
-
- /* Store the changed line. */
- if (file_sline(sp, ep, lno, lb + last, lbclen))
- goto ret1;
-
- /* Update changed line counter. */
- ++sp->rptlines[L_CHANGED];
-
- /* Display as necessary. */
- if (lflag || nflag || pflag) {
- from.lno = to.lno = lno;
- from.cno = to.cno = 0;
- if (lflag)
- ex_print(sp, ep, &from, &to, E_F_LIST);
- if (nflag)
- ex_print(sp, ep, &from, &to, E_F_HASH);
- if (pflag)
- ex_print(sp, ep, &from, &to, E_F_PRINT);
- }
- }
-
- /*
- * If not in a global command, and nothing matched, say so.
- * Else, if none of the lines displayed, put something up.
- */
- if (!matched) {
- if (!F_ISSET(sp, S_GLOBAL))
- msgq(sp, M_INFO, "No match found.");
- } else if (!lflag && !nflag && !pflag)
- F_SET(EXP(sp), EX_AUTOPRINT);
-
- rval = 0;
- if (0) {
-ret1: rval = 1;
- }
-
-interrupt_err:
- if (!F_ISSET(sp, S_GLOBAL))
- TEAR_DOWN_INTERRUPTS;
-
- if (bp != NULL)
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
-
-/*
- * regsub --
- * Do the substitution for a regular expression.
- */
-static inline int
-regsub(sp, ip, lbp, lbclenp, lblenp)
- SCR *sp;
- char *ip; /* Input line. */
- char **lbp;
- size_t *lbclenp, *lblenp;
-{
- enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv;
- size_t lbclen, lblen; /* Local copies. */
- size_t mlen; /* Match length. */
- size_t rpl; /* Remaining replacement length. */
- char *rp; /* Replacement pointer. */
- int ch;
- int no; /* Match replacement offset. */
- char *p, *t; /* Buffer pointers. */
- char *lb; /* Local copies. */
-
- lb = *lbp; /* Get local copies. */
- lbclen = *lbclenp;
- lblen = *lblenp;
-
- /*
- * QUOTING NOTE:
- *
- * There are some special sequences that vi provides in the
- * replacement patterns.
- * & string the RE matched (\& if nomagic set)
- * \# n-th regular subexpression
- * \E end \U, \L conversion
- * \e end \U, \L conversion
- * \l convert the next character to lower-case
- * \L convert to lower-case, until \E, \e, or end of replacement
- * \u convert the next character to upper-case
- * \U convert to upper-case, until \E, \e, or end of replacement
- *
- * Otherwise, since this is the lowest level of replacement, discard
- * all escape characters. This (hopefully) follows historic practice.
- */
-#define ADDCH(ch) { \
- CHAR_T __ch = (ch); \
- u_int __value = term_key_val(sp, __ch); \
- if (__value == K_CR || __value == K_NL) { \
- NEEDNEWLINE(sp); \
- sp->newl[sp->newl_cnt++] = lbclen; \
- } else if (conv != C_NOTSET) { \
- switch (conv) { \
- case C_ONELOWER: \
- conv = C_NOTSET; \
- /* FALLTHROUGH */ \
- case C_LOWER: \
- if (isupper(__ch)) \
- __ch = tolower(__ch); \
- break; \
- case C_ONEUPPER: \
- conv = C_NOTSET; \
- /* FALLTHROUGH */ \
- case C_UPPER: \
- if (islower(__ch)) \
- __ch = toupper(__ch); \
- break; \
- default: \
- abort(); \
- } \
- } \
- NEEDSP(sp, 1, p); \
- *p++ = __ch; \
- ++lbclen; \
-}
- conv = C_NOTSET;
- for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
- switch (ch = *rp++) {
- case '&':
- if (O_ISSET(sp, O_MAGIC)) {
- no = 0;
- goto subzero;
- }
- break;
- case '\\':
- if (rpl == 0)
- break;
- --rpl;
- switch (ch = *rp) {
- case '&':
- if (!O_ISSET(sp, O_MAGIC)) {
- ++rp;
- no = 0;
- goto subzero;
- }
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- no = *rp++ - '0';
-subzero: if (sp->match[no].rm_so == -1 ||
- sp->match[no].rm_eo == -1)
- continue;
- mlen =
- sp->match[no].rm_eo - sp->match[no].rm_so;
- for (t = ip + sp->match[no].rm_so; mlen--; ++t)
- ADDCH(*t);
- continue;
- case 'e':
- case 'E':
- ++rp;
- conv = C_NOTSET;
- continue;
- case 'l':
- ++rp;
- conv = C_ONELOWER;
- continue;
- case 'L':
- ++rp;
- conv = C_LOWER;
- continue;
- case 'u':
- ++rp;
- conv = C_ONEUPPER;
- continue;
- case 'U':
- ++rp;
- conv = C_UPPER;
- continue;
- default:
- ++rp;
- break;
- }
- }
- ADDCH(ch);
- }
-
- *lbp = lb; /* Update caller's information. */
- *lbclenp = lbclen;
- *lblenp = lblen;
- return (0);
-}
-
-static int
-checkmatchsize(sp, re)
- SCR *sp;
- regex_t *re;
-{
- /* Build nsub array as necessary. */
- if (sp->matchsize < re->re_nsub + 1) {
- sp->matchsize = re->re_nsub + 1;
- REALLOC(sp, sp->match,
- regmatch_t *, sp->matchsize * sizeof(regmatch_t));
- if (sp->match == NULL) {
- sp->matchsize = 0;
- return (1);
- }
- }
- return (0);
-}
-
-/*
- * subst_intr --
- * Set the interrupt bit in any screen that is interruptible.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one substitute running, it will be hard to decide which one to
- * stop.
- */
-static void
-subst_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
diff --git a/usr.bin/vi/nex/ex_tag.c b/usr.bin/vi/nex/ex_tag.c
deleted file mode 100644
index c47ab0de9c44..000000000000
--- a/usr.bin/vi/nex/ex_tag.c
+++ /dev/null
@@ -1,859 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * David Hitz of Auspex Systems, Inc.
- *
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_tag.c 8.31 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "tag.h"
-
-static char *binary_search __P((char *, char *, char *));
-static int compare __P((char *, char *, char *));
-static char *linear_search __P((char *, char *, char *));
-static int search __P((SCR *, char *, char *, char **));
-static int tag_get __P((SCR *, char *, char **, char **, char **));
-
-/*
- * ex_tagfirst --
- * The tag code can be entered from main, i.e. "vi -t tag".
- */
-int
-ex_tagfirst(sp, tagarg)
- SCR *sp;
- char *tagarg;
-{
- FREF *frp;
- MARK m;
- long tl;
- u_int flags;
- int sval;
- char *p, *tag, *name, *search;
-
- /* Taglength may limit the number of characters. */
- if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(tagarg) > tl)
- tagarg[tl] = '\0';
-
- /* Get the tag information. */
- if (tag_get(sp, tagarg, &tag, &name, &search))
- return (1);
-
- /* Create the file entry. */
- if ((frp = file_add(sp, NULL, name, 0)) == NULL)
- return (1);
- if (file_init(sp, frp, NULL, 0))
- return (1);
-
- /*
- * !!!
- * Historic vi accepted a line number as well as a search
- * string, and people are apparently still using the format.
- */
- if (isdigit(search[0])) {
- m.lno = atoi(search);
- m.cno = 0;
- } else {
- /*
- * Search for the tag; cheap fallback for C functions if
- * the name is the same but the arguments have changed.
- */
- m.lno = 1;
- m.cno = 0;
- flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
- sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
- if (sval && (p = strrchr(search, '(')) != NULL) {
- p[1] = '\0';
- sval = f_search(sp, sp->ep,
- &m, &m, search, NULL, &flags);
- }
- if (sval)
- msgq(sp, M_ERR, "%s: search pattern not found.", tag);
- }
-
- /* Set up the screen. */
- frp->lno = m.lno;
- frp->cno = m.cno;
- F_SET(frp, FR_CURSORSET);
-
- /* Might as well make this the default tag. */
- if ((EXP(sp)->tlast = strdup(tagarg)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- return (0);
-}
-
-/*
- * ex_tagpush -- :tag [file]
- * Move to a new tag.
- *
- * The tags stacks in nvi are a bit tricky. Each tag contains a file name,
- * search string, and line/column numbers. The search string is only used
- * for the first access and for user display. The first record on the stack
- * is the place where we first did a tag, so it has no search string. The
- * second record is the first tag, and so on. Note, this means that the
- * "current" tag is always on the stack. Each tag has a line/column which is
- * the location from which the user tagged the following TAG entry, and which
- * is used as the return location.
- */
-int
-ex_tagpush(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- enum {TC_CHANGE, TC_CURRENT} which;
- EX_PRIVATE *exp;
- FREF *frp;
- MARK m;
- TAG *tp;
- u_int flags;
- int sval;
- long tl;
- char *name, *p, *search, *tag;
-
- exp = EXP(sp);
- switch (cmdp->argc) {
- case 1:
- if (exp->tlast != NULL)
- FREE(exp->tlast, strlen(exp->tlast) + 1);
- if ((exp->tlast = strdup(cmdp->argv[0]->bp)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- break;
- case 0:
- if (exp->tlast == NULL) {
- msgq(sp, M_ERR, "No previous tag entered.");
- return (1);
- }
- break;
- default:
- abort();
- }
-
- /* Taglength may limit the number of characters. */
- if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tlast) > tl)
- exp->tlast[tl] = '\0';
-
- /* Get the tag information. */
- if (tag_get(sp, exp->tlast, &tag, &name, &search))
- return (1);
-
- /* Get a new FREF structure. */
- if ((frp = file_add(sp, sp->frp, name, 1)) == NULL) {
- FREE(tag, strlen(tag));
- return (1);
- }
-
- /*
- * Get a tag structure -- if this is the first tag, push it on the
- * stack as a placeholder and get another tag structure. Set the
- * line/column of the most recent element on the stack to be the
- * current values, including the file pointer. Then push the new
- * TAG onto the stack with the new file and search string for user
- * display.
- */
- CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
- if (tp != NULL && exp->tagq.tqh_first == NULL) {
- TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
- CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
- }
- if (exp->tagq.tqh_first != NULL) {
- exp->tagq.tqh_first->frp = sp->frp;
- exp->tagq.tqh_first->lno = sp->lno;
- exp->tagq.tqh_first->cno = sp->cno;
- }
- if (tp != NULL) {
- if ((tp->search = strdup(search)) == NULL)
- msgq(sp, M_SYSERR, NULL);
- else
- tp->slen = strlen(search);
- tp->frp = frp;
- TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
- }
-
- /* Switch to the new file. */
- if (sp->frp == frp)
- which = TC_CURRENT;
- else {
- MODIFY_CHECK(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
-
- if (file_init(sp, frp, NULL, 0)) {
- if (tp != NULL)
- FREE(tp, sizeof(TAG));
- FREE(tag, strlen(tag));
- return (1);
- }
- which = TC_CHANGE;
- }
-
- /*
- * !!!
- * Historic vi accepted a line number as well as a search
- * string, and people are apparently still using the format.
- */
- if (isdigit(search[0])) {
- m.lno = atoi(search);
- m.cno = 0;
- sval = 0;
- } else {
- /*
- * Search for the tag; cheap fallback for C functions
- * if the name is the same but the arguments have changed.
- */
- m.lno = 1;
- m.cno = 0;
- flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
- sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
- if (sval && (p = strrchr(search, '(')) != NULL) {
- p[1] = '\0';
- sval = f_search(sp, sp->ep,
- &m, &m, search, NULL, &flags);
- p[1] = '(';
- }
- if (sval)
- msgq(sp, M_ERR, "%s: search pattern not found.", tag);
- }
- free(tag);
-
- switch (which) {
- case TC_CHANGE:
- frp->lno = m.lno;
- frp->cno = m.cno;
- F_SET(frp, FR_CURSORSET);
- F_SET(sp, S_FSWITCH);
- break;
- case TC_CURRENT:
- if (sval)
- return (1);
- sp->lno = m.lno;
- sp->cno = m.cno;
- break;
- }
- return (0);
-}
-
-/* Free a tag or tagf structure from a queue. */
-#define FREETAG(tp) { \
- TAILQ_REMOVE(&exp->tagq, (tp), q); \
- if ((tp)->search != NULL) \
- free((tp)->search); \
- FREE((tp), sizeof(TAGF)); \
-}
-#define FREETAGF(tfp) { \
- TAILQ_REMOVE(&exp->tagfq, (tfp), q); \
- free((tfp)->name); \
- FREE((tfp), sizeof(TAGF)); \
-}
-
-/*
- * ex_tagpop -- :tagp[op][!] [number | file]
- * Pop the tag stack.
- */
-int
-ex_tagpop(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- EX_PRIVATE *exp;
- TAG *ntp, *tp;
- recno_t lno;
- long off, saved_off;
- size_t arglen, cno;
- char *arg, *p, *t;
-
- /* Check for an empty stack. */
- exp = EXP(sp);
- if (exp->tagq.tqh_first == NULL) {
- msgq(sp, M_INFO, "The tags stack is empty.");
- return (1);
- }
-
- switch (cmdp->argc) {
- case 0: /* Pop one tag. */
- tp = exp->tagq.tqh_first;
- FREETAG(tp);
- break;
- case 1: /* Name or number. */
- arg = cmdp->argv[0]->bp;
- saved_off = strtol(arg, &p, 10);
- if (*p == '\0') {
- if (saved_off < 1)
- return (0);
- for (tp = exp->tagq.tqh_first, off = saved_off;
- tp != NULL && off-- > 1; tp = tp->q.tqe_next);
- if (tp == NULL) {
- msgq(sp, M_ERR,
-"Less than %d entries on the tags stack; use :display to see the tags stack.",
- saved_off);
- return (1);
- }
- for (off = saved_off; off-- > 1;) {
- tp = exp->tagq.tqh_first;
- FREETAG(tp);
- }
- } else {
- arglen = strlen(arg);
- for (tp = exp->tagq.tqh_first;
- tp != NULL; tp = tp->q.tqe_next) {
- /* Use the user's original file name. */
- p = tp->frp->name;
- if ((t = strrchr(p, '/')) == NULL)
- t = p;
- else
- ++t;
- if (!strncmp(arg, t, arglen)) {
- ntp = tp;
- break;
- }
- }
- if (tp == NULL) {
- msgq(sp, M_ERR,
-"No file named %s on the tags stack; use :display to see the tags stack.",
- arg);
- return (1);
- }
- for (;;) {
- tp = exp->tagq.tqh_first;
- if (tp == ntp)
- break;
- FREETAG(tp);
- }
- }
- break;
- default:
- abort();
- }
-
- /* Update the cursor from the saved TAG information. */
- tp = exp->tagq.tqh_first;
- if (tp->frp == sp->frp) {
- sp->lno = tp->lno;
- sp->cno = tp->cno;
- } else {
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
-
- if (file_init(sp, tp->frp, NULL, 0))
- return (1);
-
- tp->frp->lno = tp->lno;
- tp->frp->cno = tp->cno;
- F_SET(sp->frp, FR_CURSORSET);
-
- F_SET(sp, S_FSWITCH);
- }
-
- /* If returning to the first tag, the stack is now empty. */
- if (tp->q.tqe_next == NULL)
- FREETAG(tp);
- return (0);
-}
-
-/*
- * ex_tagtop -- :tagt[op][!]
- * Clear the tag stack.
- */
-int
-ex_tagtop(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- EX_PRIVATE *exp;
- TAG *tp, tmp;
- int found;
-
- /* Pop to oldest saved information. */
- exp = EXP(sp);
- for (found = 0; (tp = exp->tagq.tqh_first) != NULL; found = 1) {
- if (exp->tagq.tqh_first == NULL)
- tmp = *tp;
- FREETAG(tp);
- }
-
- if (!found) {
- msgq(sp, M_INFO, "The tags stack is empty.");
- return (1);
- }
-
- /* If not switching files, it's easy; else do the work. */
- if (tmp.frp == sp->frp) {
- sp->lno = tmp.lno;
- sp->cno = tmp.cno;
- } else {
- MODIFY_CHECK(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
-
- if (file_init(sp, tmp.frp, NULL, 0))
- return (1);
-
- tmp.frp->lno = tmp.lno;
- tmp.frp->cno = tmp.cno;
-
- F_SET(sp->frp, FR_CURSORSET);
-
- F_SET(sp, S_FSWITCH);
- }
- return (0);
-}
-
-/*
- * ex_tagdisplay --
- * Display the list of tags.
- */
-int
-ex_tagdisplay(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- EX_PRIVATE *exp;
- TAG *tp;
- size_t len, maxlen;
- int cnt;
- char *name;
-
- exp = EXP(sp);
- if ((tp = exp->tagq.tqh_first) == NULL) {
- (void)ex_printf(EXCOOKIE, "No tags to display.\n");
- return (0);
- }
-
- /*
- * Figure out the formatting. MNOC is the maximum
- * number of file name columns before we split the line.
- */
-#define MNOC 15
- for (maxlen = 0,
- tp = exp->tagq.tqh_first; tp != NULL; tp = tp->q.tqe_next) {
- len = strlen(name = tp->frp->name); /* The original name. */
- if (maxlen < len && len < MNOC)
- maxlen = len;
- }
-
- for (cnt = 1, tp = exp->tagq.tqh_first; tp != NULL;
- ++cnt, tp = tp->q.tqe_next) {
- len = strlen(name = tp->frp->name); /* The original name. */
- if (len > maxlen || len + tp->slen > sp->cols)
- if (tp == NULL || tp->search == NULL)
- (void)ex_printf(EXCOOKIE,
- "%2d %s\n", cnt, name);
- else
- (void)ex_printf(EXCOOKIE,
- "%2d %s\n** %*.*s %s\n", cnt, name,
- (int)maxlen, (int)maxlen, "", tp->search);
- else
- if (tp == NULL || tp->search == NULL)
- (void)ex_printf(EXCOOKIE, "%2d %*.*s\n",
- cnt, (int)maxlen, (int)len, name);
- else
- (void)ex_printf(EXCOOKIE, "%2d %*.*s %s\n",
- cnt, (int)maxlen, (int)len, name,
- tp->search);
- }
- return (0);
-}
-
-/*
- * ex_tagalloc --
- * Create a new list of tag files.
- */
-int
-ex_tagalloc(sp, str)
- SCR *sp;
- char *str;
-{
- EX_PRIVATE *exp;
- TAGF *tp;
- size_t len;
- char *p, *t;
-
- /* Free current queue. */
- exp = EXP(sp);
- while ((tp = exp->tagfq.tqh_first) != NULL)
- FREETAGF(tp);
-
- /* Create new queue. */
- for (p = t = str;; ++p) {
- if (*p == '\0' || isblank(*p)) {
- if ((len = p - t) > 1) {
- MALLOC_RET(sp, tp, TAGF *, sizeof(TAGF));
- MALLOC(sp, tp->name, char *, len + 1);
- if (tp->name == NULL) {
- FREE(tp, sizeof(TAGF));
- return (1);
- }
- memmove(tp->name, t, len);
- tp->name[len] = '\0';
- tp->flags = 0;
- TAILQ_INSERT_TAIL(&exp->tagfq, tp, q);
- }
- t = p + 1;
- }
- if (*p == '\0')
- break;
- }
- return (0);
-}
- /* Free previous queue. */
-/*
- * ex_tagfree --
- * Free the tags file list.
- */
-int
-ex_tagfree(sp)
- SCR *sp;
-{
- EX_PRIVATE *exp;
- TAG *tp;
- TAGF *tfp;
-
- /* Free up tag information. */
- exp = EXP(sp);
- while ((tp = exp->tagq.tqh_first) != NULL)
- FREETAG(tp);
- while ((tfp = exp->tagfq.tqh_first) != NULL)
- FREETAGF(tfp);
- FREE(exp->tlast, strlen(exp->tlast) + 1);
- return (0);
-}
-
-/*
- * ex_tagcopy --
- * Copy a screen's tag structures.
- */
-int
-ex_tagcopy(orig, sp)
- SCR *orig, *sp;
-{
- EX_PRIVATE *oexp, *nexp;
- TAG *ap, *tp;
- TAGF *atfp, *tfp;
-
- /* Copy tag stack. */
- oexp = EXP(orig);
- nexp = EXP(sp);
- for (ap = oexp->tagq.tqh_first; ap != NULL; ap = ap->q.tqe_next) {
- MALLOC(sp, tp, TAG *, sizeof(TAG));
- if (tp == NULL)
- goto nomem;
- *tp = *ap;
- if (ap->search != NULL &&
- (tp->search = strdup(ap->search)) == NULL)
- goto nomem;
- TAILQ_INSERT_TAIL(&nexp->tagq, tp, q);
- }
-
- /* Copy list of tag files. */
- for (atfp = oexp->tagfq.tqh_first;
- atfp != NULL; atfp = atfp->q.tqe_next) {
- MALLOC(sp, tfp, TAGF *, sizeof(TAGF));
- if (tfp == NULL)
- goto nomem;
- *tfp = *atfp;
- if ((tfp->name = strdup(atfp->name)) == NULL)
- goto nomem;
- TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);
- }
-
- /* Copy the last tag. */
- if (oexp->tlast != NULL &&
- (nexp->tlast = strdup(oexp->tlast)) == NULL) {
-nomem: msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- return (0);
-}
-
-/*
- * tag_get --
- * Get a tag from the tags files.
- */
-static int
-tag_get(sp, tag, tagp, filep, searchp)
- SCR *sp;
- char *tag, **tagp, **filep, **searchp;
-{
- EX_PRIVATE *exp;
- TAGF *tfp;
- int dne;
- char *p;
-
- /*
- * Find the tag, only display missing file messages once, and
- * then only if we didn't find the tag.
- */
- dne = 0;
- exp = EXP(sp);
- for (p = NULL, tfp = exp->tagfq.tqh_first;
- tfp != NULL && p == NULL; tfp = tfp->q.tqe_next) {
- errno = 0;
- F_CLR(tfp, TAGF_DNE);
- if (search(sp, tfp->name, tag, &p))
- if (errno == ENOENT) {
- if (!F_ISSET(tfp, TAGF_DNE_WARN)) {
- dne = 1;
- F_SET(tfp, TAGF_DNE);
- }
- } else
- msgq(sp, M_SYSERR, tfp->name);
- }
-
- if (p == NULL) {
- msgq(sp, M_ERR, "%s: tag not found.", tag);
- if (dne)
- for (tfp = exp->tagfq.tqh_first;
- tfp != NULL; tfp = tfp->q.tqe_next)
- if (F_ISSET(tfp, TAGF_DNE)) {
- errno = ENOENT;
- msgq(sp, M_SYSERR, tfp->name);
- F_SET(tfp, TAGF_DNE_WARN);
- }
- return (1);
- }
-
- /*
- * Set the return pointers; tagp points to the tag, and, incidentally
- * the allocated string, filep points to the nul-terminated file name,
- * searchp points to the nul-terminated search string.
- */
- for (*tagp = p; *p && !isblank(*p); ++p);
- if (*p == '\0')
- goto malformed;
- for (*p++ = '\0'; isblank(*p); ++p);
- for (*filep = p; *p && !isblank(*p); ++p);
- if (*p == '\0')
- goto malformed;
- for (*p++ = '\0'; isblank(*p); ++p);
- *searchp = p;
- if (*p == '\0') {
-malformed: free(*tagp);
- msgq(sp, M_ERR, "%s: corrupted tag in %s.", tag, tfp->name);
- return (1);
- }
- return (0);
-}
-
-#define EQUAL 0
-#define GREATER 1
-#define LESS (-1)
-
-/*
- * search --
- * Search a file for a tag.
- */
-static int
-search(sp, name, tname, tag)
- SCR *sp;
- char *name, *tname, **tag;
-{
- struct stat sb;
- int fd, len;
- char *endp, *back, *front, *map, *p;
-
- if ((fd = open(name, O_RDONLY, 0)) < 0)
- return (1);
-
- /*
- * XXX
- * We'd like to test if the file is too big to mmap. Since we don't
- * know what size or type off_t's or size_t's are, what the largest
- * unsigned integral type is, or what random insanity the local C
- * compiler will perpetrate, doing the comparison in a portable way
- * is flatly impossible. Hope that malloc fails if the file is too
- * large.
- */
- if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size,
- PROT_READ, MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
- (void)close(fd);
- return (1);
- }
- front = map;
- back = front + sb.st_size;
-
- front = binary_search(tname, front, back);
- front = linear_search(tname, front, back);
-
- if (front == NULL || (endp = strchr(front, '\n')) == NULL) {
- *tag = NULL;
- goto done;
- }
-
- len = endp - front;
- MALLOC(sp, p, char *, len + 1);
- if (p == NULL) {
- *tag = NULL;
- goto done;
- }
- memmove(p, front, len);
- p[len] = '\0';
- *tag = p;
-
-done: if (munmap(map, (size_t)sb.st_size))
- msgq(sp, M_SYSERR, "munmap");
- if (close(fd))
- msgq(sp, M_SYSERR, "close");
- return (0);
-}
-
-/*
- * Binary search for "string" in memory between "front" and "back".
- *
- * This routine is expected to return a pointer to the start of a line at
- * *or before* the first word matching "string". Relaxing the constraint
- * this way simplifies the algorithm.
- *
- * Invariants:
- * front points to the beginning of a line at or before the first
- * matching string.
- *
- * back points to the beginning of a line at or after the first
- * matching line.
- *
- * Base of the Invariants.
- * front = NULL;
- * back = EOF;
- *
- * Advancing the Invariants:
- *
- * p = first newline after halfway point from front to back.
- *
- * If the string at "p" is not greater than the string to match,
- * p is the new front. Otherwise it is the new back.
- *
- * Termination:
- *
- * The definition of the routine allows it return at any point,
- * since front is always at or before the line to print.
- *
- * In fact, it returns when the chosen "p" equals "back". This
- * implies that there exists a string is least half as long as
- * (back - front), which in turn implies that a linear search will
- * be no more expensive than the cost of simply printing a string or two.
- *
- * Trying to continue with binary search at this point would be
- * more trouble than it's worth.
- */
-#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n');
-
-static char *
-binary_search(string, front, back)
- register char *string, *front, *back;
-{
- register char *p;
-
- p = front + (back - front) / 2;
- SKIP_PAST_NEWLINE(p, back);
-
- while (p != back) {
- if (compare(string, p, back) == GREATER)
- front = p;
- else
- back = p;
- p = front + (back - front) / 2;
- SKIP_PAST_NEWLINE(p, back);
- }
- return (front);
-}
-
-/*
- * Find the first line that starts with string, linearly searching from front
- * to back.
- *
- * Return NULL for no such line.
- *
- * This routine assumes:
- *
- * o front points at the first character in a line.
- * o front is before or at the first line to be printed.
- */
-static char *
-linear_search(string, front, back)
- char *string, *front, *back;
-{
- while (front < back) {
- switch (compare(string, front, back)) {
- case EQUAL: /* Found it. */
- return (front);
- break;
- case LESS: /* No such string. */
- return (NULL);
- break;
- case GREATER: /* Keep going. */
- break;
- }
- SKIP_PAST_NEWLINE(front, back);
- }
- return (NULL);
-}
-
-/*
- * Return LESS, GREATER, or EQUAL depending on how the string1 compares
- * with string2 (s1 ??? s2).
- *
- * o Matches up to len(s1) are EQUAL.
- * o Matches up to len(s2) are GREATER.
- *
- * The string "s1" is null terminated. The string s2 is '\t', space, (or
- * "back") terminated.
- *
- * !!!
- * Reasonably modern ctags programs use tabs as separators, not spaces.
- * However, historic programs did use spaces, and, I got complaints.
- */
-static int
-compare(s1, s2, back)
- register char *s1, *s2, *back;
-{
- for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)
- if (*s1 != *s2)
- return (*s1 < *s2 ? LESS : GREATER);
- return (*s1 ? GREATER : s2 < back &&
- (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL);
-}
diff --git a/usr.bin/vi/nex/ex_undo.c b/usr.bin/vi/nex/ex_undo.c
deleted file mode 100644
index c8dedd8d401a..000000000000
--- a/usr.bin/vi/nex/ex_undo.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_undo.c 8.4 (Berkeley) 12/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_undol -- U
- * Undo changes to this line.
- */
-int
-ex_undol(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- if (log_setline(sp, ep))
- return (1);
-
- sp->cno = 0;
- return (0);
-}
-
-/*
- * ex_undo -- u
- * Undo the last change.
- */
-int
-ex_undo(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- MARK m;
-
- /*
- * !!!
- * Multiple undo isn't available in ex, as there's no '.' command.
- * Whether 'u' is undo or redo is toggled each time, unless there
- * was a change since the last undo, in which case it's an undo.
- */
- if (!F_ISSET(ep, F_UNDO)) {
- F_SET(ep, F_UNDO);
- ep->lundo = FORWARD;
- }
- switch (ep->lundo) {
- case BACKWARD:
- if (log_forward(sp, ep, &m))
- return (1);
- ep->lundo = FORWARD;
- break;
- case FORWARD:
- if (log_backward(sp, ep, &m))
- return (1);
- ep->lundo = BACKWARD;
- break;
- case NOTSET:
- abort();
- }
- sp->lno = m.lno;
- sp->cno = m.cno;
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_usage.c b/usr.bin/vi/nex/ex_usage.c
deleted file mode 100644
index da84995d2993..000000000000
--- a/usr.bin/vi/nex/ex_usage.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_usage.c 8.11 (Berkeley) 12/17/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * ex_help -- :help
- * Display help message.
- */
-int
-ex_help(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- (void)ex_printf(EXCOOKIE,
- "To see the list of vi commands, enter \":viusage<CR>\"\n");
- (void)ex_printf(EXCOOKIE,
- "To see the list of ex commands, enter \":exusage<CR>\"\n");
- (void)ex_printf(EXCOOKIE,
- "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n");
- (void)ex_printf(EXCOOKIE,
- "For a vi key usage statement enter \":viusage [key]<CR>\"\n");
- (void)ex_printf(EXCOOKIE, "To exit, enter \":q!\"\n");
- return (0);
-}
-
-/*
- * ex_usage -- :exusage [cmd]
- * Display ex usage strings.
- */
-int
-ex_usage(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- ARGS *ap;
- EXCMDLIST const *cp;
-
- switch (cmdp->argc) {
- case 1:
- ap = cmdp->argv[0];
- for (cp = cmds; cp->name != NULL &&
- memcmp(ap->bp, cp->name, ap->len); ++cp);
- if (cp->name == NULL)
- (void)ex_printf(EXCOOKIE,
- "The %.*s command is unknown.",
- (int)ap->len, ap->bp);
- else {
- (void)ex_printf(EXCOOKIE,
- "Command: %s\n Usage: %s\n", cp->help, cp->usage);
- /*
- * !!!
- * The "visual" command has two modes, one from ex,
- * one from the vi colon line. Don't ask.
- */
- if (cp != &cmds[C_VISUAL_EX] &&
- cp != &cmds[C_VISUAL_VI])
- break;
- if (cp == &cmds[C_VISUAL_EX])
- cp = &cmds[C_VISUAL_VI];
- else
- cp = &cmds[C_VISUAL_EX];
- (void)ex_printf(EXCOOKIE,
- "Command: %s\n Usage: %s\n", cp->help, cp->usage);
- }
- break;
- case 0:
- for (cp = cmds; cp->name != NULL; ++cp)
- (void)ex_printf(EXCOOKIE,
- "%*s: %s\n", MAXCMDNAMELEN, cp->name, cp->help);
- break;
- default:
- abort();
- }
- return (0);
-}
-
-/*
- * ex_viusage -- :viusage [key]
- * Display vi usage strings.
- */
-int
-ex_viusage(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- VIKEYS const *kp;
- int key;
-
- switch (cmdp->argc) {
- case 1:
- key = cmdp->argv[0]->bp[0];
- if (key > MAXVIKEY)
- goto nokey;
-
- /* Special case: '[' and ']' commands. */
- if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key)
- goto nokey;
-
- kp = &vikeys[key];
- if (kp->func == NULL)
-nokey: (void)ex_printf(EXCOOKIE,
- "The %s key has no current meaning",
- charname(sp, key));
- else
- (void)ex_printf(EXCOOKIE,
- " Key:%s%s\nUsage: %s\n",
- isblank(*kp->help) ? "" : " ", kp->help, kp->usage);
- break;
- case 0:
- for (key = 0; key <= MAXVIKEY; ++key) {
- kp = &vikeys[key];
- if (kp->help != NULL)
- (void)ex_printf(EXCOOKIE, "%s\n", kp->help);
- }
- break;
- default:
- abort();
- }
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_util.c b/usr.bin/vi/nex/ex_util.c
deleted file mode 100644
index fa7e70b9dfcc..000000000000
--- a/usr.bin/vi/nex/ex_util.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_util.c 8.4 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_getline --
- * Return a line from the terminal.
- */
-int
-ex_getline(sp, fp, lenp)
- SCR *sp;
- FILE *fp;
- size_t *lenp;
-{
- EX_PRIVATE *exp;
- size_t off;
- int ch;
- char *p;
-
- exp = EXP(sp);
- for (off = 0, p = exp->ibp;; ++off) {
- ch = getc(fp);
- if (off >= exp->ibp_len) {
- BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
- p = exp->ibp + off;
- }
- if (ch == EOF || ch == '\n') {
- if (ch == EOF && !off)
- return (1);
- *lenp = off;
- return (0);
- }
- *p++ = ch;
- }
- /* NOTREACHED */
-}
diff --git a/usr.bin/vi/nex/ex_version.c b/usr.bin/vi/nex/ex_version.c
deleted file mode 100644
index 230632d2de3c..000000000000
--- a/usr.bin/vi/nex/ex_version.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_version.c 8.32 (Berkeley) 1/23/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_version -- :version
- * Display the program version.
- */
-int
-ex_version(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- static time_t then = 759365451;
-
- (void)ex_printf(EXCOOKIE,
-"Version 1.03, %sThe CSRG, University of California, Berkeley.\n",
- ctime(&then));
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_visual.c b/usr.bin/vi/nex/ex_visual.c
deleted file mode 100644
index d53152bde8e8..000000000000
--- a/usr.bin/vi/nex/ex_visual.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_visual.c 8.7 (Berkeley) 11/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
- *
- * Switch to visual mode.
- */
-int
-ex_visual(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- size_t len;
- int pos;
- char buf[256];
-
- /* If open option off, disallow visual command. */
- if (!O_ISSET(sp, O_OPEN)) {
- msgq(sp, M_ERR,
- "The visual command requires that the open option be set.");
- return (1);
- }
-
- /* If a line specified, move to that line. */
- if (cmdp->addrcnt)
- sp->lno = cmdp->addr1.lno;
-
- /*
- * Push a command based on the line position flags. If no
- * flag specified, the line goes at the top of the screen.
- */
- switch (F_ISSET(cmdp, E_F_CARAT | E_F_DASH | E_F_DOT | E_F_PLUS)) {
- case E_F_CARAT:
- pos = '^';
- break;
- case E_F_DASH:
- pos = '-';
- break;
- case E_F_DOT:
- pos = '.';
- break;
- case E_F_PLUS:
- default:
- pos = '+';
- break;
- }
-
- if (F_ISSET(cmdp, E_COUNT))
- len = snprintf(buf, sizeof(buf),
- "%luz%c%lu", sp->lno, pos, cmdp->count);
- else
- len = snprintf(buf, sizeof(buf), "%luz%c", sp->lno, pos);
- (void)term_push(sp, buf, len, 0, CH_NOMAP | CH_QUOTED);
-
- /*
- * !!!
- * Historically, if no line address was specified, the [p#l] flags
- * caused the cursor to be moved to the last line of the file, which
- * was then positioned as described above. This seems useless, so
- * I haven't implemented it.
- */
- switch (F_ISSET(cmdp, E_F_HASH | E_F_LIST | E_F_PRINT)) {
- case E_F_HASH:
- O_SET(sp, O_NUMBER);
- break;
- case E_F_LIST:
- O_SET(sp, O_LIST);
- break;
- case E_F_PRINT:
- break;
- }
-
- /* Switch modes. */
- F_CLR(sp, S_SCREENS);
- F_SET(sp, sp->saved_vi_mode);
-
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_write.c b/usr.bin/vi/nex/ex_write.c
deleted file mode 100644
index 5a51b6dff914..000000000000
--- a/usr.bin/vi/nex/ex_write.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_write.c 8.19 (Berkeley) 12/18/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-enum which {WQ, WRITE, XIT};
-
-static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));
-
-/*
- * ex_wq -- :wq[!] [>>] [file]
- * Write to a file.
- */
-int
-ex_wq(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- int force;
-
- if (exwr(sp, ep, cmdp, WQ))
- return (1);
-
- force = F_ISSET(cmdp, E_FORCE);
- if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
- msgq(sp, M_ERR,
- "More files to edit; use \":n\" to go to the next file");
- return (1);
- }
-
- F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
- return (0);
-}
-
-/*
- * ex_write -- :write[!] [>>] [file]
- * :write [!] [cmd]
- * Write to a file.
- */
-int
-ex_write(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (exwr(sp, ep, cmdp, WRITE));
-}
-
-
-/*
- * ex_xit -- :x[it]! [file]
- *
- * Write out any modifications and quit.
- */
-int
-ex_xit(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- int force;
-
- if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
- return (1);
-
- force = F_ISSET(cmdp, E_FORCE);
- if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
- msgq(sp, M_ERR,
- "More files to edit; use \":n\" to go to the next file");
- return (1);
- }
-
- F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
- return (0);
-}
-
-/*
- * exwr --
- * The guts of the ex write commands.
- */
-static int
-exwr(sp, ep, cmdp, cmd)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which cmd;
-{
- EX_PRIVATE *exp;
- MARK rm;
- int flags;
- char *name, *p;
-
- /* All write commands can have an associated '!'. */
- LF_INIT(FS_POSSIBLE);
- if (F_ISSET(cmdp, E_FORCE))
- LF_SET(FS_FORCE);
-
- /* Skip any leading whitespace. */
- if (cmdp->argc != 0)
- for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);
-
- /* If no arguments, just write the file back. */
- if (cmdp->argc == 0 || *p == '\0') {
- if (F_ISSET(cmdp, E_ADDR2_ALL))
- LF_SET(FS_ALL);
- return (file_write(sp, ep,
- &cmdp->addr1, &cmdp->addr2, NULL, flags));
- }
-
- /* If "write !" it's a pipe to a utility. */
- exp = EXP(sp);
- if (cmd == WRITE && *p == '!') {
- for (++p; *p && isblank(*p); ++p);
- if (*p == '\0') {
- msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
- return (1);
- }
- /* Expand the argument. */
- if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
- return (1);
- if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
- &rm, cmdp->argv[1]->bp, FILTER_WRITE))
- return (1);
- sp->lno = rm.lno;
- return (0);
- }
-
- /* If "write >>" it's an append to a file. */
- if (cmd != XIT && p[0] == '>' && p[1] == '>') {
- LF_SET(FS_APPEND);
-
- /* Skip ">>" and whitespace. */
- for (p += 2; *p && isblank(*p); ++p);
- }
-
- /* Build an argv so we get an argument count and file expansion. */
- if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
- return (1);
-
- switch (cmdp->argc) {
- case 1:
- /*
- * Nothing to expand, write the current file.
- * XXX
- * Should never happen, already checked this case.
- */
- name = NULL;
- break;
- case 2:
- /* One new argument, write it. */
- name = cmdp->argv[exp->argsoff - 1]->bp;
- set_alt_name(sp, name);
- break;
- default:
- /* If expanded to more than one argument, object. */
- msgq(sp, M_ERR, "%s expanded into too many file names",
- cmdp->argv[0]->bp);
- msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
- return (1);
- }
-
- if (F_ISSET(cmdp, E_ADDR2_ALL))
- LF_SET(FS_ALL);
- return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
-}
-
-/*
- * ex_writefp --
- * Write a range of lines to a FILE *.
- */
-int
-ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
- SCR *sp;
- EXF *ep;
- char *name;
- FILE *fp;
- MARK *fm, *tm;
- u_long *nlno, *nch;
-{
- register u_long ccnt, fline, tline;
- size_t len;
- char *p;
-
- fline = fm->lno;
- tline = tm->lno;
-
- if (nlno != NULL) {
- *nch = 0;
- *nlno = 0;
- }
- ccnt = 0;
-
- /*
- * The vi filter code has multiple processes running simultaneously,
- * and one of them calls ex_writefp(). The "unsafe" function calls
- * in this code are to file_gline() and msgq(). File_gline() is safe,
- * see the comment in filter.c:filtercmd() for details. We don't call
- * msgq if the multiple process bit in the EXF is set.
- *
- * !!!
- * Historic vi permitted files of 0 length to be written. However,
- * since the way vi got around dealing with "empty" files was to
- * always have a line in the file no matter what, it wrote them as
- * files of a single, empty line. We write empty files.
- *
- * "Alex, I'll take vi trivia for $1000."
- */
- if (tline != 0)
- for (; fline <= tline; ++fline) {
- if ((p = file_gline(sp, ep, fline, &len)) == NULL)
- break;
- if (fwrite(p, 1, len, fp) != len) {
- msgq(sp, M_SYSERR, name);
- (void)fclose(fp);
- return (1);
- }
- ccnt += len;
- if (putc('\n', fp) != '\n')
- break;
- ++ccnt;
- }
- if (fclose(fp)) {
- if (!F_ISSET(ep, F_MULTILOCK))
- msgq(sp, M_SYSERR, name);
- return (1);
- }
- if (nlno != NULL) {
- *nch = ccnt;
- *nlno = tm->lno == 0 ? 0 : tm->lno - fm->lno + 1;
- }
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_yank.c b/usr.bin/vi/nex/ex_yank.c
deleted file mode 100644
index 0897034bf022..000000000000
--- a/usr.bin/vi/nex/ex_yank.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_yank.c 8.3 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_yank -- :[line [,line]] ya[nk] [buffer] [count]
- *
- * Yank the lines into a buffer.
- */
-int
-ex_yank(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (cut(sp, ep, NULL,
- F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
- &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE));
-}
diff --git a/usr.bin/vi/nex/ex_z.c b/usr.bin/vi/nex/ex_z.c
deleted file mode 100644
index 2842a22855a5..000000000000
--- a/usr.bin/vi/nex/ex_z.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_z.c 8.4 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_z -- :[line] z [^-.+=] [count] [flags]
- *
- * Adjust window.
- */
-int
-ex_z(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- recno_t cnt, equals, lno;
- int eofcheck;
-
- /*
- * !!!
- * If no count specified, use either two times the size of the
- * scrolling region, or the size of the window option. POSIX
- * 1003.2 claims that the latter is correct, but historic ex/vi
- * documentation and practice appear to use the scrolling region.
- * I'm using the window size as it means that the entire screen
- * is used instead of losing a line to roundoff. Note, we drop
- * a line from the cnt if using the window size to leave room for
- * the next ex prompt.
- */
- if (F_ISSET(cmdp, E_COUNT))
- cnt = cmdp->count;
- else
-#ifdef HISTORIC_PRACTICE
- cnt = O_VAL(sp, O_SCROLL) * 2;
-#else
- cnt = O_VAL(sp, O_WINDOW) - 1;
-#endif
-
- equals = 0;
- eofcheck = 0;
- lno = cmdp->addr1.lno;
-
- switch (F_ISSET(cmdp,
- E_F_CARAT | E_F_DASH | E_F_DOT | E_F_EQUAL | E_F_PLUS)) {
- case E_F_CARAT: /* Display cnt * 2 before the line. */
- eofcheck = 1;
- if (lno > cnt * 2)
- cmdp->addr1.lno = (lno - cnt * 2) + 1;
- else
- cmdp->addr1.lno = 1;
- cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1;
- break;
- case E_F_DASH: /* Line goes at the bottom of the screen. */
- cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1;
- cmdp->addr2.lno = lno;
- break;
- case E_F_DOT: /* Line goes in the middle of the screen. */
- /*
- * !!!
- * Historically, the "middleness" of the line overrode the
- * count, so that "3z.19" or "3z.20" would display the first
- * 12 lines of the file, i.e. (N - 1) / 2 lines before and
- * after the specified line.
- */
- eofcheck = 1;
- cnt = (cnt - 1) / 2;
- cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
- cmdp->addr2.lno = lno + cnt;
- break;
- case E_F_EQUAL: /* Center with hyphens. */
- /*
- * !!!
- * Strangeness. The '=' flag is like the '.' flag (see the
- * above comment, it applies here as well) but with a special
- * little hack. Print out lines of hyphens before and after
- * the specified line. Additionally, the cursor remains set
- * on that line.
- */
- eofcheck = 1;
- cnt = (cnt - 1) / 2;
- cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
- cmdp->addr2.lno = lno - 1;
- if (ex_pr(sp, ep, cmdp))
- return (1);
- (void)ex_printf(EXCOOKIE,
- "%s", "----------------------------------------\n");
- cmdp->addr2.lno = cmdp->addr1.lno = equals = lno;
- if (ex_pr(sp, ep, cmdp))
- return (1);
- (void)ex_printf(EXCOOKIE,
- "%s", "----------------------------------------\n");
- cmdp->addr1.lno = lno + 1;
- cmdp->addr2.lno = (lno + cnt) - 1;
- break;
- default:
- /* If no line specified, move to the next one. */
- if (F_ISSET(cmdp, E_ADDRDEF))
- ++lno;
- /* FALLTHROUGH */
- case E_F_PLUS: /* Line goes at the top of the screen. */
- eofcheck = 1;
- cmdp->addr1.lno = lno;
- cmdp->addr2.lno = (lno + cnt) - 1;
- break;
- }
-
- if (eofcheck) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (cmdp->addr2.lno > lno)
- cmdp->addr2.lno = lno;
- }
-
- if (ex_pr(sp, ep, cmdp))
- return (1);
- if (equals)
- sp->lno = equals;
- return (0);
-}
diff --git a/usr.bin/vi/nex/excmd.c b/usr.bin/vi/nex/excmd.c
deleted file mode 100644
index 27ebc39eebe8..000000000000
--- a/usr.bin/vi/nex/excmd.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)excmd.c 8.36 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * This array maps ex command names to command functions.
- *
- * The order in which command names are listed below is important --
- * ambiguous abbreviations are resolved to be the first possible match,
- * e.g. "r" means "read", not "rewind", because "read" is listed before
- * "rewind".
- *
- * The syntax of the ex commands is unbelievably irregular, and a special
- * case from beginning to end. Each command has an associated "syntax
- * script" which describes the "arguments" that are possible. The script
- * syntax is as follows:
- *
- * ! -- ! flag
- * 1 -- flags: [+-]*[pl#][+-]*
- * 2 -- flags: [-.+^]
- * 3 -- flags: [-.+^=]
- * b -- buffer
- * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset)
- * f[N#][or] -- file (a number or N, optional or required)
- * l -- line
- * S -- string with file name expansion
- * s -- string
- * W -- word string
- * w[N#][or] -- word (a number or N, optional or required)
- */
-EXCMDLIST const cmds[] = {
-/* C_BANG */
- {"!", ex_bang, E_ADDR2_NONE|E_NORC,
- "S",
- "[line [,line]] ! command",
- "filter lines through commands or run commands"},
-/* C_HASH */
- {"#", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
- "ca1",
- "[line [,line]] # [count] [l]",
- "display numbered lines"},
-/* C_SUBAGAIN */
- {"&", ex_subagain, E_ADDR2|E_NORC,
- "s",
- "[line [,line]] & [cgr] [count] [#lp]",
- "repeat the last subsitution"},
-/* C_STAR */
- {"*", ex_at, 0,
- "b",
- "* [buffer]",
- "execute a buffer"},
-/* C_SHIFTL */
- {"<", ex_shiftl, E_ADDR2|E_AUTOPRINT|E_NORC,
- "ca1",
- "[line [,line]] <[<...] [count] [flags]",
- "shift lines left"},
-/* C_EQUAL */
- {"=", ex_equal, E_ADDR1|E_NORC,
- "1",
- "[line] = [flags]",
- "display line number"},
-/* C_SHIFTR */
- {">", ex_shiftr, E_ADDR2|E_AUTOPRINT|E_NORC,
- "ca1",
- "[line [,line]] >[>...] [count] [flags]",
- "shift lines right"},
-/* C_AT */
- {"@", ex_at, 0,
- "b",
- "@ [buffer]",
- "execute a buffer"},
-/* C_APPEND */
- {"append", ex_append, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
- "!",
- "[line] a[ppend][!]",
- "append input to a line"},
-/* C_ABBR */
- {"abbreviate", ex_abbr, E_NOGLOBAL,
- "W",
- "ab[brev] word replace",
- "specify an input abbreviation"},
-/* C_ARGS */
- {"args", ex_args, E_NOGLOBAL|E_NORC,
- "",
- "ar[gs]",
- "display file argument list"},
-/* C_BG */
- {"bg", ex_bg, E_NOGLOBAL|E_NORC,
- "",
- "bg",
- "background the current screen"},
-/* C_CHANGE */
- {"change", ex_change, E_ADDR2|E_NORC|E_ZERODEF,
- "!ca",
- "[line [,line]] c[hange][!] [count]",
- "change lines to input"},
-/* C_CD */
- {"cd", ex_cd, E_NOGLOBAL,
- "!f1o",
- "cd[!] [directory]",
- "change the current directory"},
-/* C_CHDIR */
- {"chdir", ex_cd, E_NOGLOBAL,
- "!f1o",
- "chd[ir][!] [directory]",
- "change the current directory"},
-/* C_COPY */
- {"copy", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
- "l1",
- "[line [,line]] co[py] line [flags]",
- "copy lines elsewhere in the file"},
-/* C_DELETE */
- {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC,
- "bca1",
- "[line [,line]] d[elete] [buffer] [count] [flags]",
- "delete lines from the file"},
-/* C_DISPLAY */
- {"display", ex_display, E_NOGLOBAL|E_NORC,
- "w1r",
- "display b[uffers] | s[creens] | t[ags]",
- "display buffers, screens or tags"},
-/* C_DIGRAPH */
- {"digraph", ex_digraph, E_NOGLOBAL|E_NOPERM|E_NORC,
- "",
- "digraph",
- "specify digraphs (not implemented)"},
-/* C_EDIT */
- {"edit", ex_edit, E_NOGLOBAL|E_NORC,
- "!f1o",
- "e[dit][!] [+cmd] [file]",
- "begin editing another file"},
-/* C_EX */
- {"ex", ex_edit, E_NOGLOBAL|E_NORC,
- "!f1o",
- "ex[!] [+cmd] [file]",
- "begin editing another file"},
-/* C_EXUSAGE */
- {"exusage", ex_usage, E_NOGLOBAL|E_NORC,
- "w1o",
- "[exu]sage [command]",
- "display ex command usage statement"},
-/* C_FILE */
- {"file", ex_file, E_NOGLOBAL|E_NORC,
- "f1o",
- "f[ile] [name]",
- "display (and optionally set) file name"},
-/* C_FG */
- {"fg", ex_fg, E_NOGLOBAL|E_NORC,
- "f1o",
- "fg [file]",
- "switch the current screen and a backgrounded screen"},
-/* C_GLOBAL */
- {"global", ex_global, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
- "!s",
- "[line [,line]] g[lobal][!] [;/]pattern[;/] [commands]",
- "execute a global command on lines matching a pattern"},
-/* C_HELP */
- {"help", ex_help, E_NOGLOBAL|E_NORC,
- "",
- "he[lp]",
- "display help statement"},
-/* C_INSERT */
- {"insert", ex_insert, E_ADDR1|E_NORC,
- "!",
- "[line] i[nsert][!]",
- "insert input before a line"},
-/* C_JOIN */
- {"join", ex_join, E_ADDR2|E_AUTOPRINT|E_NORC,
- "!ca1",
- "[line [,line]] j[oin][!] [count] [flags]",
- "join lines into a single line"},
-/* C_K */
- {"k", ex_mark, E_ADDR1|E_NORC,
- "w1r",
- "[line] k key",
- "mark a line position"},
-/* C_LIST */
- {"list", ex_list, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
- "ca1",
- "[line [,line]] l[ist] [count] [#]",
- "display lines in an unambiguous form"},
-/* C_MOVE */
- {"move", ex_move, E_ADDR2|E_AUTOPRINT|E_NORC,
- "l",
- "[line [,line]] m[ove] line",
- "move lines elsewhere in the file"},
-/* C_MARK */
- {"mark", ex_mark, E_ADDR1|E_NORC,
- "w1r",
- "[line] ma[rk] key",
- "mark a line position"},
-/* C_MAP */
- {"map", ex_map, 0,
- "!W",
- "map[!] [keys replace]",
- "map input or commands to one or more keys"},
-/* C_MKEXRC */
- {"mkexrc", ex_mkexrc, E_NOGLOBAL|E_NORC,
- "!f1r",
- "mkexrc[!] file",
- "write a .exrc file"},
-/* C_NEXT */
- {"next", ex_next, E_NOGLOBAL|E_NORC,
- "!fN",
- "n[ext][!] [file ...]",
- "edit (and optionally specify) the next file"},
-/* C_NUMBER */
- {"number", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
- "ca1",
- "[line [,line]] nu[mber] [count] [l]",
- "change display to number lines"},
-/* C_OPEN */
- {"open", ex_open, E_ADDR1,
- "s",
- "[line] o[pen] [/pattern/] [flags]",
- "enter \"open\" mode (not implemented)"},
-/* C_PRINT */
- {"print", ex_pr, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
- "ca1",
- "[line [,line]] p[rint] [count] [#l]",
- "display lines"},
-/* C_PRESERVE */
- {"preserve", ex_preserve, E_NOGLOBAL|E_NORC,
- "",
- "pre[serve]",
- "preserve an edit session for recovery"},
-/* C_PREVIOUS */
- {"previous", ex_prev, E_NOGLOBAL|E_NORC,
- "!",
- "prev[ious][!]",
- "edit the previous file in the file argument list"},
-/* C_PUT */
- {"put", ex_put, E_ADDR1|E_AUTOPRINT|E_NORC|E_ZERO,
- "b",
- "[line] pu[t] [buffer]",
- "append a cut buffer to the line"},
-/* C_QUIT */
- {"quit", ex_quit, E_NOGLOBAL,
- "!",
- "q[uit][!]",
- "exit ex/vi"},
-/* C_READ */
- {"read", ex_read, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
- "!s",
- "[line] r[ead] [!cmd | [file]]",
- "append input from a command or file to the line"},
-/* C_RESIZE */
- {"resize", ex_resize, E_NOGLOBAL|E_NORC,
- "c+",
- "resize [change]",
- "grow or shrink the current screen"},
-/* C_REWIND */
- {"rewind", ex_rew, E_NOGLOBAL|E_NORC,
- "!",
- "rew[ind][!]",
- "re-edit all the files in the file argument list"},
-/* C_SUBSTITUTE */
- {"substitute", ex_substitute, E_ADDR2|E_NORC,
- "s",
-"[line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]",
- "substitute on lines matching a pattern"},
-/* C_SCRIPT */
- {"script", ex_script, E_NOGLOBAL|E_NORC,
- "!f1o",
- "sc[ript][!] [file]",
- "run a shell in a screen"},
-/* C_SET */
- {"set", ex_set, E_NOGLOBAL,
- "wN",
- "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
- "set options (use \":set all\" to see all options)"},
-/* C_SHELL */
- {"shell", ex_shell, E_NOGLOBAL|E_NORC,
- "",
- "sh[ell]",
- "suspend editing and run a shell"},
-/* C_SOURCE */
- {"source", ex_source, E_NOGLOBAL,
- "f1r",
- "so[urce] file",
- "read a file of ex commands"},
-/* C_SPLIT */
- {"split", ex_split, E_NOGLOBAL|E_NORC,
- "fNo",
- "sp[lit] [file ...]",
- "split the current screen into two screens"},
-/* C_STOP */
- {"stop", ex_stop, E_NOGLOBAL|E_NORC,
- "!",
- "st[op][!]",
- "suspend the edit session"},
-/* C_SUSPEND */
- {"suspend", ex_stop, E_NOGLOBAL|E_NORC,
- "!",
- "su[spend][!]",
- "suspend the edit session"},
-/* C_T */
- {"t", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
- "l1",
- "[line [,line]] t line [flags]",
- "move lines elsewhere in the file"},
-/* C_TAG */
- {"tag", ex_tagpush, E_NOGLOBAL,
- "!w1o",
- "ta[g][!] [string]",
- "edit the file containing the tag"},
-/* C_TAGPOP */
- {"tagpop", ex_tagpop, E_NOGLOBAL|E_NORC,
- "!w1o",
- "tagp[op][!] [number | file]",
- "return to a previous tag"},
-/* C_TAGTOP */
- {"tagtop", ex_tagtop, E_NOGLOBAL|E_NORC,
- "!",
- "tagt[op][!]",
- "return to the first tag"},
-/* C_UNDOL */
- {"Undo", ex_undol, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
- "",
- "U[ndo]",
- "undo all the changes to this line"},
-/* C_UNDO */
- {"undo", ex_undo, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
- "",
- "u[ndo]",
- "undo the most recent change"},
-/* C_UNABBREVIATE */
- {"unabbreviate",ex_unabbr, E_NOGLOBAL,
- "w1r",
- "una[bbrev] word",
- "delete an abbreviation"},
-/* C_UNMAP */
- {"unmap", ex_unmap, E_NOGLOBAL,
- "!w1r",
- "unm[ap][!] word",
- "delete an input or command map"},
-/* C_VGLOBAL */
- {"vglobal", ex_vglobal, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
- "s",
- "[line [,line]] v[global] [;/]pattern[;/] [commands]",
- "execute a global command on lines NOT matching a pattern"},
-/* C_VERSION */
- {"version", ex_version, E_NOGLOBAL|E_NORC,
- "",
- "version",
- "display the program version information"},
-/* C_VISUAL_EX */
- {"visual", ex_visual, E_ADDR1|E_NOGLOBAL|E_NORC|E_ZERODEF,
- "2c11",
- "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
- "enter visual (vi) mode from ex mode"},
-/* C_VISUAL_VI */
- {"visual", ex_edit, E_NOGLOBAL|E_NORC,
- "!f1o",
- "vi[sual][!] [+cmd] [file]",
- "edit another file (from vi mode only)"},
-/* C_VIUSAGE */
- {"viusage", ex_viusage, E_NOGLOBAL|E_NORC,
- "w1o",
- "[viu]sage [key]",
- "display vi key usage statement"},
-/* C_WRITE */
- {"write", ex_write, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
- "!s",
- "[line [,line]] w[rite][!] [!cmd | [>>] [file]]",
- "write the file"},
-/* C_WQ */
- {"wq", ex_wq, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
- "!s",
- "[line [,line]] wq[!] [>>] [file]",
- "write the file and exit"},
-/* C_XIT */
- {"xit", ex_xit, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
- "!f1o",
- "[line [,line]] x[it][!] [file]",
- "exit"},
-/* C_YANK */
- {"yank", ex_yank, E_ADDR2|E_NORC,
- "bca",
- "[line [,line]] ya[nk] [buffer] [count]",
- "copy lines to a cut buffer"},
-/* C_Z */
- {"z", ex_z, E_ADDR1|E_NOGLOBAL|E_NORC,
- "3c01",
- "[line] z [-|.|+|^|=] [count] [flags]",
- "display different screens of the file"},
-/* C_SUBTILDE */
- {"~", ex_subtilde, E_ADDR2|E_NORC,
- "s",
- "[line [,line]] ~ [cgr] [count] [#lp]",
- "replace previous RE with previous replacement string,"},
- {NULL},
-};
diff --git a/usr.bin/vi/nex/excmd.h.stub b/usr.bin/vi/nex/excmd.h.stub
deleted file mode 100644
index ce2715c8b086..000000000000
--- a/usr.bin/vi/nex/excmd.h.stub
+++ /dev/null
@@ -1,340 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- *
- * @(#)excmd.h.stub 8.44 (Berkeley) 12/29/93
- */
-
-/* Ex command structure. */
-typedef struct _excmdlist {
- char *name; /* Command name. */
- /* Underlying function. */
- int (*fn) __P((SCR *, EXF *, EXCMDARG *));
-
-#define E_ADDR1 0x0000001 /* One address. */
-#define E_ADDR2 0x0000002 /* Two address. */
-#define E_ADDR2_ALL 0x0000004 /* Zero/two addresses; zero == all. */
-#define E_ADDR2_NONE 0x0000008 /* Zero/two addresses; zero == none. */
-#define E_ADDRDEF 0x0000010 /* Default addresses used. */
-#define E_AUTOPRINT 0x0000020 /* Command always sets autoprint. */
-#define E_BUFFER 0x0000040 /* Buffer name supplied. */
-#define E_COUNT 0x0000080 /* Count supplied. */
-#define E_FORCE 0x0000100 /* ! */
-
-#define E_F_CARAT 0x0000200 /* ^ flag. */
-#define E_F_DASH 0x0000400 /* - flag. */
-#define E_F_DOT 0x0000800 /* . flag. */
-#define E_F_EQUAL 0x0001000 /* = flag. */
-#define E_F_HASH 0x0002000 /* # flag. */
-#define E_F_LIST 0x0004000 /* l flag. */
-#define E_F_PLUS 0x0008000 /* + flag. */
-#define E_F_PRINT 0x0010000 /* p flag. */
-
-#define E_F_PRCLEAR 0x0020000 /* Clear the print (#, l, p) flags. */
-#define E_MODIFY 0x0040000 /* File name expansion modified arg. */
-#define E_NOGLOBAL 0x0080000 /* Not in a global. */
-#define E_NOPERM 0x0100000 /* Permission denied for now. */
-#define E_NORC 0x0200000 /* Not from a .exrc or EXINIT. */
-#define E_SETLAST 0x0400000 /* Reset last command. */
-#define E_ZERO 0x0800000 /* 0 is a legal addr1. */
-#define E_ZERODEF 0x1000000 /* 0 is default addr1 of empty files. */
- u_long flags;
- char *syntax; /* Syntax script. */
- char *usage; /* Usage line. */
- char *help; /* Help line. */
-} EXCMDLIST;
-#define MAXCMDNAMELEN 12 /* Longest command name. */
-extern EXCMDLIST const cmds[]; /* List of ex commands. */
-
-/* Structure passed around to functions implementing ex commands. */
-struct _excmdarg {
- EXCMDLIST const *cmd; /* Command entry in command table. */
- CHAR_T buffer; /* Named buffer. */
- recno_t lineno; /* Line number. */
- long count; /* Signed, specified count. */
- int addrcnt; /* Number of addresses (0, 1 or 2). */
- MARK addr1; /* 1st address. */
- MARK addr2; /* 2nd address. */
- ARGS **argv; /* Array of arguments. */
- int argc; /* Count of arguments. */
- u_int flags; /* Selected flags from EXCMDLIST. */
-};
-
-/* Global ranges. */
-typedef struct _range RANGE;
-struct _range {
- CIRCLEQ_ENTRY(_range) q; /* Linked list of ranges. */
- recno_t start, stop; /* Start/stop of the range. */
-};
-
-/* Ex private, per-screen memory. */
-typedef struct _ex_private {
- ARGS **args; /* Arguments. */
- int argscnt; /* Argument count. */
- int argsoff; /* Offset into arguments. */
-
- CHAR_T at_lbuf; /* Last executed at buffer's name. */
- int at_lbuf_set; /* If at_lbuf is set. */
-
- char *ibp; /* Line input buffer. */
- size_t ibp_len; /* Line input buffer length. */
-
- EXCMDLIST const *lastcmd; /* Last command. */
-
- CHAR_T *lastbcomm; /* Last bang command. */
-
- TAILQ_HEAD(_tagh, _tag) tagq; /* Tag stack. */
- TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag stack. */
- char *tlast; /* Saved last tag. */
-
- /* Linked list of ranges. */
- CIRCLEQ_HEAD(_rangeh, _range) rangeq;
- recno_t range_lno; /* Range set line number. */
-
-#define EX_AUTOPRINT 0x01 /* Autoprint flag. */
- u_int flags;
-} EX_PRIVATE;
-#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private))
-
-/* Macro to set up a command structure. */
-#define SETCMDARG(s, cmd_id, naddr, lno1, lno2, force, arg) { \
- ARGS *__ap[2], __a; \
- memset(&s, 0, sizeof(EXCMDARG)); \
- s.cmd = &cmds[cmd_id]; \
- s.addrcnt = (naddr); \
- s.addr1.lno = (lno1); \
- s.addr2.lno = (lno2); \
- s.addr1.cno = s.addr2.cno = 1; \
- if (force) \
- s.flags |= E_FORCE; \
- if ((__a.bp = arg) == NULL) { \
- s.argc = 0; \
- __a.len = 0; \
- } else { \
- s.argc = 1; \
- __a.len = strlen(arg); \
- } \
- __ap[0] = &__a; \
- __ap[1] = NULL; \
- s.argv = __ap; \
-}
-
-/*
- * :next, :prev, :rewind, :tag, :tagpush, :tagpop modifications check.
- * If force is set, the autowrite is skipped.
- */
-#define MODIFY_CHECK(sp, ep, force) { \
- if (F_ISSET((ep), F_MODIFIED)) \
- if (O_ISSET((sp), O_AUTOWRITE)) { \
- if (!(force) && \
- file_write((sp), (ep), NULL, NULL, NULL, \
- FS_ALL | FS_POSSIBLE)) \
- return (1); \
- } else if (ep->refcnt <= 1 && !(force)) { \
- msgq(sp, M_ERR, \
- "Modified since last write; write or use ! to override."); \
- return (1); \
- } \
-}
-
-/*
- * Macros to set and restore the terminal values, and note if the screen
- * was modified. Specific to their uses in ex/filter.c and ex/ex_shell.c.
- *
- * The old terminal values almost certainly turn on VINTR, VQUIT and VSUSP.
- * We don't want to interrupt the parent(s), so we ignore VINTR. VQUIT is
- * ignored by main() because nvi never wants to catch it. A VSUSP handler
- * have been installed by the screen code.
- */
-#define EX_LEAVE(sp, isig, act, oact, sb, osb, term) \
- if (F_ISSET(sp->gp, G_ISFROMTTY)) { \
- (act).sa_handler = SIG_IGN; \
- sigemptyset(&(act).sa_mask); \
- (act).sa_flags = 0; \
- if ((isig) = !sigaction(SIGINT, &(act), &(oact))) { \
- if (tcgetattr(STDIN_FILENO, &(term))) { \
- msgq(sp, M_SYSERR, "tcgetattr"); \
- rval = 1; \
- goto err; \
- } \
- if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, \
- &sp->gp->original_termios)) { \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- rval = 1; \
- goto err; \
- } \
- } \
- /* \
- * The process may write to the terminal. Save the \
- * access time (read) and modification time (write) \
- * of the tty; if they have changed when we restore \
- * the modes, will have to refresh the screen. \
- */ \
- sb.st_mtime = 1; \
- osb.st_mtime = 0; \
- (void)fstat(STDIN_FILENO, &osb); \
- }
-
-#define EX_RETURN(sp, isig, act, oact, sb, osb, term) \
- if (F_ISSET(sp->gp, G_ISFROMTTY) && (isig)) { \
- if (sigaction(SIGINT, &(oact), NULL)) { \
- msgq(sp, M_SYSERR, "signal"); \
- rval = 1; \
- } \
- if (tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &(term))) { \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- rval = 1; \
- } \
- /* If the terminal was used, refresh the screen. */ \
- (void)fstat(STDIN_FILENO, &(sb)); \
- if ((sb).st_mtime != (osb).st_mtime || \
- (sb).st_atime != (osb).st_atime) \
- F_SET(sp, S_REFRESH); \
- }
-
-/*
- * Filter actions:
- *
- * FILTER Filter text through the utility.
- * FILTER_READ Read from the utility into the file.
- * FILTER_WRITE Write to the utility, display its output.
- */
-enum filtertype { FILTER, FILTER_READ, FILTER_WRITE };
-int filtercmd __P((SCR *, EXF *,
- MARK *, MARK *, MARK *, char *, enum filtertype));
-
-/* Argument expansion routines. */
-int argv_init __P((SCR *, EXF *, EXCMDARG *));
-int argv_exp0 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
-int argv_exp1 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
-int argv_exp2 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
-int argv_exp3 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
-int argv_free __P((SCR *));
-
-/* Ex function prototypes. */
-int ex __P((SCR *, EXF *));
-int ex_cfile __P((SCR *, EXF *, char *));
-int ex_cmd __P((SCR *, EXF *, char *, size_t));
-int ex_end __P((SCR *));
-int ex_exec_proc __P((SCR *, char *, char *, char *));
-int ex_gb __P((SCR *, EXF *, TEXTH *, int, u_int));
-int ex_getline __P((SCR *, FILE *, size_t *));
-int ex_icmd __P((SCR *, EXF *, char *, size_t));
-int ex_init __P((SCR *, EXF *));
-int ex_is_abbrev __P((char *, size_t));
-int ex_optchange __P((SCR *, int));
-int ex_print __P((SCR *, EXF *, MARK *, MARK *, int));
-int ex_readfp __P((SCR *, EXF *, char *, FILE *, MARK *, recno_t *, int));
-void ex_refresh __P((SCR *, EXF *));
-int ex_screen_copy __P((SCR *, SCR *));
-int ex_screen_end __P((SCR *));
-int ex_sdisplay __P((SCR *, EXF *));
-int ex_suspend __P((SCR *));
-int ex_tdisplay __P((SCR *, EXF *));
-int ex_writefp __P((SCR *, EXF *,
- char *, FILE *, MARK *, MARK *, u_long *, u_long *));
-void global_insdel __P((SCR *, EXF *, enum operation, recno_t));
-int proc_wait __P((SCR *, long, const char *, int));
-int sscr_end __P((SCR *));
-int sscr_exec __P((SCR *, EXF *, recno_t));
-int sscr_input __P((SCR *));
-
-#define EXPROTO(type, name) \
- type name __P((SCR *, EXF *, EXCMDARG *))
-
-EXPROTO(int, ex_abbr);
-EXPROTO(int, ex_append);
-EXPROTO(int, ex_args);
-EXPROTO(int, ex_at);
-EXPROTO(int, ex_bang);
-EXPROTO(int, ex_bg);
-EXPROTO(int, ex_cd);
-EXPROTO(int, ex_change);
-EXPROTO(int, ex_color);
-EXPROTO(int, ex_copy);
-EXPROTO(int, ex_debug);
-EXPROTO(int, ex_delete);
-EXPROTO(int, ex_digraph);
-EXPROTO(int, ex_display);
-EXPROTO(int, ex_edit);
-EXPROTO(int, ex_equal);
-EXPROTO(int, ex_fg);
-EXPROTO(int, ex_file);
-EXPROTO(int, ex_global);
-EXPROTO(int, ex_help);
-EXPROTO(int, ex_insert);
-EXPROTO(int, ex_join);
-EXPROTO(int, ex_list);
-EXPROTO(int, ex_map);
-EXPROTO(int, ex_mark);
-EXPROTO(int, ex_mkexrc);
-EXPROTO(int, ex_move);
-EXPROTO(int, ex_next);
-EXPROTO(int, ex_number);
-EXPROTO(int, ex_open);
-EXPROTO(int, ex_pr);
-EXPROTO(int, ex_preserve);
-EXPROTO(int, ex_prev);
-EXPROTO(int, ex_put);
-EXPROTO(int, ex_quit);
-EXPROTO(int, ex_read);
-EXPROTO(int, ex_resize);
-EXPROTO(int, ex_rew);
-EXPROTO(int, ex_script);
-EXPROTO(int, ex_set);
-EXPROTO(int, ex_shell);
-EXPROTO(int, ex_shiftl);
-EXPROTO(int, ex_shiftr);
-EXPROTO(int, ex_source);
-EXPROTO(int, ex_split);
-EXPROTO(int, ex_stop);
-EXPROTO(int, ex_subagain);
-EXPROTO(int, ex_substitute);
-EXPROTO(int, ex_subtilde);
-EXPROTO(int, ex_tagpop);
-EXPROTO(int, ex_tagpush);
-EXPROTO(int, ex_tagtop);
-EXPROTO(int, ex_unabbr);
-EXPROTO(int, ex_undo);
-EXPROTO(int, ex_undol);
-EXPROTO(int, ex_unmap);
-EXPROTO(int, ex_usage);
-EXPROTO(int, ex_validate);
-EXPROTO(int, ex_version);
-EXPROTO(int, ex_vglobal);
-EXPROTO(int, ex_visual);
-EXPROTO(int, ex_viusage);
-EXPROTO(int, ex_wq);
-EXPROTO(int, ex_write);
-EXPROTO(int, ex_xit);
-EXPROTO(int, ex_yank);
-EXPROTO(int, ex_z);
diff --git a/usr.bin/vi/nex/filter.c b/usr.bin/vi/nex/filter.c
deleted file mode 100644
index d50e1e665d8d..000000000000
--- a/usr.bin/vi/nex/filter.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)filter.c 8.26 (Berkeley) 1/2/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "pathnames.h"
-
-static int filter_ldisplay __P((SCR *, FILE *));
-
-/*
- * filtercmd --
- * Run a range of lines through a filter utility and optionally
- * replace the original text with the stdout/stderr output of
- * the utility.
- */
-int
-filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
- SCR *sp;
- EXF *ep;
- MARK *fm, *tm, *rp;
- char *cmd;
- enum filtertype ftype;
-{
- struct sigaction act, oact;
- struct stat osb, sb;
- struct termios term;
- FILE *ifp, *ofp; /* GCC: can't be uninitialized. */
- pid_t parent_writer_pid, utility_pid;
- recno_t lno, nread;
- int input[2], isig, output[2], rval;
- char *name;
-
- /* Set return cursor position; guard against a line number of zero. */
- *rp = *fm;
- if (fm->lno == 0)
- rp->lno = 1;
-
- /*
- * There are three different processes running through this code.
- * They are the utility, the parent-writer and the parent-reader.
- * The parent-writer is the process that writes from the file to
- * the utility, the parent reader is the process that reads from
- * the utility.
- *
- * Input and output are named from the utility's point of view.
- * The utility reads from input[0] and the parent(s) write to
- * input[1]. The parent(s) read from output[0] and the utility
- * writes to output[1].
- *
- * In the FILTER_READ case, the utility isn't expected to want
- * input. Redirect its input from /dev/null. Otherwise open
- * up utility input pipe.
- */
- ifp = ofp = NULL;
- input[0] = input[1] = output[0] = output[1] = -1;
- if (ftype == FILTER_READ) {
- if ((input[0] = open(_PATH_DEVNULL, O_RDONLY, 0)) < 0) {
- msgq(sp, M_ERR,
- "filter: %s: %s", _PATH_DEVNULL, strerror(errno));
- return (1);
- }
- } else {
- if (pipe(input) < 0) {
- msgq(sp, M_SYSERR, "pipe");
- goto err;
- }
- if ((ifp = fdopen(input[1], "w")) == NULL) {
- msgq(sp, M_SYSERR, "fdopen");
- goto err;
- }
- }
-
- /* Open up utility output pipe. */
- if (pipe(output) < 0) {
- msgq(sp, M_SYSERR, "pipe");
- goto err;
- }
- if ((ofp = fdopen(output[0], "r")) == NULL) {
- msgq(sp, M_SYSERR, "fdopen");
- goto err;
- }
-
- /*
- * Save ex/vi terminal settings, and restore the original ones.
- * Restoration so that users can do things like ":r! cat /dev/tty".
- */
- EX_LEAVE(sp, isig, act, oact, sb, osb, term);
-
- /* Fork off the utility process. */
- switch (utility_pid = vfork()) {
- case -1: /* Error. */
- msgq(sp, M_SYSERR, "vfork");
-err: if (input[0] != -1)
- (void)close(input[0]);
- if (ifp != NULL)
- (void)fclose(ifp);
- else if (input[1] != -1)
- (void)close(input[1]);
- if (ofp != NULL)
- (void)fclose(ofp);
- else if (output[0] != -1)
- (void)close(output[0]);
- if (output[1] != -1)
- (void)close(output[1]);
- rval = 1;
- goto ret;
- case 0: /* Utility. */
- /*
- * The utility has default signal behavior. Don't bother
- * using sigaction(2) 'cause we want the default behavior.
- */
- (void)signal(SIGINT, SIG_DFL);
- (void)signal(SIGQUIT, SIG_DFL);
-
- /*
- * Redirect stdin from the read end of the input pipe,
- * and redirect stdout/stderr to the write end of the
- * output pipe.
- */
- (void)dup2(input[0], STDIN_FILENO);
- (void)dup2(output[1], STDOUT_FILENO);
- (void)dup2(output[1], STDERR_FILENO);
-
- /* Close the utility's file descriptors. */
- (void)close(input[0]);
- (void)close(input[1]);
- (void)close(output[0]);
- (void)close(output[1]);
-
- if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
- name = O_STR(sp, O_SHELL);
- else
- ++name;
-
- execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
- msgq(sp, M_ERR, "Error: execl: %s: %s",
- O_STR(sp, O_SHELL), strerror(errno));
- _exit (127);
- /* NOTREACHED */
- default: /* Parent-reader, parent-writer. */
- /* Close the pipe ends neither parent will use. */
- (void)close(input[0]);
- (void)close(output[1]);
- break;
- }
-
- /*
- * FILTER_READ:
- *
- * Reading is the simple case -- we don't need a parent writer,
- * so the parent reads the output from the read end of the output
- * pipe until it finishes, then waits for the child. Ex_readfp
- * appends to the MARK, and closes ofp.
- *
- * !!!
- * Set the return cursor to the last line read in. Historically,
- * this behaves differently from ":r file" command, which leaves
- * the cursor at the first line read in. Check to make sure that
- * it's not past EOF because we were reading into an empty file.
- */
- if (ftype == FILTER_READ) {
- rval = ex_readfp(sp, ep, "filter", ofp, fm, &nread, 0);
- sp->rptlines[L_ADDED] += nread;
- if (fm->lno == 0)
- rp->lno = nread;
- else
- rp->lno += nread;
- goto uwait;
- }
-
- /*
- * FILTER, FILTER_WRITE
- *
- * Here we need both a reader and a writer. Temporary files are
- * expensive and we'd like to avoid disk I/O. Using pipes has the
- * obvious starvation conditions. It's done as follows:
- *
- * fork
- * child
- * write lines out
- * exit
- * parent
- * FILTER:
- * read lines into the file
- * delete old lines
- * FILTER_WRITE
- * read and display lines
- * wait for child
- *
- * XXX
- * We get away without locking the underlying database because we know
- * that none of the records that we're reading will be modified until
- * after we've read them. This depends on the fact that the current
- * B+tree implementation doesn't balance pages or similar things when
- * it inserts new records. When the DB code has locking, we should
- * treat vi as if it were multiple applications sharing a database, and
- * do the required locking. If necessary a work-around would be to do
- * explicit locking in the line.c:file_gline() code, based on the flag
- * set here.
- */
- rval = 0;
- F_SET(ep, F_MULTILOCK);
- switch (parent_writer_pid = fork()) {
- case -1: /* Error. */
- rval = 1;
- msgq(sp, M_SYSERR, "fork");
- (void)close(input[1]);
- (void)close(output[0]);
- break;
- case 0: /* Parent-writer. */
- /*
- * Write the selected lines to the write end of the
- * input pipe. Ifp is closed by ex_writefp.
- */
- (void)close(output[0]);
- _exit(ex_writefp(sp, ep, "filter", ifp, fm, tm, NULL, NULL));
-
- /* NOTREACHED */
- default: /* Parent-reader. */
- (void)close(input[1]);
- if (ftype == FILTER_WRITE)
- /*
- * Read the output from the read end of the output
- * pipe and display it. Filter_ldisplay closes ofp.
- */
- rval = filter_ldisplay(sp, ofp);
- else {
- /*
- * Read the output from the read end of the output
- * pipe. Ex_readfp appends to the MARK and closes
- * ofp.
- */
- rval = ex_readfp(sp, ep, "filter", ofp, tm, &nread, 0);
- sp->rptlines[L_ADDED] += nread;
- }
-
- /* Wait for the parent-writer. */
- rval |= proc_wait(sp,
- (long)parent_writer_pid, "parent-writer", 1);
-
- /* Delete any lines written to the utility. */
- if (ftype == FILTER && rval == 0) {
- for (lno = tm->lno; lno >= fm->lno; --lno)
- if (file_dline(sp, ep, lno)) {
- rval = 1;
- break;
- }
- if (rval == 0)
- sp->rptlines[L_DELETED] +=
- (tm->lno - fm->lno) + 1;
- }
- /*
- * If the filter had no output, we may have just deleted
- * the cursor. Don't do any real error correction, we'll
- * try and recover later.
- */
- if (rp->lno > 1 && file_gline(sp, ep, rp->lno, NULL) == NULL)
- --rp->lno;
- break;
- }
- F_CLR(ep, F_MULTILOCK);
-
-uwait: rval |= proc_wait(sp, (long)utility_pid, cmd, 0);
-
- /* Restore ex/vi terminal settings. */
-ret: EX_RETURN(sp, isig, act, oact, sb, osb, term);
-
- return (rval);
-}
-
-/*
- * proc_wait --
- * Wait for one of the processes.
- *
- * !!!
- * The pid_t type varies in size from a short to a long depending on the
- * system. It has to be cast into something or the standard promotion
- * rules get you. I'm using a long based on the belief that nobody is
- * going to make it unsigned and it's unlikely to be a quad.
- */
-int
-proc_wait(sp, pid, cmd, okpipe)
- SCR *sp;
- long pid;
- const char *cmd;
- int okpipe;
-{
- extern const char *const sys_siglist[];
- size_t len;
- int pstat;
-
- /* Wait for the utility to finish. */
- (void)waitpid((pid_t)pid, &pstat, 0);
-
- /*
- * Display the utility's exit status. Ignore SIGPIPE from the
- * parent-writer, as that only means that the utility chose to
- * exit before reading all of its input.
- */
- if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
- for (; isblank(*cmd); ++cmd);
- len = strlen(cmd);
- msgq(sp, M_ERR, "%.*s%s: received signal: %s%s.",
- MIN(len, 20), cmd, len > 20 ? "..." : "",
- sys_siglist[WTERMSIG(pstat)],
- WCOREDUMP(pstat) ? "; core dumped" : "");
- return (1);
- }
- if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
- for (; isblank(*cmd); ++cmd);
- len = strlen(cmd);
- msgq(sp, M_ERR, "%.*s%s: exited with status %d",
- MIN(len, 20), cmd, len > 20 ? "..." : "",
- WEXITSTATUS(pstat));
- return (1);
- }
- return (0);
-}
-
-/*
- * filter_ldisplay --
- * Display a line output from a utility.
- *
- * XXX
- * This should probably be combined with some of the ex_print()
- * routines into a single display routine.
- */
-static int
-filter_ldisplay(sp, fp)
- SCR *sp;
- FILE *fp;
-{
- EX_PRIVATE *exp;
- size_t len;
-
- exp = EXP(sp);
- while (!ex_getline(sp, fp, &len)) {
- (void)ex_printf(EXCOOKIE, "%.*s\n", (int)len, exp->ibp);
- if (ferror(sp->stdfp)) {
- msgq(sp, M_SYSERR, NULL);
- (void)fclose(fp);
- return (1);
- }
- }
- if (fclose(fp)) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- return (0);
-}
diff --git a/usr.bin/vi/nvi/getc.c b/usr.bin/vi/nvi/getc.c
deleted file mode 100644
index d4ac2304b914..000000000000
--- a/usr.bin/vi/nvi/getc.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)getc.c 8.6 (Berkeley) 10/26/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * Character stream routines --
- * These routines return the file a character at a time. There are two
- * special cases. First, the end of a line, end of a file, start of a
- * file and empty lines are returned as special cases, and no character
- * is returned. Second, empty lines include lines that have only white
- * space in them, because the vi search functions don't care about white
- * space, and this makes it easier for them to be consistent.
- */
-
-/*
- * cs_init --
- * Initialize character stream routines.
- */
-int
-cs_init(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- recno_t lno;
-
- if ((csp->cs_bp =
- file_gline(sp, ep, csp->cs_lno, &csp->cs_len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- msgq(sp, M_BERR, "Empty file.");
- else
- GETLINE_ERR(sp, csp->cs_lno);
- return (1);
- }
- if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
- csp->cs_cno = 0;
- csp->cs_flags = CS_EMP;
- } else {
- csp->cs_flags = 0;
- csp->cs_ch = csp->cs_bp[csp->cs_cno];
- }
- return (0);
-}
-
-/*
- * cs_next --
- * Retrieve the next character.
- */
-int
-cs_next(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- recno_t slno;
-
- switch (csp->cs_flags) {
- case CS_EMP: /* EMP; get next line. */
- case CS_EOL: /* EOL; get next line. */
- slno = csp->cs_lno; /* Save current line. */
- if ((csp->cs_bp =
- file_gline(sp, ep, ++csp->cs_lno, &csp->cs_len)) == NULL) {
- csp->cs_lno = slno;
- if (file_lline(sp, ep, &slno))
- return (1);
- if (slno > csp->cs_lno) {
- GETLINE_ERR(sp, csp->cs_lno);
- return (1);
- }
- csp->cs_flags = CS_EOF;
- } else if (csp->cs_len == 0 ||
- v_isempty(csp->cs_bp, csp->cs_len)) {
- csp->cs_cno = 0;
- csp->cs_flags = CS_EMP;
- } else {
- csp->cs_flags = 0;
- csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
- }
- break;
- case 0:
- if (csp->cs_cno == csp->cs_len - 1)
- csp->cs_flags = CS_EOL;
- else
- csp->cs_ch = csp->cs_bp[++csp->cs_cno];
- break;
- case CS_EOF: /* EOF; only returned once. */
- default:
- abort();
- /* NOTREACHED */
- }
- return (0);
-}
-
-/*
- * cs_fspace --
- * If on a space, eat forward until something other than a
- * whitespace character.
- *
- * XXX
- * Semantics of checking the current character were coded for the fword()
- * function -- once the other word routines are converted, they may have
- * to change.
- */
-int
-cs_fspace(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
- return (0);
- for (;;) {
- if (cs_next(sp, ep, csp))
- return (1);
- if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
- break;
- }
- return (0);
-}
-
-/*
- * cs_fblank --
- * Eat forward to the next non-whitespace character.
- */
-int
-cs_fblank(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- for (;;) {
- if (cs_next(sp, ep, csp))
- return (1);
- if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
- csp->cs_flags == 0 && isblank(csp->cs_ch))
- continue;
- break;
- }
- return (0);
-}
-
-/*
- * cs_prev --
- * Retrieve the previous character.
- */
-int
-cs_prev(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- recno_t slno;
-
- switch (csp->cs_flags) {
- case CS_EMP: /* EMP; get previous line. */
- case CS_EOL: /* EOL; get previous line. */
- if (csp->cs_lno == 1) { /* SOF. */
- csp->cs_flags = CS_SOF;
- break;
- }
- slno = csp->cs_lno; /* Save current line. */
- if ((csp->cs_bp = /* Line should exist. */
- file_gline(sp, ep, --csp->cs_lno, &csp->cs_len)) == NULL) {
- GETLINE_ERR(sp, csp->cs_lno);
- csp->cs_lno = slno;
- return (1);
- }
- if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
- csp->cs_cno = 0;
- csp->cs_flags = CS_EMP;
- } else {
- csp->cs_flags = 0;
- csp->cs_cno = csp->cs_len - 1;
- csp->cs_ch = csp->cs_bp[csp->cs_cno];
- }
- break;
- case 0:
- if (csp->cs_cno == 0)
- csp->cs_flags = CS_EOL;
- else
- csp->cs_ch = csp->cs_bp[--csp->cs_cno];
- break;
- case CS_SOF: /* SOF; only returned once. */
- default:
- abort();
- /* NOTREACHED */
- }
- return (0);
-}
-
-/*
- * cs_bblank --
- * Eat backward to the next non-whitespace character.
- */
-int
-cs_bblank(sp, ep, csp)
- SCR *sp;
- EXF *ep;
- VCS *csp;
-{
- for (;;) {
- if (cs_prev(sp, ep, csp))
- return (1);
- if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
- csp->cs_flags == 0 && isblank(csp->cs_ch))
- continue;
- break;
- }
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_again.c b/usr.bin/vi/nvi/v_again.c
deleted file mode 100644
index 7e9ea5650d83..000000000000
--- a/usr.bin/vi/nvi/v_again.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_again.c 8.2 (Berkeley) 11/13/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * v_again -- &
- * Repeat the previous substitution.
- */
-int
-v_again(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_SUBAGAIN, 2, fm->lno, fm->lno, 1, "");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_at.c b/usr.bin/vi/nvi/v_at.c
deleted file mode 100644
index 3b21fc3186d5..000000000000
--- a/usr.bin/vi/nvi/v_at.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_at.c 8.3 (Berkeley) 8/25/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-int
-v_at(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_AT, 0, OOBLNO, OOBLNO, 0, NULL);
- cmd.buffer = vp->buffer;
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_ch.c b/usr.bin/vi/nvi/v_ch.c
deleted file mode 100644
index 40807d1db6b1..000000000000
--- a/usr.bin/vi/nvi/v_ch.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_ch.c 8.2 (Berkeley) 12/20/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-#define NOPREV { \
- msgq(sp, M_BERR, "No previous F, f, T or t search."); \
- return (1); \
-}
-
-#define NOTFOUND(ch) { \
- msgq(sp, M_BERR, "%s not found.", charname(sp, ch)); \
- return (1); \
-}
-
-/*
- * v_chrepeat -- [count];
- * Repeat the last F, f, T or t search.
- */
-int
-v_chrepeat(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- vp->character = sp->lastckey;
-
- switch (sp->csearchdir) {
- case CNOTSET:
- NOPREV;
- case FSEARCH:
- return (v_chF(sp, ep, vp, fm, tm, rp));
- case fSEARCH:
- return (v_chf(sp, ep, vp, fm, tm, rp));
- case TSEARCH:
- return (v_chT(sp, ep, vp, fm, tm, rp));
- case tSEARCH:
- return (v_cht(sp, ep, vp, fm, tm, rp));
- default:
- abort();
- }
- /* NOTREACHED */
-}
-
-/*
- * v_chrrepeat -- [count],
- * Repeat the last F, f, T or t search in the reverse direction.
- */
-int
-v_chrrepeat(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int rval;
- enum cdirection savedir;
-
- vp->character = sp->lastckey;
- savedir = sp->csearchdir;
-
- switch (sp->csearchdir) {
- case CNOTSET:
- NOPREV;
- case FSEARCH:
- rval = v_chf(sp, ep, vp, fm, tm, rp);
- break;
- case fSEARCH:
- rval = v_chF(sp, ep, vp, fm, tm, rp);
- break;
- case TSEARCH:
- rval = v_cht(sp, ep, vp, fm, tm, rp);
- break;
- case tSEARCH:
- rval = v_chT(sp, ep, vp, fm, tm, rp);
- break;
- default:
- abort();
- }
- sp->csearchdir = savedir;
- return (rval);
-}
-
-/*
- * v_cht -- [count]tc
- * Search forward in the line for the next occurrence of the character.
- * Place the cursor on it if a motion command, to its left if its not.
- */
-int
-v_cht(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int rval;
-
- rval = v_chf(sp, ep, vp, fm, tm, rp);
- if (!rval)
- --rp->cno; /* XXX: Motion interaction with v_chf. */
- sp->csearchdir = tSEARCH;
- return (rval);
-}
-
-/*
- * v_chf -- [count]fc
- * Search forward in the line for the next occurrence of the character.
- * Place the cursor to its right if a motion command, on it if its not.
- */
-int
-v_chf(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t len;
- recno_t lno;
- u_long cnt;
- int key;
- char *endp, *p, *startp;
-
- /*
- * !!!
- * If it's a dot command, it doesn't reset the key for which
- * we're searching, e.g. in "df1|f2|.|;", the ';' searches
- * for a '2'.
- */
- key = vp->character;
- if (!F_ISSET(vp, VC_ISDOT))
- sp->lastckey = key;
- sp->csearchdir = fSEARCH;
-
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- NOTFOUND(key);
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- if (len == 0)
- NOTFOUND(key);
-
- startp = p;
- endp = p + len;
- p += fm->cno;
- for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- while (++p < endp && *p != key);
- if (p == endp)
- NOTFOUND(key);
- }
- rp->lno = fm->lno;
- rp->cno = p - startp;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
- return (0);
-}
-
-/*
- * v_chT -- [count]Tc
- * Search backward in the line for the next occurrence of the character.
- * Place the cursor to its right.
- */
-int
-v_chT(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int rval;
-
- rval = v_chF(sp, ep, vp, fm, tm, rp);
- if (!rval)
- ++rp->cno;
- sp->csearchdir = TSEARCH;
- return (0);
-}
-
-/*
- * v_chF -- [count]Fc
- * Search backward in the line for the next occurrence of the character.
- * Place the cursor on it.
- */
-int
-v_chF(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t len;
- u_long cnt;
- int key;
- char *p, *endp;
-
- /*
- * !!!
- * If it's a dot command, it doesn't reset the key for which
- * we're searching, e.g. in "df1|f2|.|;", the ';' searches
- * for a '2'.
- */
- key = vp->character;
- if (!F_ISSET(vp, VC_ISDOT))
- sp->lastckey = key;
- sp->csearchdir = FSEARCH;
-
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- NOTFOUND(key);
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- if (len == 0)
- NOTFOUND(key);
-
- endp = p - 1;
- p += fm->cno;
- for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- while (--p > endp && *p != key);
- if (p == endp)
- NOTFOUND(key);
- }
- rp->lno = fm->lno;
- rp->cno = (p - endp) - 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_delete.c b/usr.bin/vi/nvi/v_delete.c
deleted file mode 100644
index 241ddf654f2e..000000000000
--- a/usr.bin/vi/nvi/v_delete.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_delete.c 8.7 (Berkeley) 1/11/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_Delete -- [buffer][count]D
- * Delete line command.
- */
-int
-v_Delete(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t len;
-
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- return (0);
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- if (len == 0)
- return (0);
-
- tm->lno = fm->lno;
- tm->cno = len;
-
- /* Yank the lines. */
- if (cut(sp, ep, NULL,
- F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, CUT_DELETE))
- return (1);
- if (delete(sp, ep, fm, tm, 0))
- return (1);
-
- rp->lno = fm->lno;
- rp->cno = fm->cno ? fm->cno - 1 : 0;
- return (0);
-}
-
-/*
- * v_delete -- [buffer][count]d[count]motion
- * Delete a range of text.
- */
-int
-v_delete(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t nlines;
- size_t len;
- int lmode;
-
- /* Yank the lines. */
- lmode = F_ISSET(vp, VC_LMODE) ? CUT_LINEMODE : 0;
- if (cut(sp, ep, NULL,
- F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, lmode | CUT_DELETE))
- return (1);
- if (delete(sp, ep, fm, tm, lmode))
- return (1);
-
- /* Check for deleting the file. */
- if (file_lline(sp, ep, &nlines))
- return (1);
- if (nlines == 0) {
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
-
- /*
- * If deleting lines, leave the cursor at the lowest line deleted,
- * else, leave the cursor where it started. Always correct for EOL.
- *
- * The historic vi would delete the line the cursor was on (even if
- * not in line mode) if the motion from the cursor was past the EOF
- * and the cursor didn't originate on the last line of the file. A
- * strange special case. We never delete the line the cursor is on.
- * We'd have to pass a flag down to the delete() routine which would
- * have to special case it.
- */
- if (lmode) {
- rp->lno = MIN(fm->lno, tm->lno);
- if (rp->lno > nlines)
- rp->lno = nlines;
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- return (0);
- }
-
- rp->lno = fm->lno;
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
- if (fm->cno >= len)
- rp->cno = len ? len - 1 : 0;
- else
- rp->cno = fm->cno;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_ex.c b/usr.bin/vi/nvi/v_ex.c
deleted file mode 100644
index 631cd342d010..000000000000
--- a/usr.bin/vi/nvi/v_ex.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_ex.c 8.1 (Berkeley) 6/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_ex --
- * Run ex.
- */
-int
-v_ex(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (sp->s_ex_run(sp, ep, rp));
-}
diff --git a/usr.bin/vi/nvi/v_exit.c b/usr.bin/vi/nvi/v_exit.c
deleted file mode 100644
index f308c480d3d7..000000000000
--- a/usr.bin/vi/nvi/v_exit.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_exit.c 8.5 (Berkeley) 12/10/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * v_exit -- ZZ
- * Save the file and exit.
- */
-int
-v_exit(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(ep, F_MODIFIED) &&
- file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
- return (1);
-
- /*
- * !!!
- * Historic practice: quit! or two quit's done in succession
- * (where ZZ counts as a quit) didn't check for other files.
- *
- * Also check for related screens; if they exist, quit, the
- * user will get the message on the last screen.
- */
- if (sp->ccnt != sp->q_ccnt + 1 &&
- ep->refcnt <= 1 && file_unedited(sp) != NULL) {
- sp->q_ccnt = sp->ccnt;
- msgq(sp, M_ERR,
- "More files to edit; use \":n\" to go to the next file");
- return (1);
- }
-
- F_SET(sp, S_EXIT);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_exmode.c b/usr.bin/vi/nvi/v_exmode.c
deleted file mode 100644
index 150ec52ccf9c..000000000000
--- a/usr.bin/vi/nvi/v_exmode.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_exmode.c 8.3 (Berkeley) 11/13/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_exmode --
- * Put the editor in EX mode.
- */
-int
-v_exmode(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- sp->saved_vi_mode = F_ISSET(sp, S_VI_CURSES | S_VI_XAW);
- F_CLR(sp, S_SCREENS);
- F_SET(sp, S_EX);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_filter.c b/usr.bin/vi/nvi/v_filter.c
deleted file mode 100644
index 52ff2ae77b8d..000000000000
--- a/usr.bin/vi/nvi/v_filter.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_filter.c 8.10 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-#include "excmd.h"
-
-/*
- * v_filter -- [count]!motion command(s)
- * Run range through shell commands, replacing text.
- */
-int
-v_filter(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
- TEXT *tp;
-
- /*
- * !!!
- * Historical vi permitted "!!" in an empty file. This is
- * handled as a special case in the ex_bang routine. Don't
- * modify this setup without understanding that one. In
- * particular, note that we're manipulating the ex argument
- * structures behind ex's back.
- */
- SETCMDARG(cmd, C_BANG, 2, fm->lno, tm->lno, 0, NULL);
- EXP(sp)->argsoff = 0; /* XXX */
- if (F_ISSET(vp, VC_ISDOT)) {
- if (argv_exp1(sp, ep, &cmd, "!", 1, 1))
- return (1);
- } else {
- /* Get the command from the user. */
- if (sp->s_get(sp, ep, &sp->tiq,
- '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
- return (1);
- /*
- * Len is 0 if backspaced over the prompt,
- * 1 if only CR entered.
- */
- tp = sp->tiq.cqh_first;
- if (tp->len <= 1)
- return (0);
-
- if (argv_exp1(sp, ep, &cmd, tp->lb + 1, tp->len - 1, 1))
- return (1);
- }
- cmd.argc = EXP(sp)->argsoff; /* XXX */
- cmd.argv = EXP(sp)->args; /* XXX */
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_increment.c b/usr.bin/vi/nvi/v_increment.c
deleted file mode 100644
index dfae29ea463e..000000000000
--- a/usr.bin/vi/nvi/v_increment.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_increment.c 8.6 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-static char * const fmt[] = {
-#define DEC 0
- "%ld",
-#define SDEC 1
- "%+ld",
-#define HEXC 2
- "%#0.*lX",
-#define HEXL 3
- "%#0.*lx",
-#define OCTAL 4
- "%#0.*lo",
-};
-
-/*
- * v_increment -- [count]#[#+-]
- * Increment/decrement a keyword number.
- */
-int
-v_increment(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- VI_PRIVATE *vip;
- u_long ulval;
- long lval;
- size_t blen, len, nlen;
- int rval;
- char *bp, *ntype, *p, nbuf[100];
-
- vip = VIP(sp);
-
- /* Do repeat operations. */
- if (vp->character == '#')
- vp->character = vip->inc_lastch;
-
- /* Get new value. */
- if (F_ISSET(vp, VC_C1SET))
- vip->inc_lastval = vp->count;
-
- if (vp->character != '+' && vp->character != '-') {
- msgq(sp, M_ERR, "usage: %s.", vp->kp->usage);
- return (1);
- }
- vip->inc_lastch = vp->character;
-
- /* Figure out the resulting type and number. */
- p = vp->keyword;
- len = vp->klen;
- if (len > 1 && p[0] == '0') {
- if (vp->character == '+') {
- ulval = strtoul(vp->keyword, NULL, 0);
- if (ULONG_MAX - ulval < vip->inc_lastval)
- goto overflow;
- ulval += vip->inc_lastval;
- } else {
- ulval = strtoul(vp->keyword, NULL, 0);
- if (ulval < vip->inc_lastval)
- goto underflow;
- ulval -= vip->inc_lastval;
- }
- ntype = fmt[OCTAL];
- if (len > 2)
- if (p[1] == 'X')
- ntype = fmt[HEXC];
- else if (p[1] == 'x')
- ntype = fmt[HEXL];
- nlen = snprintf(nbuf, sizeof(nbuf), ntype, len, ulval);
- } else {
- if (vp->character == '+') {
- lval = strtol(vp->keyword, NULL, 0);
- if (lval > 0 && LONG_MAX - lval < vip->inc_lastval) {
-overflow: msgq(sp, M_ERR, "Resulting number too large.");
- return (1);
- }
- lval += vip->inc_lastval;
- } else {
- lval = strtol(vp->keyword, NULL, 0);
- if (lval < 0 && -(LONG_MIN - lval) < vip->inc_lastval) {
-underflow: msgq(sp, M_ERR, "Resulting number too small.");
- return (1);
- }
- lval -= vip->inc_lastval;
- }
- ntype = lval != 0 &&
- (*vp->keyword == '+' || *vp->keyword == '-') ?
- fmt[SDEC] : fmt[DEC];
- nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
- }
-
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- GET_SPACE_RET(sp, bp, blen, len + nlen);
- memmove(bp, p, fm->cno);
- memmove(bp + fm->cno, nbuf, nlen);
- memmove(bp + fm->cno + nlen,
- p + fm->cno + vp->klen, len - fm->cno - vp->klen);
- len = len - vp->klen + nlen;
-
- rval = file_sline(sp, ep, fm->lno, bp, len);
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
diff --git a/usr.bin/vi/nvi/v_init.c b/usr.bin/vi/nvi/v_init.c
deleted file mode 100644
index f0d2facf4ea3..000000000000
--- a/usr.bin/vi/nvi/v_init.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_init.c 8.18 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-#include "excmd.h"
-
-static int v_comment __P((SCR *, EXF *));
-
-/*
- * v_screen_copy --
- * Copy vi screen.
- */
-int
-v_screen_copy(orig, sp)
- SCR *orig, *sp;
-{
- VI_PRIVATE *ovip, *nvip;
-
- /* Create the private vi structure. */
- CALLOC_RET(orig, nvip, VI_PRIVATE *, 1, sizeof(VI_PRIVATE));
- sp->vi_private = nvip;
-
- if (orig == NULL) {
- nvip->inc_lastch = '+';
- nvip->inc_lastval = 1;
- } else {
- ovip = VIP(orig);
-
- /* User can replay the last input, but nothing else. */
- if (ovip->rep_len != 0) {
- MALLOC(orig, nvip->rep, char *, ovip->rep_len);
- if (nvip->rep != NULL) {
- memmove(nvip->rep, ovip->rep, ovip->rep_len);
- nvip->rep_len = ovip->rep_len;
- }
- }
-
- nvip->inc_lastch = ovip->inc_lastch;
- nvip->inc_lastval = ovip->inc_lastval;
-
- if (ovip->paragraph != NULL &&
- (nvip->paragraph = strdup(ovip->paragraph)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- }
- return (0);
-}
-
-/*
- * v_screen_end --
- * End a vi screen.
- */
-int
-v_screen_end(sp)
- SCR *sp;
-{
- VI_PRIVATE *vip;
-
- vip = VIP(sp);
-
- if (vip->rep != NULL)
- FREE(vip->rep, vip->rep_len);
-
- if (vip->paragraph != NULL)
- FREE(vip->paragraph, vip->paragraph_len);
-
- /* Free private memory. */
- FREE(vip, sizeof(VI_PRIVATE));
- sp->vi_private = NULL;
-
- return (0);
-}
-
-/*
- * v_init --
- * Initialize vi.
- */
-int
-v_init(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- size_t len;
-
- /*
- * The default address is line 1, column 0. If the address set
- * bit is on for this file, load the address, ensuring that it
- * exists.
- */
- if (F_ISSET(sp->frp, FR_CURSORSET)) {
- sp->lno = sp->frp->lno;
- sp->cno = sp->frp->cno;
-
- if (file_gline(sp, ep, sp->lno, &len) == NULL) {
- if (sp->lno != 1 || sp->cno != 0) {
- if (file_lline(sp, ep, &sp->lno))
- return (1);
- if (sp->lno == 0)
- sp->lno = 1;
- sp->cno = 0;
- }
- } else if (sp->cno >= len)
- sp->cno = 0;
-
- } else {
- sp->lno = 1;
- sp->cno = 0;
-
- if (O_ISSET(sp, O_COMMENT) && v_comment(sp, ep))
- return (1);
- }
-
- /* Reset strange attraction. */
- sp->rcm = 0;
- sp->rcmflags = 0;
-
- /* Make ex display to a special function. */
- if ((sp->stdfp = fwopen(sp, sp->s_ex_write)) == NULL) {
- msgq(sp, M_SYSERR, "ex output");
- return (1);
- }
-#ifdef MAKE_EX_OUTPUT_LINE_BUFFERED
- (void)setvbuf(sp->stdfp, NULL, _IOLBF, 0);
-#endif
-
- /* Display the status line. */
- return (status(sp, ep, sp->lno, 0));
-}
-
-/*
- * v_end --
- * End vi session.
- */
-int
-v_end(sp)
- SCR *sp;
-{
- /* Close down ex output file descriptor. */
- (void)fclose(sp->stdfp);
-
- return (0);
-}
-
-/*
- * v_optchange --
- * Handle change of options for vi.
- */
-int
-v_optchange(sp, opt)
- SCR *sp;
- int opt;
-{
- switch (opt) {
- case O_PARAGRAPHS:
- case O_SECTIONS:
- return (v_buildparagraph(sp));
- }
- return (0);
-}
-
-/*
- * v_comment --
- * Skip the first comment.
- */
-static int
-v_comment(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- recno_t lno;
- size_t len;
- char *p;
-
- for (lno = 1;
- (p = file_gline(sp, ep, lno, &len)) != NULL && len == 0; ++lno);
- if (p == NULL || len <= 1 || memcmp(p, "/*", 2))
- return (0);
- do {
- for (; len; --len, ++p)
- if (p[0] == '*' && len > 1 && p[1] == '/') {
- sp->lno = lno;
- return (0);
- }
- } while ((p = file_gline(sp, ep, ++lno, &len)) != NULL);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_join.c b/usr.bin/vi/nvi/v_join.c
deleted file mode 100644
index c3f81d6d1a5c..000000000000
--- a/usr.bin/vi/nvi/v_join.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_join.c 8.3 (Berkeley) 8/29/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * v_join -- [count]J
- * Join lines together.
- */
-int
-v_join(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
- int lno;
-
- /*
- * YASC.
- * The general rule is that '#J' joins # lines, counting the current
- * line. However, 'J' and '1J' are the same as '2J', i.e. join the
- * current and next lines. This doesn't map well into the ex command
- * (which takes two line numbers), so we handle it here. Note that
- * we never test for EOF -- historically going past the end of file
- * worked just fine.
- */
- lno = fm->lno + 1;
- if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
- lno = fm->lno + (vp->count - 1);
-
- SETCMDARG(cmd, C_JOIN, 2, fm->lno, lno, 0, NULL);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_left.c b/usr.bin/vi/nvi/v_left.c
deleted file mode 100644
index cc80b379b06d..000000000000
--- a/usr.bin/vi/nvi/v_left.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_left.c 8.3 (Berkeley) 12/16/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_left -- [count]^H, [count]h
- * Move left by columns.
- */
-int
-v_left(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t cnt;
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- if (fm->cno == 0) {
- msgq(sp, M_BERR, "Already in the first column.");
- return (1);
- }
-
- rp->lno = fm->lno;
- if (fm->cno > cnt)
- rp->cno = fm->cno - cnt;
- else
- rp->cno = 0;
- return (0);
-}
-
-/*
- * v_cfirst -- [count]_
- *
- * Move to the first non-blank column on a line.
- */
-int
-v_cfirst(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t cnt;
-
- /*
- * A count moves down count - 1 rows, so, "3_" is the same as "2j_".
- *
- * !!!
- * Historically, if the _ is a motion, it is always a line motion,
- * and the line motion flag is set.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if (cnt != 1) {
- --vp->count;
- if (v_down(sp, ep, vp, fm, tm, rp))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- F_SET(vp, VC_LMODE);
- } else
- rp->lno = fm->lno;
- rp->cno = 0;
- if (nonblank(sp, ep, rp->lno, &rp->cno))
- return (1);
- return (0);
-}
-
-/*
- * v_first -- ^
- * Move to the first non-blank column on this line.
- */
-int
-v_first(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Yielding to none in our quest for compatibility with every
- * historical blemish of vi, no matter how strange it might be,
- * we permit the user to enter a count and then ignore it.
- */
- rp->cno = 0;
- if (nonblank(sp, ep, fm->lno, &rp->cno))
- return (1);
- rp->lno = fm->lno;
- return (0);
-}
-
-/*
- * v_ncol -- [count]|
- * Move to column count or the first column on this line. If the
- * requested column is past EOL, move to EOL. The nasty part is
- * that we have to know character column widths to make this work.
- */
-int
-v_ncol(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(vp, VC_C1SET) && vp->count > 1)
- rp->cno =
- sp->s_chposition(sp, ep, fm->lno, (size_t)--vp->count);
- else
- rp->cno = 0;
- rp->lno = fm->lno;
- return (0);
-}
-
-/*
- * v_zero -- 0
- * Move to the first column on this line.
- */
-int
-v_zero(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- rp->lno = fm->lno;
- rp->cno = 0;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_mark.c b/usr.bin/vi/nvi/v_mark.c
deleted file mode 100644
index 714242d9331e..000000000000
--- a/usr.bin/vi/nvi/v_mark.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_mark.c 8.3 (Berkeley) 10/31/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_mark -- m[a-z]
- * Set a mark.
- */
-int
-v_mark(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- rp->lno = fm->lno;
- rp->cno = fm->cno;
- return (mark_set(sp, ep, vp->character, fm, 1));
-}
-
-/*
- * v_gomark -- '['`a-z], or `['`a-z]
- * Move to a mark.
- *
- * The single quote form moves to the first nonblank character of a line
- * containing a mark. The back quote form moves to a mark, setting both
- * row and column. We use a single routine for both forms, taking care
- * of the nonblank behavior using a flag for the command.
- *
- * Although not commonly known, the "'`" and "'`" forms are historically
- * valid. The behavior is determined by the first character, so "`'" is
- * the same as "``". Remember this fact -- you'll be amazed at how many
- * people don't know it and will be delighted that you are able to tell
- * them.
- */
-int
-v_gomark(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- MARK *mp;
-
- if ((mp = mark_get(sp, ep, vp->character)) == NULL)
- return (1);
- *rp = *mp;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_match.c b/usr.bin/vi/nvi/v_match.c
deleted file mode 100644
index 963cca551fe8..000000000000
--- a/usr.bin/vi/nvi/v_match.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_match.c 8.7 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_match -- %
- * Search to matching character.
- */
-int
-v_match(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- register int cnt, matchc, startc;
- VCS cs;
- recno_t lno;
- size_t len, off;
- int (*gc)__P((SCR *, EXF *, VCS *));
- char *p;
-
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- goto nomatch;
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- /*
- * !!!
- * Historical practice was to search in the forward direction only.
- */
- for (off = fm->cno;; ++off) {
- if (off >= len) {
-nomatch: msgq(sp, M_BERR, "No match character on this line.");
- return (1);
- }
- switch (startc = p[off]) {
- case '(':
- matchc = ')';
- gc = cs_next;
- break;
- case ')':
- matchc = '(';
- gc = cs_prev;
- break;
- case '[':
- matchc = ']';
- gc = cs_next;
- break;
- case ']':
- matchc = '[';
- gc = cs_prev;
- break;
- case '{':
- matchc = '}';
- gc = cs_next;
- break;
- case '}':
- matchc = '{';
- gc = cs_prev;
- break;
- default:
- continue;
- }
- break;
- }
-
- cs.cs_lno = fm->lno;
- cs.cs_cno = off;
- if (cs_init(sp, ep, &cs))
- return (1);
- for (cnt = 1;;) {
- if (gc(sp, ep, &cs))
- return (1);
- if (cs.cs_flags != 0) {
- if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
- break;
- continue;
- }
- if (cs.cs_ch == startc)
- ++cnt;
- else if (cs.cs_ch == matchc && --cnt == 0)
- break;
- }
- if (cnt) {
- msgq(sp, M_BERR, "Matching character not found.");
- return (1);
- }
- rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
-
- /*
- * Movement commands go one space further. Increment the return
- * MARK or from MARK depending on the direction of the search.
- */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
- if (len)
- if (gc == cs_next)
- ++rp->cno;
- else
- ++fm->cno;
- }
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_ntext.c b/usr.bin/vi/nvi/v_ntext.c
deleted file mode 100644
index 1c17ffc5bdd0..000000000000
--- a/usr.bin/vi/nvi/v_ntext.c
+++ /dev/null
@@ -1,1728 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_ntext.c 8.80 (Berkeley) 1/13/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "seq.h"
-#include "vcmd.h"
-#include "excmd.h"
-
-static int txt_abbrev __P((SCR *, TEXT *, ARG_CHAR_T, int, int *, int *));
-static void txt_ai_resolve __P((SCR *, TEXT *));
-static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
-static void txt_err __P((SCR *, EXF *, TEXTH *));
-static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
-static int txt_indent __P((SCR *, TEXT *));
-static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
-static int txt_outdent __P((SCR *, TEXT *));
-static void txt_showmatch __P((SCR *, EXF *));
-static int txt_resolve __P((SCR *, EXF *, TEXTH *));
-
-/* Cursor character (space is hard to track on the screen). */
-#if defined(DEBUG) && 0
-#undef CURSOR_CH
-#define CURSOR_CH '+'
-#endif
-
-/* Local version of BINC. */
-#define TBINC(sp, lp, llen, nlen) { \
- if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
- goto err; \
-}
-
-/*
- * newtext --
- * Read in text from the user.
- *
- * !!!
- * Historic vi always used:
- *
- * ^D: autoindent deletion
- * ^H: last character deletion
- * ^W: last word deletion
- * ^V: quote the next character
- *
- * regardless of the user's choices for these characters. The user's erase
- * and kill characters worked in addition to these characters. Ex was not
- * completely consistent with this, as it did map the scroll command to the
- * user's EOF character.
- *
- * This implementation does not use fixed characters, but uses whatever the
- * user specified as described by the termios structure. I'm getting away
- * with something here, but I think I'm unlikely to get caught.
- *
- * !!!
- * Historic vi did a special screen optimization for tab characters. For
- * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of
- * the string when it was displayed. Because this implementation redisplays
- * the entire line on each keystroke, the "bcd" gets pushed to the right as
- * we ignore that the user has "promised" to change the rest of the characters.
- * Users have noticed, but this isn't worth fixing, and, the way that the
- * historic vi did it results in an even worse bug. Given the keystrokes
- * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
- * on the second <esc> key.
- */
-int
-v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
- SCR *sp;
- EXF *ep;
- TEXTH *tiqh;
- MARK *tm; /* To MARK. */
- const char *lp; /* Input line. */
- const size_t len; /* Input line length. */
- MARK *rp; /* Return MARK. */
- int prompt; /* Prompt to display. */
- recno_t ai_line; /* Line number to use for autoindent count. */
- u_int flags; /* TXT_ flags. */
-{
- /* State of abbreviation checks. */
- enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
- /* State of the "[^0]^D" sequences. */
- enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
- /* State of the hex input character. */
- enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
- /* State of quotation. */
- enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
- CH ikey; /* Input character structure. */
- CHAR_T ch; /* Input character. */
- GS *gp; /* Global pointer. */
- TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
- size_t rcol; /* 0-N: insert offset in the replay buffer. */
- size_t col; /* Current column. */
- u_long margin; /* Wrapmargin value. */
- u_int iflags; /* Input flags. */
- int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */
- int eval; /* Routine return value. */
- int replay; /* If replaying a set of input. */
- int showmatch; /* Showmatch set on this character. */
- int testnr; /* Test first character for nul replay. */
- int max, tmp;
- char *p;
-
- /*
- * Set the input flag, so tabs get displayed correctly
- * and everyone knows that the text buffer is in use.
- */
- F_SET(sp, S_INPUT);
-
- /* Local initialization. */
- eval = 0;
- gp = sp->gp;
-
- /*
- * Get one TEXT structure with some initial buffer space, reusing
- * the last one if it's big enough. (All TEXT bookkeeping fields
- * default to 0 -- text_init() handles this.) If changing a line,
- * copy it into the TEXT buffer.
- */
- if (tiqh->cqh_first != (void *)tiqh) {
- tp = tiqh->cqh_first;
- if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
- text_lfree(tiqh);
- goto newtp;
- }
- tp->ai = tp->insert = tp->offset = tp->owrite = 0;
- if (lp != NULL) {
- tp->len = len;
- memmove(tp->lb, lp, len);
- } else
- tp->len = 0;
- } else {
-newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
- return (1);
- CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
- }
-
- /* Set the starting line number. */
- tp->lno = sp->lno;
-
- /*
- * Set the insert and overwrite counts. If overwriting characters,
- * do insertion afterward. If not overwriting characters, assume
- * doing insertion. If change is to a mark, emphasize it with an
- * END_CH.
- */
- if (len) {
- if (LF_ISSET(TXT_OVERWRITE)) {
- tp->owrite = tm->cno - sp->cno;
- tp->insert = len - tm->cno;
- } else
- tp->insert = len - sp->cno;
-
- if (LF_ISSET(TXT_EMARK))
- tp->lb[tm->cno - 1] = END_CH;
- }
-
- /*
- * Many of the special cases in this routine are to handle autoindent
- * support. Somebody decided that it would be a good idea if "^^D"
- * and "0^D" deleted all of the autoindented characters. In an editor
- * that takes single character input from the user, this wasn't a very
- * good idea. Note also that "^^D" resets the next lines' autoindent,
- * but "0^D" doesn't.
- *
- * We assume that autoindent only happens on empty lines, so insert
- * and overwrite will be zero. If doing autoindent, figure out how
- * much indentation we need and fill it in. Update input column and
- * screen cursor as necessary.
- */
- if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
- if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
- return (1);
- sp->cno = tp->ai;
- } else {
- /*
- * The cc and S commands have a special feature -- leading
- * <blank> characters are handled as autoindent characters.
- * Beauty!
- */
- if (LF_ISSET(TXT_AICHARS)) {
- tp->offset = 0;
- tp->ai = sp->cno;
- } else
- tp->offset = sp->cno;
- }
-
- /* If getting a command buffer from the user, there may be a prompt. */
- if (LF_ISSET(TXT_PROMPT)) {
- tp->lb[sp->cno++] = prompt;
- ++tp->len;
- ++tp->offset;
- }
-
- /*
- * If appending after the end-of-line, add a space into the buffer
- * and move the cursor right. This space is inserted, i.e. pushed
- * along, and then deleted when the line is resolved. Assumes that
- * the cursor is already positioned at the end of the line. This
- * avoids the nastiness of having the cursor reside on a magical
- * column, i.e. a column that doesn't really exist. The only down
- * side is that we may wrap lines or scroll the screen before it's
- * strictly necessary. Not a big deal.
- */
- if (LF_ISSET(TXT_APPENDEOL)) {
- tp->lb[sp->cno] = CURSOR_CH;
- ++tp->len;
- ++tp->insert;
- }
-
- /*
- * Historic practice is that the wrapmargin value was a distance
- * from the RIGHT-HAND column, not the left. It's more useful to
- * us as a distance from the left-hand column.
- *
- * !!!
- * Replay commands are not affected by wrapmargin values. What
- * I found surprising was that people actually depend on it, as
- * in this gem of a macro which centers lines:
- *
- * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p
- *
- * XXX
- * Setting margin causes a significant performance hit. Normally
- * we don't update the screen if there are keys waiting, but we
- * have to if margin is set, otherwise the screen routines don't
- * know where the cursor is.
- */
- if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))
- margin = 0;
- else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
- margin = sp->cols - margin;
-
- /* Initialize abbreviations checks. */
- if (F_ISSET(gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
- abb = A_NOTSPACE;
- ab_cnt = ab_turnoff = 0;
- } else
- abb = A_NOTSET;
-
- /*
- * Set up the dot command. Dot commands are done by saving the
- * actual characters and replaying the input. We have to push
- * the characters onto the key stack and then handle them normally,
- * otherwise things like wrapmargin will fail.
- *
- * XXX
- * It would be nice if we could swallow backspaces and such, but
- * it's not all that easy to do. Another possibility would be to
- * recognize full line insertions, which could be performed quickly,
- * without replay.
- */
-nullreplay:
- rcol = 0;
- if (replay = LF_ISSET(TXT_REPLAY)) {
- /*
- * !!!
- * Historically, it wasn't an error to replay non-existent
- * input. This test is necessary, we get here by the user
- * doing an input command followed by a nul.
- *
- * !!!
- * Historically, vi did not remap or reabbreviate replayed
- * input. It did, however, beep at you if you changed an
- * abbreviation and then replayed the input. We're not that
- * compatible.
- */
- if (VIP(sp)->rep == NULL)
- return (0);
- if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))
- return (1);
- testnr = 0;
- abb = A_NOTSET;
- LF_CLR(TXT_RECORD);
- } else
- testnr = 1;
-
- iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
- for (gp, showmatch = 0,
- carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
- /*
- * Reset the line and update the screen. (The txt_showmatch()
- * code refreshes the screen for us.) Don't refresh unless
- * we're about to wait on a character or we need to know where
- * the cursor really is.
- */
- if (showmatch || margin || !KEYS_WAITING(sp)) {
- if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
- goto err;
- if (showmatch) {
- showmatch = 0;
- txt_showmatch(sp, ep);
- } else if (sp->s_refresh(sp, ep))
- goto err;
- }
-
- /* Get the next character. */
-next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
- goto err;
- ch = ikey.ch;
-
- /* Abbreviation check. See comment in txt_abbrev(). */
-#define MAX_ABBREVIATION_EXPANSION 256
- if (ikey.flags & CH_ABBREVIATED) {
- if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
- term_ab_flush(sp,
- "Abbreviation exceeded maximum number of characters");
- ab_cnt = 0;
- continue;
- }
- } else
- ab_cnt = 0;
-
- /*
- * !!!
- * Historic feature. If the first character of the input is
- * a nul, replay the previous input. This isn't documented
- * anywhere, and is a great test of vi clones.
- */
- if (ch == '\0' && testnr) {
- LF_SET(TXT_REPLAY);
- goto nullreplay;
- }
- testnr = 0;
-
- /*
- * Check to see if the character fits into the input (and
- * replay, if necessary) buffers. It isn't necessary to
- * have tp->len bytes, since it doesn't consider overwrite
- * characters, but not worth fixing.
- */
- if (LF_ISSET(TXT_RECORD)) {
- TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
- VIP(sp)->rep[rcol++] = ch;
- }
- TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
-
- /*
- * If the character was quoted, replace the last character
- * (the literal mark) with the new character. If quoted
- * by someone else, simply insert the character.
- *
- * !!!
- * Extension -- if the quoted character is HEX_CH, enter hex
- * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
- * try to use the value as a character. Anything else resets
- * hex mode.
- */
- if (ikey.flags & CH_QUOTED)
- goto ins_ch;
- if (quoted == Q_THISCHAR) {
- --sp->cno;
- ++tp->owrite;
- quoted = Q_NOTSET;
-
- if (ch == HEX_CH)
- hex = H_NEXTCHAR;
- goto ins_ch;
- }
-
- switch (ikey.value) {
- case K_CR:
- case K_NL: /* New line. */
-#define LINE_RESOLVE { \
- /* \
- * Handle abbreviations. If there was one, \
- * discard the replay characters. \
- */ \
- if (abb == A_NOTSPACE && !replay) { \
- if (txt_abbrev(sp, tp, ch, \
- LF_ISSET(TXT_INFOLINE), &tmp, \
- &ab_turnoff)) \
- goto err; \
- if (tmp) { \
- if (LF_ISSET(TXT_RECORD)) \
- rcol -= tmp; \
- goto next_ch; \
- } \
- } \
- if (abb != A_NOTSET) \
- abb = A_SPACE; \
- /* Handle hex numbers. */ \
- if (hex == H_INHEX) { \
- if (txt_hex(sp, tp, &tmp, ch)) \
- goto err; \
- if (tmp) { \
- hex = H_NOTSET; \
- goto next_ch; \
- } \
- } \
- /* \
- * The 'R' command returns any overwriteable \
- * characters in the first line to the original \
- * characters.
- */ \
- if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
- tp == tiqh->cqh_first) { \
- memmove(tp->lb + sp->cno, \
- lp + sp->cno, tp->owrite); \
- tp->insert += tp->owrite; \
- tp->owrite = 0; \
- } \
- /* Delete any appended cursor. */ \
- if (LF_ISSET(TXT_APPENDEOL)) { \
- --tp->len; \
- --tp->insert; \
- } \
-}
- LINE_RESOLVE;
-
- /* CR returns from the vi command line. */
- if (LF_ISSET(TXT_CR)) {
- /*
- * If a script window and not the colon
- * line, push a <cr> so it gets executed.
- */
- if (F_ISSET(sp, S_SCRIPT) &&
- !LF_ISSET(TXT_INFOLINE))
- (void)term_push(sp,
- "\r", 1, 0, CH_NOMAP);
- goto k_escape;
- }
-
- /*
- * Historic practice was to delete any <blank>
- * characters following the inserted newline.
- * This affects the 'R', 'c', and 's' commands.
- */
- for (p = tp->lb + sp->cno + tp->owrite;
- tp->insert && isblank(*p);
- ++p, ++tp->owrite, --tp->insert);
-
- /*
- * Move any remaining insert characters into
- * a new TEXT structure.
- */
- if ((ntp = text_init(sp,
- tp->lb + sp->cno + tp->owrite,
- tp->insert, tp->insert + 32)) == NULL)
- goto err;
-
- /* Set bookkeeping for the new line. */
- ntp->lno = tp->lno + 1;
- ntp->insert = tp->insert;
-
- /*
- * Note if the user inserted any characters on this
- * line. Done before calling txt_ai_resolve() because
- * it changes the value of sp->cno without making the
- * corresponding changes to tp->ai.
- */
- tmp = sp->cno <= tp->ai;
-
- /*
- * Resolve autoindented characters for the old line.
- * Reset the autoindent line value. 0^D keeps the ai
- * line from changing, ^D changes the level, even if
- * there are no characters in the old line. Note,
- * if using the current tp structure, use the cursor
- * as the length, the user may have erased autoindent
- * characters.
- */
- if (LF_ISSET(TXT_AUTOINDENT)) {
- txt_ai_resolve(sp, tp);
-
- if (carat_st == C_NOCHANGE) {
- if (txt_auto(sp, ep,
- OOBLNO, &ait, ait.ai, ntp))
- goto err;
- FREE_SPACE(sp, ait.lb, ait.lb_len);
- } else
- if (txt_auto(sp, ep,
- OOBLNO, tp, sp->cno, ntp))
- goto err;
- carat_st = C_NOTSET;
- }
-
- /*
- * If the user hasn't entered any characters, delete
- * any autoindent characters.
- *
- * !!!
- * Historic vi didn't get the insert test right, if
- * there were characters after the cursor, entering
- * a <cr> left the autoindent characters on the line.
- */
- if (tmp)
- sp->cno = 0;
-
- /* Reset bookkeeping for the old line. */
- tp->len = sp->cno;
- tp->ai = tp->insert = tp->owrite = 0;
-
- /* New cursor position. */
- sp->cno = ntp->ai;
-
- /* New lines are TXT_APPENDEOL if nothing to insert. */
- if (ntp->insert == 0) {
- TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
- LF_SET(TXT_APPENDEOL);
- ntp->lb[sp->cno] = CURSOR_CH;
- ++ntp->insert;
- ++ntp->len;
- }
-
- /* Update the old line. */
- if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
- goto err;
-
- /*
- * Swap old and new TEXT's, and insert the new TEXT
- * into the queue. (DON'T insert until the old line
- * has been updated, or the inserted line count in
- * line.c:file_gline() will be wrong.)
- */
- tp = ntp;
- CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
-
- /* Reset the cursor. */
- sp->lno = tp->lno;
-
- /* Update the new line. */
- if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
- goto err;
-
- /* Set the renumber bit. */
- F_SET(sp, S_RENUMBER);
-
- /* Refresh if nothing waiting. */
- if ((margin || !KEYS_WAITING(sp)) &&
- sp->s_refresh(sp, ep))
- goto err;
- goto next_ch;
- case K_ESCAPE: /* Escape. */
- if (!LF_ISSET(TXT_ESCAPE))
- goto ins_ch;
-
- LINE_RESOLVE;
-
- /*
- * If there aren't any trailing characters in the line
- * and the user hasn't entered any characters, delete
- * the autoindent characters.
- */
- if (!tp->insert && sp->cno <= tp->ai) {
- tp->len = tp->owrite = 0;
- sp->cno = 0;
- } else if (LF_ISSET(TXT_AUTOINDENT))
- txt_ai_resolve(sp, tp);
-
- /* If there are insert characters, copy them down. */
-k_escape: if (tp->insert && tp->owrite)
- memmove(tp->lb + sp->cno,
- tp->lb + sp->cno + tp->owrite, tp->insert);
- tp->len -= tp->owrite;
-
- /*
- * Delete any lines that were inserted into the text
- * structure and then erased.
- */
- while (tp->q.cqe_next != (void *)tiqh) {
- ntp = tp->q.cqe_next;
- CIRCLEQ_REMOVE(tiqh, ntp, q);
- text_free(ntp);
- }
-
- /*
- * If not resolving the lines into the file, end
- * it with a nul.
- *
- * XXX
- * This is wrong, should pass back a length.
- */
- if (LF_ISSET(TXT_RESOLVE)) {
- if (txt_resolve(sp, ep, tiqh))
- goto err;
- /*
- * Clear input flag -- input buffer no longer
- * valid.
- */
- F_CLR(sp, S_INPUT);
- } else {
- TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
- tp->lb[tp->len] = '\0';
- }
-
- /*
- * Set the return cursor position to rest on the last
- * inserted character.
- */
- if (rp != NULL) {
- rp->lno = tp->lno;
- rp->cno = sp->cno ? sp->cno - 1 : 0;
- if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
- goto err;
- }
- goto ret;
- case K_CARAT: /* Delete autoindent chars. */
- if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
- carat_st = C_CARATSET;
- goto ins_ch;
- case K_ZERO: /* Delete autoindent chars. */
- if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
- carat_st = C_ZEROSET;
- goto ins_ch;
- case K_VEOF: /* Delete autoindent char. */
- /*
- * If in the first column or no characters to erase,
- * ignore the ^D (this matches historic practice). If
- * not doing autoindent or already inserted non-ai
- * characters, it's a literal. The latter test is done
- * in the switch, as the CARAT forms are N + 1, not N.
- */
- if (!LF_ISSET(TXT_AUTOINDENT))
- goto ins_ch;
- if (sp->cno == 0 || tp->ai == 0)
- break;
- switch (carat_st) {
- case C_CARATSET: /* ^^D */
- if (sp->cno > tp->ai + tp->offset + 1)
- goto ins_ch;
-
- /* Save the ai string for later. */
- ait.lb = NULL;
- ait.lb_len = 0;
- TBINC(sp, ait.lb, ait.lb_len, tp->ai);
- memmove(ait.lb, tp->lb, tp->ai);
- ait.ai = ait.len = tp->ai;
-
- carat_st = C_NOCHANGE;
- goto leftmargin;
- case C_ZEROSET: /* 0^D */
- if (sp->cno > tp->ai + tp->offset + 1)
- goto ins_ch;
- carat_st = C_NOTSET;
-leftmargin: tp->lb[sp->cno - 1] = ' ';
- tp->owrite += sp->cno - tp->offset;
- tp->ai = 0;
- sp->cno = tp->offset;
- break;
- case C_NOTSET: /* ^D */
- if (sp->cno > tp->ai + tp->offset)
- goto ins_ch;
- (void)txt_outdent(sp, tp);
- break;
- default:
- abort();
- }
- break;
- case K_VERASE: /* Erase the last character. */
- /*
- * If can erase over the prompt, return. Len is 0
- * if backspaced over the prompt, 1 if only CR entered.
- */
- if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
- tp->len = 0;
- goto ret;
- }
-
- /*
- * If at the beginning of the line, try and drop back
- * to a previously inserted line.
- */
- if (sp->cno == 0) {
- if ((ntp = txt_backup(sp,
- ep, tiqh, tp, flags)) == NULL)
- goto err;
- tp = ntp;
- break;
- }
-
- /* If nothing to erase, bell the user. */
- if (sp->cno <= tp->offset) {
- msgq(sp, M_BERR,
- "No more characters to erase.");
- break;
- }
-
- /* Drop back one character. */
- --sp->cno;
-
- /*
- * Increment overwrite, decrement ai if deleted.
- *
- * !!!
- * Historic vi did not permit users to use erase
- * characters to delete autoindent characters.
- */
- ++tp->owrite;
- if (sp->cno < tp->ai)
- --tp->ai;
- break;
- case K_VINTR:
- /*
- * !!!
- * Historically, <interrupt> exited the user from
- * editing the infoline, and returned to the main
- * screen. It also beeped the terminal, but that
- * seems excessive.
- */
- if (LF_ISSET(TXT_INFOLINE)) {
- tp->lb[tp->len = 0] = '\0';
- goto ret;
- }
- goto ins_ch;
- case K_VWERASE: /* Skip back one word. */
- /*
- * If at the beginning of the line, try and drop back
- * to a previously inserted line.
- */
- if (sp->cno == 0) {
- if ((ntp = txt_backup(sp,
- ep, tiqh, tp, flags)) == NULL)
- goto err;
- tp = ntp;
- }
-
- /*
- * If at offset, nothing to erase so bell the user.
- */
- if (sp->cno <= tp->offset) {
- msgq(sp, M_BERR,
- "No more characters to erase.");
- break;
- }
-
- /*
- * First werase goes back to any autoindent
- * and second werase goes back to the offset.
- *
- * !!!
- * Historic vi did not permit users to use erase
- * characters to delete autoindent characters.
- */
- if (tp->ai && sp->cno > tp->ai)
- max = tp->ai;
- else {
- tp->ai = 0;
- max = tp->offset;
- }
-
- /* Skip over trailing space characters. */
- while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
- --sp->cno;
- ++tp->owrite;
- }
- if (sp->cno == max)
- break;
- /*
- * There are three types of word erase found on UNIX
- * systems. They can be identified by how the string
- * /a/b/c is treated -- as 1, 3, or 6 words. Historic
- * vi had two classes of characters, and strings were
- * delimited by them and <blank>'s, so, 6 words. The
- * historic tty interface used <blank>'s to delimit
- * strings, so, 1 word. The algorithm offered in the
- * 4.4BSD tty interface (as stty altwerase) treats it
- * as 3 words -- there are two classes of characters,
- * and strings are delimited by them and <blank>'s.
- * The difference is that the type of the first erased
- * character erased is ignored, which is exactly right
- * when erasing pathname components. Here, the options
- * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
- * tty interface and the historic tty driver behavior,
- * respectively, and the default is the same as the
- * historic vi behavior.
- */
- if (LF_ISSET(TXT_TTYWERASE))
- while (sp->cno > max) {
- --sp->cno;
- ++tp->owrite;
- if (isblank(tp->lb[sp->cno - 1]))
- break;
- }
- else {
- if (LF_ISSET(TXT_ALTWERASE)) {
- --sp->cno;
- ++tp->owrite;
- if (isblank(tp->lb[sp->cno - 1]))
- break;
- }
- if (sp->cno > max)
- tmp = inword(tp->lb[sp->cno - 1]);
- while (sp->cno > max) {
- --sp->cno;
- ++tp->owrite;
- if (tmp != inword(tp->lb[sp->cno - 1])
- || isblank(tp->lb[sp->cno - 1]))
- break;
- }
- }
- break;
- case K_VKILL: /* Restart this line. */
- /*
- * If at the beginning of the line, try and drop back
- * to a previously inserted line.
- */
- if (sp->cno == 0) {
- if ((ntp = txt_backup(sp,
- ep, tiqh, tp, flags)) == NULL)
- goto err;
- tp = ntp;
- }
-
- /* If at offset, nothing to erase so bell the user. */
- if (sp->cno <= tp->offset) {
- msgq(sp, M_BERR,
- "No more characters to erase.");
- break;
- }
-
- /*
- * First kill goes back to any autoindent
- * and second kill goes back to the offset.
- *
- * !!!
- * Historic vi did not permit users to use erase
- * characters to delete autoindent characters.
- */
- if (tp->ai && sp->cno > tp->ai)
- max = tp->ai;
- else {
- tp->ai = 0;
- max = tp->offset;
- }
- tp->owrite += sp->cno - max;
- sp->cno = max;
- break;
- case K_CNTRLT: /* Add autoindent char. */
- if (!LF_ISSET(TXT_CNTRLT))
- goto ins_ch;
- if (txt_indent(sp, tp))
- goto err;
- goto ebuf_chk;
- case K_CNTRLZ:
- (void)sp->s_suspend(sp);
- break;
-#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
- case K_FORMFEED:
- F_SET(sp, S_REFRESH);
- break;
-#endif
- case K_RIGHTBRACE:
- case K_RIGHTPAREN:
- showmatch = LF_ISSET(TXT_SHOWMATCH);
- goto ins_ch;
- case K_VLNEXT: /* Quote the next character. */
- /* If in hex mode, see if we've entered a hex value. */
- if (hex == H_INHEX) {
- if (txt_hex(sp, tp, &tmp, ch))
- goto err;
- if (tmp) {
- hex = H_NOTSET;
- goto next_ch;
- }
- }
- ch = '^';
- quoted = Q_NEXTCHAR;
- /* FALLTHROUGH */
- default: /* Insert the character. */
-ins_ch: /*
- * If entering a space character after a word, check
- * for abbreviations. If there was one, discard the
- * replay characters.
- */
- if (isblank(ch) && abb == A_NOTSPACE && !replay) {
- if (txt_abbrev(sp, tp, ch,
- LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
- goto err;
- if (tmp) {
- if (LF_ISSET(TXT_RECORD))
- rcol -= tmp;
- goto next_ch;
- }
- }
- /* If in hex mode, see if we've entered a hex value. */
- if (hex == H_INHEX && !isxdigit(ch)) {
- if (txt_hex(sp, tp, &tmp, ch))
- goto err;
- if (tmp) {
- hex = H_NOTSET;
- goto next_ch;
- }
- }
- /* Check to see if we've crossed the margin. */
- if (margin) {
- if (sp->s_column(sp, ep, &col))
- goto err;
- if (col >= margin) {
- if (txt_margin(sp, tp, &tmp, ch))
- goto err;
- if (tmp)
- goto next_ch;
- }
- }
- if (abb != A_NOTSET)
- abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
-
- if (tp->owrite) /* Overwrite a character. */
- --tp->owrite;
- else if (tp->insert) { /* Insert a character. */
- ++tp->len;
- if (tp->insert == 1)
- tp->lb[sp->cno + 1] = tp->lb[sp->cno];
- else
- memmove(tp->lb + sp->cno + 1,
- tp->lb + sp->cno, tp->insert);
- }
-
- tp->lb[sp->cno++] = ch;
-
- /*
- * If we've reached the end of the buffer, then we
- * need to switch into insert mode. This happens
- * when there's a change to a mark and the user puts
- * in more characters than the length of the motion.
- */
-ebuf_chk: if (sp->cno >= tp->len) {
- TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
- LF_SET(TXT_APPENDEOL);
- tp->lb[sp->cno] = CURSOR_CH;
- ++tp->insert;
- ++tp->len;
- }
-
- if (hex == H_NEXTCHAR)
- hex = H_INHEX;
- if (quoted == Q_NEXTCHAR)
- quoted = Q_THISCHAR;
- break;
- }
-#if defined(DEBUG) && 1
- if (sp->cno + tp->insert + tp->owrite != tp->len)
- msgq(sp, M_ERR,
- "len %u != cno: %u ai: %u insert %u overwrite %u",
- tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
- tp->len = sp->cno + tp->insert + tp->owrite;
-#endif
- }
-
- /* Clear input flag. */
-ret: F_CLR(sp, S_INPUT);
-
- if (LF_ISSET(TXT_RECORD))
- VIP(sp)->rep_cnt = rcol;
- return (eval);
-
- /* Error jump. */
-err: eval = 1;
- txt_err(sp, ep, tiqh);
- goto ret;
-}
-
-/*
- * txt_abbrev --
- * Handle abbreviations.
- */
-static int
-txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
- SCR *sp;
- TEXT *tp;
- ARG_CHAR_T pushc;
- int isinfoline, *didsubp, *turnoffp;
-{
- CHAR_T ch;
- SEQ *qp;
- size_t len, off;
- char *p;
-
- /* Find the beginning of this "word". */
- for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
- if (isblank(*p)) {
- ++p;
- break;
- }
- ++len;
- if (off == tp->ai || off == tp->offset)
- break;
- }
-
- /*
- * !!!
- * Historic vi exploded abbreviations on the command line. This has
- * obvious problems in that unabbreviating the string can be extremely
- * tricky, particularly if the string has, say, an embedded escape
- * character. Personally, I think it's a stunningly bad idea. Other
- * examples of problems this caused in historic vi are:
- * :ab foo bar
- * :ab foo baz
- * results in "bar" being abbreviated to "baz", which wasn't what the
- * user had in mind at all. Also, the commands:
- * :ab foo bar
- * :unab foo<space>
- * resulted in an error message that "bar" wasn't mapped. Finally,
- * since the string was already exploded by the time the unabbreviate
- * command got it, all it knew was that an abbreviation had occurred.
- * Cleverly, it checked the replacement string for its unabbreviation
- * match, which meant that the commands:
- * :ab foo1 bar
- * :ab foo2 bar
- * :unab foo2
- * unabbreviates "foo1", and the commands:
- * :ab foo bar
- * :ab bar baz
- * unabbreviates "foo"!
- *
- * Anyway, people neglected to first ask my opinion before they wrote
- * macros that depend on this stuff, so, we make this work as follows.
- * When checking for an abbreviation on the command line, if we get a
- * string which is <blank> terminated and which starts at the beginning
- * of the line, we check to see it is the abbreviate or unabbreviate
- * commands. If it is, turn abbreviations off and return as if no
- * abbreviation was found. Not also, minor trickiness, so that if the
- * user erases the line and starts another command, we go ahead an turn
- * abbreviations back on.
- *
- * This makes the layering look like a Nachos Supreme.
- */
- *didsubp = 0;
- if (isinfoline)
- if (off == tp->ai || off == tp->offset)
- if (ex_is_abbrev(p, len)) {
- *turnoffp = 1;
- return (0);
- } else
- *turnoffp = 0;
- else
- if (*turnoffp)
- return (0);
-
- /* Check for any abbreviations. */
- if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
- return (0);
-
- /*
- * Push the abbreviation onto the tty stack. Historically, characters
- * resulting from an abbreviation expansion were themselves subject to
- * map expansions, O_SHOWMATCH matching etc. This means the expanded
- * characters will be re-tested for abbreviations. It's difficult to
- * know what historic practice in this case was, since abbreviations
- * were applied to :colon command lines, so entering abbreviations that
- * looped was tricky, although possible. In addition, obvious loops
- * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
- * silently only implement and/or display the last abbreviation.)
- *
- * This implementation doesn't recover well from such abbreviations.
- * The main input loop counts abbreviated characters, and, when it
- * reaches a limit, discards any abbreviated characters on the queue.
- * It's difficult to back up to the original position, as the replay
- * queue would have to be adjusted, and the line state when an initial
- * abbreviated character was received would have to be saved.
- */
- ch = pushc;
- if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
- return (1);
- if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
- return (1);
-
- /*
- * Move the cursor to the start of the abbreviation,
- * adjust the length.
- */
- sp->cno -= len;
- tp->len -= len;
-
- /* Copy any insert characters back. */
- if (tp->insert)
- memmove(tp->lb + sp->cno + tp->owrite,
- tp->lb + sp->cno + tp->owrite + len, tp->insert);
-
- /*
- * We return the length of the abbreviated characters. This is so
- * the calling routine can replace the replay characters with the
- * abbreviation. This means that subsequent '.' commands will produce
- * the same text, regardless of intervening :[un]abbreviate commands.
- * This is historic practice.
- */
- *didsubp = len;
- return (0);
-}
-
-/* Offset to next column of stop size. */
-#define STOP_OFF(c, stop) (stop - (c) % stop)
-
-/*
- * txt_ai_resolve --
- * When a line is resolved by <esc> or <cr>, review autoindent
- * characters.
- */
-static void
-txt_ai_resolve(sp, tp)
- SCR *sp;
- TEXT *tp;
-{
- u_long ts;
- int del;
- size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
- char *p;
-
- /*
- * If the line is empty, has an offset, or no autoindent
- * characters, we're done.
- */
- if (!tp->len || tp->offset || !tp->ai)
- return;
-
- /*
- * The autoindent characters plus any leading <blank> characters
- * in the line are resolved into the minimum number of characters.
- * Historic practice.
- */
- ts = O_VAL(sp, O_TABSTOP);
-
- /* Figure out the last <blank> screen column. */
- for (p = tp->lb, scno = 0, len = tp->len,
- spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
- if (*p == '\t') {
- if (spaces)
- tab_after_sp = 1;
- scno += STOP_OFF(scno, ts);
- } else {
- ++spaces;
- ++scno;
- }
-
- /*
- * If there are no spaces, or no tabs after spaces and less than
- * ts spaces, it's already minimal.
- */
- if (!spaces || !tab_after_sp && spaces < ts)
- return;
-
- /* Count up spaces/tabs needed to get to the target. */
- for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
- cno += STOP_OFF(cno, ts);
- spaces = scno - cno;
-
- /*
- * Figure out how many characters we're dropping -- if we're not
- * dropping any, it's already minimal, we're done.
- */
- old = p - tp->lb;
- new = spaces + tabs;
- if (old == new)
- return;
-
- /* Shift the rest of the characters down, adjust the counts. */
- del = old - new;
- memmove(p - del, p, tp->len - old);
- sp->cno -= del;
- tp->len -= del;
-
- /* Fill in space/tab characters. */
- for (p = tp->lb; tabs--;)
- *p++ = '\t';
- while (spaces--)
- *p++ = ' ';
-}
-
-/*
- * txt_auto --
- * Handle autoindent. If aitp isn't NULL, use it, otherwise,
- * retrieve the line.
- */
-int
-txt_auto(sp, ep, lno, aitp, len, tp)
- SCR *sp;
- EXF *ep;
- recno_t lno;
- size_t len;
- TEXT *aitp, *tp;
-{
- size_t nlen;
- char *p, *t;
-
- if (aitp == NULL) {
- if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
- return (0);
- } else
- p = t = aitp->lb;
- for (nlen = 0; len; ++p) {
- if (!isblank(*p))
- break;
- /* If last character is a space, it counts. */
- if (--len == 0) {
- ++p;
- break;
- }
- }
-
- /* No indentation. */
- if (p == t)
- return (0);
-
- /* Set count. */
- nlen = p - t;
-
- /* Make sure the buffer's big enough. */
- BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
-
- /* Copy the indentation into the new buffer. */
- memmove(tp->lb + nlen, tp->lb, tp->len);
- memmove(tp->lb, t, nlen);
- tp->len += nlen;
-
- /* Return the additional length. */
- tp->ai = nlen;
- return (0);
-}
-
-/*
- * txt_backup --
- * Back up to the previously edited line.
- */
-static TEXT *
-txt_backup(sp, ep, tiqh, tp, flags)
- SCR *sp;
- EXF *ep;
- TEXTH *tiqh;
- TEXT *tp;
- u_int flags;
-{
- TEXT *ntp;
- recno_t lno;
- size_t total;
-
- /* Get a handle on the previous TEXT structure. */
- if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
- msgq(sp, M_BERR, "Already at the beginning of the insert");
- return (tp);
- }
-
- /* Make sure that we have enough space. */
- total = ntp->len + tp->insert;
- if (LF_ISSET(TXT_APPENDEOL))
- ++total;
- if (total > ntp->lb_len &&
- binc(sp, &ntp->lb, &ntp->lb_len, total))
- return (NULL);
-
- /*
- * Append a cursor or copy inserted bytes to the end of the old line.
- * Test for appending a cursor first, because the TEXT insert field
- * will be 1 if we're appending a cursor. I don't think there's a
- * third case, so abort() if there is.
- */
- if (LF_ISSET(TXT_APPENDEOL)) {
- ntp->lb[ntp->len] = CURSOR_CH;
- ntp->insert = 1;
- } else if (tp->insert) {
- memmove(ntp->lb + ntp->len, tp->lb + tp->owrite, tp->insert);
- ntp->insert = tp->insert;
- } else
- abort();
-
- /* Set bookkeeping information. */
- sp->lno = ntp->lno;
- sp->cno = ntp->len;
- ntp->len += ntp->insert;
-
- /* Release the current TEXT. */
- lno = tp->lno;
- CIRCLEQ_REMOVE(tiqh, tp, q);
- text_free(tp);
-
- /* Update the old line on the screen. */
- if (sp->s_change(sp, ep, lno, LINE_DELETE))
- return (NULL);
-
- /* Return the old line. */
- return (ntp);
-}
-
-/*
- * txt_err --
- * Handle an error during input processing.
- */
-static void
-txt_err(sp, ep, tiqh)
- SCR *sp;
- EXF *ep;
- TEXTH *tiqh;
-{
- recno_t lno;
- size_t len;
-
- /*
- * The problem with input processing is that the cursor is at an
- * indeterminate position since some input may have been lost due
- * to a malloc error. So, try to go back to the place from which
- * the cursor started, knowing that it may no longer be available.
- *
- * We depend on at least one line number being set in the text
- * chain.
- */
- for (lno = tiqh->cqh_first->lno;
- file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
-
- sp->lno = lno == 0 ? 1 : lno;
- sp->cno = 0;
-
- /* Redraw the screen, just in case. */
- F_SET(sp, S_REDRAW);
-}
-
-/*
- * txt_hex --
- * Let the user insert any character value they want.
- *
- * !!!
- * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
- * for the user to specify a character value which their keyboard
- * may not be able to enter.
- */
-static int
-txt_hex(sp, tp, was_hex, pushc)
- SCR *sp;
- TEXT *tp;
- int *was_hex;
- ARG_CHAR_T pushc;
-{
- CHAR_T ch, savec;
- size_t len, off;
- u_long value;
- char *p, *wp;
-
- /*
- * Null-terminate the string. Since nul isn't a legal hex value,
- * this should be okay, and lets us use a local routine, which
- * presumably understands the character set, to convert the value.
- */
- savec = tp->lb[sp->cno];
- tp->lb[sp->cno] = 0;
-
- /* Find the previous HEX_CH. */
- for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
- if (*p == HEX_CH) {
- wp = p + 1;
- break;
- }
- ++len;
- /* If not on this line, there's nothing to do. */
- if (off == tp->ai || off == tp->offset)
- goto nothex;
- }
-
- /* If no length, then it wasn't a hex value. */
- if (len == 0)
- goto nothex;
-
- /* Get the value. */
- value = strtol(wp, NULL, 16);
- if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
-nothex: tp->lb[sp->cno] = savec;
- *was_hex = 0;
- return (0);
- }
-
- ch = pushc;
- if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
- return (1);
- ch = value;
- if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
- return (1);
-
- tp->lb[sp->cno] = savec;
-
- /* Move the cursor to the start of the hex value, adjust the length. */
- sp->cno -= len + 1;
- tp->len -= len + 1;
-
- /* Copy any insert characters back. */
- if (tp->insert)
- memmove(tp->lb + sp->cno + tp->owrite,
- tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
-
- *was_hex = 1;
- return (0);
-}
-
-/*
- * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
- * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
- * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
- * the 10th column, and ^D moves it back.
- *
- * !!!
- * The ^T and ^D characters in historical vi only had special meaning when
- * they were the first characters typed after entering text input mode.
- * Since normal erase characters couldn't erase autoindent (in this case
- * ^T) characters, this meant that inserting text into previously existing
- * text was quite strange, ^T only worked if it was the first keystroke,
- * and then it could only be erased by using ^D. This implementation treats
- * ^T specially anywhere it occurs in the input, and permits the standard
- * erase characters to erase characters inserted using it.
- *
- * XXX
- * Technically, txt_indent, txt_outdent should part of the screen interface,
- * as they require knowledge of the size of a space character on the screen.
- * (Not the size of tabs, because tabs are logically composed of spaces.)
- * They're left in the text code because they're complicated, not to mention
- * the gruesome awareness that if spaces aren't a single column on the screen
- * for any language, we're into some serious, ah, for lack of a better word,
- * "issues".
- */
-
-/*
- * txt_indent --
- * Handle ^T indents.
- */
-static int
-txt_indent(sp, tp)
- SCR *sp;
- TEXT *tp;
-{
- u_long sw, ts;
- size_t cno, off, scno, spaces, tabs;
-
- ts = O_VAL(sp, O_TABSTOP);
- sw = O_VAL(sp, O_SHIFTWIDTH);
-
- /* Get the current screen column. */
- for (off = scno = 0; off < sp->cno; ++off)
- if (tp->lb[off] == '\t')
- scno += STOP_OFF(scno, ts);
- else
- ++scno;
-
- /* Count up spaces/tabs needed to get to the target. */
- for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
- cno + STOP_OFF(cno, ts) <= scno; ++tabs)
- cno += STOP_OFF(cno, ts);
- spaces = scno - cno;
-
- /* Put space/tab characters in place of any overwrite characters. */
- for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
- tp->lb[sp->cno++] = '\t';
- for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
- tp->lb[sp->cno++] = ' ';
-
- if (!tabs && !spaces)
- return (0);
-
- /* Make sure there's enough room. */
- BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
-
- /* Move the insert characters out of the way. */
- if (tp->insert)
- memmove(tp->lb + sp->cno + spaces + tabs,
- tp->lb + sp->cno, tp->insert);
-
- /* Add new space/tab characters. */
- for (; tabs--; ++tp->len, ++tp->ai)
- tp->lb[sp->cno++] = '\t';
- for (; spaces--; ++tp->len, ++tp->ai)
- tp->lb[sp->cno++] = ' ';
- return (0);
-}
-
-/*
- * txt_outdent --
- * Handle ^D outdents.
- *
- */
-static int
-txt_outdent(sp, tp)
- SCR *sp;
- TEXT *tp;
-{
- u_long sw, ts;
- size_t cno, off, scno, spaces;
-
- ts = O_VAL(sp, O_TABSTOP);
- sw = O_VAL(sp, O_SHIFTWIDTH);
-
- /* Get the current screen column. */
- for (off = scno = 0; off < sp->cno; ++off)
- if (tp->lb[off] == '\t')
- scno += STOP_OFF(scno, ts);
- else
- ++scno;
-
- /* Get the previous shiftwidth column. */
- for (cno = scno; --scno % sw != 0;);
-
- /* Decrement characters until less than or equal to that slot. */
- for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
- if (tp->lb[--off] == '\t')
- cno -= STOP_OFF(cno, ts);
- else
- --cno;
-
- /* Spaces needed to get to the target. */
- spaces = scno - cno;
-
- /* Maybe just a delete. */
- if (spaces == 0)
- return (0);
-
- /* Make sure there's enough room. */
- BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
-
- /* Use up any overwrite characters. */
- for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
- tp->lb[sp->cno++] = ' ';
-
- /* Maybe that was enough. */
- if (spaces == 0)
- return (0);
-
- /* Move the insert characters out of the way. */
- if (tp->insert)
- memmove(tp->lb + sp->cno + spaces,
- tp->lb + sp->cno, tp->insert);
-
- /* Add new space characters. */
- for (; spaces--; ++tp->len, ++tp->ai)
- tp->lb[sp->cno++] = ' ';
- return (0);
-}
-
-/*
- * txt_resolve --
- * Resolve the input text chain into the file.
- */
-static int
-txt_resolve(sp, ep, tiqh)
- SCR *sp;
- EXF *ep;
- TEXTH *tiqh;
-{
- TEXT *tp;
- recno_t lno;
-
- /* The first line replaces a current line. */
- tp = tiqh->cqh_first;
- if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
- return (1);
-
- /* All subsequent lines are appended into the file. */
- for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
- if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
- return (1);
- return (0);
-}
-
-/*
- * txt_showmatch --
- * Show a character match.
- *
- * !!!
- * Historic vi tried to display matches even in the :colon command line.
- * I think not.
- */
-static void
-txt_showmatch(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- struct timeval second;
- VCS cs;
- MARK m;
- fd_set zero;
- int cnt, endc, startc;
-
- /*
- * Do a refresh first, in case the v_ntext() code hasn't done
- * one in awhile, so the user can see what we're complaining
- * about.
- */
- if (sp->s_refresh(sp, ep))
- return;
- /*
- * We don't display the match if it's not on the screen. Find
- * out what the first character on the screen is.
- */
- if (sp->s_position(sp, ep, &m, 0, P_TOP))
- return;
-
- /* Initialize the getc() interface. */
- cs.cs_lno = sp->lno;
- cs.cs_cno = sp->cno - 1;
- if (cs_init(sp, ep, &cs))
- return;
- startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
-
- /* Search for the match. */
- for (cnt = 1;;) {
- if (cs_prev(sp, ep, &cs))
- return;
- if (cs.cs_lno < m.lno ||
- cs.cs_lno == m.lno && cs.cs_cno < m.cno)
- return;
- if (cs.cs_flags != 0) {
- if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
- (void)sp->s_bell(sp);
- return;
- }
- continue;
- }
- if (cs.cs_ch == endc)
- ++cnt;
- else if (cs.cs_ch == startc && --cnt == 0)
- break;
- }
-
- /* Move to the match. */
- m.lno = sp->lno;
- m.cno = sp->cno;
- sp->lno = cs.cs_lno;
- sp->cno = cs.cs_cno;
- (void)sp->s_refresh(sp, ep);
-
- /*
- * Sleep(3) is eight system calls. Do it fast -- besides,
- * I don't want to wait an entire second.
- */
- FD_ZERO(&zero);
- second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
- second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
- (void)select(0, &zero, &zero, &zero, &second);
-
- /* Return to the current location. */
- sp->lno = m.lno;
- sp->cno = m.cno;
- (void)sp->s_refresh(sp, ep);
-}
-
-/*
- * txt_margin --
- * Handle margin wrap.
- *
- * !!!
- * Historic vi belled the user each time a character was entered after
- * crossing the margin until a space was entered which could be used to
- * break the line. I don't, it tends to wake the cats.
- */
-static int
-txt_margin(sp, tp, didbreak, pushc)
- SCR *sp;
- TEXT *tp;
- int *didbreak;
- ARG_CHAR_T pushc;
-{
- CHAR_T ch;
- size_t len, off, tlen;
- char *p, *wp;
-
- /* Find the closest previous blank. */
- for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
- if (isblank(*p)) {
- wp = p + 1;
- break;
- }
- ++len;
- /* If it's the beginning of the line, there's nothing to do. */
- if (off == tp->ai || off == tp->offset) {
- *didbreak = 0;
- return (0);
- }
- }
-
- /*
- * Historic practice is to delete any trailing whitespace
- * from the previous line.
- */
- for (tlen = len;; --p, --off) {
- if (!isblank(*p))
- break;
- ++tlen;
- if (off == tp->ai || off == tp->offset)
- break;
- }
-
- ch = pushc;
- if (term_push(sp, &ch, 1, 0, CH_NOMAP))
- return (1);
- if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
- return (1);
- ch = '\n';
- if (term_push(sp, &ch, 1, 0, CH_NOMAP))
- return (1);
-
- sp->cno -= tlen;
- tp->owrite += tlen;
- *didbreak = 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_paragraph.c b/usr.bin/vi/nvi/v_paragraph.c
deleted file mode 100644
index 00591cbe899e..000000000000
--- a/usr.bin/vi/nvi/v_paragraph.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_paragraph.c 8.4 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * Paragraphs are empty lines after text or values from the paragraph or
- * section options.
- */
-
-/*
- * v_paragraphf -- [count]}
- * Move forward count paragraphs.
- */
-int
-v_paragraphf(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- enum { P_INTEXT, P_INBLANK } pstate;
- size_t lastlen, len;
- recno_t cnt, lastlno, lno;
- char *p, *lp;
-
- /* Figure out what state we're currently in. */
- lno = fm->lno;
- if ((p = file_gline(sp, ep, lno, &len)) == NULL)
- goto eof;
-
- /*
- * If we start in text, we want to switch states 2 * N - 1
- * times, in non-text, 2 * N times.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- cnt *= 2;
- if (len == 0 || v_isempty(p, len))
- pstate = P_INBLANK;
- else {
- --cnt;
- pstate = P_INTEXT;
- }
-
- for (;;) {
- lastlno = lno;
- lastlen = len;
- if ((p = file_gline(sp, ep, ++lno, &len)) == NULL)
- goto eof;
- switch (pstate) {
- case P_INTEXT:
- if (p[0] == '.' && len >= 2)
- for (lp = VIP(sp)->paragraph; *lp; lp += 2)
- if (lp[0] == p[1] &&
- (lp[1] == ' ' || lp[1] == p[2]) &&
- !--cnt)
- goto found;
- if (len == 0 || v_isempty(p, len)) {
- if (!--cnt)
- goto found;
- pstate = P_INBLANK;
- }
- break;
- case P_INBLANK:
- if (len == 0 || v_isempty(p, len))
- break;
- if (--cnt) {
- pstate = P_INTEXT;
- break;
- }
- /*
- * Historically, a motion command was up to the end
- * of the previous line, whereas the movement command
- * was to the start of the new "paragraph".
- */
-found: if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- rp->lno = lastlno;
- rp->cno = lastlen ? lastlen + 1 : 0;
- } else {
- rp->lno = lno;
- rp->cno = 0;
- }
- return (0);
- default:
- abort();
- }
- }
-
- /*
- * EOF is a movement sink, however, the } command historically
- * moved to the end of the last line if repeatedly invoked.
- */
-eof: if (fm->lno != lno - 1) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
- }
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL)
- GETLINE_ERR(sp, fm->lno);
- if (fm->cno != (len ? len - 1 : 0)) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
- }
- v_eof(sp, ep, NULL);
- return (1);
-}
-
-/*
- * v_paragraphb -- [count]{
- * Move forward count paragraph.
- */
-int
-v_paragraphb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- enum { P_INTEXT, P_INBLANK } pstate;
- size_t len;
- recno_t cnt, lno;
- char *p, *lp;
-
- /*
- * The { command historically moved to the beginning of the first
- * line if invoked on the first line.
- *
- * Check for SOF.
- */
- if (fm->lno <= 1) {
- if (fm->cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
-
- /* Figure out what state we're currently in. */
- lno = fm->lno;
- if ((p = file_gline(sp, ep, lno, &len)) == NULL)
- goto sof;
-
- /*
- * If we start in text, we want to switch states 2 * N - 1
- * times, in non-text, 2 * N times.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- cnt *= 2;
- if (len == 0 || v_isempty(p, len))
- pstate = P_INBLANK;
- else {
- --cnt;
- pstate = P_INTEXT;
- }
-
- for (;;) {
- if ((p = file_gline(sp, ep, --lno, &len)) == NULL)
- goto sof;
- switch (pstate) {
- case P_INTEXT:
- if (p[0] == '.' && len >= 2)
- for (lp = VIP(sp)->paragraph; *lp; lp += 2)
- if (lp[0] == p[1] &&
- (lp[1] == ' ' || lp[1] == p[2]) &&
- !--cnt)
- goto found;
- if (len == 0 || v_isempty(p, len)) {
- if (!--cnt)
- goto found;
- pstate = P_INBLANK;
- }
- break;
- case P_INBLANK:
- if (len != 0 && !v_isempty(p, len)) {
- if (!--cnt) {
-found: rp->lno = lno;
- rp->cno = 0;
- return (0);
- }
- pstate = P_INTEXT;
- }
- break;
- default:
- abort();
- }
- }
-
- /* SOF is a movement sink. */
-sof: rp->lno = 1;
- rp->cno = 0;
- return (0);
-}
-
-/*
- * v_buildparagraph --
- * Build the paragraph command search pattern.
- */
-int
-v_buildparagraph(sp)
- SCR *sp;
-{
- VI_PRIVATE *vip;
- size_t p_len, s_len;
- char *p, *p_p, *s_p;
-
- /*
- * The vi paragraph command searches for either a paragraph or
- * section option macro.
- */
- p_len = (p_p = O_STR(sp, O_PARAGRAPHS)) == NULL ? 0 : strlen(p_p);
- s_len = (s_p = O_STR(sp, O_SECTIONS)) == NULL ? 0 : strlen(s_p);
-
- if (p_len == 0 && s_len == 0)
- return (0);
-
- MALLOC_RET(sp, p, char *, p_len + s_len + 1);
-
- vip = VIP(sp);
- if (vip->paragraph != NULL)
- FREE(vip->paragraph, vip->paragraph_len);
-
- if (p_p != NULL)
- memmove(p, p_p, p_len + 1);
- if (s_p != NULL)
- memmove(p + p_len, s_p, s_len + 1);
- vip->paragraph = p;
- vip->paragraph_len = p_len + s_len + 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_put.c b/usr.bin/vi/nvi/v_put.c
deleted file mode 100644
index 60227ea4ccfd..000000000000
--- a/usr.bin/vi/nvi/v_put.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_put.c 8.6 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-static void inc_buf __P((SCR *, VICMDARG *));
-
-/*
- * v_Put -- [buffer]P
- * Insert the contents of the buffer before the cursor.
- */
-int
-v_Put(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(vp, VC_ISDOT))
- inc_buf(sp, vp);
- return (put(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, rp, 0));
-}
-
-/*
- * v_put -- [buffer]p
- * Insert the contents of the buffer after the cursor.
- */
-int
-v_put(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(vp, VC_ISDOT))
- inc_buf(sp, vp);
-
- return (put(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, rp, 1));
-}
-
-/*
- * Historical whackadoo. The dot command `puts' the numbered buffer
- * after the last one put. For example, `"4p.' would put buffer #4
- * and buffer #5. If the user continued to enter '.', the #9 buffer
- * would be repeatedly output. This was not documented, and is a bit
- * tricky to reconstruct. Historical versions of vi also dropped the
- * contents of the default buffer after each put, so after `"4p' the
- * default buffer would be empty. This makes no sense to me, so we
- * don't bother. Don't assume sequential order of numeric characters.
- *
- * And, if that weren't exciting enough, failed commands don't normally
- * set the dot command. Well, boys and girls, an exception is that
- * the buffer increment gets done regardless of the success of the put.
- */
-static void
-inc_buf(sp, vp)
- SCR *sp;
- VICMDARG *vp;
-{
- CHAR_T v;
-
- switch (vp->buffer) {
- case '1':
- v = '2';
- break;
- case '2':
- v = '3';
- break;
- case '3':
- v = '4';
- break;
- case '4':
- v = '5';
- break;
- case '5':
- v = '6';
- break;
- case '6':
- v = '7';
- break;
- case '7':
- v = '8';
- break;
- case '8':
- v = '9';
- break;
- default:
- return;
- }
- VIP(sp)->sdot.buffer = vp->buffer = v;
-}
diff --git a/usr.bin/vi/nvi/v_redraw.c b/usr.bin/vi/nvi/v_redraw.c
deleted file mode 100644
index fca5ba33b713..000000000000
--- a/usr.bin/vi/nvi/v_redraw.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_redraw.c 8.2 (Berkeley) 8/25/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_redraw --
- * Redraw the screen.
- */
-int
-v_redraw(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- F_SET(sp, S_REFRESH);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_replace.c b/usr.bin/vi/nvi/v_replace.c
deleted file mode 100644
index f9378e7ac4ed..000000000000
--- a/usr.bin/vi/nvi/v_replace.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_replace.c 8.12 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_replace -- [count]rc
- * The r command in historic vi was almost beautiful in its badness.
- * For example, "r<erase>" and "r<word erase>" beeped the terminal
- * and deleted a single character. "Nr<carriage return>", where N
- * was greater than 1, inserted a single carriage return. This may
- * not be right, but at least it's not insane.
- */
-int
-v_replace(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- CH ikey;
- TEXT *tp;
- recno_t lno;
- size_t blen, len;
- u_long cnt;
- int rval;
- char *bp, *p;
-
- /*
- * If the line doesn't exist, or it's empty, replacement isn't
- * allowed. It's not hard to implement, but:
- *
- * 1: It's historic practice.
- * 2: For consistency, this change would require that the more
- * general case, "Nr", when the user is < N characters from
- * the end of the line, also work.
- * 3: Replacing a newline has somewhat odd semantics.
- */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- goto nochar;
- }
- if (len == 0) {
-nochar: msgq(sp, M_BERR, "No characters to replace");
- return (1);
- }
-
- /*
- * Figure out how many characters to be replace; for no particular
- * reason other than that the semantics of replacing the newline
- * are confusing, only permit the replacement of the characters in
- * the current line. I suppose we could simply append the replacement
- * characters to the line, but I see no compelling reason to do so.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- rp->cno = fm->cno + cnt - 1;
- if (rp->cno > len - 1) {
- v_eol(sp, ep, fm);
- return (1);
- }
-
- /* Get the character, literal escapes, escape terminates. */
- if (F_ISSET(vp, VC_ISDOT)) {
- ikey.ch = VIP(sp)->rlast;
- ikey.value = term_key_val(sp, ikey.ch);
- } else {
- if (term_key(sp, &ikey, 0) != INP_OK)
- return (1);
- switch (ikey.value) {
- case K_ESCAPE:
- *rp = *fm;
- return (0);
- case K_VLNEXT:
- if (term_key(sp, &ikey, 0) != INP_OK)
- return (1);
- break;
- }
- VIP(sp)->rlast = ikey.ch;
- }
-
- /* Copy the line. */
- GET_SPACE_RET(sp, bp, blen, len);
- memmove(bp, p, len);
- p = bp;
-
- if (ikey.value == K_CR || ikey.value == K_NL) {
- /* Set return line. */
- rp->lno = fm->lno + cnt;
-
- /* The first part of the current line. */
- if (file_sline(sp, ep, fm->lno, p, fm->cno))
- goto err_ret;
-
- /*
- * The rest of the current line. And, of course, now it gets
- * tricky. Any white space after the replaced character is
- * stripped, and autoindent is applied. Put the cursor on the
- * last indent character as did historic vi.
- */
- for (p += fm->cno + cnt, len -= fm->cno + cnt;
- len && isblank(*p); --len, ++p);
-
- if ((tp = text_init(sp, p, len, len)) == NULL)
- goto err_ret;
- if (txt_auto(sp, ep, fm->lno, NULL, 0, tp))
- goto err_ret;
- rp->cno = tp->ai ? tp->ai - 1 : 0;
- if (file_aline(sp, ep, 1, fm->lno, tp->lb, tp->len))
- goto err_ret;
- text_free(tp);
-
- rval = 0;
-
- /* All of the middle lines. */
- while (--cnt)
- if (file_aline(sp, ep, 1, fm->lno, "", 0)) {
-err_ret: rval = 1;
- break;
- }
- } else {
- memset(bp + fm->cno, ikey.ch, cnt);
- rval = file_sline(sp, ep, fm->lno, bp, len);
-
- rp->lno = fm->lno;
- rp->cno = fm->cno + cnt - 1;
- }
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
diff --git a/usr.bin/vi/nvi/v_right.c b/usr.bin/vi/nvi/v_right.c
deleted file mode 100644
index 54b7be92d005..000000000000
--- a/usr.bin/vi/nvi/v_right.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_right.c 8.3 (Berkeley) 12/16/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_right -- [count]' ', [count]l
- * Move right by columns.
- *
- * Special case: the 'c' and 'd' commands can move past the end of line.
- */
-int
-v_right(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- size_t len;
-
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_eol(sp, ep, NULL);
- else
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- rp->lno = fm->lno;
- if (len == 0 || fm->cno == len - 1) {
- if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- rp->cno = len;
- return (0);
- }
- v_eol(sp, ep, NULL);
- return (1);
- }
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- rp->cno = fm->cno + cnt;
- if (rp->cno > len - 1)
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- rp->cno = len;
- else
- rp->cno = len - 1;
- return (0);
-}
-
-/*
- * v_dollar -- [count]$
- * Move to the last column.
- */
-int
-v_dollar(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t len;
- u_long cnt;
-
- /*
- * A count moves down count - 1 rows, so, "3$" is the same as "2j$".
- *
- * !!!
- * Historically, if the $ is a motion, and deleting from at or before
- * the first non-blank of the line, it's a line motion, and the line
- * motion flag is set.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if (cnt != 1) {
- --vp->count;
- if (v_down(sp, ep, vp, fm, tm, rp))
- return (1);
- rp->cno = 0;
- if (nonblank(sp, ep, rp->lno, &rp->cno))
- return (1);
- if (fm->cno <= rp->cno && F_ISSET(vp, VC_C | VC_D | VC_Y))
- F_SET(vp, VC_LMODE);
- } else
- rp->lno = fm->lno;
-
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_eol(sp, ep, NULL);
- else
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
-
- if (len == 0) {
- v_eol(sp, ep, NULL);
- return (1);
- }
-
- /* If it's a motion component, move one past the end of the line. */
- rp->cno = F_ISSET(vp, VC_C | VC_D | VC_Y) ? len : len - 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_screen.c b/usr.bin/vi/nvi/v_screen.c
deleted file mode 100644
index 986bfa4f29a2..000000000000
--- a/usr.bin/vi/nvi/v_screen.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-
- * Copyright (c) 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_screen.c 8.8 (Berkeley) 11/28/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_screen --
- * Switch screens.
- */
-int
-v_screen(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Try for the next lower screen, or, go back to the first
- * screen on the stack.
- */
- if (sp->q.cqe_next != (void *)&sp->gp->dq)
- sp->nextdisp = sp->q.cqe_next;
- else if (sp->gp->dq.cqh_first == sp) {
- msgq(sp, M_ERR, "No other screen to switch to.");
- return (1);
- } else
- sp->nextdisp = sp->gp->dq.cqh_first;
-
- /*
- * Display the old screen's status line so the user can
- * find the screen they want.
- */
- (void)status(sp, ep, fm->lno, 0);
-
- /* Save the old screen's cursor information. */
- sp->frp->lno = sp->lno;
- sp->frp->cno = sp->cno;
- F_SET(sp->frp, FR_CURSORSET);
-
- F_SET(sp, S_SSWITCH);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_scroll.c b/usr.bin/vi/nvi/v_scroll.c
deleted file mode 100644
index f69ea0fb4e87..000000000000
--- a/usr.bin/vi/nvi/v_scroll.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_scroll.c 8.8 (Berkeley) 12/16/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * The historic vi had a problem in that all movements were by physical
- * lines, not by logical, or screen lines. Arguments can be made that this
- * is the right thing to do. For example, single line movements, such as
- * 'j' or 'k', should probably work on physical lines. Commands like "dj",
- * or "j.", where '.' is a change command, make more sense for physical lines
- * than they do for logical lines.
- *
- * These arguments, however, don't apply to scrolling commands like ^D and
- * ^F -- if the window is fairly small, using physical lines can result in
- * a half-page scroll repainting the entire screen, which is not what the
- * user wanted. Second, if the line is larger than the screen, using physical
- * lines can make it impossible to display parts of the line -- there aren't
- * any commands that don't display the beginning of the line in historic vi,
- * and if both the beginning and end of the line can't be on the screen at
- * the same time, you lose. This is even worse in the case of the H, L, and
- * M commands -- for large lines, they may all refer to the same line and
- * will result in no movement at all.
- *
- * This implementation does the scrolling (^B, ^D, ^F, ^U, ^Y, ^E), and the
- * cursor positioning commands (H, L, M) commands using logical lines, not
- * physical.
- *
- * Another issue is that page and half-page scrolling commands historically
- * moved to the first non-blank character in the new line. If the line is
- * approximately the same size as the screen, this loses because the cursor
- * before and after a ^D, may refer to the same location on the screen. In
- * this implementation, scrolling commands set the cursor to the first non-
- * blank character if the line changes because of the scroll. Otherwise,
- * the cursor is left alone.
- */
-
-/*
- * v_lgoto -- [count]G
- * Go to first non-blank character of the line count, the last line
- * of the file by default.
- */
-int
-v_lgoto(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t last;
-
- if (file_lline(sp, ep, &last))
- return (1);
- if (F_ISSET(vp, VC_C1SET)) {
- if (last < vp->count) {
- v_eof(sp, ep, fm);
- return (1);
- }
- rp->lno = vp->count;
- } else
- rp->lno = last ? last : 1;
- return (0);
-}
-
-/*
- * v_home -- [count]H
- * Move to the first non-blank character of the logical line
- * count from the top of the screen, 1 by default.
- */
-int
-v_home(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (sp->s_position(sp, ep, rp,
- F_ISSET(vp, VC_C1SET) ? vp->count : 0, P_TOP));
-}
-
-/*
- * v_middle -- M
- * Move to the first non-blank character of the logical line
- * in the middle of the screen.
- */
-int
-v_middle(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Yielding to none in our quest for compatibility with every
- * historical blemish of vi, no matter how strange it might be,
- * we permit the user to enter a count and then ignore it.
- */
- return (sp->s_position(sp, ep, rp, 0, P_MIDDLE));
-}
-
-/*
- * v_bottom -- [count]L
- * Move to the first non-blank character of the logical line
- * count from the bottom of the screen, 1 by default.
- */
-int
-v_bottom(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (sp->s_position(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 0, P_BOTTOM));
-}
-
-/*
- * v_up -- [count]^P, [count]k, [count]-
- * Move up by lines.
- */
-int
-v_up(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
-
- lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- if (fm->lno <= lno) {
- v_sof(sp, fm);
- return (1);
- }
- rp->lno = fm->lno - lno;
- return (0);
-}
-
-/*
- * v_cr -- [count]^M
- * In a script window, send the line to the shell.
- * In a regular window, move down by lines.
- */
-int
-v_cr(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * If it's a script window, exec the line,
- * otherwise it's the same as v_down().
- */
- return (F_ISSET(sp, S_SCRIPT) ?
- sscr_exec(sp, ep, fm->lno) : v_down(sp, ep, vp, fm, tm, rp));
-}
-
-/*
- * v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+
- * Move down by lines.
- */
-int
-v_down(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
-
- lno = fm->lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
-
- if (file_gline(sp, ep, lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
- rp->lno = lno;
- return (0);
-}
-
-/*
- * v_hpageup -- [count]^U
- * Page up half screens.
- */
-int
-v_hpageup(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Half screens always succeed unless already at SOF. Half screens
- * set the scroll value, even if the command ultimately failed, in
- * historic vi. It's probably a don't care.
- */
- if (F_ISSET(vp, VC_C1SET))
- O_VAL(sp, O_SCROLL) = vp->count;
- else
- vp->count = O_VAL(sp, O_SCROLL);
-
- return (sp->s_down(sp, ep, rp, (recno_t)O_VAL(sp, O_SCROLL), 1));
-}
-
-/*
- * v_hpagedown -- [count]^D
- * Page down half screens.
- */
-int
-v_hpagedown(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Half screens always succeed unless already at EOF. Half screens
- * set the scroll value, even if the command ultimately failed, in
- * historic vi. It's probably a don't care.
- */
- if (F_ISSET(vp, VC_C1SET))
- O_VAL(sp, O_SCROLL) = vp->count;
- else
- vp->count = O_VAL(sp, O_SCROLL);
-
- return (sp->s_up(sp, ep, rp, (recno_t)O_VAL(sp, O_SCROLL), 1));
-}
-
-/*
- * v_pageup -- [count]^B
- * Page up full screens.
- *
- * !!!
- * Historic vi did not move to the SOF if the screen couldn't move, i.e.
- * if SOF was already displayed on the screen. This implementation does
- * move to SOF in that case, making ^B more like the the historic ^U.
- */
-int
-v_pageup(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t count;
-
- /* Calculation from POSIX 1003.2/D8. */
- count = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1);
-
- return (sp->s_down(sp, ep, rp, count, 1));
-}
-
-/*
- * v_pagedown -- [count]^F
- * Page down full screens.
- * !!!
- * Historic vi did not move to the EOF if the screen couldn't move, i.e.
- * if EOF was already displayed on the screen. This implementation does
- * move to EOF in that case, making ^F more like the the historic ^D.
- */
-int
-v_pagedown(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t count;
-
- /* Calculation from POSIX 1003.2/D8. */
- count = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1);
-
- return (sp->s_up(sp, ep, rp, count, 1));
-}
-
-/*
- * v_lineup -- [count]^Y
- * Page up by lines.
- */
-int
-v_lineup(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * The cursor moves down, staying with its original line, unless it
- * reaches the bottom of the screen.
- */
- return (sp->s_down(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0));
-}
-
-/*
- * v_linedown -- [count]^E
- * Page down by lines.
- */
-int
-v_linedown(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * The cursor moves up, staying with its original line, unless it
- * reaches the top of the screen.
- */
- return (sp->s_up(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0));
-}
diff --git a/usr.bin/vi/nvi/v_search.c b/usr.bin/vi/nvi/v_search.c
deleted file mode 100644
index 25dcaf5e2e10..000000000000
--- a/usr.bin/vi/nvi/v_search.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_search.c 8.16 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-static int bcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
-static int fcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
-static int getptrn __P((SCR *, EXF *, int, char **));
-
-/*
- * v_searchn -- n
- * Repeat last search.
- */
-int
-v_searchn(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int flags;
-
- flags = SEARCH_MSG;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- switch (sp->searchdir) {
- case BACKWARD:
- if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case FORWARD:
- if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y| VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case NOTSET:
- msgq(sp, M_ERR, "No previous search pattern.");
- return (1);
- default:
- abort();
- }
- return (0);
-}
-
-/*
- * v_searchN -- N
- * Reverse last search.
- */
-int
-v_searchN(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int flags;
-
- flags = SEARCH_MSG;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- switch (sp->searchdir) {
- case BACKWARD:
- if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case FORWARD:
- if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case NOTSET:
- msgq(sp, M_ERR, "No previous search pattern.");
- return (1);
- default:
- abort();
- }
- return (0);
-}
-
-/*
- * v_searchw -- [count]^A
- * Search for the word under the cursor.
- */
-int
-v_searchw(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t blen, len;
- u_int flags;
- int rval;
- char *bp;
-
- len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
- GET_SPACE_RET(sp, bp, blen, len);
- (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP);
-
- flags = SEARCH_MSG;
- rval = f_search(sp, ep, fm, rp, bp, NULL, &flags);
-
- FREE_SPACE(sp, bp, blen);
- if (rval)
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- return (0);
-}
-
-/*
- * v_searchb -- [count]?RE[? offset]
- * Search backward.
- */
-int
-v_searchb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int flags;
- char *ptrn;
-
- if (F_ISSET(vp, VC_ISDOT))
- ptrn = NULL;
- else {
- if (getptrn(sp, ep, '?', &ptrn))
- return (1);
- if (ptrn == NULL)
- return (0);
- }
-
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- if (b_search(sp, ep, fm, rp, ptrn, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- return (0);
-}
-
-/*
- * v_searchf -- [count]/RE[/ offset]
- * Search forward.
- */
-int
-v_searchf(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- int flags;
- char *ptrn;
-
- if (F_ISSET(vp, VC_ISDOT))
- ptrn = NULL;
- else {
- if (getptrn(sp, ep, '/', &ptrn))
- return (1);
- if (ptrn == NULL)
- return (0);
- }
-
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- if (f_search(sp, ep, fm, rp, ptrn, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- return (0);
-}
-
-/*
- * getptrn --
- * Get the search pattern.
- */
-static int
-getptrn(sp, ep, prompt, storep)
- SCR *sp;
- EXF *ep;
- int prompt;
- char **storep;
-{
- TEXT *tp;
-
- if (sp->s_get(sp, ep, &sp->tiq, prompt,
- TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
- return (1);
-
- /* Len is 0 if backspaced over the prompt, 1 if only CR entered. */
- tp = sp->tiq.cqh_first;
- if (tp->len == 0)
- *storep = NULL;
- else
- *storep = tp->lb;
- return (0);
-}
-
-/*
- * !!!
- * Historically, commands didn't affect the line searched to if the motion
- * command was a search and the pattern match was the start or end of the
- * line. There were some special cases, however, concerning search to the
- * start of end of a line.
- *
- * Vi was not, however, consistent, and it was fairly easy to confuse it.
- * For example, given the two lines:
- *
- * abcdefghi
- * ABCDEFGHI
- *
- * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
- * 'k' and put would no longer work correctly. In any case, we try to do
- * the right thing, but it's not likely exactly match historic practice.
- */
-
-/*
- * bcorrect --
- * Handle command with a backward search as the motion.
- */
-static int
-bcorrect(sp, ep, vp, fm, rp, flags)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- u_int flags;
-{
- size_t len;
- char *p;
-
- /*
- * !!!
- * Correct backward searches which start at column 0 to be one
- * past the last column of the previous line.
- *
- * Backward searches become line mode operations if they start
- * at column 0 and end at column 0 of another line.
- */
- if (fm->lno > rp->lno && fm->cno == 0) {
- if ((p = file_gline(sp, ep, --fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
- if (rp->cno == 0)
- F_SET(vp, VC_LMODE);
- fm->cno = len;
- }
-
- /*
- * !!!
- * Commands would become line mode operations if there was a delta
- * specified to the search pattern.
- */
- if (LF_ISSET(SEARCH_DELTA)) {
- F_SET(vp, VC_LMODE);
- return (0);
- }
- return (0);
-}
-
-/*
- * fcorrect --
- * Handle command with a forward search as the motion.
- */
-static int
-fcorrect(sp, ep, vp, fm, rp, flags)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- u_int flags;
-{
- size_t len;
- char *p;
-
- /*
- * !!!
- * Correct forward searches which end at column 0 to be one
- * past the last column of the previous line.
- *
- * Forward searches become line mode operations if they start
- * at column 0 and end at column 0 of another line.
- */
- if (fm->lno < rp->lno && rp->cno == 0) {
- if ((p = file_gline(sp, ep, --rp->lno, &len)) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
- if (fm->cno == 0)
- F_SET(vp, VC_LMODE);
- rp->cno = len;
- }
-
- /*
- * !!!
- * Commands would become line mode operations if there was a delta
- * specified to the search pattern.
- */
- if (LF_ISSET(SEARCH_DELTA)) {
- F_SET(vp, VC_LMODE);
- return (0);
- }
-
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_section.c b/usr.bin/vi/nvi/v_section.c
deleted file mode 100644
index 8d97e2f10b4e..000000000000
--- a/usr.bin/vi/nvi/v_section.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_section.c 8.4 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * In historic vi, the section commands ignored empty lines, unlike the
- * paragraph commands, which was probably okay. However, they also moved
- * to the start of the last line when there where no more sections instead
- * of the end of the last line like the paragraph commands. I've changed
- * the latter behaviore to match the paragraphs command.
- *
- * In historic vi, a "function" was defined as the first character of the
- * line being an open brace, which could be followed by anything. This
- * implementation follows that historic practice.
- */
-
-/* Macro to do a check on each line. */
-#define CHECK { \
- if (len == 0) \
- continue; \
- if (p[0] == '{') { \
- if (!--cnt) { \
- rp->cno = 0; \
- rp->lno = lno; \
- return (0); \
- } \
- continue; \
- } \
- if (p[0] != '.' || len < 3) \
- continue; \
- for (lp = list; *lp; lp += 2) \
- if (lp[0] == p[1] && \
- (lp[1] == ' ' || lp[1] == p[2]) && !--cnt) { \
- rp->cno = 0; \
- rp->lno = lno; \
- return (0); \
- } \
-}
-
-/*
- * v_sectionf -- [count]]]
- * Move forward count sections/functions.
- */
-int
-v_sectionf(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t len;
- recno_t cnt, lno;
- char *p, *list, *lp;
-
- /* Get macro list. */
- if ((list = O_STR(sp, O_SECTIONS)) == NULL)
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- for (lno = fm->lno; (p = file_gline(sp, ep, ++lno, &len)) != NULL;)
- CHECK;
-
- /* EOF is a movement sink. */
- if (fm->lno != lno - 1) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
- }
- v_eof(sp, ep, NULL);
- return (1);
-}
-
-/*
- * v_sectionb -- [count][[
- * Move backward count sections/functions.
- */
-int
-v_sectionb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t len;
- recno_t cnt, lno;
- char *p, *list, *lp;
-
- /* Check for SOF. */
- if (fm->lno <= 1) {
- v_sof(sp, NULL);
- return (1);
- }
-
- /* Get macro list. */
- if ((list = O_STR(sp, O_SECTIONS)) == NULL)
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- for (lno = fm->lno; (p = file_gline(sp, ep, --lno, &len)) != NULL;)
- CHECK;
-
- /* SOF is a movement sink. */
- rp->lno = 1;
- rp->cno = 0;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_sentence.c b/usr.bin/vi/nvi/v_sentence.c
deleted file mode 100644
index 684952124f14..000000000000
--- a/usr.bin/vi/nvi/v_sentence.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_sentence.c 8.7 (Berkeley) 8/26/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * In historic vi, a sentence was delimited by a '.', '?' or '!' character
- * followed by TWO spaces or a newline. One or more empty lines was also
- * treated as a separate sentence. The Berkeley documentation for historical
- * vi states that any number of ')', ']', '"' and '\'' characters can be
- * between the delimiter character and the spaces or end of line, however,
- * the historical implementation did not handle additional '"' characters.
- * We follow the documentation here, not the implementation.
- *
- * Once again, historical vi didn't do sentence movements associated with
- * counts consistently, mostly in the presence of lines containing only
- * white-space characters.
- *
- * This implementation also permits a single tab to delimit sentences, and
- * treats lines containing only white-space characters as empty lines.
- * And, tabs are eaten (along with spaces) when skipping to the start of the
- * text follow a "sentence".
- */
-
-/*
- * v_sentencef -- [count])
- * Move forward count sentences.
- */
-int
-v_sentencef(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- enum { BLANK, NONE, PERIOD } state;
- VCS cs;
- u_long cnt;
-
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
- if (cs_init(sp, ep, &cs))
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * If in white-space, the next start of sentence counts as one.
- * This may not handle " . " correctly, but it's real unclear
- * what correctly means in that case.
- */
- if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (--cnt == 0) {
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
- goto okret;
- return (1);
- }
- }
- for (state = NONE;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- break;
- if (cs.cs_flags == CS_EOL) {
- if ((state == PERIOD || state == BLANK) && --cnt == 0) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == 0 &&
- isblank(cs.cs_ch) && cs_fblank(sp, ep, &cs))
- return (1);
- goto okret;
- }
- state = NONE;
- continue;
- }
- if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */
- if (--cnt == 0)
- goto okret;
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (--cnt == 0)
- goto okret;
- state = NONE;
- continue;
- }
- switch (cs.cs_ch) {
- case '.':
- case '?':
- case '!':
- state = PERIOD;
- break;
- case ')':
- case ']':
- case '"':
- case '\'':
- if (state != PERIOD)
- state = NONE;
- break;
- case '\t':
- if (state == PERIOD)
- state = BLANK;
- /* FALLTHROUGH */
- case ' ':
- if (state == PERIOD) {
- state = BLANK;
- break;
- }
- if (state == BLANK && --cnt == 0) {
- if (cs_fblank(sp, ep, &cs))
- return (1);
- goto okret;
- }
- /* FALLTHROUGH */
- default:
- state = NONE;
- break;
- }
- }
-
- /* EOF is a movement sink. */
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
- goto okret;
- v_eof(sp, ep, NULL);
- return (1);
-
-okret: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
-
- /*
- * Historic, uh, features, yeah, that's right, call 'em features.
- * If the sentence movement is cutting an entire line, the buffer
- * is in line mode. Reach up into the caller's VICMDARG structure,
- * and whack the flags.
- */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) &&
- fm->cno == 0 && (rp->cno == 0 || cs.cs_flags != 0)) {
- if (rp->cno == 0)
- --rp->lno;
- F_SET(vp, VC_LMODE);
- }
- return (0);
-}
-
-/*
- * v_sentenceb -- [count](
- * Move backward count sentences.
- */
-int
-v_sentenceb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- VCS cs;
- recno_t slno;
- size_t len, scno;
- u_long cnt;
- int last1, last2;
-
- if (fm->lno == 1 && fm->cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
-
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
- if (cs_init(sp, ep, &cs))
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * If on an empty line, skip to the next previous
- * non-white-space character.
- */
- if (cs.cs_flags == CS_EMP) {
- if (cs_bblank(sp, ep, &cs))
- return (1);
- for (;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags != CS_EOL)
- break;
- }
- }
-
- for (last1 = last2 = 0;;) {
- if (cs_prev(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */
- break;
- if (cs.cs_flags == CS_EOL) {
- last2 = last1;
- last1 = 1;
- continue;
- }
- if (cs.cs_flags == CS_EMP) {
- if (--cnt == 0)
- goto ret;
- if (cs_bblank(sp, ep, &cs))
- return (1);
- last1 = last2 = 0;
- continue;
- }
- switch (cs.cs_ch) {
- case '.':
- case '?':
- case '!':
- if (!last1 || --cnt != 0) {
- last2 = last1 = 0;
- continue;
- }
-
-ret: slno = cs.cs_lno;
- scno = cs.cs_cno;
-
- /*
- * Move to the start of the sentence, skipping blanks
- * and special characters.
- */
- do {
- if (cs_next(sp, ep, &cs))
- return (1);
- } while (!cs.cs_flags &&
- (cs.cs_ch == ')' || cs.cs_ch == ']' ||
- cs.cs_ch == '"' || cs.cs_ch == '\''));
- if ((cs.cs_flags || isblank(cs.cs_ch)) &&
- cs_fblank(sp, ep, &cs))
- return (1);
-
- /*
- * If it was ". xyz", with the cursor on the 'x', or
- * "end. ", with the cursor in the spaces, or the
- * beginning of a sentence preceded by an empty line,
- * we can end up where we started. Fix it.
- */
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
- goto okret;
-
- /*
- * Well, if an empty line preceded possible blanks
- * and the sentence, it could be a real sentence.
- */
- for (;;) {
- if (cs_prev(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOL)
- continue;
- if (cs.cs_flags == 0 && isblank(cs.cs_ch))
- continue;
- break;
- }
- if (cs.cs_flags == CS_EMP)
- goto okret;
-
- /* But it wasn't; try again. */
- ++cnt;
- cs.cs_lno = slno;
- cs.cs_cno = scno;
- last2 = last1 = 0;
- break;
- case '\t':
- last1 = last2 = 1;
- break;
- default:
- last2 = last1;
- last1 =
- cs.cs_flags == CS_EOL || isblank(cs.cs_ch) ||
- cs.cs_ch == ')' || cs.cs_ch == ']' ||
- cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0;
- }
- }
-
-okret: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
-
- /*
- * See comment in v_sentencef(). Ignore errors, they should
- * never occur, and they'll get caught later.
- */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) && rp->cno == 0 &&
- file_gline(sp, ep, fm->lno, &len) != NULL && (len == 0 ||
- fm->cno == len - 1))
- F_SET(vp, VC_LMODE);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_shift.c b/usr.bin/vi/nvi/v_shift.c
deleted file mode 100644
index 2e984147a1c1..000000000000
--- a/usr.bin/vi/nvi/v_shift.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_shift.c 8.3 (Berkeley) 11/13/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * v_shiftl -- [count]<motion
- * Shift lines left.
- */
-int
-v_shiftl(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_SHIFTL, 2, fm->lno, tm->lno, 0, "<");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
-
-/*
- * v_shiftr -- [count]>motion
- * Shift lines right.
- */
-int
-v_shiftr(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_SHIFTR, 2, fm->lno, tm->lno, 0, ">");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_status.c b/usr.bin/vi/nvi/v_status.c
deleted file mode 100644
index 9109c0196a80..000000000000
--- a/usr.bin/vi/nvi/v_status.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_status.c 8.10 (Berkeley) 11/20/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <unistd.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_status -- ^G
- * Show the file status.
- */
-int
-v_status(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
-
- /*
- * ^G in historic vi reset the cursor column to the first
- * non-blank character in the line. This doesn't seem of
- * any usefulness whatsoever, so I don't bother.
- */
- return (status(sp, ep, fm->lno, 1));
-}
-
-int
-status(sp, ep, lno, showlast)
- SCR *sp;
- EXF *ep;
- recno_t lno;
- int showlast;
-{
- recno_t last;
- char *mo, *nc, *nf, *ro, *pid;
-#ifdef DEBUG
- char pbuf[50];
-
- (void)snprintf(pbuf, sizeof(pbuf), " (pid %u)", getpid());
- pid = pbuf;
-#else
- pid = "";
-#endif
- /*
- * See nvi/exf.c:file_init() for a description of how and
- * when the read-only bit is set. Possible displays are:
- *
- * new file
- * new file, readonly
- * [un]modified
- * [un]modified, readonly
- * name changed, [un]modified
- * name changed, [un]modified, readonly
- *
- * !!!
- * The historic display for "name changed" was "[Not edited]".
- */
- if (F_ISSET(sp->frp, FR_NEWFILE)) {
- F_CLR(sp->frp, FR_NEWFILE);
- nf = "new file";
- mo = nc = "";
- } else {
- nf = "";
- if (sp->frp->cname != NULL) {
- nc = "name changed";
- mo = F_ISSET(ep, F_MODIFIED) ?
- ", modified" : ", unmodified";
- } else {
- nc = "";
- mo = F_ISSET(ep, F_MODIFIED) ?
- "modified" : "unmodified";
- }
- }
- ro = F_ISSET(sp->frp, FR_RDONLY) ? ", readonly" : "";
- if (showlast) {
- if (file_lline(sp, ep, &last))
- return (1);
- if (last >= 1)
- msgq(sp, M_INFO,
- "%s: %s%s%s%s: line %lu of %lu [%ld%%]%s",
- FILENAME(sp->frp), nf, nc, mo, ro, lno,
- last, (lno * 100) / last, pid);
- else
- msgq(sp, M_INFO, "%s: %s%s%s%s: empty file%s",
- FILENAME(sp->frp), nf, nc, mo, ro, pid);
- } else
- msgq(sp, M_INFO, "%s: %s%s%s%s: line %lu%s",
- FILENAME(sp->frp), nf, nc, mo, ro, lno, pid);
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_stop.c b/usr.bin/vi/nvi/v_stop.c
deleted file mode 100644
index 2f64bfedf195..000000000000
--- a/usr.bin/vi/nvi/v_stop.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_stop.c 8.5 (Berkeley) 10/28/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-int
-v_stop(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /* If autowrite is set, write out the file. */
- if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE)) {
- if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
- return (1);
- if (sp->s_refresh(sp, ep))
- return (1);
- }
- return (sp->s_suspend(sp));
-}
diff --git a/usr.bin/vi/nvi/v_switch.c b/usr.bin/vi/nvi/v_switch.c
deleted file mode 100644
index d0d000facb2b..000000000000
--- a/usr.bin/vi/nvi/v_switch.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_switch.c 8.5 (Berkeley) 11/23/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-#include "excmd.h"
-
-/*
- * v_switch -- ^^
- * Switch to the previous file.
- */
-int
-v_switch(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
- char *name;
-
- /*
- * Try the alternate file name, then the previous file
- * name. Use the real name, not the user's current name.
- */
- if (sp->alt_name != NULL)
- name = sp->alt_name;
- else if (sp->p_frp != NULL)
- name = sp->p_frp->name;
- else {
- msgq(sp, M_ERR, "No previous file to edit.");
- return (1);
- }
-
- /* If autowrite is set, write out the file. */
- if (F_ISSET(ep, F_MODIFIED))
- if (O_ISSET(sp, O_AUTOWRITE)) {
- if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
- return (1);
- } else {
- msgq(sp, M_ERR,
- "Modified since last write; write or use :edit! to override.");
- return (1);
- }
-
- SETCMDARG(cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, name);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_tag.c b/usr.bin/vi/nvi/v_tag.c
deleted file mode 100644
index 530e35279420..000000000000
--- a/usr.bin/vi/nvi/v_tag.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_tag.c 8.2 (Berkeley) 12/3/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-#include "vcmd.h"
-
-/*
- * v_tagpush -- ^[
- * Do a tag search on a the cursor keyword.
- */
-int
-v_tagpush(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_TAG, 0, OOBLNO, 0, 0, vp->keyword);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
-
-/*
- * v_tagpop -- ^T
- * Pop the tags stack.
- */
-/* ARGSUSED */
-int
-v_tagpop(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- EXCMDARG cmd;
-
- SETCMDARG(cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
-}
diff --git a/usr.bin/vi/nvi/v_text.c b/usr.bin/vi/nvi/v_text.c
deleted file mode 100644
index 083b5b248e22..000000000000
--- a/usr.bin/vi/nvi/v_text.c
+++ /dev/null
@@ -1,827 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_text.c 8.23 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * !!!
- * Repeated input in the historic vi is mostly wrong and this isn't very
- * backward compatible. For example, if the user entered "3Aab\ncd" in
- * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then
- * appended to the result. There was also a hack which I don't remember
- * right now, where "3o" would open 3 lines and then let the user fill them
- * in, to make screen movements on 300 baud modems more tolerable. I don't
- * think it's going to be missed.
- */
-
-#define SET_TXT_STD(sp, f) { \
- LF_INIT((f) | TXT_BEAUTIFY | TXT_CNTRLT | TXT_ESCAPE | \
- TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); \
- if (O_ISSET(sp, O_ALTWERASE)) \
- LF_SET(TXT_ALTWERASE); \
- if (O_ISSET(sp, O_AUTOINDENT)) \
- LF_SET(TXT_AUTOINDENT); \
- if (O_ISSET(sp, O_SHOWMATCH)) \
- LF_SET(TXT_SHOWMATCH); \
- if (O_ISSET(sp, O_WRAPMARGIN)) \
- LF_SET(TXT_WRAPMARGIN); \
- if (F_ISSET(sp, S_SCRIPT)) \
- LF_SET(TXT_CR); \
- if (O_ISSET(sp, O_TTYWERASE)) \
- LF_SET(TXT_TTYWERASE); \
-}
-
-/*
- * !!!
- * There's a problem with the way that we do logging for change commands with
- * implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the
- * starting cursor position before the change command "moves" the cursor, the
- * cursor position to which we return on undo will be where the user entered
- * the change command, not the start of the change. Several of the following
- * routines re-log the cursor to make this work correctly. Historic vi tried
- * to do the same thing, and mostly got it right. (The only spectacular way
- * it fails is if the user entered 'o' from anywhere but the last character of
- * the line, the undo returned the cursor to the start of the line. If the
- * user was on the last character of the line, the cursor returned to that
- * position.)
- */
-
-static int v_CS __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *, u_int));
-
-/*
- * v_iA -- [count]A
- * Append text to the end of the line.
- */
-int
-v_iA(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- size_t len;
- u_int flags;
- int first;
- char *p;
-
- SET_TXT_STD(sp, TXT_APPENDEOL);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (first = 1, lno = fm->lno,
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- /* Move the cursor to the end of the line + 1. */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- lno = 1;
- len = 0;
- } else {
- /* Correct logging for implied cursor motion. */
- sp->cno = len == 0 ? 0 : len - 1;
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
- /* Start the change after the line. */
- sp->cno = len;
- }
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
- return (1);
-
- SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
- }
- return (0);
-}
-
-/*
- * v_ia -- [count]a
- * Append text to the cursor position.
- */
-int
-v_ia(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- u_int flags;
- size_t len;
- char *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (lno = fm->lno,
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- /*
- * Move the cursor one column to the right and
- * repaint the screen.
- */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- lno = 1;
- len = 0;
- LF_SET(TXT_APPENDEOL);
- } else if (len) {
- if (len == sp->cno + 1) {
- sp->cno = len;
- LF_SET(TXT_APPENDEOL);
- } else
- ++sp->cno;
- } else
- LF_SET(TXT_APPENDEOL);
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
- return (1);
-
- SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
- }
- return (0);
-}
-
-/*
- * v_iI -- [count]I
- * Insert text at the first non-blank character in the line.
- */
-int
-v_iI(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- size_t len;
- u_int flags;
- int first;
- char *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (first = 1, lno = fm->lno,
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- /*
- * Move the cursor to the start of the line and repaint
- * the screen.
- */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- lno = 1;
- len = 0;
- } else {
- sp->cno = 0;
- if (nonblank(sp, ep, lno, &sp->cno))
- return (1);
- /* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
- }
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
- return (1);
-
- SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
- }
- return (0);
-}
-
-/*
- * v_ii -- [count]i
- * Insert text at the cursor position.
- */
-int
-v_ii(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- size_t len;
- u_int flags;
- char *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (lno = fm->lno,
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- lno = 1;
- len = 0;
- }
- /* If len == sp->cno, it's a replay caused by a count. */
- if (len == 0 || len == sp->cno)
- LF_SET(TXT_APPENDEOL);
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
- return (1);
-
- /*
- * On replay, if the line isn't empty, advance the insert
- * by one (make it an append).
- */
- SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- if ((sp->cno = rp->cno) != 0)
- ++sp->cno;
- }
- return (0);
-}
-
-/*
- * v_iO -- [count]O
- * Insert text above this line.
- */
-int
-v_iO(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t ai_line, lno;
- size_t len;
- u_long cnt;
- u_int flags;
- int first;
- char *p;
-
- SET_TXT_STD(sp, TXT_APPENDEOL);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (first = 1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- if (sp->lno == 1) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0)
- goto insert;
- p = NULL;
- len = 0;
- ai_line = OOBLNO;
- } else {
-insert: p = "";
- sp->cno = 0;
- /* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
- if (file_iline(sp, ep, sp->lno, p, 0))
- return (1);
- if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
- GETLINE_ERR(sp, sp->lno);
- return (1);
- }
- ai_line = sp->lno + 1;
- }
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, ai_line, flags))
- return (1);
-
- SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
- }
- return (0);
-}
-
-/*
- * v_io -- [count]o
- * Insert text after this line.
- */
-int
-v_io(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t ai_line, lno;
- size_t len;
- u_long cnt;
- u_int flags;
- int first;
- char *p;
-
- SET_TXT_STD(sp, TXT_APPENDEOL);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- for (first = 1,
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
- if (sp->lno == 1) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0)
- goto insert;
- p = NULL;
- len = 0;
- ai_line = OOBLNO;
- } else {
-insert: p = "";
- sp->cno = 0;
- /* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
- len = 0;
- if (file_aline(sp, ep, 1, sp->lno, p, len))
- return (1);
- if ((p = file_gline(sp, ep, ++sp->lno, &len)) == NULL) {
- GETLINE_ERR(sp, sp->lno);
- return (1);
- }
- ai_line = sp->lno - 1;
- }
-
- if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, ai_line, flags))
- return (1);
-
- SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
- }
- return (0);
-}
-
-/*
- * v_Change -- [buffer][count]C
- * Change line command.
- */
-int
-v_Change(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (v_CS(sp, ep, vp, fm, tm, rp, 0));
-}
-
-/*
- * v_Subst -- [buffer][count]S
- * Line substitute command.
- */
-int
-v_Subst(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- u_int flags;
-
- /*
- * The S command is the same as a 'C' command from the beginning
- * of the line. This is hard to do in the parser, so do it here.
- *
- * If autoindent is on, the change is from the first *non-blank*
- * character of the line, not the first character. And, to make
- * it just a bit more exciting, the initial space is handled as
- * auto-indent characters.
- */
- LF_INIT(0);
- if (O_ISSET(sp, O_AUTOINDENT)) {
- fm->cno = 0;
- if (nonblank(sp, ep, fm->lno, &fm->cno))
- return (1);
- LF_SET(TXT_AICHARS);
- } else
- fm->cno = 0;
- sp->cno = fm->cno;
- return (v_CS(sp, ep, vp, fm, tm, rp, flags));
-}
-
-/*
- * v_CS --
- * C and S commands.
- */
-static int
-v_CS(sp, ep, vp, fm, tm, rp, iflags)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
- u_int iflags;
-{
- recno_t lno;
- size_t len;
- char *p;
- u_int flags;
-
- SET_TXT_STD(sp, iflags);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
-
- /*
- * There are two cases -- if a count is supplied, we do a line
- * mode change where we delete the lines and then insert text
- * into a new line. Otherwise, we replace the current line.
- */
- tm->lno = fm->lno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
- if (fm->lno != tm->lno) {
- /* Make sure that the to line is real. */
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
-
- /* Cut the lines. */
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
-
- /* Insert a line while we still can... */
- if (file_iline(sp, ep, fm->lno, "", 0))
- return (1);
- ++fm->lno;
- ++tm->lno;
-
- /* Delete the lines. */
- if (delete(sp, ep, fm, tm, 1))
- return (1);
-
- /* Get the inserted line. */
- if ((p = file_gline(sp, ep, --fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- tm = NULL;
- sp->lno = fm->lno;
- sp->cno = 0;
- LF_SET(TXT_APPENDEOL);
- } else {
- /* The line may be empty, but that's okay. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, tm->lno);
- return (1);
- }
- len = 0;
- LF_SET(TXT_APPENDEOL);
- } else {
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
- tm->cno = len;
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
- LF_SET(TXT_EMARK | TXT_OVERWRITE);
- }
- }
- /* Correct logging for implied cursor motion. */
- log_cursor(sp, ep);
- return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
-}
-
-/*
- * v_change -- [buffer][count]c[count]motion
- * Change command.
- */
-int
-v_change(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t blen, len;
- u_int flags;
- int lmode, rval;
- char *bp, *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
-
- /*
- * Move the cursor to the start of the change. Note, if autoindent
- * is turned on, the cc command in line mode changes from the first
- * *non-blank* character of the line, not the first character. And,
- * to make it just a bit more exciting, the initial space is handled
- * as auto-indent characters.
- */
- lmode = F_ISSET(vp, VC_LMODE) ? CUT_LINEMODE : 0;
- if (lmode) {
- fm->cno = 0;
- if (O_ISSET(sp, O_AUTOINDENT)) {
- if (nonblank(sp, ep, fm->lno, &fm->cno))
- return (1);
- LF_SET(TXT_AICHARS);
- }
- }
- sp->lno = fm->lno;
- sp->cno = fm->cno;
-
- /* Correct logging for implied cursor motion. */
- log_cursor(sp, ep);
-
- /*
- * If changing within a single line, the line either currently has
- * text or it doesn't. If it doesn't, just insert text. Otherwise,
- * copy it and overwrite it.
- */
- if (fm->lno == tm->lno) {
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (p == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- }
- len = 0;
- LF_SET(TXT_APPENDEOL);
- } else {
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, lmode))
- return (1);
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
- LF_SET(TXT_EMARK | TXT_OVERWRITE);
- }
- return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
- }
-
- /*
- * It's trickier if changing over multiple lines. If we're in
- * line mode we delete all of the lines and insert a replacement
- * line which the user edits. If there was leading whitespace
- * in the first line being changed, we copy it and use it as the
- * replacement. If we're not in line mode, we just delete the
- * text and start inserting.
- *
- * Copy the text.
- */
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, lmode))
- return (1);
-
- /* If replacing entire lines and there's leading text. */
- if (lmode && fm->cno) {
- /* Get a copy of the first line changed. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- /* Copy the leading text elsewhere. */
- GET_SPACE_RET(sp, bp, blen, fm->cno);
- memmove(bp, p, fm->cno);
- } else
- bp = NULL;
-
- /* Delete the text. */
- if (delete(sp, ep, fm, tm, lmode))
- return (1);
-
- /* If replacing entire lines, insert a replacement line. */
- if (lmode) {
- if (file_iline(sp, ep, fm->lno, bp, fm->cno))
- return (1);
- sp->lno = fm->lno;
- len = sp->cno = fm->cno;
- }
-
- /* Get the line we're editing. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- len = 0;
- }
-
- /* Check to see if we're appending to the line. */
- if (fm->cno >= len)
- LF_SET(TXT_APPENDEOL);
-
- /* No to mark. */
- tm = NULL;
-
- rval = v_ntext(sp, ep, &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags);
-
- if (bp != NULL)
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
-
-/*
- * v_Replace -- [count]R
- * Overwrite multiple characters.
- */
-int
-v_Replace(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- u_long cnt;
- size_t len;
- u_int flags;
- char *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if ((p = file_gline(sp, ep, rp->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
- len = 0;
- LF_SET(TXT_APPENDEOL);
- } else {
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
- LF_SET(TXT_OVERWRITE | TXT_REPLACE);
- }
- tm->lno = rp->lno;
- tm->cno = len ? len : 0;
- if (v_ntext(sp, ep, &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags))
- return (1);
-
- /*
- * Special case. The historic vi handled [count]R badly, in that R
- * would replace some number of characters, and then the count would
- * append count-1 copies of the replacing chars to the replaced space.
- * This seems wrong, so this version counts R commands. There is some
- * trickiness in moving back to where the user stopped replacing after
- * each R command. Basically, if the user ended with a newline, we
- * want to use rp->cno (which will be 0). Otherwise, use the column
- * after the returned cursor, unless it would be past the end of the
- * line, in which case we append to the line.
- */
- while (--cnt) {
- if ((p = file_gline(sp, ep, rp->lno, &len)) == NULL)
- GETLINE_ERR(sp, rp->lno);
- SET_TXT_STD(sp, TXT_REPLAY);
-
- sp->lno = rp->lno;
-
- if (len == 0 || rp->cno == len - 1) {
- sp->cno = len;
- LF_SET(TXT_APPENDEOL);
- } else {
- sp->cno = rp->cno;
- if (rp->cno != 0)
- ++sp->cno;
- LF_SET(TXT_OVERWRITE | TXT_REPLACE);
- }
-
- if (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags))
- return (1);
- }
- return (0);
-}
-
-/*
- * v_subst -- [buffer][count]s
- * Substitute characters.
- */
-int
-v_subst(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t len;
- u_int flags;
- char *p;
-
- SET_TXT_STD(sp, 0);
- if (F_ISSET(vp, VC_ISDOT))
- LF_SET(TXT_REPLAY);
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
- len = 0;
- LF_SET(TXT_APPENDEOL);
- } else {
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
- LF_SET(TXT_EMARK | TXT_OVERWRITE);
- }
-
- tm->lno = fm->lno;
- tm->cno = fm->cno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
- if (tm->cno > len)
- tm->cno = len;
-
- if (p != NULL && cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
-
- return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
-}
diff --git a/usr.bin/vi/nvi/v_ulcase.c b/usr.bin/vi/nvi/v_ulcase.c
deleted file mode 100644
index 12fd1c6626b9..000000000000
--- a/usr.bin/vi/nvi/v_ulcase.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_ulcase.c 8.3 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_ulcase -- [count]~
- * Toggle upper & lower case letters.
- *
- * !!!
- * In historic vi, the count was ignored. It would have been better
- * if there had been an associated motion, but it's too late to change
- * it now.
- */
-int
-v_ulcase(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t lno;
- size_t blen, lcnt, len;
- u_long cnt;
- int ch, change, rval;
- char *bp, *p;
-
- /* Figure out what memory to use. */
- GET_SPACE_RET(sp, bp, blen, 256);
-
- /*
- * !!!
- * Historic vi didn't permit ~ to cross newline boundaries.
- * I can think of no reason why it shouldn't, which at least
- * lets you auto-repeat through a paragraph.
- */
- rval = 0;
- for (change = -1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt;) {
- /* Get the line; EOF is an infinite sink. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno >= fm->lno) {
- GETLINE_ERR(sp, fm->lno);
- rval = 1;
- break;
- }
- if (change == -1) {
- v_eof(sp, ep, NULL);
- return (1);
- }
- break;
- }
-
- /* Set current line number. */
- lno = fm->lno;
-
- /* Empty lines just decrement the count. */
- if (len == 0) {
- --cnt;
- ++fm->lno;
- fm->cno = 0;
- change = 0;
- continue;
- }
-
- /* Get a copy of the line. */
- ADD_SPACE_RET(sp, bp, blen, len);
- memmove(bp, p, len);
-
- /* Set starting pointer. */
- if (change == -1)
- p = bp + fm->cno;
- else
- p = bp;
-
- /*
- * Figure out how many characters get changed in this
- * line. Set the final cursor column.
- */
- if (fm->cno + cnt >= len) {
- lcnt = len - fm->cno;
- ++fm->lno;
- fm->cno = 0;
- } else
- fm->cno += lcnt = cnt;
- cnt -= lcnt;
-
- /* Change the line. */
- for (change = 0; lcnt--; ++p) {
- ch = *(u_char *)p;
- if (islower(ch)) {
- *p = toupper(ch);
- change = 1;
- } else if (isupper(ch)) {
- *p = tolower(ch);
- change = 1;
- }
- }
-
- /* Update the line if necessary. */
- if (change && file_sline(sp, ep, lno, bp, len)) {
- rval = 1;
- break;
- }
- }
-
- /* If changed lines, could be on an illegal line. */
- if (fm->lno != lno && file_gline(sp, ep, fm->lno, &len) == NULL) {
- --fm->lno;
- fm->cno = len ? len - 1 : 0;
- }
- *rp = *fm;
-
- FREE_SPACE(sp, bp, blen);
- return (rval);
-}
diff --git a/usr.bin/vi/nvi/v_undo.c b/usr.bin/vi/nvi/v_undo.c
deleted file mode 100644
index 87c749b38179..000000000000
--- a/usr.bin/vi/nvi/v_undo.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_undo.c 8.6 (Berkeley) 1/8/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_Undo -- U
- * Undo changes to this line.
- */
-int
-v_Undo(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /*
- * Historically, U reset the cursor to the first column in the line
- * (not the first non-blank). This seems a bit non-intuitive, but,
- * considering that we may have undone multiple changes, anything
- * else (including the cursor position stored in the logging records)
- * is going to appear random.
- */
- rp->lno = fm->lno;
- rp->cno = 0;
-
- /*
- * !!!
- * Set up the flags so that an immediately subsequent 'u' will roll
- * forward, instead of backward. In historic vi, a 'u' following a
- * 'U' redid all of the changes to the line. Given that the user has
- * explicitly discarded those changes by entering 'U', it seems likely
- * that the user wants something between the original and end forms of
- * the line, so starting to replay the changes seems the best way to
- * get to there.
- */
- F_SET(ep, F_UNDO);
- ep->lundo = BACKWARD;
-
- return (log_setline(sp, ep));
-}
-
-/*
- * v_undo -- u
- * Undo the last change.
- */
-int
-v_undo(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- /* Set the command count. */
- VIP(sp)->u_ccnt = sp->ccnt;
-
- /*
- * !!!
- * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u'
- * undid the last undo. However, if there has been a change since
- * the last undo/redo, we always do an undo. To make this work when
- * the user can undo multiple operations, we leave the old semantic
- * unchanged, but make '.' after a 'u' do another undo/redo operation.
- * This has two problems.
- *
- * The first is that 'u' didn't set '.' in historic vi. So, if a
- * user made a change, realized it was in the wrong place, does a
- * 'u' to undo it, moves to the right place and then does '.', the
- * change was reapplied. To make this work, we only apply the '.'
- * to the undo command if it's the command immediately following an
- * undo command. See vi/vi.c:getcmd() for the details.
- *
- * The second is that the traditional way to view the numbered cut
- * buffers in vi was to enter the commands "1pu.u.u.u. which will
- * no longer work because the '.' immediately follows the 'u' command.
- * Since we provide a much better method of viewing buffers, and
- * nobody can think of a better way of adding in multiple undo, this
- * remains broken.
- */
- if (!F_ISSET(ep, F_UNDO)) {
- F_SET(ep, F_UNDO);
- ep->lundo = BACKWARD;
- } else if (!F_ISSET(vp, VC_ISDOT))
- ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD;
-
- switch (ep->lundo) {
- case BACKWARD:
- return (log_backward(sp, ep, rp));
- case FORWARD:
- return (log_forward(sp, ep, rp));
- default:
- abort();
- }
- /* NOTREACHED */
-}
diff --git a/usr.bin/vi/nvi/v_util.c b/usr.bin/vi/nvi/v_util.c
deleted file mode 100644
index 83c4fb4ebbf6..000000000000
--- a/usr.bin/vi/nvi/v_util.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_util.c 8.5 (Berkeley) 11/15/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_eof --
- * Vi end-of-file error.
- */
-void
-v_eof(sp, ep, mp)
- SCR *sp;
- EXF *ep;
- MARK *mp;
-{
- u_long lno;
-
- if (mp == NULL)
- msgq(sp, M_BERR, "Already at end-of-file.");
- else {
- if (file_lline(sp, ep, &lno))
- return;
- if (mp->lno >= lno)
- msgq(sp, M_BERR, "Already at end-of-file.");
- else
- msgq(sp, M_BERR,
- "Movement past the end-of-file.");
- }
-}
-
-/*
- * v_eol --
- * Vi end-of-line error.
- */
-void
-v_eol(sp, ep, mp)
- SCR *sp;
- EXF *ep;
- MARK *mp;
-{
- size_t len;
-
- if (mp == NULL)
- msgq(sp, M_BERR, "Already at end-of-line.");
- else {
- if (file_gline(sp, ep, mp->lno, &len) == NULL) {
- GETLINE_ERR(sp, mp->lno);
- return;
- }
- if (mp->cno == len - 1)
- msgq(sp, M_BERR, "Already at end-of-line.");
- else
- msgq(sp, M_BERR, "Movement past the end-of-line.");
- }
-}
-
-/*
- * v_sof --
- * Vi start-of-file error.
- */
-void
-v_sof(sp, mp)
- SCR *sp;
- MARK *mp;
-{
- if (mp == NULL || mp->lno == 1)
- msgq(sp, M_BERR, "Already at the beginning of the file.");
- else
- msgq(sp, M_BERR, "Movement past the beginning of the file.");
-}
-
-/*
- * v_isempty --
- * Return if the line contains nothing but white-space characters.
- */
-int
-v_isempty(p, len)
- char *p;
- size_t len;
-{
- for (; len--; ++p)
- if (!isblank(*p))
- return (0);
- return (1);
-}
diff --git a/usr.bin/vi/nvi/v_word.c b/usr.bin/vi/nvi/v_word.c
deleted file mode 100644
index 8d917d68e088..000000000000
--- a/usr.bin/vi/nvi/v_word.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_word.c 8.10 (Berkeley) 10/26/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * There are two types of "words". Bigwords are easy -- groups of anything
- * delimited by whitespace. Normal words are trickier. They are either a
- * group of characters, numbers and underscores, or a group of anything but,
- * delimited by whitespace. When for a word, if you're in whitespace, it's
- * easy, just remove the whitespace and go to the beginning or end of the
- * word. Otherwise, figure out if the next character is in a different group.
- * If it is, go to the beginning or end of that group, otherwise, go to the
- * beginning or end of the current group. The historic version of vi didn't
- * get this right, so, for example, there were cases where "4e" was not the
- * same as "eeee". To get it right you have to resolve the cursor after each
- * search so that the look-ahead to figure out what type of "word" the cursor
- * is in will be correct.
- *
- * Empty lines, and lines that consist of only white-space characters count
- * as a single word, and the beginning and end of the file counts as an
- * infinite number of words.
- *
- * Movements associated with commands are different than movement commands.
- * For example, in "abc def", with the cursor on the 'a', "cw" is from
- * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white
- * space is discarded from the change movement. Another example is that,
- * in the same string, a "cw" on any white space character replaces that
- * single character, and nothing else. Ain't nothin' in here that's easy.
- *
- * One historic note -- in the original vi, the 'w', 'W' and 'B' commands
- * would treat groups of empty lines as individual words, i.e. the command
- * would move the cursor to each new empty line. The 'e' and 'E' commands
- * would treat groups of empty lines as a single word, i.e. the first use
- * would move past the group of lines. The 'b' command would just beep at
- * you. If the lines contained only white-space characters, the 'w' and 'W'
- * commands will just beep at you, and the 'B', 'b', 'E' and 'e' commands
- * will treat the group as a single word, and the 'B' and 'b' commands will
- * treat the lines as individual words. This implementation treats both
- * cases as a single white-space word.
- */
-
-#define FW(test) for (; len && (test); --len, ++p)
-#define BW(test) for (; len && (test); --len, --p)
-
-enum which {BIGWORD, LITTLEWORD};
-
-static int bword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, int));
-static int eword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, int));
-static int fword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, enum which));
-
-/*
- * v_wordw -- [count]w
- * Move forward a word at a time.
- */
-int
-v_wordw(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (fword(sp, ep, vp, fm, rp, LITTLEWORD));
-}
-
-/*
- * v_wordW -- [count]W
- * Move forward a bigword at a time.
- */
-int
-v_wordW(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (fword(sp, ep, vp, fm, rp, BIGWORD));
-}
-
-/*
- * fword --
- * Move forward by words.
- */
-static int
-fword(sp, ep, vp, fm, rp, type)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- enum which type;
-{
- enum { INWORD, NOTWORD } state;
- VCS cs;
- u_long cnt;
-
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
- if (cs_init(sp, ep, &cs))
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * If in white-space:
- * If the count is 1, and it's a change command, we're done.
- * Else, move to the first non-white-space character, which
- * counts as a single word move. If it's a motion command,
- * don't move off the end of the line.
- */
- if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
- if (cs.cs_flags != CS_EMP && cnt == 1) {
- if (F_ISSET(vp, VC_C)) {
- ++cs.cs_cno;
- goto ret3;
- }
- if (F_ISSET(vp, VC_D | VC_Y)) {
- if (cs_fspace(sp, ep, &cs))
- return (1);
- goto ret1;
- }
- }
- if (cs_fblank(sp, ep, &cs))
- return (1);
- --cnt;
- }
-
- /*
- * Cyclically move to the next word -- this involves skipping
- * over word characters and then any trailing non-word characters.
- * Note, for the 'w' command, the definition of a word keeps
- * switching.
- */
- if (type == BIGWORD)
- while (cnt--) {
- for (;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- break;
- }
- /*
- * If a motion command and we're at the end of the
- * last word, we're done. Delete and yank eat any
- * trailing blanks, but we don't move off the end
- * of the line regardless.
- */
- if (cnt == 0 && F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (F_ISSET(vp, VC_D | VC_Y) &&
- cs_fspace(sp, ep, &cs))
- return (1);
- break;
- }
-
- /* Eat whitespace characters. */
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- }
- else
- while (cnt--) {
- state = cs.cs_flags == 0 &&
- inword(cs.cs_ch) ? INWORD : NOTWORD;
- for (;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- break;
- if (state == INWORD) {
- if (!inword(cs.cs_ch))
- break;
- } else
- if (inword(cs.cs_ch))
- break;
- }
- /* See comment above. */
- if (cnt == 0 && F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (F_ISSET(vp, VC_D | VC_Y) &&
- cs_fspace(sp, ep, &cs))
- return (1);
- break;
- }
-
- /* Eat whitespace characters. */
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- }
-
- /*
- * If a motion command, and eating the trailing non-word would
- * move us off this line, don't do it. Move the return cursor
- * to one past the EOL instead.
- */
-ret1: if (F_ISSET(vp, VC_C | VC_D | VC_Y) && cs.cs_flags == CS_EOL)
- ++cs.cs_cno;
-
- /* If we didn't move, we must be at EOF. */
-ret2: if (cs.cs_lno == fm->lno && cs.cs_cno == fm->cno) {
- v_eof(sp, ep, fm);
- return (1);
- }
- /*
- * If at EOF, and it's a motion command, move the return cursor
- * one past the EOF.
- */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) && cs.cs_flags == CS_EOF)
- ++cs.cs_cno;
-ret3: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
- return (0);
-}
-
-/*
- * v_wordb -- [count]b
- * Move backward a word at a time.
- */
-int
-v_wordb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (bword(sp, ep, vp, fm, rp, 0));
-}
-
-/*
- * v_WordB -- [count]B
- * Move backward a bigword at a time.
- */
-int
-v_wordB(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (bword(sp, ep, vp, fm, rp, 1));
-}
-
-/*
- * bword --
- * Move backward by words.
- */
-static int
-bword(sp, ep, vp, fm, rp, spaceonly)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- int spaceonly;
-{
- register char *p;
- recno_t lno;
- size_t len;
- u_long cno, cnt;
- char *startp;
-
- lno = fm->lno;
- cno = fm->cno;
-
- /* Check for start of file. */
- if (lno == 1 && cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
-
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_sof(sp, NULL);
- else
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * Reset the length to the number of characters in the line; the
- * first character is the current cursor position.
- */
- len = cno ? cno + 1 : 0;
- if (len == 0)
- goto line;
- for (startp = p, p += cno; cnt--;) {
- if (spaceonly) {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- --p;
- --len;
- }
- BW(isblank(*p));
- if (len)
- BW(!isblank(*p));
- else
- goto line;
- } else {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- --p;
- --len;
- }
- BW(isblank(*p));
- if (len)
- if (inword(*p))
- BW(inword(*p));
- else
- BW(!isblank(*p) && !inword(*p));
- else
- goto line;
- }
-
- if (cnt && len == 0) {
- /* If we hit SOF, stay there (historic practice). */
-line: if (lno == 1) {
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
-
- /*
- * Get the line. If the line is empty, decrement
- * count and get another one.
- */
- if ((p = file_gline(sp, ep, --lno, &len)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- if (len == 0) {
- if (cnt == 0 || --cnt == 0) {
- rp->lno = lno;
- rp->cno = 0;
- return (0);
- }
- goto line;
- }
-
- /*
- * Set the cursor to the end of the line. If the word
- * at the end of this line has only a single character,
- * we've already skipped over it.
- */
- startp = p;
- if (len) {
- p += len - 1;
- if (cnt && len > 1 && !isblank(p[0]))
- if (inword(p[0])) {
- if (!inword(p[-1]))
- --cnt;
- } else if (!isblank(p[-1]) &&
- !inword(p[-1]))
- --cnt;
- }
- } else {
- ++p;
- ++len;
- }
- }
- rp->lno = lno;
- rp->cno = p - startp;
- return (0);
-}
-
-/*
- * v_worde -- [count]e
- * Move forward to the end of the word.
- */
-int
-v_worde(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (eword(sp, ep, vp, fm, rp, 0));
-}
-
-/*
- * v_wordE -- [count]E
- * Move forward to the end of the bigword.
- */
-int
-v_wordE(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (eword(sp, ep, vp, fm, rp, 1));
-}
-
-/*
- * eword --
- * Move forward to the end of the word.
- */
-static int
-eword(sp, ep, vp, fm, rp, spaceonly)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- int spaceonly;
-{
- register char *p;
- recno_t lno;
- size_t len, llen;
- u_long cno, cnt;
- int empty;
- char *startp;
-
- lno = fm->lno;
- cno = fm->cno;
-
- if ((p = file_gline(sp, ep, lno, &llen)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_eof(sp, ep, NULL);
- else
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * Reset the length; the first character is the current cursor
- * position. If no more characters in this line, may already
- * be at EOF.
- */
- len = llen - cno;
- if (empty = llen == 0 || llen == cno + 1)
- goto line;
-
- for (startp = p += cno; cnt--; empty = 0) {
- if (spaceonly) {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- ++p;
- --len;
- }
- FW(isblank(*p));
- if (len)
- FW(!isblank(*p));
- else
- ++cnt;
- } else {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- ++p;
- --len;
- }
- FW(isblank(*p));
- if (len)
- if (inword(*p))
- FW(inword(*p));
- else
- FW(!isblank(*p) && !inword(*p));
- else
- ++cnt;
- }
-
- if (cnt && len == 0) {
- /* If we hit EOF, stay there (historic practice). */
-line: if ((p = file_gline(sp, ep, ++lno, &llen)) == NULL) {
- /*
- * If already at eof, complain, unless it's
- * a change command or a delete command and
- * there's something to delete.
- */
- if (empty) {
- if (F_ISSET(vp, VC_C) ||
- F_ISSET(vp, VC_D) && llen != 0) {
- rp->lno = lno - 1;
- rp->cno = llen ? llen : 1;
- return (0);
- }
- v_eof(sp, ep, NULL);
- return (1);
- }
- if ((p =
- file_gline(sp, ep, --lno, &llen)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- rp->lno = lno;
- rp->cno = llen ? llen - 1 : 0;
- /* The 'c', 'd' and 'y' need one more space. */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
- return (0);
- }
- len = llen;
- cno = 0;
- startp = p;
- } else {
- --p;
- ++len;
- }
- }
- rp->lno = lno;
- rp->cno = cno + (p - startp);
-
- /* The 'c', 'd' and 'y' need one more space. */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_xchar.c b/usr.bin/vi/nvi/v_xchar.c
deleted file mode 100644
index 019862240f26..000000000000
--- a/usr.bin/vi/nvi/v_xchar.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_xchar.c 8.4 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-#define NODEL(sp) { \
- msgq(sp, M_BERR, "No characters to delete."); \
- return (1); \
-}
-
-/*
- * v_xchar --
- * Deletes the character(s) on which the cursor sits.
- */
-int
-v_xchar(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- MARK m;
- recno_t lno;
- u_long cnt;
- size_t len;
-
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- NODEL(sp);
- GETLINE_ERR(sp, fm->lno);
- return (1);
- }
-
- if (len == 0)
- NODEL(sp);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * Deleting from the cursor toward the end of line, w/o moving the
- * cursor. Note, "2x" at EOL isn't the same as "xx" because the
- * left movement of the cursor as part of the 'x' command isn't
- * taken into account. Historically correct.
- */
- tm->lno = fm->lno;
- if (cnt < len - fm->cno) {
- tm->cno = fm->cno + cnt;
- m = *fm;
- } else {
- tm->cno = len;
- m.lno = fm->lno;
- m.cno = fm->cno ? fm->cno - 1 : 0;
- }
-
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
- if (delete(sp, ep, fm, tm, 0))
- return (1);
-
- *rp = m;
- return (0);
-}
-
-/*
- * v_Xchar --
- * Deletes the character(s) immediately before the current cursor
- * position.
- */
-int
-v_Xchar(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- u_long cnt;
-
- if (fm->cno == 0) {
- msgq(sp, M_BERR, "Already at the left-hand margin.");
- return (1);
- }
-
- *tm = *fm;
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- fm->cno = cnt >= tm->cno ? 0 : tm->cno - cnt;
-
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
- if (delete(sp, ep, fm, tm, 0))
- return (1);
-
- *rp = *fm;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_yank.c b/usr.bin/vi/nvi/v_yank.c
deleted file mode 100644
index 7b2718e647a4..000000000000
--- a/usr.bin/vi/nvi/v_yank.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_yank.c 8.11 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_Yank -- [buffer][count]Y
- * Yank lines of text into a cut buffer.
- */
-int
-v_Yank(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
- if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
-
- sp->rptlines[L_YANKED] += (tm->lno - fm->lno) + 1;
- return (0);
-}
-
-/*
- * v_yank -- [buffer][count]y[count][motion]
- * Yank text (or lines of text) into a cut buffer.
- */
-int
-v_yank(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(vp, VC_LMODE)) {
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
- } else if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
-
- /*
- * !!!
- * Historic vi moved the cursor to the from MARK if it was before the
- * current cursor. This makes no sense. For example, "yj" moves the
- * cursor but "yk" does not. Unfortunately, it's too late to change
- * this now. Matching the historic semantics isn't easy. The line
- * number was always changed and column movement was usually relative.
- * However, "y'a" moved the cursor to the first non-blank of the line
- * marked by a, while "y`a" moved the cursor to the line and column
- * marked by a.
- */
- if (F_ISSET(vp, VC_REVMOVE)) {
- rp->lno = fm->lno;
- if (vp->mkp == &vikeys['\'']) {
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- } else if (vp->mkp == &vikeys['`'])
- rp->cno = fm->cno;
- else
- rp->cno = sp->s_relative(sp, ep, rp->lno);
- }
-
- sp->rptlines[L_YANKED] += (tm->lno - fm->lno) + 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_z.c b/usr.bin/vi/nvi/v_z.c
deleted file mode 100644
index 31937ffc951c..000000000000
--- a/usr.bin/vi/nvi/v_z.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_z.c 8.8 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_z -- [count]z[count][-.+^<CR>]
- * Move the screen.
- */
-int
-v_z(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- recno_t last, lno;
- u_int value;
-
- /*
- * The first count is the line to use. If the value doesn't
- * exist, use the last line.
- */
- if (F_ISSET(vp, VC_C1SET)) {
- lno = vp->count;
- if (file_lline(sp, ep, &last))
- return (1);
- if (lno > last)
- lno = last;
- } else
- lno = fm->lno;
-
- /* Set return cursor values. */
- rp->lno = lno;
- rp->cno = fm->cno;
-
- /*
- * The second count is the displayed window size, i.e. the 'z'
- * command is another way to get artificially small windows.
- *
- * !!!
- * A window size of 0 was historically allowed, and simply ignored.
- * Also, this could be much more simply done by modifying the value
- * of the O_WINDOW option, but that's not how it worked historically.
- */
- if (F_ISSET(vp, VC_C2SET) &&
- vp->count2 != 0 && sp->s_rrel(sp, vp->count2))
- return (1);
-
- switch (vp->character) {
- case '-': /* Put the line at the bottom. */
- if (sp->s_fill(sp, ep, lno, P_BOTTOM))
- return (1);
- break;
- case '.': /* Put the line in the middle. */
- if (sp->s_fill(sp, ep, lno, P_MIDDLE))
- return (1);
- break;
- default: /* Put the line at the top for <cr>. */
- value = term_key_val(sp, vp->character);
- if (value != K_CR && value != K_NL) {
- msgq(sp, M_ERR, "usage: %s.", vp->kp->usage);
- return (1);
- }
- /* FALLTHROUGH */
- case '+': /* Put the line at the top. */
- if (sp->s_fill(sp, ep, lno, P_TOP))
- return (1);
- break;
- case '^': /* Print the screen before the z- screen. */
- /*
- * !!!
- * Historic practice isn't real clear on this one. It seems
- * that the command "70z^" is the same as ":70<cr>z-z^" with
- * an off-by-one difference. So, until I find documentation
- * to the contrary, the z^ command in this implementation
- * displays the screen immediately before the current one.
- * Fill the screen with the selected line at the bottom, then,
- * scroll the screen down a page, and move to the middle line
- * of the screen. Historic vi moved the cursor to some random
- * place in the screen, as far as I can tell.
- */
- if (sp->s_fill(sp, ep, lno, P_BOTTOM))
- return (1);
- if (sp->s_down(sp, ep, rp, sp->t_maxrows - 1, 1))
- return (1);
- if (sp->s_position(sp, ep, rp, 0, P_MIDDLE))
- return (1);
- break;
- }
-
- /* If the map changes, have to redraw the entire screen. */
- F_SET(sp, S_REDRAW);
-
- return (0);
-}
diff --git a/usr.bin/vi/nvi/vcmd.c b/usr.bin/vi/nvi/vcmd.c
deleted file mode 100644
index d7f1caf81d0c..000000000000
--- a/usr.bin/vi/nvi/vcmd.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)vcmd.c 8.22 (Berkeley) 1/8/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * This array maps keystrokes to vi command functions. It is known
- * in ex/ex_usage.c that it takes four columns to name a vi character.
- */
-VIKEYS const vikeys [MAXVIKEY + 1] = {
-/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */
- {NULL},
-/* 001 ^A */
- {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|V_RCM_SET,
- "[count]^A",
- "^A search forward for cursor word"},
-/* 002 ^B */
- {v_pageup, V_ABS|V_CNT|V_RCM_SETLFNB,
- "[count]^B",
- "^B page up by screens"},
-/* 003 ^C */
- {NULL, 0,
- "^C",
- "^C interrupt a search or global command"},
-/* 004 ^D */
- {v_hpagedown, V_ABS|V_CNT|V_RCM_SETLFNB,
- "[count]^D",
- "^D page down by half screens (setting count)"},
-/* 005 ^E */
- {v_linedown, V_CNT,
- "[count]^E",
- "^E page down by lines"},
-/* 006 ^F */
- {v_pagedown, V_ABS|V_CNT|V_RCM_SETLFNB,
- "[count]^F",
- "^F page down by screens"},
-/* 007 ^G */
- {v_status, 0,
- "^G",
- "^G file status"},
-/* 010 ^H */
- {v_left, V_CNT|V_MOVE|V_RCM_SET,
- "[count]^H",
- "^H move left by columns"},
-/* 011 ^I */
- {NULL},
-/* 012 ^J */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
- "[count]^J",
- "^J move down by lines"},
-/* 013 ^K */
- {NULL},
-/* 014 ^L */
- {v_redraw, 0,
- "^L",
- "^L redraw screen"},
-/* 015 ^M */
- {v_cr, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
- "[count]^M",
- "^M move down by lines (to first non-blank)"},
-/* 016 ^N */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
- "[count]^N",
- "^N move down by lines"},
-/* 017 ^O */
- {NULL},
-/* 020 ^P */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM,
- "[count]^P",
- "^P move up by lines"},
-/* 021 ^Q -- not available, used for hardware flow control. */
- {NULL},
-/* 022 ^R */
- {v_redraw, 0,
- "^R",
- "^R redraw screen"},
-/* 023 ^S -- not available, used for hardware flow control. */
- {NULL},
-/* 024 ^T */
- {v_tagpop, V_RCM_SET,
- "^T",
- "^T tag pop"},
-/* 025 ^U */
- {v_hpageup, V_ABS|V_CNT|V_RCM_SETLFNB,
- "[count]^U",
- "^U half page up (set count)"},
-/* 026 ^V */
- {NULL, 0,
- "^V",
- "^V input a literal character"},
-/* 027 ^W */
- {v_screen, 0,
- "^W",
- "^W move to next screen"},
-/* 030 ^X */
- {NULL},
-/* 031 ^Y */
- {v_lineup, V_CNT,
- "[count]^Y",
- "^Y page up by lines"},
-/* 032 ^Z */
- {v_stop, 0,
- "^Z",
- "^Z suspend editor"},
-/* 033 ^[ */
- {NULL, 0,
- "^[ <escape>",
- "^[ <escape> leave input mode, return to command mode"},
-/* 034 ^\ */
- {NULL},
-/* 035 ^] */
- {v_tagpush, V_KEYW|V_RCM_SET,
- "^]",
- "^] tag push cursor word"},
-/* 036 ^^ */
- {v_switch, 0,
- "^^",
- "^^ switch to previous file"},
-/* 037 ^_ */
- {NULL},
-/* 040 ' ' */
- {v_right, V_CNT|V_MOVE|V_RCM_SET,
- "[count]' '",
- " <space> move right by columns"},
-/* 041 ! */
- {v_filter, V_CNT|V_DOT|V_MOTION|V_RCM_SET,
- "[count]![count]motion command(s)",
- " ! filter through command(s) to motion"},
-/* 042 " */
- {NULL},
-/* 043 # */
- {v_increment, V_CHAR|V_CNT|V_DOT|V_KEYNUM|V_RCM_SET,
- "[count]#[#+-]",
- " # number increment/decrement"},
-/* 044 $ */
- {v_dollar, V_CNT|V_MOVE|V_RCM_SETLAST,
- " [count]$",
- " $ move to last column"},
-/* 045 % */
- {v_match, V_ABS|V_MOVE|V_RCM_SET,
- "%",
- " % move to match"},
-/* 046 & */
- {v_again, 0,
- "&",
- " & repeat substitution"},
-/* 047 ' */
- {v_gomark, V_ABS|V_CHAR|V_LMODE|V_MOVE|V_RCM_SETFNB,
- "'['a-z]",
- " ' move to mark (to first non-blank)"},
-/* 050 ( */
- {v_sentenceb, V_CNT|V_MOVE|V_RCM_SET,
- "[count](",
- " ( move back sentence"},
-/* 051 ) */
- {v_sentencef, V_ABS|V_CNT|V_MOVE|V_RCM_SET,
- "[count])",
- " ) move forward sentence"},
-/* 052 * */
- {NULL},
-/* 053 + */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
- "[count]+",
- " + move down by lines (to first non-blank)"},
-/* 054 , */
- {v_chrrepeat, V_CNT|V_MOVE|V_RCM_SET,
- "[count],",
- " , reverse last F, f, T or t search"},
-/* 055 - */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
- "[count]-",
- " - move up by lines (to first non-blank)"},
-/* 056 . */
- {NULL, 0,
- ".",
- " . repeat the last command"},
-/* 057 / */
- {v_searchf, V_ABS|V_MOVE|V_RCM_SET,
- "/RE[/ offset]",
- " / search forward"},
-/* 060 0 */
- {v_zero, V_MOVE|V_RCM_SET,
- "0",
- " 0 move to first character"},
-/* 061 1 */
- {NULL},
-/* 062 2 */
- {NULL},
-/* 063 3 */
- {NULL},
-/* 064 4 */
- {NULL},
-/* 065 5 */
- {NULL},
-/* 066 6 */
- {NULL},
-/* 067 7 */
- {NULL},
-/* 070 8 */
- {NULL},
-/* 071 9 */
- {NULL},
-/* 072 : */
- {v_ex, 0,
- ":command [| command] ...",
- " : ex command"},
-/* 073 ; */
- {v_chrepeat, V_CNT|V_MOVE|V_RCM_SET,
- "[count];",
- " ; repeat last F, f, T or t search"},
-/* 074 < */
- {v_shiftl, V_CNT|V_DOT|V_MOTION|V_RCM_SET|VC_SH,
- "[count]<[count]motion",
- " < shift lines left to motion"},
-/* 075 = */
- {NULL},
-/* 076 > */
- {v_shiftr, V_CNT|V_DOT|V_MOTION|V_RCM_SET|VC_SH,
- "[count]>[count]motion",
- " > shift lines right to motion"},
-/* 077 ? */
- {v_searchb, V_ABS|V_MOVE|V_RCM_SET,
- "?RE[? offset]",
- " ? search backward"},
-/* 100 @ */
- {v_at, V_RBUF|V_RCM_SET,
- "@buffer",
- " @ execute buffer"},
-/* 101 A */
- {v_iA, V_CNT|V_DOT|V_RCM_SET,
- "[count]A",
- " A append to the line"},
-/* 102 B */
- {v_wordB, V_CNT|V_MOVE|V_RCM_SET,
- "[count]B",
- " B move back bigword"},
-/* 103 C */
- {v_Change, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer][count]C",
- " C change to end-of-line"},
-/* 104 D */
- {v_Delete, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer][count]D",
- " D delete to end-of-line"},
-/* 105 E */
- {v_wordE, V_CNT|V_MOVE|V_RCM_SET,
- "[count]E",
- " E move to end of bigword"},
-/* 106 F */
- {v_chF, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
- "[count]F character",
- " F character in line backward search"},
-/* 107 G */
- {v_lgoto, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
- "[count]G",
- " G move to line"},
-/* 110 H */
- {v_home, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
- "[count]H",
- " H move to count lines from screen top"},
-/* 111 I */
- {v_iI, V_CNT|V_DOT|V_RCM_SET,
- "[count]I",
- " I insert at line beginning"},
-/* 112 J */
- {v_join, V_CNT|V_DOT|V_RCM_SET,
- "[count]J",
- " J join lines"},
-/* 113 K */
- {NULL},
-/* 114 L */
- {v_bottom, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
- "[count]L",
- " L move to screen bottom"},
-/* 115 M */
- {v_middle, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
- "M",
- " M move to screen middle"},
-/* 116 N */
- {v_searchN, V_ABS|V_MOVE|V_RCM_SET,
- "n",
- " N reverse last search"},
-/* 117 O */
- {v_iO, V_CNT|V_DOT|V_RCM_SET,
- "[count]O",
- " O insert above line"},
-/* 120 P */
- {v_Put, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer]P",
- " P insert before cursor from buffer"},
-/* 121 Q */
- {v_exmode, 0,
- "Q",
- " Q switch to ex mode"},
-/* 122 R */
- {v_Replace, V_CNT|V_DOT|V_RCM_SET,
- "[count]R",
- " R replace characters"},
-/* 123 S */
- {v_Subst, V_CNT|V_DOT|V_LMODE|V_OBUF|V_RCM_SET,
- "[buffer][count]S",
- " S substitute for the line(s)"},
-/* 124 T */
- {v_chT, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
- "[count]T character",
- " T before character in line backward search"},
-/* 125 U */
- {v_Undo, V_RCM_SET,
- "U",
- " U Restore the current line"},
-/* 126 V */
- {NULL},
-/* 127 W */
- {v_wordW, V_CNT|V_MOVE|V_RCM_SET,
- "[count]W",
- " W move to next bigword"},
-/* 130 X */
- {v_Xchar, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer][count]X",
- " X delete character before cursor"},
-/* 131 Y */
- {v_Yank, V_CNT|V_LMODE|V_OBUF,
- "[buffer][count]Y",
- " Y copy line"},
-/* 132 Z */
- {v_exit, 0,
- "ZZ",
- "ZZ save file and exit"},
-/* 133 [ */
- {v_sectionb, V_ABS|V_LMODE|V_MOVE|V_RCM_SET,
- "[[",
- "[[ move back section"},
-/* 134 \ */
- {NULL},
-/* 135 ] */
- {v_sectionf, V_ABS|V_LMODE|V_MOVE|V_RCM_SET,
- "]]",
- "]] move forward section"},
-/* 136 ^ */
- /*
- * DON'T set the V_RCM_SETFNB flag, the function has to do
- * the work anyway, in case it's a motion component. DO set
- * V_RCM_SET, so that any motion that's part of a command is
- * preserved.
- */
- {v_first, V_CNT|V_MOVE|V_RCM_SET,
- "^",
- " ^ move to first non-blank"},
-/* 137 _ */
- /*
- * DON'T set the V_RCM_SETFNB flag, the function has to do
- * the work anyway, in case it's a motion component. DO set
- * V_RCM_SET, so that any motion that's part of a command is
- * preserved.
- */
- {v_cfirst, V_CNT|V_MOVE|V_RCM_SET,
- "_",
- " _ move to first non-blank"},
-/* 140 ` */
- {v_gomark, V_ABS|V_CHAR|V_MOVE|V_RCM_SET,
- "`[`a-z]",
- " ` move to mark"},
-/* 141 a */
- {v_ia, V_CNT|V_DOT|V_RCM_SET,
- "[count]a",
- " a append after cursor"},
-/* 142 b */
- {v_wordb, V_CNT|V_MOVE|V_RCM_SET,
- "[count]b",
- " b move back word"},
-/* 143 c */
- {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|V_RCM_SET|VC_C,
- "[buffer][count]c[count]motion",
- " c change to motion"},
-/* 144 d */
- {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|V_RCM_SET|VC_D,
- "[buffer][count]d[count]motion",
- " d delete to motion"},
-/* 145 e */
- {v_worde, V_CNT|V_MOVE|V_RCM_SET,
- "[count]e",
- " e move to end of word"},
-/* 146 f */
- {v_chf, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
- "[count]f character",
- " f character in line forward search"},
-/* 147 g */
- {NULL},
-/* 150 h */
- {v_left, V_CNT|V_MOVE|V_RCM_SET,
- "[count]h",
- " h move left by columns"},
-/* 151 i */
- {v_ii, V_CNT|V_DOT|V_RCM_SET,
- "[count]i",
- " i insert before cursor"},
-/* 152 j */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
- "[count]j",
- " j move down by lines"},
-/* 153 k */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM,
- "[count]k",
- " k move up by lines"},
-/* 154 l */
- {v_right, V_CNT|V_MOVE|V_RCM_SET,
- "[count]l",
- " l move right by columns"},
-/* 155 m */
- {v_mark, V_CHAR,
- "m[a-z]",
- " m set mark"},
-/* 156 n */
- {v_searchn, V_ABS|V_MOVE|V_RCM_SET,
- "n",
- " n repeat last search"},
-/* 157 o */
- {v_io, V_CNT|V_DOT|V_RCM_SET,
- "[count]o",
- " o append after line"},
-/* 160 p */
- {v_put, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer]p",
- " p insert after cursor from buffer"},
-/* 161 q */
- {NULL},
-/* 162 r */
- {v_replace, V_CNT|V_DOT|V_RCM_SET,
- "[count]r character",
- " r replace character"},
-/* 163 s */
- {v_subst, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer][count]s",
- " s substitute character"},
-/* 164 t */
- {v_cht, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
- "[count]t character",
- " t before character in line forward search"},
-/* 165 u */
- /*
- * DON'T set the V_DOT flag, it' more complicated than that.
- * See vi/vi.c for details.
- */
- {v_undo, V_RCM_SET,
- "u",
- " u undo last change"},
-/* 166 v */
- {NULL},
-/* 167 w */
- {v_wordw, V_CNT|V_MOVE|V_RCM_SET,
- "[count]w",
- " w move to next word"},
-/* 170 x */
- {v_xchar, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
- "[buffer][count]x",
- " x delete character"},
-/* 171 y */
- {v_yank, V_CNT|V_MOTION|V_OBUF|V_RCM_SET|VC_Y,
- "[buffer][count]y[count]motion",
- " y copy text to motion into a cut buffer"},
-/* 172 z */
- /*
- * DON'T set the V_CHAR flag, the char isn't required,
- * so it's handled specially in getcmd().
- */
- {v_z, V_CNT|V_RCM_SETFNB,
- "[line]z[window_size][-|.|+|^|<CR>]",
- " z redraw window"},
-/* 173 { */
- {v_paragraphb, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SET,
- "[count]{",
- " { move back paragraph"},
-/* 174 | */
- {v_ncol, V_ABS|V_CNT|V_MOVE|V_RCM_SET,
- "[count]|",
- " | move to column"},
-/* 175 } */
- {v_paragraphf, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SET,
- "[count]}",
- " } move forward paragraph"},
-/* 176 ~ */
- {v_ulcase, V_CNT|V_DOT|V_RCM_SET,
- "[count]~",
- " ~ reverse case"},
-};
diff --git a/usr.bin/vi/nvi/vcmd.h b/usr.bin/vi/nvi/vcmd.h
deleted file mode 100644
index d48fa26acf5e..000000000000
--- a/usr.bin/vi/nvi/vcmd.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- *
- * @(#)vcmd.h 8.23 (Berkeley) 1/8/94
- */
-
-typedef struct _vikeys VIKEYS;
-
-/* Structure passed around to functions implementing vi commands. */
-typedef struct _vicmdarg {
-#define vp_startzero buffer /* START ZERO OUT. */
- CHAR_T buffer; /* Buffer. */
- CHAR_T character; /* Character. */
- u_long count; /* Count. */
- u_long count2; /* Second count (only used by z). */
- int key; /* Command key. */
- VIKEYS const *kp; /* VIKEYS key. */
- VIKEYS const *mkp; /* VIKEYS motion key. */
- size_t klen; /* Keyword length. */
-
-/*
- * Historic vi allowed "dl" when the cursor was on the last column, deleting
- * the last character, and similarly allowed "dw" when the cursor was on the
- * last column of the file. It didn't allow "dh" when the cursor was on
- * column 1, although these cases are not strictly analogous. The point is
- * that some movements would succeed if they were associated with a motion
- * command, and fail otherwise. This is part of the off-by-1 schizophrenia
- * that plagued vi. Other examples are that "dfb" deleted everything up to
- * and including the next 'b' character, but "d/b" only deleted everything
- * up to the next 'b' character. While this implementation regularizes the
- * interface to the extent possible, there are many special cases that can't
- * be fixed. This is implemented by setting special flags per command so that
- * the motion routines know what's really going on.
- *
- * Note, the VC_COMMASK flags are set in the vikeys array, and therefore
- * must have values not used in the set of flags declared in the VIKEYS
- * structure below.
- */
-#define VC_C 0x0001 /* The 'c' command. */
-#define VC_D 0x0002 /* The 'd' command. */
-#define VC_SH 0x0004 /* The '>' command. */
-#define VC_Y 0x0008 /* The 'y' command. */
-#define VC_COMMASK 0x000f /* Mask for special flags. */
-
-#define VC_BUFFER 0x0010 /* Buffer set. */
-#define VC_C1SET 0x0020 /* Count 1 set. */
-#define VC_C1RESET 0x0040 /* Reset the C1SET flag for dot commands. */
-#define VC_C2SET 0x0080 /* Count 2 set. */
-#define VC_LMODE 0x0100 /* Motion is line oriented. */
-#define VC_ISDOT 0x0200 /* Command was the dot command. */
-#define VC_REVMOVE 0x0400 /* Movement was before the cursor. */
-
- u_int flags;
-
-#define vp_endzero keyword /* END ZERO OUT. */
- char *keyword; /* Keyword. */
- size_t kbuflen; /* Keyword buffer length. */
-} VICMDARG;
-
-/* Vi command structure. */
-struct _vikeys { /* Underlying function. */
- int (*func) __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *));
-
-#define V_DONTUSE1 0x000001 /* VC_C */
-#define V_DONTUSE2 0x000002 /* VC_D */
-#define V_DONTUSE3 0x000004 /* VC_SH */
-#define V_DONTUSE4 0x000008 /* VC_Y */
-#define V_ABS 0x000010 /* Absolute movement, set '' mark. */
-#define V_CHAR 0x000020 /* Character (required, trailing). */
-#define V_CNT 0x000040 /* Count (optional, leading). */
-#define V_DOT 0x000080 /* On success, sets dot command. */
-#define V_KEYNUM 0x000100 /* Cursor referenced number. */
-#define V_KEYW 0x000200 /* Cursor referenced word. */
-#define V_LMODE 0x000400 /* Motion is line oriented. */
-#define V_MOTION 0x000800 /* Motion (required, trailing). */
-#define V_MOVE 0x001000 /* Command defines movement. */
-#define V_OBUF 0x002000 /* Buffer (optional, leading). */
-#define V_RBUF 0x004000 /* Buffer (required, trailing). */
-#define V_RCM 0x008000 /* Use relative cursor movment (RCM). */
-#define V_RCM_SET 0x010000 /* RCM: set to current position. */
-#define V_RCM_SETFNB 0x020000 /* RCM: set to first non-blank (FNB). */
-#define V_RCM_SETLAST 0x040000 /* RCM: set to last character. */
-#define V_RCM_SETLFNB 0x080000 /* RCM: set to FNB if line moved. */
-#define V_RCM_SETNNB 0x100000 /* RCM: set to next non-blank. */
- u_long flags;
- char *usage; /* Usage line. */
- char *help; /* Help line. */
-};
-#define MAXVIKEY 126 /* List of vi commands. */
-extern VIKEYS const vikeys[MAXVIKEY + 1];
-
-/* Definition of a "word". */
-#define inword(ch) (isalnum(ch) || (ch) == '_')
-
-/* Character stream structure, prototypes. */
-typedef struct _vcs {
- recno_t cs_lno; /* Line. */
- size_t cs_cno; /* Column. */
- char *cs_bp; /* Buffer. */
- size_t cs_len; /* Length. */
- int cs_ch; /* Character. */
-#define CS_EMP 1 /* Empty line. */
-#define CS_EOF 2 /* End-of-file. */
-#define CS_EOL 3 /* End-of-line. */
-#define CS_SOF 4 /* Start-of-file. */
- int cs_flags; /* Return flags. */
-} VCS;
-
-int cs_bblank __P((SCR *, EXF *, VCS *));
-int cs_fblank __P((SCR *, EXF *, VCS *));
-int cs_fspace __P((SCR *, EXF *, VCS *));
-int cs_init __P((SCR *, EXF *, VCS *));
-int cs_next __P((SCR *, EXF *, VCS *));
-int cs_prev __P((SCR *, EXF *, VCS *));
-
-/* Vi private, per-screen memory. */
-typedef struct _vi_private {
- VICMDARG sdot; /* Saved dot, motion command. */
- VICMDARG sdotmotion;
-
- CHAR_T rlast; /* Last 'r' command character. */
-
- char *rep; /* Input replay buffer. */
- size_t rep_len; /* Input replay buffer length. */
- size_t rep_cnt; /* Input replay buffer characters. */
-
- CHAR_T inc_lastch; /* Last increment character. */
- long inc_lastval; /* Last increment value. */
-
- char *paragraph; /* Paragraph search list. */
- size_t paragraph_len; /* Paragraph search list length. */
-
- u_long u_ccnt; /* Undo command count. */
-} VI_PRIVATE;
-
-#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private))
-
-/* Vi function prototypes. */
-int txt_auto __P((SCR *, EXF *, recno_t, TEXT *, size_t, TEXT *));
-int v_buildparagraph __P((SCR *));
-int v_end __P((SCR *));
-void v_eof __P((SCR *, EXF *, MARK *));
-void v_eol __P((SCR *, EXF *, MARK *));
-int v_exwrite __P((void *, const char *, int));
-int v_init __P((SCR *, EXF *));
-int v_isempty __P((char *, size_t));
-int v_msgflush __P((SCR *));
-int v_ntext __P((SCR *, EXF *, TEXTH *, MARK *,
- const char *, const size_t, MARK *, int, recno_t, u_int));
-int v_optchange __P((SCR *, int));
-int v_screen_copy __P((SCR *, SCR *));
-int v_screen_end __P((SCR *));
-void v_sof __P((SCR *, MARK *));
-int vi __P((SCR *, EXF *));
-
-#define VIPROTO(type, name) \
- type name __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *))
-
-VIPROTO(int, v_again);
-VIPROTO(int, v_at);
-VIPROTO(int, v_bottom);
-VIPROTO(int, v_cfirst);
-VIPROTO(int, v_Change);
-VIPROTO(int, v_change);
-VIPROTO(int, v_chF);
-VIPROTO(int, v_chf);
-VIPROTO(int, v_chrepeat);
-VIPROTO(int, v_chrrepeat);
-VIPROTO(int, v_chT);
-VIPROTO(int, v_cht);
-VIPROTO(int, v_cr);
-VIPROTO(int, v_Delete);
-VIPROTO(int, v_delete);
-VIPROTO(int, v_dollar);
-VIPROTO(int, v_down);
-VIPROTO(int, v_ex);
-VIPROTO(int, v_exit);
-VIPROTO(int, v_exmode);
-VIPROTO(int, v_filter);
-VIPROTO(int, v_first);
-VIPROTO(int, v_gomark);
-VIPROTO(int, v_home);
-VIPROTO(int, v_hpagedown);
-VIPROTO(int, v_hpageup);
-VIPROTO(int, v_iA);
-VIPROTO(int, v_ia);
-VIPROTO(int, v_iI);
-VIPROTO(int, v_ii);
-VIPROTO(int, v_increment);
-VIPROTO(int, v_iO);
-VIPROTO(int, v_io);
-VIPROTO(int, v_join);
-VIPROTO(int, v_left);
-VIPROTO(int, v_lgoto);
-VIPROTO(int, v_linedown);
-VIPROTO(int, v_lineup);
-VIPROTO(int, v_mark);
-VIPROTO(int, v_match);
-VIPROTO(int, v_middle);
-VIPROTO(int, v_ncol);
-VIPROTO(int, v_pagedown);
-VIPROTO(int, v_pageup);
-VIPROTO(int, v_paragraphb);
-VIPROTO(int, v_paragraphf);
-VIPROTO(int, v_Put);
-VIPROTO(int, v_put);
-VIPROTO(int, v_redraw);
-VIPROTO(int, v_Replace);
-VIPROTO(int, v_replace);
-VIPROTO(int, v_right);
-VIPROTO(int, v_screen);
-VIPROTO(int, v_searchb);
-VIPROTO(int, v_searchf);
-VIPROTO(int, v_searchN);
-VIPROTO(int, v_searchn);
-VIPROTO(int, v_searchw);
-VIPROTO(int, v_sectionb);
-VIPROTO(int, v_sectionf);
-VIPROTO(int, v_sentenceb);
-VIPROTO(int, v_sentencef);
-VIPROTO(int, v_shiftl);
-VIPROTO(int, v_shiftr);
-VIPROTO(int, v_status);
-VIPROTO(int, v_stop);
-VIPROTO(int, v_Subst);
-VIPROTO(int, v_subst);
-VIPROTO(int, v_switch);
-VIPROTO(int, v_tagpop);
-VIPROTO(int, v_tagpush);
-VIPROTO(int, v_ulcase);
-VIPROTO(int, v_Undo);
-VIPROTO(int, v_undo);
-VIPROTO(int, v_up);
-VIPROTO(int, v_wordB);
-VIPROTO(int, v_wordb);
-VIPROTO(int, v_wordE);
-VIPROTO(int, v_worde);
-VIPROTO(int, v_wordW);
-VIPROTO(int, v_wordw);
-VIPROTO(int, v_Xchar);
-VIPROTO(int, v_xchar);
-VIPROTO(int, v_Yank);
-VIPROTO(int, v_yank);
-VIPROTO(int, v_z);
-VIPROTO(int, v_zero);
diff --git a/usr.bin/vi/nvi/vi.c b/usr.bin/vi/nvi/vi.c
deleted file mode 100644
index f969d78cfabf..000000000000
--- a/usr.bin/vi/nvi/vi.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)vi.c 8.45 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-static int getcmd __P((SCR *, EXF *,
- VICMDARG *, VICMDARG *, VICMDARG *, int *));
-static inline int
- getcount __P((SCR *, ARG_CHAR_T, u_long *));
-static inline int
- getkey __P((SCR *, CH *, u_int));
-static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int));
-static int getmotion __P((SCR *, EXF *,
- VICMDARG *, VICMDARG *, MARK *, MARK *));
-
-/*
- * Side-effect:
- * The dot structure can be set by the underlying vi functions,
- * see v_Put() and v_put().
- */
-#define DOT (&VIP(sp)->sdot)
-#define DOTMOTION (&VIP(sp)->sdotmotion)
-
-/*
- * vi --
- * Main vi command loop.
- */
-int
-vi(sp, ep)
- SCR *sp;
- EXF *ep;
-{
- MARK abs, fm, tm, m;
- VICMDARG cmd, *vp;
- u_int flags, saved_mode;
- int comcount, eval;
-
- /* Start vi. */
- if (v_init(sp, ep))
- return (1);
-
- /* Paint the screen. */
- if (sp->s_refresh(sp, ep)) {
- (void)v_end(sp);
- return (1);
- }
-
- /* Command initialization. */
- memset(&cmd, 0, sizeof(VICMDARG));
-
- for (eval = 0, vp = &cmd;;) {
- if (!MAPPED_KEYS_WAITING(sp) && log_cursor(sp, ep))
- goto err;
-
- /*
- * We get a command, which may or may not have an associated
- * motion. If it does, we get it too, calling its underlying
- * function to get the resulting mark. We then call the
- * command setting the cursor to the resulting mark.
- */
- if (getcmd(sp, ep, DOT, vp, NULL, &comcount))
- goto err;
-
- /*
- * Historical practice: if a dot command gets a new count,
- * any motion component goes away, i.e. "d3w2." deletes a
- * total of 5 words.
- */
- if (F_ISSET(vp, VC_ISDOT) && comcount)
- DOTMOTION->count = 1;
-
- /* Get any associated keyword. */
- flags = vp->kp->flags;
- if (LF_ISSET(V_KEYNUM | V_KEYW) &&
- getkeyword(sp, ep, vp, flags))
- goto err;
-
- /* If a non-relative movement, copy the future absolute mark. */
- if (LF_ISSET(V_ABS)) {
- abs.lno = sp->lno;
- abs.cno = sp->cno;
- }
-
- /*
- * Do any required motion; getmotion sets the from MARK
- * and the line mode flag.
- */
- if (LF_ISSET(V_MOTION)) {
- if (getmotion(sp, ep, DOTMOTION, vp, &fm, &tm))
- goto err;
- } else {
- /*
- * Set everything to the current cursor position.
- * Line commands (ex: Y) default to the current line.
- */
- tm.lno = fm.lno = sp->lno;
- tm.cno = fm.cno = sp->cno;
-
- /*
- * Set line mode flag, for example, "yy".
- *
- * If a count is set, we set the to MARK here relative
- * to the cursor/from MARK. This is done for commands
- * that take both counts and motions, i.e. "4yy" and
- * "y%" -- there's no way the command can known which
- * the user did, so we have to do it here. There are
- * other commands that are line mode commands and take
- * counts ("#G", "#H") and for which this calculation
- * is either meaningless or wrong. Each command must
- * do its own validity checking of the value.
- */
- if (F_ISSET(vp->kp, V_LMODE)) {
- F_SET(vp, VC_LMODE);
- if (F_ISSET(vp, VC_C1SET)) {
- tm.lno = sp->lno + vp->count - 1;
- tm.cno = sp->cno;
- }
- }
- }
-
- /* Increment the command count. */
- ++sp->ccnt;
-
- /*
- * Call the function. Set the return cursor to the current
- * cursor position first -- the underlying routines don't
- * bother to do the work if it doesn't move.
- */
- m.lno = sp->lno;
- m.cno = sp->cno;
- saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
- if ((vp->kp->func)(sp, ep, vp, &fm, &tm, &m))
- goto err;
-#ifdef DEBUG
- /* Make sure no function left the temporary space locked. */
- if (F_ISSET(sp->gp, G_TMP_INUSE)) {
- msgq(sp, M_ERR,
- "Error: vi: temporary buffer not released.");
- return (1);
- }
-#endif
- /*
- * If that command took us out of vi or changed the screen,
- * then exit the loop without further action.
- */
- if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
- break;
-
- /* Set the absolute mark. */
- if (LF_ISSET(V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))
- goto err;
-
- /* Set the dot command structure. */
- if (LF_ISSET(V_DOT)) {
- *DOT = cmd;
- F_SET(DOT, VC_ISDOT);
- /*
- * If a count was supplied for both the command and
- * its motion, the count was used only for the motion.
- * Turn the count back on for the dot structure.
- */
- if (F_ISSET(vp, VC_C1RESET))
- F_SET(DOT, VC_C1SET);
- }
-
- /*
- * Some vi row movements are "attracted" to the last position
- * set, i.e. the V_RCM commands are moths to the V_RCM_SET
- * commands' candle. It's broken into two parts. Here we deal
- * with the command flags. In sp->relative(), we deal with the
- * screen flags. If the movement is to the EOL the vi command
- * handles it. If it's to the beginning, we handle it here.
- *
- * Note, some commands (e.g. _, ^) don't set the V_RCM_SETFNB
- * flag, but do the work themselves. The reason is that they
- * have to modify the column in case they're being used as a
- * motion component. Other similar commands (e.g. +, -) don't
- * have to modify the column because they are always line mode
- * operations when used as motions, so the column number isn't
- * of any interest.
- *
- * Does this totally violate the screen and editor layering?
- * You betcha. As they say, if you think you understand it,
- * you don't.
- */
- switch (LF_ISSET(V_RCM | V_RCM_SETFNB |
- V_RCM_SETLAST | V_RCM_SETLFNB | V_RCM_SETNNB)) {
- case 0:
- break;
- case V_RCM:
- m.cno = sp->s_relative(sp, ep, m.lno);
- break;
- case V_RCM_SETLAST:
- sp->rcmflags = RCM_LAST;
- break;
- case V_RCM_SETLFNB:
- if (fm.lno != m.lno) {
- if (nonblank(sp, ep, m.lno, &m.cno))
- goto err;
- sp->rcmflags = RCM_FNB;
- }
- break;
- case V_RCM_SETFNB:
- m.cno = 0;
- /* FALLTHROUGH */
- case V_RCM_SETNNB:
- if (nonblank(sp, ep, m.lno, &m.cno))
- goto err;
- sp->rcmflags = RCM_FNB;
- break;
- default:
- abort();
- }
-
- /* Update the cursor. */
- sp->lno = m.lno;
- sp->cno = m.cno;
-
- if (!MAPPED_KEYS_WAITING(sp)) {
- (void)msg_rpt(sp, 1);
-
- if (0)
-err: term_map_flush(sp, "Vi error");
- }
-
- /* Refresh the screen. */
- if (sp->s_refresh(sp, ep)) {
- eval = 1;
- break;
- }
-
- /* Set the new favorite position. */
- if (LF_ISSET(V_RCM_SET)) {
- sp->rcmflags = 0;
- (void)sp->s_column(sp, ep, &sp->rcm);
- }
- }
-
- return (v_end(sp) || eval);
-}
-
-#define KEY(key, map) { \
- if (getkey(sp, &ikey, map)) \
- return (1); \
- key = ikey.ch; \
-}
-
-/*
- * getcmd --
- *
- * The command structure for vi is less complex than ex (and don't think
- * I'm not grateful!) The command syntax is:
- *
- * [count] [buffer] [count] key [[motion] | [buffer] [character]]
- *
- * and there are several special cases. The motion value is itself a vi
- * command, with the syntax:
- *
- * [count] key [character]
- */
-static int
-getcmd(sp, ep, dp, vp, ismotion, comcountp)
- SCR *sp;
- EXF *ep;
- VICMDARG *dp, *vp;
- VICMDARG *ismotion; /* Previous key if getting motion component. */
- int *comcountp;
-{
- VIKEYS const *kp;
- u_int flags;
- CH ikey;
- CHAR_T key;
-
- /* Refresh the command structure. */
- memset(&vp->vp_startzero, 0,
- (char *)&vp->vp_endzero - (char *)&vp->vp_startzero);
-
- /* An escape bells the user if in command mode. */
- if (getkey(sp, &ikey, TXT_MAPCOMMAND)) {
- if (ikey.value == K_ESCAPE && ismotion == NULL)
- msgq(sp, M_BERR, "Already in command mode");
- return (1);
- }
-
- key = ikey.ch;
- if (key > MAXVIKEY) {
- msgq(sp, M_BERR, "%s isn't a vi command", charname(sp, key));
- return (1);
- }
-
- /* Pick up optional buffer. */
- if (key == '"') {
- KEY(vp->buffer, 0);
- F_SET(vp, VC_BUFFER);
- KEY(key, TXT_MAPCOMMAND);
- }
-
- /*
- * Pick up optional count, where a leading 0 is not a count,
- * it's a command.
- */
- if (isdigit(key) && key != '0') {
- if (getcount(sp, key, &vp->count))
- return (1);
- F_SET(vp, VC_C1SET);
- *comcountp = 1;
- KEY(key, TXT_MAPCOMMAND);
- } else
- *comcountp = 0;
-
- /* Pick up optional buffer. */
- if (key == '"') {
- if (F_ISSET(vp, VC_BUFFER)) {
- msgq(sp, M_ERR, "Only one buffer can be specified.");
- return (1);
- }
- KEY(vp->buffer, 0);
- F_SET(vp, VC_BUFFER);
- KEY(key, TXT_MAPCOMMAND);
- }
-
- /*
- * Find the command. The only legal command with no underlying
- * function is dot.
- */
- kp = vp->kp = &vikeys[vp->key = key];
- if (kp->func == NULL) {
- if (key != '.') {
- msgq(sp, M_ERR,
- "%s isn't a command", charname(sp, key));
- return (1);
- }
-
- /* If called for a motion command, stop now. */
- if (dp == NULL)
- goto usage;
-
- /* A repeatable command must have been executed. */
- if (!F_ISSET(dp, VC_ISDOT)) {
- msgq(sp, M_ERR, "No command to repeat.");
- return (1);
- }
-
- /*
- * !!!
- * If a '.' is immediately entered after an undo command, we
- * replay the log instead of redoing the last command. This
- * is necessary because 'u' can't set the dot command -- see
- * vi/v_undo.c:v_undo for details.
- */
- if (VIP(sp)->u_ccnt == sp->ccnt) {
- vp->kp = &vikeys['u'];
- F_SET(vp, VC_ISDOT);
- return (0);
- }
-
- /* Set new count/buffer, if any, and return. */
- if (F_ISSET(vp, VC_C1SET)) {
- F_SET(dp, VC_C1SET);
- dp->count = vp->count;
- }
- if (F_ISSET(vp, VC_BUFFER))
- dp->buffer = vp->buffer;
- *vp = *dp;
- return (0);
- }
-
- flags = kp->flags;
-
- /* Check for illegal count. */
- if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
- goto usage;
-
- /* Illegal motion command. */
- if (ismotion == NULL) {
- /* Illegal buffer. */
- if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
- goto usage;
-
- /* Required buffer. */
- if (LF_ISSET(V_RBUF))
- KEY(vp->buffer, 0);
-
- /*
- * Special case: '[', ']' and 'Z' commands. Doesn't the
- * fact that the *single* characters don't mean anything
- * but the *doubled* characters do just frost your shorts?
- */
- if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
- KEY(key, TXT_MAPCOMMAND);
- if (vp->key != key)
- goto usage;
- }
- /* Special case: 'z' command. */
- if (vp->key == 'z') {
- KEY(vp->character, 0);
- if (isdigit(vp->character)) {
- if (getcount(sp, vp->character, &vp->count2))
- return (1);
- F_SET(vp, VC_C2SET);
- KEY(vp->character, 0);
- }
- }
- }
-
- /*
- * Commands that have motion components can be doubled to
- * imply the current line.
- */
- else if (ismotion->key != key && !LF_ISSET(V_MOVE)) {
-usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
- vikeys[ismotion->key].usage : kp->usage);
- return (1);
- }
-
- /* Required character. */
- if (LF_ISSET(V_CHAR))
- KEY(vp->character, 0);
-
- return (0);
-}
-
-/*
- * getmotion --
- *
- * Get resulting motion mark.
- */
-static int
-getmotion(sp, ep, dm, vp, fm, tm)
- SCR *sp;
- EXF *ep;
- VICMDARG *dm, *vp;
- MARK *fm, *tm;
-{
- MARK m;
- VICMDARG motion;
- u_long cnt;
- int notused;
-
- /* If '.' command, use the dot motion, else get the motion command. */
- if (F_ISSET(vp, VC_ISDOT)) {
- motion = *dm;
- F_SET(&motion, VC_ISDOT);
- } else if (getcmd(sp, ep, NULL, &motion, vp, &notused))
- return (1);
-
- /*
- * A count may be provided both to the command and to the motion, in
- * which case the count is multiplicative. For example, "3y4y" is the
- * same as "12yy". This count is provided to the motion command and
- * not to the regular function.
- */
- cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
- if (F_ISSET(vp, VC_C1SET)) {
- motion.count *= vp->count;
- F_SET(&motion, VC_C1SET);
-
- /*
- * Set flags to restore the original values of the command
- * structure so dot commands can change the count values,
- * e.g. "2dw" "3." deletes a total of five words.
- */
- F_CLR(vp, VC_C1SET);
- F_SET(vp, VC_C1RESET);
- }
-
- /*
- * Some commands can be repeated to indicate the current line. In
- * this case, or if the command is a "line command", set the flags
- * appropriately. If not a doubled command, run the function to get
- * the resulting mark.
- */
- if (vp->key == motion.key) {
- F_SET(vp, VC_LMODE);
-
- /*
- * Set the end of the command; the column is after the line.
- *
- * If the current line is missing, i.e. the file is empty,
- * historic vi permitted a "cc" or "!!" command to insert
- * text.
- */
- tm->lno = sp->lno + motion.count - 1;
- if (file_gline(sp, ep, tm->lno, &tm->cno) == NULL) {
- if (tm->lno != 1 || vp->key != 'c' && vp->key != '!') {
- m.lno = sp->lno;
- m.cno = sp->cno;
- v_eof(sp, ep, &m);
- return (1);
- }
- tm->cno = 0;
- }
-
- /* Set the origin of the command. */
- fm->lno = sp->lno;
- fm->cno = 0;
- } else {
- /*
- * Motion commands change the underlying movement (*snarl*).
- * For example, "l" is illegal at the end of a line, but "dl"
- * is not. Set flags so the function knows the situation.
- */
- F_SET(&motion, vp->kp->flags & VC_COMMASK);
-
- /*
- * Everything starts at the current position. This permits
- * commands like 'j' and 'k', that are line oriented motions
- * and have special cursor suck semantics when they are used
- * as standalone commands, to ignore column positioning.
- */
- fm->lno = tm->lno = sp->lno;
- fm->cno = tm->cno = sp->cno;
- if ((motion.kp->func)(sp, ep, &motion, fm, NULL, tm))
- return (1);
-
- /*
- * If the underlying motion was a line motion, set the flag
- * in the command structure. Underlying commands can also
- * flag the movement as a line motion (see v_sentence).
- */
- if (F_ISSET(motion.kp, V_LMODE) || F_ISSET(&motion, VC_LMODE))
- F_SET(vp, VC_LMODE);
-
- /*
- * If the motion is in the reverse direction, switch the from
- * and to MARK's so that it's always in a forward direction.
- * Because the motion is always from the from MARK to, but not
- * including, the to MARK, the function may have modified the
- * from MARK, so that it gets the one-past-the-place semantics
- * we use; see v_match() for an example. Also set a flag so
- * that the underlying function knows that we did this; v_yank,
- * for example, has to know so it gets the return cursor right.
- */
- if (tm->lno < fm->lno ||
- tm->lno == fm->lno && tm->cno < fm->cno) {
- m = *fm;
- *fm = *tm;
- *tm = m;
- F_SET(vp, VC_REVMOVE);
- }
- }
-
- /*
- * If the command sets dot, save the motion structure. The
- * motion count was changed above and needs to be reset, that's
- * why this is done here, and not in the calling routine.
- */
- if (F_ISSET(vp->kp, V_DOT)) {
- *dm = motion;
- dm->count = cnt;
- }
-
- /* Let the underlying function know what motion command was used. */
- vp->mkp = motion.kp;
- return (0);
-}
-
-#define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c))
-
-/*
- * getkeyword --
- * Get the "word" the cursor is on.
- */
-static int
-getkeyword(sp, ep, kp, flags)
- SCR *sp;
- EXF *ep;
- VICMDARG *kp;
- u_int flags;
-{
- recno_t lno;
- size_t beg, end, len;
- char *p;
-
- if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_eof(sp, ep, NULL);
- else
- GETLINE_ERR(sp, sp->lno);
- return (1);
- }
- beg = sp->cno;
-
- /* May not be a keyword at all. */
- if (p == NULL || len == 0 ||
- LF_ISSET(V_KEYW) && !inword(p[beg]) ||
- LF_ISSET(V_KEYNUM) && !innum(p[beg]) &&
- p[beg] != '-' && p[beg] != '+') {
-noword: msgq(sp, M_BERR, "Cursor not in a %s",
- LF_ISSET(V_KEYW) ? "word" : "number");
- return (1);
- }
-
- /*
- * !!!
- * Find the beginning/end of the keyword. Keywords (V_KEYW) are
- * used for cursor-word searching and for tags. Historical vi
- * only used the word in a tag search from the cursor to the end
- * of the word, i.e. if the cursor was on the 'b' in " abc ", the
- * tag was "bc". For no particular reason, we make cursor word
- * searches follow the same rule.
- */
- if (beg != 0)
- if (LF_ISSET(V_KEYW)) {
-#ifdef MOVE_TO_KEYWORD_BEGINNING
- for (;;) {
- --beg;
- if (!inword(p[beg])) {
- ++beg;
- break;
- }
- if (beg == 0)
- break;
- }
-#endif
- } else {
- for (;;) {
- --beg;
- if (!innum(p[beg])) {
- if (beg > 0 && p[beg - 1] == '0' &&
- (p[beg] == 'X' || p[beg] == 'x'))
- --beg;
- else
- ++beg;
- break;
- }
- if (beg == 0)
- break;
- }
-
- /* Skip possible leading sign. */
- if (beg != 0 && p[beg] != '0' &&
- (p[beg - 1] == '+' || p[beg - 1] == '-'))
- --beg;
- }
-
- if (LF_ISSET(V_KEYW)) {
- for (end = sp->cno; ++end < len && inword(p[end]););
- --end;
- } else {
- for (end = sp->cno; ++end < len;) {
- if (p[end] == 'X' || p[end] == 'x') {
- if (end != beg + 1 || p[beg] != '0')
- break;
- continue;
- }
- if (!innum(p[end]))
- break;
- }
-
- /* Just a sign isn't a number. */
- if (end == beg && (p[beg] == '+' || p[beg] == '-'))
- goto noword;
- --end;
- }
-
- /*
- * Getting a keyword implies moving the cursor to its beginning.
- * Refresh now.
- */
- if (beg != sp->cno) {
- sp->cno = beg;
- sp->s_refresh(sp, ep);
- }
-
- /*
- * XXX
- * 8-bit clean problem. Numeric keywords are handled using strtol(3)
- * and friends. This would have to be fixed in v_increment and here
- * to not depend on a trailing NULL.
- */
- len = (end - beg) + 2; /* XXX */
- kp->klen = (end - beg) + 1;
- BINC_RET(sp, kp->keyword, kp->kbuflen, len);
- memmove(kp->keyword, p + beg, kp->klen);
- kp->keyword[kp->klen] = '\0'; /* XXX */
- return (0);
-}
-
-/*
- * getcount --
- * Return the next count.
- */
-static inline int
-getcount(sp, fkey, countp)
- SCR *sp;
- ARG_CHAR_T fkey;
- u_long *countp;
-{
- u_long count, tc;
- CH ikey;
-
- ikey.ch = fkey;
- count = tc = 0;
- do {
- /* Assume that overflow results in a smaller number. */
- tc = count * 10 + ikey.ch - '0';
- if (count > tc) {
- /* Toss to the next non-digit. */
- do {
- if (getkey(sp, &ikey,
- TXT_MAPCOMMAND | TXT_MAPNODIGIT))
- return (1);
- } while (isdigit(ikey.ch));
- msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX);
- return (1);
- }
- count = tc;
- if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT))
- return (1);
- } while (isdigit(ikey.ch));
- *countp = count;
- return (0);
-}
-
-/*
- * getkey --
- * Return the next key.
- */
-static inline int
-getkey(sp, ikeyp, map)
- SCR *sp;
- CH *ikeyp;
- u_int map;
-{
- switch (term_key(sp, ikeyp, map)) {
- case INP_OK:
- break;
- case INP_EOF:
- F_SET(sp, S_EXIT_FORCE);
- /* FALLTHROUGH */
- case INP_ERR:
- return (1);
- }
- return (ikeyp->value == K_ESCAPE);
-}
diff --git a/usr.bin/vi/options.c b/usr.bin/vi/options.c
index 9c74160c5c01..b4301a228460 100644
--- a/usr.bin/vi/options.c
+++ b/usr.bin/vi/options.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,27 +32,36 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)options.c 8.36 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)options.c 8.52 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
-#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
static int opts_abbcmp __P((const void *, const void *));
static int opts_cmp __P((const void *, const void *));
static OPTLIST const *opts_prefix __P((char *));
-static int opts_print __P((SCR *, OPTLIST const *, OPTION *));
+static int opts_print __P((SCR *, OPTLIST const *));
/*
* O'Reilly noted options and abbreviations are from "Learning the VI Editor",
@@ -73,6 +82,8 @@ static OPTLIST const optlist[] = {
{"autowrite", NULL, OPT_0BOOL, 0},
/* O_BEAUTIFY 4BSD */
{"beautify", NULL, OPT_0BOOL, 0},
+/* O_CDPATH 4.4BSD */
+ {"cdpath", f_cdpath, OPT_STR, 0},
/* O_COLUMNS 4.4BSD */
{"columns", f_columns, OPT_NUM, OPT_NOSAVE},
/* O_COMMENT 4.4BSD */
@@ -102,7 +113,12 @@ static OPTLIST const optlist[] = {
/* O_LINES 4.4BSD */
{"lines", f_lines, OPT_NUM, OPT_NOSAVE},
/* O_LISP 4BSD */
- {"lisp", f_lisp, OPT_0BOOL, 0},
+/*
+ * XXX
+ * When the lisp option is implemented, delete
+ * the OPT_NOSAVE flag, so that :mkexrc dumps it.
+ */
+ {"lisp", f_lisp, OPT_0BOOL, OPT_NOSAVE},
/* O_LIST 4BSD */
{"list", f_list, OPT_0BOOL, 0},
/* O_MAGIC 4BSD */
@@ -118,7 +134,7 @@ static OPTLIST const optlist[] = {
/* O_OPEN 4BSD */
{"open", NULL, OPT_1BOOL, 0},
/* O_OPTIMIZE 4BSD */
- {"optimize", f_optimize, OPT_1BOOL, 0},
+ {"optimize", NULL, OPT_1BOOL, 0},
/* O_PARAGRAPHS 4BSD */
{"paragraphs", f_paragraph, OPT_STR, 0},
/* O_PROMPT 4BSD */
@@ -131,6 +147,8 @@ static OPTLIST const optlist[] = {
{"redraw", NULL, OPT_0BOOL, 0},
/* O_REMAP 4BSD */
{"remap", NULL, OPT_1BOOL, 0},
+/* O_REMAPMAX 4.4BSD */
+ {"remapmax", NULL, OPT_1BOOL, 0},
/* O_REPORT 4BSD */
{"report", NULL, OPT_NUM, OPT_NOSTR},
/* O_RULER 4.4BSD */
@@ -172,11 +190,11 @@ static OPTLIST const optlist[] = {
/* O_VERBOSE 4.4BSD */
{"verbose", NULL, OPT_0BOOL, 0},
/* O_W1200 4BSD */
- {"w1200", f_w1200, OPT_NUM, OPT_NEVER},
+ {"w1200", f_w1200, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_W300 4BSD */
- {"w300", f_w300, OPT_NUM, OPT_NEVER},
+ {"w300", f_w300, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_W9600 4BSD */
- {"w9600", f_w9600, OPT_NUM, OPT_NEVER},
+ {"w9600", f_w9600, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_WARN 4BSD */
{"warn", NULL, OPT_1BOOL, 0},
/* O_WINDOW 4BSD */
@@ -273,7 +291,11 @@ opts_init(sp)
O_CLR(sp, cnt);
else if (op->type == OPT_1BOOL)
O_SET(sp, cnt);
-
+
+ (void)snprintf(b1, sizeof(b1), "cdpath=%s",
+ (s = getenv("CDPATH")) == NULL ? ":" : s);
+ SET_DEF(O_CDPATH, b1);
+
/*
* !!!
* Vi historically stored temporary files in /var/tmp. We store them
@@ -293,16 +315,16 @@ opts_init(sp)
(void)snprintf(b1, sizeof(b1), "scroll=%ld", O_VAL(sp, O_LINES) / 2);
SET_DEF(O_SCROLL, b1);
SET_DEF(O_SECTIONS, "sections=NHSHH HUnhsh");
- (void)snprintf(b1, sizeof(b1),
- "shell=%s", (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
+ (void)snprintf(b1, sizeof(b1), "shell=%s",
+ (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
SET_DEF(O_SHELL, b1);
SET_DEF(O_SHIFTWIDTH, "shiftwidth=8");
SET_DEF(O_SIDESCROLL, "sidescroll=16");
SET_DEF(O_TABSTOP, "tabstop=8");
(void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS);
SET_DEF(O_TAGS, b1);
- (void)snprintf(b1, sizeof(b1),
- "term=%s", (s = getenv("TERM")) == NULL ? "unknown" : s);
+ (void)snprintf(b1, sizeof(b1), "term=%s",
+ (s = getenv("TERM")) == NULL ? "unknown" : s);
SET_DEF(O_TERM, b1);
/*
@@ -348,7 +370,7 @@ opts_set(sp, argv)
u_long value, turnoff;
int ch, offset, rval;
char *endp, *equals, *name, *p;
-
+
disp = NO_DISPLAY;
for (rval = 0; (*argv)->len != 0; ++argv) {
/*
@@ -359,10 +381,11 @@ opts_set(sp, argv)
disp = ALL_DISPLAY;
continue;
}
-
+
/* Find equals sign or end of set, skipping backquoted chars. */
- for (p = name = argv[0]->bp, equals = NULL; ch = *p; ++p)
- switch(ch) {
+ for (equals = NULL,
+ p = name = argv[0]->bp; (ch = *p) != '\0'; ++p)
+ switch (ch) {
case '=':
equals = p;
break;
@@ -525,7 +548,7 @@ change: if (sp->s_optchange != NULL)
abort();
}
}
- if (disp)
+ if (disp != NO_DISPLAY)
opts_dump(sp, disp);
return (rval);
}
@@ -546,31 +569,41 @@ opts_dump(sp, type)
char nbuf[20];
/*
+ * XXX
+ * It's possible to get here by putting "set option" in the
+ * .exrc file. I can't think of a clean way to layer this,
+ * or a reasonable check to make, so we block it here.
+ */
+ if (sp->stdfp == NULL) {
+ msgq(sp, M_ERR,
+ "Option display requires that the screen be initialized.");
+ return;
+ }
+
+ /*
* Options are output in two groups -- those that fit in a column and
* those that don't. Output is done on 6 character "tab" boundaries
* for no particular reason. (Since we don't output tab characters,
* we can ignore the terminal's tab settings.) Ignore the user's tab
* setting because we have no idea how reasonable it is.
+ *
+ * Find a column width we can live with.
*/
-#define BOUND 6
-
- /* Find a column width we can live with. */
for (cnt = 6; cnt > 1; --cnt) {
- colwidth = (sp->cols - 1) / cnt & ~(BOUND - 1);
+ colwidth = (sp->cols - 1) / cnt & ~(STANDARD_TAB - 1);
if (colwidth >= 10) {
- colwidth = (colwidth + BOUND) & ~(BOUND - 1);
+ colwidth =
+ (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1);
break;
}
colwidth = 0;
}
- /*
- * Two passes. First, get the set of options to list, entering them
- * into the column list or the overflow list. No error checking,
- * since we know that at least one option (O_TERM) has the OPT_SET bit
- * set.
+ /*
+ * Get the set of options to list, entering them into
+ * the column list or the overflow list.
*/
- for (b_num = s_num = 0, op = optlist; op->name; ++op) {
+ for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) {
cnt = op - optlist;
/* If OPT_NEVER set, it's never displayed. */
@@ -618,29 +651,32 @@ opts_dump(sp, type)
b_op[b_num++] = cnt;
}
- numcols = (sp->cols - 1) / colwidth;
- if (s_num > numcols) {
- numrows = s_num / numcols;
- if (s_num % numcols)
- ++numrows;
- } else
- numrows = 1;
-
- for (row = 0; row < numrows;) {
- for (base = row, col = 0; col < numcols; ++col) {
- cnt = opts_print(sp,
- &optlist[s_op[base]], &sp->opts[s_op[base]]);
- if ((base += numrows) >= s_num)
- break;
- (void)ex_printf(EXCOOKIE,
- "%*s", (int)(colwidth - cnt), "");
+ if (s_num > 0) {
+ /* Figure out the number of columns. */
+ numcols = (sp->cols - 1) / colwidth;
+ if (s_num > numcols) {
+ numrows = s_num / numcols;
+ if (s_num % numcols)
+ ++numrows;
+ } else
+ numrows = 1;
+
+ /* Display the options in sorted order. */
+ for (row = 0; row < numrows;) {
+ for (base = row, col = 0; col < numcols; ++col) {
+ cnt = opts_print(sp, &optlist[s_op[base]]);
+ if ((base += numrows) >= s_num)
+ break;
+ (void)ex_printf(EXCOOKIE,
+ "%*s", (int)(colwidth - cnt), "");
+ }
+ if (++row < numrows || b_num)
+ (void)ex_printf(EXCOOKIE, "\n");
}
- if (++row < numrows || b_num)
- (void)ex_printf(EXCOOKIE, "\n");
}
for (row = 0; row < b_num;) {
- (void)opts_print(sp, &optlist[b_op[row]], &sp->opts[b_op[row]]);
+ (void)opts_print(sp, &optlist[b_op[row]]);
if (++row < b_num)
(void)ex_printf(EXCOOKIE, "\n");
}
@@ -652,10 +688,9 @@ opts_dump(sp, type)
* Print out an option.
*/
static int
-opts_print(sp, op, spo)
+opts_print(sp, op)
SCR *sp;
OPTLIST const *op;
- OPTION *spo;
{
int curlen, offset;
@@ -688,12 +723,11 @@ opts_save(sp, fp)
SCR *sp;
FILE *fp;
{
- OPTION *spo;
OPTLIST const *op;
int ch, cnt;
char *p;
- for (spo = sp->opts, op = optlist; op->name; ++op) {
+ for (op = optlist; op->name != NULL; ++op) {
if (F_ISSET(op, OPT_NOSAVE))
continue;
cnt = op - optlist;
diff --git a/usr.bin/vi/options.h.stub b/usr.bin/vi/options.h.stub
index f5f52b52b3d3..cb2725075b9e 100644
--- a/usr.bin/vi/options.h.stub
+++ b/usr.bin/vi/options.h.stub
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)options.h.stub 8.14 (Berkeley) 12/20/93
+ * @(#)options.h.stub 8.18 (Berkeley) 3/17/94
*/
struct _option {
@@ -50,7 +50,7 @@ struct _optlist {
char *name; /* Name. */
/* Change function. */
int (*func) __P((SCR *, OPTION *, char *, u_long));
- /* Type of object. */
+ /* Type of object. */
enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type;
#define OPT_NEVER 0x01 /* Never display the option. */
@@ -81,6 +81,7 @@ int opts_set __P((SCR *, ARGS *[]));
/* Per-option change routines. */
int f_altwerase __P((SCR *, OPTION *, char *, u_long));
+int f_cdpath __P((SCR *, OPTION *, char *, u_long));
int f_columns __P((SCR *, OPTION *, char *, u_long));
int f_keytime __P((SCR *, OPTION *, char *, u_long));
int f_leftright __P((SCR *, OPTION *, char *, u_long));
@@ -91,7 +92,6 @@ int f_matchtime __P((SCR *, OPTION *, char *, u_long));
int f_mesg __P((SCR *, OPTION *, char *, u_long));
int f_modeline __P((SCR *, OPTION *, char *, u_long));
int f_number __P((SCR *, OPTION *, char *, u_long));
-int f_optimize __P((SCR *, OPTION *, char *, u_long));
int f_paragraph __P((SCR *, OPTION *, char *, u_long));
int f_readonly __P((SCR *, OPTION *, char *, u_long));
int f_ruler __P((SCR *, OPTION *, char *, u_long));
diff --git a/usr.bin/vi/options_f.c b/usr.bin/vi/options_f.c
index efd596f9585a..e2f0ed0e4ef2 100644
--- a/usr.bin/vi/options_f.c
+++ b/usr.bin/vi/options_f.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,32 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)options_f.c 8.25 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)options_f.c 8.28 (Berkeley) 3/18/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "tag.h"
+static int opt_dup __P((SCR *, int, char *));
static int opt_putenv __P((char *));
#define DECL(f) \
@@ -72,15 +83,9 @@ DECL(f_altwerase)
return (0);
}
-DECL(f_ttywerase)
+DECL(f_cdpath)
{
- if (turnoff)
- O_CLR(sp, O_TTYWERASE);
- else {
- O_SET(sp, O_TTYWERASE);
- O_CLR(sp, O_ALTWERASE);
- }
- return (0);
+ return (opt_dup(sp, O_CDPATH, str));
}
DECL(f_columns)
@@ -280,12 +285,6 @@ DECL(f_number)
return (0);
}
-DECL(f_optimize)
-{
- msgq(sp, M_ERR, "The optimize option is not implemented.");
- return (0);
-}
-
DECL(f_paragraph)
{
if (strlen(str) & 1) {
@@ -293,15 +292,7 @@ DECL(f_paragraph)
"Paragraph options must be in sets of two characters.");
return (1);
}
-
- if (F_ISSET(&sp->opts[O_PARAGRAPHS], OPT_ALLOCATED))
- free(O_STR(sp, O_PARAGRAPHS));
- if ((O_STR(sp, O_PARAGRAPHS) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(&sp->opts[O_PARAGRAPHS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_PARAGRAPHS, str));
}
DECL(f_readonly)
@@ -334,15 +325,7 @@ DECL(f_section)
"Section options must be in sets of two characters.");
return (1);
}
-
- if (F_ISSET(&sp->opts[O_SECTIONS], OPT_ALLOCATED))
- free(O_STR(sp, O_SECTIONS));
- if ((O_STR(sp, O_SECTIONS) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(&sp->opts[O_SECTIONS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_SECTIONS, str));
}
DECL(f_shiftwidth)
@@ -412,32 +395,15 @@ DECL(f_tabstop)
DECL(f_tags)
{
- char *p;
-
- /* Copy for user display. */
- p = O_STR(sp, O_TAGS);
- if ((O_STR(sp, O_TAGS) = strdup(str)) == NULL) {
- O_STR(sp, O_TAGS) = p;
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- if (F_ISSET(&sp->opts[O_TAGS], OPT_ALLOCATED))
- FREE(p, strlen(p) + 1);
- F_SET(&sp->opts[O_TAGS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_TAGS, str));
}
DECL(f_term)
{
char buf[256];
- if (F_ISSET(&sp->opts[O_TERM], OPT_ALLOCATED))
- free(O_STR(sp, O_TERM));
- if ((O_STR(sp, O_TERM) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
+ if (opt_dup(sp, O_TERM, str))
return (1);
- }
- F_SET(&sp->opts[O_TERM], OPT_ALLOCATED | OPT_SET);
/* Set the terminal value in the environment for curses. */
(void)snprintf(buf, sizeof(buf), "TERM=%s", str);
@@ -449,6 +415,17 @@ DECL(f_term)
return (0);
}
+DECL(f_ttywerase)
+{
+ if (turnoff)
+ O_CLR(sp, O_TTYWERASE);
+ else {
+ O_SET(sp, O_TTYWERASE);
+ O_CLR(sp, O_ALTWERASE);
+ }
+ return (0);
+}
+
DECL(f_w300)
{
/* Historical behavior for w300 was < 1200. */
@@ -527,6 +504,36 @@ DECL(f_wrapmargin)
}
/*
+ * opt_dup --
+ * Copy a string value for user display.
+ */
+static int
+opt_dup(sp, opt, str)
+ SCR *sp;
+ int opt;
+ char *str;
+{
+ char *p;
+
+ /* Copy for user display. */
+ if ((p = strdup(str)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /* Free the old contents. */
+ if (F_ISSET(&sp->opts[opt], OPT_ALLOCATED))
+ free(O_STR(sp, opt));
+
+ /* Note that it's set and allocated. */
+ F_SET(&sp->opts[opt], OPT_ALLOCATED | OPT_SET);
+
+ /* Assign new contents. */
+ O_STR(sp, opt) = p;
+ return (0);
+}
+
+/*
* opt_putenv --
* Put a value into the environment. We use putenv(3) because it's
* more portable. The following hack is because some moron decided
diff --git a/usr.bin/vi/pathnames.h b/usr.bin/vi/pathnames.h
index be6352b9dfc1..c6e6906dc63a 100644
--- a/usr.bin/vi/pathnames.h
+++ b/usr.bin/vi/pathnames.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pathnames.h 8.5 (Berkeley) 12/21/93
+ * @(#)pathnames.h 8.6 (Berkeley) 3/16/94
*/
#define _PATH_BSHELL "/bin/sh"
diff --git a/usr.bin/vi/put.c b/usr.bin/vi/put.c
new file mode 100644
index 000000000000..5f680734e7f6
--- /dev/null
+++ b/usr.bin/vi/put.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)put.c 8.3 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * put --
+ * Put text buffer contents into the file.
+ *
+ * !!!
+ * Historically, pasting into a file with no lines in vi would preserve
+ * the single blank line. This is almost certainly a result of the fact
+ * that historic vi couldn't deal with a file that had no lines in it.
+ * This implementation treats that as a bug, and does not retain the blank
+ * line.
+ */
+int
+put(sp, ep, cbp, namep, cp, rp, append)
+ SCR *sp;
+ EXF *ep;
+ CB *cbp;
+ CHAR_T *namep;
+ MARK *cp, *rp;
+ int append;
+{
+ CHAR_T name;
+ TEXT *ltp, *tp;
+ recno_t lno;
+ size_t blen, clen, len;
+ char *bp, *p, *t;
+
+ if (cbp == NULL)
+ if (namep == NULL) {
+ cbp = sp->gp->dcbp;
+ if (cbp == NULL) {
+ msgq(sp, M_ERR, "The default buffer is empty.");
+ return (1);
+ }
+ } else {
+ name = *namep;
+ CBNAME(sp, cbp, name);
+ if (cbp == NULL) {
+ msgq(sp, M_ERR,
+ "Buffer %s is empty.", charname(sp, name));
+ return (1);
+ }
+ }
+ tp = cbp->textq.cqh_first;
+
+ /*
+ * It's possible to do a put into an empty file, meaning that the
+ * cut buffer simply becomes the file. It's a special case so
+ * that we can ignore it in general.
+ *
+ * Historical practice is that the cursor ends up on the first
+ * non-blank character of the first line inserted.
+ */
+ if (cp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ for (; tp != (void *)&cbp->textq;
+ ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ return (1);
+ rp->lno = 1;
+ rp->cno = 0;
+ (void)nonblank(sp, ep, rp->lno, &rp->cno);
+ goto ret;
+ }
+ }
+
+ /* If a line mode buffer, append each new line into the file. */
+ if (F_ISSET(cbp, CB_LMODE)) {
+ lno = append ? cp->lno : cp->lno - 1;
+ rp->lno = lno + 1;
+ for (; tp != (void *)&cbp->textq; ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ return (1);
+ rp->cno = 0;
+ (void)nonblank(sp, ep, rp->lno, &rp->cno);
+ goto ret;
+ }
+
+ /*
+ * If buffer was cut in character mode, replace the current line with
+ * one built from the portion of the first line to the left of the
+ * split plus the first line in the CB. Append each intermediate line
+ * in the CB. Append a line built from the portion of the first line
+ * to the right of the split plus the last line in the CB.
+ *
+ * Get the first line.
+ */
+ lno = cp->lno;
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+
+ GET_SPACE_RET(sp, bp, blen, tp->len + len + 1);
+ t = bp;
+
+ /* Original line, left of the split. */
+ if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
+ memmove(bp, p, clen);
+ p += clen;
+ t += clen;
+ }
+
+ /* First line from the CB. */
+ memmove(t, tp->lb, tp->len);
+ t += tp->len;
+
+ /* Calculate length left in original line. */
+ clen = len ? len - cp->cno - (append ? 1 : 0) : 0;
+
+ /*
+ * If no more lines in the CB, append the rest of the original
+ * line and quit. Otherwise, build the last line before doing
+ * the intermediate lines, because the line changes will lose
+ * the cached line.
+ */
+ if (tp->q.cqe_next == (void *)&cbp->textq) {
+ /*
+ * Historical practice is that if a non-line mode put
+ * is inside a single line, the cursor ends up on the
+ * last character inserted.
+ */
+ rp->lno = lno;
+ rp->cno = (t - bp) - 1;
+
+ if (clen > 0) {
+ memmove(t, p, clen);
+ t += clen;
+ }
+ if (file_sline(sp, ep, lno, bp, t - bp))
+ goto mem;
+ } else {
+ /*
+ * Have to build both the first and last lines of the
+ * put before doing any sets or we'll lose the cached
+ * line. Build both the first and last lines in the
+ * same buffer, so we don't have to have another buffer
+ * floating around.
+ *
+ * Last part of original line; check for space, reset
+ * the pointer into the buffer.
+ */
+ ltp = cbp->textq.cqh_last;
+ len = t - bp;
+ ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
+ t = bp + len;
+
+ /* Add in last part of the CB. */
+ memmove(t, ltp->lb, ltp->len);
+ if (clen)
+ memmove(t + ltp->len, p, clen);
+ clen += ltp->len;
+
+ /*
+ * Now: bp points to the first character of the first
+ * line, t points to the last character of the last
+ * line, t - bp is the length of the first line, and
+ * clen is the length of the last. Just figured you'd
+ * want to know.
+ *
+ * Output the line replacing the original line.
+ */
+ if (file_sline(sp, ep, lno, bp, t - bp))
+ goto mem;
+
+ /*
+ * Historical practice is that if a non-line mode put
+ * covers multiple lines, the cursor ends up on the
+ * first character inserted. (Of course.)
+ */
+ rp->lno = lno;
+ rp->cno = (t - bp) - 1;
+
+ /* Output any intermediate lines in the CB. */
+ for (tp = tp->q.cqe_next;
+ tp->q.cqe_next != (void *)&cbp->textq;
+ ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ goto mem;
+
+ if (file_aline(sp, ep, 1, lno, t, clen)) {
+mem: FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ /* Reporting... */
+ret: sp->rptlines[L_PUT] += lno - cp->lno;
+
+ return (0);
+}
diff --git a/usr.bin/vi/recover.c b/usr.bin/vi/recover.c
index f9a483236abe..01f94a1c5e7f 100644
--- a/usr.bin/vi/recover.c
+++ b/usr.bin/vi/recover.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,11 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
+static char sccsid[] = "@(#)recover.c 8.50 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -46,18 +47,26 @@ static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
*/
#include <sys/file.h>
-#include <netdb.h> /* MAXHOSTNAMELEN on some systems. */
+#include <netdb.h> /* MAXHOSTNAMELEN on some systems. */
+#include <bitstring.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
-#include "pathnames.h"
/*
* Recovery code.
@@ -92,7 +101,6 @@ static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
#define VI_FHEADER "Vi-recover-file: "
#define VI_PHEADER "Vi-recover-path: "
-static void rcv_alrm __P((int));
static int rcv_mailfile __P((SCR *, EXF *));
static void rcv_syncit __P((SCR *, int));
@@ -125,7 +133,7 @@ rcv_tmp(sp, ep, name)
}
(void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
}
-
+
/* Newlines delimit the mail messages. */
for (p = name; *p; ++p)
if (*p == '\n') {
@@ -169,14 +177,16 @@ rcv_init(sp, ep)
SCR *sp;
EXF *ep;
{
- struct itimerval value;
- struct sigaction act;
recno_t lno;
+ int btear;
F_CLR(ep, F_FIRSTMODIFY | F_RCV_ON);
- /* Build file to mail to the user. */
- if (rcv_mailfile(sp, ep))
+ /*
+ * If not already recoverying a file, build a file to mail
+ * to the user.
+ */
+ if (ep->rcv_mpath == NULL && rcv_mailfile(sp, ep))
goto err;
/* Force read of entire file. */
@@ -184,32 +194,22 @@ rcv_init(sp, ep)
goto err;
/* Turn on a busy message, and sync it to backing store. */
- busy_on(sp, 1, "Copying file for recovery...");
+
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 :
+ !busy_on(sp, "Copying file for recovery...");
if (ep->db->sync(ep->db, R_RECNOSYNC)) {
msgq(sp, M_ERR, "Preservation failed: %s: %s",
ep->rcv_path, strerror(errno));
- busy_off(sp);
+ if (btear)
+ busy_off(sp);
goto err;
}
- busy_off(sp);
-
- if (!F_ISSET(sp->gp, G_RECOVER_SET)) {
- /* Install the recovery timer handler. */
- act.sa_handler = rcv_alrm;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(SIGALRM, &act, NULL);
-
- /* Start the recovery timer. */
- value.it_interval.tv_sec = value.it_value.tv_sec = RCV_PERIOD;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, NULL)) {
- msgq(sp, M_ERR,
- "Error: setitimer: %s", strerror(errno));
-err: msgq(sp, M_ERR,
- "Recovery after system crash not possible.");
- return (1);
- }
+ if (btear)
+ busy_off(sp);
+
+ if (!F_ISSET(sp->gp, G_RECOVER_SET) && rcv_on(sp, ep)) {
+err: msgq(sp, M_ERR, "Recovery after system crash not possible.");
+ return (1);
}
/* We believe the file is recoverable. */
@@ -218,17 +218,6 @@ err: msgq(sp, M_ERR,
}
/*
- * rcv_alrm --
- * Recovery timer interrupt handler.
- */
-static void
-rcv_alrm(signo)
- int signo;
-{
- F_SET(__global_list, G_SIGALRM);
-}
-
-/*
* rcv_mailfile --
* Build the file to mail to the user.
*/
@@ -265,15 +254,16 @@ rcv_mailfile(sp, ep)
* be recovered. There's an obvious window between the mkstemp call
* and the lock, but it's pretty small.
*/
- if ((ep->rcv_fd = dup(fd)) != -1)
- (void)flock(ep->rcv_fd, LOCK_EX | LOCK_NB);
+ if ((ep->rcv_fd = dup(fd)) == -1 ||
+ flock(ep->rcv_fd, LOCK_EX | LOCK_NB))
+ msgq(sp, M_SYSERR, "Unable to lock recovery file");
if ((ep->rcv_mpath = strdup(path)) == NULL) {
msgq(sp, M_SYSERR, NULL);
(void)fclose(fp);
return (1);
}
-
+
t = FILENAME(sp->frp);
if ((p = strrchr(t, '/')) == NULL)
p = t;
@@ -289,7 +279,7 @@ rcv_mailfile(sp, ep)
"To: ", pw->pw_name,
"Subject: Nvi saved the file ", p,
"Precedence: bulk"); /* For vacation(1). */
- (void)fprintf(fp, "%s%.24s%s%s\n%s%s",
+ (void)fprintf(fp, "%s%.24s%s%s\n%s%s",
"On ", ctime(&now),
", the user ", pw->pw_name,
"was editing a file named ", p);
@@ -307,6 +297,7 @@ rcv_mailfile(sp, ep)
(void)fclose(fp);
return (1);
}
+ (void)fclose(fp);
return (0);
}
@@ -319,15 +310,10 @@ rcv_sync(sp, ep)
SCR *sp;
EXF *ep;
{
- struct itimerval value;
-
if (ep->db->sync(ep->db, R_RECNOSYNC)) {
+ F_CLR(ep, F_RCV_ON);
msgq(sp, M_ERR, "Automatic file backup failed: %s: %s",
ep->rcv_path, strerror(errno));
- value.it_interval.tv_sec = value.it_interval.tv_usec = 0;
- value.it_value.tv_sec = value.it_value.tv_usec = 0;
- (void)setitimer(ITIMER_REAL, &value, NULL);
- F_CLR(ep, F_RCV_ON);
return (1);
}
return (0);
@@ -432,7 +418,7 @@ rcv_syncit(sp, email)
/*
* people making love
* never exactly the same
- * just like a snowflake
+ * just like a snowflake
*
* rcv_list --
* List the files that can be recovered by this user.
@@ -511,18 +497,20 @@ rcv_read(sp, name)
struct stat sb;
DIR *dirp;
FREF *frp;
- FILE *fp;
+ FILE *fp, *sv_fp;
time_t rec_mtime;
int found, requested;
char *p, *t, *recp, *pathp;
char recpath[MAXPATHLEN], file[MAXPATHLEN], path[MAXPATHLEN];
-
+
if ((dirp = opendir(O_STR(sp, O_RECDIR))) == NULL) {
msgq(sp, M_ERR,
"%s: %s", O_STR(sp, O_RECDIR), strerror(errno));
return (1);
}
+ sv_fp = NULL;
+ rec_mtime = 0;
recp = pathp = NULL;
for (found = requested = 0; (dp = readdir(dirp)) != NULL;) {
if (strncmp(dp->d_name, "recover.", 8))
@@ -590,9 +578,11 @@ rcv_read(sp, name)
FREE(t, strlen(t) + 1);
}
rec_mtime = sb.st_mtime;
- }
-
-next: (void)fclose(fp);
+ if (sv_fp != NULL)
+ (void)fclose(sv_fp);
+ sv_fp = fp;
+ } else
+next: (void)fclose(fp);
}
(void)closedir(dirp);
@@ -607,7 +597,7 @@ next: (void)fclose(fp);
"There are older versions of this file for you to recover.");
if (found > requested)
msgq(sp, M_INFO,
- "There are other files that you can recover.");
+ "There are other files for you to recover.");
}
/* Create the FREF structure, start the btree file. */
@@ -615,8 +605,18 @@ next: (void)fclose(fp);
file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) {
FREE(recp, strlen(recp) + 1);
FREE(pathp, strlen(pathp) + 1);
+ (void)fclose(sv_fp);
return (1);
}
+
+ /*
+ * We keep an open lock on the file so that the recover option can
+ * distinguish between files that are live and those that need to
+ * be recovered. The lock is already acquired, so just get a copy.
+ */
+ if ((sp->ep->rcv_fd = dup(fileno(sv_fp))) != -1)
+ (void)fclose(sv_fp);
+
sp->ep->rcv_mpath = recp;
return (0);
}
diff --git a/usr.bin/vi/screen.c b/usr.bin/vi/screen.c
index e18bd02183dd..8664d02d7895 100644
--- a/usr.bin/vi/screen.c
+++ b/usr.bin/vi/screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)screen.c 8.51 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)screen.c 8.56 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -78,7 +88,6 @@ screen_init(orig, spp, flags)
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
if (orig == NULL) {
sp->searchdir = NOTSET;
- sp->csearchdir = CNOTSET;
switch (flags & S_SCREENS) {
case S_EX:
@@ -113,8 +122,6 @@ screen_init(orig, spp, flags)
sp->subre = orig->subre;
}
sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
- sp->csearchdir = CNOTSET;
- sp->lastckey = orig->lastckey;
if (orig->matchsize) {
len = orig->matchsize * sizeof(regmatch_t);
@@ -153,10 +160,11 @@ mem: msgq(orig, M_SYSERR, "new screen attributes");
sp->s_bg = orig->s_bg;
sp->s_busy = orig->s_busy;
sp->s_change = orig->s_change;
- sp->s_chposition = orig->s_chposition;
sp->s_clear = orig->s_clear;
+ sp->s_colpos = orig->s_colpos;
sp->s_column = orig->s_column;
sp->s_confirm = orig->s_confirm;
+ sp->s_crel = orig->s_crel;
sp->s_down = orig->s_down;
sp->s_edit = orig->s_edit;
sp->s_end = orig->s_end;
@@ -170,9 +178,8 @@ mem: msgq(orig, M_SYSERR, "new screen attributes");
sp->s_optchange = orig->s_optchange;
sp->s_position = orig->s_position;
sp->s_rabs = orig->s_rabs;
+ sp->s_rcm = orig->s_rcm;
sp->s_refresh = orig->s_refresh;
- sp->s_relative = orig->s_relative;
- sp->s_rrel = orig->s_rrel;
sp->s_split = orig->s_split;
sp->s_suspend = orig->s_suspend;
sp->s_up = orig->s_up;
@@ -256,7 +263,7 @@ screen_end(sp)
/*
* Free the message chain last, so previous failures have a place
* to put messages. Copy messages to (in order) a related screen,
- * any screen, the global area.
+ * any screen, the global area.
*/
{ SCR *c_sp; MSG *mp, *next;
if ((c_sp = sp->q.cqe_prev) != (void *)&sp->gp->dq) {
diff --git a/usr.bin/vi/screen.h b/usr.bin/vi/screen.h
index d95179352b48..741c41f01d34 100644
--- a/usr.bin/vi/screen.h
+++ b/usr.bin/vi/screen.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)screen.h 8.81 (Berkeley) 12/29/93
+ * @(#)screen.h 8.92 (Berkeley) 3/23/94
*/
/*
@@ -51,6 +51,8 @@
enum operation { LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET };
/* Position values. */
enum position { P_BOTTOM, P_FILL, P_MIDDLE, P_TOP };
+ /* Screen adjustment operations. */
+enum adjust { A_DECREASE, A_INCREASE, A_SET };
/*
* Structure for holding file references. Each SCR structure contains a
@@ -161,9 +163,12 @@ struct _scr {
SCRIPT *script; /* Vi: script mode information .*/
- char const *time_msg; /* ITIMER_REAL message. */
- struct itimerval time_value; /* ITIMER_REAL saved value. */
- struct sigaction time_handler; /* ITIMER_REAL saved handler. */
+ struct timeval busy_tod; /* ITIMER_REAL: busy time-of-day. */
+ char const *busy_msg; /* ITIMER_REAL: busy message. */
+
+ struct sigaction intr_act; /* Interrupt saved signal state. */
+ struct termios intr_term; /* Interrupt saved terminal state. */
+ int intr_level; /* 0-N: Interrupt level. */
void *vi_private; /* Vi private area. */
void *ex_private; /* Ex private area. */
@@ -177,8 +182,6 @@ struct _scr {
regex_t sre; /* Last search RE. */
regex_t subre; /* Last substitute RE. */
enum direction searchdir; /* File search direction. */
- enum cdirection csearchdir; /* Character search direction. */
- CHAR_T lastckey; /* Last search character. */
regmatch_t *match; /* Substitute match array. */
size_t matchsize; /* Substitute match array size. */
char *repl; /* Substitute replacement. */
@@ -197,60 +200,60 @@ struct _scr {
* A SCR * MUST be the first argument to these routines.
*/
/* Ring the screen bell. */
- void (*s_bell) __P((SCR *));
+ void (*s_bell) __P((SCR *));
/* Background the screen. */
- int (*s_bg) __P((SCR *));
+ int (*s_bg) __P((SCR *));
/* Put up a busy message. */
- int (*s_busy) __P((SCR *, char const *));
+ int (*s_busy) __P((SCR *, char const *));
/* Change a screen line. */
- int (*s_change) __P((SCR *, EXF *, recno_t, enum operation));
- /* Return column close to specified. */
- size_t (*s_chposition) __P((SCR *, EXF *, recno_t, size_t));
+ int (*s_change) __P((SCR *, EXF *, recno_t, enum operation));
/* Clear the screen. */
- int (*s_clear) __P((SCR *));
+ int (*s_clear) __P((SCR *));
+ /* Return column close to specified. */
+ size_t (*s_colpos) __P((SCR *, EXF *, recno_t, size_t));
/* Return the logical cursor column. */
- int (*s_column) __P((SCR *, EXF *, size_t *));
+ int (*s_column) __P((SCR *, EXF *, size_t *));
enum confirm /* Confirm an action with the user. */
- (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *));
+ (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *));
+ /* Change the relative screen size. */
+ int (*s_crel) __P((SCR *, long));
/* Move down the screen. */
- int (*s_down) __P((SCR *, EXF *, MARK *, recno_t, int));
+ int (*s_down) __P((SCR *, EXF *, MARK *, recno_t, int));
/* Edit a file. */
- int (*s_edit) __P((SCR *, EXF *));
+ int (*s_edit) __P((SCR *, EXF *));
/* End a screen. */
- int (*s_end) __P((SCR *));
+ int (*s_end) __P((SCR *));
/* Run a single ex command. */
- int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *));
+ int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *));
/* Run user's ex commands. */
- int (*s_ex_run) __P((SCR *, EXF *, MARK *));
+ int (*s_ex_run) __P((SCR *, EXF *, MARK *));
/* Screen's ex write function. */
- int (*s_ex_write) __P((void *, const char *, int));
+ int (*s_ex_write) __P((void *, const char *, int));
/* Foreground the screen. */
- int (*s_fg) __P((SCR *, CHAR_T *));
+ int (*s_fg) __P((SCR *, CHAR_T *));
/* Fill the screen's map. */
- int (*s_fill) __P((SCR *, EXF *, recno_t, enum position));
+ int (*s_fill) __P((SCR *, EXF *, recno_t, enum position));
enum input /* Get a line from the user. */
- (*s_get) __P((SCR *, EXF *, TEXTH *, int, u_int));
+ (*s_get) __P((SCR *, EXF *, TEXTH *, int, u_int));
enum input /* Get a key from the user. */
- (*s_key_read) __P((SCR *, int *, struct timeval *));
+ (*s_key_read) __P((SCR *, int *, struct timeval *));
/* Tell the screen an option changed. */
- int (*s_optchange) __P((SCR *, int));
+ int (*s_optchange) __P((SCR *, int));
/* Return column at screen position. */
- int (*s_position) __P((SCR *, EXF *,
- MARK *, u_long, enum position));
+ int (*s_position) __P((SCR *, EXF *,
+ MARK *, u_long, enum position));
/* Change the absolute screen size. */
- int (*s_rabs) __P((SCR *, long));
+ int (*s_rabs) __P((SCR *, long, enum adjust));
+ /* Return column close to selection. */
+ size_t (*s_rcm) __P((SCR *, EXF *, recno_t));
/* Refresh the screen. */
- int (*s_refresh) __P((SCR *, EXF *));
- /* Return column close to last char. */
- size_t (*s_relative) __P((SCR *, EXF *, recno_t));
- /* Change the relative screen size. */
- int (*s_rrel) __P((SCR *, long));
+ int (*s_refresh) __P((SCR *, EXF *));
/* Split the screen. */
- int (*s_split) __P((SCR *, ARGS *[]));
+ int (*s_split) __P((SCR *, ARGS *[]));
/* Suspend the screen. */
- int (*s_suspend) __P((SCR *));
+ int (*s_suspend) __P((SCR *));
/* Move up the screen. */
- int (*s_up) __P((SCR *, EXF *, MARK *, recno_t, int));
+ int (*s_up) __P((SCR *, EXF *, MARK *, recno_t, int));
/* Editor screens. */
#define S_EX 0x0000001 /* Ex screen. */
@@ -287,28 +290,38 @@ struct _scr {
#define S_SCRIPT 0x0080000 /* Window is a shell script. */
#define S_SRE_SET 0x0100000 /* The search RE has been set. */
#define S_SUBRE_SET 0x0200000 /* The substitute RE has been set. */
-#define S_TIMER_SET 0x0400000 /* If a busy timer is running. */
-#define S_UPDATE_MODE 0x0800000 /* Don't repaint modeline. */
- u_int flags;
+#define S_UPDATE_MODE 0x0400000 /* Don't repaint modeline. */
+#define S_VLITONLY 0x0800000 /* ^V literal next only. */
+ u_int32_t flags;
};
+/* Timers have no structure, so routines are here. */
+void h_alrm __P((int));
+int busy_on __P((SCR *, char const *));
+void busy_off __P((SCR *));
+int rcv_on __P((SCR *, EXF *));
+
+/* Interrupts have no structure, so routines are here. */
+void intr_end __P((SCR *));
+int intr_init __P((SCR *));
+
/* Generic routines to start/stop a screen. */
-int screen_end __P((SCR *));
-int screen_init __P((SCR *, SCR **, u_int));
+int screen_end __P((SCR *));
+int screen_init __P((SCR *, SCR **, u_int));
/* Public interfaces to the underlying screens. */
-int ex_screen_copy __P((SCR *, SCR *));
-int ex_screen_end __P((SCR *));
-int ex_screen_init __P((SCR *));
-int sex_screen_copy __P((SCR *, SCR *));
-int sex_screen_end __P((SCR *));
-int sex_screen_init __P((SCR *));
-int svi_screen_copy __P((SCR *, SCR *));
-int svi_screen_end __P((SCR *));
-int svi_screen_init __P((SCR *));
-int v_screen_copy __P((SCR *, SCR *));
-int v_screen_end __P((SCR *));
-int v_screen_init __P((SCR *));
-int xaw_screen_copy __P((SCR *, SCR *));
-int xaw_screen_end __P((SCR *));
-int xaw_screen_init __P((SCR *));
+int ex_screen_copy __P((SCR *, SCR *));
+int ex_screen_end __P((SCR *));
+int ex_screen_init __P((SCR *));
+int sex_screen_copy __P((SCR *, SCR *));
+int sex_screen_end __P((SCR *));
+int sex_screen_init __P((SCR *));
+int svi_screen_copy __P((SCR *, SCR *));
+int svi_screen_end __P((SCR *));
+int svi_screen_init __P((SCR *));
+int v_screen_copy __P((SCR *, SCR *));
+int v_screen_end __P((SCR *));
+int v_screen_init __P((SCR *));
+int xaw_screen_copy __P((SCR *, SCR *));
+int xaw_screen_end __P((SCR *));
+int xaw_screen_init __P((SCR *));
diff --git a/usr.bin/vi/search.c b/usr.bin/vi/search.c
index 22aadef48751..9ef1a836d92d 100644
--- a/usr.bin/vi/search.c
+++ b/usr.bin/vi/search.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,26 +32,34 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)search.c 8.32 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)search.c 8.40 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
-#include "interrupt.h"
static int check_delta __P((SCR *, EXF *, long, recno_t));
static int ctag_conv __P((SCR *, char **, int *));
static int get_delta __P((SCR *, char **, long *, u_int *));
static int resetup __P((SCR *, regex_t **, enum direction,
char *, char **, long *, u_int *));
-static void search_intr __P((int));
/*
* resetup --
@@ -213,7 +221,7 @@ ctag_conv(sp, ptrnp, replacedp)
/* The second character is a '^', and it's magic. */
if (p[0] == '^')
*t++ = *p++;
-
+
/*
* Escape every other magic character we can find, stripping the
* backslashes ctags inserts to escape the search delimiter
@@ -236,28 +244,6 @@ ctag_conv(sp, ptrnp, replacedp)
return (0);
}
-/*
- * search_intr --
- * Set the interrupt bit in any screen that is interruptible.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one search/global (see ex/ex_global.c) running, it will be hard
- * to decide which one to stop.
- */
-static void
-search_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
-
#define EMPTYMSG "File empty; nothing to search."
#define EOFMSG "Reached end-of-file without finding the pattern."
#define NOTFOUND "Pattern not found."
@@ -272,14 +258,13 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
char *ptrn, **eptrn;
u_int *flagp;
{
- DECLARE_INTERRUPTS;
regmatch_t match[1];
regex_t *re, lre;
recno_t lno;
size_t coff, len;
long delta;
u_int flags;
- int eval, rval, wrapped;
+ int btear, eval, itear, rval, wrapped;
char *l;
if (file_lline(sp, ep, &lno))
@@ -327,16 +312,9 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
}
}
- /*
- * Set up busy message, interrupts.
- *
- * F_search is called from the ex_tagfirst() routine, which runs
- * before the screen really exists. Make sure we don't step on
- * anything.
- */
- if (sp->s_position != NULL)
- busy_on(sp, 1, "Searching...");
- SET_UP_INTERRUPTS(search_intr);
+ /* Set up busy message, interrupts. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+ itear = !intr_init(sp);
for (rval = 1, wrapped = 0;; ++lno, coff = 0) {
if (F_ISSET(sp, S_INTERRUPTED)) {
@@ -381,7 +359,7 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
re_error(sp, eval, re);
break;
}
-
+
/* Warn if wrapped. */
if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))
msgq(sp, M_INFO, WRAPMSG);
@@ -416,13 +394,11 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
break;
}
-interrupt_err:
-
/* Turn off busy message, interrupts. */
- if (sp->s_position != NULL)
+ if (btear)
busy_off(sp);
- TEAR_DOWN_INTERRUPTS;
-
+ if (itear)
+ intr_end(sp);
return (rval);
}
@@ -434,14 +410,13 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
char *ptrn, **eptrn;
u_int *flagp;
{
- DECLARE_INTERRUPTS;
regmatch_t match[1];
regex_t *re, lre;
recno_t lno;
size_t coff, len, last;
long delta;
u_int flags;
- int eval, rval, wrapped;
+ int btear, eval, itear, rval, wrapped;
char *l;
if (file_lline(sp, ep, &lno))
@@ -471,10 +446,8 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
lno = fm->lno;
/* Turn on busy message, interrupts. */
- busy_on(sp, 1, "Searching...");
-
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- SET_UP_INTERRUPTS(search_intr);
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+ itear = !intr_init(sp);
for (rval = 1, wrapped = 0, coff = fm->cno;; --lno, coff = 0) {
if (F_ISSET(sp, S_INTERRUPTED)) {
@@ -509,7 +482,7 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
/* Set the termination. */
match[0].rm_so = 0;
- match[0].rm_eo = coff ? coff : len;
+ match[0].rm_eo = len;
#if defined(DEBUG) && 0
TRACE(sp, "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo);
@@ -524,10 +497,14 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
break;
}
+ /* Check for a match starting past the cursor. */
+ if (coff != 0 && match[0].rm_so >= coff)
+ continue;
+
/* Warn if wrapped. */
if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))
msgq(sp, M_INFO, WRAPMSG);
-
+
if (delta) {
if (check_delta(sp, ep, delta, lno))
break;
@@ -539,17 +516,17 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
match[0].rm_so, match[0].rm_eo);
#endif
/*
- * Find the last acceptable one in this line. This
- * is really painful, we need a cleaner interface to
- * regexec to make this possible.
+ * We now have the first match on the line. Step
+ * through the line character by character until we
+ * find the last acceptable match. This is painful,
+ * we need a better interface to regex to make this
+ * work.
*/
for (;;) {
- last = match[0].rm_so;
- match[0].rm_so = match[0].rm_eo + 1;
- if (match[0].rm_so >= len ||
- coff && match[0].rm_so >= coff)
+ last = match[0].rm_so++;
+ if (match[0].rm_so >= len)
break;
- match[0].rm_eo = coff ? coff : len;
+ match[0].rm_eo = len;
eval = regexec(re, l, 1, match,
(match[0].rm_so == 0 ? 0 : REG_NOTBOL) |
REG_STARTEND);
@@ -559,6 +536,8 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
re_error(sp, eval, re);
goto err;
}
+ if (coff && match[0].rm_so >= coff)
+ break;
}
rm->lno = lno;
@@ -573,11 +552,10 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
}
/* Turn off busy message, interrupts. */
-interrupt_err:
-err: busy_off(sp);
-
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- TEAR_DOWN_INTERRUPTS;
+err: if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
return (rval);
}
@@ -591,7 +569,7 @@ err: busy_off(sp);
* the global, search, and substitute patterns) work with POSIX RE's.
*
* 1: If O_MAGIC is not set, strip backslashes from the magic character
- * set (.[]*~) that have them, and add them to the ones that don't.
+ * set (.[]*~) that have them, and add them to the ones that don't.
* 2: If O_MAGIC is not set, the string "\~" is replaced with the text
* from the last substitute command's replacement string. If O_MAGIC
* is set, it's the string "~".
diff --git a/usr.bin/vi/search.h b/usr.bin/vi/search.h
index 00feff6027c8..1483a04c7b71 100644
--- a/usr.bin/vi/search.h
+++ b/usr.bin/vi/search.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)search.h 8.7 (Berkeley) 11/18/93
+ * @(#)search.h 8.9 (Berkeley) 3/16/94
*/
#define RE_WSTART "[[:<:]]" /* Not-in-word search patterns. */
@@ -46,7 +46,6 @@
#define SEARCH_TERM 0x080 /* Search pattern should terminate. */
enum direction { NOTSET, FORWARD, BACKWARD };
-enum cdirection { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH };
/* Search functions. */
int b_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
diff --git a/usr.bin/vi/seq.c b/usr.bin/vi/seq.c
index 4d6d44956b0e..119e0b9dd9a7 100644
--- a/usr.bin/vi/seq.c
+++ b/usr.bin/vi/seq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)seq.c 8.21 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)seq.c 8.26 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "seq.h"
@@ -51,54 +61,81 @@ static char sccsid[] = "@(#)seq.c 8.21 (Berkeley) 12/9/93";
* Internal version to enter a sequence.
*/
int
-seq_set(sp, name, nlen, input, ilen, output, olen, stype, userdef)
+seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags)
SCR *sp;
char *name, *input, *output;
size_t nlen, ilen, olen;
enum seqtype stype;
- int userdef;
+ int flags;
{
SEQ *lastqp, *qp;
CHAR_T *p;
+ int sv_errno;
-#if defined(DEBUG) && 0
- TRACE(sp, "seq_set: name {%s} input {%s} output {%s}\n",
- name ? name : "", input, output);
-#endif
- /* Just replace the output field in any previous occurrence. */
+ /*
+ * An input string must always be present. The output string
+ * can be NULL, when set internally, that's how we throw away
+ * input.
+ *
+ * Just replace the output field if the string already set.
+ */
if ((qp = seq_find(sp, &lastqp, input, ilen, stype, NULL)) != NULL) {
- if ((p = v_strdup(sp, output, olen)) == NULL)
+ if (output == NULL || olen == 0) {
+ p = NULL;
+ olen = 0;
+ } else if ((p = v_strdup(sp, output, olen)) == NULL) {
+ sv_errno = errno;
goto mem1;
- FREE(qp->output, qp->olen);
+ }
+ if (qp->output != NULL)
+ free(qp->output);
qp->olen = olen;
qp->output = p;
return (0);
}
- /* Allocate and initialize space. */
+ /* Allocate and initialize SEQ structure. */
CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
- if (qp == NULL)
+ if (qp == NULL) {
+ sv_errno = errno;
goto mem1;
- if (name == NULL)
+ }
+
+ /* Name. */
+ if (name == NULL || nlen == 0)
qp->name = NULL;
- else if ((qp->name = v_strdup(sp, name, nlen)) == NULL)
+ else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) {
+ sv_errno = errno;
goto mem2;
- if ((qp->input = v_strdup(sp, input, ilen)) == NULL)
+ }
+ qp->nlen = nlen;
+
+ /* Input. */
+ if ((qp->input = v_strdup(sp, input, ilen)) == NULL) {
+ sv_errno = errno;
goto mem3;
- if ((qp->output = v_strdup(sp, output, olen)) == NULL) {
- FREE(qp->input, ilen);
+ }
+ qp->ilen = ilen;
+
+ /* Output. */
+ if (output == NULL) {
+ qp->output = NULL;
+ olen = 0;
+ } else if ((qp->output = v_strdup(sp, output, olen)) == NULL) {
+ sv_errno = errno;
+ free(qp->input);
mem3: if (qp->name != NULL)
- FREE(qp->name, nlen);
+ free(qp->name);
mem2: FREE(qp, sizeof(SEQ));
-mem1: msgq(sp, M_SYSERR, NULL);
+mem1: errno = sv_errno;
+ msgq(sp, M_SYSERR, NULL);
return (1);
}
+ qp->olen = olen;
+ /* Type, flags. */
qp->stype = stype;
- qp->nlen = nlen;
- qp->ilen = ilen;
- qp->olen = olen;
- qp->flags = userdef ? S_USERDEF : 0;
+ qp->flags = flags;
/* Link into the chain. */
if (lastqp == NULL) {
@@ -131,9 +168,10 @@ seq_delete(sp, input, ilen, stype)
LIST_REMOVE(qp, q);
if (qp->name != NULL)
- FREE(qp->name, qp->nlen);
- FREE(qp->input, qp->ilen);
- FREE(qp->output, qp->olen);
+ free(qp->name);
+ free(qp->input);
+ if (qp->output != NULL)
+ free(qp->output);
FREE(qp, sizeof(SEQ));
return (0);
}
@@ -159,7 +197,7 @@ seq_find(sp, lastqp, input, ilen, stype, ispartialp)
* Ispartialp is a location where we return if there was a
* partial match, i.e. if the string were extended it might
* match something.
- *
+ *
* XXX
* Overload the meaning of ispartialp; only the terminal key
* search doesn't want the search limited to complete matches,
@@ -221,28 +259,32 @@ seq_dump(sp, stype, isname)
{
CHNAME const *cname;
SEQ *qp;
- int cnt, len, olen, tablen;
+ int cnt, len, olen;
char *p;
cnt = 0;
cname = sp->gp->cname;
- tablen = O_VAL(sp, O_TABSTOP);
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
if (stype != qp->stype)
continue;
++cnt;
for (p = qp->input,
- olen = qp->ilen, len = 0; olen > 0; --olen, ++len)
- (void)ex_printf(EXCOOKIE, "%s", cname[*p++].name);
- for (len = tablen - len % tablen; len; --len)
- (void)ex_printf(EXCOOKIE, " ");
+ olen = qp->ilen, len = 0; olen > 0; --olen)
+ len += ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
- for (p = qp->output, olen = qp->olen; olen > 0; --olen)
- (void)ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen, len = 0; olen > 0; --olen)
+ len +=
+ ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ else
+ len = 0;
if (isname && qp->name != NULL) {
- for (len = tablen - len % tablen; len; --len)
- (void)ex_printf(EXCOOKIE, " ");
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
for (p = qp->name, olen = qp->nlen; olen > 0; --olen)
(void)ex_printf(EXCOOKIE,
"%s", cname[*p++].name);
@@ -263,36 +305,34 @@ seq_save(sp, fp, prefix, stype)
char *prefix;
enum seqtype stype;
{
- CHAR_T esc;
SEQ *qp;
size_t olen;
int ch;
char *p;
/* Write a sequence command for all keys the user defined. */
- (void)term_key_ch(sp, K_VLNEXT, &esc);
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
- if (!F_ISSET(qp, S_USERDEF))
- continue;
- if (stype != qp->stype)
+ if (!F_ISSET(qp, S_USERDEF) || stype != qp->stype)
continue;
if (prefix)
(void)fprintf(fp, "%s", prefix);
for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
ch = *p++;
- if (ch == esc || ch == '|' ||
+ if (ch == LITERAL_CH || ch == '|' ||
isblank(ch) || term_key_val(sp, ch) == K_NL)
- (void)putc(esc, fp);
+ (void)putc(LITERAL_CH, fp);
(void)putc(ch, fp);
}
(void)putc(' ', fp);
- for (p = qp->output, olen = qp->olen; olen > 0; --olen) {
- ch = *p++;
- if (ch == esc || ch == '|' ||
- term_key_val(sp, ch) == K_NL)
- (void)putc(esc, fp);
- (void)putc(ch, fp);
- }
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen; olen > 0; --olen) {
+ ch = *p++;
+ if (ch == LITERAL_CH || ch == '|' ||
+ term_key_val(sp, ch) == K_NL)
+ (void)putc(LITERAL_CH, fp);
+ (void)putc(ch, fp);
+ }
(void)putc('\n', fp);
}
return (0);
diff --git a/usr.bin/vi/seq.h b/usr.bin/vi/seq.h
index b9d9ac6cfd66..97f6e8ecd03c 100644
--- a/usr.bin/vi/seq.h
+++ b/usr.bin/vi/seq.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)seq.h 8.7 (Berkeley) 12/2/93
+ * @(#)seq.h 8.9 (Berkeley) 3/16/94
*/
/*
@@ -43,6 +43,9 @@
* starting with the corresponding character. This keeps us from walking
* the list unless it's necessary.
*
+ * The name and the output fields of a SEQ can be empty, i.e. NULL.
+ * Only the input field is required.
+ *
* XXX
* The fast-lookup bits are never turned off -- users don't usually unmap
* things, though, so it's probably not a big deal.
diff --git a/usr.bin/vi/sex/sex_confirm.c b/usr.bin/vi/sex/sex_confirm.c
index 8b55fadedaae..6fc11310cfd5 100644
--- a/usr.bin/vi/sex/sex_confirm.c
+++ b/usr.bin/vi/sex/sex_confirm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_confirm.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)sex_confirm.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/sex/sex_get.c b/usr.bin/vi/sex/sex_get.c
index 54b7343608d1..c0647e7af0d1 100644
--- a/usr.bin/vi/sex/sex_get.c
+++ b/usr.bin/vi/sex/sex_get.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_get.c 8.12 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)sex_get.c 8.19 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
-#include <stdlib.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -67,6 +77,9 @@ static void repaint __P((SCR *, int, char *, size_t));
(void)fprintf(stdout, "%s", "\b \b"); \
}
+#define TXT_VALID_EX \
+ (TXT_BEAUTIFY | TXT_CNTRLD | TXT_CR | TXT_NLECHO | TXT_PROMPT)
+
/*
* sex_get --
* Fill a buffer from the terminal for ex.
@@ -117,7 +130,7 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
} else
col = 0;
- iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
+ iflags = LF_ISSET(TXT_BEAUTIFY | TXT_MAPCOMMAND | TXT_MAPINPUT);
for (quoted = Q_NOTSET;;) {
(void)fflush(stdout);
@@ -133,6 +146,20 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
}
switch (ikey.value) {
+ case K_CNTRLD:
+ /*
+ * !!!
+ * Historically, ^D took (but then ignored) a count.
+ * For simplicity, we don't return unless it's the
+ * first character entered.
+ */
+ if (LF_ISSET(TXT_CNTRLD) && tp->len == 0) {
+ tp->len = 1;
+ tp->lb[0] = '\004';
+ tp->lb[1] = '\0';
+ return (INP_OK);
+ }
+ goto ins_ch;
case K_CNTRLZ:
sex_suspend(sp);
/* FALLTHROUGH */
@@ -146,7 +173,7 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
(void)putc('\n', stdout);
(void)fflush(stdout);
}
- /* Terminate with a newline, needed by filter. */
+ /* Terminate with a nul, needed by filter. */
tp->lb[tp->len] = '\0';
return (INP_OK);
case K_VERASE:
@@ -205,10 +232,8 @@ sex_get_notty(sp, ep, tiqh, prompt, flags)
u_int flags;
{
enum { Q_NOTSET, Q_THISCHAR } quoted;
- CHNAME const *cname; /* Character map. */
TEXT *tp; /* Input text structures. */
CH ikey; /* Input character. */
- size_t col; /* 0-N: screen column. */
u_int iflags; /* Input flags. */
int rval;
@@ -234,9 +259,6 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
}
- cname = sp->gp->cname;
- col = 0;
-
iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
for (quoted = Q_NOTSET;;) {
if (rval = term_key(sp, &ikey, iflags))
@@ -246,46 +268,40 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
BINC_RET(sp, tp->wd, tp->wd_len, tp->len + 1);
if (quoted == Q_THISCHAR)
- goto ins_ch;
+ goto insq_ch;
switch (ikey.value) {
- case K_CNTRLZ:
- sex_suspend(sp);
- /* FALLTHROUGH */
- case K_CNTRLR:
- break;
+ case K_CNTRLD:
+ /* See comment above, in sex_get(). */
+ if (LF_ISSET(TXT_CNTRLD) && tp->len == 1) {
+ tp->len = 1;
+ tp->lb[0] = '\004';
+ tp->lb[1] = '\0';
+ return (INP_OK);
+ }
+ goto ins_ch;
case K_CR:
case K_NL:
- /* Terminate with a newline, needed by filter. */
+ /* Terminate with a nul, needed by filter. */
tp->lb[tp->len] = '\0';
return (INP_OK);
- case K_VERASE:
- if (tp->len)
- --tp->len;
- break;
- case K_VKILL:
- tp->len = 0;
- break;
case K_VLNEXT:
quoted = Q_THISCHAR;
break;
- case K_VWERASE:
- /* Move to the last non-space character. */
- while (tp->len)
- if (!isblank(tp->lb[--tp->len])) {
- ++tp->len;
- break;
- }
-
- /* Move to the last space character. */
- while (tp->len)
- if (isblank(tp->lb[--tp->len])) {
- ++tp->len;
- break;
- }
- break;
default:
-ins_ch: tp->lb[tp->len] = ikey.ch;
+ /*
+ * See the discussion of TXT_BEAUTIFY in vi/v_ntext.c.
+ *
+ * Eliminate any unquoted, iscntrl() character that
+ * wasn't handled specially, except <tab> or <ff>.
+ */
+ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ikey.ch) &&
+ ikey.value != K_FORMFEED && ikey.value != K_TAB) {
+ msgq(sp, M_BERR,
+ "Illegal character; quote to enter.");
+ break;
+ }
+insq_ch: tp->lb[tp->len] = ikey.ch;
++tp->len;
quoted = Q_NOTSET;
break;
diff --git a/usr.bin/vi/sex/sex_refresh.c b/usr.bin/vi/sex/sex_refresh.c
index 0ba589299080..1b417de54dc6 100644
--- a/usr.bin/vi/sex/sex_refresh.c
+++ b/usr.bin/vi/sex/sex_refresh.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_refresh.c 8.5 (Berkeley) 11/18/93";
+static char sccsid[] = "@(#)sex_refresh.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "sex_screen.h"
diff --git a/usr.bin/vi/sex/sex_screen.c b/usr.bin/vi/sex/sex_screen.c
index d087d9f17476..9b87cbb73cd4 100644
--- a/usr.bin/vi/sex/sex_screen.c
+++ b/usr.bin/vi/sex/sex_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_screen.c 8.30 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)sex_screen.c 8.36 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "sex_screen.h"
@@ -61,11 +71,12 @@ sex_screen_init(sp)
sp->s_bell = sex_bell;
sp->s_bg = (int (*)())sex_nope;
sp->s_busy = (int (*)())sex_busy;
- sp->s_change = (int (*)())sex_noop;
- sp->s_chposition = (size_t (*)())sex_abort;
- sp->s_clear = (int (*)())sex_noop;
+ sp->s_change = (int (*)())sex_noop;
+ sp->s_clear = (int (*)())sex_noop;
+ sp->s_colpos = (size_t (*)())sex_abort;
sp->s_column = (int (*)())sex_abort;
sp->s_confirm = sex_confirm;
+ sp->s_crel = (int (*)())sex_nope;
sp->s_down = (int (*)())sex_abort;
sp->s_edit = sex_screen_edit;
sp->s_end = (int (*)())sex_noop;
@@ -75,14 +86,13 @@ sex_screen_init(sp)
sp->s_fg = (int (*)())sex_nope;
sp->s_fill = (int (*)())sex_abort;
sp->s_get = F_ISSET(sp->gp,
- G_ISFROMTTY) ? sex_get : sex_get_notty;
+ G_STDIN_TTY) ? sex_get : sex_get_notty;
sp->s_key_read = sex_key_read;
sp->s_optchange = (int (*)())sex_noop;
sp->s_position = (int (*)())sex_abort;
sp->s_rabs = (int (*)())sex_nope;
+ sp->s_rcm = (size_t (*)())sex_abort;
sp->s_refresh = sex_refresh;
- sp->s_relative = (size_t (*)())sex_abort;
- sp->s_rrel = (int (*)())sex_nope;
sp->s_split = (int (*)())sex_nope;
sp->s_suspend = sex_suspend;
sp->s_up = (int (*)())sex_abort;
@@ -123,11 +133,10 @@ sex_screen_edit(sp, ep)
EXF *ep;
{
struct termios rawt, t;
- GS *saved_gp;
int force, rval;
/* Initialize the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY))
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
SEX_RAW(t, rawt);
/* Write to the terminal. */
@@ -151,8 +160,6 @@ sex_screen_edit(sp, ep)
break;
}
- saved_gp = sp->gp;
-
force = 0;
switch (F_ISSET(sp, S_MAJOR_CHANGE)) {
case S_EXIT_FORCE:
@@ -176,7 +183,7 @@ sex_screen_edit(sp, ep)
}
/* Reset the terminal state. */
-ret: if (F_ISSET(sp->gp, G_ISFROMTTY) && SEX_NORAW(t))
+ret: if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t))
rval = 1;
return (rval);
}
diff --git a/usr.bin/vi/sex/sex_term.c b/usr.bin/vi/sex/sex_term.c
index 4e3980f21efd..c69193d59dcb 100644
--- a/usr.bin/vi/sex/sex_term.c
+++ b/usr.bin/vi/sex/sex_term.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_term.c 8.24 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)sex_term.c 8.28 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "script.h"
@@ -115,10 +125,10 @@ sigchk: while (F_ISSET(sp->gp,
* when trying to complete a map, but we're going to hang
* on the next read anyway.
*/
- if (!F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (!F_ISSET(sp->gp, G_STDIN_TTY)) {
if ((nr = read(STDIN_FILENO,
tty->ch + tty->next + tty->cnt,
- tty->len - (tty->next + tty->cnt))) > 0) {
+ tty->nelem - (tty->next + tty->cnt))) > 0) {
tty->cnt += *nrp = nr;
return (INP_OK);
}
@@ -185,7 +195,7 @@ sigchk: while (F_ISSET(sp->gp,
FD_CLR(sp->script->sh_master, &sp->rdfd);
maxfd = STDIN_FILENO;
}
-
+
switch (select(maxfd + 1, &sp->rdfd, NULL, NULL, tp)) {
case -1: /* Error or interrupt. */
if (errno == EINTR)
@@ -209,7 +219,7 @@ err: msgq(sp, M_SYSERR, "select");
switch (nr = read(STDIN_FILENO,
tty->ch + tty->next + tty->cnt,
- tty->len - (tty->next + tty->cnt))) {
+ tty->nelem - (tty->next + tty->cnt))) {
case 0: /* EOF. */
return (INP_EOF);
case -1: /* Error or interrupt. */
diff --git a/usr.bin/vi/sex/sex_util.c b/usr.bin/vi/sex/sex_util.c
index 25eb17f049c3..70d3d6b84774 100644
--- a/usr.bin/vi/sex/sex_util.c
+++ b/usr.bin/vi/sex/sex_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_util.c 8.9 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)sex_util.c 8.11 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "sex_screen.h"
@@ -73,24 +82,27 @@ int
sex_suspend(sp)
SCR *sp;
{
+ GS *gp;
struct termios t;
int rval;
/* Save ex/vi terminal settings, and restore the original ones. */
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
+ gp = sp->gp;
+ if (F_ISSET(gp, G_STDIN_TTY)) {
(void)tcgetattr(STDIN_FILENO, &t);
- (void)tcsetattr(STDIN_FILENO,
- TCSADRAIN, &sp->gp->original_termios);
+ if (F_ISSET(gp, G_TERMIOS_SET))
+ (void)tcsetattr(STDIN_FILENO,
+ TCSADRAIN, &gp->original_termios);
}
/* Kill the process group. */
- F_SET(sp->gp, G_SLEEPING);
+ F_SET(gp, G_SLEEPING);
if (rval = kill(0, SIGTSTP))
msgq(sp, M_SYSERR, "SIGTSTP");
- F_CLR(sp->gp, G_SLEEPING);
+ F_CLR(gp, G_SLEEPING);
/* Restore ex/vi terminal settings. */
- if (F_ISSET(sp->gp, G_ISFROMTTY))
+ if (F_ISSET(gp, G_STDIN_TTY))
(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &t);
return (rval);
diff --git a/usr.bin/vi/svi/svi_confirm.c b/usr.bin/vi/svi/svi_confirm.c
index 01546d7d7716..316c41ef0bdb 100644
--- a/usr.bin/vi/svi/svi_confirm.c
+++ b/usr.bin/vi/svi/svi_confirm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_confirm.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)svi_confirm.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
diff --git a/usr.bin/vi/svi/svi_ex.c b/usr.bin/vi/svi/svi_ex.c
index 7a83d409b3cd..5403b89683b7 100644
--- a/usr.bin/vi/svi/svi_ex.c
+++ b/usr.bin/vi/svi/svi_ex.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_ex.c 8.36 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)svi_ex.c 8.39 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -154,7 +164,7 @@ svi_ex_run(sp, ep, rp)
*/
if (F_ISSET(sp, S_MAJOR_CHANGE))
break;
-
+
/*
* If continue not required, and one or no lines, and there
* are no waiting messages, don't wait, but don't overwrite
@@ -173,7 +183,7 @@ svi_ex_run(sp, ep, rp)
/* If the screen is trashed, go into ex mode. */
if (!in_exmode && F_ISSET(sp, S_REFRESH)) {
/* Initialize the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (F_ISSET(sp->gp, G_STDIN_TTY)) {
SEX_RAW(t, rawt);
get = sex_get;
} else
@@ -181,7 +191,7 @@ svi_ex_run(sp, ep, rp)
flags = TXT_CR | TXT_NLECHO | TXT_PROMPT;
in_exmode = 1;
}
-
+
/*
* If the user hasn't already indicated that they're done,
* they may continue in ex mode by entering a ':'.
@@ -221,7 +231,7 @@ svi_ex_run(sp, ep, rp)
ret: if (in_exmode) {
/* Reset the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY) && SEX_NORAW(t))
+ if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t))
rval = 1;
F_SET(sp, S_REFRESH);
} else
diff --git a/usr.bin/vi/svi/svi_get.c b/usr.bin/vi/svi/svi_get.c
index 46f5f0e240cb..cf988dfc605d 100644
--- a/usr.bin/vi/svi/svi_get.c
+++ b/usr.bin/vi/svi/svi_get.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_get.c 8.19 (Berkeley) 1/2/94";
+static char sccsid[] = "@(#)svi_get.c 8.22 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -60,8 +70,8 @@ svi_get(sp, ep, tiqh, prompt, flags)
{
MARK save;
SMAP *esmp;
- recno_t bot_lno, top_lno;
- size_t bot_off, cnt, top_off;
+ recno_t bot_lno;
+ size_t bot_off, cnt;
int eval;
/*
@@ -74,8 +84,6 @@ svi_get(sp, ep, tiqh, prompt, flags)
*/
bot_lno = TMAP->lno;
bot_off = TMAP->off;
- top_lno = HMAP->lno;
- top_off = HMAP->off;
save.lno = sp->lno;
save.cno = sp->cno;
@@ -140,11 +148,13 @@ svi_get(sp, ep, tiqh, prompt, flags)
return (INP_ERR);
/*
- * Invalidate the cursor, the line never really existed. This fixes
- * a bug where the user searches for the last line on the screen + 1
- * and the refresh routine thinks that's where we just were.
+ * Invalidate the cursor and the line size cache, the line never
+ * really existed. This fixes bugs where the user searches for
+ * the last line on the screen + 1 and the refresh routine thinks
+ * that's where we just were.
*/
F_SET(SVP(sp), SVI_CUR_INVALID);
+ SVI_SCR_CFLUSH(SVP(sp));
return (eval ? INP_ERR : INP_OK);
}
diff --git a/usr.bin/vi/svi/svi_line.c b/usr.bin/vi/svi/svi_line.c
index 2370a0f5eea8..58710cfa0502 100644
--- a/usr.bin/vi/svi/svi_line.c
+++ b/usr.bin/vi/svi/svi_line.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_line.c 8.18 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)svi_line.c 8.22 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -165,11 +175,23 @@ svi_line(sp, ep, smp, yp, xp)
smp->c_sboff = smp->c_eboff = 0;
smp->c_scoff = smp->c_eclen = 0;
- if (p == NULL) {
- if (smp->lno != 1)
- ADDCH(listset && skip_screens == 0 ? '$' : '~');
- } else if (listset && skip_screens == 0)
- ADDCH('$');
+ /* Lots of special cases for empty lines. */
+ if (skip_screens == 0)
+ if (p == NULL) {
+ if (smp->lno == 1) {
+ if (listset) {
+ ch = '$';
+ goto empty;
+ }
+ } else {
+ ch = '~';
+ goto empty;
+ }
+ } else
+ if (listset) {
+ ch = '$';
+empty: ADDCH(ch);
+ }
clrtoeol();
MOVEA(sp, oldy, oldx);
@@ -384,9 +406,8 @@ svi_number(sp, ep)
EXF *ep;
{
SMAP *smp;
- recno_t lno;
size_t oldy, oldx;
- char *lp, *p, nbuf[10];
+ char *lp, nbuf[10];
/*
* Try and avoid getting the last line in the file, by getting the
@@ -410,7 +431,7 @@ svi_number(sp, ep)
if (ISINFOLINE(sp, smp))
break;
if (smp->lno != 1 && lp == NULL &&
- (p = file_gline(sp, ep, smp->lno, NULL)) == NULL)
+ file_gline(sp, ep, smp->lno, NULL) == NULL)
break;
MOVE(sp, smp - HMAP, 0);
(void)snprintf(nbuf, sizeof(nbuf), O_NUMBER_FMT, smp->lno);
diff --git a/usr.bin/vi/svi/svi_refresh.c b/usr.bin/vi/svi/svi_refresh.c
index 353c08178e20..b7a1df8cad0d 100644
--- a/usr.bin/vi/svi/svi_refresh.c
+++ b/usr.bin/vi/svi/svi_refresh.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_refresh.c 8.43 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)svi_refresh.c 8.49 (Berkeley) 3/11/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -72,8 +82,8 @@ svi_refresh(sp, ep)
if (svi_curses_end(sp) || svi_curses_init(sp))
return (1);
- /* Lose any svi_screens() cached information. */
- SVP(sp)->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
/*
* Fill the map, incidentally losing any svi_line()
@@ -150,7 +160,7 @@ svi_paint(sp, ep)
SVI_PRIVATE *svp;
recno_t lastline, lcnt;
size_t cwtotal, cnt, len, x, y;
- int ch, didpaint;
+ int ch, didpaint, leftright_warp;
char *p;
#define LNO sp->lno
@@ -159,7 +169,7 @@ svi_paint(sp, ep)
#define OCNO svp->ocno
#define SCNO svp->sc_col
- didpaint = 0;
+ didpaint = leftright_warp = 0;
svp = SVP(sp);
/*
@@ -170,14 +180,14 @@ svi_paint(sp, ep)
* displayed if the leftright flag is set.
*/
if (F_ISSET(sp, S_REFORMAT)) {
- /* Toss svi_screens() cached information. */
- SVP(sp)->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
/* Toss svi_line() cached information. */
if (svi_sm_fill(sp, ep, HMAP->lno, P_TOP))
return (1);
if (O_ISSET(sp, O_LEFTRIGHT) &&
- (cnt = svi_screens(sp, ep, LNO, &CNO)) != 1)
+ (cnt = svi_opt_screens(sp, ep, LNO, &CNO)) != 1)
for (smp = HMAP; smp <= TMAP; ++smp)
smp->off = cnt;
F_CLR(sp, S_REFORMAT);
@@ -209,7 +219,7 @@ svi_paint(sp, ep)
if (svi_sm_fill(sp, ep, LNO, P_BOTTOM))
return (1);
if (sp->t_rows == 1) {
- HMAP->off = svi_screens(sp, ep, LNO, &CNO);
+ HMAP->off = svi_opt_screens(sp, ep, LNO, &CNO);
goto paint;
}
F_SET(sp, S_REDRAW);
@@ -288,15 +298,16 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
}
/*
- * 3a: Line down.
+ * 3a: Line down, or current screen.
*/
if (LNO >= HMAP->lno) {
+ /* Current screen. */
if (LNO <= TMAP->lno)
goto adjust;
/*
- * If less than half a screen away, scroll down until the
- * line is on the screen.
+ * If less than half a screen above the line, scroll down
+ * until the line is on the screen.
*/
lcnt = svi_sm_nlines(sp, ep, TMAP, LNO, HALFTEXT(sp));
if (lcnt < HALFTEXT(sp)) {
@@ -305,14 +316,31 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
return (1);
goto adjust;
}
+ goto bottom;
+ }
+ /*
+ * 3b: Line up.
+ */
+ lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, HALFTEXT(sp));
+ if (lcnt < HALFTEXT(sp)) {
/*
- * If less than a full screen from the bottom of the file, put
- * the last line of the file on the bottom of the screen. The
- * calculation is safe because we know there's at least one
- * full screen of lines, otherwise couldn't have gotten here.
+ * If less than half a screen below the line, scroll up until
+ * the line is the first line on the screen. Special check so
+ * that if the screen has been emptied, we refill it.
*/
- if (file_lline(sp, ep, &lastline))
+ if (file_gline(sp, ep, HMAP->lno, &len) != NULL) {
+ while (lcnt--)
+ if (svi_sm_1down(sp, ep))
+ return (1);
+ goto adjust;
+ }
+
+ /*
+ * If less than a full screen from the bottom of the file,
+ * put the last line of the file on the bottom of the screen.
+ */
+bottom: if (file_lline(sp, ep, &lastline))
return (1);
tmp.lno = LNO;
tmp.off = 1;
@@ -323,29 +351,11 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
F_SET(sp, S_REDRAW);
goto adjust;
}
-
- /*
- * If more than a full screen from the last line of the file,
- * put the new line in the middle of the screen.
- */
+ /* It's not close, just put the line in the middle. */
goto middle;
}
/*
- * 3b: Line up.
- *
- * If less than half a screen away, scroll up until the line is
- * the first line on the screen.
- */
- lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, HALFTEXT(sp));
- if (lcnt < HALFTEXT(sp)) {
- while (lcnt--)
- if (svi_sm_1down(sp, ep))
- return (1);
- goto adjust;
- }
-
- /*
* If less than half a screen from the top of the file, put the first
* line of the file at the top of the screen. Otherwise, put the line
* in the middle of the screen.
@@ -378,7 +388,7 @@ middle: if (svi_sm_fill(sp, ep, LNO, P_MIDDLE))
*/
adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
(LNO == HMAP->lno || LNO == TMAP->lno)) {
- cnt = svi_screens(sp, ep, LNO, &CNO);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
if (LNO == HMAP->lno && cnt < HMAP->off)
if ((HMAP->off - cnt) > HALFTEXT(sp)) {
HMAP->off = cnt;
@@ -408,14 +418,10 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
*
* Decide cursor position. If the line has changed, the cursor has
* moved over a tab, or don't know where the cursor was, reparse the
- * line. Note, if we think that the cursor "hasn't moved", reparse
- * the line. This is 'cause if it hasn't moved, we've almost always
- * lost track of it.
- *
- * Otherwise, we've just moved over fixed-width characters, and can
- * calculate the left/right scrolling and cursor movement without
- * reparsing the line. Note that we don't know which (if any) of
- * the characters between the old and new cursor positions changed.
+ * line. Otherwise, we've just moved over fixed-width characters,
+ * and can calculate the left/right scrolling and cursor movement
+ * without reparsing the line. Note that we don't know which (if any)
+ * of the characters between the old and new cursor positions changed.
*
* XXX
* With some work, it should be possible to handle tabs quickly, at
@@ -477,7 +483,7 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
goto slow;
/*
- * Quit sanity check -- it's hard to figure out exactly when
+ * Quick sanity check -- it's hard to figure out exactly when
* we cross a screen boundary as we do in the cursor right
* movement. If cnt is so large that we're going to cross the
* boundary no matter what, stop now.
@@ -507,13 +513,19 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
cwtotal -= cname[ch].len - 1;
/*
- * If the new column moved us out of the current screen,
- * calculate a new screen.
+ * If the new column moved us off of the current logical line,
+ * calculate a new one. If doing leftright scrolling, we've
+ * moved off of the current screen, as well. Since most files
+ * don't have more than two screens, we optimize moving from
+ * screen 2 to screen 1.
*/
if (SCNO < cwtotal) {
lscreen: if (O_ISSET(sp, O_LEFTRIGHT)) {
+ cnt = HMAP->off == 2 ? 1 :
+ svi_opt_screens(sp, ep, LNO, &CNO);
for (smp = HMAP; smp <= TMAP; ++smp)
- --smp->off;
+ smp->off = cnt;
+ leftright_warp = 1;
goto paint;
}
goto slow;
@@ -546,15 +558,13 @@ lscreen: if (O_ISSET(sp, O_LEFTRIGHT)) {
*/
SCNO = cwtotal;
- /*
- * If the new column moved us out of the current screen,
- * calculate a new screen.
- */
+ /* See screen change comment in section 4a. */
if (SCNO >= SCREEN_COLS(sp)) {
if (O_ISSET(sp, O_LEFTRIGHT)) {
- SCNO -= SCREEN_COLS(sp);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
for (smp = HMAP; smp <= TMAP; ++smp)
- ++smp->off;
+ smp->off = cnt;
+ leftright_warp = 1;
goto paint;
}
goto slow;
@@ -582,13 +592,15 @@ fast: getyx(stdscr, y, x);
*/
slow: for (smp = HMAP; smp->lno != LNO; ++smp);
if (O_ISSET(sp, O_LEFTRIGHT)) {
- cnt = svi_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp);
if (cnt != HMAP->off) {
if (ISINFOLINE(sp, smp))
smp->off = cnt;
- else
+ else {
for (smp = HMAP; smp <= TMAP; ++smp)
smp->off = cnt;
+ leftright_warp = 1;
+ }
goto paint;
}
}
@@ -679,6 +691,16 @@ number: if (O_ISSET(sp, O_NUMBER) && F_ISSET(sp, S_RENUMBER) && !didpaint) {
/* Flush it all out. */
refresh();
+ /*
+ * XXX
+ * Recalculate the "most favorite" cursor position. Vi doesn't know
+ * that we've warped the screen and it's going to have a completely
+ * wrong idea about where the cursor should be. This is vi's problem,
+ * and fixing it here is a gross violation of layering.
+ */
+ if (leftright_warp)
+ (void)svi_column(sp, ep, &sp->rcm);
+
return (0);
}
@@ -721,7 +743,7 @@ lcont: /* Move to the message line and clear it. */
* Print up to the "more" message. Avoid the last character
* in the last line, some hardware doesn't like it.
*/
- if (svi_ncols(sp, p, mp->len, NULL) < sp->cols - 1)
+ if (svi_screens(sp, sp->ep, p, mp->len, 0, NULL) < sp->cols - 1)
len = sp->cols - 1;
else
len = (sp->cols - sizeof(MCONTMSG)) - 1;
diff --git a/usr.bin/vi/svi/svi_relative.c b/usr.bin/vi/svi/svi_relative.c
index 7daa972c8575..f57fb3e70823 100644
--- a/usr.bin/vi/svi/svi_relative.c
+++ b/usr.bin/vi/svi/svi_relative.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_relative.c 8.7 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)svi_relative.c 8.12 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -62,144 +72,270 @@ svi_column(sp, ep, cp)
}
/*
- * svi_relative --
- * Return the physical column from the line that will display a
- * character closest to the currently most attractive character
- * position. If it's not easy, uses the underlying routine that
- * really figures it out. It's broken into two parts because the
- * svi_lrelative routine handles "logical" offsets, which nobody
- * but the screen routines understand.
+ * svi_opt_screens --
+ * Return the screen columns necessary to display the line, or
+ * if specified, the physical character column within the line,
+ * including space required for the O_NUMBER and O_LIST options.
*/
size_t
-svi_relative(sp, ep, lno)
+svi_opt_screens(sp, ep, lno, cnop)
SCR *sp;
EXF *ep;
recno_t lno;
+ size_t *cnop;
{
- size_t cno;
+ size_t cols, screens;
- /* First non-blank character. */
- if (sp->rcmflags == RCM_FNB) {
- cno = 0;
- (void)nonblank(sp, ep, lno, &cno);
- return (cno);
- }
+ /*
+ * Check for a cached value. We maintain a cache because, if the
+ * line is large, this routine gets called repeatedly. One other
+ * hack, lots of time the cursor is on column one, which is an easy
+ * one.
+ */
+ if (cnop == NULL) {
+ if (SVP(sp)->ss_lno == lno)
+ return (SVP(sp)->ss_screens);
+ } else if (*cnop == 0)
+ return (1);
- /* First character is easy, and common. */
- if (sp->rcmflags != RCM_LAST && sp->rcm == 0)
- return (0);
+ /* Figure out how many columns the line/column needs. */
+ cols = svi_screens(sp, ep, NULL, 0, lno, cnop);
+
+ /* Leading number if O_NUMBER option set. */
+ if (O_ISSET(sp, O_NUMBER))
+ cols += O_NUMBER_LENGTH;
+
+ /* Trailing '$' if O_LIST option set. */
+ if (O_ISSET(sp, O_LIST) && cnop == NULL)
+ cols += sp->gp->cname['$'].len;
- return (svi_lrelative(sp, ep, lno, 1));
+ screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0));
+ if (screens == 0)
+ screens = 1;
+
+ /* Cache the value. */
+ if (cnop == NULL) {
+ SVP(sp)->ss_lno = lno;
+ SVP(sp)->ss_screens = screens;
+ }
+ return (screens);
}
/*
- * svi_lrelative --
- * Return the physical column from the line that will display a
- * character closest to the currently most attractive character
- * position. The offset is for the commands that move logical
- * distances, i.e. if it's a logical scroll the closest physical
- * distance is based on the logical line, not the physical line.
+ * svi_screens --
+ * Return the screen columns necessary to display the line, or,
+ * if specified, the physical character column within the line.
*/
size_t
-svi_lrelative(sp, ep, lno, off)
+svi_screens(sp, ep, lp, llen, lno, cnop)
SCR *sp;
EXF *ep;
+ char *lp;
+ size_t llen;
recno_t lno;
- size_t off;
+ size_t *cnop;
{
CHNAME const *cname;
- size_t len, llen, scno;
+ size_t chlen, cno, len, scno, tab_off;
int ch, listset;
- char *lp, *p;
+ char *p;
/* Need the line to go any further. */
- if ((lp = file_gline(sp, ep, lno, &len)) == NULL)
- return (0);
+ if (lp == NULL)
+ lp = file_gline(sp, ep, lno, &llen);
- /* Empty lines are easy. */
- if (len == 0)
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
return (0);
- /* Last character is easy, and common. */
- if (sp->rcmflags == RCM_LAST)
- return (len - 1);
-
- /* Discard logical lines. */
cname = sp->gp->cname;
listset = O_ISSET(sp, O_LIST);
- for (scno = 0, p = lp, llen = len; --off;) {
- for (; len && scno < sp->cols; --len)
- SCNO_INCREMENT;
- if (len == 0)
- return (llen - 1);
- scno -= sp->cols;
- }
- /* Step through the line until reach the right character. */
- while (len--) {
- SCNO_INCREMENT;
- if (scno >= sp->rcm) {
- /* Get the offset of this character. */
- len = p - lp;
-
- /*
- * May be the next character, not this one,
- * so check to see if we've gone too far.
- */
- if (scno == sp->rcm)
- return (len < llen - 1 ? len : llen - 1);
- /* It's this character. */
- return (len - 1);
+#define SET_CHLEN { \
+ chlen = (ch = *(u_char *)p++) == '\t' && \
+ !listset ? TAB_OFF(sp, tab_off) : cname[ch].len; \
+}
+#define TAB_RESET { \
+ /* \
+ * If past the end of the screen, and the character was a tab, \
+ * reset the screen column to 0. Otherwise, display the rest \
+ * of the character on the next line. \
+ */ \
+ if ((tab_off += chlen) >= sp->cols) \
+ if (ch == '\t') { \
+ tab_off = 0; \
+ scno -= scno % sp->cols; \
+ } else \
+ tab_off -= sp->cols; \
+}
+ p = lp;
+ len = llen;
+ scno = tab_off = 0;
+ if (cnop == NULL)
+ while (len--) {
+ SET_CHLEN;
+ scno += chlen;
+ TAB_RESET;
+ }
+ else
+ for (cno = *cnop; len--; --cno) {
+ SET_CHLEN;
+ scno += chlen;
+ TAB_RESET;
+ if (cno == 0)
+ break;
}
+ return (scno);
+}
+
+/*
+ * svi_rcm --
+ * Return the physical column from the line that will display a
+ * character closest to the currently most attractive character
+ * position (which is stored as a screen column).
+ */
+size_t
+svi_rcm(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ size_t cno, len;
+
+ /* First non-blank character. */
+ if (sp->rcmflags == RCM_FNB) {
+ cno = 0;
+ (void)nonblank(sp, ep, lno, &cno);
+ return (cno);
}
- /* No such character; return start of last character. */
- return (llen - 1);
+
+ /* First character is easy, and common. */
+ if (sp->rcmflags != RCM_LAST && HMAP->off == 1 && sp->rcm == 0)
+ return (0);
+
+ /* Last character is easy, and common. */
+ if (sp->rcmflags == RCM_LAST)
+ return (file_gline(sp,
+ ep, lno, &len) == NULL || len == 0 ? 0 : len - 1);
+
+ /*
+ * Get svi_cm_private() to do the hard work. If doing leftright
+ * scrolling, we use the current screen offset, otherwise, use
+ * the first screen, i.e. an offset of 1.
+ *
+ * XXX
+ * I'm not sure that an offset of 1 is right. What happens is that
+ * the vi main loop calls us for the VM_RCM case. By using an offset
+ * of 1, we're assuming that every VM_RCM command changes lines, and
+ * that we want to position on the first screen for that line. This
+ * is currently the way it works, but it's not clean. I'd prefer it if
+ * we could find the SMAP entry the cursor references, and use that
+ * screen offset. Unfortunately, that's not going to be easy, as we
+ * don't keep that information around and it may be expensive to get.
+ */
+ return (svi_cm_private(sp, ep, lno,
+ O_ISSET(sp, O_LEFTRIGHT) ? HMAP->off : 1, sp->rcm));
}
/*
- * svi_chposition --
+ * svi_cm_public --
* Return the physical column from the line that will display a
- * character closest to the specified column.
+ * character closest to the specified screen column.
+ *
+ * The extra interface is because it's called by vi, which doesn't
+ * have a handle on the SMAP structure.
*/
size_t
-svi_chposition(sp, ep, lno, cno)
+svi_cm_public(sp, ep, lno, cno)
SCR *sp;
EXF *ep;
recno_t lno;
size_t cno;
{
+ return (svi_cm_private(sp, ep, lno, HMAP->off, cno));
+}
+
+/*
+ * svi_cm_private --
+ * Return the physical column from the line that will display a
+ * character closest to the specified screen column, taking into
+ * account the screen offset.
+ *
+ * The offset is for the commands that move logical distances, i.e.
+ * if it's a logical scroll the closest physical distance is based
+ * on the logical line, not the physical line.
+ */
+size_t
+svi_cm_private(sp, ep, lno, off, cno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t off, cno;
+{
CHNAME const *cname;
- size_t len, llen, scno;
+ size_t chlen, len, llen, scno, tab_off;
int ch, listset;
char *lp, *p;
/* Need the line to go any further. */
- if ((lp = file_gline(sp, ep, lno, &llen)) == NULL)
- return (0);
+ lp = file_gline(sp, ep, lno, &llen);
- /* Empty lines are easy. */
- if (llen == 0)
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
return (0);
- /* Step through the line until reach the right character. */
cname = sp->gp->cname;
listset = O_ISSET(sp, O_LIST);
- for (scno = 0, len = llen, p = lp; len--;) {
- SCNO_INCREMENT;
- if (scno >= cno) {
- /* Get the offset of this character. */
- len = p - lp;
-
- /*
- * May be the next character, not this one,
- * so check to see if we've gone too far.
- */
- if (scno == cno)
- return (len < llen - 1 ? len : llen - 1);
- /* It's this character. */
- return (len - 1);
+
+ /* Discard screen (logical) lines. */
+ for (scno = 0, p = lp, len = llen; --off;) {
+ while (len-- && scno < sp->cols)
+ scno += (ch = *(u_char *)p++) == '\t' &&
+ !listset ? TAB_OFF(sp, scno) : cname[ch].len;
+
+ /*
+ * If reached the end of the physical line, return
+ * the last physical character in the line.
+ */
+ if (len == 0)
+ return (llen - 1);
+
+ /*
+ * If the character was a tab, reset the screen column to 0.
+ * Otherwise, the rest of the character is displayed on the
+ * next line.
+ */
+ if (ch == '\t')
+ scno = 0;
+ else
+ scno -= sp->cols;
+ }
+
+ /* Step through the line until reach the right character or EOL. */
+ for (tab_off = scno; len--;) {
+ SET_CHLEN;
+
+ /*
+ * If we've reached the specific character, there are three
+ * cases.
+ *
+ * 1: scno == cno, i.e. the current character ends at the
+ * screen character we care about.
+ * a: off < llen - 1, i.e. not the last character in
+ * the line, return the offset of the next character.
+ * b: else return the offset of the last character.
+ * 2: scno != cno, i.e. this character overruns the character
+ * we care about, return the offset of this character.
+ */
+ if ((scno += chlen) >= cno) {
+ off = p - lp;
+ return (scno == cno ?
+ (off < llen - 1 ? off : llen - 1) : off - 1);
}
+
+ TAB_RESET;
}
- /* No such character; return start of last character. */
+
+ /* No such character; return the start of the last character. */
return (llen - 1);
}
diff --git a/usr.bin/vi/svi/svi_screen.c b/usr.bin/vi/svi/svi_screen.c
index 16e2c36d8609..71f2d36818bb 100644
--- a/usr.bin/vi/svi/svi_screen.c
+++ b/usr.bin/vi/svi/svi_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,27 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_screen.c 8.57 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)svi_screen.c 8.69 (Berkeley) 3/16/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -52,8 +61,6 @@ static char sccsid[] = "@(#)svi_screen.c 8.57 (Berkeley) 1/9/94";
static void d_to_h __P((SCR *, char *));
static int svi_initscr_kluge __P((SCR *, struct termios *));
-static void svi_keypad __P((SCR *, int));
-static void svi_keypad_pc __P((int));
/*
* svi_screen_init --
@@ -68,10 +75,11 @@ svi_screen_init(sp)
sp->s_bg = svi_bg;
sp->s_busy = svi_busy;
sp->s_change = svi_change;
- sp->s_chposition = svi_chposition;
sp->s_clear = svi_clear;
+ sp->s_colpos = svi_cm_public;
sp->s_column = svi_column;
sp->s_confirm = svi_confirm;
+ sp->s_crel = svi_crel;
sp->s_down = svi_sm_down;
sp->s_edit = svi_screen_edit;
sp->s_end = svi_screen_end;
@@ -85,9 +93,8 @@ svi_screen_init(sp)
sp->s_optchange = svi_optchange;
sp->s_position = svi_sm_position;
sp->s_rabs = svi_rabs;
+ sp->s_rcm = svi_rcm;
sp->s_refresh = svi_refresh;
- sp->s_relative = svi_relative;
- sp->s_rrel = svi_rrel;
sp->s_split = svi_split;
sp->s_suspend = svi_suspend;
sp->s_up = svi_sm_up;
@@ -110,8 +117,8 @@ svi_screen_copy(orig, sp)
sp->svi_private = nsvi;
/* INITIALIZED AT SCREEN CREATE. */
- /* Lose svi_screens() cached information. */
- nsvi->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(nsvi);
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
if (orig == NULL) {
@@ -283,7 +290,7 @@ svi_curses_init(sp)
*/
if (svi_initscr_kluge(sp, &t))
return (1);
-
+
/*
* Start the screen. Initscr() doesn't provide useful error values
* or messages. Generally, either malloc failed or the terminal
@@ -293,18 +300,18 @@ svi_curses_init(sp)
errno = 0;
if (initscr() == NULL) {
if (errno)
- msgq(sp, M_SYSERR, "initscr failed");
+ msgq(sp, M_SYSERR, "Initscr failed");
else
- msgq(sp, M_ERR, "Error: initscr failed.");
- if ((p = getenv("TERM")) == NULL)
+ msgq(sp, M_ERR, "Initscr failed.");
+ if ((p = getenv("TERM")) == NULL || !strcmp(p, "unknown"))
msgq(sp, M_ERR,
- "Error: no terminal environment variable set.");
+ "No TERM environment variable set, or TERM set to \"unknown\".");
else if (tgetent(kbuf, p) != 1)
msgq(sp, M_ERR,
-"Error: %s: unknown terminal type, or terminal lacking necessary features.", p);
+"%s: unknown terminal type, or terminal lacks necessary features.", p);
else
msgq(sp, M_ERR,
- "Error: %s: terminal type lacking necessary features.", p);
+ "%s: terminal type lacks necessary features.", p);
return (1);
}
@@ -319,9 +326,9 @@ svi_curses_init(sp)
idlok(stdscr, 1); /* Use hardware insert/delete line. */
/*
- * Vi wants the cursor keys in application mode. The historic version
- * of curses had no way to do this, and the newer versions (System V)
- * only enable it through the wgetch() interface. Do it roughly, here.
+ * Put the cursor keys into application mode. Historic versions
+ * of curses had no way to do this, and the newer versions (SunOS,
+ * System V) only enable it through the wgetch() interface.
*/
svi_keypad(sp, 1);
@@ -375,11 +382,7 @@ svi_curses_init(sp)
sp->t_maxrows = sp->rows - 1;
/* Create the screen map. */
- if ((HMAP = malloc(SIZE_HMAP(sp) * sizeof(SMAP))) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- memset(HMAP, 0, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
TMAP = HMAP + (sp->t_rows - 1);
F_SET(sp->gp, G_CURSES_INIT); /* Curses initialized. */
@@ -388,11 +391,11 @@ svi_curses_init(sp)
}
/*
- * svi_rrel --
+ * svi_crel --
* Change the relative size of the current screen.
*/
int
-svi_rrel(sp, count)
+svi_crel(sp, count)
SCR *sp;
long count;
{
@@ -436,45 +439,13 @@ svi_curses_end(sp)
TCSASOFT | TCSADRAIN, &sp->gp->s5_curses_botch);
F_CLR(sp->gp, G_CURSES_S5CB);
+ /* Restore the cursor keys to normal mode. */
svi_keypad(sp, 0);
endwin();
return (0);
}
/*
- * svi_keypad --
- * Put the keypad/cursor arrows into or out of application mode.
- */
-static void
-svi_keypad(sp, on)
- SCR *sp;
- int on;
-{
- char *sbp, *t, kbuf[2048], sbuf[128];
-
- if (tgetent(kbuf, O_STR(sp, O_TERM)) != 1)
- return;
- sbp = sbuf;
- if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL)
- return;
- (void)tputs(t, 0, svi_keypad_pc);
-}
-
-/*
- * svi_keypad_pc --
- * putchar routine for tputs().
- */
-static void
-svi_keypad_pc(argch)
- int argch;
-{
- char ch;
-
- ch = argch;
- (void)write(STDOUT_FILENO, &ch, sizeof(ch));
-}
-
-/*
* svi_initscr_kluge --
* Read all of the waiting keys before calling initscr().
*/
@@ -520,8 +491,10 @@ d_to_h(sp, emsg)
for (hidden = 0;
(tsp = sp->gp->dq.cqh_first) != (void *)&sp->gp->dq; ++hidden) {
- if (_HMAP(tsp) != NULL)
+ if (_HMAP(tsp) != NULL) {
FREE(_HMAP(tsp), SIZE_HMAP(tsp) * sizeof(SMAP));
+ _HMAP(tsp) = NULL;
+ }
CIRCLEQ_REMOVE(&sp->gp->dq, tsp, q);
CIRCLEQ_INSERT_TAIL(&sp->gp->hq, tsp, q);
}
diff --git a/usr.bin/vi/svi/svi_screen.h b/usr.bin/vi/svi/svi_screen.h
index 4bf754473df9..05ae068ccbb8 100644
--- a/usr.bin/vi/svi/svi_screen.h
+++ b/usr.bin/vi/svi/svi_screen.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)svi_screen.h 8.30 (Berkeley) 12/22/93
+ * @(#)svi_screen.h 8.38 (Berkeley) 3/15/94
*/
/*
@@ -76,7 +76,8 @@ typedef struct _svi_private {
size_t extotalcount; /* Ex overwrite count. */
size_t exlcontinue; /* Ex line continue value. */
- /* svi_screens() cache information. */
+ /* svi_opt_screens() cache information. */
+#define SVI_SCR_CFLUSH(svp) svp->ss_lno = OOBLNO
recno_t ss_lno; /* 1-N: Line number. */
size_t ss_screens; /* Return value. */
@@ -124,14 +125,18 @@ typedef struct _svi_private {
/* Small screen test. */
#define ISSMALLSCREEN(sp) ((sp)->t_minrows != (sp)->t_maxrows)
- /* Next tab offset. */
+/*
+ * Next tab offset.
+ *
+ * !!!
+ * There are problems with how the historical vi handled tabs. For example,
+ * by doing "set ts=3" and building lines that fold, you can get it to step
+ * through tabs as if they were spaces and move inserted characters to new
+ * positions when <esc> is entered. I think that nvi does tabs correctly,
+ * but there may be some historical incompatibilities.
+ */
#define TAB_OFF(sp, c) (O_VAL(sp, O_TABSTOP) - (c) % O_VAL(sp, O_TABSTOP))
-
-#define SCNO_INCREMENT /* Step through line. */\
- scno += (ch = *(u_char *)p++) == '\t' && !listset ? \
- TAB_OFF(sp, scno) : cname[ch].len
-
/* Move in a screen (absolute), and fail if it doesn't work. */
#define MOVEA(sp, lno, cno) { \
if (move(lno, cno) == ERR) { \
@@ -186,11 +191,12 @@ void svi_bell __P((SCR *));
int svi_bg __P((SCR *));
int svi_busy __P((SCR *, char const *));
int svi_change __P((SCR *, EXF *, recno_t, enum operation));
-size_t svi_chposition __P((SCR *, EXF *, recno_t, size_t));
+size_t svi_cm_public __P((SCR *, EXF *, recno_t, size_t));
int svi_column __P((SCR *, EXF *, size_t *));
enum confirm
svi_confirm __P((SCR *, EXF *, MARK *, MARK *));
int svi_clear __P((SCR *));
+int svi_crel __P((SCR *, long));
int svi_ex_cmd __P((SCR *, EXF *, struct _excmdarg *, MARK *));
int svi_ex_run __P((SCR *, EXF *, MARK *));
int svi_ex_write __P((void *, const char *, int));
@@ -198,10 +204,9 @@ int svi_fg __P((SCR *, CHAR_T *));
enum input
svi_get __P((SCR *, EXF *, TEXTH *, int, u_int));
int svi_optchange __P((SCR *, int));
-int svi_rabs __P((SCR *, long));
+int svi_rabs __P((SCR *, long, enum adjust));
+size_t svi_rcm __P((SCR *, EXF *, recno_t));
int svi_refresh __P((SCR *, EXF *));
-size_t svi_relative __P((SCR *, EXF *, recno_t));
-int svi_rrel __P((SCR *, long));
int svi_screen_copy __P((SCR *, SCR *));
int svi_screen_edit __P((SCR *, EXF *));
int svi_screen_end __P((SCR *));
@@ -214,17 +219,19 @@ int svi_suspend __P((SCR *));
int svi_swap __P((SCR *, SCR **, char *));
/* Private routines. */
+size_t svi_cm_private __P((SCR *, EXF *, recno_t, size_t, size_t));
int svi_curses_end __P((SCR *));
int svi_curses_init __P((SCR *));
int svi_divider __P((SCR *));
int svi_init __P((SCR *));
int svi_join __P((SCR *, SCR **));
+void svi_keypad __P((SCR *, int));
int svi_line __P((SCR *, EXF *, SMAP *, size_t *, size_t *));
-size_t svi_lrelative __P((SCR *, EXF *, recno_t, size_t));
-size_t svi_ncols __P((SCR *, u_char *, size_t, size_t *));
int svi_number __P((SCR *, EXF *));
+size_t svi_opt_screens __P((SCR *, EXF *, recno_t, size_t *));
int svi_paint __P((SCR *, EXF *));
-size_t svi_screens __P((SCR *, EXF *, recno_t, size_t *));
+int svi_putchar __P((int));
+size_t svi_screens __P((SCR *, EXF *, char *, size_t, recno_t, size_t *));
int svi_sm_1down __P((SCR *, EXF *));
int svi_sm_1up __P((SCR *, EXF *));
int svi_sm_cursor __P((SCR *, EXF *, SMAP **));
diff --git a/usr.bin/vi/svi/svi_smap.c b/usr.bin/vi/svi/svi_smap.c
index 5bcb6e220f3d..3e2ac3812e89 100644
--- a/usr.bin/vi/svi/svi_smap.c
+++ b/usr.bin/vi/svi/svi_smap.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_smap.c 8.29 (Berkeley) 11/30/93";
+static char sccsid[] = "@(#)svi_smap.c 8.37 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -107,13 +117,13 @@ svi_change(sp, ep, lno, op)
F_SET(SVP(sp), SVI_SCREENDIRTY);
- /* Flush cached information from svi_screens(). */
- SVP(sp)->ss_lno = OOBLNO;
-
/* Invalidate the cursor, if it's on this line. */
if (sp->lno == lno)
F_SET(SVP(sp), SVI_CUR_INVALID);
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
+
getyx(stdscr, oldy, oldx);
switch (op) {
@@ -160,10 +170,10 @@ svi_sm_fill(sp, ep, lno, pos)
enum position pos;
{
SMAP *p, tmp;
-
+
/* Flush all cached information from the SMAP. */
for (p = HMAP; p <= TMAP; ++p)
- SMAP_FLUSH(p);
+ SMAP_FLUSH(p);
switch (pos) {
case P_FILL:
@@ -180,7 +190,7 @@ svi_sm_fill(sp, ep, lno, pos)
/* See if less than half a screen from the bottom. */
if (file_lline(sp, ep, &tmp.lno))
return (1);
- tmp.off = svi_screens(sp, ep, tmp.lno, NULL);
+ tmp.off = svi_opt_screens(sp, ep, tmp.lno, NULL);
if (svi_sm_nlines(sp, ep,
&tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) {
TMAP->lno = tmp.lno;
@@ -216,7 +226,7 @@ middle: p = HMAP + (TMAP - HMAP) / 2;
case P_BOTTOM:
if (lno != OOBLNO) {
TMAP->lno = lno;
- TMAP->off = svi_screens(sp, ep, lno, NULL);
+ TMAP->off = svi_opt_screens(sp, ep, lno, NULL);
}
/* If we fail, guess that the file is too small. */
bottom: for (p = TMAP; p > HMAP; --p)
@@ -278,9 +288,12 @@ svi_sm_delete(sp, ep, lno)
* Find the line in the map, and count the number of screen lines
* which display any part of the deleted line.
*/
- for (p = HMAP; p->lno != lno; ++p);
- for (cnt_orig = 1, t = p + 1;
- t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ cnt_orig = 1;
+ else
+ for (cnt_orig = 1, t = p + 1;
+ t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
TOO_WEIRD;
@@ -288,7 +301,7 @@ svi_sm_delete(sp, ep, lno)
MOVE(sp, p - HMAP, 0);
if (svi_deleteln(sp, cnt_orig))
return (1);
-
+
/* Shift the screen map up. */
memmove(p, p + cnt_orig, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP));
@@ -326,8 +339,11 @@ svi_sm_insert(sp, ep, lno)
* Find the line in the map, find out how many screen lines
* needed to display the line.
*/
- for (p = HMAP; p->lno != lno; ++p);
- cnt_orig = svi_screens(sp, ep, lno, NULL);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ cnt_orig = 1;
+ else
+ cnt_orig = svi_opt_screens(sp, ep, lno, NULL);
TOO_WEIRD;
@@ -380,9 +396,15 @@ svi_sm_reset(sp, ep, lno)
* for the line is the same as the number needed for the new one.
* If so, repaint, otherwise do it the hard way.
*/
- for (p = HMAP; p->lno != lno; ++p);
- for (cnt_orig = 0, t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
- cnt_new = svi_screens(sp, ep, lno, NULL);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ t = p;
+ cnt_orig = cnt_new = 1;
+ } else {
+ for (cnt_orig = 0,
+ t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
+ cnt_new = svi_opt_screens(sp, ep, lno, NULL);
+ }
TOO_WEIRD;
@@ -431,7 +453,7 @@ svi_sm_reset(sp, ep, lno)
MOVE(sp, p - HMAP, 0);
if (svi_deleteln(sp, diff))
return (1);
-
+
/* Shift the screen map up. */
memmove(p, p + diff, (((TMAP - p) - diff) + 1) * sizeof(SMAP));
@@ -514,7 +536,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
return (1);
if (tmp.lno > TMAP->lno &&
!file_gline(sp, ep, tmp.lno, NULL) ||
- tmp.off > svi_screens(sp, ep, tmp.lno, NULL)) {
+ tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) {
if (!cursor_move || ignore_cursor || p == TMAP) {
v_eof(sp, ep, NULL);
return (1);
@@ -522,12 +544,12 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
if (svi_sm_next(sp, ep, p, &tmp))
return (1);
if (!file_gline(sp, ep, tmp.lno, NULL) ||
- tmp.off > svi_screens(sp, ep, tmp.lno, NULL)) {
+ tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) {
v_eof(sp, ep, NULL);
return (1);
}
}
-
+
/*
* Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
*
@@ -570,7 +592,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
/* If the line doesn't exist, we're done. */
if (TMAP->lno != tmp.lno && !file_gline(sp, ep, tmp.lno, NULL))
break;
-
+
/* Scroll the screen cursor up one logical line. */
if (svi_sm_1up(sp, ep))
return (1);
@@ -616,7 +638,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
*/
if (p->lno != svmap.lno || p->off != svmap.off) {
rp->lno = p->lno;
- rp->cno = svi_lrelative(sp, ep, p->lno, p->off);
+ rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm);
}
return (0);
}
@@ -762,7 +784,7 @@ svi_sm_down(sp, ep, rp, count, cursor_move)
/* If the line doesn't exist, we're done. */
if (HMAP->lno == 1 && HMAP->off == 1)
break;
-
+
/* Scroll the screen and cursor down one logical line. */
if (svi_sm_1down(sp, ep))
return (1);
@@ -804,7 +826,7 @@ svi_sm_down(sp, ep, rp, count, cursor_move)
*/
if (p->lno != svmap.lno || p->off != svmap.off) {
rp->lno = p->lno;
- rp->cno = svi_lrelative(sp, ep, p->lno, p->off);
+ rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm);
}
return (0);
}
@@ -876,7 +898,7 @@ svi_sm_next(sp, ep, p, t)
t->lno = p->lno + 1;
t->off = p->off;
} else {
- lcnt = svi_screens(sp, ep, p->lno, NULL);
+ lcnt = svi_opt_screens(sp, ep, p->lno, NULL);
if (lcnt == p->off) {
t->lno = p->lno + 1;
t->off = 1;
@@ -907,7 +929,7 @@ svi_sm_prev(sp, ep, p, t)
t->off = p->off - 1;
} else {
t->lno = p->lno - 1;
- t->off = svi_screens(sp, ep, t->lno, NULL);
+ t->off = svi_opt_screens(sp, ep, t->lno, NULL);
}
return (t->lno == 0);
}
@@ -969,34 +991,66 @@ svi_sm_position(sp, ep, rp, cnt, pos)
{
SMAP *smp;
recno_t last;
-
+
switch (pos) {
case P_TOP:
+ /*
+ * !!!
+ * Historically, an invalid count to the H command failed.
+ * We do nothing special here, just making sure that H in
+ * an empty screen works.
+ */
if (cnt > TMAP - HMAP)
- goto err;
+ goto sof;
smp = HMAP + cnt;
+ if (cnt && file_gline(sp, ep, smp->lno, NULL) == NULL) {
+sof: msgq(sp, M_BERR, "Movement past the end-of-screen.");
+ return (1);
+ }
break;
case P_MIDDLE:
- if (cnt > (TMAP - HMAP) / 2)
- goto err;
- smp = (HMAP + (TMAP - HMAP) / 2) + cnt;
- goto eof;
+ /*
+ * !!!
+ * Historically, a count to the M command was ignored.
+ * If the screen isn't filled, find the middle of what's
+ * real and move there.
+ */
+ if (file_gline(sp, ep, TMAP->lno, NULL) == NULL) {
+ if (file_lline(sp, ep, &last))
+ return (1);
+ for (smp = TMAP; smp->lno > last && smp > HMAP; --smp);
+ if (smp > HMAP)
+ smp -= (smp - HMAP) / 2;
+ } else
+ smp = (HMAP + (TMAP - HMAP) / 2) + cnt;
+ break;
case P_BOTTOM:
- if (cnt > TMAP - HMAP) {
-err: msgq(sp, M_BERR, "Movement past the end-of-screen.");
- return (1);
- }
+ /*
+ * !!!
+ * Historically, an invalid count to the L command failed.
+ * If the screen isn't filled, find the bottom of what's
+ * real and try to offset from there.
+ */
+ if (cnt > TMAP - HMAP)
+ goto eof;
smp = TMAP - cnt;
-eof: if (file_gline(sp, ep, smp->lno, NULL) == NULL) {
+ if (file_gline(sp, ep, smp->lno, NULL) == NULL) {
if (file_lline(sp, ep, &last))
return (1);
for (; smp->lno > last && smp > HMAP; --smp);
+ if (cnt > smp - HMAP) {
+eof: msgq(sp, M_BERR,
+ "Movement past the beginning-of-screen.");
+ return (1);
+ }
+ smp -= cnt;
}
break;
default:
abort();
}
+ /* Make sure that the cached information is valid. */
if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL))
return (1);
rp->lno = smp->lno;
@@ -1030,12 +1084,12 @@ svi_sm_nlines(sp, ep, from_sp, to_lno, max)
if (from_sp->lno > to_lno) {
lcnt = from_sp->off - 1; /* Correct for off-by-one. */
for (lno = from_sp->lno; --lno >= to_lno && lcnt <= max;)
- lcnt += svi_screens(sp, ep, lno, NULL);
+ lcnt += svi_opt_screens(sp, ep, lno, NULL);
} else {
lno = from_sp->lno;
- lcnt = (svi_screens(sp, ep, lno, NULL) - from_sp->off) + 1;
+ lcnt = (svi_opt_screens(sp, ep, lno, NULL) - from_sp->off) + 1;
for (; ++lno < to_lno && lcnt <= max;)
- lcnt += svi_screens(sp, ep, lno, NULL);
+ lcnt += svi_opt_screens(sp, ep, lno, NULL);
}
return (lcnt);
}
diff --git a/usr.bin/vi/svi/svi_split.c b/usr.bin/vi/svi/svi_split.c
index f6be03d38365..2c1a6c063eac 100644
--- a/usr.bin/vi/svi/svi_split.c
+++ b/usr.bin/vi/svi/svi_split.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_split.c 8.29 (Berkeley) 12/22/93";
+static char sccsid[] = "@(#)svi_split.c 8.36 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -72,7 +82,7 @@ svi_split(sp, argv)
/* Get a new screen. */
if (screen_init(sp, &tsp, 0))
return (1);
- MALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
if (_HMAP(tsp) == NULL)
return (1);
@@ -100,7 +110,7 @@ svi_split(sp, argv)
* The columns in the screen don't change.
*/
tsp->cols = sp->cols;
-
+
cnt = svi_sm_cursor(sp, sp->ep, &smp) ? 0 : smp - HMAP;
if (cnt <= half) { /* Parent is top half. */
/* Child. */
@@ -431,7 +441,7 @@ svi_swap(csp, nsp, name)
return (0);
}
*nsp = sp;
-
+
/* Save the old screen's cursor information. */
csp->frp->lno = csp->lno;
csp->frp->cno = csp->cno;
@@ -485,7 +495,7 @@ svi_swap(csp, nsp, name)
* a bunch of screens had to be hidden.
*/
if (HMAP == NULL)
- MALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
TMAP = HMAP + (sp->t_rows - 1);
/* Fill the map. */
@@ -510,9 +520,10 @@ svi_swap(csp, nsp, name)
* Change the absolute size of the current screen.
*/
int
-svi_rabs(sp, count)
+svi_rabs(sp, count, adj)
SCR *sp;
long count;
+ enum adjust adj;
{
SCR *g, *s;
@@ -522,8 +533,20 @@ svi_rabs(sp, count)
*/
if (count == 0)
return (0);
- if (count < 0) {
- count = -count;
+ if (adj == A_SET) {
+ if (sp->t_maxrows == count)
+ return (0);
+ if (sp->t_maxrows > count) {
+ adj = A_DECREASE;
+ count = sp->t_maxrows - count;
+ } else {
+ adj = A_INCREASE;
+ count = count - sp->t_maxrows;
+ }
+ }
+ if (adj == A_DECREASE) {
+ if (count < 0)
+ count = -count;
s = sp;
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
goto toosmall;
@@ -545,7 +568,7 @@ svi_rabs(sp, count)
if (s == NULL) {
if ((s = sp->q.cqe_prev) == (void *)&sp->gp->dq) {
toobig: msgq(sp, M_BERR, "The screen cannot %s.",
- count < 0 ? "shrink" : "grow");
+ adj == A_DECREASE ? "shrink" : "grow");
return (1);
}
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) {
@@ -558,24 +581,28 @@ toosmall: msgq(sp, M_BERR,
}
}
- /* Update the screens. */
+ /*
+ * Update the screens; we could optimize the reformatting of the
+ * screen, but this isn't likely to be a common enough operation
+ * to make it worthwhile.
+ */
g->rows += count;
g->t_rows += count;
if (g->t_minrows == g->t_maxrows)
g->t_minrows += count;
g->t_maxrows += count;
- _TMAP(g) = _HMAP(g) + (g->t_rows - 1);
+ _TMAP(g) += count;
(void)status(g, g->ep, g->lno, 0);
- F_SET(g, S_REDRAW);
+ F_SET(g, S_REFORMAT);
s->rows -= count;
s->t_rows -= count;
s->t_maxrows -= count;
if (s->t_minrows > s->t_maxrows)
s->t_minrows = s->t_maxrows;
- _TMAP(s) = _HMAP(s) + (s->t_rows - 1);
+ _TMAP(s) -= count;
(void)status(s, s->ep, s->lno, 0);
- F_SET(s, S_REDRAW);
+ F_SET(s, S_REFORMAT);
return (0);
}
diff --git a/usr.bin/vi/svi/svi_util.c b/usr.bin/vi/svi/svi_util.c
index 0da531d8db26..ac655007f58e 100644
--- a/usr.bin/vi/svi/svi_util.c
+++ b/usr.bin/vi/svi/svi_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,115 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_util.c 8.26 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)svi_util.c 8.33 (Berkeley) 3/10/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
-#include "vcmd.h"
+#include "../vi/vcmd.h"
#include "excmd.h"
#include "svi_screen.h"
/*
- * svi_screens --
- * Return the number of screens required by the line, or,
- * if a column is specified, by the column within the line.
- */
-size_t
-svi_screens(sp, ep, lno, cnop)
- SCR *sp;
- EXF *ep;
- recno_t lno;
- size_t *cnop;
-{
- size_t cols, len, screens;
- char *p;
-
- /*
- * Check for single cached value. The cache is because, if
- * the line is large, this routine gets called repeatedly.
- * One other hack, lots of time the user is on column one,
- * which is an easy one.
- */
- if (cnop == NULL) {
- if (SVP(sp)->ss_lno == lno)
- return (SVP(sp)->ss_screens);
- } else if (*cnop == 0)
- return (1);
-
- /* Get a copy of the line. */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL || len == 0)
- return (1);
-
- /* Figure out how many columns the line/column needs. */
- cols = svi_ncols(sp, p, len, cnop);
-
- /* Leading number if O_NUMBER option set. */
- if (O_ISSET(sp, O_NUMBER))
- cols += O_NUMBER_LENGTH;
-
- /* Trailing '$' if O_LIST option set. */
- if (O_ISSET(sp, O_LIST) && cnop == NULL)
- cols += sp->gp->cname['$'].len;
-
- screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0));
- if (cnop == NULL) {
- SVP(sp)->ss_lno = lno;
- SVP(sp)->ss_screens = screens;
- }
- return (screens);
-}
-
-/*
- * svi_ncols --
- * Return the number of columns required by the line, or,
- * if a column is specified, by the column within the line.
- */
-size_t
-svi_ncols(sp, p, len, cnop)
- SCR *sp;
- u_char *p;
- size_t len, *cnop;
-{
- CHNAME const *cname;
- size_t cno_cnt, scno;
- int ch, listset;
-
- cname = sp->gp->cname;
- listset = O_ISSET(sp, O_LIST);
-
- if (cnop == NULL)
- for (scno = 0; len; --len)
- SCNO_INCREMENT;
- else
- for (cno_cnt = *cnop, scno = 0; len; --len) {
- SCNO_INCREMENT;
- if (cno_cnt == 0)
- break;
- --cno_cnt;
- }
- return (scno);
-}
-
-/*
- * bell_putchar --
- * Functional version of putchar, for tputs.
- */
-static void
-bell_putchar(ch)
- int ch;
-{
- (void)putchar(ch);
-}
-
-/*
* vbell --
* Set up the visual bell information. Broken out into a
* separate routine so don't allocate 4K every time we beep.
@@ -166,12 +84,15 @@ vbell(sp)
"No visual bell for %s terminal type", s);
return (1);
}
- len = t - b2;
+ if ((len = t - b2) == 0)
+ return (1);
+
+ /* Free the old one, save the new one. */
MALLOC_RET(sp, s, char *, len);
memmove(s, b2, len);
if (SVP(sp)->VB != NULL)
free(SVP(sp)->VB);
- SVP(sp)->VB = t;
+ SVP(sp)->VB = s;
return (0);
}
@@ -185,7 +106,7 @@ svi_bell(sp)
{
if (O_ISSET(sp, O_FLASH) && !F_ISSET(SVP(sp), SVI_NO_VBELL))
if (SVP(sp)->VB != NULL) {
- (void)tputs(SVP(sp)->VB, 1, bell_putchar);
+ (void)tputs(SVP(sp)->VB, 1, svi_putchar);
(void)fflush(stdout);
} else {
if (vbell(sp))
@@ -217,7 +138,7 @@ svi_optchange(sp, opt)
F_SET(sp, S_RESIZE);
break;
case O_WINDOW:
- if (svi_rrel(sp, O_VAL(sp, O_WINDOW)))
+ if (svi_crel(sp, O_VAL(sp, O_WINDOW)))
return (1);
break;
}
@@ -237,17 +158,44 @@ svi_busy(sp, msg)
SCR *sp;
char const *msg;
{
- MOVE(sp, INFOLINE(sp), 0);
- if (msg) {
- ADDSTR(msg);
- clrtoeol();
+ /*
+ * search.c:f_search() is called from ex/ex_tag.c:ex_tagfirst(),
+ * which runs before the screen really exists. Make sure we don't
+ * step on anything.
+ */
+ if (F_ISSET(sp->gp, G_CURSES_INIT)) {
+ MOVE(sp, INFOLINE(sp), 0);
+ if (msg) {
+ ADDSTR(msg);
+ clrtoeol();
+ }
+ refresh();
+ F_SET(SVP(sp), SVI_CUR_INVALID);
}
- refresh();
- F_SET(SVP(sp), SVI_CUR_INVALID);
return (0);
}
/*
+ * svi_keypad --
+ * Put the keypad/cursor arrows into or out of application mode.
+ */
+void
+svi_keypad(sp, on)
+ SCR *sp;
+ int on;
+{
+ char *sbp, *t, kbuf[2048], sbuf[128];
+
+ if (tgetent(kbuf, O_STR(sp, O_TERM)) != 1)
+ return;
+ sbp = sbuf;
+ if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL)
+ return;
+ (void)tputs(t, 0, svi_putchar);
+ (void)fflush(stdout);
+}
+
+/*
* svi_clear --
* Clear from the row down to the end of the screen.
*/
@@ -279,6 +227,9 @@ svi_suspend(sp)
struct termios t;
int rval;
+ /* Restore the cursor keys to normal mode. */
+ svi_keypad(sp, 0);
+
/*
* XXX
* See comment in svi_curses_init().
@@ -297,10 +248,24 @@ svi_suspend(sp)
if (F_ISSET(sp->gp, G_CURSES_S5CB))
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
+ /* Put the cursor keys into application mode. */
+ svi_keypad(sp, 0);
+
return (rval);
}
/*
+ * svi_putchar --
+ * Functional version of putchar, for tputs.
+ */
+int
+svi_putchar(ch)
+ int ch;
+{
+ return putchar(ch);
+}
+
+/*
* svi_gdbrefresh --
* Stub routine so can flush out screen changes using gdb.
*/
diff --git a/usr.bin/vi/term.c b/usr.bin/vi/term.c
index d23fa80c4d45..ba7b016f3d85 100644
--- a/usr.bin/vi/term.c
+++ b/usr.bin/vi/term.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)term.c 8.41 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)term.c 8.56 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "seq.h"
-static int keycmp __P((const void *, const void *));
+static int keycmp __P((const void *, const void *));
+static void termkeyset __P((GS *, int, int));
/*
* If we're reading less than 20 characters, up the size of the tty buffer.
@@ -56,39 +66,67 @@ static int keycmp __P((const void *, const void *));
* possible if a map is large enough.
*/
#define term_read_grow(sp, tty) \
- (tty)->len - (tty)->cnt >= 20 ? 0 : __term_read_grow(sp, tty)
-static int __term_read_grow __P((SCR *, IBUF *));
+ (tty)->nelem - (tty)->cnt >= 20 ? 0 : __term_read_grow(sp, tty, 64)
+static int __term_read_grow __P((SCR *, IBUF *, int));
/*
* XXX
* THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
*/
typedef struct _tklist {
- char *ts; /* Key's termcap string. */
- char *output; /* Corresponding vi command. */
- char *name; /* Name. */
+ char *ts; /* Key's termcap string. */
+ char *output; /* Corresponding vi command. */
+ char *name; /* Name. */
+ u_char value; /* Special value (for lookup). */
} TKLIST;
-static TKLIST const tklist[] = {
- {"kA", "O", "insert line"},
- {"kD", "x", "delete character"},
- {"kd", "j", "cursor down"},
- {"kE", "D", "delete to eol"},
- {"kF", "\004", "scroll down"},
- {"kH", "$", "go to eol"},
- {"kh", "^", "go to sol"},
- {"kI", "i", "insert at cursor"},
- {"kL", "dd", "delete line"},
- {"kl", "h", "cursor left"},
- {"kN", "\006", "page down"},
- {"kP", "\002", "page up"},
- {"kR", "\025", "scroll up"},
- {"kS", "dG", "delete to end of screen"},
- {"kr", "l", "cursor right"},
- {"ku", "k", "cursor up"},
+static TKLIST const c_tklist[] = { /* Command mappings. */
+ {"kA", "O", "insert line"},
+ {"kD", "x", "delete character"},
+ {"kd", "j", "cursor down"},
+ {"kE", "D", "delete to eol"},
+ {"kF", "\004", "scroll down"},
+ {"kH", "$", "go to eol"},
+ {"kh", "^", "go to sol"},
+ {"kI", "i", "insert at cursor"},
+ {"kL", "dd", "delete line"},
+ {"kl", "h", "cursor left"},
+ {"kN", "\006", "page down"},
+ {"kP", "\002", "page up"},
+ {"kR", "\025", "scroll up"},
+ {"kS", "dG", "delete to end of screen"},
+ {"kr", "l", "cursor right"},
+ {"ku", "k", "cursor up"},
+ {NULL},
+};
+static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
+ {"kl", NULL, "cursor erase", K_VERASE},
+ {NULL},
+};
+static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
+ {"kd", NULL, "cursor down"},
+ {"ku", NULL, "cursor up"},
+ {"kr", " ", "cursor space"},
{NULL},
};
/*
+ * !!!
+ * Historic ex/vi always used:
+ *
+ * ^D: autoindent deletion
+ * ^H: last character deletion
+ * ^W: last word deletion
+ * ^Q: quote the next character (if not used in flow control).
+ * ^V: quote the next character
+ *
+ * regardless of the user's choices for these characters. The user's erase
+ * and kill characters worked in addition to these characters. Ex was not
+ * completely consistent with this scheme, as it did map the scroll command
+ * to the user's current EOF character. This implementation wires down the
+ * above characters, but in addition uses the VERASE, VINTR, VKILL and VWERASE
+ * characters described by the user's termios structure. We don't do the EOF
+ * mapping for ex, but I think I'm unlikely to get caught on that one.
+ *
* XXX
* THIS REQUIRES THAT ALL SCREENS SHARE A SPECIAL KEY SET.
*/
@@ -97,26 +135,32 @@ typedef struct _keylist {
CHAR_T ch; /* Key. */
} KEYLIST;
static KEYLIST keylist[] = {
- {K_CARAT, '^'},
- {K_CNTRLR, '\022'},
- {K_CNTRLT, '\024'},
- {K_CNTRLZ, '\032'},
- {K_COLON, ':'},
- {K_CR, '\r'},
- {K_ESCAPE, '\033'},
- {K_FORMFEED, '\f'},
- {K_NL, '\n'},
- {K_RIGHTBRACE, '}'},
- {K_RIGHTPAREN, ')'},
- {K_TAB, '\t'},
- {K_VEOF, '\004'},
- {K_VERASE, '\b'},
- {K_VINTR, '\003'},
- {K_VKILL, '\025'},
- {K_VLNEXT, '\026'},
- {K_VWERASE, '\027'},
- {K_ZERO, '0'},
+ {K_CARAT, '^'}, /* ^ */
+ {K_CNTRLD, '\004'}, /* ^D */
+ {K_CNTRLR, '\022'}, /* ^R */
+ {K_CNTRLT, '\024'}, /* ^T */
+ {K_CNTRLZ, '\032'}, /* ^Z */
+ {K_COLON, ':'}, /* : */
+ {K_CR, '\r'}, /* \r */
+ {K_ESCAPE, '\033'}, /* ^[ */
+ {K_FORMFEED, '\f'}, /* \f */
+ {K_NL, '\n'}, /* \n */
+ {K_RIGHTBRACE, '}'}, /* } */
+ {K_RIGHTPAREN, ')'}, /* ) */
+ {K_TAB, '\t'}, /* \t */
+ {K_VERASE, '\b'}, /* \b */
+ {K_VINTR, '\003'}, /* ^C */
+ {K_VKILL, '\025'}, /* ^U */
+ {K_VLNEXT, '\021'}, /* ^Q */
+ {K_VLNEXT, '\026'}, /* ^V */
+ {K_VWERASE, '\027'}, /* ^W */
+ {K_ZERO, '0'}, /* 0 */
+ {K_NOTUSED, 0}, /* VERASE, VINTR, VKILL, VWERASE */
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
};
+static int nkeylist = (sizeof(keylist) / sizeof(keylist[0])) - 4;
/*
* term_init --
@@ -131,7 +175,6 @@ term_init(sp)
GS *gp;
KEYLIST *kp;
TKLIST const *tkp;
- cc_t ch;
int cnt;
char *sbp, *t, buf[2 * 1024], sbuf[128];
@@ -143,50 +186,31 @@ term_init(sp)
gp = sp->gp;
gp->cname = asciiname; /* XXX */
- /* Set keys found in the termios structure. */
-#define TERMSET(name, val) { \
- if ((ch = gp->original_termios.c_cc[name]) != _POSIX_VDISABLE) \
- for (kp = keylist;; ++kp) \
- if (kp->value == (val)) { \
- kp->ch = ch; \
- break; \
- } \
-}
-/*
- * VEOF, VERASE, VKILL are required by POSIX 1003.1-1990,
- * VWERASE is a 4.4BSD extension.
- */
-#ifdef VEOF
- TERMSET(VEOF, K_VEOF);
-#endif
#ifdef VERASE
- TERMSET(VERASE, K_VERASE);
+ termkeyset(gp, VERASE, K_VERASE);
#endif
#ifdef VINTR
- TERMSET(VINTR, K_VINTR);
+ termkeyset(gp, VINTR, K_VINTR);
#endif
#ifdef VKILL
- TERMSET(VKILL, K_VKILL);
+ termkeyset(gp, VKILL, K_VKILL);
#endif
#ifdef VWERASE
- TERMSET(VWERASE, K_VWERASE);
+ termkeyset(gp, VWERASE, K_VWERASE);
#endif
-
/* Sort the special key list. */
- qsort(keylist,
- sizeof(keylist) / sizeof(keylist[0]), sizeof(keylist[0]), keycmp);
+ qsort(keylist, nkeylist, sizeof(keylist[0]), keycmp);
/* Initialize the fast lookup table. */
CALLOC_RET(sp,
gp->special_key, u_char *, MAX_FAST_KEY + 1, sizeof(u_char));
- for (gp->max_special = 0, kp = keylist,
- cnt = sizeof(keylist) / sizeof(keylist[0]); cnt--; ++kp) {
+ for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) {
if (gp->max_special < kp->value)
gp->max_special = kp->value;
if (kp->ch <= MAX_FAST_KEY)
gp->special_key[kp->ch] = kp->value;
}
-
+
/* Set key sequences found in the termcap entry. */
switch (tgetent(buf, O_STR(sp, O_TERM))) {
case -1:
@@ -199,7 +223,8 @@ term_init(sp)
return (0);
}
- for (tkp = tklist; tkp->name != NULL; ++tkp) {
+ /* Command mappings. */
+ for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
sbp = sbuf;
if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
continue;
@@ -207,55 +232,111 @@ term_init(sp)
tkp->output, strlen(tkp->output), SEQ_COMMAND, 0))
return (1);
}
+ /* Input mappings needing to be looked up. */
+ for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+ for (kp = keylist;; ++kp)
+ if (kp->value == tkp->value)
+ break;
+ if (kp == NULL)
+ continue;
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), &kp->ch, 1, SEQ_INPUT, 0))
+ return (1);
+ }
+ /* Input mappings that are already set or are text deletions. */
+ for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+ if (tkp->output == NULL) {
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), NULL, 0, SEQ_INPUT, 0))
+ return (1);
+ } else
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), tkp->output, strlen(tkp->output),
+ SEQ_INPUT, 0))
+ return (1);
+ }
return (0);
}
/*
+ * termkeyset --
+ * Set keys found in the termios structure. VERASE, VINTR and VKILL are
+ * required by POSIX 1003.1-1990, VWERASE is a 4.4BSD extension. We've
+ * left four open slots in the keylist table, if these values exist, put
+ * them into place. Note, they may reset (or duplicate) values already
+ * in the table, so we check for that first.
+ */
+static void
+termkeyset(gp, name, val)
+ GS *gp;
+ int name, val;
+{
+ KEYLIST *kp;
+ cc_t ch;
+
+ if (!F_ISSET(gp, G_TERMIOS_SET))
+ return;
+ if ((ch = gp->original_termios.c_cc[(name)]) == _POSIX_VDISABLE)
+ return;
+
+ /* Check for duplication. */
+ for (kp = keylist; kp->value != K_NOTUSED; ++kp)
+ if (kp->ch == ch) {
+ kp->value = val;
+ return;
+ }
+ /* Add a new entry. */
+ if (kp->value == K_NOTUSED) {
+ keylist[nkeylist].ch = ch;
+ keylist[nkeylist].value = val;
+ ++nkeylist;
+ }
+}
+
+/*
* term_push --
* Push keys onto the front of a buffer.
*
* There is a single input buffer in ex/vi. Characters are read onto the
* end of the buffer by the terminal input routines, and pushed onto the
- * front of the buffer various other functions in ex/vi. Each key has an
- * associated flag value, which indicates if it has already been quoted,
- * if it is the result of a mapping or an abbreviation.
- */
+ * front of the buffer by various other functions in ex/vi. Each key has
+ * an associated flag value, which indicates if it has already been quoted,
+ * if it is the result of a mapping or an abbreviation, as well as a count
+ * of the number of times it has been mapped.
+ */
int
-term_push(sp, s, len, cmap, flags)
+term_push(sp, s, nchars, cmap, flags)
SCR *sp;
CHAR_T *s; /* Characters. */
- size_t len; /* Number of chars. */
+ size_t nchars; /* Number of chars. */
u_int cmap; /* Map count. */
u_int flags; /* CH_* flags. */
{
IBUF *tty;
- size_t nlen;
/* If we have room, stuff the keys into the buffer. */
tty = sp->gp->tty;
- if (len <= tty->next ||
- (tty->ch != NULL && tty->cnt == 0 && len <= tty->len)) {
+ if (nchars <= tty->next ||
+ (tty->ch != NULL && tty->cnt == 0 && nchars <= tty->nelem)) {
if (tty->cnt != 0)
- tty->next -= len;
- tty->cnt += len;
- memmove(tty->ch + tty->next, s, len * sizeof(CHAR_T));
- memset(tty->chf + tty->next, flags, len);
- memset(tty->cmap + tty->next, cmap, len);
+ tty->next -= nchars;
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + tty->next, s, nchars);
+ MEMSET(tty->chf + tty->next, flags, nchars);
+ MEMSET(tty->cmap + tty->next, cmap, nchars);
return (0);
}
/* Get enough space plus a little extra. */
- nlen = tty->cnt + len;
- if (nlen > tty->len) {
- size_t olen;
-
- nlen += 64;
- olen = tty->len;
- BINC_RET(sp, tty->ch, olen, nlen * sizeof(tty->ch[0]));
- olen = tty->len;
- BINC_RET(sp, tty->chf, olen, nlen * sizeof(tty->chf[0]));
- BINC_RET(sp, tty->cmap, tty->len, nlen * sizeof(tty->cmap[0]));
- }
+ if (tty->cnt + nchars >= tty->nelem &&
+ __term_read_grow(sp, tty, MAX(nchars, 64)))
+ return (1);
/*
* If there are currently characters in the queue, shift them up,
@@ -263,26 +344,26 @@ term_push(sp, s, len, cmap, flags)
*/
#define TERM_PUSH_SHIFT 30
if (tty->cnt) {
- memmove(tty->ch + TERM_PUSH_SHIFT + len,
- tty->ch + tty->next, tty->cnt * sizeof(tty->ch[0]));
- memmove(tty->chf + TERM_PUSH_SHIFT + len,
- tty->chf + tty->next, tty->cnt * sizeof(tty->chf[0]));
- memmove(tty->cmap + TERM_PUSH_SHIFT + len,
- tty->cmap + tty->next, tty->cnt * sizeof(tty->cmap[0]));
+ MEMMOVE(tty->ch + TERM_PUSH_SHIFT + nchars,
+ tty->ch + tty->next, tty->cnt);
+ MEMMOVE(tty->chf + TERM_PUSH_SHIFT + nchars,
+ tty->chf + tty->next, tty->cnt);
+ MEMMOVE(tty->cmap + TERM_PUSH_SHIFT + nchars,
+ tty->cmap + tty->next, tty->cnt);
}
/* Put the new characters into the queue. */
tty->next = TERM_PUSH_SHIFT;
- tty->cnt += len;
- memmove(tty->ch + TERM_PUSH_SHIFT, s, len * sizeof(tty->ch[0]));
- memset(tty->chf + TERM_PUSH_SHIFT, flags, len * sizeof(tty->chf[0]));
- memset(tty->cmap + TERM_PUSH_SHIFT, cmap, len * sizeof(tty->cmap[0]));
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + TERM_PUSH_SHIFT, s, nchars);
+ MEMSET(tty->chf + TERM_PUSH_SHIFT, flags, nchars);
+ MEMSET(tty->cmap + TERM_PUSH_SHIFT, cmap, nchars);
return (0);
}
/*
- * Remove characters from the queue, simultaneously clearing the
- * flag and map counts.
+ * Remove characters from the queue, simultaneously clearing the flag
+ * and map counts.
*/
#define QREM_HEAD(q, len) { \
size_t __off = (q)->next; \
@@ -290,8 +371,8 @@ term_push(sp, s, len, cmap, flags)
tty->chf[__off] = 0; \
tty->cmap[__off] = 0; \
} else { \
- memset(tty->chf + __off, 0, len); \
- memset(tty->cmap + __off, 0, len); \
+ MEMSET(tty->chf + __off, 0, len); \
+ MEMSET(tty->cmap + __off, 0, len); \
} \
if (((q)->cnt -= len) == 0) \
(q)->next = 0; \
@@ -304,8 +385,8 @@ term_push(sp, s, len, cmap, flags)
tty->chf[__off] = 0; \
tty->cmap[__off] = 0; \
} else { \
- memset(tty->chf + __off, 0, len); \
- memset(tty->cmap + __off, 0, len); \
+ MEMSET(tty->chf + __off, 0, len); \
+ MEMSET(tty->cmap + __off, 0, len); \
} \
if (((q)->cnt -= len) == 0) \
(q)->next = 0; \
@@ -386,7 +467,7 @@ term_key(sp, chp, flags)
GS *gp;
IBUF *tty;
SEQ *qp;
- int cmap, ispartial, nr;
+ int cmap, ispartial, nr, itear;
gp = sp->gp;
tty = gp->tty;
@@ -410,6 +491,9 @@ loop: if (tty->cnt == 0) {
F_CLR(sp, S_UPDATE_MODE);
}
+ /* If no limit on remaps, set it up so the user can interrupt. */
+ itear = O_ISSET(sp, O_REMAPMAX) ? 0 : !intr_init(sp);
+
/* If the key is mappable and should be mapped, look it up. */
if (!(tty->chf[tty->next] & CH_NOMAP) &&
LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT)) {
@@ -437,10 +521,12 @@ remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt,
* unmapped.
*/
if (ispartial) {
- if (term_read_grow(sp, tty))
- return (INP_ERR);
+ if (term_read_grow(sp, tty)) {
+ rval = INP_ERR;
+ goto ret;
+ }
if (rval = sp->s_key_read(sp, &nr, tp))
- return (rval);
+ goto ret;
if (nr)
goto remap;
goto nomap;
@@ -455,31 +541,45 @@ remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt,
* character of the map is it, pretend we haven't seen the
* character.
*/
- if (LF_ISSET(TXT_MAPNODIGIT) && !isdigit(qp->output[0]))
+ if (LF_ISSET(TXT_MAPNODIGIT) &&
+ qp->output != NULL && !isdigit(qp->output[0]))
goto not_digit_ch;
/*
* Only permit a character to be remapped a certain number
* of times before we figure that it's not going to finish.
*/
- if ((cmap = tty->cmap[tty->next]) > MAX_MAP_COUNT) {
- term_map_flush(sp, "Character remapped too many times");
- return (INP_ERR);
- }
+ if (O_ISSET(sp, O_REMAPMAX)) {
+ if ((cmap = tty->cmap[tty->next]) > MAX_MAP_COUNT)
+ goto flush;
+ } else if (F_ISSET(sp, S_INTERRUPTED)) {
+flush: term_map_flush(sp, "Character remapped too many times");
+ rval = INP_ERR;
+ goto ret;
+ } else
+ cmap = 0;
/* Delete the mapped characters from the queue. */
QREM_HEAD(tty, qp->ilen);
+ /* If keys mapped to nothing, go get more. */
+ if (qp->output == NULL)
+ goto loop;
+
/* If remapping characters, push the character on the queue. */
if (O_ISSET(sp, O_REMAP)) {
- if (term_push(sp, qp->output, qp->olen, ++cmap, 0))
- return (INP_ERR);
+ if (term_push(sp, qp->output, qp->olen, ++cmap, 0)) {
+ rval = INP_ERR;
+ goto ret;
+ }
goto newmap;
}
/* Else, push the characters on the queue and return one. */
- if (term_push(sp, qp->output, qp->olen, 0, CH_NOMAP))
- return (INP_ERR);
+ if (term_push(sp, qp->output, qp->olen, 0, CH_NOMAP)) {
+ rval = INP_ERR;
+ goto ret;
+ }
}
nomap: ch = tty->ch[tty->next];
@@ -487,7 +587,8 @@ nomap: ch = tty->ch[tty->next];
not_digit_ch: chp->ch = NOT_DIGIT_CH;
chp->value = 0;
chp->flags = 0;
- return (INP_OK);
+ rval = INP_OK;
+ goto ret;
}
/* Fill in the return information. */
@@ -497,18 +598,11 @@ not_digit_ch: chp->ch = NOT_DIGIT_CH;
/* Delete the character from the queue. */
QREM_HEAD(tty, 1);
+ rval = INP_OK;
- /*
- * O_BEAUTIFY eliminates all control characters except
- * escape, form-feed, newline and tab.
- */
- if (isprint(ch) ||
- !LF_ISSET(TXT_BEAUTIFY) || !O_ISSET(sp, O_BEAUTIFY) ||
- chp->value == K_ESCAPE || chp->value == K_FORMFEED ||
- chp->value == K_NL || chp->value == K_TAB)
- return (INP_OK);
-
- goto loop;
+ret: if (itear)
+ intr_end(sp);
+ return (rval);
}
/*
@@ -529,8 +623,8 @@ term_ab_flush(sp, msg)
QREM_HEAD(tty, 1);
} while (tty->cnt && tty->chf[tty->next] & CH_ABBREVIATED);
msgq(sp, M_ERR, "%s: keys flushed.", msg);
-
}
+
/*
* term_map_flush --
* Flush any mapped keys.
@@ -549,7 +643,6 @@ term_map_flush(sp, msg)
QREM_HEAD(tty, 1);
} while (tty->cnt && tty->cmap[tty->next]);
msgq(sp, M_ERR, "%s: keys flushed.", msg);
-
}
/*
@@ -575,7 +668,7 @@ term_user_key(sp, chp)
/* Wait and read another key. */
if (rval = sp->s_key_read(sp, &nr, NULL))
return (rval);
-
+
/* Fill in the return information. */
tty = sp->gp->tty;
chp->ch = tty->ch[tty->next + (tty->cnt - 1)];
@@ -586,7 +679,7 @@ term_user_key(sp, chp)
return (INP_OK);
}
-/*
+/*
* term_key_queue --
* Read the keys off of the terminal queue until it's empty.
*/
@@ -613,26 +706,6 @@ term_key_queue(sp)
}
/*
- * term_key_ch --
- * Fill in the key for a value.
- */
-int
-term_key_ch(sp, val, chp)
- SCR *sp;
- int val;
- CHAR_T *chp;
-{
- KEYLIST *kp;
-
- for (kp = keylist;; ++kp)
- if (kp->value == val) {
- *chp = kp->ch;
- return (0);
- }
- /* NOTREACHED */
-}
-
-/*
* __term_key_val --
* Fill in the value for a key. This routine is the backup
* for the term_key_val() macro.
@@ -645,9 +718,8 @@ __term_key_val(sp, ch)
KEYLIST k, *kp;
k.ch = ch;
- kp = bsearch(&k, keylist,
- sizeof(keylist) / sizeof(keylist[0]), sizeof(keylist[0]), keycmp);
- return (kp == NULL ? 0 : kp->value);
+ kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), keycmp);
+ return (kp == NULL ? K_NOTUSED : kp->value);
}
/*
@@ -656,26 +728,24 @@ __term_key_val(sp, ch)
* the term_read_grow() macro.
*/
static int
-__term_read_grow(sp, tty)
+__term_read_grow(sp, tty, add)
SCR *sp;
IBUF *tty;
+ int add;
{
- size_t alen, len, nlen;
+ size_t new_nelem, olen;
- nlen = tty->len + 64;
- alen = tty->len - (tty->next + tty->cnt);
+ new_nelem = tty->nelem + add;
+ olen = tty->nelem * sizeof(tty->ch[0]);
+ BINC_RET(sp, tty->ch, olen, new_nelem * sizeof(tty->ch[0]));
- len = tty->len;
- BINC_RET(sp, tty->ch, len, nlen * sizeof(tty->ch[0]));
- memset(tty->ch + tty->next + tty->cnt, 0, alen * sizeof(tty->ch[0]));
+ olen = tty->nelem * sizeof(tty->chf[0]);
+ BINC_RET(sp, tty->chf, olen, new_nelem * sizeof(tty->chf[0]));
- len = tty->len;
- BINC_RET(sp, tty->chf, len, nlen * sizeof(tty->chf[0]));
- memset(tty->chf + tty->next + tty->cnt, 0, alen * sizeof(tty->chf[0]));
+ olen = tty->nelem * sizeof(tty->cmap[0]);
+ BINC_RET(sp, tty->cmap, olen, new_nelem * sizeof(tty->cmap[0]));
- BINC_RET(sp, tty->cmap, tty->len, nlen * sizeof(tty->cmap[0]));
- memset(tty->cmap +
- tty->next + tty->cnt, 0, alen * sizeof(tty->cmap[0]));
+ tty->nelem = new_nelem;
return (0);
}
diff --git a/usr.bin/vi/term.h b/usr.bin/vi/term.h
index 67f7f5d2822c..5b224cc01562 100644
--- a/usr.bin/vi/term.h
+++ b/usr.bin/vi/term.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,54 +30,69 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)term.h 8.26 (Berkeley) 1/7/94
+ * @(#)term.h 8.37 (Berkeley) 3/22/94
*/
+/*
+ * Fundamental character types.
+ *
+ * CHAR_T An integral type that can hold any character.
+ * ARG_CHAR_T The type of a CHAR_T when passed as an argument using
+ * traditional promotion rules. It should also be able
+ * to be compared against any CHAR_T for equality without
+ * problems.
+ * MAX_CHAR_T The maximum value of any character.
+ *
+ * If no integral type can hold a character, don't even try the port.
+ */
+typedef u_char CHAR_T;
+typedef u_int ARG_CHAR_T;
+#define MAX_CHAR_T 0xff
+
+/* The maximum number of columns any character can take up on a screen. */
+#define MAX_CHARACTER_COLUMNS 4
+
/* Structure to return a character and associated information. */
struct _ch {
CHAR_T ch; /* Character. */
+#define K_NOTUSED 0
#define K_CARAT 1
-#define K_CNTRLR 2
-#define K_CNTRLT 3
-#define K_CNTRLZ 4
-#define K_COLON 5
-#define K_CR 6
-#define K_ESCAPE 7
-#define K_FORMFEED 8
-#define K_NL 9
-#define K_RIGHTBRACE 10
-#define K_RIGHTPAREN 11
-#define K_TAB 12
-#define K_VEOF 13
+#define K_CNTRLD 2
+#define K_CNTRLR 3
+#define K_CNTRLT 4
+#define K_CNTRLZ 5
+#define K_COLON 6
+#define K_CR 7
+#define K_ESCAPE 8
+#define K_FORMFEED 9
+#define K_NL 10
+#define K_RIGHTBRACE 11
+#define K_RIGHTPAREN 12
+#define K_TAB 13
#define K_VERASE 14
#define K_VINTR 15
#define K_VKILL 16
#define K_VLNEXT 17
#define K_VWERASE 18
#define K_ZERO 19
- u_char value; /* Special character flag values. */
+ u_int8_t value; /* Special character flag values. */
#define CH_ABBREVIATED 0x01 /* Character from an abbreviation. */
#define CH_NOMAP 0x02 /* Do not attempt to map the character. */
#define CH_QUOTED 0x04 /* Character is already quoted. */
- u_char flags;
+ u_int8_t flags;
};
-/*
- * Structure for the key input buffer.
- *
- * MAX_MAP_COUNT was chosen based on the vi maze script, which remaps
- * characters roughly 250 times.
- */
+/* Structure for the key input buffer. */
struct _ibuf {
- CHAR_T *ch; /* Array of characters. */
- u_char *chf; /* Array of character flags (CH_*). */
-#define MAX_MAP_COUNT 270 /* Maximum times a character can remap. */
- u_char *cmap; /* Number of times character has been mapped. */
+ CHAR_T *ch; /* Array of characters. */
+ u_int8_t *chf; /* Array of character flags (CH_*). */
+#define MAX_MAP_COUNT 50 /* Infinite loop check. */
+ u_int8_t *cmap; /* Number of times character has been mapped. */
size_t cnt; /* Count of remaining characters. */
- size_t len; /* Array length. */
+ size_t nelem; /* Numer of array elements. */
size_t next; /* Offset of next array entry. */
};
/* Return if more keys in queue. */
@@ -91,7 +106,7 @@ struct _ibuf {
*/
struct _chname {
char *name; /* Character name. */
- u_char len; /* Length of the character name. */
+ u_int8_t len; /* Length of the character name. */
};
/*
@@ -130,53 +145,55 @@ enum confirm { CONF_NO, CONF_QUIT, CONF_YES };
#define isblank(ch) ((ch) == ' ' || (ch) == '\t')
#endif
+/* The "standard" tab width, for displaying things to users. */
+#define STANDARD_TAB 6
+
/* Various special characters, messages. */
#define CURSOR_CH ' ' /* Cursor character. */
#define END_CH '$' /* End of a range. */
#define HEX_CH 'x' /* Leading hex number. */
+#define LITERAL_CH '\026' /* Standard literal ^V. */
#define NOT_DIGIT_CH 'a' /* A non-isdigit() character. */
#define NO_CH 'n' /* No. */
#define QUIT_CH 'q' /* Quit. */
#define YES_CH 'y' /* Yes. */
+
#define CONFSTRING "confirm? [ynq]"
#define CONTMSG "Enter return to continue: "
#define CONTMSG_I "Enter return to continue [q to quit]: "
/* Flags describing how input is handled. */
-#define TXT_AICHARS 0x000001 /* Leading autoindent chars. */
-#define TXT_ALTWERASE 0x000002 /* Option: altwerase. */
-#define TXT_APPENDEOL 0x000004 /* Appending after EOL. */
-#define TXT_AUTOINDENT 0x000008 /* Autoindent set this line. */
-#define TXT_BEAUTIFY 0x000010 /* Only printable characters. */
-#define TXT_BS 0x000020 /* Backspace returns the buffer. */
-#define TXT_CNTRLT 0x000040 /* Control-T is an indent special. */
-#define TXT_CR 0x000080 /* CR returns the buffer. */
-#define TXT_EMARK 0x000100 /* End of replacement mark. */
-#define TXT_ESCAPE 0x000200 /* Escape returns the buffer. */
-#define TXT_INFOLINE 0x000400 /* Editing the info line. */
-#define TXT_MAPCOMMAND 0x000800 /* Apply the command map. */
-#define TXT_MAPINPUT 0x001000 /* Apply the input map. */
-#define TXT_MAPNODIGIT 0x002000 /* Return to a digit. */
-#define TXT_NLECHO 0x004000 /* Echo the newline. */
-#define TXT_OVERWRITE 0x008000 /* Overwrite characters. */
-#define TXT_PROMPT 0x010000 /* Display a prompt. */
-#define TXT_RECORD 0x020000 /* Record for replay. */
-#define TXT_REPLACE 0x040000 /* Replace; don't delete overwrite. */
-#define TXT_REPLAY 0x080000 /* Replay the last input. */
-#define TXT_RESOLVE 0x100000 /* Resolve the text into the file. */
-#define TXT_SHOWMATCH 0x200000 /* Option: showmatch. */
-#define TXT_TTYWERASE 0x400000 /* Option: ttywerase. */
-#define TXT_WRAPMARGIN 0x800000 /* Option: wrapmargin. */
-
-#define TXT_VALID_EX \
- (TXT_BEAUTIFY | TXT_CR | TXT_NLECHO | TXT_PROMPT)
+#define TXT_AICHARS 0x0000001 /* Leading autoindent chars. */
+#define TXT_ALTWERASE 0x0000002 /* Option: altwerase. */
+#define TXT_APPENDEOL 0x0000004 /* Appending after EOL. */
+#define TXT_AUTOINDENT 0x0000008 /* Autoindent set this line. */
+#define TXT_BEAUTIFY 0x0000010 /* Only printable characters. */
+#define TXT_BS 0x0000020 /* Backspace returns the buffer. */
+#define TXT_CNTRLD 0x0000040 /* Control-D is a special command. */
+#define TXT_CNTRLT 0x0000080 /* Control-T is an indent special. */
+#define TXT_CR 0x0000100 /* CR returns the buffer. */
+#define TXT_EMARK 0x0000200 /* End of replacement mark. */
+#define TXT_ESCAPE 0x0000400 /* Escape returns the buffer. */
+#define TXT_INFOLINE 0x0000800 /* Editing the info line. */
+#define TXT_MAPCOMMAND 0x0001000 /* Apply the command map. */
+#define TXT_MAPINPUT 0x0002000 /* Apply the input map. */
+#define TXT_MAPNODIGIT 0x0004000 /* Return to a digit. */
+#define TXT_NLECHO 0x0008000 /* Echo the newline. */
+#define TXT_OVERWRITE 0x0010000 /* Overwrite characters. */
+#define TXT_PROMPT 0x0020000 /* Display a prompt. */
+#define TXT_RECORD 0x0040000 /* Record for replay. */
+#define TXT_REPLACE 0x0080000 /* Replace; don't delete overwrite. */
+#define TXT_REPLAY 0x0100000 /* Replay the last input. */
+#define TXT_RESOLVE 0x0200000 /* Resolve the text into the file. */
+#define TXT_SHOWMATCH 0x0400000 /* Option: showmatch. */
+#define TXT_TTYWERASE 0x0800000 /* Option: ttywerase. */
+#define TXT_WRAPMARGIN 0x1000000 /* Option: wrapmargin. */
/* Support keyboard routines. */
int __term_key_val __P((SCR *, ARG_CHAR_T));
void term_ab_flush __P((SCR *, char *));
int term_init __P((SCR *));
enum input term_key __P((SCR *, CH *, u_int));
-int term_key_ch __P((SCR *, int, CHAR_T *));
int term_key_queue __P((SCR *));
void term_map_flush __P((SCR *, char *));
int term_push __P((SCR *, CHAR_T *, size_t, u_int, u_int));
diff --git a/usr.bin/vi/timer.c b/usr.bin/vi/timer.c
index e2bcfb1c8852..42d366384f67 100644
--- a/usr.bin/vi/timer.c
+++ b/usr.bin/vi/timer.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,135 +32,205 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)timer.c 8.7 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)timer.c 8.13 (Berkeley) 3/23/94";
#endif /* not lint */
+#include <queue.h>
#include <sys/time.h>
-#include "vi.h"
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
-static void busy_handler __P((int));
+#include "vi.h"
/*
- * XXX
- * There are two uses of timers in nvi. The first is to push the recovery
- * information out to disk at periodic intervals. The second is to display
- * a "busy" message if an operation takes too long. Rather than solve this
- * in a general fashion, we depend on the fact that only a single screen in
- * a window is active at a time, and that there are only two parts of the
- * systems that use timers.
+ * There are two uses of the ITIMER_REAL timer (SIGALRM) in nvi. The first
+ * is to push the recovery information out to disk at periodic intervals.
+ * The second is to display a "busy" message if an operation takes more time
+ * that users are willing to wait before seeing something happen. Each of
+ * these uses has a wall clock timer structure in each SCR structure. Since
+ * the busy timer has a much faster timeout than the recovery timer, most of
+ * the code ignores the recovery timer unless it's the only thing running.
*
- * It would be nice to reimplement this with multiple timers, a la POSIX
- * 1003.1, but not many systems offer them yet.
+ * XXX
+ * It would be nice to reimplement this with two timers, a la POSIX 1003.1,
+ * but not many systems offer them yet.
*/
-/*
+/*
* busy_on --
- * Display a message if too much time passes.
+ * Set a busy message timer.
*/
-void
-busy_on(sp, seconds, msg)
+int
+busy_on(sp, msg)
SCR *sp;
- int seconds;
char const *msg;
{
struct itimerval value;
- struct sigaction act;
+ struct timeval tod;
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
+ /*
+ * Give the oldest busy message precedence, since it's
+ * the longer running operation.
+ */
+ if (sp->busy_msg != NULL)
+ return (1);
- /* Turn off the current timer, saving its current value. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &sp->time_value))
- return;
+ /* Get the current time of day, and create a target time. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
+#define USER_PATIENCE_USECS (8 * 100000L)
+ sp->busy_tod.tv_sec = tod.tv_sec;
+ sp->busy_tod.tv_usec = tod.tv_usec + USER_PATIENCE_USECS;
+
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = msg;
/*
- * Decrement the original timer by the number of seconds
- * we're going to wait.
+ * Busy messages turn around fast. Reset the timer regardless
+ * of its current state.
*/
- if (sp->time_value.it_value.tv_sec > seconds)
- sp->time_value.it_value.tv_sec -= seconds;
- else
- sp->time_value.it_value.tv_sec = 1;
-
- /* Reset the handler, saving its current value. */
- act.sa_handler = busy_handler;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(SIGALRM, &act, &sp->time_handler);
-
- /* Reset the timer. */
- value.it_value.tv_sec = seconds;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_usec = USER_PATIENCE_USECS;
value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- (void)setitimer(ITIMER_REAL, &value, NULL);
-
- sp->time_msg = msg;
- F_SET(sp, S_TIMER_SET);
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL))
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (0);
}
/*
* busy_off --
- * Reset the timer handlers.
+ * Turn off a busy message timer.
*/
void
busy_off(sp)
SCR *sp;
{
- struct itimerval ovalue, value;
-
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
-
- /* If the timer flag isn't set, it must have fired. */
- if (!F_ISSET(sp, S_TIMER_SET))
- return;
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = NULL;
+}
- /* Ignore it if first on one of following system calls. */
- F_CLR(sp, S_TIMER_SET);
+/*
+ * rcv_on --
+ * Turn on recovery timer.
+ */
+int
+rcv_on(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct itimerval value;
+ struct timeval tod;
- /* Turn off the current timer. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &ovalue))
- return;
+ /* Get the current time of day. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
- /* If the timer wasn't running, we're done. */
- if (sp->time_handler.sa_handler == SIG_DFL)
- return;
+ /* Create target time of day. */
+ ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD;
+ ep->rcv_tod.tv_usec = 0;
/*
- * Increment the old timer by the number of seconds
- * remaining in the new one.
+ * If there's a busy message happening, we're done, the
+ * interrupt handler will start our timer as necessary.
*/
- sp->time_value.it_value.tv_sec += ovalue.it_value.tv_sec;
-
- /* Reset the handler to the original handler. */
- (void)sigaction(SIGALRM, &sp->time_handler, NULL);
+ if (sp->busy_msg != NULL)
+ return (0);
- /* Reset the timer. */
- (void)setitimer(ITIMER_REAL, &sp->time_value, NULL);
+ value.it_value.tv_sec = RCV_PERIOD;
+ value.it_value.tv_usec = 0;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL)) {
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (1);
+ }
+ return (0);
}
/*
- * busy_handler --
- * Display a message when the timer goes off, and restore the
- * timer to its original values.
+ * h_alrm --
+ * Handle SIGALRM.
*/
-static void
-busy_handler(signo)
+void
+h_alrm(signo)
int signo;
{
+ struct itimerval value;
+ struct timeval ntod, tod;
SCR *sp;
+ EXF *ep;
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_TIMER_SET)) {
- sp->s_busy(sp, sp->time_msg);
- busy_off(sp);
+ /* XXX: Get the current time of day; if this fails, we're dead. */
+ if (gettimeofday(&tod, NULL))
+ return;
+
+ /*
+ * Fire any timers that are past due, or any that are due
+ * in a tenth of a second or less.
+ */
+ for (ntod.tv_sec = 0, sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) {
+
+ /* Check the busy timer if the msg pointer is set. */
+ if (sp->busy_msg == NULL)
+ goto skip_busy;
+ if (sp->busy_tod.tv_sec > tod.tv_sec ||
+ sp->busy_tod.tv_sec == tod.tv_sec &&
+ sp->busy_tod.tv_usec > tod.tv_usec &&
+ sp->busy_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > sp->busy_tod.tv_sec ||
+ ntod.tv_sec == sp->busy_tod.tv_sec &&
+ ntod.tv_usec > sp->busy_tod.tv_usec)
+ ntod = sp->busy_tod;
+ } else {
+ (void)sp->s_busy(sp, sp->busy_msg);
+ sp->busy_msg = NULL;
+ }
+
+ /*
+ * Check the recovery timer if there's an EXF structure
+ * and the recovery bit is set.
+ */
+skip_busy: if ((ep = sp->ep) == NULL || !F_ISSET(sp->ep, F_RCV_ON))
+ continue;
+ if (ep->rcv_tod.tv_sec > tod.tv_sec ||
+ ep->rcv_tod.tv_sec == tod.tv_sec &&
+ ep->rcv_tod.tv_usec > tod.tv_usec &&
+ ep->rcv_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
+ } else {
+ F_SET(sp->gp, G_SIGALRM);
+ ep->rcv_tod = tod;
+ ep->rcv_tod.tv_sec += RCV_PERIOD;
+
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
}
+ }
+
+ if (ntod.tv_sec == 0)
+ return;
+
+ /* XXX: Set the timer; if this fails, we're dead. */
+ value.it_value.tv_sec = ntod.tv_sec - tod.tv_sec;
+ value.it_value.tv_usec = ntod.tv_usec - tod.tv_usec;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ (void)setitimer(ITIMER_REAL, &value, NULL);
}
diff --git a/usr.bin/vi/trace.c b/usr.bin/vi/trace.c
index f97e47bdc7db..b090477b77fa 100644
--- a/usr.bin/vi/trace.c
+++ b/usr.bin/vi/trace.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,11 +30,22 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)trace.c 8.1 (Berkeley) 6/9/93
+ * @(#)trace.c 8.2 (Berkeley) 3/8/94
*/
#ifdef DEBUG
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
diff --git a/usr.bin/vi/util.c b/usr.bin/vi/util.c
index 79a06516af48..74a5380c0e58 100644
--- a/usr.bin/vi/util.c
+++ b/usr.bin/vi/util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)util.c 8.34 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)util.c 8.44 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#ifdef __STDC__
@@ -51,6 +58,9 @@ static char sccsid[] = "@(#)util.c 8.34 (Berkeley) 12/23/93";
#include <varargs.h>
#endif
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
/*
@@ -84,14 +94,15 @@ msgq(sp, mt, fmt, va_alist)
*/
switch (mt) {
case M_BERR:
- if (sp != NULL && !O_ISSET(sp, O_VERBOSE)) {
+ if (sp != NULL && !F_ISSET(sp, S_EXSILENT) &&
+ F_ISSET(sp->gp, G_STDIN_TTY) && !O_ISSET(sp, O_VERBOSE)) {
F_SET(sp, S_BELLSCHED);
return;
}
mt = M_ERR;
break;
case M_VINFO:
- if (sp != NULL && !O_ISSET(sp, O_VERBOSE))
+ if (sp == NULL || !O_ISSET(sp, O_VERBOSE))
return;
mt = M_INFO;
/* FALLTHROUGH */
@@ -209,6 +220,13 @@ ret: reenter = 0;
* This isn't true -- edit a large file and do "100d|1". We don't implement
* this semantic as it would require that we track each line that changes
* during a command instead of just keeping count.
+ *
+ * Line counts weren't right in historic vi, either. For example, given the
+ * file:
+ * abc
+ * def
+ * the command 2d}, from the 'b' would report that two lines were deleted,
+ * not one.
*/
int
msg_rpt(sp, is_message)
@@ -216,7 +234,7 @@ msg_rpt(sp, is_message)
int is_message;
{
static const char *const action[] = {
- "added", "changed", "copied", "deleted", "joined", "moved",
+ "added", "changed", "copied", "deleted", "joined", "moved",
"put", "left shifted", "right shifted", "yanked", NULL,
};
recno_t total;
@@ -276,36 +294,45 @@ norpt: memset(sp->rptlines, 0, sizeof(sp->rptlines));
*/
int
binc(sp, argp, bsizep, min)
- SCR *sp; /* MAY BE NULL */
+ SCR *sp; /* sp MAY BE NULL!!! */
void *argp;
size_t *bsizep, min;
{
- void *bpp;
size_t csize;
+ void *bpp;
/* If already larger than the minimum, just return. */
- csize = *bsizep;
- if (min && csize >= min)
+ if (min && *bsizep >= min)
return (0);
- csize += MAX(min, 256);
+ /*
+ * If the initial pointer is null, use calloc (for non-ANSI
+ * C realloc implementations).
+ */
bpp = *(char **)argp;
+ csize = *bsizep + MAX(min, 256);
+ if (bpp == NULL) {
+ MALLOC(sp, bpp, void *, csize);
+ } else
+ REALLOC(sp, bpp, void *, csize);
- /* For non-ANSI C realloc implementations. */
- if (bpp == NULL)
- bpp = malloc(csize * sizeof(CHAR_T));
- else
- bpp = realloc(bpp, csize * sizeof(CHAR_T));
if (bpp == NULL) {
- msgq(sp, M_SYSERR, NULL);
+ /*
+ * Theoretically, realloc is supposed to leave any already
+ * held memory alone if it can't get more. Don't trust it.
+ */
*bsizep = 0;
return (1);
}
+ /*
+ * Memory is guaranteed to be zero-filled, various parts of
+ * nvi depend on this.
+ */
+ memset((char *)bpp + *bsizep, 0, csize - *bsizep);
*(char **)argp = bpp;
*bsizep = csize;
return (0);
}
-
/*
* nonblank --
* Set the column number of the first non-blank character
@@ -499,6 +526,9 @@ baud_from_bval(sp)
{
speed_t v;
+ if (!F_ISSET(sp->gp, G_TERMIOS_SET))
+ return (9600);
+
switch (v = cfgetospeed(&sp->gp->original_termios)) {
case B50:
return (50);
@@ -524,13 +554,37 @@ baud_from_bval(sp)
return (2400);
case B4800:
return (4800);
+#ifdef B7200
+ case B7200:
+ return (7200);
+#endif
case B0: /* Hangup -- ignore. */
case B9600:
return (9600);
+#ifdef B14400
+ case B14400:
+ return (14400);
+#endif
case B19200:
return (19200);
+#ifdef B28800
+ case B28800:
+ return (28800);
+#endif
case B38400:
return (38400);
+#ifdef B57600
+ case B57600:
+ return (57600);
+#endif
+#ifdef B115200
+ case B115200:
+ return (115200);
+#endif
+#ifdef B230400
+ case B230400:
+ return (230400);
+#endif
default:
/*
* EXTA and EXTB aren't required by POSIX 1003.1, and
@@ -545,14 +599,6 @@ baud_from_bval(sp)
if (v == EXTB)
return (38400);
#endif
-#ifdef B57600
- if (v == B57600)
- return (57600);
-#endif
-#ifdef B115200
- if (v == B115200)
- return (115200);
-#endif
msgq(sp, M_ERR, "Unknown terminal baud rate %u.\n", v);
return (9600);
}
diff --git a/usr.bin/vi/vi.1 b/usr.bin/vi/vi.1
deleted file mode 100644
index 7c39b10c5ae2..000000000000
--- a/usr.bin/vi/vi.1
+++ /dev/null
@@ -1,451 +0,0 @@
-.\" Copyright (c) 1994
-.\" 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.
-.\"
-.\" @(#)vi.1 8.3 (Berkeley) 3/19/94
-.\"
-.Dd "March 19, 1994"
-.Dt EX/VI 1
-.Os
-.Sh NAME
-.Nm ex, vi, view
-.Nd text editors
-.Sh SYNOPSIS
-.Nm \&ex
-.Op Fl eFlRsv
-.Op Fl c Ar cmd
-.Op Fl r Ar file
-.Op Fl t Ar tag
-.Op Fl w Ar size
-.Op Fl x Ar \&aw
-.Op Ar "file ..."
-.Nm \&vi
-.Op Fl eFlRv
-.Op Fl c Ar cmd
-.Op Fl r Ar file
-.Op Fl t Ar tag
-.Op Fl w Ar size
-.Op Fl x Ar \&aw
-.Op Ar "file ..."
-.Nm view
-.Op Fl eFlRv
-.Op Fl c Ar cmd
-.Op Fl r Ar file
-.Op Fl t Ar tag
-.Op Fl w Ar size
-.Op Fl x Ar \&aw
-.Op Ar "file ..."
-.Sh DESCRIPTION
-.Nm \&Vi
-is a screen oriented text editor.
-.Nm \&Ex
-is a line-oriented text editor.
-.Nm \&Ex
-and
-.Nm \&vi
-are different interfaces to the same program,
-and it is possible to switch back and forth during an edit session.
-.Nm View
-is the equivalent of using the
-.Fl R
-(read-only) option of
-.Nm \&vi .
-.Pp
-This manual page is the one provided with the
-.Nm ex/vi
-versions of the
-.Nm ex/vi
-text editors.
-.Nm Ex/vi
-are intended as bug-for-bug compatible replacements for the original
-Fourth Berkeley Software Distribution (4BSD)
-.Nm \&ex
-and
-.Nm \&vi
-programs.
-For the rest of this manual page,
-.Nm ex/vi
-is used only when it's necessary to distinguish it from the historic
-implementations of
-.Nm ex/vi .
-.Pp
-This manual page is intended for users already familiar with
-.Nm ex/vi .
-Anyone else should almost certainly read a good tutorial on the
-editor before this manual page.
-If you're in an unfamiliar environment, and you absolutely have to
-get work done immediately, read the section near the end of this
-manual page, entitled FAST STARTUP.
-It's probably enough to get you going.
-.Pp
-The following options are available:
-.Bl -tag -width Ds
-.It Fl c
-Execute
-.Ar cmd
-immediately after starting the edit session.
-Particularly useful for initial positioning in the file, however
-.Ar cmd
-is not limited to positioning commands.
-This is the POSIX 1003.2 interface for the historic
-.Dq "+cmd"
-syntax.
-.Nm Ex/vi
-supports both the old and new syntax.
-.It Fl e
-Start editing in ex mode, as if the command name were
-.Nm \&ex .
-.It Fl F
-Don't copy the entire file when first starting to edit.
-(The default is to make a copy in case someone else modifies
-the file during your edit session.)
-.It Fl l
-List the files that may be recovered using the
-.Fl r
-option of
-.Nm \&vi .
-This is the new interface for the historic syntax of the
-.Fl r
-option without a file argument.
-.Nm Ex/vi
-supports both the old and new syntax.
-.It Fl R
-Start editing in read-only mode, as if the command name was
-.Nm view ,
-or the readonly option was set.
-.It Fl r
-Recover the specified file.
-.It Fl s
-Enter batch mode; applicable only to
-.Nm \&ex
-edit sessions.
-Batch mode is useful when running
-.Nm \&ex
-scripts.
-Prompts, informative messages and other user oriented message
-are turned off,
-and no startup files or environmental variables are read.
-This is the POSIX 1003.2 interface for the historic
-.Dq \&\-
-argument.
-.Nm \&Ex/vi
-supports both the old and new syntax.
-.It Fl t
-Start editing at the specified tag.
-(See
-.Xr ctags 1 ).
-.It Fl w
-Set the initial window size to the specified number of lines.
-.It Fl v
-Start editing in vi mode, as if the command name was
-.Nm \&vi
-or
-.Nm view .
-.It Fl x
-Reserved for X11 interfaces.
-.Em "No X11 support is currently implemented."
-.El
-.Pp
-.Nm Ex/vi
-exit 0 on success, and greater than 0 if an error occurs.
-.Sh ENVIRONMENTAL VARIABLES
-.Bl -tag -width XXXX -compact
-.It Ev COLUMNS
-The number of columns on the screen.
-This value overrides any system or terminal specific values.
-If the COLUMNS environmental variable is not set when
-.Nm ex/vi
-runs, or the
-.Sy columns
-option is explicitly reset by the user,
-.Nm ex/vi
-enters the value into the environment.
-.It Ev EXINIT
-A list of
-.Nm \&ex
-startup commands.
-.It Ev HOME
-The user's home directory, used as the initial directory path
-for the startup
-.Pa $HOME/.exrc
-file.
-This value is also used as the default directory for the
-.Nm \&vi
-.Sy \&cd
-command.
-.It Ev LINES
-The number of rows on the screen.
-This value overrides any system or terminal specific values.
-If the LINES environmental variable is not set when
-.Nm ex/vi
-runs, or the
-.Sy lines
-option is explicitly reset by the user,
-.Nm ex/vi
-enters the value into the environment.
-.It Ev SHELL
-The user's shell of choice (see also the
-.Sy shell
-option).
-.It Ev TERM
-The user's terminal type.
-The default is the type
-.Dq unknown .
-If the TERM environmental variable is not set when
-.Nm ex/vi
-runs, or the
-.Sy term
-option is explicitly reset by the user,
-.Nm ex/vi
-enters the value into the environment.
-.It Ev TMPDIR
-The location used to stored temporary files (see also the
-.Sy directory
-option).
-.El
-.Sh SET OPTIONS
-#include <set.opt.roff>
-.Sh FAST STARTUP
-This section will tell you the minimum amount that you need to
-do simple editing tasks using
-.Nm \&vi .
-If you've never used any screen editor before, you're likely to have
-problems even with this simple introduction.
-In that case you should find someone that already knows
-.Nm \&vi
-and have them walk you through this section.
-.Pp
-.Nm \&Vi
-is a screen editor.
-This means that it takes up almost the entire screen, displaying part
-of the file on each screen line, except for the last line of the screen.
-The last line of the screen is used for you to give commands to
-.Nm \&vi ,
-and for
-.Nm \&vi
-to give information to you.
-.Pp
-The other fact that you need to understand is that
-.Nm \&vi
-is a modeful editor, i.e. you are either entering text or you
-are executing commands, and you have to be in the right mode
-to do one or the other.
-You will be in command mode when you first start editing a file.
-There are commands that switch you into input mode.
-There is only one key that takes you out of input mode,
-and that is the <escape> key.
-(Key names are written using less-than and greater-than signs, e.g.
-<escape> means the
-.Dq escape
-key, usually labeled
-.Dq esc
-on your terminal's keyboard.)
-If you're ever confused as to which mode you're in,
-keep entering the <escape> key until
-.Nm \&vi
-beeps at you.
-(Generally,
-.Nm \&vi
-will beep at you if you try and do something that's not allowed.
-It will also display error messages.)
-.Pp
-To start editing a file, enter the command
-.Dq Li "vi file_name<carriage-return>" .
-The command you should enter as soon as you start editing is
-.Dq Li ":set verbose showmode<carriage-return>" .
-This will make the editor give you verbose error messages and display
-the current mode at the bottom of the screen.
-.Pp
-The commands to move around the file are:
-.Bl -tag -width XXXX -compact
-.It Sy h
-Move the cursor left one character.
-.It Sy j
-Move the cursor down one line.
-.It Sy k
-Move the cursor up one line.
-.It Sy l
-Move the cursor right one character.
-.It Sy <cursor-arrows>
-The cursor arrow keys should work, too.
-.It Sy /text<carriage-return>
-Search for the string
-.Dq text
-in the file, and move the cursor to its first character.
-.El
-.Pp
-The commands to enter new text are:
-.Bl -tag -width XXXX -compact
-.It Sy a
-Append new text,
-.Em after
-the cursor.
-.It Sy i
-Insert new text,
-.Em before
-the cursor.
-.It Sy o
-Open a new line below the line the cursor is on, and start
-entering text.
-.It Sy O
-Open a new line above the line the cursor is on, and start
-entering text.
-.It Sy <escape>
-Once you've entered input mode using the one of the
-.Sy \&a ,
-.Sy \&i ,
-.Sy \&O ,
-or
-.Sy \&o
-commands, use
-.Sy <escape>
-to quit entering text and return to command mode.
-.El
-.Pp
-The commands to copy text are:
-.Bl -tag -width XXXX -compact
-.It Sy yy
-Copy the line the cursor is on.
-.It Sy p
-Append the copied line after the line the cursor is on.
-.El
-.Pp
-The commands to delete text are:
-.Bl -tag -width XXXX -compact
-.It Sy dd
-Delete the line the cursor is on.
-.It Sy x
-Delete the character the cursor is on.
-.El
-.Pp
-The commands to write the file are:
-.Bl -tag -width XXXX -compact
-.It Sy :w<carriage-return>
-Write the file back to the file with the name that you originally used
-as an argument on the
-.Nm \&vi
-command line.
-.It Sy :w file_name<carriage-return>
-Write the file back to the file with the name
-.Dq file_name .
-.El
-.Pp
-The commands to quit editing and exit the editor are:
-.Bl -tag -width XXXX -compact
-.It Sy :q<carriage-return>
-Quit editing and leave vi (if you've modified the file, but not
-saved your changes,
-.Nm \&vi
-will refuse to quit).
-.It Sy :q!<carriage-return>
-Quit, discarding any modifications that you may have made.
-.El
-.Pp
-One final caution.
-Unusual characters can take up more than one column on the screen,
-and long lines can take up more than a single screen line.
-The above commands work on
-.Dq physical
-characters and lines, i.e. they affect the entire line no matter
-how many screen lines it takes up and the entire character no matter
-how many screen columns it takes up.
-.Sh BUGS
-See the file
-.Pa vi/docs/bugs.current
-for a list of the known bugs in this version.
-.Sh FILES
-.Bl -tag -width /var/tmp/vi.recover -compact
-.It Pa /bin/sh
-The default user shell.
-.It Pa /etc/vi.exrc
-System-wide vi startup file.
-.It Pa /tmp
-Temporary file directory.
-.It Pa /var/tmp/vi.recover
-Recovery file directory.
-.It Pa $HOME/.exrc
-user's home directory startup file.
-.It Pa .exrc
-local directory startup file.
-.El
-.Sh SEE ALSO
-.Xr ctags 1 ,
-.Xr more 1 ,
-.Xr curses 3 ,
-.Xr dbopen 3
-.sp
-The
-.Dq "Vi Quick Reference"
-card.
-.sp
-.Dq "An Introduction to Display Editing with Vi" ,
-found in the
-.Dq "UNIX User's Manual Supplementary Documents" .
-.sp
-.Dq "Edit: A tutorial" ,
-found in the
-.Dq "UNIX User's Manual Supplementary Documents" .
-.sp
-.Dq "\&Ex Reference Manual (Version 3.7)" ,
-found in the
-.Dq "UNIX User's Manual Supplementary Documents" .
-.Pp
-.Nm Nroff/troff
-source for the previous three documents are distributed with
-.Nm ex/vi
-in the
-.Pa vi/docs/USD.doc
-directory of the
-.Nm ex/vi
-source code.
-.sp
-The files
-.Dq autowrite ,
-.Dq input ,
-.Dq quoting ,
-and
-.Dq structures ,
-found in the
-.Pa vi/docs/internals
-directory of the
-.Nm ex/vi
-source code.
-.Sh HISTORY
-The
-.Nm ex/vi
-replacements for the
-.Nm ex/vi
-editor first appeared in 4.4BSD.
-.Sh STANDARDS
-.Nm \&Ex/vi
-is close to IEEE Std1003.2 (``POSIX'').
-That document differs from historical
-.Nm ex/vi
-practice in several places; there are changes to be made on both sides.
diff --git a/usr.bin/vi/vi.h b/usr.bin/vi/vi.h
index a979925c2b05..5cf65a7ecb3d 100644
--- a/usr.bin/vi/vi.h
+++ b/usr.bin/vi/vi.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,25 +30,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)vi.h 8.33 (Berkeley) 1/9/94
+ * @(#)vi.h 8.39 (Berkeley) 3/23/94
*/
-/* System includes. */
-#include <queue.h> /* Required by screen.h. */
-#include <sys/time.h> /* Required by screen.h. */
-
-#include <bitstring.h> /* Required by screen.h. */
-#include <limits.h> /* Required by screen.h. */
-#include <signal.h> /* Required by screen.h. */
-#include <stdio.h> /* Required by screen.h. */
-#include <termios.h> /* Required by gs.h. */
-
-/*
- * Required by screen.h. This is the first include that can pull
- * in "compat.h". Should be after every other system include.
- */
-#include <regex.h>
-
/*
* Forward structure declarations. Not pretty, but the include files
* are far too interrelated for a clean solution.
@@ -61,6 +45,7 @@ typedef struct _exf EXF;
typedef struct _fref FREF;
typedef struct _gs GS;
typedef struct _ibuf IBUF;
+typedef struct _lmark LMARK;
typedef struct _mark MARK;
typedef struct _msg MSG;
typedef struct _option OPTION;
@@ -73,40 +58,20 @@ typedef struct _tagf TAGF;
typedef struct _text TEXT;
/*
- * Fundamental character types.
- *
- * CHAR_T An integral type that can hold any character.
- * ARG_CHAR_T The type of a CHAR_T when passed as an argument using
- * traditional promotion rules. It should also be able
- * to be compared against any CHAR_T for equality without
- * problems.
- * MAX_CHAR_T The maximum value of any character.
- *
- * If no integral type can hold a character, don't even try the port.
- */
-typedef u_char CHAR_T;
-typedef u_int ARG_CHAR_T;
-#define MAX_CHAR_T 0xff
-
-/* The maximum number of columns any character can take up on a screen. */
-#define MAX_CHARACTER_COLUMNS 4
-
-/*
* Local includes.
*/
-#include <db.h> /* Required by exf.h; includes compat.h. */
-
-#include "search.h" /* Required by screen.h. */
+#include "compat.h" /* typedef u_int8_t et al. */
+#include "term.h" /* Required by args.h. */
#include "args.h" /* Required by options.h. */
#include "options.h" /* Required by screen.h. */
-#include "term.h" /* Required by screen.h. */
+#include "search.h" /* Required by screen.h. */
#include "msg.h" /* Required by gs.h. */
#include "cut.h" /* Required by gs.h. */
#include "gs.h" /* Required by screen.h. */
#include "screen.h" /* Required by exf.h. */
#include "mark.h" /* Required by exf.h. */
-#include "exf.h"
+#include "exf.h"
#include "log.h"
#include "mem.h"
@@ -146,8 +111,6 @@ FILE *fwopen __P((SCR *, void *));
/* Function prototypes that don't seem to belong anywhere else. */
u_long baud_from_bval __P((SCR *));
char *charname __P((SCR *, ARG_CHAR_T));
-void busy_off __P((SCR *));
-void busy_on __P((SCR *, int, char const *));
int nonblank __P((SCR *, EXF *, recno_t, size_t *));
void set_alt_name __P((SCR *, char *));
int set_window_size __P((SCR *, u_int, int));
diff --git a/usr.bin/vi/vi/getc.c b/usr.bin/vi/vi/getc.c
new file mode 100644
index 000000000000..67aee2ff4692
--- /dev/null
+++ b/usr.bin/vi/vi/getc.c
@@ -0,0 +1,267 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)getc.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * Character stream routines --
+ * These routines return the file a character at a time. There are two
+ * special cases. First, the end of a line, end of a file, start of a
+ * file and empty lines are returned as special cases, and no character
+ * is returned. Second, empty lines include lines that have only white
+ * space in them, because the vi search functions don't care about white
+ * space, and this makes it easier for them to be consistent.
+ */
+
+/*
+ * cs_init --
+ * Initialize character stream routines.
+ */
+int
+cs_init(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t lno;
+
+ if ((csp->cs_bp =
+ file_gline(sp, ep, csp->cs_lno, &csp->cs_len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ msgq(sp, M_BERR, "Empty file.");
+ else
+ GETLINE_ERR(sp, csp->cs_lno);
+ return (1);
+ }
+ if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno];
+ }
+ return (0);
+}
+
+/*
+ * cs_next --
+ * Retrieve the next character.
+ */
+int
+cs_next(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t slno;
+
+ switch (csp->cs_flags) {
+ case CS_EMP: /* EMP; get next line. */
+ case CS_EOL: /* EOL; get next line. */
+ slno = csp->cs_lno; /* Save current line. */
+ if ((csp->cs_bp =
+ file_gline(sp, ep, ++csp->cs_lno, &csp->cs_len)) == NULL) {
+ csp->cs_lno = slno;
+ if (file_lline(sp, ep, &slno))
+ return (1);
+ if (slno > csp->cs_lno) {
+ GETLINE_ERR(sp, csp->cs_lno);
+ return (1);
+ }
+ csp->cs_flags = CS_EOF;
+ } else if (csp->cs_len == 0 ||
+ v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
+ }
+ break;
+ case 0:
+ if (csp->cs_cno == csp->cs_len - 1)
+ csp->cs_flags = CS_EOL;
+ else
+ csp->cs_ch = csp->cs_bp[++csp->cs_cno];
+ break;
+ case CS_EOF: /* EOF. */
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+/*
+ * cs_fspace --
+ * If on a space, eat forward until something other than a
+ * whitespace character.
+ *
+ * XXX
+ * Semantics of checking the current character were coded for the fword()
+ * function -- once the other word routines are converted, they may have
+ * to change.
+ */
+int
+cs_fspace(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+ return (0);
+ for (;;) {
+ if (cs_next(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+ break;
+ }
+ return (0);
+}
+
+/*
+ * cs_fblank --
+ * Eat forward to the next non-whitespace character.
+ */
+int
+cs_fblank(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ for (;;) {
+ if (cs_next(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
+ csp->cs_flags == 0 && isblank(csp->cs_ch))
+ continue;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * cs_prev --
+ * Retrieve the previous character.
+ */
+int
+cs_prev(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t slno;
+
+ switch (csp->cs_flags) {
+ case CS_EMP: /* EMP; get previous line. */
+ case CS_EOL: /* EOL; get previous line. */
+ if (csp->cs_lno == 1) { /* SOF. */
+ csp->cs_flags = CS_SOF;
+ break;
+ }
+ slno = csp->cs_lno; /* Save current line. */
+ if ((csp->cs_bp = /* Line should exist. */
+ file_gline(sp, ep, --csp->cs_lno, &csp->cs_len)) == NULL) {
+ GETLINE_ERR(sp, csp->cs_lno);
+ csp->cs_lno = slno;
+ return (1);
+ }
+ if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_cno = csp->cs_len - 1;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno];
+ }
+ break;
+ case 0:
+ if (csp->cs_cno == 0)
+ if (csp->cs_lno == 1)
+ csp->cs_flags = CS_SOF;
+ else
+ csp->cs_flags = CS_EOL;
+ else
+ csp->cs_ch = csp->cs_bp[--csp->cs_cno];
+ break;
+ case CS_SOF: /* SOF. */
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+/*
+ * cs_bblank --
+ * Eat backward to the next non-whitespace character.
+ */
+int
+cs_bblank(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ for (;;) {
+ if (cs_prev(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
+ csp->cs_flags == 0 && isblank(csp->cs_ch))
+ continue;
+ break;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_again.c b/usr.bin/vi/vi/v_again.c
new file mode 100644
index 000000000000..a96ae8036f04
--- /dev/null
+++ b/usr.bin/vi/vi/v_again.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_again.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_again -- &
+ * Repeat the previous substitution.
+ */
+int
+v_again(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1, "");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_at.c b/usr.bin/vi/vi/v_at.c
new file mode 100644
index 000000000000..c2d446843ca2
--- /dev/null
+++ b/usr.bin/vi/vi/v_at.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_at.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_at -- @
+ * Execute a buffer.
+ */
+int
+v_at(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_AT, 0, OOBLNO, OOBLNO, 0, NULL);
+ cmd.buffer = vp->buffer;
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_ch.c b/usr.bin/vi/vi/v_ch.c
new file mode 100644
index 000000000000..69fbf6865c47
--- /dev/null
+++ b/usr.bin/vi/vi/v_ch.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_ch.c 8.7 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static void notfound __P((SCR *, ARG_CHAR_T));
+static void noprev __P((SCR *));
+
+/*
+ * v_chrepeat -- [count];
+ * Repeat the last F, f, T or t search.
+ */
+int
+v_chrepeat(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ vp->character = VIP(sp)->lastckey;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ return (v_chF(sp, ep, vp));
+ case fSEARCH:
+ return (v_chf(sp, ep, vp));
+ case TSEARCH:
+ return (v_chT(sp, ep, vp));
+ case tSEARCH:
+ return (v_cht(sp, ep, vp));
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * v_chrrepeat -- [count],
+ * Repeat the last F, f, T or t search in the reverse direction.
+ */
+int
+v_chrrepeat(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum cdirection savedir;
+ int rval;
+
+ vp->character = VIP(sp)->lastckey;
+ savedir = VIP(sp)->csearchdir;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ rval = v_chf(sp, ep, vp);
+ break;
+ case fSEARCH:
+ rval = v_chF(sp, ep, vp);
+ break;
+ case TSEARCH:
+ rval = v_cht(sp, ep, vp);
+ break;
+ case tSEARCH:
+ rval = v_chT(sp, ep, vp);
+ break;
+ default:
+ abort();
+ }
+ VIP(sp)->csearchdir = savedir;
+ return (rval);
+}
+
+/*
+ * v_cht -- [count]tc
+ * Search forward in the line for the next occurrence of the character.
+ * Place the cursor on it if it's a motion command, to its left if not.
+ */
+int
+v_cht(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (v_chf(sp, ep, vp))
+ return (1);
+
+ /*
+ * v_chf places the cursor on the character, and the 't' command
+ * wants it to its left. We know this is safe since we had to
+ * have moved right for v_chf() to have succeeded.
+ */
+ --vp->m_stop.cno;
+
+ VIP(sp)->csearchdir = tSEARCH;
+ return (0);
+}
+
+/*
+ * v_chf -- [count]fc
+ * Search forward in the line for the next occurrence of the character.
+ */
+int
+v_chf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t len;
+ recno_t lno;
+ u_long cnt;
+ int key;
+ char *endp, *p, *startp;
+
+ /*
+ * !!!
+ * If it's a dot command, it doesn't reset the key for which we're
+ * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'.
+ */
+ key = vp->character;
+ if (!F_ISSET(vp, VC_ISDOT))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = fSEARCH;
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+
+ endp = (startp = p) + len;
+ p += vp->m_start.cno;
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ while (++p < endp && *p != key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
+ }
+
+ vp->m_stop.cno = p - startp;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_chT -- [count]Tc
+ * Search backward in the line for the next occurrence of the character.
+ * Place the cursor to its right.
+ */
+int
+v_chT(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (v_chF(sp, ep, vp))
+ return (1);
+
+ /*
+ * v_chF places the cursor on the character, and the 'T' command
+ * wants it to its right. We know this is safe since we had to
+ * have moved left for v_chF() to have succeeded.
+ */
+ ++vp->m_stop.cno;
+ ++vp->m_final.cno;
+
+ VIP(sp)->csearchdir = TSEARCH;
+ return (0);
+}
+
+/*
+ * v_chF -- [count]Fc
+ * Search backward in the line for the next occurrence of the character.
+ * Place the cursor on it.
+ */
+int
+v_chF(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+ u_long cnt;
+ int key;
+ char *endp, *p;
+
+ /*
+ * !!!
+ * If it's a dot command, it doesn't reset the key for which
+ * we're searching, e.g. in "df1|f2|.|;", the ';' searches
+ * for a '2'.
+ */
+ key = vp->character;
+ if (!F_ISSET(vp, VC_ISDOT))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = FSEARCH;
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+
+ endp = p - 1;
+ p += vp->m_start.cno;
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ while (--p > endp && *p != key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
+ }
+
+ vp->m_stop.cno = (p - endp) - 1;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+static void
+noprev(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "No previous F, f, T or t search.");
+}
+
+static void
+notfound(sp, ch)
+ SCR *sp;
+ ARG_CHAR_T ch;
+{
+ msgq(sp, M_BERR, "%s not found.", charname(sp, ch));
+}
diff --git a/usr.bin/vi/vi/v_delete.c b/usr.bin/vi/vi/v_delete.c
new file mode 100644
index 000000000000..46ce24d65d23
--- /dev/null
+++ b/usr.bin/vi/vi/v_delete.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_delete.c 8.10 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_Delete -- [buffer][count]D
+ * Delete line command.
+ */
+int
+v_Delete(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ return (0);
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0)
+ return (0);
+
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len - 1;
+
+ /* Yank the lines. */
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_DELETE))
+ return (1);
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 0))
+ return (1);
+
+ vp->m_final.lno = vp->m_start.lno;
+ vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0;
+ return (0);
+}
+
+/*
+ * v_delete -- [buffer][count]d[count]motion
+ * Delete a range of text.
+ */
+int
+v_delete(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t nlines;
+ size_t len;
+ int lmode;
+
+ /* Yank the lines. */
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode | CUT_DELETE))
+ return (1);
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ /*
+ * Check for deletion of the entire file. Try to check a close
+ * by line so we don't go to the end of the file unnecessarily.
+ */
+ if (file_gline(sp, ep, vp->m_final.lno + 1, &len) == NULL) {
+ if (file_lline(sp, ep, &nlines))
+ return (1);
+ if (nlines == 0) {
+ vp->m_final.lno = 1;
+ vp->m_final.cno = 0;
+ return (0);
+ }
+ }
+
+ /*
+ * One special correction, in case we've deleted the current line or
+ * character. We check it here instead of checking in every command
+ * that can be a motion component.
+ */
+ if (file_gline(sp, ep, vp->m_final.lno, &len) == NULL) {
+ if (file_gline(sp, ep, nlines, &len) == NULL) {
+ GETLINE_ERR(sp, nlines);
+ return (1);
+ }
+ vp->m_final.lno = nlines;
+ }
+ if (vp->m_final.cno >= len)
+ vp->m_final.cno = len ? len - 1 : 0;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_ex.c b/usr.bin/vi/vi/v_ex.c
new file mode 100644
index 000000000000..49f688844efb
--- /dev/null
+++ b/usr.bin/vi/vi/v_ex.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_ex.c 8.3 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_ex -- :
+ * Execute a colon command line.
+ */
+int
+v_ex(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (sp->s_ex_run(sp, ep, &vp->m_final));
+}
+
+/*
+ * v_exmode -- Q
+ * Switch the editor into EX mode.
+ */
+int
+v_exmode(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ sp->saved_vi_mode = F_ISSET(sp, S_VI_CURSES | S_VI_XAW);
+ F_CLR(sp, S_SCREENS);
+ F_SET(sp, S_EX);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_filter.c b/usr.bin/vi/vi/v_filter.c
new file mode 100644
index 000000000000..39844a8a356e
--- /dev/null
+++ b/usr.bin/vi/vi/v_filter.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_filter.c 8.12 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+/*
+ * v_filter -- [count]!motion command(s)
+ * Run range through shell commands, replacing text.
+ */
+int
+v_filter(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+ TEXT *tp;
+
+ /*
+ * !!!
+ * Historical vi permitted "!!" in an empty file. This is
+ * handled as a special case in the ex_bang routine. Don't
+ * modify this setup without understanding that one. In
+ * particular, note that we're manipulating the ex argument
+ * structures behind ex's back.
+ */
+ SETCMDARG(cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
+ EXP(sp)->argsoff = 0; /* XXX */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ if (argv_exp1(sp, ep, &cmd, "!", 1, 1))
+ return (1);
+ } else {
+ /* Get the command from the user. */
+ if (sp->s_get(sp, ep, &sp->tiq,
+ '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
+ return (1);
+ /*
+ * Len is 0 if backspaced over the prompt,
+ * 1 if only CR entered.
+ */
+ tp = sp->tiq.cqh_first;
+ if (tp->len <= 1)
+ return (0);
+
+ if (argv_exp1(sp, ep, &cmd, tp->lb + 1, tp->len - 1, 1))
+ return (1);
+ }
+ cmd.argc = EXP(sp)->argsoff; /* XXX */
+ cmd.argv = EXP(sp)->args; /* XXX */
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_increment.c b/usr.bin/vi/vi/v_increment.c
new file mode 100644
index 000000000000..aee358922662
--- /dev/null
+++ b/usr.bin/vi/vi/v_increment.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_increment.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static char * const fmt[] = {
+#define DEC 0
+ "%ld",
+#define SDEC 1
+ "%+ld",
+#define HEXC 2
+ "%#0.*lX",
+#define HEXL 3
+ "%#0.*lx",
+#define OCTAL 4
+ "%#0.*lo",
+};
+
+/*
+ * v_increment -- [count]#[#+-]
+ * Increment/decrement a keyword number.
+ */
+int
+v_increment(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VI_PRIVATE *vip;
+ u_long ulval;
+ long lval;
+ size_t blen, len, nlen;
+ int rval;
+ char *bp, *ntype, *p, nbuf[100];
+
+ vip = VIP(sp);
+
+ /* Do repeat operations. */
+ if (vp->character == '#')
+ vp->character = vip->inc_lastch;
+
+ /* Get new value. */
+ if (F_ISSET(vp, VC_C1SET))
+ vip->inc_lastval = vp->count;
+
+ if (vp->character != '+' && vp->character != '-') {
+ msgq(sp, M_ERR, "usage: %s.", vp->kp->usage);
+ return (1);
+ }
+ vip->inc_lastch = vp->character;
+
+ /* Figure out the resulting type and number. */
+ p = vp->keyword;
+ len = vp->klen;
+ if (len > 1 && p[0] == '0') {
+ if (vp->character == '+') {
+ ulval = strtoul(vp->keyword, NULL, 0);
+ if (ULONG_MAX - ulval < vip->inc_lastval)
+ goto overflow;
+ ulval += vip->inc_lastval;
+ } else {
+ ulval = strtoul(vp->keyword, NULL, 0);
+ if (ulval < vip->inc_lastval)
+ goto underflow;
+ ulval -= vip->inc_lastval;
+ }
+ ntype = fmt[OCTAL];
+ if (len > 2)
+ if (p[1] == 'X')
+ ntype = fmt[HEXC];
+ else if (p[1] == 'x')
+ ntype = fmt[HEXL];
+ nlen = snprintf(nbuf, sizeof(nbuf), ntype, len, ulval);
+ } else {
+ if (vp->character == '+') {
+ lval = strtol(vp->keyword, NULL, 0);
+ if (lval > 0 && LONG_MAX - lval < vip->inc_lastval) {
+overflow: msgq(sp, M_ERR, "Resulting number too large.");
+ return (1);
+ }
+ lval += vip->inc_lastval;
+ } else {
+ lval = strtol(vp->keyword, NULL, 0);
+ if (lval < 0 && -(LONG_MIN - lval) < vip->inc_lastval) {
+underflow: msgq(sp, M_ERR, "Resulting number too small.");
+ return (1);
+ }
+ lval -= vip->inc_lastval;
+ }
+ ntype = lval != 0 &&
+ (*vp->keyword == '+' || *vp->keyword == '-') ?
+ fmt[SDEC] : fmt[DEC];
+ nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
+ }
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ GET_SPACE_RET(sp, bp, blen, len + nlen);
+ memmove(bp, p, vp->m_start.cno);
+ memmove(bp + vp->m_start.cno, nbuf, nlen);
+ memmove(bp + vp->m_start.cno + nlen,
+ p + vp->m_start.cno + vp->klen, len - vp->m_start.cno - vp->klen);
+ len = len - vp->klen + nlen;
+
+ rval = file_sline(sp, ep, vp->m_start.lno, bp, len);
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
diff --git a/usr.bin/vi/vi/v_init.c b/usr.bin/vi/vi/v_init.c
new file mode 100644
index 000000000000..122c6c60e263
--- /dev/null
+++ b/usr.bin/vi/vi/v_init.c
@@ -0,0 +1,241 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_init.c 8.21 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+static int v_comment __P((SCR *, EXF *));
+
+/*
+ * v_screen_copy --
+ * Copy vi screen.
+ */
+int
+v_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ VI_PRIVATE *ovip, *nvip;
+
+ /* Create the private vi structure. */
+ CALLOC_RET(orig, nvip, VI_PRIVATE *, 1, sizeof(VI_PRIVATE));
+ sp->vi_private = nvip;
+
+ if (orig == NULL) {
+ nvip->inc_lastch = '+';
+ nvip->inc_lastval = 1;
+ nvip->csearchdir = CNOTSET;
+ } else {
+ ovip = VIP(orig);
+
+ /* User can replay the last input, but nothing else. */
+ if (ovip->rep_len != 0) {
+ MALLOC(orig, nvip->rep, char *, ovip->rep_len);
+ if (nvip->rep != NULL) {
+ memmove(nvip->rep, ovip->rep, ovip->rep_len);
+ nvip->rep_len = ovip->rep_len;
+ }
+ }
+
+ nvip->inc_lastch = ovip->inc_lastch;
+ nvip->inc_lastval = ovip->inc_lastval;
+
+ if (ovip->paragraph != NULL &&
+ (nvip->paragraph = strdup(ovip->paragraph)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ nvip->lastckey = ovip->lastckey;
+ nvip->csearchdir = ovip->csearchdir;
+ }
+ return (0);
+}
+
+/*
+ * v_screen_end --
+ * End a vi screen.
+ */
+int
+v_screen_end(sp)
+ SCR *sp;
+{
+ VI_PRIVATE *vip;
+
+ vip = VIP(sp);
+
+ if (vip->rep != NULL)
+ FREE(vip->rep, vip->rep_len);
+
+ if (vip->paragraph != NULL)
+ FREE(vip->paragraph, vip->paragraph_len);
+
+ /* Free private memory. */
+ FREE(vip, sizeof(VI_PRIVATE));
+ sp->vi_private = NULL;
+
+ return (0);
+}
+
+/*
+ * v_init --
+ * Initialize vi.
+ */
+int
+v_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ size_t len;
+
+ /*
+ * The default address is line 1, column 0. If the address set
+ * bit is on for this file, load the address, ensuring that it
+ * exists.
+ */
+ if (F_ISSET(sp->frp, FR_CURSORSET)) {
+ sp->lno = sp->frp->lno;
+ sp->cno = sp->frp->cno;
+
+ if (file_gline(sp, ep, sp->lno, &len) == NULL) {
+ if (sp->lno != 1 || sp->cno != 0) {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ }
+ } else if (sp->cno >= len)
+ sp->cno = 0;
+ } else {
+ sp->lno = 1;
+ sp->cno = 0;
+
+ if (O_ISSET(sp, O_COMMENT) && v_comment(sp, ep))
+ return (1);
+ }
+
+ /* Reset strange attraction. */
+ sp->rcm = 0;
+ sp->rcmflags = 0;
+
+ /* Make ex display to a special function. */
+ if ((sp->stdfp = fwopen(sp, sp->s_ex_write)) == NULL) {
+ msgq(sp, M_SYSERR, "ex output");
+ return (1);
+ }
+#ifdef MAKE_EX_OUTPUT_LINE_BUFFERED
+ (void)setvbuf(sp->stdfp, NULL, _IOLBF, 0);
+#endif
+
+ /* Display the status line. */
+ return (status(sp, ep, sp->lno, 0));
+}
+
+/*
+ * v_end --
+ * End vi session.
+ */
+int
+v_end(sp)
+ SCR *sp;
+{
+ /* Close down ex output file descriptor. */
+ (void)fclose(sp->stdfp);
+
+ return (0);
+}
+
+/*
+ * v_optchange --
+ * Handle change of options for vi.
+ */
+int
+v_optchange(sp, opt)
+ SCR *sp;
+ int opt;
+{
+ switch (opt) {
+ case O_PARAGRAPHS:
+ case O_SECTIONS:
+ return (v_buildparagraph(sp));
+ }
+ return (0);
+}
+
+/*
+ * v_comment --
+ * Skip the first comment.
+ */
+static int
+v_comment(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ recno_t lno;
+ size_t len;
+ char *p;
+
+ for (lno = 1;
+ (p = file_gline(sp, ep, lno, &len)) != NULL && len == 0; ++lno);
+ if (p == NULL || len <= 1 || memcmp(p, "/*", 2))
+ return (0);
+ do {
+ for (; len; --len, ++p)
+ if (p[0] == '*' && len > 1 && p[1] == '/') {
+ sp->lno = lno;
+ return (0);
+ }
+ } while ((p = file_gline(sp, ep, ++lno, &len)) != NULL);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_join.c b/usr.bin/vi/vi/v_join.c
new file mode 100644
index 000000000000..e7eeaa235d85
--- /dev/null
+++ b/usr.bin/vi/vi/v_join.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_join.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_join -- [count]J
+ * Join lines together.
+ */
+int
+v_join(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+ int lno;
+
+ /*
+ * YASC.
+ * The general rule is that '#J' joins # lines, counting the current
+ * line. However, 'J' and '1J' are the same as '2J', i.e. join the
+ * current and next lines. This doesn't map well into the ex command
+ * (which takes two line numbers), so we handle it here. Note that
+ * we never test for EOF -- historically going past the end of file
+ * worked just fine.
+ */
+ lno = vp->m_start.lno + 1;
+ if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
+ lno = vp->m_start.lno + (vp->count - 1);
+
+ SETCMDARG(cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, NULL);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_left.c b/usr.bin/vi/vi/v_left.c
new file mode 100644
index 000000000000..8c44657f0d20
--- /dev/null
+++ b/usr.bin/vi/vi/v_left.c
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_left.c 8.8 (Berkeley) 3/10/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_left -- [count]^H, [count]h
+ * Move left by columns.
+ */
+int
+v_left(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t cnt;
+
+ /*
+ * !!!
+ * The ^H and h commands always failed in the first column.
+ */
+ if (vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /* Find the end of the range. */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (vp->m_start.cno > cnt)
+ vp->m_stop.cno = vp->m_start.cno - cnt;
+ else
+ vp->m_stop.cno = 0;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+/*
+ * v_cfirst -- [count]_
+ * Move to the first non-blank character in a line.
+ */
+int
+v_cfirst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t cnt;
+
+ /*
+ * !!!
+ * If the _ is a motion component, it makes the command a line motion
+ * e.g. "d_" deletes the line. It also means that the cursor doesn't
+ * move.
+ *
+ * The _ command never failed in the first column.
+ */
+ if (ISMOTION(vp))
+ F_SET(vp, VM_LMODE);
+ /*
+ * !!!
+ * Historically a specified count makes _ move down count - 1
+ * rows, so, "3_" is the same as "2j_".
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (cnt != 1) {
+ --vp->count;
+ return (v_down(sp, ep, vp));
+ }
+
+ /*
+ * Move to the first non-blank.
+ *
+ * Can't just use RCM_SET_FNB, in case _ is used as the motion
+ * component of another command.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_first -- ^
+ * Move to the first non-blank character in this line.
+ */
+int
+v_first(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * Yielding to none in our quest for compatibility with every
+ * historical blemish of vi, no matter how strange it might be,
+ * we permit the user to enter a count and then ignore it.
+ */
+
+ /*
+ * Move to the first non-blank.
+ *
+ * Can't just use RCM_SET_FNB, in case ^ is used as the motion
+ * component of another command.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+
+ /*
+ * !!!
+ * The ^ command succeeded if used as a command without a whitespace
+ * character preceding the cursor in the line, but failed if used as
+ * a motion component in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+/*
+ * v_ncol -- [count]|
+ * Move to column count or the first column on this line. If the
+ * requested column is past EOL, move to EOL. The nasty part is
+ * that we have to know character column widths to make this work.
+ */
+int
+v_ncol(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (F_ISSET(vp, VC_C1SET) && vp->count > 1) {
+ --vp->count;
+ vp->m_stop.cno =
+ sp->s_colpos(sp, ep, vp->m_start.lno, (size_t)vp->count);
+ /*
+ * !!!
+ * The | command succeeded if used as a command and the cursor
+ * didn't move, but failed if used as a motion component in the
+ * same situation.
+ */
+ if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) {
+ v_nomove(sp);
+ return (1);
+ }
+ } else {
+ /*
+ * !!!
+ * The | command succeeded if used as a command in column 0
+ * without a count, but failed if used as a motion component
+ * in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+ vp->m_stop.cno = 0;
+ }
+
+ /*
+ * If moving right, non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. If moving left, non-motion and
+ * VC_D commands move to the end of the range. VC_Y remains at the
+ * start. Ignore VC_C and VC_S. Motion left commands adjust the
+ * starting point to the character before the current one.
+ */
+ if (vp->m_start.cno < vp->m_stop.cno)
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ else {
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_Y))
+ vp->m_final = vp->m_start;
+ --vp->m_start.cno;
+ }
+ }
+ return (0);
+}
+
+/*
+ * v_zero -- 0
+ * Move to the first column on this line.
+ */
+int
+v_zero(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * The 0 command succeeded if used as a command in the first column
+ * but failed if used as a motion component in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_stop.cno = 0;
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_mark.c b/usr.bin/vi/vi/v_mark.c
new file mode 100644
index 000000000000..ae0585d930ef
--- /dev/null
+++ b/usr.bin/vi/vi/v_mark.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_mark.c 8.6 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_mark -- m[a-z]
+ * Set a mark.
+ */
+int
+v_mark(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark_set(sp, ep, vp->character, &vp->m_start, 1));
+}
+
+static int mark __P((SCR *, EXF *, VICMDARG *, enum direction));
+
+/*
+ * v_bmark -- `['`a-z]
+ * Move to a mark.
+ *
+ * Moves to a mark, setting both row and column.
+ *
+ * !!!
+ * Although not commonly known, the "'`" and "'`" forms are historically
+ * valid. The behavior is determined by the first character, so "`'" is
+ * the same as "``". Remember this fact -- you'll be amazed at how many
+ * people don't know it and will be delighted that you are able to tell
+ * them.
+ */
+int
+v_bmark(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark(sp, ep, vp, BACKWARD));
+}
+
+/*
+ * v_fmark -- '['`a-z]
+ * Move to a mark.
+ *
+ * Move to the first nonblank character of the line containing the mark.
+ */
+int
+v_fmark(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark(sp, ep, vp, FORWARD));
+}
+
+static int
+mark(sp, ep, vp, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum direction dir;
+{
+ if (mark_get(sp, ep, vp->character, &vp->m_stop))
+ return (1);
+
+ /* Forward marks move to the first non-blank. */
+ if (dir == FORWARD) {
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+ }
+
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp)) {
+ vp->m_final = vp->m_stop;
+ return (0);
+ }
+
+ /*
+ * !!!
+ * If a motion component, the cursor has to move.
+ */
+ if (vp->m_stop.lno == vp->m_start.lno &&
+ vp->m_stop.cno == vp->m_start.cno) {
+ v_nomove(sp);
+ return (1);
+ }
+
+ /*
+ * If moving right, VC_D and VC_Y stay at the start. If moving left,
+ * VC_D commands move to the end of the range and VC_Y remains at the
+ * start. Ignore VC_C and VC_S. Motion left commands adjust the
+ * starting point to the character before the current one.
+ */
+ if (vp->m_start.lno > vp->m_stop.lno ||
+ vp->m_start.lno == vp->m_stop.lno &&
+ vp->m_start.cno > vp->m_stop.cno) {
+ if (F_ISSET(vp, VC_D))
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
+ --vp->m_start.cno;
+ } else
+ vp->m_final = vp->m_start;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_match.c b/usr.bin/vi/vi/v_match.c
new file mode 100644
index 000000000000..0e5642ef9c49
--- /dev/null
+++ b/usr.bin/vi/vi/v_match.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_match.c 8.10 (Berkeley) 3/10/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_match -- %
+ * Search to matching character.
+ */
+int
+v_match(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VCS cs;
+ MARK *mp;
+ recno_t lno;
+ size_t cno, len, off;
+ int cnt, matchc, startc, (*gc)__P((SCR *, EXF *, VCS *));
+ char *p;
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ goto nomatch;
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historical practice was to search for the initial character
+ * in the forward direction only.
+ */
+ for (off = vp->m_start.cno;; ++off) {
+ if (off >= len) {
+nomatch: msgq(sp, M_BERR, "No match character on this line.");
+ return (1);
+ }
+ switch (startc = p[off]) {
+ case '(':
+ matchc = ')';
+ gc = cs_next;
+ break;
+ case ')':
+ matchc = '(';
+ gc = cs_prev;
+ break;
+ case '[':
+ matchc = ']';
+ gc = cs_next;
+ break;
+ case ']':
+ matchc = '[';
+ gc = cs_prev;
+ break;
+ case '{':
+ matchc = '}';
+ gc = cs_next;
+ break;
+ case '}':
+ matchc = '{';
+ gc = cs_prev;
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = off;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+ for (cnt = 1;;) {
+ if (gc(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags != 0) {
+ if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
+ break;
+ continue;
+ }
+ if (cs.cs_ch == startc)
+ ++cnt;
+ else if (cs.cs_ch == matchc && --cnt == 0)
+ break;
+ }
+ if (cnt) {
+ msgq(sp, M_BERR, "Matching character not found.");
+ return (1);
+ }
+
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * If moving right, non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. If moving left, non-motion and
+ * VC_D commands move to the end of the range. VC_Y remains at the
+ * start. Ignore VC_C and VC_S.
+ *
+ * !!!
+ * Don't correct for leftward movement -- historic vi deleted the
+ * starting cursor position when deleting to a match.
+ */
+ if (vp->m_start.lno < vp->m_stop.lno ||
+ vp->m_start.lno == vp->m_stop.lno &&
+ vp->m_start.cno < vp->m_stop.cno)
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ else
+ vp->m_final = ISMOTION(vp) &&
+ F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+
+ /*
+ * !!!
+ * If the motion is across lines, and the earliest cursor position
+ * is at or before any non-blank characters in its line, i.e. the
+ * movement is cutting all of the line's text, the buffer is in line
+ * mode.
+ */
+ if (ISMOTION(vp) && vp->m_start.lno != vp->m_stop.lno) {
+ mp = vp->m_start.lno < vp->m_stop.lno ?
+ &vp->m_start : &vp->m_stop;
+ if (mp->cno == 0) {
+ F_SET(vp, VM_LMODE);
+ return (0);
+ }
+ cno = 0;
+ if (nonblank(sp, ep, mp->lno, &cno))
+ return (1);
+ if (cno >= mp->cno)
+ F_SET(vp, VM_LMODE);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_ntext.c b/usr.bin/vi/vi/v_ntext.c
new file mode 100644
index 000000000000..e4060af97bc8
--- /dev/null
+++ b/usr.bin/vi/vi/v_ntext.c
@@ -0,0 +1,1827 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_ntext.c 8.95 (Berkeley) 3/24/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "seq.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+static int txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *));
+static void txt_ai_resolve __P((SCR *, TEXT *));
+static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
+static void txt_err __P((SCR *, EXF *, TEXTH *));
+static int txt_hex __P((SCR *, TEXT *, int *, CHAR_T *));
+static int txt_indent __P((SCR *, TEXT *));
+static int txt_margin __P((SCR *, TEXT *, int *, CHAR_T *));
+static int txt_outdent __P((SCR *, TEXT *));
+static void txt_showmatch __P((SCR *, EXF *));
+static void txt_Rcleanup __P((SCR *,
+ TEXTH *, TEXT *, const char *, const size_t));
+static int txt_resolve __P((SCR *, EXF *, TEXTH *));
+static void txt_unmap __P((SCR *, TEXT *, u_int *));
+
+/* Cursor character (space is hard to track on the screen). */
+#if defined(DEBUG) && 0
+#undef CURSOR_CH
+#define CURSOR_CH '+'
+#endif
+
+/* Local version of BINC. */
+#define TBINC(sp, lp, llen, nlen) { \
+ if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
+ goto err; \
+}
+
+/*
+ * v_ntext --
+ * Read in text from the user.
+ *
+ * !!!
+ * Historic vi did a special screen optimization for tab characters. For
+ * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of
+ * the string when it was displayed. Because this implementation redisplays
+ * the entire line on each keystroke, the "bcd" gets pushed to the right as
+ * we ignore that the user has "promised" to change the rest of the characters.
+ * Users have noticed, but this isn't worth fixing, and, the way that the
+ * historic vi did it results in an even worse bug. Given the keystrokes
+ * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
+ * on the second <esc> key.
+ */
+int
+v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ MARK *tm; /* To MARK. */
+ const char *lp; /* Input line. */
+ const size_t len; /* Input line length. */
+ MARK *rp; /* Return MARK. */
+ int prompt; /* Prompt to display. */
+ recno_t ai_line; /* Line number to use for autoindent count. */
+ u_int flags; /* TXT_ flags. */
+{
+ /* State of abbreviation checks. */
+ enum { A_NOTSET, A_NOTWORD, A_INWORD } abb;
+ /* State of the "[^0]^D" sequences. */
+ enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
+ /* State of the hex input character. */
+ enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
+ /* State of quotation. */
+ enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
+ CH ikey; /* Input character structure. */
+ CHAR_T ch; /* Input character. */
+ TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
+ size_t rcol; /* 0-N: insert offset in the replay buffer. */
+ size_t col; /* Current column. */
+ u_long margin; /* Wrapmargin value. */
+ u_int iflags; /* Input flags. */
+ int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */
+ int eval; /* Routine return value. */
+ int replay; /* If replaying a set of input. */
+ int showmatch; /* Showmatch set on this character. */
+ int testnr; /* Test first character for nul replay. */
+ int max, tmp;
+ int unmap_tst; /* Input map needs testing. */
+ char *p;
+
+ /*
+ * Set the input flag, so tabs get displayed correctly
+ * and everyone knows that the text buffer is in use.
+ */
+ F_SET(sp, S_INPUT);
+
+ /* Local initialization. */
+ eval = 0;
+
+ /*
+ * Get one TEXT structure with some initial buffer space, reusing
+ * the last one if it's big enough. (All TEXT bookkeeping fields
+ * default to 0 -- text_init() handles this.) If changing a line,
+ * copy it into the TEXT buffer.
+ */
+ if (tiqh->cqh_first != (void *)tiqh) {
+ tp = tiqh->cqh_first;
+ if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
+ text_lfree(tiqh);
+ goto newtp;
+ }
+ tp->ai = tp->insert = tp->offset = tp->owrite = 0;
+ if (lp != NULL) {
+ tp->len = len;
+ memmove(tp->lb, lp, len);
+ } else
+ tp->len = 0;
+ } else {
+newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
+ return (1);
+ CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
+ }
+
+ /* Set the starting line number. */
+ tp->lno = sp->lno;
+
+ /*
+ * Set the insert and overwrite counts. If overwriting characters,
+ * do insertion afterward. If not overwriting characters, assume
+ * doing insertion. If change is to a mark, emphasize it with an
+ * END_CH.
+ */
+ if (len) {
+ if (LF_ISSET(TXT_OVERWRITE)) {
+ tp->owrite = (tm->cno - sp->cno) + 1;
+ tp->insert = (len - tm->cno) - 1;
+ } else
+ tp->insert = len - sp->cno;
+
+ if (LF_ISSET(TXT_EMARK))
+ tp->lb[tm->cno] = END_CH;
+ }
+
+ /*
+ * Many of the special cases in this routine are to handle autoindent
+ * support. Somebody decided that it would be a good idea if "^^D"
+ * and "0^D" deleted all of the autoindented characters. In an editor
+ * that takes single character input from the user, this beggars the
+ * imagination. Note also, "^^D" resets the next lines' autoindent,
+ * but "0^D" doesn't.
+ *
+ * We assume that autoindent only happens on empty lines, so insert
+ * and overwrite will be zero. If doing autoindent, figure out how
+ * much indentation we need and fill it in. Update input column and
+ * screen cursor as necessary.
+ */
+ if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
+ if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
+ return (1);
+ sp->cno = tp->ai;
+ } else {
+ /*
+ * The cc and S commands have a special feature -- leading
+ * <blank> characters are handled as autoindent characters.
+ * Beauty!
+ */
+ if (LF_ISSET(TXT_AICHARS)) {
+ tp->offset = 0;
+ tp->ai = sp->cno;
+ } else
+ tp->offset = sp->cno;
+ }
+
+ /* If getting a command buffer from the user, there may be a prompt. */
+ if (LF_ISSET(TXT_PROMPT)) {
+ tp->lb[sp->cno++] = prompt;
+ ++tp->len;
+ ++tp->offset;
+ }
+
+ /*
+ * If appending after the end-of-line, add a space into the buffer
+ * and move the cursor right. This space is inserted, i.e. pushed
+ * along, and then deleted when the line is resolved. Assumes that
+ * the cursor is already positioned at the end of the line. This
+ * avoids the nastiness of having the cursor reside on a magical
+ * column, i.e. a column that doesn't really exist. The only down
+ * side is that we may wrap lines or scroll the screen before it's
+ * strictly necessary. Not a big deal.
+ */
+ if (LF_ISSET(TXT_APPENDEOL)) {
+ tp->lb[sp->cno] = CURSOR_CH;
+ ++tp->len;
+ ++tp->insert;
+ }
+
+ /*
+ * Historic practice is that the wrapmargin value was a distance
+ * from the RIGHT-HAND column, not the left. It's more useful to
+ * us as a distance from the left-hand column.
+ *
+ * !!!
+ * Replay commands are not affected by wrapmargin values. What
+ * I found surprising was that people actually depend on it, as
+ * in this gem of a macro which centers lines:
+ *
+ * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p
+ *
+ * XXX
+ * Setting margin causes a significant performance hit. Normally
+ * we don't update the screen if there are keys waiting, but we
+ * have to if margin is set, otherwise the screen routines don't
+ * know where the cursor is.
+ */
+ if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))
+ margin = 0;
+ else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
+ margin = sp->cols - margin;
+
+ /* Initialize abbreviations checks. */
+ if (F_ISSET(sp->gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
+ abb = A_INWORD;
+ ab_cnt = ab_turnoff = 0;
+ } else
+ abb = A_NOTSET;
+
+ /*
+ * Set up the dot command. Dot commands are done by saving the
+ * actual characters and replaying the input. We have to push
+ * the characters onto the key stack and then handle them normally,
+ * otherwise things like wrapmargin will fail.
+ *
+ * XXX
+ * It would be nice if we could swallow backspaces and such, but
+ * it's not all that easy to do. Another possibility would be to
+ * recognize full line insertions, which could be performed quickly,
+ * without replay.
+ */
+nullreplay:
+ rcol = 0;
+ if (replay = LF_ISSET(TXT_REPLAY)) {
+ /*
+ * !!!
+ * Historically, it wasn't an error to replay non-existent
+ * input. This test is necessary, we get here by the user
+ * doing an input command followed by a nul.
+ *
+ * !!!
+ * Historically, vi did not remap or reabbreviate replayed
+ * input. It did, however, beep at you if you changed an
+ * abbreviation and then replayed the input. We're not that
+ * compatible.
+ */
+ if (VIP(sp)->rep == NULL)
+ return (0);
+ if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))
+ return (1);
+ testnr = 0;
+ abb = A_NOTSET;
+ LF_CLR(TXT_RECORD);
+ } else
+ testnr = 1;
+
+ unmap_tst = LF_ISSET(TXT_MAPINPUT) && LF_ISSET(TXT_INFOLINE);
+ iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
+ for (showmatch = 0,
+ carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
+ /*
+ * Reset the line and update the screen. (The txt_showmatch()
+ * code refreshes the screen for us.) Don't refresh unless
+ * we're about to wait on a character or we need to know where
+ * the cursor really is.
+ */
+ if (showmatch || margin || !KEYS_WAITING(sp)) {
+ if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
+ goto err;
+ if (showmatch) {
+ showmatch = 0;
+ txt_showmatch(sp, ep);
+ } else if (sp->s_refresh(sp, ep))
+ goto err;
+ }
+
+ /* Get the next character. */
+next_ch: if (term_key(sp, &ikey, quoted == Q_THISCHAR ?
+ iflags & ~(TXT_MAPCOMMAND | TXT_MAPINPUT) :
+ iflags) != INP_OK)
+ goto err;
+ ch = ikey.ch;
+
+ /* Abbreviation check. See comment in txt_abbrev(). */
+#define MAX_ABBREVIATION_EXPANSION 256
+ if (ikey.flags & CH_ABBREVIATED) {
+ if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
+ term_ab_flush(sp,
+ "Abbreviation exceeded maximum number of characters");
+ ab_cnt = 0;
+ continue;
+ }
+ } else
+ ab_cnt = 0;
+
+ /*
+ * !!!
+ * Historic feature. If the first character of the input is
+ * a nul, replay the previous input. This isn't documented
+ * anywhere, and is a great test of vi clones.
+ */
+ if (ch == '\0' && testnr) {
+ LF_SET(TXT_REPLAY);
+ goto nullreplay;
+ }
+ testnr = 0;
+
+ /*
+ * Check to see if the character fits into the input (and
+ * replay, if necessary) buffers. It isn't necessary to
+ * have tp->len bytes, since it doesn't consider overwrite
+ * characters, but not worth fixing.
+ */
+ if (LF_ISSET(TXT_RECORD)) {
+ TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
+ VIP(sp)->rep[rcol++] = ch;
+ }
+ TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
+
+ /*
+ * If the character was quoted, replace the last character
+ * (the literal mark) with the new character. If quoted
+ * by someone else, simply insert the character.
+ *
+ * !!!
+ * Extension -- if the quoted character is HEX_CH, enter hex
+ * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
+ * try to use the value as a character. Anything else resets
+ * hex mode.
+ */
+ if (ikey.flags & CH_QUOTED)
+ goto insq_ch;
+ if (quoted == Q_THISCHAR) {
+ --sp->cno;
+ ++tp->owrite;
+ quoted = Q_NOTSET;
+
+ if (ch == HEX_CH)
+ hex = H_NEXTCHAR;
+ goto insq_ch;
+ }
+
+ switch (ikey.value) {
+ case K_CR:
+ case K_NL: /* New line. */
+#define LINE_RESOLVE { \
+ /* \
+ * Handle abbreviations. If there was one, \
+ * discard the replay characters. \
+ */ \
+ if (abb == A_INWORD && !replay) { \
+ if (txt_abbrev(sp, tp, &ch, \
+ LF_ISSET(TXT_INFOLINE), &tmp, \
+ &ab_turnoff)) \
+ goto err; \
+ if (tmp) { \
+ if (LF_ISSET(TXT_RECORD)) \
+ rcol -= tmp; \
+ goto next_ch; \
+ } \
+ } \
+ if (abb != A_NOTSET) \
+ abb = A_NOTWORD; \
+ if (unmap_tst) \
+ txt_unmap(sp, tp, &iflags); \
+ /* Handle hex numbers. */ \
+ if (hex == H_INHEX) { \
+ if (txt_hex(sp, tp, &tmp, &ch)) \
+ goto err; \
+ if (tmp) { \
+ hex = H_NOTSET; \
+ goto next_ch; \
+ } \
+ } \
+ /* Clean up for the 'R' command. */ \
+ if (LF_ISSET(TXT_REPLACE)) \
+ txt_Rcleanup(sp, tiqh, tp, lp, len); \
+ /* Delete any appended cursor. */ \
+ if (LF_ISSET(TXT_APPENDEOL)) { \
+ --tp->len; \
+ --tp->insert; \
+ } \
+}
+ LINE_RESOLVE;
+
+ /* CR returns from the vi command line. */
+ if (LF_ISSET(TXT_CR)) {
+ /*
+ * If a script window and not the colon
+ * line, push a <cr> so it gets executed.
+ */
+ if (F_ISSET(sp, S_SCRIPT) &&
+ !LF_ISSET(TXT_INFOLINE))
+ (void)term_push(sp,
+ "\r", 1, 0, CH_NOMAP);
+ goto k_escape;
+ }
+
+ /*
+ * Historic practice was to delete any <blank>
+ * characters following the inserted newline.
+ * This affects the 'R', 'c', and 's' commands.
+ */
+ for (p = tp->lb + sp->cno + tp->owrite;
+ tp->insert && isblank(*p);
+ ++p, ++tp->owrite, --tp->insert);
+
+ /*
+ * Move any remaining insert characters into
+ * a new TEXT structure.
+ */
+ if ((ntp = text_init(sp,
+ tp->lb + sp->cno + tp->owrite,
+ tp->insert, tp->insert + 32)) == NULL)
+ goto err;
+
+ /* Set bookkeeping for the new line. */
+ ntp->lno = tp->lno + 1;
+ ntp->insert = tp->insert;
+
+ /*
+ * Note if the user inserted any characters on this
+ * line. Done before calling txt_ai_resolve() because
+ * it changes the value of sp->cno without making the
+ * corresponding changes to tp->ai.
+ */
+ tmp = sp->cno <= tp->ai;
+
+ /*
+ * Resolve autoindented characters for the old line.
+ * Reset the autoindent line value. 0^D keeps the ai
+ * line from changing, ^D changes the level, even if
+ * there are no characters in the old line. Note,
+ * if using the current tp structure, use the cursor
+ * as the length, the user may have erased autoindent
+ * characters.
+ */
+ if (LF_ISSET(TXT_AUTOINDENT)) {
+ txt_ai_resolve(sp, tp);
+
+ if (carat_st == C_NOCHANGE) {
+ if (txt_auto(sp, ep,
+ OOBLNO, &ait, ait.ai, ntp))
+ goto err;
+ FREE_SPACE(sp, ait.lb, ait.lb_len);
+ } else
+ if (txt_auto(sp, ep,
+ OOBLNO, tp, sp->cno, ntp))
+ goto err;
+ carat_st = C_NOTSET;
+ }
+
+ /*
+ * If the user hasn't entered any characters, delete
+ * any autoindent characters.
+ *
+ * !!!
+ * Historic vi didn't get the insert test right, if
+ * there were characters after the cursor, entering
+ * a <cr> left the autoindent characters on the line.
+ */
+ if (tmp)
+ sp->cno = 0;
+
+ /* Reset bookkeeping for the old line. */
+ tp->len = sp->cno;
+ tp->ai = tp->insert = tp->owrite = 0;
+
+ /* New cursor position. */
+ sp->cno = ntp->ai;
+
+ /* New lines are TXT_APPENDEOL if nothing to insert. */
+ if (ntp->insert == 0) {
+ TBINC(sp, ntp->lb, ntp->lb_len, ntp->len + 1);
+ LF_SET(TXT_APPENDEOL);
+ ntp->lb[sp->cno] = CURSOR_CH;
+ ++ntp->insert;
+ ++ntp->len;
+ }
+
+ /* Update the old line. */
+ if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
+ goto err;
+
+ /*
+ * Swap old and new TEXT's, and insert the new TEXT
+ * into the queue. (DON'T insert until the old line
+ * has been updated, or the inserted line count in
+ * line.c:file_gline() will be wrong.)
+ */
+ tp = ntp;
+ CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
+
+ /* Reset the cursor. */
+ sp->lno = tp->lno;
+
+ /* Update the new line. */
+ if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
+ goto err;
+
+ /* Set the renumber bit. */
+ F_SET(sp, S_RENUMBER);
+
+ /* Refresh if nothing waiting. */
+ if ((margin || !KEYS_WAITING(sp)) &&
+ sp->s_refresh(sp, ep))
+ goto err;
+ goto next_ch;
+ case K_ESCAPE: /* Escape. */
+ if (!LF_ISSET(TXT_ESCAPE))
+ goto ins_ch;
+
+ LINE_RESOLVE;
+
+ /*
+ * If there aren't any trailing characters in the line
+ * and the user hasn't entered any characters, delete
+ * the autoindent characters.
+ */
+ if (!tp->insert && sp->cno <= tp->ai) {
+ tp->len = tp->owrite = 0;
+ sp->cno = 0;
+ } else if (LF_ISSET(TXT_AUTOINDENT))
+ txt_ai_resolve(sp, tp);
+
+ /* If there are insert characters, copy them down. */
+k_escape: if (tp->insert && tp->owrite)
+ memmove(tp->lb + sp->cno,
+ tp->lb + sp->cno + tp->owrite, tp->insert);
+ tp->len -= tp->owrite;
+
+ /*
+ * Delete any lines that were inserted into the text
+ * structure and then erased.
+ */
+ while (tp->q.cqe_next != (void *)tiqh) {
+ ntp = tp->q.cqe_next;
+ CIRCLEQ_REMOVE(tiqh, ntp, q);
+ text_free(ntp);
+ }
+
+ /*
+ * If not resolving the lines into the file, end
+ * it with a nul.
+ *
+ * XXX
+ * This is wrong, should pass back a length.
+ */
+ if (LF_ISSET(TXT_RESOLVE)) {
+ if (txt_resolve(sp, ep, tiqh))
+ goto err;
+ /*
+ * Clear input flag -- input buffer no longer
+ * valid.
+ */
+ F_CLR(sp, S_INPUT);
+ } else {
+ TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
+ tp->lb[tp->len] = '\0';
+ }
+
+ /*
+ * Set the return cursor position to rest on the last
+ * inserted character.
+ */
+ if (rp != NULL) {
+ rp->lno = tp->lno;
+ rp->cno = sp->cno ? sp->cno - 1 : 0;
+ if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
+ goto err;
+ }
+ goto ret;
+ case K_CARAT: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
+ carat_st = C_CARATSET;
+ goto ins_ch;
+ case K_ZERO: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
+ carat_st = C_ZEROSET;
+ goto ins_ch;
+ case K_CNTRLD: /* Delete autoindent char. */
+ /*
+ * If in the first column or no characters to erase,
+ * ignore the ^D (this matches historic practice). If
+ * not doing autoindent or already inserted non-ai
+ * characters, it's a literal. The latter test is done
+ * in the switch, as the CARAT forms are N + 1, not N.
+ */
+ if (!LF_ISSET(TXT_AUTOINDENT))
+ goto ins_ch;
+ if (sp->cno == 0 || tp->ai == 0)
+ break;
+ switch (carat_st) {
+ case C_CARATSET: /* ^^D */
+ if (sp->cno > tp->ai + tp->offset + 1)
+ goto ins_ch;
+
+ /* Save the ai string for later. */
+ ait.lb = NULL;
+ ait.lb_len = 0;
+ TBINC(sp, ait.lb, ait.lb_len, tp->ai);
+ memmove(ait.lb, tp->lb, tp->ai);
+ ait.ai = ait.len = tp->ai;
+
+ carat_st = C_NOCHANGE;
+ goto leftmargin;
+ case C_ZEROSET: /* 0^D */
+ if (sp->cno > tp->ai + tp->offset + 1)
+ goto ins_ch;
+ carat_st = C_NOTSET;
+leftmargin: tp->lb[sp->cno - 1] = ' ';
+ tp->owrite += sp->cno - tp->offset;
+ tp->ai = 0;
+ sp->cno = tp->offset;
+ break;
+ case C_NOTSET: /* ^D */
+ if (sp->cno > tp->ai + tp->offset)
+ goto ins_ch;
+ (void)txt_outdent(sp, tp);
+ break;
+ default:
+ abort();
+ }
+ break;
+ case K_VERASE: /* Erase the last character. */
+ /*
+ * If can erase over the prompt, return. Len is 0
+ * if backspaced over the prompt, 1 if only CR entered.
+ */
+ if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
+ tp->len = 0;
+ goto ret;
+ }
+
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, flags)) == NULL)
+ goto err;
+ tp = ntp;
+ break;
+ }
+
+ /* If nothing to erase, bell the user. */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase.");
+ break;
+ }
+
+ /* Drop back one character. */
+ --sp->cno;
+
+ /*
+ * Increment overwrite, decrement ai if deleted.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ ++tp->owrite;
+ if (sp->cno < tp->ai)
+ --tp->ai;
+ break;
+ case K_VINTR:
+ /*
+ * !!!
+ * Historically, <interrupt> exited the user from
+ * editing the infoline, and returned to the main
+ * screen. It also beeped the terminal, but that
+ * seems excessive.
+ */
+ if (LF_ISSET(TXT_INFOLINE)) {
+ tp->lb[tp->len = 0] = '\0';
+ goto ret;
+ }
+ goto ins_ch;
+ case K_VWERASE: /* Skip back one word. */
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, flags)) == NULL)
+ goto err;
+ tp = ntp;
+ }
+
+ /*
+ * If at offset, nothing to erase so bell the user.
+ */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase.");
+ break;
+ }
+
+ /*
+ * First werase goes back to any autoindent
+ * and second werase goes back to the offset.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ if (tp->ai && sp->cno > tp->ai)
+ max = tp->ai;
+ else {
+ tp->ai = 0;
+ max = tp->offset;
+ }
+
+ /* Skip over trailing space characters. */
+ while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
+ --sp->cno;
+ ++tp->owrite;
+ }
+ if (sp->cno == max)
+ break;
+ /*
+ * There are three types of word erase found on UNIX
+ * systems. They can be identified by how the string
+ * /a/b/c is treated -- as 1, 3, or 6 words. Historic
+ * vi had two classes of characters, and strings were
+ * delimited by them and <blank>'s, so, 6 words. The
+ * historic tty interface used <blank>'s to delimit
+ * strings, so, 1 word. The algorithm offered in the
+ * 4.4BSD tty interface (as stty altwerase) treats it
+ * as 3 words -- there are two classes of characters,
+ * and strings are delimited by them and <blank>'s.
+ * The difference is that the type of the first erased
+ * character erased is ignored, which is exactly right
+ * when erasing pathname components. Here, the options
+ * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
+ * tty interface and the historic tty driver behavior,
+ * respectively, and the default is the same as the
+ * historic vi behavior.
+ */
+ if (LF_ISSET(TXT_TTYWERASE))
+ while (sp->cno > max) {
+ --sp->cno;
+ ++tp->owrite;
+ if (isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ else {
+ if (LF_ISSET(TXT_ALTWERASE)) {
+ --sp->cno;
+ ++tp->owrite;
+ if (isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ if (sp->cno > max)
+ tmp = inword(tp->lb[sp->cno - 1]);
+ while (sp->cno > max) {
+ --sp->cno;
+ ++tp->owrite;
+ if (tmp != inword(tp->lb[sp->cno - 1])
+ || isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ }
+ break;
+ case K_VKILL: /* Restart this line. */
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, flags)) == NULL)
+ goto err;
+ tp = ntp;
+ }
+
+ /* If at offset, nothing to erase so bell the user. */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase.");
+ break;
+ }
+
+ /*
+ * First kill goes back to any autoindent
+ * and second kill goes back to the offset.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ if (tp->ai && sp->cno > tp->ai)
+ max = tp->ai;
+ else {
+ tp->ai = 0;
+ max = tp->offset;
+ }
+ tp->owrite += sp->cno - max;
+ sp->cno = max;
+ break;
+ case K_CNTRLT: /* Add autoindent char. */
+ if (!LF_ISSET(TXT_CNTRLT))
+ goto ins_ch;
+ if (txt_indent(sp, tp))
+ goto err;
+ goto ebuf_chk;
+ case K_CNTRLZ:
+ (void)sp->s_suspend(sp);
+ break;
+#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
+ case K_FORMFEED:
+ F_SET(sp, S_REFRESH);
+ break;
+#endif
+ case K_RIGHTBRACE:
+ case K_RIGHTPAREN:
+ showmatch = LF_ISSET(TXT_SHOWMATCH);
+ goto ins_ch;
+ case K_VLNEXT: /* Quote the next character. */
+ /* If in hex mode, see if we've entered a hex value. */
+ if (hex == H_INHEX) {
+ if (txt_hex(sp, tp, &tmp, &ch))
+ goto err;
+ if (tmp) {
+ hex = H_NOTSET;
+ goto next_ch;
+ }
+ }
+ ch = '^';
+ quoted = Q_NEXTCHAR;
+ goto insq_ch;
+ default: /* Insert the character. */
+ins_ch: /*
+ * Historically, vi eliminated nul's out of hand. If
+ * the beautify option was set, it also deleted any
+ * unknown ASCII value less than space (040) and the
+ * del character (0177), except for tabs. Unknown is
+ * a key word here. Most vi documentation claims that
+ * it deleted everything but <tab>, <nl> and <ff>, as
+ * that's what the original 4BSD documentation said.
+ * This is obviously wrong, however, as <esc> would be
+ * included in that list. What we do is eliminate any
+ * unquoted, iscntrl() character that wasn't a replay
+ * and wasn't handled specially, except <tab> or <ff>.
+ */
+ if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ch) &&
+ ikey.value != K_FORMFEED && ikey.value != K_TAB) {
+ msgq(sp, M_BERR,
+ "Illegal character; quote to enter.");
+ break;
+ }
+insq_ch: /*
+ * If entering a non-word character after a word, check
+ * for abbreviations. If there was one, discard the
+ * replay characters. If entering a blank character,
+ * check for unmap commands, as well.
+ */
+ if (!inword(ch)) {
+ if (abb == A_INWORD && !replay) {
+ if (txt_abbrev(sp, tp, &ch,
+ LF_ISSET(TXT_INFOLINE),
+ &tmp, &ab_turnoff))
+ goto err;
+ if (tmp) {
+ if (LF_ISSET(TXT_RECORD))
+ rcol -= tmp;
+ goto next_ch;
+ }
+ }
+ if (isblank(ch) && unmap_tst)
+ txt_unmap(sp, tp, &iflags);
+ }
+ /* If in hex mode, see if we've entered a hex value. */
+ if (hex == H_INHEX && !isxdigit(ch)) {
+ if (txt_hex(sp, tp, &tmp, &ch))
+ goto err;
+ if (tmp) {
+ hex = H_NOTSET;
+ goto next_ch;
+ }
+ }
+ /* Check to see if we've crossed the margin. */
+ if (margin) {
+ if (sp->s_column(sp, ep, &col))
+ goto err;
+ if (col >= margin) {
+ if (txt_margin(sp, tp, &tmp, &ch))
+ goto err;
+ if (tmp)
+ goto next_ch;
+ }
+ }
+ if (abb != A_NOTSET)
+ abb = inword(ch) ? A_INWORD : A_NOTWORD;
+
+ if (tp->owrite) /* Overwrite a character. */
+ --tp->owrite;
+ else if (tp->insert) { /* Insert a character. */
+ ++tp->len;
+ if (tp->insert == 1)
+ tp->lb[sp->cno + 1] = tp->lb[sp->cno];
+ else
+ memmove(tp->lb + sp->cno + 1,
+ tp->lb + sp->cno, tp->insert);
+ }
+
+ tp->lb[sp->cno++] = ch;
+
+ /*
+ * If we've reached the end of the buffer, then we
+ * need to switch into insert mode. This happens
+ * when there's a change to a mark and the user puts
+ * in more characters than the length of the motion.
+ */
+ebuf_chk: if (sp->cno >= tp->len) {
+ TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
+ LF_SET(TXT_APPENDEOL);
+ tp->lb[sp->cno] = CURSOR_CH;
+ ++tp->insert;
+ ++tp->len;
+ }
+
+ if (hex == H_NEXTCHAR)
+ hex = H_INHEX;
+ if (quoted == Q_NEXTCHAR)
+ quoted = Q_THISCHAR;
+ break;
+ }
+#if defined(DEBUG) && 1
+ if (sp->cno + tp->insert + tp->owrite != tp->len)
+ msgq(sp, M_ERR,
+ "len %u != cno: %u ai: %u insert %u overwrite %u",
+ tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
+ tp->len = sp->cno + tp->insert + tp->owrite;
+#endif
+ }
+
+ /* Clear input flag. */
+ret: F_CLR(sp, S_INPUT);
+
+ if (LF_ISSET(TXT_RECORD))
+ VIP(sp)->rep_cnt = rcol;
+ return (eval);
+
+ /* Error jump. */
+err: eval = 1;
+ txt_err(sp, ep, tiqh);
+ goto ret;
+}
+
+/*
+ * txt_abbrev --
+ * Handle abbreviations.
+ */
+static int
+txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)
+ SCR *sp;
+ TEXT *tp;
+ CHAR_T *pushcp;
+ int isinfoline, *didsubp, *turnoffp;
+{
+ CHAR_T ch;
+ SEQ *qp;
+ size_t len, off;
+ char *p;
+
+ /*
+ * Find the start of the "word". Historically, abbreviations
+ * could be preceded by any non-word character.
+ */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (!inword(*p)) {
+ ++p;
+ break;
+ }
+ ++len;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+
+ /*
+ * !!!
+ * Historic vi exploded abbreviations on the command line. This has
+ * obvious problems in that unabbreviating the string can be extremely
+ * tricky, particularly if the string has, say, an embedded escape
+ * character. Personally, I think it's a stunningly bad idea. Other
+ * examples of problems this caused in historic vi are:
+ * :ab foo bar
+ * :ab foo baz
+ * results in "bar" being abbreviated to "baz", which wasn't what the
+ * user had in mind at all. Also, the commands:
+ * :ab foo bar
+ * :unab foo<space>
+ * resulted in an error message that "bar" wasn't mapped. Finally,
+ * since the string was already exploded by the time the unabbreviate
+ * command got it, all it knew was that an abbreviation had occurred.
+ * Cleverly, it checked the replacement string for its unabbreviation
+ * match, which meant that the commands:
+ * :ab foo1 bar
+ * :ab foo2 bar
+ * :unab foo2
+ * unabbreviates "foo1", and the commands:
+ * :ab foo bar
+ * :ab bar baz
+ * unabbreviates "foo"!
+ *
+ * Anyway, people neglected to first ask my opinion before they wrote
+ * macros that depend on this stuff, so, we make this work as follows.
+ * When checking for an abbreviation on the command line, if we get a
+ * string which is <blank> terminated and which starts at the beginning
+ * of the line, we check to see it is the abbreviate or unabbreviate
+ * commands. If it is, turn abbreviations off and return as if no
+ * abbreviation was found. Note also, minor trickiness, so that if the
+ * user erases the line and starts another command, we go ahead an turn
+ * abbreviations back on.
+ *
+ * This makes the layering look like a Nachos Supreme.
+ */
+ *didsubp = 0;
+ if (isinfoline)
+ if (off == tp->ai || off == tp->offset)
+ if (ex_is_abbrev(p, len)) {
+ *turnoffp = 1;
+ return (0);
+ } else
+ *turnoffp = 0;
+ else
+ if (*turnoffp)
+ return (0);
+
+ /* Check for any abbreviations. */
+ if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
+ return (0);
+
+ /*
+ * Push the abbreviation onto the tty stack. Historically, characters
+ * resulting from an abbreviation expansion were themselves subject to
+ * map expansions, O_SHOWMATCH matching etc. This means the expanded
+ * characters will be re-tested for abbreviations. It's difficult to
+ * know what historic practice in this case was, since abbreviations
+ * were applied to :colon command lines, so entering abbreviations that
+ * looped was tricky, although possible. In addition, obvious loops
+ * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
+ * silently only implement and/or display the last abbreviation.)
+ *
+ * This implementation doesn't recover well from such abbreviations.
+ * The main input loop counts abbreviated characters, and, when it
+ * reaches a limit, discards any abbreviated characters on the queue.
+ * It's difficult to back up to the original position, as the replay
+ * queue would have to be adjusted, and the line state when an initial
+ * abbreviated character was received would have to be saved.
+ */
+ ch = *pushcp;
+ if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
+ return (1);
+ if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
+ return (1);
+
+ /*
+ * Move the cursor to the start of the abbreviation,
+ * adjust the length.
+ */
+ sp->cno -= len;
+ tp->len -= len;
+
+ /* Copy any insert characters back. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + tp->owrite,
+ tp->lb + sp->cno + tp->owrite + len, tp->insert);
+
+ /*
+ * We return the length of the abbreviated characters. This is so
+ * the calling routine can replace the replay characters with the
+ * abbreviation. This means that subsequent '.' commands will produce
+ * the same text, regardless of intervening :[un]abbreviate commands.
+ * This is historic practice.
+ */
+ *didsubp = len;
+ return (0);
+}
+
+/*
+ * txt_unmap --
+ * Handle the unmap command.
+ */
+static void
+txt_unmap(sp, tp, iflagsp)
+ SCR *sp;
+ TEXT *tp;
+ u_int *iflagsp;
+{
+ size_t len, off;
+ char *p;
+
+ /* Find the beginning of this "word". */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (isblank(*p)) {
+ ++p;
+ break;
+ }
+ ++len;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+
+ /*
+ * !!!
+ * Historic vi exploded input mappings on the command line. See the
+ * txt_abbrev() routine for an explanation of the problems inherent
+ * in this.
+ *
+ * We make this work as follows. If we get a string which is <blank>
+ * terminated and which starts at the beginning of the line, we check
+ * to see it is the unmap command. If it is, we return that the input
+ * mapping should be turned off. Note also, minor trickiness, so that
+ * if the user erases the line and starts another command, we go ahead
+ * an turn mapping back on.
+ */
+ if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len))
+ *iflagsp &= ~TXT_MAPINPUT;
+ else
+ *iflagsp |= TXT_MAPINPUT;
+}
+
+
+/* Offset to next column of stop size. */
+#define STOP_OFF(c, stop) (stop - (c) % stop)
+
+/*
+ * txt_ai_resolve --
+ * When a line is resolved by <esc> or <cr>, review autoindent
+ * characters.
+ */
+static void
+txt_ai_resolve(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long ts;
+ int del;
+ size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
+ char *p;
+
+ /*
+ * If the line is empty, has an offset, or no autoindent
+ * characters, we're done.
+ */
+ if (!tp->len || tp->offset || !tp->ai)
+ return;
+
+ /*
+ * The autoindent characters plus any leading <blank> characters
+ * in the line are resolved into the minimum number of characters.
+ * Historic practice.
+ */
+ ts = O_VAL(sp, O_TABSTOP);
+
+ /* Figure out the last <blank> screen column. */
+ for (p = tp->lb, scno = 0, len = tp->len,
+ spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
+ if (*p == '\t') {
+ if (spaces)
+ tab_after_sp = 1;
+ scno += STOP_OFF(scno, ts);
+ } else {
+ ++spaces;
+ ++scno;
+ }
+
+ /*
+ * If there are no spaces, or no tabs after spaces and less than
+ * ts spaces, it's already minimal.
+ */
+ if (!spaces || !tab_after_sp && spaces < ts)
+ return;
+
+ /* Count up spaces/tabs needed to get to the target. */
+ for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
+ cno += STOP_OFF(cno, ts);
+ spaces = scno - cno;
+
+ /*
+ * Figure out how many characters we're dropping -- if we're not
+ * dropping any, it's already minimal, we're done.
+ */
+ old = p - tp->lb;
+ new = spaces + tabs;
+ if (old == new)
+ return;
+
+ /* Shift the rest of the characters down, adjust the counts. */
+ del = old - new;
+ memmove(p - del, p, tp->len - old);
+ sp->cno -= del;
+ tp->len -= del;
+
+ /* Fill in space/tab characters. */
+ for (p = tp->lb; tabs--;)
+ *p++ = '\t';
+ while (spaces--)
+ *p++ = ' ';
+}
+
+/*
+ * txt_auto --
+ * Handle autoindent. If aitp isn't NULL, use it, otherwise,
+ * retrieve the line.
+ */
+int
+txt_auto(sp, ep, lno, aitp, len, tp)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t len;
+ TEXT *aitp, *tp;
+{
+ size_t nlen;
+ char *p, *t;
+
+ if (aitp == NULL) {
+ if ((t = file_gline(sp, ep, lno, &len)) == NULL)
+ return (0);
+ } else
+ t = aitp->lb;
+
+ /* Count whitespace characters. */
+ for (p = t; len > 0; ++p, --len)
+ if (!isblank(*p))
+ break;
+
+ /* Set count, check for no indentation. */
+ if ((nlen = (p - t)) == 0)
+ return (0);
+
+ /* Make sure the buffer's big enough. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
+
+ /* Copy the buffer's current contents up. */
+ if (tp->len != 0)
+ memmove(tp->lb + nlen, tp->lb, tp->len);
+ tp->len += nlen;
+
+ /* Copy the indentation into the new buffer. */
+ memmove(tp->lb, t, nlen);
+
+ /* Set the autoindent count. */
+ tp->ai = nlen;
+ return (0);
+}
+
+/*
+ * txt_backup --
+ * Back up to the previously edited line.
+ */
+static TEXT *
+txt_backup(sp, ep, tiqh, tp, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ TEXT *tp;
+ u_int flags;
+{
+ TEXT *ntp;
+ recno_t lno;
+ size_t total;
+
+ /* Get a handle on the previous TEXT structure. */
+ if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
+ msgq(sp, M_BERR, "Already at the beginning of the insert");
+ return (tp);
+ }
+
+ /* Make sure that we have enough space. */
+ total = ntp->len + tp->insert;
+ if (LF_ISSET(TXT_APPENDEOL))
+ ++total;
+ if (total > ntp->lb_len &&
+ binc(sp, &ntp->lb, &ntp->lb_len, total))
+ return (NULL);
+
+ /*
+ * Append a cursor or copy inserted bytes to the end of the old line.
+ * Test for appending a cursor first, because the TEXT insert field
+ * will be 1 if we're appending a cursor. I don't think there's a
+ * third case, so abort() if there is.
+ */
+ if (LF_ISSET(TXT_APPENDEOL)) {
+ ntp->lb[ntp->len] = CURSOR_CH;
+ ntp->insert = 1;
+ } else if (tp->insert) {
+ memmove(ntp->lb + ntp->len, tp->lb + tp->owrite, tp->insert);
+ ntp->insert = tp->insert;
+ } else
+ abort();
+
+ /* Set bookkeeping information. */
+ sp->lno = ntp->lno;
+ sp->cno = ntp->len;
+ ntp->len += ntp->insert;
+
+ /* Release the current TEXT. */
+ lno = tp->lno;
+ CIRCLEQ_REMOVE(tiqh, tp, q);
+ text_free(tp);
+
+ /* Update the old line on the screen. */
+ if (sp->s_change(sp, ep, lno, LINE_DELETE))
+ return (NULL);
+
+ /* Return the old line. */
+ return (ntp);
+}
+
+/*
+ * txt_err --
+ * Handle an error during input processing.
+ */
+static void
+txt_err(sp, ep, tiqh)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+{
+ recno_t lno;
+ size_t len;
+
+ /*
+ * The problem with input processing is that the cursor is at an
+ * indeterminate position since some input may have been lost due
+ * to a malloc error. So, try to go back to the place from which
+ * the cursor started, knowing that it may no longer be available.
+ *
+ * We depend on at least one line number being set in the text
+ * chain.
+ */
+ for (lno = tiqh->cqh_first->lno;
+ file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
+
+ sp->lno = lno == 0 ? 1 : lno;
+ sp->cno = 0;
+
+ /* Redraw the screen, just in case. */
+ F_SET(sp, S_REDRAW);
+}
+
+/*
+ * txt_hex --
+ * Let the user insert any character value they want.
+ *
+ * !!!
+ * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
+ * for the user to specify a character value which their keyboard
+ * may not be able to enter.
+ */
+static int
+txt_hex(sp, tp, was_hex, pushcp)
+ SCR *sp;
+ TEXT *tp;
+ int *was_hex;
+ CHAR_T *pushcp;
+{
+ CHAR_T ch, savec;
+ size_t len, off;
+ u_long value;
+ char *p, *wp;
+
+ /*
+ * Null-terminate the string. Since nul isn't a legal hex value,
+ * this should be okay, and lets us use a local routine, which
+ * presumably understands the character set, to convert the value.
+ */
+ savec = tp->lb[sp->cno];
+ tp->lb[sp->cno] = 0;
+
+ /* Find the previous HEX_CH. */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (*p == HEX_CH) {
+ wp = p + 1;
+ break;
+ }
+ ++len;
+ /* If not on this line, there's nothing to do. */
+ if (off == tp->ai || off == tp->offset)
+ goto nothex;
+ }
+
+ /* If no length, then it wasn't a hex value. */
+ if (len == 0)
+ goto nothex;
+
+ /* Get the value. */
+ value = strtol(wp, NULL, 16);
+ if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
+nothex: tp->lb[sp->cno] = savec;
+ *was_hex = 0;
+ return (0);
+ }
+
+ ch = *pushcp;
+ if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
+ return (1);
+ ch = value;
+ if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
+ return (1);
+
+ tp->lb[sp->cno] = savec;
+
+ /* Move the cursor to the start of the hex value, adjust the length. */
+ sp->cno -= len + 1;
+ tp->len -= len + 1;
+
+ /* Copy any insert characters back. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + tp->owrite,
+ tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
+
+ *was_hex = 1;
+ return (0);
+}
+
+/*
+ * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
+ * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
+ * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
+ * the 10th column, and ^D moves it back.
+ *
+ * !!!
+ * The ^T and ^D characters in historical vi only had special meaning when
+ * they were the first characters typed after entering text input mode.
+ * Since normal erase characters couldn't erase autoindent (in this case
+ * ^T) characters, this meant that inserting text into previously existing
+ * text was quite strange, ^T only worked if it was the first keystroke,
+ * and then it could only be erased by using ^D. This implementation treats
+ * ^T specially anywhere it occurs in the input, and permits the standard
+ * erase characters to erase characters inserted using it.
+ *
+ * XXX
+ * Technically, txt_indent, txt_outdent should part of the screen interface,
+ * as they require knowledge of the size of a space character on the screen.
+ * (Not the size of tabs, because tabs are logically composed of spaces.)
+ * They're left in the text code because they're complicated, not to mention
+ * the gruesome awareness that if spaces aren't a single column on the screen
+ * for any language, we're into some serious, ah, for lack of a better word,
+ * "issues".
+ */
+
+/*
+ * txt_indent --
+ * Handle ^T indents.
+ */
+static int
+txt_indent(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long sw, ts;
+ size_t cno, off, scno, spaces, tabs;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ sw = O_VAL(sp, O_SHIFTWIDTH);
+
+ /* Get the current screen column. */
+ for (off = scno = 0; off < sp->cno; ++off)
+ if (tp->lb[off] == '\t')
+ scno += STOP_OFF(scno, ts);
+ else
+ ++scno;
+
+ /* Count up spaces/tabs needed to get to the target. */
+ for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
+ cno + STOP_OFF(cno, ts) <= scno; ++tabs)
+ cno += STOP_OFF(cno, ts);
+ spaces = scno - cno;
+
+ /* Put space/tab characters in place of any overwrite characters. */
+ for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
+ tp->lb[sp->cno++] = '\t';
+ for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+
+ if (!tabs && !spaces)
+ return (0);
+
+ /* Make sure there's enough room. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
+
+ /* Move the insert characters out of the way. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + spaces + tabs,
+ tp->lb + sp->cno, tp->insert);
+
+ /* Add new space/tab characters. */
+ for (; tabs--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = '\t';
+ for (; spaces--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+ return (0);
+}
+
+/*
+ * txt_outdent --
+ * Handle ^D outdents.
+ *
+ */
+static int
+txt_outdent(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long sw, ts;
+ size_t cno, off, scno, spaces;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ sw = O_VAL(sp, O_SHIFTWIDTH);
+
+ /* Get the current screen column. */
+ for (off = scno = 0; off < sp->cno; ++off)
+ if (tp->lb[off] == '\t')
+ scno += STOP_OFF(scno, ts);
+ else
+ ++scno;
+
+ /* Get the previous shiftwidth column. */
+ for (cno = scno; --scno % sw != 0;);
+
+ /* Decrement characters until less than or equal to that slot. */
+ for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
+ if (tp->lb[--off] == '\t')
+ cno -= STOP_OFF(cno, ts);
+ else
+ --cno;
+
+ /* Spaces needed to get to the target. */
+ spaces = scno - cno;
+
+ /* Maybe just a delete. */
+ if (spaces == 0)
+ return (0);
+
+ /* Make sure there's enough room. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
+
+ /* Use up any overwrite characters. */
+ for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
+ tp->lb[sp->cno++] = ' ';
+
+ /* Maybe that was enough. */
+ if (spaces == 0)
+ return (0);
+
+ /* Move the insert characters out of the way. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + spaces,
+ tp->lb + sp->cno, tp->insert);
+
+ /* Add new space characters. */
+ for (; spaces--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+ return (0);
+}
+
+/*
+ * txt_resolve --
+ * Resolve the input text chain into the file.
+ */
+static int
+txt_resolve(sp, ep, tiqh)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+{
+ TEXT *tp;
+ recno_t lno;
+
+ /* The first line replaces a current line. */
+ tp = tiqh->cqh_first;
+ if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
+ return (1);
+
+ /* All subsequent lines are appended into the file. */
+ for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
+ if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
+ return (1);
+ return (0);
+}
+
+/*
+ * txt_showmatch --
+ * Show a character match.
+ *
+ * !!!
+ * Historic vi tried to display matches even in the :colon command line.
+ * I think not.
+ */
+static void
+txt_showmatch(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct timeval second;
+ VCS cs;
+ MARK m;
+ fd_set zero;
+ int cnt, endc, startc;
+
+ /*
+ * Do a refresh first, in case the v_ntext() code hasn't done
+ * one in awhile, so the user can see what we're complaining
+ * about.
+ */
+ if (sp->s_refresh(sp, ep))
+ return;
+ /*
+ * We don't display the match if it's not on the screen. Find
+ * out what the first character on the screen is.
+ */
+ if (sp->s_position(sp, ep, &m, 0, P_TOP))
+ return;
+
+ /* Initialize the getc() interface. */
+ cs.cs_lno = sp->lno;
+ cs.cs_cno = sp->cno - 1;
+ if (cs_init(sp, ep, &cs))
+ return;
+ startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
+
+ /* Search for the match. */
+ for (cnt = 1;;) {
+ if (cs_prev(sp, ep, &cs))
+ return;
+ if (cs.cs_lno < m.lno ||
+ cs.cs_lno == m.lno && cs.cs_cno < m.cno)
+ return;
+ if (cs.cs_flags != 0) {
+ if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
+ (void)sp->s_bell(sp);
+ return;
+ }
+ continue;
+ }
+ if (cs.cs_ch == endc)
+ ++cnt;
+ else if (cs.cs_ch == startc && --cnt == 0)
+ break;
+ }
+
+ /* Move to the match. */
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ sp->lno = cs.cs_lno;
+ sp->cno = cs.cs_cno;
+ (void)sp->s_refresh(sp, ep);
+
+ /*
+ * Sleep(3) is eight system calls. Do it fast -- besides,
+ * I don't want to wait an entire second.
+ */
+ FD_ZERO(&zero);
+ second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
+ second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
+ (void)select(0, &zero, &zero, &zero, &second);
+
+ /* Return to the current location. */
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ (void)sp->s_refresh(sp, ep);
+}
+
+/*
+ * txt_margin --
+ * Handle margin wrap.
+ *
+ * !!!
+ * Historic vi belled the user each time a character was entered after
+ * crossing the margin until a space was entered which could be used to
+ * break the line. I don't, it tends to wake the cats.
+ */
+static int
+txt_margin(sp, tp, didbreak, pushcp)
+ SCR *sp;
+ TEXT *tp;
+ int *didbreak;
+ CHAR_T *pushcp;
+{
+ CHAR_T ch;
+ size_t len, off, tlen;
+ char *p, *wp;
+
+ /* Find the closest previous blank. */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (isblank(*p)) {
+ wp = p + 1;
+ break;
+ }
+ ++len;
+ /* If it's the beginning of the line, there's nothing to do. */
+ if (off == tp->ai || off == tp->offset) {
+ *didbreak = 0;
+ return (0);
+ }
+ }
+
+ /*
+ * Historic practice is to delete any trailing whitespace
+ * from the previous line.
+ */
+ for (tlen = len;; --p, --off) {
+ if (!isblank(*p))
+ break;
+ ++tlen;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+
+ ch = *pushcp;
+ if (term_push(sp, &ch, 1, 0, CH_NOMAP))
+ return (1);
+ if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
+ return (1);
+ ch = '\n';
+ if (term_push(sp, &ch, 1, 0, CH_NOMAP))
+ return (1);
+
+ sp->cno -= tlen;
+ tp->owrite += tlen;
+ *didbreak = 1;
+ return (0);
+}
+
+/*
+ * txt_Rcleanup --
+ * Resolve the input line for the 'R' command.
+ */
+static void
+txt_Rcleanup(sp, tiqh, tp, lp, len)
+ SCR *sp;
+ TEXTH *tiqh;
+ TEXT *tp;
+ const char *lp;
+ const size_t len;
+{
+ size_t tmp;
+
+ /*
+ * The 'R' command restores any overwritable characters in the
+ * first line to the original characters. Check to make sure
+ * that the cursor hasn't moved beyond the end of the original
+ * line.
+ */
+ if (tp != tiqh->cqh_first || tp->owrite == 0 || sp->cno >= len)
+ return;
+
+ /* Restore whatever we can restore from the original line. */
+ tmp = MIN(tp->owrite, len - sp->cno);
+ memmove(tp->lb + sp->cno, lp + sp->cno, tmp);
+
+ /*
+ * There can be more overwrite characters if the user extended the
+ * line and then erased it. What we have to do is delete whatever
+ * the user inserted and then erased. Regardless, we increase the
+ * insert character count to make the TEXT structure look right.
+ * (There shouldn't be any insert characters as 'R' replaces the
+ * entire line; if there are, this code isn't going to work).
+ */
+ if (tp->owrite > tmp)
+ tp->len -= tp->owrite - tmp;
+ tp->owrite = 0;
+ tp->insert = tmp;
+}
diff --git a/usr.bin/vi/vi/v_paragraph.c b/usr.bin/vi/vi/v_paragraph.c
new file mode 100644
index 000000000000..ceed57c7613e
--- /dev/null
+++ b/usr.bin/vi/vi/v_paragraph.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_paragraph.c 8.9 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * Paragraphs are empty lines after text or values from the paragraph
+ * or section options.
+ */
+
+/*
+ * v_paragraphf -- [count]}
+ * Move forward count paragraphs.
+ */
+int
+v_paragraphf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum { P_INTEXT, P_INBLANK } pstate;
+ size_t lastlen, len;
+ recno_t cnt, lastlno, lno;
+ char *p, *lp;
+
+ /*
+ * !!!
+ * If the starting cursor position is at or before any non-blank
+ * characters in the line, i.e. the movement is cutting all of the
+ * line's text, the buffer is in line mode. It's a lot easier to
+ * check here, because we know that the end is going to be the start
+ * or end of a line.
+ *
+ * This was historical practice in vi, with a single exception. If
+ * the paragraph movement was from the start of the last line to EOF,
+ * then all the characters were deleted from the last line, but the
+ * line itself remained. If somebody complains, don't pause, don't
+ * hesitate, just hit them.
+ */
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ else {
+ vp->m_stop = vp->m_start;
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+ if (vp->m_start.cno <= vp->m_stop.cno)
+ F_SET(vp, VM_LMODE);
+ }
+
+ /* Figure out what state we're currently in. */
+ lno = vp->m_start.lno;
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL)
+ goto eof;
+
+ /*
+ * If we start in text, we want to switch states
+ * (2 * N - 1) times, in non-text, (2 * N) times.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cnt *= 2;
+ if (len == 0 || v_isempty(p, len))
+ pstate = P_INBLANK;
+ else {
+ --cnt;
+ pstate = P_INTEXT;
+ }
+
+ for (;;) {
+ lastlno = lno;
+ lastlen = len;
+ if ((p = file_gline(sp, ep, ++lno, &len)) == NULL)
+ goto eof;
+ switch (pstate) {
+ case P_INTEXT:
+ if (p[0] == '.' && len >= 2)
+ for (lp = VIP(sp)->paragraph; *lp; lp += 2)
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' || lp[1] == p[2]) &&
+ !--cnt)
+ goto found;
+ if (len == 0 || v_isempty(p, len)) {
+ if (!--cnt)
+ goto found;
+ pstate = P_INBLANK;
+ }
+ break;
+ case P_INBLANK:
+ if (len == 0 || v_isempty(p, len))
+ break;
+ if (--cnt) {
+ pstate = P_INTEXT;
+ break;
+ }
+ /*
+ * !!!
+ * Non-motion commands move to the end of the range,
+ * VC_D and VC_Y stay at the start. Ignore VC_C and
+ * VC_S. Adjust end of the range for motion commands;
+ * historically, a motion component was to the end of
+ * the previous line, whereas the movement command was
+ * to the start of the new "paragraph".
+ */
+found: if (ISMOTION(vp)) {
+ vp->m_stop.lno = lastlno;
+ vp->m_stop.cno = lastlen ? lastlen - 1 : 0;
+ vp->m_final = vp->m_start;
+ } else {
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+ vp->m_final = vp->m_stop;
+ }
+ return (0);
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * !!!
+ * Adjust end of the range for motion commands; EOF is a movement
+ * sink. The } command historically moved to the end of the last
+ * line, not the beginning, from any position before the end of the
+ * last line.
+ */
+eof: if (vp->m_start.lno == lno - 1) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ if (vp->m_start.cno == (len ? len - 1 : 0)) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+ }
+ /*
+ * !!!
+ * Non-motion commands move to the end of the range, VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ *
+ * If deleting the line (which happens if deleting to EOF),
+ * then cursor movement is to the first nonblank.
+ */
+ if (F_ISSET(vp, VC_D)) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETFNB);
+ }
+ vp->m_stop.lno = lno - 1;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_paragraphb -- [count]{
+ * Move backward count paragraphs.
+ */
+int
+v_paragraphb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum { P_INTEXT, P_INBLANK } pstate;
+ size_t len;
+ recno_t cnt, lno;
+ char *p, *lp;
+
+ /*
+ * !!!
+ * Check for SOF. The historic vi didn't complain if users hit SOF
+ * repeatedly, unless it was part of a motion command. There is no
+ * question but that Emerson's editor of choice was vi.
+ *
+ * The { command historically moved to the beginning of the first
+ * line if invoked on the first line.
+ *
+ * !!!
+ * If the starting cursor position is in the first column (backward
+ * paragraph movements did NOT historically pay attention to non-blank
+ * characters) i.e. the movement is cutting the entire line, the buffer
+ * is in line mode. Cuts from the beginning of the line also did not
+ * cut the current line, but started at the previous EOL.
+ *
+ * Correct for a left motion component while we're thinking about it.
+ */
+ lno = vp->m_start.lno;
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0) {
+ if (vp->m_start.lno == 1) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ } else
+ --vp->m_start.lno;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_start.cno;
+
+ if (vp->m_start.lno <= 1)
+ goto sof;
+
+ /* Figure out what state we're currently in. */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL)
+ goto sof;
+
+ /*
+ * If we start in text, we want to switch states
+ * (2 * N - 1) times, in non-text, (2 * N) times.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cnt *= 2;
+ if (len == 0 || v_isempty(p, len))
+ pstate = P_INBLANK;
+ else {
+ --cnt;
+ pstate = P_INTEXT;
+ }
+
+ for (;;) {
+ if ((p = file_gline(sp, ep, --lno, &len)) == NULL)
+ goto sof;
+ switch (pstate) {
+ case P_INTEXT:
+ if (p[0] == '.' && len >= 2)
+ for (lp = VIP(sp)->paragraph; *lp; lp += 2)
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' || lp[1] == p[2]) &&
+ !--cnt)
+ goto ret;
+ if (len == 0 || v_isempty(p, len)) {
+ if (!--cnt)
+ goto ret;
+ pstate = P_INBLANK;
+ }
+ break;
+ case P_INBLANK:
+ if (len != 0 && !v_isempty(p, len)) {
+ if (!--cnt)
+ goto ret;
+ pstate = P_INTEXT;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /* SOF is a movement sink. */
+sof: lno = 1;
+
+ret: vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_buildparagraph --
+ * Build the paragraph command search pattern.
+ */
+int
+v_buildparagraph(sp)
+ SCR *sp;
+{
+ VI_PRIVATE *vip;
+ size_t p_len, s_len;
+ char *p, *p_p, *s_p;
+
+ /*
+ * The vi paragraph command searches for either a paragraph or
+ * section option macro.
+ */
+ p_len = (p_p = O_STR(sp, O_PARAGRAPHS)) == NULL ? 0 : strlen(p_p);
+ s_len = (s_p = O_STR(sp, O_SECTIONS)) == NULL ? 0 : strlen(s_p);
+
+ if (p_len == 0 && s_len == 0)
+ return (0);
+
+ MALLOC_RET(sp, p, char *, p_len + s_len + 1);
+
+ vip = VIP(sp);
+ if (vip->paragraph != NULL)
+ FREE(vip->paragraph, vip->paragraph_len);
+
+ if (p_p != NULL)
+ memmove(p, p_p, p_len + 1);
+ if (s_p != NULL)
+ memmove(p + p_len, s_p, s_len + 1);
+ vip->paragraph = p;
+ vip->paragraph_len = p_len + s_len + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_put.c b/usr.bin/vi/vi/v_put.c
new file mode 100644
index 000000000000..d427c332add5
--- /dev/null
+++ b/usr.bin/vi/vi/v_put.c
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_put.c 8.8 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static void inc_buf __P((SCR *, VICMDARG *));
+
+/*
+ * v_Put -- [buffer]P
+ * Insert the contents of the buffer before the cursor.
+ */
+int
+v_Put(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (F_ISSET(vp, VC_ISDOT))
+ inc_buf(sp, vp);
+
+ return (put(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 0));
+}
+
+/*
+ * v_put -- [buffer]p
+ * Insert the contents of the buffer after the cursor.
+ */
+int
+v_put(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (F_ISSET(vp, VC_ISDOT))
+ inc_buf(sp, vp);
+
+ return (put(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 1));
+}
+
+/*
+ * !!!
+ * Historical whackadoo. The dot command `puts' the numbered buffer
+ * after the last one put. For example, `"4p.' would put buffer #4
+ * and buffer #5. If the user continued to enter '.', the #9 buffer
+ * would be repeatedly output. This was not documented, and is a bit
+ * tricky to reconstruct. Historical versions of vi also dropped the
+ * contents of the default buffer after each put, so after `"4p' the
+ * default buffer would be empty. This makes no sense to me, so we
+ * don't bother. Don't assume sequential order of numeric characters.
+ *
+ * And, if that weren't exciting enough, failed commands don't normally
+ * set the dot command. Well, boys and girls, an exception is that
+ * the buffer increment gets done regardless of the success of the put.
+ */
+static void
+inc_buf(sp, vp)
+ SCR *sp;
+ VICMDARG *vp;
+{
+ CHAR_T v;
+
+ switch (vp->buffer) {
+ case '1':
+ v = '2';
+ break;
+ case '2':
+ v = '3';
+ break;
+ case '3':
+ v = '4';
+ break;
+ case '4':
+ v = '5';
+ break;
+ case '5':
+ v = '6';
+ break;
+ case '6':
+ v = '7';
+ break;
+ case '7':
+ v = '8';
+ break;
+ case '8':
+ v = '9';
+ break;
+ default:
+ return;
+ }
+ VIP(sp)->sdot.buffer = vp->buffer = v;
+}
diff --git a/usr.bin/vi/vi/v_redraw.c b/usr.bin/vi/vi/v_redraw.c
new file mode 100644
index 000000000000..b124e4acae44
--- /dev/null
+++ b/usr.bin/vi/vi/v_redraw.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_redraw.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_redraw -- ^R
+ * Redraw the screen.
+ */
+int
+v_redraw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ F_SET(sp, S_REFRESH);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_replace.c b/usr.bin/vi/vi/v_replace.c
new file mode 100644
index 000000000000..a9e7c470a270
--- /dev/null
+++ b/usr.bin/vi/vi/v_replace.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_replace.c 8.15 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_replace -- [count]rc
+ *
+ * !!!
+ * The r command in historic vi was almost beautiful in its badness. For
+ * example, "r<erase>" and "r<word erase>" beeped the terminal and deleted
+ * a single character. "Nr<carriage return>", where N was greater than 1,
+ * inserted a single carriage return. This may not be right, but at least
+ * it's not insane.
+ */
+int
+v_replace(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ CH ikey;
+ TEXT *tp;
+ recno_t lno;
+ size_t blen, len;
+ u_long cnt;
+ int rval;
+ char *bp, *p;
+
+ /*
+ * If the line doesn't exist, or it's empty, replacement isn't
+ * allowed. It's not hard to implement, but:
+ *
+ * 1: It's historic practice.
+ * 2: For consistency, this change would require that the more
+ * general case, "Nr", when the user is < N characters from
+ * the end of the line, also work.
+ * 3: Replacing a newline has somewhat odd semantics.
+ */
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ goto nochar;
+ }
+ if (len == 0) {
+nochar: msgq(sp, M_BERR, "No characters to replace.");
+ return (1);
+ }
+
+ /*
+ * Figure out how many characters to be replace. For no particular
+ * reason (other than that the semantics of replacing the newline
+ * are confusing) only permit the replacement of the characters in
+ * the current line. I suppose we could append replacement characters
+ * to the line, but I see no compelling reason to do so.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = vp->m_start.cno + cnt - 1;
+ if (vp->m_stop.cno > len - 1) {
+ v_eol(sp, ep, &vp->m_start);
+ return (1);
+ }
+
+ /*
+ * Get the character. Literal escapes escape any character,
+ * single escapes return.
+ */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ ikey.ch = VIP(sp)->rlast;
+ ikey.value = term_key_val(sp, ikey.ch);
+ } else {
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (1);
+ switch (ikey.value) {
+ case K_ESCAPE:
+ return (0);
+ case K_VLNEXT:
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (1);
+ break;
+ }
+ VIP(sp)->rlast = ikey.ch;
+ }
+
+ /* Copy the line. */
+ GET_SPACE_RET(sp, bp, blen, len);
+ memmove(bp, p, len);
+ p = bp;
+
+ if (ikey.value == K_CR || ikey.value == K_NL) {
+ /* Set return line. */
+ vp->m_stop.lno = vp->m_start.lno + cnt;
+ vp->m_stop.cno = 0;
+
+ /* The first part of the current line. */
+ if (file_sline(sp, ep, vp->m_start.lno, p, vp->m_start.cno))
+ goto err_ret;
+
+ /*
+ * The rest of the current line. And, of course, now it gets
+ * tricky. Any white space after the replaced character is
+ * stripped, and autoindent is applied. Put the cursor on the
+ * last indent character as did historic vi.
+ */
+ for (p += vp->m_start.cno + cnt, len -= vp->m_start.cno + cnt;
+ len && isblank(*p); --len, ++p);
+
+ if ((tp = text_init(sp, p, len, len)) == NULL)
+ goto err_ret;
+ if (txt_auto(sp, ep, vp->m_start.lno, NULL, 0, tp))
+ goto err_ret;
+ vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
+ if (file_aline(sp, ep, 1, vp->m_start.lno, tp->lb, tp->len))
+ goto err_ret;
+ text_free(tp);
+
+ rval = 0;
+
+ /* All of the middle lines. */
+ while (--cnt)
+ if (file_aline(sp, ep, 1, vp->m_start.lno, "", 0)) {
+err_ret: rval = 1;
+ break;
+ }
+ } else {
+ memset(bp + vp->m_start.cno, ikey.ch, cnt);
+ rval = file_sline(sp, ep, vp->m_start.lno, bp, len);
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ vp->m_final = vp->m_stop;
+ return (rval);
+}
diff --git a/usr.bin/vi/vi/v_right.c b/usr.bin/vi/vi/v_right.c
new file mode 100644
index 000000000000..3d78e781400c
--- /dev/null
+++ b/usr.bin/vi/vi/v_right.c
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_right.c 8.6 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_right -- [count]' ', [count]l
+ * Move right by columns.
+ */
+int
+v_right(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ v_eol(sp, ep, NULL);
+ else
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ /* It's always illegal to move right on empty lines. */
+ if (len == 0) {
+ v_eol(sp, ep, NULL);
+ return (1);
+ }
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S. Adjust the
+ * end of the range for motion commands.
+ *
+ * !!!
+ * Historically, "[cdsy]l" worked at the end of a line. Also,
+ * EOL is a count sink.
+ */
+ vp->m_stop.cno = vp->m_start.cno +
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
+ if (vp->m_start.cno == len - 1) {
+ if (!ISMOTION(vp)) {
+ v_eol(sp, ep, NULL);
+ return (1);
+ }
+ vp->m_stop.cno = vp->m_start.cno;
+ } else if (vp->m_stop.cno > len - 1)
+ vp->m_stop.cno = len - 1;
+
+ if (ISMOTION(vp)) {
+ --vp->m_stop.cno;
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_dollar -- [count]$
+ * Move to the last column.
+ */
+int
+v_dollar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ /*
+ * !!!
+ * A count moves down count - 1 rows, so, "3$" is the same as "2j$".
+ */
+ if ((F_ISSET(vp, VC_C1SET) ? vp->count : 1) != 1) {
+ /*
+ * !!!
+ * Historically, if the $ is a motion, and deleting from
+ * at or before the first non-blank of the line, it's a
+ * line motion, and the line motion flag is set.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_stop.cno))
+ return (1);
+ if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno)
+ F_SET(vp, VM_LMODE);
+
+ --vp->count;
+ if (v_down(sp, ep, vp))
+ return (1);
+ }
+
+ if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ v_eol(sp, ep, NULL);
+ else
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ /*
+ * Non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_stop.cno = len ? len - 1 : 0;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_screen.c b/usr.bin/vi/vi/v_screen.c
new file mode 100644
index 000000000000..0a4e8b009feb
--- /dev/null
+++ b/usr.bin/vi/vi/v_screen.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_screen.c 8.10 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_screen -- ^W
+ * Switch screens.
+ */
+int
+v_screen(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Try for the next lower screen, or, go back to the first
+ * screen on the stack.
+ */
+ if (sp->q.cqe_next != (void *)&sp->gp->dq)
+ sp->nextdisp = sp->q.cqe_next;
+ else if (sp->gp->dq.cqh_first == sp) {
+ msgq(sp, M_ERR, "No other screen to switch to.");
+ return (1);
+ } else
+ sp->nextdisp = sp->gp->dq.cqh_first;
+
+ /*
+ * Display the old screen's status line so the user can
+ * find the screen they want.
+ */
+ (void)status(sp, ep, vp->m_start.lno, 0);
+
+ /* Save the old screen's cursor information. */
+ sp->frp->lno = sp->lno;
+ sp->frp->cno = sp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ F_SET(sp, S_SSWITCH);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_scroll.c b/usr.bin/vi/vi/v_scroll.c
new file mode 100644
index 000000000000..ec9c26dc2955
--- /dev/null
+++ b/usr.bin/vi/vi/v_scroll.c
@@ -0,0 +1,414 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_scroll.c 8.14 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+static void goto_adjust __P((VICMDARG *));
+
+/*
+ * The historic vi had a problem in that all movements were by physical
+ * lines, not by logical, or screen lines. Arguments can be made that this
+ * is the right thing to do. For example, single line movements, such as
+ * 'j' or 'k', should probably work on physical lines. Commands like "dj",
+ * or "j.", where '.' is a change command, make more sense for physical lines
+ * than they do for logical lines.
+ *
+ * These arguments, however, don't apply to scrolling commands like ^D and
+ * ^F -- if the window is fairly small, using physical lines can result in
+ * a half-page scroll repainting the entire screen, which is not what the
+ * user wanted. Second, if the line is larger than the screen, using physical
+ * lines can make it impossible to display parts of the line -- there aren't
+ * any commands that don't display the beginning of the line in historic vi,
+ * and if both the beginning and end of the line can't be on the screen at
+ * the same time, you lose. This is even worse in the case of the H, L, and
+ * M commands -- for large lines, they may all refer to the same line and
+ * will result in no movement at all.
+ *
+ * This implementation does the scrolling (^B, ^D, ^F, ^U, ^Y, ^E), and the
+ * cursor positioning commands (H, L, M) commands using logical lines, not
+ * physical.
+ *
+ * Another issue is that page and half-page scrolling commands historically
+ * moved to the first non-blank character in the new line. If the line is
+ * approximately the same size as the screen, this loses because the cursor
+ * before and after a ^D, may refer to the same location on the screen. In
+ * this implementation, scrolling commands set the cursor to the first non-
+ * blank character if the line changes because of the scroll. Otherwise,
+ * the cursor is left alone.
+ */
+
+/*
+ * v_lgoto -- [count]G
+ * Go to first non-blank character of the line count, the last line
+ * of the file by default.
+ */
+int
+v_lgoto(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t nlines;
+
+ if (F_ISSET(vp, VC_C1SET)) {
+ if (file_gline(sp, ep, vp->count, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+ vp->m_stop.lno = vp->count;
+ } else {
+ if (file_lline(sp, ep, &nlines))
+ return (1);
+ vp->m_stop.lno = nlines ? nlines : 1;
+ }
+ goto_adjust(vp);
+ return (0);
+}
+
+/*
+ * v_home -- [count]H
+ * Move to the first non-blank character of the logical line
+ * count - 1 from the top of the screen, 0 by default.
+ */
+int
+v_home(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (sp->s_position(sp, ep, &vp->m_stop,
+ F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_TOP))
+ return (1);
+ goto_adjust(vp);
+ return (0);
+}
+
+/*
+ * v_middle -- M
+ * Move to the first non-blank character of the logical line
+ * in the middle of the screen.
+ */
+int
+v_middle(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Yielding to none in our quest for compatibility with every
+ * historical blemish of vi, no matter how strange it might be,
+ * we permit the user to enter a count and then ignore it.
+ */
+ if (sp->s_position(sp, ep, &vp->m_stop, 0, P_MIDDLE))
+ return (1);
+ goto_adjust(vp);
+ return (0);
+}
+
+/*
+ * v_bottom -- [count]L
+ * Move to the first non-blank character of the logical line
+ * count - 1 from the bottom of the screen, 0 by default.
+ */
+int
+v_bottom(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (sp->s_position(sp, ep, &vp->m_stop,
+ F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_BOTTOM))
+ return (1);
+ goto_adjust(vp);
+ return (0);
+}
+
+static void
+goto_adjust(vp)
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * If it's not a yank to the current line or greater, and we've
+ * changed lines, move to the first non-blank of the line.
+ */
+ if (!F_ISSET(vp, VC_Y) || vp->m_stop.lno < vp->m_start.lno) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETLFNB);
+ }
+
+ /* Non-motion commands go to the end of the range. */
+ vp->m_final = vp->m_stop;
+ if (!ISMOTION(vp))
+ return;
+
+ /*
+ * If moving backward in the file, VC_D and VC_Y move to the end
+ * of the range, unless the line didn't change, in which case VC_Y
+ * doesn't move. If moving forward in the file, VC_D and VC_Y stay
+ * at the start of the range. Ignore VC_C and VC_S.
+ */
+ if (vp->m_stop.lno < vp->m_start.lno ||
+ vp->m_stop.lno == vp->m_start.lno &&
+ vp->m_stop.cno < vp->m_start.cno) {
+ if (F_ISSET(vp, VC_Y) && vp->m_stop.lno == vp->m_start.lno)
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_start;
+}
+
+/*
+ * v_up -- [count]^P, [count]k, [count]-
+ * Move up by lines.
+ */
+int
+v_up(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+
+ lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (vp->m_start.lno <= lno) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ }
+ vp->m_stop.lno = vp->m_start.lno - lno;
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_cr -- [count]^M
+ * In a script window, send the line to the shell.
+ * In a regular window, move down by lines.
+ */
+int
+v_cr(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * If it's a script window, exec the line,
+ * otherwise it's the same as v_down().
+ */
+ return (F_ISSET(sp, S_SCRIPT) ?
+ sscr_exec(sp, ep, vp->m_start.lno) : v_down(sp, ep, vp));
+}
+
+/*
+ * v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+
+ * Move down by lines.
+ */
+int
+v_down(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+
+ lno = vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
+ if (file_gline(sp, ep, lno, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+ vp->m_stop.lno = lno;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_hpageup -- [count]^U
+ * Page up half screens.
+ */
+int
+v_hpageup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Half screens always succeed unless already at SOF.
+ *
+ * !!!
+ * Half screens set the scroll value, even if the command ultimately
+ * failed, in historic vi. Probably a don't care.
+ */
+ if (F_ISSET(vp, VC_C1SET))
+ O_VAL(sp, O_SCROLL) = vp->count;
+ else
+ vp->count = O_VAL(sp, O_SCROLL);
+
+ if (sp->s_down(sp, ep, &vp->m_stop, (recno_t)O_VAL(sp, O_SCROLL), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_hpagedown -- [count]^D
+ * Page down half screens.
+ */
+int
+v_hpagedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Half screens always succeed unless already at EOF.
+ *
+ * !!!
+ * Half screens set the scroll value, even if the command ultimately
+ * failed, in historic vi. Probably a don't care.
+ */
+ if (F_ISSET(vp, VC_C1SET))
+ O_VAL(sp, O_SCROLL) = vp->count;
+ else
+ vp->count = O_VAL(sp, O_SCROLL);
+
+ if (sp->s_up(sp, ep, &vp->m_stop, (recno_t)O_VAL(sp, O_SCROLL), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_pageup -- [count]^B
+ * Page up full screens.
+ *
+ * !!!
+ * Historic vi did not move to the SOF if the screen couldn't move, i.e.
+ * if SOF was already displayed on the screen. This implementation does
+ * move to SOF in that case, making ^B more like the the historic ^U.
+ */
+int
+v_pageup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Calculation from POSIX 1003.2/D8. */
+ if (sp->s_down(sp, ep, &vp->m_stop,
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_pagedown -- [count]^F
+ * Page down full screens.
+ * !!!
+ * Historic vi did not move to the EOF if the screen couldn't move, i.e.
+ * if EOF was already displayed on the screen. This implementation does
+ * move to EOF in that case, making ^F more like the the historic ^D.
+ */
+int
+v_pagedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Calculation from POSIX 1003.2/D8. */
+ if (sp->s_up(sp, ep, &vp->m_stop,
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_lineup -- [count]^Y
+ * Page up by lines.
+ */
+int
+v_lineup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * The cursor moves down, staying with its original line, unless it
+ * reaches the bottom of the screen.
+ */
+ if (sp->s_down(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_linedown -- [count]^E
+ * Page down by lines.
+ */
+int
+v_linedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * The cursor moves up, staying with its original line, unless it
+ * reaches the top of the screen.
+ */
+ if (sp->s_up(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_search.c b/usr.bin/vi/vi/v_search.c
new file mode 100644
index 000000000000..c6c950b88f81
--- /dev/null
+++ b/usr.bin/vi/vi/v_search.c
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_search.c 8.22 (Berkeley) 3/17/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static int bcorrect __P((SCR *, EXF *, VICMDARG *, u_int));
+static int fcorrect __P((SCR *, EXF *, VICMDARG *, u_int));
+static int getptrn __P((SCR *, EXF *, int, char **));
+static int search __P((SCR *, EXF *, VICMDARG *, char *, int, enum direction));
+
+/*
+ * v_searchn -- n
+ * Repeat last search.
+ */
+int
+v_searchn(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (search(sp, ep, vp, NULL, SEARCH_MSG, sp->searchdir));
+}
+
+/*
+ * v_searchN -- N
+ * Reverse last search.
+ */
+int
+v_searchN(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum direction dir;
+
+ switch (sp->searchdir) {
+ case BACKWARD:
+ dir = FORWARD;
+ break;
+ case FORWARD:
+ dir = BACKWARD;
+ break;
+ default: /* NOTSET handled in search(). */
+ dir = sp->searchdir;
+ break;
+ }
+ return (search(sp, ep, vp, NULL, SEARCH_MSG, dir));
+}
+
+/*
+ * v_searchb -- [count]?RE[? offset]
+ * Search backward.
+ */
+int
+v_searchb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ char *ptrn;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ ptrn = NULL;
+ else {
+ if (getptrn(sp, ep, '?', &ptrn))
+ return (1);
+ if (ptrn == NULL) {
+ F_SET(vp, VM_NOMOTION);
+ return (0);
+ }
+ }
+ return (search(sp, ep, vp, ptrn,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM, BACKWARD));
+}
+
+/*
+ * v_searchf -- [count]/RE[/ offset]
+ * Search forward.
+ */
+int
+v_searchf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ char *ptrn;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ ptrn = NULL;
+ else {
+ if (getptrn(sp, ep, '/', &ptrn))
+ return (1);
+ if (ptrn == NULL) {
+ F_SET(vp, VM_NOMOTION);
+ return (0);
+ }
+ }
+ return (search(sp, ep, vp, ptrn,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM, FORWARD));
+}
+
+/*
+ * v_searchw -- [count]^A
+ * Search for the word under the cursor.
+ */
+int
+v_searchw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t blen, len;
+ int rval;
+ char *bp;
+
+ len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
+ GET_SPACE_RET(sp, bp, blen, len);
+ (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP);
+
+ rval = search(sp, ep, vp, bp, SEARCH_MSG, FORWARD);
+
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+static int
+search(sp, ep, vp, ptrn, flags, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ int flags;
+ char *ptrn;
+ enum direction dir;
+{
+ if (ISMOTION(vp))
+ flags |= SEARCH_EOL;
+ switch (dir) {
+ case BACKWARD:
+ if (b_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, NULL, &flags))
+ return (1);
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+ else if (bcorrect(sp, ep, vp, flags))
+ return (1);
+ break;
+ case FORWARD:
+ if (f_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, NULL, &flags))
+ return (1);
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+ else if (fcorrect(sp, ep, vp, flags))
+ return (1);
+ break;
+ case NOTSET:
+ msgq(sp, M_ERR, "No previous search pattern.");
+ return (1);
+ default:
+ abort();
+ }
+ return (0);
+}
+
+/*
+ * getptrn --
+ * Get the search pattern.
+ */
+static int
+getptrn(sp, ep, prompt, storep)
+ SCR *sp;
+ EXF *ep;
+ int prompt;
+ char **storep;
+{
+ TEXT *tp;
+
+ if (sp->s_get(sp, ep, &sp->tiq, prompt,
+ TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
+ return (1);
+
+ /* Len is 0 if backspaced over the prompt, 1 if only CR entered. */
+ tp = sp->tiq.cqh_first;
+ if (tp->len == 0)
+ *storep = NULL;
+ else
+ *storep = tp->lb;
+ return (0);
+}
+
+/*
+ * !!!
+ * Historically, commands didn't affect the line searched to if the motion
+ * command was a search and the pattern match was the start or end of the
+ * line. There were some special cases, however, concerning search to the
+ * start of end of a line.
+ *
+ * Vi was not, however, consistent, and it was fairly easy to confuse it.
+ * For example, given the two lines:
+ *
+ * abcdefghi
+ * ABCDEFGHI
+ *
+ * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
+ * 'k' and put would no longer work correctly. In any case, we try to do
+ * the right thing, but it's not going to exactly match historic practice.
+ */
+
+/*
+ * bcorrect --
+ * Handle command with a backward search as the motion.
+ */
+static int
+bcorrect(sp, ep, vp, flags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int flags;
+{
+ size_t len;
+
+ /*
+ * VC_D commands move to the end of the range. VC_Y stays at the
+ * start unless the end of the range is on a different line, when
+ * it moves to the end of the range. Ignore VC_C and VC_S.
+ */
+ if (F_ISSET(vp, VC_D) ||
+ F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno)
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
+
+ /*
+ * !!!
+ * Correct backward searches which start at column 0 to be the last
+ * column of the previous line. Otherwise, adjust the starting point
+ * to the character before the current one.
+ *
+ * Backward searches become line mode operations if they start
+ * at column 0 and end at column 0 of another line.
+ */
+ if (vp->m_start.lno > vp->m_stop.lno && vp->m_start.cno == 0) {
+ if (file_gline(sp, ep, --vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
+ return (1);
+ }
+ if (vp->m_stop.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_start.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_start.cno;
+
+ /*
+ * !!!
+ * Commands become line mode operations if there was a delta
+ * specified to the search pattern.
+ */
+ if (LF_ISSET(SEARCH_DELTA)) {
+ F_SET(vp, VM_LMODE);
+ return (0);
+ }
+ return (0);
+}
+
+/*
+ * fcorrect --
+ * Handle command with a forward search as the motion.
+ */
+static int
+fcorrect(sp, ep, vp, flags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int flags;
+{
+ size_t len;
+
+ /* VC_D and VC_Y commands stay at the start. Ignore VC_C and VC_S. */
+ vp->m_final = vp->m_start;
+
+ /*
+ * !!!
+ * Correct forward searches which end at column 0 to be the last
+ * column of the previous line. Otherwise, adjust the ending
+ * point to the character before the current one.
+ *
+ * Forward searches become line mode operations if they start
+ * at column 0 and end at column 0 of another line.
+ */
+ if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
+ if (file_gline(sp, ep, --vp->m_stop.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
+ return (1);
+ }
+ if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_stop.cno;
+
+ /*
+ * !!!
+ * Commands become line mode operations if there was a delta
+ * specified to the search pattern.
+ */
+ if (LF_ISSET(SEARCH_DELTA)) {
+ F_SET(vp, VM_LMODE);
+ return (0);
+ }
+
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_section.c b/usr.bin/vi/vi/v_section.c
new file mode 100644
index 000000000000..0ad8d76be282
--- /dev/null
+++ b/usr.bin/vi/vi/v_section.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_section.c 8.6 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * In historic vi, the section commands ignored empty lines, unlike the
+ * paragraph commands, which was probably okay. However, they also moved
+ * to the start of the last line when there where no more sections instead
+ * of the end of the last line like the paragraph commands. I've changed
+ * the latter behavior to match the paragraph commands.
+ *
+ * In historic vi, a "function" was defined as the first character of the
+ * line being an open brace, which could be followed by anything. This
+ * implementation follows that historic practice.
+ *
+ * !!!
+ * The historic vi documentation (USD:15-10) claimed:
+ * The section commands interpret a preceding count as a different
+ * window size in which to redraw the screen at the new location,
+ * and this window size is the base size for newly drawn windows
+ * until another size is specified. This is very useful if you are
+ * on a slow terminal ...
+ *
+ * I can't get the 4BSD vi to do this, it just beeps at me. For now, a
+ * count to the section commands simply repeats the command.
+ */
+
+static int section __P((SCR *, EXF *, VICMDARG *, int, enum direction));
+
+/*
+ * v_sectionf -- [count]]]
+ * Move forward count sections/functions.
+ */
+int
+v_sectionf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (section(sp, ep, vp, 1, FORWARD));
+}
+
+/*
+ * v_sectionb -- [count][[
+ * Move backward count sections/functions.
+ */
+int
+v_sectionb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* An empty file or starting from line 1 is always illegal. */
+ if (vp->m_start.lno <= 1) {
+ v_sof(sp, NULL);
+ return (1);
+ }
+ return (section(sp, ep, vp, -1, BACKWARD));
+}
+
+static int
+section(sp, ep, vp, off, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ int off;
+ enum direction dir;
+{
+ size_t len;
+ recno_t cnt, lno;
+ int closeok;
+ char *p, *list, *lp;
+
+ /* Get the macro list. */
+ if ((list = O_STR(sp, O_SECTIONS)) == NULL)
+ return (1);
+
+ /*
+ * !!!
+ * Using ]] as a motion command was a bit special, historically.
+ * It could match } as well as the usual { and section values. If
+ * it matched a { or a section, it did NOT include the matched line.
+ * If it matched a }, it did include the line. Not a clue why.
+ */
+ closeok = ISMOTION(vp) && dir == FORWARD;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ for (lno = vp->m_start.lno;
+ (p = file_gline(sp, ep, lno += off, &len)) != NULL;) {
+ if (len == 0)
+ continue;
+ if (p[0] == '{' || closeok && p[0] == '}') {
+ if (!--cnt) {
+ if (dir == FORWARD && ISMOTION(vp) &&
+ p[0] == '{' &&
+ file_gline(sp, ep, --lno, &len) == NULL)
+ return (1);
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ goto ret;
+ }
+ continue;
+ }
+ if (p[0] != '.' || len < 3)
+ continue;
+ for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' || lp[1] == p[2]) && !--cnt) {
+ if (dir == FORWARD && ISMOTION(vp) &&
+ file_gline(sp, ep, --lno, &len) == NULL)
+ return (1);
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ goto ret;
+ }
+ }
+
+ /*
+ * If moving forward, reached EOF, if moving backward, reached SOF.
+ * Both are movement sinks. The calling code has already checked
+ * for SOF, so all we check is EOF.
+ */
+ if (dir == FORWARD) {
+ if (vp->m_start.lno == lno - 1) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+ vp->m_stop.lno = lno - 1;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else {
+ vp->m_stop.lno = 1;
+ vp->m_stop.cno = 0;
+ }
+
+ /*
+ * Non-motion commands go to the end of the range. If moving backward
+ * in the file, VC_D and VC_Y move to the end of the range. If moving
+ * forward in the file, VC_D and VC_Y stay at the start of the range.
+ * Ignore VC_C and VC_S.
+ *
+ * !!!
+ * Historic practice is the section cut was in line mode if it started
+ * from column 0 and was in the backward direction. I don't know why
+ * you'd want to cut an entire section in character mode, so I do it in
+ * line mode in both directions if the cut starts in column 0.
+ */
+ret: if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_final = ISMOTION(vp) && dir == FORWARD ? vp->m_start : vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_sentence.c b/usr.bin/vi/vi/v_sentence.c
new file mode 100644
index 000000000000..678995b7057d
--- /dev/null
+++ b/usr.bin/vi/vi/v_sentence.c
@@ -0,0 +1,386 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_sentence.c 8.12 (Berkeley) 3/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * !!!
+ * In historic vi, a sentence was delimited by a '.', '?' or '!' character
+ * followed by TWO spaces or a newline. One or more empty lines was also
+ * treated as a separate sentence. The Berkeley documentation for historical
+ * vi states that any number of ')', ']', '"' and '\'' characters can be
+ * between the delimiter character and the spaces or end of line, however,
+ * the historical implementation did not handle additional '"' characters.
+ * We follow the documentation here, not the implementation.
+ *
+ * Once again, historical vi didn't do sentence movements associated with
+ * counts consistently, mostly in the presence of lines containing only
+ * white-space characters.
+ *
+ * This implementation also permits a single tab to delimit sentences, and
+ * treats lines containing only white-space characters as empty lines.
+ * Finally, tabs are eaten (along with spaces) when skipping to the start
+ * of the text following a "sentence".
+ */
+
+/*
+ * v_sentencef -- [count])
+ * Move forward count sentences.
+ */
+int
+v_sentencef(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum { BLANK, NONE, PERIOD } state;
+ VCS cs;
+ size_t len;
+ u_long cnt;
+
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+
+ /*
+ * !!!
+ * If in white-space, the next start of sentence counts as one.
+ * This may not handle " . " correctly, but it's real unclear
+ * what correctly means in that case.
+ */
+ if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (--cnt == 0) {
+ if (vp->m_start.lno != cs.cs_lno ||
+ vp->m_start.cno != cs.cs_cno)
+ goto okret;
+ return (1);
+ }
+ }
+
+ for (state = NONE;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ break;
+ if (cs.cs_flags == CS_EOL) {
+ if ((state == PERIOD || state == BLANK) && --cnt == 0) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 &&
+ isblank(cs.cs_ch) && cs_fblank(sp, ep, &cs))
+ return (1);
+ goto okret;
+ }
+ state = NONE;
+ continue;
+ }
+ if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */
+ if (--cnt == 0)
+ goto okret;
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (--cnt == 0)
+ goto okret;
+ state = NONE;
+ continue;
+ }
+ switch (cs.cs_ch) {
+ case '.':
+ case '?':
+ case '!':
+ state = PERIOD;
+ break;
+ case ')':
+ case ']':
+ case '"':
+ case '\'':
+ if (state != PERIOD)
+ state = NONE;
+ break;
+ case '\t':
+ if (state == PERIOD)
+ state = BLANK;
+ /* FALLTHROUGH */
+ case ' ':
+ if (state == PERIOD) {
+ state = BLANK;
+ break;
+ }
+ if (state == BLANK && --cnt == 0) {
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ goto okret;
+ }
+ /* FALLTHROUGH */
+ default:
+ state = NONE;
+ break;
+ }
+ }
+
+ /* EOF is a movement sink, but it's an error not to have moved. */
+ if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+
+okret: vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * !!!
+ * Historic, uh, features, yeah, that's right, call 'em features.
+ * If the ending cursor position is at the first column in the
+ * line, i.e. the movement is cutting an entire line, the buffer
+ * is in line mode, and the ending position is the last character
+ * of the previous line.
+ *
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S. Adjust the
+ * end of the range for motion commands.
+ */
+ if (ISMOTION(vp)) {
+ if (vp->m_start.cno == 0 &&
+ (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
+ if (file_gline(sp, ep,
+ --vp->m_stop.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
+ return (1);
+ }
+ vp->m_stop.cno = len ? len - 1 : 0;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_stop.cno;
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_sentenceb -- [count](
+ * Move backward count sentences.
+ */
+int
+v_sentenceb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VCS cs;
+ recno_t slno;
+ size_t len, scno;
+ u_long cnt;
+ int last;
+
+ /*
+ * !!!
+ * Historic vi permitted the user to hit SOF repeatedly.
+ */
+ if (vp->m_start.lno == 1 && vp->m_start.cno == 0)
+ return (0);
+
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+
+ /*
+ * !!!
+ * In empty lines, skip to the previous non-white-space character.
+ * If in text, skip to the prevous white-space character. Believe
+ * it or not, in the paragraph:
+ * ab cd.
+ * AB CD.
+ * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it
+ * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia,
+ * Berkeley was once a major center of drug activity.
+ */
+ if (cs.cs_flags == CS_EMP) {
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags != CS_EOL)
+ break;
+ }
+ } else if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+
+ for (last = 0;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */
+ break;
+ if (cs.cs_flags == CS_EOL) {
+ last = 1;
+ continue;
+ }
+ if (cs.cs_flags == CS_EMP) {
+ if (--cnt == 0)
+ goto ret;
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ last = 0;
+ continue;
+ }
+ switch (cs.cs_ch) {
+ case '.':
+ case '?':
+ case '!':
+ if (!last || --cnt != 0) {
+ last = 0;
+ continue;
+ }
+
+ret: slno = cs.cs_lno;
+ scno = cs.cs_cno;
+
+ /*
+ * Move to the start of the sentence, skipping blanks
+ * and special characters.
+ */
+ do {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ } while (!cs.cs_flags &&
+ (cs.cs_ch == ')' || cs.cs_ch == ']' ||
+ cs.cs_ch == '"' || cs.cs_ch == '\''));
+ if ((cs.cs_flags || isblank(cs.cs_ch)) &&
+ cs_fblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * If it was ". xyz", with the cursor on the 'x', or
+ * "end. ", with the cursor in the spaces, or the
+ * beginning of a sentence preceded by an empty line,
+ * we can end up where we started. Fix it.
+ */
+ if (vp->m_start.lno != cs.cs_lno ||
+ vp->m_start.cno != cs.cs_cno)
+ goto okret;
+
+ /*
+ * Well, if an empty line preceded possible blanks
+ * and the sentence, it could be a real sentence.
+ */
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOL)
+ continue;
+ if (cs.cs_flags == 0 && isblank(cs.cs_ch))
+ continue;
+ break;
+ }
+ if (cs.cs_flags == CS_EMP)
+ goto okret;
+
+ /* But it wasn't; try again. */
+ ++cnt;
+ cs.cs_lno = slno;
+ cs.cs_cno = scno;
+ last = 0;
+ break;
+ case '\t':
+ last = 1;
+ break;
+ default:
+ last =
+ cs.cs_flags == CS_EOL || isblank(cs.cs_ch) ||
+ cs.cs_ch == ')' || cs.cs_ch == ']' ||
+ cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0;
+ }
+ }
+
+okret: vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * !!!
+ * If the starting and stopping cursor positions are at the first
+ * columns in the line, i.e. the movement is cutting an entire line,
+ * the buffer is in line mode, and the starting position is the last
+ * character of the previous line.
+ *
+ * VC_D and non-motion commands move to the end of the range.
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Adjust the
+ * start of the range for motion commands.
+ */
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0 &&
+ (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
+ if (file_gline(sp, ep,
+ --vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ vp->m_start.cno = len ? len - 1 : 0;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_start.cno;
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_shift.c b/usr.bin/vi/vi/v_shift.c
new file mode 100644
index 000000000000..529e6d460e17
--- /dev/null
+++ b/usr.bin/vi/vi/v_shift.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_shift.c 8.5 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_shiftl -- [count]<motion
+ * Shift lines left.
+ */
+int
+v_shiftl(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0, "<");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_shiftr -- [count]>motion
+ * Shift lines right.
+ */
+int
+v_shiftr(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0, ">");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_status.c b/usr.bin/vi/vi/v_status.c
new file mode 100644
index 000000000000..26cb191a06dc
--- /dev/null
+++ b/usr.bin/vi/vi/v_status.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_status.c 8.12 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_status -- ^G
+ * Show the file status.
+ */
+int
+v_status(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+
+ /*
+ * ^G in historic vi reset the cursor column to the first
+ * non-blank character in the line. This doesn't seem of
+ * any usefulness whatsoever, so I don't bother.
+ */
+ return (status(sp, ep, vp->m_start.lno, 1));
+}
+
+int
+status(sp, ep, lno, showlast)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ int showlast;
+{
+ recno_t last;
+ char *mo, *nc, *nf, *ro, *pid;
+#ifdef DEBUG
+ char pbuf[50];
+
+ (void)snprintf(pbuf, sizeof(pbuf), " (pid %u)", getpid());
+ pid = pbuf;
+#else
+ pid = "";
+#endif
+ /*
+ * See nvi/exf.c:file_init() for a description of how and
+ * when the read-only bit is set. Possible displays are:
+ *
+ * new file
+ * new file, readonly
+ * [un]modified
+ * [un]modified, readonly
+ * name changed, [un]modified
+ * name changed, [un]modified, readonly
+ *
+ * !!!
+ * The historic display for "name changed" was "[Not edited]".
+ */
+ if (F_ISSET(sp->frp, FR_NEWFILE)) {
+ F_CLR(sp->frp, FR_NEWFILE);
+ nf = "new file";
+ mo = nc = "";
+ } else {
+ nf = "";
+ if (sp->frp->cname != NULL) {
+ nc = "name changed";
+ mo = F_ISSET(ep, F_MODIFIED) ?
+ ", modified" : ", unmodified";
+ } else {
+ nc = "";
+ mo = F_ISSET(ep, F_MODIFIED) ?
+ "modified" : "unmodified";
+ }
+ }
+ ro = F_ISSET(sp->frp, FR_RDONLY) ? ", readonly" : "";
+ if (showlast) {
+ if (file_lline(sp, ep, &last))
+ return (1);
+ if (last >= 1)
+ msgq(sp, M_INFO,
+ "%s: %s%s%s%s: line %lu of %lu [%ld%%]%s",
+ FILENAME(sp->frp), nf, nc, mo, ro, lno,
+ last, (lno * 100) / last, pid);
+ else
+ msgq(sp, M_INFO, "%s: %s%s%s%s: empty file%s",
+ FILENAME(sp->frp), nf, nc, mo, ro, pid);
+ } else
+ msgq(sp, M_INFO, "%s: %s%s%s%s: line %lu%s",
+ FILENAME(sp->frp), nf, nc, mo, ro, lno, pid);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_stop.c b/usr.bin/vi/vi/v_stop.c
new file mode 100644
index 000000000000..d6fee83cbb05
--- /dev/null
+++ b/usr.bin/vi/vi/v_stop.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_stop.c 8.7 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_stop -- ^Z
+ * Suspend vi.
+ */
+int
+v_stop(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* If autowrite is set, write out the file. */
+ if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE)) {
+ if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+ if (sp->s_refresh(sp, ep))
+ return (1);
+ }
+ return (sp->s_suspend(sp));
+}
diff --git a/usr.bin/vi/vi/v_switch.c b/usr.bin/vi/vi/v_switch.c
new file mode 100644
index 000000000000..abdd128f0936
--- /dev/null
+++ b/usr.bin/vi/vi/v_switch.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_switch.c 8.7 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+/*
+ * v_switch -- ^^
+ * Switch to the previous file.
+ */
+int
+v_switch(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+ char *name;
+
+ /*
+ * Try the alternate file name, then the previous file
+ * name. Use the real name, not the user's current name.
+ */
+ if (sp->alt_name != NULL)
+ name = sp->alt_name;
+ else if (sp->p_frp != NULL)
+ name = sp->p_frp->name;
+ else {
+ msgq(sp, M_ERR, "No previous file to edit.");
+ return (1);
+ }
+
+ /* If autowrite is set, write out the file. */
+ if (F_ISSET(ep, F_MODIFIED))
+ if (O_ISSET(sp, O_AUTOWRITE)) {
+ if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+ } else {
+ msgq(sp, M_ERR,
+ "Modified since last write; write or use :edit! to override.");
+ return (1);
+ }
+
+ SETCMDARG(cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, name);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_tag.c b/usr.bin/vi/vi/v_tag.c
new file mode 100644
index 000000000000..caa36f473bfc
--- /dev/null
+++ b/usr.bin/vi/vi/v_tag.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_tag.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_tagpush -- ^[
+ * Do a tag search on a the cursor keyword.
+ */
+int
+v_tagpush(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_TAG, 0, OOBLNO, 0, 0, vp->keyword);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_tagpop -- ^T
+ * Pop the tags stack.
+ */
+int
+v_tagpop(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ EXCMDARG cmd;
+
+ SETCMDARG(cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
diff --git a/usr.bin/vi/vi/v_text.c b/usr.bin/vi/vi/v_text.c
new file mode 100644
index 000000000000..01d17442fc00
--- /dev/null
+++ b/usr.bin/vi/vi/v_text.c
@@ -0,0 +1,848 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_text.c 8.30 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * !!!
+ * Repeated input in the historic vi is mostly wrong and this isn't very
+ * backward compatible. For example, if the user entered "3Aab\ncd" in
+ * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then
+ * appended to the result. There was also a hack which I don't remember
+ * right now, where "3o" would open 3 lines and then let the user fill them
+ * in, to make screen movements on 300 baud modems more tolerable. I don't
+ * think it's going to be missed.
+ */
+
+#define SET_TXT_STD(sp, f) { \
+ LF_INIT((f) | TXT_CNTRLT | TXT_ESCAPE | \
+ TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); \
+ if (O_ISSET(sp, O_ALTWERASE)) \
+ LF_SET(TXT_ALTWERASE); \
+ if (O_ISSET(sp, O_AUTOINDENT)) \
+ LF_SET(TXT_AUTOINDENT); \
+ if (O_ISSET(sp, O_BEAUTIFY)) \
+ LF_SET(TXT_BEAUTIFY); \
+ if (O_ISSET(sp, O_SHOWMATCH)) \
+ LF_SET(TXT_SHOWMATCH); \
+ if (O_ISSET(sp, O_WRAPMARGIN)) \
+ LF_SET(TXT_WRAPMARGIN); \
+ if (F_ISSET(sp, S_SCRIPT)) \
+ LF_SET(TXT_CR); \
+ if (O_ISSET(sp, O_TTYWERASE)) \
+ LF_SET(TXT_TTYWERASE); \
+}
+
+/*
+ * !!!
+ * There's a problem with the way that we do logging for change commands with
+ * implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the
+ * starting cursor position before the change command "moves" the cursor, the
+ * cursor position to which we return on undo will be where the user entered
+ * the change command, not the start of the change. Several of the following
+ * routines re-log the cursor to make this work correctly. Historic vi tried
+ * to do the same thing, and mostly got it right. (The only spectacular way
+ * it fails is if the user entered 'o' from anywhere but the last character of
+ * the line, the undo returned the cursor to the start of the line. If the
+ * user was on the last character of the line, the cursor returned to that
+ * position.) We also check for mapped keys waiting, i.e. if we're in the
+ * middle of a map, don't bother logging the cursor.
+ */
+#define LOG_CORRECT { \
+ if (!MAPPED_KEYS_WAITING(sp)) \
+ (void)log_cursor(sp, ep); \
+}
+#define LOG_CORRECT_FIRST { \
+ if (first == 1) { \
+ LOG_CORRECT; \
+ first = 0; \
+ } \
+}
+
+static int v_CS __P((SCR *, EXF *, VICMDARG *, u_int));
+
+/*
+ * v_iA -- [count]A
+ * Append text to the end of the line.
+ */
+int
+v_iA(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ int first;
+ char *p;
+
+ SET_TXT_STD(sp, TXT_APPENDEOL);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (first = 1, lno = vp->m_start.lno,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ /* Move the cursor to the end of the line + 1. */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ } else {
+ /* Correct logging for implied cursor motion. */
+ if (first == 1) {
+ sp->cno = len == 0 ? 0 : len - 1;
+ LOG_CORRECT;
+ first = 0;
+ }
+
+ /* Start the change after the line. */
+ sp->cno = len;
+ }
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_ia -- [count]a
+ * Append text to the cursor position.
+ */
+int
+v_ia(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ u_int flags;
+ size_t len;
+ char *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (lno = vp->m_start.lno,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ /*
+ * Move the cursor one column to the right and
+ * repaint the screen.
+ */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else if (len) {
+ if (len == sp->cno + 1) {
+ sp->cno = len;
+ LF_SET(TXT_APPENDEOL);
+ } else
+ ++sp->cno;
+ } else
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ SET_TXT_STD(sp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_iI -- [count]I
+ * Insert text at the first non-blank character in the line.
+ */
+int
+v_iI(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ int first;
+ char *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (first = 1, lno = vp->m_start.lno,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ /*
+ * Move the cursor to the start of the line and repaint
+ * the screen.
+ */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ } else {
+ sp->cno = 0;
+ if (nonblank(sp, ep, lno, &sp->cno))
+ return (1);
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+ }
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ SET_TXT_STD(sp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_ii -- [count]i
+ * Insert text at the cursor position.
+ */
+int
+v_ii(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (lno = vp->m_start.lno,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ }
+ /* If len == sp->cno, it's a replay caused by a count. */
+ if (len == 0 || len == sp->cno)
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ /*
+ * On replay, if the line isn't empty, advance the insert
+ * by one (make it an append).
+ */
+ SET_TXT_STD(sp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ if ((sp->cno = vp->m_final.cno) != 0)
+ ++sp->cno;
+ }
+ return (0);
+}
+
+/*
+ * v_iO -- [count]O
+ * Insert text above this line.
+ */
+int
+v_iO(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t ai_line, lno;
+ size_t len;
+ u_long cnt;
+ u_int flags;
+ int first;
+ char *p;
+
+ SET_TXT_STD(sp, TXT_APPENDEOL);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (first = 1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0)
+ goto insert;
+ p = NULL;
+ len = 0;
+ ai_line = OOBLNO;
+ } else {
+insert: p = "";
+ sp->cno = 0;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+
+ if (file_iline(sp, ep, sp->lno, p, 0))
+ return (1);
+ if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+ ai_line = sp->lno + 1;
+ }
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, ai_line, flags))
+ return (1);
+
+ SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_io -- [count]o
+ * Insert text after this line.
+ */
+int
+v_io(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t ai_line, lno;
+ size_t len;
+ u_long cnt;
+ u_int flags;
+ int first;
+ char *p;
+
+ SET_TXT_STD(sp, TXT_APPENDEOL);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ for (first = 1,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0)
+ goto insert;
+ p = NULL;
+ len = 0;
+ ai_line = OOBLNO;
+ } else {
+insert: p = "";
+ sp->cno = 0;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+
+ len = 0;
+ if (file_aline(sp, ep, 1, sp->lno, p, len))
+ return (1);
+ if ((p = file_gline(sp, ep, ++sp->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+ ai_line = sp->lno - 1;
+ }
+
+ if (v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, ai_line, flags))
+ return (1);
+
+ SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_Change -- [buffer][count]C
+ * Change line command.
+ */
+int
+v_Change(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (v_CS(sp, ep, vp, 0));
+}
+
+/*
+ * v_Subst -- [buffer][count]S
+ * Line substitute command.
+ */
+int
+v_Subst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_int flags;
+
+ /*
+ * The S command is the same as a 'C' command from the beginning
+ * of the line. This is hard to do in the parser, so do it here.
+ *
+ * If autoindent is on, the change is from the first *non-blank*
+ * character of the line, not the first character. And, to make
+ * it just a bit more exciting, the initial space is handled as
+ * auto-indent characters.
+ */
+ LF_INIT(0);
+ if (O_ISSET(sp, O_AUTOINDENT)) {
+ vp->m_start.cno = 0;
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
+ return (1);
+ LF_SET(TXT_AICHARS);
+ } else
+ vp->m_start.cno = 0;
+ sp->cno = vp->m_start.cno;
+ return (v_CS(sp, ep, vp, flags));
+}
+
+/*
+ * v_CS --
+ * C and S commands.
+ */
+static int
+v_CS(sp, ep, vp, iflags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int iflags;
+{
+ MARK *tm;
+ recno_t lno;
+ size_t len;
+ char *p;
+ u_int flags;
+
+ SET_TXT_STD(sp, iflags);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+
+ /*
+ * There are two cases -- if a count is supplied, we do a line
+ * mode change where we delete the lines and then insert text
+ * into a new line. Otherwise, we replace the current line.
+ */
+ vp->m_stop.lno =
+ vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
+ if (vp->m_start.lno != vp->m_stop.lno) {
+ /* Make sure that the to line is real. */
+ if (file_gline(sp, ep,
+ vp->m_stop.lno, &vp->m_stop.cno) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+ if (vp->m_stop.cno != 0)
+ --vp->m_stop.cno;
+
+ /* Cut the lines. */
+ if (cut(sp, ep,
+ NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
+ return (1);
+
+ /* Insert a line while we still can... */
+ if (file_iline(sp, ep, vp->m_start.lno, "", 0))
+ return (1);
+ ++vp->m_start.lno;
+ ++vp->m_stop.lno;
+
+ /* Delete the lines. */
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 1))
+ return (1);
+
+ /* Get the inserted line. */
+ if ((p = file_gline(sp, ep, --vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ tm = NULL;
+ sp->lno = vp->m_start.lno;
+ sp->cno = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ /* The line may be empty, but that's okay. */
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ vp->m_stop.cno = len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (len == 0) {
+ vp->m_stop.cno = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else
+ vp->m_stop.cno = len - 1;
+ if (cut(sp, ep,
+ NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
+ return (1);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+ tm = &vp->m_stop;
+ }
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT;
+
+ return (v_ntext(sp, ep,
+ &sp->tiq, tm, p, len, &vp->m_final, 0, OOBLNO, flags));
+}
+
+/*
+ * v_change -- [buffer][count]c[count]motion
+ * Change command.
+ */
+int
+v_change(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t blen, len;
+ u_int flags;
+ int lmode, rval;
+ char *bp, *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+
+ /*
+ * Move the cursor to the start of the change. Note, if autoindent
+ * is turned on, the cc command in line mode changes from the first
+ * *non-blank* character of the line, not the first character. And,
+ * to make it just a bit more exciting, the initial space is handled
+ * as auto-indent characters.
+ */
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
+ if (lmode) {
+ vp->m_start.cno = 0;
+ if (O_ISSET(sp, O_AUTOINDENT)) {
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
+ return (1);
+ LF_SET(TXT_AICHARS);
+ }
+ }
+ sp->lno = vp->m_start.lno;
+ sp->cno = vp->m_start.cno;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT;
+
+ /*
+ * If changing within a single line, the line either currently has
+ * text or it doesn't. If it doesn't, just insert text. Otherwise,
+ * copy it and overwrite it.
+ */
+ if (vp->m_start.lno == vp->m_stop.lno) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (p == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ }
+ vp->m_stop.cno = len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (cut(sp, ep,
+ NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+ return (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
+ }
+
+ /*
+ * It's trickier if changing over multiple lines. If we're in
+ * line mode we delete all of the lines and insert a replacement
+ * line which the user edits. If there was leading whitespace
+ * in the first line being changed, we copy it and use it as the
+ * replacement. If we're not in line mode, we just delete the
+ * text and start inserting.
+ *
+ * Copy the text.
+ */
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ /* If replacing entire lines and there's leading text. */
+ if (lmode && vp->m_start.cno) {
+ /* Get a copy of the first line changed. */
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ /* Copy the leading text elsewhere. */
+ GET_SPACE_RET(sp, bp, blen, vp->m_start.cno);
+ memmove(bp, p, vp->m_start.cno);
+ } else
+ bp = NULL;
+
+ /* Delete the text. */
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ /* If replacing entire lines, insert a replacement line. */
+ if (lmode) {
+ if (file_iline(sp, ep, vp->m_start.lno, bp, vp->m_start.cno))
+ return (1);
+ sp->lno = vp->m_start.lno;
+ len = sp->cno = vp->m_start.cno;
+ }
+
+ /* Get the line we're editing. */
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ }
+
+ /* Check to see if we're appending to the line. */
+ if (vp->m_start.cno >= len)
+ LF_SET(TXT_APPENDEOL);
+
+ rval = v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags);
+
+ if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * v_Replace -- [count]R
+ * Overwrite multiple characters.
+ */
+int
+v_Replace(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_OVERWRITE | TXT_REPLACE);
+ }
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ if (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ /*
+ * Special case. The historic vi handled [count]R badly, in that R
+ * would replace some number of characters, and then the count would
+ * append count-1 copies of the replacing chars to the replaced space.
+ * This seems wrong, so this version counts R commands. There is some
+ * trickiness in moving back to where the user stopped replacing after
+ * each R command. Basically, if the user ended with a newline, we
+ * want to use vp->m_final.cno (which will be 0). Otherwise, use the
+ * column after the returned cursor, unless it would be past the end of
+ * the line, in which case we append to the line.
+ */
+ while (--cnt) {
+ if ((p = file_gline(sp, ep, vp->m_final.lno, &len)) == NULL)
+ GETLINE_ERR(sp, vp->m_final.lno);
+ SET_TXT_STD(sp, TXT_REPLAY);
+
+ sp->lno = vp->m_final.lno;
+
+ if (len == 0 || vp->m_final.cno == len - 1) {
+ sp->cno = len;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ sp->cno = vp->m_final.cno;
+ if (vp->m_final.cno != 0)
+ ++sp->cno;
+ LF_SET(TXT_OVERWRITE | TXT_REPLACE);
+ }
+
+ vp->m_stop.lno = sp->lno;
+ vp->m_stop.cno = sp->cno;
+ if (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * v_subst -- [buffer][count]s
+ * Substitute characters.
+ */
+int
+v_subst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ SET_TXT_STD(sp, 0);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno =
+ vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
+ if (vp->m_stop.cno > len - 1)
+ vp->m_stop.cno = len - 1;
+
+ if (p != NULL &&
+ cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+
+ return (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
+}
diff --git a/usr.bin/vi/vi/v_ulcase.c b/usr.bin/vi/vi/v_ulcase.c
new file mode 100644
index 000000000000..ab2ef1af4b19
--- /dev/null
+++ b/usr.bin/vi/vi/v_ulcase.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_ulcase.c 8.6 (Berkeley) 3/18/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_ulcase -- [count]~
+ * Toggle upper & lower case letters.
+ *
+ * !!!
+ * In historic vi, the count was ignored. It would have been better
+ * if there had been an associated motion, but it's too late to change
+ * it now.
+ */
+int
+v_ulcase(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t blen, lcnt, len;
+ u_long cnt;
+ int ch, change, rval;
+ char *bp, *p;
+
+ /* Get some memory. */
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ /*
+ * !!!
+ * Historic vi didn't permit ~ to cross newline boundaries. I can
+ * think of no reason why it shouldn't, which at least lets the user
+ * auto-repeat through a paragraph.
+ */
+ rval = 0;
+ for (change = -1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt;) {
+ /* Get the line; EOF is an infinite sink. */
+ if ((p = file_gline(sp, ep, vp->m_stop.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno)) {
+ rval = 1;
+ goto ret;
+ }
+ if (lno >= vp->m_stop.lno) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
+ rval = 1;
+ goto ret;
+ }
+ if (change == -1) {
+ v_eof(sp, ep, NULL);
+ rval = 1;
+ goto ret;
+ }
+ break;
+ }
+
+ /* Set current line number. */
+ lno = vp->m_stop.lno;
+
+ /* Empty lines just decrement the count. */
+ if (len == 0) {
+ --cnt;
+ ++vp->m_stop.lno;
+ vp->m_stop.cno = 0;
+ change = 0;
+ continue;
+ }
+
+ /* Get a copy of the line. */
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(bp, p, len);
+
+ /* Set starting pointer. */
+ if (change == -1)
+ p = bp + vp->m_stop.cno;
+ else
+ p = bp;
+
+ /*
+ * Figure out how many characters get changed in this
+ * line. Set the final cursor column.
+ */
+ if (vp->m_stop.cno + cnt >= len) {
+ lcnt = len - vp->m_stop.cno;
+ ++vp->m_stop.lno;
+ vp->m_stop.cno = 0;
+ } else
+ vp->m_stop.cno += lcnt = cnt;
+ cnt -= lcnt;
+
+ /* Change the line. */
+ for (change = 0; lcnt--; ++p) {
+ ch = *(u_char *)p;
+ if (islower(ch)) {
+ *p = toupper(ch);
+ change = 1;
+ } else if (isupper(ch)) {
+ *p = tolower(ch);
+ change = 1;
+ }
+ }
+
+ /* Update the line if necessary. */
+ if (change && file_sline(sp, ep, lno, bp, len)) {
+ rval = 1;
+ break;
+ }
+ }
+
+ /* If changed lines, could be on an illegal line. */
+ if (vp->m_stop.lno != lno &&
+ file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
+ --vp->m_stop.lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ }
+ vp->m_final = vp->m_stop;
+
+ret: FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
diff --git a/usr.bin/vi/vi/v_undo.c b/usr.bin/vi/vi/v_undo.c
new file mode 100644
index 000000000000..767be7fda304
--- /dev/null
+++ b/usr.bin/vi/vi/v_undo.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_undo.c 8.9 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_Undo -- U
+ * Undo changes to this line.
+ */
+int
+v_Undo(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Historically, U reset the cursor to the first column in the line
+ * (not the first non-blank). This seems a bit non-intuitive, but,
+ * considering that we may have undone multiple changes, anything
+ * else (including the cursor position stored in the logging records)
+ * is going to appear random.
+ */
+ vp->m_final.cno = 0;
+
+ /*
+ * !!!
+ * Set up the flags so that an immediately subsequent 'u' will roll
+ * forward, instead of backward. In historic vi, a 'u' following a
+ * 'U' redid all of the changes to the line. Given that the user has
+ * explicitly discarded those changes by entering 'U', it seems likely
+ * that the user wants something between the original and end forms of
+ * the line, so starting to replay the changes seems the best way to
+ * get to there.
+ */
+ F_SET(ep, F_UNDO);
+ ep->lundo = BACKWARD;
+
+ return (log_setline(sp, ep));
+}
+
+/*
+ * v_undo -- u
+ * Undo the last change.
+ */
+int
+v_undo(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Set the command count. */
+ VIP(sp)->u_ccnt = sp->ccnt;
+
+ /*
+ * !!!
+ * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u'
+ * undid the last undo. However, if there has been a change since
+ * the last undo/redo, we always do an undo. To make this work when
+ * the user can undo multiple operations, we leave the old semantic
+ * unchanged, but make '.' after a 'u' do another undo/redo operation.
+ * This has two problems.
+ *
+ * The first is that 'u' didn't set '.' in historic vi. So, if a
+ * user made a change, realized it was in the wrong place, does a
+ * 'u' to undo it, moves to the right place and then does '.', the
+ * change was reapplied. To make this work, we only apply the '.'
+ * to the undo command if it's the command immediately following an
+ * undo command. See vi/vi.c:getcmd() for the details.
+ *
+ * The second is that the traditional way to view the numbered cut
+ * buffers in vi was to enter the commands "1pu.u.u.u. which will
+ * no longer work because the '.' immediately follows the 'u' command.
+ * Since we provide a much better method of viewing buffers, and
+ * nobody can think of a better way of adding in multiple undo, this
+ * remains broken.
+ */
+ if (!F_ISSET(ep, F_UNDO)) {
+ F_SET(ep, F_UNDO);
+ ep->lundo = BACKWARD;
+ } else if (!F_ISSET(vp, VC_ISDOT))
+ ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD;
+
+ switch (ep->lundo) {
+ case BACKWARD:
+ return (log_backward(sp, ep, &vp->m_final));
+ case FORWARD:
+ return (log_forward(sp, ep, &vp->m_final));
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/vi/v_util.c b/usr.bin/vi/vi/v_util.c
new file mode 100644
index 000000000000..8959b5618af6
--- /dev/null
+++ b/usr.bin/vi/vi/v_util.c
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_util.c 8.8 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_eof --
+ * Vi end-of-file error.
+ */
+void
+v_eof(sp, ep, mp)
+ SCR *sp;
+ EXF *ep;
+ MARK *mp;
+{
+ u_long lno;
+
+ if (mp == NULL)
+ msgq(sp, M_BERR, "Already at end-of-file.");
+ else {
+ if (file_lline(sp, ep, &lno))
+ return;
+ if (mp->lno >= lno)
+ msgq(sp, M_BERR, "Already at end-of-file.");
+ else
+ msgq(sp, M_BERR,
+ "Movement past the end-of-file.");
+ }
+}
+
+/*
+ * v_eol --
+ * Vi end-of-line error.
+ */
+void
+v_eol(sp, ep, mp)
+ SCR *sp;
+ EXF *ep;
+ MARK *mp;
+{
+ size_t len;
+
+ if (mp == NULL)
+ msgq(sp, M_BERR, "Already at end-of-line.");
+ else {
+ if (file_gline(sp, ep, mp->lno, &len) == NULL) {
+ GETLINE_ERR(sp, mp->lno);
+ return;
+ }
+ if (mp->cno == len - 1)
+ msgq(sp, M_BERR, "Already at end-of-line.");
+ else
+ msgq(sp, M_BERR, "Movement past the end-of-line.");
+ }
+}
+
+/*
+ * v_nomove --
+ * Vi no cursor movement error.
+ */
+void
+v_nomove(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "No cursor movement made.");
+}
+
+/*
+ * v_sof --
+ * Vi start-of-file error.
+ */
+void
+v_sof(sp, mp)
+ SCR *sp;
+ MARK *mp;
+{
+ if (mp == NULL || mp->lno == 1)
+ msgq(sp, M_BERR, "Already at the beginning of the file.");
+ else
+ msgq(sp, M_BERR, "Movement past the beginning of the file.");
+}
+
+/*
+ * v_sol --
+ * Vi start-of-line error.
+ */
+void
+v_sol(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "Already in the first column.");
+}
+
+/*
+ * v_isempty --
+ * Return if the line contains nothing but white-space characters.
+ */
+int
+v_isempty(p, len)
+ char *p;
+ size_t len;
+{
+ for (; len--; ++p)
+ if (!isblank(*p))
+ return (0);
+ return (1);
+}
diff --git a/usr.bin/vi/vi/v_word.c b/usr.bin/vi/vi/v_word.c
new file mode 100644
index 000000000000..63f0539618b0
--- /dev/null
+++ b/usr.bin/vi/vi/v_word.c
@@ -0,0 +1,569 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_word.c 8.18 (Berkeley) 3/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * There are two types of "words". Bigwords are easy -- groups of anything
+ * delimited by whitespace. Normal words are trickier. They are either a
+ * group of characters, numbers and underscores, or a group of anything but,
+ * delimited by whitespace. When for a word, if you're in whitespace, it's
+ * easy, just remove the whitespace and go to the beginning or end of the
+ * word. Otherwise, figure out if the next character is in a different group.
+ * If it is, go to the beginning or end of that group, otherwise, go to the
+ * beginning or end of the current group. The historic version of vi didn't
+ * get this right, so, for example, there were cases where "4e" was not the
+ * same as "eeee" -- in particular, single character words, and commands that
+ * began in whitespace were almost always handled incorrectly. To get it right
+ * you have to resolve the cursor after each search so that the look-ahead to
+ * figure out what type of "word" the cursor is in will be correct.
+ *
+ * Empty lines, and lines that consist of only white-space characters count
+ * as a single word, and the beginning and end of the file counts as an
+ * infinite number of words.
+ *
+ * Movements associated with commands are different than movement commands.
+ * For example, in "abc def", with the cursor on the 'a', "cw" is from
+ * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white
+ * space is discarded from the change movement. Another example is that,
+ * in the same string, a "cw" on any white space character replaces that
+ * single character, and nothing else. Ain't nothin' in here that's easy.
+ *
+ * One historic note -- in the original vi, the 'w', 'W' and 'B' commands
+ * would treat groups of empty lines as individual words, i.e. the command
+ * would move the cursor to each new empty line. The 'e' and 'E' commands
+ * would treat groups of empty lines as a single word, i.e. the first use
+ * would move past the group of lines. The 'b' command would just beep at
+ * you, or, if you did it from the start of the line as part of a motion
+ * command, go absolutely nuts. If the lines contained only white-space
+ * characters, the 'w' and 'W' commands would just beep at you, and the 'B',
+ * 'b', 'E' and 'e' commands would treat the group as a single word, and
+ * the 'B' and 'b' commands will treat the lines as individual words. This
+ * implementation treats all of these cases as a single white-space word.
+ */
+
+enum which {BIGWORD, LITTLEWORD};
+
+static int bword __P((SCR *, EXF *, VICMDARG *, enum which));
+static int eword __P((SCR *, EXF *, VICMDARG *, enum which));
+static int fword __P((SCR *, EXF *, VICMDARG *, enum which));
+
+/*
+ * v_wordW -- [count]W
+ * Move forward a bigword at a time.
+ */
+int
+v_wordW(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (fword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_wordw -- [count]w
+ * Move forward a word at a time.
+ */
+int
+v_wordw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (fword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * fword --
+ * Move forward by words.
+ */
+static int
+fword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * If in white-space:
+ * If the count is 1, and it's a change command, we're done.
+ * Else, move to the first non-white-space character, which
+ * counts as a single word move. If it's a motion command,
+ * don't move off the end of the line.
+ */
+ if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+ if (cs.cs_flags != CS_EMP && cnt == 1) {
+ if (F_ISSET(vp, VC_C))
+ return (0);
+ if (F_ISSET(vp, VC_D | VC_Y)) {
+ if (cs_fspace(sp, ep, &cs))
+ return (1);
+ goto ret;
+ }
+ }
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ --cnt;
+ }
+
+ /*
+ * Cyclically move to the next word -- this involves skipping
+ * over word characters and then any trailing non-word characters.
+ * Note, for the 'w' command, the definition of a word keeps
+ * switching.
+ */
+ if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * If a motion command and we're at the end of the
+ * last word, we're done. Delete and yank eat any
+ * trailing blanks, but we don't move off the end
+ * of the line regardless.
+ */
+ if (cnt == 0 && ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_D | VC_Y) &&
+ cs_fspace(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0 && ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_D | VC_Y) &&
+ cs_fspace(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+
+ /*
+ * If we didn't move, we must be at EOF.
+ *
+ * !!!
+ * That's okay for motion commands, however.
+ */
+ret: if (!ISMOTION(vp) &&
+ cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+
+ /* Adjust the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+ if (ISMOTION(vp) && cs.cs_flags == 0)
+ --vp->m_stop.cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_wordE -- [count]E
+ * Move forward to the end of the bigword.
+ */
+int
+v_wordE(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (eword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_worde -- [count]e
+ * Move forward to the end of the word.
+ */
+int
+v_worde(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (eword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * eword --
+ * Move forward to the end of the word.
+ */
+static int
+eword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * !!!
+ * If in whitespace, or the next character is whitespace, move past
+ * it. (This doesn't count as a word move.) Stay at the character
+ * past the current one, it sets word "state" for the 'e' command.
+ */
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ goto start;
+ }
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * Cyclically move to the next word -- this involves skipping
+ * over word characters and then any trailing non-word characters.
+ * Note, for the 'e' command, the definition of a word keeps
+ * switching.
+ */
+start: if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * When we reach the start of the word after the last
+ * word, we're done. If we changed state, back up one
+ * to the end of the previous word.
+ */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+
+ /*
+ * If we didn't move, we must be at EOF.
+ *
+ * !!!
+ * That's okay for motion commands, however.
+ */
+ret: if (!ISMOTION(vp) &&
+ cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+
+ /* Set the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_WordB -- [count]B
+ * Move backward a bigword at a time.
+ */
+int
+v_wordB(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (bword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_wordb -- [count]b
+ * Move backward a word at a time.
+ */
+int
+v_wordb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (bword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * bword --
+ * Move backward by words.
+ */
+static int
+bword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * !!!
+ * If in whitespace, or the previous character is whitespace, move
+ * past it. (This doesn't count as a word move.) Stay at the
+ * character before the current one, it sets word "state" for the
+ * 'b' command.
+ */
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ goto start;
+ }
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * Cyclically move to the beginning of the previous word -- this
+ * involves skipping over word characters and then any trailing
+ * non-word characters. Note, for the 'b' command, the definition
+ * of a word keeps switching.
+ */
+start: if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * When we reach the end of the word before the last
+ * word, we're done. If we changed state, move forward
+ * one to the end of the next word.
+ */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_next(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_next(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ }
+
+ /* If we didn't move, we must be at SOF. */
+ret: if (cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ }
+
+ /* Set the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D commands
+ * move to the end of the range. VC_Y stays at the start unless the
+ * end of the range is on a different line, when it moves to the end
+ * of the range. Ignore VC_C and VC_S. Motion commands adjust the
+ * starting point to the character before the current one.
+ */
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp)) {
+ --vp->m_start.cno;
+ if (F_ISSET(vp, VC_Y) && vp->m_start.lno == vp->m_stop.lno)
+ vp->m_final = vp->m_start;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_xchar.c b/usr.bin/vi/vi/v_xchar.c
new file mode 100644
index 000000000000..c788db4852b2
--- /dev/null
+++ b/usr.bin/vi/vi/v_xchar.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_xchar.c 8.6 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_xchar -- [count]x
+ * Deletes the character(s) on which the cursor sits.
+ */
+int
+v_xchar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ goto nodel;
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ if (len == 0) {
+nodel: msgq(sp, M_BERR, "No characters to delete.");
+ return (1);
+ }
+
+ /*
+ * Delete from the cursor toward the end of line, w/o moving the
+ * cursor.
+ *
+ * !!!
+ * Note, "2x" at EOL isn't the same as "xx" because the left movement
+ * of the cursor as part of the 'x' command isn't taken into account.
+ * Historically correct.
+ */
+ if (F_ISSET(vp, VC_C1SET))
+ vp->m_stop.cno += vp->count - 1;
+ if (vp->m_stop.cno >= len - 1) {
+ vp->m_stop.cno = len - 1;
+ vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0;
+ } else
+ vp->m_final.cno = vp->m_start.cno;
+
+ if (cut(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
+}
+
+/*
+ * v_Xchar -- [count]X
+ * Deletes the character(s) immediately before the current cursor
+ * position.
+ */
+int
+v_Xchar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_long cnt;
+
+ if (vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (cnt >= vp->m_start.cno)
+ vp->m_start.cno = 0;
+ else
+ vp->m_start.cno -= cnt;
+ --vp->m_stop.cno;
+ vp->m_final.cno = vp->m_start.cno;
+
+ if (cut(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
+}
diff --git a/usr.bin/vi/vi/v_yank.c b/usr.bin/vi/vi/v_yank.c
new file mode 100644
index 000000000000..c5bce64dfbd8
--- /dev/null
+++ b/usr.bin/vi/vi/v_yank.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_yank.c 8.13 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_yank -- [buffer][count]Y
+ * [buffer][count]y[count][motion]
+ * Yank text (or lines of text) into a cut buffer.
+ *
+ * !!!
+ * Historic vi moved the cursor to the from MARK if it was before the current
+ * cursor and on a different line, e.g., "yj" moves the cursor but "yk" and
+ * "yh" do not. Unfortunately, it's too late to change this now. Matching
+ * the historic semantics isn't easy. The line number was always changed and
+ * column movement was usually relative. However, "y'a" moved the cursor to
+ * the first non-blank of the line marked by a, while "y`a" moved the cursor
+ * to the line and column marked by a. Hopefully, the motion component code
+ * got it right... Unlike delete, we make no adjustments here.
+ */
+int
+v_yank(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ int lmode;
+
+ /* The line may not exist in line mode cuts, check to be sure. */
+ if (F_ISSET(vp, VM_LMODE)) {
+ if (file_gline(sp, ep, vp->m_stop.lno, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+ lmode = CUT_LINEMODE;
+ } else
+ lmode = 0;
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ sp->rptlines[L_YANKED] += (vp->m_stop.lno - vp->m_start.lno) + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_z.c b/usr.bin/vi/vi/v_z.c
new file mode 100644
index 000000000000..ebae985f99c7
--- /dev/null
+++ b/usr.bin/vi/vi/v_z.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_z.c 8.11 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_z -- [count]z[count][-.+^<CR>]
+ * Move the screen.
+ */
+int
+v_z(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t last, lno;
+ u_int value;
+
+ /*
+ * The first count is the line to use. If the value doesn't
+ * exist, use the last line.
+ */
+ if (F_ISSET(vp, VC_C1SET)) {
+ lno = vp->count;
+ if (file_lline(sp, ep, &last))
+ return (1);
+ if (lno > last)
+ lno = last;
+ } else
+ lno = vp->m_start.lno;
+
+ /* Set default return cursor values. */
+ vp->m_final.lno = lno;
+ vp->m_final.cno = vp->m_start.cno;
+
+ /*
+ * The second count is the displayed window size, i.e. the 'z'
+ * command is another way to get artificially small windows.
+ *
+ * !!!
+ * A window size of 0 was historically allowed, and simply ignored.
+ * Also, this could be much more simply done by modifying the value
+ * of the O_WINDOW option, but that's not how it worked historically.
+ */
+ if (F_ISSET(vp, VC_C2SET) &&
+ vp->count2 != 0 && sp->s_crel(sp, vp->count2))
+ return (1);
+
+ switch (vp->character) {
+ case '-': /* Put the line at the bottom. */
+ if (sp->s_fill(sp, ep, lno, P_BOTTOM))
+ return (1);
+ break;
+ case '.': /* Put the line in the middle. */
+ if (sp->s_fill(sp, ep, lno, P_MIDDLE))
+ return (1);
+ break;
+ default: /* Put the line at the top for <cr>. */
+ value = term_key_val(sp, vp->character);
+ if (value != K_CR && value != K_NL) {
+ msgq(sp, M_ERR, "usage: %s.", vp->kp->usage);
+ return (1);
+ }
+ /* FALLTHROUGH */
+ case '+': /* Put the line at the top. */
+ if (sp->s_fill(sp, ep, lno, P_TOP))
+ return (1);
+ break;
+ case '^': /* Print the screen before the z- screen. */
+ /*
+ * !!!
+ * Historic practice isn't real clear on this one. It seems
+ * that the command "70z^" is the same as ":70<cr>z-z^" with
+ * an off-by-one difference. So, until I find documentation
+ * to the contrary, the z^ command in this implementation
+ * displays the screen immediately before the current one.
+ * Fill the screen with the selected line at the bottom, then,
+ * scroll the screen down a page, and move to the middle line
+ * of the screen. Historic vi moved the cursor to some random
+ * place in the screen, as far as I can tell.
+ */
+ if (sp->s_fill(sp, ep, lno, P_BOTTOM))
+ return (1);
+ if (sp->s_down(sp, ep, &vp->m_final, sp->t_maxrows - 1, 1))
+ return (1);
+ if (sp->s_position(sp, ep, &vp->m_final, 0, P_MIDDLE))
+ return (1);
+ break;
+ }
+
+ /* If the map changes, have to redraw the entire screen. */
+ F_SET(sp, S_REDRAW);
+
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_zexit.c b/usr.bin/vi/vi/v_zexit.c
new file mode 100644
index 000000000000..053646e1383a
--- /dev/null
+++ b/usr.bin/vi/vi/v_zexit.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_zexit.c 8.7 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_zexit -- ZZ
+ * Save the file and exit.
+ */
+int
+v_zexit(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (F_ISSET(ep, F_MODIFIED) &&
+ file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+
+ /*
+ * !!!
+ * Historic practice: quit! or two quit's done in succession
+ * (where ZZ counts as a quit) didn't check for other files.
+ *
+ * Check for related screens; quit if they exist, the user will
+ * get a message on the last screen.
+ */
+ if (sp->ccnt != sp->q_ccnt + 1 &&
+ ep->refcnt <= 1 && file_unedited(sp) != NULL) {
+ sp->q_ccnt = sp->ccnt;
+ msgq(sp, M_ERR,
+ "More files to edit; use \":n\" to go to the next file");
+ return (1);
+ }
+
+ F_SET(sp, S_EXIT);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/vcmd.c b/usr.bin/vi/vi/vcmd.c
new file mode 100644
index 000000000000..445f6507c4c3
--- /dev/null
+++ b/usr.bin/vi/vi/vcmd.c
@@ -0,0 +1,530 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vcmd.c 8.26 (Berkeley) 3/22/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * This array maps keystrokes to vi command functions. It is known
+ * in ex/ex_usage.c that it takes four columns to name a vi character.
+ */
+VIKEYS const vikeys [MAXVIKEY + 1] = {
+/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */
+ {NULL},
+/* 001 ^A */
+ {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|VM_RCM_SET,
+ "[count]^A",
+ "^A search forward for cursor word"},
+/* 002 ^B */
+ {v_pageup, V_ABS|V_CNT|VM_RCM_SETLFNB,
+ "[count]^B",
+ "^B page up by screens"},
+/* 003 ^C */
+ {NULL, 0,
+ "^C",
+ "^C interrupt a search or global command"},
+/* 004 ^D */
+ {v_hpagedown, V_ABS|V_CNT|VM_RCM_SETLFNB,
+ "[count]^D",
+ "^D page down by half screens (setting count)"},
+/* 005 ^E */
+ {v_linedown, V_CNT,
+ "[count]^E",
+ "^E page down by lines"},
+/* 006 ^F */
+ {v_pagedown, V_ABS|V_CNT|VM_RCM_SETLFNB,
+ "[count]^F",
+ "^F page down by screens"},
+/* 007 ^G */
+ {v_status, 0,
+ "^G",
+ "^G file status"},
+/* 010 ^H */
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]^H",
+ "^H move left by columns"},
+/* 011 ^I */
+ {NULL},
+/* 012 ^J */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]^J",
+ "^J move down by lines"},
+/* 013 ^K */
+ {NULL},
+/* 014 ^L */
+ {v_redraw, 0,
+ "^L",
+ "^L redraw screen"},
+/* 015 ^M */
+ {v_cr, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
+ "[count]^M",
+ "^M move down by lines (to first non-blank)"},
+/* 016 ^N */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]^N",
+ "^N move down by lines"},
+/* 017 ^O */
+ {NULL},
+/* 020 ^P */
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]^P",
+ "^P move up by lines"},
+/* 021 ^Q -- not available, used for hardware flow control. */
+ {NULL},
+/* 022 ^R */
+ {v_redraw, 0,
+ "^R",
+ "^R redraw screen"},
+/* 023 ^S -- not available, used for hardware flow control. */
+ {NULL},
+/* 024 ^T */
+ {v_tagpop, VM_RCM_SET,
+ "^T",
+ "^T tag pop"},
+/* 025 ^U */
+ {v_hpageup, V_ABS|V_CNT|VM_RCM_SETLFNB,
+ "[count]^U",
+ "^U half page up (set count)"},
+/* 026 ^V */
+ {NULL, 0,
+ "^V",
+ "^V input a literal character"},
+/* 027 ^W */
+ {v_screen, 0,
+ "^W",
+ "^W move to next screen"},
+/* 030 ^X */
+ {NULL},
+/* 031 ^Y */
+ {v_lineup, V_CNT,
+ "[count]^Y",
+ "^Y page up by lines"},
+/* 032 ^Z */
+ {v_stop, 0,
+ "^Z",
+ "^Z suspend editor"},
+/* 033 ^[ */
+ {NULL, 0,
+ "^[ <escape>",
+ "^[ <escape> leave input mode, return to command mode"},
+/* 034 ^\ */
+ {NULL},
+/* 035 ^] */
+ {v_tagpush, V_KEYW|VM_RCM_SET,
+ "^]",
+ "^] tag push cursor word"},
+/* 036 ^^ */
+ {v_switch, 0,
+ "^^",
+ "^^ switch to previous file"},
+/* 037 ^_ */
+ {NULL},
+/* 040 ' ' */
+ {v_right, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]' '",
+ " <space> move right by columns"},
+/* 041 ! */
+ {v_filter, V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
+ "[count]![count]motion command(s)",
+ " ! filter through command(s) to motion"},
+/* 042 " */
+ {NULL},
+/* 043 # */
+ {v_increment, V_CHAR|V_CNT|V_DOT|V_KEYNUM|VM_RCM_SET,
+ "[count]#[#+-]",
+ " # number increment/decrement"},
+/* 044 $ */
+ {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST,
+ " [count]$",
+ " $ move to last column"},
+/* 045 % */
+ {v_match, V_ABS|V_MOVE|VM_RCM_SET,
+ "%",
+ " % move to match"},
+/* 046 & */
+ {v_again, 0,
+ "&",
+ " & repeat substitution"},
+/* 047 ' */
+ {v_fmark, V_ABS|V_CHAR|V_MOVE|VM_LMODE,
+ "'['a-z]",
+ " ' move to mark (to first non-blank)"},
+/* 050 ( */
+ {v_sentenceb, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count](",
+ " ( move back sentence"},
+/* 051 ) */
+ {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count])",
+ " ) move forward sentence"},
+/* 052 * */
+ {NULL},
+/* 053 + */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
+ "[count]+",
+ " + move down by lines (to first non-blank)"},
+/* 054 , */
+ {v_chrrepeat, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count],",
+ " , reverse last F, f, T or t search"},
+/* 055 - */
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
+ "[count]-",
+ " - move up by lines (to first non-blank)"},
+/* 056 . */
+ {NULL, 0,
+ ".",
+ " . repeat the last command"},
+/* 057 / */
+ {v_searchf, V_ABS|V_MOVE|VM_RCM_SET,
+ "/RE[/ offset]",
+ " / search forward"},
+/* 060 0 */
+ {v_zero, V_MOVE|VM_RCM_SET,
+ "0",
+ " 0 move to first character"},
+/* 061 1 */
+ {NULL},
+/* 062 2 */
+ {NULL},
+/* 063 3 */
+ {NULL},
+/* 064 4 */
+ {NULL},
+/* 065 5 */
+ {NULL},
+/* 066 6 */
+ {NULL},
+/* 067 7 */
+ {NULL},
+/* 070 8 */
+ {NULL},
+/* 071 9 */
+ {NULL},
+/* 072 : */
+ {v_ex, 0,
+ ":command [| command] ...",
+ " : ex command"},
+/* 073 ; */
+ {v_chrepeat, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count];",
+ " ; repeat last F, f, T or t search"},
+/* 074 < */
+ {v_shiftl, V_CNT|V_DOT|V_MOTION|VC_S|VM_RCM_SET,
+ "[count]<[count]motion",
+ " < shift lines left to motion"},
+/* 075 = */
+ {NULL},
+/* 076 > */
+ {v_shiftr, V_CNT|V_DOT|V_MOTION|VC_S|VM_RCM_SET,
+ "[count]>[count]motion",
+ " > shift lines right to motion"},
+/* 077 ? */
+ {v_searchb, V_ABS|V_MOVE|VM_RCM_SET,
+ "?RE[? offset]",
+ " ? search backward"},
+/* 100 @ */
+ {v_at, V_RBUF|VM_RCM_SET,
+ "@buffer",
+ " @ execute buffer"},
+/* 101 A */
+ {v_iA, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]A",
+ " A append to the line"},
+/* 102 B */
+ {v_wordB, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]B",
+ " B move back bigword"},
+/* 103 C */
+ {v_Change, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer][count]C",
+ " C change to end-of-line"},
+/* 104 D */
+ {v_Delete, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer][count]D",
+ " D delete to end-of-line"},
+/* 105 E */
+ {v_wordE, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]E",
+ " E move to end of bigword"},
+/* 106 F */
+ {v_chF, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]F character",
+ " F character in line backward search"},
+/* 107 G */
+ {v_lgoto, V_ABS|V_CNT|V_MOVE|VM_LMODE,
+ "[count]G",
+ " G move to line"},
+/* 110 H */
+ {v_home, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
+ "[count]H",
+ " H move to count lines from screen top"},
+/* 111 I */
+ {v_iI, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]I",
+ " I insert at line beginning"},
+/* 112 J */
+ {v_join, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]J",
+ " J join lines"},
+/* 113 K */
+ {NULL},
+/* 114 L */
+ {v_bottom, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
+ "[count]L",
+ " L move to screen bottom"},
+/* 115 M */
+ {v_middle, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
+ "M",
+ " M move to screen middle"},
+/* 116 N */
+ {v_searchN, V_ABS|V_MOVE|VM_RCM_SET,
+ "n",
+ " N reverse last search"},
+/* 117 O */
+ {v_iO, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]O",
+ " O insert above line"},
+/* 120 P */
+ {v_Put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer]P",
+ " P insert before cursor from buffer"},
+/* 121 Q */
+ {v_exmode, 0,
+ "Q",
+ " Q switch to ex mode"},
+/* 122 R */
+ {v_Replace, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]R",
+ " R replace characters"},
+/* 123 S */
+ {v_Subst, V_CNT|V_DOT|V_OBUF|VM_LMODE|VM_RCM_SET,
+ "[buffer][count]S",
+ " S substitute for the line(s)"},
+/* 124 T */
+ {v_chT, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]T character",
+ " T before character in line backward search"},
+/* 125 U */
+ {v_Undo, VM_RCM_SET,
+ "U",
+ " U Restore the current line"},
+/* 126 V */
+ {NULL},
+/* 127 W */
+ {v_wordW, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]W",
+ " W move to next bigword"},
+/* 130 X */
+ {v_Xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer][count]X",
+ " X delete character before cursor"},
+/* 131 Y */
+ {v_yank, V_CNT|VM_LMODE|V_OBUF,
+ "[buffer][count]Y",
+ " Y copy line"},
+/* 132 Z */
+ {v_zexit, 0,
+ "ZZ",
+ "ZZ save file and exit"},
+/* 133 [ */
+ {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[[",
+ "[[ move back section"},
+/* 134 \ */
+ {NULL},
+/* 135 ] */
+ {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "]]",
+ "]] move forward section"},
+/* 136 ^ */
+ /*
+ * DON'T set the VM_RCM_SETFNB flag, the function has to do the work
+ * anyway, in case it's a motion component. DO set VM_RCM_SET, so
+ * that any motion that's part of a command is preserved.
+ */
+ {v_first, V_CNT|V_MOVE|VM_RCM_SET,
+ "^",
+ " ^ move to first non-blank"},
+/* 137 _ */
+ /*
+ * Needs both to set the VM_RCM_SETFNB flag, and to do the work
+ * in the function, in case it's a delete.
+ */
+ {v_cfirst, V_CNT|V_MOVE|VM_RCM_SETFNB,
+ "_",
+ " _ move to first non-blank"},
+/* 140 ` */
+ {v_bmark, V_ABS|V_CHAR|V_MOVE|VM_RCM_SET,
+ "`[`a-z]",
+ " ` move to mark"},
+/* 141 a */
+ {v_ia, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]a",
+ " a append after cursor"},
+/* 142 b */
+ {v_wordb, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]b",
+ " b move back word"},
+/* 143 c */
+ {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_C|VM_RCM_SET,
+ "[buffer][count]c[count]motion",
+ " c change to motion"},
+/* 144 d */
+ {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_D|VM_RCM_SET,
+ "[buffer][count]d[count]motion",
+ " d delete to motion"},
+/* 145 e */
+ {v_worde, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]e",
+ " e move to end of word"},
+/* 146 f */
+ {v_chf, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]f character",
+ " f character in line forward search"},
+/* 147 g */
+ {NULL},
+/* 150 h */
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]h",
+ " h move left by columns"},
+/* 151 i */
+ {v_ii, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]i",
+ " i insert before cursor"},
+/* 152 j */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]j",
+ " j move down by lines"},
+/* 153 k */
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]k",
+ " k move up by lines"},
+/* 154 l */
+ {v_right, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]l",
+ " l move right by columns"},
+/* 155 m */
+ {v_mark, V_CHAR,
+ "m[a-z]",
+ " m set mark"},
+/* 156 n */
+ {v_searchn, V_ABS|V_MOVE|VM_RCM_SET,
+ "n",
+ " n repeat last search"},
+/* 157 o */
+ {v_io, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]o",
+ " o append after line"},
+/* 160 p */
+ {v_put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer]p",
+ " p insert after cursor from buffer"},
+/* 161 q */
+ {NULL},
+/* 162 r */
+ {v_replace, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]r character",
+ " r replace character"},
+/* 163 s */
+ {v_subst, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer][count]s",
+ " s substitute character"},
+/* 164 t */
+ {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]t character",
+ " t before character in line forward search"},
+/* 165 u */
+ /*
+ * DON'T set the V_DOT flag, it' more complicated than that.
+ * See vi/vi.c for details.
+ */
+ {v_undo, VM_RCM_SET,
+ "u",
+ " u undo last change"},
+/* 166 v */
+ {NULL},
+/* 167 w */
+ {v_wordw, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]w",
+ " w move to next word"},
+/* 170 x */
+ {v_xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
+ "[buffer][count]x",
+ " x delete character"},
+/* 171 y */
+ {v_yank, V_CNT|V_MOTION|V_OBUF|VC_Y|VM_RCM_SET,
+ "[buffer][count]y[count]motion",
+ " y copy text to motion into a cut buffer"},
+/* 172 z */
+ /*
+ * DON'T set the V_CHAR flag, the char isn't required,
+ * so it's handled specially in getcmd().
+ */
+ {v_z, V_CNT|VM_RCM_SETFNB,
+ "[line]z[window_size][-|.|+|^|<CR>]",
+ " z redraw window"},
+/* 173 { */
+ {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]{",
+ " { move back paragraph"},
+/* 174 | */
+ {v_ncol, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]|",
+ " | move to column"},
+/* 175 } */
+ {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]}",
+ " } move forward paragraph"},
+/* 176 ~ */
+ {v_ulcase, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]~",
+ " ~ reverse case"},
+};
diff --git a/usr.bin/vi/vi/vcmd.h b/usr.bin/vi/vi/vcmd.h
new file mode 100644
index 000000000000..f469296c1822
--- /dev/null
+++ b/usr.bin/vi/vi/vcmd.h
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * 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.
+ *
+ * @(#)vcmd.h 8.27 (Berkeley) 3/17/94
+ */
+
+typedef struct _vikeys VIKEYS;
+
+/* Structure passed around to functions implementing vi commands. */
+typedef struct _vicmdarg {
+#define vp_startzero buffer /* START ZERO OUT. */
+ CHAR_T key; /* Command key. */
+ CHAR_T buffer; /* Buffer. */
+ CHAR_T character; /* Character. */
+ u_long count; /* Count. */
+ u_long count2; /* Second count (only used by z). */
+ VIKEYS const *kp; /* VIKEYS key. */
+ size_t klen; /* Keyword length. */
+
+ /*
+ * Historic vi allowed "dl" when the cursor was on the last column,
+ * deleting the last character, and similarly allowed "dw" when
+ * the cursor was on the last column of the file. It didn't allow
+ * "dh" when the cursor was on column 1, although these cases are
+ * not strictly analogous. The point is that some movements would
+ * succeed if they were associated with a motion command, and fail
+ * otherwise. This is part of the off-by-1 schizophrenia that
+ * plagued vi. Other examples are that "dfb" deleted everything
+ * up to and including the next 'b' character, while "d/b" deleted
+ * everything up to the next 'b' character. While this implementation
+ * regularizes the interface to the extent possible, there are many
+ * special cases that can't be fixed. The special cases are handled
+ * by setting flags per command so that the underlying motion routines
+ * know what's really going on.
+ *
+ * The VC_* and VM_* flags are set in the vikeys array, and the VM_*
+ * flags may be set by the underlying functions (motion component or
+ * command) as well. For this reason, the flags in the VICMDARG and
+ * VIKEYS structures live in the same name space.
+ */
+#define VC_C 0x00000001 /* The 'c' command. */
+#define VC_D 0x00000002 /* The 'd' command. */
+#define VC_S 0x00000004 /* The '>' command. */
+#define VC_Y 0x00000008 /* The 'y' command. */
+#define VC_COMMASK 0x0000000f /* Mask for special flags. */
+#define ISMOTION(vp) F_ISSET(vp, VC_COMMASK)
+
+ /*
+ * The VM_RCM_* flags are single usage, i.e. if you set one, you have
+ * to clear the others.
+ */
+#define VM_LMODE 0x00000010 /* Motion is line oriented. */
+#define VM_NOMOTION 0x00000020 /* Motion command not entered. */
+#define VM_RCM 0x00000040 /* Use relative cursor movment (RCM). */
+#define VM_RCM_SET 0x00000080 /* RCM: set to current position. */
+#define VM_RCM_SETFNB 0x00000100 /* RCM: set to first non-blank (FNB). */
+#define VM_RCM_SETLAST 0x00000200 /* RCM: set to last character. */
+#define VM_RCM_SETLFNB 0x00000400 /* RCM: set to FNB if cursor moved. */
+#define VM_RCM_SETNNB 0x00000800 /* RCM: set to next non-blank. */
+#define VM_RCM_MASK 0x00000fc0 /* Mask for RCM flags. */
+
+ /* Flags for the underlying function. */
+#define VC_BUFFER 0x00001000 /* The buffer was set. */
+#define VC_C1RESET 0x00002000 /* Reset C1SET flag for dot commands. */
+#define VC_C1SET 0x00004000 /* Count 1 was set. */
+#define VC_C2SET 0x00008000 /* Count 2 was set. */
+#define VC_ISDOT 0x00010000 /* Command was the dot command. */
+ u_int32_t flags;
+
+#define vp_endzero keyword /* END ZERO OUT. */
+ char *keyword; /* Keyword. */
+ size_t kbuflen; /* Keyword buffer length. */
+ /*
+ * There are four cursor locations that we worry about: the initial
+ * cursor position, the start of the range, the end of the range,
+ * and the final cursor position. The initial cursor position and
+ * the start of the range are both m_start, and are always the same.
+ * All locations are initialized to the starting cursor position by
+ * the main vi routines, and the underlying functions depend on this.
+ *
+ * Commands that can be motion components set the end of the range
+ * cursor position, m_stop. All commands must set the ending cursor
+ * position, m_final. The reason that m_stop isn't the same as m_final
+ * is that there are situations where the final position of the cursor
+ * is outside of the cut/delete range (e.g. 'd[[' from the first column
+ * of a line). The final cursor position often varies based on the
+ * direction of the movement, as well as the command. The only special
+ * case that the delete code handles is that it will make adjustments
+ * if the final cursor position is deleted.
+ *
+ * The reason for all of this is that the historic vi semantics were
+ * defined command-by-command. Every function has to roll its own
+ * starting and stopping positions, and adjust if it's being used as a
+ * motion component. The general rules are as follows:
+ * 1: If not a motion component, the final cursor is at the end
+ * of the range.
+ * 2: If moving backward in the file:
+ * a: VC_D moves to the end of the range.
+ * b: If the line hasn't changed, VC_Y doesn't move, else it
+ * moves to the end of the range.
+ * 3: If moving forward in the file, VC_D and VC_Y stay at the
+ * start of the range.
+ *
+ * Usually, if moving backward in the file and it's a motion component,
+ * the starting cursor is decremented by a single character (or, in a
+ * few cases, to the end of the previous line) so that the starting
+ * cursor character isn't cut or deleted. No cursor adjustment is
+ * needed for moving forward, because the cut/delete routines handle
+ * m_stop inclusively, i.e. the last character in the range is cut or
+ * deleted. This makes cutting to the EOF/EOL reasonable.
+ *
+ * We ignore VC_C and VC_S everywhere, because the text input routines
+ * always set the cursor to the last character inserted.
+ */
+ MARK m_start; /* mark: initial cursor, range start. */
+ MARK m_stop; /* mark: range end. */
+ MARK m_final; /* mark: final cursor position. */
+} VICMDARG;
+
+/* Vi command structure. */
+struct _vikeys { /* Underlying function. */
+ int (*func) __P((SCR *, EXF *, VICMDARG *));
+#define V_ABS 0x00020000 /* Absolute movement, set '' mark. */
+#define V_CHAR 0x00040000 /* Character (required, trailing). */
+#define V_CNT 0x00080000 /* Count (optional, leading). */
+#define V_DOT 0x00100000 /* On success, sets dot command. */
+#define V_KEYNUM 0x00200000 /* Cursor referenced number. */
+#define V_KEYW 0x00400000 /* Cursor referenced word. */
+#define V_MOTION 0x00800000 /* Motion (required, trailing). */
+#define V_MOVE 0x01000000 /* Command defines movement. */
+#define V_OBUF 0x02000000 /* Buffer (optional, leading). */
+#define V_RBUF 0x04000000 /* Buffer (required, trailing). */
+ u_int32_t flags;
+ char *usage; /* Usage line. */
+ char *help; /* Help line. */
+};
+#define MAXVIKEY 126 /* List of vi commands. */
+extern VIKEYS const vikeys[MAXVIKEY + 1];
+
+/* Definition of a vi "word". */
+#define inword(ch) (isalnum(ch) || (ch) == '_')
+
+/* Character stream structure, prototypes. */
+typedef struct _vcs {
+ recno_t cs_lno; /* Line. */
+ size_t cs_cno; /* Column. */
+ char *cs_bp; /* Buffer. */
+ size_t cs_len; /* Length. */
+ int cs_ch; /* Character. */
+#define CS_EMP 1 /* Empty line. */
+#define CS_EOF 2 /* End-of-file. */
+#define CS_EOL 3 /* End-of-line. */
+#define CS_SOF 4 /* Start-of-file. */
+ int cs_flags; /* Return flags. */
+} VCS;
+
+int cs_bblank __P((SCR *, EXF *, VCS *));
+int cs_fblank __P((SCR *, EXF *, VCS *));
+int cs_fspace __P((SCR *, EXF *, VCS *));
+int cs_init __P((SCR *, EXF *, VCS *));
+int cs_next __P((SCR *, EXF *, VCS *));
+int cs_prev __P((SCR *, EXF *, VCS *));
+
+ /* Character search information. */
+enum cdirection { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH };
+
+/* Vi private, per-screen memory. */
+typedef struct _vi_private {
+ VICMDARG sdot; /* Saved dot, motion command. */
+ VICMDARG sdotmotion;
+
+ CHAR_T rlast; /* Last 'r' command character. */
+
+ char *rep; /* Input replay buffer. */
+ size_t rep_len; /* Input replay buffer length. */
+ size_t rep_cnt; /* Input replay buffer characters. */
+
+ CHAR_T inc_lastch; /* Last increment character. */
+ long inc_lastval; /* Last increment value. */
+
+ char *paragraph; /* Paragraph search list. */
+ size_t paragraph_len; /* Paragraph search list length. */
+
+ u_long u_ccnt; /* Undo command count. */
+
+ CHAR_T lastckey; /* Last search character. */
+ enum cdirection csearchdir; /* Character search direction. */
+} VI_PRIVATE;
+
+#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private))
+
+/* Vi function prototypes. */
+int txt_auto __P((SCR *, EXF *, recno_t, TEXT *, size_t, TEXT *));
+int v_buildparagraph __P((SCR *));
+int v_end __P((SCR *));
+void v_eof __P((SCR *, EXF *, MARK *));
+void v_eol __P((SCR *, EXF *, MARK *));
+int v_exwrite __P((void *, const char *, int));
+int v_init __P((SCR *, EXF *));
+int v_isempty __P((char *, size_t));
+int v_msgflush __P((SCR *));
+void v_nomove __P((SCR *));
+int v_ntext __P((SCR *, EXF *, TEXTH *, MARK *,
+ const char *, const size_t, MARK *, int, recno_t, u_int));
+int v_optchange __P((SCR *, int));
+int v_screen_copy __P((SCR *, SCR *));
+int v_screen_end __P((SCR *));
+void v_sof __P((SCR *, MARK *));
+void v_sol __P((SCR *));
+int vi __P((SCR *, EXF *));
+
+#define VIPROTO(name) int name __P((SCR *, EXF *, VICMDARG *))
+VIPROTO(v_again);
+VIPROTO(v_at);
+VIPROTO(v_bmark);
+VIPROTO(v_bottom);
+VIPROTO(v_cfirst);
+VIPROTO(v_Change);
+VIPROTO(v_change);
+VIPROTO(v_chF);
+VIPROTO(v_chf);
+VIPROTO(v_chrepeat);
+VIPROTO(v_chrrepeat);
+VIPROTO(v_chT);
+VIPROTO(v_cht);
+VIPROTO(v_cr);
+VIPROTO(v_Delete);
+VIPROTO(v_delete);
+VIPROTO(v_dollar);
+VIPROTO(v_down);
+VIPROTO(v_ex);
+VIPROTO(v_exmode);
+VIPROTO(v_filter);
+VIPROTO(v_first);
+VIPROTO(v_fmark);
+VIPROTO(v_home);
+VIPROTO(v_hpagedown);
+VIPROTO(v_hpageup);
+VIPROTO(v_iA);
+VIPROTO(v_ia);
+VIPROTO(v_iI);
+VIPROTO(v_ii);
+VIPROTO(v_increment);
+VIPROTO(v_iO);
+VIPROTO(v_io);
+VIPROTO(v_join);
+VIPROTO(v_left);
+VIPROTO(v_lgoto);
+VIPROTO(v_linedown);
+VIPROTO(v_lineup);
+VIPROTO(v_mark);
+VIPROTO(v_match);
+VIPROTO(v_middle);
+VIPROTO(v_ncol);
+VIPROTO(v_pagedown);
+VIPROTO(v_pageup);
+VIPROTO(v_paragraphb);
+VIPROTO(v_paragraphf);
+VIPROTO(v_Put);
+VIPROTO(v_put);
+VIPROTO(v_redraw);
+VIPROTO(v_Replace);
+VIPROTO(v_replace);
+VIPROTO(v_right);
+VIPROTO(v_screen);
+VIPROTO(v_searchb);
+VIPROTO(v_searchf);
+VIPROTO(v_searchN);
+VIPROTO(v_searchn);
+VIPROTO(v_searchw);
+VIPROTO(v_sectionb);
+VIPROTO(v_sectionf);
+VIPROTO(v_sentenceb);
+VIPROTO(v_sentencef);
+VIPROTO(v_shiftl);
+VIPROTO(v_shiftr);
+VIPROTO(v_status);
+VIPROTO(v_stop);
+VIPROTO(v_Subst);
+VIPROTO(v_subst);
+VIPROTO(v_switch);
+VIPROTO(v_tagpop);
+VIPROTO(v_tagpush);
+VIPROTO(v_ulcase);
+VIPROTO(v_Undo);
+VIPROTO(v_undo);
+VIPROTO(v_up);
+VIPROTO(v_wordB);
+VIPROTO(v_wordb);
+VIPROTO(v_wordE);
+VIPROTO(v_worde);
+VIPROTO(v_wordW);
+VIPROTO(v_wordw);
+VIPROTO(v_Xchar);
+VIPROTO(v_xchar);
+VIPROTO(v_Yank);
+VIPROTO(v_yank);
+VIPROTO(v_z);
+VIPROTO(v_zero);
+VIPROTO(v_zexit);
diff --git a/usr.bin/vi/vi/vi.c b/usr.bin/vi/vi/vi.c
new file mode 100644
index 000000000000..67fac036e1a5
--- /dev/null
+++ b/usr.bin/vi/vi/vi.c
@@ -0,0 +1,801 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vi.c 8.57 (Berkeley) 3/18/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static int getcmd __P((SCR *, EXF *,
+ VICMDARG *, VICMDARG *, VICMDARG *, int *));
+static inline int
+ getcount __P((SCR *, ARG_CHAR_T, u_long *));
+static inline int
+ getkey __P((SCR *, CH *, u_int));
+static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int));
+static int getmotion __P((SCR *, EXF *, VICMDARG *, VICMDARG *));
+
+/*
+ * Side-effect:
+ * The dot structure can be set by the underlying vi functions,
+ * see v_Put() and v_put().
+ */
+#define DOT (&VIP(sp)->sdot)
+#define DOTMOTION (&VIP(sp)->sdotmotion)
+
+/*
+ * vi --
+ * Main vi command loop.
+ */
+int
+vi(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ MARK abs;
+ VICMDARG cmd, *vp;
+ u_int flags, saved_mode;
+ int comcount, eval;
+
+ /* Start vi and paint the screen. */
+ if (v_init(sp, ep))
+ return (1);
+ if (sp->s_refresh(sp, ep)) {
+ (void)v_end(sp);
+ return (1);
+ }
+
+ /* Command initialization. */
+ memset(&cmd, 0, sizeof(VICMDARG));
+
+ for (eval = 0, vp = &cmd;;) {
+ if (!MAPPED_KEYS_WAITING(sp) && log_cursor(sp, ep))
+ goto err;
+
+ /*
+ * We get a command, which may or may not have an associated
+ * motion. If it does, we get it too, calling its underlying
+ * function to get the resulting mark. We then call the
+ * command setting the cursor to the resulting mark.
+ */
+ if (getcmd(sp, ep, DOT, vp, NULL, &comcount))
+ goto err;
+
+ /*
+ * Historical practice: if a dot command gets a new count,
+ * any motion component goes away, i.e. "d3w2." deletes a
+ * total of 5 words.
+ */
+ if (F_ISSET(vp, VC_ISDOT) && comcount)
+ DOTMOTION->count = 1;
+
+ /* Copy the key flags into the local structure. */
+ F_SET(vp, vp->kp->flags);
+
+ /* Get any associated keyword. */
+ if (F_ISSET(vp, V_KEYNUM | V_KEYW) &&
+ getkeyword(sp, ep, vp, vp->flags))
+ goto err;
+
+ /* If a non-relative movement, copy the future absolute mark. */
+ if (F_ISSET(vp, V_ABS)) {
+ abs.lno = sp->lno;
+ abs.cno = sp->cno;
+ }
+
+ /*
+ * Set the three cursor locations to the current cursor. The
+ * underlying routines don't bother if the cursor doesn't move.
+ * This also handles line commands (e.g. Y) defaulting to the
+ * current line.
+ */
+ vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
+ vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
+
+ /*
+ * Do any required motion; getmotion sets the from MARK and the
+ * line mode flag. We save off the RCM mask and only restore
+ * it if it no RCM flags are set by the motion command. This
+ * means that the motion command is expected to determine where
+ * the cursor ends up!
+ */
+ if (F_ISSET(vp, V_MOTION)) {
+ flags = F_ISSET(vp, VM_RCM_MASK);
+ F_CLR(vp, VM_RCM_MASK);
+ if (getmotion(sp, ep, DOTMOTION, vp))
+ goto err;
+ if (F_ISSET(vp, VM_NOMOTION))
+ goto err;
+ if (!F_ISSET(vp, VM_RCM_MASK))
+ F_SET(vp, flags);
+ }
+
+ /*
+ * If a count is set and the command is line oriented, set the
+ * to MARK here relative to the cursor/from MARK. This is for
+ * commands that take both counts and motions, i.e. "4yy" and
+ * "y%". As there's no way the command can know which the user
+ * did, we have to do it here. (There are commands that are
+ * line oriented and that take counts ("#G", "#H"), for which
+ * this calculation is either completely meaningless or wrong.
+ * Each command must validate the value for itself.
+ */
+ if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
+ vp->m_stop.lno += vp->count - 1;
+
+ /* Increment the command count. */
+ ++sp->ccnt;
+
+ /* Save the mode and call the function. */
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+ if ((vp->kp->func)(sp, ep, vp))
+ goto err;
+#ifdef DEBUG
+ /* Make sure no function left the temporary space locked. */
+ if (F_ISSET(sp->gp, G_TMP_INUSE)) {
+ msgq(sp, M_ERR,
+ "Error: vi: temporary buffer not released.");
+ return (1);
+ }
+#endif
+ /*
+ * If that command took us out of vi or changed the screen,
+ * then exit the loop without further action.
+ */
+ if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
+ break;
+
+ /* Set the absolute mark. */
+ if (F_ISSET(vp, V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))
+ goto err;
+
+ /* Set the dot command structure. */
+ if (F_ISSET(vp, V_DOT)) {
+ *DOT = cmd;
+ F_SET(DOT, VC_ISDOT);
+ /*
+ * If a count was supplied for both the command and
+ * its motion, the count was used only for the motion.
+ * Turn the count back on for the dot structure.
+ */
+ if (F_ISSET(vp, VC_C1RESET))
+ F_SET(DOT, VC_C1SET);
+ }
+
+ /*
+ * Some vi row movements are "attracted" to the last position
+ * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
+ * commands' candle. It's broken into two parts. Here we deal
+ * with the command flags. In sp->relative(), we deal with the
+ * screen flags. If the movement is to the EOL the vi command
+ * handles it. If it's to the beginning, we handle it here.
+ *
+ * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
+ * flag, but do the work themselves. The reason is that they
+ * have to modify the column in case they're being used as a
+ * motion component. Other similar commands (e.g. +, -) don't
+ * have to modify the column because they are always line mode
+ * operations when used as motions, so the column number isn't
+ * of any interest.
+ *
+ * Does this totally violate the screen and editor layering?
+ * You betcha. As they say, if you think you understand it,
+ * you don't.
+ */
+ switch (F_ISSET(vp, VM_RCM_MASK)) {
+ case 0:
+ case VM_RCM_SET:
+ break;
+ case VM_RCM:
+ vp->m_final.cno = sp->s_rcm(sp, ep, vp->m_final.lno);
+ break;
+ case VM_RCM_SETLAST:
+ sp->rcmflags = RCM_LAST;
+ break;
+ case VM_RCM_SETLFNB:
+ /*
+ * If we changed lines, move to the first non-blank.
+ * This is the hack that makes logical scrolling on
+ * really long lines work.
+ */
+ if (vp->m_start.lno != vp->m_final.lno) {
+ vp->m_final.cno = 0;
+ if (nonblank(sp, ep,
+ vp->m_final.lno, &vp->m_final.cno))
+ goto err;
+ sp->rcmflags = RCM_FNB;
+ }
+ break;
+ case VM_RCM_SETFNB:
+ vp->m_final.cno = 0;
+ /* FALLTHROUGH */
+ case VM_RCM_SETNNB:
+ if (nonblank(sp, ep, vp->m_final.lno, &vp->m_final.cno))
+ goto err;
+ sp->rcmflags = RCM_FNB;
+ break;
+ default:
+ abort();
+ }
+
+ /* Update the cursor. */
+ sp->lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+
+ if (!MAPPED_KEYS_WAITING(sp)) {
+ (void)msg_rpt(sp, 1);
+
+ if (0)
+err: term_map_flush(sp, "Vi error");
+ }
+
+ /* Refresh the screen. */
+ if (sp->s_refresh(sp, ep)) {
+ eval = 1;
+ break;
+ }
+
+ /* Set the new favorite position. */
+ if (F_ISSET(vp, VM_RCM_SET)) {
+ sp->rcmflags = 0;
+ (void)sp->s_column(sp, ep, &sp->rcm);
+ }
+ }
+
+ return (v_end(sp) || eval);
+}
+
+#define KEY(key, map) { \
+ if (getkey(sp, &ikey, map)) \
+ return (1); \
+ key = ikey.ch; \
+}
+
+/*
+ * getcmd --
+ *
+ * The command structure for vi is less complex than ex (and don't think
+ * I'm not grateful!) The command syntax is:
+ *
+ * [count] [buffer] [count] key [[motion] | [buffer] [character]]
+ *
+ * and there are several special cases. The motion value is itself a vi
+ * command, with the syntax:
+ *
+ * [count] key [character]
+ */
+static int
+getcmd(sp, ep, dp, vp, ismotion, comcountp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *dp, *vp;
+ VICMDARG *ismotion; /* Previous key if getting motion component. */
+ int *comcountp;
+{
+ VIKEYS const *kp;
+ u_int flags;
+ CH ikey;
+ CHAR_T key;
+
+ /* Refresh the command structure. */
+ memset(&vp->vp_startzero, 0,
+ (char *)&vp->vp_endzero - (char *)&vp->vp_startzero);
+
+ /* An escape bells the user if in command mode. */
+ if (getkey(sp, &ikey, TXT_MAPCOMMAND)) {
+ if (ikey.value == K_ESCAPE && ismotion == NULL)
+ msgq(sp, M_BERR, "Already in command mode");
+ return (1);
+ }
+
+ key = ikey.ch;
+ if (key > MAXVIKEY) {
+ msgq(sp, M_BERR, "%s isn't a vi command", charname(sp, key));
+ return (1);
+ }
+
+ /* Pick up optional buffer. */
+ if (key == '"') {
+ KEY(vp->buffer, 0);
+ F_SET(vp, VC_BUFFER);
+ KEY(key, TXT_MAPCOMMAND);
+ }
+
+ /*
+ * Pick up optional count, where a leading 0 is not a count,
+ * it's a command.
+ */
+ if (isdigit(key) && key != '0') {
+ if (getcount(sp, key, &vp->count))
+ return (1);
+ F_SET(vp, VC_C1SET);
+ *comcountp = 1;
+ KEY(key, TXT_MAPCOMMAND);
+ } else
+ *comcountp = 0;
+
+ /* Pick up optional buffer. */
+ if (key == '"') {
+ if (F_ISSET(vp, VC_BUFFER)) {
+ msgq(sp, M_ERR, "Only one buffer can be specified.");
+ return (1);
+ }
+ KEY(vp->buffer, 0);
+ F_SET(vp, VC_BUFFER);
+ KEY(key, TXT_MAPCOMMAND);
+ }
+
+ /*
+ * Find the command. The only legal command with no underlying
+ * function is dot.
+ */
+ kp = vp->kp = &vikeys[vp->key = key];
+ if (kp->func == NULL) {
+ if (key != '.') {
+ msgq(sp, M_ERR,
+ "%s isn't a command", charname(sp, key));
+ return (1);
+ }
+
+ /* If called for a motion command, stop now. */
+ if (dp == NULL)
+ goto usage;
+
+ /* A repeatable command must have been executed. */
+ if (!F_ISSET(dp, VC_ISDOT)) {
+ msgq(sp, M_ERR, "No command to repeat.");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * If a '.' is immediately entered after an undo command, we
+ * replay the log instead of redoing the last command. This
+ * is necessary because 'u' can't set the dot command -- see
+ * vi/v_undo.c:v_undo for details.
+ */
+ if (VIP(sp)->u_ccnt == sp->ccnt) {
+ vp->kp = &vikeys['u'];
+ F_SET(vp, VC_ISDOT);
+ return (0);
+ }
+
+ /* Set new count/buffer, if any, and return. */
+ if (F_ISSET(vp, VC_C1SET)) {
+ F_SET(dp, VC_C1SET);
+ dp->count = vp->count;
+ }
+ if (F_ISSET(vp, VC_BUFFER))
+ dp->buffer = vp->buffer;
+ *vp = *dp;
+ return (0);
+ }
+
+ flags = kp->flags;
+
+ /* Check for illegal count. */
+ if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
+ goto usage;
+
+ /* Illegal motion command. */
+ if (ismotion == NULL) {
+ /* Illegal buffer. */
+ if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
+ goto usage;
+
+ /* Required buffer. */
+ if (LF_ISSET(V_RBUF))
+ KEY(vp->buffer, 0);
+ }
+
+ /*
+ * Special case: '[', ']' and 'Z' commands. Doesn't the fact that
+ * the *single* characters don't mean anything but the *doubled*
+ * characters do just frost your shorts?
+ */
+ if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
+ KEY(key, TXT_MAPCOMMAND);
+ if (vp->key != key) {
+usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
+ vikeys[ismotion->key].usage : kp->usage);
+ return (1);
+ }
+ }
+ /* Special case: 'z' command. */
+ if (vp->key == 'z') {
+ KEY(vp->character, 0);
+ if (isdigit(vp->character)) {
+ if (getcount(sp, vp->character, &vp->count2))
+ return (1);
+ F_SET(vp, VC_C2SET);
+ KEY(vp->character, 0);
+ }
+ }
+
+ /*
+ * Commands that have motion components can be doubled to
+ * imply the current line.
+ */
+ if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
+ msgq(sp, M_ERR, "%s may not be used as a motion command.",
+ charname(sp, key));
+ return (1);
+ }
+
+ /* Required character. */
+ if (LF_ISSET(V_CHAR))
+ KEY(vp->character, 0);
+
+ return (0);
+}
+
+/*
+ * getmotion --
+ *
+ * Get resulting motion mark.
+ */
+static int
+getmotion(sp, ep, dm, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *dm, *vp;
+{
+ MARK m;
+ VICMDARG motion;
+ size_t len;
+ u_long cnt;
+ int notused;
+
+ /* If '.' command, use the dot motion, else get the motion command. */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ motion = *dm;
+ F_SET(&motion, VC_ISDOT);
+ } else if (getcmd(sp, ep, NULL, &motion, vp, &notused))
+ return (1);
+
+ /*
+ * A count may be provided both to the command and to the motion, in
+ * which case the count is multiplicative. For example, "3y4y" is the
+ * same as "12yy". This count is provided to the motion command and
+ * not to the regular function.
+ */
+ cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
+ if (F_ISSET(vp, VC_C1SET)) {
+ motion.count *= vp->count;
+ F_SET(&motion, VC_C1SET);
+
+ /*
+ * Set flags to restore the original values of the command
+ * structure so dot commands can change the count values,
+ * e.g. "2dw" "3." deletes a total of five words.
+ */
+ F_CLR(vp, VC_C1SET);
+ F_SET(vp, VC_C1RESET);
+ }
+
+ /*
+ * Some commands can be repeated to indicate the current line. In
+ * this case, or if the command is a "line command", set the flags
+ * appropriately. If not a doubled command, run the function to get
+ * the resulting mark.
+ */
+ if (vp->key == motion.key) {
+ F_SET(vp, VM_LMODE);
+
+ /* Set the origin of the command. */
+ vp->m_start.lno = sp->lno;
+ vp->m_start.cno = 0;
+
+ /*
+ * Set the end of the command.
+ *
+ * If the current line is missing, i.e. the file is empty,
+ * historic vi permitted a "cc" or "!!" command to insert
+ * text.
+ */
+ vp->m_stop.lno = sp->lno + motion.count - 1;
+ if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
+ if (vp->m_stop.lno != 1 ||
+ vp->key != 'c' && vp->key != '!') {
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ v_eof(sp, ep, &m);
+ return (1);
+ }
+ vp->m_stop.cno = 0;
+ } else
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else {
+ /*
+ * Motion commands change the underlying movement (*snarl*).
+ * For example, "l" is illegal at the end of a line, but "dl"
+ * is not. Set flags so the function knows the situation.
+ */
+ F_SET(&motion, vp->kp->flags & VC_COMMASK);
+
+ /* Copy the key flags into the local structure. */
+ F_SET(&motion, motion.kp->flags);
+
+ /*
+ * Set the three cursor locations to the current cursor. This
+ * permits commands like 'j' and 'k', that are line oriented
+ * motions and have special cursor suck semantics when they are
+ * used as standalone commands, to ignore column positioning.
+ */
+ motion.m_final.lno =
+ motion.m_stop.lno = motion.m_start.lno = sp->lno;
+ motion.m_final.cno =
+ motion.m_stop.cno = motion.m_start.cno = sp->cno;
+
+ /* Run the function. */
+ if ((motion.kp->func)(sp, ep, &motion))
+ return (1);
+
+ /*
+ * Copy line mode and cursor position information from the
+ * motion command structure. The commands can flag the
+ * movement as a line motion (see v_sentence) as well as set
+ * the VM_RCM_* flags explicitly.
+ */
+ F_SET(vp,
+ F_ISSET(&motion, VM_LMODE | VM_NOMOTION | VM_RCM_MASK));
+
+ /*
+ * Motion commands can reset all of the cursor information.
+ * If the motion is in the reverse direction, switch the
+ * from and to MARK's so that it's in a forward direction.
+ * Motions are from the from MARK to the to MARK (inclusive).
+ */
+ if (motion.m_start.lno > motion.m_stop.lno ||
+ motion.m_start.lno == motion.m_stop.lno &&
+ motion.m_start.cno > motion.m_stop.cno) {
+ vp->m_start = motion.m_stop;
+ vp->m_stop = motion.m_start;
+ } else {
+ vp->m_start = motion.m_start;
+ vp->m_stop = motion.m_stop;
+ }
+ vp->m_final = motion.m_final;
+ }
+
+ /*
+ * If the command sets dot, save the motion structure. The motion
+ * count was changed above and needs to be reset, that's why this
+ * is done here, and not in the calling routine.
+ */
+ if (F_ISSET(vp->kp, V_DOT)) {
+ *dm = motion;
+ dm->count = cnt;
+ }
+ return (0);
+}
+
+#define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c))
+
+/*
+ * getkeyword --
+ * Get the "word" the cursor is on.
+ */
+static int
+getkeyword(sp, ep, kp, flags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *kp;
+ u_int flags;
+{
+ recno_t lno;
+ size_t beg, end, len;
+ char *p;
+
+ if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ v_eof(sp, ep, NULL);
+ else
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+ beg = sp->cno;
+
+ /* May not be a keyword at all. */
+ if (p == NULL || len == 0 ||
+ LF_ISSET(V_KEYW) && !inword(p[beg]) ||
+ LF_ISSET(V_KEYNUM) && !innum(p[beg]) &&
+ p[beg] != '-' && p[beg] != '+') {
+noword: msgq(sp, M_BERR, "Cursor not in a %s",
+ LF_ISSET(V_KEYW) ? "word" : "number");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Find the beginning/end of the keyword. Keywords (V_KEYW) are
+ * used for cursor-word searching and for tags. Historical vi
+ * only used the word in a tag search from the cursor to the end
+ * of the word, i.e. if the cursor was on the 'b' in " abc ", the
+ * tag was "bc". For no particular reason, we make cursor word
+ * searches follow the same rule.
+ */
+ if (beg != 0)
+ if (LF_ISSET(V_KEYW)) {
+#ifdef MOVE_TO_KEYWORD_BEGINNING
+ for (;;) {
+ --beg;
+ if (!inword(p[beg])) {
+ ++beg;
+ break;
+ }
+ if (beg == 0)
+ break;
+ }
+#endif
+ } else {
+ for (;;) {
+ --beg;
+ if (!innum(p[beg])) {
+ if (beg > 0 && p[beg - 1] == '0' &&
+ (p[beg] == 'X' || p[beg] == 'x'))
+ --beg;
+ else
+ ++beg;
+ break;
+ }
+ if (beg == 0)
+ break;
+ }
+
+ /* Skip possible leading sign. */
+ if (beg != 0 && p[beg] != '0' &&
+ (p[beg - 1] == '+' || p[beg - 1] == '-'))
+ --beg;
+ }
+
+ if (LF_ISSET(V_KEYW)) {
+ for (end = sp->cno; ++end < len && inword(p[end]););
+ --end;
+ } else {
+ for (end = sp->cno; ++end < len;) {
+ if (p[end] == 'X' || p[end] == 'x') {
+ if (end != beg + 1 || p[beg] != '0')
+ break;
+ continue;
+ }
+ if (!innum(p[end]))
+ break;
+ }
+
+ /* Just a sign isn't a number. */
+ if (end == beg && (p[beg] == '+' || p[beg] == '-'))
+ goto noword;
+ --end;
+ }
+
+ /*
+ * Getting a keyword implies moving the cursor to its beginning.
+ * Refresh now.
+ */
+ if (beg != sp->cno) {
+ sp->cno = beg;
+ sp->s_refresh(sp, ep);
+ }
+
+ /*
+ * XXX
+ * 8-bit clean problem. Numeric keywords are handled using strtol(3)
+ * and friends. This would have to be fixed in v_increment and here
+ * to not depend on a trailing NULL.
+ */
+ len = (end - beg) + 2; /* XXX */
+ kp->klen = (end - beg) + 1;
+ BINC_RET(sp, kp->keyword, kp->kbuflen, len);
+ memmove(kp->keyword, p + beg, kp->klen);
+ kp->keyword[kp->klen] = '\0'; /* XXX */
+ return (0);
+}
+
+/*
+ * getcount --
+ * Return the next count.
+ */
+static inline int
+getcount(sp, fkey, countp)
+ SCR *sp;
+ ARG_CHAR_T fkey;
+ u_long *countp;
+{
+ u_long count, tc;
+ CH ikey;
+
+ ikey.ch = fkey;
+ count = tc = 0;
+ do {
+ /* Assume that overflow results in a smaller number. */
+ tc = count * 10 + ikey.ch - '0';
+ if (count > tc) {
+ /* Toss to the next non-digit. */
+ do {
+ if (getkey(sp, &ikey,
+ TXT_MAPCOMMAND | TXT_MAPNODIGIT))
+ return (1);
+ } while (isdigit(ikey.ch));
+ msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX);
+ return (1);
+ }
+ count = tc;
+ if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT))
+ return (1);
+ } while (isdigit(ikey.ch));
+ *countp = count;
+ return (0);
+}
+
+/*
+ * getkey --
+ * Return the next key.
+ */
+static inline int
+getkey(sp, ikeyp, map)
+ SCR *sp;
+ CH *ikeyp;
+ u_int map;
+{
+ switch (term_key(sp, ikeyp, map)) {
+ case INP_OK:
+ break;
+ case INP_EOF:
+ case INP_ERR:
+ F_SET(sp, S_EXIT_FORCE);
+ return (1);
+ }
+ return (ikeyp->value == K_ESCAPE);
+}
diff --git a/usr.bin/vi/xaw/xaw_screen.c b/usr.bin/vi/xaw/xaw_screen.c
index ec76a0668cf9..c7660837d706 100644
--- a/usr.bin/vi/xaw/xaw_screen.c
+++ b/usr.bin/vi/xaw/xaw_screen.c
@@ -1,6 +1,6 @@
/*-
- * Copyright (c) 1993 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1993, 1994
+ * 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
@@ -32,9 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)xaw_screen.c 8.4 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)xaw_screen.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
/*
diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c
index c24b88502b05..9fbc2e53f608 100644
--- a/usr.bin/w/w.c
+++ b/usr.bin/w/w.c
@@ -179,6 +179,11 @@ main(argc, argv)
*nextp = ep;
nextp = &(ep->next);
bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
+ if (!strncmp(ep->utmp.ut_line, "uu", 2)) {
+ ep->idle = 0;
+ ep->tdev = -1;
+ continue;
+ }
stp = ttystat(ep->utmp.ut_line);
ep->tdev = stp->st_rdev;
#if defined(hp300) || defined(i386)
@@ -319,7 +324,8 @@ main(argc, argv)
for (ep = ehead; ep != NULL; ep = ep->next) {
printf("%-*.*s %-2.2s %-*.*s %s",
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
- strncmp(ep->utmp.ut_line, "tty", 3) == 0 ?
+ strncmp(ep->utmp.ut_line, "tty", 3) == 0 ||
+ strncmp(ep->utmp.ut_line, "cua", 3) == 0 ?
ep->utmp.ut_line+3 : ep->utmp.ut_line,
UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ?
ep->utmp.ut_host : "-",
diff --git a/usr.bin/wall/wall.c b/usr.bin/wall/wall.c
index 503560c15215..52e18211db07 100644
--- a/usr.bin/wall/wall.c
+++ b/usr.bin/wall/wall.c
@@ -103,7 +103,8 @@ usage:
/* NOSTRICT */
while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) {
if (!utmp.ut_name[0] ||
- !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name)))
+ !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name)) ||
+ !strncmp(utmp.ut_line, "uu", 2))
continue;
if (p = ttymsg(&iov, 1, utmp.ut_line))
(void)fprintf(stderr, "wall: %s\n", p);
diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c
index 1b9658e5a5ba..2480b48a1a31 100644
--- a/usr.bin/wc/wc.c
+++ b/usr.bin/wc/wc.c
@@ -39,7 +39,7 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)wc.c 5.7 (Berkeley) 3/2/91";*/
-static char rcsid[] = "$Id: wc.c,v 1.2.2.1 1994/03/07 01:39:22 rgrimes Exp $";
+static char rcsid[] = "$Id: wc.c,v 1.3 1994/02/25 22:24:42 phk Exp $";
#endif /* not lint */
/* wc line, word and char count */
diff --git a/usr.bin/whereis/whereis.c b/usr.bin/whereis/whereis.c
index 82c084462801..68a69cf2ae11 100644
--- a/usr.bin/whereis/whereis.c
+++ b/usr.bin/whereis/whereis.c
@@ -54,6 +54,7 @@ static char *bindirs[] = {
"/usr/gnu/bin",
"/usr/include",
"/usr/libexec",
+ "/usr/libexec/uucp",
"/usr/sbin",
"/usr/share",
"/usr/X386/bin",
@@ -113,6 +114,7 @@ static char *srcdirs[] = {
"/usr/src/games",
"/usr/src/gnu/lib",
"/usr/src/gnu/libexec",
+ "/usr/src/gnu/libexec/uucp",
"/usr/src/gnu/usr.bin",
"/usr/src/include",
"/usr/src/lib",
diff --git a/usr.bin/yacc/yacc.1 b/usr.bin/yacc/yacc.1
index 742633d59589..b135f3da7f49 100644
--- a/usr.bin/yacc/yacc.1
+++ b/usr.bin/yacc/yacc.1
@@ -44,13 +44,13 @@ If the
.B -l
option is not specified,
.I yacc
-will insert \#line directives in the generated code.
-The \#line directives let the C compiler relate errors in the
+will insert #line directives in the generated code.
+The #line directives let the C compiler relate errors in the
generated code to the user's original code.
If the \fB-l\fR option is specified,
.I yacc
-will not insert the \#line directives.
-\&\#line directives specified by the user will be retained.
+will not insert the #line directives.
+\&#line directives specified by the user will be retained.
.TP
\fB-p \fIsymbol_prefix\fR
The
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index c625fea95cad..e189ba5ccfaa 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,10 +1,11 @@
# @(#)Makefile 5.6.1.2 (Berkeley) 5/8/91
-SUBDIR= accton arp chown chroot config cron dbsym dev_mkdb diskpart \
- edquota fdformat flcopy ftinfo gettable htable inetd iostat kgmon \
- kvm_mkdb lpr mtree named portmap pppstats pwd_mkdb quotaon repquota \
- rmt rwhod sendmail sliplogin spkrtest swapinfo syslogd timed \
- traceroute trpt trsp vipw yp
+SUBDIR= XNSrouted ac accton arp chown chroot config cron dbsym dev_mkdb \
+ diskpart edquota fdcontrol fdformat ftinfo gettable htable \
+ inetd iostat kbdcontrol kgmon kvm_mkdb lpr lptcontrol mrouted \
+ mtree named portmap pppstats pwd_mkdb quotaon repquota rmt \
+ routed rwhod sa sendmail sliplogin slstat spkrtest swapinfo \
+ syslogd timed traceroute trpt trsp vidcontrol vipw xten yp
.if make(clean) || make(cleandir)
SUBDIR+=bad144
diff --git a/sbin/XNSrouted/Makefile b/usr.sbin/XNSrouted/Makefile
index 9f6583f8ee56..9f6583f8ee56 100644
--- a/sbin/XNSrouted/Makefile
+++ b/usr.sbin/XNSrouted/Makefile
diff --git a/sbin/XNSrouted/XNSrouted.8 b/usr.sbin/XNSrouted/XNSrouted.8
index 144cb1d40453..144cb1d40453 100644
--- a/sbin/XNSrouted/XNSrouted.8
+++ b/usr.sbin/XNSrouted/XNSrouted.8
diff --git a/sbin/XNSrouted/af.c b/usr.sbin/XNSrouted/af.c
index d131e8773992..d131e8773992 100644
--- a/sbin/XNSrouted/af.c
+++ b/usr.sbin/XNSrouted/af.c
diff --git a/sbin/XNSrouted/af.h b/usr.sbin/XNSrouted/af.h
index d2b27c531380..d2b27c531380 100644
--- a/sbin/XNSrouted/af.h
+++ b/usr.sbin/XNSrouted/af.h
diff --git a/sbin/XNSrouted/defs.h b/usr.sbin/XNSrouted/defs.h
index 5414d8c08ca3..5414d8c08ca3 100644
--- a/sbin/XNSrouted/defs.h
+++ b/usr.sbin/XNSrouted/defs.h
diff --git a/sbin/XNSrouted/if.c b/usr.sbin/XNSrouted/if.c
index 0f597a66fac3..0f597a66fac3 100644
--- a/sbin/XNSrouted/if.c
+++ b/usr.sbin/XNSrouted/if.c
diff --git a/sbin/XNSrouted/input.c b/usr.sbin/XNSrouted/input.c
index 7dc64fa5cc9c..7dc64fa5cc9c 100644
--- a/sbin/XNSrouted/input.c
+++ b/usr.sbin/XNSrouted/input.c
diff --git a/sbin/XNSrouted/interface.h b/usr.sbin/XNSrouted/interface.h
index 7cb416699a1b..7cb416699a1b 100644
--- a/sbin/XNSrouted/interface.h
+++ b/usr.sbin/XNSrouted/interface.h
diff --git a/sbin/XNSrouted/main.c b/usr.sbin/XNSrouted/main.c
index f4ddf285839c..f4ddf285839c 100644
--- a/sbin/XNSrouted/main.c
+++ b/usr.sbin/XNSrouted/main.c
diff --git a/sbin/XNSrouted/output.c b/usr.sbin/XNSrouted/output.c
index cdea11f2b73f..cdea11f2b73f 100644
--- a/sbin/XNSrouted/output.c
+++ b/usr.sbin/XNSrouted/output.c
diff --git a/sbin/XNSrouted/protocol.h b/usr.sbin/XNSrouted/protocol.h
index 9bf422b60625..9bf422b60625 100644
--- a/sbin/XNSrouted/protocol.h
+++ b/usr.sbin/XNSrouted/protocol.h
diff --git a/sbin/XNSrouted/startup.c b/usr.sbin/XNSrouted/startup.c
index 8887c1fc474a..8887c1fc474a 100644
--- a/sbin/XNSrouted/startup.c
+++ b/usr.sbin/XNSrouted/startup.c
diff --git a/sbin/XNSrouted/table.h b/usr.sbin/XNSrouted/table.h
index 159dc4e64252..159dc4e64252 100644
--- a/sbin/XNSrouted/table.h
+++ b/usr.sbin/XNSrouted/table.h
diff --git a/sbin/XNSrouted/tables.c b/usr.sbin/XNSrouted/tables.c
index 38ce4386fe25..38ce4386fe25 100644
--- a/sbin/XNSrouted/tables.c
+++ b/usr.sbin/XNSrouted/tables.c
diff --git a/sbin/XNSrouted/timer.c b/usr.sbin/XNSrouted/timer.c
index f420bc074e00..f420bc074e00 100644
--- a/sbin/XNSrouted/timer.c
+++ b/usr.sbin/XNSrouted/timer.c
diff --git a/sbin/XNSrouted/tools/query.c b/usr.sbin/XNSrouted/tools/query.c
index 2e6374d1f63f..2e6374d1f63f 100644
--- a/sbin/XNSrouted/tools/query.c
+++ b/usr.sbin/XNSrouted/tools/query.c
diff --git a/sbin/XNSrouted/trace.c b/usr.sbin/XNSrouted/trace.c
index 51728733a387..51728733a387 100644
--- a/sbin/XNSrouted/trace.c
+++ b/usr.sbin/XNSrouted/trace.c
diff --git a/sbin/XNSrouted/trace.h b/usr.sbin/XNSrouted/trace.h
index be48553d6c13..be48553d6c13 100644
--- a/sbin/XNSrouted/trace.h
+++ b/usr.sbin/XNSrouted/trace.h
diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile
new file mode 100644
index 000000000000..349e9ce83e78
--- /dev/null
+++ b/usr.sbin/ac/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.1.1.1 1994/05/18 08:00:44 csgr Exp $
+
+PROG= ac
+MAN8= ac.8
+
+# If "CONSOLE_TTY" is not defined, this program is compatible with the
+# traditional implementation (using SunOS 4.x as the sample traditional
+# implementation). This is the default.
+#
+# If "CONSOLE_TTY" is defined, it must be defined to the appropriate
+# console name, e.g. "vga". Additionally, the various commented-out
+# sections of the man page should be uncommented. This is not the
+# default because of the inability to detect the proper console name
+# easily, especially on m68k systems, which can share binaries.
+#
+#CFLAGS+=-DCONSOLE_TTY=\"vga\"
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8
new file mode 100644
index 000000000000..86f05bb51279
--- /dev/null
+++ b/usr.sbin/ac/ac.8
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) 1994 Simon J. Gerraty
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $Id: ac.8,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $
+.\"
+.Dd March 15, 1994
+.Dt AC 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm ac
+.Nd connect time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl dp
+.\".Op Fl c Ar console
+.Op Fl t Ar tty
+.Op Fl w Ar wtmp
+.Op Ar users ...
+.Sh DESCRIPTION
+If the file
+.Pa /var/log/wtmp
+exists, a record of individual login and logout
+times are written to it by
+.Xr login 8
+and
+.Xr init 8 ,
+respectively.
+.Nm \&Ac
+examines these records and writes the accumulated connect time
+for all logins to the standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width indentXXX
+.It Fl d
+Display the connect times in 24 hour chunks.
+.\" .It Fl c Ar console
+.\" Use
+.\" .Ar console
+.\" as the name of the device that local X sessions (ut_host of ":0.0")
+.\" originate from. If any login has been recorded on
+.\" .Ar console
+.\" then these X sessions are ignored unless COMPAT_SUNOS was defined at
+.\" compile time.
+.It Fl p
+Print individual users' totals.
+.It Fl t Ar tty
+Only do accounting logins on certain ttys. The
+.Ar tty
+specification can start with '!' to indicate not this
+.Ar tty
+and end with '*' to indicate all similarly named ttys.
+Multiple
+.Fl t
+flags may be specified.
+.It Fl w Ar wtmp
+Read connect time data from
+.Ar wtmp
+instead of the default file,
+.Pa /var/log/wtmp .
+.It Ar users ...
+Display totals for the given individuals only.
+.El
+.Pp
+If no arguments are given,
+.Nm ac
+displays the total connect time for all
+accounts with login sessions recorded in
+.Pa wtmp .
+.Pp
+The default
+.Pa wtmp
+file will increase without bound unless it is truncated.
+It is normally truncated by the daily scripts run
+by
+.Xr cron 8 ,
+which rename and rotate the
+.Pa wtmp
+files, keeping a week's worth of data on
+hand. No login or connect time accounting is performed if
+.Pa /var/log/wtmp
+does not exist.
+.Pp
+For example,
+.Bd -literal -offset
+ac -p -t "ttyd*" > modems
+ac -p -t "!ttyd*" > other
+.Ed
+.Pp
+allows times recorded in
+.Pa modems
+to be charged out at a different rate than
+.Pa other .
+.Pp
+The
+.Nm ac
+utility exits 0 on success, and >0 if a fatal error occurs.
+.Sh FILES
+.Bl -tag -width /var/log/wtmp.[0-7] -compact
+.It Pa /var/log/wtmp
+connect time accounting file
+.It Pa /var/log/wtmp.[0-7]
+rotated files
+.El
+.Sh SEE ALSO
+.Xr init 8 ,
+.Xr sa 8 ,
+.Xr login 1 ,
+.Xr utmp
+.Sh HISTORY
+An
+.Nm ac
+command appeard in
+.At v6 .
+This version of
+.Nm ac
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+.\" .Sh NOTES
+.\" If COMPAT_SUNOS is defined
+.\" .Nm ac
+.\" ignores the fact that entries with ut_host of ":0.0" are not real
+.\" login sessions. Normally such entries are ignored except in the case
+.\" of a user being logged in when the
+.\" .Pa wtmp
+.\" file was rotated, in which case a login with ut_host of ":0.0" may
+.\" appear without any preceeding console logins.
+.\" If no one is logged in on the console, the user is deemed to have
+.\" logged in on at the earliest time stamp found in
+.\" .Pa wtmp .
+.\" Use of
+.\" .Pa console
+.\" allows
+.\" .Nm ac
+.\" to identify and correcty process a logout for the user. The default
+.\" value for
+.\" .Pa console
+.\" is usually correct at compile time.
diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c
new file mode 100644
index 000000000000..2d6831511217
--- /dev/null
+++ b/usr.sbin/ac/ac.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou.
+ * @(#)Copyright (c) 1994, Simon J. Gerraty.
+ *
+ * This is free software. It comes with NO WARRANTY.
+ * Permission to use, modify and distribute this source code
+ * is granted subject to the following conditions.
+ * 1/ that the above copyright notice and this notice
+ * are preserved in all copies and that due credit be given
+ * to the author.
+ * 2/ that any changes to this code are clearly commented
+ * as such so that the author does not get blamed for bugs
+ * other than his own.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ac.c,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <unistd.h>
+
+/*
+ * this is for our list of currently logged in sessions
+ */
+struct utmp_list {
+ struct utmp_list *next;
+ struct utmp usr;
+};
+
+/*
+ * this is for our list of users that are accumulating time.
+ */
+struct user_list {
+ struct user_list *next;
+ char name[UT_NAMESIZE+1];
+ time_t secs;
+};
+
+/*
+ * this is for chosing whether to ignore a login
+ */
+struct tty_list {
+ struct tty_list *next;
+ char name[UT_LINESIZE+3];
+ int len;
+ int ret;
+};
+
+/*
+ * globals - yes yuk
+ */
+#ifdef CONSOLE_TTY
+static char *Console = CONSOLE_TTY;
+#endif
+static time_t Total = 0;
+static time_t FirstTime = 0;
+static int Flags = 0;
+static struct user_list *Users = NULL;
+static struct tty_list *Ttys = NULL;
+
+#define NEW(type) (type *)malloc(sizeof (type))
+
+#define AC_W 1 /* not _PATH_WTMP */
+#define AC_D 2 /* daily totals (ignore -p) */
+#define AC_P 4 /* per-user totals */
+#define AC_U 8 /* specified users only */
+#define AC_T 16 /* specified ttys only */
+
+#ifdef DEBUG
+static int Debug = 0;
+#endif
+
+int main __P((int, char **));
+int ac __P((FILE *));
+struct tty_list *add_tty __P((char *));
+int do_tty __P((char *));
+FILE *file __P((char *));
+struct utmp_list *log_in __P((struct utmp_list *, struct utmp *));
+struct utmp_list *log_out __P((struct utmp_list *, struct utmp *));
+int on_console __P((struct utmp_list *));
+void show __P((char *, time_t));
+void show_today __P((struct user_list *, struct utmp_list *,
+ time_t));
+void show_users __P((struct user_list *));
+struct user_list *update_user __P((struct user_list *, char *, time_t));
+void usage __P((void));
+
+/*
+ * open wtmp or die
+ */
+FILE *
+file(name)
+ char *name;
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "%s", name);
+ /* in case we want to discriminate */
+ if (strcmp(_PATH_WTMP, name))
+ Flags |= AC_W;
+ return fp;
+}
+
+struct tty_list *
+add_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ register char *rcp;
+
+ Flags |= AC_T;
+
+ if ((tp = NEW(struct tty_list)) == NULL)
+ err(1, "malloc");
+ tp->len = 0; /* full match */
+ tp->ret = 1; /* do if match */
+ if (*name == '!') { /* don't do if match */
+ tp->ret = 0;
+ name++;
+ }
+ (void)strncpy(tp->name, name, sizeof (tp->name) - 1);
+ tp->name[sizeof (tp->name) - 1] = '\0';
+ if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */
+ *rcp = '\0';
+ tp->len = strlen(tp->name); /* match len bytes only */
+ }
+ tp->next = Ttys;
+ Ttys = tp;
+ return Ttys;
+}
+
+/*
+ * should we process the named tty?
+ */
+int
+do_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ int def_ret = 0;
+
+ for (tp = Ttys; tp != NULL; tp = tp->next) {
+ if (tp->ret == 0) /* specific don't */
+ def_ret = 1; /* default do */
+ if (tp->len != 0) {
+ if (strncmp(name, tp->name, tp->len) == 0)
+ return tp->ret;
+ } else {
+ if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
+ return tp->ret;
+ }
+ }
+ return def_ret;
+}
+
+#ifdef CONSOLE_TTY
+/*
+ * is someone logged in on Console?
+ */
+int
+on_console(head)
+ struct utmp_list *head;
+{
+ struct utmp_list *up;
+
+ for (up = head; up; up = up->next) {
+ if (strncmp(up->usr.ut_line, Console,
+ sizeof (up->usr.ut_line)) == 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * update user's login time
+ */
+struct user_list *
+update_user(head, name, secs)
+ struct user_list *head;
+ char *name;
+ time_t secs;
+{
+ struct user_list *up;
+
+ for (up = head; up != NULL; up = up->next) {
+ if (strncmp(up->name, name, sizeof (up->name)) == 0) {
+ up->secs += secs;
+ Total += secs;
+ return head;
+ }
+ }
+ /*
+ * not found so add new user unless specified users only
+ */
+ if (Flags & AC_U)
+ return head;
+
+ if ((up = NEW(struct user_list)) == NULL)
+ err(1, "malloc");
+ up->next = head;
+ (void)strncpy(up->name, name, sizeof (up->name) - 1);
+ up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */
+ up->secs = secs;
+ Total += secs;
+ return up;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ int c;
+
+ fp = NULL;
+ while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'D':
+ Debug++;
+ break;
+#endif
+ case 'c':
+#ifdef CONSOLE_TTY
+ Console = optarg;
+#else
+ usage(); /* XXX */
+#endif
+ break;
+ case 'd':
+ Flags |= AC_D;
+ break;
+ case 'p':
+ Flags |= AC_P;
+ break;
+ case 't': /* only do specified ttys */
+ add_tty(optarg);
+ break;
+ case 'w':
+ fp = file(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc) {
+ /*
+ * initialize user list
+ */
+ for (; optind < argc; optind++) {
+ Users = update_user(Users, argv[optind], 0L);
+ }
+ Flags |= AC_U; /* freeze user list */
+ }
+ if (Flags & AC_D)
+ Flags &= ~AC_P;
+ if (fp == NULL) {
+ /*
+ * if _PATH_WTMP does not exist, exit quietly
+ */
+ if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT)
+ return 0;
+
+ fp = file(_PATH_WTMP);
+ }
+ ac(fp);
+
+ return 0;
+}
+
+/*
+ * print login time in decimal hours
+ */
+void
+show(name, secs)
+ char *name;
+ time_t secs;
+{
+ (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
+ ((double)secs / 3600));
+}
+
+void
+show_users(list)
+ struct user_list *list;
+{
+ struct user_list *lp;
+
+ for (lp = list; lp; lp = lp->next)
+ show(lp->name, lp->secs);
+}
+
+/*
+ * print total login time for 24hr period in decimal hours
+ */
+void
+show_today(users, logins, secs)
+ struct user_list *users;
+ struct utmp_list *logins;
+ time_t secs;
+{
+ struct user_list *up;
+ struct utmp_list *lp;
+ char date[64];
+ time_t yesterday = secs - 1;
+
+ (void)strftime(date, sizeof (date), "%b %e total",
+ localtime(&yesterday));
+
+ /* restore the missing second */
+ yesterday++;
+
+ for (lp = logins; lp != NULL; lp = lp->next) {
+ secs = yesterday - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+ lp->usr.ut_time = yesterday; /* as if they just logged in */
+ }
+ secs = 0;
+ for (up = users; up != NULL; up = up->next) {
+ secs += up->secs;
+ up->secs = 0; /* for next day */
+ }
+ if (secs)
+ (void)printf("%s %11.2f\n", date, ((double)secs / 3600));
+}
+
+/*
+ * log a user out and update their times.
+ * if ut_line is "~", we log all users out as the system has
+ * been shut down.
+ */
+struct utmp_list *
+log_out(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp, *lp2, *tlp;
+ time_t secs;
+
+ for (lp = head, lp2 = NULL; lp != NULL; )
+ if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line,
+ sizeof (up->ut_line)) == 0) {
+ secs = up->ut_time - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+#ifdef DEBUG
+ if (Debug)
+ printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
+ 19, ctime(&up->ut_time),
+ sizeof (lp->usr.ut_line), lp->usr.ut_line,
+ sizeof (lp->usr.ut_name), lp->usr.ut_name,
+ secs / 3600, (secs % 3600) / 60, secs % 60);
+#endif
+ /*
+ * now lose it
+ */
+ tlp = lp;
+ lp = lp->next;
+ if (tlp == head)
+ head = lp;
+ else if (lp2 != NULL)
+ lp2->next = lp;
+ free(tlp);
+ } else {
+ lp2 = lp;
+ lp = lp->next;
+ }
+ return head;
+}
+
+
+/*
+ * if do_tty says ok, login a user
+ */
+struct utmp_list *
+log_in(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp;
+
+ /*
+ * this could be a login. if we're not dealing with
+ * the console name, say it is.
+ *
+ * If we are, and if ut_host==":0.0" we know that it
+ * isn't a real login. _But_ if we have not yet recorded
+ * someone being logged in on Console - due to the wtmp
+ * file starting after they logged in, we'll pretend they
+ * logged in, at the start of the wtmp file.
+ */
+
+#ifdef CONSOLE_TTY
+ if (up->ut_host[0] == ':') {
+ /*
+ * SunOS 4.0.2 does not treat ":0.0" as special but we
+ * do.
+ */
+ if (on_console(head))
+ return head;
+ /*
+ * ok, no recorded login, so they were here when wtmp
+ * started! Adjust ut_time!
+ */
+ up->ut_time = FirstTime;
+ /*
+ * this allows us to pick the right logout
+ */
+ (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1);
+ up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */
+ }
+#endif
+ /*
+ * If we are doing specified ttys only, we ignore
+ * anything else.
+ */
+ if (Flags & AC_T)
+ if (!do_tty(up->ut_line))
+ return head;
+
+ /*
+ * go ahead and log them in
+ */
+ if ((lp = NEW(struct utmp_list)) == NULL)
+ err(1, "malloc");
+ lp->next = head;
+ head = lp;
+ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp));
+#ifdef DEBUG
+ if (Debug) {
+ printf("%-.*s %-.*s: %-.*s logged in", 19,
+ ctime(&lp->usr.ut_time), sizeof (up->ut_line),
+ up->ut_line, sizeof (up->ut_name), up->ut_name);
+ if (*up->ut_host)
+ printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host);
+ putchar('\n');
+ }
+#endif
+ return head;
+}
+
+int
+ac(fp)
+ FILE *fp;
+{
+ struct utmp_list *lp, *head = NULL;
+ struct utmp usr;
+ struct tm *ltm;
+ time_t secs;
+ int day = -1;
+
+ while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) {
+ if (!FirstTime)
+ FirstTime = usr.ut_time;
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ day = ltm->tm_yday;
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ } else
+ day = ltm->tm_yday;
+ }
+ switch(*usr.ut_line) {
+ case '|':
+ secs = usr.ut_time;
+ break;
+ case '{':
+ secs -= usr.ut_time;
+ /*
+ * adjust time for those logged in
+ */
+ for (lp = head; lp != NULL; lp = lp->next)
+ lp->usr.ut_time -= secs;
+ break;
+ case '~': /* reboot or shutdown */
+ head = log_out(head, &usr);
+ FirstTime = usr.ut_time; /* shouldn't be needed */
+ break;
+ default:
+ /*
+ * if they came in on tty[p-y]*, then it is only
+ * a login session if the ut_host field is non-empty
+ */
+ if (*usr.ut_name) {
+ if (strncmp(usr.ut_line, "tty", 3) != 0 ||
+ strchr("pqrstuvwxy", usr.ut_line[3]) == 0 ||
+ *usr.ut_host != '\0')
+ head = log_in(head, &usr);
+ } else
+ head = log_out(head, &usr);
+ break;
+ }
+ }
+ (void)fclose(fp);
+ usr.ut_time = time((time_t *)0);
+ (void)strcpy(usr.ut_line, "~");
+
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ }
+ }
+ /*
+ * anyone still logged in gets time up to now
+ */
+ head = log_out(head, &usr);
+
+ if (Flags & AC_D)
+ show_today(Users, head, time((time_t *)0));
+ else {
+ if (Flags & AC_P)
+ show_users(Users);
+ show("total", Total);
+ }
+ return 0;
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+#ifdef CONSOLE_TTY
+ "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
+#else
+ "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");
+#endif
+ exit(1);
+}
diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8
index f5c07b672c49..abf6ced7654d 100644
--- a/usr.sbin/config/config.8
+++ b/usr.sbin/config/config.8
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)config.8 6.5 (Berkeley) 3/16/91
-.\" $Id: config.8,v 1.2 1993/09/26 23:11:06 rgrimes Exp $
+.\" $Id: config.8,v 1.3 1994/06/01 09:50:08 phk Exp $
.\"
.Dd March 16, 1991
.Dt CONFIG 8
@@ -133,6 +133,10 @@ the problems in the configuration file should be corrected and
should be run again.
Attempts to compile a system that had configuration errors
are likely to fail.
+.Pp
+The entire input file is embedded in the new kernel. This means that
+.Xr strings 1
+can be used to extract it from a kernel.
.Sh FILES
.Bl -tag -width /sys/i386/conf/Makefile.i386 -compact
.It Pa /sys/conf/files
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c
index 2ea5c3d7ec32..93c089b18dde 100644
--- a/usr.sbin/config/main.c
+++ b/usr.sbin/config/main.c
@@ -146,6 +146,7 @@ usage: fputs("usage: config [-gp] sysname\n", stderr);
makefile(); /* build Makefile */
headers(); /* make a lot of .h files */
swapconf(); /* swap config files */
+ configfile(); /* add config file into kernel */
printf("Don't forget to run \"make depend\"\n");
exit(0);
}
@@ -256,3 +257,39 @@ path(file)
}
return (cp);
}
+
+
+configfile()
+{
+ FILE *fi, *fo;
+ char *p;
+ int i;
+
+ fi = fopen(PREFIX,"r");
+ if(!fi) {
+ perror(PREFIX);
+ exit(2);
+ }
+ fo = fopen(p=path("config.c"),"w");
+ if(!fo) {
+ perror(p);
+ exit(2);
+ }
+ fprintf(fo,"static char *config = \"\n");
+ fprintf(fo,"START CONFIG FILE %s\n___",PREFIX);
+ while (EOF != (i=getc(fi))) {
+ if(i == '\n') {
+ fprintf(fo,"\n___");
+ } else if(i == '\"') {
+ fprintf(fo,"\\\"");
+ } else if(i == '\\') {
+ fprintf(fo,"\\\\");
+ } else {
+ putc(i,fo);
+ }
+ }
+ fprintf(fo,"\nEND CONFIG FILE %s\n",PREFIX);
+ fprintf(fo,"\";\n");
+ fclose(fi);
+ fclose(fo);
+}
diff --git a/usr.sbin/config/mkglue.c b/usr.sbin/config/mkglue.c
index 8702448d6254..381f7bca0366 100644
--- a/usr.sbin/config/mkglue.c
+++ b/usr.sbin/config/mkglue.c
@@ -353,7 +353,7 @@ vector() {
fprintf(fp, "\
#define BUILD_VECTORS \\\n\
- BUILD_VECTOR(clk, 0,0,0, _highmask, _hardclock,1,1, al);\\\n");
+ BUILD_VECTOR(clk, 0,0,0, _high_imask, _timerintr,1,1, al);\\\n");
count=1;
for (dp = dtab; dp != 0; dp = dp->d_next) {
@@ -388,9 +388,9 @@ build_vector(fp, dp, id, offset)
strcmp(dp->d_name, "sio") == 0 ? "FAST_" : "",
dp->d_name, dp->d_unit, dp->d_unit, dp->d_irq, offset);
if (eq(dp->d_mask, "null"))
- fprintf(fp, ", _%s%dmask,", dp->d_name, dp->d_unit);
+ fprintf(fp, ", _%s%d_imask,", dp->d_name, dp->d_unit);
else
- fprintf(fp, ", _%smask, ", dp->d_mask);
+ fprintf(fp, ", _%s_imask, ", dp->d_mask);
fprintf(fp, " _%s,%d,1", id->id, 1 + dp->d_irq / 8);
if (dp->d_irq < 8)
fprintf(fp, ", al");
diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c
index 86654bfc104f..e135fc30736a 100644
--- a/usr.sbin/config/mkmakefile.c
+++ b/usr.sbin/config/mkmakefile.c
@@ -244,6 +244,10 @@ openit:
perror(fname);
exit(1);
}
+ if(ident == NULL) {
+ printf("no ident line specified\n");
+ exit(1);
+ }
next:
/*
* filename [ standard | optional ] [ config-dependent ]
diff --git a/usr.sbin/cron/cron.8 b/usr.sbin/cron/cron.8
index c89398663e0c..d96755ad0309 100644
--- a/usr.sbin/cron/cron.8
+++ b/usr.sbin/cron/cron.8
@@ -15,7 +15,7 @@
.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
.\" */
.\"
-.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1.2.1 1994/05/01 16:09:33 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1 1994/01/22 20:38:58 guido Exp $
.\"
.\" From Id: cron.8,v 2.2 1993/12/28 08:34:43 vixie Exp
.\"
diff --git a/usr.sbin/diskless_cfg/diskless.h b/usr.sbin/diskless_cfg/diskless.h
index 96d2a2d043e5..ef037279d5da 100644
--- a/usr.sbin/diskless_cfg/diskless.h
+++ b/usr.sbin/diskless_cfg/diskless.h
@@ -136,7 +136,7 @@ struct ifaliasreq {
*/
#define NFS_FHSIZE 32
-typedef struct { u_char f[NFS_FHSIZE] } nfsv2fh_t;
+typedef struct { u_char f[NFS_FHSIZE]; } nfsv2fh_t;
/*
* Arguments to mount NFS
*/
diff --git a/usr.sbin/diskless_cfg/diskless_cfg.c b/usr.sbin/diskless_cfg/diskless_cfg.c
index 3cf21379470f..7678ff54675f 100644
--- a/usr.sbin/diskless_cfg/diskless_cfg.c
+++ b/usr.sbin/diskless_cfg/diskless_cfg.c
@@ -18,6 +18,11 @@ Based loosely on the 4.4BSD diskless setup code
#include <rpc/types.h>
#include <sys/errno.h>
#include <nfs/nfs.h>
+#ifdef __SVR4
+/* Solaris: compile with -lbsm -lnsl -lsocket */
+#define getfh nfs_getfh
+#define bcopy(a,b,c) memcpy(b,a,c)
+#endif
#endif
#ifdef i386 /* Native 386bsd system */
@@ -50,6 +55,7 @@ struct nfs_diskless nfs_diskless;
#define KW_HOSTNAME 7
#define KW_KERNEL 8
#define KW_GATEWAY 9
+#define KW_SERVER 10
struct {
char *name;
@@ -63,11 +69,12 @@ struct {
{ "-wsize", KW_WSIZE },
{ "-hostname", KW_HOSTNAME },
{ "-gateway", KW_GATEWAY },
+ { "-server", KW_SERVER },
{ NULL, KW_HELP }
};
char *hostname = "386bsd";
-char *gateway = NULL;
+char gateway[256];
char cfg[64];
char *rootpath = "/var/386bsd";
char *swappath = "/var/swap/386bsd";
@@ -86,7 +93,7 @@ main(argc, argv)
char *p, *q;
netmask = 0;
- bzero(&nfs_diskless, 0, sizeof(struct nfs_diskless));
+ memset(&nfs_diskless, 0, sizeof(struct nfs_diskless));
strcpy(nfs_diskless.myif.ifra_name,"ed0");
nfs_diskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
nfs_diskless.myif.ifra_addr.sa_family = AF_INET;
@@ -107,24 +114,6 @@ main(argc, argv)
nfs_diskless.root_saddr.sa_len = sizeof(struct sockaddr);
nfs_diskless.root_saddr.sa_family = AF_INET;
- if (gethostname(servername, 256) < 0) {
- fprintf(stderr,"%s: unable to get host server name\n",argv[0]);
- exit(2);
- }
- if ((hp = gethostbyname(servername)) == NULL) {
- fprintf(stderr,"%s: unable to get host address\n",argv[0]);
- exit(2);
- }
- p = servername;
- while (*p && (*p != '.')) p++;
- *p = 0;
- nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0]
- = NFS_SOCKET >> 8;
- nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1]
- = NFS_SOCKET & 0x00FF;
- bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4);
- bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4);
-
i = 1;
while (i < argc) {
cmd = KW_HELP;
@@ -174,28 +163,49 @@ main(argc, argv)
hostname = argv[i+1];
i += 2;
break;
+ case KW_SERVER:
+ strcpy(servername,argv[i+1]);
+ i += 2;
+ break;
case KW_GATEWAY:
- gateway = argv[i+1];
+ strcpy(gateway,argv[i+1]);
i += 2;
break;
}
}
- if(gateway)
- {
- if (gethostname(gateway, 256) < 0) {
- fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]);
- exit(2);
- }
- if ((hp = gethostbyname(gateway)) == NULL) {
- fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]);
- exit(2);
- }
- nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr);
- nfs_diskless.mygateway.sa_family = AF_INET;
- nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8;
- nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF;
- bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4);
+
+ if (!*servername && gethostname(servername, sizeof servername) < 0) {
+ fprintf(stderr,"%s: unable to get host server name\n",argv[0]);
+ exit(2);
+ }
+ if ((hp = gethostbyname(servername)) == NULL) {
+ fprintf(stderr,"%s: unable to get host address\n",argv[0]);
+ exit(2);
+ }
+ p = servername;
+ while (*p && (*p != '.')) p++;
+ *p = 0;
+ nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0]
+ = NFS_SOCKET >> 8;
+ nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1]
+ = NFS_SOCKET & 0x00FF;
+ bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4);
+ bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4);
+
+ if (!*gateway && gethostname(gateway, sizeof gateway) < 0) {
+ fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]);
+ exit(2);
}
+ if ((hp = gethostbyname(gateway)) == NULL) {
+ fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]);
+ exit(2);
+ }
+ nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr);
+ nfs_diskless.mygateway.sa_family = AF_INET;
+ nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8;
+ nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF;
+ bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4);
+
nfs_diskless.swap_args.rsize = i386order(rsize);
nfs_diskless.swap_args.wsize = i386order(wsize);
nfs_diskless.root_args.rsize = i386order(rsize);
@@ -219,7 +229,7 @@ main(argc, argv)
bcopy(&broadcast, &nfs_diskless.myif.ifra_broadaddr.sa_data[2], 4);
bcopy(&netmask, &nfs_diskless.myif.ifra_mask.sa_data[2], 4);
if (stat(rootpath, &statbuf) < 0) {
- fprintf(stderr,"%s: unable to stat '%s'\n",
+ fprintf(stderr,"%s: unable to stat root '%s'\n",
argv[0],rootpath);
exit(2);
}
@@ -238,7 +248,7 @@ main(argc, argv)
strcpy(nfs_diskless.root_hostnam,buf);
printf("root is on %s\n",nfs_diskless.root_hostnam);
if (stat(swappath, &statbuf) < 0) {
- fprintf(stderr,"%s: unable to stat '%s'\n",
+ fprintf(stderr,"%s: unable to stat swap '%s'\n",
argv[0],swappath);
exit(2);
}
diff --git a/usr.sbin/fdcontrol/Makefile b/usr.sbin/fdcontrol/Makefile
new file mode 100644
index 000000000000..068cadeb782a
--- /dev/null
+++ b/usr.sbin/fdcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG = fdcontrol
+MAN8 = fdcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fdcontrol/fdcontrol.8 b/usr.sbin/fdcontrol/fdcontrol.8
new file mode 100644
index 000000000000..4c9f2872118c
--- /dev/null
+++ b/usr.sbin/fdcontrol/fdcontrol.8
@@ -0,0 +1,77 @@
+.\"
+.\" Copyright (C) 1994 by Joerg Wunsch, Dresden
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+.\"
+.Dd May 22, 1994
+.Os
+.Dt FDCONTROL 8
+.Sh NAME
+.Nm fdcontrol
+.Nd modify floppy disk parameters
+.Sh SYNOPSIS
+.Nm fdcontrol
+.Ar device
+.Sh DESCRIPTION
+.Nm Fdcontrol
+allows the specification of device parameters for the floppy disk at
+.Ar device .
+.Ar Device
+should be a character device.
+
+Since the implications of such a specification are considered harmful,
+the underlying
+.Xr ioctl 2
+command is restricted to the super-user.
+
+The command asks the user for each individual tunable parameter,
+defaulting to the currently used value.
+
+.Sh DIAGNOSTICS
+Error codes for the underlying
+.Xr ioctl 2
+commands are printed by the
+.Xr perror 3
+facility.
+
+.Sh BUGS
+The
+.Nm
+command is currently under development. It's user interface is rather
+silly and likely to change in future, options should be provided to
+allow anything being modified from the command line.
+
+.Sh SEE ALSO
+.Xr fd 4 ,
+.Xr ioctl 2 ,
+.Xr perror 3 .
+.Sh HISTORY
+.Nm Fdcontrol
+is currently under development. It's user interface and overall
+functionality are subjects to future improvements and changes.
+.Sh AUTHOR
+The program has been contributed by
+.if n Joerg Wunsch,
+.if t J\(:org Wunsch,
+Dresden.
diff --git a/usr.sbin/fdcontrol/fdcontrol.c b/usr.sbin/fdcontrol/fdcontrol.c
new file mode 100644
index 000000000000..91011a4a67f6
--- /dev/null
+++ b/usr.sbin/fdcontrol/fdcontrol.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1994 by Joerg Wunsch, Dresden
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <machine/ioctl_fd.h>
+#include <sys/file.h>
+
+int
+getnumber(void)
+{
+ int i;
+ char b[80];
+
+ fgets(b, 80, stdin);
+ if(b[0] == '\n') return -1;
+
+ sscanf(b, " %i", &i);
+ return i;
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: fdcontrol device-node\n");
+ exit(2);
+}
+
+
+#define ask(name, fmt) \
+printf(#name "? [" fmt "]: ", ft.name); fflush(stdout); \
+if((i = getnumber()) != -1) ft.name = i
+
+int
+main(int argc, char **argv)
+{
+ struct fd_type ft;
+ int fd, i;
+
+ if(argc != 2)
+ usage();
+
+ if((fd = open(argv[1], 0)) < 0)
+ {
+ perror("open(floppy)");
+ return 1;
+ }
+
+ if(ioctl(fd, FD_GTYPE, &ft) < 0)
+ {
+ perror("ioctl(FD_GTYPE)");
+ return 1;
+ }
+
+ ask(sectrac, "%d");
+ ask(secsize, "%d");
+ ask(datalen, "0x%x");
+ ask(gap, "0x%x");
+ ask(tracks, "%d");
+ ask(size, "%d");
+ ask(steptrac, "%d");
+ ask(trans, "%d");
+ ask(heads, "%d");
+ ask(f_gap, "0x%x");
+ ask(f_inter, "%d");
+
+ if(ioctl(fd, FD_STYPE, &ft) < 0)
+ {
+ perror("ioctl(FD_STYPE)");
+ return 1;
+ }
+ return 0;
+}
+
+
+
diff --git a/usr.sbin/fdformat/Makefile b/usr.sbin/fdformat/Makefile
index 209af72d124d..3ee3b4debeec 100644
--- a/usr.sbin/fdformat/Makefile
+++ b/usr.sbin/fdformat/Makefile
@@ -1,32 +1,9 @@
-# Copyright (C) 1993 by Joerg Wunsch, Dresden
-# 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.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
#
PROG = fdformat
# the -I's seem to be confusing, but necessery this way
# (so the right <unistd.h> will be found in /usr/include, and the
# "../i386/isa/ic/nec765.h" included from fdreg.h is accessible, too)
-CFLAGS+=-Wall -I/usr/include -I/sys/sys
+CFLAGS+= -Wall -I/usr/include -I/sys/sys
.include <bsd.prog.mk>
diff --git a/usr.sbin/fdformat/fdformat.1 b/usr.sbin/fdformat/fdformat.1
index 78a6b133340c..2b27f7f5ead7 100644
--- a/usr.sbin/fdformat/fdformat.1
+++ b/usr.sbin/fdformat/fdformat.1
@@ -10,20 +10,20 @@
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
.\"
.Dd September 16, 1993
-.Os FreeBSD
+.Os
.Dt FDFORMAT 1
.Sh NAME
.Nm fdformat
@@ -57,7 +57,7 @@ or default name in an abbreviated form
.Pq e.\ g. Em fd0 .
In the latter case, the name is constructed by prepending
.Pa /dev/r
-and appending an
+and appending a
.Em .capacity
to the
.Ar device_name .
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
index b88a8ea7618d..6ab7d94ff96f 100644
--- a/usr.sbin/fdformat/fdformat.c
+++ b/usr.sbin/fdformat/fdformat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden
+ * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,17 +11,17 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
*/
/*
@@ -90,7 +90,16 @@ verify_track(int fd, int track, int tracksize)
{
static char *buf = 0;
static int bufsz = 0;
-
+ int fdopts = -1, ofdopts, rv = 0;
+
+ if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
+ perror("warning: ioctl(FD_GOPTS)");
+ else {
+ ofdopts = fdopts;
+ fdopts |= FDOPT_NORETRY;
+ (void)ioctl(fd, FD_SOPTS, &fdopts);
+ }
+
if (bufsz < tracksize) {
if (buf)
free (buf);
@@ -104,10 +113,14 @@ verify_track(int fd, int track, int tracksize)
exit (2);
}
if (lseek (fd, (long) track*tracksize, 0) < 0)
- return (-1);
- if (read (fd, buf, tracksize) != tracksize)
- return (-1);
- return (0);
+ rv = -1;
+ /* try twice reading it, without using the normal retrier */
+ else if (read (fd, buf, tracksize) != tracksize
+ && read (fd, buf, tracksize) != tracksize)
+ rv = -1;
+ if(fdopts != -1)
+ (void)ioctl(fd, FD_SOPTS, &ofdopts);
+ return (rv);
}
static const char *
@@ -127,7 +140,7 @@ makename(const char *arg, const char *suffix)
}
static void
-usage ()
+usage (void)
{
printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n");
printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n");
@@ -152,7 +165,7 @@ usage ()
}
static int
-yes ()
+yes (void)
{
char reply [256], *p;
@@ -353,3 +366,18 @@ main(int argc, char **argv)
return errs;
}
+/*
+ * Local Variables:
+ * c-indent-level: 8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * c-brace-offset: -8
+ * c-brace-imaginary-offset: 0
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c++-hanging-braces: 1
+ * c++-access-specifier-offset: -8
+ * c++-empty-arglist-indent: 8
+ * c++-friend-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/flcopy/Makefile b/usr.sbin/flcopy/Makefile
deleted file mode 100644
index 2cfc59848c66..000000000000
--- a/usr.sbin/flcopy/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# @(#)Makefile 5.2 (Berkeley) 1/20/91
-
-PROG= flcopy
-MANSUBDIR=/vax
-MAN8= flcopy.8
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/flcopy/flcopy.8 b/usr.sbin/flcopy/flcopy.8
deleted file mode 100644
index 1cc14ccd9c80..000000000000
--- a/usr.sbin/flcopy/flcopy.8
+++ /dev/null
@@ -1,83 +0,0 @@
-.\" Copyright (c) 1980 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.
-.\"
-.\" @(#)flcopy.8 5.2 (Berkeley) 4/20/91
-.\"
-.TH FLCOPY 8 "April 20, 1991"
-.UC 4
-.SH NAME
-flcopy \- floppy copy
-.SH SYNOPSIS
-.nf
-.ft B
-flcopy [ \-hr ] [ \-f file ] [ \-t ntracks ]
-.ft R
-.fi
-.SH DESCRIPTION
-.I Flcopy
-copies the console floppy disk (``/dev/floppy'') to a file in the
-current directory, named ``floppy''.
-The user is then prompted to change the floppy, and enter a carriage
-return when done.
-When a carriage return is entered,
-.I flcopy
-copies the file out to the floppy disk.
-.PP
-The options are as follows:
-.TP
-\-f
-Use
-.I file
-instead of ``/dev/floppy''.
-.TP
--h
-Cause
-.I flcopy
-to copy a file named ``floppy'' in the current directory to
-the console floppy disk.
-.TP
-\-r
-Cause
-.I flcopy
-to copy the floppy to the current directory and then quit.
-.TP
-\-t
-Copy only the first
-.I ntracks
-tracks.
-.SH FILES
-floppy temporary file name
-.br
-/dev/floppy default floppy device
-.SH SEE ALSO
-crl(4), fl(4), rx(4), tu(4), arff(8), rxformat(8)
-.SH BUGS
-Device errors are handled ungracefully.
diff --git a/usr.sbin/flcopy/flcopy.c b/usr.sbin/flcopy/flcopy.c
deleted file mode 100644
index d1a2e35ff043..000000000000
--- a/usr.sbin/flcopy/flcopy.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
- All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)flcopy.c 5.4 (Berkeley) 1/20/91";
-#endif /* not lint */
-
-#include <sys/file.h>
-#include <stdio.h>
-#include "pathnames.h"
-
-int floppydes;
-char *flopname = _PATH_FLOPPY;
-long dsize = 77 * 26 * 128;
-int hflag;
-int rflag;
-
-main(argc, argv)
- register char **argv;
-{
- extern char *optarg;
- extern int optind;
- static char buff[512];
- register long count;
- register startad = -26 * 128;
- register int n, file;
- register char *cp;
- int ch;
-
- while ((ch = getopt(argc, argv, "f:hrt:")) != EOF)
- switch(ch) {
- case 'f':
- flopname = optarg;
- break;
- case 'h':
- hflag = 1;
- printf("Halftime!\n");
- if ((file = open("floppy", 0)) < 0) {
- printf("can't open \"floppy\"\n");
- exit(1);
- }
- break;
- case 'r':
- rflag = 1;
- break;
- case 't':
- dsize = atoi(optarg);
- if (dsize <= 0 || dsize > 77) {
- (void)fprintf(stderr,
- "flcopy: bad number of tracks (0 - 77).\n");
- exit(2);
- }
- dsize *= 26 * 128;
- break;
- case '?':
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (!hflag) {
- file = open("floppy", O_RDWR|O_CREAT|O_TRUNC, 0666);
- if (file < 0) {
- printf("can't open \"floppy\"\n");
- exit(1);
- }
- for (count = dsize; count > 0 ; count -= 512) {
- n = count > 512 ? 512 : count;
- lread(startad, n, buff);
- write(file, buff, n);
- startad += 512;
- }
- }
- if (rflag)
- exit(0);
- printf("Change Floppy, Hit return when done.\n");
- gets(buff);
- lseek(file, 0, 0);
- count = dsize;
- startad = -26 * 128;
- for ( ; count > 0 ; count -= 512) {
- n = count > 512 ? 512 : count;
- read(file, buff, n);
- lwrite(startad, n, buff);
- startad += 512;
- }
- exit(0);
-}
-
-rt_init()
-{
- static initized = 0;
- int mode = 2;
-
- if (initized)
- return;
- if (rflag)
- mode = 0;
- initized = 1;
- if ((floppydes = open(flopname, mode)) < 0) {
- printf("Floppy open failed\n");
- exit(1);
- }
-}
-
-/*
- * Logical to physical adress translation
- */
-long
-trans(logical)
- register int logical;
-{
- register int sector, bytes, track;
-
- logical += 26 * 128;
- bytes = (logical & 127);
- logical >>= 7;
- sector = logical % 26;
- if (sector >= 13)
- sector = sector*2 +1;
- else
- sector *= 2;
- sector += 26 + ((track = (logical / 26)) - 1) * 6;
- sector %= 26;
- return ((((track *26) + sector) << 7) + bytes);
-}
-
-lread(startad, count, obuff)
- register startad, count;
- register char *obuff;
-{
- long trans();
- extern floppydes;
-
- rt_init();
- while ((count -= 128) >= 0) {
- lseek(floppydes, trans(startad), 0);
- read(floppydes, obuff, 128);
- obuff += 128;
- startad += 128;
- }
-}
-
-lwrite(startad, count, obuff)
- register startad, count;
- register char *obuff;
-{
- long trans();
- extern floppydes;
-
- rt_init();
- while ((count -= 128) >= 0) {
- lseek(floppydes, trans(startad), 0);
- write(floppydes, obuff, 128);
- obuff += 128;
- startad += 128;
- }
-}
-
-usage()
-{
- (void)fprintf(stderr, "usage: flcopy [-hr] [-f file] [-t ntracks]\n");
- exit(1);
-}
diff --git a/usr.sbin/flcopy/pathnames.h b/usr.sbin/flcopy/pathnames.h
deleted file mode 100644
index 60b2df28a6b4..000000000000
--- a/usr.sbin/flcopy/pathnames.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * Copyright (c) 1990 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.
- *
- * @(#)pathnames.h 5.1 (Berkeley) 4/28/90
- */
-
-#define _PATH_FLOPPY "/dev/floppy"
diff --git a/usr.sbin/kbdcontrol/Makefile b/usr.sbin/kbdcontrol/Makefile
new file mode 100644
index 000000000000..da1a23380674
--- /dev/null
+++ b/usr.sbin/kbdcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG= kbdcontrol
+SRCS= kbdcontrol.c lex.l
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.1 b/usr.sbin/kbdcontrol/kbdcontrol.1
new file mode 100644
index 000000000000..645103675f4e
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.1
@@ -0,0 +1,77 @@
+.\"
+.\" kbdcontrol - a utility for manipulating the syscons keyboard driver section
+.\"
+.\" 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.
+.\"
+.\" @(#)kbdcontrol.1
+.\"
+.TH kbdcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+kbdcontrol - a utility for manipulating the syscons keyboard driver section.
+.SH SYNOPSIS
+.na
+.B kbdcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B kbdcontrol
+command is used to set various keyboard related options for the syscons
+console driver, such as keymap, keyboard repeat & delay rates, bell
+characteristics etc.
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-b\ " [ duration.pitch ]
+Set the bell duration and pitch values.
+.TP
+.BI "\-r\ " [ delay.repeat | slow | fast | normal ]
+Set keyboard
+.I delay
+and
+.I repeat
+rates, or use presets for
+.I slow,
+.I fast
+or
+.I normal.
+.TP
+.BI "\-l\ " mapfile
+Install keyboard map file from
+.I mapfile
+.TP
+.BI "\-d\ "
+Dump the current keyboard map onto stdout
+.TP
+.BI "\-f\ " #\ string
+Set function key number
+.I #
+to send
+.I string
+.
+.TP
+.BI "\-F\ "
+Set function keys back to the standard definitions.
+.TP
+.B \-v
+Turns on verbose output.
+.PP
+.SH FILES
+/usr/share/syscons/keymaps
+.SH "BUGS"
+Report when found.
+.SH "SEE ALSO"
+.BR vidcontrol (1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/SYSCONS
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c
new file mode 100644
index 000000000000..cda976b203c2
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.c
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: kbdcontrol.c,v 1.1 1994/05/20 12:18:05 sos Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include "path.h"
+#include "lex.h"
+
+char ctrl_names[32][4] = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns "
+ };
+
+char fkey_table[60][MAXFK] = {
+/* 00-03 */ "\033[M", "\033[N", "\033[O", "\033[P",
+/* 04-07 */ "\033[Q", "\033[R", "\033[S", "\033[T",
+/* 08-0B */ "\033[U", "\033[V", "\033[W", "\033[X",
+/* 0C-0F */ "\033[W", "\033[X", "\033[Y", "\033[Z",
+/* 10-13 */ "\033[a", "\033[b", "\033[c", "\033[d",
+/* 14-17 */ "\033[e", "\033[f", "\033[g", "\033[h",
+/* 18-1B */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 1C-1F */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 20-23 */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 24-27 */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 28-2B */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 2C-2F */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 30-33 */ "\033[H", "\033[A", "\033[I", "-" ,
+/* 34-37 */ "\033[D", "\177" , "\033[C", "+" ,
+/* 38-3B */ "\033[F", "\033[B", "\033[G", "\033[L"
+ };
+
+const int delays[] = {250, 500, 750, 1000};
+const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63,
+ 68, 76, 84, 92, 100, 110, 118, 126,
+ 136, 152, 168, 184, 200, 220, 236, 252,
+ 272, 304, 336, 368, 400, 440, 472, 504};
+const int ndelays = (sizeof(delays) / sizeof(int));
+const int nrepeats = (sizeof(repeats) / sizeof(int));
+int hex = 0;
+int number, verbose = 0;
+char letter;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+int
+get_entry()
+{
+ switch (yylex()) {
+ case TNOP:
+ return NOP | 0x100;
+ case TLSH:
+ return LSH | 0x100;
+ case TRSH:
+ return RSH | 0x100;
+ case TCLK:
+ return CLK | 0x100;
+ case TNLK:
+ return NLK | 0x100;
+ case TSLK:
+ return SLK | 0x100;
+ case TBTAB:
+ return BTAB | 0x100;
+ case TLALT:
+ return LALT | 0x100;
+ case TLCTR:
+ return LCTR | 0x100;
+ case TNEXT:
+ return NEXT | 0x100;
+ case TRCTR:
+ return RCTR | 0x100;
+ case TRALT:
+ return RALT | 0x100;
+ case TALK:
+ return ALK | 0x100;
+ case TASH:
+ return ASH | 0x100;
+ case TMETA:
+ return META | 0x100;
+ case TRBT:
+ return RBT | 0x100;
+ case TDBG:
+ return DBG | 0x100;
+ case TFUNC:
+ if (F(number) > L_FN)
+ return -1;
+ return F(number) | 0x100;
+ case TSCRN:
+ if (S(number) > L_SCR)
+ return -1;
+ return S(number) | 0x100;
+ case TLET:
+ return (unsigned char)letter;
+ case TNUM:
+ if (number < 0 || number > 255)
+ return -1;
+ return number;
+ default:
+ return -1;
+ }
+}
+
+
+int
+get_key_definition_line(FILE* fd, keymap_t *map)
+{
+ int i, def, scancode;
+
+ yyin = fd;
+
+ /* get scancode number */
+ if (yylex() != TNUM)
+ return -1;
+ if (number < 0 || number >= NUM_KEYS)
+ return -1;
+ scancode = number;
+
+ /* get key definitions */
+ map->key[scancode].spcl = 0;
+ for (i=0; i<NUM_STATES; i++) {
+ if ((def = get_entry()) == -1)
+ return -1;
+ if (def & 0x100)
+ map->key[scancode].spcl |= (0x80 >> i);
+ map->key[scancode].map[i] = def & 0xFF;
+ }
+ /* get lock state key def */
+ if (yylex() != TFLAG)
+ return -1;
+ map->key[scancode].flgs = number;
+ return scancode;
+}
+
+
+int
+print_entry(FILE *fp, int value)
+{
+ int val = value & 0xFF;
+
+ switch (value) {
+ case NOP | 0x100:
+ fprintf(fp, " nop ");
+ break;
+ case LSH | 0x100:
+ fprintf(fp, " lshift");
+ break;
+ case RSH | 0x100:
+ fprintf(fp, " rshift");
+ break;
+ case CLK | 0x100:
+ fprintf(fp, " clock ");
+ break;
+ case NLK | 0x100:
+ fprintf(fp, " nlock ");
+ break;
+ case SLK | 0x100:
+ fprintf(fp, " slock ");
+ break;
+ case BTAB | 0x100:
+ fprintf(fp, " btab ");
+ break;
+ case LALT | 0x100:
+ fprintf(fp, " lalt ");
+ break;
+ case LCTR | 0x100:
+ fprintf(fp, " lctrl ");
+ break;
+ case NEXT | 0x100:
+ fprintf(fp, " nscr ");
+ break;
+ case RCTR | 0x100:
+ fprintf(fp, " rctrl ");
+ break;
+ case RALT | 0x100:
+ fprintf(fp, " ralt ");
+ break;
+ case ALK | 0x100:
+ fprintf(fp, " alock ");
+ break;
+ case ASH | 0x100:
+ fprintf(fp, " ashift");
+ break;
+ case META | 0x100:
+ fprintf(fp, " meta ");
+ break;
+ case RBT | 0x100:
+ fprintf(fp, " boot ");
+ break;
+ case DBG | 0x100:
+ fprintf(fp, " debug ");
+ break;
+ default:
+ if (value & 0x100) {
+ if (val >= F_FN && val <= L_FN)
+ fprintf(fp, " fkey%02d", val - F_FN + 1);
+ else if (val >= F_SCR && val <= L_SCR)
+ fprintf(fp, " scr%02d ", val - F_SCR + 1);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ else {
+ if (val < ' ')
+ fprintf(fp, " %s ", ctrl_names[val]);
+ else if (val == 127)
+ fprintf(fp, " del ");
+ else if (isprint(val))
+ fprintf(fp, " '%c' ", val);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ }
+}
+
+
+void
+print_key_definition_line(FILE *fp, int scancode, struct key_t *key)
+{
+ int i, value;
+
+ /* print scancode number */
+ if (hex)
+ fprintf(fp, " 0x%02x ", scancode);
+ else
+ fprintf(fp, " %03d ", scancode);
+
+ /* print key definitions */
+ for (i=0; i<NUM_STATES; i++) {
+ if (key->spcl & (0x80 >> i))
+ print_entry(fp, key->map[i] | 0x100);
+ else
+ print_entry(fp, key->map[i]);
+ }
+
+ /* print lock state key def */
+ switch (key->flgs) {
+ case 0:
+ fprintf(fp, " O\n");
+ break;
+ case 1:
+ fprintf(fp, " C\n");
+ break;
+ case 2:
+ fprintf(fp, " N\n");
+ break;
+ }
+}
+
+
+void
+load_keymap(char *opt)
+{
+ keymap_t map;
+ FILE *fd;
+ int scancode, i;
+ char *name;
+ char *prefix[] = {"", "", KEYMAP_PATH, NULL};
+ char *postfix[] = {"", ".kbd", ".kbd"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], opt, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("keymap file not found");
+ return;
+ }
+ memset(map, 0, sizeof(map));
+ while (1) {
+ if ((scancode = get_key_definition_line(fd, &map)) < 0)
+ break;
+ if (scancode > map.n_keys) map.n_keys = scancode;
+ }
+ if (ioctl(0, PIO_KEYMAP, &map) < 0) {
+ perror("setting keymap");
+ fclose(fd);
+ return;
+ }
+}
+
+
+void
+print_keymap()
+{
+ keymap_t map;
+ int i;
+
+ if (ioctl(0, GIO_KEYMAP, &map) < 0) {
+ perror("getting keymap");
+ exit(1);
+ }
+ printf(
+"# alt\n"
+"# scan cntrl alt alt cntrl lock\n"
+"# code base shift cntrl shift alt shift cntrl shift state\n"
+"# ------------------------------------------------------------------\n"
+ );
+ for (i=0; i<map.n_keys; i++)
+ print_key_definition_line(stdout, i, &map.key[i]);
+}
+
+
+void
+load_default_functionkeys()
+{
+ fkeyarg_t fkey;
+ int i;
+
+ for (i=0; i<NUM_FKEYS; i++) {
+ fkey.keynum = i;
+ strcpy(fkey.keydef, fkey_table[i]);
+ fkey.flen = strlen(fkey_table[i]);
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+ }
+}
+
+void
+set_functionkey(char *keynumstr, char *string)
+{
+ fkeyarg_t fkey;
+ int keynum;
+
+ if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
+ load_default_functionkeys();
+ return;
+ }
+ fkey.keynum = atoi(keynumstr);
+ if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
+ fprintf(stderr,
+ "function key number must be between 1 and %d\n",
+ NUM_FKEYS);
+ return;
+ }
+ if ((fkey.flen = strlen(string)) > MAXFK) {
+ fprintf(stderr, "function key string too long (%d > %d)\n",
+ fkey.flen, MAXFK);
+ return;
+ }
+ strcpy(fkey.keydef, string);
+ if (verbose)
+ fprintf(stderr, "setting function key %d to <%s>\n",
+ fkey.keynum, fkey.keydef);
+ fkey.keynum -= 1;
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+}
+
+
+void
+set_bell_values(char *opt)
+{
+ int duration, pitch;
+
+ if (!strcmp(opt, "normal"))
+ duration = 1, pitch = 15;
+ else {
+ int n;
+ char *v1;
+
+ duration = strtol(opt, &v1, 0);
+ if ((duration < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ pitch = strtol(opt, &v1, 0);
+ if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -b must be DURATION.PITCH\n");
+ return;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting bell values to %d.%d\n",
+ duration, pitch);
+ fprintf(stderr, "[=%d;%dB", pitch, duration);
+}
+
+
+void
+set_keyrates(char *opt)
+{
+struct {
+ int rep:5;
+ int del:2;
+ int pad:1;
+ }rate;
+
+ if (!strcmp(opt, "slow"))
+ rate.del = 3, rate.rep = 31;
+ else if (!strcmp(opt, "normal"))
+ rate.del = 1, rate.rep = 15;
+ else if (!strcmp(opt, "fast"))
+ rate.del = rate.rep = 0;
+ else {
+ int n;
+ int delay, repeat;
+ char *v1;
+
+ delay = strtol(opt, &v1, 0);
+ if ((delay < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ repeat = strtol(opt, &v1, 0);
+ if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -r must be delay.repeat\n");
+ return;
+ }
+ for (n = 0; n < ndelays - 1; n++)
+ if (delay <= delays[n])
+ break;
+ rate.del = n;
+ for (n = 0; n < nrepeats - 1; n++)
+ if (repeat <= repeats[n])
+ break;
+ rate.rep = n;
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting keyboard rate to %d.%d\n",
+ delays[rate.del], repeats[rate.rep]);
+ if (ioctl(0, KDSETRAD, rate) < 0)
+ perror("setting keyboard rate");
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: kbdcontrol -b duration.pitch (set bell duration & pitch)\n"
+" -d (dump keyboard map to stdout)\n"
+" -l filename (load keyboard map file)\n"
+" -f <N> string (set function key N to send <string>)\n"
+" -F (set function keys back to default)\n"
+" -r delay.repeat (set keyboard delay & repeat rate)\n"
+" -r slow (set keyboard delay & repeat to slow)\n"
+" -r normal (set keyboard delay & repeat to normal)\n"
+" -r fast (set keyboard delay & repeat to fast)\n"
+" -v (verbose)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+ /*
+ if (!is_syscons(0))
+ exit(1);
+ */
+ while((opt = getopt(argc, argv, "b:df:Fl:r:vx")) != -1)
+ switch(opt) {
+ case 'b':
+ set_bell_values(optarg);
+ break;
+ case 'd':
+ print_keymap();
+ break;
+ case 'l':
+ load_keymap(optarg);
+ break;
+ case 'f':
+ set_functionkey(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'F':
+ load_default_functionkeys();
+ break;
+ case 'r':
+ set_keyrates(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
+
diff --git a/usr.sbin/kbdcontrol/lex.h b/usr.sbin/kbdcontrol/lex.h
new file mode 100644
index 000000000000..feff74009f95
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lex.h,v 1.1 1994/05/20 12:18:06 sos Exp $
+ */
+
+#define TNOP 256
+#define TLSH 257
+#define TRSH 258
+#define TCLK 259
+#define TNLK 260
+#define TSLK 261
+#define TLALT 262
+#define TLCTR 263
+#define TNEXT 264
+#define TRCTR 265
+#define TRALT 266
+#define TALK 267
+#define TASH 268
+#define TMETA 269
+#define TRBT 270
+#define TDBG 271
+#define TFUNC 272
+#define TSCRN 273
+#define TLET 274
+#define TNUM 275
+#define TFLAG 276
+#define TBTAB 277
+
+extern int number;
+extern char letter;
+extern FILE *yyin;
diff --git a/usr.sbin/kbdcontrol/lex.l b/usr.sbin/kbdcontrol/lex.l
new file mode 100644
index 000000000000..0729af70f161
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.l
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lex.l,v 1.1 1994/05/20 12:18:08 sos Exp $
+ */
+
+%{
+
+#include "lex.h"
+
+%}
+
+D [0-9]
+X [0-9a-fA-F]
+A .
+L [OCN]
+
+%%
+
+nop { return TNOP; }
+lshift { return TLSH; }
+rshift { return TRSH; }
+clock { return TCLK; }
+nlock { return TNLK; }
+slock { return TSLK; }
+lalt|alt { return TLALT; }
+btab { return TBTAB; }
+lctrl|ctrl { return TLCTR; }
+nscr { return TNEXT; }
+rctrl { return TRCTR; }
+ralt { return TRALT; }
+alock { return TALK; }
+ashift { return TASH; }
+meta { return TMETA; }
+boot { return TRBT; }
+debug { return TDBG; }
+
+NUL|nul { number = 0; return TNUM; }
+SOH|soh { number = 1; return TNUM; }
+STX|stx { number = 2; return TNUM; }
+ETX|etx { number = 3; return TNUM; }
+EOT|eot { number = 4; return TNUM; }
+ENQ|enq { number = 5; return TNUM; }
+ACK|ack { number = 6; return TNUM; }
+BEL|bel { number = 7; return TNUM; }
+BS|bs { number = 8; return TNUM; }
+HT|ht { number = 9; return TNUM; }
+LF|lf|NL|nl { number = 10; return TNUM; }
+VT|vt { number = 11; return TNUM; }
+FF|ff|NP|np { number = 12; return TNUM; }
+CR|cr { number = 13; return TNUM; }
+SO|so { number = 14; return TNUM; }
+SI|si { number = 15; return TNUM; }
+DLE|dle { number = 16; return TNUM; }
+DC1|dc1 { number = 17; return TNUM; }
+DC2|dc2 { number = 18; return TNUM; }
+DC3|dc3 { number = 19; return TNUM; }
+DC4|dc4 { number = 20; return TNUM; }
+NAK|nak { number = 21; return TNUM; }
+SYN|syn { number = 22; return TNUM; }
+ETB|etb { number = 23; return TNUM; }
+CAN|can { number = 24; return TNUM; }
+EM|em { number = 25; return TNUM; }
+SUB|sub { number = 26; return TNUM; }
+ESC|esc { number = 27; return TNUM; }
+FS|fs { number = 28; return TNUM; }
+GS|gs { number = 29; return TNUM; }
+RS|rs { number = 30; return TNUM; }
+NS|ns { number = 31; return TNUM; }
+SP|sp { number = 32; return TNUM; }
+DEL|del { number = 127; return TNUM; }
+
+fkey{D}({D}*) {
+ sscanf(yytext+4, "%d", &number);
+ return TFUNC;
+ }
+scr{D}({D}*) {
+ sscanf(yytext+3, "%d", &number);
+ return TSCRN;
+ }
+'{A}' { letter = *(yytext+1); return TLET; }
+#({A}*) { /* ignore */ }
+0x{X}({X}*) { sscanf(yytext, "%x", &number); return TNUM; }
+{D}({D}*) { sscanf(yytext, "%d", &number); return TNUM; }
+{L} {
+ if (*yytext == 'O') number = 0;
+ if (*yytext == 'C') number = 1;
+ if (*yytext == 'N') number = 2;
+ return TFLAG;
+ }
+[ \t\n] { /* ignore */ }
diff --git a/usr.sbin/kbdcontrol/path.h b/usr.sbin/kbdcontrol/path.h
new file mode 100644
index 000000000000..709acbc375dc
--- /dev/null
+++ b/usr.sbin/kbdcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/kvm_mkdb/nlist.c b/usr.sbin/kvm_mkdb/nlist.c
index f2ee8a1999b1..622e0d99edf0 100644
--- a/usr.sbin/kvm_mkdb/nlist.c
+++ b/usr.sbin/kvm_mkdb/nlist.c
@@ -122,58 +122,6 @@ create_knlist(name, db)
if ((db->put)(db, &key, &data, 0))
error("put");
- if (!strncmp((char *)key.data, VRS_SYM, sizeof(VRS_SYM) - 1)) {
- off_t cur_off, rel_off, vers_off;
-
- /* Offset relative to start of text image in VM. */
-#ifdef hp300
- rel_off = nbuf.n_value;
-#endif
-#ifdef tahoe
- /*
- * On tahoe, first 0x800 is reserved for communication
- * with the console processor.
- */
- rel_off = ((nbuf.n_value & ~KERNBASE) - 0x800);
-#endif
-#ifdef vax
- rel_off = nbuf.n_value & ~KERNBASE;
-#endif
-#ifdef i386
- rel_off = nbuf.n_value - ebuf.a_entry + CLBYTES;
-#endif
- /*
- * When loaded, data is rounded to next page cluster
- * after text, but not in file.
- */
- rel_off -= CLBYTES - (ebuf.a_text % CLBYTES);
- vers_off = N_TXTOFF(ebuf) + rel_off;
-
- cur_off = ftell(fp);
- if (fseek(fp, vers_off, SEEK_SET) == -1)
- badfmt("corrupted string table");
-
- /*
- * Read version string up to, and including newline.
- * This code assumes that a newline terminates the
- * version line.
- */
- if (fgets(buf, sizeof(buf), fp) == NULL)
- badfmt("corrupted string table");
-
- key.data = (u_char *)VRS_KEY;
- key.size = sizeof(VRS_KEY) - 1;
- data.data = (u_char *)buf;
- data.size = strlen(buf);
- if ((db->put)(db, &key, &data, 0))
- error("put");
-
- /* Restore to original values. */
- data.data = (u_char *)&nbuf;
- data.size = sizeof(NLIST);
- if (fseek(fp, cur_off, SEEK_SET) == -1)
- badfmt("corrupted string table");
- }
}
(void)fclose(fp);
}
diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c
index 0fe755dec16f..05339b640e16 100644
--- a/usr.sbin/lpr/common_source/common.c
+++ b/usr.sbin/lpr/common_source/common.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: common.c,v 1.1.1.1.2.1 1994/05/04 08:01:55 rgrimes Exp $
+ * $Id: common.c,v 1.2 1994/05/04 08:37:15 rgrimes Exp $
*/
/*
* Copyright (c) 1983 Regents of the University of California.
diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c
index eca1fb43e2db..9abe1c980bc9 100644
--- a/usr.sbin/lpr/lpr/lpr.c
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: lpr.c,v 1.1.1.1.2.2 1994/05/04 08:02:12 rgrimes Exp $
+ * $Id: lpr.c,v 1.3 1994/05/04 08:37:28 rgrimes Exp $
*/
/*
* Copyright (c) 1983 Regents of the University of California.
diff --git a/usr.sbin/lptcontrol/Makefile b/usr.sbin/lptcontrol/Makefile
new file mode 100644
index 000000000000..e685c02febc4
--- /dev/null
+++ b/usr.sbin/lptcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG = lptcontrol
+CFLAGS += -Wall
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lptcontrol/lptcontrol.1 b/usr.sbin/lptcontrol/lptcontrol.1
new file mode 100644
index 000000000000..52c34a68a725
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.1
@@ -0,0 +1,67 @@
+.\"
+.\" lptcontrol - a utility for manipulating the lpt driver
+.\"
+.\" 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.
+.\"
+.\"
+.\" $Id: lptcontrol.1,v 1.3 1994/05/22 12:31:54 csgr Exp $
+.TH lptcontrol 1 "March 12, 1994" "" "FreeBSD"
+
+.SH NAME
+lptcontrol - a utility for manipulating the lpt printer driver.
+.SH SYNOPSIS
+.na
+.B lptcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B lptcontrol
+command is used to set either the interrupt-driven or polling mode
+of individual lpt devices. When a printer is switched between
+interrupt-driven and polled mode, this change will only take effect
+the next time the device is opened.
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-i
+Turns on interrupt-driven mode.
+.TP
+.B \-p
+Turns on polled mode.
+.TP
+.BI "\-f\ " file
+Sets the mode of the printer device specified by
+.I file.
+The default value for
+.I file
+is
+.I /dev/lpt0
+.TP
+One of
+.B \-i
+or
+.B \-p
+must be specified.
+.PP
+.SH FILES
+/dev/lpt?
+.PP
+.SH BUGS
+If the port to be controlled does not have a printer connected and
+on-line, then lptcontrol will not be able to open the port in question
+for performing ioctl's and will fail.
+.sp
+Sure to be others.
+.SH "SEE ALSO"
+.BR lpt (4) ,
+.BR /sys/i386/conf/GENERICAH
+.SH AUTHOR
+Geoffrey M. Rehmet
diff --git a/usr.sbin/lptcontrol/lptcontrol.c b/usr.sbin/lptcontrol/lptcontrol.c
new file mode 100644
index 000000000000..bcb3ad303569
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1994 Geoffrey M. Rehmet
+ * 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 Geoffrey M. Rehmet
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lptcontrol.c,v 1.2 1994/04/08 22:23:39 csgr Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/lpt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+
+
+#define DEFAULT_LPT "/dev/lpt0"
+#define IRQ_INVALID -1
+#define DO_POLL 0
+#define USE_IRQ 1
+
+static char default_printer[] = DEFAULT_LPT;
+
+static void usage(const char * progname)
+{
+ fprintf(stderr, "usage: %s -i | -p [-f <file name>]\n", progname);
+ exit(1);
+}
+
+static void set_interrupt_status(int irq_status, const char * file)
+{
+ int fd;
+
+ if((fd = open(file, O_WRONLY, 0660)) < 0) {
+ perror("open");
+ exit(1);
+ }
+ if(ioctl(fd, LPT_IRQ, &irq_status) < 0) {
+ perror("ioctl");
+ exit(1);
+ }
+ close(fd);
+}
+
+
+int main (int argc, char * argv[])
+{
+ int opt;
+ int irq_status = -1;
+ char * file = default_printer;
+
+ while((opt = getopt(argc, argv, "pif:")) != -1)
+ switch(opt) {
+ case 'i': irq_status = USE_IRQ; break;
+ case 'p': irq_status = DO_POLL; break;
+ case 'f': file = optarg; break;
+ default : usage(argv[0]);
+ }
+ if(irq_status == IRQ_INVALID) usage(argv[0]);
+
+ set_interrupt_status(irq_status, file);
+
+ exit(0);
+}
+
+
diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE
new file mode 100644
index 000000000000..ef7da470b117
--- /dev/null
+++ b/usr.sbin/mrouted/LICENSE
@@ -0,0 +1,48 @@
+
+The mrouted program is covered by the following license. Use of the
+mrouted program represents acceptance of these terms and conditions.
+
+1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
+to use, copy and modify the computer software ``mrouted'' (hereinafter
+called the ``Program''), upon the terms and conditions hereinafter set
+out and until Licensee discontinues use of the Licensed Program.
+
+2. LICENSEE acknowledges that the Program is a research tool still in
+the development state, that it is being supplied ``as is,'' without any
+accompanying services from STANFORD, and that this license is entered
+into in order to encourage scientific collaboration aimed at further
+development and application of the Program.
+
+3. LICENSEE may copy the Program and may sublicense others to use object
+code copies of the Program or any derivative version of the Program.
+All copies must contain all copyright and other proprietary notices found
+in the Program as provided by STANFORD. Title to copyright to the
+Program remains with STANFORD.
+
+4. LICENSEE may create derivative versions of the Program. LICENSEE
+hereby grants STANFORD a royalty-free license to use, copy, modify,
+distribute and sublicense any such derivative works. At the time
+LICENSEE provides a copy of a derivative version of the Program to a
+third party, LICENSEE shall provide STANFORD with one copy of the source
+code of the derivative version at no charge to STANFORD.
+
+5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
+By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
+OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
+COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
+for any liability nor for any direct, indirect or consequential damages
+with respect to any claim by LICENSEE or any third party on account of or
+arising from this Agreement or use of the Program.
+
+6. This agreement shall be construed, interpreted and applied in
+accordance with the State of California and any legal action arising
+out of this Agreement or use of the Program shall be filed in a court
+in the State of California.
+
+7. Nothing in this Agreement shall be construed as conferring rights to
+use in advertising, publicity or otherwise any trademark or the name
+of ``Stanford''.
+
+The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+Leland Stanford Junior University.
diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile
new file mode 100644
index 000000000000..06b9e28be6c4
--- /dev/null
+++ b/usr.sbin/mrouted/Makefile
@@ -0,0 +1,44 @@
+#
+# Makefile for mrouted, a multicast router, and its auxiliary programs,
+# map-mbone and mrinfo.
+#
+# $Id: Makefile,v 1.3 1994/06/15 11:28:38 jkh Exp $
+#
+# Modified by: Jim Lowe for FreeBSD 5/17/94
+#
+
+IGMP_SRCS= igmp.c inet.c kern.c
+IGMP_OBJS= igmp.o inet.o kern.o
+ROUTER_SRCS= config.c main.c route.c vif.c
+ROUTER_OBJS= config.o main.o route.o vif.o
+MAPPER_SRCS= mapper.c
+MAPPER_OBJS= mapper.o
+MRINFO_SRCS= mrinfo.c
+MRINFO_OBJS= mrinfo.o
+HDRS= defs.h dvmrp.h route.h vif.h
+SRCS= ${IGMP_SRCS} ${ROUTER_SRCS} ${MAPPER_SRCS} ${MRINFO_SRCS}
+OBJS= ${IGMP_OBJS} ${ROUTER_OBJS} ${MAPPER_OBJS} ${MRINFO_OBJS}
+CLEANFILES+=mrouted map-mbone mrinfo
+
+MAN8= mrouted.8
+
+all: mrouted map-mbone mrinfo
+
+mrouted: ${IGMP_OBJS} ${ROUTER_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${ROUTER_OBJS}
+
+map-mbone: ${IGMP_OBJS} ${MAPPER_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MAPPER_OBJS}
+
+mrinfo: ${IGMP_OBJS} ${MRINFO_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MRINFO_OBJS}
+
+install: mrouted mrinfo map-mbone
+ install -c mrouted ${DESTDIR}${BINDIR}
+ install -c -o root -m 500 mrinfo ${DESTDIR}${BINDIR}
+ install -c -o root -m 500 map-mbone ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
new file mode 100644
index 000000000000..089b7098f335
--- /dev/null
+++ b/usr.sbin/mrouted/config.c
@@ -0,0 +1,528 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: config.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+char *configfilename = "/etc/mrouted.conf";
+
+
+/*
+ * Forward declarations.
+ */
+static char *next_word();
+
+
+/*
+ * Query the kernel to find network interfaces that are multicast-capable
+ * and install them in the uvifs array.
+ */
+void config_vifs_from_kernel()
+{
+ struct ifreq ifbuf[32];
+ struct ifreq *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ register struct uvif *v;
+ register vifi_t vifi;
+ int i, n;
+ u_long addr, mask, subnet;
+ u_int flags;
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ ifrp = (struct ifreq *)ifbuf;
+ ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
+ /*
+ * Loop through all of the interfaces.
+ */
+ for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
+ struct ifreq ifr;
+#if BSD >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+#else
+ n = sizeof(*ifrp);
+#endif
+ /*
+ * Ignore any interface for an address family other than IP.
+ */
+ addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+
+ /*
+ * Ignore loopback interfaces and interfaces that do not support
+ * multicast.
+ */
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+ flags = ifr.ifr_flags;
+ if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue;
+
+ /*
+ * Ignore any interface whose address and mask do not define a
+ * valid subnet number, or whose address is of the form {subnet,0}
+ * or {subnet,-1}.
+ */
+ if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
+ mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ subnet = addr & mask;
+ if (!inet_valid_subnet(subnet, mask) ||
+ addr == subnet ||
+ addr == (subnet | ~mask)) {
+ log(LOG_WARNING, 0,
+ "ignoring %s, has invalid address (%s) and/or mask (%08x)",
+ ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
+ continue;
+ }
+
+ /*
+ * Ignore any interface that is connected to the same subnet as
+ * one already installed in the uvifs array.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if ((addr & v->uv_subnetmask) == v->uv_subnet ||
+ (v->uv_subnet & mask) == subnet) {
+ log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
+ ifr.ifr_name, v->uv_name);
+ break;
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * If there is room in the uvifs array, install this interface.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = 0;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = addr;
+ v->uv_rmt_addr = 0;
+ v->uv_subnet = subnet;
+ v->uv_subnetmask = mask;
+ v->uv_subnetbcast = subnet | ~mask;
+ strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+
+ log(LOG_INFO, 0, "installing %s (%s on subnet %s) as vif #%u",
+ v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
+ numvifs);
+
+ ++numvifs;
+
+ /*
+ * If the interface is not yet up, set the vifs_down flag to
+ * remind us to check again later.
+ */
+ if (!(flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_long a;
+{
+ int n;
+ struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
+ struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
+
+ while (ifrp < ifend) {
+ if (ifrp->ifr_addr.sa_family == AF_INET &&
+ ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
+ return (ifrp);
+#if BSD >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ++ifrp;
+ else
+ ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+ ++ifrp;
+#endif
+ }
+ return (0);
+}
+/*
+ * Read the config file to learn about tunnel vifs and
+ * non-default phyint parameters.
+ */
+void config_vifs_from_file()
+{
+ FILE *f;
+ char linebuf[100];
+ char *w, *s, c;
+ u_long lcl_addr, rmt_addr;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ int i;
+ u_int n;
+ struct ifreq ifbuf[32];
+ vifi_t vifi;
+ struct uvif *v;
+
+ f = fopen(configfilename, "r");
+ if (f == NULL) {
+ if (errno != ENOENT)
+ log(LOG_WARNING, errno, "can't open %s", configfilename);
+ return;
+ }
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
+
+ s = linebuf;
+ if (EQUAL((w = next_word(&s)), "")) {
+ /*
+ * blank or comment line; ignore
+ */
+ }
+
+ else if (EQUAL(w, "phyint")) {
+ /*
+ * phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+ */
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing phyint address in %s",
+ configfilename);
+ continue;
+ }
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid phyint address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Look up the vif with the specified local address.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ lcl_addr == v->uv_lcl_addr) {
+ break;
+ }
+ }
+ if (vifi == numvifs) {
+ log(LOG_WARNING, 0,
+ "phyint %s in %s is not a configured interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Look for "disable", "metric" and "threshold" options.
+ */
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "disable")) {
+ v->uv_flags |= VIFF_DISABLED;
+ }
+ else if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing metric for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_WARNING, 0,
+ "invalid metric '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing threshold for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_WARNING, 0,
+ "invalid threshold '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else break;
+ }
+ if (!EQUAL(w, "")) continue;
+ }
+
+ else if (EQUAL(w, "tunnel")) {
+ /*
+ * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
+ */
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing tunnel local address in %s",
+ configfilename);
+ continue;
+ }
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid tunnel local address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address is one of ours.
+ */
+ ifr = ifconfaddr(&ifc, lcl_addr);
+ if (ifr == 0) {
+ log(LOG_WARNING, 0,
+ "tunnel local address %s in %s is not one of ours",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address doesn't name a loopback interface..
+ */
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
+ }
+ if (ffr.ifr_flags & IFF_LOOPBACK) {
+ log(LOG_WARNING, 0,
+ "tunnel local address %s in %s is a loopback interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Parse the remote address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing tunnel remote address in %s",
+ configfilename);
+ continue;
+ }
+ if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(rmt_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid tunnel remote address %s in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address is not one of ours.
+ */
+ if (ifconfaddr(&ifc, rmt_addr) != 0) {
+ log(LOG_WARNING, 0,
+ "tunnel remote address %s in %s is one of ours",
+ inet_fmt(rmt_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address has not been used for another
+ * tunnel and does not belong to a subnet to which we have direct
+ * access on an enabled phyint.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (rmt_addr == v->uv_rmt_addr) {
+ log(LOG_WARNING, 0,
+ "duplicate tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
+ log(LOG_WARNING, 0,
+ "unnecessary tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * OK, let's initialize a uvif structure for the tunnel.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_WARNING, 0, "too many vifs, ignoring tunnel to %s",
+ inet_fmt(rmt_addr, s1));
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = lcl_addr;
+ v->uv_rmt_addr = rmt_addr;
+ v->uv_subnet = 0;
+ v->uv_subnetmask = 0;
+ v->uv_subnetbcast = 0;
+ strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+
+ /*
+ * Look for "metric" and "threshold" options.
+ */
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing metric for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_WARNING, 0,
+ "invalid metric '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing threshold for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_WARNING, 0,
+ "invalid threshold '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
+ v->uv_flags |= VIFF_SRCRT;
+ }
+ else break;
+ }
+ if (!EQUAL(w, "")) continue;
+
+ log(LOG_INFO, 0,
+ "installing %stunnel from %s to %s as vif #%u",
+ v->uv_flags & VIFF_SRCRT? "srcrt " : "",
+ inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2), numvifs);
+
+ ++numvifs;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+
+ else {
+ log(LOG_WARNING, 0,
+ "unknown command '%s' in %s", w, configfilename);
+ }
+ }
+
+ close(f);
+}
+
+
+/*
+ * Return a pointer to the next "word" in the string to which '*s' points,
+ * lower-cased and null terminated, and advance '*s' to point beyond the word.
+ * Words are separated by blanks and/or tabs, and the input string is
+ * considered to terminate at a newline, '#' (comment), or null character.
+ * If no words remain, a pointer to a null string ("") is returned.
+ * Warning: This function clobbers the input string.
+ */
+static char *next_word(s)
+ char **s;
+{
+ char *w;
+
+ w = *s;
+ while (*w == ' ' || *w == '\t')
+ ++w;
+
+ *s = w;
+ for(;;) {
+ switch (**s) {
+
+ case ' ' :
+ case '\t' : **s = '\0';
+ ++*s;
+ return (w);
+
+ case '\n' :
+ case '#' : **s = '\0';
+ return (w);
+
+ case '\0' : return (w);
+
+ default : if (isascii(**s) && isupper(**s))
+ **s = tolower(**s);
+ ++*s;
+ }
+ }
+}
diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h
new file mode 100644
index 000000000000..ebaec8e5abff
--- /dev/null
+++ b/usr.sbin/mrouted/defs.h
@@ -0,0 +1,129 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: defs.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/igmp.h>
+#include <netinet/ip_mroute.h>
+
+#include "dvmrp.h"
+#include "vif.h"
+#include "route.h"
+
+
+/*
+ * Miscellaneous constants and macros.
+ */
+#define FALSE 0
+#define TRUE 1
+
+#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
+
+#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
+
+#define PROTOCOL_VERSION 2 /* increment when packet format/content changes */
+
+#define MROUTED_VERSION 0 /* increment on local changes or bug fixes, */
+ /* reset to 0 whever PROTOCOL_VERSION increments */
+
+#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
+ /* for IGMP 'group' field of DVMRP messages */
+
+/*
+ * External declarations for global variables and functions.
+ */
+extern char recv_buf[MAX_IP_PACKET_LEN];
+extern char send_buf[MAX_IP_PACKET_LEN];
+extern int igmp_socket;
+extern u_long allhosts_group;
+extern u_long dvmrp_group;
+
+#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
+
+extern int debug;
+
+extern int routes_changed;
+extern int delay_change_reports;
+
+extern struct uvif uvifs[MAXVIFS];
+extern vifi_t numvifs;
+extern int vifs_down;
+extern int udp_socket;
+
+extern char s1[];
+extern char s2[];
+extern char s3[];
+
+extern int errno;
+extern int sys_nerr;
+extern char * sys_errlist[];
+
+extern void log();
+
+extern void init_igmp();
+extern void accept_igmp();
+extern void send_igmp();
+
+extern void init_routes();
+extern void start_route_updates();
+extern void update_route();
+extern void age_routes();
+extern void expire_all_routes();
+extern void accept_probe();
+extern void accept_report();
+extern void report();
+extern void report_to_all_neighbors();
+extern void add_vif_to_routes();
+extern void delete_vif_from_routes();
+extern void delete_neighbor_from_routes();
+extern void dump_routes();
+
+extern void init_vifs();
+extern void check_vif_state();
+extern vifi_t find_vif();
+extern void age_vifs();
+extern void dump_vifs();
+extern void accept_group_report();
+extern void query_groups();
+extern void probe_for_neighbors();
+extern int update_neighbor();
+extern void accept_neighbor_request();
+
+extern void config_vifs_from_kernel();
+extern void config_vifs_from_file();
+
+extern int inet_valid_host();
+extern int inet_valid_subnet();
+extern char * inet_fmt();
+extern char * inet_fmts();
+extern u_long inet_parse();
+extern int inet_cksum();
+
+extern char * malloc();
+extern char * fgets();
+extern FILE * fopen();
+
+#ifndef htonl
+extern u_long htonl();
+extern u_long ntohl();
+#endif
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
new file mode 100644
index 000000000000..6928fe82bb9e
--- /dev/null
+++ b/usr.sbin/mrouted/dvmrp.h
@@ -0,0 +1,141 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: dvmrp.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * A DVMRP message consists of an IP header + an IGMP header + (for some types)
+ * zero or more bytes of data.
+ *
+ * For REPORT messages, the data is route information; the route information
+ * consists of one or more lists of the following form:
+ *
+ * (mask, (origin, metric), (origin, metric), ...)
+ *
+ * where:
+ *
+ * "mask" is the subnet mask for all the origins in the list.
+ * It is always THREE bytes long, containing the low-order
+ * three bytes of the mask (the high-order byte is always
+ * 0xff and therefore need not be transmitted).
+ *
+ * "origin" is the number of a subnet from which multicast datagrams
+ * may originate. It is from one to four bytes long,
+ * depending on the value of "mask":
+ * if all bytes of the mask are zero
+ * the subnet number is one byte long
+ * else if the low-order two bytes of the mask are zero
+ * the subnet number is two bytes long
+ * else if the lowest-order byte of the mask is zero
+ * the subnet number is three bytes long,
+ * else
+ * the subnet number is four bytes long.
+ *
+ * "metric" is a one-byte value consisting of two subfields:
+ * - the high-order bit is a flag which, when set, indicates
+ * the last (origin, metric) pair of a list.
+ * - the low-order seven bits contain the routing metric for
+ * the corresponding origin, relative to the sender of the
+ * DVMRP report. The metric may have the value of UNREACHABLE
+ * added to it as a "split horizon" indication (so called
+ * "poisoned reverse").
+ *
+ * Within a list, the origin subnet numbers must be in ascending order, and
+ * the lists themselves are in order of increasing mask value. A message may
+ * not exceed 576 bytes, the default maximum IP reassembly size, including
+ * the IP and IGMP headers; the route information may be split across more
+ * than one message if necessary, by terminating a list in one message and
+ * starting a new list in the next message (repeating the same mask value,
+ * if necessary).
+ *
+ * For NEIGHBORS messages, the data is neighboring-router information
+ * consisting of one or more lists of the following form:
+ *
+ * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...)
+ *
+ * where:
+ *
+ * "local-addr" is the sending router's address as seen by the neighbors
+ * in this list; it is always four bytes long.
+ * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding
+ * packets to any of the neighbors on this list.
+ * "threshold" is a one-byte unsigned value, a lower bound on the TTL a
+ * packet must have to be forwarded to any of the neighbors on
+ * this list.
+ * "ncount" is the number of neighbors in this list.
+ * "neighbor" is the address of a neighboring router, four bytes long.
+ *
+ * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes,
+ * including the IP and IGMP headers; split longer messages by terminating the
+ * list in one and continuing in another, repeating the local-addr, etc., if
+ * necessary.
+ *
+ * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except
+ * there is a flags byte before the neighbor count:
+ *
+ * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...)
+ */
+
+/*
+ * DVMRP message types (carried in the "code" field of an IGMP header)
+ */
+#define DVMRP_PROBE 1 /* for finding neighbors */
+#define DVMRP_REPORT 2 /* for reporting some or all routes */
+#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */
+ /* of this router's neighbors. */
+#define DVMRP_NEIGHBORS 4 /* response to such a request */
+#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */
+#define DVMRP_NEIGHBORS2 6
+
+/*
+ * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
+ */
+#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
+#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
+#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
+#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
+#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
+
+/*
+ * Limit on length of route data
+ */
+#define MAX_IP_PACKET_LEN 576
+#define MIN_IP_HEADER_LEN 20
+#define MAX_IP_HEADER_LEN 60
+#define MAX_DVMRP_DATA_LEN \
+ ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )
+
+/*
+ * Various protocol constants (all times in seconds)
+ */
+ /* address for multicast DVMRP msgs */
+#define INADDR_DVMRP_GROUP (u_long)0xe0000004 /* 224.0.0.4 */
+
+#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
+ /* (This is the timer interrupt */
+ /* interval; all times must be */
+ /* multiples of this value.) */
+
+#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */
+#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */
+#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */
+#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */
+
+#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */
+
+#define NEIGHBOR_PROBE_INTERVAL 190 /* periodic neighbor probe interval */
+#define NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */
+
+#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
+#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
+
+#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
+#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
+#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c
new file mode 100644
index 000000000000..cfd874e611b9
--- /dev/null
+++ b/usr.sbin/mrouted/igmp.c
@@ -0,0 +1,217 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: igmp.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
+char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
+int igmp_socket; /* socket for all network I/O */
+u_long allhosts_group; /* allhosts addr in net order */
+u_long dvmrp_group; /* DVMRP grp addr in net order */
+
+
+/*
+ * Open and initialize the igmp socket, and fill in the non-changing
+ * IP header fields in the output packet buffer.
+ */
+void init_igmp()
+{
+ struct ip *ip;
+
+ if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
+ log(LOG_ERR, errno, "IGMP socket");
+
+ k_hdr_include(TRUE); /* include IP header when sending */
+ k_set_rcvbuf(48*1024); /* lots of input buffering */
+ k_set_ttl(1); /* restrict multicasts to one hop */
+ k_set_loop(FALSE); /* disable multicast loopback */
+
+ ip = (struct ip *)send_buf;
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = IPPROTO_IGMP;
+ ip->ip_ttl = MAXTTL; /* applies to unicasts only */
+
+ allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
+ dvmrp_group = htonl(INADDR_DVMRP_GROUP);
+}
+
+static char *packet_kind(type, code)
+ u_char type, code;
+{
+ switch (type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
+ case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
+ case IGMP_DVMRP:
+ switch (code) {
+ case DVMRP_PROBE: return "neighbor probe ";
+ case DVMRP_REPORT: return "route report ";
+ case DVMRP_ASK_NEIGHBORS: return "neighbor request ";
+ case DVMRP_NEIGHBORS: return "neighbor list ";
+ case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
+ case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
+ default: return "unknown DVMRP msg ";
+ }
+ default: return "unknown IGMP msg ";
+ }
+}
+
+/*
+ * Process a newly received IGMP packet that is sitting in the input
+ * packet buffer.
+ */
+void accept_igmp(recvlen)
+ int recvlen;
+{
+ register vifi_t vifi;
+ register u_long src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "received packet too short (%u bytes) for IP header", recvlen);
+ return;
+ }
+
+ ip = (struct ip *)recv_buf;
+ src = ip->ip_src.s_addr;
+ dst = ip->ip_dst.s_addr;
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "received packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ return;
+ }
+
+ igmp = (struct igmp *)(recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "received IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ return;
+ }
+
+ log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
+ packet_kind(igmp->igmp_type, igmp->igmp_code),
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ return; /* Answered automatically by the kernel. */
+
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ accept_group_report(src, dst, group);
+ return;
+
+ case IGMP_DVMRP:
+ switch (igmp->igmp_code) {
+
+ case DVMRP_PROBE:
+ accept_probe(src, dst);
+ return;
+
+ case DVMRP_REPORT:
+ accept_report(src, dst,
+ (char *)(igmp+1), igmpdatalen);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS:
+ accept_neighbor_request(src, dst);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS2:
+ accept_neighbor_request2(src, dst);
+ return;
+
+ case DVMRP_NEIGHBORS:
+ accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown DVMRP message code %u from %s to %s",
+ igmp->igmp_code, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown IGMP message type %u from %s to %s",
+ igmp->igmp_type, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+}
+
+
+/*
+ * Construct an IGMP message in the output packet buffer. The caller may
+ * have already placed data in that buffer, of length 'datalen'. Then send
+ * the message from the interface with IP address 'src' to destination 'dst'.
+ */
+void send_igmp(src, dst, type, code, group, datalen)
+ u_long src, dst;
+ int type, code;
+ u_long group;
+ int datalen;
+{
+ static struct sockaddr_in sdst = {AF_INET};
+ struct ip *ip;
+ struct igmp *igmp;
+
+ ip = (struct ip *)send_buf;
+ ip->ip_src.s_addr = src;
+ ip->ip_dst.s_addr = dst;
+ ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
+
+ igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
+ igmp->igmp_type = type;
+ igmp->igmp_code = code;
+ igmp->igmp_group.s_addr = group;
+ igmp->igmp_cksum = 0;
+ igmp->igmp_cksum = inet_cksum((u_short *)igmp,
+ IGMP_MINLEN + datalen);
+
+ if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
+ if (dst == allhosts_group) k_set_loop(TRUE);
+
+ sdst.sin_addr.s_addr = dst;
+ if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
+ (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
+ if (errno == ENETDOWN) check_vif_state();
+ else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1));
+ }
+
+ if (dst == allhosts_group) k_set_loop(FALSE);
+
+ log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
+ packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
+}
diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c
new file mode 100644
index 000000000000..02b187a85a39
--- /dev/null
+++ b/usr.sbin/mrouted/inet.c
@@ -0,0 +1,187 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: inet.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char s1[16]; /* buffers to hold the string representations */
+char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
+char s3[16]; /* or inet_fmts(). */
+
+
+/*
+ * Verify that a given IP address is credible as a host address.
+ * (Without a mask, cannot detect addresses of the form {subnet,0} or
+ * {subnet,-1}.)
+ */
+int inet_valid_host(naddr)
+ u_long naddr;
+{
+ register u_long addr;
+
+ addr = ntohl(naddr);
+
+ return (!(IN_MULTICAST(addr) ||
+ IN_BADCLASS (addr) ||
+ (addr & 0xff000000) == 0));
+}
+
+
+/*
+ * Verify that a given subnet number and mask pair are credible.
+ */
+int inet_valid_subnet(nsubnet, nmask)
+ u_long nsubnet, nmask;
+{
+ register u_long subnet, mask;
+
+ subnet = ntohl(nsubnet);
+ mask = ntohl(nmask);
+
+ if ((subnet & mask) != subnet) return (FALSE);
+
+ if (IN_CLASSA(subnet)) {
+ if (mask < 0xff000000 ||
+ (subnet & 0xff000000) == 0 ||
+ (subnet & 0xff000000) == 0x7f000000) return (FALSE);
+ }
+ else if (IN_CLASSB(subnet)) {
+ if (mask < 0xffff0000) return (FALSE);
+ }
+ else if (IN_CLASSC(subnet)) {
+ if (mask < 0xffffff00) return (FALSE);
+ }
+ else return (FALSE);
+
+ return (TRUE);
+}
+
+
+/*
+ * Convert an IP address in u_long (network) format into a printable string.
+ */
+char *inet_fmt(addr, s)
+ u_long addr;
+ char *s;
+{
+ register u_char *a;
+
+ a = (u_char *)&addr;
+ sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ return (s);
+}
+
+
+/*
+ * Convert an IP subnet number in u_long (network) format into a printable
+ * string.
+ */
+char *inet_fmts(addr, mask, s)
+ u_long addr, mask;
+ char *s;
+{
+ register u_char *a, *m;
+
+ a = (u_char *)&addr;
+ m = (u_char *)&mask;
+
+ if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
+ else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
+ else sprintf(s, "%u", a[0]);
+
+ return (s);
+}
+
+
+/*
+ * Convert the printable string representation of an IP address into the
+ * u_long (network) format. Return 0xffffffff on error. (To detect the
+ * legal address with that value, you must explicitly compare the string
+ * with "255.255.255.255".)
+ */
+u_long inet_parse(s)
+ char *s;
+{
+ u_long a;
+ u_int a0, a1, a2, a3;
+ char c;
+
+ if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
+ a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
+ return (0xffffffff);
+
+ ((u_char *)&a)[0] = a0;
+ ((u_char *)&a)[1] = a1;
+ ((u_char *)&a)[2] = a2;
+ ((u_char *)&a)[3] = a3;
+
+ return (a);
+}
+
+
+/*
+ * inet_cksum extracted from:
+ * P I N G . C
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ * Modified at Uc Berkeley
+ *
+ * (ping.c) Status -
+ * Public Domain. Distribution Unlimited.
+ *
+ * I N _ C K S U M
+ *
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ */
+int inet_cksum(addr, len)
+ u_short *addr;
+ u_int len;
+{
+ register int nleft = (int)len;
+ register u_short *w = addr;
+ u_short answer = 0;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while( nleft > 1 ) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if( nleft == 1 ) {
+ *(u_char *) (&answer) = *(u_char *)w ;
+ sum += answer;
+ }
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c
new file mode 100644
index 000000000000..08c934982ebb
--- /dev/null
+++ b/usr.sbin/mrouted/kern.c
@@ -0,0 +1,213 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: kern.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+void k_set_rcvbuf(bufsize)
+ int bufsize;
+{
+ if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
+ (char *)&bufsize, sizeof(bufsize)) < 0)
+ log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
+}
+
+
+void k_hdr_include(bool)
+ int bool;
+{
+#ifdef IP_HDRINCL
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&bool, sizeof(bool)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
+#endif
+}
+
+
+void k_set_ttl(t)
+ int t;
+{
+ u_char ttl;
+
+ ttl = t;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
+}
+
+
+void k_set_loop(l)
+ int l;
+{
+ u_char loop;
+
+ loop = l;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (char *)&loop, sizeof(loop)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
+}
+
+
+void k_set_if(ifa)
+ u_long ifa;
+{
+ struct in_addr adr;
+
+ adr.s_addr = ifa;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
+ (char *)&adr, sizeof(adr)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
+ inet_fmt(ifa, s1));
+}
+
+
+void k_join(grp, ifa)
+ u_long grp;
+ u_long ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't join group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_leave(grp, ifa)
+ u_long grp;
+ u_long ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't leave group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_init_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
+ (char *)NULL, 0) < 0)
+ log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
+}
+
+
+void k_stop_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
+ (char *)NULL, 0) < 0)
+ log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel");
+}
+
+
+void k_add_vif(vifi, v)
+ vifi_t vifi;
+ struct uvif *v;
+{
+ struct vifctl vc;
+
+ vc.vifc_vifi = vifi;
+ vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
+ vc.vifc_threshold = v->uv_threshold;
+ vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
+ vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_VIF,
+ (char *)&vc, sizeof(vc)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
+}
+
+
+void k_del_vif(vifi)
+ vifi_t vifi;
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
+ (char *)&vifi, sizeof(vifi)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
+}
+
+
+void k_add_group(vifi, group)
+ vifi_t vifi;
+ u_long group;
+{
+ struct lgrplctl lc;
+
+ lc.lgc_vifi = vifi;
+ lc.lgc_gaddr.s_addr = group;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_LGRP,
+ (char *)&lc, sizeof(lc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_LGRP");
+}
+
+
+void k_del_group(vifi, group)
+ vifi_t vifi;
+ u_long group;
+{
+ struct lgrplctl lc;
+
+ lc.lgc_vifi = vifi;
+ lc.lgc_gaddr.s_addr = group;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_LGRP,
+ (char *)&lc, sizeof(lc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_LGRP");
+}
+
+
+void k_add_route(r)
+ struct rtentry *r;
+{
+ struct mrtctl mc;
+
+ mc.mrtc_origin.s_addr = r->rt_origin;
+ mc.mrtc_originmask.s_addr = r->rt_originmask;
+ mc.mrtc_parent = r->rt_parent;
+ VIFM_COPY(r->rt_children, mc.mrtc_children);
+ VIFM_COPY(r->rt_leaves, mc.mrtc_leaves);
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MRT,
+ (char *)&mc, sizeof(mc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MRT");
+}
+
+
+void k_update_route(r)
+ struct rtentry *r;
+{
+ k_add_route(r);
+}
+
+
+void k_del_route(r)
+ struct rtentry *r;
+{
+ struct in_addr orig;
+
+ orig.s_addr = r->rt_origin;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MRT,
+ (char *)&orig, sizeof(orig)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MRT");
+}
diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c
new file mode 100644
index 000000000000..75809dc478e3
--- /dev/null
+++ b/usr.sbin/mrouted/main.c
@@ -0,0 +1,322 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: main.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * Written by Steve Deering, Stanford University, February 1989.
+ *
+ * (An earlier version of DVMRP was implemented by David Waitzman of
+ * BBN STC by extending Berkeley's routed program. Some of Waitzman's
+ * extensions have been incorporated into mrouted, but none of the
+ * original routed code has been adopted.)
+ */
+
+
+#include "defs.h"
+
+extern char *configfilename;
+
+static char pidfilename[] = "/etc/mrouted.pid";
+static char dumpfilename[] = "/usr/tmp/mrouted.dump";
+
+static int debug = 0;
+
+
+/*
+ * Forward declarations.
+ */
+static void timer();
+static void hup();
+static void dump();
+static void fdump();
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int recvlen;
+ register int omask;
+ int dummy;
+ FILE *fp;
+ extern uid_t geteuid();
+
+ setlinebuf(stderr);
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mrouted: must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && *argv[0] == '-') {
+ if (strcmp(*argv, "-d") == 0) {
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ debug = atoi(*argv);
+ } else
+ debug = DEFAULT_DEBUG;
+ } else if (strcmp(*argv, "-c") == 0) {
+ if (argc > 1) {
+ argv++, argc--;
+ configfilename = *argv;
+ } else
+ goto usage;
+ } else
+ goto usage;
+ argv++, argc--;
+ }
+
+ if (argc > 0) {
+usage: fprintf(stderr, "usage: mrouted [-c configfile] [-d [debug_level]]\n");
+ exit(1);
+ }
+
+ if (debug == 0) {
+ /*
+ * Detach from the terminal
+ */
+ int t;
+
+ if (fork()) exit(0);
+ (void)close(0);
+ (void)close(1);
+ (void)close(2);
+ (void)open("/", 0);
+ (void)dup2(0, 1);
+ (void)dup2(0, 2);
+ t = open("/dev/tty", 2);
+ if (t >= 0) {
+ (void)ioctl(t, TIOCNOTTY, (char *)0);
+ (void)close(t);
+ }
+ }
+ else fprintf(stderr, "debug level %u\n", debug);
+
+#ifdef LOG_DAEMON
+ (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
+ (void)setlogmask(LOG_UPTO(LOG_NOTICE));
+#else
+ (void)openlog("mrouted", LOG_PID);
+#endif
+ log(LOG_NOTICE, 0, "mrouted version %d.%d",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+
+ fp = fopen(pidfilename, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+
+ srandom(gethostid());
+
+ init_igmp();
+ k_init_dvmrp(); /* enable DVMRP routing in kernel */
+ init_routes();
+ init_vifs();
+
+ if (debug >= 2) dump();
+
+ (void)signal(SIGALRM, timer);
+ (void)signal(SIGHUP, hup);
+ (void)signal(SIGTERM, hup);
+ (void)signal(SIGINT, hup);
+ (void)signal(SIGUSR1, fdump);
+ if (debug != 0)
+ (void)signal(SIGQUIT, dump);
+
+ (void)alarm(TIMER_INTERVAL); /* schedule first timer interrupt */
+
+ /*
+ * Main receive loop.
+ */
+ dummy = 0;
+ for(;;) {
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen < 0) {
+ if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
+ continue;
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ accept_igmp(recvlen);
+ (void)sigsetmask(omask);
+ }
+}
+
+
+/*
+ * The 'virtual_time' variable is initialized to a value that will cause the
+ * first invocation of timer() to send a probe or route report to all vifs
+ * and send group membership queries to all subnets for which this router is
+ * querier. This first invocation occurs approximately TIMER_INTERVAL seconds
+ * after the router starts up. Note that probes for neighbors and queries
+ * for group memberships are also sent at start-up time, as part of initial-
+ * ization. This repetition after a short interval is desirable for quickly
+ * building up topology and membership information in the presence of possible
+ * packet loss.
+ *
+ * 'virtual_time' advances at a rate that is only a crude approximation of
+ * real time, because it does not take into account any time spent processing,
+ * and because the timer intervals are sometimes shrunk by a random amount to
+ * avoid unwanted synchronization with other routers.
+ */
+
+static u_long virtual_time = 0;
+
+
+/*
+ * Timer routine. Performs periodic neighbor probing, route reporting, and
+ * group querying duties, and drives various timers in routing entries and
+ * virtual interface data structures.
+ */
+static void timer()
+{
+ int next_interval;
+
+ age_routes(); /* Advance the timers in the route entries */
+ age_vifs(); /* Advance the timers for neighbors and groups */
+
+ if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
+ /*
+ * Time to query the local group memberships on all subnets
+ * for which this router is the elected querier.
+ */
+ query_groups();
+ }
+
+ if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
+ /*
+ * Time to send a probe on all vifs from which no neighbors have
+ * been heard. Also, check if any inoperative interfaces have now
+ * come up. (If they have, they will also be probed as part of
+ * their initialization.)
+ */
+ probe_for_neighbors();
+
+ if (vifs_down)
+ check_vif_state();
+ }
+
+ delay_change_reports = FALSE;
+ next_interval = TIMER_INTERVAL;
+
+ if (virtual_time % ROUTE_REPORT_INTERVAL == 0) {
+ /*
+ * Time for the periodic report of all routes to all neighbors.
+ */
+ report_to_all_neighbors(ALL_ROUTES);
+
+ /*
+ * Schedule the next timer interrupt for a random time between
+ * 1 and TIMER_INTERVAL seconds from now. This randomization is
+ * intended to counteract the undesirable synchronizing tendency
+ * of periodic transmissions from multiple sources.
+ */
+ next_interval = (random() % TIMER_INTERVAL) + 1;
+ }
+ else if (routes_changed) {
+ /*
+ * Some routes have changed since the last timer interrupt, but
+ * have not been reported yet. Report the changed routes to all
+ * neighbors.
+ */
+ report_to_all_neighbors(CHANGED_ROUTES);
+ }
+
+ /*
+ * Advance virtual time and schedule the next timer interrupt.
+ */
+ virtual_time += TIMER_INTERVAL;
+ (void)alarm(next_interval);
+}
+
+
+/*
+ * On hangup signal, let everyone know we're going away.
+ */
+static void hup()
+{
+ log(LOG_INFO, 0, "hup");
+ expire_all_routes();
+ report_to_all_neighbors(ALL_ROUTES);
+ exit(1);
+}
+
+
+/*
+ * Dump internal data structures to stderr.
+ */
+static void dump()
+{
+ dump_vifs(stderr);
+ dump_routes(stderr);
+}
+
+
+/*
+ * Dump internal data structures to a file.
+ */
+static void fdump()
+{
+ FILE *fp;
+
+ fp = fopen(dumpfilename, "w");
+ if (fp != NULL) {
+ dump_vifs(fp);
+ dump_routes(fp);
+ (void) fclose(fp);
+ }
+}
+
+
+/*
+ * Log errors and other messages to the system log daemon and to stderr,
+ * according to the severity of the message and the current debug level.
+ * For errors of severity LOG_ERR or worse, terminate the program.
+ */
+void log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0: break;
+ case 1: if (severity > LOG_NOTICE) break;
+ case 2: if (severity > LOG_INFO ) break;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if(syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_NOTICE) {
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ if (syserr != 0) {
+ strcat(fmt, ": %m");
+ errno = syserr;
+ }
+ syslog(severity, fmt, a, b, c, d, e);
+
+ if (severity <= LOG_ERR) exit(-1);
+ }
+}
diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c
new file mode 100644
index 000000000000..cdc2e875611b
--- /dev/null
+++ b/usr.sbin/mrouted/mapper.c
@@ -0,0 +1,932 @@
+/* Mapper for connections between MRouteD multicast routers.
+ * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
+ *
+ * $Id: mapper.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+/*
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative
+ * works for research and evaluation purposes, provided that Xerox is
+ * acknowledged in all documentation pertaining to any such copy or derivative
+ * work. Xerox grants no other licenses expressed or implied. The Xerox trade
+ * name should not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
+ * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
+ * express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 1 /* How many times to ask each router */
+
+
+/* All IP addresses are stored in the data structure in NET order. */
+
+typedef struct neighbor {
+ struct neighbor *next;
+ u_long addr; /* IP address in NET order */
+ u_char metric; /* TTL cost of forwarding */
+ u_char threshold; /* TTL threshold to forward */
+ u_short flags; /* flags on connection */
+#define NF_PRESENT 0x8000 /* True if flags are meaningful */
+} Neighbor;
+
+typedef struct interface {
+ struct interface *next;
+ u_long addr; /* IP address of the interface in NET order */
+ Neighbor *neighbors; /* List of neighbors' IP addresses */
+} Interface;
+
+typedef struct node {
+ u_long addr; /* IP address of this entry in NET order */
+ u_long version; /* which mrouted version is running */
+ int tries; /* How many requests sent? -1 for aliases */
+ union {
+ struct node *alias; /* If alias, to what? */
+ struct interface *interfaces; /* Else, neighbor data */
+ } u;
+ struct node *left, *right;
+} Node;
+
+
+Node *routers = 0;
+u_long our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int show_names = TRUE;
+
+
+Node *find_node(addr, ptr)
+ u_long addr;
+ Node **ptr;
+{
+ Node *n = *ptr;
+
+ if (!n) {
+ *ptr = n = (Node *) malloc(sizeof(Node));
+ n->addr = addr;
+ n->version = 0;
+ n->tries = 0;
+ n->u.interfaces = 0;
+ n->left = n->right = 0;
+ return n;
+ } else if (addr == n->addr)
+ return n;
+ else if (addr < n->addr)
+ return find_node(addr, &(n->left));
+ else
+ return find_node(addr, &(n->right));
+}
+
+
+Interface *find_interface(addr, node)
+ u_long addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ if (ifc->addr == addr)
+ return ifc;
+
+ ifc = (Interface *) malloc(sizeof(Interface));
+ ifc->addr = addr;
+ ifc->next = node->u.interfaces;
+ node->u.interfaces = ifc;
+ ifc->neighbors = 0;
+
+ return ifc;
+}
+
+
+Neighbor *find_neighbor(addr, node)
+ u_long addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next)
+ if (nb->addr == addr)
+ return nb;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0: if (severity > LOG_WARNING) return;
+ case 1: if (severity > LOG_NOTICE ) return;
+ case 2: if (severity > LOG_INFO ) return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+
+/*
+ * Send a neighbors-list request.
+ */
+void ask(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void ask2(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group)
+ u_long src, dst, group;
+{
+ log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst)
+ u_long src, dst;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming route report message.
+ */
+void accept_report(src, dst, p, datalen)
+ u_long src, dst;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list request message.
+ */
+void accept_neighbor_request(src, dst)
+ u_long src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+void accept_neighbor_request2(src, dst)
+ u_long src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*p++ << 8), a += *p++)
+
+ /* if node is running a recent mrouted, ask for additional info */
+ if (level != 0) {
+ node->version = ntohl(level);
+ node->tries = 0;
+ ask2(src);
+ return;
+ }
+
+ if (debug > 3) {
+ int i;
+
+ fprintf(stderr, " datalen = %d\n", datalen);
+ for (i = 0; i < datalen; i++) {
+ if ((i & 0xF) == 0)
+ fprintf(stderr, " ");
+ fprintf(stderr, " %02x", p[i]);
+ if ((i & 0xF) == 0xF)
+ fprintf(stderr, "\n");
+ }
+ if ((datalen & 0xF) != 0xF)
+ fprintf(stderr, "\n");
+ }
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_long ifc_addr;
+ u_char metric, threshold, ncount;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 3) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(ifc_addr);
+ ifc_addr = htonl(ifc_addr);
+ metric = *p++;
+ threshold = *p++;
+ ncount = *p++;
+ datalen -= 4 + 3;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_long neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ datalen -= 4;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = 0;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+void accept_neighbors2(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_long ifc_addr;
+ u_char metric, threshold, ncount, flags;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 4) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ ifc_addr = *(u_long*)p;
+ p += 4;
+ metric = *p++;
+ threshold = *p++;
+ flags = *p++;
+ ncount = *p++;
+ datalen -= 4 + 4;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_long neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ neighbor = *(u_long*)p;
+ p += 4;
+ datalen -= 4;
+ if (neighbor == 0)
+ /* make leaf nets point to themselves */
+ neighbor = ifc_addr;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = flags | NF_PRESENT;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+
+void check_vif_state()
+{
+ log(LOG_NOTICE, 0, "network marked down...");
+}
+
+
+int retry_requests(node)
+ Node *node;
+{
+ int result;
+
+ if (node) {
+ result = retry_requests(node->left);
+ if (node->tries > 0 && node->tries < retries) {
+ if (node->version)
+ ask2(node->addr);
+ else
+ ask(node->addr);
+ node->tries++;
+ result = 1;
+ }
+ return retry_requests(node->right) || result;
+ } else
+ return 0;
+}
+
+
+char *inet_name(addr)
+ u_long addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : 0;
+}
+
+
+void print_map(node)
+ Node *node;
+{
+ if (node) {
+ char *name, *addr;
+
+ print_map(node->left);
+
+ addr = inet_fmt(node->addr, s1);
+ if (!target_addr
+ || (node->tries >= 0 && node->u.interfaces)
+ || (node->tries == -1
+ && node->u.alias->tries >= 0
+ && node->u.alias->u.interfaces)) {
+ if (show_names && (name = inet_name(node->addr)))
+ printf("%s (%s):", addr, name);
+ else
+ printf("%s:", addr);
+ if (node->tries < 0)
+ printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1));
+ else if (!node->u.interfaces)
+ printf(" no response to query\n\n");
+ else {
+ Interface *ifc;
+
+ if (node->version)
+ printf(" <v%d.%d>", node->version & 0xff,
+ (node->version >> 8) & 0xff);
+ printf("\n");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+ char *ifc_name = inet_fmt(ifc->addr, s1);
+ int ifc_len = strlen(ifc_name);
+ int count = 0;
+
+ printf(" %s:", ifc_name);
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ if (count > 0)
+ printf("%*s", ifc_len + 5, "");
+ printf(" %s", inet_fmt(nb->addr, s1));
+ if (show_names && (name = inet_name(nb->addr)))
+ printf(" (%s)", name);
+ printf(" [%d/%d", nb->metric, nb->threshold);
+ if (nb->flags) {
+ u_short flags = nb->flags;
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ }
+ printf("]\n");
+ count++;
+ }
+ }
+ printf("\n");
+ }
+ }
+ print_map(node->right);
+ }
+}
+
+
+char *graph_name(addr, buf)
+ u_long addr;
+ char *buf;
+{
+ char *name;
+
+ if (show_names && (name = inet_name(addr)))
+ strcpy(buf, name);
+ else
+ inet_fmt(addr, buf);
+
+ return buf;
+}
+
+
+void graph_edges(node)
+ Node *node;
+{
+ Interface *ifc;
+ Neighbor *nb;
+ char name[100];
+
+ if (node) {
+ graph_edges(node->left);
+ if (node->tries >= 0) {
+ printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
+ (int) node->addr,
+ node->addr & 0xFF, (node->addr >> 8) & 0xFF,
+ graph_name(node->addr, name),
+ node->u.interfaces ? "" : "*");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+ Neighbor *nb2;
+
+ if (nb_node->tries < 0)
+ nb_node = nb_node->u.alias;
+
+ if (node != nb_node &&
+ (!(nb2 = find_neighbor(node->addr, nb_node))
+ || node->addr < nb_node->addr)) {
+ printf(" %d \"%d/%d",
+ nb_node->addr, nb->metric, nb->threshold);
+ if (nb2 && (nb2->metric != nb->metric
+ || nb2->threshold != nb->threshold))
+ printf(",%d/%d", nb2->metric, nb2->threshold);
+ if (nb->flags & NF_PRESENT)
+ printf("%s%s",
+ nb->flags & DVMRP_NF_SRCRT ? "" :
+ nb->flags & DVMRP_NF_TUNNEL ? "E" : "P",
+ nb->flags & DVMRP_NF_DOWN ? "D" : "");
+ printf("\"\n");
+ }
+ }
+ printf(" ;\n");
+ }
+ graph_edges(node->right);
+ }
+}
+
+void elide_aliases(node)
+ Node *node;
+{
+ if (node) {
+ elide_aliases(node->left);
+ if (node->tries >= 0) {
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+
+ if (nb_node->tries < 0)
+ nb->addr = nb_node->u.alias->addr;
+ }
+ }
+ }
+ elide_aliases(node->right);
+ }
+}
+
+void graph_map()
+{
+ time_t now = time(0);
+ char *nowstr = ctime(&now);
+
+ nowstr[24] = '\0'; /* Kill the newline at the end */
+ elide_aliases(routers);
+ printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
+ nowstr);
+ graph_edges(routers);
+ printf("END\n");
+}
+
+
+int get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+u_long host_addr(name)
+ char *name;
+{
+ struct hostent *e = gethostbyname(name);
+ int addr;
+
+ if (e)
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(name);
+ if (addr == -1)
+ addr = 0;
+ }
+
+ return addr;
+}
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int flood = FALSE, graph = FALSE;
+
+#ifdef SYSV
+ setvbuf(stderr, NULL, _IOLBF, 0);
+#else
+ setlinebuf(stderr);
+#endif
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ goto usage;
+ break;
+ case 'f':
+ flood = TRUE;
+ break;
+ case 'g':
+ graph = TRUE;
+ break;
+ case 'n':
+ show_names = FALSE;
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ goto usage;
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ argv++, argc--;
+ }
+
+ if (argc > 1) {
+ usage:
+ fprintf(stderr,
+ "Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
+ "[-r retries] [-d [debug-level]] [router]");
+ fprintf(stderr, "\t-f Flood the routing graph with queries\n");
+ fprintf(stderr, "\t (True by default unless `router' is given)\n");
+ fprintf(stderr, "\t-g Generate output in GraphEd format\n");
+ fprintf(stderr, "\t-n Don't look up DNS names for routers\n");
+ exit(1);
+ } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) {
+ fprintf(stderr, "Unknown host: %s\n", argv[0]);
+ exit(2);
+ }
+
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dvmrp_group;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ /* Send initial seed message to all local routers */
+ ask(target_addr ? target_addr : allhosts_group);
+
+ if (target_addr) {
+ Node *n = find_node(target_addr, &routers);
+
+ n->tries = 1;
+
+ if (flood)
+ target_addr = 0;
+ }
+
+ /* Main receive loop */
+ for(;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (retry_requests(routers))
+ continue;
+ else
+ break;
+ }
+
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen >= 0)
+ accept_igmp(recvlen);
+ else if (errno != EINTR)
+ perror("recvfrom");
+ }
+
+ printf("\n");
+
+ if (graph)
+ graph_map();
+ else {
+ if (!target_addr)
+ printf("Multicast Router Connectivity:\n\n");
+ print_map(routers);
+ }
+
+ exit(0);
+}
diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c
new file mode 100644
index 000000000000..c9451348c09e
--- /dev/null
+++ b/usr.sbin/mrouted/mrinfo.c
@@ -0,0 +1,469 @@
+/*
+ * This tool requests configuration info from a multicast router
+ * and prints the reply (if any). Invoke it as:
+ *
+ * mrinfo router-name-or-address
+ *
+ * Written Wed Mar 24 1993 by Van Jacobson (adapted from the
+ * multicast mapper written by Pavel Curtis).
+ *
+ * The lawyers insist we include the following UC copyright notice.
+ * The mapper from which this is derived contained a Xerox copyright
+ * notice which follows the UC one. Try not to get depressed noting
+ * that the legal gibberish is larger than the program.
+ *
+ * Copyright (c) 1993 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ * ---------------------------------
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Xerox is acknowledged
+ * in all documentation pertaining to any such copy or derivative work. Xerox
+ * grants no other licenses expressed or implied. The Xerox trade name should
+ * not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
+ * ANY PARTICULAR PURPOSE. The software is provided "as is" without express
+ * or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Id: mrinfo.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $";
+/* original rcsid:
+ "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
+*/
+#endif
+
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to ask each router */
+
+u_long our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int target_level;
+
+char *
+inet_name(addr)
+ u_long addr;
+{
+ struct hostent *e;
+
+ if (addr == 0)
+ return "local";
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : "?";
+}
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void
+log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0:
+ if (severity > LOG_WARNING)
+ return;
+ case 1:
+ if (severity > LOG_NOTICE)
+ return;
+ case 2:
+ if (severity > LOG_INFO)
+ return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+/*
+ * Send a neighbors-list request.
+ */
+void
+ask(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void
+ask2(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void
+accept_neighbors(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*p++ << 8), a += *p++)
+
+ printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
+ while (p < ep) {
+ register u_long laddr;
+ register u_char metric;
+ register u_char thresh;
+ register int ncount;
+
+ GET_ADDR(laddr);
+ laddr = htonl(laddr);
+ metric = *p++;
+ thresh = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_long neighbor;
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ }
+ }
+}
+
+void
+accept_neighbors2(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+
+ printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
+ target_level & 0xff, (target_level >> 8) & 0xff);
+ while (p < ep) {
+ register u_char metric;
+ register u_char thresh;
+ register u_char flags;
+ register int ncount;
+ register u_long laddr = *(u_long*)p;
+
+ p += 4;
+ metric = *p++;
+ thresh = *p++;
+ flags = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_long neighbor = *(u_long*)p;
+ p += 4;
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ printf("]\n");
+ }
+ }
+}
+
+int
+get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next
+ * argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+u_long
+host_addr(name)
+ char *name;
+{
+ struct hostent *e = gethostbyname(name);
+ int addr;
+
+ if (e)
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(name);
+ if (addr == -1)
+ addr = 0;
+ }
+
+ return addr;
+}
+
+void
+usage()
+{
+ fprintf(stderr, "Usage: mrinfo [-t timeout] [-r retries] router\n");
+ exit(1);
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ setlinebuf(stderr);
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mrinfo: must be root\n");
+ exit(1);
+ }
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ usage();
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ usage();
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ usage();
+ break;
+ default:
+ usage();
+ }
+ argv++, argc--;
+ }
+ if (argc != 1)
+ usage();
+
+ target_addr = host_addr(argv[0]);
+ if (target_addr == 0) {
+ fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
+ exit(1);
+ }
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = target_addr;
+ addr.sin_port = htons(2000); /* any port over 1024 will
+ * do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ ask(target_addr);
+
+ /* Main receive loop */
+ for (;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+ register u_long src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (--retries < 0)
+ exit(1);
+ if (target_level == 0)
+ ask(target_addr);
+ else
+ ask2(target_addr);
+ continue;
+ }
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR)
+ perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "packet too short (%u bytes) for IP header",
+ recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ src = ip->ip_src.s_addr;
+ if (src != target_addr) {
+ fprintf(stderr, "mrinfo: got reply from %s",
+ inet_fmt(src, s1));
+ fprintf(stderr, " instead of %s\n",
+ inet_fmt(target_addr, s1));
+ continue;
+ }
+ dst = ip->ip_dst.s_addr;
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ continue;
+ }
+ if (igmp->igmp_type != IGMP_DVMRP)
+ continue;
+
+ switch (igmp->igmp_code) {
+
+ case DVMRP_NEIGHBORS:
+ if (group) {
+ /* knows about DVMRP_NEIGHBORS2 msg */
+ if (target_level == 0) {
+ target_level = ntohl(group);
+ ask2(target_addr);
+ }
+ } else {
+ accept_neighbors(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ break;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ }
+}
+
+/* dummies */
+void accept_probe()
+{
+}
+void accept_group_report()
+{
+}
+void accept_neighbor_request2()
+{
+}
+void accept_report()
+{
+}
+void accept_neighbor_request()
+{
+}
+void check_vif_state()
+{
+}
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
new file mode 100644
index 000000000000..5013bc7c9e5b
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.8
@@ -0,0 +1,242 @@
+'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
+.TH MROUTED 8
+.UC 5
+.SH NAME
+mrouted \- IP multicast routing daemon
+.SH SYNOPSIS
+.B /etc/mrouted
+[
+.B \-c
+.I config_file
+] [
+.B \-d
+[
+.I debug_level
+] ]
+.SH DESCRIPTION
+.I Mrouted
+is an implementation of the Distance-Vector Multicast Routing
+Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
+It maintains topological knowledge via a distance-vector routing protocol
+(like RIP, described in RFC-1058), upon which it implements a multicast
+forwarding algorithm called Truncated Reverse Path Broadcasting (TRPB).
+.PP
+.I Mrouted
+forwards a multicast datagram along a shortest (reverse) path tree
+rooted at the subnet on which the datagram originates. It is a
+.I broadcast
+tree, which means it includes
+.I all
+subnets reachable by a cooperating set of
+.I mrouted
+routers. However, the datagram will not be forwarded onto
+.I leaf
+subnets of the tree if those subnets do not have members of the destination
+group. Furthermore, the IP time-to-live of a multicast datagram may prevent
+it from being forwarded along the entire tree.
+.PP
+In order to support multicasting among subnets that are separated by (unicast)
+routers that do not support IP multicasting,
+.I mrouted
+includes support for
+"tunnels", which are virtual point-to-point links between pairs of
+.IR mrouted s
+located anywhere in an internet. IP multicast packets are encapsulated for
+transmission through tunnels, so that they look like normal unicast datagrams
+to intervening routers and subnets. The encapsulation
+is inserted on entry to a tunnel, and stripped out
+on exit from a tunnel.
+By default, the packets are encapsulated using the IP-in-IP protocol
+(IP protocol number 4).
+Older versions of
+.I mrouted
+encapsulate using IP source routing, which puts a heavy load on some
+types of routers.
+This version supports IP source route encapsulation only for backwards
+compatibility.
+.PP
+The tunnel mechanism allows
+.I mrouted
+to establish a virtual internet, for
+the purpose of multicasting only, which is independent of the physical
+internet, and which may span multiple Autonomous Systems. This capability
+is intended for experimental support of internet multicasting only, pending
+widespread support for multicast routing by the regular (unicast) routers.
+.I Mrouted
+suffers from the well-known scaling problems of any distance-vector
+routing protocol, and does not (yet) support hierarchical multicast routing
+or inter-operation with other multicast routing protocols.
+.PP
+.I Mrouted
+handles multicast routing only; there may or may not be a unicast
+router running on the same host as
+.IR mrouted .
+With the use of tunnels, it
+is not necessary for
+.I mrouted
+to have access to more than one physical subnet
+in order to perform multicast forwarding.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+If no "\-d" option is given, or if the debug level is specified as 0,
+.I mrouted
+detaches from the invoking terminal. Otherwise, it remains attached to the
+invoking terminal and responsive to signals from that terminal. If "\-d" is
+given with no argument, the debug level defaults to 2. Regardless of the
+debug level,
+.I mrouted
+always writes warning and error messages to the system
+log demon. Non-zero debug levels have the following effects:
+.IP "level 1"
+all syslog'ed messages are also printed to stderr.
+.IP "level 2"
+all level 1 messages plus notifications of "significant"
+events are printed to stderr.
+.IP "level 3"
+all level 2 messages plus notifications of all packet
+arrivals and departures are printed to stderr.
+.SH CONFIGURATION
+.PP
+.I Mrouted
+automatically configures itself to forward on all multicast-capable
+interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
+the loopback "interface"), and it finds other
+.IR mrouted s
+directly reachable
+via those interfaces. To override the default configuration, or to add
+tunnel links to other
+.IR mrouted s,
+configuration commands may be placed in
+/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
+There are two types of configuration command:
+.nf
+
+ phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+
+ tunnel <local-addr> <remote-addr> [metric <m>] [threshold <t>] [srcrt]
+
+.fi
+The phyint command can be used to disable multicast routing on the physical
+interface identified by local IP address <local-addr>, or to associate a
+non-default metric or threshold with the specified physical interface.
+Phyint commands must precede tunnel commands.
+.PP
+The tunnel command can be used to establish a tunnel link between local
+IP address <local-addr> and remote IP address <remote-addr>, and to associate
+a non-default metric or threshold with that tunnel. The tunnel must be set
+up in the mrouted.conf files of both ends before it will be used.
+For backwards compatibility with older
+.IR mrouted s,
+the srcrt keyword specifies
+encapsulation using IP source routing.
+.PP
+The metric is the "cost" associated with sending a datagram on the given
+interface or tunnel; it may be used to influence the choice of routes.
+The metric defaults to 1. Metrics should be kept as small as possible,
+because
+.I mrouted
+cannot route along paths with a sum of metrics greater
+than 31. When in doubt, the following metrics are recommended:
+.ne 5
+.IP 1
+LAN, or tunnel across a single LAN
+.IP 2
+serial link, or tunnel across a single serial link
+.IP 3
+multi-hop tunnel
+.LP
+The threshold is the minimum IP time-to-live required for a multicast datagram
+to be forwarded to the given interface or tunnel. It is used to control the
+scope of multicast datagrams. (The TTL of forwarded packets is only compared
+to the threshold, it is not decremented by the threshold. Every multicast
+router decrements the TTL by 1.) The default threshold is 1.
+Suggested thresholds:
+.IP 32
+for links that separate sites,
+.IP 64
+for links that separate regions,
+.IP 128
+for links that separate continents.
+.LP
+In general, all
+.IR mrouted s
+connected to a particular subnet or tunnel should
+use the same metric and threshold for that subnet or tunnel.
+.PP
+.I Mrouted
+will not initiate execution if it has fewer than two enabled vifs,
+where a vif (virtual interface) is either a physical multicast-capable
+interface or a tunnel. It will log a warning if all of its vifs are
+tunnels; such an
+.I mrouted
+configuration would be better replaced by more
+direct tunnels (i.e., eliminate the middle man).
+.SH SIGNALS
+.PP
+.I Mrouted
+responds to the following signals:
+.IP HUP
+.sp -.5v
+.IP TERM
+.sp -.5v
+.IP INT
+terminates execution gracefully (i.e., by sending
+good-bye messages to all neighboring routers).
+.IP USR1
+dumps the internal routing tables to /usr/tmp/mrouted.dump.
+.IP QUIT
+dumps the internal routing tables to stderr (only if
+.I mrouted
+was invoked with a non-zero debug level).
+.bp
+.SH EXAMPLE
+.PP
+The routing tables look like this:
+.nf
+
+Virtual Interface Table
+ Vif Local-Address Metric Thresh Flags
+ 0 36.2.0.8 subnet: 36.2 1 1 querier
+ groups: 224.0.2.1
+ 224.0.0.4
+ 1 36.11.0.1 subnet: 36.11 1 1 querier
+ groups: 224.0.2.1
+ 224.0.1.0
+ 224.0.0.4
+ 2 36.2.0.8 tunnel: 36.8.0.77 3 1
+ peers : 36.8.0.77
+ 3 36.2.0.8 tunnel: 36.8.0.110 3 1
+
+Multicast Routing Table
+ Origin-Subnet From-Gateway Metric In-Vif Out-Vifs
+ 36.2 1 0 1* 2 3*
+ 36.8 36.8.0.77 4 2 0* 1* 3*
+ 36.11 1 1 0* 2 3*
+
+.fi
+In this example, there are four vifs connecting to two subnets and two
+tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
+vif 1 subnets have some groups present; tunnels never have any groups. This
+instance of
+.I mrouted
+is the one responsible for sending periodic group
+membership queries on the vif 0 and vif 1 subnets, as indicated by the
+"querier" flags.
+.PP
+Associated with each subnet from which a multicast datagram can originate
+is the address of the previous hop gateway (unless the subnet is directly-
+connected), the metric of the path back to the origin, the incoming vif for
+multicasts from that origin, and a list of outgoing vifs. "*" means that
+the outgoing vif is connected to a leaf of the broadcast tree rooted at the
+origin, and a multicast datagram from that origin will be forwarded on that
+outgoing vif only if there are members of the destination group on that leaf.
+.SH FILES
+/etc/mrouted.conf
+.SH SEE ALSO
+TRPB is described, along with other multicast routing algorithms, in the
+paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
+in the Proceedings of the ACM SIGCOMM '88 Conference.
+.SH AUTHOR
+Steve Deering
diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf
new file mode 100644
index 000000000000..6629d4d1a8f8
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.conf
@@ -0,0 +1,15 @@
+# $Id: mrouted.conf,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+#
+# This is the configuration file for "mrouted", an IP multicast router.
+# mrouted looks for it in "/etc/mrouted.conf".
+#
+# Command formats:
+#
+# phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
+#
+# any phyint commands MUST precede any tunnel commands
+#
+# See the Mbone FAQ on ftp.isi.edu for metric, thresholds and connection info.
+#
+tunnel 129.89.9.63 129.89.9.50 metric 3 threshold 64 # <-- EXAMPLE; REPLACE OR DELETE
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
new file mode 100644
index 000000000000..d31165b1becd
--- /dev/null
+++ b/usr.sbin/mrouted/route.c
@@ -0,0 +1,900 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: route.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+int routes_changed; /* 1=>some routes have changed */
+int delay_change_reports; /* 1=>postpone change reports */
+
+
+/*
+ * Private variables.
+ */
+static struct rtentry *routing_table; /* pointer to list of route entries */
+static struct rtentry *rtp; /* pointer to a route entry */
+static unsigned nroutes; /* current number of route entries */
+
+
+/*
+ * Initialize the routing table and associated variables.
+ */
+void init_routes()
+{
+ routing_table = NULL;
+ nroutes = 0;
+ routes_changed = FALSE;
+ delay_change_reports = FALSE;
+}
+
+
+/*
+ * Initialize the children and leaf bits for route 'r', along with the
+ * associated dominant, subordinate, and leaf timing data structures.
+ * Return TRUE if this changes the value of either the children or
+ * leaf bitmaps for 'r'.
+ */
+static int init_children_and_leaves(r, parent)
+ register struct rtentry *r;
+ register vifi_t parent;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ vifbitmap_t old_children, old_leaves;
+
+ VIFM_COPY(r->rt_children, old_children);
+ VIFM_COPY(r->rt_leaves, old_leaves );
+
+ VIFM_CLRALL(r->rt_children);
+ VIFM_CLRALL(r->rt_leaves);
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+
+ if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ VIFM_SET(vifi, r->rt_children);
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else {
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ }
+
+ return (!VIFM_SAME(r->rt_children, old_children) ||
+ !VIFM_SAME(r->rt_leaves, old_leaves));
+}
+
+
+/*
+ * A new vif has come up -- update the children and leaf bitmaps in all route
+ * entries to take that into account.
+ */
+void add_vif_to_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE &&
+ !VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ }
+}
+
+
+/*
+ * A vif has gone down -- expire all routes that have that vif as parent,
+ * and update the children bitmaps in all other route entries to take into
+ * account the failed vif.
+ */
+void delete_vif_from_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (vifi == r->rt_parent) {
+ k_del_route(r);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ else {
+ r->rt_dominants[vifi] = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * A neighbor has failed or become unreachable. If that neighbor was
+ * considered a dominant or subordinate router in any route entries,
+ * take appropriate action.
+ */
+void delete_neighbor_from_routes(addr, vifi)
+ register u_long addr;
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (r->rt_dominants[vifi] == addr) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ else if (r->rt_subordinates[vifi] == addr) {
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else if (v->uv_neighbors == NULL &&
+ r->rt_leaf_timers[vifi] != 0) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ k_update_route(r);
+ }
+ }
+ }
+}
+
+
+/*
+ * Prepare for a sequence of ordered route updates by initializing a pointer
+ * to the start of the routing table. The pointer is used to remember our
+ * position in the routing table in order to avoid searching from the
+ * beginning for each update; this relies on having the route reports in
+ * a single message be in the same order as the route entries in the routing
+ * table.
+ */
+void start_route_updates()
+{
+ rtp = (struct rtentry *)&routing_table;
+}
+
+
+/*
+ * Starting at the route entry following the one to which 'rtp' points,
+ * look for a route entry matching the specified origin and mask. If a
+ * match is found, return TRUE and leave 'rtp' pointing at the found entry.
+ * If no match is found, return FALSE and leave 'rtp' pointing to the route
+ * entry preceding the point at which the new origin should be inserted.
+ * This code is optimized for the normal case in which the first entry to
+ * be examined is the matching entry.
+ */
+static int find_route(origin, mask)
+ register u_long origin, mask;
+{
+ register struct rtentry *r;
+
+ r = rtp->rt_next;
+ while (r != NULL) {
+ if (origin == r->rt_origin && mask == r->rt_originmask) {
+ rtp = r;
+ return (TRUE);
+ }
+ if (ntohl(mask) > ntohl(r->rt_originmask) ||
+ (mask == r->rt_originmask &&
+ ntohl(origin) > ntohl(r->rt_origin))) {
+ rtp = r;
+ r = r->rt_next;
+ }
+ else break;
+ }
+ return (FALSE);
+}
+
+
+/*
+ * Search the entire routing table, looking for an entry which conflicts
+ * with the given origin and mask, for example, an entry which has the same
+ * origin under a different mask. If a conflicting entry is found, return
+ * a pointer to the entry preceding it (to facilitate deletion); if no
+ * conflict is found, return NULL.
+ */
+static struct rtentry *find_conflicting_route(origin, mask)
+ register u_long origin, mask;
+{
+ register struct rtentry *r, *prev_r;
+
+ for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next ) {
+ if ((origin & r->rt_originmask) == r->rt_origin ||
+ (r->rt_origin & mask) == origin) {
+ return (prev_r);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * Create a new routing table entry for the specified origin and link it into
+ * the routing table. The shared variable 'rtp' is assumed to point to the
+ * routing entry after which the new one should be inserted. It is left
+ * pointing to the new entry.
+ *
+ * Only the origin, originmask, originwidth and flags fields are initialized
+ * in the new route entry; the caller is responsible for filling in the the
+ * rest.
+ */
+static void create_route(origin, mask)
+ u_long origin, mask;
+{
+ register struct rtentry *r;
+
+ if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
+ + (3 * numvifs * sizeof(u_long)))) == NULL) {
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+ }
+ r->rt_origin = origin;
+ r->rt_originmask = mask;
+ if (((char *)&mask)[3] != 0) r->rt_originwidth = 4;
+ else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3;
+ else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
+ else r->rt_originwidth = 1;
+ r->rt_flags = 0;
+ r->rt_dominants = (u_long *)(r + 1);
+ r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
+ r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
+
+ r->rt_next = rtp->rt_next;
+ rtp->rt_next = r;
+ rtp = r;
+ ++nroutes;
+}
+
+
+/*
+ * Discard the routing table entry following the one to which 'prev_r' points.
+ */
+static void discard_route(prev_r)
+ register struct rtentry *prev_r;
+{
+ register struct rtentry *r;
+
+ r = prev_r->rt_next;
+ prev_r->rt_next = r->rt_next;
+ free((char *)r);
+ --nroutes;
+}
+
+
+/*
+ * Process a route report for a single origin, creating or updating the
+ * corresponding routing table entry if necessary. 'src' is either the
+ * address of a neighboring router from which the report arrived, or zero
+ * to indicate a change of status of one of our own interfaces.
+ */
+void update_route(origin, mask, metric, src, vifi)
+ u_long origin, mask;
+ int metric;
+ u_long src;
+ vifi_t vifi;
+{
+ register struct rtentry *r;
+ struct rtentry *prev_r;
+ int adj_metric;
+
+ /*
+ * Compute an adjusted metric, taking into account the cost of the
+ * subnet or tunnel over which the report arrived, and normalizing
+ * all unreachable/poisoned metrics into a single value.
+ */
+ if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
+ log(LOG_WARNING, 0,
+ "%s reports out-of-range metric %u for origin %s",
+ inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2));
+ return;
+ }
+ adj_metric = metric + uvifs[vifi].uv_metric;
+ if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;
+
+ /*
+ * Look up the reported origin in the routing table.
+ */
+ if (!find_route(origin, mask)) {
+ /*
+ * Not found.
+ * Don't create a new entry if the report says it's unreachable,
+ * or if the reported origin and mask are invalid.
+ */
+ if (adj_metric == UNREACHABLE) {
+ return;
+ }
+ if (src != 0 && !inet_valid_subnet(origin, mask)) {
+ log(LOG_WARNING, 0,
+ "%s reports an invalid origin (%s) and/or mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+
+ /*
+ * If the new origin and mask are inconsistent with an entry
+ * already in the routing table, either ignore this update
+ * (if it came from another router), or delete the conflicting
+ * entry (if the update is for a directly-connected subnet).
+ */
+ if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) {
+ if (src != 0) {
+ log(LOG_WARNING, 0,
+ "%s reports a conflicting origin (%s) and mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+ else {
+ r = prev_r->rt_next;
+ log(LOG_WARNING, 0,
+ "deleting route with conflicting origin (%s), mask (%08x)",
+ inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask));
+
+ if (r->rt_metric != UNREACHABLE) {
+ k_del_route(r);
+ }
+ discard_route(prev_r);
+ if (rtp == r) rtp = prev_r;
+ }
+ }
+
+ /*
+ * OK, create the new routing entry. 'rtp' will be left pointing
+ * to the new entry.
+ */
+ create_route(origin, mask);
+
+ rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
+ }
+
+ /*
+ * We now have a routing entry for the reported origin. Update it?
+ */
+ r = rtp;
+ if (r->rt_metric == UNREACHABLE) {
+ /*
+ * The routing entry is for a formerly-unreachable or new origin.
+ * If the report claims reachability, update the entry to use
+ * the reported route.
+ */
+ if (adj_metric == UNREACHABLE)
+ return;
+
+ r->rt_parent = vifi;
+ init_children_and_leaves(r, vifi);
+ k_add_route(r);
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (src == r->rt_gateway) {
+ /*
+ * The report has come either from the interface directly-connected
+ * to the origin subnet (src and r->rt_gateway both equal zero) or
+ * from the gateway we have chosen as the best first-hop gateway back
+ * towards the origin (src and r->rt_gateway not equal zero). Reset
+ * the route timer and, if the reported metric has changed, update
+ * our entry accordingly.
+ */
+ r->rt_timer = 0;
+ if (adj_metric == r->rt_metric)
+ return;
+
+ if (adj_metric == UNREACHABLE) {
+ k_del_route(r);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ }
+ else if (adj_metric < r->rt_metric) {
+ if (init_children_and_leaves(r, vifi)) {
+ k_update_route(r);
+ }
+ }
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (src == 0 ||
+ (r->rt_gateway != 0 &&
+ (adj_metric < r->rt_metric ||
+ (adj_metric == r->rt_metric &&
+ r->rt_timer >= ROUTE_SWITCH_TIME)))) {
+ /*
+ * The report is for an origin we consider reachable; the report
+ * comes either from one of our own interfaces or from a gateway
+ * other than the one we have chosen as the best first-hop gateway
+ * back towards the origin. If the source of the update is one of
+ * our own interfaces, or if the origin is not a directly-connected
+ * subnet and the reported metric for that origin is better than
+ * what our routing entry says, update the entry to use the new
+ * gateway and metric. We also switch gateways if the reported
+ * metric is the same as the one in the route entry and the gateway
+ * associated with the route entry has not been heard from recently.
+ * Did you get all that?
+ */
+ if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
+ r->rt_parent = vifi;
+ if (init_children_and_leaves(r, vifi)) {
+ k_update_route(r);
+ }
+ }
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (vifi != r->rt_parent) {
+ /*
+ * The report came from a vif other than the route's parent vif.
+ * Update the children and leaf info, if necessary.
+ */
+ if (VIFM_ISSET(vifi, r->rt_children)) {
+ /*
+ * Vif is a child vif for this route.
+ */
+ if (metric < r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
+ /*
+ * Neighbor has lower metric to origin (or has same metric
+ * and lower IP address) -- it becomes the dominant router,
+ * and vif is no longer a child for me.
+ */
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_dominants [vifi] = src;
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ else if (metric > UNREACHABLE) { /* "poisoned reverse" */
+ /*
+ * Neighbor considers this vif to be on path to route's
+ * origin; if no subordinate recorded, record this neighbor
+ * as subordinate and clear the leaf flag.
+ */
+ if (r->rt_subordinates[vifi] == 0) {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = src;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ }
+ else if (src == r->rt_subordinates[vifi]) {
+ /*
+ * Current subordinate no longer considers this vif to be on
+ * path to route's origin; it is no longer a subordinate
+ * router, and we set the leaf confirmation timer to give
+ * us time to hear from other subordinates.
+ */
+ r->rt_subordinates[vifi] = 0;
+ if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+
+ }
+ else if (src == r->rt_dominants[vifi] &&
+ (metric > r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
+ /*
+ * Current dominant no longer has a lower metric to origin
+ * (or same metric and lower IP address); we adopt the vif
+ * as our own child.
+ */
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ if (metric > UNREACHABLE) {
+ r->rt_subordinates[vifi] = src;
+ }
+ else if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ }
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each routing entry.
+ */
+void age_routes()
+{
+ register struct rtentry *r;
+ register struct rtentry *prev_r;
+ register vifi_t vifi;
+
+ for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next) {
+
+ if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) {
+ /*
+ * Route is still good; see if any leaf timers need to be
+ * advanced.
+ */
+ if (r->rt_flags & RTF_LEAF_TIMING) {
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+ for (vifi = 0; vifi < numvifs; ++vifi) {
+ if (r->rt_leaf_timers[vifi] != 0) {
+ /*
+ * Unlike other timers, leaf timers decrement.
+ */
+ if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ }
+ }
+ }
+ else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
+ /*
+ * Time to garbage-collect the route entry.
+ */
+ discard_route(prev_r);
+ r = prev_r;
+ }
+ else if (r->rt_metric != UNREACHABLE) {
+ /*
+ * Time to expire the route entry. If the gateway is zero,
+ * i.e., it is a route to a directly-connected subnet, just
+ * set the timer back to zero; such routes expire only when
+ * the interface to the subnet goes down.
+ */
+ if (r->rt_gateway == 0) {
+ r->rt_timer = 0;
+ }
+ else {
+ k_del_route(r);
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Mark all routes as unreachable. This function is called only from
+ * hup() in preparation for informing all neighbors that we are going
+ * off the air. For consistency, we ought also to delete all reachable
+ * route entries from the kernel, but since we are about to exit we rely
+ * on the kernel to do its own cleanup -- no point in making all those
+ * expensive kernel calls now.
+ */
+void expire_all_routes()
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring probe from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_PROBE))
+ return;
+
+ report(ALL_ROUTES, vifi, src);
+}
+
+
+/*
+ * Process an incoming route report message.
+ */
+void accept_report(src, dst, p, datalen)
+ u_long src, dst;
+ register char *p;
+ register int datalen;
+{
+ vifi_t vifi;
+ register int width, i;
+ int metric;
+ u_long mask;
+ u_long origin;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring route report from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_REPORT))
+ return;
+
+ start_route_updates();
+
+ while (datalen > 0) { /* Loop through per-mask lists. */
+
+ if (datalen < 3) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s", inet_fmt(src, s1));
+ return;
+ }
+ ((char *)&mask)[0] = 0xff; width = 1;
+ if ((((char *)&mask)[1] = *p++) != 0) width = 2;
+ if ((((char *)&mask)[2] = *p++) != 0) width = 3;
+ if ((((char *)&mask)[3] = *p++) != 0) width = 4;
+ datalen -= 3;
+
+ do { /* Loop through (origin, metric) pairs */
+
+ if (datalen < width + 1) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s", inet_fmt(src, s1));
+ return;
+ }
+ origin = 0;
+ for (i = 0; i < width; ++i)
+ ((char *)&origin)[i] = *p++;
+ metric = *p++;
+ datalen -= width + 1;
+
+ update_route(origin, mask, (metric & 0x7f), src, vifi);
+
+ } while (!(metric & 0x80));
+ }
+
+ if (routes_changed && !delay_change_reports)
+ report_to_all_neighbors(CHANGED_ROUTES);
+}
+
+
+/*
+ * Send a route report message to destination 'dst', via virtual interface
+ * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void report(which_routes, vifi, dst)
+ int which_routes;
+ vifi_t vifi;
+ u_long dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ int datalen;
+ int width;
+ u_long mask;
+ u_long src;
+
+ src = uvifs[vifi].uv_lcl_addr;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
+ continue;
+
+ /*
+ * If there is no room for this route in the current message,
+ * send the message and start a new one.
+ */
+ if (datalen + ((r->rt_originmask == mask) ?
+ (width + 1) :
+ (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+ }
+
+ if(r->rt_originmask != mask) {
+ mask = r->rt_originmask;
+ width = r->rt_originwidth;
+ if (datalen != 0) *(p-1) |= 0x80;
+ *p++ = ((char *)&mask)[1];
+ *p++ = ((char *)&mask)[2];
+ *p++ = ((char *)&mask)[3];
+ datalen += 3;
+ }
+
+ for (i = 0; i < width; ++i)
+ *p++ = ((char *)&(r->rt_origin))[i];
+
+ *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
+ (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
+ (char)(r->rt_metric);
+
+ datalen += width + 1;
+ }
+
+ if (datalen != 0) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+ }
+}
+
+
+/*
+ * Send a route report message to all neighboring routers.
+ * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void report_to_all_neighbors(which_routes)
+ int which_routes;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct rtentry *r;
+ int routes_changed_before;
+
+ /*
+ * Remember the state of the global routes_changed flag before
+ * generating the reports, and clear the flag.
+ */
+ routes_changed_before = routes_changed;
+ routes_changed = FALSE;
+
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_neighbors != NULL) {
+ report(which_routes, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group);
+ }
+ }
+
+ /*
+ * If there were changed routes before we sent the reports AND
+ * if no new changes occurred while sending the reports, clear
+ * the change flags in the individual route entries. If changes
+ * did occur while sending the reports, new reports will be
+ * generated at the next timer interrupt.
+ */
+ if (routes_changed_before && !routes_changed) {
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_flags &= ~RTF_CHANGED;
+ }
+ }
+
+ /*
+ * Set a flag to inhibit further reports of changed routes until the
+ * next timer interrupt. This is to alleviate update storms.
+ */
+ delay_change_reports = TRUE;
+}
+
+
+/*
+ * Print the contents of the routing table on file 'fp'.
+ */
+void dump_routes(fp)
+ FILE *fp;
+{
+ register struct rtentry *r;
+ register int i;
+
+ fprintf(fp,
+ "Multicast Routing Table (%u %s)\n%s",
+ nroutes, (nroutes == 1) ? "entry" : "entries",
+ " Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ fprintf(fp, " %-15s %-15s ",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
+
+ fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
+ r->rt_metric);
+
+ fprintf(fp, "%7u ",
+ r->rt_parent);
+
+ for (i = 0; i < numvifs; ++i) {
+ if (VIFM_ISSET(i, r->rt_children)) {
+ fprintf(fp, " %u%c",
+ i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h
new file mode 100644
index 000000000000..03ee8c656cfe
--- /dev/null
+++ b/usr.sbin/mrouted/route.h
@@ -0,0 +1,50 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: route.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * Routing Table Entry, one per subnet from which a multicast could originate.
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ *
+ * The Routing Table is stored as a singly-linked list of these structures,
+ * ordered by increasing value of rt_originmask and, secondarily, by
+ * increasing value of rt_origin within each rt_originmask value.
+ * This data structure is efficient for generating route reports, whether
+ * full or partial, for processing received full reports, for clearing the
+ * CHANGED flags, and for periodically advancing the timers in all routes.
+ * It is not so efficient for updating a small number of routes in response
+ * to a partial report. In a stable topology, the latter are rare; if they
+ * turn out to be costing a lot, we can add an auxiliary hash table for
+ * faster access to arbitrary route entries.
+ */
+struct rtentry {
+ struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
+ u_long rt_origin; /* subnet origin of multicasts */
+ u_long rt_originmask; /* subnet mask for origin */
+ short rt_originwidth; /* # bytes of origin subnet number */
+ u_char rt_metric; /* cost of route back to origin */
+ u_char rt_flags; /* RTF_ flags defined below */
+ u_long rt_gateway; /* first-hop gateway back to origin */
+ vifi_t rt_parent; /* incoming vif (ie towards origin) */
+ vifbitmap_t rt_children; /* outgoing children vifs */
+ vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
+ u_long *rt_dominants; /* per vif dominant gateways */
+ u_long *rt_subordinates; /* per vif subordinate gateways */
+ u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
+ u_long rt_timer; /* for timing out the route entry */
+};
+
+#define RTF_CHANGED 0x01 /* route changed but not reported */
+#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
+
+
+#define ALL_ROUTES 0 /* possible arguments to report() */
+#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c
new file mode 100644
index 000000000000..5a55dd41654b
--- /dev/null
+++ b/usr.sbin/mrouted/vif.c
@@ -0,0 +1,782 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: vif.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
+vifi_t numvifs; /* number of vifs in use */
+int vifs_down; /* 1=>some interfaces are down */
+int udp_socket; /* Since the honkin' kernel doesn't support */
+ /* ioctls on raw IP sockets, we need a UDP */
+ /* socket as well as our IGMP (raw) socket. */
+ /* How dumb. */
+
+/*
+ * Forward declarations.
+ */
+static void start_vif();
+static void stop_vif();
+
+
+/*
+ * Initialize the virtual interfaces.
+ */
+void init_vifs()
+{
+ vifi_t vifi;
+ struct uvif *v;
+ int enabled_vifs, enabled_phyints;
+
+ numvifs = 0;
+ vifs_down = FALSE;
+
+ /*
+ * Configure the vifs based on the interface configuration of the
+ * the kernel and the contents of the configuration file.
+ * (Open a UDP socket for ioctl use in the config procedures.)
+ */
+ if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "UDP socket");
+ config_vifs_from_kernel();
+ config_vifs_from_file();
+
+ /*
+ * Quit if there are fewer than two enabled vifs.
+ */
+ enabled_vifs = 0;
+ enabled_phyints = 0;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ ++enabled_vifs;
+ if (!(v->uv_flags & VIFF_TUNNEL))
+ ++enabled_phyints;
+ }
+ }
+ if (enabled_vifs < 2)
+ log(LOG_ERR, 0, "can't forward: %s",
+ enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
+
+ if (enabled_phyints == 0)
+ log(LOG_WARNING, 0,
+ "no enabled interfaces, forwarding via tunnels only");
+
+ /*
+ * Start routing on all virtual interfaces that are not down or
+ * administratively disabled.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (!(v->uv_flags & VIFF_DOWN))
+ start_vif(vifi);
+ else log(LOG_INFO, 0,
+ "%s is not yet up; vif #%u not in service",
+ v->uv_name, vifi);
+ }
+ }
+}
+
+
+/*
+ * See if any interfaces have changed from up state to down, or vice versa,
+ * including any non-multicast-capable interfaces that are in use as local
+ * tunnel end-points. Ignore interfaces that have been administratively
+ * disabled.
+ */
+void check_vif_state()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ struct ifreq ifr;
+
+ vifs_down = FALSE;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+
+ if (v->uv_flags & VIFF_DISABLED) continue;
+
+ strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+
+ if (v->uv_flags & VIFF_DOWN) {
+ if (ifr.ifr_flags & IFF_UP) {
+ v->uv_flags &= ~VIFF_DOWN;
+ start_vif(vifi);
+ log(LOG_INFO, 0,
+ "%s has come up; vif #%u now in service",
+ v->uv_name, vifi);
+ }
+ else vifs_down = TRUE;
+ }
+ else {
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ stop_vif(vifi);
+ v->uv_flags |= VIFF_DOWN;
+ log(LOG_INFO, 0,
+ "%s has gone down; vif #%u taken out of service",
+ v->uv_name, vifi);
+ vifs_down = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Start routing on the specified virtual interface.
+ */
+static void start_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ u_long src, dst;
+
+ v = &uvifs[vifi];
+ src = v->uv_lcl_addr;
+ dst = (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr : dvmrp_group;
+
+ /*
+ * Install the interface in the kernel's vif structure.
+ */
+ k_add_vif(vifi, &uvifs[vifi]);
+
+ /*
+ * Update the existing route entries to take into account the new vif.
+ */
+ add_vif_to_routes(vifi);
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Join the DVMRP multicast group on the interface.
+ * (This is not strictly necessary, since the kernel promiscuously
+ * receives IGMP packets addressed to ANY IP multicast group while
+ * multicast routing is enabled. However, joining the group allows
+ * this host to receive non-IGMP packets as well, such as 'pings'.)
+ */
+ k_join(dvmrp_group, src);
+
+ /*
+ * Install an entry in the routing table for the subnet to which
+ * the interface is connected.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
+
+ /*
+ * Until neighbors are discovered, assume responsibility for sending
+ * periodic group membership queries to the subnet. Send the first
+ * query.
+ */
+ v->uv_flags |= VIFF_QUERIER;
+ send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0);
+ }
+
+ /*
+ * Send a probe via the new vif to look for neighbors.
+ */
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0);
+}
+
+
+/*
+ * Stop routing on the specified virtual interface.
+ */
+static void stop_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ struct listaddr *a;
+
+ v = &uvifs[vifi];
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Depart from the DVMRP multicast group on the interface.
+ */
+ k_leave(dvmrp_group, v->uv_lcl_addr);
+
+ /*
+ * Update the entry in the routing table for the subnet to which
+ * the interface is connected, to take into account the interface
+ * failure.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
+
+ /*
+ * Discard all group addresses. (No need to tell kernel;
+ * the k_del_vif() call, below, will clean up kernel state.)
+ */
+ while (v->uv_groups != NULL) {
+ a = v->uv_groups;
+ v->uv_groups = a->al_next;
+ free((char *)a);
+ }
+
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ /*
+ * Update the existing route entries to take into account the vif failure.
+ */
+ delete_vif_from_routes(vifi);
+
+ /*
+ * Delete the interface from the kernel's vif structure.
+ */
+ k_del_vif(vifi);
+
+ /*
+ * Discard all neighbor addresses.
+ */
+ while (v->uv_neighbors != NULL) {
+ a = v->uv_neighbors;
+ v->uv_neighbors = a->al_next;
+ free((char *)a);
+ }
+}
+
+
+/*
+ * Find the virtual interface from which an incoming packet arrived,
+ * based on the packet's source and destination IP addresses.
+ */
+vifi_t find_vif(src, dst)
+ register u_long src;
+ register u_long dst;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr)
+ return(vifi);
+ }
+ else {
+ if ((src & v->uv_subnetmask) == v->uv_subnet &&
+ src != v->uv_subnetbcast)
+ return(vifi);
+ }
+ }
+ }
+ return (NO_VIF);
+}
+
+
+/*
+ * Send group membership queries to all subnets for which I am querier.
+ */
+void query_groups()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_QUERIER) {
+ send_igmp(v->uv_lcl_addr, allhosts_group,
+ IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0);
+ }
+ }
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group)
+ u_long src, dst, group;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *g;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group membership report from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ /*
+ * Look for the group in our group list; if found, reset its timer.
+ */
+ for (g = v->uv_groups; g != NULL; g = g->al_next) {
+ if (group == g->al_addr) {
+ g->al_timer = 0;
+ break;
+ }
+ }
+
+ /*
+ * If not found, add it to the list and tell the kernel.
+ */
+ if (g == NULL) {
+ g = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (g == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ g->al_addr = group;
+ g->al_timer = 0;
+ g->al_next = v->uv_groups;
+ v->uv_groups = g;
+
+ k_add_group(vifi, group);
+ }
+}
+
+
+/*
+ * Send a probe on all vifs from which no neighbors have been heard recently.
+ */
+void probe_for_neighbors()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) &&
+ v->uv_neighbors == NULL) {
+ send_igmp(v->uv_lcl_addr,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group,
+ IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0);
+ }
+ }
+}
+
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void accept_neighbor_request(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long temp_addr, us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+#define PUT_ADDR(a) temp_addr = ntohl(a); \
+ *p++ = temp_addr >> 24; \
+ *p++ = (temp_addr >> 16) & 0xFF; \
+ *p++ = (temp_addr >> 8) & 0xFF; \
+ *p++ = temp_addr & 0xFF;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_DISABLED)
+ continue;
+
+ ncount = 0;
+
+ for (la = v->uv_neighbors; la; la = la->al_next) {
+
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ PUT_ADDR(v->uv_lcl_addr);
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 3;
+ }
+
+ PUT_ADDR(la->al_addr);
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void accept_neighbor_request2(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long temp_addr, us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ register u_short vflags = v->uv_flags;
+ register u_char rflags = 0;
+ if (vflags & VIFF_TUNNEL)
+ rflags |= DVMRP_NF_TUNNEL;
+ if (vflags & VIFF_SRCRT)
+ rflags |= DVMRP_NF_SRCRT;
+ if (vflags & VIFF_DOWN)
+ rflags |= DVMRP_NF_DOWN;
+ if (vflags & VIFF_DISABLED)
+ rflags |= DVMRP_NF_DISABLED;
+ if (vflags & VIFF_QUERIER)
+ rflags |= DVMRP_NF_QUERIER;
+ ncount = 0;
+ la = v->uv_neighbors;
+ if (la == NULL) {
+ /*
+ * include down & disabled interfaces and interfaces on
+ * leaf nets.
+ */
+ if (rflags & DVMRP_NF_TUNNEL)
+ rflags |= DVMRP_NF_DOWN;
+ if (datalen > MAX_DVMRP_DATA_LEN - 12) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ }
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ *p++ = 1;
+ *(u_int*)p = v->uv_rmt_addr;
+ p += 4;
+ datalen += 12;
+ } else {
+ for ( ; la; la = la->al_next) {
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 4;
+ }
+ *(u_int*)p = la->al_addr;
+ p += 4;
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+ }
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors2(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
+ * 'msgtype' is the type of DVMRP message received from the neighbor.
+ * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
+ */
+int update_neighbor(vifi, addr, msgtype)
+ vifi_t vifi;
+ u_long addr;
+ int msgtype;
+{
+ register struct uvif *v;
+ register struct listaddr *n;
+
+ v = &uvifs[vifi];
+
+ /*
+ * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
+ * IT IS ASSUMED that this was preceded by a call to find_vif(), which
+ * checks that 'addr' is either a valid remote tunnel endpoint or a
+ * non-broadcast address belonging to a directly-connected subnet.
+ * Therefore, here we check only that 'addr' is not our own address
+ * (due to an impostor or erroneous loopback) or an address of the form
+ * {subnet,0} ("the unknown host"). These checks are not performed in
+ * find_vif() because those types of address are acceptable for some
+ * types of IGMP message (such as group membership reports).
+ */
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ (addr == v->uv_lcl_addr ||
+ addr == v->uv_subnet )) {
+ log(LOG_WARNING, 0,
+ "received DVMRP message from 'the unknown host' or self: %s",
+ inet_fmt(addr, s1));
+ return (FALSE);
+ }
+
+ /*
+ * If we have received a route report from a neighbor, and we believed
+ * that we had no neighbors on this vif, send a full route report to
+ * all neighbors on the vif.
+ */
+
+ if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL)
+ report(ALL_ROUTES, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
+
+ /*
+ * Look for addr in list of neighbors; if found, reset its timer.
+ */
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (addr == n->al_addr) {
+ n->al_timer = 0;
+ break;
+ }
+ }
+
+ /*
+ * If not found, add it to the list. If the neighbor has a lower
+ * IP address than me, yield querier duties to it.
+ */
+ if (n == NULL) {
+ n = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (n == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ n->al_addr = addr;
+ n->al_timer = 0;
+ n->al_next = v->uv_neighbors;
+ v->uv_neighbors = n;
+
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ ntohl(addr) < ntohl(v->uv_lcl_addr))
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each neighbor and
+ * group entry on every vif.
+ */
+void age_vifs()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a, *prev_a, *n;
+ register u_long addr;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
+
+ for (prev_a = (struct listaddr *)&(v->uv_neighbors),
+ a = v->uv_neighbors;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME)
+ continue;
+
+ /*
+ * Neighbor has expired; delete it from the neighbor list,
+ * delete it from the 'dominants' and 'subordinates arrays of
+ * any route entries and assume querier duties unless there is
+ * another neighbor with a lower IP address than mine.
+ */
+ addr = a->al_addr;
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+
+ delete_neighbor_from_routes(addr, vifi);
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ v->uv_flags |= VIFF_QUERIER;
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
+ v->uv_flags &= ~VIFF_QUERIER;
+ break;
+ }
+ }
+ }
+ }
+
+ for (prev_a = (struct listaddr *)&(v->uv_groups),
+ a = v->uv_groups;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if ((a->al_timer += TIMER_INTERVAL) < GROUP_EXPIRE_TIME)
+ continue;
+
+ /*
+ * Group has expired; tell kernel and delete from group list.
+ */
+ k_del_group(vifi, a->al_addr);
+
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+ }
+ }
+}
+
+
+/*
+ * Print the contents of the uvifs array on file 'fp'.
+ */
+void dump_vifs(fp)
+ FILE *fp;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a;
+
+ fprintf(fp,
+ "\nVirtual Interface Table\n%s",
+ " Vif Local-Address Metric Thresh Flags\n");
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+
+ fprintf(fp, " %2u %-15s %6s: %-15s %4u %7u ",
+ vifi,
+ inet_fmt(v->uv_lcl_addr, s1),
+ (v->uv_flags & VIFF_TUNNEL) ?
+ "tunnel":
+ "subnet",
+ (v->uv_flags & VIFF_TUNNEL) ?
+ inet_fmt(v->uv_rmt_addr, s2) :
+ inet_fmts(v->uv_subnet, v->uv_subnetmask, s3),
+ v->uv_metric,
+ v->uv_threshold);
+
+ if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down");
+ if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
+ if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
+ if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
+ fprintf(fp, "\n");
+
+ if (v->uv_neighbors != NULL) {
+ fprintf(fp, " peers : %-15s\n",
+ inet_fmt(v->uv_neighbors->al_addr, s1));
+ for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %-15s\n",
+ inet_fmt(a->al_addr, s1));
+ }
+ }
+
+ if (v->uv_groups != NULL) {
+ fprintf(fp, " groups: %-15s\n",
+ inet_fmt(v->uv_groups->al_addr, s1));
+ for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %-15s\n",
+ inet_fmt(a->al_addr, s1));
+ }
+ }
+ }
+ fprintf(fp, "\n");
+}
diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h
new file mode 100644
index 000000000000..4af87c5ae805
--- /dev/null
+++ b/usr.sbin/mrouted/vif.h
@@ -0,0 +1,47 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: vif.h,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+/*
+ * User level Virtual Interface structure
+ *
+ * A "virtual interface" is either a physical, multicast-capable interface
+ * (called a "phyint") or a virtual point-to-point link (called a "tunnel").
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ */
+struct uvif {
+ u_short uv_flags; /* VIFF_ flags defined below */
+ u_char uv_metric; /* cost of this vif */
+ u_char uv_threshold; /* min ttl required to forward on vif */
+ u_long uv_lcl_addr; /* local address of this vif */
+ u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
+ u_long uv_subnet; /* subnet number (phyints only) */
+ u_long uv_subnetmask; /* subnet mask (phyints only) */
+ u_long uv_subnetbcast;/* subnet broadcast addr (phyints only) */
+ char uv_name[IFNAMSIZ]; /* interface name */
+ struct listaddr *uv_groups; /* list of local groups (phyints only) */
+ struct listaddr *uv_neighbors; /* list of neighboring routers */
+};
+
+#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
+#define VIFF_DOWN 0x0100 /* kernel state of interface */
+#define VIFF_DISABLED 0x0200 /* administratively disabled */
+#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
+
+
+struct listaddr {
+ struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
+ u_long al_addr; /* local group or neighbor address */
+ u_long al_timer; /* for timing out group or neighbor */
+};
+
+
+#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c
index d09312622265..c50611de4a4a 100644
--- a/usr.sbin/mtree/verify.c
+++ b/usr.sbin/mtree/verify.c
@@ -172,10 +172,11 @@ miss(p, tail)
(void)printf(" (not created: group not specified)");
else if (!(p->flags & F_MODE))
(void)printf(" (not created: mode not specified)");
- else if (mkdir(path, S_IRWXU))
+ else if (mkdir(path, S_IRWXU)) {
+ create = 1;
(void)printf(" (not created: %s)",
strerror(errno));
- else {
+ } else {
create = 1;
(void)printf(" (created)");
}
diff --git a/usr.sbin/named/named.restart b/usr.sbin/named/named.restart
index 6159a605cebe..19a2590e1b96 100644
--- a/usr.sbin/named/named.restart
+++ b/usr.sbin/named/named.restart
@@ -5,5 +5,5 @@
PATH=/bin:/sbin:/usr/sbin:/usr/bin
-kill -9 `cat /var/run/named.pid`
+kill -TERM `cat /var/run/named.pid`
named
diff --git a/usr.sbin/pwd_mkdb/Makefile b/usr.sbin/pwd_mkdb/Makefile
index 645728b3505c..616f10514dae 100644
--- a/usr.sbin/pwd_mkdb/Makefile
+++ b/usr.sbin/pwd_mkdb/Makefile
@@ -3,5 +3,8 @@
PROG= pwd_mkdb
SRCS= pw_scan.c pwd_mkdb.c
MAN8= pwd_mkdb.8
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8
index 2ab2cee6ca5f..845662dc233c 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.8
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8
@@ -99,6 +99,20 @@ The front-ends to
and
.IR vipw (8),
handle the locking necessary to avoid this problem.
+.PP
+Standard database make routines are slow especially for big passwd
+files. Moreover, *pwd.db bases are too big and waste root space.
+You can have much faster routines with small *pwd.db,
+but loose binary compatibility
+with previous versions and with other BSD-like systems.
+If you want to setup much faster routines, define
+.B PW_COMPACT
+envirnoment variable (f.e. 'setenv PW_COMPACT' in csh) and use
+.I bootstrappwd
+target into /usr/src/Makefile.
+If you will want to return this changes back, use the same target
+without defining
+.BR PW_COMPACT .
.SH COMPATIBILITY
Previous versions of the system had a program similar to
.I pwd_mkdb,
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
index b90daee24884..ffad7ed3158e 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.c
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -53,11 +53,42 @@ static char sccsid[] = "@(#)pwd_mkdb.c 5.5 (Berkeley) 5/6/91";
#include <string.h>
#include <stdlib.h>
+/* #define PW_COMPACT */
+/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
+#ifdef PW_COMPACT
+# define HI_BSIZE 1024
+# define HI_CACHE (512 * 1024)
+# define HI_SCACHE (128 * 1024)
+#else
+# define HI_BSIZE 4096
+# define HI_CACHE (2048 * 1024)
+#endif
+
#define INSECURE 1
#define SECURE 2
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
+HASHINFO openinfo = {
+ HI_BSIZE, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ HI_CACHE, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+#ifdef PW_COMPACT
+HASHINFO sopeninfo = {
+ HI_BSIZE, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ HI_SCACHE, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+#endif
+
char *progname = "pwd_mkdb";
static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
@@ -76,10 +107,14 @@ main(argc, argv)
DB *dp, *edp;
sigset_t set;
DBT data, key;
+#ifdef PW_COMPACT
+ DBT pdata, sdata;
+#endif
int ch, cnt, tfd;
char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
char buf2[MAXPATHLEN];
+ umask(022);
strcpy(prefix, _PATH_PWD);
makeold = 0;
while ((ch = getopt(argc, argv, "d:pv")) != EOF)
@@ -121,17 +156,21 @@ main(argc, argv)
/* Open the temporary insecure password database. */
(void)sprintf(buf, "%s/%s.tmp", prefix, _MP_DB);
- dp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, NULL);
+ dp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
if (!dp)
error(buf);
clean = FILE_INSECURE;
+#ifdef PW_COMPACT
/* Open the temporary encrypted password database. */
(void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB);
- edp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, NULL);
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &sopeninfo);
if (!edp)
error(buf);
clean = FILE_SECURE;
+#endif
/*
* Open file for old password file. Minor trickiness -- don't want to
@@ -163,11 +202,19 @@ main(argc, argv)
data.data = (u_char *)buf;
key.data = (u_char *)tbuf;
for (cnt = 1; scan(fp, &pwd); ++cnt) {
+#ifdef PW_COMPACT
+ pdata.data = (u_char *)&cnt;
+ pdata.size = sizeof(int);
+ sdata.data = (u_char *)pwd.pw_passwd;
+ sdata.size = strlen(pwd.pw_passwd) + 1;
+#endif
#define COMPACT(e) t = e; while (*p++ = *t++);
/* Create insecure data. */
p = buf;
COMPACT(pwd.pw_name);
+#ifndef PW_COMPACT
COMPACT("*");
+#endif
bcopy((char *)&pwd.pw_uid, p, sizeof(int));
p += sizeof(int);
bcopy((char *)&pwd.pw_gid, p, sizeof(int));
@@ -187,7 +234,22 @@ main(argc, argv)
len = strlen(pwd.pw_name);
bcopy(pwd.pw_name, tbuf + 1, len);
key.size = len + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1)
+#else
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#endif
+ error("put");
+
+ /* Store insecure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1)
+#else
if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#endif
error("put");
/* Store insecure by number. */
@@ -197,12 +259,41 @@ main(argc, argv)
if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
- /* Store insecure by uid. */
- tbuf[0] = _PW_KEYBYUID;
- bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
- key.size = sizeof(pwd.pw_uid) + 1;
- if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#ifdef PW_COMPACT
+ /* Store secure. */
+ if ((edp->put)(edp, &key, &sdata, R_NOOVERWRITE) == -1)
error("put");
+#endif
+
+ /* Create original format password file entry */
+ if (makeold)
+ (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
+ pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
+ pwd.pw_dir, pwd.pw_shell);
+
+ }
+ (void)(dp->close)(dp);
+#ifdef PW_COMPACT
+ (void)(edp->close)(edp);
+#endif
+
+ if (makeold) {
+ (void)fflush(oldfp);
+ (void)fsync(fileno(oldfp));
+ (void)fclose(oldfp);
+ }
+
+#ifndef PW_COMPACT
+ /* Open the temporary encrypted password database. */
+ (void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB);
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ if (!edp)
+ error(buf);
+ clean = FILE_SECURE;
+
+ rewind(fp);
+ for (cnt = 1; scan(fp, &pwd); ++cnt) {
/* Create secure data. */
p = buf;
@@ -227,35 +318,27 @@ main(argc, argv)
len = strlen(pwd.pw_name);
bcopy(pwd.pw_name, tbuf + 1, len);
key.size = len + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
/* Store secure by number. */
tbuf[0] = _PW_KEYBYNUM;
bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
key.size = sizeof(cnt) + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
/* Store secure by uid. */
tbuf[0] = _PW_KEYBYUID;
bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
key.size = sizeof(pwd.pw_uid) + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
- /* Create original format password file entry */
- if (makeold)
- (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
- pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
- pwd.pw_dir, pwd.pw_shell);
}
- (void)(dp->close)(dp);
+
(void)(edp->close)(edp);
- if (makeold) {
- (void)fsync(oldfp);
- (void)fclose(oldfp);
- }
+#endif
/* Set master.passwd permissions, in case caller forgot. */
(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
@@ -284,6 +367,7 @@ main(argc, argv)
exit(0);
}
+int
scan(fp, pw)
FILE *fp;
struct passwd *pw;
@@ -310,8 +394,8 @@ scan(fp, pw)
(void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt);
fmt: errno = EFTYPE;
error(pname);
- exit(1);
}
+ return(1);
}
mv(from, to)
diff --git a/sbin/routed/Makefile b/usr.sbin/routed/Makefile
index 0fc8bc839cbf..0fc8bc839cbf 100644
--- a/sbin/routed/Makefile
+++ b/usr.sbin/routed/Makefile
diff --git a/sbin/routed/af.c b/usr.sbin/routed/af.c
index 19807b71db41..19807b71db41 100644
--- a/sbin/routed/af.c
+++ b/usr.sbin/routed/af.c
diff --git a/sbin/routed/af.h b/usr.sbin/routed/af.h
index 2d1bf293d365..2d1bf293d365 100644
--- a/sbin/routed/af.h
+++ b/usr.sbin/routed/af.h
diff --git a/sbin/routed/defs.h b/usr.sbin/routed/defs.h
index f4fdf7a68f29..f4fdf7a68f29 100644
--- a/sbin/routed/defs.h
+++ b/usr.sbin/routed/defs.h
diff --git a/sbin/routed/if.c b/usr.sbin/routed/if.c
index 4871c9df32aa..4871c9df32aa 100644
--- a/sbin/routed/if.c
+++ b/usr.sbin/routed/if.c
diff --git a/sbin/routed/inet.c b/usr.sbin/routed/inet.c
index a465ac7637c9..a465ac7637c9 100644
--- a/sbin/routed/inet.c
+++ b/usr.sbin/routed/inet.c
diff --git a/sbin/routed/input.c b/usr.sbin/routed/input.c
index ec8c9d76239b..ec8c9d76239b 100644
--- a/sbin/routed/input.c
+++ b/usr.sbin/routed/input.c
diff --git a/usr.sbin/routed/interface.h b/usr.sbin/routed/interface.h
new file mode 100644
index 000000000000..c67f203e3f8c
--- /dev/null
+++ b/usr.sbin/routed/interface.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * @(#)interface.h 5.6 (Berkeley) 6/1/90
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ */
+struct interface {
+ struct interface *int_next;
+ struct sockaddr int_addr; /* address on this host */
+ union {
+ struct sockaddr intu_broadaddr;
+ struct sockaddr intu_dstaddr;
+ } int_intu;
+#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
+#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
+ int int_metric; /* init's routing entry */
+ int int_flags; /* see below */
+ /* START INTERNET SPECIFIC */
+ u_long int_net; /* network # */
+ u_long int_netmask; /* net mask for addr */
+ u_long int_subnet; /* subnet # */
+ u_long int_subnetmask; /* subnet mask for addr */
+ /* END INTERNET SPECIFIC */
+ struct ifdebug int_input, int_output; /* packet tracing stuff */
+ int int_ipackets; /* input packets received */
+ int int_opackets; /* output packets sent */
+ char *int_name; /* from kernel if structure */
+ u_short int_transitions; /* times gone up-down */
+};
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_LOOPBACK 0x8 /* software loopback net */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+#define IFF_KERNELPUN 0x1f /* mask for above */
+
+#define IFF_SUBNET 0x1000 /* interface on subnetted network */
+#define IFF_PASSIVE 0x2000 /* can't tell if up/down */
+#define IFF_INTERFACE 0x4000 /* hardware interface */
+#define IFF_REMOTE 0x8000 /* interface isn't on this machine */
+
+struct interface *if_ifwithaddr();
+struct interface *if_ifwithdstaddr();
+struct interface *if_ifwithnet();
+struct interface *if_iflookup();
diff --git a/sbin/routed/main.c b/usr.sbin/routed/main.c
index 75ed82f58e56..75ed82f58e56 100644
--- a/sbin/routed/main.c
+++ b/usr.sbin/routed/main.c
diff --git a/sbin/routed/output.c b/usr.sbin/routed/output.c
index 10c81b1a0ca0..10c81b1a0ca0 100644
--- a/sbin/routed/output.c
+++ b/usr.sbin/routed/output.c
diff --git a/sbin/routed/pathnames.h b/usr.sbin/routed/pathnames.h
index 54bac2751e52..54bac2751e52 100644
--- a/sbin/routed/pathnames.h
+++ b/usr.sbin/routed/pathnames.h
diff --git a/sbin/routed/query/Makefile b/usr.sbin/routed/query/Makefile
index 03746d30652d..03746d30652d 100644
--- a/sbin/routed/query/Makefile
+++ b/usr.sbin/routed/query/Makefile
diff --git a/sbin/routed/query/query.c b/usr.sbin/routed/query/query.c
index 32c10c1e1a8b..32c10c1e1a8b 100644
--- a/sbin/routed/query/query.c
+++ b/usr.sbin/routed/query/query.c
diff --git a/sbin/routed/routed.8 b/usr.sbin/routed/routed.8
index 1d428a7b39b3..1d428a7b39b3 100644
--- a/sbin/routed/routed.8
+++ b/usr.sbin/routed/routed.8
diff --git a/usr.sbin/routed/startup.c b/usr.sbin/routed/startup.c
new file mode 100644
index 000000000000..de4d58da2f45
--- /dev/null
+++ b/usr.sbin/routed/startup.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1983, 1988 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)startup.c 5.19 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+struct interface *ifnet;
+struct interface **ifnext = &ifnet;
+int lookforinterfaces = 1;
+int externalinterfaces = 0; /* # of remote and local interfaces */
+int foundloopback; /* valid flag for loopaddr */
+struct sockaddr loopaddr; /* our address on loopback */
+
+/*
+ * Find the network interfaces which have configured themselves.
+ * If the interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
+ */
+ifinit()
+{
+ struct interface ifs, *ifp;
+ int s;
+ char buf[BUFSIZ], *cp, *cplim;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct sockaddr_in *sin;
+ u_long i;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ close(s);
+ return;
+ }
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "ioctl (get interface configuration)");
+ close(s);
+ return;
+ }
+ ifr = ifc.ifc_req;
+ lookforinterfaces = 0;
+#ifdef RTM_ADD
+#define max(a, b) (a > b ? a : b)
+#define size(p) max((p).sa_len, sizeof(p))
+#else
+#define size(p) (sizeof (p))
+#endif
+ cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+ for (cp = buf; cp < cplim;
+ cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+ ifr = (struct ifreq *)cp;
+ bzero((char *)&ifs, sizeof(ifs));
+ ifs.int_addr = ifr->ifr_addr;
+ ifreq = *ifr;
+ if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "%s: ioctl (get interface flags)",
+ ifr->ifr_name);
+ continue;
+ }
+ ifs.int_flags = (ifreq.ifr_flags & IFF_KERNELPUN) | IFF_INTERFACE;
+ if ((ifs.int_flags & IFF_UP) == 0 ||
+ ifr->ifr_addr.sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ /* argh, this'll have to change sometime */
+ if (ifs.int_addr.sa_family != AF_INET)
+ continue;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "%s: ioctl (get dstaddr)",
+ ifr->ifr_name);
+ continue;
+ }
+ if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ ifs.int_dstaddr = ifreq.ifr_dstaddr;
+ }
+ /*
+ * already known to us?
+ * This allows multiple point-to-point links
+ * to share a source address (possibly with one
+ * other link), but assumes that there will not be
+ * multiple links with the same destination address.
+ */
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (if_ifwithdstaddr(&ifs.int_dstaddr))
+ continue;
+ } else if (if_ifwithaddr(&ifs.int_addr))
+ continue;
+ if (ifs.int_flags & IFF_LOOPBACK) {
+ ifs.int_flags |= IFF_PASSIVE;
+ foundloopback = 1;
+ loopaddr = ifs.int_addr;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ add_ptopt_localrt(ifp);
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "%s: ioctl (get broadaddr)",
+ ifr->ifr_name);
+ continue;
+ }
+#ifndef sun
+ ifs.int_broadaddr = ifreq.ifr_broadaddr;
+#else
+ ifs.int_broadaddr = ifreq.ifr_addr;
+#endif
+ }
+#ifdef SIOCGIFMETRIC
+ if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "%s: ioctl (get metric)",
+ ifr->ifr_name);
+ ifs.int_metric = 0;
+ } else
+ ifs.int_metric = ifreq.ifr_metric;
+#else
+ ifs.int_metric = 0;
+#endif
+ /*
+ * Use a minimum metric of one;
+ * treat the interface metric (default 0)
+ * as an increment to the hop count of one.
+ */
+ ifs.int_metric++;
+ if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "%s: ioctl (get netmask)",
+ ifr->ifr_name);
+ continue;
+ }
+ sin = (struct sockaddr_in *)&ifreq.ifr_addr;
+ ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
+ sin = (struct sockaddr_in *)&ifs.int_addr;
+ i = ntohl(sin->sin_addr.s_addr);
+ if (IN_CLASSA(i))
+ ifs.int_netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ ifs.int_netmask = IN_CLASSB_NET;
+ else
+ ifs.int_netmask = IN_CLASSC_NET;
+ ifs.int_net = i & ifs.int_netmask;
+ ifs.int_subnet = i & ifs.int_subnetmask;
+ if (ifs.int_subnetmask != ifs.int_netmask)
+ ifs.int_flags |= IFF_SUBNET;
+ ifp = (struct interface *)malloc(sizeof (struct interface));
+ if (ifp == 0) {
+ printf("routed: out of memory\n");
+ break;
+ }
+ *ifp = ifs;
+ /*
+ * Count the # of directly connected networks
+ * and point to point links which aren't looped
+ * back to ourself. This is used below to
+ * decide if we should be a routing ``supplier''.
+ */
+ if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
+ ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+ if_ifwithaddr(&ifs.int_dstaddr) == 0))
+ externalinterfaces++;
+ /*
+ * If we have a point-to-point link, we want to act
+ * as a supplier even if it's our only interface,
+ * as that's the only way our peer on the other end
+ * can tell that the link is up.
+ */
+ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+ supplier = 1;
+ ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
+ if (ifp->int_name == 0) {
+ fprintf(stderr, "routed: ifinit: out of memory\n");
+ syslog(LOG_ERR, "routed: ifinit: out of memory\n");
+ close(s);
+ return;
+ }
+ strcpy(ifp->int_name, ifr->ifr_name);
+ *ifnext = ifp;
+ ifnext = &ifp->int_next;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ close(s);
+}
+
+/*
+ * Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ * INTERNET SPECIFIC.
+ */
+addrouteforif(ifp)
+ register struct interface *ifp;
+{
+ struct sockaddr_in net;
+ struct sockaddr *dst;
+ int state;
+ register struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ dst = &ifp->int_dstaddr;
+ else {
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ }
+ rt = rtfind(dst);
+ if (rt &&
+ (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
+ return;
+ if (rt)
+ rtdelete(rt);
+ /*
+ * If interface on subnetted network,
+ * install route to network as well.
+ * This is meant for external viewers.
+ */
+ if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
+ struct in_addr subnet;
+
+ subnet = net.sin_addr;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ rt = rtfind(dst);
+ if (rt == 0)
+ rtadd(dst, &ifp->int_addr, ifp->int_metric,
+ ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
+ RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
+ else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
+ (RTS_INTERNAL|RTS_SUBNET) &&
+ ifp->int_metric < rt->rt_metric)
+ rtchange(rt, &rt->rt_router, ifp->int_metric);
+ net.sin_addr = subnet;
+ }
+ if (ifp->int_transitions++ > 0)
+ syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+ state = ifp->int_flags &
+ (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
+ if (ifp->int_flags & IFF_POINTOPOINT &&
+ (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
+ ifp->int_netmask) != ifp->int_net)
+ state &= ~RTS_SUBNET;
+ if (ifp->int_flags & IFF_LOOPBACK)
+ state |= RTS_EXTERNAL;
+ rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
+ if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
+ add_ptopt_localrt(ifp);
+}
+
+/*
+ * Add route to local end of point-to-point using loopback.
+ * If a route to this network is being sent to neighbors on other nets,
+ * mark this route as subnet so we don't have to propagate it too.
+ */
+add_ptopt_localrt(ifp)
+ register struct interface *ifp;
+{
+ struct rt_entry *rt;
+ struct sockaddr *dst;
+ struct sockaddr_in net;
+ int state;
+
+ state = RTS_INTERFACE | RTS_PASSIVE;
+
+ /* look for route to logical network */
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ rt = rtfind(dst);
+ if (rt && rt->rt_state & RTS_INTERNAL)
+ state |= RTS_SUBNET;
+
+ dst = &ifp->int_addr;
+ if (rt = rtfind(dst)) {
+ if (rt && rt->rt_state & RTS_INTERFACE)
+ return;
+ rtdelete(rt);
+ }
+ rtadd(dst, &loopaddr, 1, state);
+}
+
+/*
+ * As a concession to the ARPANET we read a list of gateways
+ * from /etc/gateways and add them to our tables. This file
+ * exists at each ARPANET gateway and indicates a set of ``remote''
+ * gateways (i.e. a gateway which we can't immediately determine
+ * if it's present or not as we can do for those directly connected
+ * at the hardware level). If a gateway is marked ``passive''
+ * in the file, then we assume it doesn't have a routing process
+ * of our design and simply assume it's always present. Those
+ * not marked passive are treated as if they were directly
+ * connected -- they're added into the interface list so we'll
+ * send them routing updates.
+ *
+ * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
+ */
+gwkludge()
+{
+ struct sockaddr_in dst, gate;
+ FILE *fp;
+ char *type, *dname, *gname, *qual, buf[BUFSIZ];
+ struct interface *ifp;
+ int metric, n;
+ struct rt_entry route;
+
+ fp = fopen(_PATH_GATEWAYS, "r");
+ if (fp == NULL)
+ return;
+ qual = buf;
+ dname = buf + 64;
+ gname = buf + ((BUFSIZ - 64) / 3);
+ type = buf + (((BUFSIZ - 64) * 2) / 3);
+ bzero((char *)&dst, sizeof (dst));
+ bzero((char *)&gate, sizeof (gate));
+ bzero((char *)&route, sizeof(route));
+/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
+#define readentry(fp) \
+ fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+ type, dname, gname, &metric, qual)
+ for (;;) {
+ if ((n = readentry(fp)) == EOF)
+ break;
+ if (!getnetorhostname(type, dname, &dst))
+ continue;
+ if (!gethostnameornumber(gname, &gate))
+ continue;
+ if (metric == 0) /* XXX */
+ metric = 1;
+ if (strcmp(qual, "passive") == 0) {
+ /*
+ * Passive entries aren't placed in our tables,
+ * only the kernel's, so we don't copy all of the
+ * external routing information within a net.
+ * Internal machines should use the default
+ * route to a suitable gateway (like us).
+ */
+ route.rt_dst = *(struct sockaddr *) &dst;
+ route.rt_router = *(struct sockaddr *) &gate;
+ route.rt_flags = RTF_UP;
+ if (strcmp(type, "host") == 0)
+ route.rt_flags |= RTF_HOST;
+ if (metric)
+ route.rt_flags |= RTF_GATEWAY;
+ (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
+ continue;
+ }
+ if (strcmp(qual, "external") == 0) {
+ /*
+ * Entries marked external are handled
+ * by other means, e.g. EGP,
+ * and are placed in our tables only
+ * to prevent overriding them
+ * with something else.
+ */
+ rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
+ continue;
+ }
+ /* assume no duplicate entries */
+ externalinterfaces++;
+ ifp = (struct interface *)malloc(sizeof (*ifp));
+ bzero((char *)ifp, sizeof (*ifp));
+ ifp->int_flags = IFF_REMOTE;
+ /* can't identify broadcast capability */
+ ifp->int_net = inet_netof(dst.sin_addr);
+ if (strcmp(type, "host") == 0) {
+ ifp->int_flags |= IFF_POINTOPOINT;
+ ifp->int_dstaddr = *((struct sockaddr *)&dst);
+ }
+ ifp->int_addr = *((struct sockaddr *)&gate);
+ ifp->int_metric = metric;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ addrouteforif(ifp);
+ }
+ fclose(fp);
+}
+
+getnetorhostname(type, name, sin)
+ char *type, *name;
+ struct sockaddr_in *sin;
+{
+
+ if (strcmp(type, "net") == 0) {
+ struct netent *np = getnetbyname(name);
+ int n;
+
+ if (np == 0)
+ n = inet_network(name);
+ else {
+ if (np->n_addrtype != AF_INET)
+ return (0);
+ n = np->n_net;
+ /*
+ * getnetbyname returns right-adjusted value.
+ */
+ if (n < 128)
+ n <<= IN_CLASSA_NSHIFT;
+ else if (n < 65536)
+ n <<= IN_CLASSB_NSHIFT;
+ else
+ n <<= IN_CLASSC_NSHIFT;
+ }
+ sin->sin_family = AF_INET;
+ sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
+ return (1);
+ }
+ if (strcmp(type, "host") == 0) {
+ struct hostent *hp = gethostbyname(name);
+
+ if (hp == 0)
+ sin->sin_addr.s_addr = inet_addr(name);
+ else {
+ if (hp->h_addrtype != AF_INET)
+ return (0);
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ }
+ sin->sin_family = AF_INET;
+ return (1);
+ }
+ return (0);
+}
+
+gethostnameornumber(name, sin)
+ char *name;
+ struct sockaddr_in *sin;
+{
+ struct hostent *hp;
+
+ hp = gethostbyname(name);
+ if (hp) {
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ sin->sin_family = hp->h_addrtype;
+ return (1);
+ }
+ sin->sin_addr.s_addr = inet_addr(name);
+ sin->sin_family = AF_INET;
+ return (sin->sin_addr.s_addr != -1);
+}
diff --git a/sbin/routed/table.h b/usr.sbin/routed/table.h
index 124e098eb295..124e098eb295 100644
--- a/sbin/routed/table.h
+++ b/usr.sbin/routed/table.h
diff --git a/sbin/routed/tables.c b/usr.sbin/routed/tables.c
index 17a4fb7b966e..17a4fb7b966e 100644
--- a/sbin/routed/tables.c
+++ b/usr.sbin/routed/tables.c
diff --git a/sbin/routed/timer.c b/usr.sbin/routed/timer.c
index fd0851d20ad9..fd0851d20ad9 100644
--- a/sbin/routed/timer.c
+++ b/usr.sbin/routed/timer.c
diff --git a/sbin/routed/trace.c b/usr.sbin/routed/trace.c
index 6e0b478bc55d..6e0b478bc55d 100644
--- a/sbin/routed/trace.c
+++ b/usr.sbin/routed/trace.c
diff --git a/sbin/routed/trace.h b/usr.sbin/routed/trace.h
index 741de720ce20..741de720ce20 100644
--- a/sbin/routed/trace.h
+++ b/usr.sbin/routed/trace.h
diff --git a/sbin/routed/trace/Makefile b/usr.sbin/routed/trace/Makefile
index 85e405af1d50..85e405af1d50 100644
--- a/sbin/routed/trace/Makefile
+++ b/usr.sbin/routed/trace/Makefile
diff --git a/sbin/routed/trace/trace.c b/usr.sbin/routed/trace/trace.c
index 64d928db8f20..64d928db8f20 100644
--- a/sbin/routed/trace/trace.c
+++ b/usr.sbin/routed/trace/trace.c
diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile
new file mode 100644
index 000000000000..c0a7a2dc767b
--- /dev/null
+++ b/usr.sbin/sa/Makefile
@@ -0,0 +1,8 @@
+# $Id: Makefile,v 1.2 1994/05/18 12:21:31 csgr Exp $
+
+PROG= sa
+MAN8= sa.8
+SRCS= main.c pdb.c usrdb.c
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h
new file mode 100644
index 000000000000..609752d2d0d2
--- /dev/null
+++ b/usr.sbin/sa/extern.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: extern.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <db.h>
+
+/* structures */
+
+struct cmdinfo {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ u_long ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
+
+struct userinfo {
+ u_long ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/* typedefs */
+
+typedef int (*cmpf_t) __P((const DBT *, const DBT *));
+
+/* external functions in sa.c */
+int main __P((int, char **));
+
+/* external functions in pdb.c */
+int pacct_init __P((void));
+void pacct_destroy __P((void));
+int pacct_add __P((const struct cmdinfo *));
+int pacct_update __P((void));
+void pacct_print __P((void));
+
+/* external functions in usrdb.c */
+int usracct_init __P((void));
+void usracct_destroy __P((void));
+int usracct_add __P((const struct cmdinfo *));
+int usracct_update __P((void));
+void usracct_print __P((void));
+
+/* variables */
+
+extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+extern int cutoff;
+extern cmpf_t sa_cmp;
+
+/* some #defines to help with db's stupidity */
+
+#define DB_CLOSE(db) \
+ ((*(db)->close)(db))
+#define DB_GET(db, key, data, flags) \
+ ((*(db)->get)((db), (key), (data), (flags)))
+#define DB_PUT(db, key, data, flags) \
+ ((*(db)->put)((db), (key), (data), (flags)))
+#define DB_SYNC(db, flags) \
+ ((*(db)->sync)((db), (flags)))
+#define DB_SEQ(db, key, data, flags) \
+ ((*(db)->seq)((db), (key), (data), (flags)))
diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c
new file mode 100644
index 000000000000..65a0216e928a
--- /dev/null
+++ b/usr.sbin/sa/main.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef LINT
+static char copright[] =
+"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
+ All rights reserved.\n";
+
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $";
+#endif
+
+/*
+ * sa: system accounting
+ */
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int acct_load __P((char *, int));
+static u_quad_t decode_comp_t __P((comp_t));
+static int cmp_comm __P((const char *, const char *));
+static int cmp_usrsys __P((const DBT *, const DBT *));
+static int cmp_avgusrsys __P((const DBT *, const DBT *));
+static int cmp_dkio __P((const DBT *, const DBT *));
+static int cmp_avgdkio __P((const DBT *, const DBT *));
+static int cmp_cpumem __P((const DBT *, const DBT *));
+static int cmp_avgcpumem __P((const DBT *, const DBT *));
+static int cmp_calls __P((const DBT *, const DBT *));
+
+int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+int cutoff = 1;
+
+static char *dfltargv[] = { _PATH_ACCT };
+static int dfltargc = (sizeof dfltargv/sizeof(char *));
+
+/* default to comparing by sum of user + system time */
+cmpf_t sa_cmp = cmp_usrsys;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char ch;
+ int error;
+
+ while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1)
+ switch (ch) {
+ case 'a':
+ /* print all commands */
+ aflag = 1;
+ break;
+ case 'b':
+ /* sort by per-call user/system time average */
+ bflag = 1;
+ sa_cmp = cmp_avgusrsys;
+ break;
+ case 'c':
+ /* print percentage total time */
+ cflag = 1;
+ break;
+ case 'd':
+ /* sort by averge number of disk I/O ops */
+ dflag = 1;
+ sa_cmp = cmp_avgdkio;
+ break;
+ case 'D':
+ /* print and sort by total disk I/O ops */
+ Dflag = 1;
+ sa_cmp = cmp_dkio;
+ break;
+ case 'f':
+ /* force no interactive threshold comprison */
+ fflag = 1;
+ break;
+ case 'i':
+ /* do not read in summary file */
+ iflag = 1;
+ break;
+ case 'j':
+ /* instead of total minutes, give sec/call */
+ jflag = 1;
+ break;
+ case 'k':
+ /* sort by cpu-time average memory usage */
+ kflag = 1;
+ sa_cmp = cmp_avgcpumem;
+ break;
+ case 'K':
+ /* print and sort by cpu-storage integral */
+ sa_cmp = cmp_cpumem;
+ Kflag = 1;
+ break;
+ case 'l':
+ /* seperate system and user time */
+ lflag = 1;
+ break;
+ case 'm':
+ /* print procs and time per-user */
+ mflag = 1;
+ break;
+ case 'n':
+ /* sort by number of calls */
+ sa_cmp = cmp_calls;
+ break;
+ case 'q':
+ /* quiet; error messages only */
+ qflag = 1;
+ break;
+ case 'r':
+ /* reverse order of sort */
+ rflag = 1;
+ break;
+ case 's':
+ /* merge accounting file into summaries */
+ sflag = 1;
+ break;
+ case 't':
+ /* report ratio of user and system times */
+ tflag = 1;
+ break;
+ case 'u':
+ /* first, print uid and command name */
+ uflag = 1;
+ break;
+ case 'v':
+ /* cull junk */
+ vflag = 1;
+ cutoff = atoi(optarg);
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+ "usage: sa [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n");
+ exit(1);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* various argument checking */
+ if (fflag && !vflag)
+ errx(1, "only one of -f requires -v");
+ if (fflag && aflag)
+ errx(1, "only one of -a and -v may be specified");
+ /* XXX need more argument checking */
+
+ if (!uflag) {
+ /* initialize tables */
+ if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
+ errx(1, "process accounting initialization failed");
+ if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
+ errx(1, "user accounting initialization failed");
+ }
+
+ if (argc == 0) {
+ argc = dfltargc;
+ argv = dfltargv;
+ }
+
+ /* for each file specified */
+ for (; argc > 0; argc--, argv++) {
+ int fd;
+
+ /*
+ * load the accounting data from the file.
+ * if it fails, go on to the next file.
+ */
+ fd = acct_load(argv[0], sflag);
+ if (fd < 0)
+ continue;
+
+ if (!uflag && sflag) {
+#ifndef DEBUG
+ sigset_t nmask, omask;
+ int unmask = 1;
+
+ /*
+ * block most signals so we aren't interrupted during
+ * the update.
+ */
+ if (sigfillset(&nmask) == -1) {
+ warn("sigfillset");
+ unmask = 0;
+ error = 1;
+ }
+ if (unmask &&
+ (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
+ warn("couldn't set signal mask ");
+ unmask = 0;
+ error = 1;
+ }
+#endif /* DEBUG */
+
+ /*
+ * truncate the accounting data file ASAP, to avoid
+ * losing data. don't worry about errors in updating
+ * the saved stats; better to underbill than overbill,
+ * but we want every accounting record intact.
+ */
+ if (ftruncate(fd, 0) == -1) {
+ warn("couldn't truncate %s", argv);
+ error = 1;
+ }
+
+ /*
+ * update saved user and process accounting data.
+ * note errors for later.
+ */
+ if (pacct_update() != 0 || usracct_update() != 0)
+ error = 1;
+
+#ifndef DEBUG
+ /*
+ * restore signals
+ */
+ if (unmask &&
+ (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
+ warn("couldn't restore signal mask");
+ error = 1;
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * close the opened accounting file
+ */
+ if (close(fd) == -1) {
+ warn("close %s", argv);
+ error = 1;
+ }
+ }
+
+ if (!uflag && !qflag) {
+ /* print any results we may have obtained. */
+ if (!mflag)
+ pacct_print();
+ else
+ usracct_print();
+ }
+
+ if (!uflag) {
+ /* finally, deallocate databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_destroy();
+ if (sflag || (mflag && !qflag))
+ usracct_destroy();
+ }
+
+ exit(error);
+}
+
+static int
+acct_load(pn, wr)
+ char *pn;
+ int wr;
+{
+ struct acct ac;
+ struct cmdinfo ci;
+ ssize_t rv;
+ int fd, i;
+
+ /*
+ * open the file
+ */
+ fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
+ if (fd == -1) {
+ warn("open %s %s", pn, wr ? "for read/write" : "read-only");
+ return (-1);
+ }
+
+ /*
+ * read all we can; don't stat and open because more processes
+ * could exit, and we'd miss them
+ */
+ while (1) {
+ /* get one accounting entry and punt if there's an error */
+ rv = read(fd, &ac, sizeof(struct acct));
+ if (rv == -1)
+ warn("error reading %s", pn);
+ else if (rv > 0 && rv < sizeof(struct acct))
+ warnx("short read of accounting data in %s", pn);
+ if (rv != sizeof(struct acct))
+ break;
+
+ /* decode it */
+ ci.ci_calls = 1;
+ for (i = 0; i < sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
+ i++) {
+ char c = ac.ac_comm[i];
+
+ if (!isascii(c) || iscntrl(c)) {
+ ci.ci_comm[i] = '?';
+ ci.ci_flags |= CI_UNPRINTABLE;
+ } else
+ ci.ci_comm[i] = c;
+ }
+ if (ac.ac_flag & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = decode_comp_t(ac.ac_etime);
+ ci.ci_utime = decode_comp_t(ac.ac_utime);
+ ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+
+ if (!uflag) {
+ /* and enter it into the usracct and pacct databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_add(&ci);
+ if (sflag || (mflag && !qflag))
+ usracct_add(&ci);
+ } else if (!qflag)
+ printf("%6u %12.2lf cpu %12quk mem %12qu io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / (double) AHZ,
+ ci.ci_mem, ci.ci_io, ci.ci_comm);
+ }
+
+ /* finally, return the file descriptor for possible truncation */
+ return (fd);
+}
+
+static u_quad_t
+decode_comp_t(comp)
+ comp_t comp;
+{
+ u_quad_t rv;
+
+ /*
+ * for more info on the comp_t format, see:
+ * /usr/src/sys/kern/kern_acct.c
+ * /usr/src/sys/sys/acct.h
+ * /usr/src/usr.bin/lastcomm/lastcomm.c
+ */
+ rv = comp & 0x1fff; /* 13 bit fraction */
+ comp >>= 13; /* 3 bit base-8 exponent */
+ while (comp--)
+ rv <<= 3;
+
+ return (rv);
+}
+
+/* sort commands, doing the right thing in terms of reversals */
+static int
+cmp_comm(s1, s2)
+ const char *s1, *s2;
+{
+ int rv;
+
+ rv = strcmp(s1, s2);
+ if (rv == 0)
+ rv = -1;
+ return (rflag ? rv : -rv);
+}
+
+/* sort by total user and system time */
+static int
+cmp_usrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ u_quad_t t1, t2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t2 = c2->ci_utime + c2->ci_stime;
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average user and system time */
+static int
+cmp_avgusrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ double t1, t2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t1 /= (double) (c1->ci_calls ? c1->ci_calls : 1);
+
+ t2 = c2->ci_utime + c2->ci_stime;
+ t2 /= (double) (c2->ci_calls ? c2->ci_calls : 1);
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by total number of disk I/O operations */
+static int
+cmp_dkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_io < c2->ci_io)
+ return -1;
+ else if (c1->ci_io == c2->ci_io)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average number of disk I/O operations */
+static int
+cmp_avgdkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ double n1, n2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ n1 = (double) c1->ci_io / (double) (c1->ci_calls ? c1->ci_calls : 1);
+ n2 = (double) c2->ci_io / (double) (c2->ci_calls ? c2->ci_calls : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-storage integral */
+static int
+cmp_cpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_mem < c2->ci_mem)
+ return -1;
+ else if (c1->ci_mem == c2->ci_mem)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-time average memory usage */
+static int
+cmp_avgcpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ u_quad_t t1, t2;
+ double n1, n2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t2 = c2->ci_utime + c2->ci_stime;
+
+ n1 = (double) c1->ci_mem / (double) (t1 ? t1 : 1);
+ n2 = (double) c2->ci_mem / (double) (t2 ? t2 : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the number of invocations */
+static int
+cmp_calls(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_calls < c2->ci_calls)
+ return -1;
+ else if (c1->ci_calls == c2->ci_calls)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
diff --git a/usr.sbin/sa/pathnames.h b/usr.sbin/sa/pathnames.h
new file mode 100644
index 000000000000..3ed865785492
--- /dev/null
+++ b/usr.sbin/sa/pathnames.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $
+ */
+
+#define _PATH_ACCT "/var/account/acct"
+#define _PATH_SAVACCT "/var/account/savacct"
+#define _PATH_USRACCT "/var/account/usracct"
diff --git a/usr.sbin/sa/pdb.c b/usr.sbin/sa/pdb.c
new file mode 100644
index 000000000000..25b0168ffa28
--- /dev/null
+++ b/usr.sbin/sa/pdb.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: pdb.c,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int check_junk __P((struct cmdinfo *));
+static void add_ci __P((const struct cmdinfo *, struct cmdinfo *));
+static void print_ci __P((const struct cmdinfo *, const struct cmdinfo *));
+
+static DB *pacct_db;
+
+int
+pacct_init()
+{
+ DB *saved_pacct_db;
+ int error;
+
+ pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
+ if (pacct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
+ NULL);
+ if (saved_pacct_db == NULL) {
+ error = errno == ENOENT ? 0 : -1;
+ if (error)
+ warn("retrieving process accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing process accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout: if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ }
+
+out: if (error != 0)
+ pacct_destroy();
+ return (error);
+}
+
+void
+pacct_destroy()
+{
+ if (DB_CLOSE(pacct_db) < 0)
+ warn("destroying process accounting stats");
+}
+
+int
+pacct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct cmdinfo newci;
+ char keydata[sizeof ci->ci_comm];
+ int rv;
+
+ bcopy(ci->ci_comm, &keydata, sizeof keydata);
+ key.data = &keydata;
+ key.size = strlen(keydata);
+
+ rv = DB_GET(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %s from process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* XXX compare size if paranoid */
+ /* add the old data to the new data */
+ bcopy(data.data, &newci, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newci, sizeof newci);
+ bcopy(key.data, newci.ci_comm, key.size);
+ }
+
+ add_ci(ci, &newci);
+
+ data.data = &newci;
+ data.size = sizeof newci;
+ rv = DB_PUT(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %s to process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 1) {
+ warnx("duplicate key %s in process accounting stats",
+ ci->ci_comm);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pacct_update()
+{
+ DB *saved_pacct_db;
+ DBT key, data;
+ int error, serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, NULL);
+ if (saved_pacct_db == NULL) {
+ warn("creating process accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving process accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_pacct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+ if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+pacct_print()
+{
+ BTREEINFO bti;
+ DBT key, data, ndata;
+ DB *output_pacct_db;
+ struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
+ int rv;
+
+ bzero(&ci_total, sizeof ci_total);
+ strcpy(ci_total.ci_comm, "");
+ bzero(&ci_other, sizeof ci_other);
+ strcpy(ci_other.ci_comm, "***other");
+ bzero(&ci_junk, sizeof ci_junk);
+ strcpy(ci_junk.ci_comm, "**junk**");
+
+ /*
+ * Retrieve them into new DB, sorted by appropriate key.
+ * At the same time, cull 'other' and 'junk'
+ */
+ bzero(&bti, sizeof bti);
+ bti.compare = sa_cmp;
+ output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (output_pacct_db == NULL) {
+ warn("couldn't sort process accounting stats");
+ return;
+ }
+
+ ndata.data = NULL;
+ ndata.size = 0;
+ rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ /* add to total */
+ add_ci(&ci, &ci_total);
+
+ if (vflag && ci.ci_calls <= cutoff &&
+ (fflag || check_junk(&ci))) {
+ /* put it into **junk** */
+ add_ci(&ci, &ci_junk);
+ goto next;
+ }
+ if (!aflag &&
+ ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
+ /* put into ***other */
+ add_ci(&ci, &ci_other);
+ goto next;
+ }
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+
+next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ }
+
+ /* insert **junk** and ***other */
+ if (ci_junk.ci_calls != 0) {
+ data.data = &ci_junk;
+ data.size = sizeof ci_junk;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+ if (ci_other.ci_calls != 0) {
+ data.data = &ci_other;
+ data.size = sizeof ci_other;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+
+ /* print out the total */
+ print_ci(&ci_total, &ci_total);
+
+ /* print out; if reversed, print first (smallest) first */
+ rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ print_ci(&ci, &ci_total);
+
+ rv = DB_SEQ(output_pacct_db, &data, &ndata,
+ rflag ? R_NEXT : R_PREV);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ }
+ DB_CLOSE(output_pacct_db);
+}
+
+static int
+check_junk(cip)
+ struct cmdinfo *cip;
+{
+ char *cp;
+ size_t len;
+
+ fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls);
+ cp = fgetln(stdin, &len);
+
+ return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
+}
+
+static void
+add_ci(fromcip, tocip)
+ const struct cmdinfo *fromcip;
+ struct cmdinfo *tocip;
+{
+ tocip->ci_calls += fromcip->ci_calls;
+ tocip->ci_etime += fromcip->ci_etime;
+ tocip->ci_utime += fromcip->ci_utime;
+ tocip->ci_stime += fromcip->ci_stime;
+ tocip->ci_mem += fromcip->ci_mem;
+ tocip->ci_io += fromcip->ci_io;
+}
+
+static void
+print_ci(cip, totalcip)
+ const struct cmdinfo *cip, *totalcip;
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8qu ", cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_calls / (double) totalcip->ci_calls);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ else
+ printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_etime / (double) totalcip->ci_etime);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.2fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ (cip->ci_utime + cip->ci_stime) / (double)
+ (totalcip->ci_utime + totalcip->ci_stime));
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag)
+ if (!uflow)
+ printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
+ else
+ printf("%8 ", "*ignore*");
+
+ if (Dflag)
+ printf("%10qutio ", cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10quk*sec ", cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
diff --git a/usr.sbin/sa/sa.8 b/usr.sbin/sa/sa.8
new file mode 100644
index 000000000000..339ab55d29e1
--- /dev/null
+++ b/usr.sbin/sa/sa.8
@@ -0,0 +1,246 @@
+.\"
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $Id: sa.8,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $
+.\"
+.Dd February 25, 1994
+.Dt SA 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm sa
+.Nd print system accounting statistics
+.Sh SYNOPSIS
+.Nm sa
+.Op Fl abcdDfijkKlmnqrstu
+.Op Fl v Ar cutoff
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm sa
+utility reports on, cleans up,
+and generally maintains system
+accounting files.
+.Pp
+.Nm Sa
+is able to condense the the information in
+.Pa /var/account/acct
+into the summary files
+.Pa /var/account/savacct
+and
+.Pa /var/account/usracct ,
+which contain system statistics according
+to command name and login id, respectively.
+This condensation is desirable because on a
+large system,
+.Pa /var/account/acct
+can grow by hundreds of blocks per day.
+The summary files are normally read before
+the accounting file, so that reports include
+all available information.
+.Pp
+If file names are supplied, they are read instead of
+.Pa /var/account/account .
+After each file is read, if the summary
+files are being updated, an updated summary will
+be saved to disk. Only one report is printed,
+after the last file is processed.
+.Pp
+The labels used in the output indicate the following, except
+where otherwise specified by individual options:
+.Bl -tag -width k*sec
+.It Dv avio
+Average number of I/O operations per execution
+.It Dv cp
+Sum of user and system time, in minutes
+.It Dv cpu
+Same as
+.Dv cp
+.It Dv k
+CPU-time averaged core usage, in 1k units
+.It Dv k*sec
+CPU storage integral, in 1k-core seconds
+.It Dv re
+Real time, in minutes
+.It Dv s
+System time, in minutes
+.It Dv tio
+Total number of I/O operations
+.It Dv u
+User time, in minutes
+.El
+.Pp
+The options to
+.Nm sa
+are:
+.Bl -tag -width Ds
+.It Fl a
+List all command names, including those containing unprintable
+characters and those used only once. By default,
+.Nm sa
+places all names containing unprintable characters and
+those used only once under the name ``***other''.
+.It Fl b
+If printing command statistics, sort output by the sum of user and system
+time divided by number of calls.
+.It Fl c
+In addition to the number of calls and the user, system and real times
+for each command, print their percentage of the total over all commands.
+.It Fl d
+If printing command statistics, sort by the average number of disk
+I/O operations. If printing user statistics, print the average number of
+disk I/O operations per user.
+.It Fl D
+If printing command statistics, sort and print by the total number
+of disk I/O operations.
+.It Fl f
+Force no interactive threshold comparison with the
+.Fl v
+option.
+.It Fl i
+Do not read in the summary files.
+.It Fl j
+Instead of the total minutes per category, give seconds per call.
+.It Fl k
+If printing command statistics, sort by the cpu-time average memory
+usage. If printing user statistics, print the cpu-time average
+memory usage.
+.It Fl K
+If printing command statistics, print and sort by the cpu-storage integral.
+.It Fl l
+Separate system and user time; normally they are combined.
+.It Fl m
+Print per-user statistics rather than per-command statistics.
+.It Fl n
+Sort by number of calls.
+.It Fl q
+Create no output other than error messages.
+.It Fl r
+Reverse order of sort.
+.It Fl s
+Truncate the accounting files when done and merge their data
+into the summary files.
+.It Fl t
+For each command, report the ratio of real time to the sum
+of user and system cpu times.
+If the cpu time is too small to report, ``*ignore*'' appears in
+this field.
+.It Fl u
+Superseding all other flags, for each entry
+in the accounting file, print the user ID, total seconds of cpu usage,
+total memory usage, number of I/O operations performed, and
+command name.
+.It Fl v Ar cutoff
+For each command used
+.Ar cutoff
+times or fewer, print the command name and await a reply
+from the terminal. If the reply begins with ``y'', add
+the command to the category ``**junk**''. This flag is
+used to strip garbage from the report.
+.El
+.Pp
+By default, per-command statistics will be printed. The number of
+calls, the total elapsed time in minutes, total cpu and user time
+in minutes, average number of I/O operations, and CPU-time
+averaged core usage will be printed. If the
+.Fl m
+option is specified, per-user statistics will be printed, including
+the user name, the number of commands invoked, total cpu time used
+(in minutes), total number of I/O operations, and CPU storage integral
+for each user. If the
+.Fl u
+option is specified, the uid, user and system time (in seconds),
+CPU storage integral, I/O usage, and command name will be printed
+for each entry in the accounting data file.
+.Pp
+If the
+.Fl u
+flag is specified, all flags other than
+.Fl q
+are ignored. If the
+.Fl m
+flag is specified, only the
+.Fl b ,
+.Fl d ,
+.Fl i ,
+.Fl k ,
+.Fl q ,
+and
+.Fl s
+flags are honored.
+.Pp
+The
+.Nm sa
+utility exits 0 on success, and >0 if an error occurs.
+.Sh FILES
+.Bl -tag -width /var/account/usracct -compact
+.It Pa /var/account/acct
+raw accounting data file
+.It Pa /var/account/savacct
+per-command accounting summary database
+.It Pa /var/account/usracct
+per-user accounting summary database
+.El
+.Sh SEE ALSO
+.Xr ac 8 ,
+.Xr acct 5 ,
+.Xr accton 8 ,
+.Xr lastcomm 1
+.Sh BUGS
+The number of options to this program is absurd, especially considering
+that there's not much logic behind their lettering.
+.Pp
+The field labels should be more consistent.
+.Pp
+NetBSD's VM system does not record the CPU storage integral.
+.Sh CAVEATS
+While the behavior of the options in this version of
+.Nm sa
+was modeled after the original version, there are some intentional
+differences and undoubtedly some unintentional ones as well. In
+particular, the
+.Fl q
+option has been added, and the
+.Fl m
+option now understands more options than it used to.
+.Pp
+The formats of the summary files created by this version of
+.Nm sa
+are very different than the those used by the original version.
+This is not considered a problem, however, because the accounting record
+format has changed as well (since user ids are now 32 bits).
+.Sh HISTORY
+.Nm Sa
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+Its date of origin is unknown to the author.
+.Sh AUTHOR
+.Bl -tag
+Chris G. Demetriou, cgd@postgres.berkeley.edu
+.El
diff --git a/usr.sbin/sa/usrdb.c b/usr.sbin/sa/usrdb.c
new file mode 100644
index 000000000000..2e004731c1fe
--- /dev/null
+++ b/usr.sbin/sa/usrdb.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: usrdb.c,v 1.2 1994/05/18 12:21:33 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int uid_compare __P((const DBT *, const DBT *));
+
+static DB *usracct_db;
+
+int
+usracct_init()
+{
+ DB *saved_usracct_db;
+ BTREEINFO bti;
+ int error;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (usracct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
+ &bti);
+ if (saved_usracct_db == NULL) {
+ error = (errno == ENOENT) ? 0 : -1;
+ if (error)
+ warn("retrieving user accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing user accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing user accounting summary");
+ error = -1;
+ }
+ }
+
+out:
+ if (error != 0)
+ usracct_destroy();
+ return (error);
+}
+
+void
+usracct_destroy()
+{
+ if (DB_CLOSE(usracct_db) < 0)
+ warn("destroying user accounting stats");
+}
+
+int
+usracct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct userinfo newui;
+ u_long uid;
+ int rv;
+
+ uid = ci->ci_uid;
+ key.data = &uid;
+ key.size = sizeof uid;
+
+ rv = DB_GET(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %d from user accounting stats", uid);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* add the old data to the new data */
+ bcopy(data.data, &newui, data.size);
+ if (newui.ui_uid != uid) {
+ warnx("key %d != expected record number %d",
+ newui.ui_uid, uid);
+ warnx("inconsistent user accounting stats");
+ return (-1);
+ }
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newui, sizeof newui);
+ newui.ui_uid = ci->ci_uid;
+ }
+
+ newui.ui_calls += ci->ci_calls;
+ newui.ui_utime += ci->ci_utime;
+ newui.ui_stime += ci->ci_stime;
+ newui.ui_mem += ci->ci_mem;
+ newui.ui_io += ci->ci_io;
+
+ data.data = &newui;
+ data.size = sizeof newui;
+ rv = DB_PUT(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %d to user accounting stats", uid);
+ return (-1);
+ } else if (rv != 0) {
+ warnx("DB_PUT returned 1");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+usracct_update()
+{
+ DB *saved_usracct_db;
+ DBT key, data;
+ BTREEINFO bti;
+ u_long uid;
+ int error, serr, nerr;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, &bti);
+ if (saved_usracct_db == NULL) {
+ warn("creating user accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving user accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_usracct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+out:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+usracct_print()
+{
+ DBT key, data;
+ struct userinfo *ui;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ ui = (struct userinfo *) data.data;
+
+ printf("%-8s %9qu ",
+ user_from_uid(ui->ui_uid, 0), ui->ui_calls);
+
+ t = (double) (ui->ui_utime + ui->ui_stime) /
+ (double) AHZ;
+ if (t < 0.0001) /* kill divide by zero */
+ t = 0.0001;
+
+ printf("%12.2lf%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
+ else
+ printf("%12qu%s", ui->ui_io, "tio");
+
+ /* t is always >= 0.0001; see above */
+ if (kflag)
+ printf("%12qu%s", ui->ui_mem / t, "k");
+ else
+ printf("%12qu%s", ui->ui_mem, "k*sec");
+
+ printf("\n");
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+ }
+}
+
+static int
+uid_compare(k1, k2)
+ const DBT *k1, *k2;
+{
+ u_long d1, d2;
+
+ bcopy(k1->data, &d1, sizeof d1);
+ bcopy(k2->data, &d2, sizeof d2);
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
diff --git a/usr.sbin/sendmail/cf/README b/usr.sbin/sendmail/cf/README
index 53bc084bb88e..c026b141f242 100644
--- a/usr.sbin/sendmail/cf/README
+++ b/usr.sbin/sendmail/cf/README
@@ -813,7 +813,7 @@ Sam Leffler's FlexFAX software is still in beta test -- but he expects a
public version out "later this week" [as of 3/1/93]. The following
blurb is direct from Sam:
- $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.7.2.1 1994/04/18 03:51:03 rgrimes Exp $
+ $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.8 1994/03/19 07:35:36 alm Exp $
How To Obtain This Software (in case all you get is this file)
--------------------------------------------------------------
diff --git a/usr.sbin/sendmail/contrib/expn.pl b/usr.sbin/sendmail/contrib/expn.pl
index 15d287b5c650..b202fd738482 100644
--- a/usr.sbin/sendmail/contrib/expn.pl
+++ b/usr.sbin/sendmail/contrib/expn.pl
@@ -14,7 +14,7 @@ $sockaddr = 'S n a4 x8';
# system requirements:
# must have 'nslookup' and 'hostname' programs.
-# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.1.2.1 1994/04/18 03:52:18 rgrimes Exp $
+# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.2 1994/03/19 07:36:03 alm Exp $
# TODO:
# less magic should apply to command-line addresses
diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c
index 1a9646365b88..8fef644fc7a9 100644
--- a/usr.sbin/sendmail/src/conf.c
+++ b/usr.sbin/sendmail/src/conf.c
@@ -913,7 +913,7 @@ getla()
/* Non Apollo stuff removed by Don Lewis 11/15/93 */
#ifndef lint
-static char rcsid[] = "@(#)$Id: conf.c,v 1.5.2.1 1994/04/18 03:53:45 rgrimes Exp $";
+static char rcsid[] = "@(#)$Id: conf.c,v 1.6 1994/03/19 07:36:47 alm Exp $";
#endif /* !lint */
#ifdef apollo
diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts
index 00c01e6e58da..16d22fbd43e0 100644
--- a/usr.sbin/sliplogin/slip.hosts
+++ b/usr.sbin/sliplogin/slip.hosts
@@ -1,6 +1,6 @@
#
# login local-addr remote-addr mask opt1 opt2
-# (normal,compress,noicmp)
+# (normal,compressautocomp,noicmp)
#
Shavoc okeeffe havoc 0xffffff00 normal
Soxford okeeffe oxford-gw 0xffffff00 compress
diff --git a/usr.sbin/sliplogin/sliplogin.c b/usr.sbin/sliplogin/sliplogin.c
index a4cf21491733..3ca006cd847e 100644
--- a/usr.sbin/sliplogin/sliplogin.c
+++ b/usr.sbin/sliplogin/sliplogin.c
@@ -280,7 +280,7 @@ main(argc, argv)
#ifdef POSIX
if (fork() > 0)
exit(0);
- if (setsid() != 0)
+ if (setsid() == -1)
perror("setsid");
#else
if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
@@ -318,6 +318,11 @@ main(argc, argv)
}
findid(name);
}
+ if (!isatty(0)) {
+ (void) fprintf(stderr, "access denied - stdin is not a tty\n");
+ syslog(LOG_ERR, "access denied - stdin is not a tty\n");
+ exit(1);
+ }
(void) fchmod(0, 0600);
(void) fprintf(stderr, "starting slip login for %s\n", loginname);
#ifdef POSIX
diff --git a/usr.sbin/slstat/Makefile b/usr.sbin/slstat/Makefile
new file mode 100644
index 000000000000..21309a612b45
--- /dev/null
+++ b/usr.sbin/slstat/Makefile
@@ -0,0 +1,11 @@
+# from: @(#)Makefile 5.6 (Berkeley) 4/23/91
+# $Id: Makefile,v 1.1.1.1 1994/06/17 06:42:36 rich Exp $
+
+PROG= slstat
+MAN8= slstat.8
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/slstat/slstat.8 b/usr.sbin/slstat/slstat.8
new file mode 100644
index 000000000000..0194cbf80e95
--- /dev/null
+++ b/usr.sbin/slstat/slstat.8
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1986 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.
+.\"
+.\" @(#)slstat.8 6.8 (Berkeley) 6/20/91
+.\"
+.TH SLSTAT 1 "June 20, 1991"
+.UC 4
+.SH NAME
+slstat \- report serial line IP statistics
+.SH SYNOPSIS
+.nf
+.ft B
+slstat [ \-i interval ] [ \-v ] [ \-r ] [ unit ] [ system ] [ core ]
+.ft R
+.fi
+.SH DESCRIPTION
+.I Slstat
+reports certain kernel statistics kept about serial line internet
+protocol traffic.
+.PP
+The options are as follows:
+.TP
+\-i
+Repeat the display indefinitely every
+.I interval
+seconds.
+If no
+.I interval
+is specified, the default is 5 seconds.
+.TP
+\-v
+Verbose display of extra fields of information.
+.TP
+\-r
+Display all values in rate per second that ammount per interval.
+.TP
+unit
+is a single digit specifying the slip interface. The default unit is
+.I 0
+for interface
+.I sl0.
+.TP
+system
+Extract the name list from the specified system instead of the default, /386bsd.
+.TP
+core
+Extract values associated with the name list from the specified
+core instead of the default, /dev/kmem.
+.PP
+By default,
+.I vmstat
+displays the following information:
+.PP
+.TP
+in
+bytes received
+.TP
+out
+bytes sent
+.TP
+pack
+packets received or sent
+.TP
+comp
+compressed packets received or sent
+.TP
+uncomp
+uncompressed packets received or sent
+.TP
+unknwn
+inbound packets of unknown type
+.TP
+toss
+inbound packets tossed because of error
+.TP
+other
+all other inbound or outbound ip packets
+.TP
+err
+input or output errors
+.TP
+search
+searches for connection state
+.TP
+miss
+times we could not find a connectoin state
+.TP
+coll
+collisions with end of clists.
+If you get many collisions (more than one or two
+a day) you probably do not have enough clists
+and you should increase "nclist" in param.c.
+.SH EXAMPLES
+The command ``slstat -i 5'' will print what the system is doing every five
+seconds.
+.SH FILES
+.ta \w'/dev/kmem 'u
+/386bsd default kernel namelist
+.br
+/dev/kmem default memory file
+.SH SEE ALSO
+.IR fstat (1),
+.IR netstat (1),
+.IR nfsstat (1),
+.IR ps (1),
+.IR systat (1),
+.IR iostat (8),
+.IR pstat (8)
+.sp
+The sections starting with ``Interpreting system activity'' in
+.IR "Installing and Operating 4.3BSD" .
+.SH BUGS
+
diff --git a/usr.sbin/slstat/slstat.c b/usr.sbin/slstat/slstat.c
new file mode 100644
index 000000000000..ddcee8b10f3e
--- /dev/null
+++ b/usr.sbin/slstat/slstat.c
@@ -0,0 +1,287 @@
+/*
+ * print serial line IP statistics:
+ * slstat [-i interval] [-v] [interface] [system] [core]
+ *
+ * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of
+ * California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: slstat.c,v 1.1.1.1 1994/06/17 06:42:39 rich Exp $";
+#endif
+
+#include <stdio.h>
+#include <paths.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#define INET
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <signal.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <net/slcompress.h>
+#include <net/if_slvar.h>
+
+struct nlist nl[] = {
+#define N_SOFTC 0
+ { "_sl_softc" },
+ "",
+};
+
+char *system = _PATH_UNIX;
+char *kmemf = NULL;
+
+int kflag;
+int rflag;
+int vflag;
+unsigned interval = 5;
+int unit;
+
+extern char *malloc();
+extern off_t lseek();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ --argc; ++argv;
+ while (argc > 0) {
+ if (strcmp(argv[0], "-v") == 0) {
+ ++vflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-r") == 0) {
+ ++rflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-i") == 0 && argv[1] &&
+ isdigit(argv[1][0])) {
+ interval = atoi(argv[1]);
+ if (interval <= 0)
+ usage();
+ ++argv, --argc;
+ ++argv, --argc;
+ continue;
+ }
+ if (isdigit(argv[0][0])) {
+ unit = atoi(argv[0]);
+ if (unit < 0)
+ usage();
+ ++argv, --argc;
+ continue;
+ }
+ if (kflag)
+ usage();
+
+ system = *argv;
+ ++argv, --argc;
+ if (argc > 0) {
+ kmemf = *argv++;
+ --argc;
+ kflag++;
+ }
+ }
+ if (kvm_openfiles(system, kmemf, NULL) < 0) {
+ (void)fprintf(stderr,
+ "slstat: kvm_openfiles(%s,%s,0): %s\n",
+ system, kmemf, kvm_geterr());
+ exit(1);
+ }
+ if ((c = kvm_nlist(nl)) != 0) {
+ if (c > 0) {
+ (void)fprintf(stderr,
+ "slstat: undefined symbols in %s:", system);
+ for (c = 0; c < sizeof(nl)/sizeof(nl[0]); c++)
+ if (nl[c].n_type == 0)
+ fprintf(stderr, " %s", nl[c].n_name);
+ (void)fputc('\n', stderr);
+ } else
+ (void)fprintf(stderr, "slstat: kvm_nlist: %s\n",
+ kvm_geterr());
+ exit(1);
+ }
+ intpr();
+ exit(0);
+}
+
+#define V(offset) ((line % 20)? ((sc->offset - osc->offset) / (rflag ? interval : 1)) : sc->offset)
+#define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate))
+
+usage()
+{
+ static char umsg[] =
+ "usage: slstat [-i interval] [-v] [unit] [system] [core]\n";
+
+ fprintf(stderr, umsg);
+ exit(1);
+}
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ */
+intpr()
+{
+ register int line = 0;
+ int oldmask;
+ void catchalarm();
+ struct sl_softc *sc, *osc;
+ off_t addr;
+
+ addr = nl[N_SOFTC].n_value + unit * sizeof(struct sl_softc);
+ sc = (struct sl_softc *)malloc(AMT);
+ osc = (struct sl_softc *)malloc(AMT);
+ bzero((char *)osc, AMT);
+
+ while (1) {
+ if (kread(addr, (char *)sc, AMT) < 0)
+ perror("kmem read");
+ (void)signal(SIGALRM, catchalarm);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if ((line % 20) == 0) {
+ printf("%8.8s %6.6s %6.6s %6.6s %6.6s",
+ "in", "pack", "comp", "uncomp", "unknwn");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s",
+ "toss", "other", "err");
+ printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s",
+ "out", "pack", "comp", "uncomp", "other");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s %6.6s",
+ "search", "miss", "err", "coll");
+ putchar('\n');
+ }
+ printf("%8u %6d %6u %6u %6u",
+ V(sc_bytesrcvd),
+ V(sc_if.if_ipackets),
+ V(sc_comp.sls_compressedin),
+ V(sc_comp.sls_uncompressedin),
+ V(sc_comp.sls_errorin));
+ if (vflag)
+ printf(" %6u %6u %6u",
+ V(sc_comp.sls_tossed),
+ V(sc_if.if_ipackets) -
+ V(sc_comp.sls_compressedin) -
+ V(sc_comp.sls_uncompressedin) -
+ V(sc_comp.sls_errorin),
+ V(sc_if.if_ierrors));
+ printf(" | %8u %6d %6u %6u %6u",
+ V(sc_bytessent) / (rflag ? interval : 1),
+ V(sc_if.if_opackets),
+ V(sc_comp.sls_compressed),
+ V(sc_comp.sls_packets) - V(sc_comp.sls_compressed),
+ V(sc_if.if_opackets) - V(sc_comp.sls_packets));
+ if (vflag)
+ printf(" %6u %6u %6u %6u",
+ V(sc_comp.sls_searches),
+ V(sc_comp.sls_misses),
+ V(sc_if.if_oerrors),
+ V(sc_if.if_collisions));
+ putchar('\n');
+ fflush(stdout);
+ line++;
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (! signalled) {
+ sigpause(0);
+ }
+ sigsetmask(oldmask);
+ signalled = 0;
+ (void)alarm(interval);
+ bcopy((char *)sc, (char *)osc, AMT);
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+void
+catchalarm()
+{
+ signalled = 1;
+}
+
+#include <kvm.h>
+#include <fcntl.h>
+
+int kd;
+
+kopen(system, kmemf, errstr)
+ char *system;
+ char *kmemf;
+ char *errstr;
+{
+ if (strcmp(system, _PATH_UNIX) == 0 &&
+ strcmp(kmemf, _PATH_KMEM) == 0) {
+ system = 0;
+ kmemf = 0;
+ }
+ kd = kvm_openfiles(system, kmemf, (void *)0);
+ if (kd == 0)
+ return -1;
+
+ return 0;
+}
+
+int
+knlist(system, nl, errstr)
+ char *system;
+ struct nlist *nl;
+ char *errstr;
+{
+ if (kd == 0)
+ /* kopen() must be called first */
+ abort();
+
+ if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) {
+ fprintf(stderr, "%s: %s: no namelist\n", errstr, system);
+ return -1;
+ }
+ return 0;
+}
+
+int
+kread(addr, buf, size)
+ off_t addr;
+ char *buf;
+ int size;
+{
+ if (kvm_read((char *)addr, buf, size) != size)
+ return -1;
+ return 0;
+}
diff --git a/usr.sbin/vidcontrol/Makefile b/usr.sbin/vidcontrol/Makefile
new file mode 100644
index 000000000000..11636b96dba2
--- /dev/null
+++ b/usr.sbin/vidcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG= vidcontrol
+SRCS= vidcontrol.c decode.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vidcontrol/decode.c b/usr.sbin/vidcontrol/decode.c
new file mode 100644
index 000000000000..88861db6e8f2
--- /dev/null
+++ b/usr.sbin/vidcontrol/decode.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: decode.c,v 1.1 1994/05/20 12:20:37 sos Exp $
+ */
+
+#include <stdio.h>
+
+int decode(FILE *fd, char *buffer)
+{
+ int n, pos = 0;
+ char *p;
+ char temp[128];
+
+#define DEC(c) (((c) - ' ') & 0x3f)
+
+ do {
+ if (!fgets(temp, sizeof(temp), fd))
+ return(0);
+ } while (strncmp(temp, "begin ", 6));
+ sscanf(temp, "begin %o %s", &n, temp);
+ for (;;) {
+ if (!fgets(p = temp, sizeof(temp), fd))
+ return(0);
+ if ((n = DEC(*p)) <= 0)
+ break;
+ for (++p; n > 0; p += 4, n -= 3)
+ if (n >= 3) {
+ buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4;
+ buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2;
+ buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]);
+ }
+ else {
+ if (n >= 1) {
+ buffer[pos++] =
+ DEC(p[0])<<2 | DEC(p[1])>>4;
+ }
+ if (n >= 2) {
+ buffer[pos++] =
+ DEC(p[1])<<4 | DEC(p[2])>>2;
+ }
+ if (n >= 3) {
+ buffer[pos++] =
+ DEC(p[2])<<6 | DEC(p[3]);
+ }
+ }
+ }
+ if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n"))
+ return(0);
+ return(pos);
+}
diff --git a/usr.sbin/vidcontrol/path.h b/usr.sbin/vidcontrol/path.h
new file mode 100644
index 000000000000..709acbc375dc
--- /dev/null
+++ b/usr.sbin/vidcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1
new file mode 100644
index 000000000000..5bc0af0372fe
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.1
@@ -0,0 +1,112 @@
+.\"
+.\" vidcontrol - a utility for manipulating the syscons video driver
+.\"
+.\" 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.
+.\"
+.\" @(#)vidcontrol.1
+.\"
+.TH vidcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+vidcontrol - a utility for manipulating the syscons video driver.
+.SH SYNOPSIS
+.na
+.B vidcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B vidcontrol
+command is used to set various options for the syscons video driver,
+such as video mode, colors, cursor, scrnmaps, font,
+screensaver type and timeout.
+
+A new video mode is selected by specifying its name as an argument to
+.B vidcontrol
+eg. "
+.B vidcontrol 80x25
+".
+
+The modes currently supported: 80x25 and 80x50 text.
+
+The colors used when displaying text can be changed by specifying the
+foreground color (eg. "
+.B vidcontrol white
+"), or both a foreground & background
+color (eg. "
+.B vidcontrol yellow blue
+").
+
+To see the supported colors on a given platform use "
+.B vidcontrol show
+".
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-r\ " foreground\ background
+Change reverse mode colors to
+.B foreground
+and
+.B background
+.
+.TP
+.BI "\-b\ " color
+Set border color to
+.B color
+(only supported on VGA hardware):
+.TP
+.BI "\-c\ " start.end
+Change the cursor apperance. The cursor is changed to a shape that starts
+on scanline
+.B start
+and ends on scanline
+.B end
+.
+.TP
+.BI "\-l\ " scrmap
+Install screen output map file from
+.I scrmap
+.TP
+.BI "\-L\ "
+Install default screen output map.
+.TP
+.BI "\-f\ " size\ file
+Load font
+.I file
+for
+.I size
+(currently, only 8x8, 8x14 or 8x16).
+The fontfile can be either uuencoded or in raw binary format.
+.TP
+.BI "\-t\ " N|off
+Sets the screensaver timeout to
+.I N
+seconds, or turns it
+.I off
+.TP
+.BI "\-s\ " NAME|help
+Sets the screensaver appearance to
+.I NAME .
+Use \-s help to print a list of the available screen savers.
+.PP
+.SH FILES
+/usr/share/syscons/fonts
+/usr/share/syscons/scrnmaps
+.SH BUGS
+Report when found.
+.SH "SEE ALSO"
+.BR kbdcontrol(1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/SYSCONS
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
new file mode 100644
index 000000000000..3278f921092a
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.c
@@ -0,0 +1,472 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: vidcontrol.c,v 1.4 1994/05/26 04:13:59 jkh Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include <sys/errno.h>
+#include "path.h"
+
+
+char legal_colors[16][16] = {
+ "black", "blue", "green", "cyan",
+ "red", "magenta", "brown", "white",
+ "grey", "lightblue", "lightgreen", "lightcyan",
+ "lightred", "lightmagenta", "yellow", "lightwhite"
+ };
+int hex = 0;
+int number, verbose = 0;
+char letter;
+struct vid_info info;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+void
+load_scrnmap(char *filename)
+{
+ FILE *fd;
+ int i, size;
+ char *name;
+ scrmap_t scrnmap;
+ char *prefix[] = {"", "", SCRNMAP_PATH, SCRNMAP_PATH, NULL};
+ char *postfix[] = {"", ".scm", "", ".scm"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("screenmap file not found");
+ return;
+ }
+ size = sizeof(scrnmap);
+ if (decode(fd, &scrnmap) != size) {
+ rewind(fd);
+ if (fread(&scrnmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad scrnmap file\n");
+ close(fd);
+ return;
+ }
+ }
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load screenmap");
+ close(fd);
+}
+
+
+void
+load_default_scrnmap()
+{
+ int i;
+ scrmap_t scrnmap;
+
+ for (i=0; i<256; i++)
+ *((char*)&scrnmap + i) = i;
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load default screenmap");
+}
+
+
+void
+print_scrnmap()
+{
+ unsigned char map[256];
+ int i;
+
+ if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
+ perror("getting scrnmap");
+ return;
+ }
+ for (i=0; i<sizeof(map); i++) {
+ if (i > 0 && i % 16 == 0)
+ fprintf(stdout, "\n");
+ if (hex)
+ fprintf(stdout, " %02x", map[i]);
+ else
+ fprintf(stdout, " %03d", map[i]);
+ }
+ fprintf(stdout, "\n");
+
+}
+
+
+void
+load_font(char *type, char *filename)
+{
+ FILE *fd;
+ int i, io, size;
+ char *name, *fontmap;
+ char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL};
+ char *postfix[] = {"", ".fnt", "", ".fnt"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("font file not found");
+ return;
+ }
+ if (!strcmp(type, "8x8")) {
+ size = 8*256;
+ io = PIO_FONT8x8;
+ }
+ else if (!strcmp(type, "8x14")) {
+ size = 14*256;
+ io = PIO_FONT8x14;
+ }
+ else if (!strcmp(type, "8x16")) {
+ size = 16*256;
+ io = PIO_FONT8x16;
+ }
+ else {
+ perror("bad font size specification");
+ close(fd);
+ return;
+ }
+ fontmap = (char*) malloc(size);
+ if (decode(fd, fontmap) != size) {
+ rewind(fd);
+ if (fread(fontmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad font file\n");
+ close(fd);
+ free(fontmap);
+ return;
+ }
+ }
+ if (ioctl(0, io, fontmap) < 0)
+ perror("can't load font");
+ close(fd);
+ free(fontmap);
+}
+
+
+void
+set_screensaver_timeout(char *arg)
+{
+ int nsec;
+
+ if (!strcmp(arg, "off"))
+ nsec = 0;
+ else {
+ nsec = atoi(arg);
+ if ((*arg == '\0') || (nsec < 1)) {
+ fprintf(stderr, "argument must be a positive number\n");
+ return;
+ }
+ }
+ if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
+ perror("setting screensaver period");
+}
+
+
+void
+set_screensaver_type(char *type)
+{
+ ssaver_t saver;
+ int i, e;
+
+ if (!strcmp(type, "help")) {
+ i = 0;
+ printf("available screen saver types:\n");
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0)
+ printf("\t%s\n", saver.name);
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ } else {
+ i = 0;
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0 && !strcmp(type, saver.name)) {
+ if (ioctl(0, CONS_SSAVER, &saver) == -1)
+ perror("setting screensaver type");
+ return;
+ }
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ else
+ fprintf(stderr, "%s: No such screensaver\n", type);
+ }
+}
+
+void
+set_cursor_values(char *size)
+{
+ int start, end;
+ int n;
+ char *v1;
+
+ start = strtol(size, &v1, 0);
+ if ((start < 0) || (*v1 != '.'))
+ goto badopt;
+ size = ++v1;
+ end = strtol(size, &v1, 0);
+ if ((end < 0) || (*size == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -c must be start.end\n");
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "setting cursor to %d.%d\n", start, end);
+ fprintf(stdout, "[=%d;%dC", start, end);
+}
+
+
+int
+video_mode(int argc, char **argv, int *index)
+{
+ int mode;
+
+ if (*index < argc) {
+ if (!strcmp(argv[*index], "80x25"))
+ mode = CONS_80x25TEXT;
+ else if (!strcmp(argv[*index], "80x50"))
+ mode = CONS_80x50TEXT;
+ else
+ return;
+ if (ioctl(0, mode, NULL) < 0)
+ perror("Cannot set videomode");
+ (*index)++;
+ }
+ return;
+}
+
+
+int
+get_color_number(char *color)
+{
+ int i;
+
+ for (i=0; i<16; i++)
+ if (!strcmp(color, legal_colors[i]))
+ return i;
+ return -1;
+}
+
+
+int
+set_normal_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if (*index < argc && (color = get_color_number(argv[*index])) != -1) {
+ (*index)++;
+ fprintf(stderr, "[=%dF", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dG", color);
+ }
+ }
+}
+
+
+set_reverse_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if ((color = get_color_number(argv[*(index)-1])) != -1) {
+ fprintf(stderr, "[=%dH", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dI", color);
+ }
+ }
+}
+
+
+set_border_color(char *arg)
+{
+ int color;
+
+ if ((color = get_color_number(arg)) != -1) {
+ fprintf(stderr, "[=%dA", color);
+ }
+ else
+ usage();
+}
+
+
+test_frame()
+{
+ int i;
+
+ fprintf(stdout, "[=0G\n\n");
+ for (i=0; i<8; i++) {
+ fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s"
+ "[=15F[=0G %2d [=%dF%-16s "
+ "[=15F %2d [=%dGBACKGROUND[=0G\n",
+ i, i, legal_colors[i], i+8, i+8,
+ legal_colors[i+8], i, i);
+ }
+ fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n",
+ info.mv_norm.fore, info.mv_norm.back,
+ info.mv_rev.fore, info.mv_rev.back);
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: vidcontrol mode (available modes: 80x25, 80x50)\n"
+" show (show available colors)\n"
+" fgcol bgcol (set fore- & background colors)\n"
+" -r fgcol bgcol (set reverse fore- & background colors)\n"
+" -b color (set border color)\n"
+" -c n.m (set cursor start line n & end line m)\n"
+#if 0
+" -d (dump screenmap to stdout)\n"
+#endif
+" -l filename (load srceenmap file filename)\n"
+" -L (load default screenmap)\n"
+" -f DxL filename (load font, D dots wide & L lines high)\n"
+" -s saver | help (set screensaver type or help for a list)\n"
+" -t N (set screensaver timeout in seconds)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+
+ info.size = sizeof(info);
+ if (ioctl(0, CONS_GETINFO, &info) < 0) {
+ perror("Must be on a vty");
+ exit(1);
+ }
+ while((opt = getopt(argc, argv, "b:c:df:l:Lr:s:t:vx")) != -1)
+ switch(opt) {
+ case 'c':
+ set_cursor_values(optarg);
+ break;
+ case 'b':
+ set_border_color(optarg);
+ break;
+ case 'd':
+ print_scrnmap();
+ break;
+ case 'f':
+ load_font(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'l':
+ load_scrnmap(optarg);
+ break;
+ case 'L':
+ load_default_scrnmap();
+ break;
+ case 'r':
+ set_reverse_colors(argc, argv, &optind);
+ break;
+ case 's':
+ set_screensaver_type(optarg);
+ break;
+ case 't':
+ set_screensaver_timeout(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if (video_mode(argc, argv, &optind)) ;
+ if (set_normal_colors(argc, argv, &optind)) ;
+ if (optind < argc && !strcmp(argv[optind], "show")) {
+ test_frame();
+ optind++;
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
diff --git a/usr.sbin/xten/Install.notes b/usr.sbin/xten/Install.notes
new file mode 100644
index 000000000000..9725ba402b58
--- /dev/null
+++ b/usr.sbin/xten/Install.notes
@@ -0,0 +1,222 @@
+Installation Notes for X-10 software
+Eugene W. Stark (stark@cs.sunysb.edu)
+October 30, 1993
+
+The TW523 is a carrier-current modem for home control/automation purposes.
+It is made by:
+
+ X-10 Inc.
+ 185A LeGrand Ave.
+ Northvale, NJ 07647
+ USA
+ (201) 784-9700 or 1-800-526-0027
+
+ X-10 Home Controls Inc.
+ 1200 Aerowood Drive, Unit 20
+ Mississauga, Ontario
+ (416) 624-4446 or 1-800-387-3346
+
+The TW523 is designed for communications using the X-10 protocol,
+which is compatible with a number of home control systems, including
+Radio Shack "Plug 'n Power(tm)" and Stanley "Lightmaker(tm)."
+I bought my TW523 from:
+
+ Home Control Concepts
+ 9353-C Activity Road
+ San Diego, CA 92126
+ (619) 693-8887
+
+They supplied me with the TW523 (which has an RJ-11 four-wire modular
+telephone connector), a modular cable, an RJ-11 to DB-25 connector with
+internal wiring, documentation from X-10 on the TW523 (very good),
+an instruction manual by Home Control Concepts (not very informative),
+and a floppy disk containing binary object code of some demonstration/test
+programs and of a C function library suitable for controlling the TW523
+by an IBM PC under MS-DOS (not useful to me other than to verify that
+the unit worked). I suggest saving money and buying the bare TW523
+rather than the TW523 development kit (what I bought), because if you
+are running 386BSD you don't really care about the DOS binaries.
+For details on the X-10 protocol itself, refer to the documentation from
+X-10 Inc.
+
+The interface to the TW-523 consists of four wires on the RJ-11 connector,
+which are jumpered to somewhat more wires on the DB-25 connector, which
+in turn is intended to plug into the PC parallel printer port. I dismantled
+the DB-25 connector to find out what they had done:
+
+ Signal RJ-11 pin DB-25 pin(s) Parallel Port
+ Transmit TX 4 (Y) 2, 4, 6, 8 Data out
+ Receive RX 3 (G) 10, 14 -ACK, -AutoFeed
+ Common 2 (R) 25 Common
+ Zero crossing 1 (B) 17 -Select Input
+
+I use the TW-523 and this software in the USA with 120V/60Hz power.
+Phil Sampson (vk2jnt@gw.vk2jnt.ampr.org OR sampson@gidday.enet.dec.com)
+in Australia has reported success in using a TW-7223 (a local version
+of the TW-523) and Tandy modules with this software under 240V/50Hz power.
+For reasons explained in the comments in the driver, it will probably not
+work if you have three-phase power, but this is usually not the case for
+normal residences and offices.
+
+
+1. Installing the TW523 Device Driver
+
+I assume that you are running FreeBSD. If you are running some other
+system, you are more or less on your own, though I can try to help if you
+have problems.
+
+Check the configuration parameters at the beginning of the file
+
+ /sys/i386/isa/tw.c
+
+Probably the only thing you might need to change is to change the
+definition of HALFCYCLE from 8333 to 10000 if you are using 50Hz power.
+The driver assumes that the TW523 device is connected to a parallel port.
+See the comments near the beginning of the file to find out where to
+get a TW523 if you don't have one, and how to make a cable for it to
+connect to your parallel port.
+
+Add a line like the following
+
+ device tw0 at isa? port 0x278 tty irq 5 vector twintr
+
+to /sys/i386/conf/YOURSYSTEM, but make sure to change the I/O port and
+interrupt to match your hardware configuration.
+
+Cd to /sys/i386/conf and do "config YOURSYSTEM".
+Cd to /sys/compile/YOURSYSTEM and do "make depend", then "make".
+(If you have any troubles, I suggest starting fresh by doing a full
+"make clean; make depend; make".) Assuming the make works correctly, do
+
+ mv /386bsd /386bsd.old
+ mv 386bsd /386bsd
+
+(If you are not a trusting person, or you don't have any spare fixit
+floppies with working kernels lying around, don't do this without testing
+the kernel first by copying it to a fixit floppy and booting from that.)
+
+Reboot the system. You should see a line indicating that the TW523 has
+been configured as the system comes up. If you see this line, then probably
+everything is going to work OK, because the TW523 will only get configured
+if the driver is able to sync to the power line. If the TW523 is not plugged
+in, or the driver is not getting sync for some reason, then you won't see
+any message on bootup.
+
+NOTE: I have received a report that some multi IDE/SIO/PARALLEL cards
+"cheat" and use TTL outputs rather than pullup open collector outputs,
+and this can mess up the scheme by which sync gets to the driver.
+If you are having trouble getting the driver to work, you might want to
+look into this possibility.
+
+In directory /dev, execute the command
+
+ MAKEDEV tw0
+
+
+2. Installing the X-10 Daemon
+
+Go to the xten source directory (probably /usr/src/contrib/xten).
+Check over the file "paths.h", if desired, to make sure that the entries
+are reasonable for your system. On my system, I have a special UID "xten"
+for the daemon. If you want to do this, too, you will have to add this UID
+to your /etc/master.passwd in the usual way. Otherwise, use "root" or
+"daemon" or something. You should change the ownership of /dev/tw0 to
+match this UID, so that the daemon will be able to access the TW-523.
+Edit the file Makefile.inc in the source directory to specify this UID:
+
+ xtenuser= xten
+
+Then run "make". If everything is OK, run
+
+ make install
+
+This should install the daemon "xtend" and the command "xten".
+
+Make sure the directory /var/spool/xten exists and is owned by the UID
+you selected above. This directory is used by the daemon for its log and
+device status files. When it is run, the daemon will also create a socket
+/var/run/tw523 and it will put its pid in /var/run/xtend.pid so that it can
+be signalled from shell scripts.
+
+Add the following lines to your /etc/rc.local file:
+
+ if [ -x /usr/libexec/xtend ]; then
+ echo -n ' xtend'; /usr/libexec/xtend
+ fi
+
+This will cause the X-10 daemon to be invoked automatically when you boot
+the system. To test the installation, you can either reboot now, or
+you can just run "xtend" by hand. The daemon should start up, and it should
+create files in /var/spool/xten. Check the file /var/spool/xten/Log to
+make sure that the daemon started up without any errors.
+
+Now you are ready to start trying X-10 commands. Try doing
+
+ xten A 1 Off
+ xten A 1 On 1 Dim:10
+
+etc. The "xten" program expects a house code as its first argument, then
+a series of key codes, which are either unit names ("1" through "16") or
+else are command names. You can find the list of command names by looking
+at the table in the file "xten.c". Each key code can optionally be followed
+by a colon : then a number specifying the number of times that command is
+to be transmitted without gaps between packets. The default is 2, and this
+is the normal case, but some commands like Bright and Dim are designed to
+be transmitted with counts other than 2. See the X-10 documentation for
+more detail.
+
+The "xten" program works by connecting to "xtend" through a socket, and
+asking that the X-10 codes be transmitted over the TW523. All activity
+on the TW523 is logged by the daemon in /var/spool/xten/Log. The daemon
+also attempts to track the state of all devices. (Of course, most X-10
+devices do not transmit when they are operated manually, so if somebody
+operates a device manually there is no way the X-10 daemon will know
+about it.)
+
+3. Low-level Programming of the TW523 Driver
+
+Normally, you would never operate the TW523 directly, rather you would
+use the shell command "xten" or you would connect to "xtend" through its
+socket. However, if you don't want to run "xtend", you can manipulate
+the TW523 directly through the device /dev/tw0. Have a look at the
+xtend code for a programming example.
+
+The driver supports read(), write(), and select() system calls.
+The driver allows multiple processes to read and write simultaneously,
+but there is probably not much sense in having more than one reader or more
+than one writer at a time, and in fact there may currently be a race
+condition in the driver if two processes try to transmit simultaneously
+(due to unsynchronized access to the sc_pkt structure in tw_sc).
+
+Transmission is done by calling write() to send three byte packets of data.
+The first byte contains a four bit house code (0=A to 15=P). The second byte
+contains five bit unit/key code (0=unit 1 to 15=unit 16, 16=All Units Off
+to 31 = Status Request). The third byte specifies the number of times the
+packet is to be transmitted without any gaps between successive transmissions.
+Normally this is 2, as per the X-10 documentation, but sometimes (e.g. for
+bright and dim codes) it can be another value. Each call to write can specify
+an arbitrary number of data bytes, but at most one packet will actually be
+processed in any call. Any incomplete packet is buffered until a subsequent
+call to write() provides data to complete it. Successive calls to write()
+leave a three-cycle gap between transmissions, per the X-10 documentation.
+The driver transmits each bit only once per half cycle, not three times as
+the X-10 documentation states, because the TW523 only provides sync on
+each power line zero crossing. So, the driver will probably not work
+properly if you have three-phase service. Most residences use a two-wire
+system, for which the driver does work.
+
+Reception is done using read(). The driver produces a series of three
+character packets. In each packet, the first character consists of flags,
+the second character is a four bit house code (0-15), and the third character
+is a five bit key/function code (0-31). The flags are the following:
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
+The select() system call can be used in the usual way to determine if there
+is data ready for reading.
+
+
+ Happy Controlling!
+ Gene Stark
+ stark@cs.sunysb.edu
diff --git a/usr.sbin/xten/Makefile b/usr.sbin/xten/Makefile
new file mode 100644
index 000000000000..6300ec9effed
--- /dev/null
+++ b/usr.sbin/xten/Makefile
@@ -0,0 +1,10 @@
+# Makefile for xten (Stark) 10/30/93
+
+PROG= xten
+SRCS= xten.c
+CFLAGS+=-I. -I/usr/src/libexec/xtend
+
+MAN1= xten.1
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/xten/xten.1 b/usr.sbin/xten/xten.1
new file mode 100644
index 000000000000..1c7d51de7963
--- /dev/null
+++ b/usr.sbin/xten/xten.1
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" 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 Eugene W. Stark.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+.\"
+.Th XTEN 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt XTEN 1
+.Os BSD FreeBSD
+.Sh NAME
+xten \- transmit X-10 commands
+.Sh SYNOPSIS
+.Nm xten
+[ - ] house key[:cnt] [ [ house ] key[:cnt] .\|.\|. ]
+.Sh DESCRIPTION
+.Nm Xten
+is a command-line interface to the X-10 daemon.
+When invoked with a one-letter house code (A-P) and a series of key/unit
+codes as arguments, it requests the X-10 daemon to transmit a corresponding
+series of X-10 packets. The X-10 daemon makes its best effort to ensure
+that the packets are all transmitted correctly, though in general it is
+not possible to tell whether the commands were actually received and
+executed by the remote X-10 devices.
+.Pp
+When invoked with the single argument \-,
+.Nm xten
+enters an interactive mode in which a line is repeatedly read from the
+standard input, sent to the X-10 daemon, and the one-line response from
+the daemon printed on the standard output.
+.Sh OPTIONS
+The
+.I
+house
+argument is a one-letter house code in the range A-P.
+All the X-10 requests generated will refer to this house code.
+Each
+.I
+key
+is either a numeric unit code in the range 1-16, or else
+is a string that specifies an X-10 function. The possible
+function code strings are:
+.Bl -diag
+.It AllUnitsOff
+.It AllLightsOn
+.It On
+.It Off
+.It Dim
+.It Bright
+.It AllLightsOff
+.It ExtendedCode
+.It HailRequest
+.It HailAcknowledge
+.It PreSetDim0
+.It PreSetDim1
+.It ExtendedData
+.It StatusOn
+.It StatusOff
+.It StatusRequest
+.El
+.Pp
+Each
+.I
+key
+may be followed by an optional numeric
+.I
+cnt,
+which specifies the number of packets that are to be sent with that
+key code without gaps. If this argument is omitted, two packets
+are transmitted. The ability to specify numbers of packets other than
+two is used by the X-10
+.I
+Dim
+and
+.I
+Bright
+commands.
+.Sh SEE ALSO
+.Xr xtend 8
+.Xr tw 4
+.Sh FILES
+.Bl -tag -width /var/spool/xten/Status -compact
+.It Pa /dev/tw0
+the TW523 special file
+.El
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/usr.sbin/xten/xten.c b/usr.sbin/xten/xten.c
new file mode 100644
index 000000000000..dc8555675d4a
--- /dev/null
+++ b/usr.sbin/xten/xten.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+/*
+ * Xten - user command interface to X-10 daemon
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+#define RETRIES 10
+#define CMDLEN 512
+
+char *X10housenames[] = {
+ "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P",
+ NULL
+};
+
+char *X10cmdnames[] = {
+ "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
+ "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
+ "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
+ NULL
+};
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int c, tmp, h, k, sock, error;
+ FILE *daemon;
+ struct sockaddr_un sa;
+ char *sockpath = SOCKPATH;
+ char reply[CMDLEN], cmd[CMDLEN], *cp;
+ int interactive = 0;
+
+ if(argc == 2 && !strcmp(argv[1], "-")) interactive++;
+ else if(argc < 3) {
+ fprintf(stderr, "Usage: %s house key[:cnt] [ [house] key[:cnt] ... ]\n", argv[0]);
+ exit(1);
+ }
+ if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "%s: Can't create socket\n", argv[0]);
+ exit(1);
+ }
+ strcpy(sa.sun_path, sockpath);
+ sa.sun_family = AF_UNIX;
+ if(connect(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) {
+ fprintf(stderr, "%s: Can't connect to X-10 daemon\n", argv[0]);
+ exit(1);
+ }
+ if((daemon = fdopen(sock, "w+")) == NULL) {
+ fprintf(stderr, "%s: Can't attach stream to socket\n", argv[0]);
+ exit(1);
+ }
+ /*
+ * If interactive, copy standard input to daemon and report results
+ * on standard output.
+ */
+ if(interactive) {
+ while(!feof(stdin)) {
+ if(fgets(cmd, CMDLEN, stdin) != NULL) {
+ fprintf(daemon, "%s", cmd);
+ fflush(daemon);
+ if(fgets(reply, CMDLEN, daemon) != NULL) {
+ fprintf(stdout, "%s", reply);
+ fflush(stdout);
+ }
+ }
+ }
+ exit(0);
+ }
+ /*
+ * Otherwise, interpret arguments and issue commands to daemon,
+ * handling retries in case of errors.
+ */
+ if((h = find(argv[1], X10housenames)) < 0) {
+ fprintf(stderr, "Invalid house code: %s\n", argv[1]);
+ exit(1);
+ }
+ argv++;
+ argv++;
+ while(argc >= 3) {
+ cp = argv[0];
+ if((tmp = find(cp, X10housenames)) >= 0) {
+ h = tmp;
+ argv++;
+ argc--;
+ continue;
+ }
+ while(*cp != '\0' && *cp != ':') cp++;
+ if(*cp == ':') c = atoi(cp+1);
+ else c = 2;
+ *cp = '\0';
+ if((k = find(argv[0], X10cmdnames)) < 0) {
+ fprintf(stderr, "Invalid key/unit code: %s\n", argv[0]);
+ error++;
+ }
+ error = 0;
+ while(error < RETRIES) {
+ fprintf(daemon, "send %s %s %d\n", X10housenames[h], X10cmdnames[k], c);
+ fflush(daemon);
+ fgets(reply, CMDLEN, daemon);
+ if(strncmp(reply, "ERROR", 5)) break;
+ error++;
+ usleep(200000);
+ }
+ if(error == RETRIES) {
+ fprintf(stderr, "Command failed: send %s %s %d\n",
+ X10housenames[h], X10cmdnames[k], c);
+ }
+ argc--;
+ argv++;
+ }
+ exit(0);
+}
+
+find(s, tab)
+char *s;
+char *tab[];
+{
+ int i;
+
+ for(i = 0; tab[i] != NULL; i++) {
+ if(strcmp(s, tab[i]) == 0) return(i);
+ }
+ return(-1);
+}